[SerialICE] New patch to review for serialice: ba9ddeb Import QEMU 0.15.1

Kyösti Mälkki (kyosti.malkki@gmail.com) gerrit at coreboot.org
Sun Apr 22 09:38:36 CEST 2012


Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/915

-gerrit

commit ba9ddeb0975204057dc02ee70c777cb886b6ec59
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date:   Sat Apr 21 16:45:23 2012 +0300

    Import QEMU 0.15.1
    
    Download from QEMU main site:
    
    http://wiki.qemu.org/download/qemu-0.15.1.tar.gz
    md5sum: 34f17737baaf1b3495c89cd6d4a607ed
    
    Renamed directory qemu-0.15.1 to qemu-0.15.x
    
    Change-Id: Iaaa13f3c5cdbd5ddf4d235731be91e25607ea7d2
    Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
 qemu-0.15.x/.gitignore                             |   72 +
 qemu-0.15.x/.gitmodules                            |   12 +
 qemu-0.15.x/CODING_STYLE                           |   81 +
 qemu-0.15.x/COPYING                                |  339 +
 qemu-0.15.x/COPYING.LIB                            |  504 +
 qemu-0.15.x/Changelog                              |  580 +
 qemu-0.15.x/HACKING                                |  122 +
 qemu-0.15.x/LICENSE                                |   18 +
 qemu-0.15.x/MAINTAINERS                            |  506 +
 qemu-0.15.x/Makefile                               |  403 +
 qemu-0.15.x/Makefile.dis                           |   23 +
 qemu-0.15.x/Makefile.hw                            |   24 +
 qemu-0.15.x/Makefile.objs                          |  387 +
 qemu-0.15.x/Makefile.target                        |  431 +
 qemu-0.15.x/Makefile.user                          |   23 +
 qemu-0.15.x/QMP/README                             |   88 +
 qemu-0.15.x/QMP/qmp-events.txt                     |  266 +
 qemu-0.15.x/QMP/qmp-shell                          |  259 +
 qemu-0.15.x/QMP/qmp-spec.txt                       |  272 +
 qemu-0.15.x/QMP/qmp.py                             |  157 +
 qemu-0.15.x/README                                 |    3 +
 qemu-0.15.x/TODO                                   |   37 +
 qemu-0.15.x/VERSION                                |    1 +
 qemu-0.15.x/a.out.h                                |  430 +
 qemu-0.15.x/acl.c                                  |  184 +
 qemu-0.15.x/acl.h                                  |   74 +
 qemu-0.15.x/aes.c                                  | 1314 ++
 qemu-0.15.x/aes.h                                  |   26 +
 qemu-0.15.x/aio.c                                  |  230 +
 qemu-0.15.x/alpha-dis.c                            | 1916 +++
 qemu-0.15.x/alpha.ld                               |  127 +
 qemu-0.15.x/arch_init.c                            |  733 ++
 qemu-0.15.x/arch_init.h                            |   34 +
 qemu-0.15.x/arm-dis.c                              | 4136 +++++++
 qemu-0.15.x/arm-semi.c                             |  509 +
 qemu-0.15.x/arm.ld                                 |  153 +
 qemu-0.15.x/async.c                                |  217 +
 qemu-0.15.x/audio/alsaaudio.c                      | 1260 ++
 qemu-0.15.x/audio/audio.c                          | 2066 ++++
 qemu-0.15.x/audio/audio.h                          |  166 +
 qemu-0.15.x/audio/audio_int.h                      |  282 +
 qemu-0.15.x/audio/audio_pt_int.c                   |  173 +
 qemu-0.15.x/audio/audio_pt_int.h                   |   22 +
 qemu-0.15.x/audio/audio_template.h                 |  560 +
 qemu-0.15.x/audio/audio_win_int.c                  |  108 +
 qemu-0.15.x/audio/audio_win_int.h                  |   10 +
 qemu-0.15.x/audio/coreaudio.c                      |  549 +
 qemu-0.15.x/audio/dsound_template.h                |  293 +
 qemu-0.15.x/audio/dsoundaudio.c                    | 1030 ++
 qemu-0.15.x/audio/esdaudio.c                       |  557 +
 qemu-0.15.x/audio/fmodaudio.c                      |  687 ++
 qemu-0.15.x/audio/mixeng.c                         |  360 +
 qemu-0.15.x/audio/mixeng.h                         |   51 +
 qemu-0.15.x/audio/mixeng_template.h                |  152 +
 qemu-0.15.x/audio/noaudio.c                        |  173 +
 qemu-0.15.x/audio/ossaudio.c                       |  944 ++
 qemu-0.15.x/audio/paaudio.c                        |  525 +
 qemu-0.15.x/audio/rate_template.h                  |  111 +
 qemu-0.15.x/audio/sdlaudio.c                       |  458 +
 qemu-0.15.x/audio/spiceaudio.c                     |  345 +
 qemu-0.15.x/audio/wavaudio.c                       |  262 +
 qemu-0.15.x/audio/wavcapture.c                     |  161 +
 qemu-0.15.x/audio/winwaveaudio.c                   |  723 ++
 qemu-0.15.x/balloon.c                              |  164 +
 qemu-0.15.x/balloon.h                              |   31 +
 qemu-0.15.x/bitmap.c                               |  256 +
 qemu-0.15.x/bitmap.h                               |  222 +
 qemu-0.15.x/bitops.c                               |  142 +
 qemu-0.15.x/bitops.h                               |  272 +
 qemu-0.15.x/block-migration.c                      |  731 ++
 qemu-0.15.x/block-migration.h                      |   23 +
 qemu-0.15.x/block.c                                | 3039 +++++
 qemu-0.15.x/block.h                                |  305 +
 qemu-0.15.x/block/blkdebug.c                       |  471 +
 qemu-0.15.x/block/blkverify.c                      |  383 +
 qemu-0.15.x/block/bochs.c                          |  230 +
 qemu-0.15.x/block/cloop.c                          |  171 +
 qemu-0.15.x/block/cow.c                            |  324 +
 qemu-0.15.x/block/curl.c                           |  564 +
 qemu-0.15.x/block/dmg.c                            |  312 +
 qemu-0.15.x/block/nbd.c                            |  272 +
 qemu-0.15.x/block/parallels.c                      |  157 +
 qemu-0.15.x/block/qcow.c                           | 1037 ++
 qemu-0.15.x/block/qcow2-cache.c                    |  326 +
 qemu-0.15.x/block/qcow2-cluster.c                  |  979 ++
 qemu-0.15.x/block/qcow2-refcount.c                 | 1185 ++
 qemu-0.15.x/block/qcow2-snapshot.c                 |  457 +
 qemu-0.15.x/block/qcow2.c                          | 1419 +++
 qemu-0.15.x/block/qcow2.h                          |  246 +
 qemu-0.15.x/block/qed-check.c                      |  211 +
 qemu-0.15.x/block/qed-cluster.c                    |  165 +
 qemu-0.15.x/block/qed-gencb.c                      |   32 +
 qemu-0.15.x/block/qed-l2-cache.c                   |  173 +
 qemu-0.15.x/block/qed-table.c                      |  319 +
 qemu-0.15.x/block/qed.c                            | 1504 +++
 qemu-0.15.x/block/qed.h                            |  334 +
 qemu-0.15.x/block/raw-posix-aio.h                  |   43 +
 qemu-0.15.x/block/raw-posix.c                      | 1552 +++
 qemu-0.15.x/block/raw-win32.c                      |  459 +
 qemu-0.15.x/block/raw.c                            |  156 +
 qemu-0.15.x/block/rbd.c                            |  811 ++
 qemu-0.15.x/block/sheepdog.c                       | 2083 ++++
 qemu-0.15.x/block/vdi.c                            |  999 ++
 qemu-0.15.x/block/vmdk.c                           | 1363 +++
 qemu-0.15.x/block/vpc.c                            |  650 +
 qemu-0.15.x/block/vvfat.c                          | 2888 +++++
 qemu-0.15.x/block_int.h                            |  266 +
 qemu-0.15.x/blockdev.c                             |  795 ++
 qemu-0.15.x/blockdev.h                             |   69 +
 qemu-0.15.x/bsd-user/bsd-mman.h                    |  121 +
 qemu-0.15.x/bsd-user/bsdload.c                     |  202 +
 qemu-0.15.x/bsd-user/elfload.c                     | 1577 +++
 qemu-0.15.x/bsd-user/errno_defs.h                  |  149 +
 qemu-0.15.x/bsd-user/freebsd/strace.list           |  171 +
 qemu-0.15.x/bsd-user/freebsd/syscall_nr.h          |  373 +
 qemu-0.15.x/bsd-user/i386/syscall.h                |  161 +
 qemu-0.15.x/bsd-user/i386/target_signal.h          |   20 +
 qemu-0.15.x/bsd-user/main.c                        | 1143 ++
 qemu-0.15.x/bsd-user/mmap.c                        |  559 +
 qemu-0.15.x/bsd-user/netbsd/strace.list            |  145 +
 qemu-0.15.x/bsd-user/netbsd/syscall_nr.h           |  373 +
 qemu-0.15.x/bsd-user/openbsd/strace.list           |  187 +
 qemu-0.15.x/bsd-user/openbsd/syscall_nr.h          |  225 +
 qemu-0.15.x/bsd-user/qemu-types.h                  |   24 +
 qemu-0.15.x/bsd-user/qemu.h                        |  394 +
 qemu-0.15.x/bsd-user/signal.c                      |   38 +
 qemu-0.15.x/bsd-user/sparc/syscall.h               |    9 +
 qemu-0.15.x/bsd-user/sparc/target_signal.h         |   27 +
 qemu-0.15.x/bsd-user/sparc64/syscall.h             |   10 +
 qemu-0.15.x/bsd-user/sparc64/target_signal.h       |   27 +
 qemu-0.15.x/bsd-user/strace.c                      |  191 +
 qemu-0.15.x/bsd-user/syscall.c                     |  559 +
 qemu-0.15.x/bsd-user/syscall_defs.h                |  114 +
 qemu-0.15.x/bsd-user/uaccess.c                     |   65 +
 qemu-0.15.x/bsd-user/x86_64/syscall.h              |  116 +
 qemu-0.15.x/bsd-user/x86_64/target_signal.h        |   19 +
 qemu-0.15.x/bswap.h                                |  240 +
 qemu-0.15.x/bt-host.c                              |  198 +
 qemu-0.15.x/bt-host.h                              |    9 +
 qemu-0.15.x/bt-vhci.c                              |  167 +
 qemu-0.15.x/buffered_file.c                        |  281 +
 qemu-0.15.x/buffered_file.h                        |   30 +
 qemu-0.15.x/cache-utils.c                          |   97 +
 qemu-0.15.x/cache-utils.h                          |   41 +
 qemu-0.15.x/check-qdict.c                          |  402 +
 qemu-0.15.x/check-qfloat.c                         |   76 +
 qemu-0.15.x/check-qint.c                           |  113 +
 qemu-0.15.x/check-qjson.c                          |  795 ++
 qemu-0.15.x/check-qlist.c                          |  153 +
 qemu-0.15.x/check-qstring.c                        |  134 +
 qemu-0.15.x/cmd.c                                  |  610 +
 qemu-0.15.x/cmd.h                                  |   79 +
 qemu-0.15.x/compatfd.c                             |  128 +
 qemu-0.15.x/compatfd.h                             |   44 +
 qemu-0.15.x/compiler.h                             |   34 +
 qemu-0.15.x/config.h                               |    2 +
 qemu-0.15.x/configure                              | 3637 ++++++
 qemu-0.15.x/console.c                              | 1718 +++
 qemu-0.15.x/console.h                              |  406 +
 qemu-0.15.x/cpu-all.h                              | 1030 ++
 qemu-0.15.x/cpu-common.h                           |  178 +
 qemu-0.15.x/cpu-defs.h                             |  223 +
 qemu-0.15.x/cpu-exec.c                             |  627 +
 qemu-0.15.x/cpus.c                                 | 1178 ++
 qemu-0.15.x/cpus.h                                 |   25 +
 qemu-0.15.x/cris-dis.c                             | 2893 +++++
 qemu-0.15.x/cursor.c                               |  210 +
 qemu-0.15.x/cursor_hidden.xpm                      |   37 +
 qemu-0.15.x/cursor_left_ptr.xpm                    |   39 +
 qemu-0.15.x/cutils.c                               |  411 +
 qemu-0.15.x/darwin-user/commpage.c                 |  357 +
 qemu-0.15.x/darwin-user/ioctls.h                   |    4 +
 qemu-0.15.x/darwin-user/ioctls_types.h             |    1 +
 qemu-0.15.x/darwin-user/machload.c                 |  902 ++
 qemu-0.15.x/darwin-user/main.c                     | 1026 ++
 qemu-0.15.x/darwin-user/mmap.c                     |  409 +
 qemu-0.15.x/darwin-user/qemu.h                     |  178 +
 qemu-0.15.x/darwin-user/signal.c                   |  454 +
 qemu-0.15.x/darwin-user/syscall.c                  | 1566 +++
 qemu-0.15.x/darwin-user/syscalls.h                 |  384 +
 qemu-0.15.x/def-helper.h                           |  240 +
 qemu-0.15.x/default-configs/alpha-linux-user.mak   |    1 +
 qemu-0.15.x/default-configs/alpha-softmmu.mak      |    9 +
 qemu-0.15.x/default-configs/arm-linux-user.mak     |    3 +
 qemu-0.15.x/default-configs/arm-softmmu.mak        |   28 +
 qemu-0.15.x/default-configs/armeb-linux-user.mak   |    3 +
 qemu-0.15.x/default-configs/cris-linux-user.mak    |    1 +
 qemu-0.15.x/default-configs/cris-softmmu.mak       |    5 +
 qemu-0.15.x/default-configs/i386-bsd-user.mak      |    1 +
 qemu-0.15.x/default-configs/i386-darwin-user.mak   |    1 +
 qemu-0.15.x/default-configs/i386-linux-user.mak    |    1 +
 qemu-0.15.x/default-configs/i386-softmmu.mak       |   23 +
 qemu-0.15.x/default-configs/lm32-softmmu.mak       |    6 +
 qemu-0.15.x/default-configs/m68k-linux-user.mak    |    3 +
 qemu-0.15.x/default-configs/m68k-softmmu.mak       |    5 +
 .../default-configs/microblaze-linux-user.mak      |    1 +
 qemu-0.15.x/default-configs/microblaze-softmmu.mak |    5 +
 .../default-configs/microblazeel-linux-user.mak    |    1 +
 .../default-configs/microblazeel-softmmu.mak       |    5 +
 qemu-0.15.x/default-configs/mips-linux-user.mak    |    1 +
 qemu-0.15.x/default-configs/mips-softmmu.mak       |   28 +
 qemu-0.15.x/default-configs/mips64-softmmu.mak     |   28 +
 qemu-0.15.x/default-configs/mips64el-softmmu.mak   |   30 +
 qemu-0.15.x/default-configs/mipsel-linux-user.mak  |    1 +
 qemu-0.15.x/default-configs/mipsel-softmmu.mak     |   28 +
 qemu-0.15.x/default-configs/pci.mak                |   17 +
 qemu-0.15.x/default-configs/ppc-darwin-user.mak    |    3 +
 qemu-0.15.x/default-configs/ppc-linux-user.mak     |    3 +
 qemu-0.15.x/default-configs/ppc-softmmu.mak        |   33 +
 qemu-0.15.x/default-configs/ppc64-linux-user.mak   |    3 +
 qemu-0.15.x/default-configs/ppc64-softmmu.mak      |   33 +
 .../default-configs/ppc64abi32-linux-user.mak      |    3 +
 qemu-0.15.x/default-configs/ppcemb-softmmu.mak     |   33 +
 qemu-0.15.x/default-configs/s390x-linux-user.mak   |    1 +
 qemu-0.15.x/default-configs/s390x-softmmu.mak      |    1 +
 qemu-0.15.x/default-configs/sh4-linux-user.mak     |    1 +
 qemu-0.15.x/default-configs/sh4-softmmu.mak        |    7 +
 qemu-0.15.x/default-configs/sh4eb-linux-user.mak   |    1 +
 qemu-0.15.x/default-configs/sh4eb-softmmu.mak      |    7 +
 qemu-0.15.x/default-configs/sparc-bsd-user.mak     |    1 +
 qemu-0.15.x/default-configs/sparc-linux-user.mak   |    1 +
 qemu-0.15.x/default-configs/sparc-softmmu.mak      |   10 +
 .../default-configs/sparc32plus-linux-user.mak     |    1 +
 qemu-0.15.x/default-configs/sparc64-bsd-user.mak   |    1 +
 qemu-0.15.x/default-configs/sparc64-linux-user.mak |    1 +
 qemu-0.15.x/default-configs/sparc64-softmmu.mak    |   13 +
 .../default-configs/unicore32-linux-user.mak       |    1 +
 qemu-0.15.x/default-configs/x86_64-bsd-user.mak    |    1 +
 qemu-0.15.x/default-configs/x86_64-linux-user.mak  |    1 +
 qemu-0.15.x/default-configs/x86_64-softmmu.mak     |   23 +
 qemu-0.15.x/device_tree.c                          |  109 +
 qemu-0.15.x/device_tree.h                          |   26 +
 qemu-0.15.x/dis-asm.h                              |  479 +
 qemu-0.15.x/disas.c                                |  437 +
 qemu-0.15.x/disas.h                                |   42 +
 qemu-0.15.x/dma-helpers.c                          |  181 +
 qemu-0.15.x/dma.h                                  |   49 +
 qemu-0.15.x/docs/blkverify.txt                     |   69 +
 qemu-0.15.x/docs/bootindex.txt                     |   43 +
 qemu-0.15.x/docs/ccid.txt                          |  135 +
 qemu-0.15.x/docs/ich9-ehci-uhci.cfg                |   37 +
 qemu-0.15.x/docs/libcacard.txt                     |  483 +
 qemu-0.15.x/docs/migration.txt                     |  303 +
 qemu-0.15.x/docs/qapi-code-gen.txt                 |  316 +
 qemu-0.15.x/docs/qdev-device-use.txt               |  416 +
 qemu-0.15.x/docs/specs/acpi_pci_hotplug.txt        |   37 +
 qemu-0.15.x/docs/specs/ivshmem_device_spec.txt     |   96 +
 qemu-0.15.x/docs/specs/qcow2.txt                   |  260 +
 qemu-0.15.x/docs/specs/qed_spec.txt                |  138 +
 qemu-0.15.x/docs/tracing.txt                       |  211 +
 qemu-0.15.x/docs/usb2.txt                          |  146 +
 qemu-0.15.x/dyngen-exec.h                          |   84 +
 qemu-0.15.x/elf.h                                  | 1262 ++
 qemu-0.15.x/envlist.c                              |  246 +
 qemu-0.15.x/envlist.h                              |   22 +
 qemu-0.15.x/error.c                                |  141 +
 qemu-0.15.x/error.h                                |   70 +
 qemu-0.15.x/error_int.h                            |   29 +
 qemu-0.15.x/exec-all.h                             |  347 +
 qemu-0.15.x/exec.c                                 | 4748 ++++++++
 qemu-0.15.x/fpu/softfloat-macros.h                 |  749 ++
 qemu-0.15.x/fpu/softfloat-specialize.h             |  816 ++
 qemu-0.15.x/fpu/softfloat.c                        | 6430 ++++++++++
 qemu-0.15.x/fpu/softfloat.h                        |  662 +
 qemu-0.15.x/fsdev/file-op-9p.h                     |  100 +
 qemu-0.15.x/fsdev/qemu-fsdev-dummy.c               |   28 +
 qemu-0.15.x/fsdev/qemu-fsdev.c                     |  100 +
 qemu-0.15.x/fsdev/qemu-fsdev.h                     |   55 +
 qemu-0.15.x/gdb-xml/arm-core.xml                   |   31 +
 qemu-0.15.x/gdb-xml/arm-neon.xml                   |   88 +
 qemu-0.15.x/gdb-xml/arm-vfp.xml                    |   29 +
 qemu-0.15.x/gdb-xml/arm-vfp3.xml                   |   45 +
 qemu-0.15.x/gdb-xml/cf-core.xml                    |   29 +
 qemu-0.15.x/gdb-xml/cf-fp.xml                      |   22 +
 qemu-0.15.x/gdb-xml/power-altivec.xml              |   57 +
 qemu-0.15.x/gdb-xml/power-core.xml                 |   49 +
 qemu-0.15.x/gdb-xml/power-fpu.xml                  |   44 +
 qemu-0.15.x/gdb-xml/power-spe.xml                  |   45 +
 qemu-0.15.x/gdb-xml/power64-core.xml               |   49 +
 qemu-0.15.x/gdbstub.c                              | 2800 +++++
 qemu-0.15.x/gdbstub.h                              |   44 +
 qemu-0.15.x/gen-icount.h                           |   48 +
 qemu-0.15.x/hmp-commands.hx                        | 1370 +++
 qemu-0.15.x/host-utils.c                           |  105 +
 qemu-0.15.x/host-utils.h                           |  236 +
 qemu-0.15.x/hpet.h                                 |   22 +
 qemu-0.15.x/hppa-dis.c                             | 2831 +++++
 qemu-0.15.x/hppa.ld                                |  211 +
 qemu-0.15.x/hw/9p.h                                |   24 +
 qemu-0.15.x/hw/9pfs/virtio-9p-debug.c              |  646 +
 qemu-0.15.x/hw/9pfs/virtio-9p-debug.h              |    6 +
 qemu-0.15.x/hw/9pfs/virtio-9p-device.c             |  173 +
 qemu-0.15.x/hw/9pfs/virtio-9p-local.c              |  557 +
 qemu-0.15.x/hw/9pfs/virtio-9p-posix-acl.c          |  159 +
 qemu-0.15.x/hw/9pfs/virtio-9p-xattr-user.c         |  112 +
 qemu-0.15.x/hw/9pfs/virtio-9p-xattr.c              |  160 +
 qemu-0.15.x/hw/9pfs/virtio-9p-xattr.h              |  105 +
 qemu-0.15.x/hw/9pfs/virtio-9p.c                    | 3652 ++++++
 qemu-0.15.x/hw/9pfs/virtio-9p.h                    |  514 +
 qemu-0.15.x/hw/a9mpcore.c                          |   29 +
 qemu-0.15.x/hw/ac97.c                              | 1346 +++
 qemu-0.15.x/hw/acpi.c                              |  396 +
 qemu-0.15.x/hw/acpi.h                              |  146 +
 qemu-0.15.x/hw/acpi_piix4.c                        |  573 +
 qemu-0.15.x/hw/adb.c                               |  455 +
 qemu-0.15.x/hw/adlib.c                             |  338 +
 qemu-0.15.x/hw/ads7846.c                           |  165 +
 qemu-0.15.x/hw/an5206.c                            |  100 +
 qemu-0.15.x/hw/apb_pci.c                           |  481 +
 qemu-0.15.x/hw/apb_pci.h                           |    9 +
 qemu-0.15.x/hw/apic.c                              | 1033 ++
 qemu-0.15.x/hw/apic.h                              |   27 +
 qemu-0.15.x/hw/apm.c                               |   86 +
 qemu-0.15.x/hw/apm.h                               |   22 +
 qemu-0.15.x/hw/applesmc.c                          |  241 +
 qemu-0.15.x/hw/arm-misc.h                          |   46 +
 qemu-0.15.x/hw/arm11mpcore.c                       |  112 +
 qemu-0.15.x/hw/arm_boot.c                          |  290 +
 qemu-0.15.x/hw/arm_gic.c                           |  749 ++
 qemu-0.15.x/hw/arm_pic.c                           |   49 +
 qemu-0.15.x/hw/arm_sysctl.c                        |  371 +
 qemu-0.15.x/hw/arm_timer.c                         |  341 +
 qemu-0.15.x/hw/armv7m.c                            |  262 +
 qemu-0.15.x/hw/armv7m_nvic.c                       |  398 +
 qemu-0.15.x/hw/audiodev.h                          |   20 +
 qemu-0.15.x/hw/axis_dev88.c                        |  356 +
 qemu-0.15.x/hw/baum.c                              |  643 +
 qemu-0.15.x/hw/baum.h                              |   26 +
 qemu-0.15.x/hw/bitbang_i2c.c                       |  231 +
 qemu-0.15.x/hw/bitbang_i2c.h                       |   14 +
 qemu-0.15.x/hw/blizzard.c                          |  997 ++
 qemu-0.15.x/hw/blizzard_template.h                 |  136 +
 qemu-0.15.x/hw/boards.h                            |   39 +
 qemu-0.15.x/hw/bonito.c                            |  814 ++
 qemu-0.15.x/hw/bt-hci-csr.c                        |  453 +
 qemu-0.15.x/hw/bt-hci.c                            | 2221 ++++
 qemu-0.15.x/hw/bt-hid.c                            |  571 +
 qemu-0.15.x/hw/bt-l2cap.c                          | 1362 +++
 qemu-0.15.x/hw/bt-sdp.c                            |  967 ++
 qemu-0.15.x/hw/bt.c                                |  121 +
 qemu-0.15.x/hw/bt.h                                | 2183 ++++
 qemu-0.15.x/hw/cbus.c                              |  618 +
 qemu-0.15.x/hw/ccid-card-emulated.c                |  595 +
 qemu-0.15.x/hw/ccid-card-passthru.c                |  339 +
 qemu-0.15.x/hw/ccid.h                              |   58 +
 qemu-0.15.x/hw/cdrom.c                             |  155 +
 qemu-0.15.x/hw/cirrus_vga.c                        | 3151 +++++
 qemu-0.15.x/hw/cirrus_vga_rop.h                    |  208 +
 qemu-0.15.x/hw/cirrus_vga_rop2.h                   |  281 +
 qemu-0.15.x/hw/collie.c                            |   69 +
 qemu-0.15.x/hw/cris-boot.c                         |   96 +
 qemu-0.15.x/hw/cris-boot.h                         |   11 +
 qemu-0.15.x/hw/cris_pic_cpu.c                      |   50 +
 qemu-0.15.x/hw/cs4231.c                            |  175 +
 qemu-0.15.x/hw/cs4231a.c                           |  686 ++
 qemu-0.15.x/hw/cuda.c                              |  745 ++
 qemu-0.15.x/hw/debugcon.c                          |  107 +
 qemu-0.15.x/hw/dec_pci.c                           |  121 +
 qemu-0.15.x/hw/dec_pci.h                           |    8 +
 qemu-0.15.x/hw/device-hotplug.c                    |   46 +
 qemu-0.15.x/hw/devices.h                           |   70 +
 qemu-0.15.x/hw/dma.c                               |  555 +
 qemu-0.15.x/hw/dp8393x.c                           |  914 ++
 qemu-0.15.x/hw/ds1225y.c                           |  184 +
 qemu-0.15.x/hw/ds1338.c                            |  132 +
 qemu-0.15.x/hw/dummy_m68k.c                        |   79 +
 qemu-0.15.x/hw/e1000.c                             | 1235 ++
 qemu-0.15.x/hw/e1000_hw.h                          |  864 ++
 qemu-0.15.x/hw/ecc.c                               |   88 +
 qemu-0.15.x/hw/eccmemctl.c                         |  332 +
 qemu-0.15.x/hw/eepro100.c                          | 2178 ++++
 qemu-0.15.x/hw/eeprom93xx.c                        |  337 +
 qemu-0.15.x/hw/eeprom93xx.h                        |   40 +
 qemu-0.15.x/hw/elf_ops.h                           |  297 +
 qemu-0.15.x/hw/empty_slot.c                        |   96 +
 qemu-0.15.x/hw/empty_slot.h                        |    2 +
 qemu-0.15.x/hw/es1370.c                            | 1051 ++
 qemu-0.15.x/hw/escc.c                              |  961 ++
 qemu-0.15.x/hw/escc.h                              |    8 +
 qemu-0.15.x/hw/esp.c                               |  772 ++
 qemu-0.15.x/hw/esp.h                               |   13 +
 qemu-0.15.x/hw/etraxfs.c                           |  159 +
 qemu-0.15.x/hw/etraxfs.h                           |   28 +
 qemu-0.15.x/hw/etraxfs_dma.c                       |  756 ++
 qemu-0.15.x/hw/etraxfs_dma.h                       |   22 +
 qemu-0.15.x/hw/etraxfs_eth.c                       |  613 +
 qemu-0.15.x/hw/etraxfs_pic.c                       |  169 +
 qemu-0.15.x/hw/etraxfs_ser.c                       |  234 +
 qemu-0.15.x/hw/etraxfs_timer.c                     |  336 +
 qemu-0.15.x/hw/event_notifier.c                    |   62 +
 qemu-0.15.x/hw/event_notifier.h                    |   16 +
 qemu-0.15.x/hw/fdc.c                               | 1983 +++
 qemu-0.15.x/hw/fdc.h                               |   31 +
 qemu-0.15.x/hw/firmware_abi.h                      |   73 +
 qemu-0.15.x/hw/flash.h                             |   54 +
 qemu-0.15.x/hw/fmopl.c                             | 1395 +++
 qemu-0.15.x/hw/fmopl.h                             |  174 +
 qemu-0.15.x/hw/framebuffer.c                       |  119 +
 qemu-0.15.x/hw/framebuffer.h                       |   22 +
 qemu-0.15.x/hw/fw_cfg.c                            |  407 +
 qemu-0.15.x/hw/fw_cfg.h                            |   70 +
 qemu-0.15.x/hw/g364fb.c                            |  615 +
 qemu-0.15.x/hw/grackle_pci.c                       |  128 +
 qemu-0.15.x/hw/grlib.h                             |  126 +
 qemu-0.15.x/hw/grlib_apbuart.c                     |  187 +
 qemu-0.15.x/hw/grlib_gptimer.c                     |  394 +
 qemu-0.15.x/hw/grlib_irqmp.c                       |  376 +
 qemu-0.15.x/hw/gt64xxx.c                           | 1153 ++
 qemu-0.15.x/hw/gumstix.c                           |  140 +
 qemu-0.15.x/hw/gus.c                               |  322 +
 qemu-0.15.x/hw/gusemu.h                            |  105 +
 qemu-0.15.x/hw/gusemu_hal.c                        |  554 +
 qemu-0.15.x/hw/gusemu_mixer.c                      |  240 +
 qemu-0.15.x/hw/gustate.h                           |  132 +
 qemu-0.15.x/hw/hda-audio.c                         |  926 ++
 qemu-0.15.x/hw/heathrow_pic.c                      |  218 +
 qemu-0.15.x/hw/hpet.c                              |  745 ++
 qemu-0.15.x/hw/hpet_emul.h                         |   71 +
 qemu-0.15.x/hw/hw.h                                |  925 ++
 qemu-0.15.x/hw/i2c.c                               |  196 +
 qemu-0.15.x/hw/i2c.h                               |   77 +
 qemu-0.15.x/hw/i8254.c                             |  546 +
 qemu-0.15.x/hw/i8259.c                             |  539 +
 qemu-0.15.x/hw/ide.h                               |   34 +
 qemu-0.15.x/hw/ide/ahci.c                          | 1168 ++
 qemu-0.15.x/hw/ide/ahci.h                          |  330 +
 qemu-0.15.x/hw/ide/atapi.c                         | 1138 ++
 qemu-0.15.x/hw/ide/cmd646.c                        |  296 +
 qemu-0.15.x/hw/ide/core.c                          | 2104 ++++
 qemu-0.15.x/hw/ide/ich.c                           |  142 +
 qemu-0.15.x/hw/ide/internal.h                      |  615 +
 qemu-0.15.x/hw/ide/isa.c                           |  119 +
 qemu-0.15.x/hw/ide/macio.c                         |  337 +
 qemu-0.15.x/hw/ide/microdrive.c                    |  550 +
 qemu-0.15.x/hw/ide/mmio.c                          |  140 +
 qemu-0.15.x/hw/ide/pci.c                           |  530 +
 qemu-0.15.x/hw/ide/pci.h                           |   52 +
 qemu-0.15.x/hw/ide/piix.c                          |  202 +
 qemu-0.15.x/hw/ide/qdev.c                          |  227 +
 qemu-0.15.x/hw/ide/via.c                           |  200 +
 qemu-0.15.x/hw/integratorcp.c                      |  544 +
 qemu-0.15.x/hw/intel-hda-defs.h                    |  717 ++
 qemu-0.15.x/hw/intel-hda.c                         | 1284 ++
 qemu-0.15.x/hw/intel-hda.h                         |   62 +
 qemu-0.15.x/hw/ioapic.c                            |  359 +
 qemu-0.15.x/hw/ioapic.h                            |   20 +
 qemu-0.15.x/hw/ioh3420.c                           |  245 +
 qemu-0.15.x/hw/ioh3420.h                           |   10 +
 qemu-0.15.x/hw/irq.c                               |   92 +
 qemu-0.15.x/hw/irq.h                               |   36 +
 qemu-0.15.x/hw/isa-bus.c                           |  205 +
 qemu-0.15.x/hw/isa.h                               |   53 +
 qemu-0.15.x/hw/isa_mmio.c                          |   82 +
 qemu-0.15.x/hw/ivshmem.c                           |  827 ++
 qemu-0.15.x/hw/jazz_led.c                          |  328 +
 qemu-0.15.x/hw/kvmclock.c                          |  120 +
 qemu-0.15.x/hw/kvmclock.h                          |   24 +
 qemu-0.15.x/hw/lan9118.c                           | 1196 ++
 qemu-0.15.x/hw/lance.c                             |  160 +
 qemu-0.15.x/hw/leon3.c                             |  217 +
 qemu-0.15.x/hw/lm32.h                              |   25 +
 qemu-0.15.x/hw/lm32_boards.c                       |  304 +
 qemu-0.15.x/hw/lm32_hwsetup.h                      |  178 +
 qemu-0.15.x/hw/lm32_juart.c                        |  150 +
 qemu-0.15.x/hw/lm32_juart.h                        |   11 +
 qemu-0.15.x/hw/lm32_pic.c                          |  190 +
 qemu-0.15.x/hw/lm32_pic.h                          |   11 +
 qemu-0.15.x/hw/lm32_sys.c                          |  161 +
 qemu-0.15.x/hw/lm32_timer.c                        |  222 +
 qemu-0.15.x/hw/lm32_uart.c                         |  288 +
 qemu-0.15.x/hw/lm832x.c                            |  512 +
 qemu-0.15.x/hw/loader.c                            |  795 ++
 qemu-0.15.x/hw/loader.h                            |   48 +
 qemu-0.15.x/hw/lsi53c895a.c                        | 2299 ++++
 qemu-0.15.x/hw/m48t59.c                            |  752 ++
 qemu-0.15.x/hw/mac_dbdma.c                         |  859 ++
 qemu-0.15.x/hw/mac_dbdma.h                         |   43 +
 qemu-0.15.x/hw/mac_nvram.c                         |  187 +
 qemu-0.15.x/hw/macio.c                             |  118 +
 qemu-0.15.x/hw/mainstone.c                         |  188 +
 qemu-0.15.x/hw/marvell_88w8618_audio.c             |  299 +
 qemu-0.15.x/hw/max111x.c                           |  173 +
 qemu-0.15.x/hw/max7310.c                           |  204 +
 qemu-0.15.x/hw/mc146818rtc.c                       |  677 ++
 qemu-0.15.x/hw/mc146818rtc.h                       |   12 +
 qemu-0.15.x/hw/mcf.h                               |   21 +
 qemu-0.15.x/hw/mcf5206.c                           |  541 +
 qemu-0.15.x/hw/mcf5208.c                           |  306 +
 qemu-0.15.x/hw/mcf_fec.c                           |  481 +
 qemu-0.15.x/hw/mcf_intc.c                          |  157 +
 qemu-0.15.x/hw/mcf_uart.c                          |  310 +
 qemu-0.15.x/hw/microblaze_pic_cpu.c                |   50 +
 qemu-0.15.x/hw/milkymist-ac97.c                    |  335 +
 qemu-0.15.x/hw/milkymist-hpdmc.c                   |  161 +
 qemu-0.15.x/hw/milkymist-hw.h                      |  224 +
 qemu-0.15.x/hw/milkymist-memcard.c                 |  294 +
 qemu-0.15.x/hw/milkymist-minimac2.c                |  539 +
 qemu-0.15.x/hw/milkymist-pfpu.c                    |  536 +
 qemu-0.15.x/hw/milkymist-softusb.c                 |  372 +
 qemu-0.15.x/hw/milkymist-sysctl.c                  |  318 +
 qemu-0.15.x/hw/milkymist-tmu2.c                    |  481 +
 qemu-0.15.x/hw/milkymist-uart.c                    |  180 +
 qemu-0.15.x/hw/milkymist-vgafb.c                   |  321 +
 qemu-0.15.x/hw/milkymist-vgafb_template.h          |   74 +
 qemu-0.15.x/hw/milkymist.c                         |  216 +
 qemu-0.15.x/hw/mips-bios.h                         |    8 +
 qemu-0.15.x/hw/mips.h                              |   36 +
 qemu-0.15.x/hw/mips_addr.c                         |   34 +
 qemu-0.15.x/hw/mips_cpudevs.h                      |   15 +
 qemu-0.15.x/hw/mips_fulong2e.c                     |  394 +
 qemu-0.15.x/hw/mips_int.c                          |   65 +
 qemu-0.15.x/hw/mips_jazz.c                         |  320 +
 qemu-0.15.x/hw/mips_malta.c                        |  966 ++
 qemu-0.15.x/hw/mips_mipssim.c                      |  212 +
 qemu-0.15.x/hw/mips_r4k.c                          |  310 +
 qemu-0.15.x/hw/mips_timer.c                        |  147 +
 qemu-0.15.x/hw/mipsnet.c                           |  273 +
 qemu-0.15.x/hw/mpc8544_guts.c                      |  135 +
 qemu-0.15.x/hw/mpcore.c                            |  286 +
 qemu-0.15.x/hw/msi.c                               |  352 +
 qemu-0.15.x/hw/msi.h                               |   41 +
 qemu-0.15.x/hw/msix.c                              |  410 +
 qemu-0.15.x/hw/msix.h                              |   36 +
 qemu-0.15.x/hw/msmouse.c                           |   79 +
 qemu-0.15.x/hw/msmouse.h                           |    2 +
 qemu-0.15.x/hw/mst_fpga.c                          |  255 +
 qemu-0.15.x/hw/multiboot.c                         |  339 +
 qemu-0.15.x/hw/multiboot.h                         |   12 +
 qemu-0.15.x/hw/musicpal.c                          | 1665 +++
 qemu-0.15.x/hw/nand.c                              |  666 +
 qemu-0.15.x/hw/ne2000-isa.c                        |  112 +
 qemu-0.15.x/hw/ne2000.c                            |  781 ++
 qemu-0.15.x/hw/ne2000.h                            |   39 +
 qemu-0.15.x/hw/nseries.c                           | 1417 +++
 qemu-0.15.x/hw/nvram.h                             |   42 +
 qemu-0.15.x/hw/omap.h                              | 1141 ++
 qemu-0.15.x/hw/omap1.c                             | 3894 ++++++
 qemu-0.15.x/hw/omap2.c                             | 2616 ++++
 qemu-0.15.x/hw/omap_clk.c                          | 1260 ++
 qemu-0.15.x/hw/omap_dma.c                          | 2082 ++++
 qemu-0.15.x/hw/omap_dss.c                          | 1068 ++
 qemu-0.15.x/hw/omap_gpio.c                         |  725 ++
 qemu-0.15.x/hw/omap_gpmc.c                         |  419 +
 qemu-0.15.x/hw/omap_gptimer.c                      |  484 +
 qemu-0.15.x/hw/omap_i2c.c                          |  470 +
 qemu-0.15.x/hw/omap_intc.c                         |  598 +
 qemu-0.15.x/hw/omap_l4.c                           |  272 +
 qemu-0.15.x/hw/omap_lcd_template.h                 |  175 +
 qemu-0.15.x/hw/omap_lcdc.c                         |  461 +
 qemu-0.15.x/hw/omap_mmc.c                          |  641 +
 qemu-0.15.x/hw/omap_sdrc.c                         |  165 +
 qemu-0.15.x/hw/omap_spi.c                          |  346 +
 qemu-0.15.x/hw/omap_sx1.c                          |  253 +
 qemu-0.15.x/hw/omap_synctimer.c                    |   96 +
 qemu-0.15.x/hw/omap_tap.c                          |  112 +
 qemu-0.15.x/hw/omap_uart.c                         |  196 +
 qemu-0.15.x/hw/onenand.c                           |  661 +
 qemu-0.15.x/hw/openpic.c                           | 1686 +++
 qemu-0.15.x/hw/openpic.h                           |   18 +
 qemu-0.15.x/hw/palm.c                              |  289 +
 qemu-0.15.x/hw/parallel.c                          |  598 +
 qemu-0.15.x/hw/pc.c                                | 1171 ++
 qemu-0.15.x/hw/pc.h                                |  241 +
 qemu-0.15.x/hw/pc_piix.c                           |  495 +
 qemu-0.15.x/hw/pci-hotplug.c                       |  292 +
 qemu-0.15.x/hw/pci-stub.c                          |   50 +
 qemu-0.15.x/hw/pci.c                               | 2185 ++++
 qemu-0.15.x/hw/pci.h                               |  485 +
 qemu-0.15.x/hw/pci_bridge.c                        |  275 +
 qemu-0.15.x/hw/pci_bridge.h                        |   66 +
 qemu-0.15.x/hw/pci_host.c                          |  159 +
 qemu-0.15.x/hw/pci_host.h                          |   53 +
 qemu-0.15.x/hw/pci_ids.h                           |  122 +
 qemu-0.15.x/hw/pci_internals.h                     |   47 +
 qemu-0.15.x/hw/pci_regs.h                          |  715 ++
 qemu-0.15.x/hw/pcie.c                              |  543 +
 qemu-0.15.x/hw/pcie.h                              |  132 +
 qemu-0.15.x/hw/pcie_aer.c                          | 1026 ++
 qemu-0.15.x/hw/pcie_aer.h                          |  106 +
 qemu-0.15.x/hw/pcie_host.c                         |  176 +
 qemu-0.15.x/hw/pcie_host.h                         |   49 +
 qemu-0.15.x/hw/pcie_port.c                         |  124 +
 qemu-0.15.x/hw/pcie_port.h                         |   51 +
 qemu-0.15.x/hw/pcie_regs.h                         |  156 +
 qemu-0.15.x/hw/pckbd.c                             |  499 +
 qemu-0.15.x/hw/pcmcia.h                            |   51 +
 qemu-0.15.x/hw/pcnet-pci.c                         |  332 +
 qemu-0.15.x/hw/pcnet.c                             | 1765 +++
 qemu-0.15.x/hw/pcnet.h                             |   42 +
 qemu-0.15.x/hw/pcspk.c                             |  147 +
 qemu-0.15.x/hw/petalogix_ml605_mmu.c               |  266 +
 qemu-0.15.x/hw/petalogix_s3adsp1800_mmu.c          |  230 +
 qemu-0.15.x/hw/pflash_cfi01.c                      |  726 ++
 qemu-0.15.x/hw/pflash_cfi02.c                      |  745 ++
 qemu-0.15.x/hw/piix4.c                             |  125 +
 qemu-0.15.x/hw/piix_pci.c                          |  502 +
 qemu-0.15.x/hw/pixel_ops.h                         |   53 +
 qemu-0.15.x/hw/pl011.c                             |  306 +
 qemu-0.15.x/hw/pl022.c                             |  300 +
 qemu-0.15.x/hw/pl031.c                             |  237 +
 qemu-0.15.x/hw/pl050.c                             |  187 +
 qemu-0.15.x/hw/pl061.c                             |  332 +
 qemu-0.15.x/hw/pl080.c                             |  407 +
 qemu-0.15.x/hw/pl110.c                             |  422 +
 qemu-0.15.x/hw/pl110_template.h                    |  307 +
 qemu-0.15.x/hw/pl181.c                             |  479 +
 qemu-0.15.x/hw/pl190.c                             |  278 +
 qemu-0.15.x/hw/pm_smbus.c                          |  176 +
 qemu-0.15.x/hw/pm_smbus.h                          |   21 +
 qemu-0.15.x/hw/ppc-viosrp.h                        |  216 +
 qemu-0.15.x/hw/ppc.c                               | 1335 ++
 qemu-0.15.x/hw/ppc.h                               |   57 +
 qemu-0.15.x/hw/ppc405.h                            |   76 +
 qemu-0.15.x/hw/ppc405_boards.c                     |  654 +
 qemu-0.15.x/hw/ppc405_uc.c                         | 2547 ++++
 qemu-0.15.x/hw/ppc440.c                            |  101 +
 qemu-0.15.x/hw/ppc440.h                            |   21 +
 qemu-0.15.x/hw/ppc440_bamboo.c                     |  200 +
 qemu-0.15.x/hw/ppc4xx.h                            |   60 +
 qemu-0.15.x/hw/ppc4xx_devs.c                       |  690 ++
 qemu-0.15.x/hw/ppc4xx_pci.c                        |  391 +
 qemu-0.15.x/hw/ppc_mac.h                           |  112 +
 qemu-0.15.x/hw/ppc_newworld.c                      |  429 +
 qemu-0.15.x/hw/ppc_oldworld.c                      |  334 +
 qemu-0.15.x/hw/ppc_prep.c                          |  763 ++
 qemu-0.15.x/hw/ppce500_mpc8544ds.c                 |  374 +
 qemu-0.15.x/hw/ppce500_pci.c                       |  328 +
 qemu-0.15.x/hw/prep_pci.c                          |  144 +
 qemu-0.15.x/hw/prep_pci.h                          |    8 +
 qemu-0.15.x/hw/primecell.h                         |   18 +
 qemu-0.15.x/hw/ps2.c                               |  628 +
 qemu-0.15.x/hw/ps2.h                               |    9 +
 qemu-0.15.x/hw/ptimer.c                            |  217 +
 qemu-0.15.x/hw/pxa.h                               |  179 +
 qemu-0.15.x/hw/pxa2xx.c                            | 2344 ++++
 qemu-0.15.x/hw/pxa2xx_dma.c                        |  568 +
 qemu-0.15.x/hw/pxa2xx_gpio.c                       |  343 +
 qemu-0.15.x/hw/pxa2xx_keypad.c                     |  337 +
 qemu-0.15.x/hw/pxa2xx_lcd.c                        | 1045 ++
 qemu-0.15.x/hw/pxa2xx_mmci.c                       |  549 +
 qemu-0.15.x/hw/pxa2xx_pcmcia.c                     |  215 +
 qemu-0.15.x/hw/pxa2xx_pic.c                        |  316 +
 qemu-0.15.x/hw/pxa2xx_template.h                   |  435 +
 qemu-0.15.x/hw/pxa2xx_timer.c                      |  518 +
 qemu-0.15.x/hw/qdev-addr.c                         |   32 +
 qemu-0.15.x/hw/qdev-addr.h                         |    5 +
 qemu-0.15.x/hw/qdev-properties.c                   |  782 ++
 qemu-0.15.x/hw/qdev.c                              |  940 ++
 qemu-0.15.x/hw/qdev.h                              |  329 +
 qemu-0.15.x/hw/qxl-logger.c                        |  250 +
 qemu-0.15.x/hw/qxl-render.c                        |  225 +
 qemu-0.15.x/hw/qxl.c                               | 1551 +++
 qemu-0.15.x/hw/qxl.h                               |  108 +
 qemu-0.15.x/hw/r2d.c                               |  341 +
 qemu-0.15.x/hw/rc4030.c                            |  830 ++
 qemu-0.15.x/hw/realview.c                          |  467 +
 qemu-0.15.x/hw/realview_gic.c                      |   79 +
 qemu-0.15.x/hw/rtl8139.c                           | 3528 ++++++
 qemu-0.15.x/hw/s390-virtio-bus.c                   |  423 +
 qemu-0.15.x/hw/s390-virtio-bus.h                   |   70 +
 qemu-0.15.x/hw/s390-virtio.c                       |  297 +
 qemu-0.15.x/hw/sb16.c                              | 1420 +++
 qemu-0.15.x/hw/sbi.c                               |  148 +
 qemu-0.15.x/hw/scsi-bus.c                          |  734 ++
 qemu-0.15.x/hw/scsi-defs.h                         |  166 +
 qemu-0.15.x/hw/scsi-disk.c                         | 1346 +++
 qemu-0.15.x/hw/scsi-generic.c                      |  568 +
 qemu-0.15.x/hw/scsi.h                              |  163 +
 qemu-0.15.x/hw/sd.c                                | 1671 +++
 qemu-0.15.x/hw/sd.h                                |   79 +
 qemu-0.15.x/hw/serial.c                            |  979 ++
 qemu-0.15.x/hw/sga.c                               |   56 +
 qemu-0.15.x/hw/sh.h                                |   54 +
 qemu-0.15.x/hw/sh7750.c                            |  817 ++
 qemu-0.15.x/hw/sh7750_regnames.c                   |   97 +
 qemu-0.15.x/hw/sh7750_regnames.h                   |    6 +
 qemu-0.15.x/hw/sh7750_regs.h                       | 1277 ++
 qemu-0.15.x/hw/sh_intc.c                           |  481 +
 qemu-0.15.x/hw/sh_intc.h                           |   80 +
 qemu-0.15.x/hw/sh_pci.c                            |  161 +
 qemu-0.15.x/hw/sh_serial.c                         |  401 +
 qemu-0.15.x/hw/sh_timer.c                          |  327 +
 qemu-0.15.x/hw/sharpsl.h                           |   17 +
 qemu-0.15.x/hw/shix.c                              |  104 +
 qemu-0.15.x/hw/slavio_intctl.c                     |  463 +
 qemu-0.15.x/hw/slavio_misc.c                       |  499 +
 qemu-0.15.x/hw/slavio_timer.c                      |  424 +
 qemu-0.15.x/hw/sm501.c                             | 1457 +++
 qemu-0.15.x/hw/sm501_template.h                    |  145 +
 qemu-0.15.x/hw/smbios.c                            |  239 +
 qemu-0.15.x/hw/smbios.h                            |  162 +
 qemu-0.15.x/hw/smbus.c                             |  318 +
 qemu-0.15.x/hw/smbus.h                             |   71 +
 qemu-0.15.x/hw/smbus_eeprom.c                      |  145 +
 qemu-0.15.x/hw/smc91c111.c                         |  797 ++
 qemu-0.15.x/hw/soc_dma.c                           |  366 +
 qemu-0.15.x/hw/soc_dma.h                           |  113 +
 qemu-0.15.x/hw/spapr.c                             |  476 +
 qemu-0.15.x/hw/spapr.h                             |  301 +
 qemu-0.15.x/hw/spapr_hcall.c                       |  519 +
 qemu-0.15.x/hw/spapr_llan.c                        |  515 +
 qemu-0.15.x/hw/spapr_rtas.c                        |  279 +
 qemu-0.15.x/hw/spapr_vio.c                         |  731 ++
 qemu-0.15.x/hw/spapr_vio.h                         |  114 +
 qemu-0.15.x/hw/spapr_vscsi.c                       |  999 ++
 qemu-0.15.x/hw/spapr_vty.c                         |  159 +
 qemu-0.15.x/hw/sparc32_dma.c                       |  305 +
 qemu-0.15.x/hw/sparc32_dma.h                       |   12 +
 qemu-0.15.x/hw/spitz.c                             | 1117 ++
 qemu-0.15.x/hw/srp.h                               |  240 +
 qemu-0.15.x/hw/ssd0303.c                           |  312 +
 qemu-0.15.x/hw/ssd0323.c                           |  355 +
 qemu-0.15.x/hw/ssi-sd.c                            |  256 +
 qemu-0.15.x/hw/ssi.c                               |   70 +
 qemu-0.15.x/hw/ssi.h                               |   45 +
 qemu-0.15.x/hw/stellaris.c                         | 1370 +++
 qemu-0.15.x/hw/stellaris_enet.c                    |  443 +
 qemu-0.15.x/hw/stellaris_input.c                   |   89 +
 qemu-0.15.x/hw/strongarm.c                         | 1598 +++
 qemu-0.15.x/hw/strongarm.h                         |   64 +
 qemu-0.15.x/hw/sun4c_intctl.c                      |  224 +
 qemu-0.15.x/hw/sun4m.c                             | 1827 +++
 qemu-0.15.x/hw/sun4m.h                             |   36 +
 qemu-0.15.x/hw/sun4m_iommu.c                       |  378 +
 qemu-0.15.x/hw/sun4u.c                             |  935 ++
 qemu-0.15.x/hw/syborg.c                            |  111 +
 qemu-0.15.x/hw/syborg.h                            |   18 +
 qemu-0.15.x/hw/syborg_fb.c                         |  551 +
 qemu-0.15.x/hw/syborg_interrupt.c                  |  238 +
 qemu-0.15.x/hw/syborg_keyboard.c                   |  221 +
 qemu-0.15.x/hw/syborg_pointer.c                    |  226 +
 qemu-0.15.x/hw/syborg_rtc.c                        |  140 +
 qemu-0.15.x/hw/syborg_serial.c                     |  335 +
 qemu-0.15.x/hw/syborg_timer.c                      |  231 +
 qemu-0.15.x/hw/syborg_virtio.c                     |  315 +
 qemu-0.15.x/hw/sysbus.c                            |  234 +
 qemu-0.15.x/hw/sysbus.h                            |   76 +
 qemu-0.15.x/hw/tc58128.c                           |  182 +
 qemu-0.15.x/hw/tc6393xb.c                          |  607 +
 qemu-0.15.x/hw/tc6393xb_template.h                 |   67 +
 qemu-0.15.x/hw/tcx.c                               |  651 +
 qemu-0.15.x/hw/tmp105.c                            |  244 +
 qemu-0.15.x/hw/tosa.c                              |  280 +
 qemu-0.15.x/hw/tsc2005.c                           |  593 +
 qemu-0.15.x/hw/tsc210x.c                           | 1293 ++
 qemu-0.15.x/hw/tusb6010.c                          |  766 ++
 qemu-0.15.x/hw/twl92230.c                          |  875 ++
 qemu-0.15.x/hw/unin_pci.c                          |  369 +
 qemu-0.15.x/hw/usb-bt.c                            |  568 +
 qemu-0.15.x/hw/usb-bus.c                           |  445 +
 qemu-0.15.x/hw/usb-ccid.c                          | 1397 +++
 qemu-0.15.x/hw/usb-desc.c                          |  466 +
 qemu-0.15.x/hw/usb-desc.h                          |  112 +
 qemu-0.15.x/hw/usb-ehci.c                          | 2359 ++++
 qemu-0.15.x/hw/usb-hid.c                           | 1007 ++
 qemu-0.15.x/hw/usb-hub.c                           |  549 +
 qemu-0.15.x/hw/usb-msd.c                           |  646 +
 qemu-0.15.x/hw/usb-musb.c                          | 1529 +++
 qemu-0.15.x/hw/usb-net.c                           | 1441 +++
 qemu-0.15.x/hw/usb-ohci.c                          | 1863 +++
 qemu-0.15.x/hw/usb-ohci.h                          |    9 +
 qemu-0.15.x/hw/usb-serial.c                        |  612 +
 qemu-0.15.x/hw/usb-uhci.c                          | 1276 ++
 qemu-0.15.x/hw/usb-uhci.h                          |   10 +
 qemu-0.15.x/hw/usb-wacom.c                         |  371 +
 qemu-0.15.x/hw/usb.c                               |  349 +
 qemu-0.15.x/hw/usb.h                               |  382 +
 qemu-0.15.x/hw/versatile_pci.c                     |  160 +
 qemu-0.15.x/hw/versatilepb.c                       |  362 +
 qemu-0.15.x/hw/vexpress.c                          |  224 +
 qemu-0.15.x/hw/vga-isa-mm.c                        |  128 +
 qemu-0.15.x/hw/vga-isa.c                           |   87 +
 qemu-0.15.x/hw/vga-pci.c                           |  122 +
 qemu-0.15.x/hw/vga.c                               | 2412 ++++
 qemu-0.15.x/hw/vga_int.h                           |  233 +
 qemu-0.15.x/hw/vga_template.h                      |  525 +
 qemu-0.15.x/hw/vhost.c                             |  789 ++
 qemu-0.15.x/hw/vhost.h                             |   50 +
 qemu-0.15.x/hw/vhost_net.c                         |  237 +
 qemu-0.15.x/hw/vhost_net.h                         |   20 +
 qemu-0.15.x/hw/virtex_ml507.c                      |  276 +
 qemu-0.15.x/hw/virtio-balloon.c                    |  308 +
 qemu-0.15.x/hw/virtio-balloon.h                    |   55 +
 qemu-0.15.x/hw/virtio-blk.c                        |  597 +
 qemu-0.15.x/hw/virtio-blk.h                        |  108 +
 qemu-0.15.x/hw/virtio-console.c                    |  168 +
 qemu-0.15.x/hw/virtio-net.c                        | 1078 ++
 qemu-0.15.x/hw/virtio-net.h                        |  189 +
 qemu-0.15.x/hw/virtio-pci.c                        |  901 ++
 qemu-0.15.x/hw/virtio-pci.h                        |   46 +
 qemu-0.15.x/hw/virtio-serial-bus.c                 |  927 ++
 qemu-0.15.x/hw/virtio-serial.h                     |  207 +
 qemu-0.15.x/hw/virtio.c                            |  962 ++
 qemu-0.15.x/hw/virtio.h                            |  239 +
 qemu-0.15.x/hw/vmmouse.c                           |  289 +
 qemu-0.15.x/hw/vmport.c                            |  148 +
 qemu-0.15.x/hw/vmware_vga.c                        | 1324 ++
 qemu-0.15.x/hw/vmware_vga.h                        |   19 +
 qemu-0.15.x/hw/vt82c686.c                          |  537 +
 qemu-0.15.x/hw/vt82c686.h                          |   11 +
 qemu-0.15.x/hw/watchdog.c                          |  147 +
 qemu-0.15.x/hw/watchdog.h                          |   43 +
 qemu-0.15.x/hw/wdt_i6300esb.c                      |  433 +
 qemu-0.15.x/hw/wdt_ib700.c                         |  137 +
 qemu-0.15.x/hw/wm8750.c                            |  707 ++
 qemu-0.15.x/hw/xen.h                               |   54 +
 qemu-0.15.x/hw/xen_backend.c                       |  757 ++
 qemu-0.15.x/hw/xen_backend.h                       |  106 +
 qemu-0.15.x/hw/xen_blkif.h                         |  103 +
 qemu-0.15.x/hw/xen_common.h                        |  138 +
 qemu-0.15.x/hw/xen_console.c                       |  279 +
 qemu-0.15.x/hw/xen_devconfig.c                     |  173 +
 qemu-0.15.x/hw/xen_disk.c                          |  853 ++
 qemu-0.15.x/hw/xen_domainbuild.c                   |  300 +
 qemu-0.15.x/hw/xen_domainbuild.h                   |   13 +
 qemu-0.15.x/hw/xen_machine_pv.c                    |  124 +
 qemu-0.15.x/hw/xen_nic.c                           |  440 +
 qemu-0.15.x/hw/xen_platform.c                      |  339 +
 qemu-0.15.x/hw/xenfb.c                             | 1017 ++
 qemu-0.15.x/hw/xics.c                              |  496 +
 qemu-0.15.x/hw/xics.h                              |   38 +
 qemu-0.15.x/hw/xilinx.h                            |   89 +
 qemu-0.15.x/hw/xilinx_axidma.c                     |  509 +
 qemu-0.15.x/hw/xilinx_axidma.h                     |   39 +
 qemu-0.15.x/hw/xilinx_axienet.c                    |  898 ++
 qemu-0.15.x/hw/xilinx_ethlite.c                    |  241 +
 qemu-0.15.x/hw/xilinx_intc.c                       |  176 +
 qemu-0.15.x/hw/xilinx_timer.c                      |  234 +
 qemu-0.15.x/hw/xilinx_uartlite.c                   |  220 +
 qemu-0.15.x/hw/xio3130_downstream.c                |  211 +
 qemu-0.15.x/hw/xio3130_downstream.h                |   11 +
 qemu-0.15.x/hw/xio3130_upstream.c                  |  186 +
 qemu-0.15.x/hw/xio3130_upstream.h                  |   10 +
 qemu-0.15.x/hw/zaurus.c                            |  284 +
 qemu-0.15.x/i386-dis.c                             | 6562 ++++++++++
 qemu-0.15.x/i386.ld                                |  153 +
 qemu-0.15.x/ia64-dis.c                             |10599 ++++++++++++++++
 qemu-0.15.x/ia64.ld                                |  209 +
 qemu-0.15.x/input.c                                |  304 +
 qemu-0.15.x/iohandler.c                            |  193 +
 qemu-0.15.x/ioport-user.c                          |   60 +
 qemu-0.15.x/ioport.c                               |  315 +
 qemu-0.15.x/ioport.h                               |   55 +
 qemu-0.15.x/iorange.h                              |   30 +
 qemu-0.15.x/iov.c                                  |   75 +
 qemu-0.15.x/iov.h                                  |   19 +
 qemu-0.15.x/json-lexer.c                           |  372 +
 qemu-0.15.x/json-lexer.h                           |   51 +
 qemu-0.15.x/json-parser.c                          |  650 +
 qemu-0.15.x/json-parser.h                          |   24 +
 qemu-0.15.x/json-streamer.c                        |  122 +
 qemu-0.15.x/json-streamer.h                        |   40 +
 qemu-0.15.x/kvm-all.c                              | 1396 +++
 qemu-0.15.x/kvm-stub.c                             |  131 +
 qemu-0.15.x/kvm.h                                  |  199 +
 qemu-0.15.x/libcacard/Makefile                     |   42 +
 qemu-0.15.x/libcacard/cac.c                        |  403 +
 qemu-0.15.x/libcacard/cac.h                        |   23 +
 qemu-0.15.x/libcacard/card_7816.c                  |  763 ++
 qemu-0.15.x/libcacard/card_7816.h                  |   62 +
 qemu-0.15.x/libcacard/card_7816t.h                 |  165 +
 qemu-0.15.x/libcacard/event.c                      |  106 +
 qemu-0.15.x/libcacard/eventt.h                     |   29 +
 qemu-0.15.x/libcacard/link_test.c                  |   22 +
 qemu-0.15.x/libcacard/vcard.c                      |  339 +
 qemu-0.15.x/libcacard/vcard.h                      |   86 +
 qemu-0.15.x/libcacard/vcard_emul.h                 |   65 +
 qemu-0.15.x/libcacard/vcard_emul_nss.c             | 1157 ++
 qemu-0.15.x/libcacard/vcard_emul_type.c            |   57 +
 qemu-0.15.x/libcacard/vcard_emul_type.h            |   32 +
 qemu-0.15.x/libcacard/vcardt.h                     |   64 +
 qemu-0.15.x/libcacard/vevent.h                     |   27 +
 qemu-0.15.x/libcacard/vreader.c                    |  513 +
 qemu-0.15.x/libcacard/vreader.h                    |   55 +
 qemu-0.15.x/libcacard/vreadert.h                   |   24 +
 qemu-0.15.x/libcacard/vscard_common.h              |  178 +
 qemu-0.15.x/libcacard/vscclient.c                  |  652 +
 qemu-0.15.x/libfdt_env.h                           |   36 +
 qemu-0.15.x/linux-aio.c                            |  261 +
 qemu-0.15.x/linux-headers/COPYING                  |  356 +
 qemu-0.15.x/linux-headers/README                   |    2 +
 qemu-0.15.x/linux-headers/asm-powerpc/kvm.h        |  275 +
 qemu-0.15.x/linux-headers/asm-powerpc/kvm_para.h   |   53 +
 qemu-0.15.x/linux-headers/asm-s390/kvm.h           |   44 +
 qemu-0.15.x/linux-headers/asm-s390/kvm_para.h      |   17 +
 qemu-0.15.x/linux-headers/asm-x86/hyperv.h         |  193 +
 qemu-0.15.x/linux-headers/asm-x86/kvm.h            |  324 +
 qemu-0.15.x/linux-headers/asm-x86/kvm_para.h       |   79 +
 qemu-0.15.x/linux-headers/linux/kvm.h              |  804 ++
 qemu-0.15.x/linux-headers/linux/kvm_para.h         |   28 +
 qemu-0.15.x/linux-headers/linux/vhost.h            |  130 +
 qemu-0.15.x/linux-headers/linux/virtio_config.h    |   54 +
 qemu-0.15.x/linux-headers/linux/virtio_ring.h      |  163 +
 qemu-0.15.x/linux-user/alpha/syscall.h             |  253 +
 qemu-0.15.x/linux-user/alpha/syscall_nr.h          |  435 +
 qemu-0.15.x/linux-user/alpha/target_signal.h       |   56 +
 qemu-0.15.x/linux-user/alpha/termbits.h            |  264 +
 qemu-0.15.x/linux-user/arm/nwfpe/double_cpdo.c     |  295 +
 qemu-0.15.x/linux-user/arm/nwfpe/extended_cpdo.c   |  272 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11.c           |  237 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11.h           |  130 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11.inl         |   50 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdo.c      |  112 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdt.c      |  381 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cprt.c      |  283 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.c        |  112 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.h        |  390 +
 qemu-0.15.x/linux-user/arm/nwfpe/fpsr.h            |  107 +
 qemu-0.15.x/linux-user/arm/nwfpe/single_cpdo.c     |  252 +
 qemu-0.15.x/linux-user/arm/syscall.h               |   42 +
 qemu-0.15.x/linux-user/arm/syscall_nr.h            |  380 +
 qemu-0.15.x/linux-user/arm/target_signal.h         |   29 +
 qemu-0.15.x/linux-user/arm/termbits.h              |  216 +
 qemu-0.15.x/linux-user/cpu-uname.c                 |   72 +
 qemu-0.15.x/linux-user/cpu-uname.h                 |    1 +
 qemu-0.15.x/linux-user/cris/syscall.h              |   36 +
 qemu-0.15.x/linux-user/cris/syscall_nr.h           |  337 +
 qemu-0.15.x/linux-user/cris/target_signal.h        |   29 +
 qemu-0.15.x/linux-user/cris/termbits.h             |  213 +
 qemu-0.15.x/linux-user/elfload.c                   | 2703 +++++
 qemu-0.15.x/linux-user/errno_defs.h                |  141 +
 qemu-0.15.x/linux-user/flat.h                      |   67 +
 qemu-0.15.x/linux-user/flatload.c                  |  813 ++
 qemu-0.15.x/linux-user/i386/syscall.h              |  146 +
 qemu-0.15.x/linux-user/i386/syscall_nr.h           |  349 +
 qemu-0.15.x/linux-user/i386/target_signal.h        |   29 +
 qemu-0.15.x/linux-user/i386/termbits.h             |  226 +
 qemu-0.15.x/linux-user/ioctls.h                    |  347 +
 qemu-0.15.x/linux-user/linux_loop.h                |   95 +
 qemu-0.15.x/linux-user/linuxload.c                 |  184 +
 qemu-0.15.x/linux-user/m68k-sim.c                  |  170 +
 qemu-0.15.x/linux-user/m68k/syscall.h              |   21 +
 qemu-0.15.x/linux-user/m68k/syscall_nr.h           |  346 +
 qemu-0.15.x/linux-user/m68k/target_signal.h        |   29 +
 qemu-0.15.x/linux-user/m68k/termbits.h             |  227 +
 qemu-0.15.x/linux-user/main.c                      | 3569 ++++++
 qemu-0.15.x/linux-user/microblaze/syscall.h        |   45 +
 qemu-0.15.x/linux-user/microblaze/syscall_nr.h     |  379 +
 qemu-0.15.x/linux-user/microblaze/target_signal.h  |   29 +
 qemu-0.15.x/linux-user/microblaze/termbits.h       |  213 +
 qemu-0.15.x/linux-user/mips/syscall.h              |  227 +
 qemu-0.15.x/linux-user/mips/syscall_nr.h           |  347 +
 qemu-0.15.x/linux-user/mips/target_signal.h        |   29 +
 qemu-0.15.x/linux-user/mips/termbits.h             |  245 +
 qemu-0.15.x/linux-user/mips64/syscall.h            |  221 +
 qemu-0.15.x/linux-user/mips64/syscall_nr.h         |  306 +
 qemu-0.15.x/linux-user/mips64/target_signal.h      |   29 +
 qemu-0.15.x/linux-user/mips64/termbits.h           |  245 +
 qemu-0.15.x/linux-user/mipsn32/syscall.h           |  221 +
 qemu-0.15.x/linux-user/mipsn32/syscall_nr.h        |  311 +
 qemu-0.15.x/linux-user/mipsn32/target_signal.h     |   29 +
 qemu-0.15.x/linux-user/mipsn32/termbits.h          |  245 +
 qemu-0.15.x/linux-user/mmap.c                      |  763 ++
 qemu-0.15.x/linux-user/ppc/syscall.h               |   64 +
 qemu-0.15.x/linux-user/ppc/syscall_nr.h            |  364 +
 qemu-0.15.x/linux-user/ppc/target_signal.h         |   29 +
 qemu-0.15.x/linux-user/ppc/termbits.h              |  236 +
 qemu-0.15.x/linux-user/qemu-types.h                |   24 +
 qemu-0.15.x/linux-user/qemu.h                      |  451 +
 qemu-0.15.x/linux-user/s390x/syscall.h             |   23 +
 qemu-0.15.x/linux-user/s390x/syscall_nr.h          |  358 +
 qemu-0.15.x/linux-user/s390x/target_signal.h       |   26 +
 qemu-0.15.x/linux-user/s390x/termbits.h            |  283 +
 qemu-0.15.x/linux-user/sh4/syscall.h               |   12 +
 qemu-0.15.x/linux-user/sh4/syscall_nr.h            |  368 +
 qemu-0.15.x/linux-user/sh4/target_signal.h         |   29 +
 qemu-0.15.x/linux-user/sh4/termbits.h              |  274 +
 qemu-0.15.x/linux-user/signal.c                    | 5316 ++++++++
 qemu-0.15.x/linux-user/socket.h                    |  147 +
 qemu-0.15.x/linux-user/sparc/syscall.h             |    9 +
 qemu-0.15.x/linux-user/sparc/syscall_nr.h          |  299 +
 qemu-0.15.x/linux-user/sparc/target_signal.h       |   36 +
 qemu-0.15.x/linux-user/sparc/termbits.h            |  279 +
 qemu-0.15.x/linux-user/sparc64/syscall.h           |   10 +
 qemu-0.15.x/linux-user/sparc64/syscall_nr.h        |  336 +
 qemu-0.15.x/linux-user/sparc64/target_signal.h     |   36 +
 qemu-0.15.x/linux-user/sparc64/termbits.h          |  279 +
 qemu-0.15.x/linux-user/strace.c                    | 1532 +++
 qemu-0.15.x/linux-user/strace.list                 | 1529 +++
 qemu-0.15.x/linux-user/syscall.c                   | 8109 +++++++++++++
 qemu-0.15.x/linux-user/syscall_defs.h              | 2333 ++++
 qemu-0.15.x/linux-user/syscall_types.h             |  203 +
 qemu-0.15.x/linux-user/target_flat.h               |   10 +
 qemu-0.15.x/linux-user/uaccess.c                   |   65 +
 qemu-0.15.x/linux-user/unicore32/syscall.h         |   55 +
 qemu-0.15.x/linux-user/unicore32/syscall_nr.h      |  371 +
 qemu-0.15.x/linux-user/unicore32/target_signal.h   |   26 +
 qemu-0.15.x/linux-user/unicore32/termbits.h        |    2 +
 qemu-0.15.x/linux-user/vm86.c                      |  481 +
 qemu-0.15.x/linux-user/x86_64/syscall.h            |   98 +
 qemu-0.15.x/linux-user/x86_64/syscall_nr.h         |  307 +
 qemu-0.15.x/linux-user/x86_64/target_signal.h      |   29 +
 qemu-0.15.x/linux-user/x86_64/termbits.h           |  247 +
 qemu-0.15.x/m68k-dis.c                             | 5051 ++++++++
 qemu-0.15.x/m68k-semi.c                            |  408 +
 qemu-0.15.x/m68k.ld                                |  175 +
 qemu-0.15.x/microblaze-dis.c                       | 1100 ++
 qemu-0.15.x/migration-exec.c                       |  144 +
 qemu-0.15.x/migration-fd.c                         |  129 +
 qemu-0.15.x/migration-tcp.c                        |  203 +
 qemu-0.15.x/migration-unix.c                       |  214 +
 qemu-0.15.x/migration.c                            |  482 +
 qemu-0.15.x/migration.h                            |  151 +
 qemu-0.15.x/mips-dis.c                             | 4873 ++++++++
 qemu-0.15.x/mips.ld                                |  222 +
 qemu-0.15.x/module.c                               |   80 +
 qemu-0.15.x/module.h                               |   40 +
 qemu-0.15.x/monitor.c                              | 5333 ++++++++
 qemu-0.15.x/monitor.h                              |   65 +
 qemu-0.15.x/nbd.c                                  |  666 +
 qemu-0.15.x/nbd.h                                  |   69 +
 qemu-0.15.x/net.c                                  | 1433 +++
 qemu-0.15.x/net.h                                  |  182 +
 qemu-0.15.x/net/checksum.c                         |   85 +
 qemu-0.15.x/net/checksum.h                         |   29 +
 qemu-0.15.x/net/dump.c                             |  159 +
 qemu-0.15.x/net/dump.h                             |   33 +
 qemu-0.15.x/net/queue.c                            |  260 +
 qemu-0.15.x/net/queue.h                            |   71 +
 qemu-0.15.x/net/slirp.c                            |  779 ++
 qemu-0.15.x/net/slirp.h                            |   51 +
 qemu-0.15.x/net/socket.c                           |  606 +
 qemu-0.15.x/net/socket.h                           |   33 +
 qemu-0.15.x/net/tap-aix.c                          |   61 +
 qemu-0.15.x/net/tap-bsd.c                          |  131 +
 qemu-0.15.x/net/tap-haiku.c                        |   61 +
 qemu-0.15.x/net/tap-linux.c                        |  195 +
 qemu-0.15.x/net/tap-linux.h                        |   63 +
 qemu-0.15.x/net/tap-solaris.c                      |  227 +
 qemu-0.15.x/net/tap-win32.c                        |  751 ++
 qemu-0.15.x/net/tap.c                              |  524 +
 qemu-0.15.x/net/tap.h                              |   60 +
 qemu-0.15.x/net/util.c                             |   60 +
 qemu-0.15.x/net/util.h                             |   32 +
 qemu-0.15.x/net/vde.c                              |  130 +
 qemu-0.15.x/net/vde.h                              |   36 +
 qemu-0.15.x/notify.c                               |   39 +
 qemu-0.15.x/notify.h                               |   43 +
 qemu-0.15.x/os-posix.c                             |  392 +
 qemu-0.15.x/os-win32.c                             |  273 +
 qemu-0.15.x/osdep.c                                |  168 +
 qemu-0.15.x/osdep.h                                |  157 +
 qemu-0.15.x/oslib-posix.c                          |  173 +
 qemu-0.15.x/oslib-win32.c                          |  114 +
 qemu-0.15.x/path.c                                 |  181 +
 qemu-0.15.x/pc-bios/Makefile                       |   19 +
 qemu-0.15.x/pc-bios/README                         |   34 +
 qemu-0.15.x/pc-bios/bamboo.dtb                     |  Bin 0 -> 3179 bytes
 qemu-0.15.x/pc-bios/bamboo.dts                     |  234 +
 qemu-0.15.x/pc-bios/bios.bin                       |  Bin 0 -> 131072 bytes
 qemu-0.15.x/pc-bios/keymaps/ar                     |   98 +
 qemu-0.15.x/pc-bios/keymaps/bepo                   |  333 +
 qemu-0.15.x/pc-bios/keymaps/common                 |  157 +
 qemu-0.15.x/pc-bios/keymaps/da                     |  120 +
 qemu-0.15.x/pc-bios/keymaps/de                     |  114 +
 qemu-0.15.x/pc-bios/keymaps/de-ch                  |  169 +
 qemu-0.15.x/pc-bios/keymaps/en-gb                  |  119 +
 qemu-0.15.x/pc-bios/keymaps/en-us                  |   35 +
 qemu-0.15.x/pc-bios/keymaps/es                     |  105 +
 qemu-0.15.x/pc-bios/keymaps/et                     |   85 +
 qemu-0.15.x/pc-bios/keymaps/fi                     |  124 +
 qemu-0.15.x/pc-bios/keymaps/fo                     |   76 +
 qemu-0.15.x/pc-bios/keymaps/fr                     |  181 +
 qemu-0.15.x/pc-bios/keymaps/fr-be                  |  134 +
 qemu-0.15.x/pc-bios/keymaps/fr-ca                  |   50 +
 qemu-0.15.x/pc-bios/keymaps/fr-ch                  |  114 +
 qemu-0.15.x/pc-bios/keymaps/hr                     |  125 +
 qemu-0.15.x/pc-bios/keymaps/hu                     |  115 +
 qemu-0.15.x/pc-bios/keymaps/is                     |  139 +
 qemu-0.15.x/pc-bios/keymaps/it                     |  115 +
 qemu-0.15.x/pc-bios/keymaps/ja                     |  109 +
 qemu-0.15.x/pc-bios/keymaps/lt                     |   57 +
 qemu-0.15.x/pc-bios/keymaps/lv                     |  128 +
 qemu-0.15.x/pc-bios/keymaps/mk                     |  101 +
 qemu-0.15.x/pc-bios/keymaps/modifiers              |   18 +
 qemu-0.15.x/pc-bios/keymaps/nl                     |   59 +
 qemu-0.15.x/pc-bios/keymaps/nl-be                  |    3 +
 qemu-0.15.x/pc-bios/keymaps/no                     |  119 +
 qemu-0.15.x/pc-bios/keymaps/pl                     |  122 +
 qemu-0.15.x/pc-bios/keymaps/pt                     |  113 +
 qemu-0.15.x/pc-bios/keymaps/pt-br                  |   69 +
 qemu-0.15.x/pc-bios/keymaps/ru                     |  109 +
 qemu-0.15.x/pc-bios/keymaps/sl                     |  110 +
 qemu-0.15.x/pc-bios/keymaps/sv                     |   81 +
 qemu-0.15.x/pc-bios/keymaps/th                     |  131 +
 qemu-0.15.x/pc-bios/keymaps/tr                     |  123 +
 qemu-0.15.x/pc-bios/linuxboot.bin                  |  Bin 0 -> 1024 bytes
 qemu-0.15.x/pc-bios/mpc8544ds.dtb                  |  Bin 0 -> 2277 bytes
 qemu-0.15.x/pc-bios/mpc8544ds.dts                  |  131 +
 qemu-0.15.x/pc-bios/multiboot.bin                  |  Bin 0 -> 1024 bytes
 qemu-0.15.x/pc-bios/ohw.diff                       | 1843 +++
 qemu-0.15.x/pc-bios/openbios-ppc                   |  Bin 0 -> 750392 bytes
 qemu-0.15.x/pc-bios/openbios-sparc32               |  Bin 0 -> 381484 bytes
 qemu-0.15.x/pc-bios/openbios-sparc64               |  Bin 0 -> 1598328 bytes
 qemu-0.15.x/pc-bios/optionrom/Makefile             |   29 +
 qemu-0.15.x/pc-bios/optionrom/linuxboot.S          |  139 +
 qemu-0.15.x/pc-bios/optionrom/multiboot.S          |  186 +
 qemu-0.15.x/pc-bios/optionrom/optionrom.h          |  136 +
 qemu-0.15.x/pc-bios/petalogix-ml605.dtb            |  Bin 0 -> 9982 bytes
 qemu-0.15.x/pc-bios/petalogix-s3adsp1800.dtb       |  Bin 0 -> 8259 bytes
 qemu-0.15.x/pc-bios/ppc_rom.bin                    |  Bin 0 -> 524288 bytes
 qemu-0.15.x/pc-bios/pxe-e1000.rom                  |  Bin 0 -> 67072 bytes
 qemu-0.15.x/pc-bios/pxe-eepro100.rom               |  Bin 0 -> 61440 bytes
 qemu-0.15.x/pc-bios/pxe-ne2k_pci.rom               |  Bin 0 -> 61440 bytes
 qemu-0.15.x/pc-bios/pxe-pcnet.rom                  |  Bin 0 -> 61440 bytes
 qemu-0.15.x/pc-bios/pxe-rtl8139.rom                |  Bin 0 -> 61440 bytes
 qemu-0.15.x/pc-bios/pxe-virtio.rom                 |  Bin 0 -> 60416 bytes
 qemu-0.15.x/pc-bios/s390-zipl.rom                  |  Bin 0 -> 3304 bytes
 qemu-0.15.x/pc-bios/slof.bin                       |  Bin 0 -> 579072 bytes
 qemu-0.15.x/pc-bios/spapr-rtas.bin                 |  Bin 0 -> 20 bytes
 qemu-0.15.x/pc-bios/spapr-rtas/Makefile            |   24 +
 qemu-0.15.x/pc-bios/spapr-rtas/spapr-rtas.S        |   37 +
 qemu-0.15.x/pc-bios/vgabios-cirrus.bin             |  Bin 0 -> 35840 bytes
 qemu-0.15.x/pc-bios/vgabios-qxl.bin                |  Bin 0 -> 40448 bytes
 qemu-0.15.x/pc-bios/vgabios-stdvga.bin             |  Bin 0 -> 40448 bytes
 qemu-0.15.x/pc-bios/vgabios-vmware.bin             |  Bin 0 -> 40448 bytes
 qemu-0.15.x/pc-bios/vgabios.bin                    |  Bin 0 -> 40448 bytes
 qemu-0.15.x/pci-ids.txt                            |   31 +
 qemu-0.15.x/pflib.c                                |  213 +
 qemu-0.15.x/pflib.h                                |   20 +
 qemu-0.15.x/poison.h                               |   63 +
 qemu-0.15.x/posix-aio-compat.c                     |  663 +
 qemu-0.15.x/ppc-dis.c                              | 5412 +++++++++
 qemu-0.15.x/ppc.ld                                 |  225 +
 qemu-0.15.x/ppc64.ld                               |  218 +
 qemu-0.15.x/qapi-schema-guest.json                 |  217 +
 qemu-0.15.x/qapi-schema-test.json                  |   22 +
 qemu-0.15.x/qapi/qapi-dealloc-visitor.c            |  147 +
 qemu-0.15.x/qapi/qapi-dealloc-visitor.h            |   26 +
 qemu-0.15.x/qapi/qapi-types-core.h                 |   20 +
 qemu-0.15.x/qapi/qapi-visit-core.c                 |  118 +
 qemu-0.15.x/qapi/qapi-visit-core.h                 |   76 +
 qemu-0.15.x/qapi/qmp-core.h                        |   41 +
 qemu-0.15.x/qapi/qmp-dispatch.c                    |  124 +
 qemu-0.15.x/qapi/qmp-input-visitor.c               |  301 +
 qemu-0.15.x/qapi/qmp-input-visitor.h               |   27 +
 qemu-0.15.x/qapi/qmp-output-visitor.c              |  239 +
 qemu-0.15.x/qapi/qmp-output-visitor.h              |   28 +
 qemu-0.15.x/qapi/qmp-registry.c                    |   40 +
 qemu-0.15.x/qbool.c                                |   68 +
 qemu-0.15.x/qbool.h                                |   29 +
 qemu-0.15.x/qdict-test-data.txt                    | 4999 ++++++++
 qemu-0.15.x/qdict.c                                |  456 +
 qemu-0.15.x/qdict.h                                |   67 +
 qemu-0.15.x/qemu-aio.h                             |   59 +
 qemu-0.15.x/qemu-barrier.h                         |   10 +
 qemu-0.15.x/qemu-char.c                            | 2700 +++++
 qemu-0.15.x/qemu-char.h                            |  130 +
 qemu-0.15.x/qemu-common.h                          |  376 +
 qemu-0.15.x/qemu-config.c                          |  703 ++
 qemu-0.15.x/qemu-config.h                          |   19 +
 qemu-0.15.x/qemu-doc.texi                          | 2717 +++++
 qemu-0.15.x/qemu-error.c                           |  210 +
 qemu-0.15.x/qemu-error.h                           |   40 +
 qemu-0.15.x/qemu-ga.c                              |  637 +
 qemu-0.15.x/qemu-img-cmds.hx                       |   59 +
 qemu-0.15.x/qemu-img.c                             | 1623 +++
 qemu-0.15.x/qemu-img.texi                          |  262 +
 qemu-0.15.x/qemu-io.c                              | 1840 +++
 qemu-0.15.x/qemu-lock.h                            |   49 +
 qemu-0.15.x/qemu-log.h                             |   93 +
 qemu-0.15.x/qemu-malloc.c                          |   98 +
 qemu-0.15.x/qemu-nbd.c                             |  499 +
 qemu-0.15.x/qemu-nbd.texi                          |   66 +
 qemu-0.15.x/qemu-objects.h                         |   25 +
 qemu-0.15.x/qemu-option.c                          |  977 ++
 qemu-0.15.x/qemu-option.h                          |  135 +
 qemu-0.15.x/qemu-options.h                         |   41 +
 qemu-0.15.x/qemu-options.hx                        | 2433 ++++
 qemu-0.15.x/qemu-os-posix.h                        |   54 +
 qemu-0.15.x/qemu-os-win32.h                        |   69 +
 qemu-0.15.x/qemu-progress.c                        |  150 +
 qemu-0.15.x/qemu-queue.h                           |  449 +
 qemu-0.15.x/qemu-sockets.c                         |  679 ++
 qemu-0.15.x/qemu-tech.texi                         |  697 ++
 qemu-0.15.x/qemu-thread-posix.c                    |  149 +
 qemu-0.15.x/qemu-thread-posix.h                    |   17 +
 qemu-0.15.x/qemu-thread-win32.c                    |  281 +
 qemu-0.15.x/qemu-thread-win32.h                    |   21 +
 qemu-0.15.x/qemu-thread.h                          |   41 +
 qemu-0.15.x/qemu-timer-common.c                    |   63 +
 qemu-0.15.x/qemu-timer.c                           | 1218 ++
 qemu-0.15.x/qemu-timer.h                           |  341 +
 qemu-0.15.x/qemu-tool.c                            |   98 +
 qemu-0.15.x/qemu-x509.h                            |    9 +
 qemu-0.15.x/qemu.sasl                              |   34 +
 qemu-0.15.x/qemu_socket.h                          |   59 +
 qemu-0.15.x/qerror.c                               |  505 +
 qemu-0.15.x/qerror.h                               |  196 +
 qemu-0.15.x/qfloat.c                               |   68 +
 qemu-0.15.x/qfloat.h                               |   29 +
 qemu-0.15.x/qga/guest-agent-command-state.c        |   73 +
 qemu-0.15.x/qga/guest-agent-commands.c             |  561 +
 qemu-0.15.x/qga/guest-agent-core.h                 |   31 +
 qemu-0.15.x/qint.c                                 |   67 +
 qemu-0.15.x/qint.h                                 |   28 +
 qemu-0.15.x/qjson.c                                |  294 +
 qemu-0.15.x/qjson.h                                |   28 +
 qemu-0.15.x/qlist.c                                |  157 +
 qemu-0.15.x/qlist.h                                |   64 +
 qemu-0.15.x/qmp-commands.hx                        | 1868 +++
 qemu-0.15.x/qobject.h                              |  112 +
 qemu-0.15.x/qstring.c                              |  141 +
 qemu-0.15.x/qstring.h                              |   35 +
 qemu-0.15.x/range.h                                |   29 +
 qemu-0.15.x/readline.c                             |  476 +
 qemu-0.15.x/readline.h                             |   55 +
 qemu-0.15.x/roms/SLOF/.gitignore                   |    6 +
 qemu-0.15.x/roms/SLOF/INSTALL                      |   93 +
 qemu-0.15.x/roms/SLOF/LICENSE                      |    8 +
 qemu-0.15.x/roms/SLOF/Makefile                     |  133 +
 qemu-0.15.x/roms/SLOF/Makefile.gen                 |  213 +
 qemu-0.15.x/roms/SLOF/README                       |  153 +
 qemu-0.15.x/roms/SLOF/board-js2x/Makefile          |   85 +
 qemu-0.15.x/roms/SLOF/board-js2x/Makefile.dirs     |   41 +
 qemu-0.15.x/roms/SLOF/board-js2x/config            |    7 +
 qemu-0.15.x/roms/SLOF/board-js2x/include/bmc.h     |   29 +
 qemu-0.15.x/roms/SLOF/board-js2x/include/hw.h      |   27 +
 .../roms/SLOF/board-js2x/include/nvramlog.h        |   65 +
 qemu-0.15.x/roms/SLOF/board-js2x/include/product.h |   31 +
 .../roms/SLOF/board-js2x/include/southbridge.h     |   28 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/Cboot.S      |   18 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/Makefile     |   61 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/board_io.S   |   62 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/hw.c         |  124 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.c     |  284 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.h     |   23 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.lds   |   56 +
 .../roms/SLOF/board-js2x/llfw/stage2_head.S        |   91 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.S    |   43 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.lds  |   22 +
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/startup.S    |  708 ++
 qemu-0.15.x/roms/SLOF/board-js2x/llfw/u4mem.c      | 4062 +++++++
 .../roms/SLOF/board-js2x/romfs/boot_rom.ffs        |   23 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/Makefile     |   89 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.c |  216 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.h |   45 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.c |  614 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.h |   18 +
 .../roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h       |   27 +
 .../roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h      |   21 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_out.c   |  114 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_pci.c   |  111 +
 qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_table.c |   45 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/Makefile     |  110 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/OF.fs        |  546 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/attu.fs      |  101 +
 .../roms/SLOF/board-js2x/slof/citrine-disk.fs      |   79 +
 .../roms/SLOF/board-js2x/slof/citrine-flash.fs     |   36 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine.fs   |  242 +
 .../roms/SLOF/board-js2x/slof/copyright-oss.fs     |   16 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/cpu.fs       |   44 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/dart.fs      |   31 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/flash.fs     |   43 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/freq.fs      |   39 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/header.fs    |   21 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/helper.fs    |   28 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/ht.fs        |  189 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/i2c.fs       |   77 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/io.fs        |   26 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/ioapic.fs    |   36 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-kcs.fs  |   57 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-vpd.fs  |   98 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/memory.fs    |   52 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/mpic.fs      |   31 +
 .../roms/SLOF/board-js2x/slof/pci-aliases.fs       |   85 +
 .../SLOF/board-js2x/slof/pci-bridge_1022_7460.fs   |  193 +
 .../roms/SLOF/board-js2x/slof/pci-capabilities.fs  |   23 +
 .../roms/SLOF/board-js2x/slof/pci-class_03.fs      |   55 +
 .../SLOF/board-js2x/slof/pci-device_1002_515e.fs   |  504 +
 .../SLOF/board-js2x/slof/pci-device_1014_028c.fs   |   25 +
 .../SLOF/board-js2x/slof/pci-device_1014_02bd.fs   |   23 +
 .../SLOF/board-js2x/slof/pci-device_1022_7451.fs   |   34 +
 .../SLOF/board-js2x/slof/pci-device_1022_7468.fs   |   50 +
 .../SLOF/board-js2x/slof/pci-device_1022_7469.fs   |   23 +
 .../roms/SLOF/board-js2x/slof/pci-interrupts.fs    |  235 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/rtas.fs      |  242 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/rtc.fs       |   59 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/serial.fs    |   48 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/sio.fs       |   85 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/tpm.fs       |   63 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/tree.fs      |  227 +
 qemu-0.15.x/roms/SLOF/board-js2x/slof/u4-mem.fs    |  313 +
 .../roms/SLOF/board-js2x/slof/vga-display.fs       |  215 +
 qemu-0.15.x/roms/SLOF/board-qemu/Makefile          |   76 +
 qemu-0.15.x/roms/SLOF/board-qemu/Makefile.dirs     |   41 +
 qemu-0.15.x/roms/SLOF/board-qemu/config            |    7 +
 qemu-0.15.x/roms/SLOF/board-qemu/include/hw.h      |   27 +
 .../roms/SLOF/board-qemu/include/nvramlog.h        |   65 +
 qemu-0.15.x/roms/SLOF/board-qemu/include/product.h |   31 +
 .../roms/SLOF/board-qemu/include/southbridge.h     |   20 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/Cboot.S      |   18 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/Makefile     |   56 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/board_io.S   |   46 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.c     |  186 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.h     |   23 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.lds   |   55 +
 .../roms/SLOF/board-qemu/llfw/stage2_head.S        |   95 +
 qemu-0.15.x/roms/SLOF/board-qemu/llfw/startup.S    |  258 +
 .../roms/SLOF/board-qemu/romfs/boot_rom.ffs        |   21 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/Makefile     |   96 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/OF.fs        |  160 +
 .../roms/SLOF/board-qemu/slof/copyright-oss.fs     |   16 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/fdt.fs       |  251 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/header.fs    |   22 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/helper.fs    |   35 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/hvterm.fs    |   26 +
 .../roms/SLOF/board-qemu/slof/qemu-bootlist.fs     |   38 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/rtas.fs      |  126 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/tree.fs      |  150 +
 .../roms/SLOF/board-qemu/slof/vio-hvterm.fs        |   32 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-veth.fs  |   41 +
 .../roms/SLOF/board-qemu/slof/vio-vscsi-device.fs  |   72 +
 qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi.fs |  623 +
 qemu-0.15.x/roms/SLOF/board-qemu/veth/Makefile     |   50 +
 .../roms/SLOF/board-qemu/veth/module_entry.c       |   44 +
 qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.c       |  280 +
 qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.lds     |   39 +
 qemu-0.15.x/roms/SLOF/clients/Makefile             |   29 +
 qemu-0.15.x/roms/SLOF/clients/clients.mk           |   13 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/Makefile     |   66 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/app/Makefile |   51 +
 .../roms/SLOF/clients/net-snk/app/biosemu/Makefile |   38 +
 .../SLOF/clients/net-snk/app/biosemu/biosemu.c     |  345 +
 .../SLOF/clients/net-snk/app/biosemu/biosemu.h     |   40 +
 .../roms/SLOF/clients/net-snk/app/biosemu/debug.c  |   55 +
 .../roms/SLOF/clients/net-snk/app/biosemu/debug.h  |   74 +
 .../roms/SLOF/clients/net-snk/app/biosemu/device.c |  327 +
 .../roms/SLOF/clients/net-snk/app/biosemu/device.h |  155 +
 .../SLOF/clients/net-snk/app/biosemu/interrupt.c   |  607 +
 .../SLOF/clients/net-snk/app/biosemu/interrupt.h   |   21 +
 .../roms/SLOF/clients/net-snk/app/biosemu/io.c     |  431 +
 .../roms/SLOF/clients/net-snk/app/biosemu/io.h     |   30 +
 .../roms/SLOF/clients/net-snk/app/biosemu/mem.c    |  463 +
 .../roms/SLOF/clients/net-snk/app/biosemu/mem.h    |   36 +
 .../roms/SLOF/clients/net-snk/app/biosemu/vbe.c    |  775 ++
 .../roms/SLOF/clients/net-snk/app/biosemu/vbe.h    |   16 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/app/main.c   |   78 +
 .../roms/SLOF/clients/net-snk/app/netapps/Makefile |   29 +
 .../roms/SLOF/clients/net-snk/app/netapps/args.c   |  142 +
 .../roms/SLOF/clients/net-snk/app/netapps/args.h   |   22 +
 .../SLOF/clients/net-snk/app/netapps/netapps.h     |   19 +
 .../SLOF/clients/net-snk/app/netapps/netboot.c     |  662 +
 .../SLOF/clients/net-snk/app/netapps/netflash.c    |  187 +
 .../roms/SLOF/clients/net-snk/app/netapps/ping.c   |  193 +
 .../roms/SLOF/clients/net-snk/app/netlib/Makefile  |   42 +
 .../roms/SLOF/clients/net-snk/app/netlib/bootp.c   |  248 +
 .../roms/SLOF/clients/net-snk/app/netlib/dhcp.c    |  993 ++
 .../roms/SLOF/clients/net-snk/app/netlib/dhcp.h    |   53 +
 .../roms/SLOF/clients/net-snk/app/netlib/dns.c     |  485 +
 .../roms/SLOF/clients/net-snk/app/netlib/dns.h     |   28 +
 .../SLOF/clients/net-snk/app/netlib/ethernet.c     |  186 +
 .../SLOF/clients/net-snk/app/netlib/ethernet.h     |   47 +
 .../roms/SLOF/clients/net-snk/app/netlib/ipv4.c    |  871 ++
 .../roms/SLOF/clients/net-snk/app/netlib/ipv4.h    |   96 +
 .../roms/SLOF/clients/net-snk/app/netlib/tcp.c     |   50 +
 .../roms/SLOF/clients/net-snk/app/netlib/tcp.h     |   27 +
 .../roms/SLOF/clients/net-snk/app/netlib/tftp.c    |  597 +
 .../roms/SLOF/clients/net-snk/app/netlib/tftp.h    |   48 +
 .../roms/SLOF/clients/net-snk/app/netlib/udp.c     |  153 +
 .../roms/SLOF/clients/net-snk/app/netlib/udp.h     |   58 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/client.lds   |   51 +
 .../roms/SLOF/clients/net-snk/include/crt0.h       |   20 +
 .../roms/SLOF/clients/net-snk/include/endian.h     |   46 +
 .../roms/SLOF/clients/net-snk/include/fcntl.h      |   25 +
 .../roms/SLOF/clients/net-snk/include/fileio.h     |   53 +
 .../roms/SLOF/clients/net-snk/include/ioctl.h      |   19 +
 .../roms/SLOF/clients/net-snk/include/kernel.h     |   32 +
 .../roms/SLOF/clients/net-snk/include/macros.h     |   72 +
 .../SLOF/clients/net-snk/include/netdriver_int.h   |  192 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/include/of.h |   56 +
 .../roms/SLOF/clients/net-snk/include/pci.h        |   26 +
 .../roms/SLOF/clients/net-snk/include/rtas.h       |   45 +
 .../roms/SLOF/clients/net-snk/include/sys/socket.h |   55 +
 .../roms/SLOF/clients/net-snk/include/systemcall.h |  148 +
 .../roms/SLOF/clients/net-snk/include/time.h       |   36 +
 .../roms/SLOF/clients/net-snk/include/types.h      |   26 +
 .../roms/SLOF/clients/net-snk/kernel/Makefile      |   31 +
 .../roms/SLOF/clients/net-snk/kernel/crt0.c        |   74 +
 .../roms/SLOF/clients/net-snk/kernel/endian.c      |   30 +
 .../roms/SLOF/clients/net-snk/kernel/entry.S       |  167 +
 .../roms/SLOF/clients/net-snk/kernel/init.c        |  143 +
 .../roms/SLOF/clients/net-snk/kernel/lowmem.S      |  186 +
 .../roms/SLOF/clients/net-snk/kernel/modules.c     |  208 +
 .../roms/SLOF/clients/net-snk/kernel/systemcall.c  |  285 +
 .../roms/SLOF/clients/net-snk/kernel/timer.c       |   67 +
 .../roms/SLOF/clients/net-snk/libc/Makefile        |   44 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/libc/io.c    |   42 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/libc/ioctl.c |   20 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/libc/sbrk.c  |   37 +
 .../roms/SLOF/clients/net-snk/libc/socket/Makefile |   39 +
 .../roms/SLOF/clients/net-snk/libc/socket/send.c   |   36 +
 .../roms/SLOF/clients/net-snk/libc/time/Makefile   |   39 +
 .../roms/SLOF/clients/net-snk/libc/time/ftime.c    |   38 +
 .../roms/SLOF/clients/net-snk/libc/time/timer.c    |   39 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/make.rules   |   26 +
 .../roms/SLOF/clients/net-snk/oflib/Makefile       |   41 +
 .../roms/SLOF/clients/net-snk/oflib/entry.S        |   37 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/of.c   |  886 ++
 qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/pci.c  |   86 +
 qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/rtas.c |  334 +
 .../roms/SLOF/clients/net-snk/sec-client.lds       |   50 +
 qemu-0.15.x/roms/SLOF/clients/takeover/Makefile    |   59 +
 qemu-0.15.x/roms/SLOF/clients/takeover/client.lds  |   60 +
 qemu-0.15.x/roms/SLOF/clients/takeover/entry.S     |   93 +
 qemu-0.15.x/roms/SLOF/clients/takeover/main.c      |  218 +
 qemu-0.15.x/roms/SLOF/clients/takeover/ppc32wrap.S |   30 +
 qemu-0.15.x/roms/SLOF/clients/takeover/takeover.h  |   23 +
 qemu-0.15.x/roms/SLOF/include/calculatecrc.h       |   66 +
 qemu-0.15.x/roms/SLOF/include/libelf.h             |   18 +
 qemu-0.15.x/roms/SLOF/include/macros.h             |   58 +
 qemu-0.15.x/roms/SLOF/include/memmap.h             |   26 +
 qemu-0.15.x/roms/SLOF/include/pcd.h                |   58 +
 qemu-0.15.x/roms/SLOF/include/ppc970/cache.h       |   40 +
 qemu-0.15.x/roms/SLOF/include/ppc970/cpu.h         |  103 +
 qemu-0.15.x/roms/SLOF/include/ppcp7/cache.h        |   62 +
 qemu-0.15.x/roms/SLOF/include/ppcp7/cpu.h          |   50 +
 qemu-0.15.x/roms/SLOF/include/romfs.h              |   60 +
 qemu-0.15.x/roms/SLOF/include/rtas.h               |   42 +
 qemu-0.15.x/roms/SLOF/include/rtas_table.h         |   32 +
 qemu-0.15.x/roms/SLOF/include/termctrl.h           |   62 +
 qemu-0.15.x/roms/SLOF/include/types.h              |   28 +
 qemu-0.15.x/roms/SLOF/include/xvect.h              |   21 +
 qemu-0.15.x/roms/SLOF/lib/Makefile                 |   35 +
 qemu-0.15.x/roms/SLOF/lib/libbases/Makefile        |   40 +
 qemu-0.15.x/roms/SLOF/lib/libbases/libbases.code   |   42 +
 qemu-0.15.x/roms/SLOF/lib/libbases/libbases.in     |   17 +
 qemu-0.15.x/roms/SLOF/lib/libbootmsg/Makefile      |   73 +
 qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.code  |   61 +
 qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.in    |   19 +
 qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S |  203 +
 qemu-0.15.x/roms/SLOF/lib/libbootmsg/libbootmsg.h  |   21 +
 qemu-0.15.x/roms/SLOF/lib/libc/Makefile            |   61 +
 qemu-0.15.x/roms/SLOF/lib/libc/README.txt          |   49 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/Makefile.inc  |   20 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/isdigit.c     |   25 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/isprint.c     |   18 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/isspace.c     |   29 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/isxdigit.c    |   21 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/tolower.c     |   18 +
 qemu-0.15.x/roms/SLOF/lib/libc/ctype/toupper.c     |   21 +
 qemu-0.15.x/roms/SLOF/lib/libc/getopt/Makefile.inc |   17 +
 qemu-0.15.x/roms/SLOF/lib/libc/getopt/getopt.c     |  470 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/ctype.h     |   24 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/errno.h     |   34 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/getopt.h    |   37 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/limits.h    |   32 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/stdarg.h    |   22 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/stddef.h    |   25 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/stdint.h    |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/stdio.h     |   63 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/stdlib.h    |   33 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/string.h    |   36 +
 qemu-0.15.x/roms/SLOF/lib/libc/include/unistd.h    |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/Makefile.inc  |   23 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/fileno.c      |   19 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/fprintf.c     |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/fscanf.c      |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/printf.c      |   27 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/putc.c        |   25 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/putchar.c     |   21 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/puts.c        |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/scanf.c       |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/setvbuf.c     |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/sprintf.c     |   30 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/stdchnls.c    |   23 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfprintf.c    |   27 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfscanf.c     |  266 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsnprintf.c   |  242 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsprintf.c    |   19 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsscanf.c     |  131 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/Makefile.inc |   22 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atoi.c       |   18 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atol.c       |   18 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/error.c      |   15 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/free.c       |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc.c     |  157 +
 .../roms/SLOF/lib/libc/stdlib/malloc_defs.h        |   16 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/memalign.c   |   26 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/rand.c       |   24 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/realloc.c    |   40 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtol.c     |  113 +
 qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtoul.c    |  103 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/Makefile.inc |   22 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/memchr.c     |   29 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/memcmp.c     |   30 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/memcpy.c     |   27 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/memmove.c    |   42 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/memset.c     |   25 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strcasecmp.c |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strcat.c     |   24 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strchr.c     |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strcmp.c     |   28 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strcpy.c     |   25 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strlen.c     |   27 +
 .../roms/SLOF/lib/libc/string/strncasecmp.c        |   32 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strncmp.c    |   31 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strncpy.c    |   33 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strstr.c     |   37 +
 qemu-0.15.x/roms/SLOF/lib/libc/string/strtok.c     |   45 +
 qemu-0.15.x/roms/SLOF/lib/libelf/Makefile          |   47 +
 qemu-0.15.x/roms/SLOF/lib/libelf/elf.c             |  234 +
 qemu-0.15.x/roms/SLOF/lib/libelf/libelf.code       |   21 +
 qemu-0.15.x/roms/SLOF/lib/libelf/libelf.in         |   12 +
 qemu-0.15.x/roms/SLOF/lib/libhvcall/Makefile       |   53 +
 qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.S       |   86 +
 qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.code    |   51 +
 qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.in      |   18 +
 qemu-0.15.x/roms/SLOF/lib/libhvcall/libhvcall.h    |   65 +
 qemu-0.15.x/roms/SLOF/lib/libipmi/Makefile         |   28 +
 qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.code     |  120 +
 qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.h        |   33 +
 qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.in       |   24 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/Makefile        |   50 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/envvar.c        |  244 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.code   |  279 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.in     |   41 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.c         |  527 +
 qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.h         |   90 +
 qemu-0.15.x/roms/SLOF/llfw/boot_abort.S            |   95 +
 qemu-0.15.x/roms/SLOF/llfw/boot_abort.h            |   37 +
 qemu-0.15.x/roms/SLOF/llfw/clib/Makefile.inc       |   42 +
 qemu-0.15.x/roms/SLOF/llfw/clib/iolib.c            |   65 +
 qemu-0.15.x/roms/SLOF/llfw/clib/iolib.h            |   35 +
 qemu-0.15.x/roms/SLOF/llfw/io_generic/Makefile.inc |   38 +
 qemu-0.15.x/roms/SLOF/llfw/io_generic/io_generic.S |  129 +
 qemu-0.15.x/roms/SLOF/llfw/nvramlog.S              |  351 +
 qemu-0.15.x/roms/SLOF/llfw/romfs.S                 |  362 +
 qemu-0.15.x/roms/SLOF/llfw/romfs_wrap.c            |   22 +
 qemu-0.15.x/roms/SLOF/make.rules                   |   68 +
 qemu-0.15.x/roms/SLOF/other-licence/Makefile       |   31 +
 qemu-0.15.x/roms/SLOF/other-licence/bcm/Makefile   |   57 +
 qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.c  | 3428 ++++++
 qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.h  |  296 +
 qemu-0.15.x/roms/SLOF/other-licence/bcm/types.h    |   26 +
 .../roms/SLOF/other-licence/common/Makefile        |   44 +
 .../roms/SLOF/other-licence/common/module.lds      |   39 +
 .../roms/SLOF/other-licence/common/module_entry.c  |   64 +
 .../roms/SLOF/other-licence/x86emu/Makefile        |   46 +
 .../SLOF/other-licence/x86emu/x86emu_changes.diff  |  893 ++
 .../SLOF/other-licence/x86emu/x86emu_download.sh   |   60 +
 qemu-0.15.x/roms/SLOF/romfs/header.img             |    1 +
 qemu-0.15.x/roms/SLOF/romfs/tools/Makefile         |   55 +
 qemu-0.15.x/roms/SLOF/romfs/tools/build_ffs.c      |  476 +
 qemu-0.15.x/roms/SLOF/romfs/tools/cfg_parse.c      |  371 +
 qemu-0.15.x/roms/SLOF/romfs/tools/cfgparse.h       |   59 +
 qemu-0.15.x/roms/SLOF/romfs/tools/create_crc.c     |  467 +
 qemu-0.15.x/roms/SLOF/romfs/tools/create_flash.c   |  163 +
 qemu-0.15.x/roms/SLOF/romfs/tools/createcrc.h      |   19 +
 qemu-0.15.x/roms/SLOF/rtas/Makefile.inc            |   89 +
 qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.c     |  274 +
 qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.h     |   23 +
 .../roms/SLOF/rtas/flash/tmpXXX.update-comments    |   11 +
 qemu-0.15.x/roms/SLOF/rtas/reloc.S                 |  183 +
 qemu-0.15.x/roms/SLOF/rtas/rtas.lds                |   49 +
 qemu-0.15.x/roms/SLOF/rtas/rtas_call.c             |   89 +
 qemu-0.15.x/roms/SLOF/rtas/rtas_common.S           |   87 +
 qemu-0.15.x/roms/SLOF/rtas/rtas_entry.S            |   72 +
 qemu-0.15.x/roms/SLOF/slof/Makefile.inc            |  165 +
 qemu-0.15.x/roms/SLOF/slof/OF.lds                  |   65 +
 qemu-0.15.x/roms/SLOF/slof/default-font.c          | 1653 +++
 qemu-0.15.x/roms/SLOF/slof/engine.in               |  540 +
 qemu-0.15.x/roms/SLOF/slof/entry.S                 |  187 +
 qemu-0.15.x/roms/SLOF/slof/fs/accept.fs            |  410 +
 qemu-0.15.x/roms/SLOF/slof/fs/alloc-mem.fs         |   75 +
 qemu-0.15.x/roms/SLOF/slof/fs/available.fs         |   72 +
 qemu-0.15.x/roms/SLOF/slof/fs/banner.fs            |   23 +
 qemu-0.15.x/roms/SLOF/slof/fs/base.fs              |  558 +
 qemu-0.15.x/roms/SLOF/slof/fs/boot.fs              |  243 +
 qemu-0.15.x/roms/SLOF/slof/fs/bootmsg.fs           |   74 +
 qemu-0.15.x/roms/SLOF/slof/fs/claim.fs             |  406 +
 qemu-0.15.x/roms/SLOF/slof/fs/client.fs            |  208 +
 qemu-0.15.x/roms/SLOF/slof/fs/debug.fs             |  437 +
 .../roms/SLOF/slof/fs/devices/pci-class_02.fs      |   35 +
 .../roms/SLOF/slof/fs/devices/pci-class_0c.fs      |   39 +
 .../SLOF/slof/fs/devices/pci-device_10de_0141.fs   |   49 +
 qemu-0.15.x/roms/SLOF/slof/fs/dictionary.fs        |   74 +
 qemu-0.15.x/roms/SLOF/slof/fs/display.fs           |  123 +
 qemu-0.15.x/roms/SLOF/slof/fs/dump.fs              |   42 +
 qemu-0.15.x/roms/SLOF/slof/fs/elf.fs               |  305 +
 qemu-0.15.x/roms/SLOF/slof/fs/envvar.fs            |  421 +
 qemu-0.15.x/roms/SLOF/slof/fs/envvar_defaults.fs   |   44 +
 qemu-0.15.x/roms/SLOF/slof/fs/exception.fs         |  154 +
 qemu-0.15.x/roms/SLOF/slof/fs/fbuffer.fs           |  178 +
 qemu-0.15.x/roms/SLOF/slof/fs/fcode/1275.fs        |  353 +
 qemu-0.15.x/roms/SLOF/slof/fs/fcode/big.fs         |   45 +
 qemu-0.15.x/roms/SLOF/slof/fs/fcode/core.fs        |  169 +
 qemu-0.15.x/roms/SLOF/slof/fs/fcode/evaluator.fs   |   99 +
 qemu-0.15.x/roms/SLOF/slof/fs/fcode/tokens.fs      |  411 +
 qemu-0.15.x/roms/SLOF/slof/fs/find-hash.fs         |   77 +
 qemu-0.15.x/roms/SLOF/slof/fs/generic-disk.fs      |   68 +
 qemu-0.15.x/roms/SLOF/slof/fs/history.fs           |  107 +
 qemu-0.15.x/roms/SLOF/slof/fs/ide.fs               |  612 +
 qemu-0.15.x/roms/SLOF/slof/fs/instance.fs          |  130 +
 qemu-0.15.x/roms/SLOF/slof/fs/little-endian.fs     |   72 +
 qemu-0.15.x/roms/SLOF/slof/fs/loaders.fs           |   87 +
 qemu-0.15.x/roms/SLOF/slof/fs/logging.fs           |   45 +
 qemu-0.15.x/roms/SLOF/slof/fs/node.fs              |  478 +
 qemu-0.15.x/roms/SLOF/slof/fs/nvram.fs             |  189 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages.fs          |   62 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages/bulk.fs     |   87 +
 .../roms/SLOF/slof/fs/packages/deblocker.fs        |   61 +
 .../roms/SLOF/slof/fs/packages/disk-label.fs       |  521 +
 .../roms/SLOF/slof/fs/packages/ext2-files.fs       |  140 +
 .../roms/SLOF/slof/fs/packages/fat-files.fs        |  187 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages/filler.fs   |   21 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages/iso-9660.fs |  312 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages/obp-tftp.fs |   73 +
 .../roms/SLOF/slof/fs/packages/rom-files.fs        |   85 +
 qemu-0.15.x/roms/SLOF/slof/fs/packages/sms.fs      |   29 +
 qemu-0.15.x/roms/SLOF/slof/fs/pci-bridge.fs        |   62 +
 .../roms/SLOF/slof/fs/pci-class-code-names.fs      |  263 +
 qemu-0.15.x/roms/SLOF/slof/fs/pci-config-bridge.fs |   85 +
 qemu-0.15.x/roms/SLOF/slof/fs/pci-device.fs        |  101 +
 qemu-0.15.x/roms/SLOF/slof/fs/pci-properties.fs    |  650 +
 qemu-0.15.x/roms/SLOF/slof/fs/pci-scan.fs          |  495 +
 qemu-0.15.x/roms/SLOF/slof/fs/preprocessor.fs      |   41 +
 qemu-0.15.x/roms/SLOF/slof/fs/property.fs          |  189 +
 qemu-0.15.x/roms/SLOF/slof/fs/quiesce.fs           |   54 +
 qemu-0.15.x/roms/SLOF/slof/fs/rmove.fs             |   53 +
 qemu-0.15.x/roms/SLOF/slof/fs/romfs.fs             |  123 +
 qemu-0.15.x/roms/SLOF/slof/fs/root.fs              |   57 +
 qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-cpu.fs     |   23 +
 qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-flash.fs   |   46 +
 qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-init.fs    |  121 +
 qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-reboot.fs  |   33 +
 qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-vpd.fs     |   33 +
 qemu-0.15.x/roms/SLOF/slof/fs/scsi-loader.fs       |   77 +
 qemu-0.15.x/roms/SLOF/slof/fs/scsi-support.fs      |  809 ++
 qemu-0.15.x/roms/SLOF/slof/fs/search.fs            |   89 +
 qemu-0.15.x/roms/SLOF/slof/fs/slof-logo.fs         |   20 +
 qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-load.fs      |   70 +
 qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-nvram.fs     |  124 +
 qemu-0.15.x/roms/SLOF/slof/fs/stack.fs             |   57 +
 qemu-0.15.x/roms/SLOF/slof/fs/start-up.fs          |   92 +
 qemu-0.15.x/roms/SLOF/slof/fs/term-io.fs           |   95 +
 qemu-0.15.x/roms/SLOF/slof/fs/terminal.fs          |  196 +
 qemu-0.15.x/roms/SLOF/slof/fs/timebase.fs          |   24 +
 qemu-0.15.x/roms/SLOF/slof/fs/translate.fs         |  152 +
 qemu-0.15.x/roms/SLOF/slof/fs/update_flash.fs      |  110 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-enumerate.fs |  324 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-hub.fs       |  459 +
 .../SLOF/slof/fs/usb/usb-kbd-device-support.fs     |  102 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-keyboard.fs  |  371 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-mouse.fs     |   28 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-ohci.fs      | 1190 ++
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-static.fs    |  297 +
 .../roms/SLOF/slof/fs/usb/usb-storage-support.fs   |  155 +
 .../roms/SLOF/slof/fs/usb/usb-storage-wrapper.fs   |  181 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage.fs   |  639 +
 qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-support.fs   |  651 +
 qemu-0.15.x/roms/SLOF/slof/fs/vpd-bootlist.fs      |  134 +
 qemu-0.15.x/roms/SLOF/slof/fs/xmodem.fs            |  120 +
 qemu-0.15.x/roms/SLOF/slof/lowmem.S                |   69 +
 qemu-0.15.x/roms/SLOF/slof/ofw.S                   |   44 +
 qemu-0.15.x/roms/SLOF/slof/paflof.c                |  109 +
 qemu-0.15.x/roms/SLOF/slof/paflof.h                |   41 +
 qemu-0.15.x/roms/SLOF/slof/ppc64.c                 |  110 +
 qemu-0.15.x/roms/SLOF/slof/ppc64.code              |  264 +
 qemu-0.15.x/roms/SLOF/slof/ppc64.h                 |   41 +
 qemu-0.15.x/roms/SLOF/slof/ppc64.in                |  103 +
 qemu-0.15.x/roms/SLOF/slof/prep.h                  |   46 +
 qemu-0.15.x/roms/SLOF/slof/prim.code               |  634 +
 qemu-0.15.x/roms/SLOF/slof/prim.in                 |  110 +
 qemu-0.15.x/roms/SLOF/slof/ref.pl                  |  148 +
 qemu-0.15.x/roms/SLOF/slof/types.h                 |   49 +
 qemu-0.15.x/roms/SLOF/tools/Makefile               |   33 +
 qemu-0.15.x/roms/SLOF/tools/create_reloc_table.sh  |   60 +
 qemu-0.15.x/roms/SLOF/tools/gen_reloc_table.c      |   95 +
 qemu-0.15.x/roms/ipxe/COPYING                      |  339 +
 qemu-0.15.x/roms/ipxe/COPYRIGHTS                   |   12 +
 qemu-0.15.x/roms/ipxe/README                       |    8 +
 qemu-0.15.x/roms/ipxe/contrib/README               |    9 +
 qemu-0.15.x/roms/ipxe/contrib/errdb/.gitignore     |    1 +
 qemu-0.15.x/roms/ipxe/contrib/errdb/errdb.pl       |  108 +
 qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/README   |   62 +
 .../roms/ipxe/contrib/rom-o-matic/bottom.php       |   62 +
 .../roms/ipxe/contrib/rom-o-matic/build.php        |  306 +
 .../ipxe/contrib/rom-o-matic/customize-flags.php   |   69 +
 .../roms/ipxe/contrib/rom-o-matic/directions.php   |   63 +
 .../ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html |    1 +
 .../contrib/rom-o-matic/doc/BANNER_TIMEOUT.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html   |    3 +
 .../roms/ipxe/contrib/rom-o-matic/doc/COMDATA.html |    1 +
 .../ipxe/contrib/rom-o-matic/doc/COMPARITY.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html  |    1 +
 .../ipxe/contrib/rom-o-matic/doc/COMSPEED.html     |    1 +
 .../roms/ipxe/contrib/rom-o-matic/doc/COMSTOP.html |    1 +
 .../ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html   |    1 +
 .../contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html   |    1 +
 .../contrib/rom-o-matic/doc/CONSOLE_SERIAL.html    |    1 +
 .../contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html  |    1 +
 .../contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html  |    1 +
 .../contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html |    1 +
 .../ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html     |    1 +
 .../ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html |    1 +
 .../rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html        |    1 +
 .../rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html       |    1 +
 .../rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html       |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html   |    1 +
 .../contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html     |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html    |    1 +
 .../contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html   |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html |    1 +
 .../ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html   |    1 +
 .../ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html |    1 +
 .../roms/ipxe/contrib/rom-o-matic/doc/NVO_CMD.html |    1 +
 .../ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html    |    1 +
 .../ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html  |    1 +
 .../roms/ipxe/contrib/rom-o-matic/flag-table.php   |  499 +
 .../roms/ipxe/contrib/rom-o-matic/globals.php      |   51 +
 .../roms/ipxe/contrib/rom-o-matic/index.php        |   47 +
 qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/top.php  |   41 +
 .../roms/ipxe/contrib/rom-o-matic/utils.php        |  683 ++
 qemu-0.15.x/roms/ipxe/contrib/vm/.gitignore        |    6 +
 qemu-0.15.x/roms/ipxe/contrib/vm/Makefile          |    7 +
 .../roms/ipxe/contrib/vm/bochs-writable-ROM-patch  |   15 +
 qemu-0.15.x/roms/ipxe/contrib/vm/bochsrc.txt       |  751 ++
 qemu-0.15.x/roms/ipxe/contrib/vm/cow               |   49 +
 qemu-0.15.x/roms/ipxe/contrib/vm/serial-console    |  278 +
 qemu-0.15.x/roms/ipxe/contrib/vm/serial-console.1  |  190 +
 qemu-0.15.x/roms/ipxe/src/.gitignore               |    4 +
 qemu-0.15.x/roms/ipxe/src/Makefile                 |  177 +
 qemu-0.15.x/roms/ipxe/src/Makefile.housekeeping    | 1145 ++
 qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile       |  105 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.efi   |   10 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.linux |    6 +
 .../roms/ipxe/src/arch/i386/Makefile.pcbios        |   86 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/README.i386    |  197 +
 .../roms/ipxe/src/arch/i386/core/aout_loader.c     |  144 +
 .../roms/ipxe/src/arch/i386/core/basemem_packet.c  |   32 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/cmdline.c |  113 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/cpu.c     |   73 +
 .../roms/ipxe/src/arch/i386/core/dumpregs.c        |   23 +
 .../roms/ipxe/src/arch/i386/core/freebsd_loader.c  |  377 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbidt.S  |  215 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbmach.c |  151 +
 .../ipxe/src/arch/i386/core/linux/linux_syscall.S  |   45 +
 .../roms/ipxe/src/arch/i386/core/nulltrap.c        |   51 +
 .../roms/ipxe/src/arch/i386/core/patch_cf.S        |   38 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/pic8259.c |   66 +
 .../roms/ipxe/src/arch/i386/core/rdtsc_timer.c     |   89 +
 .../roms/ipxe/src/arch/i386/core/relocate.c        |  129 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/setjmp.S  |   42 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack.S   |   15 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack16.S |   15 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/timer2.c  |   87 +
 .../roms/ipxe/src/arch/i386/core/video_subr.c      |  104 +
 .../roms/ipxe/src/arch/i386/core/virtaddr.S        |  103 +
 .../roms/ipxe/src/arch/i386/core/wince_loader.c    |  273 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/core/x86_io.c  |   96 +
 .../roms/ipxe/src/arch/i386/drivers/net/undi.c     |  148 +
 .../roms/ipxe/src/arch/i386/drivers/net/undiisr.S  |   87 +
 .../roms/ipxe/src/arch/i386/drivers/net/undiload.c |  173 +
 .../roms/ipxe/src/arch/i386/drivers/net/undinet.c  |  652 +
 .../roms/ipxe/src/arch/i386/drivers/net/undionly.c |  129 +
 .../ipxe/src/arch/i386/drivers/net/undipreload.c   |   37 +
 .../roms/ipxe/src/arch/i386/drivers/net/undirom.c  |  234 +
 .../ipxe/src/arch/i386/firmware/pcbios/basemem.c   |   46 +
 .../src/arch/i386/firmware/pcbios/bios_console.c   |  314 +
 .../src/arch/i386/firmware/pcbios/e820mangler.S    |  584 +
 .../ipxe/src/arch/i386/firmware/pcbios/fakee820.c  |   93 +
 .../ipxe/src/arch/i386/firmware/pcbios/hidemem.c   |  220 +
 .../ipxe/src/arch/i386/firmware/pcbios/memmap.c    |  322 +
 .../ipxe/src/arch/i386/firmware/pcbios/pnpbios.c   |  109 +
 .../roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c |  103 +
 .../ipxe/src/arch/i386/hci/commands/reboot_cmd.c   |   66 +
 .../roms/ipxe/src/arch/i386/image/bootsector.c     |  114 +
 .../roms/ipxe/src/arch/i386/image/bzimage.c        |  551 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/image/com32.c  |  331 +
 .../roms/ipxe/src/arch/i386/image/comboot.c        |  326 +
 .../roms/ipxe/src/arch/i386/image/elfboot.c        |  107 +
 .../roms/ipxe/src/arch/i386/image/multiboot.c      |  472 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/image/nbi.c    |  424 +
 .../roms/ipxe/src/arch/i386/image/pxe_image.c      |  108 +
 .../roms/ipxe/src/arch/i386/include/basemem.h      |   35 +
 .../ipxe/src/arch/i386/include/basemem_packet.h    |   15 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios.h |   10 +
 .../roms/ipxe/src/arch/i386/include/bios_disks.h   |   69 +
 .../roms/ipxe/src/arch/i386/include/biosint.h      |   33 +
 .../ipxe/src/arch/i386/include/bits/byteswap.h     |   43 +
 .../ipxe/src/arch/i386/include/bits/compiler.h     |   27 +
 .../roms/ipxe/src/arch/i386/include/bits/cpu.h     |   86 +
 .../roms/ipxe/src/arch/i386/include/bits/endian.h  |    8 +
 .../roms/ipxe/src/arch/i386/include/bits/errfile.h |   42 +
 .../roms/ipxe/src/arch/i386/include/bits/io.h      |   14 +
 .../ipxe/src/arch/i386/include/bits/linux_api.h    |    6 +
 .../roms/ipxe/src/arch/i386/include/bits/nap.h     |   15 +
 .../roms/ipxe/src/arch/i386/include/bits/sanboot.h |   14 +
 .../roms/ipxe/src/arch/i386/include/bits/smbios.h  |   14 +
 .../roms/ipxe/src/arch/i386/include/bits/stdint.h  |   23 +
 .../roms/ipxe/src/arch/i386/include/bits/timer.h   |   15 +
 .../roms/ipxe/src/arch/i386/include/bits/uaccess.h |   14 +
 .../roms/ipxe/src/arch/i386/include/bits/umalloc.h |   14 +
 .../roms/ipxe/src/arch/i386/include/bochs.h        |   34 +
 .../roms/ipxe/src/arch/i386/include/bootsector.h   |   14 +
 .../roms/ipxe/src/arch/i386/include/bzimage.h      |  142 +
 .../roms/ipxe/src/arch/i386/include/comboot.h      |  177 +
 .../src/arch/i386/include/efi/ipxe/dhcp_arch.h     |   40 +
 .../roms/ipxe/src/arch/i386/include/fakee820.h     |    9 +
 .../roms/ipxe/src/arch/i386/include/gdbmach.h      |   64 +
 .../roms/ipxe/src/arch/i386/include/int13.h        |  267 +
 .../ipxe/src/arch/i386/include/ipxe/bios_nap.h     |   18 +
 .../ipxe/src/arch/i386/include/ipxe/bios_sanboot.h |   18 +
 .../ipxe/src/arch/i386/include/ipxe/bios_smbios.h  |   18 +
 .../ipxe/src/arch/i386/include/ipxe/bios_timer.h   |   44 +
 .../src/arch/i386/include/ipxe/memtop_umalloc.h    |   18 +
 .../ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h  |   39 +
 .../roms/ipxe/src/arch/i386/include/ipxe/timer2.h  |   14 +
 .../roms/ipxe/src/arch/i386/include/ipxe/x86_io.h  |  153 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/include/kir.h  |   18 +
 .../roms/ipxe/src/arch/i386/include/libkir.h       |  233 +
 .../roms/ipxe/src/arch/i386/include/librm.h        |  201 +
 .../roms/ipxe/src/arch/i386/include/limits.h       |   61 +
 .../roms/ipxe/src/arch/i386/include/memsizes.h     |   19 +
 .../roms/ipxe/src/arch/i386/include/multiboot.h    |  149 +
 .../src/arch/i386/include/pcbios/ipxe/dhcp_arch.h  |   40 +
 .../roms/ipxe/src/arch/i386/include/pic8259.h      |   71 +
 .../roms/ipxe/src/arch/i386/include/pnpbios.h      |   17 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe.h  |  152 +
 .../roms/ipxe/src/arch/i386/include/pxe_api.h      | 1909 +++
 .../roms/ipxe/src/arch/i386/include/pxe_call.h     |   43 +
 .../roms/ipxe/src/arch/i386/include/pxe_types.h    |  127 +
 .../roms/ipxe/src/arch/i386/include/pxeparent.h    |   11 +
 .../roms/ipxe/src/arch/i386/include/realmode.h     |  127 +
 .../roms/ipxe/src/arch/i386/include/registers.h    |  198 +
 .../roms/ipxe/src/arch/i386/include/setjmp.h       |   40 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/include/undi.h |  106 +
 .../roms/ipxe/src/arch/i386/include/undiload.h     |   35 +
 .../roms/ipxe/src/arch/i386/include/undinet.h      |   17 +
 .../roms/ipxe/src/arch/i386/include/undipreload.h  |   18 +
 .../roms/ipxe/src/arch/i386/include/undirom.h      |   53 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/include/vga.h  |  228 +
 .../ipxe/src/arch/i386/interface/pcbios/bios_nap.c |   16 +
 .../src/arch/i386/interface/pcbios/bios_smbios.c   |   86 +
 .../src/arch/i386/interface/pcbios/bios_timer.c    |   65 +
 .../ipxe/src/arch/i386/interface/pcbios/biosint.c  |   92 +
 .../ipxe/src/arch/i386/interface/pcbios/int13.c    | 1434 +++
 .../arch/i386/interface/pcbios/memtop_umalloc.c    |  202 +
 .../ipxe/src/arch/i386/interface/pcbios/pcibios.c  |  114 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_call.c    |  521 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_entry.S   |  216 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_file.c    |  306 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_loader.c  |   50 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_preboot.c |  332 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_tftp.c    |  564 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_udp.c     |  407 +
 .../ipxe/src/arch/i386/interface/pxe/pxe_undi.c    |  822 ++
 .../src/arch/i386/interface/pxeparent/pxeparent.c  |  191 +
 .../arch/i386/interface/pxeparent/pxeparent_dhcp.c |   69 +
 .../src/arch/i386/interface/syslinux/com32_call.c  |  207 +
 .../arch/i386/interface/syslinux/com32_wrapper.S   |  122 +
 .../arch/i386/interface/syslinux/comboot_call.c    |  700 ++
 .../arch/i386/interface/syslinux/comboot_resolv.c  |   61 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/kir-Makefile   |   26 +
 .../roms/ipxe/src/arch/i386/prefix/bootpart.S      |  218 +
 .../roms/ipxe/src/arch/i386/prefix/dskprefix.S     |  383 +
 .../roms/ipxe/src/arch/i386/prefix/exeprefix.S     |  156 +
 .../roms/ipxe/src/arch/i386/prefix/hdprefix.S      |  111 +
 .../roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S   |   14 +
 .../roms/ipxe/src/arch/i386/prefix/kpxeprefix.S    |   10 +
 .../roms/ipxe/src/arch/i386/prefix/libprefix.S     |  934 ++
 .../roms/ipxe/src/arch/i386/prefix/linuxprefix.S   |   28 +
 .../roms/ipxe/src/arch/i386/prefix/lkrnprefix.S    |  228 +
 qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mbr.S   |   13 +
 .../roms/ipxe/src/arch/i386/prefix/mromprefix.S    |  434 +
 .../roms/ipxe/src/arch/i386/prefix/nbiprefix.S     |   78 +
 .../roms/ipxe/src/arch/i386/prefix/nullprefix.S    |   13 +
 .../roms/ipxe/src/arch/i386/prefix/pxeprefix.S     |  763 ++
 .../roms/ipxe/src/arch/i386/prefix/romprefix.S     |  812 ++
 .../roms/ipxe/src/arch/i386/prefix/undiloader.S    |   52 +
 .../roms/ipxe/src/arch/i386/prefix/unnrv2b.S       |  184 +
 .../roms/ipxe/src/arch/i386/prefix/unnrv2b16.S     |    9 +
 .../roms/ipxe/src/arch/i386/prefix/usbdisk.S       |   23 +
 .../roms/ipxe/src/arch/i386/scripts/i386-kir.lds   |  200 +
 .../roms/ipxe/src/arch/i386/scripts/i386.lds       |  220 +
 .../roms/ipxe/src/arch/i386/scripts/linux.lds      |  102 +
 .../roms/ipxe/src/arch/i386/transitions/liba20.S   |  305 +
 .../roms/ipxe/src/arch/i386/transitions/libkir.S   |  256 +
 .../roms/ipxe/src/arch/i386/transitions/librm.S    |  571 +
 .../ipxe/src/arch/i386/transitions/librm_mgmt.c    |   58 +
 qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile        |   15 +
 qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.efi    |   28 +
 qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.linux  |   13 +
 .../roms/ipxe/src/arch/x86/core/linux/linux_api.c  |  106 +
 .../ipxe/src/arch/x86/core/linux/linux_strerror.c  |  169 +
 .../roms/ipxe/src/arch/x86/core/pcidirect.c        |   47 +
 .../roms/ipxe/src/arch/x86/core/x86_string.c       |   63 +
 .../src/arch/x86/include/bits/linux_api_platform.h |    6 +
 .../roms/ipxe/src/arch/x86/include/bits/pci_io.h   |   15 +
 .../roms/ipxe/src/arch/x86/include/bits/string.h   |  252 +
 .../src/arch/x86/include/ipxe/efi/efix86_nap.h     |   18 +
 .../roms/ipxe/src/arch/x86/include/ipxe/pcibios.h  |  135 +
 .../ipxe/src/arch/x86/include/ipxe/pcidirect.h     |  141 +
 .../src/arch/x86/include/linux/ipxe/dhcp_arch.h    |   36 +
 .../ipxe/src/arch/x86/include/valgrind/memcheck.h  |  309 +
 .../ipxe/src/arch/x86/include/valgrind/valgrind.h  | 4536 +++++++
 .../ipxe/src/arch/x86/interface/efi/efix86_nap.c   |   48 +
 .../roms/ipxe/src/arch/x86/prefix/efidrvprefix.c   |   47 +
 .../roms/ipxe/src/arch/x86/prefix/efiprefix.c      |   41 +
 qemu-0.15.x/roms/ipxe/src/arch/x86/scripts/efi.lds |  108 +
 qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile     |   41 +
 qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.efi |   14 +
 .../roms/ipxe/src/arch/x86_64/Makefile.linux       |    6 +
 .../src/arch/x86_64/core/linux/linux_syscall.S     |   33 +
 .../ipxe/src/arch/x86_64/include/bits/byteswap.h   |   22 +
 .../ipxe/src/arch/x86_64/include/bits/compiler.h   |   14 +
 .../ipxe/src/arch/x86_64/include/bits/endian.h     |    6 +
 .../ipxe/src/arch/x86_64/include/bits/errfile.h    |   11 +
 .../roms/ipxe/src/arch/x86_64/include/bits/io.h    |   10 +
 .../ipxe/src/arch/x86_64/include/bits/linux_api.h  |    6 +
 .../roms/ipxe/src/arch/x86_64/include/bits/nap.h   |   12 +
 .../ipxe/src/arch/x86_64/include/bits/sanboot.h    |   12 +
 .../ipxe/src/arch/x86_64/include/bits/smbios.h     |   10 +
 .../ipxe/src/arch/x86_64/include/bits/stdint.h     |   21 +
 .../roms/ipxe/src/arch/x86_64/include/bits/timer.h |   10 +
 .../ipxe/src/arch/x86_64/include/bits/uaccess.h    |   10 +
 .../ipxe/src/arch/x86_64/include/bits/umalloc.h    |   10 +
 .../src/arch/x86_64/include/efi/ipxe/dhcp_arch.h   |   40 +
 .../roms/ipxe/src/arch/x86_64/include/gdbmach.h    |   51 +
 .../roms/ipxe/src/arch/x86_64/include/limits.h     |   59 +
 .../roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S |   25 +
 .../roms/ipxe/src/arch/x86_64/scripts/linux.lds    |  102 +
 qemu-0.15.x/roms/ipxe/src/config/.gitignore        |    1 +
 qemu-0.15.x/roms/ipxe/src/config/config.c          |  290 +
 qemu-0.15.x/roms/ipxe/src/config/config_ethernet.c |   26 +
 qemu-0.15.x/roms/ipxe/src/config/config_fc.c       |   31 +
 .../roms/ipxe/src/config/config_infiniband.c       |   23 +
 qemu-0.15.x/roms/ipxe/src/config/config_net80211.c |   50 +
 .../roms/ipxe/src/config/config_romprefix.c        |   24 +
 qemu-0.15.x/roms/ipxe/src/config/console.h         |   28 +
 qemu-0.15.x/roms/ipxe/src/config/defaults.h        |   10 +
 qemu-0.15.x/roms/ipxe/src/config/defaults/efi.h    |   24 +
 qemu-0.15.x/roms/ipxe/src/config/defaults/linux.h  |   22 +
 qemu-0.15.x/roms/ipxe/src/config/defaults/pcbios.h |   37 +
 qemu-0.15.x/roms/ipxe/src/config/general.h         |  157 +
 qemu-0.15.x/roms/ipxe/src/config/ioapi.h           |   19 +
 qemu-0.15.x/roms/ipxe/src/config/isa.h             |   17 +
 qemu-0.15.x/roms/ipxe/src/config/nap.h             |   19 +
 qemu-0.15.x/roms/ipxe/src/config/sanboot.h         |   16 +
 qemu-0.15.x/roms/ipxe/src/config/serial.h          |   37 +
 qemu-0.15.x/roms/ipxe/src/config/sideband.h        |   14 +
 qemu-0.15.x/roms/ipxe/src/config/timer.h           |   19 +
 qemu-0.15.x/roms/ipxe/src/config/umalloc.h         |   16 +
 qemu-0.15.x/roms/ipxe/src/core/acpi.c              |   85 +
 qemu-0.15.x/roms/ipxe/src/core/ansiesc.c           |  116 +
 qemu-0.15.x/roms/ipxe/src/core/asprintf.c          |   49 +
 qemu-0.15.x/roms/ipxe/src/core/base16.c            |  106 +
 qemu-0.15.x/roms/ipxe/src/core/base64.c            |  155 +
 qemu-0.15.x/roms/ipxe/src/core/basename.c          |   64 +
 qemu-0.15.x/roms/ipxe/src/core/bitmap.c            |  101 +
 qemu-0.15.x/roms/ipxe/src/core/bitops.c            |   13 +
 qemu-0.15.x/roms/ipxe/src/core/blockdev.c          |  138 +
 qemu-0.15.x/roms/ipxe/src/core/btext.c             | 5039 ++++++++
 qemu-0.15.x/roms/ipxe/src/core/console.c           |  130 +
 qemu-0.15.x/roms/ipxe/src/core/cpio.c              |   42 +
 qemu-0.15.x/roms/ipxe/src/core/ctype.c             |   48 +
 qemu-0.15.x/roms/ipxe/src/core/cwuri.c             |   48 +
 qemu-0.15.x/roms/ipxe/src/core/debug.c             |  171 +
 qemu-0.15.x/roms/ipxe/src/core/debug_md5.c         |   47 +
 qemu-0.15.x/roms/ipxe/src/core/device.c            |  135 +
 qemu-0.15.x/roms/ipxe/src/core/downloader.c        |  256 +
 qemu-0.15.x/roms/ipxe/src/core/edd.c               |   56 +
 qemu-0.15.x/roms/ipxe/src/core/errno.c             |   18 +
 qemu-0.15.x/roms/ipxe/src/core/exec.c              |  492 +
 qemu-0.15.x/roms/ipxe/src/core/fnrec.c             |  202 +
 qemu-0.15.x/roms/ipxe/src/core/gdbserial.c         |   48 +
 qemu-0.15.x/roms/ipxe/src/core/gdbstub.c           |  399 +
 qemu-0.15.x/roms/ipxe/src/core/gdbudp.c            |  259 +
 qemu-0.15.x/roms/ipxe/src/core/getkey.c            |   84 +
 qemu-0.15.x/roms/ipxe/src/core/getopt.c            |  273 +
 qemu-0.15.x/roms/ipxe/src/core/hw.c                |   66 +
 qemu-0.15.x/roms/ipxe/src/core/i82365.c            |  656 +
 qemu-0.15.x/roms/ipxe/src/core/image.c             |  353 +
 qemu-0.15.x/roms/ipxe/src/core/init.c              |   98 +
 qemu-0.15.x/roms/ipxe/src/core/interface.c         |  291 +
 qemu-0.15.x/roms/ipxe/src/core/iobuf.c             |   96 +
 qemu-0.15.x/roms/ipxe/src/core/job.c               |   54 +
 qemu-0.15.x/roms/ipxe/src/core/linebuf.c           |  111 +
 qemu-0.15.x/roms/ipxe/src/core/main.c              |  118 +
 qemu-0.15.x/roms/ipxe/src/core/malloc.c            |  476 +
 qemu-0.15.x/roms/ipxe/src/core/misc.c              |   60 +
 qemu-0.15.x/roms/ipxe/src/core/monojob.c           |  115 +
 qemu-0.15.x/roms/ipxe/src/core/null_nap.c          |    3 +
 qemu-0.15.x/roms/ipxe/src/core/null_sanboot.c      |   44 +
 qemu-0.15.x/roms/ipxe/src/core/nvo.c               |  320 +
 qemu-0.15.x/roms/ipxe/src/core/open.c              |  227 +
 qemu-0.15.x/roms/ipxe/src/core/parseopt.c          |  235 +
 qemu-0.15.x/roms/ipxe/src/core/pc_kbd.c            |  112 +
 qemu-0.15.x/roms/ipxe/src/core/pcmcia.c            |  270 +
 qemu-0.15.x/roms/ipxe/src/core/posix_io.c          |  338 +
 qemu-0.15.x/roms/ipxe/src/core/process.c           |  114 +
 qemu-0.15.x/roms/ipxe/src/core/random.c            |   41 +
 qemu-0.15.x/roms/ipxe/src/core/refcnt.c            |   98 +
 qemu-0.15.x/roms/ipxe/src/core/resolv.c            |  430 +
 qemu-0.15.x/roms/ipxe/src/core/serial.c            |  254 +
 qemu-0.15.x/roms/ipxe/src/core/serial_console.c    |   31 +
 qemu-0.15.x/roms/ipxe/src/core/settings.c          | 1744 +++
 qemu-0.15.x/roms/ipxe/src/core/string.c            |  355 +
 qemu-0.15.x/roms/ipxe/src/core/stringextra.c       |  275 +
 qemu-0.15.x/roms/ipxe/src/core/strtoull.c          |   48 +
 qemu-0.15.x/roms/ipxe/src/core/timer.c             |   42 +
 qemu-0.15.x/roms/ipxe/src/core/uri.c               |  500 +
 qemu-0.15.x/roms/ipxe/src/core/uuid.c              |   50 +
 qemu-0.15.x/roms/ipxe/src/core/vsprintf.c          |  423 +
 qemu-0.15.x/roms/ipxe/src/core/xfer.c              |  339 +
 qemu-0.15.x/roms/ipxe/src/crypto/aes_wrap.c        |  123 +
 qemu-0.15.x/roms/ipxe/src/crypto/arc4.c            |  131 +
 qemu-0.15.x/roms/ipxe/src/crypto/asn1.c            |  166 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/aes.c       |  478 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.c    | 1496 +++
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.h    |   93 +
 .../roms/ipxe/src/crypto/axtls/bigint_impl.h       |  105 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/crypto.h    |  302 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/os_port.h   |   61 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/rsa.c       |  332 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls/sha1.c      |  240 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls_aes.c       |  158 +
 qemu-0.15.x/roms/ipxe/src/crypto/axtls_sha1.c      |   25 +
 qemu-0.15.x/roms/ipxe/src/crypto/cbc.c             |  101 +
 qemu-0.15.x/roms/ipxe/src/crypto/chap.c            |  124 +
 qemu-0.15.x/roms/ipxe/src/crypto/crandom.c         |   55 +
 qemu-0.15.x/roms/ipxe/src/crypto/crc32.c           |   54 +
 qemu-0.15.x/roms/ipxe/src/crypto/crypto_null.c     |   87 +
 qemu-0.15.x/roms/ipxe/src/crypto/hmac.c            |  122 +
 qemu-0.15.x/roms/ipxe/src/crypto/md5.c             |  234 +
 qemu-0.15.x/roms/ipxe/src/crypto/sha1extra.c       |  165 +
 qemu-0.15.x/roms/ipxe/src/crypto/x509.c            |  183 +
 qemu-0.15.x/roms/ipxe/src/doc/build_sys.dox        |  419 +
 qemu-0.15.x/roms/ipxe/src/doc/pxe_extensions       |  312 +
 qemu-0.15.x/roms/ipxe/src/doxygen.cfg              | 1486 +++
 .../roms/ipxe/src/drivers/bitbash/bitbash.c        |   57 +
 .../roms/ipxe/src/drivers/bitbash/i2c_bit.c        |  393 +
 .../roms/ipxe/src/drivers/bitbash/spi_bit.c        |  228 +
 qemu-0.15.x/roms/ipxe/src/drivers/block/ata.c      |  678 ++
 qemu-0.15.x/roms/ipxe/src/drivers/block/ibft.c     |  480 +
 qemu-0.15.x/roms/ipxe/src/drivers/block/scsi.c     |  960 ++
 qemu-0.15.x/roms/ipxe/src/drivers/block/srp.c      |  828 ++
 qemu-0.15.x/roms/ipxe/src/drivers/bus/eisa.c       |  182 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/isa.c        |  173 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/isa_ids.c    |   26 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/isapnp.c     |  755 ++
 qemu-0.15.x/roms/ipxe/src/drivers/bus/mca.c        |  177 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/pci.c        |  368 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/pcibackup.c  |   90 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/pciextra.c   |   86 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/pcivpd.c     |  555 +
 qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-pci.c |   64 +
 .../roms/ipxe/src/drivers/bus/virtio-ring.c        |  136 +
 .../roms/ipxe/src/drivers/infiniband/MT25218_PRM.h | 3460 ++++++
 .../roms/ipxe/src/drivers/infiniband/MT25408_PRM.h | 3404 ++++++
 .../roms/ipxe/src/drivers/infiniband/arbel.c       | 2839 +++++
 .../roms/ipxe/src/drivers/infiniband/arbel.h       |  623 +
 .../roms/ipxe/src/drivers/infiniband/hermon.c      | 3854 ++++++
 .../roms/ipxe/src/drivers/infiniband/hermon.h      |  932 ++
 .../roms/ipxe/src/drivers/infiniband/linda.c       | 2430 ++++
 .../roms/ipxe/src/drivers/infiniband/linda.h       |  276 +
 .../roms/ipxe/src/drivers/infiniband/linda_fw.c    | 1069 ++
 .../roms/ipxe/src/drivers/infiniband/mlx_bitops.h  |  245 +
 .../roms/ipxe/src/drivers/infiniband/qib7322.c     | 2428 ++++
 .../roms/ipxe/src/drivers/infiniband/qib7322.h     |  364 +
 .../ipxe/src/drivers/infiniband/qib_7220_regs.h    | 1762 +++
 .../ipxe/src/drivers/infiniband/qib_7322_regs.h    | 7261 +++++++++++
 .../ipxe/src/drivers/infiniband/qib_genbits.pl     |  116 +
 qemu-0.15.x/roms/ipxe/src/drivers/linux/linux.c    |  153 +
 qemu-0.15.x/roms/ipxe/src/drivers/linux/tap.c      |  249 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c503.c      |    5 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c509-eisa.c |   49 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.c      |  432 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.h      |  394 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.c      |  763 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.txt    |   31 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c529.c      |   62 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.c      |  553 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.h      |  437 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c5x9.c      |  416 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.c      |  988 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.h      |  308 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.c   |  693 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.h   |  631 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k.c        | 1698 +++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k.h        | 1279 ++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c |  340 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c   |  154 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c   |  544 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c    |  631 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c | 1760 +++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c   |  122 +
 .../ipxe/src/drivers/net/ath5k/ath5k_initvals.c    | 1560 +++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c    |  534 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c    | 2581 ++++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c    |  390 +
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c  | 1174 ++
 .../roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c |  107 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/base.h |  145 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/desc.h |  332 +
 .../roms/ipxe/src/drivers/net/ath5k/eeprom.h       |  451 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/reg.h  | 2589 ++++
 .../roms/ipxe/src/drivers/net/ath5k/rfbuffer.h     | 1181 ++
 .../roms/ipxe/src/drivers/net/ath5k/rfgain.h       |  516 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.c      | 1749 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.h      | 1033 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/b44.c        |  953 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/b44.h        |  469 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.c       | 2697 +++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.h       | 4598 +++++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2_fw.h    | 3494 ++++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.c     |  739 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.h     |  481 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.txt   |   45 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/davicom.c    |  708 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/depca.c      |  805 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/dmfe.c       | 1227 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000.c        |   35 +
 .../roms/ipxe/src/drivers/net/e1000/e1000.h        |  326 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_82540.c  |  754 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_82541.c  | 1314 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_82541.h  |   86 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_82542.c  |  571 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_82543.c  | 1635 +++
 .../roms/ipxe/src/drivers/net/e1000/e1000_82543.h  |   45 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_api.c    | 1108 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_api.h    |  127 +
 .../ipxe/src/drivers/net/e1000/e1000_defines.h     | 1416 +++
 .../roms/ipxe/src/drivers/net/e1000/e1000_hw.h     |  728 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_mac.c    | 2196 ++++
 .../roms/ipxe/src/drivers/net/e1000/e1000_mac.h    |   94 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_main.c   |  909 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_manage.c |  389 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_manage.h |   84 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_nvm.c    |  923 ++
 .../roms/ipxe/src/drivers/net/e1000/e1000_nvm.h    |   63 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_osdep.h  |  118 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_phy.c    | 2308 ++++
 .../roms/ipxe/src/drivers/net/e1000/e1000_phy.h    |  171 +
 .../roms/ipxe/src/drivers/net/e1000/e1000_regs.h   |  329 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e.c      |   34 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e.h      |  532 +
 .../src/drivers/net/e1000e/e1000e_80003es2lan.c    | 1533 +++
 .../src/drivers/net/e1000e/e1000e_80003es2lan.h    |  100 +
 .../ipxe/src/drivers/net/e1000e/e1000e_82571.c     | 1818 +++
 .../ipxe/src/drivers/net/e1000e/e1000e_82571.h     |   55 +
 .../ipxe/src/drivers/net/e1000e/e1000e_defines.h   | 1469 +++
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h   |  719 ++
 .../ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c   | 3444 ++++++
 .../ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h   |  196 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c  | 1883 +++
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h  |   79 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_main.c | 1265 ++
 .../ipxe/src/drivers/net/e1000e/e1000e_manage.c    |  372 +
 .../ipxe/src/drivers/net/e1000e/e1000e_manage.h    |   86 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c  |  596 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h  |   53 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c  | 3323 +++++
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h  |  261 +
 .../roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h |  340 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/eepro.c      |  638 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.c   | 1163 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.h   |  204 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snp.h    |   49 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.c |  362 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.h |   35 +
 .../roms/ipxe/src/drivers/net/efi/snponly.c        |  129 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.c    |  537 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.h    |  190 +
 .../roms/ipxe/src/drivers/net/etherfabric.c        | 4225 +++++++
 .../roms/ipxe/src/drivers/net/etherfabric.h        |  553 +
 .../roms/ipxe/src/drivers/net/etherfabric_nic.h    |  204 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.c  | 1981 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.h  |  601 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/hfa384x.h    | 3069 +++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.c    |   32 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.h    |  324 +
 .../roms/ipxe/src/drivers/net/igb/igb_82575.c      | 1617 +++
 .../roms/ipxe/src/drivers/net/igb/igb_82575.h      |  442 +
 .../roms/ipxe/src/drivers/net/igb/igb_api.c        | 1108 ++
 .../roms/ipxe/src/drivers/net/igb/igb_api.h        |  166 +
 .../roms/ipxe/src/drivers/net/igb/igb_defines.h    | 1515 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_hw.h |  697 ++
 .../roms/ipxe/src/drivers/net/igb/igb_mac.c        | 1991 +++
 .../roms/ipxe/src/drivers/net/igb/igb_mac.h        |   82 +
 .../roms/ipxe/src/drivers/net/igb/igb_main.c       | 1010 ++
 .../roms/ipxe/src/drivers/net/igb/igb_manage.c     |  388 +
 .../roms/ipxe/src/drivers/net/igb/igb_manage.h     |   83 +
 .../roms/ipxe/src/drivers/net/igb/igb_nvm.c        |  627 +
 .../roms/ipxe/src/drivers/net/igb/igb_nvm.h        |   52 +
 .../roms/ipxe/src/drivers/net/igb/igb_osdep.h      |  129 +
 .../roms/ipxe/src/drivers/net/igb/igb_phy.c        | 2470 ++++
 .../roms/ipxe/src/drivers/net/igb/igb_phy.h        |  171 +
 .../roms/ipxe/src/drivers/net/igb/igb_regs.h       |  486 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf.h        |  377 +
 .../ipxe/src/drivers/net/igbvf/igbvf_defines.h     | 1395 +++
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_main.c   |  954 ++
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.c    |  404 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.h    |   87 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h  |  121 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_regs.h   |  338 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_vf.c     |  455 +
 .../roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h     |  345 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ipoib.c      |  787 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/jme.c        | 1308 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/jme.h        |  914 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/legacy.c     |  157 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/mtd80x.c     | 1022 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge.c   | 1335 ++
 .../roms/ipxe/src/drivers/net/myri10ge_mcp.h       |  514 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.c    |  604 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.h    |  232 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ne.c         |    6 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ne2k_isa.c   |  375 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/ns83820.c    | 1007 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.c     | 1037 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.h     |  240 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/p80211hdr.h  |  301 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.c    | 1161 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.h    |  181 +
 .../roms/ipxe/src/drivers/net/phantom/nx_bitops.h  |  194 +
 .../src/drivers/net/phantom/nxhal_nic_interface.h  |  501 +
 .../roms/ipxe/src/drivers/net/phantom/phantom.c    | 2178 ++++
 .../roms/ipxe/src/drivers/net/phantom/phantom.h    |  212 +
 .../roms/ipxe/src/drivers/net/phantom/phantom_hw.h |  184 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/pnic.c       |  280 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/pnic_api.h   |   61 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/prism2.c     |  857 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_pci.c |   58 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_plx.c |  122 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.c      | 2232 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.h      |  486 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/rtl8139.c    |  596 +
 .../roms/ipxe/src/drivers/net/rtl818x/rtl8180.c    |   17 +
 .../ipxe/src/drivers/net/rtl818x/rtl8180_grf5101.c |  186 +
 .../ipxe/src/drivers/net/rtl818x/rtl8180_max2820.c |  158 +
 .../ipxe/src/drivers/net/rtl818x/rtl8180_sa2400.c  |  217 +
 .../roms/ipxe/src/drivers/net/rtl818x/rtl8185.c    |   14 +
 .../ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c |  804 ++
 .../roms/ipxe/src/drivers/net/rtl818x/rtl818x.c    |  854 ++
 .../roms/ipxe/src/drivers/net/rtl818x/rtl818x.h    |  359 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.c     | 1174 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.h     |  311 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.c     | 1303 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.h     |  375 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/skge.c       | 2468 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/skge.h       | 2623 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.c       | 2393 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.h       | 2176 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.c    |  952 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.h    |  428 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/sundance.c   |  898 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.c        | 3435 ++++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.h        | 2121 ++++
 qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.c       | 1723 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.h       |  491 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.c      | 1969 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.txt    |   54 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/via-rhine.c  | 1447 +++
 .../roms/ipxe/src/drivers/net/via-velocity.c       | 1926 +++
 .../roms/ipxe/src/drivers/net/via-velocity.h       | 1932 +++
 qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.c |  419 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.h |   44 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge.c  |   18 +
 .../roms/ipxe/src/drivers/net/vxge/vxge_config.c   | 1868 +++
 .../roms/ipxe/src/drivers/net/vxge/vxge_config.h   |  783 ++
 .../roms/ipxe/src/drivers/net/vxge/vxge_main.c     |  718 ++
 .../roms/ipxe/src/drivers/net/vxge/vxge_main.h     |  230 +
 .../roms/ipxe/src/drivers/net/vxge/vxge_reg.h      | 4700 ++++++++
 .../roms/ipxe/src/drivers/net/vxge/vxge_traffic.c  |  738 ++
 .../roms/ipxe/src/drivers/net/vxge/vxge_traffic.h  |  309 +
 .../roms/ipxe/src/drivers/net/vxge/vxge_version.h  |   40 +
 qemu-0.15.x/roms/ipxe/src/drivers/net/w89c840.c    |  964 ++
 qemu-0.15.x/roms/ipxe/src/drivers/net/wd.c         |    6 +
 .../roms/ipxe/src/drivers/net/wlan_compat.h        |  577 +
 qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvs.c        |  165 +
 qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvsvpd.c     |  233 +
 qemu-0.15.x/roms/ipxe/src/drivers/nvs/spi.c        |  140 +
 qemu-0.15.x/roms/ipxe/src/drivers/nvs/threewire.c  |  131 +
 .../roms/ipxe/src/hci/commands/autoboot_cmd.c      |   57 +
 .../roms/ipxe/src/hci/commands/config_cmd.c        |  102 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/dhcp_cmd.c  |  137 +
 .../roms/ipxe/src/hci/commands/digest_cmd.c        |  121 +
 .../roms/ipxe/src/hci/commands/fcmgmt_cmd.c        |  216 +
 .../roms/ipxe/src/hci/commands/gdbstub_cmd.c       |  110 +
 .../roms/ipxe/src/hci/commands/ifmgmt_cmd.c        |  181 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/image_cmd.c |  423 +
 .../roms/ipxe/src/hci/commands/iwmgmt_cmd.c        |  106 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/login_cmd.c |   72 +
 .../roms/ipxe/src/hci/commands/lotest_cmd.c        |   97 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/nvo_cmd.c   |  240 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/route_cmd.c |   69 +
 .../roms/ipxe/src/hci/commands/sanboot_cmd.c       |   90 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/time_cmd.c  |  119 +
 qemu-0.15.x/roms/ipxe/src/hci/commands/vlan_cmd.c  |  139 +
 qemu-0.15.x/roms/ipxe/src/hci/editstring.c         |  203 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_al.c   |   32 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_az.c   |   24 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_bg.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_by.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cf.c   |   24 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cz.c   |   27 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_de.c   |   46 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_dk.c   |   31 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_es.c   |   29 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_et.c   |   30 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fi.c   |   38 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fr.c   |   68 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_gr.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_hu.c   |   34 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_il.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_it.c   |   32 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_lt.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mk.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mt.c   |   20 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_nl.c   |   34 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_no.c   |  105 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pl.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pt.c   |   29 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ro.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ru.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sg.c   |   41 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sr.c   |   35 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_th.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ua.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_uk.c   |   19 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_us.c   |   15 +
 qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_wo.c   |   55 +
 qemu-0.15.x/roms/ipxe/src/hci/linux_args.c         |  190 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/alert.c     |   18 +
 .../roms/ipxe/src/hci/mucurses/ansi_screen.c       |   74 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/clear.c     |   90 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/colour.c    |   66 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/cursor.h    |   37 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/edging.c    |  111 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/kb.c        |  143 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.c  |  147 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.h  |   23 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/print.c     |   86 +
 .../roms/ipxe/src/hci/mucurses/print_nadv.c        |   26 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/slk.c       |  363 +
 .../roms/ipxe/src/hci/mucurses/widgets/editbox.c   |  102 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/winattrs.c  |  133 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/windows.c   |  158 +
 qemu-0.15.x/roms/ipxe/src/hci/mucurses/wininit.c   |   37 +
 qemu-0.15.x/roms/ipxe/src/hci/readline.c           |  324 +
 qemu-0.15.x/roms/ipxe/src/hci/shell.c              |  137 +
 qemu-0.15.x/roms/ipxe/src/hci/strerror.c           |  125 +
 qemu-0.15.x/roms/ipxe/src/hci/tui/login_ui.c       |  137 +
 qemu-0.15.x/roms/ipxe/src/hci/tui/settings_ui.c    |  573 +
 qemu-0.15.x/roms/ipxe/src/hci/wireless_errors.c    |  108 +
 qemu-0.15.x/roms/ipxe/src/image/efi_image.c        |  103 +
 qemu-0.15.x/roms/ipxe/src/image/elf.c              |  163 +
 qemu-0.15.x/roms/ipxe/src/image/embedded.c         |   91 +
 qemu-0.15.x/roms/ipxe/src/image/script.c           |  352 +
 qemu-0.15.x/roms/ipxe/src/image/segment.c          |   90 +
 qemu-0.15.x/roms/ipxe/src/include/.gitignore       |    1 +
 qemu-0.15.x/roms/ipxe/src/include/alloca.h         |   25 +
 qemu-0.15.x/roms/ipxe/src/include/assert.h         |   67 +
 qemu-0.15.x/roms/ipxe/src/include/big_bswap.h      |   33 +
 qemu-0.15.x/roms/ipxe/src/include/bootp.h          |  230 +
 qemu-0.15.x/roms/ipxe/src/include/btext.h          |   62 +
 qemu-0.15.x/roms/ipxe/src/include/byteswap.h       |   59 +
 qemu-0.15.x/roms/ipxe/src/include/coff.h           |   73 +
 qemu-0.15.x/roms/ipxe/src/include/compiler.h       |  759 ++
 qemu-0.15.x/roms/ipxe/src/include/cpu.h            |    6 +
 qemu-0.15.x/roms/ipxe/src/include/ctype.h          |   32 +
 qemu-0.15.x/roms/ipxe/src/include/curses.h         |  755 ++
 qemu-0.15.x/roms/ipxe/src/include/elf.h            |  234 +
 qemu-0.15.x/roms/ipxe/src/include/endian.h         |   21 +
 qemu-0.15.x/roms/ipxe/src/include/errno.h          |  761 ++
 qemu-0.15.x/roms/ipxe/src/include/etherboot.h      |   44 +
 qemu-0.15.x/roms/ipxe/src/include/fs.h             |   41 +
 qemu-0.15.x/roms/ipxe/src/include/getopt.h         |   94 +
 qemu-0.15.x/roms/ipxe/src/include/hci/ifmgmt_cmd.h |   37 +
 qemu-0.15.x/roms/ipxe/src/include/hci/linux_args.h |   31 +
 qemu-0.15.x/roms/ipxe/src/include/i82365.h         |  452 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/acpi.h      |   63 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/aes.h       |   30 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ansiesc.h   |  120 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/aoe.h       |  131 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/api.h       |   84 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/arc4.h      |   22 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/arp.h       |   44 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/asn1.h      |   34 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ata.h       |  204 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/base16.h    |   38 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/base64.h    |   41 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/bitbash.h   |   52 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/bitmap.h    |   85 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/bitops.h    |  230 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/blockdev.h  |   55 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/bofm.h      |  351 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/cbc.h       |  100 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/chap.h      |   53 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/command.h   |   28 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/console.h   |  108 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/cpio.h      |   53 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/crc32.h     |   10 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/crypto.h    |  156 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/device.h    |  139 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcp.h      |  652 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcpopts.h  |   43 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcppkt.h   |   71 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/dns.h       |   92 +
 .../roms/ipxe/src/include/ipxe/downloader.h        |   18 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/eapol.h     |  113 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/edd.h       |  193 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/editbox.h   |   61 +
 .../roms/ipxe/src/include/ipxe/editstring.h        |   48 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Base.h  |  965 ++
 .../include/ipxe/efi/Guid/HiiFormMapMethodGuid.h   |   27 +
 .../ipxe/efi/Guid/HiiPlatformSetupFormset.h        |   37 +
 .../ipxe/src/include/ipxe/efi/Guid/MdeModuleHii.h  |  222 +
 .../roms/ipxe/src/include/ipxe/efi/Guid/PcAnsi.h   |   60 +
 .../roms/ipxe/src/include/ipxe/efi/Guid/SmBios.h   |   34 +
 .../src/include/ipxe/efi/Guid/WinCertificate.h     |  130 +
 .../ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h |  280 +
 .../src/include/ipxe/efi/IndustryStandard/Pci22.h  |  817 ++
 .../include/ipxe/efi/IndustryStandard/PeImage.h    |  757 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/LICENCE |   40 +
 .../roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h |   43 +
 .../ipxe/src/include/ipxe/efi/Pi/PiDependency.h    |   49 +
 .../roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h   |  715 ++
 .../ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h  |  482 +
 .../src/include/ipxe/efi/Pi/PiFirmwareVolume.h     |  233 +
 .../roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h      |  451 +
 .../ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h    |  138 +
 .../ipxe/src/include/ipxe/efi/Pi/PiS3BootScript.h  |   61 +
 .../ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h    | 1130 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/PiDxe.h |   27 +
 .../roms/ipxe/src/include/ipxe/efi/ProcessorBind.h |   19 +
 .../src/include/ipxe/efi/Protocol/ComponentName2.h |  175 +
 .../roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h  |  300 +
 .../ipxe/src/include/ipxe/efi/Protocol/CpuIo.h     |   48 +
 .../ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h    |  144 +
 .../src/include/ipxe/efi/Protocol/DebugSupport.h   |  685 ++
 .../src/include/ipxe/efi/Protocol/DevicePath.h     | 1074 ++
 .../src/include/ipxe/efi/Protocol/DriverBinding.h  |  203 +
 .../src/include/ipxe/efi/Protocol/FormBrowser2.h   |  177 +
 .../include/ipxe/efi/Protocol/HiiConfigAccess.h    |  221 +
 .../src/include/ipxe/efi/Protocol/HiiDatabase.h    |  519 +
 .../src/include/ipxe/efi/Protocol/LoadedImage.h    |   90 +
 .../ipxe/efi/Protocol/NetworkInterfaceIdentifier.h |   93 +
 .../ipxe/src/include/ipxe/efi/Protocol/PciIo.h     |  560 +
 .../include/ipxe/efi/Protocol/PciRootBridgeIo.h    |  438 +
 .../src/include/ipxe/efi/Protocol/SimpleNetwork.h  |  664 +
 .../src/include/ipxe/efi/Protocol/SimpleTextIn.h   |  138 +
 .../src/include/ipxe/efi/Protocol/SimpleTextOut.h  |  406 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi.h  |   29 +
 .../ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h  |  287 +
 .../roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h  |  142 +
 .../ipxe/efi/Uefi/UefiInternalFormRepresentation.h | 2068 ++++
 .../src/include/ipxe/efi/Uefi/UefiMultiPhase.h     |  171 +
 .../roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h  | 1772 +++
 .../roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h | 2099 ++++
 .../ipxe/src/include/ipxe/efi/X64/ProcessorBind.h  |  290 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi.h   |  146 +
 .../roms/ipxe/src/include/ipxe/efi/efi_driver.h    |   49 +
 .../roms/ipxe/src/include/ipxe/efi/efi_hii.h       |  140 +
 .../roms/ipxe/src/include/ipxe/efi/efi_io.h        |  180 +
 .../roms/ipxe/src/include/ipxe/efi/efi_pci.h       |   46 +
 .../roms/ipxe/src/include/ipxe/efi/efi_pci_api.h   |  148 +
 .../roms/ipxe/src/include/ipxe/efi/efi_smbios.h    |   18 +
 .../roms/ipxe/src/include/ipxe/efi/efi_strings.h   |   23 +
 .../roms/ipxe/src/include/ipxe/efi/efi_timer.h     |   18 +
 .../roms/ipxe/src/include/ipxe/efi/efi_uaccess.h   |   90 +
 .../roms/ipxe/src/include/ipxe/efi/efi_umalloc.h   |   18 +
 .../roms/ipxe/src/include/ipxe/efi/import.pl       |  135 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/eisa.h      |  128 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/elf.h       |   17 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/errfile.h   |  245 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/errortab.h  |   28 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/eth_slow.h  |  255 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ethernet.h  |   87 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fakedhcp.h  |   23 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fc.h        |  471 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fcels.h     |  445 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fcns.h      |  217 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fcoe.h      |   92 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fcp.h       |  166 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/features.h  |  105 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/fip.h       |  450 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ftp.h       |   15 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbserial.h |   21 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbstub.h   |   77 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbudp.h    |   24 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/hidemem.h   |   17 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/hmac.h      |   32 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/http.h      |   23 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/i2c.h       |  171 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cm.h     |   72 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cmrc.h   |   20 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mad.h    |  591 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mcast.h  |   48 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mi.h     |  135 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_packet.h |  160 +
 .../roms/ipxe/src/include/ipxe/ib_pathrec.h        |   76 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_sma.h    |   20 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_smc.h    |   20 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_srp.h    |   58 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ibft.h      |  271 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp.h      |   25 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp6.h     |   59 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ieee80211.h | 1161 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/if_arp.h    |  102 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/if_ether.h  |   39 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/image.h     |  184 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/in.h        |  104 +
 .../roms/ipxe/src/include/ipxe/infiniband.h        |  705 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/init.h      |   88 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/interface.h |  234 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/io.h        |  532 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/iobuf.h     |  229 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ip.h        |   96 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ip6.h       |   80 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ipoib.h     |   58 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/isa.h       |   95 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/isa_ids.h   |   51 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/isapnp.h    |  276 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/iscsi.h     |  702 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/job.h       |   38 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/keymap.h    |   30 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/keys.h      |   88 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/linebuf.h   |   30 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/linux.h     |  144 +
 .../roms/ipxe/src/include/ipxe/linux/linux_nap.h   |   18 +
 .../ipxe/src/include/ipxe/linux/linux_smbios.h     |   18 +
 .../roms/ipxe/src/include/ipxe/linux/linux_timer.h |   18 +
 .../ipxe/src/include/ipxe/linux/linux_uaccess.h    |  104 +
 .../ipxe/src/include/ipxe/linux/linux_umalloc.h    |   18 +
 .../roms/ipxe/src/include/ipxe/linux_compat.h      |   27 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/list.h      |  215 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/login_ui.h  |   14 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/malloc.h    |   81 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/mca.h       |  106 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/md5.h       |   24 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/monojob.h   |   18 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/nap.h       |   57 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/ndp.h       |   21 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211.h  | 1207 ++
 .../roms/ipxe/src/include/ipxe/net80211_err.h      |  633 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/netdevice.h |  669 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/null_nap.h  |   23 +
 .../roms/ipxe/src/include/ipxe/null_sanboot.h      |   18 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/nvo.h       |   52 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/nvs.h       |   68 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/nvsvpd.h    |   33 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/open.h      |  106 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/parseopt.h  |  126 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/pci.h       |  436 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_ids.h   |  351 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_io.h    |  124 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/pcibackup.h |   33 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/pcivpd.h    |  181 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/posix_io.h  |   87 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/process.h   |   91 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/profile.h   |   80 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/rarp.h      |   16 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/rc80211.h   |   19 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/refcnt.h    |  114 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/resolv.h    |   51 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/retry.h     |  111 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/rotate.h    |   29 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/rsa.h       |   12 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/sanboot.h   |   93 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/script.h    |   16 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/scsi.h      |  310 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/sec80211.h  |   52 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/segment.h   |   17 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/serial.h    |   16 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/settings.h  |  393 +
 .../roms/ipxe/src/include/ipxe/settings_ui.h       |   16 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/sha1.h      |   24 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/shell.h     |   36 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/smbios.h    |  162 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/socket.h    |  102 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/spi.h       |  258 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/spi_bit.h   |   63 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/srp.h       |  833 ++
 qemu-0.15.x/roms/ipxe/src/include/ipxe/syslog.h    |   36 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/tables.h    |  518 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/tcp.h       |  342 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/tcpip.h     |  128 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/tftp.h      |   85 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/threewire.h |  105 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/timer.h     |   77 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/tls.h       |  187 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/uaccess.h   |  345 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/udp.h       |   45 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/umalloc.h   |   69 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/uri.h       |  192 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/uuid.h      |   33 +
 .../roms/ipxe/src/include/ipxe/virtio-pci.h        |  101 +
 .../roms/ipxe/src/include/ipxe/virtio-ring.h       |  142 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/vlan.h      |   69 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/vsprintf.h  |   74 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/wpa.h       |  503 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/x509.h      |   41 +
 qemu-0.15.x/roms/ipxe/src/include/ipxe/xfer.h      |  107 +
 qemu-0.15.x/roms/ipxe/src/include/libgen.h         |    9 +
 qemu-0.15.x/roms/ipxe/src/include/linux_api.h      |   73 +
 qemu-0.15.x/roms/ipxe/src/include/little_bswap.h   |   35 +
 qemu-0.15.x/roms/ipxe/src/include/mii.h            |  219 +
 qemu-0.15.x/roms/ipxe/src/include/nic.h            |  271 +
 qemu-0.15.x/roms/ipxe/src/include/old_tcp.h        |   37 +
 qemu-0.15.x/roms/ipxe/src/include/pc_kbd.h         |    7 +
 qemu-0.15.x/roms/ipxe/src/include/pcmcia-opts.h    |   23 +
 qemu-0.15.x/roms/ipxe/src/include/pcmcia.h         |  156 +
 .../roms/ipxe/src/include/readline/readline.h      |   57 +
 qemu-0.15.x/roms/ipxe/src/include/stdarg.h         |   12 +
 qemu-0.15.x/roms/ipxe/src/include/stddef.h         |   30 +
 qemu-0.15.x/roms/ipxe/src/include/stdint.h         |   36 +
 qemu-0.15.x/roms/ipxe/src/include/stdio.h          |   47 +
 qemu-0.15.x/roms/ipxe/src/include/stdlib.h         |  115 +
 qemu-0.15.x/roms/ipxe/src/include/string.h         |   51 +
 qemu-0.15.x/roms/ipxe/src/include/strings.h        |   65 +
 qemu-0.15.x/roms/ipxe/src/include/sys/time.h       |   20 +
 qemu-0.15.x/roms/ipxe/src/include/sys_info.h       |   33 +
 qemu-0.15.x/roms/ipxe/src/include/time.h           |   22 +
 qemu-0.15.x/roms/ipxe/src/include/unistd.h         |   43 +
 qemu-0.15.x/roms/ipxe/src/include/usr/autoboot.h   |   25 +
 qemu-0.15.x/roms/ipxe/src/include/usr/dhcpmgmt.h   |   17 +
 qemu-0.15.x/roms/ipxe/src/include/usr/fcmgmt.h     |   21 +
 qemu-0.15.x/roms/ipxe/src/include/usr/ifmgmt.h     |   19 +
 qemu-0.15.x/roms/ipxe/src/include/usr/imgmgmt.h    |   56 +
 qemu-0.15.x/roms/ipxe/src/include/usr/iwmgmt.h     |   17 +
 qemu-0.15.x/roms/ipxe/src/include/usr/lotest.h     |   15 +
 qemu-0.15.x/roms/ipxe/src/include/usr/prompt.h     |   14 +
 qemu-0.15.x/roms/ipxe/src/include/usr/route.h      |   14 +
 qemu-0.15.x/roms/ipxe/src/interface/bofm/bofm.c    |  335 +
 qemu-0.15.x/roms/ipxe/src/interface/efi/efi_bofm.c |  367 +
 .../roms/ipxe/src/interface/efi/efi_console.c      |  276 +
 .../roms/ipxe/src/interface/efi/efi_driver.c       |  140 +
 qemu-0.15.x/roms/ipxe/src/interface/efi/efi_init.c |  162 +
 qemu-0.15.x/roms/ipxe/src/interface/efi/efi_io.c   |  217 +
 qemu-0.15.x/roms/ipxe/src/interface/efi/efi_pci.c  |  529 +
 .../roms/ipxe/src/interface/efi/efi_smbios.c       |   64 +
 qemu-0.15.x/roms/ipxe/src/interface/efi/efi_snp.c  | 1324 ++
 .../roms/ipxe/src/interface/efi/efi_strerror.c     |   45 +
 .../roms/ipxe/src/interface/efi/efi_strings.c      |  147 +
 .../roms/ipxe/src/interface/efi/efi_timer.c        |  118 +
 .../roms/ipxe/src/interface/efi/efi_uaccess.c      |   39 +
 .../roms/ipxe/src/interface/efi/efi_umalloc.c      |   98 +
 .../roms/ipxe/src/interface/linux/linux_console.c  |  146 +
 .../roms/ipxe/src/interface/linux/linux_nap.c      |   40 +
 .../roms/ipxe/src/interface/linux/linux_smbios.c   |   37 +
 .../roms/ipxe/src/interface/linux/linux_timer.c    |   80 +
 .../roms/ipxe/src/interface/linux/linux_uaccess.c  |   38 +
 .../roms/ipxe/src/interface/linux/linux_umalloc.c  |  154 +
 .../roms/ipxe/src/interface/smbios/smbios.c        |  180 +
 .../ipxe/src/interface/smbios/smbios_settings.c    |  210 +
 qemu-0.15.x/roms/ipxe/src/libgcc/__divdi3.c        |   26 +
 qemu-0.15.x/roms/ipxe/src/libgcc/__moddi3.c        |   26 +
 qemu-0.15.x/roms/ipxe/src/libgcc/__udivdi3.c       |   10 +
 qemu-0.15.x/roms/ipxe/src/libgcc/__udivmoddi4.c    |   32 +
 qemu-0.15.x/roms/ipxe/src/libgcc/__umoddi3.c       |   13 +
 qemu-0.15.x/roms/ipxe/src/libgcc/icc.c             |    8 +
 qemu-0.15.x/roms/ipxe/src/libgcc/libgcc.h          |   14 +
 qemu-0.15.x/roms/ipxe/src/libgcc/memcpy.c          |   18 +
 qemu-0.15.x/roms/ipxe/src/net/80211/net80211.c     | 2820 +++++
 qemu-0.15.x/roms/ipxe/src/net/80211/rc80211.c      |  371 +
 qemu-0.15.x/roms/ipxe/src/net/80211/sec80211.c     |  517 +
 qemu-0.15.x/roms/ipxe/src/net/80211/wep.c          |  303 +
 qemu-0.15.x/roms/ipxe/src/net/80211/wpa.c          |  911 ++
 qemu-0.15.x/roms/ipxe/src/net/80211/wpa_ccmp.c     |  528 +
 qemu-0.15.x/roms/ipxe/src/net/80211/wpa_psk.c      |  125 +
 qemu-0.15.x/roms/ipxe/src/net/80211/wpa_tkip.c     |  586 +
 qemu-0.15.x/roms/ipxe/src/net/aoe.c                | 1055 ++
 qemu-0.15.x/roms/ipxe/src/net/arp.c                |  290 +
 qemu-0.15.x/roms/ipxe/src/net/cachedhcp.c          |   77 +
 qemu-0.15.x/roms/ipxe/src/net/dhcpopts.c           |  462 +
 qemu-0.15.x/roms/ipxe/src/net/dhcppkt.c            |  303 +
 qemu-0.15.x/roms/ipxe/src/net/eapol.c              |   85 +
 qemu-0.15.x/roms/ipxe/src/net/eth_slow.c           |  270 +
 qemu-0.15.x/roms/ipxe/src/net/ethernet.c           |  196 +
 qemu-0.15.x/roms/ipxe/src/net/fakedhcp.c           |  217 +
 qemu-0.15.x/roms/ipxe/src/net/fc.c                 | 1900 +++
 qemu-0.15.x/roms/ipxe/src/net/fcels.c              | 1338 ++
 qemu-0.15.x/roms/ipxe/src/net/fcns.c               |  240 +
 qemu-0.15.x/roms/ipxe/src/net/fcoe.c               | 1224 ++
 qemu-0.15.x/roms/ipxe/src/net/fcp.c                | 1070 ++
 qemu-0.15.x/roms/ipxe/src/net/icmp.c               |  103 +
 qemu-0.15.x/roms/ipxe/src/net/icmpv6.c             |  126 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband.c         |  995 ++
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cm.c   |  495 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cmrc.c |  434 +
 .../roms/ipxe/src/net/infiniband/ib_mcast.c        |  212 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mi.c   |  406 +
 .../roms/ipxe/src/net/infiniband/ib_packet.c       |  241 +
 .../roms/ipxe/src/net/infiniband/ib_pathrec.c      |  288 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_sma.c  |  370 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_smc.c  |  255 +
 qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_srp.c  |  581 +
 qemu-0.15.x/roms/ipxe/src/net/iobpad.c             |   68 +
 qemu-0.15.x/roms/ipxe/src/net/ipv4.c               |  636 +
 qemu-0.15.x/roms/ipxe/src/net/ipv6.c               |  382 +
 qemu-0.15.x/roms/ipxe/src/net/mii.c                |  147 +
 qemu-0.15.x/roms/ipxe/src/net/ndp.c                |  180 +
 qemu-0.15.x/roms/ipxe/src/net/netdev_settings.c    |  140 +
 qemu-0.15.x/roms/ipxe/src/net/netdevice.c          |  758 ++
 qemu-0.15.x/roms/ipxe/src/net/nullnet.c            |   60 +
 qemu-0.15.x/roms/ipxe/src/net/rarp.c               |   72 +
 qemu-0.15.x/roms/ipxe/src/net/retry.c              |  204 +
 qemu-0.15.x/roms/ipxe/src/net/tcp.c                | 1353 +++
 qemu-0.15.x/roms/ipxe/src/net/tcp/ftp.c            |  491 +
 qemu-0.15.x/roms/ipxe/src/net/tcp/http.c           |  562 +
 qemu-0.15.x/roms/ipxe/src/net/tcp/https.c          |   51 +
 qemu-0.15.x/roms/ipxe/src/net/tcp/iscsi.c          | 2101 ++++
 qemu-0.15.x/roms/ipxe/src/net/tcpip.c              |  135 +
 qemu-0.15.x/roms/ipxe/src/net/tls.c                | 1754 +++
 qemu-0.15.x/roms/ipxe/src/net/udp.c                |  448 +
 qemu-0.15.x/roms/ipxe/src/net/udp/dhcp.c           | 1478 +++
 qemu-0.15.x/roms/ipxe/src/net/udp/dns.c            |  640 +
 qemu-0.15.x/roms/ipxe/src/net/udp/slam.c           |  756 ++
 qemu-0.15.x/roms/ipxe/src/net/udp/syslog.c         |  206 +
 qemu-0.15.x/roms/ipxe/src/net/udp/tftp.c           | 1267 ++
 qemu-0.15.x/roms/ipxe/src/net/vlan.c               |  490 +
 qemu-0.15.x/roms/ipxe/src/tests/bofm_test.c        |  169 +
 .../roms/ipxe/src/tests/comboot/shuffle-simple.asm |   40 +
 .../roms/ipxe/src/tests/comboot/version.asm        |  136 +
 qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.S     |   54 +
 qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.gdb   |  116 +
 qemu-0.15.x/roms/ipxe/src/tests/linebuf_test.c     |   35 +
 qemu-0.15.x/roms/ipxe/src/tests/memcpy_test.c      |   39 +
 qemu-0.15.x/roms/ipxe/src/tests/umalloc_test.c     |   26 +
 qemu-0.15.x/roms/ipxe/src/tests/uri_test.c         |  146 +
 qemu-0.15.x/roms/ipxe/src/usr/autoboot.c           |  407 +
 qemu-0.15.x/roms/ipxe/src/usr/dhcpmgmt.c           |   80 +
 qemu-0.15.x/roms/ipxe/src/usr/fcmgmt.c             |  116 +
 qemu-0.15.x/roms/ipxe/src/usr/ifmgmt.c             |  148 +
 qemu-0.15.x/roms/ipxe/src/usr/imgmgmt.c            |  243 +
 qemu-0.15.x/roms/ipxe/src/usr/iwmgmt.c             |  226 +
 qemu-0.15.x/roms/ipxe/src/usr/lotest.c             |  217 +
 qemu-0.15.x/roms/ipxe/src/usr/prompt.c             |   66 +
 qemu-0.15.x/roms/ipxe/src/usr/pxemenu.c            |  383 +
 qemu-0.15.x/roms/ipxe/src/usr/route.c              |   45 +
 qemu-0.15.x/roms/ipxe/src/util/.gitignore          |    9 +
 qemu-0.15.x/roms/ipxe/src/util/Makefile            |   22 +
 qemu-0.15.x/roms/ipxe/src/util/Option/ROM.pm       |  502 +
 qemu-0.15.x/roms/ipxe/src/util/catrom.pl           |   48 +
 qemu-0.15.x/roms/ipxe/src/util/diffsize.pl         |  101 +
 qemu-0.15.x/roms/ipxe/src/util/disrom.pl           |   81 +
 qemu-0.15.x/roms/ipxe/src/util/efirom.c            |  280 +
 qemu-0.15.x/roms/ipxe/src/util/einfo.c             |  167 +
 qemu-0.15.x/roms/ipxe/src/util/elf2efi.c           |  809 ++
 qemu-0.15.x/roms/ipxe/src/util/fixrom.pl           |   34 +
 qemu-0.15.x/roms/ipxe/src/util/fnrec.pl            |  145 +
 qemu-0.15.x/roms/ipxe/src/util/geniso              |   72 +
 qemu-0.15.x/roms/ipxe/src/util/genkeymap.pl        |  235 +
 qemu-0.15.x/roms/ipxe/src/util/genliso             |   74 +
 qemu-0.15.x/roms/ipxe/src/util/gensdsk             |   65 +
 qemu-0.15.x/roms/ipxe/src/util/get-pci-ids         |  135 +
 qemu-0.15.x/roms/ipxe/src/util/hijack.c            |  628 +
 qemu-0.15.x/roms/ipxe/src/util/iccfix.c            |  156 +
 qemu-0.15.x/roms/ipxe/src/util/licence.pl          |  149 +
 qemu-0.15.x/roms/ipxe/src/util/mergerom.pl         |   98 +
 qemu-0.15.x/roms/ipxe/src/util/modrom.pl           |  226 +
 qemu-0.15.x/roms/ipxe/src/util/mucurses_test.c     |   63 +
 qemu-0.15.x/roms/ipxe/src/util/nrv2b.c             | 1501 +++
 qemu-0.15.x/roms/ipxe/src/util/padimg.pl           |   44 +
 qemu-0.15.x/roms/ipxe/src/util/parserom.pl         |   66 +
 qemu-0.15.x/roms/ipxe/src/util/sortobjdump.pl      |   40 +
 qemu-0.15.x/roms/ipxe/src/util/swapdevids.pl       |   49 +
 qemu-0.15.x/roms/ipxe/src/util/symcheck.pl         |  191 +
 qemu-0.15.x/roms/ipxe/src/util/zbin.c              |  434 +
 qemu-0.15.x/roms/seabios/.gitignore                |    4 +
 qemu-0.15.x/roms/seabios/COPYING                   |  674 ++
 qemu-0.15.x/roms/seabios/COPYING.LESSER            |  165 +
 qemu-0.15.x/roms/seabios/Makefile                  |  230 +
 qemu-0.15.x/roms/seabios/README                    |  190 +
 qemu-0.15.x/roms/seabios/TODO                      |   29 +
 qemu-0.15.x/roms/seabios/src/Kconfig               |  370 +
 qemu-0.15.x/roms/seabios/src/acpi-dsdt.dsl         |  926 ++
 qemu-0.15.x/roms/seabios/src/acpi-dsdt.hex         | 1212 ++
 qemu-0.15.x/roms/seabios/src/acpi.c                |  694 ++
 qemu-0.15.x/roms/seabios/src/acpi.h                |  101 +
 qemu-0.15.x/roms/seabios/src/ahci.c                |  484 +
 qemu-0.15.x/roms/seabios/src/ahci.h                |  196 +
 qemu-0.15.x/roms/seabios/src/apm.c                 |  238 +
 qemu-0.15.x/roms/seabios/src/asm-offsets.c         |   31 +
 qemu-0.15.x/roms/seabios/src/ata.c                 | 1044 ++
 qemu-0.15.x/roms/seabios/src/ata.h                 |  153 +
 qemu-0.15.x/roms/seabios/src/biosvar.h             |  332 +
 qemu-0.15.x/roms/seabios/src/block.c               |  324 +
 qemu-0.15.x/roms/seabios/src/blockcmd.c            |   81 +
 qemu-0.15.x/roms/seabios/src/blockcmd.h            |   77 +
 qemu-0.15.x/roms/seabios/src/boot.c                |  648 +
 qemu-0.15.x/roms/seabios/src/boot.h                |   22 +
 qemu-0.15.x/roms/seabios/src/bootsplash.c          |  255 +
 qemu-0.15.x/roms/seabios/src/bregs.h               |   96 +
 qemu-0.15.x/roms/seabios/src/cdrom.c               |  379 +
 qemu-0.15.x/roms/seabios/src/clock.c               |  650 +
 qemu-0.15.x/roms/seabios/src/cmos.h                |   74 +
 qemu-0.15.x/roms/seabios/src/config.h              |  123 +
 qemu-0.15.x/roms/seabios/src/coreboot.c            |  617 +
 qemu-0.15.x/roms/seabios/src/dev-i440fx.c          |  116 +
 qemu-0.15.x/roms/seabios/src/dev-i440fx.h          |   14 +
 qemu-0.15.x/roms/seabios/src/disk.c                |  896 ++
 qemu-0.15.x/roms/seabios/src/disk.h                |  259 +
 qemu-0.15.x/roms/seabios/src/entryfuncs.S          |  173 +
 qemu-0.15.x/roms/seabios/src/farptr.h              |  204 +
 qemu-0.15.x/roms/seabios/src/floppy.c              |  622 +
 qemu-0.15.x/roms/seabios/src/font.c                |  139 +
 qemu-0.15.x/roms/seabios/src/gen-defs.h            |   19 +
 qemu-0.15.x/roms/seabios/src/ioport.h              |  136 +
 qemu-0.15.x/roms/seabios/src/jpeg.c                | 1041 ++
 qemu-0.15.x/roms/seabios/src/jpeg.h                |   11 +
 qemu-0.15.x/roms/seabios/src/kbd.c                 |  573 +
 qemu-0.15.x/roms/seabios/src/lzmadecode.c          |  398 +
 qemu-0.15.x/roms/seabios/src/lzmadecode.h          |   67 +
 qemu-0.15.x/roms/seabios/src/memmap.c              |  127 +
 qemu-0.15.x/roms/seabios/src/memmap.h              |   32 +
 qemu-0.15.x/roms/seabios/src/misc.c                |  190 +
 qemu-0.15.x/roms/seabios/src/mouse.c               |  344 +
 qemu-0.15.x/roms/seabios/src/mptable.c             |  206 +
 qemu-0.15.x/roms/seabios/src/mptable.h             |   80 +
 qemu-0.15.x/roms/seabios/src/mtrr.c                |  102 +
 qemu-0.15.x/roms/seabios/src/optionroms.c          |  495 +
 qemu-0.15.x/roms/seabios/src/output.c              |  582 +
 qemu-0.15.x/roms/seabios/src/paravirt.c            |  411 +
 qemu-0.15.x/roms/seabios/src/paravirt.h            |  108 +
 qemu-0.15.x/roms/seabios/src/pci.c                 |  304 +
 qemu-0.15.x/roms/seabios/src/pci.h                 |  148 +
 qemu-0.15.x/roms/seabios/src/pci_ids.h             | 2610 ++++
 qemu-0.15.x/roms/seabios/src/pci_region.c          |   77 +
 qemu-0.15.x/roms/seabios/src/pci_regs.h            |  556 +
 qemu-0.15.x/roms/seabios/src/pcibios.c             |  234 +
 qemu-0.15.x/roms/seabios/src/pciinit.c             |  418 +
 qemu-0.15.x/roms/seabios/src/pic.c                 |   52 +
 qemu-0.15.x/roms/seabios/src/pic.h                 |   97 +
 qemu-0.15.x/roms/seabios/src/pirtable.c            |  105 +
 qemu-0.15.x/roms/seabios/src/pmm.c                 |  588 +
 qemu-0.15.x/roms/seabios/src/pnpbios.c             |  103 +
 qemu-0.15.x/roms/seabios/src/post.c                |  389 +
 qemu-0.15.x/roms/seabios/src/ps2port.c             |  472 +
 qemu-0.15.x/roms/seabios/src/ps2port.h             |   63 +
 qemu-0.15.x/roms/seabios/src/ramdisk.c             |  105 +
 qemu-0.15.x/roms/seabios/src/resume.c              |  125 +
 qemu-0.15.x/roms/seabios/src/romlayout.S           |  589 +
 qemu-0.15.x/roms/seabios/src/serial.c              |  315 +
 qemu-0.15.x/roms/seabios/src/shadow.c              |  151 +
 qemu-0.15.x/roms/seabios/src/smbios.c              |  514 +
 qemu-0.15.x/roms/seabios/src/smbios.h              |  166 +
 qemu-0.15.x/roms/seabios/src/smm.c                 |  127 +
 qemu-0.15.x/roms/seabios/src/smp.c                 |  129 +
 qemu-0.15.x/roms/seabios/src/ssdt-proc.dsl         |   50 +
 qemu-0.15.x/roms/seabios/src/stacks.c              |  395 +
 qemu-0.15.x/roms/seabios/src/system.c              |  365 +
 qemu-0.15.x/roms/seabios/src/types.h               |  142 +
 qemu-0.15.x/roms/seabios/src/usb-ehci.c            |  761 ++
 qemu-0.15.x/roms/seabios/src/usb-ehci.h            |  173 +
 qemu-0.15.x/roms/seabios/src/usb-hid.c             |  418 +
 qemu-0.15.x/roms/seabios/src/usb-hid.h             |   31 +
 qemu-0.15.x/roms/seabios/src/usb-hub.c             |  185 +
 qemu-0.15.x/roms/seabios/src/usb-hub.h             |   60 +
 qemu-0.15.x/roms/seabios/src/usb-msc.c             |  260 +
 qemu-0.15.x/roms/seabios/src/usb-msc.h             |   27 +
 qemu-0.15.x/roms/seabios/src/usb-ohci.c            |  532 +
 qemu-0.15.x/roms/seabios/src/usb-ohci.h            |  143 +
 qemu-0.15.x/roms/seabios/src/usb-uhci.c            |  604 +
 qemu-0.15.x/roms/seabios/src/usb-uhci.h            |  128 +
 qemu-0.15.x/roms/seabios/src/usb.c                 |  473 +
 qemu-0.15.x/roms/seabios/src/usb.h                 |  216 +
 qemu-0.15.x/roms/seabios/src/util.c                |  324 +
 qemu-0.15.x/roms/seabios/src/util.h                |  500 +
 qemu-0.15.x/roms/seabios/src/vgahooks.c            |  316 +
 qemu-0.15.x/roms/seabios/src/virtio-blk.c          |  184 +
 qemu-0.15.x/roms/seabios/src/virtio-blk.h          |   43 +
 qemu-0.15.x/roms/seabios/src/virtio-pci.c          |   69 +
 qemu-0.15.x/roms/seabios/src/virtio-pci.h          |  104 +
 qemu-0.15.x/roms/seabios/src/virtio-ring.c         |  151 +
 qemu-0.15.x/roms/seabios/src/virtio-ring.h         |  131 +
 qemu-0.15.x/roms/seabios/tools/buildrom.py         |   43 +
 qemu-0.15.x/roms/seabios/tools/checkrom.py         |   63 +
 qemu-0.15.x/roms/seabios/tools/checkstack.py       |  225 +
 qemu-0.15.x/roms/seabios/tools/checksum.py         |   16 +
 qemu-0.15.x/roms/seabios/tools/gen-offsets.sh      |   17 +
 qemu-0.15.x/roms/seabios/tools/kconfig/.gitignore  |   23 +
 qemu-0.15.x/roms/seabios/tools/kconfig/Makefile    |  361 +
 qemu-0.15.x/roms/seabios/tools/kconfig/POTFILES.in |   12 +
 qemu-0.15.x/roms/seabios/tools/kconfig/check.sh    |   14 +
 qemu-0.15.x/roms/seabios/tools/kconfig/conf.c      |  654 +
 qemu-0.15.x/roms/seabios/tools/kconfig/confdata.c  | 1062 ++
 qemu-0.15.x/roms/seabios/tools/kconfig/expr.c      | 1173 ++
 qemu-0.15.x/roms/seabios/tools/kconfig/expr.h      |  231 +
 qemu-0.15.x/roms/seabios/tools/kconfig/gconf.c     | 1577 +++
 qemu-0.15.x/roms/seabios/tools/kconfig/gconf.glade |  661 +
 qemu-0.15.x/roms/seabios/tools/kconfig/images.c    |  326 +
 .../roms/seabios/tools/kconfig/kconfig_load.c      |   35 +
 qemu-0.15.x/roms/seabios/tools/kconfig/kxgettext.c |  236 +
 .../roms/seabios/tools/kconfig/lex.zconf.c_shipped | 2430 ++++
 qemu-0.15.x/roms/seabios/tools/kconfig/lkc.h       |  196 +
 qemu-0.15.x/roms/seabios/tools/kconfig/lkc_proto.h |   53 +
 .../roms/seabios/tools/kconfig/lxdialog/.gitignore |    4 +
 .../seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING |    4 +
 .../tools/kconfig/lxdialog/check-lxdialog.sh       |   84 +
 .../seabios/tools/kconfig/lxdialog/checklist.c     |  332 +
 .../roms/seabios/tools/kconfig/lxdialog/dialog.h   |  230 +
 .../roms/seabios/tools/kconfig/lxdialog/inputbox.c |  238 +
 .../roms/seabios/tools/kconfig/lxdialog/menubox.c  |  434 +
 .../roms/seabios/tools/kconfig/lxdialog/textbox.c  |  391 +
 .../roms/seabios/tools/kconfig/lxdialog/util.c     |  657 +
 .../roms/seabios/tools/kconfig/lxdialog/yesno.c    |  114 +
 qemu-0.15.x/roms/seabios/tools/kconfig/mconf.c     |  862 ++
 qemu-0.15.x/roms/seabios/tools/kconfig/menu.c      |  609 +
 qemu-0.15.x/roms/seabios/tools/kconfig/nconf.c     | 1561 +++
 qemu-0.15.x/roms/seabios/tools/kconfig/nconf.gui.c |  617 +
 qemu-0.15.x/roms/seabios/tools/kconfig/nconf.h     |   96 +
 qemu-0.15.x/roms/seabios/tools/kconfig/qconf.cc    | 1787 +++
 qemu-0.15.x/roms/seabios/tools/kconfig/qconf.h     |  337 +
 qemu-0.15.x/roms/seabios/tools/kconfig/symbol.c    | 1260 ++
 qemu-0.15.x/roms/seabios/tools/kconfig/util.c      |  138 +
 qemu-0.15.x/roms/seabios/tools/kconfig/zconf.gperf |   47 +
 .../seabios/tools/kconfig/zconf.hash.c_shipped     |  245 +
 qemu-0.15.x/roms/seabios/tools/kconfig/zconf.l     |  360 +
 .../roms/seabios/tools/kconfig/zconf.tab.c_shipped | 2505 ++++
 qemu-0.15.x/roms/seabios/tools/kconfig/zconf.y     |  749 ++
 qemu-0.15.x/roms/seabios/tools/layoutrom.py        |  579 +
 qemu-0.15.x/roms/seabios/tools/readserial.py       |  137 +
 qemu-0.15.x/roms/seabios/tools/test-gcc.sh         |   88 +
 qemu-0.15.x/roms/seabios/tools/transdump.py        |   50 +
 qemu-0.15.x/roms/seabios/vgasrc/clext.c            |  390 +
 qemu-0.15.x/roms/seabios/vgasrc/vga.c              | 1387 +++
 qemu-0.15.x/roms/seabios/vgasrc/vgaentry.S         |   48 +
 qemu-0.15.x/roms/seabios/vgasrc/vgafb.c            |  512 +
 qemu-0.15.x/roms/seabios/vgasrc/vgafonts.c         |  785 ++
 qemu-0.15.x/roms/seabios/vgasrc/vgaio.c            |  555 +
 qemu-0.15.x/roms/seabios/vgasrc/vgalayout.lds.S    |   24 +
 qemu-0.15.x/roms/seabios/vgasrc/vgatables.c        |  438 +
 qemu-0.15.x/roms/seabios/vgasrc/vgatables.h        |  217 +
 qemu-0.15.x/roms/vgabios/.cvsignore                |    1 +
 qemu-0.15.x/roms/vgabios/BUGS                      |    3 +
 qemu-0.15.x/roms/vgabios/COPYING                   |  504 +
 qemu-0.15.x/roms/vgabios/ChangeLog                 | 1311 ++
 qemu-0.15.x/roms/vgabios/Makefile                  |  103 +
 qemu-0.15.x/roms/vgabios/Notes                     |   11 +
 qemu-0.15.x/roms/vgabios/README                    |  226 +
 qemu-0.15.x/roms/vgabios/TODO                      |   26 +
 qemu-0.15.x/roms/vgabios/biossums.c                |  282 +
 qemu-0.15.x/roms/vgabios/clext.c                   | 1641 +++
 qemu-0.15.x/roms/vgabios/dataseghack               |   23 +
 qemu-0.15.x/roms/vgabios/tests/lfbprof/Makefile    |    5 +
 qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.c   |  594 +
 qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.h   |  149 +
 qemu-0.15.x/roms/vgabios/tests/testbios.c          |  353 +
 qemu-0.15.x/roms/vgabios/vbe.c                     | 1456 +++
 qemu-0.15.x/roms/vgabios/vbe.h                     |  315 +
 qemu-0.15.x/roms/vgabios/vbe_display_api.txt       |  237 +
 qemu-0.15.x/roms/vgabios/vbetables-gen.c           |  261 +
 qemu-0.15.x/roms/vgabios/vgabios.c                 | 3923 ++++++
 qemu-0.15.x/roms/vgabios/vgabios.h                 |   47 +
 qemu-0.15.x/roms/vgabios/vgafonts.h                |  784 ++
 qemu-0.15.x/roms/vgabios/vgatables.h               |  622 +
 qemu-0.15.x/rules.mak                              |   72 +
 qemu-0.15.x/rwhandler.c                            |   87 +
 qemu-0.15.x/rwhandler.h                            |   27 +
 qemu-0.15.x/s390-dis.c                             | 1796 +++
 qemu-0.15.x/s390.ld                                |  201 +
 qemu-0.15.x/savevm.c                               | 2179 ++++
 qemu-0.15.x/scripts/checkpatch.pl                  | 2913 +++++
 qemu-0.15.x/scripts/create_config                  |  103 +
 qemu-0.15.x/scripts/feature_to_c.sh                |   78 +
 qemu-0.15.x/scripts/get_maintainer.pl              | 2149 ++++
 qemu-0.15.x/scripts/hxtool                         |  102 +
 qemu-0.15.x/scripts/make_device_config.sh          |   28 +
 qemu-0.15.x/scripts/ordereddict.py                 |  127 +
 qemu-0.15.x/scripts/qapi-commands.py               |  385 +
 qemu-0.15.x/scripts/qapi-types.py                  |  270 +
 qemu-0.15.x/scripts/qapi-visit.py                  |  246 +
 qemu-0.15.x/scripts/qapi.py                        |  203 +
 qemu-0.15.x/scripts/qemu-binfmt-conf.sh            |   68 +
 qemu-0.15.x/scripts/refresh-pxe-roms.sh            |   99 +
 qemu-0.15.x/scripts/signrom.sh                     |   45 +
 qemu-0.15.x/scripts/simpletrace.py                 |  151 +
 qemu-0.15.x/scripts/texi2pod.pl                    |  477 +
 qemu-0.15.x/scripts/tracetool                      |  637 +
 qemu-0.15.x/scripts/update-linux-headers.sh        |   55 +
 qemu-0.15.x/sh4-dis.c                              | 2077 ++++
 qemu-0.15.x/simpletrace.c                          |  355 +
 qemu-0.15.x/simpletrace.h                          |   48 +
 qemu-0.15.x/slirp/COPYRIGHT                        |   61 +
 qemu-0.15.x/slirp/bootp.c                          |  314 +
 qemu-0.15.x/slirp/bootp.h                          |  122 +
 qemu-0.15.x/slirp/cksum.c                          |  139 +
 qemu-0.15.x/slirp/debug.h                          |   34 +
 qemu-0.15.x/slirp/if.c                             |  209 +
 qemu-0.15.x/slirp/if.h                             |   25 +
 qemu-0.15.x/slirp/ip.h                             |  253 +
 qemu-0.15.x/slirp/ip_icmp.c                        |  438 +
 qemu-0.15.x/slirp/ip_icmp.h                        |  164 +
 qemu-0.15.x/slirp/ip_input.c                       |  662 +
 qemu-0.15.x/slirp/ip_output.c                      |  172 +
 qemu-0.15.x/slirp/libslirp.h                       |   56 +
 qemu-0.15.x/slirp/main.h                           |   46 +
 qemu-0.15.x/slirp/mbuf.c                           |  218 +
 qemu-0.15.x/slirp/mbuf.h                           |  124 +
 qemu-0.15.x/slirp/misc.c                           |  423 +
 qemu-0.15.x/slirp/misc.h                           |   72 +
 qemu-0.15.x/slirp/sbuf.c                           |  181 +
 qemu-0.15.x/slirp/sbuf.h                           |   30 +
 qemu-0.15.x/slirp/slirp.c                          | 1150 ++
 qemu-0.15.x/slirp/slirp.h                          |  325 +
 qemu-0.15.x/slirp/slirp_config.h                   |  188 +
 qemu-0.15.x/slirp/socket.c                         |  728 ++
 qemu-0.15.x/slirp/socket.h                         |   95 +
 qemu-0.15.x/slirp/tcp.h                            |  164 +
 qemu-0.15.x/slirp/tcp_input.c                      | 1487 +++
 qemu-0.15.x/slirp/tcp_output.c                     |  492 +
 qemu-0.15.x/slirp/tcp_subr.c                       |  915 ++
 qemu-0.15.x/slirp/tcp_timer.c                      |  292 +
 qemu-0.15.x/slirp/tcp_timer.h                      |  127 +
 qemu-0.15.x/slirp/tcp_var.h                        |  161 +
 qemu-0.15.x/slirp/tcpip.h                          |   77 +
 qemu-0.15.x/slirp/tftp.c                           |  422 +
 qemu-0.15.x/slirp/tftp.h                           |   43 +
 qemu-0.15.x/slirp/udp.c                            |  387 +
 qemu-0.15.x/slirp/udp.h                            |   86 +
 qemu-0.15.x/softmmu-semi.h                         |   70 +
 qemu-0.15.x/softmmu_defs.h                         |   22 +
 qemu-0.15.x/softmmu_exec.h                         |  153 +
 qemu-0.15.x/softmmu_header.h                       |  198 +
 qemu-0.15.x/softmmu_template.h                     |  332 +
 qemu-0.15.x/sparc-dis.c                            | 3275 +++++
 qemu-0.15.x/sparc.ld                               |  150 +
 qemu-0.15.x/sparc64.ld                             |  138 +
 qemu-0.15.x/spice-qemu-char.c                      |  204 +
 qemu-0.15.x/sysconfigs/target/target-x86_64.conf   |   86 +
 qemu-0.15.x/sysemu.h                               |  178 +
 qemu-0.15.x/target-alpha/STATUS                    |   28 +
 qemu-0.15.x/target-alpha/cpu.h                     |  516 +
 qemu-0.15.x/target-alpha/exec.h                    |   39 +
 qemu-0.15.x/target-alpha/helper.c                  |  486 +
 qemu-0.15.x/target-alpha/helper.h                  |  118 +
 qemu-0.15.x/target-alpha/machine.c                 |   87 +
 qemu-0.15.x/target-alpha/op_helper.c               | 1350 +++
 qemu-0.15.x/target-alpha/translate.c               | 3488 ++++++
 qemu-0.15.x/target-arm/cpu.h                       |  535 +
 qemu-0.15.x/target-arm/exec.h                      |   30 +
 qemu-0.15.x/target-arm/helper.c                    | 3068 +++++
 qemu-0.15.x/target-arm/helper.h                    |  472 +
 qemu-0.15.x/target-arm/iwmmxt_helper.c             |  681 ++
 qemu-0.15.x/target-arm/machine.c                   |  225 +
 qemu-0.15.x/target-arm/neon_helper.c               | 2017 ++++
 qemu-0.15.x/target-arm/op_addsub.h                 |  103 +
 qemu-0.15.x/target-arm/op_helper.c                 |  426 +
 qemu-0.15.x/target-arm/translate.c                 |10073 ++++++++++++++++
 qemu-0.15.x/target-cris/cpu.h                      |  282 +
 qemu-0.15.x/target-cris/crisv10-decode.h           |  107 +
 qemu-0.15.x/target-cris/crisv32-decode.h           |  128 +
 qemu-0.15.x/target-cris/exec.h                     |   28 +
 qemu-0.15.x/target-cris/helper.c                   |  270 +
 qemu-0.15.x/target-cris/helper.h                   |   26 +
 qemu-0.15.x/target-cris/machine.c                  |   90 +
 qemu-0.15.x/target-cris/mmu.c                      |  367 +
 qemu-0.15.x/target-cris/mmu.h                      |   17 +
 qemu-0.15.x/target-cris/op_helper.c                |  655 +
 qemu-0.15.x/target-cris/opcode-cris.h              |  365 +
 qemu-0.15.x/target-cris/translate.c                | 3609 ++++++
 qemu-0.15.x/target-cris/translate_v10.c            | 1242 ++
 qemu-0.15.x/target-i386/TODO                       |   32 +
 qemu-0.15.x/target-i386/cpu.h                      | 1060 ++
 qemu-0.15.x/target-i386/cpuid.c                    | 1308 ++
 qemu-0.15.x/target-i386/exec.h                     |  142 +
 qemu-0.15.x/target-i386/helper.c                   | 1292 ++
 qemu-0.15.x/target-i386/helper.h                   |  220 +
 qemu-0.15.x/target-i386/helper_template.h          |  334 +
 qemu-0.15.x/target-i386/kvm.c                      | 1837 +++
 qemu-0.15.x/target-i386/machine.c                  |  437 +
 qemu-0.15.x/target-i386/op_helper.c                | 5719 +++++++++
 qemu-0.15.x/target-i386/ops_sse.h                  | 2087 ++++
 qemu-0.15.x/target-i386/ops_sse_header.h           |  349 +
 qemu-0.15.x/target-i386/svm.h                      |  222 +
 qemu-0.15.x/target-i386/translate.c                | 7913 ++++++++++++
 qemu-0.15.x/target-lm32/README                     |   46 +
 qemu-0.15.x/target-lm32/TODO                       |    3 +
 qemu-0.15.x/target-lm32/cpu.h                      |  257 +
 qemu-0.15.x/target-lm32/exec.h                     |   38 +
 qemu-0.15.x/target-lm32/helper.c                   |  254 +
 qemu-0.15.x/target-lm32/helper.h                   |   14 +
 qemu-0.15.x/target-lm32/machine.c                  |   33 +
 qemu-0.15.x/target-lm32/op_helper.c                |  106 +
 qemu-0.15.x/target-lm32/translate.c                | 1239 ++
 qemu-0.15.x/target-m68k/cpu.h                      |  270 +
 qemu-0.15.x/target-m68k/exec.h                     |   28 +
 qemu-0.15.x/target-m68k/helper.c                   |  923 ++
 qemu-0.15.x/target-m68k/helpers.h                  |   54 +
 qemu-0.15.x/target-m68k/m68k-qreg.h                |   11 +
 qemu-0.15.x/target-m68k/op_helper.c                |  248 +
 qemu-0.15.x/target-m68k/qregs.def                  |   13 +
 qemu-0.15.x/target-m68k/translate.c                | 3115 +++++
 qemu-0.15.x/target-microblaze/cpu.h                |  366 +
 qemu-0.15.x/target-microblaze/exec.h               |   27 +
 qemu-0.15.x/target-microblaze/helper.c             |  281 +
 qemu-0.15.x/target-microblaze/helper.h             |   39 +
 qemu-0.15.x/target-microblaze/machine.c            |   11 +
 qemu-0.15.x/target-microblaze/microblaze-decode.h  |   55 +
 qemu-0.15.x/target-microblaze/mmu.c                |  302 +
 qemu-0.15.x/target-microblaze/mmu.h                |   91 +
 qemu-0.15.x/target-microblaze/op_helper.c          |  520 +
 qemu-0.15.x/target-microblaze/translate.c          | 1945 +++
 qemu-0.15.x/target-mips/TODO                       |   52 +
 qemu-0.15.x/target-mips/cpu.h                      |  683 ++
 qemu-0.15.x/target-mips/exec.h                     |   60 +
 qemu-0.15.x/target-mips/helper.c                   |  693 ++
 qemu-0.15.x/target-mips/helper.h                   |  290 +
 qemu-0.15.x/target-mips/machine.c                  |  308 +
 qemu-0.15.x/target-mips/mips-defs.h                |   72 +
 qemu-0.15.x/target-mips/op_helper.c                | 3048 +++++
 qemu-0.15.x/target-mips/translate.c                |12744 ++++++++++++++++++++
 qemu-0.15.x/target-mips/translate_init.c           |  594 +
 qemu-0.15.x/target-ppc/STATUS                      |  559 +
 qemu-0.15.x/target-ppc/cpu.h                       | 2031 ++++
 qemu-0.15.x/target-ppc/exec.h                      |   34 +
 qemu-0.15.x/target-ppc/helper.c                    | 3107 +++++
 qemu-0.15.x/target-ppc/helper.h                    |  411 +
 qemu-0.15.x/target-ppc/helper_regs.h               |  111 +
 qemu-0.15.x/target-ppc/kvm.c                       |  555 +
 qemu-0.15.x/target-ppc/kvm_ppc.c                   |  105 +
 qemu-0.15.x/target-ppc/kvm_ppc.h                   |   53 +
 qemu-0.15.x/target-ppc/machine.c                   |  181 +
 qemu-0.15.x/target-ppc/mfrom_table.c               |   79 +
 qemu-0.15.x/target-ppc/mfrom_table_gen.c           |   33 +
 qemu-0.15.x/target-ppc/op_helper.c                 | 4409 +++++++
 qemu-0.15.x/target-ppc/translate.c                 | 9539 +++++++++++++++
 qemu-0.15.x/target-ppc/translate_init.c            |10067 ++++++++++++++++
 qemu-0.15.x/target-s390x/cpu.h                     |  976 ++
 qemu-0.15.x/target-s390x/exec.h                    |   37 +
 qemu-0.15.x/target-s390x/helper.c                  |  627 +
 qemu-0.15.x/target-s390x/helpers.h                 |  151 +
 qemu-0.15.x/target-s390x/kvm.c                     |  490 +
 qemu-0.15.x/target-s390x/machine.c                 |   30 +
 qemu-0.15.x/target-s390x/op_helper.c               | 2991 +++++
 qemu-0.15.x/target-s390x/translate.c               | 5245 ++++++++
 qemu-0.15.x/target-sh4/README.sh4                  |  150 +
 qemu-0.15.x/target-sh4/cpu.h                       |  377 +
 qemu-0.15.x/target-sh4/exec.h                      |   33 +
 qemu-0.15.x/target-sh4/helper.c                    |  842 ++
 qemu-0.15.x/target-sh4/helper.h                    |   54 +
 qemu-0.15.x/target-sh4/op_helper.c                 |  752 ++
 qemu-0.15.x/target-sh4/translate.c                 | 2075 ++++
 qemu-0.15.x/target-sparc/TODO                      |   88 +
 qemu-0.15.x/target-sparc/cpu.h                     |  731 ++
 qemu-0.15.x/target-sparc/exec.h                    |   15 +
 qemu-0.15.x/target-sparc/helper.c                  | 1857 +++
 qemu-0.15.x/target-sparc/helper.h                  |  165 +
 qemu-0.15.x/target-sparc/machine.c                 |  225 +
 qemu-0.15.x/target-sparc/op_helper.c               | 4371 +++++++
 qemu-0.15.x/target-sparc/translate.c               | 5140 ++++++++
 qemu-0.15.x/target-unicore32/cpu.h                 |  188 +
 qemu-0.15.x/target-unicore32/exec.h                |   43 +
 qemu-0.15.x/target-unicore32/helper.c              |  486 +
 qemu-0.15.x/target-unicore32/helper.h              |   70 +
 qemu-0.15.x/target-unicore32/op_helper.c           |  248 +
 qemu-0.15.x/target-unicore32/translate.c           | 2103 ++++
 qemu-0.15.x/targphys.h                             |   21 +
 qemu-0.15.x/tcg-runtime.c                          |   85 +
 qemu-0.15.x/tcg/LICENSE                            |    3 +
 qemu-0.15.x/tcg/README                             |  519 +
 qemu-0.15.x/tcg/TODO                               |   14 +
 qemu-0.15.x/tcg/arm/tcg-target.c                   | 1865 +++
 qemu-0.15.x/tcg/arm/tcg-target.h                   |   93 +
 qemu-0.15.x/tcg/hppa/tcg-target.c                  | 1710 +++
 qemu-0.15.x/tcg/hppa/tcg-target.h                  |  120 +
 qemu-0.15.x/tcg/i386/tcg-target.c                  | 1988 +++
 qemu-0.15.x/tcg/i386/tcg-target.h                  |  126 +
 qemu-0.15.x/tcg/ia64/tcg-target.c                  | 2393 ++++
 qemu-0.15.x/tcg/ia64/tcg-target.h                  |  156 +
 qemu-0.15.x/tcg/mips/tcg-target.c                  | 1533 +++
 qemu-0.15.x/tcg/mips/tcg-target.h                  |  114 +
 qemu-0.15.x/tcg/ppc/tcg-target.c                   | 1922 +++
 qemu-0.15.x/tcg/ppc/tcg-target.h                   |   98 +
 qemu-0.15.x/tcg/ppc64/tcg-target.c                 | 1699 +++
 qemu-0.15.x/tcg/ppc64/tcg-target.h                 |  109 +
 qemu-0.15.x/tcg/s390/tcg-target.c                  | 2327 ++++
 qemu-0.15.x/tcg/s390/tcg-target.h                  |  109 +
 qemu-0.15.x/tcg/sparc/tcg-target.c                 | 1572 +++
 qemu-0.15.x/tcg/sparc/tcg-target.h                 |  150 +
 qemu-0.15.x/tcg/tcg-op.h                           | 2539 ++++
 qemu-0.15.x/tcg/tcg-opc.h                          |  310 +
 qemu-0.15.x/tcg/tcg-runtime.h                      |   18 +
 qemu-0.15.x/tcg/tcg.c                              | 2224 ++++
 qemu-0.15.x/tcg/tcg.h                              |  523 +
 qemu-0.15.x/test-qmp-commands.c                    |  113 +
 qemu-0.15.x/test-visitor.c                         |  306 +
 qemu-0.15.x/tests/Makefile                         |  151 +
 qemu-0.15.x/tests/alpha/Makefile                   |   35 +
 qemu-0.15.x/tests/alpha/crt.s                      |   26 +
 qemu-0.15.x/tests/alpha/hello-alpha.c              |    5 +
 qemu-0.15.x/tests/alpha/test-cond.c                |   87 +
 qemu-0.15.x/tests/alpha/test-ovf.c                 |   29 +
 qemu-0.15.x/tests/cris/Makefile                    |  155 +
 qemu-0.15.x/tests/cris/README                      |    1 +
 qemu-0.15.x/tests/cris/check_abs.c                 |   40 +
 qemu-0.15.x/tests/cris/check_addc.c                |   58 +
 qemu-0.15.x/tests/cris/check_addcm.c               |   85 +
 qemu-0.15.x/tests/cris/check_addi.s                |   57 +
 qemu-0.15.x/tests/cris/check_addiv32.s             |   62 +
 qemu-0.15.x/tests/cris/check_addm.s                |   96 +
 qemu-0.15.x/tests/cris/check_addo.c                |  125 +
 qemu-0.15.x/tests/cris/check_addoq.c               |   44 +
 qemu-0.15.x/tests/cris/check_addq.s                |   47 +
 qemu-0.15.x/tests/cris/check_addr.s                |   96 +
 qemu-0.15.x/tests/cris/check_addxc.s               |   91 +
 qemu-0.15.x/tests/cris/check_addxm.s               |  106 +
 qemu-0.15.x/tests/cris/check_addxr.s               |   96 +
 qemu-0.15.x/tests/cris/check_andc.s                |   80 +
 qemu-0.15.x/tests/cris/check_andm.s                |   90 +
 qemu-0.15.x/tests/cris/check_andq.s                |   46 +
 qemu-0.15.x/tests/cris/check_andr.s                |   95 +
 qemu-0.15.x/tests/cris/check_asr.s                 |  230 +
 qemu-0.15.x/tests/cris/check_ba.s                  |   93 +
 qemu-0.15.x/tests/cris/check_bas.s                 |  102 +
 qemu-0.15.x/tests/cris/check_bcc.s                 |  197 +
 qemu-0.15.x/tests/cris/check_bound.c               |  142 +
 qemu-0.15.x/tests/cris/check_boundc.s              |  101 +
 qemu-0.15.x/tests/cris/check_boundr.s              |  125 +
 qemu-0.15.x/tests/cris/check_btst.s                |   96 +
 qemu-0.15.x/tests/cris/check_clearfv32.s           |   19 +
 qemu-0.15.x/tests/cris/check_clrjmp1.s             |   36 +
 qemu-0.15.x/tests/cris/check_cmp-2.s               |   15 +
 qemu-0.15.x/tests/cris/check_cmpc.s                |   86 +
 qemu-0.15.x/tests/cris/check_cmpm.s                |   96 +
 qemu-0.15.x/tests/cris/check_cmpq.s                |   75 +
 qemu-0.15.x/tests/cris/check_cmpr.s                |  102 +
 qemu-0.15.x/tests/cris/check_cmpxc.s               |   92 +
 qemu-0.15.x/tests/cris/check_cmpxm.s               |  106 +
 qemu-0.15.x/tests/cris/check_dstep.s               |   42 +
 qemu-0.15.x/tests/cris/check_ftag.c                |   37 +
 .../tests/cris/check_gcctorture_pr28634-1.c        |   15 +
 qemu-0.15.x/tests/cris/check_gcctorture_pr28634.c  |   15 +
 qemu-0.15.x/tests/cris/check_glibc_kernelversion.c |  116 +
 qemu-0.15.x/tests/cris/check_hello.c               |    7 +
 qemu-0.15.x/tests/cris/check_int64.c               |   47 +
 qemu-0.15.x/tests/cris/check_jsr.s                 |   85 +
 qemu-0.15.x/tests/cris/check_lapc.s                |   78 +
 qemu-0.15.x/tests/cris/check_lsl.s                 |  217 +
 qemu-0.15.x/tests/cris/check_lsr.s                 |  218 +
 qemu-0.15.x/tests/cris/check_lz.c                  |   49 +
 qemu-0.15.x/tests/cris/check_mapbrk.c              |   39 +
 qemu-0.15.x/tests/cris/check_mcp.s                 |   49 +
 qemu-0.15.x/tests/cris/check_mmap1.c               |   48 +
 qemu-0.15.x/tests/cris/check_mmap2.c               |   48 +
 qemu-0.15.x/tests/cris/check_mmap3.c               |   33 +
 qemu-0.15.x/tests/cris/check_movdelsr1.s           |   33 +
 qemu-0.15.x/tests/cris/check_movecr.s              |   37 +
 qemu-0.15.x/tests/cris/check_movei.s               |   50 +
 qemu-0.15.x/tests/cris/check_movemr.s              |   78 +
 qemu-0.15.x/tests/cris/check_movemrv32.s           |   96 +
 qemu-0.15.x/tests/cris/check_moveq.c               |   51 +
 qemu-0.15.x/tests/cris/check_mover.s               |   28 +
 qemu-0.15.x/tests/cris/check_moverm.s              |   45 +
 qemu-0.15.x/tests/cris/check_movmp.s               |  131 +
 qemu-0.15.x/tests/cris/check_movpmv32.s            |   35 +
 qemu-0.15.x/tests/cris/check_movpr.s               |   28 +
 qemu-0.15.x/tests/cris/check_movprv32.s            |   21 +
 qemu-0.15.x/tests/cris/check_movscr.s              |   29 +
 qemu-0.15.x/tests/cris/check_movsm.s               |   44 +
 qemu-0.15.x/tests/cris/check_movsr.s               |   46 +
 qemu-0.15.x/tests/cris/check_movucr.s              |   33 +
 qemu-0.15.x/tests/cris/check_movum.s               |   40 +
 qemu-0.15.x/tests/cris/check_movur.s               |   45 +
 qemu-0.15.x/tests/cris/check_mulv32.s              |   51 +
 qemu-0.15.x/tests/cris/check_mulx.s                |  246 +
 qemu-0.15.x/tests/cris/check_neg.s                 |  104 +
 qemu-0.15.x/tests/cris/check_not.s                 |   31 +
 qemu-0.15.x/tests/cris/check_openpf1.c             |   38 +
 qemu-0.15.x/tests/cris/check_openpf2.c             |   16 +
 qemu-0.15.x/tests/cris/check_openpf3.c             |   49 +
 qemu-0.15.x/tests/cris/check_openpf4.c             |    5 +
 qemu-0.15.x/tests/cris/check_openpf5.c             |   56 +
 qemu-0.15.x/tests/cris/check_orc.s                 |   71 +
 qemu-0.15.x/tests/cris/check_orm.s                 |   75 +
 qemu-0.15.x/tests/cris/check_orq.s                 |   41 +
 qemu-0.15.x/tests/cris/check_orr.s                 |   84 +
 qemu-0.15.x/tests/cris/check_ret.s                 |   25 +
 qemu-0.15.x/tests/cris/check_scc.s                 |   95 +
 qemu-0.15.x/tests/cris/check_settls1.c             |   45 +
 qemu-0.15.x/tests/cris/check_sigalrm.c             |   26 +
 qemu-0.15.x/tests/cris/check_stat1.c               |   16 +
 qemu-0.15.x/tests/cris/check_stat2.c               |   20 +
 qemu-0.15.x/tests/cris/check_stat3.c               |   25 +
 qemu-0.15.x/tests/cris/check_stat4.c               |   27 +
 qemu-0.15.x/tests/cris/check_subc.s                |   87 +
 qemu-0.15.x/tests/cris/check_subm.s                |   96 +
 qemu-0.15.x/tests/cris/check_subq.s                |   52 +
 qemu-0.15.x/tests/cris/check_subr.s                |  102 +
 qemu-0.15.x/tests/cris/check_swap.c                |   76 +
 qemu-0.15.x/tests/cris/check_time1.c               |   46 +
 qemu-0.15.x/tests/cris/check_time2.c               |   18 +
 qemu-0.15.x/tests/cris/check_xarith.s              |   72 +
 qemu-0.15.x/tests/cris/crisutils.h                 |   71 +
 qemu-0.15.x/tests/cris/crt.s                       |   13 +
 qemu-0.15.x/tests/cris/sys.c                       |   51 +
 qemu-0.15.x/tests/cris/sys.h                       |   16 +
 qemu-0.15.x/tests/cris/testutils.inc               |  117 +
 qemu-0.15.x/tests/hello-arm.c                      |  113 +
 qemu-0.15.x/tests/hello-i386.c                     |   26 +
 qemu-0.15.x/tests/hello-mips.c                     |   64 +
 qemu-0.15.x/tests/linux-test.c                     |  537 +
 qemu-0.15.x/tests/lm32/Makefile                    |  102 +
 qemu-0.15.x/tests/lm32/crt.S                       |   84 +
 qemu-0.15.x/tests/lm32/linker.ld                   |   55 +
 qemu-0.15.x/tests/lm32/macros.inc                  |   79 +
 qemu-0.15.x/tests/lm32/test_add.S                  |   75 +
 qemu-0.15.x/tests/lm32/test_addi.S                 |   56 +
 qemu-0.15.x/tests/lm32/test_and.S                  |   45 +
 qemu-0.15.x/tests/lm32/test_andhi.S                |   35 +
 qemu-0.15.x/tests/lm32/test_andi.S                 |   35 +
 qemu-0.15.x/tests/lm32/test_b.S                    |   13 +
 qemu-0.15.x/tests/lm32/test_be.S                   |   48 +
 qemu-0.15.x/tests/lm32/test_bg.S                   |   78 +
 qemu-0.15.x/tests/lm32/test_bge.S                  |   78 +
 qemu-0.15.x/tests/lm32/test_bgeu.S                 |   78 +
 qemu-0.15.x/tests/lm32/test_bgu.S                  |   78 +
 qemu-0.15.x/tests/lm32/test_bi.S                   |   23 +
 qemu-0.15.x/tests/lm32/test_bne.S                  |   48 +
 qemu-0.15.x/tests/lm32/test_break.S                |   20 +
 qemu-0.15.x/tests/lm32/test_bret.S                 |   38 +
 qemu-0.15.x/tests/lm32/test_call.S                 |   16 +
 qemu-0.15.x/tests/lm32/test_calli.S                |   15 +
 qemu-0.15.x/tests/lm32/test_cmpe.S                 |   40 +
 qemu-0.15.x/tests/lm32/test_cmpei.S                |   35 +
 qemu-0.15.x/tests/lm32/test_cmpg.S                 |   64 +
 qemu-0.15.x/tests/lm32/test_cmpge.S                |   64 +
 qemu-0.15.x/tests/lm32/test_cmpgei.S               |   55 +
 qemu-0.15.x/tests/lm32/test_cmpgeu.S               |   64 +
 qemu-0.15.x/tests/lm32/test_cmpgeui.S              |   55 +
 qemu-0.15.x/tests/lm32/test_cmpgi.S                |   55 +
 qemu-0.15.x/tests/lm32/test_cmpgu.S                |   64 +
 qemu-0.15.x/tests/lm32/test_cmpgui.S               |   55 +
 qemu-0.15.x/tests/lm32/test_cmpne.S                |   40 +
 qemu-0.15.x/tests/lm32/test_cmpnei.S               |   35 +
 qemu-0.15.x/tests/lm32/test_divu.S                 |   29 +
 qemu-0.15.x/tests/lm32/test_eret.S                 |   38 +
 qemu-0.15.x/tests/lm32/test_lb.S                   |   45 +
 qemu-0.15.x/tests/lm32/test_lbu.S                  |   45 +
 qemu-0.15.x/tests/lm32/test_lh.S                   |   45 +
 qemu-0.15.x/tests/lm32/test_lhu.S                  |   45 +
 qemu-0.15.x/tests/lm32/test_lw.S                   |   30 +
 qemu-0.15.x/tests/lm32/test_modu.S                 |   35 +
 qemu-0.15.x/tests/lm32/test_mul.S                  |   70 +
 qemu-0.15.x/tests/lm32/test_muli.S                 |   45 +
 qemu-0.15.x/tests/lm32/test_nor.S                  |   51 +
 qemu-0.15.x/tests/lm32/test_nori.S                 |   35 +
 qemu-0.15.x/tests/lm32/test_or.S                   |   51 +
 qemu-0.15.x/tests/lm32/test_orhi.S                 |   35 +
 qemu-0.15.x/tests/lm32/test_ori.S                  |   35 +
 qemu-0.15.x/tests/lm32/test_ret.S                  |   14 +
 qemu-0.15.x/tests/lm32/test_sb.S                   |   30 +
 qemu-0.15.x/tests/lm32/test_scall.S                |   20 +
 qemu-0.15.x/tests/lm32/test_sextb.S                |   20 +
 qemu-0.15.x/tests/lm32/test_sexth.S                |   20 +
 qemu-0.15.x/tests/lm32/test_sh.S                   |   30 +
 qemu-0.15.x/tests/lm32/test_sl.S                   |   45 +
 qemu-0.15.x/tests/lm32/test_sli.S                  |   30 +
 qemu-0.15.x/tests/lm32/test_sr.S                   |   57 +
 qemu-0.15.x/tests/lm32/test_sri.S                  |   40 +
 qemu-0.15.x/tests/lm32/test_sru.S                  |   57 +
 qemu-0.15.x/tests/lm32/test_srui.S                 |   40 +
 qemu-0.15.x/tests/lm32/test_sub.S                  |   75 +
 qemu-0.15.x/tests/lm32/test_sw.S                   |   35 +
 qemu-0.15.x/tests/lm32/test_xnor.S                 |   51 +
 qemu-0.15.x/tests/lm32/test_xnori.S                |   35 +
 qemu-0.15.x/tests/lm32/test_xor.S                  |   51 +
 qemu-0.15.x/tests/lm32/test_xori.S                 |   35 +
 qemu-0.15.x/tests/pi_10.com                        |  Bin 0 -> 54 bytes
 qemu-0.15.x/tests/qruncom.c                        |  284 +
 qemu-0.15.x/tests/runcom.c                         |  192 +
 qemu-0.15.x/tests/sha1.c                           |  240 +
 qemu-0.15.x/tests/test-arm-iwmmxt.s                |   49 +
 qemu-0.15.x/tests/test-i386-code16.S               |   79 +
 qemu-0.15.x/tests/test-i386-muldiv.h               |   76 +
 qemu-0.15.x/tests/test-i386-shift.h                |  185 +
 qemu-0.15.x/tests/test-i386-ssse3.c                |   57 +
 qemu-0.15.x/tests/test-i386-vm86.S                 |  103 +
 qemu-0.15.x/tests/test-i386.c                      | 2764 +++++
 qemu-0.15.x/tests/test-i386.h                      |  152 +
 qemu-0.15.x/tests/test-mmap.c                      |  476 +
 qemu-0.15.x/tests/test_path.c                      |  160 +
 qemu-0.15.x/tests/testthread.c                     |   51 +
 qemu-0.15.x/thunk.c                                |  288 +
 qemu-0.15.x/thunk.h                                |  161 +
 qemu-0.15.x/trace-events                           |  427 +
 qemu-0.15.x/translate-all.c                        |  163 +
 qemu-0.15.x/uboot_image.h                          |  158 +
 qemu-0.15.x/ui/cocoa.m                             | 1025 ++
 qemu-0.15.x/ui/curses.c                            |  367 +
 qemu-0.15.x/ui/curses_keys.h                       |  509 +
 qemu-0.15.x/ui/d3des.c                             |  424 +
 qemu-0.15.x/ui/d3des.h                             |   51 +
 qemu-0.15.x/ui/keymaps.c                           |  210 +
 qemu-0.15.x/ui/keymaps.h                           |   77 +
 qemu-0.15.x/ui/qemu-spice.h                        |   65 +
 qemu-0.15.x/ui/sdl.c                               |  904 ++
 qemu-0.15.x/ui/sdl_keysym.h                        |  277 +
 qemu-0.15.x/ui/sdl_zoom.c                          |   95 +
 qemu-0.15.x/ui/sdl_zoom.h                          |   25 +
 qemu-0.15.x/ui/sdl_zoom_template.h                 |  225 +
 qemu-0.15.x/ui/spice-core.c                        |  694 ++
 qemu-0.15.x/ui/spice-display.c                     |  434 +
 qemu-0.15.x/ui/spice-display.h                     |   82 +
 qemu-0.15.x/ui/spice-input.c                       |  217 +
 qemu-0.15.x/ui/vnc-auth-sasl.c                     |  632 +
 qemu-0.15.x/ui/vnc-auth-sasl.h                     |   74 +
 qemu-0.15.x/ui/vnc-auth-vencrypt.c                 |  175 +
 qemu-0.15.x/ui/vnc-auth-vencrypt.h                 |   33 +
 qemu-0.15.x/ui/vnc-enc-hextile-template.h          |  211 +
 qemu-0.15.x/ui/vnc-enc-hextile.c                   |  116 +
 qemu-0.15.x/ui/vnc-enc-tight.c                     | 1777 +++
 qemu-0.15.x/ui/vnc-enc-tight.h                     |  183 +
 qemu-0.15.x/ui/vnc-enc-zlib.c                      |  152 +
 qemu-0.15.x/ui/vnc-enc-zrle-template.c             |  263 +
 qemu-0.15.x/ui/vnc-enc-zrle.c                      |  366 +
 qemu-0.15.x/ui/vnc-enc-zrle.h                      |   40 +
 qemu-0.15.x/ui/vnc-enc-zywrle-template.c           |  170 +
 qemu-0.15.x/ui/vnc-enc-zywrle.h                    |  659 +
 qemu-0.15.x/ui/vnc-jobs-async.c                    |  341 +
 qemu-0.15.x/ui/vnc-jobs-sync.c                     |   73 +
 qemu-0.15.x/ui/vnc-jobs.h                          |   87 +
 qemu-0.15.x/ui/vnc-palette.c                       |  158 +
 qemu-0.15.x/ui/vnc-palette.h                       |   68 +
 qemu-0.15.x/ui/vnc-tls.c                           |  445 +
 qemu-0.15.x/ui/vnc-tls.h                           |   76 +
 qemu-0.15.x/ui/vnc.c                               | 2933 +++++
 qemu-0.15.x/ui/vnc.h                               |  556 +
 qemu-0.15.x/ui/vnc_keysym.h                        |  342 +
 qemu-0.15.x/ui/x_keymap.c                          |  168 +
 qemu-0.15.x/ui/x_keymap.h                          |   32 +
 qemu-0.15.x/usb-bsd.c                              |  645 +
 qemu-0.15.x/usb-linux.c                            | 1961 +++
 qemu-0.15.x/usb-redir.c                            | 1218 ++
 qemu-0.15.x/usb-stub.c                             |   52 +
 qemu-0.15.x/user-exec.c                            |  674 ++
 qemu-0.15.x/version.rc                             |   28 +
 qemu-0.15.x/vgafont.h                              | 4611 +++++++
 qemu-0.15.x/vl.c                                   | 3341 +++++
 qemu-0.15.x/x86_64.ld                              |  180 +
 qemu-0.15.x/xen-all.c                              |  955 ++
 qemu-0.15.x/xen-mapcache.c                         |  369 +
 qemu-0.15.x/xen-mapcache.h                         |   51 +
 qemu-0.15.x/xen-stub.c                             |   45 +
 3441 files changed, 1264154 insertions(+), 0 deletions(-)

diff --git a/qemu-0.15.x/.gitignore b/qemu-0.15.x/.gitignore
new file mode 100644
index 0000000..54835bc
--- /dev/null
+++ b/qemu-0.15.x/.gitignore
@@ -0,0 +1,72 @@
+config-devices.*
+config-all-devices.*
+config-host.*
+config-target.*
+trace.h
+trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
+*-timestamp
+*-softmmu
+*-darwin-user
+*-linux-user
+*-bsd-user
+libdis*
+libhw32
+libhw64
+libuser
+qapi-generated
+qemu-doc.html
+qemu-tech.html
+qemu-doc.info
+qemu-tech.info
+qemu.1
+qemu.pod
+qemu-img.1
+qemu-img.pod
+qemu-img
+qemu-nbd
+qemu-nbd.8
+qemu-nbd.pod
+qemu-options.def
+qemu-options.texi
+qemu-img-cmds.texi
+qemu-img-cmds.h
+qemu-io
+qemu-ga
+qemu-monitor.texi
+QMP/qmp-commands.txt
+.gdbinit
+*.a
+*.aux
+*.cp
+*.dvi
+*.exe
+*.fn
+*.ky
+*.log
+*.pdf
+*.cps
+*.fns
+*.kys
+*.pg
+*.pyc
+*.toc
+*.tp
+*.vr
+*.d
+*.o
+*.swp
+*.orig
+.pc
+patches
+pc-bios/bios-pq/status
+pc-bios/vgabios-pq/status
+pc-bios/optionrom/linuxboot.bin
+pc-bios/optionrom/multiboot.bin
+pc-bios/optionrom/multiboot.raw
+.stgit-*
+cscope.*
+tags
+TAGS
+*~
diff --git a/qemu-0.15.x/.gitmodules b/qemu-0.15.x/.gitmodules
new file mode 100644
index 0000000..7884471
--- /dev/null
+++ b/qemu-0.15.x/.gitmodules
@@ -0,0 +1,12 @@
+[submodule "roms/vgabios"]
+	path = roms/vgabios
+	url = git://git.qemu.org/vgabios.git/
+[submodule "roms/seabios"]
+	path = roms/seabios
+	url = git://git.qemu.org/seabios.git/
+[submodule "roms/SLOF"]
+	path = roms/SLOF
+	url = git://git.qemu.org/SLOF.git
+[submodule "roms/ipxe"]
+	path = roms/ipxe
+	url = git://git.qemu.org/ipxe.git
diff --git a/qemu-0.15.x/CODING_STYLE b/qemu-0.15.x/CODING_STYLE
new file mode 100644
index 0000000..5ecfa22
--- /dev/null
+++ b/qemu-0.15.x/CODING_STYLE
@@ -0,0 +1,81 @@
+Qemu Coding Style
+=================
+
+Please use the script checkpatch.pl in the scripts directory to check
+patches before submitting.
+
+1. Whitespace
+
+Of course, the most important aspect in any coding style is whitespace.
+Crusty old coders who have trouble spotting the glasses on their noses
+can tell the difference between a tab and eight spaces from a distance
+of approximately fifteen parsecs.  Many a flamewar have been fought and
+lost on this issue.
+
+QEMU indents are four spaces.  Tabs are never used, except in Makefiles
+where they have been irreversibly coded into the syntax.
+Spaces of course are superior to tabs because:
+
+ - You have just one way to specify whitespace, not two.  Ambiguity breeds
+   mistakes.
+ - The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
+ - Tab indents push your code to the right, making your screen seriously
+   unbalanced.
+ - Tabs will be rendered incorrectly on editors who are misconfigured not
+   to use tab stops of eight positions.
+ - Tabs are rendered badly in patches, causing off-by-one errors in almost
+   every line.
+ - It is the QEMU coding style.
+
+Do not leave whitespace dangling off the ends of lines.
+
+2. Line width
+
+Lines are 80 characters; not longer.
+
+Rationale:
+ - Some people like to tile their 24" screens with a 6x4 matrix of 80x24
+   xterms and use vi in all of them.  The best way to punish them is to
+   let them keep doing it.
+ - Code and especially patches is much more readable if limited to a sane
+   line length.  Eighty is traditional.
+ - It is the QEMU coding style.
+
+3. Naming
+
+Variables are lower_case_with_underscores; easy to type and read.  Structured
+type names are in CamelCase; harder to type but standing out.  Scalar type
+names are lower_case_with_underscores_ending_with_a_t, like the POSIX
+uint64_t and family.  Note that this last convention contradicts POSIX
+and is therefore likely to be changed.
+
+When wrapping standard library functions, use the prefix qemu_ to alert
+readers that they are seeing a wrapped version; otherwise avoid this prefix.
+
+4. Block structure
+
+Every indented statement is braced; even if the block contains just one
+statement.  The opening brace is on the line that contains the control
+flow statement that introduces the new block; the closing brace is on the
+same line as the else keyword, or on a line by itself if there is no else
+keyword.  Example:
+
+    if (a == 5) {
+        printf("a was 5.\n");
+    } else if (a == 6) {
+        printf("a was 6.\n");
+    } else {
+        printf("a was something else entirely.\n");
+    }
+
+An exception is the opening brace for a function; for reasons of tradition
+and clarity it comes on a line by itself:
+
+    void a_function(void)
+    {
+        do_something();
+    }
+
+Rationale: a consistent (except for functions...) bracing style reduces
+ambiguity and avoids needless churn when lines are added or removed.
+Furthermore, it is the QEMU coding style.
diff --git a/qemu-0.15.x/COPYING b/qemu-0.15.x/COPYING
new file mode 100644
index 0000000..00ccfbb
--- /dev/null
+++ b/qemu-0.15.x/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/qemu-0.15.x/COPYING.LIB b/qemu-0.15.x/COPYING.LIB
new file mode 100644
index 0000000..48afc2e
--- /dev/null
+++ b/qemu-0.15.x/COPYING.LIB
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/qemu-0.15.x/Changelog b/qemu-0.15.x/Changelog
new file mode 100644
index 0000000..28a69af
--- /dev/null
+++ b/qemu-0.15.x/Changelog
@@ -0,0 +1,580 @@
+This file documents changes for QEMU releases 0.12 and earlier.
+For changelog information for later releases, see
+http://wiki.qemu.org/ChangeLog or look at the git history for
+more detailed information.
+
+
+version 0.12.0:
+
+  - Update to SeaBIOS 0.5.0
+  - e1000: fix device link status in Linux (Anthony Liguori)
+  - monitor: fix QMP for balloon command (Luiz Capitulino)
+  - QMP: Return an empty dict by default (Luiz Capitulino)
+  - QMP: Only handle converted commands (Luiz Capitulino)
+  - pci: support PCI based option rom loading (Gerd Hoffman/Anthony Liguori)
+  - Fix backcompat for hotplug of SCSI controllers (Daniel P. Berrange)
+  - fdc: fix migration from 0.11 (Juan Quintela)
+  - vmware-vga: fix segv on cursor resize. (Dave Airlie)
+  - vmware-vga: various fixes (Dave Airlie/Anthony Liguori)
+  - qdev: improve property error reporting. (Gerd Hoffmann)
+  - fix vga names in default_list (Gerd Hoffmann)
+  - usb-host: check mon before using it. (Gerd Hoffmann)
+  - usb-net: use qdev for -usbdevice (Gerd Hoffmann)
+  - monitor: Catch printing to non-existent monitor (Luiz Capitulino)
+  - Avoid permanently disabled QEMU monitor when UNIX migration fails (Daniel P. Berrange)
+  - Fix loading of ELF multiboot kernels (Kevin Wolf)
+  - qemu-io: Fix memory leak (Kevin Wolf)
+  - Fix thinko in linuxboot.S (Paolo Bonzini)
+  - target-i386: Fix evaluation of DR7 register (Jan Kiszka)
+  - vnc: hextile: do not generate ForegroundSpecified and SubrectsColoured tiles (Anthony Liguori)
+  - S390: Bail out without KVM (Alexander Graf)
+  - S390: Don't tell guest we're updating config space (Alexander Graf)
+  - target-s390: Fail on unknown instructions (Alexander Graf)
+  - osdep: Fix runtime failure on older Linux kernels (Andre Przywara)
+  - Fix a make -j race (Juergen Lock)
+  - target-alpha: Fix generic ctz64. (Richard Henderson)
+  - s390: Fix buggy assignment (Stefan Weil)
+  - target-mips: fix user-mode emulation startup (Nathan Froyd)
+  - target-i386: Update CPUID feature set for TCG (Andre Przywara)
+  - s390: fix build on 32 bit host (Michael S. Tsirkin)
+	
+version 0.12.0-rc2:
+
+  - v2: properly save kvm system time msr registers (Glauber Costa)
+  - convert more monitor commands to qmp (Luiz Capitulino)
+  - vnc: fix capslock tracking logic. (Gerd Hoffmann)
+  - QemuOpts: allow larger option values. (Gerd Hoffmann)
+  - scsi: fix drive hotplug. (Gerd Hoffmann)
+  - pci: don't hw_error() when no slot is available. (Gerd Hoffmann)
+  - pci: don't abort() when trying to hotplug with acpi off. (Gerd Hoffmann)
+  - allow default devices to be implemented in config file (Gerd Hoffman)
+  - vc: colorize chardev title line with blue background. (Gerd Hoffmann)
+  - chardev: make chardevs specified in config file work. (Gerd Hoffmann)
+  - qdev: also match bus name for global properties (Gerd Hoffmann)
+  - qdev: add command line option to set global defaults for properties. (Gerd Hoffmann)
+  - kvm: x86: Save/restore exception_index (Jan Kiszka)
+  - qdev: Replace device names containing whitespace (Markus Armbruster)
+  - fix rtc-td-hack on host without high-res timers (Gleb Natapov)
+  - virtio: verify features on load (Michael S. Tsirkin)
+  - vmware_vga: add rom file so that it boots. (Dave Airlie)
+  - Do not abort on qemu_malloc(0) in production builds (Anthony Liguori)
+  - Fix ARM userspace strex implementation. (Paul Brook)
+  - qemu: delete rule target on error (Michael S. Tsirkin)
+  - QMP: add human-readable description to error response (Markus Armbruster)
+  - convert more monitor commands to QError (Markus Armbruster)
+  - monitor: Fix double-prompt after "change vnc passwd BLA" (Markus Armbruster)
+  - monitor: do_cont(): Don't ask for passwords (Luiz Capitulino)
+  - monitor: Introduce 'block_passwd' command (Luiz Capitulino)
+  - pci: interrupt disable bit support (Michael S. Tsirkin)
+  - pci: interrupt status bit implementation (Michael S. Tsirkin)
+  - pci: prepare irq code for interrupt state (Michael S. Tsirkin)
+  - msix: function mask support (Michael S. Tsirkin)
+  - msix: macro rename for function mask support (Michael S. Tsirkin)
+  - cpuid: Fix multicore setup on Intel (Andre Przywara)
+  - kvm: x86: Fix initial kvm_has_msr_star (Jan Kiszka)
+  - Update OpenBIOS images to r640 (Aurelien Jarno)	
+
+version 0.10.2:
+
+  - fix savevm/loadvm (Anthony Liguori)
+  - live migration: fix dirty tracking windows (Glauber Costa)
+  - live migration: improve error propogation (Glauber Costa)
+  - qcow2: fix image creation for > ~2TB images (Chris Wright)
+  - hotplug: fix error handling for if= parameter (Eduardo Habkost)
+  - qcow2: fix data corruption (Nolan Leake)
+  - virtio: fix guest oops with 2.6.25 kernels (Rusty Russell)
+  - SH4: add support for -kernel (Takashi Yoshii, Aurelien Jarno)
+  - hotplug: fix closing of char devices (Jan Kiszka)
+  - hotplug: remove incorrect check for device name (Eduardo Habkost)
+  - enable -k on win32 (Herve Poussineau)
+  - configure: use LANG=C for grep (Andreas Faerber)
+  - fix VGA regression (malc)
+	
+version 0.10.1:
+
+  - virtio-net: check right return size on sg list (Alex Williamson)
+  - Make qemu_announce_self handle holes (live migration after hotplug)
+    (Marcelo Tosatti)
+  - Revert r6804-r6808 (qcow2 allocation info).  This series of changes added
+    a high cost to startup for large qcow2 images (Anthony Liguori)
+  - qemu-img: fix help message (Aurelien Jarno)
+  - Fix build for non-default installs of SDL (Anthony Liguori)
+  - Fix race condition in env->interrupt_request.  When using TCG and a dynticks
+    host timer, this condition could cause TCG to get stuck in an infinite
+    loop (Aurelien Jarno)
+  - Fix reading encrypted hard disk passwords during early startup (Jan Kiszka)
+  - Fix encrypted disk reporting in 'info block' (Jan Kiszka)
+  - Fix console size with tiny displays (MusicPal) (Jan Kiszka)
+  - Improve error handling in bdrv_open2 (Jan Kiszka)
+  - Avoid leaking data in mux'ed character devices (Jan Kiszka)
+  - Fix initial character device reset (no banner in monitor) (Jan Kiszka)
+  - Fix cpuid KVM crash on i386 host (Lubomir Rintel)
+  - Fix SLES10sp2 installation by adding ISTAT1 register to LSI SCSI emulation
+    (Ryan Harper)
+
+version 0.10.0:
+
+  - TCG support (No longer requires GCC 3.x)
+  - Kernel Virtual Machine acceleration support
+  - BSD userspace emulation
+  - Bluetooth emulation and host passthrough support
+  - GDB XML register description support
+  - Intel e1000 emulation
+  - HPET emulation
+  - VirtIO paravirtual device support
+  - Marvell 88w8618 / MusicPal emulation
+  - Nokia N-series tablet emulation / OMAP2 processor emulation
+  - PCI hotplug support
+  - Live migration and new save/restore formats
+  - Curses display support
+  - qemu-nbd utility to mount supported block formats
+  - Altivec support in PPC emulation and new firmware (OpenBIOS)
+  - Multiple VNC clients are now supported
+  - TLS encryption is now supported in VNC
+  - MIPS Magnum R4000 machine (Hervé Poussineau)
+  - Braille support (Samuel Thibault)
+  - Freecom MusicPal system emulation (Jan Kiszka)
+  - OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski)
+  - EsounD audio driver (Frederick Reeve)
+  - Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz)
+  - Many, many, bug fixes and new features
+
+version 0.9.1:
+
+  - TFTP booting from host directory (Anthony Liguori, Erwan Velu)
+  - Tap device emulation for Solaris (Sittichai Palanisong)
+  - Monitor multiplexing to several I/O channels (Jason Wessel)
+  - ds1225y nvram support (Herve Poussineau)
+  - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
+  - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
+  - MIPS 64-bit FPU support (Thiemo Seufer)
+  - Xscale PDA emulation (Andrzej Zaborowski)
+  - ColdFire system emulation (Paul Brook)
+  - Improved SH4 support (Magnus Damm)
+  - MIPS64 support (Aurelien Jarno, Thiemo Seufer)
+  - Preliminary Alpha guest support (J. Mayer)
+  - Read-only support for Parallels disk images (Alex Beregszaszi)
+  - SVM (x86 virtualization) support (Alexander Graf)
+  - CRIS emulation (Edgar E. Iglesias)
+  - SPARC32PLUS execution support (Blue Swirl)
+  - MIPS mipssim pseudo machine (Thiemo Seufer)
+  - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
+  - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
+  - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
+  - Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
+  - Intel mainstone II board emulation (Armin Kuster)
+  - VMware SVGA II graphics card support (Andrzej Zaborowski)
+
+version 0.9.0:
+
+  - Support for relative paths in backing files for disk images
+  - Async file I/O API
+  - New qcow2 disk image format
+  - Support of multiple VM snapshots
+  - Linux: specific host CDROM and floppy support
+  - SMM support
+  - Moved PCI init, MP table init and ACPI table init to Bochs BIOS
+  - Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
+  - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
+  - Darwin userspace emulation (Pierre d'Herbemont)
+  - m68k user support (Paul Brook)
+  - several x86 and x86_64 emulation fixes
+  - Mouse relative offset VNC extension (Anthony Liguori)
+  - PXE boot support (Anthony Liguori)
+  - '-daemonize' option (Anthony Liguori)
+
+version 0.8.2:
+
+  - ACPI support
+  - PC VGA BIOS fixes
+  - switch to OpenBios for SPARC targets (Blue Swirl)
+  - VNC server fixes
+  - MIPS FPU support (Marius Groeger)
+  - Solaris/SPARC host support (Juergen Keil)
+  - PPC breakpoints and single stepping (Jason Wessel)
+  - USB updates (Paul Brook)
+  - UDP/TCP/telnet character devices (Jason Wessel)
+  - Windows sparse file support (Frediano Ziglio)
+  - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
+  - PCNET NIC support (Antony T Curtis)
+  - Support for variable frequency host CPUs
+  - Workaround for win32 SMP hosts
+  - Support for AMD Flash memories (Jocelyn Mayer)
+  - Audio capture to WAV files support (malc)
+
+version 0.8.1:
+
+  - USB tablet support (Brad Campbell, Anthony Liguori)
+  - win32 host serial support (Kazu)
+  - PC speaker support (Joachim Henke)
+  - IDE LBA48 support (Jens Axboe)
+  - SSE3 support
+  - Solaris port (Juergen Keil)
+  - Preliminary SH4 target (Samuel Tardieu)
+  - VNC server (Anthony Liguori)
+  - slirp fixes (Ed Swierk et al.)
+  - USB fixes
+  - ARM Versatile Platform Baseboard emulation (Paul Brook)
+
+version 0.8.0:
+
+  - ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
+    cpu (Paul Brook)
+  - SMP support
+  - Mac OS X cocoa improvements (Mike Kronenberg)
+  - Mac OS X CoreAudio driver (Mike Kronenberg)
+  - DirectSound driver (malc)
+  - ALSA audio driver (malc)
+  - new audio options: '-soundhw' and '-audio-help' (malc)
+  - ES1370 PCI audio device (malc)
+  - Initial USB support
+  - Linux host serial port access
+  - Linux host low level parallel port access
+  - New network emulation code supporting VLANs.
+  - MIPS and MIPSel User Linux emulation
+  - MIPS fixes to boot Linux (Daniel Jacobowitz)
+  - NX bit support
+  - Initial SPARC SMP support (Blue Swirl)
+  - Major overhaul of the virtual FAT driver for read/write support
+    (Johannes Schindelin)
+
+version 0.7.2:
+
+  - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
+  - merge self modifying code handling in dirty ram page mecanism.
+  - MIPS fixes (Ralf Baechle)
+  - better user net performances
+
+version 0.7.1:
+
+  - read-only Virtual FAT support (Johannes Schindelin)
+  - Windows 2000 install disk full hack (original idea from Vladimir
+    N. Oleynik)
+  - VMDK disk image creation (Filip Navara)
+  - SPARC64 progress (Blue Swirl)
+  - initial MIPS support (Jocelyn mayer)
+  - MIPS improvements (Ralf Baechle)
+  - 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
+  - IOAPIC support (Filip Navara)
+
+version 0.7.0:
+
+  - better BIOS translation and HDD geometry auto-detection
+  - user mode networking bug fix
+  - undocumented FPU ops support
+  - Cirrus VGA: support for 1280x1024x[8,15,16] modes
+  - 'pidfile' option
+  - .dmg disk image format support (Johannes Schindelin)
+  - keymaps support (initial patch by Johannes Schindelin)
+  - big endian ARM support (Lennert Buytenhek)
+  - added generic 64 bit target support
+  - x86_64 target support
+  - initial APIC support
+  - MMX/SSE/SSE2/PNI support
+  - PC parallel port support (Mark Jonckheere)
+  - initial SPARC64 support (Blue Swirl)
+  - SPARC target boots Linux (Blue Swirl)
+  - armv5te user mode support (Paul Brook)
+  - ARM VFP support (Paul Brook)
+  - ARM "Angel" semihosting syscalls (Paul Brook)
+  - user mode gdb stub support (Paul Brook)
+  - Samba 3 support
+  - initial Cocoa support (Pierre d'Herbemont)
+  - generic FPU emulation code
+  - Virtual PC read-only disk image support (Alex Beregszaszi)
+
+version 0.6.1:
+
+  - Mac OS X port (Pierre d'Herbemont)
+  - Virtual console support
+  - Better monitor line edition
+  - New block device layer
+  - New 'qcow' growable disk image support with AES encryption and
+    transparent decompression
+  - VMware 3 and 4 read-only disk image support (untested)
+  - Support for up to 4 serial ports
+  - TFTP server support (Magnus Damm)
+  - Port redirection support in user mode networking
+  - Support for not executable data sections
+  - Compressed loop disk image support (Johannes Schindelin)
+  - Level triggered IRQ fix (aka NE2000 PCI performance fix) (Steve
+    Wormley)
+  - Fixed Fedora Core 2 problems (now you can run qemu without any
+    LD_ASSUME_KERNEL tricks on FC2)
+  - DHCP fix for Windows (accept DHCPREQUEST alone)
+  - SPARC system emulation (Blue Swirl)
+  - Automatic Samba configuration for host file access from Windows.
+  - '-loadvm' and '-full-screen' options
+  - ne2000 savevm support (Johannes Schindelin)
+  - Ctrl-Alt is now the default grab key. Ctrl-Alt-[0-9] switches to
+    the virtual consoles.
+  - BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert)
+  - Floppy fixes for NT4 and NT5 (Mike Nordell)
+  - NT4 IDE fixes (Ben Pfaf, Mike Nordell)
+  - SDL Audio support and SB16 fixes (malc)
+  - ENTER instruction bug fix (initial patch by Stefan Kisdaroczi)
+  - VGA font change fix
+  - VGA read-only CRTC register fix
+
+version 0.6.0:
+
+  - minimalist FPU exception support (NetBSD FPU probe fix)
+  - cr0.ET fix (Win95 boot)
+  - *BSD port (Markus Niemisto)
+  - I/O access fix (signaled by Mark Jonckheere)
+  - IDE drives serial number fix (Mike Nordell)
+  - int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
+  - int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
+  - BSR/BSF "undefined behaviour" fix
+  - vmdk2raw: convert VMware disk images to raw images
+  - PCI support
+  - NE2K PCI support
+  - dummy VGA PCI support
+  - VGA font selection fix (Daniel Serpell)
+  - PIC reset fix (Hidemi KAWAI)
+  - PIC spurious irq support (aka Solaris install bug)
+  - added '-localtime' option
+  - Cirrus CL-GD54xx VGA support (initial patch by Makoto Suzuki (suzu))
+  - APM and system shutdown support
+  - Fixed system reset
+  - Support for other PC BIOSes
+  - Initial PowerMac hardware emulation
+  - PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer)
+  - initial IDE BMDMA support (needed for Darwin x86)
+  - Set the default memory size for PC emulation to 128 MB
+
+version 0.5.5:
+
+  - SDL full screen support (initial patch by malc)
+  - VGA support on PowerPC PREP
+  - VBE fixes (Matthew Mastracci)
+  - PIT fixes (aka Win98 hardware probe and "VGA slowness" bug)
+  - IDE master only fixes (aka Win98 CD-ROM probe bug)
+  - ARM load/store half word fix (Ulrich Hecht)
+  - FDC fixes for Win98
+
+version 0.5.4:
+
+  - qemu-fast fixes
+  - BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
+  - keyboard/mouse fix (Mike Nordell)
+  - IDE fixes (Linux did not recognized slave drivers)
+  - VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
+  - QEMU can now boot a PowerPC Linux kernel (Jocelyn Mayer)
+  - User mode network stack
+  - imul imm8 fix + 0x82 opcode support (Hidemi KAWAI)
+  - precise self modifying code (aka BeOS install bug)
+
+version 0.5.3:
+
+  - added Bochs VESA VBE support
+  - VGA memory map mode 3 access fix (OS/2 install fix)
+  - IDE fixes (Jens Axboe)
+  - CPU interrupt fixes
+  - fixed various TLB invalidation cases (NT install)
+  - fixed cr0.WP semantics (XP install)
+  - direct chaining support for SPARC and PowerPC (faster)
+  - ARM NWFPE support (initial patch by Ulrich Hecht)
+  - added specific x86 to x86 translator (close to native performance
+    in qemu-i386 and qemu-fast)
+  - shm syscalls support (Paul McKerras)
+  - added accurate CR0.MP/ME/TS emulation
+  - fixed DMA memory write access (Win95 boot floppy fix)
+  - graphical x86 linux loader
+  - command line monitor
+  - generic removable device support
+  - support of CD-ROM change
+  - multiple network interface support
+  - initial x86-64 host support (Gwenole Beauchesne)
+  - lret to outer priviledge fix (OS/2 install fix)
+  - task switch fixes (SkyOS boot)
+  - VM save/restore commands
+  - new timer API
+  - more precise RTC emulation (periodic timers + time updates)
+  - Win32 port (initial patch by Kazu)
+
+version 0.5.2:
+
+  - improved soft MMU speed (assembly functions and specializing)
+  - improved multitasking speed by avoiding flushing TBs when
+    switching tasks
+  - improved qemu-fast speed
+  - improved self modifying code handling (big performance gain in
+    softmmu mode).
+  - fixed IO checking
+  - fixed CD-ROM detection (win98 install CD)
+  - fixed addseg real mode bug (GRUB boot fix)
+  - added ROM memory support (win98 boot)
+  - fixed 'call Ev' in case of paging exception
+  - updated the script 'qemu-binfmt-conf.sh' to use QEMU automagically
+    when launching executables for the supported target CPUs.
+  - PowerPC system emulation update (Jocelyn Mayer)
+  - PC floppy emulation and DMA fixes (Jocelyn Mayer)
+  - polled mode for PIC (Jocelyn Mayer)
+  - fixed PTE dirty bit handling
+  - fixed xadd same reg bug
+  - fixed cmpxchg exception safeness
+  - access to virtual memory in gdb stub
+  - task gate and NT flag fixes
+  - eflags optimisation fix for string operations
+
+version 0.5.1:
+
+  - float access fixes when using soft mmu
+  - PC emulation support on PowerPC
+  - A20 support
+  - IDE CD-ROM emulation
+  - ARM fixes (Ulrich Hecht)
+  - SB16 emulation (malc)
+  - IRET and INT fixes in VM86 mode with IOPL=3
+  - Port I/Os use TSS io map
+  - Full task switching/task gate support
+  - added verr, verw, arpl, fcmovxx
+  - PowerPC target support (Jocelyn Mayer)
+  - Major SPARC target fixes (dynamically linked programs begin to work)
+
+version 0.5.0:
+
+  - full hardware level VGA emulation
+  - graphical display with SDL
+  - added PS/2 mouse and keyboard emulation
+  - popw (%esp) fix
+  - mov to/from segment data width fix
+  - added real mode support
+  - added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
+  - m68k host port (Richard Zidlicky)
+  - partial soft MMU support for memory mapped I/Os
+  - multi-target build
+  - fixed: no error code in hardware interrupts
+  - fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
+  - correct single stepping thru string operations
+  - preliminary SPARC target support (Thomas M. Ogrisegg)
+  - tun-fd option (Rusty Russell)
+  - automatic IDE geometry detection
+  - renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
+  - added man page
+  - added full soft mmu mode to launch unpatched OSes.
+
+version 0.4.3:
+
+  - x86 exception fix in case of nop instruction.
+  - gcc 3.2.2 bug workaround (RedHat 9 fix)
+  - sparc and Alpha host fixes
+  - many ARM target fixes: 'ls' and 'bash' can be launched.
+
+version 0.4.2:
+
+ - many exception handling fixes (can compile a Linux kernel inside vl)
+ - IDE emulation support
+ - initial GDB stub support
+ - deferred update support for disk images (Rusty Russell)
+ - accept User Mode Linux Copy On Write disk images
+ - SMP kernels can at least be booted
+
+version 0.4.1:
+
+ - more accurate timer support in vl.
+ - more reliable NE2000 probe in vl.
+ - added 2.5.66 kernel in vl-test.
+ - added VLTMPDIR environment variable in vl.
+
+version 0.4:
+
+ - initial support for ring 0 x86 processor emulation
+ - fixed signal handling for correct dosemu DPMI emulation
+ - fast x86 MMU emulation with mmap()
+ - fixed popl (%esp) case
+ - Linux kernel can be executed by QEMU with the 'vl' command.
+
+version 0.3:
+
+ - initial support for ARM emulation
+ - added fnsave, frstor, fnstenv, fldenv FPU instructions
+ - added FPU register save in signal emulation
+ - initial ARM port
+ - Sparc and Alpha ports work on the regression test
+ - generic ioctl number conversion
+ - fixed ioctl type conversion
+
+version 0.2:
+
+ - PowerPC disassembly and ELF symbols output (Rusty Russell)
+ - flock support (Rusty Russell)
+ - ugetrlimit support (Rusty Russell)
+ - fstat64 fix (Rusty Russell)
+ - initial Alpha port (Falk Hueffner)
+ - initial IA64 port (Matt Wilson)
+ - initial Sparc and Sparc64 port (David S. Miller)
+ - added HLT instruction
+ - LRET instruction fix.
+ - added GPF generation for I/Os.
+ - added INT3 and TF flag support.
+ - SHL instruction C flag fix.
+ - mmap emulation for host page size > 4KB
+ - self-modifying code support
+ - better VM86 support (dosemu works on non trivial programs)
+ - precise exception support (EIP is computed correctly in most cases)
+ - more precise LDT/GDT/IDT emulation
+ - faster segment load in vm86 mode
+ - direct chaining of basic blocks (faster emulation)
+
+version 0.1.6:
+
+ - automatic library search system. QEMU can now work with unpatched
+   ELF dynamic loader and libc (Rusty Russell).
+ - ISO C warning fixes (Alistair Strachan)
+ - first self-virtualizable version (works only as long as the
+   translation cache is not flushed)
+ - RH9 fixes
+
+version 0.1.5:
+
+ - ppc64 support + personality() patch (Rusty Russell)
+ - first Alpha CPU patches (Falk Hueffner)
+ - removed bfd.h dependency
+ - fixed shrd, shld, idivl and divl on PowerPC.
+ - fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
+
+version 0.1.4:
+
+ - more accurate VM86 emulation (can launch small DOS 16 bit
+   executables in wine).
+ - fixed push/pop fs/gs
+ - added iret instruction.
+ - added times() syscall and SIOCATMARK ioctl.
+
+version 0.1.3:
+
+ - S390 support (Ulrich Weigand)
+ - glibc 2.3.x compile fix (Ulrich Weigand)
+ - socketcall endian fix (Ulrich Weigand)
+ - struct sockaddr endian fix (Ulrich Weigand)
+ - sendmsg/recvmsg endian fix (Ulrich Weigand)
+ - execve endian fix (Ulrich Weigand)
+ - fdset endian fix (Ulrich Weigand)
+ - partial setsockopt syscall support (Ulrich Weigand)
+ - more accurate pushf/popf emulation
+ - first partial vm86() syscall support (can be used with runcom example).
+ - added bound, cmpxchg8b, cpuid instructions
+ - added 16 bit addressing support/override for string operations
+ - poll() fix
+
+version 0.1.2:
+
+ - compile fixes
+ - xlat instruction
+ - xchg instruction memory lock
+ - added simple vm86 example (not working with QEMU yet). The 54 byte
+   DOS executable 'pi_10.com' program was released by Bertram
+   Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
+
+version 0.1.1:
+
+ - glibc 2.2 compilation fixes
+ - added -s and -L options
+ - binary distribution of x86 glibc and wine
+ - big endian fixes in ELF loader and getdents.
+
+version 0.1:
+
+ - initial public release.
diff --git a/qemu-0.15.x/HACKING b/qemu-0.15.x/HACKING
new file mode 100644
index 0000000..3af53fd
--- /dev/null
+++ b/qemu-0.15.x/HACKING
@@ -0,0 +1,122 @@
+1. Preprocessor
+
+For variadic macros, stick with this C99-like syntax:
+
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
+
+2. C types
+
+It should be common sense to use the right type, but we have collected
+a few useful guidelines here.
+
+2.1. Scalars
+
+If you're using "int" or "long", odds are good that there's a better type.
+If a variable is counting something, it should be declared with an
+unsigned type.
+
+If it's host memory-size related, size_t should be a good choice (use
+ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
+but only for RAM, it may not cover whole guest address space.
+
+If it's file-size related, use off_t.
+If it's file-offset related (i.e., signed), use off_t.
+If it's just counting small numbers use "unsigned int";
+(on all but oddball embedded systems, you can assume that that
+type is at least four bytes wide).
+
+In the event that you require a specific width, use a standard type
+like int32_t, uint32_t, uint64_t, etc.  The specific types are
+mandatory for VMState fields.
+
+Don't use Linux kernel internal types like u32, __u32 or __le32.
+
+Use target_phys_addr_t for guest physical addresses except pcibus_t
+for PCI addresses.  In addition, ram_addr_t is a QEMU internal address
+space that maps guest RAM physical addresses into an intermediate
+address space that can map to host virtual address spaces.  Generally
+speaking, the size of guest memory can always fit into ram_addr_t but
+it would not be correct to store an actual guest physical address in a
+ram_addr_t.
+
+Use target_ulong (or abi_ulong) for CPU virtual addresses, however
+devices should not need to use target_ulong.
+
+Of course, take all of the above with a grain of salt.  If you're about
+to use some system interface that requires a type like size_t, pid_t or
+off_t, use matching types for any corresponding variables.
+
+Also, if you try to use e.g., "unsigned int" as a type, and that
+conflicts with the signedness of a related variable, sometimes
+it's best just to use the *wrong* type, if "pulling the thread"
+and fixing all related variables would be too invasive.
+
+Finally, while using descriptive types is important, be careful not to
+go overboard.  If whatever you're doing causes warnings, or requires
+casts, then reconsider or ask for help.
+
+2.2. Pointers
+
+Ensure that all of your pointers are "const-correct".
+Unless a pointer is used to modify the pointed-to storage,
+give it the "const" attribute.  That way, the reader knows
+up-front that this is a read-only pointer.  Perhaps more
+importantly, if we're diligent about this, when you see a non-const
+pointer, you're guaranteed that it is used to modify the storage
+it points to, or it is aliased to another pointer that is.
+
+2.3. Typedefs
+Typedefs are used to eliminate the redundant 'struct' keyword.
+
+2.4. Reserved namespaces in C and POSIX
+Underscore capital, double underscore, and underscore 't' suffixes should be
+avoided.
+
+3. Low level memory management
+
+Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
+APIs is not allowed in the QEMU codebase. Instead of these routines,
+use the replacement qemu_malloc/qemu_mallocz/qemu_realloc/qemu_free or
+qemu_vmalloc/qemu_memalign/qemu_vfree APIs.
+
+Please note that NULL check for the qemu_malloc result is redundant and
+that qemu_malloc() call with zero size is not allowed.
+
+Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
+qemu_vfree, since breaking this will cause problems on Win32 and user
+emulators.
+
+4. String manipulation
+
+Do not use the strncpy function.  According to the man page, it does
+*not* guarantee a NULL-terminated buffer, which makes it extremely dangerous
+to use.  Instead, use functionally equivalent function:
+void pstrcpy(char *buf, int buf_size, const char *str)
+
+Don't use strcat because it can't check for buffer overflows, but:
+char *pstrcat(char *buf, int buf_size, const char *s)
+
+The same limitation exists with sprintf and vsprintf, so use snprintf and
+vsnprintf.
+
+QEMU provides other useful string functions:
+int strstart(const char *str, const char *val, const char **ptr)
+int stristart(const char *str, const char *val, const char **ptr)
+int qemu_strnlen(const char *s, int max_len)
+
+There are also replacement character processing macros for isxyz and toxyz,
+so instead of e.g. isalnum you should use qemu_isalnum.
+
+Because of the memory management rules, you must use qemu_strdup/qemu_strndup
+instead of plain strdup/strndup.
+
+5. Printf-style functions
+
+Whenever you add a new printf-style function, i.e., one with a format
+string argument and following "..." in its prototype, be sure to use
+gcc's printf attribute directive in the prototype.
+
+This makes it so gcc's -Wformat and -Wformat-security options can do
+their jobs and cross-check format strings with the number and types
+of arguments.
diff --git a/qemu-0.15.x/LICENSE b/qemu-0.15.x/LICENSE
new file mode 100644
index 0000000..cbd92c0
--- /dev/null
+++ b/qemu-0.15.x/LICENSE
@@ -0,0 +1,18 @@
+The following points clarify the QEMU license:
+
+1) QEMU as a whole is released under the GNU General Public License
+
+2) Parts of QEMU have specific licenses which are compatible with the
+GNU General Public License. Hence each source file contains its own
+licensing information.
+
+In particular, the QEMU virtual CPU core library (libqemu.a) is
+released under the GNU Lesser General Public License. Many hardware
+device emulation sources are released under the BSD license.
+
+3) The Tiny Code Generator (TCG) is released under the BSD license
+   (see license headers in files).
+
+4) QEMU is a trademark of Fabrice Bellard.
+
+Fabrice Bellard.
diff --git a/qemu-0.15.x/MAINTAINERS b/qemu-0.15.x/MAINTAINERS
new file mode 100644
index 0000000..6115e4e
--- /dev/null
+++ b/qemu-0.15.x/MAINTAINERS
@@ -0,0 +1,506 @@
+QEMU Maintainers
+================
+
+The intention of this file is not to establish who owns what portions of the
+code base, but to provide a set of names that developers can consult when they
+have a question about a particular subset and also to provide a set of names
+to be CC'd when submitting a patch to obtain appropriate review.
+
+In general, if you have a question about inclusion of a patch, you should
+consult qemu-devel and not any specific individual privately.
+
+Descriptions of section entries:
+
+	M: Mail patches to: FullName <address at domain>
+	L: Mailing list that is relevant to this area
+	W: Web-page with status/info
+	Q: Patchwork web based patch tracking system site
+	T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
+	S: Status, one of the following:
+	   Supported:	Someone is actually paid to look after this.
+	   Maintained:	Someone actually looks after it.
+	   Odd Fixes:	It has a maintainer but they don't have time to do
+			much other than throw the odd patch in. See below..
+	   Orphan:	No current maintainer [but maybe you could take the
+			role as you write your new code].
+	   Obsolete:	Old code. Something tagged obsolete generally means
+			it has been replaced by a better system and you
+			should be using that.
+	F: Files and directories with wildcard patterns.
+	   A trailing slash includes all files and subdirectory files.
+	   F:	drivers/net/	all files in and below drivers/net
+	   F:	drivers/net/*	all files in drivers/net, but not below
+	   F:	*/net/*		all files in "any top level directory"/net
+	   One pattern per line.  Multiple F: lines acceptable.
+	X: Files and directories that are NOT maintained, same rules as F:
+	   Files exclusions are tested before file matches.
+	   Can be useful for excluding a specific subdirectory, for instance:
+	   F:	net/
+	   X:	net/ipv6/
+	   matches all files in and below net excluding net/ipv6/
+	K: Keyword perl extended regex pattern to match content in a
+	   patch or file.  For instance:
+	   K: of_get_profile
+	      matches patches or files that contain "of_get_profile"
+	   K: \b(printk|pr_(info|err))\b
+	      matches patches or files that contain one or more of the words
+	      printk, pr_info or pr_err
+	   One regex pattern per line.  Multiple K: lines acceptable.
+
+
+General Project Administration
+------------------------------
+M: Anthony Liguori <aliguori at us.ibm.com>
+M: Paul Brook <paul at codesourcery.com>
+
+Guest CPU cores (TCG):
+----------------------
+Alpha
+M: Richard Henderson <rth at twiddle.net>
+S: Maintained
+F: target-alpha/
+
+ARM
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: target-arm/
+
+CRIS
+M: Edgar E. Iglesias <edgar.iglesias at gmail.com>
+S: Maintained
+F: target-cris/
+
+LM32
+M: Michael Walle <michael at walle.cc>
+S: Maintained
+F: target-lm32/
+
+M68K
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: target-m68k/
+
+MicroBlaze
+M: Edgar E. Iglesias <edgar.iglesias at gmail.com>
+S: Maintained
+F: target-microblaze/
+
+MIPS
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: target-mips/
+
+PowerPC
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: target-ppc/
+
+S390
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: target-s390x/
+
+SH4
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: target-sh4/
+
+SPARC
+M: Blue Swirl <blauwirbel at gmail.com>
+S: Maintained
+F: target-sparc/
+
+X86
+M: qemu-devel at nongnu.org
+S: Odd Fixes
+F: target-i386/
+
+Guest CPU Cores (KVM):
+----------------------
+
+Overall
+M: Avi Kivity <avi at redhat.com>
+M: Marcelo Tosatti <mtosatti at redhat.com>
+L: kvm at vger.kernel.org
+S: Supported
+F: kvm-*
+F: */kvm.*
+
+PPC
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: target-ppc/kvm.c
+
+S390
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: target-s390x/kvm.c
+
+X86
+M: Avi Kivity <avi at redhat.com>
+M: Marcelo Tosatti <mtosatti at redhat.com>
+L: kvm at vger.kernel.org
+S: Supported
+F: target-i386/kvm.c
+
+ARM Machines
+------------
+Gumstix
+M: qemu-devel at nongnu.org
+S: Orphan
+F: hw/gumstix.c
+
+Integrator CP
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/integratorcp.c
+
+Mainstone
+M: qemu-devel at nongnu.org
+S: Orphan
+F: hw/mainstone.c
+
+Musicpal
+M: Jan Kiszka <jan.kiszka at web.de>
+S: Maintained
+F: hw/musicpal.c
+
+nSeries
+M: Andrzej Zaborowski <balrogg at gmail.com>
+S: Maintained
+F: hw/nseries.c
+
+Palm
+M: Andrzej Zaborowski <balrogg at gmail.com>
+S: Maintained
+F: hw/palm.c
+
+Real View
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/realview*
+
+Spitz
+M: Andrzej Zaborowski <balrogg at gmail.com>
+S: Maintained
+F: hw/spitz.c
+
+Stellaris
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/stellaris.c
+
+Versatile PB
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/versatilepb.c
+
+CRIS Machines
+-------------
+Axis Dev88
+M: Edgar E. Iglesias <edgar.iglesias at gmail.com>
+S: Maintained
+F: hw/axis_dev88.c
+
+etraxfs
+M: Edgar E. Iglesias <edgar.iglesias at gmail.com>
+S: Maintained
+F: hw/etraxfs.c
+
+LM32 Machines
+-------------
+EVR32 and uclinux BSP
+M: Michael Walle <michael at walle.cc>
+S: Maintained
+F: hw/lm32_boards.c
+
+milkymist
+M: Michael Walle <michael at walle.cc>
+S: Maintained
+F: hw/milkymist.c
+
+M68K Machines
+-------------
+an5206
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/an5206.c
+
+dummy_m68k
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/dummy_m68k.c
+
+mcf5208
+M: Paul Brook <paul at codesourcery.com>
+S: Maintained
+F: hw/mcf5208.c
+
+MicroBlaze Machines
+-------------------
+petalogix_s3adsp1800
+M: Edgar E. Iglesias <edgar.iglesias at gmail.com>
+S: Maintained
+F: hw/petalogix_s3adsp1800.c
+
+MIPS Machines
+-------------
+Jazz
+M: Hervé Poussineau <hpoussin at reactos.org>
+S: Maintained
+F: hw/mips_jazz.c
+
+Malta
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: hw/mips_malta.c
+
+Mipssim
+M: qemu-devel at nongnu.org
+S: Orphan
+F: hw/mips_mipssim.c
+
+R4000
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: hw/mips_r4k.c
+
+PowerPC Machines
+----------------
+405
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: hw/ppc405_boards.c
+
+New World
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: hw/ppc_newworld.c
+
+Old World
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: hw/ppc_oldworld.c
+
+Prep
+M: qemu-devel at nongnu.org
+S: Orphan
+F: hw/ppc_prep.c
+
+SH4 Machines
+------------
+R2D
+M: Magnus Damm <magnus.damm at gmail.com>
+S: Maintained
+F: hw/r2d.c
+
+Shix
+M: Magnus Damm <magnus.damm at gmail.com>
+S: Orphan
+F: hw/shix.c
+
+SPARC Machines
+--------------
+Sun4m
+M: Blue Swirl <blauwirbel at gmail.com>
+S: Maintained
+F: hw/sun4m.c
+
+Sun4u
+M: Blue Swirl <blauwirbel at gmail.com>
+S: Maintained
+F: hw/sun4u.c
+
+S390 Machines
+-------------
+S390 Virtio
+M: Alexander Graf <agraf at suse.de>
+S: Maintained
+F: hw/s390-*.c
+
+X86 Machines
+------------
+PC
+M: Anthony Liguori <aliguori at us.ibm.com>
+S: Supported
+F: hw/pc.[ch] hw/pc_piix.c
+
+Devices
+-------
+IDE
+M: Kevin Wolf <kwolf at redhat.com>
+S: Odd Fixes
+F: hw/ide/
+
+PCI
+M: Michael S. Tsirkin <mst at redhat.com>
+S: Supported
+F: hw/pci*
+F: hw/piix*
+
+SCSI
+M: Paul Brook <paul at codesourcery.com>
+M: Kevin Wolf <kwolf at redhat.com>
+S: Odd Fixes
+F: hw/lsi53c895a.c
+F: hw/scsi*
+
+USB
+M: Gerd Hoffmann <kraxel at redhat.com>
+S: Maintained
+F: hw/usb*
+
+vhost
+M: Michael S. Tsirkin <mst at redhat.com>
+S: Supported
+F: hw/vhost*
+
+virtio
+M: Anthony Liguori <aliguori at us.ibm.com>
+S: Supported
+F: hw/virtio*
+
+virtio-9p
+M: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
+S: Supported
+F: hw/virtio-9p*
+
+virtio-blk
+M: Kevin Wolf <kwolf at redhat.com>
+S: Supported
+F: hw/virtio-blk*
+
+virtio-serial
+M: Amit Shah <amit.shah at redhat.com>
+S: Supported
+F: hw/virtio-serial*
+F: hw/virtio-console*
+
+Subsystems
+----------
+Audio
+M: Vassili Karpov (malc) <av1474 at comtv.ru>
+S: Maintained
+F: audio/
+
+Block
+M: Kevin Wolf <kwolf at redhat.com>
+S: Supported
+F: block*
+F: block/
+
+Character Devices
+M: Anthony Liguori <aliguori at us.ibm.com>
+S: Maintained
+F: qemu-char.c
+
+GDB stub
+M: qemu-devel at nongnu.org
+S: Odd Fixes
+F: gdbstub*
+F: gdb-xml/
+
+SPICE
+M: Gerd Hoffmann <kraxel at redhat.com>
+S: Supported
+F: ui/qemu-spice.h
+F: ui/spice-*.c
+F: audio/spiceaudio.c
+F: hw/qxl*
+
+Graphics
+M: Anthony Liguori <aliguori at us.ibm.com>
+S: Maintained
+F: ui/
+
+Main loop
+M: Anthony Liguori <aliguori at us.ibm.com>
+S: Supported
+F: vl.c
+
+Monitor (QMP/HMP)
+M: Luiz Capitulino <lcapitulino at redhat.com>
+M: Markus Armbruster <armbru at redhat.com>
+S: Supported
+F: monitor.c
+
+Network device layer
+M: Anthony Liguori <aliguori at us.ibm.com>
+M: Mark McLoughlin <markmc at redhat.com>
+S: Maintained
+F: net/
+
+SLIRP
+M: qemu-devel at nongnu.org
+S: Orphan
+F: slirp/
+
+Usermode Emulation
+------------------
+BSD user
+M: Blue Swirl <blauwirbel at gmail.com>
+S: Maintained
+F: bsd-user/
+
+Darwin user
+M: qemu-devel at nongnu.org
+S: Orphan
+F: darwin-user/
+
+Linux user
+M: Riku Voipio <riku.voipio at iki.fi>
+S: Maintained
+F: linux-user/
+
+Tiny Code Generator (TCG)
+-------------------------
+Common code
+M: qemu-devel at nongnu.org
+S: Maintained
+F: tcg/
+
+ARM target
+M: Andrzej Zaborowski <balrogg at gmail.com>
+S: Maintained
+F: tcg/arm/
+
+HPPA target
+M: Richard Henderson <rth at twiddle.net>
+S: Maintained
+F: tcg/hppa/
+
+i386 target
+M: qemu-devel at nongnu.org
+S: Maintained
+F: tcg/i386/
+
+IA64 target
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: tcg/ia64/
+
+MIPS target
+M: Aurelien Jarno <aurelien at aurel32.net>
+S: Maintained
+F: tcg/mips/
+
+PPC
+M: Vassili Karpov (malc) <av1474 at comtv.ru>
+S: Maintained
+F: tcg/ppc/
+
+PPC64 target
+M: Vassili Karpov (malc) <av1474 at comtv.ru>
+S: Maintained
+F: tcg/ppc64/
+
+S390 target
+M: Alexander Graf <agraf at suse.de>
+M: Richard Henderson <rth at twiddle.net>
+S: Maintained
+F: tcg/s390/
+
+SPARC target
+M: Blue Swirl <blauwirbel at gmail.com>
+S: Maintained
+F: tcg/sparc/
diff --git a/qemu-0.15.x/Makefile b/qemu-0.15.x/Makefile
new file mode 100644
index 0000000..0a31633
--- /dev/null
+++ b/qemu-0.15.x/Makefile
@@ -0,0 +1,403 @@
+# Makefile for QEMU.
+
+GENERATED_HEADERS = config-host.h trace.h qemu-options.def
+ifeq ($(TRACE_BACKEND),dtrace)
+GENERATED_HEADERS += trace-dtrace.h
+endif
+
+ifneq ($(wildcard config-host.mak),)
+# Put the all: rule here so that config-host.mak can contain dependencies.
+all: build-all
+include config-host.mak
+include $(SRC_PATH)/rules.mak
+config-host.mak: $(SRC_PATH)/configure
+	@echo $@ is out-of-date, running configure
+	@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
+else
+config-host.mak:
+	@echo "Please call configure before running make!"
+	@exit 1
+endif
+
+# Don't try to regenerate Makefile or configure
+# We don't generate any of them
+Makefile: ;
+configure: ;
+
+.PHONY: all clean cscope distclean dvi html info install install-doc \
+	pdf recurse-all speed tar tarbin test build-all
+
+$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
+
+LIBS+=-lz $(LIBS_TOOLS)
+
+ifdef BUILD_DOCS
+DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
+else
+DOCS=
+endif
+
+SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
+SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
+SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
+
+config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
+	$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
+
+-include $(SUBDIR_DEVICES_MAK_DEP)
+
+%/config-devices.mak: default-configs/%.mak
+	$(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, "  GEN   $@")
+	@if test -f $@; then \
+	  if cmp -s $@.old $@; then \
+	    mv $@.tmp $@; \
+	    cp -p $@ $@.old; \
+	  else \
+	    if test -f $@.old; then \
+	      echo "WARNING: $@ (user modified) out of date.";\
+	    else \
+	      echo "WARNING: $@ out of date.";\
+	    fi; \
+	    echo "Run \"make defconfig\" to regenerate."; \
+	    rm $@.tmp; \
+	  fi; \
+	 else \
+	  mv $@.tmp $@; \
+	  cp -p $@ $@.old; \
+	 fi
+
+defconfig:
+	rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
+
+-include config-all-devices.mak
+
+build-all: $(DOCS) $(TOOLS) recurse-all
+
+config-host.h: config-host.h-timestamp
+config-host.h-timestamp: config-host.mak
+qemu-options.def: $(SRC_PATH)/qemu-options.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
+
+SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
+
+subdir-%: $(GENERATED_HEADERS)
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
+
+ifneq ($(wildcard config-host.mak),)
+include $(SRC_PATH)/Makefile.objs
+endif
+
+$(common-obj-y): $(GENERATED_HEADERS)
+subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o
+
+$(filter %-softmmu,$(SUBDIR_RULES)): $(trace-obj-y) $(common-obj-y) subdir-libdis
+
+$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) $(trace-obj-y) subdir-libdis-user subdir-libuser
+
+ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
+romsubdir-%:
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pc-bios/$* V="$(V)" TARGET_DIR="$*/",)
+
+ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
+
+recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
+
+audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
+
+QEMU_CFLAGS+=$(CURL_CFLAGS)
+
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
+ui/cocoa.o: ui/cocoa.m
+
+ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+
+ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
+
+bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
+
+version.o: $(SRC_PATH)/version.rc config-host.mak
+	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
+
+version-obj-$(CONFIG_WIN32) += version.o
+######################################################################
+# Support building shared library libcacard
+
+.PHONY: libcacard.la install-libcacard
+ifeq ($(LIBTOOL),)
+libcacard.la:
+	@echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+	@echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(GENERATED_HEADERS) $(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
+
+install-libcacard: libcacard.la
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
+endif
+######################################################################
+
+qemu-img.o: qemu-img-cmds.h
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
+
+qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+
+qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+
+qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+
+qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
+
+check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
+
+CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
+
+check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
+check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
+check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
+check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
+
+$(qapi-obj-y): $(GENERATED_HEADERS)
+qapi-dir := qapi-generated
+test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+
+$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
+$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
+$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
+$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
+	    $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+
+$(qapi-dir)/qga-qapi-types.c: $(qapi-dir)/qga-qapi-types.h
+$(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+$(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h
+$(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+$(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+
+test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
+test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
+test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+
+QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o
+QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c)
+
+$(QGALIB_GEN): $(GENERATED_HEADERS)
+$(QGALIB) qemu-ga.o: $(QGALIB_GEN) $(qapi-obj-y)
+qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o
+
+QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
+
+clean:
+# avoid old build problems by removing potentially incorrect old files
+	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
+	rm -f qemu-options.def
+	rm -f *.o *.d *.a *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~
+	rm -Rf .libs
+	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
+	rm -f qemu-img-cmds.h
+	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
+	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
+	rm -f trace-dtrace.h trace-dtrace.h-timestamp
+	rm -rf $(qapi-dir)
+	$(MAKE) -C tests clean
+	for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
+	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
+	rm -f $$d/qemu-options.def; \
+        done
+
+distclean: clean
+	rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
+	rm -f config-all-devices.mak
+	rm -f roms/seabios/config.mak roms/vgabios/config.mak
+	rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
+	rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
+	rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
+	rm -f qemu-doc.vr
+	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
+	for d in $(TARGET_DIRS) $(QEMULIBS); do \
+	rm -rf $$d || exit 1 ; \
+        done
+
+KEYMAPS=da     en-gb  et  fr     fr-ch  is  lt  modifiers  no  pt-br  sv \
+ar      de     en-us  fi  fr-be  hr     it  lv  nl         pl  ru     th \
+common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
+
+ifdef INSTALL_BLOBS
+BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
+vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
+ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
+pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
+pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
+bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
+mpc8544ds.dtb \
+multiboot.bin linuxboot.bin \
+s390-zipl.rom \
+spapr-rtas.bin slof.bin
+else
+BLOBS=
+endif
+
+install-doc: $(DOCS)
+	$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
+	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
+ifdef CONFIG_POSIX
+	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
+	$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
+	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
+	$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
+endif
+
+install-sysconfig:
+	$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
+	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
+
+install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
+	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
+ifneq ($(TOOLS),)
+	$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
+endif
+ifneq ($(BLOBS),)
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
+	set -e; for x in $(BLOBS); do \
+		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+	done
+endif
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
+	set -e; for x in $(KEYMAPS); do \
+		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+	done
+	for d in $(TARGET_DIRS); do \
+	$(MAKE) -C $$d $@ || exit 1 ; \
+        done
+
+# various test targets
+test speed: all
+	$(MAKE) -C tests $@
+
+.PHONY: TAGS
+TAGS:
+	find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
+
+cscope:
+	rm -f ./cscope.*
+	find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
+	cscope -b
+
+# documentation
+MAKEINFO=makeinfo
+MAKEINFOFLAGS=--no-headers --no-split --number-sections
+TEXIFLAG=$(if $(V),,--quiet)
+%.dvi: %.texi
+	$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"  GEN   $@")
+
+%.html: %.texi
+	$(call quiet-command,$(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
+	"  GEN   $@")
+
+%.info: %.texi
+	$(call quiet-command,$(MAKEINFO) $< -o $@,"  GEN   $@")
+
+%.pdf: %.texi
+	$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"  GEN   $@")
+
+qemu-options.texi: $(SRC_PATH)/qemu-options.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
+
+qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
+
+QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@,"  GEN   $@")
+
+qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
+
+qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
+	$(call quiet-command, \
+	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
+	  pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
+	  "  GEN   $@")
+
+qemu-img.1: qemu-img.texi qemu-img-cmds.texi
+	$(call quiet-command, \
+	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
+	  pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
+	  "  GEN   $@")
+
+qemu-nbd.8: qemu-nbd.texi
+	$(call quiet-command, \
+	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
+	  pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
+	  "  GEN   $@")
+
+dvi: qemu-doc.dvi qemu-tech.dvi
+html: qemu-doc.html qemu-tech.html
+info: qemu-doc.info qemu-tech.info
+pdf: qemu-doc.pdf qemu-tech.pdf
+
+qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
+	qemu-img.texi qemu-nbd.texi qemu-options.texi \
+	qemu-monitor.texi qemu-img-cmds.texi
+
+VERSION ?= $(shell cat VERSION)
+FILE = qemu-$(VERSION)
+
+# tar release (use 'make -k tar' on a checkouted tree)
+tar:
+	rm -rf /tmp/$(FILE)
+	cp -r . /tmp/$(FILE)
+	cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
+	rm -rf /tmp/$(FILE)
+
+SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS))
+SYSTEM_PROGS=$(patsubst qemu-system-i386,qemu, \
+             $(patsubst %-softmmu,qemu-system-%, \
+             $(SYSTEM_TARGETS)))
+
+USER_TARGETS=$(filter %-user,$(TARGET_DIRS))
+USER_PROGS=$(patsubst %-bsd-user,qemu-%, \
+           $(patsubst %-darwin-user,qemu-%, \
+           $(patsubst %-linux-user,qemu-%, \
+           $(USER_TARGETS))))
+
+# generate a binary distribution
+tarbin:
+	cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
+	$(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \
+	$(patsubst %,$(bindir)/%, $(USER_PROGS)) \
+	$(bindir)/qemu-img \
+	$(bindir)/qemu-nbd \
+	$(datadir)/bios.bin \
+	$(datadir)/vgabios.bin \
+	$(datadir)/vgabios-cirrus.bin \
+	$(datadir)/ppc_rom.bin \
+	$(datadir)/openbios-sparc32 \
+	$(datadir)/openbios-sparc64 \
+	$(datadir)/openbios-ppc \
+	$(datadir)/pxe-e1000.rom \
+	$(datadir)/pxe-eepro100.rom \
+	$(datadir)/pxe-ne2k_pci.rom \
+	$(datadir)/pxe-pcnet.rom \
+	$(datadir)/pxe-rtl8139.rom \
+	$(datadir)/pxe-virtio.rom \
+	$(docdir)/qemu-doc.html \
+	$(docdir)/qemu-tech.html \
+	$(mandir)/man1/qemu.1 \
+	$(mandir)/man1/qemu-img.1 \
+	$(mandir)/man8/qemu-nbd.8
+
+# Include automatically generated dependency files
+-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
diff --git a/qemu-0.15.x/Makefile.dis b/qemu-0.15.x/Makefile.dis
new file mode 100644
index 0000000..3e1fcaf
--- /dev/null
+++ b/qemu-0.15.x/Makefile.dis
@@ -0,0 +1,23 @@
+# Makefile for disassemblers.
+
+include ../config-host.mak
+include config.mak
+include $(SRC_PATH)/rules.mak
+
+.PHONY: all
+
+$(call set-vpath, $(SRC_PATH))
+
+QEMU_CFLAGS+=-I..
+
+include $(SRC_PATH)/Makefile.objs
+
+all: $(libdis-y)
+# Dummy command so that make thinks it has done something
+	@true
+
+clean:
+	rm -f *.o *.d *.a *~
+
+# Include automatically generated dependency files
+-include $(wildcard *.d */*.d)
diff --git a/qemu-0.15.x/Makefile.hw b/qemu-0.15.x/Makefile.hw
new file mode 100644
index 0000000..b9181ab
--- /dev/null
+++ b/qemu-0.15.x/Makefile.hw
@@ -0,0 +1,24 @@
+# Makefile for qemu target independent devices.
+
+include ../config-host.mak
+include ../config-all-devices.mak
+include config.mak
+include $(SRC_PATH)/rules.mak
+
+.PHONY: all
+
+$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
+
+QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
+
+include $(SRC_PATH)/Makefile.objs
+
+all: $(hw-obj-y)
+# Dummy command so that make thinks it has done something
+	@true
+
+clean:
+	rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~
+
+# Include automatically generated dependency files
+-include $(wildcard *.d */*.d)
diff --git a/qemu-0.15.x/Makefile.objs b/qemu-0.15.x/Makefile.objs
new file mode 100644
index 0000000..6991a9f
--- /dev/null
+++ b/qemu-0.15.x/Makefile.objs
@@ -0,0 +1,387 @@
+#######################################################################
+# QObject
+qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
+qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
+qobject-obj-y += qerror.o error.o
+
+#######################################################################
+# oslib-obj-y is code depending on the OS (win32 vs posix)
+oslib-obj-y = osdep.o
+oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
+oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
+
+#######################################################################
+# block-obj-y is code used by both qemu system emulation and qemu-img
+
+block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
+block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
+block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
+block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
+
+block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
+block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
+block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
+block-nested-y += qed-check.o
+block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-nested-$(CONFIG_WIN32) += raw-win32.o
+block-nested-$(CONFIG_POSIX) += raw-posix.o
+block-nested-$(CONFIG_CURL) += curl.o
+block-nested-$(CONFIG_RBD) += rbd.o
+
+block-obj-y +=  $(addprefix block/, $(block-nested-y))
+
+net-obj-y = net.o
+net-nested-y = queue.o checksum.o util.o
+net-nested-y += socket.o
+net-nested-y += dump.o
+net-nested-$(CONFIG_POSIX) += tap.o
+net-nested-$(CONFIG_LINUX) += tap-linux.o
+net-nested-$(CONFIG_WIN32) += tap-win32.o
+net-nested-$(CONFIG_BSD) += tap-bsd.o
+net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
+net-nested-$(CONFIG_AIX) += tap-aix.o
+net-nested-$(CONFIG_HAIKU) += tap-haiku.o
+net-nested-$(CONFIG_SLIRP) += slirp.o
+net-nested-$(CONFIG_VDE) += vde.o
+net-obj-y += $(addprefix net/, $(net-nested-y))
+
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
+# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
+# only pull in the actual virtio-9p device if we also enabled virtio.
+CONFIG_REALLY_VIRTFS=y
+fsdev-nested-y = qemu-fsdev.o
+else
+fsdev-nested-y = qemu-fsdev-dummy.o
+endif
+fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
+
+######################################################################
+# libqemu_common.a: Target independent part of system emulation. The
+# long term path is to suppress *all* target specific code in case of
+# system emulation, i.e. a single QEMU executable should support all
+# CPUs and machines.
+
+common-obj-y = $(block-obj-y) blockdev.o
+common-obj-y += $(net-obj-y)
+common-obj-y += $(qobject-obj-y)
+common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
+common-obj-y += readline.o console.o cursor.o qemu-error.o
+common-obj-y += $(oslib-obj-y)
+common-obj-$(CONFIG_WIN32) += os-win32.o
+common-obj-$(CONFIG_POSIX) += os-posix.o
+
+common-obj-y += tcg-runtime.o host-utils.o
+common-obj-y += irq.o ioport.o input.o
+common-obj-$(CONFIG_PTIMER) += ptimer.o
+common-obj-$(CONFIG_MAX7310) += max7310.o
+common-obj-$(CONFIG_WM8750) += wm8750.o
+common-obj-$(CONFIG_TWL92230) += twl92230.o
+common-obj-$(CONFIG_TSC2005) += tsc2005.o
+common-obj-$(CONFIG_LM832X) += lm832x.o
+common-obj-$(CONFIG_TMP105) += tmp105.o
+common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
+common-obj-$(CONFIG_SSD0303) += ssd0303.o
+common-obj-$(CONFIG_SSD0323) += ssd0323.o
+common-obj-$(CONFIG_ADS7846) += ads7846.o
+common-obj-$(CONFIG_MAX111X) += max111x.o
+common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-y += i2c.o smbus.o smbus_eeprom.o
+common-obj-y += eeprom93xx.o
+common-obj-y += scsi-disk.o cdrom.o
+common-obj-y += scsi-generic.o scsi-bus.o
+common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
+common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
+common-obj-$(CONFIG_SSI) += ssi.o
+common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
+common-obj-$(CONFIG_SD) += sd.o
+common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
+common-obj-y += bt-hci-csr.o
+common-obj-y += buffered_file.o migration.o migration-tcp.o
+common-obj-y += qemu-char.o savevm.o #aio.o
+common-obj-y += msmouse.o ps2.o
+common-obj-y += qdev.o qdev-properties.o
+common-obj-y += block-migration.o iohandler.o
+common-obj-y += pflib.o
+common-obj-y += bitmap.o bitops.o
+
+common-obj-$(CONFIG_BRLAPI) += baum.o
+common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+common-obj-$(CONFIG_WIN32) += version.o
+
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
+
+audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+audio-obj-$(CONFIG_SDL) += sdlaudio.o
+audio-obj-$(CONFIG_OSS) += ossaudio.o
+audio-obj-$(CONFIG_SPICE) += spiceaudio.o
+audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
+audio-obj-$(CONFIG_ALSA) += alsaaudio.o
+audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
+audio-obj-$(CONFIG_FMOD) += fmodaudio.o
+audio-obj-$(CONFIG_ESD) += esdaudio.o
+audio-obj-$(CONFIG_PA) += paaudio.o
+audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
+audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
+audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
+audio-obj-y += wavcapture.o
+common-obj-y += $(addprefix audio/, $(audio-obj-y))
+
+ui-obj-y += keymaps.o
+ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+ui-obj-$(CONFIG_COCOA) += cocoa.o
+ui-obj-$(CONFIG_CURSES) += curses.o
+vnc-obj-y += vnc.o d3des.o
+vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
+vnc-obj-y += vnc-enc-tight.o vnc-palette.o
+vnc-obj-y += vnc-enc-zrle.o
+vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
+vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
+ifdef CONFIG_VNC_THREAD
+vnc-obj-y += vnc-jobs-async.o
+else
+vnc-obj-y += vnc-jobs-sync.o
+endif
+common-obj-y += $(addprefix ui/, $(ui-obj-y))
+common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y))
+
+common-obj-y += iov.o acl.o
+common-obj-$(CONFIG_POSIX) += compatfd.o
+common-obj-y += notify.o event_notifier.o
+common-obj-y += qemu-timer.o qemu-timer-common.o
+
+slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
+slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
+slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
+common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
+
+# xen backend driver support
+common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o
+
+######################################################################
+# libuser
+
+user-obj-y =
+user-obj-y += envlist.o path.o
+user-obj-y += tcg-runtime.o host-utils.o
+user-obj-y += cutils.o cache-utils.o
+
+######################################################################
+# libhw
+
+hw-obj-y =
+hw-obj-y += vl.o loader.o
+hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
+hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
+hw-obj-y += fw_cfg.o
+hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
+hw-obj-$(CONFIG_PCI) += msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
+hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
+hw-obj-y += watchdog.o
+hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
+hw-obj-$(CONFIG_ECC) += ecc.o
+hw-obj-$(CONFIG_NAND) += nand.o
+hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
+hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
+
+hw-obj-$(CONFIG_M48T59) += m48t59.o
+hw-obj-$(CONFIG_ESCC) += escc.o
+hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
+
+hw-obj-$(CONFIG_SERIAL) += serial.o
+hw-obj-$(CONFIG_PARALLEL) += parallel.o
+hw-obj-$(CONFIG_I8254) += i8254.o
+hw-obj-$(CONFIG_PCSPK) += pcspk.o
+hw-obj-$(CONFIG_PCKBD) += pckbd.o
+hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
+hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
+hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
+hw-obj-$(CONFIG_FDC) += fdc.o
+hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
+hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
+hw-obj-$(CONFIG_DMA) += dma.o
+hw-obj-$(CONFIG_HPET) += hpet.o
+hw-obj-$(CONFIG_APPLESMC) += applesmc.o
+hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
+hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
+hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
+
+# PPC devices
+hw-obj-$(CONFIG_OPENPIC) += openpic.o
+hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
+# Mac shared devices
+hw-obj-$(CONFIG_MACIO) += macio.o
+hw-obj-$(CONFIG_CUDA) += cuda.o
+hw-obj-$(CONFIG_ADB) += adb.o
+hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
+hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
+# OldWorld PowerMac
+hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
+hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o
+# NewWorld PowerMac
+hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o
+hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o
+# PowerPC E500 boards
+hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
+
+# MIPS devices
+hw-obj-$(CONFIG_PIIX4) += piix4.o
+
+# PCI watchdog devices
+hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
+
+hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
+
+# PCI network cards
+hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
+hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
+hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
+hw-obj-$(CONFIG_E1000_PCI) += e1000.o
+hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
+
+hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
+hw-obj-$(CONFIG_LAN9118) += lan9118.o
+hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
+
+# IDE
+hw-obj-$(CONFIG_IDE_CORE) += ide/core.o ide/atapi.o
+hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o
+hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o
+hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o
+hw-obj-$(CONFIG_IDE_PIIX) += ide/piix.o
+hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o
+hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
+hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
+hw-obj-$(CONFIG_AHCI) += ide/ahci.o
+hw-obj-$(CONFIG_AHCI) += ide/ich.o
+
+# SCSI layer
+hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
+hw-obj-$(CONFIG_ESP) += esp.o
+
+hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
+hw-obj-y += qdev-addr.o
+
+# VGA
+hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
+hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
+hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
+hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
+hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+
+hw-obj-$(CONFIG_RC4030) += rc4030.o
+hw-obj-$(CONFIG_DP8393X) += dp8393x.o
+hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
+hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
+
+# Sound
+sound-obj-y =
+sound-obj-$(CONFIG_SB16) += sb16.o
+sound-obj-$(CONFIG_ES1370) += es1370.o
+sound-obj-$(CONFIG_AC97) += ac97.o
+sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
+sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
+sound-obj-$(CONFIG_CS4231A) += cs4231a.o
+sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
+
+adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
+hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
+
+9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) +=  virtio-9p-local.o virtio-9p-xattr.o
+9pfs-nested-$(CONFIG_VIRTFS) +=   virtio-9p-xattr-user.o virtio-9p-posix-acl.o
+
+hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
+
+
+######################################################################
+# libdis
+# NOTE: the disassembler code is only needed for debugging
+
+libdis-y =
+libdis-$(CONFIG_ALPHA_DIS) += alpha-dis.o
+libdis-$(CONFIG_ARM_DIS) += arm-dis.o
+libdis-$(CONFIG_CRIS_DIS) += cris-dis.o
+libdis-$(CONFIG_HPPA_DIS) += hppa-dis.o
+libdis-$(CONFIG_I386_DIS) += i386-dis.o
+libdis-$(CONFIG_IA64_DIS) += ia64-dis.o
+libdis-$(CONFIG_M68K_DIS) += m68k-dis.o
+libdis-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
+libdis-$(CONFIG_MIPS_DIS) += mips-dis.o
+libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
+libdis-$(CONFIG_S390_DIS) += s390-dis.o
+libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
+libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
+
+######################################################################
+# trace
+
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
+trace.h: trace.h-timestamp
+endif
+trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
+	@cmp -s $@ trace.h || cp $@ trace.h
+
+trace.c: trace.c-timestamp
+trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
+	@cmp -s $@ trace.c || cp $@ trace.c
+
+trace.o: trace.c $(GENERATED_HEADERS)
+
+trace-dtrace.h: trace-dtrace.dtrace
+	$(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependency
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+
+ifeq ($(LIBTOOL),)
+trace-dtrace.lo: trace-dtrace.dtrace
+	@echo "missing libtool. please install and rerun configure."; exit 1
+else
+trace-dtrace.lo: trace-dtrace.dtrace
+	$(call quiet-command,libtool --mode=compile --tag=CC dtrace -o $@ -G -s $<, "  lt GEN trace-dtrace.o")
+endif
+
+simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
+
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
+trace-obj-y = trace.o
+ifeq ($(TRACE_BACKEND),simple)
+trace-obj-y += simpletrace.o
+user-obj-y += qemu-timer-common.o
+endif
+endif
+
+######################################################################
+# smartcard
+
+libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
+
+######################################################################
+# qapi
+
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
+vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
+
+vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
+
+vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/qemu-0.15.x/Makefile.target b/qemu-0.15.x/Makefile.target
new file mode 100644
index 0000000..cde509b
--- /dev/null
+++ b/qemu-0.15.x/Makefile.target
@@ -0,0 +1,431 @@
+# -*- Mode: makefile -*-
+
+GENERATED_HEADERS = config-target.h
+CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
+CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
+CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
+
+include ../config-host.mak
+include config-devices.mak
+include config-target.mak
+include $(SRC_PATH)/rules.mak
+ifneq ($(HWDIR),)
+include $(HWDIR)/config.mak
+endif
+
+TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
+$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw)
+ifdef CONFIG_LINUX
+QEMU_CFLAGS += -I../linux-headers
+endif
+QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
+
+include $(SRC_PATH)/Makefile.objs
+
+ifdef CONFIG_USER_ONLY
+# user emulator name
+QEMU_PROG=qemu-$(TARGET_ARCH2)
+else
+# system emulator name
+ifeq ($(TARGET_ARCH), i386)
+QEMU_PROG=qemu$(EXESUF)
+else
+QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
+endif
+endif
+
+PROGS=$(QEMU_PROG)
+STPFILES=
+
+ifndef CONFIG_HAIKU
+LIBS+=-lm
+endif
+
+config-target.h: config-target.h-timestamp
+config-target.h-timestamp: config-target.mak
+
+ifdef CONFIG_SYSTEMTAP_TRACE
+stap: $(QEMU_PROG).stp
+
+ifdef CONFIG_USER_ONLY
+TARGET_TYPE=user
+else
+TARGET_TYPE=system
+endif
+
+$(QEMU_PROG).stp:
+	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
+		--$(TRACE_BACKEND) \
+		--binary $(bindir)/$(QEMU_PROG) \
+		--target-arch $(TARGET_ARCH) \
+		--target-type $(TARGET_TYPE) \
+		--stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
+else
+stap:
+endif
+
+all: $(PROGS) stap
+
+# Dummy command so that make thinks it has done something
+	@true
+
+#########################################################
+# cpu emulator library
+libobj-y = exec.o translate-all.o cpu-exec.o translate.o
+libobj-y += tcg/tcg.o
+libobj-y += fpu/softfloat.o
+libobj-y += op_helper.o helper.o
+ifeq ($(TARGET_BASE_ARCH), i386)
+libobj-y += cpuid.o
+endif
+libobj-$(CONFIG_NEED_MMU) += mmu.o
+libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
+
+libobj-y += disas.o
+
+$(libobj-y): $(GENERATED_HEADERS)
+
+# libqemu
+
+translate.o: translate.c cpu.h
+
+translate-all.o: translate-all.c cpu.h
+
+tcg/tcg.o: cpu.h
+
+# HELPER_CFLAGS is used for all the code compiled with static register
+# variables
+op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+
+# Note: this is a workaround. The real fix is to avoid compiling
+# cpu_signal_handler() in user-exec.c.
+signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+
+#########################################################
+# Linux user emulator target
+
+ifdef CONFIG_LINUX_USER
+
+$(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR))
+
+QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
+obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
+      elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
+      qemu-malloc.o user-exec.o $(oslib-obj-y)
+
+obj-$(TARGET_HAS_BFLT) += flatload.o
+
+obj-$(TARGET_I386) += vm86.o
+
+obj-i386-y += ioport-user.o
+
+nwfpe-obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o
+nwfpe-obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o
+obj-arm-y +=  $(addprefix nwfpe/, $(nwfpe-obj-y))
+obj-arm-y += arm-semi.o
+
+obj-m68k-y += m68k-sim.o m68k-semi.o
+
+$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
+
+obj-y += $(addprefix ../libuser/, $(user-obj-y))
+obj-y += $(addprefix ../libdis-user/, $(libdis-y))
+obj-y += $(libobj-y)
+
+endif #CONFIG_LINUX_USER
+
+#########################################################
+# Darwin user emulator target
+
+ifdef CONFIG_DARWIN_USER
+
+$(call set-vpath, $(SRC_PATH)/darwin-user)
+
+QEMU_CFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
+
+# Leave some space for the regular program loading zone
+LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
+
+LIBS+=-lmx
+
+obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
+        gdbstub.o user-exec.o
+
+obj-i386-y += ioport-user.o
+
+$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
+
+obj-y += $(addprefix ../libuser/, $(user-obj-y))
+obj-y += $(addprefix ../libdis-user/, $(libdis-y))
+obj-y += $(libobj-y)
+
+endif #CONFIG_DARWIN_USER
+
+#########################################################
+# BSD user emulator target
+
+ifdef CONFIG_BSD_USER
+
+$(call set-vpath, $(SRC_PATH)/bsd-user)
+
+QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
+
+obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
+        gdbstub.o uaccess.o user-exec.o
+
+obj-i386-y += ioport-user.o
+
+$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
+
+obj-y += $(addprefix ../libuser/, $(user-obj-y))
+obj-y += $(addprefix ../libdis-user/, $(libdis-y))
+obj-y += $(libobj-y)
+
+endif #CONFIG_BSD_USER
+
+#########################################################
+# System emulator target
+ifdef CONFIG_SOFTMMU
+
+obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
+# virtio has to be here due to weird dependency between PCI and virtio-net.
+# need to fix this properly
+obj-$(CONFIG_NO_PCI) += pci-stub.o
+obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
+obj-y += vhost_net.o
+obj-$(CONFIG_VHOST_NET) += vhost.o
+obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
+obj-y += rwhandler.o
+obj-$(CONFIG_KVM) += kvm.o kvm-all.o
+obj-$(CONFIG_NO_KVM) += kvm-stub.o
+LIBS+=-lz
+
+QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
+QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
+QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
+QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
+
+# xen support
+obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
+obj-$(CONFIG_NO_XEN) += xen-stub.o
+
+obj-i386-$(CONFIG_XEN) += xen_platform.o
+
+# Inter-VM PCI shared memory
+CONFIG_IVSHMEM =
+ifeq ($(CONFIG_KVM), y)
+  ifeq ($(CONFIG_PCI), y)
+    CONFIG_IVSHMEM = y
+  endif
+endif
+obj-$(CONFIG_IVSHMEM) += ivshmem.o
+
+# Hardware support
+obj-i386-y += vga.o
+obj-i386-y += mc146818rtc.o i8259.o pc.o
+obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += vmport.o
+obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
+obj-i386-y += debugcon.o multiboot.o
+obj-i386-y += pc_piix.o
+obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
+
+# shared objects
+obj-ppc-y = ppc.o
+obj-ppc-y += vga.o
+# PREP target
+obj-ppc-y += i8259.o mc146818rtc.o
+obj-ppc-y += ppc_prep.o
+# OldWorld PowerMac
+obj-ppc-y += ppc_oldworld.o
+# NewWorld PowerMac
+obj-ppc-y += ppc_newworld.o
+# IBM pSeries (sPAPR)
+ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
+obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
+obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
+endif
+# PowerPC 4xx boards
+obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
+obj-ppc-y += ppc440.o ppc440_bamboo.o
+# PowerPC E500 boards
+obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
+# PowerPC 440 Xilinx ML507 reference board.
+obj-ppc-y += virtex_ml507.o
+obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
+obj-ppc-$(CONFIG_FDT) += device_tree.o
+
+# Xilinx PPC peripherals
+obj-ppc-y += xilinx_intc.o
+obj-ppc-y += xilinx_timer.o
+obj-ppc-y += xilinx_uartlite.o
+obj-ppc-y += xilinx_ethlite.o
+
+# LM32 boards
+obj-lm32-y += lm32_boards.o
+obj-lm32-y += milkymist.o
+
+# LM32 peripherals
+obj-lm32-y += lm32_pic.o
+obj-lm32-y += lm32_juart.o
+obj-lm32-y += lm32_timer.o
+obj-lm32-y += lm32_uart.o
+obj-lm32-y += lm32_sys.o
+obj-lm32-y += milkymist-ac97.o
+obj-lm32-y += milkymist-hpdmc.o
+obj-lm32-y += milkymist-memcard.o
+obj-lm32-y += milkymist-minimac2.o
+obj-lm32-y += milkymist-pfpu.o
+obj-lm32-y += milkymist-softusb.o
+obj-lm32-y += milkymist-sysctl.o
+obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
+obj-lm32-y += milkymist-uart.o
+obj-lm32-y += milkymist-vgafb.o
+obj-lm32-y += framebuffer.o
+
+obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
+obj-mips-y += mips_addr.o mips_timer.o mips_int.o
+obj-mips-y += vga.o i8259.o
+obj-mips-y += g364fb.o jazz_led.o
+obj-mips-y += gt64xxx.o mc146818rtc.o
+obj-mips-y += cirrus_vga.o
+obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
+
+obj-microblaze-y = petalogix_s3adsp1800_mmu.o
+obj-microblaze-y += petalogix_ml605_mmu.o
+
+obj-microblaze-y += microblaze_pic_cpu.o
+obj-microblaze-y += xilinx_intc.o
+obj-microblaze-y += xilinx_timer.o
+obj-microblaze-y += xilinx_uartlite.o
+obj-microblaze-y += xilinx_ethlite.o
+obj-microblaze-y += xilinx_axidma.o
+obj-microblaze-y += xilinx_axienet.o
+
+obj-microblaze-$(CONFIG_FDT) += device_tree.o
+
+# Boards
+obj-cris-y = cris_pic_cpu.o
+obj-cris-y += cris-boot.o
+obj-cris-y += etraxfs.o axis_dev88.o
+obj-cris-y += axis_dev88.o
+
+# IO blocks
+obj-cris-y += etraxfs_dma.o
+obj-cris-y += etraxfs_pic.o
+obj-cris-y += etraxfs_eth.o
+obj-cris-y += etraxfs_timer.o
+obj-cris-y += etraxfs_ser.o
+
+ifeq ($(TARGET_ARCH), sparc64)
+obj-sparc-y = sun4u.o apb_pci.o
+obj-sparc-y += vga.o
+obj-sparc-y += mc146818rtc.o
+obj-sparc-y += cirrus_vga.o
+else
+obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
+obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
+obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
+
+# GRLIB
+obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
+endif
+
+obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
+obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
+obj-arm-y += versatile_pci.o
+obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-arm-y += pl061.o
+obj-arm-y += arm-semi.o
+obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
+obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
+obj-arm-y += gumstix.o
+obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
+		omap_gpio.o omap_intc.o omap_uart.o
+obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
+		omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
+obj-arm-y += omap_sx1.o palm.o tsc210x.o
+obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
+obj-arm-y += mst_fpga.o mainstone.o
+obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
+obj-arm-y += framebuffer.o
+obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
+obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
+obj-arm-y += syborg_virtio.o
+obj-arm-y += vexpress.o
+obj-arm-y += strongarm.o
+obj-arm-y += collie.o
+
+obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
+obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
+obj-sh4-y += ide/mmio.o
+
+obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
+obj-m68k-y += m68k-semi.o dummy_m68k.o
+
+obj-s390x-y = s390-virtio-bus.o s390-virtio.o
+
+obj-alpha-y = i8259.o mc146818rtc.o
+obj-alpha-y += vga.o cirrus_vga.o
+
+main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
+
+monitor.o: hmp-commands.h qmp-commands.h
+
+$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
+
+obj-y += $(addprefix ../, $(common-obj-y))
+obj-y += $(addprefix ../libdis/, $(libdis-y))
+obj-y += $(libobj-y)
+obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
+
+endif # CONFIG_SOFTMMU
+
+ifndef CONFIG_LINUX_USER
+# libcacard needs qemu-thread support, and besides is only needed by devices
+# so not requires with linux-user targets
+obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
+endif # CONFIG_LINUX_USER
+
+obj-y += $(addprefix ../, $(trace-obj-y))
+obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
+
+$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+	$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
+
+
+gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
+	$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
+
+hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
+
+qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
+	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
+
+clean:
+	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
+	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+	rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
+ifdef CONFIG_SYSTEMTAP_TRACE
+	rm -f *.stp
+endif
+
+install: all
+ifneq ($(PROGS),)
+	$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
+ifneq ($(STRIP),)
+	$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
+endif
+endif
+ifdef CONFIG_SYSTEMTAP_TRACE
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
+	$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+endif
+
+# Include automatically generated dependency files
+-include $(wildcard *.d */*.d)
diff --git a/qemu-0.15.x/Makefile.user b/qemu-0.15.x/Makefile.user
new file mode 100644
index 0000000..024b773
--- /dev/null
+++ b/qemu-0.15.x/Makefile.user
@@ -0,0 +1,23 @@
+# Makefile for qemu target independent user files.
+
+include ../config-host.mak
+include $(SRC_PATH)/rules.mak
+-include config.mak
+
+.PHONY: all
+
+$(call set-vpath, $(SRC_PATH))
+
+QEMU_CFLAGS+=-I..
+
+include $(SRC_PATH)/Makefile.objs
+
+all: $(user-obj-y)
+# Dummy command so that make thinks it has done something
+	@true
+
+clean:
+	rm -f *.o *.d *.a *~
+
+# Include automatically generated dependency files
+-include $(wildcard *.d */*.d)
diff --git a/qemu-0.15.x/QMP/README b/qemu-0.15.x/QMP/README
new file mode 100644
index 0000000..c95a08c
--- /dev/null
+++ b/qemu-0.15.x/QMP/README
@@ -0,0 +1,88 @@
+                          QEMU Monitor Protocol
+                          =====================
+
+Introduction
+-------------
+
+The QEMU Monitor Protocol (QMP) allows applications to communicate with
+QEMU's Monitor.
+
+QMP is JSON[1] based and currently has the following features:
+
+- Lightweight, text-based, easy to parse data format
+- Asynchronous messages support (ie. events)
+- Capabilities Negotiation
+
+For detailed information on QMP's usage, please, refer to the following files:
+
+o qmp-spec.txt      QEMU Monitor Protocol current specification
+o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
+o qmp-events.txt    List of available asynchronous events
+
+There is also a simple Python script called 'qmp-shell' available.
+
+IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
+section in the qmp-commands.txt file before making any serious use of QMP.
+
+
+[1] http://www.json.org
+
+Usage
+-----
+
+To enable QMP, you need a QEMU monitor instance in "control mode". There are
+two ways of doing this.
+
+The simplest one is using the '-qmp' command-line option. The following
+example makes QMP available on localhost port 4444:
+
+  $ qemu [...] -qmp tcp:localhost:4444,server
+
+However, in order to have more complex combinations, like multiple monitors,
+the '-mon' command-line option should be used along with the '-chardev' one.
+For instance, the following example creates one user monitor on stdio and one
+QMP monitor on localhost port 4444.
+
+   $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
+                -chardev socket,id=mon1,host=localhost,port=4444,server \
+                -mon chardev=mon1,mode=control
+
+Please, refer to QEMU's manpage for more information.
+
+Simple Testing
+--------------
+
+To manually test QMP one can connect with telnet and issue commands by hand:
+
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
+{ "execute": "qmp_capabilities" }
+{"return": {}}
+{ "execute": "query-version" }
+{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
+
+Development Process
+-------------------
+
+When changing QMP's interface (by adding new commands, events or modifying
+existing ones) it's mandatory to update the relevant documentation, which is
+one (or more) of the files listed in the 'Introduction' section*.
+
+Also, it's strongly recommended to send the documentation patch first, before
+doing any code change. This is so because:
+
+  1. Avoids the code dictating the interface
+
+  2. Review can improve your interface.  Letting that happen before
+     you implement it can save you work.
+
+* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
+  is the file that should be edited.
+
+Homepage
+--------
+
+http://wiki.qemu.org/QMP
diff --git a/qemu-0.15.x/QMP/qmp-events.txt b/qemu-0.15.x/QMP/qmp-events.txt
new file mode 100644
index 0000000..0ce5d4e
--- /dev/null
+++ b/qemu-0.15.x/QMP/qmp-events.txt
@@ -0,0 +1,266 @@
+                   QEMU Monitor Protocol Events
+                   ============================
+
+BLOCK_IO_ERROR
+--------------
+
+Emitted when a disk I/O error occurs.
+
+Data:
+
+- "device": device name (json-string)
+- "operation": I/O operation (json-string, "read" or "write")
+- "action": action that has been taken, it's one of the following (json-string):
+    "ignore": error has been ignored
+    "report": error has been reported to the device
+    "stop": error caused VM to be stopped
+
+Example:
+
+{ "event": "BLOCK_IO_ERROR",
+    "data": { "device": "ide0-hd1",
+              "operation": "write",
+              "action": "stop" },
+    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+Note: If action is "stop", a STOP event will eventually follow the
+BLOCK_IO_ERROR event.
+
+RESET
+-----
+
+Emitted when the Virtual Machine is reseted.
+
+Data: None.
+
+Example:
+
+{ "event": "RESET",
+    "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
+
+RESUME
+------
+
+Emitted when the Virtual Machine resumes execution.
+
+Data: None.
+
+Example:
+
+{ "event": "RESUME",
+    "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
+
+RTC_CHANGE
+----------
+
+Emitted when the guest changes the RTC time.
+
+Data:
+
+- "offset": delta against the host UTC in seconds (json-number)
+
+Example:
+
+{ "event": "RTC_CHANGE",
+    "data": { "offset": 78 },
+    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
+SHUTDOWN
+--------
+
+Emitted when the Virtual Machine is powered down.
+
+Data: None.
+
+Example:
+
+{ "event": "SHUTDOWN",
+    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+
+Note: If the command-line option "-no-shutdown" has been specified, a STOP
+event will eventually follow the SHUTDOWN event.
+
+STOP
+----
+
+Emitted when the Virtual Machine is stopped.
+
+Data: None.
+
+Example:
+
+{ "event": "STOP",
+    "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
+
+VNC_CONNECTED
+-------------
+
+Emitted when a VNC client establishes a connection.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "event": "VNC_CONNECTED",
+    "data": {
+        "server": { "auth": "sasl", "family": "ipv4",
+                    "service": "5901", "host": "0.0.0.0" },
+        "client": { "family": "ipv4", "service": "58425",
+                    "host": "127.0.0.1" } },
+    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+
+
+Note: This event is emitted before any authentication takes place, thus
+the authentication ID is not provided.
+
+VNC_DISCONNECTED
+----------------
+
+Emitted when the conection is closed.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "x509_dname": TLS dname (json-string, optional)
+  - "sasl_username": SASL username (json-string, optional)
+
+Example:
+
+{ "event": "VNC_DISCONNECTED",
+    "data": {
+        "server": { "auth": "sasl", "family": "ipv4",
+                    "service": "5901", "host": "0.0.0.0" },
+        "client": { "family": "ipv4", "service": "58425",
+                    "host": "127.0.0.1", "sasl_username": "luiz" } },
+    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+
+VNC_INITIALIZED
+---------------
+
+Emitted after authentication takes place (if any) and the VNC session is
+made active.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "service": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "x509_dname": TLS dname (json-string, optional)
+  - "sasl_username": SASL username (json-string, optional)
+
+Example:
+
+{ "event": "VNC_INITIALIZED",
+    "data": {
+        "server": { "auth": "sasl", "family": "ipv4",
+                    "service": "5901", "host": "0.0.0.0"},
+        "client": { "family": "ipv4", "service": "46089",
+                    "host": "127.0.0.1", "sasl_username": "luiz" } },
+        "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
+
+SPICE_CONNECTED, SPICE_DISCONNECTED
+-----------------------------------
+
+Emitted when a SPICE client connects or disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+  "event": "SPICE_CONNECTED",
+  "data": {
+    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
+
+SPICE_INITIALIZED
+-----------------
+
+Emitted after initial handshake and authentication takes place (if any)
+and the SPICE channel is up'n'running
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "connection-id": spice connection id.  All channels with the same id
+                     belong to the same spice session (json-int)
+  - "channel-type": channel type.  "1" is the main control channel, filter for
+                    this one if you want track spice sessions only (json-int)
+  - "channel-id": channel id.  Usually "0", might be different needed when
+                  multiple channels of the same type exist, such as multiple
+                  display channels in a multihead setup (json-int)
+  - "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+  "event": "SPICE_INITIALIZED",
+  "data": {"server": {"auth": "spice", "port": "5921",
+                      "family": "ipv4", "host": "127.0.0.1"},
+           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+                      "connection-id": 1804289383, "host": "127.0.0.1",
+                      "channel-id": 0, "tls": true}
+}}
+
+
+WATCHDOG
+--------
+
+Emitted when the watchdog device's timer is expired.
+
+Data:
+
+- "action": Action that has been taken, it's one of the following (json-string):
+            "reset", "shutdown", "poweroff", "pause", "debug", or "none"
+
+Example:
+
+{ "event": "WATCHDOG",
+     "data": { "action": "reset" },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
+followed respectively by the RESET, SHUTDOWN, or STOP events.
diff --git a/qemu-0.15.x/QMP/qmp-shell b/qemu-0.15.x/QMP/qmp-shell
new file mode 100755
index 0000000..42dabc8
--- /dev/null
+++ b/qemu-0.15.x/QMP/qmp-shell
@@ -0,0 +1,259 @@
+#!/usr/bin/python
+#
+# Low-level QEMU shell on top of QMP.
+#
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+#  Luiz Capitulino <lcapitulino at redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# # qemu [...] -qmp unix:./qmp-sock,server
+#
+# Run the shell:
+#
+# $ qmp-shell ./qmp-sock
+#
+# Commands have the following format:
+#
+#    < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+#
+# For example:
+#
+# (QEMU) device_add driver=e1000 id=net1
+# {u'return': {}}
+# (QEMU)
+
+import qmp
+import readline
+import sys
+
+class QMPCompleter(list):
+    def complete(self, text, state):
+        for cmd in self:
+            if cmd.startswith(text):
+                if not state:
+                    return cmd
+                else:
+                    state -= 1
+
+class QMPShellError(Exception):
+    pass
+
+class QMPShellBadPort(QMPShellError):
+    pass
+
+# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
+#       _execute_cmd()). Let's design a better one.
+class QMPShell(qmp.QEMUMonitorProtocol):
+    def __init__(self, address):
+        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
+        self._greeting = None
+        self._completer = None
+
+    def __get_address(self, arg):
+        """
+        Figure out if the argument is in the port:host form, if it's not it's
+        probably a file path.
+        """
+        addr = arg.split(':')
+        if len(addr) == 2:
+            try:
+                port = int(addr[1])
+            except ValueError:
+                raise QMPShellBadPort
+            return ( addr[0], port )
+        # socket path
+        return arg
+
+    def _fill_completion(self):
+        for cmd in self.cmd('query-commands')['return']:
+            self._completer.append(cmd['name'])
+
+    def __completer_setup(self):
+        self._completer = QMPCompleter()
+        self._fill_completion()
+        readline.set_completer(self._completer.complete)
+        readline.parse_and_bind("tab: complete")
+        # XXX: default delimiters conflict with some command names (eg. query-),
+        # clearing everything as it doesn't seem to matter
+        readline.set_completer_delims('')
+
+    def __build_cmd(self, cmdline):
+        """
+        Build a QMP input object from a user provided command-line in the
+        following format:
+    
+            < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+        """
+        cmdargs = cmdline.split()
+        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+        for arg in cmdargs[1:]:
+            opt = arg.split('=')
+            try:
+                value = int(opt[1])
+            except ValueError:
+                value = opt[1]
+            qmpcmd['arguments'][opt[0]] = value
+        return qmpcmd
+
+    def _execute_cmd(self, cmdline):
+        try:
+            qmpcmd = self.__build_cmd(cmdline)
+        except:
+            print 'command format: <command-name> ',
+            print '[arg-name1=arg1] ... [arg-nameN=argN]'
+            return True
+        resp = self.cmd_obj(qmpcmd)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        print resp
+        return True
+
+    def connect(self):
+        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
+        self.__completer_setup()
+
+    def show_banner(self, msg='Welcome to the QMP low-level shell!'):
+        print msg
+        version = self._greeting['QMP']['version']['qemu']
+        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
+
+    def read_exec_command(self, prompt):
+        """
+        Read and execute a command.
+
+        @return True if execution was ok, return False if disconnected.
+        """
+        try:
+            cmdline = raw_input(prompt)
+        except EOFError:
+            print
+            return False
+        if cmdline == '':
+            for ev in self.get_events():
+                print ev
+            self.clear_events()
+            return True
+        else:
+            return self._execute_cmd(cmdline)
+
+class HMPShell(QMPShell):
+    def __init__(self, address):
+        QMPShell.__init__(self, address)
+        self.__cpu_index = 0
+
+    def __cmd_completion(self):
+        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
+            if cmd and cmd[0] != '[' and cmd[0] != '\t':
+                name = cmd.split()[0] # drop help text
+                if name == 'info':
+                    continue
+                if name.find('|') != -1:
+                    # Command in the form 'foobar|f' or 'f|foobar', take the
+                    # full name
+                    opt = name.split('|')
+                    if len(opt[0]) == 1:
+                        name = opt[1]
+                    else:
+                        name = opt[0]
+                self._completer.append(name)
+                self._completer.append('help ' + name) # help completion
+
+    def __info_completion(self):
+        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
+            if cmd:
+                self._completer.append('info ' + cmd.split()[1])
+
+    def __other_completion(self):
+        # special cases
+        self._completer.append('help info')
+
+    def _fill_completion(self):
+        self.__cmd_completion()
+        self.__info_completion()
+        self.__other_completion()
+
+    def __cmd_passthrough(self, cmdline, cpu_index = 0):
+        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
+                              { 'command-line': cmdline,
+                                'cpu-index': cpu_index } })
+
+    def _execute_cmd(self, cmdline):
+        if cmdline.split()[0] == "cpu":
+            # trap the cpu command, it requires special setting
+            try:
+                idx = int(cmdline.split()[1])
+                if not 'return' in self.__cmd_passthrough('info version', idx):
+                    print 'bad CPU index'
+                    return True
+                self.__cpu_index = idx
+            except ValueError:
+                print 'cpu command takes an integer argument'
+                return True
+        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        assert 'return' in resp or 'error' in resp
+        if 'return' in resp:
+            # Success
+            if len(resp['return']) > 0:
+                print resp['return'],
+        else:
+            # Error
+            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
+        return True
+
+    def show_banner(self):
+        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
+
+def die(msg):
+    sys.stderr.write('ERROR: %s\n' % msg)
+    sys.exit(1)
+
+def fail_cmdline(option=None):
+    if option:
+        sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
+    sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
+    sys.exit(1)
+
+def main():
+    addr = ''
+    try:
+        if len(sys.argv) == 2:
+            qemu = QMPShell(sys.argv[1])
+            addr = sys.argv[1]
+        elif len(sys.argv) == 3:
+            if sys.argv[1] != '-H':
+                fail_cmdline(sys.argv[1])
+            qemu = HMPShell(sys.argv[2])
+            addr = sys.argv[2]
+        else:
+                fail_cmdline()
+    except QMPShellBadPort:
+        die('bad port number in command-line')
+
+    try:
+        qemu.connect()
+    except qmp.QMPConnectError:
+        die('Didn\'t get QMP greeting message')
+    except qmp.QMPCapabilitiesError:
+        die('Could not negotiate capabilities')
+    except qemu.error:
+        die('Could not connect to %s' % addr)
+
+    qemu.show_banner()
+    while qemu.read_exec_command('(QEMU) '):
+        pass
+    qemu.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/QMP/qmp-spec.txt b/qemu-0.15.x/QMP/qmp-spec.txt
new file mode 100644
index 0000000..9d30a8c
--- /dev/null
+++ b/qemu-0.15.x/QMP/qmp-spec.txt
@@ -0,0 +1,272 @@
+           QEMU Monitor Protocol Specification - Version 0.1
+
+1. Introduction
+===============
+
+This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
+which is available for applications to control QEMU at the machine-level.
+
+To enable QMP support, QEMU has to be run in "control mode". This is done by
+starting QEMU with the appropriate command-line options. Please, refer to the
+QEMU manual page for more information.
+
+2. Protocol Specification
+=========================
+
+This section details the protocol format. For the purpose of this document
+"Client" is any application which is communicating with QEMU in control mode,
+and "Server" is QEMU itself.
+
+JSON data structures, when mentioned in this document, are always in the
+following format:
+
+    json-DATA-STRUCTURE-NAME
+
+Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
+the JSON standard:
+
+http://www.ietf.org/rfc/rfc4627.txt
+
+For convenience, json-object members and json-array elements mentioned in
+this document will be in a certain order. However, in real protocol usage
+they can be in ANY order, thus no particular order should be assumed.
+
+2.1 General Definitions
+-----------------------
+
+2.1.1 All interactions transmitted by the Server are json-objects, always
+      terminating with CRLF
+
+2.1.2 All json-objects members are mandatory when not specified otherwise
+
+2.2 Server Greeting
+-------------------
+
+Right when connected the Server will issue a greeting message, which signals
+that the connection has been successfully established and that the Server is
+ready for capabilities negotiation (for more information refer to section
+'4. Capabilities Negotiation').
+
+The format is:
+
+{ "QMP": { "version": json-object, "capabilities": json-array } }
+
+ Where,
+
+- The "version" member contains the Server's version information (the format
+  is the same of the 'query-version' command)
+- The "capabilities" member specify the availability of features beyond the
+  baseline specification
+
+2.3 Issuing Commands
+--------------------
+
+The format for command execution is:
+
+{ "execute": json-string, "arguments": json-object, "id": json-value }
+
+ Where,
+
+- The "execute" member identifies the command to be executed by the Server
+- The "arguments" member is used to pass any arguments required for the
+  execution of the command, it is optional when no arguments are required
+- The "id" member is a transaction identification associated with the
+  command execution, it is optional and will be part of the response if
+  provided
+
+2.4 Commands Responses
+----------------------
+
+There are two possible responses which the Server will issue as the result
+of a command execution: success or error.
+
+2.4.1 success
+-------------
+
+The success response is issued when the command execution has finished
+without errors.
+
+The format is:
+
+{ "return": json-object, "id": json-value }
+
+ Where,
+
+- The "return" member contains the command returned data, which is defined
+  in a per-command basis or an empty json-object if the command does not
+  return data
+- The "id" member contains the transaction identification associated
+  with the command execution (if issued by the Client)
+
+2.4.2 error
+-----------
+
+The error response is issued when the command execution could not be
+completed because of an error condition.
+
+The format is:
+
+{ "error": { "class": json-string, "data": json-object, "desc": json-string },
+  "id": json-value }
+
+ Where,
+
+- The "class" member contains the error class name (eg. "ServiceUnavailable")
+- The "data" member contains specific error data and is defined in a
+  per-command basis, it will be an empty json-object if the error has no data
+- The "desc" member is a human-readable error message. Clients should
+  not attempt to parse this message.
+- The "id" member contains the transaction identification associated with
+  the command execution (if issued by the Client)
+
+NOTE: Some errors can occur before the Server is able to read the "id" member,
+in these cases the "id" member will not be part of the error response, even
+if provided by the client.
+
+2.5 Asynchronous events
+-----------------------
+
+As a result of state changes, the Server may send messages unilaterally
+to the Client at any time. They are called 'asynchronous events'.
+
+The format is:
+
+{ "event": json-string, "data": json-object,
+  "timestamp": { "seconds": json-number, "microseconds": json-number } }
+
+ Where,
+
+- The "event" member contains the event's name
+- The "data" member contains event specific data, which is defined in a
+  per-event basis, it is optional
+- The "timestamp" member contains the exact time of when the event occurred
+  in the Server. It is a fixed json-object with time in seconds and
+  microseconds
+
+For a listing of supported asynchronous events, please, refer to the
+qmp-events.txt file.
+
+3. QMP Examples
+===============
+
+This section provides some examples of real QMP usage, in all of them
+'C' stands for 'Client' and 'S' stands for 'Server'.
+
+3.1 Server greeting
+-------------------
+
+S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
+
+3.2 Simple 'stop' execution
+---------------------------
+
+C: { "execute": "stop" }
+S: {"return": {}}
+
+3.3 KVM information
+-------------------
+
+C: { "execute": "query-kvm", "id": "example" }
+S: {"return": {"enabled": true, "present": true}, "id": "example"}
+
+3.4 Parsing error
+------------------
+
+C: { "execute": }
+S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
+{}}}
+
+3.5 Powerdown event
+-------------------
+
+S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
+"POWERDOWN"}
+
+4. Capabilities Negotiation
+----------------------------
+
+When a Client successfully establishes a connection, the Server is in
+Capabilities Negotiation mode.
+
+In this mode only the 'qmp_capabilities' command is allowed to run, all
+other commands will return the CommandNotFound error. Asynchronous messages
+are not delivered either.
+
+Clients should use the 'qmp_capabilities' command to enable capabilities
+advertised in the Server's greeting (section '2.2 Server Greeting') they
+support.
+
+When the 'qmp_capabilities' command is issued, and if it does not return an
+error, the Server enters in Command mode where capabilities changes take
+effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
+messages are delivered.
+
+5 Compatibility Considerations
+------------------------------
+
+All protocol changes or new features which modify the protocol format in an
+incompatible way are disabled by default and will be advertised by the
+capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
+that array and enable the capabilities they support.
+
+Additionally, Clients must not assume any particular:
+
+- Size of json-objects or length of json-arrays
+- Order of json-object members or json-array elements
+- Amount of errors generated by a command, that is, new errors can be added
+  to any existing command in newer versions of the Server
+
+6. Downstream extension of QMP
+------------------------------
+
+We recommend that downstream consumers of QEMU do *not* modify QMP.
+Management tools should be able to support both upstream and downstream
+versions of QMP without special logic, and downstream extensions are
+inherently at odds with that.
+
+However, we recognize that it is sometimes impossible for downstreams to
+avoid modifying QMP.  Both upstream and downstream need to take care to
+preserve long-term compatibility and interoperability.
+
+To help with that, QMP reserves JSON object member names beginning with
+'__' (double underscore) for downstream use ("downstream names").  This
+means upstream will never use any downstream names for its commands,
+arguments, errors, asynchronous events, and so forth.
+
+Any new names downstream wishes to add must begin with '__'.  To
+ensure compatibility with other downstreams, it is strongly
+recommended that you prefix your downstram names with '__RFQDN_' where
+RFQDN is a valid, reverse fully qualified domain name which you
+control.  For example, a qemu-kvm specific monitor command would be:
+
+    (qemu) __org.linux-kvm_enable_irqchip
+
+Downstream must not change the server greeting (section 2.2) other than
+to offer additional capabilities.  But see below for why even that is
+discouraged.
+
+Section '5 Compatibility Considerations' applies to downstream as well
+as to upstream, obviously.  It follows that downstream must behave
+exactly like upstream for any input not containing members with
+downstream names ("downstream members"), except it may add members
+with downstream names to its output.
+
+Thus, a client should not be able to distinguish downstream from
+upstream as long as it doesn't send input with downstream members, and
+properly ignores any downstream members in the output it receives.
+
+Advice on downstream modifications:
+
+1. Introducing new commands is okay.  If you want to extend an existing
+   command, consider introducing a new one with the new behaviour
+   instead.
+
+2. Introducing new asynchronous messages is okay.  If you want to extend
+   an existing message, consider adding a new one instead.
+
+3. Introducing new errors for use in new commands is okay.  Adding new
+   errors to existing commands counts as extension, so 1. applies.
+
+4. New capabilities are strongly discouraged.  Capabilities are for
+   evolving the basic protocol, and multiple diverging basic protocol
+   dialects are most undesirable.
diff --git a/qemu-0.15.x/QMP/qmp.py b/qemu-0.15.x/QMP/qmp.py
new file mode 100644
index 0000000..c7dbea0
--- /dev/null
+++ b/qemu-0.15.x/QMP/qmp.py
@@ -0,0 +1,157 @@
+# QEMU Monitor Protocol Python class
+# 
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+#  Luiz Capitulino <lcapitulino at redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import json
+import errno
+import socket
+
+class QMPError(Exception):
+    pass
+
+class QMPConnectError(QMPError):
+    pass
+
+class QMPCapabilitiesError(QMPError):
+    pass
+
+class QEMUMonitorProtocol:
+    def __init__(self, address, server=False):
+        """
+        Create a QEMUMonitorProtocol class.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @param server: server mode listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
+        """
+        self.__events = []
+        self.__address = address
+        self.__sock = self.__get_sock()
+        if server:
+            self.__sock.bind(self.__address)
+            self.__sock.listen(1)
+
+    def __get_sock(self):
+        if isinstance(self.__address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def __negotiate_capabilities(self):
+        self.__sockfile = self.__sock.makefile()
+        greeting = self.__json_read()
+        if greeting is None or not greeting.has_key('QMP'):
+            raise QMPConnectError
+        # Greeting seems ok, negotiate capabilities
+        resp = self.cmd('qmp_capabilities')
+        if "return" in resp:
+            return greeting
+        raise QMPCapabilitiesError
+
+    def __json_read(self, only_event=False):
+        while True:
+            data = self.__sockfile.readline()
+            if not data:
+                return
+            resp = json.loads(data)
+            if 'event' in resp:
+                self.__events.append(resp)
+                if not only_event:
+                    continue
+            return resp
+
+    error = socket.error
+
+    def connect(self):
+        """
+        Connect to the QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock.connect(self.__address)
+        return self.__negotiate_capabilities()
+
+    def accept(self):
+        """
+        Await connection from QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock, _ = self.__sock.accept()
+        return self.__negotiate_capabilities()
+
+    def cmd_obj(self, qmp_cmd):
+        """
+        Send a QMP command to the QMP Monitor.
+
+        @param qmp_cmd: QMP command to be sent as a Python dict
+        @return QMP response as a Python dict or None if the connection has
+                been closed
+        """
+        try:
+            self.__sock.sendall(json.dumps(qmp_cmd))
+        except socket.error, err:
+            if err[0] == errno.EPIPE:
+                return
+            raise socket.error(err)
+        return self.__json_read()
+
+    def cmd(self, name, args=None, id=None):
+        """
+        Build a QMP command and send it to the QMP Monitor.
+
+        @param name: command name (string)
+        @param args: command arguments (dict)
+        @param id: command id (dict, list, string or int)
+        """
+        qmp_cmd = { 'execute': name }
+        if args:
+            qmp_cmd['arguments'] = args
+        if id:
+            qmp_cmd['id'] = id
+        return self.cmd_obj(qmp_cmd)
+
+    def get_events(self, wait=False):
+        """
+        Get a list of available QMP events.
+
+        @param wait: block until an event is available (bool)
+        """
+        self.__sock.setblocking(0)
+        try:
+            self.__json_read()
+        except socket.error, err:
+            if err[0] == errno.EAGAIN:
+                # No data available
+                pass
+        self.__sock.setblocking(1)
+        if not self.__events and wait:
+            self.__json_read(only_event=True)
+        return self.__events
+
+    def clear_events(self):
+        """
+        Clear current list of pending events.
+        """
+        self.__events = []
+
+    def close(self):
+        self.__sock.close()
+        self.__sockfile.close()
diff --git a/qemu-0.15.x/README b/qemu-0.15.x/README
new file mode 100644
index 0000000..dfd56f2
--- /dev/null
+++ b/qemu-0.15.x/README
@@ -0,0 +1,3 @@
+Read the documentation in qemu-doc.html.
+
+Fabrice Bellard.
diff --git a/qemu-0.15.x/TODO b/qemu-0.15.x/TODO
new file mode 100644
index 0000000..1d4c638
--- /dev/null
+++ b/qemu-0.15.x/TODO
@@ -0,0 +1,37 @@
+General:
+-------
+- cycle counter for all archs
+- cpu_interrupt() win32/SMP fix
+- merge PIC spurious interrupt patch
+- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
+- config file (at least for windows/Mac OS X)
+- update doc: PCI infos.
+- basic VGA optimizations
+- better code fetch
+- do not resize vga if invalid size.
+- TLB code protection support for PPC
+- disable SMC handling for ARM/SPARC/PPC (not finished)
+- see undefined flags for BTx insn
+- keyboard output buffer filling timing emulation
+- tests for each target CPU
+- fix all remaining thread lock issues (must put TBs in a specific invalid
+  state, find a solution for tb_flush()).
+
+ppc specific:
+------------
+- TLB invalidate not needed if msr_pr changes
+- enable shift optimizations ?
+
+linux-user specific:
+-------------------
+- remove threading support as it cannot work at this point
+- improve IPC syscalls
+- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
+  issues, fix 16 bit uid issues)
+- use kernel traps for unaligned accesses on ARM ?
+
+
+lower priority:
+--------------
+- int15 ah=86: use better timing
+- use -msoft-float on ARM
diff --git a/qemu-0.15.x/VERSION b/qemu-0.15.x/VERSION
new file mode 100644
index 0000000..e815b86
--- /dev/null
+++ b/qemu-0.15.x/VERSION
@@ -0,0 +1 @@
+0.15.1
diff --git a/qemu-0.15.x/a.out.h b/qemu-0.15.x/a.out.h
new file mode 100644
index 0000000..dfc104e
--- /dev/null
+++ b/qemu-0.15.x/a.out.h
@@ -0,0 +1,430 @@
+/* a.out.h
+
+   Copyright 1997, 1998, 1999, 2001 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _A_OUT_H_
+#define _A_OUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define COFF_IMAGE_WITH_PE
+#define COFF_LONG_SECTION_NAMES
+
+/*** coff information for Intel 386/486.  */
+
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+  short f_magic;	/* magic number			*/
+  short f_nscns;	/* number of sections		*/
+  host_ulong f_timdat;	/* time & date stamp		*/
+  host_ulong f_symptr;	/* file pointer to symtab	*/
+  host_ulong f_nsyms;	/* number of symtab entries	*/
+  short f_opthdr;	/* sizeof(optional hdr)		*/
+  short f_flags;	/* flags			*/
+};
+
+/* Bits for f_flags:
+ *	F_RELFLG	relocation info stripped from file
+ *	F_EXEC		file is executable (no unresolved external references)
+ *	F_LNNO		line numbers stripped from file
+ *	F_LSYMS		local symbols stripped from file
+ *	F_AR32WR	file has byte ordering of an AR32WR machine (e.g. vax)
+ */
+
+#define F_RELFLG	(0x0001)
+#define F_EXEC		(0x0002)
+#define F_LNNO		(0x0004)
+#define F_LSYMS		(0x0008)
+
+
+
+#define	I386MAGIC	0x14c
+#define I386PTXMAGIC	0x154
+#define I386AIXMAGIC	0x175
+
+/* This is Lynx's all-platform magic number for executables. */
+
+#define LYNXCOFFMAGIC	0415
+
+#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \
+		       && (x).f_magic != I386AIXMAGIC \
+		       && (x).f_magic != I386PTXMAGIC \
+		       && (x).f_magic != LYNXCOFFMAGIC)
+
+#define	FILHDR	struct external_filehdr
+#define	FILHSZ	20
+
+
+/********************** AOUT "OPTIONAL HEADER"=
+ **********************/
+
+
+typedef struct
+{
+  unsigned short magic;		/* type of file				*/
+  unsigned short vstamp;	/* version stamp			*/
+  host_ulong	tsize;		/* text size in bytes, padded to FW bdry*/
+  host_ulong	dsize;		/* initialized data "  "		*/
+  host_ulong	bsize;		/* uninitialized data "   "		*/
+  host_ulong	entry;		/* entry pt.				*/
+  host_ulong text_start;	/* base of text used for this file */
+  host_ulong data_start;	/* base of data used for this file=
+ */
+}
+AOUTHDR;
+
+#define AOUTSZ 28
+#define AOUTHDRSZ 28
+
+#define OMAGIC          0404    /* object files, eg as output */
+#define ZMAGIC          0413    /* demand load format, eg normal ld output */
+#define STMAGIC		0401	/* target shlib */
+#define SHMAGIC		0443	/* host   shlib */
+
+
+/* define some NT default values */
+/*  #define NT_IMAGE_BASE        0x400000 moved to internal.h */
+#define NT_SECTION_ALIGNMENT 0x1000
+#define NT_FILE_ALIGNMENT    0x200
+#define NT_DEF_RESERVE       0x100000
+#define NT_DEF_COMMIT        0x1000
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+  char		s_name[8];	/* section name			*/
+  host_ulong	s_paddr;	/* physical address, offset
+				   of last addr in scn */
+  host_ulong	s_vaddr;	/* virtual address		*/
+  host_ulong	s_size;		/* section size			*/
+  host_ulong	s_scnptr;	/* file ptr to raw data for section */
+  host_ulong	s_relptr;	/* file ptr to relocation	*/
+  host_ulong	s_lnnoptr;	/* file ptr to line numbers	*/
+  unsigned short s_nreloc;	/* number of relocation entries	*/
+  unsigned short s_nlnno;	/* number of line number entries*/
+  host_ulong	s_flags;	/* flags			*/
+};
+
+#define	SCNHDR	struct external_scnhdr
+#define	SCNHSZ	40
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT	".text"
+#define _DATA	".data"
+#define _BSS	".bss"
+#define _COMMENT ".comment"
+#define _LIB ".lib"
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+  union {
+    host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
+    host_ulong l_paddr;	/* (physical) address of line number	*/
+  } l_addr;
+  unsigned short l_lnno;	/* line number		*/
+};
+
+#define	LINENO	struct external_lineno
+#define	LINESZ	6
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN	8	/* # characters in a symbol name	*/
+#define E_FILNMLEN	14	/* # characters in a file name		*/
+#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
+
+struct __attribute__((packed)) external_syment
+{
+  union {
+    char e_name[E_SYMNMLEN];
+    struct {
+      host_ulong e_zeroes;
+      host_ulong e_offset;
+    } e;
+  } e;
+  host_ulong e_value;
+  unsigned short e_scnum;
+  unsigned short e_type;
+  char e_sclass[1];
+  char e_numaux[1];
+};
+
+#define N_BTMASK	(0xf)
+#define N_TMASK		(0x30)
+#define N_BTSHFT	(4)
+#define N_TSHIFT	(2)
+
+union external_auxent {
+  struct {
+    host_ulong x_tagndx;	/* str, un, or enum tag indx */
+    union {
+      struct {
+	unsigned short  x_lnno; /* declaration line number */
+	unsigned short  x_size; /* str/union/array size */
+      } x_lnsz;
+      host_ulong x_fsize;	/* size of function */
+    } x_misc;
+    union {
+      struct {			/* if ISFCN, tag, or .bb */
+	host_ulong x_lnnoptr;/* ptr to fcn line # */
+	host_ulong x_endndx;	/* entry ndx past block end */
+      } x_fcn;
+      struct {			/* if ISARY, up to 4 dimen. */
+	char x_dimen[E_DIMNUM][2];
+      } x_ary;
+    } x_fcnary;
+    unsigned short x_tvndx;	/* tv index */
+  } x_sym;
+
+  union {
+    char x_fname[E_FILNMLEN];
+    struct {
+      host_ulong x_zeroes;
+      host_ulong x_offset;
+    } x_n;
+  } x_file;
+
+  struct {
+    host_ulong x_scnlen;	/* section length */
+    unsigned short x_nreloc;	/* # relocation entries */
+    unsigned short x_nlinno;	/* # line numbers */
+    host_ulong x_checksum;	/* section COMDAT checksum */
+    unsigned short x_associated;/* COMDAT associated section index */
+    char x_comdat[1];		/* COMDAT selection number */
+  } x_scn;
+
+  struct {
+    host_ulong x_tvfill;	/* tv fill value */
+    unsigned short x_tvlen;	/* length of .tv */
+    char x_tvran[2][2];		/* tv range */
+  } x_tv;	/* info about .tv section (in auxent of symbol .tv)) */
+
+};
+
+#define	SYMENT	struct external_syment
+#define	SYMESZ	18
+#define	AUXENT	union external_auxent
+#define	AUXESZ	18
+
+#define _ETEXT	"etext"
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct external_reloc {
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_type[2];
+};
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+/* end of coff/i386.h */
+
+/* PE COFF header information */
+
+#ifndef _PE_H
+#define _PE_H
+
+/* NT specific file attributes */
+#define IMAGE_FILE_RELOCS_STRIPPED           0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008
+#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080
+#define IMAGE_FILE_32BIT_MACHINE             0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED            0x0200
+#define IMAGE_FILE_SYSTEM                    0x1000
+#define IMAGE_FILE_DLL                       0x2000
+#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000
+
+/* additional flags to be set for section headers to allow the NT loader to
+   read and write to the section data (to replace the addresses of data in
+   dlls for one thing); also to execute the section in .text's case=
+ */
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE     0x20000000
+#define IMAGE_SCN_MEM_READ        0x40000000
+#define IMAGE_SCN_MEM_WRITE       0x80000000
+
+/*
+ * Section characteristics added for ppc-nt
+ */
+
+#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  /* Reserved.  */
+
+#define IMAGE_SCN_CNT_CODE                   0x00000020  /* Section contains code. */
+#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  /* Section contains initialized data. */
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  /* Section contains uninitialized data. */
+
+#define IMAGE_SCN_LNK_OTHER                  0x00000100  /* Reserved.  */
+#define IMAGE_SCN_LNK_INFO                   0x00000200  /* Section contains comments or some other type of information. */
+#define IMAGE_SCN_LNK_REMOVE                 0x00000800  /* Section contents will not become part of image. */
+#define IMAGE_SCN_LNK_COMDAT                 0x00001000  /* Section contents comdat. */
+
+#define IMAGE_SCN_MEM_FARDATA                0x00008000
+
+#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
+#define IMAGE_SCN_MEM_16BIT                  0x00020000
+#define IMAGE_SCN_MEM_LOCKED                 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD                0x00080000
+
+#define IMAGE_SCN_ALIGN_1BYTES               0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES               0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES               0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES               0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  /* Default alignment if no others are specified. */
+#define IMAGE_SCN_ALIGN_32BYTES              0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES              0x00700000
+
+
+#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  /* Section contains extended relocations. */
+#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  /* Section is not cachable.               */
+#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  /* Section is not pageable.               */
+#define IMAGE_SCN_MEM_SHARED                 0x10000000  /* Section is shareable.                  */
+
+/* COMDAT selection codes.  */
+
+#define IMAGE_COMDAT_SELECT_NODUPLICATES     (1) /* Warn if duplicates.  */
+#define IMAGE_COMDAT_SELECT_ANY		     (2) /* No warning.  */
+#define IMAGE_COMDAT_SELECT_SAME_SIZE	     (3) /* Warn if different size.  */
+#define IMAGE_COMDAT_SELECT_EXACT_MATCH	     (4) /* Warn if different.  */
+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE	     (5) /* Base on other section.  */
+
+/* Magic values that are true for all dos/nt implementations */
+#define DOSMAGIC       0x5a4d
+#define NT_SIGNATURE   0x00004550
+
+/* NT allows long filenames, we want to accommodate this.  This may break
+     some of the bfd functions */
+#undef  FILNMLEN
+#define FILNMLEN	18	/* # characters in a file name		*/
+
+
+#ifdef COFF_IMAGE_WITH_PE
+/* The filehdr is only weired in images */
+
+#undef FILHDR
+struct external_PE_filehdr
+{
+  /* DOS header fields */
+  unsigned short e_magic;	/* Magic number, 0x5a4d */
+  unsigned short e_cblp;	/* Bytes on last page of file, 0x90 */
+  unsigned short e_cp;		/* Pages in file, 0x3 */
+  unsigned short e_crlc;	/* Relocations, 0x0 */
+  unsigned short e_cparhdr;	/* Size of header in paragraphs, 0x4 */
+  unsigned short e_minalloc;	/* Minimum extra paragraphs needed, 0x0 */
+  unsigned short e_maxalloc;	/* Maximum extra paragraphs needed, 0xFFFF */
+  unsigned short e_ss;		/* Initial (relative) SS value, 0x0 */
+  unsigned short e_sp;		/* Initial SP value, 0xb8 */
+  unsigned short e_csum;	/* Checksum, 0x0 */
+  unsigned short e_ip;		/* Initial IP value, 0x0 */
+  unsigned short e_cs;		/* Initial (relative) CS value, 0x0 */
+  unsigned short e_lfarlc;	/* File address of relocation table, 0x40 */
+  unsigned short e_ovno;	/* Overlay number, 0x0 */
+  char e_res[4][2];		/* Reserved words, all 0x0 */
+  unsigned short e_oemid;	/* OEM identifier (for e_oeminfo), 0x0 */
+  unsigned short e_oeminfo;	/* OEM information; e_oemid specific, 0x0 */
+  char e_res2[10][2];		/* Reserved words, all 0x0 */
+  host_ulong e_lfanew;	/* File address of new exe header, 0x80 */
+  char dos_message[16][4];	/* other stuff, always follow DOS header */
+  unsigned int nt_signature;	/* required NT signature, 0x4550 */
+
+  /* From standard header */
+
+  unsigned short f_magic;	/* magic number			*/
+  unsigned short f_nscns;	/* number of sections		*/
+  host_ulong f_timdat;	/* time & date stamp		*/
+  host_ulong f_symptr;	/* file pointer to symtab	*/
+  host_ulong f_nsyms;	/* number of symtab entries	*/
+  unsigned short f_opthdr;	/* sizeof(optional hdr)		*/
+  unsigned short f_flags;	/* flags			*/
+};
+
+
+#define FILHDR struct external_PE_filehdr
+#undef FILHSZ
+#define FILHSZ 152
+
+#endif
+
+typedef struct
+{
+  unsigned short magic;		/* type of file				*/
+  unsigned short vstamp;	/* version stamp			*/
+  host_ulong	tsize;		/* text size in bytes, padded to FW bdry*/
+  host_ulong	dsize;		/* initialized data "  "		*/
+  host_ulong	bsize;		/* uninitialized data "   "		*/
+  host_ulong	entry;		/* entry pt.				*/
+  host_ulong text_start;	/* base of text used for this file */
+  host_ulong data_start;	/* base of all data used for this file */
+
+  /* NT extra fields; see internal.h for descriptions */
+  host_ulong  ImageBase;
+  host_ulong  SectionAlignment;
+  host_ulong  FileAlignment;
+  unsigned short  MajorOperatingSystemVersion;
+  unsigned short  MinorOperatingSystemVersion;
+  unsigned short  MajorImageVersion;
+  unsigned short  MinorImageVersion;
+  unsigned short  MajorSubsystemVersion;
+  unsigned short  MinorSubsystemVersion;
+  char  Reserved1[4];
+  host_ulong  SizeOfImage;
+  host_ulong  SizeOfHeaders;
+  host_ulong  CheckSum;
+  unsigned short Subsystem;
+  unsigned short DllCharacteristics;
+  host_ulong  SizeOfStackReserve;
+  host_ulong  SizeOfStackCommit;
+  host_ulong  SizeOfHeapReserve;
+  host_ulong  SizeOfHeapCommit;
+  host_ulong  LoaderFlags;
+  host_ulong  NumberOfRvaAndSizes;
+  /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
+  char  DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
+
+} PEAOUTHDR;
+
+
+#undef AOUTSZ
+#define AOUTSZ (AOUTHDRSZ + 196)
+
+#undef  E_FILNMLEN
+#define E_FILNMLEN	18	/* # characters in a file name		*/
+#endif
+
+/* end of coff/pe.h */
+
+#define DT_NON		(0)	/* no derived type */
+#define DT_PTR		(1)	/* pointer */
+#define DT_FCN		(2)	/* function */
+#define DT_ARY		(3)	/* array */
+
+#define ISPTR(x)	(((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+#define ISFCN(x)	(((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+#define ISARY(x)	(((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _A_OUT_H_ */
diff --git a/qemu-0.15.x/acl.c b/qemu-0.15.x/acl.c
new file mode 100644
index 0000000..82c2704
--- /dev/null
+++ b/qemu-0.15.x/acl.c
@@ -0,0 +1,184 @@
+/*
+ * QEMU access control list management
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "qemu-common.h"
+#include "acl.h"
+
+#ifdef CONFIG_FNMATCH
+#include <fnmatch.h>
+#endif
+
+
+static unsigned int nacls = 0;
+static qemu_acl **acls = NULL;
+
+
+
+qemu_acl *qemu_acl_find(const char *aclname)
+{
+    int i;
+    for (i = 0 ; i < nacls ; i++) {
+        if (strcmp(acls[i]->aclname, aclname) == 0)
+            return acls[i];
+    }
+
+    return NULL;
+}
+
+qemu_acl *qemu_acl_init(const char *aclname)
+{
+    qemu_acl *acl;
+
+    acl = qemu_acl_find(aclname);
+    if (acl)
+        return acl;
+
+    acl = qemu_malloc(sizeof(*acl));
+    acl->aclname = qemu_strdup(aclname);
+    /* Deny by default, so there is no window of "open
+     * access" between QEMU starting, and the user setting
+     * up ACLs in the monitor */
+    acl->defaultDeny = 1;
+
+    acl->nentries = 0;
+    QTAILQ_INIT(&acl->entries);
+
+    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
+    acls[nacls] = acl;
+    nacls++;
+
+    return acl;
+}
+
+int qemu_acl_party_is_allowed(qemu_acl *acl,
+                              const char *party)
+{
+    qemu_acl_entry *entry;
+
+    QTAILQ_FOREACH(entry, &acl->entries, next) {
+#ifdef CONFIG_FNMATCH
+        if (fnmatch(entry->match, party, 0) == 0)
+            return entry->deny ? 0 : 1;
+#else
+        /* No fnmatch, so fallback to exact string matching
+         * instead of allowing wildcards */
+        if (strcmp(entry->match, party) == 0)
+            return entry->deny ? 0 : 1;
+#endif
+    }
+
+    return acl->defaultDeny ? 0 : 1;
+}
+
+
+void qemu_acl_reset(qemu_acl *acl)
+{
+    qemu_acl_entry *entry;
+
+    /* Put back to deny by default, so there is no window
+     * of "open access" while the user re-initializes the
+     * access control list */
+    acl->defaultDeny = 1;
+    QTAILQ_FOREACH(entry, &acl->entries, next) {
+        QTAILQ_REMOVE(&acl->entries, entry, next);
+        free(entry->match);
+        free(entry);
+    }
+    acl->nentries = 0;
+}
+
+
+int qemu_acl_append(qemu_acl *acl,
+                    int deny,
+                    const char *match)
+{
+    qemu_acl_entry *entry;
+
+    entry = qemu_malloc(sizeof(*entry));
+    entry->match = qemu_strdup(match);
+    entry->deny = deny;
+
+    QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
+    acl->nentries++;
+
+    return acl->nentries;
+}
+
+
+int qemu_acl_insert(qemu_acl *acl,
+                    int deny,
+                    const char *match,
+                    int index)
+{
+    qemu_acl_entry *entry;
+    qemu_acl_entry *tmp;
+    int i = 0;
+
+    if (index <= 0)
+        return -1;
+    if (index >= acl->nentries)
+        return qemu_acl_append(acl, deny, match);
+
+
+    entry = qemu_malloc(sizeof(*entry));
+    entry->match = qemu_strdup(match);
+    entry->deny = deny;
+
+    QTAILQ_FOREACH(tmp, &acl->entries, next) {
+        i++;
+        if (i == index) {
+            QTAILQ_INSERT_BEFORE(tmp, entry, next);
+            acl->nentries++;
+            break;
+        }
+    }
+
+    return i;
+}
+
+int qemu_acl_remove(qemu_acl *acl,
+                    const char *match)
+{
+    qemu_acl_entry *entry;
+    int i = 0;
+
+    QTAILQ_FOREACH(entry, &acl->entries, next) {
+        i++;
+        if (strcmp(entry->match, match) == 0) {
+            QTAILQ_REMOVE(&acl->entries, entry, next);
+            return i;
+        }
+    }
+    return -1;
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/acl.h b/qemu-0.15.x/acl.h
new file mode 100644
index 0000000..0ef7804
--- /dev/null
+++ b/qemu-0.15.x/acl.h
@@ -0,0 +1,74 @@
+/*
+ * QEMU access control list management
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 __QEMU_ACL_H__
+#define __QEMU_ACL_H__
+
+#include "qemu-queue.h"
+
+typedef struct qemu_acl_entry qemu_acl_entry;
+typedef struct qemu_acl qemu_acl;
+
+struct qemu_acl_entry {
+    char *match;
+    int deny;
+
+    QTAILQ_ENTRY(qemu_acl_entry) next;
+};
+
+struct qemu_acl {
+    char *aclname;
+    unsigned int nentries;
+    QTAILQ_HEAD(,qemu_acl_entry) entries;
+    int defaultDeny;
+};
+
+qemu_acl *qemu_acl_init(const char *aclname);
+
+qemu_acl *qemu_acl_find(const char *aclname);
+
+int qemu_acl_party_is_allowed(qemu_acl *acl,
+			      const char *party);
+
+void qemu_acl_reset(qemu_acl *acl);
+
+int qemu_acl_append(qemu_acl *acl,
+		    int deny,
+		    const char *match);
+int qemu_acl_insert(qemu_acl *acl,
+		    int deny,
+		    const char *match,
+		    int index);
+int qemu_acl_remove(qemu_acl *acl,
+		    const char *match);
+
+#endif /* __QEMU_ACL_H__ */
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/aes.c b/qemu-0.15.x/aes.c
new file mode 100644
index 0000000..eb37adb
--- /dev/null
+++ b/qemu-0.15.x/aes.c
@@ -0,0 +1,1314 @@
+/**
+ *
+ * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
+ */
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen at esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers at esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto at terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
+ */
+#include "qemu-common.h"
+#include "aes.h"
+
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+/* This controls loop-unrolling in aes_core.c */
+#undef FULL_UNROLL
+# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ */
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+			AES_KEY *key) {
+
+	u32 *rk;
+   	int i = 0;
+	u32 temp;
+
+	if (!userKey || !key)
+		return -1;
+	if (bits != 128 && bits != 192 && bits != 256)
+		return -2;
+
+	rk = key->rd_key;
+
+	if (bits==128)
+		key->rounds = 10;
+	else if (bits==192)
+		key->rounds = 12;
+	else
+		key->rounds = 14;
+
+	rk[0] = GETU32(userKey     );
+	rk[1] = GETU32(userKey +  4);
+	rk[2] = GETU32(userKey +  8);
+	rk[3] = GETU32(userKey + 12);
+	if (bits == 128) {
+		while (1) {
+			temp  = rk[3];
+			rk[4] = rk[0] ^
+				(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+				(Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+				(Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+				(Te4[(temp >> 24)       ] & 0x000000ff) ^
+				rcon[i];
+			rk[5] = rk[1] ^ rk[4];
+			rk[6] = rk[2] ^ rk[5];
+			rk[7] = rk[3] ^ rk[6];
+			if (++i == 10) {
+				return 0;
+			}
+			rk += 4;
+		}
+	}
+	rk[4] = GETU32(userKey + 16);
+	rk[5] = GETU32(userKey + 20);
+	if (bits == 192) {
+		while (1) {
+			temp = rk[ 5];
+			rk[ 6] = rk[ 0] ^
+				(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+				(Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+				(Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+				(Te4[(temp >> 24)       ] & 0x000000ff) ^
+				rcon[i];
+			rk[ 7] = rk[ 1] ^ rk[ 6];
+			rk[ 8] = rk[ 2] ^ rk[ 7];
+			rk[ 9] = rk[ 3] ^ rk[ 8];
+			if (++i == 8) {
+				return 0;
+			}
+			rk[10] = rk[ 4] ^ rk[ 9];
+			rk[11] = rk[ 5] ^ rk[10];
+			rk += 6;
+		}
+	}
+	rk[6] = GETU32(userKey + 24);
+	rk[7] = GETU32(userKey + 28);
+	if (bits == 256) {
+		while (1) {
+			temp = rk[ 7];
+			rk[ 8] = rk[ 0] ^
+				(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+				(Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+				(Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+				(Te4[(temp >> 24)       ] & 0x000000ff) ^
+				rcon[i];
+			rk[ 9] = rk[ 1] ^ rk[ 8];
+			rk[10] = rk[ 2] ^ rk[ 9];
+			rk[11] = rk[ 3] ^ rk[10];
+			if (++i == 7) {
+				return 0;
+			}
+			temp = rk[11];
+			rk[12] = rk[ 4] ^
+				(Te4[(temp >> 24)       ] & 0xff000000) ^
+				(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+				(Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
+				(Te4[(temp      ) & 0xff] & 0x000000ff);
+			rk[13] = rk[ 5] ^ rk[12];
+			rk[14] = rk[ 6] ^ rk[13];
+			rk[15] = rk[ 7] ^ rk[14];
+
+			rk += 8;
+        	}
+	}
+	return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ */
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+			 AES_KEY *key) {
+
+        u32 *rk;
+	int i, j, status;
+	u32 temp;
+
+	/* first, start with an encryption schedule */
+	status = AES_set_encrypt_key(userKey, bits, key);
+	if (status < 0)
+		return status;
+
+	rk = key->rd_key;
+
+	/* invert the order of the round keys: */
+	for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
+		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+	}
+	/* apply the inverse MixColumn transform to all round keys but the first and the last: */
+	for (i = 1; i < (key->rounds); i++) {
+		rk += 4;
+		rk[0] =
+			Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
+			Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+			Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
+			Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
+		rk[1] =
+			Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
+			Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+			Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
+			Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
+		rk[2] =
+			Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
+			Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+			Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
+			Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
+		rk[3] =
+			Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
+			Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+			Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
+			Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
+	}
+	return 0;
+}
+
+#ifndef AES_ASM
+/*
+ * Encrypt a single block
+ * in and out can overlap
+ */
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+		 const AES_KEY *key) {
+
+	const u32 *rk;
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	assert(in && out && key);
+	rk = key->rd_key;
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(in     ) ^ rk[0];
+	s1 = GETU32(in +  4) ^ rk[1];
+	s2 = GETU32(in +  8) ^ rk[2];
+	s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+	/* round 1: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+   	/* round 2: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+	/* round 3: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+   	/* round 4: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+	/* round 5: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+   	/* round 6: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+	/* round 7: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+   	/* round 8: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+	/* round 9: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    if (key->rounds > 10) {
+        /* round 10: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+        if (key->rounds > 12) {
+            /* round 12: */
+            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+        }
+    }
+    rk += key->rounds << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = key->rounds >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 =
+		(Te4[(t0 >> 24)       ] & 0xff000000) ^
+		(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t3      ) & 0xff] & 0x000000ff) ^
+		rk[0];
+	PUTU32(out     , s0);
+	s1 =
+		(Te4[(t1 >> 24)       ] & 0xff000000) ^
+		(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t0      ) & 0xff] & 0x000000ff) ^
+		rk[1];
+	PUTU32(out +  4, s1);
+	s2 =
+		(Te4[(t2 >> 24)       ] & 0xff000000) ^
+		(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t1      ) & 0xff] & 0x000000ff) ^
+		rk[2];
+	PUTU32(out +  8, s2);
+	s3 =
+		(Te4[(t3 >> 24)       ] & 0xff000000) ^
+		(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t2      ) & 0xff] & 0x000000ff) ^
+		rk[3];
+	PUTU32(out + 12, s3);
+}
+
+/*
+ * Decrypt a single block
+ * in and out can overlap
+ */
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+		 const AES_KEY *key) {
+
+	const u32 *rk;
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	assert(in && out && key);
+	rk = key->rd_key;
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+    s0 = GETU32(in     ) ^ rk[0];
+    s1 = GETU32(in +  4) ^ rk[1];
+    s2 = GETU32(in +  8) ^ rk[2];
+    s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+    if (key->rounds > 10) {
+        /* round 10: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+        if (key->rounds > 12) {
+            /* round 12: */
+            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+        }
+    }
+	rk += key->rounds << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = key->rounds >> 1;
+    for (;;) {
+        t0 =
+            Td0[(s0 >> 24)       ] ^
+            Td1[(s3 >> 16) & 0xff] ^
+            Td2[(s2 >>  8) & 0xff] ^
+            Td3[(s1      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Td0[(s1 >> 24)       ] ^
+            Td1[(s0 >> 16) & 0xff] ^
+            Td2[(s3 >>  8) & 0xff] ^
+            Td3[(s2      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Td0[(s2 >> 24)       ] ^
+            Td1[(s1 >> 16) & 0xff] ^
+            Td2[(s0 >>  8) & 0xff] ^
+            Td3[(s3      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Td0[(s3 >> 24)       ] ^
+            Td1[(s2 >> 16) & 0xff] ^
+            Td2[(s1 >>  8) & 0xff] ^
+            Td3[(s0      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td0[(t0 >> 24)       ] ^
+            Td1[(t3 >> 16) & 0xff] ^
+            Td2[(t2 >>  8) & 0xff] ^
+            Td3[(t1      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Td0[(t1 >> 24)       ] ^
+            Td1[(t0 >> 16) & 0xff] ^
+            Td2[(t3 >>  8) & 0xff] ^
+            Td3[(t2      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Td0[(t2 >> 24)       ] ^
+            Td1[(t1 >> 16) & 0xff] ^
+            Td2[(t0 >>  8) & 0xff] ^
+            Td3[(t3      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Td0[(t3 >> 24)       ] ^
+            Td1[(t2 >> 16) & 0xff] ^
+            Td2[(t1 >>  8) & 0xff] ^
+            Td3[(t0      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+   	s0 =
+   		(Td4[(t0 >> 24)       ] & 0xff000000) ^
+   		(Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+   		(Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+   		(Td4[(t1      ) & 0xff] & 0x000000ff) ^
+   		rk[0];
+	PUTU32(out     , s0);
+   	s1 =
+   		(Td4[(t1 >> 24)       ] & 0xff000000) ^
+   		(Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+   		(Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+   		(Td4[(t2      ) & 0xff] & 0x000000ff) ^
+   		rk[1];
+	PUTU32(out +  4, s1);
+   	s2 =
+   		(Td4[(t2 >> 24)       ] & 0xff000000) ^
+   		(Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+   		(Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+   		(Td4[(t3      ) & 0xff] & 0x000000ff) ^
+   		rk[2];
+	PUTU32(out +  8, s2);
+   	s3 =
+   		(Td4[(t3 >> 24)       ] & 0xff000000) ^
+   		(Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+   		(Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+   		(Td4[(t0      ) & 0xff] & 0x000000ff) ^
+   		rk[3];
+	PUTU32(out + 12, s3);
+}
+
+#endif /* AES_ASM */
+
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+		     const unsigned long length, const AES_KEY *key,
+		     unsigned char *ivec, const int enc)
+{
+
+	unsigned long n;
+	unsigned long len = length;
+	unsigned char tmp[AES_BLOCK_SIZE];
+
+	assert(in && out && key && ivec);
+
+	if (enc) {
+		while (len >= AES_BLOCK_SIZE) {
+			for(n=0; n < AES_BLOCK_SIZE; ++n)
+				tmp[n] = in[n] ^ ivec[n];
+			AES_encrypt(tmp, out, key);
+			memcpy(ivec, out, AES_BLOCK_SIZE);
+			len -= AES_BLOCK_SIZE;
+			in += AES_BLOCK_SIZE;
+			out += AES_BLOCK_SIZE;
+		}
+		if (len) {
+			for(n=0; n < len; ++n)
+				tmp[n] = in[n] ^ ivec[n];
+			for(n=len; n < AES_BLOCK_SIZE; ++n)
+				tmp[n] = ivec[n];
+			AES_encrypt(tmp, tmp, key);
+			memcpy(out, tmp, AES_BLOCK_SIZE);
+			memcpy(ivec, tmp, AES_BLOCK_SIZE);
+		}
+	} else {
+		while (len >= AES_BLOCK_SIZE) {
+			memcpy(tmp, in, AES_BLOCK_SIZE);
+			AES_decrypt(in, out, key);
+			for(n=0; n < AES_BLOCK_SIZE; ++n)
+				out[n] ^= ivec[n];
+			memcpy(ivec, tmp, AES_BLOCK_SIZE);
+			len -= AES_BLOCK_SIZE;
+			in += AES_BLOCK_SIZE;
+			out += AES_BLOCK_SIZE;
+		}
+		if (len) {
+			memcpy(tmp, in, AES_BLOCK_SIZE);
+			AES_decrypt(tmp, tmp, key);
+			for(n=0; n < len; ++n)
+				out[n] = tmp[n] ^ ivec[n];
+			memcpy(ivec, tmp, AES_BLOCK_SIZE);
+		}
+	}
+}
diff --git a/qemu-0.15.x/aes.h b/qemu-0.15.x/aes.h
new file mode 100644
index 0000000..a0167eb
--- /dev/null
+++ b/qemu-0.15.x/aes.h
@@ -0,0 +1,26 @@
+#ifndef QEMU_AES_H
+#define QEMU_AES_H
+
+#define AES_MAXNR 14
+#define AES_BLOCK_SIZE 16
+
+struct aes_key_st {
+    uint32_t rd_key[4 *(AES_MAXNR + 1)];
+    int rounds;
+};
+typedef struct aes_key_st AES_KEY;
+
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+	AES_KEY *key);
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+	AES_KEY *key);
+
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+	const AES_KEY *key);
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+	const AES_KEY *key);
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+		     const unsigned long length, const AES_KEY *key,
+		     unsigned char *ivec, const int enc);
+
+#endif
diff --git a/qemu-0.15.x/aio.c b/qemu-0.15.x/aio.c
new file mode 100644
index 0000000..2f08655
--- /dev/null
+++ b/qemu-0.15.x/aio.c
@@ -0,0 +1,230 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "block.h"
+#include "qemu-queue.h"
+#include "qemu_socket.h"
+
+typedef struct AioHandler AioHandler;
+
+/* The list of registered AIO handlers */
+static QLIST_HEAD(, AioHandler) aio_handlers;
+
+/* This is a simple lock used to protect the aio_handlers list.  Specifically,
+ * it's used to ensure that no callbacks are removed while we're walking and
+ * dispatching callbacks.
+ */
+static int walking_handlers;
+
+struct AioHandler
+{
+    int fd;
+    IOHandler *io_read;
+    IOHandler *io_write;
+    AioFlushHandler *io_flush;
+    AioProcessQueue *io_process_queue;
+    int deleted;
+    void *opaque;
+    QLIST_ENTRY(AioHandler) node;
+};
+
+static AioHandler *find_aio_handler(int fd)
+{
+    AioHandler *node;
+
+    QLIST_FOREACH(node, &aio_handlers, node) {
+        if (node->fd == fd)
+            if (!node->deleted)
+                return node;
+    }
+
+    return NULL;
+}
+
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            AioProcessQueue *io_process_queue,
+                            void *opaque)
+{
+    AioHandler *node;
+
+    node = find_aio_handler(fd);
+
+    /* Are we deleting the fd handler? */
+    if (!io_read && !io_write) {
+        if (node) {
+            /* If the lock is held, just mark the node as deleted */
+            if (walking_handlers)
+                node->deleted = 1;
+            else {
+                /* Otherwise, delete it for real.  We can't just mark it as
+                 * deleted because deleted nodes are only cleaned up after
+                 * releasing the walking_handlers lock.
+                 */
+                QLIST_REMOVE(node, node);
+                qemu_free(node);
+            }
+        }
+    } else {
+        if (node == NULL) {
+            /* Alloc and insert if it's not already there */
+            node = qemu_mallocz(sizeof(AioHandler));
+            node->fd = fd;
+            QLIST_INSERT_HEAD(&aio_handlers, node, node);
+        }
+        /* Update handler with latest information */
+        node->io_read = io_read;
+        node->io_write = io_write;
+        node->io_flush = io_flush;
+        node->io_process_queue = io_process_queue;
+        node->opaque = opaque;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
+
+    return 0;
+}
+
+void qemu_aio_flush(void)
+{
+    AioHandler *node;
+    int ret;
+
+    do {
+        ret = 0;
+
+	/*
+	 * If there are pending emulated aio start them now so flush
+	 * will be able to return 1.
+	 */
+        qemu_aio_wait();
+
+        QLIST_FOREACH(node, &aio_handlers, node) {
+            if (node->io_flush) {
+                ret |= node->io_flush(node->opaque);
+            }
+        }
+    } while (qemu_bh_poll() || ret > 0);
+}
+
+int qemu_aio_process_queue(void)
+{
+    AioHandler *node;
+    int ret = 0;
+
+    walking_handlers = 1;
+
+    QLIST_FOREACH(node, &aio_handlers, node) {
+        if (node->io_process_queue) {
+            if (node->io_process_queue(node->opaque)) {
+                ret = 1;
+            }
+        }
+    }
+
+    walking_handlers = 0;
+
+    return ret;
+}
+
+void qemu_aio_wait(void)
+{
+    int ret;
+
+    if (qemu_bh_poll())
+        return;
+
+    /*
+     * If there are callbacks left that have been queued, we need to call then.
+     * Return afterwards to avoid waiting needlessly in select().
+     */
+    if (qemu_aio_process_queue())
+        return;
+
+    do {
+        AioHandler *node;
+        fd_set rdfds, wrfds;
+        int max_fd = -1;
+
+        walking_handlers = 1;
+
+        FD_ZERO(&rdfds);
+        FD_ZERO(&wrfds);
+
+        /* fill fd sets */
+        QLIST_FOREACH(node, &aio_handlers, node) {
+            /* If there aren't pending AIO operations, don't invoke callbacks.
+             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+             * wait indefinitely.
+             */
+            if (node->io_flush && node->io_flush(node->opaque) == 0)
+                continue;
+
+            if (!node->deleted && node->io_read) {
+                FD_SET(node->fd, &rdfds);
+                max_fd = MAX(max_fd, node->fd + 1);
+            }
+            if (!node->deleted && node->io_write) {
+                FD_SET(node->fd, &wrfds);
+                max_fd = MAX(max_fd, node->fd + 1);
+            }
+        }
+
+        walking_handlers = 0;
+
+        /* No AIO operations?  Get us out of here */
+        if (max_fd == -1)
+            break;
+
+        /* wait until next event */
+        ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+        if (ret == -1 && errno == EINTR)
+            continue;
+
+        /* if we have any readable fds, dispatch event */
+        if (ret > 0) {
+            walking_handlers = 1;
+
+            /* we have to walk very carefully in case
+             * qemu_aio_set_fd_handler is called while we're walking */
+            node = QLIST_FIRST(&aio_handlers);
+            while (node) {
+                AioHandler *tmp;
+
+                if (!node->deleted &&
+                    FD_ISSET(node->fd, &rdfds) &&
+                    node->io_read) {
+                    node->io_read(node->opaque);
+                }
+                if (!node->deleted &&
+                    FD_ISSET(node->fd, &wrfds) &&
+                    node->io_write) {
+                    node->io_write(node->opaque);
+                }
+
+                tmp = node;
+                node = QLIST_NEXT(node, node);
+
+                if (tmp->deleted) {
+                    QLIST_REMOVE(tmp, node);
+                    qemu_free(tmp);
+                }
+            }
+
+            walking_handlers = 0;
+        }
+    } while (ret == 0);
+}
diff --git a/qemu-0.15.x/alpha-dis.c b/qemu-0.15.x/alpha-dis.c
new file mode 100644
index 0000000..ae331b3
--- /dev/null
+++ b/qemu-0.15.x/alpha-dis.c
@@ -0,0 +1,1916 @@
+/* alpha-dis.c -- Disassemble Alpha AXP instructions
+   Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Richard Henderson <rth at tamu.edu>,
+   patterned after the PPC opcode handling written by Ian Lance Taylor.
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+will be useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this file; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include "dis-asm.h"
+
+/* MAX is redefined below, so remove any previous definition. */
+#undef MAX
+
+/* The opcode table is an array of struct alpha_opcode.  */
+
+struct alpha_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+
+  /* The opcode itself.  Those bits which will be filled in with
+     operands are zeroes.  */
+  unsigned opcode;
+
+  /* The opcode mask.  This is used by the disassembler.  This is a
+     mask containing ones indicating those bits which must match the
+     opcode field, and zeroes indicating those bits which need not
+     match (and are presumably filled in by operands).  */
+  unsigned mask;
+
+  /* One bit flags for the opcode.  These are primarily used to
+     indicate specific processors and environments support the
+     instructions.  The defined values are listed below. */
+  unsigned flags;
+
+  /* An array of operand codes.  Each code is an index into the
+     operand table.  They appear in the order which the operands must
+     appear in assembly code, and are terminated by a zero.  */
+  unsigned char operands[4];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct alpha_opcode alpha_opcodes[];
+extern const unsigned alpha_num_opcodes;
+
+/* Values defined for the flags field of a struct alpha_opcode.  */
+
+/* CPU Availability */
+#define AXP_OPCODE_BASE  0x0001  /* Base architecture -- all cpus.  */
+#define AXP_OPCODE_EV4   0x0002  /* EV4 specific PALcode insns.  */
+#define AXP_OPCODE_EV5   0x0004  /* EV5 specific PALcode insns.  */
+#define AXP_OPCODE_EV6   0x0008  /* EV6 specific PALcode insns.  */
+#define AXP_OPCODE_BWX   0x0100  /* Byte/word extension (amask bit 0).  */
+#define AXP_OPCODE_CIX   0x0200  /* "Count" extension (amask bit 1).  */
+#define AXP_OPCODE_MAX   0x0400  /* Multimedia extension (amask bit 8).  */
+
+#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6))
+
+/* A macro to extract the major opcode from an instruction.  */
+#define AXP_OP(i)	(((i) >> 26) & 0x3F)
+
+/* The total number of major opcodes. */
+#define AXP_NOPS	0x40
+
+
+/* The operands table is an array of struct alpha_operand.  */
+
+struct alpha_operand
+{
+  /* The number of bits in the operand.  */
+  unsigned int bits : 5;
+
+  /* How far the operand is left shifted in the instruction.  */
+  unsigned int shift : 5;
+
+  /* The default relocation type for this operand.  */
+  signed int default_reloc : 16;
+
+  /* One bit syntax flags.  */
+  unsigned int flags : 16;
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+         i |= (op & ((1 << o->bits) - 1)) << o->shift;
+     (i is the instruction which we are filling in, o is a pointer to
+     this structure, and op is the opcode value; this assumes twos
+     complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will return the new value
+     of the instruction.  If the ERRMSG argument is not NULL, then if
+     the operand value is illegal, *ERRMSG will be set to a warning
+     string (the operand will be inserted in any case).  If the
+     operand value is legal, *ERRMSG will be unchanged (most operands
+     can accept any value).  */
+  unsigned (*insert) (unsigned instruction, int op,
+                      const char **errmsg);
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+         op = ((i) >> o->shift) & ((1 << o->bits) - 1);
+	 if ((o->flags & AXP_OPERAND_SIGNED) != 0
+	     && (op & (1 << (o->bits - 1))) != 0)
+	   op -= 1 << o->bits;
+     (i is the instruction, o is a pointer to this structure, and op
+     is the result; this assumes twos complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.  */
+  int (*extract) (unsigned instruction, int *invalid);
+};
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the alpha_opcodes table.  */
+
+extern const struct alpha_operand alpha_operands[];
+extern const unsigned alpha_num_operands;
+
+/* Values defined for the flags field of a struct alpha_operand.  */
+
+/* Mask for selecting the type for typecheck purposes */
+#define AXP_OPERAND_TYPECHECK_MASK					\
+  (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR |		\
+   AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | 	\
+   AXP_OPERAND_UNSIGNED)
+
+/* This operand does not actually exist in the assembler input.  This
+   is used to support extended mnemonics, for which two operands fields
+   are identical.  The assembler should call the insert function with
+   any op value.  The disassembler should call the extract function,
+   ignore the return value, and check the value placed in the invalid
+   argument.  */
+#define AXP_OPERAND_FAKE	01
+
+/* The operand should be wrapped in parentheses rather than separated
+   from the previous by a comma.  This is used for the load and store
+   instructions which want their operands to look like "Ra,disp(Rb)".  */
+#define AXP_OPERAND_PARENS	02
+
+/* Used in combination with PARENS, this suppresses the suppression of
+   the comma.  This is used for "jmp Ra,(Rb),hint".  */
+#define AXP_OPERAND_COMMA	04
+
+/* This operand names an integer register.  */
+#define AXP_OPERAND_IR		010
+
+/* This operand names a floating point register.  */
+#define AXP_OPERAND_FPR		020
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define AXP_OPERAND_RELATIVE	040
+
+/* This operand takes signed values.  */
+#define AXP_OPERAND_SIGNED	0100
+
+/* This operand takes unsigned values.  This exists primarily so that
+   a flags value of 0 can be treated as end-of-arguments.  */
+#define AXP_OPERAND_UNSIGNED	0200
+
+/* Suppress overflow detection on this field.  This is used for hints. */
+#define AXP_OPERAND_NOOVERFLOW	0400
+
+/* Mask for optional argument default value.  */
+#define AXP_OPERAND_OPTIONAL_MASK 07000
+
+/* This operand defaults to zero.  This is used for jump hints.  */
+#define AXP_OPERAND_DEFAULT_ZERO 01000
+
+/* This operand should default to the first (real) operand and is used
+   in conjunction with AXP_OPERAND_OPTIONAL.  This allows
+   "and $0,3,$0" to be written as "and $0,3", etc.  I don't like
+   it, but it's what DEC does.  */
+#define AXP_OPERAND_DEFAULT_FIRST 02000
+
+/* Similarly, this operand should default to the second (real) operand.
+   This allows "negl $0" instead of "negl $0,$0".  */
+#define AXP_OPERAND_DEFAULT_SECOND 04000
+
+
+/* Register common names */
+
+#define AXP_REG_V0	0
+#define AXP_REG_T0	1
+#define AXP_REG_T1	2
+#define AXP_REG_T2	3
+#define AXP_REG_T3	4
+#define AXP_REG_T4	5
+#define AXP_REG_T5	6
+#define AXP_REG_T6	7
+#define AXP_REG_T7	8
+#define AXP_REG_S0	9
+#define AXP_REG_S1	10
+#define AXP_REG_S2	11
+#define AXP_REG_S3	12
+#define AXP_REG_S4	13
+#define AXP_REG_S5	14
+#define AXP_REG_FP	15
+#define AXP_REG_A0	16
+#define AXP_REG_A1	17
+#define AXP_REG_A2	18
+#define AXP_REG_A3	19
+#define AXP_REG_A4	20
+#define AXP_REG_A5	21
+#define AXP_REG_T8	22
+#define AXP_REG_T9	23
+#define AXP_REG_T10	24
+#define AXP_REG_T11	25
+#define AXP_REG_RA	26
+#define AXP_REG_PV	27
+#define AXP_REG_T12	27
+#define AXP_REG_AT	28
+#define AXP_REG_GP	29
+#define AXP_REG_SP	30
+#define AXP_REG_ZERO	31
+
+enum bfd_reloc_code_real {
+    BFD_RELOC_23_PCREL_S2,
+    BFD_RELOC_ALPHA_HINT
+};
+
+/* This file holds the Alpha AXP opcode table.  The opcode table includes
+   almost all of the extended instruction mnemonics.  This permits the
+   disassembler to use them, and simplifies the assembler logic, at the
+   cost of increasing the table size.  The table is strictly constant
+   data, so the compiler should be able to put it in the text segment.
+
+   This file also holds the operand table.  All knowledge about inserting
+   and extracting operands from instructions is kept in this file.
+
+   The information for the base instruction set was compiled from the
+   _Alpha Architecture Handbook_, Digital Order Number EC-QD2KB-TE,
+   version 2.
+
+   The information for the post-ev5 architecture extensions BWX, CIX and
+   MAX came from version 3 of this same document, which is also available
+   on-line at http://ftp.digital.com/pub/Digital/info/semiconductor
+   /literature/alphahb2.pdf
+
+   The information for the EV4 PALcode instructions was compiled from
+   _DECchip 21064 and DECchip 21064A Alpha AXP Microprocessors Hardware
+   Reference Manual_, Digital Order Number EC-Q9ZUA-TE, preliminary
+   revision dated June 1994.
+
+   The information for the EV5 PALcode instructions was compiled from
+   _Alpha 21164 Microprocessor Hardware Reference Manual_, Digital
+   Order Number EC-QAEQB-TE, preliminary revision dated April 1995.  */
+
+/* Local insertion and extraction functions */
+
+static unsigned insert_rba (unsigned, int, const char **);
+static unsigned insert_rca (unsigned, int, const char **);
+static unsigned insert_za (unsigned, int, const char **);
+static unsigned insert_zb (unsigned, int, const char **);
+static unsigned insert_zc (unsigned, int, const char **);
+static unsigned insert_bdisp (unsigned, int, const char **);
+static unsigned insert_jhint (unsigned, int, const char **);
+static unsigned insert_ev6hwjhint (unsigned, int, const char **);
+
+static int extract_rba (unsigned, int *);
+static int extract_rca (unsigned, int *);
+static int extract_za (unsigned, int *);
+static int extract_zb (unsigned, int *);
+static int extract_zc (unsigned, int *);
+static int extract_bdisp (unsigned, int *);
+static int extract_jhint (unsigned, int *);
+static int extract_ev6hwjhint (unsigned, int *);
+
+
+/* The operands table  */
+
+const struct alpha_operand alpha_operands[] =
+{
+  /* The fields are bits, shift, insert, extract, flags */
+  /* The zero index is used to indicate end-of-list */
+#define UNUSED		0
+  { 0, 0, 0, 0, 0, 0 },
+
+  /* The plain integer register fields */
+#define RA		(UNUSED + 1)
+  { 5, 21, 0, AXP_OPERAND_IR, 0, 0 },
+#define RB		(RA + 1)
+  { 5, 16, 0, AXP_OPERAND_IR, 0, 0 },
+#define RC		(RB + 1)
+  { 5, 0, 0, AXP_OPERAND_IR, 0, 0 },
+
+  /* The plain fp register fields */
+#define FA		(RC + 1)
+  { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 },
+#define FB		(FA + 1)
+  { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 },
+#define FC		(FB + 1)
+  { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 },
+
+  /* The integer registers when they are ZERO */
+#define ZA		(FC + 1)
+  { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za },
+#define ZB		(ZA + 1)
+  { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb },
+#define ZC		(ZB + 1)
+  { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc },
+
+  /* The RB field when it needs parentheses */
+#define PRB		(ZC + 1)
+  { 5, 16, 0, AXP_OPERAND_IR|AXP_OPERAND_PARENS, 0, 0 },
+
+  /* The RB field when it needs parentheses _and_ a preceding comma */
+#define CPRB		(PRB + 1)
+  { 5, 16, 0,
+    AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA, 0, 0 },
+
+  /* The RB field when it must be the same as the RA field */
+#define RBA		(CPRB + 1)
+  { 5, 16, 0, AXP_OPERAND_FAKE, insert_rba, extract_rba },
+
+  /* The RC field when it must be the same as the RB field */
+#define RCA		(RBA + 1)
+  { 5, 0, 0, AXP_OPERAND_FAKE, insert_rca, extract_rca },
+
+  /* The RC field when it can *default* to RA */
+#define DRC1		(RCA + 1)
+  { 5, 0, 0,
+    AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
+
+  /* The RC field when it can *default* to RB */
+#define DRC2		(DRC1 + 1)
+  { 5, 0, 0,
+    AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
+
+  /* The FC field when it can *default* to RA */
+#define DFC1		(DRC2 + 1)
+  { 5, 0, 0,
+    AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
+
+  /* The FC field when it can *default* to RB */
+#define DFC2		(DFC1 + 1)
+  { 5, 0, 0,
+    AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
+
+  /* The unsigned 8-bit literal of Operate format insns */
+#define LIT		(DFC2 + 1)
+  { 8, 13, -LIT, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The signed 16-bit displacement of Memory format insns.  From here
+     we can't tell what relocation should be used, so don't use a default. */
+#define MDISP		(LIT + 1)
+  { 16, 0, -MDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+  /* The signed "23-bit" aligned displacement of Branch format insns */
+#define BDISP		(MDISP + 1)
+  { 21, 0, BFD_RELOC_23_PCREL_S2,
+    AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
+
+  /* The 26-bit PALcode function */
+#define PALFN		(BDISP + 1)
+  { 26, 0, -PALFN, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint */
+#define JMPHINT		(PALFN + 1)
+  { 14, 0, BFD_RELOC_ALPHA_HINT,
+    AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
+    insert_jhint, extract_jhint },
+
+  /* The optional hint to RET/JSR_COROUTINE */
+#define RETHINT		(JMPHINT + 1)
+  { 14, 0, -RETHINT,
+    AXP_OPERAND_UNSIGNED|AXP_OPERAND_DEFAULT_ZERO, 0, 0 },
+
+  /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns */
+#define EV4HWDISP	(RETHINT + 1)
+#define EV6HWDISP	(EV4HWDISP)
+  { 12, 0, -EV4HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+  /* The 5-bit index for the ev4 hw_m[ft]pr (pal19/pal1d) insns */
+#define EV4HWINDEX	(EV4HWDISP + 1)
+  { 5, 0, -EV4HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The 8-bit index for the oddly unqualified hw_m[tf]pr insns
+     that occur in DEC PALcode.  */
+#define EV4EXTHWINDEX	(EV4HWINDEX + 1)
+  { 8, 0, -EV4EXTHWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The 10-bit displacement for the ev5 hw_{ld,st} (pal1b/pal1f) insns */
+#define EV5HWDISP	(EV4EXTHWINDEX + 1)
+  { 10, 0, -EV5HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+  /* The 16-bit index for the ev5 hw_m[ft]pr (pal19/pal1d) insns */
+#define EV5HWINDEX	(EV5HWDISP + 1)
+  { 16, 0, -EV5HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The 16-bit combined index/scoreboard mask for the ev6
+     hw_m[ft]pr (pal19/pal1d) insns */
+#define EV6HWINDEX	(EV5HWINDEX + 1)
+  { 16, 0, -EV6HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+  /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn */
+#define EV6HWJMPHINT	(EV6HWINDEX+ 1)
+  { 8, 0, -EV6HWJMPHINT,
+    AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
+    insert_ev6hwjhint, extract_ev6hwjhint }
+};
+
+const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operands);
+
+/* The RB field when it is the same as the RA field in the same insn.
+   This operand is marked fake.  The insertion function just copies
+   the RA field into the RB field, and the extraction function just
+   checks that the fields are the same. */
+
+/*ARGSUSED*/
+static unsigned
+insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static int
+extract_rba(unsigned insn, int *invalid)
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+
+/* The same for the RC field */
+
+/*ARGSUSED*/
+static unsigned
+insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | ((insn >> 21) & 0x1f);
+}
+
+static int
+extract_rca(unsigned insn, int *invalid)
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != (insn & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+
+/* Fake arguments in which the registers must be set to ZERO */
+
+/*ARGSUSED*/
+static unsigned
+insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (31 << 21);
+}
+
+static int
+extract_za(unsigned insn, int *invalid)
+{
+  if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31)
+    *invalid = 1;
+  return 0;
+}
+
+/*ARGSUSED*/
+static unsigned
+insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (31 << 16);
+}
+
+static int
+extract_zb(unsigned insn, int *invalid)
+{
+  if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31)
+    *invalid = 1;
+  return 0;
+}
+
+/*ARGSUSED*/
+static unsigned
+insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | 31;
+}
+
+static int
+extract_zc(unsigned insn, int *invalid)
+{
+  if (invalid != (int *) NULL && (insn & 0x1f) != 31)
+    *invalid = 1;
+  return 0;
+}
+
+
+/* The displacement field of a Branch format insn.  */
+
+static unsigned
+insert_bdisp(unsigned insn, int value, const char **errmsg)
+{
+  if (errmsg != (const char **)NULL && (value & 3))
+    *errmsg = _("branch operand unaligned");
+  return insn | ((value / 4) & 0x1FFFFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
+{
+  return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000);
+}
+
+
+/* The hint field of a JMP/JSR insn.  */
+
+static unsigned
+insert_jhint(unsigned insn, int value, const char **errmsg)
+{
+  if (errmsg != (const char **)NULL && (value & 3))
+    *errmsg = _("jump hint unaligned");
+  return insn | ((value / 4) & 0x3FFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
+{
+  return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000);
+}
+
+/* The hint field of an EV6 HW_JMP/JSR insn.  */
+
+static unsigned
+insert_ev6hwjhint(unsigned insn, int value, const char **errmsg)
+{
+  if (errmsg != (const char **)NULL && (value & 3))
+    *errmsg = _("jump hint unaligned");
+  return insn | ((value / 4) & 0x1FFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
+{
+  return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000);
+}
+
+
+/* Macros used to form opcodes */
+
+/* The main opcode */
+#define OP(x)		(((x) & 0x3F) << 26)
+#define OP_MASK		0xFC000000
+
+/* Branch format instructions */
+#define BRA_(oo)	OP(oo)
+#define BRA_MASK	OP_MASK
+#define BRA(oo)		BRA_(oo), BRA_MASK
+
+/* Floating point format instructions */
+#define FP_(oo,fff)	(OP(oo) | (((fff) & 0x7FF) << 5))
+#define FP_MASK		(OP_MASK | 0xFFE0)
+#define FP(oo,fff)	FP_(oo,fff), FP_MASK
+
+/* Memory format instructions */
+#define MEM_(oo)	OP(oo)
+#define MEM_MASK	OP_MASK
+#define MEM(oo)		MEM_(oo), MEM_MASK
+
+/* Memory/Func Code format instructions */
+#define MFC_(oo,ffff)	(OP(oo) | ((ffff) & 0xFFFF))
+#define MFC_MASK	(OP_MASK | 0xFFFF)
+#define MFC(oo,ffff)	MFC_(oo,ffff), MFC_MASK
+
+/* Memory/Branch format instructions */
+#define MBR_(oo,h)	(OP(oo) | (((h) & 3) << 14))
+#define MBR_MASK	(OP_MASK | 0xC000)
+#define MBR(oo,h)	MBR_(oo,h), MBR_MASK
+
+/* Operate format instructions.  The OPRL variant specifies a
+   literal second argument. */
+#define OPR_(oo,ff)	(OP(oo) | (((ff) & 0x7F) << 5))
+#define OPRL_(oo,ff)	(OPR_((oo),(ff)) | 0x1000)
+#define OPR_MASK	(OP_MASK | 0x1FE0)
+#define OPR(oo,ff)	OPR_(oo,ff), OPR_MASK
+#define OPRL(oo,ff)	OPRL_(oo,ff), OPR_MASK
+
+/* Generic PALcode format instructions */
+#define PCD_(oo)	OP(oo)
+#define PCD_MASK	OP_MASK
+#define PCD(oo)		PCD_(oo), PCD_MASK
+
+/* Specific PALcode instructions */
+#define SPCD_(oo,ffff)	(OP(oo) | ((ffff) & 0x3FFFFFF))
+#define SPCD_MASK	0xFFFFFFFF
+#define SPCD(oo,ffff)	SPCD_(oo,ffff), SPCD_MASK
+
+/* Hardware memory (hw_{ld,st}) instructions */
+#define EV4HWMEM_(oo,f)	(OP(oo) | (((f) & 0xF) << 12))
+#define EV4HWMEM_MASK	(OP_MASK | 0xF000)
+#define EV4HWMEM(oo,f)	EV4HWMEM_(oo,f), EV4HWMEM_MASK
+
+#define EV5HWMEM_(oo,f)	(OP(oo) | (((f) & 0x3F) << 10))
+#define EV5HWMEM_MASK	(OP_MASK | 0xF800)
+#define EV5HWMEM(oo,f)	EV5HWMEM_(oo,f), EV5HWMEM_MASK
+
+#define EV6HWMEM_(oo,f)	(OP(oo) | (((f) & 0xF) << 12))
+#define EV6HWMEM_MASK	(OP_MASK | 0xF000)
+#define EV6HWMEM(oo,f)	EV6HWMEM_(oo,f), EV6HWMEM_MASK
+
+#define EV6HWMBR_(oo,h)	(OP(oo) | (((h) & 7) << 13))
+#define EV6HWMBR_MASK	(OP_MASK | 0xE000)
+#define EV6HWMBR(oo,h)	EV6HWMBR_(oo,h), EV6HWMBR_MASK
+
+/* Abbreviations for instruction subsets.  */
+#define BASE			AXP_OPCODE_BASE
+#define EV4			AXP_OPCODE_EV4
+#define EV5			AXP_OPCODE_EV5
+#define EV6			AXP_OPCODE_EV6
+#define BWX			AXP_OPCODE_BWX
+#define CIX			AXP_OPCODE_CIX
+#define MAX			AXP_OPCODE_MAX
+
+/* Common combinations of arguments */
+#define ARG_NONE		{ 0 }
+#define ARG_BRA			{ RA, BDISP }
+#define ARG_FBRA		{ FA, BDISP }
+#define ARG_FP			{ FA, FB, DFC1 }
+#define ARG_FPZ1		{ ZA, FB, DFC1 }
+#define ARG_MEM			{ RA, MDISP, PRB }
+#define ARG_FMEM		{ FA, MDISP, PRB }
+#define ARG_OPR			{ RA, RB, DRC1 }
+#define ARG_OPRL		{ RA, LIT, DRC1 }
+#define ARG_OPRZ1		{ ZA, RB, DRC1 }
+#define ARG_OPRLZ1		{ ZA, LIT, RC }
+#define ARG_PCD			{ PALFN }
+#define ARG_EV4HWMEM		{ RA, EV4HWDISP, PRB }
+#define ARG_EV4HWMPR		{ RA, RBA, EV4HWINDEX }
+#define ARG_EV5HWMEM		{ RA, EV5HWDISP, PRB }
+#define ARG_EV6HWMEM		{ RA, EV6HWDISP, PRB }
+
+/* The opcode table.
+
+   The format of the opcode table is:
+
+   NAME OPCODE MASK { OPERANDS }
+
+   NAME		is the name of the instruction.
+
+   OPCODE	is the instruction opcode.
+
+   MASK		is the opcode mask; this is used to tell the disassembler
+            	which bits in the actual opcode must match OPCODE.
+
+   OPERANDS	is the list of operands.
+
+   The preceding macros merge the text of the OPCODE and MASK fields.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches, so this table is sorted to put more
+   specific instructions before more general instructions.
+
+   Otherwise, it is sorted by major opcode and minor function code.
+
+   There are three classes of not-really-instructions in this table:
+
+   ALIAS	is another name for another instruction.  Some of
+		these come from the Architecture Handbook, some
+		come from the original gas opcode tables.  In all
+		cases, the functionality of the opcode is unchanged.
+
+   PSEUDO	a stylized code form endorsed by Chapter A.4 of the
+		Architecture Handbook.
+
+   EXTRA	a stylized code form found in the original gas tables.
+
+   And two annotations:
+
+   EV56 BUT	opcodes that are officially introduced as of the ev56,
+   		but with defined results on previous implementations.
+
+   EV56 UNA	opcodes that were introduced as of the ev56 with
+   		presumably undefined results on previous implementations
+		that were not assigned to a particular extension.
+*/
+
+const struct alpha_opcode alpha_opcodes[] = {
+  { "halt",		SPCD(0x00,0x0000), BASE, ARG_NONE },
+  { "draina",		SPCD(0x00,0x0002), BASE, ARG_NONE },
+  { "bpt",		SPCD(0x00,0x0080), BASE, ARG_NONE },
+  { "bugchk",		SPCD(0x00,0x0081), BASE, ARG_NONE },
+  { "callsys",		SPCD(0x00,0x0083), BASE, ARG_NONE },
+  { "chmk", 		SPCD(0x00,0x0083), BASE, ARG_NONE },
+  { "imb",		SPCD(0x00,0x0086), BASE, ARG_NONE },
+  { "rduniq",		SPCD(0x00,0x009e), BASE, ARG_NONE },
+  { "wruniq",		SPCD(0x00,0x009f), BASE, ARG_NONE },
+  { "gentrap",		SPCD(0x00,0x00aa), BASE, ARG_NONE },
+  { "call_pal",		PCD(0x00), BASE, ARG_PCD },
+  { "pal",		PCD(0x00), BASE, ARG_PCD },		/* alias */
+
+  { "lda",		MEM(0x08), BASE, { RA, MDISP, ZB } },	/* pseudo */
+  { "lda",		MEM(0x08), BASE, ARG_MEM },
+  { "ldah",		MEM(0x09), BASE, { RA, MDISP, ZB } },	/* pseudo */
+  { "ldah",		MEM(0x09), BASE, ARG_MEM },
+  { "ldbu",		MEM(0x0A), BWX, ARG_MEM },
+  { "unop",		MEM_(0x0B) | (30 << 16),
+			MEM_MASK, BASE, { ZA } },		/* pseudo */
+  { "ldq_u",		MEM(0x0B), BASE, ARG_MEM },
+  { "ldwu",		MEM(0x0C), BWX, ARG_MEM },
+  { "stw",		MEM(0x0D), BWX, ARG_MEM },
+  { "stb",		MEM(0x0E), BWX, ARG_MEM },
+  { "stq_u",		MEM(0x0F), BASE, ARG_MEM },
+
+  { "sextl",		OPR(0x10,0x00), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "sextl",		OPRL(0x10,0x00), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "addl",		OPR(0x10,0x00), BASE, ARG_OPR },
+  { "addl",		OPRL(0x10,0x00), BASE, ARG_OPRL },
+  { "s4addl",		OPR(0x10,0x02), BASE, ARG_OPR },
+  { "s4addl",		OPRL(0x10,0x02), BASE, ARG_OPRL },
+  { "negl",		OPR(0x10,0x09), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "negl",		OPRL(0x10,0x09), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "subl",		OPR(0x10,0x09), BASE, ARG_OPR },
+  { "subl",		OPRL(0x10,0x09), BASE, ARG_OPRL },
+  { "s4subl",		OPR(0x10,0x0B), BASE, ARG_OPR },
+  { "s4subl",		OPRL(0x10,0x0B), BASE, ARG_OPRL },
+  { "cmpbge",		OPR(0x10,0x0F), BASE, ARG_OPR },
+  { "cmpbge",		OPRL(0x10,0x0F), BASE, ARG_OPRL },
+  { "s8addl",		OPR(0x10,0x12), BASE, ARG_OPR },
+  { "s8addl",		OPRL(0x10,0x12), BASE, ARG_OPRL },
+  { "s8subl",		OPR(0x10,0x1B), BASE, ARG_OPR },
+  { "s8subl",		OPRL(0x10,0x1B), BASE, ARG_OPRL },
+  { "cmpult",		OPR(0x10,0x1D), BASE, ARG_OPR },
+  { "cmpult",		OPRL(0x10,0x1D), BASE, ARG_OPRL },
+  { "addq",		OPR(0x10,0x20), BASE, ARG_OPR },
+  { "addq",		OPRL(0x10,0x20), BASE, ARG_OPRL },
+  { "s4addq",		OPR(0x10,0x22), BASE, ARG_OPR },
+  { "s4addq",		OPRL(0x10,0x22), BASE, ARG_OPRL },
+  { "negq", 		OPR(0x10,0x29), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "negq", 		OPRL(0x10,0x29), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "subq",		OPR(0x10,0x29), BASE, ARG_OPR },
+  { "subq",		OPRL(0x10,0x29), BASE, ARG_OPRL },
+  { "s4subq",		OPR(0x10,0x2B), BASE, ARG_OPR },
+  { "s4subq",		OPRL(0x10,0x2B), BASE, ARG_OPRL },
+  { "cmpeq",		OPR(0x10,0x2D), BASE, ARG_OPR },
+  { "cmpeq",		OPRL(0x10,0x2D), BASE, ARG_OPRL },
+  { "s8addq",		OPR(0x10,0x32), BASE, ARG_OPR },
+  { "s8addq",		OPRL(0x10,0x32), BASE, ARG_OPRL },
+  { "s8subq",		OPR(0x10,0x3B), BASE, ARG_OPR },
+  { "s8subq",		OPRL(0x10,0x3B), BASE, ARG_OPRL },
+  { "cmpule",		OPR(0x10,0x3D), BASE, ARG_OPR },
+  { "cmpule",		OPRL(0x10,0x3D), BASE, ARG_OPRL },
+  { "addl/v",		OPR(0x10,0x40), BASE, ARG_OPR },
+  { "addl/v",		OPRL(0x10,0x40), BASE, ARG_OPRL },
+  { "negl/v",		OPR(0x10,0x49), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "negl/v",		OPRL(0x10,0x49), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "subl/v",		OPR(0x10,0x49), BASE, ARG_OPR },
+  { "subl/v",		OPRL(0x10,0x49), BASE, ARG_OPRL },
+  { "cmplt",		OPR(0x10,0x4D), BASE, ARG_OPR },
+  { "cmplt",		OPRL(0x10,0x4D), BASE, ARG_OPRL },
+  { "addq/v",		OPR(0x10,0x60), BASE, ARG_OPR },
+  { "addq/v",		OPRL(0x10,0x60), BASE, ARG_OPRL },
+  { "negq/v",		OPR(0x10,0x69), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "negq/v",		OPRL(0x10,0x69), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "subq/v",		OPR(0x10,0x69), BASE, ARG_OPR },
+  { "subq/v",		OPRL(0x10,0x69), BASE, ARG_OPRL },
+  { "cmple",		OPR(0x10,0x6D), BASE, ARG_OPR },
+  { "cmple",		OPRL(0x10,0x6D), BASE, ARG_OPRL },
+
+  { "and",		OPR(0x11,0x00), BASE, ARG_OPR },
+  { "and",		OPRL(0x11,0x00), BASE, ARG_OPRL },
+  { "andnot",		OPR(0x11,0x08), BASE, ARG_OPR },	/* alias */
+  { "andnot",		OPRL(0x11,0x08), BASE, ARG_OPRL },	/* alias */
+  { "bic",		OPR(0x11,0x08), BASE, ARG_OPR },
+  { "bic",		OPRL(0x11,0x08), BASE, ARG_OPRL },
+  { "cmovlbs",		OPR(0x11,0x14), BASE, ARG_OPR },
+  { "cmovlbs",		OPRL(0x11,0x14), BASE, ARG_OPRL },
+  { "cmovlbc",		OPR(0x11,0x16), BASE, ARG_OPR },
+  { "cmovlbc",		OPRL(0x11,0x16), BASE, ARG_OPRL },
+  { "nop",		OPR(0x11,0x20), BASE, { ZA, ZB, ZC } }, /* pseudo */
+  { "clr",		OPR(0x11,0x20), BASE, { ZA, ZB, RC } }, /* pseudo */
+  { "mov",		OPR(0x11,0x20), BASE, { ZA, RB, RC } }, /* pseudo */
+  { "mov",		OPR(0x11,0x20), BASE, { RA, RBA, RC } }, /* pseudo */
+  { "mov",		OPRL(0x11,0x20), BASE, { ZA, LIT, RC } }, /* pseudo */
+  { "or",		OPR(0x11,0x20), BASE, ARG_OPR },	/* alias */
+  { "or",		OPRL(0x11,0x20), BASE, ARG_OPRL },	/* alias */
+  { "bis",		OPR(0x11,0x20), BASE, ARG_OPR },
+  { "bis",		OPRL(0x11,0x20), BASE, ARG_OPRL },
+  { "cmoveq",		OPR(0x11,0x24), BASE, ARG_OPR },
+  { "cmoveq",		OPRL(0x11,0x24), BASE, ARG_OPRL },
+  { "cmovne",		OPR(0x11,0x26), BASE, ARG_OPR },
+  { "cmovne",		OPRL(0x11,0x26), BASE, ARG_OPRL },
+  { "not",		OPR(0x11,0x28), BASE, ARG_OPRZ1 },	/* pseudo */
+  { "not",		OPRL(0x11,0x28), BASE, ARG_OPRLZ1 },	/* pseudo */
+  { "ornot",		OPR(0x11,0x28), BASE, ARG_OPR },
+  { "ornot",		OPRL(0x11,0x28), BASE, ARG_OPRL },
+  { "xor",		OPR(0x11,0x40), BASE, ARG_OPR },
+  { "xor",		OPRL(0x11,0x40), BASE, ARG_OPRL },
+  { "cmovlt",		OPR(0x11,0x44), BASE, ARG_OPR },
+  { "cmovlt",		OPRL(0x11,0x44), BASE, ARG_OPRL },
+  { "cmovge",		OPR(0x11,0x46), BASE, ARG_OPR },
+  { "cmovge",		OPRL(0x11,0x46), BASE, ARG_OPRL },
+  { "eqv",		OPR(0x11,0x48), BASE, ARG_OPR },
+  { "eqv",		OPRL(0x11,0x48), BASE, ARG_OPRL },
+  { "xornot",		OPR(0x11,0x48), BASE, ARG_OPR },	/* alias */
+  { "xornot",		OPRL(0x11,0x48), BASE, ARG_OPRL },	/* alias */
+  { "amask",		OPR(0x11,0x61), BASE, ARG_OPRZ1 },	/* ev56 but */
+  { "amask",		OPRL(0x11,0x61), BASE, ARG_OPRLZ1 },	/* ev56 but */
+  { "cmovle",		OPR(0x11,0x64), BASE, ARG_OPR },
+  { "cmovle",		OPRL(0x11,0x64), BASE, ARG_OPRL },
+  { "cmovgt",		OPR(0x11,0x66), BASE, ARG_OPR },
+  { "cmovgt",		OPRL(0x11,0x66), BASE, ARG_OPRL },
+  { "implver",		OPRL_(0x11,0x6C)|(31<<21)|(1<<13),
+    			0xFFFFFFE0, BASE, { RC } },		/* ev56 but */
+
+  { "mskbl",		OPR(0x12,0x02), BASE, ARG_OPR },
+  { "mskbl",		OPRL(0x12,0x02), BASE, ARG_OPRL },
+  { "extbl",		OPR(0x12,0x06), BASE, ARG_OPR },
+  { "extbl",		OPRL(0x12,0x06), BASE, ARG_OPRL },
+  { "insbl",		OPR(0x12,0x0B), BASE, ARG_OPR },
+  { "insbl",		OPRL(0x12,0x0B), BASE, ARG_OPRL },
+  { "mskwl",		OPR(0x12,0x12), BASE, ARG_OPR },
+  { "mskwl",		OPRL(0x12,0x12), BASE, ARG_OPRL },
+  { "extwl",		OPR(0x12,0x16), BASE, ARG_OPR },
+  { "extwl",		OPRL(0x12,0x16), BASE, ARG_OPRL },
+  { "inswl",		OPR(0x12,0x1B), BASE, ARG_OPR },
+  { "inswl",		OPRL(0x12,0x1B), BASE, ARG_OPRL },
+  { "mskll",		OPR(0x12,0x22), BASE, ARG_OPR },
+  { "mskll",		OPRL(0x12,0x22), BASE, ARG_OPRL },
+  { "extll",		OPR(0x12,0x26), BASE, ARG_OPR },
+  { "extll",		OPRL(0x12,0x26), BASE, ARG_OPRL },
+  { "insll",		OPR(0x12,0x2B), BASE, ARG_OPR },
+  { "insll",		OPRL(0x12,0x2B), BASE, ARG_OPRL },
+  { "zap",		OPR(0x12,0x30), BASE, ARG_OPR },
+  { "zap",		OPRL(0x12,0x30), BASE, ARG_OPRL },
+  { "zapnot",		OPR(0x12,0x31), BASE, ARG_OPR },
+  { "zapnot",		OPRL(0x12,0x31), BASE, ARG_OPRL },
+  { "mskql",		OPR(0x12,0x32), BASE, ARG_OPR },
+  { "mskql",		OPRL(0x12,0x32), BASE, ARG_OPRL },
+  { "srl",		OPR(0x12,0x34), BASE, ARG_OPR },
+  { "srl",		OPRL(0x12,0x34), BASE, ARG_OPRL },
+  { "extql",		OPR(0x12,0x36), BASE, ARG_OPR },
+  { "extql",		OPRL(0x12,0x36), BASE, ARG_OPRL },
+  { "sll",		OPR(0x12,0x39), BASE, ARG_OPR },
+  { "sll",		OPRL(0x12,0x39), BASE, ARG_OPRL },
+  { "insql",		OPR(0x12,0x3B), BASE, ARG_OPR },
+  { "insql",		OPRL(0x12,0x3B), BASE, ARG_OPRL },
+  { "sra",		OPR(0x12,0x3C), BASE, ARG_OPR },
+  { "sra",		OPRL(0x12,0x3C), BASE, ARG_OPRL },
+  { "mskwh",		OPR(0x12,0x52), BASE, ARG_OPR },
+  { "mskwh",		OPRL(0x12,0x52), BASE, ARG_OPRL },
+  { "inswh",		OPR(0x12,0x57), BASE, ARG_OPR },
+  { "inswh",		OPRL(0x12,0x57), BASE, ARG_OPRL },
+  { "extwh",		OPR(0x12,0x5A), BASE, ARG_OPR },
+  { "extwh",		OPRL(0x12,0x5A), BASE, ARG_OPRL },
+  { "msklh",		OPR(0x12,0x62), BASE, ARG_OPR },
+  { "msklh",		OPRL(0x12,0x62), BASE, ARG_OPRL },
+  { "inslh",		OPR(0x12,0x67), BASE, ARG_OPR },
+  { "inslh",		OPRL(0x12,0x67), BASE, ARG_OPRL },
+  { "extlh",		OPR(0x12,0x6A), BASE, ARG_OPR },
+  { "extlh",		OPRL(0x12,0x6A), BASE, ARG_OPRL },
+  { "mskqh",		OPR(0x12,0x72), BASE, ARG_OPR },
+  { "mskqh",		OPRL(0x12,0x72), BASE, ARG_OPRL },
+  { "insqh",		OPR(0x12,0x77), BASE, ARG_OPR },
+  { "insqh",		OPRL(0x12,0x77), BASE, ARG_OPRL },
+  { "extqh",		OPR(0x12,0x7A), BASE, ARG_OPR },
+  { "extqh",		OPRL(0x12,0x7A), BASE, ARG_OPRL },
+
+  { "mull",		OPR(0x13,0x00), BASE, ARG_OPR },
+  { "mull",		OPRL(0x13,0x00), BASE, ARG_OPRL },
+  { "mulq",		OPR(0x13,0x20), BASE, ARG_OPR },
+  { "mulq",		OPRL(0x13,0x20), BASE, ARG_OPRL },
+  { "umulh",		OPR(0x13,0x30), BASE, ARG_OPR },
+  { "umulh",		OPRL(0x13,0x30), BASE, ARG_OPRL },
+  { "mull/v",		OPR(0x13,0x40), BASE, ARG_OPR },
+  { "mull/v",		OPRL(0x13,0x40), BASE, ARG_OPRL },
+  { "mulq/v",		OPR(0x13,0x60), BASE, ARG_OPR },
+  { "mulq/v",		OPRL(0x13,0x60), BASE, ARG_OPRL },
+
+  { "itofs",		FP(0x14,0x004), CIX, { RA, ZB, FC } },
+  { "sqrtf/c",		FP(0x14,0x00A), CIX, ARG_FPZ1 },
+  { "sqrts/c",		FP(0x14,0x00B), CIX, ARG_FPZ1 },
+  { "itoff",		FP(0x14,0x014), CIX, { RA, ZB, FC } },
+  { "itoft",		FP(0x14,0x024), CIX, { RA, ZB, FC } },
+  { "sqrtg/c",		FP(0x14,0x02A), CIX, ARG_FPZ1 },
+  { "sqrtt/c",		FP(0x14,0x02B), CIX, ARG_FPZ1 },
+  { "sqrts/m",		FP(0x14,0x04B), CIX, ARG_FPZ1 },
+  { "sqrtt/m",		FP(0x14,0x06B), CIX, ARG_FPZ1 },
+  { "sqrtf",		FP(0x14,0x08A), CIX, ARG_FPZ1 },
+  { "sqrts",		FP(0x14,0x08B), CIX, ARG_FPZ1 },
+  { "sqrtg",		FP(0x14,0x0AA), CIX, ARG_FPZ1 },
+  { "sqrtt",		FP(0x14,0x0AB), CIX, ARG_FPZ1 },
+  { "sqrts/d",		FP(0x14,0x0CB), CIX, ARG_FPZ1 },
+  { "sqrtt/d",		FP(0x14,0x0EB), CIX, ARG_FPZ1 },
+  { "sqrtf/uc",		FP(0x14,0x10A), CIX, ARG_FPZ1 },
+  { "sqrts/uc",		FP(0x14,0x10B), CIX, ARG_FPZ1 },
+  { "sqrtg/uc",		FP(0x14,0x12A), CIX, ARG_FPZ1 },
+  { "sqrtt/uc",		FP(0x14,0x12B), CIX, ARG_FPZ1 },
+  { "sqrts/um",		FP(0x14,0x14B), CIX, ARG_FPZ1 },
+  { "sqrtt/um",		FP(0x14,0x16B), CIX, ARG_FPZ1 },
+  { "sqrtf/u",		FP(0x14,0x18A), CIX, ARG_FPZ1 },
+  { "sqrts/u",		FP(0x14,0x18B), CIX, ARG_FPZ1 },
+  { "sqrtg/u",		FP(0x14,0x1AA), CIX, ARG_FPZ1 },
+  { "sqrtt/u",		FP(0x14,0x1AB), CIX, ARG_FPZ1 },
+  { "sqrts/ud",		FP(0x14,0x1CB), CIX, ARG_FPZ1 },
+  { "sqrtt/ud",		FP(0x14,0x1EB), CIX, ARG_FPZ1 },
+  { "sqrtf/sc",		FP(0x14,0x40A), CIX, ARG_FPZ1 },
+  { "sqrtg/sc",		FP(0x14,0x42A), CIX, ARG_FPZ1 },
+  { "sqrtf/s",		FP(0x14,0x48A), CIX, ARG_FPZ1 },
+  { "sqrtg/s",		FP(0x14,0x4AA), CIX, ARG_FPZ1 },
+  { "sqrtf/suc",	FP(0x14,0x50A), CIX, ARG_FPZ1 },
+  { "sqrts/suc",	FP(0x14,0x50B), CIX, ARG_FPZ1 },
+  { "sqrtg/suc",	FP(0x14,0x52A), CIX, ARG_FPZ1 },
+  { "sqrtt/suc",	FP(0x14,0x52B), CIX, ARG_FPZ1 },
+  { "sqrts/sum",	FP(0x14,0x54B), CIX, ARG_FPZ1 },
+  { "sqrtt/sum",	FP(0x14,0x56B), CIX, ARG_FPZ1 },
+  { "sqrtf/su",		FP(0x14,0x58A), CIX, ARG_FPZ1 },
+  { "sqrts/su",		FP(0x14,0x58B), CIX, ARG_FPZ1 },
+  { "sqrtg/su",		FP(0x14,0x5AA), CIX, ARG_FPZ1 },
+  { "sqrtt/su",		FP(0x14,0x5AB), CIX, ARG_FPZ1 },
+  { "sqrts/sud",	FP(0x14,0x5CB), CIX, ARG_FPZ1 },
+  { "sqrtt/sud",	FP(0x14,0x5EB), CIX, ARG_FPZ1 },
+  { "sqrts/suic",	FP(0x14,0x70B), CIX, ARG_FPZ1 },
+  { "sqrtt/suic",	FP(0x14,0x72B), CIX, ARG_FPZ1 },
+  { "sqrts/suim",	FP(0x14,0x74B), CIX, ARG_FPZ1 },
+  { "sqrtt/suim",	FP(0x14,0x76B), CIX, ARG_FPZ1 },
+  { "sqrts/sui",	FP(0x14,0x78B), CIX, ARG_FPZ1 },
+  { "sqrtt/sui",	FP(0x14,0x7AB), CIX, ARG_FPZ1 },
+  { "sqrts/suid",	FP(0x14,0x7CB), CIX, ARG_FPZ1 },
+  { "sqrtt/suid",	FP(0x14,0x7EB), CIX, ARG_FPZ1 },
+
+  { "addf/c",		FP(0x15,0x000), BASE, ARG_FP },
+  { "subf/c",		FP(0x15,0x001), BASE, ARG_FP },
+  { "mulf/c",		FP(0x15,0x002), BASE, ARG_FP },
+  { "divf/c",		FP(0x15,0x003), BASE, ARG_FP },
+  { "cvtdg/c",		FP(0x15,0x01E), BASE, ARG_FPZ1 },
+  { "addg/c",		FP(0x15,0x020), BASE, ARG_FP },
+  { "subg/c",		FP(0x15,0x021), BASE, ARG_FP },
+  { "mulg/c",		FP(0x15,0x022), BASE, ARG_FP },
+  { "divg/c",		FP(0x15,0x023), BASE, ARG_FP },
+  { "cvtgf/c",		FP(0x15,0x02C), BASE, ARG_FPZ1 },
+  { "cvtgd/c",		FP(0x15,0x02D), BASE, ARG_FPZ1 },
+  { "cvtgq/c",		FP(0x15,0x02F), BASE, ARG_FPZ1 },
+  { "cvtqf/c",		FP(0x15,0x03C), BASE, ARG_FPZ1 },
+  { "cvtqg/c",		FP(0x15,0x03E), BASE, ARG_FPZ1 },
+  { "addf",		FP(0x15,0x080), BASE, ARG_FP },
+  { "negf",		FP(0x15,0x081), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subf",		FP(0x15,0x081), BASE, ARG_FP },
+  { "mulf",		FP(0x15,0x082), BASE, ARG_FP },
+  { "divf",		FP(0x15,0x083), BASE, ARG_FP },
+  { "cvtdg",		FP(0x15,0x09E), BASE, ARG_FPZ1 },
+  { "addg",		FP(0x15,0x0A0), BASE, ARG_FP },
+  { "negg",		FP(0x15,0x0A1), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subg",		FP(0x15,0x0A1), BASE, ARG_FP },
+  { "mulg",		FP(0x15,0x0A2), BASE, ARG_FP },
+  { "divg",		FP(0x15,0x0A3), BASE, ARG_FP },
+  { "cmpgeq",		FP(0x15,0x0A5), BASE, ARG_FP },
+  { "cmpglt",		FP(0x15,0x0A6), BASE, ARG_FP },
+  { "cmpgle",		FP(0x15,0x0A7), BASE, ARG_FP },
+  { "cvtgf",		FP(0x15,0x0AC), BASE, ARG_FPZ1 },
+  { "cvtgd",		FP(0x15,0x0AD), BASE, ARG_FPZ1 },
+  { "cvtgq",		FP(0x15,0x0AF), BASE, ARG_FPZ1 },
+  { "cvtqf",		FP(0x15,0x0BC), BASE, ARG_FPZ1 },
+  { "cvtqg",		FP(0x15,0x0BE), BASE, ARG_FPZ1 },
+  { "addf/uc",		FP(0x15,0x100), BASE, ARG_FP },
+  { "subf/uc",		FP(0x15,0x101), BASE, ARG_FP },
+  { "mulf/uc",		FP(0x15,0x102), BASE, ARG_FP },
+  { "divf/uc",		FP(0x15,0x103), BASE, ARG_FP },
+  { "cvtdg/uc",		FP(0x15,0x11E), BASE, ARG_FPZ1 },
+  { "addg/uc",		FP(0x15,0x120), BASE, ARG_FP },
+  { "subg/uc",		FP(0x15,0x121), BASE, ARG_FP },
+  { "mulg/uc",		FP(0x15,0x122), BASE, ARG_FP },
+  { "divg/uc",		FP(0x15,0x123), BASE, ARG_FP },
+  { "cvtgf/uc",		FP(0x15,0x12C), BASE, ARG_FPZ1 },
+  { "cvtgd/uc",		FP(0x15,0x12D), BASE, ARG_FPZ1 },
+  { "cvtgq/vc",		FP(0x15,0x12F), BASE, ARG_FPZ1 },
+  { "addf/u",		FP(0x15,0x180), BASE, ARG_FP },
+  { "subf/u",		FP(0x15,0x181), BASE, ARG_FP },
+  { "mulf/u",		FP(0x15,0x182), BASE, ARG_FP },
+  { "divf/u",		FP(0x15,0x183), BASE, ARG_FP },
+  { "cvtdg/u",		FP(0x15,0x19E), BASE, ARG_FPZ1 },
+  { "addg/u",		FP(0x15,0x1A0), BASE, ARG_FP },
+  { "subg/u",		FP(0x15,0x1A1), BASE, ARG_FP },
+  { "mulg/u",		FP(0x15,0x1A2), BASE, ARG_FP },
+  { "divg/u",		FP(0x15,0x1A3), BASE, ARG_FP },
+  { "cvtgf/u",		FP(0x15,0x1AC), BASE, ARG_FPZ1 },
+  { "cvtgd/u",		FP(0x15,0x1AD), BASE, ARG_FPZ1 },
+  { "cvtgq/v",		FP(0x15,0x1AF), BASE, ARG_FPZ1 },
+  { "addf/sc",		FP(0x15,0x400), BASE, ARG_FP },
+  { "subf/sc",		FP(0x15,0x401), BASE, ARG_FP },
+  { "mulf/sc",		FP(0x15,0x402), BASE, ARG_FP },
+  { "divf/sc",		FP(0x15,0x403), BASE, ARG_FP },
+  { "cvtdg/sc",		FP(0x15,0x41E), BASE, ARG_FPZ1 },
+  { "addg/sc",		FP(0x15,0x420), BASE, ARG_FP },
+  { "subg/sc",		FP(0x15,0x421), BASE, ARG_FP },
+  { "mulg/sc",		FP(0x15,0x422), BASE, ARG_FP },
+  { "divg/sc",		FP(0x15,0x423), BASE, ARG_FP },
+  { "cvtgf/sc",		FP(0x15,0x42C), BASE, ARG_FPZ1 },
+  { "cvtgd/sc",		FP(0x15,0x42D), BASE, ARG_FPZ1 },
+  { "cvtgq/sc",		FP(0x15,0x42F), BASE, ARG_FPZ1 },
+  { "addf/s",		FP(0x15,0x480), BASE, ARG_FP },
+  { "negf/s",		FP(0x15,0x481), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subf/s",		FP(0x15,0x481), BASE, ARG_FP },
+  { "mulf/s",		FP(0x15,0x482), BASE, ARG_FP },
+  { "divf/s",		FP(0x15,0x483), BASE, ARG_FP },
+  { "cvtdg/s",		FP(0x15,0x49E), BASE, ARG_FPZ1 },
+  { "addg/s",		FP(0x15,0x4A0), BASE, ARG_FP },
+  { "negg/s",		FP(0x15,0x4A1), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subg/s",		FP(0x15,0x4A1), BASE, ARG_FP },
+  { "mulg/s",		FP(0x15,0x4A2), BASE, ARG_FP },
+  { "divg/s",		FP(0x15,0x4A3), BASE, ARG_FP },
+  { "cmpgeq/s",		FP(0x15,0x4A5), BASE, ARG_FP },
+  { "cmpglt/s",		FP(0x15,0x4A6), BASE, ARG_FP },
+  { "cmpgle/s",		FP(0x15,0x4A7), BASE, ARG_FP },
+  { "cvtgf/s",		FP(0x15,0x4AC), BASE, ARG_FPZ1 },
+  { "cvtgd/s",		FP(0x15,0x4AD), BASE, ARG_FPZ1 },
+  { "cvtgq/s",		FP(0x15,0x4AF), BASE, ARG_FPZ1 },
+  { "addf/suc",		FP(0x15,0x500), BASE, ARG_FP },
+  { "subf/suc",		FP(0x15,0x501), BASE, ARG_FP },
+  { "mulf/suc",		FP(0x15,0x502), BASE, ARG_FP },
+  { "divf/suc",		FP(0x15,0x503), BASE, ARG_FP },
+  { "cvtdg/suc",	FP(0x15,0x51E), BASE, ARG_FPZ1 },
+  { "addg/suc",		FP(0x15,0x520), BASE, ARG_FP },
+  { "subg/suc",		FP(0x15,0x521), BASE, ARG_FP },
+  { "mulg/suc",		FP(0x15,0x522), BASE, ARG_FP },
+  { "divg/suc",		FP(0x15,0x523), BASE, ARG_FP },
+  { "cvtgf/suc",	FP(0x15,0x52C), BASE, ARG_FPZ1 },
+  { "cvtgd/suc",	FP(0x15,0x52D), BASE, ARG_FPZ1 },
+  { "cvtgq/svc",	FP(0x15,0x52F), BASE, ARG_FPZ1 },
+  { "addf/su",		FP(0x15,0x580), BASE, ARG_FP },
+  { "subf/su",		FP(0x15,0x581), BASE, ARG_FP },
+  { "mulf/su",		FP(0x15,0x582), BASE, ARG_FP },
+  { "divf/su",		FP(0x15,0x583), BASE, ARG_FP },
+  { "cvtdg/su",		FP(0x15,0x59E), BASE, ARG_FPZ1 },
+  { "addg/su",		FP(0x15,0x5A0), BASE, ARG_FP },
+  { "subg/su",		FP(0x15,0x5A1), BASE, ARG_FP },
+  { "mulg/su",		FP(0x15,0x5A2), BASE, ARG_FP },
+  { "divg/su",		FP(0x15,0x5A3), BASE, ARG_FP },
+  { "cvtgf/su",		FP(0x15,0x5AC), BASE, ARG_FPZ1 },
+  { "cvtgd/su",		FP(0x15,0x5AD), BASE, ARG_FPZ1 },
+  { "cvtgq/sv",		FP(0x15,0x5AF), BASE, ARG_FPZ1 },
+
+  { "adds/c",		FP(0x16,0x000), BASE, ARG_FP },
+  { "subs/c",		FP(0x16,0x001), BASE, ARG_FP },
+  { "muls/c",		FP(0x16,0x002), BASE, ARG_FP },
+  { "divs/c",		FP(0x16,0x003), BASE, ARG_FP },
+  { "addt/c",		FP(0x16,0x020), BASE, ARG_FP },
+  { "subt/c",		FP(0x16,0x021), BASE, ARG_FP },
+  { "mult/c",		FP(0x16,0x022), BASE, ARG_FP },
+  { "divt/c",		FP(0x16,0x023), BASE, ARG_FP },
+  { "cvtts/c",		FP(0x16,0x02C), BASE, ARG_FPZ1 },
+  { "cvttq/c",		FP(0x16,0x02F), BASE, ARG_FPZ1 },
+  { "cvtqs/c",		FP(0x16,0x03C), BASE, ARG_FPZ1 },
+  { "cvtqt/c",		FP(0x16,0x03E), BASE, ARG_FPZ1 },
+  { "adds/m",		FP(0x16,0x040), BASE, ARG_FP },
+  { "subs/m",		FP(0x16,0x041), BASE, ARG_FP },
+  { "muls/m",		FP(0x16,0x042), BASE, ARG_FP },
+  { "divs/m",		FP(0x16,0x043), BASE, ARG_FP },
+  { "addt/m",		FP(0x16,0x060), BASE, ARG_FP },
+  { "subt/m",		FP(0x16,0x061), BASE, ARG_FP },
+  { "mult/m",		FP(0x16,0x062), BASE, ARG_FP },
+  { "divt/m",		FP(0x16,0x063), BASE, ARG_FP },
+  { "cvtts/m",		FP(0x16,0x06C), BASE, ARG_FPZ1 },
+  { "cvttq/m",		FP(0x16,0x06F), BASE, ARG_FPZ1 },
+  { "cvtqs/m",		FP(0x16,0x07C), BASE, ARG_FPZ1 },
+  { "cvtqt/m",		FP(0x16,0x07E), BASE, ARG_FPZ1 },
+  { "adds",		FP(0x16,0x080), BASE, ARG_FP },
+  { "negs", 		FP(0x16,0x081), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subs",		FP(0x16,0x081), BASE, ARG_FP },
+  { "muls",		FP(0x16,0x082), BASE, ARG_FP },
+  { "divs",		FP(0x16,0x083), BASE, ARG_FP },
+  { "addt",		FP(0x16,0x0A0), BASE, ARG_FP },
+  { "negt", 		FP(0x16,0x0A1), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subt",		FP(0x16,0x0A1), BASE, ARG_FP },
+  { "mult",		FP(0x16,0x0A2), BASE, ARG_FP },
+  { "divt",		FP(0x16,0x0A3), BASE, ARG_FP },
+  { "cmptun",		FP(0x16,0x0A4), BASE, ARG_FP },
+  { "cmpteq",		FP(0x16,0x0A5), BASE, ARG_FP },
+  { "cmptlt",		FP(0x16,0x0A6), BASE, ARG_FP },
+  { "cmptle",		FP(0x16,0x0A7), BASE, ARG_FP },
+  { "cvtts",		FP(0x16,0x0AC), BASE, ARG_FPZ1 },
+  { "cvttq",		FP(0x16,0x0AF), BASE, ARG_FPZ1 },
+  { "cvtqs",		FP(0x16,0x0BC), BASE, ARG_FPZ1 },
+  { "cvtqt",		FP(0x16,0x0BE), BASE, ARG_FPZ1 },
+  { "adds/d",		FP(0x16,0x0C0), BASE, ARG_FP },
+  { "subs/d",		FP(0x16,0x0C1), BASE, ARG_FP },
+  { "muls/d",		FP(0x16,0x0C2), BASE, ARG_FP },
+  { "divs/d",		FP(0x16,0x0C3), BASE, ARG_FP },
+  { "addt/d",		FP(0x16,0x0E0), BASE, ARG_FP },
+  { "subt/d",		FP(0x16,0x0E1), BASE, ARG_FP },
+  { "mult/d",		FP(0x16,0x0E2), BASE, ARG_FP },
+  { "divt/d",		FP(0x16,0x0E3), BASE, ARG_FP },
+  { "cvtts/d",		FP(0x16,0x0EC), BASE, ARG_FPZ1 },
+  { "cvttq/d",		FP(0x16,0x0EF), BASE, ARG_FPZ1 },
+  { "cvtqs/d",		FP(0x16,0x0FC), BASE, ARG_FPZ1 },
+  { "cvtqt/d",		FP(0x16,0x0FE), BASE, ARG_FPZ1 },
+  { "adds/uc",		FP(0x16,0x100), BASE, ARG_FP },
+  { "subs/uc",		FP(0x16,0x101), BASE, ARG_FP },
+  { "muls/uc",		FP(0x16,0x102), BASE, ARG_FP },
+  { "divs/uc",		FP(0x16,0x103), BASE, ARG_FP },
+  { "addt/uc",		FP(0x16,0x120), BASE, ARG_FP },
+  { "subt/uc",		FP(0x16,0x121), BASE, ARG_FP },
+  { "mult/uc",		FP(0x16,0x122), BASE, ARG_FP },
+  { "divt/uc",		FP(0x16,0x123), BASE, ARG_FP },
+  { "cvtts/uc",		FP(0x16,0x12C), BASE, ARG_FPZ1 },
+  { "cvttq/vc",		FP(0x16,0x12F), BASE, ARG_FPZ1 },
+  { "adds/um",		FP(0x16,0x140), BASE, ARG_FP },
+  { "subs/um",		FP(0x16,0x141), BASE, ARG_FP },
+  { "muls/um",		FP(0x16,0x142), BASE, ARG_FP },
+  { "divs/um",		FP(0x16,0x143), BASE, ARG_FP },
+  { "addt/um",		FP(0x16,0x160), BASE, ARG_FP },
+  { "subt/um",		FP(0x16,0x161), BASE, ARG_FP },
+  { "mult/um",		FP(0x16,0x162), BASE, ARG_FP },
+  { "divt/um",		FP(0x16,0x163), BASE, ARG_FP },
+  { "cvtts/um",		FP(0x16,0x16C), BASE, ARG_FPZ1 },
+  { "cvttq/vm",		FP(0x16,0x16F), BASE, ARG_FPZ1 },
+  { "adds/u",		FP(0x16,0x180), BASE, ARG_FP },
+  { "subs/u",		FP(0x16,0x181), BASE, ARG_FP },
+  { "muls/u",		FP(0x16,0x182), BASE, ARG_FP },
+  { "divs/u",		FP(0x16,0x183), BASE, ARG_FP },
+  { "addt/u",		FP(0x16,0x1A0), BASE, ARG_FP },
+  { "subt/u",		FP(0x16,0x1A1), BASE, ARG_FP },
+  { "mult/u",		FP(0x16,0x1A2), BASE, ARG_FP },
+  { "divt/u",		FP(0x16,0x1A3), BASE, ARG_FP },
+  { "cvtts/u",		FP(0x16,0x1AC), BASE, ARG_FPZ1 },
+  { "cvttq/v",		FP(0x16,0x1AF), BASE, ARG_FPZ1 },
+  { "adds/ud",		FP(0x16,0x1C0), BASE, ARG_FP },
+  { "subs/ud",		FP(0x16,0x1C1), BASE, ARG_FP },
+  { "muls/ud",		FP(0x16,0x1C2), BASE, ARG_FP },
+  { "divs/ud",		FP(0x16,0x1C3), BASE, ARG_FP },
+  { "addt/ud",		FP(0x16,0x1E0), BASE, ARG_FP },
+  { "subt/ud",		FP(0x16,0x1E1), BASE, ARG_FP },
+  { "mult/ud",		FP(0x16,0x1E2), BASE, ARG_FP },
+  { "divt/ud",		FP(0x16,0x1E3), BASE, ARG_FP },
+  { "cvtts/ud",		FP(0x16,0x1EC), BASE, ARG_FPZ1 },
+  { "cvttq/vd",		FP(0x16,0x1EF), BASE, ARG_FPZ1 },
+  { "cvtst",		FP(0x16,0x2AC), BASE, ARG_FPZ1 },
+  { "adds/suc",		FP(0x16,0x500), BASE, ARG_FP },
+  { "subs/suc",		FP(0x16,0x501), BASE, ARG_FP },
+  { "muls/suc",		FP(0x16,0x502), BASE, ARG_FP },
+  { "divs/suc",		FP(0x16,0x503), BASE, ARG_FP },
+  { "addt/suc",		FP(0x16,0x520), BASE, ARG_FP },
+  { "subt/suc",		FP(0x16,0x521), BASE, ARG_FP },
+  { "mult/suc",		FP(0x16,0x522), BASE, ARG_FP },
+  { "divt/suc",		FP(0x16,0x523), BASE, ARG_FP },
+  { "cvtts/suc",	FP(0x16,0x52C), BASE, ARG_FPZ1 },
+  { "cvttq/svc",	FP(0x16,0x52F), BASE, ARG_FPZ1 },
+  { "adds/sum",		FP(0x16,0x540), BASE, ARG_FP },
+  { "subs/sum",		FP(0x16,0x541), BASE, ARG_FP },
+  { "muls/sum",		FP(0x16,0x542), BASE, ARG_FP },
+  { "divs/sum",		FP(0x16,0x543), BASE, ARG_FP },
+  { "addt/sum",		FP(0x16,0x560), BASE, ARG_FP },
+  { "subt/sum",		FP(0x16,0x561), BASE, ARG_FP },
+  { "mult/sum",		FP(0x16,0x562), BASE, ARG_FP },
+  { "divt/sum",		FP(0x16,0x563), BASE, ARG_FP },
+  { "cvtts/sum",	FP(0x16,0x56C), BASE, ARG_FPZ1 },
+  { "cvttq/svm",	FP(0x16,0x56F), BASE, ARG_FPZ1 },
+  { "adds/su",		FP(0x16,0x580), BASE, ARG_FP },
+  { "negs/su",		FP(0x16,0x581), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subs/su",		FP(0x16,0x581), BASE, ARG_FP },
+  { "muls/su",		FP(0x16,0x582), BASE, ARG_FP },
+  { "divs/su",		FP(0x16,0x583), BASE, ARG_FP },
+  { "addt/su",		FP(0x16,0x5A0), BASE, ARG_FP },
+  { "negt/su",		FP(0x16,0x5A1), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subt/su",		FP(0x16,0x5A1), BASE, ARG_FP },
+  { "mult/su",		FP(0x16,0x5A2), BASE, ARG_FP },
+  { "divt/su",		FP(0x16,0x5A3), BASE, ARG_FP },
+  { "cmptun/su",	FP(0x16,0x5A4), BASE, ARG_FP },
+  { "cmpteq/su",	FP(0x16,0x5A5), BASE, ARG_FP },
+  { "cmptlt/su",	FP(0x16,0x5A6), BASE, ARG_FP },
+  { "cmptle/su",	FP(0x16,0x5A7), BASE, ARG_FP },
+  { "cvtts/su",		FP(0x16,0x5AC), BASE, ARG_FPZ1 },
+  { "cvttq/sv",		FP(0x16,0x5AF), BASE, ARG_FPZ1 },
+  { "adds/sud",		FP(0x16,0x5C0), BASE, ARG_FP },
+  { "subs/sud",		FP(0x16,0x5C1), BASE, ARG_FP },
+  { "muls/sud",		FP(0x16,0x5C2), BASE, ARG_FP },
+  { "divs/sud",		FP(0x16,0x5C3), BASE, ARG_FP },
+  { "addt/sud",		FP(0x16,0x5E0), BASE, ARG_FP },
+  { "subt/sud",		FP(0x16,0x5E1), BASE, ARG_FP },
+  { "mult/sud",		FP(0x16,0x5E2), BASE, ARG_FP },
+  { "divt/sud",		FP(0x16,0x5E3), BASE, ARG_FP },
+  { "cvtts/sud",	FP(0x16,0x5EC), BASE, ARG_FPZ1 },
+  { "cvttq/svd",	FP(0x16,0x5EF), BASE, ARG_FPZ1 },
+  { "cvtst/s",		FP(0x16,0x6AC), BASE, ARG_FPZ1 },
+  { "adds/suic",	FP(0x16,0x700), BASE, ARG_FP },
+  { "subs/suic",	FP(0x16,0x701), BASE, ARG_FP },
+  { "muls/suic",	FP(0x16,0x702), BASE, ARG_FP },
+  { "divs/suic",	FP(0x16,0x703), BASE, ARG_FP },
+  { "addt/suic",	FP(0x16,0x720), BASE, ARG_FP },
+  { "subt/suic",	FP(0x16,0x721), BASE, ARG_FP },
+  { "mult/suic",	FP(0x16,0x722), BASE, ARG_FP },
+  { "divt/suic",	FP(0x16,0x723), BASE, ARG_FP },
+  { "cvtts/suic",	FP(0x16,0x72C), BASE, ARG_FPZ1 },
+  { "cvttq/svic",	FP(0x16,0x72F), BASE, ARG_FPZ1 },
+  { "cvtqs/suic",	FP(0x16,0x73C), BASE, ARG_FPZ1 },
+  { "cvtqt/suic",	FP(0x16,0x73E), BASE, ARG_FPZ1 },
+  { "adds/suim",	FP(0x16,0x740), BASE, ARG_FP },
+  { "subs/suim",	FP(0x16,0x741), BASE, ARG_FP },
+  { "muls/suim",	FP(0x16,0x742), BASE, ARG_FP },
+  { "divs/suim",	FP(0x16,0x743), BASE, ARG_FP },
+  { "addt/suim",	FP(0x16,0x760), BASE, ARG_FP },
+  { "subt/suim",	FP(0x16,0x761), BASE, ARG_FP },
+  { "mult/suim",	FP(0x16,0x762), BASE, ARG_FP },
+  { "divt/suim",	FP(0x16,0x763), BASE, ARG_FP },
+  { "cvtts/suim",	FP(0x16,0x76C), BASE, ARG_FPZ1 },
+  { "cvttq/svim",	FP(0x16,0x76F), BASE, ARG_FPZ1 },
+  { "cvtqs/suim",	FP(0x16,0x77C), BASE, ARG_FPZ1 },
+  { "cvtqt/suim",	FP(0x16,0x77E), BASE, ARG_FPZ1 },
+  { "adds/sui",		FP(0x16,0x780), BASE, ARG_FP },
+  { "negs/sui", 	FP(0x16,0x781), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subs/sui",		FP(0x16,0x781), BASE, ARG_FP },
+  { "muls/sui",		FP(0x16,0x782), BASE, ARG_FP },
+  { "divs/sui",		FP(0x16,0x783), BASE, ARG_FP },
+  { "addt/sui",		FP(0x16,0x7A0), BASE, ARG_FP },
+  { "negt/sui", 	FP(0x16,0x7A1), BASE, ARG_FPZ1 },	/* pseudo */
+  { "subt/sui",		FP(0x16,0x7A1), BASE, ARG_FP },
+  { "mult/sui",		FP(0x16,0x7A2), BASE, ARG_FP },
+  { "divt/sui",		FP(0x16,0x7A3), BASE, ARG_FP },
+  { "cvtts/sui",	FP(0x16,0x7AC), BASE, ARG_FPZ1 },
+  { "cvttq/svi",	FP(0x16,0x7AF), BASE, ARG_FPZ1 },
+  { "cvtqs/sui",	FP(0x16,0x7BC), BASE, ARG_FPZ1 },
+  { "cvtqt/sui",	FP(0x16,0x7BE), BASE, ARG_FPZ1 },
+  { "adds/suid",	FP(0x16,0x7C0), BASE, ARG_FP },
+  { "subs/suid",	FP(0x16,0x7C1), BASE, ARG_FP },
+  { "muls/suid",	FP(0x16,0x7C2), BASE, ARG_FP },
+  { "divs/suid",	FP(0x16,0x7C3), BASE, ARG_FP },
+  { "addt/suid",	FP(0x16,0x7E0), BASE, ARG_FP },
+  { "subt/suid",	FP(0x16,0x7E1), BASE, ARG_FP },
+  { "mult/suid",	FP(0x16,0x7E2), BASE, ARG_FP },
+  { "divt/suid",	FP(0x16,0x7E3), BASE, ARG_FP },
+  { "cvtts/suid",	FP(0x16,0x7EC), BASE, ARG_FPZ1 },
+  { "cvttq/svid",	FP(0x16,0x7EF), BASE, ARG_FPZ1 },
+  { "cvtqs/suid",	FP(0x16,0x7FC), BASE, ARG_FPZ1 },
+  { "cvtqt/suid",	FP(0x16,0x7FE), BASE, ARG_FPZ1 },
+
+  { "cvtlq",		FP(0x17,0x010), BASE, ARG_FPZ1 },
+  { "fnop",		FP(0x17,0x020), BASE, { ZA, ZB, ZC } },	/* pseudo */
+  { "fclr",		FP(0x17,0x020), BASE, { ZA, ZB, FC } },	/* pseudo */
+  { "fabs",		FP(0x17,0x020), BASE, ARG_FPZ1 },	/* pseudo */
+  { "fmov",		FP(0x17,0x020), BASE, { FA, RBA, FC } }, /* pseudo */
+  { "cpys",		FP(0x17,0x020), BASE, ARG_FP },
+  { "fneg",		FP(0x17,0x021), BASE, { FA, RBA, FC } }, /* pseudo */
+  { "cpysn",		FP(0x17,0x021), BASE, ARG_FP },
+  { "cpyse",		FP(0x17,0x022), BASE, ARG_FP },
+  { "mt_fpcr",		FP(0x17,0x024), BASE, { FA, RBA, RCA } },
+  { "mf_fpcr",		FP(0x17,0x025), BASE, { FA, RBA, RCA } },
+  { "fcmoveq",		FP(0x17,0x02A), BASE, ARG_FP },
+  { "fcmovne",		FP(0x17,0x02B), BASE, ARG_FP },
+  { "fcmovlt",		FP(0x17,0x02C), BASE, ARG_FP },
+  { "fcmovge",		FP(0x17,0x02D), BASE, ARG_FP },
+  { "fcmovle",		FP(0x17,0x02E), BASE, ARG_FP },
+  { "fcmovgt",		FP(0x17,0x02F), BASE, ARG_FP },
+  { "cvtql",		FP(0x17,0x030), BASE, ARG_FPZ1 },
+  { "cvtql/v",		FP(0x17,0x130), BASE, ARG_FPZ1 },
+  { "cvtql/sv",		FP(0x17,0x530), BASE, ARG_FPZ1 },
+
+  { "trapb",		MFC(0x18,0x0000), BASE, ARG_NONE },
+  { "draint",		MFC(0x18,0x0000), BASE, ARG_NONE },	/* alias */
+  { "excb",		MFC(0x18,0x0400), BASE, ARG_NONE },
+  { "mb",		MFC(0x18,0x4000), BASE, ARG_NONE },
+  { "wmb",		MFC(0x18,0x4400), BASE, ARG_NONE },
+  { "fetch",		MFC(0x18,0x8000), BASE, { ZA, PRB } },
+  { "fetch_m",		MFC(0x18,0xA000), BASE, { ZA, PRB } },
+  { "rpcc",		MFC(0x18,0xC000), BASE, { RA } },
+  { "rc",		MFC(0x18,0xE000), BASE, { RA } },
+  { "ecb",		MFC(0x18,0xE800), BASE, { ZA, PRB } },	/* ev56 una */
+  { "rs",		MFC(0x18,0xF000), BASE, { RA } },
+  { "wh64",		MFC(0x18,0xF800), BASE, { ZA, PRB } },	/* ev56 una */
+  { "wh64en",		MFC(0x18,0xFC00), BASE, { ZA, PRB } },	/* ev7 una */
+
+  { "hw_mfpr",		OPR(0x19,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
+  { "hw_mfpr",		OP(0x19), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
+  { "hw_mfpr",		OP(0x19), OP_MASK, EV6, { RA, ZB, EV6HWINDEX } },
+  { "hw_mfpr/i",	OPR(0x19,0x01), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/a",	OPR(0x19,0x02), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/ai",	OPR(0x19,0x03), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/p",	OPR(0x19,0x04), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/pi",	OPR(0x19,0x05), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/pa",	OPR(0x19,0x06), EV4, ARG_EV4HWMPR },
+  { "hw_mfpr/pai",	OPR(0x19,0x07), EV4, ARG_EV4HWMPR },
+  { "pal19",		PCD(0x19), BASE, ARG_PCD },
+
+  { "jmp",		MBR_(0x1A,0), MBR_MASK | 0x3FFF,	/* pseudo */
+			BASE, { ZA, CPRB } },
+  { "jmp",		MBR(0x1A,0), BASE, { RA, CPRB, JMPHINT } },
+  { "jsr",		MBR(0x1A,1), BASE, { RA, CPRB, JMPHINT } },
+  { "ret",		MBR_(0x1A,2) | (31 << 21) | (26 << 16) | 1,/* pseudo */
+			0xFFFFFFFF, BASE, { 0 } },
+  { "ret",		MBR(0x1A,2), BASE, { RA, CPRB, RETHINT } },
+  { "jcr",		MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, /* alias */
+  { "jsr_coroutine",	MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } },
+
+  { "hw_ldl",		EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
+  { "hw_ldl",		EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
+  { "hw_ldl",		EV6HWMEM(0x1B,0x8), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/a",		EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/a",		EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/a",		EV6HWMEM(0x1B,0xC), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/al",	EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/ar",	EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/av",	EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/avl",	EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/aw",	EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/awl",	EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/awv",	EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/awvl",	EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/l",		EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/p",		EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/p",		EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/p",		EV6HWMEM(0x1B,0x0), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/pa",	EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/pa",	EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pal",	EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/par",	EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/pav",	EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pavl",	EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/paw",	EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pawl",	EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pawv",	EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pawvl",	EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pl",	EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pr",	EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/pv",	EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pvl",	EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pw",	EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pwl",	EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pwv",	EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/pwvl",	EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/r",		EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
+  { "hw_ldl/v",		EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/v",		EV6HWMEM(0x1B,0x4), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/vl",	EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/w",		EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/w",		EV6HWMEM(0x1B,0xA), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/wa",	EV6HWMEM(0x1B,0xE), EV6, ARG_EV6HWMEM },
+  { "hw_ldl/wl",	EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/wv",	EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
+  { "hw_ldl/wvl",	EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l",		EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/a",	EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/av",	EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/aw",	EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/awv",	EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/p",	EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/p",	EV6HWMEM(0x1B,0x2), EV6, ARG_EV6HWMEM },
+  { "hw_ldl_l/pa",	EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/pav",	EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/paw",	EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/pawv",	EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/pv",	EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/pw",	EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/pwv",	EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/v",	EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/w",	EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+  { "hw_ldl_l/wv",	EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+  { "hw_ldq",		EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
+  { "hw_ldq",		EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
+  { "hw_ldq",		EV6HWMEM(0x1B,0x9), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/a",		EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/a",		EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/a",		EV6HWMEM(0x1B,0xD), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/al",	EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/ar",	EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/av",	EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/avl",	EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/aw",	EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/awl",	EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/awv",	EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/awvl",	EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/l",		EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/p",		EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/p",		EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/p",		EV6HWMEM(0x1B,0x1), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/pa",	EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/pa",	EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pal",	EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/par",	EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/pav",	EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pavl",	EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/paw",	EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pawl",	EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pawv",	EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pawvl",	EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pl",	EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pr",	EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/pv",	EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pvl",	EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pw",	EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pwl",	EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pwv",	EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/pwvl",	EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/r",		EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
+  { "hw_ldq/v",		EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/v",		EV6HWMEM(0x1B,0x5), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/vl",	EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/w",		EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/w",		EV6HWMEM(0x1B,0xB), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/wa",	EV6HWMEM(0x1B,0xF), EV6, ARG_EV6HWMEM },
+  { "hw_ldq/wl",	EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/wv",	EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
+  { "hw_ldq/wvl",	EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l",		EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/a",	EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/av",	EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/aw",	EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/awv",	EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/p",	EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/p",	EV6HWMEM(0x1B,0x3), EV6, ARG_EV6HWMEM },
+  { "hw_ldq_l/pa",	EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/pav",	EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/paw",	EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/pawv",	EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/pv",	EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/pw",	EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/pwv",	EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/v",	EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/w",	EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+  { "hw_ldq_l/wv",	EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+  { "hw_ld",		EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
+  { "hw_ld",		EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
+  { "hw_ld/a",		EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
+  { "hw_ld/a",		EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
+  { "hw_ld/al",		EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_ld/aq",		EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
+  { "hw_ld/aq",		EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
+  { "hw_ld/aql",	EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_ld/aqv",	EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
+  { "hw_ld/aqvl",	EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_ld/ar",		EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
+  { "hw_ld/arq",	EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
+  { "hw_ld/av",		EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
+  { "hw_ld/avl",	EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_ld/aw",		EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awl",	EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awq",	EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awql",	EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awqv",	EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awqvl",	EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awv",	EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
+  { "hw_ld/awvl",	EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+  { "hw_ld/l",		EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_ld/p",		EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
+  { "hw_ld/p",		EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pa",		EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
+  { "hw_ld/pa",		EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pal",	EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_ld/paq",	EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
+  { "hw_ld/paq",	EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
+  { "hw_ld/paql",	EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_ld/paqv",	EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
+  { "hw_ld/paqvl",	EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_ld/par",	EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
+  { "hw_ld/parq",	EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
+  { "hw_ld/pav",	EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pavl",	EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_ld/paw",	EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawl",	EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawq",	EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawql",	EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawqv",	EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawqvl",	EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawv",	EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pawvl",	EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pl",		EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pq",		EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
+  { "hw_ld/pq",		EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pql",	EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pqv",	EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pqvl",	EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pr",		EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
+  { "hw_ld/prq",	EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
+  { "hw_ld/pv",		EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pvl",	EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pw",		EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwl",	EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwq",	EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwql",	EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwqv",	EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwqvl",	EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwv",	EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
+  { "hw_ld/pwvl",	EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+  { "hw_ld/q",		EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
+  { "hw_ld/q",		EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
+  { "hw_ld/ql",		EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_ld/qv",		EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
+  { "hw_ld/qvl",	EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_ld/r",		EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
+  { "hw_ld/rq",		EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
+  { "hw_ld/v",		EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
+  { "hw_ld/vl",		EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+  { "hw_ld/w",		EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wl",		EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wq",		EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wql",	EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wqv",	EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wqvl",	EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wv",		EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
+  { "hw_ld/wvl",	EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+  { "pal1b",		PCD(0x1B), BASE, ARG_PCD },
+
+  { "sextb",		OPR(0x1C, 0x00), BWX, ARG_OPRZ1 },
+  { "sextw",		OPR(0x1C, 0x01), BWX, ARG_OPRZ1 },
+  { "ctpop",		OPR(0x1C, 0x30), CIX, ARG_OPRZ1 },
+  { "perr",		OPR(0x1C, 0x31), MAX, ARG_OPR },
+  { "ctlz",		OPR(0x1C, 0x32), CIX, ARG_OPRZ1 },
+  { "cttz",		OPR(0x1C, 0x33), CIX, ARG_OPRZ1 },
+  { "unpkbw",		OPR(0x1C, 0x34), MAX, ARG_OPRZ1 },
+  { "unpkbl",		OPR(0x1C, 0x35), MAX, ARG_OPRZ1 },
+  { "pkwb",		OPR(0x1C, 0x36), MAX, ARG_OPRZ1 },
+  { "pklb",		OPR(0x1C, 0x37), MAX, ARG_OPRZ1 },
+  { "minsb8", 		OPR(0x1C, 0x38), MAX, ARG_OPR },
+  { "minsb8", 		OPRL(0x1C, 0x38), MAX, ARG_OPRL },
+  { "minsw4", 		OPR(0x1C, 0x39), MAX, ARG_OPR },
+  { "minsw4", 		OPRL(0x1C, 0x39), MAX, ARG_OPRL },
+  { "minub8", 		OPR(0x1C, 0x3A), MAX, ARG_OPR },
+  { "minub8", 		OPRL(0x1C, 0x3A), MAX, ARG_OPRL },
+  { "minuw4", 		OPR(0x1C, 0x3B), MAX, ARG_OPR },
+  { "minuw4", 		OPRL(0x1C, 0x3B), MAX, ARG_OPRL },
+  { "maxub8",		OPR(0x1C, 0x3C), MAX, ARG_OPR },
+  { "maxub8",		OPRL(0x1C, 0x3C), MAX, ARG_OPRL },
+  { "maxuw4",		OPR(0x1C, 0x3D), MAX, ARG_OPR },
+  { "maxuw4",		OPRL(0x1C, 0x3D), MAX, ARG_OPRL },
+  { "maxsb8",		OPR(0x1C, 0x3E), MAX, ARG_OPR },
+  { "maxsb8",		OPRL(0x1C, 0x3E), MAX, ARG_OPRL },
+  { "maxsw4",		OPR(0x1C, 0x3F), MAX, ARG_OPR },
+  { "maxsw4",		OPRL(0x1C, 0x3F), MAX, ARG_OPRL },
+  { "ftoit",		FP(0x1C, 0x70), CIX, { FA, ZB, RC } },
+  { "ftois",		FP(0x1C, 0x78), CIX, { FA, ZB, RC } },
+
+  { "hw_mtpr",		OPR(0x1D,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
+  { "hw_mtpr",		OP(0x1D), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
+  { "hw_mtpr",		OP(0x1D), OP_MASK, EV6, { ZA, RB, EV6HWINDEX } },
+  { "hw_mtpr/i", 	OPR(0x1D,0x01), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/a", 	OPR(0x1D,0x02), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/ai",	OPR(0x1D,0x03), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/p", 	OPR(0x1D,0x04), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/pi",	OPR(0x1D,0x05), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/pa",	OPR(0x1D,0x06), EV4, ARG_EV4HWMPR },
+  { "hw_mtpr/pai",	OPR(0x1D,0x07), EV4, ARG_EV4HWMPR },
+  { "pal1d",		PCD(0x1D), BASE, ARG_PCD },
+
+  { "hw_rei",		SPCD(0x1E,0x3FF8000), EV4|EV5, ARG_NONE },
+  { "hw_rei_stall",	SPCD(0x1E,0x3FFC000), EV5, ARG_NONE },
+  { "hw_jmp", 		EV6HWMBR(0x1E,0x0), EV6, { ZA, PRB, EV6HWJMPHINT } },
+  { "hw_jsr", 		EV6HWMBR(0x1E,0x2), EV6, { ZA, PRB, EV6HWJMPHINT } },
+  { "hw_ret", 		EV6HWMBR(0x1E,0x4), EV6, { ZA, PRB } },
+  { "hw_jcr", 		EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } },
+  { "hw_coroutine",	EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, /* alias */
+  { "hw_jmp/stall",	EV6HWMBR(0x1E,0x1), EV6, { ZA, PRB, EV6HWJMPHINT } },
+  { "hw_jsr/stall", 	EV6HWMBR(0x1E,0x3), EV6, { ZA, PRB, EV6HWJMPHINT } },
+  { "hw_ret/stall",	EV6HWMBR(0x1E,0x5), EV6, { ZA, PRB } },
+  { "hw_jcr/stall", 	EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } },
+  { "hw_coroutine/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, /* alias */
+  { "pal1e",		PCD(0x1E), BASE, ARG_PCD },
+
+  { "hw_stl",		EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
+  { "hw_stl",		EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
+  { "hw_stl",		EV6HWMEM(0x1F,0x4), EV6, ARG_EV6HWMEM }, /* ??? 8 */
+  { "hw_stl/a",		EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
+  { "hw_stl/a",		EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
+  { "hw_stl/a",		EV6HWMEM(0x1F,0xC), EV6, ARG_EV6HWMEM },
+  { "hw_stl/ac",	EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_stl/ar",	EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
+  { "hw_stl/av",	EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
+  { "hw_stl/avc",	EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_stl/c",		EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_stl/p",		EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
+  { "hw_stl/p",		EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
+  { "hw_stl/p",		EV6HWMEM(0x1F,0x0), EV6, ARG_EV6HWMEM },
+  { "hw_stl/pa",	EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
+  { "hw_stl/pa",	EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pac",	EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pav",	EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pavc",	EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pc",	EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pr",	EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
+  { "hw_stl/pv",	EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
+  { "hw_stl/pvc",	EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_stl/r",		EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
+  { "hw_stl/v",		EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
+  { "hw_stl/vc",	EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c",		EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/a",	EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/av",	EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/p",	EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/p",	EV6HWMEM(0x1F,0x2), EV6, ARG_EV6HWMEM },
+  { "hw_stl_c/pa",	EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/pav",	EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/pv",	EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_stl_c/v",	EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+  { "hw_stq",		EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
+  { "hw_stq",		EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
+  { "hw_stq",		EV6HWMEM(0x1F,0x5), EV6, ARG_EV6HWMEM }, /* ??? 9 */
+  { "hw_stq/a",		EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
+  { "hw_stq/a",		EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
+  { "hw_stq/a",		EV6HWMEM(0x1F,0xD), EV6, ARG_EV6HWMEM },
+  { "hw_stq/ac",	EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_stq/ar",	EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
+  { "hw_stq/av",	EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
+  { "hw_stq/avc",	EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_stq/c",		EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_stq/p",		EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
+  { "hw_stq/p",		EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
+  { "hw_stq/p",		EV6HWMEM(0x1F,0x1), EV6, ARG_EV6HWMEM },
+  { "hw_stq/pa",	EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
+  { "hw_stq/pa",	EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
+  { "hw_stq/pac",	EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_stq/par",	EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
+  { "hw_stq/par",	EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
+  { "hw_stq/pav",	EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
+  { "hw_stq/pavc",	EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_stq/pc",	EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_stq/pr",	EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
+  { "hw_stq/pv",	EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
+  { "hw_stq/pvc",	EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_stq/r",		EV4HWMEM(0x1F,0x3), EV4, ARG_EV4HWMEM },
+  { "hw_stq/v",		EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
+  { "hw_stq/vc",	EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c",		EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/a",	EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/av",	EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/p",	EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/p",	EV6HWMEM(0x1F,0x3), EV6, ARG_EV6HWMEM },
+  { "hw_stq_c/pa",	EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/pav",	EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/pv",	EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_stq_c/v",	EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_st",		EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
+  { "hw_st",		EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
+  { "hw_st/a",		EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
+  { "hw_st/a",		EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
+  { "hw_st/ac",		EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+  { "hw_st/aq",		EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
+  { "hw_st/aq",		EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
+  { "hw_st/aqc",	EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+  { "hw_st/aqv",	EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
+  { "hw_st/aqvc",	EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+  { "hw_st/ar",		EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
+  { "hw_st/arq",	EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
+  { "hw_st/av",		EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
+  { "hw_st/avc",	EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+  { "hw_st/c",		EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+  { "hw_st/p",		EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
+  { "hw_st/p",		EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
+  { "hw_st/pa",		EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
+  { "hw_st/pa",		EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
+  { "hw_st/pac",	EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+  { "hw_st/paq",	EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
+  { "hw_st/paq",	EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
+  { "hw_st/paqc",	EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+  { "hw_st/paqv",	EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
+  { "hw_st/paqvc",	EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+  { "hw_st/par",	EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
+  { "hw_st/parq",	EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
+  { "hw_st/pav",	EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
+  { "hw_st/pavc",	EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+  { "hw_st/pc",		EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+  { "hw_st/pq",		EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
+  { "hw_st/pq",		EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
+  { "hw_st/pqc",	EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+  { "hw_st/pqv",	EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
+  { "hw_st/pqvc",	EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+  { "hw_st/pr",		EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
+  { "hw_st/prq",	EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
+  { "hw_st/pv",		EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
+  { "hw_st/pvc",	EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+  { "hw_st/q",		EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
+  { "hw_st/q",		EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
+  { "hw_st/qc",		EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+  { "hw_st/qv",		EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
+  { "hw_st/qvc",	EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+  { "hw_st/r",		EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
+  { "hw_st/v",		EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
+  { "hw_st/vc",		EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+  { "pal1f",		PCD(0x1F), BASE, ARG_PCD },
+
+  { "ldf",		MEM(0x20), BASE, ARG_FMEM },
+  { "ldg",		MEM(0x21), BASE, ARG_FMEM },
+  { "lds",		MEM(0x22), BASE, ARG_FMEM },
+  { "ldt",		MEM(0x23), BASE, ARG_FMEM },
+  { "stf",		MEM(0x24), BASE, ARG_FMEM },
+  { "stg",		MEM(0x25), BASE, ARG_FMEM },
+  { "sts",		MEM(0x26), BASE, ARG_FMEM },
+  { "stt",		MEM(0x27), BASE, ARG_FMEM },
+
+  { "ldl",		MEM(0x28), BASE, ARG_MEM },
+  { "ldq",		MEM(0x29), BASE, ARG_MEM },
+  { "ldl_l",		MEM(0x2A), BASE, ARG_MEM },
+  { "ldq_l",		MEM(0x2B), BASE, ARG_MEM },
+  { "stl",		MEM(0x2C), BASE, ARG_MEM },
+  { "stq",		MEM(0x2D), BASE, ARG_MEM },
+  { "stl_c",		MEM(0x2E), BASE, ARG_MEM },
+  { "stq_c",		MEM(0x2F), BASE, ARG_MEM },
+
+  { "br",		BRA(0x30), BASE, { ZA, BDISP } },	/* pseudo */
+  { "br",		BRA(0x30), BASE, ARG_BRA },
+  { "fbeq",		BRA(0x31), BASE, ARG_FBRA },
+  { "fblt",		BRA(0x32), BASE, ARG_FBRA },
+  { "fble",		BRA(0x33), BASE, ARG_FBRA },
+  { "bsr",		BRA(0x34), BASE, ARG_BRA },
+  { "fbne",		BRA(0x35), BASE, ARG_FBRA },
+  { "fbge",		BRA(0x36), BASE, ARG_FBRA },
+  { "fbgt",		BRA(0x37), BASE, ARG_FBRA },
+  { "blbc",		BRA(0x38), BASE, ARG_BRA },
+  { "beq",		BRA(0x39), BASE, ARG_BRA },
+  { "blt",		BRA(0x3A), BASE, ARG_BRA },
+  { "ble",		BRA(0x3B), BASE, ARG_BRA },
+  { "blbs",		BRA(0x3C), BASE, ARG_BRA },
+  { "bne",		BRA(0x3D), BASE, ARG_BRA },
+  { "bge",		BRA(0x3E), BASE, ARG_BRA },
+  { "bgt",		BRA(0x3F), BASE, ARG_BRA },
+};
+
+const unsigned alpha_num_opcodes = sizeof(alpha_opcodes)/sizeof(*alpha_opcodes);
+
+/* OSF register names.  */
+
+static const char * const osf_regnames[64] = {
+  "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
+  "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
+  "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
+  "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
+  "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+  "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
+};
+
+/* VMS register names.  */
+
+static const char * const vms_regnames[64] = {
+  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
+  "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
+  "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
+  "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
+  "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
+  "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
+};
+
+/* Disassemble Alpha instructions.  */
+
+int
+print_insn_alpha (bfd_vma memaddr, struct disassemble_info *info)
+{
+  static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
+  const char * const * regnames;
+  const struct alpha_opcode *opcode, *opcode_end;
+  const unsigned char *opindex;
+  unsigned insn, op, isa_mask;
+  int need_comma;
+
+  /* Initialize the majorop table the first time through */
+  if (!opcode_index[0])
+    {
+      opcode = alpha_opcodes;
+      opcode_end = opcode + alpha_num_opcodes;
+
+      for (op = 0; op < AXP_NOPS; ++op)
+	{
+	  opcode_index[op] = opcode;
+	  while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
+	    ++opcode;
+	}
+      opcode_index[op] = opcode;
+    }
+
+  if (info->flavour == bfd_target_evax_flavour)
+    regnames = vms_regnames;
+  else
+    regnames = osf_regnames;
+
+  isa_mask = AXP_OPCODE_NOPAL;
+  switch (info->mach)
+    {
+    case bfd_mach_alpha_ev4:
+      isa_mask |= AXP_OPCODE_EV4;
+      break;
+    case bfd_mach_alpha_ev5:
+      isa_mask |= AXP_OPCODE_EV5;
+      break;
+    case bfd_mach_alpha_ev6:
+      isa_mask |= AXP_OPCODE_EV6;
+      break;
+    }
+
+  /* Read the insn into a host word */
+  {
+    bfd_byte buffer[4];
+    int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+    if (status != 0)
+      {
+	(*info->memory_error_func) (status, memaddr, info);
+	return -1;
+      }
+    insn = bfd_getl32 (buffer);
+  }
+
+  /* Get the major opcode of the instruction.  */
+  op = AXP_OP (insn);
+
+  /* Find the first match in the opcode table.  */
+  opcode_end = opcode_index[op + 1];
+  for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
+    {
+      if ((insn ^ opcode->opcode) & opcode->mask)
+	continue;
+
+      if (!(opcode->flags & isa_mask))
+	continue;
+
+      /* Make two passes over the operands.  First see if any of them
+	 have extraction functions, and, if they do, make sure the
+	 instruction is valid.  */
+      {
+	int invalid = 0;
+	for (opindex = opcode->operands; *opindex != 0; opindex++)
+	  {
+	    const struct alpha_operand *operand = alpha_operands + *opindex;
+	    if (operand->extract)
+	      (*operand->extract) (insn, &invalid);
+	  }
+	if (invalid)
+	  continue;
+      }
+
+      /* The instruction is valid.  */
+      goto found;
+    }
+
+  /* No instruction found */
+  (*info->fprintf_func) (info->stream, ".long %#08x", insn);
+
+  return 4;
+
+found:
+  (*info->fprintf_func) (info->stream, "%s", opcode->name);
+  if (opcode->operands[0] != 0)
+    (*info->fprintf_func) (info->stream, "\t");
+
+  /* Now extract and print the operands.  */
+  need_comma = 0;
+  for (opindex = opcode->operands; *opindex != 0; opindex++)
+    {
+      const struct alpha_operand *operand = alpha_operands + *opindex;
+      int value;
+
+      /* Operands that are marked FAKE are simply ignored.  We
+	 already made sure that the extract function considered
+	 the instruction to be valid.  */
+      if ((operand->flags & AXP_OPERAND_FAKE) != 0)
+	continue;
+
+      /* Extract the value from the instruction.  */
+      if (operand->extract)
+	value = (*operand->extract) (insn, (int *) NULL);
+      else
+	{
+	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+	  if (operand->flags & AXP_OPERAND_SIGNED)
+	    {
+	      int signbit = 1 << (operand->bits - 1);
+	      value = (value ^ signbit) - signbit;
+	    }
+	}
+
+      if (need_comma &&
+	  ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
+	   != AXP_OPERAND_PARENS))
+	{
+	  (*info->fprintf_func) (info->stream, ",");
+	}
+      if (operand->flags & AXP_OPERAND_PARENS)
+	(*info->fprintf_func) (info->stream, "(");
+
+      /* Print the operand as directed by the flags.  */
+      if (operand->flags & AXP_OPERAND_IR)
+	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
+      else if (operand->flags & AXP_OPERAND_FPR)
+	(*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
+      else if (operand->flags & AXP_OPERAND_RELATIVE)
+	(*info->print_address_func) (memaddr + 4 + value, info);
+      else if (operand->flags & AXP_OPERAND_SIGNED)
+	(*info->fprintf_func) (info->stream, "%d", value);
+      else
+	(*info->fprintf_func) (info->stream, "%#x", value);
+
+      if (operand->flags & AXP_OPERAND_PARENS)
+	(*info->fprintf_func) (info->stream, ")");
+      need_comma = 1;
+    }
+
+  return 4;
+}
diff --git a/qemu-0.15.x/alpha.ld b/qemu-0.15.x/alpha.ld
new file mode 100644
index 0000000..906d76b
--- /dev/null
+++ b/qemu-0.15.x/alpha.ld
@@ -0,0 +1,127 @@
+OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
+	      "elf64-alpha")
+OUTPUT_ARCH(alpha)
+ENTRY(__start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp) 	}
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .gnu.version   : { *(.gnu.version)	}
+  .gnu.version_d   : { *(.gnu.version_d)	}
+  .gnu.version_r   : { *(.gnu.version_r)	}
+  .rel.text      :
+    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+  .rela.text     :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rel.data      :
+    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+  .rela.data     :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rel.rodata    :
+    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+  .rela.rodata   :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.init      : { *(.rel.init)	}
+  .rela.init     : { *(.rela.init)	}
+  .rel.fini      : { *(.rel.fini)	}
+  .rela.fini     : { *(.rela.fini)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	} =0x47ff041f
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  } =0x47ff041f
+  _etext = .;
+  PROVIDE (etext = .);
+  .fini      : { *(.fini)    } =0x47ff041f
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x100000) + (. & (0x100000 - 1));
+  .data    :
+  {
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+  .plt      : { *(.plt)	}
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff --git a/qemu-0.15.x/arch_init.c b/qemu-0.15.x/arch_init.c
new file mode 100644
index 0000000..484b39d
--- /dev/null
+++ b/qemu-0.15.x/arch_init.c
@@ -0,0 +1,733 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+#include "config.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "arch_init.h"
+#include "audio/audio.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "hw/audiodev.h"
+#include "kvm.h"
+#include "migration.h"
+#include "net.h"
+#include "gdbstub.h"
+#include "hw/smbios.h"
+
+#ifdef TARGET_SPARC
+int graphic_width = 1024;
+int graphic_height = 768;
+int graphic_depth = 8;
+#else
+int graphic_width = 800;
+int graphic_height = 600;
+int graphic_depth = 15;
+#endif
+
+const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
+
+#if defined(TARGET_ALPHA)
+#define QEMU_ARCH QEMU_ARCH_ALPHA
+#elif defined(TARGET_ARM)
+#define QEMU_ARCH QEMU_ARCH_ARM
+#elif defined(TARGET_CRIS)
+#define QEMU_ARCH QEMU_ARCH_CRIS
+#elif defined(TARGET_I386)
+#define QEMU_ARCH QEMU_ARCH_I386
+#elif defined(TARGET_M68K)
+#define QEMU_ARCH QEMU_ARCH_M68K
+#elif defined(TARGET_LM32)
+#define QEMU_ARCH QEMU_ARCH_LM32
+#elif defined(TARGET_MICROBLAZE)
+#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
+#elif defined(TARGET_MIPS)
+#define QEMU_ARCH QEMU_ARCH_MIPS
+#elif defined(TARGET_PPC)
+#define QEMU_ARCH QEMU_ARCH_PPC
+#elif defined(TARGET_S390X)
+#define QEMU_ARCH QEMU_ARCH_S390X
+#elif defined(TARGET_SH4)
+#define QEMU_ARCH QEMU_ARCH_SH4
+#elif defined(TARGET_SPARC)
+#define QEMU_ARCH QEMU_ARCH_SPARC
+#endif
+
+const uint32_t arch_type = QEMU_ARCH;
+
+/***********************************************************/
+/* ram save/restore */
+
+#define RAM_SAVE_FLAG_FULL     0x01 /* Obsolete, not used anymore */
+#define RAM_SAVE_FLAG_COMPRESS 0x02
+#define RAM_SAVE_FLAG_MEM_SIZE 0x04
+#define RAM_SAVE_FLAG_PAGE     0x08
+#define RAM_SAVE_FLAG_EOS      0x10
+#define RAM_SAVE_FLAG_CONTINUE 0x20
+
+static int is_dup_page(uint8_t *page, uint8_t ch)
+{
+    uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
+    uint32_t *array = (uint32_t *)page;
+    int i;
+
+    for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
+        if (array[i] != val) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static RAMBlock *last_block;
+static ram_addr_t last_offset;
+
+static int ram_save_block(QEMUFile *f)
+{
+    RAMBlock *block = last_block;
+    ram_addr_t offset = last_offset;
+    ram_addr_t current_addr;
+    int bytes_sent = 0;
+
+    if (!block)
+        block = QLIST_FIRST(&ram_list.blocks);
+
+    current_addr = block->offset + offset;
+
+    do {
+        if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
+            uint8_t *p;
+            int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
+
+            cpu_physical_memory_reset_dirty(current_addr,
+                                            current_addr + TARGET_PAGE_SIZE,
+                                            MIGRATION_DIRTY_FLAG);
+
+            p = block->host + offset;
+
+            if (is_dup_page(p, *p)) {
+                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
+                if (!cont) {
+                    qemu_put_byte(f, strlen(block->idstr));
+                    qemu_put_buffer(f, (uint8_t *)block->idstr,
+                                    strlen(block->idstr));
+                }
+                qemu_put_byte(f, *p);
+                bytes_sent = 1;
+            } else {
+                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_PAGE);
+                if (!cont) {
+                    qemu_put_byte(f, strlen(block->idstr));
+                    qemu_put_buffer(f, (uint8_t *)block->idstr,
+                                    strlen(block->idstr));
+                }
+                qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
+                bytes_sent = TARGET_PAGE_SIZE;
+            }
+
+            break;
+        }
+
+        offset += TARGET_PAGE_SIZE;
+        if (offset >= block->length) {
+            offset = 0;
+            block = QLIST_NEXT(block, next);
+            if (!block)
+                block = QLIST_FIRST(&ram_list.blocks);
+        }
+
+        current_addr = block->offset + offset;
+
+    } while (current_addr != last_block->offset + last_offset);
+
+    last_block = block;
+    last_offset = offset;
+
+    return bytes_sent;
+}
+
+static uint64_t bytes_transferred;
+
+static ram_addr_t ram_save_remaining(void)
+{
+    RAMBlock *block;
+    ram_addr_t count = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        ram_addr_t addr;
+        for (addr = block->offset; addr < block->offset + block->length;
+             addr += TARGET_PAGE_SIZE) {
+            if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
+
+uint64_t ram_bytes_remaining(void)
+{
+    return ram_save_remaining() * TARGET_PAGE_SIZE;
+}
+
+uint64_t ram_bytes_transferred(void)
+{
+    return bytes_transferred;
+}
+
+uint64_t ram_bytes_total(void)
+{
+    RAMBlock *block;
+    uint64_t total = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next)
+        total += block->length;
+
+    return total;
+}
+
+static int block_compar(const void *a, const void *b)
+{
+    RAMBlock * const *ablock = a;
+    RAMBlock * const *bblock = b;
+    if ((*ablock)->offset < (*bblock)->offset) {
+        return -1;
+    } else if ((*ablock)->offset > (*bblock)->offset) {
+        return 1;
+    }
+    return 0;
+}
+
+static void sort_ram_list(void)
+{
+    RAMBlock *block, *nblock, **blocks;
+    int n;
+    n = 0;
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        ++n;
+    }
+    blocks = qemu_malloc(n * sizeof *blocks);
+    n = 0;
+    QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
+        blocks[n++] = block;
+        QLIST_REMOVE(block, next);
+    }
+    qsort(blocks, n, sizeof *blocks, block_compar);
+    while (--n >= 0) {
+        QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
+    }
+    qemu_free(blocks);
+}
+
+int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+{
+    ram_addr_t addr;
+    uint64_t bytes_transferred_last;
+    double bwidth = 0;
+    uint64_t expected_time = 0;
+
+    if (stage < 0) {
+        cpu_physical_memory_set_dirty_tracking(0);
+        return 0;
+    }
+
+    if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
+        qemu_file_set_error(f);
+        return 0;
+    }
+
+    if (stage == 1) {
+        RAMBlock *block;
+        bytes_transferred = 0;
+        last_block = NULL;
+        last_offset = 0;
+        sort_ram_list();
+
+        /* Make sure all dirty bits are set */
+        QLIST_FOREACH(block, &ram_list.blocks, next) {
+            for (addr = block->offset; addr < block->offset + block->length;
+                 addr += TARGET_PAGE_SIZE) {
+                if (!cpu_physical_memory_get_dirty(addr,
+                                                   MIGRATION_DIRTY_FLAG)) {
+                    cpu_physical_memory_set_dirty(addr);
+                }
+            }
+        }
+
+        /* Enable dirty memory tracking */
+        cpu_physical_memory_set_dirty_tracking(1);
+
+        qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
+
+        QLIST_FOREACH(block, &ram_list.blocks, next) {
+            qemu_put_byte(f, strlen(block->idstr));
+            qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
+            qemu_put_be64(f, block->length);
+        }
+    }
+
+    bytes_transferred_last = bytes_transferred;
+    bwidth = qemu_get_clock_ns(rt_clock);
+
+    while (!qemu_file_rate_limit(f)) {
+        int bytes_sent;
+
+        bytes_sent = ram_save_block(f);
+        bytes_transferred += bytes_sent;
+        if (bytes_sent == 0) { /* no more blocks */
+            break;
+        }
+    }
+
+    bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
+    bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
+
+    /* if we haven't transferred anything this round, force expected_time to a
+     * a very high value, but without crashing */
+    if (bwidth == 0) {
+        bwidth = 0.000001;
+    }
+
+    /* try transferring iterative blocks of memory */
+    if (stage == 3) {
+        int bytes_sent;
+
+        /* flush all remaining blocks regardless of rate limiting */
+        while ((bytes_sent = ram_save_block(f)) != 0) {
+            bytes_transferred += bytes_sent;
+        }
+        cpu_physical_memory_set_dirty_tracking(0);
+    }
+
+    qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+
+    expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
+
+    return (stage == 2) && (expected_time <= migrate_max_downtime());
+}
+
+static inline void *host_from_stream_offset(QEMUFile *f,
+                                            ram_addr_t offset,
+                                            int flags)
+{
+    static RAMBlock *block = NULL;
+    char id[256];
+    uint8_t len;
+
+    if (flags & RAM_SAVE_FLAG_CONTINUE) {
+        if (!block) {
+            fprintf(stderr, "Ack, bad migration stream!\n");
+            return NULL;
+        }
+
+        return block->host + offset;
+    }
+
+    len = qemu_get_byte(f);
+    qemu_get_buffer(f, (uint8_t *)id, len);
+    id[len] = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!strncmp(id, block->idstr, sizeof(id)))
+            return block->host + offset;
+    }
+
+    fprintf(stderr, "Can't find block %s!\n", id);
+    return NULL;
+}
+
+int ram_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ram_addr_t addr;
+    int flags;
+
+    if (version_id < 3 || version_id > 4) {
+        return -EINVAL;
+    }
+
+    do {
+        addr = qemu_get_be64(f);
+
+        flags = addr & ~TARGET_PAGE_MASK;
+        addr &= TARGET_PAGE_MASK;
+
+        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
+            if (version_id == 3) {
+                if (addr != ram_bytes_total()) {
+                    return -EINVAL;
+                }
+            } else {
+                /* Synchronize RAM block list */
+                char id[256];
+                ram_addr_t length;
+                ram_addr_t total_ram_bytes = addr;
+
+                while (total_ram_bytes) {
+                    RAMBlock *block;
+                    uint8_t len;
+
+                    len = qemu_get_byte(f);
+                    qemu_get_buffer(f, (uint8_t *)id, len);
+                    id[len] = 0;
+                    length = qemu_get_be64(f);
+
+                    QLIST_FOREACH(block, &ram_list.blocks, next) {
+                        if (!strncmp(id, block->idstr, sizeof(id))) {
+                            if (block->length != length)
+                                return -EINVAL;
+                            break;
+                        }
+                    }
+
+                    if (!block) {
+                        fprintf(stderr, "Unknown ramblock \"%s\", cannot "
+                                "accept migration\n", id);
+                        return -EINVAL;
+                    }
+
+                    total_ram_bytes -= length;
+                }
+            }
+        }
+
+        if (flags & RAM_SAVE_FLAG_COMPRESS) {
+            void *host;
+            uint8_t ch;
+
+            if (version_id == 3)
+                host = qemu_get_ram_ptr(addr);
+            else
+                host = host_from_stream_offset(f, addr, flags);
+            if (!host) {
+                return -EINVAL;
+            }
+
+            ch = qemu_get_byte(f);
+            memset(host, ch, TARGET_PAGE_SIZE);
+#ifndef _WIN32
+            if (ch == 0 &&
+                (!kvm_enabled() || kvm_has_sync_mmu())) {
+                qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
+            }
+#endif
+        } else if (flags & RAM_SAVE_FLAG_PAGE) {
+            void *host;
+
+            if (version_id == 3)
+                host = qemu_get_ram_ptr(addr);
+            else
+                host = host_from_stream_offset(f, addr, flags);
+
+            qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+        }
+        if (qemu_file_has_error(f)) {
+            return -EIO;
+        }
+    } while (!(flags & RAM_SAVE_FLAG_EOS));
+
+    return 0;
+}
+
+void qemu_service_io(void)
+{
+    qemu_notify_event();
+}
+
+#ifdef HAS_AUDIO
+struct soundhw {
+    const char *name;
+    const char *descr;
+    int enabled;
+    int isa;
+    union {
+        int (*init_isa) (qemu_irq *pic);
+        int (*init_pci) (PCIBus *bus);
+    } init;
+};
+
+static struct soundhw soundhw[] = {
+#ifdef HAS_AUDIO_CHOICE
+#if defined(TARGET_I386) || defined(TARGET_MIPS)
+    {
+        "pcspk",
+        "PC speaker",
+        0,
+        1,
+        { .init_isa = pcspk_audio_init }
+    },
+#endif
+
+#ifdef CONFIG_SB16
+    {
+        "sb16",
+        "Creative Sound Blaster 16",
+        0,
+        1,
+        { .init_isa = SB16_init }
+    },
+#endif
+
+#ifdef CONFIG_CS4231A
+    {
+        "cs4231a",
+        "CS4231A",
+        0,
+        1,
+        { .init_isa = cs4231a_init }
+    },
+#endif
+
+#ifdef CONFIG_ADLIB
+    {
+        "adlib",
+#ifdef HAS_YMF262
+        "Yamaha YMF262 (OPL3)",
+#else
+        "Yamaha YM3812 (OPL2)",
+#endif
+        0,
+        1,
+        { .init_isa = Adlib_init }
+    },
+#endif
+
+#ifdef CONFIG_GUS
+    {
+        "gus",
+        "Gravis Ultrasound GF1",
+        0,
+        1,
+        { .init_isa = GUS_init }
+    },
+#endif
+
+#ifdef CONFIG_AC97
+    {
+        "ac97",
+        "Intel 82801AA AC97 Audio",
+        0,
+        0,
+        { .init_pci = ac97_init }
+    },
+#endif
+
+#ifdef CONFIG_ES1370
+    {
+        "es1370",
+        "ENSONIQ AudioPCI ES1370",
+        0,
+        0,
+        { .init_pci = es1370_init }
+    },
+#endif
+
+#ifdef CONFIG_HDA
+    {
+        "hda",
+        "Intel HD Audio",
+        0,
+        0,
+        { .init_pci = intel_hda_and_codec_init }
+    },
+#endif
+
+#endif /* HAS_AUDIO_CHOICE */
+
+    { NULL, NULL, 0, 0, { NULL } }
+};
+
+void select_soundhw(const char *optarg)
+{
+    struct soundhw *c;
+
+    if (*optarg == '?') {
+    show_valid_cards:
+
+        printf("Valid sound card names (comma separated):\n");
+        for (c = soundhw; c->name; ++c) {
+            printf ("%-11s %s\n", c->name, c->descr);
+        }
+        printf("\n-soundhw all will enable all of the above\n");
+        exit(*optarg != '?');
+    }
+    else {
+        size_t l;
+        const char *p;
+        char *e;
+        int bad_card = 0;
+
+        if (!strcmp(optarg, "all")) {
+            for (c = soundhw; c->name; ++c) {
+                c->enabled = 1;
+            }
+            return;
+        }
+
+        p = optarg;
+        while (*p) {
+            e = strchr(p, ',');
+            l = !e ? strlen(p) : (size_t) (e - p);
+
+            for (c = soundhw; c->name; ++c) {
+                if (!strncmp(c->name, p, l) && !c->name[l]) {
+                    c->enabled = 1;
+                    break;
+                }
+            }
+
+            if (!c->name) {
+                if (l > 80) {
+                    fprintf(stderr,
+                            "Unknown sound card name (too big to show)\n");
+                }
+                else {
+                    fprintf(stderr, "Unknown sound card name `%.*s'\n",
+                            (int) l, p);
+                }
+                bad_card = 1;
+            }
+            p += l + (e != NULL);
+        }
+
+        if (bad_card) {
+            goto show_valid_cards;
+        }
+    }
+}
+
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus)
+{
+    struct soundhw *c;
+
+    for (c = soundhw; c->name; ++c) {
+        if (c->enabled) {
+            if (c->isa) {
+                if (isa_pic) {
+                    c->init.init_isa(isa_pic);
+                }
+            } else {
+                if (pci_bus) {
+                    c->init.init_pci(pci_bus);
+                }
+            }
+        }
+    }
+}
+#else
+void select_soundhw(const char *optarg)
+{
+}
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus)
+{
+}
+#endif
+
+int qemu_uuid_parse(const char *str, uint8_t *uuid)
+{
+    int ret;
+
+    if (strlen(str) != 36) {
+        return -1;
+    }
+
+    ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
+                 &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
+                 &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14],
+                 &uuid[15]);
+
+    if (ret != 16) {
+        return -1;
+    }
+#ifdef TARGET_I386
+    smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
+#endif
+    return 0;
+}
+
+void do_acpitable_option(const char *optarg)
+{
+#ifdef TARGET_I386
+    if (acpi_table_add(optarg) < 0) {
+        fprintf(stderr, "Wrong acpi table provided\n");
+        exit(1);
+    }
+#endif
+}
+
+void do_smbios_option(const char *optarg)
+{
+#ifdef TARGET_I386
+    if (smbios_entry_add(optarg) < 0) {
+        fprintf(stderr, "Wrong smbios provided\n");
+        exit(1);
+    }
+#endif
+}
+
+void cpudef_init(void)
+{
+#if defined(cpudef_setup)
+    cpudef_setup(); /* parse cpu definitions in target config file */
+#endif
+}
+
+int audio_available(void)
+{
+#ifdef HAS_AUDIO
+    return 1;
+#else
+    return 0;
+#endif
+}
+
+int tcg_available(void)
+{
+    return 1;
+}
+
+int kvm_available(void)
+{
+#ifdef CONFIG_KVM
+    return 1;
+#else
+    return 0;
+#endif
+}
+
+int xen_available(void)
+{
+#ifdef CONFIG_XEN
+    return 1;
+#else
+    return 0;
+#endif
+}
diff --git a/qemu-0.15.x/arch_init.h b/qemu-0.15.x/arch_init.h
new file mode 100644
index 0000000..2de9f08
--- /dev/null
+++ b/qemu-0.15.x/arch_init.h
@@ -0,0 +1,34 @@
+#ifndef QEMU_ARCH_INIT_H
+#define QEMU_ARCH_INIT_H
+
+extern const char arch_config_name[];
+
+enum {
+    QEMU_ARCH_ALL = -1,
+    QEMU_ARCH_ALPHA = 1,
+    QEMU_ARCH_ARM = 2,
+    QEMU_ARCH_CRIS = 4,
+    QEMU_ARCH_I386 = 8,
+    QEMU_ARCH_M68K = 16,
+    QEMU_ARCH_LM32 = 32,
+    QEMU_ARCH_MICROBLAZE = 64,
+    QEMU_ARCH_MIPS = 128,
+    QEMU_ARCH_PPC = 256,
+    QEMU_ARCH_S390X = 512,
+    QEMU_ARCH_SH4 = 1024,
+    QEMU_ARCH_SPARC = 2048,
+};
+
+extern const uint32_t arch_type;
+
+void select_soundhw(const char *optarg);
+void do_acpitable_option(const char *optarg);
+void do_smbios_option(const char *optarg);
+void cpudef_init(void);
+int audio_available(void);
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus);
+int tcg_available(void);
+int kvm_available(void);
+int xen_available(void);
+
+#endif
diff --git a/qemu-0.15.x/arm-dis.c b/qemu-0.15.x/arm-dis.c
new file mode 100644
index 0000000..3ece02c
--- /dev/null
+++ b/qemu-0.15.x/arm-dis.c
@@ -0,0 +1,4136 @@
+/* Instruction printing code for the ARM
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   2007, Free Software Foundation, Inc.
+   Contributed by Richard Earnshaw (rwe at pegasus.esprit.ec.org)
+   Modification by James G. Smith (jsmith at cygnus.co.uk)
+
+   This file is part of libopcodes.
+
+   This program is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* Start of qemu specific additions.  Mostly this is stub definitions
+   for things we don't care about.  */
+
+#include "dis-asm.h"
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
+
+#define ARM_EXT_V1	 0
+#define ARM_EXT_V2	 0
+#define ARM_EXT_V2S	 0
+#define ARM_EXT_V3	 0
+#define ARM_EXT_V3M	 0
+#define ARM_EXT_V4	 0
+#define ARM_EXT_V4T	 0
+#define ARM_EXT_V5	 0
+#define ARM_EXT_V5T	 0
+#define ARM_EXT_V5ExP	 0
+#define ARM_EXT_V5E	 0
+#define ARM_EXT_V5J	 0
+#define ARM_EXT_V6       0
+#define ARM_EXT_V6K      0
+#define ARM_EXT_V6Z      0
+#define ARM_EXT_V6T2	 0
+#define ARM_EXT_V7	 0
+#define ARM_EXT_DIV	 0
+
+/* Co-processor space extensions.  */
+#define ARM_CEXT_XSCALE   0
+#define ARM_CEXT_MAVERICK 0
+#define ARM_CEXT_IWMMXT   0
+
+#define FPU_FPA_EXT_V1	 0
+#define FPU_FPA_EXT_V2	 0
+#define FPU_VFP_EXT_NONE 0
+#define FPU_VFP_EXT_V1xD 0
+#define FPU_VFP_EXT_V1	 0
+#define FPU_VFP_EXT_V2	 0
+#define FPU_MAVERICK	 0
+#define FPU_VFP_EXT_V3	 0
+#define FPU_NEON_EXT_V1	 0
+
+/* Assume host uses ieee float.  */
+static void floatformat_to_double (unsigned char *data, double *dest)
+{
+    union {
+        uint32_t i;
+        float f;
+    } u;
+    u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+    *dest = u.f;
+}
+
+/* End of qemu specific additions.  */
+
+/* FIXME: Belongs in global header.  */
+#ifndef strneq
+#define strneq(a,b,n)	(strncmp ((a), (b), (n)) == 0)
+#endif
+
+#ifndef NUM_ELEM
+#define NUM_ELEM(a)     (sizeof (a) / sizeof (a)[0])
+#endif
+
+struct opcode32
+{
+  unsigned long arch;		/* Architecture defining this insn.  */
+  unsigned long value, mask;	/* Recognise insn if (op&mask)==value.  */
+  const char *assembler;	/* How to disassemble this insn.  */
+};
+
+struct opcode16
+{
+  unsigned long arch;		/* Architecture defining this insn.  */
+  unsigned short value, mask;	/* Recognise insn if (op&mask)==value.  */
+  const char *assembler;	/* How to disassemble this insn.  */
+};
+
+/* print_insn_coprocessor recognizes the following format control codes:
+
+   %%			%
+
+   %c			print condition code (always bits 28-31 in ARM mode)
+   %q			print shifter argument
+   %u			print condition code (unconditional in ARM mode)
+   %A			print address for ldc/stc/ldf/stf instruction
+   %B			print vstm/vldm register list
+   %C			print vstr/vldr address operand
+   %I                   print cirrus signed shift immediate: bits 0..3|4..6
+   %F			print the COUNT field of a LFM/SFM instruction.
+   %P			print floating point precision in arithmetic insn
+   %Q			print floating point precision in ldf/stf insn
+   %R			print floating point rounding mode
+
+   %<bitfield>r		print as an ARM register
+   %<bitfield>d		print the bitfield in decimal
+   %<bitfield>k		print immediate for VFPv3 conversion instruction
+   %<bitfield>x		print the bitfield in hex
+   %<bitfield>X		print the bitfield as 1 hex digit without leading "0x"
+   %<bitfield>f		print a floating point constant if >7 else a
+			floating point register
+   %<bitfield>w         print as an iWMMXt width field - [bhwd]ss/us
+   %<bitfield>g         print as an iWMMXt 64-bit register
+   %<bitfield>G         print as an iWMMXt general purpose or control register
+   %<bitfield>D		print as a NEON D register
+   %<bitfield>Q		print as a NEON Q register
+
+   %y<code>		print a single precision VFP reg.
+			  Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
+   %z<code>		print a double precision VFP reg
+			  Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
+
+   %<bitfield>'c	print specified char iff bitfield is all ones
+   %<bitfield>`c	print specified char iff bitfield is all zeroes
+   %<bitfield>?ab...    select from array of values in big endian order
+
+   %L			print as an iWMMXt N/M width field.
+   %Z			print the Immediate of a WSHUFH instruction.
+   %l			like 'A' except use byte offsets for 'B' & 'H'
+			versions.
+   %i			print 5-bit immediate in bits 8,3..0
+			(print "32" when 0)
+   %r			print register offset address for wldt/wstr instruction
+*/
+
+/* Common coprocessor opcodes shared between Arm and Thumb-2.  */
+
+static const struct opcode32 coprocessor_opcodes[] =
+{
+  /* XScale instructions.  */
+  {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"},
+  {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"},
+
+  /* Intel Wireless MMX technology instructions.  */
+#define FIRST_IWMMXT_INSN 0x0e130130
+#define IWMMXT_INSN_COUNT 73
+  {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"},
+  {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"},
+  {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"},
+  {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"},
+  {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"},
+  {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"},
+  {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"},
+  {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"},
+  {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"},
+  {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"},
+  {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"},
+  {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"},
+  {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"},
+  {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"},
+  {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"},
+  {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"},
+  {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"},
+  {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"},
+  {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"},
+  {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"},
+  {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"},
+  {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"},
+  {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"},
+  {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"},
+  {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"},
+  {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"},
+
+  /* Floating point coprocessor (FPA) instructions */
+  {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"},
+  {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"},
+  {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"},
+  {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"},
+  {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"},
+  {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"},
+  {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"},
+  {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"},
+  {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"},
+  {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"},
+  {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
+
+  /* Register load/store */
+  {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"},
+  {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"},
+  {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"},
+  {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"},
+  {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"},
+  {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"},
+
+  /* Data transfer between ARM and NEON registers */
+  {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"},
+  {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"},
+  {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"},
+  {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"},
+  {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"},
+
+  /* Floating point coprocessor (VFP) instructions */
+  {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"},
+  {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"},
+  {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"},
+  {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"},
+  {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"},
+  {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"},
+  {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"},
+  {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"},
+  {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"},
+  {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"},
+  {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"},
+  {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"},
+  {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"},
+  {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"},
+  {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t<impl def %16-19x>, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, <impl def %16-19x>"},
+  {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"},
+  {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"},
+  {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"},
+  {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"},
+  {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"},
+  {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"},
+  {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"},
+  {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"},
+  {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"},
+  {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"},
+  {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"},
+  {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"},
+  {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"},
+  {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"},
+  {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"},
+  {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"},
+  {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"},
+  {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"},
+  {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"},
+  {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"},
+  {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"},
+  {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"},
+  {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"},
+  {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"},
+  {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"},
+  {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"},
+  {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"},
+  {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"},
+  {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"},
+  {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"},
+  {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"},
+  {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"},
+
+  /* Cirrus coprocessor instructions.  */
+  {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
+  {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"},
+  {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"},
+  {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"},
+  {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"},
+  {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"},
+  {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"},
+  {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
+  {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
+
+  /* Generic coprocessor instructions */
+  {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+  {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+  {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
+  {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+  {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+  {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"},
+  {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"},
+
+  /* V6 coprocessor instructions */
+  {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+  {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+
+  /* V5 coprocessor instructions */
+  {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"},
+  {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"},
+  {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
+  {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+  {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+
+  {0, 0, 0, 0}
+};
+
+/* Neon opcode table:  This does not encode the top byte -- that is
+   checked by the print_insn_neon routine, as it depends on whether we are
+   doing thumb32 or arm32 disassembly.  */
+
+/* print_insn_neon recognizes the following format control codes:
+
+   %%			%
+
+   %c			print condition code
+   %A			print v{st,ld}[1234] operands
+   %B			print v{st,ld}[1234] any one operands
+   %C			print v{st,ld}[1234] single->all operands
+   %D			print scalar
+   %E			print vmov, vmvn, vorr, vbic encoded constant
+   %F			print vtbl,vtbx register list
+
+   %<bitfield>r		print as an ARM register
+   %<bitfield>d		print the bitfield in decimal
+   %<bitfield>e         print the 2^N - bitfield in decimal
+   %<bitfield>D		print as a NEON D register
+   %<bitfield>Q		print as a NEON Q register
+   %<bitfield>R		print as a NEON D or Q register
+   %<bitfield>Sn	print byte scaled width limited by n
+   %<bitfield>Tn	print short scaled width limited by n
+   %<bitfield>Un	print long scaled width limited by n
+
+   %<bitfield>'c	print specified char iff bitfield is all ones
+   %<bitfield>`c	print specified char iff bitfield is all zeroes
+   %<bitfield>?ab...    select from array of values in big endian order  */
+
+static const struct opcode32 neon_opcodes[] =
+{
+  /* Extract */
+  {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"},
+  {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"},
+
+  /* Move data element to all lanes */
+  {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"},
+  {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"},
+  {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"},
+
+  /* Table lookup */
+  {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"},
+
+  /* Two registers, miscellaneous */
+  {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"},
+  {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"},
+  {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"},
+  {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"},
+  {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"},
+  {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"},
+  {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"},
+
+  /* Three registers of the same length */
+  {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"},
+  {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"},
+  {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"},
+  {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"},
+  {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"},
+
+  /* One register and an immediate value */
+  {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"},
+  {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"},
+
+  /* Two registers and a shift amount */
+  {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"},
+  {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"},
+  {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"},
+  {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"},
+  {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"},
+  {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"},
+  {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"},
+  {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"},
+  {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"},
+  {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"},
+  {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"},
+  {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"},
+  {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"},
+  {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"},
+  {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"},
+  {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"},
+  {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"},
+  {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"},
+  {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"},
+  {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"},
+  {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"},
+  {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"},
+  {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"},
+  {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"},
+  {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"},
+  {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"},
+  {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"},
+  {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"},
+
+  /* Three registers of different lengths */
+  {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"},
+  {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+  {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"},
+
+  /* Two registers and a scalar */
+  {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+  {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"},
+
+  /* Element and structure load/store */
+  {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"},
+  {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"},
+  {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"},
+  {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"},
+  {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"},
+  {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"},
+  {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"},
+  {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"},
+  {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"},
+  {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"},
+
+  {0,0 ,0, 0}
+};
+
+/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb.  All three are partially
+   ordered: they must be searched linearly from the top to obtain a correct
+   match.  */
+
+/* print_insn_arm recognizes the following format control codes:
+
+   %%			%
+
+   %a			print address for ldr/str instruction
+   %s                   print address for ldr/str halfword/signextend instruction
+   %b			print branch destination
+   %c			print condition code (always bits 28-31)
+   %m			print register mask for ldm/stm instruction
+   %o			print operand2 (immediate or register + shift)
+   %p			print 'p' iff bits 12-15 are 15
+   %t			print 't' iff bit 21 set and bit 24 clear
+   %B			print arm BLX(1) destination
+   %C			print the PSR sub type.
+   %U			print barrier type.
+   %P			print address for pli instruction.
+
+   %<bitfield>r		print as an ARM register
+   %<bitfield>d		print the bitfield in decimal
+   %<bitfield>W         print the bitfield plus one in decimal
+   %<bitfield>x		print the bitfield in hex
+   %<bitfield>X		print the bitfield as 1 hex digit without leading "0x"
+
+   %<bitfield>'c	print specified char iff bitfield is all ones
+   %<bitfield>`c	print specified char iff bitfield is all zeroes
+   %<bitfield>?ab...    select from array of values in big endian order
+
+   %e                   print arm SMI operand (bits 0..7,8..19).
+   %E			print the LSB and WIDTH fields of a BFI or BFC instruction.
+   %V                   print the 16-bit immediate field of a MOVT or MOVW instruction.  */
+
+static const struct opcode32 arm_opcodes[] =
+{
+  /* ARM instructions.  */
+  {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"},
+  {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"},
+  {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"},
+  {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+
+  /* V7 instructions.  */
+  {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"},
+  {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"},
+  {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"},
+  {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"},
+  {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"},
+
+  /* ARM V6T2 instructions.  */
+  {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"},
+  {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"},
+  {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"},
+  {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"},
+  {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"},
+  {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"},
+  {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"},
+
+  /* ARM V6Z instructions.  */
+  {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"},
+
+  /* ARM V6K instructions.  */
+  {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"},
+  {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"},
+  {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"},
+  {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"},
+  {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"},
+  {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"},
+  {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"},
+
+  /* ARM V6K NOP hints.  */
+  {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"},
+  {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"},
+  {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"},
+  {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"},
+  {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"},
+
+  /* ARM V6 instructions. */
+  {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"},
+  {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"},
+  {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"},
+  {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"},
+  {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"},
+  {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"},
+  {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"},
+  {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"},
+  {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"},
+  {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"},
+  {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"},
+  {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"},
+  {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"},
+  {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"},
+  {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"},
+  {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"},
+  {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"},
+  {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"},
+  {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"},
+  {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"},
+  {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"},
+  {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"},
+  {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"},
+  {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"},
+  {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"},
+  {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"},
+
+  /* V5J instruction.  */
+  {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"},
+
+  /* V5 Instructions.  */
+  {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"},
+  {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"},
+  {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"},
+  {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"},
+
+  /* V5E "El Segundo" Instructions.  */
+  {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"},
+  {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"},
+  {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"},
+  {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+
+  {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+  {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+
+  {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+
+  {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"},
+
+  {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"},
+  {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"},
+
+  {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0,  "qadd%c\t%12-15r, %0-3r, %16-19r"},
+  {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"},
+  {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0,  "qsub%c\t%12-15r, %0-3r, %16-19r"},
+  {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"},
+
+  /* ARM Instructions.  */
+  {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"},
+  {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"},
+  {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
+  {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"},
+  {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"},
+  {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"},
+  {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"},
+  {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"},
+  {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"},
+  {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"},
+  {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"},
+  {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"},
+  {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"},
+  {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"},
+  {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"},
+  {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"},
+  {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"},
+  {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"},
+  {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"},
+  {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"},
+  {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"},
+  {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"},
+  {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"},
+  {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"},
+  {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"},
+  {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"},
+  {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"},
+  {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"},
+  {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"},
+  {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"},
+  {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"},
+
+  /* The rest.  */
+  {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"},
+  {0, 0x00000000, 0x00000000, 0}
+};
+
+/* print_insn_thumb16 recognizes the following format control codes:
+
+   %S                   print Thumb register (bits 3..5 as high number if bit 6 set)
+   %D                   print Thumb register (bits 0..2 as high number if bit 7 set)
+   %<bitfield>I         print bitfield as a signed decimal
+   				(top bit of range being the sign bit)
+   %N                   print Thumb register mask (with LR)
+   %O                   print Thumb register mask (with PC)
+   %M                   print Thumb register mask
+   %b			print CZB's 6-bit unsigned branch destination
+   %s			print Thumb right-shift immediate (6..10; 0 == 32).
+   %c			print the condition code
+   %C			print the condition code, or "s" if not conditional
+   %x			print warning if conditional an not at end of IT block"
+   %X			print "\t; unpredictable <IT:code>" if conditional
+   %I			print IT instruction suffix and operands
+   %<bitfield>r		print bitfield as an ARM register
+   %<bitfield>d		print bitfield as a decimal
+   %<bitfield>H         print (bitfield * 2) as a decimal
+   %<bitfield>W         print (bitfield * 4) as a decimal
+   %<bitfield>a         print (bitfield * 4) as a pc-rel offset + decoded symbol
+   %<bitfield>B         print Thumb branch destination (signed displacement)
+   %<bitfield>c         print bitfield as a condition code
+   %<bitnum>'c		print specified char iff bit is one
+   %<bitnum>?ab		print a if bit is one else print b.  */
+
+static const struct opcode16 thumb_opcodes[] =
+{
+  /* Thumb instructions.  */
+
+  /* ARM V6K no-argument instructions.  */
+  {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"},
+  {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"},
+  {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"},
+  {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"},
+  {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"},
+  {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"},
+
+  /* ARM V6T2 instructions.  */
+  {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"},
+  {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"},
+  {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"},
+
+  /* ARM V6.  */
+  {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"},
+  {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"},
+  {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"},
+  {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"},
+
+  /* ARM V5 ISA extends Thumb.  */
+  {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional.  */
+  /* This is BLX(2).  BLX(1) is a 32-bit instruction.  */
+  {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"},	/* note: 4 bit register number.  */
+  /* ARM V4T ISA (Thumb v1).  */
+  {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"},
+  /* Format 4.  */
+  {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"},
+  {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"},
+  /* format 13 */
+  {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"},
+  {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\tsp, #%0-6W"},
+  /* format 5 */
+  {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"},
+  {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"},
+  {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"},
+  {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"},
+  /* format 14 */
+  {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"},
+  {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\t%O"},
+  /* format 2 */
+  {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"},
+  {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"},
+  {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"},
+  {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\t%0-2r, %3-5r, #%6-8d"},
+  /* format 8 */
+  {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"},
+  {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"},
+  {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\t%0-2r, [%3-5r, %6-8r]"},
+  /* format 7 */
+  {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"},
+  {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"},
+  /* format 1 */
+  {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"},
+  {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"},
+  {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"},
+  /* format 3 */
+  {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"},
+  {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"},
+  {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"},
+  {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\t%8-10r, #%0-7d"},
+  /* format 6 */
+  {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"},  /* TODO: Disassemble PC relative "LDR rD,=<symbolic>" */
+  /* format 9 */
+  {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"},
+  {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"},
+  {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"},
+  {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\t%0-2r, [%3-5r, #%6-10d]"},
+  /* format 10 */
+  {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"},
+  {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\t%0-2r, [%3-5r, #%6-10H]"},
+  /* format 11 */
+  {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"},
+  {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\t%8-10r, [sp, #%0-7W]"},
+  /* format 12 */
+  {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"},
+  {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"},
+  /* format 15 */
+  {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"},
+  {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"},
+  /* format 17 */
+  {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"},
+  /* format 16 */
+  {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"},
+  {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"},
+  /* format 18 */
+  {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"},
+
+  /* The E800 .. FFFF range is unconditionally redirected to the
+     32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs
+     are processed via that table.  Thus, we can never encounter a
+     bare "second half of BL/BLX(1)" instruction here.  */
+  {ARM_EXT_V1,  0x0000, 0x0000, "undefined"},
+  {0, 0, 0, 0}
+};
+
+/* Thumb32 opcodes use the same table structure as the ARM opcodes.
+   We adopt the convention that hw1 is the high 16 bits of .value and
+   .mask, hw2 the low 16 bits.
+
+   print_insn_thumb32 recognizes the following format control codes:
+
+       %%		%
+
+       %I		print a 12-bit immediate from hw1[10],hw2[14:12,7:0]
+       %M		print a modified 12-bit immediate (same location)
+       %J		print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0]
+       %K		print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4]
+       %S		print a possibly-shifted Rm
+
+       %a		print the address of a plain load/store
+       %w		print the width and signedness of a core load/store
+       %m		print register mask for ldm/stm
+
+       %E		print the lsb and width fields of a bfc/bfi instruction
+       %F		print the lsb and width fields of a sbfx/ubfx instruction
+       %b		print a conditional branch offset
+       %B		print an unconditional branch offset
+       %s		print the shift field of an SSAT instruction
+       %R		print the rotation field of an SXT instruction
+       %U		print barrier type.
+       %P		print address for pli instruction.
+       %c		print the condition code
+       %x		print warning if conditional an not at end of IT block"
+       %X		print "\t; unpredictable <IT:code>" if conditional
+
+       %<bitfield>d	print bitfield in decimal
+       %<bitfield>W	print bitfield*4 in decimal
+       %<bitfield>r	print bitfield as an ARM register
+       %<bitfield>c	print bitfield as a condition code
+
+       %<bitfield>'c	print specified char iff bitfield is all ones
+       %<bitfield>`c	print specified char iff bitfield is all zeroes
+       %<bitfield>?ab... select from array of values in big endian order
+
+   With one exception at the bottom (done because BL and BLX(1) need
+   to come dead last), this table was machine-sorted first in
+   decreasing order of number of bits set in the mask, then in
+   increasing numeric order of mask, then in increasing numeric order
+   of opcode.  This order is not the clearest for a human reader, but
+   is guaranteed never to catch a special-case bit pattern with a more
+   general mask, which is important, because this instruction encoding
+   makes heavy use of special-case bit patterns.  */
+static const struct opcode32 thumb32_opcodes[] =
+{
+  /* V7 instructions.  */
+  {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"},
+  {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"},
+  {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"},
+  {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"},
+  {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"},
+  {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"},
+
+  /* Instructions defined in the basic V6T2 set.  */
+  {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"},
+  {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"},
+  {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"},
+  {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"},
+  {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"},
+  {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"},
+
+  {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"},
+  {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"},
+  {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"},
+  {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"},
+  {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"},
+  {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"},
+  {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"},
+  {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"},
+  {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"},
+  {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"},
+  {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"},
+  {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"},
+  {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"},
+  {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"},
+  {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"},
+  {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"},
+  {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"},
+  {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"},
+  {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"},
+  {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"},
+  {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"},
+  {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"},
+  {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"},
+  {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"},
+  {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"},
+  {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"},
+  {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"},
+  {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"},
+  {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"},
+  {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"},
+  {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"},
+  {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"},
+  {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"},
+  {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"},
+  {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"},
+  {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"},
+  {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"},
+  {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"},
+  {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"},
+  {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"},
+  {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"},
+  {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"},
+  {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"},
+  {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"},
+  {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"},
+  {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"},
+  {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"},
+  {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"},
+  {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"},
+  {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"},
+  {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"},
+  {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"},
+  {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"},
+  {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"},
+  {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"},
+  {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"},
+  {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"},
+  {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"},
+  {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"},
+
+  /* Filter out Bcc with cond=E or F, which are used for other instructions.  */
+  {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"},
+  {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"},
+  {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"},
+  {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"},
+
+  /* These have been 32-bit since the invention of Thumb.  */
+  {ARM_EXT_V4T,  0xf000c000, 0xf800d000, "blx%c\t%B%x"},
+  {ARM_EXT_V4T,  0xf000d000, 0xf800d000, "bl%c\t%B%x"},
+
+  /* Fallback.  */
+  {ARM_EXT_V1,   0x00000000, 0x00000000, "undefined"},
+  {0, 0, 0, 0}
+};
+
+static const char *const arm_conditional[] =
+{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al", "<und>", ""};
+
+static const char *const arm_fp_const[] =
+{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
+
+static const char *const arm_shift[] =
+{"lsl", "lsr", "asr", "ror"};
+
+typedef struct
+{
+  const char *name;
+  const char *description;
+  const char *reg_names[16];
+}
+arm_regname;
+
+static const arm_regname regnames[] =
+{
+  { "raw" , "Select raw register names",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
+  { "gcc",  "Select register names used by GCC",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
+  { "std",  "Select register names used in ARM's ISA documentation",
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp",  "lr",  "pc" }},
+  { "apcs", "Select register names used in the APCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
+  { "atpcs", "Select register names used in the ATPCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  "v8",  "IP",  "SP",  "LR",  "PC" }},
+  { "special-atpcs", "Select special register names used in the ATPCS",
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }},
+};
+
+static const char *const iwmmxt_wwnames[] =
+{"b", "h", "w", "d"};
+
+static const char *const iwmmxt_wwssnames[] =
+{"b", "bus", "bc", "bss",
+ "h", "hus", "hc", "hss",
+ "w", "wus", "wc", "wss",
+ "d", "dus", "dc", "dss"
+};
+
+static const char *const iwmmxt_regnames[] =
+{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+  "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15"
+};
+
+static const char *const iwmmxt_cregnames[] =
+{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved",
+  "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved"
+};
+
+/* Default to GCC register name set.  */
+static unsigned int regname_selected = 1;
+
+#define NUM_ARM_REGNAMES  NUM_ELEM (regnames)
+#define arm_regnames      regnames[regname_selected].reg_names
+
+static bfd_boolean force_thumb = false;
+
+/* Current IT instruction state.  This contains the same state as the IT
+   bits in the CPSR.  */
+static unsigned int ifthen_state;
+/* IT state for the next instruction.  */
+static unsigned int ifthen_next_state;
+/* The address of the insn for which the IT state is valid.  */
+static bfd_vma ifthen_address;
+#define IFTHEN_COND ((ifthen_state >> 4) & 0xf)
+
+/* Cached mapping symbol state.  */
+enum map_type {
+  MAP_ARM,
+  MAP_THUMB,
+  MAP_DATA
+};
+
+enum map_type last_type;
+int last_mapping_sym = -1;
+bfd_vma last_mapping_addr = 0;
+
+/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?.
+   Returns pointer to following character of the format string and
+   fills in *VALUEP and *WIDTHP with the extracted value and number of
+   bits extracted.  WIDTHP can be NULL. */
+
+static const char *
+arm_decode_bitfield (const char *ptr, unsigned long insn,
+		     unsigned long *valuep, int *widthp)
+{
+  unsigned long value = 0;
+  int width = 0;
+
+  do
+    {
+      int start, end;
+      int bits;
+
+      for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++)
+	start = start * 10 + *ptr - '0';
+      if (*ptr == '-')
+	for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++)
+	  end = end * 10 + *ptr - '0';
+      else
+	end = start;
+      bits = end - start;
+      if (bits < 0)
+	abort ();
+      value |= ((insn >> start) & ((2ul << bits) - 1)) << width;
+      width += bits + 1;
+    }
+  while (*ptr++ == ',');
+  *valuep = value;
+  if (widthp)
+    *widthp = width;
+  return ptr - 1;
+}
+
+static void
+arm_decode_shift (long given, fprintf_function func, void *stream,
+		  int print_shift)
+{
+  func (stream, "%s", arm_regnames[given & 0xf]);
+
+  if ((given & 0xff0) != 0)
+    {
+      if ((given & 0x10) == 0)
+	{
+	  int amount = (given & 0xf80) >> 7;
+	  int shift = (given & 0x60) >> 5;
+
+	  if (amount == 0)
+	    {
+	      if (shift == 3)
+		{
+		  func (stream, ", rrx");
+		  return;
+		}
+
+	      amount = 32;
+	    }
+
+	  if (print_shift)
+	    func (stream, ", %s #%d", arm_shift[shift], amount);
+	  else
+	    func (stream, ", #%d", amount);
+	}
+      else if (print_shift)
+	func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
+	      arm_regnames[(given & 0xf00) >> 8]);
+      else
+	func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]);
+    }
+}
+
+/* Print one coprocessor instruction on INFO->STREAM.
+   Return true if the instuction matched, false if this is not a
+   recognised coprocessor instruction.  */
+
+static bfd_boolean
+print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given,
+			bfd_boolean thumb)
+{
+  const struct opcode32 *insn;
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+  unsigned long mask;
+  unsigned long value;
+  int cond;
+
+  for (insn = coprocessor_opcodes; insn->assembler; insn++)
+    {
+      if (insn->value == FIRST_IWMMXT_INSN
+	  && info->mach != bfd_mach_arm_XScale
+	  && info->mach != bfd_mach_arm_iWMMXt
+	  && info->mach != bfd_mach_arm_iWMMXt2)
+	insn = insn + IWMMXT_INSN_COUNT;
+
+      mask = insn->mask;
+      value = insn->value;
+      if (thumb)
+	{
+	  /* The high 4 bits are 0xe for Arm conditional instructions, and
+	     0xe for arm unconditional instructions.  The rest of the
+	     encoding is the same.  */
+	  mask |= 0xf0000000;
+	  value |= 0xe0000000;
+	  if (ifthen_state)
+	    cond = IFTHEN_COND;
+	  else
+	    cond = 16;
+	}
+      else
+	{
+	  /* Only match unconditional instuctions against unconditional
+	     patterns.  */
+	  if ((given & 0xf0000000) == 0xf0000000)
+	    {
+	      mask |= 0xf0000000;
+	      cond = 16;
+	    }
+	  else
+	    {
+	      cond = (given >> 28) & 0xf;
+	      if (cond == 0xe)
+		cond = 16;
+	    }
+	}
+      if ((given & mask) == value)
+	{
+	  const char *c;
+
+	  for (c = insn->assembler; *c; c++)
+	    {
+	      if (*c == '%')
+		{
+		  switch (*++c)
+		    {
+		    case '%':
+		      func (stream, "%%");
+		      break;
+
+		    case 'A':
+		      func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+
+		      if ((given & (1 << 24)) != 0)
+			{
+			  int offset = given & 0xff;
+
+			  if (offset)
+			    func (stream, ", #%s%d]%s",
+				  ((given & 0x00800000) == 0 ? "-" : ""),
+				  offset * 4,
+				  ((given & 0x00200000) != 0 ? "!" : ""));
+			  else
+			    func (stream, "]");
+			}
+		      else
+			{
+			  int offset = given & 0xff;
+
+			  func (stream, "]");
+
+			  if (given & (1 << 21))
+			    {
+			      if (offset)
+				func (stream, ", #%s%d",
+				      ((given & 0x00800000) == 0 ? "-" : ""),
+				      offset * 4);
+			    }
+			  else
+			    func (stream, ", {%d}", offset);
+			}
+		      break;
+
+		    case 'B':
+		      {
+			int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10);
+			int offset = (given >> 1) & 0x3f;
+
+			if (offset == 1)
+			  func (stream, "{d%d}", regno);
+			else if (regno + offset > 32)
+			  func (stream, "{d%d-<overflow reg d%d>}", regno, regno + offset - 1);
+			else
+			  func (stream, "{d%d-d%d}", regno, regno + offset - 1);
+		      }
+		      break;
+
+		    case 'C':
+		      {
+			int rn = (given >> 16) & 0xf;
+			int offset = (given & 0xff) * 4;
+			int add = (given >> 23) & 1;
+
+			func (stream, "[%s", arm_regnames[rn]);
+
+			if (offset)
+			  {
+			    if (!add)
+			      offset = -offset;
+			    func (stream, ", #%d", offset);
+			  }
+			func (stream, "]");
+			if (rn == 15)
+			  {
+			    func (stream, "\t; ");
+                            /* FIXME: Unsure if info->bytes_per_chunk is the
+                               right thing to use here.  */
+			    info->print_address_func (offset + pc
+                              + info->bytes_per_chunk * 2, info);
+			  }
+		      }
+		      break;
+
+		    case 'c':
+		      func (stream, "%s", arm_conditional[cond]);
+		      break;
+
+		    case 'I':
+		      /* Print a Cirrus/DSP shift immediate.  */
+		      /* Immediates are 7bit signed ints with bits 0..3 in
+			 bits 0..3 of opcode and bits 4..6 in bits 5..7
+			 of opcode.  */
+		      {
+			int imm;
+
+			imm = (given & 0xf) | ((given & 0xe0) >> 1);
+
+			/* Is ``imm'' a negative number?  */
+			if (imm & 0x40)
+			  imm |= (-1 << 7);
+
+			func (stream, "%d", imm);
+		      }
+
+		      break;
+
+		    case 'F':
+		      switch (given & 0x00408000)
+			{
+			case 0:
+			  func (stream, "4");
+			  break;
+			case 0x8000:
+			  func (stream, "1");
+			  break;
+			case 0x00400000:
+			  func (stream, "2");
+			  break;
+			default:
+			  func (stream, "3");
+			}
+		      break;
+
+		    case 'P':
+		      switch (given & 0x00080080)
+			{
+			case 0:
+			  func (stream, "s");
+			  break;
+			case 0x80:
+			  func (stream, "d");
+			  break;
+			case 0x00080000:
+			  func (stream, "e");
+			  break;
+			default:
+			  func (stream, _("<illegal precision>"));
+			  break;
+			}
+		      break;
+		    case 'Q':
+		      switch (given & 0x00408000)
+			{
+			case 0:
+			  func (stream, "s");
+			  break;
+			case 0x8000:
+			  func (stream, "d");
+			  break;
+			case 0x00400000:
+			  func (stream, "e");
+			  break;
+			default:
+			  func (stream, "p");
+			  break;
+			}
+		      break;
+		    case 'R':
+		      switch (given & 0x60)
+			{
+			case 0:
+			  break;
+			case 0x20:
+			  func (stream, "p");
+			  break;
+			case 0x40:
+			  func (stream, "m");
+			  break;
+			default:
+			  func (stream, "z");
+			  break;
+			}
+		      break;
+
+		    case '0': case '1': case '2': case '3': case '4':
+		    case '5': case '6': case '7': case '8': case '9':
+		      {
+			int width;
+			unsigned long value;
+
+			c = arm_decode_bitfield (c, given, &value, &width);
+
+			switch (*c)
+			  {
+			  case 'r':
+			    func (stream, "%s", arm_regnames[value]);
+			    break;
+			  case 'D':
+			    func (stream, "d%ld", value);
+			    break;
+			  case 'Q':
+			    if (value & 1)
+			      func (stream, "<illegal reg q%ld.5>", value >> 1);
+			    else
+			      func (stream, "q%ld", value >> 1);
+			    break;
+			  case 'd':
+			    func (stream, "%ld", value);
+			    break;
+                          case 'k':
+                            {
+                              int from = (given & (1 << 7)) ? 32 : 16;
+                              func (stream, "%ld", from - value);
+                            }
+                            break;
+
+			  case 'f':
+			    if (value > 7)
+			      func (stream, "#%s", arm_fp_const[value & 7]);
+			    else
+			      func (stream, "f%ld", value);
+			    break;
+
+			  case 'w':
+			    if (width == 2)
+			      func (stream, "%s", iwmmxt_wwnames[value]);
+			    else
+			      func (stream, "%s", iwmmxt_wwssnames[value]);
+			    break;
+
+			  case 'g':
+			    func (stream, "%s", iwmmxt_regnames[value]);
+			    break;
+			  case 'G':
+			    func (stream, "%s", iwmmxt_cregnames[value]);
+			    break;
+
+			  case 'x':
+			    func (stream, "0x%lx", value);
+			    break;
+
+			  case '`':
+			    c++;
+			    if (value == 0)
+			      func (stream, "%c", *c);
+			    break;
+			  case '\'':
+			    c++;
+			    if (value == ((1ul << width) - 1))
+			      func (stream, "%c", *c);
+			    break;
+			  case '?':
+			    func (stream, "%c", c[(1 << width) - (int)value]);
+			    c += 1 << width;
+			    break;
+			  default:
+			    abort ();
+			  }
+			break;
+
+		      case 'y':
+		      case 'z':
+			{
+			  int single = *c++ == 'y';
+			  int regno;
+
+			  switch (*c)
+			    {
+			    case '4': /* Sm pair */
+			      func (stream, "{");
+			      /* Fall through.  */
+			    case '0': /* Sm, Dm */
+			      regno = given & 0x0000000f;
+			      if (single)
+				{
+				  regno <<= 1;
+				  regno += (given >> 5) & 1;
+				}
+                              else
+                                regno += ((given >> 5) & 1) << 4;
+			      break;
+
+			    case '1': /* Sd, Dd */
+			      regno = (given >> 12) & 0x0000000f;
+			      if (single)
+				{
+				  regno <<= 1;
+				  regno += (given >> 22) & 1;
+				}
+                              else
+                                regno += ((given >> 22) & 1) << 4;
+			      break;
+
+			    case '2': /* Sn, Dn */
+			      regno = (given >> 16) & 0x0000000f;
+			      if (single)
+				{
+				  regno <<= 1;
+				  regno += (given >> 7) & 1;
+				}
+                              else
+                                regno += ((given >> 7) & 1) << 4;
+			      break;
+
+			    case '3': /* List */
+			      func (stream, "{");
+			      regno = (given >> 12) & 0x0000000f;
+			      if (single)
+				{
+				  regno <<= 1;
+				  regno += (given >> 22) & 1;
+				}
+                              else
+                                regno += ((given >> 22) & 1) << 4;
+			      break;
+
+			    default:
+			      abort ();
+			    }
+
+			  func (stream, "%c%d", single ? 's' : 'd', regno);
+
+			  if (*c == '3')
+			    {
+			      int count = given & 0xff;
+
+			      if (single == 0)
+				count >>= 1;
+
+			      if (--count)
+				{
+				  func (stream, "-%c%d",
+					single ? 's' : 'd',
+					regno + count);
+				}
+
+			      func (stream, "}");
+			    }
+			  else if (*c == '4')
+			    func (stream, ", %c%d}", single ? 's' : 'd',
+				  regno + 1);
+			}
+			break;
+
+		      case 'L':
+			switch (given & 0x00400100)
+			  {
+			  case 0x00000000: func (stream, "b"); break;
+			  case 0x00400000: func (stream, "h"); break;
+			  case 0x00000100: func (stream, "w"); break;
+			  case 0x00400100: func (stream, "d"); break;
+			  default:
+			    break;
+			  }
+			break;
+
+		      case 'Z':
+			{
+			  int value;
+			  /* given (20, 23) | given (0, 3) */
+			  value = ((given >> 16) & 0xf0) | (given & 0xf);
+			  func (stream, "%d", value);
+			}
+			break;
+
+		      case 'l':
+			/* This is like the 'A' operator, except that if
+			   the width field "M" is zero, then the offset is
+			   *not* multiplied by four.  */
+			{
+			  int offset = given & 0xff;
+			  int multiplier = (given & 0x00000100) ? 4 : 1;
+
+			  func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+
+			  if (offset)
+			    {
+			      if ((given & 0x01000000) != 0)
+				func (stream, ", #%s%d]%s",
+				      ((given & 0x00800000) == 0 ? "-" : ""),
+				      offset * multiplier,
+				      ((given & 0x00200000) != 0 ? "!" : ""));
+			      else
+				func (stream, "], #%s%d",
+				      ((given & 0x00800000) == 0 ? "-" : ""),
+				      offset * multiplier);
+			    }
+			  else
+			    func (stream, "]");
+			}
+			break;
+
+		      case 'r':
+			{
+			  int imm4 = (given >> 4) & 0xf;
+			  int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1);
+			  int ubit = (given >> 23) & 1;
+			  const char *rm = arm_regnames [given & 0xf];
+			  const char *rn = arm_regnames [(given >> 16) & 0xf];
+
+			  switch (puw_bits)
+			    {
+			    case 1:
+			      /* fall through */
+			    case 3:
+			      func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm);
+			      if (imm4)
+				func (stream, ", lsl #%d", imm4);
+			      break;
+
+			    case 4:
+			      /* fall through */
+			    case 5:
+			      /* fall through */
+			    case 6:
+			      /* fall through */
+			    case 7:
+			      func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm);
+			      if (imm4 > 0)
+				func (stream, ", lsl #%d", imm4);
+			      func (stream, "]");
+			      if (puw_bits == 5 || puw_bits == 7)
+				func (stream, "!");
+			      break;
+
+			    default:
+			      func (stream, "INVALID");
+			    }
+			}
+			break;
+
+		      case 'i':
+			{
+			  long imm5;
+			  imm5 = ((given & 0x100) >> 4) | (given & 0xf);
+			  func (stream, "%ld", (imm5 == 0) ? 32 : imm5);
+			}
+			break;
+
+		      default:
+			abort ();
+		      }
+		    }
+		}
+	      else
+		func (stream, "%c", *c);
+	    }
+	  return true;
+	}
+    }
+  return false;
+}
+
+static void
+print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
+{
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+
+  if (((given & 0x000f0000) == 0x000f0000)
+      && ((given & 0x02000000) == 0))
+    {
+      int offset = given & 0xfff;
+
+      func (stream, "[pc");
+
+      if (given & 0x01000000)
+	{
+	  if ((given & 0x00800000) == 0)
+	    offset = - offset;
+
+	  /* Pre-indexed.  */
+	  func (stream, ", #%d]", offset);
+
+	  offset += pc + 8;
+
+	  /* Cope with the possibility of write-back
+	     being used.  Probably a very dangerous thing
+	     for the programmer to do, but who are we to
+	     argue ?  */
+	  if (given & 0x00200000)
+	    func (stream, "!");
+	}
+      else
+	{
+	  /* Post indexed.  */
+	  func (stream, "], #%d", offset);
+
+	  /* ie ignore the offset.  */
+	  offset = pc + 8;
+	}
+
+      func (stream, "\t; ");
+      info->print_address_func (offset, info);
+    }
+  else
+    {
+      func (stream, "[%s",
+	    arm_regnames[(given >> 16) & 0xf]);
+      if ((given & 0x01000000) != 0)
+	{
+	  if ((given & 0x02000000) == 0)
+	    {
+	      int offset = given & 0xfff;
+	      if (offset)
+		func (stream, ", #%s%d",
+		      (((given & 0x00800000) == 0)
+		       ? "-" : ""), offset);
+	    }
+	  else
+	    {
+	      func (stream, ", %s",
+		    (((given & 0x00800000) == 0)
+		     ? "-" : ""));
+	      arm_decode_shift (given, func, stream, 1);
+	    }
+
+	  func (stream, "]%s",
+		((given & 0x00200000) != 0) ? "!" : "");
+	}
+      else
+	{
+	  if ((given & 0x02000000) == 0)
+	    {
+	      int offset = given & 0xfff;
+	      if (offset)
+		func (stream, "], #%s%d",
+		      (((given & 0x00800000) == 0)
+		       ? "-" : ""), offset);
+	      else
+		func (stream, "]");
+	    }
+	  else
+	    {
+	      func (stream, "], %s",
+		    (((given & 0x00800000) == 0)
+		     ? "-" : ""));
+	      arm_decode_shift (given, func, stream, 1);
+	    }
+	}
+    }
+}
+
+/* Print one neon instruction on INFO->STREAM.
+   Return true if the instuction matched, false if this is not a
+   recognised neon instruction.  */
+
+static bfd_boolean
+print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
+{
+  const struct opcode32 *insn;
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+
+  if (thumb)
+    {
+      if ((given & 0xef000000) == 0xef000000)
+	{
+	  /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding.  */
+	  unsigned long bit28 = given & (1 << 28);
+
+	  given &= 0x00ffffff;
+	  if (bit28)
+            given |= 0xf3000000;
+          else
+	    given |= 0xf2000000;
+	}
+      else if ((given & 0xff000000) == 0xf9000000)
+	given ^= 0xf9000000 ^ 0xf4000000;
+      else
+	return false;
+    }
+
+  for (insn = neon_opcodes; insn->assembler; insn++)
+    {
+      if ((given & insn->mask) == insn->value)
+	{
+	  const char *c;
+
+	  for (c = insn->assembler; *c; c++)
+	    {
+	      if (*c == '%')
+		{
+		  switch (*++c)
+		    {
+		    case '%':
+		      func (stream, "%%");
+		      break;
+
+		    case 'c':
+		      if (thumb && ifthen_state)
+			func (stream, "%s", arm_conditional[IFTHEN_COND]);
+		      break;
+
+		    case 'A':
+		      {
+			static const unsigned char enc[16] =
+			{
+			  0x4, 0x14, /* st4 0,1 */
+			  0x4, /* st1 2 */
+			  0x4, /* st2 3 */
+			  0x3, /* st3 4 */
+			  0x13, /* st3 5 */
+			  0x3, /* st1 6 */
+			  0x1, /* st1 7 */
+			  0x2, /* st2 8 */
+			  0x12, /* st2 9 */
+			  0x2, /* st1 10 */
+			  0, 0, 0, 0, 0
+			};
+			int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4);
+			int rn = ((given >> 16) & 0xf);
+			int rm = ((given >> 0) & 0xf);
+			int align = ((given >> 4) & 0x3);
+			int type = ((given >> 8) & 0xf);
+			int n = enc[type] & 0xf;
+			int stride = (enc[type] >> 4) + 1;
+			int ix;
+
+			func (stream, "{");
+			if (stride > 1)
+			  for (ix = 0; ix != n; ix++)
+			    func (stream, "%sd%d", ix ? "," : "", rd + ix * stride);
+			else if (n == 1)
+			  func (stream, "d%d", rd);
+			else
+			  func (stream, "d%d-d%d", rd, rd + n - 1);
+			func (stream, "}, [%s", arm_regnames[rn]);
+			if (align)
+			  func (stream, ", :%d", 32 << align);
+			func (stream, "]");
+			if (rm == 0xd)
+			  func (stream, "!");
+			else if (rm != 0xf)
+			  func (stream, ", %s", arm_regnames[rm]);
+		      }
+		      break;
+
+		    case 'B':
+		      {
+			int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4);
+			int rn = ((given >> 16) & 0xf);
+			int rm = ((given >> 0) & 0xf);
+			int idx_align = ((given >> 4) & 0xf);
+                        int align = 0;
+			int size = ((given >> 10) & 0x3);
+			int idx = idx_align >> (size + 1);
+                        int length = ((given >> 8) & 3) + 1;
+                        int stride = 1;
+                        int i;
+
+                        if (length > 1 && size > 0)
+                          stride = (idx_align & (1 << size)) ? 2 : 1;
+
+                        switch (length)
+                          {
+                          case 1:
+                            {
+                              int amask = (1 << size) - 1;
+                              if ((idx_align & (1 << size)) != 0)
+                                return false;
+                              if (size > 0)
+                                {
+                                  if ((idx_align & amask) == amask)
+                                    align = 8 << size;
+                                  else if ((idx_align & amask) != 0)
+                                    return false;
+                                }
+                              }
+                            break;
+
+                          case 2:
+                            if (size == 2 && (idx_align & 2) != 0)
+                              return false;
+                            align = (idx_align & 1) ? 16 << size : 0;
+                            break;
+
+                          case 3:
+                            if ((size == 2 && (idx_align & 3) != 0)
+                                || (idx_align & 1) != 0)
+                              return false;
+                            break;
+
+                          case 4:
+                            if (size == 2)
+                              {
+                                if ((idx_align & 3) == 3)
+                                  return false;
+                                align = (idx_align & 3) * 64;
+                              }
+                            else
+                              align = (idx_align & 1) ? 32 << size : 0;
+                            break;
+
+                          default:
+                            abort ();
+                          }
+
+			func (stream, "{");
+                        for (i = 0; i < length; i++)
+                          func (stream, "%sd%d[%d]", (i == 0) ? "" : ",",
+                            rd + i * stride, idx);
+                        func (stream, "}, [%s", arm_regnames[rn]);
+			if (align)
+			  func (stream, ", :%d", align);
+			func (stream, "]");
+			if (rm == 0xd)
+			  func (stream, "!");
+			else if (rm != 0xf)
+			  func (stream, ", %s", arm_regnames[rm]);
+		      }
+		      break;
+
+		    case 'C':
+		      {
+			int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4);
+			int rn = ((given >> 16) & 0xf);
+			int rm = ((given >> 0) & 0xf);
+			int align = ((given >> 4) & 0x1);
+			int size = ((given >> 6) & 0x3);
+			int type = ((given >> 8) & 0x3);
+			int n = type + 1;
+			int stride = ((given >> 5) & 0x1);
+			int ix;
+
+			if (stride && (n == 1))
+			  n++;
+			else
+			  stride++;
+
+			func (stream, "{");
+			if (stride > 1)
+			  for (ix = 0; ix != n; ix++)
+			    func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride);
+			else if (n == 1)
+			  func (stream, "d%d[]", rd);
+			else
+			  func (stream, "d%d[]-d%d[]", rd, rd + n - 1);
+			func (stream, "}, [%s", arm_regnames[rn]);
+			if (align)
+			  {
+                            int align = (8 * (type + 1)) << size;
+                            if (type == 3)
+                              align = (size > 1) ? align >> 1 : align;
+			    if (type == 2 || (type == 0 && !size))
+			      func (stream, ", :<bad align %d>", align);
+			    else
+			      func (stream, ", :%d", align);
+			  }
+			func (stream, "]");
+			if (rm == 0xd)
+			  func (stream, "!");
+			else if (rm != 0xf)
+			  func (stream, ", %s", arm_regnames[rm]);
+		      }
+		      break;
+
+		    case 'D':
+		      {
+			int raw_reg = (given & 0xf) | ((given >> 1) & 0x10);
+			int size = (given >> 20) & 3;
+			int reg = raw_reg & ((4 << size) - 1);
+			int ix = raw_reg >> size >> 2;
+
+			func (stream, "d%d[%d]", reg, ix);
+		      }
+		      break;
+
+		    case 'E':
+		      /* Neon encoded constant for mov, mvn, vorr, vbic */
+		      {
+			int bits = 0;
+			int cmode = (given >> 8) & 0xf;
+			int op = (given >> 5) & 0x1;
+			unsigned long value = 0, hival = 0;
+			unsigned shift;
+                        int size = 0;
+                        int isfloat = 0;
+
+			bits |= ((given >> 24) & 1) << 7;
+			bits |= ((given >> 16) & 7) << 4;
+			bits |= ((given >> 0) & 15) << 0;
+
+			if (cmode < 8)
+			  {
+			    shift = (cmode >> 1) & 3;
+			    value = (unsigned long)bits << (8 * shift);
+                            size = 32;
+			  }
+			else if (cmode < 12)
+			  {
+			    shift = (cmode >> 1) & 1;
+			    value = (unsigned long)bits << (8 * shift);
+                            size = 16;
+			  }
+			else if (cmode < 14)
+			  {
+			    shift = (cmode & 1) + 1;
+			    value = (unsigned long)bits << (8 * shift);
+			    value |= (1ul << (8 * shift)) - 1;
+                            size = 32;
+			  }
+			else if (cmode == 14)
+			  {
+			    if (op)
+			      {
+				/* bit replication into bytes */
+				int ix;
+				unsigned long mask;
+
+				value = 0;
+                                hival = 0;
+				for (ix = 7; ix >= 0; ix--)
+				  {
+				    mask = ((bits >> ix) & 1) ? 0xff : 0;
+                                    if (ix <= 3)
+				      value = (value << 8) | mask;
+                                    else
+                                      hival = (hival << 8) | mask;
+				  }
+                                size = 64;
+			      }
+                            else
+                              {
+                                /* byte replication */
+                                value = (unsigned long)bits;
+                                size = 8;
+                              }
+			  }
+			else if (!op)
+			  {
+			    /* floating point encoding */
+			    int tmp;
+
+			    value = (unsigned long)(bits & 0x7f) << 19;
+			    value |= (unsigned long)(bits & 0x80) << 24;
+			    tmp = bits & 0x40 ? 0x3c : 0x40;
+			    value |= (unsigned long)tmp << 24;
+                            size = 32;
+                            isfloat = 1;
+			  }
+			else
+			  {
+			    func (stream, "<illegal constant %.8x:%x:%x>",
+                                  bits, cmode, op);
+			    break;
+			  }
+                        switch (size)
+                          {
+                          case 8:
+			    func (stream, "#%ld\t; 0x%.2lx", value, value);
+                            break;
+
+                          case 16:
+                            func (stream, "#%ld\t; 0x%.4lx", value, value);
+                            break;
+
+                          case 32:
+                            if (isfloat)
+                              {
+                                unsigned char valbytes[4];
+                                double fvalue;
+
+                                /* Do this a byte at a time so we don't have to
+                                   worry about the host's endianness.  */
+                                valbytes[0] = value & 0xff;
+                                valbytes[1] = (value >> 8) & 0xff;
+                                valbytes[2] = (value >> 16) & 0xff;
+                                valbytes[3] = (value >> 24) & 0xff;
+
+                                floatformat_to_double (valbytes, &fvalue);
+
+                                func (stream, "#%.7g\t; 0x%.8lx", fvalue,
+                                      value);
+                              }
+                            else
+                              func (stream, "#%ld\t; 0x%.8lx",
+				(long) ((value & 0x80000000)
+					? value | ~0xffffffffl : value), value);
+                            break;
+
+                          case 64:
+                            func (stream, "#0x%.8lx%.8lx", hival, value);
+                            break;
+
+                          default:
+                            abort ();
+                          }
+		      }
+		      break;
+
+		    case 'F':
+		      {
+			int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10);
+			int num = (given >> 8) & 0x3;
+
+			if (!num)
+			  func (stream, "{d%d}", regno);
+			else if (num + regno >= 32)
+			  func (stream, "{d%d-<overflow reg d%d}", regno, regno + num);
+			else
+			  func (stream, "{d%d-d%d}", regno, regno + num);
+		      }
+		      break;
+
+
+		    case '0': case '1': case '2': case '3': case '4':
+		    case '5': case '6': case '7': case '8': case '9':
+		      {
+			int width;
+			unsigned long value;
+
+			c = arm_decode_bitfield (c, given, &value, &width);
+
+			switch (*c)
+			  {
+			  case 'r':
+			    func (stream, "%s", arm_regnames[value]);
+			    break;
+			  case 'd':
+			    func (stream, "%ld", value);
+			    break;
+			  case 'e':
+			    func (stream, "%ld", (1ul << width) - value);
+			    break;
+
+			  case 'S':
+			  case 'T':
+			  case 'U':
+			    /* various width encodings */
+			    {
+			      int base = 8 << (*c - 'S'); /* 8,16 or 32 */
+			      int limit;
+			      unsigned low, high;
+
+			      c++;
+			      if (*c >= '0' && *c <= '9')
+				limit = *c - '0';
+			      else if (*c >= 'a' && *c <= 'f')
+				limit = *c - 'a' + 10;
+			      else
+				abort ();
+			      low = limit >> 2;
+			      high = limit & 3;
+
+			      if (value < low || value > high)
+				func (stream, "<illegal width %d>", base << value);
+			      else
+				func (stream, "%d", base << value);
+			    }
+			    break;
+			  case 'R':
+			    if (given & (1 << 6))
+			      goto Q;
+			    /* FALLTHROUGH */
+			  case 'D':
+			    func (stream, "d%ld", value);
+			    break;
+			  case 'Q':
+			  Q:
+			    if (value & 1)
+			      func (stream, "<illegal reg q%ld.5>", value >> 1);
+			    else
+			      func (stream, "q%ld", value >> 1);
+			    break;
+
+			  case '`':
+			    c++;
+			    if (value == 0)
+			      func (stream, "%c", *c);
+			    break;
+			  case '\'':
+			    c++;
+			    if (value == ((1ul << width) - 1))
+			      func (stream, "%c", *c);
+			    break;
+			  case '?':
+			    func (stream, "%c", c[(1 << width) - (int)value]);
+			    c += 1 << width;
+			    break;
+			  default:
+			    abort ();
+			  }
+			break;
+
+		      default:
+			abort ();
+		      }
+		    }
+		}
+	      else
+		func (stream, "%c", *c);
+	    }
+	  return true;
+	}
+    }
+  return false;
+}
+
+/* Print one ARM instruction from PC on INFO->STREAM.  */
+
+static void
+print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given)
+{
+  const struct opcode32 *insn;
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+
+  if (print_insn_coprocessor (pc, info, given, false))
+    return;
+
+  if (print_insn_neon (info, given, false))
+    return;
+
+  for (insn = arm_opcodes; insn->assembler; insn++)
+    {
+      if (insn->value == FIRST_IWMMXT_INSN
+	  && info->mach != bfd_mach_arm_XScale
+	  && info->mach != bfd_mach_arm_iWMMXt)
+	insn = insn + IWMMXT_INSN_COUNT;
+
+      if ((given & insn->mask) == insn->value
+	  /* Special case: an instruction with all bits set in the condition field
+	     (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask,
+	     or by the catchall at the end of the table.  */
+	  && ((given & 0xF0000000) != 0xF0000000
+	      || (insn->mask & 0xF0000000) == 0xF0000000
+	      || (insn->mask == 0 && insn->value == 0)))
+	{
+	  const char *c;
+
+	  for (c = insn->assembler; *c; c++)
+	    {
+	      if (*c == '%')
+		{
+		  switch (*++c)
+		    {
+		    case '%':
+		      func (stream, "%%");
+		      break;
+
+		    case 'a':
+		      print_arm_address (pc, info, given);
+		      break;
+
+		    case 'P':
+		      /* Set P address bit and use normal address
+			 printing routine.  */
+		      print_arm_address (pc, info, given | (1 << 24));
+		      break;
+
+		    case 's':
+                      if ((given & 0x004f0000) == 0x004f0000)
+			{
+                          /* PC relative with immediate offset.  */
+			  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+
+			  if ((given & 0x00800000) == 0)
+			    offset = -offset;
+
+			  func (stream, "[pc, #%d]\t; ", offset);
+			  info->print_address_func (offset + pc + 8, info);
+			}
+		      else
+			{
+			  func (stream, "[%s",
+				arm_regnames[(given >> 16) & 0xf]);
+			  if ((given & 0x01000000) != 0)
+			    {
+                              /* Pre-indexed.  */
+			      if ((given & 0x00400000) == 0x00400000)
+				{
+                                  /* Immediate.  */
+                                  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+				  if (offset)
+				    func (stream, ", #%s%d",
+					  (((given & 0x00800000) == 0)
+					   ? "-" : ""), offset);
+				}
+			      else
+				{
+                                  /* Register.  */
+				  func (stream, ", %s%s",
+					(((given & 0x00800000) == 0)
+					 ? "-" : ""),
+                                        arm_regnames[given & 0xf]);
+				}
+
+			      func (stream, "]%s",
+				    ((given & 0x00200000) != 0) ? "!" : "");
+			    }
+			  else
+			    {
+                              /* Post-indexed.  */
+			      if ((given & 0x00400000) == 0x00400000)
+				{
+                                  /* Immediate.  */
+                                  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+				  if (offset)
+				    func (stream, "], #%s%d",
+					  (((given & 0x00800000) == 0)
+					   ? "-" : ""), offset);
+				  else
+				    func (stream, "]");
+				}
+			      else
+				{
+                                  /* Register.  */
+				  func (stream, "], %s%s",
+					(((given & 0x00800000) == 0)
+					 ? "-" : ""),
+                                        arm_regnames[given & 0xf]);
+				}
+			    }
+			}
+		      break;
+
+		    case 'b':
+		      {
+			int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000);
+			info->print_address_func (disp*4 + pc + 8, info);
+		      }
+		      break;
+
+		    case 'c':
+		      if (((given >> 28) & 0xf) != 0xe)
+			func (stream, "%s",
+			      arm_conditional [(given >> 28) & 0xf]);
+		      break;
+
+		    case 'm':
+		      {
+			int started = 0;
+			int reg;
+
+			func (stream, "{");
+			for (reg = 0; reg < 16; reg++)
+			  if ((given & (1 << reg)) != 0)
+			    {
+			      if (started)
+				func (stream, ", ");
+			      started = 1;
+			      func (stream, "%s", arm_regnames[reg]);
+			    }
+			func (stream, "}");
+		      }
+		      break;
+
+		    case 'q':
+		      arm_decode_shift (given, func, stream, 0);
+		      break;
+
+		    case 'o':
+		      if ((given & 0x02000000) != 0)
+			{
+			  int rotate = (given & 0xf00) >> 7;
+			  int immed = (given & 0xff);
+			  immed = (((immed << (32 - rotate))
+				    | (immed >> rotate)) & 0xffffffff);
+			  func (stream, "#%d\t; 0x%x", immed, immed);
+			}
+		      else
+			arm_decode_shift (given, func, stream, 1);
+		      break;
+
+		    case 'p':
+		      if ((given & 0x0000f000) == 0x0000f000)
+			func (stream, "p");
+		      break;
+
+		    case 't':
+		      if ((given & 0x01200000) == 0x00200000)
+			func (stream, "t");
+		      break;
+
+		    case 'A':
+		      func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+
+		      if ((given & (1 << 24)) != 0)
+			{
+			  int offset = given & 0xff;
+
+			  if (offset)
+			    func (stream, ", #%s%d]%s",
+				  ((given & 0x00800000) == 0 ? "-" : ""),
+				  offset * 4,
+				  ((given & 0x00200000) != 0 ? "!" : ""));
+			  else
+			    func (stream, "]");
+			}
+		      else
+			{
+			  int offset = given & 0xff;
+
+			  func (stream, "]");
+
+			  if (given & (1 << 21))
+			    {
+			      if (offset)
+				func (stream, ", #%s%d",
+				      ((given & 0x00800000) == 0 ? "-" : ""),
+				      offset * 4);
+			    }
+			  else
+			    func (stream, ", {%d}", offset);
+			}
+		      break;
+
+		    case 'B':
+		      /* Print ARM V5 BLX(1) address: pc+25 bits.  */
+		      {
+			bfd_vma address;
+			bfd_vma offset = 0;
+
+			if (given & 0x00800000)
+			  /* Is signed, hi bits should be ones.  */
+			  offset = (-1) ^ 0x00ffffff;
+
+			/* Offset is (SignExtend(offset field)<<2).  */
+			offset += given & 0x00ffffff;
+			offset <<= 2;
+			address = offset + pc + 8;
+
+			if (given & 0x01000000)
+			  /* H bit allows addressing to 2-byte boundaries.  */
+			  address += 2;
+
+		        info->print_address_func (address, info);
+		      }
+		      break;
+
+		    case 'C':
+		      func (stream, "_");
+		      if (given & 0x80000)
+			func (stream, "f");
+		      if (given & 0x40000)
+			func (stream, "s");
+		      if (given & 0x20000)
+			func (stream, "x");
+		      if (given & 0x10000)
+			func (stream, "c");
+		      break;
+
+		    case 'U':
+		      switch (given & 0xf)
+			{
+			case 0xf: func(stream, "sy"); break;
+			case 0x7: func(stream, "un"); break;
+			case 0xe: func(stream, "st"); break;
+			case 0x6: func(stream, "unst"); break;
+			default:
+			  func(stream, "#%d", (int)given & 0xf);
+			  break;
+			}
+		      break;
+
+		    case '0': case '1': case '2': case '3': case '4':
+		    case '5': case '6': case '7': case '8': case '9':
+		      {
+			int width;
+			unsigned long value;
+
+			c = arm_decode_bitfield (c, given, &value, &width);
+
+			switch (*c)
+			  {
+			  case 'r':
+			    func (stream, "%s", arm_regnames[value]);
+			    break;
+			  case 'd':
+			    func (stream, "%ld", value);
+			    break;
+			  case 'b':
+			    func (stream, "%ld", value * 8);
+			    break;
+			  case 'W':
+			    func (stream, "%ld", value + 1);
+			    break;
+			  case 'x':
+			    func (stream, "0x%08lx", value);
+
+			    /* Some SWI instructions have special
+			       meanings.  */
+			    if ((given & 0x0fffffff) == 0x0FF00000)
+			      func (stream, "\t; IMB");
+			    else if ((given & 0x0fffffff) == 0x0FF00001)
+			      func (stream, "\t; IMBRange");
+			    break;
+			  case 'X':
+			    func (stream, "%01lx", value & 0xf);
+			    break;
+			  case '`':
+			    c++;
+			    if (value == 0)
+			      func (stream, "%c", *c);
+			    break;
+			  case '\'':
+			    c++;
+			    if (value == ((1ul << width) - 1))
+			      func (stream, "%c", *c);
+			    break;
+			  case '?':
+			    func (stream, "%c", c[(1 << width) - (int)value]);
+			    c += 1 << width;
+			    break;
+			  default:
+			    abort ();
+			  }
+			break;
+
+		      case 'e':
+			{
+			  int imm;
+
+			  imm = (given & 0xf) | ((given & 0xfff00) >> 4);
+			  func (stream, "%d", imm);
+			}
+			break;
+
+		      case 'E':
+			/* LSB and WIDTH fields of BFI or BFC.  The machine-
+			   language instruction encodes LSB and MSB.  */
+			{
+			  long msb = (given & 0x001f0000) >> 16;
+			  long lsb = (given & 0x00000f80) >> 7;
+
+			  long width = msb - lsb + 1;
+			  if (width > 0)
+			    func (stream, "#%lu, #%lu", lsb, width);
+			  else
+			    func (stream, "(invalid: %lu:%lu)", lsb, msb);
+			}
+			break;
+
+		      case 'V':
+			/* 16-bit unsigned immediate from a MOVT or MOVW
+			   instruction, encoded in bits 0:11 and 15:19.  */
+			{
+			  long hi = (given & 0x000f0000) >> 4;
+			  long lo = (given & 0x00000fff);
+			  long imm16 = hi | lo;
+			  func (stream, "#%lu\t; 0x%lx", imm16, imm16);
+			}
+			break;
+
+		      default:
+			abort ();
+		      }
+		    }
+		}
+	      else
+		func (stream, "%c", *c);
+	    }
+	  return;
+	}
+    }
+  abort ();
+}
+
+/* Print one 16-bit Thumb instruction from PC on INFO->STREAM.  */
+
+static void
+print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
+{
+  const struct opcode16 *insn;
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+
+  for (insn = thumb_opcodes; insn->assembler; insn++)
+    if ((given & insn->mask) == insn->value)
+      {
+	const char *c = insn->assembler;
+	for (; *c; c++)
+	  {
+	    int domaskpc = 0;
+	    int domasklr = 0;
+
+	    if (*c != '%')
+	      {
+		func (stream, "%c", *c);
+		continue;
+	      }
+
+	    switch (*++c)
+	      {
+	      case '%':
+		func (stream, "%%");
+		break;
+
+	      case 'c':
+		if (ifthen_state)
+		  func (stream, "%s", arm_conditional[IFTHEN_COND]);
+		break;
+
+	      case 'C':
+		if (ifthen_state)
+		  func (stream, "%s", arm_conditional[IFTHEN_COND]);
+		else
+		  func (stream, "s");
+		break;
+
+	      case 'I':
+		{
+		  unsigned int tmp;
+
+		  ifthen_next_state = given & 0xff;
+		  for (tmp = given << 1; tmp & 0xf; tmp <<= 1)
+		    func (stream, ((given ^ tmp) & 0x10) ? "e" : "t");
+		  func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]);
+		}
+		break;
+
+	      case 'x':
+		if (ifthen_next_state)
+		  func (stream, "\t; unpredictable branch in IT block\n");
+		break;
+
+	      case 'X':
+		if (ifthen_state)
+		  func (stream, "\t; unpredictable <IT:%s>",
+			arm_conditional[IFTHEN_COND]);
+		break;
+
+	      case 'S':
+		{
+		  long reg;
+
+		  reg = (given >> 3) & 0x7;
+		  if (given & (1 << 6))
+		    reg += 8;
+
+		  func (stream, "%s", arm_regnames[reg]);
+		}
+		break;
+
+	      case 'D':
+		{
+		  long reg;
+
+		  reg = given & 0x7;
+		  if (given & (1 << 7))
+		    reg += 8;
+
+		  func (stream, "%s", arm_regnames[reg]);
+		}
+		break;
+
+	      case 'N':
+		if (given & (1 << 8))
+		  domasklr = 1;
+		/* Fall through.  */
+	      case 'O':
+		if (*c == 'O' && (given & (1 << 8)))
+		  domaskpc = 1;
+		/* Fall through.  */
+	      case 'M':
+		{
+		  int started = 0;
+		  int reg;
+
+		  func (stream, "{");
+
+		  /* It would be nice if we could spot
+		     ranges, and generate the rS-rE format: */
+		  for (reg = 0; (reg < 8); reg++)
+		    if ((given & (1 << reg)) != 0)
+		      {
+			if (started)
+			  func (stream, ", ");
+			started = 1;
+			func (stream, "%s", arm_regnames[reg]);
+		      }
+
+		  if (domasklr)
+		    {
+		      if (started)
+			func (stream, ", ");
+		      started = 1;
+		      func (stream, "%s", arm_regnames[14] /* "lr" */);
+		    }
+
+		  if (domaskpc)
+		    {
+		      if (started)
+			func (stream, ", ");
+		      func (stream, "%s", arm_regnames[15] /* "pc" */);
+		    }
+
+		  func (stream, "}");
+		}
+		break;
+
+	      case 'b':
+		/* Print ARM V6T2 CZB address: pc+4+6 bits.  */
+		{
+		  bfd_vma address = (pc + 4
+				     + ((given & 0x00f8) >> 2)
+				     + ((given & 0x0200) >> 3));
+		  info->print_address_func (address, info);
+		}
+		break;
+
+	      case 's':
+		/* Right shift immediate -- bits 6..10; 1-31 print
+		   as themselves, 0 prints as 32.  */
+		{
+		  long imm = (given & 0x07c0) >> 6;
+		  if (imm == 0)
+		    imm = 32;
+		  func (stream, "#%ld", imm);
+		}
+		break;
+
+	      case '0': case '1': case '2': case '3': case '4':
+	      case '5': case '6': case '7': case '8': case '9':
+		{
+		  int bitstart = *c++ - '0';
+		  int bitend = 0;
+
+		  while (*c >= '0' && *c <= '9')
+		    bitstart = (bitstart * 10) + *c++ - '0';
+
+		  switch (*c)
+		    {
+		    case '-':
+		      {
+			long reg;
+
+			c++;
+			while (*c >= '0' && *c <= '9')
+			  bitend = (bitend * 10) + *c++ - '0';
+			if (!bitend)
+			  abort ();
+			reg = given >> bitstart;
+			reg &= (2 << (bitend - bitstart)) - 1;
+			switch (*c)
+			  {
+			  case 'r':
+			    func (stream, "%s", arm_regnames[reg]);
+			    break;
+
+			  case 'd':
+			    func (stream, "%ld", reg);
+			    break;
+
+			  case 'H':
+			    func (stream, "%ld", reg << 1);
+			    break;
+
+			  case 'W':
+			    func (stream, "%ld", reg << 2);
+			    break;
+
+			  case 'a':
+			    /* PC-relative address -- the bottom two
+			       bits of the address are dropped
+			       before the calculation.  */
+			    info->print_address_func
+			      (((pc + 4) & ~3) + (reg << 2), info);
+			    break;
+
+			  case 'x':
+			    func (stream, "0x%04lx", reg);
+			    break;
+
+			  case 'B':
+			    reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+			    info->print_address_func (reg * 2 + pc + 4, info);
+			    break;
+
+			  case 'c':
+			    func (stream, "%s", arm_conditional [reg]);
+			    break;
+
+			  default:
+			    abort ();
+			  }
+		      }
+		      break;
+
+		    case '\'':
+		      c++;
+		      if ((given & (1 << bitstart)) != 0)
+			func (stream, "%c", *c);
+		      break;
+
+		    case '?':
+		      ++c;
+		      if ((given & (1 << bitstart)) != 0)
+			func (stream, "%c", *c++);
+		      else
+			func (stream, "%c", *++c);
+		      break;
+
+		    default:
+		      abort ();
+		    }
+		}
+		break;
+
+	      default:
+		abort ();
+	      }
+	  }
+	return;
+      }
+
+  /* No match.  */
+  abort ();
+}
+
+/* Return the name of an V7M special register.  */
+static const char *
+psr_name (int regno)
+{
+  switch (regno)
+    {
+    case 0: return "APSR";
+    case 1: return "IAPSR";
+    case 2: return "EAPSR";
+    case 3: return "PSR";
+    case 5: return "IPSR";
+    case 6: return "EPSR";
+    case 7: return "IEPSR";
+    case 8: return "MSP";
+    case 9: return "PSP";
+    case 16: return "PRIMASK";
+    case 17: return "BASEPRI";
+    case 18: return "BASEPRI_MASK";
+    case 19: return "FAULTMASK";
+    case 20: return "CONTROL";
+    default: return "<unknown>";
+    }
+}
+
+/* Print one 32-bit Thumb instruction from PC on INFO->STREAM.  */
+
+static void
+print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
+{
+  const struct opcode32 *insn;
+  void *stream = info->stream;
+  fprintf_function func = info->fprintf_func;
+
+  if (print_insn_coprocessor (pc, info, given, true))
+    return;
+
+  if (print_insn_neon (info, given, true))
+    return;
+
+  for (insn = thumb32_opcodes; insn->assembler; insn++)
+    if ((given & insn->mask) == insn->value)
+      {
+	const char *c = insn->assembler;
+	for (; *c; c++)
+	  {
+	    if (*c != '%')
+	      {
+		func (stream, "%c", *c);
+		continue;
+	      }
+
+	    switch (*++c)
+	      {
+	      case '%':
+		func (stream, "%%");
+		break;
+
+	      case 'c':
+		if (ifthen_state)
+		  func (stream, "%s", arm_conditional[IFTHEN_COND]);
+		break;
+
+	      case 'x':
+		if (ifthen_next_state)
+		  func (stream, "\t; unpredictable branch in IT block\n");
+		break;
+
+	      case 'X':
+		if (ifthen_state)
+		  func (stream, "\t; unpredictable <IT:%s>",
+			arm_conditional[IFTHEN_COND]);
+		break;
+
+	      case 'I':
+		{
+		  unsigned int imm12 = 0;
+		  imm12 |= (given & 0x000000ffu);
+		  imm12 |= (given & 0x00007000u) >> 4;
+		  imm12 |= (given & 0x04000000u) >> 15;
+		  func (stream, "#%u\t; 0x%x", imm12, imm12);
+		}
+		break;
+
+	      case 'M':
+		{
+		  unsigned int bits = 0, imm, imm8, mod;
+		  bits |= (given & 0x000000ffu);
+		  bits |= (given & 0x00007000u) >> 4;
+		  bits |= (given & 0x04000000u) >> 15;
+		  imm8 = (bits & 0x0ff);
+		  mod = (bits & 0xf00) >> 8;
+		  switch (mod)
+		    {
+		    case 0: imm = imm8; break;
+		    case 1: imm = ((imm8<<16) | imm8); break;
+		    case 2: imm = ((imm8<<24) | (imm8 << 8)); break;
+		    case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break;
+		    default:
+		      mod  = (bits & 0xf80) >> 7;
+		      imm8 = (bits & 0x07f) | 0x80;
+		      imm  = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff);
+		    }
+		  func (stream, "#%u\t; 0x%x", imm, imm);
+		}
+		break;
+
+	      case 'J':
+		{
+		  unsigned int imm = 0;
+		  imm |= (given & 0x000000ffu);
+		  imm |= (given & 0x00007000u) >> 4;
+		  imm |= (given & 0x04000000u) >> 15;
+		  imm |= (given & 0x000f0000u) >> 4;
+		  func (stream, "#%u\t; 0x%x", imm, imm);
+		}
+		break;
+
+	      case 'K':
+		{
+		  unsigned int imm = 0;
+		  imm |= (given & 0x000f0000u) >> 16;
+		  imm |= (given & 0x00000ff0u) >> 0;
+		  imm |= (given & 0x0000000fu) << 12;
+		  func (stream, "#%u\t; 0x%x", imm, imm);
+		}
+		break;
+
+	      case 'S':
+		{
+		  unsigned int reg = (given & 0x0000000fu);
+		  unsigned int stp = (given & 0x00000030u) >> 4;
+		  unsigned int imm = 0;
+		  imm |= (given & 0x000000c0u) >> 6;
+		  imm |= (given & 0x00007000u) >> 10;
+
+		  func (stream, "%s", arm_regnames[reg]);
+		  switch (stp)
+		    {
+		    case 0:
+		      if (imm > 0)
+			func (stream, ", lsl #%u", imm);
+		      break;
+
+		    case 1:
+		      if (imm == 0)
+			imm = 32;
+		      func (stream, ", lsr #%u", imm);
+		      break;
+
+		    case 2:
+		      if (imm == 0)
+			imm = 32;
+		      func (stream, ", asr #%u", imm);
+		      break;
+
+		    case 3:
+		      if (imm == 0)
+			func (stream, ", rrx");
+		      else
+			func (stream, ", ror #%u", imm);
+		    }
+		}
+		break;
+
+	      case 'a':
+		{
+		  unsigned int Rn  = (given & 0x000f0000) >> 16;
+		  unsigned int U   = (given & 0x00800000) >> 23;
+		  unsigned int op  = (given & 0x00000f00) >> 8;
+		  unsigned int i12 = (given & 0x00000fff);
+		  unsigned int i8  = (given & 0x000000ff);
+		  bfd_boolean writeback = false, postind = false;
+		  int offset = 0;
+
+		  func (stream, "[%s", arm_regnames[Rn]);
+		  if (U) /* 12-bit positive immediate offset */
+		    offset = i12;
+		  else if (Rn == 15) /* 12-bit negative immediate offset */
+		    offset = -(int)i12;
+		  else if (op == 0x0) /* shifted register offset */
+		    {
+		      unsigned int Rm = (i8 & 0x0f);
+		      unsigned int sh = (i8 & 0x30) >> 4;
+		      func (stream, ", %s", arm_regnames[Rm]);
+		      if (sh)
+			func (stream, ", lsl #%u", sh);
+		      func (stream, "]");
+		      break;
+		    }
+		  else switch (op)
+		    {
+		    case 0xE:  /* 8-bit positive immediate offset */
+		      offset = i8;
+		      break;
+
+		    case 0xC:  /* 8-bit negative immediate offset */
+		      offset = -i8;
+		      break;
+
+		    case 0xF:  /* 8-bit + preindex with wb */
+		      offset = i8;
+		      writeback = true;
+		      break;
+
+		    case 0xD:  /* 8-bit - preindex with wb */
+		      offset = -i8;
+		      writeback = true;
+		      break;
+
+		    case 0xB:  /* 8-bit + postindex */
+		      offset = i8;
+		      postind = true;
+		      break;
+
+		    case 0x9:  /* 8-bit - postindex */
+		      offset = -i8;
+		      postind = true;
+		      break;
+
+		    default:
+		      func (stream, ", <undefined>]");
+		      goto skip;
+		    }
+
+		  if (postind)
+		    func (stream, "], #%d", offset);
+		  else
+		    {
+		      if (offset)
+			func (stream, ", #%d", offset);
+		      func (stream, writeback ? "]!" : "]");
+		    }
+
+		  if (Rn == 15)
+		    {
+		      func (stream, "\t; ");
+		      info->print_address_func (((pc + 4) & ~3) + offset, info);
+		    }
+		}
+	      skip:
+		break;
+
+	      case 'A':
+		{
+		  unsigned int P   = (given & 0x01000000) >> 24;
+		  unsigned int U   = (given & 0x00800000) >> 23;
+		  unsigned int W   = (given & 0x00400000) >> 21;
+		  unsigned int Rn  = (given & 0x000f0000) >> 16;
+		  unsigned int off = (given & 0x000000ff);
+
+		  func (stream, "[%s", arm_regnames[Rn]);
+		  if (P)
+		    {
+		      if (off || !U)
+			func (stream, ", #%c%u", U ? '+' : '-', off * 4);
+		      func (stream, "]");
+		      if (W)
+			func (stream, "!");
+		    }
+		  else
+		    {
+		      func (stream, "], ");
+		      if (W)
+			func (stream, "#%c%u", U ? '+' : '-', off * 4);
+		      else
+			func (stream, "{%u}", off);
+		    }
+		}
+		break;
+
+	      case 'w':
+		{
+		  unsigned int Sbit = (given & 0x01000000) >> 24;
+		  unsigned int type = (given & 0x00600000) >> 21;
+		  switch (type)
+		    {
+		    case 0: func (stream, Sbit ? "sb" : "b"); break;
+		    case 1: func (stream, Sbit ? "sh" : "h"); break;
+		    case 2:
+		      if (Sbit)
+			func (stream, "??");
+		      break;
+		    case 3:
+		      func (stream, "??");
+		      break;
+		    }
+		}
+		break;
+
+	      case 'm':
+		{
+		  int started = 0;
+		  int reg;
+
+		  func (stream, "{");
+		  for (reg = 0; reg < 16; reg++)
+		    if ((given & (1 << reg)) != 0)
+		      {
+			if (started)
+			  func (stream, ", ");
+			started = 1;
+			func (stream, "%s", arm_regnames[reg]);
+		      }
+		  func (stream, "}");
+		}
+		break;
+
+	      case 'E':
+		{
+		  unsigned int msb = (given & 0x0000001f);
+		  unsigned int lsb = 0;
+		  lsb |= (given & 0x000000c0u) >> 6;
+		  lsb |= (given & 0x00007000u) >> 10;
+		  func (stream, "#%u, #%u", lsb, msb - lsb + 1);
+		}
+		break;
+
+	      case 'F':
+		{
+		  unsigned int width = (given & 0x0000001f) + 1;
+		  unsigned int lsb = 0;
+		  lsb |= (given & 0x000000c0u) >> 6;
+		  lsb |= (given & 0x00007000u) >> 10;
+		  func (stream, "#%u, #%u", lsb, width);
+		}
+		break;
+
+	      case 'b':
+		{
+		  unsigned int S = (given & 0x04000000u) >> 26;
+		  unsigned int J1 = (given & 0x00002000u) >> 13;
+		  unsigned int J2 = (given & 0x00000800u) >> 11;
+		  int offset = 0;
+
+		  offset |= !S << 20;
+		  offset |= J2 << 19;
+		  offset |= J1 << 18;
+		  offset |= (given & 0x003f0000) >> 4;
+		  offset |= (given & 0x000007ff) << 1;
+		  offset -= (1 << 20);
+
+		  info->print_address_func (pc + 4 + offset, info);
+		}
+		break;
+
+	      case 'B':
+		{
+		  unsigned int S = (given & 0x04000000u) >> 26;
+		  unsigned int I1 = (given & 0x00002000u) >> 13;
+		  unsigned int I2 = (given & 0x00000800u) >> 11;
+		  int offset = 0;
+
+		  offset |= !S << 24;
+		  offset |= !(I1 ^ S) << 23;
+		  offset |= !(I2 ^ S) << 22;
+		  offset |= (given & 0x03ff0000u) >> 4;
+		  offset |= (given & 0x000007ffu) << 1;
+		  offset -= (1 << 24);
+		  offset += pc + 4;
+
+		  /* BLX target addresses are always word aligned.  */
+		  if ((given & 0x00001000u) == 0)
+		      offset &= ~2u;
+
+		  info->print_address_func (offset, info);
+		}
+		break;
+
+	      case 's':
+		{
+		  unsigned int shift = 0;
+		  shift |= (given & 0x000000c0u) >> 6;
+		  shift |= (given & 0x00007000u) >> 10;
+		  if (given & 0x00200000u)
+		    func (stream, ", asr #%u", shift);
+		  else if (shift)
+		    func (stream, ", lsl #%u", shift);
+		  /* else print nothing - lsl #0 */
+		}
+		break;
+
+	      case 'R':
+		{
+		  unsigned int rot = (given & 0x00000030) >> 4;
+		  if (rot)
+		    func (stream, ", ror #%u", rot * 8);
+		}
+		break;
+
+	      case 'U':
+		switch (given & 0xf)
+		  {
+		  case 0xf: func(stream, "sy"); break;
+		  case 0x7: func(stream, "un"); break;
+		  case 0xe: func(stream, "st"); break;
+		  case 0x6: func(stream, "unst"); break;
+		  default:
+		    func(stream, "#%d", (int)given & 0xf);
+		    break;
+		  }
+		break;
+
+	      case 'C':
+		if ((given & 0xff) == 0)
+		  {
+		    func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C');
+		    if (given & 0x800)
+		      func (stream, "f");
+		    if (given & 0x400)
+		      func (stream, "s");
+		    if (given & 0x200)
+		      func (stream, "x");
+		    if (given & 0x100)
+		      func (stream, "c");
+		  }
+		else
+		  {
+		    func (stream, "%s", psr_name (given & 0xff));
+		  }
+		break;
+
+	      case 'D':
+		if ((given & 0xff) == 0)
+		  func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
+		else
+		  func (stream, "%s", psr_name (given & 0xff));
+		break;
+
+	      case '0': case '1': case '2': case '3': case '4':
+	      case '5': case '6': case '7': case '8': case '9':
+		{
+		  int width;
+		  unsigned long val;
+
+		  c = arm_decode_bitfield (c, given, &val, &width);
+
+		  switch (*c)
+		    {
+		    case 'd': func (stream, "%lu", val); break;
+		    case 'W': func (stream, "%lu", val * 4); break;
+		    case 'r': func (stream, "%s", arm_regnames[val]); break;
+
+		    case 'c':
+		      func (stream, "%s", arm_conditional[val]);
+		      break;
+
+		    case '\'':
+		      c++;
+		      if (val == ((1ul << width) - 1))
+			func (stream, "%c", *c);
+		      break;
+
+		    case '`':
+		      c++;
+		      if (val == 0)
+			func (stream, "%c", *c);
+		      break;
+
+		    case '?':
+		      func (stream, "%c", c[(1 << width) - (int)val]);
+		      c += 1 << width;
+		      break;
+
+		    default:
+		      abort ();
+		    }
+		}
+		break;
+
+	      default:
+		abort ();
+	      }
+	  }
+	return;
+      }
+
+  /* No match.  */
+  abort ();
+}
+
+/* Print data bytes on INFO->STREAM.  */
+
+static void
+print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info,
+		 long given)
+{
+  switch (info->bytes_per_chunk)
+    {
+    case 1:
+      info->fprintf_func (info->stream, ".byte\t0x%02lx", given);
+      break;
+    case 2:
+      info->fprintf_func (info->stream, ".short\t0x%04lx", given);
+      break;
+    case 4:
+      info->fprintf_func (info->stream, ".word\t0x%08lx", given);
+      break;
+    default:
+      abort ();
+    }
+}
+
+/* Search back through the insn stream to determine if this instruction is
+   conditionally executed.  */
+static void
+find_ifthen_state (bfd_vma pc, struct disassemble_info *info,
+		   bfd_boolean little)
+{
+  unsigned char b[2];
+  unsigned int insn;
+  int status;
+  /* COUNT is twice the number of instructions seen.  It will be odd if we
+     just crossed an instruction boundary.  */
+  int count;
+  int it_count;
+  unsigned int seen_it;
+  bfd_vma addr;
+
+  ifthen_address = pc;
+  ifthen_state = 0;
+
+  addr = pc;
+  count = 1;
+  it_count = 0;
+  seen_it = 0;
+  /* Scan backwards looking for IT instructions, keeping track of where
+     instruction boundaries are.  We don't know if something is actually an
+     IT instruction until we find a definite instruction boundary.  */
+  for (;;)
+    {
+      if (addr == 0 || info->symbol_at_address_func(addr, info))
+	{
+	  /* A symbol must be on an instruction boundary, and will not
+	     be within an IT block.  */
+	  if (seen_it && (count & 1))
+	    break;
+
+	  return;
+	}
+      addr -= 2;
+      status = info->read_memory_func (addr, (bfd_byte *)b, 2, info);
+      if (status)
+	return;
+
+      if (little)
+	insn = (b[0]) | (b[1] << 8);
+      else
+	insn = (b[1]) | (b[0] << 8);
+      if (seen_it)
+	{
+	  if ((insn & 0xf800) < 0xe800)
+	    {
+	      /* Addr + 2 is an instruction boundary.  See if this matches
+	         the expected boundary based on the position of the last
+		 IT candidate.  */
+	      if (count & 1)
+		break;
+	      seen_it = 0;
+	    }
+	}
+      if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0)
+	{
+	  /* This could be an IT instruction.  */
+	  seen_it = insn;
+	  it_count = count >> 1;
+	}
+      if ((insn & 0xf800) >= 0xe800)
+	count++;
+      else
+	count = (count + 2) | 1;
+      /* IT blocks contain at most 4 instructions.  */
+      if (count >= 8 && !seen_it)
+	return;
+    }
+  /* We found an IT instruction.  */
+  ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f);
+  if ((ifthen_state & 0xf) == 0)
+    ifthen_state = 0;
+}
+
+/* NOTE: There are no checks in these routines that
+   the relevant number of data bytes exist.  */
+
+int
+print_insn_arm (bfd_vma pc, struct disassemble_info *info)
+{
+  unsigned char b[4];
+  long		given;
+  int           status;
+  int           is_thumb = false;
+  int           is_data = false;
+  unsigned int	size = 4;
+  void	 	(*printer) (bfd_vma, struct disassemble_info *, long);
+#if 0
+  bfd_boolean   found = false;
+
+  if (info->disassembler_options)
+    {
+      parse_disassembler_options (info->disassembler_options);
+
+      /* To avoid repeated parsing of these options, we remove them here.  */
+      info->disassembler_options = NULL;
+    }
+
+  /* First check the full symtab for a mapping symbol, even if there
+     are no usable non-mapping symbols for this address.  */
+  if (info->symtab != NULL
+      && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour)
+    {
+      bfd_vma addr;
+      int n;
+      int last_sym = -1;
+      enum map_type type = MAP_ARM;
+
+      if (pc <= last_mapping_addr)
+	last_mapping_sym = -1;
+      is_thumb = (last_type == MAP_THUMB);
+      found = false;
+      /* Start scanning at the start of the function, or wherever
+	 we finished last time.  */
+      n = info->symtab_pos + 1;
+      if (n < last_mapping_sym)
+	n = last_mapping_sym;
+
+      /* Scan up to the location being disassembled.  */
+      for (; n < info->symtab_size; n++)
+	{
+	  addr = bfd_asymbol_value (info->symtab[n]);
+	  if (addr > pc)
+	    break;
+	  if ((info->section == NULL
+	       || info->section == info->symtab[n]->section)
+	      && get_sym_code_type (info, n, &type))
+	    {
+	      last_sym = n;
+	      found = true;
+	    }
+	}
+
+      if (!found)
+	{
+	  n = info->symtab_pos;
+	  if (n < last_mapping_sym - 1)
+	    n = last_mapping_sym - 1;
+
+	  /* No mapping symbol found at this address.  Look backwards
+	     for a preceeding one.  */
+	  for (; n >= 0; n--)
+	    {
+	      if (get_sym_code_type (info, n, &type))
+		{
+		  last_sym = n;
+		  found = true;
+		  break;
+		}
+	    }
+	}
+
+      last_mapping_sym = last_sym;
+      last_type = type;
+      is_thumb = (last_type == MAP_THUMB);
+      is_data = (last_type == MAP_DATA);
+
+      /* Look a little bit ahead to see if we should print out
+	 two or four bytes of data.  If there's a symbol,
+	 mapping or otherwise, after two bytes then don't
+	 print more.  */
+      if (is_data)
+	{
+	  size = 4 - (pc & 3);
+	  for (n = last_sym + 1; n < info->symtab_size; n++)
+	    {
+	      addr = bfd_asymbol_value (info->symtab[n]);
+	      if (addr > pc)
+		{
+		  if (addr - pc < size)
+		    size = addr - pc;
+		  break;
+		}
+	    }
+	  /* If the next symbol is after three bytes, we need to
+	     print only part of the data, so that we can use either
+	     .byte or .short.  */
+	  if (size == 3)
+	    size = (pc & 1) ? 1 : 2;
+	}
+    }
+
+  if (info->symbols != NULL)
+    {
+      if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
+	{
+	  coff_symbol_type * cs;
+
+	  cs = coffsymbol (*info->symbols);
+	  is_thumb = (   cs->native->u.syment.n_sclass == C_THUMBEXT
+		      || cs->native->u.syment.n_sclass == C_THUMBSTAT
+		      || cs->native->u.syment.n_sclass == C_THUMBLABEL
+		      || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
+		      || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
+	}
+      else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour
+	       && !found)
+	{
+	  /* If no mapping symbol has been found then fall back to the type
+	     of the function symbol.  */
+	  elf_symbol_type *  es;
+	  unsigned int       type;
+
+	  es = *(elf_symbol_type **)(info->symbols);
+	  type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
+
+	  is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
+	}
+    }
+#else
+  int little;
+
+  little = (info->endian == BFD_ENDIAN_LITTLE);
+  is_thumb |= (pc & 1);
+  pc &= ~(bfd_vma)1;
+#endif
+
+  if (force_thumb)
+    is_thumb = true;
+
+  info->bytes_per_line = 4;
+
+  if (is_data)
+    {
+      int i;
+
+      /* size was already set above.  */
+      info->bytes_per_chunk = size;
+      printer = print_insn_data;
+
+      status = info->read_memory_func (pc, (bfd_byte *)b, size, info);
+      given = 0;
+      if (little)
+	for (i = size - 1; i >= 0; i--)
+	  given = b[i] | (given << 8);
+      else
+	for (i = 0; i < (int) size; i++)
+	  given = b[i] | (given << 8);
+    }
+  else if (!is_thumb)
+    {
+      /* In ARM mode endianness is a straightforward issue: the instruction
+	 is four bytes long and is either ordered 0123 or 3210.  */
+      printer = print_insn_arm_internal;
+      info->bytes_per_chunk = 4;
+      size = 4;
+
+      status = info->read_memory_func (pc, (bfd_byte *)b, 4, info);
+      if (little)
+	given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
+      else
+	given = (b[3]) | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
+    }
+  else
+    {
+      /* In Thumb mode we have the additional wrinkle of two
+	 instruction lengths.  Fortunately, the bits that determine
+	 the length of the current instruction are always to be found
+	 in the first two bytes.  */
+      printer = print_insn_thumb16;
+      info->bytes_per_chunk = 2;
+      size = 2;
+
+      status = info->read_memory_func (pc, (bfd_byte *)b, 2, info);
+      if (little)
+	given = (b[0]) | (b[1] << 8);
+      else
+	given = (b[1]) | (b[0] << 8);
+
+      if (!status)
+	{
+	  /* These bit patterns signal a four-byte Thumb
+	     instruction.  */
+	  if ((given & 0xF800) == 0xF800
+	      || (given & 0xF800) == 0xF000
+	      || (given & 0xF800) == 0xE800)
+	    {
+	      status = info->read_memory_func (pc + 2, (bfd_byte *)b, 2, info);
+	      if (little)
+		given = (b[0]) | (b[1] << 8) | (given << 16);
+	      else
+		given = (b[1]) | (b[0] << 8) | (given << 16);
+
+	      printer = print_insn_thumb32;
+	      size = 4;
+	    }
+	}
+
+      if (ifthen_address != pc)
+	find_ifthen_state(pc, info, little);
+
+      if (ifthen_state)
+	{
+	  if ((ifthen_state & 0xf) == 0x8)
+	    ifthen_next_state = 0;
+	  else
+	    ifthen_next_state = (ifthen_state & 0xe0)
+				| ((ifthen_state & 0xf) << 1);
+	}
+    }
+
+  if (status)
+    {
+      info->memory_error_func (status, pc, info);
+      return -1;
+    }
+  if (info->flags & INSN_HAS_RELOC)
+    /* If the instruction has a reloc associated with it, then
+       the offset field in the instruction will actually be the
+       addend for the reloc.  (We are using REL type relocs).
+       In such cases, we can ignore the pc when computing
+       addresses, since the addend is not currently pc-relative.  */
+    pc = 0;
+
+  /* We include the hexdump of the instruction. The format here
+     matches that used by objdump and the ARM ARM (in particular,
+     32 bit Thumb instructions are displayed as pairs of halfwords,
+     not as a single word.)  */
+  if (is_thumb)
+    {
+      if (size == 2)
+	{
+	  info->fprintf_func(info->stream, "%04lx       ",
+			     ((unsigned long)given) & 0xffff);
+	}
+      else
+	{
+	  info->fprintf_func(info->stream, "%04lx %04lx  ",
+			     (((unsigned long)given) >> 16) & 0xffff,
+			     ((unsigned long)given) & 0xffff);
+	}
+    }
+  else
+    {
+      info->fprintf_func(info->stream, "%08lx      ",
+			 ((unsigned long)given) & 0xffffffff);
+    }
+
+  printer (pc, info, given);
+
+  if (is_thumb)
+    {
+      ifthen_state = ifthen_next_state;
+      ifthen_address += size;
+    }
+  return size;
+}
diff --git a/qemu-0.15.x/arm-semi.c b/qemu-0.15.x/arm-semi.c
new file mode 100644
index 0000000..873518a
--- /dev/null
+++ b/qemu-0.15.x/arm-semi.c
@@ -0,0 +1,509 @@
+/*
+ *  Arm "Angel" semihosting syscalls
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Written by Paul Brook.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "cpu.h"
+#ifdef CONFIG_USER_ONLY
+#include "qemu.h"
+
+#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#else
+#include "qemu-common.h"
+#include "gdbstub.h"
+#include "hw/arm-misc.h"
+#endif
+
+#define SYS_OPEN        0x01
+#define SYS_CLOSE       0x02
+#define SYS_WRITEC      0x03
+#define SYS_WRITE0      0x04
+#define SYS_WRITE       0x05
+#define SYS_READ        0x06
+#define SYS_READC       0x07
+#define SYS_ISTTY       0x09
+#define SYS_SEEK        0x0a
+#define SYS_FLEN        0x0c
+#define SYS_TMPNAM      0x0d
+#define SYS_REMOVE      0x0e
+#define SYS_RENAME      0x0f
+#define SYS_CLOCK       0x10
+#define SYS_TIME        0x11
+#define SYS_SYSTEM      0x12
+#define SYS_ERRNO       0x13
+#define SYS_GET_CMDLINE 0x15
+#define SYS_HEAPINFO    0x16
+#define SYS_EXIT        0x18
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define GDB_O_RDONLY  0x000
+#define GDB_O_WRONLY  0x001
+#define GDB_O_RDWR    0x002
+#define GDB_O_APPEND  0x008
+#define GDB_O_CREAT   0x200
+#define GDB_O_TRUNC   0x400
+#define GDB_O_BINARY  0
+
+static int gdb_open_modeflags[12] = {
+    GDB_O_RDONLY,
+    GDB_O_RDONLY | GDB_O_BINARY,
+    GDB_O_RDWR,
+    GDB_O_RDWR | GDB_O_BINARY,
+    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
+    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
+    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
+    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
+    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
+    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
+};
+
+static int open_modeflags[12] = {
+    O_RDONLY,
+    O_RDONLY | O_BINARY,
+    O_RDWR,
+    O_RDWR | O_BINARY,
+    O_WRONLY | O_CREAT | O_TRUNC,
+    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+    O_RDWR | O_CREAT | O_TRUNC,
+    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+    O_WRONLY | O_CREAT | O_APPEND,
+    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
+    O_RDWR | O_CREAT | O_APPEND,
+    O_RDWR | O_CREAT | O_APPEND | O_BINARY
+};
+
+#ifdef CONFIG_USER_ONLY
+static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
+{
+    if (code == (uint32_t)-1)
+        ts->swi_errno = errno;
+    return code;
+}
+#else
+static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
+{
+    return code;
+}
+
+#include "softmmu-semi.h"
+#endif
+
+static target_ulong arm_semi_syscall_len;
+
+#if !defined(CONFIG_USER_ONLY)
+static target_ulong syscall_err;
+#endif
+
+static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+#ifdef CONFIG_USER_ONLY
+    TaskState *ts = env->opaque;
+#endif
+
+    if (ret == (target_ulong)-1) {
+#ifdef CONFIG_USER_ONLY
+        ts->swi_errno = err;
+#else
+	syscall_err = err;
+#endif
+        env->regs[0] = ret;
+    } else {
+        /* Fixup syscalls that use nonstardard return conventions.  */
+        switch (env->regs[0]) {
+        case SYS_WRITE:
+        case SYS_READ:
+            env->regs[0] = arm_semi_syscall_len - ret;
+            break;
+        case SYS_SEEK:
+            env->regs[0] = 0;
+            break;
+        default:
+            env->regs[0] = ret;
+            break;
+        }
+    }
+}
+
+static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    /* The size is always stored in big-endian order, extract
+       the value. We assume the size always fit in 32 bits.  */
+    uint32_t size;
+    cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
+    env->regs[0] = be32_to_cpu(size);
+#ifdef CONFIG_USER_ONLY
+    ((TaskState *)env->opaque)->swi_errno = err;
+#else
+    syscall_err = err;
+#endif
+}
+
+#define ARG(n)					\
+({						\
+    target_ulong __arg;				\
+    /* FIXME - handle get_user() failure */	\
+    get_user_ual(__arg, args + (n) * 4);	\
+    __arg;					\
+})
+#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
+uint32_t do_arm_semihosting(CPUState *env)
+{
+    target_ulong args;
+    char * s;
+    int nr;
+    uint32_t ret;
+    uint32_t len;
+#ifdef CONFIG_USER_ONLY
+    TaskState *ts = env->opaque;
+#else
+    CPUState *ts = env;
+#endif
+
+    nr = env->regs[0];
+    args = env->regs[1];
+    switch (nr) {
+    case SYS_OPEN:
+        if (!(s = lock_user_string(ARG(0))))
+            /* FIXME - should this error code be -TARGET_EFAULT ? */
+            return (uint32_t)-1;
+        if (ARG(1) >= 12)
+            return (uint32_t)-1;
+        if (strcmp(s, ":tt") == 0) {
+            if (ARG(1) < 4)
+                return STDIN_FILENO;
+            else
+                return STDOUT_FILENO;
+        }
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
+			   (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
+            return env->regs[0];
+        } else {
+            ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
+        }
+        unlock_user(s, ARG(0), 0);
+        return ret;
+    case SYS_CLOSE:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
+            return env->regs[0];
+        } else {
+            return set_swi_errno(ts, close(ARG(0)));
+        }
+    case SYS_WRITEC:
+        {
+          char c;
+
+          if (get_user_u8(c, args))
+              /* FIXME - should this error code be -TARGET_EFAULT ? */
+              return (uint32_t)-1;
+          /* Write to debug console.  stderr is near enough.  */
+          if (use_gdb_syscalls()) {
+                gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
+                return env->regs[0];
+          } else {
+                return write(STDERR_FILENO, &c, 1);
+          }
+        }
+    case SYS_WRITE0:
+        if (!(s = lock_user_string(args)))
+            /* FIXME - should this error code be -TARGET_EFAULT ? */
+            return (uint32_t)-1;
+        len = strlen(s);
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
+            ret = env->regs[0];
+        } else {
+            ret = write(STDERR_FILENO, s, len);
+        }
+        unlock_user(s, args, 0);
+        return ret;
+    case SYS_WRITE:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            arm_semi_syscall_len = len;
+            gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
+            return env->regs[0];
+        } else {
+            if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            ret = set_swi_errno(ts, write(ARG(0), s, len));
+            unlock_user(s, ARG(1), 0);
+            if (ret == (uint32_t)-1)
+                return -1;
+            return len - ret;
+        }
+    case SYS_READ:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            arm_semi_syscall_len = len;
+            gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
+            return env->regs[0];
+        } else {
+            if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            do
+              ret = set_swi_errno(ts, read(ARG(0), s, len));
+            while (ret == -1 && errno == EINTR);
+            unlock_user(s, ARG(1), len);
+            if (ret == (uint32_t)-1)
+                return -1;
+            return len - ret;
+        }
+    case SYS_READC:
+       /* XXX: Read from debug cosole. Not implemented.  */
+        return 0;
+    case SYS_ISTTY:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
+            return env->regs[0];
+        } else {
+            return isatty(ARG(0));
+        }
+    case SYS_SEEK:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
+            return env->regs[0];
+        } else {
+            ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
+            if (ret == (uint32_t)-1)
+              return -1;
+            return 0;
+        }
+    case SYS_FLEN:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
+			   ARG(0), env->regs[13]-64);
+            return env->regs[0];
+        } else {
+            struct stat buf;
+            ret = set_swi_errno(ts, fstat(ARG(0), &buf));
+            if (ret == (uint32_t)-1)
+                return -1;
+            return buf.st_size;
+        }
+    case SYS_TMPNAM:
+        /* XXX: Not implemented.  */
+        return -1;
+    case SYS_REMOVE:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
+            ret = env->regs[0];
+        } else {
+            if (!(s = lock_user_string(ARG(0))))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            ret =  set_swi_errno(ts, remove(s));
+            unlock_user(s, ARG(0), 0);
+        }
+        return ret;
+    case SYS_RENAME:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
+                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
+            return env->regs[0];
+        } else {
+            char *s2;
+            s = lock_user_string(ARG(0));
+            s2 = lock_user_string(ARG(2));
+            if (!s || !s2)
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                ret = (uint32_t)-1;
+            else
+                ret = set_swi_errno(ts, rename(s, s2));
+            if (s2)
+                unlock_user(s2, ARG(2), 0);
+            if (s)
+                unlock_user(s, ARG(0), 0);
+            return ret;
+        }
+    case SYS_CLOCK:
+        return clock() / (CLOCKS_PER_SEC / 100);
+    case SYS_TIME:
+        return set_swi_errno(ts, time(NULL));
+    case SYS_SYSTEM:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
+            return env->regs[0];
+        } else {
+            if (!(s = lock_user_string(ARG(0))))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            ret = set_swi_errno(ts, system(s));
+            unlock_user(s, ARG(0), 0);
+            return ret;
+        }
+    case SYS_ERRNO:
+#ifdef CONFIG_USER_ONLY
+        return ts->swi_errno;
+#else
+        return syscall_err;
+#endif
+    case SYS_GET_CMDLINE:
+        {
+            /* Build a command-line from the original argv.
+             *
+             * The inputs are:
+             *     * ARG(0), pointer to a buffer of at least the size
+             *               specified in ARG(1).
+             *     * ARG(1), size of the buffer pointed to by ARG(0) in
+             *               bytes.
+             *
+             * The outputs are:
+             *     * ARG(0), pointer to null-terminated string of the
+             *               command line.
+             *     * ARG(1), length of the string pointed to by ARG(0).
+             */
+
+            char *output_buffer;
+            size_t input_size = ARG(1);
+            size_t output_size;
+            int status = 0;
+
+            /* Compute the size of the output string.  */
+#if !defined(CONFIG_USER_ONLY)
+            output_size = strlen(ts->boot_info->kernel_filename)
+                        + 1  /* Separating space.  */
+                        + strlen(ts->boot_info->kernel_cmdline)
+                        + 1; /* Terminating null byte.  */
+#else
+            unsigned int i;
+
+            output_size = ts->info->arg_end - ts->info->arg_start;
+            if (!output_size) {
+                /* We special-case the "empty command line" case (argc==0).
+                   Just provide the terminating 0. */
+                output_size = 1;
+            }
+#endif
+
+            if (output_size > input_size) {
+                 /* Not enough space to store command-line arguments.  */
+                return -1;
+            }
+
+            /* Adjust the command-line length.  */
+            SET_ARG(1, output_size - 1);
+
+            /* Lock the buffer on the ARM side.  */
+            output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0);
+            if (!output_buffer) {
+                return -1;
+            }
+
+            /* Copy the command-line arguments.  */
+#if !defined(CONFIG_USER_ONLY)
+            pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
+            pstrcat(output_buffer, output_size, " ");
+            pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
+#else
+            if (output_size == 1) {
+                /* Empty command-line.  */
+                output_buffer[0] = '\0';
+                goto out;
+            }
+
+            if (copy_from_user(output_buffer, ts->info->arg_start,
+                               output_size)) {
+                status = -1;
+                goto out;
+            }
+
+            /* Separate arguments by white spaces.  */
+            for (i = 0; i < output_size - 1; i++) {
+                if (output_buffer[i] == 0) {
+                    output_buffer[i] = ' ';
+                }
+            }
+        out:
+#endif
+            /* Unlock the buffer on the ARM side.  */
+            unlock_user(output_buffer, ARG(0), output_size);
+
+            return status;
+        }
+    case SYS_HEAPINFO:
+        {
+            uint32_t *ptr;
+            uint32_t limit;
+
+#ifdef CONFIG_USER_ONLY
+            /* Some C libraries assume the heap immediately follows .bss, so
+               allocate it using sbrk.  */
+            if (!ts->heap_limit) {
+                abi_ulong ret;
+
+                ts->heap_base = do_brk(0);
+                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
+                /* Try a big heap, and reduce the size if that fails.  */
+                for (;;) {
+                    ret = do_brk(limit);
+                    if (ret >= limit) {
+                        break;
+                    }
+                    limit = (ts->heap_base >> 1) + (limit >> 1);
+                }
+                ts->heap_limit = limit;
+            }
+
+            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            ptr[0] = tswap32(ts->heap_base);
+            ptr[1] = tswap32(ts->heap_limit);
+            ptr[2] = tswap32(ts->stack_base);
+            ptr[3] = tswap32(0); /* Stack limit.  */
+            unlock_user(ptr, ARG(0), 16);
+#else
+            limit = ram_size;
+            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
+                /* FIXME - should this error code be -TARGET_EFAULT ? */
+                return (uint32_t)-1;
+            /* TODO: Make this use the limit of the loaded application.  */
+            ptr[0] = tswap32(limit / 2);
+            ptr[1] = tswap32(limit);
+            ptr[2] = tswap32(limit); /* Stack base */
+            ptr[3] = tswap32(0); /* Stack limit.  */
+            unlock_user(ptr, ARG(0), 16);
+#endif
+            return 0;
+        }
+    case SYS_EXIT:
+        gdb_exit(env, 0);
+        exit(0);
+    default:
+        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
+        cpu_dump_state(env, stderr, fprintf, 0);
+        abort();
+    }
+}
diff --git a/qemu-0.15.x/arm.ld b/qemu-0.15.x/arm.ld
new file mode 100644
index 0000000..7f13da9
--- /dev/null
+++ b/qemu-0.15.x/arm.ld
@@ -0,0 +1,153 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
+	      "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp) 	}
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .gnu.version   : { *(.gnu.version)	}
+  .gnu.version_d   : { *(.gnu.version_d)	}
+  .gnu.version_r   : { *(.gnu.version_r)	}
+  .rel.text      :
+    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+  .rela.text     :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rel.data      :
+    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+  .rela.data     :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rel.rodata    :
+    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+  .rela.rodata   :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.init      : { *(.rel.init)	}
+  .rela.init     : { *(.rela.init)	}
+  .rel.fini      : { *(.rel.fini)	}
+  .rela.fini     : { *(.rela.fini)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	} =0x47ff041f
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  } =0x47ff041f
+  _etext = .;
+  PROVIDE (etext = .);
+  .fini      : { *(.fini)    } =0x47ff041f
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+   __exidx_start = .;
+  .ARM.exidx   : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+   __exidx_end = .;
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x100000) + (. & (0x100000 - 1));
+  .data    :
+  {
+    *(.gen_code)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .data1   : { *(.data1) }
+  .preinit_array     :
+  {
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+  }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+  .plt      : { *(.plt)	}
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff --git a/qemu-0.15.x/async.c b/qemu-0.15.x/async.c
new file mode 100644
index 0000000..fd313df
--- /dev/null
+++ b/qemu-0.15.x/async.c
@@ -0,0 +1,217 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "qemu-common.h"
+#include "qemu-aio.h"
+
+/*
+ * An AsyncContext protects the callbacks of AIO requests and Bottom Halves
+ * against interfering with each other. A typical example is qcow2 that accepts
+ * asynchronous requests, but relies for manipulation of its metadata on
+ * synchronous bdrv_read/write that doesn't trigger any callbacks.
+ *
+ * However, these functions are often emulated using AIO which means that AIO
+ * callbacks must be run - but at the same time we must not run callbacks of
+ * other requests as they might start to modify metadata and corrupt the
+ * internal state of the caller of bdrv_read/write.
+ *
+ * To achieve the desired semantics we switch into a new AsyncContext.
+ * Callbacks must only be run if they belong to the current AsyncContext.
+ * Otherwise they need to be queued until their own context is active again.
+ * This is how you can make qemu_aio_wait() wait only for your own callbacks.
+ *
+ * The AsyncContexts form a stack. When you leave a AsyncContexts, you always
+ * return to the old ("parent") context.
+ */
+struct AsyncContext {
+    /* Consecutive number of the AsyncContext (position in the stack) */
+    int id;
+
+    /* Anchor of the list of Bottom Halves belonging to the context */
+    struct QEMUBH *first_bh;
+
+    /* Link to parent context */
+    struct AsyncContext *parent;
+};
+
+/* The currently active AsyncContext */
+static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
+
+/*
+ * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
+ * won't be called until this context is left again.
+ */
+void async_context_push(void)
+{
+    struct AsyncContext *new = qemu_mallocz(sizeof(*new));
+    new->parent = async_context;
+    new->id = async_context->id + 1;
+    async_context = new;
+}
+
+/* Run queued AIO completions and destroy Bottom Half */
+static void bh_run_aio_completions(void *opaque)
+{
+    QEMUBH **bh = opaque;
+    qemu_bh_delete(*bh);
+    qemu_free(bh);
+    qemu_aio_process_queue();
+}
+/*
+ * Leave the currently active AsyncContext. All Bottom Halves belonging to the
+ * old context are executed before changing the context.
+ */
+void async_context_pop(void)
+{
+    struct AsyncContext *old = async_context;
+    QEMUBH **bh;
+
+    /* Flush the bottom halves, we don't want to lose them */
+    while (qemu_bh_poll());
+
+    /* Switch back to the parent context */
+    async_context = async_context->parent;
+    qemu_free(old);
+
+    if (async_context == NULL) {
+        abort();
+    }
+
+    /* Schedule BH to run any queued AIO completions as soon as possible */
+    bh = qemu_malloc(sizeof(*bh));
+    *bh = qemu_bh_new(bh_run_aio_completions, bh);
+    qemu_bh_schedule(*bh);
+}
+
+/*
+ * Returns the ID of the currently active AsyncContext
+ */
+int get_async_context_id(void)
+{
+    return async_context->id;
+}
+
+/***********************************************************/
+/* bottom halves (can be seen as timers which expire ASAP) */
+
+struct QEMUBH {
+    QEMUBHFunc *cb;
+    void *opaque;
+    int scheduled;
+    int idle;
+    int deleted;
+    QEMUBH *next;
+};
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+    QEMUBH *bh;
+    bh = qemu_mallocz(sizeof(QEMUBH));
+    bh->cb = cb;
+    bh->opaque = opaque;
+    bh->next = async_context->first_bh;
+    async_context->first_bh = bh;
+    return bh;
+}
+
+int qemu_bh_poll(void)
+{
+    QEMUBH *bh, **bhp, *next;
+    int ret;
+
+    ret = 0;
+    for (bh = async_context->first_bh; bh; bh = next) {
+        next = bh->next;
+        if (!bh->deleted && bh->scheduled) {
+            bh->scheduled = 0;
+            if (!bh->idle)
+                ret = 1;
+            bh->idle = 0;
+            bh->cb(bh->opaque);
+        }
+    }
+
+    /* remove deleted bhs */
+    bhp = &async_context->first_bh;
+    while (*bhp) {
+        bh = *bhp;
+        if (bh->deleted) {
+            *bhp = bh->next;
+            qemu_free(bh);
+        } else
+            bhp = &bh->next;
+    }
+
+    return ret;
+}
+
+void qemu_bh_schedule_idle(QEMUBH *bh)
+{
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->idle = 1;
+}
+
+void qemu_bh_schedule(QEMUBH *bh)
+{
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->idle = 0;
+    /* stop the currently executing CPU to execute the BH ASAP */
+    qemu_notify_event();
+}
+
+void qemu_bh_cancel(QEMUBH *bh)
+{
+    bh->scheduled = 0;
+}
+
+void qemu_bh_delete(QEMUBH *bh)
+{
+    bh->scheduled = 0;
+    bh->deleted = 1;
+}
+
+void qemu_bh_update_timeout(int *timeout)
+{
+    QEMUBH *bh;
+
+    for (bh = async_context->first_bh; bh; bh = bh->next) {
+        if (!bh->deleted && bh->scheduled) {
+            if (bh->idle) {
+                /* idle bottom halves will be polled at least
+                 * every 10ms */
+                *timeout = MIN(10, *timeout);
+            } else {
+                /* non-idle bottom halves will be executed
+                 * immediately */
+                *timeout = 0;
+                break;
+            }
+        }
+    }
+}
+
diff --git a/qemu-0.15.x/audio/alsaaudio.c b/qemu-0.15.x/audio/alsaaudio.c
new file mode 100644
index 0000000..4d72014
--- /dev/null
+++ b/qemu-0.15.x/audio/alsaaudio.c
@@ -0,0 +1,1260 @@
+/*
+ * QEMU ALSA audio driver
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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 <alsa/asoundlib.h>
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "audio.h"
+
+#if QEMU_GNUC_PREREQ(4, 3)
+#pragma GCC diagnostic ignored "-Waddress"
+#endif
+
+#define AUDIO_CAP "alsa"
+#include "audio_int.h"
+
+struct pollhlp {
+    snd_pcm_t *handle;
+    struct pollfd *pfds;
+    int count;
+    int mask;
+};
+
+typedef struct ALSAVoiceOut {
+    HWVoiceOut hw;
+    int wpos;
+    int pending;
+    void *pcm_buf;
+    snd_pcm_t *handle;
+    struct pollhlp pollhlp;
+} ALSAVoiceOut;
+
+typedef struct ALSAVoiceIn {
+    HWVoiceIn hw;
+    snd_pcm_t *handle;
+    void *pcm_buf;
+    struct pollhlp pollhlp;
+} ALSAVoiceIn;
+
+static struct {
+    int size_in_usec_in;
+    int size_in_usec_out;
+    const char *pcm_name_in;
+    const char *pcm_name_out;
+    unsigned int buffer_size_in;
+    unsigned int period_size_in;
+    unsigned int buffer_size_out;
+    unsigned int period_size_out;
+    unsigned int threshold;
+
+    int buffer_size_in_overridden;
+    int period_size_in_overridden;
+
+    int buffer_size_out_overridden;
+    int period_size_out_overridden;
+    int verbose;
+} conf = {
+    .buffer_size_out = 4096,
+    .period_size_out = 1024,
+    .pcm_name_out = "default",
+    .pcm_name_in = "default",
+};
+
+struct alsa_params_req {
+    int freq;
+    snd_pcm_format_t fmt;
+    int nchannels;
+    int size_in_usec;
+    int override_mask;
+    unsigned int buffer_size;
+    unsigned int period_size;
+};
+
+struct alsa_params_obt {
+    int freq;
+    audfmt_e fmt;
+    int endianness;
+    int nchannels;
+    snd_pcm_uframes_t samples;
+};
+
+static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+}
+
+static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
+    int err,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+}
+
+static void alsa_fini_poll (struct pollhlp *hlp)
+{
+    int i;
+    struct pollfd *pfds = hlp->pfds;
+
+    if (pfds) {
+        for (i = 0; i < hlp->count; ++i) {
+            qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+        }
+        qemu_free (pfds);
+    }
+    hlp->pfds = NULL;
+    hlp->count = 0;
+    hlp->handle = NULL;
+}
+
+static void alsa_anal_close1 (snd_pcm_t **handlep)
+{
+    int err = snd_pcm_close (*handlep);
+    if (err) {
+        alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
+    }
+    *handlep = NULL;
+}
+
+static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
+{
+    alsa_fini_poll (hlp);
+    alsa_anal_close1 (handlep);
+}
+
+static int alsa_recover (snd_pcm_t *handle)
+{
+    int err = snd_pcm_prepare (handle);
+    if (err < 0) {
+        alsa_logerr (err, "Failed to prepare handle %p\n", handle);
+        return -1;
+    }
+    return 0;
+}
+
+static int alsa_resume (snd_pcm_t *handle)
+{
+    int err = snd_pcm_resume (handle);
+    if (err < 0) {
+        alsa_logerr (err, "Failed to resume handle %p\n", handle);
+        return -1;
+    }
+    return 0;
+}
+
+static void alsa_poll_handler (void *opaque)
+{
+    int err, count;
+    snd_pcm_state_t state;
+    struct pollhlp *hlp = opaque;
+    unsigned short revents;
+
+    count = poll (hlp->pfds, hlp->count, 0);
+    if (count < 0) {
+        dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
+        return;
+    }
+
+    if (!count) {
+        return;
+    }
+
+    /* XXX: ALSA example uses initial count, not the one returned by
+       poll, correct? */
+    err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
+                                            hlp->count, &revents);
+    if (err < 0) {
+        alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
+        return;
+    }
+
+    if (!(revents & hlp->mask)) {
+        if (conf.verbose) {
+            dolog ("revents = %d\n", revents);
+        }
+        return;
+    }
+
+    state = snd_pcm_state (hlp->handle);
+    switch (state) {
+    case SND_PCM_STATE_SETUP:
+        alsa_recover (hlp->handle);
+        break;
+
+    case SND_PCM_STATE_XRUN:
+        alsa_recover (hlp->handle);
+        break;
+
+    case SND_PCM_STATE_SUSPENDED:
+        alsa_resume (hlp->handle);
+        break;
+
+    case SND_PCM_STATE_PREPARED:
+        audio_run ("alsa run (prepared)");
+        break;
+
+    case SND_PCM_STATE_RUNNING:
+        audio_run ("alsa run (running)");
+        break;
+
+    default:
+        dolog ("Unexpected state %d\n", state);
+    }
+}
+
+static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
+{
+    int i, count, err;
+    struct pollfd *pfds;
+
+    count = snd_pcm_poll_descriptors_count (handle);
+    if (count <= 0) {
+        dolog ("Could not initialize poll mode\n"
+               "Invalid number of poll descriptors %d\n", count);
+        return -1;
+    }
+
+    pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
+    if (!pfds) {
+        dolog ("Could not initialize poll mode\n");
+        return -1;
+    }
+
+    err = snd_pcm_poll_descriptors (handle, pfds, count);
+    if (err < 0) {
+        alsa_logerr (err, "Could not initialize poll mode\n"
+                     "Could not obtain poll descriptors\n");
+        qemu_free (pfds);
+        return -1;
+    }
+
+    for (i = 0; i < count; ++i) {
+        if (pfds[i].events & POLLIN) {
+            err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
+                                       NULL, hlp);
+        }
+        if (pfds[i].events & POLLOUT) {
+            if (conf.verbose) {
+                dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
+            }
+            err = qemu_set_fd_handler (pfds[i].fd, NULL,
+                                       alsa_poll_handler, hlp);
+        }
+        if (conf.verbose) {
+            dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
+                   pfds[i].events, i, pfds[i].fd, err);
+        }
+
+        if (err) {
+            dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
+                   pfds[i].events, i, pfds[i].fd, err);
+
+            while (i--) {
+                qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+            }
+            qemu_free (pfds);
+            return -1;
+        }
+    }
+    hlp->pfds = pfds;
+    hlp->count = count;
+    hlp->handle = handle;
+    hlp->mask = mask;
+    return 0;
+}
+
+static int alsa_poll_out (HWVoiceOut *hw)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+    return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
+}
+
+static int alsa_poll_in (HWVoiceIn *hw)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+    return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
+}
+
+static int alsa_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
+{
+    switch (fmt) {
+    case AUD_FMT_S8:
+        return SND_PCM_FORMAT_S8;
+
+    case AUD_FMT_U8:
+        return SND_PCM_FORMAT_U8;
+
+    case AUD_FMT_S16:
+        if (endianness) {
+            return SND_PCM_FORMAT_S16_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_S16_LE;
+        }
+
+    case AUD_FMT_U16:
+        if (endianness) {
+            return SND_PCM_FORMAT_U16_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_U16_LE;
+        }
+
+    case AUD_FMT_S32:
+        if (endianness) {
+            return SND_PCM_FORMAT_S32_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_S32_LE;
+        }
+
+    case AUD_FMT_U32:
+        if (endianness) {
+            return SND_PCM_FORMAT_U32_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_U32_LE;
+        }
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return SND_PCM_FORMAT_U8;
+    }
+}
+
+static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
+                           int *endianness)
+{
+    switch (alsafmt) {
+    case SND_PCM_FORMAT_S8:
+        *endianness = 0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case SND_PCM_FORMAT_U8:
+        *endianness = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case SND_PCM_FORMAT_S16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case SND_PCM_FORMAT_U16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case SND_PCM_FORMAT_S16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case SND_PCM_FORMAT_U16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case SND_PCM_FORMAT_S32_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S32;
+        break;
+
+    case SND_PCM_FORMAT_U32_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U32;
+        break;
+
+    case SND_PCM_FORMAT_S32_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S32;
+        break;
+
+    case SND_PCM_FORMAT_U32_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U32;
+        break;
+
+    default:
+        dolog ("Unrecognized audio format %d\n", alsafmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void alsa_dump_info (struct alsa_params_req *req,
+                            struct alsa_params_obt *obt,
+                            snd_pcm_format_t obtfmt)
+{
+    dolog ("parameter | requested value | obtained value\n");
+    dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
+    dolog ("channels  |      %10d |     %10d\n",
+           req->nchannels, obt->nchannels);
+    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
+    dolog ("============================================\n");
+    dolog ("requested: buffer size %d period size %d\n",
+           req->buffer_size, req->period_size);
+    dolog ("obtained: samples %ld\n", obt->samples);
+}
+
+static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
+{
+    int err;
+    snd_pcm_sw_params_t *sw_params;
+
+    snd_pcm_sw_params_alloca (&sw_params);
+
+    err = snd_pcm_sw_params_current (handle, sw_params);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to get current software parameters\n");
+        return;
+    }
+
+    err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to set software threshold to %ld\n",
+                     threshold);
+        return;
+    }
+
+    err = snd_pcm_sw_params (handle, sw_params);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to set software parameters\n");
+        return;
+    }
+}
+
+static int alsa_open (int in, struct alsa_params_req *req,
+                      struct alsa_params_obt *obt, snd_pcm_t **handlep)
+{
+    snd_pcm_t *handle;
+    snd_pcm_hw_params_t *hw_params;
+    int err;
+    int size_in_usec;
+    unsigned int freq, nchannels;
+    const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
+    snd_pcm_uframes_t obt_buffer_size;
+    const char *typ = in ? "ADC" : "DAC";
+    snd_pcm_format_t obtfmt;
+
+    freq = req->freq;
+    nchannels = req->nchannels;
+    size_in_usec = req->size_in_usec;
+
+    snd_pcm_hw_params_alloca (&hw_params);
+
+    err = snd_pcm_open (
+        &handle,
+        pcm_name,
+        in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
+        SND_PCM_NONBLOCK
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
+        return -1;
+    }
+
+    err = snd_pcm_hw_params_any (handle, hw_params);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_access (
+        handle,
+        hw_params,
+        SND_PCM_ACCESS_RW_INTERLEAVED
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set access type\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
+    if (err < 0 && conf.verbose) {
+        alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
+    }
+
+    err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_channels_near (
+        handle,
+        hw_params,
+        &nchannels
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
+                      req->nchannels);
+        goto err;
+    }
+
+    if (nchannels != 1 && nchannels != 2) {
+        alsa_logerr2 (err, typ,
+                      "Can not handle obtained number of channels %d\n",
+                      nchannels);
+        goto err;
+    }
+
+    if (req->buffer_size) {
+        unsigned long obt;
+
+        if (size_in_usec) {
+            int dir = 0;
+            unsigned int btime = req->buffer_size;
+
+            err = snd_pcm_hw_params_set_buffer_time_near (
+                handle,
+                hw_params,
+                &btime,
+                &dir
+                );
+            obt = btime;
+        }
+        else {
+            snd_pcm_uframes_t bsize = req->buffer_size;
+
+            err = snd_pcm_hw_params_set_buffer_size_near (
+                handle,
+                hw_params,
+                &bsize
+                );
+            obt = bsize;
+        }
+        if (err < 0) {
+            alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
+                          size_in_usec ? "time" : "size", req->buffer_size);
+            goto err;
+        }
+
+        if ((req->override_mask & 2) && (obt - req->buffer_size))
+            dolog ("Requested buffer %s %u was rejected, using %lu\n",
+                   size_in_usec ? "time" : "size", req->buffer_size, obt);
+    }
+
+    if (req->period_size) {
+        unsigned long obt;
+
+        if (size_in_usec) {
+            int dir = 0;
+            unsigned int ptime = req->period_size;
+
+            err = snd_pcm_hw_params_set_period_time_near (
+                handle,
+                hw_params,
+                &ptime,
+                &dir
+                );
+            obt = ptime;
+        }
+        else {
+            int dir = 0;
+            snd_pcm_uframes_t psize = req->period_size;
+
+            err = snd_pcm_hw_params_set_period_size_near (
+                handle,
+                hw_params,
+                &psize,
+                &dir
+                );
+            obt = psize;
+        }
+
+        if (err < 0) {
+            alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
+                          size_in_usec ? "time" : "size", req->period_size);
+            goto err;
+        }
+
+        if (((req->override_mask & 1) && (obt - req->period_size)))
+            dolog ("Requested period %s %u was rejected, using %lu\n",
+                   size_in_usec ? "time" : "size", req->period_size, obt);
+    }
+
+    err = snd_pcm_hw_params (handle, hw_params);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to get buffer size\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to get format\n");
+        goto err;
+    }
+
+    if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
+        dolog ("Invalid format was returned %d\n", obtfmt);
+        goto err;
+    }
+
+    err = snd_pcm_prepare (handle);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
+        goto err;
+    }
+
+    if (!in && conf.threshold) {
+        snd_pcm_uframes_t threshold;
+        int bytes_per_sec;
+
+        bytes_per_sec = freq << (nchannels == 2);
+
+        switch (obt->fmt) {
+        case AUD_FMT_S8:
+        case AUD_FMT_U8:
+            break;
+
+        case AUD_FMT_S16:
+        case AUD_FMT_U16:
+            bytes_per_sec <<= 1;
+            break;
+
+        case AUD_FMT_S32:
+        case AUD_FMT_U32:
+            bytes_per_sec <<= 2;
+            break;
+        }
+
+        threshold = (conf.threshold * bytes_per_sec) / 1000;
+        alsa_set_threshold (handle, threshold);
+    }
+
+    obt->nchannels = nchannels;
+    obt->freq = freq;
+    obt->samples = obt_buffer_size;
+
+    *handlep = handle;
+
+    if (conf.verbose &&
+        (obtfmt != req->fmt ||
+         obt->nchannels != req->nchannels ||
+         obt->freq != req->freq)) {
+        dolog ("Audio parameters for %s\n", typ);
+        alsa_dump_info (req, obt, obtfmt);
+    }
+
+#ifdef DEBUG
+    alsa_dump_info (req, obt, obtfmt);
+#endif
+    return 0;
+
+ err:
+    alsa_anal_close1 (&handle);
+    return -1;
+}
+
+static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
+{
+    snd_pcm_sframes_t avail;
+
+    avail = snd_pcm_avail_update (handle);
+    if (avail < 0) {
+        if (avail == -EPIPE) {
+            if (!alsa_recover (handle)) {
+                avail = snd_pcm_avail_update (handle);
+            }
+        }
+
+        if (avail < 0) {
+            alsa_logerr (avail,
+                         "Could not obtain number of available frames\n");
+            return -1;
+        }
+    }
+
+    return avail;
+}
+
+static void alsa_write_pending (ALSAVoiceOut *alsa)
+{
+    HWVoiceOut *hw = &alsa->hw;
+
+    while (alsa->pending) {
+        int left_till_end_samples = hw->samples - alsa->wpos;
+        int len = audio_MIN (alsa->pending, left_till_end_samples);
+        char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
+
+        while (len) {
+            snd_pcm_sframes_t written;
+
+            written = snd_pcm_writei (alsa->handle, src, len);
+
+            if (written <= 0) {
+                switch (written) {
+                case 0:
+                    if (conf.verbose) {
+                        dolog ("Failed to write %d frames (wrote zero)\n", len);
+                    }
+                    return;
+
+                case -EPIPE:
+                    if (alsa_recover (alsa->handle)) {
+                        alsa_logerr (written, "Failed to write %d frames\n",
+                                     len);
+                        return;
+                    }
+                    if (conf.verbose) {
+                        dolog ("Recovering from playback xrun\n");
+                    }
+                    continue;
+
+                case -ESTRPIPE:
+                    /* stream is suspended and waiting for an
+                       application recovery */
+                    if (alsa_resume (alsa->handle)) {
+                        alsa_logerr (written, "Failed to write %d frames\n",
+                                     len);
+                        return;
+                    }
+                    if (conf.verbose) {
+                        dolog ("Resuming suspended output stream\n");
+                    }
+                    continue;
+
+                case -EAGAIN:
+                    return;
+
+                default:
+                    alsa_logerr (written, "Failed to write %d frames from %p\n",
+                                 len, src);
+                    return;
+                }
+            }
+
+            alsa->wpos = (alsa->wpos + written) % hw->samples;
+            alsa->pending -= written;
+            len -= written;
+        }
+    }
+}
+
+static int alsa_run_out (HWVoiceOut *hw, int live)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+    int decr;
+    snd_pcm_sframes_t avail;
+
+    avail = alsa_get_avail (alsa->handle);
+    if (avail < 0) {
+        dolog ("Could not get number of available playback frames\n");
+        return 0;
+    }
+
+    decr = audio_MIN (live, avail);
+    decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
+    alsa->pending += decr;
+    alsa_write_pending (alsa);
+    return decr;
+}
+
+static void alsa_fini_out (HWVoiceOut *hw)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+    ldebug ("alsa_fini\n");
+    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
+
+    if (alsa->pcm_buf) {
+        qemu_free (alsa->pcm_buf);
+        alsa->pcm_buf = NULL;
+    }
+}
+
+static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+    struct alsa_params_req req;
+    struct alsa_params_obt obt;
+    snd_pcm_t *handle;
+    struct audsettings obt_as;
+
+    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.period_size = conf.period_size_out;
+    req.buffer_size = conf.buffer_size_out;
+    req.size_in_usec = conf.size_in_usec_out;
+    req.override_mask =
+        (conf.period_size_out_overridden ? 1 : 0) |
+        (conf.buffer_size_out_overridden ? 2 : 0);
+
+    if (alsa_open (0, &req, &obt, &handle)) {
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = obt.fmt;
+    obt_as.endianness = obt.endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = obt.samples;
+
+    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
+    if (!alsa->pcm_buf) {
+        dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        alsa_anal_close1 (&handle);
+        return -1;
+    }
+
+    alsa->handle = handle;
+    return 0;
+}
+
+#define VOICE_CTL_PAUSE 0
+#define VOICE_CTL_PREPARE 1
+#define VOICE_CTL_START 2
+
+static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
+{
+    int err;
+
+    if (ctl == VOICE_CTL_PAUSE) {
+        err = snd_pcm_drop (handle);
+        if (err < 0) {
+            alsa_logerr (err, "Could not stop %s\n", typ);
+            return -1;
+        }
+    }
+    else {
+        err = snd_pcm_prepare (handle);
+        if (err < 0) {
+            alsa_logerr (err, "Could not prepare handle for %s\n", typ);
+            return -1;
+        }
+        if (ctl == VOICE_CTL_START) {
+            err = snd_pcm_start(handle);
+            if (err < 0) {
+                alsa_logerr (err, "Could not start handle for %s\n", typ);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            ldebug ("enabling voice\n");
+            if (poll_mode && alsa_poll_out (hw)) {
+                poll_mode = 0;
+            }
+            hw->poll_mode = poll_mode;
+            return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
+        }
+
+    case VOICE_DISABLE:
+        ldebug ("disabling voice\n");
+        if (hw->poll_mode) {
+            hw->poll_mode = 0;
+            alsa_fini_poll (&alsa->pollhlp);
+        }
+        return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
+    }
+
+    return -1;
+}
+
+static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+    struct alsa_params_req req;
+    struct alsa_params_obt obt;
+    snd_pcm_t *handle;
+    struct audsettings obt_as;
+
+    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.period_size = conf.period_size_in;
+    req.buffer_size = conf.buffer_size_in;
+    req.size_in_usec = conf.size_in_usec_in;
+    req.override_mask =
+        (conf.period_size_in_overridden ? 1 : 0) |
+        (conf.buffer_size_in_overridden ? 2 : 0);
+
+    if (alsa_open (1, &req, &obt, &handle)) {
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = obt.fmt;
+    obt_as.endianness = obt.endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = obt.samples;
+
+    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!alsa->pcm_buf) {
+        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        alsa_anal_close1 (&handle);
+        return -1;
+    }
+
+    alsa->handle = handle;
+    return 0;
+}
+
+static void alsa_fini_in (HWVoiceIn *hw)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
+
+    if (alsa->pcm_buf) {
+        qemu_free (alsa->pcm_buf);
+        alsa->pcm_buf = NULL;
+    }
+}
+
+static int alsa_run_in (HWVoiceIn *hw)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int i;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    int decr;
+    struct {
+        int add;
+        int len;
+    } bufs[2] = {
+        { .add = hw->wpos, .len = 0 },
+        { .add = 0,        .len = 0 }
+    };
+    snd_pcm_sframes_t avail;
+    snd_pcm_uframes_t read_samples = 0;
+
+    if (!dead) {
+        return 0;
+    }
+
+    avail = alsa_get_avail (alsa->handle);
+    if (avail < 0) {
+        dolog ("Could not get number of captured frames\n");
+        return 0;
+    }
+
+    if (!avail) {
+        snd_pcm_state_t state;
+
+        state = snd_pcm_state (alsa->handle);
+        switch (state) {
+        case SND_PCM_STATE_PREPARED:
+            avail = hw->samples;
+            break;
+        case SND_PCM_STATE_SUSPENDED:
+            /* stream is suspended and waiting for an application recovery */
+            if (alsa_resume (alsa->handle)) {
+                dolog ("Failed to resume suspended input stream\n");
+                return 0;
+            }
+            if (conf.verbose) {
+                dolog ("Resuming suspended input stream\n");
+            }
+            break;
+        default:
+            if (conf.verbose) {
+                dolog ("No frames available and ALSA state is %d\n", state);
+            }
+            return 0;
+        }
+    }
+
+    decr = audio_MIN (dead, avail);
+    if (!decr) {
+        return 0;
+    }
+
+    if (hw->wpos + decr > hw->samples) {
+        bufs[0].len = (hw->samples - hw->wpos);
+        bufs[1].len = (decr - (hw->samples - hw->wpos));
+    }
+    else {
+        bufs[0].len = decr;
+    }
+
+    for (i = 0; i < 2; ++i) {
+        void *src;
+        struct st_sample *dst;
+        snd_pcm_sframes_t nread;
+        snd_pcm_uframes_t len;
+
+        len = bufs[i].len;
+
+        src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
+        dst = hw->conv_buf + bufs[i].add;
+
+        while (len) {
+            nread = snd_pcm_readi (alsa->handle, src, len);
+
+            if (nread <= 0) {
+                switch (nread) {
+                case 0:
+                    if (conf.verbose) {
+                        dolog ("Failed to read %ld frames (read zero)\n", len);
+                    }
+                    goto exit;
+
+                case -EPIPE:
+                    if (alsa_recover (alsa->handle)) {
+                        alsa_logerr (nread, "Failed to read %ld frames\n", len);
+                        goto exit;
+                    }
+                    if (conf.verbose) {
+                        dolog ("Recovering from capture xrun\n");
+                    }
+                    continue;
+
+                case -EAGAIN:
+                    goto exit;
+
+                default:
+                    alsa_logerr (
+                        nread,
+                        "Failed to read %ld frames from %p\n",
+                        len,
+                        src
+                        );
+                    goto exit;
+                }
+            }
+
+            hw->conv (dst, src, nread);
+
+            src = advance (src, nread << hwshift);
+            dst += nread;
+
+            read_samples += nread;
+            len -= nread;
+        }
+    }
+
+ exit:
+    hw->wpos = (hw->wpos + read_samples) % hw->samples;
+    return read_samples;
+}
+
+static int alsa_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            ldebug ("enabling voice\n");
+            if (poll_mode && alsa_poll_in (hw)) {
+                poll_mode = 0;
+            }
+            hw->poll_mode = poll_mode;
+
+            return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
+        }
+
+    case VOICE_DISABLE:
+        ldebug ("disabling voice\n");
+        if (hw->poll_mode) {
+            hw->poll_mode = 0;
+            alsa_fini_poll (&alsa->pollhlp);
+        }
+        return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
+    }
+
+    return -1;
+}
+
+static void *alsa_audio_init (void)
+{
+    return &conf;
+}
+
+static void alsa_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option alsa_options[] = {
+    {
+        .name        = "DAC_SIZE_IN_USEC",
+        .tag         = AUD_OPT_BOOL,
+        .valp        = &conf.size_in_usec_out,
+        .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
+    },
+    {
+        .name        = "DAC_PERIOD_SIZE",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.period_size_out,
+        .descr       = "DAC period size (0 to go with system default)",
+        .overriddenp = &conf.period_size_out_overridden
+    },
+    {
+        .name        = "DAC_BUFFER_SIZE",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.buffer_size_out,
+        .descr       = "DAC buffer size (0 to go with system default)",
+        .overriddenp = &conf.buffer_size_out_overridden
+    },
+    {
+        .name        = "ADC_SIZE_IN_USEC",
+        .tag         = AUD_OPT_BOOL,
+        .valp        = &conf.size_in_usec_in,
+        .descr       =
+        "ADC period/buffer size in microseconds (otherwise in frames)"
+    },
+    {
+        .name        = "ADC_PERIOD_SIZE",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.period_size_in,
+        .descr       = "ADC period size (0 to go with system default)",
+        .overriddenp = &conf.period_size_in_overridden
+    },
+    {
+        .name        = "ADC_BUFFER_SIZE",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.buffer_size_in,
+        .descr       = "ADC buffer size (0 to go with system default)",
+        .overriddenp = &conf.buffer_size_in_overridden
+    },
+    {
+        .name        = "THRESHOLD",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.threshold,
+        .descr       = "(undocumented)"
+    },
+    {
+        .name        = "DAC_DEV",
+        .tag         = AUD_OPT_STR,
+        .valp        = &conf.pcm_name_out,
+        .descr       = "DAC device name (for instance dmix)"
+    },
+    {
+        .name        = "ADC_DEV",
+        .tag         = AUD_OPT_STR,
+        .valp        = &conf.pcm_name_in,
+        .descr       = "ADC device name"
+    },
+    {
+        .name        = "VERBOSE",
+        .tag         = AUD_OPT_BOOL,
+        .valp        = &conf.verbose,
+        .descr       = "Behave in a more verbose way"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops alsa_pcm_ops = {
+    .init_out = alsa_init_out,
+    .fini_out = alsa_fini_out,
+    .run_out  = alsa_run_out,
+    .write    = alsa_write,
+    .ctl_out  = alsa_ctl_out,
+
+    .init_in  = alsa_init_in,
+    .fini_in  = alsa_fini_in,
+    .run_in   = alsa_run_in,
+    .read     = alsa_read,
+    .ctl_in   = alsa_ctl_in,
+};
+
+struct audio_driver alsa_audio_driver = {
+    .name           = "alsa",
+    .descr          = "ALSA http://www.alsa-project.org",
+    .options        = alsa_options,
+    .init           = alsa_audio_init,
+    .fini           = alsa_audio_fini,
+    .pcm_ops        = &alsa_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (ALSAVoiceOut),
+    .voice_size_in  = sizeof (ALSAVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/audio.c b/qemu-0.15.x/audio/audio.c
new file mode 100644
index 0000000..50d2b64
--- /dev/null
+++ b/qemu-0.15.x/audio/audio.c
@@ -0,0 +1,2066 @@
+/*
+ * QEMU Audio subsystem
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "audio.h"
+#include "monitor.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+
+#define AUDIO_CAP "audio"
+#include "audio_int.h"
+
+/* #define DEBUG_PLIVE */
+/* #define DEBUG_LIVE */
+/* #define DEBUG_OUT */
+/* #define DEBUG_CAPTURE */
+/* #define DEBUG_POLL */
+
+#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
+
+
+/* Order of CONFIG_AUDIO_DRIVERS is import.
+   The 1st one is the one used by default, that is the reason
+    that we generate the list.
+*/
+static struct audio_driver *drvtab[] = {
+#ifdef CONFIG_SPICE
+    &spice_audio_driver,
+#endif
+    CONFIG_AUDIO_DRIVERS
+    &no_audio_driver,
+    &wav_audio_driver
+};
+
+struct fixed_settings {
+    int enabled;
+    int nb_voices;
+    int greedy;
+    struct audsettings settings;
+};
+
+static struct {
+    struct fixed_settings fixed_out;
+    struct fixed_settings fixed_in;
+    union {
+        int hertz;
+        int64_t ticks;
+    } period;
+    int plive;
+    int log_to_monitor;
+    int try_poll_in;
+    int try_poll_out;
+} conf = {
+    .fixed_out = { /* DAC fixed settings */
+        .enabled = 1,
+        .nb_voices = 1,
+        .greedy = 1,
+        .settings = {
+            .freq = 44100,
+            .nchannels = 2,
+            .fmt = AUD_FMT_S16,
+            .endianness =  AUDIO_HOST_ENDIANNESS,
+        }
+    },
+
+    .fixed_in = { /* ADC fixed settings */
+        .enabled = 1,
+        .nb_voices = 1,
+        .greedy = 1,
+        .settings = {
+            .freq = 44100,
+            .nchannels = 2,
+            .fmt = AUD_FMT_S16,
+            .endianness = AUDIO_HOST_ENDIANNESS,
+        }
+    },
+
+    .period = { .hertz = 250 },
+    .plive = 0,
+    .log_to_monitor = 0,
+    .try_poll_in = 1,
+    .try_poll_out = 1,
+};
+
+static AudioState glob_audio_state;
+
+const struct mixeng_volume nominal_volume = {
+    .mute = 0,
+#ifdef FLOAT_MIXENG
+    .r = 1.0,
+    .l = 1.0,
+#else
+    .r = 1ULL << 32,
+    .l = 1ULL << 32,
+#endif
+};
+
+#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
+#error No its not
+#else
+static void audio_print_options (const char *prefix,
+                                 struct audio_option *opt);
+
+int audio_bug (const char *funcname, int cond)
+{
+    if (cond) {
+        static int shown;
+
+        AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
+        if (!shown) {
+            struct audio_driver *d;
+
+            shown = 1;
+            AUD_log (NULL, "Save all your work and restart without audio\n");
+            AUD_log (NULL, "Please send bug report to av1474 at comtv.ru\n");
+            AUD_log (NULL, "I am sorry\n");
+            d = glob_audio_state.drv;
+            if (d) {
+                audio_print_options (d->name, d->options);
+            }
+        }
+        AUD_log (NULL, "Context:\n");
+
+#if defined AUDIO_BREAKPOINT_ON_BUG
+#  if defined HOST_I386
+#    if defined __GNUC__
+        __asm__ ("int3");
+#    elif defined _MSC_VER
+        _asm _emit 0xcc;
+#    else
+        abort ();
+#    endif
+#  else
+        abort ();
+#  endif
+#endif
+    }
+
+    return cond;
+}
+#endif
+
+static inline int audio_bits_to_index (int bits)
+{
+    switch (bits) {
+    case 8:
+        return 0;
+
+    case 16:
+        return 1;
+
+    case 32:
+        return 2;
+
+    default:
+        audio_bug ("bits_to_index", 1);
+        AUD_log (NULL, "invalid bits %d\n", bits);
+        return 0;
+    }
+}
+
+void *audio_calloc (const char *funcname, int nmemb, size_t size)
+{
+    int cond;
+    size_t len;
+
+    len = nmemb * size;
+    cond = !nmemb || !size;
+    cond |= nmemb < 0;
+    cond |= len < size;
+
+    if (audio_bug ("audio_calloc", cond)) {
+        AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
+                 funcname);
+        AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
+        return NULL;
+    }
+
+    return qemu_mallocz (len);
+}
+
+static char *audio_alloc_prefix (const char *s)
+{
+    const char qemu_prefix[] = "QEMU_";
+    size_t len, i;
+    char *r, *u;
+
+    if (!s) {
+        return NULL;
+    }
+
+    len = strlen (s);
+    r = qemu_malloc (len + sizeof (qemu_prefix));
+
+    u = r + sizeof (qemu_prefix) - 1;
+
+    pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix);
+    pstrcat (r, len + sizeof (qemu_prefix), s);
+
+    for (i = 0; i < len; ++i) {
+        u[i] = qemu_toupper(u[i]);
+    }
+
+    return r;
+}
+
+static const char *audio_audfmt_to_string (audfmt_e fmt)
+{
+    switch (fmt) {
+    case AUD_FMT_U8:
+        return "U8";
+
+    case AUD_FMT_U16:
+        return "U16";
+
+    case AUD_FMT_S8:
+        return "S8";
+
+    case AUD_FMT_S16:
+        return "S16";
+
+    case AUD_FMT_U32:
+        return "U32";
+
+    case AUD_FMT_S32:
+        return "S32";
+    }
+
+    dolog ("Bogus audfmt %d returning S16\n", fmt);
+    return "S16";
+}
+
+static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
+                                        int *defaultp)
+{
+    if (!strcasecmp (s, "u8")) {
+        *defaultp = 0;
+        return AUD_FMT_U8;
+    }
+    else if (!strcasecmp (s, "u16")) {
+        *defaultp = 0;
+        return AUD_FMT_U16;
+    }
+    else if (!strcasecmp (s, "u32")) {
+        *defaultp = 0;
+        return AUD_FMT_U32;
+    }
+    else if (!strcasecmp (s, "s8")) {
+        *defaultp = 0;
+        return AUD_FMT_S8;
+    }
+    else if (!strcasecmp (s, "s16")) {
+        *defaultp = 0;
+        return AUD_FMT_S16;
+    }
+    else if (!strcasecmp (s, "s32")) {
+        *defaultp = 0;
+        return AUD_FMT_S32;
+    }
+    else {
+        dolog ("Bogus audio format `%s' using %s\n",
+               s, audio_audfmt_to_string (defval));
+        *defaultp = 1;
+        return defval;
+    }
+}
+
+static audfmt_e audio_get_conf_fmt (const char *envname,
+                                    audfmt_e defval,
+                                    int *defaultp)
+{
+    const char *var = getenv (envname);
+    if (!var) {
+        *defaultp = 1;
+        return defval;
+    }
+    return audio_string_to_audfmt (var, defval, defaultp);
+}
+
+static int audio_get_conf_int (const char *key, int defval, int *defaultp)
+{
+    int val;
+    char *strval;
+
+    strval = getenv (key);
+    if (strval) {
+        *defaultp = 0;
+        val = atoi (strval);
+        return val;
+    }
+    else {
+        *defaultp = 1;
+        return defval;
+    }
+}
+
+static const char *audio_get_conf_str (const char *key,
+                                       const char *defval,
+                                       int *defaultp)
+{
+    const char *val = getenv (key);
+    if (!val) {
+        *defaultp = 1;
+        return defval;
+    }
+    else {
+        *defaultp = 0;
+        return val;
+    }
+}
+
+void AUD_vlog (const char *cap, const char *fmt, va_list ap)
+{
+    if (conf.log_to_monitor) {
+        if (cap) {
+            monitor_printf(default_mon, "%s: ", cap);
+        }
+
+        monitor_vprintf(default_mon, fmt, ap);
+    }
+    else {
+        if (cap) {
+            fprintf (stderr, "%s: ", cap);
+        }
+
+        vfprintf (stderr, fmt, ap);
+    }
+}
+
+void AUD_log (const char *cap, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (cap, fmt, ap);
+    va_end (ap);
+}
+
+static void audio_print_options (const char *prefix,
+                                 struct audio_option *opt)
+{
+    char *uprefix;
+
+    if (!prefix) {
+        dolog ("No prefix specified\n");
+        return;
+    }
+
+    if (!opt) {
+        dolog ("No options\n");
+        return;
+    }
+
+    uprefix = audio_alloc_prefix (prefix);
+
+    for (; opt->name; opt++) {
+        const char *state = "default";
+        printf ("  %s_%s: ", uprefix, opt->name);
+
+        if (opt->overriddenp && *opt->overriddenp) {
+            state = "current";
+        }
+
+        switch (opt->tag) {
+        case AUD_OPT_BOOL:
+            {
+                int *intp = opt->valp;
+                printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
+            }
+            break;
+
+        case AUD_OPT_INT:
+            {
+                int *intp = opt->valp;
+                printf ("integer, %s = %d\n", state, *intp);
+            }
+            break;
+
+        case AUD_OPT_FMT:
+            {
+                audfmt_e *fmtp = opt->valp;
+                printf (
+                    "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n",
+                    state,
+                    audio_audfmt_to_string (*fmtp)
+                    );
+            }
+            break;
+
+        case AUD_OPT_STR:
+            {
+                const char **strp = opt->valp;
+                printf ("string, %s = %s\n",
+                        state,
+                        *strp ? *strp : "(not set)");
+            }
+            break;
+
+        default:
+            printf ("???\n");
+            dolog ("Bad value tag for option %s_%s %d\n",
+                   uprefix, opt->name, opt->tag);
+            break;
+        }
+        printf ("    %s\n", opt->descr);
+    }
+
+    qemu_free (uprefix);
+}
+
+static void audio_process_options (const char *prefix,
+                                   struct audio_option *opt)
+{
+    char *optname;
+    const char qemu_prefix[] = "QEMU_";
+    size_t preflen, optlen;
+
+    if (audio_bug (AUDIO_FUNC, !prefix)) {
+        dolog ("prefix = NULL\n");
+        return;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !opt)) {
+        dolog ("opt = NULL\n");
+        return;
+    }
+
+    preflen = strlen (prefix);
+
+    for (; opt->name; opt++) {
+        size_t len, i;
+        int def;
+
+        if (!opt->valp) {
+            dolog ("Option value pointer for `%s' is not set\n",
+                   opt->name);
+            continue;
+        }
+
+        len = strlen (opt->name);
+        /* len of opt->name + len of prefix + size of qemu_prefix
+         * (includes trailing zero) + zero + underscore (on behalf of
+         * sizeof) */
+        optlen = len + preflen + sizeof (qemu_prefix) + 1;
+        optname = qemu_malloc (optlen);
+
+        pstrcpy (optname, optlen, qemu_prefix);
+
+        /* copy while upper-casing, including trailing zero */
+        for (i = 0; i <= preflen; ++i) {
+            optname[i + sizeof (qemu_prefix) - 1] = qemu_toupper(prefix[i]);
+        }
+        pstrcat (optname, optlen, "_");
+        pstrcat (optname, optlen, opt->name);
+
+        def = 1;
+        switch (opt->tag) {
+        case AUD_OPT_BOOL:
+        case AUD_OPT_INT:
+            {
+                int *intp = opt->valp;
+                *intp = audio_get_conf_int (optname, *intp, &def);
+            }
+            break;
+
+        case AUD_OPT_FMT:
+            {
+                audfmt_e *fmtp = opt->valp;
+                *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
+            }
+            break;
+
+        case AUD_OPT_STR:
+            {
+                const char **strp = opt->valp;
+                *strp = audio_get_conf_str (optname, *strp, &def);
+            }
+            break;
+
+        default:
+            dolog ("Bad value tag for option `%s' - %d\n",
+                   optname, opt->tag);
+            break;
+        }
+
+        if (!opt->overriddenp) {
+            opt->overriddenp = &opt->overridden;
+        }
+        *opt->overriddenp = !def;
+        qemu_free (optname);
+    }
+}
+
+static void audio_print_settings (struct audsettings *as)
+{
+    dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        AUD_log (NULL, "S8");
+        break;
+    case AUD_FMT_U8:
+        AUD_log (NULL, "U8");
+        break;
+    case AUD_FMT_S16:
+        AUD_log (NULL, "S16");
+        break;
+    case AUD_FMT_U16:
+        AUD_log (NULL, "U16");
+        break;
+    case AUD_FMT_S32:
+        AUD_log (NULL, "S32");
+        break;
+    case AUD_FMT_U32:
+        AUD_log (NULL, "U32");
+        break;
+    default:
+        AUD_log (NULL, "invalid(%d)", as->fmt);
+        break;
+    }
+
+    AUD_log (NULL, " endianness=");
+    switch (as->endianness) {
+    case 0:
+        AUD_log (NULL, "little");
+        break;
+    case 1:
+        AUD_log (NULL, "big");
+        break;
+    default:
+        AUD_log (NULL, "invalid");
+        break;
+    }
+    AUD_log (NULL, "\n");
+}
+
+static int audio_validate_settings (struct audsettings *as)
+{
+    int invalid;
+
+    invalid = as->nchannels != 1 && as->nchannels != 2;
+    invalid |= as->endianness != 0 && as->endianness != 1;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        break;
+    default:
+        invalid = 1;
+        break;
+    }
+
+    invalid |= as->freq <= 0;
+    return invalid ? -1 : 0;
+}
+
+static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
+{
+    int bits = 8, sign = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        sign = 1;
+    case AUD_FMT_U8:
+        break;
+
+    case AUD_FMT_S16:
+        sign = 1;
+    case AUD_FMT_U16:
+        bits = 16;
+        break;
+
+    case AUD_FMT_S32:
+        sign = 1;
+    case AUD_FMT_U32:
+        bits = 32;
+        break;
+    }
+    return info->freq == as->freq
+        && info->nchannels == as->nchannels
+        && info->sign == sign
+        && info->bits == bits
+        && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
+}
+
+void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
+{
+    int bits = 8, sign = 0, shift = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        sign = 1;
+    case AUD_FMT_U8:
+        break;
+
+    case AUD_FMT_S16:
+        sign = 1;
+    case AUD_FMT_U16:
+        bits = 16;
+        shift = 1;
+        break;
+
+    case AUD_FMT_S32:
+        sign = 1;
+    case AUD_FMT_U32:
+        bits = 32;
+        shift = 2;
+        break;
+    }
+
+    info->freq = as->freq;
+    info->bits = bits;
+    info->sign = sign;
+    info->nchannels = as->nchannels;
+    info->shift = (as->nchannels == 2) + shift;
+    info->align = (1 << info->shift) - 1;
+    info->bytes_per_second = info->freq << info->shift;
+    info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
+}
+
+void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
+{
+    if (!len) {
+        return;
+    }
+
+    if (info->sign) {
+        memset (buf, 0x00, len << info->shift);
+    }
+    else {
+        switch (info->bits) {
+        case 8:
+            memset (buf, 0x80, len << info->shift);
+            break;
+
+        case 16:
+            {
+                int i;
+                uint16_t *p = buf;
+                int shift = info->nchannels - 1;
+                short s = INT16_MAX;
+
+                if (info->swap_endianness) {
+                    s = bswap16 (s);
+                }
+
+                for (i = 0; i < len << shift; i++) {
+                    p[i] = s;
+                }
+            }
+            break;
+
+        case 32:
+            {
+                int i;
+                uint32_t *p = buf;
+                int shift = info->nchannels - 1;
+                int32_t s = INT32_MAX;
+
+                if (info->swap_endianness) {
+                    s = bswap32 (s);
+                }
+
+                for (i = 0; i < len << shift; i++) {
+                    p[i] = s;
+                }
+            }
+            break;
+
+        default:
+            AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
+                     info->bits);
+            break;
+        }
+    }
+}
+
+/*
+ * Capture
+ */
+static void noop_conv (struct st_sample *dst, const void *src, int samples)
+{
+    (void) src;
+    (void) dst;
+    (void) samples;
+}
+
+static CaptureVoiceOut *audio_pcm_capture_find_specific (
+    struct audsettings *as
+    )
+{
+    CaptureVoiceOut *cap;
+    AudioState *s = &glob_audio_state;
+
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        if (audio_pcm_info_eq (&cap->hw.info, as)) {
+            return cap;
+        }
+    }
+    return NULL;
+}
+
+static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
+{
+    struct capture_callback *cb;
+
+#ifdef DEBUG_CAPTURE
+    dolog ("notification %d sent\n", cmd);
+#endif
+    for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+        cb->ops.notify (cb->opaque, cmd);
+    }
+}
+
+static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
+{
+    if (cap->hw.enabled != enabled) {
+        audcnotification_e cmd;
+        cap->hw.enabled = enabled;
+        cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
+        audio_notify_capture (cap, cmd);
+    }
+}
+
+static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
+{
+    HWVoiceOut *hw = &cap->hw;
+    SWVoiceOut *sw;
+    int enabled = 0;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active) {
+            enabled = 1;
+            break;
+        }
+    }
+    audio_capture_maybe_changed (cap, enabled);
+}
+
+static void audio_detach_capture (HWVoiceOut *hw)
+{
+    SWVoiceCap *sc = hw->cap_head.lh_first;
+
+    while (sc) {
+        SWVoiceCap *sc1 = sc->entries.le_next;
+        SWVoiceOut *sw = &sc->sw;
+        CaptureVoiceOut *cap = sc->cap;
+        int was_active = sw->active;
+
+        if (sw->rate) {
+            st_rate_stop (sw->rate);
+            sw->rate = NULL;
+        }
+
+        QLIST_REMOVE (sw, entries);
+        QLIST_REMOVE (sc, entries);
+        qemu_free (sc);
+        if (was_active) {
+            /* We have removed soft voice from the capture:
+               this might have changed the overall status of the capture
+               since this might have been the only active voice */
+            audio_recalc_and_notify_capture (cap);
+        }
+        sc = sc1;
+    }
+}
+
+static int audio_attach_capture (HWVoiceOut *hw)
+{
+    AudioState *s = &glob_audio_state;
+    CaptureVoiceOut *cap;
+
+    audio_detach_capture (hw);
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        SWVoiceCap *sc;
+        SWVoiceOut *sw;
+        HWVoiceOut *hw_cap = &cap->hw;
+
+        sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
+        if (!sc) {
+            dolog ("Could not allocate soft capture voice (%zu bytes)\n",
+                   sizeof (*sc));
+            return -1;
+        }
+
+        sc->cap = cap;
+        sw = &sc->sw;
+        sw->hw = hw_cap;
+        sw->info = hw->info;
+        sw->empty = 1;
+        sw->active = hw->enabled;
+        sw->conv = noop_conv;
+        sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
+        sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
+        if (!sw->rate) {
+            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
+            qemu_free (sw);
+            return -1;
+        }
+        QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
+        QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
+#ifdef DEBUG_CAPTURE
+        asprintf (&sw->name, "for %p %d,%d,%d",
+                  hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
+        dolog ("Added %s active = %d\n", sw->name, sw->active);
+#endif
+        if (sw->active) {
+            audio_capture_maybe_changed (cap, 1);
+        }
+    }
+    return 0;
+}
+
+/*
+ * Hard voice (capture)
+ */
+static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
+{
+    SWVoiceIn *sw;
+    int m = hw->total_samples_captured;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active) {
+            m = audio_MIN (m, sw->total_hw_samples_acquired);
+        }
+    }
+    return m;
+}
+
+int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
+{
+    int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
+    }
+    return live;
+}
+
+int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
+                           int live, int pending)
+{
+    int left = hw->samples - pending;
+    int len = audio_MIN (left, live);
+    int clipped = 0;
+
+    while (len) {
+        struct st_sample *src = hw->mix_buf + hw->rpos;
+        uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
+        int samples_till_end_of_buf = hw->samples - hw->rpos;
+        int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
+
+        hw->clip (dst, src, samples_to_clip);
+
+        hw->rpos = (hw->rpos + samples_to_clip) % hw->samples;
+        len -= samples_to_clip;
+        clipped += samples_to_clip;
+    }
+    return clipped;
+}
+
+/*
+ * Soft voice (capture)
+ */
+static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
+{
+    HWVoiceIn *hw = sw->hw;
+    int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    int rpos;
+
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
+    }
+
+    rpos = hw->wpos - live;
+    if (rpos >= 0) {
+        return rpos;
+    }
+    else {
+        return hw->samples + rpos;
+    }
+}
+
+int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
+{
+    HWVoiceIn *hw = sw->hw;
+    int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
+    struct st_sample *src, *dst = sw->buf;
+
+    rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
+
+    live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
+    }
+
+    samples = size >> sw->info.shift;
+    if (!live) {
+        return 0;
+    }
+
+    swlim = (live * sw->ratio) >> 32;
+    swlim = audio_MIN (swlim, samples);
+
+    while (swlim) {
+        src = hw->conv_buf + rpos;
+        isamp = hw->wpos - rpos;
+        /* XXX: <= ? */
+        if (isamp <= 0) {
+            isamp = hw->samples - rpos;
+        }
+
+        if (!isamp) {
+            break;
+        }
+        osamp = swlim;
+
+        if (audio_bug (AUDIO_FUNC, osamp < 0)) {
+            dolog ("osamp=%d\n", osamp);
+            return 0;
+        }
+
+        st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
+        swlim -= osamp;
+        rpos = (rpos + isamp) % hw->samples;
+        dst += osamp;
+        ret += osamp;
+        total += isamp;
+    }
+
+    mixeng_volume (sw->buf, ret, &sw->vol);
+
+    sw->clip (buf, sw->buf, ret);
+    sw->total_hw_samples_acquired += total;
+    return ret << sw->info.shift;
+}
+
+/*
+ * Hard voice (playback)
+ */
+static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
+{
+    SWVoiceOut *sw;
+    int m = INT_MAX;
+    int nb_live = 0;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active || !sw->empty) {
+            m = audio_MIN (m, sw->total_hw_samples_mixed);
+            nb_live += 1;
+        }
+    }
+
+    *nb_livep = nb_live;
+    return m;
+}
+
+static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
+{
+    int smin;
+    int nb_live1;
+
+    smin = audio_pcm_hw_find_min_out (hw, &nb_live1);
+    if (nb_live) {
+        *nb_live = nb_live1;
+    }
+
+    if (nb_live1) {
+        int live = smin;
+
+        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+            return 0;
+        }
+        return live;
+    }
+    return 0;
+}
+
+/*
+ * Soft voice (playback)
+ */
+int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
+{
+    int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
+    int ret = 0, pos = 0, total = 0;
+
+    if (!sw) {
+        return size;
+    }
+
+    hwsamples = sw->hw->samples;
+
+    live = sw->total_hw_samples_mixed;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
+        dolog ("live=%d hw->samples=%d\n", live, hwsamples);
+        return 0;
+    }
+
+    if (live == hwsamples) {
+#ifdef DEBUG_OUT
+        dolog ("%s is full %d\n", sw->name, live);
+#endif
+        return 0;
+    }
+
+    wpos = (sw->hw->rpos + live) % hwsamples;
+    samples = size >> sw->info.shift;
+
+    dead = hwsamples - live;
+    swlim = ((int64_t) dead << 32) / sw->ratio;
+    swlim = audio_MIN (swlim, samples);
+    if (swlim) {
+        sw->conv (sw->buf, buf, swlim);
+        mixeng_volume (sw->buf, swlim, &sw->vol);
+    }
+
+    while (swlim) {
+        dead = hwsamples - live;
+        left = hwsamples - wpos;
+        blck = audio_MIN (dead, left);
+        if (!blck) {
+            break;
+        }
+        isamp = swlim;
+        osamp = blck;
+        st_rate_flow_mix (
+            sw->rate,
+            sw->buf + pos,
+            sw->hw->mix_buf + wpos,
+            &isamp,
+            &osamp
+            );
+        ret += isamp;
+        swlim -= isamp;
+        pos += isamp;
+        live += osamp;
+        wpos = (wpos + osamp) % hwsamples;
+        total += osamp;
+    }
+
+    sw->total_hw_samples_mixed += total;
+    sw->empty = sw->total_hw_samples_mixed == 0;
+
+#ifdef DEBUG_OUT
+    dolog (
+        "%s: write size %d ret %d total sw %d\n",
+        SW_NAME (sw),
+        size >> sw->info.shift,
+        ret,
+        sw->total_hw_samples_mixed
+        );
+#endif
+
+    return ret << sw->info.shift;
+}
+
+#ifdef DEBUG_AUDIO
+static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
+{
+    dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
+           cap, info->bits, info->sign, info->freq, info->nchannels);
+}
+#endif
+
+#define DAC
+#include "audio_template.h"
+#undef DAC
+#include "audio_template.h"
+
+/*
+ * Timer
+ */
+static int audio_is_timer_needed (void)
+{
+    HWVoiceIn *hwi = NULL;
+    HWVoiceOut *hwo = NULL;
+
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
+        if (!hwo->poll_mode) return 1;
+    }
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
+        if (!hwi->poll_mode) return 1;
+    }
+    return 0;
+}
+
+static void audio_reset_timer (AudioState *s)
+{
+    if (audio_is_timer_needed ()) {
+        qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1);
+    }
+    else {
+        qemu_del_timer (s->ts);
+    }
+}
+
+static void audio_timer (void *opaque)
+{
+    audio_run ("timer");
+    audio_reset_timer (opaque);
+}
+
+/*
+ * Public API
+ */
+int AUD_write (SWVoiceOut *sw, void *buf, int size)
+{
+    int bytes;
+
+    if (!sw) {
+        /* XXX: Consider options */
+        return size;
+    }
+
+    if (!sw->hw->enabled) {
+        dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
+        return 0;
+    }
+
+    bytes = sw->hw->pcm_ops->write (sw, buf, size);
+    return bytes;
+}
+
+int AUD_read (SWVoiceIn *sw, void *buf, int size)
+{
+    int bytes;
+
+    if (!sw) {
+        /* XXX: Consider options */
+        return size;
+    }
+
+    if (!sw->hw->enabled) {
+        dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
+        return 0;
+    }
+
+    bytes = sw->hw->pcm_ops->read (sw, buf, size);
+    return bytes;
+}
+
+int AUD_get_buffer_size_out (SWVoiceOut *sw)
+{
+    return sw->hw->samples << sw->hw->info.shift;
+}
+
+void AUD_set_active_out (SWVoiceOut *sw, int on)
+{
+    HWVoiceOut *hw;
+
+    if (!sw) {
+        return;
+    }
+
+    hw = sw->hw;
+    if (sw->active != on) {
+        AudioState *s = &glob_audio_state;
+        SWVoiceOut *temp_sw;
+        SWVoiceCap *sc;
+
+        if (on) {
+            hw->pending_disable = 0;
+            if (!hw->enabled) {
+                hw->enabled = 1;
+                if (s->vm_running) {
+                    hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
+                    audio_reset_timer (s);
+                }
+            }
+        }
+        else {
+            if (hw->enabled) {
+                int nb_active = 0;
+
+                for (temp_sw = hw->sw_head.lh_first; temp_sw;
+                     temp_sw = temp_sw->entries.le_next) {
+                    nb_active += temp_sw->active != 0;
+                }
+
+                hw->pending_disable = nb_active == 1;
+            }
+        }
+
+        for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            sc->sw.active = hw->enabled;
+            if (hw->enabled) {
+                audio_capture_maybe_changed (sc->cap, 1);
+            }
+        }
+        sw->active = on;
+    }
+}
+
+void AUD_set_active_in (SWVoiceIn *sw, int on)
+{
+    HWVoiceIn *hw;
+
+    if (!sw) {
+        return;
+    }
+
+    hw = sw->hw;
+    if (sw->active != on) {
+        AudioState *s = &glob_audio_state;
+        SWVoiceIn *temp_sw;
+
+        if (on) {
+            if (!hw->enabled) {
+                hw->enabled = 1;
+                if (s->vm_running) {
+                    hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
+                    audio_reset_timer (s);
+                }
+            }
+            sw->total_hw_samples_acquired = hw->total_samples_captured;
+        }
+        else {
+            if (hw->enabled) {
+                int nb_active = 0;
+
+                for (temp_sw = hw->sw_head.lh_first; temp_sw;
+                     temp_sw = temp_sw->entries.le_next) {
+                    nb_active += temp_sw->active != 0;
+                }
+
+                if (nb_active == 1) {
+                    hw->enabled = 0;
+                    hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
+                }
+            }
+        }
+        sw->active = on;
+    }
+}
+
+static int audio_get_avail (SWVoiceIn *sw)
+{
+    int live;
+
+    if (!sw) {
+        return 0;
+    }
+
+    live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
+        return 0;
+    }
+
+    ldebug (
+        "%s: get_avail live %d ret %" PRId64 "\n",
+        SW_NAME (sw),
+        live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
+        );
+
+    return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
+}
+
+static int audio_get_free (SWVoiceOut *sw)
+{
+    int live, dead;
+
+    if (!sw) {
+        return 0;
+    }
+
+    live = sw->total_hw_samples_mixed;
+
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
+        return 0;
+    }
+
+    dead = sw->hw->samples - live;
+
+#ifdef DEBUG_OUT
+    dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
+           SW_NAME (sw),
+           live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
+#endif
+
+    return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
+}
+
+static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
+{
+    int n;
+
+    if (hw->enabled) {
+        SWVoiceCap *sc;
+
+        for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            SWVoiceOut *sw = &sc->sw;
+            int rpos2 = rpos;
+
+            n = samples;
+            while (n) {
+                int till_end_of_hw = hw->samples - rpos2;
+                int to_write = audio_MIN (till_end_of_hw, n);
+                int bytes = to_write << hw->info.shift;
+                int written;
+
+                sw->buf = hw->mix_buf + rpos2;
+                written = audio_pcm_sw_write (sw, NULL, bytes);
+                if (written - bytes) {
+                    dolog ("Could not mix %d bytes into a capture "
+                           "buffer, mixed %d\n",
+                           bytes, written);
+                    break;
+                }
+                n -= to_write;
+                rpos2 = (rpos2 + to_write) % hw->samples;
+            }
+        }
+    }
+
+    n = audio_MIN (samples, hw->samples - rpos);
+    mixeng_clear (hw->mix_buf + rpos, n);
+    mixeng_clear (hw->mix_buf, samples - n);
+}
+
+static void audio_run_out (AudioState *s)
+{
+    HWVoiceOut *hw = NULL;
+    SWVoiceOut *sw;
+
+    while ((hw = audio_pcm_hw_find_any_enabled_out (hw))) {
+        int played;
+        int live, free, nb_live, cleanup_required, prev_rpos;
+
+        live = audio_pcm_hw_get_live_out (hw, &nb_live);
+        if (!nb_live) {
+            live = 0;
+        }
+
+        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+            continue;
+        }
+
+        if (hw->pending_disable && !nb_live) {
+            SWVoiceCap *sc;
+#ifdef DEBUG_OUT
+            dolog ("Disabling voice\n");
+#endif
+            hw->enabled = 0;
+            hw->pending_disable = 0;
+            hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+            for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+                sc->sw.active = 0;
+                audio_recalc_and_notify_capture (sc->cap);
+            }
+            continue;
+        }
+
+        if (!live) {
+            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+                if (sw->active) {
+                    free = audio_get_free (sw);
+                    if (free > 0) {
+                        sw->callback.fn (sw->callback.opaque, free);
+                    }
+                }
+            }
+            continue;
+        }
+
+        prev_rpos = hw->rpos;
+        played = hw->pcm_ops->run_out (hw, live);
+        if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
+            dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
+                   hw->rpos, hw->samples, played);
+            hw->rpos = 0;
+        }
+
+#ifdef DEBUG_OUT
+        dolog ("played=%d\n", played);
+#endif
+
+        if (played) {
+            hw->ts_helper += played;
+            audio_capture_mix_and_clear (hw, prev_rpos, played);
+        }
+
+        cleanup_required = 0;
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            if (!sw->active && sw->empty) {
+                continue;
+            }
+
+            if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
+                dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
+                       played, sw->total_hw_samples_mixed);
+                played = sw->total_hw_samples_mixed;
+            }
+
+            sw->total_hw_samples_mixed -= played;
+
+            if (!sw->total_hw_samples_mixed) {
+                sw->empty = 1;
+                cleanup_required |= !sw->active && !sw->callback.fn;
+            }
+
+            if (sw->active) {
+                free = audio_get_free (sw);
+                if (free > 0) {
+                    sw->callback.fn (sw->callback.opaque, free);
+                }
+            }
+        }
+
+        if (cleanup_required) {
+            SWVoiceOut *sw1;
+
+            sw = hw->sw_head.lh_first;
+            while (sw) {
+                sw1 = sw->entries.le_next;
+                if (!sw->active && !sw->callback.fn) {
+#ifdef DEBUG_PLIVE
+                    dolog ("Finishing with old voice\n");
+#endif
+                    audio_close_out (sw);
+                }
+                sw = sw1;
+            }
+        }
+    }
+}
+
+static void audio_run_in (AudioState *s)
+{
+    HWVoiceIn *hw = NULL;
+
+    while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
+        SWVoiceIn *sw;
+        int captured, min;
+
+        captured = hw->pcm_ops->run_in (hw);
+
+        min = audio_pcm_hw_find_min_in (hw);
+        hw->total_samples_captured += captured - min;
+        hw->ts_helper += captured;
+
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            sw->total_hw_samples_acquired -= min;
+
+            if (sw->active) {
+                int avail;
+
+                avail = audio_get_avail (sw);
+                if (avail > 0) {
+                    sw->callback.fn (sw->callback.opaque, avail);
+                }
+            }
+        }
+    }
+}
+
+static void audio_run_capture (AudioState *s)
+{
+    CaptureVoiceOut *cap;
+
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        int live, rpos, captured;
+        HWVoiceOut *hw = &cap->hw;
+        SWVoiceOut *sw;
+
+        captured = live = audio_pcm_hw_get_live_out (hw, NULL);
+        rpos = hw->rpos;
+        while (live) {
+            int left = hw->samples - rpos;
+            int to_capture = audio_MIN (live, left);
+            struct st_sample *src;
+            struct capture_callback *cb;
+
+            src = hw->mix_buf + rpos;
+            hw->clip (cap->buf, src, to_capture);
+            mixeng_clear (src, to_capture);
+
+            for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+                cb->ops.capture (cb->opaque, cap->buf,
+                                 to_capture << hw->info.shift);
+            }
+            rpos = (rpos + to_capture) % hw->samples;
+            live -= to_capture;
+        }
+        hw->rpos = rpos;
+
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            if (!sw->active && sw->empty) {
+                continue;
+            }
+
+            if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
+                dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
+                       captured, sw->total_hw_samples_mixed);
+                captured = sw->total_hw_samples_mixed;
+            }
+
+            sw->total_hw_samples_mixed -= captured;
+            sw->empty = sw->total_hw_samples_mixed == 0;
+        }
+    }
+}
+
+void audio_run (const char *msg)
+{
+    AudioState *s = &glob_audio_state;
+
+    audio_run_out (s);
+    audio_run_in (s);
+    audio_run_capture (s);
+#ifdef DEBUG_POLL
+    {
+        static double prevtime;
+        double currtime;
+        struct timeval tv;
+
+        if (gettimeofday (&tv, NULL)) {
+            perror ("audio_run: gettimeofday");
+            return;
+        }
+
+        currtime = tv.tv_sec + tv.tv_usec * 1e-6;
+        dolog ("Elapsed since last %s: %f\n", msg, currtime - prevtime);
+        prevtime = currtime;
+    }
+#endif
+}
+
+static struct audio_option audio_options[] = {
+    /* DAC */
+    {
+        .name  = "DAC_FIXED_SETTINGS",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.fixed_out.enabled,
+        .descr = "Use fixed settings for host DAC"
+    },
+    {
+        .name  = "DAC_FIXED_FREQ",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_out.settings.freq,
+        .descr = "Frequency for fixed host DAC"
+    },
+    {
+        .name  = "DAC_FIXED_FMT",
+        .tag   = AUD_OPT_FMT,
+        .valp  = &conf.fixed_out.settings.fmt,
+        .descr = "Format for fixed host DAC"
+    },
+    {
+        .name  = "DAC_FIXED_CHANNELS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_out.settings.nchannels,
+        .descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)"
+    },
+    {
+        .name  = "DAC_VOICES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_out.nb_voices,
+        .descr = "Number of voices for DAC"
+    },
+    {
+        .name  = "DAC_TRY_POLL",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.try_poll_out,
+        .descr = "Attempt using poll mode for DAC"
+    },
+    /* ADC */
+    {
+        .name  = "ADC_FIXED_SETTINGS",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.fixed_in.enabled,
+        .descr = "Use fixed settings for host ADC"
+    },
+    {
+        .name  = "ADC_FIXED_FREQ",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_in.settings.freq,
+        .descr = "Frequency for fixed host ADC"
+    },
+    {
+        .name  = "ADC_FIXED_FMT",
+        .tag   = AUD_OPT_FMT,
+        .valp  = &conf.fixed_in.settings.fmt,
+        .descr = "Format for fixed host ADC"
+    },
+    {
+        .name  = "ADC_FIXED_CHANNELS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_in.settings.nchannels,
+        .descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)"
+    },
+    {
+        .name  = "ADC_VOICES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fixed_in.nb_voices,
+        .descr = "Number of voices for ADC"
+    },
+    {
+        .name  = "ADC_TRY_POLL",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.try_poll_in,
+        .descr = "Attempt using poll mode for ADC"
+    },
+    /* Misc */
+    {
+        .name  = "TIMER_PERIOD",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.period.hertz,
+        .descr = "Timer period in HZ (0 - use lowest possible)"
+    },
+    {
+        .name  = "PLIVE",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.plive,
+        .descr = "(undocumented)"
+    },
+    {
+        .name  = "LOG_TO_MONITOR",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.log_to_monitor,
+        .descr = "Print logging messages to monitor instead of stderr"
+    },
+    { /* End of list */ }
+};
+
+static void audio_pp_nb_voices (const char *typ, int nb)
+{
+    switch (nb) {
+    case 0:
+        printf ("Does not support %s\n", typ);
+        break;
+    case 1:
+        printf ("One %s voice\n", typ);
+        break;
+    case INT_MAX:
+        printf ("Theoretically supports many %s voices\n", typ);
+        break;
+    default:
+        printf ("Theoretically supports upto %d %s voices\n", nb, typ);
+        break;
+    }
+
+}
+
+void AUD_help (void)
+{
+    size_t i;
+
+    audio_process_options ("AUDIO", audio_options);
+    for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+        struct audio_driver *d = drvtab[i];
+        if (d->options) {
+            audio_process_options (d->name, d->options);
+        }
+    }
+
+    printf ("Audio options:\n");
+    audio_print_options ("AUDIO", audio_options);
+    printf ("\n");
+
+    printf ("Available drivers:\n");
+
+    for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+        struct audio_driver *d = drvtab[i];
+
+        printf ("Name: %s\n", d->name);
+        printf ("Description: %s\n", d->descr);
+
+        audio_pp_nb_voices ("playback", d->max_voices_out);
+        audio_pp_nb_voices ("capture", d->max_voices_in);
+
+        if (d->options) {
+            printf ("Options:\n");
+            audio_print_options (d->name, d->options);
+        }
+        else {
+            printf ("No options\n");
+        }
+        printf ("\n");
+    }
+
+    printf (
+        "Options are settable through environment variables.\n"
+        "Example:\n"
+#ifdef _WIN32
+        "  set QEMU_AUDIO_DRV=wav\n"
+        "  set QEMU_WAV_PATH=c:\\tune.wav\n"
+#else
+        "  export QEMU_AUDIO_DRV=wav\n"
+        "  export QEMU_WAV_PATH=$HOME/tune.wav\n"
+        "(for csh replace export with setenv in the above)\n"
+#endif
+        "  qemu ...\n\n"
+        );
+}
+
+static int audio_driver_init (AudioState *s, struct audio_driver *drv)
+{
+    if (drv->options) {
+        audio_process_options (drv->name, drv->options);
+    }
+    s->drv_opaque = drv->init ();
+
+    if (s->drv_opaque) {
+        audio_init_nb_voices_out (drv);
+        audio_init_nb_voices_in (drv);
+        s->drv = drv;
+        return 0;
+    }
+    else {
+        dolog ("Could not init `%s' audio driver\n", drv->name);
+        return -1;
+    }
+}
+
+static void audio_vm_change_state_handler (void *opaque, int running,
+                                           int reason)
+{
+    AudioState *s = opaque;
+    HWVoiceOut *hwo = NULL;
+    HWVoiceIn *hwi = NULL;
+    int op = running ? VOICE_ENABLE : VOICE_DISABLE;
+
+    s->vm_running = running;
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
+        hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out);
+    }
+
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
+        hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
+    }
+    audio_reset_timer (s);
+}
+
+static void audio_atexit (void)
+{
+    AudioState *s = &glob_audio_state;
+    HWVoiceOut *hwo = NULL;
+    HWVoiceIn *hwi = NULL;
+
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
+        SWVoiceCap *sc;
+
+        hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
+        hwo->pcm_ops->fini_out (hwo);
+
+        for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            CaptureVoiceOut *cap = sc->cap;
+            struct capture_callback *cb;
+
+            for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+                cb->ops.destroy (cb->opaque);
+            }
+        }
+    }
+
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
+        hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
+        hwi->pcm_ops->fini_in (hwi);
+    }
+
+    if (s->drv) {
+        s->drv->fini (s->drv_opaque);
+    }
+}
+
+static const VMStateDescription vmstate_audio = {
+    .name = "audio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void audio_init (void)
+{
+    size_t i;
+    int done = 0;
+    const char *drvname;
+    VMChangeStateEntry *e;
+    AudioState *s = &glob_audio_state;
+
+    if (s->drv) {
+        return;
+    }
+
+    QLIST_INIT (&s->hw_head_out);
+    QLIST_INIT (&s->hw_head_in);
+    QLIST_INIT (&s->cap_head);
+    atexit (audio_atexit);
+
+    s->ts = qemu_new_timer_ns (vm_clock, audio_timer, s);
+    if (!s->ts) {
+        hw_error("Could not create audio timer\n");
+    }
+
+    audio_process_options ("AUDIO", audio_options);
+
+    s->nb_hw_voices_out = conf.fixed_out.nb_voices;
+    s->nb_hw_voices_in = conf.fixed_in.nb_voices;
+
+    if (s->nb_hw_voices_out <= 0) {
+        dolog ("Bogus number of playback voices %d, setting to 1\n",
+               s->nb_hw_voices_out);
+        s->nb_hw_voices_out = 1;
+    }
+
+    if (s->nb_hw_voices_in <= 0) {
+        dolog ("Bogus number of capture voices %d, setting to 0\n",
+               s->nb_hw_voices_in);
+        s->nb_hw_voices_in = 0;
+    }
+
+    {
+        int def;
+        drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
+    }
+
+    if (drvname) {
+        int found = 0;
+
+        for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+            if (!strcmp (drvname, drvtab[i]->name)) {
+                done = !audio_driver_init (s, drvtab[i]);
+                found = 1;
+                break;
+            }
+        }
+
+        if (!found) {
+            dolog ("Unknown audio driver `%s'\n", drvname);
+            dolog ("Run with -audio-help to list available drivers\n");
+        }
+    }
+
+    if (!done) {
+        for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) {
+            if (drvtab[i]->can_be_default) {
+                done = !audio_driver_init (s, drvtab[i]);
+            }
+        }
+    }
+
+    if (!done) {
+        done = !audio_driver_init (s, &no_audio_driver);
+        if (!done) {
+            hw_error("Could not initialize audio subsystem\n");
+        }
+        else {
+            dolog ("warning: Using timer based audio emulation\n");
+        }
+    }
+
+    if (conf.period.hertz <= 0) {
+        if (conf.period.hertz < 0) {
+            dolog ("warning: Timer period is negative - %d "
+                   "treating as zero\n",
+                   conf.period.hertz);
+        }
+        conf.period.ticks = 1;
+    } else {
+        conf.period.ticks =
+            muldiv64 (1, get_ticks_per_sec (), conf.period.hertz);
+    }
+
+    e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
+    if (!e) {
+        dolog ("warning: Could not register change state handler\n"
+               "(Audio can continue looping even after stopping the VM)\n");
+    }
+
+    QLIST_INIT (&s->card_head);
+    vmstate_register (NULL, 0, &vmstate_audio, s);
+}
+
+void AUD_register_card (const char *name, QEMUSoundCard *card)
+{
+    audio_init ();
+    card->name = qemu_strdup (name);
+    memset (&card->entries, 0, sizeof (card->entries));
+    QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
+}
+
+void AUD_remove_card (QEMUSoundCard *card)
+{
+    QLIST_REMOVE (card, entries);
+    qemu_free (card->name);
+}
+
+
+CaptureVoiceOut *AUD_add_capture (
+    struct audsettings *as,
+    struct audio_capture_ops *ops,
+    void *cb_opaque
+    )
+{
+    AudioState *s = &glob_audio_state;
+    CaptureVoiceOut *cap;
+    struct capture_callback *cb;
+
+    if (audio_validate_settings (as)) {
+        dolog ("Invalid settings were passed when trying to add capture\n");
+        audio_print_settings (as);
+        goto err0;
+    }
+
+    cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
+    if (!cb) {
+        dolog ("Could not allocate capture callback information, size %zu\n",
+               sizeof (*cb));
+        goto err0;
+    }
+    cb->ops = *ops;
+    cb->opaque = cb_opaque;
+
+    cap = audio_pcm_capture_find_specific (as);
+    if (cap) {
+        QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+        return cap;
+    }
+    else {
+        HWVoiceOut *hw;
+        CaptureVoiceOut *cap;
+
+        cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
+        if (!cap) {
+            dolog ("Could not allocate capture voice, size %zu\n",
+                   sizeof (*cap));
+            goto err1;
+        }
+
+        hw = &cap->hw;
+        QLIST_INIT (&hw->sw_head);
+        QLIST_INIT (&cap->cb_head);
+
+        /* XXX find a more elegant way */
+        hw->samples = 4096 * 4;
+        hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
+                                    sizeof (struct st_sample));
+        if (!hw->mix_buf) {
+            dolog ("Could not allocate capture mix buffer (%d samples)\n",
+                   hw->samples);
+            goto err2;
+        }
+
+        audio_pcm_init_info (&hw->info, as);
+
+        cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+        if (!cap->buf) {
+            dolog ("Could not allocate capture buffer "
+                   "(%d samples, each %d bytes)\n",
+                   hw->samples, 1 << hw->info.shift);
+            goto err3;
+        }
+
+        hw->clip = mixeng_clip
+            [hw->info.nchannels == 2]
+            [hw->info.sign]
+            [hw->info.swap_endianness]
+            [audio_bits_to_index (hw->info.bits)];
+
+        QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
+        QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+
+        hw = NULL;
+        while ((hw = audio_pcm_hw_find_any_out (hw))) {
+            audio_attach_capture (hw);
+        }
+        return cap;
+
+    err3:
+        qemu_free (cap->hw.mix_buf);
+    err2:
+        qemu_free (cap);
+    err1:
+        qemu_free (cb);
+    err0:
+        return NULL;
+    }
+}
+
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
+{
+    struct capture_callback *cb;
+
+    for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+        if (cb->opaque == cb_opaque) {
+            cb->ops.destroy (cb_opaque);
+            QLIST_REMOVE (cb, entries);
+            qemu_free (cb);
+
+            if (!cap->cb_head.lh_first) {
+                SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
+
+                while (sw) {
+                    SWVoiceCap *sc = (SWVoiceCap *) sw;
+#ifdef DEBUG_CAPTURE
+                    dolog ("freeing %s\n", sw->name);
+#endif
+
+                    sw1 = sw->entries.le_next;
+                    if (sw->rate) {
+                        st_rate_stop (sw->rate);
+                        sw->rate = NULL;
+                    }
+                    QLIST_REMOVE (sw, entries);
+                    QLIST_REMOVE (sc, entries);
+                    qemu_free (sc);
+                    sw = sw1;
+                }
+                QLIST_REMOVE (cap, entries);
+                qemu_free (cap);
+            }
+            return;
+        }
+    }
+}
+
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+    if (sw) {
+        sw->vol.mute = mute;
+        sw->vol.l = nominal_volume.l * lvol / 255;
+        sw->vol.r = nominal_volume.r * rvol / 255;
+    }
+}
+
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+    if (sw) {
+        sw->vol.mute = mute;
+        sw->vol.l = nominal_volume.l * lvol / 255;
+        sw->vol.r = nominal_volume.r * rvol / 255;
+    }
+}
diff --git a/qemu-0.15.x/audio/audio.h b/qemu-0.15.x/audio/audio.h
new file mode 100644
index 0000000..a70fda9
--- /dev/null
+++ b/qemu-0.15.x/audio/audio.h
@@ -0,0 +1,166 @@
+/*
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 QEMU_AUDIO_H
+#define QEMU_AUDIO_H
+
+#include "config-host.h"
+#include "qemu-queue.h"
+
+typedef void (*audio_callback_fn) (void *opaque, int avail);
+
+typedef enum {
+    AUD_FMT_U8,
+    AUD_FMT_S8,
+    AUD_FMT_U16,
+    AUD_FMT_S16,
+    AUD_FMT_U32,
+    AUD_FMT_S32
+} audfmt_e;
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define AUDIO_HOST_ENDIANNESS 1
+#else
+#define AUDIO_HOST_ENDIANNESS 0
+#endif
+
+struct audsettings {
+    int freq;
+    int nchannels;
+    audfmt_e fmt;
+    int endianness;
+};
+
+typedef enum {
+    AUD_CNOTIFY_ENABLE,
+    AUD_CNOTIFY_DISABLE
+} audcnotification_e;
+
+struct audio_capture_ops {
+    void (*notify) (void *opaque, audcnotification_e cmd);
+    void (*capture) (void *opaque, void *buf, int size);
+    void (*destroy) (void *opaque);
+};
+
+struct capture_ops {
+    void (*info) (void *opaque);
+    void (*destroy) (void *opaque);
+};
+
+typedef struct CaptureState {
+    void *opaque;
+    struct capture_ops ops;
+    QLIST_ENTRY (CaptureState) entries;
+} CaptureState;
+
+typedef struct SWVoiceOut SWVoiceOut;
+typedef struct CaptureVoiceOut CaptureVoiceOut;
+typedef struct SWVoiceIn SWVoiceIn;
+
+typedef struct QEMUSoundCard {
+    char *name;
+    QLIST_ENTRY (QEMUSoundCard) entries;
+} QEMUSoundCard;
+
+typedef struct QEMUAudioTimeStamp {
+    uint64_t old_ts;
+} QEMUAudioTimeStamp;
+
+void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
+void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+void AUD_help (void);
+void AUD_register_card (const char *name, QEMUSoundCard *card);
+void AUD_remove_card (QEMUSoundCard *card);
+CaptureVoiceOut *AUD_add_capture (
+    struct audsettings *as,
+    struct audio_capture_ops *ops,
+    void *opaque
+    );
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
+
+SWVoiceOut *AUD_open_out (
+    QEMUSoundCard *card,
+    SWVoiceOut *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn callback_fn,
+    struct audsettings *settings
+    );
+
+void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
+int  AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
+int  AUD_get_buffer_size_out (SWVoiceOut *sw);
+void AUD_set_active_out (SWVoiceOut *sw, int on);
+int  AUD_is_active_out (SWVoiceOut *sw);
+
+void     AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
+uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
+
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol);
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol);
+
+SWVoiceIn *AUD_open_in (
+    QEMUSoundCard *card,
+    SWVoiceIn *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn callback_fn,
+    struct audsettings *settings
+    );
+
+void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
+int  AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
+void AUD_set_active_in (SWVoiceIn *sw, int on);
+int  AUD_is_active_in (SWVoiceIn *sw);
+
+void     AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
+uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
+
+static inline void *advance (void *p, int incr)
+{
+    uint8_t *d = p;
+    return (d + incr);
+}
+
+#ifdef __GNUC__
+#define audio_MIN(a, b) ( __extension__ ({      \
+    __typeof (a) ta = a;                        \
+    __typeof (b) tb = b;                        \
+    ((ta)>(tb)?(tb):(ta));                      \
+}))
+
+#define audio_MAX(a, b) ( __extension__ ({      \
+    __typeof (a) ta = a;                        \
+    __typeof (b) tb = b;                        \
+    ((ta)<(tb)?(tb):(ta));                      \
+}))
+#else
+#define audio_MIN(a, b) ((a)>(b)?(b):(a))
+#define audio_MAX(a, b) ((a)<(b)?(b):(a))
+#endif
+
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+                       int bits, int nchannels);
+
+#endif  /* audio.h */
diff --git a/qemu-0.15.x/audio/audio_int.h b/qemu-0.15.x/audio/audio_int.h
new file mode 100644
index 0000000..2003f8b
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_int.h
@@ -0,0 +1,282 @@
+/*
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 QEMU_AUDIO_INT_H
+#define QEMU_AUDIO_INT_H
+
+#ifdef CONFIG_COREAUDIO
+#define FLOAT_MIXENG
+/* #define RECIPROCAL */
+#endif
+#include "mixeng.h"
+
+struct audio_pcm_ops;
+
+typedef enum {
+    AUD_OPT_INT,
+    AUD_OPT_FMT,
+    AUD_OPT_STR,
+    AUD_OPT_BOOL
+} audio_option_tag_e;
+
+struct audio_option {
+    const char *name;
+    audio_option_tag_e tag;
+    void *valp;
+    const char *descr;
+    int *overriddenp;
+    int overridden;
+};
+
+struct audio_callback {
+    void *opaque;
+    audio_callback_fn fn;
+};
+
+struct audio_pcm_info {
+    int bits;
+    int sign;
+    int freq;
+    int nchannels;
+    int align;
+    int shift;
+    int bytes_per_second;
+    int swap_endianness;
+};
+
+typedef struct SWVoiceCap SWVoiceCap;
+
+typedef struct HWVoiceOut {
+    int enabled;
+    int poll_mode;
+    int pending_disable;
+    struct audio_pcm_info info;
+
+    f_sample *clip;
+
+    int rpos;
+    uint64_t ts_helper;
+
+    struct st_sample *mix_buf;
+
+    int samples;
+    QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
+    QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
+    struct audio_pcm_ops *pcm_ops;
+    QLIST_ENTRY (HWVoiceOut) entries;
+} HWVoiceOut;
+
+typedef struct HWVoiceIn {
+    int enabled;
+    int poll_mode;
+    struct audio_pcm_info info;
+
+    t_sample *conv;
+
+    int wpos;
+    int total_samples_captured;
+    uint64_t ts_helper;
+
+    struct st_sample *conv_buf;
+
+    int samples;
+    QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
+    struct audio_pcm_ops *pcm_ops;
+    QLIST_ENTRY (HWVoiceIn) entries;
+} HWVoiceIn;
+
+struct SWVoiceOut {
+    QEMUSoundCard *card;
+    struct audio_pcm_info info;
+    t_sample *conv;
+    int64_t ratio;
+    struct st_sample *buf;
+    void *rate;
+    int total_hw_samples_mixed;
+    int active;
+    int empty;
+    HWVoiceOut *hw;
+    char *name;
+    struct mixeng_volume vol;
+    struct audio_callback callback;
+    QLIST_ENTRY (SWVoiceOut) entries;
+};
+
+struct SWVoiceIn {
+    QEMUSoundCard *card;
+    int active;
+    struct audio_pcm_info info;
+    int64_t ratio;
+    void *rate;
+    int total_hw_samples_acquired;
+    struct st_sample *buf;
+    f_sample *clip;
+    HWVoiceIn *hw;
+    char *name;
+    struct mixeng_volume vol;
+    struct audio_callback callback;
+    QLIST_ENTRY (SWVoiceIn) entries;
+};
+
+struct audio_driver {
+    const char *name;
+    const char *descr;
+    struct audio_option *options;
+    void *(*init) (void);
+    void (*fini) (void *);
+    struct audio_pcm_ops *pcm_ops;
+    int can_be_default;
+    int max_voices_out;
+    int max_voices_in;
+    int voice_size_out;
+    int voice_size_in;
+};
+
+struct audio_pcm_ops {
+    int  (*init_out)(HWVoiceOut *hw, struct audsettings *as);
+    void (*fini_out)(HWVoiceOut *hw);
+    int  (*run_out) (HWVoiceOut *hw, int live);
+    int  (*write)   (SWVoiceOut *sw, void *buf, int size);
+    int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+
+    int  (*init_in) (HWVoiceIn *hw, struct audsettings *as);
+    void (*fini_in) (HWVoiceIn *hw);
+    int  (*run_in)  (HWVoiceIn *hw);
+    int  (*read)    (SWVoiceIn *sw, void *buf, int size);
+    int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
+};
+
+struct capture_callback {
+    struct audio_capture_ops ops;
+    void *opaque;
+    QLIST_ENTRY (capture_callback) entries;
+};
+
+struct CaptureVoiceOut {
+    HWVoiceOut hw;
+    void *buf;
+    QLIST_HEAD (cb_listhead, capture_callback) cb_head;
+    QLIST_ENTRY (CaptureVoiceOut) entries;
+};
+
+struct SWVoiceCap {
+    SWVoiceOut sw;
+    CaptureVoiceOut *cap;
+    QLIST_ENTRY (SWVoiceCap) entries;
+};
+
+struct AudioState {
+    struct audio_driver *drv;
+    void *drv_opaque;
+
+    QEMUTimer *ts;
+    QLIST_HEAD (card_listhead, QEMUSoundCard) card_head;
+    QLIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
+    QLIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
+    QLIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
+    int nb_hw_voices_out;
+    int nb_hw_voices_in;
+    int vm_running;
+};
+
+extern struct audio_driver no_audio_driver;
+extern struct audio_driver oss_audio_driver;
+extern struct audio_driver sdl_audio_driver;
+extern struct audio_driver wav_audio_driver;
+extern struct audio_driver fmod_audio_driver;
+extern struct audio_driver alsa_audio_driver;
+extern struct audio_driver coreaudio_audio_driver;
+extern struct audio_driver dsound_audio_driver;
+extern struct audio_driver esd_audio_driver;
+extern struct audio_driver pa_audio_driver;
+extern struct audio_driver spice_audio_driver;
+extern struct audio_driver winwave_audio_driver;
+extern const struct mixeng_volume nominal_volume;
+
+void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
+void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
+
+int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
+int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
+
+int  audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
+
+int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
+                           int live, int pending);
+
+int audio_bug (const char *funcname, int cond);
+void *audio_calloc (const char *funcname, int nmemb, size_t size);
+
+void audio_run (const char *msg);
+
+#define VOICE_ENABLE 1
+#define VOICE_DISABLE 2
+
+static inline int audio_ring_dist (int dst, int src, int len)
+{
+    return (dst >= src) ? (dst - src) : (len - src + dst);
+}
+
+static void GCC_ATTR dolog (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+}
+
+#ifdef DEBUG
+static void GCC_ATTR ldebug (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+}
+#else
+#if defined NDEBUG && defined __GNUC__
+#define ldebug(...)
+#elif defined NDEBUG && defined _MSC_VER
+#define ldebug __noop
+#else
+static void GCC_ATTR ldebug (const char *fmt, ...)
+{
+    (void) fmt;
+}
+#endif
+#endif
+
+#undef GCC_ATTR
+
+#define AUDIO_STRINGIFY_(n) #n
+#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
+
+#if defined _MSC_VER || defined __GNUC__
+#define AUDIO_FUNC __FUNCTION__
+#else
+#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__)
+#endif
+
+#endif /* audio_int.h */
diff --git a/qemu-0.15.x/audio/audio_pt_int.c b/qemu-0.15.x/audio/audio_pt_int.c
new file mode 100644
index 0000000..9a9c306
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_pt_int.c
@@ -0,0 +1,173 @@
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "audio-pt"
+
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
+                                       const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (pt->drv, fmt, ap);
+    va_end (ap);
+
+    AUD_log (NULL, "\n");
+    AUD_log (pt->drv, "Reason: %s\n", strerror (err));
+}
+
+int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
+                   void *opaque, const char *drv, const char *cap)
+{
+    int err, err2;
+    const char *efunc;
+    sigset_t set, old_set;
+
+    p->drv = drv;
+
+    err = sigfillset (&set);
+    if (err) {
+        logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+
+    err = pthread_mutex_init (&p->mutex, NULL);
+    if (err) {
+        efunc = "pthread_mutex_init";
+        goto err0;
+    }
+
+    err = pthread_cond_init (&p->cond, NULL);
+    if (err) {
+        efunc = "pthread_cond_init";
+        goto err1;
+    }
+
+    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
+    if (err) {
+        efunc = "pthread_sigmask";
+        goto err2;
+    }
+
+    err = pthread_create (&p->thread, NULL, func, opaque);
+
+    err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+    if (err2) {
+        logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed",
+                cap, AUDIO_FUNC);
+        /* We have failed to restore original signal mask, all bets are off,
+           so terminate the process */
+        exit (EXIT_FAILURE);
+    }
+
+    if (err) {
+        efunc = "pthread_create";
+        goto err2;
+    }
+
+    return 0;
+
+ err2:
+    err2 = pthread_cond_destroy (&p->cond);
+    if (err2) {
+        logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+    }
+
+ err1:
+    err2 = pthread_mutex_destroy (&p->mutex);
+    if (err2) {
+        logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+    }
+
+ err0:
+    logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
+    return -1;
+}
+
+int audio_pt_fini (struct audio_pt *p, const char *cap)
+{
+    int err, ret = 0;
+
+    err = pthread_cond_destroy (&p->cond);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+        ret = -1;
+    }
+
+    err = pthread_mutex_destroy (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+        ret = -1;
+    }
+    return ret;
+}
+
+int audio_pt_lock (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_lock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_unlock (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_wait (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_cond_wait (&p->cond, &p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    err = pthread_cond_signal (&p->cond);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
+{
+    int err;
+    void *ret;
+
+    err = pthread_join (p->thread, &ret);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    *arg = ret;
+    return 0;
+}
diff --git a/qemu-0.15.x/audio/audio_pt_int.h b/qemu-0.15.x/audio/audio_pt_int.h
new file mode 100644
index 0000000..0dfff76
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_pt_int.h
@@ -0,0 +1,22 @@
+#ifndef QEMU_AUDIO_PT_INT_H
+#define QEMU_AUDIO_PT_INT_H
+
+#include <pthread.h>
+
+struct audio_pt {
+    const char *drv;
+    pthread_t thread;
+    pthread_cond_t cond;
+    pthread_mutex_t mutex;
+};
+
+int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
+                   const char *, const char *);
+int audio_pt_fini (struct audio_pt *, const char *);
+int audio_pt_lock (struct audio_pt *, const char *);
+int audio_pt_unlock (struct audio_pt *, const char *);
+int audio_pt_wait (struct audio_pt *, const char *);
+int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
+int audio_pt_join (struct audio_pt *, void **, const char *);
+
+#endif /* audio_pt_int.h */
diff --git a/qemu-0.15.x/audio/audio_template.h b/qemu-0.15.x/audio/audio_template.h
new file mode 100644
index 0000000..fd4469e
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_template.h
@@ -0,0 +1,560 @@
+/*
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+#ifdef DAC
+#define NAME "playback"
+#define HWBUF hw->mix_buf
+#define TYPE out
+#define HW HWVoiceOut
+#define SW SWVoiceOut
+#else
+#define NAME "capture"
+#define TYPE in
+#define HW HWVoiceIn
+#define SW SWVoiceIn
+#define HWBUF hw->conv_buf
+#endif
+
+static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
+{
+    AudioState *s = &glob_audio_state;
+    int max_voices = glue (drv->max_voices_, TYPE);
+    int voice_size = glue (drv->voice_size_, TYPE);
+
+    if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
+        if (!max_voices) {
+#ifdef DAC
+            dolog ("Driver `%s' does not support " NAME "\n", drv->name);
+#endif
+        }
+        else {
+            dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
+                   drv->name,
+                   glue (s->nb_hw_voices_, TYPE),
+                   max_voices);
+        }
+        glue (s->nb_hw_voices_, TYPE) = max_voices;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
+        dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
+               drv->name, max_voices);
+        glue (s->nb_hw_voices_, TYPE) = 0;
+    }
+
+    if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
+        dolog ("drv=`%s' voice_size=%d max_voices=0\n",
+               drv->name, voice_size);
+    }
+}
+
+static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
+{
+    if (HWBUF) {
+        qemu_free (HWBUF);
+    }
+
+    HWBUF = NULL;
+}
+
+static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
+{
+    HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
+    if (!HWBUF) {
+        dolog ("Could not allocate " NAME " buffer (%d samples)\n",
+               hw->samples);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
+{
+    if (sw->buf) {
+        qemu_free (sw->buf);
+    }
+
+    if (sw->rate) {
+        st_rate_stop (sw->rate);
+    }
+
+    sw->buf = NULL;
+    sw->rate = NULL;
+}
+
+static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
+{
+    int samples;
+
+    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
+
+    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
+    if (!sw->buf) {
+        dolog ("Could not allocate buffer for `%s' (%d samples)\n",
+               SW_NAME (sw), samples);
+        return -1;
+    }
+
+#ifdef DAC
+    sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
+#else
+    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
+#endif
+    if (!sw->rate) {
+        qemu_free (sw->buf);
+        sw->buf = NULL;
+        return -1;
+    }
+    return 0;
+}
+
+static int glue (audio_pcm_sw_init_, TYPE) (
+    SW *sw,
+    HW *hw,
+    const char *name,
+    struct audsettings *as
+    )
+{
+    int err;
+
+    audio_pcm_init_info (&sw->info, as);
+    sw->hw = hw;
+    sw->active = 0;
+#ifdef DAC
+    sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
+    sw->total_hw_samples_mixed = 0;
+    sw->empty = 1;
+#else
+    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
+#endif
+
+#ifdef DAC
+    sw->conv = mixeng_conv
+#else
+    sw->clip = mixeng_clip
+#endif
+        [sw->info.nchannels == 2]
+        [sw->info.sign]
+        [sw->info.swap_endianness]
+        [audio_bits_to_index (sw->info.bits)];
+
+    sw->name = qemu_strdup (name);
+    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
+    if (err) {
+        qemu_free (sw->name);
+        sw->name = NULL;
+    }
+    return err;
+}
+
+static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
+{
+    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
+    if (sw->name) {
+        qemu_free (sw->name);
+        sw->name = NULL;
+    }
+}
+
+static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
+{
+    QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
+}
+
+static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
+{
+    QLIST_REMOVE (sw, entries);
+}
+
+static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
+{
+    AudioState *s = &glob_audio_state;
+    HW *hw = *hwp;
+
+    if (!hw->sw_head.lh_first) {
+#ifdef DAC
+        audio_detach_capture (hw);
+#endif
+        QLIST_REMOVE (hw, entries);
+        glue (s->nb_hw_voices_, TYPE) += 1;
+        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
+        glue (hw->pcm_ops->fini_, TYPE) (hw);
+        qemu_free (hw);
+        *hwp = NULL;
+    }
+}
+
+static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
+{
+    AudioState *s = &glob_audio_state;
+    return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
+}
+
+static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
+{
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+        if (hw->enabled) {
+            return hw;
+        }
+    }
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
+    HW *hw,
+    struct audsettings *as
+    )
+{
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+        if (audio_pcm_info_eq (&hw->info, as)) {
+            return hw;
+        }
+    }
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
+{
+    HW *hw;
+    AudioState *s = &glob_audio_state;
+    struct audio_driver *drv = s->drv;
+
+    if (!glue (s->nb_hw_voices_, TYPE)) {
+        return NULL;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !drv)) {
+        dolog ("No host audio driver\n");
+        return NULL;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
+        dolog ("Host audio driver without pcm_ops\n");
+        return NULL;
+    }
+
+    hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
+    if (!hw) {
+        dolog ("Can not allocate voice `%s' size %d\n",
+               drv->name, glue (drv->voice_size_, TYPE));
+        return NULL;
+    }
+
+    hw->pcm_ops = drv->pcm_ops;
+    QLIST_INIT (&hw->sw_head);
+#ifdef DAC
+    QLIST_INIT (&hw->cap_head);
+#endif
+    if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
+        goto err0;
+    }
+
+    if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
+        dolog ("hw->samples=%d\n", hw->samples);
+        goto err1;
+    }
+
+#ifdef DAC
+    hw->clip = mixeng_clip
+#else
+    hw->conv = mixeng_conv
+#endif
+        [hw->info.nchannels == 2]
+        [hw->info.sign]
+        [hw->info.swap_endianness]
+        [audio_bits_to_index (hw->info.bits)];
+
+    if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
+        goto err1;
+    }
+
+    QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
+    glue (s->nb_hw_voices_, TYPE) -= 1;
+#ifdef DAC
+    audio_attach_capture (hw);
+#endif
+    return hw;
+
+ err1:
+    glue (hw->pcm_ops->fini_, TYPE) (hw);
+ err0:
+    qemu_free (hw);
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
+{
+    HW *hw;
+
+    if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
+        hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
+        if (hw) {
+            return hw;
+        }
+    }
+
+    hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
+    if (hw) {
+        return hw;
+    }
+
+    hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
+    if (hw) {
+        return hw;
+    }
+
+    return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
+}
+
+static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
+    const char *sw_name,
+    struct audsettings *as
+    )
+{
+    SW *sw;
+    HW *hw;
+    struct audsettings hw_as;
+
+    if (glue (conf.fixed_, TYPE).enabled) {
+        hw_as = glue (conf.fixed_, TYPE).settings;
+    }
+    else {
+        hw_as = *as;
+    }
+
+    sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
+    if (!sw) {
+        dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
+               sw_name ? sw_name : "unknown", sizeof (*sw));
+        goto err1;
+    }
+
+    hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
+    if (!hw) {
+        goto err2;
+    }
+
+    glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
+
+    if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
+        goto err3;
+    }
+
+    return sw;
+
+err3:
+    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
+    glue (audio_pcm_hw_gc_, TYPE) (&hw);
+err2:
+    qemu_free (sw);
+err1:
+    return NULL;
+}
+
+static void glue (audio_close_, TYPE) (SW *sw)
+{
+    glue (audio_pcm_sw_fini_, TYPE) (sw);
+    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
+    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
+    qemu_free (sw);
+}
+
+void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
+{
+    if (sw) {
+        if (audio_bug (AUDIO_FUNC, !card)) {
+            dolog ("card=%p\n", card);
+            return;
+        }
+
+        glue (audio_close_, TYPE) (sw);
+    }
+}
+
+SW *glue (AUD_open_, TYPE) (
+    QEMUSoundCard *card,
+    SW *sw,
+    const char *name,
+    void *callback_opaque ,
+    audio_callback_fn callback_fn,
+    struct audsettings *as
+    )
+{
+    AudioState *s = &glob_audio_state;
+#ifdef DAC
+    int live = 0;
+    SW *old_sw = NULL;
+#endif
+
+    ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
+            name, as->freq, as->nchannels, as->fmt);
+
+    if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
+        dolog ("card=%p name=%p callback_fn=%p as=%p\n",
+               card, name, callback_fn, as);
+        goto fail;
+    }
+
+    if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
+        audio_print_settings (as);
+        goto fail;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !s->drv)) {
+        dolog ("Can not open `%s' (no host audio driver)\n", name);
+        goto fail;
+    }
+
+    if (sw && audio_pcm_info_eq (&sw->info, as)) {
+        return sw;
+    }
+
+#ifdef DAC
+    if (conf.plive && sw && (!sw->active && !sw->empty)) {
+        live = sw->total_hw_samples_mixed;
+
+#ifdef DEBUG_PLIVE
+        dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
+        dolog ("Old %s freq %d, bits %d, channels %d\n",
+               SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
+        dolog ("New %s freq %d, bits %d, channels %d\n",
+               name,
+               as->freq,
+               (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
+               as->nchannels);
+#endif
+
+        if (live) {
+            old_sw = sw;
+            old_sw->callback.fn = NULL;
+            sw = NULL;
+        }
+    }
+#endif
+
+    if (!glue (conf.fixed_, TYPE).enabled && sw) {
+        glue (AUD_close_, TYPE) (card, sw);
+        sw = NULL;
+    }
+
+    if (sw) {
+        HW *hw = sw->hw;
+
+        if (!hw) {
+            dolog ("Internal logic error voice `%s' has no hardware store\n",
+                   SW_NAME (sw));
+            goto fail;
+        }
+
+        glue (audio_pcm_sw_fini_, TYPE) (sw);
+        if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
+            goto fail;
+        }
+    }
+    else {
+        sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
+        if (!sw) {
+            dolog ("Failed to create voice `%s'\n", name);
+            return NULL;
+        }
+    }
+
+    sw->card = card;
+    sw->vol = nominal_volume;
+    sw->callback.fn = callback_fn;
+    sw->callback.opaque = callback_opaque;
+
+#ifdef DAC
+    if (live) {
+        int mixed =
+            (live << old_sw->info.shift)
+            * old_sw->info.bytes_per_second
+            / sw->info.bytes_per_second;
+
+#ifdef DEBUG_PLIVE
+        dolog ("Silence will be mixed %d\n", mixed);
+#endif
+        sw->total_hw_samples_mixed += mixed;
+    }
+#endif
+
+#ifdef DEBUG_AUDIO
+    dolog ("%s\n", name);
+    audio_pcm_print_info ("hw", &sw->hw->info);
+    audio_pcm_print_info ("sw", &sw->info);
+#endif
+
+    return sw;
+
+ fail:
+    glue (AUD_close_, TYPE) (card, sw);
+    return NULL;
+}
+
+int glue (AUD_is_active_, TYPE) (SW *sw)
+{
+    return sw ? sw->active : 0;
+}
+
+void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
+{
+    if (!sw) {
+        return;
+    }
+
+    ts->old_ts = sw->hw->ts_helper;
+}
+
+uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
+{
+    uint64_t delta, cur_ts, old_ts;
+
+    if (!sw) {
+        return 0;
+    }
+
+    cur_ts = sw->hw->ts_helper;
+    old_ts = ts->old_ts;
+    /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
+
+    if (cur_ts >= old_ts) {
+        delta = cur_ts - old_ts;
+    }
+    else {
+        delta = UINT64_MAX - old_ts + cur_ts;
+    }
+
+    if (!delta) {
+        return 0;
+    }
+
+    return muldiv64 (delta, sw->hw->info.freq, 1000000);
+}
+
+#undef TYPE
+#undef HW
+#undef SW
+#undef HWBUF
+#undef NAME
diff --git a/qemu-0.15.x/audio/audio_win_int.c b/qemu-0.15.x/audio/audio_win_int.c
new file mode 100644
index 0000000..5869052
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_win_int.c
@@ -0,0 +1,108 @@
+/* public domain */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "win-int"
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "audio.h"
+#include "audio_int.h"
+#include "audio_win_int.h"
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+                                    struct audsettings *as)
+{
+    memset (wfx, 0, sizeof (*wfx));
+
+    wfx->wFormatTag = WAVE_FORMAT_PCM;
+    wfx->nChannels = as->nchannels;
+    wfx->nSamplesPerSec = as->freq;
+    wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
+    wfx->nBlockAlign = 1 << (as->nchannels == 2);
+    wfx->cbSize = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        wfx->wBitsPerSample = 8;
+        break;
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        wfx->wBitsPerSample = 16;
+        wfx->nAvgBytesPerSec <<= 1;
+        wfx->nBlockAlign <<= 1;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        wfx->wBitsPerSample = 32;
+        wfx->nAvgBytesPerSec <<= 2;
+        wfx->nBlockAlign <<= 2;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", as->freq);
+        return -1;
+    }
+
+    return 0;
+}
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+                                  struct audsettings *as)
+{
+    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
+        dolog ("Invalid wave format, tag is not PCM, but %d\n",
+               wfx->wFormatTag);
+        return -1;
+    }
+
+    if (!wfx->nSamplesPerSec) {
+        dolog ("Invalid wave format, frequency is zero\n");
+        return -1;
+    }
+    as->freq = wfx->nSamplesPerSec;
+
+    switch (wfx->nChannels) {
+    case 1:
+        as->nchannels = 1;
+        break;
+
+    case 2:
+        as->nchannels = 2;
+        break;
+
+    default:
+        dolog (
+            "Invalid wave format, number of channels is not 1 or 2, but %d\n",
+            wfx->nChannels
+            );
+        return -1;
+    }
+
+    switch (wfx->wBitsPerSample) {
+    case 8:
+        as->fmt = AUD_FMT_U8;
+        break;
+
+    case 16:
+        as->fmt = AUD_FMT_S16;
+        break;
+
+    case 32:
+        as->fmt = AUD_FMT_S32;
+        break;
+
+    default:
+        dolog ("Invalid wave format, bits per sample is not "
+               "8, 16 or 32, but %d\n",
+               wfx->wBitsPerSample);
+        return -1;
+    }
+
+    return 0;
+}
+
diff --git a/qemu-0.15.x/audio/audio_win_int.h b/qemu-0.15.x/audio/audio_win_int.h
new file mode 100644
index 0000000..fa5b3cb
--- /dev/null
+++ b/qemu-0.15.x/audio/audio_win_int.h
@@ -0,0 +1,10 @@
+#ifndef AUDIO_WIN_INT_H
+#define AUDIO_WIN_INT_H
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+                                    struct audsettings *as);
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+                                  struct audsettings *as);
+
+#endif /* AUDIO_WIN_INT_H */
diff --git a/qemu-0.15.x/audio/coreaudio.c b/qemu-0.15.x/audio/coreaudio.c
new file mode 100644
index 0000000..5964c62
--- /dev/null
+++ b/qemu-0.15.x/audio/coreaudio.c
@@ -0,0 +1,549 @@
+/*
+ * QEMU OS X CoreAudio audio driver
+ *
+ * Copyright (c) 2005 Mike Kronenberg
+ *
+ * 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 <CoreAudio/CoreAudio.h>
+#include <string.h>             /* strerror */
+#include <pthread.h>            /* pthread_X */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "coreaudio"
+#include "audio_int.h"
+
+struct {
+    int buffer_frames;
+    int nbuffers;
+    int isAtexit;
+} conf = {
+    .buffer_frames = 512,
+    .nbuffers = 4,
+    .isAtexit = 0
+};
+
+typedef struct coreaudioVoiceOut {
+    HWVoiceOut hw;
+    pthread_mutex_t mutex;
+    int isAtexit;
+    AudioDeviceID outputDeviceID;
+    UInt32 audioDevicePropertyBufferFrameSize;
+    AudioStreamBasicDescription outputStreamBasicDescription;
+    int live;
+    int decr;
+    int rpos;
+} coreaudioVoiceOut;
+
+static void coreaudio_logstatus (OSStatus status)
+{
+    const char *str = "BUG";
+
+    switch(status) {
+    case kAudioHardwareNoError:
+        str = "kAudioHardwareNoError";
+        break;
+
+    case kAudioHardwareNotRunningError:
+        str = "kAudioHardwareNotRunningError";
+        break;
+
+    case kAudioHardwareUnspecifiedError:
+        str = "kAudioHardwareUnspecifiedError";
+        break;
+
+    case kAudioHardwareUnknownPropertyError:
+        str = "kAudioHardwareUnknownPropertyError";
+        break;
+
+    case kAudioHardwareBadPropertySizeError:
+        str = "kAudioHardwareBadPropertySizeError";
+        break;
+
+    case kAudioHardwareIllegalOperationError:
+        str = "kAudioHardwareIllegalOperationError";
+        break;
+
+    case kAudioHardwareBadDeviceError:
+        str = "kAudioHardwareBadDeviceError";
+        break;
+
+    case kAudioHardwareBadStreamError:
+        str = "kAudioHardwareBadStreamError";
+        break;
+
+    case kAudioHardwareUnsupportedOperationError:
+        str = "kAudioHardwareUnsupportedOperationError";
+        break;
+
+    case kAudioDeviceUnsupportedFormatError:
+        str = "kAudioDeviceUnsupportedFormatError";
+        break;
+
+    case kAudioDevicePermissionsError:
+        str = "kAudioDevicePermissionsError";
+        break;
+
+    default:
+        AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
+        return;
+    }
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
+    OSStatus status,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_log (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    coreaudio_logstatus (status);
+}
+
+static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
+    OSStatus status,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    coreaudio_logstatus (status);
+}
+
+static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+{
+    OSStatus status;
+    UInt32 result = 0;
+    UInt32 propertySize = sizeof(outputDeviceID);
+    status = AudioDeviceGetProperty(
+        outputDeviceID, 0, 0,
+        kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr(status,
+                         "Could not determine whether Device is playing\n");
+    }
+    return result;
+}
+
+static void coreaudio_atexit (void)
+{
+    conf.isAtexit = 1;
+}
+
+static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
+{
+    int err;
+
+    err = pthread_mutex_lock (&core->mutex);
+    if (err) {
+        dolog ("Could not lock voice for %s\nReason: %s\n",
+               fn_name, strerror (err));
+        return -1;
+    }
+    return 0;
+}
+
+static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&core->mutex);
+    if (err) {
+        dolog ("Could not unlock voice for %s\nReason: %s\n",
+               fn_name, strerror (err));
+        return -1;
+    }
+    return 0;
+}
+
+static int coreaudio_run_out (HWVoiceOut *hw, int live)
+{
+    int decr;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    if (coreaudio_lock (core, "coreaudio_run_out")) {
+        return 0;
+    }
+
+    if (core->decr > live) {
+        ldebug ("core->decr %d live %d core->live %d\n",
+                core->decr,
+                live,
+                core->live);
+    }
+
+    decr = audio_MIN (core->decr, live);
+    core->decr -= decr;
+
+    core->live = live - decr;
+    hw->rpos = core->rpos;
+
+    coreaudio_unlock (core, "coreaudio_run_out");
+    return decr;
+}
+
+/* callback to feed audiooutput buffer */
+static OSStatus audioDeviceIOProc(
+    AudioDeviceID inDevice,
+    const AudioTimeStamp* inNow,
+    const AudioBufferList* inInputData,
+    const AudioTimeStamp* inInputTime,
+    AudioBufferList* outOutputData,
+    const AudioTimeStamp* inOutputTime,
+    void* hwptr)
+{
+    UInt32 frame, frameCount;
+    float *out = outOutputData->mBuffers[0].mData;
+    HWVoiceOut *hw = hwptr;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
+    int rpos, live;
+    struct st_sample *src;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+    const float scale = 1.f / UINT_MAX;
+#else
+    const float scale = UINT_MAX;
+#endif
+#endif
+
+    if (coreaudio_lock (core, "audioDeviceIOProc")) {
+        inInputTime = 0;
+        return 0;
+    }
+
+    frameCount = core->audioDevicePropertyBufferFrameSize;
+    live = core->live;
+
+    /* if there are not enough samples, set signal and return */
+    if (live < frameCount) {
+        inInputTime = 0;
+        coreaudio_unlock (core, "audioDeviceIOProc(empty)");
+        return 0;
+    }
+
+    rpos = core->rpos;
+    src = hw->mix_buf + rpos;
+
+    /* fill buffer */
+    for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+        *out++ = src[frame].l; /* left channel */
+        *out++ = src[frame].r; /* right channel */
+#else
+#ifdef RECIPROCAL
+        *out++ = src[frame].l * scale; /* left channel */
+        *out++ = src[frame].r * scale; /* right channel */
+#else
+        *out++ = src[frame].l / scale; /* left channel */
+        *out++ = src[frame].r / scale; /* right channel */
+#endif
+#endif
+    }
+
+    rpos = (rpos + frameCount) % hw->samples;
+    core->decr += frameCount;
+    core->rpos = rpos;
+
+    coreaudio_unlock (core, "audioDeviceIOProc");
+    return 0;
+}
+
+static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    OSStatus status;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+    UInt32 propertySize;
+    int err;
+    const char *typ = "playback";
+    AudioValueRange frameRange;
+
+    /* create mutex */
+    err = pthread_mutex_init(&core->mutex, NULL);
+    if (err) {
+        dolog("Could not create mutex\nReason: %s\n", strerror (err));
+        return -1;
+    }
+
+    audio_pcm_init_info (&hw->info, as);
+
+    /* open default output device */
+    propertySize = sizeof(core->outputDeviceID);
+    status = AudioHardwareGetProperty(
+        kAudioHardwarePropertyDefaultOutputDevice,
+        &propertySize,
+        &core->outputDeviceID);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get default output Device\n");
+        return -1;
+    }
+    if (core->outputDeviceID == kAudioDeviceUnknown) {
+        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
+        return -1;
+    }
+
+    /* get minimum and maximum buffer frame sizes */
+    propertySize = sizeof(frameRange);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        0,
+        kAudioDevicePropertyBufferFrameSizeRange,
+        &propertySize,
+        &frameRange);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame range\n");
+        return -1;
+    }
+
+    if (frameRange.mMinimum > conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
+        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
+    }
+    else if (frameRange.mMaximum < conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
+        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
+    }
+    else {
+        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
+    }
+
+    /* set Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+    status = AudioDeviceSetProperty(
+        core->outputDeviceID,
+        NULL,
+        0,
+        false,
+        kAudioDevicePropertyBufferFrameSize,
+        propertySize,
+        &core->audioDevicePropertyBufferFrameSize);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not set device buffer frame size %" PRIu32 "\n",
+                           (uint32_t)core->audioDevicePropertyBufferFrameSize);
+        return -1;
+    }
+
+    /* get Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        false,
+        kAudioDevicePropertyBufferFrameSize,
+        &propertySize,
+        &core->audioDevicePropertyBufferFrameSize);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame size\n");
+        return -1;
+    }
+    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
+
+    /* get StreamFormat */
+    propertySize = sizeof(core->outputStreamBasicDescription);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        false,
+        kAudioDevicePropertyStreamFormat,
+        &propertySize,
+        &core->outputStreamBasicDescription);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get Device Stream properties\n");
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* set Samplerate */
+    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
+    propertySize = sizeof(core->outputStreamBasicDescription);
+    status = AudioDeviceSetProperty(
+        core->outputDeviceID,
+        0,
+        0,
+        0,
+        kAudioDevicePropertyStreamFormat,
+        propertySize,
+        &core->outputStreamBasicDescription);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
+                           as->freq);
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* set Callback */
+    status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* start Playback */
+    if (!isPlaying(core->outputDeviceID)) {
+        status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
+        if (status != kAudioHardwareNoError) {
+            coreaudio_logerr2 (status, typ, "Could not start playback\n");
+            AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
+            core->outputDeviceID = kAudioDeviceUnknown;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static void coreaudio_fini_out (HWVoiceOut *hw)
+{
+    OSStatus status;
+    int err;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    if (!conf.isAtexit) {
+        /* stop playback */
+        if (isPlaying(core->outputDeviceID)) {
+            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+            if (status != kAudioHardwareNoError) {
+                coreaudio_logerr (status, "Could not stop playback\n");
+            }
+        }
+
+        /* remove callback */
+        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
+                                         audioDeviceIOProc);
+        if (status != kAudioHardwareNoError) {
+            coreaudio_logerr (status, "Could not remove IOProc\n");
+        }
+    }
+    core->outputDeviceID = kAudioDeviceUnknown;
+
+    /* destroy mutex */
+    err = pthread_mutex_destroy(&core->mutex);
+    if (err) {
+        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
+    }
+}
+
+static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    OSStatus status;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        /* start playback */
+        if (!isPlaying(core->outputDeviceID)) {
+            status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
+            if (status != kAudioHardwareNoError) {
+                coreaudio_logerr (status, "Could not resume playback\n");
+            }
+        }
+        break;
+
+    case VOICE_DISABLE:
+        /* stop playback */
+        if (!conf.isAtexit) {
+            if (isPlaying(core->outputDeviceID)) {
+                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+                if (status != kAudioHardwareNoError) {
+                    coreaudio_logerr (status, "Could not pause playback\n");
+                }
+            }
+        }
+        break;
+    }
+    return 0;
+}
+
+static void *coreaudio_audio_init (void)
+{
+    atexit(coreaudio_atexit);
+    return &coreaudio_audio_init;
+}
+
+static void coreaudio_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option coreaudio_options[] = {
+    {
+        .name  = "BUFFER_SIZE",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.buffer_frames,
+        .descr = "Size of the buffer in frames"
+    },
+    {
+        .name  = "BUFFER_COUNT",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nbuffers,
+        .descr = "Number of buffers"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops coreaudio_pcm_ops = {
+    .init_out = coreaudio_init_out,
+    .fini_out = coreaudio_fini_out,
+    .run_out  = coreaudio_run_out,
+    .write    = coreaudio_write,
+    .ctl_out  = coreaudio_ctl_out
+};
+
+struct audio_driver coreaudio_audio_driver = {
+    .name           = "coreaudio",
+    .descr          = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
+    .options        = coreaudio_options,
+    .init           = coreaudio_audio_init,
+    .fini           = coreaudio_audio_fini,
+    .pcm_ops        = &coreaudio_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = 1,
+    .max_voices_in  = 0,
+    .voice_size_out = sizeof (coreaudioVoiceOut),
+    .voice_size_in  = 0
+};
diff --git a/qemu-0.15.x/audio/dsound_template.h b/qemu-0.15.x/audio/dsound_template.h
new file mode 100644
index 0000000..8b37d16
--- /dev/null
+++ b/qemu-0.15.x/audio/dsound_template.h
@@ -0,0 +1,293 @@
+/*
+ * QEMU DirectSound audio driver header
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+#ifdef DSBTYPE_IN
+#define NAME "capture buffer"
+#define NAME2 "DirectSoundCapture"
+#define TYPE in
+#define IFACE IDirectSoundCaptureBuffer
+#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
+#define FIELD dsound_capture_buffer
+#define FIELD2 dsound_capture
+#else
+#define NAME "playback buffer"
+#define NAME2 "DirectSound"
+#define TYPE out
+#define IFACE IDirectSoundBuffer
+#define BUFPTR LPDIRECTSOUNDBUFFER
+#define FIELD dsound_buffer
+#define FIELD2 dsound
+#endif
+
+static int glue (dsound_unlock_, TYPE) (
+    BUFPTR buf,
+    LPVOID p1,
+    LPVOID p2,
+    DWORD blen1,
+    DWORD blen2
+    )
+{
+    HRESULT hr;
+
+    hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not unlock " NAME "\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int glue (dsound_lock_, TYPE) (
+    BUFPTR buf,
+    struct audio_pcm_info *info,
+    DWORD pos,
+    DWORD len,
+    LPVOID *p1p,
+    LPVOID *p2p,
+    DWORD *blen1p,
+    DWORD *blen2p,
+    int entire
+    )
+{
+    HRESULT hr;
+    int i;
+    LPVOID p1 = NULL, p2 = NULL;
+    DWORD blen1 = 0, blen2 = 0;
+    DWORD flag;
+
+#ifdef DSBTYPE_IN
+    flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
+#else
+    flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
+#endif
+    for (i = 0; i < conf.lock_retries; ++i) {
+        hr = glue (IFACE, _Lock) (
+            buf,
+            pos,
+            len,
+            &p1,
+            &blen1,
+            &p2,
+            &blen2,
+            flag
+            );
+
+        if (FAILED (hr)) {
+#ifndef DSBTYPE_IN
+            if (hr == DSERR_BUFFERLOST) {
+                if (glue (dsound_restore_, TYPE) (buf)) {
+                    dsound_logerr (hr, "Could not lock " NAME "\n");
+                    goto fail;
+                }
+                continue;
+            }
+#endif
+            dsound_logerr (hr, "Could not lock " NAME "\n");
+            goto fail;
+        }
+
+        break;
+    }
+
+    if (i == conf.lock_retries) {
+        dolog ("%d attempts to lock " NAME " failed\n", i);
+        goto fail;
+    }
+
+    if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
+        dolog ("DirectSound returned misaligned buffer %ld %ld\n",
+               blen1, blen2);
+        glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
+        goto fail;
+    }
+
+    if (!p1 && blen1) {
+        dolog ("warning: !p1 && blen1=%ld\n", blen1);
+        blen1 = 0;
+    }
+
+    if (!p2 && blen2) {
+        dolog ("warning: !p2 && blen2=%ld\n", blen2);
+        blen2 = 0;
+    }
+
+    *p1p = p1;
+    *p2p = p2;
+    *blen1p = blen1;
+    *blen2p = blen2;
+    return 0;
+
+ fail:
+    *p1p = NULL - 1;
+    *p2p = NULL - 1;
+    *blen1p = -1;
+    *blen2p = -1;
+    return -1;
+}
+
+#ifdef DSBTYPE_IN
+static void dsound_fini_in (HWVoiceIn *hw)
+#else
+static void dsound_fini_out (HWVoiceOut *hw)
+#endif
+{
+    HRESULT hr;
+#ifdef DSBTYPE_IN
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+#else
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+#endif
+
+    if (ds->FIELD) {
+        hr = glue (IFACE, _Stop) (ds->FIELD);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not stop " NAME "\n");
+        }
+
+        hr = glue (IFACE, _Release) (ds->FIELD);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release " NAME "\n");
+        }
+        ds->FIELD = NULL;
+    }
+}
+
+#ifdef DSBTYPE_IN
+static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
+#else
+static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
+#endif
+{
+    int err;
+    HRESULT hr;
+    dsound *s = &glob_dsound;
+    WAVEFORMATEX wfx;
+    struct audsettings obt_as;
+#ifdef DSBTYPE_IN
+    const char *typ = "ADC";
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    DSCBUFFERDESC bd;
+    DSCBCAPS bc;
+#else
+    const char *typ = "DAC";
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    DSBUFFERDESC bd;
+    DSBCAPS bc;
+#endif
+
+    if (!s->FIELD2) {
+        dolog ("Attempt to initialize voice without " NAME2 " object\n");
+        return -1;
+    }
+
+    err = waveformat_from_audio_settings (&wfx, as);
+    if (err) {
+        return -1;
+    }
+
+    memset (&bd, 0, sizeof (bd));
+    bd.dwSize = sizeof (bd);
+    bd.lpwfxFormat = &wfx;
+#ifdef DSBTYPE_IN
+    bd.dwBufferBytes = conf.bufsize_in;
+    hr = IDirectSoundCapture_CreateCaptureBuffer (
+        s->dsound_capture,
+        &bd,
+        &ds->dsound_capture_buffer,
+        NULL
+        );
+#else
+    bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+    bd.dwBufferBytes = conf.bufsize_out;
+    hr = IDirectSound_CreateSoundBuffer (
+        s->dsound,
+        &bd,
+        &ds->dsound_buffer,
+        NULL
+        );
+#endif
+
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
+        return -1;
+    }
+
+    hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
+        goto fail0;
+    }
+
+#ifdef DEBUG_DSOUND
+    dolog (NAME "\n");
+    print_wave_format (&wfx);
+#endif
+
+    memset (&bc, 0, sizeof (bc));
+    bc.dwSize = sizeof (bc);
+
+    hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
+        goto fail0;
+    }
+
+    err = waveformat_to_audio_settings (&wfx, &obt_as);
+    if (err) {
+        goto fail0;
+    }
+
+    ds->first_time = 1;
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
+
+    if (bc.dwBufferBytes & hw->info.align) {
+        dolog (
+            "GetCaps returned misaligned buffer size %ld, alignment %d\n",
+            bc.dwBufferBytes, hw->info.align + 1
+            );
+    }
+    hw->samples = bc.dwBufferBytes >> hw->info.shift;
+
+#ifdef DEBUG_DSOUND
+    dolog ("caps %ld, desc %ld\n",
+           bc.dwBufferBytes, bd.dwBufferBytes);
+
+    dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
+           hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
+#endif
+    return 0;
+
+ fail0:
+    glue (dsound_fini_, TYPE) (hw);
+    return -1;
+}
+
+#undef NAME
+#undef NAME2
+#undef TYPE
+#undef IFACE
+#undef BUFPTR
+#undef FIELD
+#undef FIELD2
diff --git a/qemu-0.15.x/audio/dsoundaudio.c b/qemu-0.15.x/audio/dsoundaudio.c
new file mode 100644
index 0000000..e2d89fd
--- /dev/null
+++ b/qemu-0.15.x/audio/dsoundaudio.c
@@ -0,0 +1,1030 @@
+/*
+ * QEMU DirectSound audio driver
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/*
+ * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
+ */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "dsound"
+#include "audio_int.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <objbase.h>
+#include <dsound.h>
+
+#include "audio_win_int.h"
+
+/* #define DEBUG_DSOUND */
+
+static struct {
+    int lock_retries;
+    int restore_retries;
+    int getstatus_retries;
+    int set_primary;
+    int bufsize_in;
+    int bufsize_out;
+    struct audsettings settings;
+    int latency_millis;
+} conf = {
+    .lock_retries       = 1,
+    .restore_retries    = 1,
+    .getstatus_retries  = 1,
+    .set_primary        = 0,
+    .bufsize_in         = 16384,
+    .bufsize_out        = 16384,
+    .settings.freq      = 44100,
+    .settings.nchannels = 2,
+    .settings.fmt       = AUD_FMT_S16,
+    .latency_millis     = 10
+};
+
+typedef struct {
+    LPDIRECTSOUND dsound;
+    LPDIRECTSOUNDCAPTURE dsound_capture;
+    LPDIRECTSOUNDBUFFER dsound_primary_buffer;
+    struct audsettings settings;
+} dsound;
+
+static dsound glob_dsound;
+
+typedef struct {
+    HWVoiceOut hw;
+    LPDIRECTSOUNDBUFFER dsound_buffer;
+    DWORD old_pos;
+    int first_time;
+#ifdef DEBUG_DSOUND
+    DWORD old_ppos;
+    DWORD played;
+    DWORD mixed;
+#endif
+} DSoundVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    int first_time;
+    LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
+} DSoundVoiceIn;
+
+static void dsound_log_hresult (HRESULT hr)
+{
+    const char *str = "BUG";
+
+    switch (hr) {
+    case DS_OK:
+        str = "The method succeeded";
+        break;
+#ifdef DS_NO_VIRTUALIZATION
+    case DS_NO_VIRTUALIZATION:
+        str = "The buffer was created, but another 3D algorithm was substituted";
+        break;
+#endif
+#ifdef DS_INCOMPLETE
+    case DS_INCOMPLETE:
+        str = "The method succeeded, but not all the optional effects were obtained";
+        break;
+#endif
+#ifdef DSERR_ACCESSDENIED
+    case DSERR_ACCESSDENIED:
+        str = "The request failed because access was denied";
+        break;
+#endif
+#ifdef DSERR_ALLOCATED
+    case DSERR_ALLOCATED:
+        str = "The request failed because resources, such as a priority level, were already in use by another caller";
+        break;
+#endif
+#ifdef DSERR_ALREADYINITIALIZED
+    case DSERR_ALREADYINITIALIZED:
+        str = "The object is already initialized";
+        break;
+#endif
+#ifdef DSERR_BADFORMAT
+    case DSERR_BADFORMAT:
+        str = "The specified wave format is not supported";
+        break;
+#endif
+#ifdef DSERR_BADSENDBUFFERGUID
+    case DSERR_BADSENDBUFFERGUID:
+        str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
+        break;
+#endif
+#ifdef DSERR_BUFFERLOST
+    case DSERR_BUFFERLOST:
+        str = "The buffer memory has been lost and must be restored";
+        break;
+#endif
+#ifdef DSERR_BUFFERTOOSMALL
+    case DSERR_BUFFERTOOSMALL:
+        str = "The buffer size is not great enough to enable effects processing";
+        break;
+#endif
+#ifdef DSERR_CONTROLUNAVAIL
+    case DSERR_CONTROLUNAVAIL:
+        str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
+        break;
+#endif
+#ifdef DSERR_DS8_REQUIRED
+    case DSERR_DS8_REQUIRED:
+        str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
+        break;
+#endif
+#ifdef DSERR_FXUNAVAILABLE
+    case DSERR_FXUNAVAILABLE:
+        str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
+        break;
+#endif
+#ifdef DSERR_GENERIC
+    case DSERR_GENERIC :
+        str = "An undetermined error occurred inside the DirectSound subsystem";
+        break;
+#endif
+#ifdef DSERR_INVALIDCALL
+    case DSERR_INVALIDCALL:
+        str = "This function is not valid for the current state of this object";
+        break;
+#endif
+#ifdef DSERR_INVALIDPARAM
+    case DSERR_INVALIDPARAM:
+        str = "An invalid parameter was passed to the returning function";
+        break;
+#endif
+#ifdef DSERR_NOAGGREGATION
+    case DSERR_NOAGGREGATION:
+        str = "The object does not support aggregation";
+        break;
+#endif
+#ifdef DSERR_NODRIVER
+    case DSERR_NODRIVER:
+        str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
+        break;
+#endif
+#ifdef DSERR_NOINTERFACE
+    case DSERR_NOINTERFACE:
+        str = "The requested COM interface is not available";
+        break;
+#endif
+#ifdef DSERR_OBJECTNOTFOUND
+    case DSERR_OBJECTNOTFOUND:
+        str = "The requested object was not found";
+        break;
+#endif
+#ifdef DSERR_OTHERAPPHASPRIO
+    case DSERR_OTHERAPPHASPRIO:
+        str = "Another application has a higher priority level, preventing this call from succeeding";
+        break;
+#endif
+#ifdef DSERR_OUTOFMEMORY
+    case DSERR_OUTOFMEMORY:
+        str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
+        break;
+#endif
+#ifdef DSERR_PRIOLEVELNEEDED
+    case DSERR_PRIOLEVELNEEDED:
+        str = "A cooperative level of DSSCL_PRIORITY or higher is required";
+        break;
+#endif
+#ifdef DSERR_SENDLOOP
+    case DSERR_SENDLOOP:
+        str = "A circular loop of send effects was detected";
+        break;
+#endif
+#ifdef DSERR_UNINITIALIZED
+    case DSERR_UNINITIALIZED:
+        str = "The Initialize method has not been called or has not been called successfully before other methods were called";
+        break;
+#endif
+#ifdef DSERR_UNSUPPORTED
+    case DSERR_UNSUPPORTED:
+        str = "The function called is not supported at this time";
+        break;
+#endif
+    default:
+        AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
+        return;
+    }
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) dsound_logerr (
+    HRESULT hr,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    dsound_log_hresult (hr);
+}
+
+static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
+    HRESULT hr,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    dsound_log_hresult (hr);
+}
+
+static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
+{
+    return (millis * info->bytes_per_second) / 1000;
+}
+
+#ifdef DEBUG_DSOUND
+static void print_wave_format (WAVEFORMATEX *wfx)
+{
+    dolog ("tag             = %d\n", wfx->wFormatTag);
+    dolog ("nChannels       = %d\n", wfx->nChannels);
+    dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
+    dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
+    dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
+    dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
+    dolog ("cbSize          = %d\n", wfx->cbSize);
+}
+#endif
+
+static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
+{
+    HRESULT hr;
+    int i;
+
+    for (i = 0; i < conf.restore_retries; ++i) {
+        hr = IDirectSoundBuffer_Restore (dsb);
+
+        switch (hr) {
+        case DS_OK:
+            return 0;
+
+        case DSERR_BUFFERLOST:
+            continue;
+
+        default:
+            dsound_logerr (hr, "Could not restore playback buffer\n");
+            return -1;
+        }
+    }
+
+    dolog ("%d attempts to restore playback buffer failed\n", i);
+    return -1;
+}
+
+#include "dsound_template.h"
+#define DSBTYPE_IN
+#include "dsound_template.h"
+#undef DSBTYPE_IN
+
+static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
+{
+    HRESULT hr;
+    int i;
+
+    for (i = 0; i < conf.getstatus_retries; ++i) {
+        hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not get playback buffer status\n");
+            return -1;
+        }
+
+        if (*statusp & DSERR_BUFFERLOST) {
+            if (dsound_restore_out (dsb)) {
+                return -1;
+            }
+            continue;
+        }
+        break;
+    }
+
+    return 0;
+}
+
+static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
+                                 DWORD *statusp)
+{
+    HRESULT hr;
+
+    hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get capture buffer status\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
+{
+    int src_len1 = dst_len;
+    int src_len2 = 0;
+    int pos = hw->rpos + dst_len;
+    struct st_sample *src1 = hw->mix_buf + hw->rpos;
+    struct st_sample *src2 = NULL;
+
+    if (pos > hw->samples) {
+        src_len1 = hw->samples - hw->rpos;
+        src2 = hw->mix_buf;
+        src_len2 = dst_len - src_len1;
+        pos = src_len2;
+    }
+
+    if (src_len1) {
+        hw->clip (dst, src1, src_len1);
+    }
+
+    if (src_len2) {
+        dst = advance (dst, src_len1 << hw->info.shift);
+        hw->clip (dst, src2, src_len2);
+    }
+
+    hw->rpos = pos % hw->samples;
+}
+
+static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
+{
+    int err;
+    LPVOID p1, p2;
+    DWORD blen1, blen2, len1, len2;
+
+    err = dsound_lock_out (
+        dsb,
+        &hw->info,
+        0,
+        hw->samples << hw->info.shift,
+        &p1, &p2,
+        &blen1, &blen2,
+        1
+        );
+    if (err) {
+        return;
+    }
+
+    len1 = blen1 >> hw->info.shift;
+    len2 = blen2 >> hw->info.shift;
+
+#ifdef DEBUG_DSOUND
+    dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
+           p1, blen1, len1,
+           p2, blen2, len2);
+#endif
+
+    if (p1 && len1) {
+        audio_pcm_info_clear_buf (&hw->info, p1, len1);
+    }
+
+    if (p2 && len2) {
+        audio_pcm_info_clear_buf (&hw->info, p2, len2);
+    }
+
+    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
+}
+
+static void dsound_close (dsound *s)
+{
+    HRESULT hr;
+
+    if (s->dsound_primary_buffer) {
+        hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release primary buffer\n");
+        }
+        s->dsound_primary_buffer = NULL;
+    }
+}
+
+static int dsound_open (dsound *s)
+{
+    int err;
+    HRESULT hr;
+    WAVEFORMATEX wfx;
+    DSBUFFERDESC dsbd;
+    HWND hwnd;
+
+    hwnd = GetForegroundWindow ();
+    hr = IDirectSound_SetCooperativeLevel (
+        s->dsound,
+        hwnd,
+        DSSCL_PRIORITY
+        );
+
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not set cooperative level for window %p\n",
+                       hwnd);
+        return -1;
+    }
+
+    if (!conf.set_primary) {
+        return 0;
+    }
+
+    err = waveformat_from_audio_settings (&wfx, &conf.settings);
+    if (err) {
+        return -1;
+    }
+
+    memset (&dsbd, 0, sizeof (dsbd));
+    dsbd.dwSize = sizeof (dsbd);
+    dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+    dsbd.dwBufferBytes = 0;
+    dsbd.lpwfxFormat = NULL;
+
+    hr = IDirectSound_CreateSoundBuffer (
+        s->dsound,
+        &dsbd,
+        &s->dsound_primary_buffer,
+        NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create primary playback buffer\n");
+        return -1;
+    }
+
+    hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not set primary playback buffer format\n");
+    }
+
+    hr = IDirectSoundBuffer_GetFormat (
+        s->dsound_primary_buffer,
+        &wfx,
+        sizeof (wfx),
+        NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get primary playback buffer format\n");
+        goto fail0;
+    }
+
+#ifdef DEBUG_DSOUND
+    dolog ("Primary\n");
+    print_wave_format (&wfx);
+#endif
+
+    err = waveformat_to_audio_settings (&wfx, &s->settings);
+    if (err) {
+        goto fail0;
+    }
+
+    return 0;
+
+ fail0:
+    dsound_close (s);
+    return -1;
+}
+
+static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    HRESULT hr;
+    DWORD status;
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+
+    if (!dsb) {
+        dolog ("Attempt to control voice without a buffer\n");
+        return 0;
+    }
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (dsound_get_status_out (dsb, &status)) {
+            return -1;
+        }
+
+        if (status & DSBSTATUS_PLAYING) {
+            dolog ("warning: Voice is already playing\n");
+            return 0;
+        }
+
+        dsound_clear_sample (hw, dsb);
+
+        hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not start playing buffer\n");
+            return -1;
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (dsound_get_status_out (dsb, &status)) {
+            return -1;
+        }
+
+        if (status & DSBSTATUS_PLAYING) {
+            hr = IDirectSoundBuffer_Stop (dsb);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not stop playing buffer\n");
+                return -1;
+            }
+        }
+        else {
+            dolog ("warning: Voice is not playing\n");
+        }
+        break;
+    }
+    return 0;
+}
+
+static int dsound_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int dsound_run_out (HWVoiceOut *hw, int live)
+{
+    int err;
+    HRESULT hr;
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+    int len, hwshift;
+    DWORD blen1, blen2;
+    DWORD len1, len2;
+    DWORD decr;
+    DWORD wpos, ppos, old_pos;
+    LPVOID p1, p2;
+    int bufsize;
+
+    if (!dsb) {
+        dolog ("Attempt to run empty with playback buffer\n");
+        return 0;
+    }
+
+    hwshift = hw->info.shift;
+    bufsize = hw->samples << hwshift;
+
+    hr = IDirectSoundBuffer_GetCurrentPosition (
+        dsb,
+        &ppos,
+        ds->first_time ? &wpos : NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get playback buffer position\n");
+        return 0;
+    }
+
+    len = live << hwshift;
+
+    if (ds->first_time) {
+        if (conf.latency_millis) {
+            DWORD cur_blat;
+
+            cur_blat = audio_ring_dist (wpos, ppos, bufsize);
+            ds->first_time = 0;
+            old_pos = wpos;
+            old_pos +=
+                millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
+            old_pos %= bufsize;
+            old_pos &= ~hw->info.align;
+        }
+        else {
+            old_pos = wpos;
+        }
+#ifdef DEBUG_DSOUND
+        ds->played = 0;
+        ds->mixed = 0;
+#endif
+    }
+    else {
+        if (ds->old_pos == ppos) {
+#ifdef DEBUG_DSOUND
+            dolog ("old_pos == ppos\n");
+#endif
+            return 0;
+        }
+
+#ifdef DEBUG_DSOUND
+        ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
+#endif
+        old_pos = ds->old_pos;
+    }
+
+    if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
+        len = ppos - old_pos;
+    }
+    else {
+        if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
+            len = bufsize - old_pos + ppos;
+        }
+    }
+
+    if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
+        dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
+               len, bufsize, old_pos, ppos);
+        return 0;
+    }
+
+    len &= ~hw->info.align;
+    if (!len) {
+        return 0;
+    }
+
+#ifdef DEBUG_DSOUND
+    ds->old_ppos = ppos;
+#endif
+    err = dsound_lock_out (
+        dsb,
+        &hw->info,
+        old_pos,
+        len,
+        &p1, &p2,
+        &blen1, &blen2,
+        0
+        );
+    if (err) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && len1) {
+        dsound_write_sample (hw, p1, len1);
+    }
+
+    if (p2 && len2) {
+        dsound_write_sample (hw, p2, len2);
+    }
+
+    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
+    ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
+
+#ifdef DEBUG_DSOUND
+    ds->mixed += decr << hwshift;
+
+    dolog ("played %lu mixed %lu diff %ld sec %f\n",
+           ds->played,
+           ds->mixed,
+           ds->mixed - ds->played,
+           abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
+#endif
+    return decr;
+}
+
+static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    HRESULT hr;
+    DWORD status;
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
+
+    if (!dscb) {
+        dolog ("Attempt to control capture voice without a buffer\n");
+        return -1;
+    }
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (dsound_get_status_in (dscb, &status)) {
+            return -1;
+        }
+
+        if (status & DSCBSTATUS_CAPTURING) {
+            dolog ("warning: Voice is already capturing\n");
+            return 0;
+        }
+
+        /* clear ?? */
+
+        hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not start capturing\n");
+            return -1;
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (dsound_get_status_in (dscb, &status)) {
+            return -1;
+        }
+
+        if (status & DSCBSTATUS_CAPTURING) {
+            hr = IDirectSoundCaptureBuffer_Stop (dscb);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not stop capturing\n");
+                return -1;
+            }
+        }
+        else {
+            dolog ("warning: Voice is not capturing\n");
+        }
+        break;
+    }
+    return 0;
+}
+
+static int dsound_read (SWVoiceIn *sw, void *buf, int len)
+{
+    return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int dsound_run_in (HWVoiceIn *hw)
+{
+    int err;
+    HRESULT hr;
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
+    int live, len, dead;
+    DWORD blen1, blen2;
+    DWORD len1, len2;
+    DWORD decr;
+    DWORD cpos, rpos;
+    LPVOID p1, p2;
+    int hwshift;
+
+    if (!dscb) {
+        dolog ("Attempt to run without capture buffer\n");
+        return 0;
+    }
+
+    hwshift = hw->info.shift;
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    if (!dead) {
+        return 0;
+    }
+
+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
+        dscb,
+        &cpos,
+        ds->first_time ? &rpos : NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get capture buffer position\n");
+        return 0;
+    }
+
+    if (ds->first_time) {
+        ds->first_time = 0;
+        if (rpos & hw->info.align) {
+            ldebug ("warning: Misaligned capture read position %ld(%d)\n",
+                    rpos, hw->info.align);
+        }
+        hw->wpos = rpos >> hwshift;
+    }
+
+    if (cpos & hw->info.align) {
+        ldebug ("warning: Misaligned capture position %ld(%d)\n",
+                cpos, hw->info.align);
+    }
+    cpos >>= hwshift;
+
+    len = audio_ring_dist (cpos, hw->wpos, hw->samples);
+    if (!len) {
+        return 0;
+    }
+    len = audio_MIN (len, dead);
+
+    err = dsound_lock_in (
+        dscb,
+        &hw->info,
+        hw->wpos << hwshift,
+        len << hwshift,
+        &p1,
+        &p2,
+        &blen1,
+        &blen2,
+        0
+        );
+    if (err) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && len1) {
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
+    }
+
+    if (p2 && len2) {
+        hw->conv (hw->conv_buf, p2, len2);
+    }
+
+    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
+    hw->wpos = (hw->wpos + decr) % hw->samples;
+    return decr;
+}
+
+static void dsound_audio_fini (void *opaque)
+{
+    HRESULT hr;
+    dsound *s = opaque;
+
+    if (!s->dsound) {
+        return;
+    }
+
+    hr = IDirectSound_Release (s->dsound);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not release DirectSound\n");
+    }
+    s->dsound = NULL;
+
+    if (!s->dsound_capture) {
+        return;
+    }
+
+    hr = IDirectSoundCapture_Release (s->dsound_capture);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not release DirectSoundCapture\n");
+    }
+    s->dsound_capture = NULL;
+}
+
+static void *dsound_audio_init (void)
+{
+    int err;
+    HRESULT hr;
+    dsound *s = &glob_dsound;
+
+    hr = CoInitialize (NULL);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not initialize COM\n");
+        return NULL;
+    }
+
+    hr = CoCreateInstance (
+        &CLSID_DirectSound,
+        NULL,
+        CLSCTX_ALL,
+        &IID_IDirectSound,
+        (void **) &s->dsound
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create DirectSound instance\n");
+        return NULL;
+    }
+
+    hr = IDirectSound_Initialize (s->dsound, NULL);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not initialize DirectSound\n");
+
+        hr = IDirectSound_Release (s->dsound);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release DirectSound\n");
+        }
+        s->dsound = NULL;
+        return NULL;
+    }
+
+    hr = CoCreateInstance (
+        &CLSID_DirectSoundCapture,
+        NULL,
+        CLSCTX_ALL,
+        &IID_IDirectSoundCapture,
+        (void **) &s->dsound_capture
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
+    }
+    else {
+        hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
+
+            hr = IDirectSoundCapture_Release (s->dsound_capture);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not release DirectSoundCapture\n");
+            }
+            s->dsound_capture = NULL;
+        }
+    }
+
+    err = dsound_open (s);
+    if (err) {
+        dsound_audio_fini (s);
+        return NULL;
+    }
+
+    return s;
+}
+
+static struct audio_option dsound_options[] = {
+    {
+        .name  = "LOCK_RETRIES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.lock_retries,
+        .descr = "Number of times to attempt locking the buffer"
+    },
+    {
+        .name  = "RESTOURE_RETRIES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.restore_retries,
+        .descr = "Number of times to attempt restoring the buffer"
+    },
+    {
+        .name  = "GETSTATUS_RETRIES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.getstatus_retries,
+        .descr = "Number of times to attempt getting status of the buffer"
+    },
+    {
+        .name  = "SET_PRIMARY",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.set_primary,
+        .descr = "Set the parameters of primary buffer"
+    },
+    {
+        .name  = "LATENCY_MILLIS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.latency_millis,
+        .descr = "(undocumented)"
+    },
+    {
+        .name  = "PRIMARY_FREQ",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.settings.freq,
+        .descr = "Primary buffer frequency"
+    },
+    {
+        .name  = "PRIMARY_CHANNELS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.settings.nchannels,
+        .descr = "Primary buffer number of channels (1 - mono, 2 - stereo)"
+    },
+    {
+        .name  = "PRIMARY_FMT",
+        .tag   = AUD_OPT_FMT,
+        .valp  = &conf.settings.fmt,
+        .descr = "Primary buffer format"
+    },
+    {
+        .name  = "BUFSIZE_OUT",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.bufsize_out,
+        .descr = "(undocumented)"
+    },
+    {
+        .name  = "BUFSIZE_IN",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.bufsize_in,
+        .descr = "(undocumented)"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops dsound_pcm_ops = {
+    .init_out = dsound_init_out,
+    .fini_out = dsound_fini_out,
+    .run_out  = dsound_run_out,
+    .write    = dsound_write,
+    .ctl_out  = dsound_ctl_out,
+
+    .init_in  = dsound_init_in,
+    .fini_in  = dsound_fini_in,
+    .run_in   = dsound_run_in,
+    .read     = dsound_read,
+    .ctl_in   = dsound_ctl_in
+};
+
+struct audio_driver dsound_audio_driver = {
+    .name           = "dsound",
+    .descr          = "DirectSound http://wikipedia.org/wiki/DirectSound",
+    .options        = dsound_options,
+    .init           = dsound_audio_init,
+    .fini           = dsound_audio_fini,
+    .pcm_ops        = &dsound_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = 1,
+    .voice_size_out = sizeof (DSoundVoiceOut),
+    .voice_size_in  = sizeof (DSoundVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/esdaudio.c b/qemu-0.15.x/audio/esdaudio.c
new file mode 100644
index 0000000..ff97b39
--- /dev/null
+++ b/qemu-0.15.x/audio/esdaudio.c
@@ -0,0 +1,557 @@
+/*
+ * QEMU ESD audio driver
+ *
+ * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
+ *
+ * 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 <esd.h>
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "esd"
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+typedef struct {
+    HWVoiceOut hw;
+    int done;
+    int live;
+    int decr;
+    int rpos;
+    void *pcm_buf;
+    int fd;
+    struct audio_pt pt;
+} ESDVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    int done;
+    int dead;
+    int incr;
+    int wpos;
+    void *pcm_buf;
+    int fd;
+    struct audio_pt pt;
+} ESDVoiceIn;
+
+static struct {
+    int samples;
+    int divisor;
+    char *dac_host;
+    char *adc_host;
+} conf = {
+    .samples = 1024,
+    .divisor = 2,
+};
+
+static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+/* playback */
+static void *qesd_thread_out (void *arg)
+{
+    ESDVoiceOut *esd = arg;
+    HWVoiceOut *hw = &esd->hw;
+    int threshold;
+
+    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return NULL;
+    }
+
+    for (;;) {
+        int decr, to_mix, rpos;
+
+        for (;;) {
+            if (esd->done) {
+                goto exit;
+            }
+
+            if (esd->live > threshold) {
+                break;
+            }
+
+            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        decr = to_mix = esd->live;
+        rpos = hw->rpos;
+
+        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_mix) {
+            ssize_t written;
+            int chunk = audio_MIN (to_mix, hw->samples - rpos);
+            struct st_sample *src = hw->mix_buf + rpos;
+
+            hw->clip (esd->pcm_buf, src, chunk);
+
+        again:
+            written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
+            if (written == -1) {
+                if (errno == EINTR || errno == EAGAIN) {
+                    goto again;
+                }
+                qesd_logerr (errno, "write failed\n");
+                return NULL;
+            }
+
+            if (written != chunk << hw->info.shift) {
+                int wsamples = written >> hw->info.shift;
+                int wbytes = wsamples << hw->info.shift;
+                if (wbytes != written) {
+                    dolog ("warning: Misaligned write %d (requested %zd), "
+                           "alignment %d\n",
+                           wbytes, written, hw->info.align + 1);
+                }
+                to_mix -= wsamples;
+                rpos = (rpos + wsamples) % hw->samples;
+                break;
+            }
+
+            rpos = (rpos + chunk) % hw->samples;
+            to_mix -= chunk;
+        }
+
+        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        esd->rpos = rpos;
+        esd->live -= decr;
+        esd->decr += decr;
+    }
+
+ exit:
+    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qesd_run_out (HWVoiceOut *hw, int live)
+{
+    int decr;
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    decr = audio_MIN (live, esd->decr);
+    esd->decr -= decr;
+    esd->live = live - decr;
+    hw->rpos = esd->rpos;
+    if (esd->live > 0) {
+        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    }
+    return decr;
+}
+
+static int qesd_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+    struct audsettings obt_as = *as;
+    int esdfmt = ESD_STREAM | ESD_PLAY;
+
+    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        esdfmt |= ESD_BITS8;
+        obt_as.fmt = AUD_FMT_U8;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("Will use 16 instead of 32 bit samples\n");
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+    deffmt:
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
+        goto deffmt;
+
+    }
+    obt_as.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+
+    hw->samples = conf.samples;
+    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!esd->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        return -1;
+    }
+
+    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
+    if (esd->fd < 0) {
+        qesd_logerr (errno, "esd_play_stream failed\n");
+        goto fail1;
+    }
+
+    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail2;
+    }
+
+    return 0;
+
+ fail2:
+    if (close (esd->fd)) {
+        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+                     AUDIO_FUNC, esd->fd);
+    }
+    esd->fd = -1;
+
+ fail1:
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+    return -1;
+}
+
+static void qesd_fini_out (HWVoiceOut *hw)
+{
+    void *ret;
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+    audio_pt_lock (&esd->pt, AUDIO_FUNC);
+    esd->done = 1;
+    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+    if (esd->fd >= 0) {
+        if (close (esd->fd)) {
+            qesd_logerr (errno, "failed to close esd socket\n");
+        }
+        esd->fd = -1;
+    }
+
+    audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+/* capture */
+static void *qesd_thread_in (void *arg)
+{
+    ESDVoiceIn *esd = arg;
+    HWVoiceIn *hw = &esd->hw;
+    int threshold;
+
+    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return NULL;
+    }
+
+    for (;;) {
+        int incr, to_grab, wpos;
+
+        for (;;) {
+            if (esd->done) {
+                goto exit;
+            }
+
+            if (esd->dead > threshold) {
+                break;
+            }
+
+            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        incr = to_grab = esd->dead;
+        wpos = hw->wpos;
+
+        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_grab) {
+            ssize_t nread;
+            int chunk = audio_MIN (to_grab, hw->samples - wpos);
+            void *buf = advance (esd->pcm_buf, wpos);
+
+        again:
+            nread = read (esd->fd, buf, chunk << hw->info.shift);
+            if (nread == -1) {
+                if (errno == EINTR || errno == EAGAIN) {
+                    goto again;
+                }
+                qesd_logerr (errno, "read failed\n");
+                return NULL;
+            }
+
+            if (nread != chunk << hw->info.shift) {
+                int rsamples = nread >> hw->info.shift;
+                int rbytes = rsamples << hw->info.shift;
+                if (rbytes != nread) {
+                    dolog ("warning: Misaligned write %d (requested %zd), "
+                           "alignment %d\n",
+                           rbytes, nread, hw->info.align + 1);
+                }
+                to_grab -= rsamples;
+                wpos = (wpos + rsamples) % hw->samples;
+                break;
+            }
+
+            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
+            wpos = (wpos + chunk) % hw->samples;
+            to_grab -= chunk;
+        }
+
+        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        esd->wpos = wpos;
+        esd->dead -= incr;
+        esd->incr += incr;
+    }
+
+ exit:
+    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qesd_run_in (HWVoiceIn *hw)
+{
+    int live, incr, dead;
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    incr = audio_MIN (dead, esd->incr);
+    esd->incr -= incr;
+    esd->dead = dead - incr;
+    hw->wpos = esd->wpos;
+    if (esd->dead > 0) {
+        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    }
+    return incr;
+}
+
+static int qesd_read (SWVoiceIn *sw, void *buf, int len)
+{
+    return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+    struct audsettings obt_as = *as;
+    int esdfmt = ESD_STREAM | ESD_RECORD;
+
+    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        esdfmt |= ESD_BITS8;
+        obt_as.fmt = AUD_FMT_U8;
+        break;
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("Will use 16 instead of 32 bit samples\n");
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+    }
+    obt_as.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+
+    hw->samples = conf.samples;
+    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!esd->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        return -1;
+    }
+
+    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
+    if (esd->fd < 0) {
+        qesd_logerr (errno, "esd_record_stream failed\n");
+        goto fail1;
+    }
+
+    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail2;
+    }
+
+    return 0;
+
+ fail2:
+    if (close (esd->fd)) {
+        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+                     AUDIO_FUNC, esd->fd);
+    }
+    esd->fd = -1;
+
+ fail1:
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+    return -1;
+}
+
+static void qesd_fini_in (HWVoiceIn *hw)
+{
+    void *ret;
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+    audio_pt_lock (&esd->pt, AUDIO_FUNC);
+    esd->done = 1;
+    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+    if (esd->fd >= 0) {
+        if (close (esd->fd)) {
+            qesd_logerr (errno, "failed to close esd socket\n");
+        }
+        esd->fd = -1;
+    }
+
+    audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+/* common */
+static void *qesd_audio_init (void)
+{
+    return &conf;
+}
+
+static void qesd_audio_fini (void *opaque)
+{
+    (void) opaque;
+    ldebug ("esd_fini");
+}
+
+struct audio_option qesd_options[] = {
+    {
+        .name  = "SAMPLES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.samples,
+        .descr = "buffer size in samples"
+    },
+    {
+        .name  = "DIVISOR",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.divisor,
+        .descr = "threshold divisor"
+    },
+    {
+        .name  = "DAC_HOST",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.dac_host,
+        .descr = "playback host"
+    },
+    {
+        .name  = "ADC_HOST",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.adc_host,
+        .descr = "capture host"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops qesd_pcm_ops = {
+    .init_out = qesd_init_out,
+    .fini_out = qesd_fini_out,
+    .run_out  = qesd_run_out,
+    .write    = qesd_write,
+    .ctl_out  = qesd_ctl_out,
+
+    .init_in  = qesd_init_in,
+    .fini_in  = qesd_fini_in,
+    .run_in   = qesd_run_in,
+    .read     = qesd_read,
+    .ctl_in   = qesd_ctl_in,
+};
+
+struct audio_driver esd_audio_driver = {
+    .name           = "esd",
+    .descr          = "http://en.wikipedia.org/wiki/Esound",
+    .options        = qesd_options,
+    .init           = qesd_audio_init,
+    .fini           = qesd_audio_fini,
+    .pcm_ops        = &qesd_pcm_ops,
+    .can_be_default = 0,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (ESDVoiceOut),
+    .voice_size_in  = sizeof (ESDVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/fmodaudio.c b/qemu-0.15.x/audio/fmodaudio.c
new file mode 100644
index 0000000..c34cf53
--- /dev/null
+++ b/qemu-0.15.x/audio/fmodaudio.c
@@ -0,0 +1,687 @@
+/*
+ * QEMU FMOD audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 <fmod.h>
+#include <fmod_errors.h>
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "fmod"
+#include "audio_int.h"
+
+typedef struct FMODVoiceOut {
+    HWVoiceOut hw;
+    unsigned int old_pos;
+    FSOUND_SAMPLE *fmod_sample;
+    int channel;
+} FMODVoiceOut;
+
+typedef struct FMODVoiceIn {
+    HWVoiceIn hw;
+    FSOUND_SAMPLE *fmod_sample;
+} FMODVoiceIn;
+
+static struct {
+    const char *drvname;
+    int nb_samples;
+    int freq;
+    int nb_channels;
+    int bufsize;
+    int broken_adc;
+} conf = {
+    .nb_samples  = 2048 * 2,
+    .freq        = 44100,
+    .nb_channels = 2,
+};
+
+static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n",
+             FMOD_ErrorString (FSOUND_GetError ()));
+}
+
+static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n",
+             FMOD_ErrorString (FSOUND_GetError ()));
+}
+
+static int fmod_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static void fmod_clear_sample (FMODVoiceOut *fmd)
+{
+    HWVoiceOut *hw = &fmd->hw;
+    int status;
+    void *p1 = 0, *p2 = 0;
+    unsigned int len1 = 0, len2 = 0;
+
+    status = FSOUND_Sample_Lock (
+        fmd->fmod_sample,
+        0,
+        hw->samples << hw->info.shift,
+        &p1,
+        &p2,
+        &len1,
+        &len2
+        );
+
+    if (!status) {
+        fmod_logerr ("Failed to lock sample\n");
+        return;
+    }
+
+    if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
+        dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
+               len1, len2, hw->info.align + 1);
+        goto fail;
+    }
+
+    if ((len1 + len2) - (hw->samples << hw->info.shift)) {
+        dolog ("Lock returned incomplete length %d, %d\n",
+               len1 + len2, hw->samples << hw->info.shift);
+        goto fail;
+    }
+
+    audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
+
+ fail:
+    status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
+    if (!status) {
+        fmod_logerr ("Failed to unlock sample\n");
+    }
+}
+
+static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
+{
+    int src_len1 = dst_len;
+    int src_len2 = 0;
+    int pos = hw->rpos + dst_len;
+    struct st_sample *src1 = hw->mix_buf + hw->rpos;
+    struct st_sample *src2 = NULL;
+
+    if (pos > hw->samples) {
+        src_len1 = hw->samples - hw->rpos;
+        src2 = hw->mix_buf;
+        src_len2 = dst_len - src_len1;
+        pos = src_len2;
+    }
+
+    if (src_len1) {
+        hw->clip (dst, src1, src_len1);
+    }
+
+    if (src_len2) {
+        dst = advance (dst, src_len1 << hw->info.shift);
+        hw->clip (dst, src2, src_len2);
+    }
+
+    hw->rpos = pos % hw->samples;
+}
+
+static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
+                               unsigned int blen1, unsigned int blen2)
+{
+    int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
+    if (!status) {
+        fmod_logerr ("Failed to unlock sample\n");
+        return -1;
+    }
+    return 0;
+}
+
+static int fmod_lock_sample (
+    FSOUND_SAMPLE *sample,
+    struct audio_pcm_info *info,
+    int pos,
+    int len,
+    void **p1,
+    void **p2,
+    unsigned int *blen1,
+    unsigned int *blen2
+    )
+{
+    int status;
+
+    status = FSOUND_Sample_Lock (
+        sample,
+        pos << info->shift,
+        len << info->shift,
+        p1,
+        p2,
+        blen1,
+        blen2
+        );
+
+    if (!status) {
+        fmod_logerr ("Failed to lock sample\n");
+        return -1;
+    }
+
+    if ((*blen1 & info->align) || (*blen2 & info->align)) {
+        dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
+               *blen1, *blen2, info->align + 1);
+
+        fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
+
+        *p1 = NULL - 1;
+        *p2 = NULL - 1;
+        *blen1 = ~0U;
+        *blen2 = ~0U;
+        return -1;
+    }
+
+    if (!*p1 && *blen1) {
+        dolog ("warning: !p1 && blen1=%d\n", *blen1);
+        *blen1 = 0;
+    }
+
+    if (!p2 && *blen2) {
+        dolog ("warning: !p2 && blen2=%d\n", *blen2);
+        *blen2 = 0;
+    }
+
+    return 0;
+}
+
+static int fmod_run_out (HWVoiceOut *hw, int live)
+{
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+    int decr;
+    void *p1 = 0, *p2 = 0;
+    unsigned int blen1 = 0, blen2 = 0;
+    unsigned int len1 = 0, len2 = 0;
+
+    if (!hw->pending_disable) {
+        return 0;
+    }
+
+    decr = live;
+
+    if (fmd->channel >= 0) {
+        int len = decr;
+        int old_pos = fmd->old_pos;
+        int ppos = FSOUND_GetCurrentPosition (fmd->channel);
+
+        if (ppos == old_pos || !ppos) {
+            return 0;
+        }
+
+        if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
+            len = ppos - old_pos;
+        }
+        else {
+            if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
+                len = hw->samples - old_pos + ppos;
+            }
+        }
+        decr = len;
+
+        if (audio_bug (AUDIO_FUNC, decr < 0)) {
+            dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
+                   decr, live, ppos, old_pos, len);
+            return 0;
+        }
+    }
+
+
+    if (!decr) {
+        return 0;
+    }
+
+    if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
+                          fmd->old_pos, decr,
+                          &p1, &p2,
+                          &blen1, &blen2)) {
+        return 0;
+    }
+
+    len1 = blen1 >> hw->info.shift;
+    len2 = blen2 >> hw->info.shift;
+    ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
+    decr = len1 + len2;
+
+    if (p1 && len1) {
+        fmod_write_sample (hw, p1, len1);
+    }
+
+    if (p2 && len2) {
+        fmod_write_sample (hw, p2, len2);
+    }
+
+    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
+
+    fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
+    return decr;
+}
+
+static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
+{
+    int mode = FSOUND_LOOP_NORMAL;
+
+    switch (fmt) {
+    case AUD_FMT_S8:
+        mode |= FSOUND_SIGNED | FSOUND_8BITS;
+        break;
+
+    case AUD_FMT_U8:
+        mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
+        break;
+
+    case AUD_FMT_S16:
+        mode |= FSOUND_SIGNED | FSOUND_16BITS;
+        break;
+
+    case AUD_FMT_U16:
+        mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_FMOD
+        abort ();
+#endif
+        mode |= FSOUND_8BITS;
+    }
+    mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
+    return mode;
+}
+
+static void fmod_fini_out (HWVoiceOut *hw)
+{
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+
+    if (fmd->fmod_sample) {
+        FSOUND_Sample_Free (fmd->fmod_sample);
+        fmd->fmod_sample = 0;
+
+        if (fmd->channel >= 0) {
+            FSOUND_StopSound (fmd->channel);
+        }
+    }
+}
+
+static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    int bits16, mode, channel;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+    struct audsettings obt_as = *as;
+
+    mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
+    fmd->fmod_sample = FSOUND_Sample_Alloc (
+        FSOUND_FREE,            /* index */
+        conf.nb_samples,        /* length */
+        mode,                   /* mode */
+        as->freq,               /* freq */
+        255,                    /* volume */
+        128,                    /* pan */
+        255                     /* priority */
+        );
+
+    if (!fmd->fmod_sample) {
+        fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
+        return -1;
+    }
+
+    channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
+    if (channel < 0) {
+        fmod_logerr2 ("DAC", "Failed to start playing sound\n");
+        FSOUND_Sample_Free (fmd->fmod_sample);
+        return -1;
+    }
+    fmd->channel = channel;
+
+    /* FMOD always operates on little endian frames? */
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
+    bits16 = (mode & FSOUND_16BITS) != 0;
+    hw->samples = conf.nb_samples;
+    return 0;
+}
+
+static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    int status;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        fmod_clear_sample (fmd);
+        status = FSOUND_SetPaused (fmd->channel, 0);
+        if (!status) {
+            fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
+        }
+        break;
+
+    case VOICE_DISABLE:
+        status = FSOUND_SetPaused (fmd->channel, 1);
+        if (!status) {
+            fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
+        }
+        break;
+    }
+    return 0;
+}
+
+static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    int bits16, mode;
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+    struct audsettings obt_as = *as;
+
+    if (conf.broken_adc) {
+        return -1;
+    }
+
+    mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
+    fmd->fmod_sample = FSOUND_Sample_Alloc (
+        FSOUND_FREE,            /* index */
+        conf.nb_samples,        /* length */
+        mode,                   /* mode */
+        as->freq,               /* freq */
+        255,                    /* volume */
+        128,                    /* pan */
+        255                     /* priority */
+        );
+
+    if (!fmd->fmod_sample) {
+        fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
+        return -1;
+    }
+
+    /* FMOD always operates on little endian frames? */
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
+    bits16 = (mode & FSOUND_16BITS) != 0;
+    hw->samples = conf.nb_samples;
+    return 0;
+}
+
+static void fmod_fini_in (HWVoiceIn *hw)
+{
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+
+    if (fmd->fmod_sample) {
+        FSOUND_Record_Stop ();
+        FSOUND_Sample_Free (fmd->fmod_sample);
+        fmd->fmod_sample = 0;
+    }
+}
+
+static int fmod_run_in (HWVoiceIn *hw)
+{
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int live, dead, new_pos, len;
+    unsigned int blen1 = 0, blen2 = 0;
+    unsigned int len1, len2;
+    unsigned int decr;
+    void *p1, *p2;
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    if (!dead) {
+        return 0;
+    }
+
+    new_pos = FSOUND_Record_GetPosition ();
+    if (new_pos < 0) {
+        fmod_logerr ("Could not get recording position\n");
+        return 0;
+    }
+
+    len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
+    if (!len) {
+        return 0;
+    }
+    len = audio_MIN (len, dead);
+
+    if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
+                          hw->wpos, len,
+                          &p1, &p2,
+                          &blen1, &blen2)) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && blen1) {
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
+    }
+    if (p2 && len2) {
+        hw->conv (hw->conv_buf, p2, len2);
+    }
+
+    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
+    hw->wpos = (hw->wpos + decr) % hw->samples;
+    return decr;
+}
+
+static struct {
+    const char *name;
+    int type;
+} drvtab[] = {
+    { .name = "none",   .type = FSOUND_OUTPUT_NOSOUND },
+#ifdef _WIN32
+    { .name = "winmm",  .type = FSOUND_OUTPUT_WINMM   },
+    { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND  },
+    { .name = "a3d",    .type = FSOUND_OUTPUT_A3D     },
+    { .name = "asio",   .type = FSOUND_OUTPUT_ASIO    },
+#endif
+#ifdef __linux__
+    { .name = "oss",    .type = FSOUND_OUTPUT_OSS     },
+    { .name = "alsa",   .type = FSOUND_OUTPUT_ALSA    },
+    { .name = "esd",    .type = FSOUND_OUTPUT_ESD     },
+#endif
+#ifdef __APPLE__
+    { .name = "mac",    .type = FSOUND_OUTPUT_MAC     },
+#endif
+#if 0
+    { .name = "xbox",   .type = FSOUND_OUTPUT_XBOX    },
+    { .name = "ps2",    .type = FSOUND_OUTPUT_PS2     },
+    { .name = "gcube",  .type = FSOUND_OUTPUT_GC      },
+#endif
+    { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
+};
+
+static void *fmod_audio_init (void)
+{
+    size_t i;
+    double ver;
+    int status;
+    int output_type = -1;
+    const char *drv = conf.drvname;
+
+    ver = FSOUND_GetVersion ();
+    if (ver < FMOD_VERSION) {
+        dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
+        return NULL;
+    }
+
+#ifdef __linux__
+    if (ver < 3.75) {
+        dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
+               "ADC will be disabled.\n");
+        conf.broken_adc = 1;
+    }
+#endif
+
+    if (drv) {
+        int found = 0;
+        for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+            if (!strcmp (drv, drvtab[i].name)) {
+                output_type = drvtab[i].type;
+                found = 1;
+                break;
+            }
+        }
+        if (!found) {
+            dolog ("Unknown FMOD driver `%s'\n", drv);
+            dolog ("Valid drivers:\n");
+            for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
+                dolog ("  %s\n", drvtab[i].name);
+            }
+        }
+    }
+
+    if (output_type != -1) {
+        status = FSOUND_SetOutput (output_type);
+        if (!status) {
+            fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
+            return NULL;
+        }
+    }
+
+    if (conf.bufsize) {
+        status = FSOUND_SetBufferSize (conf.bufsize);
+        if (!status) {
+            fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
+        }
+    }
+
+    status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
+    if (!status) {
+        fmod_logerr ("FSOUND_Init failed\n");
+        return NULL;
+    }
+
+    return &conf;
+}
+
+static int fmod_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    int status;
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
+        if (!status) {
+            fmod_logerr ("Failed to start recording\n");
+        }
+        break;
+
+    case VOICE_DISABLE:
+        status = FSOUND_Record_Stop ();
+        if (!status) {
+            fmod_logerr ("Failed to stop recording\n");
+        }
+        break;
+    }
+    return 0;
+}
+
+static void fmod_audio_fini (void *opaque)
+{
+    (void) opaque;
+    FSOUND_Close ();
+}
+
+static struct audio_option fmod_options[] = {
+    {
+        .name  = "DRV",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.drvname,
+        .descr = "FMOD driver"
+    },
+    {
+        .name  = "FREQ",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.freq,
+        .descr = "Default frequency"
+    },
+    {
+        .name  = "SAMPLES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nb_samples,
+        .descr = "Buffer size in samples"
+    },
+    {
+        .name  = "CHANNELS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nb_channels,
+        .descr = "Number of default channels (1 - mono, 2 - stereo)"
+    },
+    {
+        .name  = "BUFSIZE",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.bufsize,
+        .descr = "(undocumented)"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops fmod_pcm_ops = {
+    .init_out = fmod_init_out,
+    .fini_out = fmod_fini_out,
+    .run_out  = fmod_run_out,
+    .write    = fmod_write,
+    .ctl_out  = fmod_ctl_out,
+
+    .init_in  = fmod_init_in,
+    .fini_in  = fmod_fini_in,
+    .run_in   = fmod_run_in,
+    .read     = fmod_read,
+    .ctl_in   = fmod_ctl_in
+};
+
+struct audio_driver fmod_audio_driver = {
+    .name           = "fmod",
+    .descr          = "FMOD 3.xx http://www.fmod.org",
+    .options        = fmod_options,
+    .init           = fmod_audio_init,
+    .fini           = fmod_audio_fini,
+    .pcm_ops        = &fmod_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (FMODVoiceOut),
+    .voice_size_in  = sizeof (FMODVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/mixeng.c b/qemu-0.15.x/audio/mixeng.c
new file mode 100644
index 0000000..4a9e8eb
--- /dev/null
+++ b/qemu-0.15.x/audio/mixeng.c
@@ -0,0 +1,360 @@
+/*
+ * QEMU Mixing engine
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ * Copyright (c) 1998 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 "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "mixeng"
+#include "audio_int.h"
+
+/* 8 bit */
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+
+/* Signed 8 bit */
+#define IN_T int8_t
+#define IN_MIN SCHAR_MIN
+#define IN_MAX SCHAR_MAX
+#define SIGNED
+#define SHIFT 8
+#include "mixeng_template.h"
+#undef SIGNED
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Unsigned 8 bit */
+#define IN_T uint8_t
+#define IN_MIN 0
+#define IN_MAX UCHAR_MAX
+#define SHIFT 8
+#include "mixeng_template.h"
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+
+/* Signed 16 bit */
+#define IN_T int16_t
+#define IN_MIN SHRT_MIN
+#define IN_MAX SHRT_MAX
+#define SIGNED
+#define SHIFT 16
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap16 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef SIGNED
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Unsigned 16 bit */
+#define IN_T uint16_t
+#define IN_MIN 0
+#define IN_MAX USHRT_MAX
+#define SHIFT 16
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap16 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Signed 32 bit */
+#define IN_T int32_t
+#define IN_MIN INT32_MIN
+#define IN_MAX INT32_MAX
+#define SIGNED
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef SIGNED
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Unsigned 32 bit */
+#define IN_T uint32_t
+#define IN_MIN 0
+#define IN_MAX UINT32_MAX
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+t_sample *mixeng_conv[2][2][2][3] = {
+    {
+        {
+            {
+                conv_natural_uint8_t_to_mono,
+                conv_natural_uint16_t_to_mono,
+                conv_natural_uint32_t_to_mono
+            },
+            {
+                conv_natural_uint8_t_to_mono,
+                conv_swap_uint16_t_to_mono,
+                conv_swap_uint32_t_to_mono,
+            }
+        },
+        {
+            {
+                conv_natural_int8_t_to_mono,
+                conv_natural_int16_t_to_mono,
+                conv_natural_int32_t_to_mono
+            },
+            {
+                conv_natural_int8_t_to_mono,
+                conv_swap_int16_t_to_mono,
+                conv_swap_int32_t_to_mono
+            }
+        }
+    },
+    {
+        {
+            {
+                conv_natural_uint8_t_to_stereo,
+                conv_natural_uint16_t_to_stereo,
+                conv_natural_uint32_t_to_stereo
+            },
+            {
+                conv_natural_uint8_t_to_stereo,
+                conv_swap_uint16_t_to_stereo,
+                conv_swap_uint32_t_to_stereo
+            }
+        },
+        {
+            {
+                conv_natural_int8_t_to_stereo,
+                conv_natural_int16_t_to_stereo,
+                conv_natural_int32_t_to_stereo
+            },
+            {
+                conv_natural_int8_t_to_stereo,
+                conv_swap_int16_t_to_stereo,
+                conv_swap_int32_t_to_stereo,
+            }
+        }
+    }
+};
+
+f_sample *mixeng_clip[2][2][2][3] = {
+    {
+        {
+            {
+                clip_natural_uint8_t_from_mono,
+                clip_natural_uint16_t_from_mono,
+                clip_natural_uint32_t_from_mono
+            },
+            {
+                clip_natural_uint8_t_from_mono,
+                clip_swap_uint16_t_from_mono,
+                clip_swap_uint32_t_from_mono
+            }
+        },
+        {
+            {
+                clip_natural_int8_t_from_mono,
+                clip_natural_int16_t_from_mono,
+                clip_natural_int32_t_from_mono
+            },
+            {
+                clip_natural_int8_t_from_mono,
+                clip_swap_int16_t_from_mono,
+                clip_swap_int32_t_from_mono
+            }
+        }
+    },
+    {
+        {
+            {
+                clip_natural_uint8_t_from_stereo,
+                clip_natural_uint16_t_from_stereo,
+                clip_natural_uint32_t_from_stereo
+            },
+            {
+                clip_natural_uint8_t_from_stereo,
+                clip_swap_uint16_t_from_stereo,
+                clip_swap_uint32_t_from_stereo
+            }
+        },
+        {
+            {
+                clip_natural_int8_t_from_stereo,
+                clip_natural_int16_t_from_stereo,
+                clip_natural_int32_t_from_stereo
+            },
+            {
+                clip_natural_int8_t_from_stereo,
+                clip_swap_int16_t_from_stereo,
+                clip_swap_int32_t_from_stereo
+            }
+        }
+    }
+};
+
+/*
+ * August 21, 1998
+ * Copyright 1998 Fabrice Bellard.
+ *
+ * [Rewrote completly the code of Lance Norskog And Sundry
+ * Contributors with a more efficient algorithm.]
+ *
+ * This source code is freely redistributable and may be used for
+ * any purpose.  This copyright notice must be maintained.
+ * Lance Norskog And Sundry Contributors are not responsible for
+ * the consequences of using this software.
+ */
+
+/*
+ * Sound Tools rate change effect file.
+ */
+/*
+ * Linear Interpolation.
+ *
+ * The use of fractional increment allows us to use no buffer. It
+ * avoid the problems at the end of the buffer we had with the old
+ * method which stored a possibly big buffer of size
+ * lcm(in_rate,out_rate).
+ *
+ * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
+ * the input & output frequencies are equal, a delay of one sample is
+ * introduced.  Limited to processing 32-bit count worth of samples.
+ *
+ * 1 << FRAC_BITS evaluating to zero in several places.  Changed with
+ * an (unsigned long) cast to make it safe.  MarkMLl 2/1/99
+ */
+
+/* Private data */
+struct rate {
+    uint64_t opos;
+    uint64_t opos_inc;
+    uint32_t ipos;              /* position in the input stream (integer) */
+    struct st_sample ilast;          /* last sample in the input stream */
+};
+
+/*
+ * Prepare processing.
+ */
+void *st_rate_start (int inrate, int outrate)
+{
+    struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate));
+
+    if (!rate) {
+        dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
+        return NULL;
+    }
+
+    rate->opos = 0;
+
+    /* increment */
+    rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
+
+    rate->ipos = 0;
+    rate->ilast.l = 0;
+    rate->ilast.r = 0;
+    return rate;
+}
+
+#define NAME st_rate_flow_mix
+#define OP(a, b) a += b
+#include "rate_template.h"
+
+#define NAME st_rate_flow
+#define OP(a, b) a = b
+#include "rate_template.h"
+
+void st_rate_stop (void *opaque)
+{
+    qemu_free (opaque);
+}
+
+void mixeng_clear (struct st_sample *buf, int len)
+{
+    memset (buf, 0, len * sizeof (struct st_sample));
+}
+
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
+{
+#ifdef CONFIG_MIXEMU
+    if (vol->mute) {
+        mixeng_clear (buf, len);
+        return;
+    }
+
+    while (len--) {
+#ifdef FLOAT_MIXENG
+        buf->l = buf->l * vol->l;
+        buf->r = buf->r * vol->r;
+#else
+        buf->l = (buf->l * vol->l) >> 32;
+        buf->r = (buf->r * vol->r) >> 32;
+#endif
+        buf += 1;
+    }
+#else
+    (void) buf;
+    (void) len;
+    (void) vol;
+#endif
+}
diff --git a/qemu-0.15.x/audio/mixeng.h b/qemu-0.15.x/audio/mixeng.h
new file mode 100644
index 0000000..9de443b
--- /dev/null
+++ b/qemu-0.15.x/audio/mixeng.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU Mixing engine header
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 QEMU_MIXENG_H
+#define QEMU_MIXENG_H
+
+#ifdef FLOAT_MIXENG
+typedef float mixeng_real;
+struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
+struct st_sample { mixeng_real l; mixeng_real r; };
+#else
+struct mixeng_volume { int mute; int64_t r; int64_t l; };
+struct st_sample { int64_t l; int64_t r; };
+#endif
+
+typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
+typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
+
+extern t_sample *mixeng_conv[2][2][2][3];
+extern f_sample *mixeng_clip[2][2][2][3];
+
+void *st_rate_start (int inrate, int outrate);
+void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
+                   int *isamp, int *osamp);
+void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
+                       int *isamp, int *osamp);
+void st_rate_stop (void *opaque);
+void mixeng_clear (struct st_sample *buf, int len);
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
+
+#endif  /* mixeng.h */
diff --git a/qemu-0.15.x/audio/mixeng_template.h b/qemu-0.15.x/audio/mixeng_template.h
new file mode 100644
index 0000000..e644c23
--- /dev/null
+++ b/qemu-0.15.x/audio/mixeng_template.h
@@ -0,0 +1,152 @@
+/*
+ * QEMU Mixing engine
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/*
+ * Tusen tack till Mike Nordell
+ * dec++'ified by Dscho
+ */
+
+#ifndef SIGNED
+#define HALF (IN_MAX >> 1)
+#endif
+
+#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
+
+#ifdef FLOAT_MIXENG
+static mixeng_real inline glue (conv_, ET) (IN_T v)
+{
+    IN_T nv = ENDIAN_CONVERT (v);
+
+#ifdef RECIPROCAL
+#ifdef SIGNED
+    return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
+#else
+    return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
+#endif
+#else  /* !RECIPROCAL */
+#ifdef SIGNED
+    return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
+#else
+    return (nv - HALF) / (mixeng_real) IN_MAX;
+#endif
+#endif
+}
+
+static IN_T inline glue (clip_, ET) (mixeng_real v)
+{
+    if (v >= 0.5) {
+        return IN_MAX;
+    }
+    else if (v < -0.5) {
+        return IN_MIN;
+    }
+
+#ifdef SIGNED
+    return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
+#else
+    return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
+#endif
+}
+
+#else  /* !FLOAT_MIXENG */
+
+static inline int64_t glue (conv_, ET) (IN_T v)
+{
+    IN_T nv = ENDIAN_CONVERT (v);
+#ifdef SIGNED
+    return ((int64_t) nv) << (32 - SHIFT);
+#else
+    return ((int64_t) nv - HALF) << (32 - SHIFT);
+#endif
+}
+
+static inline IN_T glue (clip_, ET) (int64_t v)
+{
+    if (v >= 0x7f000000) {
+        return IN_MAX;
+    }
+    else if (v < -2147483648LL) {
+        return IN_MIN;
+    }
+
+#ifdef SIGNED
+    return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT)));
+#else
+    return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF));
+#endif
+}
+#endif
+
+static void glue (glue (conv_, ET), _to_stereo)
+    (struct st_sample *dst, const void *src, int samples)
+{
+    struct st_sample *out = dst;
+    IN_T *in = (IN_T *) src;
+
+    while (samples--) {
+        out->l = glue (conv_, ET) (*in++);
+        out->r = glue (conv_, ET) (*in++);
+        out += 1;
+    }
+}
+
+static void glue (glue (conv_, ET), _to_mono)
+    (struct st_sample *dst, const void *src, int samples)
+{
+    struct st_sample *out = dst;
+    IN_T *in = (IN_T *) src;
+
+    while (samples--) {
+        out->l = glue (conv_, ET) (in[0]);
+        out->r = out->l;
+        out += 1;
+        in += 1;
+    }
+}
+
+static void glue (glue (clip_, ET), _from_stereo)
+    (void *dst, const struct st_sample *src, int samples)
+{
+    const struct st_sample *in = src;
+    IN_T *out = (IN_T *) dst;
+    while (samples--) {
+        *out++ = glue (clip_, ET) (in->l);
+        *out++ = glue (clip_, ET) (in->r);
+        in += 1;
+    }
+}
+
+static void glue (glue (clip_, ET), _from_mono)
+    (void *dst, const struct st_sample *src, int samples)
+{
+    const struct st_sample *in = src;
+    IN_T *out = (IN_T *) dst;
+    while (samples--) {
+        *out++ = glue (clip_, ET) (in->l + in->r);
+        in += 1;
+    }
+}
+
+#undef ET
+#undef HALF
diff --git a/qemu-0.15.x/audio/noaudio.c b/qemu-0.15.x/audio/noaudio.c
new file mode 100644
index 0000000..54958f8
--- /dev/null
+++ b/qemu-0.15.x/audio/noaudio.c
@@ -0,0 +1,173 @@
+/*
+ * QEMU Timer based audio emulation
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 "qemu-common.h"
+#include "audio.h"
+#include "qemu-timer.h"
+
+#define AUDIO_CAP "noaudio"
+#include "audio_int.h"
+
+typedef struct NoVoiceOut {
+    HWVoiceOut hw;
+    int64_t old_ticks;
+} NoVoiceOut;
+
+typedef struct NoVoiceIn {
+    HWVoiceIn hw;
+    int64_t old_ticks;
+} NoVoiceIn;
+
+static int no_run_out (HWVoiceOut *hw, int live)
+{
+    NoVoiceOut *no = (NoVoiceOut *) hw;
+    int decr, samples;
+    int64_t now;
+    int64_t ticks;
+    int64_t bytes;
+
+    now = qemu_get_clock_ns (vm_clock);
+    ticks = now - no->old_ticks;
+    bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
+    bytes = audio_MIN (bytes, INT_MAX);
+    samples = bytes >> hw->info.shift;
+
+    no->old_ticks = now;
+    decr = audio_MIN (live, samples);
+    hw->rpos = (hw->rpos + decr) % hw->samples;
+    return decr;
+}
+
+static int no_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int no_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    audio_pcm_init_info (&hw->info, as);
+    hw->samples = 1024;
+    return 0;
+}
+
+static void no_fini_out (HWVoiceOut *hw)
+{
+    (void) hw;
+}
+
+static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+static int no_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    audio_pcm_init_info (&hw->info, as);
+    hw->samples = 1024;
+    return 0;
+}
+
+static void no_fini_in (HWVoiceIn *hw)
+{
+    (void) hw;
+}
+
+static int no_run_in (HWVoiceIn *hw)
+{
+    NoVoiceIn *no = (NoVoiceIn *) hw;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    int samples = 0;
+
+    if (dead) {
+        int64_t now = qemu_get_clock_ns (vm_clock);
+        int64_t ticks = now - no->old_ticks;
+        int64_t bytes =
+            muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
+
+        no->old_ticks = now;
+        bytes = audio_MIN (bytes, INT_MAX);
+        samples = bytes >> hw->info.shift;
+        samples = audio_MIN (samples, dead);
+    }
+    return samples;
+}
+
+static int no_read (SWVoiceIn *sw, void *buf, int size)
+{
+    /* use custom code here instead of audio_pcm_sw_read() to avoid
+     * useless resampling/mixing */
+    int samples = size >> sw->info.shift;
+    int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
+    int to_clear = audio_MIN (samples, total);
+    sw->total_hw_samples_acquired += total;
+    audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
+    return to_clear << sw->info.shift;
+}
+
+static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+static void *no_audio_init (void)
+{
+    return &no_audio_init;
+}
+
+static void no_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_pcm_ops no_pcm_ops = {
+    .init_out = no_init_out,
+    .fini_out = no_fini_out,
+    .run_out  = no_run_out,
+    .write    = no_write,
+    .ctl_out  = no_ctl_out,
+
+    .init_in  = no_init_in,
+    .fini_in  = no_fini_in,
+    .run_in   = no_run_in,
+    .read     = no_read,
+    .ctl_in   = no_ctl_in
+};
+
+struct audio_driver no_audio_driver = {
+    .name           = "none",
+    .descr          = "Timer based audio emulation",
+    .options        = NULL,
+    .init           = no_audio_init,
+    .fini           = no_audio_fini,
+    .pcm_ops        = &no_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (NoVoiceOut),
+    .voice_size_in  = sizeof (NoVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/ossaudio.c b/qemu-0.15.x/audio/ossaudio.c
new file mode 100644
index 0000000..b49e102
--- /dev/null
+++ b/qemu-0.15.x/audio/ossaudio.c
@@ -0,0 +1,944 @@
+/*
+ * QEMU OSS audio driver
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef __OpenBSD__
+#include <soundcard.h>
+#else
+#include <sys/soundcard.h>
+#endif
+#include "qemu-common.h"
+#include "host-utils.h"
+#include "qemu-char.h"
+#include "audio.h"
+
+#define AUDIO_CAP "oss"
+#include "audio_int.h"
+
+#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
+#define USE_DSP_POLICY
+#endif
+
+typedef struct OSSVoiceOut {
+    HWVoiceOut hw;
+    void *pcm_buf;
+    int fd;
+    int wpos;
+    int nfrags;
+    int fragsize;
+    int mmapped;
+    int pending;
+} OSSVoiceOut;
+
+typedef struct OSSVoiceIn {
+    HWVoiceIn hw;
+    void *pcm_buf;
+    int fd;
+    int nfrags;
+    int fragsize;
+} OSSVoiceIn;
+
+static struct {
+    int try_mmap;
+    int nfrags;
+    int fragsize;
+    const char *devpath_out;
+    const char *devpath_in;
+    int debug;
+    int exclusive;
+    int policy;
+} conf = {
+    .try_mmap = 0,
+    .nfrags = 4,
+    .fragsize = 4096,
+    .devpath_out = "/dev/dsp",
+    .devpath_in = "/dev/dsp",
+    .debug = 0,
+    .exclusive = 0,
+    .policy = 5
+};
+
+struct oss_params {
+    int freq;
+    audfmt_e fmt;
+    int nchannels;
+    int nfrags;
+    int fragsize;
+};
+
+static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
+    int err,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+static void oss_anal_close (int *fdp)
+{
+    int err;
+
+    qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
+    err = close (*fdp);
+    if (err) {
+        oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
+    }
+    *fdp = -1;
+}
+
+static void oss_helper_poll_out (void *opaque)
+{
+    (void) opaque;
+    audio_run ("oss_poll_out");
+}
+
+static void oss_helper_poll_in (void *opaque)
+{
+    (void) opaque;
+    audio_run ("oss_poll_in");
+}
+
+static int oss_poll_out (HWVoiceOut *hw)
+{
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+
+    return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
+}
+
+static int oss_poll_in (HWVoiceIn *hw)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+    return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
+}
+
+static int oss_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int aud_to_ossfmt (audfmt_e fmt, int endianness)
+{
+    switch (fmt) {
+    case AUD_FMT_S8:
+        return AFMT_S8;
+
+    case AUD_FMT_U8:
+        return AFMT_U8;
+
+    case AUD_FMT_S16:
+        if (endianness) {
+            return AFMT_S16_BE;
+        }
+        else {
+            return AFMT_S16_LE;
+        }
+
+    case AUD_FMT_U16:
+        if (endianness) {
+            return AFMT_U16_BE;
+        }
+        else {
+            return AFMT_U16_LE;
+        }
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return AFMT_U8;
+    }
+}
+
+static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
+{
+    switch (ossfmt) {
+    case AFMT_S8:
+        *endianness = 0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case AFMT_U8:
+        *endianness = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case AFMT_S16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AFMT_U16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case AFMT_S16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AFMT_U16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    default:
+        dolog ("Unrecognized audio format %d\n", ossfmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+#if defined DEBUG_MISMATCHES || defined DEBUG
+static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
+{
+    dolog ("parameter | requested value | obtained value\n");
+    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
+    dolog ("channels  |      %10d |     %10d\n",
+           req->nchannels, obt->nchannels);
+    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
+    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
+    dolog ("fragsize  |      %10d |     %10d\n",
+           req->fragsize, obt->fragsize);
+}
+#endif
+
+#ifdef USE_DSP_POLICY
+static int oss_get_version (int fd, int *version, const char *typ)
+{
+    if (ioctl (fd, OSS_GETVERSION, &version)) {
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+        /*
+         * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
+         * since 7.x, but currently only on the mixer device (or in
+         * the Linuxolator), and in the native version that part of
+         * the code is in fact never reached so the ioctl fails anyway.
+         * Until this is fixed, just check the errno and if its what
+         * FreeBSD's sound drivers return atm assume they are new enough.
+         */
+        if (errno == EINVAL) {
+            *version = 0x040000;
+            return 0;
+        }
+#endif
+        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
+        return -1;
+    }
+    return 0;
+}
+#endif
+
+static int oss_open (int in, struct oss_params *req,
+                     struct oss_params *obt, int *pfd)
+{
+    int fd;
+    int oflags = conf.exclusive ? O_EXCL : 0;
+    audio_buf_info abinfo;
+    int fmt, freq, nchannels;
+    int setfragment = 1;
+    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
+    const char *typ = in ? "ADC" : "DAC";
+
+    /* Kludge needed to have working mmap on Linux */
+    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
+
+    fd = open (dspname, oflags | O_NONBLOCK);
+    if (-1 == fd) {
+        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
+        return -1;
+    }
+
+    freq = req->freq;
+    nchannels = req->nchannels;
+    fmt = req->fmt;
+
+    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
+        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
+        goto err;
+    }
+
+    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
+        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
+                     req->nchannels);
+        goto err;
+    }
+
+    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
+        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
+        goto err;
+    }
+
+    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
+        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
+        goto err;
+    }
+
+#ifdef USE_DSP_POLICY
+    if (conf.policy >= 0) {
+        int version;
+
+        if (!oss_get_version (fd, &version, typ)) {
+            if (conf.debug) {
+                dolog ("OSS version = %#x\n", version);
+            }
+
+            if (version >= 0x040000) {
+                int policy = conf.policy;
+                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
+                    oss_logerr2 (errno, typ,
+                                 "Failed to set timing policy to %d\n",
+                                 conf.policy);
+                    goto err;
+                }
+                setfragment = 0;
+            }
+        }
+    }
+#endif
+
+    if (setfragment) {
+        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
+        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
+            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
+                         req->nfrags, req->fragsize);
+            goto err;
+        }
+    }
+
+    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
+        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
+        goto err;
+    }
+
+    if (!abinfo.fragstotal || !abinfo.fragsize) {
+        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
+                 abinfo.fragstotal, abinfo.fragsize, typ);
+        goto err;
+    }
+
+    obt->fmt = fmt;
+    obt->nchannels = nchannels;
+    obt->freq = freq;
+    obt->nfrags = abinfo.fragstotal;
+    obt->fragsize = abinfo.fragsize;
+    *pfd = fd;
+
+#ifdef DEBUG_MISMATCHES
+    if ((req->fmt != obt->fmt) ||
+        (req->nchannels != obt->nchannels) ||
+        (req->freq != obt->freq) ||
+        (req->fragsize != obt->fragsize) ||
+        (req->nfrags != obt->nfrags)) {
+        dolog ("Audio parameters mismatch\n");
+        oss_dump_info (req, obt);
+    }
+#endif
+
+#ifdef DEBUG
+    oss_dump_info (req, obt);
+#endif
+    return 0;
+
+ err:
+    oss_anal_close (&fd);
+    return -1;
+}
+
+static void oss_write_pending (OSSVoiceOut *oss)
+{
+    HWVoiceOut *hw = &oss->hw;
+
+    if (oss->mmapped) {
+        return;
+    }
+
+    while (oss->pending) {
+        int samples_written;
+        ssize_t bytes_written;
+        int samples_till_end = hw->samples - oss->wpos;
+        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
+        int bytes_to_write = samples_to_write << hw->info.shift;
+        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
+
+        bytes_written = write (oss->fd, pcm, bytes_to_write);
+        if (bytes_written < 0) {
+            if (errno != EAGAIN) {
+                oss_logerr (errno, "failed to write %d bytes\n",
+                            bytes_to_write);
+            }
+            break;
+        }
+
+        if (bytes_written & hw->info.align) {
+            dolog ("misaligned write asked for %d, but got %zd\n",
+                   bytes_to_write, bytes_written);
+            return;
+        }
+
+        samples_written = bytes_written >> hw->info.shift;
+        oss->pending -= samples_written;
+        oss->wpos = (oss->wpos + samples_written) % hw->samples;
+        if (bytes_written - bytes_to_write) {
+            break;
+        }
+    }
+}
+
+static int oss_run_out (HWVoiceOut *hw, int live)
+{
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+    int err, decr;
+    struct audio_buf_info abinfo;
+    struct count_info cntinfo;
+    int bufsize;
+
+    bufsize = hw->samples << hw->info.shift;
+
+    if (oss->mmapped) {
+        int bytes, pos;
+
+        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
+        if (err < 0) {
+            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
+            return 0;
+        }
+
+        pos = hw->rpos << hw->info.shift;
+        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
+        decr = audio_MIN (bytes >> hw->info.shift, live);
+    }
+    else {
+        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
+        if (err < 0) {
+            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
+            return 0;
+        }
+
+        if (abinfo.bytes > bufsize) {
+            if (conf.debug) {
+                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
+                       "please report your OS/audio hw to av1474 at comtv.ru\n",
+                       abinfo.bytes, bufsize);
+            }
+            abinfo.bytes = bufsize;
+        }
+
+        if (abinfo.bytes < 0) {
+            if (conf.debug) {
+                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
+                       abinfo.bytes, bufsize);
+            }
+            return 0;
+        }
+
+        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
+        if (!decr) {
+            return 0;
+        }
+    }
+
+    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
+    oss->pending += decr;
+    oss_write_pending (oss);
+
+    return decr;
+}
+
+static void oss_fini_out (HWVoiceOut *hw)
+{
+    int err;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+
+    ldebug ("oss_fini\n");
+    oss_anal_close (&oss->fd);
+
+    if (oss->pcm_buf) {
+        if (oss->mmapped) {
+            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
+            if (err) {
+                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
+                            oss->pcm_buf, hw->samples << hw->info.shift);
+            }
+        }
+        else {
+            qemu_free (oss->pcm_buf);
+        }
+        oss->pcm_buf = NULL;
+    }
+}
+
+static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+    struct oss_params req, obt;
+    int endianness;
+    int err;
+    int fd;
+    audfmt_e effective_fmt;
+    struct audsettings obt_as;
+
+    oss->fd = -1;
+
+    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.fragsize = conf.fragsize;
+    req.nfrags = conf.nfrags;
+
+    if (oss_open (0, &req, &obt, &fd)) {
+        return -1;
+    }
+
+    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        oss_anal_close (&fd);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    oss->nfrags = obt.nfrags;
+    oss->fragsize = obt.fragsize;
+
+    if (obt.nfrags * obt.fragsize & hw->info.align) {
+        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
+               obt.nfrags * obt.fragsize, hw->info.align + 1);
+    }
+
+    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
+
+    oss->mmapped = 0;
+    if (conf.try_mmap) {
+        oss->pcm_buf = mmap (
+            NULL,
+            hw->samples << hw->info.shift,
+            PROT_READ | PROT_WRITE,
+            MAP_SHARED,
+            fd,
+            0
+            );
+        if (oss->pcm_buf == MAP_FAILED) {
+            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
+                        hw->samples << hw->info.shift);
+        }
+        else {
+            int err;
+            int trig = 0;
+            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
+            }
+            else {
+                trig = PCM_ENABLE_OUTPUT;
+                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+                    oss_logerr (
+                        errno,
+                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
+                        );
+                }
+                else {
+                    oss->mmapped = 1;
+                }
+            }
+
+            if (!oss->mmapped) {
+                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
+                if (err) {
+                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
+                                oss->pcm_buf, hw->samples << hw->info.shift);
+                }
+            }
+        }
+    }
+
+    if (!oss->mmapped) {
+        oss->pcm_buf = audio_calloc (
+            AUDIO_FUNC,
+            hw->samples,
+            1 << hw->info.shift
+            );
+        if (!oss->pcm_buf) {
+            dolog (
+                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
+                hw->samples,
+                1 << hw->info.shift
+                );
+            oss_anal_close (&fd);
+            return -1;
+        }
+    }
+
+    oss->fd = fd;
+    return 0;
+}
+
+static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    int trig;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            ldebug ("enabling voice\n");
+            if (poll_mode && oss_poll_out (hw)) {
+                poll_mode = 0;
+            }
+            hw->poll_mode = poll_mode;
+
+            if (!oss->mmapped) {
+                return 0;
+            }
+
+            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
+            trig = PCM_ENABLE_OUTPUT;
+            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+                oss_logerr (
+                    errno,
+                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
+                    );
+                return -1;
+            }
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (hw->poll_mode) {
+            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
+            hw->poll_mode = 0;
+        }
+
+        if (!oss->mmapped) {
+            return 0;
+        }
+
+        ldebug ("disabling voice\n");
+        trig = 0;
+        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
+            return -1;
+        }
+        break;
+    }
+    return 0;
+}
+
+static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+    struct oss_params req, obt;
+    int endianness;
+    int err;
+    int fd;
+    audfmt_e effective_fmt;
+    struct audsettings obt_as;
+
+    oss->fd = -1;
+
+    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.fragsize = conf.fragsize;
+    req.nfrags = conf.nfrags;
+    if (oss_open (1, &req, &obt, &fd)) {
+        return -1;
+    }
+
+    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        oss_anal_close (&fd);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    oss->nfrags = obt.nfrags;
+    oss->fragsize = obt.fragsize;
+
+    if (obt.nfrags * obt.fragsize & hw->info.align) {
+        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
+               obt.nfrags * obt.fragsize, hw->info.align + 1);
+    }
+
+    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
+    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!oss->pcm_buf) {
+        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        oss_anal_close (&fd);
+        return -1;
+    }
+
+    oss->fd = fd;
+    return 0;
+}
+
+static void oss_fini_in (HWVoiceIn *hw)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+    oss_anal_close (&oss->fd);
+
+    if (oss->pcm_buf) {
+        qemu_free (oss->pcm_buf);
+        oss->pcm_buf = NULL;
+    }
+}
+
+static int oss_run_in (HWVoiceIn *hw)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int i;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    size_t read_samples = 0;
+    struct {
+        int add;
+        int len;
+    } bufs[2] = {
+        { .add = hw->wpos, .len = 0 },
+        { .add = 0,        .len = 0 }
+    };
+
+    if (!dead) {
+        return 0;
+    }
+
+    if (hw->wpos + dead > hw->samples) {
+        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
+        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
+    }
+    else {
+        bufs[0].len = dead << hwshift;
+    }
+
+    for (i = 0; i < 2; ++i) {
+        ssize_t nread;
+
+        if (bufs[i].len) {
+            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
+            nread = read (oss->fd, p, bufs[i].len);
+
+            if (nread > 0) {
+                if (nread & hw->info.align) {
+                    dolog ("warning: Misaligned read %zd (requested %d), "
+                           "alignment %d\n", nread, bufs[i].add << hwshift,
+                           hw->info.align + 1);
+                }
+                read_samples += nread >> hwshift;
+                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
+            }
+
+            if (bufs[i].len - nread) {
+                if (nread == -1) {
+                    switch (errno) {
+                    case EINTR:
+                    case EAGAIN:
+                        break;
+                    default:
+                        oss_logerr (
+                            errno,
+                            "Failed to read %d bytes of audio (to %p)\n",
+                            bufs[i].len, p
+                            );
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    hw->wpos = (hw->wpos + read_samples) % hw->samples;
+    return read_samples;
+}
+
+static int oss_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            if (poll_mode && oss_poll_in (hw)) {
+                poll_mode = 0;
+            }
+            hw->poll_mode = poll_mode;
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (hw->poll_mode) {
+            hw->poll_mode = 0;
+            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
+        }
+        break;
+    }
+    return 0;
+}
+
+static void *oss_audio_init (void)
+{
+    return &conf;
+}
+
+static void oss_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option oss_options[] = {
+    {
+        .name  = "FRAGSIZE",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.fragsize,
+        .descr = "Fragment size in bytes"
+    },
+    {
+        .name  = "NFRAGS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nfrags,
+        .descr = "Number of fragments"
+    },
+    {
+        .name  = "MMAP",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.try_mmap,
+        .descr = "Try using memory mapped access"
+    },
+    {
+        .name  = "DAC_DEV",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.devpath_out,
+        .descr = "Path to DAC device"
+    },
+    {
+        .name  = "ADC_DEV",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.devpath_in,
+        .descr = "Path to ADC device"
+    },
+    {
+        .name  = "EXCLUSIVE",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.exclusive,
+        .descr = "Open device in exclusive mode (vmix wont work)"
+    },
+#ifdef USE_DSP_POLICY
+    {
+        .name  = "POLICY",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.policy,
+        .descr = "Set the timing policy of the device, -1 to use fragment mode",
+    },
+#endif
+    {
+        .name  = "DEBUG",
+        .tag   = AUD_OPT_BOOL,
+        .valp  = &conf.debug,
+        .descr = "Turn on some debugging messages"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops oss_pcm_ops = {
+    .init_out = oss_init_out,
+    .fini_out = oss_fini_out,
+    .run_out  = oss_run_out,
+    .write    = oss_write,
+    .ctl_out  = oss_ctl_out,
+
+    .init_in  = oss_init_in,
+    .fini_in  = oss_fini_in,
+    .run_in   = oss_run_in,
+    .read     = oss_read,
+    .ctl_in   = oss_ctl_in
+};
+
+struct audio_driver oss_audio_driver = {
+    .name           = "oss",
+    .descr          = "OSS http://www.opensound.com",
+    .options        = oss_options,
+    .init           = oss_audio_init,
+    .fini           = oss_audio_fini,
+    .pcm_ops        = &oss_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (OSSVoiceOut),
+    .voice_size_in  = sizeof (OSSVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/paaudio.c b/qemu-0.15.x/audio/paaudio.c
new file mode 100644
index 0000000..fb4510e
--- /dev/null
+++ b/qemu-0.15.x/audio/paaudio.c
@@ -0,0 +1,525 @@
+/* public domain */
+#include "qemu-common.h"
+#include "audio.h"
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+#define AUDIO_CAP "pulseaudio"
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+typedef struct {
+    HWVoiceOut hw;
+    int done;
+    int live;
+    int decr;
+    int rpos;
+    pa_simple *s;
+    void *pcm_buf;
+    struct audio_pt pt;
+} PAVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    int done;
+    int dead;
+    int incr;
+    int wpos;
+    pa_simple *s;
+    void *pcm_buf;
+    struct audio_pt pt;
+} PAVoiceIn;
+
+static struct {
+    int samples;
+    char *server;
+    char *sink;
+    char *source;
+} conf = {
+    .samples = 4096,
+};
+
+static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
+}
+
+static void *qpa_thread_out (void *arg)
+{
+    PAVoiceOut *pa = arg;
+    HWVoiceOut *hw = &pa->hw;
+
+    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+        return NULL;
+    }
+
+    for (;;) {
+        int decr, to_mix, rpos;
+
+        for (;;) {
+            if (pa->done) {
+                goto exit;
+            }
+
+            if (pa->live > 0) {
+                break;
+            }
+
+            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+        rpos = pa->rpos;
+
+        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_mix) {
+            int error;
+            int chunk = audio_MIN (to_mix, hw->samples - rpos);
+            struct st_sample *src = hw->mix_buf + rpos;
+
+            hw->clip (pa->pcm_buf, src, chunk);
+
+            if (pa_simple_write (pa->s, pa->pcm_buf,
+                                 chunk << hw->info.shift, &error) < 0) {
+                qpa_logerr (error, "pa_simple_write failed\n");
+                return NULL;
+            }
+
+            rpos = (rpos + chunk) % hw->samples;
+            to_mix -= chunk;
+        }
+
+        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        pa->rpos = rpos;
+        pa->live -= decr;
+        pa->decr += decr;
+    }
+
+ exit:
+    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qpa_run_out (HWVoiceOut *hw, int live)
+{
+    int decr;
+    PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    decr = audio_MIN (live, pa->decr);
+    pa->decr -= decr;
+    pa->live = live - decr;
+    hw->rpos = pa->rpos;
+    if (pa->live > 0) {
+        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+    }
+    return decr;
+}
+
+static int qpa_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+/* capture */
+static void *qpa_thread_in (void *arg)
+{
+    PAVoiceIn *pa = arg;
+    HWVoiceIn *hw = &pa->hw;
+
+    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+        return NULL;
+    }
+
+    for (;;) {
+        int incr, to_grab, wpos;
+
+        for (;;) {
+            if (pa->done) {
+                goto exit;
+            }
+
+            if (pa->dead > 0) {
+                break;
+            }
+
+            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+        wpos = pa->wpos;
+
+        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_grab) {
+            int error;
+            int chunk = audio_MIN (to_grab, hw->samples - wpos);
+            void *buf = advance (pa->pcm_buf, wpos);
+
+            if (pa_simple_read (pa->s, buf,
+                                chunk << hw->info.shift, &error) < 0) {
+                qpa_logerr (error, "pa_simple_read failed\n");
+                return NULL;
+            }
+
+            hw->conv (hw->conv_buf + wpos, buf, chunk);
+            wpos = (wpos + chunk) % hw->samples;
+            to_grab -= chunk;
+        }
+
+        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        pa->wpos = wpos;
+        pa->dead -= incr;
+        pa->incr += incr;
+    }
+
+ exit:
+    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qpa_run_in (HWVoiceIn *hw)
+{
+    int live, incr, dead;
+    PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    incr = audio_MIN (dead, pa->incr);
+    pa->incr -= incr;
+    pa->dead = dead - incr;
+    hw->wpos = pa->wpos;
+    if (pa->dead > 0) {
+        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+    }
+    return incr;
+}
+
+static int qpa_read (SWVoiceIn *sw, void *buf, int len)
+{
+    return audio_pcm_sw_read (sw, buf, len);
+}
+
+static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
+{
+    int format;
+
+    switch (afmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        format = PA_SAMPLE_U8;
+        break;
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
+        break;
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
+        break;
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", afmt);
+        format = PA_SAMPLE_U8;
+        break;
+    }
+    return format;
+}
+
+static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
+{
+    switch (fmt) {
+    case PA_SAMPLE_U8:
+        return AUD_FMT_U8;
+    case PA_SAMPLE_S16BE:
+        *endianness = 1;
+        return AUD_FMT_S16;
+    case PA_SAMPLE_S16LE:
+        *endianness = 0;
+        return AUD_FMT_S16;
+    case PA_SAMPLE_S32BE:
+        *endianness = 1;
+        return AUD_FMT_S32;
+    case PA_SAMPLE_S32LE:
+        *endianness = 0;
+        return AUD_FMT_S32;
+    default:
+        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
+        return AUD_FMT_U8;
+    }
+}
+
+static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    int error;
+    static pa_sample_spec ss;
+    static pa_buffer_attr ba;
+    struct audsettings obt_as = *as;
+    PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+    ss.format = audfmt_to_pa (as->fmt, as->endianness);
+    ss.channels = as->nchannels;
+    ss.rate = as->freq;
+
+    /*
+     * qemu audio tick runs at 250 Hz (by default), so processing
+     * data chunks worth 4 ms of sound should be a good fit.
+     */
+    ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
+    ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
+    ba.maxlength = -1;
+    ba.prebuf = -1;
+
+    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
+
+    pa->s = pa_simple_new (
+        conf.server,
+        "qemu",
+        PA_STREAM_PLAYBACK,
+        conf.sink,
+        "pcm.playback",
+        &ss,
+        NULL,                   /* channel map */
+        &ba,                    /* buffering attributes */
+        &error
+        );
+    if (!pa->s) {
+        qpa_logerr (error, "pa_simple_new for playback failed\n");
+        goto fail1;
+    }
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = conf.samples;
+    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    pa->rpos = hw->rpos;
+    if (!pa->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        goto fail2;
+    }
+
+    if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail3;
+    }
+
+    return 0;
+
+ fail3:
+    qemu_free (pa->pcm_buf);
+    pa->pcm_buf = NULL;
+ fail2:
+    pa_simple_free (pa->s);
+    pa->s = NULL;
+ fail1:
+    return -1;
+}
+
+static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    int error;
+    static pa_sample_spec ss;
+    struct audsettings obt_as = *as;
+    PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+    ss.format = audfmt_to_pa (as->fmt, as->endianness);
+    ss.channels = as->nchannels;
+    ss.rate = as->freq;
+
+    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
+
+    pa->s = pa_simple_new (
+        conf.server,
+        "qemu",
+        PA_STREAM_RECORD,
+        conf.source,
+        "pcm.capture",
+        &ss,
+        NULL,                   /* channel map */
+        NULL,                   /* buffering attributes */
+        &error
+        );
+    if (!pa->s) {
+        qpa_logerr (error, "pa_simple_new for capture failed\n");
+        goto fail1;
+    }
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = conf.samples;
+    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    pa->wpos = hw->wpos;
+    if (!pa->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        goto fail2;
+    }
+
+    if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail3;
+    }
+
+    return 0;
+
+ fail3:
+    qemu_free (pa->pcm_buf);
+    pa->pcm_buf = NULL;
+ fail2:
+    pa_simple_free (pa->s);
+    pa->s = NULL;
+ fail1:
+    return -1;
+}
+
+static void qpa_fini_out (HWVoiceOut *hw)
+{
+    void *ret;
+    PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+    audio_pt_lock (&pa->pt, AUDIO_FUNC);
+    pa->done = 1;
+    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
+
+    if (pa->s) {
+        pa_simple_free (pa->s);
+        pa->s = NULL;
+    }
+
+    audio_pt_fini (&pa->pt, AUDIO_FUNC);
+    qemu_free (pa->pcm_buf);
+    pa->pcm_buf = NULL;
+}
+
+static void qpa_fini_in (HWVoiceIn *hw)
+{
+    void *ret;
+    PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+    audio_pt_lock (&pa->pt, AUDIO_FUNC);
+    pa->done = 1;
+    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
+
+    if (pa->s) {
+        pa_simple_free (pa->s);
+        pa->s = NULL;
+    }
+
+    audio_pt_fini (&pa->pt, AUDIO_FUNC);
+    qemu_free (pa->pcm_buf);
+    pa->pcm_buf = NULL;
+}
+
+static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+/* common */
+static void *qpa_audio_init (void)
+{
+    return &conf;
+}
+
+static void qpa_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+struct audio_option qpa_options[] = {
+    {
+        .name  = "SAMPLES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.samples,
+        .descr = "buffer size in samples"
+    },
+    {
+        .name  = "SERVER",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.server,
+        .descr = "server address"
+    },
+    {
+        .name  = "SINK",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.sink,
+        .descr = "sink device name"
+    },
+    {
+        .name  = "SOURCE",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.source,
+        .descr = "source device name"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops qpa_pcm_ops = {
+    .init_out = qpa_init_out,
+    .fini_out = qpa_fini_out,
+    .run_out  = qpa_run_out,
+    .write    = qpa_write,
+    .ctl_out  = qpa_ctl_out,
+
+    .init_in  = qpa_init_in,
+    .fini_in  = qpa_fini_in,
+    .run_in   = qpa_run_in,
+    .read     = qpa_read,
+    .ctl_in   = qpa_ctl_in
+};
+
+struct audio_driver pa_audio_driver = {
+    .name           = "pa",
+    .descr          = "http://www.pulseaudio.org/",
+    .options        = qpa_options,
+    .init           = qpa_audio_init,
+    .fini           = qpa_audio_fini,
+    .pcm_ops        = &qpa_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (PAVoiceOut),
+    .voice_size_in  = sizeof (PAVoiceIn)
+};
diff --git a/qemu-0.15.x/audio/rate_template.h b/qemu-0.15.x/audio/rate_template.h
new file mode 100644
index 0000000..bd4b1c7
--- /dev/null
+++ b/qemu-0.15.x/audio/rate_template.h
@@ -0,0 +1,111 @@
+/*
+ * QEMU Mixing engine
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ * Copyright (c) 1998 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.
+ */
+
+/*
+ * Processed signed long samples from ibuf to obuf.
+ * Return number of samples processed.
+ */
+void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
+           int *isamp, int *osamp)
+{
+    struct rate *rate = opaque;
+    struct st_sample *istart, *iend;
+    struct st_sample *ostart, *oend;
+    struct st_sample ilast, icur, out;
+#ifdef FLOAT_MIXENG
+    mixeng_real t;
+#else
+    int64_t t;
+#endif
+
+    ilast = rate->ilast;
+
+    istart = ibuf;
+    iend = ibuf + *isamp;
+
+    ostart = obuf;
+    oend = obuf + *osamp;
+
+    if (rate->opos_inc == (1ULL + UINT_MAX)) {
+        int i, n = *isamp > *osamp ? *osamp : *isamp;
+        for (i = 0; i < n; i++) {
+            OP (obuf[i].l, ibuf[i].l);
+            OP (obuf[i].r, ibuf[i].r);
+        }
+        *isamp = n;
+        *osamp = n;
+        return;
+    }
+
+    while (obuf < oend) {
+
+        /* Safety catch to make sure we have input samples.  */
+        if (ibuf >= iend) {
+            break;
+        }
+
+        /* read as many input samples so that ipos > opos */
+
+        while (rate->ipos <= (rate->opos >> 32)) {
+            ilast = *ibuf++;
+            rate->ipos++;
+            /* See if we finished the input buffer yet */
+            if (ibuf >= iend) {
+                goto the_end;
+            }
+        }
+
+        icur = *ibuf;
+
+        /* interpolate */
+#ifdef FLOAT_MIXENG
+#ifdef RECIPROCAL
+        t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
+#else
+        t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX;
+#endif
+        out.l = (ilast.l * (1.0 - t)) + icur.l * t;
+        out.r = (ilast.r * (1.0 - t)) + icur.r * t;
+#else
+        t = rate->opos & 0xffffffff;
+        out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32;
+        out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32;
+#endif
+
+        /* output sample & increment position */
+        OP (obuf->l, out.l);
+        OP (obuf->r, out.r);
+        obuf += 1;
+        rate->opos += rate->opos_inc;
+    }
+
+the_end:
+    *isamp = ibuf - istart;
+    *osamp = obuf - ostart;
+    rate->ilast = ilast;
+}
+
+#undef NAME
+#undef OP
diff --git a/qemu-0.15.x/audio/sdlaudio.c b/qemu-0.15.x/audio/sdlaudio.c
new file mode 100644
index 0000000..d24daa5
--- /dev/null
+++ b/qemu-0.15.x/audio/sdlaudio.c
@@ -0,0 +1,458 @@
+/*
+ * QEMU SDL audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 <SDL.h>
+#include <SDL_thread.h>
+#include "qemu-common.h"
+#include "audio.h"
+
+#ifndef _WIN32
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+#include <pthread.h>
+#endif
+#endif
+
+#define AUDIO_CAP "sdl"
+#include "audio_int.h"
+
+typedef struct SDLVoiceOut {
+    HWVoiceOut hw;
+    int live;
+    int rpos;
+    int decr;
+} SDLVoiceOut;
+
+static struct {
+    int nb_samples;
+} conf = {
+    .nb_samples = 1024
+};
+
+static struct SDLAudioState {
+    int exit;
+    SDL_mutex *mutex;
+    SDL_sem *sem;
+    int initialized;
+} glob_sdl;
+typedef struct SDLAudioState SDLAudioState;
+
+static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
+}
+
+static int sdl_lock (SDLAudioState *s, const char *forfn)
+{
+    if (SDL_LockMutex (s->mutex)) {
+        sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
+        return -1;
+    }
+    return 0;
+}
+
+static int sdl_unlock (SDLAudioState *s, const char *forfn)
+{
+    if (SDL_UnlockMutex (s->mutex)) {
+        sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
+        return -1;
+    }
+    return 0;
+}
+
+static int sdl_post (SDLAudioState *s, const char *forfn)
+{
+    if (SDL_SemPost (s->sem)) {
+        sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
+        return -1;
+    }
+    return 0;
+}
+
+static int sdl_wait (SDLAudioState *s, const char *forfn)
+{
+    if (SDL_SemWait (s->sem)) {
+        sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
+        return -1;
+    }
+    return 0;
+}
+
+static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
+{
+    if (sdl_unlock (s, forfn)) {
+        return -1;
+    }
+
+    return sdl_post (s, forfn);
+}
+
+static int aud_to_sdlfmt (audfmt_e fmt)
+{
+    switch (fmt) {
+    case AUD_FMT_S8:
+        return AUDIO_S8;
+
+    case AUD_FMT_U8:
+        return AUDIO_U8;
+
+    case AUD_FMT_S16:
+        return AUDIO_S16LSB;
+
+    case AUD_FMT_U16:
+        return AUDIO_U16LSB;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return AUDIO_U8;
+    }
+}
+
+static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
+{
+    switch (sdlfmt) {
+    case AUDIO_S8:
+        *endianness = 0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case AUDIO_U8:
+        *endianness = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case AUDIO_S16LSB:
+        *endianness = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AUDIO_U16LSB:
+        *endianness = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case AUDIO_S16MSB:
+        *endianness = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AUDIO_U16MSB:
+        *endianness = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    default:
+        dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
+{
+    int status;
+#ifndef _WIN32
+    int err;
+    sigset_t new, old;
+
+    /* Make sure potential threads created by SDL don't hog signals.  */
+    err = sigfillset (&new);
+    if (err) {
+        dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
+        return -1;
+    }
+    err = pthread_sigmask (SIG_BLOCK, &new, &old);
+    if (err) {
+        dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
+        return -1;
+    }
+#endif
+
+    status = SDL_OpenAudio (req, obt);
+    if (status) {
+        sdl_logerr ("SDL_OpenAudio failed\n");
+    }
+
+#ifndef _WIN32
+    err = pthread_sigmask (SIG_SETMASK, &old, NULL);
+    if (err) {
+        dolog ("sdl_open: pthread_sigmask (restore) failed: %s\n",
+               strerror (errno));
+        /* We have failed to restore original signal mask, all bets are off,
+           so exit the process */
+        exit (EXIT_FAILURE);
+    }
+#endif
+    return status;
+}
+
+static void sdl_close (SDLAudioState *s)
+{
+    if (s->initialized) {
+        sdl_lock (s, "sdl_close");
+        s->exit = 1;
+        sdl_unlock_and_post (s, "sdl_close");
+        SDL_PauseAudio (1);
+        SDL_CloseAudio ();
+        s->initialized = 0;
+    }
+}
+
+static void sdl_callback (void *opaque, Uint8 *buf, int len)
+{
+    SDLVoiceOut *sdl = opaque;
+    SDLAudioState *s = &glob_sdl;
+    HWVoiceOut *hw = &sdl->hw;
+    int samples = len >> hw->info.shift;
+
+    if (s->exit) {
+        return;
+    }
+
+    while (samples) {
+        int to_mix, decr;
+
+        /* dolog ("in callback samples=%d\n", samples); */
+        sdl_wait (s, "sdl_callback");
+        if (s->exit) {
+            return;
+        }
+
+        if (sdl_lock (s, "sdl_callback")) {
+            return;
+        }
+
+        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
+            dolog ("sdl->live=%d hw->samples=%d\n",
+                   sdl->live, hw->samples);
+            return;
+        }
+
+        if (!sdl->live) {
+            goto again;
+        }
+
+        /* dolog ("in callback live=%d\n", live); */
+        to_mix = audio_MIN (samples, sdl->live);
+        decr = to_mix;
+        while (to_mix) {
+            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
+            struct st_sample *src = hw->mix_buf + hw->rpos;
+
+            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
+            hw->clip (buf, src, chunk);
+            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
+            to_mix -= chunk;
+            buf += chunk << hw->info.shift;
+        }
+        samples -= decr;
+        sdl->live -= decr;
+        sdl->decr += decr;
+
+    again:
+        if (sdl_unlock (s, "sdl_callback")) {
+            return;
+        }
+    }
+    /* dolog ("done len=%d\n", len); */
+}
+
+static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int sdl_run_out (HWVoiceOut *hw, int live)
+{
+    int decr;
+    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
+    SDLAudioState *s = &glob_sdl;
+
+    if (sdl_lock (s, "sdl_run_out")) {
+        return 0;
+    }
+
+    if (sdl->decr > live) {
+        ldebug ("sdl->decr %d live %d sdl->live %d\n",
+                sdl->decr,
+                live,
+                sdl->live);
+    }
+
+    decr = audio_MIN (sdl->decr, live);
+    sdl->decr -= decr;
+
+    sdl->live = live - decr;
+    hw->rpos = sdl->rpos;
+
+    if (sdl->live > 0) {
+        sdl_unlock_and_post (s, "sdl_run_out");
+    }
+    else {
+        sdl_unlock (s, "sdl_run_out");
+    }
+    return decr;
+}
+
+static void sdl_fini_out (HWVoiceOut *hw)
+{
+    (void) hw;
+
+    sdl_close (&glob_sdl);
+}
+
+static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
+    SDLAudioState *s = &glob_sdl;
+    SDL_AudioSpec req, obt;
+    int endianness;
+    int err;
+    audfmt_e effective_fmt;
+    struct audsettings obt_as;
+
+    req.freq = as->freq;
+    req.format = aud_to_sdlfmt (as->fmt);
+    req.channels = as->nchannels;
+    req.samples = conf.nb_samples;
+    req.callback = sdl_callback;
+    req.userdata = sdl;
+
+    if (sdl_open (&req, &obt)) {
+        return -1;
+    }
+
+    err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
+    if (err) {
+        sdl_close (s);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.channels;
+    obt_as.fmt = effective_fmt;
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+    hw->samples = obt.samples;
+
+    s->initialized = 1;
+    s->exit = 0;
+    SDL_PauseAudio (0);
+    return 0;
+}
+
+static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        SDL_PauseAudio (0);
+        break;
+
+    case VOICE_DISABLE:
+        SDL_PauseAudio (1);
+        break;
+    }
+    return 0;
+}
+
+static void *sdl_audio_init (void)
+{
+    SDLAudioState *s = &glob_sdl;
+
+    if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
+        sdl_logerr ("SDL failed to initialize audio subsystem\n");
+        return NULL;
+    }
+
+    s->mutex = SDL_CreateMutex ();
+    if (!s->mutex) {
+        sdl_logerr ("Failed to create SDL mutex\n");
+        SDL_QuitSubSystem (SDL_INIT_AUDIO);
+        return NULL;
+    }
+
+    s->sem = SDL_CreateSemaphore (0);
+    if (!s->sem) {
+        sdl_logerr ("Failed to create SDL semaphore\n");
+        SDL_DestroyMutex (s->mutex);
+        SDL_QuitSubSystem (SDL_INIT_AUDIO);
+        return NULL;
+    }
+
+    return s;
+}
+
+static void sdl_audio_fini (void *opaque)
+{
+    SDLAudioState *s = opaque;
+    sdl_close (s);
+    SDL_DestroySemaphore (s->sem);
+    SDL_DestroyMutex (s->mutex);
+    SDL_QuitSubSystem (SDL_INIT_AUDIO);
+}
+
+static struct audio_option sdl_options[] = {
+    {
+        .name  = "SAMPLES",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nb_samples,
+        .descr = "Size of SDL buffer in samples"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops sdl_pcm_ops = {
+    .init_out = sdl_init_out,
+    .fini_out = sdl_fini_out,
+    .run_out  = sdl_run_out,
+    .write    = sdl_write_out,
+    .ctl_out  = sdl_ctl_out,
+};
+
+struct audio_driver sdl_audio_driver = {
+    .name           = "sdl",
+    .descr          = "SDL http://www.libsdl.org",
+    .options        = sdl_options,
+    .init           = sdl_audio_init,
+    .fini           = sdl_audio_fini,
+    .pcm_ops        = &sdl_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = 1,
+    .max_voices_in  = 0,
+    .voice_size_out = sizeof (SDLVoiceOut),
+    .voice_size_in  = 0
+};
diff --git a/qemu-0.15.x/audio/spiceaudio.c b/qemu-0.15.x/audio/spiceaudio.c
new file mode 100644
index 0000000..f972110
--- /dev/null
+++ b/qemu-0.15.x/audio/spiceaudio.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "ui/qemu-spice.h"
+
+#define AUDIO_CAP "spice"
+#include "audio.h"
+#include "audio_int.h"
+
+#define LINE_IN_SAMPLES 1024
+#define LINE_OUT_SAMPLES 1024
+
+typedef struct SpiceRateCtl {
+    int64_t               start_ticks;
+    int64_t               bytes_sent;
+} SpiceRateCtl;
+
+typedef struct SpiceVoiceOut {
+    HWVoiceOut            hw;
+    SpicePlaybackInstance sin;
+    SpiceRateCtl          rate;
+    int                   active;
+    uint32_t              *frame;
+    uint32_t              *fpos;
+    uint32_t              fsize;
+} SpiceVoiceOut;
+
+typedef struct SpiceVoiceIn {
+    HWVoiceIn             hw;
+    SpiceRecordInstance   sin;
+    SpiceRateCtl          rate;
+    int                   active;
+    uint32_t              samples[LINE_IN_SAMPLES];
+} SpiceVoiceIn;
+
+static const SpicePlaybackInterface playback_sif = {
+    .base.type          = SPICE_INTERFACE_PLAYBACK,
+    .base.description   = "playback",
+    .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+static const SpiceRecordInterface record_sif = {
+    .base.type          = SPICE_INTERFACE_RECORD,
+    .base.description   = "record",
+    .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
+};
+
+static void *spice_audio_init (void)
+{
+    if (!using_spice) {
+        return NULL;
+    }
+    return &spice_audio_init;
+}
+
+static void spice_audio_fini (void *opaque)
+{
+    /* nothing */
+}
+
+static void rate_start (SpiceRateCtl *rate)
+{
+    memset (rate, 0, sizeof (*rate));
+    rate->start_ticks = qemu_get_clock_ns (vm_clock);
+}
+
+static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
+{
+    int64_t now;
+    int64_t ticks;
+    int64_t bytes;
+    int64_t samples;
+
+    now = qemu_get_clock_ns (vm_clock);
+    ticks = now - rate->start_ticks;
+    bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
+    samples = (bytes - rate->bytes_sent) >> info->shift;
+    if (samples < 0 || samples > 65536) {
+        fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
+        rate_start (rate);
+        samples = 0;
+    }
+    rate->bytes_sent += samples << info->shift;
+    return samples;
+}
+
+/* playback */
+
+static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &settings);
+    hw->samples = LINE_OUT_SAMPLES;
+    out->active = 0;
+
+    out->sin.base.sif = &playback_sif.base;
+    qemu_spice_add_interface (&out->sin.base);
+    return 0;
+}
+
+static void line_out_fini (HWVoiceOut *hw)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+    spice_server_remove_interface (&out->sin.base);
+}
+
+static int line_out_run (HWVoiceOut *hw, int live)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+    int rpos, decr;
+    int samples;
+
+    if (!live) {
+        return 0;
+    }
+
+    decr = rate_get_samples (&hw->info, &out->rate);
+    decr = audio_MIN (live, decr);
+
+    samples = decr;
+    rpos = hw->rpos;
+    while (samples) {
+        int left_till_end_samples = hw->samples - rpos;
+        int len = audio_MIN (samples, left_till_end_samples);
+
+        if (!out->frame) {
+            spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
+            out->fpos = out->frame;
+        }
+        if (out->frame) {
+            len = audio_MIN (len, out->fsize);
+            hw->clip (out->fpos, hw->mix_buf + rpos, len);
+            out->fsize -= len;
+            out->fpos  += len;
+            if (out->fsize == 0) {
+                spice_server_playback_put_samples (&out->sin, out->frame);
+                out->frame = out->fpos = NULL;
+            }
+        }
+        rpos = (rpos + len) % hw->samples;
+        samples -= len;
+    }
+    hw->rpos = rpos;
+    return decr;
+}
+
+static int line_out_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (out->active) {
+            break;
+        }
+        out->active = 1;
+        rate_start (&out->rate);
+        spice_server_playback_start (&out->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!out->active) {
+            break;
+        }
+        out->active = 0;
+        if (out->frame) {
+            memset (out->fpos, 0, out->fsize << 2);
+            spice_server_playback_put_samples (&out->sin, out->frame);
+            out->frame = out->fpos = NULL;
+        }
+        spice_server_playback_stop (&out->sin);
+        break;
+    }
+    return 0;
+}
+
+/* record */
+
+static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &settings);
+    hw->samples = LINE_IN_SAMPLES;
+    in->active = 0;
+
+    in->sin.base.sif = &record_sif.base;
+    qemu_spice_add_interface (&in->sin.base);
+    return 0;
+}
+
+static void line_in_fini (HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+    spice_server_remove_interface (&in->sin.base);
+}
+
+static int line_in_run (HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+    int num_samples;
+    int ready;
+    int len[2];
+    uint64_t delta_samp;
+    const uint32_t *samples;
+
+    if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
+        return 0;
+    }
+
+    delta_samp = rate_get_samples (&hw->info, &in->rate);
+    num_samples = audio_MIN (num_samples, delta_samp);
+
+    ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
+    samples = in->samples;
+    if (ready == 0) {
+        static const uint32_t silence[LINE_IN_SAMPLES];
+        samples = silence;
+        ready = LINE_IN_SAMPLES;
+    }
+
+    num_samples = audio_MIN (ready, num_samples);
+
+    if (hw->wpos + num_samples > hw->samples) {
+        len[0] = hw->samples - hw->wpos;
+        len[1] = num_samples - len[0];
+    } else {
+        len[0] = num_samples;
+        len[1] = 0;
+    }
+
+    hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
+
+    if (len[1]) {
+        hw->conv (hw->conv_buf, samples + len[0], len[1]);
+    }
+
+    hw->wpos = (hw->wpos + num_samples) % hw->samples;
+
+    return num_samples;
+}
+
+static int line_in_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (in->active) {
+            break;
+        }
+        in->active = 1;
+        rate_start (&in->rate);
+        spice_server_record_start (&in->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!in->active) {
+            break;
+        }
+        in->active = 0;
+        spice_server_record_stop (&in->sin);
+        break;
+    }
+    return 0;
+}
+
+static struct audio_option audio_options[] = {
+    { /* end of list */ },
+};
+
+static struct audio_pcm_ops audio_callbacks = {
+    .init_out = line_out_init,
+    .fini_out = line_out_fini,
+    .run_out  = line_out_run,
+    .write    = line_out_write,
+    .ctl_out  = line_out_ctl,
+
+    .init_in  = line_in_init,
+    .fini_in  = line_in_fini,
+    .run_in   = line_in_run,
+    .read     = line_in_read,
+    .ctl_in   = line_in_ctl,
+};
+
+struct audio_driver spice_audio_driver = {
+    .name           = "spice",
+    .descr          = "spice audio driver",
+    .options        = audio_options,
+    .init           = spice_audio_init,
+    .fini           = spice_audio_fini,
+    .pcm_ops        = &audio_callbacks,
+    .max_voices_out = 1,
+    .max_voices_in  = 1,
+    .voice_size_out = sizeof (SpiceVoiceOut),
+    .voice_size_in  = sizeof (SpiceVoiceIn),
+};
+
+void qemu_spice_audio_init (void)
+{
+    spice_audio_driver.can_be_default = 1;
+}
diff --git a/qemu-0.15.x/audio/wavaudio.c b/qemu-0.15.x/audio/wavaudio.c
new file mode 100644
index 0000000..294f357
--- /dev/null
+++ b/qemu-0.15.x/audio/wavaudio.c
@@ -0,0 +1,262 @@
+/*
+ * QEMU WAV audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "qemu-timer.h"
+#include "audio.h"
+
+#define AUDIO_CAP "wav"
+#include "audio_int.h"
+
+typedef struct WAVVoiceOut {
+    HWVoiceOut hw;
+    QEMUFile *f;
+    int64_t old_ticks;
+    void *pcm_buf;
+    int total_samples;
+} WAVVoiceOut;
+
+static struct {
+    struct audsettings settings;
+    const char *wav_path;
+} conf = {
+    .settings.freq      = 44100,
+    .settings.nchannels = 2,
+    .settings.fmt       = AUD_FMT_S16,
+    .wav_path           = "qemu.wav"
+};
+
+static int wav_run_out (HWVoiceOut *hw, int live)
+{
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+    int rpos, decr, samples;
+    uint8_t *dst;
+    struct st_sample *src;
+    int64_t now = qemu_get_clock_ns (vm_clock);
+    int64_t ticks = now - wav->old_ticks;
+    int64_t bytes =
+        muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
+
+    if (bytes > INT_MAX) {
+        samples = INT_MAX >> hw->info.shift;
+    }
+    else {
+        samples = bytes >> hw->info.shift;
+    }
+
+    wav->old_ticks = now;
+    decr = audio_MIN (live, samples);
+    samples = decr;
+    rpos = hw->rpos;
+    while (samples) {
+        int left_till_end_samples = hw->samples - rpos;
+        int convert_samples = audio_MIN (samples, left_till_end_samples);
+
+        src = hw->mix_buf + rpos;
+        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
+
+        hw->clip (dst, src, convert_samples);
+        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
+
+        rpos = (rpos + convert_samples) % hw->samples;
+        samples -= convert_samples;
+        wav->total_samples += convert_samples;
+    }
+
+    hw->rpos = rpos;
+    return decr;
+}
+
+static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+/* VICE code: Store number as little endian. */
+static void le_store (uint8_t *buf, uint32_t val, int len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        buf[i] = (uint8_t) (val & 0xff);
+        val >>= 8;
+    }
+}
+
+static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+    int bits16 = 0, stereo = 0;
+    uint8_t hdr[] = {
+        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
+        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
+        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
+        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
+    };
+    struct audsettings wav_as = conf.settings;
+
+    (void) as;
+
+    stereo = wav_as.nchannels == 2;
+    switch (wav_as.fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        bits16 = 0;
+        break;
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        bits16 = 1;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("WAVE files can not handle 32bit formats\n");
+        return -1;
+    }
+
+    hdr[34] = bits16 ? 0x10 : 0x08;
+
+    wav_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &wav_as);
+
+    hw->samples = 1024;
+    wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!wav->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        return -1;
+    }
+
+    le_store (hdr + 22, hw->info.nchannels, 2);
+    le_store (hdr + 24, hw->info.freq, 4);
+    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
+    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
+
+    wav->f = qemu_fopen (conf.wav_path, "wb");
+    if (!wav->f) {
+        dolog ("Failed to open wave file `%s'\nReason: %s\n",
+               conf.wav_path, strerror (errno));
+        qemu_free (wav->pcm_buf);
+        wav->pcm_buf = NULL;
+        return -1;
+    }
+
+    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+    return 0;
+}
+
+static void wav_fini_out (HWVoiceOut *hw)
+{
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+    uint8_t rlen[4];
+    uint8_t dlen[4];
+    uint32_t datalen = wav->total_samples << hw->info.shift;
+    uint32_t rifflen = datalen + 36;
+
+    if (!wav->f) {
+        return;
+    }
+
+    le_store (rlen, rifflen, 4);
+    le_store (dlen, datalen, 4);
+
+    qemu_fseek (wav->f, 4, SEEK_SET);
+    qemu_put_buffer (wav->f, rlen, 4);
+
+    qemu_fseek (wav->f, 32, SEEK_CUR);
+    qemu_put_buffer (wav->f, dlen, 4);
+
+    qemu_fclose (wav->f);
+    wav->f = NULL;
+
+    qemu_free (wav->pcm_buf);
+    wav->pcm_buf = NULL;
+}
+
+static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+static void *wav_audio_init (void)
+{
+    return &conf;
+}
+
+static void wav_audio_fini (void *opaque)
+{
+    (void) opaque;
+    ldebug ("wav_fini");
+}
+
+static struct audio_option wav_options[] = {
+    {
+        .name  = "FREQUENCY",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.settings.freq,
+        .descr = "Frequency"
+    },
+    {
+        .name  = "FORMAT",
+        .tag   = AUD_OPT_FMT,
+        .valp  = &conf.settings.fmt,
+        .descr = "Format"
+    },
+    {
+        .name  = "DAC_FIXED_CHANNELS",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.settings.nchannels,
+        .descr = "Number of channels (1 - mono, 2 - stereo)"
+    },
+    {
+        .name  = "PATH",
+        .tag   = AUD_OPT_STR,
+        .valp  = &conf.wav_path,
+        .descr = "Path to wave file"
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops wav_pcm_ops = {
+    .init_out = wav_init_out,
+    .fini_out = wav_fini_out,
+    .run_out  = wav_run_out,
+    .write    = wav_write_out,
+    .ctl_out  = wav_ctl_out,
+};
+
+struct audio_driver wav_audio_driver = {
+    .name           = "wav",
+    .descr          = "WAV renderer http://wikipedia.org/wiki/WAV",
+    .options        = wav_options,
+    .init           = wav_audio_init,
+    .fini           = wav_audio_fini,
+    .pcm_ops        = &wav_pcm_ops,
+    .can_be_default = 0,
+    .max_voices_out = 1,
+    .max_voices_in  = 0,
+    .voice_size_out = sizeof (WAVVoiceOut),
+    .voice_size_in  = 0
+};
diff --git a/qemu-0.15.x/audio/wavcapture.c b/qemu-0.15.x/audio/wavcapture.c
new file mode 100644
index 0000000..1f49cd1
--- /dev/null
+++ b/qemu-0.15.x/audio/wavcapture.c
@@ -0,0 +1,161 @@
+#include "hw/hw.h"
+#include "monitor.h"
+#include "audio.h"
+
+typedef struct {
+    QEMUFile *f;
+    int bytes;
+    char *path;
+    int freq;
+    int bits;
+    int nchannels;
+    CaptureVoiceOut *cap;
+} WAVState;
+
+/* VICE code: Store number as little endian. */
+static void le_store (uint8_t *buf, uint32_t val, int len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        buf[i] = (uint8_t) (val & 0xff);
+        val >>= 8;
+    }
+}
+
+static void wav_notify (void *opaque, audcnotification_e cmd)
+{
+    (void) opaque;
+    (void) cmd;
+}
+
+static void wav_destroy (void *opaque)
+{
+    WAVState *wav = opaque;
+    uint8_t rlen[4];
+    uint8_t dlen[4];
+    uint32_t datalen = wav->bytes;
+    uint32_t rifflen = datalen + 36;
+
+    if (wav->f) {
+        le_store (rlen, rifflen, 4);
+        le_store (dlen, datalen, 4);
+
+        qemu_fseek (wav->f, 4, SEEK_SET);
+        qemu_put_buffer (wav->f, rlen, 4);
+
+        qemu_fseek (wav->f, 32, SEEK_CUR);
+        qemu_put_buffer (wav->f, dlen, 4);
+        qemu_fclose (wav->f);
+    }
+
+    qemu_free (wav->path);
+}
+
+static void wav_capture (void *opaque, void *buf, int size)
+{
+    WAVState *wav = opaque;
+
+    qemu_put_buffer (wav->f, buf, size);
+    wav->bytes += size;
+}
+
+static void wav_capture_destroy (void *opaque)
+{
+    WAVState *wav = opaque;
+
+    AUD_del_capture (wav->cap, wav);
+}
+
+static void wav_capture_info (void *opaque)
+{
+    WAVState *wav = opaque;
+    char *path = wav->path;
+
+    monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
+                   wav->freq, wav->bits, wav->nchannels,
+                   path ? path : "<not available>", wav->bytes);
+}
+
+static struct capture_ops wav_capture_ops = {
+    .destroy = wav_capture_destroy,
+    .info = wav_capture_info
+};
+
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+                       int bits, int nchannels)
+{
+    Monitor *mon = cur_mon;
+    WAVState *wav;
+    uint8_t hdr[] = {
+        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
+        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
+        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
+        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
+    };
+    struct audsettings as;
+    struct audio_capture_ops ops;
+    int stereo, bits16, shift;
+    CaptureVoiceOut *cap;
+
+    if (bits != 8 && bits != 16) {
+        monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
+        return -1;
+    }
+
+    if (nchannels != 1 && nchannels != 2) {
+        monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
+                       nchannels);
+        return -1;
+    }
+
+    stereo = nchannels == 2;
+    bits16 = bits == 16;
+
+    as.freq = freq;
+    as.nchannels = 1 << stereo;
+    as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
+    as.endianness = 0;
+
+    ops.notify = wav_notify;
+    ops.capture = wav_capture;
+    ops.destroy = wav_destroy;
+
+    wav = qemu_mallocz (sizeof (*wav));
+
+    shift = bits16 + stereo;
+    hdr[34] = bits16 ? 0x10 : 0x08;
+
+    le_store (hdr + 22, as.nchannels, 2);
+    le_store (hdr + 24, freq, 4);
+    le_store (hdr + 28, freq << shift, 4);
+    le_store (hdr + 32, 1 << shift, 2);
+
+    wav->f = qemu_fopen (path, "wb");
+    if (!wav->f) {
+        monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
+                       path, strerror (errno));
+        qemu_free (wav);
+        return -1;
+    }
+
+    wav->path = qemu_strdup (path);
+    wav->bits = bits;
+    wav->nchannels = nchannels;
+    wav->freq = freq;
+
+    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+
+    cap = AUD_add_capture (&as, &ops, wav);
+    if (!cap) {
+        monitor_printf(mon, "Failed to add audio capture\n");
+        qemu_free (wav->path);
+        qemu_fclose (wav->f);
+        qemu_free (wav);
+        return -1;
+    }
+
+    wav->cap = cap;
+    s->opaque = wav;
+    s->ops = wav_capture_ops;
+    return 0;
+}
diff --git a/qemu-0.15.x/audio/winwaveaudio.c b/qemu-0.15.x/audio/winwaveaudio.c
new file mode 100644
index 0000000..e5ad3c6
--- /dev/null
+++ b/qemu-0.15.x/audio/winwaveaudio.c
@@ -0,0 +1,723 @@
+/* public domain */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "audio.h"
+
+#define AUDIO_CAP "winwave"
+#include "audio_int.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "audio_win_int.h"
+
+static struct {
+    int dac_headers;
+    int dac_samples;
+    int adc_headers;
+    int adc_samples;
+} conf = {
+    .dac_headers = 4,
+    .dac_samples = 1024,
+    .adc_headers = 4,
+    .adc_samples = 1024
+};
+
+typedef struct {
+    HWVoiceOut hw;
+    HWAVEOUT hwo;
+    WAVEHDR *hdrs;
+    HANDLE event;
+    void *pcm_buf;
+    int avail;
+    int pending;
+    int curhdr;
+    int paused;
+    CRITICAL_SECTION crit_sect;
+} WaveVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    HWAVEIN hwi;
+    WAVEHDR *hdrs;
+    HANDLE event;
+    void *pcm_buf;
+    int curhdr;
+    int paused;
+    int rpos;
+    int avail;
+    CRITICAL_SECTION crit_sect;
+} WaveVoiceIn;
+
+static void winwave_log_mmresult (MMRESULT mr)
+{
+    const char *str = "BUG";
+
+    switch (mr) {
+    case MMSYSERR_NOERROR:
+        str = "Success";
+        break;
+
+    case MMSYSERR_INVALHANDLE:
+        str = "Specified device handle is invalid";
+        break;
+
+    case MMSYSERR_BADDEVICEID:
+        str = "Specified device id is out of range";
+        break;
+
+    case MMSYSERR_NODRIVER:
+        str = "No device driver is present";
+        break;
+
+    case MMSYSERR_NOMEM:
+        str = "Unable to allocate or locl memory";
+        break;
+
+    case WAVERR_SYNC:
+        str = "Device is synchronous but waveOutOpen was called "
+            "without using the WINWAVE_ALLOWSYNC flag";
+        break;
+
+    case WAVERR_UNPREPARED:
+        str = "The data block pointed to by the pwh parameter "
+            "hasn't been prepared";
+        break;
+
+    case WAVERR_STILLPLAYING:
+        str = "There are still buffers in the queue";
+        break;
+
+    default:
+        dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
+        return;
+    }
+
+    dolog ("Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) winwave_logerr (
+    MMRESULT mr,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (NULL, " failed\n");
+    winwave_log_mmresult (mr);
+}
+
+static void winwave_anal_close_out (WaveVoiceOut *wave)
+{
+    MMRESULT mr;
+
+    mr = waveOutClose (wave->hwo);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveOutClose");
+    }
+    wave->hwo = NULL;
+}
+
+static void CALLBACK winwave_callback_out (
+    HWAVEOUT hwo,
+    UINT msg,
+    DWORD_PTR dwInstance,
+    DWORD_PTR dwParam1,
+    DWORD_PTR dwParam2
+    )
+{
+    WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
+
+    switch (msg) {
+    case WOM_DONE:
+        {
+            WAVEHDR *h = (WAVEHDR *) dwParam1;
+            if (!h->dwUser) {
+                h->dwUser = 1;
+                EnterCriticalSection (&wave->crit_sect);
+                {
+                    wave->avail += conf.dac_samples;
+                }
+                LeaveCriticalSection (&wave->crit_sect);
+                if (wave->hw.poll_mode) {
+                    if (!SetEvent (wave->event)) {
+                        dolog ("DAC SetEvent failed %lx\n", GetLastError ());
+                    }
+                }
+            }
+        }
+        break;
+
+    case WOM_CLOSE:
+    case WOM_OPEN:
+        break;
+
+    default:
+        dolog ("unknown wave out callback msg %x\n", msg);
+    }
+}
+
+static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    int i;
+    int err;
+    MMRESULT mr;
+    WAVEFORMATEX wfx;
+    WaveVoiceOut *wave;
+
+    wave = (WaveVoiceOut *) hw;
+
+    InitializeCriticalSection (&wave->crit_sect);
+
+    err = waveformat_from_audio_settings (&wfx, as);
+    if (err) {
+        goto err0;
+    }
+
+    mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
+                      (DWORD_PTR) winwave_callback_out,
+                      (DWORD_PTR) wave, CALLBACK_FUNCTION);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveOutOpen");
+        goto err1;
+    }
+
+    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
+                               sizeof (*wave->hdrs));
+    if (!wave->hdrs) {
+        goto err2;
+    }
+
+    audio_pcm_init_info (&hw->info, as);
+    hw->samples = conf.dac_samples * conf.dac_headers;
+    wave->avail = hw->samples;
+
+    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
+                                  conf.dac_headers << hw->info.shift);
+    if (!wave->pcm_buf) {
+        goto err3;
+    }
+
+    for (i = 0; i < conf.dac_headers; ++i) {
+        WAVEHDR *h = &wave->hdrs[i];
+
+        h->dwUser = 0;
+        h->dwBufferLength = conf.dac_samples << hw->info.shift;
+        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
+        h->dwFlags = 0;
+
+        mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
+            goto err4;
+        }
+    }
+
+    return 0;
+
+ err4:
+    qemu_free (wave->pcm_buf);
+ err3:
+    qemu_free (wave->hdrs);
+ err2:
+    winwave_anal_close_out (wave);
+ err1:
+ err0:
+    return -1;
+}
+
+static int winwave_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int winwave_run_out (HWVoiceOut *hw, int live)
+{
+    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
+    int decr;
+    int doreset;
+
+    EnterCriticalSection (&wave->crit_sect);
+    {
+        decr = audio_MIN (live, wave->avail);
+        decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
+        wave->pending += decr;
+        wave->avail -= decr;
+    }
+    LeaveCriticalSection (&wave->crit_sect);
+
+    doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
+    if (doreset && !ResetEvent (wave->event)) {
+        dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
+    }
+
+    while (wave->pending >= conf.dac_samples) {
+        MMRESULT mr;
+        WAVEHDR *h = &wave->hdrs[wave->curhdr];
+
+        h->dwUser = 0;
+        mr = waveOutWrite (wave->hwo, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
+            break;
+        }
+
+        wave->pending -= conf.dac_samples;
+        wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
+    }
+
+    return decr;
+}
+
+static void winwave_poll (void *opaque)
+{
+    (void) opaque;
+    audio_run ("winwave_poll");
+}
+
+static void winwave_fini_out (HWVoiceOut *hw)
+{
+    int i;
+    MMRESULT mr;
+    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
+
+    mr = waveOutReset (wave->hwo);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveOutReset");
+    }
+
+    for (i = 0; i < conf.dac_headers; ++i) {
+        mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
+                                     sizeof (wave->hdrs[i]));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
+        }
+    }
+
+    winwave_anal_close_out (wave);
+
+    if (wave->event) {
+        qemu_del_wait_object (wave->event, winwave_poll, wave);
+        if (!CloseHandle (wave->event)) {
+            dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
+        }
+        wave->event = NULL;
+    }
+
+    qemu_free (wave->pcm_buf);
+    wave->pcm_buf = NULL;
+
+    qemu_free (wave->hdrs);
+    wave->hdrs = NULL;
+}
+
+static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    MMRESULT mr;
+    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            if (poll_mode && !wave->event) {
+                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
+                if (!wave->event) {
+                    dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
+                           GetLastError ());
+                }
+            }
+
+            if (wave->event) {
+                int ret;
+
+                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
+                hw->poll_mode = (ret == 0);
+            }
+            else {
+                hw->poll_mode = 0;
+            }
+            if (wave->paused) {
+                mr = waveOutRestart (wave->hwo);
+                if (mr != MMSYSERR_NOERROR) {
+                    winwave_logerr (mr, "waveOutRestart");
+                }
+                wave->paused = 0;
+            }
+        }
+        return 0;
+
+    case VOICE_DISABLE:
+        if (!wave->paused) {
+            mr = waveOutPause (wave->hwo);
+            if (mr != MMSYSERR_NOERROR) {
+                winwave_logerr (mr, "waveOutPause");
+            }
+            else {
+                wave->paused = 1;
+            }
+        }
+        if (wave->event) {
+            qemu_del_wait_object (wave->event, winwave_poll, wave);
+        }
+        return 0;
+    }
+    return -1;
+}
+
+static void winwave_anal_close_in (WaveVoiceIn *wave)
+{
+    MMRESULT mr;
+
+    mr = waveInClose (wave->hwi);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveInClose");
+    }
+    wave->hwi = NULL;
+}
+
+static void CALLBACK winwave_callback_in (
+    HWAVEIN *hwi,
+    UINT msg,
+    DWORD_PTR dwInstance,
+    DWORD_PTR dwParam1,
+    DWORD_PTR dwParam2
+    )
+{
+    WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
+
+    switch (msg) {
+    case WIM_DATA:
+        {
+            WAVEHDR *h = (WAVEHDR *) dwParam1;
+            if (!h->dwUser) {
+                h->dwUser = 1;
+                EnterCriticalSection (&wave->crit_sect);
+                {
+                    wave->avail += conf.adc_samples;
+                }
+                LeaveCriticalSection (&wave->crit_sect);
+                if (wave->hw.poll_mode) {
+                    if (!SetEvent (wave->event)) {
+                        dolog ("ADC SetEvent failed %lx\n", GetLastError ());
+                    }
+                }
+            }
+        }
+        break;
+
+    case WIM_CLOSE:
+    case WIM_OPEN:
+        break;
+
+    default:
+        dolog ("unknown wave in callback msg %x\n", msg);
+    }
+}
+
+static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
+{
+    int doreset;
+
+    doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
+    if (doreset && !ResetEvent (wave->event)) {
+        dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
+    }
+
+    while (samples >= conf.adc_samples) {
+        MMRESULT mr;
+        WAVEHDR *h = &wave->hdrs[wave->curhdr];
+
+        h->dwUser = 0;
+        mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
+        }
+        wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
+        samples -= conf.adc_samples;
+    }
+}
+
+static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
+{
+    int i;
+    int err;
+    MMRESULT mr;
+    WAVEFORMATEX wfx;
+    WaveVoiceIn *wave;
+
+    wave = (WaveVoiceIn *) hw;
+
+    InitializeCriticalSection (&wave->crit_sect);
+
+    err = waveformat_from_audio_settings (&wfx, as);
+    if (err) {
+        goto err0;
+    }
+
+    mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
+                     (DWORD_PTR) winwave_callback_in,
+                     (DWORD_PTR) wave, CALLBACK_FUNCTION);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveInOpen");
+        goto err1;
+    }
+
+    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
+                               sizeof (*wave->hdrs));
+    if (!wave->hdrs) {
+        goto err2;
+    }
+
+    audio_pcm_init_info (&hw->info, as);
+    hw->samples = conf.adc_samples * conf.adc_headers;
+    wave->avail = 0;
+
+    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
+                                  conf.adc_headers << hw->info.shift);
+    if (!wave->pcm_buf) {
+        goto err3;
+    }
+
+    for (i = 0; i < conf.adc_headers; ++i) {
+        WAVEHDR *h = &wave->hdrs[i];
+
+        h->dwUser = 0;
+        h->dwBufferLength = conf.adc_samples << hw->info.shift;
+        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
+        h->dwFlags = 0;
+
+        mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
+            goto err4;
+        }
+    }
+
+    wave->paused = 1;
+    winwave_add_buffers (wave, hw->samples);
+    return 0;
+
+ err4:
+    qemu_free (wave->pcm_buf);
+ err3:
+    qemu_free (wave->hdrs);
+ err2:
+    winwave_anal_close_in (wave);
+ err1:
+ err0:
+    return -1;
+}
+
+static void winwave_fini_in (HWVoiceIn *hw)
+{
+    int i;
+    MMRESULT mr;
+    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
+
+    mr = waveInReset (wave->hwi);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveInReset");
+    }
+
+    for (i = 0; i < conf.adc_headers; ++i) {
+        mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
+                                     sizeof (wave->hdrs[i]));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
+        }
+    }
+
+    winwave_anal_close_in (wave);
+
+    if (wave->event) {
+        qemu_del_wait_object (wave->event, winwave_poll, wave);
+        if (!CloseHandle (wave->event)) {
+            dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
+        }
+        wave->event = NULL;
+    }
+
+    qemu_free (wave->pcm_buf);
+    wave->pcm_buf = NULL;
+
+    qemu_free (wave->hdrs);
+    wave->hdrs = NULL;
+}
+
+static int winwave_run_in (HWVoiceIn *hw)
+{
+    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    int decr, ret;
+
+    if (!dead) {
+        return 0;
+    }
+
+    EnterCriticalSection (&wave->crit_sect);
+    {
+        decr = audio_MIN (dead, wave->avail);
+        wave->avail -= decr;
+    }
+    LeaveCriticalSection (&wave->crit_sect);
+
+    ret = decr;
+    while (decr) {
+        int left = hw->samples - hw->wpos;
+        int conv = audio_MIN (left, decr);
+        hw->conv (hw->conv_buf + hw->wpos,
+                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
+                  conv);
+
+        wave->rpos = (wave->rpos + conv) % hw->samples;
+        hw->wpos = (hw->wpos + conv) % hw->samples;
+        decr -= conv;
+    }
+
+    winwave_add_buffers (wave, ret);
+    return ret;
+}
+
+static int winwave_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    MMRESULT mr;
+    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        {
+            va_list ap;
+            int poll_mode;
+
+            va_start (ap, cmd);
+            poll_mode = va_arg (ap, int);
+            va_end (ap);
+
+            if (poll_mode && !wave->event) {
+                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
+                if (!wave->event) {
+                    dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
+                           GetLastError ());
+                }
+            }
+
+            if (wave->event) {
+                int ret;
+
+                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
+                hw->poll_mode = (ret == 0);
+            }
+            else {
+                hw->poll_mode = 0;
+            }
+            if (wave->paused) {
+                mr = waveInStart (wave->hwi);
+                if (mr != MMSYSERR_NOERROR) {
+                    winwave_logerr (mr, "waveInStart");
+                }
+                wave->paused = 0;
+            }
+        }
+        return 0;
+
+    case VOICE_DISABLE:
+        if (!wave->paused) {
+            mr = waveInStop (wave->hwi);
+            if (mr != MMSYSERR_NOERROR) {
+                winwave_logerr (mr, "waveInStop");
+            }
+            else {
+                wave->paused = 1;
+            }
+        }
+        if (wave->event) {
+            qemu_del_wait_object (wave->event, winwave_poll, wave);
+        }
+        return 0;
+    }
+    return 0;
+}
+
+static void *winwave_audio_init (void)
+{
+    return &conf;
+}
+
+static void winwave_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option winwave_options[] = {
+    {
+        .name        = "DAC_HEADERS",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.dac_headers,
+        .descr       = "DAC number of headers",
+    },
+    {
+        .name        = "DAC_SAMPLES",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.dac_samples,
+        .descr       = "DAC number of samples per header",
+    },
+    {
+        .name        = "ADC_HEADERS",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.adc_headers,
+        .descr       = "ADC number of headers",
+    },
+    {
+        .name        = "ADC_SAMPLES",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.adc_samples,
+        .descr       = "ADC number of samples per header",
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops winwave_pcm_ops = {
+    .init_out = winwave_init_out,
+    .fini_out = winwave_fini_out,
+    .run_out  = winwave_run_out,
+    .write    = winwave_write,
+    .ctl_out  = winwave_ctl_out,
+    .init_in  = winwave_init_in,
+    .fini_in  = winwave_fini_in,
+    .run_in   = winwave_run_in,
+    .read     = winwave_read,
+    .ctl_in   = winwave_ctl_in
+};
+
+struct audio_driver winwave_audio_driver = {
+    .name           = "winwave",
+    .descr          = "Windows Waveform Audio http://msdn.microsoft.com",
+    .options        = winwave_options,
+    .init           = winwave_audio_init,
+    .fini           = winwave_audio_fini,
+    .pcm_ops        = &winwave_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = INT_MAX,
+    .voice_size_out = sizeof (WaveVoiceOut),
+    .voice_size_in  = sizeof (WaveVoiceIn)
+};
diff --git a/qemu-0.15.x/balloon.c b/qemu-0.15.x/balloon.c
new file mode 100644
index 0000000..f56fdc1
--- /dev/null
+++ b/qemu-0.15.x/balloon.c
@@ -0,0 +1,164 @@
+/*
+ * Generic Balloon handlers and management
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah at redhat.com>
+ *
+ * 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 "monitor.h"
+#include "qjson.h"
+#include "qint.h"
+#include "cpu-common.h"
+#include "kvm.h"
+#include "balloon.h"
+#include "trace.h"
+
+static QEMUBalloonEvent *balloon_event_fn;
+static QEMUBalloonStatus *balloon_stat_fn;
+static void *balloon_opaque;
+
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                             QEMUBalloonStatus *stat_func, void *opaque)
+{
+    if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
+        /* We're already registered one balloon handler.  How many can
+         * a guest really have?
+         */
+        error_report("Another balloon device already registered");
+        return -1;
+    }
+    balloon_event_fn = event_func;
+    balloon_stat_fn = stat_func;
+    balloon_opaque = opaque;
+    return 0;
+}
+
+static int qemu_balloon(ram_addr_t target)
+{
+    if (!balloon_event_fn) {
+        return 0;
+    }
+    trace_balloon_event(balloon_opaque, target);
+    balloon_event_fn(balloon_opaque, target);
+    return 1;
+}
+
+static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
+{
+    if (!balloon_stat_fn) {
+        return 0;
+    }
+    balloon_stat_fn(balloon_opaque, cb, opaque);
+    return 1;
+}
+
+static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
+{
+    Monitor *mon = opaque;
+
+    if (strcmp(key, "actual")) {
+        monitor_printf(mon, ",%s=%" PRId64, key,
+                       qint_get_int(qobject_to_qint(obj)));
+    }
+}
+
+void monitor_print_balloon(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+    if (!qdict_haskey(qdict, "actual")) {
+        return;
+    }
+    monitor_printf(mon, "balloon: actual=%" PRId64,
+                   qdict_get_int(qdict, "actual") >> 20);
+    qdict_iter(qdict, print_balloon_stat, mon);
+    monitor_printf(mon, "\n");
+}
+
+/**
+ * do_info_balloon(): Balloon information
+ *
+ * Make an asynchronous request for balloon info.  When the request completes
+ * a QDict will be returned according to the following specification:
+ *
+ * - "actual": current balloon value in bytes
+ * The following fields may or may not be present:
+ * - "mem_swapped_in": Amount of memory swapped in (bytes)
+ * - "mem_swapped_out": Amount of memory swapped out (bytes)
+ * - "major_page_faults": Number of major faults
+ * - "minor_page_faults": Number of minor faults
+ * - "free_mem": Total amount of free and unused memory (bytes)
+ * - "total_mem": Total amount of available memory (bytes)
+ *
+ * Example:
+ *
+ * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
+ *   "major_page_faults": 142, "minor_page_faults": 239245,
+ *   "free_mem": 1014185984, "total_mem": 1044668416 }
+ */
+int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
+{
+    int ret;
+
+    if (kvm_enabled() && !kvm_has_sync_mmu()) {
+        qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+        return -1;
+    }
+
+    ret = qemu_balloon_status(cb, opaque);
+    if (!ret) {
+        qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * do_balloon(): Request VM to change its memory allocation
+ */
+int do_balloon(Monitor *mon, const QDict *params,
+	       MonitorCompletion cb, void *opaque)
+{
+    int64_t target;
+    int ret;
+
+    if (kvm_enabled() && !kvm_has_sync_mmu()) {
+        qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+        return -1;
+    }
+
+    target = qdict_get_int(params, "value");
+    if (target <= 0) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
+        return -1;
+    }
+    ret = qemu_balloon(target);
+    if (ret == 0) {
+        qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
+        return -1;
+    }
+
+    cb(opaque, NULL);
+    return 0;
+}
diff --git a/qemu-0.15.x/balloon.h b/qemu-0.15.x/balloon.h
new file mode 100644
index 0000000..3df14e6
--- /dev/null
+++ b/qemu-0.15.x/balloon.h
@@ -0,0 +1,31 @@
+/*
+ * Balloon
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_BALLOON_H
+#define _QEMU_BALLOON_H
+
+#include "monitor.h"
+
+typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
+typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
+                                 void *cb_data);
+
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+			     QEMUBalloonStatus *stat_func, void *opaque);
+
+void monitor_print_balloon(Monitor *mon, const QObject *data);
+int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
+int do_balloon(Monitor *mon, const QDict *params,
+               MonitorCompletion cb, void *opaque);
+
+#endif
diff --git a/qemu-0.15.x/bitmap.c b/qemu-0.15.x/bitmap.c
new file mode 100644
index 0000000..a62c8ba
--- /dev/null
+++ b/qemu-0.15.x/bitmap.c
@@ -0,0 +1,256 @@
+/*
+ * Bitmap Module
+ *
+ * Stolen from linux/src/lib/bitmap.c
+ *
+ * Copyright (C) 2010 Corentin Chary
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.
+ */
+
+#include "bitops.h"
+#include "bitmap.h"
+
+/*
+ * bitmaps provide an array of bits, implemented using an an
+ * array of unsigned longs.  The number of valid bits in a
+ * given bitmap does _not_ need to be an exact multiple of
+ * BITS_PER_LONG.
+ *
+ * The possible unused bits in the last, partially used word
+ * of a bitmap are 'don't care'.  The implementation makes
+ * no particular effort to keep them zero.  It ensures that
+ * their value will not affect the results of any operation.
+ * The bitmap operations that return Boolean (bitmap_empty,
+ * for example) or scalar (bitmap_weight, for example) results
+ * carefully filter out these unused bits from impacting their
+ * results.
+ *
+ * These operations actually hold to a slightly stronger rule:
+ * if you don't input any bitmaps to these ops that have some
+ * unused bits set, then they won't output any set unused bits
+ * in output bitmaps.
+ *
+ * The byte ordering of bitmaps is more natural on little
+ * endian architectures.
+ */
+
+int slow_bitmap_empty(const unsigned long *bitmap, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap[k]) {
+            return 0;
+        }
+    }
+    if (bits % BITS_PER_LONG) {
+        if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int slow_bitmap_full(const unsigned long *bitmap, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (~bitmap[k]) {
+            return 0;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int slow_bitmap_equal(const unsigned long *bitmap1,
+                      const unsigned long *bitmap2, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap1[k] != bitmap2[k]) {
+            return 0;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
+                            int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        dst[k] = ~src[k];
+    }
+
+    if (bits % BITS_PER_LONG) {
+        dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
+    }
+}
+
+int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+    unsigned long result = 0;
+
+    for (k = 0; k < nr; k++) {
+        result |= (dst[k] = bitmap1[k] & bitmap2[k]);
+    }
+    return result != 0;
+}
+
+void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+
+    for (k = 0; k < nr; k++) {
+        dst[k] = bitmap1[k] | bitmap2[k];
+    }
+}
+
+void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                     const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+
+    for (k = 0; k < nr; k++) {
+        dst[k] = bitmap1[k] ^ bitmap2[k];
+    }
+}
+
+int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits)
+{
+    int k;
+    int nr = BITS_TO_LONGS(bits);
+    unsigned long result = 0;
+
+    for (k = 0; k < nr; k++) {
+        result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
+    }
+    return result != 0;
+}
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
+
+void bitmap_set(unsigned long *map, int start, int nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const int size = start + nr;
+    int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+    while (nr - bits_to_set >= 0) {
+        *p |= mask_to_set;
+        nr -= bits_to_set;
+        bits_to_set = BITS_PER_LONG;
+        mask_to_set = ~0UL;
+        p++;
+    }
+    if (nr) {
+        mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+        *p |= mask_to_set;
+    }
+}
+
+void bitmap_clear(unsigned long *map, int start, int nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const int size = start + nr;
+    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+
+    while (nr - bits_to_clear >= 0) {
+        *p &= ~mask_to_clear;
+        nr -= bits_to_clear;
+        bits_to_clear = BITS_PER_LONG;
+        mask_to_clear = ~0UL;
+        p++;
+    }
+    if (nr) {
+        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+        *p &= ~mask_to_clear;
+    }
+}
+
+#define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
+
+/**
+ * bitmap_find_next_zero_area - find a contiguous aligned zero area
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @align_mask: Alignment mask for zero area
+ *
+ * The @align_mask should be one less than a power of 2; the effect is that
+ * the bit offset of all zero areas this function finds is multiples of that
+ * power of 2. A @align_mask of 0 means no alignment is required.
+ */
+unsigned long bitmap_find_next_zero_area(unsigned long *map,
+					 unsigned long size,
+					 unsigned long start,
+					 unsigned int nr,
+					 unsigned long align_mask)
+{
+    unsigned long index, end, i;
+again:
+    index = find_next_zero_bit(map, size, start);
+
+    /* Align allocation */
+    index = ALIGN_MASK(index, align_mask);
+
+    end = index + nr;
+    if (end > size) {
+        return end;
+    }
+    i = find_next_bit(map, end, index);
+    if (i < end) {
+        start = i + 1;
+        goto again;
+    }
+    return index;
+}
+
+int slow_bitmap_intersects(const unsigned long *bitmap1,
+                           const unsigned long *bitmap2, int bits)
+{
+    int k, lim = bits/BITS_PER_LONG;
+
+    for (k = 0; k < lim; ++k) {
+        if (bitmap1[k] & bitmap2[k]) {
+            return 1;
+        }
+    }
+
+    if (bits % BITS_PER_LONG) {
+        if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
+            return 1;
+        }
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/bitmap.h b/qemu-0.15.x/bitmap.h
new file mode 100644
index 0000000..efd5d3a
--- /dev/null
+++ b/qemu-0.15.x/bitmap.h
@@ -0,0 +1,222 @@
+/*
+ * Bitmap Module
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#include "qemu-common.h"
+#include "bitops.h"
+
+/*
+ * The available bitmap operations and their rough meaning in the
+ * case that the bitmap is a single unsigned long are thus:
+ *
+ * Note that nbits should be always a compile time evaluable constant.
+ * Otherwise many inlines will generate horrible code.
+ *
+ * bitmap_zero(dst, nbits)			*dst = 0UL
+ * bitmap_fill(dst, nbits)			*dst = ~0UL
+ * bitmap_copy(dst, src, nbits)			*dst = *src
+ * bitmap_and(dst, src1, src2, nbits)		*dst = *src1 & *src2
+ * bitmap_or(dst, src1, src2, nbits)		*dst = *src1 | *src2
+ * bitmap_xor(dst, src1, src2, nbits)		*dst = *src1 ^ *src2
+ * bitmap_andnot(dst, src1, src2, nbits)	*dst = *src1 & ~(*src2)
+ * bitmap_complement(dst, src, nbits)		*dst = ~(*src)
+ * bitmap_equal(src1, src2, nbits)		Are *src1 and *src2 equal?
+ * bitmap_intersects(src1, src2, nbits) 	Do *src1 and *src2 overlap?
+ * bitmap_empty(src, nbits)			Are all bits zero in *src?
+ * bitmap_full(src, nbits)			Are all bits set in *src?
+ * bitmap_set(dst, pos, nbits)			Set specified bit area
+ * bitmap_clear(dst, pos, nbits)		Clear specified bit area
+ * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
+ */
+
+/*
+ * Also the following operations apply to bitmaps.
+ *
+ * set_bit(bit, addr)			*addr |= bit
+ * clear_bit(bit, addr)			*addr &= ~bit
+ * change_bit(bit, addr)		*addr ^= bit
+ * test_bit(bit, addr)			Is bit set in *addr?
+ * test_and_set_bit(bit, addr)		Set bit and return old value
+ * test_and_clear_bit(bit, addr)	Clear bit and return old value
+ * test_and_change_bit(bit, addr)	Change bit and return old value
+ * find_first_zero_bit(addr, nbits)	Position first zero bit in *addr
+ * find_first_bit(addr, nbits)		Position first set bit in *addr
+ * find_next_zero_bit(addr, nbits, bit)	Position next zero bit in *addr >= bit
+ * find_next_bit(addr, nbits, bit)	Position next set bit in *addr >= bit
+ */
+
+#define BITMAP_LAST_WORD_MASK(nbits)                                    \
+    (                                                                   \
+        ((nbits) % BITS_PER_LONG) ?                                     \
+        (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL                       \
+        )
+
+#define DECLARE_BITMAP(name,bits)                  \
+	unsigned long name[BITS_TO_LONGS(bits)]
+
+#define small_nbits(nbits)                      \
+	((nbits) <= BITS_PER_LONG)
+
+int slow_bitmap_empty(const unsigned long *bitmap, int bits);
+int slow_bitmap_full(const unsigned long *bitmap, int bits);
+int slow_bitmap_equal(const unsigned long *bitmap1,
+                   const unsigned long *bitmap2, int bits);
+void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
+                         int bits);
+void slow_bitmap_shift_right(unsigned long *dst,
+                          const unsigned long *src, int shift, int bits);
+void slow_bitmap_shift_left(unsigned long *dst,
+                         const unsigned long *src, int shift, int bits);
+int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                 const unsigned long *bitmap2, int bits);
+void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                 const unsigned long *bitmap2, int bits);
+void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                  const unsigned long *bitmap2, int bits);
+int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                    const unsigned long *bitmap2, int bits);
+int slow_bitmap_intersects(const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+
+static inline unsigned long *bitmap_new(int nbits)
+{
+    int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+    return qemu_mallocz(len);
+}
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = 0UL;
+    } else {
+        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+        memset(dst, 0, len);
+    }
+}
+
+static inline void bitmap_fill(unsigned long *dst, int nbits)
+{
+    size_t nlongs = BITS_TO_LONGS(nbits);
+    if (!small_nbits(nbits)) {
+        int len = (nlongs - 1) * sizeof(unsigned long);
+        memset(dst, 0xff,  len);
+    }
+    dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
+                               int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src;
+    } else {
+        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+        memcpy(dst, src, len);
+    }
+}
+
+static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
+                             const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return (*dst = *src1 & *src2) != 0;
+    }
+    return slow_bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src1 | *src2;
+    } else {
+        slow_bitmap_or(dst, src1, src2, nbits);
+    }
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = *src1 ^ *src2;
+    } else {
+        slow_bitmap_xor(dst, src1, src2, nbits);
+    }
+}
+
+static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return (*dst = *src1 & ~(*src2)) != 0;
+    }
+    return slow_bitmap_andnot(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
+			int nbits)
+{
+    if (small_nbits(nbits)) {
+        *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
+    } else {
+        slow_bitmap_complement(dst, src, nbits);
+    }
+}
+
+static inline int bitmap_equal(const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_equal(src1, src2, nbits);
+    }
+}
+
+static inline int bitmap_empty(const unsigned long *src, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_empty(src, nbits);
+    }
+}
+
+static inline int bitmap_full(const unsigned long *src, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+    } else {
+        return slow_bitmap_full(src, nbits);
+    }
+}
+
+static inline int bitmap_intersects(const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+    if (small_nbits(nbits)) {
+        return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+    } else {
+        return slow_bitmap_intersects(src1, src2, nbits);
+    }
+}
+
+void bitmap_set(unsigned long *map, int i, int len);
+void bitmap_clear(unsigned long *map, int start, int nr);
+unsigned long bitmap_find_next_zero_area(unsigned long *map,
+					 unsigned long size,
+					 unsigned long start,
+					 unsigned int nr,
+					 unsigned long align_mask);
+
+#endif /* BITMAP_H */
diff --git a/qemu-0.15.x/bitops.c b/qemu-0.15.x/bitops.c
new file mode 100644
index 0000000..d9de71f
--- /dev/null
+++ b/qemu-0.15.x/bitops.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ * Copyright (C) 2008 IBM Corporation
+ * Written by Rusty Russell <rusty at rustcorp.com.au>
+ * (Inspired by David Howell's find_next_bit implementation)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "bitops.h"
+
+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/*
+ * Find the next set bit in a memory region.
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+			    unsigned long offset)
+{
+    const unsigned long *p = addr + BITOP_WORD(offset);
+    unsigned long result = offset & ~(BITS_PER_LONG-1);
+    unsigned long tmp;
+
+    if (offset >= size) {
+        return size;
+    }
+    size -= result;
+    offset %= BITS_PER_LONG;
+    if (offset) {
+        tmp = *(p++);
+        tmp &= (~0UL << offset);
+        if (size < BITS_PER_LONG) {
+            goto found_first;
+        }
+        if (tmp) {
+            goto found_middle;
+        }
+        size -= BITS_PER_LONG;
+        result += BITS_PER_LONG;
+    }
+    while (size & ~(BITS_PER_LONG-1)) {
+        if ((tmp = *(p++))) {
+            goto found_middle;
+        }
+        result += BITS_PER_LONG;
+        size -= BITS_PER_LONG;
+    }
+    if (!size) {
+        return result;
+    }
+    tmp = *p;
+
+found_first:
+    tmp &= (~0UL >> (BITS_PER_LONG - size));
+    if (tmp == 0UL) {		/* Are any bits set? */
+        return result + size;	/* Nope. */
+    }
+found_middle:
+    return result + bitops_ffsl(tmp);
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+				 unsigned long offset)
+{
+    const unsigned long *p = addr + BITOP_WORD(offset);
+    unsigned long result = offset & ~(BITS_PER_LONG-1);
+    unsigned long tmp;
+
+    if (offset >= size) {
+        return size;
+    }
+    size -= result;
+    offset %= BITS_PER_LONG;
+    if (offset) {
+        tmp = *(p++);
+        tmp |= ~0UL >> (BITS_PER_LONG - offset);
+        if (size < BITS_PER_LONG) {
+            goto found_first;
+        }
+        if (~tmp) {
+            goto found_middle;
+        }
+        size -= BITS_PER_LONG;
+        result += BITS_PER_LONG;
+    }
+    while (size & ~(BITS_PER_LONG-1)) {
+        if (~(tmp = *(p++))) {
+            goto found_middle;
+        }
+        result += BITS_PER_LONG;
+        size -= BITS_PER_LONG;
+    }
+    if (!size) {
+        return result;
+    }
+    tmp = *p;
+
+found_first:
+    tmp |= ~0UL << size;
+    if (tmp == ~0UL) {	/* Are any bits zero? */
+        return result + size;	/* Nope. */
+    }
+found_middle:
+    return result + ffz(tmp);
+}
+
+unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
+{
+    unsigned long words;
+    unsigned long tmp;
+
+    /* Start at final word. */
+    words = size / BITS_PER_LONG;
+
+    /* Partial final word? */
+    if (size & (BITS_PER_LONG-1)) {
+        tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
+                                       - (size & (BITS_PER_LONG-1)))));
+        if (tmp) {
+            goto found;
+        }
+    }
+
+    while (words) {
+        tmp = addr[--words];
+        if (tmp) {
+        found:
+            return words * BITS_PER_LONG + bitops_flsl(tmp);
+        }
+    }
+
+    /* Not found */
+    return size;
+}
diff --git a/qemu-0.15.x/bitops.h b/qemu-0.15.x/bitops.h
new file mode 100644
index 0000000..07d1a06
--- /dev/null
+++ b/qemu-0.15.x/bitops.h
@@ -0,0 +1,272 @@
+/*
+ * Bitops Module
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include "qemu-common.h"
+
+#define BITS_PER_BYTE           CHAR_BIT
+#define BITS_PER_LONG           (sizeof (unsigned long) * BITS_PER_BYTE)
+
+#define BIT(nr)			(1UL << (nr))
+#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+
+/**
+ * bitops_ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static unsigned long bitops_ffsl(unsigned long word)
+{
+	int num = 0;
+
+#if LONG_MAX > 0x7FFFFFFF
+	if ((word & 0xffffffff) == 0) {
+		num += 32;
+		word >>= 32;
+	}
+#endif
+	if ((word & 0xffff) == 0) {
+		num += 16;
+		word >>= 16;
+	}
+	if ((word & 0xff) == 0) {
+		num += 8;
+		word >>= 8;
+	}
+	if ((word & 0xf) == 0) {
+		num += 4;
+		word >>= 4;
+	}
+	if ((word & 0x3) == 0) {
+		num += 2;
+		word >>= 2;
+	}
+	if ((word & 0x1) == 0) {
+		num += 1;
+        }
+	return num;
+}
+
+/**
+ * bitops_fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long bitops_flsl(unsigned long word)
+{
+	int num = BITS_PER_LONG - 1;
+
+#if LONG_MAX > 0x7FFFFFFF
+	if (!(word & (~0ul << 32))) {
+		num -= 32;
+		word <<= 32;
+	}
+#endif
+	if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
+		num -= 16;
+		word <<= 16;
+	}
+	if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
+		num -= 8;
+		word <<= 8;
+	}
+	if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
+		num -= 4;
+		word <<= 4;
+	}
+	if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
+		num -= 2;
+
+		word <<= 2;
+	}
+	if (!(word & (~0ul << (BITS_PER_LONG-1))))
+		num -= 1;
+	return num;
+}
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+    return bitops_ffsl(~word);
+}
+
+/**
+ * set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static inline void set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p  |= mask;
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ */
+static inline void clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p &= ~mask;
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ */
+static inline void change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p ^= mask;
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old | mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ */
+static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old & ~mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ */
+static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+/**
+ * find_last_bit - find the last set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit, or size.
+ */
+unsigned long find_last_bit(const unsigned long *addr,
+                            unsigned long size);
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+unsigned long find_next_bit(const unsigned long *addr,
+				   unsigned long size, unsigned long offset);
+
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+
+unsigned long find_next_zero_bit(const unsigned long *addr,
+                                 unsigned long size,
+                                 unsigned long offset);
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit.
+ */
+static inline unsigned long find_first_bit(const unsigned long *addr,
+                                           unsigned long size)
+{
+    return find_next_bit(addr, size, 0);
+}
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first cleared bit.
+ */
+static inline unsigned long find_first_zero_bit(const unsigned long *addr,
+                                                unsigned long size)
+{
+    return find_next_zero_bit(addr, size, 0);
+}
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+    unsigned long count;
+
+    for (count = 0; w; w >>= 1) {
+        count += w & 1;
+    }
+    return count;
+}
+
+#endif
diff --git a/qemu-0.15.x/block-migration.c b/qemu-0.15.x/block-migration.c
new file mode 100644
index 0000000..0936c7d
--- /dev/null
+++ b/qemu-0.15.x/block-migration.c
@@ -0,0 +1,731 @@
+/*
+ * QEMU live block migration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Liran Schour   <lirans at il.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "hw/hw.h"
+#include "qemu-queue.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "block-migration.h"
+#include "migration.h"
+#include "blockdev.h"
+#include <assert.h>
+
+#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
+
+#define BLK_MIG_FLAG_DEVICE_BLOCK       0x01
+#define BLK_MIG_FLAG_EOS                0x02
+#define BLK_MIG_FLAG_PROGRESS           0x04
+
+#define MAX_IS_ALLOCATED_SEARCH 65536
+
+//#define DEBUG_BLK_MIGRATION
+
+#ifdef DEBUG_BLK_MIGRATION
+#define DPRINTF(fmt, ...) \
+    do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef struct BlkMigDevState {
+    BlockDriverState *bs;
+    int bulk_completed;
+    int shared_base;
+    int64_t cur_sector;
+    int64_t cur_dirty;
+    int64_t completed_sectors;
+    int64_t total_sectors;
+    int64_t dirty;
+    QSIMPLEQ_ENTRY(BlkMigDevState) entry;
+    unsigned long *aio_bitmap;
+} BlkMigDevState;
+
+typedef struct BlkMigBlock {
+    uint8_t *buf;
+    BlkMigDevState *bmds;
+    int64_t sector;
+    int nr_sectors;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    BlockDriverAIOCB *aiocb;
+    int ret;
+    QSIMPLEQ_ENTRY(BlkMigBlock) entry;
+} BlkMigBlock;
+
+typedef struct BlkMigState {
+    int blk_enable;
+    int shared_base;
+    QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
+    QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
+    int submitted;
+    int read_done;
+    int transferred;
+    int64_t total_sector_sum;
+    int prev_progress;
+    int bulk_completed;
+    long double total_time;
+    long double prev_time_offset;
+    int reads;
+} BlkMigState;
+
+static BlkMigState block_mig_state;
+
+static void blk_send(QEMUFile *f, BlkMigBlock * blk)
+{
+    int len;
+
+    /* sector number and flags */
+    qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS)
+                     | BLK_MIG_FLAG_DEVICE_BLOCK);
+
+    /* device name */
+    len = strlen(blk->bmds->bs->device_name);
+    qemu_put_byte(f, len);
+    qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
+
+    qemu_put_buffer(f, blk->buf, BLOCK_SIZE);
+}
+
+int blk_mig_active(void)
+{
+    return !QSIMPLEQ_EMPTY(&block_mig_state.bmds_list);
+}
+
+uint64_t blk_mig_bytes_transferred(void)
+{
+    BlkMigDevState *bmds;
+    uint64_t sum = 0;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        sum += bmds->completed_sectors;
+    }
+    return sum << BDRV_SECTOR_BITS;
+}
+
+uint64_t blk_mig_bytes_remaining(void)
+{
+    return blk_mig_bytes_total() - blk_mig_bytes_transferred();
+}
+
+uint64_t blk_mig_bytes_total(void)
+{
+    BlkMigDevState *bmds;
+    uint64_t sum = 0;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        sum += bmds->total_sectors;
+    }
+    return sum << BDRV_SECTOR_BITS;
+}
+
+static inline long double compute_read_bwidth(void)
+{
+    assert(block_mig_state.total_time != 0);
+    return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
+}
+
+static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
+{
+    int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
+        return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+            (1UL << (chunk % (sizeof(unsigned long) * 8))));
+    } else {
+        return 0;
+    }
+}
+
+static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
+                             int nb_sectors, int set)
+{
+    int64_t start, end;
+    unsigned long val, idx, bit;
+
+    start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
+    end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    for (; start <= end; start++) {
+        idx = start / (sizeof(unsigned long) * 8);
+        bit = start % (sizeof(unsigned long) * 8);
+        val = bmds->aio_bitmap[idx];
+        if (set) {
+            val |= 1UL << bit;
+        } else {
+            val &= ~(1UL << bit);
+        }
+        bmds->aio_bitmap[idx] = val;
+    }
+}
+
+static void alloc_aio_bitmap(BlkMigDevState *bmds)
+{
+    BlockDriverState *bs = bmds->bs;
+    int64_t bitmap_size;
+
+    bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
+            BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+    bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
+
+    bmds->aio_bitmap = qemu_mallocz(bitmap_size);
+}
+
+static void blk_mig_read_cb(void *opaque, int ret)
+{
+    long double curr_time = qemu_get_clock_ns(rt_clock);
+    BlkMigBlock *blk = opaque;
+
+    blk->ret = ret;
+
+    block_mig_state.reads++;
+    block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset);
+    block_mig_state.prev_time_offset = curr_time;
+
+    QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
+    bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
+
+    block_mig_state.submitted--;
+    block_mig_state.read_done++;
+    assert(block_mig_state.submitted >= 0);
+}
+
+static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
+                                BlkMigDevState *bmds)
+{
+    int64_t total_sectors = bmds->total_sectors;
+    int64_t cur_sector = bmds->cur_sector;
+    BlockDriverState *bs = bmds->bs;
+    BlkMigBlock *blk;
+    int nr_sectors;
+
+    if (bmds->shared_base) {
+        while (cur_sector < total_sectors &&
+               !bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH,
+                                  &nr_sectors)) {
+            cur_sector += nr_sectors;
+        }
+    }
+
+    if (cur_sector >= total_sectors) {
+        bmds->cur_sector = bmds->completed_sectors = total_sectors;
+        return 1;
+    }
+
+    bmds->completed_sectors = cur_sector;
+
+    cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1);
+
+    /* we are going to transfer a full block even if it is not allocated */
+    nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
+        nr_sectors = total_sectors - cur_sector;
+    }
+
+    blk = qemu_malloc(sizeof(BlkMigBlock));
+    blk->buf = qemu_malloc(BLOCK_SIZE);
+    blk->bmds = bmds;
+    blk->sector = cur_sector;
+    blk->nr_sectors = nr_sectors;
+
+    blk->iov.iov_base = blk->buf;
+    blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+    qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+
+    if (block_mig_state.submitted == 0) {
+        block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+    }
+
+    blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+                                nr_sectors, blk_mig_read_cb, blk);
+    if (!blk->aiocb) {
+        goto error;
+    }
+    block_mig_state.submitted++;
+
+    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
+    bmds->cur_sector = cur_sector + nr_sectors;
+
+    return (bmds->cur_sector >= total_sectors);
+
+error:
+    monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
+    qemu_file_set_error(f);
+    qemu_free(blk->buf);
+    qemu_free(blk);
+    return 0;
+}
+
+static void set_dirty_tracking(int enable)
+{
+    BlkMigDevState *bmds;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        bdrv_set_dirty_tracking(bmds->bs, enable);
+    }
+}
+
+static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
+{
+    Monitor *mon = opaque;
+    BlkMigDevState *bmds;
+    int64_t sectors;
+
+    if (!bdrv_is_read_only(bs)) {
+        sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+        if (sectors <= 0) {
+            return;
+        }
+
+        bmds = qemu_mallocz(sizeof(BlkMigDevState));
+        bmds->bs = bs;
+        bmds->bulk_completed = 0;
+        bmds->total_sectors = sectors;
+        bmds->completed_sectors = 0;
+        bmds->shared_base = block_mig_state.shared_base;
+        alloc_aio_bitmap(bmds);
+        drive_get_ref(drive_get_by_blockdev(bs));
+        bdrv_set_in_use(bs, 1);
+
+        block_mig_state.total_sector_sum += sectors;
+
+        if (bmds->shared_base) {
+            monitor_printf(mon, "Start migration for %s with shared base "
+                                "image\n",
+                           bs->device_name);
+        } else {
+            monitor_printf(mon, "Start full migration for %s\n",
+                           bs->device_name);
+        }
+
+        QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
+    }
+}
+
+static void init_blk_migration(Monitor *mon, QEMUFile *f)
+{
+    block_mig_state.submitted = 0;
+    block_mig_state.read_done = 0;
+    block_mig_state.transferred = 0;
+    block_mig_state.total_sector_sum = 0;
+    block_mig_state.prev_progress = -1;
+    block_mig_state.bulk_completed = 0;
+    block_mig_state.total_time = 0;
+    block_mig_state.reads = 0;
+
+    bdrv_iterate(init_blk_migration_it, mon);
+}
+
+static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
+{
+    int64_t completed_sector_sum = 0;
+    BlkMigDevState *bmds;
+    int progress;
+    int ret = 0;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        if (bmds->bulk_completed == 0) {
+            if (mig_save_device_bulk(mon, f, bmds) == 1) {
+                /* completed bulk section for this device */
+                bmds->bulk_completed = 1;
+            }
+            completed_sector_sum += bmds->completed_sectors;
+            ret = 1;
+            break;
+        } else {
+            completed_sector_sum += bmds->completed_sectors;
+        }
+    }
+
+    if (block_mig_state.total_sector_sum != 0) {
+        progress = completed_sector_sum * 100 /
+                   block_mig_state.total_sector_sum;
+    } else {
+        progress = 100;
+    }
+    if (progress != block_mig_state.prev_progress) {
+        block_mig_state.prev_progress = progress;
+        qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
+                         | BLK_MIG_FLAG_PROGRESS);
+        monitor_printf(mon, "Completed %d %%\r", progress);
+        monitor_flush(mon);
+    }
+
+    return ret;
+}
+
+static void blk_mig_reset_dirty_cursor(void)
+{
+    BlkMigDevState *bmds;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        bmds->cur_dirty = 0;
+    }
+}
+
+static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
+                                 BlkMigDevState *bmds, int is_async)
+{
+    BlkMigBlock *blk;
+    int64_t total_sectors = bmds->total_sectors;
+    int64_t sector;
+    int nr_sectors;
+
+    for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
+        if (bmds_aio_inflight(bmds, sector)) {
+            qemu_aio_flush();
+        }
+        if (bdrv_get_dirty(bmds->bs, sector)) {
+
+            if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
+                nr_sectors = total_sectors - sector;
+            } else {
+                nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
+            }
+            blk = qemu_malloc(sizeof(BlkMigBlock));
+            blk->buf = qemu_malloc(BLOCK_SIZE);
+            blk->bmds = bmds;
+            blk->sector = sector;
+            blk->nr_sectors = nr_sectors;
+
+            if (is_async) {
+                blk->iov.iov_base = blk->buf;
+                blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+                qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+
+                if (block_mig_state.submitted == 0) {
+                    block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+                }
+
+                blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
+                                            nr_sectors, blk_mig_read_cb, blk);
+                if (!blk->aiocb) {
+                    goto error;
+                }
+                block_mig_state.submitted++;
+                bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
+            } else {
+                if (bdrv_read(bmds->bs, sector, blk->buf,
+                              nr_sectors) < 0) {
+                    goto error;
+                }
+                blk_send(f, blk);
+
+                qemu_free(blk->buf);
+                qemu_free(blk);
+            }
+
+            bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
+            break;
+        }
+        sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
+        bmds->cur_dirty = sector;
+    }
+
+    return (bmds->cur_dirty >= bmds->total_sectors);
+
+error:
+    monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
+    qemu_file_set_error(f);
+    qemu_free(blk->buf);
+    qemu_free(blk);
+    return 0;
+}
+
+static int blk_mig_save_dirty_block(Monitor *mon, QEMUFile *f, int is_async)
+{
+    BlkMigDevState *bmds;
+    int ret = 0;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        if (mig_save_device_dirty(mon, f, bmds, is_async) == 0) {
+            ret = 1;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static void flush_blks(QEMUFile* f)
+{
+    BlkMigBlock *blk;
+
+    DPRINTF("%s Enter submitted %d read_done %d transferred %d\n",
+            __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
+            block_mig_state.transferred);
+
+    while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
+        if (qemu_file_rate_limit(f)) {
+            break;
+        }
+        if (blk->ret < 0) {
+            qemu_file_set_error(f);
+            break;
+        }
+        blk_send(f, blk);
+
+        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
+        qemu_free(blk->buf);
+        qemu_free(blk);
+
+        block_mig_state.read_done--;
+        block_mig_state.transferred++;
+        assert(block_mig_state.read_done >= 0);
+    }
+
+    DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
+            block_mig_state.submitted, block_mig_state.read_done,
+            block_mig_state.transferred);
+}
+
+static int64_t get_remaining_dirty(void)
+{
+    BlkMigDevState *bmds;
+    int64_t dirty = 0;
+
+    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+        dirty += bdrv_get_dirty_count(bmds->bs);
+    }
+
+    return dirty * BLOCK_SIZE;
+}
+
+static int is_stage2_completed(void)
+{
+    int64_t remaining_dirty;
+    long double bwidth;
+
+    if (block_mig_state.bulk_completed == 1) {
+
+        remaining_dirty = get_remaining_dirty();
+        if (remaining_dirty == 0) {
+            return 1;
+        }
+
+        bwidth = compute_read_bwidth();
+
+        if ((remaining_dirty / bwidth) <=
+            migrate_max_downtime()) {
+            /* finish stage2 because we think that we can finish remaing work
+               below max_downtime */
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void blk_mig_cleanup(Monitor *mon)
+{
+    BlkMigDevState *bmds;
+    BlkMigBlock *blk;
+
+    set_dirty_tracking(0);
+
+    while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
+        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
+        bdrv_set_in_use(bmds->bs, 0);
+        drive_put_ref(drive_get_by_blockdev(bmds->bs));
+        qemu_free(bmds->aio_bitmap);
+        qemu_free(bmds);
+    }
+
+    while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
+        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
+        qemu_free(blk->buf);
+        qemu_free(blk);
+    }
+
+    monitor_printf(mon, "\n");
+}
+
+static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+{
+    DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
+            stage, block_mig_state.submitted, block_mig_state.transferred);
+
+    if (stage < 0) {
+        blk_mig_cleanup(mon);
+        return 0;
+    }
+
+    if (block_mig_state.blk_enable != 1) {
+        /* no need to migrate storage */
+        qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+        return 1;
+    }
+
+    if (stage == 1) {
+        init_blk_migration(mon, f);
+
+        /* start track dirty blocks */
+        set_dirty_tracking(1);
+    }
+
+    flush_blks(f);
+
+    if (qemu_file_has_error(f)) {
+        blk_mig_cleanup(mon);
+        return 0;
+    }
+
+    blk_mig_reset_dirty_cursor();
+
+    if (stage == 2) {
+        /* control the rate of transfer */
+        while ((block_mig_state.submitted +
+                block_mig_state.read_done) * BLOCK_SIZE <
+               qemu_file_get_rate_limit(f)) {
+            if (block_mig_state.bulk_completed == 0) {
+                /* first finish the bulk phase */
+                if (blk_mig_save_bulked_block(mon, f) == 0) {
+                    /* finished saving bulk on all devices */
+                    block_mig_state.bulk_completed = 1;
+                }
+            } else {
+                if (blk_mig_save_dirty_block(mon, f, 1) == 0) {
+                    /* no more dirty blocks */
+                    break;
+                }
+            }
+        }
+
+        flush_blks(f);
+
+        if (qemu_file_has_error(f)) {
+            blk_mig_cleanup(mon);
+            return 0;
+        }
+    }
+
+    if (stage == 3) {
+        /* we know for sure that save bulk is completed and
+           all async read completed */
+        assert(block_mig_state.submitted == 0);
+
+        while (blk_mig_save_dirty_block(mon, f, 0) != 0);
+        blk_mig_cleanup(mon);
+
+        /* report completion */
+        qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
+
+        if (qemu_file_has_error(f)) {
+            return 0;
+        }
+
+        monitor_printf(mon, "Block migration completed\n");
+    }
+
+    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+
+    return ((stage == 2) && is_stage2_completed());
+}
+
+static int block_load(QEMUFile *f, void *opaque, int version_id)
+{
+    static int banner_printed;
+    int len, flags;
+    char device_name[256];
+    int64_t addr;
+    BlockDriverState *bs, *bs_prev = NULL;
+    uint8_t *buf;
+    int64_t total_sectors = 0;
+    int nr_sectors;
+
+    do {
+        addr = qemu_get_be64(f);
+
+        flags = addr & ~BDRV_SECTOR_MASK;
+        addr >>= BDRV_SECTOR_BITS;
+
+        if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
+            int ret;
+            /* get device name */
+            len = qemu_get_byte(f);
+            qemu_get_buffer(f, (uint8_t *)device_name, len);
+            device_name[len] = '\0';
+
+            bs = bdrv_find(device_name);
+            if (!bs) {
+                fprintf(stderr, "Error unknown block device %s\n",
+                        device_name);
+                return -EINVAL;
+            }
+
+            if (bs != bs_prev) {
+                bs_prev = bs;
+                total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+                if (total_sectors <= 0) {
+                    error_report("Error getting length of block device %s",
+                                 device_name);
+                    return -EINVAL;
+                }
+            }
+
+            if (total_sectors - addr < BDRV_SECTORS_PER_DIRTY_CHUNK) {
+                nr_sectors = total_sectors - addr;
+            } else {
+                nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
+            }
+
+            buf = qemu_malloc(BLOCK_SIZE);
+
+            qemu_get_buffer(f, buf, BLOCK_SIZE);
+            ret = bdrv_write(bs, addr, buf, nr_sectors);
+
+            qemu_free(buf);
+            if (ret < 0) {
+                return ret;
+            }
+        } else if (flags & BLK_MIG_FLAG_PROGRESS) {
+            if (!banner_printed) {
+                printf("Receiving block device images\n");
+                banner_printed = 1;
+            }
+            printf("Completed %d %%%c", (int)addr,
+                   (addr == 100) ? '\n' : '\r');
+            fflush(stdout);
+        } else if (!(flags & BLK_MIG_FLAG_EOS)) {
+            fprintf(stderr, "Unknown flags\n");
+            return -EINVAL;
+        }
+        if (qemu_file_has_error(f)) {
+            return -EIO;
+        }
+    } while (!(flags & BLK_MIG_FLAG_EOS));
+
+    return 0;
+}
+
+static void block_set_params(int blk_enable, int shared_base, void *opaque)
+{
+    block_mig_state.blk_enable = blk_enable;
+    block_mig_state.shared_base = shared_base;
+
+    /* shared base means that blk_enable = 1 */
+    block_mig_state.blk_enable |= shared_base;
+}
+
+void blk_mig_init(void)
+{
+    QSIMPLEQ_INIT(&block_mig_state.bmds_list);
+    QSIMPLEQ_INIT(&block_mig_state.blk_list);
+
+    register_savevm_live(NULL, "block", 0, 1, block_set_params,
+                         block_save_live, NULL, block_load, &block_mig_state);
+}
diff --git a/qemu-0.15.x/block-migration.h b/qemu-0.15.x/block-migration.h
new file mode 100644
index 0000000..ffa8ac0
--- /dev/null
+++ b/qemu-0.15.x/block-migration.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU live block migration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Liran Schour   <lirans at il.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef BLOCK_MIGRATION_H
+#define BLOCK_MIGRATION_H
+
+void blk_mig_init(void);
+int blk_mig_active(void);
+uint64_t blk_mig_bytes_transferred(void);
+uint64_t blk_mig_bytes_remaining(void);
+uint64_t blk_mig_bytes_total(void);
+
+#endif /* BLOCK_MIGRATION_H */
diff --git a/qemu-0.15.x/block.c b/qemu-0.15.x/block.c
new file mode 100644
index 0000000..9549b9e
--- /dev/null
+++ b/qemu-0.15.x/block.c
@@ -0,0 +1,3039 @@
+/*
+ * 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 "config-host.h"
+#include "qemu-common.h"
+#include "trace.h"
+#include "monitor.h"
+#include "block_int.h"
+#include "module.h"
+#include "qemu-objects.h"
+
+#ifdef CONFIG_BSD
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#ifndef __DragonFly__
+#include <sys/disk.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque);
+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);
+
+static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
+    QTAILQ_HEAD_INITIALIZER(bdrv_states);
+
+static QLIST_HEAD(, BlockDriver) bdrv_drivers =
+    QLIST_HEAD_INITIALIZER(bdrv_drivers);
+
+/* The device to use for VM snapshots */
+static BlockDriverState *bs_snapshots;
+
+/* If non-zero, use only whitelisted block drivers */
+static int use_bdrv_whitelist;
+
+#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] == ':');
+}
+
+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
+
+/* check if the path starts with "<protocol>:" */
+static int path_has_protocol(const char *path)
+{
+#ifdef _WIN32
+    if (is_windows_drive(path) ||
+        is_windows_drive_prefix(path)) {
+        return 0;
+    }
+#endif
+
+    return strchr(path, ':') != NULL;
+}
+
+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);
+    }
+}
+
+void bdrv_register(BlockDriver *bdrv)
+{
+    if (!bdrv->bdrv_aio_readv) {
+        /* add AIO emulation layer */
+        bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
+        bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
+    } else if (!bdrv->bdrv_read) {
+        /* add synchronous IO emulation layer */
+        bdrv->bdrv_read = bdrv_read_em;
+        bdrv->bdrv_write = bdrv_write_em;
+    }
+
+    if (!bdrv->bdrv_aio_flush)
+        bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
+
+    QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
+}
+
+/* create a new block device (by default it is empty) */
+BlockDriverState *bdrv_new(const char *device_name)
+{
+    BlockDriverState *bs;
+
+    bs = qemu_mallocz(sizeof(BlockDriverState));
+    pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
+    if (device_name[0] != '\0') {
+        QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
+    }
+    return bs;
+}
+
+BlockDriver *bdrv_find_format(const char *format_name)
+{
+    BlockDriver *drv1;
+    QLIST_FOREACH(drv1, &bdrv_drivers, list) {
+        if (!strcmp(drv1->format_name, format_name)) {
+            return drv1;
+        }
+    }
+    return NULL;
+}
+
+static int bdrv_is_whitelisted(BlockDriver *drv)
+{
+    static const char *whitelist[] = {
+        CONFIG_BDRV_WHITELIST
+    };
+    const char **p;
+
+    if (!whitelist[0])
+        return 1;               /* no whitelist, anything goes */
+
+    for (p = whitelist; *p; p++) {
+        if (!strcmp(drv->format_name, *p)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+BlockDriver *bdrv_find_whitelisted_format(const char *format_name)
+{
+    BlockDriver *drv = bdrv_find_format(format_name);
+    return drv && bdrv_is_whitelisted(drv) ? drv : NULL;
+}
+
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options)
+{
+    if (!drv->bdrv_create)
+        return -ENOTSUP;
+
+    return drv->bdrv_create(filename, options);
+}
+
+int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
+{
+    BlockDriver *drv;
+
+    drv = bdrv_find_protocol(filename);
+    if (drv == NULL) {
+        return -ENOENT;
+    }
+
+    return bdrv_create(drv, filename, options);
+}
+
+#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;
+    const char *tmpdir;
+    /* XXX: race condition possible */
+    tmpdir = getenv("TMPDIR");
+    if (!tmpdir)
+        tmpdir = "/tmp";
+    snprintf(filename, size, "%s/vl.XXXXXX", tmpdir);
+    fd = mkstemp(filename);
+    close(fd);
+}
+#endif
+
+/*
+ * Detect host devices. By convention, /dev/cdrom[N] is always
+ * recognized as a host CDROM.
+ */
+static BlockDriver *find_hdev_driver(const char *filename)
+{
+    int score_max = 0, score;
+    BlockDriver *drv = NULL, *d;
+
+    QLIST_FOREACH(d, &bdrv_drivers, list) {
+        if (d->bdrv_probe_device) {
+            score = d->bdrv_probe_device(filename);
+            if (score > score_max) {
+                score_max = score;
+                drv = d;
+            }
+        }
+    }
+
+    return drv;
+}
+
+BlockDriver *bdrv_find_protocol(const char *filename)
+{
+    BlockDriver *drv1;
+    char protocol[128];
+    int len;
+    const char *p;
+
+    /* TODO Drivers without bdrv_file_open must be specified explicitly */
+
+    /*
+     * XXX(hch): we really should not let host device detection
+     * override an explicit protocol specification, but moving this
+     * later breaks access to device names with colons in them.
+     * Thanks to the brain-dead persistent naming schemes on udev-
+     * based Linux systems those actually are quite common.
+     */
+    drv1 = find_hdev_driver(filename);
+    if (drv1) {
+        return drv1;
+    }
+
+    if (!path_has_protocol(filename)) {
+        return bdrv_find_format("file");
+    }
+    p = strchr(filename, ':');
+    assert(p != NULL);
+    len = p - filename;
+    if (len > sizeof(protocol) - 1)
+        len = sizeof(protocol) - 1;
+    memcpy(protocol, filename, len);
+    protocol[len] = '\0';
+    QLIST_FOREACH(drv1, &bdrv_drivers, list) {
+        if (drv1->protocol_name &&
+            !strcmp(drv1->protocol_name, protocol)) {
+            return drv1;
+        }
+    }
+    return NULL;
+}
+
+static int find_image_format(const char *filename, BlockDriver **pdrv)
+{
+    int ret, score, score_max;
+    BlockDriver *drv1, *drv;
+    uint8_t buf[2048];
+    BlockDriverState *bs;
+
+    ret = bdrv_file_open(&bs, filename, 0);
+    if (ret < 0) {
+        *pdrv = NULL;
+        return ret;
+    }
+
+    /* Return the raw BlockDriver * to scsi-generic devices or empty drives */
+    if (bs->sg || !bdrv_is_inserted(bs)) {
+        bdrv_delete(bs);
+        drv = bdrv_find_format("raw");
+        if (!drv) {
+            ret = -ENOENT;
+        }
+        *pdrv = drv;
+        return ret;
+    }
+
+    ret = bdrv_pread(bs, 0, buf, sizeof(buf));
+    bdrv_delete(bs);
+    if (ret < 0) {
+        *pdrv = NULL;
+        return ret;
+    }
+
+    score_max = 0;
+    drv = NULL;
+    QLIST_FOREACH(drv1, &bdrv_drivers, list) {
+        if (drv1->bdrv_probe) {
+            score = drv1->bdrv_probe(buf, ret, filename);
+            if (score > score_max) {
+                score_max = score;
+                drv = drv1;
+            }
+        }
+    }
+    if (!drv) {
+        ret = -ENOENT;
+    }
+    *pdrv = drv;
+    return ret;
+}
+
+/**
+ * Set the current 'total_sectors' value
+ */
+static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
+{
+    BlockDriver *drv = bs->drv;
+
+    /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
+    if (bs->sg)
+        return 0;
+
+    /* query actual device if possible, otherwise just trust the hint */
+    if (drv->bdrv_getlength) {
+        int64_t length = drv->bdrv_getlength(bs);
+        if (length < 0) {
+            return length;
+        }
+        hint = length >> BDRV_SECTOR_BITS;
+    }
+
+    bs->total_sectors = hint;
+    return 0;
+}
+
+/*
+ * Common part for opening disk images and files
+ */
+static int bdrv_open_common(BlockDriverState *bs, const char *filename,
+    int flags, BlockDriver *drv)
+{
+    int ret, open_flags;
+
+    assert(drv != NULL);
+
+    bs->file = NULL;
+    bs->total_sectors = 0;
+    bs->encrypted = 0;
+    bs->valid_key = 0;
+    bs->open_flags = flags;
+    /* buffer_alignment defaulted to 512, drivers can change this value */
+    bs->buffer_alignment = 512;
+
+    pstrcpy(bs->filename, sizeof(bs->filename), filename);
+
+    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
+        return -ENOTSUP;
+    }
+
+    bs->drv = drv;
+    bs->opaque = qemu_mallocz(drv->instance_size);
+
+    if (flags & BDRV_O_CACHE_WB)
+        bs->enable_write_cache = 1;
+
+    /*
+     * Clear flags that are internal to the block layer before opening the
+     * image.
+     */
+    open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+    /*
+     * Snapshots should be writable.
+     */
+    if (bs->is_temporary) {
+        open_flags |= BDRV_O_RDWR;
+    }
+
+    /* Open the image, either directly or using a protocol */
+    if (drv->bdrv_file_open) {
+        ret = drv->bdrv_file_open(bs, filename, open_flags);
+    } else {
+        ret = bdrv_file_open(&bs->file, filename, open_flags);
+        if (ret >= 0) {
+            ret = drv->bdrv_open(bs, open_flags);
+        }
+    }
+
+    if (ret < 0) {
+        goto free_and_fail;
+    }
+
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
+
+    ret = refresh_total_sectors(bs, bs->total_sectors);
+    if (ret < 0) {
+        goto free_and_fail;
+    }
+
+#ifndef _WIN32
+    if (bs->is_temporary) {
+        unlink(filename);
+    }
+#endif
+    return 0;
+
+free_and_fail:
+    if (bs->file) {
+        bdrv_delete(bs->file);
+        bs->file = NULL;
+    }
+    qemu_free(bs->opaque);
+    bs->opaque = NULL;
+    bs->drv = NULL;
+    return ret;
+}
+
+/*
+ * Opens a file using a protocol (file, host_device, nbd, ...)
+ */
+int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
+{
+    BlockDriverState *bs;
+    BlockDriver *drv;
+    int ret;
+
+    drv = bdrv_find_protocol(filename);
+    if (!drv) {
+        return -ENOENT;
+    }
+
+    bs = bdrv_new("");
+    ret = bdrv_open_common(bs, filename, flags, drv);
+    if (ret < 0) {
+        bdrv_delete(bs);
+        return ret;
+    }
+    bs->growable = 1;
+    *pbs = bs;
+    return 0;
+}
+
+/*
+ * Opens a disk image (raw, qcow2, vmdk, ...)
+ */
+int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
+              BlockDriver *drv)
+{
+    int ret;
+
+    if (flags & BDRV_O_SNAPSHOT) {
+        BlockDriverState *bs1;
+        int64_t total_size;
+        int is_protocol = 0;
+        BlockDriver *bdrv_qcow2;
+        QEMUOptionParameter *options;
+        char tmp_filename[PATH_MAX];
+        char backing_filename[PATH_MAX];
+
+        /* 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("");
+        ret = bdrv_open(bs1, filename, 0, drv);
+        if (ret < 0) {
+            bdrv_delete(bs1);
+            return ret;
+        }
+        total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
+
+        if (bs1->drv && bs1->drv->protocol_name)
+            is_protocol = 1;
+
+        bdrv_delete(bs1);
+
+        get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+
+        /* Real path is meaningless for protocols */
+        if (is_protocol)
+            snprintf(backing_filename, sizeof(backing_filename),
+                     "%s", filename);
+        else if (!realpath(filename, backing_filename))
+            return -errno;
+
+        bdrv_qcow2 = bdrv_find_format("qcow2");
+        options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
+
+        set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
+        set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
+        if (drv) {
+            set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
+                drv->format_name);
+        }
+
+        ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
+        free_option_parameters(options);
+        if (ret < 0) {
+            return ret;
+        }
+
+        filename = tmp_filename;
+        drv = bdrv_qcow2;
+        bs->is_temporary = 1;
+    }
+
+    /* Find the right image format driver */
+    if (!drv) {
+        ret = find_image_format(filename, &drv);
+    }
+
+    if (!drv) {
+        goto unlink_and_fail;
+    }
+
+    /* Open the image */
+    ret = bdrv_open_common(bs, filename, flags, drv);
+    if (ret < 0) {
+        goto unlink_and_fail;
+    }
+
+    /* If there is a backing file, use it */
+    if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') {
+        char backing_filename[PATH_MAX];
+        int back_flags;
+        BlockDriver *back_drv = NULL;
+
+        bs->backing_hd = bdrv_new("");
+
+        if (path_has_protocol(bs->backing_file)) {
+            pstrcpy(backing_filename, sizeof(backing_filename),
+                    bs->backing_file);
+        } else {
+            path_combine(backing_filename, sizeof(backing_filename),
+                         filename, bs->backing_file);
+        }
+
+        if (bs->backing_format[0] != '\0') {
+            back_drv = bdrv_find_format(bs->backing_format);
+        }
+
+        /* backing files always opened read-only */
+        back_flags =
+            flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+        ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
+        if (ret < 0) {
+            bdrv_close(bs);
+            return ret;
+        }
+        if (bs->is_temporary) {
+            bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+        } else {
+            /* base image inherits from "parent" */
+            bs->backing_hd->keep_read_only = bs->keep_read_only;
+        }
+    }
+
+    if (!bdrv_key_required(bs)) {
+        /* call the change callback */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+    }
+
+    return 0;
+
+unlink_and_fail:
+    if (bs->is_temporary) {
+        unlink(filename);
+    }
+    return ret;
+}
+
+void bdrv_close(BlockDriverState *bs)
+{
+    if (bs->drv) {
+        if (bs == bs_snapshots) {
+            bs_snapshots = NULL;
+        }
+        if (bs->backing_hd) {
+            bdrv_delete(bs->backing_hd);
+            bs->backing_hd = NULL;
+        }
+        bs->drv->bdrv_close(bs);
+        qemu_free(bs->opaque);
+#ifdef _WIN32
+        if (bs->is_temporary) {
+            unlink(bs->filename);
+        }
+#endif
+        bs->opaque = NULL;
+        bs->drv = NULL;
+
+        if (bs->file != NULL) {
+            bdrv_close(bs->file);
+        }
+
+        /* call the change callback */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+    }
+}
+
+void bdrv_close_all(void)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        bdrv_close(bs);
+    }
+}
+
+/* make a BlockDriverState anonymous by removing from bdrv_state list.
+   Also, NULL terminate the device_name to prevent double remove */
+void bdrv_make_anon(BlockDriverState *bs)
+{
+    if (bs->device_name[0] != '\0') {
+        QTAILQ_REMOVE(&bdrv_states, bs, list);
+    }
+    bs->device_name[0] = '\0';
+}
+
+void bdrv_delete(BlockDriverState *bs)
+{
+    assert(!bs->peer);
+
+    /* remove from list, if necessary */
+    bdrv_make_anon(bs);
+
+    bdrv_close(bs);
+    if (bs->file != NULL) {
+        bdrv_delete(bs->file);
+    }
+
+    assert(bs != bs_snapshots);
+    qemu_free(bs);
+}
+
+int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
+{
+    if (bs->peer) {
+        return -EBUSY;
+    }
+    bs->peer = qdev;
+    return 0;
+}
+
+void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
+{
+    assert(bs->peer == qdev);
+    bs->peer = NULL;
+}
+
+DeviceState *bdrv_get_attached(BlockDriverState *bs)
+{
+    return bs->peer;
+}
+
+/*
+ * Run consistency checks on an image
+ *
+ * Returns 0 if the check could be completed (it doesn't mean that the image is
+ * free of errors) or -errno when an internal error occurred. The results of the
+ * check are stored in res.
+ */
+int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
+{
+    if (bs->drv->bdrv_check == NULL) {
+        return -ENOTSUP;
+    }
+
+    memset(res, 0, sizeof(*res));
+    return bs->drv->bdrv_check(bs, res);
+}
+
+#define COMMIT_BUF_SECTORS 2048
+
+/* commit COW file into the raw image */
+int bdrv_commit(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    BlockDriver *backing_drv;
+    int64_t sector, total_sectors;
+    int n, ro, open_flags;
+    int ret = 0, rw_ret = 0;
+    uint8_t *buf;
+    char filename[1024];
+    BlockDriverState *bs_rw, *bs_ro;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    
+    if (!bs->backing_hd) {
+        return -ENOTSUP;
+    }
+
+    if (bs->backing_hd->keep_read_only) {
+        return -EACCES;
+    }
+
+    backing_drv = bs->backing_hd->drv;
+    ro = bs->backing_hd->read_only;
+    strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+    open_flags =  bs->backing_hd->open_flags;
+
+    if (ro) {
+        /* re-open as RW */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_rw = bdrv_new("");
+        rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR,
+            backing_drv);
+        if (rw_ret < 0) {
+            bdrv_delete(bs_rw);
+            /* try to re-open read-only */
+            bs_ro = bdrv_new("");
+            ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
+                backing_drv);
+            if (ret < 0) {
+                bdrv_delete(bs_ro);
+                /* drive not functional anymore */
+                bs->drv = NULL;
+                return ret;
+            }
+            bs->backing_hd = bs_ro;
+            return rw_ret;
+        }
+        bs->backing_hd = bs_rw;
+    }
+
+    total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+    buf = qemu_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
+
+    for (sector = 0; sector < total_sectors; sector += n) {
+        if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
+
+            if (bdrv_read(bs, sector, buf, n) != 0) {
+                ret = -EIO;
+                goto ro_cleanup;
+            }
+
+            if (bdrv_write(bs->backing_hd, sector, buf, n) != 0) {
+                ret = -EIO;
+                goto ro_cleanup;
+            }
+        }
+    }
+
+    if (drv->bdrv_make_empty) {
+        ret = drv->bdrv_make_empty(bs);
+        bdrv_flush(bs);
+    }
+
+    /*
+     * Make sure all data we wrote to the backing device is actually
+     * stable on disk.
+     */
+    if (bs->backing_hd)
+        bdrv_flush(bs->backing_hd);
+
+ro_cleanup:
+    qemu_free(buf);
+
+    if (ro) {
+        /* re-open as RO */
+        bdrv_delete(bs->backing_hd);
+        bs->backing_hd = NULL;
+        bs_ro = bdrv_new("");
+        ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
+            backing_drv);
+        if (ret < 0) {
+            bdrv_delete(bs_ro);
+            /* drive not functional anymore */
+            bs->drv = NULL;
+            return ret;
+        }
+        bs->backing_hd = bs_ro;
+        bs->backing_hd->keep_read_only = 0;
+    }
+
+    return ret;
+}
+
+void bdrv_commit_all(void)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        bdrv_commit(bs);
+    }
+}
+
+/*
+ * Return values:
+ * 0        - success
+ * -EINVAL  - backing format specified, but no file
+ * -ENOSPC  - can't update the backing file because no space is left in the
+ *            image file header
+ * -ENOTSUP - format driver doesn't support changing the backing file
+ */
+int bdrv_change_backing_file(BlockDriverState *bs,
+    const char *backing_file, const char *backing_fmt)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (drv->bdrv_change_backing_file != NULL) {
+        return drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
+    } else {
+        return -ENOTSUP;
+    }
+}
+
+static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
+                                   size_t size)
+{
+    int64_t len;
+
+    if (!bdrv_is_inserted(bs))
+        return -ENOMEDIUM;
+
+    if (bs->growable)
+        return 0;
+
+    len = bdrv_getlength(bs);
+
+    if (offset < 0)
+        return -EIO;
+
+    if ((offset > len) || (len - offset < size))
+        return -EIO;
+
+    return 0;
+}
+
+static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
+                              int nb_sectors)
+{
+    return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
+                                   nb_sectors * BDRV_SECTOR_SIZE);
+}
+
+/* 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;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
+
+    return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
+}
+
+static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int dirty)
+{
+    int64_t start, end;
+    unsigned long val, idx, bit;
+
+    start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
+    end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    for (; start <= end; start++) {
+        idx = start / (sizeof(unsigned long) * 8);
+        bit = start % (sizeof(unsigned long) * 8);
+        val = bs->dirty_bitmap[idx];
+        if (dirty) {
+            if (!(val & (1UL << bit))) {
+                bs->dirty_count++;
+                val |= 1UL << bit;
+            }
+        } else {
+            if (val & (1UL << bit)) {
+                bs->dirty_count--;
+                val &= ~(1UL << bit);
+            }
+        }
+        bs->dirty_bitmap[idx] = val;
+    }
+}
+
+/* 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 (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
+
+    if (bs->dirty_bitmap) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+
+    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+        bs->wr_highest_sector = sector_num + nb_sectors - 1;
+    }
+
+    return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
+}
+
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
+               void *buf, int count1)
+{
+    uint8_t tmp_buf[BDRV_SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+    int ret;
+
+    count = count1;
+    /* first read to align to sector start */
+    len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> BDRV_SECTOR_BITS;
+    if (len > 0) {
+        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+        memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* read the sectors "in place" */
+    nb_sectors = count >> BDRV_SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
+            return ret;
+        sector_num += nb_sectors;
+        len = nb_sectors << BDRV_SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+        memcpy(buf, tmp_buf, count);
+    }
+    return count1;
+}
+
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
+                const void *buf, int count1)
+{
+    uint8_t tmp_buf[BDRV_SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+    int ret;
+
+    count = count1;
+    /* first write to align to sector start */
+    len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> BDRV_SECTOR_BITS;
+    if (len > 0) {
+        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+        memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
+        if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* write the sectors "in place" */
+    nb_sectors = count >> BDRV_SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
+            return ret;
+        sector_num += nb_sectors;
+        len = nb_sectors << BDRV_SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+        memcpy(tmp_buf, buf, count);
+        if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
+            return ret;
+    }
+    return count1;
+}
+
+/*
+ * Writes to the file and ensures that no writes are reordered across this
+ * request (acts as a barrier)
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
+    const void *buf, int count)
+{
+    int ret;
+
+    ret = bdrv_pwrite(bs, offset, buf, count);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* No flush needed for cache=writethrough, it uses O_DSYNC */
+    if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
+        bdrv_flush(bs);
+    }
+
+    return 0;
+}
+
+/*
+ * Writes to the file and ensures that no writes are reordered across this
+ * request (acts as a barrier)
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors)
+{
+    return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
+        buf, BDRV_SECTOR_SIZE * nb_sectors);
+}
+
+/**
+ * Truncate file to 'offset' bytes (needed only for file protocols)
+ */
+int bdrv_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_truncate)
+        return -ENOTSUP;
+    if (bs->read_only)
+        return -EACCES;
+    if (bdrv_in_use(bs))
+        return -EBUSY;
+    ret = drv->bdrv_truncate(bs, offset);
+    if (ret == 0) {
+        ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
+        if (bs->change_cb) {
+            bs->change_cb(bs->change_opaque, CHANGE_SIZE);
+        }
+    }
+    return ret;
+}
+
+/**
+ * Length of a allocated file in bytes. Sparse files are counted by actual
+ * allocated space. Return < 0 if error or unknown.
+ */
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (drv->bdrv_get_allocated_file_size) {
+        return drv->bdrv_get_allocated_file_size(bs);
+    }
+    if (bs->file) {
+        return bdrv_get_allocated_file_size(bs->file);
+    }
+    return -ENOTSUP;
+}
+
+/**
+ * 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 (bs->growable || bs->removable) {
+        if (drv->bdrv_getlength) {
+            return drv->bdrv_getlength(bs);
+        }
+    }
+    return bs->total_sectors * BDRV_SECTOR_SIZE;
+}
+
+/* return 0 as number of sectors if no device present or error */
+void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
+{
+    int64_t length;
+    length = bdrv_getlength(bs);
+    if (length < 0)
+        length = 0;
+    else
+        length = length >> BDRV_SECTOR_BITS;
+    *nb_sectors_ptr = length;
+}
+
+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(BlockDriverState *bs,
+                           int *pcylinders, int *pheads, int *psectors)
+{
+    uint8_t buf[BDRV_SECTOR_SIZE];
+    int ret, i, heads, sectors, cylinders;
+    struct partition *p;
+    uint32_t nr_sects;
+    uint64_t nb_sectors;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+
+    ret = bdrv_read(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 = 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;
+}
+
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs)
+{
+    int translation, lba_detected = 0;
+    int cylinders, heads, secs;
+    uint64_t nb_sectors;
+
+    /* if a geometry hint is available, use it */
+    bdrv_get_geometry(bs, &nb_sectors);
+    bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs);
+    translation = bdrv_get_translation_hint(bs);
+    if (cylinders != 0) {
+        *pcyls = cylinders;
+        *pheads = heads;
+        *psecs = secs;
+    } else {
+        if (guess_disk_lchs(bs, &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 {
+                *pcyls = cylinders;
+                *pheads = heads;
+                *psecs = secs;
+                /* disable any translation to be in sync with
+                   the logical geometry */
+                if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                    bdrv_set_translation_hint(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;
+            *pcyls = cylinders;
+            *pheads = 16;
+            *psecs = 63;
+            if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) {
+                if ((*pcyls * *pheads) <= 131072) {
+                    bdrv_set_translation_hint(bs,
+                                              BIOS_ATA_TRANSLATION_LARGE);
+                } else {
+                    bdrv_set_translation_hint(bs,
+                                              BIOS_ATA_TRANSLATION_LBA);
+                }
+            }
+        }
+        bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs);
+    }
+}
+
+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_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;
+}
+
+/* Recognize floppy formats */
+typedef struct FDFormat {
+    FDriveType drive;
+    uint8_t last_sect;
+    uint8_t max_track;
+    uint8_t max_head;
+} FDFormat;
+
+static const FDFormat fd_formats[] = {
+    /* First entry is default format */
+    /* 1.44 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144, 18, 80, 1, },
+    { FDRIVE_DRV_144, 20, 80, 1, },
+    { FDRIVE_DRV_144, 21, 80, 1, },
+    { FDRIVE_DRV_144, 21, 82, 1, },
+    { FDRIVE_DRV_144, 21, 83, 1, },
+    { FDRIVE_DRV_144, 22, 80, 1, },
+    { FDRIVE_DRV_144, 23, 80, 1, },
+    { FDRIVE_DRV_144, 24, 80, 1, },
+    /* 2.88 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_288, 36, 80, 1, },
+    { FDRIVE_DRV_288, 39, 80, 1, },
+    { FDRIVE_DRV_288, 40, 80, 1, },
+    { FDRIVE_DRV_288, 44, 80, 1, },
+    { FDRIVE_DRV_288, 48, 80, 1, },
+    /* 720 kB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144,  9, 80, 1, },
+    { FDRIVE_DRV_144, 10, 80, 1, },
+    { FDRIVE_DRV_144, 10, 82, 1, },
+    { FDRIVE_DRV_144, 10, 83, 1, },
+    { FDRIVE_DRV_144, 13, 80, 1, },
+    { FDRIVE_DRV_144, 14, 80, 1, },
+    /* 1.2 MB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, 15, 80, 1, },
+    { FDRIVE_DRV_120, 18, 80, 1, },
+    { FDRIVE_DRV_120, 18, 82, 1, },
+    { FDRIVE_DRV_120, 18, 83, 1, },
+    { FDRIVE_DRV_120, 20, 80, 1, },
+    /* 720 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 80, 1, },
+    { FDRIVE_DRV_120, 11, 80, 1, },
+    /* 360 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 40, 1, },
+    { FDRIVE_DRV_120,  9, 40, 0, },
+    { FDRIVE_DRV_120, 10, 41, 1, },
+    { FDRIVE_DRV_120, 10, 42, 1, },
+    /* 320 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  8, 40, 1, },
+    { FDRIVE_DRV_120,  8, 40, 0, },
+    /* 360 kB must match 5"1/4 better than 3"1/2... */
+    { FDRIVE_DRV_144,  9, 80, 0, },
+    /* end */
+    { FDRIVE_DRV_NONE, -1, -1, 0, },
+};
+
+void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
+                                   int *max_track, int *last_sect,
+                                   FDriveType drive_in, FDriveType *drive)
+{
+    const FDFormat *parse;
+    uint64_t nb_sectors, size;
+    int i, first_match, match;
+
+    bdrv_get_geometry_hint(bs, nb_heads, max_track, last_sect);
+    if (*nb_heads != 0 && *max_track != 0 && *last_sect != 0) {
+        /* User defined disk */
+    } else {
+        bdrv_get_geometry(bs, &nb_sectors);
+        match = -1;
+        first_match = -1;
+        for (i = 0; ; i++) {
+            parse = &fd_formats[i];
+            if (parse->drive == FDRIVE_DRV_NONE) {
+                break;
+            }
+            if (drive_in == parse->drive ||
+                drive_in == FDRIVE_DRV_NONE) {
+                size = (parse->max_head + 1) * parse->max_track *
+                    parse->last_sect;
+                if (nb_sectors == size) {
+                    match = i;
+                    break;
+                }
+                if (first_match == -1) {
+                    first_match = i;
+                }
+            }
+        }
+        if (match == -1) {
+            if (first_match == -1) {
+                match = 1;
+            } else {
+                match = first_match;
+            }
+            parse = &fd_formats[match];
+        }
+        *nb_heads = parse->max_head + 1;
+        *max_track = parse->max_track;
+        *last_sect = parse->last_sect;
+        *drive = parse->drive;
+    }
+}
+
+int bdrv_get_translation_hint(BlockDriverState *bs)
+{
+    return bs->translation;
+}
+
+void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
+                       BlockErrorAction on_write_error)
+{
+    bs->on_read_error = on_read_error;
+    bs->on_write_error = on_write_error;
+}
+
+BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
+{
+    return is_read ? bs->on_read_error : bs->on_write_error;
+}
+
+void bdrv_set_removable(BlockDriverState *bs, int removable)
+{
+    bs->removable = removable;
+    if (removable && bs == bs_snapshots) {
+        bs_snapshots = NULL;
+    }
+}
+
+int bdrv_is_removable(BlockDriverState *bs)
+{
+    return bs->removable;
+}
+
+int bdrv_is_read_only(BlockDriverState *bs)
+{
+    return bs->read_only;
+}
+
+int bdrv_is_sg(BlockDriverState *bs)
+{
+    return bs->sg;
+}
+
+int bdrv_enable_write_cache(BlockDriverState *bs)
+{
+    return bs->enable_write_cache;
+}
+
+/* XXX: no longer used */
+void bdrv_set_change_cb(BlockDriverState *bs,
+                        void (*change_cb)(void *opaque, int reason),
+                        void *opaque)
+{
+    bs->change_cb = change_cb;
+    bs->change_opaque = opaque;
+}
+
+int bdrv_is_encrypted(BlockDriverState *bs)
+{
+    if (bs->backing_hd && bs->backing_hd->encrypted)
+        return 1;
+    return bs->encrypted;
+}
+
+int bdrv_key_required(BlockDriverState *bs)
+{
+    BlockDriverState *backing_hd = bs->backing_hd;
+
+    if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
+        return 1;
+    return (bs->encrypted && !bs->valid_key);
+}
+
+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) {
+        return -EINVAL;
+    } else if (!bs->drv || !bs->drv->bdrv_set_key) {
+        return -ENOMEDIUM;
+    }
+    ret = bs->drv->bdrv_set_key(bs, key);
+    if (ret < 0) {
+        bs->valid_key = 0;
+    } else if (!bs->valid_key) {
+        bs->valid_key = 1;
+        /* call the change callback now, we skipped it on open */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+    }
+    return ret;
+}
+
+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;
+
+    QLIST_FOREACH(drv, &bdrv_drivers, list) {
+        it(opaque, drv->format_name);
+    }
+}
+
+BlockDriverState *bdrv_find(const char *name)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        if (!strcmp(name, bs->device_name)) {
+            return bs;
+        }
+    }
+    return NULL;
+}
+
+BlockDriverState *bdrv_next(BlockDriverState *bs)
+{
+    if (!bs) {
+        return QTAILQ_FIRST(&bdrv_states);
+    }
+    return QTAILQ_NEXT(bs, list);
+}
+
+void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        it(opaque, bs);
+    }
+}
+
+const char *bdrv_get_device_name(BlockDriverState *bs)
+{
+    return bs->device_name;
+}
+
+int bdrv_flush(BlockDriverState *bs)
+{
+    if (bs->open_flags & BDRV_O_NO_FLUSH) {
+        return 0;
+    }
+
+    if (bs->drv && bs->drv->bdrv_flush) {
+        return bs->drv->bdrv_flush(bs);
+    }
+
+    /*
+     * Some block drivers always operate in either writethrough or unsafe mode
+     * and don't support bdrv_flush therefore. Usually qemu doesn't know how
+     * the server works (because the behaviour is hardcoded or depends on
+     * server-side configuration), so we can't ensure that everything is safe
+     * on disk. Returning an error doesn't work because that would break guests
+     * even if the server operates in writethrough mode.
+     *
+     * Let's hope the user knows what he's doing.
+     */
+    return 0;
+}
+
+void bdrv_flush_all(void)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        if (bs->drv && !bdrv_is_read_only(bs) &&
+            (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) {
+            bdrv_flush(bs);
+        }
+    }
+}
+
+int bdrv_has_zero_init(BlockDriverState *bs)
+{
+    assert(bs->drv);
+
+    if (bs->drv->bdrv_has_zero_init) {
+        return bs->drv->bdrv_has_zero_init(bs);
+    }
+
+    return 1;
+}
+
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    }
+    if (!bs->drv->bdrv_discard) {
+        return 0;
+    }
+    return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
+}
+
+/*
+ * Returns true iff the specified sector is present in the disk image. Drivers
+ * not implementing the functionality are assumed to not support backing files,
+ * hence all their sectors are reported as allocated.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the specified sector) that are known to be in the same
+ * allocated/unallocated state.
+ *
+ * 'nb_sectors' is the max value 'pnum' should be set to.
+ */
+int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
+	int *pnum)
+{
+    int64_t n;
+    if (!bs->drv->bdrv_is_allocated) {
+        if (sector_num >= bs->total_sectors) {
+            *pnum = 0;
+            return 0;
+        }
+        n = bs->total_sectors - sector_num;
+        *pnum = (n < nb_sectors) ? (n) : (nb_sectors);
+        return 1;
+    }
+    return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
+}
+
+void bdrv_mon_event(const BlockDriverState *bdrv,
+                    BlockMonEventAction action, int is_read)
+{
+    QObject *data;
+    const char *action_str;
+
+    switch (action) {
+    case BDRV_ACTION_REPORT:
+        action_str = "report";
+        break;
+    case BDRV_ACTION_IGNORE:
+        action_str = "ignore";
+        break;
+    case BDRV_ACTION_STOP:
+        action_str = "stop";
+        break;
+    default:
+        abort();
+    }
+
+    data = qobject_from_jsonf("{ 'device': %s, 'action': %s, 'operation': %s }",
+                              bdrv->device_name,
+                              action_str,
+                              is_read ? "read" : "write");
+    monitor_protocol_event(QEVENT_BLOCK_IO_ERROR, data);
+
+    qobject_decref(data);
+}
+
+static void bdrv_print_dict(QObject *obj, void *opaque)
+{
+    QDict *bs_dict;
+    Monitor *mon = opaque;
+
+    bs_dict = qobject_to_qdict(obj);
+
+    monitor_printf(mon, "%s: removable=%d",
+                        qdict_get_str(bs_dict, "device"),
+                        qdict_get_bool(bs_dict, "removable"));
+
+    if (qdict_get_bool(bs_dict, "removable")) {
+        monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
+    }
+
+    if (qdict_haskey(bs_dict, "inserted")) {
+        QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
+
+        monitor_printf(mon, " file=");
+        monitor_print_filename(mon, qdict_get_str(qdict, "file"));
+        if (qdict_haskey(qdict, "backing_file")) {
+            monitor_printf(mon, " backing_file=");
+            monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
+        }
+        monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
+                            qdict_get_bool(qdict, "ro"),
+                            qdict_get_str(qdict, "drv"),
+                            qdict_get_bool(qdict, "encrypted"));
+    } else {
+        monitor_printf(mon, " [not inserted]");
+    }
+
+    monitor_printf(mon, "\n");
+}
+
+void bdrv_info_print(Monitor *mon, const QObject *data)
+{
+    qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
+}
+
+void bdrv_info(Monitor *mon, QObject **ret_data)
+{
+    QList *bs_list;
+    BlockDriverState *bs;
+
+    bs_list = qlist_new();
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        QObject *bs_obj;
+
+        bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
+                                    "'removable': %i, 'locked': %i }",
+                                    bs->device_name, bs->removable,
+                                    bs->locked);
+
+        if (bs->drv) {
+            QObject *obj;
+            QDict *bs_dict = qobject_to_qdict(bs_obj);
+
+            obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
+                                     "'encrypted': %i }",
+                                     bs->filename, bs->read_only,
+                                     bs->drv->format_name,
+                                     bdrv_is_encrypted(bs));
+            if (bs->backing_file[0] != '\0') {
+                QDict *qdict = qobject_to_qdict(obj);
+                qdict_put(qdict, "backing_file",
+                          qstring_from_str(bs->backing_file));
+            }
+
+            qdict_put_obj(bs_dict, "inserted", obj);
+        }
+        qlist_append_obj(bs_list, bs_obj);
+    }
+
+    *ret_data = QOBJECT(bs_list);
+}
+
+static void bdrv_stats_iter(QObject *data, void *opaque)
+{
+    QDict *qdict;
+    Monitor *mon = opaque;
+
+    qdict = qobject_to_qdict(data);
+    monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
+
+    qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
+    monitor_printf(mon, " rd_bytes=%" PRId64
+                        " wr_bytes=%" PRId64
+                        " rd_operations=%" PRId64
+                        " wr_operations=%" PRId64
+                        "\n",
+                        qdict_get_int(qdict, "rd_bytes"),
+                        qdict_get_int(qdict, "wr_bytes"),
+                        qdict_get_int(qdict, "rd_operations"),
+                        qdict_get_int(qdict, "wr_operations"));
+}
+
+void bdrv_stats_print(Monitor *mon, const QObject *data)
+{
+    qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
+}
+
+static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
+{
+    QObject *res;
+    QDict *dict;
+
+    res = qobject_from_jsonf("{ 'stats': {"
+                             "'rd_bytes': %" PRId64 ","
+                             "'wr_bytes': %" PRId64 ","
+                             "'rd_operations': %" PRId64 ","
+                             "'wr_operations': %" PRId64 ","
+                             "'wr_highest_offset': %" PRId64
+                             "} }",
+                             bs->rd_bytes, bs->wr_bytes,
+                             bs->rd_ops, bs->wr_ops,
+                             bs->wr_highest_sector *
+                             (uint64_t)BDRV_SECTOR_SIZE);
+    dict  = qobject_to_qdict(res);
+
+    if (*bs->device_name) {
+        qdict_put(dict, "device", qstring_from_str(bs->device_name));
+    }
+
+    if (bs->file) {
+        QObject *parent = bdrv_info_stats_bs(bs->file);
+        qdict_put_obj(dict, "parent", parent);
+    }
+
+    return res;
+}
+
+void bdrv_info_stats(Monitor *mon, QObject **ret_data)
+{
+    QObject *obj;
+    QList *devices;
+    BlockDriverState *bs;
+
+    devices = qlist_new();
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        obj = bdrv_info_stats_bs(bs);
+        qlist_append_obj(devices, obj);
+    }
+
+    *ret_data = QOBJECT(devices);
+}
+
+const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
+{
+    if (bs->backing_hd && bs->backing_hd->encrypted)
+        return bs->backing_file;
+    else if (bs->encrypted)
+        return bs->filename;
+    else
+        return NULL;
+}
+
+void bdrv_get_backing_filename(BlockDriverState *bs,
+                               char *filename, int filename_size)
+{
+    if (!bs->backing_file) {
+        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;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
+
+    if (bs->dirty_bitmap) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+
+    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);
+}
+
+int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
+                      int64_t pos, int size)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_save_vmstate)
+        return drv->bdrv_save_vmstate(bs, buf, pos, size);
+    if (bs->file)
+        return bdrv_save_vmstate(bs->file, buf, pos, size);
+    return -ENOTSUP;
+}
+
+int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
+                      int64_t pos, int size)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_load_vmstate)
+        return drv->bdrv_load_vmstate(bs, buf, pos, size);
+    if (bs->file)
+        return bdrv_load_vmstate(bs->file, buf, pos, size);
+    return -ENOTSUP;
+}
+
+void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv || !drv->bdrv_debug_event) {
+        return;
+    }
+
+    return drv->bdrv_debug_event(bs, event);
+
+}
+
+/**************************************************************/
+/* handling of snapshots */
+
+int bdrv_can_snapshot(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+        return 0;
+    }
+
+    if (!drv->bdrv_snapshot_create) {
+        if (bs->file != NULL) {
+            return bdrv_can_snapshot(bs->file);
+        }
+        return 0;
+    }
+
+    return 1;
+}
+
+int bdrv_is_snapshot(BlockDriverState *bs)
+{
+    return !!(bs->open_flags & BDRV_O_SNAPSHOT);
+}
+
+BlockDriverState *bdrv_snapshots(void)
+{
+    BlockDriverState *bs;
+
+    if (bs_snapshots) {
+        return bs_snapshots;
+    }
+
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+        if (bdrv_can_snapshot(bs)) {
+            bs_snapshots = bs;
+            return bs;
+        }
+    }
+    return NULL;
+}
+
+int bdrv_snapshot_create(BlockDriverState *bs,
+                         QEMUSnapshotInfo *sn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_snapshot_create)
+        return drv->bdrv_snapshot_create(bs, sn_info);
+    if (bs->file)
+        return bdrv_snapshot_create(bs->file, sn_info);
+    return -ENOTSUP;
+}
+
+int bdrv_snapshot_goto(BlockDriverState *bs,
+                       const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    int ret, open_ret;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_snapshot_goto)
+        return drv->bdrv_snapshot_goto(bs, snapshot_id);
+
+    if (bs->file) {
+        drv->bdrv_close(bs);
+        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
+        open_ret = drv->bdrv_open(bs, bs->open_flags);
+        if (open_ret < 0) {
+            bdrv_delete(bs->file);
+            bs->drv = NULL;
+            return open_ret;
+        }
+        return ret;
+    }
+
+    return -ENOTSUP;
+}
+
+int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_snapshot_delete)
+        return drv->bdrv_snapshot_delete(bs, snapshot_id);
+    if (bs->file)
+        return bdrv_snapshot_delete(bs->file, snapshot_id);
+    return -ENOTSUP;
+}
+
+int bdrv_snapshot_list(BlockDriverState *bs,
+                       QEMUSnapshotInfo **psn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (drv->bdrv_snapshot_list)
+        return drv->bdrv_snapshot_list(bs, psn_info);
+    if (bs->file)
+        return bdrv_snapshot_list(bs->file, psn_info);
+    return -ENOTSUP;
+}
+
+int bdrv_snapshot_load_tmp(BlockDriverState *bs,
+        const char *snapshot_name)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (!bs->read_only) {
+        return -EINVAL;
+    }
+    if (drv->bdrv_snapshot_load_tmp) {
+        return drv->bdrv_snapshot_load_tmp(bs, snapshot_name);
+    }
+    return -ENOTSUP;
+}
+
+#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;
+}
+
+
+/**************************************************************/
+/* async I/Os */
+
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *qiov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+    BlockDriverAIOCB *ret;
+
+    trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
+
+    if (!drv)
+        return NULL;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return NULL;
+
+    ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
+                              cb, opaque);
+
+    if (ret) {
+	/* Update stats even though technically transfer has not happened. */
+	bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
+	bs->rd_ops ++;
+    }
+
+    return ret;
+}
+
+typedef struct BlockCompleteData {
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+    BlockDriverState *bs;
+    int64_t sector_num;
+    int nb_sectors;
+} BlockCompleteData;
+
+static void block_complete_cb(void *opaque, int ret)
+{
+    BlockCompleteData *b = opaque;
+
+    if (b->bs->dirty_bitmap) {
+        set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
+    }
+    b->cb(b->opaque, ret);
+    qemu_free(b);
+}
+
+static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
+
+    blkdata->bs = bs;
+    blkdata->cb = cb;
+    blkdata->opaque = opaque;
+    blkdata->sector_num = sector_num;
+    blkdata->nb_sectors = nb_sectors;
+
+    return blkdata;
+}
+
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *qiov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+    BlockDriverAIOCB *ret;
+    BlockCompleteData *blk_cb_data;
+
+    trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
+
+    if (!drv)
+        return NULL;
+    if (bs->read_only)
+        return NULL;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return NULL;
+
+    if (bs->dirty_bitmap) {
+        blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
+                                         opaque);
+        cb = &block_complete_cb;
+        opaque = blk_cb_data;
+    }
+
+    ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
+                               cb, opaque);
+
+    if (ret) {
+        /* Update stats even though technically transfer has not happened. */
+        bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
+        bs->wr_ops ++;
+        if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+            bs->wr_highest_sector = sector_num + nb_sectors - 1;
+        }
+    }
+
+    return ret;
+}
+
+
+typedef struct MultiwriteCB {
+    int error;
+    int num_requests;
+    int num_callbacks;
+    struct {
+        BlockDriverCompletionFunc *cb;
+        void *opaque;
+        QEMUIOVector *free_qiov;
+        void *free_buf;
+    } callbacks[];
+} MultiwriteCB;
+
+static void multiwrite_user_cb(MultiwriteCB *mcb)
+{
+    int i;
+
+    for (i = 0; i < mcb->num_callbacks; i++) {
+        mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
+        if (mcb->callbacks[i].free_qiov) {
+            qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
+        }
+        qemu_free(mcb->callbacks[i].free_qiov);
+        qemu_vfree(mcb->callbacks[i].free_buf);
+    }
+}
+
+static void multiwrite_cb(void *opaque, int ret)
+{
+    MultiwriteCB *mcb = opaque;
+
+    trace_multiwrite_cb(mcb, ret);
+
+    if (ret < 0 && !mcb->error) {
+        mcb->error = ret;
+    }
+
+    mcb->num_requests--;
+    if (mcb->num_requests == 0) {
+        multiwrite_user_cb(mcb);
+        qemu_free(mcb);
+    }
+}
+
+static int multiwrite_req_compare(const void *a, const void *b)
+{
+    const BlockRequest *req1 = a, *req2 = b;
+
+    /*
+     * Note that we can't simply subtract req2->sector from req1->sector
+     * here as that could overflow the return value.
+     */
+    if (req1->sector > req2->sector) {
+        return 1;
+    } else if (req1->sector < req2->sector) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/*
+ * Takes a bunch of requests and tries to merge them. Returns the number of
+ * requests that remain after merging.
+ */
+static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
+    int num_reqs, MultiwriteCB *mcb)
+{
+    int i, outidx;
+
+    // Sort requests by start sector
+    qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
+
+    // Check if adjacent requests touch the same clusters. If so, combine them,
+    // filling up gaps with zero sectors.
+    outidx = 0;
+    for (i = 1; i < num_reqs; i++) {
+        int merge = 0;
+        int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
+
+        // This handles the cases that are valid for all block drivers, namely
+        // exactly sequential writes and overlapping writes.
+        if (reqs[i].sector <= oldreq_last) {
+            merge = 1;
+        }
+
+        // The block driver may decide that it makes sense to combine requests
+        // even if there is a gap of some sectors between them. In this case,
+        // the gap is filled with zeros (therefore only applicable for yet
+        // unused space in format like qcow2).
+        if (!merge && bs->drv->bdrv_merge_requests) {
+            merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
+        }
+
+        if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
+            merge = 0;
+        }
+
+        if (merge) {
+            size_t size;
+            QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
+            qemu_iovec_init(qiov,
+                reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
+
+            // Add the first request to the merged one. If the requests are
+            // overlapping, drop the last sectors of the first request.
+            size = (reqs[i].sector - reqs[outidx].sector) << 9;
+            qemu_iovec_concat(qiov, reqs[outidx].qiov, size);
+
+            // We might need to add some zeros between the two requests
+            if (reqs[i].sector > oldreq_last) {
+                size_t zero_bytes = (reqs[i].sector - oldreq_last) << 9;
+                uint8_t *buf = qemu_blockalign(bs, zero_bytes);
+                memset(buf, 0, zero_bytes);
+                qemu_iovec_add(qiov, buf, zero_bytes);
+                mcb->callbacks[i].free_buf = buf;
+            }
+
+            // Add the second request
+            qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
+
+            reqs[outidx].nb_sectors = qiov->size >> 9;
+            reqs[outidx].qiov = qiov;
+
+            mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
+        } else {
+            outidx++;
+            reqs[outidx].sector     = reqs[i].sector;
+            reqs[outidx].nb_sectors = reqs[i].nb_sectors;
+            reqs[outidx].qiov       = reqs[i].qiov;
+        }
+    }
+
+    return outidx + 1;
+}
+
+/*
+ * Submit multiple AIO write requests at once.
+ *
+ * On success, the function returns 0 and all requests in the reqs array have
+ * been submitted. In error case this function returns -1, and any of the
+ * requests may or may not be submitted yet. In particular, this means that the
+ * callback will be called for some of the requests, for others it won't. The
+ * caller must check the error field of the BlockRequest to wait for the right
+ * callbacks (if error != 0, no callback will be called).
+ *
+ * The implementation may modify the contents of the reqs array, e.g. to merge
+ * requests. However, the fields opaque and error are left unmodified as they
+ * are used to signal failure for a single request to the caller.
+ */
+int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
+{
+    BlockDriverAIOCB *acb;
+    MultiwriteCB *mcb;
+    int i;
+
+    /* don't submit writes if we don't have a medium */
+    if (bs->drv == NULL) {
+        for (i = 0; i < num_reqs; i++) {
+            reqs[i].error = -ENOMEDIUM;
+        }
+        return -1;
+    }
+
+    if (num_reqs == 0) {
+        return 0;
+    }
+
+    // Create MultiwriteCB structure
+    mcb = qemu_mallocz(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
+    mcb->num_requests = 0;
+    mcb->num_callbacks = num_reqs;
+
+    for (i = 0; i < num_reqs; i++) {
+        mcb->callbacks[i].cb = reqs[i].cb;
+        mcb->callbacks[i].opaque = reqs[i].opaque;
+    }
+
+    // Check for mergable requests
+    num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
+
+    trace_bdrv_aio_multiwrite(mcb, mcb->num_callbacks, num_reqs);
+
+    /*
+     * Run the aio requests. As soon as one request can't be submitted
+     * successfully, fail all requests that are not yet submitted (we must
+     * return failure for all requests anyway)
+     *
+     * num_requests cannot be set to the right value immediately: If
+     * bdrv_aio_writev fails for some request, num_requests would be too high
+     * and therefore multiwrite_cb() would never recognize the multiwrite
+     * request as completed. We also cannot use the loop variable i to set it
+     * when the first request fails because the callback may already have been
+     * called for previously submitted requests. Thus, num_requests must be
+     * incremented for each request that is submitted.
+     *
+     * The problem that callbacks may be called early also means that we need
+     * to take care that num_requests doesn't become 0 before all requests are
+     * submitted - multiwrite_cb() would consider the multiwrite request
+     * completed. A dummy request that is "completed" by a manual call to
+     * multiwrite_cb() takes care of this.
+     */
+    mcb->num_requests = 1;
+
+    // Run the aio requests
+    for (i = 0; i < num_reqs; i++) {
+        mcb->num_requests++;
+        acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
+            reqs[i].nb_sectors, multiwrite_cb, mcb);
+
+        if (acb == NULL) {
+            // We can only fail the whole thing if no request has been
+            // submitted yet. Otherwise we'll wait for the submitted AIOs to
+            // complete and report the error in the callback.
+            if (i == 0) {
+                trace_bdrv_aio_multiwrite_earlyfail(mcb);
+                goto fail;
+            } else {
+                trace_bdrv_aio_multiwrite_latefail(mcb, i);
+                multiwrite_cb(mcb, -EIO);
+                break;
+            }
+        }
+    }
+
+    /* Complete the dummy request */
+    multiwrite_cb(mcb, 0);
+
+    return 0;
+
+fail:
+    for (i = 0; i < mcb->num_callbacks; i++) {
+        reqs[i].error = -EIO;
+    }
+    qemu_free(mcb);
+    return -1;
+}
+
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    trace_bdrv_aio_flush(bs, opaque);
+
+    if (bs->open_flags & BDRV_O_NO_FLUSH) {
+        return bdrv_aio_noop_em(bs, cb, opaque);
+    }
+
+    if (!drv)
+        return NULL;
+    return drv->bdrv_aio_flush(bs, cb, opaque);
+}
+
+void bdrv_aio_cancel(BlockDriverAIOCB *acb)
+{
+    acb->pool->cancel(acb);
+}
+
+
+/**************************************************************/
+/* async block device emulation */
+
+typedef struct BlockDriverAIOCBSync {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+    /* vector translation state */
+    QEMUIOVector *qiov;
+    uint8_t *bounce;
+    int is_write;
+} BlockDriverAIOCBSync;
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+    BlockDriverAIOCBSync *acb =
+        container_of(blockacb, BlockDriverAIOCBSync, common);
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+    qemu_aio_release(acb);
+}
+
+static AIOPool bdrv_em_aio_pool = {
+    .aiocb_size         = sizeof(BlockDriverAIOCBSync),
+    .cancel             = bdrv_aio_cancel_em,
+};
+
+static void bdrv_aio_bh_cb(void *opaque)
+{
+    BlockDriverAIOCBSync *acb = opaque;
+
+    if (!acb->is_write)
+        qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
+    qemu_vfree(acb->bounce);
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov,
+                                            int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque,
+                                            int is_write)
+
+{
+    BlockDriverAIOCBSync *acb;
+
+    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
+    acb->is_write = is_write;
+    acb->qiov = qiov;
+    acb->bounce = qemu_blockalign(bs, qiov->size);
+
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+
+    if (is_write) {
+        qemu_iovec_to_buffer(acb->qiov, acb->bounce);
+        acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
+    } else {
+        acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
+    }
+
+    qemu_bh_schedule(acb->bh);
+
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+}
+
+static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+}
+
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
+
+    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
+    acb->is_write = 1; /* don't bounce in the completion hadler */
+    acb->qiov = NULL;
+    acb->bounce = NULL;
+    acb->ret = 0;
+
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+
+    bdrv_flush(bs);
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
+
+    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
+    acb->is_write = 1; /* don't bounce in the completion handler */
+    acb->qiov = NULL;
+    acb->bounce = NULL;
+    acb->ret = 0;
+
+    if (!acb->bh) {
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    }
+
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+/**************************************************************/
+/* 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;
+    struct iovec iov;
+    QEMUIOVector qiov;
+
+    async_context_push();
+
+    async_ret = NOT_DONE;
+    iov.iov_base = (void *)buf;
+    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
+        bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        async_ret = -1;
+        goto fail;
+    }
+
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+
+
+fail:
+    async_context_pop();
+    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;
+    struct iovec iov;
+    QEMUIOVector qiov;
+
+    async_context_push();
+
+    async_ret = NOT_DONE;
+    iov.iov_base = (void *)buf;
+    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
+        bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        async_ret = -1;
+        goto fail;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+
+fail:
+    async_context_pop();
+    return async_ret;
+}
+
+void bdrv_init(void)
+{
+    module_call_init(MODULE_INIT_BLOCK);
+}
+
+void bdrv_init_with_whitelist(void)
+{
+    use_bdrv_whitelist = 1;
+    bdrv_init();
+}
+
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+                   BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCB *acb;
+
+    if (pool->free_aiocb) {
+        acb = pool->free_aiocb;
+        pool->free_aiocb = acb->next;
+    } else {
+        acb = qemu_mallocz(pool->aiocb_size);
+        acb->pool = pool;
+    }
+    acb->bs = bs;
+    acb->cb = cb;
+    acb->opaque = opaque;
+    return acb;
+}
+
+void qemu_aio_release(void *p)
+{
+    BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
+    AIOPool *pool = acb->pool;
+    acb->next = pool->free_aiocb;
+    pool->free_aiocb = acb;
+}
+
+/**************************************************************/
+/* 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 !bs->tray_open;
+    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
+ */
+int bdrv_eject(BlockDriverState *bs, int eject_flag)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+
+    if (bs->locked) {
+        return -EBUSY;
+    }
+
+    if (!drv || !drv->bdrv_eject) {
+        ret = -ENOTSUP;
+    } else {
+        ret = drv->bdrv_eject(bs, eject_flag);
+    }
+    if (ret == -ENOTSUP) {
+        ret = 0;
+    }
+    if (ret >= 0) {
+        bs->tray_open = eject_flag;
+    }
+
+    return ret;
+}
+
+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;
+
+    trace_bdrv_set_locked(bs, locked);
+
+    bs->locked = locked;
+    if (drv && drv->bdrv_set_locked) {
+        drv->bdrv_set_locked(bs, locked);
+    }
+}
+
+/* needed for generic scsi interface */
+
+int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (drv && drv->bdrv_ioctl)
+        return drv->bdrv_ioctl(bs, req, buf);
+    return -ENOTSUP;
+}
+
+BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (drv && drv->bdrv_aio_ioctl)
+        return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque);
+    return NULL;
+}
+
+
+
+void *qemu_blockalign(BlockDriverState *bs, size_t size)
+{
+    return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
+}
+
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
+{
+    int64_t bitmap_size;
+
+    bs->dirty_count = 0;
+    if (enable) {
+        if (!bs->dirty_bitmap) {
+            bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
+                    BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+            bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
+
+            bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+        }
+    } else {
+        if (bs->dirty_bitmap) {
+            qemu_free(bs->dirty_bitmap);
+            bs->dirty_bitmap = NULL;
+        }
+    }
+}
+
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
+{
+    int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    if (bs->dirty_bitmap &&
+        (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
+        return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+            (1UL << (chunk % (sizeof(unsigned long) * 8))));
+    } else {
+        return 0;
+    }
+}
+
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+                      int nr_sectors)
+{
+    set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
+}
+
+int64_t bdrv_get_dirty_count(BlockDriverState *bs)
+{
+    return bs->dirty_count;
+}
+
+void bdrv_set_in_use(BlockDriverState *bs, int in_use)
+{
+    assert(bs->in_use != in_use);
+    bs->in_use = in_use;
+}
+
+int bdrv_in_use(BlockDriverState *bs)
+{
+    return bs->in_use;
+}
+
+int bdrv_img_create(const char *filename, const char *fmt,
+                    const char *base_filename, const char *base_fmt,
+                    char *options, uint64_t img_size, int flags)
+{
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *backing_fmt, *backing_file, *size;
+    BlockDriverState *bs = NULL;
+    BlockDriver *drv, *proto_drv;
+    BlockDriver *backing_drv = NULL;
+    int ret = 0;
+
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(fmt);
+    if (!drv) {
+        error_report("Unknown file format '%s'", fmt);
+        ret = -EINVAL;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        error_report("Unknown protocol '%s'", filename);
+        ret = -EINVAL;
+        goto out;
+    }
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+
+    /* Create parameter list with default values */
+    param = parse_option_parameters("", create_options, param);
+
+    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
+
+    /* Parse -o options */
+    if (options) {
+        param = parse_option_parameters(options, create_options, param);
+        if (param == NULL) {
+            error_report("Invalid options for file format '%s'.", fmt);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    if (base_filename) {
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
+                                 base_filename)) {
+            error_report("Backing file not supported for file format '%s'",
+                         fmt);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    if (base_fmt) {
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+            error_report("Backing file format not supported for file "
+                         "format '%s'", fmt);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    if (backing_file && backing_file->value.s) {
+        if (!strcmp(filename, backing_file->value.s)) {
+            error_report("Error: Trying to create an image with the "
+                         "same filename as the backing file");
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
+    if (backing_fmt && backing_fmt->value.s) {
+        backing_drv = bdrv_find_format(backing_fmt->value.s);
+        if (!backing_drv) {
+            error_report("Unknown backing file format '%s'",
+                         backing_fmt->value.s);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    // The size for the image must always be specified, with one exception:
+    // If we are using a backing file, we can obtain the size from there
+    size = get_option_parameter(param, BLOCK_OPT_SIZE);
+    if (size && size->value.n == -1) {
+        if (backing_file && backing_file->value.s) {
+            uint64_t size;
+            char buf[32];
+
+            bs = bdrv_new("");
+
+            ret = bdrv_open(bs, backing_file->value.s, flags, backing_drv);
+            if (ret < 0) {
+                error_report("Could not open '%s'", backing_file->value.s);
+                goto out;
+            }
+            bdrv_get_geometry(bs, &size);
+            size *= 512;
+
+            snprintf(buf, sizeof(buf), "%" PRId64, size);
+            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
+        } else {
+            error_report("Image creation needs a size parameter");
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    printf("Formatting '%s', fmt=%s ", filename, fmt);
+    print_option_parameters(param);
+    puts("");
+
+    ret = bdrv_create(drv, filename, param);
+
+    if (ret < 0) {
+        if (ret == -ENOTSUP) {
+            error_report("Formatting or formatting option not supported for "
+                         "file format '%s'", fmt);
+        } else if (ret == -EFBIG) {
+            error_report("The image size is too large for file format '%s'",
+                         fmt);
+        } else {
+            error_report("%s: error while creating %s: %s", filename, fmt,
+                         strerror(-ret));
+        }
+    }
+
+out:
+    free_option_parameters(create_options);
+    free_option_parameters(param);
+
+    if (bs) {
+        bdrv_delete(bs);
+    }
+
+    return ret;
+}
diff --git a/qemu-0.15.x/block.h b/qemu-0.15.x/block.h
new file mode 100644
index 0000000..59cc410
--- /dev/null
+++ b/qemu-0.15.x/block.h
@@ -0,0 +1,305 @@
+#ifndef BLOCK_H
+#define BLOCK_H
+
+#include "qemu-aio.h"
+#include "qemu-common.h"
+#include "qemu-option.h"
+#include "qobject.h"
+
+/* block.c */
+typedef struct BlockDriver BlockDriver;
+
+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_RDWR        0x0002
+#define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes in a snapshot */
+#define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */
+#define BDRV_O_CACHE_WB    0x0040 /* use write-back caching */
+#define BDRV_O_NATIVE_AIO  0x0080 /* use native AIO instead of the thread pool */
+#define BDRV_O_NO_BACKING  0x0100 /* don't open the backing file */
+#define BDRV_O_NO_FLUSH    0x0200 /* disable flushing on this disk */
+
+#define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
+
+#define BDRV_SECTOR_BITS   9
+#define BDRV_SECTOR_SIZE   (1ULL << BDRV_SECTOR_BITS)
+#define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1)
+
+typedef enum {
+    BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
+    BLOCK_ERR_STOP_ANY
+} BlockErrorAction;
+
+typedef enum {
+    BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
+} BlockMonEventAction;
+
+void bdrv_mon_event(const BlockDriverState *bdrv,
+                    BlockMonEventAction action, int is_read);
+void bdrv_info_print(Monitor *mon, const QObject *data);
+void bdrv_info(Monitor *mon, QObject **ret_data);
+void bdrv_stats_print(Monitor *mon, const QObject *data);
+void bdrv_info_stats(Monitor *mon, QObject **ret_data);
+
+void bdrv_init(void);
+void bdrv_init_with_whitelist(void);
+BlockDriver *bdrv_find_protocol(const char *filename);
+BlockDriver *bdrv_find_format(const char *format_name);
+BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options);
+int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
+BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_make_anon(BlockDriverState *bs);
+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,
+              BlockDriver *drv);
+void bdrv_close(BlockDriverState *bs);
+int bdrv_attach(BlockDriverState *bs, DeviceState *qdev);
+void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
+DeviceState *bdrv_get_attached(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_pwrite_sync(BlockDriverState *bs, int64_t offset,
+    const void *buf, int count);
+int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors);
+int bdrv_truncate(BlockDriverState *bs, int64_t offset);
+int64_t bdrv_getlength(BlockDriverState *bs);
+int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
+void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
+int bdrv_commit(BlockDriverState *bs);
+void bdrv_commit_all(void);
+int bdrv_change_backing_file(BlockDriverState *bs,
+    const char *backing_file, const char *backing_fmt);
+void bdrv_register(BlockDriver *bdrv);
+
+
+typedef struct BdrvCheckResult {
+    int corruptions;
+    int leaks;
+    int check_errors;
+} BdrvCheckResult;
+
+int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
+
+/* async block I/O */
+typedef struct BlockDriverAIOCB BlockDriverAIOCB;
+typedef void BlockDriverCompletionFunc(void *opaque, int ret);
+typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
+                                     int sector_num);
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *iov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *iov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+void bdrv_aio_cancel(BlockDriverAIOCB *acb);
+
+typedef struct BlockRequest {
+    /* Fields to be filled by multiwrite caller */
+    int64_t sector;
+    int nb_sectors;
+    QEMUIOVector *qiov;
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+
+    /* Filled by multiwrite implementation */
+    int error;
+} BlockRequest;
+
+int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs,
+    int num_reqs);
+
+/* sg packet commands */
+int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
+BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+/* Ensure contents are flushed to disk.  */
+int bdrv_flush(BlockDriverState *bs);
+void bdrv_flush_all(void);
+void bdrv_close_all(void);
+
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
+int bdrv_has_zero_init(BlockDriverState *bs);
+int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
+                      int *pnum);
+
+#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_translation_hint(BlockDriverState *bs, int translation);
+void bdrv_get_geometry_hint(BlockDriverState *bs,
+                            int *pcyls, int *pheads, int *psecs);
+typedef enum FDriveType {
+    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
+    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
+    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
+    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
+} FDriveType;
+
+void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
+                                   int *max_track, int *last_sect,
+                                   FDriveType drive_in, FDriveType *drive);
+int bdrv_get_translation_hint(BlockDriverState *bs);
+void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
+                       BlockErrorAction on_write_error);
+BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
+void bdrv_set_removable(BlockDriverState *bs, int removable);
+int bdrv_is_removable(BlockDriverState *bs);
+int bdrv_is_read_only(BlockDriverState *bs);
+int bdrv_is_sg(BlockDriverState *bs);
+int bdrv_enable_write_cache(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);
+int bdrv_eject(BlockDriverState *bs, int eject_flag);
+void bdrv_set_change_cb(BlockDriverState *bs,
+                        void (*change_cb)(void *opaque, int reason),
+                        void *opaque);
+void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
+BlockDriverState *bdrv_find(const char *name);
+BlockDriverState *bdrv_next(BlockDriverState *bs);
+void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
+                  void *opaque);
+int bdrv_is_encrypted(BlockDriverState *bs);
+int bdrv_key_required(BlockDriverState *bs);
+int bdrv_set_key(BlockDriverState *bs, const char *key);
+int bdrv_query_missing_keys(void);
+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);
+
+const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
+void bdrv_get_backing_filename(BlockDriverState *bs,
+                               char *filename, int filename_size);
+int bdrv_can_snapshot(BlockDriverState *bs);
+int bdrv_is_snapshot(BlockDriverState *bs);
+BlockDriverState *bdrv_snapshots(void);
+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_snapshot_load_tmp(BlockDriverState *bs,
+                           const char *snapshot_name);
+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);
+
+int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
+                      int64_t pos, int size);
+
+int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
+                      int64_t pos, int size);
+
+int bdrv_img_create(const char *filename, const char *fmt,
+                    const char *base_filename, const char *base_fmt,
+                    char *options, uint64_t img_size, int flags);
+
+#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
+
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+                      int nr_sectors);
+int64_t bdrv_get_dirty_count(BlockDriverState *bs);
+
+void bdrv_set_in_use(BlockDriverState *bs, int in_use);
+int bdrv_in_use(BlockDriverState *bs);
+
+typedef enum {
+    BLKDBG_L1_UPDATE,
+
+    BLKDBG_L1_GROW_ALLOC_TABLE,
+    BLKDBG_L1_GROW_WRITE_TABLE,
+    BLKDBG_L1_GROW_ACTIVATE_TABLE,
+
+    BLKDBG_L2_LOAD,
+    BLKDBG_L2_UPDATE,
+    BLKDBG_L2_UPDATE_COMPRESSED,
+    BLKDBG_L2_ALLOC_COW_READ,
+    BLKDBG_L2_ALLOC_WRITE,
+
+    BLKDBG_READ,
+    BLKDBG_READ_AIO,
+    BLKDBG_READ_BACKING,
+    BLKDBG_READ_BACKING_AIO,
+    BLKDBG_READ_COMPRESSED,
+
+    BLKDBG_WRITE_AIO,
+    BLKDBG_WRITE_COMPRESSED,
+
+    BLKDBG_VMSTATE_LOAD,
+    BLKDBG_VMSTATE_SAVE,
+
+    BLKDBG_COW_READ,
+    BLKDBG_COW_WRITE,
+
+    BLKDBG_REFTABLE_LOAD,
+    BLKDBG_REFTABLE_GROW,
+
+    BLKDBG_REFBLOCK_LOAD,
+    BLKDBG_REFBLOCK_UPDATE,
+    BLKDBG_REFBLOCK_UPDATE_PART,
+    BLKDBG_REFBLOCK_ALLOC,
+    BLKDBG_REFBLOCK_ALLOC_HOOKUP,
+    BLKDBG_REFBLOCK_ALLOC_WRITE,
+    BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
+    BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
+    BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
+
+    BLKDBG_CLUSTER_ALLOC,
+    BLKDBG_CLUSTER_ALLOC_BYTES,
+    BLKDBG_CLUSTER_FREE,
+
+    BLKDBG_EVENT_MAX,
+} BlkDebugEvent;
+
+#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
+void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
+
+#endif
diff --git a/qemu-0.15.x/block/blkdebug.c b/qemu-0.15.x/block/blkdebug.c
new file mode 100644
index 0000000..cd9eb80
--- /dev/null
+++ b/qemu-0.15.x/block/blkdebug.c
@@ -0,0 +1,471 @@
+/*
+ * Block protocol for I/O error injection
+ *
+ * Copyright (c) 2010 Kevin Wolf <kwolf at redhat.com>
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+typedef struct BlkdebugVars {
+    int state;
+
+    /* If inject_errno != 0, an error is injected for requests */
+    int inject_errno;
+
+    /* Decides if all future requests fail (false) or only the next one and
+     * after the next request inject_errno is reset to 0 (true) */
+    bool inject_once;
+
+    /* Decides if aio_readv/writev fails right away (true) or returns an error
+     * return value only in the callback (false) */
+    bool inject_immediately;
+} BlkdebugVars;
+
+typedef struct BDRVBlkdebugState {
+    BlkdebugVars vars;
+    QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
+} BDRVBlkdebugState;
+
+typedef struct BlkdebugAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} BlkdebugAIOCB;
+
+static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
+
+static AIOPool blkdebug_aio_pool = {
+    .aiocb_size = sizeof(BlkdebugAIOCB),
+    .cancel     = blkdebug_aio_cancel,
+};
+
+enum {
+    ACTION_INJECT_ERROR,
+    ACTION_SET_STATE,
+};
+
+typedef struct BlkdebugRule {
+    BlkDebugEvent event;
+    int action;
+    int state;
+    union {
+        struct {
+            int error;
+            int immediately;
+            int once;
+        } inject;
+        struct {
+            int new_state;
+        } set_state;
+    } options;
+    QLIST_ENTRY(BlkdebugRule) next;
+} BlkdebugRule;
+
+static QemuOptsList inject_error_opts = {
+    .name = "inject-error",
+    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
+    .desc = {
+        {
+            .name = "event",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "errno",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "once",
+            .type = QEMU_OPT_BOOL,
+        },
+        {
+            .name = "immediately",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList set_state_opts = {
+    .name = "set-state",
+    .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
+    .desc = {
+        {
+            .name = "event",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "new_state",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList *config_groups[] = {
+    &inject_error_opts,
+    &set_state_opts,
+    NULL
+};
+
+static const char *event_names[BLKDBG_EVENT_MAX] = {
+    [BLKDBG_L1_UPDATE]                      = "l1_update",
+    [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
+    [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
+    [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
+
+    [BLKDBG_L2_LOAD]                        = "l2_load",
+    [BLKDBG_L2_UPDATE]                      = "l2_update",
+    [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
+    [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
+    [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
+
+    [BLKDBG_READ]                           = "read",
+    [BLKDBG_READ_AIO]                       = "read_aio",
+    [BLKDBG_READ_BACKING]                   = "read_backing",
+    [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
+    [BLKDBG_READ_COMPRESSED]                = "read_compressed",
+
+    [BLKDBG_WRITE_AIO]                      = "write_aio",
+    [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
+
+    [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
+    [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
+
+    [BLKDBG_COW_READ]                       = "cow_read",
+    [BLKDBG_COW_WRITE]                      = "cow_write",
+
+    [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
+    [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
+
+    [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
+    [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
+    [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
+    [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
+    [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
+    [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
+    [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
+
+    [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
+    [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
+    [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
+};
+
+static int get_event_by_name(const char *name, BlkDebugEvent *event)
+{
+    int i;
+
+    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+        if (!strcmp(event_names[i], name)) {
+            *event = i;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+struct add_rule_data {
+    BDRVBlkdebugState *s;
+    int action;
+};
+
+static int add_rule(QemuOpts *opts, void *opaque)
+{
+    struct add_rule_data *d = opaque;
+    BDRVBlkdebugState *s = d->s;
+    const char* event_name;
+    BlkDebugEvent event;
+    struct BlkdebugRule *rule;
+
+    /* Find the right event for the rule */
+    event_name = qemu_opt_get(opts, "event");
+    if (!event_name || get_event_by_name(event_name, &event) < 0) {
+        return -1;
+    }
+
+    /* Set attributes common for all actions */
+    rule = qemu_mallocz(sizeof(*rule));
+    *rule = (struct BlkdebugRule) {
+        .event  = event,
+        .action = d->action,
+        .state  = qemu_opt_get_number(opts, "state", 0),
+    };
+
+    /* Parse action-specific options */
+    switch (d->action) {
+    case ACTION_INJECT_ERROR:
+        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
+        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
+        rule->options.inject.immediately =
+            qemu_opt_get_bool(opts, "immediately", 0);
+        break;
+
+    case ACTION_SET_STATE:
+        rule->options.set_state.new_state =
+            qemu_opt_get_number(opts, "new_state", 0);
+        break;
+    };
+
+    /* Add the rule */
+    QLIST_INSERT_HEAD(&s->rules[event], rule, next);
+
+    return 0;
+}
+
+static int read_config(BDRVBlkdebugState *s, const char *filename)
+{
+    FILE *f;
+    int ret;
+    struct add_rule_data d;
+
+    f = fopen(filename, "r");
+    if (f == NULL) {
+        return -errno;
+    }
+
+    ret = qemu_config_parse(f, config_groups, filename);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    d.s = s;
+    d.action = ACTION_INJECT_ERROR;
+    qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
+
+    d.action = ACTION_SET_STATE;
+    qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
+
+    ret = 0;
+fail:
+    qemu_opts_reset(&inject_error_opts);
+    qemu_opts_reset(&set_state_opts);
+    fclose(f);
+    return ret;
+}
+
+/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
+static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    int ret;
+    char *config, *c;
+
+    /* Parse the blkdebug: prefix */
+    if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
+        return -EINVAL;
+    }
+    filename += strlen("blkdebug:");
+
+    /* Read rules from config file */
+    c = strchr(filename, ':');
+    if (c == NULL) {
+        return -EINVAL;
+    }
+
+    config = strdup(filename);
+    config[c - filename] = '\0';
+    ret = read_config(s, config);
+    free(config);
+    if (ret < 0) {
+        return ret;
+    }
+    filename = c + 1;
+
+    /* Set initial state */
+    s->vars.state = 1;
+
+    /* Open the backing file */
+    ret = bdrv_file_open(&bs->file, filename, flags);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static void error_callback_bh(void *opaque)
+{
+    struct BlkdebugAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_aio_release(acb);
+}
+
+static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    int error = s->vars.inject_errno;
+    struct BlkdebugAIOCB *acb;
+    QEMUBH *bh;
+
+    if (s->vars.inject_once) {
+        s->vars.inject_errno = 0;
+    }
+
+    if (s->vars.inject_immediately) {
+        return NULL;
+    }
+
+    acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
+    acb->ret = -error;
+
+    bh = qemu_bh_new(error_callback_bh, acb);
+    acb->bh = bh;
+    qemu_bh_schedule(bh);
+
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+
+    if (s->vars.inject_errno) {
+        return inject_error(bs, cb, opaque);
+    }
+
+    BlockDriverAIOCB *acb =
+        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+    return acb;
+}
+
+static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+
+    if (s->vars.inject_errno) {
+        return inject_error(bs, cb, opaque);
+    }
+
+    BlockDriverAIOCB *acb =
+        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+    return acb;
+}
+
+static void blkdebug_close(BlockDriverState *bs)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    BlkdebugRule *rule, *next;
+    int i;
+
+    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
+            QLIST_REMOVE(rule, next);
+            qemu_free(rule);
+        }
+    }
+}
+
+static int blkdebug_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
+    BlkdebugVars *old_vars)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    BlkdebugVars *vars = &s->vars;
+
+    /* Only process rules for the current state */
+    if (rule->state && rule->state != old_vars->state) {
+        return;
+    }
+
+    /* Take the action */
+    switch (rule->action) {
+    case ACTION_INJECT_ERROR:
+        vars->inject_errno       = rule->options.inject.error;
+        vars->inject_once        = rule->options.inject.once;
+        vars->inject_immediately = rule->options.inject.immediately;
+        break;
+
+    case ACTION_SET_STATE:
+        vars->state              = rule->options.set_state.new_state;
+        break;
+    }
+}
+
+static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+{
+    BDRVBlkdebugState *s = bs->opaque;
+    struct BlkdebugRule *rule;
+    BlkdebugVars old_vars = s->vars;
+
+    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
+
+    QLIST_FOREACH(rule, &s->rules[event], next) {
+        process_rule(bs, rule, &old_vars);
+    }
+}
+
+static BlockDriver bdrv_blkdebug = {
+    .format_name        = "blkdebug",
+    .protocol_name      = "blkdebug",
+
+    .instance_size      = sizeof(BDRVBlkdebugState),
+
+    .bdrv_file_open     = blkdebug_open,
+    .bdrv_close         = blkdebug_close,
+    .bdrv_flush         = blkdebug_flush,
+
+    .bdrv_aio_readv     = blkdebug_aio_readv,
+    .bdrv_aio_writev    = blkdebug_aio_writev,
+    .bdrv_aio_flush     = blkdebug_aio_flush,
+
+    .bdrv_debug_event   = blkdebug_debug_event,
+};
+
+static void bdrv_blkdebug_init(void)
+{
+    bdrv_register(&bdrv_blkdebug);
+}
+
+block_init(bdrv_blkdebug_init);
diff --git a/qemu-0.15.x/block/blkverify.c b/qemu-0.15.x/block/blkverify.c
new file mode 100644
index 0000000..c7522b4
--- /dev/null
+++ b/qemu-0.15.x/block/blkverify.c
@@ -0,0 +1,383 @@
+/*
+ * Block protocol for block driver correctness testing
+ *
+ * Copyright (C) 2010 IBM, Corp.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdarg.h>
+#include "qemu_socket.h" /* for EINPROGRESS on Windows */
+#include "block_int.h"
+
+typedef struct {
+    BlockDriverState *test_file;
+} BDRVBlkverifyState;
+
+typedef struct BlkverifyAIOCB BlkverifyAIOCB;
+struct BlkverifyAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+
+    /* Request metadata */
+    bool is_write;
+    int64_t sector_num;
+    int nb_sectors;
+
+    int ret;                    /* first completed request's result */
+    unsigned int done;          /* completion counter */
+    bool *finished;             /* completion signal for cancel */
+
+    QEMUIOVector *qiov;         /* user I/O vector */
+    QEMUIOVector raw_qiov;      /* cloned I/O vector for raw file */
+    void *buf;                  /* buffer for raw file I/O */
+
+    void (*verify)(BlkverifyAIOCB *acb);
+};
+
+static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb;
+    bool finished = false;
+
+    /* Wait until request completes, invokes its callback, and frees itself */
+    acb->finished = &finished;
+    while (!finished) {
+        qemu_aio_wait();
+    }
+}
+
+static AIOPool blkverify_aio_pool = {
+    .aiocb_size         = sizeof(BlkverifyAIOCB),
+    .cancel             = blkverify_aio_cancel,
+};
+
+static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
+                                             const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
+            acb->is_write ? "write" : "read", acb->sector_num,
+            acb->nb_sectors);
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(1);
+}
+
+/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
+static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+    int ret;
+    char *raw, *c;
+
+    /* Parse the blkverify: prefix */
+    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
+        return -EINVAL;
+    }
+    filename += strlen("blkverify:");
+
+    /* Parse the raw image filename */
+    c = strchr(filename, ':');
+    if (c == NULL) {
+        return -EINVAL;
+    }
+
+    raw = strdup(filename);
+    raw[c - filename] = '\0';
+    ret = bdrv_file_open(&bs->file, raw, flags);
+    free(raw);
+    if (ret < 0) {
+        return ret;
+    }
+    filename = c + 1;
+
+    /* Open the test file */
+    s->test_file = bdrv_new("");
+    ret = bdrv_open(s->test_file, filename, flags, NULL);
+    if (ret < 0) {
+        bdrv_delete(s->test_file);
+        s->test_file = NULL;
+        return ret;
+    }
+
+    return 0;
+}
+
+static void blkverify_close(BlockDriverState *bs)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+
+    bdrv_delete(s->test_file);
+    s->test_file = NULL;
+}
+
+static int blkverify_flush(BlockDriverState *bs)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+
+    /* Only flush test file, the raw file is not important */
+    return bdrv_flush(s->test_file);
+}
+
+static int64_t blkverify_getlength(BlockDriverState *bs)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+
+    return bdrv_getlength(s->test_file);
+}
+
+/**
+ * Check that I/O vector contents are identical
+ *
+ * @a:          I/O vector
+ * @b:          I/O vector
+ * @ret:        Offset to first mismatching byte or -1 if match
+ */
+static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
+{
+    int i;
+    ssize_t offset = 0;
+
+    assert(a->niov == b->niov);
+    for (i = 0; i < a->niov; i++) {
+        size_t len = 0;
+        uint8_t *p = (uint8_t *)a->iov[i].iov_base;
+        uint8_t *q = (uint8_t *)b->iov[i].iov_base;
+
+        assert(a->iov[i].iov_len == b->iov[i].iov_len);
+        while (len < a->iov[i].iov_len && *p++ == *q++) {
+            len++;
+        }
+
+        offset += len;
+
+        if (len != a->iov[i].iov_len) {
+            return offset;
+        }
+    }
+    return -1;
+}
+
+typedef struct {
+    int src_index;
+    struct iovec *src_iov;
+    void *dest_base;
+} IOVectorSortElem;
+
+static int sortelem_cmp_src_base(const void *a, const void *b)
+{
+    const IOVectorSortElem *elem_a = a;
+    const IOVectorSortElem *elem_b = b;
+
+    /* Don't overflow */
+    if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
+        return -1;
+    } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int sortelem_cmp_src_index(const void *a, const void *b)
+{
+    const IOVectorSortElem *elem_a = a;
+    const IOVectorSortElem *elem_b = b;
+
+    return elem_a->src_index - elem_b->src_index;
+}
+
+/**
+ * Copy contents of I/O vector
+ *
+ * The relative relationships of overlapping iovecs are preserved.  This is
+ * necessary to ensure identical semantics in the cloned I/O vector.
+ */
+static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
+                                  void *buf)
+{
+    IOVectorSortElem sortelems[src->niov];
+    void *last_end;
+    int i;
+
+    /* Sort by source iovecs by base address */
+    for (i = 0; i < src->niov; i++) {
+        sortelems[i].src_index = i;
+        sortelems[i].src_iov = &src->iov[i];
+    }
+    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
+
+    /* Allocate buffer space taking into account overlapping iovecs */
+    last_end = NULL;
+    for (i = 0; i < src->niov; i++) {
+        struct iovec *cur = sortelems[i].src_iov;
+        ptrdiff_t rewind = 0;
+
+        /* Detect overlap */
+        if (last_end && last_end > cur->iov_base) {
+            rewind = last_end - cur->iov_base;
+        }
+
+        sortelems[i].dest_base = buf - rewind;
+        buf += cur->iov_len - MIN(rewind, cur->iov_len);
+        last_end = MAX(cur->iov_base + cur->iov_len, last_end);
+    }
+
+    /* Sort by source iovec index and build destination iovec */
+    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
+    for (i = 0; i < src->niov; i++) {
+        qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
+    }
+}
+
+static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
+                                         int64_t sector_num, QEMUIOVector *qiov,
+                                         int nb_sectors,
+                                         BlockDriverCompletionFunc *cb,
+                                         void *opaque)
+{
+    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
+
+    acb->bh = NULL;
+    acb->is_write = is_write;
+    acb->sector_num = sector_num;
+    acb->nb_sectors = nb_sectors;
+    acb->ret = -EINPROGRESS;
+    acb->done = 0;
+    acb->qiov = qiov;
+    acb->buf = NULL;
+    acb->verify = NULL;
+    acb->finished = NULL;
+    return acb;
+}
+
+static void blkverify_aio_bh(void *opaque)
+{
+    BlkverifyAIOCB *acb = opaque;
+
+    qemu_bh_delete(acb->bh);
+    if (acb->buf) {
+        qemu_iovec_destroy(&acb->raw_qiov);
+        qemu_vfree(acb->buf);
+    }
+    acb->common.cb(acb->common.opaque, acb->ret);
+    if (acb->finished) {
+        *acb->finished = true;
+    }
+    qemu_aio_release(acb);
+}
+
+static void blkverify_aio_cb(void *opaque, int ret)
+{
+    BlkverifyAIOCB *acb = opaque;
+
+    switch (++acb->done) {
+    case 1:
+        acb->ret = ret;
+        break;
+
+    case 2:
+        if (acb->ret != ret) {
+            blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
+        }
+
+        if (acb->verify) {
+            acb->verify(acb);
+        }
+
+        acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
+        qemu_bh_schedule(acb->bh);
+        break;
+    }
+}
+
+static void blkverify_verify_readv(BlkverifyAIOCB *acb)
+{
+    ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
+    if (offset != -1) {
+        blkverify_err(acb, "contents mismatch in sector %" PRId64,
+                      acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
+    }
+}
+
+static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+    BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
+                                            nb_sectors, cb, opaque);
+
+    acb->verify = blkverify_verify_readv;
+    acb->buf = qemu_blockalign(bs->file, qiov->size);
+    qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
+    blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
+
+    if (!bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
+                        blkverify_aio_cb, acb)) {
+        blkverify_aio_cb(acb, -EIO);
+    }
+    if (!bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
+                        blkverify_aio_cb, acb)) {
+        blkverify_aio_cb(acb, -EIO);
+    }
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+    BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
+                                            nb_sectors, cb, opaque);
+
+    if (!bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
+                         blkverify_aio_cb, acb)) {
+        blkverify_aio_cb(acb, -EIO);
+    }
+    if (!bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
+                         blkverify_aio_cb, acb)) {
+        blkverify_aio_cb(acb, -EIO);
+    }
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+
+    /* Only flush test file, the raw file is not important */
+    return bdrv_aio_flush(s->test_file, cb, opaque);
+}
+
+static BlockDriver bdrv_blkverify = {
+    .format_name        = "blkverify",
+    .protocol_name      = "blkverify",
+
+    .instance_size      = sizeof(BDRVBlkverifyState),
+
+    .bdrv_getlength     = blkverify_getlength,
+
+    .bdrv_file_open     = blkverify_open,
+    .bdrv_close         = blkverify_close,
+    .bdrv_flush         = blkverify_flush,
+
+    .bdrv_aio_readv     = blkverify_aio_readv,
+    .bdrv_aio_writev    = blkverify_aio_writev,
+    .bdrv_aio_flush     = blkverify_aio_flush,
+};
+
+static void bdrv_blkverify_init(void)
+{
+    bdrv_register(&bdrv_blkverify);
+}
+
+block_init(bdrv_blkverify_init);
diff --git a/qemu-0.15.x/block/bochs.c b/qemu-0.15.x/block/bochs.c
new file mode 100644
index 0000000..5fe2fa3
--- /dev/null
+++ b/qemu-0.15.x/block/bochs.c
@@ -0,0 +1,230 @@
+/*
+ * Block driver for the various disk image formats used by Bochs
+ * Currently only for "growing" type in read-only mode
+ *
+ * Copyright (c) 2005 Alex Beregszaszi
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+/**************************************************************/
+
+#define HEADER_MAGIC "Bochs Virtual HD Image"
+#define HEADER_VERSION 0x00020000
+#define HEADER_V1 0x00010000
+#define HEADER_SIZE 512
+
+#define REDOLOG_TYPE "Redolog"
+#define GROWING_TYPE "Growing"
+
+// not allocated: 0xffffffff
+
+// always little-endian
+struct bochs_header_v1 {
+    char magic[32]; // "Bochs Virtual HD Image"
+    char type[16]; // "Redolog"
+    char subtype[16]; // "Undoable" / "Volatile" / "Growing"
+    uint32_t version;
+    uint32_t header; // size of header
+
+    union {
+	struct {
+	    uint32_t catalog; // num of entries
+	    uint32_t bitmap; // bitmap size
+	    uint32_t extent; // extent size
+	    uint64_t disk; // disk size
+	    char padding[HEADER_SIZE - 64 - 8 - 20];
+	} redolog;
+	char padding[HEADER_SIZE - 64 - 8];
+    } extra;
+};
+
+// always little-endian
+struct bochs_header {
+    char magic[32]; // "Bochs Virtual HD Image"
+    char type[16]; // "Redolog"
+    char subtype[16]; // "Undoable" / "Volatile" / "Growing"
+    uint32_t version;
+    uint32_t header; // size of header
+
+    union {
+	struct {
+	    uint32_t catalog; // num of entries
+	    uint32_t bitmap; // bitmap size
+	    uint32_t extent; // extent size
+	    uint32_t reserved; // for ???
+	    uint64_t disk; // disk size
+	    char padding[HEADER_SIZE - 64 - 8 - 24];
+	} redolog;
+	char padding[HEADER_SIZE - 64 - 8];
+    } extra;
+};
+
+typedef struct BDRVBochsState {
+    uint32_t *catalog_bitmap;
+    int catalog_size;
+
+    int data_offset;
+
+    int bitmap_blocks;
+    int extent_blocks;
+    int extent_size;
+} BDRVBochsState;
+
+static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const struct bochs_header *bochs = (const void *)buf;
+
+    if (buf_size < HEADER_SIZE)
+	return 0;
+
+    if (!strcmp(bochs->magic, HEADER_MAGIC) &&
+	!strcmp(bochs->type, REDOLOG_TYPE) &&
+	!strcmp(bochs->subtype, GROWING_TYPE) &&
+	((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
+	(le32_to_cpu(bochs->version) == HEADER_V1)))
+	return 100;
+
+    return 0;
+}
+
+static int bochs_open(BlockDriverState *bs, int flags)
+{
+    BDRVBochsState *s = bs->opaque;
+    int i;
+    struct bochs_header bochs;
+    struct bochs_header_v1 header_v1;
+
+    bs->read_only = 1; // no write support yet
+
+    if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
+        goto fail;
+    }
+
+    if (strcmp(bochs.magic, HEADER_MAGIC) ||
+        strcmp(bochs.type, REDOLOG_TYPE) ||
+        strcmp(bochs.subtype, GROWING_TYPE) ||
+	((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
+	(le32_to_cpu(bochs.version) != HEADER_V1))) {
+        goto fail;
+    }
+
+    if (le32_to_cpu(bochs.version) == HEADER_V1) {
+      memcpy(&header_v1, &bochs, sizeof(bochs));
+      bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
+    } else {
+      bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
+    }
+
+    s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
+    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
+    if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
+                   s->catalog_size * 4) != s->catalog_size * 4)
+	goto fail;
+    for (i = 0; i < s->catalog_size; i++)
+	le32_to_cpus(&s->catalog_bitmap[i]);
+
+    s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
+
+    s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
+    s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
+
+    s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
+
+    return 0;
+ fail:
+    return -1;
+}
+
+static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+{
+    BDRVBochsState *s = bs->opaque;
+    int64_t offset = sector_num * 512;
+    int64_t extent_index, extent_offset, bitmap_offset;
+    char bitmap_entry;
+
+    // seek to sector
+    extent_index = offset / s->extent_size;
+    extent_offset = (offset % s->extent_size) / 512;
+
+    if (s->catalog_bitmap[extent_index] == 0xffffffff) {
+	return -1; /* not allocated */
+    }
+
+    bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
+	(s->extent_blocks + s->bitmap_blocks));
+
+    /* read in bitmap for current extent */
+    if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
+                   &bitmap_entry, 1) != 1) {
+        return -1;
+    }
+
+    if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
+	return -1; /* not allocated */
+    }
+
+    return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
+}
+
+static int bochs_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+
+    while (nb_sectors > 0) {
+        int64_t block_offset = seek_to_sector(bs, sector_num);
+        if (block_offset >= 0) {
+            ret = bdrv_pread(bs->file, block_offset, buf, 512);
+            if (ret != 512) {
+                return -1;
+            }
+        } else
+            memset(buf, 0, 512);
+        nb_sectors--;
+        sector_num++;
+        buf += 512;
+    }
+    return 0;
+}
+
+static void bochs_close(BlockDriverState *bs)
+{
+    BDRVBochsState *s = bs->opaque;
+    qemu_free(s->catalog_bitmap);
+}
+
+static BlockDriver bdrv_bochs = {
+    .format_name	= "bochs",
+    .instance_size	= sizeof(BDRVBochsState),
+    .bdrv_probe		= bochs_probe,
+    .bdrv_open		= bochs_open,
+    .bdrv_read		= bochs_read,
+    .bdrv_close		= bochs_close,
+};
+
+static void bdrv_bochs_init(void)
+{
+    bdrv_register(&bdrv_bochs);
+}
+
+block_init(bdrv_bochs_init);
diff --git a/qemu-0.15.x/block/cloop.c b/qemu-0.15.x/block/cloop.c
new file mode 100644
index 0000000..fe015c4
--- /dev/null
+++ b/qemu-0.15.x/block/cloop.c
@@ -0,0 +1,171 @@
+/*
+ * QEMU Block driver for CLOOP images
+ *
+ * Copyright (c) 2004 Johannes E. Schindelin
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+#include <zlib.h>
+
+typedef struct BDRVCloopState {
+    uint32_t block_size;
+    uint32_t n_blocks;
+    uint64_t* offsets;
+    uint32_t sectors_per_block;
+    uint32_t current_block;
+    uint8_t *compressed_block;
+    uint8_t *uncompressed_block;
+    z_stream zstream;
+} BDRVCloopState;
+
+static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const char* magic_version_2_0="#!/bin/sh\n"
+	"#V2.0 Format\n"
+	"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
+    int length=strlen(magic_version_2_0);
+    if(length>buf_size)
+	length=buf_size;
+    if(!memcmp(magic_version_2_0,buf,length))
+	return 2;
+    return 0;
+}
+
+static int cloop_open(BlockDriverState *bs, int flags)
+{
+    BDRVCloopState *s = bs->opaque;
+    uint32_t offsets_size,max_compressed_block_size=1,i;
+
+    bs->read_only = 1;
+
+    /* read header */
+    if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
+        goto cloop_close;
+    }
+    s->block_size = be32_to_cpu(s->block_size);
+
+    if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
+        goto cloop_close;
+    }
+    s->n_blocks = be32_to_cpu(s->n_blocks);
+
+    /* read offsets */
+    offsets_size = s->n_blocks * sizeof(uint64_t);
+    s->offsets = qemu_malloc(offsets_size);
+    if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
+            offsets_size) {
+	goto cloop_close;
+    }
+    for(i=0;i<s->n_blocks;i++) {
+	s->offsets[i]=be64_to_cpu(s->offsets[i]);
+	if(i>0) {
+	    uint32_t size=s->offsets[i]-s->offsets[i-1];
+	    if(size>max_compressed_block_size)
+		max_compressed_block_size=size;
+	}
+    }
+
+    /* initialize zlib engine */
+    s->compressed_block = qemu_malloc(max_compressed_block_size+1);
+    s->uncompressed_block = qemu_malloc(s->block_size);
+    if(inflateInit(&s->zstream) != Z_OK)
+	goto cloop_close;
+    s->current_block=s->n_blocks;
+
+    s->sectors_per_block = s->block_size/512;
+    bs->total_sectors = s->n_blocks*s->sectors_per_block;
+    return 0;
+
+cloop_close:
+    return -1;
+}
+
+static inline int cloop_read_block(BlockDriverState *bs, int block_num)
+{
+    BDRVCloopState *s = bs->opaque;
+
+    if(s->current_block != block_num) {
+	int ret;
+        uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
+
+        ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
+                         bytes);
+        if (ret != bytes)
+            return -1;
+
+	s->zstream.next_in = s->compressed_block;
+	s->zstream.avail_in = bytes;
+	s->zstream.next_out = s->uncompressed_block;
+	s->zstream.avail_out = s->block_size;
+	ret = inflateReset(&s->zstream);
+	if(ret != Z_OK)
+	    return -1;
+	ret = inflate(&s->zstream, Z_FINISH);
+	if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
+	    return -1;
+
+	s->current_block = block_num;
+    }
+    return 0;
+}
+
+static int cloop_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVCloopState *s = bs->opaque;
+    int i;
+
+    for(i=0;i<nb_sectors;i++) {
+	uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
+	    block_num=(sector_num+i)/s->sectors_per_block;
+	if(cloop_read_block(bs, block_num) != 0)
+	    return -1;
+	memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
+    }
+    return 0;
+}
+
+static void cloop_close(BlockDriverState *bs)
+{
+    BDRVCloopState *s = bs->opaque;
+    if(s->n_blocks>0)
+	free(s->offsets);
+    free(s->compressed_block);
+    free(s->uncompressed_block);
+    inflateEnd(&s->zstream);
+}
+
+static BlockDriver bdrv_cloop = {
+    .format_name	= "cloop",
+    .instance_size	= sizeof(BDRVCloopState),
+    .bdrv_probe		= cloop_probe,
+    .bdrv_open		= cloop_open,
+    .bdrv_read		= cloop_read,
+    .bdrv_close		= cloop_close,
+};
+
+static void bdrv_cloop_init(void)
+{
+    bdrv_register(&bdrv_cloop);
+}
+
+block_init(bdrv_cloop_init);
diff --git a/qemu-0.15.x/block/cow.c b/qemu-0.15.x/block/cow.c
new file mode 100644
index 0000000..4cf543c
--- /dev/null
+++ b/qemu-0.15.x/block/cow.c
@@ -0,0 +1,324 @@
+/*
+ * Block driver for the COW format
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+/**************************************************************/
+/* COW block driver using file system holes */
+
+/* user mode linux compatible COW file */
+#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+#define COW_VERSION 2
+
+struct cow_header_v2 {
+    uint32_t magic;
+    uint32_t version;
+    char backing_file[1024];
+    int32_t mtime;
+    uint64_t size;
+    uint32_t sectorsize;
+};
+
+typedef struct BDRVCowState {
+    int64_t cow_sectors_offset;
+} BDRVCowState;
+
+static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const struct cow_header_v2 *cow_header = (const void *)buf;
+
+    if (buf_size >= sizeof(struct cow_header_v2) &&
+        be32_to_cpu(cow_header->magic) == COW_MAGIC &&
+        be32_to_cpu(cow_header->version) == COW_VERSION)
+        return 100;
+    else
+        return 0;
+}
+
+static int cow_open(BlockDriverState *bs, int flags)
+{
+    BDRVCowState *s = bs->opaque;
+    struct cow_header_v2 cow_header;
+    int bitmap_size;
+    int64_t size;
+
+    /* see if it is a cow image */
+    if (bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header)) !=
+            sizeof(cow_header)) {
+        goto fail;
+    }
+
+    if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
+        be32_to_cpu(cow_header.version) != COW_VERSION) {
+        goto fail;
+    }
+
+    /* cow image found */
+    size = be64_to_cpu(cow_header.size);
+    bs->total_sectors = size / 512;
+
+    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
+            cow_header.backing_file);
+
+    bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
+    s->cow_sectors_offset = (bitmap_size + 511) & ~511;
+    return 0;
+ fail:
+    return -1;
+}
+
+/*
+ * XXX(hch): right now these functions are extremly ineffcient.
+ * We should just read the whole bitmap we'll need in one go instead.
+ */
+static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
+{
+    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
+    uint8_t bitmap;
+    int ret;
+
+    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
+    }
+
+    bitmap |= (1 << (bitnum % 8));
+
+    ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
+    }
+    return 0;
+}
+
+static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
+{
+    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
+    uint8_t bitmap;
+    int ret;
+
+    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
+    }
+
+    return !!(bitmap & (1 << (bitnum % 8)));
+}
+
+/* Return true if first block has been changed (ie. current version is
+ * in COW file).  Set the number of continuous blocks for which that
+ * is true. */
+static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
+        int nb_sectors, int *num_same)
+{
+    int changed;
+
+    if (nb_sectors == 0) {
+	*num_same = nb_sectors;
+	return 0;
+    }
+
+    changed = is_bit_set(bs, sector_num);
+    if (changed < 0) {
+        return 0; /* XXX: how to return I/O errors? */
+    }
+
+    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
+	if (is_bit_set(bs, sector_num + *num_same) != changed)
+	    break;
+    }
+
+    return changed;
+}
+
+static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
+        int nb_sectors)
+{
+    int error = 0;
+    int i;
+
+    for (i = 0; i < nb_sectors; i++) {
+        error = cow_set_bit(bs, sector_num + i);
+        if (error) {
+            break;
+        }
+    }
+
+    return error;
+}
+
+static int cow_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVCowState *s = bs->opaque;
+    int ret, n;
+
+    while (nb_sectors > 0) {
+        if (cow_is_allocated(bs, sector_num, nb_sectors, &n)) {
+            ret = bdrv_pread(bs->file,
+                        s->cow_sectors_offset + sector_num * 512,
+                        buf, n * 512);
+            if (ret != n * 512)
+                return -1;
+        } else {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+                if (ret < 0)
+                    return -1;
+            } else {
+            memset(buf, 0, n * 512);
+        }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+
+static int cow_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVCowState *s = bs->opaque;
+    int ret;
+
+    ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
+                      buf, nb_sectors * 512);
+    if (ret != nb_sectors * 512)
+        return -1;
+
+    return cow_update_bitmap(bs, sector_num, nb_sectors);
+}
+
+static void cow_close(BlockDriverState *bs)
+{
+}
+
+static int cow_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd, cow_fd;
+    struct cow_header_v2 cow_header;
+    struct stat st;
+    int64_t image_sectors = 0;
+    const char *image_filename = NULL;
+    int ret;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            image_sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            image_filename = options->value.s;
+        }
+        options++;
+    }
+
+    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+              0644);
+    if (cow_fd < 0)
+        return -errno;
+    memset(&cow_header, 0, sizeof(cow_header));
+    cow_header.magic = cpu_to_be32(COW_MAGIC);
+    cow_header.version = cpu_to_be32(COW_VERSION);
+    if (image_filename) {
+        /* Note: if no file, we put a dummy mtime */
+        cow_header.mtime = cpu_to_be32(0);
+
+        fd = open(image_filename, O_RDONLY | O_BINARY);
+        if (fd < 0) {
+            close(cow_fd);
+            goto mtime_fail;
+        }
+        if (fstat(fd, &st) != 0) {
+            close(fd);
+            goto mtime_fail;
+        }
+        close(fd);
+        cow_header.mtime = cpu_to_be32(st.st_mtime);
+    mtime_fail:
+        pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
+                image_filename);
+    }
+    cow_header.sectorsize = cpu_to_be32(512);
+    cow_header.size = cpu_to_be64(image_sectors * 512);
+    ret = qemu_write_full(cow_fd, &cow_header, sizeof(cow_header));
+    if (ret != sizeof(cow_header)) {
+        ret = -errno;
+        goto exit;
+    }
+
+    /* resize to include at least all the bitmap */
+    ret = ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
+    if (ret) {
+        ret = -errno;
+        goto exit;
+    }
+
+exit:
+    close(cow_fd);
+    return ret;
+}
+
+static int cow_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static QEMUOptionParameter cow_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_cow = {
+    .format_name	= "cow",
+    .instance_size	= sizeof(BDRVCowState),
+    .bdrv_probe		= cow_probe,
+    .bdrv_open		= cow_open,
+    .bdrv_read		= cow_read,
+    .bdrv_write		= cow_write,
+    .bdrv_close		= cow_close,
+    .bdrv_create	= cow_create,
+    .bdrv_flush		= cow_flush,
+    .bdrv_is_allocated	= cow_is_allocated,
+
+    .create_options = cow_create_options,
+};
+
+static void bdrv_cow_init(void)
+{
+    bdrv_register(&bdrv_cow);
+}
+
+block_init(bdrv_cow_init);
diff --git a/qemu-0.15.x/block/curl.c b/qemu-0.15.x/block/curl.c
new file mode 100644
index 0000000..407f095
--- /dev/null
+++ b/qemu-0.15.x/block/curl.c
@@ -0,0 +1,564 @@
+/*
+ * QEMU Block driver for CURL images
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include <curl/curl.h>
+
+// #define DEBUG
+// #define DEBUG_VERBOSE
+
+#ifdef DEBUG_CURL
+#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define CURL_NUM_STATES 8
+#define CURL_NUM_ACB    8
+#define SECTOR_SIZE     512
+#define READ_AHEAD_SIZE (256 * 1024)
+
+#define FIND_RET_NONE   0
+#define FIND_RET_OK     1
+#define FIND_RET_WAIT   2
+
+struct BDRVCURLState;
+
+typedef struct CURLAIOCB {
+    BlockDriverAIOCB common;
+    QEMUIOVector *qiov;
+    size_t start;
+    size_t end;
+} CURLAIOCB;
+
+typedef struct CURLState
+{
+    struct BDRVCURLState *s;
+    CURLAIOCB *acb[CURL_NUM_ACB];
+    CURL *curl;
+    char *orig_buf;
+    size_t buf_start;
+    size_t buf_off;
+    size_t buf_len;
+    char range[128];
+    char errmsg[CURL_ERROR_SIZE];
+    char in_use;
+} CURLState;
+
+typedef struct BDRVCURLState {
+    CURLM *multi;
+    size_t len;
+    CURLState states[CURL_NUM_STATES];
+    char *url;
+    size_t readahead_size;
+} BDRVCURLState;
+
+static void curl_clean_state(CURLState *s);
+static void curl_multi_do(void *arg);
+
+static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
+                        void *s, void *sp)
+{
+    DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
+    switch (action) {
+        case CURL_POLL_IN:
+            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
+            break;
+        case CURL_POLL_OUT:
+            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s);
+            break;
+        case CURL_POLL_INOUT:
+            qemu_aio_set_fd_handler(fd, curl_multi_do,
+                                    curl_multi_do, NULL, NULL, s);
+            break;
+        case CURL_POLL_REMOVE:
+            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
+            break;
+    }
+
+    return 0;
+}
+
+static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
+{
+    CURLState *s = ((CURLState*)opaque);
+    size_t realsize = size * nmemb;
+    size_t fsize;
+
+    if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) {
+        s->s->len = fsize;
+    }
+
+    return realsize;
+}
+
+static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
+{
+    CURLState *s = ((CURLState*)opaque);
+    size_t realsize = size * nmemb;
+    int i;
+
+    DPRINTF("CURL: Just reading %zd bytes\n", realsize);
+
+    if (!s || !s->orig_buf)
+        goto read_end;
+
+    memcpy(s->orig_buf + s->buf_off, ptr, realsize);
+    s->buf_off += realsize;
+
+    for(i=0; i<CURL_NUM_ACB; i++) {
+        CURLAIOCB *acb = s->acb[i];
+
+        if (!acb)
+            continue;
+
+        if ((s->buf_off >= acb->end)) {
+            qemu_iovec_from_buffer(acb->qiov, s->orig_buf + acb->start,
+                                   acb->end - acb->start);
+            acb->common.cb(acb->common.opaque, 0);
+            qemu_aio_release(acb);
+            s->acb[i] = NULL;
+        }
+    }
+
+read_end:
+    return realsize;
+}
+
+static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
+                         CURLAIOCB *acb)
+{
+    int i;
+    size_t end = start + len;
+
+    for (i=0; i<CURL_NUM_STATES; i++) {
+        CURLState *state = &s->states[i];
+        size_t buf_end = (state->buf_start + state->buf_off);
+        size_t buf_fend = (state->buf_start + state->buf_len);
+
+        if (!state->orig_buf)
+            continue;
+        if (!state->buf_off)
+            continue;
+
+        // Does the existing buffer cover our section?
+        if ((start >= state->buf_start) &&
+            (start <= buf_end) &&
+            (end >= state->buf_start) &&
+            (end <= buf_end))
+        {
+            char *buf = state->orig_buf + (start - state->buf_start);
+
+            qemu_iovec_from_buffer(acb->qiov, buf, len);
+            acb->common.cb(acb->common.opaque, 0);
+
+            return FIND_RET_OK;
+        }
+
+        // Wait for unfinished chunks
+        if ((start >= state->buf_start) &&
+            (start <= buf_fend) &&
+            (end >= state->buf_start) &&
+            (end <= buf_fend))
+        {
+            int j;
+
+            acb->start = start - state->buf_start;
+            acb->end = acb->start + len;
+
+            for (j=0; j<CURL_NUM_ACB; j++) {
+                if (!state->acb[j]) {
+                    state->acb[j] = acb;
+                    return FIND_RET_WAIT;
+                }
+            }
+        }
+    }
+
+    return FIND_RET_NONE;
+}
+
+static void curl_multi_do(void *arg)
+{
+    BDRVCURLState *s = (BDRVCURLState *)arg;
+    int running;
+    int r;
+    int msgs_in_queue;
+
+    if (!s->multi)
+        return;
+
+    do {
+        r = curl_multi_socket_all(s->multi, &running);
+    } while(r == CURLM_CALL_MULTI_PERFORM);
+
+    /* Try to find done transfers, so we can free the easy
+     * handle again. */
+    do {
+        CURLMsg *msg;
+        msg = curl_multi_info_read(s->multi, &msgs_in_queue);
+
+        if (!msg)
+            break;
+        if (msg->msg == CURLMSG_NONE)
+            break;
+
+        switch (msg->msg) {
+            case CURLMSG_DONE:
+            {
+                CURLState *state = NULL;
+                curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
+                curl_clean_state(state);
+                break;
+            }
+            default:
+                msgs_in_queue = 0;
+                break;
+        }
+    } while(msgs_in_queue);
+}
+
+static CURLState *curl_init_state(BDRVCURLState *s)
+{
+    CURLState *state = NULL;
+    int i, j;
+
+    do {
+        for (i=0; i<CURL_NUM_STATES; i++) {
+            for (j=0; j<CURL_NUM_ACB; j++)
+                if (s->states[i].acb[j])
+                    continue;
+            if (s->states[i].in_use)
+                continue;
+
+            state = &s->states[i];
+            state->in_use = 1;
+            break;
+        }
+        if (!state) {
+            usleep(100);
+            curl_multi_do(s);
+        }
+    } while(!state);
+
+    if (state->curl)
+        goto has_curl;
+
+    state->curl = curl_easy_init();
+    if (!state->curl)
+        return NULL;
+    curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
+    curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
+    curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
+    curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
+    curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
+    curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
+    curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
+    curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
+    curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
+    
+#ifdef DEBUG_VERBOSE
+    curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
+#endif
+
+has_curl:
+
+    state->s = s;
+
+    return state;
+}
+
+static void curl_clean_state(CURLState *s)
+{
+    if (s->s->multi)
+        curl_multi_remove_handle(s->s->multi, s->curl);
+    s->in_use = 0;
+}
+
+static int curl_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVCURLState *s = bs->opaque;
+    CURLState *state = NULL;
+    double d;
+
+    #define RA_OPTSTR ":readahead="
+    char *file;
+    char *ra;
+    const char *ra_val;
+    int parse_state = 0;
+
+    static int inited = 0;
+
+    file = qemu_strdup(filename);
+    s->readahead_size = READ_AHEAD_SIZE;
+
+    /* Parse a trailing ":readahead=#:" param, if present. */
+    ra = file + strlen(file) - 1;
+    while (ra >= file) {
+        if (parse_state == 0) {
+            if (*ra == ':')
+                parse_state++;
+            else
+                break;
+        } else if (parse_state == 1) {
+            if (*ra > '9' || *ra < '0') {
+                char *opt_start = ra - strlen(RA_OPTSTR) + 1;
+                if (opt_start > file &&
+                    strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
+                    ra_val = ra + 1;
+                    ra -= strlen(RA_OPTSTR) - 1;
+                    *ra = '\0';
+                    s->readahead_size = atoi(ra_val);
+                    break;
+                } else {
+                    break;
+                }
+            }
+        }
+        ra--;
+    }
+
+    if ((s->readahead_size & 0x1ff) != 0) {
+        fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
+                s->readahead_size);
+        goto out_noclean;
+    }
+
+    if (!inited) {
+        curl_global_init(CURL_GLOBAL_ALL);
+        inited = 1;
+    }
+
+    DPRINTF("CURL: Opening %s\n", file);
+    s->url = file;
+    state = curl_init_state(s);
+    if (!state)
+        goto out_noclean;
+
+    // Get file size
+
+    curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
+    curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb);
+    if (curl_easy_perform(state->curl))
+        goto out;
+    curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
+    curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
+    curl_easy_setopt(state->curl, CURLOPT_NOBODY, 0);
+    if (d)
+        s->len = (size_t)d;
+    else if(!s->len)
+        goto out;
+    DPRINTF("CURL: Size = %zd\n", s->len);
+
+    curl_clean_state(state);
+    curl_easy_cleanup(state->curl);
+    state->curl = NULL;
+
+    // Now we know the file exists and its size, so let's
+    // initialize the multi interface!
+
+    s->multi = curl_multi_init();
+    curl_multi_setopt( s->multi, CURLMOPT_SOCKETDATA, s); 
+    curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb ); 
+    curl_multi_do(s);
+
+    return 0;
+
+out:
+    fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
+    curl_easy_cleanup(state->curl);
+    state->curl = NULL;
+out_noclean:
+    qemu_free(file);
+    return -EINVAL;
+}
+
+static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    // Do we have to implement canceling? Seems to work without...
+}
+
+static AIOPool curl_aio_pool = {
+    .aiocb_size         = sizeof(CURLAIOCB),
+    .cancel             = curl_aio_cancel,
+};
+
+static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVCURLState *s = bs->opaque;
+    CURLAIOCB *acb;
+    size_t start = sector_num * SECTOR_SIZE;
+    size_t end;
+    CURLState *state;
+
+    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+
+    acb->qiov = qiov;
+
+    // In case we have the requested data already (e.g. read-ahead),
+    // we can just call the callback and be done.
+
+    switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
+        case FIND_RET_OK:
+            qemu_aio_release(acb);
+            // fall through
+        case FIND_RET_WAIT:
+            return &acb->common;
+        default:
+            break;
+    }
+
+    // No cache found, so let's start a new request
+
+    state = curl_init_state(s);
+    if (!state)
+        return NULL;
+
+    acb->start = 0;
+    acb->end = (nb_sectors * SECTOR_SIZE);
+
+    state->buf_off = 0;
+    if (state->orig_buf)
+        qemu_free(state->orig_buf);
+    state->buf_start = start;
+    state->buf_len = acb->end + s->readahead_size;
+    end = MIN(start + state->buf_len, s->len) - 1;
+    state->orig_buf = qemu_malloc(state->buf_len);
+    state->acb[0] = acb;
+
+    snprintf(state->range, 127, "%zd-%zd", start, end);
+    DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
+            (nb_sectors * SECTOR_SIZE), start, state->range);
+    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
+
+    curl_multi_add_handle(s->multi, state->curl);
+    curl_multi_do(s);
+
+    return &acb->common;
+}
+
+static void curl_close(BlockDriverState *bs)
+{
+    BDRVCURLState *s = bs->opaque;
+    int i;
+
+    DPRINTF("CURL: Close\n");
+    for (i=0; i<CURL_NUM_STATES; i++) {
+        if (s->states[i].in_use)
+            curl_clean_state(&s->states[i]);
+        if (s->states[i].curl) {
+            curl_easy_cleanup(s->states[i].curl);
+            s->states[i].curl = NULL;
+        }
+        if (s->states[i].orig_buf) {
+            qemu_free(s->states[i].orig_buf);
+            s->states[i].orig_buf = NULL;
+        }
+    }
+    if (s->multi)
+        curl_multi_cleanup(s->multi);
+    if (s->url)
+        free(s->url);
+}
+
+static int64_t curl_getlength(BlockDriverState *bs)
+{
+    BDRVCURLState *s = bs->opaque;
+    return s->len;
+}
+
+static BlockDriver bdrv_http = {
+    .format_name     = "http",
+    .protocol_name   = "http",
+
+    .instance_size   = sizeof(BDRVCURLState),
+    .bdrv_file_open  = curl_open,
+    .bdrv_close      = curl_close,
+    .bdrv_getlength  = curl_getlength,
+
+    .bdrv_aio_readv  = curl_aio_readv,
+};
+
+static BlockDriver bdrv_https = {
+    .format_name     = "https",
+    .protocol_name   = "https",
+
+    .instance_size   = sizeof(BDRVCURLState),
+    .bdrv_file_open  = curl_open,
+    .bdrv_close      = curl_close,
+    .bdrv_getlength  = curl_getlength,
+
+    .bdrv_aio_readv  = curl_aio_readv,
+};
+
+static BlockDriver bdrv_ftp = {
+    .format_name     = "ftp",
+    .protocol_name   = "ftp",
+
+    .instance_size   = sizeof(BDRVCURLState),
+    .bdrv_file_open  = curl_open,
+    .bdrv_close      = curl_close,
+    .bdrv_getlength  = curl_getlength,
+
+    .bdrv_aio_readv  = curl_aio_readv,
+};
+
+static BlockDriver bdrv_ftps = {
+    .format_name     = "ftps",
+    .protocol_name   = "ftps",
+
+    .instance_size   = sizeof(BDRVCURLState),
+    .bdrv_file_open  = curl_open,
+    .bdrv_close      = curl_close,
+    .bdrv_getlength  = curl_getlength,
+
+    .bdrv_aio_readv  = curl_aio_readv,
+};
+
+static BlockDriver bdrv_tftp = {
+    .format_name     = "tftp",
+    .protocol_name   = "tftp",
+
+    .instance_size   = sizeof(BDRVCURLState),
+    .bdrv_file_open  = curl_open,
+    .bdrv_close      = curl_close,
+    .bdrv_getlength  = curl_getlength,
+
+    .bdrv_aio_readv  = curl_aio_readv,
+};
+
+static void curl_block_init(void)
+{
+    bdrv_register(&bdrv_http);
+    bdrv_register(&bdrv_https);
+    bdrv_register(&bdrv_ftp);
+    bdrv_register(&bdrv_ftps);
+    bdrv_register(&bdrv_tftp);
+}
+
+block_init(curl_block_init);
diff --git a/qemu-0.15.x/block/dmg.c b/qemu-0.15.x/block/dmg.c
new file mode 100644
index 0000000..a3c815b
--- /dev/null
+++ b/qemu-0.15.x/block/dmg.c
@@ -0,0 +1,312 @@
+/*
+ * QEMU Block driver for DMG images
+ *
+ * Copyright (c) 2004 Johannes E. Schindelin
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "bswap.h"
+#include "module.h"
+#include <zlib.h>
+
+typedef struct BDRVDMGState {
+    /* each chunk contains a certain number of sectors,
+     * offsets[i] is the offset in the .dmg file,
+     * lengths[i] is the length of the compressed chunk,
+     * sectors[i] is the sector beginning at offsets[i],
+     * sectorcounts[i] is the number of sectors in that chunk,
+     * the sectors array is ordered
+     * 0<=i<n_chunks */
+
+    uint32_t n_chunks;
+    uint32_t* types;
+    uint64_t* offsets;
+    uint64_t* lengths;
+    uint64_t* sectors;
+    uint64_t* sectorcounts;
+    uint32_t current_chunk;
+    uint8_t *compressed_chunk;
+    uint8_t *uncompressed_chunk;
+    z_stream zstream;
+} BDRVDMGState;
+
+static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    int len=strlen(filename);
+    if(len>4 && !strcmp(filename+len-4,".dmg"))
+	return 2;
+    return 0;
+}
+
+static off_t read_off(BlockDriverState *bs, int64_t offset)
+{
+	uint64_t buffer;
+	if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
+		return 0;
+	return be64_to_cpu(buffer);
+}
+
+static off_t read_uint32(BlockDriverState *bs, int64_t offset)
+{
+	uint32_t buffer;
+	if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
+		return 0;
+	return be32_to_cpu(buffer);
+}
+
+static int dmg_open(BlockDriverState *bs, int flags)
+{
+    BDRVDMGState *s = bs->opaque;
+    off_t info_begin,info_end,last_in_offset,last_out_offset;
+    uint32_t count;
+    uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
+    int64_t offset;
+
+    bs->read_only = 1;
+    s->n_chunks = 0;
+    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
+
+    /* read offset of info blocks */
+    offset = bdrv_getlength(bs->file);
+    if (offset < 0) {
+        goto fail;
+    }
+    offset -= 0x1d8;
+
+    info_begin = read_off(bs, offset);
+    if (info_begin == 0) {
+	goto fail;
+    }
+
+    if (read_uint32(bs, info_begin) != 0x100) {
+        goto fail;
+    }
+
+    count = read_uint32(bs, info_begin + 4);
+    if (count == 0) {
+        goto fail;
+    }
+    info_end = info_begin + count;
+
+    offset = info_begin + 0x100;
+
+    /* read offsets */
+    last_in_offset = last_out_offset = 0;
+    while (offset < info_end) {
+        uint32_t type;
+
+	count = read_uint32(bs, offset);
+	if(count==0)
+	    goto fail;
+        offset += 4;
+
+	type = read_uint32(bs, offset);
+	if (type == 0x6d697368 && count >= 244) {
+	    int new_size, chunk_count;
+
+            offset += 4;
+            offset += 200;
+
+	    chunk_count = (count-204)/40;
+	    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
+	    s->types = qemu_realloc(s->types, new_size/2);
+	    s->offsets = qemu_realloc(s->offsets, new_size);
+	    s->lengths = qemu_realloc(s->lengths, new_size);
+	    s->sectors = qemu_realloc(s->sectors, new_size);
+	    s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
+
+	    for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
+		s->types[i] = read_uint32(bs, offset);
+		offset += 4;
+		if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
+		    if(s->types[i]==0xffffffff) {
+			last_in_offset = s->offsets[i-1]+s->lengths[i-1];
+			last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
+		    }
+		    chunk_count--;
+		    i--;
+		    offset += 36;
+		    continue;
+		}
+		offset += 4;
+
+		s->sectors[i] = last_out_offset+read_off(bs, offset);
+		offset += 8;
+
+		s->sectorcounts[i] = read_off(bs, offset);
+		offset += 8;
+
+		s->offsets[i] = last_in_offset+read_off(bs, offset);
+		offset += 8;
+
+		s->lengths[i] = read_off(bs, offset);
+		offset += 8;
+
+		if(s->lengths[i]>max_compressed_size)
+		    max_compressed_size = s->lengths[i];
+		if(s->sectorcounts[i]>max_sectors_per_chunk)
+		    max_sectors_per_chunk = s->sectorcounts[i];
+	    }
+	    s->n_chunks+=chunk_count;
+	}
+    }
+
+    /* initialize zlib engine */
+    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
+    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
+    if(inflateInit(&s->zstream) != Z_OK)
+	goto fail;
+
+    s->current_chunk = s->n_chunks;
+
+    return 0;
+fail:
+    return -1;
+}
+
+static inline int is_sector_in_chunk(BDRVDMGState* s,
+		uint32_t chunk_num,int sector_num)
+{
+    if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
+	    s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
+	return 0;
+    else
+	return -1;
+}
+
+static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
+{
+    /* binary search */
+    uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
+    while(chunk1!=chunk2) {
+	chunk3 = (chunk1+chunk2)/2;
+	if(s->sectors[chunk3]>sector_num)
+	    chunk2 = chunk3;
+	else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
+	    return chunk3;
+	else
+	    chunk1 = chunk3;
+    }
+    return s->n_chunks; /* error */
+}
+
+static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
+{
+    BDRVDMGState *s = bs->opaque;
+
+    if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
+	int ret;
+	uint32_t chunk = search_chunk(s,sector_num);
+
+	if(chunk>=s->n_chunks)
+	    return -1;
+
+	s->current_chunk = s->n_chunks;
+	switch(s->types[chunk]) {
+	case 0x80000005: { /* zlib compressed */
+	    int i;
+
+	    /* we need to buffer, because only the chunk as whole can be
+	     * inflated. */
+	    i=0;
+	    do {
+                ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
+                                 s->compressed_chunk+i, s->lengths[chunk]-i);
+		if(ret<0 && errno==EINTR)
+		    ret=0;
+		i+=ret;
+	    } while(ret>=0 && ret+i<s->lengths[chunk]);
+
+	    if (ret != s->lengths[chunk])
+		return -1;
+
+	    s->zstream.next_in = s->compressed_chunk;
+	    s->zstream.avail_in = s->lengths[chunk];
+	    s->zstream.next_out = s->uncompressed_chunk;
+	    s->zstream.avail_out = 512*s->sectorcounts[chunk];
+	    ret = inflateReset(&s->zstream);
+	    if(ret != Z_OK)
+		return -1;
+	    ret = inflate(&s->zstream, Z_FINISH);
+	    if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
+		return -1;
+	    break; }
+	case 1: /* copy */
+	    ret = bdrv_pread(bs->file, s->offsets[chunk],
+                             s->uncompressed_chunk, s->lengths[chunk]);
+	    if (ret != s->lengths[chunk])
+		return -1;
+	    break;
+	case 2: /* zero */
+	    memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
+	    break;
+	}
+	s->current_chunk = chunk;
+    }
+    return 0;
+}
+
+static int dmg_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVDMGState *s = bs->opaque;
+    int i;
+
+    for(i=0;i<nb_sectors;i++) {
+	uint32_t sector_offset_in_chunk;
+	if(dmg_read_chunk(bs, sector_num+i) != 0)
+	    return -1;
+	sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
+	memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
+    }
+    return 0;
+}
+
+static void dmg_close(BlockDriverState *bs)
+{
+    BDRVDMGState *s = bs->opaque;
+    if(s->n_chunks>0) {
+	free(s->types);
+	free(s->offsets);
+	free(s->lengths);
+	free(s->sectors);
+	free(s->sectorcounts);
+    }
+    free(s->compressed_chunk);
+    free(s->uncompressed_chunk);
+    inflateEnd(&s->zstream);
+}
+
+static BlockDriver bdrv_dmg = {
+    .format_name	= "dmg",
+    .instance_size	= sizeof(BDRVDMGState),
+    .bdrv_probe		= dmg_probe,
+    .bdrv_open		= dmg_open,
+    .bdrv_read		= dmg_read,
+    .bdrv_close		= dmg_close,
+};
+
+static void bdrv_dmg_init(void)
+{
+    bdrv_register(&bdrv_dmg);
+}
+
+block_init(bdrv_dmg_init);
diff --git a/qemu-0.15.x/block/nbd.c b/qemu-0.15.x/block/nbd.c
new file mode 100644
index 0000000..7a52f62
--- /dev/null
+++ b/qemu-0.15.x/block/nbd.c
@@ -0,0 +1,272 @@
+/*
+ * QEMU Block driver for  NBD
+ *
+ * Copyright (C) 2008 Bull S.A.S.
+ *     Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ * Some parts:
+ *    Copyright (C) 2007 Anthony Liguori <anthony at codemonkey.ws>
+ *
+ * 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 "qemu-common.h"
+#include "nbd.h"
+#include "module.h"
+#include "qemu_socket.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#define EN_OPTSTR ":exportname="
+
+/* #define DEBUG_NBD */
+
+#if defined(DEBUG_NBD)
+#define logout(fmt, ...) \
+                fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+typedef struct BDRVNBDState {
+    int sock;
+    off_t size;
+    size_t blocksize;
+    char *export_name; /* An NBD server may export several devices */
+
+    /* If it begins with  '/', this is a UNIX domain socket. Otherwise,
+     * it's a string of the form <hostname|ip4|\[ip6\]>:port
+     */
+    char *host_spec;
+} BDRVNBDState;
+
+static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
+{
+    char *file;
+    char *export_name;
+    const char *host_spec;
+    const char *unixpath;
+    int err = -EINVAL;
+
+    file = qemu_strdup(filename);
+
+    export_name = strstr(file, EN_OPTSTR);
+    if (export_name) {
+        if (export_name[strlen(EN_OPTSTR)] == 0) {
+            goto out;
+        }
+        export_name[0] = 0; /* truncate 'file' */
+        export_name += strlen(EN_OPTSTR);
+        s->export_name = qemu_strdup(export_name);
+    }
+
+    /* extract the host_spec - fail if it's not nbd:... */
+    if (!strstart(file, "nbd:", &host_spec)) {
+        goto out;
+    }
+
+    /* are we a UNIX or TCP socket? */
+    if (strstart(host_spec, "unix:", &unixpath)) {
+        if (unixpath[0] != '/') { /* We demand  an absolute path*/
+            goto out;
+        }
+        s->host_spec = qemu_strdup(unixpath);
+    } else {
+        s->host_spec = qemu_strdup(host_spec);
+    }
+
+    err = 0;
+
+out:
+    qemu_free(file);
+    if (err != 0) {
+        qemu_free(s->export_name);
+        qemu_free(s->host_spec);
+    }
+    return err;
+}
+
+static int nbd_establish_connection(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    int sock;
+    int ret;
+    off_t size;
+    size_t blocksize;
+    uint32_t nbdflags;
+
+    if (s->host_spec[0] == '/') {
+        sock = unix_socket_outgoing(s->host_spec);
+    } else {
+        sock = tcp_socket_outgoing_spec(s->host_spec);
+    }
+
+    /* Failed to establish connection */
+    if (sock == -1) {
+        logout("Failed to establish connection to NBD server\n");
+        return -errno;
+    }
+
+    /* NBD handshake */
+    ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
+                                &blocksize);
+    if (ret == -1) {
+        logout("Failed to negotiate with the NBD server\n");
+        closesocket(sock);
+        return -errno;
+    }
+
+    /* Now that we're connected, set the socket to be non-blocking */
+    socket_set_nonblock(sock);
+
+    s->sock = sock;
+    s->size = size;
+    s->blocksize = blocksize;
+
+    logout("Established connection with NBD server\n");
+    return 0;
+}
+
+static void nbd_teardown_connection(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+
+    request.type = NBD_CMD_DISC;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = 0;
+    request.len = 0;
+    nbd_send_request(s->sock, &request);
+
+    closesocket(s->sock);
+}
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+    BDRVNBDState *s = bs->opaque;
+    int result;
+
+    /* Pop the config into our state object. Exit if invalid. */
+    result = nbd_config(s, filename, flags);
+    if (result != 0) {
+        return result;
+    }
+
+    /* establish TCP connection, return error if it fails
+     * TODO: Configurable retry-until-timeout behaviour.
+     */
+    result = nbd_establish_connection(bs);
+
+    return result;
+}
+
+static int nbd_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    request.type = NBD_CMD_READ;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = sector_num * 512;;
+    request.len = nb_sectors * 512;
+
+    if (nbd_send_request(s->sock, &request) == -1)
+        return -errno;
+
+    if (nbd_receive_reply(s->sock, &reply) == -1)
+        return -errno;
+
+    if (reply.error !=0)
+        return -reply.error;
+
+    if (reply.handle != request.handle)
+        return -EIO;
+
+    if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
+        return -EIO;
+
+    return 0;
+}
+
+static int nbd_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    request.type = NBD_CMD_WRITE;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = sector_num * 512;;
+    request.len = nb_sectors * 512;
+
+    if (nbd_send_request(s->sock, &request) == -1)
+        return -errno;
+
+    if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
+        return -EIO;
+
+    if (nbd_receive_reply(s->sock, &reply) == -1)
+        return -errno;
+
+    if (reply.error !=0)
+        return -reply.error;
+
+    if (reply.handle != request.handle)
+        return -EIO;
+
+    return 0;
+}
+
+static void nbd_close(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    qemu_free(s->export_name);
+    qemu_free(s->host_spec);
+
+    nbd_teardown_connection(bs);
+}
+
+static int64_t nbd_getlength(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+
+    return s->size;
+}
+
+static BlockDriver bdrv_nbd = {
+    .format_name	= "nbd",
+    .instance_size	= sizeof(BDRVNBDState),
+    .bdrv_file_open	= nbd_open,
+    .bdrv_read		= nbd_read,
+    .bdrv_write		= nbd_write,
+    .bdrv_close		= nbd_close,
+    .bdrv_getlength	= nbd_getlength,
+    .protocol_name	= "nbd",
+};
+
+static void bdrv_nbd_init(void)
+{
+    bdrv_register(&bdrv_nbd);
+}
+
+block_init(bdrv_nbd_init);
diff --git a/qemu-0.15.x/block/parallels.c b/qemu-0.15.x/block/parallels.c
new file mode 100644
index 0000000..35a14aa
--- /dev/null
+++ b/qemu-0.15.x/block/parallels.c
@@ -0,0 +1,157 @@
+/*
+ * Block driver for Parallels disk image format
+ *
+ * Copyright (c) 2007 Alex Beregszaszi
+ *
+ * This code is based on comparing different disk images created by Parallels.
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+/**************************************************************/
+
+#define HEADER_MAGIC "WithoutFreeSpace"
+#define HEADER_VERSION 2
+#define HEADER_SIZE 64
+
+// always little-endian
+struct parallels_header {
+    char magic[16]; // "WithoutFreeSpace"
+    uint32_t version;
+    uint32_t heads;
+    uint32_t cylinders;
+    uint32_t tracks;
+    uint32_t catalog_entries;
+    uint32_t nb_sectors;
+    char padding[24];
+} __attribute__((packed));
+
+typedef struct BDRVParallelsState {
+
+    uint32_t *catalog_bitmap;
+    int catalog_size;
+
+    int tracks;
+} BDRVParallelsState;
+
+static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const struct parallels_header *ph = (const void *)buf;
+
+    if (buf_size < HEADER_SIZE)
+	return 0;
+
+    if (!memcmp(ph->magic, HEADER_MAGIC, 16) &&
+	(le32_to_cpu(ph->version) == HEADER_VERSION))
+	return 100;
+
+    return 0;
+}
+
+static int parallels_open(BlockDriverState *bs, int flags)
+{
+    BDRVParallelsState *s = bs->opaque;
+    int i;
+    struct parallels_header ph;
+
+    bs->read_only = 1; // no write support yet
+
+    if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
+        goto fail;
+
+    if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
+	(le32_to_cpu(ph.version) != HEADER_VERSION)) {
+        goto fail;
+    }
+
+    bs->total_sectors = le32_to_cpu(ph.nb_sectors);
+
+    s->tracks = le32_to_cpu(ph.tracks);
+
+    s->catalog_size = le32_to_cpu(ph.catalog_entries);
+    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
+    if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
+	s->catalog_size * 4)
+	goto fail;
+    for (i = 0; i < s->catalog_size; i++)
+	le32_to_cpus(&s->catalog_bitmap[i]);
+
+    return 0;
+fail:
+    if (s->catalog_bitmap)
+	qemu_free(s->catalog_bitmap);
+    return -1;
+}
+
+static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+{
+    BDRVParallelsState *s = bs->opaque;
+    uint32_t index, offset;
+
+    index = sector_num / s->tracks;
+    offset = sector_num % s->tracks;
+
+    /* not allocated */
+    if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
+	return -1;
+    return (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
+}
+
+static int parallels_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    while (nb_sectors > 0) {
+        int64_t position = seek_to_sector(bs, sector_num);
+        if (position >= 0) {
+            if (bdrv_pread(bs->file, position, buf, 512) != 512)
+                return -1;
+        } else {
+            memset(buf, 0, 512);
+        }
+        nb_sectors--;
+        sector_num++;
+        buf += 512;
+    }
+    return 0;
+}
+
+static void parallels_close(BlockDriverState *bs)
+{
+    BDRVParallelsState *s = bs->opaque;
+    qemu_free(s->catalog_bitmap);
+}
+
+static BlockDriver bdrv_parallels = {
+    .format_name	= "parallels",
+    .instance_size	= sizeof(BDRVParallelsState),
+    .bdrv_probe		= parallels_probe,
+    .bdrv_open		= parallels_open,
+    .bdrv_read		= parallels_read,
+    .bdrv_close		= parallels_close,
+};
+
+static void bdrv_parallels_init(void)
+{
+    bdrv_register(&bdrv_parallels);
+}
+
+block_init(bdrv_parallels_init);
diff --git a/qemu-0.15.x/block/qcow.c b/qemu-0.15.x/block/qcow.c
new file mode 100644
index 0000000..227b104
--- /dev/null
+++ b/qemu-0.15.x/block/qcow.c
@@ -0,0 +1,1037 @@
+/*
+ * Block driver for the QCOW format
+ *
+ * Copyright (c) 2004-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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+#include <zlib.h>
+#include "aes.h"
+
+/**************************************************************/
+/* QEMU COW block driver with compression and encryption support */
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 1
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES  1
+
+#define QCOW_OFLAG_COMPRESSED (1LL << 63)
+
+typedef struct QCowHeader {
+    uint32_t magic;
+    uint32_t version;
+    uint64_t backing_file_offset;
+    uint32_t backing_file_size;
+    uint32_t mtime;
+    uint64_t size; /* in bytes */
+    uint8_t cluster_bits;
+    uint8_t l2_bits;
+    uint32_t crypt_method;
+    uint64_t l1_table_offset;
+} QCowHeader;
+
+#define L2_CACHE_SIZE 16
+
+typedef struct BDRVQcowState {
+    int cluster_bits;
+    int cluster_size;
+    int cluster_sectors;
+    int l2_bits;
+    int l2_size;
+    int l1_size;
+    uint64_t cluster_offset_mask;
+    uint64_t l1_table_offset;
+    uint64_t *l1_table;
+    uint64_t *l2_cache;
+    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
+    uint32_t l2_cache_counts[L2_CACHE_SIZE];
+    uint8_t *cluster_cache;
+    uint8_t *cluster_data;
+    uint64_t cluster_cache_offset;
+    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
+    uint32_t crypt_method_header;
+    AES_KEY aes_encrypt_key;
+    AES_KEY aes_decrypt_key;
+} BDRVQcowState;
+
+static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
+
+static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const QCowHeader *cow_header = (const void *)buf;
+
+    if (buf_size >= sizeof(QCowHeader) &&
+        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
+        be32_to_cpu(cow_header->version) == QCOW_VERSION)
+        return 100;
+    else
+        return 0;
+}
+
+static int qcow_open(BlockDriverState *bs, int flags)
+{
+    BDRVQcowState *s = bs->opaque;
+    int len, i, shift;
+    QCowHeader header;
+
+    if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
+        goto fail;
+    be32_to_cpus(&header.magic);
+    be32_to_cpus(&header.version);
+    be64_to_cpus(&header.backing_file_offset);
+    be32_to_cpus(&header.backing_file_size);
+    be32_to_cpus(&header.mtime);
+    be64_to_cpus(&header.size);
+    be32_to_cpus(&header.crypt_method);
+    be64_to_cpus(&header.l1_table_offset);
+
+    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+        goto fail;
+    if (header.size <= 1 || header.cluster_bits < 9)
+        goto fail;
+    if (header.crypt_method > QCOW_CRYPT_AES)
+        goto fail;
+    s->crypt_method_header = header.crypt_method;
+    if (s->crypt_method_header)
+        bs->encrypted = 1;
+    s->cluster_bits = header.cluster_bits;
+    s->cluster_size = 1 << s->cluster_bits;
+    s->cluster_sectors = 1 << (s->cluster_bits - 9);
+    s->l2_bits = header.l2_bits;
+    s->l2_size = 1 << s->l2_bits;
+    bs->total_sectors = header.size / 512;
+    s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;
+
+    /* read the level 1 table */
+    shift = s->cluster_bits + s->l2_bits;
+    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
+
+    s->l1_table_offset = header.l1_table_offset;
+    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    if (!s->l1_table)
+        goto fail;
+    if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
+        s->l1_size * sizeof(uint64_t))
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+    /* alloc L2 cache */
+    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    if (!s->l2_cache)
+        goto fail;
+    s->cluster_cache = qemu_malloc(s->cluster_size);
+    if (!s->cluster_cache)
+        goto fail;
+    s->cluster_data = qemu_malloc(s->cluster_size);
+    if (!s->cluster_data)
+        goto fail;
+    s->cluster_cache_offset = -1;
+
+    /* read the backing file name */
+    if (header.backing_file_offset != 0) {
+        len = header.backing_file_size;
+        if (len > 1023)
+            len = 1023;
+        if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
+            goto fail;
+        bs->backing_file[len] = '\0';
+    }
+    return 0;
+
+ fail:
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    return -1;
+}
+
+static int qcow_set_key(BlockDriverState *bs, const char *key)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint8_t keybuf[16];
+    int len, i;
+
+    memset(keybuf, 0, 16);
+    len = strlen(key);
+    if (len > 16)
+        len = 16;
+    /* XXX: we could compress the chars to 7 bits to increase
+       entropy */
+    for(i = 0;i < len;i++) {
+        keybuf[i] = key[i];
+    }
+    s->crypt_method = s->crypt_method_header;
+
+    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
+        return -1;
+    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
+        return -1;
+#if 0
+    /* test */
+    {
+        uint8_t in[16];
+        uint8_t out[16];
+        uint8_t tmp[16];
+        for(i=0;i<16;i++)
+            in[i] = i;
+        AES_encrypt(in, tmp, &s->aes_encrypt_key);
+        AES_decrypt(tmp, out, &s->aes_decrypt_key);
+        for(i = 0; i < 16; i++)
+            printf(" %02x", tmp[i]);
+        printf("\n");
+        for(i = 0; i < 16; i++)
+            printf(" %02x", out[i]);
+        printf("\n");
+    }
+#endif
+    return 0;
+}
+
+/* The crypt function is compatible with the linux cryptoloop
+   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
+   supported */
+static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                            uint8_t *out_buf, const uint8_t *in_buf,
+                            int nb_sectors, int enc,
+                            const AES_KEY *key)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } ivec;
+    int i;
+
+    for(i = 0; i < nb_sectors; i++) {
+        ivec.ll[0] = cpu_to_le64(sector_num);
+        ivec.ll[1] = 0;
+        AES_cbc_encrypt(in_buf, out_buf, 512, key,
+                        ivec.b, enc);
+        sector_num++;
+        in_buf += 512;
+        out_buf += 512;
+    }
+}
+
+/* 'allocate' is:
+ *
+ * 0 to not allocate.
+ *
+ * 1 to allocate a normal cluster (for sector indexes 'n_start' to
+ * 'n_end')
+ *
+ * 2 to allocate a compressed cluster of size
+ * 'compressed_size'. 'compressed_size' must be > 0 and <
+ * cluster_size
+ *
+ * return 0 if not allocated.
+ */
+static uint64_t get_cluster_offset(BlockDriverState *bs,
+                                   uint64_t offset, int allocate,
+                                   int compressed_size,
+                                   int n_start, int n_end)
+{
+    BDRVQcowState *s = bs->opaque;
+    int min_index, i, j, l1_index, l2_index;
+    uint64_t l2_offset, *l2_table, cluster_offset, tmp;
+    uint32_t min_count;
+    int new_l2_table;
+
+    l1_index = offset >> (s->l2_bits + s->cluster_bits);
+    l2_offset = s->l1_table[l1_index];
+    new_l2_table = 0;
+    if (!l2_offset) {
+        if (!allocate)
+            return 0;
+        /* allocate a new l2 entry */
+        l2_offset = bdrv_getlength(bs->file);
+        /* round to cluster size */
+        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
+        /* update the L1 entry */
+        s->l1_table[l1_index] = l2_offset;
+        tmp = cpu_to_be64(l2_offset);
+        if (bdrv_pwrite_sync(bs->file,
+                s->l1_table_offset + l1_index * sizeof(tmp),
+                &tmp, sizeof(tmp)) < 0)
+            return 0;
+        new_l2_table = 1;
+    }
+    for(i = 0; i < L2_CACHE_SIZE; i++) {
+        if (l2_offset == s->l2_cache_offsets[i]) {
+            /* increment the hit count */
+            if (++s->l2_cache_counts[i] == 0xffffffff) {
+                for(j = 0; j < L2_CACHE_SIZE; j++) {
+                    s->l2_cache_counts[j] >>= 1;
+                }
+            }
+            l2_table = s->l2_cache + (i << s->l2_bits);
+            goto found;
+        }
+    }
+    /* not found: load a new entry in the least used one */
+    min_index = 0;
+    min_count = 0xffffffff;
+    for(i = 0; i < L2_CACHE_SIZE; i++) {
+        if (s->l2_cache_counts[i] < min_count) {
+            min_count = s->l2_cache_counts[i];
+            min_index = i;
+        }
+    }
+    l2_table = s->l2_cache + (min_index << s->l2_bits);
+    if (new_l2_table) {
+        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+        if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
+                s->l2_size * sizeof(uint64_t)) < 0)
+            return 0;
+    } else {
+        if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
+            s->l2_size * sizeof(uint64_t))
+            return 0;
+    }
+    s->l2_cache_offsets[min_index] = l2_offset;
+    s->l2_cache_counts[min_index] = 1;
+ found:
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    if (!cluster_offset ||
+        ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
+        if (!allocate)
+            return 0;
+        /* allocate a new cluster */
+        if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
+            (n_end - n_start) < s->cluster_sectors) {
+            /* if the cluster is already compressed, we must
+               decompress it in the case it is not completely
+               overwritten */
+            if (decompress_cluster(bs, cluster_offset) < 0)
+                return 0;
+            cluster_offset = bdrv_getlength(bs->file);
+            cluster_offset = (cluster_offset + s->cluster_size - 1) &
+                ~(s->cluster_size - 1);
+            /* write the cluster content */
+            if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) !=
+                s->cluster_size)
+                return -1;
+        } else {
+            cluster_offset = bdrv_getlength(bs->file);
+            if (allocate == 1) {
+                /* round to cluster size */
+                cluster_offset = (cluster_offset + s->cluster_size - 1) &
+                    ~(s->cluster_size - 1);
+                bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
+                /* if encrypted, we must initialize the cluster
+                   content which won't be written */
+                if (s->crypt_method &&
+                    (n_end - n_start) < s->cluster_sectors) {
+                    uint64_t start_sect;
+                    start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
+                    memset(s->cluster_data + 512, 0x00, 512);
+                    for(i = 0; i < s->cluster_sectors; i++) {
+                        if (i < n_start || i >= n_end) {
+                            encrypt_sectors(s, start_sect + i,
+                                            s->cluster_data,
+                                            s->cluster_data + 512, 1, 1,
+                                            &s->aes_encrypt_key);
+                            if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
+                                            s->cluster_data, 512) != 512)
+                                return -1;
+                        }
+                    }
+                }
+            } else if (allocate == 2) {
+                cluster_offset |= QCOW_OFLAG_COMPRESSED |
+                    (uint64_t)compressed_size << (63 - s->cluster_bits);
+            }
+        }
+        /* update L2 table */
+        tmp = cpu_to_be64(cluster_offset);
+        l2_table[l2_index] = tmp;
+        if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
+                &tmp, sizeof(tmp)) < 0)
+            return 0;
+    }
+    return cluster_offset;
+}
+
+static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum)
+{
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster, n;
+    uint64_t cluster_offset;
+
+    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+    index_in_cluster = sector_num & (s->cluster_sectors - 1);
+    n = s->cluster_sectors - index_in_cluster;
+    if (n > nb_sectors)
+        n = nb_sectors;
+    *pnum = n;
+    return (cluster_offset != 0);
+}
+
+static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
+                             const uint8_t *buf, int buf_size)
+{
+    z_stream strm1, *strm = &strm1;
+    int ret, out_len;
+
+    memset(strm, 0, sizeof(*strm));
+
+    strm->next_in = (uint8_t *)buf;
+    strm->avail_in = buf_size;
+    strm->next_out = out_buf;
+    strm->avail_out = out_buf_size;
+
+    ret = inflateInit2(strm, -12);
+    if (ret != Z_OK)
+        return -1;
+    ret = inflate(strm, Z_FINISH);
+    out_len = strm->next_out - out_buf;
+    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+        out_len != out_buf_size) {
+        inflateEnd(strm);
+        return -1;
+    }
+    inflateEnd(strm);
+    return 0;
+}
+
+static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, csize;
+    uint64_t coffset;
+
+    coffset = cluster_offset & s->cluster_offset_mask;
+    if (s->cluster_cache_offset != coffset) {
+        csize = cluster_offset >> (63 - s->cluster_bits);
+        csize &= (s->cluster_size - 1);
+        ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
+        if (ret != csize)
+            return -1;
+        if (decompress_buffer(s->cluster_cache, s->cluster_size,
+                              s->cluster_data, csize) < 0) {
+            return -1;
+        }
+        s->cluster_cache_offset = coffset;
+    }
+    return 0;
+}
+
+#if 0
+
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
+                     uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, index_in_cluster, n;
+    uint64_t cluster_offset;
+
+    while (nb_sectors > 0) {
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        n = s->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors)
+            n = nb_sectors;
+        if (!cluster_offset) {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+                if (ret < 0)
+                    return -1;
+            } else {
+                memset(buf, 0, 512 * n);
+            }
+        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            if (decompress_cluster(bs, cluster_offset) < 0)
+                return -1;
+            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
+        } else {
+            ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512);
+            if (ret != n * 512)
+                return -1;
+            if (s->crypt_method) {
+                encrypt_sectors(s, sector_num, buf, buf, n, 0,
+                                &s->aes_decrypt_key);
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+#endif
+
+typedef struct QCowAIOCB {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    QEMUIOVector *qiov;
+    uint8_t *buf;
+    void *orig_buf;
+    int nb_sectors;
+    int n;
+    uint64_t cluster_offset;
+    uint8_t *cluster_data;
+    struct iovec hd_iov;
+    bool is_write;
+    QEMUBH *bh;
+    QEMUIOVector hd_qiov;
+    BlockDriverAIOCB *hd_aiocb;
+} QCowAIOCB;
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+    .aiocb_size         = sizeof(QCowAIOCB),
+    .cancel             = qcow_aio_cancel,
+};
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->qiov = qiov;
+    acb->is_write = is_write;
+
+    if (qiov->niov > 1) {
+        acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
+        if (is_write)
+            qemu_iovec_to_buffer(qiov, acb->buf);
+    } else {
+        acb->buf = (uint8_t *)qiov->iov->iov_base;
+    }
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    acb->cluster_offset = 0;
+    return acb;
+}
+
+static void qcow_aio_read_cb(void *opaque, int ret);
+static void qcow_aio_write_cb(void *opaque, int ret);
+
+static void qcow_aio_rw_bh(void *opaque)
+{
+    QCowAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    if (acb->is_write) {
+        qcow_aio_write_cb(opaque, 0);
+    } else {
+        qcow_aio_read_cb(opaque, 0);
+    }
+}
+
+static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+{
+    if (acb->bh) {
+        return -EIO;
+    }
+
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh) {
+        return -EIO;
+    }
+
+    qemu_bh_schedule(acb->bh);
+
+    return 0;
+}
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+
+    acb->hd_aiocb = NULL;
+    if (ret < 0)
+        goto done;
+
+ redo:
+    /* post process the read buffer */
+    if (!acb->cluster_offset) {
+        /* nothing to do */
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* nothing to do */
+    } else {
+        if (s->crypt_method) {
+            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+                            acb->n, 0,
+                            &s->aes_decrypt_key);
+        }
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    /* prepare next AIO request */
+    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
+                                             0, 0, 0, 0);
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+
+    if (!acb->cluster_offset) {
+        if (bs->backing_hd) {
+            /* read from the base image */
+            acb->hd_iov.iov_base = (void *)acb->buf;
+            acb->hd_iov.iov_len = acb->n * 512;
+            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
+            if (acb->hd_aiocb == NULL) {
+                ret = -EIO;
+                goto done;
+            }
+        } else {
+            /* Note: in this case, no need to wait */
+            memset(acb->buf, 0, 512 * acb->n);
+            goto redo;
+        }
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* add AIO support for compressed blocks ? */
+        if (decompress_cluster(bs, acb->cluster_offset) < 0) {
+            ret = -EIO;
+            goto done;
+        }
+        memcpy(acb->buf,
+               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+        goto redo;
+    } else {
+        if ((acb->cluster_offset & 511) != 0) {
+            ret = -EIO;
+            goto done;
+        }
+        acb->hd_iov.iov_base = (void *)acb->buf;
+        acb->hd_iov.iov_len = acb->n * 512;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(bs->file,
+                            (acb->cluster_offset >> 9) + index_in_cluster,
+                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
+            goto done;
+        }
+    }
+
+    return;
+
+done:
+    if (acb->qiov->niov > 1) {
+        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+        qemu_vfree(acb->orig_buf);
+    }
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QCowAIOCB *acb;
+    int ret;
+
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    if (!acb)
+        return NULL;
+
+    ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+    uint64_t cluster_offset;
+    const uint8_t *src_buf;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0)
+        goto done;
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
+                                        index_in_cluster,
+                                        index_in_cluster + acb->n);
+    if (!cluster_offset || (cluster_offset & 511) != 0) {
+        ret = -EIO;
+        goto done;
+    }
+    if (s->crypt_method) {
+        if (!acb->cluster_data) {
+            acb->cluster_data = qemu_mallocz(s->cluster_size);
+            if (!acb->cluster_data) {
+                ret = -ENOMEM;
+                goto done;
+            }
+        }
+        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
+                        acb->n, 1, &s->aes_encrypt_key);
+        src_buf = acb->cluster_data;
+    } else {
+        src_buf = acb->buf;
+    }
+
+    acb->hd_iov.iov_base = (void *)src_buf;
+    acb->hd_iov.iov_len = acb->n * 512;
+    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    acb->hd_aiocb = bdrv_aio_writev(bs->file,
+                                    (cluster_offset >> 9) + index_in_cluster,
+                                    &acb->hd_qiov, acb->n,
+                                    qcow_aio_write_cb, acb);
+    if (acb->hd_aiocb == NULL) {
+        ret = -EIO;
+        goto done;
+    }
+    return;
+
+done:
+    if (acb->qiov->niov > 1)
+        qemu_vfree(acb->orig_buf);
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowAIOCB *acb;
+    int ret;
+
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+    if (!acb)
+        return NULL;
+
+
+    ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static void qcow_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+}
+
+static int qcow_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd, header_size, backing_filename_len, l1_size, i, shift;
+    QCowHeader header;
+    uint64_t tmp;
+    int64_t total_size = 0;
+    const char *backing_file = NULL;
+    int flags = 0;
+    int ret;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -errno;
+    memset(&header, 0, sizeof(header));
+    header.magic = cpu_to_be32(QCOW_MAGIC);
+    header.version = cpu_to_be32(QCOW_VERSION);
+    header.size = cpu_to_be64(total_size * 512);
+    header_size = sizeof(header);
+    backing_filename_len = 0;
+    if (backing_file) {
+        if (strcmp(backing_file, "fat:")) {
+            header.backing_file_offset = cpu_to_be64(header_size);
+            backing_filename_len = strlen(backing_file);
+            header.backing_file_size = cpu_to_be32(backing_filename_len);
+            header_size += backing_filename_len;
+        } else {
+            /* special backing file for vvfat */
+            backing_file = NULL;
+        }
+        header.cluster_bits = 9; /* 512 byte cluster to avoid copying
+                                    unmodifyed sectors */
+        header.l2_bits = 12; /* 32 KB L2 tables */
+    } else {
+        header.cluster_bits = 12; /* 4 KB clusters */
+        header.l2_bits = 9; /* 4 KB L2 tables */
+    }
+    header_size = (header_size + 7) & ~7;
+    shift = header.cluster_bits + header.l2_bits;
+    l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
+
+    header.l1_table_offset = cpu_to_be64(header_size);
+    if (flags & BLOCK_FLAG_ENCRYPT) {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+    } else {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+    }
+
+    /* write all the data */
+    ret = qemu_write_full(fd, &header, sizeof(header));
+    if (ret != sizeof(header)) {
+        ret = -errno;
+        goto exit;
+    }
+
+    if (backing_file) {
+        ret = qemu_write_full(fd, backing_file, backing_filename_len);
+        if (ret != backing_filename_len) {
+            ret = -errno;
+            goto exit;
+        }
+
+    }
+    lseek(fd, header_size, SEEK_SET);
+    tmp = 0;
+    for(i = 0;i < l1_size; i++) {
+        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
+        if (ret != sizeof(tmp)) {
+            ret = -errno;
+            goto exit;
+        }
+    }
+
+    ret = 0;
+exit:
+    close(fd);
+    return ret;
+}
+
+static int qcow_make_empty(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+    int ret;
+
+    memset(s->l1_table, 0, l1_length);
+    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
+            l1_length) < 0)
+        return -1;
+    ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
+    if (ret < 0)
+        return ret;
+
+    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+
+    return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+   tables to avoid losing bytes in alignment */
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    z_stream strm;
+    int ret, out_len;
+    uint8_t *out_buf;
+    uint64_t cluster_offset;
+
+    if (nb_sectors != s->cluster_sectors)
+        return -EINVAL;
+
+    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+    if (!out_buf)
+        return -1;
+
+    /* best compression, small window, no zlib header */
+    memset(&strm, 0, sizeof(strm));
+    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
+                       Z_DEFLATED, -12,
+                       9, Z_DEFAULT_STRATEGY);
+    if (ret != 0) {
+        qemu_free(out_buf);
+        return -1;
+    }
+
+    strm.avail_in = s->cluster_size;
+    strm.next_in = (uint8_t *)buf;
+    strm.avail_out = s->cluster_size;
+    strm.next_out = out_buf;
+
+    ret = deflate(&strm, Z_FINISH);
+    if (ret != Z_STREAM_END && ret != Z_OK) {
+        qemu_free(out_buf);
+        deflateEnd(&strm);
+        return -1;
+    }
+    out_len = strm.next_out - out_buf;
+
+    deflateEnd(&strm);
+
+    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+        /* could not compress: write normal cluster */
+        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+    } else {
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
+                                            out_len, 0, 0);
+        cluster_offset &= s->cluster_offset_mask;
+        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
+            qemu_free(out_buf);
+            return -1;
+        }
+    }
+
+    qemu_free(out_buf);
+    return 0;
+}
+
+static int qcow_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdi->cluster_size = s->cluster_size;
+    return 0;
+}
+
+
+static QEMUOptionParameter qcow_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_ENCRYPT,
+        .type = OPT_FLAG,
+        .help = "Encrypt the image"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_qcow = {
+    .format_name	= "qcow",
+    .instance_size	= sizeof(BDRVQcowState),
+    .bdrv_probe		= qcow_probe,
+    .bdrv_open		= qcow_open,
+    .bdrv_close		= qcow_close,
+    .bdrv_create	= qcow_create,
+    .bdrv_flush		= qcow_flush,
+    .bdrv_is_allocated	= qcow_is_allocated,
+    .bdrv_set_key	= qcow_set_key,
+    .bdrv_make_empty	= qcow_make_empty,
+    .bdrv_aio_readv	= qcow_aio_readv,
+    .bdrv_aio_writev	= qcow_aio_writev,
+    .bdrv_aio_flush	= qcow_aio_flush,
+    .bdrv_write_compressed = qcow_write_compressed,
+    .bdrv_get_info	= qcow_get_info,
+
+    .create_options = qcow_create_options,
+};
+
+static void bdrv_qcow_init(void)
+{
+    bdrv_register(&bdrv_qcow);
+}
+
+block_init(bdrv_qcow_init);
diff --git a/qemu-0.15.x/block/qcow2-cache.c b/qemu-0.15.x/block/qcow2-cache.c
new file mode 100644
index 0000000..8408847
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2-cache.c
@@ -0,0 +1,326 @@
+/*
+ * L2/refcount table cache for the QCOW2 format
+ *
+ * Copyright (c) 2010 Kevin Wolf <kwolf at redhat.com>
+ *
+ * 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 "block_int.h"
+#include "qemu-common.h"
+#include "qcow2.h"
+
+typedef struct Qcow2CachedTable {
+    void*   table;
+    int64_t offset;
+    bool    dirty;
+    int     cache_hits;
+    int     ref;
+} Qcow2CachedTable;
+
+struct Qcow2Cache {
+    Qcow2CachedTable*       entries;
+    struct Qcow2Cache*      depends;
+    int                     size;
+    bool                    depends_on_flush;
+    bool                    writethrough;
+};
+
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+    bool writethrough)
+{
+    BDRVQcowState *s = bs->opaque;
+    Qcow2Cache *c;
+    int i;
+
+    c = qemu_mallocz(sizeof(*c));
+    c->size = num_tables;
+    c->entries = qemu_mallocz(sizeof(*c->entries) * num_tables);
+    c->writethrough = writethrough;
+
+    for (i = 0; i < c->size; i++) {
+        c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
+    }
+
+    return c;
+}
+
+int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
+{
+    int i;
+
+    for (i = 0; i < c->size; i++) {
+        assert(c->entries[i].ref == 0);
+        qemu_vfree(c->entries[i].table);
+    }
+
+    qemu_free(c->entries);
+    qemu_free(c);
+
+    return 0;
+}
+
+static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
+{
+    int ret;
+
+    ret = qcow2_cache_flush(bs, c->depends);
+    if (ret < 0) {
+        return ret;
+    }
+
+    c->depends = NULL;
+    c->depends_on_flush = false;
+
+    return 0;
+}
+
+static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret = 0;
+
+    if (!c->entries[i].dirty || !c->entries[i].offset) {
+        return 0;
+    }
+
+    if (c->depends) {
+        ret = qcow2_cache_flush_dependency(bs, c);
+    } else if (c->depends_on_flush) {
+        ret = bdrv_flush(bs->file);
+        if (ret >= 0) {
+            c->depends_on_flush = false;
+        }
+    }
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (c == s->refcount_block_cache) {
+        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
+    } else if (c == s->l2_table_cache) {
+        BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
+    }
+
+    ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
+        s->cluster_size);
+    if (ret < 0) {
+        return ret;
+    }
+
+    c->entries[i].dirty = false;
+
+    return 0;
+}
+
+int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
+{
+    int result = 0;
+    int ret;
+    int i;
+
+    for (i = 0; i < c->size; i++) {
+        ret = qcow2_cache_entry_flush(bs, c, i);
+        if (ret < 0 && result != -ENOSPC) {
+            result = ret;
+        }
+    }
+
+    if (result == 0) {
+        ret = bdrv_flush(bs->file);
+        if (ret < 0) {
+            result = ret;
+        }
+    }
+
+    return result;
+}
+
+int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
+    Qcow2Cache *dependency)
+{
+    int ret;
+
+    if (dependency->depends) {
+        ret = qcow2_cache_flush_dependency(bs, dependency);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (c->depends && (c->depends != dependency)) {
+        ret = qcow2_cache_flush_dependency(bs, c);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    c->depends = dependency;
+    return 0;
+}
+
+void qcow2_cache_depends_on_flush(Qcow2Cache *c)
+{
+    c->depends_on_flush = true;
+}
+
+static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
+{
+    int i;
+    int min_count = INT_MAX;
+    int min_index = -1;
+
+
+    for (i = 0; i < c->size; i++) {
+        if (c->entries[i].ref) {
+            continue;
+        }
+
+        if (c->entries[i].cache_hits < min_count) {
+            min_index = i;
+            min_count = c->entries[i].cache_hits;
+        }
+
+        /* Give newer hits priority */
+        /* TODO Check how to optimize the replacement strategy */
+        c->entries[i].cache_hits /= 2;
+    }
+
+    if (min_index == -1) {
+        /* This can't happen in current synchronous code, but leave the check
+         * here as a reminder for whoever starts using AIO with the cache */
+        abort();
+    }
+    return min_index;
+}
+
+static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
+    uint64_t offset, void **table, bool read_from_disk)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+    int ret;
+
+    /* Check if the table is already cached */
+    for (i = 0; i < c->size; i++) {
+        if (c->entries[i].offset == offset) {
+            goto found;
+        }
+    }
+
+    /* If not, write a table back and replace it */
+    i = qcow2_cache_find_entry_to_replace(c);
+    if (i < 0) {
+        return i;
+    }
+
+    ret = qcow2_cache_entry_flush(bs, c, i);
+    if (ret < 0) {
+        return ret;
+    }
+
+    c->entries[i].offset = 0;
+    if (read_from_disk) {
+        if (c == s->l2_table_cache) {
+            BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
+        }
+
+        ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    /* Give the table some hits for the start so that it won't be replaced
+     * immediately. The number 32 is completely arbitrary. */
+    c->entries[i].cache_hits = 32;
+    c->entries[i].offset = offset;
+
+    /* And return the right table */
+found:
+    c->entries[i].cache_hits++;
+    c->entries[i].ref++;
+    *table = c->entries[i].table;
+    return 0;
+}
+
+int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+    void **table)
+{
+    return qcow2_cache_do_get(bs, c, offset, table, true);
+}
+
+int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+    void **table)
+{
+    return qcow2_cache_do_get(bs, c, offset, table, false);
+}
+
+int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
+{
+    int i;
+
+    for (i = 0; i < c->size; i++) {
+        if (c->entries[i].table == *table) {
+            goto found;
+        }
+    }
+    return -ENOENT;
+
+found:
+    c->entries[i].ref--;
+    *table = NULL;
+
+    assert(c->entries[i].ref >= 0);
+
+    if (c->writethrough) {
+        return qcow2_cache_entry_flush(bs, c, i);
+    } else {
+        return 0;
+    }
+}
+
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
+{
+    int i;
+
+    for (i = 0; i < c->size; i++) {
+        if (c->entries[i].table == table) {
+            goto found;
+        }
+    }
+    abort();
+
+found:
+    c->entries[i].dirty = true;
+}
+
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable)
+{
+    bool old = c->writethrough;
+
+    if (!old && enable) {
+        qcow2_cache_flush(bs, c);
+    }
+
+    c->writethrough = enable;
+    return old;
+}
diff --git a/qemu-0.15.x/block/qcow2-cluster.c b/qemu-0.15.x/block/qcow2-cluster.c
new file mode 100644
index 0000000..882f50a
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2-cluster.c
@@ -0,0 +1,979 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-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 <zlib.h>
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int new_l1_size, new_l1_size2, ret, i;
+    uint64_t *new_l1_table;
+    int64_t new_l1_table_offset;
+    uint8_t data[12];
+
+    if (min_size <= s->l1_size)
+        return 0;
+
+    if (exact_size) {
+        new_l1_size = min_size;
+    } else {
+        /* Bump size up to reduce the number of times we have to grow */
+        new_l1_size = s->l1_size;
+        if (new_l1_size == 0) {
+            new_l1_size = 1;
+        }
+        while (min_size > new_l1_size) {
+            new_l1_size = (new_l1_size * 3 + 1) / 2;
+        }
+    }
+
+#ifdef DEBUG_ALLOC2
+    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
+#endif
+
+    new_l1_size2 = sizeof(uint64_t) * new_l1_size;
+    new_l1_table = qemu_mallocz(align_offset(new_l1_size2, 512));
+    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
+
+    /* write new table (align to cluster) */
+    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
+    new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
+    if (new_l1_table_offset < 0) {
+        qemu_free(new_l1_table);
+        return new_l1_table_offset;
+    }
+
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
+    ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
+    if (ret < 0)
+        goto fail;
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
+
+    /* set new table */
+    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
+    cpu_to_be32w((uint32_t*)data, new_l1_size);
+    cpu_to_be64wu((uint64_t*)(data + 4), new_l1_table_offset);
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
+    if (ret < 0) {
+        goto fail;
+    }
+    qemu_free(s->l1_table);
+    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
+    s->l1_table_offset = new_l1_table_offset;
+    s->l1_table = new_l1_table;
+    s->l1_size = new_l1_size;
+    return 0;
+ fail:
+    qemu_free(new_l1_table);
+    qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
+    return ret;
+}
+
+/*
+ * l2_load
+ *
+ * Loads a L2 table into memory. If the table is in the cache, the cache
+ * is used; otherwise the L2 table is loaded from the image file.
+ *
+ * Returns a pointer to the L2 table on success, or NULL if the read from
+ * the image file failed.
+ */
+
+static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
+    uint64_t **l2_table)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset, (void**) l2_table);
+
+    return ret;
+}
+
+/*
+ * Writes one sector of the L1 table to the disk (can't update single entries
+ * and we really don't want bdrv_pread to perform a read-modify-write)
+ */
+#define L1_ENTRIES_PER_SECTOR (512 / 8)
+static int write_l1_entry(BlockDriverState *bs, int l1_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t buf[L1_ENTRIES_PER_SECTOR];
+    int l1_start_index;
+    int i, ret;
+
+    l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
+    for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
+        buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
+    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,
+        buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+/*
+ * l2_allocate
+ *
+ * Allocate a new l2 entry in the file. If l1_index points to an already
+ * used entry in the L2 table (i.e. we are doing a copy on write for the L2
+ * table) copy the contents of the old L2 table into the newly allocated one.
+ * Otherwise the new table is initialized with zeros.
+ *
+ */
+
+static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t old_l2_offset;
+    uint64_t *l2_table;
+    int64_t l2_offset;
+    int ret;
+
+    old_l2_offset = s->l1_table[l1_index];
+
+    /* allocate a new l2 entry */
+
+    l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+    if (l2_offset < 0) {
+        return l2_offset;
+    }
+
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* allocate a new entry in the l2 cache */
+
+    ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
+    if (ret < 0) {
+        return ret;
+    }
+
+    l2_table = *table;
+
+    if (old_l2_offset == 0) {
+        /* if there was no old l2 table, clear the new table */
+        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+    } else {
+        uint64_t* old_table;
+
+        /* if there was an old l2 table, read it from the disk */
+        BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
+        ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
+            (void**) &old_table);
+        if (ret < 0) {
+            goto fail;
+        }
+
+        memcpy(l2_table, old_table, s->cluster_size);
+
+        ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &old_table);
+        if (ret < 0) {
+            goto fail;
+        }
+    }
+
+    /* write the l2 table to the file */
+    BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
+
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+    ret = qcow2_cache_flush(bs, s->l2_table_cache);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* update the L1 entry */
+    s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
+    ret = write_l1_entry(bs, l1_index);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    *table = l2_table;
+    return 0;
+
+fail:
+    qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
+    s->l1_table[l1_index] = old_l2_offset;
+    return ret;
+}
+
+static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
+        uint64_t *l2_table, uint64_t start, uint64_t mask)
+{
+    int i;
+    uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+
+    if (!offset)
+        return 0;
+
+    for (i = start; i < start + nb_clusters; i++)
+        if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+            break;
+
+	return (i - start);
+}
+
+static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
+{
+    int i = 0;
+
+    while(nb_clusters-- && l2_table[i] == 0)
+        i++;
+
+    return i;
+}
+
+/* The crypt function is compatible with the linux cryptoloop
+   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
+   supported */
+void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                           uint8_t *out_buf, const uint8_t *in_buf,
+                           int nb_sectors, int enc,
+                           const AES_KEY *key)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } ivec;
+    int i;
+
+    for(i = 0; i < nb_sectors; i++) {
+        ivec.ll[0] = cpu_to_le64(sector_num);
+        ivec.ll[1] = 0;
+        AES_cbc_encrypt(in_buf, out_buf, 512, key,
+                        ivec.b, enc);
+        sector_num++;
+        in_buf += 512;
+        out_buf += 512;
+    }
+}
+
+
+static int qcow2_read(BlockDriverState *bs, int64_t sector_num,
+                      uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, index_in_cluster, n, n1;
+    uint64_t cluster_offset;
+    struct iovec iov;
+    QEMUIOVector qiov;
+
+    while (nb_sectors > 0) {
+        n = nb_sectors;
+
+        ret = qcow2_get_cluster_offset(bs, sector_num << 9, &n,
+            &cluster_offset);
+        if (ret < 0) {
+            return ret;
+        }
+
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        if (!cluster_offset) {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                iov.iov_base = buf;
+                iov.iov_len = n * 512;
+                qemu_iovec_init_external(&qiov, &iov, 1);
+
+                n1 = qcow2_backing_read1(bs->backing_hd, &qiov, sector_num, n);
+                if (n1 > 0) {
+                    BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING);
+                    ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
+                    if (ret < 0)
+                        return -1;
+                }
+            } else {
+                memset(buf, 0, 512 * n);
+            }
+        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            if (qcow2_decompress_cluster(bs, cluster_offset) < 0)
+                return -1;
+            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
+        } else {
+            BLKDBG_EVENT(bs->file, BLKDBG_READ);
+            ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512);
+            if (ret != n * 512)
+                return -1;
+            if (s->crypt_method) {
+                qcow2_encrypt_sectors(s, sector_num, buf, buf, n, 0,
+                                &s->aes_decrypt_key);
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+
+static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
+                        uint64_t cluster_offset, int n_start, int n_end)
+{
+    BDRVQcowState *s = bs->opaque;
+    int n, ret;
+
+    n = n_end - n_start;
+    if (n <= 0)
+        return 0;
+    BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
+    ret = qcow2_read(bs, start_sect + n_start, s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    if (s->crypt_method) {
+        qcow2_encrypt_sectors(s, start_sect + n_start,
+                        s->cluster_data,
+                        s->cluster_data, n, 1,
+                        &s->aes_encrypt_key);
+    }
+    BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
+    ret = bdrv_write(bs->file, (cluster_offset >> 9) + n_start,
+        s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    return 0;
+}
+
+
+/*
+ * get_cluster_offset
+ *
+ * For a given offset of the disk image, find the cluster offset in
+ * qcow2 file. The offset is stored in *cluster_offset.
+ *
+ * on entry, *num is the number of contiguous clusters we'd like to
+ * access following offset.
+ *
+ * on exit, *num is the number of contiguous clusters we can read.
+ *
+ * Return 0, if the offset is found
+ * Return -errno, otherwise.
+ *
+ */
+
+int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int *num, uint64_t *cluster_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    unsigned int l1_index, l2_index;
+    uint64_t l2_offset, *l2_table;
+    int l1_bits, c;
+    unsigned int index_in_cluster, nb_clusters;
+    uint64_t nb_available, nb_needed;
+    int ret;
+
+    index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
+    nb_needed = *num + index_in_cluster;
+
+    l1_bits = s->l2_bits + s->cluster_bits;
+
+    /* compute how many bytes there are between the offset and
+     * the end of the l1 entry
+     */
+
+    nb_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1));
+
+    /* compute the number of available sectors */
+
+    nb_available = (nb_available >> 9) + index_in_cluster;
+
+    if (nb_needed > nb_available) {
+        nb_needed = nb_available;
+    }
+
+    *cluster_offset = 0;
+
+    /* seek the the l2 offset in the l1 table */
+
+    l1_index = offset >> l1_bits;
+    if (l1_index >= s->l1_size)
+        goto out;
+
+    l2_offset = s->l1_table[l1_index];
+
+    /* seek the l2 table of the given l2 offset */
+
+    if (!l2_offset)
+        goto out;
+
+    /* load the l2 table in memory */
+
+    l2_offset &= ~QCOW_OFLAG_COPIED;
+    ret = l2_load(bs, l2_offset, &l2_table);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* find the cluster offset for the given disk offset */
+
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+    *cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    nb_clusters = size_to_clusters(s, nb_needed << 9);
+
+    if (!*cluster_offset) {
+        /* how many empty clusters ? */
+        c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
+    } else {
+        /* how many allocated clusters ? */
+        c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+                &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+    }
+
+    qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+
+   nb_available = (c * s->cluster_sectors);
+out:
+    if (nb_available > nb_needed)
+        nb_available = nb_needed;
+
+    *num = nb_available - index_in_cluster;
+
+    *cluster_offset &=~QCOW_OFLAG_COPIED;
+    return 0;
+}
+
+/*
+ * get_cluster_table
+ *
+ * for a given disk offset, load (and allocate if needed)
+ * the l2 table.
+ *
+ * the l2 table offset in the qcow2 file and the cluster index
+ * in the l2 table are given to the caller.
+ *
+ * Returns 0 on success, -errno in failure case
+ */
+static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
+                             uint64_t **new_l2_table,
+                             uint64_t *new_l2_offset,
+                             int *new_l2_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    unsigned int l1_index, l2_index;
+    uint64_t l2_offset;
+    uint64_t *l2_table = NULL;
+    int ret;
+
+    /* seek the the l2 offset in the l1 table */
+
+    l1_index = offset >> (s->l2_bits + s->cluster_bits);
+    if (l1_index >= s->l1_size) {
+        ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+    l2_offset = s->l1_table[l1_index];
+
+    /* seek the l2 table of the given l2 offset */
+
+    if (l2_offset & QCOW_OFLAG_COPIED) {
+        /* load the l2 table in memory */
+        l2_offset &= ~QCOW_OFLAG_COPIED;
+        ret = l2_load(bs, l2_offset, &l2_table);
+        if (ret < 0) {
+            return ret;
+        }
+    } else {
+        /* First allocate a new L2 table (and do COW if needed) */
+        ret = l2_allocate(bs, l1_index, &l2_table);
+        if (ret < 0) {
+            return ret;
+        }
+
+        /* Then decrease the refcount of the old table */
+        if (l2_offset) {
+            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+        }
+        l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
+    }
+
+    /* find the cluster offset for the given disk offset */
+
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+
+    *new_l2_table = l2_table;
+    *new_l2_offset = l2_offset;
+    *new_l2_index = l2_index;
+
+    return 0;
+}
+
+/*
+ * alloc_compressed_cluster_offset
+ *
+ * For a given offset of the disk image, return cluster offset in
+ * qcow2 file.
+ *
+ * If the offset is not found, allocate a new compressed cluster.
+ *
+ * Return the cluster offset if successful,
+ * Return 0, otherwise.
+ *
+ */
+
+uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
+                                               uint64_t offset,
+                                               int compressed_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l2_index, ret;
+    uint64_t l2_offset, *l2_table;
+    int64_t cluster_offset;
+    int nb_csectors;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+    if (ret < 0) {
+        return 0;
+    }
+
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    if (cluster_offset & QCOW_OFLAG_COPIED)
+        return cluster_offset & ~QCOW_OFLAG_COPIED;
+
+    if (cluster_offset)
+        qcow2_free_any_clusters(bs, cluster_offset, 1);
+
+    cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
+    if (cluster_offset < 0) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        return 0;
+    }
+
+    nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
+                  (cluster_offset >> 9);
+
+    cluster_offset |= QCOW_OFLAG_COMPRESSED |
+                      ((uint64_t)nb_csectors << s->csize_shift);
+
+    /* update L2 table */
+
+    /* compressed clusters never have the copied flag */
+
+    BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+    l2_table[l2_index] = cpu_to_be64(cluster_offset);
+    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    if (ret < 0) {
+        return 0;
+    }
+
+    return cluster_offset;
+}
+
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, j = 0, l2_index, ret;
+    uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
+    uint64_t cluster_offset = m->cluster_offset;
+    bool cow = false;
+
+    if (m->nb_clusters == 0)
+        return 0;
+
+    old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t));
+
+    /* copy content of unmodified sectors */
+    start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
+    if (m->n_start) {
+        cow = true;
+        ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start);
+        if (ret < 0)
+            goto err;
+    }
+
+    if (m->nb_available & (s->cluster_sectors - 1)) {
+        uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1);
+        cow = true;
+        ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9),
+                m->nb_available - end, s->cluster_sectors);
+        if (ret < 0)
+            goto err;
+    }
+
+    /*
+     * Update L2 table.
+     *
+     * Before we update the L2 table to actually point to the new cluster, we
+     * need to be sure that the refcounts have been increased and COW was
+     * handled.
+     */
+    if (cow) {
+        qcow2_cache_depends_on_flush(s->l2_table_cache);
+    }
+
+    qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
+    ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
+    if (ret < 0) {
+        goto err;
+    }
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+
+    for (i = 0; i < m->nb_clusters; i++) {
+        /* if two concurrent writes happen to the same unallocated cluster
+	 * each write allocates separate cluster and writes data concurrently.
+	 * The first one to complete updates l2 table with pointer to its
+	 * cluster the second one has to do RMW (which is done above by
+	 * copy_sectors()), update l2 table with its cluster pointer and free
+	 * old cluster. This is what this loop does */
+        if(l2_table[l2_index + i] != 0)
+            old_cluster[j++] = l2_table[l2_index + i];
+
+        l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
+                    (i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
+     }
+
+
+    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    if (ret < 0) {
+        goto err;
+    }
+
+    /*
+     * If this was a COW, we need to decrease the refcount of the old cluster.
+     * Also flush bs->file to get the right order for L2 and refcount update.
+     */
+    if (j != 0) {
+        for (i = 0; i < j; i++) {
+            qcow2_free_any_clusters(bs,
+                be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
+        }
+    }
+
+    ret = 0;
+err:
+    qemu_free(old_cluster);
+    return ret;
+ }
+
+/*
+ * alloc_cluster_offset
+ *
+ * For a given offset of the disk image, return cluster offset in qcow2 file.
+ * If the offset is not found, allocate a new cluster.
+ *
+ * If the cluster was already allocated, m->nb_clusters is set to 0,
+ * m->depends_on is set to NULL and the other fields in m are meaningless.
+ *
+ * If the cluster is newly allocated, m->nb_clusters is set to the number of
+ * contiguous clusters that have been allocated. This may be 0 if the request
+ * conflict with another write request in flight; in this case, m->depends_on
+ * is set and the remaining fields of m are meaningless.
+ *
+ * If m->nb_clusters is non-zero, the other fields of m are valid and contain
+ * information about the first allocated cluster.
+ *
+ * Return 0 on success and -errno in error cases
+ */
+int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int n_start, int n_end, int *num, QCowL2Meta *m)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l2_index, ret;
+    uint64_t l2_offset, *l2_table;
+    int64_t cluster_offset;
+    unsigned int nb_clusters, i = 0;
+    QCowL2Meta *old_alloc;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+    if (ret < 0) {
+        return ret;
+    }
+
+    nb_clusters = size_to_clusters(s, n_end << 9);
+
+    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+
+    /* We keep all QCOW_OFLAG_COPIED clusters */
+
+    if (cluster_offset & QCOW_OFLAG_COPIED) {
+        nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
+                &l2_table[l2_index], 0, 0);
+
+        cluster_offset &= ~QCOW_OFLAG_COPIED;
+        m->nb_clusters = 0;
+        m->depends_on = NULL;
+
+        goto out;
+    }
+
+    /* for the moment, multiple compressed clusters are not managed */
+
+    if (cluster_offset & QCOW_OFLAG_COMPRESSED)
+        nb_clusters = 1;
+
+    /* how many available clusters ? */
+
+    while (i < nb_clusters) {
+        i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
+                &l2_table[l2_index], i, 0);
+        if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
+            break;
+        }
+
+        i += count_contiguous_free_clusters(nb_clusters - i,
+                &l2_table[l2_index + i]);
+        if (i >= nb_clusters) {
+            break;
+        }
+
+        cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
+
+        if ((cluster_offset & QCOW_OFLAG_COPIED) ||
+                (cluster_offset & QCOW_OFLAG_COMPRESSED))
+            break;
+    }
+    assert(i <= nb_clusters);
+    nb_clusters = i;
+
+    /*
+     * Check if there already is an AIO write request in flight which allocates
+     * the same cluster. In this case we need to wait until the previous
+     * request has completed and updated the L2 table accordingly.
+     */
+    QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
+
+        uint64_t end_offset = offset + nb_clusters * s->cluster_size;
+        uint64_t old_offset = old_alloc->offset;
+        uint64_t old_end_offset = old_alloc->offset +
+            old_alloc->nb_clusters * s->cluster_size;
+
+        if (end_offset < old_offset || offset > old_end_offset) {
+            /* No intersection */
+        } else {
+            if (offset < old_offset) {
+                /* Stop at the start of a running allocation */
+                nb_clusters = (old_offset - offset) >> s->cluster_bits;
+            } else {
+                nb_clusters = 0;
+            }
+
+            if (nb_clusters == 0) {
+                /* Set dependency and wait for a callback */
+                m->depends_on = old_alloc;
+                m->nb_clusters = 0;
+                *num = 0;
+
+                goto out_wait_dependency;
+            }
+        }
+    }
+
+    if (!nb_clusters) {
+        abort();
+    }
+
+    QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
+
+    /* allocate a new cluster */
+
+    cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
+    if (cluster_offset < 0) {
+        ret = cluster_offset;
+        goto fail;
+    }
+
+    /* save info needed for meta data update */
+    m->offset = offset;
+    m->n_start = n_start;
+    m->nb_clusters = nb_clusters;
+
+out:
+    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    if (ret < 0) {
+        goto fail_put;
+    }
+
+    m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
+    m->cluster_offset = cluster_offset;
+
+    *num = m->nb_available - n_start;
+
+    return 0;
+
+out_wait_dependency:
+    return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+
+fail:
+    qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+fail_put:
+    QLIST_REMOVE(m, next_in_flight);
+    return ret;
+}
+
+static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
+                             const uint8_t *buf, int buf_size)
+{
+    z_stream strm1, *strm = &strm1;
+    int ret, out_len;
+
+    memset(strm, 0, sizeof(*strm));
+
+    strm->next_in = (uint8_t *)buf;
+    strm->avail_in = buf_size;
+    strm->next_out = out_buf;
+    strm->avail_out = out_buf_size;
+
+    ret = inflateInit2(strm, -12);
+    if (ret != Z_OK)
+        return -1;
+    ret = inflate(strm, Z_FINISH);
+    out_len = strm->next_out - out_buf;
+    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+        out_len != out_buf_size) {
+        inflateEnd(strm);
+        return -1;
+    }
+    inflateEnd(strm);
+    return 0;
+}
+
+int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, csize, nb_csectors, sector_offset;
+    uint64_t coffset;
+
+    coffset = cluster_offset & s->cluster_offset_mask;
+    if (s->cluster_cache_offset != coffset) {
+        nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
+        sector_offset = coffset & 511;
+        csize = nb_csectors * 512 - sector_offset;
+        BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
+        ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
+        if (ret < 0) {
+            return ret;
+        }
+        if (decompress_buffer(s->cluster_cache, s->cluster_size,
+                              s->cluster_data + sector_offset, csize) < 0) {
+            return -EIO;
+        }
+        s->cluster_cache_offset = coffset;
+    }
+    return 0;
+}
+
+/*
+ * This discards as many clusters of nb_clusters as possible at once (i.e.
+ * all clusters in the same L2 table) and returns the number of discarded
+ * clusters.
+ */
+static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
+    unsigned int nb_clusters)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t l2_offset, *l2_table;
+    int l2_index;
+    int ret;
+    int i;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Limit nb_clusters to one L2 table */
+    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+    for (i = 0; i < nb_clusters; i++) {
+        uint64_t old_offset;
+
+        old_offset = be64_to_cpu(l2_table[l2_index + i]);
+        old_offset &= ~QCOW_OFLAG_COPIED;
+
+        if (old_offset == 0) {
+            continue;
+        }
+
+        /* First remove L2 entries */
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+        l2_table[l2_index + i] = cpu_to_be64(0);
+
+        /* Then decrease the refcount */
+        qcow2_free_any_clusters(bs, old_offset, 1);
+    }
+
+    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return nb_clusters;
+}
+
+int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
+    int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t end_offset;
+    unsigned int nb_clusters;
+    int ret;
+
+    end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
+
+    /* Round start up and end down */
+    offset = align_offset(offset, s->cluster_size);
+    end_offset &= ~(s->cluster_size - 1);
+
+    if (offset > end_offset) {
+        return 0;
+    }
+
+    nb_clusters = size_to_clusters(s, end_offset - offset);
+
+    /* Each L2 table is handled by its own loop iteration */
+    while (nb_clusters > 0) {
+        ret = discard_single_l2(bs, offset, nb_clusters);
+        if (ret < 0) {
+            return ret;
+        }
+
+        nb_clusters -= ret;
+        offset += (ret * s->cluster_size);
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/block/qcow2-refcount.c b/qemu-0.15.x/block/qcow2-refcount.c
new file mode 100644
index 0000000..14b2f67
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2-refcount.c
@@ -0,0 +1,1185 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-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 "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
+static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
+                            int64_t offset, int64_t length,
+                            int addend);
+
+
+/*********************************************************/
+/* refcount handling */
+
+int qcow2_refcount_init(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, refcount_table_size2, i;
+
+    refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
+    s->refcount_table = qemu_malloc(refcount_table_size2);
+    if (s->refcount_table_size > 0) {
+        BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
+        ret = bdrv_pread(bs->file, s->refcount_table_offset,
+                         s->refcount_table, refcount_table_size2);
+        if (ret != refcount_table_size2)
+            goto fail;
+        for(i = 0; i < s->refcount_table_size; i++)
+            be64_to_cpus(&s->refcount_table[i]);
+    }
+    return 0;
+ fail:
+    return -ENOMEM;
+}
+
+void qcow2_refcount_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->refcount_table);
+}
+
+
+static int load_refcount_block(BlockDriverState *bs,
+                               int64_t refcount_block_offset,
+                               void **refcount_block)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD);
+    ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
+        refcount_block);
+
+    return ret;
+}
+
+/*
+ * Returns the refcount of the cluster given by its index. Any non-negative
+ * return value is the refcount of the cluster, negative values are -errno
+ * and indicate an error.
+ */
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int refcount_table_index, block_index;
+    int64_t refcount_block_offset;
+    int ret;
+    uint16_t *refcount_block;
+    uint16_t refcount;
+
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+    if (refcount_table_index >= s->refcount_table_size)
+        return 0;
+    refcount_block_offset = s->refcount_table[refcount_table_index];
+    if (!refcount_block_offset)
+        return 0;
+
+    ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
+        (void**) &refcount_block);
+    if (ret < 0) {
+        return ret;
+    }
+
+    block_index = cluster_index &
+        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+    refcount = be16_to_cpu(refcount_block[block_index]);
+
+    ret = qcow2_cache_put(bs, s->refcount_block_cache,
+        (void**) &refcount_block);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return refcount;
+}
+
+/*
+ * Rounds the refcount table size up to avoid growing the table for each single
+ * refcount block that is allocated.
+ */
+static unsigned int next_refcount_table_size(BDRVQcowState *s,
+    unsigned int min_size)
+{
+    unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
+    unsigned int refcount_table_clusters =
+        MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
+
+    while (min_clusters > refcount_table_clusters) {
+        refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
+    }
+
+    return refcount_table_clusters << (s->cluster_bits - 3);
+}
+
+
+/* Checks if two offsets are described by the same refcount block */
+static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
+    uint64_t offset_b)
+{
+    uint64_t block_a = offset_a >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
+    uint64_t block_b = offset_b >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
+
+    return (block_a == block_b);
+}
+
+/*
+ * Loads a refcount block. If it doesn't exist yet, it is allocated first
+ * (including growing the refcount table if needed).
+ *
+ * Returns 0 on success or -errno in error case
+ */
+static int alloc_refcount_block(BlockDriverState *bs,
+    int64_t cluster_index, uint16_t **refcount_block)
+{
+    BDRVQcowState *s = bs->opaque;
+    unsigned int refcount_table_index;
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
+
+    /* Find the refcount block for the given cluster */
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+
+    if (refcount_table_index < s->refcount_table_size) {
+
+        uint64_t refcount_block_offset =
+            s->refcount_table[refcount_table_index];
+
+        /* If it's already there, we're done */
+        if (refcount_block_offset) {
+             return load_refcount_block(bs, refcount_block_offset,
+                 (void**) refcount_block);
+        }
+    }
+
+    /*
+     * If we came here, we need to allocate something. Something is at least
+     * a cluster for the new refcount block. It may also include a new refcount
+     * table if the old refcount table is too small.
+     *
+     * Note that allocating clusters here needs some special care:
+     *
+     * - We can't use the normal qcow2_alloc_clusters(), it would try to
+     *   increase the refcount and very likely we would end up with an endless
+     *   recursion. Instead we must place the refcount blocks in a way that
+     *   they can describe them themselves.
+     *
+     * - We need to consider that at this point we are inside update_refcounts
+     *   and doing the initial refcount increase. This means that some clusters
+     *   have already been allocated by the caller, but their refcount isn't
+     *   accurate yet. free_cluster_index tells us where this allocation ends
+     *   as long as we don't overwrite it by freeing clusters.
+     *
+     * - alloc_clusters_noref and qcow2_free_clusters may load a different
+     *   refcount block into the cache
+     */
+
+    *refcount_block = NULL;
+
+    /* We write to the refcount table, so we might depend on L2 tables */
+    qcow2_cache_flush(bs, s->l2_table_cache);
+
+    /* Allocate the refcount block itself and mark it as used */
+    int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
+    if (new_block < 0) {
+        return new_block;
+    }
+
+#ifdef DEBUG_ALLOC2
+    fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
+        " at %" PRIx64 "\n",
+        refcount_table_index, cluster_index << s->cluster_bits, new_block);
+#endif
+
+    if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
+        /* Zero the new refcount block before updating it */
+        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
+            (void**) refcount_block);
+        if (ret < 0) {
+            goto fail_block;
+        }
+
+        memset(*refcount_block, 0, s->cluster_size);
+
+        /* The block describes itself, need to update the cache */
+        int block_index = (new_block >> s->cluster_bits) &
+            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+        (*refcount_block)[block_index] = cpu_to_be16(1);
+    } else {
+        /* Described somewhere else. This can recurse at most twice before we
+         * arrive at a block that describes itself. */
+        ret = update_refcount(bs, new_block, s->cluster_size, 1);
+        if (ret < 0) {
+            goto fail_block;
+        }
+
+        bdrv_flush(bs->file);
+
+        /* Initialize the new refcount block only after updating its refcount,
+         * update_refcount uses the refcount cache itself */
+        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
+            (void**) refcount_block);
+        if (ret < 0) {
+            goto fail_block;
+        }
+
+        memset(*refcount_block, 0, s->cluster_size);
+    }
+
+    /* Now the new refcount block needs to be written to disk */
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
+    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        goto fail_block;
+    }
+
+    /* If the refcount table is big enough, just hook the block up there */
+    if (refcount_table_index < s->refcount_table_size) {
+        uint64_t data64 = cpu_to_be64(new_block);
+        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
+        ret = bdrv_pwrite_sync(bs->file,
+            s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
+            &data64, sizeof(data64));
+        if (ret < 0) {
+            goto fail_block;
+        }
+
+        s->refcount_table[refcount_table_index] = new_block;
+        return 0;
+    }
+
+    ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
+    if (ret < 0) {
+        goto fail_block;
+    }
+
+    /*
+     * If we come here, we need to grow the refcount table. Again, a new
+     * refcount table needs some space and we can't simply allocate to avoid
+     * endless recursion.
+     *
+     * Therefore let's grab new refcount blocks at the end of the image, which
+     * will describe themselves and the new refcount table. This way we can
+     * reference them only in the new table and do the switch to the new
+     * refcount table at once without producing an inconsistent state in
+     * between.
+     */
+    BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW);
+
+    /* Calculate the number of refcount blocks needed so far */
+    uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
+    uint64_t blocks_used = (s->free_cluster_index +
+        refcount_block_clusters - 1) / refcount_block_clusters;
+
+    /* And now we need at least one block more for the new metadata */
+    uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
+    uint64_t last_table_size;
+    uint64_t blocks_clusters;
+    do {
+        uint64_t table_clusters = size_to_clusters(s, table_size);
+        blocks_clusters = 1 +
+            ((table_clusters + refcount_block_clusters - 1)
+            / refcount_block_clusters);
+        uint64_t meta_clusters = table_clusters + blocks_clusters;
+
+        last_table_size = table_size;
+        table_size = next_refcount_table_size(s, blocks_used +
+            ((meta_clusters + refcount_block_clusters - 1)
+            / refcount_block_clusters));
+
+    } while (last_table_size != table_size);
+
+#ifdef DEBUG_ALLOC2
+    fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
+        s->refcount_table_size, table_size);
+#endif
+
+    /* Create the new refcount table and blocks */
+    uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
+        s->cluster_size;
+    uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
+    uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size);
+    uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t));
+
+    assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
+
+    /* Fill the new refcount table */
+    memcpy(new_table, s->refcount_table,
+        s->refcount_table_size * sizeof(uint64_t));
+    new_table[refcount_table_index] = new_block;
+
+    int i;
+    for (i = 0; i < blocks_clusters; i++) {
+        new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
+    }
+
+    /* Fill the refcount blocks */
+    uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
+    int block = 0;
+    for (i = 0; i < table_clusters + blocks_clusters; i++) {
+        new_blocks[block++] = cpu_to_be16(1);
+    }
+
+    /* Write refcount blocks to disk */
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
+    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
+        blocks_clusters * s->cluster_size);
+    qemu_free(new_blocks);
+    if (ret < 0) {
+        goto fail_table;
+    }
+
+    /* Write refcount table to disk */
+    for(i = 0; i < table_size; i++) {
+        cpu_to_be64s(&new_table[i]);
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
+    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
+        table_size * sizeof(uint64_t));
+    if (ret < 0) {
+        goto fail_table;
+    }
+
+    for(i = 0; i < table_size; i++) {
+        cpu_to_be64s(&new_table[i]);
+    }
+
+    /* Hook up the new refcount table in the qcow2 header */
+    uint8_t data[12];
+    cpu_to_be64w((uint64_t*)data, table_offset);
+    cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
+    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
+        data, sizeof(data));
+    if (ret < 0) {
+        goto fail_table;
+    }
+
+    /* And switch it in memory */
+    uint64_t old_table_offset = s->refcount_table_offset;
+    uint64_t old_table_size = s->refcount_table_size;
+
+    qemu_free(s->refcount_table);
+    s->refcount_table = new_table;
+    s->refcount_table_size = table_size;
+    s->refcount_table_offset = table_offset;
+
+    /* Free old table. Remember, we must not change free_cluster_index */
+    uint64_t old_free_cluster_index = s->free_cluster_index;
+    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
+    s->free_cluster_index = old_free_cluster_index;
+
+    ret = load_refcount_block(bs, new_block, (void**) refcount_block);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return new_block;
+
+fail_table:
+    qemu_free(new_table);
+fail_block:
+    if (*refcount_block != NULL) {
+        qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
+    }
+    return ret;
+}
+
+/* XXX: cache several refcount block clusters ? */
+static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
+    int64_t offset, int64_t length, int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+    uint16_t *refcount_block = NULL;
+    int64_t old_table_index = -1;
+    int ret;
+
+#ifdef DEBUG_ALLOC2
+    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
+           offset, length, addend);
+#endif
+    if (length < 0) {
+        return -EINVAL;
+    } else if (length == 0) {
+        return 0;
+    }
+
+    if (addend < 0) {
+        qcow2_cache_set_dependency(bs, s->refcount_block_cache,
+            s->l2_table_cache);
+    }
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + length - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size)
+    {
+        int block_index, refcount;
+        int64_t cluster_index = cluster_offset >> s->cluster_bits;
+        int64_t table_index =
+            cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+
+        /* Load the refcount block and allocate it if needed */
+        if (table_index != old_table_index) {
+            if (refcount_block) {
+                ret = qcow2_cache_put(bs, s->refcount_block_cache,
+                    (void**) &refcount_block);
+                if (ret < 0) {
+                    goto fail;
+                }
+            }
+
+            ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
+            if (ret < 0) {
+                goto fail;
+            }
+        }
+        old_table_index = table_index;
+
+        qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
+
+        /* we can update the count and save it */
+        block_index = cluster_index &
+            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+
+        refcount = be16_to_cpu(refcount_block[block_index]);
+        refcount += addend;
+        if (refcount < 0 || refcount > 0xffff) {
+            ret = -EINVAL;
+            goto fail;
+        }
+        if (refcount == 0 && cluster_index < s->free_cluster_index) {
+            s->free_cluster_index = cluster_index;
+        }
+        refcount_block[block_index] = cpu_to_be16(refcount);
+    }
+
+    ret = 0;
+fail:
+    /* Write last changed block to disk */
+    if (refcount_block) {
+        int wret;
+        wret = qcow2_cache_put(bs, s->refcount_block_cache,
+            (void**) &refcount_block);
+        if (wret < 0) {
+            return ret < 0 ? ret : wret;
+        }
+    }
+
+    /*
+     * Try do undo any updates if an error is returned (This may succeed in
+     * some cases like ENOSPC for allocating a new refcount block)
+     */
+    if (ret < 0) {
+        int dummy;
+        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
+        (void)dummy;
+    }
+
+    return ret;
+}
+
+/*
+ * Increases or decreases the refcount of a given cluster by one.
+ * addend must be 1 or -1.
+ *
+ * If the return value is non-negative, it is the new refcount of the cluster.
+ * If it is negative, it is -errno and indicates an error.
+ */
+static int update_cluster_refcount(BlockDriverState *bs,
+                                   int64_t cluster_index,
+                                   int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
+    if (ret < 0) {
+        return ret;
+    }
+
+    bdrv_flush(bs->file);
+
+    return get_refcount(bs, cluster_index);
+}
+
+
+
+/*********************************************************/
+/* cluster allocation functions */
+
+
+
+/* return < 0 if error */
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, nb_clusters, refcount;
+
+    nb_clusters = size_to_clusters(s, size);
+retry:
+    for(i = 0; i < nb_clusters; i++) {
+        int64_t next_cluster_index = s->free_cluster_index++;
+        refcount = get_refcount(bs, next_cluster_index);
+
+        if (refcount < 0) {
+            return refcount;
+        } else if (refcount != 0) {
+            goto retry;
+        }
+    }
+#ifdef DEBUG_ALLOC2
+    printf("alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
+            size,
+            (s->free_cluster_index - nb_clusters) << s->cluster_bits);
+#endif
+    return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
+}
+
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
+{
+    int64_t offset;
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
+    offset = alloc_clusters_noref(bs, size);
+    if (offset < 0) {
+        return offset;
+    }
+
+    ret = update_refcount(bs, offset, size, 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return offset;
+}
+
+/* only used to allocate compressed sectors. We try to allocate
+   contiguous sectors. size must be <= cluster_size */
+int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, cluster_offset;
+    int free_in_cluster;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
+    assert(size > 0 && size <= s->cluster_size);
+    if (s->free_byte_offset == 0) {
+        s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
+        if (s->free_byte_offset < 0) {
+            return s->free_byte_offset;
+        }
+    }
+ redo:
+    free_in_cluster = s->cluster_size -
+        (s->free_byte_offset & (s->cluster_size - 1));
+    if (size <= free_in_cluster) {
+        /* enough space in current cluster */
+        offset = s->free_byte_offset;
+        s->free_byte_offset += size;
+        free_in_cluster -= size;
+        if (free_in_cluster == 0)
+            s->free_byte_offset = 0;
+        if ((offset & (s->cluster_size - 1)) != 0)
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+    } else {
+        offset = qcow2_alloc_clusters(bs, s->cluster_size);
+        if (offset < 0) {
+            return offset;
+        }
+        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
+        if ((cluster_offset + s->cluster_size) == offset) {
+            /* we are lucky: contiguous data */
+            offset = s->free_byte_offset;
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+            s->free_byte_offset += size;
+        } else {
+            s->free_byte_offset = offset;
+            goto redo;
+        }
+    }
+
+    bdrv_flush(bs->file);
+    return offset;
+}
+
+void qcow2_free_clusters(BlockDriverState *bs,
+                          int64_t offset, int64_t size)
+{
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE);
+    ret = update_refcount(bs, offset, size, -1);
+    if (ret < 0) {
+        fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
+        /* TODO Remember the clusters to free them later and avoid leaking */
+    }
+}
+
+/*
+ * free_any_clusters
+ *
+ * free clusters according to its type: compressed or not
+ *
+ */
+
+void qcow2_free_any_clusters(BlockDriverState *bs,
+    uint64_t cluster_offset, int nb_clusters)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    /* free the cluster */
+
+    if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        int nb_csectors;
+        nb_csectors = ((cluster_offset >> s->csize_shift) &
+                       s->csize_mask) + 1;
+        qcow2_free_clusters(bs,
+            (cluster_offset & s->cluster_offset_mask) & ~511,
+            nb_csectors * 512);
+        return;
+    }
+
+    qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
+
+    return;
+}
+
+
+
+/*********************************************************/
+/* snapshots and image creation */
+
+
+
+void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
+    int64_t size)
+{
+    int refcount;
+    int64_t start, last, cluster_offset;
+    uint16_t *p;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1)  & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size) {
+        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
+        refcount = be16_to_cpu(*p);
+        refcount++;
+        *p = cpu_to_be16(refcount);
+    }
+}
+
+/* update the refcounts of snapshots and the copied flag */
+int qcow2_update_snapshot_refcount(BlockDriverState *bs,
+    int64_t l1_table_offset, int l1_size, int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
+    int64_t old_offset, old_l2_offset;
+    int i, j, l1_modified = 0, nb_csectors, refcount;
+    int ret;
+    bool old_l2_writethrough, old_refcount_writethrough;
+
+    /* Switch caches to writeback mode during update */
+    old_l2_writethrough =
+        qcow2_cache_set_writethrough(bs, s->l2_table_cache, false);
+    old_refcount_writethrough =
+        qcow2_cache_set_writethrough(bs, s->refcount_block_cache, false);
+
+    l2_table = NULL;
+    l1_table = NULL;
+    l1_size2 = l1_size * sizeof(uint64_t);
+    if (l1_table_offset != s->l1_table_offset) {
+        if (l1_size2 != 0) {
+            l1_table = qemu_mallocz(align_offset(l1_size2, 512));
+        } else {
+            l1_table = NULL;
+        }
+        l1_allocated = 1;
+        if (bdrv_pread(bs->file, l1_table_offset,
+                       l1_table, l1_size2) != l1_size2)
+        {
+            ret = -EIO;
+            goto fail;
+        }
+
+        for(i = 0;i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    } else {
+        assert(l1_size == s->l1_size);
+        l1_table = s->l1_table;
+        l1_allocated = 0;
+    }
+
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            old_l2_offset = l2_offset;
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+
+            ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
+                (void**) &l2_table);
+            if (ret < 0) {
+                goto fail;
+            }
+
+            for(j = 0; j < s->l2_size; j++) {
+                offset = be64_to_cpu(l2_table[j]);
+                if (offset != 0) {
+                    old_offset = offset;
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    if (offset & QCOW_OFLAG_COMPRESSED) {
+                        nb_csectors = ((offset >> s->csize_shift) &
+                                       s->csize_mask) + 1;
+                        if (addend != 0) {
+                            int ret;
+                            ret = update_refcount(bs,
+                                (offset & s->cluster_offset_mask) & ~511,
+                                nb_csectors * 512, addend);
+                            if (ret < 0) {
+                                goto fail;
+                            }
+
+                            /* TODO Flushing once for the whole function should
+                             * be enough */
+                            bdrv_flush(bs->file);
+                        }
+                        /* compressed clusters are never modified */
+                        refcount = 2;
+                    } else {
+                        if (addend != 0) {
+                            refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+                        } else {
+                            refcount = get_refcount(bs, offset >> s->cluster_bits);
+                        }
+
+                        if (refcount < 0) {
+                            ret = -EIO;
+                            goto fail;
+                        }
+                    }
+
+                    if (refcount == 1) {
+                        offset |= QCOW_OFLAG_COPIED;
+                    }
+                    if (offset != old_offset) {
+                        if (addend > 0) {
+                            qcow2_cache_set_dependency(bs, s->l2_table_cache,
+                                s->refcount_block_cache);
+                        }
+                        l2_table[j] = cpu_to_be64(offset);
+                        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+                    }
+                }
+            }
+
+            ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+            if (ret < 0) {
+                goto fail;
+            }
+
+
+            if (addend != 0) {
+                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
+            } else {
+                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
+            }
+            if (refcount < 0) {
+                ret = -EIO;
+                goto fail;
+            } else if (refcount == 1) {
+                l2_offset |= QCOW_OFLAG_COPIED;
+            }
+            if (l2_offset != old_l2_offset) {
+                l1_table[i] = l2_offset;
+                l1_modified = 1;
+            }
+        }
+    }
+
+    ret = 0;
+fail:
+    if (l2_table) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    }
+
+    /* Enable writethrough cache mode again */
+    qcow2_cache_set_writethrough(bs, s->l2_table_cache, old_l2_writethrough);
+    qcow2_cache_set_writethrough(bs, s->refcount_block_cache,
+        old_refcount_writethrough);
+
+    if (l1_modified) {
+        for(i = 0; i < l1_size; i++)
+            cpu_to_be64s(&l1_table[i]);
+        if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
+                        l1_size2) < 0)
+            goto fail;
+        for(i = 0; i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    }
+    if (l1_allocated)
+        qemu_free(l1_table);
+    return ret;
+}
+
+
+
+
+/*********************************************************/
+/* refcount checking functions */
+
+
+
+/*
+ * Increases the refcount for a range of clusters in a given refcount table.
+ * This is used to construct a temporary refcount table out of L1 and L2 tables
+ * which can be compared the the refcount table saved in the image.
+ *
+ * Modifies the number of errors in res.
+ */
+static void inc_refcounts(BlockDriverState *bs,
+                          BdrvCheckResult *res,
+                          uint16_t *refcount_table,
+                          int refcount_table_size,
+                          int64_t offset, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+    int k;
+
+    if (size <= 0)
+        return;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size) {
+        k = cluster_offset >> s->cluster_bits;
+        if (k < 0) {
+            fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
+                cluster_offset);
+            res->corruptions++;
+        } else if (k >= refcount_table_size) {
+            fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
+                "the end of the image file, can't properly check refcounts.\n",
+                cluster_offset);
+            res->check_errors++;
+        } else {
+            if (++refcount_table[k] == 0) {
+                fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
+                    "\n", cluster_offset);
+                res->corruptions++;
+            }
+        }
+    }
+}
+
+/*
+ * Increases the refcount in the given refcount table for the all clusters
+ * referenced in the L2 table. While doing so, performs some checks on L2
+ * entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
+static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
+    uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
+    int check_copied)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l2_table, offset;
+    int i, l2_size, nb_csectors, refcount;
+
+    /* Read L2 table from disk */
+    l2_size = s->l2_size * sizeof(uint64_t);
+    l2_table = qemu_malloc(l2_size);
+
+    if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size)
+        goto fail;
+
+    /* Do the actual checks */
+    for(i = 0; i < s->l2_size; i++) {
+        offset = be64_to_cpu(l2_table[i]);
+        if (offset != 0) {
+            if (offset & QCOW_OFLAG_COMPRESSED) {
+                /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+                if (offset & QCOW_OFLAG_COPIED) {
+                    fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+                        "copied flag must never be set for compressed "
+                        "clusters\n", offset >> s->cluster_bits);
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    res->corruptions++;
+                }
+
+                /* Mark cluster as used */
+                nb_csectors = ((offset >> s->csize_shift) &
+                               s->csize_mask) + 1;
+                offset &= s->cluster_offset_mask;
+                inc_refcounts(bs, res, refcount_table, refcount_table_size,
+                    offset & ~511, nb_csectors * 512);
+            } else {
+                /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+                if (check_copied) {
+                    uint64_t entry = offset;
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    refcount = get_refcount(bs, offset >> s->cluster_bits);
+                    if (refcount < 0) {
+                        fprintf(stderr, "Can't get refcount for offset %"
+                            PRIx64 ": %s\n", entry, strerror(-refcount));
+                        goto fail;
+                    }
+                    if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
+                        fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+                            PRIx64 " refcount=%d\n", entry, refcount);
+                        res->corruptions++;
+                    }
+                }
+
+                /* Mark cluster as used */
+                offset &= ~QCOW_OFLAG_COPIED;
+                inc_refcounts(bs, res, refcount_table,refcount_table_size,
+                    offset, s->cluster_size);
+
+                /* Correct offsets are cluster aligned */
+                if (offset & (s->cluster_size - 1)) {
+                    fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+                        "properly aligned; L2 entry corrupted.\n", offset);
+                    res->corruptions++;
+                }
+            }
+        }
+    }
+
+    qemu_free(l2_table);
+    return 0;
+
+fail:
+    fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
+    qemu_free(l2_table);
+    return -EIO;
+}
+
+/*
+ * Increases the refcount for the L1 table, its L2 tables and all referenced
+ * clusters in the given refcount table. While doing so, performs some checks
+ * on L1 and L2 entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
+static int check_refcounts_l1(BlockDriverState *bs,
+                              BdrvCheckResult *res,
+                              uint16_t *refcount_table,
+                              int refcount_table_size,
+                              int64_t l1_table_offset, int l1_size,
+                              int check_copied)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, l2_offset, l1_size2;
+    int i, refcount, ret;
+
+    l1_size2 = l1_size * sizeof(uint64_t);
+
+    /* Mark L1 table as used */
+    inc_refcounts(bs, res, refcount_table, refcount_table_size,
+        l1_table_offset, l1_size2);
+
+    /* Read L1 table entries from disk */
+    if (l1_size2 == 0) {
+        l1_table = NULL;
+    } else {
+        l1_table = qemu_malloc(l1_size2);
+        if (bdrv_pread(bs->file, l1_table_offset,
+                       l1_table, l1_size2) != l1_size2)
+            goto fail;
+        for(i = 0;i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    }
+
+    /* Do the actual checks */
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+            if (check_copied) {
+                refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
+                    >> s->cluster_bits);
+                if (refcount < 0) {
+                    fprintf(stderr, "Can't get refcount for l2_offset %"
+                        PRIx64 ": %s\n", l2_offset, strerror(-refcount));
+                    goto fail;
+                }
+                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
+                    fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
+                        " refcount=%d\n", l2_offset, refcount);
+                    res->corruptions++;
+                }
+            }
+
+            /* Mark L2 table as used */
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+            inc_refcounts(bs, res, refcount_table, refcount_table_size,
+                l2_offset, s->cluster_size);
+
+            /* L2 tables are cluster aligned */
+            if (l2_offset & (s->cluster_size - 1)) {
+                fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
+                    "cluster aligned; L1 entry corrupted\n", l2_offset);
+                res->corruptions++;
+            }
+
+            /* Process and check L2 entries */
+            ret = check_refcounts_l2(bs, res, refcount_table,
+                refcount_table_size, l2_offset, check_copied);
+            if (ret < 0) {
+                goto fail;
+            }
+        }
+    }
+    qemu_free(l1_table);
+    return 0;
+
+fail:
+    fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
+    res->check_errors++;
+    qemu_free(l1_table);
+    return -EIO;
+}
+
+/*
+ * Checks an image for refcount consistency.
+ *
+ * Returns 0 if no errors are found, the number of errors in case the image is
+ * detected as corrupted, and -errno when an internal error occurred.
+ */
+int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t size;
+    int nb_clusters, refcount1, refcount2, i;
+    QCowSnapshot *sn;
+    uint16_t *refcount_table;
+    int ret;
+
+    size = bdrv_getlength(bs->file);
+    nb_clusters = size_to_clusters(s, size);
+    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
+
+    /* header */
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
+        0, s->cluster_size);
+
+    /* current L1 table */
+    ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
+                       s->l1_table_offset, s->l1_size, 1);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* snapshots */
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
+            sn->l1_table_offset, sn->l1_size, 0);
+        if (ret < 0) {
+            goto fail;
+        }
+    }
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
+        s->snapshots_offset, s->snapshots_size);
+
+    /* refcount data */
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
+        s->refcount_table_offset,
+        s->refcount_table_size * sizeof(uint64_t));
+
+    for(i = 0; i < s->refcount_table_size; i++) {
+        uint64_t offset, cluster;
+        offset = s->refcount_table[i];
+        cluster = offset >> s->cluster_bits;
+
+        /* Refcount blocks are cluster aligned */
+        if (offset & (s->cluster_size - 1)) {
+            fprintf(stderr, "ERROR refcount block %d is not "
+                "cluster aligned; refcount table entry corrupted\n", i);
+            res->corruptions++;
+            continue;
+        }
+
+        if (cluster >= nb_clusters) {
+            fprintf(stderr, "ERROR refcount block %d is outside image\n", i);
+            res->corruptions++;
+            continue;
+        }
+
+        if (offset != 0) {
+            inc_refcounts(bs, res, refcount_table, nb_clusters,
+                offset, s->cluster_size);
+            if (refcount_table[cluster] != 1) {
+                fprintf(stderr, "ERROR refcount block %d refcount=%d\n",
+                    i, refcount_table[cluster]);
+                res->corruptions++;
+            }
+        }
+    }
+
+    /* compare ref counts */
+    for(i = 0; i < nb_clusters; i++) {
+        refcount1 = get_refcount(bs, i);
+        if (refcount1 < 0) {
+            fprintf(stderr, "Can't get refcount for cluster %d: %s\n",
+                i, strerror(-refcount1));
+            res->check_errors++;
+            continue;
+        }
+
+        refcount2 = refcount_table[i];
+        if (refcount1 != refcount2) {
+            fprintf(stderr, "%s cluster %d refcount=%d reference=%d\n",
+                   refcount1 < refcount2 ? "ERROR" : "Leaked",
+                   i, refcount1, refcount2);
+            if (refcount1 < refcount2) {
+                res->corruptions++;
+            } else {
+                res->leaks++;
+            }
+        }
+    }
+
+    ret = 0;
+
+fail:
+    qemu_free(refcount_table);
+
+    return ret;
+}
+
diff --git a/qemu-0.15.x/block/qcow2-snapshot.c b/qemu-0.15.x/block/qcow2-snapshot.c
new file mode 100644
index 0000000..e32bcf0
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2-snapshot.c
@@ -0,0 +1,457 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-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 "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+typedef struct __attribute__((packed)) QCowSnapshotHeader {
+    /* header is 8 byte aligned */
+    uint64_t l1_table_offset;
+
+    uint32_t l1_size;
+    uint16_t id_str_size;
+    uint16_t name_size;
+
+    uint32_t date_sec;
+    uint32_t date_nsec;
+
+    uint64_t vm_clock_nsec;
+
+    uint32_t vm_state_size;
+    uint32_t extra_data_size; /* for extension */
+    /* extra data follows */
+    /* id_str follows */
+    /* name follows  */
+} QCowSnapshotHeader;
+
+void qcow2_free_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        qemu_free(s->snapshots[i].name);
+        qemu_free(s->snapshots[i].id_str);
+    }
+    qemu_free(s->snapshots);
+    s->snapshots = NULL;
+    s->nb_snapshots = 0;
+}
+
+int qcow2_read_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshotHeader h;
+    QCowSnapshot *sn;
+    int i, id_str_size, name_size;
+    int64_t offset;
+    uint32_t extra_data_size;
+
+    if (!s->nb_snapshots) {
+        s->snapshots = NULL;
+        s->snapshots_size = 0;
+        return 0;
+    }
+
+    offset = s->snapshots_offset;
+    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
+    for(i = 0; i < s->nb_snapshots; i++) {
+        offset = align_offset(offset, 8);
+        if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h))
+            goto fail;
+        offset += sizeof(h);
+        sn = s->snapshots + i;
+        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
+        sn->l1_size = be32_to_cpu(h.l1_size);
+        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
+        sn->date_sec = be32_to_cpu(h.date_sec);
+        sn->date_nsec = be32_to_cpu(h.date_nsec);
+        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
+        extra_data_size = be32_to_cpu(h.extra_data_size);
+
+        id_str_size = be16_to_cpu(h.id_str_size);
+        name_size = be16_to_cpu(h.name_size);
+
+        offset += extra_data_size;
+
+        sn->id_str = qemu_malloc(id_str_size + 1);
+        if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
+            goto fail;
+        offset += id_str_size;
+        sn->id_str[id_str_size] = '\0';
+
+        sn->name = qemu_malloc(name_size + 1);
+        if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size)
+            goto fail;
+        offset += name_size;
+        sn->name[name_size] = '\0';
+    }
+    s->snapshots_size = offset - s->snapshots_offset;
+    return 0;
+ fail:
+    qcow2_free_snapshots(bs);
+    return -1;
+}
+
+/* add at the end of the file a new list of snapshots */
+static int qcow2_write_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    QCowSnapshotHeader h;
+    int i, name_size, id_str_size, snapshots_size;
+    uint64_t data64;
+    uint32_t data32;
+    int64_t offset, snapshots_offset;
+
+    /* compute the size of the snapshots */
+    offset = 0;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        offset = align_offset(offset, 8);
+        offset += sizeof(h);
+        offset += strlen(sn->id_str);
+        offset += strlen(sn->name);
+    }
+    snapshots_size = offset;
+
+    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
+    bdrv_flush(bs->file);
+    offset = snapshots_offset;
+    if (offset < 0) {
+        return offset;
+    }
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        memset(&h, 0, sizeof(h));
+        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
+        h.l1_size = cpu_to_be32(sn->l1_size);
+        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
+        h.date_sec = cpu_to_be32(sn->date_sec);
+        h.date_nsec = cpu_to_be32(sn->date_nsec);
+        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
+
+        id_str_size = strlen(sn->id_str);
+        name_size = strlen(sn->name);
+        h.id_str_size = cpu_to_be16(id_str_size);
+        h.name_size = cpu_to_be16(name_size);
+        offset = align_offset(offset, 8);
+        if (bdrv_pwrite_sync(bs->file, offset, &h, sizeof(h)) < 0)
+            goto fail;
+        offset += sizeof(h);
+        if (bdrv_pwrite_sync(bs->file, offset, sn->id_str, id_str_size) < 0)
+            goto fail;
+        offset += id_str_size;
+        if (bdrv_pwrite_sync(bs->file, offset, sn->name, name_size) < 0)
+            goto fail;
+        offset += name_size;
+    }
+
+    /* update the various header fields */
+    data64 = cpu_to_be64(snapshots_offset);
+    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, snapshots_offset),
+                    &data64, sizeof(data64)) < 0)
+        goto fail;
+    data32 = cpu_to_be32(s->nb_snapshots);
+    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
+                    &data32, sizeof(data32)) < 0)
+        goto fail;
+
+    /* free the old snapshot table */
+    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
+    s->snapshots_offset = snapshots_offset;
+    s->snapshots_size = snapshots_size;
+    return 0;
+ fail:
+    return -1;
+}
+
+static void find_new_snapshot_id(BlockDriverState *bs,
+                                 char *id_str, int id_str_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, id, id_max = 0;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        id = strtoul(sn->id_str, NULL, 10);
+        if (id > id_max)
+            id_max = id;
+    }
+    snprintf(id_str, id_str_size, "%d", id_max + 1);
+}
+
+static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].id_str, id_str))
+            return i;
+    }
+    return -1;
+}
+
+static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, ret;
+
+    ret = find_snapshot_by_id(bs, name);
+    if (ret >= 0)
+        return ret;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].name, name))
+            return i;
+    }
+    return -1;
+}
+
+/* if no id is provided, a new one is constructed */
+int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
+    int i, ret;
+    uint64_t *l1_table = NULL;
+    int64_t l1_table_offset;
+
+    memset(sn, 0, sizeof(*sn));
+
+    if (sn_info->id_str[0] == '\0') {
+        /* compute a new id */
+        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
+    }
+
+    /* check that the ID is unique */
+    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
+        return -ENOENT;
+
+    sn->id_str = qemu_strdup(sn_info->id_str);
+    if (!sn->id_str)
+        goto fail;
+    sn->name = qemu_strdup(sn_info->name);
+    if (!sn->name)
+        goto fail;
+    sn->vm_state_size = sn_info->vm_state_size;
+    sn->date_sec = sn_info->date_sec;
+    sn->date_nsec = sn_info->date_nsec;
+    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+
+    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
+    if (ret < 0)
+        goto fail;
+
+    /* create the L1 table of the snapshot */
+    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+    if (l1_table_offset < 0) {
+        goto fail;
+    }
+    bdrv_flush(bs->file);
+
+    sn->l1_table_offset = l1_table_offset;
+    sn->l1_size = s->l1_size;
+
+    if (s->l1_size != 0) {
+        l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    } else {
+        l1_table = NULL;
+    }
+
+    for(i = 0; i < s->l1_size; i++) {
+        l1_table[i] = cpu_to_be64(s->l1_table[i]);
+    }
+    if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
+                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
+        goto fail;
+    qemu_free(l1_table);
+    l1_table = NULL;
+
+    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
+    if (s->snapshots) {
+        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+        qemu_free(s->snapshots);
+    }
+    s->snapshots = snapshots1;
+    s->snapshots[s->nb_snapshots++] = *sn;
+
+    if (qcow2_write_snapshots(bs) < 0)
+        goto fail;
+#ifdef DEBUG_ALLOC
+    qcow2_check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    qemu_free(sn->name);
+    qemu_free(l1_table);
+    return -1;
+}
+
+/* copy the snapshot 'snapshot_name' into the current disk image */
+int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, snapshot_index;
+    int cur_l1_bytes, sn_l1_bytes;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
+        goto fail;
+
+    if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
+        goto fail;
+
+    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
+    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
+
+    if (cur_l1_bytes > sn_l1_bytes) {
+        memset(s->l1_table + sn->l1_size, 0, cur_l1_bytes - sn_l1_bytes);
+    }
+
+    /* copy the snapshot l1 table to the current l1 table */
+    if (bdrv_pread(bs->file, sn->l1_table_offset,
+                   s->l1_table, sn_l1_bytes) < 0)
+        goto fail;
+    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
+                    s->l1_table, cur_l1_bytes) < 0)
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+
+    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
+        goto fail;
+
+#ifdef DEBUG_ALLOC
+    qcow2_check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    return -EIO;
+}
+
+int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int snapshot_index, ret;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
+    if (ret < 0)
+        return ret;
+    /* must update the copied flag on the current cluster offsets */
+    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
+    if (ret < 0)
+        return ret;
+    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
+
+    qemu_free(sn->id_str);
+    qemu_free(sn->name);
+    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
+    s->nb_snapshots--;
+    ret = qcow2_write_snapshots(bs);
+    if (ret < 0) {
+        /* XXX: restore snapshot if error ? */
+        return ret;
+    }
+#ifdef DEBUG_ALLOC
+    qcow2_check_refcounts(bs);
+#endif
+    return 0;
+}
+
+int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+{
+    BDRVQcowState *s = bs->opaque;
+    QEMUSnapshotInfo *sn_tab, *sn_info;
+    QCowSnapshot *sn;
+    int i;
+
+    if (!s->nb_snapshots) {
+        *psn_tab = NULL;
+        return s->nb_snapshots;
+    }
+
+    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn_info = sn_tab + i;
+        sn = s->snapshots + i;
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
+                sn->id_str);
+        pstrcpy(sn_info->name, sizeof(sn_info->name),
+                sn->name);
+        sn_info->vm_state_size = sn->vm_state_size;
+        sn_info->date_sec = sn->date_sec;
+        sn_info->date_nsec = sn->date_nsec;
+        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+    }
+    *psn_tab = sn_tab;
+    return s->nb_snapshots;
+}
+
+int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
+{
+    int i, snapshot_index, l1_size2;
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
+    if (snapshot_index < 0) {
+        return -ENOENT;
+    }
+
+    sn = &s->snapshots[snapshot_index];
+    s->l1_size = sn->l1_size;
+    l1_size2 = s->l1_size * sizeof(uint64_t);
+    if (s->l1_table != NULL) {
+        qemu_free(s->l1_table);
+    }
+
+    s->l1_table_offset = sn->l1_table_offset;
+    s->l1_table = qemu_mallocz(align_offset(l1_size2, 512));
+
+    if (bdrv_pread(bs->file, sn->l1_table_offset,
+                   s->l1_table, l1_size2) != l1_size2) {
+        return -1;
+    }
+
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/block/qcow2.c b/qemu-0.15.x/block/qcow2.c
new file mode 100644
index 0000000..48e1b95
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2.c
@@ -0,0 +1,1419 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+#include <zlib.h>
+#include "aes.h"
+#include "block/qcow2.h"
+#include "qemu-error.h"
+#include "qerror.h"
+
+/*
+  Differences with QCOW:
+
+  - Support for multiple incremental snapshots.
+  - Memory management by reference counts.
+  - Clusters which have a reference count of one have the bit
+    QCOW_OFLAG_COPIED to optimize write performance.
+  - Size of compressed clusters is stored in sectors to reduce bit usage
+    in the cluster offsets.
+  - Support for storing additional data (such as the VM state) in the
+    snapshots.
+  - If a backing store is used, the cluster size is not constrained
+    (could be backported to QCOW).
+  - L2 tables have always a size of one cluster.
+*/
+
+
+typedef struct {
+    uint32_t magic;
+    uint32_t len;
+} QCowExtension;
+#define  QCOW2_EXT_MAGIC_END 0
+#define  QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+
+static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const QCowHeader *cow_header = (const void *)buf;
+
+    if (buf_size >= sizeof(QCowHeader) &&
+        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
+        be32_to_cpu(cow_header->version) >= QCOW_VERSION)
+        return 100;
+    else
+        return 0;
+}
+
+
+/* 
+ * read qcow2 extension and fill bs
+ * start reading from start_offset
+ * finish reading upon magic of value 0 or when end_offset reached
+ * unknown magic is skipped (future extension this version knows nothing about)
+ * return 0 upon success, non-0 otherwise
+ */
+static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+                                 uint64_t end_offset)
+{
+    QCowExtension ext;
+    uint64_t offset;
+
+#ifdef DEBUG_EXT
+    printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
+#endif
+    offset = start_offset;
+    while (offset < end_offset) {
+
+#ifdef DEBUG_EXT
+        /* Sanity check */
+        if (offset > s->cluster_size)
+            printf("qcow2_read_extension: suspicious offset %lu\n", offset);
+
+        printf("attemting to read extended header in offset %lu\n", offset);
+#endif
+
+        if (bdrv_pread(bs->file, offset, &ext, sizeof(ext)) != sizeof(ext)) {
+            fprintf(stderr, "qcow2_read_extension: ERROR: "
+                    "pread fail from offset %" PRIu64 "\n",
+                    offset);
+            return 1;
+        }
+        be32_to_cpus(&ext.magic);
+        be32_to_cpus(&ext.len);
+        offset += sizeof(ext);
+#ifdef DEBUG_EXT
+        printf("ext.magic = 0x%x\n", ext.magic);
+#endif
+        switch (ext.magic) {
+        case QCOW2_EXT_MAGIC_END:
+            return 0;
+
+        case QCOW2_EXT_MAGIC_BACKING_FORMAT:
+            if (ext.len >= sizeof(bs->backing_format)) {
+                fprintf(stderr, "ERROR: ext_backing_format: len=%u too large"
+                        " (>=%zu)\n",
+                        ext.len, sizeof(bs->backing_format));
+                return 2;
+            }
+            if (bdrv_pread(bs->file, offset , bs->backing_format,
+                           ext.len) != ext.len)
+                return 3;
+            bs->backing_format[ext.len] = '\0';
+#ifdef DEBUG_EXT
+            printf("Qcow2: Got format extension %s\n", bs->backing_format);
+#endif
+            offset = ((offset + ext.len + 7) & ~7);
+            break;
+
+        default:
+            /* unknown magic -- just skip it */
+            offset = ((offset + ext.len + 7) & ~7);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+static int qcow2_open(BlockDriverState *bs, int flags)
+{
+    BDRVQcowState *s = bs->opaque;
+    int len, i, ret = 0;
+    QCowHeader header;
+    uint64_t ext_end;
+    bool writethrough;
+
+    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+    if (ret < 0) {
+        goto fail;
+    }
+    be32_to_cpus(&header.magic);
+    be32_to_cpus(&header.version);
+    be64_to_cpus(&header.backing_file_offset);
+    be32_to_cpus(&header.backing_file_size);
+    be64_to_cpus(&header.size);
+    be32_to_cpus(&header.cluster_bits);
+    be32_to_cpus(&header.crypt_method);
+    be64_to_cpus(&header.l1_table_offset);
+    be32_to_cpus(&header.l1_size);
+    be64_to_cpus(&header.refcount_table_offset);
+    be32_to_cpus(&header.refcount_table_clusters);
+    be64_to_cpus(&header.snapshots_offset);
+    be32_to_cpus(&header.nb_snapshots);
+
+    if (header.magic != QCOW_MAGIC) {
+        ret = -EINVAL;
+        goto fail;
+    }
+    if (header.version != QCOW_VERSION) {
+        char version[64];
+        snprintf(version, sizeof(version), "QCOW version %d", header.version);
+        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+            bs->device_name, "qcow2", version);
+        ret = -ENOTSUP;
+        goto fail;
+    }
+    if (header.cluster_bits < MIN_CLUSTER_BITS ||
+        header.cluster_bits > MAX_CLUSTER_BITS) {
+        ret = -EINVAL;
+        goto fail;
+    }
+    if (header.crypt_method > QCOW_CRYPT_AES) {
+        ret = -EINVAL;
+        goto fail;
+    }
+    s->crypt_method_header = header.crypt_method;
+    if (s->crypt_method_header) {
+        bs->encrypted = 1;
+    }
+    s->cluster_bits = header.cluster_bits;
+    s->cluster_size = 1 << s->cluster_bits;
+    s->cluster_sectors = 1 << (s->cluster_bits - 9);
+    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
+    s->l2_size = 1 << s->l2_bits;
+    bs->total_sectors = header.size / 512;
+    s->csize_shift = (62 - (s->cluster_bits - 8));
+    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
+    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
+    s->refcount_table_offset = header.refcount_table_offset;
+    s->refcount_table_size =
+        header.refcount_table_clusters << (s->cluster_bits - 3);
+
+    s->snapshots_offset = header.snapshots_offset;
+    s->nb_snapshots = header.nb_snapshots;
+
+    /* read the level 1 table */
+    s->l1_size = header.l1_size;
+    s->l1_vm_state_index = size_to_l1(s, header.size);
+    /* the L1 table must contain at least enough entries to put
+       header.size bytes */
+    if (s->l1_size < s->l1_vm_state_index) {
+        ret = -EINVAL;
+        goto fail;
+    }
+    s->l1_table_offset = header.l1_table_offset;
+    if (s->l1_size > 0) {
+        s->l1_table = qemu_mallocz(
+            align_offset(s->l1_size * sizeof(uint64_t), 512));
+        ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+                         s->l1_size * sizeof(uint64_t));
+        if (ret < 0) {
+            goto fail;
+        }
+        for(i = 0;i < s->l1_size; i++) {
+            be64_to_cpus(&s->l1_table[i]);
+        }
+    }
+
+    /* alloc L2 table/refcount block cache */
+    writethrough = ((flags & BDRV_O_CACHE_WB) == 0);
+    s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE, writethrough);
+    s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE,
+        writethrough);
+
+    s->cluster_cache = qemu_malloc(s->cluster_size);
+    /* one more sector for decompressed data alignment */
+    s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+                                  + 512);
+    s->cluster_cache_offset = -1;
+
+    ret = qcow2_refcount_init(bs);
+    if (ret != 0) {
+        goto fail;
+    }
+
+    QLIST_INIT(&s->cluster_allocs);
+
+    /* read qcow2 extensions */
+    if (header.backing_file_offset) {
+        ext_end = header.backing_file_offset;
+    } else {
+        ext_end = s->cluster_size;
+    }
+    if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* read the backing file name */
+    if (header.backing_file_offset != 0) {
+        len = header.backing_file_size;
+        if (len > 1023) {
+            len = 1023;
+        }
+        ret = bdrv_pread(bs->file, header.backing_file_offset,
+                         bs->backing_file, len);
+        if (ret < 0) {
+            goto fail;
+        }
+        bs->backing_file[len] = '\0';
+    }
+    if (qcow2_read_snapshots(bs) < 0) {
+        ret = -EINVAL;
+        goto fail;
+    }
+
+#ifdef DEBUG_ALLOC
+    qcow2_check_refcounts(bs);
+#endif
+    return ret;
+
+ fail:
+    qcow2_free_snapshots(bs);
+    qcow2_refcount_close(bs);
+    qemu_free(s->l1_table);
+    if (s->l2_table_cache) {
+        qcow2_cache_destroy(bs, s->l2_table_cache);
+    }
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    return ret;
+}
+
+static int qcow2_set_key(BlockDriverState *bs, const char *key)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint8_t keybuf[16];
+    int len, i;
+
+    memset(keybuf, 0, 16);
+    len = strlen(key);
+    if (len > 16)
+        len = 16;
+    /* XXX: we could compress the chars to 7 bits to increase
+       entropy */
+    for(i = 0;i < len;i++) {
+        keybuf[i] = key[i];
+    }
+    s->crypt_method = s->crypt_method_header;
+
+    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
+        return -1;
+    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
+        return -1;
+#if 0
+    /* test */
+    {
+        uint8_t in[16];
+        uint8_t out[16];
+        uint8_t tmp[16];
+        for(i=0;i<16;i++)
+            in[i] = i;
+        AES_encrypt(in, tmp, &s->aes_encrypt_key);
+        AES_decrypt(tmp, out, &s->aes_decrypt_key);
+        for(i = 0; i < 16; i++)
+            printf(" %02x", tmp[i]);
+        printf("\n");
+        for(i = 0; i < 16; i++)
+            printf(" %02x", out[i]);
+        printf("\n");
+    }
+#endif
+    return 0;
+}
+
+static int qcow2_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                              int nb_sectors, int *pnum)
+{
+    uint64_t cluster_offset;
+    int ret;
+
+    *pnum = nb_sectors;
+    /* FIXME We can get errors here, but the bdrv_is_allocated interface can't
+     * pass them on today */
+    ret = qcow2_get_cluster_offset(bs, sector_num << 9, pnum, &cluster_offset);
+    if (ret < 0) {
+        *pnum = 0;
+    }
+
+    return (cluster_offset != 0);
+}
+
+/* handle reading after the end of the backing file */
+int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
+                  int64_t sector_num, int nb_sectors)
+{
+    int n1;
+    if ((sector_num + nb_sectors) <= bs->total_sectors)
+        return nb_sectors;
+    if (sector_num >= bs->total_sectors)
+        n1 = 0;
+    else
+        n1 = bs->total_sectors - sector_num;
+
+    qemu_iovec_memset_skip(qiov, 0, 512 * (nb_sectors - n1), 512 * n1);
+
+    return n1;
+}
+
+typedef struct QCowAIOCB {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    QEMUIOVector *qiov;
+    int remaining_sectors;
+    int cur_nr_sectors;	/* number of sectors in current iteration */
+    uint64_t bytes_done;
+    uint64_t cluster_offset;
+    uint8_t *cluster_data;
+    bool is_write;
+    BlockDriverAIOCB *hd_aiocb;
+    QEMUIOVector hd_qiov;
+    QEMUBH *bh;
+    QCowL2Meta l2meta;
+    QLIST_ENTRY(QCowAIOCB) next_depend;
+} QCowAIOCB;
+
+static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
+static AIOPool qcow2_aio_pool = {
+    .aiocb_size         = sizeof(QCowAIOCB),
+    .cancel             = qcow2_aio_cancel,
+};
+
+static void qcow2_aio_read_cb(void *opaque, int ret);
+static void qcow2_aio_write_cb(void *opaque, int ret);
+
+static void qcow2_aio_rw_bh(void *opaque)
+{
+    QCowAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    if (acb->is_write) {
+        qcow2_aio_write_cb(opaque, 0);
+    } else {
+        qcow2_aio_read_cb(opaque, 0);
+    }
+}
+
+static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+{
+    if (acb->bh)
+        return -EIO;
+
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh)
+        return -EIO;
+
+    qemu_bh_schedule(acb->bh);
+
+    return 0;
+}
+
+static void qcow2_aio_read_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster, n1;
+
+    acb->hd_aiocb = NULL;
+    if (ret < 0)
+        goto done;
+
+    /* post process the read buffer */
+    if (!acb->cluster_offset) {
+        /* nothing to do */
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* nothing to do */
+    } else {
+        if (s->crypt_method) {
+            qcow2_encrypt_sectors(s, acb->sector_num,  acb->cluster_data,
+                acb->cluster_data, acb->cur_nr_sectors, 0, &s->aes_decrypt_key);
+            qemu_iovec_reset(&acb->hd_qiov);
+            qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
+                acb->cur_nr_sectors * 512);
+            qemu_iovec_from_buffer(&acb->hd_qiov, acb->cluster_data,
+                512 * acb->cur_nr_sectors);
+        }
+    }
+
+    acb->remaining_sectors -= acb->cur_nr_sectors;
+    acb->sector_num += acb->cur_nr_sectors;
+    acb->bytes_done += acb->cur_nr_sectors * 512;
+
+    if (acb->remaining_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    /* prepare next AIO request */
+    acb->cur_nr_sectors = acb->remaining_sectors;
+    if (s->crypt_method) {
+        acb->cur_nr_sectors = MIN(acb->cur_nr_sectors,
+            QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
+    }
+
+    ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
+        &acb->cur_nr_sectors, &acb->cluster_offset);
+    if (ret < 0) {
+        goto done;
+    }
+
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+
+    qemu_iovec_reset(&acb->hd_qiov);
+    qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
+        acb->cur_nr_sectors * 512);
+
+    if (!acb->cluster_offset) {
+
+        if (bs->backing_hd) {
+            /* read from the base image */
+            n1 = qcow2_backing_read1(bs->backing_hd, &acb->hd_qiov,
+                acb->sector_num, acb->cur_nr_sectors);
+            if (n1 > 0) {
+                BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+                acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                                    &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
+                if (acb->hd_aiocb == NULL) {
+                    ret = -EIO;
+                    goto done;
+                }
+            } else {
+                ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+                if (ret < 0)
+                    goto done;
+            }
+        } else {
+            /* Note: in this case, no need to wait */
+            qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
+            ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+            if (ret < 0)
+                goto done;
+        }
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* add AIO support for compressed blocks ? */
+        ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
+        if (ret < 0) {
+            goto done;
+        }
+
+        qemu_iovec_from_buffer(&acb->hd_qiov,
+            s->cluster_cache + index_in_cluster * 512,
+            512 * acb->cur_nr_sectors);
+
+        ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+        if (ret < 0)
+            goto done;
+    } else {
+        if ((acb->cluster_offset & 511) != 0) {
+            ret = -EIO;
+            goto done;
+        }
+
+        if (s->crypt_method) {
+            /*
+             * For encrypted images, read everything into a temporary
+             * contiguous buffer on which the AES functions can work.
+             */
+            if (!acb->cluster_data) {
+                acb->cluster_data =
+                    qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+            }
+
+            assert(acb->cur_nr_sectors <=
+                QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
+            qemu_iovec_reset(&acb->hd_qiov);
+            qemu_iovec_add(&acb->hd_qiov, acb->cluster_data,
+                512 * acb->cur_nr_sectors);
+        }
+
+        BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+        acb->hd_aiocb = bdrv_aio_readv(bs->file,
+                            (acb->cluster_offset >> 9) + index_in_cluster,
+                            &acb->hd_qiov, acb->cur_nr_sectors,
+                            qcow2_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
+            goto done;
+        }
+    }
+
+    return;
+done:
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_iovec_destroy(&acb->hd_qiov);
+    qemu_aio_release(acb);
+}
+
+static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *qiov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb,
+                                  void *opaque, int is_write)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->qiov = qiov;
+    acb->is_write = is_write;
+
+    qemu_iovec_init(&acb->hd_qiov, qiov->niov);
+
+    acb->bytes_done = 0;
+    acb->remaining_sectors = nb_sectors;
+    acb->cur_nr_sectors = 0;
+    acb->cluster_offset = 0;
+    acb->l2meta.nb_clusters = 0;
+    QLIST_INIT(&acb->l2meta.dependent_requests);
+    return acb;
+}
+
+static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
+                                         int64_t sector_num,
+                                         QEMUIOVector *qiov, int nb_sectors,
+                                         BlockDriverCompletionFunc *cb,
+                                         void *opaque)
+{
+    QCowAIOCB *acb;
+    int ret;
+
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    if (!acb)
+        return NULL;
+
+    ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+    if (ret < 0) {
+        qemu_iovec_destroy(&acb->hd_qiov);
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static void run_dependent_requests(QCowL2Meta *m)
+{
+    QCowAIOCB *req;
+    QCowAIOCB *next;
+
+    /* Take the request off the list of running requests */
+    if (m->nb_clusters != 0) {
+        QLIST_REMOVE(m, next_in_flight);
+    }
+
+    /* Restart all dependent requests */
+    QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
+        qcow2_aio_write_cb(req, 0);
+    }
+
+    /* Empty the list for the next part of the request */
+    QLIST_INIT(&m->dependent_requests);
+}
+
+static void qcow2_aio_write_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+    int n_end;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret >= 0) {
+        ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
+    }
+
+    run_dependent_requests(&acb->l2meta);
+
+    if (ret < 0)
+        goto done;
+
+    acb->remaining_sectors -= acb->cur_nr_sectors;
+    acb->sector_num += acb->cur_nr_sectors;
+    acb->bytes_done += acb->cur_nr_sectors * 512;
+
+    if (acb->remaining_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    n_end = index_in_cluster + acb->remaining_sectors;
+    if (s->crypt_method &&
+        n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
+        n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
+
+    ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
+        index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta);
+    if (ret < 0) {
+        goto done;
+    }
+
+    acb->cluster_offset = acb->l2meta.cluster_offset;
+
+    /* Need to wait for another request? If so, we are done for now. */
+    if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
+        QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
+            acb, next_depend);
+        return;
+    }
+
+    assert((acb->cluster_offset & 511) == 0);
+
+    qemu_iovec_reset(&acb->hd_qiov);
+    qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done,
+        acb->cur_nr_sectors * 512);
+
+    if (s->crypt_method) {
+        if (!acb->cluster_data) {
+            acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
+                                             s->cluster_size);
+        }
+
+        assert(acb->hd_qiov.size <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+        qemu_iovec_to_buffer(&acb->hd_qiov, acb->cluster_data);
+
+        qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data,
+            acb->cluster_data, acb->cur_nr_sectors, 1, &s->aes_encrypt_key);
+
+        qemu_iovec_reset(&acb->hd_qiov);
+        qemu_iovec_add(&acb->hd_qiov, acb->cluster_data,
+            acb->cur_nr_sectors * 512);
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+    acb->hd_aiocb = bdrv_aio_writev(bs->file,
+                                    (acb->cluster_offset >> 9) + index_in_cluster,
+                                    &acb->hd_qiov, acb->cur_nr_sectors,
+                                    qcow2_aio_write_cb, acb);
+    if (acb->hd_aiocb == NULL) {
+        ret = -EIO;
+        goto fail;
+    }
+
+    return;
+
+fail:
+    if (acb->l2meta.nb_clusters != 0) {
+        QLIST_REMOVE(&acb->l2meta, next_in_flight);
+    }
+done:
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_iovec_destroy(&acb->hd_qiov);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
+                                          int64_t sector_num,
+                                          QEMUIOVector *qiov, int nb_sectors,
+                                          BlockDriverCompletionFunc *cb,
+                                          void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowAIOCB *acb;
+    int ret;
+
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+    if (!acb)
+        return NULL;
+
+    ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+    if (ret < 0) {
+        qemu_iovec_destroy(&acb->hd_qiov);
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static void qcow2_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->l1_table);
+
+    qcow2_cache_flush(bs, s->l2_table_cache);
+    qcow2_cache_flush(bs, s->refcount_block_cache);
+
+    qcow2_cache_destroy(bs, s->l2_table_cache);
+    qcow2_cache_destroy(bs, s->refcount_block_cache);
+
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    qcow2_refcount_close(bs);
+}
+
+/*
+ * Updates the variable length parts of the qcow2 header, i.e. the backing file
+ * name and all extensions. qcow2 was not designed to allow such changes, so if
+ * we run out of space (we can only use the first cluster) this function may
+ * fail.
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+static int qcow2_update_ext_header(BlockDriverState *bs,
+    const char *backing_file, const char *backing_fmt)
+{
+    size_t backing_file_len = 0;
+    size_t backing_fmt_len = 0;
+    BDRVQcowState *s = bs->opaque;
+    QCowExtension ext_backing_fmt = {0, 0};
+    int ret;
+
+    /* Backing file format doesn't make sense without a backing file */
+    if (backing_fmt && !backing_file) {
+        return -EINVAL;
+    }
+
+    /* Prepare the backing file format extension if needed */
+    if (backing_fmt) {
+        ext_backing_fmt.len = cpu_to_be32(strlen(backing_fmt));
+        ext_backing_fmt.magic = cpu_to_be32(QCOW2_EXT_MAGIC_BACKING_FORMAT);
+        backing_fmt_len = ((sizeof(ext_backing_fmt)
+            + strlen(backing_fmt) + 7) & ~7);
+    }
+
+    /* Check if we can fit the new header into the first cluster */
+    if (backing_file) {
+        backing_file_len = strlen(backing_file);
+    }
+
+    size_t header_size = sizeof(QCowHeader) + backing_file_len
+        + backing_fmt_len;
+
+    if (header_size > s->cluster_size) {
+        return -ENOSPC;
+    }
+
+    /* Rewrite backing file name and qcow2 extensions */
+    size_t ext_size = header_size - sizeof(QCowHeader);
+    uint8_t buf[ext_size];
+    size_t offset = 0;
+    size_t backing_file_offset = 0;
+
+    if (backing_file) {
+        if (backing_fmt) {
+            int padding = backing_fmt_len -
+                (sizeof(ext_backing_fmt) + strlen(backing_fmt));
+
+            memcpy(buf + offset, &ext_backing_fmt, sizeof(ext_backing_fmt));
+            offset += sizeof(ext_backing_fmt);
+
+            memcpy(buf + offset, backing_fmt, strlen(backing_fmt));
+            offset += strlen(backing_fmt);
+
+            memset(buf + offset, 0, padding);
+            offset += padding;
+        }
+
+        memcpy(buf + offset, backing_file, backing_file_len);
+        backing_file_offset = sizeof(QCowHeader) + offset;
+    }
+
+    ret = bdrv_pwrite_sync(bs->file, sizeof(QCowHeader), buf, ext_size);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* Update header fields */
+    uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset);
+    uint32_t be_backing_file_size = cpu_to_be32(backing_file_len);
+
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_offset),
+        &be_backing_file_offset, sizeof(uint64_t));
+    if (ret < 0) {
+        goto fail;
+    }
+
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_size),
+        &be_backing_file_size, sizeof(uint32_t));
+    if (ret < 0) {
+        goto fail;
+    }
+
+    ret = 0;
+fail:
+    return ret;
+}
+
+static int qcow2_change_backing_file(BlockDriverState *bs,
+    const char *backing_file, const char *backing_fmt)
+{
+    return qcow2_update_ext_header(bs, backing_file, backing_fmt);
+}
+
+static int preallocate(BlockDriverState *bs)
+{
+    uint64_t nb_sectors;
+    uint64_t offset;
+    int num;
+    int ret;
+    QCowL2Meta meta;
+
+    nb_sectors = bdrv_getlength(bs) >> 9;
+    offset = 0;
+    QLIST_INIT(&meta.dependent_requests);
+    meta.cluster_offset = 0;
+
+    while (nb_sectors) {
+        num = MIN(nb_sectors, INT_MAX >> 9);
+        ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = qcow2_alloc_cluster_link_l2(bs, &meta);
+        if (ret < 0) {
+            qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
+            return ret;
+        }
+
+        /* There are no dependent requests, but we need to remove our request
+         * from the list of in-flight requests */
+        run_dependent_requests(&meta);
+
+        /* TODO Preallocate data if requested */
+
+        nb_sectors -= num;
+        offset += num << 9;
+    }
+
+    /*
+     * It is expected that the image file is large enough to actually contain
+     * all of the allocated clusters (otherwise we get failing reads after
+     * EOF). Extend the image to the last allocated sector.
+     */
+    if (meta.cluster_offset != 0) {
+        uint8_t buf[512];
+        memset(buf, 0, 512);
+        ret = bdrv_write(bs->file, (meta.cluster_offset >> 9) + num - 1, buf, 1);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+static int qcow2_create2(const char *filename, int64_t total_size,
+                         const char *backing_file, const char *backing_format,
+                         int flags, size_t cluster_size, int prealloc,
+                         QEMUOptionParameter *options)
+{
+    /* Calulate cluster_bits */
+    int cluster_bits;
+    cluster_bits = ffs(cluster_size) - 1;
+    if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
+        (1 << cluster_bits) != cluster_size)
+    {
+        error_report(
+            "Cluster size must be a power of two between %d and %dk",
+            1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
+        return -EINVAL;
+    }
+
+    /*
+     * Open the image file and write a minimal qcow2 header.
+     *
+     * We keep things simple and start with a zero-sized image. We also
+     * do without refcount blocks or a L1 table for now. We'll fix the
+     * inconsistency later.
+     *
+     * We do need a refcount table because growing the refcount table means
+     * allocating two new refcount blocks - the seconds of which would be at
+     * 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
+     * size for any qcow2 image.
+     */
+    BlockDriverState* bs;
+    QCowHeader header;
+    uint8_t* refcount_table;
+    int ret;
+
+    ret = bdrv_create_file(filename, options);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Write the header */
+    memset(&header, 0, sizeof(header));
+    header.magic = cpu_to_be32(QCOW_MAGIC);
+    header.version = cpu_to_be32(QCOW_VERSION);
+    header.cluster_bits = cpu_to_be32(cluster_bits);
+    header.size = cpu_to_be64(0);
+    header.l1_table_offset = cpu_to_be64(0);
+    header.l1_size = cpu_to_be32(0);
+    header.refcount_table_offset = cpu_to_be64(cluster_size);
+    header.refcount_table_clusters = cpu_to_be32(1);
+
+    if (flags & BLOCK_FLAG_ENCRYPT) {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+    } else {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+    }
+
+    ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
+    if (ret < 0) {
+        goto out;
+    }
+
+    /* Write an empty refcount table */
+    refcount_table = qemu_mallocz(cluster_size);
+    ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
+    qemu_free(refcount_table);
+
+    if (ret < 0) {
+        goto out;
+    }
+
+    bdrv_close(bs);
+
+    /*
+     * And now open the image and make it consistent first (i.e. increase the
+     * refcount of the cluster that is occupied by the header and the refcount
+     * table)
+     */
+    BlockDriver* drv = bdrv_find_format("qcow2");
+    assert(drv != NULL);
+    ret = bdrv_open(bs, filename,
+        BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv);
+    if (ret < 0) {
+        goto out;
+    }
+
+    ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
+    if (ret < 0) {
+        goto out;
+
+    } else if (ret != 0) {
+        error_report("Huh, first cluster in empty image is already in use?");
+        abort();
+    }
+
+    /* Okay, now that we have a valid image, let's give it the right size */
+    ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE);
+    if (ret < 0) {
+        goto out;
+    }
+
+    /* Want a backing file? There you go.*/
+    if (backing_file) {
+        ret = bdrv_change_backing_file(bs, backing_file, backing_format);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+
+    /* And if we're supposed to preallocate metadata, do that now */
+    if (prealloc) {
+        ret = preallocate(bs);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+
+    ret = 0;
+out:
+    bdrv_delete(bs);
+    return ret;
+}
+
+static int qcow2_create(const char *filename, QEMUOptionParameter *options)
+{
+    const char *backing_file = NULL;
+    const char *backing_fmt = NULL;
+    uint64_t sectors = 0;
+    int flags = 0;
+    size_t cluster_size = DEFAULT_CLUSTER_SIZE;
+    int prealloc = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
+            backing_fmt = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                cluster_size = options->value.n;
+            }
+        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
+            if (!options->value.s || !strcmp(options->value.s, "off")) {
+                prealloc = 0;
+            } else if (!strcmp(options->value.s, "metadata")) {
+                prealloc = 1;
+            } else {
+                fprintf(stderr, "Invalid preallocation mode: '%s'\n",
+                    options->value.s);
+                return -EINVAL;
+            }
+        }
+        options++;
+    }
+
+    if (backing_file && prealloc) {
+        fprintf(stderr, "Backing file and preallocation cannot be used at "
+            "the same time\n");
+        return -EINVAL;
+    }
+
+    return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
+                         cluster_size, prealloc, options);
+}
+
+static int qcow2_make_empty(BlockDriverState *bs)
+{
+#if 0
+    /* XXX: not correct */
+    BDRVQcowState *s = bs->opaque;
+    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+    int ret;
+
+    memset(s->l1_table, 0, l1_length);
+    if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0)
+        return -1;
+    ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
+    if (ret < 0)
+        return ret;
+
+    l2_cache_reset(bs);
+#endif
+    return 0;
+}
+
+static int qcow2_discard(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors)
+{
+    return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+        nb_sectors);
+}
+
+static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, new_l1_size;
+
+    if (offset & 511) {
+        return -EINVAL;
+    }
+
+    /* cannot proceed if image has snapshots */
+    if (s->nb_snapshots) {
+        return -ENOTSUP;
+    }
+
+    /* shrinking is currently not supported */
+    if (offset < bs->total_sectors * 512) {
+        return -ENOTSUP;
+    }
+
+    new_l1_size = size_to_l1(s, offset);
+    ret = qcow2_grow_l1_table(bs, new_l1_size, true);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* write updated header.size */
+    offset = cpu_to_be64(offset);
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
+                           &offset, sizeof(uint64_t));
+    if (ret < 0) {
+        return ret;
+    }
+
+    s->l1_vm_state_index = new_l1_size;
+    return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+   tables to avoid losing bytes in alignment */
+static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                                  const uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    z_stream strm;
+    int ret, out_len;
+    uint8_t *out_buf;
+    uint64_t cluster_offset;
+
+    if (nb_sectors == 0) {
+        /* align end of file to a sector boundary to ease reading with
+           sector based I/Os */
+        cluster_offset = bdrv_getlength(bs->file);
+        cluster_offset = (cluster_offset + 511) & ~511;
+        bdrv_truncate(bs->file, cluster_offset);
+        return 0;
+    }
+
+    if (nb_sectors != s->cluster_sectors)
+        return -EINVAL;
+
+    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+
+    /* best compression, small window, no zlib header */
+    memset(&strm, 0, sizeof(strm));
+    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
+                       Z_DEFLATED, -12,
+                       9, Z_DEFAULT_STRATEGY);
+    if (ret != 0) {
+        qemu_free(out_buf);
+        return -1;
+    }
+
+    strm.avail_in = s->cluster_size;
+    strm.next_in = (uint8_t *)buf;
+    strm.avail_out = s->cluster_size;
+    strm.next_out = out_buf;
+
+    ret = deflate(&strm, Z_FINISH);
+    if (ret != Z_STREAM_END && ret != Z_OK) {
+        qemu_free(out_buf);
+        deflateEnd(&strm);
+        return -1;
+    }
+    out_len = strm.next_out - out_buf;
+
+    deflateEnd(&strm);
+
+    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+        /* could not compress: write normal cluster */
+        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+    } else {
+        cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
+            sector_num << 9, out_len);
+        if (!cluster_offset)
+            return -1;
+        cluster_offset &= s->cluster_offset_mask;
+        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
+        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
+            qemu_free(out_buf);
+            return -1;
+        }
+    }
+
+    qemu_free(out_buf);
+    return 0;
+}
+
+static int qcow2_flush(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = qcow2_cache_flush(bs, s->l2_table_cache);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return bdrv_flush(bs->file);
+}
+
+static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
+                                         BlockDriverCompletionFunc *cb,
+                                         void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = qcow2_cache_flush(bs, s->l2_table_cache);
+    if (ret < 0) {
+        return NULL;
+    }
+
+    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (ret < 0) {
+        return NULL;
+    }
+
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
+{
+	return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
+}
+
+static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdi->cluster_size = s->cluster_size;
+    bdi->vm_state_offset = qcow2_vm_state_offset(s);
+    return 0;
+}
+
+
+static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result)
+{
+    return qcow2_check_refcounts(bs, result);
+}
+
+#if 0
+static void dump_refcounts(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t nb_clusters, k, k1, size;
+    int refcount;
+
+    size = bdrv_getlength(bs->file);
+    nb_clusters = size_to_clusters(s, size);
+    for(k = 0; k < nb_clusters;) {
+        k1 = k;
+        refcount = get_refcount(bs, k);
+        k++;
+        while (k < nb_clusters && get_refcount(bs, k) == refcount)
+            k++;
+        printf("%" PRId64 ": refcount=%d nb=%" PRId64 "\n", k, refcount,
+               k - k1);
+    }
+}
+#endif
+
+static int qcow2_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
+                              int64_t pos, int size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int growable = bs->growable;
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
+    bs->growable = 1;
+    ret = bdrv_pwrite(bs, qcow2_vm_state_offset(s) + pos, buf, size);
+    bs->growable = growable;
+
+    return ret;
+}
+
+static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
+                              int64_t pos, int size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int growable = bs->growable;
+    int ret;
+
+    BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
+    bs->growable = 1;
+    ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size);
+    bs->growable = growable;
+
+    return ret;
+}
+
+static QEMUOptionParameter qcow2_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FMT,
+        .type = OPT_STRING,
+        .help = "Image format of the base image"
+    },
+    {
+        .name = BLOCK_OPT_ENCRYPT,
+        .type = OPT_FLAG,
+        .help = "Encrypt the image"
+    },
+    {
+        .name = BLOCK_OPT_CLUSTER_SIZE,
+        .type = OPT_SIZE,
+        .help = "qcow2 cluster size",
+        .value = { .n = DEFAULT_CLUSTER_SIZE },
+    },
+    {
+        .name = BLOCK_OPT_PREALLOC,
+        .type = OPT_STRING,
+        .help = "Preallocation mode (allowed values: off, metadata)"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_qcow2 = {
+    .format_name        = "qcow2",
+    .instance_size      = sizeof(BDRVQcowState),
+    .bdrv_probe         = qcow2_probe,
+    .bdrv_open          = qcow2_open,
+    .bdrv_close         = qcow2_close,
+    .bdrv_create        = qcow2_create,
+    .bdrv_flush         = qcow2_flush,
+    .bdrv_is_allocated  = qcow2_is_allocated,
+    .bdrv_set_key       = qcow2_set_key,
+    .bdrv_make_empty    = qcow2_make_empty,
+
+    .bdrv_aio_readv     = qcow2_aio_readv,
+    .bdrv_aio_writev    = qcow2_aio_writev,
+    .bdrv_aio_flush     = qcow2_aio_flush,
+
+    .bdrv_discard           = qcow2_discard,
+    .bdrv_truncate          = qcow2_truncate,
+    .bdrv_write_compressed  = qcow2_write_compressed,
+
+    .bdrv_snapshot_create   = qcow2_snapshot_create,
+    .bdrv_snapshot_goto     = qcow2_snapshot_goto,
+    .bdrv_snapshot_delete   = qcow2_snapshot_delete,
+    .bdrv_snapshot_list     = qcow2_snapshot_list,
+    .bdrv_snapshot_load_tmp     = qcow2_snapshot_load_tmp,
+    .bdrv_get_info      = qcow2_get_info,
+
+    .bdrv_save_vmstate    = qcow2_save_vmstate,
+    .bdrv_load_vmstate    = qcow2_load_vmstate,
+
+    .bdrv_change_backing_file   = qcow2_change_backing_file,
+
+    .create_options = qcow2_create_options,
+    .bdrv_check = qcow2_check,
+};
+
+static void bdrv_qcow2_init(void)
+{
+    bdrv_register(&bdrv_qcow2);
+}
+
+block_init(bdrv_qcow2_init);
diff --git a/qemu-0.15.x/block/qcow2.h b/qemu-0.15.x/block/qcow2.h
new file mode 100644
index 0000000..6a0a21b
--- /dev/null
+++ b/qemu-0.15.x/block/qcow2.h
@@ -0,0 +1,246 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-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.
+ */
+
+#ifndef BLOCK_QCOW2_H
+#define BLOCK_QCOW2_H
+
+#include "aes.h"
+
+//#define DEBUG_ALLOC
+//#define DEBUG_ALLOC2
+//#define DEBUG_EXT
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 2
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES  1
+
+#define QCOW_MAX_CRYPT_CLUSTERS 32
+
+/* indicate that the refcount of the referenced cluster is exactly one. */
+#define QCOW_OFLAG_COPIED     (1LL << 63)
+/* indicate that the cluster is compressed (they never have the copied flag) */
+#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+
+#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
+
+#define MIN_CLUSTER_BITS 9
+#define MAX_CLUSTER_BITS 21
+
+#define L2_CACHE_SIZE 16
+
+/* Must be at least 4 to cover all cases of refcount table growth */
+#define REFCOUNT_CACHE_SIZE 4
+
+#define DEFAULT_CLUSTER_SIZE 65536
+
+typedef struct QCowHeader {
+    uint32_t magic;
+    uint32_t version;
+    uint64_t backing_file_offset;
+    uint32_t backing_file_size;
+    uint32_t cluster_bits;
+    uint64_t size; /* in bytes */
+    uint32_t crypt_method;
+    uint32_t l1_size; /* XXX: save number of clusters instead ? */
+    uint64_t l1_table_offset;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_clusters;
+    uint32_t nb_snapshots;
+    uint64_t snapshots_offset;
+} QCowHeader;
+
+typedef struct QCowSnapshot {
+    uint64_t l1_table_offset;
+    uint32_t l1_size;
+    char *id_str;
+    char *name;
+    uint32_t vm_state_size;
+    uint32_t date_sec;
+    uint32_t date_nsec;
+    uint64_t vm_clock_nsec;
+} QCowSnapshot;
+
+struct Qcow2Cache;
+typedef struct Qcow2Cache Qcow2Cache;
+
+typedef struct BDRVQcowState {
+    int cluster_bits;
+    int cluster_size;
+    int cluster_sectors;
+    int l2_bits;
+    int l2_size;
+    int l1_size;
+    int l1_vm_state_index;
+    int csize_shift;
+    int csize_mask;
+    uint64_t cluster_offset_mask;
+    uint64_t l1_table_offset;
+    uint64_t *l1_table;
+
+    Qcow2Cache* l2_table_cache;
+    Qcow2Cache* refcount_block_cache;
+
+    uint8_t *cluster_cache;
+    uint8_t *cluster_data;
+    uint64_t cluster_cache_offset;
+    QLIST_HEAD(QCowClusterAlloc, QCowL2Meta) cluster_allocs;
+
+    uint64_t *refcount_table;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_size;
+    int64_t free_cluster_index;
+    int64_t free_byte_offset;
+
+    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
+    uint32_t crypt_method_header;
+    AES_KEY aes_encrypt_key;
+    AES_KEY aes_decrypt_key;
+    uint64_t snapshots_offset;
+    int snapshots_size;
+    int nb_snapshots;
+    QCowSnapshot *snapshots;
+} BDRVQcowState;
+
+/* XXX: use std qcow open function ? */
+typedef struct QCowCreateState {
+    int cluster_size;
+    int cluster_bits;
+    uint16_t *refcount_block;
+    uint64_t *refcount_table;
+    int64_t l1_table_offset;
+    int64_t refcount_table_offset;
+    int64_t refcount_block_offset;
+} QCowCreateState;
+
+struct QCowAIOCB;
+
+/* XXX This could be private for qcow2-cluster.c */
+typedef struct QCowL2Meta
+{
+    uint64_t offset;
+    uint64_t cluster_offset;
+    int n_start;
+    int nb_available;
+    int nb_clusters;
+    struct QCowL2Meta *depends_on;
+    QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
+
+    QLIST_ENTRY(QCowL2Meta) next_in_flight;
+} QCowL2Meta;
+
+static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
+{
+    return (size + (s->cluster_size - 1)) >> s->cluster_bits;
+}
+
+static inline int size_to_l1(BDRVQcowState *s, int64_t size)
+{
+    int shift = s->cluster_bits + s->l2_bits;
+    return (size + (1ULL << shift) - 1) >> shift;
+}
+
+static inline int64_t align_offset(int64_t offset, int n)
+{
+    offset = (offset + n - 1) & ~(n - 1);
+    return offset;
+}
+
+
+// FIXME Need qcow2_ prefix to global functions
+
+/* qcow2.c functions */
+int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
+                  int64_t sector_num, int nb_sectors);
+
+/* qcow2-refcount.c functions */
+int qcow2_refcount_init(BlockDriverState *bs);
+void qcow2_refcount_close(BlockDriverState *bs);
+
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
+int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
+void qcow2_free_clusters(BlockDriverState *bs,
+    int64_t offset, int64_t size);
+void qcow2_free_any_clusters(BlockDriverState *bs,
+    uint64_t cluster_offset, int nb_clusters);
+
+void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
+    int64_t size);
+int qcow2_update_snapshot_refcount(BlockDriverState *bs,
+    int64_t l1_table_offset, int l1_size, int addend);
+
+int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
+
+/* qcow2-cluster.c functions */
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
+void qcow2_l2_cache_reset(BlockDriverState *bs);
+int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
+void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                     uint8_t *out_buf, const uint8_t *in_buf,
+                     int nb_sectors, int enc,
+                     const AES_KEY *key);
+
+int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int *num, uint64_t *cluster_offset);
+int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int n_start, int n_end, int *num, QCowL2Meta *m);
+uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
+                                         uint64_t offset,
+                                         int compressed_size);
+
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
+int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
+    int nb_sectors);
+
+/* qcow2-snapshot.c functions */
+int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
+int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
+int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
+int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
+int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
+
+void qcow2_free_snapshots(BlockDriverState *bs);
+int qcow2_read_snapshots(BlockDriverState *bs);
+
+/* qcow2-cache.c functions */
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+    bool writethrough);
+int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
+    bool enable);
+
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
+int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
+int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
+    Qcow2Cache *dependency);
+void qcow2_cache_depends_on_flush(Qcow2Cache *c);
+
+int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+    void **table);
+int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+    void **table);
+int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+
+#endif
diff --git a/qemu-0.15.x/block/qed-check.c b/qemu-0.15.x/block/qed-check.c
new file mode 100644
index 0000000..22cd07f
--- /dev/null
+++ b/qemu-0.15.x/block/qed-check.c
@@ -0,0 +1,211 @@
+/*
+ * QEMU Enhanced Disk Format Consistency Check
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qed.h"
+
+typedef struct {
+    BDRVQEDState *s;
+    BdrvCheckResult *result;
+    bool fix;                           /* whether to fix invalid offsets */
+
+    uint64_t nclusters;
+    uint32_t *used_clusters;            /* referenced cluster bitmap */
+
+    QEDRequest request;
+} QEDCheck;
+
+static bool qed_test_bit(uint32_t *bitmap, uint64_t n) {
+    return !!(bitmap[n / 32] & (1 << (n % 32)));
+}
+
+static void qed_set_bit(uint32_t *bitmap, uint64_t n) {
+    bitmap[n / 32] |= 1 << (n % 32);
+}
+
+/**
+ * Set bitmap bits for clusters
+ *
+ * @check:          Check structure
+ * @offset:         Starting offset in bytes
+ * @n:              Number of clusters
+ */
+static bool qed_set_used_clusters(QEDCheck *check, uint64_t offset,
+                                  unsigned int n)
+{
+    uint64_t cluster = qed_bytes_to_clusters(check->s, offset);
+    unsigned int corruptions = 0;
+
+    while (n-- != 0) {
+        /* Clusters should only be referenced once */
+        if (qed_test_bit(check->used_clusters, cluster)) {
+            corruptions++;
+        }
+
+        qed_set_bit(check->used_clusters, cluster);
+        cluster++;
+    }
+
+    check->result->corruptions += corruptions;
+    return corruptions == 0;
+}
+
+/**
+ * Check an L2 table
+ *
+ * @ret:            Number of invalid cluster offsets
+ */
+static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
+{
+    BDRVQEDState *s = check->s;
+    unsigned int i, num_invalid = 0;
+
+    for (i = 0; i < s->table_nelems; i++) {
+        uint64_t offset = table->offsets[i];
+
+        if (qed_offset_is_unalloc_cluster(offset) ||
+            qed_offset_is_zero_cluster(offset)) {
+            continue;
+        }
+
+        /* Detect invalid cluster offset */
+        if (!qed_check_cluster_offset(s, offset)) {
+            if (check->fix) {
+                table->offsets[i] = 0;
+            } else {
+                check->result->corruptions++;
+            }
+
+            num_invalid++;
+            continue;
+        }
+
+        qed_set_used_clusters(check, offset, 1);
+    }
+
+    return num_invalid;
+}
+
+/**
+ * Descend tables and check each cluster is referenced once only
+ */
+static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
+{
+    BDRVQEDState *s = check->s;
+    unsigned int i, num_invalid_l1 = 0;
+    int ret, last_error = 0;
+
+    /* Mark L1 table clusters used */
+    qed_set_used_clusters(check, s->header.l1_table_offset,
+                          s->header.table_size);
+
+    for (i = 0; i < s->table_nelems; i++) {
+        unsigned int num_invalid_l2;
+        uint64_t offset = table->offsets[i];
+
+        if (qed_offset_is_unalloc_cluster(offset)) {
+            continue;
+        }
+
+        /* Detect invalid L2 offset */
+        if (!qed_check_table_offset(s, offset)) {
+            /* Clear invalid offset */
+            if (check->fix) {
+                table->offsets[i] = 0;
+            } else {
+                check->result->corruptions++;
+            }
+
+            num_invalid_l1++;
+            continue;
+        }
+
+        if (!qed_set_used_clusters(check, offset, s->header.table_size)) {
+            continue; /* skip an invalid table */
+        }
+
+        ret = qed_read_l2_table_sync(s, &check->request, offset);
+        if (ret) {
+            check->result->check_errors++;
+            last_error = ret;
+            continue;
+        }
+
+        num_invalid_l2 = qed_check_l2_table(check,
+                                            check->request.l2_table->table);
+
+        /* Write out fixed L2 table */
+        if (num_invalid_l2 > 0 && check->fix) {
+            ret = qed_write_l2_table_sync(s, &check->request, 0,
+                                          s->table_nelems, false);
+            if (ret) {
+                check->result->check_errors++;
+                last_error = ret;
+                continue;
+            }
+        }
+    }
+
+    /* Drop reference to final table */
+    qed_unref_l2_cache_entry(check->request.l2_table);
+    check->request.l2_table = NULL;
+
+    /* Write out fixed L1 table */
+    if (num_invalid_l1 > 0 && check->fix) {
+        ret = qed_write_l1_table_sync(s, 0, s->table_nelems);
+        if (ret) {
+            check->result->check_errors++;
+            last_error = ret;
+        }
+    }
+
+    return last_error;
+}
+
+/**
+ * Check for unreferenced (leaked) clusters
+ */
+static void qed_check_for_leaks(QEDCheck *check)
+{
+    BDRVQEDState *s = check->s;
+    uint64_t i;
+
+    for (i = s->header.header_size; i < check->nclusters; i++) {
+        if (!qed_test_bit(check->used_clusters, i)) {
+            check->result->leaks++;
+        }
+    }
+}
+
+int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
+{
+    QEDCheck check = {
+        .s = s,
+        .result = result,
+        .nclusters = qed_bytes_to_clusters(s, s->file_size),
+        .request = { .l2_table = NULL },
+        .fix = fix,
+    };
+    int ret;
+
+    check.used_clusters = qemu_mallocz(((check.nclusters + 31) / 32) *
+                                       sizeof(check.used_clusters[0]));
+
+    ret = qed_check_l1_table(&check, s->l1_table);
+    if (ret == 0) {
+        /* Only check for leaks if entire image was scanned successfully */
+        qed_check_for_leaks(&check);
+    }
+
+    qemu_free(check.used_clusters);
+    return ret;
+}
diff --git a/qemu-0.15.x/block/qed-cluster.c b/qemu-0.15.x/block/qed-cluster.c
new file mode 100644
index 0000000..3e19ad1
--- /dev/null
+++ b/qemu-0.15.x/block/qed-cluster.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU Enhanced Disk Format Cluster functions
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qed.h"
+
+/**
+ * Count the number of contiguous data clusters
+ *
+ * @s:              QED state
+ * @table:          L2 table
+ * @index:          First cluster index
+ * @n:              Maximum number of clusters
+ * @offset:         Set to first cluster offset
+ *
+ * This function scans tables for contiguous clusters.  A contiguous run of
+ * clusters may be allocated, unallocated, or zero.
+ */
+static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
+                                                  QEDTable *table,
+                                                  unsigned int index,
+                                                  unsigned int n,
+                                                  uint64_t *offset)
+{
+    unsigned int end = MIN(index + n, s->table_nelems);
+    uint64_t last = table->offsets[index];
+    unsigned int i;
+
+    *offset = last;
+
+    for (i = index + 1; i < end; i++) {
+        if (qed_offset_is_unalloc_cluster(last)) {
+            /* Counting unallocated clusters */
+            if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
+                break;
+            }
+        } else if (qed_offset_is_zero_cluster(last)) {
+            /* Counting zero clusters */
+            if (!qed_offset_is_zero_cluster(table->offsets[i])) {
+                break;
+            }
+        } else {
+            /* Counting allocated clusters */
+            if (table->offsets[i] != last + s->header.cluster_size) {
+                break;
+            }
+            last = table->offsets[i];
+        }
+    }
+    return i - index;
+}
+
+typedef struct {
+    BDRVQEDState *s;
+    uint64_t pos;
+    size_t len;
+
+    QEDRequest *request;
+
+    /* User callback */
+    QEDFindClusterFunc *cb;
+    void *opaque;
+} QEDFindClusterCB;
+
+static void qed_find_cluster_cb(void *opaque, int ret)
+{
+    QEDFindClusterCB *find_cluster_cb = opaque;
+    BDRVQEDState *s = find_cluster_cb->s;
+    QEDRequest *request = find_cluster_cb->request;
+    uint64_t offset = 0;
+    size_t len = 0;
+    unsigned int index;
+    unsigned int n;
+
+    if (ret) {
+        goto out;
+    }
+
+    index = qed_l2_index(s, find_cluster_cb->pos);
+    n = qed_bytes_to_clusters(s,
+                              qed_offset_into_cluster(s, find_cluster_cb->pos) +
+                              find_cluster_cb->len);
+    n = qed_count_contiguous_clusters(s, request->l2_table->table,
+                                      index, n, &offset);
+
+    if (qed_offset_is_unalloc_cluster(offset)) {
+        ret = QED_CLUSTER_L2;
+    } else if (qed_offset_is_zero_cluster(offset)) {
+        ret = QED_CLUSTER_ZERO;
+    } else if (qed_check_cluster_offset(s, offset)) {
+        ret = QED_CLUSTER_FOUND;
+    } else {
+        ret = -EINVAL;
+    }
+
+    len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
+              qed_offset_into_cluster(s, find_cluster_cb->pos));
+
+out:
+    find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
+    qemu_free(find_cluster_cb);
+}
+
+/**
+ * Find the offset of a data cluster
+ *
+ * @s:          QED state
+ * @request:    L2 cache entry
+ * @pos:        Byte position in device
+ * @len:        Number of bytes
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ *
+ * This function translates a position in the block device to an offset in the
+ * image file.  It invokes the cb completion callback to report back the
+ * translated offset or unallocated range in the image file.
+ *
+ * If the L2 table exists, request->l2_table points to the L2 table cache entry
+ * and the caller must free the reference when they are finished.  The cache
+ * entry is exposed in this way to avoid callers having to read the L2 table
+ * again later during request processing.  If request->l2_table is non-NULL it
+ * will be unreferenced before taking on the new cache entry.
+ */
+void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
+                      size_t len, QEDFindClusterFunc *cb, void *opaque)
+{
+    QEDFindClusterCB *find_cluster_cb;
+    uint64_t l2_offset;
+
+    /* Limit length to L2 boundary.  Requests are broken up at the L2 boundary
+     * so that a request acts on one L2 table at a time.
+     */
+    len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
+
+    l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
+    if (qed_offset_is_unalloc_cluster(l2_offset)) {
+        cb(opaque, QED_CLUSTER_L1, 0, len);
+        return;
+    }
+    if (!qed_check_table_offset(s, l2_offset)) {
+        cb(opaque, -EINVAL, 0, 0);
+        return;
+    }
+
+    find_cluster_cb = qemu_malloc(sizeof(*find_cluster_cb));
+    find_cluster_cb->s = s;
+    find_cluster_cb->pos = pos;
+    find_cluster_cb->len = len;
+    find_cluster_cb->cb = cb;
+    find_cluster_cb->opaque = opaque;
+    find_cluster_cb->request = request;
+
+    qed_read_l2_table(s, request, l2_offset,
+                      qed_find_cluster_cb, find_cluster_cb);
+}
diff --git a/qemu-0.15.x/block/qed-gencb.c b/qemu-0.15.x/block/qed-gencb.c
new file mode 100644
index 0000000..1513dc6
--- /dev/null
+++ b/qemu-0.15.x/block/qed-gencb.c
@@ -0,0 +1,32 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qed.h"
+
+void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
+{
+    GenericCB *gencb = qemu_malloc(len);
+    gencb->cb = cb;
+    gencb->opaque = opaque;
+    return gencb;
+}
+
+void gencb_complete(void *opaque, int ret)
+{
+    GenericCB *gencb = opaque;
+    BlockDriverCompletionFunc *cb = gencb->cb;
+    void *user_opaque = gencb->opaque;
+
+    qemu_free(gencb);
+    cb(user_opaque, ret);
+}
diff --git a/qemu-0.15.x/block/qed-l2-cache.c b/qemu-0.15.x/block/qed-l2-cache.c
new file mode 100644
index 0000000..57518a4
--- /dev/null
+++ b/qemu-0.15.x/block/qed-l2-cache.c
@@ -0,0 +1,173 @@
+/*
+ * QEMU Enhanced Disk Format L2 Cache
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+/*
+ * L2 table cache usage is as follows:
+ *
+ * An open image has one L2 table cache that is used to avoid accessing the
+ * image file for recently referenced L2 tables.
+ *
+ * Cluster offset lookup translates the logical offset within the block device
+ * to a cluster offset within the image file.  This is done by indexing into
+ * the L1 and L2 tables which store cluster offsets.  It is here where the L2
+ * table cache serves up recently referenced L2 tables.
+ *
+ * If there is a cache miss, that L2 table is read from the image file and
+ * committed to the cache.  Subsequent accesses to that L2 table will be served
+ * from the cache until the table is evicted from the cache.
+ *
+ * L2 tables are also committed to the cache when new L2 tables are allocated
+ * in the image file.  Since the L2 table cache is write-through, the new L2
+ * table is first written out to the image file and then committed to the
+ * cache.
+ *
+ * Multiple I/O requests may be using an L2 table cache entry at any given
+ * time.  That means an entry may be in use across several requests and
+ * reference counting is needed to free the entry at the correct time.  In
+ * particular, an entry evicted from the cache will only be freed once all
+ * references are dropped.
+ *
+ * An in-flight I/O request will hold a reference to a L2 table cache entry for
+ * the period during which it needs to access the L2 table.  This includes
+ * cluster offset lookup, L2 table allocation, and L2 table update when a new
+ * data cluster has been allocated.
+ *
+ * An interesting case occurs when two requests need to access an L2 table that
+ * is not in the cache.  Since the operation to read the table from the image
+ * file takes some time to complete, both requests may see a cache miss and
+ * start reading the L2 table from the image file.  The first to finish will
+ * commit its L2 table into the cache.  When the second tries to commit its
+ * table will be deleted in favor of the existing cache entry.
+ */
+
+#include "trace.h"
+#include "qed.h"
+
+/* Each L2 holds 2GB so this let's us fully cache a 100GB disk */
+#define MAX_L2_CACHE_SIZE 50
+
+/**
+ * Initialize the L2 cache
+ */
+void qed_init_l2_cache(L2TableCache *l2_cache)
+{
+    QTAILQ_INIT(&l2_cache->entries);
+    l2_cache->n_entries = 0;
+}
+
+/**
+ * Free the L2 cache
+ */
+void qed_free_l2_cache(L2TableCache *l2_cache)
+{
+    CachedL2Table *entry, *next_entry;
+
+    QTAILQ_FOREACH_SAFE(entry, &l2_cache->entries, node, next_entry) {
+        qemu_vfree(entry->table);
+        qemu_free(entry);
+    }
+}
+
+/**
+ * Allocate an uninitialized entry from the cache
+ *
+ * The returned entry has a reference count of 1 and is owned by the caller.
+ * The caller must allocate the actual table field for this entry and it must
+ * be freeable using qemu_vfree().
+ */
+CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache)
+{
+    CachedL2Table *entry;
+
+    entry = qemu_mallocz(sizeof(*entry));
+    entry->ref++;
+
+    trace_qed_alloc_l2_cache_entry(l2_cache, entry);
+
+    return entry;
+}
+
+/**
+ * Decrease an entry's reference count and free if necessary when the reference
+ * count drops to zero.
+ */
+void qed_unref_l2_cache_entry(CachedL2Table *entry)
+{
+    if (!entry) {
+        return;
+    }
+
+    entry->ref--;
+    trace_qed_unref_l2_cache_entry(entry, entry->ref);
+    if (entry->ref == 0) {
+        qemu_vfree(entry->table);
+        qemu_free(entry);
+    }
+}
+
+/**
+ * Find an entry in the L2 cache.  This may return NULL and it's up to the
+ * caller to satisfy the cache miss.
+ *
+ * For a cached entry, this function increases the reference count and returns
+ * the entry.
+ */
+CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset)
+{
+    CachedL2Table *entry;
+
+    QTAILQ_FOREACH(entry, &l2_cache->entries, node) {
+        if (entry->offset == offset) {
+            trace_qed_find_l2_cache_entry(l2_cache, entry, offset, entry->ref);
+            entry->ref++;
+            return entry;
+        }
+    }
+    return NULL;
+}
+
+/**
+ * Commit an L2 cache entry into the cache.  This is meant to be used as part of
+ * the process to satisfy a cache miss.  A caller would allocate an entry which
+ * is not actually in the L2 cache and then once the entry was valid and
+ * present on disk, the entry can be committed into the cache.
+ *
+ * Since the cache is write-through, it's important that this function is not
+ * called until the entry is present on disk and the L1 has been updated to
+ * point to the entry.
+ *
+ * N.B. This function steals a reference to the l2_table from the caller so the
+ * caller must obtain a new reference by issuing a call to
+ * qed_find_l2_cache_entry().
+ */
+void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table)
+{
+    CachedL2Table *entry;
+
+    entry = qed_find_l2_cache_entry(l2_cache, l2_table->offset);
+    if (entry) {
+        qed_unref_l2_cache_entry(entry);
+        qed_unref_l2_cache_entry(l2_table);
+        return;
+    }
+
+    if (l2_cache->n_entries >= MAX_L2_CACHE_SIZE) {
+        entry = QTAILQ_FIRST(&l2_cache->entries);
+        QTAILQ_REMOVE(&l2_cache->entries, entry, node);
+        l2_cache->n_entries--;
+        qed_unref_l2_cache_entry(entry);
+    }
+
+    l2_cache->n_entries++;
+    QTAILQ_INSERT_TAIL(&l2_cache->entries, l2_table, node);
+}
diff --git a/qemu-0.15.x/block/qed-table.c b/qemu-0.15.x/block/qed-table.c
new file mode 100644
index 0000000..5c5d4b4
--- /dev/null
+++ b/qemu-0.15.x/block/qed-table.c
@@ -0,0 +1,319 @@
+/*
+ * QEMU Enhanced Disk Format Table I/O
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "qemu_socket.h" /* for EINPROGRESS on Windows */
+#include "qed.h"
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEDTable *table;
+
+    struct iovec iov;
+    QEMUIOVector qiov;
+} QEDReadTableCB;
+
+static void qed_read_table_cb(void *opaque, int ret)
+{
+    QEDReadTableCB *read_table_cb = opaque;
+    QEDTable *table = read_table_cb->table;
+    int noffsets = read_table_cb->iov.iov_len / sizeof(uint64_t);
+    int i;
+
+    /* Handle I/O error */
+    if (ret) {
+        goto out;
+    }
+
+    /* Byteswap offsets */
+    for (i = 0; i < noffsets; i++) {
+        table->offsets[i] = le64_to_cpu(table->offsets[i]);
+    }
+
+out:
+    /* Completion */
+    trace_qed_read_table_cb(read_table_cb->s, read_table_cb->table, ret);
+    gencb_complete(&read_table_cb->gencb, ret);
+}
+
+static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
+                           BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
+                                                cb, opaque);
+    QEMUIOVector *qiov = &read_table_cb->qiov;
+    BlockDriverAIOCB *aiocb;
+
+    trace_qed_read_table(s, offset, table);
+
+    read_table_cb->s = s;
+    read_table_cb->table = table;
+    read_table_cb->iov.iov_base = table->offsets,
+    read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
+
+    qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
+    aiocb = bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
+                           read_table_cb->iov.iov_len / BDRV_SECTOR_SIZE,
+                           qed_read_table_cb, read_table_cb);
+    if (!aiocb) {
+        qed_read_table_cb(read_table_cb, -EIO);
+    }
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEDTable *orig_table;
+    QEDTable *table;
+    bool flush;             /* flush after write? */
+
+    struct iovec iov;
+    QEMUIOVector qiov;
+} QEDWriteTableCB;
+
+static void qed_write_table_cb(void *opaque, int ret)
+{
+    QEDWriteTableCB *write_table_cb = opaque;
+
+    trace_qed_write_table_cb(write_table_cb->s,
+                             write_table_cb->orig_table,
+                             write_table_cb->flush,
+                             ret);
+
+    if (ret) {
+        goto out;
+    }
+
+    if (write_table_cb->flush) {
+        /* We still need to flush first */
+        write_table_cb->flush = false;
+        bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb,
+                       write_table_cb);
+        return;
+    }
+
+out:
+    qemu_vfree(write_table_cb->table);
+    gencb_complete(&write_table_cb->gencb, ret);
+    return;
+}
+
+/**
+ * Write out an updated part or all of a table
+ *
+ * @s:          QED state
+ * @offset:     Offset of table in image file, in bytes
+ * @table:      Table
+ * @index:      Index of first element
+ * @n:          Number of elements
+ * @flush:      Whether or not to sync to disk
+ * @cb:         Completion function
+ * @opaque:     Argument for completion function
+ */
+static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
+                            unsigned int index, unsigned int n, bool flush,
+                            BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDWriteTableCB *write_table_cb;
+    BlockDriverAIOCB *aiocb;
+    unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
+    unsigned int start, end, i;
+    size_t len_bytes;
+
+    trace_qed_write_table(s, offset, table, index, n);
+
+    /* Calculate indices of the first and one after last elements */
+    start = index & ~sector_mask;
+    end = (index + n + sector_mask) & ~sector_mask;
+
+    len_bytes = (end - start) * sizeof(uint64_t);
+
+    write_table_cb = gencb_alloc(sizeof(*write_table_cb), cb, opaque);
+    write_table_cb->s = s;
+    write_table_cb->orig_table = table;
+    write_table_cb->flush = flush;
+    write_table_cb->table = qemu_blockalign(s->bs, len_bytes);
+    write_table_cb->iov.iov_base = write_table_cb->table->offsets;
+    write_table_cb->iov.iov_len = len_bytes;
+    qemu_iovec_init_external(&write_table_cb->qiov, &write_table_cb->iov, 1);
+
+    /* Byteswap table */
+    for (i = start; i < end; i++) {
+        uint64_t le_offset = cpu_to_le64(table->offsets[i]);
+        write_table_cb->table->offsets[i - start] = le_offset;
+    }
+
+    /* Adjust for offset into table */
+    offset += start * sizeof(uint64_t);
+
+    aiocb = bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+                            &write_table_cb->qiov,
+                            write_table_cb->iov.iov_len / BDRV_SECTOR_SIZE,
+                            qed_write_table_cb, write_table_cb);
+    if (!aiocb) {
+        qed_write_table_cb(write_table_cb, -EIO);
+    }
+}
+
+/**
+ * Propagate return value from async callback
+ */
+static void qed_sync_cb(void *opaque, int ret)
+{
+    *(int *)opaque = ret;
+}
+
+int qed_read_l1_table_sync(BDRVQEDState *s)
+{
+    int ret = -EINPROGRESS;
+
+    async_context_push();
+
+    qed_read_table(s, s->header.l1_table_offset,
+                   s->l1_table, qed_sync_cb, &ret);
+    while (ret == -EINPROGRESS) {
+        qemu_aio_wait();
+    }
+
+    async_context_pop();
+
+    return ret;
+}
+
+void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
+                        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
+    qed_write_table(s, s->header.l1_table_offset,
+                    s->l1_table, index, n, false, cb, opaque);
+}
+
+int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
+                            unsigned int n)
+{
+    int ret = -EINPROGRESS;
+
+    async_context_push();
+
+    qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
+    while (ret == -EINPROGRESS) {
+        qemu_aio_wait();
+    }
+
+    async_context_pop();
+
+    return ret;
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    uint64_t l2_offset;
+    QEDRequest *request;
+} QEDReadL2TableCB;
+
+static void qed_read_l2_table_cb(void *opaque, int ret)
+{
+    QEDReadL2TableCB *read_l2_table_cb = opaque;
+    QEDRequest *request = read_l2_table_cb->request;
+    BDRVQEDState *s = read_l2_table_cb->s;
+    CachedL2Table *l2_table = request->l2_table;
+    uint64_t l2_offset = read_l2_table_cb->l2_offset;
+
+    if (ret) {
+        /* can't trust loaded L2 table anymore */
+        qed_unref_l2_cache_entry(l2_table);
+        request->l2_table = NULL;
+    } else {
+        l2_table->offset = l2_offset;
+
+        qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
+
+        /* This is guaranteed to succeed because we just committed the entry
+         * to the cache.
+         */
+        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
+        assert(request->l2_table != NULL);
+    }
+
+    gencb_complete(&read_l2_table_cb->gencb, ret);
+}
+
+void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
+                       BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDReadL2TableCB *read_l2_table_cb;
+
+    qed_unref_l2_cache_entry(request->l2_table);
+
+    /* Check for cached L2 entry */
+    request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
+    if (request->l2_table) {
+        cb(opaque, 0);
+        return;
+    }
+
+    request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
+    request->l2_table->table = qed_alloc_table(s);
+
+    read_l2_table_cb = gencb_alloc(sizeof(*read_l2_table_cb), cb, opaque);
+    read_l2_table_cb->s = s;
+    read_l2_table_cb->l2_offset = offset;
+    read_l2_table_cb->request = request;
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
+    qed_read_table(s, offset, request->l2_table->table,
+                   qed_read_l2_table_cb, read_l2_table_cb);
+}
+
+int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
+{
+    int ret = -EINPROGRESS;
+
+    async_context_push();
+
+    qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
+    while (ret == -EINPROGRESS) {
+        qemu_aio_wait();
+    }
+
+    async_context_pop();
+    return ret;
+}
+
+void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
+                        unsigned int index, unsigned int n, bool flush,
+                        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
+    qed_write_table(s, request->l2_table->offset,
+                    request->l2_table->table, index, n, flush, cb, opaque);
+}
+
+int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                            unsigned int index, unsigned int n, bool flush)
+{
+    int ret = -EINPROGRESS;
+
+    async_context_push();
+
+    qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
+    while (ret == -EINPROGRESS) {
+        qemu_aio_wait();
+    }
+
+    async_context_pop();
+    return ret;
+}
diff --git a/qemu-0.15.x/block/qed.c b/qemu-0.15.x/block/qed.c
new file mode 100644
index 0000000..4dc33be
--- /dev/null
+++ b/qemu-0.15.x/block/qed.c
@@ -0,0 +1,1504 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-timer.h"
+#include "trace.h"
+#include "qed.h"
+#include "qerror.h"
+
+static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QEDAIOCB *acb = (QEDAIOCB *)blockacb;
+    bool finished = false;
+
+    /* Wait for the request to finish */
+    acb->finished = &finished;
+    while (!finished) {
+        qemu_aio_wait();
+    }
+}
+
+static AIOPool qed_aio_pool = {
+    .aiocb_size         = sizeof(QEDAIOCB),
+    .cancel             = qed_aio_cancel,
+};
+
+static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
+                          const char *filename)
+{
+    const QEDHeader *header = (const QEDHeader *)buf;
+
+    if (buf_size < sizeof(*header)) {
+        return 0;
+    }
+    if (le32_to_cpu(header->magic) != QED_MAGIC) {
+        return 0;
+    }
+    return 100;
+}
+
+/**
+ * Check whether an image format is raw
+ *
+ * @fmt:    Backing file format, may be NULL
+ */
+static bool qed_fmt_is_raw(const char *fmt)
+{
+    return fmt && strcmp(fmt, "raw") == 0;
+}
+
+static void qed_header_le_to_cpu(const QEDHeader *le, QEDHeader *cpu)
+{
+    cpu->magic = le32_to_cpu(le->magic);
+    cpu->cluster_size = le32_to_cpu(le->cluster_size);
+    cpu->table_size = le32_to_cpu(le->table_size);
+    cpu->header_size = le32_to_cpu(le->header_size);
+    cpu->features = le64_to_cpu(le->features);
+    cpu->compat_features = le64_to_cpu(le->compat_features);
+    cpu->autoclear_features = le64_to_cpu(le->autoclear_features);
+    cpu->l1_table_offset = le64_to_cpu(le->l1_table_offset);
+    cpu->image_size = le64_to_cpu(le->image_size);
+    cpu->backing_filename_offset = le32_to_cpu(le->backing_filename_offset);
+    cpu->backing_filename_size = le32_to_cpu(le->backing_filename_size);
+}
+
+static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le)
+{
+    le->magic = cpu_to_le32(cpu->magic);
+    le->cluster_size = cpu_to_le32(cpu->cluster_size);
+    le->table_size = cpu_to_le32(cpu->table_size);
+    le->header_size = cpu_to_le32(cpu->header_size);
+    le->features = cpu_to_le64(cpu->features);
+    le->compat_features = cpu_to_le64(cpu->compat_features);
+    le->autoclear_features = cpu_to_le64(cpu->autoclear_features);
+    le->l1_table_offset = cpu_to_le64(cpu->l1_table_offset);
+    le->image_size = cpu_to_le64(cpu->image_size);
+    le->backing_filename_offset = cpu_to_le32(cpu->backing_filename_offset);
+    le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size);
+}
+
+static int qed_write_header_sync(BDRVQEDState *s)
+{
+    QEDHeader le;
+    int ret;
+
+    qed_header_cpu_to_le(&s->header, &le);
+    ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le));
+    if (ret != sizeof(le)) {
+        return ret;
+    }
+    return 0;
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    int nsectors;
+    uint8_t *buf;
+} QEDWriteHeaderCB;
+
+static void qed_write_header_cb(void *opaque, int ret)
+{
+    QEDWriteHeaderCB *write_header_cb = opaque;
+
+    qemu_vfree(write_header_cb->buf);
+    gencb_complete(write_header_cb, ret);
+}
+
+static void qed_write_header_read_cb(void *opaque, int ret)
+{
+    QEDWriteHeaderCB *write_header_cb = opaque;
+    BDRVQEDState *s = write_header_cb->s;
+    BlockDriverAIOCB *acb;
+
+    if (ret) {
+        qed_write_header_cb(write_header_cb, ret);
+        return;
+    }
+
+    /* Update header */
+    qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
+
+    acb = bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov,
+                          write_header_cb->nsectors, qed_write_header_cb,
+                          write_header_cb);
+    if (!acb) {
+        qed_write_header_cb(write_header_cb, -EIO);
+    }
+}
+
+/**
+ * Update header in-place (does not rewrite backing filename or other strings)
+ *
+ * This function only updates known header fields in-place and does not affect
+ * extra data after the QED header.
+ */
+static void qed_write_header(BDRVQEDState *s, BlockDriverCompletionFunc cb,
+                             void *opaque)
+{
+    /* We must write full sectors for O_DIRECT but cannot necessarily generate
+     * the data following the header if an unrecognized compat feature is
+     * active.  Therefore, first read the sectors containing the header, update
+     * them, and write back.
+     */
+
+    BlockDriverAIOCB *acb;
+    int nsectors = (sizeof(QEDHeader) + BDRV_SECTOR_SIZE - 1) /
+                   BDRV_SECTOR_SIZE;
+    size_t len = nsectors * BDRV_SECTOR_SIZE;
+    QEDWriteHeaderCB *write_header_cb = gencb_alloc(sizeof(*write_header_cb),
+                                                    cb, opaque);
+
+    write_header_cb->s = s;
+    write_header_cb->nsectors = nsectors;
+    write_header_cb->buf = qemu_blockalign(s->bs, len);
+    write_header_cb->iov.iov_base = write_header_cb->buf;
+    write_header_cb->iov.iov_len = len;
+    qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
+
+    acb = bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors,
+                         qed_write_header_read_cb, write_header_cb);
+    if (!acb) {
+        qed_write_header_cb(write_header_cb, -EIO);
+    }
+}
+
+static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size)
+{
+    uint64_t table_entries;
+    uint64_t l2_size;
+
+    table_entries = (table_size * cluster_size) / sizeof(uint64_t);
+    l2_size = table_entries * cluster_size;
+
+    return l2_size * table_entries;
+}
+
+static bool qed_is_cluster_size_valid(uint32_t cluster_size)
+{
+    if (cluster_size < QED_MIN_CLUSTER_SIZE ||
+        cluster_size > QED_MAX_CLUSTER_SIZE) {
+        return false;
+    }
+    if (cluster_size & (cluster_size - 1)) {
+        return false; /* not power of 2 */
+    }
+    return true;
+}
+
+static bool qed_is_table_size_valid(uint32_t table_size)
+{
+    if (table_size < QED_MIN_TABLE_SIZE ||
+        table_size > QED_MAX_TABLE_SIZE) {
+        return false;
+    }
+    if (table_size & (table_size - 1)) {
+        return false; /* not power of 2 */
+    }
+    return true;
+}
+
+static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size,
+                                    uint32_t table_size)
+{
+    if (image_size % BDRV_SECTOR_SIZE != 0) {
+        return false; /* not multiple of sector size */
+    }
+    if (image_size > qed_max_image_size(cluster_size, table_size)) {
+        return false; /* image is too large */
+    }
+    return true;
+}
+
+/**
+ * Read a string of known length from the image file
+ *
+ * @file:       Image file
+ * @offset:     File offset to start of string, in bytes
+ * @n:          String length in bytes
+ * @buf:        Destination buffer
+ * @buflen:     Destination buffer length in bytes
+ * @ret:        0 on success, -errno on failure
+ *
+ * The string is NUL-terminated.
+ */
+static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
+                           char *buf, size_t buflen)
+{
+    int ret;
+    if (n >= buflen) {
+        return -EINVAL;
+    }
+    ret = bdrv_pread(file, offset, buf, n);
+    if (ret < 0) {
+        return ret;
+    }
+    buf[n] = '\0';
+    return 0;
+}
+
+/**
+ * Allocate new clusters
+ *
+ * @s:          QED state
+ * @n:          Number of contiguous clusters to allocate
+ * @ret:        Offset of first allocated cluster
+ *
+ * This function only produces the offset where the new clusters should be
+ * written.  It updates BDRVQEDState but does not make any changes to the image
+ * file.
+ */
+static uint64_t qed_alloc_clusters(BDRVQEDState *s, unsigned int n)
+{
+    uint64_t offset = s->file_size;
+    s->file_size += n * s->header.cluster_size;
+    return offset;
+}
+
+QEDTable *qed_alloc_table(BDRVQEDState *s)
+{
+    /* Honor O_DIRECT memory alignment requirements */
+    return qemu_blockalign(s->bs,
+                           s->header.cluster_size * s->header.table_size);
+}
+
+/**
+ * Allocate a new zeroed L2 table
+ */
+static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
+{
+    CachedL2Table *l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
+
+    l2_table->table = qed_alloc_table(s);
+    l2_table->offset = qed_alloc_clusters(s, s->header.table_size);
+
+    memset(l2_table->table->offsets, 0,
+           s->header.cluster_size * s->header.table_size);
+    return l2_table;
+}
+
+static void qed_aio_next_io(void *opaque, int ret);
+
+static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
+{
+    assert(!s->allocating_write_reqs_plugged);
+
+    s->allocating_write_reqs_plugged = true;
+}
+
+static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
+{
+    QEDAIOCB *acb;
+
+    assert(s->allocating_write_reqs_plugged);
+
+    s->allocating_write_reqs_plugged = false;
+
+    acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
+    if (acb) {
+        qed_aio_next_io(acb, 0);
+    }
+}
+
+static void qed_finish_clear_need_check(void *opaque, int ret)
+{
+    /* Do nothing */
+}
+
+static void qed_flush_after_clear_need_check(void *opaque, int ret)
+{
+    BDRVQEDState *s = opaque;
+
+    bdrv_aio_flush(s->bs, qed_finish_clear_need_check, s);
+
+    /* No need to wait until flush completes */
+    qed_unplug_allocating_write_reqs(s);
+}
+
+static void qed_clear_need_check(void *opaque, int ret)
+{
+    BDRVQEDState *s = opaque;
+
+    if (ret) {
+        qed_unplug_allocating_write_reqs(s);
+        return;
+    }
+
+    s->header.features &= ~QED_F_NEED_CHECK;
+    qed_write_header(s, qed_flush_after_clear_need_check, s);
+}
+
+static void qed_need_check_timer_cb(void *opaque)
+{
+    BDRVQEDState *s = opaque;
+
+    /* The timer should only fire when allocating writes have drained */
+    assert(!QSIMPLEQ_FIRST(&s->allocating_write_reqs));
+
+    trace_qed_need_check_timer_cb(s);
+
+    qed_plug_allocating_write_reqs(s);
+
+    /* Ensure writes are on disk before clearing flag */
+    bdrv_aio_flush(s->bs, qed_clear_need_check, s);
+}
+
+static void qed_start_need_check_timer(BDRVQEDState *s)
+{
+    trace_qed_start_need_check_timer(s);
+
+    /* Use vm_clock so we don't alter the image file while suspended for
+     * migration.
+     */
+    qemu_mod_timer(s->need_check_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() * QED_NEED_CHECK_TIMEOUT);
+}
+
+/* It's okay to call this multiple times or when no timer is started */
+static void qed_cancel_need_check_timer(BDRVQEDState *s)
+{
+    trace_qed_cancel_need_check_timer(s);
+    qemu_del_timer(s->need_check_timer);
+}
+
+static int bdrv_qed_open(BlockDriverState *bs, int flags)
+{
+    BDRVQEDState *s = bs->opaque;
+    QEDHeader le_header;
+    int64_t file_size;
+    int ret;
+
+    s->bs = bs;
+    QSIMPLEQ_INIT(&s->allocating_write_reqs);
+
+    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
+    if (ret < 0) {
+        return ret;
+    }
+    ret = 0; /* ret should always be 0 or -errno */
+    qed_header_le_to_cpu(&le_header, &s->header);
+
+    if (s->header.magic != QED_MAGIC) {
+        return -EINVAL;
+    }
+    if (s->header.features & ~QED_FEATURE_MASK) {
+        /* image uses unsupported feature bits */
+        char buf[64];
+        snprintf(buf, sizeof(buf), "%" PRIx64,
+            s->header.features & ~QED_FEATURE_MASK);
+        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+            bs->device_name, "QED", buf);
+        return -ENOTSUP;
+    }
+    if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
+        return -EINVAL;
+    }
+
+    /* Round down file size to the last cluster */
+    file_size = bdrv_getlength(bs->file);
+    if (file_size < 0) {
+        return file_size;
+    }
+    s->file_size = qed_start_of_cluster(s, file_size);
+
+    if (!qed_is_table_size_valid(s->header.table_size)) {
+        return -EINVAL;
+    }
+    if (!qed_is_image_size_valid(s->header.image_size,
+                                 s->header.cluster_size,
+                                 s->header.table_size)) {
+        return -EINVAL;
+    }
+    if (!qed_check_table_offset(s, s->header.l1_table_offset)) {
+        return -EINVAL;
+    }
+
+    s->table_nelems = (s->header.cluster_size * s->header.table_size) /
+                      sizeof(uint64_t);
+    s->l2_shift = ffs(s->header.cluster_size) - 1;
+    s->l2_mask = s->table_nelems - 1;
+    s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
+
+    if ((s->header.features & QED_F_BACKING_FILE)) {
+        if ((uint64_t)s->header.backing_filename_offset +
+            s->header.backing_filename_size >
+            s->header.cluster_size * s->header.header_size) {
+            return -EINVAL;
+        }
+
+        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
+                              s->header.backing_filename_size, bs->backing_file,
+                              sizeof(bs->backing_file));
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
+            pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
+        }
+    }
+
+    /* Reset unknown autoclear feature bits.  This is a backwards
+     * compatibility mechanism that allows images to be opened by older
+     * programs, which "knock out" unknown feature bits.  When an image is
+     * opened by a newer program again it can detect that the autoclear
+     * feature is no longer valid.
+     */
+    if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
+        !bdrv_is_read_only(bs->file)) {
+        s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
+
+        ret = qed_write_header_sync(s);
+        if (ret) {
+            return ret;
+        }
+
+        /* From here on only known autoclear feature bits are valid */
+        bdrv_flush(bs->file);
+    }
+
+    s->l1_table = qed_alloc_table(s);
+    qed_init_l2_cache(&s->l2_cache);
+
+    ret = qed_read_l1_table_sync(s);
+    if (ret) {
+        goto out;
+    }
+
+    /* If image was not closed cleanly, check consistency */
+    if (s->header.features & QED_F_NEED_CHECK) {
+        /* Read-only images cannot be fixed.  There is no risk of corruption
+         * since write operations are not possible.  Therefore, allow
+         * potentially inconsistent images to be opened read-only.  This can
+         * aid data recovery from an otherwise inconsistent image.
+         */
+        if (!bdrv_is_read_only(bs->file)) {
+            BdrvCheckResult result = {0};
+
+            ret = qed_check(s, &result, true);
+            if (ret) {
+                goto out;
+            }
+            if (!result.corruptions && !result.check_errors) {
+                /* Ensure fixes reach storage before clearing check bit */
+                bdrv_flush(s->bs);
+
+                s->header.features &= ~QED_F_NEED_CHECK;
+                qed_write_header_sync(s);
+            }
+        }
+    }
+
+    s->need_check_timer = qemu_new_timer_ns(vm_clock,
+                                            qed_need_check_timer_cb, s);
+
+out:
+    if (ret) {
+        qed_free_l2_cache(&s->l2_cache);
+        qemu_vfree(s->l1_table);
+    }
+    return ret;
+}
+
+static void bdrv_qed_close(BlockDriverState *bs)
+{
+    BDRVQEDState *s = bs->opaque;
+
+    qed_cancel_need_check_timer(s);
+    qemu_free_timer(s->need_check_timer);
+
+    /* Ensure writes reach stable storage */
+    bdrv_flush(bs->file);
+
+    /* Clean shutdown, no check required on next open */
+    if (s->header.features & QED_F_NEED_CHECK) {
+        s->header.features &= ~QED_F_NEED_CHECK;
+        qed_write_header_sync(s);
+    }
+
+    qed_free_l2_cache(&s->l2_cache);
+    qemu_vfree(s->l1_table);
+}
+
+static int bdrv_qed_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static int qed_create(const char *filename, uint32_t cluster_size,
+                      uint64_t image_size, uint32_t table_size,
+                      const char *backing_file, const char *backing_fmt)
+{
+    QEDHeader header = {
+        .magic = QED_MAGIC,
+        .cluster_size = cluster_size,
+        .table_size = table_size,
+        .header_size = 1,
+        .features = 0,
+        .compat_features = 0,
+        .l1_table_offset = cluster_size,
+        .image_size = image_size,
+    };
+    QEDHeader le_header;
+    uint8_t *l1_table = NULL;
+    size_t l1_size = header.cluster_size * header.table_size;
+    int ret = 0;
+    BlockDriverState *bs = NULL;
+
+    ret = bdrv_create_file(filename, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR | BDRV_O_CACHE_WB);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* File must start empty and grow, check truncate is supported */
+    ret = bdrv_truncate(bs, 0);
+    if (ret < 0) {
+        goto out;
+    }
+
+    if (backing_file) {
+        header.features |= QED_F_BACKING_FILE;
+        header.backing_filename_offset = sizeof(le_header);
+        header.backing_filename_size = strlen(backing_file);
+
+        if (qed_fmt_is_raw(backing_fmt)) {
+            header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
+        }
+    }
+
+    qed_header_cpu_to_le(&header, &le_header);
+    ret = bdrv_pwrite(bs, 0, &le_header, sizeof(le_header));
+    if (ret < 0) {
+        goto out;
+    }
+    ret = bdrv_pwrite(bs, sizeof(le_header), backing_file,
+                      header.backing_filename_size);
+    if (ret < 0) {
+        goto out;
+    }
+
+    l1_table = qemu_mallocz(l1_size);
+    ret = bdrv_pwrite(bs, header.l1_table_offset, l1_table, l1_size);
+    if (ret < 0) {
+        goto out;
+    }
+
+    ret = 0; /* success */
+out:
+    qemu_free(l1_table);
+    bdrv_delete(bs);
+    return ret;
+}
+
+static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint64_t image_size = 0;
+    uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
+    uint32_t table_size = QED_DEFAULT_TABLE_SIZE;
+    const char *backing_file = NULL;
+    const char *backing_fmt = NULL;
+
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            image_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
+            backing_fmt = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                cluster_size = options->value.n;
+            }
+        } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) {
+            if (options->value.n) {
+                table_size = options->value.n;
+            }
+        }
+        options++;
+    }
+
+    if (!qed_is_cluster_size_valid(cluster_size)) {
+        fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n",
+                QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
+        return -EINVAL;
+    }
+    if (!qed_is_table_size_valid(table_size)) {
+        fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n",
+                QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
+        return -EINVAL;
+    }
+    if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
+        fprintf(stderr, "QED image size must be a non-zero multiple of "
+                        "cluster size and less than %" PRIu64 " bytes\n",
+                qed_max_image_size(cluster_size, table_size));
+        return -EINVAL;
+    }
+
+    return qed_create(filename, cluster_size, image_size, table_size,
+                      backing_file, backing_fmt);
+}
+
+typedef struct {
+    int is_allocated;
+    int *pnum;
+} QEDIsAllocatedCB;
+
+static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
+{
+    QEDIsAllocatedCB *cb = opaque;
+    *cb->pnum = len / BDRV_SECTOR_SIZE;
+    cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO);
+}
+
+static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                                  int nb_sectors, int *pnum)
+{
+    BDRVQEDState *s = bs->opaque;
+    uint64_t pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
+    size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
+    QEDIsAllocatedCB cb = {
+        .is_allocated = -1,
+        .pnum = pnum,
+    };
+    QEDRequest request = { .l2_table = NULL };
+
+    async_context_push();
+
+    qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb);
+
+    while (cb.is_allocated == -1) {
+        qemu_aio_wait();
+    }
+
+    async_context_pop();
+
+    qed_unref_l2_cache_entry(request.l2_table);
+
+    return cb.is_allocated;
+}
+
+static int bdrv_qed_make_empty(BlockDriverState *bs)
+{
+    return -ENOTSUP;
+}
+
+static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
+{
+    return acb->common.bs->opaque;
+}
+
+/**
+ * Read from the backing file or zero-fill if no backing file
+ *
+ * @s:          QED state
+ * @pos:        Byte position in device
+ * @qiov:       Destination I/O vector
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ *
+ * This function reads qiov->size bytes starting at pos from the backing file.
+ * If there is no backing file then zeroes are read.
+ */
+static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
+                                  QEMUIOVector *qiov,
+                                  BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCB *aiocb;
+    uint64_t backing_length = 0;
+    size_t size;
+
+    /* If there is a backing file, get its length.  Treat the absence of a
+     * backing file like a zero length backing file.
+     */
+    if (s->bs->backing_hd) {
+        int64_t l = bdrv_getlength(s->bs->backing_hd);
+        if (l < 0) {
+            cb(opaque, l);
+            return;
+        }
+        backing_length = l;
+    }
+
+    /* Zero all sectors if reading beyond the end of the backing file */
+    if (pos >= backing_length ||
+        pos + qiov->size > backing_length) {
+        qemu_iovec_memset(qiov, 0, qiov->size);
+    }
+
+    /* Complete now if there are no backing file sectors to read */
+    if (pos >= backing_length) {
+        cb(opaque, 0);
+        return;
+    }
+
+    /* If the read straddles the end of the backing file, shorten it */
+    size = MIN((uint64_t)backing_length - pos, qiov->size);
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING);
+    aiocb = bdrv_aio_readv(s->bs->backing_hd, pos / BDRV_SECTOR_SIZE,
+                           qiov, size / BDRV_SECTOR_SIZE, cb, opaque);
+    if (!aiocb) {
+        cb(opaque, -EIO);
+    }
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEMUIOVector qiov;
+    struct iovec iov;
+    uint64_t offset;
+} CopyFromBackingFileCB;
+
+static void qed_copy_from_backing_file_cb(void *opaque, int ret)
+{
+    CopyFromBackingFileCB *copy_cb = opaque;
+    qemu_vfree(copy_cb->iov.iov_base);
+    gencb_complete(&copy_cb->gencb, ret);
+}
+
+static void qed_copy_from_backing_file_write(void *opaque, int ret)
+{
+    CopyFromBackingFileCB *copy_cb = opaque;
+    BDRVQEDState *s = copy_cb->s;
+    BlockDriverAIOCB *aiocb;
+
+    if (ret) {
+        qed_copy_from_backing_file_cb(copy_cb, ret);
+        return;
+    }
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
+    aiocb = bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE,
+                            &copy_cb->qiov,
+                            copy_cb->qiov.size / BDRV_SECTOR_SIZE,
+                            qed_copy_from_backing_file_cb, copy_cb);
+    if (!aiocb) {
+        qed_copy_from_backing_file_cb(copy_cb, -EIO);
+    }
+}
+
+/**
+ * Copy data from backing file into the image
+ *
+ * @s:          QED state
+ * @pos:        Byte position in device
+ * @len:        Number of bytes
+ * @offset:     Byte offset in image file
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ */
+static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
+                                       uint64_t len, uint64_t offset,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque)
+{
+    CopyFromBackingFileCB *copy_cb;
+
+    /* Skip copy entirely if there is no work to do */
+    if (len == 0) {
+        cb(opaque, 0);
+        return;
+    }
+
+    copy_cb = gencb_alloc(sizeof(*copy_cb), cb, opaque);
+    copy_cb->s = s;
+    copy_cb->offset = offset;
+    copy_cb->iov.iov_base = qemu_blockalign(s->bs, len);
+    copy_cb->iov.iov_len = len;
+    qemu_iovec_init_external(&copy_cb->qiov, &copy_cb->iov, 1);
+
+    qed_read_backing_file(s, pos, &copy_cb->qiov,
+                          qed_copy_from_backing_file_write, copy_cb);
+}
+
+/**
+ * Link one or more contiguous clusters into a table
+ *
+ * @s:              QED state
+ * @table:          L2 table
+ * @index:          First cluster index
+ * @n:              Number of contiguous clusters
+ * @cluster:        First cluster offset
+ *
+ * The cluster offset may be an allocated byte offset in the image file, the
+ * zero cluster marker, or the unallocated cluster marker.
+ */
+static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
+                                unsigned int n, uint64_t cluster)
+{
+    int i;
+    for (i = index; i < index + n; i++) {
+        table->offsets[i] = cluster;
+        if (!qed_offset_is_unalloc_cluster(cluster) &&
+            !qed_offset_is_zero_cluster(cluster)) {
+            cluster += s->header.cluster_size;
+        }
+    }
+}
+
+static void qed_aio_complete_bh(void *opaque)
+{
+    QEDAIOCB *acb = opaque;
+    BlockDriverCompletionFunc *cb = acb->common.cb;
+    void *user_opaque = acb->common.opaque;
+    int ret = acb->bh_ret;
+    bool *finished = acb->finished;
+
+    qemu_bh_delete(acb->bh);
+    qemu_aio_release(acb);
+
+    /* Invoke callback */
+    cb(user_opaque, ret);
+
+    /* Signal cancel completion */
+    if (finished) {
+        *finished = true;
+    }
+}
+
+static void qed_aio_complete(QEDAIOCB *acb, int ret)
+{
+    BDRVQEDState *s = acb_to_s(acb);
+
+    trace_qed_aio_complete(s, acb, ret);
+
+    /* Free resources */
+    qemu_iovec_destroy(&acb->cur_qiov);
+    qed_unref_l2_cache_entry(acb->request.l2_table);
+
+    /* Arrange for a bh to invoke the completion function */
+    acb->bh_ret = ret;
+    acb->bh = qemu_bh_new(qed_aio_complete_bh, acb);
+    qemu_bh_schedule(acb->bh);
+
+    /* Start next allocating write request waiting behind this one.  Note that
+     * requests enqueue themselves when they first hit an unallocated cluster
+     * but they wait until the entire request is finished before waking up the
+     * next request in the queue.  This ensures that we don't cycle through
+     * requests multiple times but rather finish one at a time completely.
+     */
+    if (acb == QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+        QSIMPLEQ_REMOVE_HEAD(&s->allocating_write_reqs, next);
+        acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
+        if (acb) {
+            qed_aio_next_io(acb, 0);
+        } else if (s->header.features & QED_F_NEED_CHECK) {
+            qed_start_need_check_timer(s);
+        }
+    }
+}
+
+/**
+ * Commit the current L2 table to the cache
+ */
+static void qed_commit_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    CachedL2Table *l2_table = acb->request.l2_table;
+    uint64_t l2_offset = l2_table->offset;
+
+    qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
+
+    /* This is guaranteed to succeed because we just committed the entry to the
+     * cache.
+     */
+    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
+    assert(acb->request.l2_table != NULL);
+
+    qed_aio_next_io(opaque, ret);
+}
+
+/**
+ * Update L1 table with new L2 table offset and write it out
+ */
+static void qed_aio_write_l1_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    int index;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    index = qed_l1_index(s, acb->cur_pos);
+    s->l1_table->offsets[index] = acb->request.l2_table->offset;
+
+    qed_write_l1_table(s, index, 1, qed_commit_l2_update, acb);
+}
+
+/**
+ * Update L2 table with new cluster offsets and write them out
+ */
+static void qed_aio_write_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
+    int index;
+
+    if (ret) {
+        goto err;
+    }
+
+    if (need_alloc) {
+        qed_unref_l2_cache_entry(acb->request.l2_table);
+        acb->request.l2_table = qed_new_l2_table(s);
+    }
+
+    index = qed_l2_index(s, acb->cur_pos);
+    qed_update_l2_table(s, acb->request.l2_table->table, index, acb->cur_nclusters,
+                         acb->cur_cluster);
+
+    if (need_alloc) {
+        /* Write out the whole new L2 table */
+        qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true,
+                            qed_aio_write_l1_update, acb);
+    } else {
+        /* Write out only the updated part of the L2 table */
+        qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters, false,
+                            qed_aio_next_io, acb);
+    }
+    return;
+
+err:
+    qed_aio_complete(acb, ret);
+}
+
+/**
+ * Flush new data clusters before updating the L2 table
+ *
+ * This flush is necessary when a backing file is in use.  A crash during an
+ * allocating write could result in empty clusters in the image.  If the write
+ * only touched a subregion of the cluster, then backing image sectors have
+ * been lost in the untouched region.  The solution is to flush after writing a
+ * new data cluster and before updating the L2 table.
+ */
+static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+
+    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update, opaque)) {
+        qed_aio_complete(acb, -EIO);
+    }
+}
+
+/**
+ * Write data to the image file
+ */
+static void qed_aio_write_main(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t offset = acb->cur_cluster +
+                      qed_offset_into_cluster(s, acb->cur_pos);
+    BlockDriverCompletionFunc *next_fn;
+    BlockDriverAIOCB *file_acb;
+
+    trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    if (acb->find_cluster_ret == QED_CLUSTER_FOUND) {
+        next_fn = qed_aio_next_io;
+    } else {
+        if (s->bs->backing_hd) {
+            next_fn = qed_aio_write_flush_before_l2_update;
+        } else {
+            next_fn = qed_aio_write_l2_update;
+        }
+    }
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
+    file_acb = bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+                               &acb->cur_qiov,
+                               acb->cur_qiov.size / BDRV_SECTOR_SIZE,
+                               next_fn, acb);
+    if (!file_acb) {
+        qed_aio_complete(acb, -EIO);
+    }
+}
+
+/**
+ * Populate back untouched region of new data cluster
+ */
+static void qed_aio_write_postfill(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t start = acb->cur_pos + acb->cur_qiov.size;
+    uint64_t len =
+        qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
+    uint64_t offset = acb->cur_cluster +
+                      qed_offset_into_cluster(s, acb->cur_pos) +
+                      acb->cur_qiov.size;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    trace_qed_aio_write_postfill(s, acb, start, len, offset);
+    qed_copy_from_backing_file(s, start, len, offset,
+                                qed_aio_write_main, acb);
+}
+
+/**
+ * Populate front untouched region of new data cluster
+ */
+static void qed_aio_write_prefill(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t start = qed_start_of_cluster(s, acb->cur_pos);
+    uint64_t len = qed_offset_into_cluster(s, acb->cur_pos);
+
+    trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
+    qed_copy_from_backing_file(s, start, len, acb->cur_cluster,
+                                qed_aio_write_postfill, acb);
+}
+
+/**
+ * Check if the QED_F_NEED_CHECK bit should be set during allocating write
+ */
+static bool qed_should_set_need_check(BDRVQEDState *s)
+{
+    /* The flush before L2 update path ensures consistency */
+    if (s->bs->backing_hd) {
+        return false;
+    }
+
+    return !(s->header.features & QED_F_NEED_CHECK);
+}
+
+/**
+ * Write new data cluster
+ *
+ * @acb:        Write request
+ * @len:        Length in bytes
+ *
+ * This path is taken when writing to previously unallocated clusters.
+ */
+static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
+{
+    BDRVQEDState *s = acb_to_s(acb);
+
+    /* Cancel timer when the first allocating request comes in */
+    if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
+        qed_cancel_need_check_timer(s);
+    }
+
+    /* Freeze this request if another allocating write is in progress */
+    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+        QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);
+    }
+    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
+        s->allocating_write_reqs_plugged) {
+        return; /* wait for existing request to finish */
+    }
+
+    acb->cur_nclusters = qed_bytes_to_clusters(s,
+            qed_offset_into_cluster(s, acb->cur_pos) + len);
+    acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    if (qed_should_set_need_check(s)) {
+        s->header.features |= QED_F_NEED_CHECK;
+        qed_write_header(s, qed_aio_write_prefill, acb);
+    } else {
+        qed_aio_write_prefill(acb, 0);
+    }
+}
+
+/**
+ * Write data cluster in place
+ *
+ * @acb:        Write request
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * This path is taken when writing to already allocated clusters.
+ */
+static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
+{
+    /* Calculate the I/O vector */
+    acb->cur_cluster = offset;
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    /* Do the actual write */
+    qed_aio_write_main(acb, 0);
+}
+
+/**
+ * Write data cluster
+ *
+ * @opaque:     Write request
+ * @ret:        QED_CLUSTER_FOUND, QED_CLUSTER_L2, QED_CLUSTER_L1,
+ *              or -errno
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * Callback from qed_find_cluster().
+ */
+static void qed_aio_write_data(void *opaque, int ret,
+                               uint64_t offset, size_t len)
+{
+    QEDAIOCB *acb = opaque;
+
+    trace_qed_aio_write_data(acb_to_s(acb), acb, ret, offset, len);
+
+    acb->find_cluster_ret = ret;
+
+    switch (ret) {
+    case QED_CLUSTER_FOUND:
+        qed_aio_write_inplace(acb, offset, len);
+        break;
+
+    case QED_CLUSTER_L2:
+    case QED_CLUSTER_L1:
+    case QED_CLUSTER_ZERO:
+        qed_aio_write_alloc(acb, len);
+        break;
+
+    default:
+        qed_aio_complete(acb, ret);
+        break;
+    }
+}
+
+/**
+ * Read data cluster
+ *
+ * @opaque:     Read request
+ * @ret:        QED_CLUSTER_FOUND, QED_CLUSTER_L2, QED_CLUSTER_L1,
+ *              or -errno
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * Callback from qed_find_cluster().
+ */
+static void qed_aio_read_data(void *opaque, int ret,
+                              uint64_t offset, size_t len)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    BlockDriverState *bs = acb->common.bs;
+    BlockDriverAIOCB *file_acb;
+
+    /* Adjust offset into cluster */
+    offset += qed_offset_into_cluster(s, acb->cur_pos);
+
+    trace_qed_aio_read_data(s, acb, ret, offset, len);
+
+    if (ret < 0) {
+        goto err;
+    }
+
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    /* Handle zero cluster and backing file reads */
+    if (ret == QED_CLUSTER_ZERO) {
+        qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size);
+        qed_aio_next_io(acb, 0);
+        return;
+    } else if (ret != QED_CLUSTER_FOUND) {
+        qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
+                              qed_aio_next_io, acb);
+        return;
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+    file_acb = bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
+                              &acb->cur_qiov,
+                              acb->cur_qiov.size / BDRV_SECTOR_SIZE,
+                              qed_aio_next_io, acb);
+    if (!file_acb) {
+        ret = -EIO;
+        goto err;
+    }
+    return;
+
+err:
+    qed_aio_complete(acb, ret);
+}
+
+/**
+ * Begin next I/O or complete the request
+ */
+static void qed_aio_next_io(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    QEDFindClusterFunc *io_fn =
+        acb->is_write ? qed_aio_write_data : qed_aio_read_data;
+
+    trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
+
+    /* Handle I/O error */
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    acb->qiov_offset += acb->cur_qiov.size;
+    acb->cur_pos += acb->cur_qiov.size;
+    qemu_iovec_reset(&acb->cur_qiov);
+
+    /* Complete request */
+    if (acb->cur_pos >= acb->end_pos) {
+        qed_aio_complete(acb, 0);
+        return;
+    }
+
+    /* Find next cluster and start I/O */
+    qed_find_cluster(s, &acb->request,
+                      acb->cur_pos, acb->end_pos - acb->cur_pos,
+                      io_fn, acb);
+}
+
+static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
+                                       int64_t sector_num,
+                                       QEMUIOVector *qiov, int nb_sectors,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque, bool is_write)
+{
+    QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
+
+    trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
+                         opaque, is_write);
+
+    acb->is_write = is_write;
+    acb->finished = NULL;
+    acb->qiov = qiov;
+    acb->qiov_offset = 0;
+    acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
+    acb->end_pos = acb->cur_pos + nb_sectors * BDRV_SECTOR_SIZE;
+    acb->request.l2_table = NULL;
+    qemu_iovec_init(&acb->cur_qiov, qiov->niov);
+
+    /* Start request */
+    qed_aio_next_io(acb, 0);
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov, int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
+{
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, false);
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             QEMUIOVector *qiov, int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, true);
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
+{
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVQEDState *s = bs->opaque;
+    uint64_t old_image_size;
+    int ret;
+
+    if (!qed_is_image_size_valid(offset, s->header.cluster_size,
+                                 s->header.table_size)) {
+        return -EINVAL;
+    }
+
+    /* Shrinking is currently not supported */
+    if ((uint64_t)offset < s->header.image_size) {
+        return -ENOTSUP;
+    }
+
+    old_image_size = s->header.image_size;
+    s->header.image_size = offset;
+    ret = qed_write_header_sync(s);
+    if (ret < 0) {
+        s->header.image_size = old_image_size;
+    }
+    return ret;
+}
+
+static int64_t bdrv_qed_getlength(BlockDriverState *bs)
+{
+    BDRVQEDState *s = bs->opaque;
+    return s->header.image_size;
+}
+
+static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQEDState *s = bs->opaque;
+
+    memset(bdi, 0, sizeof(*bdi));
+    bdi->cluster_size = s->header.cluster_size;
+    return 0;
+}
+
+static int bdrv_qed_change_backing_file(BlockDriverState *bs,
+                                        const char *backing_file,
+                                        const char *backing_fmt)
+{
+    BDRVQEDState *s = bs->opaque;
+    QEDHeader new_header, le_header;
+    void *buffer;
+    size_t buffer_len, backing_file_len;
+    int ret;
+
+    /* Refuse to set backing filename if unknown compat feature bits are
+     * active.  If the image uses an unknown compat feature then we may not
+     * know the layout of data following the header structure and cannot safely
+     * add a new string.
+     */
+    if (backing_file && (s->header.compat_features &
+                         ~QED_COMPAT_FEATURE_MASK)) {
+        return -ENOTSUP;
+    }
+
+    memcpy(&new_header, &s->header, sizeof(new_header));
+
+    new_header.features &= ~(QED_F_BACKING_FILE |
+                             QED_F_BACKING_FORMAT_NO_PROBE);
+
+    /* Adjust feature flags */
+    if (backing_file) {
+        new_header.features |= QED_F_BACKING_FILE;
+
+        if (qed_fmt_is_raw(backing_fmt)) {
+            new_header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
+        }
+    }
+
+    /* Calculate new header size */
+    backing_file_len = 0;
+
+    if (backing_file) {
+        backing_file_len = strlen(backing_file);
+    }
+
+    buffer_len = sizeof(new_header);
+    new_header.backing_filename_offset = buffer_len;
+    new_header.backing_filename_size = backing_file_len;
+    buffer_len += backing_file_len;
+
+    /* Make sure we can rewrite header without failing */
+    if (buffer_len > new_header.header_size * new_header.cluster_size) {
+        return -ENOSPC;
+    }
+
+    /* Prepare new header */
+    buffer = qemu_malloc(buffer_len);
+
+    qed_header_cpu_to_le(&new_header, &le_header);
+    memcpy(buffer, &le_header, sizeof(le_header));
+    buffer_len = sizeof(le_header);
+
+    memcpy(buffer + buffer_len, backing_file, backing_file_len);
+    buffer_len += backing_file_len;
+
+    /* Write new header */
+    ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
+    qemu_free(buffer);
+    if (ret == 0) {
+        memcpy(&s->header, &new_header, sizeof(new_header));
+    }
+    return ret;
+}
+
+static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result)
+{
+    BDRVQEDState *s = bs->opaque;
+
+    return qed_check(s, result, false);
+}
+
+static QEMUOptionParameter qed_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size (in bytes)"
+    }, {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    }, {
+        .name = BLOCK_OPT_BACKING_FMT,
+        .type = OPT_STRING,
+        .help = "Image format of the base image"
+    }, {
+        .name = BLOCK_OPT_CLUSTER_SIZE,
+        .type = OPT_SIZE,
+        .help = "Cluster size (in bytes)",
+        .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
+    }, {
+        .name = BLOCK_OPT_TABLE_SIZE,
+        .type = OPT_SIZE,
+        .help = "L1/L2 table size (in clusters)"
+    },
+    { /* end of list */ }
+};
+
+static BlockDriver bdrv_qed = {
+    .format_name              = "qed",
+    .instance_size            = sizeof(BDRVQEDState),
+    .create_options           = qed_create_options,
+
+    .bdrv_probe               = bdrv_qed_probe,
+    .bdrv_open                = bdrv_qed_open,
+    .bdrv_close               = bdrv_qed_close,
+    .bdrv_create              = bdrv_qed_create,
+    .bdrv_flush               = bdrv_qed_flush,
+    .bdrv_is_allocated        = bdrv_qed_is_allocated,
+    .bdrv_make_empty          = bdrv_qed_make_empty,
+    .bdrv_aio_readv           = bdrv_qed_aio_readv,
+    .bdrv_aio_writev          = bdrv_qed_aio_writev,
+    .bdrv_aio_flush           = bdrv_qed_aio_flush,
+    .bdrv_truncate            = bdrv_qed_truncate,
+    .bdrv_getlength           = bdrv_qed_getlength,
+    .bdrv_get_info            = bdrv_qed_get_info,
+    .bdrv_change_backing_file = bdrv_qed_change_backing_file,
+    .bdrv_check               = bdrv_qed_check,
+};
+
+static void bdrv_qed_init(void)
+{
+    bdrv_register(&bdrv_qed);
+}
+
+block_init(bdrv_qed_init);
diff --git a/qemu-0.15.x/block/qed.h b/qemu-0.15.x/block/qed.h
new file mode 100644
index 0000000..388fdb3
--- /dev/null
+++ b/qemu-0.15.x/block/qed.h
@@ -0,0 +1,334 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef BLOCK_QED_H
+#define BLOCK_QED_H
+
+#include "block_int.h"
+
+/* The layout of a QED file is as follows:
+ *
+ * +--------+----------+----------+----------+-----+
+ * | header | L1 table | cluster0 | cluster1 | ... |
+ * +--------+----------+----------+----------+-----+
+ *
+ * There is a 2-level pagetable for cluster allocation:
+ *
+ *                     +----------+
+ *                     | L1 table |
+ *                     +----------+
+ *                ,------'  |  '------.
+ *           +----------+   |    +----------+
+ *           | L2 table |  ...   | L2 table |
+ *           +----------+        +----------+
+ *       ,------'  |  '------.
+ *  +----------+   |    +----------+
+ *  |   Data   |  ...   |   Data   |
+ *  +----------+        +----------+
+ *
+ * The L1 table is fixed size and always present.  L2 tables are allocated on
+ * demand.  The L1 table size determines the maximum possible image size; it
+ * can be influenced using the cluster_size and table_size values.
+ *
+ * All fields are little-endian on disk.
+ */
+
+enum {
+    QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
+
+    /* The image supports a backing file */
+    QED_F_BACKING_FILE = 0x01,
+
+    /* The image needs a consistency check before use */
+    QED_F_NEED_CHECK = 0x02,
+
+    /* The backing file format must not be probed, treat as raw image */
+    QED_F_BACKING_FORMAT_NO_PROBE = 0x04,
+
+    /* Feature bits must be used when the on-disk format changes */
+    QED_FEATURE_MASK = QED_F_BACKING_FILE | /* supported feature bits */
+                       QED_F_NEED_CHECK |
+                       QED_F_BACKING_FORMAT_NO_PROBE,
+    QED_COMPAT_FEATURE_MASK = 0,            /* supported compat feature bits */
+    QED_AUTOCLEAR_FEATURE_MASK = 0,         /* supported autoclear feature bits */
+
+    /* Data is stored in groups of sectors called clusters.  Cluster size must
+     * be large to avoid keeping too much metadata.  I/O requests that have
+     * sub-cluster size will require read-modify-write.
+     */
+    QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
+    QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
+    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
+
+    /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
+     * a multiple of clusters so large maximum image sizes can be supported
+     * without jacking up the cluster size too much.
+     */
+    QED_MIN_TABLE_SIZE = 1,        /* in clusters */
+    QED_MAX_TABLE_SIZE = 16,
+    QED_DEFAULT_TABLE_SIZE = 4,
+
+    /* Delay to flush and clean image after last allocating write completes */
+    QED_NEED_CHECK_TIMEOUT = 5,    /* in seconds */
+};
+
+typedef struct {
+    uint32_t magic;                 /* QED\0 */
+
+    uint32_t cluster_size;          /* in bytes */
+    uint32_t table_size;            /* for L1 and L2 tables, in clusters */
+    uint32_t header_size;           /* in clusters */
+
+    uint64_t features;              /* format feature bits */
+    uint64_t compat_features;       /* compatible feature bits */
+    uint64_t autoclear_features;    /* self-resetting feature bits */
+
+    uint64_t l1_table_offset;       /* in bytes */
+    uint64_t image_size;            /* total logical image size, in bytes */
+
+    /* if (features & QED_F_BACKING_FILE) */
+    uint32_t backing_filename_offset; /* in bytes from start of header */
+    uint32_t backing_filename_size;   /* in bytes */
+} QEDHeader;
+
+typedef struct {
+    uint64_t offsets[0];            /* in bytes */
+} QEDTable;
+
+/* The L2 cache is a simple write-through cache for L2 structures */
+typedef struct CachedL2Table {
+    QEDTable *table;
+    uint64_t offset;    /* offset=0 indicates an invalidate entry */
+    QTAILQ_ENTRY(CachedL2Table) node;
+    int ref;
+} CachedL2Table;
+
+typedef struct {
+    QTAILQ_HEAD(, CachedL2Table) entries;
+    unsigned int n_entries;
+} L2TableCache;
+
+typedef struct QEDRequest {
+    CachedL2Table *l2_table;
+} QEDRequest;
+
+typedef struct QEDAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int bh_ret;                     /* final return status for completion bh */
+    QSIMPLEQ_ENTRY(QEDAIOCB) next;  /* next request */
+    bool is_write;                  /* false - read, true - write */
+    bool *finished;                 /* signal for cancel completion */
+    uint64_t end_pos;               /* request end on block device, in bytes */
+
+    /* User scatter-gather list */
+    QEMUIOVector *qiov;
+    size_t qiov_offset;             /* byte count already processed */
+
+    /* Current cluster scatter-gather list */
+    QEMUIOVector cur_qiov;
+    uint64_t cur_pos;               /* position on block device, in bytes */
+    uint64_t cur_cluster;           /* cluster offset in image file */
+    unsigned int cur_nclusters;     /* number of clusters being accessed */
+    int find_cluster_ret;           /* used for L1/L2 update */
+
+    QEDRequest request;
+} QEDAIOCB;
+
+typedef struct {
+    BlockDriverState *bs;           /* device */
+    uint64_t file_size;             /* length of image file, in bytes */
+
+    QEDHeader header;               /* always cpu-endian */
+    QEDTable *l1_table;
+    L2TableCache l2_cache;          /* l2 table cache */
+    uint32_t table_nelems;
+    uint32_t l1_shift;
+    uint32_t l2_shift;
+    uint32_t l2_mask;
+
+    /* Allocating write request queue */
+    QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
+    bool allocating_write_reqs_plugged;
+
+    /* Periodic flush and clear need check flag */
+    QEMUTimer *need_check_timer;
+} BDRVQEDState;
+
+enum {
+    QED_CLUSTER_FOUND,         /* cluster found */
+    QED_CLUSTER_ZERO,          /* zero cluster found */
+    QED_CLUSTER_L2,            /* cluster missing in L2 */
+    QED_CLUSTER_L1,            /* cluster missing in L1 */
+};
+
+/**
+ * qed_find_cluster() completion callback
+ *
+ * @opaque:     User data for completion callback
+ * @ret:        QED_CLUSTER_FOUND   Success
+ *              QED_CLUSTER_L2      Data cluster unallocated in L2
+ *              QED_CLUSTER_L1      L2 unallocated in L1
+ *              -errno              POSIX error occurred
+ * @offset:     Data cluster offset
+ * @len:        Contiguous bytes starting from cluster offset
+ *
+ * This function is invoked when qed_find_cluster() completes.
+ *
+ * On success ret is QED_CLUSTER_FOUND and offset/len are a contiguous range
+ * in the image file.
+ *
+ * On failure ret is QED_CLUSTER_L2 or QED_CLUSTER_L1 for missing L2 or L1
+ * table offset, respectively.  len is number of contiguous unallocated bytes.
+ */
+typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
+
+/**
+ * Generic callback for chaining async callbacks
+ */
+typedef struct {
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+} GenericCB;
+
+void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
+void gencb_complete(void *opaque, int ret);
+
+/**
+ * L2 cache functions
+ */
+void qed_init_l2_cache(L2TableCache *l2_cache);
+void qed_free_l2_cache(L2TableCache *l2_cache);
+CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache);
+void qed_unref_l2_cache_entry(CachedL2Table *entry);
+CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset);
+void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
+
+/**
+ * Table I/O functions
+ */
+int qed_read_l1_table_sync(BDRVQEDState *s);
+void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
+                        BlockDriverCompletionFunc *cb, void *opaque);
+int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
+                            unsigned int n);
+int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                           uint64_t offset);
+void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
+                       BlockDriverCompletionFunc *cb, void *opaque);
+void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
+                        unsigned int index, unsigned int n, bool flush,
+                        BlockDriverCompletionFunc *cb, void *opaque);
+int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                            unsigned int index, unsigned int n, bool flush);
+
+/**
+ * Cluster functions
+ */
+void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
+                      size_t len, QEDFindClusterFunc *cb, void *opaque);
+
+/**
+ * Consistency check
+ */
+int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
+
+QEDTable *qed_alloc_table(BDRVQEDState *s);
+
+/**
+ * Round down to the start of a cluster
+ */
+static inline uint64_t qed_start_of_cluster(BDRVQEDState *s, uint64_t offset)
+{
+    return offset & ~(uint64_t)(s->header.cluster_size - 1);
+}
+
+static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
+{
+    return offset & (s->header.cluster_size - 1);
+}
+
+static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes)
+{
+    return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
+           (s->header.cluster_size - 1);
+}
+
+static inline unsigned int qed_l1_index(BDRVQEDState *s, uint64_t pos)
+{
+    return pos >> s->l1_shift;
+}
+
+static inline unsigned int qed_l2_index(BDRVQEDState *s, uint64_t pos)
+{
+    return (pos >> s->l2_shift) & s->l2_mask;
+}
+
+/**
+ * Test if a cluster offset is valid
+ */
+static inline bool qed_check_cluster_offset(BDRVQEDState *s, uint64_t offset)
+{
+    uint64_t header_size = (uint64_t)s->header.header_size *
+                           s->header.cluster_size;
+
+    if (offset & (s->header.cluster_size - 1)) {
+        return false;
+    }
+    return offset >= header_size && offset < s->file_size;
+}
+
+/**
+ * Test if a table offset is valid
+ */
+static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
+{
+    uint64_t end_offset = offset + (s->header.table_size - 1) *
+                          s->header.cluster_size;
+
+    /* Overflow check */
+    if (end_offset <= offset) {
+        return false;
+    }
+
+    return qed_check_cluster_offset(s, offset) &&
+           qed_check_cluster_offset(s, end_offset);
+}
+
+static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s,
+                                                 uint64_t offset)
+{
+    if (qed_offset_into_cluster(s, offset)) {
+        return false;
+    }
+    return true;
+}
+
+static inline bool qed_offset_is_unalloc_cluster(uint64_t offset)
+{
+    if (offset == 0) {
+        return true;
+    }
+    return false;
+}
+
+static inline bool qed_offset_is_zero_cluster(uint64_t offset)
+{
+    if (offset == 1) {
+        return true;
+    }
+    return false;
+}
+
+#endif /* BLOCK_QED_H */
diff --git a/qemu-0.15.x/block/raw-posix-aio.h b/qemu-0.15.x/block/raw-posix-aio.h
new file mode 100644
index 0000000..dfc63b8
--- /dev/null
+++ b/qemu-0.15.x/block/raw-posix-aio.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU Posix block I/O backend AIO support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_RAW_POSIX_AIO_H
+#define QEMU_RAW_POSIX_AIO_H
+
+/* AIO request types */
+#define QEMU_AIO_READ         0x0001
+#define QEMU_AIO_WRITE        0x0002
+#define QEMU_AIO_IOCTL        0x0004
+#define QEMU_AIO_FLUSH        0x0008
+#define QEMU_AIO_TYPE_MASK \
+	(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH)
+
+/* AIO flags */
+#define QEMU_AIO_MISALIGNED   0x1000
+
+
+/* posix-aio-compat.c - thread pool based implementation */
+int paio_init(void);
+BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type);
+BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+/* linux-aio.c - Linux native implementation */
+void *laio_init(void);
+BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type);
+
+#endif /* QEMU_RAW_POSIX_AIO_H */
diff --git a/qemu-0.15.x/block/raw-posix.c b/qemu-0.15.x/block/raw-posix.c
new file mode 100644
index 0000000..cd89c83
--- /dev/null
+++ b/qemu-0.15.x/block/raw-posix.c
@@ -0,0 +1,1552 @@
+/*
+ * Block driver for RAW files (posix)
+ *
+ * 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "block_int.h"
+#include "module.h"
+#include "block/raw-posix-aio.h"
+
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <sys/dkio.h>
+#endif
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#endif
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/disk.h>
+#include <sys/cdio.h>
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#endif
+
+#ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/disk.h>
+#endif
+
+#ifdef __DragonFly__
+#include <sys/ioctl.h>
+#include <sys/diskslice.h>
+#endif
+
+#ifdef CONFIG_XFS
+#include <xfs/xfs.h>
+#endif
+
+//#define DEBUG_FLOPPY
+
+//#define DEBUG_BLOCK
+#if defined(DEBUG_BLOCK)
+#define DEBUG_BLOCK_PRINT(formatCstr, ...) do { if (qemu_log_enabled()) \
+    { qemu_log(formatCstr, ## __VA_ARGS__); qemu_log_flush(); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, ...)
+#endif
+
+/* OS X does not have O_DSYNC */
+#ifndef O_DSYNC
+#ifdef O_SYNC
+#define O_DSYNC O_SYNC
+#elif defined(O_FSYNC)
+#define O_DSYNC O_FSYNC
+#endif
+#endif
+
+/* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */
+#ifndef O_DIRECT
+#define O_DIRECT O_DSYNC
+#endif
+
+#define FTYPE_FILE   0
+#define FTYPE_CD     1
+#define FTYPE_FD     2
+
+/* if the FD is not accessed during that time (in ns), we try to
+   reopen it to see if the disk has been changed */
+#define FD_OPEN_TIMEOUT (1000000000)
+
+#define MAX_BLOCKSIZE	4096
+
+typedef struct BDRVRawState {
+    int fd;
+    int type;
+    int open_flags;
+#if defined(__linux__)
+    /* linux floppy specific */
+    int64_t fd_open_time;
+    int64_t fd_error_time;
+    int fd_got_error;
+    int fd_media_changed;
+#endif
+#ifdef CONFIG_LINUX_AIO
+    int use_aio;
+    void *aio_ctx;
+#endif
+    uint8_t *aligned_buf;
+    unsigned aligned_buf_size;
+#ifdef CONFIG_XFS
+    bool is_xfs : 1;
+#endif
+} BDRVRawState;
+
+static int fd_open(BlockDriverState *bs);
+static int64_t raw_getlength(BlockDriverState *bs);
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static int cdrom_reopen(BlockDriverState *bs);
+#endif
+
+#if defined(__NetBSD__)
+static int raw_normalize_devicepath(const char **filename)
+{
+    static char namebuf[PATH_MAX];
+    const char *dp, *fname;
+    struct stat sb;
+
+    fname = *filename;
+    dp = strrchr(fname, '/');
+    if (lstat(fname, &sb) < 0) {
+        fprintf(stderr, "%s: stat failed: %s\n",
+            fname, strerror(errno));
+        return -errno;
+    }
+
+    if (!S_ISBLK(sb.st_mode)) {
+        return 0;
+    }
+
+    if (dp == NULL) {
+        snprintf(namebuf, PATH_MAX, "r%s", fname);
+    } else {
+        snprintf(namebuf, PATH_MAX, "%.*s/r%s",
+            (int)(dp - fname), fname, dp + 1);
+    }
+    fprintf(stderr, "%s is a block device", fname);
+    *filename = namebuf;
+    fprintf(stderr, ", using %s\n", *filename);
+
+    return 0;
+}
+#else
+static int raw_normalize_devicepath(const char **filename)
+{
+    return 0;
+}
+#endif
+
+static int raw_open_common(BlockDriverState *bs, const char *filename,
+                           int bdrv_flags, int open_flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd, ret;
+
+    ret = raw_normalize_devicepath(&filename);
+    if (ret != 0) {
+        return ret;
+    }
+
+    s->open_flags = open_flags | O_BINARY;
+    s->open_flags &= ~O_ACCMODE;
+    if (bdrv_flags & BDRV_O_RDWR) {
+        s->open_flags |= O_RDWR;
+    } else {
+        s->open_flags |= O_RDONLY;
+    }
+
+    /* Use O_DSYNC for write-through caching, no flags for write-back caching,
+     * and O_DIRECT for no caching. */
+    if ((bdrv_flags & BDRV_O_NOCACHE))
+        s->open_flags |= O_DIRECT;
+    if (!(bdrv_flags & BDRV_O_CACHE_WB))
+        s->open_flags |= O_DSYNC;
+
+    s->fd = -1;
+    fd = qemu_open(filename, s->open_flags, 0644);
+    if (fd < 0) {
+        ret = -errno;
+        if (ret == -EROFS)
+            ret = -EACCES;
+        return ret;
+    }
+    s->fd = fd;
+    s->aligned_buf = NULL;
+
+    if ((bdrv_flags & BDRV_O_NOCACHE)) {
+        /*
+         * Allocate a buffer for read/modify/write cycles.  Chose the size
+         * pessimistically as we don't know the block size yet.
+         */
+        s->aligned_buf_size = 32 * MAX_BLOCKSIZE;
+        s->aligned_buf = qemu_memalign(MAX_BLOCKSIZE, s->aligned_buf_size);
+        if (s->aligned_buf == NULL) {
+            goto out_close;
+        }
+    }
+
+#ifdef CONFIG_LINUX_AIO
+    if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
+                      (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
+
+        /* We're falling back to POSIX AIO in some cases */
+        paio_init();
+
+        s->aio_ctx = laio_init();
+        if (!s->aio_ctx) {
+            goto out_free_buf;
+        }
+        s->use_aio = 1;
+    } else
+#endif
+    {
+        if (paio_init() < 0) {
+            goto out_free_buf;
+        }
+#ifdef CONFIG_LINUX_AIO
+        s->use_aio = 0;
+#endif
+    }
+
+#ifdef CONFIG_XFS
+    if (platform_test_xfs_fd(s->fd)) {
+        s->is_xfs = 1;
+    }
+#endif
+
+    return 0;
+
+out_free_buf:
+    qemu_vfree(s->aligned_buf);
+out_close:
+    close(fd);
+    return -errno;
+}
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+
+    s->type = FTYPE_FILE;
+    return raw_open_common(bs, filename, flags, 0);
+}
+
+/* XXX: use host sector size if necessary with:
+#ifdef DIOCGSECTORSIZE
+        {
+            unsigned int sectorsize = 512;
+            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
+                sectorsize > bufsize)
+                bufsize = sectorsize;
+        }
+#endif
+#ifdef CONFIG_COCOA
+        uint32_t blockSize = 512;
+        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
+            bufsize = blockSize;
+        }
+#endif
+*/
+
+/*
+ * offset and count are in bytes, but must be multiples of 512 for files
+ * opened with O_DIRECT. buf must be aligned to 512 bytes then.
+ *
+ * This function may be called without alignment if the caller ensures
+ * that O_DIRECT is not in effect.
+ */
+static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+    ret = pread(s->fd, buf, count, offset);
+    if (ret == count)
+        return ret;
+
+    /* Allow reads beyond the end (needed for pwrite) */
+    if ((ret == 0) && bs->growable) {
+        int64_t size = raw_getlength(bs);
+        if (offset >= size) {
+            memset(buf, 0, count);
+            return count;
+        }
+    }
+
+    DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] read failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+    /* Try harder for CDrom. */
+    if (s->type != FTYPE_FILE) {
+        ret = pread(s->fd, buf, count, offset);
+        if (ret == count)
+            return ret;
+        ret = pread(s->fd, buf, count, offset);
+        if (ret == count)
+            return ret;
+
+        DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                          "] retry read failed %d : %d = %s\n",
+                          s->fd, bs->filename, offset, buf, count,
+                          bs->total_sectors, ret, errno, strerror(errno));
+    }
+
+    return  (ret < 0) ? -errno : ret;
+}
+
+/*
+ * offset and count are in bytes, but must be multiples of the sector size
+ * for files opened with O_DIRECT. buf must be aligned to sector size bytes
+ * then.
+ *
+ * This function may be called without alignment if the caller ensures
+ * that O_DIRECT is not in effect.
+ */
+static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return -errno;
+
+    ret = pwrite(s->fd, buf, count, offset);
+    if (ret == count)
+        return ret;
+
+    DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] write failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+    return  (ret < 0) ? -errno : ret;
+}
+
+
+/*
+ * offset and count are in bytes and possibly not aligned. For files opened
+ * with O_DIRECT, necessary alignments are ensured before calling
+ * raw_pread_aligned to do the actual read.
+ */
+static int raw_pread(BlockDriverState *bs, int64_t offset,
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    unsigned sector_mask = bs->buffer_alignment - 1;
+    int size, ret, shift, sum;
+
+    sum = 0;
+
+    if (s->aligned_buf != NULL)  {
+
+        if (offset & sector_mask) {
+            /* align offset on a sector size bytes boundary */
+
+            shift = offset & sector_mask;
+            size = (shift + count + sector_mask) & ~sector_mask;
+            if (size > s->aligned_buf_size)
+                size = s->aligned_buf_size;
+            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size);
+            if (ret < 0)
+                return ret;
+
+            size = bs->buffer_alignment - shift;
+            if (size > count)
+                size = count;
+            memcpy(buf, s->aligned_buf + shift, size);
+
+            buf += size;
+            offset += size;
+            count -= size;
+            sum += size;
+
+            if (count == 0)
+                return sum;
+        }
+        if (count & sector_mask || (uintptr_t) buf & sector_mask) {
+
+            /* read on aligned buffer */
+
+            while (count) {
+
+                size = (count + sector_mask) & ~sector_mask;
+                if (size > s->aligned_buf_size)
+                    size = s->aligned_buf_size;
+
+                ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
+                if (ret < 0) {
+                    return ret;
+                } else if (ret == 0) {
+                    fprintf(stderr, "raw_pread: read beyond end of file\n");
+                    abort();
+                }
+
+                size = ret;
+                if (size > count)
+                    size = count;
+
+                memcpy(buf, s->aligned_buf, size);
+
+                buf += size;
+                offset += size;
+                count -= size;
+                sum += size;
+            }
+
+            return sum;
+        }
+    }
+
+    return raw_pread_aligned(bs, offset, buf, count) + sum;
+}
+
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+
+    ret = raw_pread(bs, sector_num * BDRV_SECTOR_SIZE, buf,
+                    nb_sectors * BDRV_SECTOR_SIZE);
+    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
+        ret = 0;
+    return ret;
+}
+
+/*
+ * offset and count are in bytes and possibly not aligned. For files opened
+ * with O_DIRECT, necessary alignments are ensured before calling
+ * raw_pwrite_aligned to do the actual write.
+ */
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    unsigned sector_mask = bs->buffer_alignment - 1;
+    int size, ret, shift, sum;
+
+    sum = 0;
+
+    if (s->aligned_buf != NULL) {
+
+        if (offset & sector_mask) {
+            /* align offset on a sector size bytes boundary */
+            shift = offset & sector_mask;
+            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf,
+                                    bs->buffer_alignment);
+            if (ret < 0)
+                return ret;
+
+            size = bs->buffer_alignment - shift;
+            if (size > count)
+                size = count;
+            memcpy(s->aligned_buf + shift, buf, size);
+
+            ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf,
+                                     bs->buffer_alignment);
+            if (ret < 0)
+                return ret;
+
+            buf += size;
+            offset += size;
+            count -= size;
+            sum += size;
+
+            if (count == 0)
+                return sum;
+        }
+        if (count & sector_mask || (uintptr_t) buf & sector_mask) {
+
+            while ((size = (count & ~sector_mask)) != 0) {
+
+                if (size > s->aligned_buf_size)
+                    size = s->aligned_buf_size;
+
+                memcpy(s->aligned_buf, buf, size);
+
+                ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size);
+                if (ret < 0)
+                    return ret;
+
+                buf += ret;
+                offset += ret;
+                count -= ret;
+                sum += ret;
+            }
+            /* here, count < sector_size because (count & ~sector_mask) == 0 */
+            if (count) {
+                ret = raw_pread_aligned(bs, offset, s->aligned_buf,
+                                     bs->buffer_alignment);
+                if (ret < 0)
+                    return ret;
+                 memcpy(s->aligned_buf, buf, count);
+
+                 ret = raw_pwrite_aligned(bs, offset, s->aligned_buf,
+                                     bs->buffer_alignment);
+                 if (ret < 0)
+                     return ret;
+                 if (count < ret)
+                     ret = count;
+
+                 sum += ret;
+            }
+            return sum;
+        }
+    }
+    return raw_pwrite_aligned(bs, offset, buf, count) + sum;
+}
+
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    ret = raw_pwrite(bs, sector_num * BDRV_SECTOR_SIZE, buf,
+                     nb_sectors * BDRV_SECTOR_SIZE);
+    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
+        ret = 0;
+    return ret;
+}
+
+/*
+ * Check if all memory in this vector is sector aligned.
+ */
+static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
+{
+    int i;
+
+    for (i = 0; i < qiov->niov; i++) {
+        if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    /*
+     * If O_DIRECT is used the buffer needs to be aligned on a sector
+     * boundary.  Check if this is the case or telll the low-level
+     * driver that it needs to copy the buffer.
+     */
+    if (s->aligned_buf) {
+        if (!qiov_is_aligned(bs, qiov)) {
+            type |= QEMU_AIO_MISALIGNED;
+#ifdef CONFIG_LINUX_AIO
+        } else if (s->use_aio) {
+            return laio_submit(bs, s->aio_ctx, s->fd, sector_num, qiov,
+                               nb_sectors, cb, opaque, type);
+#endif
+        }
+    }
+
+    return paio_submit(bs, s->fd, sector_num, qiov, nb_sectors,
+                       cb, opaque, type);
+}
+
+static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
+                          cb, opaque, QEMU_AIO_READ);
+}
+
+static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
+                          cb, opaque, QEMU_AIO_WRITE);
+}
+
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+        if (s->aligned_buf != NULL)
+            qemu_vfree(s->aligned_buf);
+    }
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRawState *s = bs->opaque;
+    if (s->type != FTYPE_FILE)
+        return -ENOTSUP;
+    if (ftruncate(s->fd, offset) < 0)
+        return -errno;
+    return 0;
+}
+
+#ifdef __OpenBSD__
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    struct stat st;
+
+    if (fstat(fd, &st))
+        return -1;
+    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+        struct disklabel dl;
+
+        if (ioctl(fd, DIOCGDINFO, &dl))
+            return -1;
+        return (uint64_t)dl.d_secsize *
+            dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+    } else
+        return st.st_size;
+}
+#elif defined(__NetBSD__)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    struct stat st;
+
+    if (fstat(fd, &st))
+        return -1;
+    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+        struct dkwedge_info dkw;
+
+        if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) {
+            return dkw.dkw_size * 512;
+        } else {
+            struct disklabel dl;
+
+            if (ioctl(fd, DIOCGDINFO, &dl))
+                return -1;
+            return (uint64_t)dl.d_secsize *
+                dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+        }
+    } else
+        return st.st_size;
+}
+#elif defined(__sun__)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    struct dk_minfo minfo;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /*
+     * Use the DKIOCGMEDIAINFO ioctl to read the size.
+     */
+    ret = ioctl(s->fd, DKIOCGMEDIAINFO, &minfo);
+    if (ret != -1) {
+        return minfo.dki_lbsize * minfo.dki_capacity;
+    }
+
+    /*
+     * There are reports that lseek on some devices fails, but
+     * irc discussion said that contingency on contingency was overkill.
+     */
+    return lseek(s->fd, 0, SEEK_END);
+}
+#elif defined(CONFIG_BSD)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    int64_t size;
+    struct stat sb;
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
+    int reopened = 0;
+#endif
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
+again:
+#endif
+    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#elif defined(DIOCGPART)
+        {
+                struct partinfo pi;
+                if (ioctl(fd, DIOCGPART, &pi) == 0)
+                        size = pi.media_size;
+                else
+                        size = 0;
+        }
+        if (size == 0)
+#endif
+#ifdef CONFIG_COCOA
+        size = LONG_LONG_MAX;
+#else
+        size = lseek(fd, 0LL, SEEK_END);
+#endif
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+        switch(s->type) {
+        case FTYPE_CD:
+            /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
+            if (size == 2048LL * (unsigned)-1)
+                size = 0;
+            /* XXX no disc?  maybe we need to reopen... */
+            if (size <= 0 && !reopened && cdrom_reopen(bs) >= 0) {
+                reopened = 1;
+                goto again;
+            }
+        }
+#endif
+    } else {
+        size = lseek(fd, 0, SEEK_END);
+    }
+    return size;
+}
+#else
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return lseek(s->fd, 0, SEEK_END);
+}
+#endif
+
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    struct stat st;
+    BDRVRawState *s = bs->opaque;
+
+    if (fstat(s->fd, &st) < 0) {
+        return -errno;
+    }
+    return (int64_t)st.st_blocks * 512;
+}
+
+static int raw_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int result = 0;
+    int64_t total_size = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / BDRV_SECTOR_SIZE;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+              0644);
+    if (fd < 0) {
+        result = -errno;
+    } else {
+        if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
+            result = -errno;
+        }
+        if (close(fd) != 0) {
+            result = -errno;
+        }
+    }
+    return result;
+}
+
+static int raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    return qemu_fdatasync(s->fd);
+}
+
+#ifdef CONFIG_XFS
+static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
+{
+    struct xfs_flock64 fl;
+
+    memset(&fl, 0, sizeof(fl));
+    fl.l_whence = SEEK_SET;
+    fl.l_start = sector_num << 9;
+    fl.l_len = (int64_t)nb_sectors << 9;
+
+    if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
+        DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
+        return -errno;
+    }
+
+    return 0;
+}
+#endif
+
+static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+#ifdef CONFIG_XFS
+    BDRVRawState *s = bs->opaque;
+
+    if (s->is_xfs) {
+        return xfs_discard(s, sector_num, nb_sectors);
+    }
+#endif
+
+    return 0;
+}
+
+static QEMUOptionParameter raw_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_file = {
+    .format_name = "file",
+    .protocol_name = "file",
+    .instance_size = sizeof(BDRVRawState),
+    .bdrv_probe = NULL, /* no probe for protocols */
+    .bdrv_file_open = raw_open,
+    .bdrv_read = raw_read,
+    .bdrv_write = raw_write,
+    .bdrv_close = raw_close,
+    .bdrv_create = raw_create,
+    .bdrv_flush = raw_flush,
+    .bdrv_discard = raw_discard,
+
+    .bdrv_aio_readv = raw_aio_readv,
+    .bdrv_aio_writev = raw_aio_writev,
+    .bdrv_aio_flush = raw_aio_flush,
+
+    .bdrv_truncate = raw_truncate,
+    .bdrv_getlength = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    .create_options = raw_create_options,
+};
+
+/***********************************************/
+/* host device */
+
+#ifdef CONFIG_COCOA
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
+static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
+{
+    kern_return_t       kernResult;
+    mach_port_t     masterPort;
+    CFMutableDictionaryRef  classesToMatch;
+
+    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
+    if ( KERN_SUCCESS != kernResult ) {
+        printf( "IOMasterPort returned %d\n", kernResult );
+    }
+
+    classesToMatch = IOServiceMatching( kIOCDMediaClass );
+    if ( classesToMatch == NULL ) {
+        printf( "IOServiceMatching returned a NULL dictionary.\n" );
+    } else {
+    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+    }
+    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
+    if ( KERN_SUCCESS != kernResult )
+    {
+        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
+    }
+
+    return kernResult;
+}
+
+kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
+{
+    io_object_t     nextMedia;
+    kern_return_t   kernResult = KERN_FAILURE;
+    *bsdPath = '\0';
+    nextMedia = IOIteratorNext( mediaIterator );
+    if ( nextMedia )
+    {
+        CFTypeRef   bsdPathAsCFString;
+    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
+        if ( bsdPathAsCFString ) {
+            size_t devPathLength;
+            strcpy( bsdPath, _PATH_DEV );
+            strcat( bsdPath, "r" );
+            devPathLength = strlen( bsdPath );
+            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
+                kernResult = KERN_SUCCESS;
+            }
+            CFRelease( bsdPathAsCFString );
+        }
+        IOObjectRelease( nextMedia );
+    }
+
+    return kernResult;
+}
+
+#endif
+
+static int hdev_probe_device(const char *filename)
+{
+    struct stat st;
+
+    /* allow a dedicated CD-ROM driver to match with a higher priority */
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return 50;
+
+    if (stat(filename, &st) >= 0 &&
+            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+        return 100;
+    }
+
+    return 0;
+}
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+
+#ifdef CONFIG_COCOA
+    if (strstart(filename, "/dev/cdrom", NULL)) {
+        kern_return_t kernResult;
+        io_iterator_t mediaIterator;
+        char bsdPath[ MAXPATHLEN ];
+        int fd;
+
+        kernResult = FindEjectableCDMedia( &mediaIterator );
+        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
+
+        if ( bsdPath[ 0 ] != '\0' ) {
+            strcat(bsdPath,"s0");
+            /* some CDs don't have a partition 0 */
+            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+            if (fd < 0) {
+                bsdPath[strlen(bsdPath)-1] = '1';
+            } else {
+                close(fd);
+            }
+            filename = bsdPath;
+        }
+
+        if ( mediaIterator )
+            IOObjectRelease( mediaIterator );
+    }
+#endif
+
+    s->type = FTYPE_FILE;
+#if defined(__linux__)
+    {
+        char resolved_path[ MAXPATHLEN ], *temp;
+
+        temp = realpath(filename, resolved_path);
+        if (temp && strstart(temp, "/dev/sg", NULL)) {
+            bs->sg = 1;
+        }
+    }
+#endif
+
+    return raw_open_common(bs, filename, flags, 0);
+}
+
+#if defined(__linux__)
+/* Note: we do not have a reliable method to detect if the floppy is
+   present. The current method is to try to open the floppy at every
+   I/O and to keep it opened during a few hundreds of ms. */
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int last_media_present;
+
+    if (s->type != FTYPE_FD)
+        return 0;
+    last_media_present = (s->fd >= 0);
+    if (s->fd >= 0 &&
+        (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
+        close(s->fd);
+        s->fd = -1;
+#ifdef DEBUG_FLOPPY
+        printf("Floppy closed\n");
+#endif
+    }
+    if (s->fd < 0) {
+        if (s->fd_got_error &&
+            (get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
+#ifdef DEBUG_FLOPPY
+            printf("No floppy (open delayed)\n");
+#endif
+            return -EIO;
+        }
+        s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
+        if (s->fd < 0) {
+            s->fd_error_time = get_clock();
+            s->fd_got_error = 1;
+            if (last_media_present)
+                s->fd_media_changed = 1;
+#ifdef DEBUG_FLOPPY
+            printf("No floppy\n");
+#endif
+            return -EIO;
+        }
+#ifdef DEBUG_FLOPPY
+        printf("Floppy opened\n");
+#endif
+    }
+    if (!last_media_present)
+        s->fd_media_changed = 1;
+    s->fd_open_time = get_clock();
+    s->fd_got_error = 0;
+    return 0;
+}
+
+static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+    BDRVRawState *s = bs->opaque;
+
+    return ioctl(s->fd, req, buf);
+}
+
+static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+    return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
+}
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+
+    /* this is just to ensure s->fd is sane (its called by io ops) */
+    if (s->fd >= 0)
+        return 0;
+    return -EIO;
+}
+#else /* !linux && !FreeBSD */
+
+static int fd_open(BlockDriverState *bs)
+{
+    return 0;
+}
+
+#endif /* !linux && !FreeBSD */
+
+static int hdev_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int ret = 0;
+    struct stat stat_buf;
+    int64_t total_size = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_size = options->value.n / BDRV_SECTOR_SIZE;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_BINARY);
+    if (fd < 0)
+        return -errno;
+
+    if (fstat(fd, &stat_buf) < 0)
+        ret = -errno;
+    else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
+        ret = -ENODEV;
+    else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
+        ret = -ENOSPC;
+
+    close(fd);
+    return ret;
+}
+
+static int hdev_has_zero_init(BlockDriverState *bs)
+{
+    return 0;
+}
+
+static BlockDriver bdrv_host_device = {
+    .format_name        = "host_device",
+    .protocol_name        = "host_device",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device  = hdev_probe_device,
+    .bdrv_file_open     = hdev_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .bdrv_has_zero_init = hdev_has_zero_init,
+    .bdrv_flush         = raw_flush,
+
+    .bdrv_aio_readv	= raw_aio_readv,
+    .bdrv_aio_writev	= raw_aio_writev,
+    .bdrv_aio_flush	= raw_aio_flush,
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength	= raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    /* generic scsi device */
+#ifdef __linux__
+    .bdrv_ioctl         = hdev_ioctl,
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+#endif
+};
+
+#ifdef __linux__
+static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    s->type = FTYPE_FD;
+
+    /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
+    ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
+    if (ret)
+        return ret;
+
+    /* close fd so that we can reopen it as needed */
+    close(s->fd);
+    s->fd = -1;
+    s->fd_media_changed = 1;
+
+    return 0;
+}
+
+static int floppy_probe_device(const char *filename)
+{
+    int fd, ret;
+    int prio = 0;
+    struct floppy_struct fdparam;
+    struct stat st;
+
+    if (strstart(filename, "/dev/fd", NULL))
+        prio = 50;
+
+    fd = open(filename, O_RDONLY | O_NONBLOCK);
+    if (fd < 0) {
+        goto out;
+    }
+    ret = fstat(fd, &st);
+    if (ret == -1 || !S_ISBLK(st.st_mode)) {
+        goto outc;
+    }
+
+    /* Attempt to detect via a floppy specific ioctl */
+    ret = ioctl(fd, FDGETPRM, &fdparam);
+    if (ret >= 0)
+        prio = 100;
+
+outc:
+    close(fd);
+out:
+    return prio;
+}
+
+
+static int floppy_is_inserted(BlockDriverState *bs)
+{
+    return fd_open(bs) >= 0;
+}
+
+static int floppy_media_changed(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    /*
+     * XXX: we do not have a true media changed indication.
+     * It does not work if the floppy is changed without trying to read it.
+     */
+    fd_open(bs);
+    ret = s->fd_media_changed;
+    s->fd_media_changed = 0;
+#ifdef DEBUG_FLOPPY
+    printf("Floppy changed=%d\n", ret);
+#endif
+    return ret;
+}
+
+static int floppy_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd;
+
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+    if (fd >= 0) {
+        if (ioctl(fd, FDEJECT, 0) < 0)
+            perror("FDEJECT");
+        close(fd);
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_floppy = {
+    .format_name        = "host_floppy",
+    .protocol_name      = "host_floppy",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= floppy_probe_device,
+    .bdrv_file_open     = floppy_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .bdrv_has_zero_init = hdev_has_zero_init,
+    .bdrv_flush         = raw_flush,
+
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_flush	= raw_aio_flush,
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength	= raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    /* removable device support */
+    .bdrv_is_inserted   = floppy_is_inserted,
+    .bdrv_media_changed = floppy_media_changed,
+    .bdrv_eject         = floppy_eject,
+};
+
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+
+    s->type = FTYPE_CD;
+
+    /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
+    return raw_open_common(bs, filename, flags, O_NONBLOCK);
+}
+
+static int cdrom_probe_device(const char *filename)
+{
+    int fd, ret;
+    int prio = 0;
+    struct stat st;
+
+    fd = open(filename, O_RDONLY | O_NONBLOCK);
+    if (fd < 0) {
+        goto out;
+    }
+    ret = fstat(fd, &st);
+    if (ret == -1 || !S_ISBLK(st.st_mode)) {
+        goto outc;
+    }
+
+    /* Attempt to detect via a CDROM specific ioctl */
+    ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+    if (ret >= 0)
+        prio = 100;
+
+outc:
+    close(fd);
+out:
+    return prio;
+}
+
+static int cdrom_is_inserted(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+    if (ret == CDS_DISC_OK)
+        return 1;
+    return 0;
+}
+
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDROMEJECT, NULL) < 0)
+            perror("CDROMEJECT");
+    } else {
+        if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
+            perror("CDROMEJECT");
+    }
+
+    return 0;
+}
+
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (ioctl(s->fd, CDROM_LOCKDOOR, locked) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .protocol_name      = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_file_open     = cdrom_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .bdrv_has_zero_init = hdev_has_zero_init,
+    .bdrv_flush         = raw_flush,
+
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_flush	= raw_aio_flush,
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    /* removable device support */
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
+
+    /* generic scsi device */
+    .bdrv_ioctl         = hdev_ioctl,
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+};
+#endif /* __linux__ */
+
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    s->type = FTYPE_CD;
+
+    ret = raw_open_common(bs, filename, flags, 0);
+    if (ret)
+        return ret;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
+}
+
+static int cdrom_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/cd", NULL) ||
+            strstart(filename, "/dev/acd", NULL))
+        return 100;
+    return 0;
+}
+
+static int cdrom_reopen(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd;
+
+    /*
+     * Force reread of possibly changed/newly loaded disc,
+     * FreeBSD seems to not notice sometimes...
+     */
+    if (s->fd >= 0)
+        close(s->fd);
+    fd = open(bs->filename, s->open_flags, 0644);
+    if (fd < 0) {
+        s->fd = -1;
+        return -EIO;
+    }
+    s->fd = fd;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
+}
+
+static int cdrom_is_inserted(BlockDriverState *bs)
+{
+    return raw_getlength(bs) > 0;
+}
+
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (s->fd < 0)
+        return -ENOTSUP;
+
+    (void) ioctl(s->fd, CDIOCALLOW);
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDIOCEJECT) < 0)
+            perror("CDIOCEJECT");
+    } else {
+        if (ioctl(s->fd, CDIOCCLOSE) < 0)
+            perror("CDIOCCLOSE");
+    }
+
+    if (cdrom_reopen(bs) < 0)
+        return -ENOTSUP;
+    return 0;
+}
+
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (s->fd < 0)
+        return -ENOTSUP;
+    if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .protocol_name      = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_file_open     = cdrom_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .bdrv_has_zero_init = hdev_has_zero_init,
+    .bdrv_flush         = raw_flush,
+
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_flush	= raw_aio_flush,
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength     = raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    /* removable device support */
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
+};
+#endif /* __FreeBSD__ */
+
+static void bdrv_file_init(void)
+{
+    /*
+     * Register all the drivers.  Note that order is important, the driver
+     * registered last will get probed first.
+     */
+    bdrv_register(&bdrv_file);
+    bdrv_register(&bdrv_host_device);
+#ifdef __linux__
+    bdrv_register(&bdrv_host_floppy);
+    bdrv_register(&bdrv_host_cdrom);
+#endif
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+    bdrv_register(&bdrv_host_cdrom);
+#endif
+}
+
+block_init(bdrv_file_init);
diff --git a/qemu-0.15.x/block/raw-win32.c b/qemu-0.15.x/block/raw-win32.c
new file mode 100644
index 0000000..91067e7
--- /dev/null
+++ b/qemu-0.15.x/block/raw-win32.c
@@ -0,0 +1,459 @@
+/*
+ * Block driver for RAW files (win32)
+ *
+ * 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "block_int.h"
+#include "module.h"
+#include <windows.h>
+#include <winioctl.h>
+
+#define FTYPE_FILE 0
+#define FTYPE_CD     1
+#define FTYPE_HARDDISK 2
+
+typedef struct BDRVRawState {
+    HANDLE hfile;
+    int type;
+    char drive_path[16]; /* format: "d:\" */
+} BDRVRawState;
+
+int qemu_ftruncate64(int fd, int64_t length)
+{
+    LARGE_INTEGER li;
+    LONG high;
+    HANDLE h;
+    BOOL res;
+
+    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
+	return -1;
+
+    h = (HANDLE)_get_osfhandle(fd);
+
+    /* get current position, ftruncate do not change position */
+    li.HighPart = 0;
+    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
+    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+	return -1;
+
+    high = length >> 32;
+    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+	return -1;
+    res = SetEndOfFile(h);
+
+    /* back to old position */
+    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
+    return res ? 0 : -1;
+}
+
+static int set_sparse(int fd)
+{
+    DWORD returned;
+    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
+				 NULL, 0, NULL, 0, &returned, NULL);
+}
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int access_flags;
+    DWORD overlapped;
+
+    s->type = FTYPE_FILE;
+
+    if (flags & BDRV_O_RDWR) {
+        access_flags = GENERIC_READ | GENERIC_WRITE;
+    } else {
+        access_flags = GENERIC_READ;
+    }
+
+    overlapped = FILE_ATTRIBUTE_NORMAL;
+    if (flags & BDRV_O_NOCACHE)
+        overlapped |= FILE_FLAG_NO_BUFFERING;
+    if (!(flags & BDRV_O_CACHE_WB))
+        overlapped |= FILE_FLAG_WRITE_THROUGH;
+    s->hfile = CreateFile(filename, access_flags,
+                          FILE_SHARE_READ, NULL,
+                          OPEN_EXISTING, overlapped, NULL);
+    if (s->hfile == INVALID_HANDLE_VALUE) {
+        int err = GetLastError();
+
+        if (err == ERROR_ACCESS_DENIED)
+            return -EACCES;
+        return -1;
+    }
+    return 0;
+}
+
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVRawState *s = bs->opaque;
+    OVERLAPPED ov;
+    DWORD ret_count;
+    int ret;
+    int64_t offset = sector_num * 512;
+    int count = nb_sectors * 512;
+
+    memset(&ov, 0, sizeof(ov));
+    ov.Offset = offset;
+    ov.OffsetHigh = offset >> 32;
+    ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
+    if (!ret)
+        return ret_count;
+    if (ret_count == count)
+        ret_count = 0;
+    return ret_count;
+}
+
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVRawState *s = bs->opaque;
+    OVERLAPPED ov;
+    DWORD ret_count;
+    int ret;
+    int64_t offset = sector_num * 512;
+    int count = nb_sectors * 512;
+
+    memset(&ov, 0, sizeof(ov));
+    ov.Offset = offset;
+    ov.OffsetHigh = offset >> 32;
+    ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
+    if (!ret)
+        return ret_count;
+    if (ret_count == count)
+        ret_count = 0;
+    return ret_count;
+}
+
+static int raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = FlushFileBuffers(s->hfile);
+    if (ret == 0) {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    CloseHandle(s->hfile);
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRawState *s = bs->opaque;
+    LONG low, high;
+
+    low = offset;
+    high = offset >> 32;
+    if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
+	return -EIO;
+    if (!SetEndOfFile(s->hfile))
+        return -EIO;
+    return 0;
+}
+
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    LARGE_INTEGER l;
+    ULARGE_INTEGER available, total, total_free;
+    DISK_GEOMETRY_EX dg;
+    DWORD count;
+    BOOL status;
+
+    switch(s->type) {
+    case FTYPE_FILE:
+        l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
+        if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+            return -EIO;
+        break;
+    case FTYPE_CD:
+        if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
+            return -EIO;
+        l.QuadPart = total.QuadPart;
+        break;
+    case FTYPE_HARDDISK:
+        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
+        if (status != 0) {
+            l = dg.DiskSize;
+        }
+        break;
+    default:
+        return -EIO;
+    }
+    return l.QuadPart;
+}
+
+static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
+{
+    typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
+                                              DWORD * high);
+    get_compressed_t get_compressed;
+    struct _stati64 st;
+    const char *filename = bs->filename;
+    /* WinNT support GetCompressedFileSize to determine allocate size */
+    get_compressed =
+        (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
+                                            "GetCompressedFileSizeA");
+    if (get_compressed) {
+        DWORD high, low;
+        low = get_compressed(filename, &high);
+        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
+            return (((int64_t) high) << 32) + low;
+        }
+    }
+
+    if (_stati64(filename, &st) < 0) {
+        return -1;
+    }
+    return st.st_size;
+}
+
+static int raw_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int64_t total_size = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+              0644);
+    if (fd < 0)
+        return -EIO;
+    set_sparse(fd);
+    ftruncate(fd, total_size * 512);
+    close(fd);
+    return 0;
+}
+
+static QEMUOptionParameter raw_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_file = {
+    .format_name	= "file",
+    .protocol_name	= "file",
+    .instance_size	= sizeof(BDRVRawState),
+    .bdrv_file_open	= raw_open,
+    .bdrv_close		= raw_close,
+    .bdrv_create	= raw_create,
+    .bdrv_flush		= raw_flush,
+    .bdrv_read		= raw_read,
+    .bdrv_write		= raw_write,
+    .bdrv_truncate	= raw_truncate,
+    .bdrv_getlength	= raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+
+    .create_options = raw_create_options,
+};
+
+/***********************************************/
+/* host device */
+
+static int find_cdrom(char *cdrom_name, int cdrom_name_size)
+{
+    char drives[256], *pdrv = drives;
+    UINT type;
+
+    memset(drives, 0, sizeof(drives));
+    GetLogicalDriveStrings(sizeof(drives), drives);
+    while(pdrv[0] != '\0') {
+        type = GetDriveType(pdrv);
+        switch(type) {
+        case DRIVE_CDROM:
+            snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
+            return 0;
+            break;
+        }
+        pdrv += lstrlen(pdrv) + 1;
+    }
+    return -1;
+}
+
+static int find_device_type(BlockDriverState *bs, const char *filename)
+{
+    BDRVRawState *s = bs->opaque;
+    UINT type;
+    const char *p;
+
+    if (strstart(filename, "\\\\.\\", &p) ||
+        strstart(filename, "//./", &p)) {
+        if (stristart(p, "PhysicalDrive", NULL))
+            return FTYPE_HARDDISK;
+        snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
+        type = GetDriveType(s->drive_path);
+        switch (type) {
+        case DRIVE_REMOVABLE:
+        case DRIVE_FIXED:
+            return FTYPE_HARDDISK;
+        case DRIVE_CDROM:
+            return FTYPE_CD;
+        default:
+            return FTYPE_FILE;
+        }
+    } else {
+        return FTYPE_FILE;
+    }
+}
+
+static int hdev_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return 100;
+    if (is_windows_drive(filename))
+        return 100;
+    return 0;
+}
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int access_flags, create_flags;
+    DWORD overlapped;
+    char device_name[64];
+
+    if (strstart(filename, "/dev/cdrom", NULL)) {
+        if (find_cdrom(device_name, sizeof(device_name)) < 0)
+            return -ENOENT;
+        filename = device_name;
+    } else {
+        /* transform drive letters into device name */
+        if (((filename[0] >= 'a' && filename[0] <= 'z') ||
+             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+            filename[1] == ':' && filename[2] == '\0') {
+            snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
+            filename = device_name;
+        }
+    }
+    s->type = find_device_type(bs, filename);
+
+    if (flags & BDRV_O_RDWR) {
+        access_flags = GENERIC_READ | GENERIC_WRITE;
+    } else {
+        access_flags = GENERIC_READ;
+    }
+    create_flags = OPEN_EXISTING;
+
+    overlapped = FILE_ATTRIBUTE_NORMAL;
+    if (flags & BDRV_O_NOCACHE)
+        overlapped |= FILE_FLAG_NO_BUFFERING;
+    if (!(flags & BDRV_O_CACHE_WB))
+        overlapped |= FILE_FLAG_WRITE_THROUGH;
+    s->hfile = CreateFile(filename, access_flags,
+                          FILE_SHARE_READ, NULL,
+                          create_flags, overlapped, NULL);
+    if (s->hfile == INVALID_HANDLE_VALUE) {
+        int err = GetLastError();
+
+        if (err == ERROR_ACCESS_DENIED)
+            return -EACCES;
+        return -1;
+    }
+    return 0;
+}
+
+#if 0
+/***********************************************/
+/* removable device additional commands */
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+    return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+    return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+    DWORD ret_count;
+
+    if (s->type == FTYPE_FILE)
+        return -ENOTSUP;
+    if (eject_flag) {
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
+                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+    } else {
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
+                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+    }
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+    return -ENOTSUP;
+}
+#endif
+
+static int hdev_has_zero_init(BlockDriverState *bs)
+{
+    return 0;
+}
+
+static BlockDriver bdrv_host_device = {
+    .format_name	= "host_device",
+    .protocol_name	= "host_device",
+    .instance_size	= sizeof(BDRVRawState),
+    .bdrv_probe_device	= hdev_probe_device,
+    .bdrv_file_open	= hdev_open,
+    .bdrv_close		= raw_close,
+    .bdrv_flush		= raw_flush,
+    .bdrv_has_zero_init = hdev_has_zero_init,
+
+    .bdrv_read		= raw_read,
+    .bdrv_write	        = raw_write,
+    .bdrv_getlength	= raw_getlength,
+    .bdrv_get_allocated_file_size
+                        = raw_get_allocated_file_size,
+};
+
+static void bdrv_file_init(void)
+{
+    bdrv_register(&bdrv_file);
+    bdrv_register(&bdrv_host_device);
+}
+
+block_init(bdrv_file_init);
diff --git a/qemu-0.15.x/block/raw.c b/qemu-0.15.x/block/raw.c
new file mode 100644
index 0000000..b0f72d6
--- /dev/null
+++ b/qemu-0.15.x/block/raw.c
@@ -0,0 +1,156 @@
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+static int raw_open(BlockDriverState *bs, int flags)
+{
+    bs->sg = bs->file->sg;
+    return 0;
+}
+
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    return bdrv_read(bs->file, sector_num, buf, nb_sectors);
+}
+
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    return bdrv_write(bs->file, sector_num, buf, nb_sectors);
+}
+
+static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+}
+
+static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
+    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+}
+
+static int raw_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
+    BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    return bdrv_getlength(bs->file);
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    return bdrv_truncate(bs->file, offset);
+}
+
+static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+   return 1; /* everything can be opened as raw image */
+}
+
+static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    return bdrv_discard(bs->file, sector_num, nb_sectors);
+}
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+    return bdrv_is_inserted(bs->file);
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+    return bdrv_eject(bs->file, eject_flag);
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+    bdrv_set_locked(bs->file, locked);
+    return 0;
+}
+
+static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+   return bdrv_ioctl(bs->file, req, buf);
+}
+
+static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+   return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
+}
+
+static int raw_create(const char *filename, QEMUOptionParameter *options)
+{
+    return bdrv_create_file(filename, options);
+}
+
+static QEMUOptionParameter raw_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static int raw_has_zero_init(BlockDriverState *bs)
+{
+    return bdrv_has_zero_init(bs->file);
+}
+
+static BlockDriver bdrv_raw = {
+    .format_name        = "raw",
+
+    /* It's really 0, but we need to make qemu_malloc() happy */
+    .instance_size      = 1,
+
+    .bdrv_open          = raw_open,
+    .bdrv_close         = raw_close,
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_flush         = raw_flush,
+    .bdrv_probe         = raw_probe,
+    .bdrv_getlength     = raw_getlength,
+    .bdrv_truncate      = raw_truncate,
+
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_flush     = raw_aio_flush,
+    .bdrv_discard       = raw_discard,
+
+    .bdrv_is_inserted   = raw_is_inserted,
+    .bdrv_eject         = raw_eject,
+    .bdrv_set_locked    = raw_set_locked,
+    .bdrv_ioctl         = raw_ioctl,
+    .bdrv_aio_ioctl     = raw_aio_ioctl,
+
+    .bdrv_create        = raw_create,
+    .create_options     = raw_create_options,
+    .bdrv_has_zero_init = raw_has_zero_init,
+};
+
+static void bdrv_raw_init(void)
+{
+    bdrv_register(&bdrv_raw);
+}
+
+block_init(bdrv_raw_init);
diff --git a/qemu-0.15.x/block/rbd.c b/qemu-0.15.x/block/rbd.c
new file mode 100644
index 0000000..d5659cd
--- /dev/null
+++ b/qemu-0.15.x/block/rbd.c
@@ -0,0 +1,811 @@
+/*
+ * QEMU Block driver for RADOS (Ceph)
+ *
+ * Copyright (C) 2010-2011 Christian Brunner <chb at muc.de>,
+ *                         Josh Durgin <josh.durgin at dreamhost.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <inttypes.h>
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+
+#include "block_int.h"
+
+#include <rbd/librbd.h>
+
+
+
+/*
+ * When specifying the image filename use:
+ *
+ * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
+ *
+ * poolname must be the name of an existing rados pool
+ *
+ * devicename is the basename for all objects used to
+ * emulate the raw device.
+ *
+ * Each option given is used to configure rados, and may be
+ * any Ceph option, or "conf". The "conf" option specifies
+ * a Ceph configuration file to read.
+ *
+ * Metadata information (image size, ...) is stored in an
+ * object with the name "devicename.rbd".
+ *
+ * The raw device is split into 4MB sized objects by default.
+ * The sequencenumber is encoded in a 12 byte long hex-string,
+ * and is attached to the devicename, separated by a dot.
+ * e.g. "devicename.1234567890ab"
+ *
+ */
+
+#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
+
+#define RBD_MAX_CONF_NAME_SIZE 128
+#define RBD_MAX_CONF_VAL_SIZE 512
+#define RBD_MAX_CONF_SIZE 1024
+#define RBD_MAX_POOL_NAME_SIZE 128
+#define RBD_MAX_SNAP_NAME_SIZE 128
+#define RBD_MAX_SNAPS 100
+
+typedef struct RBDAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+    QEMUIOVector *qiov;
+    char *bounce;
+    int write;
+    int64_t sector_num;
+    int error;
+    struct BDRVRBDState *s;
+    int cancelled;
+} RBDAIOCB;
+
+typedef struct RADOSCB {
+    int rcbid;
+    RBDAIOCB *acb;
+    struct BDRVRBDState *s;
+    int done;
+    int64_t size;
+    char *buf;
+    int ret;
+} RADOSCB;
+
+#define RBD_FD_READ 0
+#define RBD_FD_WRITE 1
+
+typedef struct BDRVRBDState {
+    int fds[2];
+    rados_t cluster;
+    rados_ioctx_t io_ctx;
+    rbd_image_t image;
+    char name[RBD_MAX_IMAGE_NAME_SIZE];
+    int qemu_aio_count;
+    char *snap;
+    int event_reader_pos;
+    RADOSCB *event_rcb;
+} BDRVRBDState;
+
+static void rbd_aio_bh_cb(void *opaque);
+
+static int qemu_rbd_next_tok(char *dst, int dst_len,
+                             char *src, char delim,
+                             const char *name,
+                             char **p)
+{
+    int l;
+    char *end;
+
+    *p = NULL;
+
+    if (delim != '\0') {
+        end = strchr(src, delim);
+        if (end) {
+            *p = end + 1;
+            *end = '\0';
+        }
+    }
+    l = strlen(src);
+    if (l >= dst_len) {
+        error_report("%s too long", name);
+        return -EINVAL;
+    } else if (l == 0) {
+        error_report("%s too short", name);
+        return -EINVAL;
+    }
+
+    pstrcpy(dst, dst_len, src);
+
+    return 0;
+}
+
+static int qemu_rbd_parsename(const char *filename,
+                              char *pool, int pool_len,
+                              char *snap, int snap_len,
+                              char *name, int name_len,
+                              char *conf, int conf_len)
+{
+    const char *start;
+    char *p, *buf;
+    int ret;
+
+    if (!strstart(filename, "rbd:", &start)) {
+        return -EINVAL;
+    }
+
+    buf = qemu_strdup(start);
+    p = buf;
+    *snap = '\0';
+    *conf = '\0';
+
+    ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+    if (ret < 0 || !p) {
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (strchr(p, '@')) {
+        ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
+        if (ret < 0) {
+            goto done;
+        }
+        ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+    } else {
+        ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
+    }
+    if (ret < 0 || !p) {
+        goto done;
+    }
+
+    ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
+
+done:
+    qemu_free(buf);
+    return ret;
+}
+
+static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
+{
+    char *p, *buf;
+    char name[RBD_MAX_CONF_NAME_SIZE];
+    char value[RBD_MAX_CONF_VAL_SIZE];
+    int ret = 0;
+
+    buf = qemu_strdup(conf);
+    p = buf;
+
+    while (p) {
+        ret = qemu_rbd_next_tok(name, sizeof(name), p,
+                                '=', "conf option name", &p);
+        if (ret < 0) {
+            break;
+        }
+
+        if (!p) {
+            error_report("conf option %s has no value", name);
+            ret = -EINVAL;
+            break;
+        }
+
+        ret = qemu_rbd_next_tok(value, sizeof(value), p,
+                                ':', "conf option value", &p);
+        if (ret < 0) {
+            break;
+        }
+
+        if (strcmp(name, "conf")) {
+            ret = rados_conf_set(cluster, name, value);
+            if (ret < 0) {
+                error_report("invalid conf option %s", name);
+                ret = -EINVAL;
+                break;
+            }
+        } else {
+            ret = rados_conf_read_file(cluster, value);
+            if (ret < 0) {
+                error_report("error reading conf file %s", value);
+                break;
+            }
+        }
+    }
+
+    qemu_free(buf);
+    return ret;
+}
+
+static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
+{
+    int64_t bytes = 0;
+    int64_t objsize;
+    int obj_order = 0;
+    char pool[RBD_MAX_POOL_NAME_SIZE];
+    char name[RBD_MAX_IMAGE_NAME_SIZE];
+    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+    char conf[RBD_MAX_CONF_SIZE];
+    rados_t cluster;
+    rados_ioctx_t io_ctx;
+    int ret;
+
+    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+                           snap_buf, sizeof(snap_buf),
+                           name, sizeof(name),
+                           conf, sizeof(conf)) < 0) {
+        return -EINVAL;
+    }
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            bytes = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                objsize = options->value.n;
+                if ((objsize - 1) & objsize) {    /* not a power of 2? */
+                    error_report("obj size needs to be power of 2");
+                    return -EINVAL;
+                }
+                if (objsize < 4096) {
+                    error_report("obj size too small");
+                    return -EINVAL;
+                }
+                obj_order = ffs(objsize) - 1;
+            }
+        }
+        options++;
+    }
+
+    if (rados_create(&cluster, NULL) < 0) {
+        error_report("error initializing");
+        return -EIO;
+    }
+
+    if (strstr(conf, "conf=") == NULL) {
+        if (rados_conf_read_file(cluster, NULL) < 0) {
+            error_report("error reading config file");
+            rados_shutdown(cluster);
+            return -EIO;
+        }
+    }
+
+    if (conf[0] != '\0' &&
+        qemu_rbd_set_conf(cluster, conf) < 0) {
+        error_report("error setting config options");
+        rados_shutdown(cluster);
+        return -EIO;
+    }
+
+    if (rados_connect(cluster) < 0) {
+        error_report("error connecting");
+        rados_shutdown(cluster);
+        return -EIO;
+    }
+
+    if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
+        error_report("error opening pool %s", pool);
+        rados_shutdown(cluster);
+        return -EIO;
+    }
+
+    ret = rbd_create(io_ctx, name, bytes, &obj_order);
+    rados_ioctx_destroy(io_ctx);
+    rados_shutdown(cluster);
+
+    return ret;
+}
+
+/*
+ * This aio completion is being called from qemu_rbd_aio_event_reader()
+ * and runs in qemu context. It schedules a bh, but just in case the aio
+ * was not cancelled before.
+ */
+static void qemu_rbd_complete_aio(RADOSCB *rcb)
+{
+    RBDAIOCB *acb = rcb->acb;
+    int64_t r;
+
+    if (acb->cancelled) {
+        qemu_vfree(acb->bounce);
+        qemu_aio_release(acb);
+        goto done;
+    }
+
+    r = rcb->ret;
+
+    if (acb->write) {
+        if (r < 0) {
+            acb->ret = r;
+            acb->error = 1;
+        } else if (!acb->error) {
+            acb->ret = rcb->size;
+        }
+    } else {
+        if (r < 0) {
+            memset(rcb->buf, 0, rcb->size);
+            acb->ret = r;
+            acb->error = 1;
+        } else if (r < rcb->size) {
+            memset(rcb->buf + r, 0, rcb->size - r);
+            if (!acb->error) {
+                acb->ret = rcb->size;
+            }
+        } else if (!acb->error) {
+            acb->ret = r;
+        }
+    }
+    /* Note that acb->bh can be NULL in case where the aio was cancelled */
+    acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
+    qemu_bh_schedule(acb->bh);
+done:
+    qemu_free(rcb);
+}
+
+/*
+ * aio fd read handler. It runs in the qemu context and calls the
+ * completion handling of completed rados aio operations.
+ */
+static void qemu_rbd_aio_event_reader(void *opaque)
+{
+    BDRVRBDState *s = opaque;
+
+    ssize_t ret;
+
+    do {
+        char *p = (char *)&s->event_rcb;
+
+        /* now read the rcb pointer that was sent from a non qemu thread */
+        if ((ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
+                        sizeof(s->event_rcb) - s->event_reader_pos)) > 0) {
+            if (ret > 0) {
+                s->event_reader_pos += ret;
+                if (s->event_reader_pos == sizeof(s->event_rcb)) {
+                    s->event_reader_pos = 0;
+                    qemu_rbd_complete_aio(s->event_rcb);
+                    s->qemu_aio_count--;
+                }
+            }
+        }
+    } while (ret < 0 && errno == EINTR);
+}
+
+static int qemu_rbd_aio_flush_cb(void *opaque)
+{
+    BDRVRBDState *s = opaque;
+
+    return (s->qemu_aio_count > 0);
+}
+
+static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRBDState *s = bs->opaque;
+    char pool[RBD_MAX_POOL_NAME_SIZE];
+    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+    char conf[RBD_MAX_CONF_SIZE];
+    int r;
+
+    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+                           snap_buf, sizeof(snap_buf),
+                           s->name, sizeof(s->name),
+                           conf, sizeof(conf)) < 0) {
+        return -EINVAL;
+    }
+    s->snap = NULL;
+    if (snap_buf[0] != '\0') {
+        s->snap = qemu_strdup(snap_buf);
+    }
+
+    r = rados_create(&s->cluster, NULL);
+    if (r < 0) {
+        error_report("error initializing");
+        return r;
+    }
+
+    if (strstr(conf, "conf=") == NULL) {
+        r = rados_conf_read_file(s->cluster, NULL);
+        if (r < 0) {
+            error_report("error reading config file");
+            rados_shutdown(s->cluster);
+            return r;
+        }
+    }
+
+    if (conf[0] != '\0') {
+        r = qemu_rbd_set_conf(s->cluster, conf);
+        if (r < 0) {
+            error_report("error setting config options");
+            rados_shutdown(s->cluster);
+            return r;
+        }
+    }
+
+    r = rados_connect(s->cluster);
+    if (r < 0) {
+        error_report("error connecting");
+        rados_shutdown(s->cluster);
+        return r;
+    }
+
+    r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
+    if (r < 0) {
+        error_report("error opening pool %s", pool);
+        rados_shutdown(s->cluster);
+        return r;
+    }
+
+    r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
+    if (r < 0) {
+        error_report("error reading header from %s", s->name);
+        rados_ioctx_destroy(s->io_ctx);
+        rados_shutdown(s->cluster);
+        return r;
+    }
+
+    bs->read_only = (s->snap != NULL);
+
+    s->event_reader_pos = 0;
+    r = qemu_pipe(s->fds);
+    if (r < 0) {
+        error_report("error opening eventfd");
+        goto failed;
+    }
+    fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
+    fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
+                            NULL, qemu_rbd_aio_flush_cb, NULL, s);
+
+
+    return 0;
+
+failed:
+    rbd_close(s->image);
+    rados_ioctx_destroy(s->io_ctx);
+    rados_shutdown(s->cluster);
+    return r;
+}
+
+static void qemu_rbd_close(BlockDriverState *bs)
+{
+    BDRVRBDState *s = bs->opaque;
+
+    close(s->fds[0]);
+    close(s->fds[1]);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
+        NULL);
+
+    rbd_close(s->image);
+    rados_ioctx_destroy(s->io_ctx);
+    qemu_free(s->snap);
+    rados_shutdown(s->cluster);
+}
+
+/*
+ * Cancel aio. Since we don't reference acb in a non qemu threads,
+ * it is safe to access it here.
+ */
+static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    RBDAIOCB *acb = (RBDAIOCB *) blockacb;
+    acb->cancelled = 1;
+}
+
+static AIOPool rbd_aio_pool = {
+    .aiocb_size = sizeof(RBDAIOCB),
+    .cancel = qemu_rbd_aio_cancel,
+};
+
+static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
+{
+    int ret = 0;
+    while (1) {
+        fd_set wfd;
+        int fd = s->fds[RBD_FD_WRITE];
+
+        /* send the op pointer to the qemu thread that is responsible
+           for the aio/op completion. Must do it in a qemu thread context */
+        ret = write(fd, (void *)&rcb, sizeof(rcb));
+        if (ret >= 0) {
+            break;
+        }
+        if (errno == EINTR) {
+            continue;
+        }
+        if (errno != EAGAIN) {
+            break;
+        }
+
+        FD_ZERO(&wfd);
+        FD_SET(fd, &wfd);
+        do {
+            ret = select(fd + 1, NULL, &wfd, NULL, NULL);
+        } while (ret < 0 && errno == EINTR);
+    }
+
+    return ret;
+}
+
+/*
+ * This is the callback function for rbd_aio_read and _write
+ *
+ * Note: this function is being called from a non qemu thread so
+ * we need to be careful about what we do here. Generally we only
+ * write to the block notification pipe, and do the rest of the
+ * io completion handling from qemu_rbd_aio_event_reader() which
+ * runs in a qemu context.
+ */
+static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
+{
+    int ret;
+    rcb->ret = rbd_aio_get_return_value(c);
+    rbd_aio_release(c);
+    ret = qemu_rbd_send_pipe(rcb->s, rcb);
+    if (ret < 0) {
+        error_report("failed writing to acb->s->fds");
+        qemu_free(rcb);
+    }
+}
+
+/* Callback when all queued rbd_aio requests are complete */
+
+static void rbd_aio_bh_cb(void *opaque)
+{
+    RBDAIOCB *acb = opaque;
+
+    if (!acb->write) {
+        qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
+    }
+    qemu_vfree(acb->bounce);
+    acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
+                                           int64_t sector_num,
+                                           QEMUIOVector *qiov,
+                                           int nb_sectors,
+                                           BlockDriverCompletionFunc *cb,
+                                           void *opaque, int write)
+{
+    RBDAIOCB *acb;
+    RADOSCB *rcb;
+    rbd_completion_t c;
+    int64_t off, size;
+    char *buf;
+    int r;
+
+    BDRVRBDState *s = bs->opaque;
+
+    acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
+    if (!acb) {
+        return NULL;
+    }
+    acb->write = write;
+    acb->qiov = qiov;
+    acb->bounce = qemu_blockalign(bs, qiov->size);
+    acb->ret = 0;
+    acb->error = 0;
+    acb->s = s;
+    acb->cancelled = 0;
+    acb->bh = NULL;
+
+    if (write) {
+        qemu_iovec_to_buffer(acb->qiov, acb->bounce);
+    }
+
+    buf = acb->bounce;
+
+    off = sector_num * BDRV_SECTOR_SIZE;
+    size = nb_sectors * BDRV_SECTOR_SIZE;
+
+    s->qemu_aio_count++; /* All the RADOSCB */
+
+    rcb = qemu_malloc(sizeof(RADOSCB));
+    rcb->done = 0;
+    rcb->acb = acb;
+    rcb->buf = buf;
+    rcb->s = acb->s;
+    rcb->size = size;
+    r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+    if (r < 0) {
+        goto failed;
+    }
+
+    if (write) {
+        r = rbd_aio_write(s->image, off, size, buf, c);
+    } else {
+        r = rbd_aio_read(s->image, off, size, buf, c);
+    }
+
+    if (r < 0) {
+        goto failed;
+    }
+
+    return &acb->common;
+
+failed:
+    qemu_free(rcb);
+    s->qemu_aio_count--;
+    qemu_aio_release(acb);
+    return NULL;
+}
+
+static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov,
+                                            int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
+{
+    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+}
+
+static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             QEMUIOVector *qiov,
+                                             int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+}
+
+static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVRBDState *s = bs->opaque;
+    rbd_image_info_t info;
+    int r;
+
+    r = rbd_stat(s->image, &info, sizeof(info));
+    if (r < 0) {
+        return r;
+    }
+
+    bdi->cluster_size = info.obj_size;
+    return 0;
+}
+
+static int64_t qemu_rbd_getlength(BlockDriverState *bs)
+{
+    BDRVRBDState *s = bs->opaque;
+    rbd_image_info_t info;
+    int r;
+
+    r = rbd_stat(s->image, &info, sizeof(info));
+    if (r < 0) {
+        return r;
+    }
+
+    return info.size;
+}
+
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRBDState *s = bs->opaque;
+    int r;
+
+    r = rbd_resize(s->image, offset);
+    if (r < 0) {
+        return r;
+    }
+
+    return 0;
+}
+
+static int qemu_rbd_snap_create(BlockDriverState *bs,
+                                QEMUSnapshotInfo *sn_info)
+{
+    BDRVRBDState *s = bs->opaque;
+    int r;
+
+    if (sn_info->name[0] == '\0') {
+        return -EINVAL; /* we need a name for rbd snapshots */
+    }
+
+    /*
+     * rbd snapshots are using the name as the user controlled unique identifier
+     * we can't use the rbd snapid for that purpose, as it can't be set
+     */
+    if (sn_info->id_str[0] != '\0' &&
+        strcmp(sn_info->id_str, sn_info->name) != 0) {
+        return -EINVAL;
+    }
+
+    if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
+        return -ERANGE;
+    }
+
+    r = rbd_snap_create(s->image, sn_info->name);
+    if (r < 0) {
+        error_report("failed to create snap: %s", strerror(-r));
+        return r;
+    }
+
+    return 0;
+}
+
+static int qemu_rbd_snap_list(BlockDriverState *bs,
+                              QEMUSnapshotInfo **psn_tab)
+{
+    BDRVRBDState *s = bs->opaque;
+    QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
+    int i, snap_count;
+    rbd_snap_info_t *snaps;
+    int max_snaps = RBD_MAX_SNAPS;
+
+    do {
+        snaps = qemu_malloc(sizeof(*snaps) * max_snaps);
+        snap_count = rbd_snap_list(s->image, snaps, &max_snaps);
+        if (snap_count < 0) {
+            qemu_free(snaps);
+        }
+    } while (snap_count == -ERANGE);
+
+    if (snap_count <= 0) {
+        return snap_count;
+    }
+
+    sn_tab = qemu_mallocz(snap_count * sizeof(QEMUSnapshotInfo));
+
+    for (i = 0; i < snap_count; i++) {
+        const char *snap_name = snaps[i].name;
+
+        sn_info = sn_tab + i;
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
+        pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
+
+        sn_info->vm_state_size = snaps[i].size;
+        sn_info->date_sec = 0;
+        sn_info->date_nsec = 0;
+        sn_info->vm_clock_nsec = 0;
+    }
+    rbd_snap_list_end(snaps);
+
+    *psn_tab = sn_tab;
+    return snap_count;
+}
+
+static QEMUOptionParameter qemu_rbd_create_options[] = {
+    {
+     .name = BLOCK_OPT_SIZE,
+     .type = OPT_SIZE,
+     .help = "Virtual disk size"
+    },
+    {
+     .name = BLOCK_OPT_CLUSTER_SIZE,
+     .type = OPT_SIZE,
+     .help = "RBD object size"
+    },
+    {NULL}
+};
+
+static BlockDriver bdrv_rbd = {
+    .format_name        = "rbd",
+    .instance_size      = sizeof(BDRVRBDState),
+    .bdrv_file_open     = qemu_rbd_open,
+    .bdrv_close         = qemu_rbd_close,
+    .bdrv_create        = qemu_rbd_create,
+    .bdrv_get_info      = qemu_rbd_getinfo,
+    .create_options     = qemu_rbd_create_options,
+    .bdrv_getlength     = qemu_rbd_getlength,
+    .bdrv_truncate      = qemu_rbd_truncate,
+    .protocol_name      = "rbd",
+
+    .bdrv_aio_readv     = qemu_rbd_aio_readv,
+    .bdrv_aio_writev    = qemu_rbd_aio_writev,
+
+    .bdrv_snapshot_create = qemu_rbd_snap_create,
+    .bdrv_snapshot_list = qemu_rbd_snap_list,
+};
+
+static void bdrv_rbd_init(void)
+{
+    bdrv_register(&bdrv_rbd);
+}
+
+block_init(bdrv_rbd_init);
diff --git a/qemu-0.15.x/block/sheepdog.c b/qemu-0.15.x/block/sheepdog.c
new file mode 100644
index 0000000..e150ac0
--- /dev/null
+++ b/qemu-0.15.x/block/sheepdog.c
@@ -0,0 +1,2083 @@
+/*
+ * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "qemu_socket.h"
+#include "block_int.h"
+#include "bitops.h"
+
+#define SD_PROTO_VER 0x01
+
+#define SD_DEFAULT_ADDR "localhost"
+#define SD_DEFAULT_PORT "7000"
+
+#define SD_OP_CREATE_AND_WRITE_OBJ  0x01
+#define SD_OP_READ_OBJ       0x02
+#define SD_OP_WRITE_OBJ      0x03
+
+#define SD_OP_NEW_VDI        0x11
+#define SD_OP_LOCK_VDI       0x12
+#define SD_OP_RELEASE_VDI    0x13
+#define SD_OP_GET_VDI_INFO   0x14
+#define SD_OP_READ_VDIS      0x15
+
+#define SD_FLAG_CMD_WRITE    0x01
+#define SD_FLAG_CMD_COW      0x02
+
+#define SD_RES_SUCCESS       0x00 /* Success */
+#define SD_RES_UNKNOWN       0x01 /* Unknown error */
+#define SD_RES_NO_OBJ        0x02 /* No object found */
+#define SD_RES_EIO           0x03 /* I/O error */
+#define SD_RES_VDI_EXIST     0x04 /* Vdi exists already */
+#define SD_RES_INVALID_PARMS 0x05 /* Invalid parameters */
+#define SD_RES_SYSTEM_ERROR  0x06 /* System error */
+#define SD_RES_VDI_LOCKED    0x07 /* Vdi is locked */
+#define SD_RES_NO_VDI        0x08 /* No vdi found */
+#define SD_RES_NO_BASE_VDI   0x09 /* No base vdi found */
+#define SD_RES_VDI_READ      0x0A /* Cannot read requested vdi */
+#define SD_RES_VDI_WRITE     0x0B /* Cannot write requested vdi */
+#define SD_RES_BASE_VDI_READ 0x0C /* Cannot read base vdi */
+#define SD_RES_BASE_VDI_WRITE   0x0D /* Cannot write base vdi */
+#define SD_RES_NO_TAG        0x0E /* Requested tag is not found */
+#define SD_RES_STARTUP       0x0F /* Sheepdog is on starting up */
+#define SD_RES_VDI_NOT_LOCKED   0x10 /* Vdi is not locked */
+#define SD_RES_SHUTDOWN      0x11 /* Sheepdog is shutting down */
+#define SD_RES_NO_MEM        0x12 /* Cannot allocate memory */
+#define SD_RES_FULL_VDI      0x13 /* we already have the maximum vdis */
+#define SD_RES_VER_MISMATCH  0x14 /* Protocol version mismatch */
+#define SD_RES_NO_SPACE      0x15 /* Server has no room for new objects */
+#define SD_RES_WAIT_FOR_FORMAT  0x16 /* Waiting for a format operation */
+#define SD_RES_WAIT_FOR_JOIN    0x17 /* Waiting for other nodes joining */
+#define SD_RES_JOIN_FAILED   0x18 /* Target node had failed to join sheepdog */
+
+/*
+ * Object ID rules
+ *
+ *  0 - 19 (20 bits): data object space
+ * 20 - 31 (12 bits): reserved data object space
+ * 32 - 55 (24 bits): vdi object space
+ * 56 - 59 ( 4 bits): reserved vdi object space
+ * 60 - 63 ( 4 bits): object type indentifier space
+ */
+
+#define VDI_SPACE_SHIFT   32
+#define VDI_BIT (UINT64_C(1) << 63)
+#define VMSTATE_BIT (UINT64_C(1) << 62)
+#define MAX_DATA_OBJS (UINT64_C(1) << 20)
+#define MAX_CHILDREN 1024
+#define SD_MAX_VDI_LEN 256
+#define SD_MAX_VDI_TAG_LEN 256
+#define SD_NR_VDIS   (1U << 24)
+#define SD_DATA_OBJ_SIZE (UINT64_C(1) << 22)
+#define SD_MAX_VDI_SIZE (SD_DATA_OBJ_SIZE * MAX_DATA_OBJS)
+#define SECTOR_SIZE 512
+
+#define SD_INODE_SIZE (sizeof(SheepdogInode))
+#define CURRENT_VDI_ID 0
+
+typedef struct SheepdogReq {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint32_t opcode_specific[8];
+} SheepdogReq;
+
+typedef struct SheepdogRsp {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint32_t result;
+    uint32_t opcode_specific[7];
+} SheepdogRsp;
+
+typedef struct SheepdogObjReq {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint64_t oid;
+    uint64_t cow_oid;
+    uint32_t copies;
+    uint32_t rsvd;
+    uint64_t offset;
+} SheepdogObjReq;
+
+typedef struct SheepdogObjRsp {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint32_t result;
+    uint32_t copies;
+    uint32_t pad[6];
+} SheepdogObjRsp;
+
+typedef struct SheepdogVdiReq {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint64_t vdi_size;
+    uint32_t base_vdi_id;
+    uint32_t copies;
+    uint32_t snapid;
+    uint32_t pad[3];
+} SheepdogVdiReq;
+
+typedef struct SheepdogVdiRsp {
+    uint8_t proto_ver;
+    uint8_t opcode;
+    uint16_t flags;
+    uint32_t epoch;
+    uint32_t id;
+    uint32_t data_length;
+    uint32_t result;
+    uint32_t rsvd;
+    uint32_t vdi_id;
+    uint32_t pad[5];
+} SheepdogVdiRsp;
+
+typedef struct SheepdogInode {
+    char name[SD_MAX_VDI_LEN];
+    char tag[SD_MAX_VDI_TAG_LEN];
+    uint64_t ctime;
+    uint64_t snap_ctime;
+    uint64_t vm_clock_nsec;
+    uint64_t vdi_size;
+    uint64_t vm_state_size;
+    uint16_t copy_policy;
+    uint8_t nr_copies;
+    uint8_t block_size_shift;
+    uint32_t snap_id;
+    uint32_t vdi_id;
+    uint32_t parent_vdi_id;
+    uint32_t child_vdi_id[MAX_CHILDREN];
+    uint32_t data_vdi_id[MAX_DATA_OBJS];
+} SheepdogInode;
+
+/*
+ * 64 bit FNV-1a non-zero initial basis
+ */
+#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
+
+/*
+ * 64 bit Fowler/Noll/Vo FNV-1a hash code
+ */
+static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
+{
+    unsigned char *bp = buf;
+    unsigned char *be = bp + len;
+    while (bp < be) {
+        hval ^= (uint64_t) *bp++;
+        hval += (hval << 1) + (hval << 4) + (hval << 5) +
+            (hval << 7) + (hval << 8) + (hval << 40);
+    }
+    return hval;
+}
+
+static inline int is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
+{
+    return inode->vdi_id == inode->data_vdi_id[idx];
+}
+
+static inline int is_data_obj(uint64_t oid)
+{
+    return !(VDI_BIT & oid);
+}
+
+static inline uint64_t data_oid_to_idx(uint64_t oid)
+{
+    return oid & (MAX_DATA_OBJS - 1);
+}
+
+static inline uint64_t vid_to_vdi_oid(uint32_t vid)
+{
+    return VDI_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT);
+}
+
+static inline uint64_t vid_to_vmstate_oid(uint32_t vid, uint32_t idx)
+{
+    return VMSTATE_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT) | idx;
+}
+
+static inline uint64_t vid_to_data_oid(uint32_t vid, uint32_t idx)
+{
+    return ((uint64_t)vid << VDI_SPACE_SHIFT) | idx;
+}
+
+static inline int is_snapshot(struct SheepdogInode *inode)
+{
+    return !!inode->snap_ctime;
+}
+
+#undef dprintf
+#ifdef DEBUG_SDOG
+#define dprintf(fmt, args...)                                       \
+    do {                                                            \
+        fprintf(stdout, "%s %d: " fmt, __func__, __LINE__, ##args); \
+    } while (0)
+#else
+#define dprintf(fmt, args...)
+#endif
+
+typedef struct SheepdogAIOCB SheepdogAIOCB;
+
+typedef struct AIOReq {
+    SheepdogAIOCB *aiocb;
+    unsigned int iov_offset;
+
+    uint64_t oid;
+    uint64_t base_oid;
+    uint64_t offset;
+    unsigned int data_len;
+    uint8_t flags;
+    uint32_t id;
+
+    QLIST_ENTRY(AIOReq) outstanding_aio_siblings;
+    QLIST_ENTRY(AIOReq) aioreq_siblings;
+} AIOReq;
+
+enum AIOCBState {
+    AIOCB_WRITE_UDATA,
+    AIOCB_READ_UDATA,
+};
+
+struct SheepdogAIOCB {
+    BlockDriverAIOCB common;
+
+    QEMUIOVector *qiov;
+
+    int64_t sector_num;
+    int nb_sectors;
+
+    int ret;
+    enum AIOCBState aiocb_type;
+
+    QEMUBH *bh;
+    void (*aio_done_func)(SheepdogAIOCB *);
+
+    int canceled;
+
+    QLIST_HEAD(aioreq_head, AIOReq) aioreq_head;
+};
+
+typedef struct BDRVSheepdogState {
+    SheepdogInode inode;
+
+    uint32_t min_dirty_data_idx;
+    uint32_t max_dirty_data_idx;
+
+    char name[SD_MAX_VDI_LEN];
+    int is_snapshot;
+
+    char *addr;
+    char *port;
+    int fd;
+
+    uint32_t aioreq_seq_num;
+    QLIST_HEAD(outstanding_aio_head, AIOReq) outstanding_aio_head;
+} BDRVSheepdogState;
+
+static const char * sd_strerror(int err)
+{
+    int i;
+
+    static const struct {
+        int err;
+        const char *desc;
+    } errors[] = {
+        {SD_RES_SUCCESS, "Success"},
+        {SD_RES_UNKNOWN, "Unknown error"},
+        {SD_RES_NO_OBJ, "No object found"},
+        {SD_RES_EIO, "I/O error"},
+        {SD_RES_VDI_EXIST, "VDI exists already"},
+        {SD_RES_INVALID_PARMS, "Invalid parameters"},
+        {SD_RES_SYSTEM_ERROR, "System error"},
+        {SD_RES_VDI_LOCKED, "VDI is already locked"},
+        {SD_RES_NO_VDI, "No vdi found"},
+        {SD_RES_NO_BASE_VDI, "No base VDI found"},
+        {SD_RES_VDI_READ, "Failed read the requested VDI"},
+        {SD_RES_VDI_WRITE, "Failed to write the requested VDI"},
+        {SD_RES_BASE_VDI_READ, "Failed to read the base VDI"},
+        {SD_RES_BASE_VDI_WRITE, "Failed to write the base VDI"},
+        {SD_RES_NO_TAG, "Failed to find the requested tag"},
+        {SD_RES_STARTUP, "The system is still booting"},
+        {SD_RES_VDI_NOT_LOCKED, "VDI isn't locked"},
+        {SD_RES_SHUTDOWN, "The system is shutting down"},
+        {SD_RES_NO_MEM, "Out of memory on the server"},
+        {SD_RES_FULL_VDI, "We already have the maximum vdis"},
+        {SD_RES_VER_MISMATCH, "Protocol version mismatch"},
+        {SD_RES_NO_SPACE, "Server has no space for new objects"},
+        {SD_RES_WAIT_FOR_FORMAT, "Sheepdog is waiting for a format operation"},
+        {SD_RES_WAIT_FOR_JOIN, "Sheepdog is waiting for other nodes joining"},
+        {SD_RES_JOIN_FAILED, "Target node had failed to join sheepdog"},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(errors); ++i) {
+        if (errors[i].err == err) {
+            return errors[i].desc;
+        }
+    }
+
+    return "Invalid error code";
+}
+
+/*
+ * Sheepdog I/O handling:
+ *
+ * 1. In the sd_aio_readv/writev, read/write requests are added to the
+ *    QEMU Bottom Halves.
+ *
+ * 2. In sd_readv_writev_bh_cb, the callbacks of BHs, we send the I/O
+ *    requests to the server and link the requests to the
+ *    outstanding_list in the BDRVSheepdogState.  we exits the
+ *    function without waiting for receiving the response.
+ *
+ * 3. We receive the response in aio_read_response, the fd handler to
+ *    the sheepdog connection.  If metadata update is needed, we send
+ *    the write request to the vdi object in sd_write_done, the write
+ *    completion function.  The AIOCB callback is not called until all
+ *    the requests belonging to the AIOCB are finished.
+ */
+
+static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
+                                    uint64_t oid, unsigned int data_len,
+                                    uint64_t offset, uint8_t flags,
+                                    uint64_t base_oid, unsigned int iov_offset)
+{
+    AIOReq *aio_req;
+
+    aio_req = qemu_malloc(sizeof(*aio_req));
+    aio_req->aiocb = acb;
+    aio_req->iov_offset = iov_offset;
+    aio_req->oid = oid;
+    aio_req->base_oid = base_oid;
+    aio_req->offset = offset;
+    aio_req->data_len = data_len;
+    aio_req->flags = flags;
+    aio_req->id = s->aioreq_seq_num++;
+
+    QLIST_INSERT_HEAD(&s->outstanding_aio_head, aio_req,
+                      outstanding_aio_siblings);
+    QLIST_INSERT_HEAD(&acb->aioreq_head, aio_req, aioreq_siblings);
+
+    return aio_req;
+}
+
+static inline int free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
+{
+    SheepdogAIOCB *acb = aio_req->aiocb;
+    QLIST_REMOVE(aio_req, outstanding_aio_siblings);
+    QLIST_REMOVE(aio_req, aioreq_siblings);
+    qemu_free(aio_req);
+
+    return !QLIST_EMPTY(&acb->aioreq_head);
+}
+
+static void sd_finish_aiocb(SheepdogAIOCB *acb)
+{
+    if (!acb->canceled) {
+        acb->common.cb(acb->common.opaque, acb->ret);
+    }
+    qemu_aio_release(acb);
+}
+
+static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
+
+    /*
+     * Sheepdog cannot cancel the requests which are already sent to
+     * the servers, so we just complete the request with -EIO here.
+     */
+    acb->common.cb(acb->common.opaque, -EIO);
+    acb->canceled = 1;
+}
+
+static AIOPool sd_aio_pool = {
+    .aiocb_size = sizeof(SheepdogAIOCB),
+    .cancel = sd_aio_cancel,
+};
+
+static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
+                                   int64_t sector_num, int nb_sectors,
+                                   BlockDriverCompletionFunc *cb, void *opaque)
+{
+    SheepdogAIOCB *acb;
+
+    acb = qemu_aio_get(&sd_aio_pool, bs, cb, opaque);
+
+    acb->qiov = qiov;
+
+    acb->sector_num = sector_num;
+    acb->nb_sectors = nb_sectors;
+
+    acb->aio_done_func = NULL;
+    acb->canceled = 0;
+    acb->bh = NULL;
+    acb->ret = 0;
+    QLIST_INIT(&acb->aioreq_head);
+    return acb;
+}
+
+static int sd_schedule_bh(QEMUBHFunc *cb, SheepdogAIOCB *acb)
+{
+    if (acb->bh) {
+        error_report("bug: %d %d", acb->aiocb_type, acb->aiocb_type);
+        return -EIO;
+    }
+
+    acb->bh = qemu_bh_new(cb, acb);
+    qemu_bh_schedule(acb->bh);
+    return 0;
+}
+
+#ifdef _WIN32
+
+struct msghdr {
+    struct iovec *msg_iov;
+    size_t        msg_iovlen;
+};
+
+static ssize_t sendmsg(int s, const struct msghdr *msg, int flags)
+{
+    size_t size = 0;
+    char *buf, *p;
+    int i, ret;
+
+    /* count the msg size */
+    for (i = 0; i < msg->msg_iovlen; i++) {
+        size += msg->msg_iov[i].iov_len;
+    }
+    buf = qemu_malloc(size);
+
+    p = buf;
+    for (i = 0; i < msg->msg_iovlen; i++) {
+        memcpy(p, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+        p += msg->msg_iov[i].iov_len;
+    }
+
+    ret = send(s, buf, size, flags);
+
+    qemu_free(buf);
+    return ret;
+}
+
+static ssize_t recvmsg(int s, struct msghdr *msg, int flags)
+{
+    size_t size = 0;
+    char *buf, *p;
+    int i, ret;
+
+    /* count the msg size */
+    for (i = 0; i < msg->msg_iovlen; i++) {
+        size += msg->msg_iov[i].iov_len;
+    }
+    buf = qemu_malloc(size);
+
+    ret = qemu_recv(s, buf, size, flags);
+    if (ret < 0) {
+        goto out;
+    }
+
+    p = buf;
+    for (i = 0; i < msg->msg_iovlen; i++) {
+        memcpy(msg->msg_iov[i].iov_base, p, msg->msg_iov[i].iov_len);
+        p += msg->msg_iov[i].iov_len;
+    }
+out:
+    qemu_free(buf);
+    return ret;
+}
+
+#endif
+
+/*
+ * Send/recv data with iovec buffers
+ *
+ * This function send/recv data from/to the iovec buffer directly.
+ * The first `offset' bytes in the iovec buffer are skipped and next
+ * `len' bytes are used.
+ *
+ * For example,
+ *
+ *   do_send_recv(sockfd, iov, len, offset, 1);
+ *
+ * is equals to
+ *
+ *   char *buf = malloc(size);
+ *   iov_to_buf(iov, iovcnt, buf, offset, size);
+ *   send(sockfd, buf, size, 0);
+ *   free(buf);
+ */
+static int do_send_recv(int sockfd, struct iovec *iov, int len, int offset,
+                        int write)
+{
+    struct msghdr msg;
+    int ret, diff;
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+    len += offset;
+
+    while (iov->iov_len < len) {
+        len -= iov->iov_len;
+
+        iov++;
+        msg.msg_iovlen++;
+    }
+
+    diff = iov->iov_len - len;
+    iov->iov_len -= diff;
+
+    while (msg.msg_iov->iov_len <= offset) {
+        offset -= msg.msg_iov->iov_len;
+
+        msg.msg_iov++;
+        msg.msg_iovlen--;
+    }
+
+    msg.msg_iov->iov_base = (char *) msg.msg_iov->iov_base + offset;
+    msg.msg_iov->iov_len -= offset;
+
+    if (write) {
+        ret = sendmsg(sockfd, &msg, 0);
+    } else {
+        ret = recvmsg(sockfd, &msg, 0);
+    }
+
+    msg.msg_iov->iov_base = (char *) msg.msg_iov->iov_base - offset;
+    msg.msg_iov->iov_len += offset;
+
+    iov->iov_len += diff;
+    return ret;
+}
+
+static int connect_to_sdog(const char *addr, const char *port)
+{
+    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+    int fd, ret;
+    struct addrinfo hints, *res, *res0;
+
+    if (!addr) {
+        addr = SD_DEFAULT_ADDR;
+        port = SD_DEFAULT_PORT;
+    }
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+
+    ret = getaddrinfo(addr, port, &hints, &res0);
+    if (ret) {
+        error_report("unable to get address info %s, %s",
+                     addr, strerror(errno));
+        return -1;
+    }
+
+    for (res = res0; res; res = res->ai_next) {
+        ret = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
+                          sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+        if (ret) {
+            continue;
+        }
+
+        fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+        if (fd < 0) {
+            continue;
+        }
+
+    reconnect:
+        ret = connect(fd, res->ai_addr, res->ai_addrlen);
+        if (ret < 0) {
+            if (errno == EINTR) {
+                goto reconnect;
+            }
+            break;
+        }
+
+        dprintf("connected to %s:%s\n", addr, port);
+        goto success;
+    }
+    fd = -1;
+    error_report("failed connect to %s:%s", addr, port);
+success:
+    freeaddrinfo(res0);
+    return fd;
+}
+
+static int do_readv_writev(int sockfd, struct iovec *iov, int len,
+                           int iov_offset, int write)
+{
+    int ret;
+again:
+    ret = do_send_recv(sockfd, iov, len, iov_offset, write);
+    if (ret < 0) {
+        if (errno == EINTR || errno == EAGAIN) {
+            goto again;
+        }
+        error_report("failed to recv a rsp, %s", strerror(errno));
+        return 1;
+    }
+
+    iov_offset += ret;
+    len -= ret;
+    if (len) {
+        goto again;
+    }
+
+    return 0;
+}
+
+static int do_readv(int sockfd, struct iovec *iov, int len, int iov_offset)
+{
+    return do_readv_writev(sockfd, iov, len, iov_offset, 0);
+}
+
+static int do_writev(int sockfd, struct iovec *iov, int len, int iov_offset)
+{
+    return do_readv_writev(sockfd, iov, len, iov_offset, 1);
+}
+
+static int do_read_write(int sockfd, void *buf, int len, int write)
+{
+    struct iovec iov;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    return do_readv_writev(sockfd, &iov, len, 0, write);
+}
+
+static int do_read(int sockfd, void *buf, int len)
+{
+    return do_read_write(sockfd, buf, len, 0);
+}
+
+static int do_write(int sockfd, void *buf, int len)
+{
+    return do_read_write(sockfd, buf, len, 1);
+}
+
+static int send_req(int sockfd, SheepdogReq *hdr, void *data,
+                    unsigned int *wlen)
+{
+    int ret;
+    struct iovec iov[2];
+
+    iov[0].iov_base = hdr;
+    iov[0].iov_len = sizeof(*hdr);
+
+    if (*wlen) {
+        iov[1].iov_base = data;
+        iov[1].iov_len = *wlen;
+    }
+
+    ret = do_writev(sockfd, iov, sizeof(*hdr) + *wlen, 0);
+    if (ret) {
+        error_report("failed to send a req, %s", strerror(errno));
+        ret = -1;
+    }
+
+    return ret;
+}
+
+static int do_req(int sockfd, SheepdogReq *hdr, void *data,
+                  unsigned int *wlen, unsigned int *rlen)
+{
+    int ret;
+
+    ret = send_req(sockfd, hdr, data, wlen);
+    if (ret) {
+        ret = -1;
+        goto out;
+    }
+
+    ret = do_read(sockfd, hdr, sizeof(*hdr));
+    if (ret) {
+        error_report("failed to get a rsp, %s", strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    if (*rlen > hdr->data_length) {
+        *rlen = hdr->data_length;
+    }
+
+    if (*rlen) {
+        ret = do_read(sockfd, data, *rlen);
+        if (ret) {
+            error_report("failed to get the data, %s", strerror(errno));
+            ret = -1;
+            goto out;
+        }
+    }
+    ret = 0;
+out:
+    return ret;
+}
+
+static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+                           struct iovec *iov, int niov, int create,
+                           enum AIOCBState aiocb_type);
+
+/*
+ * This function searchs pending requests to the object `oid', and
+ * sends them.
+ */
+static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
+{
+    AIOReq *aio_req, *next;
+    SheepdogAIOCB *acb;
+    int ret;
+
+    QLIST_FOREACH_SAFE(aio_req, &s->outstanding_aio_head,
+                       outstanding_aio_siblings, next) {
+        if (id == aio_req->id) {
+            continue;
+        }
+        if (aio_req->oid != oid) {
+            continue;
+        }
+
+        acb = aio_req->aiocb;
+        ret = add_aio_request(s, aio_req, acb->qiov->iov,
+                              acb->qiov->niov, 0, acb->aiocb_type);
+        if (ret < 0) {
+            error_report("add_aio_request is failed");
+            free_aio_req(s, aio_req);
+            if (QLIST_EMPTY(&acb->aioreq_head)) {
+                sd_finish_aiocb(acb);
+            }
+        }
+    }
+}
+
+/*
+ * Receive responses of the I/O requests.
+ *
+ * This function is registered as a fd handler, and called from the
+ * main loop when s->fd is ready for reading responses.
+ */
+static void aio_read_response(void *opaque)
+{
+    SheepdogObjRsp rsp;
+    BDRVSheepdogState *s = opaque;
+    int fd = s->fd;
+    int ret;
+    AIOReq *aio_req = NULL;
+    SheepdogAIOCB *acb;
+    int rest;
+    unsigned long idx;
+
+    if (QLIST_EMPTY(&s->outstanding_aio_head)) {
+        return;
+    }
+
+    /* read a header */
+    ret = do_read(fd, &rsp, sizeof(rsp));
+    if (ret) {
+        error_report("failed to get the header, %s", strerror(errno));
+        return;
+    }
+
+    /* find the right aio_req from the outstanding_aio list */
+    QLIST_FOREACH(aio_req, &s->outstanding_aio_head, outstanding_aio_siblings) {
+        if (aio_req->id == rsp.id) {
+            break;
+        }
+    }
+    if (!aio_req) {
+        error_report("cannot find aio_req %x", rsp.id);
+        return;
+    }
+
+    acb = aio_req->aiocb;
+
+    switch (acb->aiocb_type) {
+    case AIOCB_WRITE_UDATA:
+        if (!is_data_obj(aio_req->oid)) {
+            break;
+        }
+        idx = data_oid_to_idx(aio_req->oid);
+
+        if (s->inode.data_vdi_id[idx] != s->inode.vdi_id) {
+            /*
+             * If the object is newly created one, we need to update
+             * the vdi object (metadata object).  min_dirty_data_idx
+             * and max_dirty_data_idx are changed to include updated
+             * index between them.
+             */
+            s->inode.data_vdi_id[idx] = s->inode.vdi_id;
+            s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
+            s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
+
+            /*
+             * Some requests may be blocked because simultaneous
+             * create requests are not allowed, so we search the
+             * pending requests here.
+             */
+            send_pending_req(s, vid_to_data_oid(s->inode.vdi_id, idx), rsp.id);
+        }
+        break;
+    case AIOCB_READ_UDATA:
+        ret = do_readv(fd, acb->qiov->iov, rsp.data_length,
+                       aio_req->iov_offset);
+        if (ret) {
+            error_report("failed to get the data, %s", strerror(errno));
+            return;
+        }
+        break;
+    }
+
+    if (rsp.result != SD_RES_SUCCESS) {
+        acb->ret = -EIO;
+        error_report("%s", sd_strerror(rsp.result));
+    }
+
+    rest = free_aio_req(s, aio_req);
+    if (!rest) {
+        /*
+         * We've finished all requests which belong to the AIOCB, so
+         * we can call the callback now.
+         */
+        acb->aio_done_func(acb);
+    }
+}
+
+static int aio_flush_request(void *opaque)
+{
+    BDRVSheepdogState *s = opaque;
+
+    return !QLIST_EMPTY(&s->outstanding_aio_head);
+}
+
+#if !defined(SOL_TCP) || !defined(TCP_CORK)
+
+static int set_cork(int fd, int v)
+{
+    return 0;
+}
+
+#else
+
+static int set_cork(int fd, int v)
+{
+    return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
+}
+
+#endif
+
+static int set_nodelay(int fd)
+{
+    int ret, opt;
+
+    opt = 1;
+    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
+    return ret;
+}
+
+/*
+ * Return a socket discriptor to read/write objects.
+ *
+ * We cannot use this discriptor for other operations because
+ * the block driver may be on waiting response from the server.
+ */
+static int get_sheep_fd(BDRVSheepdogState *s)
+{
+    int ret, fd;
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        error_report("%s", strerror(errno));
+        return -1;
+    }
+
+    socket_set_nonblock(fd);
+
+    ret = set_nodelay(fd);
+    if (ret) {
+        error_report("%s", strerror(errno));
+        closesocket(fd);
+        return -1;
+    }
+
+    qemu_aio_set_fd_handler(fd, aio_read_response, NULL, aio_flush_request,
+                            NULL, s);
+    return fd;
+}
+
+/*
+ * Parse a filename
+ *
+ * filename must be one of the following formats:
+ *   1. [vdiname]
+ *   2. [vdiname]:[snapid]
+ *   3. [vdiname]:[tag]
+ *   4. [hostname]:[port]:[vdiname]
+ *   5. [hostname]:[port]:[vdiname]:[snapid]
+ *   6. [hostname]:[port]:[vdiname]:[tag]
+ *
+ * You can boot from the snapshot images by specifying `snapid` or
+ * `tag'.
+ *
+ * You can run VMs outside the Sheepdog cluster by specifying
+ * `hostname' and `port' (experimental).
+ */
+static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
+                         char *vdi, uint32_t *snapid, char *tag)
+{
+    char *p, *q;
+    int nr_sep;
+
+    p = q = qemu_strdup(filename);
+
+    /* count the number of separators */
+    nr_sep = 0;
+    while (*p) {
+        if (*p == ':') {
+            nr_sep++;
+        }
+        p++;
+    }
+    p = q;
+
+    /* use the first two tokens as hostname and port number. */
+    if (nr_sep >= 2) {
+        s->addr = p;
+        p = strchr(p, ':');
+        *p++ = '\0';
+
+        s->port = p;
+        p = strchr(p, ':');
+        *p++ = '\0';
+    } else {
+        s->addr = NULL;
+        s->port = 0;
+    }
+
+    strncpy(vdi, p, SD_MAX_VDI_LEN);
+
+    p = strchr(vdi, ':');
+    if (p) {
+        *p++ = '\0';
+        *snapid = strtoul(p, NULL, 10);
+        if (*snapid == 0) {
+            strncpy(tag, p, SD_MAX_VDI_TAG_LEN);
+        }
+    } else {
+        *snapid = CURRENT_VDI_ID; /* search current vdi */
+    }
+
+    if (s->addr == NULL) {
+        qemu_free(q);
+    }
+
+    return 0;
+}
+
+static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
+                         char *tag, uint32_t *vid, int for_snapshot)
+{
+    int ret, fd;
+    SheepdogVdiReq hdr;
+    SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
+    unsigned int wlen, rlen = 0;
+    char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        return -1;
+    }
+
+    memset(buf, 0, sizeof(buf));
+    strncpy(buf, filename, SD_MAX_VDI_LEN);
+    strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
+
+    memset(&hdr, 0, sizeof(hdr));
+    if (for_snapshot) {
+        hdr.opcode = SD_OP_GET_VDI_INFO;
+    } else {
+        hdr.opcode = SD_OP_LOCK_VDI;
+    }
+    wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
+    hdr.proto_ver = SD_PROTO_VER;
+    hdr.data_length = wlen;
+    hdr.snapid = snapid;
+    hdr.flags = SD_FLAG_CMD_WRITE;
+
+    ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+    if (ret) {
+        ret = -1;
+        goto out;
+    }
+
+    if (rsp->result != SD_RES_SUCCESS) {
+        error_report("cannot get vdi info, %s, %s %d %s",
+                     sd_strerror(rsp->result), filename, snapid, tag);
+        ret = -1;
+        goto out;
+    }
+    *vid = rsp->vdi_id;
+
+    ret = 0;
+out:
+    closesocket(fd);
+    return ret;
+}
+
+static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+                           struct iovec *iov, int niov, int create,
+                           enum AIOCBState aiocb_type)
+{
+    int nr_copies = s->inode.nr_copies;
+    SheepdogObjReq hdr;
+    unsigned int wlen;
+    int ret;
+    uint64_t oid = aio_req->oid;
+    unsigned int datalen = aio_req->data_len;
+    uint64_t offset = aio_req->offset;
+    uint8_t flags = aio_req->flags;
+    uint64_t old_oid = aio_req->base_oid;
+
+    if (!nr_copies) {
+        error_report("bug");
+    }
+
+    memset(&hdr, 0, sizeof(hdr));
+
+    if (aiocb_type == AIOCB_READ_UDATA) {
+        wlen = 0;
+        hdr.opcode = SD_OP_READ_OBJ;
+        hdr.flags = flags;
+    } else if (create) {
+        wlen = datalen;
+        hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
+        hdr.flags = SD_FLAG_CMD_WRITE | flags;
+    } else {
+        wlen = datalen;
+        hdr.opcode = SD_OP_WRITE_OBJ;
+        hdr.flags = SD_FLAG_CMD_WRITE | flags;
+    }
+
+    hdr.oid = oid;
+    hdr.cow_oid = old_oid;
+    hdr.copies = s->inode.nr_copies;
+
+    hdr.data_length = datalen;
+    hdr.offset = offset;
+
+    hdr.id = aio_req->id;
+
+    set_cork(s->fd, 1);
+
+    /* send a header */
+    ret = do_write(s->fd, &hdr, sizeof(hdr));
+    if (ret) {
+        error_report("failed to send a req, %s", strerror(errno));
+        return -EIO;
+    }
+
+    if (wlen) {
+        ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset);
+        if (ret) {
+            error_report("failed to send a data, %s", strerror(errno));
+            return -EIO;
+        }
+    }
+
+    set_cork(s->fd, 0);
+
+    return 0;
+}
+
+static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
+                             unsigned int datalen, uint64_t offset,
+                             int write, int create)
+{
+    SheepdogObjReq hdr;
+    SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
+    unsigned int wlen, rlen;
+    int ret;
+
+    memset(&hdr, 0, sizeof(hdr));
+
+    if (write) {
+        wlen = datalen;
+        rlen = 0;
+        hdr.flags = SD_FLAG_CMD_WRITE;
+        if (create) {
+            hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
+        } else {
+            hdr.opcode = SD_OP_WRITE_OBJ;
+        }
+    } else {
+        wlen = 0;
+        rlen = datalen;
+        hdr.opcode = SD_OP_READ_OBJ;
+    }
+    hdr.oid = oid;
+    hdr.data_length = datalen;
+    hdr.offset = offset;
+    hdr.copies = copies;
+
+    ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+    if (ret) {
+        error_report("failed to send a request to the sheep");
+        return -1;
+    }
+
+    switch (rsp->result) {
+    case SD_RES_SUCCESS:
+        return 0;
+    default:
+        error_report("%s", sd_strerror(rsp->result));
+        return -1;
+    }
+}
+
+static int read_object(int fd, char *buf, uint64_t oid, int copies,
+                       unsigned int datalen, uint64_t offset)
+{
+    return read_write_object(fd, buf, oid, copies, datalen, offset, 0, 0);
+}
+
+static int write_object(int fd, char *buf, uint64_t oid, int copies,
+                        unsigned int datalen, uint64_t offset, int create)
+{
+    return read_write_object(fd, buf, oid, copies, datalen, offset, 1, create);
+}
+
+static int sd_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    int ret, fd;
+    uint32_t vid = 0;
+    BDRVSheepdogState *s = bs->opaque;
+    char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+    uint32_t snapid;
+    char *buf = NULL;
+
+    strstart(filename, "sheepdog:", (const char **)&filename);
+
+    QLIST_INIT(&s->outstanding_aio_head);
+    s->fd = -1;
+
+    memset(vdi, 0, sizeof(vdi));
+    memset(tag, 0, sizeof(tag));
+    if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) {
+        goto out;
+    }
+    s->fd = get_sheep_fd(s);
+    if (s->fd < 0) {
+        goto out;
+    }
+
+    ret = find_vdi_name(s, vdi, snapid, tag, &vid, 0);
+    if (ret) {
+        goto out;
+    }
+
+    if (snapid) {
+        dprintf("%" PRIx32 " snapshot inode was open.\n", vid);
+        s->is_snapshot = 1;
+    }
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        error_report("failed to connect");
+        goto out;
+    }
+
+    buf = qemu_malloc(SD_INODE_SIZE);
+    ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0);
+
+    closesocket(fd);
+
+    if (ret) {
+        goto out;
+    }
+
+    memcpy(&s->inode, buf, sizeof(s->inode));
+    s->min_dirty_data_idx = UINT32_MAX;
+    s->max_dirty_data_idx = 0;
+
+    bs->total_sectors = s->inode.vdi_size / SECTOR_SIZE;
+    strncpy(s->name, vdi, sizeof(s->name));
+    qemu_free(buf);
+    return 0;
+out:
+    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+    if (s->fd >= 0) {
+        closesocket(s->fd);
+    }
+    qemu_free(buf);
+    return -1;
+}
+
+static int do_sd_create(char *filename, int64_t vdi_size,
+                        uint32_t base_vid, uint32_t *vdi_id, int snapshot,
+                        const char *addr, const char *port)
+{
+    SheepdogVdiReq hdr;
+    SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
+    int fd, ret;
+    unsigned int wlen, rlen = 0;
+    char buf[SD_MAX_VDI_LEN];
+
+    fd = connect_to_sdog(addr, port);
+    if (fd < 0) {
+        return -EIO;
+    }
+
+    memset(buf, 0, sizeof(buf));
+    strncpy(buf, filename, SD_MAX_VDI_LEN);
+
+    memset(&hdr, 0, sizeof(hdr));
+    hdr.opcode = SD_OP_NEW_VDI;
+    hdr.base_vdi_id = base_vid;
+
+    wlen = SD_MAX_VDI_LEN;
+
+    hdr.flags = SD_FLAG_CMD_WRITE;
+    hdr.snapid = snapshot;
+
+    hdr.data_length = wlen;
+    hdr.vdi_size = vdi_size;
+
+    ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+
+    closesocket(fd);
+
+    if (ret) {
+        return -EIO;
+    }
+
+    if (rsp->result != SD_RES_SUCCESS) {
+        error_report("%s, %s", sd_strerror(rsp->result), filename);
+        return -EIO;
+    }
+
+    if (vdi_id) {
+        *vdi_id = rsp->vdi_id;
+    }
+
+    return 0;
+}
+
+static int sd_prealloc(const char *filename)
+{
+    BlockDriverState *bs = NULL;
+    uint32_t idx, max_idx;
+    int64_t vdi_size;
+    void *buf = qemu_mallocz(SD_DATA_OBJ_SIZE);
+    int ret;
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        goto out;
+    }
+
+    vdi_size = bdrv_getlength(bs);
+    if (vdi_size < 0) {
+        ret = vdi_size;
+        goto out;
+    }
+    max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
+
+    for (idx = 0; idx < max_idx; idx++) {
+        /*
+         * The created image can be a cloned image, so we need to read
+         * a data from the source image.
+         */
+        ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+        ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+out:
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    qemu_free(buf);
+
+    return ret;
+}
+
+static int sd_create(const char *filename, QEMUOptionParameter *options)
+{
+    int ret;
+    uint32_t vid = 0, base_vid = 0;
+    int64_t vdi_size = 0;
+    char *backing_file = NULL;
+    BDRVSheepdogState s;
+    char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+    uint32_t snapid;
+    int prealloc = 0;
+    const char *vdiname;
+
+    strstart(filename, "sheepdog:", &vdiname);
+
+    memset(&s, 0, sizeof(s));
+    memset(vdi, 0, sizeof(vdi));
+    memset(tag, 0, sizeof(tag));
+    if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
+        error_report("invalid filename");
+        return -EINVAL;
+    }
+
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            vdi_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
+            if (!options->value.s || !strcmp(options->value.s, "off")) {
+                prealloc = 0;
+            } else if (!strcmp(options->value.s, "full")) {
+                prealloc = 1;
+            } else {
+                error_report("Invalid preallocation mode: '%s'",
+                             options->value.s);
+                return -EINVAL;
+            }
+        }
+        options++;
+    }
+
+    if (vdi_size > SD_MAX_VDI_SIZE) {
+        error_report("too big image size");
+        return -EINVAL;
+    }
+
+    if (backing_file) {
+        BlockDriverState *bs;
+        BDRVSheepdogState *s;
+        BlockDriver *drv;
+
+        /* Currently, only Sheepdog backing image is supported. */
+        drv = bdrv_find_protocol(backing_file);
+        if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
+            error_report("backing_file must be a sheepdog image");
+            return -EINVAL;
+        }
+
+        ret = bdrv_file_open(&bs, backing_file, 0);
+        if (ret < 0)
+            return -EIO;
+
+        s = bs->opaque;
+
+        if (!is_snapshot(&s->inode)) {
+            error_report("cannot clone from a non snapshot vdi");
+            bdrv_delete(bs);
+            return -EINVAL;
+        }
+
+        base_vid = s->inode.vdi_id;
+        bdrv_delete(bs);
+    }
+
+    ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+    if (!prealloc || ret) {
+        return ret;
+    }
+
+    return sd_prealloc(filename);
+}
+
+static void sd_close(BlockDriverState *bs)
+{
+    BDRVSheepdogState *s = bs->opaque;
+    SheepdogVdiReq hdr;
+    SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
+    unsigned int wlen, rlen = 0;
+    int fd, ret;
+
+    dprintf("%s\n", s->name);
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        return;
+    }
+
+    memset(&hdr, 0, sizeof(hdr));
+
+    hdr.opcode = SD_OP_RELEASE_VDI;
+    wlen = strlen(s->name) + 1;
+    hdr.data_length = wlen;
+    hdr.flags = SD_FLAG_CMD_WRITE;
+
+    ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen);
+
+    closesocket(fd);
+
+    if (!ret && rsp->result != SD_RES_SUCCESS &&
+        rsp->result != SD_RES_VDI_NOT_LOCKED) {
+        error_report("%s, %s", sd_strerror(rsp->result), s->name);
+    }
+
+    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+    closesocket(s->fd);
+    qemu_free(s->addr);
+}
+
+static int64_t sd_getlength(BlockDriverState *bs)
+{
+    BDRVSheepdogState *s = bs->opaque;
+
+    return s->inode.vdi_size;
+}
+
+static int sd_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVSheepdogState *s = bs->opaque;
+    int ret, fd;
+    unsigned int datalen;
+
+    if (offset < s->inode.vdi_size) {
+        error_report("shrinking is not supported");
+        return -EINVAL;
+    } else if (offset > SD_MAX_VDI_SIZE) {
+        error_report("too big image size");
+        return -EINVAL;
+    }
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        return -EIO;
+    }
+
+    /* we don't need to update entire object */
+    datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
+    s->inode.vdi_size = offset;
+    ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
+                       s->inode.nr_copies, datalen, 0, 0);
+    close(fd);
+
+    if (ret < 0) {
+        error_report("failed to update an inode.");
+        return -EIO;
+    }
+
+    return 0;
+}
+
+/*
+ * This function is called after writing data objects.  If we need to
+ * update metadata, this sends a write request to the vdi object.
+ * Otherwise, this calls the AIOCB callback.
+ */
+static void sd_write_done(SheepdogAIOCB *acb)
+{
+    int ret;
+    BDRVSheepdogState *s = acb->common.bs->opaque;
+    struct iovec iov;
+    AIOReq *aio_req;
+    uint32_t offset, data_len, mn, mx;
+
+    mn = s->min_dirty_data_idx;
+    mx = s->max_dirty_data_idx;
+    if (mn <= mx) {
+        /* we need to update the vdi object. */
+        offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) +
+            mn * sizeof(s->inode.data_vdi_id[0]);
+        data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]);
+
+        s->min_dirty_data_idx = UINT32_MAX;
+        s->max_dirty_data_idx = 0;
+
+        iov.iov_base = &s->inode;
+        iov.iov_len = sizeof(s->inode);
+        aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
+                                data_len, offset, 0, 0, offset);
+        ret = add_aio_request(s, aio_req, &iov, 1, 0, AIOCB_WRITE_UDATA);
+        if (ret) {
+            free_aio_req(s, aio_req);
+            acb->ret = -EIO;
+            goto out;
+        }
+
+        acb->aio_done_func = sd_finish_aiocb;
+        acb->aiocb_type = AIOCB_WRITE_UDATA;
+        return;
+    }
+out:
+    sd_finish_aiocb(acb);
+}
+
+/*
+ * Create a writable VDI from a snapshot
+ */
+static int sd_create_branch(BDRVSheepdogState *s)
+{
+    int ret, fd;
+    uint32_t vid;
+    char *buf;
+
+    dprintf("%" PRIx32 " is snapshot.\n", s->inode.vdi_id);
+
+    buf = qemu_malloc(SD_INODE_SIZE);
+
+    ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1,
+                       s->addr, s->port);
+    if (ret) {
+        goto out;
+    }
+
+    dprintf("%" PRIx32 " is created.\n", vid);
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        error_report("failed to connect");
+        goto out;
+    }
+
+    ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
+                      SD_INODE_SIZE, 0);
+
+    closesocket(fd);
+
+    if (ret < 0) {
+        goto out;
+    }
+
+    memcpy(&s->inode, buf, sizeof(s->inode));
+
+    s->is_snapshot = 0;
+    ret = 0;
+    dprintf("%" PRIx32 " was newly created.\n", s->inode.vdi_id);
+
+out:
+    qemu_free(buf);
+
+    return ret;
+}
+
+/*
+ * Send I/O requests to the server.
+ *
+ * This function sends requests to the server, links the requests to
+ * the outstanding_list in BDRVSheepdogState, and exits without
+ * waiting the response.  The responses are received in the
+ * `aio_read_response' function which is called from the main loop as
+ * a fd handler.
+ */
+static void sd_readv_writev_bh_cb(void *p)
+{
+    SheepdogAIOCB *acb = p;
+    int ret = 0;
+    unsigned long len, done = 0, total = acb->nb_sectors * SECTOR_SIZE;
+    unsigned long idx = acb->sector_num * SECTOR_SIZE / SD_DATA_OBJ_SIZE;
+    uint64_t oid;
+    uint64_t offset = (acb->sector_num * SECTOR_SIZE) % SD_DATA_OBJ_SIZE;
+    BDRVSheepdogState *s = acb->common.bs->opaque;
+    SheepdogInode *inode = &s->inode;
+    AIOReq *aio_req;
+
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    if (acb->aiocb_type == AIOCB_WRITE_UDATA && s->is_snapshot) {
+        /*
+         * In the case we open the snapshot VDI, Sheepdog creates the
+         * writable VDI when we do a write operation first.
+         */
+        ret = sd_create_branch(s);
+        if (ret) {
+            acb->ret = -EIO;
+            goto out;
+        }
+    }
+
+    while (done != total) {
+        uint8_t flags = 0;
+        uint64_t old_oid = 0;
+        int create = 0;
+
+        oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+
+        len = MIN(total - done, SD_DATA_OBJ_SIZE - offset);
+
+        if (!inode->data_vdi_id[idx]) {
+            if (acb->aiocb_type == AIOCB_READ_UDATA) {
+                goto done;
+            }
+
+            create = 1;
+        } else if (acb->aiocb_type == AIOCB_WRITE_UDATA
+                   && !is_data_obj_writable(inode, idx)) {
+            /* Copy-On-Write */
+            create = 1;
+            old_oid = oid;
+            flags = SD_FLAG_CMD_COW;
+        }
+
+        if (create) {
+            dprintf("update ino (%" PRIu32") %" PRIu64 " %" PRIu64
+                    " %" PRIu64 "\n", inode->vdi_id, oid,
+                    vid_to_data_oid(inode->data_vdi_id[idx], idx), idx);
+            oid = vid_to_data_oid(inode->vdi_id, idx);
+            dprintf("new oid %lx\n", oid);
+        }
+
+        aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, old_oid, done);
+
+        if (create) {
+            AIOReq *areq;
+            QLIST_FOREACH(areq, &s->outstanding_aio_head,
+                          outstanding_aio_siblings) {
+                if (areq == aio_req) {
+                    continue;
+                }
+                if (areq->oid == oid) {
+                    /*
+                     * Sheepdog cannot handle simultaneous create
+                     * requests to the same object.  So we cannot send
+                     * the request until the previous request
+                     * finishes.
+                     */
+                    aio_req->flags = 0;
+                    aio_req->base_oid = 0;
+                    goto done;
+                }
+            }
+        }
+
+        ret = add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
+                              create, acb->aiocb_type);
+        if (ret < 0) {
+            error_report("add_aio_request is failed");
+            free_aio_req(s, aio_req);
+            acb->ret = -EIO;
+            goto out;
+        }
+    done:
+        offset = 0;
+        idx++;
+        done += len;
+    }
+out:
+    if (QLIST_EMPTY(&acb->aioreq_head)) {
+        sd_finish_aiocb(acb);
+    }
+}
+
+static BlockDriverAIOCB *sd_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                                       QEMUIOVector *qiov, int nb_sectors,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque)
+{
+    SheepdogAIOCB *acb;
+
+    if (bs->growable && sector_num + nb_sectors > bs->total_sectors) {
+        /* TODO: shouldn't block here */
+        if (sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE) < 0) {
+            return NULL;
+        }
+        bs->total_sectors = sector_num + nb_sectors;
+    }
+
+    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, cb, opaque);
+    acb->aio_done_func = sd_write_done;
+    acb->aiocb_type = AIOCB_WRITE_UDATA;
+
+    sd_schedule_bh(sd_readv_writev_bh_cb, acb);
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *sd_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                                      QEMUIOVector *qiov, int nb_sectors,
+                                      BlockDriverCompletionFunc *cb,
+                                      void *opaque)
+{
+    SheepdogAIOCB *acb;
+    int i;
+
+    acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, cb, opaque);
+    acb->aiocb_type = AIOCB_READ_UDATA;
+    acb->aio_done_func = sd_finish_aiocb;
+
+    /*
+     * TODO: we can do better; we don't need to initialize
+     * blindly.
+     */
+    for (i = 0; i < qiov->niov; i++) {
+        memset(qiov->iov[i].iov_base, 0, qiov->iov[i].iov_len);
+    }
+
+    sd_schedule_bh(sd_readv_writev_bh_cb, acb);
+    return &acb->common;
+}
+
+static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+{
+    BDRVSheepdogState *s = bs->opaque;
+    int ret, fd;
+    uint32_t new_vid;
+    SheepdogInode *inode;
+    unsigned int datalen;
+
+    dprintf("sn_info: name %s id_str %s s: name %s vm_state_size %d "
+            "is_snapshot %d\n", sn_info->name, sn_info->id_str,
+            s->name, sn_info->vm_state_size, s->is_snapshot);
+
+    if (s->is_snapshot) {
+        error_report("You can't create a snapshot of a snapshot VDI, "
+                     "%s (%" PRIu32 ").", s->name, s->inode.vdi_id);
+
+        return -EINVAL;
+    }
+
+    dprintf("%s %s\n", sn_info->name, sn_info->id_str);
+
+    s->inode.vm_state_size = sn_info->vm_state_size;
+    s->inode.vm_clock_nsec = sn_info->vm_clock_nsec;
+    strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
+    /* we don't need to update entire object */
+    datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
+
+    /* refresh inode. */
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        ret = -EIO;
+        goto cleanup;
+    }
+
+    ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
+                       s->inode.nr_copies, datalen, 0, 0);
+    if (ret < 0) {
+        error_report("failed to write snapshot's inode.");
+        ret = -EIO;
+        goto cleanup;
+    }
+
+    ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1,
+                       s->addr, s->port);
+    if (ret < 0) {
+        error_report("failed to create inode for snapshot. %s",
+                     strerror(errno));
+        ret = -EIO;
+        goto cleanup;
+    }
+
+    inode = (SheepdogInode *)qemu_malloc(datalen);
+
+    ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
+                      s->inode.nr_copies, datalen, 0);
+
+    if (ret < 0) {
+        error_report("failed to read new inode info. %s", strerror(errno));
+        ret = -EIO;
+        goto cleanup;
+    }
+
+    memcpy(&s->inode, inode, datalen);
+    dprintf("s->inode: name %s snap_id %x oid %x\n",
+            s->inode.name, s->inode.snap_id, s->inode.vdi_id);
+
+cleanup:
+    closesocket(fd);
+    return ret;
+}
+
+static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVSheepdogState *s = bs->opaque;
+    BDRVSheepdogState *old_s;
+    char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+    char *buf = NULL;
+    uint32_t vid;
+    uint32_t snapid = 0;
+    int ret = -ENOENT, fd;
+
+    old_s = qemu_malloc(sizeof(BDRVSheepdogState));
+
+    memcpy(old_s, s, sizeof(BDRVSheepdogState));
+
+    memset(vdi, 0, sizeof(vdi));
+    strncpy(vdi, s->name, sizeof(vdi));
+
+    memset(tag, 0, sizeof(tag));
+    snapid = strtoul(snapshot_id, NULL, 10);
+    if (!snapid) {
+        strncpy(tag, s->name, sizeof(tag));
+    }
+
+    ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
+    if (ret) {
+        error_report("Failed to find_vdi_name");
+        ret = -ENOENT;
+        goto out;
+    }
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        error_report("failed to connect");
+        goto out;
+    }
+
+    buf = qemu_malloc(SD_INODE_SIZE);
+    ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
+                      SD_INODE_SIZE, 0);
+
+    closesocket(fd);
+
+    if (ret) {
+        ret = -ENOENT;
+        goto out;
+    }
+
+    memcpy(&s->inode, buf, sizeof(s->inode));
+
+    if (!s->inode.vm_state_size) {
+        error_report("Invalid snapshot");
+        ret = -ENOENT;
+        goto out;
+    }
+
+    s->is_snapshot = 1;
+
+    qemu_free(buf);
+    qemu_free(old_s);
+
+    return 0;
+out:
+    /* recover bdrv_sd_state */
+    memcpy(s, old_s, sizeof(BDRVSheepdogState));
+    qemu_free(buf);
+    qemu_free(old_s);
+
+    error_report("failed to open. recover old bdrv_sd_state.");
+
+    return ret;
+}
+
+static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    /* FIXME: Delete specified snapshot id.  */
+    return 0;
+}
+
+static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+{
+    BDRVSheepdogState *s = bs->opaque;
+    SheepdogReq req;
+    int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
+    QEMUSnapshotInfo *sn_tab = NULL;
+    unsigned wlen, rlen;
+    int found = 0;
+    static SheepdogInode inode;
+    unsigned long *vdi_inuse;
+    unsigned int start_nr;
+    uint64_t hval;
+    uint32_t vid;
+
+    vdi_inuse = qemu_malloc(max);
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        goto out;
+    }
+
+    rlen = max;
+    wlen = 0;
+
+    memset(&req, 0, sizeof(req));
+
+    req.opcode = SD_OP_READ_VDIS;
+    req.data_length = max;
+
+    ret = do_req(fd, (SheepdogReq *)&req, vdi_inuse, &wlen, &rlen);
+
+    closesocket(fd);
+    if (ret) {
+        goto out;
+    }
+
+    sn_tab = qemu_mallocz(nr * sizeof(*sn_tab));
+
+    /* calculate a vdi id with hash function */
+    hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
+    start_nr = hval & (SD_NR_VDIS - 1);
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        error_report("failed to connect");
+        goto out;
+    }
+
+    for (vid = start_nr; found < nr; vid = (vid + 1) % SD_NR_VDIS) {
+        if (!test_bit(vid, vdi_inuse)) {
+            break;
+        }
+
+        /* we don't need to read entire object */
+        ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
+                          0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0);
+
+        if (ret) {
+            continue;
+        }
+
+        if (!strcmp(inode.name, s->name) && is_snapshot(&inode)) {
+            sn_tab[found].date_sec = inode.snap_ctime >> 32;
+            sn_tab[found].date_nsec = inode.snap_ctime & 0xffffffff;
+            sn_tab[found].vm_state_size = inode.vm_state_size;
+            sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
+
+            snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
+                     inode.snap_id);
+            strncpy(sn_tab[found].name, inode.tag,
+                    MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)));
+            found++;
+        }
+    }
+
+    closesocket(fd);
+out:
+    *psn_tab = sn_tab;
+
+    qemu_free(vdi_inuse);
+
+    return found;
+}
+
+static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
+                                int64_t pos, int size, int load)
+{
+    int fd, create;
+    int ret = 0;
+    unsigned int data_len;
+    uint64_t vmstate_oid;
+    uint32_t vdi_index;
+    uint64_t offset;
+
+    fd = connect_to_sdog(s->addr, s->port);
+    if (fd < 0) {
+        ret = -EIO;
+        goto cleanup;
+    }
+
+    while (size) {
+        vdi_index = pos / SD_DATA_OBJ_SIZE;
+        offset = pos % SD_DATA_OBJ_SIZE;
+
+        data_len = MIN(size, SD_DATA_OBJ_SIZE);
+
+        vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index);
+
+        create = (offset == 0);
+        if (load) {
+            ret = read_object(fd, (char *)data, vmstate_oid,
+                              s->inode.nr_copies, data_len, offset);
+        } else {
+            ret = write_object(fd, (char *)data, vmstate_oid,
+                               s->inode.nr_copies, data_len, offset, create);
+        }
+
+        if (ret < 0) {
+            error_report("failed to save vmstate %s", strerror(errno));
+            ret = -EIO;
+            goto cleanup;
+        }
+
+        pos += data_len;
+        size -= data_len;
+        ret += data_len;
+    }
+cleanup:
+    closesocket(fd);
+    return ret;
+}
+
+static int sd_save_vmstate(BlockDriverState *bs, const uint8_t *data,
+                           int64_t pos, int size)
+{
+    BDRVSheepdogState *s = bs->opaque;
+
+    return do_load_save_vmstate(s, (uint8_t *)data, pos, size, 0);
+}
+
+static int sd_load_vmstate(BlockDriverState *bs, uint8_t *data,
+                           int64_t pos, int size)
+{
+    BDRVSheepdogState *s = bs->opaque;
+
+    return do_load_save_vmstate(s, data, pos, size, 1);
+}
+
+
+static QEMUOptionParameter sd_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_PREALLOC,
+        .type = OPT_STRING,
+        .help = "Preallocation mode (allowed values: off, full)"
+    },
+    { NULL }
+};
+
+BlockDriver bdrv_sheepdog = {
+    .format_name    = "sheepdog",
+    .protocol_name  = "sheepdog",
+    .instance_size  = sizeof(BDRVSheepdogState),
+    .bdrv_file_open = sd_open,
+    .bdrv_close     = sd_close,
+    .bdrv_create    = sd_create,
+    .bdrv_getlength = sd_getlength,
+    .bdrv_truncate  = sd_truncate,
+
+    .bdrv_aio_readv     = sd_aio_readv,
+    .bdrv_aio_writev    = sd_aio_writev,
+
+    .bdrv_snapshot_create   = sd_snapshot_create,
+    .bdrv_snapshot_goto     = sd_snapshot_goto,
+    .bdrv_snapshot_delete   = sd_snapshot_delete,
+    .bdrv_snapshot_list     = sd_snapshot_list,
+
+    .bdrv_save_vmstate  = sd_save_vmstate,
+    .bdrv_load_vmstate  = sd_load_vmstate,
+
+    .create_options = sd_create_options,
+};
+
+static void bdrv_sheepdog_init(void)
+{
+    bdrv_register(&bdrv_sheepdog);
+}
+block_init(bdrv_sheepdog_init);
diff --git a/qemu-0.15.x/block/vdi.c b/qemu-0.15.x/block/vdi.c
new file mode 100644
index 0000000..261cf9b
--- /dev/null
+++ b/qemu-0.15.x/block/vdi.c
@@ -0,0 +1,999 @@
+/*
+ * Block driver for the Virtual Disk Image (VDI) format
+ *
+ * Copyright (c) 2009 Stefan Weil
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) version 3 or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Reference:
+ * http://forums.virtualbox.org/viewtopic.php?t=8046
+ *
+ * This driver supports create / read / write operations on VDI images.
+ *
+ * Todo (see also TODO in code):
+ *
+ * Some features like snapshots are still missing.
+ *
+ * Deallocation of zero-filled blocks and shrinking images are missing, too
+ * (might be added to common block layer).
+ *
+ * Allocation of blocks could be optimized (less writes to block map and
+ * header).
+ *
+ * Read and write of adjacents blocks could be done in one operation
+ * (current code uses one operation per block (1 MiB).
+ *
+ * The code is not thread safe (missing locks for changes in header and
+ * block table, no problem with current QEMU).
+ *
+ * Hints:
+ *
+ * Blocks (VDI documentation) correspond to clusters (QEMU).
+ * QEMU's backing files could be implemented using VDI snapshot files (TODO).
+ * VDI snapshot files may also contain the complete machine state.
+ * Maybe this machine state can be converted to QEMU PC machine snapshot data.
+ *
+ * The driver keeps a block cache (little endian entries) in memory.
+ * For the standard block size (1 MiB), a 1 TiB disk will use 4 MiB RAM,
+ * so this seems to be reasonable.
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+#if defined(CONFIG_UUID)
+#include <uuid/uuid.h>
+#else
+/* TODO: move uuid emulation to some central place in QEMU. */
+#include "sysemu.h"     /* UUID_FMT */
+typedef unsigned char uuid_t[16];
+void uuid_generate(uuid_t out);
+int uuid_is_null(const uuid_t uu);
+void uuid_unparse(const uuid_t uu, char *out);
+#endif
+
+/* Code configuration options. */
+
+/* Enable debug messages. */
+//~ #define CONFIG_VDI_DEBUG
+
+/* Support write operations on VDI images. */
+#define CONFIG_VDI_WRITE
+
+/* Support non-standard block (cluster) size. This is untested.
+ * Maybe it will be needed for very large images.
+ */
+//~ #define CONFIG_VDI_BLOCK_SIZE
+
+/* Support static (fixed, pre-allocated) images. */
+#define CONFIG_VDI_STATIC_IMAGE
+
+/* Command line option for static images. */
+#define BLOCK_OPT_STATIC "static"
+
+#define KiB     1024
+#define MiB     (KiB * KiB)
+
+#define SECTOR_SIZE 512
+#define DEFAULT_CLUSTER_SIZE (1 * MiB)
+
+#if defined(CONFIG_VDI_DEBUG)
+#define logout(fmt, ...) \
+                fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+/* Image signature. */
+#define VDI_SIGNATURE 0xbeda107f
+
+/* Image version. */
+#define VDI_VERSION_1_1 0x00010001
+
+/* Image type. */
+#define VDI_TYPE_DYNAMIC 1
+#define VDI_TYPE_STATIC  2
+
+/* Innotek / SUN images use these strings in header.text:
+ * "<<< innotek VirtualBox Disk Image >>>\n"
+ * "<<< Sun xVM VirtualBox Disk Image >>>\n"
+ * "<<< Sun VirtualBox Disk Image >>>\n"
+ * The value does not matter, so QEMU created images use a different text.
+ */
+#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
+
+/* Unallocated blocks use this index (no need to convert endianness). */
+#define VDI_UNALLOCATED UINT32_MAX
+
+#if !defined(CONFIG_UUID)
+void uuid_generate(uuid_t out)
+{
+    memset(out, 0, sizeof(uuid_t));
+}
+
+int uuid_is_null(const uuid_t uu)
+{
+    uuid_t null_uuid = { 0 };
+    return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
+}
+
+void uuid_unparse(const uuid_t uu, char *out)
+{
+    snprintf(out, 37, UUID_FMT,
+            uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
+            uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
+}
+#endif
+
+typedef struct {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    QEMUIOVector *qiov;
+    uint8_t *buf;
+    /* Total number of sectors. */
+    int nb_sectors;
+    /* Number of sectors for current AIO. */
+    int n_sectors;
+    /* New allocated block map entry. */
+    uint32_t bmap_first;
+    uint32_t bmap_last;
+    /* Buffer for new allocated block. */
+    void *block_buffer;
+    void *orig_buf;
+    bool is_write;
+    int header_modified;
+    BlockDriverAIOCB *hd_aiocb;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
+    QEMUBH *bh;
+} VdiAIOCB;
+
+typedef struct {
+    char text[0x40];
+    uint32_t signature;
+    uint32_t version;
+    uint32_t header_size;
+    uint32_t image_type;
+    uint32_t image_flags;
+    char description[256];
+    uint32_t offset_bmap;
+    uint32_t offset_data;
+    uint32_t cylinders;         /* disk geometry, unused here */
+    uint32_t heads;             /* disk geometry, unused here */
+    uint32_t sectors;           /* disk geometry, unused here */
+    uint32_t sector_size;
+    uint32_t unused1;
+    uint64_t disk_size;
+    uint32_t block_size;
+    uint32_t block_extra;       /* unused here */
+    uint32_t blocks_in_image;
+    uint32_t blocks_allocated;
+    uuid_t uuid_image;
+    uuid_t uuid_last_snap;
+    uuid_t uuid_link;
+    uuid_t uuid_parent;
+    uint64_t unused2[7];
+} VdiHeader;
+
+typedef struct {
+    /* The block map entries are little endian (even in memory). */
+    uint32_t *bmap;
+    /* Size of block (bytes). */
+    uint32_t block_size;
+    /* Size of block (sectors). */
+    uint32_t block_sectors;
+    /* First sector of block map. */
+    uint32_t bmap_sector;
+    /* VDI header (converted to host endianness). */
+    VdiHeader header;
+} BDRVVdiState;
+
+/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
+ * format (network byte order, standard, see RFC 4122) and vice versa.
+ */
+static void uuid_convert(uuid_t uuid)
+{
+    bswap32s((uint32_t *)&uuid[0]);
+    bswap16s((uint16_t *)&uuid[4]);
+    bswap16s((uint16_t *)&uuid[6]);
+}
+
+static void vdi_header_to_cpu(VdiHeader *header)
+{
+    le32_to_cpus(&header->signature);
+    le32_to_cpus(&header->version);
+    le32_to_cpus(&header->header_size);
+    le32_to_cpus(&header->image_type);
+    le32_to_cpus(&header->image_flags);
+    le32_to_cpus(&header->offset_bmap);
+    le32_to_cpus(&header->offset_data);
+    le32_to_cpus(&header->cylinders);
+    le32_to_cpus(&header->heads);
+    le32_to_cpus(&header->sectors);
+    le32_to_cpus(&header->sector_size);
+    le64_to_cpus(&header->disk_size);
+    le32_to_cpus(&header->block_size);
+    le32_to_cpus(&header->block_extra);
+    le32_to_cpus(&header->blocks_in_image);
+    le32_to_cpus(&header->blocks_allocated);
+    uuid_convert(header->uuid_image);
+    uuid_convert(header->uuid_last_snap);
+    uuid_convert(header->uuid_link);
+    uuid_convert(header->uuid_parent);
+}
+
+static void vdi_header_to_le(VdiHeader *header)
+{
+    cpu_to_le32s(&header->signature);
+    cpu_to_le32s(&header->version);
+    cpu_to_le32s(&header->header_size);
+    cpu_to_le32s(&header->image_type);
+    cpu_to_le32s(&header->image_flags);
+    cpu_to_le32s(&header->offset_bmap);
+    cpu_to_le32s(&header->offset_data);
+    cpu_to_le32s(&header->cylinders);
+    cpu_to_le32s(&header->heads);
+    cpu_to_le32s(&header->sectors);
+    cpu_to_le32s(&header->sector_size);
+    cpu_to_le64s(&header->disk_size);
+    cpu_to_le32s(&header->block_size);
+    cpu_to_le32s(&header->block_extra);
+    cpu_to_le32s(&header->blocks_in_image);
+    cpu_to_le32s(&header->blocks_allocated);
+    cpu_to_le32s(&header->blocks_allocated);
+    uuid_convert(header->uuid_image);
+    uuid_convert(header->uuid_last_snap);
+    uuid_convert(header->uuid_link);
+    uuid_convert(header->uuid_parent);
+}
+
+#if defined(CONFIG_VDI_DEBUG)
+static void vdi_header_print(VdiHeader *header)
+{
+    char uuid[37];
+    logout("text        %s", header->text);
+    logout("signature   0x%04x\n", header->signature);
+    logout("header size 0x%04x\n", header->header_size);
+    logout("image type  0x%04x\n", header->image_type);
+    logout("image flags 0x%04x\n", header->image_flags);
+    logout("description %s\n", header->description);
+    logout("offset bmap 0x%04x\n", header->offset_bmap);
+    logout("offset data 0x%04x\n", header->offset_data);
+    logout("cylinders   0x%04x\n", header->cylinders);
+    logout("heads       0x%04x\n", header->heads);
+    logout("sectors     0x%04x\n", header->sectors);
+    logout("sector size 0x%04x\n", header->sector_size);
+    logout("image size  0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
+           header->disk_size, header->disk_size / MiB);
+    logout("block size  0x%04x\n", header->block_size);
+    logout("block extra 0x%04x\n", header->block_extra);
+    logout("blocks tot. 0x%04x\n", header->blocks_in_image);
+    logout("blocks all. 0x%04x\n", header->blocks_allocated);
+    uuid_unparse(header->uuid_image, uuid);
+    logout("uuid image  %s\n", uuid);
+    uuid_unparse(header->uuid_last_snap, uuid);
+    logout("uuid snap   %s\n", uuid);
+    uuid_unparse(header->uuid_link, uuid);
+    logout("uuid link   %s\n", uuid);
+    uuid_unparse(header->uuid_parent, uuid);
+    logout("uuid parent %s\n", uuid);
+}
+#endif
+
+static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
+{
+    /* TODO: additional checks possible. */
+    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
+    uint32_t blocks_allocated = 0;
+    uint32_t block;
+    uint32_t *bmap;
+    logout("\n");
+
+    bmap = qemu_malloc(s->header.blocks_in_image * sizeof(uint32_t));
+    memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
+
+    /* Check block map and value of blocks_allocated. */
+    for (block = 0; block < s->header.blocks_in_image; block++) {
+        uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
+        if (bmap_entry != VDI_UNALLOCATED) {
+            if (bmap_entry < s->header.blocks_in_image) {
+                blocks_allocated++;
+                if (bmap[bmap_entry] == VDI_UNALLOCATED) {
+                    bmap[bmap_entry] = bmap_entry;
+                } else {
+                    fprintf(stderr, "ERROR: block index %" PRIu32
+                            " also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
+                    res->corruptions++;
+                }
+            } else {
+                fprintf(stderr, "ERROR: block index %" PRIu32
+                        " too large, is %" PRIu32 "\n", block, bmap_entry);
+                res->corruptions++;
+            }
+        }
+    }
+    if (blocks_allocated != s->header.blocks_allocated) {
+        fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
+               ", should be %" PRIu32 "\n",
+               blocks_allocated, s->header.blocks_allocated);
+        res->corruptions++;
+    }
+
+    qemu_free(bmap);
+
+    return 0;
+}
+
+static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    /* TODO: vdi_get_info would be needed for machine snapshots.
+       vm_state_offset is still missing. */
+    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
+    logout("\n");
+    bdi->cluster_size = s->block_size;
+    bdi->vm_state_offset = 0;
+    return 0;
+}
+
+static int vdi_make_empty(BlockDriverState *bs)
+{
+    /* TODO: missing code. */
+    logout("\n");
+    /* The return value for missing code must be 0, see block.c. */
+    return 0;
+}
+
+static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const VdiHeader *header = (const VdiHeader *)buf;
+    int result = 0;
+
+    logout("\n");
+
+    if (buf_size < sizeof(*header)) {
+        /* Header too small, no VDI. */
+    } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
+        result = 100;
+    }
+
+    if (result == 0) {
+        logout("no vdi image\n");
+    } else {
+        logout("%s", header->text);
+    }
+
+    return result;
+}
+
+static int vdi_open(BlockDriverState *bs, int flags)
+{
+    BDRVVdiState *s = bs->opaque;
+    VdiHeader header;
+    size_t bmap_size;
+
+    logout("\n");
+
+    if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
+        goto fail;
+    }
+
+    vdi_header_to_cpu(&header);
+#if defined(CONFIG_VDI_DEBUG)
+    vdi_header_print(&header);
+#endif
+
+    if (header.disk_size % SECTOR_SIZE != 0) {
+        /* 'VBoxManage convertfromraw' can create images with odd disk sizes.
+           We accept them but round the disk size to the next multiple of
+           SECTOR_SIZE. */
+        logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
+        header.disk_size += SECTOR_SIZE - 1;
+        header.disk_size &= ~(SECTOR_SIZE - 1);
+    }
+
+    if (header.version != VDI_VERSION_1_1) {
+        logout("unsupported version %u.%u\n",
+               header.version >> 16, header.version & 0xffff);
+        goto fail;
+    } else if (header.offset_bmap % SECTOR_SIZE != 0) {
+        /* We only support block maps which start on a sector boundary. */
+        logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
+        goto fail;
+    } else if (header.offset_data % SECTOR_SIZE != 0) {
+        /* We only support data blocks which start on a sector boundary. */
+        logout("unsupported data offset 0x%x B\n", header.offset_data);
+        goto fail;
+    } else if (header.sector_size != SECTOR_SIZE) {
+        logout("unsupported sector size %u B\n", header.sector_size);
+        goto fail;
+    } else if (header.block_size != 1 * MiB) {
+        logout("unsupported block size %u B\n", header.block_size);
+        goto fail;
+    } else if (header.disk_size >
+               (uint64_t)header.blocks_in_image * header.block_size) {
+        logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
+        goto fail;
+    } else if (!uuid_is_null(header.uuid_link)) {
+        logout("link uuid != 0, unsupported\n");
+        goto fail;
+    } else if (!uuid_is_null(header.uuid_parent)) {
+        logout("parent uuid != 0, unsupported\n");
+        goto fail;
+    }
+
+    bs->total_sectors = header.disk_size / SECTOR_SIZE;
+
+    s->block_size = header.block_size;
+    s->block_sectors = header.block_size / SECTOR_SIZE;
+    s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
+    s->header = header;
+
+    bmap_size = header.blocks_in_image * sizeof(uint32_t);
+    bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
+    if (bmap_size > 0) {
+        s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
+    }
+    if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
+        goto fail_free_bmap;
+    }
+
+    return 0;
+
+ fail_free_bmap:
+    qemu_free(s->bmap);
+
+ fail:
+    return -1;
+}
+
+static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum)
+{
+    /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
+    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
+    size_t bmap_index = sector_num / s->block_sectors;
+    size_t sector_in_block = sector_num % s->block_sectors;
+    int n_sectors = s->block_sectors - sector_in_block;
+    uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
+    logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
+    if (n_sectors > nb_sectors) {
+        n_sectors = nb_sectors;
+    }
+    *pnum = n_sectors;
+    return bmap_entry != VDI_UNALLOCATED;
+}
+
+static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    /* TODO: This code is untested. How can I get it executed? */
+    VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
+    logout("\n");
+    if (acb->hd_aiocb) {
+        bdrv_aio_cancel(acb->hd_aiocb);
+    }
+    qemu_aio_release(acb);
+}
+
+static AIOPool vdi_aio_pool = {
+    .aiocb_size = sizeof(VdiAIOCB),
+    .cancel = vdi_aio_cancel,
+};
+
+static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
+        QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+{
+    VdiAIOCB *acb;
+
+    logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
+           bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
+
+    acb = qemu_aio_get(&vdi_aio_pool, bs, cb, opaque);
+    if (acb) {
+        acb->hd_aiocb = NULL;
+        acb->sector_num = sector_num;
+        acb->qiov = qiov;
+        acb->is_write = is_write;
+
+        if (qiov->niov > 1) {
+            acb->buf = qemu_blockalign(bs, qiov->size);
+            acb->orig_buf = acb->buf;
+            if (is_write) {
+                qemu_iovec_to_buffer(qiov, acb->buf);
+            }
+        } else {
+            acb->buf = (uint8_t *)qiov->iov->iov_base;
+        }
+        acb->nb_sectors = nb_sectors;
+        acb->n_sectors = 0;
+        acb->bmap_first = VDI_UNALLOCATED;
+        acb->bmap_last = VDI_UNALLOCATED;
+        acb->block_buffer = NULL;
+        acb->header_modified = 0;
+    }
+    return acb;
+}
+
+static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
+{
+    logout("\n");
+
+    if (acb->bh) {
+        return -EIO;
+    }
+
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh) {
+        return -EIO;
+    }
+
+    qemu_bh_schedule(acb->bh);
+
+    return 0;
+}
+
+static void vdi_aio_read_cb(void *opaque, int ret);
+static void vdi_aio_write_cb(void *opaque, int ret);
+
+static void vdi_aio_rw_bh(void *opaque)
+{
+    VdiAIOCB *acb = opaque;
+    logout("\n");
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    if (acb->is_write) {
+        vdi_aio_write_cb(opaque, 0);
+    } else {
+        vdi_aio_read_cb(opaque, 0);
+    }
+}
+
+static void vdi_aio_read_cb(void *opaque, int ret)
+{
+    VdiAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVVdiState *s = bs->opaque;
+    uint32_t bmap_entry;
+    uint32_t block_index;
+    uint32_t sector_in_block;
+    uint32_t n_sectors;
+
+    logout("%u sectors read\n", acb->n_sectors);
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0) {
+        goto done;
+    }
+
+    acb->nb_sectors -= acb->n_sectors;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    acb->sector_num += acb->n_sectors;
+    acb->buf += acb->n_sectors * SECTOR_SIZE;
+
+    block_index = acb->sector_num / s->block_sectors;
+    sector_in_block = acb->sector_num % s->block_sectors;
+    n_sectors = s->block_sectors - sector_in_block;
+    if (n_sectors > acb->nb_sectors) {
+        n_sectors = acb->nb_sectors;
+    }
+
+    logout("will read %u sectors starting at sector %" PRIu64 "\n",
+           n_sectors, acb->sector_num);
+
+    /* prepare next AIO request */
+    acb->n_sectors = n_sectors;
+    bmap_entry = le32_to_cpu(s->bmap[block_index]);
+    if (bmap_entry == VDI_UNALLOCATED) {
+        /* Block not allocated, return zeros, no need to wait. */
+        memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
+        ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+        if (ret < 0) {
+            goto done;
+        }
+    } else {
+        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
+                          (uint64_t)bmap_entry * s->block_sectors +
+                          sector_in_block;
+        acb->hd_iov.iov_base = (void *)acb->buf;
+        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
+                                       n_sectors, vdi_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
+            goto done;
+        }
+    }
+    return;
+done:
+    if (acb->qiov->niov > 1) {
+        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+        qemu_vfree(acb->orig_buf);
+    }
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    VdiAIOCB *acb;
+    int ret;
+
+    logout("\n");
+    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    if (!acb) {
+        return NULL;
+    }
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static void vdi_aio_write_cb(void *opaque, int ret)
+{
+    VdiAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVVdiState *s = bs->opaque;
+    uint32_t bmap_entry;
+    uint32_t block_index;
+    uint32_t sector_in_block;
+    uint32_t n_sectors;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0) {
+        goto done;
+    }
+
+    acb->nb_sectors -= acb->n_sectors;
+    acb->sector_num += acb->n_sectors;
+    acb->buf += acb->n_sectors * SECTOR_SIZE;
+
+    if (acb->nb_sectors == 0) {
+        logout("finished data write\n");
+        acb->n_sectors = 0;
+        if (acb->header_modified) {
+            VdiHeader *header = acb->block_buffer;
+            logout("now writing modified header\n");
+            assert(acb->bmap_first != VDI_UNALLOCATED);
+            *header = s->header;
+            vdi_header_to_le(header);
+            acb->header_modified = 0;
+            acb->hd_iov.iov_base = acb->block_buffer;
+            acb->hd_iov.iov_len = SECTOR_SIZE;
+            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+            acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
+                                            vdi_aio_write_cb, acb);
+            if (acb->hd_aiocb == NULL) {
+                ret = -EIO;
+                goto done;
+            }
+            return;
+        } else if (acb->bmap_first != VDI_UNALLOCATED) {
+            /* One or more new blocks were allocated. */
+            uint64_t offset;
+            uint32_t bmap_first;
+            uint32_t bmap_last;
+            qemu_free(acb->block_buffer);
+            acb->block_buffer = NULL;
+            bmap_first = acb->bmap_first;
+            bmap_last = acb->bmap_last;
+            logout("now writing modified block map entry %u...%u\n",
+                   bmap_first, bmap_last);
+            /* Write modified sectors from block map. */
+            bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
+            bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
+            n_sectors = bmap_last - bmap_first + 1;
+            offset = s->bmap_sector + bmap_first;
+            acb->bmap_first = VDI_UNALLOCATED;
+            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
+                                            bmap_first * SECTOR_SIZE);
+            acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+            logout("will write %u block map sectors starting from entry %u\n",
+                   n_sectors, bmap_first);
+            acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
+                                            n_sectors, vdi_aio_write_cb, acb);
+            if (acb->hd_aiocb == NULL) {
+                ret = -EIO;
+                goto done;
+            }
+            return;
+        }
+        ret = 0;
+        goto done;
+    }
+
+    logout("%u sectors written\n", acb->n_sectors);
+
+    block_index = acb->sector_num / s->block_sectors;
+    sector_in_block = acb->sector_num % s->block_sectors;
+    n_sectors = s->block_sectors - sector_in_block;
+    if (n_sectors > acb->nb_sectors) {
+        n_sectors = acb->nb_sectors;
+    }
+
+    logout("will write %u sectors starting at sector %" PRIu64 "\n",
+           n_sectors, acb->sector_num);
+
+    /* prepare next AIO request */
+    acb->n_sectors = n_sectors;
+    bmap_entry = le32_to_cpu(s->bmap[block_index]);
+    if (bmap_entry == VDI_UNALLOCATED) {
+        /* Allocate new block and write to it. */
+        uint64_t offset;
+        uint8_t *block;
+        bmap_entry = s->header.blocks_allocated;
+        s->bmap[block_index] = cpu_to_le32(bmap_entry);
+        s->header.blocks_allocated++;
+        offset = s->header.offset_data / SECTOR_SIZE +
+                 (uint64_t)bmap_entry * s->block_sectors;
+        block = acb->block_buffer;
+        if (block == NULL) {
+            block = qemu_mallocz(s->block_size);
+            acb->block_buffer = block;
+            acb->bmap_first = block_index;
+            assert(!acb->header_modified);
+            acb->header_modified = 1;
+        }
+        acb->bmap_last = block_index;
+        memcpy(block + sector_in_block * SECTOR_SIZE,
+               acb->buf, n_sectors * SECTOR_SIZE);
+        acb->hd_iov.iov_base = (void *)block;
+        acb->hd_iov.iov_len = s->block_size;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
+                                        &acb->hd_qiov, s->block_sectors,
+                                        vdi_aio_write_cb, acb);
+        if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
+            goto done;
+        }
+    } else {
+        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
+                          (uint64_t)bmap_entry * s->block_sectors +
+                          sector_in_block;
+        acb->hd_iov.iov_base = (void *)acb->buf;
+        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
+                                        n_sectors, vdi_aio_write_cb, acb);
+        if (acb->hd_aiocb == NULL) {
+            ret = -EIO;
+            goto done;
+        }
+    }
+
+    return;
+
+done:
+    if (acb->qiov->niov > 1) {
+        qemu_vfree(acb->orig_buf);
+    }
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    VdiAIOCB *acb;
+    int ret;
+
+    logout("\n");
+    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+    if (!acb) {
+        return NULL;
+    }
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+
+static int vdi_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int result = 0;
+    uint64_t bytes = 0;
+    uint32_t blocks;
+    size_t block_size = DEFAULT_CLUSTER_SIZE;
+    uint32_t image_type = VDI_TYPE_DYNAMIC;
+    VdiHeader header;
+    size_t i;
+    size_t bmap_size;
+    uint32_t *bmap;
+
+    logout("\n");
+
+    /* Read out options. */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            bytes = options->value.n;
+#if defined(CONFIG_VDI_BLOCK_SIZE)
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
+                block_size = options->value.n;
+            }
+#endif
+#if defined(CONFIG_VDI_STATIC_IMAGE)
+        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
+            if (options->value.n) {
+                image_type = VDI_TYPE_STATIC;
+            }
+#endif
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+              0644);
+    if (fd < 0) {
+        return -errno;
+    }
+
+    /* We need enough blocks to store the given disk size,
+       so always round up. */
+    blocks = (bytes + block_size - 1) / block_size;
+
+    bmap_size = blocks * sizeof(uint32_t);
+    bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
+
+    memset(&header, 0, sizeof(header));
+    pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
+    header.signature = VDI_SIGNATURE;
+    header.version = VDI_VERSION_1_1;
+    header.header_size = 0x180;
+    header.image_type = image_type;
+    header.offset_bmap = 0x200;
+    header.offset_data = 0x200 + bmap_size;
+    header.sector_size = SECTOR_SIZE;
+    header.disk_size = bytes;
+    header.block_size = block_size;
+    header.blocks_in_image = blocks;
+    if (image_type == VDI_TYPE_STATIC) {
+        header.blocks_allocated = blocks;
+    }
+    uuid_generate(header.uuid_image);
+    uuid_generate(header.uuid_last_snap);
+    /* There is no need to set header.uuid_link or header.uuid_parent here. */
+#if defined(CONFIG_VDI_DEBUG)
+    vdi_header_print(&header);
+#endif
+    vdi_header_to_le(&header);
+    if (write(fd, &header, sizeof(header)) < 0) {
+        result = -errno;
+    }
+
+    bmap = NULL;
+    if (bmap_size > 0) {
+        bmap = (uint32_t *)qemu_mallocz(bmap_size);
+    }
+    for (i = 0; i < blocks; i++) {
+        if (image_type == VDI_TYPE_STATIC) {
+            bmap[i] = i;
+        } else {
+            bmap[i] = VDI_UNALLOCATED;
+        }
+    }
+    if (write(fd, bmap, bmap_size) < 0) {
+        result = -errno;
+    }
+    qemu_free(bmap);
+    if (image_type == VDI_TYPE_STATIC) {
+        if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
+            result = -errno;
+        }
+    }
+
+    if (close(fd) < 0) {
+        result = -errno;
+    }
+
+    return result;
+}
+
+static void vdi_close(BlockDriverState *bs)
+{
+}
+
+static int vdi_flush(BlockDriverState *bs)
+{
+    logout("\n");
+    return bdrv_flush(bs->file);
+}
+
+
+static QEMUOptionParameter vdi_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+#if defined(CONFIG_VDI_BLOCK_SIZE)
+    {
+        .name = BLOCK_OPT_CLUSTER_SIZE,
+        .type = OPT_SIZE,
+        .help = "VDI cluster (block) size",
+        .value = { .n = DEFAULT_CLUSTER_SIZE },
+    },
+#endif
+#if defined(CONFIG_VDI_STATIC_IMAGE)
+    {
+        .name = BLOCK_OPT_STATIC,
+        .type = OPT_FLAG,
+        .help = "VDI static (pre-allocated) image"
+    },
+#endif
+    /* TODO: An additional option to set UUID values might be useful. */
+    { NULL }
+};
+
+static BlockDriver bdrv_vdi = {
+    .format_name = "vdi",
+    .instance_size = sizeof(BDRVVdiState),
+    .bdrv_probe = vdi_probe,
+    .bdrv_open = vdi_open,
+    .bdrv_close = vdi_close,
+    .bdrv_create = vdi_create,
+    .bdrv_flush = vdi_flush,
+    .bdrv_is_allocated = vdi_is_allocated,
+    .bdrv_make_empty = vdi_make_empty,
+
+    .bdrv_aio_readv = vdi_aio_readv,
+#if defined(CONFIG_VDI_WRITE)
+    .bdrv_aio_writev = vdi_aio_writev,
+#endif
+
+    .bdrv_get_info = vdi_get_info,
+
+    .create_options = vdi_create_options,
+    .bdrv_check = vdi_check,
+};
+
+static void bdrv_vdi_init(void)
+{
+    logout("\n");
+    bdrv_register(&bdrv_vdi);
+}
+
+block_init(bdrv_vdi_init);
diff --git a/qemu-0.15.x/block/vmdk.c b/qemu-0.15.x/block/vmdk.c
new file mode 100644
index 0000000..37478d2
--- /dev/null
+++ b/qemu-0.15.x/block/vmdk.c
@@ -0,0 +1,1363 @@
+/*
+ * Block driver for the VMDK format
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2005 Filip Navara
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
+#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
+
+typedef struct {
+    uint32_t version;
+    uint32_t flags;
+    uint32_t disk_sectors;
+    uint32_t granularity;
+    uint32_t l1dir_offset;
+    uint32_t l1dir_size;
+    uint32_t file_sectors;
+    uint32_t cylinders;
+    uint32_t heads;
+    uint32_t sectors_per_track;
+} VMDK3Header;
+
+typedef struct {
+    uint32_t version;
+    uint32_t flags;
+    int64_t capacity;
+    int64_t granularity;
+    int64_t desc_offset;
+    int64_t desc_size;
+    int32_t num_gtes_per_gte;
+    int64_t rgd_offset;
+    int64_t gd_offset;
+    int64_t grain_offset;
+    char filler[1];
+    char check_bytes[4];
+} __attribute__((packed)) VMDK4Header;
+
+#define L2_CACHE_SIZE 16
+
+typedef struct VmdkExtent {
+    BlockDriverState *file;
+    bool flat;
+    int64_t sectors;
+    int64_t end_sector;
+    int64_t flat_start_offset;
+    int64_t l1_table_offset;
+    int64_t l1_backup_table_offset;
+    uint32_t *l1_table;
+    uint32_t *l1_backup_table;
+    unsigned int l1_size;
+    uint32_t l1_entry_sectors;
+
+    unsigned int l2_size;
+    uint32_t *l2_cache;
+    uint32_t l2_cache_offsets[L2_CACHE_SIZE];
+    uint32_t l2_cache_counts[L2_CACHE_SIZE];
+
+    unsigned int cluster_sectors;
+} VmdkExtent;
+
+typedef struct BDRVVmdkState {
+    int desc_offset;
+    bool cid_updated;
+    uint32_t parent_cid;
+    int num_extents;
+    /* Extent array with num_extents entries, ascend ordered by address */
+    VmdkExtent *extents;
+} BDRVVmdkState;
+
+typedef struct VmdkMetaData {
+    uint32_t offset;
+    unsigned int l1_index;
+    unsigned int l2_index;
+    unsigned int l2_offset;
+    int valid;
+} VmdkMetaData;
+
+static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    uint32_t magic;
+
+    if (buf_size < 4) {
+        return 0;
+    }
+    magic = be32_to_cpu(*(uint32_t *)buf);
+    if (magic == VMDK3_MAGIC ||
+        magic == VMDK4_MAGIC) {
+        return 100;
+    } else {
+        const char *p = (const char *)buf;
+        const char *end = p + buf_size;
+        while (p < end) {
+            if (*p == '#') {
+                /* skip comment line */
+                while (p < end && *p != '\n') {
+                    p++;
+                }
+                p++;
+                continue;
+            }
+            if (*p == ' ') {
+                while (p < end && *p == ' ') {
+                    p++;
+                }
+                /* skip '\r' if windows line endings used. */
+                if (p < end && *p == '\r') {
+                    p++;
+                }
+                /* only accept blank lines before 'version=' line */
+                if (p == end || *p != '\n') {
+                    return 0;
+                }
+                p++;
+                continue;
+            }
+            if (end - p >= strlen("version=X\n")) {
+                if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
+                    strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
+                    return 100;
+                }
+            }
+            if (end - p >= strlen("version=X\r\n")) {
+                if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
+                    strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
+                    return 100;
+                }
+            }
+            return 0;
+        }
+        return 0;
+    }
+}
+
+#define CHECK_CID 1
+
+#define SECTOR_SIZE 512
+#define DESC_SIZE (20 * SECTOR_SIZE)    /* 20 sectors of 512 bytes each */
+#define BUF_SIZE 4096
+#define HEADER_SIZE 512                 /* first sector of 512 bytes */
+
+static void vmdk_free_extents(BlockDriverState *bs)
+{
+    int i;
+    BDRVVmdkState *s = bs->opaque;
+
+    for (i = 0; i < s->num_extents; i++) {
+        qemu_free(s->extents[i].l1_table);
+        qemu_free(s->extents[i].l2_cache);
+        qemu_free(s->extents[i].l1_backup_table);
+    }
+    qemu_free(s->extents);
+}
+
+static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
+{
+    char desc[DESC_SIZE];
+    uint32_t cid;
+    const char *p_name, *cid_str;
+    size_t cid_str_size;
+    BDRVVmdkState *s = bs->opaque;
+
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+        return 0;
+    }
+
+    if (parent) {
+        cid_str = "parentCID";
+        cid_str_size = sizeof("parentCID");
+    } else {
+        cid_str = "CID";
+        cid_str_size = sizeof("CID");
+    }
+
+    p_name = strstr(desc, cid_str);
+    if (p_name != NULL) {
+        p_name += cid_str_size;
+        sscanf(p_name, "%x", &cid);
+    }
+
+    return cid;
+}
+
+static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
+{
+    char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
+    char *p_name, *tmp_str;
+    BDRVVmdkState *s = bs->opaque;
+
+    memset(desc, 0, sizeof(desc));
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+        return -EIO;
+    }
+
+    tmp_str = strstr(desc, "parentCID");
+    pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
+    p_name = strstr(desc, "CID");
+    if (p_name != NULL) {
+        p_name += sizeof("CID");
+        snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
+        pstrcat(desc, sizeof(desc), tmp_desc);
+    }
+
+    if (bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE) < 0) {
+        return -EIO;
+    }
+    return 0;
+}
+
+static int vmdk_is_cid_valid(BlockDriverState *bs)
+{
+#ifdef CHECK_CID
+    BDRVVmdkState *s = bs->opaque;
+    BlockDriverState *p_bs = bs->backing_hd;
+    uint32_t cur_pcid;
+
+    if (p_bs) {
+        cur_pcid = vmdk_read_cid(p_bs, 0);
+        if (s->parent_cid != cur_pcid) {
+            /* CID not valid */
+            return 0;
+        }
+    }
+#endif
+    /* CID valid */
+    return 1;
+}
+
+static int vmdk_parent_open(BlockDriverState *bs)
+{
+    char *p_name;
+    char desc[DESC_SIZE + 1];
+    BDRVVmdkState *s = bs->opaque;
+
+    desc[DESC_SIZE] = '\0';
+    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+        return -1;
+    }
+
+    p_name = strstr(desc, "parentFileNameHint");
+    if (p_name != NULL) {
+        char *end_name;
+
+        p_name += sizeof("parentFileNameHint") + 1;
+        end_name = strchr(p_name, '\"');
+        if (end_name == NULL) {
+            return -1;
+        }
+        if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
+            return -1;
+        }
+
+        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
+    }
+
+    return 0;
+}
+
+/* Create and append extent to the extent array. Return the added VmdkExtent
+ * address. return NULL if allocation failed. */
+static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
+                           BlockDriverState *file, bool flat, int64_t sectors,
+                           int64_t l1_offset, int64_t l1_backup_offset,
+                           uint32_t l1_size,
+                           int l2_size, unsigned int cluster_sectors)
+{
+    VmdkExtent *extent;
+    BDRVVmdkState *s = bs->opaque;
+
+    s->extents = qemu_realloc(s->extents,
+                              (s->num_extents + 1) * sizeof(VmdkExtent));
+    extent = &s->extents[s->num_extents];
+    s->num_extents++;
+
+    memset(extent, 0, sizeof(VmdkExtent));
+    extent->file = file;
+    extent->flat = flat;
+    extent->sectors = sectors;
+    extent->l1_table_offset = l1_offset;
+    extent->l1_backup_table_offset = l1_backup_offset;
+    extent->l1_size = l1_size;
+    extent->l1_entry_sectors = l2_size * cluster_sectors;
+    extent->l2_size = l2_size;
+    extent->cluster_sectors = cluster_sectors;
+
+    if (s->num_extents > 1) {
+        extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
+    } else {
+        extent->end_sector = extent->sectors;
+    }
+    bs->total_sectors = extent->end_sector;
+    return extent;
+}
+
+static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
+{
+    int ret;
+    int l1_size, i;
+
+    /* read the L1 table */
+    l1_size = extent->l1_size * sizeof(uint32_t);
+    extent->l1_table = qemu_malloc(l1_size);
+    ret = bdrv_pread(extent->file,
+                    extent->l1_table_offset,
+                    extent->l1_table,
+                    l1_size);
+    if (ret < 0) {
+        goto fail_l1;
+    }
+    for (i = 0; i < extent->l1_size; i++) {
+        le32_to_cpus(&extent->l1_table[i]);
+    }
+
+    if (extent->l1_backup_table_offset) {
+        extent->l1_backup_table = qemu_malloc(l1_size);
+        ret = bdrv_pread(extent->file,
+                        extent->l1_backup_table_offset,
+                        extent->l1_backup_table,
+                        l1_size);
+        if (ret < 0) {
+            goto fail_l1b;
+        }
+        for (i = 0; i < extent->l1_size; i++) {
+            le32_to_cpus(&extent->l1_backup_table[i]);
+        }
+    }
+
+    extent->l2_cache =
+        qemu_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
+    return 0;
+ fail_l1b:
+    qemu_free(extent->l1_backup_table);
+ fail_l1:
+    qemu_free(extent->l1_table);
+    return ret;
+}
+
+static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
+{
+    int ret;
+    uint32_t magic;
+    VMDK3Header header;
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *extent;
+
+    s->desc_offset = 0x200;
+    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
+        goto fail;
+    }
+    extent = vmdk_add_extent(bs,
+                             bs->file, false,
+                             le32_to_cpu(header.disk_sectors),
+                             le32_to_cpu(header.l1dir_offset) << 9,
+                             0, 1 << 6, 1 << 9,
+                             le32_to_cpu(header.granularity));
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        /* vmdk_init_tables cleans up on fail, so only free allocation of
+         * vmdk_add_extent here. */
+        goto fail;
+    }
+    return 0;
+ fail:
+    vmdk_free_extents(bs);
+    return ret;
+}
+
+static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
+{
+    int ret;
+    uint32_t magic;
+    uint32_t l1_size, l1_entry_sectors;
+    VMDK4Header header;
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *extent;
+
+    s->desc_offset = 0x200;
+    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    if (ret < 0) {
+        goto fail;
+    }
+    l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
+                        * le64_to_cpu(header.granularity);
+    l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
+                / l1_entry_sectors;
+    extent = vmdk_add_extent(bs, bs->file, false,
+                          le64_to_cpu(header.capacity),
+                          le64_to_cpu(header.gd_offset) << 9,
+                          le64_to_cpu(header.rgd_offset) << 9,
+                          l1_size,
+                          le32_to_cpu(header.num_gtes_per_gte),
+                          le64_to_cpu(header.granularity));
+    if (extent->l1_entry_sectors <= 0) {
+        ret = -EINVAL;
+        goto fail;
+    }
+    /* try to open parent images, if exist */
+    ret = vmdk_parent_open(bs);
+    if (ret) {
+        goto fail;
+    }
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    ret = vmdk_init_tables(bs, extent);
+    if (ret) {
+        goto fail;
+    }
+    return 0;
+ fail:
+    vmdk_free_extents(bs);
+    return ret;
+}
+
+/* find an option value out of descriptor file */
+static int vmdk_parse_description(const char *desc, const char *opt_name,
+        char *buf, int buf_size)
+{
+    char *opt_pos, *opt_end;
+    const char *end = desc + strlen(desc);
+
+    opt_pos = strstr(desc, opt_name);
+    if (!opt_pos) {
+        return -1;
+    }
+    /* Skip "=\"" following opt_name */
+    opt_pos += strlen(opt_name) + 2;
+    if (opt_pos >= end) {
+        return -1;
+    }
+    opt_end = opt_pos;
+    while (opt_end < end && *opt_end != '"') {
+        opt_end++;
+    }
+    if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
+        return -1;
+    }
+    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
+    return 0;
+}
+
+static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
+        const char *desc_file_path)
+{
+    int ret;
+    char access[11];
+    char type[11];
+    char fname[512];
+    const char *p = desc;
+    int64_t sectors = 0;
+    int64_t flat_offset;
+
+    while (*p) {
+        /* parse extent line:
+         * RW [size in sectors] FLAT "file-name.vmdk" OFFSET
+         * or
+         * RW [size in sectors] SPARSE "file-name.vmdk"
+         */
+        flat_offset = -1;
+        ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
+                access, &sectors, type, fname, &flat_offset);
+        if (ret < 4 || strcmp(access, "RW")) {
+            goto next_line;
+        } else if (!strcmp(type, "FLAT")) {
+            if (ret != 5 || flat_offset < 0) {
+                return -EINVAL;
+            }
+        } else if (ret != 4) {
+            return -EINVAL;
+        }
+
+        /* trim the quotation marks around */
+        if (fname[0] == '"') {
+            memmove(fname, fname + 1, strlen(fname));
+            if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
+                return -EINVAL;
+            }
+            fname[strlen(fname) - 1] = '\0';
+        }
+        if (sectors <= 0 ||
+            (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
+            (strcmp(access, "RW"))) {
+            goto next_line;
+        }
+
+        /* save to extents array */
+        if (!strcmp(type, "FLAT")) {
+            /* FLAT extent */
+            char extent_path[PATH_MAX];
+            BlockDriverState *extent_file;
+            VmdkExtent *extent;
+
+            path_combine(extent_path, sizeof(extent_path),
+                    desc_file_path, fname);
+            ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
+            if (ret) {
+                return ret;
+            }
+            extent = vmdk_add_extent(bs, extent_file, true, sectors,
+                            0, 0, 0, 0, sectors);
+            extent->flat_start_offset = flat_offset;
+        } else {
+            /* SPARSE extent, not supported for now */
+            fprintf(stderr,
+                "VMDK: Not supported extent type \"%s\""".\n", type);
+            return -ENOTSUP;
+        }
+next_line:
+        /* move to next line */
+        while (*p && *p != '\n') {
+            p++;
+        }
+        p++;
+    }
+    return 0;
+}
+
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
+{
+    int ret;
+    char buf[2048];
+    char ct[128];
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+    buf[2047] = '\0';
+    if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
+        return -EINVAL;
+    }
+    if (strcmp(ct, "monolithicFlat")) {
+        fprintf(stderr,
+                "VMDK: Not supported image type \"%s\""".\n", ct);
+        return -ENOTSUP;
+    }
+    s->desc_offset = 0;
+    ret = vmdk_parse_extents(buf, bs, bs->file->filename);
+    if (ret) {
+        return ret;
+    }
+
+    /* try to open parent images, if exist */
+    if (vmdk_parent_open(bs)) {
+        qemu_free(s->extents);
+        return -EINVAL;
+    }
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    return 0;
+}
+
+static int vmdk_open(BlockDriverState *bs, int flags)
+{
+    uint32_t magic;
+
+    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
+        return -EIO;
+    }
+
+    magic = be32_to_cpu(magic);
+    if (magic == VMDK3_MAGIC) {
+        return vmdk_open_vmdk3(bs, flags);
+    } else if (magic == VMDK4_MAGIC) {
+        return vmdk_open_vmdk4(bs, flags);
+    } else {
+        return vmdk_open_desc_file(bs, flags);
+    }
+}
+
+static int get_whole_cluster(BlockDriverState *bs,
+                VmdkExtent *extent,
+                uint64_t cluster_offset,
+                uint64_t offset,
+                bool allocate)
+{
+    /* 128 sectors * 512 bytes each = grain size 64KB */
+    uint8_t  whole_grain[extent->cluster_sectors * 512];
+
+    /* we will be here if it's first write on non-exist grain(cluster).
+     * try to read from parent image, if exist */
+    if (bs->backing_hd) {
+        int ret;
+
+        if (!vmdk_is_cid_valid(bs)) {
+            return -1;
+        }
+
+        /* floor offset to cluster */
+        offset -= offset % (extent->cluster_sectors * 512);
+        ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
+                extent->cluster_sectors);
+        if (ret < 0) {
+            return -1;
+        }
+
+        /* Write grain only into the active image */
+        ret = bdrv_write(extent->file, cluster_offset, whole_grain,
+                extent->cluster_sectors);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
+{
+    /* update L2 table */
+    if (bdrv_pwrite_sync(
+                extent->file,
+                ((int64_t)m_data->l2_offset * 512)
+                    + (m_data->l2_index * sizeof(m_data->offset)),
+                &(m_data->offset),
+                sizeof(m_data->offset)
+            ) < 0) {
+        return -1;
+    }
+    /* update backup L2 table */
+    if (extent->l1_backup_table_offset != 0) {
+        m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
+        if (bdrv_pwrite_sync(
+                    extent->file,
+                    ((int64_t)m_data->l2_offset * 512)
+                        + (m_data->l2_index * sizeof(m_data->offset)),
+                    &(m_data->offset), sizeof(m_data->offset)
+                ) < 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int get_cluster_offset(BlockDriverState *bs,
+                                    VmdkExtent *extent,
+                                    VmdkMetaData *m_data,
+                                    uint64_t offset,
+                                    int allocate,
+                                    uint64_t *cluster_offset)
+{
+    unsigned int l1_index, l2_offset, l2_index;
+    int min_index, i, j;
+    uint32_t min_count, *l2_table, tmp = 0;
+
+    if (m_data) {
+        m_data->valid = 0;
+    }
+    if (extent->flat) {
+        *cluster_offset = extent->flat_start_offset;
+        return 0;
+    }
+
+    l1_index = (offset >> 9) / extent->l1_entry_sectors;
+    if (l1_index >= extent->l1_size) {
+        return -1;
+    }
+    l2_offset = extent->l1_table[l1_index];
+    if (!l2_offset) {
+        return -1;
+    }
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (l2_offset == extent->l2_cache_offsets[i]) {
+            /* increment the hit count */
+            if (++extent->l2_cache_counts[i] == 0xffffffff) {
+                for (j = 0; j < L2_CACHE_SIZE; j++) {
+                    extent->l2_cache_counts[j] >>= 1;
+                }
+            }
+            l2_table = extent->l2_cache + (i * extent->l2_size);
+            goto found;
+        }
+    }
+    /* not found: load a new entry in the least used one */
+    min_index = 0;
+    min_count = 0xffffffff;
+    for (i = 0; i < L2_CACHE_SIZE; i++) {
+        if (extent->l2_cache_counts[i] < min_count) {
+            min_count = extent->l2_cache_counts[i];
+            min_index = i;
+        }
+    }
+    l2_table = extent->l2_cache + (min_index * extent->l2_size);
+    if (bdrv_pread(
+                extent->file,
+                (int64_t)l2_offset * 512,
+                l2_table,
+                extent->l2_size * sizeof(uint32_t)
+            ) != extent->l2_size * sizeof(uint32_t)) {
+        return -1;
+    }
+
+    extent->l2_cache_offsets[min_index] = l2_offset;
+    extent->l2_cache_counts[min_index] = 1;
+ found:
+    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
+    *cluster_offset = le32_to_cpu(l2_table[l2_index]);
+
+    if (!*cluster_offset) {
+        if (!allocate) {
+            return -1;
+        }
+
+        /* Avoid the L2 tables update for the images that have snapshots. */
+        *cluster_offset = bdrv_getlength(extent->file);
+        bdrv_truncate(
+            extent->file,
+            *cluster_offset + (extent->cluster_sectors << 9)
+        );
+
+        *cluster_offset >>= 9;
+        tmp = cpu_to_le32(*cluster_offset);
+        l2_table[l2_index] = tmp;
+
+        /* First of all we write grain itself, to avoid race condition
+         * that may to corrupt the image.
+         * This problem may occur because of insufficient space on host disk
+         * or inappropriate VM shutdown.
+         */
+        if (get_whole_cluster(
+                bs, extent, *cluster_offset, offset, allocate) == -1) {
+            return -1;
+        }
+
+        if (m_data) {
+            m_data->offset = tmp;
+            m_data->l1_index = l1_index;
+            m_data->l2_index = l2_index;
+            m_data->l2_offset = l2_offset;
+            m_data->valid = 1;
+        }
+    }
+    *cluster_offset <<= 9;
+    return 0;
+}
+
+static VmdkExtent *find_extent(BDRVVmdkState *s,
+                                int64_t sector_num, VmdkExtent *start_hint)
+{
+    VmdkExtent *extent = start_hint;
+
+    if (!extent) {
+        extent = &s->extents[0];
+    }
+    while (extent < &s->extents[s->num_extents]) {
+        if (sector_num < extent->end_sector) {
+            return extent;
+        }
+        extent++;
+    }
+    return NULL;
+}
+
+static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum)
+{
+    BDRVVmdkState *s = bs->opaque;
+    int64_t index_in_cluster, n, ret;
+    uint64_t offset;
+    VmdkExtent *extent;
+
+    extent = find_extent(s, sector_num, NULL);
+    if (!extent) {
+        return 0;
+    }
+    ret = get_cluster_offset(bs, extent, NULL,
+                            sector_num * 512, 0, &offset);
+    /* get_cluster_offset returning 0 means success */
+    ret = !ret;
+
+    index_in_cluster = sector_num % extent->cluster_sectors;
+    n = extent->cluster_sectors - index_in_cluster;
+    if (n > nb_sectors) {
+        n = nb_sectors;
+    }
+    *pnum = n;
+    return ret;
+}
+
+static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVVmdkState *s = bs->opaque;
+    int ret;
+    uint64_t n, index_in_cluster;
+    VmdkExtent *extent = NULL;
+    uint64_t cluster_offset;
+
+    while (nb_sectors > 0) {
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                            bs, extent, NULL,
+                            sector_num << 9, 0, &cluster_offset);
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
+            n = nb_sectors;
+        }
+        if (ret) {
+            /* if not allocated, try to read from parent image, if exist */
+            if (bs->backing_hd) {
+                if (!vmdk_is_cid_valid(bs)) {
+                    return -EINVAL;
+                }
+                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+                if (ret < 0) {
+                    return ret;
+                }
+            } else {
+                memset(buf, 0, 512 * n);
+            }
+        } else {
+            ret = bdrv_pread(extent->file,
+                            cluster_offset + index_in_cluster * 512,
+                            buf, n * 512);
+            if (ret < 0) {
+                return ret;
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+
+static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *extent = NULL;
+    int n, ret;
+    int64_t index_in_cluster;
+    uint64_t cluster_offset;
+    VmdkMetaData m_data;
+
+    if (sector_num > bs->total_sectors) {
+        fprintf(stderr,
+                "(VMDK) Wrong offset: sector_num=0x%" PRIx64
+                " total_sectors=0x%" PRIx64 "\n",
+                sector_num, bs->total_sectors);
+        return -EIO;
+    }
+
+    while (nb_sectors > 0) {
+        extent = find_extent(s, sector_num, extent);
+        if (!extent) {
+            return -EIO;
+        }
+        ret = get_cluster_offset(
+                                bs,
+                                extent,
+                                &m_data,
+                                sector_num << 9, 1,
+                                &cluster_offset);
+        if (ret) {
+            return -EINVAL;
+        }
+        index_in_cluster = sector_num % extent->cluster_sectors;
+        n = extent->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors) {
+            n = nb_sectors;
+        }
+
+        ret = bdrv_pwrite(extent->file,
+                        cluster_offset + index_in_cluster * 512,
+                        buf,
+                        n * 512);
+        if (ret < 0) {
+            return ret;
+        }
+        if (m_data.valid) {
+            /* update L2 tables */
+            if (vmdk_L2update(extent, &m_data) == -1) {
+                return -EIO;
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+
+        /* update CID on the first write every time the virtual disk is
+         * opened */
+        if (!s->cid_updated) {
+            vmdk_write_cid(bs, time(NULL));
+            s->cid_updated = true;
+        }
+    }
+    return 0;
+}
+
+
+static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
+{
+    int ret, i;
+    int fd = 0;
+    VMDK4Header header;
+    uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
+
+    fd = open(
+        filename,
+        O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+        0644);
+    if (fd < 0) {
+        return -errno;
+    }
+    if (flat) {
+        ret = ftruncate(fd, filesize);
+        if (ret < 0) {
+            ret = -errno;
+        }
+        goto exit;
+    }
+    magic = cpu_to_be32(VMDK4_MAGIC);
+    memset(&header, 0, sizeof(header));
+    header.version = 1;
+    header.flags = 3; /* ?? */
+    header.capacity = filesize / 512;
+    header.granularity = 128;
+    header.num_gtes_per_gte = 512;
+
+    grains = (filesize / 512 + header.granularity - 1) / header.granularity;
+    gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
+    gt_count =
+        (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
+    gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
+
+    header.desc_offset = 1;
+    header.desc_size = 20;
+    header.rgd_offset = header.desc_offset + header.desc_size;
+    header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
+    header.grain_offset =
+       ((header.gd_offset + gd_size + (gt_size * gt_count) +
+         header.granularity - 1) / header.granularity) *
+        header.granularity;
+    /* swap endianness for all header fields */
+    header.version = cpu_to_le32(header.version);
+    header.flags = cpu_to_le32(header.flags);
+    header.capacity = cpu_to_le64(header.capacity);
+    header.granularity = cpu_to_le64(header.granularity);
+    header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
+    header.desc_offset = cpu_to_le64(header.desc_offset);
+    header.desc_size = cpu_to_le64(header.desc_size);
+    header.rgd_offset = cpu_to_le64(header.rgd_offset);
+    header.gd_offset = cpu_to_le64(header.gd_offset);
+    header.grain_offset = cpu_to_le64(header.grain_offset);
+
+    header.check_bytes[0] = 0xa;
+    header.check_bytes[1] = 0x20;
+    header.check_bytes[2] = 0xd;
+    header.check_bytes[3] = 0xa;
+
+    /* write all the data */
+    ret = qemu_write_full(fd, &magic, sizeof(magic));
+    if (ret != sizeof(magic)) {
+        ret = -errno;
+        goto exit;
+    }
+    ret = qemu_write_full(fd, &header, sizeof(header));
+    if (ret != sizeof(header)) {
+        ret = -errno;
+        goto exit;
+    }
+
+    ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
+    if (ret < 0) {
+        ret = -errno;
+        goto exit;
+    }
+
+    /* write grain directory */
+    lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
+    for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
+         i < gt_count; i++, tmp += gt_size) {
+        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
+        if (ret != sizeof(tmp)) {
+            ret = -errno;
+            goto exit;
+        }
+    }
+
+    /* write backup grain directory */
+    lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
+    for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
+         i < gt_count; i++, tmp += gt_size) {
+        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
+        if (ret != sizeof(tmp)) {
+            ret = -errno;
+            goto exit;
+        }
+    }
+
+    ret = 0;
+ exit:
+    close(fd);
+    return ret;
+}
+
+static int filename_decompose(const char *filename, char *path, char *prefix,
+        char *postfix, size_t buf_len)
+{
+    const char *p, *q;
+
+    if (filename == NULL || !strlen(filename)) {
+        fprintf(stderr, "Vmdk: no filename provided.\n");
+        return -1;
+    }
+    p = strrchr(filename, '/');
+    if (p == NULL) {
+        p = strrchr(filename, '\\');
+    }
+    if (p == NULL) {
+        p = strrchr(filename, ':');
+    }
+    if (p != NULL) {
+        p++;
+        if (p - filename >= buf_len) {
+            return -1;
+        }
+        pstrcpy(path, p - filename + 1, filename);
+    } else {
+        p = filename;
+        path[0] = '\0';
+    }
+    q = strrchr(p, '.');
+    if (q == NULL) {
+        pstrcpy(prefix, buf_len, p);
+        postfix[0] = '\0';
+    } else {
+        if (q - p >= buf_len) {
+            return -1;
+        }
+        pstrcpy(prefix, q - p + 1, p);
+        pstrcpy(postfix, buf_len, q);
+    }
+    return 0;
+}
+
+static int relative_path(char *dest, int dest_size,
+        const char *base, const char *target)
+{
+    int i = 0;
+    int n = 0;
+    const char *p, *q;
+#ifdef _WIN32
+    const char *sep = "\\";
+#else
+    const char *sep = "/";
+#endif
+
+    if (!(dest && base && target)) {
+        return -1;
+    }
+    if (path_is_absolute(target)) {
+        dest[dest_size - 1] = '\0';
+        strncpy(dest, target, dest_size - 1);
+        return 0;
+    }
+    while (base[i] == target[i]) {
+        i++;
+    }
+    p = &base[i];
+    q = &target[i];
+    while (*p) {
+        if (*p == *sep) {
+            n++;
+        }
+        p++;
+    }
+    dest[0] = '\0';
+    for (; n; n--) {
+        pstrcat(dest, dest_size, "..");
+        pstrcat(dest, dest_size, sep);
+    }
+    pstrcat(dest, dest_size, q);
+    return 0;
+}
+
+static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd, idx = 0;
+    char desc[BUF_SIZE];
+    int64_t total_size = 0, filesize;
+    const char *backing_file = NULL;
+    const char *fmt = NULL;
+    int flags = 0;
+    int ret = 0;
+    bool flat, split;
+    char ext_desc_lines[BUF_SIZE] = "";
+    char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
+    const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
+    const char *desc_extent_line;
+    char parent_desc_line[BUF_SIZE] = "";
+    uint32_t parent_cid = 0xffffffff;
+    const char desc_template[] =
+        "# Disk DescriptorFile\n"
+        "version=1\n"
+        "CID=%x\n"
+        "parentCID=%x\n"
+        "createType=\"%s\"\n"
+        "%s"
+        "\n"
+        "# Extent description\n"
+        "%s"
+        "\n"
+        "# The Disk Data Base\n"
+        "#DDB\n"
+        "\n"
+        "ddb.virtualHWVersion = \"%d\"\n"
+        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
+        "ddb.geometry.heads = \"16\"\n"
+        "ddb.geometry.sectors = \"63\"\n"
+        "ddb.adapterType = \"ide\"\n";
+
+    if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
+        return -EINVAL;
+    }
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
+            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
+        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
+            fmt = options->value.s;
+        }
+        options++;
+    }
+    if (!fmt) {
+        /* Default format to monolithicSparse */
+        fmt = "monolithicSparse";
+    } else if (strcmp(fmt, "monolithicFlat") &&
+               strcmp(fmt, "monolithicSparse") &&
+               strcmp(fmt, "twoGbMaxExtentSparse") &&
+               strcmp(fmt, "twoGbMaxExtentFlat")) {
+        fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
+        return -EINVAL;
+    }
+    split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
+              strcmp(fmt, "twoGbMaxExtentSparse"));
+    flat = !(strcmp(fmt, "monolithicFlat") &&
+             strcmp(fmt, "twoGbMaxExtentFlat"));
+    if (flat) {
+        desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
+    } else {
+        desc_extent_line = "RW %lld SPARSE \"%s\"\n";
+    }
+    if (flat && backing_file) {
+        /* not supporting backing file for flat image */
+        return -ENOTSUP;
+    }
+    if (backing_file) {
+        char parent_filename[PATH_MAX];
+        BlockDriverState *bs = bdrv_new("");
+        ret = bdrv_open(bs, backing_file, 0, NULL);
+        if (ret != 0) {
+            bdrv_delete(bs);
+            return ret;
+        }
+        if (strcmp(bs->drv->format_name, "vmdk")) {
+            bdrv_delete(bs);
+            return -EINVAL;
+        }
+        filesize = bdrv_getlength(bs);
+        parent_cid = vmdk_read_cid(bs, 0);
+        bdrv_delete(bs);
+        relative_path(parent_filename, sizeof(parent_filename),
+                      filename, backing_file);
+        snprintf(parent_desc_line, sizeof(parent_desc_line),
+                "parentFileNameHint=\"%s\"", parent_filename);
+    }
+
+    /* Create extents */
+    filesize = total_size;
+    while (filesize > 0) {
+        char desc_line[BUF_SIZE];
+        char ext_filename[PATH_MAX];
+        char desc_filename[PATH_MAX];
+        int64_t size = filesize;
+
+        if (split && size > split_size) {
+            size = split_size;
+        }
+        if (split) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
+                    prefix, flat ? 'f' : 's', ++idx, postfix);
+        } else if (flat) {
+            snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
+                    prefix, postfix);
+        } else {
+            snprintf(desc_filename, sizeof(desc_filename), "%s%s",
+                    prefix, postfix);
+        }
+        snprintf(ext_filename, sizeof(ext_filename), "%s%s",
+                path, desc_filename);
+
+        if (vmdk_create_extent(ext_filename, size, flat)) {
+            return -EINVAL;
+        }
+        filesize -= size;
+
+        /* Format description line */
+        snprintf(desc_line, sizeof(desc_line),
+                    desc_extent_line, size / 512, desc_filename);
+        pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
+    }
+    /* generate descriptor file */
+    snprintf(desc, sizeof(desc), desc_template,
+            (unsigned int)time(NULL),
+            parent_cid,
+            fmt,
+            parent_desc_line,
+            ext_desc_lines,
+            (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
+            total_size / (int64_t)(63 * 16 * 512));
+    if (split || flat) {
+        fd = open(
+                filename,
+                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                0644);
+    } else {
+        fd = open(
+                filename,
+                O_WRONLY | O_BINARY | O_LARGEFILE,
+                0644);
+    }
+    if (fd < 0) {
+        return -errno;
+    }
+    /* the descriptor offset = 0x200 */
+    if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
+        ret = -errno;
+        goto exit;
+    }
+    ret = qemu_write_full(fd, desc, strlen(desc));
+    if (ret != strlen(desc)) {
+        ret = -errno;
+        goto exit;
+    }
+    ret = 0;
+exit:
+    close(fd);
+    return ret;
+}
+
+static void vmdk_close(BlockDriverState *bs)
+{
+    vmdk_free_extents(bs);
+}
+
+static int vmdk_flush(BlockDriverState *bs)
+{
+    int i, ret, err;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_flush(bs->file);
+    for (i = 0; i < s->num_extents; i++) {
+        err = bdrv_flush(s->extents[i].file);
+        if (err < 0) {
+            ret = err;
+        }
+    }
+    return ret;
+}
+
+static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
+{
+    int i;
+    int64_t ret = 0;
+    int64_t r;
+    BDRVVmdkState *s = bs->opaque;
+
+    ret = bdrv_get_allocated_file_size(bs->file);
+    if (ret < 0) {
+        return ret;
+    }
+    for (i = 0; i < s->num_extents; i++) {
+        if (s->extents[i].file == bs->file) {
+            continue;
+        }
+        r = bdrv_get_allocated_file_size(s->extents[i].file);
+        if (r < 0) {
+            return r;
+        }
+        ret += r;
+    }
+    return ret;
+}
+
+static QEMUOptionParameter vmdk_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_COMPAT6,
+        .type = OPT_FLAG,
+        .help = "VMDK version 6 image"
+    },
+    {
+        .name = BLOCK_OPT_SUBFMT,
+        .type = OPT_STRING,
+        .help =
+            "VMDK flat extent format, can be one of "
+            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_vmdk = {
+    .format_name    = "vmdk",
+    .instance_size  = sizeof(BDRVVmdkState),
+    .bdrv_probe     = vmdk_probe,
+    .bdrv_open      = vmdk_open,
+    .bdrv_read      = vmdk_read,
+    .bdrv_write     = vmdk_write,
+    .bdrv_close     = vmdk_close,
+    .bdrv_create    = vmdk_create,
+    .bdrv_flush     = vmdk_flush,
+    .bdrv_is_allocated  = vmdk_is_allocated,
+    .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
+
+    .create_options = vmdk_create_options,
+};
+
+static void bdrv_vmdk_init(void)
+{
+    bdrv_register(&bdrv_vmdk);
+}
+
+block_init(bdrv_vmdk_init);
diff --git a/qemu-0.15.x/block/vpc.c b/qemu-0.15.x/block/vpc.c
new file mode 100644
index 0000000..56865da
--- /dev/null
+++ b/qemu-0.15.x/block/vpc.c
@@ -0,0 +1,650 @@
+/*
+ * Block driver for Connectix / Microsoft Virtual PC images
+ *
+ * Copyright (c) 2005 Alex Beregszaszi
+ * Copyright (c) 2009 Kevin Wolf <kwolf at suse.de>
+ *
+ * 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 "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+/**************************************************************/
+
+#define HEADER_SIZE 512
+
+//#define CACHE
+
+enum vhd_type {
+    VHD_FIXED           = 2,
+    VHD_DYNAMIC         = 3,
+    VHD_DIFFERENCING    = 4,
+};
+
+// Seconds since Jan 1, 2000 0:00:00 (UTC)
+#define VHD_TIMESTAMP_BASE 946684800
+
+// always big-endian
+struct vhd_footer {
+    char        creator[8]; // "conectix"
+    uint32_t    features;
+    uint32_t    version;
+
+    // Offset of next header structure, 0xFFFFFFFF if none
+    uint64_t    data_offset;
+
+    // Seconds since Jan 1, 2000 0:00:00 (UTC)
+    uint32_t    timestamp;
+
+    char        creator_app[4]; // "vpc "
+    uint16_t    major;
+    uint16_t    minor;
+    char        creator_os[4]; // "Wi2k"
+
+    uint64_t    orig_size;
+    uint64_t    size;
+
+    uint16_t    cyls;
+    uint8_t     heads;
+    uint8_t     secs_per_cyl;
+
+    uint32_t    type;
+
+    // Checksum of the Hard Disk Footer ("one's complement of the sum of all
+    // the bytes in the footer without the checksum field")
+    uint32_t    checksum;
+
+    // UUID used to identify a parent hard disk (backing file)
+    uint8_t     uuid[16];
+
+    uint8_t     in_saved_state;
+};
+
+struct vhd_dyndisk_header {
+    char        magic[8]; // "cxsparse"
+
+    // Offset of next header structure, 0xFFFFFFFF if none
+    uint64_t    data_offset;
+
+    // Offset of the Block Allocation Table (BAT)
+    uint64_t    table_offset;
+
+    uint32_t    version;
+    uint32_t    max_table_entries; // 32bit/entry
+
+    // 2 MB by default, must be a power of two
+    uint32_t    block_size;
+
+    uint32_t    checksum;
+    uint8_t     parent_uuid[16];
+    uint32_t    parent_timestamp;
+    uint32_t    reserved;
+
+    // Backing file name (in UTF-16)
+    uint8_t     parent_name[512];
+
+    struct {
+        uint32_t    platform;
+        uint32_t    data_space;
+        uint32_t    data_length;
+        uint32_t    reserved;
+        uint64_t    data_offset;
+    } parent_locator[8];
+};
+
+typedef struct BDRVVPCState {
+    uint8_t footer_buf[HEADER_SIZE];
+    uint64_t free_data_block_offset;
+    int max_table_entries;
+    uint32_t *pagetable;
+    uint64_t bat_offset;
+    uint64_t last_bitmap_offset;
+
+    uint32_t block_size;
+    uint32_t bitmap_size;
+
+#ifdef CACHE
+    uint8_t *pageentry_u8;
+    uint32_t *pageentry_u32;
+    uint16_t *pageentry_u16;
+
+    uint64_t last_bitmap;
+#endif
+} BDRVVPCState;
+
+static uint32_t vpc_checksum(uint8_t* buf, size_t size)
+{
+    uint32_t res = 0;
+    int i;
+
+    for (i = 0; i < size; i++)
+        res += buf[i];
+
+    return ~res;
+}
+
+
+static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
+	return 100;
+    return 0;
+}
+
+static int vpc_open(BlockDriverState *bs, int flags)
+{
+    BDRVVPCState *s = bs->opaque;
+    int i;
+    struct vhd_footer* footer;
+    struct vhd_dyndisk_header* dyndisk_header;
+    uint8_t buf[HEADER_SIZE];
+    uint32_t checksum;
+
+    if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
+        goto fail;
+
+    footer = (struct vhd_footer*) s->footer_buf;
+    if (strncmp(footer->creator, "conectix", 8))
+        goto fail;
+
+    checksum = be32_to_cpu(footer->checksum);
+    footer->checksum = 0;
+    if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
+        fprintf(stderr, "block-vpc: The header checksum of '%s' is "
+            "incorrect.\n", bs->filename);
+
+    // The visible size of a image in Virtual PC depends on the geometry
+    // rather than on the size stored in the footer (the size in the footer
+    // is too large usually)
+    bs->total_sectors = (int64_t)
+        be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
+
+    if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
+            != HEADER_SIZE)
+        goto fail;
+
+    dyndisk_header = (struct vhd_dyndisk_header*) buf;
+
+    if (strncmp(dyndisk_header->magic, "cxsparse", 8))
+        goto fail;
+
+
+    s->block_size = be32_to_cpu(dyndisk_header->block_size);
+    s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
+
+    s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+    s->pagetable = qemu_malloc(s->max_table_entries * 4);
+
+    s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
+    if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
+            s->max_table_entries * 4) != s->max_table_entries * 4)
+	    goto fail;
+
+    s->free_data_block_offset =
+        (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
+
+    for (i = 0; i < s->max_table_entries; i++) {
+        be32_to_cpus(&s->pagetable[i]);
+        if (s->pagetable[i] != 0xFFFFFFFF) {
+            int64_t next = (512 * (int64_t) s->pagetable[i]) +
+                s->bitmap_size + s->block_size;
+
+            if (next> s->free_data_block_offset)
+                s->free_data_block_offset = next;
+        }
+    }
+
+    s->last_bitmap_offset = (int64_t) -1;
+
+#ifdef CACHE
+    s->pageentry_u8 = qemu_malloc(512);
+    s->pageentry_u32 = s->pageentry_u8;
+    s->pageentry_u16 = s->pageentry_u8;
+    s->last_pagetable = -1;
+#endif
+
+    return 0;
+ fail:
+    return -1;
+}
+
+/*
+ * Returns the absolute byte offset of the given sector in the image file.
+ * If the sector is not allocated, -1 is returned instead.
+ *
+ * The parameter write must be 1 if the offset will be used for a write
+ * operation (the block bitmaps is updated then), 0 otherwise.
+ */
+static inline int64_t get_sector_offset(BlockDriverState *bs,
+    int64_t sector_num, int write)
+{
+    BDRVVPCState *s = bs->opaque;
+    uint64_t offset = sector_num * 512;
+    uint64_t bitmap_offset, block_offset;
+    uint32_t pagetable_index, pageentry_index;
+
+    pagetable_index = offset / s->block_size;
+    pageentry_index = (offset % s->block_size) / 512;
+
+    if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
+        return -1; // not allocated
+
+    bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
+    block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
+
+    // We must ensure that we don't write to any sectors which are marked as
+    // unused in the bitmap. We get away with setting all bits in the block
+    // bitmap each time we write to a new block. This might cause Virtual PC to
+    // miss sparse read optimization, but it's not a problem in terms of
+    // correctness.
+    if (write && (s->last_bitmap_offset != bitmap_offset)) {
+        uint8_t bitmap[s->bitmap_size];
+
+        s->last_bitmap_offset = bitmap_offset;
+        memset(bitmap, 0xff, s->bitmap_size);
+        bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+    }
+
+//    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
+//	sector_num, pagetable_index, pageentry_index,
+//	bitmap_offset, block_offset);
+
+// disabled by reason
+#if 0
+#ifdef CACHE
+    if (bitmap_offset != s->last_bitmap)
+    {
+	lseek(s->fd, bitmap_offset, SEEK_SET);
+
+	s->last_bitmap = bitmap_offset;
+
+	// Scary! Bitmap is stored as big endian 32bit entries,
+	// while we used to look it up byte by byte
+	read(s->fd, s->pageentry_u8, 512);
+	for (i = 0; i < 128; i++)
+	    be32_to_cpus(&s->pageentry_u32[i]);
+    }
+
+    if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
+	return -1;
+#else
+    lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
+
+    read(s->fd, &bitmap_entry, 1);
+
+    if ((bitmap_entry >> (pageentry_index % 8)) & 1)
+	return -1; // not allocated
+#endif
+#endif
+
+    return block_offset;
+}
+
+/*
+ * Writes the footer to the end of the image file. This is needed when the
+ * file grows as it overwrites the old footer
+ *
+ * Returns 0 on success and < 0 on error
+ */
+static int rewrite_footer(BlockDriverState* bs)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    int64_t offset = s->free_data_block_offset;
+
+    ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * Allocates a new block. This involves writing a new footer and updating
+ * the Block Allocation Table to use the space at the old end of the image
+ * file (overwriting the old footer)
+ *
+ * Returns the sectors' offset in the image file on success and < 0 on error
+ */
+static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
+{
+    BDRVVPCState *s = bs->opaque;
+    int64_t bat_offset;
+    uint32_t index, bat_value;
+    int ret;
+    uint8_t bitmap[s->bitmap_size];
+
+    // Check if sector_num is valid
+    if ((sector_num < 0) || (sector_num > bs->total_sectors))
+        return -1;
+
+    // Write entry into in-memory BAT
+    index = (sector_num * 512) / s->block_size;
+    if (s->pagetable[index] != 0xFFFFFFFF)
+        return -1;
+
+    s->pagetable[index] = s->free_data_block_offset / 512;
+
+    // Initialize the block's bitmap
+    memset(bitmap, 0xff, s->bitmap_size);
+    bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+        s->bitmap_size);
+
+    // Write new footer (the old one will be overwritten)
+    s->free_data_block_offset += s->block_size + s->bitmap_size;
+    ret = rewrite_footer(bs);
+    if (ret < 0)
+        goto fail;
+
+    // Write BAT entry to disk
+    bat_offset = s->bat_offset + (4 * index);
+    bat_value = be32_to_cpu(s->pagetable[index]);
+    ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
+    if (ret < 0)
+        goto fail;
+
+    return get_sector_offset(bs, sector_num, 0);
+
+fail:
+    s->free_data_block_offset -= (s->block_size + s->bitmap_size);
+    return -1;
+}
+
+static int vpc_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVVPCState *s = bs->opaque;
+    int ret;
+    int64_t offset;
+    int64_t sectors, sectors_per_block;
+
+    while (nb_sectors > 0) {
+        offset = get_sector_offset(bs, sector_num, 0);
+
+        sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+        sectors = sectors_per_block - (sector_num % sectors_per_block);
+        if (sectors > nb_sectors) {
+            sectors = nb_sectors;
+        }
+
+        if (offset == -1) {
+            memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
+        } else {
+            ret = bdrv_pread(bs->file, offset, buf,
+                sectors * BDRV_SECTOR_SIZE);
+            if (ret != sectors * BDRV_SECTOR_SIZE) {
+                return -1;
+            }
+        }
+
+        nb_sectors -= sectors;
+        sector_num += sectors;
+        buf += sectors * BDRV_SECTOR_SIZE;
+    }
+    return 0;
+}
+
+static int vpc_write(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors)
+{
+    BDRVVPCState *s = bs->opaque;
+    int64_t offset;
+    int64_t sectors, sectors_per_block;
+    int ret;
+
+    while (nb_sectors > 0) {
+        offset = get_sector_offset(bs, sector_num, 1);
+
+        sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+        sectors = sectors_per_block - (sector_num % sectors_per_block);
+        if (sectors > nb_sectors) {
+            sectors = nb_sectors;
+        }
+
+        if (offset == -1) {
+            offset = alloc_block(bs, sector_num);
+            if (offset < 0)
+                return -1;
+        }
+
+        ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
+        if (ret != sectors * BDRV_SECTOR_SIZE) {
+            return -1;
+        }
+
+        nb_sectors -= sectors;
+        sector_num += sectors;
+        buf += sectors * BDRV_SECTOR_SIZE;
+    }
+
+    return 0;
+}
+
+static int vpc_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+/*
+ * Calculates the number of cylinders, heads and sectors per cylinder
+ * based on a given number of sectors. This is the algorithm described
+ * in the VHD specification.
+ *
+ * Note that the geometry doesn't always exactly match total_sectors but
+ * may round it down.
+ *
+ * Returns 0 on success, -EFBIG if the size is larger than 127 GB
+ */
+static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
+    uint8_t* heads, uint8_t* secs_per_cyl)
+{
+    uint32_t cyls_times_heads;
+
+    if (total_sectors > 65535 * 16 * 255)
+        return -EFBIG;
+
+    if (total_sectors > 65535 * 16 * 63) {
+        *secs_per_cyl = 255;
+        *heads = 16;
+        cyls_times_heads = total_sectors / *secs_per_cyl;
+    } else {
+        *secs_per_cyl = 17;
+        cyls_times_heads = total_sectors / *secs_per_cyl;
+        *heads = (cyls_times_heads + 1023) / 1024;
+
+        if (*heads < 4)
+            *heads = 4;
+
+        if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
+            *secs_per_cyl = 31;
+            *heads = 16;
+            cyls_times_heads = total_sectors / *secs_per_cyl;
+        }
+
+        if (cyls_times_heads >= (*heads * 1024)) {
+            *secs_per_cyl = 63;
+            *heads = 16;
+            cyls_times_heads = total_sectors / *secs_per_cyl;
+        }
+    }
+
+    *cyls = cyls_times_heads / *heads;
+
+    return 0;
+}
+
+static int vpc_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint8_t buf[1024];
+    struct vhd_footer* footer = (struct vhd_footer*) buf;
+    struct vhd_dyndisk_header* dyndisk_header =
+        (struct vhd_dyndisk_header*) buf;
+    int fd, i;
+    uint16_t cyls = 0;
+    uint8_t heads = 0;
+    uint8_t secs_per_cyl = 0;
+    size_t block_size, num_bat_entries;
+    int64_t total_sectors = 0;
+    int ret = -EIO;
+
+    // Read out options
+    total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
+                    BDRV_SECTOR_SIZE;
+
+    // Create the file
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -EIO;
+
+    /* Calculate matching total_size and geometry. Increase the number of
+       sectors requested until we get enough (or fail). */
+    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+        if (calculate_geometry(total_sectors + i,
+                               &cyls, &heads, &secs_per_cyl)) {
+            ret = -EFBIG;
+            goto fail;
+        }
+    }
+    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+    // Prepare the Hard Disk Footer
+    memset(buf, 0, 1024);
+
+    memcpy(footer->creator, "conectix", 8);
+    // TODO Check if "qemu" creator_app is ok for VPC
+    memcpy(footer->creator_app, "qemu", 4);
+    memcpy(footer->creator_os, "Wi2k", 4);
+
+    footer->features = be32_to_cpu(0x02);
+    footer->version = be32_to_cpu(0x00010000);
+    footer->data_offset = be64_to_cpu(HEADER_SIZE);
+    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+    // Version of Virtual PC 2007
+    footer->major = be16_to_cpu(0x0005);
+    footer->minor =be16_to_cpu(0x0003);
+
+    footer->orig_size = be64_to_cpu(total_sectors * 512);
+    footer->size = be64_to_cpu(total_sectors * 512);
+
+    footer->cyls = be16_to_cpu(cyls);
+    footer->heads = heads;
+    footer->secs_per_cyl = secs_per_cyl;
+
+    footer->type = be32_to_cpu(VHD_DYNAMIC);
+
+    // TODO uuid is missing
+
+    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+    // Write the footer (twice: at the beginning and at the end)
+    block_size = 0x200000;
+    num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
+
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
+
+    if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0) {
+        goto fail;
+    }
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
+
+    // Write the initial BAT
+    if (lseek(fd, 3 * 512, SEEK_SET) < 0) {
+        goto fail;
+    }
+
+    memset(buf, 0xFF, 512);
+    for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
+        if (write(fd, buf, 512) != 512) {
+            goto fail;
+        }
+    }
+
+
+    // Prepare the Dynamic Disk Header
+    memset(buf, 0, 1024);
+
+    memcpy(dyndisk_header->magic, "cxsparse", 8);
+
+    dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
+    dyndisk_header->table_offset = be64_to_cpu(3 * 512);
+    dyndisk_header->version = be32_to_cpu(0x00010000);
+    dyndisk_header->block_size = be32_to_cpu(block_size);
+    dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
+
+    dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
+
+    // Write the header
+    if (lseek(fd, 512, SEEK_SET) < 0) {
+        goto fail;
+    }
+
+    if (write(fd, buf, 1024) != 1024) {
+        goto fail;
+    }
+    ret = 0;
+
+ fail:
+    close(fd);
+    return ret;
+}
+
+static void vpc_close(BlockDriverState *bs)
+{
+    BDRVVPCState *s = bs->opaque;
+    qemu_free(s->pagetable);
+#ifdef CACHE
+    qemu_free(s->pageentry_u8);
+#endif
+}
+
+static QEMUOptionParameter vpc_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_vpc = {
+    .format_name    = "vpc",
+    .instance_size  = sizeof(BDRVVPCState),
+    .bdrv_probe     = vpc_probe,
+    .bdrv_open      = vpc_open,
+    .bdrv_read      = vpc_read,
+    .bdrv_write     = vpc_write,
+    .bdrv_flush     = vpc_flush,
+    .bdrv_close     = vpc_close,
+    .bdrv_create    = vpc_create,
+
+    .create_options = vpc_create_options,
+};
+
+static void bdrv_vpc_init(void)
+{
+    bdrv_register(&bdrv_vpc);
+}
+
+block_init(bdrv_vpc_init);
diff --git a/qemu-0.15.x/block/vvfat.c b/qemu-0.15.x/block/vvfat.c
new file mode 100644
index 0000000..fe568fe
--- /dev/null
+++ b/qemu-0.15.x/block/vvfat.c
@@ -0,0 +1,2888 @@
+/* vim:set shiftwidth=4 ts=8: */
+/*
+ * QEMU Block driver for virtual VFAT (shadows a local directory)
+ *
+ * Copyright (c) 2004,2005 Johannes E. Schindelin
+ *
+ * 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 <sys/stat.h>
+#include <dirent.h>
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+#ifndef S_IWGRP
+#define S_IWGRP 0
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0
+#endif
+
+/* TODO: add ":bootsector=blabla.img:" */
+/* LATER TODO: add automatic boot sector generation from
+    BOOTEASY.ASM and Ranish Partition Manager
+    Note that DOS assumes the system files to be the first files in the
+    file system (test if the boot sector still relies on that fact)! */
+/* MAYBE TODO: write block-visofs.c */
+/* TODO: call try_commit() only after a timeout */
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+
+#define DLOG(a) a
+
+#undef stderr
+#define stderr STDERR
+FILE* stderr = NULL;
+
+static void checkpoint(void);
+
+#ifdef __MINGW32__
+void nonono(const char* file, int line, const char* msg) {
+    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
+    exit(-5);
+}
+#undef assert
+#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
+#endif
+
+#else
+
+#define DLOG(a)
+
+#endif
+
+/* dynamic array functions */
+typedef struct array_t {
+    char* pointer;
+    unsigned int size,next,item_size;
+} array_t;
+
+static inline void array_init(array_t* array,unsigned int item_size)
+{
+    array->pointer = NULL;
+    array->size=0;
+    array->next=0;
+    array->item_size=item_size;
+}
+
+static inline void array_free(array_t* array)
+{
+    if(array->pointer)
+        free(array->pointer);
+    array->size=array->next=0;
+}
+
+/* does not automatically grow */
+static inline void* array_get(array_t* array,unsigned int index) {
+    assert(index < array->next);
+    return array->pointer + index * array->item_size;
+}
+
+static inline int array_ensure_allocated(array_t* array, int index)
+{
+    if((index + 1) * array->item_size > array->size) {
+	int new_size = (index + 32) * array->item_size;
+	array->pointer = qemu_realloc(array->pointer, new_size);
+	if (!array->pointer)
+	    return -1;
+	array->size = new_size;
+	array->next = index + 1;
+    }
+
+    return 0;
+}
+
+static inline void* array_get_next(array_t* array) {
+    unsigned int next = array->next;
+    void* result;
+
+    if (array_ensure_allocated(array, next) < 0)
+	return NULL;
+
+    array->next = next + 1;
+    result = array_get(array, next);
+
+    return result;
+}
+
+static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
+    if((array->next+count)*array->item_size>array->size) {
+	int increment=count*array->item_size;
+	array->pointer=qemu_realloc(array->pointer,array->size+increment);
+	if(!array->pointer)
+            return NULL;
+	array->size+=increment;
+    }
+    memmove(array->pointer+(index+count)*array->item_size,
+		array->pointer+index*array->item_size,
+		(array->next-index)*array->item_size);
+    array->next+=count;
+    return array->pointer+index*array->item_size;
+}
+
+/* this performs a "roll", so that the element which was at index_from becomes
+ * index_to, but the order of all other elements is preserved. */
+static inline int array_roll(array_t* array,int index_to,int index_from,int count)
+{
+    char* buf;
+    char* from;
+    char* to;
+    int is;
+
+    if(!array ||
+	    index_to<0 || index_to>=array->next ||
+	    index_from<0 || index_from>=array->next)
+	return -1;
+
+    if(index_to==index_from)
+	return 0;
+
+    is=array->item_size;
+    from=array->pointer+index_from*is;
+    to=array->pointer+index_to*is;
+    buf=qemu_malloc(is*count);
+    memcpy(buf,from,is*count);
+
+    if(index_to<index_from)
+	memmove(to+is*count,to,from-to);
+    else
+	memmove(from,from+is*count,to-from);
+
+    memcpy(to,buf,is*count);
+
+    free(buf);
+
+    return 0;
+}
+
+static inline int array_remove_slice(array_t* array,int index, int count)
+{
+    assert(index >=0);
+    assert(count > 0);
+    assert(index + count <= array->next);
+    if(array_roll(array,array->next-1,index,count))
+	return -1;
+    array->next -= count;
+    return 0;
+}
+
+static int array_remove(array_t* array,int index)
+{
+    return array_remove_slice(array, index, 1);
+}
+
+/* return the index for a given member */
+static int array_index(array_t* array, void* pointer)
+{
+    size_t offset = (char*)pointer - array->pointer;
+    assert((offset % array->item_size) == 0);
+    assert(offset/array->item_size < array->next);
+    return offset/array->item_size;
+}
+
+/* These structures are used to fake a disk and the VFAT filesystem.
+ * For this reason we need to use __attribute__((packed)). */
+
+typedef struct bootsector_t {
+    uint8_t jump[3];
+    uint8_t name[8];
+    uint16_t sector_size;
+    uint8_t sectors_per_cluster;
+    uint16_t reserved_sectors;
+    uint8_t number_of_fats;
+    uint16_t root_entries;
+    uint16_t total_sectors16;
+    uint8_t media_type;
+    uint16_t sectors_per_fat;
+    uint16_t sectors_per_track;
+    uint16_t number_of_heads;
+    uint32_t hidden_sectors;
+    uint32_t total_sectors;
+    union {
+        struct {
+	    uint8_t drive_number;
+	    uint8_t current_head;
+	    uint8_t signature;
+	    uint32_t id;
+	    uint8_t volume_label[11];
+	} __attribute__((packed)) fat16;
+	struct {
+	    uint32_t sectors_per_fat;
+	    uint16_t flags;
+	    uint8_t major,minor;
+	    uint32_t first_cluster_of_root_directory;
+	    uint16_t info_sector;
+	    uint16_t backup_boot_sector;
+	    uint16_t ignored;
+	} __attribute__((packed)) fat32;
+    } u;
+    uint8_t fat_type[8];
+    uint8_t ignored[0x1c0];
+    uint8_t magic[2];
+} __attribute__((packed)) bootsector_t;
+
+typedef struct {
+    uint8_t head;
+    uint8_t sector;
+    uint8_t cylinder;
+} mbr_chs_t;
+
+typedef struct partition_t {
+    uint8_t attributes; /* 0x80 = bootable */
+    mbr_chs_t start_CHS;
+    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
+    mbr_chs_t end_CHS;
+    uint32_t start_sector_long;
+    uint32_t length_sector_long;
+} __attribute__((packed)) partition_t;
+
+typedef struct mbr_t {
+    uint8_t ignored[0x1b8];
+    uint32_t nt_id;
+    uint8_t ignored2[2];
+    partition_t partition[4];
+    uint8_t magic[2];
+} __attribute__((packed)) mbr_t;
+
+typedef struct direntry_t {
+    uint8_t name[8];
+    uint8_t extension[3];
+    uint8_t attributes;
+    uint8_t reserved[2];
+    uint16_t ctime;
+    uint16_t cdate;
+    uint16_t adate;
+    uint16_t begin_hi;
+    uint16_t mtime;
+    uint16_t mdate;
+    uint16_t begin;
+    uint32_t size;
+} __attribute__((packed)) direntry_t;
+
+/* this structure are used to transparently access the files */
+
+typedef struct mapping_t {
+    /* begin is the first cluster, end is the last+1 */
+    uint32_t begin,end;
+    /* as s->directory is growable, no pointer may be used here */
+    unsigned int dir_index;
+    /* the clusters of a file may be in any order; this points to the first */
+    int first_mapping_index;
+    union {
+	/* offset is
+	 * - the offset in the file (in clusters) for a file, or
+	 * - the next cluster of the directory for a directory, and
+	 * - the address of the buffer for a faked entry
+	 */
+	struct {
+	    uint32_t offset;
+	} file;
+	struct {
+	    int parent_mapping_index;
+	    int first_dir_index;
+	} dir;
+    } info;
+    /* path contains the full path, i.e. it always starts with s->path */
+    char* path;
+
+    enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
+	MODE_DIRECTORY = 4, MODE_FAKED = 8,
+	MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
+    int read_only;
+} mapping_t;
+
+#ifdef DEBUG
+static void print_direntry(const struct direntry_t*);
+static void print_mapping(const struct mapping_t* mapping);
+#endif
+
+/* here begins the real VVFAT driver */
+
+typedef struct BDRVVVFATState {
+    BlockDriverState* bs; /* pointer to parent */
+    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
+    unsigned char first_sectors[0x40*0x200];
+
+    int fat_type; /* 16 or 32 */
+    array_t fat,directory,mapping;
+
+    unsigned int cluster_size;
+    unsigned int sectors_per_cluster;
+    unsigned int sectors_per_fat;
+    unsigned int sectors_of_root_directory;
+    uint32_t last_cluster_of_root_directory;
+    unsigned int faked_sectors; /* how many sectors are faked before file data */
+    uint32_t sector_count; /* total number of sectors of the partition */
+    uint32_t cluster_count; /* total number of clusters of this partition */
+    uint32_t max_fat_value;
+
+    int current_fd;
+    mapping_t* current_mapping;
+    unsigned char* cluster; /* points to current cluster */
+    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
+    unsigned int current_cluster;
+
+    /* write support */
+    BlockDriverState* write_target;
+    char* qcow_filename;
+    BlockDriverState* qcow;
+    void* fat2;
+    char* used_clusters;
+    array_t commits;
+    const char* path;
+    int downcase_short_names;
+} BDRVVVFATState;
+
+/* take the sector position spos and convert it to Cylinder/Head/Sector position
+ * if the position is outside the specified geometry, fill maximum value for CHS
+ * and return 1 to signal overflow.
+ */
+static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
+    int head,sector;
+    sector   = spos % (bs->secs);  spos/= bs->secs;
+    head     = spos % (bs->heads); spos/= bs->heads;
+    if(spos >= bs->cyls){
+        /* Overflow,
+        it happens if 32bit sector positions are used, while CHS is only 24bit.
+        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
+        chs->head     = 0xFF;
+        chs->sector   = 0xFF;
+        chs->cylinder = 0xFF;
+        return 1;
+    }
+    chs->head     = (uint8_t)head;
+    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
+    chs->cylinder = (uint8_t)spos;
+    return 0;
+}
+
+static void init_mbr(BDRVVVFATState* s)
+{
+    /* TODO: if the files mbr.img and bootsect.img exist, use them */
+    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
+    partition_t* partition = &(real_mbr->partition[0]);
+    int lba;
+
+    memset(s->first_sectors,0,512);
+
+    /* Win NT Disk Signature */
+    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
+
+    partition->attributes=0x80; /* bootable */
+
+    /* LBA is used when partition is outside the CHS geometry */
+    lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
+    lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
+
+    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
+    partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
+    partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
+
+    /* FAT12/FAT16/FAT32 */
+    /* DOS uses different types when partition is LBA,
+       probably to prevent older versions from using CHS on them */
+    partition->fs_type= s->fat_type==12 ? 0x1:
+                        s->fat_type==16 ? (lba?0xe:0x06):
+                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
+
+    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
+}
+
+/* direntry functions */
+
+/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
+static inline int short2long_name(char* dest,const char* src)
+{
+    int i;
+    int len;
+    for(i=0;i<129 && src[i];i++) {
+        dest[2*i]=src[i];
+	dest[2*i+1]=0;
+    }
+    len=2*i;
+    dest[2*i]=dest[2*i+1]=0;
+    for(i=2*i+2;(i%26);i++)
+	dest[i]=0xff;
+    return len;
+}
+
+static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
+{
+    char buffer[258];
+    int length=short2long_name(buffer,filename),
+        number_of_entries=(length+25)/26,i;
+    direntry_t* entry;
+
+    for(i=0;i<number_of_entries;i++) {
+	entry=array_get_next(&(s->directory));
+	entry->attributes=0xf;
+	entry->reserved[0]=0;
+	entry->begin=0;
+	entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
+    }
+    for(i=0;i<26*number_of_entries;i++) {
+	int offset=(i%26);
+	if(offset<10) offset=1+offset;
+	else if(offset<22) offset=14+offset-10;
+	else offset=28+offset-22;
+	entry=array_get(&(s->directory),s->directory.next-1-(i/26));
+	entry->name[offset]=buffer[i];
+    }
+    return array_get(&(s->directory),s->directory.next-number_of_entries);
+}
+
+static char is_free(const direntry_t* direntry)
+{
+    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
+}
+
+static char is_volume_label(const direntry_t* direntry)
+{
+    return direntry->attributes == 0x28;
+}
+
+static char is_long_name(const direntry_t* direntry)
+{
+    return direntry->attributes == 0xf;
+}
+
+static char is_short_name(const direntry_t* direntry)
+{
+    return !is_volume_label(direntry) && !is_long_name(direntry)
+	&& !is_free(direntry);
+}
+
+static char is_directory(const direntry_t* direntry)
+{
+    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
+}
+
+static inline char is_dot(const direntry_t* direntry)
+{
+    return is_short_name(direntry) && direntry->name[0] == '.';
+}
+
+static char is_file(const direntry_t* direntry)
+{
+    return is_short_name(direntry) && !is_directory(direntry);
+}
+
+static inline uint32_t begin_of_direntry(const direntry_t* direntry)
+{
+    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
+}
+
+static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
+{
+    return le32_to_cpu(direntry->size);
+}
+
+static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
+{
+    direntry->begin = cpu_to_le16(begin & 0xffff);
+    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
+}
+
+/* fat functions */
+
+static inline uint8_t fat_chksum(const direntry_t* entry)
+{
+    uint8_t chksum=0;
+    int i;
+
+    for(i=0;i<11;i++) {
+        unsigned char c;
+
+        c = (i < 8) ? entry->name[i] : entry->extension[i-8];
+        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
+    }
+
+    return chksum;
+}
+
+/* if return_time==0, this returns the fat_date, else the fat_time */
+static uint16_t fat_datetime(time_t time,int return_time) {
+    struct tm* t;
+#ifdef _WIN32
+    t=localtime(&time); /* this is not thread safe */
+#else
+    struct tm t1;
+    t = &t1;
+    localtime_r(&time,t);
+#endif
+    if(return_time)
+	return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
+    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
+}
+
+static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
+{
+    if(s->fat_type==32) {
+	uint32_t* entry=array_get(&(s->fat),cluster);
+	*entry=cpu_to_le32(value);
+    } else if(s->fat_type==16) {
+	uint16_t* entry=array_get(&(s->fat),cluster);
+	*entry=cpu_to_le16(value&0xffff);
+    } else {
+	int offset = (cluster*3/2);
+	unsigned char* p = array_get(&(s->fat), offset);
+        switch (cluster&1) {
+	case 0:
+		p[0] = value&0xff;
+		p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
+		break;
+	case 1:
+		p[0] = (p[0]&0xf) | ((value&0xf)<<4);
+		p[1] = (value>>4);
+		break;
+	}
+    }
+}
+
+static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
+{
+    if(s->fat_type==32) {
+	uint32_t* entry=array_get(&(s->fat),cluster);
+	return le32_to_cpu(*entry);
+    } else if(s->fat_type==16) {
+	uint16_t* entry=array_get(&(s->fat),cluster);
+	return le16_to_cpu(*entry);
+    } else {
+	const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
+	return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+    }
+}
+
+static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
+{
+    if(fat_entry>s->max_fat_value-8)
+	return -1;
+    return 0;
+}
+
+static inline void init_fat(BDRVVVFATState* s)
+{
+    if (s->fat_type == 12) {
+	array_init(&(s->fat),1);
+	array_ensure_allocated(&(s->fat),
+		s->sectors_per_fat * 0x200 * 3 / 2 - 1);
+    } else {
+	array_init(&(s->fat),(s->fat_type==32?4:2));
+	array_ensure_allocated(&(s->fat),
+		s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
+    }
+    memset(s->fat.pointer,0,s->fat.size);
+
+    switch(s->fat_type) {
+	case 12: s->max_fat_value=0xfff; break;
+	case 16: s->max_fat_value=0xffff; break;
+	case 32: s->max_fat_value=0x0fffffff; break;
+	default: s->max_fat_value=0; /* error... */
+    }
+
+}
+
+/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
+/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
+static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
+	unsigned int directory_start, const char* filename, int is_dot)
+{
+    int i,j,long_index=s->directory.next;
+    direntry_t* entry = NULL;
+    direntry_t* entry_long = NULL;
+
+    if(is_dot) {
+	entry=array_get_next(&(s->directory));
+	memset(entry->name,0x20,11);
+	memcpy(entry->name,filename,strlen(filename));
+	return entry;
+    }
+
+    entry_long=create_long_filename(s,filename);
+
+    i = strlen(filename);
+    for(j = i - 1; j>0  && filename[j]!='.';j--);
+    if (j > 0)
+	i = (j > 8 ? 8 : j);
+    else if (i > 8)
+	i = 8;
+
+    entry=array_get_next(&(s->directory));
+    memset(entry->name,0x20,11);
+    memcpy(entry->name, filename, i);
+
+    if(j > 0)
+	for (i = 0; i < 3 && filename[j+1+i]; i++)
+	    entry->extension[i] = filename[j+1+i];
+
+    /* upcase & remove unwanted characters */
+    for(i=10;i>=0;i--) {
+	if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
+	if(entry->name[i]<=' ' || entry->name[i]>0x7f
+		|| strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
+	    entry->name[i]='_';
+        else if(entry->name[i]>='a' && entry->name[i]<='z')
+            entry->name[i]+='A'-'a';
+    }
+
+    /* mangle duplicates */
+    while(1) {
+	direntry_t* entry1=array_get(&(s->directory),directory_start);
+	int j;
+
+	for(;entry1<entry;entry1++)
+	    if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
+		break; /* found dupe */
+	if(entry1==entry) /* no dupe found */
+	    break;
+
+	/* use all 8 characters of name */
+	if(entry->name[7]==' ') {
+	    int j;
+	    for(j=6;j>0 && entry->name[j]==' ';j--)
+		entry->name[j]='~';
+	}
+
+	/* increment number */
+	for(j=7;j>0 && entry->name[j]=='9';j--)
+	    entry->name[j]='0';
+	if(j>0) {
+	    if(entry->name[j]<'0' || entry->name[j]>'9')
+	        entry->name[j]='0';
+	    else
+	        entry->name[j]++;
+	}
+    }
+
+    /* calculate checksum; propagate to long name */
+    if(entry_long) {
+        uint8_t chksum=fat_chksum(entry);
+
+	/* calculate anew, because realloc could have taken place */
+	entry_long=array_get(&(s->directory),long_index);
+	while(entry_long<entry && is_long_name(entry_long)) {
+	    entry_long->reserved[1]=chksum;
+	    entry_long++;
+	}
+    }
+
+    return entry;
+}
+
+/*
+ * Read a directory. (the index of the corresponding mapping must be passed).
+ */
+static int read_directory(BDRVVVFATState* s, int mapping_index)
+{
+    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+    direntry_t* direntry;
+    const char* dirname = mapping->path;
+    int first_cluster = mapping->begin;
+    int parent_index = mapping->info.dir.parent_mapping_index;
+    mapping_t* parent_mapping = (mapping_t*)
+        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
+    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
+
+    DIR* dir=opendir(dirname);
+    struct dirent* entry;
+    int i;
+
+    assert(mapping->mode & MODE_DIRECTORY);
+
+    if(!dir) {
+	mapping->end = mapping->begin;
+	return -1;
+    }
+
+    i = mapping->info.dir.first_dir_index =
+	    first_cluster == 0 ? 0 : s->directory.next;
+
+    /* actually read the directory, and allocate the mappings */
+    while((entry=readdir(dir))) {
+	unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
+        char* buffer;
+	direntry_t* direntry;
+        struct stat st;
+	int is_dot=!strcmp(entry->d_name,".");
+	int is_dotdot=!strcmp(entry->d_name,"..");
+
+	if(first_cluster == 0 && (is_dotdot || is_dot))
+	    continue;
+
+	buffer=(char*)qemu_malloc(length);
+	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
+
+	if(stat(buffer,&st)<0) {
+	    free(buffer);
+            continue;
+	}
+
+	/* create directory entry for this file */
+	direntry=create_short_and_long_name(s, i, entry->d_name,
+		is_dot || is_dotdot);
+	direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
+	direntry->reserved[0]=direntry->reserved[1]=0;
+	direntry->ctime=fat_datetime(st.st_ctime,1);
+	direntry->cdate=fat_datetime(st.st_ctime,0);
+	direntry->adate=fat_datetime(st.st_atime,0);
+	direntry->begin_hi=0;
+	direntry->mtime=fat_datetime(st.st_mtime,1);
+	direntry->mdate=fat_datetime(st.st_mtime,0);
+	if(is_dotdot)
+	    set_begin_of_direntry(direntry, first_cluster_of_parent);
+	else if(is_dot)
+	    set_begin_of_direntry(direntry, first_cluster);
+	else
+	    direntry->begin=0; /* do that later */
+        if (st.st_size > 0x7fffffff) {
+	    fprintf(stderr, "File %s is larger than 2GB\n", buffer);
+	    free(buffer);
+            closedir(dir);
+	    return -2;
+        }
+	direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
+
+	/* create mapping for this file */
+	if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
+	    s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
+	    s->current_mapping->begin=0;
+	    s->current_mapping->end=st.st_size;
+	    /*
+	     * we get the direntry of the most recent direntry, which
+	     * contains the short name and all the relevant information.
+	     */
+	    s->current_mapping->dir_index=s->directory.next-1;
+	    s->current_mapping->first_mapping_index = -1;
+	    if (S_ISDIR(st.st_mode)) {
+		s->current_mapping->mode = MODE_DIRECTORY;
+		s->current_mapping->info.dir.parent_mapping_index =
+		    mapping_index;
+	    } else {
+		s->current_mapping->mode = MODE_UNDEFINED;
+		s->current_mapping->info.file.offset = 0;
+	    }
+	    s->current_mapping->path=buffer;
+	    s->current_mapping->read_only =
+		(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
+	}
+    }
+    closedir(dir);
+
+    /* fill with zeroes up to the end of the cluster */
+    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
+	direntry_t* direntry=array_get_next(&(s->directory));
+	memset(direntry,0,sizeof(direntry_t));
+    }
+
+/* TODO: if there are more entries, bootsector has to be adjusted! */
+#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
+    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
+	/* root directory */
+	int cur = s->directory.next;
+	array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
+	memset(array_get(&(s->directory), cur), 0,
+		(ROOT_ENTRIES - cur) * sizeof(direntry_t));
+    }
+
+     /* reget the mapping, since s->mapping was possibly realloc()ed */
+    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
+    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
+	* 0x20 / s->cluster_size;
+    mapping->end = first_cluster;
+
+    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
+    set_begin_of_direntry(direntry, mapping->begin);
+
+    return 0;
+}
+
+static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
+{
+    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
+}
+
+static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
+{
+    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
+}
+
+static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
+{
+    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
+}
+
+#ifdef DBG
+static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
+{
+    if(mapping->mode==MODE_UNDEFINED)
+	return 0;
+    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
+}
+#endif
+
+static int init_directories(BDRVVVFATState* s,
+	const char* dirname)
+{
+    bootsector_t* bootsector;
+    mapping_t* mapping;
+    unsigned int i;
+    unsigned int cluster;
+
+    memset(&(s->first_sectors[0]),0,0x40*0x200);
+
+    s->cluster_size=s->sectors_per_cluster*0x200;
+    s->cluster_buffer=qemu_malloc(s->cluster_size);
+
+    /*
+     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
+     * where sc is sector_count,
+     * spf is sectors_per_fat,
+     * spc is sectors_per_clusters, and
+     * fat_type = 12, 16 or 32.
+     */
+    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
+    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
+
+    array_init(&(s->mapping),sizeof(mapping_t));
+    array_init(&(s->directory),sizeof(direntry_t));
+
+    /* add volume label */
+    {
+	direntry_t* entry=array_get_next(&(s->directory));
+	entry->attributes=0x28; /* archive | volume label */
+	memcpy(entry->name,"QEMU VVF",8);
+	memcpy(entry->extension,"AT ",3);
+    }
+
+    /* Now build FAT, and write back information into directory */
+    init_fat(s);
+
+    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
+    s->cluster_count=sector2cluster(s, s->sector_count);
+
+    mapping = array_get_next(&(s->mapping));
+    mapping->begin = 0;
+    mapping->dir_index = 0;
+    mapping->info.dir.parent_mapping_index = -1;
+    mapping->first_mapping_index = -1;
+    mapping->path = qemu_strdup(dirname);
+    i = strlen(mapping->path);
+    if (i > 0 && mapping->path[i - 1] == '/')
+	mapping->path[i - 1] = '\0';
+    mapping->mode = MODE_DIRECTORY;
+    mapping->read_only = 0;
+    s->path = mapping->path;
+
+    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
+	/* MS-DOS expects the FAT to be 0 for the root directory
+	 * (except for the media byte). */
+	/* LATER TODO: still true for FAT32? */
+	int fix_fat = (i != 0);
+	mapping = array_get(&(s->mapping), i);
+
+        if (mapping->mode & MODE_DIRECTORY) {
+	    mapping->begin = cluster;
+	    if(read_directory(s, i)) {
+		fprintf(stderr, "Could not read directory %s\n",
+			mapping->path);
+		return -1;
+	    }
+	    mapping = array_get(&(s->mapping), i);
+	} else {
+	    assert(mapping->mode == MODE_UNDEFINED);
+	    mapping->mode=MODE_NORMAL;
+	    mapping->begin = cluster;
+	    if (mapping->end > 0) {
+		direntry_t* direntry = array_get(&(s->directory),
+			mapping->dir_index);
+
+		mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
+		set_begin_of_direntry(direntry, mapping->begin);
+	    } else {
+		mapping->end = cluster + 1;
+		fix_fat = 0;
+	    }
+	}
+
+	assert(mapping->begin < mapping->end);
+
+	/* next free cluster */
+	cluster = mapping->end;
+
+	if(cluster > s->cluster_count) {
+	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
+		    s->fat_type,
+		    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
+								: "2.88 MB"
+				      : "504MB");
+	    return -EINVAL;
+	}
+
+	/* fix fat for entry */
+	if (fix_fat) {
+	    int j;
+	    for(j = mapping->begin; j < mapping->end - 1; j++)
+		fat_set(s, j, j+1);
+	    fat_set(s, mapping->end - 1, s->max_fat_value);
+	}
+    }
+
+    mapping = array_get(&(s->mapping), 0);
+    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
+    s->last_cluster_of_root_directory = mapping->end;
+
+    /* the FAT signature */
+    fat_set(s,0,s->max_fat_value);
+    fat_set(s,1,s->max_fat_value);
+
+    s->current_mapping = NULL;
+
+    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
+    bootsector->jump[0]=0xeb;
+    bootsector->jump[1]=0x3e;
+    bootsector->jump[2]=0x90;
+    memcpy(bootsector->name,"QEMU    ",8);
+    bootsector->sector_size=cpu_to_le16(0x200);
+    bootsector->sectors_per_cluster=s->sectors_per_cluster;
+    bootsector->reserved_sectors=cpu_to_le16(1);
+    bootsector->number_of_fats=0x2; /* number of FATs */
+    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
+    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
+    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
+    s->fat.pointer[0] = bootsector->media_type;
+    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
+    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
+    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
+    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
+    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
+
+    /* LATER TODO: if FAT32, this is wrong */
+    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
+    bootsector->u.fat16.current_head=0;
+    bootsector->u.fat16.signature=0x29;
+    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
+
+    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
+    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
+    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
+
+    return 0;
+}
+
+#ifdef DEBUG
+static BDRVVVFATState *vvv = NULL;
+#endif
+
+static int enable_write_target(BDRVVVFATState *s);
+static int is_consistent(BDRVVVFATState *s);
+
+static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
+{
+    BDRVVVFATState *s = bs->opaque;
+    int floppy = 0;
+    int i;
+
+#ifdef DEBUG
+    vvv = s;
+#endif
+
+DLOG(if (stderr == NULL) {
+    stderr = fopen("vvfat.log", "a");
+    setbuf(stderr, NULL);
+})
+
+    s->bs = bs;
+
+    s->fat_type=16;
+    /* LATER TODO: if FAT32, adjust */
+    s->sectors_per_cluster=0x10;
+    /* 504MB disk*/
+    bs->cyls=1024; bs->heads=16; bs->secs=63;
+
+    s->current_cluster=0xffffffff;
+
+    s->first_sectors_number=0x40;
+    /* read only is the default for safety */
+    bs->read_only = 1;
+    s->qcow = s->write_target = NULL;
+    s->qcow_filename = NULL;
+    s->fat2 = NULL;
+    s->downcase_short_names = 1;
+
+    if (!strstart(dirname, "fat:", NULL))
+	return -1;
+
+    if (strstr(dirname, ":floppy:")) {
+	floppy = 1;
+	s->fat_type = 12;
+	s->first_sectors_number = 1;
+	s->sectors_per_cluster=2;
+	bs->cyls = 80; bs->heads = 2; bs->secs = 36;
+    }
+
+    s->sector_count=bs->cyls*bs->heads*bs->secs;
+
+    if (strstr(dirname, ":32:")) {
+	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
+	s->fat_type = 32;
+    } else if (strstr(dirname, ":16:")) {
+	s->fat_type = 16;
+    } else if (strstr(dirname, ":12:")) {
+	s->fat_type = 12;
+	s->sector_count=2880;
+    }
+
+    if (strstr(dirname, ":rw:")) {
+	if (enable_write_target(s))
+	    return -1;
+	bs->read_only = 0;
+    }
+
+    i = strrchr(dirname, ':') - dirname;
+    assert(i >= 3);
+    if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
+	/* workaround for DOS drive names */
+	dirname += i-1;
+    else
+	dirname += i+1;
+
+    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
+
+    if(init_directories(s, dirname))
+	return -1;
+
+    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
+
+    if(s->first_sectors_number==0x40)
+	init_mbr(s);
+
+    /* for some reason or other, MS-DOS does not like to know about CHS... */
+    if (floppy)
+	bs->heads = bs->cyls = bs->secs = 0;
+
+    //    assert(is_consistent(s));
+    return 0;
+}
+
+static inline void vvfat_close_current_file(BDRVVVFATState *s)
+{
+    if(s->current_mapping) {
+	s->current_mapping = NULL;
+	if (s->current_fd) {
+		close(s->current_fd);
+		s->current_fd = 0;
+	}
+    }
+    s->current_cluster = -1;
+}
+
+/* mappings between index1 and index2-1 are supposed to be ordered
+ * return value is the index of the last mapping for which end>cluster_num
+ */
+static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
+{
+    while(1) {
+        int index3;
+	mapping_t* mapping;
+	index3=(index1+index2)/2;
+	mapping=array_get(&(s->mapping),index3);
+	assert(mapping->begin < mapping->end);
+	if(mapping->begin>=cluster_num) {
+	    assert(index2!=index3 || index2==0);
+	    if(index2==index3)
+		return index1;
+	    index2=index3;
+	} else {
+	    if(index1==index3)
+		return mapping->end<=cluster_num ? index2 : index1;
+	    index1=index3;
+	}
+	assert(index1<=index2);
+	DLOG(mapping=array_get(&(s->mapping),index1);
+	assert(mapping->begin<=cluster_num);
+	assert(index2 >= s->mapping.next ||
+		((mapping = array_get(&(s->mapping),index2)) &&
+		mapping->end>cluster_num)));
+    }
+}
+
+static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
+{
+    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
+    mapping_t* mapping;
+    if(index>=s->mapping.next)
+        return NULL;
+    mapping=array_get(&(s->mapping),index);
+    if(mapping->begin>cluster_num)
+        return NULL;
+    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
+    return mapping;
+}
+
+/*
+ * This function simply compares path == mapping->path. Since the mappings
+ * are sorted by cluster, this is expensive: O(n).
+ */
+static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
+	const char* path)
+{
+    int i;
+
+    for (i = 0; i < s->mapping.next; i++) {
+	mapping_t* mapping = array_get(&(s->mapping), i);
+	if (mapping->first_mapping_index < 0 &&
+		!strcmp(path, mapping->path))
+	    return mapping;
+    }
+
+    return NULL;
+}
+
+static int open_file(BDRVVVFATState* s,mapping_t* mapping)
+{
+    if(!mapping)
+	return -1;
+    if(!s->current_mapping ||
+	    strcmp(s->current_mapping->path,mapping->path)) {
+	/* open file */
+	int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
+	if(fd<0)
+	    return -1;
+	vvfat_close_current_file(s);
+	s->current_fd = fd;
+	s->current_mapping = mapping;
+    }
+    return 0;
+}
+
+static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
+{
+    if(s->current_cluster != cluster_num) {
+	int result=0;
+	off_t offset;
+	assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
+	if(!s->current_mapping
+		|| s->current_mapping->begin>cluster_num
+		|| s->current_mapping->end<=cluster_num) {
+	    /* binary search of mappings for file */
+	    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
+
+	    assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
+
+	    if (mapping && mapping->mode & MODE_DIRECTORY) {
+		vvfat_close_current_file(s);
+		s->current_mapping = mapping;
+read_cluster_directory:
+		offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
+		s->cluster = (unsigned char*)s->directory.pointer+offset
+			+ 0x20*s->current_mapping->info.dir.first_dir_index;
+		assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
+		assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
+		s->current_cluster = cluster_num;
+		return 0;
+	    }
+
+	    if(open_file(s,mapping))
+		return -2;
+	} else if (s->current_mapping->mode & MODE_DIRECTORY)
+	    goto read_cluster_directory;
+
+	assert(s->current_fd);
+
+	offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
+	if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
+	    return -3;
+	s->cluster=s->cluster_buffer;
+	result=read(s->current_fd,s->cluster,s->cluster_size);
+	if(result<0) {
+	    s->current_cluster = -1;
+	    return -1;
+	}
+	s->current_cluster = cluster_num;
+    }
+    return 0;
+}
+
+#ifdef DEBUG
+static void hexdump(const void* address, uint32_t len)
+{
+    const unsigned char* p = address;
+    int i, j;
+
+    for (i = 0; i < len; i += 16) {
+	for (j = 0; j < 16 && i + j < len; j++)
+	    fprintf(stderr, "%02x ", p[i + j]);
+	for (; j < 16; j++)
+	    fprintf(stderr, "   ");
+	fprintf(stderr, " ");
+	for (j = 0; j < 16 && i + j < len; j++)
+	    fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
+	fprintf(stderr, "\n");
+    }
+}
+
+static void print_direntry(const direntry_t* direntry)
+{
+    int j = 0;
+    char buffer[1024];
+
+    fprintf(stderr, "direntry %p: ", direntry);
+    if(!direntry)
+	return;
+    if(is_long_name(direntry)) {
+	unsigned char* c=(unsigned char*)direntry;
+	int i;
+	for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
+#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
+	    ADD_CHAR(c[i]);
+	for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
+	    ADD_CHAR(c[i]);
+	for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
+	    ADD_CHAR(c[i]);
+	buffer[j] = 0;
+	fprintf(stderr, "%s\n", buffer);
+    } else {
+	int i;
+	for(i=0;i<11;i++)
+	    ADD_CHAR(direntry->name[i]);
+	buffer[j] = 0;
+	fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
+		buffer,
+		direntry->attributes,
+		begin_of_direntry(direntry),le32_to_cpu(direntry->size));
+    }
+}
+
+static void print_mapping(const mapping_t* mapping)
+{
+    fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
+        "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
+        mapping, mapping->begin, mapping->end, mapping->dir_index,
+        mapping->first_mapping_index, mapping->path, mapping->mode);
+
+    if (mapping->mode & MODE_DIRECTORY)
+	fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
+    else
+	fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
+}
+#endif
+
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVVVFATState *s = bs->opaque;
+    int i;
+
+    for(i=0;i<nb_sectors;i++,sector_num++) {
+	if (sector_num >= s->sector_count)
+	   return -1;
+	if (s->qcow) {
+	    int n;
+	    if (s->qcow->drv->bdrv_is_allocated(s->qcow,
+			sector_num, nb_sectors-i, &n)) {
+DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
+		if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
+		    return -1;
+		i += n - 1;
+		sector_num += n - 1;
+		continue;
+	    }
+DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
+	}
+	if(sector_num<s->faked_sectors) {
+	    if(sector_num<s->first_sectors_number)
+		memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
+	    else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
+		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
+	    else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
+		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
+	} else {
+	    uint32_t sector=sector_num-s->faked_sectors,
+	    sector_offset_in_cluster=(sector%s->sectors_per_cluster),
+	    cluster_num=sector/s->sectors_per_cluster;
+	    if(read_cluster(s, cluster_num) != 0) {
+		/* LATER TODO: strict: return -1; */
+		memset(buf+i*0x200,0,0x200);
+		continue;
+	    }
+	    memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
+	}
+    }
+    return 0;
+}
+
+/* LATER TODO: statify all functions */
+
+/*
+ * Idea of the write support (use snapshot):
+ *
+ * 1. check if all data is consistent, recording renames, modifications,
+ *    new files and directories (in s->commits).
+ *
+ * 2. if the data is not consistent, stop committing
+ *
+ * 3. handle renames, and create new files and directories (do not yet
+ *    write their contents)
+ *
+ * 4. walk the directories, fixing the mapping and direntries, and marking
+ *    the handled mappings as not deleted
+ *
+ * 5. commit the contents of the files
+ *
+ * 6. handle deleted files and directories
+ *
+ */
+
+typedef struct commit_t {
+    char* path;
+    union {
+	struct { uint32_t cluster; } rename;
+	struct { int dir_index; uint32_t modified_offset; } writeout;
+	struct { uint32_t first_cluster; } new_file;
+	struct { uint32_t cluster; } mkdir;
+    } param;
+    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
+    enum {
+	ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
+    } action;
+} commit_t;
+
+static void clear_commits(BDRVVVFATState* s)
+{
+    int i;
+DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
+    for (i = 0; i < s->commits.next; i++) {
+	commit_t* commit = array_get(&(s->commits), i);
+	assert(commit->path || commit->action == ACTION_WRITEOUT);
+	if (commit->action != ACTION_WRITEOUT) {
+	    assert(commit->path);
+	    free(commit->path);
+	} else
+	    assert(commit->path == NULL);
+    }
+    s->commits.next = 0;
+}
+
+static void schedule_rename(BDRVVVFATState* s,
+	uint32_t cluster, char* new_path)
+{
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = new_path;
+    commit->param.rename.cluster = cluster;
+    commit->action = ACTION_RENAME;
+}
+
+static void schedule_writeout(BDRVVVFATState* s,
+	int dir_index, uint32_t modified_offset)
+{
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = NULL;
+    commit->param.writeout.dir_index = dir_index;
+    commit->param.writeout.modified_offset = modified_offset;
+    commit->action = ACTION_WRITEOUT;
+}
+
+static void schedule_new_file(BDRVVVFATState* s,
+	char* path, uint32_t first_cluster)
+{
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = path;
+    commit->param.new_file.first_cluster = first_cluster;
+    commit->action = ACTION_NEW_FILE;
+}
+
+static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
+{
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = path;
+    commit->param.mkdir.cluster = cluster;
+    commit->action = ACTION_MKDIR;
+}
+
+typedef struct {
+    /*
+     * Since the sequence number is at most 0x3f, and the filename
+     * length is at most 13 times the sequence number, the maximal
+     * filename length is 0x3f * 13 bytes.
+     */
+    unsigned char name[0x3f * 13 + 1];
+    int checksum, len;
+    int sequence_number;
+} long_file_name;
+
+static void lfn_init(long_file_name* lfn)
+{
+   lfn->sequence_number = lfn->len = 0;
+   lfn->checksum = 0x100;
+}
+
+/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
+static int parse_long_name(long_file_name* lfn,
+	const direntry_t* direntry)
+{
+    int i, j, offset;
+    const unsigned char* pointer = (const unsigned char*)direntry;
+
+    if (!is_long_name(direntry))
+	return 1;
+
+    if (pointer[0] & 0x40) {
+	lfn->sequence_number = pointer[0] & 0x3f;
+	lfn->checksum = pointer[13];
+	lfn->name[0] = 0;
+	lfn->name[lfn->sequence_number * 13] = 0;
+    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
+	return -1;
+    else if (pointer[13] != lfn->checksum)
+	return -2;
+    else if (pointer[12] || pointer[26] || pointer[27])
+	return -3;
+
+    offset = 13 * (lfn->sequence_number - 1);
+    for (i = 0, j = 1; i < 13; i++, j+=2) {
+	if (j == 11)
+	    j = 14;
+	else if (j == 26)
+	    j = 28;
+
+	if (pointer[j+1] == 0)
+	    lfn->name[offset + i] = pointer[j];
+	else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
+	    return -4;
+	else
+	    lfn->name[offset + i] = 0;
+    }
+
+    if (pointer[0] & 0x40)
+	lfn->len = offset + strlen((char*)lfn->name + offset);
+
+    return 0;
+}
+
+/* returns 0 if successful, >0 if no short_name, and <0 on error */
+static int parse_short_name(BDRVVVFATState* s,
+	long_file_name* lfn, direntry_t* direntry)
+{
+    int i, j;
+
+    if (!is_short_name(direntry))
+	return 1;
+
+    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
+    for (i = 0; i <= j; i++) {
+	if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
+	    return -1;
+	else if (s->downcase_short_names)
+	    lfn->name[i] = qemu_tolower(direntry->name[i]);
+	else
+	    lfn->name[i] = direntry->name[i];
+    }
+
+    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
+    if (j >= 0) {
+	lfn->name[i++] = '.';
+	lfn->name[i + j + 1] = '\0';
+	for (;j >= 0; j--) {
+	    if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
+		return -2;
+	    else if (s->downcase_short_names)
+		lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
+	    else
+		lfn->name[i + j] = direntry->extension[j];
+	}
+    } else
+	lfn->name[i + j + 1] = '\0';
+
+    lfn->len = strlen((char*)lfn->name);
+
+    return 0;
+}
+
+static inline uint32_t modified_fat_get(BDRVVVFATState* s,
+	unsigned int cluster)
+{
+    if (cluster < s->last_cluster_of_root_directory) {
+	if (cluster + 1 == s->last_cluster_of_root_directory)
+	    return s->max_fat_value;
+	else
+	    return cluster + 1;
+    }
+
+    if (s->fat_type==32) {
+        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
+        return le32_to_cpu(*entry);
+    } else if (s->fat_type==16) {
+        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
+        return le16_to_cpu(*entry);
+    } else {
+        const uint8_t* x=s->fat2+cluster*3/2;
+        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+    }
+}
+
+static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
+{
+    int was_modified = 0;
+    int i, dummy;
+
+    if (s->qcow == NULL)
+	return 0;
+
+    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
+	was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+		cluster2sector(s, cluster_num) + i, 1, &dummy);
+
+    return was_modified;
+}
+
+static const char* get_basename(const char* path)
+{
+    char* basename = strrchr(path, '/');
+    if (basename == NULL)
+	return path;
+    else
+	return basename + 1; /* strip '/' */
+}
+
+/*
+ * The array s->used_clusters holds the states of the clusters. If it is
+ * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
+ * was modified, bit 3 is set.
+ * If any cluster is allocated, but not part of a file or directory, this
+ * driver refuses to commit.
+ */
+typedef enum {
+     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
+} used_t;
+
+/*
+ * get_cluster_count_for_direntry() not only determines how many clusters
+ * are occupied by direntry, but also if it was renamed or modified.
+ *
+ * A file is thought to be renamed *only* if there already was a file with
+ * exactly the same first cluster, but a different name.
+ *
+ * Further, the files/directories handled by this function are
+ * assumed to be *not* deleted (and *only* those).
+ */
+static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
+	direntry_t* direntry, const char* path)
+{
+    /*
+     * This is a little bit tricky:
+     * IF the guest OS just inserts a cluster into the file chain,
+     * and leaves the rest alone, (i.e. the original file had clusters
+     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
+     *
+     * - do_commit will write the cluster into the file at the given
+     *   offset, but
+     *
+     * - the cluster which is overwritten should be moved to a later
+     *   position in the file.
+     *
+     * I am not aware that any OS does something as braindead, but this
+     * situation could happen anyway when not committing for a long time.
+     * Just to be sure that this does not bite us, detect it, and copy the
+     * contents of the clusters to-be-overwritten into the qcow.
+     */
+    int copy_it = 0;
+    int was_modified = 0;
+    int32_t ret = 0;
+
+    uint32_t cluster_num = begin_of_direntry(direntry);
+    uint32_t offset = 0;
+    int first_mapping_index = -1;
+    mapping_t* mapping = NULL;
+    const char* basename2 = NULL;
+
+    vvfat_close_current_file(s);
+
+    /* the root directory */
+    if (cluster_num == 0)
+	return 0;
+
+    /* write support */
+    if (s->qcow) {
+	basename2 = get_basename(path);
+
+	mapping = find_mapping_for_cluster(s, cluster_num);
+
+	if (mapping) {
+	    const char* basename;
+
+	    assert(mapping->mode & MODE_DELETED);
+	    mapping->mode &= ~MODE_DELETED;
+
+	    basename = get_basename(mapping->path);
+
+	    assert(mapping->mode & MODE_NORMAL);
+
+	    /* rename */
+	    if (strcmp(basename, basename2))
+		schedule_rename(s, cluster_num, qemu_strdup(path));
+	} else if (is_file(direntry))
+	    /* new file */
+	    schedule_new_file(s, qemu_strdup(path), cluster_num);
+	else {
+            abort();
+	    return 0;
+	}
+    }
+
+    while(1) {
+	if (s->qcow) {
+	    if (!copy_it && cluster_was_modified(s, cluster_num)) {
+		if (mapping == NULL ||
+			mapping->begin > cluster_num ||
+			mapping->end <= cluster_num)
+		mapping = find_mapping_for_cluster(s, cluster_num);
+
+
+		if (mapping &&
+			(mapping->mode & MODE_DIRECTORY) == 0) {
+
+		    /* was modified in qcow */
+		    if (offset != mapping->info.file.offset + s->cluster_size
+			    * (cluster_num - mapping->begin)) {
+			/* offset of this cluster in file chain has changed */
+                        abort();
+			copy_it = 1;
+		    } else if (offset == 0) {
+			const char* basename = get_basename(mapping->path);
+
+			if (strcmp(basename, basename2))
+			    copy_it = 1;
+			first_mapping_index = array_index(&(s->mapping), mapping);
+		    }
+
+		    if (mapping->first_mapping_index != first_mapping_index
+			    && mapping->info.file.offset > 0) {
+                        abort();
+			copy_it = 1;
+		    }
+
+		    /* need to write out? */
+		    if (!was_modified && is_file(direntry)) {
+			was_modified = 1;
+			schedule_writeout(s, mapping->dir_index, offset);
+		    }
+		}
+	    }
+
+	    if (copy_it) {
+		int i, dummy;
+		/*
+		 * This is horribly inefficient, but that is okay, since
+		 * it is rarely executed, if at all.
+		 */
+		int64_t offset = cluster2sector(s, cluster_num);
+
+		vvfat_close_current_file(s);
+		for (i = 0; i < s->sectors_per_cluster; i++)
+		    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
+				offset + i, 1, &dummy)) {
+			if (vvfat_read(s->bs,
+				    offset, s->cluster_buffer, 1))
+			    return -1;
+			if (s->qcow->drv->bdrv_write(s->qcow,
+				    offset, s->cluster_buffer, 1))
+			    return -2;
+		    }
+	    }
+	}
+
+	ret++;
+	if (s->used_clusters[cluster_num] & USED_ANY)
+	    return 0;
+	s->used_clusters[cluster_num] = USED_FILE;
+
+	cluster_num = modified_fat_get(s, cluster_num);
+
+	if (fat_eof(s, cluster_num))
+	    return ret;
+	else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
+	    return -1;
+
+	offset += s->cluster_size;
+    }
+}
+
+/*
+ * This function looks at the modified data (qcow).
+ * It returns 0 upon inconsistency or error, and the number of clusters
+ * used by the directory, its subdirectories and their files.
+ */
+static int check_directory_consistency(BDRVVVFATState *s,
+	int cluster_num, const char* path)
+{
+    int ret = 0;
+    unsigned char* cluster = qemu_malloc(s->cluster_size);
+    direntry_t* direntries = (direntry_t*)cluster;
+    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
+
+    long_file_name lfn;
+    int path_len = strlen(path);
+    char path2[PATH_MAX];
+
+    assert(path_len < PATH_MAX); /* len was tested before! */
+    pstrcpy(path2, sizeof(path2), path);
+    path2[path_len] = '/';
+    path2[path_len + 1] = '\0';
+
+    if (mapping) {
+	const char* basename = get_basename(mapping->path);
+	const char* basename2 = get_basename(path);
+
+	assert(mapping->mode & MODE_DIRECTORY);
+
+	assert(mapping->mode & MODE_DELETED);
+	mapping->mode &= ~MODE_DELETED;
+
+	if (strcmp(basename, basename2))
+	    schedule_rename(s, cluster_num, qemu_strdup(path));
+    } else
+	/* new directory */
+	schedule_mkdir(s, cluster_num, qemu_strdup(path));
+
+    lfn_init(&lfn);
+    do {
+	int i;
+	int subret = 0;
+
+	ret++;
+
+	if (s->used_clusters[cluster_num] & USED_ANY) {
+	    fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
+	    return 0;
+	}
+	s->used_clusters[cluster_num] = USED_DIRECTORY;
+
+DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
+	subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
+		s->sectors_per_cluster);
+	if (subret) {
+	    fprintf(stderr, "Error fetching direntries\n");
+	fail:
+	    free(cluster);
+	    return 0;
+	}
+
+	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
+	    int cluster_count = 0;
+
+DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
+	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
+		    is_free(direntries + i))
+		continue;
+
+	    subret = parse_long_name(&lfn, direntries + i);
+	    if (subret < 0) {
+		fprintf(stderr, "Error in long name\n");
+		goto fail;
+	    }
+	    if (subret == 0 || is_free(direntries + i))
+		continue;
+
+	    if (fat_chksum(direntries+i) != lfn.checksum) {
+		subret = parse_short_name(s, &lfn, direntries + i);
+		if (subret < 0) {
+		    fprintf(stderr, "Error in short name (%d)\n", subret);
+		    goto fail;
+		}
+		if (subret > 0 || !strcmp((char*)lfn.name, ".")
+			|| !strcmp((char*)lfn.name, ".."))
+		    continue;
+	    }
+	    lfn.checksum = 0x100; /* cannot use long name twice */
+
+	    if (path_len + 1 + lfn.len >= PATH_MAX) {
+		fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
+		goto fail;
+	    }
+            pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
+                    (char*)lfn.name);
+
+	    if (is_directory(direntries + i)) {
+		if (begin_of_direntry(direntries + i) == 0) {
+		    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
+		    goto fail;
+		}
+		cluster_count = check_directory_consistency(s,
+			begin_of_direntry(direntries + i), path2);
+		if (cluster_count == 0) {
+		    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
+		    goto fail;
+		}
+	    } else if (is_file(direntries + i)) {
+		/* check file size with FAT */
+		cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
+		if (cluster_count !=
+			(le32_to_cpu(direntries[i].size) + s->cluster_size
+			 - 1) / s->cluster_size) {
+		    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
+		    goto fail;
+		}
+	    } else
+                abort(); /* cluster_count = 0; */
+
+	    ret += cluster_count;
+	}
+
+	cluster_num = modified_fat_get(s, cluster_num);
+    } while(!fat_eof(s, cluster_num));
+
+    free(cluster);
+    return ret;
+}
+
+/* returns 1 on success */
+static int is_consistent(BDRVVVFATState* s)
+{
+    int i, check;
+    int used_clusters_count = 0;
+
+DLOG(checkpoint());
+    /*
+     * - get modified FAT
+     * - compare the two FATs (TODO)
+     * - get buffer for marking used clusters
+     * - recurse direntries from root (using bs->bdrv_read to make
+     *    sure to get the new data)
+     *   - check that the FAT agrees with the size
+     *   - count the number of clusters occupied by this directory and
+     *     its files
+     * - check that the cumulative used cluster count agrees with the
+     *   FAT
+     * - if all is fine, return number of used clusters
+     */
+    if (s->fat2 == NULL) {
+	int size = 0x200 * s->sectors_per_fat;
+	s->fat2 = qemu_malloc(size);
+	memcpy(s->fat2, s->fat.pointer, size);
+    }
+    check = vvfat_read(s->bs,
+	    s->first_sectors_number, s->fat2, s->sectors_per_fat);
+    if (check) {
+	fprintf(stderr, "Could not copy fat\n");
+	return 0;
+    }
+    assert (s->used_clusters);
+    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
+	s->used_clusters[i] &= ~USED_ANY;
+
+    clear_commits(s);
+
+    /* mark every mapped file/directory as deleted.
+     * (check_directory_consistency() will unmark those still present). */
+    if (s->qcow)
+	for (i = 0; i < s->mapping.next; i++) {
+	    mapping_t* mapping = array_get(&(s->mapping), i);
+	    if (mapping->first_mapping_index < 0)
+		mapping->mode |= MODE_DELETED;
+	}
+
+    used_clusters_count = check_directory_consistency(s, 0, s->path);
+    if (used_clusters_count <= 0) {
+	DLOG(fprintf(stderr, "problem in directory\n"));
+	return 0;
+    }
+
+    check = s->last_cluster_of_root_directory;
+    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
+	if (modified_fat_get(s, i)) {
+	    if(!s->used_clusters[i]) {
+		DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
+		return 0;
+	    }
+	    check++;
+	}
+
+	if (s->used_clusters[i] == USED_ALLOCATED) {
+	    /* allocated, but not used... */
+	    DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
+	    return 0;
+	}
+    }
+
+    if (check != used_clusters_count)
+	return 0;
+
+    return used_clusters_count;
+}
+
+static inline void adjust_mapping_indices(BDRVVVFATState* s,
+	int offset, int adjust)
+{
+    int i;
+
+    for (i = 0; i < s->mapping.next; i++) {
+	mapping_t* mapping = array_get(&(s->mapping), i);
+
+#define ADJUST_MAPPING_INDEX(name) \
+	if (mapping->name >= offset) \
+	    mapping->name += adjust
+
+	ADJUST_MAPPING_INDEX(first_mapping_index);
+	if (mapping->mode & MODE_DIRECTORY)
+	    ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
+    }
+}
+
+/* insert or update mapping */
+static mapping_t* insert_mapping(BDRVVVFATState* s,
+	uint32_t begin, uint32_t end)
+{
+    /*
+     * - find mapping where mapping->begin >= begin,
+     * - if mapping->begin > begin: insert
+     *   - adjust all references to mappings!
+     * - else: adjust
+     * - replace name
+     */
+    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
+    mapping_t* mapping = NULL;
+    mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
+	    && mapping->begin < begin) {
+	mapping->end = begin;
+	index++;
+	mapping = array_get(&(s->mapping), index);
+    }
+    if (index >= s->mapping.next || mapping->begin > begin) {
+	mapping = array_insert(&(s->mapping), index, 1);
+	mapping->path = NULL;
+	adjust_mapping_indices(s, index, +1);
+    }
+
+    mapping->begin = begin;
+    mapping->end = end;
+
+DLOG(mapping_t* next_mapping;
+assert(index + 1 >= s->mapping.next ||
+((next_mapping = array_get(&(s->mapping), index + 1)) &&
+ next_mapping->begin >= end)));
+
+    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+	s->current_mapping = array_get(&(s->mapping),
+		s->current_mapping - first_mapping);
+
+    return mapping;
+}
+
+static int remove_mapping(BDRVVVFATState* s, int mapping_index)
+{
+    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+    mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+    /* free mapping */
+    if (mapping->first_mapping_index < 0)
+	free(mapping->path);
+
+    /* remove from s->mapping */
+    array_remove(&(s->mapping), mapping_index);
+
+    /* adjust all references to mappings */
+    adjust_mapping_indices(s, mapping_index, -1);
+
+    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+	s->current_mapping = array_get(&(s->mapping),
+		s->current_mapping - first_mapping);
+
+    return 0;
+}
+
+static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
+{
+    int i;
+    for (i = 0; i < s->mapping.next; i++) {
+	mapping_t* mapping = array_get(&(s->mapping), i);
+	if (mapping->dir_index >= offset)
+	    mapping->dir_index += adjust;
+	if ((mapping->mode & MODE_DIRECTORY) &&
+		mapping->info.dir.first_dir_index >= offset)
+	    mapping->info.dir.first_dir_index += adjust;
+    }
+}
+
+static direntry_t* insert_direntries(BDRVVVFATState* s,
+	int dir_index, int count)
+{
+    /*
+     * make room in s->directory,
+     * adjust_dirindices
+     */
+    direntry_t* result = array_insert(&(s->directory), dir_index, count);
+    if (result == NULL)
+	return NULL;
+    adjust_dirindices(s, dir_index, count);
+    return result;
+}
+
+static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
+{
+    int ret = array_remove_slice(&(s->directory), dir_index, count);
+    if (ret)
+	return ret;
+    adjust_dirindices(s, dir_index, -count);
+    return 0;
+}
+
+/*
+ * Adapt the mappings of the cluster chain starting at first cluster
+ * (i.e. if a file starts at first_cluster, the chain is followed according
+ * to the modified fat, and the corresponding entries in s->mapping are
+ * adjusted)
+ */
+static int commit_mappings(BDRVVVFATState* s,
+	uint32_t first_cluster, int dir_index)
+{
+    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t cluster = first_cluster;
+
+    vvfat_close_current_file(s);
+
+    assert(mapping);
+    assert(mapping->begin == first_cluster);
+    mapping->first_mapping_index = -1;
+    mapping->dir_index = dir_index;
+    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
+	MODE_DIRECTORY : MODE_NORMAL;
+
+    while (!fat_eof(s, cluster)) {
+	uint32_t c, c1;
+
+	for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
+		c = c1, c1 = modified_fat_get(s, c1));
+
+	c++;
+	if (c > mapping->end) {
+	    int index = array_index(&(s->mapping), mapping);
+	    int i, max_i = s->mapping.next - index;
+	    for (i = 1; i < max_i && mapping[i].begin < c; i++);
+	    while (--i > 0)
+		remove_mapping(s, index + 1);
+	}
+	assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
+		|| mapping[1].begin >= c);
+	mapping->end = c;
+
+	if (!fat_eof(s, c1)) {
+	    int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
+	    mapping_t* next_mapping = i >= s->mapping.next ? NULL :
+		array_get(&(s->mapping), i);
+
+	    if (next_mapping == NULL || next_mapping->begin > c1) {
+		int i1 = array_index(&(s->mapping), mapping);
+
+		next_mapping = insert_mapping(s, c1, c1+1);
+
+		if (c1 < c)
+		    i1++;
+		mapping = array_get(&(s->mapping), i1);
+	    }
+
+	    next_mapping->dir_index = mapping->dir_index;
+	    next_mapping->first_mapping_index =
+		mapping->first_mapping_index < 0 ?
+		array_index(&(s->mapping), mapping) :
+		mapping->first_mapping_index;
+	    next_mapping->path = mapping->path;
+	    next_mapping->mode = mapping->mode;
+	    next_mapping->read_only = mapping->read_only;
+	    if (mapping->mode & MODE_DIRECTORY) {
+		next_mapping->info.dir.parent_mapping_index =
+			mapping->info.dir.parent_mapping_index;
+		next_mapping->info.dir.first_dir_index =
+			mapping->info.dir.first_dir_index +
+			0x10 * s->sectors_per_cluster *
+			(mapping->end - mapping->begin);
+	    } else
+		next_mapping->info.file.offset = mapping->info.file.offset +
+			mapping->end - mapping->begin;
+
+	    mapping = next_mapping;
+	}
+
+	cluster = c1;
+    }
+
+    return 0;
+}
+
+static int commit_direntries(BDRVVVFATState* s,
+	int dir_index, int parent_mapping_index)
+{
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
+    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+
+    int factor = 0x10 * s->sectors_per_cluster;
+    int old_cluster_count, new_cluster_count;
+    int current_dir_index = mapping->info.dir.first_dir_index;
+    int first_dir_index = current_dir_index;
+    int ret, i;
+    uint32_t c;
+
+DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
+
+    assert(direntry);
+    assert(mapping);
+    assert(mapping->begin == first_cluster);
+    assert(mapping->info.dir.first_dir_index < s->directory.next);
+    assert(mapping->mode & MODE_DIRECTORY);
+    assert(dir_index == 0 || is_directory(direntry));
+
+    mapping->info.dir.parent_mapping_index = parent_mapping_index;
+
+    if (first_cluster == 0) {
+	old_cluster_count = new_cluster_count =
+	    s->last_cluster_of_root_directory;
+    } else {
+	for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+		c = fat_get(s, c))
+	    old_cluster_count++;
+
+	for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+		c = modified_fat_get(s, c))
+	    new_cluster_count++;
+    }
+
+    if (new_cluster_count > old_cluster_count) {
+	if (insert_direntries(s,
+		current_dir_index + factor * old_cluster_count,
+		factor * (new_cluster_count - old_cluster_count)) == NULL)
+	    return -1;
+    } else if (new_cluster_count < old_cluster_count)
+	remove_direntries(s,
+		current_dir_index + factor * new_cluster_count,
+		factor * (old_cluster_count - new_cluster_count));
+
+    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
+	void* direntry = array_get(&(s->directory), current_dir_index);
+	int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
+		s->sectors_per_cluster);
+	if (ret)
+	    return ret;
+	assert(!strncmp(s->directory.pointer, "QEMU", 4));
+	current_dir_index += factor;
+    }
+
+    ret = commit_mappings(s, first_cluster, dir_index);
+    if (ret)
+	return ret;
+
+    /* recurse */
+    for (i = 0; i < factor * new_cluster_count; i++) {
+	direntry = array_get(&(s->directory), first_dir_index + i);
+	if (is_directory(direntry) && !is_dot(direntry)) {
+	    mapping = find_mapping_for_cluster(s, first_cluster);
+	    assert(mapping->mode & MODE_DIRECTORY);
+	    ret = commit_direntries(s, first_dir_index + i,
+		array_index(&(s->mapping), mapping));
+	    if (ret)
+		return ret;
+	}
+    }
+
+    return 0;
+}
+
+/* commit one file (adjust contents, adjust mapping),
+   return first_mapping_index */
+static int commit_one_file(BDRVVVFATState* s,
+	int dir_index, uint32_t offset)
+{
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t c = begin_of_direntry(direntry);
+    uint32_t first_cluster = c;
+    mapping_t* mapping = find_mapping_for_cluster(s, c);
+    uint32_t size = filesize_of_direntry(direntry);
+    char* cluster = qemu_malloc(s->cluster_size);
+    uint32_t i;
+    int fd = 0;
+
+    assert(offset < size);
+    assert((offset % s->cluster_size) == 0);
+
+    for (i = s->cluster_size; i < offset; i += s->cluster_size)
+	c = modified_fat_get(s, c);
+
+    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
+    if (fd < 0) {
+	fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
+		strerror(errno), errno);
+	return fd;
+    }
+    if (offset > 0)
+	if (lseek(fd, offset, SEEK_SET) != offset)
+	    return -3;
+
+    while (offset < size) {
+	uint32_t c1;
+	int rest_size = (size - offset > s->cluster_size ?
+		s->cluster_size : size - offset);
+	int ret;
+
+	c1 = modified_fat_get(s, c);
+
+	assert((size - offset == 0 && fat_eof(s, c)) ||
+		(size > offset && c >=2 && !fat_eof(s, c)));
+
+	ret = vvfat_read(s->bs, cluster2sector(s, c),
+	    (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
+
+	if (ret < 0)
+	    return ret;
+
+	if (write(fd, cluster, rest_size) < 0)
+	    return -2;
+
+	offset += rest_size;
+	c = c1;
+    }
+
+    if (ftruncate(fd, size)) {
+        perror("ftruncate()");
+        close(fd);
+        return -4;
+    }
+    close(fd);
+
+    return commit_mappings(s, first_cluster, dir_index);
+}
+
+#ifdef DEBUG
+/* test, if all mappings point to valid direntries */
+static void check1(BDRVVVFATState* s)
+{
+    int i;
+    for (i = 0; i < s->mapping.next; i++) {
+	mapping_t* mapping = array_get(&(s->mapping), i);
+	if (mapping->mode & MODE_DELETED) {
+	    fprintf(stderr, "deleted\n");
+	    continue;
+	}
+	assert(mapping->dir_index < s->directory.next);
+	direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
+	assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
+	if (mapping->mode & MODE_DIRECTORY) {
+	    assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
+	    assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
+	}
+    }
+}
+
+/* test, if all direntries have mappings */
+static void check2(BDRVVVFATState* s)
+{
+    int i;
+    int first_mapping = -1;
+
+    for (i = 0; i < s->directory.next; i++) {
+	direntry_t* direntry = array_get(&(s->directory), i);
+
+	if (is_short_name(direntry) && begin_of_direntry(direntry)) {
+	    mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
+	    assert(mapping);
+	    assert(mapping->dir_index == i || is_dot(direntry));
+	    assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
+	}
+
+	if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
+	    /* cluster start */
+	    int j, count = 0;
+
+	    for (j = 0; j < s->mapping.next; j++) {
+		mapping_t* mapping = array_get(&(s->mapping), j);
+		if (mapping->mode & MODE_DELETED)
+		    continue;
+		if (mapping->mode & MODE_DIRECTORY) {
+		    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
+			assert(++count == 1);
+			if (mapping->first_mapping_index == -1)
+			    first_mapping = array_index(&(s->mapping), mapping);
+			else
+			    assert(first_mapping == mapping->first_mapping_index);
+			if (mapping->info.dir.parent_mapping_index < 0)
+			    assert(j == 0);
+			else {
+			    mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
+			    assert(parent->mode & MODE_DIRECTORY);
+			    assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
+			}
+		    }
+		}
+	    }
+	    if (count == 0)
+		first_mapping = -1;
+	}
+    }
+}
+#endif
+
+static int handle_renames_and_mkdirs(BDRVVVFATState* s)
+{
+    int i;
+
+#ifdef DEBUG
+    fprintf(stderr, "handle_renames\n");
+    for (i = 0; i < s->commits.next; i++) {
+	commit_t* commit = array_get(&(s->commits), i);
+	fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
+    }
+#endif
+
+    for (i = 0; i < s->commits.next;) {
+	commit_t* commit = array_get(&(s->commits), i);
+	if (commit->action == ACTION_RENAME) {
+	    mapping_t* mapping = find_mapping_for_cluster(s,
+		    commit->param.rename.cluster);
+	    char* old_path = mapping->path;
+
+	    assert(commit->path);
+	    mapping->path = commit->path;
+	    if (rename(old_path, mapping->path))
+		return -2;
+
+	    if (mapping->mode & MODE_DIRECTORY) {
+		int l1 = strlen(mapping->path);
+		int l2 = strlen(old_path);
+		int diff = l1 - l2;
+		direntry_t* direntry = array_get(&(s->directory),
+			mapping->info.dir.first_dir_index);
+		uint32_t c = mapping->begin;
+		int i = 0;
+
+		/* recurse */
+		while (!fat_eof(s, c)) {
+		    do {
+			direntry_t* d = direntry + i;
+
+			if (is_file(d) || (is_directory(d) && !is_dot(d))) {
+			    mapping_t* m = find_mapping_for_cluster(s,
+				    begin_of_direntry(d));
+			    int l = strlen(m->path);
+			    char* new_path = qemu_malloc(l + diff + 1);
+
+			    assert(!strncmp(m->path, mapping->path, l2));
+
+                            pstrcpy(new_path, l + diff + 1, mapping->path);
+                            pstrcpy(new_path + l1, l + diff + 1 - l1,
+                                    m->path + l2);
+
+			    schedule_rename(s, m->begin, new_path);
+			}
+			i++;
+		    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
+		    c = fat_get(s, c);
+		}
+	    }
+
+	    free(old_path);
+	    array_remove(&(s->commits), i);
+	    continue;
+	} else if (commit->action == ACTION_MKDIR) {
+	    mapping_t* mapping;
+	    int j, parent_path_len;
+
+#ifdef __MINGW32__
+            if (mkdir(commit->path))
+                return -5;
+#else
+            if (mkdir(commit->path, 0755))
+                return -5;
+#endif
+
+	    mapping = insert_mapping(s, commit->param.mkdir.cluster,
+		    commit->param.mkdir.cluster + 1);
+	    if (mapping == NULL)
+		return -6;
+
+	    mapping->mode = MODE_DIRECTORY;
+	    mapping->read_only = 0;
+	    mapping->path = commit->path;
+	    j = s->directory.next;
+	    assert(j);
+	    insert_direntries(s, s->directory.next,
+		    0x10 * s->sectors_per_cluster);
+	    mapping->info.dir.first_dir_index = j;
+
+	    parent_path_len = strlen(commit->path)
+		- strlen(get_basename(commit->path)) - 1;
+	    for (j = 0; j < s->mapping.next; j++) {
+		mapping_t* m = array_get(&(s->mapping), j);
+		if (m->first_mapping_index < 0 && m != mapping &&
+			!strncmp(m->path, mapping->path, parent_path_len) &&
+			strlen(m->path) == parent_path_len)
+		    break;
+	    }
+	    assert(j < s->mapping.next);
+	    mapping->info.dir.parent_mapping_index = j;
+
+	    array_remove(&(s->commits), i);
+	    continue;
+	}
+
+	i++;
+    }
+    return 0;
+}
+
+/*
+ * TODO: make sure that the short name is not matching *another* file
+ */
+static int handle_commits(BDRVVVFATState* s)
+{
+    int i, fail = 0;
+
+    vvfat_close_current_file(s);
+
+    for (i = 0; !fail && i < s->commits.next; i++) {
+	commit_t* commit = array_get(&(s->commits), i);
+	switch(commit->action) {
+	case ACTION_RENAME: case ACTION_MKDIR:
+            abort();
+	    fail = -2;
+	    break;
+	case ACTION_WRITEOUT: {
+#ifndef NDEBUG
+            /* these variables are only used by assert() below */
+	    direntry_t* entry = array_get(&(s->directory),
+		    commit->param.writeout.dir_index);
+	    uint32_t begin = begin_of_direntry(entry);
+	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
+#endif
+
+	    assert(mapping);
+	    assert(mapping->begin == begin);
+	    assert(commit->path == NULL);
+
+	    if (commit_one_file(s, commit->param.writeout.dir_index,
+			commit->param.writeout.modified_offset))
+		fail = -3;
+
+	    break;
+	}
+	case ACTION_NEW_FILE: {
+	    int begin = commit->param.new_file.first_cluster;
+	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
+	    direntry_t* entry;
+	    int i;
+
+	    /* find direntry */
+	    for (i = 0; i < s->directory.next; i++) {
+		entry = array_get(&(s->directory), i);
+		if (is_file(entry) && begin_of_direntry(entry) == begin)
+		    break;
+	    }
+
+	    if (i >= s->directory.next) {
+		fail = -6;
+		continue;
+	    }
+
+	    /* make sure there exists an initial mapping */
+	    if (mapping && mapping->begin != begin) {
+		mapping->end = begin;
+		mapping = NULL;
+	    }
+	    if (mapping == NULL) {
+		mapping = insert_mapping(s, begin, begin+1);
+	    }
+	    /* most members will be fixed in commit_mappings() */
+	    assert(commit->path);
+	    mapping->path = commit->path;
+	    mapping->read_only = 0;
+	    mapping->mode = MODE_NORMAL;
+	    mapping->info.file.offset = 0;
+
+	    if (commit_one_file(s, i, 0))
+		fail = -7;
+
+	    break;
+	}
+	default:
+            abort();
+	}
+    }
+    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
+	return -1;
+    return fail;
+}
+
+static int handle_deletes(BDRVVVFATState* s)
+{
+    int i, deferred = 1, deleted = 1;
+
+    /* delete files corresponding to mappings marked as deleted */
+    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
+    while (deferred && deleted) {
+	deferred = 0;
+	deleted = 0;
+
+	for (i = 1; i < s->mapping.next; i++) {
+	    mapping_t* mapping = array_get(&(s->mapping), i);
+	    if (mapping->mode & MODE_DELETED) {
+		direntry_t* entry = array_get(&(s->directory),
+			mapping->dir_index);
+
+		if (is_free(entry)) {
+		    /* remove file/directory */
+		    if (mapping->mode & MODE_DIRECTORY) {
+			int j, next_dir_index = s->directory.next,
+			first_dir_index = mapping->info.dir.first_dir_index;
+
+			if (rmdir(mapping->path) < 0) {
+			    if (errno == ENOTEMPTY) {
+				deferred++;
+				continue;
+			    } else
+				return -5;
+			}
+
+			for (j = 1; j < s->mapping.next; j++) {
+			    mapping_t* m = array_get(&(s->mapping), j);
+			    if (m->mode & MODE_DIRECTORY &&
+				    m->info.dir.first_dir_index >
+				    first_dir_index &&
+				    m->info.dir.first_dir_index <
+				    next_dir_index)
+				next_dir_index =
+				    m->info.dir.first_dir_index;
+			}
+			remove_direntries(s, first_dir_index,
+				next_dir_index - first_dir_index);
+
+			deleted++;
+		    }
+		} else {
+		    if (unlink(mapping->path))
+			return -4;
+		    deleted++;
+		}
+		DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
+		remove_mapping(s, i);
+	    }
+	}
+    }
+
+    return 0;
+}
+
+/*
+ * synchronize mapping with new state:
+ *
+ * - copy FAT (with bdrv_read)
+ * - mark all filenames corresponding to mappings as deleted
+ * - recurse direntries from root (using bs->bdrv_read)
+ * - delete files corresponding to mappings marked as deleted
+ */
+static int do_commit(BDRVVVFATState* s)
+{
+    int ret = 0;
+
+    /* the real meat are the commits. Nothing to do? Move along! */
+    if (s->commits.next == 0)
+	return 0;
+
+    vvfat_close_current_file(s);
+
+    ret = handle_renames_and_mkdirs(s);
+    if (ret) {
+	fprintf(stderr, "Error handling renames (%d)\n", ret);
+        abort();
+	return ret;
+    }
+
+    /* copy FAT (with bdrv_read) */
+    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
+
+    /* recurse direntries from root (using bs->bdrv_read) */
+    ret = commit_direntries(s, 0, -1);
+    if (ret) {
+	fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
+        abort();
+	return ret;
+    }
+
+    ret = handle_commits(s);
+    if (ret) {
+	fprintf(stderr, "Error handling commits (%d)\n", ret);
+        abort();
+	return ret;
+    }
+
+    ret = handle_deletes(s);
+    if (ret) {
+	fprintf(stderr, "Error deleting\n");
+        abort();
+	return ret;
+    }
+
+    s->qcow->drv->bdrv_make_empty(s->qcow);
+
+    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
+
+DLOG(checkpoint());
+    return 0;
+}
+
+static int try_commit(BDRVVVFATState* s)
+{
+    vvfat_close_current_file(s);
+DLOG(checkpoint());
+    if(!is_consistent(s))
+	return -1;
+    return do_commit(s);
+}
+
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
+                    const uint8_t *buf, int nb_sectors)
+{
+    BDRVVVFATState *s = bs->opaque;
+    int i, ret;
+
+DLOG(checkpoint());
+
+    /* Check if we're operating in read-only mode */
+    if (s->qcow == NULL) {
+        return -EACCES;
+    }
+
+    vvfat_close_current_file(s);
+
+    /*
+     * Some sanity checks:
+     * - do not allow writing to the boot sector
+     * - do not allow to write non-ASCII filenames
+     */
+
+    if (sector_num < s->first_sectors_number)
+	return -1;
+
+    for (i = sector2cluster(s, sector_num);
+	    i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
+	mapping_t* mapping = find_mapping_for_cluster(s, i);
+	if (mapping) {
+	    if (mapping->read_only) {
+		fprintf(stderr, "Tried to write to write-protected file %s\n",
+			mapping->path);
+		return -1;
+	    }
+
+	    if (mapping->mode & MODE_DIRECTORY) {
+		int begin = cluster2sector(s, i);
+		int end = begin + s->sectors_per_cluster, k;
+		int dir_index;
+		const direntry_t* direntries;
+		long_file_name lfn;
+
+		lfn_init(&lfn);
+
+		if (begin < sector_num)
+		    begin = sector_num;
+		if (end > sector_num + nb_sectors)
+		    end = sector_num + nb_sectors;
+		dir_index  = mapping->dir_index +
+		    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
+		direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
+
+		for (k = 0; k < (end - begin) * 0x10; k++) {
+		    /* do not allow non-ASCII filenames */
+		    if (parse_long_name(&lfn, direntries + k) < 0) {
+			fprintf(stderr, "Warning: non-ASCII filename\n");
+			return -1;
+		    }
+		    /* no access to the direntry of a read-only file */
+		    else if (is_short_name(direntries+k) &&
+			    (direntries[k].attributes & 1)) {
+			if (memcmp(direntries + k,
+				    array_get(&(s->directory), dir_index + k),
+				    sizeof(direntry_t))) {
+			    fprintf(stderr, "Warning: tried to write to write-protected file\n");
+			    return -1;
+			}
+		    }
+		}
+	    }
+	    i = mapping->end;
+	} else
+	    i++;
+    }
+
+    /*
+     * Use qcow backend. Commit later.
+     */
+DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
+    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+    if (ret < 0) {
+	fprintf(stderr, "Error writing to qcow backend\n");
+	return ret;
+    }
+
+    for (i = sector2cluster(s, sector_num);
+	    i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
+	if (i >= 0)
+	    s->used_clusters[i] |= USED_ALLOCATED;
+
+DLOG(checkpoint());
+    /* TODO: add timeout */
+    try_commit(s);
+
+DLOG(checkpoint());
+    return 0;
+}
+
+static int vvfat_is_allocated(BlockDriverState *bs,
+	int64_t sector_num, int nb_sectors, int* n)
+{
+    BDRVVVFATState* s = bs->opaque;
+    *n = s->sector_count - sector_num;
+    if (*n > nb_sectors)
+	*n = nb_sectors;
+    else if (*n < 0)
+	return 0;
+    return 1;
+}
+
+static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
+	const uint8_t* buffer, int nb_sectors) {
+    BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
+    return try_commit(s);
+}
+
+static void write_target_close(BlockDriverState *bs) {
+    BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
+    bdrv_delete(s->qcow);
+    free(s->qcow_filename);
+}
+
+static BlockDriver vvfat_write_target = {
+    .format_name        = "vvfat_write_target",
+    .bdrv_write         = write_target_commit,
+    .bdrv_close         = write_target_close,
+};
+
+static int enable_write_target(BDRVVVFATState *s)
+{
+    BlockDriver *bdrv_qcow;
+    QEMUOptionParameter *options;
+    int ret;
+    int size = sector2cluster(s, s->sector_count);
+    s->used_clusters = calloc(size, 1);
+
+    array_init(&(s->commits), sizeof(commit_t));
+
+    s->qcow_filename = qemu_malloc(1024);
+    get_tmp_filename(s->qcow_filename, 1024);
+
+    bdrv_qcow = bdrv_find_format("qcow");
+    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
+    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
+    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
+
+    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
+	return -1;
+
+    s->qcow = bdrv_new("");
+    if (s->qcow == NULL) {
+        return -1;
+    }
+
+    ret = bdrv_open(s->qcow, s->qcow_filename,
+            BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
+    if (ret < 0) {
+	return ret;
+    }
+
+#ifndef _WIN32
+    unlink(s->qcow_filename);
+#endif
+
+    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
+    s->bs->backing_hd->drv = &vvfat_write_target;
+    s->bs->backing_hd->opaque = qemu_malloc(sizeof(void*));
+    *(void**)s->bs->backing_hd->opaque = s;
+
+    return 0;
+}
+
+static void vvfat_close(BlockDriverState *bs)
+{
+    BDRVVVFATState *s = bs->opaque;
+
+    vvfat_close_current_file(s);
+    array_free(&(s->fat));
+    array_free(&(s->directory));
+    array_free(&(s->mapping));
+    if(s->cluster_buffer)
+        free(s->cluster_buffer);
+}
+
+static BlockDriver bdrv_vvfat = {
+    .format_name	= "vvfat",
+    .instance_size	= sizeof(BDRVVVFATState),
+    .bdrv_file_open	= vvfat_open,
+    .bdrv_read		= vvfat_read,
+    .bdrv_write		= vvfat_write,
+    .bdrv_close		= vvfat_close,
+    .bdrv_is_allocated	= vvfat_is_allocated,
+    .protocol_name	= "fat",
+};
+
+static void bdrv_vvfat_init(void)
+{
+    bdrv_register(&bdrv_vvfat);
+}
+
+block_init(bdrv_vvfat_init);
+
+#ifdef DEBUG
+static void checkpoint(void) {
+    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
+    check1(vvv);
+    check2(vvv);
+    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
+#if 0
+    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
+	fprintf(stderr, "Nonono!\n");
+    mapping_t* mapping;
+    direntry_t* direntry;
+    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
+    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
+    if (vvv->mapping.next<47)
+	return;
+    assert((mapping = array_get(&(vvv->mapping), 47)));
+    assert(mapping->dir_index < vvv->directory.next);
+    direntry = array_get(&(vvv->directory), mapping->dir_index);
+    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
+#endif
+    return;
+    /* avoid compiler warnings: */
+    hexdump(NULL, 100);
+    remove_mapping(vvv, 0);
+    print_mapping(NULL);
+    print_direntry(NULL);
+}
+#endif
diff --git a/qemu-0.15.x/block_int.h b/qemu-0.15.x/block_int.h
new file mode 100644
index 0000000..efb6803
--- /dev/null
+++ b/qemu-0.15.x/block_int.h
@@ -0,0 +1,266 @@
+/*
+ * 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
+
+#include "block.h"
+#include "qemu-option.h"
+#include "qemu-queue.h"
+
+#define BLOCK_FLAG_ENCRYPT	1
+#define BLOCK_FLAG_COMPAT6	4
+
+#define BLOCK_OPT_SIZE          "size"
+#define BLOCK_OPT_ENCRYPT       "encryption"
+#define BLOCK_OPT_COMPAT6       "compat6"
+#define BLOCK_OPT_BACKING_FILE  "backing_file"
+#define BLOCK_OPT_BACKING_FMT   "backing_fmt"
+#define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
+#define BLOCK_OPT_TABLE_SIZE    "table_size"
+#define BLOCK_OPT_PREALLOC      "preallocation"
+#define BLOCK_OPT_SUBFMT        "subformat"
+
+typedef struct AIOPool {
+    void (*cancel)(BlockDriverAIOCB *acb);
+    int aiocb_size;
+    BlockDriverAIOCB *free_aiocb;
+} AIOPool;
+
+struct BlockDriver {
+    const char *format_name;
+    int instance_size;
+    int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
+    int (*bdrv_probe_device)(const char *filename);
+    int (*bdrv_open)(BlockDriverState *bs, int flags);
+    int (*bdrv_file_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, QEMUOptionParameter *options);
+    int (*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_readv)(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors);
+
+    int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
+        int num_reqs);
+    int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
+        BlockRequest *b);
+
+
+    const char *protocol_name;
+    int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
+    int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    int64_t (*bdrv_get_allocated_file_size)(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_snapshot_load_tmp)(BlockDriverState *bs,
+                                  const char *snapshot_name);
+    int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+
+    int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf,
+                             int64_t pos, int size);
+    int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf,
+                             int64_t pos, int size);
+
+    int (*bdrv_change_backing_file)(BlockDriverState *bs,
+        const char *backing_file, const char *backing_fmt);
+
+    /* 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);
+
+    /* to control generic scsi devices */
+    int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
+    BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+    /* List of options for creating images, terminated by name == NULL */
+    QEMUOptionParameter *create_options;
+
+
+    /*
+     * Returns 0 for completed check, -errno for internal errors.
+     * The check results are stored in result.
+     */
+    int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result);
+
+    void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
+
+    /*
+     * Returns 1 if newly created images are guaranteed to contain only
+     * zeros, 0 otherwise.
+     */
+    int (*bdrv_has_zero_init)(BlockDriverState *bs);
+
+    QLIST_ENTRY(BlockDriver) list;
+};
+
+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 keep_read_only; /* if true, the media was requested to stay read only */
+    int open_flags; /* flags used to open the file, re-used for re-open */
+    int removable; /* if true, the media can be removed */
+    int locked;    /* if true, the media cannot temporarily be ejected */
+    int tray_open; /* if true, the virtual tray is open */
+    int encrypted; /* if true, the media is encrypted */
+    int valid_key; /* if true, a valid encryption key has been set */
+    int sg;        /* if true, the device is a /dev/sg* */
+    /* event callback when inserting/removing */
+    void (*change_cb)(void *opaque, int reason);
+    void *change_opaque;
+
+    BlockDriver *drv; /* NULL means no media */
+    void *opaque;
+
+    DeviceState *peer;
+
+    char filename[1024];
+    char backing_file[1024]; /* if non zero, the image is a diff of
+                                this file image */
+    char backing_format[16]; /* if non-zero and backing_file exists */
+    int is_temporary;
+    int media_changed;
+
+    BlockDriverState *backing_hd;
+    BlockDriverState *file;
+
+    /* async read/write emulation */
+
+    void *sync_aiocb;
+
+    /* I/O stats (display with "info blockstats"). */
+    uint64_t rd_bytes;
+    uint64_t wr_bytes;
+    uint64_t rd_ops;
+    uint64_t wr_ops;
+    uint64_t wr_highest_sector;
+
+    /* Whether the disk can expand beyond total_sectors */
+    int growable;
+
+    /* the memory alignment required for the buffers handled by this driver */
+    int buffer_alignment;
+
+    /* do we need to tell the quest if we have a volatile write cache? */
+    int enable_write_cache;
+
+    /* NOTE: the following infos are only hints for real hardware
+       drivers. They are not used by the block driver */
+    int cyls, heads, secs, translation;
+    BlockErrorAction on_read_error, on_write_error;
+    char device_name[32];
+    unsigned long *dirty_bitmap;
+    int64_t dirty_count;
+    int in_use; /* users other than guest access, eg. block migration */
+    QTAILQ_ENTRY(BlockDriverState) list;
+    void *private;
+};
+
+#define CHANGE_MEDIA    0x01
+#define CHANGE_SIZE     0x02
+
+struct BlockDriverAIOCB {
+    AIOPool *pool;
+    BlockDriverState *bs;
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+    BlockDriverAIOCB *next;
+};
+
+void get_tmp_filename(char *filename, int size);
+
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+                   BlockDriverCompletionFunc *cb, void *opaque);
+void qemu_aio_release(void *p);
+
+void *qemu_blockalign(BlockDriverState *bs, size_t size);
+
+#ifdef _WIN32
+int is_windows_drive(const char *filename);
+#endif
+
+typedef struct BlockConf {
+    BlockDriverState *bs;
+    uint16_t physical_block_size;
+    uint16_t logical_block_size;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+    int32_t bootindex;
+    uint32_t discard_granularity;
+} BlockConf;
+
+static inline unsigned int get_physical_block_exp(BlockConf *conf)
+{
+    unsigned int exp = 0, size;
+
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
+        exp++;
+    }
+
+    return exp;
+}
+
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
+    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
+    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
+                       _conf.logical_block_size, 512),                  \
+    DEFINE_PROP_UINT16("physical_block_size", _state,                   \
+                       _conf.physical_block_size, 512),                 \
+    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
+    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, 0)
+
+#endif /* BLOCK_INT_H */
diff --git a/qemu-0.15.x/blockdev.c b/qemu-0.15.x/blockdev.c
new file mode 100644
index 0000000..0b8d3a4
--- /dev/null
+++ b/qemu-0.15.x/blockdev.c
@@ -0,0 +1,795 @@
+/*
+ * QEMU host block devices
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#include "block.h"
+#include "blockdev.h"
+#include "monitor.h"
+#include "qerror.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "sysemu.h"
+#include "hw/qdev.h"
+#include "block_int.h"
+
+static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
+
+static const char *const if_name[IF_COUNT] = {
+    [IF_NONE] = "none",
+    [IF_IDE] = "ide",
+    [IF_SCSI] = "scsi",
+    [IF_FLOPPY] = "floppy",
+    [IF_PFLASH] = "pflash",
+    [IF_MTD] = "mtd",
+    [IF_SD] = "sd",
+    [IF_VIRTIO] = "virtio",
+    [IF_XEN] = "xen",
+};
+
+static const int if_max_devs[IF_COUNT] = {
+    /*
+     * Do not change these numbers!  They govern how drive option
+     * index maps to unit and bus.  That mapping is ABI.
+     *
+     * All controllers used to imlement if=T drives need to support
+     * if_max_devs[T] units, for any T with if_max_devs[T] != 0.
+     * Otherwise, some index values map to "impossible" bus, unit
+     * values.
+     *
+     * For instance, if you change [IF_SCSI] to 255, -drive
+     * if=scsi,index=12 no longer means bus=1,unit=5, but
+     * bus=0,unit=12.  With an lsi53c895a controller (7 units max),
+     * the drive can't be set up.  Regression.
+     */
+    [IF_IDE] = 2,
+    [IF_SCSI] = 7,
+};
+
+/*
+ * We automatically delete the drive when a device using it gets
+ * unplugged.  Questionable feature, but we can't just drop it.
+ * Device models call blockdev_mark_auto_del() to schedule the
+ * automatic deletion, and generic qdev code calls blockdev_auto_del()
+ * when deletion is actually safe.
+ */
+void blockdev_mark_auto_del(BlockDriverState *bs)
+{
+    DriveInfo *dinfo = drive_get_by_blockdev(bs);
+
+    if (dinfo) {
+        dinfo->auto_del = 1;
+    }
+}
+
+void blockdev_auto_del(BlockDriverState *bs)
+{
+    DriveInfo *dinfo = drive_get_by_blockdev(bs);
+
+    if (dinfo && dinfo->auto_del) {
+        drive_put_ref(dinfo);
+    }
+}
+
+static int drive_index_to_bus_id(BlockInterfaceType type, int index)
+{
+    int max_devs = if_max_devs[type];
+    return max_devs ? index / max_devs : 0;
+}
+
+static int drive_index_to_unit_id(BlockInterfaceType type, int index)
+{
+    int max_devs = if_max_devs[type];
+    return max_devs ? index % max_devs : index;
+}
+
+QemuOpts *drive_def(const char *optstr)
+{
+    return qemu_opts_parse(qemu_find_opts("drive"), optstr, 0);
+}
+
+QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
+                    const char *optstr)
+{
+    QemuOpts *opts;
+    char buf[32];
+
+    opts = drive_def(optstr);
+    if (!opts) {
+        return NULL;
+    }
+    if (type != IF_DEFAULT) {
+        qemu_opt_set(opts, "if", if_name[type]);
+    }
+    if (index >= 0) {
+        snprintf(buf, sizeof(buf), "%d", index);
+        qemu_opt_set(opts, "index", buf);
+    }
+    if (file)
+        qemu_opt_set(opts, "file", file);
+    return opts;
+}
+
+DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
+{
+    DriveInfo *dinfo;
+
+    /* seek interface, bus and unit */
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (dinfo->type == type &&
+	    dinfo->bus == bus &&
+	    dinfo->unit == unit)
+            return dinfo;
+    }
+
+    return NULL;
+}
+
+DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
+{
+    return drive_get(type,
+                     drive_index_to_bus_id(type, index),
+                     drive_index_to_unit_id(type, index));
+}
+
+int drive_get_max_bus(BlockInterfaceType type)
+{
+    int max_bus;
+    DriveInfo *dinfo;
+
+    max_bus = -1;
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if(dinfo->type == type &&
+           dinfo->bus > max_bus)
+            max_bus = dinfo->bus;
+    }
+    return max_bus;
+}
+
+/* Get a block device.  This should only be used for single-drive devices
+   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
+   appropriate bus.  */
+DriveInfo *drive_get_next(BlockInterfaceType type)
+{
+    static int next_block_unit[IF_COUNT];
+
+    return drive_get(type, 0, next_block_unit[type]++);
+}
+
+DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
+{
+    DriveInfo *dinfo;
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (dinfo->bdrv == bs) {
+            return dinfo;
+        }
+    }
+    return NULL;
+}
+
+static void bdrv_format_print(void *opaque, const char *name)
+{
+    error_printf(" %s", name);
+}
+
+static void drive_uninit(DriveInfo *dinfo)
+{
+    qemu_opts_del(dinfo->opts);
+    bdrv_delete(dinfo->bdrv);
+    qemu_free(dinfo->id);
+    QTAILQ_REMOVE(&drives, dinfo, next);
+    qemu_free(dinfo);
+}
+
+void drive_put_ref(DriveInfo *dinfo)
+{
+    assert(dinfo->refcount);
+    if (--dinfo->refcount == 0) {
+        drive_uninit(dinfo);
+    }
+}
+
+void drive_get_ref(DriveInfo *dinfo)
+{
+    dinfo->refcount++;
+}
+
+static int parse_block_error_action(const char *buf, int is_read)
+{
+    if (!strcmp(buf, "ignore")) {
+        return BLOCK_ERR_IGNORE;
+    } else if (!is_read && !strcmp(buf, "enospc")) {
+        return BLOCK_ERR_STOP_ENOSPC;
+    } else if (!strcmp(buf, "stop")) {
+        return BLOCK_ERR_STOP_ANY;
+    } else if (!strcmp(buf, "report")) {
+        return BLOCK_ERR_REPORT;
+    } else {
+        error_report("'%s' invalid %s error action",
+                     buf, is_read ? "read" : "write");
+        return -1;
+    }
+}
+
+DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
+{
+    const char *buf;
+    const char *file = NULL;
+    char devname[128];
+    const char *serial;
+    const char *mediastr = "";
+    BlockInterfaceType type;
+    enum { MEDIA_DISK, MEDIA_CDROM } media;
+    int bus_id, unit_id;
+    int cyls, heads, secs, translation;
+    BlockDriver *drv = NULL;
+    int max_devs;
+    int index;
+    int ro = 0;
+    int bdrv_flags = 0;
+    int on_read_error, on_write_error;
+    const char *devaddr;
+    DriveInfo *dinfo;
+    int snapshot = 0;
+    int ret;
+
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+    media = MEDIA_DISK;
+
+    /* extract parameters */
+    bus_id  = qemu_opt_get_number(opts, "bus", 0);
+    unit_id = qemu_opt_get_number(opts, "unit", -1);
+    index   = qemu_opt_get_number(opts, "index", -1);
+
+    cyls  = qemu_opt_get_number(opts, "cyls", 0);
+    heads = qemu_opt_get_number(opts, "heads", 0);
+    secs  = qemu_opt_get_number(opts, "secs", 0);
+
+    snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
+    ro = qemu_opt_get_bool(opts, "readonly", 0);
+
+    file = qemu_opt_get(opts, "file");
+    serial = qemu_opt_get(opts, "serial");
+
+    if ((buf = qemu_opt_get(opts, "if")) != NULL) {
+        pstrcpy(devname, sizeof(devname), buf);
+        for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++)
+            ;
+        if (type == IF_COUNT) {
+            error_report("unsupported bus type '%s'", buf);
+            return NULL;
+	}
+    } else {
+        type = default_to_scsi ? IF_SCSI : IF_IDE;
+        pstrcpy(devname, sizeof(devname), if_name[type]);
+    }
+
+    max_devs = if_max_devs[type];
+
+    if (cyls || heads || secs) {
+        if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
+            error_report("invalid physical cyls number");
+	    return NULL;
+	}
+        if (heads < 1 || (type == IF_IDE && heads > 16)) {
+            error_report("invalid physical heads number");
+	    return NULL;
+	}
+        if (secs < 1 || (type == IF_IDE && secs > 63)) {
+            error_report("invalid physical secs number");
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
+        if (!cyls) {
+            error_report("'%s' trans must be used with cyls, heads and secs",
+                         buf);
+            return NULL;
+        }
+        if (!strcmp(buf, "none"))
+            translation = BIOS_ATA_TRANSLATION_NONE;
+        else if (!strcmp(buf, "lba"))
+            translation = BIOS_ATA_TRANSLATION_LBA;
+        else if (!strcmp(buf, "auto"))
+            translation = BIOS_ATA_TRANSLATION_AUTO;
+	else {
+            error_report("'%s' invalid translation type", buf);
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "media")) != NULL) {
+        if (!strcmp(buf, "disk")) {
+	    media = MEDIA_DISK;
+	} else if (!strcmp(buf, "cdrom")) {
+            if (cyls || secs || heads) {
+                error_report("CHS can't be set with media=%s", buf);
+	        return NULL;
+            }
+	    media = MEDIA_CDROM;
+	} else {
+	    error_report("'%s' invalid media", buf);
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
+        if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
+            bdrv_flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+        } else if (!strcmp(buf, "writeback")) {
+            bdrv_flags |= BDRV_O_CACHE_WB;
+        } else if (!strcmp(buf, "unsafe")) {
+            bdrv_flags |= BDRV_O_CACHE_WB;
+            bdrv_flags |= BDRV_O_NO_FLUSH;
+        } else if (!strcmp(buf, "writethrough")) {
+            /* this is the default */
+        } else {
+           error_report("invalid cache option");
+           return NULL;
+        }
+    }
+
+#ifdef CONFIG_LINUX_AIO
+    if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
+        if (!strcmp(buf, "native")) {
+            bdrv_flags |= BDRV_O_NATIVE_AIO;
+        } else if (!strcmp(buf, "threads")) {
+            /* this is the default */
+        } else {
+           error_report("invalid aio option");
+           return NULL;
+        }
+    }
+#endif
+
+    if ((buf = qemu_opt_get(opts, "format")) != NULL) {
+       if (strcmp(buf, "?") == 0) {
+           error_printf("Supported formats:");
+           bdrv_iterate_format(bdrv_format_print, NULL);
+           error_printf("\n");
+           return NULL;
+        }
+        drv = bdrv_find_whitelisted_format(buf);
+        if (!drv) {
+            error_report("'%s' invalid format", buf);
+            return NULL;
+        }
+    }
+
+    on_write_error = BLOCK_ERR_STOP_ENOSPC;
+    if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
+        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
+            error_report("werror is not supported by this bus type");
+            return NULL;
+        }
+
+        on_write_error = parse_block_error_action(buf, 0);
+        if (on_write_error < 0) {
+            return NULL;
+        }
+    }
+
+    on_read_error = BLOCK_ERR_REPORT;
+    if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
+        if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
+            error_report("rerror is not supported by this bus type");
+            return NULL;
+        }
+
+        on_read_error = parse_block_error_action(buf, 1);
+        if (on_read_error < 0) {
+            return NULL;
+        }
+    }
+
+    if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
+        if (type != IF_VIRTIO) {
+            error_report("addr is not supported by this bus type");
+            return NULL;
+        }
+    }
+
+    /* compute bus and unit according index */
+
+    if (index != -1) {
+        if (bus_id != 0 || unit_id != -1) {
+            error_report("index cannot be used with bus and unit");
+            return NULL;
+        }
+        bus_id = drive_index_to_bus_id(type, index);
+        unit_id = drive_index_to_unit_id(type, index);
+    }
+
+    /* if user doesn't specify a unit_id,
+     * try to find the first free
+     */
+
+    if (unit_id == -1) {
+       unit_id = 0;
+       while (drive_get(type, bus_id, unit_id) != NULL) {
+           unit_id++;
+           if (max_devs && unit_id >= max_devs) {
+               unit_id -= max_devs;
+               bus_id++;
+           }
+       }
+    }
+
+    /* check unit id */
+
+    if (max_devs && unit_id >= max_devs) {
+        error_report("unit %d too big (max is %d)",
+                     unit_id, max_devs - 1);
+        return NULL;
+    }
+
+    /*
+     * catch multiple definitions
+     */
+
+    if (drive_get(type, bus_id, unit_id) != NULL) {
+        error_report("drive with bus=%d, unit=%d (index=%d) exists",
+                     bus_id, unit_id, index);
+        return NULL;
+    }
+
+    /* init */
+
+    dinfo = qemu_mallocz(sizeof(*dinfo));
+    if ((buf = qemu_opts_id(opts)) != NULL) {
+        dinfo->id = qemu_strdup(buf);
+    } else {
+        /* no id supplied -> create one */
+        dinfo->id = qemu_mallocz(32);
+        if (type == IF_IDE || type == IF_SCSI)
+            mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
+        if (max_devs)
+            snprintf(dinfo->id, 32, "%s%i%s%i",
+                     devname, bus_id, mediastr, unit_id);
+        else
+            snprintf(dinfo->id, 32, "%s%s%i",
+                     devname, mediastr, unit_id);
+    }
+    dinfo->bdrv = bdrv_new(dinfo->id);
+    dinfo->devaddr = devaddr;
+    dinfo->type = type;
+    dinfo->bus = bus_id;
+    dinfo->unit = unit_id;
+    dinfo->opts = opts;
+    dinfo->refcount = 1;
+    if (serial)
+        strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
+    QTAILQ_INSERT_TAIL(&drives, dinfo, next);
+
+    bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
+
+    switch(type) {
+    case IF_IDE:
+    case IF_SCSI:
+    case IF_XEN:
+    case IF_NONE:
+        switch(media) {
+	case MEDIA_DISK:
+            if (cyls != 0) {
+                bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
+                bdrv_set_translation_hint(dinfo->bdrv, translation);
+            }
+	    break;
+	case MEDIA_CDROM:
+            bdrv_set_removable(dinfo->bdrv, 1);
+            dinfo->media_cd = 1;
+	    break;
+	}
+        break;
+    case IF_SD:
+        /* FIXME: This isn't really a floppy, but it's a reasonable
+           approximation.  */
+    case IF_FLOPPY:
+        bdrv_set_removable(dinfo->bdrv, 1);
+        break;
+    case IF_PFLASH:
+    case IF_MTD:
+        break;
+    case IF_VIRTIO:
+        /* add virtio block device */
+        opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+        qemu_opt_set(opts, "driver", "virtio-blk");
+        qemu_opt_set(opts, "drive", dinfo->id);
+        if (devaddr)
+            qemu_opt_set(opts, "addr", devaddr);
+        break;
+    default:
+        abort();
+    }
+    if (!file || !*file) {
+        return dinfo;
+    }
+    if (snapshot) {
+        /* always use cache=unsafe with snapshot */
+        bdrv_flags &= ~BDRV_O_CACHE_MASK;
+        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+    }
+
+    if (media == MEDIA_CDROM) {
+        /* CDROM is fine for any interface, don't check.  */
+        ro = 1;
+    } else if (ro == 1) {
+        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
+            error_report("readonly not supported by this bus type");
+            goto err;
+        }
+    }
+
+    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+
+    ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
+    if (ret < 0) {
+        error_report("could not open disk image %s: %s",
+                     file, strerror(-ret));
+        goto err;
+    }
+
+    if (bdrv_key_required(dinfo->bdrv))
+        autostart = 0;
+    return dinfo;
+
+err:
+    bdrv_delete(dinfo->bdrv);
+    qemu_free(dinfo->id);
+    QTAILQ_REMOVE(&drives, dinfo, next);
+    qemu_free(dinfo);
+    return NULL;
+}
+
+void do_commit(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    BlockDriverState *bs;
+
+    if (!strcmp(device, "all")) {
+        bdrv_commit_all();
+    } else {
+        bs = bdrv_find(device);
+        if (!bs) {
+            qerror_report(QERR_DEVICE_NOT_FOUND, device);
+            return;
+        }
+        bdrv_commit(bs);
+    }
+}
+
+int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *filename = qdict_get_try_str(qdict, "snapshot-file");
+    const char *format = qdict_get_try_str(qdict, "format");
+    BlockDriverState *bs;
+    BlockDriver *drv, *old_drv, *proto_drv;
+    int ret = 0;
+    int flags;
+    char old_filename[1024];
+
+    if (!filename) {
+        qerror_report(QERR_MISSING_PARAMETER, "snapshot-file");
+        ret = -1;
+        goto out;
+    }
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        ret = -1;
+        goto out;
+    }
+
+    pstrcpy(old_filename, sizeof(old_filename), bs->filename);
+
+    old_drv = bs->drv;
+    flags = bs->open_flags;
+
+    if (!format) {
+        format = "qcow2";
+    }
+
+    drv = bdrv_find_format(format);
+    if (!drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    ret = bdrv_img_create(filename, format, bs->filename,
+                          bs->drv->format_name, NULL, -1, flags);
+    if (ret) {
+        goto out;
+    }
+
+    qemu_aio_flush();
+    bdrv_flush(bs);
+
+    bdrv_close(bs);
+    ret = bdrv_open(bs, filename, flags, drv);
+    /*
+     * If reopening the image file we just created fails, fall back
+     * and try to re-open the original image. If that fails too, we
+     * are in serious trouble.
+     */
+    if (ret != 0) {
+        ret = bdrv_open(bs, old_filename, flags, old_drv);
+        if (ret != 0) {
+            qerror_report(QERR_OPEN_FILE_FAILED, old_filename);
+        } else {
+            qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        }
+    }
+out:
+    if (ret) {
+        ret = -1;
+    }
+
+    return ret;
+}
+
+static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
+{
+    if (!force) {
+        if (!bdrv_is_removable(bs)) {
+            qerror_report(QERR_DEVICE_NOT_REMOVABLE,
+                           bdrv_get_device_name(bs));
+            return -1;
+        }
+        if (bdrv_is_locked(bs)) {
+            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+            return -1;
+        }
+    }
+    bdrv_close(bs);
+    return 0;
+}
+
+int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    BlockDriverState *bs;
+    int force = qdict_get_try_bool(qdict, "force", 0);
+    const char *filename = qdict_get_str(qdict, "device");
+
+    bs = bdrv_find(filename);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, filename);
+        return -1;
+    }
+    return eject_device(mon, bs, force);
+}
+
+int do_block_set_passwd(Monitor *mon, const QDict *qdict,
+                        QObject **ret_data)
+{
+    BlockDriverState *bs;
+    int err;
+
+    bs = bdrv_find(qdict_get_str(qdict, "device"));
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
+        return -1;
+    }
+
+    err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
+    if (err == -EINVAL) {
+        qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+        return -1;
+    } else if (err < 0) {
+        qerror_report(QERR_INVALID_PASSWORD);
+        return -1;
+    }
+
+    return 0;
+}
+
+int do_change_block(Monitor *mon, const char *device,
+                    const char *filename, const char *fmt)
+{
+    BlockDriverState *bs;
+    BlockDriver *drv = NULL;
+    int bdrv_flags;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        return -1;
+    }
+    if (fmt) {
+        drv = bdrv_find_whitelisted_format(fmt);
+        if (!drv) {
+            qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
+            return -1;
+        }
+    }
+    if (eject_device(mon, bs, 0) < 0) {
+        return -1;
+    }
+    bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
+    bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
+    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
+        qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        return -1;
+    }
+    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+}
+
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    BlockDriverState *bs;
+
+    bs = bdrv_find(id);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        return -1;
+    }
+    if (bdrv_in_use(bs)) {
+        qerror_report(QERR_DEVICE_IN_USE, id);
+        return -1;
+    }
+
+    /* quiesce block driver; prevent further io */
+    qemu_aio_flush();
+    bdrv_flush(bs);
+    bdrv_close(bs);
+
+    /* if we have a device associated with this BlockDriverState (bs->peer)
+     * then we need to make the drive anonymous until the device
+     * can be removed.  If this is a drive with no device backing
+     * then we can just get rid of the block driver state right here.
+     */
+    if (bs->peer) {
+        bdrv_make_anon(bs);
+    } else {
+        drive_uninit(drive_get_by_blockdev(bs));
+    }
+
+    return 0;
+}
+
+/*
+ * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
+ * existing QERR_ macro mess is cleaned up.  A good example for better
+ * error reports can be found in the qemu-img resize code.
+ */
+int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    int64_t size = qdict_get_int(qdict, "size");
+    BlockDriverState *bs;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        return -1;
+    }
+
+    if (size < 0) {
+        qerror_report(QERR_UNDEFINED_ERROR);
+        return -1;
+    }
+
+    if (bdrv_truncate(bs, size)) {
+        qerror_report(QERR_UNDEFINED_ERROR);
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/blockdev.h b/qemu-0.15.x/blockdev.h
new file mode 100644
index 0000000..3587786
--- /dev/null
+++ b/qemu-0.15.x/blockdev.h
@@ -0,0 +1,69 @@
+/*
+ * QEMU host block devices
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#ifndef BLOCKDEV_H
+#define BLOCKDEV_H
+
+#include "block.h"
+#include "qemu-queue.h"
+
+void blockdev_mark_auto_del(BlockDriverState *bs);
+void blockdev_auto_del(BlockDriverState *bs);
+
+#define BLOCK_SERIAL_STRLEN 20
+
+typedef enum {
+    IF_DEFAULT = -1,            /* for use with drive_add() only */
+    IF_NONE,
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
+    IF_COUNT
+} BlockInterfaceType;
+
+struct DriveInfo {
+    BlockDriverState *bdrv;
+    char *id;
+    const char *devaddr;
+    BlockInterfaceType type;
+    int bus;
+    int unit;
+    int auto_del;               /* see blockdev_mark_auto_del() */
+    int media_cd;
+    QemuOpts *opts;
+    char serial[BLOCK_SERIAL_STRLEN + 1];
+    QTAILQ_ENTRY(DriveInfo) next;
+    int refcount;
+};
+
+DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
+DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
+int drive_get_max_bus(BlockInterfaceType type);
+DriveInfo *drive_get_next(BlockInterfaceType type);
+void drive_get_ref(DriveInfo *dinfo);
+void drive_put_ref(DriveInfo *dinfo);
+DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
+
+QemuOpts *drive_def(const char *optstr);
+QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
+                    const char *optstr);
+DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
+
+/* device-hotplug */
+
+DriveInfo *add_init_drive(const char *opts);
+
+void do_commit(Monitor *mon, const QDict *qdict);
+int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_change_block(Monitor *mon, const char *device,
+                    const char *filename, const char *fmt);
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+#endif
diff --git a/qemu-0.15.x/bsd-user/bsd-mman.h b/qemu-0.15.x/bsd-user/bsd-mman.h
new file mode 100644
index 0000000..910e8c1
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/bsd-mman.h
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1982, 1986, 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.
+ * 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.
+ *
+ *      @(#)mman.h      8.2 (Berkeley) 1/9/95
+ * $FreeBSD: src/sys/sys/mman.h,v 1.42 2008/03/28 04:29:27 ps Exp $
+ */
+
+#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080  /* previously misimplemented MAP_INHERIT */
+#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100  /* previously unimplemented MAP_NOEXTEND */
+#define TARGET_FREEBSD_MAP_STACK        0x0400  /* region grows down, like a stack */
+#define TARGET_FREEBSD_MAP_NOSYNC       0x0800  /* page to but do not sync underlying file */
+
+#define TARGET_FREEBSD_MAP_FLAGMASK     0x1ff7
+
+/*      $NetBSD: mman.h,v 1.42 2008/11/18 22:13:49 ad Exp $     */
+
+/*-
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *      @(#)mman.h      8.2 (Berkeley) 1/9/95
+ */
+#define TARGET_NETBSD_MAP_INHERIT       0x0080  /* region is retained after exec */
+#define TARGET_NETBSD_MAP_TRYFIXED      0x0400 /* attempt hint address, even within break */
+#define TARGET_NETBSD_MAP_WIRED         0x0800  /* mlock() mapping when it is established */
+
+#define TARGET_NETBSD_MAP_STACK         0x2000  /* allocated from memory, swap space (stack) */
+
+#define TARGET_NETBSD_MAP_FLAGMASK      0x3ff7
+
+/*      $OpenBSD: mman.h,v 1.18 2003/07/21 22:52:19 tedu Exp $  */
+/*      $NetBSD: mman.h,v 1.11 1995/03/26 20:24:23 jtc Exp $    */
+
+/*-
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *      @(#)mman.h      8.1 (Berkeley) 6/2/93
+ */
+
+#define TARGET_OPENBSD_MAP_INHERIT      0x0080  /* region is retained after exec */
+#define TARGET_OPENBSD_MAP_NOEXTEND     0x0100  /* for MAP_FILE, don't change file size */
+#define TARGET_OPENBSD_MAP_TRYFIXED     0x0400  /* attempt hint address, even within heap */
+
+#define TARGET_OPENBSD_MAP_FLAGMASK     0x17f7
+
+// XXX
+#define TARGET_BSD_MAP_FLAGMASK         0x3ff7
diff --git a/qemu-0.15.x/bsd-user/bsdload.c b/qemu-0.15.x/bsd-user/bsdload.c
new file mode 100644
index 0000000..6d9bb6f
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/bsdload.c
@@ -0,0 +1,202 @@
+/* Code for loading BSD executables.  Mostly linux kernel code.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "qemu.h"
+
+#define TARGET_NGROUPS 32
+
+/* ??? This should really be somewhere else.  */
+abi_long memcpy_to_target(abi_ulong dest, const void *src,
+                          unsigned long len)
+{
+    void *host_ptr;
+
+    host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
+    if (!host_ptr)
+        return -TARGET_EFAULT;
+    memcpy(host_ptr, src, len);
+    unlock_user(host_ptr, dest, 1);
+    return 0;
+}
+
+static int in_group_p(gid_t g)
+{
+    /* return TRUE if we're in the specified group, FALSE otherwise */
+    int         ngroup;
+    int         i;
+    gid_t       grouplist[TARGET_NGROUPS];
+
+    ngroup = getgroups(TARGET_NGROUPS, grouplist);
+    for(i = 0; i < ngroup; i++) {
+        if(grouplist[i] == g) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int count(char ** vec)
+{
+    int         i;
+
+    for(i = 0; *vec; i++) {
+        vec++;
+    }
+
+    return(i);
+}
+
+static int prepare_binprm(struct linux_binprm *bprm)
+{
+    struct stat         st;
+    int mode;
+    int retval, id_change;
+
+    if(fstat(bprm->fd, &st) < 0) {
+        return(-errno);
+    }
+
+    mode = st.st_mode;
+    if(!S_ISREG(mode)) {        /* Must be regular file */
+        return(-EACCES);
+    }
+    if(!(mode & 0111)) {        /* Must have at least one execute bit set */
+        return(-EACCES);
+    }
+
+    bprm->e_uid = geteuid();
+    bprm->e_gid = getegid();
+    id_change = 0;
+
+    /* Set-uid? */
+    if(mode & S_ISUID) {
+        bprm->e_uid = st.st_uid;
+        if(bprm->e_uid != geteuid()) {
+            id_change = 1;
+        }
+    }
+
+    /* Set-gid? */
+    /*
+     * If setgid is set but no group execute bit then this
+     * is a candidate for mandatory locking, not a setgid
+     * executable.
+     */
+    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+        bprm->e_gid = st.st_gid;
+        if (!in_group_p(bprm->e_gid)) {
+                id_change = 1;
+        }
+    }
+
+    memset(bprm->buf, 0, sizeof(bprm->buf));
+    retval = lseek(bprm->fd, 0L, SEEK_SET);
+    if(retval >= 0) {
+        retval = read(bprm->fd, bprm->buf, 128);
+    }
+    if(retval < 0) {
+        perror("prepare_binprm");
+        exit(-1);
+        /* return(-errno); */
+    }
+    else {
+        return(retval);
+    }
+}
+
+/* Construct the envp and argv tables on the target stack.  */
+abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
+                              abi_ulong stringp, int push_ptr)
+{
+    int n = sizeof(abi_ulong);
+    abi_ulong envp;
+    abi_ulong argv;
+
+    sp -= (envc + 1) * n;
+    envp = sp;
+    sp -= (argc + 1) * n;
+    argv = sp;
+    if (push_ptr) {
+        /* FIXME - handle put_user() failures */
+        sp -= n;
+        put_user_ual(envp, sp);
+        sp -= n;
+        put_user_ual(argv, sp);
+    }
+    sp -= n;
+    /* FIXME - handle put_user() failures */
+    put_user_ual(argc, sp);
+
+    while (argc-- > 0) {
+        /* FIXME - handle put_user() failures */
+        put_user_ual(stringp, argv);
+        argv += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    /* FIXME - handle put_user() failures */
+    put_user_ual(0, argv);
+    while (envc-- > 0) {
+        /* FIXME - handle put_user() failures */
+        put_user_ual(stringp, envp);
+        envp += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    /* FIXME - handle put_user() failures */
+    put_user_ual(0, envp);
+
+    return sp;
+}
+
+int loader_exec(const char * filename, char ** argv, char ** envp,
+             struct target_pt_regs * regs, struct image_info *infop)
+{
+    struct linux_binprm bprm;
+    int retval;
+    int i;
+
+    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
+            bprm.page[i] = NULL;
+    retval = open(filename, O_RDONLY);
+    if (retval < 0)
+        return retval;
+    bprm.fd = retval;
+    bprm.filename = (char *)filename;
+    bprm.argc = count(argv);
+    bprm.argv = argv;
+    bprm.envc = count(envp);
+    bprm.envp = envp;
+
+    retval = prepare_binprm(&bprm);
+
+    if(retval>=0) {
+        if (bprm.buf[0] == 0x7f
+                && bprm.buf[1] == 'E'
+                && bprm.buf[2] == 'L'
+                && bprm.buf[3] == 'F') {
+            retval = load_elf_binary(&bprm,regs,infop);
+        } else {
+            fprintf(stderr, "Unknown binary format\n");
+            return -1;
+        }
+    }
+
+    if(retval>=0) {
+        /* success.  Initialize important registers */
+        do_init_thread(regs, infop);
+        return retval;
+    }
+
+    /* Something went wrong, return the inode and free the argument pages*/
+    for (i=0 ; i<MAX_ARG_PAGES ; i++) {
+        free(bprm.page[i]);
+    }
+    return(retval);
+}
diff --git a/qemu-0.15.x/bsd-user/elfload.c b/qemu-0.15.x/bsd-user/elfload.c
new file mode 100644
index 0000000..1ef1f97
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/elfload.c
@@ -0,0 +1,1577 @@
+/* This is the Linux kernel elf-loading code, ported into user space */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qemu.h"
+#include "disas.h"
+
+#ifdef _ARCH_PPC64
+#undef ARCH_DLINFO
+#undef ELF_PLATFORM
+#undef ELF_HWCAP
+#undef ELF_CLASS
+#undef ELF_DATA
+#undef ELF_ARCH
+#endif
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+        ADDR_NO_RANDOMIZE =     0x0040000,      /* disable randomization of VA space */
+        FDPIC_FUNCPTRS =        0x0080000,      /* userspace function ptrs point to descriptors
+                                                 * (signal handling)
+                                                 */
+        MMAP_PAGE_ZERO =        0x0100000,
+        ADDR_COMPAT_LAYOUT =    0x0200000,
+        READ_IMPLIES_EXEC =     0x0400000,
+        ADDR_LIMIT_32BIT =      0x0800000,
+        SHORT_INODE =           0x1000000,
+        WHOLE_SECONDS =         0x2000000,
+        STICKY_TIMEOUTS =       0x4000000,
+        ADDR_LIMIT_3GB =        0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+        PER_LINUX =             0x0000,
+        PER_LINUX_32BIT =       0x0000 | ADDR_LIMIT_32BIT,
+        PER_LINUX_FDPIC =       0x0000 | FDPIC_FUNCPTRS,
+        PER_SVR4 =              0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_SVR3 =              0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_SCOSVR3 =           0x0003 | STICKY_TIMEOUTS |
+                                         WHOLE_SECONDS | SHORT_INODE,
+        PER_OSR5 =              0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+        PER_WYSEV386 =          0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_ISCR4 =             0x0005 | STICKY_TIMEOUTS,
+        PER_BSD =               0x0006,
+        PER_SUNOS =             0x0006 | STICKY_TIMEOUTS,
+        PER_XENIX =             0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+        PER_LINUX32 =           0x0008,
+        PER_LINUX32_3GB =       0x0008 | ADDR_LIMIT_3GB,
+        PER_IRIX32 =            0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+        PER_IRIXN32 =           0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+        PER_IRIX64 =            0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+        PER_RISCOS =            0x000c,
+        PER_SOLARIS =           0x000d | STICKY_TIMEOUTS,
+        PER_UW7 =               0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+        PER_OSF4 =              0x000f,                  /* OSF/1 v4 */
+        PER_HPUX =              0x0010,
+        PER_MASK =              0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifdef TARGET_I386
+
+#define ELF_PLATFORM get_elf_platform()
+
+static const char *get_elf_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+  return thread_env->cpuid_features;
+}
+
+#ifdef TARGET_X86_64
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
+}
+
+#else
+
+#define ELF_START_MMAP 0x80000000
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS       ELFCLASS32
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
+    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+       starts %edx contains a pointer to a function which might be
+       registered using `atexit'.  This provides a mean for the
+       dynamic linker to call DT_FINI functions for shared libraries
+       that have been loaded before the code runs.
+
+       A value of 0 tells we have no such handler.  */
+    regs->edx = 0;
+}
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+#endif
+
+#ifdef TARGET_ARM
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_ARM )
+
+#define ELF_CLASS       ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH        EM_ARM
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->ARM_cpsr = 0x10;
+    if (infop->entry & 1)
+      regs->ARM_cpsr |= CPSR_T;
+    regs->ARM_pc = infop->entry & 0xfffffffe;
+    regs->ARM_sp = infop->start_stack;
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
+    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    regs->ARM_r10 = infop->start_data;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+enum
+{
+  ARM_HWCAP_ARM_SWP       = 1 << 0,
+  ARM_HWCAP_ARM_HALF      = 1 << 1,
+  ARM_HWCAP_ARM_THUMB     = 1 << 2,
+  ARM_HWCAP_ARM_26BIT     = 1 << 3,
+  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+  ARM_HWCAP_ARM_FPA       = 1 << 5,
+  ARM_HWCAP_ARM_VFP       = 1 << 6,
+  ARM_HWCAP_ARM_EDSP      = 1 << 7,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
+                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
+                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
+
+#endif
+
+#ifdef TARGET_SPARC
+#ifdef TARGET_SPARC64
+
+#define ELF_START_MMAP 0x80000000
+
+#ifndef TARGET_ABI32
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#else
+#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
+#endif
+
+#define ELF_CLASS   ELFCLASS64
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARCV9
+
+#define STACK_BIAS              2047
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+#ifndef TARGET_ABI32
+    regs->tstate = 0;
+#endif
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+#ifdef TARGET_ABI32
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+#else
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else {
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+        if (bsd_type == target_freebsd) {
+            regs->u_regs[8] = infop->start_stack;
+            regs->u_regs[11] = infop->start_stack;
+        }
+    }
+#endif
+}
+
+#else
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARC
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->psr = 0;
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+}
+
+#endif
+#endif
+
+#ifdef TARGET_PPC
+
+#define ELF_START_MMAP 0x80000000
+
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+
+#define elf_check_arch(x) ( (x) == EM_PPC64 )
+
+#define ELF_CLASS       ELFCLASS64
+
+#else
+
+#define elf_check_arch(x) ( (x) == EM_PPC )
+
+#define ELF_CLASS       ELFCLASS32
+
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH        EM_PPC
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE          19
+#define AT_ICACHEBSIZE          20
+#define AT_UCACHEBSIZE          21
+/* A special ignored type value for PPC, for glibc compatibility.  */
+#define AT_IGNOREPPC            22
+/*
+ * The requirements here are:
+ * - keep the final alignment of sp (sp & 0xf)
+ * - make sure the 32-bit value at the first 16 byte aligned position of
+ *   AUXV is greater than 16 for glibc compatibility.
+ *   AT_IGNOREPPC is used for that.
+ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
+ *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
+ */
+#define DLINFO_ARCH_ITEMS       5
+#define ARCH_DLINFO                                                     \
+do {                                                                    \
+        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
+        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
+        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
+        /*                                                              \
+         * Now handle glibc compatibility.                              \
+         */                                                             \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
+ } while (0)
+
+static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
+{
+    abi_ulong pos = infop->start_stack;
+    abi_ulong tmp;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+    abi_ulong entry, toc;
+#endif
+
+    _regs->gpr[1] = infop->start_stack;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+    entry = ldq_raw(infop->entry) + infop->load_addr;
+    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
+    _regs->gpr[2] = toc;
+    infop->entry = entry;
+#endif
+    _regs->nip = infop->entry;
+    /* Note that isn't exactly what regular kernel does
+     * but this is what the ABI wants and is needed to allow
+     * execution of PPC BSD programs.
+     */
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(_regs->gpr[3], pos);
+    pos += sizeof(abi_ulong);
+    _regs->gpr[4] = pos;
+    for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
+        tmp = ldl(pos);
+    _regs->gpr[5] = pos;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+#endif
+
+#ifdef TARGET_MIPS
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+
+#ifdef TARGET_MIPS64
+#define ELF_CLASS   ELFCLASS64
+#else
+#define ELF_CLASS   ELFCLASS32
+#endif
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->cp0_epc = infop->entry;
+    regs->regs[29] = infop->start_stack;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* TARGET_MIPS */
+
+#ifdef TARGET_SH4
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SH )
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA  ELFDATA2LSB
+#define ELF_ARCH  EM_SH
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+  /* Check other registers XXXXX */
+  regs->pc = infop->entry;
+  regs->regs[15] = infop->start_stack;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif
+
+#ifdef TARGET_CRIS
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_CRIS )
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA  ELFDATA2LSB
+#define ELF_ARCH  EM_CRIS
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+  regs->erp = infop->entry;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        8192
+
+#endif
+
+#ifdef TARGET_M68K
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_68K )
+
+#define ELF_CLASS       ELFCLASS32
+#define ELF_DATA        ELFDATA2MSB
+#define ELF_ARCH        EM_68K
+
+/* ??? Does this need to do anything?
+#define ELF_PLAT_INIT(_r) */
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->usp = infop->start_stack;
+    regs->sr = 0;
+    regs->pc = infop->entry;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       8192
+
+#endif
+
+#ifdef TARGET_ALPHA
+
+#define ELF_START_MMAP (0x30000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_ALPHA
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->pc = infop->entry;
+    regs->ps = 8;
+    regs->usp = infop->start_stack;
+    regs->unique = infop->start_data; /* ? */
+    printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
+           regs->unique, infop->start_data);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        8192
+
+#endif /* TARGET_ALPHA */
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+#include "elf.h"
+
+struct exec
+{
+  unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+  unsigned int a_text;   /* length of text, in bytes */
+  unsigned int a_data;   /* length of data, in bytes */
+  unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+  unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+  unsigned int a_entry;  /* start address */
+  unsigned int a_trsize; /* length of relocation info for text, in bytes */
+  unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* max code+data+bss space allocated to elf interpreter */
+#define INTERP_MAP_SIZE (32 * 1024 * 1024)
+
+/* max code+data+bss+brk space allocated to ET_DYN executables */
+#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+#define DLINFO_ITEMS 12
+
+static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
+{
+        memcpy(to, from, n);
+}
+
+static int load_aout_interp(void * exptr, int interp_fd);
+
+#ifdef BSWAP_NEEDED
+static void bswap_ehdr(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);                    /* Object file type */
+    bswap16s(&ehdr->e_machine);         /* Architecture */
+    bswap32s(&ehdr->e_version);         /* Object file version */
+    bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
+    bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
+    bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
+}
+
+static void bswap_phdr(struct elf_phdr *phdr)
+{
+    bswap32s(&phdr->p_type);                    /* Segment type */
+    bswaptls(&phdr->p_offset);          /* Segment file offset */
+    bswaptls(&phdr->p_vaddr);           /* Segment virtual address */
+    bswaptls(&phdr->p_paddr);           /* Segment physical address */
+    bswaptls(&phdr->p_filesz);          /* Segment size in file */
+    bswaptls(&phdr->p_memsz);           /* Segment size in memory */
+    bswap32s(&phdr->p_flags);           /* Segment flags */
+    bswaptls(&phdr->p_align);           /* Segment alignment */
+}
+
+static void bswap_shdr(struct elf_shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswaptls(&shdr->sh_flags);
+    bswaptls(&shdr->sh_addr);
+    bswaptls(&shdr->sh_offset);
+    bswaptls(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswaptls(&shdr->sh_addralign);
+    bswaptls(&shdr->sh_entsize);
+}
+
+static void bswap_sym(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswaptls(&sym->st_value);
+    bswaptls(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+#endif
+
+/*
+ * 'copy_elf_strings()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ *
+ */
+static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
+                                  abi_ulong p)
+{
+    char *tmp, *tmp1, *pag = NULL;
+    int len, offset = 0;
+
+    if (!p) {
+        return 0;       /* bullet-proofing */
+    }
+    while (argc-- > 0) {
+        tmp = argv[argc];
+        if (!tmp) {
+            fprintf(stderr, "VFS: argc is wrong");
+            exit(-1);
+        }
+        tmp1 = tmp;
+        while (*tmp++);
+        len = tmp - tmp1;
+        if (p < len) {  /* this shouldn't happen - 128kB */
+                return 0;
+        }
+        while (len) {
+            --p; --tmp; --len;
+            if (--offset < 0) {
+                offset = p % TARGET_PAGE_SIZE;
+                pag = (char *)page[p/TARGET_PAGE_SIZE];
+                if (!pag) {
+                    pag = (char *)malloc(TARGET_PAGE_SIZE);
+                    memset(pag, 0, TARGET_PAGE_SIZE);
+                    page[p/TARGET_PAGE_SIZE] = pag;
+                    if (!pag)
+                        return 0;
+                }
+            }
+            if (len == 0 || offset == 0) {
+                *(pag + offset) = *tmp;
+            }
+            else {
+              int bytes_to_copy = (len > offset) ? offset : len;
+              tmp -= bytes_to_copy;
+              p -= bytes_to_copy;
+              offset -= bytes_to_copy;
+              len -= bytes_to_copy;
+              memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+            }
+        }
+    }
+    return p;
+}
+
+static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+                                 struct image_info *info)
+{
+    abi_ulong stack_base, size, error;
+    int i;
+
+    /* Create enough stack to hold everything.  If we don't use
+     * it for args, we'll use it for something else...
+     */
+    size = x86_stack_size;
+    if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
+        size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+    error = target_mmap(0,
+                        size + qemu_host_page_size,
+                        PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANON,
+                        -1, 0);
+    if (error == -1) {
+        perror("stk mmap");
+        exit(-1);
+    }
+    /* we reserve one extra page at the top of the stack as guard */
+    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+
+    stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+    p += stack_base;
+
+    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
+            free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+    return p;
+}
+
+static void set_brk(abi_ulong start, abi_ulong end)
+{
+        /* page-align the start and end addresses... */
+        start = HOST_PAGE_ALIGN(start);
+        end = HOST_PAGE_ALIGN(end);
+        if (end <= start)
+                return;
+        if(target_mmap(start, end - start,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
+            perror("cannot mmap brk");
+            exit(-1);
+        }
+}
+
+
+/* We need to explicitly zero any fractional pages after the data
+   section (i.e. bss).  This would contain the junk from the file that
+   should not be in memory. */
+static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
+{
+        abi_ulong nbyte;
+
+        if (elf_bss >= last_bss)
+                return;
+
+        /* XXX: this is really a hack : if the real host page size is
+           smaller than the target page size, some pages after the end
+           of the file may not be mapped. A better fix would be to
+           patch target_mmap(), but it is more complicated as the file
+           size must be known */
+        if (qemu_real_host_page_size < qemu_host_page_size) {
+            abi_ulong end_addr, end_addr1;
+            end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
+                ~(qemu_real_host_page_size - 1);
+            end_addr = HOST_PAGE_ALIGN(elf_bss);
+            if (end_addr1 < end_addr) {
+                mmap((void *)g2h(end_addr1), end_addr - end_addr1,
+                     PROT_READ|PROT_WRITE|PROT_EXEC,
+                     MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
+            }
+        }
+
+        nbyte = elf_bss & (qemu_host_page_size-1);
+        if (nbyte) {
+            nbyte = qemu_host_page_size - nbyte;
+            do {
+                /* FIXME - what to do if put_user() fails? */
+                put_user_u8(0, elf_bss);
+                elf_bss++;
+            } while (--nbyte);
+        }
+}
+
+
+static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr * exec,
+                                   abi_ulong load_addr,
+                                   abi_ulong load_bias,
+                                   abi_ulong interp_load_addr, int ibcs,
+                                   struct image_info *info)
+{
+        abi_ulong sp;
+        int size;
+        abi_ulong u_platform;
+        const char *k_platform;
+        const int n = sizeof(elf_addr_t);
+
+        sp = p;
+        u_platform = 0;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        }
+        /*
+         * Force 16 byte _final_ alignment here for generality.
+         */
+        sp = sp &~ (abi_ulong)15;
+        size = (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+        size += DLINFO_ARCH_ITEMS * 2;
+#endif
+        size += envc + argc + 2;
+        size += (!ibcs ? 3 : 1);        /* argc itself */
+        size *= n;
+        if (size & 15)
+            sp -= 16 - (size & 15);
+
+        /* This is correct because Linux defines
+         * elf_addr_t as Elf32_Off / Elf64_Off
+         */
+#define NEW_AUX_ENT(id, val) do {               \
+            sp -= n; put_user_ual(val, sp);     \
+            sp -= n; put_user_ual(id, sp);      \
+          } while(0)
+
+        NEW_AUX_ENT (AT_NULL, 0);
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+        NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+        NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+        NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+        NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+        NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+        /*
+         * ARCH_DLINFO must come last so platform specific code can enforce
+         * special alignment requirements on the AUXV if necessary (eg. PPC).
+         */
+        ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+        sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+        return sp;
+}
+
+
+static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
+                                 int interpreter_fd,
+                                 abi_ulong *interp_load_addr)
+{
+        struct elf_phdr *elf_phdata  =  NULL;
+        struct elf_phdr *eppnt;
+        abi_ulong load_addr = 0;
+        int load_addr_set = 0;
+        int retval;
+        abi_ulong last_bss, elf_bss;
+        abi_ulong error;
+        int i;
+
+        elf_bss = 0;
+        last_bss = 0;
+        error = 0;
+
+#ifdef BSWAP_NEEDED
+        bswap_ehdr(interp_elf_ex);
+#endif
+        /* First of all, some simple consistency checks */
+        if ((interp_elf_ex->e_type != ET_EXEC &&
+             interp_elf_ex->e_type != ET_DYN) ||
+           !elf_check_arch(interp_elf_ex->e_machine)) {
+                return ~((abi_ulong)0UL);
+        }
+
+
+        /* Now read in all of the header information */
+
+        if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+            return ~(abi_ulong)0UL;
+
+        elf_phdata =  (struct elf_phdr *)
+                malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+
+        if (!elf_phdata)
+          return ~((abi_ulong)0UL);
+
+        /*
+         * If the size of this structure has changed, then punt, since
+         * we will be doing the wrong thing.
+         */
+        if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+            free(elf_phdata);
+            return ~((abi_ulong)0UL);
+        }
+
+        retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
+        if(retval >= 0) {
+            retval = read(interpreter_fd,
+                           (char *) elf_phdata,
+                           sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+        }
+        if (retval < 0) {
+                perror("load_elf_interp");
+                exit(-1);
+                free (elf_phdata);
+                return retval;
+        }
+#ifdef BSWAP_NEEDED
+        eppnt = elf_phdata;
+        for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+            bswap_phdr(eppnt);
+        }
+#endif
+
+        if (interp_elf_ex->e_type == ET_DYN) {
+            /* in order to avoid hardcoding the interpreter load
+               address in qemu, we allocate a big enough memory zone */
+            error = target_mmap(0, INTERP_MAP_SIZE,
+                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
+                                -1, 0);
+            if (error == -1) {
+                perror("mmap");
+                exit(-1);
+            }
+            load_addr = error;
+            load_addr_set = 1;
+        }
+
+        eppnt = elf_phdata;
+        for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+          if (eppnt->p_type == PT_LOAD) {
+            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+            int elf_prot = 0;
+            abi_ulong vaddr = 0;
+            abi_ulong k;
+
+            if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
+            if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+            if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                elf_type |= MAP_FIXED;
+                vaddr = eppnt->p_vaddr;
+            }
+            error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
+                 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
+                 elf_prot,
+                 elf_type,
+                 interpreter_fd,
+                 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+            if (error == -1) {
+              /* Real error */
+              close(interpreter_fd);
+              free(elf_phdata);
+              return ~((abi_ulong)0UL);
+            }
+
+            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+              load_addr = error;
+              load_addr_set = 1;
+            }
+
+            /*
+             * Find the end of the file  mapping for this phdr, and keep
+             * track of the largest address we see for this.
+             */
+            k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+            if (k > elf_bss) elf_bss = k;
+
+            /*
+             * Do the same thing for the memory mapping - between
+             * elf_bss and last_bss is the bss section.
+             */
+            k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+            if (k > last_bss) last_bss = k;
+          }
+
+        /* Now use mmap to map the library into memory. */
+
+        close(interpreter_fd);
+
+        /*
+         * Now fill out the bss section.  First pad the last page up
+         * to the page boundary, and then perform a mmap to make sure
+         * that there are zeromapped pages up to and including the last
+         * bss page.
+         */
+        padzero(elf_bss, last_bss);
+        elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
+
+        /* Map the last of the bss segment */
+        if (last_bss > elf_bss) {
+            target_mmap(elf_bss, last_bss-elf_bss,
+                        PROT_READ|PROT_WRITE|PROT_EXEC,
+                        MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
+        }
+        free(elf_phdata);
+
+        *interp_load_addr = load_addr;
+        return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+}
+
+static int symfind(const void *s0, const void *s1)
+{
+    struct elf_sym *key = (struct elf_sym *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (key->st_value < sym->st_value) {
+        result = -1;
+    } else if (key->st_value > sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
+{
+#if ELF_CLASS == ELFCLASS32
+    struct elf_sym *syms = s->disas_symtab.elf32;
+#else
+    struct elf_sym *syms = s->disas_symtab.elf64;
+#endif
+
+    // binary search
+    struct elf_sym key;
+    struct elf_sym *sym;
+
+    key.st_value = orig_addr;
+
+    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
+    if (sym != NULL) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+/* FIXME: This should use elf_ops.h  */
+static int symcmp(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+/* Best attempt to load symbols from this ELF object. */
+static void load_symbols(struct elfhdr *hdr, int fd)
+{
+    unsigned int i, nsyms;
+    struct elf_shdr sechdr, symtab, strtab;
+    char *strings;
+    struct syminfo *s;
+    struct elf_sym *syms, *new_syms;
+
+    lseek(fd, hdr->e_shoff, SEEK_SET);
+    for (i = 0; i < hdr->e_shnum; i++) {
+        if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
+            return;
+#ifdef BSWAP_NEEDED
+        bswap_shdr(&sechdr);
+#endif
+        if (sechdr.sh_type == SHT_SYMTAB) {
+            symtab = sechdr;
+            lseek(fd, hdr->e_shoff
+                  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
+            if (read(fd, &strtab, sizeof(strtab))
+                != sizeof(strtab))
+                return;
+#ifdef BSWAP_NEEDED
+            bswap_shdr(&strtab);
+#endif
+            goto found;
+        }
+    }
+    return; /* Shouldn't happen... */
+
+ found:
+    /* Now know where the strtab and symtab are.  Snarf them. */
+    s = malloc(sizeof(*s));
+    syms = malloc(symtab.sh_size);
+    if (!syms) {
+        free(s);
+        return;
+    }
+    s->disas_strtab = strings = malloc(strtab.sh_size);
+    if (!s->disas_strtab) {
+        free(s);
+        free(syms);
+        return;
+    }
+
+    lseek(fd, symtab.sh_offset, SEEK_SET);
+    if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
+        free(s);
+        free(syms);
+        free(strings);
+        return;
+    }
+
+    nsyms = symtab.sh_size / sizeof(struct elf_sym);
+
+    i = 0;
+    while (i < nsyms) {
+#ifdef BSWAP_NEEDED
+        bswap_sym(syms + i);
+#endif
+        // Throw away entries which we do not need.
+        if (syms[i].st_shndx == SHN_UNDEF ||
+                syms[i].st_shndx >= SHN_LORESERVE ||
+                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            nsyms--;
+            if (i < nsyms) {
+                syms[i] = syms[nsyms];
+            }
+            continue;
+        }
+#if defined(TARGET_ARM) || defined (TARGET_MIPS)
+        /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+        syms[i].st_value &= ~(target_ulong)1;
+#endif
+        i++;
+    }
+
+     /* Attempt to free the storage associated with the local symbols
+        that we threw away.  Whether or not this has any effect on the
+        memory allocation depends on the malloc implementation and how
+        many symbols we managed to discard. */
+    new_syms = realloc(syms, nsyms * sizeof(*syms));
+    if (new_syms == NULL) {
+        free(s);
+        free(syms);
+        free(strings);
+        return;
+    }
+    syms = new_syms;
+
+    qsort(syms, nsyms, sizeof(*syms), symcmp);
+
+    lseek(fd, strtab.sh_offset, SEEK_SET);
+    if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
+        free(s);
+        free(syms);
+        free(strings);
+        return;
+    }
+    s->disas_num_syms = nsyms;
+#if ELF_CLASS == ELFCLASS32
+    s->disas_symtab.elf32 = syms;
+    s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
+#else
+    s->disas_symtab.elf64 = syms;
+    s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
+#endif
+    s->next = syminfos;
+    syminfos = s;
+}
+
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info)
+{
+    struct elfhdr elf_ex;
+    struct elfhdr interp_elf_ex;
+    struct exec interp_ex;
+    int interpreter_fd = -1; /* avoid warning */
+    abi_ulong load_addr, load_bias;
+    int load_addr_set = 0;
+    unsigned int interpreter_type = INTERPRETER_NONE;
+    unsigned char ibcs2_interpreter;
+    int i;
+    abi_ulong mapped_addr;
+    struct elf_phdr * elf_ppnt;
+    struct elf_phdr *elf_phdata;
+    abi_ulong elf_bss, k, elf_brk;
+    int retval;
+    char * elf_interpreter;
+    abi_ulong elf_entry, interp_load_addr = 0;
+    int status;
+    abi_ulong start_code, end_code, start_data, end_data;
+    abi_ulong reloc_func_desc = 0;
+    abi_ulong elf_stack;
+    char passed_fileno[6];
+
+    ibcs2_interpreter = 0;
+    status = 0;
+    load_addr = 0;
+    load_bias = 0;
+    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
+#ifdef BSWAP_NEEDED
+    bswap_ehdr(&elf_ex);
+#endif
+
+    /* First of all, some simple consistency checks */
+    if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+                                (! elf_check_arch(elf_ex.e_machine))) {
+            return -ENOEXEC;
+    }
+
+    bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
+    bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
+    bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+    if (!bprm->p) {
+        retval = -E2BIG;
+    }
+
+    /* Now read in all of the header information */
+    elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+    if (elf_phdata == NULL) {
+        return -ENOMEM;
+    }
+
+    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
+    if(retval > 0) {
+        retval = read(bprm->fd, (char *) elf_phdata,
+                                elf_ex.e_phentsize * elf_ex.e_phnum);
+    }
+
+    if (retval < 0) {
+        perror("load_elf_binary");
+        exit(-1);
+        free (elf_phdata);
+        return -errno;
+    }
+
+#ifdef BSWAP_NEEDED
+    elf_ppnt = elf_phdata;
+    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
+        bswap_phdr(elf_ppnt);
+    }
+#endif
+    elf_ppnt = elf_phdata;
+
+    elf_bss = 0;
+    elf_brk = 0;
+
+
+    elf_stack = ~((abi_ulong)0UL);
+    elf_interpreter = NULL;
+    start_code = ~((abi_ulong)0UL);
+    end_code = 0;
+    start_data = 0;
+    end_data = 0;
+    interp_ex.a_info = 0;
+
+    for(i=0;i < elf_ex.e_phnum; i++) {
+        if (elf_ppnt->p_type == PT_INTERP) {
+            if ( elf_interpreter != NULL )
+            {
+                free (elf_phdata);
+                free(elf_interpreter);
+                close(bprm->fd);
+                return -EINVAL;
+            }
+
+            /* This is the program interpreter used for
+             * shared libraries - for now assume that this
+             * is an a.out format binary
+             */
+
+            elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
+
+            if (elf_interpreter == NULL) {
+                free (elf_phdata);
+                close(bprm->fd);
+                return -ENOMEM;
+            }
+
+            retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
+            if(retval >= 0) {
+                retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
+            }
+            if(retval < 0) {
+                perror("load_elf_binary2");
+                exit(-1);
+            }
+
+            /* If the program interpreter is one of these two,
+               then assume an iBCS2 image. Otherwise assume
+               a native linux image. */
+
+            /* JRP - Need to add X86 lib dir stuff here... */
+
+            if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
+                strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
+              ibcs2_interpreter = 1;
+            }
+
+#if 0
+            printf("Using ELF interpreter %s\n", path(elf_interpreter));
+#endif
+            if (retval >= 0) {
+                retval = open(path(elf_interpreter), O_RDONLY);
+                if(retval >= 0) {
+                    interpreter_fd = retval;
+                }
+                else {
+                    perror(elf_interpreter);
+                    exit(-1);
+                    /* retval = -errno; */
+                }
+            }
+
+            if (retval >= 0) {
+                retval = lseek(interpreter_fd, 0, SEEK_SET);
+                if(retval >= 0) {
+                    retval = read(interpreter_fd,bprm->buf,128);
+                }
+            }
+            if (retval >= 0) {
+                interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+                interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+            }
+            if (retval < 0) {
+                perror("load_elf_binary3");
+                exit(-1);
+                free (elf_phdata);
+                free(elf_interpreter);
+                close(bprm->fd);
+                return retval;
+            }
+        }
+        elf_ppnt++;
+    }
+
+    /* Some simple consistency checks for the interpreter */
+    if (elf_interpreter){
+        interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+
+        /* Now figure out which format our binary is */
+        if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
+                (N_MAGIC(interp_ex) != QMAGIC)) {
+          interpreter_type = INTERPRETER_ELF;
+        }
+
+        if (interp_elf_ex.e_ident[0] != 0x7f ||
+                strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
+            interpreter_type &= ~INTERPRETER_ELF;
+        }
+
+        if (!interpreter_type) {
+            free(elf_interpreter);
+            free(elf_phdata);
+            close(bprm->fd);
+            return -ELIBBAD;
+        }
+    }
+
+    /* OK, we are done with that, now set up the arg stuff,
+       and then start this sucker up */
+
+    {
+        char * passed_p;
+
+        if (interpreter_type == INTERPRETER_AOUT) {
+            snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
+            passed_p = passed_fileno;
+
+            if (elf_interpreter) {
+                bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
+                bprm->argc++;
+            }
+        }
+        if (!bprm->p) {
+            if (elf_interpreter) {
+                free(elf_interpreter);
+            }
+            free (elf_phdata);
+            close(bprm->fd);
+            return -E2BIG;
+        }
+    }
+
+    /* OK, This is the point of no return */
+    info->end_data = 0;
+    info->end_code = 0;
+    info->start_mmap = (abi_ulong)ELF_START_MMAP;
+    info->mmap = 0;
+    elf_entry = (abi_ulong) elf_ex.e_entry;
+
+#if defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * In case where user has not explicitly set the guest_base, we
+     * probe here that should we set it automatically.
+     */
+    if (!have_guest_base) {
+        /*
+         * Go through ELF program header table and find out whether
+	 * any of the segments drop below our current mmap_min_addr and
+         * in that case set guest_base to corresponding address.
+         */
+        for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
+            i++, elf_ppnt++) {
+            if (elf_ppnt->p_type != PT_LOAD)
+                continue;
+            if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
+                guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
+                break;
+            }
+        }
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+    /* Do this so that we can load the interpreter, if need be.  We will
+       change some of these later */
+    info->rss = 0;
+    bprm->p = setup_arg_pages(bprm->p, bprm, info);
+    info->start_stack = bprm->p;
+
+    /* Now we do a little grungy work by mmaping the ELF image into
+     * the correct location in memory.  At this point, we assume that
+     * the image should be loaded at fixed address, not at a variable
+     * address.
+     */
+
+    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+        int elf_prot = 0;
+        int elf_flags = 0;
+        abi_ulong error;
+
+        if (elf_ppnt->p_type != PT_LOAD)
+            continue;
+
+        if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+        if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+        if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+        elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
+        if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+            elf_flags |= MAP_FIXED;
+        } else if (elf_ex.e_type == ET_DYN) {
+            /* Try and get dynamic programs out of the way of the default mmap
+               base, as well as whatever program they might try to exec.  This
+               is because the brk will follow the loader, and is not movable.  */
+            /* NOTE: for qemu, we do a big mmap to get enough space
+               without hardcoding any address */
+            error = target_mmap(0, ET_DYN_MAP_SIZE,
+                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
+                                -1, 0);
+            if (error == -1) {
+                perror("mmap");
+                exit(-1);
+            }
+            load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
+        }
+
+        error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
+                            (elf_ppnt->p_filesz +
+                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+                            elf_prot,
+                            (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
+                            bprm->fd,
+                            (elf_ppnt->p_offset -
+                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+        if (error == -1) {
+            perror("mmap");
+            exit(-1);
+        }
+
+#ifdef LOW_ELF_STACK
+        if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
+            elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
+#endif
+
+        if (!load_addr_set) {
+            load_addr_set = 1;
+            load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+            if (elf_ex.e_type == ET_DYN) {
+                load_bias += error -
+                    TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
+                load_addr += load_bias;
+                reloc_func_desc = load_bias;
+            }
+        }
+        k = elf_ppnt->p_vaddr;
+        if (k < start_code)
+            start_code = k;
+        if (start_data < k)
+            start_data = k;
+        k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+        if (k > elf_bss)
+            elf_bss = k;
+        if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+            end_code = k;
+        if (end_data < k)
+            end_data = k;
+        k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+        if (k > elf_brk) elf_brk = k;
+    }
+
+    elf_entry += load_bias;
+    elf_bss += load_bias;
+    elf_brk += load_bias;
+    start_code += load_bias;
+    end_code += load_bias;
+    start_data += load_bias;
+    end_data += load_bias;
+
+    if (elf_interpreter) {
+        if (interpreter_type & 1) {
+            elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
+        }
+        else if (interpreter_type & 2) {
+            elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+                                            &interp_load_addr);
+        }
+        reloc_func_desc = interp_load_addr;
+
+        close(interpreter_fd);
+        free(elf_interpreter);
+
+        if (elf_entry == ~((abi_ulong)0UL)) {
+            printf("Unable to load interpreter\n");
+            free(elf_phdata);
+            exit(-1);
+            return 0;
+        }
+    }
+
+    free(elf_phdata);
+
+    if (qemu_log_enabled())
+        load_symbols(&elf_ex, bprm->fd);
+
+    if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
+    info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
+
+#ifdef LOW_ELF_STACK
+    info->start_stack = bprm->p = elf_stack - 4;
+#endif
+    bprm->p = create_elf_tables(bprm->p,
+                    bprm->argc,
+                    bprm->envc,
+                    &elf_ex,
+                    load_addr, load_bias,
+                    interp_load_addr,
+                    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
+                    info);
+    info->load_addr = reloc_func_desc;
+    info->start_brk = info->brk = elf_brk;
+    info->end_code = end_code;
+    info->start_code = start_code;
+    info->start_data = start_data;
+    info->end_data = end_data;
+    info->start_stack = bprm->p;
+
+    /* Calling set_brk effectively mmaps the pages that we need for the bss and break
+       sections */
+    set_brk(elf_bss, elf_brk);
+
+    padzero(elf_bss, elf_brk);
+
+#if 0
+    printf("(start_brk) %x\n" , info->start_brk);
+    printf("(end_code) %x\n" , info->end_code);
+    printf("(start_code) %x\n" , info->start_code);
+    printf("(end_data) %x\n" , info->end_data);
+    printf("(start_stack) %x\n" , info->start_stack);
+    printf("(brk) %x\n" , info->brk);
+#endif
+
+    if ( info->personality == PER_SVR4 )
+    {
+            /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+               and some applications "depend" upon this behavior.
+               Since we do not have the power to recompile these, we
+               emulate the SVr4 behavior.  Sigh.  */
+            mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+                                      MAP_FIXED | MAP_PRIVATE, -1, 0);
+    }
+
+    info->entry = elf_entry;
+
+    return 0;
+}
+
+static int load_aout_interp(void * exptr, int interp_fd)
+{
+    printf("a.out interpreter not yet supported\n");
+    return(0);
+}
+
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    init_thread(regs, infop);
+}
diff --git a/qemu-0.15.x/bsd-user/errno_defs.h b/qemu-0.15.x/bsd-user/errno_defs.h
new file mode 100644
index 0000000..1efa502
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/errno_defs.h
@@ -0,0 +1,149 @@
+/*      $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $      */
+/*      $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $   */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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. 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.
+ *
+ *      @(#)errno.h     8.5 (Berkeley) 1/21/94
+ */
+
+#define TARGET_EPERM            1               /* Operation not permitted */
+#define TARGET_ENOENT           2               /* No such file or directory */
+#define TARGET_ESRCH            3               /* No such process */
+#define TARGET_EINTR            4               /* Interrupted system call */
+#define TARGET_EIO              5               /* Input/output error */
+#define TARGET_ENXIO            6               /* Device not configured */
+#define TARGET_E2BIG            7               /* Argument list too long */
+#define TARGET_ENOEXEC          8               /* Exec format error */
+#define TARGET_EBADF            9               /* Bad file descriptor */
+#define TARGET_ECHILD           10              /* No child processes */
+#define TARGET_EDEADLK          11              /* Resource deadlock avoided */
+                                        /* 11 was EAGAIN */
+#define TARGET_ENOMEM           12              /* Cannot allocate memory */
+#define TARGET_EACCES           13              /* Permission denied */
+#define TARGET_EFAULT           14              /* Bad address */
+#define TARGET_ENOTBLK          15              /* Block device required */
+#define TARGET_EBUSY            16              /* Device busy */
+#define TARGET_EEXIST           17              /* File exists */
+#define TARGET_EXDEV            18              /* Cross-device link */
+#define TARGET_ENODEV           19              /* Operation not supported by device */
+#define TARGET_ENOTDIR          20              /* Not a directory */
+#define TARGET_EISDIR           21              /* Is a directory */
+#define TARGET_EINVAL           22              /* Invalid argument */
+#define TARGET_ENFILE           23              /* Too many open files in system */
+#define TARGET_EMFILE           24              /* Too many open files */
+#define TARGET_ENOTTY           25              /* Inappropriate ioctl for device */
+#define TARGET_ETXTBSY          26              /* Text file busy */
+#define TARGET_EFBIG            27              /* File too large */
+#define TARGET_ENOSPC           28              /* No space left on device */
+#define TARGET_ESPIPE           29              /* Illegal seek */
+#define TARGET_EROFS            30              /* Read-only file system */
+#define TARGET_EMLINK           31              /* Too many links */
+#define TARGET_EPIPE            32              /* Broken pipe */
+
+/* math software */
+#define TARGET_EDOM             33              /* Numerical argument out of domain */
+#define TARGET_ERANGE           34              /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define TARGET_EAGAIN           35              /* Resource temporarily unavailable */
+#define TARGET_EWOULDBLOCK      EAGAIN          /* Operation would block */
+#define TARGET_EINPROGRESS      36              /* Operation now in progress */
+#define TARGET_EALREADY 37              /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define TARGET_ENOTSOCK 38              /* Socket operation on non-socket */
+#define TARGET_EDESTADDRREQ     39              /* Destination address required */
+#define TARGET_EMSGSIZE 40              /* Message too long */
+#define TARGET_EPROTOTYPE       41              /* Protocol wrong type for socket */
+#define TARGET_ENOPROTOOPT      42              /* Protocol not available */
+#define TARGET_EPROTONOSUPPORT  43              /* Protocol not supported */
+#define TARGET_ESOCKTNOSUPPORT  44              /* Socket type not supported */
+#define TARGET_EOPNOTSUPP       45              /* Operation not supported */
+#define TARGET_EPFNOSUPPORT     46              /* Protocol family not supported */
+#define TARGET_EAFNOSUPPORT     47              /* Address family not supported by protocol family */
+#define TARGET_EADDRINUSE       48              /* Address already in use */
+#define TARGET_EADDRNOTAVAIL    49              /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define TARGET_ENETDOWN 50              /* Network is down */
+#define TARGET_ENETUNREACH      51              /* Network is unreachable */
+#define TARGET_ENETRESET        52              /* Network dropped connection on reset */
+#define TARGET_ECONNABORTED     53              /* Software caused connection abort */
+#define TARGET_ECONNRESET       54              /* Connection reset by peer */
+#define TARGET_ENOBUFS          55              /* No buffer space available */
+#define TARGET_EISCONN          56              /* Socket is already connected */
+#define TARGET_ENOTCONN 57              /* Socket is not connected */
+#define TARGET_ESHUTDOWN        58              /* Can't send after socket shutdown */
+#define TARGET_ETOOMANYREFS     59              /* Too many references: can't splice */
+#define TARGET_ETIMEDOUT        60              /* Operation timed out */
+#define TARGET_ECONNREFUSED     61              /* Connection refused */
+
+#define TARGET_ELOOP            62              /* Too many levels of symbolic links */
+#define TARGET_ENAMETOOLONG     63              /* File name too long */
+
+/* should be rearranged */
+#define TARGET_EHOSTDOWN        64              /* Host is down */
+#define TARGET_EHOSTUNREACH     65              /* No route to host */
+#define TARGET_ENOTEMPTY        66              /* Directory not empty */
+
+/* quotas & mush */
+#define TARGET_EPROCLIM 67              /* Too many processes */
+#define TARGET_EUSERS           68              /* Too many users */
+#define TARGET_EDQUOT           69              /* Disk quota exceeded */
+
+/* Network File System */
+#define TARGET_ESTALE           70              /* Stale NFS file handle */
+#define TARGET_EREMOTE          71              /* Too many levels of remote in path */
+#define TARGET_EBADRPC          72              /* RPC struct is bad */
+#define TARGET_ERPCMISMATCH     73              /* RPC version wrong */
+#define TARGET_EPROGUNAVAIL     74              /* RPC prog. not avail */
+#define TARGET_EPROGMISMATCH    75              /* Program version wrong */
+#define TARGET_EPROCUNAVAIL     76              /* Bad procedure for program */
+
+#define TARGET_ENOLCK           77              /* No locks available */
+#define TARGET_ENOSYS           78              /* Function not implemented */
+
+#define TARGET_EFTYPE           79              /* Inappropriate file type or format */
+#define TARGET_EAUTH            80              /* Authentication error */
+#define TARGET_ENEEDAUTH        81              /* Need authenticator */
+#define TARGET_EIPSEC           82              /* IPsec processing failure */
+#define TARGET_ENOATTR          83              /* Attribute not found */
+#define TARGET_EILSEQ           84              /* Illegal byte sequence */
+#define TARGET_ENOMEDIUM        85              /* No medium found */
+#define TARGET_EMEDIUMTYPE      86              /* Wrong Medium Type */
+#define TARGET_EOVERFLOW        87              /* Conversion overflow */
+#define TARGET_ECANCELED        88              /* Operation canceled */
+#define TARGET_EIDRM            89              /* Identifier removed */
+#define TARGET_ENOMSG           90              /* No message of desired type */
+#define TARGET_ELAST            90              /* Must be equal largest errno */
diff --git a/qemu-0.15.x/bsd-user/freebsd/strace.list b/qemu-0.15.x/bsd-user/freebsd/strace.list
new file mode 100644
index 0000000..1edf412
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/freebsd/strace.list
@@ -0,0 +1,171 @@
+{ TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_bind, "bind", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_break, "break", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_chflags, "chflags", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_chown, "chown", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_chroot, "chroot", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_close, "close", "%s(%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL },
+{ TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getlogin, "getlogin", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_getresgid, "getresgid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getresuid, "getresuid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getsid, "getsid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
+{ TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mincore, "mincore", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_minherit, "minherit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_FREEBSD_NR_mlock, "mlock", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
+{ TARGET_FREEBSD_NR_mount, "mount", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_msgctl, "msgctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_msgget, "msgget", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_msync, "msync", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_munlock, "munlock", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_preadv, "preadv", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_profil, "profil", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_readv, "readv", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_reboot, "reboot", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_semget, "semget", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setlogin, "setlogin", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setregid, "setregid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setresgid, "setresgid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setresuid, "setresuid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setsid, "setsid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_setuid, "setuid", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_shmat, "shmat", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_shmctl, "shmctl", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_shmget, "shmget", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sigaction, "sigaction", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_sigpending, "sigpending", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
+{ TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
+{ TARGET_FREEBSD_NR_unmount, "unmount", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_utimes, "utimes", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_vfork, "vfork", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_wait4, "wait4", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_FREEBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },
diff --git a/qemu-0.15.x/bsd-user/freebsd/syscall_nr.h b/qemu-0.15.x/bsd-user/freebsd/syscall_nr.h
new file mode 100644
index 0000000..36336ab
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/freebsd/syscall_nr.h
@@ -0,0 +1,373 @@
+/*
+ * System call numbers.
+ *
+ * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $
+ * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson
+ */
+
+#define TARGET_FREEBSD_NR_syscall     0
+#define TARGET_FREEBSD_NR_exit        1
+#define TARGET_FREEBSD_NR_fork        2
+#define TARGET_FREEBSD_NR_read        3
+#define TARGET_FREEBSD_NR_write       4
+#define TARGET_FREEBSD_NR_open        5
+#define TARGET_FREEBSD_NR_close       6
+#define TARGET_FREEBSD_NR_wait4       7
+#define TARGET_FREEBSD_NR_link        9
+#define TARGET_FREEBSD_NR_unlink      10
+#define TARGET_FREEBSD_NR_chdir       12
+#define TARGET_FREEBSD_NR_fchdir      13
+#define TARGET_FREEBSD_NR_mknod       14
+#define TARGET_FREEBSD_NR_chmod       15
+#define TARGET_FREEBSD_NR_chown       16
+#define TARGET_FREEBSD_NR_break       17
+#define TARGET_FREEBSD_NR_freebsd4_getfsstat  18
+#define TARGET_FREEBSD_NR_getpid      20
+#define TARGET_FREEBSD_NR_mount       21
+#define TARGET_FREEBSD_NR_unmount     22
+#define TARGET_FREEBSD_NR_setuid      23
+#define TARGET_FREEBSD_NR_getuid      24
+#define TARGET_FREEBSD_NR_geteuid     25
+#define TARGET_FREEBSD_NR_ptrace      26
+#define TARGET_FREEBSD_NR_recvmsg     27
+#define TARGET_FREEBSD_NR_sendmsg     28
+#define TARGET_FREEBSD_NR_recvfrom    29
+#define TARGET_FREEBSD_NR_accept      30
+#define TARGET_FREEBSD_NR_getpeername 31
+#define TARGET_FREEBSD_NR_getsockname 32
+#define TARGET_FREEBSD_NR_access      33
+#define TARGET_FREEBSD_NR_chflags     34
+#define TARGET_FREEBSD_NR_fchflags    35
+#define TARGET_FREEBSD_NR_sync        36
+#define TARGET_FREEBSD_NR_kill        37
+#define TARGET_FREEBSD_NR_getppid     39
+#define TARGET_FREEBSD_NR_dup 41
+#define TARGET_FREEBSD_NR_pipe        42
+#define TARGET_FREEBSD_NR_getegid     43
+#define TARGET_FREEBSD_NR_profil      44
+#define TARGET_FREEBSD_NR_ktrace      45
+#define TARGET_FREEBSD_NR_getgid      47
+#define TARGET_FREEBSD_NR_getlogin    49
+#define TARGET_FREEBSD_NR_setlogin    50
+#define TARGET_FREEBSD_NR_acct        51
+#define TARGET_FREEBSD_NR_sigaltstack 53
+#define TARGET_FREEBSD_NR_ioctl       54
+#define TARGET_FREEBSD_NR_reboot      55
+#define TARGET_FREEBSD_NR_revoke      56
+#define TARGET_FREEBSD_NR_symlink     57
+#define TARGET_FREEBSD_NR_readlink    58
+#define TARGET_FREEBSD_NR_execve      59
+#define TARGET_FREEBSD_NR_umask       60
+#define TARGET_FREEBSD_NR_chroot      61
+#define TARGET_FREEBSD_NR_msync       65
+#define TARGET_FREEBSD_NR_vfork       66
+#define TARGET_FREEBSD_NR_sbrk        69
+#define TARGET_FREEBSD_NR_sstk        70
+#define TARGET_FREEBSD_NR_vadvise     72
+#define TARGET_FREEBSD_NR_munmap      73
+#define TARGET_FREEBSD_NR_mprotect    74
+#define TARGET_FREEBSD_NR_madvise     75
+#define TARGET_FREEBSD_NR_mincore     78
+#define TARGET_FREEBSD_NR_getgroups   79
+#define TARGET_FREEBSD_NR_setgroups   80
+#define TARGET_FREEBSD_NR_getpgrp     81
+#define TARGET_FREEBSD_NR_setpgid     82
+#define TARGET_FREEBSD_NR_setitimer   83
+#define TARGET_FREEBSD_NR_swapon      85
+#define TARGET_FREEBSD_NR_getitimer   86
+#define TARGET_FREEBSD_NR_getdtablesize       89
+#define TARGET_FREEBSD_NR_dup2        90
+#define TARGET_FREEBSD_NR_fcntl       92
+#define TARGET_FREEBSD_NR_select      93
+#define TARGET_FREEBSD_NR_fsync       95
+#define TARGET_FREEBSD_NR_setpriority 96
+#define TARGET_FREEBSD_NR_socket      97
+#define TARGET_FREEBSD_NR_connect     98
+#define TARGET_FREEBSD_NR_getpriority 100
+#define TARGET_FREEBSD_NR_bind        104
+#define TARGET_FREEBSD_NR_setsockopt  105
+#define TARGET_FREEBSD_NR_listen      106
+#define TARGET_FREEBSD_NR_gettimeofday        116
+#define TARGET_FREEBSD_NR_getrusage   117
+#define TARGET_FREEBSD_NR_getsockopt  118
+#define TARGET_FREEBSD_NR_readv       120
+#define TARGET_FREEBSD_NR_writev      121
+#define TARGET_FREEBSD_NR_settimeofday        122
+#define TARGET_FREEBSD_NR_fchown      123
+#define TARGET_FREEBSD_NR_fchmod      124
+#define TARGET_FREEBSD_NR_setreuid    126
+#define TARGET_FREEBSD_NR_setregid    127
+#define TARGET_FREEBSD_NR_rename      128
+#define TARGET_FREEBSD_NR_flock       131
+#define TARGET_FREEBSD_NR_mkfifo      132
+#define TARGET_FREEBSD_NR_sendto      133
+#define TARGET_FREEBSD_NR_shutdown    134
+#define TARGET_FREEBSD_NR_socketpair  135
+#define TARGET_FREEBSD_NR_mkdir       136
+#define TARGET_FREEBSD_NR_rmdir       137
+#define TARGET_FREEBSD_NR_utimes      138
+#define TARGET_FREEBSD_NR_adjtime     140
+#define TARGET_FREEBSD_NR_setsid      147
+#define TARGET_FREEBSD_NR_quotactl    148
+#define TARGET_FREEBSD_NR_nlm_syscall 154
+#define TARGET_FREEBSD_NR_nfssvc      155
+#define TARGET_FREEBSD_NR_freebsd4_statfs     157
+#define TARGET_FREEBSD_NR_freebsd4_fstatfs    158
+#define TARGET_FREEBSD_NR_lgetfh      160
+#define TARGET_FREEBSD_NR_getfh       161
+#define TARGET_FREEBSD_NR_getdomainname       162
+#define TARGET_FREEBSD_NR_setdomainname       163
+#define TARGET_FREEBSD_NR_uname       164
+#define TARGET_FREEBSD_NR_sysarch     165
+#define TARGET_FREEBSD_NR_rtprio      166
+#define TARGET_FREEBSD_NR_semsys      169
+#define TARGET_FREEBSD_NR_msgsys      170
+#define TARGET_FREEBSD_NR_shmsys      171
+#define TARGET_FREEBSD_NR_freebsd6_pread      173
+#define TARGET_FREEBSD_NR_freebsd6_pwrite     174
+#define TARGET_FREEBSD_NR_setfib      175
+#define TARGET_FREEBSD_NR_ntp_adjtime 176
+#define TARGET_FREEBSD_NR_setgid      181
+#define TARGET_FREEBSD_NR_setegid     182
+#define TARGET_FREEBSD_NR_seteuid     183
+#define TARGET_FREEBSD_NR_stat        188
+#define TARGET_FREEBSD_NR_fstat       189
+#define TARGET_FREEBSD_NR_lstat       190
+#define TARGET_FREEBSD_NR_pathconf    191
+#define TARGET_FREEBSD_NR_fpathconf   192
+#define TARGET_FREEBSD_NR_getrlimit   194
+#define TARGET_FREEBSD_NR_setrlimit   195
+#define TARGET_FREEBSD_NR_getdirentries       196
+#define TARGET_FREEBSD_NR_freebsd6_mmap       197
+#define TARGET_FREEBSD_NR___syscall   198
+#define TARGET_FREEBSD_NR_freebsd6_lseek      199
+#define TARGET_FREEBSD_NR_freebsd6_truncate   200
+#define TARGET_FREEBSD_NR_freebsd6_ftruncate  201
+#define TARGET_FREEBSD_NR___sysctl    202
+#define TARGET_FREEBSD_NR_mlock       203
+#define TARGET_FREEBSD_NR_munlock     204
+#define TARGET_FREEBSD_NR_undelete    205
+#define TARGET_FREEBSD_NR_futimes     206
+#define TARGET_FREEBSD_NR_getpgid     207
+#define TARGET_FREEBSD_NR_poll        209
+#define TARGET_FREEBSD_NR___semctl    220
+#define TARGET_FREEBSD_NR_semget      221
+#define TARGET_FREEBSD_NR_semop       222
+#define TARGET_FREEBSD_NR_msgctl      224
+#define TARGET_FREEBSD_NR_msgget      225
+#define TARGET_FREEBSD_NR_msgsnd      226
+#define TARGET_FREEBSD_NR_msgrcv      227
+#define TARGET_FREEBSD_NR_shmat       228
+#define TARGET_FREEBSD_NR_shmctl      229
+#define TARGET_FREEBSD_NR_shmdt       230
+#define TARGET_FREEBSD_NR_shmget      231
+#define TARGET_FREEBSD_NR_clock_gettime       232
+#define TARGET_FREEBSD_NR_clock_settime       233
+#define TARGET_FREEBSD_NR_clock_getres        234
+#define TARGET_FREEBSD_NR_ktimer_create       235
+#define TARGET_FREEBSD_NR_ktimer_delete       236
+#define TARGET_FREEBSD_NR_ktimer_settime      237
+#define TARGET_FREEBSD_NR_ktimer_gettime      238
+#define TARGET_FREEBSD_NR_ktimer_getoverrun   239
+#define TARGET_FREEBSD_NR_nanosleep   240
+#define TARGET_FREEBSD_NR_ntp_gettime 248
+#define TARGET_FREEBSD_NR_minherit    250
+#define TARGET_FREEBSD_NR_rfork       251
+#define TARGET_FREEBSD_NR_openbsd_poll        252
+#define TARGET_FREEBSD_NR_issetugid   253
+#define TARGET_FREEBSD_NR_lchown      254
+#define TARGET_FREEBSD_NR_aio_read    255
+#define TARGET_FREEBSD_NR_aio_write   256
+#define TARGET_FREEBSD_NR_lio_listio  257
+#define TARGET_FREEBSD_NR_getdents    272
+#define TARGET_FREEBSD_NR_lchmod      274
+#define TARGET_FREEBSD_NR_netbsd_lchown       275
+#define TARGET_FREEBSD_NR_lutimes     276
+#define TARGET_FREEBSD_NR_netbsd_msync        277
+#define TARGET_FREEBSD_NR_nstat       278
+#define TARGET_FREEBSD_NR_nfstat      279
+#define TARGET_FREEBSD_NR_nlstat      280
+#define TARGET_FREEBSD_NR_preadv      289
+#define TARGET_FREEBSD_NR_pwritev     290
+#define TARGET_FREEBSD_NR_freebsd4_fhstatfs   297
+#define TARGET_FREEBSD_NR_fhopen      298
+#define TARGET_FREEBSD_NR_fhstat      299
+#define TARGET_FREEBSD_NR_modnext     300
+#define TARGET_FREEBSD_NR_modstat     301
+#define TARGET_FREEBSD_NR_modfnext    302
+#define TARGET_FREEBSD_NR_modfind     303
+#define TARGET_FREEBSD_NR_kldload     304
+#define TARGET_FREEBSD_NR_kldunload   305
+#define TARGET_FREEBSD_NR_kldfind     306
+#define TARGET_FREEBSD_NR_kldnext     307
+#define TARGET_FREEBSD_NR_kldstat     308
+#define TARGET_FREEBSD_NR_kldfirstmod 309
+#define TARGET_FREEBSD_NR_getsid      310
+#define TARGET_FREEBSD_NR_setresuid   311
+#define TARGET_FREEBSD_NR_setresgid   312
+#define TARGET_FREEBSD_NR_aio_return  314
+#define TARGET_FREEBSD_NR_aio_suspend 315
+#define TARGET_FREEBSD_NR_aio_cancel  316
+#define TARGET_FREEBSD_NR_aio_error   317
+#define TARGET_FREEBSD_NR_oaio_read   318
+#define TARGET_FREEBSD_NR_oaio_write  319
+#define TARGET_FREEBSD_NR_olio_listio 320
+#define TARGET_FREEBSD_NR_yield       321
+#define TARGET_FREEBSD_NR_mlockall    324
+#define TARGET_FREEBSD_NR_munlockall  325
+#define TARGET_FREEBSD_NR___getcwd    326
+#define TARGET_FREEBSD_NR_sched_setparam      327
+#define TARGET_FREEBSD_NR_sched_getparam      328
+#define TARGET_FREEBSD_NR_sched_setscheduler  329
+#define TARGET_FREEBSD_NR_sched_getscheduler  330
+#define TARGET_FREEBSD_NR_sched_yield 331
+#define TARGET_FREEBSD_NR_sched_get_priority_max      332
+#define TARGET_FREEBSD_NR_sched_get_priority_min      333
+#define TARGET_FREEBSD_NR_sched_rr_get_interval       334
+#define TARGET_FREEBSD_NR_utrace      335
+#define TARGET_FREEBSD_NR_freebsd4_sendfile   336
+#define TARGET_FREEBSD_NR_kldsym      337
+#define TARGET_FREEBSD_NR_jail        338
+#define TARGET_FREEBSD_NR_sigprocmask 340
+#define TARGET_FREEBSD_NR_sigsuspend  341
+#define TARGET_FREEBSD_NR_freebsd4_sigaction  342
+#define TARGET_FREEBSD_NR_sigpending  343
+#define TARGET_FREEBSD_NR_freebsd4_sigreturn  344
+#define TARGET_FREEBSD_NR_sigtimedwait        345
+#define TARGET_FREEBSD_NR_sigwaitinfo 346
+#define TARGET_FREEBSD_NR___acl_get_file      347
+#define TARGET_FREEBSD_NR___acl_set_file      348
+#define TARGET_FREEBSD_NR___acl_get_fd        349
+#define TARGET_FREEBSD_NR___acl_set_fd        350
+#define TARGET_FREEBSD_NR___acl_delete_file   351
+#define TARGET_FREEBSD_NR___acl_delete_fd     352
+#define TARGET_FREEBSD_NR___acl_aclcheck_file 353
+#define TARGET_FREEBSD_NR___acl_aclcheck_fd   354
+#define TARGET_FREEBSD_NR_extattrctl  355
+#define TARGET_FREEBSD_NR_extattr_set_file    356
+#define TARGET_FREEBSD_NR_extattr_get_file    357
+#define TARGET_FREEBSD_NR_extattr_delete_file 358
+#define TARGET_FREEBSD_NR_aio_waitcomplete    359
+#define TARGET_FREEBSD_NR_getresuid   360
+#define TARGET_FREEBSD_NR_getresgid   361
+#define TARGET_FREEBSD_NR_kqueue      362
+#define TARGET_FREEBSD_NR_kevent      363
+#define TARGET_FREEBSD_NR_extattr_set_fd      371
+#define TARGET_FREEBSD_NR_extattr_get_fd      372
+#define TARGET_FREEBSD_NR_extattr_delete_fd   373
+#define TARGET_FREEBSD_NR___setugid   374
+#define TARGET_FREEBSD_NR_nfsclnt     375
+#define TARGET_FREEBSD_NR_eaccess     376
+#define TARGET_FREEBSD_NR_nmount      378
+#define TARGET_FREEBSD_NR___mac_get_proc      384
+#define TARGET_FREEBSD_NR___mac_set_proc      385
+#define TARGET_FREEBSD_NR___mac_get_fd        386
+#define TARGET_FREEBSD_NR___mac_get_file      387
+#define TARGET_FREEBSD_NR___mac_set_fd        388
+#define TARGET_FREEBSD_NR___mac_set_file      389
+#define TARGET_FREEBSD_NR_kenv        390
+#define TARGET_FREEBSD_NR_lchflags    391
+#define TARGET_FREEBSD_NR_uuidgen     392
+#define TARGET_FREEBSD_NR_sendfile    393
+#define TARGET_FREEBSD_NR_mac_syscall 394
+#define TARGET_FREEBSD_NR_getfsstat   395
+#define TARGET_FREEBSD_NR_statfs      396
+#define TARGET_FREEBSD_NR_fstatfs     397
+#define TARGET_FREEBSD_NR_fhstatfs    398
+#define TARGET_FREEBSD_NR_ksem_close  400
+#define TARGET_FREEBSD_NR_ksem_post   401
+#define TARGET_FREEBSD_NR_ksem_wait   402
+#define TARGET_FREEBSD_NR_ksem_trywait        403
+#define TARGET_FREEBSD_NR_ksem_init   404
+#define TARGET_FREEBSD_NR_ksem_open   405
+#define TARGET_FREEBSD_NR_ksem_unlink 406
+#define TARGET_FREEBSD_NR_ksem_getvalue       407
+#define TARGET_FREEBSD_NR_ksem_destroy        408
+#define TARGET_FREEBSD_NR___mac_get_pid       409
+#define TARGET_FREEBSD_NR___mac_get_link      410
+#define TARGET_FREEBSD_NR___mac_set_link      411
+#define TARGET_FREEBSD_NR_extattr_set_link    412
+#define TARGET_FREEBSD_NR_extattr_get_link    413
+#define TARGET_FREEBSD_NR_extattr_delete_link 414
+#define TARGET_FREEBSD_NR___mac_execve        415
+#define TARGET_FREEBSD_NR_sigaction   416
+#define TARGET_FREEBSD_NR_sigreturn   417
+#define TARGET_FREEBSD_NR_getcontext  421
+#define TARGET_FREEBSD_NR_setcontext  422
+#define TARGET_FREEBSD_NR_swapcontext 423
+#define TARGET_FREEBSD_NR_swapoff     424
+#define TARGET_FREEBSD_NR___acl_get_link      425
+#define TARGET_FREEBSD_NR___acl_set_link      426
+#define TARGET_FREEBSD_NR___acl_delete_link   427
+#define TARGET_FREEBSD_NR___acl_aclcheck_link 428
+#define TARGET_FREEBSD_NR_sigwait     429
+#define TARGET_FREEBSD_NR_thr_create  430
+#define TARGET_FREEBSD_NR_thr_exit    431
+#define TARGET_FREEBSD_NR_thr_self    432
+#define TARGET_FREEBSD_NR_thr_kill    433
+#define TARGET_FREEBSD_NR__umtx_lock  434
+#define TARGET_FREEBSD_NR__umtx_unlock        435
+#define TARGET_FREEBSD_NR_jail_attach 436
+#define TARGET_FREEBSD_NR_extattr_list_fd     437
+#define TARGET_FREEBSD_NR_extattr_list_file   438
+#define TARGET_FREEBSD_NR_extattr_list_link   439
+#define TARGET_FREEBSD_NR_ksem_timedwait      441
+#define TARGET_FREEBSD_NR_thr_suspend 442
+#define TARGET_FREEBSD_NR_thr_wake    443
+#define TARGET_FREEBSD_NR_kldunloadf  444
+#define TARGET_FREEBSD_NR_audit       445
+#define TARGET_FREEBSD_NR_auditon     446
+#define TARGET_FREEBSD_NR_getauid     447
+#define TARGET_FREEBSD_NR_setauid     448
+#define TARGET_FREEBSD_NR_getaudit    449
+#define TARGET_FREEBSD_NR_setaudit    450
+#define TARGET_FREEBSD_NR_getaudit_addr       451
+#define TARGET_FREEBSD_NR_setaudit_addr       452
+#define TARGET_FREEBSD_NR_auditctl    453
+#define TARGET_FREEBSD_NR__umtx_op    454
+#define TARGET_FREEBSD_NR_thr_new     455
+#define TARGET_FREEBSD_NR_sigqueue    456
+#define TARGET_FREEBSD_NR_kmq_open    457
+#define TARGET_FREEBSD_NR_kmq_setattr 458
+#define TARGET_FREEBSD_NR_kmq_timedreceive    459
+#define TARGET_FREEBSD_NR_kmq_timedsend       460
+#define TARGET_FREEBSD_NR_kmq_notify  461
+#define TARGET_FREEBSD_NR_kmq_unlink  462
+#define TARGET_FREEBSD_NR_abort2      463
+#define TARGET_FREEBSD_NR_thr_set_name        464
+#define TARGET_FREEBSD_NR_aio_fsync   465
+#define TARGET_FREEBSD_NR_rtprio_thread       466
+#define TARGET_FREEBSD_NR_sctp_peeloff        471
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg        472
+#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov    473
+#define TARGET_FREEBSD_NR_sctp_generic_recvmsg        474
+#define TARGET_FREEBSD_NR_pread       475
+#define TARGET_FREEBSD_NR_pwrite      476
+#define TARGET_FREEBSD_NR_mmap        477
+#define TARGET_FREEBSD_NR_lseek       478
+#define TARGET_FREEBSD_NR_truncate    479
+#define TARGET_FREEBSD_NR_ftruncate   480
+#define TARGET_FREEBSD_NR_thr_kill2   481
+#define TARGET_FREEBSD_NR_shm_open    482
+#define TARGET_FREEBSD_NR_shm_unlink  483
+#define TARGET_FREEBSD_NR_cpuset      484
+#define TARGET_FREEBSD_NR_cpuset_setid        485
+#define TARGET_FREEBSD_NR_cpuset_getid        486
+#define TARGET_FREEBSD_NR_cpuset_getaffinity  487
+#define TARGET_FREEBSD_NR_cpuset_setaffinity  488
+#define TARGET_FREEBSD_NR_faccessat   489
+#define TARGET_FREEBSD_NR_fchmodat    490
+#define TARGET_FREEBSD_NR_fchownat    491
+#define TARGET_FREEBSD_NR_fexecve     492
+#define TARGET_FREEBSD_NR_fstatat     493
+#define TARGET_FREEBSD_NR_futimesat   494
+#define TARGET_FREEBSD_NR_linkat      495
+#define TARGET_FREEBSD_NR_mkdirat     496
+#define TARGET_FREEBSD_NR_mkfifoat    497
+#define TARGET_FREEBSD_NR_mknodat     498
+#define TARGET_FREEBSD_NR_openat      499
+#define TARGET_FREEBSD_NR_readlinkat  500
+#define TARGET_FREEBSD_NR_renameat    501
+#define TARGET_FREEBSD_NR_symlinkat   502
+#define TARGET_FREEBSD_NR_unlinkat    503
+#define TARGET_FREEBSD_NR_posix_openpt        504
diff --git a/qemu-0.15.x/bsd-user/i386/syscall.h b/qemu-0.15.x/bsd-user/i386/syscall.h
new file mode 100644
index 0000000..9b34c61
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/i386/syscall.h
@@ -0,0 +1,161 @@
+/* default linux values for the selectors */
+#define __USER_CS	(0x23)
+#define __USER_DS	(0x2B)
+
+struct target_pt_regs {
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	int  xds;
+	int  xes;
+	long orig_eax;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+
+/* ioctls */
+
+#define TARGET_LDT_ENTRIES      8192
+#define TARGET_LDT_ENTRY_SIZE	8
+
+#define TARGET_GDT_ENTRIES             9
+#define TARGET_GDT_ENTRY_TLS_ENTRIES   3
+#define TARGET_GDT_ENTRY_TLS_MIN       6
+#define TARGET_GDT_ENTRY_TLS_MAX       (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
+
+struct target_modify_ldt_ldt_s {
+    unsigned int  entry_number;
+    abi_ulong base_addr;
+    unsigned int limit;
+    unsigned int flags;
+};
+
+/* vm86 defines */
+
+#define TARGET_BIOSSEG		0x0f000
+
+#define TARGET_CPU_086		0
+#define TARGET_CPU_186		1
+#define TARGET_CPU_286		2
+#define TARGET_CPU_386		3
+#define TARGET_CPU_486		4
+#define TARGET_CPU_586		5
+
+#define TARGET_VM86_SIGNAL	0	/* return due to signal */
+#define TARGET_VM86_UNKNOWN	1	/* unhandled GP fault - IO-instruction or similar */
+#define TARGET_VM86_INTx	2	/* int3/int x instruction (ARG = x) */
+#define TARGET_VM86_STI	3	/* sti/popf/iret instruction enabled virtual interrupts */
+
+/*
+ * Additional return values when invoking new vm86()
+ */
+#define TARGET_VM86_PICRETURN	4	/* return due to pending PIC request */
+#define TARGET_VM86_TRAP	6	/* return due to DOS-debugger request */
+
+/*
+ * function codes when invoking new vm86()
+ */
+#define TARGET_VM86_PLUS_INSTALL_CHECK	0
+#define TARGET_VM86_ENTER		1
+#define TARGET_VM86_ENTER_NO_BYPASS	2
+#define	TARGET_VM86_REQUEST_IRQ	3
+#define TARGET_VM86_FREE_IRQ		4
+#define TARGET_VM86_GET_IRQ_BITS	5
+#define TARGET_VM86_GET_AND_RESET_IRQ	6
+
+/*
+ * This is the stack-layout seen by the user space program when we have
+ * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
+ * is 'kernel_vm86_regs' (see below).
+ */
+
+struct target_vm86_regs {
+/*
+ * normal regs, with special meaning for the segment descriptors..
+ */
+	abi_long ebx;
+	abi_long ecx;
+	abi_long edx;
+	abi_long esi;
+	abi_long edi;
+	abi_long ebp;
+	abi_long eax;
+	abi_long __null_ds;
+	abi_long __null_es;
+	abi_long __null_fs;
+	abi_long __null_gs;
+	abi_long orig_eax;
+	abi_long eip;
+	unsigned short cs, __csh;
+	abi_long eflags;
+	abi_long esp;
+	unsigned short ss, __ssh;
+/*
+ * these are specific to v86 mode:
+ */
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned short fs, __fsh;
+	unsigned short gs, __gsh;
+};
+
+struct target_revectored_struct {
+	abi_ulong __map[8];			/* 256 bits */
+};
+
+struct target_vm86_struct {
+	struct target_vm86_regs regs;
+	abi_ulong flags;
+	abi_ulong screen_bitmap;
+	abi_ulong cpu_type;
+	struct target_revectored_struct int_revectored;
+	struct target_revectored_struct int21_revectored;
+};
+
+/*
+ * flags masks
+ */
+#define TARGET_VM86_SCREEN_BITMAP	0x0001
+
+struct target_vm86plus_info_struct {
+        abi_ulong flags;
+#define TARGET_force_return_for_pic (1 << 0)
+#define TARGET_vm86dbg_active       (1 << 1)  /* for debugger */
+#define TARGET_vm86dbg_TFpendig     (1 << 2)  /* for debugger */
+#define TARGET_is_vm86pus           (1 << 31) /* for vm86 internal use */
+	unsigned char vm86dbg_intxxtab[32];   /* for debugger */
+};
+
+struct target_vm86plus_struct {
+	struct target_vm86_regs regs;
+	abi_ulong flags;
+	abi_ulong screen_bitmap;
+	abi_ulong cpu_type;
+	struct target_revectored_struct int_revectored;
+	struct target_revectored_struct int21_revectored;
+	struct target_vm86plus_info_struct vm86plus;
+};
+
+/* FreeBSD sysarch(2) */
+#define TARGET_FREEBSD_I386_GET_LDT	0
+#define TARGET_FREEBSD_I386_SET_LDT	1
+				/* I386_IOPL */
+#define TARGET_FREEBSD_I386_GET_IOPERM	3
+#define TARGET_FREEBSD_I386_SET_IOPERM	4
+				/* xxxxx */
+#define TARGET_FREEBSD_I386_VM86	6
+#define TARGET_FREEBSD_I386_GET_FSBASE	7
+#define TARGET_FREEBSD_I386_SET_FSBASE	8
+#define TARGET_FREEBSD_I386_GET_GSBASE	9
+#define TARGET_FREEBSD_I386_SET_GSBASE	10
+
+
+#define UNAME_MACHINE "i386"
+
diff --git a/qemu-0.15.x/bsd-user/i386/target_signal.h b/qemu-0.15.x/bsd-user/i386/target_signal.h
new file mode 100644
index 0000000..2ef36d1
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/i386/target_signal.h
@@ -0,0 +1,20 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/bsd-user/main.c b/qemu-0.15.x/bsd-user/main.c
new file mode 100644
index 0000000..a63b877
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/main.c
@@ -0,0 +1,1143 @@
+/*
+ *  qemu user main
+ *
+ *  Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <machine/trap.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+/* For tb_lock */
+#include "cpu.h"
+#include "tcg.h"
+#include "qemu-timer.h"
+#include "envlist.h"
+
+#define DEBUG_LOGFILE "/tmp/qemu.log"
+
+int singlestep;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr;
+unsigned long guest_base;
+int have_guest_base;
+#endif
+
+static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
+const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
+extern char **environ;
+enum BSDType bsd_type;
+
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+   we allocate a bigger stack. Need a better solution, for example
+   by remapping the process stack directly at the right place */
+unsigned long x86_stack_size = 512 * 1024;
+
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
+#if defined(TARGET_I386)
+int cpu_get_pic_interrupt(CPUState *env)
+{
+    return -1;
+}
+#endif
+
+/* These are no-ops because we are not threadsafe.  */
+static inline void cpu_exec_start(CPUState *env)
+{
+}
+
+static inline void cpu_exec_end(CPUState *env)
+{
+}
+
+static inline void start_exclusive(void)
+{
+}
+
+static inline void end_exclusive(void)
+{
+}
+
+void fork_start(void)
+{
+}
+
+void fork_end(int child)
+{
+    if (child) {
+        gdbserver_fork(thread_env);
+    }
+}
+
+void cpu_list_lock(void)
+{
+}
+
+void cpu_list_unlock(void)
+{
+}
+
+#ifdef TARGET_I386
+/***********************************************************/
+/* CPUX86 core interface */
+
+void cpu_smm_update(CPUState *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+static uint64_t *idt_table;
+#ifdef TARGET_X86_64
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+                       uint64_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+    p[2] = tswap32(addr >> 32);
+    p[3] = 0;
+}
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+#endif
+
+void cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    //target_siginfo_t info;
+
+    for(;;) {
+        trapnr = cpu_x86_exec(env);
+        switch(trapnr) {
+        case 0x80:
+            /* syscall from int $0x80 */
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+#ifndef TARGET_ABI32
+        case EXCP_SYSCALL:
+            /* syscall from syscall instruction */
+            if (bsd_type == target_freebsd)
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
+            env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
+            break;
+#endif
+#if 0
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_fault(env);
+            } else
+#endif
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1))
+                info.si_code = TARGET_SEGV_MAPERR;
+            else
+                info.si_code = TARGET_SEGV_ACCERR;
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                /* division by zero */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->eip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP01_DB:
+        case EXCP03_INT3:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                info.si_signo = SIGTRAP;
+                info.si_errno = 0;
+                if (trapnr == EXCP01_DB) {
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    info._sifields._sigfault._addr = env->eip;
+                } else {
+                    info.si_code = TARGET_SI_KERNEL;
+                    info._sifields._sigfault._addr = 0;
+                }
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+#if 0
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+#endif
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+                    (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+#ifdef TARGET_SPARC
+#define SPARC64_STACK_BIAS 2047
+
+//#define DEBUG_WIN
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1)
+        index += 16 * env->nwindows;
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static inline void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+    if (sp_ptr & 3)
+        sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for(i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+static void save_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+    unsigned int new_wim;
+    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->wim = new_wim;
+#else
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->cansave++;
+    env->canrestore--;
+#endif
+}
+
+static void restore_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+    unsigned int new_wim;
+#endif
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+#ifndef TARGET_SPARC64
+    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+#endif
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+    if (sp_ptr & 3)
+        sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for(i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+#ifdef TARGET_SPARC64
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1)
+        env->cleanwin++;
+    env->cansave--;
+#else
+    env->wim = new_wim;
+#endif
+}
+
+static void flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for(;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+#ifndef TARGET_SPARC64
+        if (env->wim & (1 << cwp1))
+            break;
+#else
+        if (env->canrestore == 0)
+            break;
+        env->cansave++;
+        env->canrestore--;
+#endif
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#ifndef TARGET_SPARC64
+    /* set wim so that restore will reload the registers */
+    env->wim = 1 << cwp1;
+#endif
+#if defined(DEBUG_WIN)
+    printf("flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
+void cpu_loop(CPUSPARCState *env)
+{
+    int trapnr, ret, syscall_nr;
+    //target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_sparc_exec (env);
+
+        switch (trapnr) {
+#ifndef TARGET_SPARC64
+        case 0x80:
+#else
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd)
+                goto badtrap;
+        case 0x100:
+#endif
+            syscall_nr = env->gregs[1];
+            if (bsd_type == target_freebsd)
+                ret = do_freebsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5], 0, 0);
+            else if (bsd_type == target_netbsd)
+                ret = do_netbsd_syscall(env, syscall_nr,
+                                        env->regwptr[0], env->regwptr[1],
+                                        env->regwptr[2], env->regwptr[3],
+                                        env->regwptr[4], env->regwptr[5]);
+            else { //if (bsd_type == target_openbsd)
+#if defined(TARGET_SPARC64)
+                syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+                                TARGET_OPENBSD_SYSCALL_G2RFLAG);
+#endif
+                ret = do_openbsd_syscall(env, syscall_nr,
+                                         env->regwptr[0], env->regwptr[1],
+                                         env->regwptr[2], env->regwptr[3],
+                                         env->regwptr[4], env->regwptr[5]);
+            }
+            if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+                env->xcc |= PSR_CARRY;
+#else
+                env->psr |= PSR_CARRY;
+#endif
+            } else {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+                env->xcc &= ~PSR_CARRY;
+#else
+                env->psr &= ~PSR_CARRY;
+#endif
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+#if defined(TARGET_SPARC64)
+            if (bsd_type == target_openbsd &&
+                env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
+                env->pc = env->gregs[2];
+                env->npc = env->pc + 4;
+            } else if (bsd_type == target_openbsd &&
+                       env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
+                env->pc = env->gregs[7];
+                env->npc = env->pc + 4;
+            } else {
+                env->pc = env->npc;
+                env->npc = env->npc + 4;
+            }
+#else
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+#endif
+            break;
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+#ifndef TARGET_SPARC64
+        case TT_WIN_OVF: /* window overflow */
+            save_window(env);
+            break;
+        case TT_WIN_UNF: /* window underflow */
+            restore_window(env);
+            break;
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmuregs[4];
+                queue_signal(env, info.si_signo, &info);
+            }
+#endif
+            break;
+#else
+        case TT_SPILL: /* window overflow */
+            save_window(env);
+            break;
+        case TT_FILL: /* window underflow */
+            restore_window(env);
+            break;
+        case TT_TFAULT:
+        case TT_DFAULT:
+#if 0
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT)
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                else
+                    info._sifields._sigfault._addr = env->tsptr->tpc;
+                //queue_signal(env, info.si_signo, &info);
+            }
+#endif
+            break;
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+#if 0
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    //queue_signal(env, info.si_signo, &info);
+                  }
+#endif
+            }
+            break;
+        default:
+#ifdef TARGET_SPARC64
+        badtrap:
+#endif
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+
+#endif
+
+static void usage(void)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
+           "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+           "BSD CPU emulator (compiled for %s emulation)\n"
+           "\n"
+           "Standard options:\n"
+           "-h                print this help\n"
+           "-g port           wait gdb connection to port\n"
+           "-L path           set the elf interpreter prefix (default=%s)\n"
+           "-s size           set the stack size in bytes (default=%ld)\n"
+           "-cpu model        select CPU (-cpu ? for list)\n"
+           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
+           "-E var=value      sets/modifies targets environment variable(s)\n"
+           "-U var            unsets targets environment variable(s)\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+           "-B address        set guest_base address to address\n"
+#endif
+           "-bsd type         select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
+           "\n"
+           "Debug options:\n"
+           "-d options   activate log (default logfile=%s)\n"
+           "-D logfile   override default logfile location\n"
+           "-p pagesize  set the host page size to 'pagesize'\n"
+           "-singlestep  always run in singlestep mode\n"
+           "-strace      log system calls\n"
+           "\n"
+           "Environment variables:\n"
+           "QEMU_STRACE       Print system calls and arguments similar to the\n"
+           "                  'strace' program.  Enable by setting to any value.\n"
+           "You can use -E and -U options to set/unset environment variables\n"
+           "for target process.  It is possible to provide several variables\n"
+           "by repeating the option.  For example:\n"
+           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+           "Note that if you provide several changes to single variable\n"
+           "last change will stay in effect.\n"
+           ,
+           TARGET_ARCH,
+           interp_prefix,
+           x86_stack_size,
+           DEBUG_LOGFILE);
+    exit(1);
+}
+
+THREAD CPUState *thread_env;
+
+/* Assumes contents are already zeroed.  */
+void init_task_state(TaskState *ts)
+{
+    int i;
+
+    ts->used = 1;
+    ts->first_free = ts->sigqueue_table;
+    for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
+        ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
+    }
+    ts->sigqueue_table[i].next = NULL;
+}
+
+int main(int argc, char **argv)
+{
+    const char *filename;
+    const char *cpu_model;
+    const char *log_file = DEBUG_LOGFILE;
+    const char *log_mask = NULL;
+    struct target_pt_regs regs1, *regs = &regs1;
+    struct image_info info1, *info = &info1;
+    TaskState ts1, *ts = &ts1;
+    CPUState *env;
+    int optind;
+    const char *r;
+    int gdbstub_port = 0;
+    char **target_environ, **wrk;
+    envlist_t *envlist = NULL;
+    bsd_type = target_openbsd;
+
+    if (argc <= 1)
+        usage();
+
+    if ((envlist = envlist_create()) == NULL) {
+        (void) fprintf(stderr, "Unable to allocate envlist\n");
+        exit(1);
+    }
+
+    /* add current environment into the list */
+    for (wrk = environ; *wrk != NULL; wrk++) {
+        (void) envlist_setenv(envlist, *wrk);
+    }
+
+    cpu_model = NULL;
+#if defined(cpudef_setup)
+    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+        r = argv[optind];
+        if (r[0] != '-')
+            break;
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        } else if (!strcmp(r, "d")) {
+            if (optind >= argc) {
+                break;
+            }
+            log_mask = argv[optind++];
+        } else if (!strcmp(r, "D")) {
+            if (optind >= argc) {
+                break;
+            }
+            log_file = argv[optind++];
+        } else if (!strcmp(r, "E")) {
+            r = argv[optind++];
+            if (envlist_setenv(envlist, r) != 0)
+                usage();
+        } else if (!strcmp(r, "ignore-environment")) {
+            envlist_free(envlist);
+            if ((envlist = envlist_create()) == NULL) {
+                (void) fprintf(stderr, "Unable to allocate envlist\n");
+                exit(1);
+            }
+        } else if (!strcmp(r, "U")) {
+            r = argv[optind++];
+            if (envlist_unsetenv(envlist, r) != 0)
+                usage();
+        } else if (!strcmp(r, "s")) {
+            r = argv[optind++];
+            x86_stack_size = strtol(r, (char **)&r, 0);
+            if (x86_stack_size <= 0)
+                usage();
+            if (*r == 'M')
+                x86_stack_size *= 1024 * 1024;
+            else if (*r == 'k' || *r == 'K')
+                x86_stack_size *= 1024;
+        } else if (!strcmp(r, "L")) {
+            interp_prefix = argv[optind++];
+        } else if (!strcmp(r, "p")) {
+            qemu_host_page_size = atoi(argv[optind++]);
+            if (qemu_host_page_size == 0 ||
+                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+                fprintf(stderr, "page size must be a power of two\n");
+                exit(1);
+            }
+        } else if (!strcmp(r, "g")) {
+            gdbstub_port = atoi(argv[optind++]);
+        } else if (!strcmp(r, "r")) {
+            qemu_uname_release = argv[optind++];
+        } else if (!strcmp(r, "cpu")) {
+            cpu_model = argv[optind++];
+            if (strcmp(cpu_model, "?") == 0) {
+/* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list)
+                    cpu_list(stdout, &fprintf);
+#endif
+                exit(1);
+            }
+#if defined(CONFIG_USE_GUEST_BASE)
+        } else if (!strcmp(r, "B")) {
+           guest_base = strtol(argv[optind++], NULL, 0);
+           have_guest_base = 1;
+#endif
+        } else if (!strcmp(r, "drop-ld-preload")) {
+            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+        } else if (!strcmp(r, "bsd")) {
+            if (!strcasecmp(argv[optind], "freebsd")) {
+                bsd_type = target_freebsd;
+            } else if (!strcasecmp(argv[optind], "netbsd")) {
+                bsd_type = target_netbsd;
+            } else if (!strcasecmp(argv[optind], "openbsd")) {
+                bsd_type = target_openbsd;
+            } else {
+                usage();
+            }
+            optind++;
+        } else if (!strcmp(r, "singlestep")) {
+            singlestep = 1;
+        } else if (!strcmp(r, "strace")) {
+            do_strace = 1;
+        } else
+        {
+            usage();
+        }
+    }
+
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    if (log_mask) {
+        int mask;
+        const CPULogItem *item;
+
+        mask = cpu_str_to_log_mask(log_mask);
+        if (!mask) {
+            printf("Log items (comma separated):\n");
+            for (item = cpu_log_items; item->mask != 0; item++) {
+                printf("%-10s %s\n", item->name, item->help);
+            }
+            exit(1);
+        }
+        cpu_set_log(mask);
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+    filename = argv[optind];
+
+    /* Zero out regs */
+    memset(regs, 0, sizeof(struct target_pt_regs));
+
+    /* Zero out image_info */
+    memset(info, 0, sizeof(struct image_info));
+
+    /* Scan interp_prefix dir for replacement files. */
+    init_paths(interp_prefix);
+
+    if (cpu_model == NULL) {
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+#elif defined(TARGET_SPARC)
+#ifdef TARGET_SPARC64
+        cpu_model = "TI UltraSparc II";
+#else
+        cpu_model = "Fujitsu MB86904";
+#endif
+#else
+        cpu_model = "any";
+#endif
+    }
+    cpu_exec_init_all(0);
+    /* NOTE: we need to init the CPU at this stage to get
+       qemu_host_page_size */
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
+    cpu_reset(env);
+#endif
+    thread_env = env;
+
+    if (getenv("QEMU_STRACE")) {
+        do_strace = 1;
+    }
+
+    target_environ = envlist_to_environ(envlist, NULL);
+    envlist_free(envlist);
+
+#if defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Now that page sizes are configured in cpu_init() we can do
+     * proper page alignment for guest_base.
+     */
+    guest_base = HOST_PAGE_ALIGN(guest_base);
+
+    /*
+     * Read in mmap_min_addr kernel parameter.  This value is used
+     * When loading the ELF image to determine whether guest_base
+     * is needed.
+     *
+     * When user has explicitly set the quest base, we skip this
+     * test.
+     */
+    if (!have_guest_base) {
+        FILE *fp;
+
+        if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
+            unsigned long tmp;
+            if (fscanf(fp, "%lu", &tmp) == 1) {
+                mmap_min_addr = tmp;
+                qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
+            }
+            fclose(fp);
+        }
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+        printf("Error loading %s\n", filename);
+        _exit(1);
+    }
+
+    for (wrk = target_environ; *wrk; wrk++) {
+        free(*wrk);
+    }
+
+    free(target_environ);
+
+    if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+        qemu_log("guest_base  0x%lx\n", guest_base);
+#endif
+        log_page_dump();
+
+        qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
+        qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
+        qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_code);
+        qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_data);
+        qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
+        qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_stack);
+        qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
+        qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
+    }
+
+    target_set_brk(info->brk);
+    syscall_init();
+    signal_init();
+
+#if defined(CONFIG_USE_GUEST_BASE)
+    /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
+       generating the prologue until now so that the prologue can take
+       the real value of GUEST_BASE into account.  */
+    tcg_prologue_init(&tcg_ctx);
+#endif
+
+    /* build Task State */
+    memset(ts, 0, sizeof(TaskState));
+    init_task_state(ts);
+    ts->info = info;
+    env->opaque = ts;
+
+#if defined(TARGET_I386)
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->cpuid_features & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+#ifndef TARGET_ABI32
+    /* enable 64 bit mode if possible */
+    if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
+        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+        exit(1);
+    }
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+    env->hflags |= HF_LMA_MASK;
+#endif
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* linux register setup */
+#ifndef TARGET_ABI32
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+#else
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+#endif
+
+    /* linux interrupt setup */
+#ifndef TARGET_ABI32
+    env->idt.limit = 511;
+#else
+    env->idt.limit = 255;
+#endif
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+                                PROT_READ|PROT_WRITE,
+                                MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    idt_table = g2h(env->idt.base);
+    set_idt(0, 0);
+    set_idt(1, 0);
+    set_idt(2, 0);
+    set_idt(3, 3);
+    set_idt(4, 3);
+    set_idt(5, 0);
+    set_idt(6, 0);
+    set_idt(7, 0);
+    set_idt(8, 0);
+    set_idt(9, 0);
+    set_idt(10, 0);
+    set_idt(11, 0);
+    set_idt(12, 0);
+    set_idt(13, 0);
+    set_idt(14, 0);
+    set_idt(15, 0);
+    set_idt(16, 0);
+    set_idt(17, 0);
+    set_idt(18, 0);
+    set_idt(19, 0);
+    set_idt(0x80, 3);
+
+    /* linux segment setup */
+    {
+        uint64_t *gdt_table;
+        env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+                                    PROT_READ|PROT_WRITE,
+                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+        env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+        gdt_table = g2h(env->gdt.base);
+#ifdef TARGET_ABI32
+        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+        /* 64 bit code segment */
+        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 DESC_L_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
+        write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+    }
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
+#else
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+#endif
+#elif defined(TARGET_SPARC)
+    {
+        int i;
+        env->pc = regs->pc;
+        env->npc = regs->npc;
+        env->y = regs->y;
+        for(i = 0; i < 8; i++)
+            env->gregs[i] = regs->u_regs[i];
+        for(i = 0; i < 8; i++)
+            env->regwptr[i] = regs->u_regs[i + 8];
+    }
+#else
+#error unsupported target CPU
+#endif
+
+    if (gdbstub_port) {
+        gdbserver_start (gdbstub_port);
+        gdb_handlesig(env, 0);
+    }
+    cpu_loop(env);
+    /* never exits */
+    return 0;
+}
diff --git a/qemu-0.15.x/bsd-user/mmap.c b/qemu-0.15.x/bsd-user/mmap.c
new file mode 100644
index 0000000..207c774
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/mmap.c
@@ -0,0 +1,559 @@
+/*
+ *  mmap support for qemu
+ *
+ *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+#include "bsd-mman.h"
+
+//#define DEBUG_MMAP
+
+#if defined(CONFIG_USE_NPTL)
+pthread_mutex_t mmap_mutex;
+static int __thread mmap_lock_count;
+
+void mmap_lock(void)
+{
+    if (mmap_lock_count++ == 0) {
+        pthread_mutex_lock(&mmap_mutex);
+    }
+}
+
+void mmap_unlock(void)
+{
+    if (--mmap_lock_count == 0) {
+        pthread_mutex_unlock(&mmap_mutex);
+    }
+}
+
+/* Grab lock to make sure things are in a consistent state after fork().  */
+void mmap_fork_start(void)
+{
+    if (mmap_lock_count)
+        abort();
+    pthread_mutex_lock(&mmap_mutex);
+}
+
+void mmap_fork_end(int child)
+{
+    if (child)
+        pthread_mutex_init(&mmap_mutex, NULL);
+    else
+        pthread_mutex_unlock(&mmap_mutex);
+}
+#else
+/* We aren't threadsafe to start with, so no need to worry about locking.  */
+void mmap_lock(void)
+{
+}
+
+void mmap_unlock(void)
+{
+}
+#endif
+
+void *qemu_vmalloc(size_t size)
+{
+    void *p;
+    mmap_lock();
+    /* Use map and mark the pages as used.  */
+    p = mmap(NULL, size, PROT_READ | PROT_WRITE,
+             MAP_PRIVATE | MAP_ANON, -1, 0);
+
+    if (h2g_valid(p)) {
+        /* Allocated region overlaps guest address space.
+           This may recurse.  */
+        abi_ulong addr = h2g(p);
+        page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
+                       PAGE_RESERVED);
+    }
+
+    mmap_unlock();
+    return p;
+}
+
+void *qemu_malloc(size_t size)
+{
+    char * p;
+    size += 16;
+    p = qemu_vmalloc(size);
+    *(size_t *)p = size;
+    return p + 16;
+}
+
+/* We use map, which is always zero initialized.  */
+void * qemu_mallocz(size_t size)
+{
+    return qemu_malloc(size);
+}
+
+void qemu_free(void *ptr)
+{
+    /* FIXME: We should unmark the reserved pages here.  However this gets
+       complicated when one target page spans multiple host pages, so we
+       don't bother.  */
+    size_t *p;
+    p = (size_t *)((char *)ptr - 16);
+    munmap(p, *p);
+}
+
+void *qemu_realloc(void *ptr, size_t size)
+{
+    size_t old_size, copy;
+    void *new_ptr;
+
+    if (!ptr)
+        return qemu_malloc(size);
+    old_size = *(size_t *)((char *)ptr - 16);
+    copy = old_size < size ? old_size : size;
+    new_ptr = qemu_malloc(size);
+    memcpy(new_ptr, ptr, copy);
+    qemu_free(ptr);
+    return new_ptr;
+}
+
+/* NOTE: all the constants are the HOST ones, but addresses are target. */
+int target_mprotect(abi_ulong start, abi_ulong len, int prot)
+{
+    abi_ulong end, host_start, host_end, addr;
+    int prot1, ret;
+
+#ifdef DEBUG_MMAP
+    printf("mprotect: start=0x" TARGET_FMT_lx
+           " len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len,
+           prot & PROT_READ ? 'r' : '-',
+           prot & PROT_WRITE ? 'w' : '-',
+           prot & PROT_EXEC ? 'x' : '-');
+#endif
+
+    if ((start & ~TARGET_PAGE_MASK) != 0)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
+    if (len == 0)
+        return 0;
+
+    mmap_lock();
+    host_start = start & qemu_host_page_mask;
+    host_end = HOST_PAGE_ALIGN(end);
+    if (start > host_start) {
+        /* handle host page containing start */
+        prot1 = prot;
+        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        if (host_end == host_start + qemu_host_page_size) {
+            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+                prot1 |= page_get_flags(addr);
+            }
+            end = host_end;
+        }
+        ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
+        if (ret != 0)
+            goto error;
+        host_start += qemu_host_page_size;
+    }
+    if (end < host_end) {
+        prot1 = prot;
+        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
+                       prot1 & PAGE_BITS);
+        if (ret != 0)
+            goto error;
+        host_end -= qemu_host_page_size;
+    }
+
+    /* handle the pages in the middle */
+    if (host_start < host_end) {
+        ret = mprotect(g2h(host_start), host_end - host_start, prot);
+        if (ret != 0)
+            goto error;
+    }
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+    mmap_unlock();
+    return 0;
+error:
+    mmap_unlock();
+    return ret;
+}
+
+/* map an incomplete host page */
+static int mmap_frag(abi_ulong real_start,
+                     abi_ulong start, abi_ulong end,
+                     int prot, int flags, int fd, abi_ulong offset)
+{
+    abi_ulong real_end, addr;
+    void *host_start;
+    int prot1, prot_new;
+
+    real_end = real_start + qemu_host_page_size;
+    host_start = g2h(real_start);
+
+    /* get the protection of the target pages outside the mapping */
+    prot1 = 0;
+    for(addr = real_start; addr < real_end; addr++) {
+        if (addr < start || addr >= end)
+            prot1 |= page_get_flags(addr);
+    }
+
+    if (prot1 == 0) {
+        /* no page was there, so we allocate one */
+        void *p = mmap(host_start, qemu_host_page_size, prot,
+                       flags | MAP_ANON, -1, 0);
+        if (p == MAP_FAILED)
+            return -1;
+        prot1 = prot;
+    }
+    prot1 &= PAGE_BITS;
+
+    prot_new = prot | prot1;
+    if (!(flags & MAP_ANON)) {
+        /* msync() won't work here, so we return an error if write is
+           possible while it is a shared mapping */
+        if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
+            (prot & PROT_WRITE))
+            return -1;
+
+        /* adjust protection to be able to read */
+        if (!(prot1 & PROT_WRITE))
+            mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+
+        /* read the corresponding file data */
+        pread(fd, g2h(start), end - start, offset);
+
+        /* put final protection */
+        if (prot_new != (prot1 | PROT_WRITE))
+            mprotect(host_start, qemu_host_page_size, prot_new);
+    } else {
+        /* just update the protection */
+        if (prot_new != prot1) {
+            mprotect(host_start, qemu_host_page_size, prot_new);
+        }
+    }
+    return 0;
+}
+
+#if defined(__CYGWIN__)
+/* Cygwin doesn't have a whole lot of address space.  */
+static abi_ulong mmap_next_start = 0x18000000;
+#else
+static abi_ulong mmap_next_start = 0x40000000;
+#endif
+
+unsigned long last_brk;
+
+/* find a free memory area of size 'size'. The search starts at
+   'start'. If 'start' == 0, then a default start address is used.
+   Return -1 if error.
+*/
+/* page_init() marks pages used by the host as reserved to be sure not
+   to use them. */
+static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+{
+    abi_ulong addr, addr1, addr_start;
+    int prot;
+    unsigned long new_brk;
+
+    new_brk = (unsigned long)sbrk(0);
+    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
+        /* This is a hack to catch the host allocating memory with brk().
+           If it uses mmap then we loose.
+           FIXME: We really want to avoid the host allocating memory in
+           the first place, and maybe leave some slack to avoid switching
+           to mmap.  */
+        page_set_flags(last_brk & TARGET_PAGE_MASK,
+                       TARGET_PAGE_ALIGN(new_brk),
+                       PAGE_RESERVED);
+    }
+    last_brk = new_brk;
+
+    size = HOST_PAGE_ALIGN(size);
+    start = start & qemu_host_page_mask;
+    addr = start;
+    if (addr == 0)
+        addr = mmap_next_start;
+    addr_start = addr;
+    for(;;) {
+        prot = 0;
+        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr1);
+        }
+        if (prot == 0)
+            break;
+        addr += qemu_host_page_size;
+        /* we found nothing */
+        if (addr == addr_start)
+            return (abi_ulong)-1;
+    }
+    if (start == 0)
+        mmap_next_start = addr + size;
+    return addr;
+}
+
+/* NOTE: all the constants are the HOST ones */
+abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
+                     int flags, int fd, abi_ulong offset)
+{
+    abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
+    unsigned long host_start;
+
+    mmap_lock();
+#ifdef DEBUG_MMAP
+    {
+        printf("mmap: start=0x" TARGET_FMT_lx
+               " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=",
+               start, len,
+               prot & PROT_READ ? 'r' : '-',
+               prot & PROT_WRITE ? 'w' : '-',
+               prot & PROT_EXEC ? 'x' : '-');
+        if (flags & MAP_FIXED)
+            printf("MAP_FIXED ");
+        if (flags & MAP_ANON)
+            printf("MAP_ANON ");
+        switch(flags & TARGET_BSD_MAP_FLAGMASK) {
+        case MAP_PRIVATE:
+            printf("MAP_PRIVATE ");
+            break;
+        case MAP_SHARED:
+            printf("MAP_SHARED ");
+            break;
+        default:
+            printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK);
+            break;
+        }
+        printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
+    }
+#endif
+
+    if (offset & ~TARGET_PAGE_MASK) {
+        errno = EINVAL;
+        goto fail;
+    }
+
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        goto the_end;
+    real_start = start & qemu_host_page_mask;
+
+    if (!(flags & MAP_FIXED)) {
+        abi_ulong mmap_start;
+        void *p;
+        host_offset = offset & qemu_host_page_mask;
+        host_len = len + offset - host_offset;
+        host_len = HOST_PAGE_ALIGN(host_len);
+        mmap_start = mmap_find_vma(real_start, host_len);
+        if (mmap_start == (abi_ulong)-1) {
+            errno = ENOMEM;
+            goto fail;
+        }
+        /* Note: we prefer to control the mapping address. It is
+           especially important if qemu_host_page_size >
+           qemu_real_host_page_size */
+        p = mmap(g2h(mmap_start),
+                 host_len, prot, flags | MAP_FIXED, fd, host_offset);
+        if (p == MAP_FAILED)
+            goto fail;
+        /* update start so that it points to the file position at 'offset' */
+        host_start = (unsigned long)p;
+        if (!(flags & MAP_ANON))
+            host_start += offset - host_offset;
+        start = h2g(host_start);
+    } else {
+        int flg;
+        target_ulong addr;
+
+        if (start & ~TARGET_PAGE_MASK) {
+            errno = EINVAL;
+            goto fail;
+        }
+        end = start + len;
+        real_end = HOST_PAGE_ALIGN(end);
+
+        for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            flg = page_get_flags(addr);
+            if (flg & PAGE_RESERVED) {
+                errno = ENXIO;
+                goto fail;
+            }
+        }
+
+        /* worst case: we cannot map the file because the offset is not
+           aligned, so we read it */
+        if (!(flags & MAP_ANON) &&
+            (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
+            /* msync() won't work here, so we return an error if write is
+               possible while it is a shared mapping */
+            if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
+                (prot & PROT_WRITE)) {
+                errno = EINVAL;
+                goto fail;
+            }
+            retaddr = target_mmap(start, len, prot | PROT_WRITE,
+                                  MAP_FIXED | MAP_PRIVATE | MAP_ANON,
+                                  -1, 0);
+            if (retaddr == -1)
+                goto fail;
+            pread(fd, g2h(start), len, offset);
+            if (!(prot & PROT_WRITE)) {
+                ret = target_mprotect(start, len, prot);
+                if (ret != 0) {
+                    start = ret;
+                    goto the_end;
+                }
+            }
+            goto the_end;
+        }
+
+        /* handle the start of the mapping */
+        if (start > real_start) {
+            if (real_end == real_start + qemu_host_page_size) {
+                /* one single host page */
+                ret = mmap_frag(real_start, start, end,
+                                prot, flags, fd, offset);
+                if (ret == -1)
+                    goto fail;
+                goto the_end1;
+            }
+            ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
+                            prot, flags, fd, offset);
+            if (ret == -1)
+                goto fail;
+            real_start += qemu_host_page_size;
+        }
+        /* handle the end of the mapping */
+        if (end < real_end) {
+            ret = mmap_frag(real_end - qemu_host_page_size,
+                            real_end - qemu_host_page_size, real_end,
+                            prot, flags, fd,
+                            offset + real_end - qemu_host_page_size - start);
+            if (ret == -1)
+                goto fail;
+            real_end -= qemu_host_page_size;
+        }
+
+        /* map the middle (easier) */
+        if (real_start < real_end) {
+            void *p;
+            unsigned long offset1;
+            if (flags & MAP_ANON)
+                offset1 = 0;
+            else
+                offset1 = offset + real_start - start;
+            p = mmap(g2h(real_start), real_end - real_start,
+                     prot, flags, fd, offset1);
+            if (p == MAP_FAILED)
+                goto fail;
+        }
+    }
+ the_end1:
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+ the_end:
+#ifdef DEBUG_MMAP
+    printf("ret=0x" TARGET_FMT_lx "\n", start);
+    page_dump(stdout);
+    printf("\n");
+#endif
+    mmap_unlock();
+    return start;
+fail:
+    mmap_unlock();
+    return -1;
+}
+
+int target_munmap(abi_ulong start, abi_ulong len)
+{
+    abi_ulong end, real_start, real_end, addr;
+    int prot, ret;
+
+#ifdef DEBUG_MMAP
+    printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+#endif
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        return -EINVAL;
+    mmap_lock();
+    end = start + len;
+    real_start = start & qemu_host_page_mask;
+    real_end = HOST_PAGE_ALIGN(end);
+
+    if (start > real_start) {
+        /* handle host page containing start */
+        prot = 0;
+        for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (real_end == real_start + qemu_host_page_size) {
+            for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+                prot |= page_get_flags(addr);
+            }
+            end = real_end;
+        }
+        if (prot != 0)
+            real_start += qemu_host_page_size;
+    }
+    if (end < real_end) {
+        prot = 0;
+        for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (prot != 0)
+            real_end -= qemu_host_page_size;
+    }
+
+    ret = 0;
+    /* unmap what we can */
+    if (real_start < real_end) {
+        ret = munmap(g2h(real_start), real_end - real_start);
+    }
+
+    if (ret == 0)
+        page_set_flags(start, start + len, 0);
+    mmap_unlock();
+    return ret;
+}
+
+int target_msync(abi_ulong start, abi_ulong len, int flags)
+{
+    abi_ulong end;
+
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    if (end == start)
+        return 0;
+
+    start &= qemu_host_page_mask;
+    return msync(g2h(start), end - start, flags);
+}
diff --git a/qemu-0.15.x/bsd-user/netbsd/strace.list b/qemu-0.15.x/bsd-user/netbsd/strace.list
new file mode 100644
index 0000000..5609d70
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/netbsd/strace.list
@@ -0,0 +1,145 @@
+{ TARGET_NETBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
+{ TARGET_NETBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_acct, "acct", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_bind, "bind", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_break, "break", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
+{ TARGET_NETBSD_NR_chflags, "chflags", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_chown, "chown", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_chroot, "chroot", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_close, "close", "%s(%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_dup, "dup", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_execve, "execve", NULL, print_execve, NULL },
+{ TARGET_NETBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_NETBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_flock, "flock", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_fork, "fork", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_fsync, "fsync", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
+{ TARGET_NETBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getsid, "getsid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
+{ TARGET_NETBSD_NR_kevent, "kevent", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_kill, "kill", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lchown, "lchown", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NETBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_lseek, "lseek", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_madvise, "madvise", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_mincore, "mincore", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_minherit, "minherit", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NETBSD_NR_mlock, "mlock", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
+{ TARGET_NETBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_msgget, "msgget", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_munlock, "munlock", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_pipe, "pipe", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_poll, "poll", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_pread, "pread", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_preadv, "preadv", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_profil, "profil", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_readv, "readv", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_reboot, "reboot", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NETBSD_NR_revoke, "revoke", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_select, "select", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_semget, "semget", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_semop, "semop", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setegid, "setegid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setgid, "setgid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setregid, "setregid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setsid, "setsid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_setuid, "setuid", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_shmat, "shmat", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_shmget, "shmget", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sstk, "sstk", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_swapctl, "swapctl", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NETBSD_NR_sync, "sync", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_truncate, "truncate", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
+{ TARGET_NETBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
+{ TARGET_NETBSD_NR_unmount, "unmount", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_utimes, "utimes", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_vfork, "vfork", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_wait4, "wait4", NULL, NULL, NULL },
+{ TARGET_NETBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_NETBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },
diff --git a/qemu-0.15.x/bsd-user/netbsd/syscall_nr.h b/qemu-0.15.x/bsd-user/netbsd/syscall_nr.h
new file mode 100644
index 0000000..2e9ab53
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/netbsd/syscall_nr.h
@@ -0,0 +1,373 @@
+/* $NetBSD: syscall.h,v 1.215 2008/06/17 16:07:57 tsutsui Exp $ */
+
+/*
+ * System call numbers.
+ *
+ * created from	NetBSD: syscalls.master,v 1.204 2008/06/17 16:05:23 tsutsui Exp
+ */
+
+#define TARGET_NETBSD_NR_syscall     0
+#define TARGET_NETBSD_NR_exit        1
+#define TARGET_NETBSD_NR_fork        2
+#define TARGET_NETBSD_NR_read        3
+#define TARGET_NETBSD_NR_write       4
+#define TARGET_NETBSD_NR_open        5
+#define TARGET_NETBSD_NR_close       6
+#define TARGET_NETBSD_NR_wait4       7
+#define TARGET_NETBSD_NR_compat_43_ocreat    8
+#define TARGET_NETBSD_NR_link        9
+#define TARGET_NETBSD_NR_unlink      10
+#define TARGET_NETBSD_NR_chdir       12
+#define TARGET_NETBSD_NR_fchdir      13
+#define TARGET_NETBSD_NR_mknod       14
+#define TARGET_NETBSD_NR_chmod       15
+#define TARGET_NETBSD_NR_chown       16
+#define TARGET_NETBSD_NR_break       17
+#define TARGET_NETBSD_NR_compat_20_getfsstat 18
+#define TARGET_NETBSD_NR_compat_43_olseek    19
+#define TARGET_NETBSD_NR_getpid      20
+#define TARGET_NETBSD_NR_getpid      20
+#define TARGET_NETBSD_NR_compat_40_mount     21
+#define TARGET_NETBSD_NR_unmount     22
+#define TARGET_NETBSD_NR_setuid      23
+#define TARGET_NETBSD_NR_getuid      24
+#define TARGET_NETBSD_NR_getuid      24
+#define TARGET_NETBSD_NR_geteuid     25
+#define TARGET_NETBSD_NR_ptrace      26
+#define TARGET_NETBSD_NR_recvmsg     27
+#define TARGET_NETBSD_NR_sendmsg     28
+#define TARGET_NETBSD_NR_recvfrom    29
+#define TARGET_NETBSD_NR_accept      30
+#define TARGET_NETBSD_NR_getpeername 31
+#define TARGET_NETBSD_NR_getsockname 32
+#define TARGET_NETBSD_NR_access      33
+#define TARGET_NETBSD_NR_chflags     34
+#define TARGET_NETBSD_NR_fchflags    35
+#define TARGET_NETBSD_NR_sync        36
+#define TARGET_NETBSD_NR_kill        37
+#define TARGET_NETBSD_NR_compat_43_stat43    38
+#define TARGET_NETBSD_NR_getppid     39
+#define TARGET_NETBSD_NR_compat_43_lstat43   40
+#define TARGET_NETBSD_NR_dup 41
+#define TARGET_NETBSD_NR_pipe        42
+#define TARGET_NETBSD_NR_getegid     43
+#define TARGET_NETBSD_NR_profil      44
+#define TARGET_NETBSD_NR_ktrace      45
+#define TARGET_NETBSD_NR_compat_13_sigaction13       46
+#define TARGET_NETBSD_NR_getgid      47
+#define TARGET_NETBSD_NR_getgid      47
+#define TARGET_NETBSD_NR_compat_13_sigprocmask13     48
+#define TARGET_NETBSD_NR___getlogin  49
+#define TARGET_NETBSD_NR___setlogin  50
+#define TARGET_NETBSD_NR_acct        51
+#define TARGET_NETBSD_NR_compat_13_sigpending13      52
+#define TARGET_NETBSD_NR_compat_13_sigaltstack13     53
+#define TARGET_NETBSD_NR_ioctl       54
+#define TARGET_NETBSD_NR_compat_12_oreboot   55
+#define TARGET_NETBSD_NR_revoke      56
+#define TARGET_NETBSD_NR_symlink     57
+#define TARGET_NETBSD_NR_readlink    58
+#define TARGET_NETBSD_NR_execve      59
+#define TARGET_NETBSD_NR_umask       60
+#define TARGET_NETBSD_NR_chroot      61
+#define TARGET_NETBSD_NR_compat_43_fstat43   62
+#define TARGET_NETBSD_NR_compat_43_ogetkerninfo      63
+#define TARGET_NETBSD_NR_compat_43_ogetpagesize      64
+#define TARGET_NETBSD_NR_compat_12_msync     65
+#define TARGET_NETBSD_NR_vfork       66
+#define TARGET_NETBSD_NR_sbrk        69
+#define TARGET_NETBSD_NR_sstk        70
+#define TARGET_NETBSD_NR_compat_43_ommap     71
+#define TARGET_NETBSD_NR_vadvise     72
+#define TARGET_NETBSD_NR_munmap      73
+#define TARGET_NETBSD_NR_mprotect    74
+#define TARGET_NETBSD_NR_madvise     75
+#define TARGET_NETBSD_NR_mincore     78
+#define TARGET_NETBSD_NR_getgroups   79
+#define TARGET_NETBSD_NR_setgroups   80
+#define TARGET_NETBSD_NR_getpgrp     81
+#define TARGET_NETBSD_NR_setpgid     82
+#define TARGET_NETBSD_NR_setitimer   83
+#define TARGET_NETBSD_NR_compat_43_owait     84
+#define TARGET_NETBSD_NR_compat_12_oswapon   85
+#define TARGET_NETBSD_NR_getitimer   86
+#define TARGET_NETBSD_NR_compat_43_ogethostname      87
+#define TARGET_NETBSD_NR_compat_43_osethostname      88
+#define TARGET_NETBSD_NR_compat_43_ogetdtablesize    89
+#define TARGET_NETBSD_NR_dup2        90
+#define TARGET_NETBSD_NR_fcntl       92
+#define TARGET_NETBSD_NR_select      93
+#define TARGET_NETBSD_NR_fsync       95
+#define TARGET_NETBSD_NR_setpriority 96
+#define TARGET_NETBSD_NR_compat_30_socket    97
+#define TARGET_NETBSD_NR_connect     98
+#define TARGET_NETBSD_NR_compat_43_oaccept   99
+#define TARGET_NETBSD_NR_getpriority 100
+#define TARGET_NETBSD_NR_compat_43_osend     101
+#define TARGET_NETBSD_NR_compat_43_orecv     102
+#define TARGET_NETBSD_NR_compat_13_sigreturn13       103
+#define TARGET_NETBSD_NR_bind        104
+#define TARGET_NETBSD_NR_setsockopt  105
+#define TARGET_NETBSD_NR_listen      106
+#define TARGET_NETBSD_NR_compat_43_osigvec   108
+#define TARGET_NETBSD_NR_compat_43_osigblock 109
+#define TARGET_NETBSD_NR_compat_43_osigsetmask       110
+#define TARGET_NETBSD_NR_compat_13_sigsuspend13      111
+#define TARGET_NETBSD_NR_compat_43_osigstack 112
+#define TARGET_NETBSD_NR_compat_43_orecvmsg  113
+#define TARGET_NETBSD_NR_compat_43_osendmsg  114
+#define TARGET_NETBSD_NR_gettimeofday        116
+#define TARGET_NETBSD_NR_getrusage   117
+#define TARGET_NETBSD_NR_getsockopt  118
+#define TARGET_NETBSD_NR_readv       120
+#define TARGET_NETBSD_NR_writev      121
+#define TARGET_NETBSD_NR_settimeofday        122
+#define TARGET_NETBSD_NR_fchown      123
+#define TARGET_NETBSD_NR_fchmod      124
+#define TARGET_NETBSD_NR_compat_43_orecvfrom 125
+#define TARGET_NETBSD_NR_setreuid    126
+#define TARGET_NETBSD_NR_setregid    127
+#define TARGET_NETBSD_NR_rename      128
+#define TARGET_NETBSD_NR_compat_43_otruncate 129
+#define TARGET_NETBSD_NR_compat_43_oftruncate        130
+#define TARGET_NETBSD_NR_flock       131
+#define TARGET_NETBSD_NR_mkfifo      132
+#define TARGET_NETBSD_NR_sendto      133
+#define TARGET_NETBSD_NR_shutdown    134
+#define TARGET_NETBSD_NR_socketpair  135
+#define TARGET_NETBSD_NR_mkdir       136
+#define TARGET_NETBSD_NR_rmdir       137
+#define TARGET_NETBSD_NR_utimes      138
+#define TARGET_NETBSD_NR_adjtime     140
+#define TARGET_NETBSD_NR_compat_43_ogetpeername      141
+#define TARGET_NETBSD_NR_compat_43_ogethostid        142
+#define TARGET_NETBSD_NR_compat_43_osethostid        143
+#define TARGET_NETBSD_NR_compat_43_ogetrlimit        144
+#define TARGET_NETBSD_NR_compat_43_osetrlimit        145
+#define TARGET_NETBSD_NR_compat_43_okillpg   146
+#define TARGET_NETBSD_NR_setsid      147
+#define TARGET_NETBSD_NR_quotactl    148
+#define TARGET_NETBSD_NR_compat_43_oquota    149
+#define TARGET_NETBSD_NR_compat_43_ogetsockname      150
+#define TARGET_NETBSD_NR_nfssvc      155
+#define TARGET_NETBSD_NR_compat_43_ogetdirentries    156
+#define TARGET_NETBSD_NR_compat_20_statfs    157
+#define TARGET_NETBSD_NR_compat_20_fstatfs   158
+#define TARGET_NETBSD_NR_compat_30_getfh     161
+#define TARGET_NETBSD_NR_compat_09_ogetdomainname    162
+#define TARGET_NETBSD_NR_compat_09_osetdomainname    163
+#define TARGET_NETBSD_NR_compat_09_ouname    164
+#define TARGET_NETBSD_NR_sysarch     165
+#define TARGET_NETBSD_NR_compat_10_osemsys   169
+#define TARGET_NETBSD_NR_compat_10_omsgsys   170
+#define TARGET_NETBSD_NR_compat_10_oshmsys   171
+#define TARGET_NETBSD_NR_pread       173
+#define TARGET_NETBSD_NR_pwrite      174
+#define TARGET_NETBSD_NR_compat_30_ntp_gettime       175
+#define TARGET_NETBSD_NR_ntp_adjtime 176
+#define TARGET_NETBSD_NR_setgid      181
+#define TARGET_NETBSD_NR_setegid     182
+#define TARGET_NETBSD_NR_seteuid     183
+#define TARGET_NETBSD_NR_lfs_bmapv   184
+#define TARGET_NETBSD_NR_lfs_markv   185
+#define TARGET_NETBSD_NR_lfs_segclean        186
+#define TARGET_NETBSD_NR_lfs_segwait 187
+#define TARGET_NETBSD_NR_compat_12_stat12    188
+#define TARGET_NETBSD_NR_compat_12_fstat12   189
+#define TARGET_NETBSD_NR_compat_12_lstat12   190
+#define TARGET_NETBSD_NR_pathconf    191
+#define TARGET_NETBSD_NR_fpathconf   192
+#define TARGET_NETBSD_NR_getrlimit   194
+#define TARGET_NETBSD_NR_setrlimit   195
+#define TARGET_NETBSD_NR_compat_12_getdirentries     196
+#define TARGET_NETBSD_NR_mmap        197
+#define TARGET_NETBSD_NR___syscall   198
+#define TARGET_NETBSD_NR_lseek       199
+#define TARGET_NETBSD_NR_truncate    200
+#define TARGET_NETBSD_NR_ftruncate   201
+#define TARGET_NETBSD_NR___sysctl    202
+#define TARGET_NETBSD_NR_mlock       203
+#define TARGET_NETBSD_NR_munlock     204
+#define TARGET_NETBSD_NR_undelete    205
+#define TARGET_NETBSD_NR_futimes     206
+#define TARGET_NETBSD_NR_getpgid     207
+#define TARGET_NETBSD_NR_reboot      208
+#define TARGET_NETBSD_NR_poll        209
+#define TARGET_NETBSD_NR_compat_14___semctl  220
+#define TARGET_NETBSD_NR_semget      221
+#define TARGET_NETBSD_NR_semop       222
+#define TARGET_NETBSD_NR_semconfig   223
+#define TARGET_NETBSD_NR_compat_14_msgctl    224
+#define TARGET_NETBSD_NR_msgget      225
+#define TARGET_NETBSD_NR_msgsnd      226
+#define TARGET_NETBSD_NR_msgrcv      227
+#define TARGET_NETBSD_NR_shmat       228
+#define TARGET_NETBSD_NR_compat_14_shmctl    229
+#define TARGET_NETBSD_NR_shmdt       230
+#define TARGET_NETBSD_NR_shmget      231
+#define TARGET_NETBSD_NR_clock_gettime       232
+#define TARGET_NETBSD_NR_clock_settime       233
+#define TARGET_NETBSD_NR_clock_getres        234
+#define TARGET_NETBSD_NR_timer_create        235
+#define TARGET_NETBSD_NR_timer_delete        236
+#define TARGET_NETBSD_NR_timer_settime       237
+#define TARGET_NETBSD_NR_timer_gettime       238
+#define TARGET_NETBSD_NR_timer_getoverrun    239
+#define TARGET_NETBSD_NR_nanosleep   240
+#define TARGET_NETBSD_NR_fdatasync   241
+#define TARGET_NETBSD_NR_mlockall    242
+#define TARGET_NETBSD_NR_munlockall  243
+#define TARGET_NETBSD_NR___sigtimedwait      244
+#define TARGET_NETBSD_NR_modctl      246
+#define TARGET_NETBSD_NR__ksem_init  247
+#define TARGET_NETBSD_NR__ksem_open  248
+#define TARGET_NETBSD_NR__ksem_unlink        249
+#define TARGET_NETBSD_NR__ksem_close 250
+#define TARGET_NETBSD_NR__ksem_post  251
+#define TARGET_NETBSD_NR__ksem_wait  252
+#define TARGET_NETBSD_NR__ksem_trywait       253
+#define TARGET_NETBSD_NR__ksem_getvalue      254
+#define TARGET_NETBSD_NR__ksem_destroy       255
+#define TARGET_NETBSD_NR_mq_open     257
+#define TARGET_NETBSD_NR_mq_close    258
+#define TARGET_NETBSD_NR_mq_unlink   259
+#define TARGET_NETBSD_NR_mq_getattr  260
+#define TARGET_NETBSD_NR_mq_setattr  261
+#define TARGET_NETBSD_NR_mq_notify   262
+#define TARGET_NETBSD_NR_mq_send     263
+#define TARGET_NETBSD_NR_mq_receive  264
+#define TARGET_NETBSD_NR_mq_timedsend        265
+#define TARGET_NETBSD_NR_mq_timedreceive     266
+#define TARGET_NETBSD_NR___posix_rename      270
+#define TARGET_NETBSD_NR_swapctl     271
+#define TARGET_NETBSD_NR_compat_30_getdents  272
+#define TARGET_NETBSD_NR_minherit    273
+#define TARGET_NETBSD_NR_lchmod      274
+#define TARGET_NETBSD_NR_lchown      275
+#define TARGET_NETBSD_NR_lutimes     276
+#define TARGET_NETBSD_NR___msync13   277
+#define TARGET_NETBSD_NR_compat_30___stat13  278
+#define TARGET_NETBSD_NR_compat_30___fstat13 279
+#define TARGET_NETBSD_NR_compat_30___lstat13 280
+#define TARGET_NETBSD_NR___sigaltstack14     281
+#define TARGET_NETBSD_NR___vfork14   282
+#define TARGET_NETBSD_NR___posix_chown       283
+#define TARGET_NETBSD_NR___posix_fchown      284
+#define TARGET_NETBSD_NR___posix_lchown      285
+#define TARGET_NETBSD_NR_getsid      286
+#define TARGET_NETBSD_NR___clone     287
+#define TARGET_NETBSD_NR_fktrace     288
+#define TARGET_NETBSD_NR_preadv      289
+#define TARGET_NETBSD_NR_pwritev     290
+#define TARGET_NETBSD_NR_compat_16___sigaction14     291
+#define TARGET_NETBSD_NR___sigpending14      292
+#define TARGET_NETBSD_NR___sigprocmask14     293
+#define TARGET_NETBSD_NR___sigsuspend14      294
+#define TARGET_NETBSD_NR_compat_16___sigreturn14     295
+#define TARGET_NETBSD_NR___getcwd    296
+#define TARGET_NETBSD_NR_fchroot     297
+#define TARGET_NETBSD_NR_compat_30_fhopen    298
+#define TARGET_NETBSD_NR_compat_30_fhstat    299
+#define TARGET_NETBSD_NR_compat_20_fhstatfs  300
+#define TARGET_NETBSD_NR_____semctl13        301
+#define TARGET_NETBSD_NR___msgctl13  302
+#define TARGET_NETBSD_NR___shmctl13  303
+#define TARGET_NETBSD_NR_lchflags    304
+#define TARGET_NETBSD_NR_issetugid   305
+#define TARGET_NETBSD_NR_utrace      306
+#define TARGET_NETBSD_NR_getcontext  307
+#define TARGET_NETBSD_NR_setcontext  308
+#define TARGET_NETBSD_NR__lwp_create 309
+#define TARGET_NETBSD_NR__lwp_exit   310
+#define TARGET_NETBSD_NR__lwp_self   311
+#define TARGET_NETBSD_NR__lwp_wait   312
+#define TARGET_NETBSD_NR__lwp_suspend        313
+#define TARGET_NETBSD_NR__lwp_continue       314
+#define TARGET_NETBSD_NR__lwp_wakeup 315
+#define TARGET_NETBSD_NR__lwp_getprivate     316
+#define TARGET_NETBSD_NR__lwp_setprivate     317
+#define TARGET_NETBSD_NR__lwp_kill   318
+#define TARGET_NETBSD_NR__lwp_detach 319
+#define TARGET_NETBSD_NR__lwp_park   320
+#define TARGET_NETBSD_NR__lwp_unpark 321
+#define TARGET_NETBSD_NR__lwp_unpark_all     322
+#define TARGET_NETBSD_NR__lwp_setname        323
+#define TARGET_NETBSD_NR__lwp_getname        324
+#define TARGET_NETBSD_NR__lwp_ctl    325
+#define TARGET_NETBSD_NR_sa_register 330
+#define TARGET_NETBSD_NR_sa_stacks   331
+#define TARGET_NETBSD_NR_sa_enable   332
+#define TARGET_NETBSD_NR_sa_setconcurrency   333
+#define TARGET_NETBSD_NR_sa_yield    334
+#define TARGET_NETBSD_NR_sa_preempt  335
+#define TARGET_NETBSD_NR_sa_unblockyield     336
+#define TARGET_NETBSD_NR___sigaction_sigtramp        340
+#define TARGET_NETBSD_NR_pmc_get_info        341
+#define TARGET_NETBSD_NR_pmc_control 342
+#define TARGET_NETBSD_NR_rasctl      343
+#define TARGET_NETBSD_NR_kqueue      344
+#define TARGET_NETBSD_NR_kevent      345
+#define TARGET_NETBSD_NR__sched_setparam     346
+#define TARGET_NETBSD_NR__sched_getparam     347
+#define TARGET_NETBSD_NR__sched_setaffinity  348
+#define TARGET_NETBSD_NR__sched_getaffinity  349
+#define TARGET_NETBSD_NR_sched_yield 350
+#define TARGET_NETBSD_NR_fsync_range 354
+#define TARGET_NETBSD_NR_uuidgen     355
+#define TARGET_NETBSD_NR_getvfsstat  356
+#define TARGET_NETBSD_NR_statvfs1    357
+#define TARGET_NETBSD_NR_fstatvfs1   358
+#define TARGET_NETBSD_NR_compat_30_fhstatvfs1        359
+#define TARGET_NETBSD_NR_extattrctl  360
+#define TARGET_NETBSD_NR_extattr_set_file    361
+#define TARGET_NETBSD_NR_extattr_get_file    362
+#define TARGET_NETBSD_NR_extattr_delete_file 363
+#define TARGET_NETBSD_NR_extattr_set_fd      364
+#define TARGET_NETBSD_NR_extattr_get_fd      365
+#define TARGET_NETBSD_NR_extattr_delete_fd   366
+#define TARGET_NETBSD_NR_extattr_set_link    367
+#define TARGET_NETBSD_NR_extattr_get_link    368
+#define TARGET_NETBSD_NR_extattr_delete_link 369
+#define TARGET_NETBSD_NR_extattr_list_fd     370
+#define TARGET_NETBSD_NR_extattr_list_file   371
+#define TARGET_NETBSD_NR_extattr_list_link   372
+#define TARGET_NETBSD_NR_pselect     373
+#define TARGET_NETBSD_NR_pollts      374
+#define TARGET_NETBSD_NR_setxattr    375
+#define TARGET_NETBSD_NR_lsetxattr   376
+#define TARGET_NETBSD_NR_fsetxattr   377
+#define TARGET_NETBSD_NR_getxattr    378
+#define TARGET_NETBSD_NR_lgetxattr   379
+#define TARGET_NETBSD_NR_fgetxattr   380
+#define TARGET_NETBSD_NR_listxattr   381
+#define TARGET_NETBSD_NR_llistxattr  382
+#define TARGET_NETBSD_NR_flistxattr  383
+#define TARGET_NETBSD_NR_removexattr 384
+#define TARGET_NETBSD_NR_lremovexattr        385
+#define TARGET_NETBSD_NR_fremovexattr        386
+#define TARGET_NETBSD_NR___stat30    387
+#define TARGET_NETBSD_NR___fstat30   388
+#define TARGET_NETBSD_NR___lstat30   389
+#define TARGET_NETBSD_NR___getdents30        390
+#define TARGET_NETBSD_NR_compat_30___fhstat30        392
+#define TARGET_NETBSD_NR___ntp_gettime30     393
+#define TARGET_NETBSD_NR___socket30  394
+#define TARGET_NETBSD_NR___getfh30   395
+#define TARGET_NETBSD_NR___fhopen40  396
+#define TARGET_NETBSD_NR___fhstatvfs140      397
+#define TARGET_NETBSD_NR___fhstat40  398
+#define TARGET_NETBSD_NR_aio_cancel  399
+#define TARGET_NETBSD_NR_aio_error   400
+#define TARGET_NETBSD_NR_aio_fsync   401
+#define TARGET_NETBSD_NR_aio_read    402
+#define TARGET_NETBSD_NR_aio_return  403
+#define TARGET_NETBSD_NR_aio_suspend 404
+#define TARGET_NETBSD_NR_aio_write   405
+#define TARGET_NETBSD_NR_lio_listio  406
+#define TARGET_NETBSD_NR___mount50   410
+#define TARGET_NETBSD_NR_mremap      411
+#define TARGET_NETBSD_NR_pset_create 412
+#define TARGET_NETBSD_NR_pset_destroy        413
+#define TARGET_NETBSD_NR_pset_assign 414
+#define TARGET_NETBSD_NR__pset_bind  415
+#define TARGET_NETBSD_NR___posix_fadvise50   416
diff --git a/qemu-0.15.x/bsd-user/openbsd/strace.list b/qemu-0.15.x/bsd-user/openbsd/strace.list
new file mode 100644
index 0000000..1f0a331
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/openbsd/strace.list
@@ -0,0 +1,187 @@
+{ TARGET_OPENBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
+{ TARGET_OPENBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_acct, "acct", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_adjfreq, "adjfreq", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_bind, "bind", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_break, "break", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
+{ TARGET_OPENBSD_NR_chflags, "chflags", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_chown, "chown", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_chroot, "chroot", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_close, "close", "%s(%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_closefrom, "closefrom", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_dup, "dup", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_dup2, "dup2", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_execve, "execve", NULL, print_execve, NULL },
+{ TARGET_OPENBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
+{ TARGET_OPENBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_flock, "flock", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fork, "fork", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_fsync, "fsync", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_futimes, "futimes", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_getfh, "getfh", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getlogin, "getlogin", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getpeereid, "getpeereid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
+{ TARGET_OPENBSD_NR_getresgid, "getresgid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getresuid, "getresuid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getsid, "getsid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getthrid, "getthrid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
+{ TARGET_OPENBSD_NR_kevent, "kevent", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_kill, "kill", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lchown, "lchown", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_OPENBSD_NR_listen, "listen", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lseek, "lseek", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_madvise, "madvise", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mincore, "mincore", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_minherit, "minherit", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_OPENBSD_NR_mlock, "mlock", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
+{ TARGET_OPENBSD_NR_mount, "mount", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_mquery, "mquery", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_msgctl, "msgctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_msgget, "msgget", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_msync, "msync", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_munlock, "munlock", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_opipe, "opipe", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_osigaltstack, "osigaltstack", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_pipe, "pipe", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_poll, "poll", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_pread, "pread", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_preadv, "preadv", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_profil, "profil", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_readv, "readv", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_reboot, "reboot", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_OPENBSD_NR_revoke, "revoke", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_rfork, "rfork", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_select, "select", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_semget, "semget", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_semop, "semop", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sendto, "sendto", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setegid, "setegid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setgid, "setgid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setlogin, "setlogin", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setregid, "setregid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setresgid, "setresgid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setresuid, "setresuid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setsid, "setsid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_setuid, "setuid", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_shmat, "shmat", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_shmctl, "shmctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_shmget, "shmget", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sigaction, "sigaction", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_sigpending, "sigpending", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_socket, "socket", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sstk, "sstk", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_OPENBSD_NR_swapctl, "swapctl", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_OPENBSD_NR_sync, "sync", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_syscall, "syscall", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_threxit, "threxit", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_thrsigdivert, "thrsigdivert", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_thrsleep, "thrsleep", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_thrwakeup, "thrwakeup", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_truncate, "truncate", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
+{ TARGET_OPENBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
+{ TARGET_OPENBSD_NR_unmount, "unmount", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_utimes, "utimes", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_vfork, "vfork", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_wait4, "wait4", NULL, NULL, NULL },
+{ TARGET_OPENBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
+{ TARGET_OPENBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },
+{ TARGET_OPENBSD_NR_xfspioctl, "xfspioctl", NULL, NULL, NULL },
diff --git a/qemu-0.15.x/bsd-user/openbsd/syscall_nr.h b/qemu-0.15.x/bsd-user/openbsd/syscall_nr.h
new file mode 100644
index 0000000..dececfd
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/openbsd/syscall_nr.h
@@ -0,0 +1,225 @@
+/*      $OpenBSD: syscall.h,v 1.101 2008/03/16 19:43:41 otto Exp $      */
+
+/*
+ * System call numbers.
+ *
+ * created from;        OpenBSD: syscalls.master,v 1.90 2008/03/16 19:42:57 otto Exp
+ */
+
+#define TARGET_OPENBSD_NR_syscall     0
+#define TARGET_OPENBSD_NR_exit        1
+#define TARGET_OPENBSD_NR_fork        2
+#define TARGET_OPENBSD_NR_read        3
+#define TARGET_OPENBSD_NR_write       4
+#define TARGET_OPENBSD_NR_open        5
+#define TARGET_OPENBSD_NR_close       6
+#define TARGET_OPENBSD_NR_wait4       7
+#define TARGET_OPENBSD_NR_link        9
+#define TARGET_OPENBSD_NR_unlink      10
+#define TARGET_OPENBSD_NR_chdir       12
+#define TARGET_OPENBSD_NR_fchdir      13
+#define TARGET_OPENBSD_NR_mknod       14
+#define TARGET_OPENBSD_NR_chmod       15
+#define TARGET_OPENBSD_NR_chown       16
+#define TARGET_OPENBSD_NR_break       17
+#define TARGET_OPENBSD_NR_getpid      20
+#define TARGET_OPENBSD_NR_mount       21
+#define TARGET_OPENBSD_NR_unmount     22
+#define TARGET_OPENBSD_NR_setuid      23
+#define TARGET_OPENBSD_NR_getuid      24
+#define TARGET_OPENBSD_NR_geteuid     25
+#define TARGET_OPENBSD_NR_ptrace      26
+#define TARGET_OPENBSD_NR_recvmsg     27
+#define TARGET_OPENBSD_NR_sendmsg     28
+#define TARGET_OPENBSD_NR_recvfrom    29
+#define TARGET_OPENBSD_NR_accept      30
+#define TARGET_OPENBSD_NR_getpeername 31
+#define TARGET_OPENBSD_NR_getsockname 32
+#define TARGET_OPENBSD_NR_access      33
+#define TARGET_OPENBSD_NR_chflags     34
+#define TARGET_OPENBSD_NR_fchflags    35
+#define TARGET_OPENBSD_NR_sync        36
+#define TARGET_OPENBSD_NR_kill        37
+#define TARGET_OPENBSD_NR_getppid     39
+#define TARGET_OPENBSD_NR_dup 41
+#define TARGET_OPENBSD_NR_opipe       42
+#define TARGET_OPENBSD_NR_getegid     43
+#define TARGET_OPENBSD_NR_profil      44
+#define TARGET_OPENBSD_NR_ktrace      45
+#define TARGET_OPENBSD_NR_sigaction   46
+#define TARGET_OPENBSD_NR_getgid      47
+#define TARGET_OPENBSD_NR_sigprocmask 48
+#define TARGET_OPENBSD_NR_getlogin    49
+#define TARGET_OPENBSD_NR_setlogin    50
+#define TARGET_OPENBSD_NR_acct        51
+#define TARGET_OPENBSD_NR_sigpending  52
+#define TARGET_OPENBSD_NR_osigaltstack        53
+#define TARGET_OPENBSD_NR_ioctl       54
+#define TARGET_OPENBSD_NR_reboot      55
+#define TARGET_OPENBSD_NR_revoke      56
+#define TARGET_OPENBSD_NR_symlink     57
+#define TARGET_OPENBSD_NR_readlink    58
+#define TARGET_OPENBSD_NR_execve      59
+#define TARGET_OPENBSD_NR_umask       60
+#define TARGET_OPENBSD_NR_chroot      61
+#define TARGET_OPENBSD_NR_vfork       66
+#define TARGET_OPENBSD_NR_sbrk        69
+#define TARGET_OPENBSD_NR_sstk        70
+#define TARGET_OPENBSD_NR_munmap      73
+#define TARGET_OPENBSD_NR_mprotect    74
+#define TARGET_OPENBSD_NR_madvise     75
+#define TARGET_OPENBSD_NR_mincore     78
+#define TARGET_OPENBSD_NR_getgroups   79
+#define TARGET_OPENBSD_NR_setgroups   80
+#define TARGET_OPENBSD_NR_getpgrp     81
+#define TARGET_OPENBSD_NR_setpgid     82
+#define TARGET_OPENBSD_NR_setitimer   83
+#define TARGET_OPENBSD_NR_getitimer   86
+#define TARGET_OPENBSD_NR_dup2        90
+#define TARGET_OPENBSD_NR_fcntl       92
+#define TARGET_OPENBSD_NR_select      93
+#define TARGET_OPENBSD_NR_fsync       95
+#define TARGET_OPENBSD_NR_setpriority 96
+#define TARGET_OPENBSD_NR_socket      97
+#define TARGET_OPENBSD_NR_connect     98
+#define TARGET_OPENBSD_NR_getpriority 100
+#define TARGET_OPENBSD_NR_sigreturn   103
+#define TARGET_OPENBSD_NR_bind        104
+#define TARGET_OPENBSD_NR_setsockopt  105
+#define TARGET_OPENBSD_NR_listen      106
+#define TARGET_OPENBSD_NR_sigsuspend  111
+#define TARGET_OPENBSD_NR_gettimeofday        116
+#define TARGET_OPENBSD_NR_getrusage   117
+#define TARGET_OPENBSD_NR_getsockopt  118
+#define TARGET_OPENBSD_NR_readv       120
+#define TARGET_OPENBSD_NR_writev      121
+#define TARGET_OPENBSD_NR_settimeofday        122
+#define TARGET_OPENBSD_NR_fchown      123
+#define TARGET_OPENBSD_NR_fchmod      124
+#define TARGET_OPENBSD_NR_setreuid    126
+#define TARGET_OPENBSD_NR_setregid    127
+#define TARGET_OPENBSD_NR_rename      128
+#define TARGET_OPENBSD_NR_flock       131
+#define TARGET_OPENBSD_NR_mkfifo      132
+#define TARGET_OPENBSD_NR_sendto      133
+#define TARGET_OPENBSD_NR_shutdown    134
+#define TARGET_OPENBSD_NR_socketpair  135
+#define TARGET_OPENBSD_NR_mkdir       136
+#define TARGET_OPENBSD_NR_rmdir       137
+#define TARGET_OPENBSD_NR_utimes      138
+#define TARGET_OPENBSD_NR_adjtime     140
+#define TARGET_OPENBSD_NR_setsid      147
+#define TARGET_OPENBSD_NR_quotactl    148
+#define TARGET_OPENBSD_NR_nfssvc      155
+#define TARGET_OPENBSD_NR_getfh       161
+#define TARGET_OPENBSD_NR_sysarch     165
+#define TARGET_OPENBSD_NR_pread       173
+#define TARGET_OPENBSD_NR_pwrite      174
+#define TARGET_OPENBSD_NR_setgid      181
+#define TARGET_OPENBSD_NR_setegid     182
+#define TARGET_OPENBSD_NR_seteuid     183
+#define TARGET_OPENBSD_NR_lfs_bmapv   184
+#define TARGET_OPENBSD_NR_lfs_markv   185
+#define TARGET_OPENBSD_NR_lfs_segclean        186
+#define TARGET_OPENBSD_NR_lfs_segwait 187
+#define TARGET_OPENBSD_NR_pathconf    191
+#define TARGET_OPENBSD_NR_fpathconf   192
+#define TARGET_OPENBSD_NR_swapctl     193
+#define TARGET_OPENBSD_NR_getrlimit   194
+#define TARGET_OPENBSD_NR_setrlimit   195
+#define TARGET_OPENBSD_NR_getdirentries       196
+#define TARGET_OPENBSD_NR_mmap        197
+#define TARGET_OPENBSD_NR___syscall   198
+#define TARGET_OPENBSD_NR_lseek       199
+#define TARGET_OPENBSD_NR_truncate    200
+#define TARGET_OPENBSD_NR_ftruncate   201
+#define TARGET_OPENBSD_NR___sysctl    202
+#define TARGET_OPENBSD_NR_mlock       203
+#define TARGET_OPENBSD_NR_munlock     204
+#define TARGET_OPENBSD_NR_futimes     206
+#define TARGET_OPENBSD_NR_getpgid     207
+#define TARGET_OPENBSD_NR_xfspioctl   208
+#define TARGET_OPENBSD_NR_semget      221
+#define TARGET_OPENBSD_NR_msgget      225
+#define TARGET_OPENBSD_NR_msgsnd      226
+#define TARGET_OPENBSD_NR_msgrcv      227
+#define TARGET_OPENBSD_NR_shmat       228
+#define TARGET_OPENBSD_NR_shmdt       230
+#define TARGET_OPENBSD_NR_clock_gettime       232
+#define TARGET_OPENBSD_NR_clock_settime       233
+#define TARGET_OPENBSD_NR_clock_getres        234
+#define TARGET_OPENBSD_NR_nanosleep   240
+#define TARGET_OPENBSD_NR_minherit    250
+#define TARGET_OPENBSD_NR_rfork       251
+#define TARGET_OPENBSD_NR_poll        252
+#define TARGET_OPENBSD_NR_issetugid   253
+#define TARGET_OPENBSD_NR_lchown      254
+#define TARGET_OPENBSD_NR_getsid      255
+#define TARGET_OPENBSD_NR_msync       256
+#define TARGET_OPENBSD_NR_pipe        263
+#define TARGET_OPENBSD_NR_fhopen      264
+#define TARGET_OPENBSD_NR_preadv      267
+#define TARGET_OPENBSD_NR_pwritev     268
+#define TARGET_OPENBSD_NR_kqueue      269
+#define TARGET_OPENBSD_NR_kevent      270
+#define TARGET_OPENBSD_NR_mlockall    271
+#define TARGET_OPENBSD_NR_munlockall  272
+#define TARGET_OPENBSD_NR_getpeereid  273
+#define TARGET_OPENBSD_NR_getresuid   281
+#define TARGET_OPENBSD_NR_setresuid   282
+#define TARGET_OPENBSD_NR_getresgid   283
+#define TARGET_OPENBSD_NR_setresgid   284
+#define TARGET_OPENBSD_NR_mquery      286
+#define TARGET_OPENBSD_NR_closefrom   287
+#define TARGET_OPENBSD_NR_sigaltstack 288
+#define TARGET_OPENBSD_NR_shmget      289
+#define TARGET_OPENBSD_NR_semop       290
+#define TARGET_OPENBSD_NR_stat        291
+#define TARGET_OPENBSD_NR_fstat       292
+#define TARGET_OPENBSD_NR_lstat       293
+#define TARGET_OPENBSD_NR_fhstat      294
+#define TARGET_OPENBSD_NR___semctl    295
+#define TARGET_OPENBSD_NR_shmctl      296
+#define TARGET_OPENBSD_NR_msgctl      297
+#define TARGET_OPENBSD_NR_sched_yield 298
+#define TARGET_OPENBSD_NR_getthrid    299
+#define TARGET_OPENBSD_NR_thrsleep    300
+#define TARGET_OPENBSD_NR_thrwakeup   301
+#define TARGET_OPENBSD_NR_threxit     302
+#define TARGET_OPENBSD_NR_thrsigdivert        303
+#define TARGET_OPENBSD_NR___getcwd    304
+#define TARGET_OPENBSD_NR_adjfreq     305
+#define TARGET_OPENBSD_NR_getfsstat   306
+#define TARGET_OPENBSD_NR_statfs      307
+#define TARGET_OPENBSD_NR_fstatfs     308
+#define TARGET_OPENBSD_NR_fhstatfs    309
+
+/* syscall flags from machine/trap.h */
+
+/*      $OpenBSD: trap.h,v 1.4 2008/07/04 22:04:37 kettenis Exp $       */
+/*      $NetBSD: trap.h,v 1.4 1999/06/07 05:28:04 eeh Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 Eduardo Horvath
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``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  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.
+ *
+ */
+#define TARGET_OPENBSD_SYSCALL_G2RFLAG 0x400   /* on success, return to %g2 rather than npc */
+#define TARGET_OPENBSD_SYSCALL_G7RFLAG 0x800   /* use %g7 as above (deprecated) */
diff --git a/qemu-0.15.x/bsd-user/qemu-types.h b/qemu-0.15.x/bsd-user/qemu-types.h
new file mode 100644
index 0000000..1adda9f
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/qemu-types.h
@@ -0,0 +1,24 @@
+#ifndef QEMU_TYPES_H
+#define QEMU_TYPES_H
+#include "cpu.h"
+
+#ifdef TARGET_ABI32
+typedef uint32_t abi_ulong;
+typedef int32_t abi_long;
+#define TARGET_ABI_FMT_lx "%08x"
+#define TARGET_ABI_FMT_ld "%d"
+#define TARGET_ABI_FMT_lu "%u"
+#define TARGET_ABI_BITS 32
+#else
+typedef target_ulong abi_ulong;
+typedef target_long abi_long;
+#define TARGET_ABI_FMT_lx TARGET_FMT_lx
+#define TARGET_ABI_FMT_ld TARGET_FMT_ld
+#define TARGET_ABI_FMT_lu TARGET_FMT_lu
+#define TARGET_ABI_BITS TARGET_LONG_BITS
+/* for consistency, define ABI32 too */
+#if TARGET_ABI_BITS == 32
+#define TARGET_ABI32 1
+#endif
+#endif
+#endif
diff --git a/qemu-0.15.x/bsd-user/qemu.h b/qemu-0.15.x/bsd-user/qemu.h
new file mode 100644
index 0000000..1ba2d08
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/qemu.h
@@ -0,0 +1,394 @@
+#ifndef QEMU_H
+#define QEMU_H
+
+#include <signal.h>
+#include <string.h>
+
+#include "cpu.h"
+
+#undef DEBUG_REMAP
+#ifdef DEBUG_REMAP
+#include <stdlib.h>
+#endif /* DEBUG_REMAP */
+
+#include "qemu-types.h"
+
+enum BSDType {
+    target_freebsd,
+    target_netbsd,
+    target_openbsd,
+};
+extern enum BSDType bsd_type;
+
+#include "syscall_defs.h"
+#include "syscall.h"
+#include "target_signal.h"
+#include "gdbstub.h"
+
+#if defined(CONFIG_USE_NPTL)
+#define THREAD __thread
+#else
+#define THREAD
+#endif
+
+/* This struct is used to hold certain information about the image.
+ * Basically, it replicates in user space what would be certain
+ * task_struct fields in the kernel
+ */
+struct image_info {
+    abi_ulong load_addr;
+    abi_ulong start_code;
+    abi_ulong end_code;
+    abi_ulong start_data;
+    abi_ulong end_data;
+    abi_ulong start_brk;
+    abi_ulong brk;
+    abi_ulong start_mmap;
+    abi_ulong mmap;
+    abi_ulong rss;
+    abi_ulong start_stack;
+    abi_ulong entry;
+    abi_ulong code_offset;
+    abi_ulong data_offset;
+    int       personality;
+};
+
+#define MAX_SIGQUEUE_SIZE 1024
+
+struct sigqueue {
+    struct sigqueue *next;
+    //target_siginfo_t info;
+};
+
+struct emulated_sigtable {
+    int pending; /* true if signal is pending */
+    struct sigqueue *first;
+    struct sigqueue info; /* in order to always have memory for the
+                             first signal, we put it here */
+};
+
+/* NOTE: we force a big alignment so that the stack stored after is
+   aligned too */
+typedef struct TaskState {
+    struct TaskState *next;
+    int used; /* non zero if used */
+    struct image_info *info;
+
+    struct emulated_sigtable sigtab[TARGET_NSIG];
+    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct sigqueue *first_free; /* first free siginfo queue entry */
+    int signal_pending; /* non zero if a signal may be pending */
+
+    uint8_t stack[0];
+} __attribute__((aligned(16))) TaskState;
+
+void init_task_state(TaskState *ts);
+extern const char *qemu_uname_release;
+#if defined(CONFIG_USE_GUEST_BASE)
+extern unsigned long mmap_min_addr;
+#endif
+
+/* ??? See if we can avoid exposing so much of the loader internals.  */
+/*
+ * MAX_ARG_PAGES defines the number of pages allocated for arguments
+ * and envelope for the new program. 32 should suffice, this gives
+ * a maximum env+arg of 128kB w/4KB pages!
+ */
+#define MAX_ARG_PAGES 32
+
+/*
+ * This structure is used to hold the arguments that are
+ * used when loading binaries.
+ */
+struct linux_binprm {
+        char buf[128];
+        void *page[MAX_ARG_PAGES];
+        abi_ulong p;
+        int fd;
+        int e_uid, e_gid;
+        int argc, envc;
+        char **argv;
+        char **envp;
+        char * filename;        /* Name of binary */
+};
+
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
+abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
+                              abi_ulong stringp, int push_ptr);
+int loader_exec(const char * filename, char ** argv, char ** envp,
+             struct target_pt_regs * regs, struct image_info *infop);
+
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+
+abi_long memcpy_to_target(abi_ulong dest, const void *src,
+                          unsigned long len);
+void target_set_brk(abi_ulong new_brk);
+abi_long do_brk(abi_ulong new_brk);
+void syscall_init(void);
+abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+                            abi_long arg2, abi_long arg3, abi_long arg4,
+                            abi_long arg5, abi_long arg6, abi_long arg7,
+                            abi_long arg8);
+abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
+                           abi_long arg2, abi_long arg3, abi_long arg4,
+                           abi_long arg5, abi_long arg6);
+abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
+                            abi_long arg2, abi_long arg3, abi_long arg4,
+                            abi_long arg5, abi_long arg6);
+void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+extern THREAD CPUState *thread_env;
+void cpu_loop(CPUState *env);
+char *target_strerror(int err);
+int get_osversion(void);
+void fork_start(void);
+void fork_end(int child);
+
+#include "qemu-log.h"
+
+/* strace.c */
+void
+print_freebsd_syscall(int num,
+                      abi_long arg1, abi_long arg2, abi_long arg3,
+                      abi_long arg4, abi_long arg5, abi_long arg6);
+void print_freebsd_syscall_ret(int num, abi_long ret);
+void
+print_netbsd_syscall(int num,
+                     abi_long arg1, abi_long arg2, abi_long arg3,
+                     abi_long arg4, abi_long arg5, abi_long arg6);
+void print_netbsd_syscall_ret(int num, abi_long ret);
+void
+print_openbsd_syscall(int num,
+                      abi_long arg1, abi_long arg2, abi_long arg3,
+                      abi_long arg4, abi_long arg5, abi_long arg6);
+void print_openbsd_syscall_ret(int num, abi_long ret);
+extern int do_strace;
+
+/* signal.c */
+void process_pending_signals(CPUState *cpu_env);
+void signal_init(void);
+//int queue_signal(CPUState *env, int sig, target_siginfo_t *info);
+//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+long do_sigreturn(CPUState *env);
+long do_rt_sigreturn(CPUState *env);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+
+/* mmap.c */
+int target_mprotect(abi_ulong start, abi_ulong len, int prot);
+abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
+                     int flags, int fd, abi_ulong offset);
+int target_munmap(abi_ulong start, abi_ulong len);
+abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
+                       abi_ulong new_size, unsigned long flags,
+                       abi_ulong new_addr);
+int target_msync(abi_ulong start, abi_ulong len, int flags);
+extern unsigned long last_brk;
+void mmap_lock(void);
+void mmap_unlock(void);
+void cpu_list_lock(void);
+void cpu_list_unlock(void);
+#if defined(CONFIG_USE_NPTL)
+void mmap_fork_start(void);
+void mmap_fork_end(int child);
+#endif
+
+/* main.c */
+extern unsigned long x86_stack_size;
+
+/* user access */
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1 /* implies read access */
+
+static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
+{
+    return page_check_range((target_ulong)addr, size,
+                            (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
+}
+
+/* NOTE __get_user and __put_user use host pointers and don't check access. */
+/* These are usually used to access struct data members once the
+ * struct has been locked - usually with lock_user_struct().
+ */
+#define __put_user(x, hptr)\
+({\
+    int size = sizeof(*hptr);\
+    switch(size) {\
+    case 1:\
+        *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\
+        break;\
+    case 2:\
+        *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\
+        break;\
+    case 4:\
+        *(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\
+        break;\
+    case 8:\
+        *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\
+        break;\
+    default:\
+        abort();\
+    }\
+    0;\
+})
+
+#define __get_user(x, hptr) \
+({\
+    int size = sizeof(*hptr);\
+    switch(size) {\
+    case 1:\
+        x = (typeof(*hptr))*(uint8_t *)(hptr);\
+        break;\
+    case 2:\
+        x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\
+        break;\
+    case 4:\
+        x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\
+        break;\
+    case 8:\
+        x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\
+        break;\
+    default:\
+        /* avoid warning */\
+        x = 0;\
+        abort();\
+    }\
+    0;\
+})
+
+/* put_user()/get_user() take a guest address and check access */
+/* These are usually used to access an atomic data type, such as an int,
+ * that has been passed by address.  These internally perform locking
+ * and unlocking on the data type.
+ */
+#define put_user(x, gaddr, target_type)                                 \
+({                                                                      \
+    abi_ulong __gaddr = (gaddr);                                        \
+    target_type *__hptr;                                                \
+    abi_long __ret;                                                     \
+    if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \
+        __ret = __put_user((x), __hptr);                                \
+        unlock_user(__hptr, __gaddr, sizeof(target_type));              \
+    } else                                                              \
+        __ret = -TARGET_EFAULT;                                         \
+    __ret;                                                              \
+})
+
+#define get_user(x, gaddr, target_type)                                 \
+({                                                                      \
+    abi_ulong __gaddr = (gaddr);                                        \
+    target_type *__hptr;                                                \
+    abi_long __ret;                                                     \
+    if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \
+        __ret = __get_user((x), __hptr);                                \
+        unlock_user(__hptr, __gaddr, 0);                                \
+    } else {                                                            \
+        /* avoid warning */                                             \
+        (x) = 0;                                                        \
+        __ret = -TARGET_EFAULT;                                         \
+    }                                                                   \
+    __ret;                                                              \
+})
+
+#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong)
+#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long)
+#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t)
+#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t)
+#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t)
+#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t)
+#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t)
+#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t)
+#define put_user_u8(x, gaddr)  put_user((x), (gaddr), uint8_t)
+#define put_user_s8(x, gaddr)  put_user((x), (gaddr), int8_t)
+
+#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong)
+#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long)
+#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t)
+#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t)
+#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t)
+#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t)
+#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t)
+#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t)
+#define get_user_u8(x, gaddr)  get_user((x), (gaddr), uint8_t)
+#define get_user_s8(x, gaddr)  get_user((x), (gaddr), int8_t)
+
+/* copy_from_user() and copy_to_user() are usually used to copy data
+ * buffers between the target and host.  These internally perform
+ * locking/unlocking of the memory.
+ */
+abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
+abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
+
+/* Functions for accessing guest memory.  The tget and tput functions
+   read/write single values, byteswapping as necessary.  The lock_user
+   gets a pointer to a contiguous area of guest memory, but does not perform
+   and byteswapping.  lock_user may return either a pointer to the guest
+   memory, or a temporary buffer.  */
+
+/* Lock an area of guest memory into the host.  If copy is true then the
+   host area will have the same contents as the guest.  */
+static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
+{
+    if (!access_ok(type, guest_addr, len))
+        return NULL;
+#ifdef DEBUG_REMAP
+    {
+        void *addr;
+        addr = malloc(len);
+        if (copy)
+            memcpy(addr, g2h(guest_addr), len);
+        else
+            memset(addr, 0, len);
+        return addr;
+    }
+#else
+    return g2h(guest_addr);
+#endif
+}
+
+/* Unlock an area of guest memory.  The first LEN bytes must be
+   flushed back to guest memory. host_ptr = NULL is explicitly
+   allowed and does nothing. */
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
+                               long len)
+{
+
+#ifdef DEBUG_REMAP
+    if (!host_ptr)
+        return;
+    if (host_ptr == g2h(guest_addr))
+        return;
+    if (len > 0)
+        memcpy(g2h(guest_addr), host_ptr, len);
+    free(host_ptr);
+#endif
+}
+
+/* Return the length of a string in target memory or -TARGET_EFAULT if
+   access error. */
+abi_long target_strlen(abi_ulong gaddr);
+
+/* Like lock_user but for null terminated strings.  */
+static inline void *lock_user_string(abi_ulong guest_addr)
+{
+    abi_long len;
+    len = target_strlen(guest_addr);
+    if (len < 0)
+        return NULL;
+    return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
+}
+
+/* Helper macros for locking/ulocking a target struct.  */
+#define lock_user_struct(type, host_ptr, guest_addr, copy)      \
+    (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
+#define unlock_user_struct(host_ptr, guest_addr, copy)          \
+    unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
+
+#if defined(CONFIG_USE_NPTL)
+#include <pthread.h>
+#endif
+
+#endif /* QEMU_H */
diff --git a/qemu-0.15.x/bsd-user/signal.c b/qemu-0.15.x/bsd-user/signal.c
new file mode 100644
index 0000000..40313c8
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/signal.c
@@ -0,0 +1,38 @@
+/*
+ *  Emulation of BSD signals
+ *
+ *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "qemu.h"
+#include "target_signal.h"
+
+//#define DEBUG_SIGNAL
+
+void signal_init(void)
+{
+}
+
+void process_pending_signals(CPUState *cpu_env)
+{
+}
diff --git a/qemu-0.15.x/bsd-user/sparc/syscall.h b/qemu-0.15.x/bsd-user/sparc/syscall.h
new file mode 100644
index 0000000..5a9bb7e
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/sparc/syscall.h
@@ -0,0 +1,9 @@
+struct target_pt_regs {
+	abi_ulong psr;
+	abi_ulong pc;
+	abi_ulong npc;
+	abi_ulong y;
+	abi_ulong u_regs[16];
+};
+
+#define UNAME_MACHINE "sun4"
diff --git a/qemu-0.15.x/bsd-user/sparc/target_signal.h b/qemu-0.15.x/bsd-user/sparc/target_signal.h
new file mode 100644
index 0000000..5b2abba
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/sparc/target_signal.h
@@ -0,0 +1,27 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/bsd-user/sparc64/syscall.h b/qemu-0.15.x/bsd-user/sparc64/syscall.h
new file mode 100644
index 0000000..81a816d
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/sparc64/syscall.h
@@ -0,0 +1,10 @@
+struct target_pt_regs {
+	abi_ulong u_regs[16];
+	abi_ulong tstate;
+	abi_ulong pc;
+	abi_ulong npc;
+	abi_ulong y;
+	abi_ulong fprs;
+};
+
+#define UNAME_MACHINE "sun4u"
diff --git a/qemu-0.15.x/bsd-user/sparc64/target_signal.h b/qemu-0.15.x/bsd-user/sparc64/target_signal.h
new file mode 100644
index 0000000..5b2abba
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/sparc64/target_signal.h
@@ -0,0 +1,27 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/bsd-user/strace.c b/qemu-0.15.x/bsd-user/strace.c
new file mode 100644
index 0000000..d73bbca
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/strace.c
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include "qemu.h"
+
+int do_strace=0;
+
+struct syscallname {
+    int nr;
+    const char *name;
+    const char *format;
+    void (*call)(const struct syscallname *,
+                 abi_long, abi_long, abi_long,
+                 abi_long, abi_long, abi_long);
+    void (*result)(const struct syscallname *, abi_long);
+};
+
+/*
+ * Utility functions
+ */
+
+static void
+print_execve(const struct syscallname *name,
+             abi_long arg1, abi_long arg2, abi_long arg3,
+             abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_ulong arg_ptr_addr;
+    char *s;
+
+    if (!(s = lock_user_string(arg1)))
+        return;
+    gemu_log("%s(\"%s\",{", name->name, s);
+    unlock_user(s, arg1, 0);
+
+    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
+        abi_ulong *arg_ptr, arg_addr;
+
+        arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
+        if (!arg_ptr)
+            return;
+        arg_addr = tswapl(*arg_ptr);
+        unlock_user(arg_ptr, arg_ptr_addr, 0);
+        if (!arg_addr)
+            break;
+        if ((s = lock_user_string(arg_addr))) {
+            gemu_log("\"%s\",", s);
+            unlock_user(s, arg_addr, 0);
+        }
+    }
+
+    gemu_log("NULL})");
+}
+
+/*
+ * Variants for the return value output function
+ */
+
+static void
+print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
+{
+if( ret == -1 ) {
+        gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
+    } else {
+        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
+    }
+}
+
+#if 0 /* currently unused */
+static void
+print_syscall_ret_raw(struct syscallname *name, abi_long ret)
+{
+        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
+}
+#endif
+
+/*
+ * An array of all of the syscalls we know about
+ */
+
+static const struct syscallname freebsd_scnames[] = {
+#include "freebsd/strace.list"
+};
+static const struct syscallname netbsd_scnames[] = {
+#include "netbsd/strace.list"
+};
+static const struct syscallname openbsd_scnames[] = {
+#include "openbsd/strace.list"
+};
+
+static void
+print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
+              abi_long arg1, abi_long arg2, abi_long arg3,
+              abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    unsigned int i;
+    const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
+        TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
+        TARGET_ABI_FMT_ld ")";
+
+    gemu_log("%d ", getpid() );
+
+    for (i = 0; i < nscnames; i++)
+        if (scnames[i].nr == num) {
+            if (scnames[i].call != NULL) {
+                scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
+                                arg6);
+            } else {
+                /* XXX: this format system is broken because it uses
+                   host types and host pointers for strings */
+                if (scnames[i].format != NULL)
+                    format = scnames[i].format;
+                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4,
+                         arg5, arg6);
+            }
+            return;
+        }
+    gemu_log("Unknown syscall %d\n", num);
+}
+
+static void
+print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
+                  unsigned int nscnames)
+{
+    unsigned int i;
+
+    for (i = 0; i < nscnames; i++)
+        if (scnames[i].nr == num) {
+            if (scnames[i].result != NULL) {
+                scnames[i].result(&scnames[i], ret);
+            } else {
+                if( ret < 0 ) {
+                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
+                             strerror(-ret));
+                } else {
+                    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
+                }
+            }
+            break;
+        }
+}
+
+/*
+ * The public interface to this module.
+ */
+void
+print_freebsd_syscall(int num,
+                      abi_long arg1, abi_long arg2, abi_long arg3,
+                      abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
+                  arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+void
+print_freebsd_syscall_ret(int num, abi_long ret)
+{
+    print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
+}
+
+void
+print_netbsd_syscall(int num,
+                      abi_long arg1, abi_long arg2, abi_long arg3,
+                      abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
+                  arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+void
+print_netbsd_syscall_ret(int num, abi_long ret)
+{
+    print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
+}
+
+void
+print_openbsd_syscall(int num,
+                      abi_long arg1, abi_long arg2, abi_long arg3,
+                      abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames),
+                  arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+void
+print_openbsd_syscall_ret(int num, abi_long ret)
+{
+    print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
+}
diff --git a/qemu-0.15.x/bsd-user/syscall.c b/qemu-0.15.x/bsd-user/syscall.c
new file mode 100644
index 0000000..d4d039a
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/syscall.c
@@ -0,0 +1,559 @@
+/*
+ *  BSD syscalls
+ *
+ *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <utime.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+//#define DEBUG
+
+static abi_ulong target_brk;
+static abi_ulong target_original_brk;
+
+static inline abi_long get_errno(abi_long ret)
+{
+    if (ret == -1)
+        /* XXX need to translate host -> target errnos here */
+        return -(errno);
+    else
+        return ret;
+}
+
+#define target_to_host_bitmask(x, tbl) (x)
+
+static inline int is_error(abi_long ret)
+{
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
+}
+
+void target_set_brk(abi_ulong new_brk)
+{
+    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
+}
+
+/* do_obreak() must return target errnos. */
+static abi_long do_obreak(abi_ulong new_brk)
+{
+    abi_ulong brk_page;
+    abi_long mapped_addr;
+    int new_alloc_size;
+
+    if (!new_brk)
+        return 0;
+    if (new_brk < target_original_brk)
+        return -TARGET_EINVAL;
+
+    brk_page = HOST_PAGE_ALIGN(target_brk);
+
+    /* If the new brk is less than this, set it and we're done... */
+    if (new_brk < brk_page) {
+        target_brk = new_brk;
+        return 0;
+    }
+
+    /* We need to allocate more memory after the brk... */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                                        PROT_READ|PROT_WRITE,
+                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
+
+    if (!is_error(mapped_addr))
+        target_brk = new_brk;
+    else
+        return mapped_addr;
+
+    return 0;
+}
+
+#if defined(TARGET_I386)
+static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch(op) {
+#ifdef TARGET_ABI32
+    case TARGET_FREEBSD_I386_SET_GSBASE:
+    case TARGET_FREEBSD_I386_SET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
+#else
+    case TARGET_FREEBSD_AMD64_SET_GSBASE:
+    case TARGET_FREEBSD_AMD64_SET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
+#endif
+            idx = R_GS;
+        else
+            idx = R_FS;
+        if (get_user(val, parms, abi_ulong))
+            return -TARGET_EFAULT;
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+#ifdef TARGET_ABI32
+    case TARGET_FREEBSD_I386_GET_GSBASE:
+    case TARGET_FREEBSD_I386_GET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
+#else
+    case TARGET_FREEBSD_AMD64_GET_GSBASE:
+    case TARGET_FREEBSD_AMD64_GET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
+#endif
+            idx = R_GS;
+        else
+            idx = R_FS;
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong))
+            return -TARGET_EFAULT;
+        break;
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+#endif
+
+#ifdef TARGET_SPARC
+static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
+{
+    /* XXX handle
+     * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
+     * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
+     */
+    return -TARGET_EINVAL;
+}
+#endif
+
+#ifdef __FreeBSD__
+/*
+ * XXX this uses the undocumented oidfmt interface to find the kind of
+ * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
+ * (this is mostly copied from src/sbin/sysctl/sysctl.c)
+ */
+static int
+oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+{
+    int qoid[CTL_MAXNAME+2];
+    uint8_t buf[BUFSIZ];
+    int i;
+    size_t j;
+
+    qoid[0] = 0;
+    qoid[1] = 4;
+    memcpy(qoid + 2, oid, len * sizeof(int));
+
+    j = sizeof(buf);
+    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+    if (i)
+        return i;
+
+    if (kind)
+        *kind = *(uint32_t *)buf;
+
+    if (fmt)
+        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+    return (0);
+}
+
+/*
+ * try and convert sysctl return data for the target.
+ * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
+ */
+static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
+{
+    switch (kind & CTLTYPE) {
+    case CTLTYPE_INT:
+    case CTLTYPE_UINT:
+        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
+        break;
+#ifdef TARGET_ABI32
+    case CTLTYPE_LONG:
+    case CTLTYPE_ULONG:
+        *(uint32_t *)holdp = tswap32(*(long *)holdp);
+        break;
+#else
+    case CTLTYPE_LONG:
+        *(uint64_t *)holdp = tswap64(*(long *)holdp);
+    case CTLTYPE_ULONG:
+        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
+        break;
+#endif
+    case CTLTYPE_QUAD:
+        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
+        break;
+    case CTLTYPE_STRING:
+        break;
+    default:
+        /* XXX unhandled */
+        return -1;
+    }
+    return 0;
+}
+
+/* XXX this needs to be emulated on non-FreeBSD hosts... */
+static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
+                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+    abi_long ret;
+    void *hnamep, *holdp, *hnewp = NULL;
+    size_t holdlen;
+    abi_ulong oldlen = 0;
+    int32_t *snamep = qemu_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    uint32_t kind = 0;
+
+    if (oldlenp)
+        get_user_ual(oldlen, oldlenp);
+    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
+        return -TARGET_EFAULT;
+    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
+        return -TARGET_EFAULT;
+    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
+        return -TARGET_EFAULT;
+    holdlen = oldlen;
+    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
+       *q++ = tswap32(*p);
+    oidfmt(snamep, namelen, NULL, &kind);
+    /* XXX swap hnewp */
+    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
+    if (!ret)
+        sysctl_oldcvt(holdp, holdlen, kind);
+    put_user_ual(holdlen, oldlenp);
+    unlock_user(hnamep, namep, 0);
+    unlock_user(holdp, oldp, holdlen);
+    if (hnewp)
+        unlock_user(hnewp, newp, 0);
+    qemu_free(snamep);
+    return ret;
+}
+#endif
+
+/* FIXME
+ * lock_iovec()/unlock_iovec() have a return code of 0 for success where
+ * other lock functions have a return code of 0 for failure.
+ */
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+                           int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        base = tswapl(target_vec[i].iov_base);
+        vec[i].iov_len = tswapl(target_vec[i].iov_len);
+        if (vec[i].iov_len != 0) {
+            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
+            /* Don't check lock_user return value. We must call writev even
+               if a element has invalid base address. */
+        } else {
+            /* zero length pointer is ignored */
+            vec[i].iov_base = NULL;
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+    return 0;
+}
+
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+                             int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        if (target_vec[i].iov_base) {
+            base = tswapl(target_vec[i].iov_base);
+            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+
+    return 0;
+}
+
+/* do_syscall() should always have a single exit point at the end so
+   that actions, such as logging of syscall results, can be performed.
+   All errnos that do_syscall() returns must be -TARGET_<errcode>. */
+abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+                            abi_long arg2, abi_long arg3, abi_long arg4,
+                            abi_long arg5, abi_long arg6, abi_long arg7,
+                            abi_long arg8)
+{
+    abi_long ret;
+    void *p;
+
+#ifdef DEBUG
+    gemu_log("freebsd syscall %d\n", num);
+#endif
+    if(do_strace)
+        print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+
+    switch(num) {
+    case TARGET_FREEBSD_NR_exit:
+#ifdef TARGET_GPROF
+        _mcleanup();
+#endif
+        gdb_exit(cpu_env, arg1);
+        /* XXX: should free thread stack and CPU env */
+        _exit(arg1);
+        ret = 0; /* avoid warning */
+        break;
+    case TARGET_FREEBSD_NR_read:
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(read(arg1, p, arg3));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_FREEBSD_NR_write:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(write(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+    case TARGET_FREEBSD_NR_writev:
+        {
+            int count = arg3;
+            struct iovec *vec;
+
+            vec = alloca(count * sizeof(struct iovec));
+            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+                goto efault;
+            ret = get_errno(writev(arg1, vec, count));
+            unlock_iovec(vec, arg2, count, 0);
+        }
+        break;
+    case TARGET_FREEBSD_NR_open:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(open(path(p),
+                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                             arg3));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_FREEBSD_NR_mmap:
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
+                                    arg5,
+                                    arg6));
+        break;
+    case TARGET_FREEBSD_NR_mprotect:
+        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        break;
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
+        break;
+#ifdef __FreeBSD__
+    case TARGET_FREEBSD_NR___sysctl:
+        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+#endif
+    case TARGET_FREEBSD_NR_sysarch:
+        ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
+        break;
+    case TARGET_FREEBSD_NR_syscall:
+    case TARGET_FREEBSD_NR___syscall:
+        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
+        break;
+    default:
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+        break;
+    }
+ fail:
+#ifdef DEBUG
+    gemu_log(" = %ld\n", ret);
+#endif
+    if (do_strace)
+        print_freebsd_syscall_ret(num, ret);
+    return ret;
+ efault:
+    ret = -TARGET_EFAULT;
+    goto fail;
+}
+
+abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
+                           abi_long arg2, abi_long arg3, abi_long arg4,
+                           abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+#ifdef DEBUG
+    gemu_log("netbsd syscall %d\n", num);
+#endif
+    if(do_strace)
+        print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+
+    switch(num) {
+    case TARGET_NETBSD_NR_exit:
+#ifdef TARGET_GPROF
+        _mcleanup();
+#endif
+        gdb_exit(cpu_env, arg1);
+        /* XXX: should free thread stack and CPU env */
+        _exit(arg1);
+        ret = 0; /* avoid warning */
+        break;
+    case TARGET_NETBSD_NR_read:
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(read(arg1, p, arg3));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_NETBSD_NR_write:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(write(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+    case TARGET_NETBSD_NR_open:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(open(path(p),
+                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                             arg3));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NETBSD_NR_mmap:
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
+                                    arg5,
+                                    arg6));
+        break;
+    case TARGET_NETBSD_NR_mprotect:
+        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        break;
+    case TARGET_NETBSD_NR_syscall:
+    case TARGET_NETBSD_NR___syscall:
+        ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
+        break;
+    default:
+        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+    }
+ fail:
+#ifdef DEBUG
+    gemu_log(" = %ld\n", ret);
+#endif
+    if (do_strace)
+        print_netbsd_syscall_ret(num, ret);
+    return ret;
+ efault:
+    ret = -TARGET_EFAULT;
+    goto fail;
+}
+
+abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
+                            abi_long arg2, abi_long arg3, abi_long arg4,
+                            abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    void *p;
+
+#ifdef DEBUG
+    gemu_log("openbsd syscall %d\n", num);
+#endif
+    if(do_strace)
+        print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+
+    switch(num) {
+    case TARGET_OPENBSD_NR_exit:
+#ifdef TARGET_GPROF
+        _mcleanup();
+#endif
+        gdb_exit(cpu_env, arg1);
+        /* XXX: should free thread stack and CPU env */
+        _exit(arg1);
+        ret = 0; /* avoid warning */
+        break;
+    case TARGET_OPENBSD_NR_read:
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(read(arg1, p, arg3));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_OPENBSD_NR_write:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(write(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+    case TARGET_OPENBSD_NR_open:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(open(path(p),
+                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                             arg3));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_OPENBSD_NR_mmap:
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
+                                    arg5,
+                                    arg6));
+        break;
+    case TARGET_OPENBSD_NR_mprotect:
+        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        break;
+    case TARGET_OPENBSD_NR_syscall:
+    case TARGET_OPENBSD_NR___syscall:
+        ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
+        break;
+    default:
+        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+    }
+ fail:
+#ifdef DEBUG
+    gemu_log(" = %ld\n", ret);
+#endif
+    if (do_strace)
+        print_openbsd_syscall_ret(num, ret);
+    return ret;
+ efault:
+    ret = -TARGET_EFAULT;
+    goto fail;
+}
+
+void syscall_init(void)
+{
+}
diff --git a/qemu-0.15.x/bsd-user/syscall_defs.h b/qemu-0.15.x/bsd-user/syscall_defs.h
new file mode 100644
index 0000000..207ddee
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/syscall_defs.h
@@ -0,0 +1,114 @@
+/*      $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $     */
+/*      $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $     */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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. 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.
+ *
+ *      @(#)signal.h    8.2 (Berkeley) 1/21/94
+ */
+
+#define TARGET_NSIG     32              /* counting 0; could be 33 (mask is 1-32) */
+
+#define TARGET_SIGHUP  1       /* hangup */
+#define TARGET_SIGINT  2       /* interrupt */
+#define TARGET_SIGQUIT 3       /* quit */
+#define TARGET_SIGILL  4       /* illegal instruction (not reset when caught) */
+#define TARGET_SIGTRAP 5       /* trace trap (not reset when caught) */
+#define TARGET_SIGABRT 6       /* abort() */
+#define TARGET_SIGIOT  SIGABRT /* compatibility */
+#define TARGET_SIGEMT  7       /* EMT instruction */
+#define TARGET_SIGFPE  8       /* floating point exception */
+#define TARGET_SIGKILL 9       /* kill (cannot be caught or ignored) */
+#define TARGET_SIGBUS  10      /* bus error */
+#define TARGET_SIGSEGV 11      /* segmentation violation */
+#define TARGET_SIGSYS  12      /* bad argument to system call */
+#define TARGET_SIGPIPE 13      /* write on a pipe with no one to read it */
+#define TARGET_SIGALRM 14      /* alarm clock */
+#define TARGET_SIGTERM 15      /* software termination signal from kill */
+#define TARGET_SIGURG  16      /* urgent condition on IO channel */
+#define TARGET_SIGSTOP 17      /* sendable stop signal not from tty */
+#define TARGET_SIGTSTP 18      /* stop signal from tty */
+#define TARGET_SIGCONT 19      /* continue a stopped process */
+#define TARGET_SIGCHLD 20      /* to parent on child stop or exit */
+#define TARGET_SIGTTIN 21      /* to readers pgrp upon background tty read */
+#define TARGET_SIGTTOU 22      /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define TARGET_SIGIO   23      /* input/output possible signal */
+#define TARGET_SIGXCPU 24      /* exceeded CPU time limit */
+#define TARGET_SIGXFSZ 25      /* exceeded file size limit */
+#define TARGET_SIGVTALRM 26    /* virtual time alarm */
+#define TARGET_SIGPROF 27      /* profiling time alarm */
+#define TARGET_SIGWINCH 28      /* window size changes */
+#define TARGET_SIGINFO  29      /* information request */
+#define TARGET_SIGUSR1 30       /* user defined signal 1 */
+#define TARGET_SIGUSR2 31       /* user defined signal 2 */
+
+/*
+ * Language spec says we must list exactly one parameter, even though we
+ * actually supply three.  Ugh!
+ */
+#define TARGET_SIG_DFL         (void (*)(int))0
+#define TARGET_SIG_IGN         (void (*)(int))1
+#define TARGET_SIG_ERR         (void (*)(int))-1
+
+#define TARGET_SA_ONSTACK       0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART       0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND     0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER       0x0010  /* don't mask the signal we're delivering */
+#define TARGET_SA_NOCLDWAIT     0x0020  /* don't create zombies (assign to pid 1) */
+#define TARGET_SA_USERTRAMP    0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP     0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO       0x0040  /* generate siginfo_t */
+
+/*
+ * Flags for sigprocmask:
+ */
+#define TARGET_SIG_BLOCK       1       /* block specified signal set */
+#define TARGET_SIG_UNBLOCK     2       /* unblock specified signal set */
+#define TARGET_SIG_SETMASK     3       /* set specified signal set */
+
+#define TARGET_BADSIG          SIG_ERR
+
+#define TARGET_SS_ONSTACK       0x0001  /* take signals on alternate stack */
+#define TARGET_SS_DISABLE       0x0004  /* disable taking signals on alternate stack */
+
+#include "errno_defs.h"
+
+#include "freebsd/syscall_nr.h"
+#include "netbsd/syscall_nr.h"
+#include "openbsd/syscall_nr.h"
+
+struct target_iovec {
+    abi_long iov_base;   /* Starting address */
+    abi_long iov_len;   /* Number of bytes */
+};
+
diff --git a/qemu-0.15.x/bsd-user/uaccess.c b/qemu-0.15.x/bsd-user/uaccess.c
new file mode 100644
index 0000000..677f19c
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/uaccess.c
@@ -0,0 +1,65 @@
+/* User memory access */
+#include <stdio.h>
+#include <string.h>
+
+#include "qemu.h"
+
+/* copy_from_user() and copy_to_user() are usually used to copy data
+ * buffers between the target and host.  These internally perform
+ * locking/unlocking of the memory.
+ */
+abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
+{
+    abi_long ret = 0;
+    void *ghptr;
+
+    if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
+        memcpy(hptr, ghptr, len);
+        unlock_user(ghptr, gaddr, 0);
+    } else
+        ret = -TARGET_EFAULT;
+
+    return ret;
+}
+
+
+abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
+{
+    abi_long ret = 0;
+    void *ghptr;
+
+    if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
+        memcpy(ghptr, hptr, len);
+        unlock_user(ghptr, gaddr, len);
+    } else
+        ret = -TARGET_EFAULT;
+
+    return ret;
+}
+
+/* Return the length of a string in target memory or -TARGET_EFAULT if
+   access error  */
+abi_long target_strlen(abi_ulong guest_addr1)
+{
+    uint8_t *ptr;
+    abi_ulong guest_addr;
+    int max_len, len;
+
+    guest_addr = guest_addr1;
+    for(;;) {
+        max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK);
+        ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
+        if (!ptr)
+            return -TARGET_EFAULT;
+        len = qemu_strnlen((char *)ptr, max_len);
+        unlock_user(ptr, guest_addr, 0);
+        guest_addr += len;
+        /* we don't allow wrapping or integer overflow */
+        if (guest_addr == 0 ||
+            (guest_addr - guest_addr1) > 0x7fffffff)
+            return -TARGET_EFAULT;
+        if (len != max_len)
+            break;
+    }
+    return guest_addr - guest_addr1;
+}
diff --git a/qemu-0.15.x/bsd-user/x86_64/syscall.h b/qemu-0.15.x/bsd-user/x86_64/syscall.h
new file mode 100644
index 0000000..5f71b7c
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/x86_64/syscall.h
@@ -0,0 +1,116 @@
+#define __USER_CS	(0x33)
+#define __USER_DS	(0x2B)
+
+struct target_pt_regs {
+	abi_ulong r15;
+	abi_ulong r14;
+	abi_ulong r13;
+	abi_ulong r12;
+	abi_ulong rbp;
+	abi_ulong rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ 	abi_ulong r11;
+	abi_ulong r10;
+	abi_ulong r9;
+	abi_ulong r8;
+	abi_ulong rax;
+	abi_ulong rcx;
+	abi_ulong rdx;
+	abi_ulong rsi;
+	abi_ulong rdi;
+	abi_ulong orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+	abi_ulong rip;
+	abi_ulong cs;
+	abi_ulong eflags;
+	abi_ulong rsp;
+	abi_ulong ss;
+/* top of stack page */
+};
+
+/* Maximum number of LDT entries supported. */
+#define TARGET_LDT_ENTRIES	8192
+/* The size of each LDT entry. */
+#define TARGET_LDT_ENTRY_SIZE	8
+
+#define TARGET_GDT_ENTRIES 16
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 12
+#define TARGET_GDT_ENTRY_TLS_MAX 14
+
+#if 0 // Redefine this
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+        abi_ulong     base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+	unsigned int  lm:1;
+};
+#else
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+        abi_ulong     base_addr;
+	unsigned int  limit;
+        unsigned int flags;
+};
+#endif
+
+struct target_ipc64_perm
+{
+	int		key;
+	uint32_t	uid;
+	uint32_t	gid;
+	uint32_t	cuid;
+	uint32_t	cgid;
+	unsigned short		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	abi_ulong		__unused1;
+	abi_ulong		__unused2;
+};
+
+struct target_msqid64_ds {
+	struct target_ipc64_perm msg_perm;
+	unsigned int msg_stime;	/* last msgsnd time */
+	unsigned int msg_rtime;	/* last msgrcv time */
+	unsigned int msg_ctime;	/* last change time */
+	abi_ulong  msg_cbytes;	/* current number of bytes on queue */
+	abi_ulong  msg_qnum;	/* number of messages in queue */
+	abi_ulong  msg_qbytes;	/* max number of bytes on queue */
+	unsigned int msg_lspid;	/* pid of last msgsnd */
+	unsigned int msg_lrpid;	/* last receive pid */
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+/* FreeBSD sysarch(2) */
+#define TARGET_FREEBSD_I386_GET_LDT	0
+#define TARGET_FREEBSD_I386_SET_LDT	1
+				/* I386_IOPL */
+#define TARGET_FREEBSD_I386_GET_IOPERM	3
+#define TARGET_FREEBSD_I386_SET_IOPERM	4
+				/* xxxxx */
+#define TARGET_FREEBSD_I386_GET_FSBASE	7
+#define TARGET_FREEBSD_I386_SET_FSBASE	8
+#define TARGET_FREEBSD_I386_GET_GSBASE	9
+#define TARGET_FREEBSD_I386_SET_GSBASE	10
+
+#define TARGET_FREEBSD_AMD64_GET_FSBASE	128
+#define TARGET_FREEBSD_AMD64_SET_FSBASE	129
+#define TARGET_FREEBSD_AMD64_GET_GSBASE	130
+#define TARGET_FREEBSD_AMD64_SET_GSBASE	131
+
+
+#define UNAME_MACHINE "x86_64"
+
+#define TARGET_ARCH_SET_GS 0x1001
+#define TARGET_ARCH_SET_FS 0x1002
+#define TARGET_ARCH_GET_FS 0x1003
+#define TARGET_ARCH_GET_GS 0x1004
diff --git a/qemu-0.15.x/bsd-user/x86_64/target_signal.h b/qemu-0.15.x/bsd-user/x86_64/target_signal.h
new file mode 100644
index 0000000..659cd40
--- /dev/null
+++ b/qemu-0.15.x/bsd-user/x86_64/target_signal.h
@@ -0,0 +1,19 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/bswap.h b/qemu-0.15.x/bswap.h
new file mode 100644
index 0000000..82a7951
--- /dev/null
+++ b/qemu-0.15.x/bswap.h
@@ -0,0 +1,240 @@
+#ifndef BSWAP_H
+#define BSWAP_H
+
+#include "config-host.h"
+
+#include <inttypes.h>
+
+#ifdef CONFIG_MACHINE_BSWAP_H
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <machine/bswap.h>
+#else
+
+#ifdef CONFIG_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+#define bswap_16(x) \
+({ \
+	uint16_t __x = (x); \
+	((uint16_t)( \
+		(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
+		(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
+})
+
+#define bswap_32(x) \
+({ \
+	uint32_t __x = (x); \
+	((uint32_t)( \
+		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
+})
+
+#define bswap_64(x) \
+({ \
+	uint64_t __x = (x); \
+	((uint64_t)( \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) <<  8) | \
+	        (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >>  8) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
+})
+
+#endif /* !CONFIG_BYTESWAP_H */
+
+static inline uint16_t bswap16(uint16_t x)
+{
+    return bswap_16(x);
+}
+
+static inline uint32_t bswap32(uint32_t x)
+{
+    return bswap_32(x);
+}
+
+static inline uint64_t bswap64(uint64_t x)
+{
+    return bswap_64(x);
+}
+
+#endif /* ! CONFIG_MACHINE_BSWAP_H */
+
+static inline void bswap16s(uint16_t *s)
+{
+    *s = bswap16(*s);
+}
+
+static inline void bswap32s(uint32_t *s)
+{
+    *s = bswap32(*s);
+}
+
+static inline void bswap64s(uint64_t *s)
+{
+    *s = bswap64(*s);
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define be_bswap(v, size) (v)
+#define le_bswap(v, size) bswap ## size(v)
+#define be_bswaps(v, size)
+#define le_bswaps(p, size) *p = bswap ## size(*p);
+#else
+#define le_bswap(v, size) (v)
+#define be_bswap(v, size) bswap ## size(v)
+#define le_bswaps(v, size)
+#define be_bswaps(p, size) *p = bswap ## size(*p);
+#endif
+
+#define CPU_CONVERT(endian, size, type)\
+static inline type endian ## size ## _to_cpu(type v)\
+{\
+    return endian ## _bswap(v, size);\
+}\
+\
+static inline type cpu_to_ ## endian ## size(type v)\
+{\
+    return endian ## _bswap(v, size);\
+}\
+\
+static inline void endian ## size ## _to_cpus(type *p)\
+{\
+    endian ## _bswaps(p, size)\
+}\
+\
+static inline void cpu_to_ ## endian ## size ## s(type *p)\
+{\
+    endian ## _bswaps(p, size)\
+}\
+\
+static inline type endian ## size ## _to_cpup(const type *p)\
+{\
+    return endian ## size ## _to_cpu(*p);\
+}\
+\
+static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
+{\
+     *p = cpu_to_ ## endian ## size(v);\
+}
+
+CPU_CONVERT(be, 16, uint16_t)
+CPU_CONVERT(be, 32, uint32_t)
+CPU_CONVERT(be, 64, uint64_t)
+
+CPU_CONVERT(le, 16, uint16_t)
+CPU_CONVERT(le, 32, uint32_t)
+CPU_CONVERT(le, 64, uint64_t)
+
+/* unaligned versions (optimized for frequent unaligned accesses)*/
+
+#if defined(__i386__) || defined(_ARCH_PPC)
+
+#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
+#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
+#define le16_to_cpupu(p) le16_to_cpup(p)
+#define le32_to_cpupu(p) le32_to_cpup(p)
+#define be32_to_cpupu(p) be32_to_cpup(p)
+
+#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
+#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
+#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v)
+
+#else
+
+static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v & 0xff;
+    p1[1] = v >> 8;
+}
+
+static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v & 0xff;
+    p1[1] = v >> 8;
+    p1[2] = v >> 16;
+    p1[3] = v >> 24;
+}
+
+static inline uint16_t le16_to_cpupu(const uint16_t *p)
+{
+    const uint8_t *p1 = (const uint8_t *)p;
+    return p1[0] | (p1[1] << 8);
+}
+
+static inline uint32_t le32_to_cpupu(const uint32_t *p)
+{
+    const uint8_t *p1 = (const uint8_t *)p;
+    return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
+}
+
+static inline uint32_t be32_to_cpupu(const uint32_t *p)
+{
+    const uint8_t *p1 = (const uint8_t *)p;
+    return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24);
+}
+
+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 & 0xff;
+}
+
+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 & 0xff;
+}
+
+static inline void cpu_to_be64wu(uint64_t *p, uint64_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 56;
+    p1[1] = v >> 48;
+    p1[2] = v >> 40;
+    p1[3] = v >> 32;
+    p1[4] = v >> 24;
+    p1[5] = v >> 16;
+    p1[6] = v >> 8;
+    p1[7] = v & 0xff;
+}
+
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define cpu_to_32wu cpu_to_be32wu
+#define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v)
+#else
+#define cpu_to_32wu cpu_to_le32wu
+#define leul_to_cpu(v) (v)
+#endif
+
+#undef le_bswap
+#undef be_bswap
+#undef le_bswaps
+#undef be_bswaps
+
+/* len must be one of 1, 2, 4 */
+static inline uint32_t qemu_bswap_len(uint32_t value, int len)
+{
+    return bswap32(value) >> (32 - 8 * len);
+}
+
+#endif /* BSWAP_H */
diff --git a/qemu-0.15.x/bt-host.c b/qemu-0.15.x/bt-host.c
new file mode 100644
index 0000000..095254d
--- /dev/null
+++ b/qemu-0.15.x/bt-host.c
@@ -0,0 +1,198 @@
+/*
+ * Wrap a host Bluetooth HCI socket in a struct HCIInfo.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "net.h"
+#include "bt-host.h"
+
+#ifndef _WIN32
+# include <errno.h>
+# include <sys/ioctl.h>
+# include <sys/uio.h>
+# ifdef CONFIG_BLUEZ
+#  include <bluetooth/bluetooth.h>
+#  include <bluetooth/hci.h>
+#  include <bluetooth/hci_lib.h>
+# else
+#  include "hw/bt.h"
+#  define HCI_MAX_FRAME_SIZE	1028
+# endif
+
+struct bt_host_hci_s {
+    struct HCIInfo hci;
+    int fd;
+
+    uint8_t hdr[HCI_MAX_FRAME_SIZE];
+    int len;
+};
+
+static void bt_host_send(struct HCIInfo *hci,
+                int type, const uint8_t *data, int len)
+{
+    struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
+    uint8_t pkt = type;
+    struct iovec iv[2];
+
+    iv[0].iov_base = (void *)&pkt;
+    iv[0].iov_len  = 1;
+    iv[1].iov_base = (void *) data;
+    iv[1].iov_len  = len;
+
+    while (writev(s->fd, iv, 2) < 0) {
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+    }
+}
+
+static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_COMMAND_PKT, data, len);
+}
+
+static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
+}
+
+static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_SCODATA_PKT, data, len);
+}
+
+static void bt_host_read(void *opaque)
+{
+    struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
+    uint8_t *pkt;
+    int pktlen;
+
+    /* Seems that we can't read only the header first and then the amount
+     * of data indicated in the header because Linux will discard everything
+     * that's not been read in one go.  */
+    s->len = read(s->fd, s->hdr, sizeof(s->hdr));
+
+    if (s->len < 0) {
+        fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
+        return;
+    }
+
+    pkt = s->hdr;
+    while (s->len --)
+        switch (*pkt ++) {
+        case HCI_EVENT_PKT:
+            if (s->len < 2)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[1] + 2, s->len);
+            s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+
+            /* TODO: if this is an Inquiry Result event, it's also
+             * interpreted by Linux kernel before we received it, possibly
+             * we should clean the kernel Inquiry cache through
+             * ioctl(s->fd, HCI_INQUIRY, ...).  */
+            break;
+
+        case HCI_ACLDATA_PKT:
+            if (s->len < 4)
+                goto bad_pkt;
+
+            pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
+            s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_SCODATA_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->len -= pktlen;
+            pkt += pktlen;
+
+        default:
+        bad_pkt:
+            fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
+        }
+}
+
+static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
+{
+    return -ENOTSUP;
+}
+
+struct HCIInfo *bt_host_hci(const char *id)
+{
+    struct bt_host_hci_s *s;
+    int fd = -1;
+# ifdef CONFIG_BLUEZ
+    int dev_id = hci_devid(id);
+    struct hci_filter flt;
+
+    if (dev_id < 0) {
+        fprintf(stderr, "qemu: `%s' not available\n", id);
+        return 0;
+    }
+
+    fd = hci_open_dev(dev_id);
+
+    /* XXX: can we ensure nobody else has the device opened?  */
+# endif
+
+    if (fd < 0) {
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        id, strerror(errno), errno);
+        return NULL;
+    }
+
+# ifdef CONFIG_BLUEZ
+    hci_filter_clear(&flt);
+    hci_filter_all_ptypes(&flt);
+    hci_filter_all_events(&flt);
+
+    if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+        fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
+        return 0;
+    }
+# endif
+
+    s = qemu_mallocz(sizeof(struct bt_host_hci_s));
+    s->fd = fd;
+    s->hci.cmd_send = bt_host_cmd;
+    s->hci.sco_send = bt_host_sco;
+    s->hci.acl_send = bt_host_acl;
+    s->hci.bdaddr_set = bt_host_bdaddr_set;
+
+    qemu_set_fd_handler(s->fd, bt_host_read, NULL, s);
+
+    return &s->hci;
+}
+#else
+struct HCIInfo *bt_host_hci(const char *id)
+{
+    fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n");
+
+    return 0;
+}
+#endif
diff --git a/qemu-0.15.x/bt-host.h b/qemu-0.15.x/bt-host.h
new file mode 100644
index 0000000..f1eff65
--- /dev/null
+++ b/qemu-0.15.x/bt-host.h
@@ -0,0 +1,9 @@
+#ifndef BT_HOST_H
+#define BT_HOST_H
+
+struct HCIInfo;
+
+/* bt-host.c */
+struct HCIInfo *bt_host_hci(const char *id);
+
+#endif
diff --git a/qemu-0.15.x/bt-vhci.c b/qemu-0.15.x/bt-vhci.c
new file mode 100644
index 0000000..3c57720
--- /dev/null
+++ b/qemu-0.15.x/bt-vhci.c
@@ -0,0 +1,167 @@
+/*
+ * Support for host VHCIs inside qemu scatternets.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "net.h"
+#include "hw/bt.h"
+
+#define VHCI_DEV	"/dev/vhci"
+#define VHCI_UDEV	"/dev/hci_vhci"
+
+struct bt_vhci_s {
+    int fd;
+    struct HCIInfo *info;
+
+    uint8_t hdr[4096];
+    int len;
+};
+
+static void vhci_read(void *opaque)
+{
+    struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
+    uint8_t *pkt;
+    int pktlen;
+
+    /* Seems that we can't read only the header first and then the amount
+     * of data indicated in the header because Linux will discard everything
+     * that's not been read in one go.  */
+    s->len = read(s->fd, s->hdr, sizeof(s->hdr));
+
+    if (s->len < 0) {
+        fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
+        return;
+    }
+
+    pkt = s->hdr;
+    while (s->len --)
+        switch (*pkt ++) {
+        case HCI_COMMAND_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->info->cmd_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_ACLDATA_PKT:
+            if (s->len < 4)
+                goto bad_pkt;
+
+            pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
+            s->info->acl_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_SCODATA_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->info->sco_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        default:
+        bad_pkt:
+            fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
+        }
+}
+
+static void vhci_host_send(void *opaque,
+                int type, const uint8_t *data, int len)
+{
+    struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
+#if 0
+    uint8_t pkt = type;
+    struct iovec iv[2];
+
+    iv[0].iov_base = &pkt;
+    iv[0].iov_len  = 1;
+    iv[1].iov_base = (void *) data;
+    iv[1].iov_len  = len;
+
+    while (writev(s->fd, iv, 2) < 0)
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+#else
+    /* Apparently VHCI wants us to write everything in one chunk :-(  */
+    static uint8_t buf[4096];
+
+    buf[0] = type;
+    memcpy(buf + 1, data, len);
+
+    while (write(s->fd, buf, len + 1) < 0)
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+#endif
+}
+
+static void vhci_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
+}
+
+static void vhci_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
+}
+
+void bt_vhci_init(struct HCIInfo *info)
+{
+    struct bt_vhci_s *s;
+    int err[2];
+    int fd;
+
+    fd = open(VHCI_DEV, O_RDWR);
+    err[0] = errno;
+    if (fd < 0) {
+        fd = open(VHCI_UDEV, O_RDWR);
+        err[1] = errno;
+    }
+
+    if (fd < 0) {
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        VHCI_DEV, strerror(err[0]), err[0]);
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        VHCI_UDEV, strerror(err[1]), err[1]);
+        exit(-1);
+    }
+
+    s = qemu_mallocz(sizeof(struct bt_vhci_s));
+    s->fd = fd;
+    s->info = info ?: qemu_next_hci();
+    s->info->opaque = s;
+    s->info->evt_recv = vhci_out_hci_packet_event;
+    s->info->acl_recv = vhci_out_hci_packet_acl;
+
+    qemu_set_fd_handler(s->fd, vhci_read, NULL, s);
+}
diff --git a/qemu-0.15.x/buffered_file.c b/qemu-0.15.x/buffered_file.c
new file mode 100644
index 0000000..41b42c3
--- /dev/null
+++ b/qemu-0.15.x/buffered_file.c
@@ -0,0 +1,281 @@
+/*
+ * QEMU buffered QEMUFile
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+
+//#define DEBUG_BUFFERED_FILE
+
+typedef struct QEMUFileBuffered
+{
+    BufferedPutFunc *put_buffer;
+    BufferedPutReadyFunc *put_ready;
+    BufferedWaitForUnfreezeFunc *wait_for_unfreeze;
+    BufferedCloseFunc *close;
+    void *opaque;
+    QEMUFile *file;
+    int has_error;
+    int freeze_output;
+    size_t bytes_xfer;
+    size_t xfer_limit;
+    uint8_t *buffer;
+    size_t buffer_size;
+    size_t buffer_capacity;
+    QEMUTimer *timer;
+} QEMUFileBuffered;
+
+#ifdef DEBUG_BUFFERED_FILE
+#define DPRINTF(fmt, ...) \
+    do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static void buffered_append(QEMUFileBuffered *s,
+                            const uint8_t *buf, size_t size)
+{
+    if (size > (s->buffer_capacity - s->buffer_size)) {
+        void *tmp;
+
+        DPRINTF("increasing buffer capacity from %zu by %zu\n",
+                s->buffer_capacity, size + 1024);
+
+        s->buffer_capacity += size + 1024;
+
+        tmp = qemu_realloc(s->buffer, s->buffer_capacity);
+        if (tmp == NULL) {
+            fprintf(stderr, "qemu file buffer expansion failed\n");
+            exit(1);
+        }
+
+        s->buffer = tmp;
+    }
+
+    memcpy(s->buffer + s->buffer_size, buf, size);
+    s->buffer_size += size;
+}
+
+static void buffered_flush(QEMUFileBuffered *s)
+{
+    size_t offset = 0;
+
+    if (s->has_error) {
+        DPRINTF("flush when error, bailing\n");
+        return;
+    }
+
+    DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
+
+    while (offset < s->buffer_size) {
+        ssize_t ret;
+
+        ret = s->put_buffer(s->opaque, s->buffer + offset,
+                            s->buffer_size - offset);
+        if (ret == -EAGAIN) {
+            DPRINTF("backend not ready, freezing\n");
+            s->freeze_output = 1;
+            break;
+        }
+
+        if (ret <= 0) {
+            DPRINTF("error flushing data, %zd\n", ret);
+            s->has_error = 1;
+            break;
+        } else {
+            DPRINTF("flushed %zd byte(s)\n", ret);
+            offset += ret;
+        }
+    }
+
+    DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
+    memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
+    s->buffer_size -= offset;
+}
+
+static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileBuffered *s = opaque;
+    int offset = 0;
+    ssize_t ret;
+
+    DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
+
+    if (s->has_error) {
+        DPRINTF("flush when error, bailing\n");
+        return -EINVAL;
+    }
+
+    DPRINTF("unfreezing output\n");
+    s->freeze_output = 0;
+
+    buffered_flush(s);
+
+    while (!s->freeze_output && offset < size) {
+        if (s->bytes_xfer > s->xfer_limit) {
+            DPRINTF("transfer limit exceeded when putting\n");
+            break;
+        }
+
+        ret = s->put_buffer(s->opaque, buf + offset, size - offset);
+        if (ret == -EAGAIN) {
+            DPRINTF("backend not ready, freezing\n");
+            s->freeze_output = 1;
+            break;
+        }
+
+        if (ret <= 0) {
+            DPRINTF("error putting\n");
+            s->has_error = 1;
+            offset = -EINVAL;
+            break;
+        }
+
+        DPRINTF("put %zd byte(s)\n", ret);
+        offset += ret;
+        s->bytes_xfer += ret;
+    }
+
+    if (offset >= 0) {
+        DPRINTF("buffering %d bytes\n", size - offset);
+        buffered_append(s, buf + offset, size - offset);
+        offset = size;
+    }
+
+    if (pos == 0 && size == 0) {
+        DPRINTF("file is ready\n");
+        if (s->bytes_xfer <= s->xfer_limit) {
+            DPRINTF("notifying client\n");
+            s->put_ready(s->opaque);
+        }
+    }
+
+    return offset;
+}
+
+static int buffered_close(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+    int ret;
+
+    DPRINTF("closing\n");
+
+    while (!s->has_error && s->buffer_size) {
+        buffered_flush(s);
+        if (s->freeze_output)
+            s->wait_for_unfreeze(s);
+    }
+
+    ret = s->close(s->opaque);
+
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_free(s->buffer);
+    qemu_free(s);
+
+    return ret;
+}
+
+static int buffered_rate_limit(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+
+    if (s->has_error)
+        return 0;
+
+    if (s->freeze_output)
+        return 1;
+
+    if (s->bytes_xfer > s->xfer_limit)
+        return 1;
+
+    return 0;
+}
+
+static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
+{
+    QEMUFileBuffered *s = opaque;
+    if (s->has_error)
+        goto out;
+
+    if (new_rate > SIZE_MAX) {
+        new_rate = SIZE_MAX;
+    }
+
+    s->xfer_limit = new_rate / 10;
+    
+out:
+    return s->xfer_limit;
+}
+
+static int64_t buffered_get_rate_limit(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+  
+    return s->xfer_limit;
+}
+
+static void buffered_rate_tick(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+
+    if (s->has_error) {
+        buffered_close(s);
+        return;
+    }
+
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
+
+    if (s->freeze_output)
+        return;
+
+    s->bytes_xfer = 0;
+
+    buffered_flush(s);
+
+    /* Add some checks around this */
+    s->put_ready(s->opaque);
+}
+
+QEMUFile *qemu_fopen_ops_buffered(void *opaque,
+                                  size_t bytes_per_sec,
+                                  BufferedPutFunc *put_buffer,
+                                  BufferedPutReadyFunc *put_ready,
+                                  BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
+                                  BufferedCloseFunc *close)
+{
+    QEMUFileBuffered *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->opaque = opaque;
+    s->xfer_limit = bytes_per_sec / 10;
+    s->put_buffer = put_buffer;
+    s->put_ready = put_ready;
+    s->wait_for_unfreeze = wait_for_unfreeze;
+    s->close = close;
+
+    s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
+                             buffered_close, buffered_rate_limit,
+                             buffered_set_rate_limit,
+			     buffered_get_rate_limit);
+
+    s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s);
+
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
+
+    return s->file;
+}
diff --git a/qemu-0.15.x/buffered_file.h b/qemu-0.15.x/buffered_file.h
new file mode 100644
index 0000000..98d358b
--- /dev/null
+++ b/qemu-0.15.x/buffered_file.h
@@ -0,0 +1,30 @@
+/*
+ * QEMU buffered QEMUFile
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_BUFFERED_FILE_H
+#define QEMU_BUFFERED_FILE_H
+
+#include "hw/hw.h"
+
+typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size);
+typedef void (BufferedPutReadyFunc)(void *opaque);
+typedef void (BufferedWaitForUnfreezeFunc)(void *opaque);
+typedef int (BufferedCloseFunc)(void *opaque);
+
+QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t xfer_limit,
+                                  BufferedPutFunc *put_buffer,
+                                  BufferedPutReadyFunc *put_ready,
+                                  BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
+                                  BufferedCloseFunc *close);
+
+#endif
diff --git a/qemu-0.15.x/cache-utils.c b/qemu-0.15.x/cache-utils.c
new file mode 100644
index 0000000..2db5af2
--- /dev/null
+++ b/qemu-0.15.x/cache-utils.c
@@ -0,0 +1,97 @@
+#include "cache-utils.h"
+
+#if defined(_ARCH_PPC)
+struct qemu_cache_conf qemu_cache_conf = {
+    .dcache_bsize = 16,
+    .icache_bsize = 16
+};
+
+#if defined _AIX
+#include <sys/systemcfg.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    qemu_cache_conf.icache_bsize = _system_configuration.icache_line;
+    qemu_cache_conf.dcache_bsize = _system_configuration.dcache_line;
+}
+
+#elif defined __linux__
+
+#define QEMU_AT_NULL        0
+#define QEMU_AT_DCACHEBSIZE 19
+#define QEMU_AT_ICACHEBSIZE 20
+
+static void ppc_init_cacheline_sizes(char **envp)
+{
+    unsigned long *auxv;
+
+    while (*envp++);
+
+    for (auxv = (unsigned long *) envp; *auxv != QEMU_AT_NULL; auxv += 2) {
+        switch (*auxv) {
+        case QEMU_AT_DCACHEBSIZE: qemu_cache_conf.dcache_bsize = auxv[1]; break;
+        case QEMU_AT_ICACHEBSIZE: qemu_cache_conf.icache_bsize = auxv[1]; break;
+        default: break;
+        }
+    }
+}
+
+#elif defined __APPLE__
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    size_t len;
+    unsigned cacheline;
+    int name[2] = { CTL_HW, HW_CACHELINE };
+
+    len = sizeof(cacheline);
+    if (sysctl(name, 2, &cacheline, &len, NULL, 0)) {
+        perror("sysctl CTL_HW HW_CACHELINE failed");
+    } else {
+        qemu_cache_conf.dcache_bsize = cacheline;
+        qemu_cache_conf.icache_bsize = cacheline;
+    }
+}
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    size_t len = 4;
+    unsigned cacheline;
+
+    if (sysctlbyname ("machdep.cacheline_size", &cacheline, &len, NULL, 0)) {
+        fprintf(stderr, "sysctlbyname machdep.cacheline_size failed: %s\n",
+                strerror(errno));
+        exit(1);
+    }
+
+    qemu_cache_conf.dcache_bsize = cacheline;
+    qemu_cache_conf.icache_bsize = cacheline;
+}
+#endif
+
+#ifdef __linux__
+void qemu_cache_utils_init(char **envp)
+{
+    ppc_init_cacheline_sizes(envp);
+}
+#else
+void qemu_cache_utils_init(char **envp)
+{
+    (void) envp;
+    ppc_init_cacheline_sizes();
+}
+#endif
+
+#endif /* _ARCH_PPC */
diff --git a/qemu-0.15.x/cache-utils.h b/qemu-0.15.x/cache-utils.h
new file mode 100644
index 0000000..0b65907
--- /dev/null
+++ b/qemu-0.15.x/cache-utils.h
@@ -0,0 +1,41 @@
+#ifndef QEMU_CACHE_UTILS_H
+#define QEMU_CACHE_UTILS_H
+
+#if defined(_ARCH_PPC)
+struct qemu_cache_conf {
+    unsigned long dcache_bsize;
+    unsigned long icache_bsize;
+};
+
+extern struct qemu_cache_conf qemu_cache_conf;
+
+void qemu_cache_utils_init(char **envp);
+
+/* mildly adjusted code from tcg-dyngen.c */
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    unsigned long p, start1, stop1;
+    unsigned long dsize = qemu_cache_conf.dcache_bsize;
+    unsigned long isize = qemu_cache_conf.icache_bsize;
+
+    start1 = start & ~(dsize - 1);
+    stop1 = (stop + dsize - 1) & ~(dsize - 1);
+    for (p = start1; p < stop1; p += dsize) {
+        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
+    }
+    asm volatile ("sync" : : : "memory");
+
+    start &= start & ~(isize - 1);
+    stop1 = (stop + isize - 1) & ~(isize - 1);
+    for (p = start1; p < stop1; p += isize) {
+        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
+    }
+    asm volatile ("sync" : : : "memory");
+    asm volatile ("isync" : : : "memory");
+}
+
+#else
+#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
+#endif
+
+#endif /* QEMU_CACHE_UTILS_H */
diff --git a/qemu-0.15.x/check-qdict.c b/qemu-0.15.x/check-qdict.c
new file mode 100644
index 0000000..ecc7fd7
--- /dev/null
+++ b/qemu-0.15.x/check-qdict.c
@@ -0,0 +1,402 @@
+/*
+ * QDict unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <check.h>
+
+#include "qint.h"
+#include "qdict.h"
+#include "qstring.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qdict_new_test)
+{
+    QDict *qdict;
+
+    qdict = qdict_new();
+    fail_unless(qdict != NULL);
+    fail_unless(qdict_size(qdict) == 0);
+    fail_unless(qdict->base.refcnt == 1);
+    fail_unless(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
+
+    // destroy doesn't exit yet
+    free(qdict);
+}
+END_TEST
+
+START_TEST(qdict_put_obj_test)
+{
+    QInt *qi;
+    QDict *qdict;
+    QDictEntry *ent;
+    const int num = 42;
+
+    qdict = qdict_new();
+
+    // key "" will have tdb hash 12345
+    qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
+
+    fail_unless(qdict_size(qdict) == 1);
+    ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
+    qi = qobject_to_qint(ent->value);
+    fail_unless(qint_get_int(qi) == num);
+
+    // destroy doesn't exit yet
+    QDECREF(qi);
+    qemu_free(ent->key);
+    qemu_free(ent);
+    qemu_free(qdict);
+}
+END_TEST
+
+START_TEST(qdict_destroy_simple_test)
+{
+    QDict *qdict;
+
+    qdict = qdict_new();
+    qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
+    qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
+
+    QDECREF(qdict);
+}
+END_TEST
+
+static QDict *tests_dict = NULL;
+
+static void qdict_setup(void)
+{
+    tests_dict = qdict_new();
+    fail_unless(tests_dict != NULL);
+}
+
+static void qdict_teardown(void)
+{
+    QDECREF(tests_dict);
+    tests_dict = NULL;
+}
+
+START_TEST(qdict_get_test)
+{
+    QInt *qi;
+    QObject *obj;
+    const int value = -42;
+    const char *key = "test";
+
+    qdict_put(tests_dict, key, qint_from_int(value));
+
+    obj = qdict_get(tests_dict, key);
+    fail_unless(obj != NULL);
+
+    qi = qobject_to_qint(obj);
+    fail_unless(qint_get_int(qi) == value);
+}
+END_TEST
+
+START_TEST(qdict_get_int_test)
+{
+    int ret;
+    const int value = 100;
+    const char *key = "int";
+
+    qdict_put(tests_dict, key, qint_from_int(value));
+
+    ret = qdict_get_int(tests_dict, key);
+    fail_unless(ret == value);
+}
+END_TEST
+
+START_TEST(qdict_get_try_int_test)
+{
+    int ret;
+    const int value = 100;
+    const char *key = "int";
+
+    qdict_put(tests_dict, key, qint_from_int(value));
+
+    ret = qdict_get_try_int(tests_dict, key, 0);
+    fail_unless(ret == value);
+}
+END_TEST
+
+START_TEST(qdict_get_str_test)
+{
+    const char *p;
+    const char *key = "key";
+    const char *str = "string";
+
+    qdict_put(tests_dict, key, qstring_from_str(str));
+
+    p = qdict_get_str(tests_dict, key);
+    fail_unless(p != NULL);
+    fail_unless(strcmp(p, str) == 0);
+}
+END_TEST
+
+START_TEST(qdict_get_try_str_test)
+{
+    const char *p;
+    const char *key = "key";
+    const char *str = "string";
+
+    qdict_put(tests_dict, key, qstring_from_str(str));
+
+    p = qdict_get_try_str(tests_dict, key);
+    fail_unless(p != NULL);
+    fail_unless(strcmp(p, str) == 0);
+}
+END_TEST
+
+START_TEST(qdict_haskey_not_test)
+{
+    fail_unless(qdict_haskey(tests_dict, "test") == 0);
+}
+END_TEST
+
+START_TEST(qdict_haskey_test)
+{
+    const char *key = "test";
+
+    qdict_put(tests_dict, key, qint_from_int(0));
+    fail_unless(qdict_haskey(tests_dict, key) == 1);
+}
+END_TEST
+
+START_TEST(qdict_del_test)
+{
+    const char *key = "key test";
+
+    qdict_put(tests_dict, key, qstring_from_str("foo"));
+    fail_unless(qdict_size(tests_dict) == 1);
+
+    qdict_del(tests_dict, key);
+
+    fail_unless(qdict_size(tests_dict) == 0);
+    fail_unless(qdict_haskey(tests_dict, key) == 0);
+}
+END_TEST
+
+START_TEST(qobject_to_qdict_test)
+{
+    fail_unless(qobject_to_qdict(QOBJECT(tests_dict)) == tests_dict);
+}
+END_TEST
+
+START_TEST(qdict_iterapi_test)
+{
+    int count;
+    const QDictEntry *ent;
+
+    fail_unless(qdict_first(tests_dict) == NULL);
+
+    qdict_put(tests_dict, "key1", qint_from_int(1));
+    qdict_put(tests_dict, "key2", qint_from_int(2));
+    qdict_put(tests_dict, "key3", qint_from_int(3));
+
+    count = 0;
+    for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
+        fail_unless(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
+        count++;
+    }
+
+    fail_unless(count == qdict_size(tests_dict));
+
+    /* Do it again to test restarting */
+    count = 0;
+    for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
+        fail_unless(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
+        count++;
+    }
+
+    fail_unless(count == qdict_size(tests_dict));
+}
+END_TEST
+
+/*
+ * Errors test-cases
+ */
+
+START_TEST(qdict_put_exists_test)
+{
+    int value;
+    const char *key = "exists";
+
+    qdict_put(tests_dict, key, qint_from_int(1));
+    qdict_put(tests_dict, key, qint_from_int(2));
+
+    value = qdict_get_int(tests_dict, key);
+    fail_unless(value == 2);
+
+    fail_unless(qdict_size(tests_dict) == 1);
+}
+END_TEST
+
+START_TEST(qdict_get_not_exists_test)
+{
+    fail_unless(qdict_get(tests_dict, "foo") == NULL);
+}
+END_TEST
+
+/*
+ * Stress test-case
+ *
+ * This is a lot big for a unit-test, but there is no other place
+ * to have it.
+ */
+
+static void remove_dots(char *string)
+{
+    char *p = strchr(string, ':');
+    if (p)
+        *p = '\0';
+}
+
+static QString *read_line(FILE *file, char *key)
+{
+    char value[128];
+
+    if (fscanf(file, "%127s%127s", key, value) == EOF) {
+        return NULL;
+    }
+    remove_dots(key);
+    return qstring_from_str(value);
+}
+
+#define reset_file(file)    fseek(file, 0L, SEEK_SET)
+
+START_TEST(qdict_stress_test)
+{
+    size_t lines;
+    char key[128];
+    FILE *test_file;
+    QDict *qdict;
+    QString *value;
+    const char *test_file_path = "qdict-test-data.txt";
+
+    test_file = fopen(test_file_path, "r");
+    fail_unless(test_file != NULL);
+
+    // Create the dict
+    qdict = qdict_new();
+    fail_unless(qdict != NULL);
+
+    // Add everything from the test file
+    for (lines = 0;; lines++) {
+        value = read_line(test_file, key);
+        if (!value)
+            break;
+
+        qdict_put(qdict, key, value);
+    }
+    fail_unless(qdict_size(qdict) == lines);
+
+    // Check if everything is really in there
+    reset_file(test_file);
+    for (;;) {
+        const char *str1, *str2;
+
+        value = read_line(test_file, key);
+        if (!value)
+            break;
+
+        str1 = qstring_get_str(value);
+
+        str2 = qdict_get_str(qdict, key);
+        fail_unless(str2 != NULL);
+
+        fail_unless(strcmp(str1, str2) == 0);
+
+        QDECREF(value);
+    }
+
+    // Delete everything
+    reset_file(test_file);
+    for (;;) {
+        value = read_line(test_file, key);
+        if (!value)
+            break;
+
+        qdict_del(qdict, key);
+        QDECREF(value);
+
+        fail_unless(qdict_haskey(qdict, key) == 0);
+    }
+    fclose(test_file);
+
+    fail_unless(qdict_size(qdict) == 0);
+    QDECREF(qdict);
+}
+END_TEST
+
+static Suite *qdict_suite(void)
+{
+    Suite *s;
+    TCase *qdict_public_tcase;
+    TCase *qdict_public2_tcase;
+    TCase *qdict_stress_tcase;
+    TCase *qdict_errors_tcase;
+
+    s = suite_create("QDict test-suite");
+
+    qdict_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qdict_public_tcase);
+    tcase_add_test(qdict_public_tcase, qdict_new_test);
+    tcase_add_test(qdict_public_tcase, qdict_put_obj_test);
+    tcase_add_test(qdict_public_tcase, qdict_destroy_simple_test);
+
+    /* Continue, but now with fixtures */
+    qdict_public2_tcase = tcase_create("Public Interface (2)");
+    suite_add_tcase(s, qdict_public2_tcase);
+    tcase_add_checked_fixture(qdict_public2_tcase, qdict_setup, qdict_teardown);
+    tcase_add_test(qdict_public2_tcase, qdict_get_test);
+    tcase_add_test(qdict_public2_tcase, qdict_get_int_test);
+    tcase_add_test(qdict_public2_tcase, qdict_get_try_int_test);
+    tcase_add_test(qdict_public2_tcase, qdict_get_str_test);
+    tcase_add_test(qdict_public2_tcase, qdict_get_try_str_test);
+    tcase_add_test(qdict_public2_tcase, qdict_haskey_not_test);
+    tcase_add_test(qdict_public2_tcase, qdict_haskey_test);
+    tcase_add_test(qdict_public2_tcase, qdict_del_test);
+    tcase_add_test(qdict_public2_tcase, qobject_to_qdict_test);
+    tcase_add_test(qdict_public2_tcase, qdict_iterapi_test);
+
+    qdict_errors_tcase = tcase_create("Errors");
+    suite_add_tcase(s, qdict_errors_tcase);
+    tcase_add_checked_fixture(qdict_errors_tcase, qdict_setup, qdict_teardown);
+    tcase_add_test(qdict_errors_tcase, qdict_put_exists_test);
+    tcase_add_test(qdict_errors_tcase, qdict_get_not_exists_test);
+
+    /* The Big one */
+    qdict_stress_tcase = tcase_create("Stress Test");
+    suite_add_tcase(s, qdict_stress_tcase);
+    tcase_add_test(qdict_stress_tcase, qdict_stress_test);
+
+    return s;
+}
+
+int main(void)
+{
+	int nf;
+	Suite *s;
+	SRunner *sr;
+
+	s = qdict_suite();
+	sr = srunner_create(s);
+
+	srunner_run_all(sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/check-qfloat.c b/qemu-0.15.x/check-qfloat.c
new file mode 100644
index 0000000..b71d983
--- /dev/null
+++ b/qemu-0.15.x/check-qfloat.c
@@ -0,0 +1,76 @@
+/*
+ * QFloat unit-tests.
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <check.h>
+
+#include "qfloat.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qfloat_from_double_test)
+{
+    QFloat *qf;
+    const double value = -42.23423;
+
+    qf = qfloat_from_double(value);
+    fail_unless(qf != NULL);
+    fail_unless(qf->value == value);
+    fail_unless(qf->base.refcnt == 1);
+    fail_unless(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
+
+    // destroy doesn't exit yet
+    qemu_free(qf);
+}
+END_TEST
+
+START_TEST(qfloat_destroy_test)
+{
+    QFloat *qf = qfloat_from_double(0.0);
+    QDECREF(qf);
+}
+END_TEST
+
+static Suite *qfloat_suite(void)
+{
+    Suite *s;
+    TCase *qfloat_public_tcase;
+
+    s = suite_create("QFloat test-suite");
+
+    qfloat_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qfloat_public_tcase);
+    tcase_add_test(qfloat_public_tcase, qfloat_from_double_test);
+    tcase_add_test(qfloat_public_tcase, qfloat_destroy_test);
+
+    return s;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s;
+    SRunner *sr;
+
+    s = qfloat_suite();
+    sr = srunner_create(s);
+
+    srunner_run_all(sr, CK_NORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/check-qint.c b/qemu-0.15.x/check-qint.c
new file mode 100644
index 0000000..f3b0316
--- /dev/null
+++ b/qemu-0.15.x/check-qint.c
@@ -0,0 +1,113 @@
+/*
+ * QInt unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <check.h>
+
+#include "qint.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qint_from_int_test)
+{
+    QInt *qi;
+    const int value = -42;
+
+    qi = qint_from_int(value);
+    fail_unless(qi != NULL);
+    fail_unless(qi->value == value);
+    fail_unless(qi->base.refcnt == 1);
+    fail_unless(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
+
+    // destroy doesn't exit yet
+    qemu_free(qi);
+}
+END_TEST
+
+START_TEST(qint_destroy_test)
+{
+    QInt *qi = qint_from_int(0);
+    QDECREF(qi);
+}
+END_TEST
+
+START_TEST(qint_from_int64_test)
+{
+    QInt *qi;
+    const int64_t value = 0x1234567890abcdefLL;
+
+    qi = qint_from_int(value);
+    fail_unless((int64_t) qi->value == value);
+
+    QDECREF(qi);
+}
+END_TEST
+
+START_TEST(qint_get_int_test)
+{
+    QInt *qi;
+    const int value = 123456;
+
+    qi = qint_from_int(value);
+    fail_unless(qint_get_int(qi) == value);
+
+    QDECREF(qi);
+}
+END_TEST
+
+START_TEST(qobject_to_qint_test)
+{
+    QInt *qi;
+
+    qi = qint_from_int(0);
+    fail_unless(qobject_to_qint(QOBJECT(qi)) == qi);
+
+    QDECREF(qi);
+}
+END_TEST
+
+static Suite *qint_suite(void)
+{
+    Suite *s;
+    TCase *qint_public_tcase;
+
+    s = suite_create("QInt test-suite");
+
+    qint_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qint_public_tcase);
+    tcase_add_test(qint_public_tcase, qint_from_int_test);
+    tcase_add_test(qint_public_tcase, qint_destroy_test);
+    tcase_add_test(qint_public_tcase, qint_from_int64_test);
+    tcase_add_test(qint_public_tcase, qint_get_int_test);
+    tcase_add_test(qint_public_tcase, qobject_to_qint_test);
+
+    return s;
+}
+
+int main(void)
+{
+	int nf;
+	Suite *s;
+	SRunner *sr;
+
+	s = qint_suite();
+	sr = srunner_create(s);
+
+	srunner_run_all(sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/check-qjson.c b/qemu-0.15.x/check-qjson.c
new file mode 100644
index 0000000..36d4ac2
--- /dev/null
+++ b/qemu-0.15.x/check-qjson.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <check.h>
+
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "qjson.h"
+
+#include "qemu-common.h"
+
+START_TEST(escaped_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+        int skip;
+    } test_cases[] = {
+        { "\"\\b\"", "\b" },
+        { "\"\\f\"", "\f" },
+        { "\"\\n\"", "\n" },
+        { "\"\\r\"", "\r" },
+        { "\"\\t\"", "\t" },
+        { "\"/\"", "/" },
+        { "\"\\/\"", "/", .skip = 1 },
+        { "\"\\\\\"", "\\" },
+        { "\"\\\"\"", "\"" },
+        { "\"hello world \\\"embedded string\\\"\"",
+          "hello world \"embedded string\"" },
+        { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
+        { "\"single byte utf-8 \\u0020\"", "single byte utf-8  ", .skip = 1 },
+        { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
+        { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
+                    "%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
+
+        if (test_cases[i].skip == 0) {
+            str = qobject_to_json(obj);
+            fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
+                        "%s != %s\n", qstring_get_str(str),
+                                      test_cases[i].encoded);
+
+            qobject_decref(obj);
+        }
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+    } test_cases[] = {
+        { "\"hello world\"", "hello world" },
+        { "\"the quick brown fox jumped over the fence\"",
+          "the quick brown fox jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        str = qobject_to_json(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+
+        qobject_decref(obj);
+        
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(single_quote_string)
+{
+    int i;
+    struct {
+        const char *encoded;
+        const char *decoded;
+    } test_cases[] = {
+        { "'hello world'", "hello world" },
+        { "'the quick brown fox \\' jumped over the fence'",
+          "the quick brown fox ' jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(vararg_string)
+{
+    int i;
+    struct {
+        const char *decoded;
+    } test_cases[] = {
+        { "hello world" },
+        { "the quick brown fox jumped over the fence" },
+        {}
+    };
+
+    for (i = 0; test_cases[i].decoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_jsonf("%s", test_cases[i].decoded);
+
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
+        
+        str = qobject_to_qstring(obj);
+        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_number)
+{
+    int i;
+    struct {
+        const char *encoded;
+        int64_t decoded;
+        int skip;
+    } test_cases[] = {
+        { "0", 0 },
+        { "1234", 1234 },
+        { "1", 1 },
+        { "-32", -32 },
+        { "-0", 0, .skip = 1 },
+        { },
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QInt *qint;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+        qint = qobject_to_qint(obj);
+        fail_unless(qint_get_int(qint) == test_cases[i].decoded);
+        if (test_cases[i].skip == 0) {
+            QString *str;
+
+            str = qobject_to_json(obj);
+            fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+            QDECREF(str);
+        }
+
+        QDECREF(qint);
+    }
+}
+END_TEST
+
+START_TEST(float_number)
+{
+    int i;
+    struct {
+        const char *encoded;
+        double decoded;
+        int skip;
+    } test_cases[] = {
+        { "32.43", 32.43 },
+        { "0.222", 0.222 },
+        { "-32.12313", -32.12313 },
+        { "-32.20e-10", -32.20e-10, .skip = 1 },
+        { },
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QFloat *qfloat;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+
+        qfloat = qobject_to_qfloat(obj);
+        fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
+
+        if (test_cases[i].skip == 0) {
+            QString *str;
+
+            str = qobject_to_json(obj);
+            fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+            QDECREF(str);
+        }
+
+        QDECREF(qfloat);
+    }
+}
+END_TEST
+
+START_TEST(vararg_number)
+{
+    QObject *obj;
+    QInt *qint;
+    QFloat *qfloat;
+    int value = 0x2342;
+    int64_t value64 = 0x2342342343LL;
+    double valuef = 2.323423423;
+
+    obj = qobject_from_jsonf("%d", value);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+    qint = qobject_to_qint(obj);
+    fail_unless(qint_get_int(qint) == value);
+
+    QDECREF(qint);
+
+    obj = qobject_from_jsonf("%" PRId64, value64);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QINT);
+
+    qint = qobject_to_qint(obj);
+    fail_unless(qint_get_int(qint) == value64);
+
+    QDECREF(qint);
+
+    obj = qobject_from_jsonf("%f", valuef);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
+
+    qfloat = qobject_to_qfloat(obj);
+    fail_unless(qfloat_get_double(qfloat) == valuef);
+
+    QDECREF(qfloat);
+}
+END_TEST
+
+START_TEST(keyword_literal)
+{
+    QObject *obj;
+    QBool *qbool;
+    QString *str;
+
+    obj = qobject_from_json("true");
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) != 0);
+
+    str = qobject_to_json(obj);
+    fail_unless(strcmp(qstring_get_str(str), "true") == 0);
+    QDECREF(str);
+
+    QDECREF(qbool);
+
+    obj = qobject_from_json("false");
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) == 0);
+
+    str = qobject_to_json(obj);
+    fail_unless(strcmp(qstring_get_str(str), "false") == 0);
+    QDECREF(str);
+
+    QDECREF(qbool);
+
+    obj = qobject_from_jsonf("%i", false);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) == 0);
+
+    QDECREF(qbool);
+    
+    obj = qobject_from_jsonf("%i", true);
+    fail_unless(obj != NULL);
+    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
+
+    qbool = qobject_to_qbool(obj);
+    fail_unless(qbool_get_int(qbool) != 0);
+
+    QDECREF(qbool);
+}
+END_TEST
+
+typedef struct LiteralQDictEntry LiteralQDictEntry;
+typedef struct LiteralQObject LiteralQObject;
+
+struct LiteralQObject
+{
+    int type;
+    union {
+        int64_t qint;
+        const char *qstr;
+        LiteralQDictEntry *qdict;
+        LiteralQObject *qlist;
+    } value;
+};
+
+struct LiteralQDictEntry
+{
+    const char *key;
+    LiteralQObject value;
+};
+
+#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
+#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
+#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
+#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
+
+typedef struct QListCompareHelper
+{
+    int index;
+    LiteralQObject *objs;
+    int result;
+} QListCompareHelper;
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
+
+static void compare_helper(QObject *obj, void *opaque)
+{
+    QListCompareHelper *helper = opaque;
+
+    if (helper->result == 0) {
+        return;
+    }
+
+    if (helper->objs[helper->index].type == QTYPE_NONE) {
+        helper->result = 0;
+        return;
+    }
+
+    helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
+}
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
+{
+    if (lhs->type != qobject_type(rhs)) {
+        return 0;
+    }
+
+    switch (lhs->type) {
+    case QTYPE_QINT:
+        return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
+    case QTYPE_QSTRING:
+        return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
+    case QTYPE_QDICT: {
+        int i;
+
+        for (i = 0; lhs->value.qdict[i].key; i++) {
+            QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
+
+            if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
+                return 0;
+            }
+        }
+
+        return 1;
+    }
+    case QTYPE_QLIST: {
+        QListCompareHelper helper;
+
+        helper.index = 0;
+        helper.objs = lhs->value.qlist;
+        helper.result = 1;
+        
+        qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
+
+        return helper.result;
+    }
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+START_TEST(simple_dict)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { "foo", QLIT_QINT(42) },
+                        { "bar", QLIT_QSTR("hello world") },
+                        { }
+                    })),
+        }, {
+            .encoded = "{}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { }
+                    })),
+        }, {
+            .encoded = "{\"foo\": 43}",
+            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+                        { "foo", QLIT_QINT(43) },
+                        { }
+                    })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QDICT);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        str = qobject_to_json(obj);
+        qobject_decref(obj);
+
+        obj = qobject_from_json(qstring_get_str(str));
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QDICT);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+        qobject_decref(obj);
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_list)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = "[43,42]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = "[43]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        { }
+                    })),
+        },
+        {
+            .encoded = "[]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        { }
+                    })),
+        },
+        {
+            .encoded = "[{}]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QDICT(((LiteralQDictEntry[]){
+                                    {},
+                                        })),
+                        {},
+                            })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        str = qobject_to_json(obj);
+        qobject_decref(obj);
+
+        obj = qobject_from_json(qstring_get_str(str));
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+        qobject_decref(obj);
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_whitespace)
+{
+    int i;
+    struct {
+        const char *encoded;
+        LiteralQObject decoded;
+    } test_cases[] = {
+        {
+            .encoded = " [ 43 , 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QDICT(((LiteralQDictEntry[]){
+                                    { "h", QLIT_QSTR("b") },
+                                    { }})),
+                        QLIT_QLIST(((LiteralQObject[]){
+                                    { }})),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        {
+            .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
+            .decoded = QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(43),
+                        QLIT_QDICT(((LiteralQDictEntry[]){
+                                    { "h", QLIT_QSTR("b") },
+                                    { "a", QLIT_QINT(32) },
+                                    { }})),
+                        QLIT_QLIST(((LiteralQObject[]){
+                                    { }})),
+                        QLIT_QINT(42),
+                        { }
+                    })),
+        },
+        { }
+    };
+
+    for (i = 0; test_cases[i].encoded; i++) {
+        QObject *obj;
+        QString *str;
+
+        obj = qobject_from_json(test_cases[i].encoded);
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        str = qobject_to_json(obj);
+        qobject_decref(obj);
+
+        obj = qobject_from_json(qstring_get_str(str));
+        fail_unless(obj != NULL);
+        fail_unless(qobject_type(obj) == QTYPE_QLIST);
+
+        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+        qobject_decref(obj);
+        QDECREF(str);
+    }
+}
+END_TEST
+
+START_TEST(simple_varargs)
+{
+    QObject *embedded_obj;
+    QObject *obj;
+    LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
+            QLIT_QINT(1),
+            QLIT_QINT(2),
+            QLIT_QLIST(((LiteralQObject[]){
+                        QLIT_QINT(32),
+                        QLIT_QINT(42),
+                        {}})),
+            {}}));
+
+    embedded_obj = qobject_from_json("[32, 42]");
+    fail_unless(embedded_obj != NULL);
+
+    obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
+    fail_unless(obj != NULL);
+
+    fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
+
+    qobject_decref(obj);
+}
+END_TEST
+
+START_TEST(empty_input)
+{
+    const char *empty = "";
+
+    QObject *obj = qobject_from_json(empty);
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_string)
+{
+    QObject *obj = qobject_from_json("\"abc");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_sq_string)
+{
+    QObject *obj = qobject_from_json("'abc");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_escape)
+{
+    QObject *obj = qobject_from_json("\"abc\\\"");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_array)
+{
+    QObject *obj = qobject_from_json("[32");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_array_comma)
+{
+    QObject *obj = qobject_from_json("[32,");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(invalid_array_comma)
+{
+    QObject *obj = qobject_from_json("[32,}");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_dict)
+{
+    QObject *obj = qobject_from_json("{'abc':32");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_dict_comma)
+{
+    QObject *obj = qobject_from_json("{'abc':32,");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+#if 0
+START_TEST(invalid_dict_comma)
+{
+    QObject *obj = qobject_from_json("{'abc':32,}");
+    fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_literal)
+{
+    QObject *obj = qobject_from_json("nul");
+    fail_unless(obj == NULL);
+}
+END_TEST
+#endif
+
+static Suite *qjson_suite(void)
+{
+    Suite *suite;
+    TCase *string_literals, *number_literals, *keyword_literals;
+    TCase *dicts, *lists, *whitespace, *varargs, *errors;
+
+    string_literals = tcase_create("String Literals");
+    tcase_add_test(string_literals, simple_string);
+    tcase_add_test(string_literals, escaped_string);
+    tcase_add_test(string_literals, single_quote_string);
+    tcase_add_test(string_literals, vararg_string);
+
+    number_literals = tcase_create("Number Literals");
+    tcase_add_test(number_literals, simple_number);
+    tcase_add_test(number_literals, float_number);
+    tcase_add_test(number_literals, vararg_number);
+
+    keyword_literals = tcase_create("Keywords");
+    tcase_add_test(keyword_literals, keyword_literal);
+    dicts = tcase_create("Objects");
+    tcase_add_test(dicts, simple_dict);
+    lists = tcase_create("Lists");
+    tcase_add_test(lists, simple_list);
+
+    whitespace = tcase_create("Whitespace");
+    tcase_add_test(whitespace, simple_whitespace);
+
+    varargs = tcase_create("Varargs");
+    tcase_add_test(varargs, simple_varargs);
+
+    errors = tcase_create("Invalid JSON");
+    tcase_add_test(errors, empty_input);
+    tcase_add_test(errors, unterminated_string);
+    tcase_add_test(errors, unterminated_escape);
+    tcase_add_test(errors, unterminated_sq_string);
+    tcase_add_test(errors, unterminated_array);
+    tcase_add_test(errors, unterminated_array_comma);
+    tcase_add_test(errors, invalid_array_comma);
+    tcase_add_test(errors, unterminated_dict);
+    tcase_add_test(errors, unterminated_dict_comma);
+#if 0
+    /* FIXME: this print parse error messages on stderr.  */
+    tcase_add_test(errors, invalid_dict_comma);
+    tcase_add_test(errors, unterminated_literal);
+#endif
+
+    suite = suite_create("QJSON test-suite");
+    suite_add_tcase(suite, string_literals);
+    suite_add_tcase(suite, number_literals);
+    suite_add_tcase(suite, keyword_literals);
+    suite_add_tcase(suite, dicts);
+    suite_add_tcase(suite, lists);
+    suite_add_tcase(suite, whitespace);
+    suite_add_tcase(suite, varargs);
+    suite_add_tcase(suite, errors);
+
+    return suite;
+}
+
+int main(void)
+{
+    int nf;
+    Suite *s;
+    SRunner *sr;
+
+    s = qjson_suite();
+    sr = srunner_create(s);
+        
+    srunner_run_all(sr, CK_NORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/check-qlist.c b/qemu-0.15.x/check-qlist.c
new file mode 100644
index 0000000..58984cb
--- /dev/null
+++ b/qemu-0.15.x/check-qlist.c
@@ -0,0 +1,153 @@
+/*
+ * QList unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <check.h>
+
+#include "qint.h"
+#include "qlist.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qlist_new_test)
+{
+    QList *qlist;
+
+    qlist = qlist_new();
+    fail_unless(qlist != NULL);
+    fail_unless(qlist->base.refcnt == 1);
+    fail_unless(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
+
+    // destroy doesn't exist yet
+    qemu_free(qlist);
+}
+END_TEST
+
+START_TEST(qlist_append_test)
+{
+    QInt *qi;
+    QList *qlist;
+    QListEntry *entry;
+
+    qi = qint_from_int(42);
+
+    qlist = qlist_new();
+    qlist_append(qlist, qi);
+
+    entry = QTAILQ_FIRST(&qlist->head);
+    fail_unless(entry != NULL);
+    fail_unless(entry->value == QOBJECT(qi));
+
+    // destroy doesn't exist yet
+    QDECREF(qi);
+    qemu_free(entry);
+    qemu_free(qlist);
+}
+END_TEST
+
+START_TEST(qobject_to_qlist_test)
+{
+    QList *qlist;
+
+    qlist = qlist_new();
+
+    fail_unless(qobject_to_qlist(QOBJECT(qlist)) == qlist);
+
+    // destroy doesn't exist yet
+    qemu_free(qlist);
+}
+END_TEST
+
+START_TEST(qlist_destroy_test)
+{
+    int i;
+    QList *qlist;
+
+    qlist = qlist_new();
+
+    for (i = 0; i < 42; i++)
+        qlist_append(qlist, qint_from_int(i));
+
+    QDECREF(qlist);
+}
+END_TEST
+
+static int iter_called;
+static const int iter_max = 42;
+
+static void iter_func(QObject *obj, void *opaque)
+{
+    QInt *qi;
+
+    fail_unless(opaque == NULL);
+
+    qi = qobject_to_qint(obj);
+    fail_unless(qi != NULL);
+    fail_unless((qint_get_int(qi) >= 0) && (qint_get_int(qi) <= iter_max));
+
+    iter_called++;
+}
+
+START_TEST(qlist_iter_test)
+{
+    int i;
+    QList *qlist;
+
+    qlist = qlist_new();
+
+    for (i = 0; i < iter_max; i++)
+        qlist_append(qlist, qint_from_int(i));
+
+    iter_called = 0;
+    qlist_iter(qlist, iter_func, NULL);
+
+    fail_unless(iter_called == iter_max);
+
+    QDECREF(qlist);
+}
+END_TEST
+
+static Suite *QList_suite(void)
+{
+    Suite *s;
+    TCase *qlist_public_tcase;
+
+    s = suite_create("QList suite");
+
+    qlist_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qlist_public_tcase);
+    tcase_add_test(qlist_public_tcase, qlist_new_test);
+    tcase_add_test(qlist_public_tcase, qlist_append_test);
+    tcase_add_test(qlist_public_tcase, qobject_to_qlist_test);
+    tcase_add_test(qlist_public_tcase, qlist_destroy_test);
+    tcase_add_test(qlist_public_tcase, qlist_iter_test);
+
+    return s;
+}
+
+int main(void)
+{
+	int nf;
+	Suite *s;
+	SRunner *sr;
+
+	s = QList_suite();
+	sr = srunner_create(s);
+
+	srunner_run_all(sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/check-qstring.c b/qemu-0.15.x/check-qstring.c
new file mode 100644
index 0000000..c9bafc2
--- /dev/null
+++ b/qemu-0.15.x/check-qstring.c
@@ -0,0 +1,134 @@
+/*
+ * QString unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <check.h>
+
+#include "qstring.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+START_TEST(qstring_from_str_test)
+{
+    QString *qstring;
+    const char *str = "QEMU";
+
+    qstring = qstring_from_str(str);
+    fail_unless(qstring != NULL);
+    fail_unless(qstring->base.refcnt == 1);
+    fail_unless(strcmp(str, qstring->string) == 0);
+    fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
+
+    // destroy doesn't exit yet
+    qemu_free(qstring->string);
+    qemu_free(qstring);
+}
+END_TEST
+
+START_TEST(qstring_destroy_test)
+{
+    QString *qstring = qstring_from_str("destroy test");
+    QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_get_str_test)
+{
+    QString *qstring;
+    const char *ret_str;
+    const char *str = "QEMU/KVM";
+
+    qstring = qstring_from_str(str);
+    ret_str = qstring_get_str(qstring);
+    fail_unless(strcmp(ret_str, str) == 0);
+
+    QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_append_chr_test)
+{
+    int i;
+    QString *qstring;
+    const char *str = "qstring append char unit-test";
+
+    qstring = qstring_new();
+
+    for (i = 0; str[i]; i++)
+        qstring_append_chr(qstring, str[i]);
+
+    fail_unless(strcmp(str, qstring_get_str(qstring)) == 0);
+    QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_from_substr_test)
+{
+    QString *qs;
+
+    qs = qstring_from_substr("virtualization", 3, 9);
+    fail_unless(qs != NULL);
+    fail_unless(strcmp(qstring_get_str(qs), "tualiza") == 0);
+
+    QDECREF(qs);
+}
+END_TEST
+
+
+START_TEST(qobject_to_qstring_test)
+{
+    QString *qstring;
+
+    qstring = qstring_from_str("foo");
+    fail_unless(qobject_to_qstring(QOBJECT(qstring)) == qstring);
+
+    QDECREF(qstring);
+}
+END_TEST
+
+static Suite *qstring_suite(void)
+{
+    Suite *s;
+    TCase *qstring_public_tcase;
+
+    s = suite_create("QString test-suite");
+
+    qstring_public_tcase = tcase_create("Public Interface");
+    suite_add_tcase(s, qstring_public_tcase);
+    tcase_add_test(qstring_public_tcase, qstring_from_str_test);
+    tcase_add_test(qstring_public_tcase, qstring_destroy_test);
+    tcase_add_test(qstring_public_tcase, qstring_get_str_test);
+    tcase_add_test(qstring_public_tcase, qstring_append_chr_test);
+    tcase_add_test(qstring_public_tcase, qstring_from_substr_test);
+    tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
+
+    return s;
+}
+
+int main(void)
+{
+	int nf;
+	Suite *s;
+	SRunner *sr;
+
+	s = qstring_suite();
+	sr = srunner_create(s);
+
+	srunner_run_all(sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/cmd.c b/qemu-0.15.x/cmd.c
new file mode 100644
index 0000000..ecca167
--- /dev/null
+++ b/qemu-0.15.x/cmd.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <getopt.h>
+
+#include "cmd.h"
+#include "qemu-aio.h"
+
+#define _(x)	x	/* not gettext support yet */
+
+/* from libxcmd/command.c */
+
+cmdinfo_t	*cmdtab;
+int		ncmds;
+
+static argsfunc_t	args_func;
+static checkfunc_t	check_func;
+static int		ncmdline;
+static char		**cmdline;
+
+static int
+compare(const void *a, const void *b)
+{
+	return strcmp(((const cmdinfo_t *)a)->name,
+		      ((const cmdinfo_t *)b)->name);
+}
+
+void
+add_command(
+	const cmdinfo_t	*ci)
+{
+	cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
+	cmdtab[ncmds - 1] = *ci;
+	qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
+}
+
+static int
+check_command(
+	const cmdinfo_t	*ci)
+{
+	if (check_func)
+		return check_func(ci);
+	return 1;
+}
+
+void
+add_check_command(
+	checkfunc_t	cf)
+{
+	check_func = cf;
+}
+
+int
+command_usage(
+	const cmdinfo_t *ci)
+{
+	printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
+	return 0;
+}
+
+int
+command(
+	const cmdinfo_t	*ct,
+	int		argc,
+	char		**argv)
+{
+	char		*cmd = argv[0];
+
+	if (!check_command(ct))
+		return 0;
+
+	if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
+		if (ct->argmax == -1)
+			fprintf(stderr,
+	_("bad argument count %d to %s, expected at least %d arguments\n"),
+				argc-1, cmd, ct->argmin);
+		else if (ct->argmin == ct->argmax)
+			fprintf(stderr,
+	_("bad argument count %d to %s, expected %d arguments\n"),
+				argc-1, cmd, ct->argmin);
+		else
+			fprintf(stderr,
+	_("bad argument count %d to %s, expected between %d and %d arguments\n"),
+			argc-1, cmd, ct->argmin, ct->argmax);
+		return 0;
+	}
+	optind = 0;
+	return ct->cfunc(argc, argv);
+}
+
+const cmdinfo_t *
+find_command(
+	const char	*cmd)
+{
+	cmdinfo_t	*ct;
+
+	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
+		if (strcmp(ct->name, cmd) == 0 ||
+		    (ct->altname && strcmp(ct->altname, cmd) == 0))
+			return (const cmdinfo_t *)ct;
+	}
+	return NULL;
+}
+
+void
+add_user_command(char *optarg)
+{
+	ncmdline++;
+	cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
+	if (!cmdline) {
+		perror("realloc");
+		exit(1);
+	}
+	cmdline[ncmdline-1] = optarg;
+}
+
+static int
+args_command(
+	int	index)
+{
+	if (args_func)
+		return args_func(index);
+	return 0;
+}
+
+void
+add_args_command(
+	argsfunc_t	af)
+{
+	args_func = af;
+}
+
+static void prep_fetchline(void *opaque)
+{
+    int *fetchable = opaque;
+
+    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    *fetchable= 1;
+}
+
+static char *get_prompt(void);
+
+void
+command_loop(void)
+{
+	int		c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
+	char		*input;
+	char		**v;
+	const cmdinfo_t	*ct;
+
+	for (i = 0; !done && i < ncmdline; i++) {
+		input = strdup(cmdline[i]);
+		if (!input) {
+			fprintf(stderr,
+				_("cannot strdup command '%s': %s\n"),
+				cmdline[i], strerror(errno));
+			exit(1);
+		}
+		v = breakline(input, &c);
+		if (c) {
+			ct = find_command(v[0]);
+			if (ct) {
+				if (ct->flags & CMD_FLAG_GLOBAL)
+					done = command(ct, c, v);
+				else {
+					j = 0;
+					while (!done && (j = args_command(j)))
+						done = command(ct, c, v);
+				}
+			} else
+				fprintf(stderr, _("command \"%s\" not found\n"),
+					v[0]);
+		}
+		doneline(input, v);
+	}
+	if (cmdline) {
+		free(cmdline);
+		return;
+	}
+
+	while (!done) {
+        if (!prompted) {
+            printf("%s", get_prompt());
+            fflush(stdout);
+            qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
+                                    NULL, &fetchable);
+            prompted = 1;
+        }
+
+        qemu_aio_wait();
+
+        if (!fetchable) {
+            continue;
+        }
+		if ((input = fetchline()) == NULL)
+			break;
+		v = breakline(input, &c);
+		if (c) {
+			ct = find_command(v[0]);
+			if (ct)
+				done = command(ct, c, v);
+			else
+				fprintf(stderr, _("command \"%s\" not found\n"),
+					v[0]);
+		}
+		doneline(input, v);
+
+        prompted = 0;
+        fetchable = 0;
+	}
+    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+}
+
+/* from libxcmd/input.c */
+
+#if defined(ENABLE_READLINE)
+# include <readline/history.h>
+# include <readline/readline.h>
+#elif defined(ENABLE_EDITLINE)
+# include <histedit.h>
+#endif
+
+static char *
+get_prompt(void)
+{
+	static char	prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
+
+	if (!prompt[0])
+		snprintf(prompt, sizeof(prompt), "%s> ", progname);
+	return prompt;
+}
+
+#if defined(ENABLE_READLINE)
+char *
+fetchline(void)
+{
+	char	*line;
+
+	line = readline(get_prompt());
+	if (line && *line)
+		add_history(line);
+	return line;
+}
+#elif defined(ENABLE_EDITLINE)
+static char *el_get_prompt(EditLine *e) { return get_prompt(); }
+char *
+fetchline(void)
+{
+	static EditLine	*el;
+	static History	*hist;
+	HistEvent	hevent;
+	char		*line;
+	int		count;
+
+	if (!el) {
+		hist = history_init();
+		history(hist, &hevent, H_SETSIZE, 100);
+		el = el_init(progname, stdin, stdout, stderr);
+		el_source(el, NULL);
+		el_set(el, EL_SIGNAL, 1);
+		el_set(el, EL_PROMPT, el_get_prompt);
+		el_set(el, EL_HIST, history, (const char *)hist);
+	}
+	line = strdup(el_gets(el, &count));
+	if (line) {
+		if (count > 0)
+			line[count-1] = '\0';
+		if (*line)
+			history(hist, &hevent, H_ENTER, line);
+	}
+	return line;
+}
+#else
+# define MAXREADLINESZ	1024
+char *
+fetchline(void)
+{
+	char	*p, *line = malloc(MAXREADLINESZ);
+
+	if (!line)
+		return NULL;
+	if (!fgets(line, MAXREADLINESZ, stdin)) {
+		free(line);
+		return NULL;
+	}
+	p = line + strlen(line);
+	if (p != line && p[-1] == '\n')
+		p[-1] = '\0';
+	return line;
+}
+#endif
+
+static char *qemu_strsep(char **input, const char *delim)
+{
+    char *result = *input;
+    if (result != NULL) {
+        char *p;
+
+        for (p = result; *p != '\0'; p++) {
+            if (strchr(delim, *p)) {
+                break;
+            }
+        }
+        if (*p == '\0') {
+            *input = NULL;
+        } else {
+            *p = '\0';
+            *input = p + 1;
+        }
+    }
+    return result;
+}
+
+char **
+breakline(
+	char	*input,
+	int	*count)
+{
+	int	c = 0;
+	char	*p;
+	char	**rval = calloc(sizeof(char *), 1);
+
+	while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
+		if (!*p)
+			continue;
+		c++;
+		rval = realloc(rval, sizeof(*rval) * (c + 1));
+		if (!rval) {
+			c = 0;
+			break;
+		}
+		rval[c - 1] = p;
+		rval[c] = NULL;
+	}
+	*count = c;
+	return rval;
+}
+
+void
+doneline(
+	char	*input,
+	char	**vec)
+{
+	free(input);
+	free(vec);
+}
+
+#define EXABYTES(x)	((long long)(x) << 60)
+#define PETABYTES(x)	((long long)(x) << 50)
+#define TERABYTES(x)	((long long)(x) << 40)
+#define GIGABYTES(x)	((long long)(x) << 30)
+#define MEGABYTES(x)	((long long)(x) << 20)
+#define KILOBYTES(x)	((long long)(x) << 10)
+
+long long
+cvtnum(
+	char		*s)
+{
+	long long	i;
+	char		*sp;
+	int		c;
+
+	i = strtoll(s, &sp, 0);
+	if (i == 0 && sp == s)
+		return -1LL;
+	if (*sp == '\0')
+		return i;
+
+	if (sp[1] != '\0')
+		return -1LL;
+
+	c = tolower(*sp);
+	switch (c) {
+	default:
+		return i;
+	case 'k':
+		return KILOBYTES(i);
+	case 'm':
+		return MEGABYTES(i);
+	case 'g':
+		return GIGABYTES(i);
+	case 't':
+		return TERABYTES(i);
+	case 'p':
+		return PETABYTES(i);
+	case 'e':
+		return  EXABYTES(i);
+	}
+	return -1LL;
+}
+
+#define TO_EXABYTES(x)	((x) / EXABYTES(1))
+#define TO_PETABYTES(x)	((x) / PETABYTES(1))
+#define TO_TERABYTES(x)	((x) / TERABYTES(1))
+#define TO_GIGABYTES(x)	((x) / GIGABYTES(1))
+#define TO_MEGABYTES(x)	((x) / MEGABYTES(1))
+#define TO_KILOBYTES(x)	((x) / KILOBYTES(1))
+
+void
+cvtstr(
+	double		value,
+	char		*str,
+	size_t		size)
+{
+	const char	*fmt;
+	int		precise;
+
+	precise = ((double)value * 1000 == (double)(int)value * 1000);
+
+	if (value >= EXABYTES(1)) {
+		fmt = precise ? "%.f EiB" : "%.3f EiB";
+		snprintf(str, size, fmt, TO_EXABYTES(value));
+	} else if (value >= PETABYTES(1)) {
+		fmt = precise ? "%.f PiB" : "%.3f PiB";
+		snprintf(str, size, fmt, TO_PETABYTES(value));
+	} else if (value >= TERABYTES(1)) {
+		fmt = precise ? "%.f TiB" : "%.3f TiB";
+		snprintf(str, size, fmt, TO_TERABYTES(value));
+	} else if (value >= GIGABYTES(1)) {
+		fmt = precise ? "%.f GiB" : "%.3f GiB";
+		snprintf(str, size, fmt, TO_GIGABYTES(value));
+	} else if (value >= MEGABYTES(1)) {
+		fmt = precise ? "%.f MiB" : "%.3f MiB";
+		snprintf(str, size, fmt, TO_MEGABYTES(value));
+	} else if (value >= KILOBYTES(1)) {
+		fmt = precise ? "%.f KiB" : "%.3f KiB";
+		snprintf(str, size, fmt, TO_KILOBYTES(value));
+	} else {
+		snprintf(str, size, "%f bytes", value);
+	}
+}
+
+struct timeval
+tsub(struct timeval t1, struct timeval t2)
+{
+	t1.tv_usec -= t2.tv_usec;
+	if (t1.tv_usec < 0) {
+		t1.tv_usec += 1000000;
+		t1.tv_sec--;
+	}
+	t1.tv_sec -= t2.tv_sec;
+	return t1;
+}
+
+double
+tdiv(double value, struct timeval tv)
+{
+	return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
+}
+
+#define HOURS(sec)	((sec) / (60 * 60))
+#define MINUTES(sec)	(((sec) % (60 * 60)) / 60)
+#define SECONDS(sec)	((sec) % 60)
+
+void
+timestr(
+	struct timeval	*tv,
+	char		*ts,
+	size_t		size,
+	int		format)
+{
+	double		usec = (double)tv->tv_usec / 1000000.0;
+
+	if (format & TERSE_FIXED_TIME) {
+		if (!HOURS(tv->tv_sec)) {
+			snprintf(ts, size, "%u:%02u.%02u",
+				(unsigned int) MINUTES(tv->tv_sec),
+				(unsigned int) SECONDS(tv->tv_sec),
+				(unsigned int) (usec * 100));
+			return;
+		}
+		format |= VERBOSE_FIXED_TIME;	/* fallback if hours needed */
+	}
+
+	if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
+		snprintf(ts, size, "%u:%02u:%02u.%02u",
+			(unsigned int) HOURS(tv->tv_sec),
+			(unsigned int) MINUTES(tv->tv_sec),
+			(unsigned int) SECONDS(tv->tv_sec),
+			(unsigned int) (usec * 100));
+	} else {
+		snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
+	}
+}
+
+
+/* from libxcmd/quit.c */
+
+static cmdinfo_t quit_cmd;
+
+/* ARGSUSED */
+static int
+quit_f(
+	int	argc,
+	char	**argv)
+{
+	return 1;
+}
+
+void
+quit_init(void)
+{
+	quit_cmd.name = _("quit");
+	quit_cmd.altname = _("q");
+	quit_cmd.cfunc = quit_f;
+	quit_cmd.argmin = -1;
+	quit_cmd.argmax = -1;
+	quit_cmd.flags = CMD_FLAG_GLOBAL;
+	quit_cmd.oneline = _("exit the program");
+
+	add_command(&quit_cmd);
+}
+
+/* from libxcmd/help.c */
+
+static cmdinfo_t help_cmd;
+static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
+static void help_oneline(const char *cmd, const cmdinfo_t *ct);
+
+static void
+help_all(void)
+{
+	const cmdinfo_t	*ct;
+
+	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
+		help_oneline(ct->name, ct);
+	printf(_("\nUse 'help commandname' for extended help.\n"));
+}
+
+static int
+help_f(
+	int		argc,
+	char		**argv)
+{
+	const cmdinfo_t	*ct;
+
+	if (argc == 1) {
+		help_all();
+		return 0;
+	}
+	ct = find_command(argv[1]);
+	if (ct == NULL) {
+		printf(_("command %s not found\n"), argv[1]);
+		return 0;
+	}
+	help_onecmd(argv[1], ct);
+	return 0;
+}
+
+static void
+help_onecmd(
+	const char	*cmd,
+	const cmdinfo_t	*ct)
+{
+	help_oneline(cmd, ct);
+	if (ct->help)
+		ct->help();
+}
+
+static void
+help_oneline(
+	const char	*cmd,
+	const cmdinfo_t	*ct)
+{
+	if (cmd)
+		printf("%s ", cmd);
+	else {
+		printf("%s ", ct->name);
+		if (ct->altname)
+			printf("(or %s) ", ct->altname);
+	}
+	if (ct->args)
+		printf("%s ", ct->args);
+	printf("-- %s\n", ct->oneline);
+}
+
+void
+help_init(void)
+{
+	help_cmd.name = _("help");
+	help_cmd.altname = _("?");
+	help_cmd.cfunc = help_f;
+	help_cmd.argmin = 0;
+	help_cmd.argmax = 1;
+	help_cmd.flags = CMD_FLAG_GLOBAL;
+	help_cmd.args = _("[command]");
+	help_cmd.oneline = _("help for one or all commands");
+
+	add_command(&help_cmd);
+}
diff --git a/qemu-0.15.x/cmd.h b/qemu-0.15.x/cmd.h
new file mode 100644
index 0000000..b763b19
--- /dev/null
+++ b/qemu-0.15.x/cmd.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __COMMAND_H__
+#define __COMMAND_H__
+
+#define CMD_FLAG_GLOBAL	((int)0x80000000)	/* don't iterate "args" */
+
+typedef int (*cfunc_t)(int argc, char **argv);
+typedef void (*helpfunc_t)(void);
+
+typedef struct cmdinfo {
+	const char	*name;
+	const char	*altname;
+	cfunc_t		cfunc;
+	int		argmin;
+	int		argmax;
+	int		canpush;
+	int		flags;
+	const char	*args;
+	const char	*oneline;
+	helpfunc_t      help;
+} cmdinfo_t;
+
+extern cmdinfo_t	*cmdtab;
+extern int		ncmds;
+
+void help_init(void);
+void quit_init(void);
+
+typedef int (*argsfunc_t)(int index);
+typedef int (*checkfunc_t)(const cmdinfo_t *ci);
+
+void add_command(const cmdinfo_t *ci);
+void add_user_command(char *optarg);
+void add_args_command(argsfunc_t af);
+void add_check_command(checkfunc_t cf);
+
+const cmdinfo_t *find_command(const char *cmd);
+
+void command_loop(void);
+int command_usage(const cmdinfo_t *ci);
+int command(const cmdinfo_t *ci, int argc, char **argv);
+
+/* from input.h */
+char **breakline(char *input, int *count);
+void doneline(char *input, char **vec);
+char *fetchline(void);
+
+long long cvtnum(char *s);
+void cvtstr(double value, char *str, size_t sz);
+
+struct timeval tsub(struct timeval t1, struct timeval t2);
+double tdiv(double value, struct timeval tv);
+
+enum {
+	DEFAULT_TIME		= 0x0,
+	TERSE_FIXED_TIME	= 0x1,
+	VERBOSE_FIXED_TIME	= 0x2
+};
+
+void timestr(struct timeval *tv, char *str, size_t sz, int flags);
+
+extern char *progname;
+
+#endif	/* __COMMAND_H__ */
diff --git a/qemu-0.15.x/compatfd.c b/qemu-0.15.x/compatfd.c
new file mode 100644
index 0000000..31654c6
--- /dev/null
+++ b/qemu-0.15.x/compatfd.c
@@ -0,0 +1,128 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "compatfd.h"
+
+#include <sys/syscall.h>
+#include <pthread.h>
+
+struct sigfd_compat_info
+{
+    sigset_t mask;
+    int fd;
+};
+
+static void *sigwait_compat(void *opaque)
+{
+    struct sigfd_compat_info *info = opaque;
+    sigset_t all;
+
+    sigfillset(&all);
+    pthread_sigmask(SIG_BLOCK, &all, NULL);
+
+    while (1) {
+        int sig;
+        int err;
+
+        err = sigwait(&info->mask, &sig);
+        if (err != 0) {
+            if (errno == EINTR) {
+                continue;
+            } else {
+                return NULL;
+            }
+        } else {
+            struct qemu_signalfd_siginfo buffer;
+            size_t offset = 0;
+
+            memset(&buffer, 0, sizeof(buffer));
+            buffer.ssi_signo = sig;
+
+            while (offset < sizeof(buffer)) {
+                ssize_t len;
+
+                len = write(info->fd, (char *)&buffer + offset,
+                            sizeof(buffer) - offset);
+                if (len == -1 && errno == EINTR)
+                    continue;
+
+                if (len <= 0) {
+                    return NULL;
+                }
+
+                offset += len;
+            }
+        }
+    }
+}
+
+static int qemu_signalfd_compat(const sigset_t *mask)
+{
+    pthread_attr_t attr;
+    pthread_t tid;
+    struct sigfd_compat_info *info;
+    int fds[2];
+
+    info = malloc(sizeof(*info));
+    if (info == NULL) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    if (pipe(fds) == -1) {
+        free(info);
+        return -1;
+    }
+
+    qemu_set_cloexec(fds[0]);
+    qemu_set_cloexec(fds[1]);
+
+    memcpy(&info->mask, mask, sizeof(*mask));
+    info->fd = fds[1];
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    pthread_create(&tid, &attr, sigwait_compat, info);
+
+    pthread_attr_destroy(&attr);
+
+    return fds[0];
+}
+
+int qemu_signalfd(const sigset_t *mask)
+{
+#if defined(CONFIG_SIGNALFD)
+    int ret;
+
+    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
+    if (ret != -1) {
+        qemu_set_cloexec(ret);
+        return ret;
+    }
+#endif
+
+    return qemu_signalfd_compat(mask);
+}
+
+bool qemu_signalfd_available(void)
+{
+#ifdef CONFIG_SIGNALFD
+    errno = 0;
+    syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
+    return errno != ENOSYS;
+#else
+    return false;
+#endif
+}
diff --git a/qemu-0.15.x/compatfd.h b/qemu-0.15.x/compatfd.h
new file mode 100644
index 0000000..6b04877
--- /dev/null
+++ b/qemu-0.15.x/compatfd.h
@@ -0,0 +1,44 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_COMPATFD_H
+#define QEMU_COMPATFD_H
+
+#include <signal.h>
+
+struct qemu_signalfd_siginfo {
+    uint32_t ssi_signo;   /* Signal number */
+    int32_t  ssi_errno;   /* Error number (unused) */
+    int32_t  ssi_code;    /* Signal code */
+    uint32_t ssi_pid;     /* PID of sender */
+    uint32_t ssi_uid;     /* Real UID of sender */
+    int32_t  ssi_fd;      /* File descriptor (SIGIO) */
+    uint32_t ssi_tid;     /* Kernel timer ID (POSIX timers) */
+    uint32_t ssi_band;    /* Band event (SIGIO) */
+    uint32_t ssi_overrun; /* POSIX timer overrun count */
+    uint32_t ssi_trapno;  /* Trap number that caused signal */
+    int32_t  ssi_status;  /* Exit status or signal (SIGCHLD) */
+    int32_t  ssi_int;     /* Integer sent by sigqueue(2) */
+    uint64_t ssi_ptr;     /* Pointer sent by sigqueue(2) */
+    uint64_t ssi_utime;   /* User CPU time consumed (SIGCHLD) */
+    uint64_t ssi_stime;   /* System CPU time consumed (SIGCHLD) */
+    uint64_t ssi_addr;    /* Address that generated signal
+                             (for hardware-generated signals) */
+    uint8_t  pad[48];     /* Pad size to 128 bytes (allow for
+                             additional fields in the future) */
+};
+
+int qemu_signalfd(const sigset_t *mask);
+bool qemu_signalfd_available(void);
+
+#endif
diff --git a/qemu-0.15.x/compiler.h b/qemu-0.15.x/compiler.h
new file mode 100644
index 0000000..9af5dc6
--- /dev/null
+++ b/qemu-0.15.x/compiler.h
@@ -0,0 +1,34 @@
+/* public domain */
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include "config-host.h"
+
+#define QEMU_NORETURN __attribute__ ((__noreturn__))
+#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
+#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define QEMU_WARN_UNUSED_RESULT
+#endif
+
+#define QEMU_BUILD_BUG_ON(x) \
+    typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
+
+#if defined __GNUC__
+# if (__GNUC__ < 4) || \
+     defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4)
+   /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
+#  define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
+#  define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
+# else
+   /* Use gnu_printf when supported (qemu uses standard format strings). */
+#  define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
+#  define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
+# endif
+#else
+#define GCC_ATTR /**/
+#define GCC_FMT_ATTR(n, m)
+#endif
+
+#endif /* COMPILER_H */
diff --git a/qemu-0.15.x/config.h b/qemu-0.15.x/config.h
new file mode 100644
index 0000000..e20f786
--- /dev/null
+++ b/qemu-0.15.x/config.h
@@ -0,0 +1,2 @@
+#include "config-host.h"
+#include "config-target.h"
diff --git a/qemu-0.15.x/configure b/qemu-0.15.x/configure
new file mode 100755
index 0000000..29d6212
--- /dev/null
+++ b/qemu-0.15.x/configure
@@ -0,0 +1,3637 @@
+#!/bin/sh
+#
+# qemu configure script (c) 2003 Fabrice Bellard
+#
+# set temporary file name
+if test ! -z "$TMPDIR" ; then
+    TMPDIR1="${TMPDIR}"
+elif test ! -z "$TEMPDIR" ; then
+    TMPDIR1="${TEMPDIR}"
+else
+    TMPDIR1="/tmp"
+fi
+
+TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
+TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
+TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
+
+# NB: do not call "exit" in the trap handler; this is buggy with some shells;
+# see <1285349658-3122-1-git-send-email-loic.minier at linaro.org>
+trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM
+rm -f config.log
+
+compile_object() {
+  echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
+  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
+}
+
+compile_prog() {
+  local_cflags="$1"
+  local_ldflags="$2"
+  echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
+  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
+}
+
+# symbolically link $1 to $2.  Portable version of "ln -sf".
+symlink() {
+  rm -f $2
+  ln -s $1 $2
+}
+
+# check whether a command is available to this shell (may be either an
+# executable or a builtin)
+has() {
+    type "$1" >/dev/null 2>&1
+}
+
+# search for an executable in PATH
+path_of() {
+    local_command="$1"
+    local_ifs="$IFS"
+    local_dir=""
+
+    # pathname has a dir component?
+    if [ "${local_command#*/}" != "$local_command" ]; then
+        if [ -x "$local_command" ] && [ ! -d "$local_command" ]; then
+            echo "$local_command"
+            return 0
+        fi
+    fi
+    if [ -z "$local_command" ]; then
+        return 1
+    fi
+
+    IFS=:
+    for local_dir in $PATH; do
+        if [ -x "$local_dir/$local_command" ] && [ ! -d "$local_dir/$local_command" ]; then
+            echo "$local_dir/$local_command"
+            IFS="${local_ifs:-$(printf ' \t\n')}"
+            return 0
+        fi
+    done
+    # not found
+    IFS="${local_ifs:-$(printf ' \t\n')}"
+    return 1
+}
+
+# default parameters
+source_path=`dirname "$0"`
+cpu=""
+interp_prefix="/usr/gnemul/qemu-%M"
+static="no"
+sparc_cpu=""
+cross_prefix=""
+audio_drv_list=""
+audio_card_list="ac97 es1370 sb16 hda"
+audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
+block_drv_whitelist=""
+host_cc="gcc"
+helper_cflags=""
+libs_softmmu=""
+libs_tools=""
+audio_pt_int=""
+audio_win_int=""
+cc_i386=i386-pc-linux-gnu-gcc
+
+target_list=""
+
+# Default value for a variable defining feature "foo".
+#  * foo="no"  feature will only be used if --enable-foo arg is given
+#  * foo=""    feature will be searched for, and if found, will be used
+#              unless --disable-foo is given
+#  * foo="yes" this value will only be set by --enable-foo flag.
+#              feature will searched for,
+#              if not found, configure exits with error
+#
+# Always add --enable-foo and --disable-foo command line args.
+# Distributions want to ensure that several features are compiled in, and it
+# is impossible without a --enable-foo that exits if a feature is not found.
+
+bluez=""
+brlapi=""
+curl=""
+curses=""
+docs=""
+fdt=""
+kvm=""
+nptl=""
+sdl=""
+vnc="yes"
+sparse="no"
+uuid=""
+vde=""
+vnc_tls=""
+vnc_sasl=""
+vnc_jpeg=""
+vnc_png=""
+vnc_thread="no"
+xen=""
+xen_ctrl_version=""
+linux_aio=""
+attr=""
+vhost_net=""
+xfs=""
+
+gprof="no"
+debug_tcg="no"
+debug_mon="no"
+debug="no"
+strip_opt="yes"
+bigendian="no"
+mingw32="no"
+EXESUF=""
+prefix="/usr/local"
+mandir="\${prefix}/share/man"
+datadir="\${prefix}/share/qemu"
+docdir="\${prefix}/share/doc/qemu"
+bindir="\${prefix}/bin"
+libdir="\${prefix}/lib"
+sysconfdir="\${prefix}/etc"
+confsuffix="/qemu"
+slirp="yes"
+fmod_lib=""
+fmod_inc=""
+oss_lib=""
+bsd="no"
+linux="no"
+solaris="no"
+profiler="no"
+cocoa="no"
+softmmu="yes"
+linux_user="no"
+darwin_user="no"
+bsd_user="no"
+guest_base=""
+uname_release=""
+io_thread="no"
+mixemu="no"
+aix="no"
+blobs="yes"
+pkgversion=""
+check_utests="no"
+user_pie="no"
+zero_malloc=""
+trace_backend="nop"
+trace_file="trace"
+spice=""
+rbd=""
+smartcard=""
+smartcard_nss=""
+usb_redir=""
+opengl=""
+guest_agent="yes"
+
+# parse CC options first
+for opt do
+  optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+  case "$opt" in
+  --cross-prefix=*) cross_prefix="$optarg"
+  ;;
+  --cc=*) CC="$optarg"
+  ;;
+  --source-path=*) source_path="$optarg"
+  ;;
+  --cpu=*) cpu="$optarg"
+  ;;
+  --extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS"
+  ;;
+  --extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS"
+  ;;
+  --sparc_cpu=*)
+    sparc_cpu="$optarg"
+    case $sparc_cpu in
+    v7|v8|v8plus|v8plusa)
+      cpu="sparc"
+    ;;
+    v9)
+      cpu="sparc64"
+    ;;
+    *)
+      echo "undefined SPARC architecture. Exiting";
+      exit 1
+    ;;
+    esac
+  ;;
+  esac
+done
+# OS specific
+# Using uname is really, really broken.  Once we have the right set of checks
+# we can eliminate it's usage altogether
+
+cc="${cross_prefix}${CC-gcc}"
+ar="${cross_prefix}${AR-ar}"
+objcopy="${cross_prefix}${OBJCOPY-objcopy}"
+ld="${cross_prefix}${LD-ld}"
+strip="${cross_prefix}${STRIP-strip}"
+windres="${cross_prefix}${WINDRES-windres}"
+pkg_config="${cross_prefix}${PKG_CONFIG-pkg-config}"
+sdl_config="${cross_prefix}${SDL_CONFIG-sdl-config}"
+
+# default flags for all hosts
+QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
+CFLAGS="-g $CFLAGS"
+QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
+QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
+QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_CFLAGS"
+QEMU_INCLUDES="-I. -I\$(SRC_PATH)"
+LDFLAGS="-g $LDFLAGS"
+
+# make source path absolute
+source_path=`cd "$source_path"; pwd`
+
+check_define() {
+cat > $TMPC <<EOF
+#if !defined($1)
+#error Not defined
+#endif
+int main(void) { return 0; }
+EOF
+  compile_object
+}
+
+if test ! -z "$cpu" ; then
+  # command line argument
+  :
+elif check_define __i386__ ; then
+  cpu="i386"
+elif check_define __x86_64__ ; then
+  cpu="x86_64"
+elif check_define __sparc__ ; then
+  # We can't check for 64 bit (when gcc is biarch) or V8PLUSA
+  # They must be specified using --sparc_cpu
+  if check_define __arch64__ ; then
+    cpu="sparc64"
+  else
+    cpu="sparc"
+  fi
+elif check_define _ARCH_PPC ; then
+  if check_define _ARCH_PPC64 ; then
+    cpu="ppc64"
+  else
+    cpu="ppc"
+  fi
+elif check_define __mips__ ; then
+  cpu="mips"
+elif check_define __ia64__ ; then
+  cpu="ia64"
+elif check_define __s390__ ; then
+  if check_define __s390x__ ; then
+    cpu="s390x"
+  else
+    cpu="s390"
+  fi
+else
+  cpu=`uname -m`
+fi
+
+case "$cpu" in
+  alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32)
+    cpu="$cpu"
+  ;;
+  i386|i486|i586|i686|i86pc|BePC)
+    cpu="i386"
+  ;;
+  x86_64|amd64)
+    cpu="x86_64"
+  ;;
+  armv*b)
+    cpu="armv4b"
+  ;;
+  armv*l)
+    cpu="armv4l"
+  ;;
+  parisc|parisc64)
+    cpu="hppa"
+  ;;
+  mips*)
+    cpu="mips"
+  ;;
+  s390)
+    cpu="s390"
+  ;;
+  s390x)
+    cpu="s390x"
+  ;;
+  sparc|sun4[cdmuv])
+    cpu="sparc"
+  ;;
+  *)
+    echo "Unsupported CPU = $cpu"
+    exit 1
+  ;;
+esac
+
+# OS specific
+if check_define __linux__ ; then
+  targetos="Linux"
+elif check_define _WIN32 ; then
+  targetos='MINGW32'
+elif check_define __OpenBSD__ ; then
+  targetos='OpenBSD'
+elif check_define __sun__ ; then
+  targetos='SunOS'
+elif check_define __HAIKU__ ; then
+  targetos='Haiku'
+else
+  targetos=`uname -s`
+fi
+
+case $targetos in
+CYGWIN*)
+  mingw32="yes"
+  QEMU_CFLAGS="-mno-cygwin $QEMU_CFLAGS"
+  audio_possible_drivers="winwave sdl"
+  audio_drv_list="winwave"
+;;
+MINGW32*)
+  mingw32="yes"
+  audio_possible_drivers="winwave dsound sdl fmod"
+  audio_drv_list="winwave"
+;;
+GNU/kFreeBSD)
+  bsd="yes"
+  audio_drv_list="oss"
+  audio_possible_drivers="oss sdl esd pa"
+;;
+FreeBSD)
+  bsd="yes"
+  make="${MAKE-gmake}"
+  audio_drv_list="oss"
+  audio_possible_drivers="oss sdl esd pa"
+  # needed for kinfo_getvmmap(3) in libutil.h
+  LIBS="-lutil $LIBS"
+;;
+DragonFly)
+  bsd="yes"
+  make="${MAKE-gmake}"
+  audio_drv_list="oss"
+  audio_possible_drivers="oss sdl esd pa"
+;;
+NetBSD)
+  bsd="yes"
+  make="${MAKE-gmake}"
+  audio_drv_list="oss"
+  audio_possible_drivers="oss sdl esd"
+  oss_lib="-lossaudio"
+;;
+OpenBSD)
+  bsd="yes"
+  make="${MAKE-gmake}"
+  audio_drv_list="oss"
+  audio_possible_drivers="oss sdl esd"
+  oss_lib="-lossaudio"
+;;
+Darwin)
+  bsd="yes"
+  darwin="yes"
+  # on Leopard most of the system is 32-bit, so we have to ask the kernel it if we can
+  # run 64-bit userspace code
+  if [ "$cpu" = "i386" ] ; then
+    is_x86_64=`sysctl -n hw.optional.x86_64`
+    [ "$is_x86_64" = "1" ] && cpu=x86_64
+  fi
+  if [ "$cpu" = "x86_64" ] ; then
+    QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
+    LDFLAGS="-arch x86_64 $LDFLAGS"
+  else
+    QEMU_CFLAGS="-mdynamic-no-pic $QEMU_CFLAGS"
+  fi
+  darwin_user="yes"
+  cocoa="yes"
+  audio_drv_list="coreaudio"
+  audio_possible_drivers="coreaudio sdl fmod"
+  LDFLAGS="-framework CoreFoundation -framework IOKit $LDFLAGS"
+  libs_softmmu="-F/System/Library/Frameworks -framework Cocoa -framework IOKit $libs_softmmu"
+;;
+SunOS)
+  solaris="yes"
+  make="${MAKE-gmake}"
+  install="${INSTALL-ginstall}"
+  ld="gld"
+  smbd="${SMBD-/usr/sfw/sbin/smbd}"
+  needs_libsunmath="no"
+  solarisrev=`uname -r | cut -f2 -d.`
+  # have to select again, because `uname -m` returns i86pc
+  # even on an x86_64 box.
+  solariscpu=`isainfo -k`
+  if test "${solariscpu}" = "amd64" ; then
+    cpu="x86_64"
+  fi
+  if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+    if test "$solarisrev" -le 9 ; then
+      if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
+        needs_libsunmath="yes"
+        QEMU_CFLAGS="-I/opt/SUNWspro/prod/include/cc $QEMU_CFLAGS"
+        LDFLAGS="-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib $LDFLAGS"
+        LIBS="-lsunmath $LIBS"
+      else
+        echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without"
+        echo "libsunmath from the Sun Studio compilers tools, due to a lack of"
+        echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86"
+        echo "Studio 11 can be downloaded from www.sun.com."
+        exit 1
+      fi
+    fi
+  fi
+  if test -f /usr/include/sys/soundcard.h ; then
+    audio_drv_list="oss"
+  fi
+  audio_possible_drivers="oss sdl"
+# needed for CMSG_ macros in sys/socket.h
+  QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS"
+# needed for TIOCWIN* defines in termios.h
+  QEMU_CFLAGS="-D__EXTENSIONS__ $QEMU_CFLAGS"
+  QEMU_CFLAGS="-std=gnu99 $QEMU_CFLAGS"
+  LIBS="-lsocket -lnsl -lresolv $LIBS"
+;;
+AIX)
+  aix="yes"
+  make="${MAKE-gmake}"
+;;
+Haiku)
+  haiku="yes"
+  QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS $QEMU_CFLAGS"
+  LIBS="-lposix_error_mapper -lnetwork $LIBS"
+;;
+*)
+  audio_drv_list="oss"
+  audio_possible_drivers="oss alsa sdl esd pa"
+  linux="yes"
+  linux_user="yes"
+  usb="linux"
+  kvm="yes"
+  vhost_net="yes"
+  if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+    audio_possible_drivers="$audio_possible_drivers fmod"
+  fi
+;;
+esac
+
+if [ "$bsd" = "yes" ] ; then
+  if [ "$darwin" != "yes" ] ; then
+    usb="bsd"
+  fi
+  bsd_user="yes"
+fi
+
+: ${make=${MAKE-make}}
+: ${install=${INSTALL-install}}
+: ${python=${PYTHON-python}}
+: ${smbd=${SMBD-/usr/sbin/smbd}}
+
+if test "$mingw32" = "yes" ; then
+  EXESUF=".exe"
+  QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
+  # enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
+  QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
+  LIBS="-lwinmm -lws2_32 -liberty -liphlpapi $LIBS"
+  prefix="c:/Program Files/Qemu"
+  mandir="\${prefix}"
+  datadir="\${prefix}"
+  docdir="\${prefix}"
+  bindir="\${prefix}"
+  sysconfdir="\${prefix}"
+  confsuffix=""
+fi
+
+werror=""
+
+for opt do
+  optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+  case "$opt" in
+  --help|-h) show_help=yes
+  ;;
+  --version|-V) exec cat $source_path/VERSION
+  ;;
+  --prefix=*) prefix="$optarg"
+  ;;
+  --interp-prefix=*) interp_prefix="$optarg"
+  ;;
+  --source-path=*)
+  ;;
+  --cross-prefix=*)
+  ;;
+  --cc=*)
+  ;;
+  --host-cc=*) host_cc="$optarg"
+  ;;
+  --make=*) make="$optarg"
+  ;;
+  --install=*) install="$optarg"
+  ;;
+  --python=*) python="$optarg"
+  ;;
+  --smbd=*) smbd="$optarg"
+  ;;
+  --extra-cflags=*)
+  ;;
+  --extra-ldflags=*)
+  ;;
+  --cpu=*)
+  ;;
+  --target-list=*) target_list="$optarg"
+  ;;
+  --enable-trace-backend=*) trace_backend="$optarg"
+  ;;
+  --with-trace-file=*) trace_file="$optarg"
+  ;;
+  --enable-gprof) gprof="yes"
+  ;;
+  --static)
+    static="yes"
+    LDFLAGS="-static $LDFLAGS"
+  ;;
+  --mandir=*) mandir="$optarg"
+  ;;
+  --bindir=*) bindir="$optarg"
+  ;;
+  --libdir=*) libdir="$optarg"
+  ;;
+  --datadir=*) datadir="$optarg"
+  ;;
+  --docdir=*) docdir="$optarg"
+  ;;
+  --sysconfdir=*) sysconfdir="$optarg"
+  ;;
+  --disable-sdl) sdl="no"
+  ;;
+  --enable-sdl) sdl="yes"
+  ;;
+  --disable-vnc) vnc="no"
+  ;;
+  --enable-vnc) vnc="yes"
+  ;;
+  --fmod-lib=*) fmod_lib="$optarg"
+  ;;
+  --fmod-inc=*) fmod_inc="$optarg"
+  ;;
+  --oss-lib=*) oss_lib="$optarg"
+  ;;
+  --audio-card-list=*) audio_card_list=`echo "$optarg" | sed -e 's/,/ /g'`
+  ;;
+  --audio-drv-list=*) audio_drv_list="$optarg"
+  ;;
+  --block-drv-whitelist=*) block_drv_whitelist=`echo "$optarg" | sed -e 's/,/ /g'`
+  ;;
+  --enable-debug-tcg) debug_tcg="yes"
+  ;;
+  --disable-debug-tcg) debug_tcg="no"
+  ;;
+  --enable-debug-mon) debug_mon="yes"
+  ;;
+  --disable-debug-mon) debug_mon="no"
+  ;;
+  --enable-debug)
+      # Enable debugging options that aren't excessively noisy
+      debug_tcg="yes"
+      debug_mon="yes"
+      debug="yes"
+      strip_opt="no"
+  ;;
+  --enable-sparse) sparse="yes"
+  ;;
+  --disable-sparse) sparse="no"
+  ;;
+  --disable-strip) strip_opt="no"
+  ;;
+  --disable-vnc-tls) vnc_tls="no"
+  ;;
+  --enable-vnc-tls) vnc_tls="yes"
+  ;;
+  --disable-vnc-sasl) vnc_sasl="no"
+  ;;
+  --enable-vnc-sasl) vnc_sasl="yes"
+  ;;
+  --disable-vnc-jpeg) vnc_jpeg="no"
+  ;;
+  --enable-vnc-jpeg) vnc_jpeg="yes"
+  ;;
+  --disable-vnc-png) vnc_png="no"
+  ;;
+  --enable-vnc-png) vnc_png="yes"
+  ;;
+  --disable-vnc-thread) vnc_thread="no"
+  ;;
+  --enable-vnc-thread) vnc_thread="yes"
+  ;;
+  --disable-slirp) slirp="no"
+  ;;
+  --disable-uuid) uuid="no"
+  ;;
+  --enable-uuid) uuid="yes"
+  ;;
+  --disable-vde) vde="no"
+  ;;
+  --enable-vde) vde="yes"
+  ;;
+  --disable-xen) xen="no"
+  ;;
+  --enable-xen) xen="yes"
+  ;;
+  --disable-brlapi) brlapi="no"
+  ;;
+  --enable-brlapi) brlapi="yes"
+  ;;
+  --disable-bluez) bluez="no"
+  ;;
+  --enable-bluez) bluez="yes"
+  ;;
+  --disable-kvm) kvm="no"
+  ;;
+  --enable-kvm) kvm="yes"
+  ;;
+  --disable-spice) spice="no"
+  ;;
+  --enable-spice) spice="yes"
+  ;;
+  --enable-profiler) profiler="yes"
+  ;;
+  --enable-cocoa)
+      cocoa="yes" ;
+      sdl="no" ;
+      audio_drv_list="coreaudio `echo $audio_drv_list | sed s,coreaudio,,g`"
+  ;;
+  --disable-system) softmmu="no"
+  ;;
+  --enable-system) softmmu="yes"
+  ;;
+  --disable-user)
+      linux_user="no" ;
+      bsd_user="no" ;
+      darwin_user="no"
+  ;;
+  --enable-user) ;;
+  --disable-linux-user) linux_user="no"
+  ;;
+  --enable-linux-user) linux_user="yes"
+  ;;
+  --disable-darwin-user) darwin_user="no"
+  ;;
+  --enable-darwin-user) darwin_user="yes"
+  ;;
+  --disable-bsd-user) bsd_user="no"
+  ;;
+  --enable-bsd-user) bsd_user="yes"
+  ;;
+  --enable-guest-base) guest_base="yes"
+  ;;
+  --disable-guest-base) guest_base="no"
+  ;;
+  --enable-user-pie) user_pie="yes"
+  ;;
+  --disable-user-pie) user_pie="no"
+  ;;
+  --enable-uname-release=*) uname_release="$optarg"
+  ;;
+  --sparc_cpu=*)
+  ;;
+  --enable-werror) werror="yes"
+  ;;
+  --disable-werror) werror="no"
+  ;;
+  --disable-curses) curses="no"
+  ;;
+  --enable-curses) curses="yes"
+  ;;
+  --disable-curl) curl="no"
+  ;;
+  --enable-curl) curl="yes"
+  ;;
+  --disable-fdt) fdt="no"
+  ;;
+  --enable-fdt) fdt="yes"
+  ;;
+  --disable-check-utests) check_utests="no"
+  ;;
+  --enable-check-utests) check_utests="yes"
+  ;;
+  --disable-nptl) nptl="no"
+  ;;
+  --enable-nptl) nptl="yes"
+  ;;
+  --enable-mixemu) mixemu="yes"
+  ;;
+  --disable-linux-aio) linux_aio="no"
+  ;;
+  --enable-linux-aio) linux_aio="yes"
+  ;;
+  --disable-attr) attr="no"
+  ;;
+  --enable-attr) attr="yes"
+  ;;
+  --enable-io-thread) io_thread="yes"
+  ;;
+  --disable-blobs) blobs="no"
+  ;;
+  --with-pkgversion=*) pkgversion=" ($optarg)"
+  ;;
+  --disable-docs) docs="no"
+  ;;
+  --enable-docs) docs="yes"
+  ;;
+  --disable-vhost-net) vhost_net="no"
+  ;;
+  --enable-vhost-net) vhost_net="yes"
+  ;;
+  --disable-opengl) opengl="no"
+  ;;
+  --enable-opengl) opengl="yes"
+  ;;
+  --*dir)
+  ;;
+  --disable-rbd) rbd="no"
+  ;;
+  --enable-rbd) rbd="yes"
+  ;;
+  --disable-smartcard) smartcard="no"
+  ;;
+  --enable-smartcard) smartcard="yes"
+  ;;
+  --disable-smartcard-nss) smartcard_nss="no"
+  ;;
+  --enable-smartcard-nss) smartcard_nss="yes"
+  ;;
+  --disable-usb-redir) usb_redir="no"
+  ;;
+  --enable-usb-redir) usb_redir="yes"
+  ;;
+  --enable-guest-agent) guest_agent="yes"
+  ;;
+  --disable-guest-agent) guest_agent="no"
+  ;;
+  *) echo "ERROR: unknown option $opt"; show_help="yes"
+  ;;
+  esac
+done
+
+#
+# If cpu ~= sparc and  sparc_cpu hasn't been defined, plug in the right
+# QEMU_CFLAGS/LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
+#
+host_guest_base="no"
+case "$cpu" in
+    sparc) case $sparc_cpu in
+           v7|v8)
+             QEMU_CFLAGS="-mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
+           ;;
+           v8plus|v8plusa)
+             QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
+           ;;
+           *) # sparc_cpu not defined in the command line
+             QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_v8plus__ $QEMU_CFLAGS"
+           esac
+           LDFLAGS="-m32 $LDFLAGS"
+           QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS"
+           if test "$solaris" = "no" ; then
+             QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS"
+             helper_cflags="-ffixed-i0"
+           fi
+           ;;
+    sparc64)
+           QEMU_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__ $QEMU_CFLAGS"
+           LDFLAGS="-m64 $LDFLAGS"
+           QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS"
+           if test "$solaris" != "no" ; then
+             QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS"
+           fi
+           ;;
+    s390)
+           QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS"
+           LDFLAGS="-m31 $LDFLAGS"
+           host_guest_base="yes"
+           ;;
+    s390x)
+           QEMU_CFLAGS="-m64 -march=z990 $QEMU_CFLAGS"
+           LDFLAGS="-m64 $LDFLAGS"
+           host_guest_base="yes"
+           ;;
+    i386)
+           QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
+           LDFLAGS="-m32 $LDFLAGS"
+           cc_i386='$(CC) -m32'
+           helper_cflags="-fomit-frame-pointer"
+           host_guest_base="yes"
+           ;;
+    x86_64)
+           QEMU_CFLAGS="-m64 $QEMU_CFLAGS"
+           LDFLAGS="-m64 $LDFLAGS"
+           cc_i386='$(CC) -m32'
+           host_guest_base="yes"
+           ;;
+    arm*)
+           host_guest_base="yes"
+           ;;
+    ppc*)
+           host_guest_base="yes"
+           ;;
+    mips*)
+           host_guest_base="yes"
+           ;;
+    ia64*)
+           host_guest_base="yes"
+           ;;
+    hppa*)
+           host_guest_base="yes"
+           ;;
+    unicore32*)
+           host_guest_base="yes"
+           ;;
+esac
+
+[ -z "$guest_base" ] && guest_base="$host_guest_base"
+
+
+default_target_list=""
+
+# these targets are portable
+if [ "$softmmu" = "yes" ] ; then
+    default_target_list="\
+i386-softmmu \
+x86_64-softmmu \
+arm-softmmu \
+cris-softmmu \
+lm32-softmmu \
+m68k-softmmu \
+microblaze-softmmu \
+microblazeel-softmmu \
+mips-softmmu \
+mipsel-softmmu \
+mips64-softmmu \
+mips64el-softmmu \
+ppc-softmmu \
+ppcemb-softmmu \
+ppc64-softmmu \
+sh4-softmmu \
+sh4eb-softmmu \
+sparc-softmmu \
+sparc64-softmmu \
+s390x-softmmu \
+"
+fi
+# the following are Linux specific
+if [ "$linux_user" = "yes" ] ; then
+    default_target_list="${default_target_list}\
+i386-linux-user \
+x86_64-linux-user \
+alpha-linux-user \
+arm-linux-user \
+armeb-linux-user \
+cris-linux-user \
+m68k-linux-user \
+microblaze-linux-user \
+microblazeel-linux-user \
+mips-linux-user \
+mipsel-linux-user \
+ppc-linux-user \
+ppc64-linux-user \
+ppc64abi32-linux-user \
+sh4-linux-user \
+sh4eb-linux-user \
+sparc-linux-user \
+sparc64-linux-user \
+sparc32plus-linux-user \
+unicore32-linux-user \
+s390x-linux-user \
+"
+fi
+# the following are Darwin specific
+if [ "$darwin_user" = "yes" ] ; then
+    default_target_list="$default_target_list i386-darwin-user ppc-darwin-user "
+fi
+# the following are BSD specific
+if [ "$bsd_user" = "yes" ] ; then
+    default_target_list="${default_target_list}\
+i386-bsd-user \
+x86_64-bsd-user \
+sparc-bsd-user \
+sparc64-bsd-user \
+"
+fi
+
+if test x"$show_help" = x"yes" ; then
+cat << EOF
+
+Usage: configure [options]
+Options: [defaults in brackets after descriptions]
+
+EOF
+echo "Standard options:"
+echo "  --help                   print this message"
+echo "  --prefix=PREFIX          install in PREFIX [$prefix]"
+echo "  --interp-prefix=PREFIX   where to find shared libraries, etc."
+echo "                           use %M for cpu name [$interp_prefix]"
+echo "  --target-list=LIST       set target list (default: build everything)"
+echo "Available targets: $default_target_list" | \
+    fold -s -w 53 | sed -e 's/^/                           /'
+echo ""
+echo "Advanced options (experts only):"
+echo "  --source-path=PATH       path of source code [$source_path]"
+echo "  --cross-prefix=PREFIX    use PREFIX for compile tools [$cross_prefix]"
+echo "  --cc=CC                  use C compiler CC [$cc]"
+echo "  --host-cc=CC             use C compiler CC [$host_cc] for code run at"
+echo "                           build time"
+echo "  --extra-cflags=CFLAGS    append extra C compiler flags QEMU_CFLAGS"
+echo "  --extra-ldflags=LDFLAGS  append extra linker flags LDFLAGS"
+echo "  --make=MAKE              use specified make [$make]"
+echo "  --install=INSTALL        use specified install [$install]"
+echo "  --python=PYTHON          use specified python [$python]"
+echo "  --smbd=SMBD              use specified smbd [$smbd]"
+echo "  --static                 enable static build [$static]"
+echo "  --mandir=PATH            install man pages in PATH"
+echo "  --datadir=PATH           install firmware in PATH"
+echo "  --docdir=PATH            install documentation in PATH"
+echo "  --bindir=PATH            install binaries in PATH"
+echo "  --sysconfdir=PATH        install config in PATH/qemu"
+echo "  --enable-debug-tcg       enable TCG debugging"
+echo "  --disable-debug-tcg      disable TCG debugging (default)"
+echo "  --enable-debug           enable common debug build options"
+echo "  --enable-sparse          enable sparse checker"
+echo "  --disable-sparse         disable sparse checker (default)"
+echo "  --disable-strip          disable stripping binaries"
+echo "  --disable-werror         disable compilation abort on warning"
+echo "  --disable-sdl            disable SDL"
+echo "  --enable-sdl             enable SDL"
+echo "  --disable-vnc            disable VNC"
+echo "  --enable-vnc             enable VNC"
+echo "  --enable-cocoa           enable COCOA (Mac OS X only)"
+echo "  --audio-drv-list=LIST    set audio drivers list:"
+echo "                           Available drivers: $audio_possible_drivers"
+echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
+echo "                           Available cards: $audio_possible_cards"
+echo "  --block-drv-whitelist=L  set block driver whitelist"
+echo "                           (affects only QEMU, not qemu-img)"
+echo "  --enable-mixemu          enable mixer emulation"
+echo "  --disable-xen            disable xen backend driver support"
+echo "  --enable-xen             enable xen backend driver support"
+echo "  --disable-brlapi         disable BrlAPI"
+echo "  --enable-brlapi          enable BrlAPI"
+echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
+echo "  --enable-vnc-tls         enable TLS encryption for VNC server"
+echo "  --disable-vnc-sasl       disable SASL encryption for VNC server"
+echo "  --enable-vnc-sasl        enable SASL encryption for VNC server"
+echo "  --disable-vnc-jpeg       disable JPEG lossy compression for VNC server"
+echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
+echo "  --disable-vnc-png        disable PNG compression for VNC server (default)"
+echo "  --enable-vnc-png         enable PNG compression for VNC server"
+echo "  --disable-vnc-thread     disable threaded VNC server"
+echo "  --enable-vnc-thread      enable threaded VNC server"
+echo "  --disable-curses         disable curses output"
+echo "  --enable-curses          enable curses output"
+echo "  --disable-curl           disable curl connectivity"
+echo "  --enable-curl            enable curl connectivity"
+echo "  --disable-fdt            disable fdt device tree"
+echo "  --enable-fdt             enable fdt device tree"
+echo "  --disable-check-utests   disable check unit-tests"
+echo "  --enable-check-utests    enable check unit-tests"
+echo "  --disable-bluez          disable bluez stack connectivity"
+echo "  --enable-bluez           enable bluez stack connectivity"
+echo "  --disable-slirp          disable SLIRP userspace network connectivity"
+echo "  --disable-kvm            disable KVM acceleration support"
+echo "  --enable-kvm             enable KVM acceleration support"
+echo "  --disable-nptl           disable usermode NPTL support"
+echo "  --enable-nptl            enable usermode NPTL support"
+echo "  --enable-system          enable all system emulation targets"
+echo "  --disable-system         disable all system emulation targets"
+echo "  --enable-user            enable supported user emulation targets"
+echo "  --disable-user           disable all user emulation targets"
+echo "  --enable-linux-user      enable all linux usermode emulation targets"
+echo "  --disable-linux-user     disable all linux usermode emulation targets"
+echo "  --enable-darwin-user     enable all darwin usermode emulation targets"
+echo "  --disable-darwin-user    disable all darwin usermode emulation targets"
+echo "  --enable-bsd-user        enable all BSD usermode emulation targets"
+echo "  --disable-bsd-user       disable all BSD usermode emulation targets"
+echo "  --enable-guest-base      enable GUEST_BASE support for usermode"
+echo "                           emulation targets"
+echo "  --disable-guest-base     disable GUEST_BASE support"
+echo "  --enable-user-pie        build usermode emulation targets as PIE"
+echo "  --disable-user-pie       do not build usermode emulation targets as PIE"
+echo "  --fmod-lib               path to FMOD library"
+echo "  --fmod-inc               path to FMOD includes"
+echo "  --oss-lib                path to OSS library"
+echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
+echo "  --disable-uuid           disable uuid support"
+echo "  --enable-uuid            enable uuid support"
+echo "  --disable-vde            disable support for vde network"
+echo "  --enable-vde             enable support for vde network"
+echo "  --disable-linux-aio      disable Linux AIO support"
+echo "  --enable-linux-aio       enable Linux AIO support"
+echo "  --disable-attr           disables attr and xattr support"
+echo "  --enable-attr            enable attr and xattr support"
+echo "  --enable-io-thread       enable IO thread"
+echo "  --disable-blobs          disable installing provided firmware blobs"
+echo "  --enable-docs            enable documentation build"
+echo "  --disable-docs           disable documentation build"
+echo "  --disable-vhost-net      disable vhost-net acceleration support"
+echo "  --enable-vhost-net       enable vhost-net acceleration support"
+echo "  --enable-trace-backend=B Set trace backend"
+echo "                           Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+echo "  --with-trace-file=NAME   Full PATH,NAME of file to store traces"
+echo "                           Default:trace-<pid>"
+echo "  --disable-spice          disable spice"
+echo "  --enable-spice           enable spice"
+echo "  --enable-rbd             enable building the rados block device (rbd)"
+echo "  --disable-smartcard      disable smartcard support"
+echo "  --enable-smartcard       enable smartcard support"
+echo "  --disable-smartcard-nss  disable smartcard nss support"
+echo "  --enable-smartcard-nss   enable smartcard nss support"
+echo "  --disable-usb-redir      disable usb network redirection support"
+echo "  --enable-usb-redir       enable usb network redirection support"
+echo "  --disable-guest-agent    disable building of the QEMU Guest Agent"
+echo "  --enable-guest-agent     enable building of the QEMU Guest Agent"
+echo ""
+echo "NOTE: The object files are built at the place where configure is launched"
+exit 1
+fi
+
+# check that the C compiler works.
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if compile_object ; then
+  : C compiler works ok
+else
+    echo "ERROR: \"$cc\" either does not exist or does not work"
+    exit 1
+fi
+
+gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
+gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
+gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
+gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags"
+cat > $TMPC << EOF
+int main(void) { return 0; }
+EOF
+for flag in $gcc_flags; do
+    if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
+	QEMU_CFLAGS="$QEMU_CFLAGS $flag"
+    fi
+done
+
+#
+# Solaris specific configure tool chain decisions
+#
+if test "$solaris" = "yes" ; then
+  if has $install; then
+    :
+  else
+    echo "Solaris install program not found. Use --install=/usr/ucb/install or"
+    echo "install fileutils from www.blastwave.org using pkg-get -i fileutils"
+    echo "to get ginstall which is used by default (which lives in /opt/csw/bin)"
+    exit 1
+  fi
+  if test "`path_of $install`" = "/usr/sbin/install" ; then
+    echo "Error: Solaris /usr/sbin/install is not an appropriate install program."
+    echo "try ginstall from the GNU fileutils available from www.blastwave.org"
+    echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
+    exit 1
+  fi
+  if has ar; then
+    :
+  else
+    echo "Error: No path includes ar"
+    if test -f /usr/ccs/bin/ar ; then
+      echo "Add /usr/ccs/bin to your path and rerun configure"
+    fi
+    exit 1
+  fi
+fi
+
+if test "$guest_agent" != "no" ; then
+  if has $python; then
+    :
+  else
+    echo "Python not found. Use --python=/path/to/python"
+    exit 1
+  fi
+fi
+
+if test -z "$target_list" ; then
+    target_list="$default_target_list"
+else
+    target_list=`echo "$target_list" | sed -e 's/,/ /g'`
+fi
+if test -z "$target_list" ; then
+    echo "No targets enabled"
+    exit 1
+fi
+# see if system emulation was really requested
+case " $target_list " in
+  *"-softmmu "*) softmmu=yes
+  ;;
+  *) softmmu=no
+  ;;
+esac
+
+feature_not_found() {
+  feature=$1
+
+  echo "ERROR"
+  echo "ERROR: User requested feature $feature"
+  echo "ERROR: configure was not able to find it"
+  echo "ERROR"
+  exit 1;
+}
+
+if test -z "$cross_prefix" ; then
+
+# ---
+# big/little endian test
+cat > $TMPC << EOF
+#include <inttypes.h>
+int main(int argc, char ** argv){
+        volatile uint32_t i=0x01234567;
+        return (*((uint8_t*)(&i))) == 0x67;
+}
+EOF
+
+if compile_prog "" "" ; then
+$TMPE && bigendian="yes"
+else
+echo big/little test failed
+fi
+
+else
+
+# if cross compiling, cannot launch a program, so make a static guess
+case "$cpu" in
+  armv4b|hppa|m68k|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
+    bigendian=yes
+  ;;
+esac
+
+fi
+
+# host long bits test, actually a pointer size test
+cat > $TMPC << EOF
+int sizeof_pointer_is_8[sizeof(void *) == 8 ? 1 : -1];
+EOF
+if compile_object; then
+hostlongbits=64
+else
+hostlongbits=32
+fi
+
+
+##########################################
+# NPTL probe
+
+if test "$nptl" != "no" ; then
+  cat > $TMPC <<EOF
+#include <sched.h>
+#include <linux/futex.h>
+void foo()
+{
+#if !defined(CLONE_SETTLS) || !defined(FUTEX_WAIT)
+#error bork
+#endif
+}
+EOF
+
+  if compile_object ; then
+    nptl=yes
+  else
+    if test "$nptl" = "yes" ; then
+      feature_not_found "nptl"
+    fi
+    nptl=no
+  fi
+fi
+
+##########################################
+# zlib check
+
+cat > $TMPC << EOF
+#include <zlib.h>
+int main(void) { zlibVersion(); return 0; }
+EOF
+if compile_prog "" "-lz" ; then
+    :
+else
+    echo
+    echo "Error: zlib check failed"
+    echo "Make sure to have the zlib libs and headers installed."
+    echo
+    exit 1
+fi
+
+##########################################
+# xen probe
+
+if test "$xen" != "no" ; then
+  xen_libs="-lxenstore -lxenctrl -lxenguest"
+
+  # Xen unstable
+  cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+  xc_interface *xc;
+  xs_daemon_open();
+  xc = xc_interface_open(0, 0, 0);
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_gnttab_open(NULL, 0);
+  xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
+  return 0;
+}
+EOF
+  if compile_prog "" "$xen_libs" ; then
+    xen_ctrl_version=410
+    xen=yes
+
+  # Xen 4.0.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+  struct xen_add_to_physmap xatp = {
+    .domid = 0, .space = XENMAPSPACE_gmfn, .idx = 0, .gpfn = 0,
+  };
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_memory_op(0, XENMEM_add_to_physmap, &xatp);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=400
+    xen=yes
+
+  # Xen 3.4.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+int main(void) {
+  struct xen_add_to_physmap xatp = {
+    .domid = 0, .space = XENMAPSPACE_gmfn, .idx = 0, .gpfn = 0,
+  };
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_memory_op(0, XENMEM_add_to_physmap, &xatp);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=340
+    xen=yes
+
+  # Xen 3.3.0
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+int main(void) {
+  xs_daemon_open();
+  xc_interface_open();
+  xc_gnttab_open();
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=330
+    xen=yes
+
+  # Xen not found or unsupported
+  else
+    if test "$xen" = "yes" ; then
+      feature_not_found "xen"
+    fi
+    xen=no
+  fi
+
+  if test "$xen" = yes; then
+    libs_softmmu="$xen_libs $libs_softmmu"
+  fi
+fi
+
+##########################################
+# pkg-config probe
+
+if ! has $pkg_config; then
+  echo warning: proceeding without "$pkg_config" >&2
+  pkg_config=/bin/false
+fi
+
+##########################################
+# libtool probe
+
+if ! has libtool; then
+    libtool=
+else
+    libtool=libtool
+fi
+
+##########################################
+# Sparse probe
+if test "$sparse" != "no" ; then
+  if has cgcc; then
+    sparse=yes
+  else
+    if test "$sparse" = "yes" ; then
+      feature_not_found "sparse"
+    fi
+    sparse=no
+  fi
+fi
+
+##########################################
+# SDL probe
+
+# Look for sdl configuration program (pkg-config or sdl-config).  Try
+# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
+if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
+  sdl_config=sdl-config
+fi
+
+if $pkg_config sdl --modversion >/dev/null 2>&1; then
+  sdlconfig="$pkg_config sdl"
+  _sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
+elif has ${sdl_config}; then
+  sdlconfig="$sdl_config"
+  _sdlversion=`$sdlconfig --version | sed 's/[^0-9]//g'`
+else
+  if test "$sdl" = "yes" ; then
+    feature_not_found "sdl"
+  fi
+  sdl=no
+fi
+if test -n "$cross_prefix" && test "$(basename "$sdlconfig")" = sdl-config; then
+  echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2
+fi
+
+sdl_too_old=no
+if test "$sdl" != "no" ; then
+  cat > $TMPC << EOF
+#include <SDL.h>
+#undef main /* We don't want SDL to override our main() */
+int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
+EOF
+  sdl_cflags=`$sdlconfig --cflags 2> /dev/null`
+  if test "$static" = "yes" ; then
+    sdl_libs=`$sdlconfig --static-libs 2>/dev/null`
+  else
+    sdl_libs=`$sdlconfig --libs 2> /dev/null`
+  fi
+  if compile_prog "$sdl_cflags" "$sdl_libs" ; then
+    if test "$_sdlversion" -lt 121 ; then
+      sdl_too_old=yes
+    else
+      if test "$cocoa" = "no" ; then
+        sdl=yes
+      fi
+    fi
+
+    # static link with sdl ? (note: sdl.pc's --static --libs is broken)
+    if test "$sdl" = "yes" -a "$static" = "yes" ; then
+      if test $? = 0 && echo $sdl_libs | grep -- -laa > /dev/null; then
+         sdl_libs="$sdl_libs `aalib-config --static-libs 2>/dev/null`"
+         sdl_cflags="$sdl_cflags `aalib-config --cflags 2>/dev/null`"
+      fi
+      if compile_prog "$sdl_cflags" "$sdl_libs" ; then
+	:
+      else
+        sdl=no
+      fi
+    fi # static link
+  else # sdl not found
+    if test "$sdl" = "yes" ; then
+      feature_not_found "sdl"
+    fi
+    sdl=no
+  fi # sdl compile test
+fi
+
+if test "$sdl" = "yes" ; then
+  cat > $TMPC <<EOF
+#include <SDL.h>
+#if defined(SDL_VIDEO_DRIVER_X11)
+#include <X11/XKBlib.h>
+#else
+#error No x11 support
+#endif
+int main(void) { return 0; }
+EOF
+  if compile_prog "$sdl_cflags" "$sdl_libs" ; then
+    sdl_libs="$sdl_libs -lX11"
+  fi
+  if test "$mingw32" = "yes" ; then
+    sdl_libs="`echo $sdl_libs | sed s/-mwindows//g` -mconsole"
+  fi
+  libs_softmmu="$sdl_libs $libs_softmmu"
+fi
+
+##########################################
+# VNC TLS detection
+if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
+  cat > $TMPC <<EOF
+#include <gnutls/gnutls.h>
+int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
+EOF
+  vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
+  vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
+  if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then
+    vnc_tls=yes
+    libs_softmmu="$vnc_tls_libs $libs_softmmu"
+  else
+    if test "$vnc_tls" = "yes" ; then
+      feature_not_found "vnc-tls"
+    fi
+    vnc_tls=no
+  fi
+fi
+
+##########################################
+# VNC SASL detection
+if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
+  cat > $TMPC <<EOF
+#include <sasl/sasl.h>
+#include <stdio.h>
+int main(void) { sasl_server_init(NULL, "qemu"); return 0; }
+EOF
+  # Assuming Cyrus-SASL installed in /usr prefix
+  vnc_sasl_cflags=""
+  vnc_sasl_libs="-lsasl2"
+  if compile_prog "$vnc_sasl_cflags" "$vnc_sasl_libs" ; then
+    vnc_sasl=yes
+    libs_softmmu="$vnc_sasl_libs $libs_softmmu"
+  else
+    if test "$vnc_sasl" = "yes" ; then
+      feature_not_found "vnc-sasl"
+    fi
+    vnc_sasl=no
+  fi
+fi
+
+##########################################
+# VNC JPEG detection
+if test "$vnc" = "yes" -a "$vnc_jpeg" != "no" ; then
+cat > $TMPC <<EOF
+#include <stdio.h>
+#include <jpeglib.h>
+int main(void) { struct jpeg_compress_struct s; jpeg_create_compress(&s); return 0; }
+EOF
+    vnc_jpeg_cflags=""
+    vnc_jpeg_libs="-ljpeg"
+  if compile_prog "$vnc_jpeg_cflags" "$vnc_jpeg_libs" ; then
+    vnc_jpeg=yes
+    libs_softmmu="$vnc_jpeg_libs $libs_softmmu"
+  else
+    if test "$vnc_jpeg" = "yes" ; then
+      feature_not_found "vnc-jpeg"
+    fi
+    vnc_jpeg=no
+  fi
+fi
+
+##########################################
+# VNC PNG detection
+if test "$vnc" = "yes" -a "$vnc_png" != "no" ; then
+cat > $TMPC <<EOF
+//#include <stdio.h>
+#include <png.h>
+#include <stddef.h>
+int main(void) {
+    png_structp png_ptr;
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    return 0;
+}
+EOF
+  if $pkg_config libpng --modversion >/dev/null 2>&1; then
+    vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
+    vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
+  else
+    vnc_png_cflags=""
+    vnc_png_libs="-lpng"
+  fi
+  if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
+    vnc_png=yes
+    libs_softmmu="$vnc_png_libs $libs_softmmu"
+    QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
+  else
+    if test "$vnc_png" = "yes" ; then
+      feature_not_found "vnc-png"
+    fi
+    vnc_png=no
+  fi
+fi
+
+##########################################
+# fnmatch() probe, used for ACL routines
+fnmatch="no"
+cat > $TMPC << EOF
+#include <fnmatch.h>
+int main(void)
+{
+    fnmatch("foo", "foo", 0);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+   fnmatch="yes"
+fi
+
+##########################################
+# uuid_generate() probe, used for vdi block driver
+if test "$uuid" != "no" ; then
+  uuid_libs="-luuid"
+  cat > $TMPC << EOF
+#include <uuid/uuid.h>
+int main(void)
+{
+    uuid_t my_uuid;
+    uuid_generate(my_uuid);
+    return 0;
+}
+EOF
+  if compile_prog "" "$uuid_libs" ; then
+    uuid="yes"
+    libs_softmmu="$uuid_libs $libs_softmmu"
+    libs_tools="$uuid_libs $libs_tools"
+  else
+    if test "$uuid" = "yes" ; then
+      feature_not_found "uuid"
+    fi
+    uuid=no
+  fi
+fi
+
+##########################################
+# xfsctl() probe, used for raw-posix
+if test "$xfs" != "no" ; then
+  cat > $TMPC << EOF
+#include <xfs/xfs.h>
+int main(void)
+{
+    xfsctl(NULL, 0, 0, NULL);
+    return 0;
+}
+EOF
+  if compile_prog "" "" ; then
+    xfs="yes"
+  else
+    if test "$xfs" = "yes" ; then
+      feature_not_found "xfs"
+    fi
+    xfs=no
+  fi
+fi
+
+##########################################
+# vde libraries probe
+if test "$vde" != "no" ; then
+  vde_libs="-lvdeplug"
+  cat > $TMPC << EOF
+#include <libvdeplug.h>
+int main(void)
+{
+    struct vde_open_args a = {0, 0, 0};
+    vde_open("", "", &a);
+    return 0;
+}
+EOF
+  if compile_prog "" "$vde_libs" ; then
+    vde=yes
+    libs_softmmu="$vde_libs $libs_softmmu"
+    libs_tools="$vde_libs $libs_tools"
+  else
+    if test "$vde" = "yes" ; then
+      feature_not_found "vde"
+    fi
+    vde=no
+  fi
+fi
+
+##########################################
+# Sound support libraries probe
+
+audio_drv_probe()
+{
+    drv=$1
+    hdr=$2
+    lib=$3
+    exp=$4
+    cfl=$5
+        cat > $TMPC << EOF
+#include <$hdr>
+int main(void) { $exp }
+EOF
+    if compile_prog "$cfl" "$lib" ; then
+        :
+    else
+        echo
+        echo "Error: $drv check failed"
+        echo "Make sure to have the $drv libs and headers installed."
+        echo
+        exit 1
+    fi
+}
+
+audio_drv_list=`echo "$audio_drv_list" | sed -e 's/,/ /g'`
+for drv in $audio_drv_list; do
+    case $drv in
+    alsa)
+    audio_drv_probe $drv alsa/asoundlib.h -lasound \
+        "snd_pcm_t **handle; return snd_pcm_close(*handle);"
+    libs_softmmu="-lasound $libs_softmmu"
+    ;;
+
+    fmod)
+    if test -z $fmod_lib || test -z $fmod_inc; then
+        echo
+        echo "Error: You must specify path to FMOD library and headers"
+        echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
+        echo
+        exit 1
+    fi
+    audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc"
+    libs_softmmu="$fmod_lib $libs_softmmu"
+    ;;
+
+    esd)
+    audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);'
+    libs_softmmu="-lesd $libs_softmmu"
+    audio_pt_int="yes"
+    ;;
+
+    pa)
+    audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \
+        "pa_simple *s = 0; pa_simple_free(s); return 0;"
+    libs_softmmu="-lpulse -lpulse-simple $libs_softmmu"
+    audio_pt_int="yes"
+    ;;
+
+    coreaudio)
+      libs_softmmu="-framework CoreAudio $libs_softmmu"
+    ;;
+
+    dsound)
+      libs_softmmu="-lole32 -ldxguid $libs_softmmu"
+      audio_win_int="yes"
+    ;;
+
+    oss)
+      libs_softmmu="$oss_lib $libs_softmmu"
+    ;;
+
+    sdl|wav)
+    # XXX: Probes for CoreAudio, DirectSound, SDL(?)
+    ;;
+
+    winwave)
+      libs_softmmu="-lwinmm $libs_softmmu"
+      audio_win_int="yes"
+    ;;
+
+    *)
+    echo "$audio_possible_drivers" | grep -q "\<$drv\>" || {
+        echo
+        echo "Error: Unknown driver '$drv' selected"
+        echo "Possible drivers are: $audio_possible_drivers"
+        echo
+        exit 1
+    }
+    ;;
+    esac
+done
+
+##########################################
+# BrlAPI probe
+
+if test "$brlapi" != "no" ; then
+  brlapi_libs="-lbrlapi"
+  cat > $TMPC << EOF
+#include <brlapi.h>
+#include <stddef.h>
+int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); }
+EOF
+  if compile_prog "" "$brlapi_libs" ; then
+    brlapi=yes
+    libs_softmmu="$brlapi_libs $libs_softmmu"
+  else
+    if test "$brlapi" = "yes" ; then
+      feature_not_found "brlapi"
+    fi
+    brlapi=no
+  fi
+fi
+
+##########################################
+# curses probe
+if test "$mingw32" = "yes" ; then
+    curses_list="-lpdcurses"
+else
+    curses_list="-lncurses -lcurses"
+fi
+
+if test "$curses" != "no" ; then
+  curses_found=no
+  cat > $TMPC << EOF
+#include <curses.h>
+#ifdef __OpenBSD__
+#define resize_term resizeterm
+#endif
+int main(void) { resize_term(0, 0); return curses_version(); }
+EOF
+  for curses_lib in $curses_list; do
+    if compile_prog "" "$curses_lib" ; then
+      curses_found=yes
+      libs_softmmu="$curses_lib $libs_softmmu"
+      break
+    fi
+  done
+  if test "$curses_found" = "yes" ; then
+    curses=yes
+  else
+    if test "$curses" = "yes" ; then
+      feature_not_found "curses"
+    fi
+    curses=no
+  fi
+fi
+
+##########################################
+# curl probe
+
+if $pkg_config libcurl --modversion >/dev/null 2>&1; then
+  curlconfig="$pkg_config libcurl"
+else
+  curlconfig=curl-config
+fi
+
+if test "$curl" != "no" ; then
+  cat > $TMPC << EOF
+#include <curl/curl.h>
+int main(void) { curl_easy_init(); curl_multi_setopt(0, 0, 0); return 0; }
+EOF
+  curl_cflags=`$curlconfig --cflags 2>/dev/null`
+  curl_libs=`$curlconfig --libs 2>/dev/null`
+  if compile_prog "$curl_cflags" "$curl_libs" ; then
+    curl=yes
+    libs_tools="$curl_libs $libs_tools"
+    libs_softmmu="$curl_libs $libs_softmmu"
+  else
+    if test "$curl" = "yes" ; then
+      feature_not_found "curl"
+    fi
+    curl=no
+  fi
+fi # test "$curl"
+
+##########################################
+# check framework probe
+
+if test "$check_utests" != "no" ; then
+  cat > $TMPC << EOF
+#include <check.h>
+int main(void) { suite_create("qemu test"); return 0; }
+EOF
+  check_libs=`$pkg_config --libs check`
+  if compile_prog "" $check_libs ; then
+    check_utests=yes
+    libs_tools="$check_libs $libs_tools"
+  else
+    if test "$check_utests" = "yes" ; then
+      feature_not_found "check"
+    fi
+    check_utests=no
+  fi
+fi # test "$check_utests"
+
+##########################################
+# bluez support probe
+if test "$bluez" != "no" ; then
+  cat > $TMPC << EOF
+#include <bluetooth/bluetooth.h>
+int main(void) { return bt_error(0); }
+EOF
+  bluez_cflags=`$pkg_config --cflags bluez 2> /dev/null`
+  bluez_libs=`$pkg_config --libs bluez 2> /dev/null`
+  if compile_prog "$bluez_cflags" "$bluez_libs" ; then
+    bluez=yes
+    libs_softmmu="$bluez_libs $libs_softmmu"
+  else
+    if test "$bluez" = "yes" ; then
+      feature_not_found "bluez"
+    fi
+    bluez="no"
+  fi
+fi
+
+##########################################
+# glib support probe
+if test "$guest_agent" != "no" ; then
+    if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
+        glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
+        glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
+        libs_softmmu="$glib_libs $libs_softmmu"
+        libs_tools="$glib_libs $libs_tools"
+    else
+        echo "glib-2.0 required to compile QEMU"
+        exit 1
+    fi
+fi
+
+##########################################
+# pthread probe
+PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
+
+pthread=no
+cat > $TMPC << EOF
+#include <pthread.h>
+int main(void) { pthread_create(0,0,0,0); return 0; }
+EOF
+if compile_prog "" "" ; then
+  pthread=yes
+else
+  for pthread_lib in $PTHREADLIBS_LIST; do
+    if compile_prog "" "$pthread_lib" ; then
+      pthread=yes
+      LIBS="$pthread_lib $LIBS"
+      break
+    fi
+  done
+fi
+
+if test "$mingw32" != yes -a "$pthread" = no; then
+  echo
+  echo "Error: pthread check failed"
+  echo "Make sure to have the pthread libs and headers installed."
+  echo
+  exit 1
+fi
+
+##########################################
+# rbd probe
+if test "$rbd" != "no" ; then
+  cat > $TMPC <<EOF
+#include <stdio.h>
+#include <rbd/librbd.h>
+int main(void) {
+    rados_t cluster;
+    rados_create(&cluster, NULL);
+    return 0;
+}
+EOF
+  rbd_libs="-lrbd -lrados"
+  if compile_prog "" "$rbd_libs" ; then
+    rbd=yes
+    libs_tools="$rbd_libs $libs_tools"
+    libs_softmmu="$rbd_libs $libs_softmmu"
+  else
+    if test "$rbd" = "yes" ; then
+      feature_not_found "rados block device"
+    fi
+    rbd=no
+  fi
+fi
+
+##########################################
+# linux-aio probe
+
+if test "$linux_aio" != "no" ; then
+  cat > $TMPC <<EOF
+#include <libaio.h>
+#include <sys/eventfd.h>
+#include <stddef.h>
+int main(void) { io_setup(0, NULL); io_set_eventfd(NULL, 0); eventfd(0, 0); return 0; }
+EOF
+  if compile_prog "" "-laio" ; then
+    linux_aio=yes
+    libs_softmmu="$libs_softmmu -laio"
+    libs_tools="$libs_tools -laio"
+  else
+    if test "$linux_aio" = "yes" ; then
+      feature_not_found "linux AIO"
+    fi
+    linux_aio=no
+  fi
+fi
+
+##########################################
+# attr probe
+
+if test "$attr" != "no" ; then
+  cat > $TMPC <<EOF
+#include <stdio.h>
+#include <sys/types.h>
+#include <attr/xattr.h>
+int main(void) { getxattr(NULL, NULL, NULL, 0); setxattr(NULL, NULL, NULL, 0, 0); return 0; }
+EOF
+  if compile_prog "" "-lattr" ; then
+    attr=yes
+    LIBS="-lattr $LIBS"
+  else
+    if test "$attr" = "yes" ; then
+      feature_not_found "ATTR"
+    fi
+    attr=no
+  fi
+fi
+
+##########################################
+# iovec probe
+cat > $TMPC <<EOF
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+int main(void) { struct iovec iov; return 0; }
+EOF
+iovec=no
+if compile_prog "" "" ; then
+  iovec=yes
+fi
+
+##########################################
+# preadv probe
+cat > $TMPC <<EOF
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+int main(void) { preadv; }
+EOF
+preadv=no
+if compile_prog "" "" ; then
+  preadv=yes
+fi
+
+##########################################
+# fdt probe
+if test "$fdt" != "no" ; then
+  fdt_libs="-lfdt"
+  cat > $TMPC << EOF
+int main(void) { return 0; }
+EOF
+  if compile_prog "" "$fdt_libs" ; then
+    fdt=yes
+  else
+    if test "$fdt" = "yes" ; then
+      feature_not_found "fdt"
+    fi
+    fdt_libs=
+    fdt=no
+  fi
+fi
+
+##########################################
+# opengl probe, used by milkymist-tmu2
+if test "$opengl" != "no" ; then
+  opengl_libs="-lGL"
+  cat > $TMPC << EOF
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+int main(void) { GL_VERSION; return 0; }
+EOF
+  if compile_prog "" "-lGL" ; then
+    opengl=yes
+  else
+    if test "$opengl" = "yes" ; then
+      feature_not_found "opengl"
+    fi
+    opengl_libs=
+    opengl=no
+  fi
+fi
+
+#
+# Check for xxxat() functions when we are building linux-user
+# emulator.  This is done because older glibc versions don't
+# have syscall stubs for these implemented.
+#
+atfile=no
+cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+	/* try to unlink nonexisting file */
+	return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
+}
+EOF
+if compile_prog "" "" ; then
+  atfile=yes
+fi
+
+# Check for inotify functions when we are building linux-user
+# emulator.  This is done because older glibc versions don't
+# have syscall stubs for these implemented.  In that case we
+# don't provide them even if kernel supports them.
+#
+inotify=no
+cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+	/* try to start inotify */
+	return inotify_init();
+}
+EOF
+if compile_prog "" "" ; then
+  inotify=yes
+fi
+
+inotify1=no
+cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+    /* try to start inotify */
+    return inotify_init1(0);
+}
+EOF
+if compile_prog "" "" ; then
+  inotify1=yes
+fi
+
+# check if utimensat and futimens are supported
+utimens=no
+cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <stddef.h>
+#include <fcntl.h>
+
+int main(void)
+{
+    utimensat(AT_FDCWD, "foo", NULL, 0);
+    futimens(0, NULL);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  utimens=yes
+fi
+
+# check if pipe2 is there
+pipe2=no
+cat > $TMPC << EOF
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(void)
+{
+    int pipefd[2];
+    pipe2(pipefd, O_CLOEXEC);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  pipe2=yes
+fi
+
+# check if accept4 is there
+accept4=no
+cat > $TMPC << EOF
+#include <sys/socket.h>
+#include <stddef.h>
+
+int main(void)
+{
+    accept4(0, NULL, NULL, SOCK_CLOEXEC);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  accept4=yes
+fi
+
+# check if tee/splice is there. vmsplice was added same time.
+splice=no
+cat > $TMPC << EOF
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+
+int main(void)
+{
+    int len, fd;
+    len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
+    splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  splice=yes
+fi
+
+##########################################
+# signalfd probe
+signalfd="no"
+cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <signal.h>
+int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
+EOF
+
+if compile_prog "" "" ; then
+  signalfd=yes
+elif test "$kvm" = "yes" -a "$io_thread" != "yes"; then
+  echo
+  echo "ERROR: Host kernel lacks signalfd() support,"
+  echo "but KVM depends on it when the IO thread is disabled."
+  echo
+  exit 1
+fi
+
+# check if eventfd is supported
+eventfd=no
+cat > $TMPC << EOF
+#include <sys/eventfd.h>
+
+int main(void)
+{
+    int efd = eventfd(0, 0);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  eventfd=yes
+fi
+
+# check for fallocate
+fallocate=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+
+int main(void)
+{
+    fallocate(0, 0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  fallocate=yes
+fi
+
+# check for sync_file_range
+sync_file_range=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+
+int main(void)
+{
+    sync_file_range(0, 0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  sync_file_range=yes
+fi
+
+# check for linux/fiemap.h and FS_IOC_FIEMAP
+fiemap=no
+cat > $TMPC << EOF
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+int main(void)
+{
+    ioctl(0, FS_IOC_FIEMAP, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  fiemap=yes
+fi
+
+# check for dup3
+dup3=no
+cat > $TMPC << EOF
+#include <unistd.h>
+
+int main(void)
+{
+    dup3(0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  dup3=yes
+fi
+
+# check for epoll support
+epoll=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    epoll_create(0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll=yes
+fi
+
+# epoll_create1 and epoll_pwait are later additions
+# so we must check separately for their presence
+epoll_create1=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    /* Note that we use epoll_create1 as a value, not as
+     * a function being called. This is necessary so that on
+     * old SPARC glibc versions where the function was present in
+     * the library but not declared in the header file we will
+     * fail the configure check. (Otherwise we will get a compiler
+     * warning but not an error, and will proceed to fail the
+     * qemu compile where we compile with -Werror.)
+     */
+    epoll_create1;
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll_create1=yes
+fi
+
+epoll_pwait=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+    epoll_pwait(0, 0, 0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  epoll_pwait=yes
+fi
+
+# Check if tools are available to build documentation.
+if test "$docs" != "no" ; then
+  if has makeinfo && has pod2man; then
+    docs=yes
+  else
+    if test "$docs" = "yes" ; then
+      feature_not_found "docs"
+    fi
+    docs=no
+  fi
+fi
+
+# Search for bswap_32 function
+byteswap_h=no
+cat > $TMPC << EOF
+#include <byteswap.h>
+int main(void) { return bswap_32(0); }
+EOF
+if compile_prog "" "" ; then
+  byteswap_h=yes
+fi
+
+# Search for bswap_32 function
+bswap_h=no
+cat > $TMPC << EOF
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <machine/bswap.h>
+int main(void) { return bswap32(0); }
+EOF
+if compile_prog "" "" ; then
+  bswap_h=yes
+fi
+
+##########################################
+# Do we need librt
+cat > $TMPC <<EOF
+#include <signal.h>
+#include <time.h>
+int main(void) { clockid_t id; return clock_gettime(id, NULL); }
+EOF
+
+if compile_prog "" "" ; then
+  :
+elif compile_prog "" "-lrt" ; then
+  LIBS="-lrt $LIBS"
+fi
+
+if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
+        "$aix" != "yes" -a "$haiku" != "yes" ; then
+    libs_softmmu="-lutil $libs_softmmu"
+fi
+
+##########################################
+# check if the compiler defines offsetof
+
+need_offsetof=yes
+cat > $TMPC << EOF
+#include <stddef.h>
+int main(void) { struct s { int f; }; return offsetof(struct s, f); }
+EOF
+if compile_prog "" "" ; then
+    need_offsetof=no
+fi
+
+##########################################
+# check if the compiler understands attribute warn_unused_result
+#
+# This could be smarter, but gcc -Werror does not error out even when warning
+# about attribute warn_unused_result
+
+gcc_attribute_warn_unused_result=no
+cat > $TMPC << EOF
+#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4)
+#error gcc 3.3 or older
+#endif
+int main(void) { return 0;}
+EOF
+if compile_prog "" ""; then
+    gcc_attribute_warn_unused_result=yes
+fi
+
+# spice probe
+if test "$spice" != "no" ; then
+  cat > $TMPC << EOF
+#include <spice.h>
+int main(void) { spice_server_new(); return 0; }
+EOF
+  spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
+  spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
+  if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \
+     compile_prog "$spice_cflags" "$spice_libs" ; then
+    spice="yes"
+    libs_softmmu="$libs_softmmu $spice_libs"
+    QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
+  else
+    if test "$spice" = "yes" ; then
+      feature_not_found "spice"
+    fi
+    spice="no"
+  fi
+fi
+
+# check for libcacard for smartcard support
+if test "$smartcard" != "no" ; then
+    smartcard="yes"
+    smartcard_cflags=""
+    # TODO - what's the minimal nss version we support?
+    if test "$smartcard_nss" != "no"; then
+        if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
+            smartcard_nss="yes"
+            smartcard_cflags="-I\$(SRC_PATH)/libcacard"
+            libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
+            libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
+            QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
+            LIBS="$libcacard_libs $LIBS"
+        else
+            if test "$smartcard_nss" = "yes"; then
+                feature_not_found "nss"
+            fi
+            smartcard_nss="no"
+        fi
+    fi
+fi
+if test "$smartcard" = "no" ; then
+    smartcard_nss="no"
+fi
+
+# check for usbredirparser for usb network redirection support
+if test "$usb_redir" != "no" ; then
+    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
+        usb_redir="yes"
+        usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
+        usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
+        QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
+        LIBS="$LIBS $usb_redir_libs"
+    else
+        if test "$usb_redir" = "yes"; then
+            feature_not_found "usb-redir"
+        fi
+        usb_redir="no"
+    fi
+fi
+
+##########################################
+
+##########################################
+# check if we have fdatasync
+
+fdatasync=no
+cat > $TMPC << EOF
+#include <unistd.h>
+int main(void) {
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+return fdatasync(0);
+#else
+#abort Not supported
+#endif
+}
+EOF
+if compile_prog "" "" ; then
+    fdatasync=yes
+fi
+
+##########################################
+# check if we have madvise
+
+madvise=no
+cat > $TMPC << EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stddef.h>
+int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }
+EOF
+if compile_prog "" "" ; then
+    madvise=yes
+fi
+
+##########################################
+# check if we have posix_madvise
+
+posix_madvise=no
+cat > $TMPC << EOF
+#include <sys/mman.h>
+#include <stddef.h>
+int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }
+EOF
+if compile_prog "" "" ; then
+    posix_madvise=yes
+fi
+
+##########################################
+# check if trace backend exists
+
+sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+if test "$?" -ne 0 ; then
+  echo
+  echo "Error: invalid trace backend"
+  echo "Please choose a supported trace backend."
+  echo
+  exit 1
+fi
+
+##########################################
+# For 'ust' backend, test if ust headers are present
+if test "$trace_backend" = "ust"; then
+  cat > $TMPC << EOF
+#include <ust/tracepoint.h>
+#include <ust/marker.h>
+int main(void) { return 0; }
+EOF
+  if compile_prog "" "" ; then
+    LIBS="-lust $LIBS"
+  else
+    echo
+    echo "Error: Trace backend 'ust' missing libust header files"
+    echo
+    exit 1
+  fi
+fi
+
+##########################################
+# For 'dtrace' backend, test if 'dtrace' command is present
+if test "$trace_backend" = "dtrace"; then
+  if ! has 'dtrace' ; then
+    echo
+    echo "Error: dtrace command is not found in PATH $PATH"
+    echo
+    exit 1
+  fi
+  trace_backend_stap="no"
+  if has 'stap' ; then
+    trace_backend_stap="yes"
+  fi
+fi
+
+##########################################
+# __sync_fetch_and_and requires at least -march=i486. Many toolchains
+# use i686 as default anyway, but for those that don't, an explicit
+# specification is necessary
+if test $vhost_net = "yes" && test $cpu = "i386"; then
+  cat > $TMPC << EOF
+int sfaa(unsigned *ptr)
+{
+  return __sync_fetch_and_and(ptr, 0);
+}
+
+int main(int argc, char **argv)
+{
+  int val = 42;
+  sfaa(&val);
+  return val;
+}
+EOF
+  if ! compile_prog "" "" ; then
+    CFLAGS+="-march=i486"
+  fi
+fi
+
+##########################################
+# End of CC checks
+# After here, no more $cc or $ld runs
+
+if test "$debug" = "no" ; then
+  CFLAGS="-O2 $CFLAGS"
+fi
+
+# Consult white-list to determine whether to enable werror
+# by default.  Only enable by default for git builds
+z_version=`cut -f3 -d. $source_path/VERSION`
+
+if test -z "$werror" ; then
+    if test "$z_version" = "50" -a \
+        "$linux" = "yes" ; then
+        werror="yes"
+    else
+        werror="no"
+    fi
+fi
+
+# Disable zero malloc errors for official releases unless explicitly told to
+# enable/disable
+if test -z "$zero_malloc" ; then
+    if test "$z_version" = "50" ; then
+	zero_malloc="no"
+    else
+	zero_malloc="yes"
+    fi
+fi
+
+if test "$werror" = "yes" ; then
+    QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
+fi
+
+if test "$solaris" = "no" ; then
+    if $ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then
+        LDFLAGS="-Wl,--warn-common $LDFLAGS"
+    fi
+fi
+
+# Use ASLR, no-SEH and DEP if available
+if test "$mingw32" = "yes" ; then
+    for flag in --dynamicbase --no-seh --nxcompat; do
+        if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ; then
+            LDFLAGS="-Wl,$flag $LDFLAGS"
+        fi
+    done
+fi
+
+confdir=$sysconfdir$confsuffix
+
+tools=
+if test "$softmmu" = yes ; then
+  tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
+  if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
+      tools="qemu-nbd\$(EXESUF) $tools"
+    if [ "$guest_agent" = "yes" ]; then
+      tools="qemu-ga\$(EXESUF) $tools"
+    fi
+    if [ "$check_utests" = "yes" ]; then
+      tools="check-qint check-qstring check-qdict check-qlist $tools"
+      tools="check-qfloat check-qjson $tools"
+    fi
+  fi
+fi
+
+# Mac OS X ships with a broken assembler
+roms=
+if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
+        "$targetos" != "Darwin" -a "$targetos" != "SunOS" -a \
+        "$softmmu" = yes ; then
+  roms="optionrom"
+fi
+if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
+  roms="$roms spapr-rtas"
+fi
+
+echo "Install prefix    $prefix"
+echo "BIOS directory    `eval echo $datadir`"
+echo "binary directory  `eval echo $bindir`"
+echo "library directory `eval echo $libdir`"
+echo "config directory  `eval echo $sysconfdir`"
+if test "$mingw32" = "no" ; then
+echo "Manual directory  `eval echo $mandir`"
+echo "ELF interp prefix $interp_prefix"
+fi
+echo "Source path       $source_path"
+echo "C compiler        $cc"
+echo "Host C compiler   $host_cc"
+echo "CFLAGS            $CFLAGS"
+echo "QEMU_CFLAGS       $QEMU_CFLAGS"
+echo "LDFLAGS           $LDFLAGS"
+echo "make              $make"
+echo "install           $install"
+echo "python            $python"
+if test "$slirp" = "yes" ; then
+    echo "smbd              $smbd"
+fi
+echo "host CPU          $cpu"
+echo "host big endian   $bigendian"
+echo "target list       $target_list"
+echo "tcg debug enabled $debug_tcg"
+echo "Mon debug enabled $debug_mon"
+echo "gprof enabled     $gprof"
+echo "sparse enabled    $sparse"
+echo "strip binaries    $strip_opt"
+echo "profiler          $profiler"
+echo "static build      $static"
+echo "-Werror enabled   $werror"
+if test "$darwin" = "yes" ; then
+    echo "Cocoa support     $cocoa"
+fi
+echo "SDL support       $sdl"
+echo "curses support    $curses"
+echo "curl support      $curl"
+echo "check support     $check_utests"
+echo "mingw32 support   $mingw32"
+echo "Audio drivers     $audio_drv_list"
+echo "Extra audio cards $audio_card_list"
+echo "Block whitelist   $block_drv_whitelist"
+echo "Mixer emulation   $mixemu"
+echo "VNC support       $vnc"
+if test "$vnc" = "yes" ; then
+    echo "VNC TLS support   $vnc_tls"
+    echo "VNC SASL support  $vnc_sasl"
+    echo "VNC JPEG support  $vnc_jpeg"
+    echo "VNC PNG support   $vnc_png"
+    echo "VNC thread        $vnc_thread"
+fi
+if test -n "$sparc_cpu"; then
+    echo "Target Sparc Arch $sparc_cpu"
+fi
+echo "xen support       $xen"
+echo "brlapi support    $brlapi"
+echo "bluez  support    $bluez"
+echo "Documentation     $docs"
+[ ! -z "$uname_release" ] && \
+echo "uname -r          $uname_release"
+echo "NPTL support      $nptl"
+echo "GUEST_BASE        $guest_base"
+echo "PIE user targets  $user_pie"
+echo "vde support       $vde"
+echo "IO thread         $io_thread"
+echo "Linux AIO support $linux_aio"
+echo "ATTR/XATTR support $attr"
+echo "Install blobs     $blobs"
+echo "KVM support       $kvm"
+echo "fdt support       $fdt"
+echo "preadv support    $preadv"
+echo "fdatasync         $fdatasync"
+echo "madvise           $madvise"
+echo "posix_madvise     $posix_madvise"
+echo "uuid support      $uuid"
+echo "vhost-net support $vhost_net"
+echo "Trace backend     $trace_backend"
+echo "Trace output file $trace_file-<pid>"
+echo "spice support     $spice"
+echo "rbd support       $rbd"
+echo "xfsctl support    $xfs"
+echo "nss used          $smartcard_nss"
+echo "usb net redir     $usb_redir"
+echo "OpenGL support    $opengl"
+echo "build guest agent $guest_agent"
+
+if test $sdl_too_old = "yes"; then
+echo "-> Your SDL version is too old - please upgrade to have SDL support"
+fi
+
+config_host_mak="config-host.mak"
+config_host_ld="config-host.ld"
+
+echo "# Automatically generated by configure - do not modify" > $config_host_mak
+printf "# Configured with:" >> $config_host_mak
+printf " '%s'" "$0" "$@" >> $config_host_mak
+echo >> $config_host_mak
+
+echo all: >> $config_host_mak
+echo "prefix=$prefix" >> $config_host_mak
+echo "bindir=$bindir" >> $config_host_mak
+echo "libdir=$libdir" >> $config_host_mak
+echo "mandir=$mandir" >> $config_host_mak
+echo "datadir=$datadir" >> $config_host_mak
+echo "sysconfdir=$sysconfdir" >> $config_host_mak
+echo "docdir=$docdir" >> $config_host_mak
+echo "confdir=$confdir" >> $config_host_mak
+
+case "$cpu" in
+  i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32)
+    ARCH=$cpu
+  ;;
+  armv4b|armv4l)
+    ARCH=arm
+  ;;
+esac
+echo "ARCH=$ARCH" >> $config_host_mak
+if test "$debug_tcg" = "yes" ; then
+  echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
+fi
+if test "$debug_mon" = "yes" ; then
+  echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
+fi
+if test "$debug" = "yes" ; then
+  echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
+fi
+if test "$strip_opt" = "yes" ; then
+  echo "STRIP=${strip}" >> $config_host_mak
+fi
+if test "$bigendian" = "yes" ; then
+  echo "HOST_WORDS_BIGENDIAN=y" >> $config_host_mak
+fi
+echo "HOST_LONG_BITS=$hostlongbits" >> $config_host_mak
+if test "$mingw32" = "yes" ; then
+  echo "CONFIG_WIN32=y" >> $config_host_mak
+  rc_version=`cat $source_path/VERSION`
+  version_major=${rc_version%%.*}
+  rc_version=${rc_version#*.}
+  version_minor=${rc_version%%.*}
+  rc_version=${rc_version#*.}
+  version_subminor=${rc_version%%.*}
+  version_micro=0
+  echo "CONFIG_FILEVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
+  echo "CONFIG_PRODUCTVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
+else
+  echo "CONFIG_POSIX=y" >> $config_host_mak
+fi
+
+if test "$linux" = "yes" ; then
+  echo "CONFIG_LINUX=y" >> $config_host_mak
+fi
+
+if test "$darwin" = "yes" ; then
+  echo "CONFIG_DARWIN=y" >> $config_host_mak
+fi
+
+if test "$aix" = "yes" ; then
+  echo "CONFIG_AIX=y" >> $config_host_mak
+fi
+
+if test "$solaris" = "yes" ; then
+  echo "CONFIG_SOLARIS=y" >> $config_host_mak
+  echo "CONFIG_SOLARIS_VERSION=$solarisrev" >> $config_host_mak
+  if test "$needs_libsunmath" = "yes" ; then
+    echo "CONFIG_NEEDS_LIBSUNMATH=y" >> $config_host_mak
+  fi
+fi
+if test "$haiku" = "yes" ; then
+  echo "CONFIG_HAIKU=y" >> $config_host_mak
+fi
+if test "$static" = "yes" ; then
+  echo "CONFIG_STATIC=y" >> $config_host_mak
+fi
+if test $profiler = "yes" ; then
+  echo "CONFIG_PROFILER=y" >> $config_host_mak
+fi
+if test "$slirp" = "yes" ; then
+  echo "CONFIG_SLIRP=y" >> $config_host_mak
+  echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
+  QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES"
+fi
+if test "$vde" = "yes" ; then
+  echo "CONFIG_VDE=y" >> $config_host_mak
+fi
+for card in $audio_card_list; do
+    def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
+    echo "$def=y" >> $config_host_mak
+done
+echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config_host_mak
+for drv in $audio_drv_list; do
+    def=CONFIG_`echo $drv | tr '[:lower:]' '[:upper:]'`
+    echo "$def=y" >> $config_host_mak
+    if test "$drv" = "fmod"; then
+        echo "FMOD_CFLAGS=-I$fmod_inc" >> $config_host_mak
+    fi
+done
+if test "$audio_pt_int" = "yes" ; then
+  echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
+fi
+if test "$audio_win_int" = "yes" ; then
+  echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
+fi
+echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak
+if test "$mixemu" = "yes" ; then
+  echo "CONFIG_MIXEMU=y" >> $config_host_mak
+fi
+if test "$vnc" = "yes" ; then
+  echo "CONFIG_VNC=y" >> $config_host_mak
+fi
+if test "$vnc_tls" = "yes" ; then
+  echo "CONFIG_VNC_TLS=y" >> $config_host_mak
+  echo "VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_host_mak
+fi
+if test "$vnc_sasl" = "yes" ; then
+  echo "CONFIG_VNC_SASL=y" >> $config_host_mak
+  echo "VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_host_mak
+fi
+if test "$vnc_jpeg" = "yes" ; then
+  echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
+  echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
+fi
+if test "$vnc_png" = "yes" ; then
+  echo "CONFIG_VNC_PNG=y" >> $config_host_mak
+  echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
+fi
+if test "$vnc_thread" = "yes" ; then
+  echo "CONFIG_VNC_THREAD=y" >> $config_host_mak
+fi
+if test "$fnmatch" = "yes" ; then
+  echo "CONFIG_FNMATCH=y" >> $config_host_mak
+fi
+if test "$uuid" = "yes" ; then
+  echo "CONFIG_UUID=y" >> $config_host_mak
+fi
+if test "$xfs" = "yes" ; then
+  echo "CONFIG_XFS=y" >> $config_host_mak
+fi
+qemu_version=`head $source_path/VERSION`
+echo "VERSION=$qemu_version" >>$config_host_mak
+echo "PKGVERSION=$pkgversion" >>$config_host_mak
+echo "SRC_PATH=$source_path" >> $config_host_mak
+echo "TARGET_DIRS=$target_list" >> $config_host_mak
+if [ "$docs" = "yes" ] ; then
+  echo "BUILD_DOCS=yes" >> $config_host_mak
+fi
+if test "$sdl" = "yes" ; then
+  echo "CONFIG_SDL=y" >> $config_host_mak
+  echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
+fi
+if test "$cocoa" = "yes" ; then
+  echo "CONFIG_COCOA=y" >> $config_host_mak
+fi
+if test "$curses" = "yes" ; then
+  echo "CONFIG_CURSES=y" >> $config_host_mak
+fi
+if test "$atfile" = "yes" ; then
+  echo "CONFIG_ATFILE=y" >> $config_host_mak
+fi
+if test "$utimens" = "yes" ; then
+  echo "CONFIG_UTIMENSAT=y" >> $config_host_mak
+fi
+if test "$pipe2" = "yes" ; then
+  echo "CONFIG_PIPE2=y" >> $config_host_mak
+fi
+if test "$accept4" = "yes" ; then
+  echo "CONFIG_ACCEPT4=y" >> $config_host_mak
+fi
+if test "$splice" = "yes" ; then
+  echo "CONFIG_SPLICE=y" >> $config_host_mak
+fi
+if test "$eventfd" = "yes" ; then
+  echo "CONFIG_EVENTFD=y" >> $config_host_mak
+fi
+if test "$fallocate" = "yes" ; then
+  echo "CONFIG_FALLOCATE=y" >> $config_host_mak
+fi
+if test "$sync_file_range" = "yes" ; then
+  echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
+fi
+if test "$fiemap" = "yes" ; then
+  echo "CONFIG_FIEMAP=y" >> $config_host_mak
+fi
+if test "$dup3" = "yes" ; then
+  echo "CONFIG_DUP3=y" >> $config_host_mak
+fi
+if test "$epoll" = "yes" ; then
+  echo "CONFIG_EPOLL=y" >> $config_host_mak
+fi
+if test "$epoll_create1" = "yes" ; then
+  echo "CONFIG_EPOLL_CREATE1=y" >> $config_host_mak
+fi
+if test "$epoll_pwait" = "yes" ; then
+  echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
+fi
+if test "$inotify" = "yes" ; then
+  echo "CONFIG_INOTIFY=y" >> $config_host_mak
+fi
+if test "$inotify1" = "yes" ; then
+  echo "CONFIG_INOTIFY1=y" >> $config_host_mak
+fi
+if test "$byteswap_h" = "yes" ; then
+  echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
+fi
+if test "$bswap_h" = "yes" ; then
+  echo "CONFIG_MACHINE_BSWAP_H=y" >> $config_host_mak
+fi
+if test "$curl" = "yes" ; then
+  echo "CONFIG_CURL=y" >> $config_host_mak
+  echo "CURL_CFLAGS=$curl_cflags" >> $config_host_mak
+fi
+if test "$brlapi" = "yes" ; then
+  echo "CONFIG_BRLAPI=y" >> $config_host_mak
+fi
+if test "$bluez" = "yes" ; then
+  echo "CONFIG_BLUEZ=y" >> $config_host_mak
+  echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
+fi
+echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
+if test "$xen" = "yes" ; then
+  echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
+  echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
+fi
+if test "$io_thread" = "yes" ; then
+  echo "CONFIG_IOTHREAD=y" >> $config_host_mak
+fi
+if test "$linux_aio" = "yes" ; then
+  echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
+fi
+if test "$attr" = "yes" ; then
+  echo "CONFIG_ATTR=y" >> $config_host_mak
+fi
+if test "$linux" = "yes" ; then
+  if test "$attr" = "yes" ; then
+    echo "CONFIG_VIRTFS=y" >> $config_host_mak
+  fi
+fi
+if test "$blobs" = "yes" ; then
+  echo "INSTALL_BLOBS=yes" >> $config_host_mak
+fi
+if test "$iovec" = "yes" ; then
+  echo "CONFIG_IOVEC=y" >> $config_host_mak
+fi
+if test "$preadv" = "yes" ; then
+  echo "CONFIG_PREADV=y" >> $config_host_mak
+fi
+if test "$fdt" = "yes" ; then
+  echo "CONFIG_FDT=y" >> $config_host_mak
+fi
+if test "$signalfd" = "yes" ; then
+  echo "CONFIG_SIGNALFD=y" >> $config_host_mak
+fi
+if test "$need_offsetof" = "yes" ; then
+  echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
+fi
+if test "$gcc_attribute_warn_unused_result" = "yes" ; then
+  echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak
+fi
+if test "$fdatasync" = "yes" ; then
+  echo "CONFIG_FDATASYNC=y" >> $config_host_mak
+fi
+if test "$madvise" = "yes" ; then
+  echo "CONFIG_MADVISE=y" >> $config_host_mak
+fi
+if test "$posix_madvise" = "yes" ; then
+  echo "CONFIG_POSIX_MADVISE=y" >> $config_host_mak
+fi
+
+if test "$spice" = "yes" ; then
+  echo "CONFIG_SPICE=y" >> $config_host_mak
+fi
+
+if test "$smartcard" = "yes" ; then
+  echo "CONFIG_SMARTCARD=y" >> $config_host_mak
+fi
+
+if test "$smartcard_nss" = "yes" ; then
+  echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
+fi
+
+if test "$usb_redir" = "yes" ; then
+  echo "CONFIG_USB_REDIR=y" >> $config_host_mak
+fi
+
+if test "$opengl" = "yes" ; then
+  echo "CONFIG_OPENGL=y" >> $config_host_mak
+fi
+
+# XXX: suppress that
+if [ "$bsd" = "yes" ] ; then
+  echo "CONFIG_BSD=y" >> $config_host_mak
+fi
+
+echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
+
+if test "$zero_malloc" = "yes" ; then
+  echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
+fi
+if test "$rbd" = "yes" ; then
+  echo "CONFIG_RBD=y" >> $config_host_mak
+fi
+
+# USB host support
+case "$usb" in
+linux)
+  echo "HOST_USB=linux" >> $config_host_mak
+;;
+bsd)
+  echo "HOST_USB=bsd" >> $config_host_mak
+;;
+*)
+  echo "HOST_USB=stub" >> $config_host_mak
+;;
+esac
+
+echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak
+if test "$trace_backend" = "simple"; then
+  echo "CONFIG_SIMPLE_TRACE=y" >> $config_host_mak
+fi
+# Set the appropriate trace file.
+if test "$trace_backend" = "simple"; then
+  trace_file="\"$trace_file-\" FMT_pid"
+fi
+if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
+  echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
+fi
+echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
+
+echo "TOOLS=$tools" >> $config_host_mak
+echo "ROMS=$roms" >> $config_host_mak
+echo "MAKE=$make" >> $config_host_mak
+echo "INSTALL=$install" >> $config_host_mak
+echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak
+echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
+echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
+echo "PYTHON=$python" >> $config_host_mak
+echo "CC=$cc" >> $config_host_mak
+echo "CC_I386=$cc_i386" >> $config_host_mak
+echo "HOST_CC=$host_cc" >> $config_host_mak
+echo "AR=$ar" >> $config_host_mak
+echo "OBJCOPY=$objcopy" >> $config_host_mak
+echo "LD=$ld" >> $config_host_mak
+echo "WINDRES=$windres" >> $config_host_mak
+echo "LIBTOOL=$libtool" >> $config_host_mak
+echo "CFLAGS=$CFLAGS" >> $config_host_mak
+echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
+echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
+if test "$sparse" = "yes" ; then
+  echo "CC           := REAL_CC=\"\$(CC)\" cgcc"       >> $config_host_mak
+  echo "HOST_CC      := REAL_CC=\"\$(HOST_CC)\" cgcc"  >> $config_host_mak
+  echo "QEMU_CFLAGS  += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
+fi
+echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak
+echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
+echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
+echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
+echo "LIBS+=$LIBS" >> $config_host_mak
+echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
+echo "EXESUF=$EXESUF" >> $config_host_mak
+
+# generate list of library paths for linker script
+
+$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > ${config_host_ld}
+
+if test -f ${config_host_ld}~ ; then
+  if cmp -s $config_host_ld ${config_host_ld}~ ; then
+    mv ${config_host_ld}~ $config_host_ld
+  else
+    rm ${config_host_ld}~
+  fi
+fi
+
+for d in libdis libdis-user; do
+    mkdir -p $d
+    symlink $source_path/Makefile.dis $d/Makefile
+    echo > $d/config.mak
+done
+if test "$static" = "no" -a "$user_pie" = "yes" ; then
+  echo "QEMU_CFLAGS+=-fpie" > libdis-user/config.mak
+fi
+
+for target in $target_list; do
+target_dir="$target"
+config_target_mak=$target_dir/config-target.mak
+target_arch2=`echo $target | cut -d '-' -f 1`
+target_bigendian="no"
+
+case "$target_arch2" in
+  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
+  target_bigendian=yes
+  ;;
+esac
+target_softmmu="no"
+target_user_only="no"
+target_linux_user="no"
+target_darwin_user="no"
+target_bsd_user="no"
+case "$target" in
+  ${target_arch2}-softmmu)
+    target_softmmu="yes"
+    ;;
+  ${target_arch2}-linux-user)
+    if test "$linux" != "yes" ; then
+      echo "ERROR: Target '$target' is only available on a Linux host"
+      exit 1
+    fi
+    target_user_only="yes"
+    target_linux_user="yes"
+    ;;
+  ${target_arch2}-darwin-user)
+    if test "$darwin" != "yes" ; then
+      echo "ERROR: Target '$target' is only available on a Darwin host"
+      exit 1
+    fi
+    target_user_only="yes"
+    target_darwin_user="yes"
+    ;;
+  ${target_arch2}-bsd-user)
+    if test "$bsd" != "yes" ; then
+      echo "ERROR: Target '$target' is only available on a BSD host"
+      exit 1
+    fi
+    target_user_only="yes"
+    target_bsd_user="yes"
+    ;;
+  *)
+    echo "ERROR: Target '$target' not recognised"
+    exit 1
+    ;;
+esac
+
+mkdir -p $target_dir
+mkdir -p $target_dir/fpu
+mkdir -p $target_dir/tcg
+mkdir -p $target_dir/ide
+mkdir -p $target_dir/9pfs
+if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
+  mkdir -p $target_dir/nwfpe
+fi
+symlink $source_path/Makefile.target $target_dir/Makefile
+
+
+echo "# Automatically generated by configure - do not modify" > $config_target_mak
+
+bflt="no"
+target_nptl="no"
+interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_arch2/g"`
+echo "CONFIG_QEMU_INTERP_PREFIX=\"$interp_prefix1\"" >> $config_target_mak
+gdb_xml_files=""
+target_short_alignment=2
+target_int_alignment=4
+target_long_alignment=4
+target_llong_alignment=8
+target_libs_softmmu=
+
+TARGET_ARCH="$target_arch2"
+TARGET_BASE_ARCH=""
+TARGET_ABI_DIR=""
+
+case "$target_arch2" in
+  i386)
+    target_phys_bits=64
+  ;;
+  x86_64)
+    TARGET_BASE_ARCH=i386
+    target_phys_bits=64
+    target_long_alignment=8
+  ;;
+  alpha)
+    target_phys_bits=64
+    target_long_alignment=8
+    target_nptl="yes"
+  ;;
+  arm|armeb)
+    TARGET_ARCH=arm
+    bflt="yes"
+    target_nptl="yes"
+    gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
+    target_phys_bits=32
+    target_llong_alignment=4
+  ;;
+  cris)
+    target_nptl="yes"
+    target_phys_bits=32
+  ;;
+  lm32)
+    target_phys_bits=32
+    target_libs_softmmu="$opengl_libs"
+  ;;
+  m68k)
+    bflt="yes"
+    gdb_xml_files="cf-core.xml cf-fp.xml"
+    target_phys_bits=32
+    target_int_alignment=2
+    target_long_alignment=2
+    target_llong_alignment=2
+  ;;
+  microblaze|microblazeel)
+    TARGET_ARCH=microblaze
+    bflt="yes"
+    target_nptl="yes"
+    target_phys_bits=32
+    target_libs_softmmu="$fdt_libs"
+  ;;
+  mips|mipsel)
+    TARGET_ARCH=mips
+    echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak
+    target_nptl="yes"
+    target_phys_bits=64
+  ;;
+  mipsn32|mipsn32el)
+    TARGET_ARCH=mipsn32
+    TARGET_BASE_ARCH=mips
+    echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak
+    target_phys_bits=64
+  ;;
+  mips64|mips64el)
+    TARGET_ARCH=mips64
+    TARGET_BASE_ARCH=mips
+    echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
+    target_phys_bits=64
+    target_long_alignment=8
+  ;;
+  ppc)
+    gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+    target_phys_bits=32
+    target_nptl="yes"
+    target_libs_softmmu="$fdt_libs"
+  ;;
+  ppcemb)
+    TARGET_BASE_ARCH=ppc
+    TARGET_ABI_DIR=ppc
+    gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+    target_phys_bits=64
+    target_nptl="yes"
+    target_libs_softmmu="$fdt_libs"
+  ;;
+  ppc64)
+    TARGET_BASE_ARCH=ppc
+    TARGET_ABI_DIR=ppc
+    gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+    target_phys_bits=64
+    target_long_alignment=8
+    target_libs_softmmu="$fdt_libs"
+  ;;
+  ppc64abi32)
+    TARGET_ARCH=ppc64
+    TARGET_BASE_ARCH=ppc
+    TARGET_ABI_DIR=ppc
+    echo "TARGET_ABI32=y" >> $config_target_mak
+    gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
+    target_phys_bits=64
+    target_libs_softmmu="$fdt_libs"
+  ;;
+  sh4|sh4eb)
+    TARGET_ARCH=sh4
+    bflt="yes"
+    target_nptl="yes"
+    target_phys_bits=32
+  ;;
+  sparc)
+    target_phys_bits=64
+  ;;
+  sparc64)
+    TARGET_BASE_ARCH=sparc
+    target_phys_bits=64
+    target_long_alignment=8
+  ;;
+  sparc32plus)
+    TARGET_ARCH=sparc64
+    TARGET_BASE_ARCH=sparc
+    TARGET_ABI_DIR=sparc
+    echo "TARGET_ABI32=y" >> $config_target_mak
+    target_phys_bits=64
+  ;;
+  s390x)
+    target_nptl="yes"
+    target_phys_bits=64
+    target_long_alignment=8
+  ;;
+  unicore32)
+    target_phys_bits=32
+  ;;
+  *)
+    echo "Unsupported target CPU"
+    exit 1
+  ;;
+esac
+echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
+echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
+echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
+echo "TARGET_LLONG_ALIGNMENT=$target_llong_alignment" >> $config_target_mak
+echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak
+target_arch_name="`echo $TARGET_ARCH | tr '[:lower:]' '[:upper:]'`"
+echo "TARGET_$target_arch_name=y" >> $config_target_mak
+echo "TARGET_ARCH2=$target_arch2" >> $config_target_mak
+# TARGET_BASE_ARCH needs to be defined after TARGET_ARCH
+if [ "$TARGET_BASE_ARCH" = "" ]; then
+  TARGET_BASE_ARCH=$TARGET_ARCH
+fi
+echo "TARGET_BASE_ARCH=$TARGET_BASE_ARCH" >> $config_target_mak
+if [ "$TARGET_ABI_DIR" = "" ]; then
+  TARGET_ABI_DIR=$TARGET_ARCH
+fi
+echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
+case "$target_arch2" in
+  i386|x86_64)
+    if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
+      target_phys_bits=64
+      echo "CONFIG_XEN=y" >> $config_target_mak
+      if test "$cpu" = "i386" -o "$cpu" = "x86_64"; then
+          echo "CONFIG_XEN_MAPCACHE=y" >> $config_target_mak
+      fi
+    fi
+esac
+case "$target_arch2" in
+  i386|x86_64|ppcemb|ppc|ppc64|s390x)
+    # Make sure the target and host cpus are compatible
+    if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
+      \( "$target_arch2" = "$cpu" -o \
+      \( "$target_arch2" = "ppcemb" -a "$cpu" = "ppc" \) -o \
+      \( "$target_arch2" = "ppc64"  -a "$cpu" = "ppc" \) -o \
+      \( "$target_arch2" = "ppc"    -a "$cpu" = "ppc64" \) -o \
+      \( "$target_arch2" = "ppcemb" -a "$cpu" = "ppc64" \) -o \
+      \( "$target_arch2" = "x86_64" -a "$cpu" = "i386"   \) -o \
+      \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
+      echo "CONFIG_KVM=y" >> $config_target_mak
+      if test $vhost_net = "yes" ; then
+        echo "CONFIG_VHOST_NET=y" >> $config_target_mak
+      fi
+    fi
+esac
+if test "$target_bigendian" = "yes" ; then
+  echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
+fi
+if test "$target_softmmu" = "yes" ; then
+  echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
+  echo "CONFIG_SOFTMMU=y" >> $config_target_mak
+  echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak
+  echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak
+  echo "subdir-$target: subdir-libhw$target_phys_bits" >> $config_host_mak
+fi
+if test "$target_user_only" = "yes" ; then
+  echo "CONFIG_USER_ONLY=y" >> $config_target_mak
+fi
+if test "$target_linux_user" = "yes" ; then
+  echo "CONFIG_LINUX_USER=y" >> $config_target_mak
+fi
+if test "$target_darwin_user" = "yes" ; then
+  echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
+fi
+if test "$smartcard_nss" = "yes" ; then
+  echo "subdir-$target: subdir-libcacard" >> $config_host_mak
+  echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
+  echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
+fi
+list=""
+if test ! -z "$gdb_xml_files" ; then
+  for x in $gdb_xml_files; do
+    list="$list $source_path/gdb-xml/$x"
+  done
+  echo "TARGET_XML_FILES=$list" >> $config_target_mak
+fi
+
+if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
+  echo "TARGET_HAS_BFLT=y" >> $config_target_mak
+fi
+if test "$target_user_only" = "yes" \
+        -a "$nptl" = "yes" -a "$target_nptl" = "yes"; then
+  echo "CONFIG_USE_NPTL=y" >> $config_target_mak
+fi
+if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
+  echo "CONFIG_USE_GUEST_BASE=y" >> $config_target_mak
+fi
+if test "$target_bsd_user" = "yes" ; then
+  echo "CONFIG_BSD_USER=y" >> $config_target_mak
+fi
+
+# generate QEMU_CFLAGS/LDFLAGS for targets
+
+cflags=""
+includes=""
+ldflags=""
+
+if test "$ARCH" = "sparc64" ; then
+  includes="-I\$(SRC_PATH)/tcg/sparc $includes"
+elif test "$ARCH" = "s390x" ; then
+  includes="-I\$(SRC_PATH)/tcg/s390 $includes"
+elif test "$ARCH" = "x86_64" ; then
+  includes="-I\$(SRC_PATH)/tcg/i386 $includes"
+else
+  includes="-I\$(SRC_PATH)/tcg/\$(ARCH) $includes"
+fi
+includes="-I\$(SRC_PATH)/tcg $includes"
+includes="-I\$(SRC_PATH)/fpu $includes"
+
+if test "$target_user_only" = "yes" ; then
+    libdis_config_mak=libdis-user/config.mak
+else
+    libdis_config_mak=libdis/config.mak
+fi
+
+for i in $ARCH $TARGET_BASE_ARCH ; do
+  case "$i" in
+  alpha)
+    echo "CONFIG_ALPHA_DIS=y"  >> $config_target_mak
+    echo "CONFIG_ALPHA_DIS=y"  >> $libdis_config_mak
+  ;;
+  arm)
+    echo "CONFIG_ARM_DIS=y"  >> $config_target_mak
+    echo "CONFIG_ARM_DIS=y"  >> $libdis_config_mak
+  ;;
+  cris)
+    echo "CONFIG_CRIS_DIS=y"  >> $config_target_mak
+    echo "CONFIG_CRIS_DIS=y"  >> $libdis_config_mak
+  ;;
+  hppa)
+    echo "CONFIG_HPPA_DIS=y"  >> $config_target_mak
+    echo "CONFIG_HPPA_DIS=y"  >> $libdis_config_mak
+  ;;
+  i386|x86_64)
+    echo "CONFIG_I386_DIS=y"  >> $config_target_mak
+    echo "CONFIG_I386_DIS=y"  >> $libdis_config_mak
+  ;;
+  ia64*)
+    echo "CONFIG_IA64_DIS=y"  >> $config_target_mak
+    echo "CONFIG_IA64_DIS=y"  >> $libdis_config_mak
+  ;;
+  m68k)
+    echo "CONFIG_M68K_DIS=y"  >> $config_target_mak
+    echo "CONFIG_M68K_DIS=y"  >> $libdis_config_mak
+  ;;
+  microblaze*)
+    echo "CONFIG_MICROBLAZE_DIS=y"  >> $config_target_mak
+    echo "CONFIG_MICROBLAZE_DIS=y"  >> $libdis_config_mak
+  ;;
+  mips*)
+    echo "CONFIG_MIPS_DIS=y"  >> $config_target_mak
+    echo "CONFIG_MIPS_DIS=y"  >> $libdis_config_mak
+  ;;
+  ppc*)
+    echo "CONFIG_PPC_DIS=y"  >> $config_target_mak
+    echo "CONFIG_PPC_DIS=y"  >> $libdis_config_mak
+  ;;
+  s390*)
+    echo "CONFIG_S390_DIS=y"  >> $config_target_mak
+    echo "CONFIG_S390_DIS=y"  >> $libdis_config_mak
+  ;;
+  sh4)
+    echo "CONFIG_SH4_DIS=y"  >> $config_target_mak
+    echo "CONFIG_SH4_DIS=y"  >> $libdis_config_mak
+  ;;
+  sparc*)
+    echo "CONFIG_SPARC_DIS=y"  >> $config_target_mak
+    echo "CONFIG_SPARC_DIS=y"  >> $libdis_config_mak
+  ;;
+  esac
+done
+
+case "$ARCH" in
+alpha)
+  # Ensure there's only a single GP
+  cflags="-msmall-data $cflags"
+;;
+esac
+
+if test "$target_softmmu" = "yes" ; then
+  case "$TARGET_BASE_ARCH" in
+  arm)
+    cflags="-DHAS_AUDIO $cflags"
+  ;;
+  lm32)
+    cflags="-DHAS_AUDIO $cflags"
+  ;;
+  i386|mips|ppc)
+    cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
+  ;;
+  esac
+fi
+
+if test "$target_user_only" = "yes" -a "$static" = "no" -a \
+	"$user_pie" = "yes" ; then
+  cflags="-fpie $cflags"
+  ldflags="-pie $ldflags"
+fi
+
+if test "$target_softmmu" = "yes" -a \( \
+        "$TARGET_ARCH" = "microblaze" -o \
+        "$TARGET_ARCH" = "cris" \) ; then
+  echo "CONFIG_NEED_MMU=y" >> $config_target_mak
+fi
+
+if test "$gprof" = "yes" ; then
+  echo "TARGET_GPROF=yes" >> $config_target_mak
+  if test "$target_linux_user" = "yes" ; then
+    cflags="-p $cflags"
+    ldflags="-p $ldflags"
+  fi
+  if test "$target_softmmu" = "yes" ; then
+    ldflags="-p $ldflags"
+    echo "GPROF_CFLAGS=-p" >> $config_target_mak
+  fi
+fi
+
+linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/\$(ARCH).ld"
+if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
+  case "$ARCH" in
+  sparc)
+    # -static is used to avoid g1/g3 usage by the dynamic linker
+    ldflags="$linker_script -static $ldflags"
+    ;;
+  alpha | s390x)
+    # The default placement of the application is fine.
+    ;;
+  *)
+    ldflags="$linker_script $ldflags"
+    ;;
+  esac
+fi
+
+# use included Linux headers
+if test "$linux" = "yes" ; then
+  includes="-I\$(SRC_PATH)/linux-headers $includes"
+  mkdir -p linux-headers
+  case "$cpu" in
+  i386|x86_64)
+    symlink $source_path/linux-headers/asm-x86 linux-headers/asm
+    ;;
+  ppcemb|ppc|ppc64)
+    symlink $source_path/linux-headers/asm-powerpc linux-headers/asm
+    ;;
+  s390x)
+    symlink $source_path/linux-headers/asm-s390 linux-headers/asm
+    ;;
+  esac
+fi
+
+echo "LDFLAGS+=$ldflags" >> $config_target_mak
+echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak
+echo "QEMU_INCLUDES+=$includes" >> $config_target_mak
+
+done # for target in $targets
+
+# build tree in object directory in case the source is not in the current directory
+DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
+DIRS="$DIRS pc-bios/spapr-rtas"
+DIRS="$DIRS roms/seabios roms/vgabios"
+DIRS="$DIRS fsdev ui"
+DIRS="$DIRS qapi"
+DIRS="$DIRS qga"
+FILES="Makefile tests/Makefile qdict-test-data.txt"
+FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
+FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
+FILES="$FILES pc-bios/spapr-rtas/Makefile"
+FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
+for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
+    FILES="$FILES pc-bios/`basename $bios_file`"
+done
+mkdir -p $DIRS
+for f in $FILES ; do
+    if [ -e "$source_path/$f" ] && ! [ -e "$f" ]; then
+        symlink "$source_path/$f" "$f"
+    fi
+done
+
+# temporary config to build submodules
+for rom in seabios vgabios ; do
+    config_mak=roms/$rom/config.mak
+    echo "# Automatically generated by configure - do not modify" > $config_mak
+    echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
+    echo "CC=$cc" >> $config_mak
+    echo "BCC=bcc" >> $config_mak
+    echo "CPP=${cross_prefix}cpp" >> $config_mak
+    echo "OBJCOPY=objcopy" >> $config_mak
+    echo "IASL=iasl" >> $config_mak
+    echo "LD=$ld" >> $config_mak
+done
+
+for hwlib in 32 64; do
+  d=libhw$hwlib
+  mkdir -p $d
+  mkdir -p $d/ide
+  symlink $source_path/Makefile.hw $d/Makefile
+  mkdir -p $d/9pfs
+  echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
+done
+
+if [ "$source_path" != `pwd` ]; then
+    # out of tree build
+    mkdir -p libcacard
+    rm -f libcacard/Makefile
+    symlink "$source_path/libcacard/Makefile" libcacard/Makefile
+fi
+
+d=libuser
+mkdir -p $d
+symlink $source_path/Makefile.user $d/Makefile
+if test "$static" = "no" -a "$user_pie" = "yes" ; then
+  echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
+fi
+
+if test "$docs" = "yes" ; then
+  mkdir -p QMP
+fi
diff --git a/qemu-0.15.x/console.c b/qemu-0.15.x/console.c
new file mode 100644
index 0000000..242086c
--- /dev/null
+++ b/qemu-0.15.x/console.c
@@ -0,0 +1,1718 @@
+/*
+ * QEMU graphical console
+ *
+ * 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 "qemu-common.h"
+#include "console.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_CONSOLE
+#define DEFAULT_BACKSCROLL 512
+#define MAX_CONSOLES 12
+
+#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
+
+typedef struct TextAttributes {
+    uint8_t fgcol:4;
+    uint8_t bgcol:4;
+    uint8_t bold:1;
+    uint8_t uline:1;
+    uint8_t blink:1;
+    uint8_t invers:1;
+    uint8_t unvisible:1;
+} TextAttributes;
+
+typedef struct TextCell {
+    uint8_t ch;
+    TextAttributes t_attrib;
+} TextCell;
+
+#define MAX_ESC_PARAMS 3
+
+enum TTYState {
+    TTY_STATE_NORM,
+    TTY_STATE_ESC,
+    TTY_STATE_CSI,
+};
+
+typedef struct QEMUFIFO {
+    uint8_t *buf;
+    int buf_size;
+    int count, wptr, rptr;
+} QEMUFIFO;
+
+static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
+{
+    int l, len;
+
+    l = f->buf_size - f->count;
+    if (len1 > l)
+        len1 = l;
+    len = len1;
+    while (len > 0) {
+        l = f->buf_size - f->wptr;
+        if (l > len)
+            l = len;
+        memcpy(f->buf + f->wptr, buf, l);
+        f->wptr += l;
+        if (f->wptr >= f->buf_size)
+            f->wptr = 0;
+        buf += l;
+        len -= l;
+    }
+    f->count += len1;
+    return len1;
+}
+
+static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
+{
+    int l, len;
+
+    if (len1 > f->count)
+        len1 = f->count;
+    len = len1;
+    while (len > 0) {
+        l = f->buf_size - f->rptr;
+        if (l > len)
+            l = len;
+        memcpy(buf, f->buf + f->rptr, l);
+        f->rptr += l;
+        if (f->rptr >= f->buf_size)
+            f->rptr = 0;
+        buf += l;
+        len -= l;
+    }
+    f->count -= len1;
+    return len1;
+}
+
+typedef enum {
+    GRAPHIC_CONSOLE,
+    TEXT_CONSOLE,
+    TEXT_CONSOLE_FIXED_SIZE
+} console_type_t;
+
+/* ??? This is mis-named.
+   It is used for both text and graphical consoles.  */
+struct TextConsole {
+    console_type_t console_type;
+    DisplayState *ds;
+    /* Graphic console state.  */
+    vga_hw_update_ptr hw_update;
+    vga_hw_invalidate_ptr hw_invalidate;
+    vga_hw_screen_dump_ptr hw_screen_dump;
+    vga_hw_text_update_ptr hw_text_update;
+    void *hw;
+
+    int g_width, g_height;
+    int width;
+    int height;
+    int total_height;
+    int backscroll_height;
+    int x, y;
+    int x_saved, y_saved;
+    int y_displayed;
+    int y_base;
+    TextAttributes t_attrib_default; /* default text attributes */
+    TextAttributes t_attrib; /* currently active text attributes */
+    TextCell *cells;
+    int text_x[2], text_y[2], cursor_invalidate;
+    int echo;
+
+    int update_x0;
+    int update_y0;
+    int update_x1;
+    int update_y1;
+
+    enum TTYState state;
+    int esc_params[MAX_ESC_PARAMS];
+    int nb_esc_params;
+
+    CharDriverState *chr;
+    /* fifo for key pressed */
+    QEMUFIFO out_fifo;
+    uint8_t out_fifo_buf[16];
+    QEMUTimer *kbd_timer;
+};
+
+static DisplayState *display_state;
+static TextConsole *active_console;
+static TextConsole *consoles[MAX_CONSOLES];
+static int nb_consoles = 0;
+
+void vga_hw_update(void)
+{
+    if (active_console && active_console->hw_update)
+        active_console->hw_update(active_console->hw);
+}
+
+void vga_hw_invalidate(void)
+{
+    if (active_console && active_console->hw_invalidate)
+        active_console->hw_invalidate(active_console->hw);
+}
+
+void vga_hw_screen_dump(const char *filename)
+{
+    TextConsole *previous_active_console;
+
+    previous_active_console = active_console;
+    active_console = consoles[0];
+    /* There is currently no way of specifying which screen we want to dump,
+       so always dump the first one.  */
+    if (consoles[0] && consoles[0]->hw_screen_dump)
+        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
+    active_console = previous_active_console;
+}
+
+void vga_hw_text_update(console_ch_t *chardata)
+{
+    if (active_console && active_console->hw_text_update)
+        active_console->hw_text_update(active_console->hw, chardata);
+}
+
+/* convert a RGBA color to a color index usable in graphic primitives */
+static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
+{
+    unsigned int r, g, b, color;
+
+    switch(ds_get_bits_per_pixel(ds)) {
+#if 0
+    case 8:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = (rgb_to_index[r] * 6 * 6) +
+            (rgb_to_index[g] * 6) +
+            (rgb_to_index[b]);
+        break;
+#endif
+    case 15:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+        break;
+    case 16:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+        break;
+    case 32:
+    default:
+        color = rgba;
+        break;
+    }
+    return color;
+}
+
+static void vga_fill_rect (DisplayState *ds,
+                           int posx, int posy, int width, int height, uint32_t color)
+{
+    uint8_t *d, *d1;
+    int x, y, bpp;
+
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d1 = ds_get_data(ds) +
+        ds_get_linesize(ds) * posy + bpp * posx;
+    for (y = 0; y < height; y++) {
+        d = d1;
+        switch(bpp) {
+        case 1:
+            for (x = 0; x < width; x++) {
+                *((uint8_t *)d) = color;
+                d++;
+            }
+            break;
+        case 2:
+            for (x = 0; x < width; x++) {
+                *((uint16_t *)d) = color;
+                d += 2;
+            }
+            break;
+        case 4:
+            for (x = 0; x < width; x++) {
+                *((uint32_t *)d) = color;
+                d += 4;
+            }
+            break;
+        }
+        d1 += ds_get_linesize(ds);
+    }
+}
+
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
+{
+    const uint8_t *s;
+    uint8_t *d;
+    int wb, y, bpp;
+
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    wb = w * bpp;
+    if (yd <= ys) {
+        s = ds_get_data(ds) +
+            ds_get_linesize(ds) * ys + bpp * xs;
+        d = ds_get_data(ds) +
+            ds_get_linesize(ds) * yd + bpp * xd;
+        for (y = 0; y < h; y++) {
+            memmove(d, s, wb);
+            d += ds_get_linesize(ds);
+            s += ds_get_linesize(ds);
+        }
+    } else {
+        s = ds_get_data(ds) +
+            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
+        d = ds_get_data(ds) +
+            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
+       for (y = 0; y < h; y++) {
+            memmove(d, s, wb);
+            d -= ds_get_linesize(ds);
+            s -= ds_get_linesize(ds);
+        }
+    }
+}
+
+/***********************************************************/
+/* basic char display */
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+#include "vgafont.h"
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) x
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+static uint32_t color_table[2][8];
+
+enum color_names {
+    COLOR_BLACK   = 0,
+    COLOR_RED     = 1,
+    COLOR_GREEN   = 2,
+    COLOR_YELLOW  = 3,
+    COLOR_BLUE    = 4,
+    COLOR_MAGENTA = 5,
+    COLOR_CYAN    = 6,
+    COLOR_WHITE   = 7
+};
+
+static const uint32_t color_table_rgb[2][8] = {
+    {   /* dark */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
+        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
+        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
+        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
+        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
+    },
+    {   /* bright */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
+        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
+        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
+        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
+        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
+    }
+};
+
+static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
+{
+    switch(ds_get_bits_per_pixel(ds)) {
+    case 8:
+        col |= col << 8;
+        col |= col << 16;
+        break;
+    case 15:
+    case 16:
+        col |= col << 16;
+        break;
+    default:
+        break;
+    }
+
+    return col;
+}
+#ifdef DEBUG_CONSOLE
+static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
+{
+    if (t_attrib->bold) {
+        printf("b");
+    } else {
+        printf(" ");
+    }
+    if (t_attrib->uline) {
+        printf("u");
+    } else {
+        printf(" ");
+    }
+    if (t_attrib->blink) {
+        printf("l");
+    } else {
+        printf(" ");
+    }
+    if (t_attrib->invers) {
+        printf("i");
+    } else {
+        printf(" ");
+    }
+    if (t_attrib->unvisible) {
+        printf("n");
+    } else {
+        printf(" ");
+    }
+
+    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
+}
+#endif
+
+static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
+                          TextAttributes *t_attrib)
+{
+    uint8_t *d;
+    const uint8_t *font_ptr;
+    unsigned int font_data, linesize, xorcol, bpp;
+    int i;
+    unsigned int fgcol, bgcol;
+
+#ifdef DEBUG_CONSOLE
+    printf("x: %2i y: %2i", x, y);
+    console_print_text_attributes(t_attrib, ch);
+#endif
+
+    if (t_attrib->invers) {
+        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
+        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
+    } else {
+        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
+        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
+    }
+
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d = ds_get_data(ds) +
+        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
+    linesize = ds_get_linesize(ds);
+    font_ptr = vgafont16 + FONT_HEIGHT * ch;
+    xorcol = bgcol ^ fgcol;
+    switch(ds_get_bits_per_pixel(ds)) {
+    case 8:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            if (t_attrib->uline
+                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+                font_data = 0xFFFF;
+            }
+            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    case 16:
+    case 15:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            if (t_attrib->uline
+                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+                font_data = 0xFFFF;
+            }
+            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    case 32:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+                font_data = 0xFFFF;
+            }
+            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    }
+}
+
+static void text_console_resize(TextConsole *s)
+{
+    TextCell *cells, *c, *c1;
+    int w1, x, y, last_width;
+
+    last_width = s->width;
+    s->width = s->g_width / FONT_WIDTH;
+    s->height = s->g_height / FONT_HEIGHT;
+
+    w1 = last_width;
+    if (s->width < w1)
+        w1 = s->width;
+
+    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
+    for(y = 0; y < s->total_height; y++) {
+        c = &cells[y * s->width];
+        if (w1 > 0) {
+            c1 = &s->cells[y * last_width];
+            for(x = 0; x < w1; x++) {
+                *c++ = *c1++;
+            }
+        }
+        for(x = w1; x < s->width; x++) {
+            c->ch = ' ';
+            c->t_attrib = s->t_attrib_default;
+            c++;
+        }
+    }
+    qemu_free(s->cells);
+    s->cells = cells;
+}
+
+static inline void text_update_xy(TextConsole *s, int x, int y)
+{
+    s->text_x[0] = MIN(s->text_x[0], x);
+    s->text_x[1] = MAX(s->text_x[1], x);
+    s->text_y[0] = MIN(s->text_y[0], y);
+    s->text_y[1] = MAX(s->text_y[1], y);
+}
+
+static void invalidate_xy(TextConsole *s, int x, int y)
+{
+    if (s->update_x0 > x * FONT_WIDTH)
+        s->update_x0 = x * FONT_WIDTH;
+    if (s->update_y0 > y * FONT_HEIGHT)
+        s->update_y0 = y * FONT_HEIGHT;
+    if (s->update_x1 < (x + 1) * FONT_WIDTH)
+        s->update_x1 = (x + 1) * FONT_WIDTH;
+    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
+        s->update_y1 = (y + 1) * FONT_HEIGHT;
+}
+
+static void update_xy(TextConsole *s, int x, int y)
+{
+    TextCell *c;
+    int y1, y2;
+
+    if (s == active_console) {
+        if (!ds_get_bits_per_pixel(s->ds)) {
+            text_update_xy(s, x, y);
+            return;
+        }
+
+        y1 = (s->y_base + y) % s->total_height;
+        y2 = y1 - s->y_displayed;
+        if (y2 < 0)
+            y2 += s->total_height;
+        if (y2 < s->height) {
+            c = &s->cells[y1 * s->width + x];
+            vga_putcharxy(s->ds, x, y2, c->ch,
+                          &(c->t_attrib));
+            invalidate_xy(s, x, y2);
+        }
+    }
+}
+
+static void console_show_cursor(TextConsole *s, int show)
+{
+    TextCell *c;
+    int y, y1;
+
+    if (s == active_console) {
+        int x = s->x;
+
+        if (!ds_get_bits_per_pixel(s->ds)) {
+            s->cursor_invalidate = 1;
+            return;
+        }
+
+        if (x >= s->width) {
+            x = s->width - 1;
+        }
+        y1 = (s->y_base + s->y) % s->total_height;
+        y = y1 - s->y_displayed;
+        if (y < 0)
+            y += s->total_height;
+        if (y < s->height) {
+            c = &s->cells[y1 * s->width + x];
+            if (show) {
+                TextAttributes t_attrib = s->t_attrib_default;
+                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
+            } else {
+                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
+            }
+            invalidate_xy(s, x, y);
+        }
+    }
+}
+
+static void console_refresh(TextConsole *s)
+{
+    TextCell *c;
+    int x, y, y1;
+
+    if (s != active_console)
+        return;
+    if (!ds_get_bits_per_pixel(s->ds)) {
+        s->text_x[0] = 0;
+        s->text_y[0] = 0;
+        s->text_x[1] = s->width - 1;
+        s->text_y[1] = s->height - 1;
+        s->cursor_invalidate = 1;
+        return;
+    }
+
+    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
+                  color_table[0][COLOR_BLACK]);
+    y1 = s->y_displayed;
+    for(y = 0; y < s->height; y++) {
+        c = s->cells + y1 * s->width;
+        for(x = 0; x < s->width; x++) {
+            vga_putcharxy(s->ds, x, y, c->ch,
+                          &(c->t_attrib));
+            c++;
+        }
+        if (++y1 == s->total_height)
+            y1 = 0;
+    }
+    console_show_cursor(s, 1);
+    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
+}
+
+static void console_scroll(int ydelta)
+{
+    TextConsole *s;
+    int i, y1;
+
+    s = active_console;
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
+        return;
+
+    if (ydelta > 0) {
+        for(i = 0; i < ydelta; i++) {
+            if (s->y_displayed == s->y_base)
+                break;
+            if (++s->y_displayed == s->total_height)
+                s->y_displayed = 0;
+        }
+    } else {
+        ydelta = -ydelta;
+        i = s->backscroll_height;
+        if (i > s->total_height - s->height)
+            i = s->total_height - s->height;
+        y1 = s->y_base - i;
+        if (y1 < 0)
+            y1 += s->total_height;
+        for(i = 0; i < ydelta; i++) {
+            if (s->y_displayed == y1)
+                break;
+            if (--s->y_displayed < 0)
+                s->y_displayed = s->total_height - 1;
+        }
+    }
+    console_refresh(s);
+}
+
+static void console_put_lf(TextConsole *s)
+{
+    TextCell *c;
+    int x, y1;
+
+    s->y++;
+    if (s->y >= s->height) {
+        s->y = s->height - 1;
+
+        if (s->y_displayed == s->y_base) {
+            if (++s->y_displayed == s->total_height)
+                s->y_displayed = 0;
+        }
+        if (++s->y_base == s->total_height)
+            s->y_base = 0;
+        if (s->backscroll_height < s->total_height)
+            s->backscroll_height++;
+        y1 = (s->y_base + s->height - 1) % s->total_height;
+        c = &s->cells[y1 * s->width];
+        for(x = 0; x < s->width; x++) {
+            c->ch = ' ';
+            c->t_attrib = s->t_attrib_default;
+            c++;
+        }
+        if (s == active_console && s->y_displayed == s->y_base) {
+            if (!ds_get_bits_per_pixel(s->ds)) {
+                s->text_x[0] = 0;
+                s->text_y[0] = 0;
+                s->text_x[1] = s->width - 1;
+                s->text_y[1] = s->height - 1;
+                return;
+            }
+
+            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
+                       s->width * FONT_WIDTH,
+                       (s->height - 1) * FONT_HEIGHT);
+            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
+                          s->width * FONT_WIDTH, FONT_HEIGHT,
+                          color_table[0][s->t_attrib_default.bgcol]);
+            s->update_x0 = 0;
+            s->update_y0 = 0;
+            s->update_x1 = s->width * FONT_WIDTH;
+            s->update_y1 = s->height * FONT_HEIGHT;
+        }
+    }
+}
+
+/* Set console attributes depending on the current escape codes.
+ * NOTE: I know this code is not very efficient (checking every color for it
+ * self) but it is more readable and better maintainable.
+ */
+static void console_handle_escape(TextConsole *s)
+{
+    int i;
+
+    for (i=0; i<s->nb_esc_params; i++) {
+        switch (s->esc_params[i]) {
+            case 0: /* reset all console attributes to default */
+                s->t_attrib = s->t_attrib_default;
+                break;
+            case 1:
+                s->t_attrib.bold = 1;
+                break;
+            case 4:
+                s->t_attrib.uline = 1;
+                break;
+            case 5:
+                s->t_attrib.blink = 1;
+                break;
+            case 7:
+                s->t_attrib.invers = 1;
+                break;
+            case 8:
+                s->t_attrib.unvisible = 1;
+                break;
+            case 22:
+                s->t_attrib.bold = 0;
+                break;
+            case 24:
+                s->t_attrib.uline = 0;
+                break;
+            case 25:
+                s->t_attrib.blink = 0;
+                break;
+            case 27:
+                s->t_attrib.invers = 0;
+                break;
+            case 28:
+                s->t_attrib.unvisible = 0;
+                break;
+            /* set foreground color */
+            case 30:
+                s->t_attrib.fgcol=COLOR_BLACK;
+                break;
+            case 31:
+                s->t_attrib.fgcol=COLOR_RED;
+                break;
+            case 32:
+                s->t_attrib.fgcol=COLOR_GREEN;
+                break;
+            case 33:
+                s->t_attrib.fgcol=COLOR_YELLOW;
+                break;
+            case 34:
+                s->t_attrib.fgcol=COLOR_BLUE;
+                break;
+            case 35:
+                s->t_attrib.fgcol=COLOR_MAGENTA;
+                break;
+            case 36:
+                s->t_attrib.fgcol=COLOR_CYAN;
+                break;
+            case 37:
+                s->t_attrib.fgcol=COLOR_WHITE;
+                break;
+            /* set background color */
+            case 40:
+                s->t_attrib.bgcol=COLOR_BLACK;
+                break;
+            case 41:
+                s->t_attrib.bgcol=COLOR_RED;
+                break;
+            case 42:
+                s->t_attrib.bgcol=COLOR_GREEN;
+                break;
+            case 43:
+                s->t_attrib.bgcol=COLOR_YELLOW;
+                break;
+            case 44:
+                s->t_attrib.bgcol=COLOR_BLUE;
+                break;
+            case 45:
+                s->t_attrib.bgcol=COLOR_MAGENTA;
+                break;
+            case 46:
+                s->t_attrib.bgcol=COLOR_CYAN;
+                break;
+            case 47:
+                s->t_attrib.bgcol=COLOR_WHITE;
+                break;
+        }
+    }
+}
+
+static void console_clear_xy(TextConsole *s, int x, int y)
+{
+    int y1 = (s->y_base + y) % s->total_height;
+    TextCell *c = &s->cells[y1 * s->width + x];
+    c->ch = ' ';
+    c->t_attrib = s->t_attrib_default;
+    update_xy(s, x, y);
+}
+
+static void console_putchar(TextConsole *s, int ch)
+{
+    TextCell *c;
+    int y1, i;
+    int x, y;
+
+    switch(s->state) {
+    case TTY_STATE_NORM:
+        switch(ch) {
+        case '\r':  /* carriage return */
+            s->x = 0;
+            break;
+        case '\n':  /* newline */
+            console_put_lf(s);
+            break;
+        case '\b':  /* backspace */
+            if (s->x > 0)
+                s->x--;
+            break;
+        case '\t':  /* tabspace */
+            if (s->x + (8 - (s->x % 8)) > s->width) {
+                s->x = 0;
+                console_put_lf(s);
+            } else {
+                s->x = s->x + (8 - (s->x % 8));
+            }
+            break;
+        case '\a':  /* alert aka. bell */
+            /* TODO: has to be implemented */
+            break;
+        case 14:
+            /* SI (shift in), character set 0 (ignored) */
+            break;
+        case 15:
+            /* SO (shift out), character set 1 (ignored) */
+            break;
+        case 27:    /* esc (introducing an escape sequence) */
+            s->state = TTY_STATE_ESC;
+            break;
+        default:
+            if (s->x >= s->width) {
+                /* line wrap */
+                s->x = 0;
+                console_put_lf(s);
+            }
+            y1 = (s->y_base + s->y) % s->total_height;
+            c = &s->cells[y1 * s->width + s->x];
+            c->ch = ch;
+            c->t_attrib = s->t_attrib;
+            update_xy(s, s->x, s->y);
+            s->x++;
+            break;
+        }
+        break;
+    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
+        if (ch == '[') {
+            for(i=0;i<MAX_ESC_PARAMS;i++)
+                s->esc_params[i] = 0;
+            s->nb_esc_params = 0;
+            s->state = TTY_STATE_CSI;
+        } else {
+            s->state = TTY_STATE_NORM;
+        }
+        break;
+    case TTY_STATE_CSI: /* handle escape sequence parameters */
+        if (ch >= '0' && ch <= '9') {
+            if (s->nb_esc_params < MAX_ESC_PARAMS) {
+                s->esc_params[s->nb_esc_params] =
+                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
+            }
+        } else {
+            s->nb_esc_params++;
+            if (ch == ';')
+                break;
+#ifdef DEBUG_CONSOLE
+            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
+                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
+#endif
+            s->state = TTY_STATE_NORM;
+            switch(ch) {
+            case 'A':
+                /* move cursor up */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y -= s->esc_params[0];
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'B':
+                /* move cursor down */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y += s->esc_params[0];
+                if (s->y >= s->height) {
+                    s->y = s->height - 1;
+                }
+                break;
+            case 'C':
+                /* move cursor right */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x += s->esc_params[0];
+                if (s->x >= s->width) {
+                    s->x = s->width - 1;
+                }
+                break;
+            case 'D':
+                /* move cursor left */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x -= s->esc_params[0];
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                break;
+            case 'G':
+                /* move cursor to column */
+                s->x = s->esc_params[0] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                break;
+            case 'f':
+            case 'H':
+                /* move cursor to row, column */
+                s->x = s->esc_params[1] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                s->y = s->esc_params[0] - 1;
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'J':
+                switch (s->esc_params[0]) {
+                case 0:
+                    /* clear to end of screen */
+                    for (y = s->y; y < s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x < s->x) {
+                                continue;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 1:
+                    /* clear from beginning of screen */
+                    for (y = 0; y <= s->y; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x > s->x) {
+                                break;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 2:
+                    /* clear entire screen */
+                    for (y = 0; y <= s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                break;
+                }
+            case 'K':
+                switch (s->esc_params[0]) {
+                case 0:
+                /* clear to eol */
+                for(x = s->x; x < s->width; x++) {
+                        console_clear_xy(s, x, s->y);
+                }
+                break;
+                case 1:
+                    /* clear from beginning of line */
+                    for (x = 0; x <= s->x; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
+                    break;
+                case 2:
+                    /* clear entire line */
+                    for(x = 0; x < s->width; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
+                break;
+            }
+                break;
+            case 'm':
+            console_handle_escape(s);
+            break;
+            case 'n':
+                /* report cursor position */
+                /* TODO: send ESC[row;colR */
+                break;
+            case 's':
+                /* save cursor position */
+                s->x_saved = s->x;
+                s->y_saved = s->y;
+                break;
+            case 'u':
+                /* restore cursor position */
+                s->x = s->x_saved;
+                s->y = s->y_saved;
+                break;
+            default:
+#ifdef DEBUG_CONSOLE
+                fprintf(stderr, "unhandled escape character '%c'\n", ch);
+#endif
+                break;
+            }
+            break;
+        }
+    }
+}
+
+void console_select(unsigned int index)
+{
+    TextConsole *s;
+
+    if (index >= MAX_CONSOLES)
+        return;
+    if (active_console) {
+        active_console->g_width = ds_get_width(active_console->ds);
+        active_console->g_height = ds_get_height(active_console->ds);
+    }
+    s = consoles[index];
+    if (s) {
+        DisplayState *ds = s->ds;
+        active_console = s;
+        if (ds_get_bits_per_pixel(s->ds)) {
+            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
+        } else {
+            s->ds->surface->width = s->width;
+            s->ds->surface->height = s->height;
+        }
+        dpy_resize(s->ds);
+        vga_hw_invalidate();
+    }
+}
+
+static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    TextConsole *s = chr->opaque;
+    int i;
+
+    s->update_x0 = s->width * FONT_WIDTH;
+    s->update_y0 = s->height * FONT_HEIGHT;
+    s->update_x1 = 0;
+    s->update_y1 = 0;
+    console_show_cursor(s, 0);
+    for(i = 0; i < len; i++) {
+        console_putchar(s, buf[i]);
+    }
+    console_show_cursor(s, 1);
+    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
+        dpy_update(s->ds, s->update_x0, s->update_y0,
+                   s->update_x1 - s->update_x0,
+                   s->update_y1 - s->update_y0);
+    }
+    return len;
+}
+
+static void console_send_event(CharDriverState *chr, int event)
+{
+    TextConsole *s = chr->opaque;
+    int i;
+
+    if (event == CHR_EVENT_FOCUS) {
+        for(i = 0; i < nb_consoles; i++) {
+            if (consoles[i] == s) {
+                console_select(i);
+                break;
+            }
+        }
+    }
+}
+
+static void kbd_send_chars(void *opaque)
+{
+    TextConsole *s = opaque;
+    int len;
+    uint8_t buf[16];
+
+    len = qemu_chr_can_read(s->chr);
+    if (len > s->out_fifo.count)
+        len = s->out_fifo.count;
+    if (len > 0) {
+        if (len > sizeof(buf))
+            len = sizeof(buf);
+        qemu_fifo_read(&s->out_fifo, buf, len);
+        qemu_chr_read(s->chr, buf, len);
+    }
+    /* characters are pending: we send them a bit later (XXX:
+       horrible, should change char device API) */
+    if (s->out_fifo.count > 0) {
+        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
+    }
+}
+
+/* called when an ascii key is pressed */
+void kbd_put_keysym(int keysym)
+{
+    TextConsole *s;
+    uint8_t buf[16], *q;
+    int c;
+
+    s = active_console;
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
+        return;
+
+    switch(keysym) {
+    case QEMU_KEY_CTRL_UP:
+        console_scroll(-1);
+        break;
+    case QEMU_KEY_CTRL_DOWN:
+        console_scroll(1);
+        break;
+    case QEMU_KEY_CTRL_PAGEUP:
+        console_scroll(-10);
+        break;
+    case QEMU_KEY_CTRL_PAGEDOWN:
+        console_scroll(10);
+        break;
+    default:
+        /* convert the QEMU keysym to VT100 key string */
+        q = buf;
+        if (keysym >= 0xe100 && keysym <= 0xe11f) {
+            *q++ = '\033';
+            *q++ = '[';
+            c = keysym - 0xe100;
+            if (c >= 10)
+                *q++ = '0' + (c / 10);
+            *q++ = '0' + (c % 10);
+            *q++ = '~';
+        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
+            *q++ = '\033';
+            *q++ = '[';
+            *q++ = keysym & 0xff;
+        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
+            console_puts(s->chr, (const uint8_t *) "\r", 1);
+            *q++ = '\n';
+        } else {
+            *q++ = keysym;
+        }
+        if (s->echo) {
+            console_puts(s->chr, buf, q - buf);
+        }
+        if (s->chr->chr_read) {
+            qemu_fifo_write(&s->out_fifo, buf, q - buf);
+            kbd_send_chars(s);
+        }
+        break;
+    }
+}
+
+static void text_console_invalidate(void *opaque)
+{
+    TextConsole *s = (TextConsole *) opaque;
+    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
+        s->g_width = ds_get_width(s->ds);
+        s->g_height = ds_get_height(s->ds);
+        text_console_resize(s);
+    }
+    console_refresh(s);
+}
+
+static void text_console_update(void *opaque, console_ch_t *chardata)
+{
+    TextConsole *s = (TextConsole *) opaque;
+    int i, j, src;
+
+    if (s->text_x[0] <= s->text_x[1]) {
+        src = (s->y_base + s->text_y[0]) * s->width;
+        chardata += s->text_y[0] * s->width;
+        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
+            for (j = 0; j < s->width; j ++, src ++)
+                console_write_ch(chardata ++, s->cells[src].ch |
+                                (s->cells[src].t_attrib.fgcol << 12) |
+                                (s->cells[src].t_attrib.bgcol << 8) |
+                                (s->cells[src].t_attrib.bold << 21));
+        dpy_update(s->ds, s->text_x[0], s->text_y[0],
+                   s->text_x[1] - s->text_x[0], i - s->text_y[0]);
+        s->text_x[0] = s->width;
+        s->text_y[0] = s->height;
+        s->text_x[1] = 0;
+        s->text_y[1] = 0;
+    }
+    if (s->cursor_invalidate) {
+        dpy_cursor(s->ds, s->x, s->y);
+        s->cursor_invalidate = 0;
+    }
+}
+
+static TextConsole *get_graphic_console(DisplayState *ds)
+{
+    int i;
+    TextConsole *s;
+    for (i = 0; i < nb_consoles; i++) {
+        s = consoles[i];
+        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
+            return s;
+    }
+    return NULL;
+}
+
+static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
+{
+    TextConsole *s;
+    int i;
+
+    if (nb_consoles >= MAX_CONSOLES)
+        return NULL;
+    s = qemu_mallocz(sizeof(TextConsole));
+    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
+        (console_type == GRAPHIC_CONSOLE))) {
+        active_console = s;
+    }
+    s->ds = ds;
+    s->console_type = console_type;
+    if (console_type != GRAPHIC_CONSOLE) {
+        consoles[nb_consoles++] = s;
+    } else {
+        /* HACK: Put graphical consoles before text consoles.  */
+        for (i = nb_consoles; i > 0; i--) {
+            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
+                break;
+            consoles[i] = consoles[i - 1];
+        }
+        consoles[i] = s;
+        nb_consoles++;
+    }
+    return s;
+}
+
+static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    int linesize = width * 4;
+    qemu_alloc_display(surface, width, height, linesize,
+                       qemu_default_pixelformat(32), 0);
+    return surface;
+}
+
+static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
+                                          int width, int height)
+{
+    int linesize = width * 4;
+    qemu_alloc_display(surface, width, height, linesize,
+                       qemu_default_pixelformat(32), 0);
+    return surface;
+}
+
+void qemu_alloc_display(DisplaySurface *surface, int width, int height,
+                        int linesize, PixelFormat pf, int newflags)
+{
+    void *data;
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = pf;
+    if (surface->flags & QEMU_ALLOCATED_FLAG) {
+        data = qemu_realloc(surface->data,
+                            surface->linesize * surface->height);
+    } else {
+        data = qemu_malloc(surface->linesize * surface->height);
+    }
+    surface->data = (uint8_t *)data;
+    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
+#endif
+}
+
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                              int linesize, uint8_t *data)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_BIG_ENDIAN_FLAG;
+#endif
+    surface->data = data;
+
+    return surface;
+}
+
+static void defaultallocator_free_displaysurface(DisplaySurface *surface)
+{
+    if (surface == NULL)
+        return;
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
+}
+
+static struct DisplayAllocator default_allocator = {
+    defaultallocator_create_displaysurface,
+    defaultallocator_resize_displaysurface,
+    defaultallocator_free_displaysurface
+};
+
+static void dumb_display_init(void)
+{
+    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+    int width = 640;
+    int height = 480;
+
+    ds->allocator = &default_allocator;
+    if (is_fixedsize_console()) {
+        width = active_console->g_width;
+        height = active_console->g_height;
+    }
+    ds->surface = qemu_create_displaysurface(ds, width, height);
+    register_displaystate(ds);
+}
+
+/***********************************************************/
+/* register display */
+
+void register_displaystate(DisplayState *ds)
+{
+    DisplayState **s;
+    s = &display_state;
+    while (*s != NULL)
+        s = &(*s)->next;
+    ds->next = NULL;
+    *s = ds;
+}
+
+DisplayState *get_displaystate(void)
+{
+    if (!display_state) {
+        dumb_display_init ();
+    }
+    return display_state;
+}
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
+{
+    if(ds->allocator ==  &default_allocator) {
+        DisplaySurface *surf;
+        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
+        defaultallocator_free_displaysurface(ds->surface);
+        ds->surface = surf;
+        ds->allocator = da;
+    }
+    return ds->allocator;
+}
+
+DisplayState *graphic_console_init(vga_hw_update_ptr update,
+                                   vga_hw_invalidate_ptr invalidate,
+                                   vga_hw_screen_dump_ptr screen_dump,
+                                   vga_hw_text_update_ptr text_update,
+                                   void *opaque)
+{
+    TextConsole *s;
+    DisplayState *ds;
+
+    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
+    ds->allocator = &default_allocator; 
+    ds->surface = qemu_create_displaysurface(ds, 640, 480);
+
+    s = new_console(ds, GRAPHIC_CONSOLE);
+    if (s == NULL) {
+        qemu_free_displaysurface(ds);
+        qemu_free(ds);
+        return NULL;
+    }
+    s->hw_update = update;
+    s->hw_invalidate = invalidate;
+    s->hw_screen_dump = screen_dump;
+    s->hw_text_update = text_update;
+    s->hw = opaque;
+
+    register_displaystate(ds);
+    return ds;
+}
+
+int is_graphic_console(void)
+{
+    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
+}
+
+int is_fixedsize_console(void)
+{
+    return active_console && active_console->console_type != TEXT_CONSOLE;
+}
+
+void console_color_init(DisplayState *ds)
+{
+    int i, j;
+    for (j = 0; j < 2; j++) {
+        for (i = 0; i < 8; i++) {
+            color_table[j][i] = col_expand(ds,
+                   vga_get_color(ds, color_table_rgb[j][i]));
+        }
+    }
+}
+
+static int n_text_consoles;
+static CharDriverState *text_consoles[128];
+
+static void text_console_set_echo(CharDriverState *chr, bool echo)
+{
+    TextConsole *s = chr->opaque;
+
+    s->echo = echo;
+}
+
+static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
+{
+    TextConsole *s;
+    static int color_inited;
+
+    s = chr->opaque;
+
+    chr->chr_write = console_puts;
+    chr->chr_send_event = console_send_event;
+
+    s->out_fifo.buf = s->out_fifo_buf;
+    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
+    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
+    s->ds = ds;
+
+    if (!color_inited) {
+        color_inited = 1;
+        console_color_init(s->ds);
+    }
+    s->y_displayed = 0;
+    s->y_base = 0;
+    s->total_height = DEFAULT_BACKSCROLL;
+    s->x = 0;
+    s->y = 0;
+    if (s->console_type == TEXT_CONSOLE) {
+        s->g_width = ds_get_width(s->ds);
+        s->g_height = ds_get_height(s->ds);
+    }
+
+    s->hw_invalidate = text_console_invalidate;
+    s->hw_text_update = text_console_update;
+    s->hw = s;
+
+    /* Set text attribute defaults */
+    s->t_attrib_default.bold = 0;
+    s->t_attrib_default.uline = 0;
+    s->t_attrib_default.blink = 0;
+    s->t_attrib_default.invers = 0;
+    s->t_attrib_default.unvisible = 0;
+    s->t_attrib_default.fgcol = COLOR_WHITE;
+    s->t_attrib_default.bgcol = COLOR_BLACK;
+    /* set current text attributes to default */
+    s->t_attrib = s->t_attrib_default;
+    text_console_resize(s);
+
+    if (chr->label) {
+        char msg[128];
+        int len;
+
+        s->t_attrib.bgcol = COLOR_BLUE;
+        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
+        console_puts(chr, (uint8_t*)msg, len);
+        s->t_attrib = s->t_attrib_default;
+    }
+
+    qemu_chr_generic_open(chr);
+    if (chr->init)
+        chr->init(chr);
+}
+
+int text_console_init(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+    TextConsole *s;
+    unsigned width;
+    unsigned height;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+
+    if (n_text_consoles == 128) {
+        fprintf(stderr, "Too many text consoles\n");
+        exit(1);
+    }
+    text_consoles[n_text_consoles] = chr;
+    n_text_consoles++;
+
+    width = qemu_opt_get_number(opts, "width", 0);
+    if (width == 0)
+        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
+
+    height = qemu_opt_get_number(opts, "height", 0);
+    if (height == 0)
+        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
+
+    if (width == 0 || height == 0) {
+        s = new_console(NULL, TEXT_CONSOLE);
+    } else {
+        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
+    }
+
+    if (!s) {
+        free(chr);
+        return -EBUSY;
+    }
+
+    s->chr = chr;
+    s->g_width = width;
+    s->g_height = height;
+    chr->opaque = s;
+    chr->chr_set_echo = text_console_set_echo;
+
+    *_chr = chr;
+    return 0;
+}
+
+void text_consoles_set_display(DisplayState *ds)
+{
+    int i;
+
+    for (i = 0; i < n_text_consoles; i++) {
+        text_console_do_init(text_consoles[i], ds);
+    }
+
+    n_text_consoles = 0;
+}
+
+void qemu_console_resize(DisplayState *ds, int width, int height)
+{
+    TextConsole *s = get_graphic_console(ds);
+    if (!s) return;
+
+    s->g_width = width;
+    s->g_height = height;
+    if (is_graphic_console()) {
+        ds->surface = qemu_resize_displaysurface(ds, width, height);
+        dpy_resize(ds);
+    }
+}
+
+void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
+                       int dst_x, int dst_y, int w, int h)
+{
+    if (is_graphic_console()) {
+        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
+    }
+}
+
+PixelFormat qemu_different_endianness_pixelformat(int bpp)
+{
+    PixelFormat pf;
+
+    memset(&pf, 0x00, sizeof(PixelFormat));
+
+    pf.bits_per_pixel = bpp;
+    pf.bytes_per_pixel = bpp / 8;
+    pf.depth = bpp == 32 ? 24 : bpp;
+
+    switch (bpp) {
+        case 24:
+            pf.rmask = 0x000000FF;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x00FF0000;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.rshift = 0;
+            pf.gshift = 8;
+            pf.bshift = 16;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            break;
+        case 32:
+            pf.rmask = 0x0000FF00;
+            pf.gmask = 0x00FF0000;
+            pf.bmask = 0xFF000000;
+            pf.amask = 0x00000000;
+            pf.amax = 255;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.ashift = 0;
+            pf.rshift = 8;
+            pf.gshift = 16;
+            pf.bshift = 24;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            pf.abits = 8;
+            break;
+        default:
+            break;
+    }
+    return pf;
+}
+
+PixelFormat qemu_default_pixelformat(int bpp)
+{
+    PixelFormat pf;
+
+    memset(&pf, 0x00, sizeof(PixelFormat));
+
+    pf.bits_per_pixel = bpp;
+    pf.bytes_per_pixel = bpp / 8;
+    pf.depth = bpp == 32 ? 24 : bpp;
+
+    switch (bpp) {
+        case 15:
+            pf.bits_per_pixel = 16;
+            pf.bytes_per_pixel = 2;
+            pf.rmask = 0x00007c00;
+            pf.gmask = 0x000003E0;
+            pf.bmask = 0x0000001F;
+            pf.rmax = 31;
+            pf.gmax = 31;
+            pf.bmax = 31;
+            pf.rshift = 10;
+            pf.gshift = 5;
+            pf.bshift = 0;
+            pf.rbits = 5;
+            pf.gbits = 5;
+            pf.bbits = 5;
+            break;
+        case 16:
+            pf.rmask = 0x0000F800;
+            pf.gmask = 0x000007E0;
+            pf.bmask = 0x0000001F;
+            pf.rmax = 31;
+            pf.gmax = 63;
+            pf.bmax = 31;
+            pf.rshift = 11;
+            pf.gshift = 5;
+            pf.bshift = 0;
+            pf.rbits = 5;
+            pf.gbits = 6;
+            pf.bbits = 5;
+            break;
+        case 24:
+            pf.rmask = 0x00FF0000;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x000000FF;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.rshift = 16;
+            pf.gshift = 8;
+            pf.bshift = 0;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+        case 32:
+            pf.rmask = 0x00FF0000;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x000000FF;
+            pf.amax = 255;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.ashift = 24;
+            pf.rshift = 16;
+            pf.gshift = 8;
+            pf.bshift = 0;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            pf.abits = 8;
+            break;
+        default:
+            break;
+    }
+    return pf;
+}
diff --git a/qemu-0.15.x/console.h b/qemu-0.15.x/console.h
new file mode 100644
index 0000000..67d1373
--- /dev/null
+++ b/qemu-0.15.x/console.h
@@ -0,0 +1,406 @@
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+#include "qemu-char.h"
+#include "qdict.h"
+#include "notify.h"
+#include "qerror.h"
+#include "monitor.h"
+
+/* keyboard/mouse support */
+
+#define MOUSE_EVENT_LBUTTON 0x01
+#define MOUSE_EVENT_RBUTTON 0x02
+#define MOUSE_EVENT_MBUTTON 0x04
+
+/* identical to the ps/2 keyboard bits */
+#define QEMU_SCROLL_LOCK_LED (1 << 0)
+#define QEMU_NUM_LOCK_LED    (1 << 1)
+#define QEMU_CAPS_LOCK_LED   (1 << 2)
+
+/* in ms */
+#define GUI_REFRESH_INTERVAL 30
+
+typedef void QEMUPutKBDEvent(void *opaque, int keycode);
+typedef void QEMUPutLEDEvent(void *opaque, int ledstate);
+typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
+
+typedef struct QEMUPutMouseEntry {
+    QEMUPutMouseEvent *qemu_put_mouse_event;
+    void *qemu_put_mouse_event_opaque;
+    int qemu_put_mouse_event_absolute;
+    char *qemu_put_mouse_event_name;
+
+    int index;
+
+    /* used internally by qemu for handling mice */
+    QTAILQ_ENTRY(QEMUPutMouseEntry) node;
+} QEMUPutMouseEntry;
+
+typedef struct QEMUPutLEDEntry {
+    QEMUPutLEDEvent *put_led;
+    void *opaque;
+    QTAILQ_ENTRY(QEMUPutLEDEntry) next;
+} QEMUPutLEDEntry;
+
+void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+void qemu_remove_kbd_event_handler(void);
+QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+                                                void *opaque, int absolute,
+                                                const char *name);
+void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry);
+void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry);
+
+QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque);
+void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
+
+void kbd_put_keycode(int keycode);
+void kbd_put_ledstate(int ledstate);
+void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
+
+/* Does the current mouse generate absolute events */
+int kbd_mouse_is_absolute(void);
+void qemu_add_mouse_mode_change_notifier(Notifier *notify);
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
+
+/* Of all the mice, is there one that generates absolute events */
+int kbd_mouse_has_absolute(void);
+
+struct MouseTransformInfo {
+    /* Touchscreen resolution */
+    int x;
+    int y;
+    /* Calibration values as used/generated by tslib */
+    int a[7];
+};
+
+void do_info_mice_print(Monitor *mon, const QObject *data);
+void do_info_mice(Monitor *mon, QObject **ret_data);
+void do_mouse_set(Monitor *mon, const QDict *qdict);
+
+/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
+   constants) */
+#define QEMU_KEY_ESC1(c) ((c) | 0xe100)
+#define QEMU_KEY_BACKSPACE  0x007f
+#define QEMU_KEY_UP         QEMU_KEY_ESC1('A')
+#define QEMU_KEY_DOWN       QEMU_KEY_ESC1('B')
+#define QEMU_KEY_RIGHT      QEMU_KEY_ESC1('C')
+#define QEMU_KEY_LEFT       QEMU_KEY_ESC1('D')
+#define QEMU_KEY_HOME       QEMU_KEY_ESC1(1)
+#define QEMU_KEY_END        QEMU_KEY_ESC1(4)
+#define QEMU_KEY_PAGEUP     QEMU_KEY_ESC1(5)
+#define QEMU_KEY_PAGEDOWN   QEMU_KEY_ESC1(6)
+#define QEMU_KEY_DELETE     QEMU_KEY_ESC1(3)
+
+#define QEMU_KEY_CTRL_UP         0xe400
+#define QEMU_KEY_CTRL_DOWN       0xe401
+#define QEMU_KEY_CTRL_LEFT       0xe402
+#define QEMU_KEY_CTRL_RIGHT      0xe403
+#define QEMU_KEY_CTRL_HOME       0xe404
+#define QEMU_KEY_CTRL_END        0xe405
+#define QEMU_KEY_CTRL_PAGEUP     0xe406
+#define QEMU_KEY_CTRL_PAGEDOWN   0xe407
+
+void kbd_put_keysym(int keysym);
+
+/* consoles */
+
+#define QEMU_BIG_ENDIAN_FLAG    0x01
+#define QEMU_ALLOCATED_FLAG     0x02
+#define QEMU_REALPIXELS_FLAG    0x04
+
+struct PixelFormat {
+    uint8_t bits_per_pixel;
+    uint8_t bytes_per_pixel;
+    uint8_t depth; /* color depth in bits */
+    uint32_t rmask, gmask, bmask, amask;
+    uint8_t rshift, gshift, bshift, ashift;
+    uint8_t rmax, gmax, bmax, amax;
+    uint8_t rbits, gbits, bbits, abits;
+};
+
+struct DisplaySurface {
+    uint8_t flags;
+    int width;
+    int height;
+    int linesize;        /* bytes per line */
+    uint8_t *data;
+
+    struct PixelFormat pf;
+};
+
+/* cursor data format is 32bit RGBA */
+typedef struct QEMUCursor {
+    int                 width, height;
+    int                 hot_x, hot_y;
+    int                 refcount;
+    uint32_t            data[];
+} QEMUCursor;
+
+QEMUCursor *cursor_alloc(int width, int height);
+void cursor_get(QEMUCursor *c);
+void cursor_put(QEMUCursor *c);
+QEMUCursor *cursor_builtin_hidden(void);
+QEMUCursor *cursor_builtin_left_ptr(void);
+void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
+int cursor_get_mono_bpl(QEMUCursor *c);
+void cursor_set_mono(QEMUCursor *c,
+                     uint32_t foreground, uint32_t background, uint8_t *image,
+                     int transparent, uint8_t *mask);
+void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
+void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
+
+struct DisplayChangeListener {
+    int idle;
+    uint64_t gui_timer_interval;
+
+    void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
+    void (*dpy_resize)(struct DisplayState *s);
+    void (*dpy_setdata)(struct DisplayState *s);
+    void (*dpy_refresh)(struct DisplayState *s);
+    void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
+                     int dst_x, int dst_y, int w, int h);
+    void (*dpy_fill)(struct DisplayState *s, int x, int y,
+                     int w, int h, uint32_t c);
+    void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
+
+    struct DisplayChangeListener *next;
+};
+
+struct DisplayAllocator {
+    DisplaySurface* (*create_displaysurface)(int width, int height);
+    DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height);
+    void (*free_displaysurface)(DisplaySurface *surface);
+};
+
+struct DisplayState {
+    struct DisplaySurface *surface;
+    void *opaque;
+    struct QEMUTimer *gui_timer;
+
+    struct DisplayAllocator* allocator;
+    struct DisplayChangeListener* listeners;
+
+    void (*mouse_set)(int x, int y, int on);
+    void (*cursor_define)(QEMUCursor *cursor);
+
+    struct DisplayState *next;
+};
+
+void register_displaystate(DisplayState *ds);
+DisplayState *get_displaystate(void);
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                                int linesize, uint8_t *data);
+void qemu_alloc_display(DisplaySurface *surface, int width, int height,
+                        int linesize, PixelFormat pf, int newflags);
+PixelFormat qemu_different_endianness_pixelformat(int bpp);
+PixelFormat qemu_default_pixelformat(int bpp);
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
+
+static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
+{
+    return ds->allocator->create_displaysurface(width, height);    
+}
+
+static inline DisplaySurface* qemu_resize_displaysurface(DisplayState *ds, int width, int height)
+{
+    return ds->allocator->resize_displaysurface(ds->surface, width, height);
+}
+
+static inline void qemu_free_displaysurface(DisplayState *ds)
+{
+    ds->allocator->free_displaysurface(ds->surface);
+}
+
+static inline int is_surface_bgr(DisplaySurface *surface)
+{
+    if (surface->pf.bits_per_pixel == 32 && surface->pf.rshift == 0)
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_buffer_shared(DisplaySurface *surface)
+{
+    return (!(surface->flags & QEMU_ALLOCATED_FLAG) &&
+            !(surface->flags & QEMU_REALPIXELS_FLAG));
+}
+
+static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
+{
+    dcl->next = ds->listeners;
+    ds->listeners = dcl;
+}
+
+static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_update(s, x, y, w, h);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_resize(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_resize(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_setdata(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_setdata) dcl->dpy_setdata(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_refresh(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh) dcl->dpy_refresh(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
+                             int dst_x, int dst_y, int w, int h) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_copy)
+            dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
+        else /* TODO */
+            dcl->dpy_update(s, dst_x, dst_y, w, h);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_fill(struct DisplayState *s, int x, int y,
+                             int w, int h, uint32_t c) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
+        dcl = dcl->next;
+    }
+}
+
+static inline int ds_get_linesize(DisplayState *ds)
+{
+    return ds->surface->linesize;
+}
+
+static inline uint8_t* ds_get_data(DisplayState *ds)
+{
+    return ds->surface->data;
+}
+
+static inline int ds_get_width(DisplayState *ds)
+{
+    return ds->surface->width;
+}
+
+static inline int ds_get_height(DisplayState *ds)
+{
+    return ds->surface->height;
+}
+
+static inline int ds_get_bits_per_pixel(DisplayState *ds)
+{
+    return ds->surface->pf.bits_per_pixel;
+}
+
+static inline int ds_get_bytes_per_pixel(DisplayState *ds)
+{
+    return ds->surface->pf.bytes_per_pixel;
+}
+
+typedef unsigned long console_ch_t;
+static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
+{
+    if (!(ch & 0xff))
+        ch |= ' ';
+    *dest = ch;
+}
+
+typedef void (*vga_hw_update_ptr)(void *);
+typedef void (*vga_hw_invalidate_ptr)(void *);
+typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
+typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
+
+DisplayState *graphic_console_init(vga_hw_update_ptr update,
+                                   vga_hw_invalidate_ptr invalidate,
+                                   vga_hw_screen_dump_ptr screen_dump,
+                                   vga_hw_text_update_ptr text_update,
+                                   void *opaque);
+
+void vga_hw_update(void);
+void vga_hw_invalidate(void);
+void vga_hw_screen_dump(const char *filename);
+void vga_hw_text_update(console_ch_t *chardata);
+
+int is_graphic_console(void);
+int is_fixedsize_console(void);
+int text_console_init(QemuOpts *opts, CharDriverState **_chr);
+void text_consoles_set_display(DisplayState *ds);
+void console_select(unsigned int index);
+void console_color_init(DisplayState *ds);
+void qemu_console_resize(DisplayState *ds, int width, int height);
+void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
+                       int dst_x, int dst_y, int w, int h);
+
+/* sdl.c */
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
+
+/* cocoa.m */
+void cocoa_display_init(DisplayState *ds, int full_screen);
+
+/* vnc.c */
+void vnc_display_init(DisplayState *ds);
+void vnc_display_close(DisplayState *ds);
+int vnc_display_open(DisplayState *ds, const char *display);
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth);
+int vnc_display_disable_login(DisplayState *ds);
+char *vnc_display_local_addr(DisplayState *ds);
+#ifdef CONFIG_VNC
+int vnc_display_password(DisplayState *ds, const char *password);
+int vnc_display_pw_expire(DisplayState *ds, time_t expires);
+void do_info_vnc_print(Monitor *mon, const QObject *data);
+void do_info_vnc(Monitor *mon, QObject **ret_data);
+#else
+static inline int vnc_display_password(DisplayState *ds, const char *password)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+}
+static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+};
+static inline void do_info_vnc(Monitor *mon, QObject **ret_data)
+{
+};
+static inline void do_info_vnc_print(Monitor *mon, const QObject *data)
+{
+    monitor_printf(mon, "VNC support disabled\n");
+};
+#endif
+
+/* curses.c */
+void curses_display_init(DisplayState *ds, int full_screen);
+
+#endif
diff --git a/qemu-0.15.x/cpu-all.h b/qemu-0.15.x/cpu-all.h
new file mode 100644
index 0000000..e839100
--- /dev/null
+++ b/qemu-0.15.x/cpu-all.h
@@ -0,0 +1,1030 @@
+/*
+ * defines common to all virtual CPUs
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_ALL_H
+#define CPU_ALL_H
+
+#include "qemu-common.h"
+#include "cpu-common.h"
+
+/* some important defines:
+ *
+ * WORDS_ALIGNED : if defined, the host cpu can only make word aligned
+ * memory accesses.
+ *
+ * HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and
+ * otherwise little endian.
+ *
+ * (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
+ *
+ * TARGET_WORDS_BIGENDIAN : same for target cpu
+ */
+
+#include "softfloat.h"
+
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+#define BSWAP_NEEDED
+#endif
+
+#ifdef BSWAP_NEEDED
+
+static inline uint16_t tswap16(uint16_t s)
+{
+    return bswap16(s);
+}
+
+static inline uint32_t tswap32(uint32_t s)
+{
+    return bswap32(s);
+}
+
+static inline uint64_t tswap64(uint64_t s)
+{
+    return bswap64(s);
+}
+
+static inline void tswap16s(uint16_t *s)
+{
+    *s = bswap16(*s);
+}
+
+static inline void tswap32s(uint32_t *s)
+{
+    *s = bswap32(*s);
+}
+
+static inline void tswap64s(uint64_t *s)
+{
+    *s = bswap64(*s);
+}
+
+#else
+
+static inline uint16_t tswap16(uint16_t s)
+{
+    return s;
+}
+
+static inline uint32_t tswap32(uint32_t s)
+{
+    return s;
+}
+
+static inline uint64_t tswap64(uint64_t s)
+{
+    return s;
+}
+
+static inline void tswap16s(uint16_t *s)
+{
+}
+
+static inline void tswap32s(uint32_t *s)
+{
+}
+
+static inline void tswap64s(uint64_t *s)
+{
+}
+
+#endif
+
+#if TARGET_LONG_SIZE == 4
+#define tswapl(s) tswap32(s)
+#define tswapls(s) tswap32s((uint32_t *)(s))
+#define bswaptls(s) bswap32s(s)
+#else
+#define tswapl(s) tswap64(s)
+#define tswapls(s) tswap64s((uint64_t *)(s))
+#define bswaptls(s) bswap64s(s)
+#endif
+
+typedef union {
+    float32 f;
+    uint32_t l;
+} CPU_FloatU;
+
+/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
+   endian ! */
+typedef union {
+    float64 d;
+#if defined(HOST_WORDS_BIGENDIAN)
+    struct {
+        uint32_t upper;
+        uint32_t lower;
+    } l;
+#else
+    struct {
+        uint32_t lower;
+        uint32_t upper;
+    } l;
+#endif
+    uint64_t ll;
+} CPU_DoubleU;
+
+typedef union {
+     floatx80 d;
+     struct {
+         uint64_t lower;
+         uint16_t upper;
+     } l;
+} CPU_LDoubleU;
+
+typedef union {
+    float128 q;
+#if defined(HOST_WORDS_BIGENDIAN)
+    struct {
+        uint32_t upmost;
+        uint32_t upper;
+        uint32_t lower;
+        uint32_t lowest;
+    } l;
+    struct {
+        uint64_t upper;
+        uint64_t lower;
+    } ll;
+#else
+    struct {
+        uint32_t lowest;
+        uint32_t lower;
+        uint32_t upper;
+        uint32_t upmost;
+    } l;
+    struct {
+        uint64_t lower;
+        uint64_t upper;
+    } ll;
+#endif
+} CPU_QuadU;
+
+/* CPU memory access without any memory or io remapping */
+
+/*
+ * the generic syntax for the memory accesses is:
+ *
+ * load: ld{type}{sign}{size}{endian}_{access_type}(ptr)
+ *
+ * store: st{type}{size}{endian}_{access_type}(ptr, val)
+ *
+ * type is:
+ * (empty): integer access
+ *   f    : float access
+ *
+ * sign is:
+ * (empty): for floats or 32 bit size
+ *   u    : unsigned
+ *   s    : signed
+ *
+ * size is:
+ *   b: 8 bits
+ *   w: 16 bits
+ *   l: 32 bits
+ *   q: 64 bits
+ *
+ * endian is:
+ * (empty): target cpu endianness or 8 bit access
+ *   r    : reversed target cpu endianness (not implemented yet)
+ *   be   : big endian (not implemented yet)
+ *   le   : little endian (not implemented yet)
+ *
+ * access_type is:
+ *   raw    : host memory access
+ *   user   : user mode access using soft MMU
+ *   kernel : kernel mode access using soft MMU
+ */
+static inline int ldub_p(const void *ptr)
+{
+    return *(uint8_t *)ptr;
+}
+
+static inline int ldsb_p(const void *ptr)
+{
+    return *(int8_t *)ptr;
+}
+
+static inline void stb_p(void *ptr, int v)
+{
+    *(uint8_t *)ptr = v;
+}
+
+/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
+   kernel handles unaligned load/stores may give better results, but
+   it is a system wide setting : bad */
+#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+/* conservative code for little endian unaligned accesses */
+static inline int lduw_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return val;
+#else
+    const uint8_t *p = ptr;
+    return p[0] | (p[1] << 8);
+#endif
+}
+
+static inline int ldsw_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return (int16_t)val;
+#else
+    const uint8_t *p = ptr;
+    return (int16_t)(p[0] | (p[1] << 8));
+#endif
+}
+
+static inline int ldl_le_p(const void *ptr)
+{
+#ifdef _ARCH_PPC
+    int val;
+    __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+    return val;
+#else
+    const uint8_t *p = ptr;
+    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+#endif
+}
+
+static inline uint64_t ldq_le_p(const void *ptr)
+{
+    const uint8_t *p = ptr;
+    uint32_t v1, v2;
+    v1 = ldl_le_p(p);
+    v2 = ldl_le_p(p + 4);
+    return v1 | ((uint64_t)v2 << 32);
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+#ifdef _ARCH_PPC
+    __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
+#else
+    uint8_t *p = ptr;
+    p[0] = v;
+    p[1] = v >> 8;
+#endif
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+#ifdef _ARCH_PPC
+    __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
+#else
+    uint8_t *p = ptr;
+    p[0] = v;
+    p[1] = v >> 8;
+    p[2] = v >> 16;
+    p[3] = v >> 24;
+#endif
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+    uint8_t *p = ptr;
+    stl_le_p(p, (uint32_t)v);
+    stl_le_p(p + 4, v >> 32);
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(const void *ptr)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = ldl_le_p(ptr);
+    return u.f;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = v;
+    stl_le_p(ptr, u.i);
+}
+
+static inline float64 ldfq_le_p(const void *ptr)
+{
+    CPU_DoubleU u;
+    u.l.lower = ldl_le_p(ptr);
+    u.l.upper = ldl_le_p(ptr + 4);
+    return u.d;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+    CPU_DoubleU u;
+    u.d = v;
+    stl_le_p(ptr, u.l.lower);
+    stl_le_p(ptr + 4, u.l.upper);
+}
+
+#else
+
+static inline int lduw_le_p(const void *ptr)
+{
+    return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_le_p(const void *ptr)
+{
+    return *(int16_t *)ptr;
+}
+
+static inline int ldl_le_p(const void *ptr)
+{
+    return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_le_p(const void *ptr)
+{
+    return *(uint64_t *)ptr;
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+    *(uint16_t *)ptr = v;
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+    *(uint32_t *)ptr = v;
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+    *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(const void *ptr)
+{
+    return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_le_p(const void *ptr)
+{
+    return *(float64 *)ptr;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+    *(float32 *)ptr = v;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+    *(float64 *)ptr = v;
+}
+#endif
+
+#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+static inline int lduw_be_p(const void *ptr)
+{
+#if defined(__i386__)
+    int val;
+    asm volatile ("movzwl %1, %0\n"
+                  "xchgb %b0, %h0\n"
+                  : "=q" (val)
+                  : "m" (*(uint16_t *)ptr));
+    return val;
+#else
+    const uint8_t *b = ptr;
+    return ((b[0] << 8) | b[1]);
+#endif
+}
+
+static inline int ldsw_be_p(const void *ptr)
+{
+#if defined(__i386__)
+    int val;
+    asm volatile ("movzwl %1, %0\n"
+                  "xchgb %b0, %h0\n"
+                  : "=q" (val)
+                  : "m" (*(uint16_t *)ptr));
+    return (int16_t)val;
+#else
+    const uint8_t *b = ptr;
+    return (int16_t)((b[0] << 8) | b[1]);
+#endif
+}
+
+static inline int ldl_be_p(const void *ptr)
+{
+#if defined(__i386__) || defined(__x86_64__)
+    int val;
+    asm volatile ("movl %1, %0\n"
+                  "bswap %0\n"
+                  : "=r" (val)
+                  : "m" (*(uint32_t *)ptr));
+    return val;
+#else
+    const uint8_t *b = ptr;
+    return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+#endif
+}
+
+static inline uint64_t ldq_be_p(const void *ptr)
+{
+    uint32_t a,b;
+    a = ldl_be_p(ptr);
+    b = ldl_be_p((uint8_t *)ptr + 4);
+    return (((uint64_t)a<<32)|b);
+}
+
+static inline void stw_be_p(void *ptr, int v)
+{
+#if defined(__i386__)
+    asm volatile ("xchgb %b0, %h0\n"
+                  "movw %w0, %1\n"
+                  : "=q" (v)
+                  : "m" (*(uint16_t *)ptr), "0" (v));
+#else
+    uint8_t *d = (uint8_t *) ptr;
+    d[0] = v >> 8;
+    d[1] = v;
+#endif
+}
+
+static inline void stl_be_p(void *ptr, int v)
+{
+#if defined(__i386__) || defined(__x86_64__)
+    asm volatile ("bswap %0\n"
+                  "movl %0, %1\n"
+                  : "=r" (v)
+                  : "m" (*(uint32_t *)ptr), "0" (v));
+#else
+    uint8_t *d = (uint8_t *) ptr;
+    d[0] = v >> 24;
+    d[1] = v >> 16;
+    d[2] = v >> 8;
+    d[3] = v;
+#endif
+}
+
+static inline void stq_be_p(void *ptr, uint64_t v)
+{
+    stl_be_p(ptr, v >> 32);
+    stl_be_p((uint8_t *)ptr + 4, v);
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(const void *ptr)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = ldl_be_p(ptr);
+    return u.f;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = v;
+    stl_be_p(ptr, u.i);
+}
+
+static inline float64 ldfq_be_p(const void *ptr)
+{
+    CPU_DoubleU u;
+    u.l.upper = ldl_be_p(ptr);
+    u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
+    return u.d;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+    CPU_DoubleU u;
+    u.d = v;
+    stl_be_p(ptr, u.l.upper);
+    stl_be_p((uint8_t *)ptr + 4, u.l.lower);
+}
+
+#else
+
+static inline int lduw_be_p(const void *ptr)
+{
+    return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_be_p(const void *ptr)
+{
+    return *(int16_t *)ptr;
+}
+
+static inline int ldl_be_p(const void *ptr)
+{
+    return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_be_p(const void *ptr)
+{
+    return *(uint64_t *)ptr;
+}
+
+static inline void stw_be_p(void *ptr, int v)
+{
+    *(uint16_t *)ptr = v;
+}
+
+static inline void stl_be_p(void *ptr, int v)
+{
+    *(uint32_t *)ptr = v;
+}
+
+static inline void stq_be_p(void *ptr, uint64_t v)
+{
+    *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(const void *ptr)
+{
+    return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_be_p(const void *ptr)
+{
+    return *(float64 *)ptr;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+    *(float32 *)ptr = v;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+    *(float64 *)ptr = v;
+}
+
+#endif
+
+/* target CPU memory access functions */
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define lduw_p(p) lduw_be_p(p)
+#define ldsw_p(p) ldsw_be_p(p)
+#define ldl_p(p) ldl_be_p(p)
+#define ldq_p(p) ldq_be_p(p)
+#define ldfl_p(p) ldfl_be_p(p)
+#define ldfq_p(p) ldfq_be_p(p)
+#define stw_p(p, v) stw_be_p(p, v)
+#define stl_p(p, v) stl_be_p(p, v)
+#define stq_p(p, v) stq_be_p(p, v)
+#define stfl_p(p, v) stfl_be_p(p, v)
+#define stfq_p(p, v) stfq_be_p(p, v)
+#else
+#define lduw_p(p) lduw_le_p(p)
+#define ldsw_p(p) ldsw_le_p(p)
+#define ldl_p(p) ldl_le_p(p)
+#define ldq_p(p) ldq_le_p(p)
+#define ldfl_p(p) ldfl_le_p(p)
+#define ldfq_p(p) ldfq_le_p(p)
+#define stw_p(p, v) stw_le_p(p, v)
+#define stl_p(p, v) stl_le_p(p, v)
+#define stq_p(p, v) stq_le_p(p, v)
+#define stfl_p(p, v) stfl_le_p(p, v)
+#define stfq_p(p, v) stfq_le_p(p, v)
+#endif
+
+/* MMU memory access macros */
+
+#if defined(CONFIG_USER_ONLY)
+#include <assert.h>
+#include "qemu-types.h"
+
+/* On some host systems the guest address space is reserved on the host.
+ * This allows the guest address space to be offset to a convenient location.
+ */
+#if defined(CONFIG_USE_GUEST_BASE)
+extern unsigned long guest_base;
+extern int have_guest_base;
+extern unsigned long reserved_va;
+#define GUEST_BASE guest_base
+#define RESERVED_VA reserved_va
+#else
+#define GUEST_BASE 0ul
+#define RESERVED_VA 0ul
+#endif
+
+/* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
+#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
+
+#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
+#define h2g_valid(x) 1
+#else
+#define h2g_valid(x) ({ \
+    unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
+    __guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS); \
+})
+#endif
+
+#define h2g(x) ({ \
+    unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
+    /* Check if given address fits target address space */ \
+    assert(h2g_valid(x)); \
+    (abi_ulong)__ret; \
+})
+
+#define saddr(x) g2h(x)
+#define laddr(x) g2h(x)
+
+#else /* !CONFIG_USER_ONLY */
+/* NOTE: we use double casts if pointers and target_ulong have
+   different sizes */
+#define saddr(x) (uint8_t *)(long)(x)
+#define laddr(x) (uint8_t *)(long)(x)
+#endif
+
+#define ldub_raw(p) ldub_p(laddr((p)))
+#define ldsb_raw(p) ldsb_p(laddr((p)))
+#define lduw_raw(p) lduw_p(laddr((p)))
+#define ldsw_raw(p) ldsw_p(laddr((p)))
+#define ldl_raw(p) ldl_p(laddr((p)))
+#define ldq_raw(p) ldq_p(laddr((p)))
+#define ldfl_raw(p) ldfl_p(laddr((p)))
+#define ldfq_raw(p) ldfq_p(laddr((p)))
+#define stb_raw(p, v) stb_p(saddr((p)), v)
+#define stw_raw(p, v) stw_p(saddr((p)), v)
+#define stl_raw(p, v) stl_p(saddr((p)), v)
+#define stq_raw(p, v) stq_p(saddr((p)), v)
+#define stfl_raw(p, v) stfl_p(saddr((p)), v)
+#define stfq_raw(p, v) stfq_p(saddr((p)), v)
+
+
+#if defined(CONFIG_USER_ONLY)
+
+/* if user mode, no other memory access functions */
+#define ldub(p) ldub_raw(p)
+#define ldsb(p) ldsb_raw(p)
+#define lduw(p) lduw_raw(p)
+#define ldsw(p) ldsw_raw(p)
+#define ldl(p) ldl_raw(p)
+#define ldq(p) ldq_raw(p)
+#define ldfl(p) ldfl_raw(p)
+#define ldfq(p) ldfq_raw(p)
+#define stb(p, v) stb_raw(p, v)
+#define stw(p, v) stw_raw(p, v)
+#define stl(p, v) stl_raw(p, v)
+#define stq(p, v) stq_raw(p, v)
+#define stfl(p, v) stfl_raw(p, v)
+#define stfq(p, v) stfq_raw(p, v)
+
+#define ldub_code(p) ldub_raw(p)
+#define ldsb_code(p) ldsb_raw(p)
+#define lduw_code(p) lduw_raw(p)
+#define ldsw_code(p) ldsw_raw(p)
+#define ldl_code(p) ldl_raw(p)
+#define ldq_code(p) ldq_raw(p)
+
+#define ldub_kernel(p) ldub_raw(p)
+#define ldsb_kernel(p) ldsb_raw(p)
+#define lduw_kernel(p) lduw_raw(p)
+#define ldsw_kernel(p) ldsw_raw(p)
+#define ldl_kernel(p) ldl_raw(p)
+#define ldq_kernel(p) ldq_raw(p)
+#define ldfl_kernel(p) ldfl_raw(p)
+#define ldfq_kernel(p) ldfq_raw(p)
+#define stb_kernel(p, v) stb_raw(p, v)
+#define stw_kernel(p, v) stw_raw(p, v)
+#define stl_kernel(p, v) stl_raw(p, v)
+#define stq_kernel(p, v) stq_raw(p, v)
+#define stfl_kernel(p, v) stfl_raw(p, v)
+#define stfq_kernel(p, vt) stfq_raw(p, v)
+
+#endif /* defined(CONFIG_USER_ONLY) */
+
+/* page related stuff */
+
+#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
+#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
+#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
+
+/* ??? These should be the larger of unsigned long and target_ulong.  */
+extern unsigned long qemu_real_host_page_size;
+extern unsigned long qemu_host_page_bits;
+extern unsigned long qemu_host_page_size;
+extern unsigned long qemu_host_page_mask;
+
+#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
+
+/* same as PROT_xxx */
+#define PAGE_READ      0x0001
+#define PAGE_WRITE     0x0002
+#define PAGE_EXEC      0x0004
+#define PAGE_BITS      (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
+#define PAGE_VALID     0x0008
+/* original state of the write flag (used when tracking self-modifying
+   code */
+#define PAGE_WRITE_ORG 0x0010
+#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
+/* FIXME: Code that sets/uses this is broken and needs to go away.  */
+#define PAGE_RESERVED  0x0020
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+void page_dump(FILE *f);
+
+typedef int (*walk_memory_regions_fn)(void *, abi_ulong,
+                                      abi_ulong, unsigned long);
+int walk_memory_regions(void *, walk_memory_regions_fn);
+
+int page_get_flags(target_ulong address);
+void page_set_flags(target_ulong start, target_ulong end, int flags);
+int page_check_range(target_ulong start, target_ulong len, int flags);
+#endif
+
+CPUState *cpu_copy(CPUState *env);
+CPUState *qemu_get_cpu(int cpu);
+
+#define CPU_DUMP_CODE 0x00010000
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags);
+void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                         int flags);
+
+void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+extern CPUState *first_cpu;
+extern CPUState *cpu_single_env;
+
+/* Flags for use in ENV->INTERRUPT_PENDING.
+
+   The numbers assigned here are non-sequential in order to preserve
+   binary compatibility with the vmstate dump.  Bit 0 (0x0001) was
+   previously used for CPU_INTERRUPT_EXIT, and is cleared when loading
+   the vmstate dump.  */
+
+/* External hardware interrupt pending.  This is typically used for
+   interrupts from devices.  */
+#define CPU_INTERRUPT_HARD        0x0002
+
+/* Exit the current TB.  This is typically used when some system-level device
+   makes some change to the memory mapping.  E.g. the a20 line change.  */
+#define CPU_INTERRUPT_EXITTB      0x0004
+
+/* Halt the CPU.  */
+#define CPU_INTERRUPT_HALT        0x0020
+
+/* Debug event pending.  */
+#define CPU_INTERRUPT_DEBUG       0x0080
+
+/* Several target-specific external hardware interrupts.  Each target/cpu.h
+   should define proper names based on these defines.  */
+#define CPU_INTERRUPT_TGT_EXT_0   0x0008
+#define CPU_INTERRUPT_TGT_EXT_1   0x0010
+#define CPU_INTERRUPT_TGT_EXT_2   0x0040
+#define CPU_INTERRUPT_TGT_EXT_3   0x0200
+#define CPU_INTERRUPT_TGT_EXT_4   0x1000
+
+/* Several target-specific internal interrupts.  These differ from the
+   preceeding target-specific interrupts in that they are intended to
+   originate from within the cpu itself, typically in response to some
+   instruction being executed.  These, therefore, are not masked while
+   single-stepping within the debugger.  */
+#define CPU_INTERRUPT_TGT_INT_0   0x0100
+#define CPU_INTERRUPT_TGT_INT_1   0x0400
+#define CPU_INTERRUPT_TGT_INT_2   0x0800
+
+/* First unused bit: 0x2000.  */
+
+/* The set of all bits that should be masked when single-stepping.  */
+#define CPU_INTERRUPT_SSTEP_MASK \
+    (CPU_INTERRUPT_HARD          \
+     | CPU_INTERRUPT_TGT_EXT_0   \
+     | CPU_INTERRUPT_TGT_EXT_1   \
+     | CPU_INTERRUPT_TGT_EXT_2   \
+     | CPU_INTERRUPT_TGT_EXT_3   \
+     | CPU_INTERRUPT_TGT_EXT_4)
+
+#ifndef CONFIG_USER_ONLY
+typedef void (*CPUInterruptHandler)(CPUState *, int);
+
+extern CPUInterruptHandler cpu_interrupt_handler;
+
+static inline void cpu_interrupt(CPUState *s, int mask)
+{
+    cpu_interrupt_handler(s, mask);
+}
+#else /* USER_ONLY */
+void cpu_interrupt(CPUState *env, int mask);
+#endif /* USER_ONLY */
+
+void cpu_reset_interrupt(CPUState *env, int mask);
+
+void cpu_exit(CPUState *s);
+
+bool qemu_cpu_has_work(CPUState *env);
+
+/* Breakpoint/watchpoint flags */
+#define BP_MEM_READ           0x01
+#define BP_MEM_WRITE          0x02
+#define BP_MEM_ACCESS         (BP_MEM_READ | BP_MEM_WRITE)
+#define BP_STOP_BEFORE_ACCESS 0x04
+#define BP_WATCHPOINT_HIT     0x08
+#define BP_GDB                0x10
+#define BP_CPU                0x20
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint);
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags);
+void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint);
+void cpu_breakpoint_remove_all(CPUState *env, int mask);
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint);
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr,
+                          target_ulong len, int flags);
+void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint);
+void cpu_watchpoint_remove_all(CPUState *env, int mask);
+
+#define SSTEP_ENABLE  0x1  /* Enable simulated HW single stepping */
+#define SSTEP_NOIRQ   0x2  /* Do not use IRQ while single stepping */
+#define SSTEP_NOTIMER 0x4  /* Do not Timers while single stepping */
+
+void cpu_single_step(CPUState *env, int enabled);
+void cpu_reset(CPUState *s);
+int cpu_is_stopped(CPUState *env);
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data);
+
+#define CPU_LOG_TB_OUT_ASM (1 << 0)
+#define CPU_LOG_TB_IN_ASM  (1 << 1)
+#define CPU_LOG_TB_OP      (1 << 2)
+#define CPU_LOG_TB_OP_OPT  (1 << 3)
+#define CPU_LOG_INT        (1 << 4)
+#define CPU_LOG_EXEC       (1 << 5)
+#define CPU_LOG_PCALL      (1 << 6)
+#define CPU_LOG_IOPORT     (1 << 7)
+#define CPU_LOG_TB_CPU     (1 << 8)
+#define CPU_LOG_RESET      (1 << 9)
+
+/* define log items */
+typedef struct CPULogItem {
+    int mask;
+    const char *name;
+    const char *help;
+} CPULogItem;
+
+extern const CPULogItem cpu_log_items[];
+
+void cpu_set_log(int log_flags);
+void cpu_set_log_filename(const char *filename);
+int cpu_str_to_log_mask(const char *str);
+
+#if !defined(CONFIG_USER_ONLY)
+
+/* Return the physical page corresponding to a virtual one. Use it
+   only for debugging because no protection checks are done. Return -1
+   if no page found. */
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
+
+/* memory API */
+
+extern int phys_ram_fd;
+extern ram_addr_t ram_size;
+
+/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
+#define RAM_PREALLOC_MASK   (1 << 0)
+
+typedef struct RAMBlock {
+    uint8_t *host;
+    ram_addr_t offset;
+    ram_addr_t length;
+    uint32_t flags;
+    char idstr[256];
+    QLIST_ENTRY(RAMBlock) next;
+#if defined(__linux__) && !defined(TARGET_S390X)
+    int fd;
+#endif
+} RAMBlock;
+
+typedef struct RAMList {
+    uint8_t *phys_dirty;
+    QLIST_HEAD(ram, RAMBlock) blocks;
+} RAMList;
+extern RAMList ram_list;
+
+extern const char *mem_path;
+extern int mem_prealloc;
+
+/* physical memory access */
+
+/* MMIO pages are identified by a combination of an IO device index and
+   3 flags.  The ROMD code stores the page ram offset in iotlb entry, 
+   so only a limited number of ids are avaiable.  */
+
+#define IO_MEM_NB_ENTRIES  (1 << (TARGET_PAGE_BITS  - IO_MEM_SHIFT))
+
+/* Flags stored in the low bits of the TLB virtual address.  These are
+   defined so that fast path ram access is all zeros.  */
+/* Zero if TLB entry is valid.  */
+#define TLB_INVALID_MASK   (1 << 3)
+/* Set if TLB entry references a clean RAM page.  The iotlb entry will
+   contain the page physical address.  */
+#define TLB_NOTDIRTY    (1 << 4)
+/* Set if TLB entry is an IO callback.  */
+#define TLB_MMIO        (1 << 5)
+
+#define VGA_DIRTY_FLAG       0x01
+#define CODE_DIRTY_FLAG      0x02
+#define MIGRATION_DIRTY_FLAG 0x08
+
+/* read dirty bit (return 0 or 1) */
+static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
+{
+    return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
+}
+
+static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
+{
+    return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
+}
+
+static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
+                                                int dirty_flags)
+{
+    return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+}
+
+static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
+{
+    ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
+}
+
+static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
+                                                      int dirty_flags)
+{
+    return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
+}
+
+static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
+                                                        int length,
+                                                        int dirty_flags)
+{
+    int i, mask, len;
+    uint8_t *p;
+
+    len = length >> TARGET_PAGE_BITS;
+    mask = ~dirty_flags;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    for (i = 0; i < len; i++) {
+        p[i] &= mask;
+    }
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+                                     int dirty_flags);
+void cpu_tlb_update_dirty(CPUState *env);
+
+int cpu_physical_memory_set_dirty_tracking(int enable);
+
+int cpu_physical_memory_get_dirty_tracking(void);
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr);
+
+int cpu_physical_log_start(target_phys_addr_t start_addr,
+                           ram_addr_t size);
+
+int cpu_physical_log_stop(target_phys_addr_t start_addr,
+                          ram_addr_t size);
+
+void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
+#endif /* !CONFIG_USER_ONLY */
+
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write);
+
+#endif /* CPU_ALL_H */
diff --git a/qemu-0.15.x/cpu-common.h b/qemu-0.15.x/cpu-common.h
new file mode 100644
index 0000000..44b04b3
--- /dev/null
+++ b/qemu-0.15.x/cpu-common.h
@@ -0,0 +1,178 @@
+#ifndef CPU_COMMON_H
+#define CPU_COMMON_H 1
+
+/* CPU interfaces that are target indpendent.  */
+
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__)
+#define WORDS_ALIGNED
+#endif
+
+#ifdef TARGET_PHYS_ADDR_BITS
+#include "targphys.h"
+#endif
+
+#ifndef NEED_CPU_H
+#include "poison.h"
+#endif
+
+#include "bswap.h"
+#include "qemu-queue.h"
+
+#if !defined(CONFIG_USER_ONLY)
+
+enum device_endian {
+    DEVICE_NATIVE_ENDIAN,
+    DEVICE_BIG_ENDIAN,
+    DEVICE_LITTLE_ENDIAN,
+};
+
+/* address in the RAM (different from a physical address) */
+typedef unsigned long ram_addr_t;
+
+/* memory API */
+
+typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
+typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
+
+void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
+                                      ram_addr_t size,
+                                      ram_addr_t phys_offset,
+                                      ram_addr_t region_offset,
+                                      bool log_dirty);
+
+static inline void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                                       ram_addr_t size,
+                                                       ram_addr_t phys_offset,
+                                                       ram_addr_t region_offset)
+{
+    cpu_register_physical_memory_log(start_addr, size, phys_offset,
+                                     region_offset, false);
+}
+
+static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
+                                                ram_addr_t size,
+                                                ram_addr_t phys_offset)
+{
+    cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0);
+}
+
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
+                        ram_addr_t size, void *host);
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
+void qemu_ram_free(ram_addr_t addr);
+void qemu_ram_free_from_ptr(ram_addr_t addr);
+void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
+/* This should only be used for ram local to a device.  */
+void *qemu_get_ram_ptr(ram_addr_t addr);
+void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size);
+/* Same but slower, to use for migration, where the order of
+ * RAMBlocks must not change. */
+void *qemu_safe_ram_ptr(ram_addr_t addr);
+void qemu_put_ram_ptr(void *addr);
+/* This should not be used by devices.  */
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque, enum device_endian endian);
+void cpu_unregister_io_memory(int table_address);
+
+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,
+                                            void *buf, int len)
+{
+    cpu_physical_memory_rw(addr, buf, len, 0);
+}
+static inline void cpu_physical_memory_write(target_phys_addr_t addr,
+                                             const void *buf, int len)
+{
+    cpu_physical_memory_rw(addr, (void *)buf, len, 1);
+}
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write);
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len);
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
+void cpu_unregister_map_client(void *cookie);
+
+struct CPUPhysMemoryClient;
+typedef struct CPUPhysMemoryClient CPUPhysMemoryClient;
+struct CPUPhysMemoryClient {
+    void (*set_memory)(struct CPUPhysMemoryClient *client,
+                       target_phys_addr_t start_addr,
+                       ram_addr_t size,
+                       ram_addr_t phys_offset,
+                       bool log_dirty);
+    int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
+                             target_phys_addr_t start_addr,
+                             target_phys_addr_t end_addr);
+    int (*migration_log)(struct CPUPhysMemoryClient *client,
+                         int enable);
+    int (*log_start)(struct CPUPhysMemoryClient *client,
+                     target_phys_addr_t phys_addr, ram_addr_t size);
+    int (*log_stop)(struct CPUPhysMemoryClient *client,
+                    target_phys_addr_t phys_addr, ram_addr_t size);
+    QLIST_ENTRY(CPUPhysMemoryClient) list;
+};
+
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);
+
+/* Coalesced MMIO regions are areas where write operations can be reordered.
+ * This usually implies that write operations are side-effect free.  This allows
+ * batching which can make a major impact on performance when using
+ * virtualization.
+ */
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
+
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
+
+void qemu_flush_coalesced_mmio_buffer(void);
+
+uint32_t ldub_phys(target_phys_addr_t addr);
+uint32_t lduw_le_phys(target_phys_addr_t addr);
+uint32_t lduw_be_phys(target_phys_addr_t addr);
+uint32_t ldl_le_phys(target_phys_addr_t addr);
+uint32_t ldl_be_phys(target_phys_addr_t addr);
+uint64_t ldq_le_phys(target_phys_addr_t addr);
+uint64_t ldq_be_phys(target_phys_addr_t addr);
+void stb_phys(target_phys_addr_t addr, uint32_t val);
+void stw_le_phys(target_phys_addr_t addr, uint32_t val);
+void stw_be_phys(target_phys_addr_t addr, uint32_t val);
+void stl_le_phys(target_phys_addr_t addr, uint32_t val);
+void stl_be_phys(target_phys_addr_t addr, uint32_t val);
+void stq_le_phys(target_phys_addr_t addr, uint64_t val);
+void stq_be_phys(target_phys_addr_t addr, uint64_t val);
+
+#ifdef NEED_CPU_H
+uint32_t lduw_phys(target_phys_addr_t addr);
+uint32_t ldl_phys(target_phys_addr_t addr);
+uint64_t ldq_phys(target_phys_addr_t addr);
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
+void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
+void stw_phys(target_phys_addr_t addr, uint32_t val);
+void stl_phys(target_phys_addr_t addr, uint32_t val);
+void stq_phys(target_phys_addr_t addr, uint64_t val);
+#endif
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len);
+
+#define IO_MEM_SHIFT       3
+
+#define IO_MEM_RAM         (0 << IO_MEM_SHIFT) /* hardcoded offset */
+#define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
+#define IO_MEM_UNASSIGNED  (2 << IO_MEM_SHIFT)
+#define IO_MEM_NOTDIRTY    (3 << IO_MEM_SHIFT)
+
+/* Acts like a ROM when read and like a device when written.  */
+#define IO_MEM_ROMD        (1)
+#define IO_MEM_SUBPAGE     (2)
+
+#endif
+
+#endif /* !CPU_COMMON_H */
diff --git a/qemu-0.15.x/cpu-defs.h b/qemu-0.15.x/cpu-defs.h
new file mode 100644
index 0000000..db48a7a
--- /dev/null
+++ b/qemu-0.15.x/cpu-defs.h
@@ -0,0 +1,223 @@
+/*
+ * common defines for all CPUs
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_DEFS_H
+#define CPU_DEFS_H
+
+#ifndef NEED_CPU_H
+#error cpu.h included from common code
+#endif
+
+#include "config.h"
+#include <setjmp.h>
+#include <inttypes.h>
+#include <signal.h>
+#include "osdep.h"
+#include "qemu-queue.h"
+#include "targphys.h"
+
+#ifndef TARGET_LONG_BITS
+#error TARGET_LONG_BITS must be defined before including this header
+#endif
+
+#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
+
+typedef int16_t target_short __attribute__ ((aligned(TARGET_SHORT_ALIGNMENT)));
+typedef uint16_t target_ushort __attribute__((aligned(TARGET_SHORT_ALIGNMENT)));
+typedef int32_t target_int __attribute__((aligned(TARGET_INT_ALIGNMENT)));
+typedef uint32_t target_uint __attribute__((aligned(TARGET_INT_ALIGNMENT)));
+typedef int64_t target_llong __attribute__((aligned(TARGET_LLONG_ALIGNMENT)));
+typedef uint64_t target_ullong __attribute__((aligned(TARGET_LLONG_ALIGNMENT)));
+/* target_ulong is the type of a virtual address */
+#if TARGET_LONG_SIZE == 4
+typedef int32_t target_long __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+typedef uint32_t target_ulong __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+#define TARGET_FMT_lx "%08x"
+#define TARGET_FMT_ld "%d"
+#define TARGET_FMT_lu "%u"
+#elif TARGET_LONG_SIZE == 8
+typedef int64_t target_long __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+typedef uint64_t target_ulong __attribute__((aligned(TARGET_LONG_ALIGNMENT)));
+#define TARGET_FMT_lx "%016" PRIx64
+#define TARGET_FMT_ld "%" PRId64
+#define TARGET_FMT_lu "%" PRIu64
+#else
+#error TARGET_LONG_SIZE undefined
+#endif
+
+#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
+
+#define EXCP_INTERRUPT 	0x10000 /* async interruption */
+#define EXCP_HLT        0x10001 /* hlt instruction reached */
+#define EXCP_DEBUG      0x10002 /* cpu stopped after a breakpoint or singlestep */
+#define EXCP_HALTED     0x10003 /* cpu is halted (waiting for external event) */
+
+#define TB_JMP_CACHE_BITS 12
+#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
+
+/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
+   addresses on the same page.  The top bits are the same.  This allows
+   TLB invalidation to quickly clear a subset of the hash table.  */
+#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
+#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
+#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
+#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
+
+#if !defined(CONFIG_USER_ONLY)
+#define CPU_TLB_BITS 8
+#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
+
+#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32
+#define CPU_TLB_ENTRY_BITS 4
+#else
+#define CPU_TLB_ENTRY_BITS 5
+#endif
+
+typedef struct CPUTLBEntry {
+    /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address
+       bit TARGET_PAGE_BITS-1..4  : Nonzero for accesses that should not
+                                    go directly to ram.
+       bit 3                      : indicates that the entry is invalid
+       bit 2..0                   : zero
+    */
+    target_ulong addr_read;
+    target_ulong addr_write;
+    target_ulong addr_code;
+    /* Addend to virtual address to get host address.  IO accesses
+       use the corresponding iotlb value.  */
+    unsigned long addend;
+    /* padding to get a power of two size */
+    uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) - 
+                  (sizeof(target_ulong) * 3 + 
+                   ((-sizeof(target_ulong) * 3) & (sizeof(unsigned long) - 1)) + 
+                   sizeof(unsigned long))];
+} CPUTLBEntry;
+
+extern int CPUTLBEntry_wrong_size[sizeof(CPUTLBEntry) == (1 << CPU_TLB_ENTRY_BITS) ? 1 : -1];
+
+#define CPU_COMMON_TLB \
+    /* The meaning of the MMU modes is defined in the target code. */   \
+    CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE];                  \
+    target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE];               \
+    target_ulong tlb_flush_addr;                                        \
+    target_ulong tlb_flush_mask;
+
+#else
+
+#define CPU_COMMON_TLB
+
+#endif
+
+
+#ifdef HOST_WORDS_BIGENDIAN
+typedef struct icount_decr_u16 {
+    uint16_t high;
+    uint16_t low;
+} icount_decr_u16;
+#else
+typedef struct icount_decr_u16 {
+    uint16_t low;
+    uint16_t high;
+} icount_decr_u16;
+#endif
+
+struct kvm_run;
+struct KVMState;
+struct qemu_work_item;
+
+typedef struct CPUBreakpoint {
+    target_ulong pc;
+    int flags; /* BP_* */
+    QTAILQ_ENTRY(CPUBreakpoint) entry;
+} CPUBreakpoint;
+
+typedef struct CPUWatchpoint {
+    target_ulong vaddr;
+    target_ulong len_mask;
+    int flags; /* BP_* */
+    QTAILQ_ENTRY(CPUWatchpoint) entry;
+} CPUWatchpoint;
+
+#define CPU_TEMP_BUF_NLONGS 128
+#define CPU_COMMON                                                      \
+    struct TranslationBlock *current_tb; /* currently executing TB  */  \
+    /* soft mmu support */                                              \
+    /* in order to avoid passing too many arguments to the MMIO         \
+       helpers, we store some rarely used information in the CPU        \
+       context) */                                                      \
+    unsigned long mem_io_pc; /* host pc at which the memory was         \
+                                accessed */                             \
+    target_ulong mem_io_vaddr; /* target virtual addr at which the      \
+                                     memory was accessed */             \
+    uint32_t halted; /* Nonzero if the CPU is in suspend state */       \
+    uint32_t interrupt_request;                                         \
+    volatile sig_atomic_t exit_request;                                 \
+    CPU_COMMON_TLB                                                      \
+    struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];           \
+    /* buffer for temporaries in the code generator */                  \
+    long temp_buf[CPU_TEMP_BUF_NLONGS];                                 \
+                                                                        \
+    int64_t icount_extra; /* Instructions until next timer event.  */   \
+    /* Number of cycles left, with interrupt flag in high bit.          \
+       This allows a single read-compare-cbranch-write sequence to test \
+       for both decrementer underflow and exceptions.  */               \
+    union {                                                             \
+        uint32_t u32;                                                   \
+        icount_decr_u16 u16;                                            \
+    } icount_decr;                                                      \
+    uint32_t can_do_io; /* nonzero if memory mapped IO is safe.  */     \
+                                                                        \
+    /* from this point: preserved by CPU reset */                       \
+    /* ice debug support */                                             \
+    QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints;            \
+    int singlestep_enabled;                                             \
+                                                                        \
+    QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints;            \
+    CPUWatchpoint *watchpoint_hit;                                      \
+                                                                        \
+    struct GDBRegisterState *gdb_regs;                                  \
+                                                                        \
+    /* Core interrupt code */                                           \
+    jmp_buf jmp_env;                                                    \
+    int exception_index;                                                \
+                                                                        \
+    CPUState *next_cpu; /* next CPU sharing TB cache */                 \
+    int cpu_index; /* CPU index (informative) */                        \
+    uint32_t host_tid; /* host thread ID */                             \
+    int numa_node; /* NUMA node this cpu is belonging to  */            \
+    int nr_cores;  /* number of cores within this CPU package */        \
+    int nr_threads;/* number of threads within this CPU */              \
+    int running; /* Nonzero if cpu is currently running(usermode).  */  \
+    int thread_id;                                                      \
+    /* user data */                                                     \
+    void *opaque;                                                       \
+                                                                        \
+    uint32_t created;                                                   \
+    uint32_t stop;   /* Stop request */                                 \
+    uint32_t stopped; /* Artificially stopped */                        \
+    struct QemuThread *thread;                                          \
+    struct QemuCond *halt_cond;                                         \
+    int thread_kicked;                                                  \
+    struct qemu_work_item *queued_work_first, *queued_work_last;        \
+    const char *cpu_model_str;                                          \
+    struct KVMState *kvm_state;                                         \
+    struct kvm_run *kvm_run;                                            \
+    int kvm_fd;                                                         \
+    int kvm_vcpu_dirty;
+
+#endif
diff --git a/qemu-0.15.x/cpu-exec.c b/qemu-0.15.x/cpu-exec.c
new file mode 100644
index 0000000..de0d716
--- /dev/null
+++ b/qemu-0.15.x/cpu-exec.c
@@ -0,0 +1,627 @@
+/*
+ *  i386 emulator main execution loop
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "cpu.h"
+#include "disas.h"
+#include "tcg.h"
+#include "qemu-barrier.h"
+
+int tb_invalidated_flag;
+
+//#define CONFIG_DEBUG_EXEC
+
+bool qemu_cpu_has_work(CPUState *env)
+{
+    return cpu_has_work(env);
+}
+
+void cpu_loop_exit(CPUState *env)
+{
+    env->current_tb = NULL;
+    longjmp(env->jmp_env, 1);
+}
+
+/* exit the current TB from a signal handler. The host registers are
+   restored in a state compatible with the CPU emulator
+ */
+#if defined(CONFIG_SOFTMMU)
+void cpu_resume_from_signal(CPUState *env, void *puc)
+{
+    /* XXX: restore cpu registers saved in host registers */
+
+    env->exception_index = -1;
+    longjmp(env->jmp_env, 1);
+}
+#endif
+
+/* Execute the code without caching the generated code. An interpreter
+   could be used if available. */
+static void cpu_exec_nocache(CPUState *env, int max_cycles,
+                             TranslationBlock *orig_tb)
+{
+    unsigned long next_tb;
+    TranslationBlock *tb;
+
+    /* Should never happen.
+       We only end up here when an existing TB is too long.  */
+    if (max_cycles > CF_COUNT_MASK)
+        max_cycles = CF_COUNT_MASK;
+
+    tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
+                     max_cycles);
+    env->current_tb = tb;
+    /* execute the generated code */
+    next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
+    env->current_tb = NULL;
+
+    if ((next_tb & 3) == 2) {
+        /* Restore PC.  This may happen if async event occurs before
+           the TB starts executing.  */
+        cpu_pc_from_tb(env, tb);
+    }
+    tb_phys_invalidate(tb, -1);
+    tb_free(tb);
+}
+
+static TranslationBlock *tb_find_slow(CPUState *env,
+                                      target_ulong pc,
+                                      target_ulong cs_base,
+                                      uint64_t flags)
+{
+    TranslationBlock *tb, **ptb1;
+    unsigned int h;
+    tb_page_addr_t phys_pc, phys_page1, phys_page2;
+    target_ulong virt_page2;
+
+    tb_invalidated_flag = 0;
+
+    /* find translated block using physical mappings */
+    phys_pc = get_page_addr_code(env, pc);
+    phys_page1 = phys_pc & TARGET_PAGE_MASK;
+    phys_page2 = -1;
+    h = tb_phys_hash_func(phys_pc);
+    ptb1 = &tb_phys_hash[h];
+    for(;;) {
+        tb = *ptb1;
+        if (!tb)
+            goto not_found;
+        if (tb->pc == pc &&
+            tb->page_addr[0] == phys_page1 &&
+            tb->cs_base == cs_base &&
+            tb->flags == flags) {
+            /* check next page if needed */
+            if (tb->page_addr[1] != -1) {
+                virt_page2 = (pc & TARGET_PAGE_MASK) +
+                    TARGET_PAGE_SIZE;
+                phys_page2 = get_page_addr_code(env, virt_page2);
+                if (tb->page_addr[1] == phys_page2)
+                    goto found;
+            } else {
+                goto found;
+            }
+        }
+        ptb1 = &tb->phys_hash_next;
+    }
+ not_found:
+   /* if no translated code available, then translate it now */
+    tb = tb_gen_code(env, pc, cs_base, flags, 0);
+
+ found:
+    /* Move the last found TB to the head of the list */
+    if (likely(*ptb1)) {
+        *ptb1 = tb->phys_hash_next;
+        tb->phys_hash_next = tb_phys_hash[h];
+        tb_phys_hash[h] = tb;
+    }
+    /* we add the TB in the virtual pc hash table */
+    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
+    return tb;
+}
+
+static inline TranslationBlock *tb_find_fast(CPUState *env)
+{
+    TranslationBlock *tb;
+    target_ulong cs_base, pc;
+    int flags;
+
+    /* we record a subset of the CPU state. It will
+       always be the same before a given translated block
+       is executed. */
+    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
+                 tb->flags != flags)) {
+        tb = tb_find_slow(env, pc, cs_base, flags);
+    }
+    return tb;
+}
+
+static CPUDebugExcpHandler *debug_excp_handler;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    CPUDebugExcpHandler *old_handler = debug_excp_handler;
+
+    debug_excp_handler = handler;
+    return old_handler;
+}
+
+static void cpu_handle_debug_exception(CPUState *env)
+{
+    CPUWatchpoint *wp;
+
+    if (!env->watchpoint_hit) {
+        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+            wp->flags &= ~BP_WATCHPOINT_HIT;
+        }
+    }
+    if (debug_excp_handler) {
+        debug_excp_handler(env);
+    }
+}
+
+/* main execution loop */
+
+volatile sig_atomic_t exit_request;
+
+int cpu_exec(CPUState *env)
+{
+    int ret, interrupt_request;
+    TranslationBlock *tb;
+    uint8_t *tc_ptr;
+    unsigned long next_tb;
+
+    if (env->halted) {
+        if (!cpu_has_work(env)) {
+            return EXCP_HALTED;
+        }
+
+        env->halted = 0;
+    }
+
+    cpu_single_env = env;
+
+    if (unlikely(exit_request)) {
+        env->exit_request = 1;
+    }
+
+#if defined(TARGET_I386)
+    /* put eflags in CPU temporary format */
+    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+    DF = 1 - (2 * ((env->eflags >> 10) & 1));
+    CC_OP = CC_OP_EFLAGS;
+    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+#elif defined(TARGET_SPARC)
+#elif defined(TARGET_M68K)
+    env->cc_op = CC_OP_FLAGS;
+    env->cc_dest = env->sr & 0xf;
+    env->cc_x = (env->sr >> 4) & 1;
+#elif defined(TARGET_ALPHA)
+#elif defined(TARGET_ARM)
+#elif defined(TARGET_UNICORE32)
+#elif defined(TARGET_PPC)
+#elif defined(TARGET_LM32)
+#elif defined(TARGET_MICROBLAZE)
+#elif defined(TARGET_MIPS)
+#elif defined(TARGET_SH4)
+#elif defined(TARGET_CRIS)
+#elif defined(TARGET_S390X)
+    /* XXXXX */
+#else
+#error unsupported target CPU
+#endif
+    env->exception_index = -1;
+
+    /* prepare setjmp context for exception handling */
+    for(;;) {
+        if (setjmp(env->jmp_env) == 0) {
+            /* if an exception is pending, we execute it here */
+            if (env->exception_index >= 0) {
+                if (env->exception_index >= EXCP_INTERRUPT) {
+                    /* exit request from the cpu execution loop */
+                    ret = env->exception_index;
+                    if (ret == EXCP_DEBUG) {
+                        cpu_handle_debug_exception(env);
+                    }
+                    break;
+                } else {
+#if defined(CONFIG_USER_ONLY)
+                    /* if user mode only, we simulate a fake exception
+                       which will be handled outside the cpu execution
+                       loop */
+#if defined(TARGET_I386)
+                    do_interrupt(env);
+#endif
+                    ret = env->exception_index;
+                    break;
+#else
+                    do_interrupt(env);
+                    env->exception_index = -1;
+#endif
+                }
+            }
+
+            next_tb = 0; /* force lookup of first TB */
+            for(;;) {
+                interrupt_request = env->interrupt_request;
+                if (unlikely(interrupt_request)) {
+                    if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
+                        /* Mask out external interrupts for this step. */
+                        interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
+                    }
+                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
+                        env->exception_index = EXCP_DEBUG;
+                        cpu_loop_exit(env);
+                    }
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
+    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
+    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
+                    if (interrupt_request & CPU_INTERRUPT_HALT) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+                        env->halted = 1;
+                        env->exception_index = EXCP_HLT;
+                        cpu_loop_exit(env);
+                    }
+#endif
+#if defined(TARGET_I386)
+                    if (interrupt_request & CPU_INTERRUPT_INIT) {
+                            svm_check_intercept(env, SVM_EXIT_INIT);
+                            do_cpu_init(env);
+                            env->exception_index = EXCP_HALTED;
+                            cpu_loop_exit(env);
+                    } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
+                            do_cpu_sipi(env);
+                    } else if (env->hflags2 & HF2_GIF_MASK) {
+                        if ((interrupt_request & CPU_INTERRUPT_SMI) &&
+                            !(env->hflags & HF_SMM_MASK)) {
+                            svm_check_intercept(env, SVM_EXIT_SMI);
+                            env->interrupt_request &= ~CPU_INTERRUPT_SMI;
+                            do_smm_enter(env);
+                            next_tb = 0;
+                        } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
+                                   !(env->hflags2 & HF2_NMI_MASK)) {
+                            env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+                            env->hflags2 |= HF2_NMI_MASK;
+                            do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
+                            next_tb = 0;
+			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
+                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+                            do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
+                            next_tb = 0;
+                        } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                                   (((env->hflags2 & HF2_VINTR_MASK) && 
+                                     (env->hflags2 & HF2_HIF_MASK)) ||
+                                    (!(env->hflags2 & HF2_VINTR_MASK) && 
+                                     (env->eflags & IF_MASK && 
+                                      !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
+                            int intno;
+                            svm_check_intercept(env, SVM_EXIT_INTR);
+                            env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
+                            intno = cpu_get_pic_interrupt(env);
+                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
+                            do_interrupt_x86_hardirq(env, intno, 1);
+                            /* ensure that no TB jump will be modified as
+                               the program flow was changed */
+                            next_tb = 0;
+#if !defined(CONFIG_USER_ONLY)
+                        } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
+                                   (env->eflags & IF_MASK) && 
+                                   !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
+                            int intno;
+                            /* FIXME: this should respect TPR */
+                            svm_check_intercept(env, SVM_EXIT_VINTR);
+                            intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
+                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
+                            do_interrupt_x86_hardirq(env, intno, 1);
+                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+                            next_tb = 0;
+#endif
+                        }
+                    }
+#elif defined(TARGET_PPC)
+#if 0
+                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
+                        cpu_reset(env);
+                    }
+#endif
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        ppc_hw_interrupt(env);
+                        if (env->pending_interrupts == 0)
+                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_LM32)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->ie & IE_IE)) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_MICROBLAZE)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->sregs[SR_MSR] & MSR_IE)
+                        && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
+                        && !(env->iflags & (D_FLAG | IMM_FLAG))) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_MIPS)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                        cpu_mips_hw_interrupts_pending(env)) {
+                        /* Raise it */
+                        env->exception_index = EXCP_EXT_INTERRUPT;
+                        env->error_code = 0;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_SPARC)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        if (cpu_interrupts_enabled(env) &&
+                            env->interrupt_index > 0) {
+                            int pil = env->interrupt_index & 0xf;
+                            int type = env->interrupt_index & 0xf0;
+
+                            if (((type == TT_EXTINT) &&
+                                  cpu_pil_allowed(env, pil)) ||
+                                  type != TT_EXTINT) {
+                                env->exception_index = env->interrupt_index;
+                                do_interrupt(env);
+                                next_tb = 0;
+                            }
+                        }
+		    }
+#elif defined(TARGET_ARM)
+                    if (interrupt_request & CPU_INTERRUPT_FIQ
+                        && !(env->uncached_cpsr & CPSR_F)) {
+                        env->exception_index = EXCP_FIQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+                    /* ARMv7-M interrupt return works by loading a magic value
+                       into the PC.  On real hardware the load causes the
+                       return to occur.  The qemu implementation performs the
+                       jump normally, then does the exception return when the
+                       CPU tries to execute code at the magic address.
+                       This will cause the magic PC value to be pushed to
+                       the stack if an interrupt occurred at the wrong time.
+                       We avoid this by disabling interrupts when
+                       pc contains a magic address.  */
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
+                            || !(env->uncached_cpsr & CPSR_I))) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_UNICORE32)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && !(env->uncached_asr & ASR_I)) {
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_SH4)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_ALPHA)
+                    {
+                        int idx = -1;
+                        /* ??? This hard-codes the OSF/1 interrupt levels.  */
+		        switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
+                        case 0 ... 3:
+                            if (interrupt_request & CPU_INTERRUPT_HARD) {
+                                idx = EXCP_DEV_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 4:
+                            if (interrupt_request & CPU_INTERRUPT_TIMER) {
+                                idx = EXCP_CLK_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 5:
+                            if (interrupt_request & CPU_INTERRUPT_SMP) {
+                                idx = EXCP_SMP_INTERRUPT;
+                            }
+                            /* FALLTHRU */
+                        case 6:
+                            if (interrupt_request & CPU_INTERRUPT_MCHK) {
+                                idx = EXCP_MCHK;
+                            }
+                        }
+                        if (idx >= 0) {
+                            env->exception_index = idx;
+                            env->error_code = 0;
+                            do_interrupt(env);
+                            next_tb = 0;
+                        }
+                    }
+#elif defined(TARGET_CRIS)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && (env->pregs[PR_CCS] & I_FLAG)
+                        && !env->locked_irq) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+                    if (interrupt_request & CPU_INTERRUPT_NMI
+                        && (env->pregs[PR_CCS] & M_FLAG)) {
+                        env->exception_index = EXCP_NMI;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_M68K)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && ((env->sr & SR_I) >> SR_I_SHIFT)
+                            < env->pending_level) {
+                        /* Real hardware gets the interrupt vector via an
+                           IACK cycle at this point.  Current emulated
+                           hardware doesn't rely on this, so we
+                           provide/save the vector when the interrupt is
+                           first signalled.  */
+                        env->exception_index = env->pending_vector;
+                        do_interrupt_m68k_hardirq(env);
+                        next_tb = 0;
+                    }
+#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                        (env->psw.mask & PSW_MASK_EXT)) {
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
+#endif
+                   /* Don't use the cached interrupt_request value,
+                      do_interrupt may have updated the EXITTB flag. */
+                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
+                        /* ensure that no TB jump will be modified as
+                           the program flow was changed */
+                        next_tb = 0;
+                    }
+                }
+                if (unlikely(env->exit_request)) {
+                    env->exit_request = 0;
+                    env->exception_index = EXCP_INTERRUPT;
+                    cpu_loop_exit(env);
+                }
+#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
+                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
+                    /* restore flags in standard format */
+#if defined(TARGET_I386)
+                    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
+                        | (DF & DF_MASK);
+                    log_cpu_state(env, X86_DUMP_CCOP);
+                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+#elif defined(TARGET_M68K)
+                    cpu_m68k_flush_flags(env, env->cc_op);
+                    env->cc_op = CC_OP_FLAGS;
+                    env->sr = (env->sr & 0xffe0)
+                              | env->cc_dest | (env->cc_x << 4);
+                    log_cpu_state(env, 0);
+#else
+                    log_cpu_state(env, 0);
+#endif
+                }
+#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
+                spin_lock(&tb_lock);
+                tb = tb_find_fast(env);
+                /* Note: we do it here to avoid a gcc bug on Mac OS X when
+                   doing it in tb_find_slow */
+                if (tb_invalidated_flag) {
+                    /* as some TB could have been invalidated because
+                       of memory exceptions while generating the code, we
+                       must recompute the hash index here */
+                    next_tb = 0;
+                    tb_invalidated_flag = 0;
+                }
+#ifdef CONFIG_DEBUG_EXEC
+                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
+                             (long)tb->tc_ptr, tb->pc,
+                             lookup_symbol(tb->pc));
+#endif
+                /* see if we can patch the calling TB. When the TB
+                   spans two pages, we cannot safely do a direct
+                   jump. */
+                if (next_tb != 0 && tb->page_addr[1] == -1) {
+                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
+                }
+                spin_unlock(&tb_lock);
+
+                /* cpu_interrupt might be called while translating the
+                   TB, but before it is linked into a potentially
+                   infinite loop and becomes env->current_tb. Avoid
+                   starting execution if there is a pending interrupt. */
+                env->current_tb = tb;
+                barrier();
+                if (likely(!env->exit_request)) {
+                    tc_ptr = tb->tc_ptr;
+                /* execute the generated code */
+                    next_tb = tcg_qemu_tb_exec(env, tc_ptr);
+                    if ((next_tb & 3) == 2) {
+                        /* Instruction counter expired.  */
+                        int insns_left;
+                        tb = (TranslationBlock *)(long)(next_tb & ~3);
+                        /* Restore PC.  */
+                        cpu_pc_from_tb(env, tb);
+                        insns_left = env->icount_decr.u32;
+                        if (env->icount_extra && insns_left >= 0) {
+                            /* Refill decrementer and continue execution.  */
+                            env->icount_extra += insns_left;
+                            if (env->icount_extra > 0xffff) {
+                                insns_left = 0xffff;
+                            } else {
+                                insns_left = env->icount_extra;
+                            }
+                            env->icount_extra -= insns_left;
+                            env->icount_decr.u16.low = insns_left;
+                        } else {
+                            if (insns_left > 0) {
+                                /* Execute remaining instructions.  */
+                                cpu_exec_nocache(env, insns_left, tb);
+                            }
+                            env->exception_index = EXCP_INTERRUPT;
+                            next_tb = 0;
+                            cpu_loop_exit(env);
+                        }
+                    }
+                }
+                env->current_tb = NULL;
+                /* reset soft MMU for next block (it can currently
+                   only be set by a memory fault) */
+            } /* for(;;) */
+        } else {
+            /* Reload env after longjmp - the compiler may have smashed all
+             * local variables as longjmp is marked 'noreturn'. */
+            env = cpu_single_env;
+        }
+    } /* for(;;) */
+
+
+#if defined(TARGET_I386)
+    /* restore flags in standard format */
+    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
+        | (DF & DF_MASK);
+#elif defined(TARGET_ARM)
+    /* XXX: Save/restore host fpu exception state?.  */
+#elif defined(TARGET_UNICORE32)
+#elif defined(TARGET_SPARC)
+#elif defined(TARGET_PPC)
+#elif defined(TARGET_LM32)
+#elif defined(TARGET_M68K)
+    cpu_m68k_flush_flags(env, env->cc_op);
+    env->cc_op = CC_OP_FLAGS;
+    env->sr = (env->sr & 0xffe0)
+              | env->cc_dest | (env->cc_x << 4);
+#elif defined(TARGET_MICROBLAZE)
+#elif defined(TARGET_MIPS)
+#elif defined(TARGET_SH4)
+#elif defined(TARGET_ALPHA)
+#elif defined(TARGET_CRIS)
+#elif defined(TARGET_S390X)
+    /* XXXXX */
+#else
+#error unsupported target CPU
+#endif
+
+    /* fail safe : never use cpu_single_env outside cpu_exec() */
+    cpu_single_env = NULL;
+    return ret;
+}
diff --git a/qemu-0.15.x/cpus.c b/qemu-0.15.x/cpus.c
new file mode 100644
index 0000000..6bf4e3f
--- /dev/null
+++ b/qemu-0.15.x/cpus.c
@@ -0,0 +1,1178 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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.
+ */
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+
+#include "monitor.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "dma.h"
+#include "kvm.h"
+
+#include "qemu-thread.h"
+#include "cpus.h"
+
+#ifndef _WIN32
+#include "compatfd.h"
+#endif
+
+#ifdef SIGRTMIN
+#define SIG_IPI (SIGRTMIN+4)
+#else
+#define SIG_IPI SIGUSR1
+#endif
+
+#ifdef CONFIG_LINUX
+
+#include <sys/prctl.h>
+
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
+#endif
+
+#ifndef PR_MCE_KILL_SET
+#define PR_MCE_KILL_SET 1
+#endif
+
+#ifndef PR_MCE_KILL_EARLY
+#define PR_MCE_KILL_EARLY 1
+#endif
+
+#endif /* CONFIG_LINUX */
+
+static CPUState *next_cpu;
+
+/***********************************************************/
+void hw_error(const char *fmt, ...)
+{
+    va_list ap;
+    CPUState *env;
+
+    va_start(ap, fmt);
+    fprintf(stderr, "qemu: hardware error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        fprintf(stderr, "CPU #%d:\n", env->cpu_index);
+#ifdef TARGET_I386
+        cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
+#else
+        cpu_dump_state(env, stderr, fprintf, 0);
+#endif
+    }
+    va_end(ap);
+    abort();
+}
+
+void cpu_synchronize_all_states(void)
+{
+    CPUState *cpu;
+
+    for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+        cpu_synchronize_state(cpu);
+    }
+}
+
+void cpu_synchronize_all_post_reset(void)
+{
+    CPUState *cpu;
+
+    for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+        cpu_synchronize_post_reset(cpu);
+    }
+}
+
+void cpu_synchronize_all_post_init(void)
+{
+    CPUState *cpu;
+
+    for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+        cpu_synchronize_post_init(cpu);
+    }
+}
+
+int cpu_is_stopped(CPUState *env)
+{
+    return !vm_running || env->stopped;
+}
+
+static void do_vm_stop(int reason)
+{
+    if (vm_running) {
+        cpu_disable_ticks();
+        vm_running = 0;
+        pause_all_vcpus();
+        vm_state_notify(0, reason);
+        qemu_aio_flush();
+        bdrv_flush_all();
+        monitor_protocol_event(QEVENT_STOP, NULL);
+    }
+}
+
+static int cpu_can_run(CPUState *env)
+{
+    if (env->stop) {
+        return 0;
+    }
+    if (env->stopped || !vm_running) {
+        return 0;
+    }
+    return 1;
+}
+
+static bool cpu_thread_is_idle(CPUState *env)
+{
+    if (env->stop || env->queued_work_first) {
+        return false;
+    }
+    if (env->stopped || !vm_running) {
+        return true;
+    }
+    if (!env->halted || qemu_cpu_has_work(env) ||
+        (kvm_enabled() && kvm_irqchip_in_kernel())) {
+        return false;
+    }
+    return true;
+}
+
+bool all_cpu_threads_idle(void)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (!cpu_thread_is_idle(env)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static void cpu_handle_guest_debug(CPUState *env)
+{
+    gdb_set_stop_cpu(env);
+    qemu_system_debug_request();
+#ifdef CONFIG_IOTHREAD
+    env->stopped = 1;
+#endif
+}
+
+#ifdef CONFIG_IOTHREAD
+static void cpu_signal(int sig)
+{
+    if (cpu_single_env) {
+        cpu_exit(cpu_single_env);
+    }
+    exit_request = 1;
+}
+#endif
+
+#ifdef CONFIG_LINUX
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS, &action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();
+}
+
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
+{
+    if (kvm_on_sigbus(siginfo->ssi_code,
+                      (void *)(intptr_t)siginfo->ssi_addr)) {
+        sigbus_reraise();
+    }
+}
+
+static void qemu_init_sigbus(void)
+{
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS, &action, NULL);
+
+    prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
+}
+
+static void qemu_kvm_eat_signals(CPUState *env)
+{
+    struct timespec ts = { 0, 0 };
+    siginfo_t siginfo;
+    sigset_t waitset;
+    sigset_t chkset;
+    int r;
+
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
+
+    do {
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
+            perror("sigtimedwait");
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
+                sigbus_reraise();
+            }
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            perror("sigpending");
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
+
+#ifndef CONFIG_IOTHREAD
+    if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) {
+        qemu_notify_event();
+    }
+#endif
+}
+
+#else /* !CONFIG_LINUX */
+
+static void qemu_init_sigbus(void)
+{
+}
+
+static void qemu_kvm_eat_signals(CPUState *env)
+{
+}
+#endif /* !CONFIG_LINUX */
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+static void qemu_event_increment(void)
+{
+    /* Write 8 bytes to be compatible with eventfd.  */
+    static const uint64_t val = 1;
+    ssize_t ret;
+
+    if (io_thread_fd == -1) {
+        return;
+    }
+    do {
+        ret = write(io_thread_fd, &val, sizeof(val));
+    } while (ret < 0 && errno == EINTR);
+
+    /* EAGAIN is fine, a read must be pending.  */
+    if (ret < 0 && errno != EAGAIN) {
+        fprintf(stderr, "qemu_event_increment: write() failed: %s\n",
+                strerror(errno));
+        exit (1);
+    }
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    ssize_t len;
+    char buffer[512];
+
+    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
+    do {
+        len = read(fd, buffer, sizeof(buffer));
+    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+}
+
+static int qemu_event_init(void)
+{
+    int err;
+    int fds[2];
+
+    err = qemu_eventfd(fds);
+    if (err == -1) {
+        return -errno;
+    }
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0) {
+        goto fail;
+    }
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(intptr_t)fds[0]);
+
+    io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+
+static void dummy_signal(int sig)
+{
+}
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+    int fd = (intptr_t)opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN) {
+            break;
+        }
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+        } else if (action.sa_handler) {
+            action.sa_handler(info.ssi_signo);
+        }
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    int sigfd;
+    sigset_t set;
+
+#ifdef CONFIG_IOTHREAD
+    /* SIGUSR2 used by posix-aio-compat.c */
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+    /*
+     * SIG_IPI must be blocked in the main thread and must not be caught
+     * by sigwait() in the signal thread. Otherwise, the cpu thread will
+     * not catch it reliably.
+     */
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    sigaddset(&set, SIGBUS);
+#else
+    sigemptyset(&set);
+    sigaddset(&set, SIGBUS);
+    if (kvm_enabled()) {
+        /*
+         * We need to process timer signals synchronously to avoid a race
+         * between exit_request check and KVM vcpu entry.
+         */
+        sigaddset(&set, SIGIO);
+        sigaddset(&set, SIGALRM);
+    }
+#endif
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigfd = qemu_signalfd(&set);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl_setfl(sigfd, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(intptr_t)sigfd);
+
+    return 0;
+}
+
+static void qemu_kvm_init_cpu_signals(CPUState *env)
+{
+    int r;
+    sigset_t set;
+    struct sigaction sigact;
+
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = dummy_signal;
+    sigaction(SIG_IPI, &sigact, NULL);
+
+#ifdef CONFIG_IOTHREAD
+    pthread_sigmask(SIG_BLOCK, NULL, &set);
+    sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
+    r = kvm_set_signal_mask(env, &set);
+    if (r) {
+        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
+        exit(1);
+    }
+#else
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    pthread_sigmask(SIG_BLOCK, NULL, &set);
+    sigdelset(&set, SIGIO);
+    sigdelset(&set, SIGALRM);
+#endif
+    sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
+    r = kvm_set_signal_mask(env, &set);
+    if (r) {
+        fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
+        exit(1);
+    }
+}
+
+static void qemu_tcg_init_cpu_signals(void)
+{
+#ifdef CONFIG_IOTHREAD
+    sigset_t set;
+    struct sigaction sigact;
+
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = cpu_signal;
+    sigaction(SIG_IPI, &sigact, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIG_IPI);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+#endif
+}
+
+#else /* _WIN32 */
+
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+        return -1;
+    }
+    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+static void qemu_event_increment(void)
+{
+    if (!SetEvent(qemu_event_handle)) {
+        fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
+                GetLastError());
+        exit (1);
+    }
+}
+
+static int qemu_signal_init(void)
+{
+    return 0;
+}
+
+static void qemu_kvm_init_cpu_signals(CPUState *env)
+{
+    abort();
+}
+
+static void qemu_tcg_init_cpu_signals(void)
+{
+}
+#endif /* _WIN32 */
+
+#ifndef CONFIG_IOTHREAD
+int qemu_init_main_loop(void)
+{
+    int ret;
+
+    ret = qemu_signal_init();
+    if (ret) {
+        return ret;
+    }
+
+    qemu_init_sigbus();
+
+    return qemu_event_init();
+}
+
+void qemu_main_loop_start(void)
+{
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+    int r;
+
+    env->nr_cores = smp_cores;
+    env->nr_threads = smp_threads;
+
+    if (kvm_enabled()) {
+        r = kvm_init_vcpu(env);
+        if (r < 0) {
+            fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
+            exit(1);
+        }
+        qemu_kvm_init_cpu_signals(env);
+    } else {
+        qemu_tcg_init_cpu_signals();
+    }
+}
+
+int qemu_cpu_is_self(void *env)
+{
+    return 1;
+}
+
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
+{
+    func(data);
+}
+
+void resume_all_vcpus(void)
+{
+}
+
+void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+}
+
+void qemu_cpu_kick_self(void)
+{
+#ifndef _WIN32
+    assert(cpu_single_env);
+
+    raise(SIG_IPI);
+#else
+    abort();
+#endif
+}
+
+void qemu_notify_event(void)
+{
+    CPUState *env = cpu_single_env;
+
+    qemu_event_increment ();
+    if (env) {
+        cpu_exit(env);
+    }
+    if (next_cpu && env != next_cpu) {
+        cpu_exit(next_cpu);
+    }
+    exit_request = 1;
+}
+
+void qemu_mutex_lock_iothread(void) {}
+void qemu_mutex_unlock_iothread(void) {}
+
+void cpu_stop_current(void)
+{
+}
+
+void vm_stop(int reason)
+{
+    do_vm_stop(reason);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+QemuMutex qemu_global_mutex;
+static QemuCond qemu_io_proceeded_cond;
+static bool iothread_requesting_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+static QemuCond qemu_work_cond;
+
+int qemu_init_main_loop(void)
+{
+    int ret;
+
+    qemu_init_sigbus();
+
+    ret = qemu_signal_init();
+    if (ret) {
+        return ret;
+    }
+
+    /* Note eventfd must be drained before signalfd handlers run */
+    ret = qemu_event_init();
+    if (ret) {
+        return ret;
+    }
+
+    qemu_cond_init(&qemu_cpu_cond);
+    qemu_cond_init(&qemu_system_cond);
+    qemu_cond_init(&qemu_pause_cond);
+    qemu_cond_init(&qemu_work_cond);
+    qemu_cond_init(&qemu_io_proceeded_cond);
+    qemu_mutex_init(&qemu_global_mutex);
+    qemu_mutex_lock(&qemu_global_mutex);
+
+    qemu_thread_get_self(&io_thread);
+
+    return 0;
+}
+
+void qemu_main_loop_start(void)
+{
+    qemu_system_ready = 1;
+    qemu_cond_broadcast(&qemu_system_cond);
+}
+
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
+{
+    struct qemu_work_item wi;
+
+    if (qemu_cpu_is_self(env)) {
+        func(data);
+        return;
+    }
+
+    wi.func = func;
+    wi.data = data;
+    if (!env->queued_work_first) {
+        env->queued_work_first = &wi;
+    } else {
+        env->queued_work_last->next = &wi;
+    }
+    env->queued_work_last = &wi;
+    wi.next = NULL;
+    wi.done = false;
+
+    qemu_cpu_kick(env);
+    while (!wi.done) {
+        CPUState *self_env = cpu_single_env;
+
+        qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
+        cpu_single_env = self_env;
+    }
+}
+
+static void flush_queued_work(CPUState *env)
+{
+    struct qemu_work_item *wi;
+
+    if (!env->queued_work_first) {
+        return;
+    }
+
+    while ((wi = env->queued_work_first)) {
+        env->queued_work_first = wi->next;
+        wi->func(wi->data);
+        wi->done = true;
+    }
+    env->queued_work_last = NULL;
+    qemu_cond_broadcast(&qemu_work_cond);
+}
+
+static void qemu_wait_io_event_common(CPUState *env)
+{
+    if (env->stop) {
+        env->stop = 0;
+        env->stopped = 1;
+        qemu_cond_signal(&qemu_pause_cond);
+    }
+    flush_queued_work(env);
+    env->thread_kicked = false;
+}
+
+static void qemu_tcg_wait_io_event(void)
+{
+    CPUState *env;
+
+    while (all_cpu_threads_idle()) {
+       /* Start accounting real time to the virtual clock if the CPUs
+          are idle.  */
+        qemu_clock_warp(vm_clock);
+        qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
+    }
+
+    while (iothread_requesting_mutex) {
+        qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        qemu_wait_io_event_common(env);
+    }
+}
+
+static void qemu_kvm_wait_io_event(CPUState *env)
+{
+    while (cpu_thread_is_idle(env)) {
+        qemu_cond_wait(env->halt_cond, &qemu_global_mutex);
+    }
+
+    qemu_kvm_eat_signals(env);
+    qemu_wait_io_event_common(env);
+}
+
+static void *qemu_kvm_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+    int r;
+
+    qemu_mutex_lock(&qemu_global_mutex);
+    qemu_thread_get_self(env->thread);
+    env->thread_id = qemu_get_thread_id();
+
+    r = kvm_init_vcpu(env);
+    if (r < 0) {
+        fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r));
+        exit(1);
+    }
+
+    qemu_kvm_init_cpu_signals(env);
+
+    /* signal CPU creation */
+    env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready) {
+        qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex);
+    }
+
+    while (1) {
+        if (cpu_can_run(env)) {
+            r = kvm_cpu_exec(env);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(env);
+            }
+        }
+        qemu_kvm_wait_io_event(env);
+    }
+
+    return NULL;
+}
+
+static void *qemu_tcg_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+
+    qemu_tcg_init_cpu_signals();
+    qemu_thread_get_self(env->thread);
+
+    /* signal CPU creation */
+    qemu_mutex_lock(&qemu_global_mutex);
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->thread_id = qemu_get_thread_id();
+        env->created = 1;
+    }
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready) {
+        qemu_cond_wait(&qemu_system_cond, &qemu_global_mutex);
+    }
+
+    while (1) {
+        cpu_exec_all();
+        if (use_icount && qemu_next_icount_deadline() <= 0) {
+            qemu_notify_event();
+        }
+        qemu_tcg_wait_io_event();
+    }
+
+    return NULL;
+}
+
+static void qemu_cpu_kick_thread(CPUState *env)
+{
+#ifndef _WIN32
+    int err;
+
+    err = pthread_kill(env->thread->thread, SIG_IPI);
+    if (err) {
+        fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
+        exit(1);
+    }
+#else /* _WIN32 */
+    if (!qemu_cpu_is_self(env)) {
+        SuspendThread(env->thread->thread);
+        cpu_signal(0);
+        ResumeThread(env->thread->thread);
+    }
+#endif
+}
+
+void qemu_cpu_kick(void *_env)
+{
+    CPUState *env = _env;
+
+    qemu_cond_broadcast(env->halt_cond);
+    if (!env->thread_kicked) {
+        qemu_cpu_kick_thread(env);
+        env->thread_kicked = true;
+    }
+}
+
+void qemu_cpu_kick_self(void)
+{
+#ifndef _WIN32
+    assert(cpu_single_env);
+
+    if (!cpu_single_env->thread_kicked) {
+        qemu_cpu_kick_thread(cpu_single_env);
+        cpu_single_env->thread_kicked = true;
+    }
+#else
+    abort();
+#endif
+}
+
+int qemu_cpu_is_self(void *_env)
+{
+    CPUState *env = _env;
+
+    return qemu_thread_is_self(env->thread);
+}
+
+void qemu_mutex_lock_iothread(void)
+{
+    if (kvm_enabled()) {
+        qemu_mutex_lock(&qemu_global_mutex);
+    } else {
+        iothread_requesting_mutex = true;
+        if (qemu_mutex_trylock(&qemu_global_mutex)) {
+            qemu_cpu_kick_thread(first_cpu);
+            qemu_mutex_lock(&qemu_global_mutex);
+        }
+        iothread_requesting_mutex = false;
+        qemu_cond_broadcast(&qemu_io_proceeded_cond);
+    }
+}
+
+void qemu_mutex_unlock_iothread(void)
+{
+    qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+static int all_vcpus_paused(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        if (!penv->stopped) {
+            return 0;
+        }
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    return 1;
+}
+
+void pause_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 1;
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    while (!all_vcpus_paused()) {
+        qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
+        penv = first_cpu;
+        while (penv) {
+            qemu_cpu_kick(penv);
+            penv = (CPUState *)penv->next_cpu;
+        }
+    }
+}
+
+void resume_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 0;
+        penv->stopped = 0;
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+}
+
+static void qemu_tcg_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    /* share a single thread for all cpus with TCG */
+    if (!tcg_cpu_thread) {
+        env->thread = qemu_mallocz(sizeof(QemuThread));
+        env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+        qemu_cond_init(env->halt_cond);
+        qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env);
+        while (env->created == 0) {
+            qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+        }
+        tcg_cpu_thread = env->thread;
+        tcg_halt_cond = env->halt_cond;
+    } else {
+        env->thread = tcg_cpu_thread;
+        env->halt_cond = tcg_halt_cond;
+    }
+}
+
+static void qemu_kvm_start_vcpu(CPUState *env)
+{
+    env->thread = qemu_mallocz(sizeof(QemuThread));
+    env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+    qemu_cond_init(env->halt_cond);
+    qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env);
+    while (env->created == 0) {
+        qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+    }
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    env->nr_cores = smp_cores;
+    env->nr_threads = smp_threads;
+    if (kvm_enabled()) {
+        qemu_kvm_start_vcpu(env);
+    } else {
+        qemu_tcg_init_vcpu(env);
+    }
+}
+
+void qemu_notify_event(void)
+{
+    qemu_event_increment();
+}
+
+void cpu_stop_current(void)
+{
+    if (cpu_single_env) {
+        cpu_single_env->stop = 0;
+        cpu_single_env->stopped = 1;
+        cpu_exit(cpu_single_env);
+        qemu_cond_signal(&qemu_pause_cond);
+    }
+}
+
+void vm_stop(int reason)
+{
+    if (!qemu_thread_is_self(&io_thread)) {
+        qemu_system_vmstop_request(reason);
+        /*
+         * FIXME: should not return to device code in case
+         * vm_stop() has been requested.
+         */
+        cpu_stop_current();
+        return;
+    }
+    do_vm_stop(reason);
+}
+
+#endif
+
+static int tcg_cpu_exec(CPUState *env)
+{
+    int ret;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+    ti = profile_getclock();
+#endif
+    if (use_icount) {
+        int64_t count;
+        int decr;
+        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+        env->icount_decr.u16.low = 0;
+        env->icount_extra = 0;
+        count = qemu_icount_round(qemu_next_icount_deadline());
+        qemu_icount += count;
+        decr = (count > 0xffff) ? 0xffff : count;
+        count -= decr;
+        env->icount_decr.u16.low = decr;
+        env->icount_extra = count;
+    }
+    ret = cpu_exec(env);
+#ifdef CONFIG_PROFILER
+    qemu_time += profile_getclock() - ti;
+#endif
+    if (use_icount) {
+        /* Fold pending instructions back into the
+           instruction counter, and clear the interrupt flag.  */
+        qemu_icount -= (env->icount_decr.u16.low
+                        + env->icount_extra);
+        env->icount_decr.u32 = 0;
+        env->icount_extra = 0;
+    }
+    return ret;
+}
+
+bool cpu_exec_all(void)
+{
+    int r;
+
+    /* Account partial waits to the vm_clock.  */
+    qemu_clock_warp(vm_clock);
+
+    if (next_cpu == NULL) {
+        next_cpu = first_cpu;
+    }
+    for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
+        CPUState *env = next_cpu;
+
+        qemu_clock_enable(vm_clock,
+                          (env->singlestep_enabled & SSTEP_NOTIMER) == 0);
+
+#ifndef CONFIG_IOTHREAD
+        if (qemu_alarm_pending()) {
+            break;
+        }
+#endif
+        if (cpu_can_run(env)) {
+            if (kvm_enabled()) {
+                r = kvm_cpu_exec(env);
+                qemu_kvm_eat_signals(env);
+            } else {
+                r = tcg_cpu_exec(env);
+            }
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(env);
+                break;
+            }
+        } else if (env->stop || env->stopped) {
+            break;
+        }
+    }
+    exit_request = 0;
+    return !all_cpu_threads_idle();
+}
+
+void set_numa_modes(void)
+{
+    CPUState *env;
+    int i;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] & (1 << env->cpu_index)) {
+                env->numa_node = i;
+            }
+        }
+    }
+}
+
+void set_cpu_log(const char *optarg)
+{
+    int mask;
+    const CPULogItem *item;
+
+    mask = cpu_str_to_log_mask(optarg);
+    if (!mask) {
+        printf("Log items (comma separated):\n");
+        for (item = cpu_log_items; item->mask != 0; item++) {
+            printf("%-10s %s\n", item->name, item->help);
+        }
+        exit(1);
+    }
+    cpu_set_log(mask);
+}
+
+void set_cpu_log_filename(const char *optarg)
+{
+    cpu_set_log_filename(optarg);
+}
+
+/* Return the virtual CPU time, based on the instruction counter.  */
+int64_t cpu_get_icount(void)
+{
+    int64_t icount;
+    CPUState *env = cpu_single_env;;
+
+    icount = qemu_icount;
+    if (env) {
+        if (!can_do_io(env)) {
+            fprintf(stderr, "Bad clock read\n");
+        }
+        icount -= (env->icount_decr.u16.low + env->icount_extra);
+    }
+    return qemu_icount_bias + (icount << icount_time_shift);
+}
+
+void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
+{
+    /* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list_id)
+    cpu_list_id(f, cpu_fprintf, optarg);
+#elif defined(cpu_list)
+    cpu_list(f, cpu_fprintf); /* deprecated */
+#endif
+}
diff --git a/qemu-0.15.x/cpus.h b/qemu-0.15.x/cpus.h
new file mode 100644
index 0000000..f42b54e
--- /dev/null
+++ b/qemu-0.15.x/cpus.h
@@ -0,0 +1,25 @@
+#ifndef QEMU_CPUS_H
+#define QEMU_CPUS_H
+
+/* cpus.c */
+int qemu_init_main_loop(void);
+void qemu_main_loop_start(void);
+void resume_all_vcpus(void);
+void pause_all_vcpus(void);
+void cpu_stop_current(void);
+
+void cpu_synchronize_all_states(void);
+void cpu_synchronize_all_post_reset(void);
+void cpu_synchronize_all_post_init(void);
+
+/* vl.c */
+extern int smp_cores;
+extern int smp_threads;
+void vm_state_notify(int running, int reason);
+bool cpu_exec_all(void);
+void set_numa_modes(void);
+void set_cpu_log(const char *optarg);
+void set_cpu_log_filename(const char *optarg);
+void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
+
+#endif
diff --git a/qemu-0.15.x/cris-dis.c b/qemu-0.15.x/cris-dis.c
new file mode 100644
index 0000000..5fa67d9
--- /dev/null
+++ b/qemu-0.15.x/cris-dis.c
@@ -0,0 +1,2893 @@
+/* Disassembler code for CRIS.
+   Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Contributed by Axis Communications AB, Lund, Sweden.
+   Written by Hans-Peter Nilsson.
+
+   This file is part of the GNU binutils and GDB, the GNU debugger.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "qemu-common.h"
+#include "dis-asm.h"
+//#include "sysdep.h"
+#include "target-cris/opcode-cris.h"
+//#include "libiberty.h"
+
+#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0)
+
+/* cris-opc.c -- Table of opcodes for the CRIS processor.
+   Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications AB, Lund, Sweden.
+   Originally written for GAS 1.38.1 by Mikael Asker.
+   Reorganized by Hans-Peter Nilsson.
+
+This file is part of GAS, GDB and the GNU binutils.
+
+GAS, GDB, and GNU binutils is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GAS, GDB, and GNU binutils are distributed in the hope that they will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+/* This table isn't used for CRISv32 and the size of immediate operands.  */
+const struct cris_spec_reg
+cris_spec_regs[] =
+{
+  {"bz",  0,  1, cris_ver_v32p,	   NULL},
+  {"p0",  0,  1, 0,		   NULL},
+  {"vr",  1,  1, 0,		   NULL},
+  {"p1",  1,  1, 0,		   NULL},
+  {"pid", 2,  1, cris_ver_v32p,    NULL},
+  {"p2",  2,  1, cris_ver_v32p,	   NULL},
+  {"p2",  2,  1, cris_ver_warning, NULL},
+  {"srs", 3,  1, cris_ver_v32p,    NULL},
+  {"p3",  3,  1, cris_ver_v32p,	   NULL},
+  {"p3",  3,  1, cris_ver_warning, NULL},
+  {"wz",  4,  2, cris_ver_v32p,	   NULL},
+  {"p4",  4,  2, 0,		   NULL},
+  {"ccr", 5,  2, cris_ver_v0_10,   NULL},
+  {"exs", 5,  4, cris_ver_v32p,	   NULL},
+  {"p5",  5,  2, cris_ver_v0_10,   NULL},
+  {"p5",  5,  4, cris_ver_v32p,	   NULL},
+  {"dcr0",6,  2, cris_ver_v0_3,	   NULL},
+  {"eda", 6,  4, cris_ver_v32p,	   NULL},
+  {"p6",  6,  2, cris_ver_v0_3,	   NULL},
+  {"p6",  6,  4, cris_ver_v32p,	   NULL},
+  {"dcr1/mof", 7, 4, cris_ver_v10p,
+   "Register `dcr1/mof' with ambiguous size specified.  Guessing 4 bytes"},
+  {"dcr1/mof", 7, 2, cris_ver_v0_3,
+   "Register `dcr1/mof' with ambiguous size specified.  Guessing 2 bytes"},
+  {"mof", 7,  4, cris_ver_v10p,	   NULL},
+  {"dcr1",7,  2, cris_ver_v0_3,	   NULL},
+  {"p7",  7,  4, cris_ver_v10p,	   NULL},
+  {"p7",  7,  2, cris_ver_v0_3,	   NULL},
+  {"dz",  8,  4, cris_ver_v32p,	   NULL},
+  {"p8",  8,  4, 0,		   NULL},
+  {"ibr", 9,  4, cris_ver_v0_10,   NULL},
+  {"ebp", 9,  4, cris_ver_v32p,	   NULL},
+  {"p9",  9,  4, 0,		   NULL},
+  {"irp", 10, 4, cris_ver_v0_10,   NULL},
+  {"erp", 10, 4, cris_ver_v32p,	   NULL},
+  {"p10", 10, 4, 0,		   NULL},
+  {"srp", 11, 4, 0,		   NULL},
+  {"p11", 11, 4, 0,		   NULL},
+  /* For disassembly use only.  Accept at assembly with a warning.  */
+  {"bar/dtp0", 12, 4, cris_ver_warning,
+   "Ambiguous register `bar/dtp0' specified"},
+  {"nrp", 12, 4, cris_ver_v32p,	   NULL},
+  {"bar", 12, 4, cris_ver_v8_10,   NULL},
+  {"dtp0",12, 4, cris_ver_v0_3,	   NULL},
+  {"p12", 12, 4, 0,		   NULL},
+  /* For disassembly use only.  Accept at assembly with a warning.  */
+  {"dccr/dtp1",13, 4, cris_ver_warning,
+   "Ambiguous register `dccr/dtp1' specified"},
+  {"ccs", 13, 4, cris_ver_v32p,	   NULL},
+  {"dccr",13, 4, cris_ver_v8_10,   NULL},
+  {"dtp1",13, 4, cris_ver_v0_3,	   NULL},
+  {"p13", 13, 4, 0,		   NULL},
+  {"brp", 14, 4, cris_ver_v3_10,   NULL},
+  {"usp", 14, 4, cris_ver_v32p,	   NULL},
+  {"p14", 14, 4, cris_ver_v3p,	   NULL},
+  {"usp", 15, 4, cris_ver_v10,	   NULL},
+  {"spc", 15, 4, cris_ver_v32p,	   NULL},
+  {"p15", 15, 4, cris_ver_v10p,	   NULL},
+  {NULL, 0, 0, cris_ver_version_all, NULL}
+};
+
+/* Add version specifiers to this table when necessary.
+   The (now) regular coding of register names suggests a simpler
+   implementation.  */
+const struct cris_support_reg cris_support_regs[] =
+{
+  {"s0", 0},
+  {"s1", 1},
+  {"s2", 2},
+  {"s3", 3},
+  {"s4", 4},
+  {"s5", 5},
+  {"s6", 6},
+  {"s7", 7},
+  {"s8", 8},
+  {"s9", 9},
+  {"s10", 10},
+  {"s11", 11},
+  {"s12", 12},
+  {"s13", 13},
+  {"s14", 14},
+  {"s15", 15},
+  {NULL, 0}
+};
+
+/* All CRIS opcodes are 16 bits.
+
+   - The match component is a mask saying which bits must match a
+     particular opcode in order for an instruction to be an instance
+     of that opcode.
+
+   - The args component is a string containing characters symbolically
+     matching the operands of an instruction.  Used for both assembly
+     and disassembly.
+
+     Operand-matching characters:
+     [ ] , space
+        Verbatim.
+     A	The string "ACR" (case-insensitive).
+     B	Not really an operand.  It causes a "BDAP -size,SP" prefix to be
+	output for the PUSH alias-instructions and recognizes a push-
+	prefix at disassembly.  This letter isn't recognized for v32.
+	Must be followed by a R or P letter.
+     !	Non-match pattern, will not match if there's a prefix insn.
+     b	Non-matching operand, used for branches with 16-bit
+	displacement. Only recognized by the disassembler.
+     c	5-bit unsigned immediate in bits <4:0>.
+     C	4-bit unsigned immediate in bits <3:0>.
+     d  At assembly, optionally (as in put other cases before this one)
+	".d" or ".D" at the start of the operands, followed by one space
+	character.  At disassembly, nothing.
+     D	General register in bits <15:12> and <3:0>.
+     f	List of flags in bits <15:12> and <3:0>.
+     i	6-bit signed immediate in bits <5:0>.
+     I	6-bit unsigned immediate in bits <5:0>.
+     M	Size modifier (B, W or D) for CLEAR instructions.
+     m	Size modifier (B, W or D) in bits <5:4>
+     N  A 32-bit dword, like in the difference between s and y.
+        This has no effect on bits in the opcode.  Can also be expressed
+	as "[pc+]" in input.
+     n  As N, but PC-relative (to the start of the instruction).
+     o	[-128..127] word offset in bits <7:1> and <0>.  Used by 8-bit
+	branch instructions.
+     O	[-128..127] offset in bits <7:0>.  Also matches a comma and a
+	general register after the expression, in bits <15:12>.  Used
+	only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode).
+     P	Special register in bits <15:12>.
+     p	Indicates that the insn is a prefix insn.  Must be first
+	character.
+     Q  As O, but don't relax; force an 8-bit offset.
+     R	General register in bits <15:12>.
+     r	General register in bits <3:0>.
+     S	Source operand in bit <10> and a prefix; a 3-operand prefix
+	without side-effect.
+     s	Source operand in bits <10> and <3:0>, optionally with a
+	side-effect prefix, except [pc] (the name, not R15 as in ACR)
+	isn't allowed for v32 and higher.
+     T  Support register in bits <15:12>.
+     u  4-bit (PC-relative) unsigned immediate word offset in bits <3:0>.
+     U  Relaxes to either u or n, instruction is assumed LAPCQ or LAPC.
+	Not recognized at disassembly.
+     x	Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>.
+     y	Like 's' but do not allow an integer at assembly.
+     Y	The difference s-y; only an integer is allowed.
+     z	Size modifier (B or W) in bit <4>.  */
+
+
+/* Please note the order of the opcodes in this table is significant.
+   The assembler requires that all instances of the same mnemonic must
+   be consecutive.  If they aren't, the assembler might not recognize
+   them, or may indicate an internal error.
+
+   The disassembler should not normally care about the order of the
+   opcodes, but will prefer an earlier alternative if the "match-score"
+   (see cris-dis.c) is computed as equal.
+
+   It should not be significant for proper execution that this table is
+   in alphabetical order, but please follow that convention for an easy
+   overview.  */
+
+const struct cris_opcode
+cris_opcodes[] =
+{
+  {"abs",     0x06B0, 0x0940,		  "r,R",     0, SIZE_NONE,     0,
+   cris_abs_op},
+
+  {"add",     0x0600, 0x09c0,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"add",     0x0A00, 0x01c0,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"add",     0x0A00, 0x01c0,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"add",     0x0a00, 0x05c0,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"add",     0x0A00, 0x01c0,		  "m s,R",   0, SIZE_FIELD,
+   cris_ver_v32p,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"addc",    0x0570, 0x0A80,		  "r,R",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addc",    0x09A0, 0x0250,		  "s,R",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addi",    0x0540, 0x0A80,		  "x,r,A",   0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_addi_op},
+
+  {"addi",    0x0500, 0x0Ac0,		  "x,r",     0, SIZE_NONE,     0,
+   cris_addi_op},
+
+  /* This collates after "addo", but we want to disassemble as "addoq",
+     not "addo".  */
+  {"addoq",   0x0100, 0x0E00,		  "Q,A",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addo",    0x0940, 0x0280,		  "m s,R,A", 0, SIZE_FIELD_SIGNED,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  /* This must be located after the insn above, lest we misinterpret
+     "addo.b -1,r0,acr" as "addo .b-1,r0,acr".  FIXME: Sounds like a
+     parser bug.  */
+  {"addo",   0x0100, 0x0E00,		  "O,A",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addq",    0x0200, 0x0Dc0,		  "I,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_add_sub_op},
+
+  {"adds",    0x0420, 0x0Bc0,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
+  {"adds",    0x0820, 0x03c0,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"adds",    0x0820, 0x03c0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"adds",    0x0820, 0x07c0,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"addu",    0x0400, 0x0be0,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"addu",    0x0800, 0x03e0,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"addu",    0x0800, 0x03e0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"addu",    0x0800, 0x07e0,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"and",     0x0700, 0x08C0,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"and",     0x0B00, 0x00C0,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"and",     0x0B00, 0x00C0,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"and",     0x0B00, 0x04C0,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"andq",    0x0300, 0x0CC0,		  "i,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_and_cmp_move_or_op},
+
+  {"asr",     0x0780, 0x0840,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_asr_op},
+
+  {"asrq",    0x03a0, 0x0c40,		  "c,R",     0, SIZE_NONE,     0,
+   cris_asrq_op},
+
+  {"ax",      0x15B0, 0xEA4F,		  "",	     0, SIZE_NONE,     0,
+   cris_ax_ei_setf_op},
+
+  /* FIXME: Should use branch #defines.  */
+  {"b",	      0x0dff, 0x0200,		  "b",	     1, SIZE_NONE,     0,
+   cris_sixteen_bit_offset_branch_op},
+
+  {"ba",
+   BA_QUICK_OPCODE,
+   0x0F00+(0xF-CC_A)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  /* Needs to come after the usual "ba o", which might be relaxed to
+     this one.  */
+  {"ba",     BA_DWORD_OPCODE,
+   0xffff & (~BA_DWORD_OPCODE),		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bas",     0x0EBF, 0x0140,		  "n,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"basc",     0x0EFF, 0x0100,		  "n,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bcc",
+   BRANCH_QUICK_OPCODE+CC_CC*0x1000,
+   0x0f00+(0xF-CC_CC)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bcs",
+   BRANCH_QUICK_OPCODE+CC_CS*0x1000,
+   0x0f00+(0xF-CC_CS)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bdap",
+   BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS,  "pm s,R",  0, SIZE_FIELD_SIGNED,
+   cris_ver_v0_10,
+   cris_bdap_prefix},
+
+  {"bdap",
+   BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS,  "pO",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_quick_mode_bdap_prefix},
+
+  {"beq",
+   BRANCH_QUICK_OPCODE+CC_EQ*0x1000,
+   0x0f00+(0xF-CC_EQ)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  /* This is deliberately put before "bext" to trump it, even though not
+     in alphabetical order, since we don't do excluding version checks
+     for v0..v10.  */
+  {"bwf",
+   BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
+   0x0f00+(0xF-CC_EXT)*0x1000,		  "o",	     1, SIZE_NONE,
+   cris_ver_v10,
+   cris_eight_bit_offset_branch_op},
+
+  {"bext",
+   BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
+   0x0f00+(0xF-CC_EXT)*0x1000,		  "o",	     1, SIZE_NONE,
+   cris_ver_v0_3,
+   cris_eight_bit_offset_branch_op},
+
+  {"bge",
+   BRANCH_QUICK_OPCODE+CC_GE*0x1000,
+   0x0f00+(0xF-CC_GE)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bgt",
+   BRANCH_QUICK_OPCODE+CC_GT*0x1000,
+   0x0f00+(0xF-CC_GT)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bhi",
+   BRANCH_QUICK_OPCODE+CC_HI*0x1000,
+   0x0f00+(0xF-CC_HI)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bhs",
+   BRANCH_QUICK_OPCODE+CC_HS*0x1000,
+   0x0f00+(0xF-CC_HS)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"biap", BIAP_OPCODE, BIAP_Z_BITS,	  "pm r,R",  0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_biap_prefix},
+
+  {"ble",
+   BRANCH_QUICK_OPCODE+CC_LE*0x1000,
+   0x0f00+(0xF-CC_LE)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"blo",
+   BRANCH_QUICK_OPCODE+CC_LO*0x1000,
+   0x0f00+(0xF-CC_LO)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bls",
+   BRANCH_QUICK_OPCODE+CC_LS*0x1000,
+   0x0f00+(0xF-CC_LS)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"blt",
+   BRANCH_QUICK_OPCODE+CC_LT*0x1000,
+   0x0f00+(0xF-CC_LT)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bmi",
+   BRANCH_QUICK_OPCODE+CC_MI*0x1000,
+   0x0f00+(0xF-CC_MI)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bmod",    0x0ab0, 0x0140,		  "s,R",     0, SIZE_FIX_32,
+   cris_ver_sim_v0_10,
+   cris_not_implemented_op},
+
+  {"bmod",    0x0ab0, 0x0140,		  "S,D",     0, SIZE_NONE,
+   cris_ver_sim_v0_10,
+   cris_not_implemented_op},
+
+  {"bmod",    0x0ab0, 0x0540,		  "S,R,r",   0, SIZE_NONE,
+   cris_ver_sim_v0_10,
+   cris_not_implemented_op},
+
+  {"bne",
+   BRANCH_QUICK_OPCODE+CC_NE*0x1000,
+   0x0f00+(0xF-CC_NE)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bound",   0x05c0, 0x0A00,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_two_operand_bound_op},
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"bound",   0x09c0, 0x0200,		  "m s,R",   0, SIZE_FIELD,
+   cris_ver_v0_10,
+   cris_two_operand_bound_op},
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"bound",   0x0dcf, 0x0200,		  "m Y,R",   0, SIZE_FIELD,    0,
+   cris_two_operand_bound_op},
+  {"bound",   0x09c0, 0x0200,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_two_operand_bound_op},
+  {"bound",   0x09c0, 0x0600,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_bound_op},
+
+  {"bpl",
+   BRANCH_QUICK_OPCODE+CC_PL*0x1000,
+   0x0f00+(0xF-CC_PL)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"break",   0xe930, 0x16c0,		  "C",	     0, SIZE_NONE,
+   cris_ver_v3p,
+   cris_break_op},
+
+  {"bsb",
+   BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
+   0x0f00+(0xF-CC_EXT)*0x1000,		  "o",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_eight_bit_offset_branch_op},
+
+  {"bsr",     0xBEBF, 0x4140,		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bsrc",     0xBEFF, 0x4100,		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bstore",  0x0af0, 0x0100,		  "s,R",     0, SIZE_FIX_32,
+   cris_ver_warning,
+   cris_not_implemented_op},
+
+  {"bstore",  0x0af0, 0x0100,		  "S,D",     0, SIZE_NONE,
+   cris_ver_warning,
+   cris_not_implemented_op},
+
+  {"bstore",  0x0af0, 0x0500,		  "S,R,r",   0, SIZE_NONE,
+   cris_ver_warning,
+   cris_not_implemented_op},
+
+  {"btst",    0x04F0, 0x0B00,		  "r,R",     0, SIZE_NONE,     0,
+   cris_btst_nop_op},
+  {"btstq",   0x0380, 0x0C60,		  "c,R",     0, SIZE_NONE,     0,
+   cris_btst_nop_op},
+
+  {"bvc",
+   BRANCH_QUICK_OPCODE+CC_VC*0x1000,
+   0x0f00+(0xF-CC_VC)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"bvs",
+   BRANCH_QUICK_OPCODE+CC_VS*0x1000,
+   0x0f00+(0xF-CC_VS)*0x1000,		  "o",	     1, SIZE_NONE,     0,
+   cris_eight_bit_offset_branch_op},
+
+  {"clear",   0x0670, 0x3980,		  "M r",     0, SIZE_NONE,     0,
+   cris_reg_mode_clear_op},
+
+  {"clear",   0x0A70, 0x3180,		  "M y",     0, SIZE_NONE,     0,
+   cris_none_reg_mode_clear_test_op},
+
+  {"clear",   0x0A70, 0x3180,		  "M S",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_clear_test_op},
+
+  {"clearf",  0x05F0, 0x0A00,		  "f",	     0, SIZE_NONE,     0,
+   cris_clearf_di_op},
+
+  {"cmp",     0x06C0, 0x0900,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"cmp",     0x0Ac0, 0x0100,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"cmp",     0x0Ac0, 0x0100,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"cmpq",    0x02C0, 0x0D00,		  "i,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_and_cmp_move_or_op},
+
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
+  {"cmps",    0x08e0, 0x0300,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"cmps",    0x08e0, 0x0300,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"cmpu",    0x08c0, 0x0320,		  "z s,R" ,  0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"cmpu",    0x08c0, 0x0320,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"di",      0x25F0, 0xDA0F,		  "",	     0, SIZE_NONE,     0,
+   cris_clearf_di_op},
+
+  {"dip",     DIP_OPCODE, DIP_Z_BITS,	  "ps",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
+   cris_dip_prefix},
+
+  {"div",     0x0980, 0x0640,		  "m R,r",   0, SIZE_FIELD,    0,
+   cris_not_implemented_op},
+
+  {"dstep",   0x06f0, 0x0900,		  "r,R",     0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"ei",      0x25B0, 0xDA4F,		  "",	     0, SIZE_NONE,     0,
+   cris_ax_ei_setf_op},
+
+  {"fidxd",    0x0ab0, 0xf540,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"fidxi",    0x0d30, 0xF2C0,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"ftagd",    0x1AB0, 0xE540,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"ftagi",    0x1D30, 0xE2C0,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"halt",    0xF930, 0x06CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"jas",    0x09B0, 0x0640,		  "r,P",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jas",    0x0DBF, 0x0240,		  "N,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jasc",    0x0B30, 0x04C0,		  "r,P",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jasc",    0x0F3F, 0x00C0,		  "N,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jbrc",    0x69b0, 0x9640,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_reg_mode_jump_op},
+
+  {"jbrc",    0x6930, 0x92c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jbrc",    0x6930, 0x92c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jir",     0xA9b0, 0x5640,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_reg_mode_jump_op},
+
+  {"jir",     0xA930, 0x52c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jir",     0xA930, 0x52c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jirc",    0x29b0, 0xd640,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_reg_mode_jump_op},
+
+  {"jirc",    0x2930, 0xd2c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jirc",    0x2930, 0xd2c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jsr",     0xB9b0, 0x4640,		  "r",	     0, SIZE_NONE,     0,
+   cris_reg_mode_jump_op},
+
+  {"jsr",     0xB930, 0x42c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jsr",     0xBDBF, 0x4240,		  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"jsr",     0xB930, 0x42c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jsrc",    0x39b0, 0xc640,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_reg_mode_jump_op},
+
+  {"jsrc",    0x3930, 0xc2c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jsrc",    0x3930, 0xc2c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v8_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jsrc",    0xBB30, 0x44C0,		  "r",       0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jsrc",    0xBF3F, 0x40C0,		  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jump",    0x09b0, 0xF640,		  "r",	     0, SIZE_NONE,     0,
+   cris_reg_mode_jump_op},
+
+  {"jump",
+   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "s",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jump",
+   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "S",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jump",    0x09F0, 0x060F,		  "P",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"jump",
+   JUMP_PC_INCR_OPCODE_V32,
+   (0xffff & ~JUMP_PC_INCR_OPCODE_V32),	  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"jmpu",    0x8930, 0x72c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v10,
+   cris_none_reg_mode_jump_op},
+
+  {"jmpu",    0x8930, 0x72c0,		   "S",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_none_reg_mode_jump_op},
+
+  {"lapc",    0x0970, 0x0680,		  "U,R",    0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"lapc",    0x0D7F, 0x0280,		  "dn,R",    0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"lapcq",   0x0970, 0x0680,		  "u,R",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_addi_op},
+
+  {"lsl",     0x04C0, 0x0B00,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"lslq",    0x03c0, 0x0C20,		  "c,R",     0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"lsr",     0x07C0, 0x0800,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"lsrq",    0x03e0, 0x0C00,		  "c,R",     0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"lz",      0x0730, 0x08C0,		  "r,R",     0, SIZE_NONE,
+   cris_ver_v3p,
+   cris_not_implemented_op},
+
+  {"mcp",      0x07f0, 0x0800,		  "P,r",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"move",    0x0640, 0x0980,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",    0x0A40, 0x0180,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",    0x0A40, 0x0180,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",    0x0630, 0x09c0,		  "r,P",     0, SIZE_NONE,     0,
+   cris_move_to_preg_op},
+
+  {"move",    0x0670, 0x0980,		  "P,r",     0, SIZE_NONE,     0,
+   cris_reg_mode_move_from_preg_op},
+
+  {"move",    0x0BC0, 0x0000,		  "m R,y",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",    0x0BC0, 0x0000,		  "m D,S",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",
+   MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS,
+   "s,P",   0, SIZE_SPEC_REG, 0,
+   cris_move_to_preg_op},
+
+  {"move",    0x0A30, 0x01c0,		  "S,P",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_move_to_preg_op},
+
+  {"move",    0x0A70, 0x0180,		  "P,y",     0, SIZE_SPEC_REG, 0,
+   cris_none_reg_mode_move_from_preg_op},
+
+  {"move",    0x0A70, 0x0180,		  "P,S",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_move_from_preg_op},
+
+  {"move",    0x0B70, 0x0480,		  "r,T",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"move",    0x0F70, 0x0080,		  "T,r",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"movem",   0x0BF0, 0x0000,		  "R,y",     0, SIZE_FIX_32,   0,
+   cris_move_reg_to_mem_movem_op},
+
+  {"movem",   0x0BF0, 0x0000,		  "D,S",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_move_reg_to_mem_movem_op},
+
+  {"movem",   0x0BB0, 0x0040,		  "s,R",     0, SIZE_FIX_32,   0,
+   cris_move_mem_to_reg_movem_op},
+
+  {"movem",   0x0BB0, 0x0040,		  "S,D",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_move_mem_to_reg_movem_op},
+
+  {"moveq",   0x0240, 0x0D80,		  "i,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_and_cmp_move_or_op},
+
+  {"movs",    0x0460, 0x0B80,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
+  {"movs",    0x0860, 0x0380,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"movs",    0x0860, 0x0380,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"movu",    0x0440, 0x0Ba0,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"movu",    0x0840, 0x03a0,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"movu",    0x0840, 0x03a0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"mstep",   0x07f0, 0x0800,		  "r,R",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"muls",    0x0d00, 0x02c0,		  "m r,R",   0, SIZE_NONE,
+   cris_ver_v10p,
+   cris_muls_op},
+
+  {"mulu",    0x0900, 0x06c0,		  "m r,R",   0, SIZE_NONE,
+   cris_ver_v10p,
+   cris_mulu_op},
+
+  {"neg",     0x0580, 0x0A40,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"nop",     NOP_OPCODE, NOP_Z_BITS,	  "",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_btst_nop_op},
+
+  {"nop",     NOP_OPCODE_V32, NOP_Z_BITS_V32, "",    0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_btst_nop_op},
+
+  {"not",     0x8770, 0x7880,		  "r",	     0, SIZE_NONE,     0,
+   cris_dstep_logshift_mstep_neg_not_op},
+
+  {"or",      0x0740, 0x0880,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"or",      0x0B40, 0x0080,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"or",      0x0B40, 0x0080,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"or",      0x0B40, 0x0480,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"orq",     0x0340, 0x0C80,		  "i,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_and_cmp_move_or_op},
+
+  {"pop",     0x0E6E, 0x0191,		  "!R",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"pop",     0x0e3e, 0x01c1,		  "!P",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_move_from_preg_op},
+
+  {"push",    0x0FEE, 0x0011,		  "BR",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"push",    0x0E7E, 0x0181,		  "BP",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_move_to_preg_op},
+
+  {"rbf",     0x3b30, 0xc0c0,		  "y",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_not_implemented_op},
+
+  {"rbf",     0x3b30, 0xc0c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_not_implemented_op},
+
+  {"rfe",     0x2930, 0xD6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"rfg",     0x4930, 0xB6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"rfn",     0x5930, 0xA6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"ret",     0xB67F, 0x4980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_move_from_preg_op},
+
+  {"ret",     0xB9F0, 0x460F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_move_from_preg_op},
+
+  {"retb",    0xe67f, 0x1980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_move_from_preg_op},
+
+  {"rete",     0xA9F0, 0x560F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_move_from_preg_op},
+
+  {"reti",    0xA67F, 0x5980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_move_from_preg_op},
+
+  {"retn",     0xC9F0, 0x360F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_move_from_preg_op},
+
+  {"sbfs",    0x3b70, 0xc080,		  "y",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_not_implemented_op},
+
+  {"sbfs",    0x3b70, 0xc080,		  "S",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_not_implemented_op},
+
+  {"sa",
+   0x0530+CC_A*0x1000,
+   0x0AC0+(0xf-CC_A)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"ssb",
+   0x0530+CC_EXT*0x1000,
+   0x0AC0+(0xf-CC_EXT)*0x1000,		  "r",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_scc_op},
+
+  {"scc",
+   0x0530+CC_CC*0x1000,
+   0x0AC0+(0xf-CC_CC)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"scs",
+   0x0530+CC_CS*0x1000,
+   0x0AC0+(0xf-CC_CS)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"seq",
+   0x0530+CC_EQ*0x1000,
+   0x0AC0+(0xf-CC_EQ)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"setf",    0x05b0, 0x0A40,		  "f",	     0, SIZE_NONE,     0,
+   cris_ax_ei_setf_op},
+
+  {"sfe",    0x3930, 0xC6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  /* Need to have "swf" in front of "sext" so it is the one displayed in
+     disassembly.  */
+  {"swf",
+   0x0530+CC_EXT*0x1000,
+   0x0AC0+(0xf-CC_EXT)*0x1000,		  "r",	     0, SIZE_NONE,
+   cris_ver_v10,
+   cris_scc_op},
+
+  {"sext",
+   0x0530+CC_EXT*0x1000,
+   0x0AC0+(0xf-CC_EXT)*0x1000,		  "r",	     0, SIZE_NONE,
+   cris_ver_v0_3,
+   cris_scc_op},
+
+  {"sge",
+   0x0530+CC_GE*0x1000,
+   0x0AC0+(0xf-CC_GE)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"sgt",
+   0x0530+CC_GT*0x1000,
+   0x0AC0+(0xf-CC_GT)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"shi",
+   0x0530+CC_HI*0x1000,
+   0x0AC0+(0xf-CC_HI)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"shs",
+   0x0530+CC_HS*0x1000,
+   0x0AC0+(0xf-CC_HS)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"sle",
+   0x0530+CC_LE*0x1000,
+   0x0AC0+(0xf-CC_LE)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"slo",
+   0x0530+CC_LO*0x1000,
+   0x0AC0+(0xf-CC_LO)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"sls",
+   0x0530+CC_LS*0x1000,
+   0x0AC0+(0xf-CC_LS)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"slt",
+   0x0530+CC_LT*0x1000,
+   0x0AC0+(0xf-CC_LT)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"smi",
+   0x0530+CC_MI*0x1000,
+   0x0AC0+(0xf-CC_MI)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"sne",
+   0x0530+CC_NE*0x1000,
+   0x0AC0+(0xf-CC_NE)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"spl",
+   0x0530+CC_PL*0x1000,
+   0x0AC0+(0xf-CC_PL)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"sub",     0x0680, 0x0940,		  "m r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"sub",     0x0a80, 0x0140,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"sub",     0x0a80, 0x0140,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"sub",     0x0a80, 0x0540,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"subq",    0x0280, 0x0d40,		  "I,R",     0, SIZE_NONE,     0,
+   cris_quick_mode_add_sub_op},
+
+  {"subs",    0x04a0, 0x0b40,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
+  {"subs",    0x08a0, 0x0340,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"subs",    0x08a0, 0x0340,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"subs",    0x08a0, 0x0740,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"subu",    0x0480, 0x0b60,		  "z r,R",   0, SIZE_NONE,     0,
+   cris_reg_mode_add_sub_cmp_and_or_move_op},
+
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"subu",    0x0880, 0x0360,		  "z s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"subu",    0x0880, 0x0360,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"subu",    0x0880, 0x0760,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_three_operand_add_sub_cmp_and_or_op},
+
+  {"svc",
+   0x0530+CC_VC*0x1000,
+   0x0AC0+(0xf-CC_VC)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  {"svs",
+   0x0530+CC_VS*0x1000,
+   0x0AC0+(0xf-CC_VS)*0x1000,		  "r",	     0, SIZE_NONE,     0,
+   cris_scc_op},
+
+  /* The insn "swapn" is the same as "not" and will be disassembled as
+     such, but the swap* family of mnmonics are generally v8-and-higher
+     only, so count it in.  */
+  {"swapn",   0x8770, 0x7880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapw",   0x4770, 0xb880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnw",  0xc770, 0x3880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapb",   0x2770, 0xd880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnb",  0xA770, 0x5880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapwb",  0x6770, 0x9880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnwb", 0xE770, 0x1880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapr",   0x1770, 0xe880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnr",  0x9770, 0x6880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapwr",  0x5770, 0xa880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnwr", 0xd770, 0x2880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapbr",  0x3770, 0xc880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnbr", 0xb770, 0x4880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapwbr", 0x7770, 0x8880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"swapnwbr", 0xf770, 0x0880,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8p,
+   cris_not_implemented_op},
+
+  {"test",    0x0640, 0x0980,		  "m D",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_test_op},
+
+  {"test",    0x0b80, 0xf040,		  "m y",     0, SIZE_FIELD,    0,
+   cris_none_reg_mode_clear_test_op},
+
+  {"test",    0x0b80, 0xf040,		  "m S",     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_clear_test_op},
+
+  {"xor",     0x07B0, 0x0840,		  "r,R",     0, SIZE_NONE,     0,
+   cris_xor_op},
+
+  {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op}
+};
+
+/* Condition-names, indexed by the CC_* numbers as found in cris.h. */
+const char * const
+cris_cc_strings[] =
+{
+  "hs",
+  "lo",
+  "ne",
+  "eq",
+  "vc",
+  "vs",
+  "pl",
+  "mi",
+  "ls",
+  "hi",
+  "ge",
+  "lt",
+  "gt",
+  "le",
+  "a",
+  /* This is a placeholder.  In v0, this would be "ext".  In v32, this
+     is "sb".  See cris_conds15.  */
+  "wf"
+};
+
+/* Different names and semantics for condition 1111 (0xf).  */
+const struct cris_cond15 cris_cond15s[] =
+{
+  /* FIXME: In what version did condition "ext" disappear?  */
+  {"ext", cris_ver_v0_3},
+  {"wf", cris_ver_v10},
+  {"sb", cris_ver_v32p},
+  {NULL, 0}
+};
+
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
+
+
+/* No instruction will be disassembled longer than this.  In theory, and
+   in silicon, address prefixes can be cascaded.  In practice, cascading
+   is not used by GCC, and not supported by the assembler.  */
+#ifndef MAX_BYTES_PER_CRIS_INSN
+#define MAX_BYTES_PER_CRIS_INSN 8
+#endif
+
+/* Whether or not to decode prefixes, folding it into the following
+   instruction.  FIXME: Make this optional later.  */
+#ifndef PARSE_PREFIX
+#define PARSE_PREFIX 1
+#endif
+
+/* Sometimes we prefix all registers with this character.  */
+#define REGISTER_PREFIX_CHAR '$'
+
+/* Whether or not to trace the following sequence:
+   sub* X,r%d
+   bound* Y,r%d
+   adds.w [pc+r%d.w],pc
+
+   This is the assembly form of a switch-statement in C.
+   The "sub is optional.  If there is none, then X will be zero.
+   X is the value of the first case,
+   Y is the number of cases (including default).
+
+   This results in case offsets printed on the form:
+    case N: -> case_address
+   where N is an estimation on the corresponding 'case' operand in C,
+   and case_address is where execution of that case continues after the
+   sequence presented above.
+
+   The old style of output was to print the offsets as instructions,
+   which made it hard to follow "case"-constructs in the disassembly,
+   and caused a lot of annoying warnings about undefined instructions.
+
+   FIXME: Make this optional later.  */
+#ifndef TRACE_CASE
+#define TRACE_CASE (disdata->trace_case)
+#endif
+
+enum cris_disass_family
+ { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 };
+
+/* Stored in the disasm_info->private_data member.  */
+struct cris_disasm_data
+{
+  /* Whether to print something less confusing if we find something
+     matching a switch-construct.  */
+  bfd_boolean trace_case;
+
+  /* Whether this code is flagged as crisv32.  FIXME: Should be an enum
+     that includes "compatible".  */
+  enum cris_disass_family distype;
+};
+
+/* Value of first element in switch.  */
+static long case_offset = 0;
+
+/* How many more case-offsets to print.  */
+static long case_offset_counter = 0;
+
+/* Number of case offsets.  */
+static long no_of_case_offsets = 0;
+
+/* Candidate for next case_offset.  */
+static long last_immediate = 0;
+
+static int cris_constraint
+  (const char *, unsigned, unsigned, struct cris_disasm_data *);
+
+/* Parse disassembler options and store state in info.  FIXME: For the
+   time being, we abuse static variables.  */
+
+static bfd_boolean
+cris_parse_disassembler_options (disassemble_info *info,
+				 enum cris_disass_family distype)
+{
+  struct cris_disasm_data *disdata;
+
+  info->private_data = calloc (1, sizeof (struct cris_disasm_data));
+  disdata = (struct cris_disasm_data *) info->private_data;
+  if (disdata == NULL)
+    return false;
+
+  /* Default true.  */
+  disdata->trace_case
+    = (info->disassembler_options == NULL
+       || (strcmp (info->disassembler_options, "nocase") != 0));
+
+  disdata->distype = distype;
+  return true;
+}
+
+static const struct cris_spec_reg *
+spec_reg_info (unsigned int sreg, enum cris_disass_family distype)
+{
+  int i;
+
+  for (i = 0; cris_spec_regs[i].name != NULL; i++)
+    {
+      if (cris_spec_regs[i].number == sreg)
+	{
+	  if (distype == cris_dis_v32)
+	    switch (cris_spec_regs[i].applicable_version)
+	      {
+	      case cris_ver_warning:
+	      case cris_ver_version_all:
+	      case cris_ver_v3p:
+	      case cris_ver_v8p:
+	      case cris_ver_v10p:
+	      case cris_ver_v32p:
+		/* No ambiguous sizes or register names with CRISv32.  */
+		if (cris_spec_regs[i].warning == NULL)
+		  return &cris_spec_regs[i];
+	      default:
+		;
+	      }
+	  else if (cris_spec_regs[i].applicable_version != cris_ver_v32p)
+	    return &cris_spec_regs[i];
+	}
+    }
+
+  return NULL;
+}
+
+/* Return the number of bits in the argument.  */
+
+static int
+number_of_bits (unsigned int val)
+{
+  int bits;
+
+  for (bits = 0; val != 0; val &= val - 1)
+    bits++;
+
+  return bits;
+}
+
+/* Get an entry in the opcode-table.  */
+
+static const struct cris_opcode *
+get_opcode_entry (unsigned int insn,
+		  unsigned int prefix_insn,
+		  struct cris_disasm_data *disdata)
+{
+  /* For non-prefixed insns, we keep a table of pointers, indexed by the
+     insn code.  Each entry is initialized when found to be NULL.  */
+  static const struct cris_opcode **opc_table = NULL;
+
+  const struct cris_opcode *max_matchedp = NULL;
+  const struct cris_opcode **prefix_opc_table = NULL;
+
+  /* We hold a table for each prefix that need to be handled differently.  */
+  static const struct cris_opcode **dip_prefixes = NULL;
+  static const struct cris_opcode **bdapq_m1_prefixes = NULL;
+  static const struct cris_opcode **bdapq_m2_prefixes = NULL;
+  static const struct cris_opcode **bdapq_m4_prefixes = NULL;
+  static const struct cris_opcode **rest_prefixes = NULL;
+
+  /* Allocate and clear the opcode-table.  */
+  if (opc_table == NULL)
+    {
+      opc_table = qemu_malloc (65536 * sizeof (opc_table[0]));
+
+      memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *));
+
+      dip_prefixes
+	= qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+
+      memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0]));
+
+      bdapq_m1_prefixes
+	= qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+
+      memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0]));
+
+      bdapq_m2_prefixes
+	= qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+
+      memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0]));
+
+      bdapq_m4_prefixes
+	= qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+
+      memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0]));
+
+      rest_prefixes
+	= qemu_malloc (65536 * sizeof (const struct cris_opcode **));
+
+      memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0]));
+    }
+
+  /* Get the right table if this is a prefix.
+     This code is connected to cris_constraints in that it knows what
+     prefixes play a role in recognition of patterns; the necessary
+     state is reflected by which table is used.  If constraints
+     involving match or non-match of prefix insns are changed, then this
+     probably needs changing too.  */
+  if (prefix_insn != NO_CRIS_PREFIX)
+    {
+      const struct cris_opcode *popcodep
+	= (opc_table[prefix_insn] != NULL
+	   ? opc_table[prefix_insn]
+	   : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata));
+
+      if (popcodep == NULL)
+	return NULL;
+
+      if (popcodep->match == BDAP_QUICK_OPCODE)
+	{
+	  /* Since some offsets are recognized with "push" macros, we
+	     have to have different tables for them.  */
+	  int offset = (prefix_insn & 255);
+
+	  if (offset > 127)
+	    offset -= 256;
+
+	  switch (offset)
+	    {
+	    case -4:
+	      prefix_opc_table = bdapq_m4_prefixes;
+	      break;
+
+	    case -2:
+	      prefix_opc_table = bdapq_m2_prefixes;
+	      break;
+
+	    case -1:
+	      prefix_opc_table = bdapq_m1_prefixes;
+	      break;
+
+	    default:
+	      prefix_opc_table = rest_prefixes;
+	      break;
+	    }
+	}
+      else if (popcodep->match == DIP_OPCODE)
+	/* We don't allow postincrement when the prefix is DIP, so use a
+	   different table for DIP.  */
+	prefix_opc_table = dip_prefixes;
+      else
+	prefix_opc_table = rest_prefixes;
+    }
+
+  if (prefix_insn != NO_CRIS_PREFIX
+      && prefix_opc_table[insn] != NULL)
+    max_matchedp = prefix_opc_table[insn];
+  else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL)
+    max_matchedp = opc_table[insn];
+  else
+    {
+      const struct cris_opcode *opcodep;
+      int max_level_of_match = -1;
+
+      for (opcodep = cris_opcodes;
+	   opcodep->name != NULL;
+	   opcodep++)
+	{
+	  int level_of_match;
+
+	  if (disdata->distype == cris_dis_v32)
+	    {
+	      switch (opcodep->applicable_version)
+		{
+		case cris_ver_version_all:
+		  break;
+
+		case cris_ver_v0_3:
+		case cris_ver_v0_10:
+		case cris_ver_v3_10:
+		case cris_ver_sim_v0_10:
+		case cris_ver_v8_10:
+		case cris_ver_v10:
+		case cris_ver_warning:
+		  continue;
+
+		case cris_ver_v3p:
+		case cris_ver_v8p:
+		case cris_ver_v10p:
+		case cris_ver_v32p:
+		  break;
+
+		case cris_ver_v8:
+		  abort ();
+		default:
+		  abort ();
+		}
+	    }
+	  else
+	    {
+	      switch (opcodep->applicable_version)
+		{
+		case cris_ver_version_all:
+		case cris_ver_v0_3:
+		case cris_ver_v3p:
+		case cris_ver_v0_10:
+		case cris_ver_v8p:
+		case cris_ver_v8_10:
+		case cris_ver_v10:
+		case cris_ver_sim_v0_10:
+		case cris_ver_v10p:
+		case cris_ver_warning:
+		  break;
+
+		case cris_ver_v32p:
+		  continue;
+
+		case cris_ver_v8:
+		  abort ();
+		default:
+		  abort ();
+		}
+	    }
+
+	  /* We give a double lead for bits matching the template in
+	     cris_opcodes.  Not even, because then "move p8,r10" would
+	     be given 2 bits lead over "clear.d r10".  When there's a
+	     tie, the first entry in the table wins.  This is
+	     deliberate, to avoid a more complicated recognition
+	     formula.  */
+	  if ((opcodep->match & insn) == opcodep->match
+	      && (opcodep->lose & insn) == 0
+	      && ((level_of_match
+		   = cris_constraint (opcodep->args,
+				      insn,
+				      prefix_insn,
+				      disdata))
+		  >= 0)
+	      && ((level_of_match
+		   += 2 * number_of_bits (opcodep->match
+					  | opcodep->lose))
+			  > max_level_of_match))
+		    {
+		      max_matchedp = opcodep;
+		      max_level_of_match = level_of_match;
+
+		      /* If there was a full match, never mind looking
+			 further.  */
+		      if (level_of_match >= 2 * 16)
+			break;
+		    }
+		}
+      /* Fill in the new entry.
+
+	 If there are changes to the opcode-table involving prefixes, and
+	 disassembly then does not work correctly, try removing the
+	 else-clause below that fills in the prefix-table.  If that
+	 helps, you need to change the prefix_opc_table setting above, or
+	 something related.  */
+      if (prefix_insn == NO_CRIS_PREFIX)
+	opc_table[insn] = max_matchedp;
+      else
+	prefix_opc_table[insn] = max_matchedp;
+    }
+
+  return max_matchedp;
+}
+
+/* Return -1 if the constraints of a bitwise-matched instruction say
+   that there is no match.  Otherwise return a nonnegative number
+   indicating the confidence in the match (higher is better).  */
+
+static int
+cris_constraint (const char *cs,
+		 unsigned int insn,
+		 unsigned int prefix_insn,
+		 struct cris_disasm_data *disdata)
+{
+  int retval = 0;
+  int tmp;
+  int prefix_ok = 0;
+  const char *s;
+
+  for (s = cs; *s; s++)
+    switch (*s)
+      {
+      case '!':
+	/* Do not recognize "pop" if there's a prefix and then only for
+           v0..v10.  */
+	if (prefix_insn != NO_CRIS_PREFIX
+	    || disdata->distype != cris_dis_v0_v10)
+	  return -1;
+	break;
+
+      case 'U':
+	/* Not recognized at disassembly.  */
+	return -1;
+
+      case 'M':
+	/* Size modifier for "clear", i.e. special register 0, 4 or 8.
+	   Check that it is one of them.  Only special register 12 could
+	   be mismatched, but checking for matches is more logical than
+	   checking for mismatches when there are only a few cases.  */
+	tmp = ((insn >> 12) & 0xf);
+	if (tmp != 0 && tmp != 4 && tmp != 8)
+	  return -1;
+	break;
+
+      case 'm':
+	if ((insn & 0x30) == 0x30)
+	  return -1;
+	break;
+
+      case 'S':
+	/* A prefix operand without side-effect.  */
+	if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0)
+	  {
+	    prefix_ok = 1;
+	    break;
+	  }
+	else
+	  return -1;
+
+      case 's':
+      case 'y':
+      case 'Y':
+	/* If this is a prefixed insn with postincrement (side-effect),
+	   the prefix must not be DIP.  */
+	if (prefix_insn != NO_CRIS_PREFIX)
+	  {
+	    if (insn & 0x400)
+	      {
+		const struct cris_opcode *prefix_opcodep
+		  = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
+
+		if (prefix_opcodep->match == DIP_OPCODE)
+		  return -1;
+	      }
+
+	    prefix_ok = 1;
+	  }
+	break;
+
+      case 'B':
+	/* If we don't fall through, then the prefix is ok.  */
+	prefix_ok = 1;
+
+	/* A "push" prefix.  Check for valid "push" size.
+	   In case of special register, it may be != 4.  */
+	if (prefix_insn != NO_CRIS_PREFIX)
+	  {
+	    /* Match the prefix insn to BDAPQ.  */
+	    const struct cris_opcode *prefix_opcodep
+	      = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
+
+	    if (prefix_opcodep->match == BDAP_QUICK_OPCODE)
+	      {
+		int pushsize = (prefix_insn & 255);
+
+		if (pushsize > 127)
+		  pushsize -= 256;
+
+		if (s[1] == 'P')
+		  {
+		    unsigned int spec_reg = (insn >> 12) & 15;
+		    const struct cris_spec_reg *sregp
+		      = spec_reg_info (spec_reg, disdata->distype);
+
+		    /* For a special-register, the "prefix size" must
+		       match the size of the register.  */
+		    if (sregp && sregp->reg_size == (unsigned int) -pushsize)
+		      break;
+		  }
+		else if (s[1] == 'R')
+		  {
+		    if ((insn & 0x30) == 0x20 && pushsize == -4)
+		      break;
+		  }
+		/* FIXME:  Should abort here; next constraint letter
+		   *must* be 'P' or 'R'.  */
+	      }
+	  }
+	return -1;
+
+      case 'D':
+	retval = (((insn >> 12) & 15) == (insn & 15));
+	if (!retval)
+	  return -1;
+	else
+	  retval += 4;
+	break;
+
+      case 'P':
+	{
+	  const struct cris_spec_reg *sregp
+	    = spec_reg_info ((insn >> 12) & 15, disdata->distype);
+
+	  /* Since we match four bits, we will give a value of 4-1 = 3
+	     in a match.  If there is a corresponding exact match of a
+	     special register in another pattern, it will get a value of
+	     4, which will be higher.  This should be correct in that an
+	     exact pattern would match better than a general pattern.
+
+	     Note that there is a reason for not returning zero; the
+	     pattern for "clear" is partly  matched in the bit-pattern
+	     (the two lower bits must be zero), while the bit-pattern
+	     for a move from a special register is matched in the
+	     register constraint.  */
+
+	  if (sregp != NULL)
+	    {
+	      retval += 3;
+	      break;
+	    }
+	  else
+	    return -1;
+	}
+      }
+
+  if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok)
+    return -1;
+
+  return retval;
+}
+
+/* Format number as hex with a leading "0x" into outbuffer.  */
+
+static char *
+format_hex (unsigned long number,
+	    char *outbuffer,
+	    struct cris_disasm_data *disdata)
+{
+  /* Truncate negative numbers on >32-bit hosts.  */
+  number &= 0xffffffff;
+
+  sprintf (outbuffer, "0x%lx", number);
+
+  /* Save this value for the "case" support.  */
+  if (TRACE_CASE)
+    last_immediate = number;
+
+  return outbuffer + strlen (outbuffer);
+}
+
+/* Format number as decimal into outbuffer.  Parameter signedp says
+   whether the number should be formatted as signed (!= 0) or
+   unsigned (== 0).  */
+
+static char *
+format_dec (long number, char *outbuffer, int signedp)
+{
+  last_immediate = number;
+  sprintf (outbuffer, signedp ? "%ld" : "%lu", number);
+
+  return outbuffer + strlen (outbuffer);
+}
+
+/* Format the name of the general register regno into outbuffer.  */
+
+static char *
+format_reg (struct cris_disasm_data *disdata,
+	    int regno,
+	    char *outbuffer_start,
+	    bfd_boolean with_reg_prefix)
+{
+  char *outbuffer = outbuffer_start;
+
+  if (with_reg_prefix)
+    *outbuffer++ = REGISTER_PREFIX_CHAR;
+
+  switch (regno)
+    {
+    case 15:
+      /* For v32, there is no context in which we output PC.  */
+      if (disdata->distype == cris_dis_v32)
+	strcpy (outbuffer, "acr");
+      else
+	strcpy (outbuffer, "pc");
+      break;
+
+    case 14:
+      strcpy (outbuffer, "sp");
+      break;
+
+    default:
+      sprintf (outbuffer, "r%d", regno);
+      break;
+    }
+
+  return outbuffer_start + strlen (outbuffer_start);
+}
+
+/* Format the name of a support register into outbuffer.  */
+
+static char *
+format_sup_reg (unsigned int regno,
+		char *outbuffer_start,
+		bfd_boolean with_reg_prefix)
+{
+  char *outbuffer = outbuffer_start;
+  int i;
+
+  if (with_reg_prefix)
+    *outbuffer++ = REGISTER_PREFIX_CHAR;
+
+  for (i = 0; cris_support_regs[i].name != NULL; i++)
+    if (cris_support_regs[i].number == regno)
+      {
+	sprintf (outbuffer, "%s", cris_support_regs[i].name);
+	return outbuffer_start + strlen (outbuffer_start);
+      }
+
+  /* There's supposed to be register names covering all numbers, though
+     some may be generic names.  */
+  sprintf (outbuffer, "format_sup_reg-BUG");
+  return outbuffer_start + strlen (outbuffer_start);
+}
+
+/* Return the length of an instruction.  */
+
+static unsigned
+bytes_to_skip (unsigned int insn,
+	       const struct cris_opcode *matchedp,
+	       enum cris_disass_family distype,
+	       const struct cris_opcode *prefix_matchedp)
+{
+  /* Each insn is a word plus "immediate" operands.  */
+  unsigned to_skip = 2;
+  const char *template = matchedp->args;
+  const char *s;
+
+  for (s = template; *s; s++)
+    if ((*s == 's' || *s == 'N' || *s == 'Y')
+	&& (insn & 0x400) && (insn & 15) == 15
+	&& prefix_matchedp == NULL)
+      {
+	/* Immediate via [pc+], so we have to check the size of the
+	   operand.  */
+	int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3));
+
+	if (matchedp->imm_oprnd_size == SIZE_FIX_32)
+	  to_skip += 4;
+	else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)
+	  {
+	    const struct cris_spec_reg *sregp
+	      = spec_reg_info ((insn >> 12) & 15, distype);
+
+	    /* FIXME: Improve error handling; should have been caught
+	       earlier.  */
+	    if (sregp == NULL)
+	      return 2;
+
+	    /* PC is incremented by two, not one, for a byte.  Except on
+	       CRISv32, where constants are always DWORD-size for
+	       special registers.  */
+	    to_skip +=
+	      distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1;
+	  }
+	else
+	  to_skip += (mode_size + 1) & ~1;
+      }
+    else if (*s == 'n')
+      to_skip += 4;
+    else if (*s == 'b')
+      to_skip += 2;
+
+  return to_skip;
+}
+
+/* Print condition code flags.  */
+
+static char *
+print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp)
+{
+  /* Use the v8 (Etrax 100) flag definitions for disassembly.
+     The differences with v0 (Etrax 1..4) vs. Svinto are:
+      v0 'd' <=> v8 'm'
+      v0 'e' <=> v8 'b'.
+     FIXME: Emit v0..v3 flag names somehow.  */
+  static const char v8_fnames[] = "cvznxibm";
+  static const char v32_fnames[] = "cvznxiup";
+  const char *fnames
+    = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames;
+
+  unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));
+  int i;
+
+  for (i = 0; i < 8; i++)
+    if (flagbits & (1 << i))
+      *cp++ = fnames[i];
+
+  return cp;
+}
+
+/* Print out an insn with its operands, and update the info->insn_type
+   fields.  The prefix_opcodep and the rest hold a prefix insn that is
+   supposed to be output as an address mode.  */
+
+static void
+print_with_operands (const struct cris_opcode *opcodep,
+		     unsigned int insn,
+		     unsigned char *buffer,
+		     bfd_vma addr,
+		     disassemble_info *info,
+		     /* If a prefix insn was before this insn (and is supposed
+			to be output as an address), here is a description of
+			it.  */
+		     const struct cris_opcode *prefix_opcodep,
+		     unsigned int prefix_insn,
+		     unsigned char *prefix_buffer,
+		     bfd_boolean with_reg_prefix)
+{
+  /* Get a buffer of somewhat reasonable size where we store
+     intermediate parts of the insn.  */
+  char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2];
+  char *tp = temp;
+  static const char mode_char[] = "bwd?";
+  const char *s;
+  const char *cs;
+  struct cris_disasm_data *disdata
+    = (struct cris_disasm_data *) info->private_data;
+
+  /* Print out the name first thing we do.  */
+  (*info->fprintf_func) (info->stream, "%s", opcodep->name);
+
+  cs = opcodep->args;
+  s = cs;
+
+  /* Ignore any prefix indicator.  */
+  if (*s == 'p')
+    s++;
+
+  if (*s == 'm' || *s == 'M' || *s == 'z')
+    {
+      *tp++ = '.';
+
+      /* Get the size-letter.  */
+      *tp++ = *s == 'M'
+	? (insn & 0x8000 ? 'd'
+	   : insn & 0x4000 ? 'w' : 'b')
+	: mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)];
+
+      /* Ignore the size and the space character that follows.  */
+      s += 2;
+    }
+
+  /* Add a space if this isn't a long-branch, because for those will add
+     the condition part of the name later.  */
+  if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256))
+    *tp++ = ' ';
+
+  /* Fill in the insn-type if deducible from the name (and there's no
+     better way).  */
+  if (opcodep->name[0] == 'j')
+    {
+      if (CONST_STRNEQ (opcodep->name, "jsr"))
+	/* It's "jsr" or "jsrc".  */
+	info->insn_type = dis_jsr;
+      else
+	/* Any other jump-type insn is considered a branch.  */
+	info->insn_type = dis_branch;
+    }
+
+  /* We might know some more fields right now.  */
+  info->branch_delay_insns = opcodep->delayed;
+
+  /* Handle operands.  */
+  for (; *s; s++)
+    {
+    switch (*s)
+      {
+      case 'T':
+	tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+	break;
+
+      case 'A':
+	if (with_reg_prefix)
+	  *tp++ = REGISTER_PREFIX_CHAR;
+	*tp++ = 'a';
+	*tp++ = 'c';
+	*tp++ = 'r';
+	break;
+
+      case '[':
+      case ']':
+      case ',':
+	*tp++ = *s;
+	break;
+
+      case '!':
+	/* Ignore at this point; used at earlier stages to avoid
+	   recognition if there's a prefix at something that in other
+	   ways looks like a "pop".  */
+	break;
+
+      case 'd':
+	/* Ignore.  This is an optional ".d " on the large one of
+	   relaxable insns.  */
+	break;
+
+      case 'B':
+	/* This was the prefix that made this a "push".  We've already
+	   handled it by recognizing it, so signal that the prefix is
+	   handled by setting it to NULL.  */
+	prefix_opcodep = NULL;
+	break;
+
+      case 'D':
+      case 'r':
+	tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
+	break;
+
+      case 'R':
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
+	break;
+
+      case 'n':
+	{
+	  /* Like N but pc-relative to the start of the insn.  */
+	  unsigned long number
+	    = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+	       + buffer[5] * 0x1000000 + addr);
+
+	  /* Finish off and output previous formatted bytes.  */
+	  *tp = 0;
+	  if (temp[0])
+	    (*info->fprintf_func) (info->stream, "%s", temp);
+	  tp = temp;
+
+	  (*info->print_address_func) ((bfd_vma) number, info);
+	}
+	break;
+
+      case 'u':
+	{
+	  /* Like n but the offset is bits <3:0> in the instruction.  */
+	  unsigned long number = (buffer[0] & 0xf) * 2 + addr;
+
+	  /* Finish off and output previous formatted bytes.  */
+	  *tp = 0;
+	  if (temp[0])
+	    (*info->fprintf_func) (info->stream, "%s", temp);
+	  tp = temp;
+
+	  (*info->print_address_func) ((bfd_vma) number, info);
+	}
+	break;
+
+      case 'N':
+      case 'y':
+      case 'Y':
+      case 'S':
+      case 's':
+	/* Any "normal" memory operand.  */
+	if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL)
+	  {
+	    /* We're looking at [pc+], i.e. we need to output an immediate
+	       number, where the size can depend on different things.  */
+	    long number;
+	    int signedp
+	      = ((*cs == 'z' && (insn & 0x20))
+		 || opcodep->match == BDAP_QUICK_OPCODE);
+	    int nbytes;
+
+	    if (opcodep->imm_oprnd_size == SIZE_FIX_32)
+	      nbytes = 4;
+	    else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
+	      {
+		const struct cris_spec_reg *sregp
+		  = spec_reg_info ((insn >> 12) & 15, disdata->distype);
+
+		/* A NULL return should have been as a non-match earlier,
+		   so catch it as an internal error in the error-case
+		   below.  */
+		if (sregp == NULL)
+		  /* Whatever non-valid size.  */
+		  nbytes = 42;
+		else
+		  /* PC is always incremented by a multiple of two.
+		     For CRISv32, immediates are always 4 bytes for
+		     special registers.  */
+		  nbytes = disdata->distype == cris_dis_v32
+		    ? 4 : (sregp->reg_size + 1) & ~1;
+	      }
+	    else
+	      {
+		int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3));
+
+		if (mode_size == 1)
+		  nbytes = 2;
+		else
+		  nbytes = mode_size;
+	      }
+
+	    switch (nbytes)
+	      {
+	      case 1:
+		number = buffer[2];
+		if (signedp && number > 127)
+		  number -= 256;
+		break;
+
+	      case 2:
+		number = buffer[2] + buffer[3] * 256;
+		if (signedp && number > 32767)
+		  number -= 65536;
+		break;
+
+	      case 4:
+		number
+		  = buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+		  + buffer[5] * 0x1000000;
+		break;
+
+	      default:
+		strcpy (tp, "bug");
+		tp += 3;
+		number = 42;
+	      }
+
+	    if ((*cs == 'z' && (insn & 0x20))
+		|| (opcodep->match == BDAP_QUICK_OPCODE
+		    && (nbytes <= 2 || buffer[1 + nbytes] == 0)))
+	      tp = format_dec (number, tp, signedp);
+	    else
+	      {
+		unsigned int highbyte = (number >> 24) & 0xff;
+
+		/* Either output this as an address or as a number.  If it's
+		   a dword with the same high-byte as the address of the
+		   insn, assume it's an address, and also if it's a non-zero
+		   non-0xff high-byte.  If this is a jsr or a jump, then
+		   it's definitely an address.  */
+		if (nbytes == 4
+		    && (highbyte == ((addr >> 24) & 0xff)
+			|| (highbyte != 0 && highbyte != 0xff)
+			|| info->insn_type == dis_branch
+			|| info->insn_type == dis_jsr))
+		  {
+		    /* Finish off and output previous formatted bytes.  */
+		    *tp = 0;
+		    tp = temp;
+		    if (temp[0])
+		      (*info->fprintf_func) (info->stream, "%s", temp);
+
+		    (*info->print_address_func) ((bfd_vma) number, info);
+
+		    info->target = number;
+		  }
+		else
+		  tp = format_hex (number, tp, disdata);
+	      }
+	  }
+	else
+	  {
+	    /* Not an immediate number.  Then this is a (possibly
+	       prefixed) memory operand.  */
+	    if (info->insn_type != dis_nonbranch)
+	      {
+		int mode_size
+		  = 1 << ((insn >> 4)
+			  & (opcodep->args[0] == 'z' ? 1 : 3));
+		int size;
+		info->insn_type = dis_dref;
+		info->flags |= CRIS_DIS_FLAG_MEMREF;
+
+		if (opcodep->imm_oprnd_size == SIZE_FIX_32)
+		  size = 4;
+		else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
+		  {
+		    const struct cris_spec_reg *sregp
+		      = spec_reg_info ((insn >> 12) & 15, disdata->distype);
+
+		    /* FIXME: Improve error handling; should have been caught
+		       earlier.  */
+		    if (sregp == NULL)
+		      size = 4;
+		    else
+		      size = sregp->reg_size;
+		  }
+		else
+		  size = mode_size;
+
+		info->data_size = size;
+	      }
+
+	    *tp++ = '[';
+
+	    if (prefix_opcodep
+		/* We don't match dip with a postincremented field
+		   as a side-effect address mode.  */
+		&& ((insn & 0x400) == 0
+		    || prefix_opcodep->match != DIP_OPCODE))
+	      {
+		if (insn & 0x400)
+		  {
+		    tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
+		    *tp++ = '=';
+		  }
+
+
+		/* We mainly ignore the prefix format string when the
+		   address-mode syntax is output.  */
+		switch (prefix_opcodep->match)
+		  {
+		  case DIP_OPCODE:
+		    /* It's [r], [r+] or [pc+].  */
+		    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
+		      {
+			/* It's [pc+].  This cannot possibly be anything
+			   but an address.  */
+			unsigned long number
+			  = prefix_buffer[2] + prefix_buffer[3] * 256
+			  + prefix_buffer[4] * 65536
+			  + prefix_buffer[5] * 0x1000000;
+
+			info->target = (bfd_vma) number;
+
+			/* Finish off and output previous formatted
+			   data.  */
+			*tp = 0;
+			tp = temp;
+			if (temp[0])
+			  (*info->fprintf_func) (info->stream, "%s", temp);
+
+			(*info->print_address_func) ((bfd_vma) number, info);
+		      }
+		    else
+		      {
+			/* For a memref in an address, we use target2.
+			   In this case, target is zero.  */
+			info->flags
+			  |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
+			      | CRIS_DIS_FLAG_MEM_TARGET2_MEM);
+
+			info->target2 = prefix_insn & 15;
+
+			*tp++ = '[';
+			tp = format_reg (disdata, prefix_insn & 15, tp,
+					 with_reg_prefix);
+			if (prefix_insn & 0x400)
+			  *tp++ = '+';
+			*tp++ = ']';
+		      }
+		    break;
+
+		  case BDAP_QUICK_OPCODE:
+		    {
+		      int number;
+
+		      number = prefix_buffer[0];
+		      if (number > 127)
+			number -= 256;
+
+		      /* Output "reg+num" or, if num < 0, "reg-num".  */
+		      tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
+				       with_reg_prefix);
+		      if (number >= 0)
+			*tp++ = '+';
+		      tp = format_dec (number, tp, 1);
+
+		      info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
+		      info->target = (prefix_insn >> 12) & 15;
+		      info->target2 = (bfd_vma) number;
+		      break;
+		    }
+
+		  case BIAP_OPCODE:
+		    /* Output "r+R.m".  */
+		    tp = format_reg (disdata, prefix_insn & 15, tp,
+				     with_reg_prefix);
+		    *tp++ = '+';
+		    tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
+				     with_reg_prefix);
+		    *tp++ = '.';
+		    *tp++ = mode_char[(prefix_insn >> 4) & 3];
+
+		    info->flags
+		      |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
+			  | CRIS_DIS_FLAG_MEM_TARGET_IS_REG
+
+			  | ((prefix_insn & 0x8000)
+			     ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4
+			     : ((prefix_insn & 0x8000)
+				? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0)));
+
+		    /* Is it the casejump?  It's a "adds.w [pc+r%d.w],pc".  */
+		    if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f)
+		      /* Then start interpreting data as offsets.  */
+		      case_offset_counter = no_of_case_offsets;
+		    break;
+
+		  case BDAP_INDIR_OPCODE:
+		    /* Output "r+s.m", or, if "s" is [pc+], "r+s" or
+		       "r-s".  */
+		    tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
+				     with_reg_prefix);
+
+		    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
+		      {
+			long number;
+			unsigned int nbytes;
+
+			/* It's a value.  Get its size.  */
+			int mode_size = 1 << ((prefix_insn >> 4) & 3);
+
+			if (mode_size == 1)
+			  nbytes = 2;
+			else
+			  nbytes = mode_size;
+
+			switch (nbytes)
+			  {
+			  case 1:
+			    number = prefix_buffer[2];
+			    if (number > 127)
+			      number -= 256;
+			    break;
+
+			  case 2:
+			    number = prefix_buffer[2] + prefix_buffer[3] * 256;
+			    if (number > 32767)
+			      number -= 65536;
+			    break;
+
+			  case 4:
+			    number
+			      = prefix_buffer[2] + prefix_buffer[3] * 256
+			      + prefix_buffer[4] * 65536
+			      + prefix_buffer[5] * 0x1000000;
+			    break;
+
+			  default:
+			    strcpy (tp, "bug");
+			    tp += 3;
+			    number = 42;
+			  }
+
+			info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
+			info->target2 = (bfd_vma) number;
+
+			/* If the size is dword, then assume it's an
+			   address.  */
+			if (nbytes == 4)
+			  {
+			    /* Finish off and output previous formatted
+			       bytes.  */
+			    *tp++ = '+';
+			    *tp = 0;
+			    tp = temp;
+			    (*info->fprintf_func) (info->stream, "%s", temp);
+
+			    (*info->print_address_func) ((bfd_vma) number, info);
+			  }
+			else
+			  {
+			    if (number >= 0)
+			      *tp++ = '+';
+			    tp = format_dec (number, tp, 1);
+			  }
+		      }
+		    else
+		      {
+			/* Output "r+[R].m" or "r+[R+].m".  */
+			*tp++ = '+';
+			*tp++ = '[';
+			tp = format_reg (disdata, prefix_insn & 15, tp,
+					 with_reg_prefix);
+			if (prefix_insn & 0x400)
+			  *tp++ = '+';
+			*tp++ = ']';
+			*tp++ = '.';
+			*tp++ = mode_char[(prefix_insn >> 4) & 3];
+
+			info->flags
+			  |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
+			      | CRIS_DIS_FLAG_MEM_TARGET2_MEM
+			      | CRIS_DIS_FLAG_MEM_TARGET_IS_REG
+
+			      | (((prefix_insn >> 4) == 2)
+				 ? 0
+				 : (((prefix_insn >> 4) & 3) == 1
+				    ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD
+				    : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE)));
+		      }
+		    break;
+
+		  default:
+		    (*info->fprintf_func) (info->stream, "?prefix-bug");
+		  }
+
+		/* To mark that the prefix is used, reset it.  */
+		prefix_opcodep = NULL;
+	      }
+	    else
+	      {
+		tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
+
+		info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
+		info->target = insn & 15;
+
+		if (insn & 0x400)
+		  *tp++ = '+';
+	      }
+	    *tp++ = ']';
+	  }
+	break;
+
+      case 'x':
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
+	*tp++ = '.';
+	*tp++ = mode_char[(insn >> 4) & 3];
+	break;
+
+      case 'I':
+	tp = format_dec (insn & 63, tp, 0);
+	break;
+
+      case 'b':
+	{
+	  int where = buffer[2] + buffer[3] * 256;
+
+	  if (where > 32767)
+	    where -= 65536;
+
+	  where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4);
+
+	  if (insn == BA_PC_INCR_OPCODE)
+	    info->insn_type = dis_branch;
+	  else
+	    info->insn_type = dis_condbranch;
+
+	  info->target = (bfd_vma) where;
+
+	  *tp = 0;
+	  tp = temp;
+	  (*info->fprintf_func) (info->stream, "%s%s ",
+				 temp, cris_cc_strings[insn >> 12]);
+
+	  (*info->print_address_func) ((bfd_vma) where, info);
+	}
+      break;
+
+    case 'c':
+      tp = format_dec (insn & 31, tp, 0);
+      break;
+
+    case 'C':
+      tp = format_dec (insn & 15, tp, 0);
+      break;
+
+    case 'o':
+      {
+	long offset = insn & 0xfe;
+	bfd_vma target;
+
+	if (insn & 1)
+	  offset |= ~0xff;
+
+	if (opcodep->match == BA_QUICK_OPCODE)
+	  info->insn_type = dis_branch;
+	else
+	  info->insn_type = dis_condbranch;
+
+	target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset;
+	info->target = target;
+	*tp = 0;
+	tp = temp;
+	(*info->fprintf_func) (info->stream, "%s", temp);
+	(*info->print_address_func) (target, info);
+      }
+      break;
+
+    case 'Q':
+    case 'O':
+      {
+	long number = buffer[0];
+
+	if (number > 127)
+	  number = number - 256;
+
+	tp = format_dec (number, tp, 1);
+	*tp++ = ',';
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
+      }
+      break;
+
+    case 'f':
+      tp = print_flags (disdata, insn, tp);
+      break;
+
+    case 'i':
+      tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
+      break;
+
+    case 'P':
+      {
+	const struct cris_spec_reg *sregp
+	  = spec_reg_info ((insn >> 12) & 15, disdata->distype);
+
+	if (sregp->name == NULL)
+	  /* Should have been caught as a non-match eariler.  */
+	  *tp++ = '?';
+	else
+	  {
+	    if (with_reg_prefix)
+	      *tp++ = REGISTER_PREFIX_CHAR;
+	    strcpy (tp, sregp->name);
+	    tp += strlen (tp);
+	  }
+      }
+      break;
+
+    default:
+      strcpy (tp, "???");
+      tp += 3;
+    }
+  }
+
+  *tp = 0;
+
+  if (prefix_opcodep)
+    (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")",
+			   prefix_opcodep->name, prefix_opcodep->args);
+
+  (*info->fprintf_func) (info->stream, "%s", temp);
+
+  /* Get info for matching case-tables, if we don't have any active.
+     We assume that the last constant seen is used; either in the insn
+     itself or in a "move.d const,rN, sub.d rN,rM"-like sequence.  */
+  if (TRACE_CASE && case_offset_counter == 0)
+    {
+      if (CONST_STRNEQ (opcodep->name, "sub"))
+	case_offset = last_immediate;
+
+      /* It could also be an "add", if there are negative case-values.  */
+      else if (CONST_STRNEQ (opcodep->name, "add"))
+	/* The first case is the negated operand to the add.  */
+	case_offset = -last_immediate;
+
+      /* A bound insn will tell us the number of cases.  */
+      else if (CONST_STRNEQ (opcodep->name, "bound"))
+	no_of_case_offsets = last_immediate + 1;
+
+      /* A jump or jsr or branch breaks the chain of insns for a
+	 case-table, so assume default first-case again.  */
+      else if (info->insn_type == dis_jsr
+	       || info->insn_type == dis_branch
+	       || info->insn_type == dis_condbranch)
+	case_offset = 0;
+    }
+}
+
+
+/* Print the CRIS instruction at address memaddr on stream.  Returns
+   length of the instruction, in bytes.  Prefix register names with `$' if
+   WITH_REG_PREFIX.  */
+
+static int
+print_insn_cris_generic (bfd_vma memaddr,
+			 disassemble_info *info,
+			 bfd_boolean with_reg_prefix)
+{
+  int nbytes;
+  unsigned int insn;
+  const struct cris_opcode *matchedp;
+  int advance = 0;
+  struct cris_disasm_data *disdata
+    = (struct cris_disasm_data *) info->private_data;
+
+  /* No instruction will be disassembled as longer than this number of
+     bytes; stacked prefixes will not be expanded.  */
+  unsigned char buffer[MAX_BYTES_PER_CRIS_INSN];
+  unsigned char *bufp;
+  int status = 0;
+  bfd_vma addr;
+
+  /* There will be an "out of range" error after the last instruction.
+     Reading pairs of bytes in decreasing number, we hope that we will get
+     at least the amount that we will consume.
+
+     If we can't get any data, or we do not get enough data, we print
+     the error message.  */
+
+  nbytes = info->buffer_length;
+  if (nbytes > MAX_BYTES_PER_CRIS_INSN)
+	  nbytes = MAX_BYTES_PER_CRIS_INSN;
+  status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);  
+
+  /* If we did not get all we asked for, then clear the rest.
+     Hopefully this makes a reproducible result in case of errors.  */
+  if (nbytes != MAX_BYTES_PER_CRIS_INSN)
+    memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes);
+
+  addr = memaddr;
+  bufp = buffer;
+
+  /* Set some defaults for the insn info.  */
+  info->insn_info_valid = 1;
+  info->branch_delay_insns = 0;
+  info->data_size = 0;
+  info->insn_type = dis_nonbranch;
+  info->flags = 0;
+  info->target = 0;
+  info->target2 = 0;
+
+  /* If we got any data, disassemble it.  */
+  if (nbytes != 0)
+    {
+      matchedp = NULL;
+
+      insn = bufp[0] + bufp[1] * 256;
+
+      /* If we're in a case-table, don't disassemble the offsets.  */
+      if (TRACE_CASE && case_offset_counter != 0)
+	{
+	  info->insn_type = dis_noninsn;
+	  advance += 2;
+
+	  /* If to print data as offsets, then shortcut here.  */
+	  (*info->fprintf_func) (info->stream, "case %ld%s: -> ",
+				 case_offset + no_of_case_offsets
+				 - case_offset_counter,
+				 case_offset_counter == 1 ? "/default" :
+				 "");
+
+	  (*info->print_address_func) ((bfd_vma)
+				       ((short) (insn)
+					+ (long) (addr
+						  - (no_of_case_offsets
+						     - case_offset_counter)
+						  * 2)), info);
+	  case_offset_counter--;
+
+	  /* The default case start (without a "sub" or "add") must be
+	     zero.  */
+	  if (case_offset_counter == 0)
+	    case_offset = 0;
+	}
+      else if (insn == 0)
+	{
+	  /* We're often called to disassemble zeroes.  While this is a
+	     valid "bcc .+2" insn, it is also useless enough and enough
+	     of a nuiscance that we will just output "bcc .+2" for it
+	     and signal it as a noninsn.  */
+	  (*info->fprintf_func) (info->stream,
+				 disdata->distype == cris_dis_v32
+				 ? "bcc ." : "bcc .+2");
+	  info->insn_type = dis_noninsn;
+	  advance += 2;
+	}
+      else
+	{
+	  const struct cris_opcode *prefix_opcodep = NULL;
+	  unsigned char *prefix_buffer = bufp;
+	  unsigned int prefix_insn = insn;
+	  int prefix_size = 0;
+
+	  matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata);
+
+	  /* Check if we're supposed to write out prefixes as address
+	     modes and if this was a prefix.  */
+	  if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p')
+	    {
+	      /* If it's a prefix, put it into the prefix vars and get the
+		 main insn.  */
+	      prefix_size = bytes_to_skip (prefix_insn, matchedp,
+					   disdata->distype, NULL);
+	      prefix_opcodep = matchedp;
+
+	      insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;
+	      matchedp = get_opcode_entry (insn, prefix_insn, disdata);
+
+	      if (matchedp != NULL)
+		{
+		  addr += prefix_size;
+		  bufp += prefix_size;
+		  advance += prefix_size;
+		}
+	      else
+		{
+		  /* The "main" insn wasn't valid, at least not when
+		     prefixed.  Put back things enough to output the
+		     prefix insn only, as a normal insn.  */
+		  matchedp = prefix_opcodep;
+		  insn = prefix_insn;
+		  prefix_opcodep = NULL;
+		}
+	    }
+
+	  if (matchedp == NULL)
+	    {
+	      (*info->fprintf_func) (info->stream, "??0x%x", insn);
+	      advance += 2;
+
+	      info->insn_type = dis_noninsn;
+	    }
+	  else
+	    {
+	      advance
+		+= bytes_to_skip (insn, matchedp, disdata->distype,
+				  prefix_opcodep);
+
+	      /* The info_type and assorted fields will be set according
+		 to the operands.   */
+	      print_with_operands (matchedp, insn, bufp, addr, info,
+				   prefix_opcodep, prefix_insn,
+				   prefix_buffer, with_reg_prefix);
+	    }
+	}
+    }
+  else
+    info->insn_type = dis_noninsn;
+
+  /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error
+     status when reading that much, and the insn decoding indicated a
+     length exceeding what we read, there is an error.  */
+  if (status != 0 && (nbytes == 0 || advance > nbytes))
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  /* Max supported insn size with one folded prefix insn.  */
+  info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN;
+
+  /* I would like to set this to a fixed value larger than the actual
+     number of bytes to print in order to avoid spaces between bytes,
+     but objdump.c (2.9.1) does not like that, so we print 16-bit
+     chunks, which is the next choice.  */
+  info->bytes_per_chunk = 2;
+
+  /* Printing bytes in order of increasing addresses makes sense,
+     especially on a little-endian target.
+     This is completely the opposite of what you think; setting this to
+     BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N
+     we want.  */
+  info->display_endian = BFD_ENDIAN_BIG;
+
+  return advance;
+}
+
+/* Disassemble, prefixing register names with `$'.  CRIS v0..v10.  */
+static int
+print_insn_cris_with_register_prefix (bfd_vma vma,
+				      disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+    return -1;
+  return print_insn_cris_generic (vma, info, true);
+}
+/* Disassemble, prefixing register names with `$'.  CRIS v32.  */
+
+static int
+print_insn_crisv32_with_register_prefix (bfd_vma vma,
+					 disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, true);
+}
+
+#if 0
+/* Disassemble, prefixing register names with `$'.
+   Common v10 and v32 subset.  */
+
+static int
+print_insn_crisv10_v32_with_register_prefix (bfd_vma vma,
+					     disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, true);
+}
+
+/* Disassemble, no prefixes on register names.  CRIS v0..v10.  */
+
+static int
+print_insn_cris_without_register_prefix (bfd_vma vma,
+					 disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+    return -1;
+  return print_insn_cris_generic (vma, info, false);
+}
+
+/* Disassemble, no prefixes on register names.  CRIS v32.  */
+
+static int
+print_insn_crisv32_without_register_prefix (bfd_vma vma,
+					    disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, false);
+}
+
+/* Disassemble, no prefixes on register names.
+   Common v10 and v32 subset.  */
+
+static int
+print_insn_crisv10_v32_without_register_prefix (bfd_vma vma,
+						disassemble_info *info)
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, false);
+}
+#endif
+
+int
+print_insn_crisv10 (bfd_vma vma,
+		    disassemble_info *info)
+{
+  return print_insn_cris_with_register_prefix(vma, info);
+}
+
+int
+print_insn_crisv32 (bfd_vma vma,
+		    disassemble_info *info)
+{
+  return print_insn_crisv32_with_register_prefix(vma, info);
+}
+
+/* Return a disassembler-function that prints registers with a `$' prefix,
+   or one that prints registers without a prefix.
+   FIXME: We should improve the solution to avoid the multitude of
+   functions seen above.  */
+#if 0
+disassembler_ftype
+cris_get_disassembler (bfd *abfd)
+{
+  /* If there's no bfd in sight, we return what is valid as input in all
+     contexts if fed back to the assembler: disassembly *with* register
+     prefix.  Unfortunately this will be totally wrong for v32.  */
+  if (abfd == NULL)
+    return print_insn_cris_with_register_prefix;
+
+  if (bfd_get_symbol_leading_char (abfd) == 0)
+    {
+      if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+	return print_insn_crisv32_with_register_prefix;
+      if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+	return print_insn_crisv10_v32_with_register_prefix;
+
+      /* We default to v10.  This may be specifically specified in the
+	 bfd mach, but is also the default setting.  */
+      return print_insn_cris_with_register_prefix;
+    }
+
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+    return print_insn_crisv32_without_register_prefix;
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+    return print_insn_crisv10_v32_without_register_prefix;
+  return print_insn_cris_without_register_prefix;
+}
+#endif
+/* Local variables:
+   eval: (c-set-style "gnu")
+   indent-tabs-mode: t
+   End:  */
diff --git a/qemu-0.15.x/cursor.c b/qemu-0.15.x/cursor.c
new file mode 100644
index 0000000..dfb9eef
--- /dev/null
+++ b/qemu-0.15.x/cursor.c
@@ -0,0 +1,210 @@
+#include "qemu-common.h"
+#include "console.h"
+
+#include "cursor_hidden.xpm"
+#include "cursor_left_ptr.xpm"
+
+/* for creating built-in cursors */
+static QEMUCursor *cursor_parse_xpm(const char *xpm[])
+{
+    QEMUCursor *c;
+    uint32_t ctab[128];
+    unsigned int width, height, colors, chars;
+    unsigned int line = 0, i, r, g, b, x, y, pixel;
+    char name[16];
+    uint8_t idx;
+
+    /* parse header line: width, height, #colors, #chars */
+    if (sscanf(xpm[line], "%d %d %d %d", &width, &height, &colors, &chars) != 4) {
+        fprintf(stderr, "%s: header parse error: \"%s\"\n",
+                __FUNCTION__, xpm[line]);
+        return NULL;
+    }
+    if (chars != 1) {
+        fprintf(stderr, "%s: chars != 1 not supported\n", __FUNCTION__);
+        return NULL;
+    }
+    line++;
+
+    /* parse color table */
+    for (i = 0; i < colors; i++, line++) {
+        if (sscanf(xpm[line], "%c c %15s", &idx, name) == 2) {
+            if (sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3) {
+                ctab[idx] = (0xff << 24) | (b << 16) | (g << 8) | r;
+                continue;
+            }
+            if (strcmp(name, "None") == 0) {
+                ctab[idx] = 0x00000000;
+                continue;
+            }
+        }
+        fprintf(stderr, "%s: color parse error: \"%s\"\n",
+                __FUNCTION__, xpm[line]);
+        return NULL;
+    }
+
+    /* parse pixel data */
+    c = cursor_alloc(width, height);
+    for (pixel = 0, y = 0; y < height; y++, line++) {
+        for (x = 0; x < height; x++, pixel++) {
+            idx = xpm[line][x];
+            c->data[pixel] = ctab[idx];
+        }
+    }
+    return c;
+}
+
+/* nice for debugging */
+void cursor_print_ascii_art(QEMUCursor *c, const char *prefix)
+{
+    uint32_t *data = c->data;
+    int x,y;
+
+    for (y = 0; y < c->height; y++) {
+        fprintf(stderr, "%s: %2d: |", prefix, y);
+        for (x = 0; x < c->width; x++, data++) {
+            if ((*data & 0xff000000) != 0xff000000) {
+                fprintf(stderr, " "); /* transparent */
+            } else if ((*data & 0x00ffffff) == 0x00ffffff) {
+                fprintf(stderr, "."); /* white */
+            } else if ((*data & 0x00ffffff) == 0x00000000) {
+                fprintf(stderr, "X"); /* black */
+            } else {
+                fprintf(stderr, "o"); /* other */
+            }
+        }
+        fprintf(stderr, "|\n");
+    }
+}
+
+QEMUCursor *cursor_builtin_hidden(void)
+{
+    QEMUCursor *c;
+
+    c = cursor_parse_xpm(cursor_hidden_xpm);
+    return c;
+}
+
+QEMUCursor *cursor_builtin_left_ptr(void)
+{
+    QEMUCursor *c;
+
+    c = cursor_parse_xpm(cursor_left_ptr_xpm);
+    return c;
+}
+
+QEMUCursor *cursor_alloc(int width, int height)
+{
+    QEMUCursor *c;
+    int datasize = width * height * sizeof(uint32_t);
+
+    c = qemu_mallocz(sizeof(QEMUCursor) + datasize);
+    c->width  = width;
+    c->height = height;
+    c->refcount = 1;
+    return c;
+}
+
+void cursor_get(QEMUCursor *c)
+{
+    c->refcount++;
+}
+
+void cursor_put(QEMUCursor *c)
+{
+    if (c == NULL)
+        return;
+    c->refcount--;
+    if (c->refcount)
+        return;
+    qemu_free(c);
+}
+
+int cursor_get_mono_bpl(QEMUCursor *c)
+{
+    return (c->width + 7) / 8;
+}
+
+void cursor_set_mono(QEMUCursor *c,
+                     uint32_t foreground, uint32_t background, uint8_t *image,
+                     int transparent, uint8_t *mask)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if (transparent && mask[x/8] & bit) {
+                *data = 0x00000000;
+            } else if (!transparent && !(mask[x/8] & bit)) {
+                *data = 0x00000000;
+            } else if (image[x/8] & bit) {
+                *data = 0xff000000 | foreground;
+            } else {
+                *data = 0xff000000 | background;
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        mask  += bpl;
+        image += bpl;
+    }
+}
+
+void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    memset(image, 0, bpl * c->height);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if (((*data & 0xff000000) == 0xff000000) &&
+                ((*data & 0x00ffffff) == foreground)) {
+                image[x/8] |= bit;
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        image += bpl;
+    }
+}
+
+void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    memset(mask, 0, bpl * c->height);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if ((*data & 0xff000000) != 0xff000000) {
+                if (transparent != 0) {
+                    mask[x/8] |= bit;
+                }
+            } else {
+                if (transparent == 0) {
+                    mask[x/8] |= bit;
+                }
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        mask += bpl;
+    }
+}
diff --git a/qemu-0.15.x/cursor_hidden.xpm b/qemu-0.15.x/cursor_hidden.xpm
new file mode 100644
index 0000000..354e7a9
--- /dev/null
+++ b/qemu-0.15.x/cursor_hidden.xpm
@@ -0,0 +1,37 @@
+/* XPM */
+static const char *cursor_hidden_xpm[] = {
+    "32 32 1 1",
+    "  c None",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+};
diff --git a/qemu-0.15.x/cursor_left_ptr.xpm b/qemu-0.15.x/cursor_left_ptr.xpm
new file mode 100644
index 0000000..6c9ada9
--- /dev/null
+++ b/qemu-0.15.x/cursor_left_ptr.xpm
@@ -0,0 +1,39 @@
+/* XPM */
+static const char *cursor_left_ptr_xpm[] = {
+    "32 32 3 1",
+    "X c #000000",
+    ". c #ffffff",
+    "  c None",
+    "X                               ",
+    "XX                              ",
+    "X.X                             ",
+    "X..X                            ",
+    "X...X                           ",
+    "X....X                          ",
+    "X.....X                         ",
+    "X......X                        ",
+    "X.......X                       ",
+    "X........X                      ",
+    "X.....XXXXX                     ",
+    "X..X..X                         ",
+    "X.X X..X                        ",
+    "XX  X..X                        ",
+    "X    X..X                       ",
+    "     X..X                       ",
+    "      X..X                      ",
+    "      X..X                      ",
+    "       XX                       ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+    "                                ",
+};
diff --git a/qemu-0.15.x/cutils.c b/qemu-0.15.x/cutils.c
new file mode 100644
index 0000000..f9a7e36
--- /dev/null
+++ b/qemu-0.15.x/cutils.c
@@ -0,0 +1,411 @@
+/*
+ * Simple C functions to supplement the C library
+ *
+ * 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 "qemu-common.h"
+#include "host-utils.h"
+#include <math.h>
+
+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';
+}
+
+/* strcat and truncate. */
+char *pstrcat(char *buf, int buf_size, const char *s)
+{
+    int len;
+    len = strlen(buf);
+    if (len < buf_size)
+        pstrcpy(buf + len, buf_size - len, s);
+    return buf;
+}
+
+int strstart(const char *str, const char *val, const char **ptr)
+{
+    const char *p, *q;
+    p = str;
+    q = val;
+    while (*q != '\0') {
+        if (*p != *q)
+            return 0;
+        p++;
+        q++;
+    }
+    if (ptr)
+        *ptr = p;
+    return 1;
+}
+
+int stristart(const char *str, const char *val, const char **ptr)
+{
+    const char *p, *q;
+    p = str;
+    q = val;
+    while (*q != '\0') {
+        if (qemu_toupper(*p) != qemu_toupper(*q))
+            return 0;
+        p++;
+        q++;
+    }
+    if (ptr)
+        *ptr = p;
+    return 1;
+}
+
+/* XXX: use host strnlen if available ? */
+int qemu_strnlen(const char *s, int max_len)
+{
+    int i;
+
+    for(i = 0; i < max_len; i++) {
+        if (s[i] == '\0') {
+            break;
+        }
+    }
+    return i;
+}
+
+time_t mktimegm(struct tm *tm)
+{
+    time_t t;
+    int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
+    if (m < 3) {
+        m += 12;
+        y--;
+    }
+    t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + 
+                 y / 400 - 719469);
+    t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
+    return t;
+}
+
+int qemu_fls(int i)
+{
+    return 32 - clz32(i);
+}
+
+/*
+ * Make sure data goes on disk, but if possible do not bother to
+ * write out the inode just for timestamp updates.
+ *
+ * Unfortunately even in 2009 many operating systems do not support
+ * fdatasync and have to fall back to fsync.
+ */
+int qemu_fdatasync(int fd)
+{
+#ifdef CONFIG_FDATASYNC
+    return fdatasync(fd);
+#else
+    return fsync(fd);
+#endif
+}
+
+/* io vectors */
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
+{
+    qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec));
+    qiov->niov = 0;
+    qiov->nalloc = alloc_hint;
+    qiov->size = 0;
+}
+
+void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
+{
+    int i;
+
+    qiov->iov = iov;
+    qiov->niov = niov;
+    qiov->nalloc = -1;
+    qiov->size = 0;
+    for (i = 0; i < niov; i++)
+        qiov->size += iov[i].iov_len;
+}
+
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
+{
+    assert(qiov->nalloc != -1);
+
+    if (qiov->niov == qiov->nalloc) {
+        qiov->nalloc = 2 * qiov->nalloc + 1;
+        qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+    }
+    qiov->iov[qiov->niov].iov_base = base;
+    qiov->iov[qiov->niov].iov_len = len;
+    qiov->size += len;
+    ++qiov->niov;
+}
+
+/*
+ * Copies iovecs from src to the end of dst. It starts copying after skipping
+ * the given number of bytes in src and copies until src is completely copied
+ * or the total size of the copied iovec reaches size.The size of the last
+ * copied iovec is changed in order to fit the specified total size if it isn't
+ * a perfect fit already.
+ */
+void qemu_iovec_copy(QEMUIOVector *dst, QEMUIOVector *src, uint64_t skip,
+    size_t size)
+{
+    int i;
+    size_t done;
+    void *iov_base;
+    uint64_t iov_len;
+
+    assert(dst->nalloc != -1);
+
+    done = 0;
+    for (i = 0; (i < src->niov) && (done != size); i++) {
+        if (skip >= src->iov[i].iov_len) {
+            /* Skip the whole iov */
+            skip -= src->iov[i].iov_len;
+            continue;
+        } else {
+            /* Skip only part (or nothing) of the iov */
+            iov_base = (uint8_t*) src->iov[i].iov_base + skip;
+            iov_len = src->iov[i].iov_len - skip;
+            skip = 0;
+        }
+
+        if (done + iov_len > size) {
+            qemu_iovec_add(dst, iov_base, size - done);
+            break;
+        } else {
+            qemu_iovec_add(dst, iov_base, iov_len);
+        }
+        done += iov_len;
+    }
+}
+
+void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size)
+{
+    qemu_iovec_copy(dst, src, 0, size);
+}
+
+void qemu_iovec_destroy(QEMUIOVector *qiov)
+{
+    assert(qiov->nalloc != -1);
+
+    qemu_free(qiov->iov);
+}
+
+void qemu_iovec_reset(QEMUIOVector *qiov)
+{
+    assert(qiov->nalloc != -1);
+
+    qiov->niov = 0;
+    qiov->size = 0;
+}
+
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
+{
+    uint8_t *p = (uint8_t *)buf;
+    int i;
+
+    for (i = 0; i < qiov->niov; ++i) {
+        memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
+        p += qiov->iov[i].iov_len;
+    }
+}
+
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
+{
+    const uint8_t *p = (const uint8_t *)buf;
+    size_t copy;
+    int i;
+
+    for (i = 0; i < qiov->niov && count; ++i) {
+        copy = count;
+        if (copy > qiov->iov[i].iov_len)
+            copy = qiov->iov[i].iov_len;
+        memcpy(qiov->iov[i].iov_base, p, copy);
+        p     += copy;
+        count -= copy;
+    }
+}
+
+void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count)
+{
+    size_t n;
+    int i;
+
+    for (i = 0; i < qiov->niov && count; ++i) {
+        n = MIN(count, qiov->iov[i].iov_len);
+        memset(qiov->iov[i].iov_base, c, n);
+        count -= n;
+    }
+}
+
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+                            size_t skip)
+{
+    int i;
+    size_t done;
+    void *iov_base;
+    uint64_t iov_len;
+
+    done = 0;
+    for (i = 0; (i < qiov->niov) && (done != count); i++) {
+        if (skip >= qiov->iov[i].iov_len) {
+            /* Skip the whole iov */
+            skip -= qiov->iov[i].iov_len;
+            continue;
+        } else {
+            /* Skip only part (or nothing) of the iov */
+            iov_base = (uint8_t*) qiov->iov[i].iov_base + skip;
+            iov_len = qiov->iov[i].iov_len - skip;
+            skip = 0;
+        }
+
+        if (done + iov_len > count) {
+            memset(iov_base, c, count - done);
+            break;
+        } else {
+            memset(iov_base, c, iov_len);
+        }
+        done += iov_len;
+    }
+}
+
+#ifndef _WIN32
+/* Sets a specific flag */
+int fcntl_setfl(int fd, int flag)
+{
+    int flags;
+
+    flags = fcntl(fd, F_GETFL);
+    if (flags == -1)
+        return -errno;
+
+    if (fcntl(fd, F_SETFL, flags | flag) == -1)
+        return -errno;
+
+    return 0;
+}
+#endif
+
+/*
+ * Convert string to bytes, allowing either B/b for bytes, K/k for KB,
+ * M/m for MB, G/g for GB or T/t for TB. Default without any postfix
+ * is MB. End pointer will be returned in *end, if not NULL. A valid
+ * value must be terminated by whitespace, ',' or '\0'. Return -1 on
+ * error.
+ */
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+{
+    int64_t retval = -1;
+    char *endptr;
+    unsigned char c, d;
+    int mul_required = 0;
+    double val, mul, integral, fraction;
+
+    errno = 0;
+    val = strtod(nptr, &endptr);
+    if (isnan(val) || endptr == nptr || errno != 0) {
+        goto fail;
+    }
+    fraction = modf(val, &integral);
+    if (fraction != 0) {
+        mul_required = 1;
+    }
+    /*
+     * Any whitespace character is fine for terminating the number,
+     * in addition we accept ',' to handle strings where the size is
+     * part of a multi token argument.
+     */
+    c = *endptr;
+    d = c;
+    if (qemu_isspace(c) || c == '\0' || c == ',') {
+        c = 0;
+        if (default_suffix) {
+            d = default_suffix;
+        } else {
+            d = c;
+        }
+    }
+    switch (qemu_toupper(d)) {
+    case STRTOSZ_DEFSUFFIX_B:
+        mul = 1;
+        if (mul_required) {
+            goto fail;
+        }
+        break;
+    case STRTOSZ_DEFSUFFIX_KB:
+        mul = 1 << 10;
+        break;
+    case 0:
+        if (mul_required) {
+            goto fail;
+        }
+    case STRTOSZ_DEFSUFFIX_MB:
+        mul = 1ULL << 20;
+        break;
+    case STRTOSZ_DEFSUFFIX_GB:
+        mul = 1ULL << 30;
+        break;
+    case STRTOSZ_DEFSUFFIX_TB:
+        mul = 1ULL << 40;
+        break;
+    default:
+        goto fail;
+    }
+    /*
+     * If not terminated by whitespace, ',', or \0, increment endptr
+     * to point to next character, then check that we are terminated
+     * by an appropriate separating character, ie. whitespace, ',', or
+     * \0. If not, we are seeing trailing garbage, thus fail.
+     */
+    if (c != 0) {
+        endptr++;
+        if (!qemu_isspace(*endptr) && *endptr != ',' && *endptr != 0) {
+            goto fail;
+        }
+    }
+    if ((val * mul >= INT64_MAX) || val < 0) {
+        goto fail;
+    }
+    retval = val * mul;
+
+fail:
+    if (end) {
+        *end = endptr;
+    }
+
+    return retval;
+}
+
+int64_t strtosz(const char *nptr, char **end)
+{
+    return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
+}
diff --git a/qemu-0.15.x/darwin-user/commpage.c b/qemu-0.15.x/darwin-user/commpage.c
new file mode 100644
index 0000000..cc29bdd
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/commpage.c
@@ -0,0 +1,357 @@
+ /*
+ *  Commpage syscalls
+ *
+ *  Copyright (c) 2006 Pierre d'Herbemont
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/message.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <libkern/OSAtomic.h>
+
+#include "qemu.h"
+
+//#define DEBUG_COMMPAGE
+
+#ifdef DEBUG_COMMPAGE
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); } while(0)
+#endif
+
+/********************************************************************
+ *   Commpage definitions
+ */
+#ifdef TARGET_I386
+/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
+# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
+# define COMMPAGE_SIZE  (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
+#elif defined(TARGET_PPC)
+/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
+# define COMMPAGE_START (-8*4096)
+# define COMMPAGE_SIZE  (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
+#endif
+
+void do_compare_and_swap32(void *cpu_env, int num);
+void do_compare_and_swap64(void *cpu_env, int num);
+void do_add_atomic_word32(void *cpu_env, int num);
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
+void do_nanotime(void *cpu_env, int num);
+
+void unimpl_commpage(void *cpu_env, int num);
+
+typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+                uint32_t arg8);
+typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
+                uint32_t arg2, uint32_t arg3,  uint32_t arg4, uint32_t arg5,
+                uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+#define HAS_PTR  0x10
+#define NO_PTR   0x20
+#define CALL_DIRECT   0x1
+#define CALL_INDIRECT 0x2
+
+#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
+    { #name, offset, nargs, options, (commpage_8args_function_t)func }
+
+struct commpage_entry {
+    char * name;
+    int offset;
+    int nargs;
+    char options;
+    commpage_8args_function_t function;
+};
+
+static inline int commpage_code_num(struct commpage_entry *entry)
+{
+    if((entry->options & HAS_PTR))
+        return entry->offset + 4;
+    else
+        return entry->offset;
+}
+
+static inline int commpage_is_indirect(struct commpage_entry *entry)
+{
+    return !(entry->options & CALL_DIRECT);
+}
+
+/********************************************************************
+ *   Commpage entry
+ */
+static struct commpage_entry commpage_entries[] =
+{
+    COMMPAGE_ENTRY(compare_and_swap32,    0, 0x080,  do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
+    COMMPAGE_ENTRY(compare_and_swap64,    0, 0x0c0,  do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
+    COMMPAGE_ENTRY(enqueue,               0, 0x100,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(dequeue,               0, 0x140,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(memory_barrier,        0, 0x180,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(add_atomic_word32,     0, 0x1a0,  do_add_atomic_word32,  CALL_INDIRECT | HAS_PTR),
+    COMMPAGE_ENTRY(add_atomic_word64,     0, 0x1c0,  unimpl_commpage,       CALL_INDIRECT | HAS_PTR),
+
+    COMMPAGE_ENTRY(mach_absolute_time,    0, 0x200,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(spinlock_try,          1, 0x220,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(spinlock_lock,         1, 0x260,  OSSpinLockLock,        CALL_DIRECT),
+    COMMPAGE_ENTRY(spinlock_unlock,       1, 0x2a0,  OSSpinLockUnlock,      CALL_DIRECT),
+    COMMPAGE_ENTRY(pthread_getspecific,   0, 0x2c0,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(gettimeofday,          1, 0x2e0,  do_cgettimeofday,      CALL_INDIRECT),
+    COMMPAGE_ENTRY(sys_dcache_flush,      0, 0x4e0,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(pthread_self,          0, 0x580,  unimpl_commpage,       CALL_INDIRECT),
+
+    COMMPAGE_ENTRY(relinquish,            0, 0x5c0,  unimpl_commpage,       CALL_INDIRECT),
+
+#ifdef TARGET_I386
+    COMMPAGE_ENTRY(bts,                   0, 0x5e0,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(btc,                   0, 0x5f0,  unimpl_commpage,       CALL_INDIRECT),
+#endif
+
+    COMMPAGE_ENTRY(bzero,                 2, 0x600,  bzero,                 CALL_DIRECT),
+    COMMPAGE_ENTRY(bcopy,                 3, 0x780,  bcopy,                 CALL_DIRECT),
+    COMMPAGE_ENTRY(memcpy,                3, 0x7a0,  memcpy,                CALL_DIRECT),
+
+#ifdef TARGET_I386
+    COMMPAGE_ENTRY(old_nanotime,          0, 0xf80,  do_nanotime,           CALL_INDIRECT),
+    COMMPAGE_ENTRY(memset_pattern,        0, 0xf80,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(long_copy,             0, 0x1200, unimpl_commpage,       CALL_INDIRECT),
+
+    COMMPAGE_ENTRY(sysintegrity,          0, 0x1600, unimpl_commpage,       CALL_INDIRECT),
+
+    COMMPAGE_ENTRY(nanotime,              0, 0x1700, do_nanotime,           CALL_INDIRECT),
+#elif TARGET_PPC
+    COMMPAGE_ENTRY(compare_and_swap32b,   0, 0xf80,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(compare_and_swap64b,   0, 0xfc0,  unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(memset_pattern,        0, 0x1000, unimpl_commpage,       CALL_INDIRECT),
+    COMMPAGE_ENTRY(bigcopy,               0, 0x1140, unimpl_commpage,       CALL_INDIRECT),
+#endif
+};
+
+
+/********************************************************************
+ *   Commpage backdoor
+ */
+static inline void print_commpage_entry(struct commpage_entry entry)
+{
+    printf("@0x%x %s\n", entry.offset, entry.name);
+}
+
+static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
+{
+#ifdef TARGET_I386
+    char * commpage = (char*)(COMMPAGE_START+entry.offset);
+    int c = 0;
+    if(entry.options & HAS_PTR)
+    {
+        commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
+        commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
+        commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
+        commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
+    }
+    commpage[c++] = 0xcd;
+    commpage[c++] = 0x79; /* int 0x79 */
+    commpage[c++] = 0xc3; /* ret */
+#else
+    qerror("can't install the commpage on this arch\n");
+#endif
+}
+
+/********************************************************************
+ *   Commpage initialization
+ */
+void commpage_init(void)
+{
+#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(_ARCH_PPC) ^ defined(TARGET_PPC))
+    int i;
+    void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
+                           PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    if((int)commpage != COMMPAGE_START)
+        qerror("can't allocate the commpage\n");
+
+    bzero(commpage, COMMPAGE_SIZE);
+
+    /* XXX: commpage data not handled */
+
+    for(i = 0; i < ARRAY_SIZE(commpage_entries); i++)
+        install_commpage_backdoor_for_entry(commpage_entries[i]);
+#else
+    /* simply map our pages so they can be executed
+       XXX: we don't really want to do that since in the ppc on ppc situation we may
+       not able to run commpages host optimized instructions (like G5's on a G5),
+       hence this is sometimes a broken fix. */
+    page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
+#endif
+}
+
+/********************************************************************
+ *   Commpage implementation
+ */
+void do_compare_and_swap32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+    uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
+    uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
+    DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
+
+    if(old == tswap32(*value))
+    {
+        uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
+        *value = tswap32(new);
+        /* set zf flag */
+        ((CPUX86State*)cpu_env)->eflags |= 0x40;
+    }
+    else
+    {
+        ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
+        /* unset zf flag */
+        ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+    }
+#else
+    qerror("do_compare_and_swap32 unimplemented");
+#endif
+}
+
+void do_compare_and_swap64(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+    /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
+    uint64_t old, new, swapped_val;
+    uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
+    old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
+
+    DPRINTF("commpage: compare_and_swap64(%" PRIx64 ",new,%p)\n", old, value);
+    swapped_val = tswap64(*value);
+
+    if(old == swapped_val)
+    {
+        new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
+        *value = tswap64(new);
+        /* set zf flag */
+        ((CPUX86State*)cpu_env)->eflags |= 0x40;
+    }
+    else
+    {
+        ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
+        ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
+        /* unset zf flag */
+        ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+    }
+#else
+    qerror("do_compare_and_swap64 unimplemented");
+#endif
+}
+
+void do_add_atomic_word32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+    uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
+    uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
+    uint32_t swapped_value = tswap32(*value);
+
+    DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
+
+    /* old value in EAX */
+    ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
+    *value = tswap32(swapped_value + amt);
+#else
+    qerror("do_add_atomic_word32 unimplemented");
+#endif
+}
+
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
+{
+#ifdef TARGET_I386
+    extern int __commpage_gettimeofday(struct timeval *);
+    DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
+    struct timeval *time = (struct timeval *)arg1;
+    int ret = __commpage_gettimeofday(time);
+    tswap32s((uint32_t*)&time->tv_sec);
+    tswap32s((uint32_t*)&time->tv_usec);
+    ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
+#else
+    qerror("do_gettimeofday unimplemented");
+#endif
+}
+
+void do_nanotime(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+    uint64_t t = mach_absolute_time();
+    ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
+    ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
+#else
+    qerror("do_nanotime unimplemented");
+#endif
+}
+
+void unimpl_commpage(void *cpu_env, int num)
+{
+    qerror("qemu: commpage function 0x%x not implemented\n", num);
+}
+
+/********************************************************************
+ *   do_commpage - called by the main cpu loop
+ */
+void
+do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+                uint32_t arg8)
+{
+    int i, found = 0;
+
+    arg1 = tswap32(arg1);
+    arg2 = tswap32(arg2);
+    arg3 = tswap32(arg3);
+    arg4 = tswap32(arg4);
+    arg5 = tswap32(arg5);
+    arg6 = tswap32(arg6);
+    arg7 = tswap32(arg7);
+    arg8 = tswap32(arg8);
+
+    num = num-COMMPAGE_START-2;
+
+    for(i = 0; i < ARRAY_SIZE(commpage_entries); i++) {
+        if( num == commpage_code_num(&commpage_entries[i]) )
+        {
+            DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
+            found = 1;
+            if(commpage_is_indirect(&commpage_entries[i]))
+            {
+                commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
+                function(cpu_env, num, arg1, arg2, arg3,
+                    arg4, arg5, arg6, arg7, arg8);
+            }
+            else
+            {
+                commpage_entries[i].function(arg1, arg2, arg3,
+                    arg4, arg5, arg6, arg7, arg8);
+            }
+            break;
+        }
+    }
+
+    if(!found)
+    {
+        gemu_log("qemu: commpage function 0x%x not defined\n", num);
+        gdb_handlesig (cpu_env, SIGTRAP);
+        exit(-1);
+    }
+}
diff --git a/qemu-0.15.x/darwin-user/ioctls.h b/qemu-0.15.x/darwin-user/ioctls.h
new file mode 100644
index 0000000..dc73af2
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/ioctls.h
@@ -0,0 +1,4 @@
+     /* emulated ioctl list */
+
+     IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
diff --git a/qemu-0.15.x/darwin-user/ioctls_types.h b/qemu-0.15.x/darwin-user/ioctls_types.h
new file mode 100644
index 0000000..014561a
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/ioctls_types.h
@@ -0,0 +1 @@
+STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
diff --git a/qemu-0.15.x/darwin-user/machload.c b/qemu-0.15.x/darwin-user/machload.c
new file mode 100644
index 0000000..3bc3b65
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/machload.c
@@ -0,0 +1,902 @@
+/*
+ *  Mach-O object file loading
+ *
+ *  Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qemu.h"
+#include "disas.h"
+
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+
+//#define DEBUG_MACHLOAD
+
+#ifdef DEBUG_MACHLOAD
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); } while(0)
+#endif
+
+# define check_mach_header(x) (x.magic == MH_CIGAM)
+
+extern const char *interp_prefix;
+
+/* we don't have a good implementation for this */
+#define DONT_USE_DYLD_SHARED_MAP
+
+/* Pass extra arg to DYLD for debug */
+//#define ACTIVATE_DYLD_TRACE
+
+//#define OVERRIDE_DYLINKER
+
+#ifdef OVERRIDE_DYLINKER
+# ifdef TARGET_I386
+#  define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld"
+# else
+#  define DYLINKER_NAME "/usr/lib/dyld"
+# endif
+#endif
+
+/* XXX: in an include */
+struct nlist_extended
+{
+    union {
+        char *n_name;
+        long  n_strx;
+    } n_un;
+    unsigned char n_type;
+    unsigned char n_sect;
+    short st_desc;
+    unsigned long st_value;
+    unsigned long st_size;
+};
+
+/* Print symbols in gdb */
+void *macho_text_sect = 0;
+int   macho_offset = 0;
+
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh);
+
+#ifdef TARGET_I386
+typedef struct mach_i386_thread_state {
+    unsigned int    eax;
+    unsigned int    ebx;
+    unsigned int    ecx;
+    unsigned int    edx;
+    unsigned int    edi;
+    unsigned int    esi;
+    unsigned int    ebp;
+    unsigned int    esp;
+    unsigned int    ss;
+    unsigned int    eflags;
+    unsigned int    eip;
+    unsigned int    cs;
+    unsigned int    ds;
+    unsigned int    es;
+    unsigned int    fs;
+    unsigned int    gs;
+} mach_i386_thread_state_t;
+
+void bswap_i386_thread_state(struct mach_i386_thread_state *ts)
+{
+    bswap32s((uint32_t*)&ts->eax);
+    bswap32s((uint32_t*)&ts->ebx);
+    bswap32s((uint32_t*)&ts->ecx);
+    bswap32s((uint32_t*)&ts->edx);
+    bswap32s((uint32_t*)&ts->edi);
+    bswap32s((uint32_t*)&ts->esi);
+    bswap32s((uint32_t*)&ts->ebp);
+    bswap32s((uint32_t*)&ts->esp);
+    bswap32s((uint32_t*)&ts->ss);
+    bswap32s((uint32_t*)&ts->eflags);
+    bswap32s((uint32_t*)&ts->eip);
+    bswap32s((uint32_t*)&ts->cs);
+    bswap32s((uint32_t*)&ts->ds);
+    bswap32s((uint32_t*)&ts->es);
+    bswap32s((uint32_t*)&ts->fs);
+    bswap32s((uint32_t*)&ts->gs);
+}
+#define target_thread_state mach_i386_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_I386
+#define TARGET_CPU_NAME "i386"
+#endif
+
+#ifdef TARGET_PPC
+struct mach_ppc_thread_state {
+    unsigned int srr0;      /* Instruction address register (PC) */
+    unsigned int srr1;    /* Machine state register (supervisor) */
+    unsigned int r0;
+    unsigned int r1;
+    unsigned int r2;
+    unsigned int r3;
+    unsigned int r4;
+    unsigned int r5;
+    unsigned int r6;
+    unsigned int r7;
+    unsigned int r8;
+    unsigned int r9;
+    unsigned int r10;
+    unsigned int r11;
+    unsigned int r12;
+    unsigned int r13;
+    unsigned int r14;
+    unsigned int r15;
+    unsigned int r16;
+    unsigned int r17;
+    unsigned int r18;
+    unsigned int r19;
+    unsigned int r20;
+    unsigned int r21;
+    unsigned int r22;
+    unsigned int r23;
+    unsigned int r24;
+    unsigned int r25;
+    unsigned int r26;
+    unsigned int r27;
+    unsigned int r28;
+    unsigned int r29;
+    unsigned int r30;
+    unsigned int r31;
+
+    unsigned int cr;        /* Condition register */
+    unsigned int xer;    /* User's integer exception register */
+    unsigned int lr;    /* Link register */
+    unsigned int ctr;    /* Count register */
+    unsigned int mq;    /* MQ register (601 only) */
+
+    unsigned int vrsave;    /* Vector Save Register */
+};
+
+void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts)
+{
+    bswap32s((uint32_t*)&ts->srr0);
+    bswap32s((uint32_t*)&ts->srr1);
+    bswap32s((uint32_t*)&ts->r0);
+    bswap32s((uint32_t*)&ts->r1);
+    bswap32s((uint32_t*)&ts->r2);
+    bswap32s((uint32_t*)&ts->r3);
+    bswap32s((uint32_t*)&ts->r4);
+    bswap32s((uint32_t*)&ts->r5);
+    bswap32s((uint32_t*)&ts->r6);
+    bswap32s((uint32_t*)&ts->r7);
+    bswap32s((uint32_t*)&ts->r8);
+    bswap32s((uint32_t*)&ts->r9);
+    bswap32s((uint32_t*)&ts->r10);
+    bswap32s((uint32_t*)&ts->r11);
+    bswap32s((uint32_t*)&ts->r12);
+    bswap32s((uint32_t*)&ts->r13);
+    bswap32s((uint32_t*)&ts->r14);
+    bswap32s((uint32_t*)&ts->r15);
+    bswap32s((uint32_t*)&ts->r16);
+    bswap32s((uint32_t*)&ts->r17);
+    bswap32s((uint32_t*)&ts->r18);
+    bswap32s((uint32_t*)&ts->r19);
+    bswap32s((uint32_t*)&ts->r20);
+    bswap32s((uint32_t*)&ts->r21);
+    bswap32s((uint32_t*)&ts->r22);
+    bswap32s((uint32_t*)&ts->r23);
+    bswap32s((uint32_t*)&ts->r24);
+    bswap32s((uint32_t*)&ts->r25);
+    bswap32s((uint32_t*)&ts->r26);
+    bswap32s((uint32_t*)&ts->r27);
+    bswap32s((uint32_t*)&ts->r28);
+    bswap32s((uint32_t*)&ts->r29);
+    bswap32s((uint32_t*)&ts->r30);
+    bswap32s((uint32_t*)&ts->r31);
+
+    bswap32s((uint32_t*)&ts->cr);
+    bswap32s((uint32_t*)&ts->xer);
+    bswap32s((uint32_t*)&ts->lr);
+    bswap32s((uint32_t*)&ts->ctr);
+    bswap32s((uint32_t*)&ts->mq);
+
+    bswap32s((uint32_t*)&ts->vrsave);
+}
+
+#define target_thread_state mach_ppc_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_POWERPC
+#define TARGET_CPU_NAME "PowerPC"
+#endif
+
+struct target_thread_command {
+    unsigned long    cmd;    /* LC_THREAD or  LC_UNIXTHREAD */
+    unsigned long    cmdsize;    /* total size of this command */
+    unsigned long flavor;    /* flavor of thread state */
+    unsigned long count;        /* count of longs in thread state */
+    struct target_thread_state state;  /* thread state for this flavor */
+};
+
+void bswap_tc(struct target_thread_command *tc)
+{
+    bswap32s((uint32_t*)(&tc->flavor));
+    bswap32s((uint32_t*)&tc->count);
+#if defined(TARGET_I386)
+    bswap_i386_thread_state(&tc->state);
+#elif defined(TARGET_PPC)
+    bswap_ppc_thread_state(&tc->state);
+#else
+# error unknown TARGET_CPU_TYPE
+#endif
+}
+
+void bswap_mh(struct mach_header *mh)
+{
+    bswap32s((uint32_t*)(&mh->magic));
+    bswap32s((uint32_t*)&mh->cputype);
+    bswap32s((uint32_t*)&mh->cpusubtype);
+    bswap32s((uint32_t*)&mh->filetype);
+    bswap32s((uint32_t*)&mh->ncmds);
+    bswap32s((uint32_t*)&mh->sizeofcmds);
+    bswap32s((uint32_t*)&mh->flags);
+}
+
+void bswap_lc(struct load_command *lc)
+{
+    bswap32s((uint32_t*)&lc->cmd);
+    bswap32s((uint32_t*)&lc->cmdsize);
+}
+
+
+void bswap_fh(struct fat_header *fh)
+{
+    bswap32s((uint32_t*)&fh->magic);
+    bswap32s((uint32_t*)&fh->nfat_arch);
+}
+
+void bswap_fa(struct fat_arch *fa)
+{
+    bswap32s((uint32_t*)&fa->cputype);
+    bswap32s((uint32_t*)&fa->cpusubtype);
+    bswap32s((uint32_t*)&fa->offset);
+    bswap32s((uint32_t*)&fa->size);
+    bswap32s((uint32_t*)&fa->align);
+}
+
+void bswap_segcmd(struct segment_command *sc)
+{
+    bswap32s((uint32_t*)&sc->vmaddr);
+    bswap32s((uint32_t*)&sc->vmsize);
+    bswap32s((uint32_t*)&sc->fileoff);
+    bswap32s((uint32_t*)&sc->filesize);
+    bswap32s((uint32_t*)&sc->maxprot);
+    bswap32s((uint32_t*)&sc->initprot);
+    bswap32s((uint32_t*)&sc->nsects);
+    bswap32s((uint32_t*)&sc->flags);
+}
+
+void bswap_symtabcmd(struct symtab_command *stc)
+{
+    bswap32s((uint32_t*)&stc->cmd);
+    bswap32s((uint32_t*)&stc->cmdsize);
+    bswap32s((uint32_t*)&stc->symoff);
+    bswap32s((uint32_t*)&stc->nsyms);
+    bswap32s((uint32_t*)&stc->stroff);
+    bswap32s((uint32_t*)&stc->strsize);
+}
+
+void bswap_sym(struct nlist *n)
+{
+    bswap32s((uint32_t*)&n->n_un.n_strx);
+    bswap16s((uint16_t*)&n->n_desc);
+    bswap32s((uint32_t*)&n->n_value);
+}
+
+int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap)
+{
+    int entry;
+    if(need_bswap)
+        bswap_tc(tc);
+#if defined(TARGET_I386)
+    entry = tc->state.eip;
+    DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n",
+            tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp,
+            tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es,
+            tc->state.fs, tc->state.gs );
+#define reg_copy(reg)   regs->reg = tc->state.reg
+    if(regs)
+    {
+        reg_copy(eax);
+        reg_copy(ebx);
+        reg_copy(ecx);
+        reg_copy(edx);
+
+        reg_copy(edi);
+        reg_copy(esi);
+
+        reg_copy(ebp);
+        reg_copy(esp);
+
+        reg_copy(eflags);
+        reg_copy(eip);
+    /*
+        reg_copy(ss);
+        reg_copy(cs);
+        reg_copy(ds);
+        reg_copy(es);
+        reg_copy(fs);
+        reg_copy(gs);*/
+    }
+#undef reg_copy
+#elif defined(TARGET_PPC)
+    entry =  tc->state.srr0;
+#endif
+    DPRINTF("load_thread: entry 0x%x\n", entry);
+    return entry;
+}
+
+int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap)
+{
+    int size;
+    char * dylinker_name;
+    size = dc->cmdsize - sizeof(struct dylinker_command);
+
+    if(need_bswap)
+        dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc);
+    else
+        dylinker_name = (char*)((dc->name.offset)+(int)dc);
+
+#ifdef OVERRIDE_DYLINKER
+    dylinker_name = DYLINKER_NAME;
+#else
+    if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1)
+        qerror("can't allocate the new dylinker name\n");
+#endif
+
+    DPRINTF("dylinker_name %s\n", dylinker_name);
+    return load_object(dylinker_name, NULL, NULL);
+}
+
+int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide)
+{
+    unsigned long addr = sc->vmaddr;
+    unsigned long size = sc->filesize;
+    unsigned long error = 0;
+
+    if(need_bswap)
+        bswap_segcmd(sc);
+
+    if(sc->vmaddr == 0)
+    {
+        DPRINTF("load_segment: sc->vmaddr == 0 returning\n");
+        return -1;
+    }
+
+    if (strcmp(sc->segname, "__PAGEZERO") == 0)
+    {
+        DPRINTF("load_segment: __PAGEZERO returning\n");
+        return -1;
+    }
+
+    /* Right now mmap memory */
+    /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */
+    DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide);
+
+    if(sc->filesize > 0)
+    {
+        int opt = 0;
+
+        if(fixed)
+            opt |= MAP_FIXED;
+
+        DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide);
+
+        addr = target_mmap(sc->vmaddr+slide, sc->filesize,  sc->initprot, opt, fd, mh_pos + sc->fileoff);
+
+        if(addr==-1)
+            qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+
+        error = addr-sc->vmaddr;
+    }
+    else
+    {
+        addr = sc->vmaddr+slide;
+        error = slide;
+    }
+
+    if(sc->vmsize > sc->filesize)
+    {
+        addr += sc->filesize;
+        size = sc->vmsize-sc->filesize;
+        addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+        if(addr==-1)
+            qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+    }
+
+    return error;
+}
+
+void *load_data(int fd, long offset, unsigned int size)
+{
+    char *data;
+
+    data = malloc(size);
+    if (!data)
+        return NULL;
+    lseek(fd, offset, SEEK_SET);
+    if (read(fd, data, size) != size) {
+        free(data);
+        return NULL;
+    }
+    return data;
+}
+
+/* load a mach-o object file */
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh)
+{
+    int need_bswap = 0;
+    int entry_point = 0;
+    int dyld_entry_point = 0;
+    int slide, mmapfixed;
+    int fd;
+    struct load_command *lcmds, *lc;
+    int is_fat = 0;
+    unsigned int i, magic;
+    int mach_hdr_pos = 0;
+    struct mach_header mach_hdr;
+
+    /* for symbol lookup whith -d flag. */
+    struct symtab_command *    symtabcmd = 0;
+    struct nlist_extended *symtab, *sym;
+    struct nlist     *symtab_std, *syment;
+    char            *strtab;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0)
+        qerror("can't open file '%s'", filename);
+
+    /* Read magic header.  */
+    if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
+        qerror("unable to read Magic of '%s'", filename);
+
+    /* Check Mach identification.  */
+    if(magic == MH_MAGIC)
+    {
+        is_fat = 0;
+        need_bswap = 0;
+    } else if (magic == MH_CIGAM)
+    {
+        is_fat = 0;
+        need_bswap = 1;
+    } else if (magic == FAT_MAGIC)
+    {
+        is_fat = 1;
+        need_bswap = 0;
+    } else if (magic == FAT_CIGAM)
+    {
+        is_fat = 1;
+        need_bswap = 1;
+    }
+    else
+        qerror("Not a Mach-O file.", filename);
+
+    DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]");
+    if(is_fat)
+    {
+        int found = 0;
+        struct fat_header fh;
+        struct fat_arch *fa;
+
+        lseek(fd, 0, SEEK_SET);
+
+        /* Read Fat header.  */
+        if (read(fd, &fh, sizeof (fh)) != sizeof (fh))
+            qerror("unable to read file header");
+
+        if(need_bswap)
+            bswap_fh(&fh);
+
+        /* Read Fat Arch.  */
+        fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch);
+
+        if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch)
+            qerror("unable to read file header");
+
+        for( i = 0; i < fh.nfat_arch; i++, fa++)
+        {
+            if(need_bswap)
+                bswap_fa(fa);
+            if(fa->cputype == TARGET_CPU_TYPE)
+            {
+                mach_hdr_pos = fa->offset;
+                lseek(fd, mach_hdr_pos, SEEK_SET);
+
+                /* Read Mach header.  */
+
+                if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header))
+                    qerror("unable to read file header");
+
+                if(mach_hdr.magic == MH_MAGIC)
+                    need_bswap = 0;
+                else if (mach_hdr.magic == MH_CIGAM)
+                    need_bswap = 1;
+                else
+                    qerror("Invalid mach header in Fat Mach-O File");
+                found = 1;
+                break;
+            }
+        }
+        if(!found)
+            qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME);
+    }
+    else
+    {
+        lseek(fd, 0, SEEK_SET);
+        /* Read Mach header */
+        if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
+            qerror("%s: unable to read file header", filename);
+    }
+
+    if(need_bswap)
+        bswap_mh(&mach_hdr);
+
+    if ((mach_hdr.cputype) != TARGET_CPU_TYPE)
+        qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME);
+
+
+    switch(mach_hdr.filetype)
+    {
+        case MH_EXECUTE:  break;
+        case MH_FVMLIB:
+        case MH_DYLIB:
+        case MH_DYLINKER: break;
+        default:
+            qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype);
+    }
+
+    /* read segment headers */
+    lcmds = malloc(mach_hdr.sizeofcmds);
+
+    if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds)
+            qerror("%s: unable to read load_command", filename);
+    slide = 0;
+    mmapfixed = 0;
+    for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++)
+    {
+
+        if(need_bswap)
+            bswap_lc(lc);
+        switch(lc->cmd)
+        {
+            case LC_SEGMENT:
+                /* The main_exe can't be relocated */
+                if(mach_hdr.filetype == MH_EXECUTE)
+                    mmapfixed = 1;
+
+                slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide);
+
+                /* other segment must be mapped according to slide exactly, if load_segment did something */
+                if(slide != -1)
+                    mmapfixed = 1;
+                else
+                    slide = 0; /* load_segment didn't map the segment */
+
+                if(mach_hdr.filetype == MH_EXECUTE && slide != 0)
+                    qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide);
+
+                if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0)
+                {
+                    /* Text section */
+                    if(mach_hdr.filetype == MH_EXECUTE)
+                    {
+                        /* return the mach_header */
+                        *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+                    }
+                    else
+                    {
+                        /* it is dyld save the section for gdb, we will be interested in dyld symbol
+                           while debuging */
+                        macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+                        macho_offset = slide;
+                    }
+                }
+                break;
+            case LC_LOAD_DYLINKER:
+                dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap );
+                break;
+            case LC_LOAD_DYLIB:
+                /* dyld will do that for us */
+                break;
+            case LC_THREAD:
+            case LC_UNIXTHREAD:
+                {
+                struct target_pt_regs * _regs;
+                if(mach_hdr.filetype == MH_DYLINKER)
+                    _regs = regs;
+                else
+                    _regs = 0;
+                entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap );
+                }
+                break;
+            case LC_SYMTAB:
+                /* Save the symtab and strtab */
+                symtabcmd = (struct symtab_command *)lc;
+                break;
+            case LC_ID_DYLINKER:
+            case LC_ID_DYLIB:
+            case LC_UUID:
+            case LC_DYSYMTAB:
+            case LC_TWOLEVEL_HINTS:
+            case LC_PREBIND_CKSUM:
+            case LC_SUB_LIBRARY:
+                break;
+            default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename);
+        }
+        lc = (struct load_command*)((int)(lc)+(lc->cmdsize));
+    }
+
+    if(symtabcmd)
+    {
+        if(need_bswap)
+            bswap_symtabcmd(symtabcmd);
+
+        symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist));
+        strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize);
+
+        symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms);
+
+        if(need_bswap)
+        {
+            for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++)
+                bswap_sym(syment);
+        }
+
+        for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++)
+        {
+            struct nlist *sym_follow, *sym_next = 0;
+            unsigned int j;
+            memset(sym, 0, sizeof(*sym));
+
+            sym->n_type = syment->n_type;
+            if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
+                continue;
+
+            memcpy(sym, syment, sizeof(*syment));
+
+            /* Find the following symbol in order to get the current symbol size */
+            for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) {
+                if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
+                    continue;
+                if(!sym_next) {
+                    sym_next = sym_follow;
+                    continue;
+                }
+                if(!(sym_next->n_value > sym_follow->n_value))
+                    continue;
+                sym_next = sym_follow;
+            }
+            if(sym_next)
+                sym->st_size = sym_next->n_value - sym->st_value;
+            else
+                sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */
+
+            sym->st_value += slide;
+        }
+
+        free((void*)symtab_std);
+
+        {
+            DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms);
+            struct syminfo *s;
+            s = malloc(sizeof(*s));
+            s->disas_symtab = symtab;
+            s->disas_strtab = strtab;
+            s->disas_num_syms = symtabcmd->nsyms;
+            s->next = syminfos;
+            syminfos = s;
+        }
+    }
+    close(fd);
+    if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point)
+        return dyld_entry_point;
+    else
+        return entry_point+slide;
+}
+
+extern unsigned long stack_size;
+
+unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
+{
+    unsigned long stack_base, error, size;
+    int i;
+    int * stack;
+    int argc, envc;
+
+    /* Create enough stack to hold everything.  If we don't use
+     * it for args, we'll use it for something else...
+     */
+    size = stack_size;
+
+    error = target_mmap(0,
+                        size + qemu_host_page_size,
+                        PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS,
+                        -1, 0);
+    if (error == -1)
+        qerror("stk mmap");
+
+    /* we reserve one extra page at the top of the stack as guard */
+    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+
+    stack_base = error + size;
+    stack = (void*)stack_base;
+/*
+ *    | STRING AREA |
+ *    +-------------+
+ *    |      0      |
+*    +-------------+
+ *    |  apple[n]   |
+ *    +-------------+
+ *           :
+ *    +-------------+
+ *    |  apple[0]   |
+ *    +-------------+
+ *    |      0      |
+ *    +-------------+
+ *    |    env[n]   |
+ *    +-------------+
+ *           :
+ *           :
+ *    +-------------+
+ *    |    env[0]   |
+ *    +-------------+
+ *    |      0      |
+ *    +-------------+
+ *    | arg[argc-1] |
+ *    +-------------+
+ *           :
+ *           :
+ *    +-------------+
+ *    |    arg[0]   |
+ *    +-------------+
+ *    |     argc    |
+ *    +-------------+
+ * sp->    |      mh     | address of where the a.out's file offset 0 is in memory
+ *    +-------------+
+*/
+    /* Construct the stack Stack grows down */
+    stack--;
+
+    /* XXX: string should go up there */
+
+    *stack = 0;
+    stack--;
+
+    /* Push the absolute path of our executable */
+    DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]);
+    stl(stack, (int) argv[0]);
+
+    stack--;
+
+    stl(stack, 0);
+    stack--;
+
+    /* Get envc */
+    for(envc = 0; env[envc]; envc++);
+
+    for(i = envc-1; i >= 0; i--)
+    {
+        DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]);
+        stl(stack, (int)env[i]);
+        stack--;
+
+        /* XXX: remove that when string will be on top of the stack */
+        page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID);
+    }
+
+    /* Add on the stack the interp_prefix choosen if so */
+    if(interp_prefix[0])
+    {
+        char *dyld_root;
+        asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix);
+        page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID);
+
+        stl(stack, (int)dyld_root);
+        stack--;
+    }
+
+#ifdef DONT_USE_DYLD_SHARED_MAP
+    {
+        char *shared_map_mode;
+        asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid");
+        page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID);
+
+        stl(stack, (int)shared_map_mode);
+        stack--;
+    }
+#endif
+
+#ifdef ACTIVATE_DYLD_TRACE
+    char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes",
+    "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes",
+    "DYLD_PRINT_INITIALIZERS=yes",
+    "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" };
+
+    char ** extra_env = malloc(sizeof(extra_env_static));
+    bcopy(extra_env_static, extra_env, sizeof(extra_env_static));
+    page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID);
+
+    for(i = 0; i<9; i++)
+    {
+        DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]);
+        stl(stack, (int) extra_env[i]);
+        stack--;
+    }
+#endif
+
+    stl(stack, 0);
+    stack--;
+
+    /* Get argc */
+    for(argc = 0; argv[argc]; argc++);
+
+    for(i = argc-1; i >= 0; i--)
+    {
+        DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]);
+        stl(stack, (int) argv[i]);
+        stack--;
+
+        /* XXX: remove that when string will be on top of the stack */
+        page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
+    }
+
+    DPRINTF("pushing argc %d \n", argc);
+    stl(stack, argc);
+    stack--;
+
+    DPRINTF("pushing mh 0x%x \n", (int)mh);
+    stl(stack, (int) mh);
+
+    /* Stack points on the mh */
+    return (unsigned long)stack;
+}
+
+int mach_exec(const char * filename, char ** argv, char ** envp,
+             struct target_pt_regs * regs)
+{
+    int entrypoint, stack;
+    void * mh; /* the Mach Header that will be  used by dyld */
+
+    DPRINTF("mach_exec at 0x%x\n", (int)mach_exec);
+
+    entrypoint = load_object(filename, regs, &mh);
+    stack = setup_arg_pages(mh, argv, envp);
+#if defined(TARGET_I386)
+    regs->eip = entrypoint;
+    regs->esp = stack;
+#elif defined(TARGET_PPC)
+    regs->nip = entrypoint;
+    regs->gpr[1] = stack;
+#endif
+    DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh);
+
+    if(!entrypoint)
+        qerror("%s: no entry point!\n", filename);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/darwin-user/main.c b/qemu-0.15.x/darwin-user/main.c
new file mode 100644
index 0000000..72307ad
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/main.c
@@ -0,0 +1,1026 @@
+/*
+ *  qemu user main
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *  Copyright (c) 2006 Pierre d'Herbemont
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+#define DEBUG_LOGFILE "/tmp/qemu.log"
+
+#ifdef __APPLE__
+#include <crt_externs.h>
+# define environ  (*_NSGetEnviron())
+#endif
+
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+
+int singlestep;
+
+const char *interp_prefix = "";
+
+asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
+
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+   we allocate a bigger stack. Need a better solution, for example
+   by remapping the process stack directly at the right place */
+unsigned long stack_size = 512 * 1024;
+
+void qerror(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fprintf(stderr, "\n");
+    exit(1);
+}
+
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
+int cpu_get_pic_interrupt(CPUState *env)
+{
+    return -1;
+}
+#ifdef TARGET_PPC
+
+static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+{
+    /* TO FIX */
+    return 0;
+}
+
+uint64_t cpu_ppc_load_tbl (CPUState *env)
+{
+    return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint64_t cpu_ppc_load_atbl (CPUState *env)
+{
+    return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_atbu (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+{
+    cpu_ppc_load_tbu(env);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
+{
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
+{
+    return -1;
+}
+
+#define EXCP_DUMP(env, fmt, ...)                                        \
+do {                                                                    \
+    fprintf(stderr, fmt , ## __VA_ARGS__);                              \
+    cpu_dump_state(env, stderr, fprintf, 0);                            \
+    qemu_log(fmt, ## __VA_ARGS__);                                      \
+    log_cpu_state(env, 0);                                              \
+} while (0)
+
+void cpu_loop(CPUPPCState *env)
+{
+    int trapnr;
+    uint32_t ret;
+    target_siginfo_t info;
+
+    for(;;) {
+        trapnr = cpu_ppc_exec(env);
+        switch(trapnr) {
+        case POWERPC_EXCP_NONE:
+            /* Just go on */
+            break;
+        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
+            cpu_abort(env, "Critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
+            cpu_abort(env, "Machine check exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSI:      /* Data storage exception                */
+#ifndef DAR
+/* To deal with multiple qemu header version as host for the darwin-user code */
+# define DAR SPR_DAR
+#endif
+            EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
+                      env->spr[SPR_DAR]);
+            /* Handle this via the gdb */
+            gdb_handlesig (env, SIGSEGV);
+
+            info.si_addr = (void*)env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
+            EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx "\n",
+                      env->spr[SPR_DAR]);
+            /* Handle this via the gdb */
+            gdb_handlesig (env, SIGSEGV);
+
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EXTERNAL: /* External input                        */
+            cpu_abort(env, "External interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
+            EXCP_DUMP(env, "Unaligned memory access\n");
+            info.si_errno = 0;
+            info.si_code = BUS_ADRALN;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
+            /* XXX: check this */
+            switch (env->error_code & ~0xF) {
+            case POWERPC_EXCP_FP:
+                EXCP_DUMP(env, "Floating point program exception\n");
+                /* Set FX */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_FP_OX:
+                    info.si_code = FPE_FLTOVF;
+                    break;
+                case POWERPC_EXCP_FP_UX:
+                    info.si_code = FPE_FLTUND;
+                    break;
+                case POWERPC_EXCP_FP_ZX:
+                case POWERPC_EXCP_FP_VXZDZ:
+                    info.si_code = FPE_FLTDIV;
+                    break;
+                case POWERPC_EXCP_FP_XX:
+                    info.si_code = FPE_FLTRES;
+                    break;
+                case POWERPC_EXCP_FP_VXSOFT:
+                    info.si_code = FPE_FLTINV;
+                    break;
+                case POWERPC_EXCP_FP_VXSNAN:
+                case POWERPC_EXCP_FP_VXISI:
+                case POWERPC_EXCP_FP_VXIDI:
+                case POWERPC_EXCP_FP_VXIMZ:
+                case POWERPC_EXCP_FP_VXVC:
+                case POWERPC_EXCP_FP_VXSQRT:
+                case POWERPC_EXCP_FP_VXCVI:
+                    info.si_code = FPE_FLTSUB;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+                              env->error_code);
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_INVAL:
+                EXCP_DUMP(env, "Invalid instruction\n");
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_INVAL_INVAL:
+                    info.si_code = ILL_ILLOPC;
+                    break;
+                case POWERPC_EXCP_INVAL_LSWX:
+                    info.si_code = ILL_ILLOPN;
+                    break;
+                case POWERPC_EXCP_INVAL_SPR:
+                    info.si_code = ILL_PRVREG;
+                    break;
+                case POWERPC_EXCP_INVAL_FP:
+                    info.si_code = ILL_COPROC;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = ILL_ILLADR;
+                    break;
+                }
+                /* Handle this via the gdb */
+                gdb_handlesig (env, SIGSEGV);
+                break;
+            case POWERPC_EXCP_PRIV:
+                EXCP_DUMP(env, "Privilege violation\n");
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_PRIV_OPC:
+                    info.si_code = ILL_PRVOPC;
+                    break;
+                case POWERPC_EXCP_PRIV_REG:
+                    info.si_code = ILL_PRVREG;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = ILL_PRVOPC;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_TRAP:
+                cpu_abort(env, "Tried to call a TRAP\n");
+                break;
+            default:
+                /* Should not happen ! */
+                cpu_abort(env, "Unknown program exception (%02x)\n",
+                          env->error_code);
+                break;
+            }
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
+            EXCP_DUMP(env, "No floating point allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
+            cpu_abort(env, "Syscall exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
+            EXCP_DUMP(env, "No APU instruction allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
+            cpu_abort(env, "Decrementer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
+            cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
+            cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
+            cpu_abort(env, "Data TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
+            cpu_abort(env, "Instruction TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DEBUG:    /* Debug interrupt                       */
+            gdb_handlesig (env, SIGTRAP);
+            break;
+        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
+            EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
+            cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
+            cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
+            cpu_abort(env, "Doorbell interrupt while in user mode. "
+                       "Aborting\n");
+            break;
+        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
+            cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RESET:    /* System reset exception                */
+            cpu_abort(env, "Reset interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
+            cpu_abort(env, "Data segment exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
+            cpu_abort(env, "Instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
+            cpu_abort(env, "Hypervisor decrementer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
+            /* Nothing to do:
+             * we use this exception to emulate step-by-step execution mode.
+             */
+            break;
+        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
+            cpu_abort(env, "Hypervisor data storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
+            cpu_abort(env, "Hypervisor instruction storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
+            cpu_abort(env, "Hypervisor data segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
+            cpu_abort(env, "Hypervisor instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
+            EXCP_DUMP(env, "No Altivec instructions allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
+            cpu_abort(env, "Programable interval timer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_IO:       /* IO error exception                    */
+            cpu_abort(env, "IO error exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
+            cpu_abort(env, "Run mode exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
+            cpu_abort(env, "Emulation trap exception not handled\n");
+            break;
+        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
+            cpu_abort(env, "Instruction fetch TLB exception "
+                      "while in user-mode. Aborting");
+            break;
+        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
+            cpu_abort(env, "Data load TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
+            cpu_abort(env, "Data store TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
+            cpu_abort(env, "Floating-point assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
+            cpu_abort(env, "Instruction address breakpoint exception "
+                      "not handled\n");
+            break;
+        case POWERPC_EXCP_SMI:      /* System management interrupt           */
+            cpu_abort(env, "System management interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
+            cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_PERFM:    /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
+            cpu_abort(env, "Vector assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
+            cpu_abort(env, "Soft patch exception not handled\n");
+            break;
+        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
+            cpu_abort(env, "Maintenance exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_STOP:     /* stop translation                      */
+            /* We did invalidate the instruction cache. Go on */
+            break;
+        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
+            /* We just stopped because of a branch. Go on */
+            break;
+        case POWERPC_EXCP_SYSCALL_USER:
+            /* system call in user-mode emulation */
+            /* system call */
+            if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+                ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
+                                      env->gpr[5], env->gpr[6], env->gpr[7],
+                                      env->gpr[8], env->gpr[9], env->gpr[10]*/);
+            else if(((int)env->gpr[0])<0)
+                ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+                                      env->gpr[5], env->gpr[6], env->gpr[7],
+                                      env->gpr[8], env->gpr[9], env->gpr[10]);
+            else
+                ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+                                        env->gpr[5], env->gpr[6], env->gpr[7],
+                                        env->gpr[8], env->gpr[9], env->gpr[10]);
+
+            /* Unix syscall error signaling */
+            if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+            {
+                if( (int)ret < 0 )
+                    env->nip += 0;
+                else
+                    env->nip += 4;
+            }
+
+            /* Return value */
+            env->gpr[3] = ret;
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        default:
+            cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+            break;
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+
+#ifdef TARGET_I386
+
+/***********************************************************/
+/* CPUX86 core interface */
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+void
+write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    stl((uint8_t *)ptr, e1);
+    stl((uint8_t *)ptr + 4, e2);
+}
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     unsigned long addr, unsigned int sel)
+{
+    unsigned int e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    stl((uint8_t *)ptr, e1);
+    stl((uint8_t *)ptr + 4, e2);
+}
+
+#define GDT_TABLE_SIZE 14
+#define LDT_TABLE_SIZE 15
+#define IDT_TABLE_SIZE 256
+#define TSS_SIZE 104
+uint64_t gdt_table[GDT_TABLE_SIZE];
+uint64_t ldt_table[LDT_TABLE_SIZE];
+uint64_t idt_table[IDT_TABLE_SIZE];
+uint32_t tss[TSS_SIZE];
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+/* ABI convention: after a syscall if there was an error the CF flag is set */
+static inline void set_error(CPUX86State *env, int ret)
+{
+    if(ret<0)
+        env->eflags = env->eflags | 0x1;
+    else
+        env->eflags &= ~0x1;
+    env->regs[R_EAX] = ret;
+}
+
+void cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    int ret;
+    uint8_t *pc;
+    target_siginfo_t info;
+
+    for(;;) {
+        trapnr = cpu_x86_exec(env);
+        uint32_t *params = (uint32_t *)env->regs[R_ESP];
+        switch(trapnr) {
+        case 0x79: /* Our commpage hack back door exit is here */
+            do_commpage(env,  env->eip,   *(params + 1), *(params + 2),
+                                          *(params + 3), *(params + 4),
+                                          *(params + 5), *(params + 6),
+                                          *(params + 7), *(params + 8));
+            break;
+        case 0x81: /* mach syscall */
+        {
+            ret = do_mach_syscall(env,  env->regs[R_EAX],
+                                          *(params + 1), *(params + 2),
+                                          *(params + 3), *(params + 4),
+                                          *(params + 5), *(params + 6),
+                                          *(params + 7), *(params + 8));
+            set_error(env, ret);
+            break;
+        }
+        case 0x90: /* unix backdoor */
+        {
+            /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
+            int saved_stack = env->regs[R_ESP];
+            env->regs[R_ESP] = env->regs[R_ECX];
+
+            ret = do_unix_syscall(env, env->regs[R_EAX]);
+
+            env->regs[R_ECX] = env->regs[R_ESP];
+            env->regs[R_ESP] = saved_stack;
+
+            set_error(env, ret);
+            break;
+        }
+        case 0x80: /* unix syscall */
+        {
+            ret = do_unix_syscall(env, env->regs[R_EAX]/*,
+                                          *(params + 1), *(params + 2),
+                                          *(params + 3), *(params + 4),
+                                          *(params + 5), *(params + 6),
+                                          *(params + 7), *(params + 8)*/);
+            set_error(env, ret);
+            break;
+        }
+        case 0x82: /* thread syscall */
+        {
+            ret = do_thread_syscall(env,  env->regs[R_EAX],
+                                          *(params + 1), *(params + 2),
+                                          *(params + 3), *(params + 4),
+                                          *(params + 5), *(params + 6),
+                                          *(params + 7), *(params + 8));
+            set_error(env, ret);
+            break;
+        }
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = BUS_NOOP;
+            info.si_addr = 0;
+            gdb_handlesig (env, SIGBUS);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP0D_GPF:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = SEGV_NOOP;
+            info.si_addr = 0;
+            gdb_handlesig (env, SIGSEGV);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1))
+                info.si_code = SEGV_MAPERR;
+            else
+                info.si_code = SEGV_ACCERR;
+            info.si_addr = (void*)env->cr[2];
+            gdb_handlesig (env, SIGSEGV);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP00_DIVZ:
+            /* division by zero */
+            info.si_signo = SIGFPE;
+            info.si_errno = 0;
+            info.si_code = FPE_INTDIV;
+            info.si_addr = (void*)env->eip;
+            gdb_handlesig (env, SIGFPE);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP01_SSTP:
+        case EXCP03_INT3:
+            info.si_signo = SIGTRAP;
+            info.si_errno = 0;
+            info.si_code = TRAP_BRKPT;
+            info.si_addr = (void*)env->eip;
+            gdb_handlesig (env, SIGTRAP);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = SEGV_NOOP;
+            info.si_addr = 0;
+            gdb_handlesig (env, SIGSEGV);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_ILLOPN;
+            info.si_addr = (void*)env->eip;
+            gdb_handlesig (env, SIGILL);
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TRAP_BRKPT;
+                    queue_signal(info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            pc = (void*)(env->segs[R_CS].base + env->eip);
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+                    (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+static void usage(void)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
+           "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
+           "Darwin CPU emulator (compiled for %s emulation)\n"
+           "\n"
+           "-h           print this help\n"
+           "-L path      set the %s library path (default='%s')\n"
+           "-s size      set the stack size in bytes (default=%ld)\n"
+           "\n"
+           "debug options:\n"
+           "-d options   activate log (logfile='%s')\n"
+           "-g wait for gdb on port 1234\n"
+           "-p pagesize  set the host page size to 'pagesize'\n",
+           "-singlestep  always run in singlestep mode\n"
+           TARGET_ARCH,
+           TARGET_ARCH,
+           interp_prefix,
+           stack_size,
+           DEBUG_LOGFILE);
+    exit(1);
+}
+
+/* XXX: currently only used for async signals (see signal.c) */
+CPUState *global_env;
+/* used only if single thread */
+CPUState *cpu_single_env = NULL;
+
+/* used to free thread contexts */
+TaskState *first_task_state;
+
+int main(int argc, char **argv)
+{
+    const char *filename;
+    const char *log_file = DEBUG_LOGFILE;
+    const char *log_mask = NULL;
+    struct target_pt_regs regs1, *regs = &regs1;
+    TaskState ts1, *ts = &ts1;
+    CPUState *env;
+    int optind;
+    short use_gdbstub = 0;
+    const char *r;
+    const char *cpu_model;
+
+    if (argc <= 1)
+        usage();
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+        r = argv[optind];
+        if (r[0] != '-')
+            break;
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        } else if (!strcmp(r, "d")) {
+            if (optind >= argc) {
+                break;
+            }
+            log_mask = argv[optind++];
+        } else if (!strcmp(r, "D")) {
+            if (optind >= argc) {
+                break;
+            }
+            log_file = argv[optind++];
+        } else if (!strcmp(r, "s")) {
+            r = argv[optind++];
+            stack_size = strtol(r, (char **)&r, 0);
+            if (stack_size <= 0)
+                usage();
+            if (*r == 'M')
+                stack_size *= 1024 * 1024;
+            else if (*r == 'k' || *r == 'K')
+                stack_size *= 1024;
+        } else if (!strcmp(r, "L")) {
+            interp_prefix = argv[optind++];
+        } else if (!strcmp(r, "p")) {
+            qemu_host_page_size = atoi(argv[optind++]);
+            if (qemu_host_page_size == 0 ||
+                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+                fprintf(stderr, "page size must be a power of two\n");
+                exit(1);
+            }
+        } else
+        if (!strcmp(r, "g")) {
+            use_gdbstub = 1;
+        } else if (!strcmp(r, "cpu")) {
+            cpu_model = argv[optind++];
+            if (strcmp(cpu_model, "?") == 0) {
+/* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list)
+                    cpu_list(stdout, &fprintf);
+#endif
+                exit(1);
+            }
+        } else if (!strcmp(r, "singlestep")) {
+            singlestep = 1;
+        } else
+        {
+            usage();
+        }
+    }
+
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    if (log_mask) {
+        int mask;
+        CPULogItem *item;
+
+        mask = cpu_str_to_log_mask(log_mask);
+        if (!mask) {
+            printf("Log items (comma separated):\n");
+            for (item = cpu_log_items; item->mask != 0; item++) {
+                printf("%-10s %s\n", item->name, item->help);
+            }
+            exit(1);
+        }
+        cpu_set_log(mask);
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+    filename = argv[optind];
+
+    /* Zero out regs */
+    memset(regs, 0, sizeof(struct target_pt_regs));
+
+    if (cpu_model == NULL) {
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+#elif defined(TARGET_PPC)
+#ifdef TARGET_PPC64
+        cpu_model = "970";
+#else
+        cpu_model = "750";
+#endif
+#else
+#error unsupported CPU
+#endif
+    }
+    
+    cpu_exec_init_all(0);
+    /* NOTE: we need to init the CPU at this stage to get
+       qemu_host_page_size */
+    env = cpu_init(cpu_model);
+    cpu_reset(env);
+
+    printf("Starting %s with qemu\n----------------\n", filename);
+
+    commpage_init();
+
+    if (mach_exec(filename, argv+optind, environ, regs) != 0) {
+    printf("Error loading %s\n", filename);
+    _exit(1);
+    }
+
+    syscall_init();
+    signal_init();
+    global_env = env;
+
+    /* build Task State */
+    memset(ts, 0, sizeof(TaskState));
+    env->opaque = ts;
+    ts->used = 1;
+
+#if defined(TARGET_I386)
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+
+    if (env->cpuid_features & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* darwin register setup */
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+
+    /* Darwin LDT setup */
+    /* 2 - User code segment
+       3 - User data segment
+       4 - User cthread */
+    bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
+    env->ldt.base = (uint32_t) ldt_table;
+    env->ldt.limit = sizeof(ldt_table) - 1;
+
+    write_dt(ldt_table + 2, 0, 0xfffff,
+             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+             (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+    write_dt(ldt_table + 3, 0, 0xfffff,
+             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+             (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+    write_dt(ldt_table + 4, 0, 0xfffff,
+             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+             (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+    /* Darwin GDT setup.
+     * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
+       now everything is done via  int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
+    bzero(gdt_table, sizeof(gdt_table));
+    env->gdt.base = (uint32_t)gdt_table;
+    env->gdt.limit = sizeof(gdt_table) - 1;
+
+    /* Set up a back door to handle sysenter syscalls (unix) */
+    char * syscallbackdoor = malloc(64);
+    page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
+
+    int i = 0;
+    syscallbackdoor[i++] = 0xcd;
+    syscallbackdoor[i++] = 0x90; /* int 0x90 */
+    syscallbackdoor[i++] = 0x0F;
+    syscallbackdoor[i++] = 0x35; /* sysexit */
+
+    /* Darwin sysenter/sysexit setup */
+    env->sysenter_cs = 0x1; //XXX
+    env->sysenter_eip = (int)syscallbackdoor;
+    env->sysenter_esp = (int)malloc(64);
+
+    /* Darwin TSS setup
+       This must match up with GDT[4] */
+    env->tr.base = (uint32_t) tss;
+    env->tr.limit = sizeof(tss) - 1;
+    env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
+    stw(tss + 2, 0x10);  // ss0 = 0x10 = GDT[2] = Kernel Data Segment
+
+    /* Darwin interrupt setup */
+    bzero(idt_table, sizeof(idt_table));
+    env->idt.base = (uint32_t) idt_table;
+    env->idt.limit = sizeof(idt_table) - 1;
+    set_idt(0, 0);
+    set_idt(1, 0);
+    set_idt(2, 0);
+    set_idt(3, 3);
+    set_idt(4, 3);
+    set_idt(5, 3);
+    set_idt(6, 0);
+    set_idt(7, 0);
+    set_idt(8, 0);
+    set_idt(9, 0);
+    set_idt(10, 0);
+    set_idt(11, 0);
+    set_idt(12, 0);
+    set_idt(13, 0);
+    set_idt(14, 0);
+    set_idt(15, 0);
+    set_idt(16, 0);
+    set_idt(17, 0);
+    set_idt(18, 0);
+    set_idt(19, 0);
+    /* Syscalls are done via
+        int 0x80 (unix) (rarely used)
+        int 0x81 (mach)
+        int 0x82 (thread)
+        int 0x83 (diag) (not handled here)
+        sysenter/sysexit (unix) -> we redirect that to int 0x90 */
+    set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
+    set_idt(0x80, 3); /* Unix Syscall */
+    set_idt(0x81, 3); /* Mach Syscalls */
+    set_idt(0x82, 3); /* thread Syscalls */
+
+    set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */
+
+
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+
+#elif defined(TARGET_PPC)
+    {
+        int i;
+
+#if defined(TARGET_PPC64)
+#if defined(TARGET_ABI32)
+        env->msr &= ~((target_ulong)1 << MSR_SF);
+#else
+        env->msr |= (target_ulong)1 << MSR_SF;
+#endif
+#endif
+        env->nip = regs->nip;
+        for(i = 0; i < 32; i++) {
+            env->gpr[i] = regs->gpr[i];
+        }
+    }
+#else
+#error unsupported target CPU
+#endif
+
+    if (use_gdbstub) {
+        printf("Waiting for gdb Connection on port 1234...\n");
+        gdbserver_start (1234);
+        gdb_handlesig(env, 0);
+    }
+
+    cpu_loop(env);
+    /* never exits */
+    return 0;
+}
diff --git a/qemu-0.15.x/darwin-user/mmap.c b/qemu-0.15.x/darwin-user/mmap.c
new file mode 100644
index 0000000..d840b28
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/mmap.c
@@ -0,0 +1,409 @@
+/*
+ *  mmap support for qemu
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+//#define DEBUG_MMAP
+
+/* NOTE: all the constants are the HOST ones */
+int target_mprotect(unsigned long start, unsigned long len, int prot)
+{
+    unsigned long end, host_start, host_end, addr;
+    int prot1, ret;
+
+#ifdef DEBUG_MMAP
+    printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
+           prot & PROT_READ ? 'r' : '-',
+           prot & PROT_WRITE ? 'w' : '-',
+           prot & PROT_EXEC ? 'x' : '-');
+#endif
+
+    if ((start & ~TARGET_PAGE_MASK) != 0)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+        return -EINVAL;
+    if (len == 0)
+        return 0;
+
+    host_start = start & qemu_host_page_mask;
+    host_end = HOST_PAGE_ALIGN(end);
+    if (start > host_start) {
+        /* handle host page containing start */
+        prot1 = prot;
+        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        if (host_end == host_start + qemu_host_page_size) {
+            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+                prot1 |= page_get_flags(addr);
+            }
+            end = host_end;
+        }
+        ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
+        if (ret != 0)
+            return ret;
+        host_start += qemu_host_page_size;
+    }
+    if (end < host_end) {
+        prot1 = prot;
+        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
+                       prot1 & PAGE_BITS);
+        if (ret != 0)
+            return ret;
+        host_end -= qemu_host_page_size;
+    }
+
+    /* handle the pages in the middle */
+    if (host_start < host_end) {
+        ret = mprotect((void *)host_start, host_end - host_start, prot);
+        if (ret != 0)
+            return ret;
+    }
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+    return 0;
+}
+
+/* map an incomplete host page */
+int mmap_frag(unsigned long host_start,
+               unsigned long start, unsigned long end,
+               int prot, int flags, int fd, unsigned long offset)
+{
+    unsigned long host_end, ret, addr;
+    int prot1, prot_new;
+
+    host_end = host_start + qemu_host_page_size;
+
+    /* get the protection of the target pages outside the mapping */
+    prot1 = 0;
+    for(addr = host_start; addr < host_end; addr++) {
+        if (addr < start || addr >= end)
+            prot1 |= page_get_flags(addr);
+    }
+
+    if (prot1 == 0) {
+        /* no page was there, so we allocate one */
+        ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
+                         flags | MAP_ANONYMOUS, -1, 0);
+        if (ret == -1)
+            return ret;
+    }
+    prot1 &= PAGE_BITS;
+
+    prot_new = prot | prot1;
+    if (!(flags & MAP_ANONYMOUS)) {
+        /* msync() won't work here, so we return an error if write is
+           possible while it is a shared mapping */
+#ifndef __APPLE__
+        if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+        if ((flags &  MAP_SHARED) &&
+#endif
+            (prot & PROT_WRITE))
+            return -1;
+
+        /* adjust protection to be able to read */
+        if (!(prot1 & PROT_WRITE))
+            mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+
+        /* read the corresponding file data */
+        pread(fd, (void *)start, end - start, offset);
+
+        /* put final protection */
+        if (prot_new != (prot1 | PROT_WRITE))
+            mprotect((void *)host_start, qemu_host_page_size, prot_new);
+    } else {
+        /* just update the protection */
+        if (prot_new != prot1) {
+            mprotect((void *)host_start, qemu_host_page_size, prot_new);
+        }
+    }
+    return 0;
+}
+
+/* NOTE: all the constants are the HOST ones */
+long target_mmap(unsigned long start, unsigned long len, int prot,
+                 int flags, int fd, unsigned long offset)
+{
+    unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+    static unsigned long last_start = 0x40000000;
+#endif
+
+#ifdef DEBUG_MMAP
+    {
+        printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
+               start, len,
+               prot & PROT_READ ? 'r' : '-',
+               prot & PROT_WRITE ? 'w' : '-',
+               prot & PROT_EXEC ? 'x' : '-');
+        if (flags & MAP_FIXED)
+            printf("MAP_FIXED ");
+        if (flags & MAP_ANONYMOUS)
+            printf("MAP_ANON ");
+#ifndef MAP_TYPE
+# define MAP_TYPE 0x3
+#endif
+        switch(flags & MAP_TYPE) {
+        case MAP_PRIVATE:
+            printf("MAP_PRIVATE ");
+            break;
+        case MAP_SHARED:
+            printf("MAP_SHARED ");
+            break;
+        default:
+            printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
+            break;
+        }
+        printf("fd=%d offset=%lx\n", fd, offset);
+    }
+#endif
+
+    if (offset & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        return start;
+    host_start = start & qemu_host_page_mask;
+
+    if (!(flags & MAP_FIXED)) {
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+        /* tell the kernel to search at the same place as i386 */
+        if (host_start == 0) {
+            host_start = last_start;
+            last_start += HOST_PAGE_ALIGN(len);
+        }
+#endif
+        if (qemu_host_page_size != qemu_real_host_page_size) {
+            /* NOTE: this code is only for debugging with '-p' option */
+            /* reserve a memory area */
+            host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
+            host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
+                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+            if (host_start == -1)
+                return host_start;
+            host_end = host_start + host_len;
+            start = HOST_PAGE_ALIGN(host_start);
+            end = start + HOST_PAGE_ALIGN(len);
+            if (start > host_start)
+                munmap((void *)host_start, start - host_start);
+            if (end < host_end)
+                munmap((void *)end, host_end - end);
+            /* use it as a fixed mapping */
+            flags |= MAP_FIXED;
+        } else {
+            /* if not fixed, no need to do anything */
+            host_offset = offset & qemu_host_page_mask;
+            host_len = len + offset - host_offset;
+            start = (long)mmap((void *)host_start, host_len,
+                               prot, flags, fd, host_offset);
+            if (start == -1)
+                return start;
+            /* update start so that it points to the file position at 'offset' */
+            if (!(flags & MAP_ANONYMOUS))
+                start += offset - host_offset;
+            goto the_end1;
+        }
+    }
+
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    end = start + len;
+    host_end = HOST_PAGE_ALIGN(end);
+
+    /* worst case: we cannot map the file because the offset is not
+       aligned, so we read it */
+    if (!(flags & MAP_ANONYMOUS) &&
+        (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
+        /* msync() won't work here, so we return an error if write is
+           possible while it is a shared mapping */
+#ifndef __APPLE__
+        if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+        if ((flags & MAP_SHARED) &&
+#endif
+            (prot & PROT_WRITE))
+            return -EINVAL;
+        retaddr = target_mmap(start, len, prot | PROT_WRITE,
+                              MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+                              -1, 0);
+        if (retaddr == -1)
+            return retaddr;
+        pread(fd, (void *)start, len, offset);
+        if (!(prot & PROT_WRITE)) {
+            ret = target_mprotect(start, len, prot);
+            if (ret != 0)
+                return ret;
+        }
+        goto the_end;
+    }
+
+    /* handle the start of the mapping */
+    if (start > host_start) {
+        if (host_end == host_start + qemu_host_page_size) {
+            /* one single host page */
+            ret = mmap_frag(host_start, start, end,
+                            prot, flags, fd, offset);
+            if (ret == -1)
+                return ret;
+            goto the_end1;
+        }
+        ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
+                        prot, flags, fd, offset);
+        if (ret == -1)
+            return ret;
+        host_start += qemu_host_page_size;
+    }
+    /* handle the end of the mapping */
+    if (end < host_end) {
+        ret = mmap_frag(host_end - qemu_host_page_size,
+                        host_end - qemu_host_page_size, host_end,
+                        prot, flags, fd,
+                        offset + host_end - qemu_host_page_size - start);
+        if (ret == -1)
+            return ret;
+        host_end -= qemu_host_page_size;
+    }
+
+    /* map the middle (easier) */
+    if (host_start < host_end) {
+        unsigned long offset1;
+	if (flags & MAP_ANONYMOUS)
+	  offset1 = 0;
+	else
+	  offset1 = offset + host_start - start;
+        ret = (long)mmap((void *)host_start, host_end - host_start,
+                         prot, flags, fd, offset1);
+        if (ret == -1)
+            return ret;
+    }
+ the_end1:
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+ the_end:
+#ifdef DEBUG_MMAP
+    printf("target_mmap: ret=0x%lx\n", (long)start);
+    page_dump(stdout);
+    printf("\n");
+#endif
+    return start;
+}
+
+int target_munmap(unsigned long start, unsigned long len)
+{
+    unsigned long end, host_start, host_end, addr;
+    int prot, ret;
+
+#ifdef DEBUG_MMAP
+    printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+#endif
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        return -EINVAL;
+    end = start + len;
+    host_start = start & qemu_host_page_mask;
+    host_end = HOST_PAGE_ALIGN(end);
+
+    if (start > host_start) {
+        /* handle host page containing start */
+        prot = 0;
+        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (host_end == host_start + qemu_host_page_size) {
+            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+                prot |= page_get_flags(addr);
+            }
+            end = host_end;
+        }
+        if (prot != 0)
+            host_start += qemu_host_page_size;
+    }
+    if (end < host_end) {
+        prot = 0;
+        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (prot != 0)
+            host_end -= qemu_host_page_size;
+    }
+
+    /* unmap what we can */
+    if (host_start < host_end) {
+        ret = munmap((void *)host_start, host_end - host_start);
+        if (ret != 0)
+            return ret;
+    }
+
+    page_set_flags(start, start + len, 0);
+    return 0;
+}
+
+/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
+   blocks which have been allocated starting on a host page */
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+                   unsigned long new_size, unsigned long flags,
+                   unsigned long new_addr)
+{
+#ifndef __APPLE__
+    /* XXX: use 5 args syscall */
+    new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
+    if (new_addr == -1)
+        return new_addr;
+    prot = page_get_flags(old_addr);
+    page_set_flags(old_addr, old_addr + old_size, 0);
+    page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
+    return new_addr;
+#else
+    qerror("target_mremap: unsupported\n");
+#endif
+
+}
+
+int target_msync(unsigned long start, unsigned long len, int flags)
+{
+    unsigned long end;
+
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    if (end == start)
+        return 0;
+
+    start &= qemu_host_page_mask;
+    return msync((void *)start, end - start, flags);
+}
diff --git a/qemu-0.15.x/darwin-user/qemu.h b/qemu-0.15.x/darwin-user/qemu.h
new file mode 100644
index 0000000..b6d3e6c
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/qemu.h
@@ -0,0 +1,178 @@
+#ifndef GEMU_H
+#define GEMU_H
+
+#include <signal.h>
+#include <string.h>
+
+#include "cpu.h"
+
+#include "thunk.h"
+
+#include "gdbstub.h"
+
+typedef siginfo_t target_siginfo_t;
+#define target_sigaction	sigaction
+#ifdef TARGET_I386
+struct target_pt_regs {
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	int  xds;
+	int  xes;
+	long orig_eax;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+struct	target_sigcontext {
+    int			sc_onstack;
+    int			sc_mask;
+    int	sc_eax;
+    int	sc_ebx;
+    int	sc_ecx;
+    int	sc_edx;
+    int	sc_edi;
+    int	sc_esi;
+    int	sc_ebp;
+    int	sc_esp;
+    int	sc_ss;
+    int	sc_eflags;
+    int	sc_eip;
+    int	sc_cs;
+    int	sc_ds;
+    int	sc_es;
+    int	sc_fs;
+    int	sc_gs;
+};
+
+#define __USER_CS	(0x17)
+#define __USER_DS	(0x1F)
+
+#elif defined(TARGET_PPC)
+struct target_pt_regs {
+	unsigned long gpr[32];
+	unsigned long nip;
+	unsigned long msr;
+	unsigned long orig_gpr3;	/* Used for restarting system calls */
+	unsigned long ctr;
+	unsigned long link;
+	unsigned long xer;
+	unsigned long ccr;
+	unsigned long mq;		/* 601 only (not used at present) */
+					/* Used on APUS to hold IPL value. */
+	unsigned long trap;		/* Reason for being here */
+	unsigned long dar;		/* Fault registers */
+	unsigned long dsisr;
+	unsigned long result; 		/* Result of a system call */
+};
+
+struct target_sigcontext {
+    int		sc_onstack;     /* sigstack state to restore */
+    int		sc_mask;        /* signal mask to restore */
+    int		sc_ir;			/* pc */
+    int		sc_psw;         /* processor status word */
+    int		sc_sp;      	/* stack pointer if sc_regs == NULL */
+    void	*sc_regs;		/* (kernel private) saved state */
+};
+
+#endif
+
+typedef struct TaskState {
+    struct TaskState *next;
+    int used; /* non zero if used */
+    uint8_t stack[0];
+} __attribute__((aligned(16))) TaskState;
+
+void syscall_init(void);
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_unix_syscall(void *cpu_env, int num);
+int do_sigaction(int sig, const struct sigaction *act,
+                 struct sigaction *oact);
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
+
+void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void qerror(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
+void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
+
+extern CPUState *global_env;
+void cpu_loop(CPUState *env);
+void init_paths(const char *prefix);
+const char *path(const char *pathname);
+
+#include "qemu-log.h"
+
+/* commpage.c */
+void commpage_init(void);
+void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+/* signal.c */
+void process_pending_signals(void *cpu_env);
+void signal_init(void);
+int queue_signal(int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+long do_sigreturn(CPUState *env, int num);
+
+/* machload.c */
+int mach_exec(const char * filename, char ** argv, char ** envp,
+			  struct target_pt_regs * regs);
+
+/* mmap.c */
+int target_mprotect(unsigned long start, unsigned long len, int prot);
+long target_mmap(unsigned long start, unsigned long len, int prot,
+                 int flags, int fd, unsigned long offset);
+int target_munmap(unsigned long start, unsigned long len);
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+                   unsigned long new_size, unsigned long flags,
+                   unsigned long new_addr);
+int target_msync(unsigned long start, unsigned long len, int flags);
+
+/* user access */
+
+/* XXX: todo protect every memory access */
+#define lock_user(x,y,z)    (void*)(x)
+#define unlock_user(x,y,z)
+
+/* Mac OS X ABI arguments processing */
+#ifdef TARGET_I386
+static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
+{
+    uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+    *i+=4;
+    return tswap32(*args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
+{
+    uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+    *i+=8;
+    return tswap64(*args);
+}
+#elif defined(TARGET_PPC)
+static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
+{
+    /* XXX: won't work when args goes on stack after gpr10 */
+    uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
+    *i+=4;
+    return tswap32(args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
+{
+    /* XXX: won't work when args goes on stack after gpr10 */
+    uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
+    *i+=(8 << 8) + 8;
+    return tswap64(args);
+}
+#endif
+
+#endif
diff --git a/qemu-0.15.x/darwin-user/signal.c b/qemu-0.15.x/darwin-user/signal.c
new file mode 100644
index 0000000..e2adca3
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/signal.c
@@ -0,0 +1,454 @@
+/*
+ *  Emulation of Linux signals
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+
+#ifdef __ia64__
+#undef uc_mcontext
+#undef uc_sigmask
+#undef uc_stack
+#undef uc_link
+#endif
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+#define DEBUG_SIGNAL
+
+#define MAX_SIGQUEUE_SIZE 1024
+
+struct sigqueue {
+    struct sigqueue *next;
+    target_siginfo_t info;
+};
+
+struct emulated_sigaction {
+    struct target_sigaction sa;
+    int pending; /* true if signal is pending */
+    struct sigqueue *first;
+    struct sigqueue info; /* in order to always have memory for the
+                             first signal, we put it here */
+};
+
+static struct sigaltstack target_sigaltstack_used = {
+    0, 0, SA_DISABLE
+};
+
+static struct emulated_sigaction sigact_table[NSIG];
+static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+static struct sigqueue *first_free; /* first free siginfo queue entry */
+static int signal_pending; /* non zero if a signal may be pending */
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+                                void *puc);
+
+
+static inline int host_to_target_signal(int sig)
+{
+    return sig;
+}
+
+static inline int target_to_host_signal(int sig)
+{
+    return sig;
+}
+
+/* siginfo conversion */
+
+
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+}
+
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
+{
+
+}
+
+void signal_init(void)
+{
+    struct sigaction act;
+    int i;
+
+    /* set all host signal handlers. ALL signals are blocked during
+       the handlers to serialize them. */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO;
+    act.sa_sigaction = host_signal_handler;
+    for(i = 1; i < NSIG; i++) {
+        sigaction(i, &act, NULL);
+    }
+
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    first_free = &sigqueue_table[0];
+    for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
+        sigqueue_table[i].next = &sigqueue_table[i + 1];
+    sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
+}
+
+/* signal queue handling */
+
+static inline struct sigqueue *alloc_sigqueue(void)
+{
+    struct sigqueue *q = first_free;
+    if (!q)
+        return NULL;
+    first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(struct sigqueue *q)
+{
+    q->next = first_free;
+    first_free = q;
+}
+
+/* abort execution with signal */
+void QEMU_NORETURN force_sig(int sig)
+{
+    int host_sig;
+    host_sig = target_to_host_signal(sig);
+    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
+            sig, strsignal(host_sig));
+    _exit(-host_sig);
+}
+
+/* queue a signal so that it will be send to the virtual CPU as soon
+   as possible */
+int queue_signal(int sig, target_siginfo_t *info)
+{
+    struct emulated_sigaction *k;
+    struct sigqueue *q, **pq;
+    target_ulong handler;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "queue_signal: sig=%d\n",
+            sig);
+#endif
+    k = &sigact_table[sig - 1];
+    handler = (target_ulong)k->sa.sa_handler;
+    if (handler == SIG_DFL) {
+        /* default handler : ignore some signal. The other are fatal */
+        if (sig != SIGCHLD &&
+            sig != SIGURG &&
+            sig != SIGWINCH) {
+            force_sig(sig);
+        } else {
+            return 0; /* indicate ignored */
+        }
+    } else if (handler == host_to_target_signal(SIG_IGN)) {
+        /* ignore signal */
+        return 0;
+    } else if (handler == host_to_target_signal(SIG_ERR)) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+        if (!k->pending) {
+            /* first signal */
+            q = &k->info;
+        } else {
+            q = alloc_sigqueue();
+            if (!q)
+                return -EAGAIN;
+            while (*pq != NULL)
+                pq = &(*pq)->next;
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* signal that a new signal is pending */
+        signal_pending = 1;
+        return 1; /* indicates that the signal was queued */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+                                void *puc)
+{
+    int sig;
+    target_siginfo_t tinfo;
+
+    /* the CPU emulator uses some host signals to detect exceptions,
+       we we forward to it some signals */
+    if (host_signum == SIGSEGV || host_signum == SIGBUS) {
+        if (cpu_signal_handler(host_signum, (void*)info, puc))
+            return;
+    }
+
+    /* get target signal number */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > NSIG)
+        return;
+
+#if defined(DEBUG_SIGNAL)
+	fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    if (queue_signal(sig, &tinfo) == 1) {
+        /* interrupt the virtual CPU as soon as possible */
+        cpu_exit(global_env);
+    }
+}
+
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
+{
+    /* XXX: test errors */
+    if(oss)
+    {
+        oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
+        oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
+        oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
+    }
+    if(ss)
+    {
+        target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
+        target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
+        target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
+    }
+    return 0;
+}
+
+int do_sigaction(int sig, const struct sigaction *act,
+                 struct sigaction *oact)
+{
+    struct emulated_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+
+    if (sig < 1 || sig > NSIG)
+        return -EINVAL;
+
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+            sig, (int)act, (int)oact);
+#endif
+    if (oact) {
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+            sig, (int)act, (int)oact);
+#endif
+
+        oact->sa_handler = tswapl(k->sa.sa_handler);
+        oact->sa_flags = tswapl(k->sa.sa_flags);
+        oact->sa_mask = tswapl(k->sa.sa_mask);
+    }
+    if (act) {
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
+            act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+        k->sa.sa_handler = tswapl(act->sa_handler);
+        k->sa.sa_flags = tswapl(act->sa_flags);
+        k->sa.sa_mask = tswapl(act->sa_mask);
+        /* we update the host signal state */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "sigaction handler going to call sigaction\n",
+            act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+            sigfillset(&act1.sa_mask);
+            act1.sa_flags = SA_SIGINFO;
+            if (k->sa.sa_flags & SA_RESTART)
+                act1.sa_flags |= SA_RESTART;
+            /* NOTE: it is important to update the host kernel signal
+               ignore state to avoid getting unexpected interrupted
+               syscalls */
+            if (k->sa.sa_handler == SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->sa.sa_handler == SIG_DFL) {
+                act1.sa_sigaction = (void *)SIG_DFL;
+            } else {
+                act1.sa_sigaction = host_signal_handler;
+            }
+            sigaction(host_sig, &act1, NULL);
+        }
+    }
+    return 0;
+}
+
+
+#ifdef TARGET_I386
+
+static inline void *
+get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
+{
+    /* XXX Fix that */
+    if(target_sigaltstack_used.ss_flags & SA_DISABLE)
+    {
+        int esp;
+        /* Default to using normal stack */
+        esp = env->regs[R_ESP];
+
+        return (void *)((esp - frame_size) & -8ul);
+    }
+    else
+    {
+        return target_sigaltstack_used.ss_sp;
+    }
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			void *set, CPUState *env)
+{
+	void *frame;
+	int i, err = 0;
+
+    fprintf(stderr, "setup_frame %d\n", sig);
+	frame = get_sigframe(ka, env, sizeof(*frame));
+
+	/* Set up registers for signal handler */
+	env->regs[R_ESP] = (unsigned long) frame;
+	env->eip = (unsigned long) ka->sa.sa_handler;
+
+	env->eflags &= ~TF_MASK;
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV /* , current */);
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+    int i = 0;
+    struct target_sigcontext *scp = get_int_arg(&i, env);
+    /* XXX Get current signal number */
+    /* XXX Adjust accordin to sc_onstack, sc_mask */
+    if(tswapl(scp->sc_onstack) & 0x1)
+        target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
+    else
+        target_sigaltstack_used.ss_flags &=  SA_DISABLE;
+    int set = tswapl(scp->sc_eax);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
+    fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
+    fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
+
+    env->regs[R_EAX] = tswapl(scp->sc_eax);
+    env->regs[R_EBX] = tswapl(scp->sc_ebx);
+    env->regs[R_ECX] = tswapl(scp->sc_ecx);
+    env->regs[R_EDX] = tswapl(scp->sc_edx);
+    env->regs[R_EDI] = tswapl(scp->sc_edi);
+    env->regs[R_ESI] = tswapl(scp->sc_esi);
+    env->regs[R_EBP] = tswapl(scp->sc_ebp);
+    env->regs[R_ESP] = tswapl(scp->sc_esp);
+    env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
+    env->eflags = tswapl(scp->sc_eflags);
+    env->eip = tswapl(scp->sc_eip);
+    env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
+    env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
+    env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
+    env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
+    env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
+
+    /* Again, because our caller's caller will reset EAX */
+    return env->regs[R_EAX];
+}
+
+#else
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			void *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+    int i = 0;
+    struct target_sigcontext *scp = get_int_arg(&i, env);
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -ENOSYS;
+}
+
+#endif
+
+void process_pending_signals(void *cpu_env)
+{
+    struct emulated_sigaction *k;
+    struct sigqueue *q;
+    target_ulong handler;
+    int sig;
+
+    if (!signal_pending)
+        return;
+
+    k = sigact_table;
+
+    for(sig = 1; sig <= NSIG; sig++) {
+        if (k->pending)
+            goto handle_signal;
+        k++;
+    }
+
+    /* if no signal is pending, just return */
+    signal_pending = 0;
+    return;
+handle_signal:
+    #ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+    #endif
+    /* dequeue signal */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first)
+        k->pending = 0;
+
+    sig = gdb_handlesig (cpu_env, sig);
+    if (!sig) {
+        fprintf (stderr, "Lost signal\n");
+        abort();
+    }
+
+    handler = k->sa.sa_handler;
+    if (handler == SIG_DFL) {
+        /* default handler : ignore some signal. The other are fatal */
+        if (sig != SIGCHLD &&
+            sig != SIGURG &&
+            sig != SIGWINCH) {
+            force_sig(sig);
+        }
+    } else if (handler == SIG_IGN) {
+        /* ignore sig */
+    } else if (handler == SIG_ERR) {
+        force_sig(sig);
+    } else {
+
+        setup_frame(sig, k, 0, cpu_env);
+	if (k->sa.sa_flags & SA_RESETHAND)
+            k->sa.sa_handler = SIG_DFL;
+    }
+    if (q != &k->info)
+        free_sigqueue(q);
+}
diff --git a/qemu-0.15.x/darwin-user/syscall.c b/qemu-0.15.x/darwin-user/syscall.c
new file mode 100644
index 0000000..f3cc1f8
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/syscall.c
@@ -0,0 +1,1566 @@
+/*
+ *  Darwin syscalls
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *  Copyright (c) 2006 Pierre d'Herbemont
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/host_info.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/message.h>
+
+#include <pthread.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/dirent.h>
+#include <sys/uio.h>
+#include <sys/termios.h>
+#include <sys/ptrace.h>
+#include <net/if.h>
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <sys/attr.h>
+
+#include <mach/ndr.h>
+#include <mach/mig_errors.h>
+
+#include <sys/xattr.h>
+
+#include "qemu.h"
+
+//#define DEBUG_SYSCALL
+
+#ifdef DEBUG_SYSCALL
+# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1
+# define DEBUG_BEGIN_ENABLE  __DEBUG_qemu_user_force_enable = 1;
+# define DEBUG_END_ENABLE  __DEBUG_qemu_user_force_enable = 0;
+
+# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0
+# define DEBUG_ENABLE_ALL()  static int __DEBUG_qemu_user_force_enable = 1
+    DEBUG_ENABLE_ALL();
+
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); \
+                           if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \
+                         } while(0)
+#else
+# define DEBUG_FORCE_ENABLE_LOCAL()
+# define DEBUG_BEGIN_ENABLE
+# define DEBUG_END_ENABLE
+
+# define DPRINTF(...) do { qemu_log(__VA_ARGS__); } while(0)
+#endif
+
+enum {
+    bswap_out = 0,
+    bswap_in = 1
+};
+
+extern const char *interp_prefix;
+
+static inline long get_errno(long ret)
+{
+    if (ret == -1)
+        return -errno;
+    else
+        return ret;
+}
+
+static inline int is_error(long ret)
+{
+    return (unsigned long)ret >= (unsigned long)(-4096);
+}
+
+/* ------------------------------------------------------------
+   Mach syscall handling
+*/
+
+void static inline print_description_msg_header(mach_msg_header_t *hdr)
+{
+    char *name = NULL;
+    int i;
+    struct { int number; char *name; } msg_name[] =
+    {
+        /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */
+        { 200,      "host_info" },
+        { 202,      "host_page_size" },
+        { 206,      "host_get_clock_service" },
+        { 206,      "host_get_clock_service" },
+        { 206,      "host_get_clock_service" },
+        { 306,      "host_get_clock_service" },
+        { 3204,     "mach_port_allocate" },
+        { 3206,     "mach_port_deallocate" },
+        { 3404,     "mach_ports_lookup" },
+        { 3409,     "mach_task_get_special_port" },
+        { 3414,     "mach_task_get_exception_ports" },
+        { 3418,     "mach_semaphore_create" },
+        { 3504,     "mach_semaphore_create" },
+        { 3509,     "mach_semaphore_create" },
+        { 3518,     "semaphore_create" },
+        { 3616,     "thread_policy" },
+        { 3801,     "vm_allocate" },
+        { 3802,     "vm_deallocate" },
+        { 3802,     "vm_deallocate" },
+        { 3803,     "vm_protect" },
+        { 3812,     "vm_map" },
+        { 4241776,  "lu_message_send_id" },  /* lookupd */
+        { 4241876,  "lu_message_reply_id" }, /* lookupd */
+    };
+
+    for(i = 0; i < ARRAY_SIZE(msg_name); i++) {
+        if(msg_name[i].number == hdr->msgh_id)
+        {
+            name = msg_name[i].name;
+            break;
+        }
+    }
+    if(!name)
+        DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id);
+    else
+        DPRINTF("%s\n", name);
+#if 0
+    DPRINTF("Bits: %8x\n", hdr->msgh_bits);
+    DPRINTF("Size: %8x\n", hdr->msgh_size);
+    DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port);
+    DPRINTF("Locl: %8x\n", hdr->msgh_local_port);
+    DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved);
+
+    DPRINTF("Id  : %8x\n", hdr->msgh_id);
+
+    NDR_record_t *ndr = (NDR_record_t *)(hdr + 1);
+    DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr);
+    DPRINTF("%d %d %d %d %d %d %d %d\n",
+           ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding,
+           ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2);
+#endif
+}
+
+static inline void print_mach_msg_return(mach_msg_return_t ret)
+{
+    int i, found = 0;
+#define MACH_MSG_RET(msg) { msg, #msg }
+    struct { int code; char *name; } msg_name[] =
+    {
+        /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */
+        /* send message */
+        MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL),
+        MACH_MSG_RET(MACH_SEND_NO_BUFFER),
+        MACH_MSG_RET(MACH_SEND_INVALID_DATA),
+        MACH_MSG_RET(MACH_SEND_INVALID_HEADER),
+        MACH_MSG_RET(MACH_SEND_INVALID_DEST),
+        MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY),
+        MACH_MSG_RET(MACH_SEND_INVALID_REPLY),
+        MACH_MSG_RET(MACH_SEND_INVALID_TRAILER),
+        MACH_MSG_RET(MACH_SEND_INVALID_MEMORY),
+        MACH_MSG_RET(MACH_SEND_INVALID_RIGHT),
+        MACH_MSG_RET(MACH_SEND_INVALID_TYPE),
+        MACH_MSG_RET(MACH_SEND_INTERRUPTED),
+        MACH_MSG_RET(MACH_SEND_TIMED_OUT),
+
+        MACH_MSG_RET(MACH_RCV_BODY_ERROR),
+        MACH_MSG_RET(MACH_RCV_HEADER_ERROR),
+
+        MACH_MSG_RET(MACH_RCV_IN_SET),
+        MACH_MSG_RET(MACH_RCV_INTERRUPTED),
+
+        MACH_MSG_RET(MACH_RCV_INVALID_DATA),
+        MACH_MSG_RET(MACH_RCV_INVALID_NAME),
+        MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY),
+        MACH_MSG_RET(MACH_RCV_INVALID_TRAILER),
+        MACH_MSG_RET(MACH_RCV_INVALID_TYPE),
+
+        MACH_MSG_RET(MACH_RCV_PORT_CHANGED),
+        MACH_MSG_RET(MACH_RCV_PORT_DIED),
+
+        MACH_MSG_RET(MACH_RCV_SCATTER_SMALL),
+        MACH_MSG_RET(MACH_RCV_TIMED_OUT),
+        MACH_MSG_RET(MACH_RCV_TOO_LARGE)
+    };
+#undef MACH_MSG_RET
+
+    if( ret == MACH_MSG_SUCCESS)
+        DPRINTF("MACH_MSG_SUCCESS\n");
+    else
+    {
+        for( i = 0; i < ARRAY_SIZE(msg_name); i++) {
+            if(msg_name[i].code == ret) {
+                DPRINTF("%s\n", msg_name[i].name);
+                found = 1;
+                break;
+            }
+        }
+        if(!found)
+            qerror("unknow mach message ret code %d\n", ret);
+    }
+}
+
+static inline void swap_mach_msg_header(mach_msg_header_t *hdr)
+{
+    hdr->msgh_bits = tswap32(hdr->msgh_bits);
+    hdr->msgh_size = tswap32(hdr->msgh_size);
+    hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port);
+    hdr->msgh_local_port = tswap32(hdr->msgh_local_port);
+    hdr->msgh_reserved = tswap32(hdr->msgh_reserved);
+    hdr->msgh_id = tswap32(hdr->msgh_id);
+}
+
+struct complex_msg {
+            mach_msg_header_t hdr;
+            mach_msg_body_t body;
+};
+
+static inline void swap_mach_msg_body(struct complex_msg *complex_msg, int bswap)
+{
+    mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1);
+    int i,j;
+
+    if(bswap == bswap_in)
+        tswap32s(&complex_msg->body.msgh_descriptor_count);
+
+    DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count);
+
+    for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) {
+        switch(descr->type)
+        {
+            case MACH_MSG_PORT_DESCRIPTOR:
+                tswap32s(&descr->name);
+                descr++;
+                break;
+            case MACH_MSG_OOL_DESCRIPTOR:
+            {
+                mach_msg_ool_descriptor_t *ool = (void *)descr;
+                tswap32s((uint32_t *)&ool->address);
+                tswap32s(&ool->size);
+
+                descr = (mach_msg_port_descriptor_t *)(ool+1);
+                break;
+            }
+            case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+            {
+                mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr;
+                mach_port_name_t * port_names;
+
+                if(bswap == bswap_in)
+                {
+                    tswap32s((uint32_t *)&ool_ports->address);
+                    tswap32s(&ool_ports->count);
+                }
+
+                port_names = ool_ports->address;
+
+                for(j = 0; j < ool_ports->count; j++)
+                    tswap32s(&port_names[j]);
+
+                if(bswap == bswap_out)
+                {
+                    tswap32s((uint32_t *)&ool_ports->address);
+                    tswap32s(&ool_ports->count);
+                }
+
+                descr = (mach_msg_port_descriptor_t *)(ool_ports+1);
+                break;
+            }
+            default: qerror("unknow mach msg descriptor type %x\n", descr->type);
+        }
+    }
+    if(bswap == bswap_out)
+        tswap32s(&complex_msg->body.msgh_descriptor_count);
+}
+
+static inline void swap_mach_msg(mach_msg_header_t *hdr, int bswap)
+{
+    if (bswap == bswap_out && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+        swap_mach_msg_body((struct complex_msg *)hdr, bswap);
+
+    swap_mach_msg_header(hdr);
+
+    if (bswap == bswap_in && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+        swap_mach_msg_body((struct complex_msg *)hdr, bswap);
+}
+
+static inline uint32_t target_mach_msg_trap(
+        mach_msg_header_t *hdr, uint32_t options, uint32_t send_size,
+        uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify)
+{
+    extern int mach_msg_trap(mach_msg_header_t *, mach_msg_option_t,
+          mach_msg_size_t, mach_msg_size_t, mach_port_t,
+          mach_msg_timeout_t, mach_port_t);
+    mach_msg_audit_trailer_t *trailer;
+    mach_msg_id_t msg_id;
+    uint32_t ret = 0;
+    int i;
+
+    swap_mach_msg(hdr, bswap_in);
+
+    msg_id = hdr->msgh_id;
+
+    print_description_msg_header(hdr);
+
+    ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify);
+
+    print_mach_msg_return(ret);
+
+    if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) )
+    {
+        /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should
+                probably always bswap it  */
+        /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in
+                    natural_t units but according to xnu/osfmk/mach/message.h: "The size of
+                    the message must be specified in bytes" */
+        trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size);
+        /* XXX: Should probably do that based on the option asked by the sender, but dealing
+        with kernel answer seems more sound */
+        switch(trailer->msgh_trailer_size)
+        {
+            case sizeof(mach_msg_audit_trailer_t):
+                for(i = 0; i < 8; i++)
+                    tswap32s(&trailer->msgh_audit.val[i]);
+                /* Fall in mach_msg_security_trailer_t case */
+            case sizeof(mach_msg_security_trailer_t):
+                tswap32s(&trailer->msgh_sender.val[0]);
+                tswap32s(&trailer->msgh_sender.val[1]);
+                /* Fall in mach_msg_seqno_trailer_t case */
+            case sizeof(mach_msg_seqno_trailer_t):
+                tswap32s(&trailer->msgh_seqno);
+                /* Fall in mach_msg_trailer_t case */
+            case sizeof(mach_msg_trailer_t):
+                tswap32s(&trailer->msgh_trailer_type);
+                tswap32s(&trailer->msgh_trailer_size);
+                break;
+            case 0:
+                /* Safer not to byteswap, but probably wrong */
+                break;
+            default:
+                qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size);
+                break;
+        }
+    }
+
+    /* Special message handling */
+    switch (msg_id) {
+        case 200: /* host_info */
+        {
+            mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+            struct {
+                uint32_t unknow1;
+                uint32_t max_cpus;
+                uint32_t avail_cpus;
+                uint32_t memory_size;
+                uint32_t cpu_type;
+                uint32_t cpu_subtype;
+            } *data = (void *)(err+1);
+
+            DPRINTF("maxcpu = 0x%x\n",   data->max_cpus);
+            DPRINTF("numcpu = 0x%x\n",   data->avail_cpus);
+            DPRINTF("memsize = 0x%x\n",  data->memory_size);
+
+#if defined(TARGET_I386)
+            data->cpu_type = CPU_TYPE_I386;
+            DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type);
+            data->cpu_subtype = CPU_SUBTYPE_PENT;
+            DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype);
+#elif defined(TARGET_PPC)
+            data->cpu_type = CPU_TYPE_POWERPC;
+            DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type);
+            data->cpu_subtype = CPU_SUBTYPE_POWERPC_750;
+            DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype);
+#else
+# error target not supported
+#endif
+            break;
+        }
+        case 202: /* host_page_size */
+        {
+            mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+            uint32_t *pagesize = (uint32_t *)(err+1);
+
+            DPRINTF("pagesize = %d\n", *pagesize);
+            break;
+        }
+        default: break;
+    }
+
+    swap_mach_msg(hdr, bswap_out);
+
+    return ret;
+}
+
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+                uint32_t arg8)
+{
+    extern uint32_t mach_reply_port(void);
+
+    long ret = 0;
+
+    arg1 = tswap32(arg1);
+    arg2 = tswap32(arg2);
+    arg3 = tswap32(arg3);
+    arg4 = tswap32(arg4);
+    arg5 = tswap32(arg5);
+    arg6 = tswap32(arg6);
+    arg7 = tswap32(arg7);
+    arg8 = tswap32(arg8);
+
+    DPRINTF("mach syscall %d : " , num);
+
+    switch(num) {
+    /* see xnu/osfmk/mach/syscall_sw.h */
+    case -26:
+        DPRINTF("mach_reply_port()\n");
+        ret = mach_reply_port();
+        break;
+    case -27:
+        DPRINTF("mach_thread_self()\n");
+        ret = mach_thread_self();
+        break;
+    case -28:
+        DPRINTF("mach_task_self()\n");
+        ret = mach_task_self();
+        break;
+    case -29:
+        DPRINTF("mach_host_self()\n");
+        ret = mach_host_self();
+        break;
+    case -31:
+        DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+                arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -33:
+        DPRINTF("semaphore_signal_trap(0x%x)\n", arg1);
+        ret = semaphore_signal_trap(arg1);
+        break;
+    case -34:
+        DPRINTF("semaphore_signal_all_trap(0x%x)\n", arg1);
+        ret = semaphore_signal_all_trap(arg1);
+        break;
+    case -35:
+        DPRINTF("semaphore_signal_thread_trap(0x%x)\n", arg1, arg2);
+        ret = semaphore_signal_thread_trap(arg1,arg2);
+        break;
+#endif
+    case -36:
+        DPRINTF("semaphore_wait_trap(0x%x)\n", arg1);
+        extern int semaphore_wait_trap(int); // XXX: is there any header for that?
+        ret = semaphore_wait_trap(arg1);
+        break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -37:
+        DPRINTF("semaphore_wait_signal_trap(0x%x, 0x%x)\n", arg1, arg2);
+        ret = semaphore_wait_signal_trap(arg1,arg2);
+        break;
+#endif
+    case -43:
+        DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+                arg1, arg2, arg3, arg4, arg5);
+        ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5);
+        tswap32s((uint32_t*)arg3);
+        break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -61:
+        DPRINTF("syscall_thread_switch(0x%x, 0x%x, 0x%x)\n",
+                arg1, arg2, arg3);
+        ret = syscall_thread_switch(arg1, arg2, arg3);  // just a hint to the scheduler; can drop?
+        break;
+#endif
+    case -89:
+        DPRINTF("mach_timebase_info(0x%x)\n", arg1);
+        struct mach_timebase_info info;
+        ret = mach_timebase_info(&info);
+        if(!is_error(ret))
+        {
+            struct mach_timebase_info *outInfo = (void*)arg1;
+            outInfo->numer = tswap32(info.numer);
+            outInfo->denom = tswap32(info.denom);
+        }
+        break;
+    case -90:
+        DPRINTF("mach_wait_until()\n");
+        extern int mach_wait_until(uint64_t); // XXX: is there any header for that?
+        ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1);
+        break;
+    case -91:
+        DPRINTF("mk_timer_create()\n");
+        extern int mk_timer_create(); // XXX: is there any header for that?
+        ret = mk_timer_create();
+        break;
+    case -92:
+        DPRINTF("mk_timer_destroy()\n");
+        extern int mk_timer_destroy(int); // XXX: is there any header for that?
+        ret = mk_timer_destroy(arg1);
+        break;
+    case -93:
+        DPRINTF("mk_timer_create()\n");
+        extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that?
+        ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2);
+        break;
+    case -94:
+        DPRINTF("mk_timer_cancel()\n");
+        extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that?
+        ret = mk_timer_cancel(arg1, (uint64_t *)arg2);
+        if((!is_error(ret)) && arg2)
+            tswap64s((uint64_t *)arg2);
+        break;
+    default:
+        gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num);
+        gdb_handlesig (cpu_env, SIGTRAP);
+        exit(0);
+        break;
+    }
+    return ret;
+}
+
+/* ------------------------------------------------------------
+   thread type syscall handling
+*/
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+                uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+                uint32_t arg8)
+{
+    extern uint32_t cthread_set_self(uint32_t);
+    extern uint32_t processor_facilities_used(void);
+    long ret = 0;
+
+    arg1 = tswap32(arg1);
+    arg2 = tswap32(arg2);
+    arg3 = tswap32(arg3);
+    arg4 = tswap32(arg4);
+    arg5 = tswap32(arg5);
+    arg6 = tswap32(arg6);
+    arg7 = tswap32(arg7);
+    arg8 = tswap32(arg8);
+
+    DPRINTF("thread syscall %d : " , num);
+
+    switch(num) {
+#ifdef TARGET_I386
+    case 0x3:
+#endif
+    case 0x7FF1: /* cthread_set_self */
+        DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1);
+        ret = cthread_set_self(arg1);
+#ifdef TARGET_I386
+        /* we need to update the LDT with the address of the thread */
+        write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+        /* New i386 convention, %gs should be set to our this LDT entry */
+        cpu_x86_load_seg(cpu_env, R_GS, 0x27);
+        /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/
+        ret = 0x27;
+#endif
+        break;
+    case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */
+        DPRINTF("pthread_self()\n");
+        ret = (uint32_t)pthread_self();
+        break;
+    case 0x7FF3:
+        DPRINTF("processor_facilities_used()\n");
+#ifdef __i386__
+        qerror("processor_facilities_used: not implemented!\n");
+#else
+        ret = (uint32_t)processor_facilities_used();
+#endif
+        break;
+    default:
+        gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num);
+        gdb_handlesig (cpu_env, SIGTRAP);
+        exit(0);
+        break;
+    }
+    return ret;
+}
+
+/* ------------------------------------------------------------
+   ioctl handling
+*/
+static inline void byteswap_termios(struct termios *t)
+{
+    tswap32s((uint32_t*)&t->c_iflag);
+    tswap32s((uint32_t*)&t->c_oflag);
+    tswap32s((uint32_t*)&t->c_cflag);
+    tswap32s((uint32_t*)&t->c_lflag);
+    /* 20 (char) bytes then */
+    tswap32s((uint32_t*)&t->c_ispeed);
+    tswap32s((uint32_t*)&t->c_ospeed);
+}
+
+static inline void byteswap_winsize(struct winsize *w)
+{
+    tswap16s(&w->ws_row);
+    tswap16s(&w->ws_col);
+    tswap16s(&w->ws_xpixel);
+    tswap16s(&w->ws_ypixel);
+}
+
+#define STRUCT(name, ...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "ioctls_types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, ...) const argtype struct_ ## name ## _def[] = {  __VA_ARGS__, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "ioctls_types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+typedef struct IOCTLEntry {
+    unsigned int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    const argtype arg_type[5];
+} IOCTLEntry;
+
+#define IOC_R 0x0001
+#define IOC_W 0x0002
+#define IOC_RW (IOC_R | IOC_W)
+
+#define MAX_STRUCT_SIZE 4096
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access,  ...)                        \
+    { cmd, cmd, #cmd, access, {  __VA_ARGS__ } },
+#include "ioctls.h"
+    { 0, 0, },
+};
+
+/* ??? Implement proper locking for ioctls.  */
+static long do_ioctl(long fd, long cmd, long arg)
+{
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    int ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    ie = ioctl_entries;
+    for(;;) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd);
+            return -ENOSYS;
+        }
+        if (ie->target_cmd == cmd)
+            break;
+        ie++;
+    }
+    arg_type = ie->arg_type;
+#if defined(DEBUG)
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
+#endif
+    switch(arg_type[0]) {
+    case TYPE_NULL:
+        /* no argument */
+        ret = get_errno(ioctl(fd, ie->host_cmd));
+        break;
+    case TYPE_PTRVOID:
+    case TYPE_INT:
+        /* int argment */
+        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+        break;
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch(ie->access) {
+        case IOC_R:
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(arg, target_size, 0);
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        case IOC_W:
+            argptr = lock_user(arg, target_size, 1);
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+        default:
+        case IOC_RW:
+            argptr = lock_user(arg, target_size, 1);
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(arg, target_size, 0);
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]);
+        ret = -ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+/* ------------------------------------------------------------
+   Unix syscall handling
+*/
+
+static inline void byteswap_attrlist(struct attrlist *a)
+{
+    tswap16s(&a->bitmapcount);
+    tswap16s(&a->reserved);
+    tswap32s(&a->commonattr);
+    tswap32s(&a->volattr);
+    tswap32s(&a->dirattr);
+    tswap32s(&a->fileattr);
+    tswap32s(&a->forkattr);
+}
+
+struct attrbuf_header {
+    unsigned long length;
+};
+
+static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist)
+{
+    DPRINTF("attrBuf.lenght %lx\n", attrbuf->length);
+}
+
+static inline void byteswap_statfs(struct statfs *s)
+{
+    tswap16s((uint16_t*)&s->f_otype);
+    tswap16s((uint16_t*)&s->f_oflags);
+    tswap32s((uint32_t*)&s->f_bsize);
+    tswap32s((uint32_t*)&s->f_iosize);
+    tswap32s((uint32_t*)&s->f_blocks);
+    tswap32s((uint32_t*)&s->f_bfree);
+    tswap32s((uint32_t*)&s->f_bavail);
+    tswap32s((uint32_t*)&s->f_files);
+    tswap32s((uint32_t*)&s->f_ffree);
+    tswap32s((uint32_t*)&s->f_fsid.val[0]);
+    tswap32s((uint32_t*)&s->f_fsid.val[1]);
+    tswap16s((uint16_t*)&s->f_reserved1);
+    tswap16s((uint16_t*)&s->f_type);
+    tswap32s((uint32_t*)&s->f_flags);
+}
+
+static inline void byteswap_stat(struct stat *s)
+{
+    tswap32s((uint32_t*)&s->st_dev);
+    tswap32s(&s->st_ino);
+    tswap16s(&s->st_mode);
+    tswap16s(&s->st_nlink);
+    tswap32s(&s->st_uid);
+    tswap32s(&s->st_gid);
+    tswap32s((uint32_t*)&s->st_rdev);
+    tswap32s((uint32_t*)&s->st_atimespec.tv_sec);
+    tswap32s((uint32_t*)&s->st_atimespec.tv_nsec);
+    tswap32s((uint32_t*)&s->st_mtimespec.tv_sec);
+    tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec);
+    tswap32s((uint32_t*)&s->st_ctimespec.tv_sec);
+    tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec);
+    tswap64s((uint64_t*)&s->st_size);
+    tswap64s((uint64_t*)&s->st_blocks);
+    tswap32s((uint32_t*)&s->st_blksize);
+    tswap32s(&s->st_flags);
+    tswap32s(&s->st_gen);
+}
+
+static inline void byteswap_dirents(struct dirent *d, int bytes)
+{
+    char *b;
+    for( b = (char*)d; (int)b < (int)d+bytes; )
+    {
+        unsigned short s = ((struct dirent *)b)->d_reclen;
+        tswap32s(&((struct dirent *)b)->d_ino);
+        tswap16s(&((struct dirent *)b)->d_reclen);
+        if(s<=0)
+            break;
+        b += s;
+    }
+}
+
+static inline void byteswap_iovec(struct iovec *v, int n)
+{
+    int i;
+    for(i = 0; i < n; i++)
+    {
+        tswap32s((uint32_t*)&v[i].iov_base);
+        tswap32s((uint32_t*)&v[i].iov_len);
+    }
+}
+
+static inline void byteswap_timeval(struct timeval *t)
+{
+    tswap32s((uint32_t*)&t->tv_sec);
+    tswap32s((uint32_t*)&t->tv_usec);
+}
+
+long do_unix_syscall_indirect(void *cpu_env, int num);
+long do_sync(void);
+long do_exit(uint32_t arg1);
+long do_getlogin(char *out, uint32_t size);
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3);
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3);
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3);
+long do_execve(char* arg1, char ** arg2, char ** arg3);
+long do_getgroups(uint32_t arg1, gid_t * arg2);
+long do_gettimeofday(struct timeval * arg1, void * arg2);
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_utimes(char * arg1, struct timeval * arg2);
+long do_futimes(uint32_t arg1, struct timeval * arg2);
+long do_statfs(char * arg1, struct statfs * arg2);
+long do_fstatfs(uint32_t arg1, struct statfs * arg2);
+long do_stat(char * arg1, struct stat * arg2);
+long do_fstat(uint32_t arg1, struct stat * arg2);
+long do_lstat(char * arg1, struct stat * arg2);
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4);
+long do_lseek(void *cpu_env, int num);
+long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen  /* ignored */);
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5);
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8);
+long do_fcntl(int fd, int cmd, int arg);
+
+long no_syscall(void *cpu_env, int num);
+
+long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4)
+{
+    DPRINTF("0x%x, %p, 0x%lx, 0x%" PRIx64 "\n", arg1, arg2, arg3, arg4);
+    long ret = pread(arg1, arg2, arg3, arg4);
+    return ret;
+}
+
+long do_read(int d, void *buf, size_t nbytes)
+{
+    DPRINTF("0x%x, %p, 0x%lx\n", d, buf, nbytes);
+    long ret = get_errno(read(d, buf, nbytes));
+    if(!is_error(ret))
+        DPRINTF("%x\n", *(uint32_t*)buf);
+    return ret;
+}
+
+long unimpl_unix_syscall(void *cpu_env, int num);
+
+typedef long (*syscall_function_t)(void *cpu_env, int num);
+
+
+/* define a table that will handle the syscall number->function association */
+#define VOID    void
+#define INT     (uint32_t)get_int_arg(&i, cpu_env)
+#define INT64   (uint64_t)get_int64_arg(&i, cpu_env)
+#define UINT    (unsigned int)INT
+#define PTR     (void*)INT
+
+#define SIZE    INT
+#define OFFSET  INT64
+
+#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) {  return (long)function(); }
+#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1;  return (long)function(arg1); }
+#define WRAPPER_CALL_DIRECT_2(function, _arg1, _arg2) long __qemu_##function(void *cpu_env) { int i = 0;  typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; return (long)function(arg1, arg2); }
+#define WRAPPER_CALL_DIRECT_3(function, _arg1, _arg2, _arg3) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; return (long)function(arg1, arg2, arg3); }
+#define WRAPPER_CALL_DIRECT_4(function, _arg1, _arg2, _arg3, _arg4) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; return (long)function(arg1, arg2, arg3, arg4); }
+#define WRAPPER_CALL_DIRECT_5(function, _arg1, _arg2, _arg3, _arg4, _arg5) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5;  return (long)function(arg1, arg2, arg3, arg4, arg5); }
+#define WRAPPER_CALL_DIRECT_6(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6;  return (long)function(arg1, arg2, arg3, arg4, arg5, arg6); }
+#define WRAPPER_CALL_DIRECT_7(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); }
+#define WRAPPER_CALL_DIRECT_8(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8) long __qemu_##function(void *cpu_env) { int i = 0;   typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; typeof(_arg8) arg8 = _arg8;  return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); }
+#define WRAPPER_CALL_DIRECT(function, nargs, ...) WRAPPER_CALL_DIRECT_##nargs(function, __VA_ARGS__)
+#define WRAPPER_CALL_NOERRNO(function, nargs, ...)  WRAPPER_CALL_DIRECT(function, nargs, __VA_ARGS__)
+#define WRAPPER_CALL_INDIRECT(function, nargs, ...)
+#define ENTRY(name, number, function, nargs, call_type, ...)  WRAPPER_##call_type(function, nargs, __VA_ARGS__)
+
+#include "syscalls.h"
+
+#undef ENTRY
+#undef WRAPPER_CALL_DIRECT
+#undef WRAPPER_CALL_NOERRNO
+#undef WRAPPER_CALL_INDIRECT
+#undef OFFSET
+#undef SIZE
+#undef INT
+#undef PTR
+#undef INT64
+
+#define _ENTRY(name, number, function, nargs, call_type) [number] = {\
+        name, \
+        number, \
+        (syscall_function_t)function, \
+        nargs, \
+        call_type  \
+        },
+
+#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type)  _ENTRY(name, number, __qemu_##function, nargs, call_type)
+#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type)
+#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type)
+#define ENTRY(name, number, function, nargs, call_type, ...) ENTRY_##call_type(name, number, function, nargs, call_type)
+
+#define CALL_DIRECT 1
+#define CALL_INDIRECT 2
+#define CALL_NOERRNO  (CALL_DIRECT | 4 /* = 5 */)
+
+struct unix_syscall {
+    char * name;
+    int number;
+    syscall_function_t function;
+    int nargs;
+    int call_type;
+} unix_syscall_table[SYS_MAXSYSCALL] = {
+#include "syscalls.h"
+};
+
+#undef ENTRY
+#undef _ENTRY
+#undef ENTRY_CALL_DIRECT
+#undef ENTRY_CALL_INDIRECT
+#undef ENTRY_CALL_NOERRNO
+
+/* Actual syscalls implementation */
+
+long do_unix_syscall_indirect(void *cpu_env, int num)
+{
+    long ret;
+    int new_num;
+    int i = 0;
+
+    new_num = get_int_arg(&i, cpu_env);
+#ifdef TARGET_I386
+    ((CPUX86State*)cpu_env)->regs[R_ESP] += 4;
+    /* XXX: not necessary */
+    ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num;
+#elif TARGET_PPC
+    {
+        int i;
+        uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+        for(i = 3; i < 11; i++)
+            *regs[i] = *regs[i+1];
+        /* XXX: not necessary */
+        *regs[0] = new_num;
+    }
+#endif
+    ret = do_unix_syscall(cpu_env, new_num);
+#ifdef TARGET_I386
+    ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4;
+    /* XXX: not necessary */
+    ((CPUX86State*)cpu_env)->regs[R_EAX] = num;
+#elif TARGET_PPC
+    {
+        int i;
+        /* XXX: not really needed those regs are volatile across calls */
+        uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+        for(i = 11; i > 3; i--)
+            *regs[i] = *regs[i-1];
+        regs[3] = new_num;
+        *regs[0] = num;
+    }
+#endif
+    return ret;
+}
+
+long do_exit(uint32_t arg1)
+{
+    exit(arg1);
+    /* not reached */
+    return -1;
+}
+
+long do_sync(void)
+{
+    sync();
+    return 0;
+}
+
+long do_getlogin(char *out, uint32_t size)
+{
+    char *login = getlogin();
+    if(!login)
+        return -1;
+    memcpy(out, login, size);
+    return 0;
+}
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3)
+{
+    /* XXX: don't let the %s stay in there */
+    DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+    return get_errno(open(arg1, arg2, arg3));
+}
+
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3)
+{
+    long ret;
+    DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+    ret = get_errno(getfsstat(arg1, arg2, arg3));
+    if((!is_error(ret)) && arg1)
+        byteswap_statfs(arg1);
+    return ret;
+}
+
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3)
+{
+    long ret;
+    DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3);
+    gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3);
+    if(arg2)
+        tswap32s(arg2);
+    ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3));
+    if((!is_error(ret)) && arg3)
+        tswap32s(arg3);
+    if(arg2)
+        tswap32s(arg2);
+    return ret;
+}
+
+long do_execve(char* arg1, char ** arg2, char ** arg3)
+{
+    long ret;
+    char **argv = arg2;
+    char **envp = arg3;
+    int argc;
+    int envc;
+
+    /* XXX: don't let the %s stay in here */
+    DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3);
+
+    for(argc = 0; argv[argc]; argc++);
+    for(envc = 0; envp[envc]; envc++);
+
+    argv = (char**)malloc(sizeof(char*)*argc);
+    envp = (char**)malloc(sizeof(char*)*envc);
+
+    for(; argc >= 0; argc--)
+        argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]);
+
+    for(; envc >= 0; envc--)
+        envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]);
+
+    ret = get_errno(execve(arg1, argv, envp));
+    free(argv);
+    free(envp);
+    return ret;
+}
+
+long do_getgroups(uint32_t arg1, gid_t * arg2)
+{
+    long ret;
+    int i;
+    DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2);
+    ret = get_errno(getgroups(arg1, arg2));
+    if(ret > 0)
+        for(i = 0; i < arg1; i++)
+            tswap32s(&arg2[i]);
+    return ret;
+}
+
+long do_gettimeofday(struct timeval * arg1, void * arg2)
+{
+    long ret;
+    DPRINTF("gettimeofday(%p, %p)\n",
+            arg1, arg2);
+    ret = get_errno(gettimeofday(arg1, arg2));
+    if(!is_error(ret))
+    {
+        /* timezone no longer used according to the manpage, so don't bother with it */
+        byteswap_timeval(arg1);
+    }
+    return ret;
+}
+
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+    long ret;
+    DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+    if(arg2)
+        byteswap_iovec(arg2, arg3);
+    ret = get_errno(readv(arg1, arg2, arg3));
+    if((!is_error(ret)) && arg2)
+        byteswap_iovec(arg2, arg3);
+    return ret;
+}
+
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+    long ret;
+    DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+    if(arg2)
+        byteswap_iovec(arg2, arg3);
+    ret = get_errno(writev(arg1, arg2, arg3));
+    if((!is_error(ret)) && arg2)
+        byteswap_iovec(arg2, arg3);
+    return ret;
+}
+
+long do_utimes(char * arg1, struct timeval * arg2)
+{
+    DPRINTF("utimes(%p, %p)\n", arg1, arg2);
+    if(arg2)
+    {
+        byteswap_timeval(arg2);
+        byteswap_timeval(arg2+1);
+    }
+    return get_errno(utimes(arg1, arg2));
+}
+
+long do_futimes(uint32_t arg1, struct timeval * arg2)
+{
+    DPRINTF("futimes(0x%x, %p)\n", arg1, arg2);
+    if(arg2)
+    {
+        byteswap_timeval(arg2);
+        byteswap_timeval(arg2+1);
+    }
+    return get_errno(futimes(arg1, arg2));
+}
+
+long do_statfs(char * arg1, struct statfs * arg2)
+{
+    long ret;
+    DPRINTF("statfs(%p, %p)\n", arg1, arg2);
+    ret = get_errno(statfs(arg1, arg2));
+    if(!is_error(ret))
+        byteswap_statfs(arg2);
+    return ret;
+}
+
+long do_fstatfs(uint32_t arg1, struct statfs* arg2)
+{
+    long ret;
+    DPRINTF("fstatfs(0x%x, %p)\n",
+            arg1, arg2);
+    ret = get_errno(fstatfs(arg1, arg2));
+    if(!is_error(ret))
+        byteswap_statfs(arg2);
+
+    return ret;
+}
+
+long do_stat(char * arg1, struct stat * arg2)
+{
+    long ret;
+    /* XXX: don't let the %s stay in there */
+    DPRINTF("stat(%s, %p)\n", arg1, arg2);
+    ret = get_errno(stat(arg1, arg2));
+    if(!is_error(ret))
+        byteswap_stat(arg2);
+    return ret;
+}
+
+long do_fstat(uint32_t arg1, struct stat * arg2)
+{
+    long ret;
+    DPRINTF("fstat(0x%x, %p)\n", arg1, arg2);
+    ret = get_errno(fstat(arg1, arg2));
+    if(!is_error(ret))
+        byteswap_stat(arg2);
+    return ret;
+}
+
+long do_lstat(char * arg1, struct stat * arg2)
+{
+    long ret;
+    /* XXX: don't let the %s stay in there */
+    DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2);
+    ret = get_errno(lstat(arg1, arg2));
+    if(!is_error(ret))
+        byteswap_stat(arg2);
+    return ret;
+}
+
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4)
+{
+    long ret;
+    DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4);
+    if(arg4)
+        tswap32s((uint32_t *)arg4);
+    ret = get_errno(getdirentries(arg1, arg2, arg3, arg4));
+    if(arg4)
+        tswap32s((uint32_t *)arg4);
+    if(!is_error(ret))
+        byteswap_dirents(arg2, ret);
+    return ret;
+}
+
+long do_lseek(void *cpu_env, int num)
+{
+    long ret;
+    int i = 0;
+    uint32_t arg1 = get_int_arg(&i, cpu_env);
+    uint64_t offset = get_int64_arg(&i, cpu_env);
+    uint32_t arg3 = get_int_arg(&i, cpu_env);
+    uint64_t r = lseek(arg1, offset, arg3);
+#ifdef TARGET_I386
+    /* lowest word in eax, highest in edx */
+    ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */
+    ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#elif defined TARGET_PPC
+    ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */
+    ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#else
+    qerror("64 bit ret value on your arch?");
+#endif
+    return get_errno(ret);
+}
+
+void no_swap(void * oldp, int size)
+{
+}
+
+void sysctl_tswap32s(void * oldp, int size)
+{
+    tswap32s(oldp);
+}
+
+void bswap_oid(uint32_t * oldp, int size)
+{
+    int count = size / sizeof(int);
+    int i = 0;
+    do { tswap32s(oldp + i); } while (++i < count);
+}
+
+void sysctl_usrstack(uint32_t * oldp, int size)
+{
+    DPRINTF("sysctl_usrstack: 0x%x\n", *oldp);
+    tswap32s(oldp);
+}
+
+void sysctl_ncpu(uint32_t * ncpu, int size)
+{
+    *ncpu = 0x1;
+    DPRINTF("sysctl_ncpu: 0x%x\n", *ncpu);
+    tswap32s(ncpu);
+}
+
+void sysctl_exec(char * exec, int size)
+{
+    DPRINTF("sysctl_exec: %s\n", exec);
+}
+
+void sysctl_translate(char * exec, int size)
+{
+    DPRINTF("sysctl_translate: %s\n", exec);
+}
+
+struct sysctl_dir {
+    int num;
+    const char * name;
+    void (*swap_func)(void *, int);
+    struct sysctl_dir *childs;
+};
+
+#define ENTRYD(num, name, childs) { num, name, NULL, childs }
+#define ENTRYE(num, name, func)   { num, name, (void (*)(void *, int))func, NULL  }
+struct sysctl_dir sysctls_unspec[] = {
+    ENTRYE(3,  "oip", bswap_oid),
+    { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls_kern[] = {
+    ENTRYE(KERN_TRANSLATE,          "translate",    sysctl_translate), /* 44 */
+    ENTRYE(KERN_EXEC,               "exec",         sysctl_exec), /* 45 */
+    ENTRYE(KERN_USRSTACK32,          "KERN_USRSTACK32", sysctl_usrstack), /* 35 */
+    ENTRYE(KERN_SHREG_PRIVATIZABLE,  "KERN_SHREG_PRIVATIZABLE", sysctl_tswap32s), /* 54 */
+    { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls_hw[] = {
+    ENTRYE(HW_NCPU, "ncpud", sysctl_tswap32s),
+    ENTRYE(104, "104", no_swap),
+    ENTRYE(105, "105", no_swap),
+    { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls[] = {
+    ENTRYD(CTL_UNSPEC, "unspec", sysctls_unspec),
+    ENTRYD(CTL_KERN, "kern", sysctls_kern),
+    ENTRYD(CTL_HW,   "hw",   sysctls_hw ),
+    { 0, NULL, NULL, NULL }
+};
+
+#undef ENTRYE
+#undef ENTRYD
+
+static inline struct sysctl_dir * get_sysctl_entry_for_mib(int mib, struct sysctl_dir * sysctl_elmt)
+{
+    if(!sysctl_elmt)
+        return NULL;
+    for(; sysctl_elmt->name != NULL ; sysctl_elmt++) {
+        if(sysctl_elmt->num == mib)
+            return sysctl_elmt;
+    }
+    return NULL;
+}
+
+static inline long bswap_syctl(int * mib, int count, void *buf, int size)
+{
+    int i;
+    struct sysctl_dir * sysctl = sysctls;
+    struct sysctl_dir * ret = NULL;
+
+    for(i = 0; i < count; i++) {
+
+        if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))) {
+            gemu_log("bswap_syctl: can't find mib %d\n", mib[i]);
+            return -ENOTDIR;
+        }
+        if(!(sysctl = sysctl->childs))
+            break;
+    }
+
+    if(ret->childs)
+        qerror("we shouldn't have a directory element\n");
+
+    ret->swap_func(buf, size);
+    return 0;
+}
+
+static inline void print_syctl(int * mib, int count)
+{
+    int i;
+    struct sysctl_dir * sysctl = sysctls;
+    struct sysctl_dir * ret = NULL;
+
+    for(i = 0; i < count; i++) {
+        if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))){
+            gemu_log("print_syctl: can't find mib %d\n", mib[i]);
+            return;
+        }
+        DPRINTF("%s.", sysctl->name);
+        if(!(sysctl = sysctl->childs))
+            break;
+    }
+    DPRINTF("\n");
+}
+
+long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen  /* ignored */)
+{
+    long ret = 0;
+    int i;
+    DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n",
+            name, namelen, oldp, oldlenp, newp, newlen);
+    if(name) {
+        i = 0;
+        do { tswap32s( name + i); } while (++i < namelen);
+        print_syctl(name, namelen);
+        //bswap_syctl(name, namelen, newp, newlen);
+        tswap32s((uint32_t*)oldlenp);
+    }
+
+    if(name) /* Sometimes sysctl is called with no arg1, ignore */
+        ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+    if (!is_error(ret) && bswap_syctl(name, namelen, oldp, *oldlenp) != 0) {
+        return -ENOTDIR;
+    }
+#endif
+
+    if(name) {
+        //bswap_syctl(name, namelen, newp, newlen);
+        tswap32s((uint32_t*)oldlenp);
+
+        i = 0;
+        do { tswap32s( name + i); } while (++i < namelen);
+    }
+    return ret;
+}
+
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5)
+{
+    struct attrlist * attrlist = (void *)arg2;
+    long ret;
+
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+    gemu_log("SYS_getdirentriesattr unimplemented\n");
+    return -ENOTSUP;
+#endif
+    /* XXX: don't let the %s stay in there */
+    DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n",
+            (char *)arg1, arg2, arg3, arg4, arg5);
+
+    if(arg2) /* XXX: We should handle that in a copy especially
+        if the structure is not writable */
+        byteswap_attrlist(attrlist);
+
+    ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5));
+
+    if(!is_error(ret))
+    {
+        byteswap_attrbuf((void *)arg3, attrlist);
+        byteswap_attrlist(attrlist);
+    }
+    return ret;
+}
+
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8)
+{
+    DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n",
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+    qerror("SYS_getdirentriesattr unimplemented\n");
+#endif
+
+    return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4,
+                                       (unsigned long *)arg5, (unsigned long *)arg6,
+                                       (unsigned long *)arg7, arg8));
+}
+
+static inline void bswap_flock(struct flock *f)
+{
+    tswap64s(&f->l_start);
+    tswap64s(&f->l_len);
+    tswap32s(&f->l_pid);
+    tswap16s(&f->l_type);
+    tswap16s(&f->l_whence);
+}
+
+static inline void bswap_fstore(struct fstore *f)
+{
+    tswap32s(&f->fst_flags);
+    tswap32s(&f->fst_posmode);
+    tswap64s(&f->fst_offset);
+    tswap64s(&f->fst_length);
+    tswap64s(&f->fst_bytesalloc);
+}
+
+static inline void bswap_radvisory(struct radvisory *f)
+{
+    tswap64s(&f->ra_offset);
+    tswap32s(&f->ra_count);
+}
+
+static inline void bswap_fbootstraptransfer(struct fbootstraptransfer *f)
+{
+    tswap64s(&f->fbt_offset);
+    tswap32s((uint32_t*)&f->fbt_length);
+    tswap32s((uint32_t*)&f->fbt_buffer); /* XXX: this is a ptr */
+}
+
+static inline void bswap_log2phys(struct log2phys *f)
+{
+    tswap32s(&f->l2p_flags);
+    tswap64s(&f->l2p_contigbytes);
+    tswap64s(&f->l2p_devoffset);
+}
+
+static inline void bswap_fcntl_arg(int cmd, void * arg)
+{
+    switch(cmd)
+    {
+        case F_DUPFD:
+        case F_GETFD:
+        case F_SETFD:
+        case F_GETFL:
+        case F_SETFL:
+        case F_GETOWN:
+        case F_SETOWN:
+        case F_SETSIZE:
+        case F_RDAHEAD:
+        case F_FULLFSYNC:
+            break;
+        case F_GETLK:
+        case F_SETLK:
+        case F_SETLKW:
+            bswap_flock(arg);
+            break;
+        case F_PREALLOCATE:
+            bswap_fstore(arg);
+            break;
+        case F_RDADVISE:
+            bswap_radvisory(arg);
+            break;
+        case F_READBOOTSTRAP:
+        case F_WRITEBOOTSTRAP:
+            bswap_fbootstraptransfer(arg);
+            break;
+        case F_LOG2PHYS:
+            bswap_log2phys(arg);
+            break;
+        default:
+            gemu_log("unknow cmd in fcntl\n");
+    }
+}
+
+long do_fcntl(int fd, int cmd, int arg)
+{
+    long ret;
+    bswap_fcntl_arg(cmd, (void *)arg);
+    ret = get_errno(fcntl(fd, cmd, arg));
+    if(!is_error(ret))
+        bswap_fcntl_arg(cmd, (void *)arg);
+    return ret;
+}
+
+long no_syscall(void *cpu_env, int num)
+{
+    /* XXX: We should probably fordward it to the host kernel */
+    qerror("no unix syscall %d\n", num);
+    /* not reached */
+    return -1;
+}
+
+long unimpl_unix_syscall(void *cpu_env, int num)
+{
+    if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+        qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+    gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num);
+    gdb_handlesig (cpu_env, SIGTRAP);
+    exit(-1);
+}
+
+long do_unix_syscall(void *cpu_env, int num)
+{
+    long ret = 0;
+
+    DPRINTF("unix syscall %d: " , num);
+
+    if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+        qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+    DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" );
+    ret = unix_syscall_table[num].function(cpu_env, num);
+
+    if(!(unix_syscall_table[num].call_type & CALL_NOERRNO))
+        ret = get_errno(ret);
+
+    DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret);
+    return ret;
+}
+
+/* ------------------------------------------------------------
+   syscall_init
+*/
+void syscall_init(void)
+{
+    /* Nothing yet */
+}
diff --git a/qemu-0.15.x/darwin-user/syscalls.h b/qemu-0.15.x/darwin-user/syscalls.h
new file mode 100644
index 0000000..34d95da
--- /dev/null
+++ b/qemu-0.15.x/darwin-user/syscalls.h
@@ -0,0 +1,384 @@
+/* generated from xnu/bsd/kern/syscalls.master */
+
+ ENTRY("syscall",                  SYS_syscall,                        do_unix_syscall_indirect,          0, CALL_INDIRECT, VOID) /* 0  indirect syscall */
+ ENTRY("exit",                     SYS_exit,                           do_exit,                           1, CALL_DIRECT, INT)   /* 1  */
+ ENTRY("fork",                     SYS_fork,                           fork,                              0, CALL_NOERRNO, VOID)  /* 2  */
+ ENTRY("read",                     SYS_read,                           do_read,                           3, CALL_DIRECT, INT, PTR, SIZE)   /* 3  */
+ ENTRY("write",                    SYS_write,                          write,                             3, CALL_DIRECT, INT, PTR, SIZE)   /* 4  */
+ ENTRY("open",                     SYS_open,                           do_open,                           3, CALL_DIRECT, PTR, INT, INT)   /* 5  */
+ ENTRY("close",                    SYS_close,                          close,                             1, CALL_DIRECT, INT)   /* 6  */
+ ENTRY("wait4",                    SYS_wait4,                          wait4,                             4, CALL_DIRECT, INT, PTR, INT, PTR)   /* 7  */
+ ENTRY("",                         8,                                  no_syscall,                        0, CALL_INDIRECT, VOID) /* 8  old creat */
+ ENTRY("link",                     SYS_link,                           link,                              2, CALL_DIRECT, PTR, PTR)   /* 9  */
+ ENTRY("unlink",                   SYS_unlink,                         unlink,                            1, CALL_DIRECT, PTR)   /* 10  */
+ ENTRY("",                         11,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 11  old execv */
+ ENTRY("chdir",                    SYS_chdir,                          chdir,                             1, CALL_DIRECT, PTR)   /* 12  */
+ ENTRY("fchdir",                   SYS_fchdir,                         fchdir,                            1, CALL_DIRECT, INT)   /* 13  */
+ ENTRY("mknod",                    SYS_mknod,                          mknod,                             3, CALL_DIRECT, PTR, INT, INT)   /* 14  */
+ ENTRY("chmod",                    SYS_chmod,                          chmod,                             2, CALL_DIRECT, PTR, INT)   /* 15  */
+ ENTRY("chown",                    SYS_chown,                          chown,                             3, CALL_DIRECT, PTR, INT, INT)   /* 16  */
+ ENTRY("obreak",                   SYS_obreak,                         no_syscall,                        1, CALL_INDIRECT, VOID)   /* 17  old break */
+ ENTRY("ogetfsstat",               18,                                 unimpl_unix_syscall,               3, CALL_INDIRECT, PTR, INT, INT)   /* 18  */
+ ENTRY("",                         19,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 19  old lseek */
+ ENTRY("getpid",                   SYS_getpid,                         getpid,                            0, CALL_NOERRNO, VOID)   /* 20  */
+ ENTRY("",                         21,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 21  old mount */
+ ENTRY("",                         22,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 22  old umount */
+ ENTRY("setuid",                   SYS_setuid,                         setuid,                            1, CALL_DIRECT, INT)   /* 23  */
+ ENTRY("getuid",                   SYS_getuid,                         getuid,                            0, CALL_NOERRNO, VOID)   /* 24  */
+ ENTRY("geteuid",                  SYS_geteuid,                        geteuid,                           0, CALL_NOERRNO, VOID)   /* 25  */
+ ENTRY("ptrace",                   SYS_ptrace,                         ptrace,                            4, CALL_DIRECT, INT, INT, PTR, INT)   /* 26  */
+ ENTRY("recvmsg",                  SYS_recvmsg,                        recvmsg,                           3, CALL_DIRECT, INT, PTR, INT)   /* 27  */
+ ENTRY("sendmsg",                  SYS_sendmsg,                        sendmsg,                           3, CALL_DIRECT, INT, PTR, INT)   /* 28  */
+ ENTRY("recvfrom",                 SYS_recvfrom,                       recvfrom,                          6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR)   /* 29  */
+ ENTRY("accept",                   SYS_accept,                         accept,                            3, CALL_DIRECT, INT, PTR, PTR)   /* 30  */
+ ENTRY("getpeername",              SYS_getpeername,                    getpeername,                       3, CALL_DIRECT, INT, PTR, PTR)   /* 31  */
+ ENTRY("getsockname",              SYS_getsockname,                    getsockname,                       3, CALL_DIRECT, INT, PTR, PTR)   /* 32  */
+ ENTRY("access",                   SYS_access,                         access,                            2, CALL_DIRECT, PTR, INT)   /* 33  */
+ ENTRY("chflags",                  SYS_chflags,                        chflags,                           2, CALL_DIRECT, PTR, INT)   /* 34  */
+ ENTRY("fchflags",                 SYS_fchflags,                       fchflags,                          2, CALL_DIRECT, INT, INT)   /* 35  */
+ ENTRY("sync",                     SYS_sync,                           do_sync,                           0, CALL_INDIRECT, VOID)   /* 36  */
+ ENTRY("kill",                     SYS_kill,                           kill,                              2, CALL_DIRECT, INT, INT)   /* 37  */
+ ENTRY("",                         38,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 38  old stat */
+ ENTRY("getppid",                  SYS_getppid,                        getppid,                           0, CALL_DIRECT, VOID)   /* 39  */
+ ENTRY("",                         40,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 40  old lstat */
+ ENTRY("dup",                      SYS_dup,                            dup,                               1, CALL_DIRECT, INT)   /* 41  */
+ ENTRY("pipe",                     SYS_pipe,                           pipe,               0, CALL_INDIRECT, PTR)   /* 42  */
+ ENTRY("getegid",                  SYS_getegid,                        getegid,                           0, CALL_NOERRNO, VOID)  /* 43  */
+ ENTRY("profil",                   SYS_profil,                         profil,                            4, CALL_DIRECT, PTR, SIZE, INT, INT)   /* 44  */
+ ENTRY("ktrace",                   SYS_ktrace,                         no_syscall,                        4, CALL_INDIRECT, VOID) /* 45  */
+ ENTRY("sigaction",                SYS_sigaction,                      do_sigaction,                      3, CALL_DIRECT, INT, PTR, PTR)   /* 46  */
+ ENTRY("getgid",                   SYS_getgid,                         getgid,                            0, CALL_NOERRNO, VOID)  /* 47  */
+ ENTRY("sigprocmask",              SYS_sigprocmask,                    do_sigprocmask,                    3, CALL_DIRECT, INT, PTR, PTR)   /* 48  */
+ ENTRY("getlogin",                 SYS_getlogin,                       do_getlogin,                       2, CALL_DIRECT, PTR, UINT)   /* 49 XXX */
+ ENTRY("setlogin",                 SYS_setlogin,                       setlogin,                          1, CALL_DIRECT, PTR)   /* 50  */
+ ENTRY("acct",                     SYS_acct,                           acct,                              1, CALL_DIRECT, PTR)   /* 51  */
+ ENTRY("sigpending",               SYS_sigpending,                     sigpending,                        1, CALL_DIRECT, PTR)   /* 52  */
+ ENTRY("sigaltstack",              SYS_sigaltstack,                    do_sigaltstack,                    2, CALL_DIRECT, PTR, PTR)   /* 53  */
+ ENTRY("ioctl",                    SYS_ioctl,                          do_ioctl,                          3, CALL_DIRECT, INT, INT, INT)   /* 54  */
+ ENTRY("reboot",                   SYS_reboot,                         unimpl_unix_syscall,               2, CALL_INDIRECT, INT, PTR)   /* 55  */
+ ENTRY("revoke",                   SYS_revoke,                         revoke,                            1, CALL_DIRECT, PTR)   /* 56  */
+ ENTRY("symlink",                  SYS_symlink,                        symlink,                           2, CALL_DIRECT, PTR, PTR)   /* 57  */
+ ENTRY("readlink",                 SYS_readlink,                       readlink,                          3, CALL_DIRECT, PTR, PTR, INT)   /* 58  */
+ ENTRY("execve",                   SYS_execve,                         do_execve,                         3, CALL_DIRECT, PTR, PTR, PTR)   /* 59  */
+ ENTRY("umask",                    SYS_umask,                          umask,                             1, CALL_DIRECT, INT)   /* 60  */
+ ENTRY("chroot",                   SYS_chroot,                         chroot,                            1, CALL_DIRECT, PTR)   /* 61  */
+ ENTRY("",                         62,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 62  old fstat */
+ ENTRY("",                         63,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 63  used internally , reserved */
+ ENTRY("",                         64,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 64  old getpagesize */
+ ENTRY("msync",                    SYS_msync,                          target_msync,                      3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT)   /* 65  */
+ ENTRY("vfork",                    SYS_vfork,                          vfork,                             0, CALL_DIRECT, VOID)   /* 66  */
+ ENTRY("",                         67,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 67  old vread */
+ ENTRY("",                         68,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 68  old vwrite */
+ ENTRY("sbrk",                     SYS_sbrk,                           sbrk,                              1, CALL_DIRECT, INT)   /* 69  */
+ ENTRY("sstk",                     SYS_sstk,                           no_syscall,                        1, CALL_INDIRECT, VOID) /* 70  */
+ ENTRY("",                         71,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 71  old mmap */
+ ENTRY("ovadvise",                 SYS_ovadvise,                       no_syscall,                        0, CALL_INDIRECT, VOID) /* 72  old vadvise */
+ ENTRY("munmap",                   SYS_munmap,                         target_munmap,                     2, CALL_DIRECT, UINT /* PTR */, SIZE)   /* 73  */
+ ENTRY("mprotect",                 SYS_mprotect,                       mprotect,                          3, CALL_DIRECT, PTR, SIZE, INT)   /* 74  */
+ ENTRY("madvise",                  SYS_madvise,                        madvise,                           3, CALL_DIRECT, PTR, SIZE, INT)   /* 75  */
+ ENTRY("",                         76,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 76  old vhangup */
+ ENTRY("",                         77,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 77  old vlimit */
+ ENTRY("mincore",                  SYS_mincore,                        mincore,                           3, CALL_DIRECT, PTR, SIZE, PTR)   /* 78  */
+ ENTRY("getgroups",                SYS_getgroups,                      do_getgroups,                      2, CALL_DIRECT, UINT, PTR)   /* 79  */
+ ENTRY("setgroups",                SYS_setgroups,                      setgroups,                         2, CALL_DIRECT, UINT, PTR)   /* 80  */
+ ENTRY("getpgrp",                  SYS_getpgrp,                        getpgrp,                           0, CALL_DIRECT, VOID)   /* 81  */
+ ENTRY("setpgid",                  SYS_setpgid,                        setpgid,                           2, CALL_DIRECT, INT, INT)   /* 82  */
+ ENTRY("setitimer",                SYS_setitimer,                      setitimer,                         3, CALL_DIRECT, INT, PTR, PTR)   /* 83  */
+ ENTRY("",                         84,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 84  old wait */
+ ENTRY("swapon",                   SYS_swapon,                         unimpl_unix_syscall,               0, CALL_INDIRECT, VOID)   /* 85  */
+ ENTRY("getitimer",                SYS_getitimer,                      getitimer,                         2, CALL_DIRECT, INT, PTR)   /* 86  */
+ ENTRY("",                         87,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 87  old gethostname */
+ ENTRY("",                         88,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 88  old sethostname */
+ ENTRY("getdtablesize",            SYS_getdtablesize,                  getdtablesize,                     0, CALL_DIRECT, VOID)   /* 89  */
+ ENTRY("dup2",                     SYS_dup2,                           dup2,                              2, CALL_DIRECT, INT, INT)   /* 90  */
+ ENTRY("",                         91,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 91  old getdopt */
+ ENTRY("fcntl",                    SYS_fcntl,                          do_fcntl,                          3, CALL_DIRECT, INT, INT, INT)   /* 92  */
+ ENTRY("select",                   SYS_select,                         select,                            5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR)   /* 93  */
+ ENTRY("",                         94,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 94  old setdopt */
+ ENTRY("fsync",                    SYS_fsync,                          fsync,                             1, CALL_DIRECT, INT)   /* 95  */
+ ENTRY("setpriority",              SYS_setpriority,                    setpriority,                       3, CALL_DIRECT, INT, INT, INT)   /* 96  */
+ ENTRY("socket",                   SYS_socket,                         socket,                            3, CALL_DIRECT, INT, INT, INT)   /* 97  */
+ ENTRY("connect",                  SYS_connect,                        connect,                           3, CALL_DIRECT, INT, PTR, INT)   /* 98  */
+ ENTRY("",                         99,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 99  old accept */
+ ENTRY("getpriority",              SYS_getpriority,                    getpriority,                       2, CALL_DIRECT, INT, INT)   /* 100  */
+ ENTRY("",                         101,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 101  old send */
+ ENTRY("",                         102,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 102  old recv */
+ ENTRY("",                         103,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 103  old sigreturn */
+ ENTRY("bind",                     SYS_bind,                           bind,                              3, CALL_DIRECT, INT, PTR, INT)   /* 104  */
+ ENTRY("setsockopt",               SYS_setsockopt,                     setsockopt,                        5, CALL_DIRECT, INT, INT, INT, PTR, INT)   /* 105  */
+ ENTRY("listen",                   SYS_listen,                         listen,                            2, CALL_DIRECT, INT, INT)   /* 106  */
+ ENTRY("",                         107,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 107  old vtimes */
+ ENTRY("",                         108,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 108  old sigvec */
+ ENTRY("",                         109,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 109  old sigblock */
+ ENTRY("",                         110,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 110  old sigsetmask */
+ ENTRY("sigsuspend",               SYS_sigsuspend,                     unimpl_unix_syscall,               1, CALL_INDIRECT, INT)   /* 111  */
+ ENTRY("",                         112,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 112  old sigstack */
+ ENTRY("",                         113,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 113  old recvmsg */
+ ENTRY("",                         114,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 114  old sendmsg */
+ ENTRY("",                         115,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 115  old vtrace */
+ ENTRY("gettimeofday",             SYS_gettimeofday,                   do_gettimeofday,                   2, CALL_DIRECT, PTR, PTR) /* 116  */
+ ENTRY("getrusage",                SYS_getrusage,                      getrusage,                         2, CALL_DIRECT, INT, PTR)   /* 117  */
+ ENTRY("getsockopt",               SYS_getsockopt,                     getsockopt,                        5, CALL_DIRECT, INT, INT, INT, PTR, PTR)   /* 118  */
+ ENTRY("",                         119,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 119  old resuba */
+ ENTRY("readv",                    SYS_readv,                          do_readv,                          3, CALL_DIRECT, INT, PTR, UINT)   /* 120  */
+ ENTRY("writev",                   SYS_writev,                         do_writev,                         3, CALL_DIRECT, INT, PTR, UINT)   /* 121  */
+ ENTRY("settimeofday",             SYS_settimeofday,                   settimeofday,                      2, CALL_DIRECT, PTR, PTR)   /* 122  */
+ ENTRY("fchown",                   SYS_fchown,                         fchown,                            3, CALL_DIRECT, INT, INT, INT)   /* 123  */
+ ENTRY("fchmod",                   SYS_fchmod,                         fchmod,                            2, CALL_DIRECT, INT, INT)   /* 124  */
+ ENTRY("",                         125,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 125  old recvfrom */
+ ENTRY("",                         126,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 126  old setreuid */
+ ENTRY("",                         127,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 127  old setregid */
+ ENTRY("rename",                   SYS_rename,                         rename,                            2, CALL_DIRECT, PTR, PTR)   /* 128  */
+ ENTRY("",                         129,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 129  old truncate */
+ ENTRY("",                         130,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 130  old ftruncate */
+ ENTRY("flock",                    SYS_flock,                          flock,                             2, CALL_DIRECT, INT, INT)   /* 131  */
+ ENTRY("mkfifo",                   SYS_mkfifo,                         mkfifo,                            2, CALL_DIRECT, PTR, INT)   /* 132  */
+ ENTRY("sendto",                   SYS_sendto,                         sendto,                            6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT)   /* 133  */
+ ENTRY("shutdown",                 SYS_shutdown,                       shutdown,                          2, CALL_DIRECT, INT, INT)   /* 134  */
+ ENTRY("socketpair",               SYS_socketpair,                     socketpair,                        4, CALL_DIRECT, INT, INT, INT, PTR)   /* 135  */
+ ENTRY("mkdir",                    SYS_mkdir,                          mkdir,                             2, CALL_DIRECT, PTR, INT)   /* 136  */
+ ENTRY("rmdir",                    SYS_rmdir,                          rmdir,                             1, CALL_DIRECT, PTR)   /* 137  */
+ ENTRY("utimes",                   SYS_utimes,                         do_utimes,                         2, CALL_DIRECT, PTR, PTR)   /* 138  */
+ ENTRY("futimes",                  SYS_futimes,                        do_futimes,                        2, CALL_DIRECT, INT, PTR)   /* 139  */
+ ENTRY("adjtime",                  SYS_adjtime,                        adjtime,                           2, CALL_DIRECT, PTR, PTR)   /* 140  */
+ ENTRY("",                         141,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 141  old getpeername */
+ ENTRY("",                         142,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 142  old gethostid */
+ ENTRY("",                         143,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 143  old sethostid */
+ ENTRY("",                         144,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 144  old getrlimit */
+ ENTRY("",                         145,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 145  old setrlimit */
+ ENTRY("",                         146,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 146  old killpg */
+ ENTRY("setsid",                   SYS_setsid,                         setsid,                            0, CALL_DIRECT, VOID)   /* 147  */
+ ENTRY("",                         148,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 148  old setquota */
+ ENTRY("",                         149,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 149  old qquota */
+ ENTRY("",                         150,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 150  old getsockname */
+ ENTRY("getpgid",                  SYS_getpgid,                        getpgid,                           1, CALL_DIRECT, INT)   /* 151  */
+ ENTRY("setprivexec",              SYS_setprivexec,                    no_syscall,                        1, CALL_INDIRECT, VOID) /* 152  */
+ ENTRY("pread",                    SYS_pread,                          do_pread,                          4, CALL_DIRECT, INT, PTR, SIZE, OFFSET)   /* 153  */
+ ENTRY("pwrite",                   SYS_pwrite,                         pwrite,                            4, CALL_DIRECT, INT, PTR, SIZE, OFFSET)   /* 154  */
+#ifdef SYS_nfssvc
+ ENTRY("nfssvc",                   SYS_nfssvc,                         nfssvc,                            2, CALL_DIRECT, INT, PTR)   /* 155  */
+#else
+ ENTRY("nfssvc",                   155,                                no_syscall,                        2, CALL_INDIRECT, VOID)   /* 155  */
+#endif
+ ENTRY("",                         155,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 155  */
+ ENTRY("",                         156,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 156  old getdirentries */
+ ENTRY("statfs",                   SYS_statfs,                         do_statfs,                         2, CALL_DIRECT, PTR, PTR)   /* 157  */
+ ENTRY("fstatfs",                  SYS_fstatfs,                        do_fstatfs,                        2, CALL_DIRECT, INT, PTR)   /* 158  */
+ ENTRY("unmount",                  SYS_unmount,                        unmount,                           2, CALL_DIRECT, PTR, INT)   /* 159  */
+ ENTRY("",                         160,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 160  old async_daemon */
+ ENTRY("",                         161,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 161  */
+ ENTRY("",                         162,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 162  old getdomainname */
+ ENTRY("",                         163,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 163  old setdomainname */
+ ENTRY("",                         164,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 164  */
+ ENTRY("quotactl",                 SYS_quotactl,                       no_syscall,                        4, CALL_INDIRECT, VOID) /* 165  */
+ ENTRY("",                         166,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 166  old exportfs */
+ ENTRY("mount",                    SYS_mount,                          mount,                             4, CALL_DIRECT, PTR, PTR, INT, PTR)   /* 167  */
+ ENTRY("",                         168,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 168  old ustat */
+ ENTRY("",                         169,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 169  */
+ ENTRY("table",                    SYS_table,                          no_syscall,                        0, CALL_INDIRECT, VOID) /* 170  old table */
+ ENTRY("",                         171,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 171  old wait3 */
+ ENTRY("",                         172,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 172  old rpause */
+ ENTRY("waitid",                   SYS_waitid,                         unimpl_unix_syscall,               4, CALL_INDIRECT, VOID) /* 173  */
+ ENTRY("",                         174,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 174  old getdents */
+ ENTRY("",                         175,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 175  old gc_control */
+ ENTRY("add_profil",               SYS_add_profil,                     add_profil,                        4, CALL_DIRECT, PTR, SIZE, UINT, UINT)   /* 176  */
+ ENTRY("",                         177,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 177  */
+ ENTRY("",                         178,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 178  */
+ ENTRY("",                         179,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 179  */
+ ENTRY("kdebug_trace",             SYS_kdebug_trace,                   no_syscall,                        6, CALL_INDIRECT, VOID) /* 180  */
+ ENTRY("setgid",                   SYS_setgid,                         setgid,                            1, CALL_DIRECT, INT)   /* 181  */
+ ENTRY("setegid",                  SYS_setegid,                        setegid,                           1, CALL_DIRECT, INT)   /* 182  */
+ ENTRY("seteuid",                  SYS_seteuid,                        seteuid,                           1, CALL_DIRECT, INT)   /* 183  */
+ ENTRY("sigreturn",                SYS_sigreturn,                      do_sigreturn,                      2, CALL_INDIRECT, PTR, INT)   /* 184  */
+ ENTRY("chud",                     SYS_chud,                           unimpl_unix_syscall,               6, CALL_INDIRECT, VOID)   /* 185  */
+ ENTRY("",                         186,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 186  */
+ ENTRY("",                         187,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 187  */
+ ENTRY("stat",                     SYS_stat,                           do_stat,                           2, CALL_DIRECT, PTR, PTR)   /* 188  */
+ ENTRY("fstat",                    SYS_fstat,                          do_fstat,                          2, CALL_DIRECT, INT, PTR)   /* 189  */
+ ENTRY("lstat",                    SYS_lstat,                          do_lstat,                          2, CALL_DIRECT, PTR, PTR)   /* 190  */
+ ENTRY("pathconf",                 SYS_pathconf,                       pathconf,                          2, CALL_DIRECT, PTR, INT)   /* 191  */
+ ENTRY("fpathconf",                SYS_fpathconf,                      fpathconf,                         2, CALL_DIRECT, INT, INT)   /* 192  */
+ ENTRY("getfsstat",                SYS_getfsstat,                      do_getfsstat,                      3, CALL_DIRECT, PTR, INT, INT)   /* 193  */
+ ENTRY("",                         193,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 193  */
+ ENTRY("getrlimit",                SYS_getrlimit,                      getrlimit,                         2, CALL_DIRECT, UINT, PTR)   /* 194  */
+ ENTRY("setrlimit",                SYS_setrlimit,                      setrlimit,                         2, CALL_DIRECT, UINT, PTR)   /* 195  */
+ ENTRY("getdirentries",            SYS_getdirentries,                  do_getdirentries,                  4, CALL_DIRECT, INT, PTR, UINT, PTR)   /* 196  */
+ ENTRY("mmap",                     SYS_mmap,                           target_mmap,                       6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET)   /* 197  */
+ ENTRY("",                         198,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 198  __syscall */
+ ENTRY("lseek",                    SYS_lseek,                          do_lseek,                          3, CALL_INDIRECT, INT, OFFSET, INT)   /* 199  */
+ ENTRY("truncate",                 SYS_truncate,                       truncate,                          2, CALL_DIRECT, PTR, OFFSET)   /* 200  */
+ ENTRY("ftruncate",                SYS_ftruncate,                      ftruncate,                         2, CALL_DIRECT, INT, OFFSET)   /* 201  */
+ ENTRY("__sysctl",                 SYS___sysctl,                       do___sysctl,                       6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE)   /* 202  */
+ ENTRY("mlock",                    SYS_mlock,                          mlock,                             2, CALL_DIRECT, PTR, SIZE)   /* 203  */
+ ENTRY("munlock",                  SYS_munlock,                        munlock,                           2, CALL_DIRECT, PTR, SIZE)   /* 204  */
+ ENTRY("undelete",                 SYS_undelete,                       undelete,                          1, CALL_DIRECT, PTR)   /* 205  */
+ ENTRY("ATsocket",                 SYS_ATsocket,                       no_syscall,                        1, CALL_INDIRECT, VOID) /* 206  */
+ ENTRY("ATgetmsg",                 SYS_ATgetmsg,                       no_syscall,                        4, CALL_INDIRECT, VOID) /* 207  */
+ ENTRY("ATputmsg",                 SYS_ATputmsg,                       no_syscall,                        4, CALL_INDIRECT, VOID) /* 208  */
+ ENTRY("ATPsndreq",                SYS_ATPsndreq,                      no_syscall,                        4, CALL_INDIRECT, VOID) /* 209  */
+ ENTRY("ATPsndrsp",                SYS_ATPsndrsp,                      no_syscall,                        4, CALL_INDIRECT, VOID) /* 210  */
+ ENTRY("ATPgetreq",                SYS_ATPgetreq,                      no_syscall,                        3, CALL_INDIRECT, VOID) /* 211  */
+ ENTRY("ATPgetrsp",                SYS_ATPgetrsp,                      no_syscall,                        2, CALL_INDIRECT, VOID) /* 212  */
+ ENTRY("",                         213,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 213  Reserved for AppleTalk */
+ ENTRY("kqueue_from_portset_np",   SYS_kqueue_from_portset_np,         no_syscall,                        1, CALL_INDIRECT, VOID) /* 214  */
+ ENTRY("kqueue_portset_np",        SYS_kqueue_portset_np,              no_syscall,                        1, CALL_INDIRECT, VOID) /* 215  */
+ ENTRY("mkcomplex",                SYS_mkcomplex,                      no_syscall,                        3, CALL_INDIRECT, VOID)   /* 216  soon to be obsolete */
+ ENTRY("statv",                    SYS_statv,                          no_syscall,                        2, CALL_INDIRECT, VOID)   /* 217  soon to be obsolete */
+ ENTRY("lstatv",                   SYS_lstatv,                         no_syscall,                        2, CALL_INDIRECT, VOID)   /* 218  soon to be obsolete */
+ ENTRY("fstatv",                   SYS_fstatv,                         no_syscall,                        2, CALL_INDIRECT, VOID)   /* 219  soon to be obsolete */
+ ENTRY("getattrlist",              SYS_getattrlist,                    do_getattrlist,                    5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT)   /* 220  */
+ ENTRY("setattrlist",              SYS_setattrlist,                    unimpl_unix_syscall,               5, CALL_INDIRECT, VOID) /* 221  */
+ ENTRY("getdirentriesattr",        SYS_getdirentriesattr,              do_getdirentriesattr,              8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT)   /* 222  */
+ ENTRY("exchangedata",             SYS_exchangedata,                   exchangedata,                      3, CALL_DIRECT, PTR, PTR, UINT)   /* 223  */
+ ENTRY("checkuseraccess",          SYS_checkuseraccess,                checkuseraccess,                   6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT)   /* 224  */
+ ENTRY("",                         224,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 224  HFS checkuseraccess check access to a file */
+ ENTRY("searchfs",                 SYS_searchfs,                       searchfs,                          6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR)   /* 225  */
+ ENTRY("delete",                   SYS_delete,                         no_syscall,                        1, CALL_INDIRECT, VOID)   /* 226  private delete ( Carbon semantics ) */
+ ENTRY("copyfile",                 SYS_copyfile,                       no_syscall,                        4, CALL_INDIRECT, VOID)   /* 227  */
+ ENTRY("",                         228,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 228  */
+ ENTRY("",                         229,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 229  */
+ ENTRY("poll",                     SYS_poll,                           no_syscall,                        3, CALL_INDIRECT, VOID) /* 230  */
+ ENTRY("watchevent",               SYS_watchevent,                     no_syscall,                        2, CALL_INDIRECT, VOID)   /* 231  */
+ ENTRY("waitevent",                SYS_waitevent,                      no_syscall,                        2, CALL_INDIRECT, VOID)   /* 232  */
+ ENTRY("modwatch",                 SYS_modwatch,                       no_syscall,                        2, CALL_INDIRECT, VOID)   /* 233  */
+ ENTRY("getxattr",                 SYS_getxattr,                       no_syscall,                        6, CALL_INDIRECT, VOID)   /* 234  */
+ ENTRY("fgetxattr",                SYS_fgetxattr,                      no_syscall,                        6, CALL_INDIRECT, VOID)   /* 235  */
+ ENTRY("setxattr",                 SYS_setxattr,                       no_syscall,                        6, CALL_INDIRECT, VOID)   /* 236  */
+ ENTRY("fsetxattr",                SYS_fsetxattr,                      no_syscall,                        6, CALL_INDIRECT, VOID)   /* 237  */
+ ENTRY("removexattr",              SYS_removexattr,                    no_syscall,                        3, CALL_INDIRECT, VOID)   /* 238  */
+ ENTRY("fremovexattr",             SYS_fremovexattr,                   no_syscall,                        3, CALL_INDIRECT, VOID)   /* 239  */
+ ENTRY("listxattr",                SYS_listxattr,                      listxattr,                         4, CALL_INDIRECT, VOID)   /* 240  */
+ ENTRY("flistxattr",               SYS_flistxattr,                     no_syscall,                        4, CALL_INDIRECT, VOID)   /* 241  */
+ ENTRY("fsctl",                    SYS_fsctl,                          fsctl,                             4, CALL_DIRECT, PTR, UINT, PTR, UINT)   /* 242  */
+ ENTRY("initgroups",               SYS_initgroups,                     unimpl_unix_syscall,               3, CALL_INDIRECT, UINT, PTR, INT)   /* 243  */
+ ENTRY("",                         244,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 244  */
+ ENTRY("",                         245,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 245  */
+ ENTRY("",                         246,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 246  */
+#ifdef SYS_nfsclnt
+ ENTRY("nfsclnt",                  SYS_nfsclnt,                        nfsclnt,                           2, CALL_DIRECT, INT, PTR)   /* 247  */
+#else
+ ENTRY("nfsclnt",                  247,                                no_syscall,                        2, CALL_INDIRECT, VOID)   /* 247  */
+#endif
+ ENTRY("",                         247,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 247  */
+ ENTRY("",                         248,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 248  */
+ ENTRY("",                         249,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 249  */
+ ENTRY("minherit",                 SYS_minherit,                       minherit,                          3, CALL_DIRECT, PTR, INT, INT)   /* 250  */
+ ENTRY("semsys",                   SYS_semsys,                         unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 251  */
+ ENTRY("msgsys",                   SYS_msgsys,                         unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 252  */
+ ENTRY("shmsys",                   SYS_shmsys,                         unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 253  */
+ ENTRY("semctl",                   SYS_semctl,                         unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 254  */
+ ENTRY("semget",                   SYS_semget,                         unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 255  */
+ ENTRY("semop",                    SYS_semop,                          unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 256  */
+ ENTRY("",                         257,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 257  */
+ ENTRY("msgctl",                   SYS_msgctl,                         unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 258  */
+ ENTRY("msgget",                   SYS_msgget,                         unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 259  */
+ ENTRY("msgsnd",                   SYS_msgsnd,                         unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 260  */
+ ENTRY("msgrcv",                   SYS_msgrcv,                         unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 261  */
+ ENTRY("shmat",                    SYS_shmat,                          unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 262  */
+ ENTRY("shmctl",                   SYS_shmctl,                         unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 263  */
+ ENTRY("shmdt",                    SYS_shmdt,                          unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 264  */
+ ENTRY("shmget",                   SYS_shmget,                         unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 265  */
+ ENTRY("shm_open",                 SYS_shm_open,                       shm_open,                          3, CALL_DIRECT, PTR, INT, INT)   /* 266  */
+ ENTRY("shm_unlink",               SYS_shm_unlink,                     shm_unlink,                        1, CALL_DIRECT, PTR)   /* 267  */
+ ENTRY("sem_open",                 SYS_sem_open,                       unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 268  */
+ ENTRY("sem_close",                SYS_sem_close,                      unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 269  */
+ ENTRY("sem_unlink",               SYS_sem_unlink,                     unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 270  */
+ ENTRY("sem_wait",                 SYS_sem_wait,                       unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 271  */
+ ENTRY("sem_trywait",              SYS_sem_trywait,                    unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 272  */
+ ENTRY("sem_post",                 SYS_sem_post,                       unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 273  */
+ ENTRY("sem_getvalue",             SYS_sem_getvalue,                   unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 274  */
+ ENTRY("sem_init",                 SYS_sem_init,                       unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 275  */
+ ENTRY("sem_destroy",              SYS_sem_destroy,                    unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 276  */
+ ENTRY("open_extended",            SYS_open_extended,                  unimpl_unix_syscall,               6, CALL_INDIRECT, VOID)   /* 277  */
+ ENTRY("umask_extended",           SYS_umask_extended,                 unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 278  */
+ ENTRY("stat_extended",            SYS_stat_extended,                  unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 279  */
+ ENTRY("lstat_extended",           SYS_lstat_extended,                 unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 280  */
+ ENTRY("fstat_extended",           SYS_fstat_extended,                 unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 281  */
+ ENTRY("chmod_extended",           SYS_chmod_extended,                 unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 282  */
+ ENTRY("fchmod_extended",          SYS_fchmod_extended,                unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 283  */
+ ENTRY("access_extended",          SYS_access_extended,                unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 284  */
+ ENTRY("settid",                   SYS_settid,                         unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 285  */
+ ENTRY("gettid",                   SYS_gettid,                         unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 286  */
+ ENTRY("setsgroups",               SYS_setsgroups,                     unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 287  */
+ ENTRY("getsgroups",               SYS_getsgroups,                     unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 288  */
+ ENTRY("setwgroups",               SYS_setwgroups,                     unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 289  */
+ ENTRY("getwgroups",               SYS_getwgroups,                     unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 290  */
+ ENTRY("mkfifo_extended",          SYS_mkfifo_extended,                unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 291  */
+ ENTRY("mkdir_extended",           SYS_mkdir_extended,                 unimpl_unix_syscall,               5, CALL_INDIRECT, VOID)   /* 292  */
+ ENTRY("identitysvc",              SYS_identitysvc,                    unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 293  */
+ ENTRY("",                         294,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 294  */
+ ENTRY("",                         295,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 295  */
+ ENTRY("load_shared_file",         SYS_load_shared_file,               unimpl_unix_syscall,               7, CALL_INDIRECT, VOID)   /* 296  */
+ ENTRY("reset_shared_file",        SYS_reset_shared_file,              unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 297  */
+ ENTRY("new_system_shared_regions",  SYS_new_system_shared_regions,    unimpl_unix_syscall,               0, CALL_INDIRECT, VOID)   /* 298  */
+ ENTRY("shared_region_map_file_np",  SYS_shared_region_map_file_np,    unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 299  */
+ ENTRY("shared_region_make_private_np",  SYS_shared_region_make_private_np,  unimpl_unix_syscall,         2, CALL_INDIRECT, VOID)   /* 300  */
+ ENTRY("",                         301,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 301  */
+ ENTRY("",                         302,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 302  */
+ ENTRY("",                         303,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 303  */
+ ENTRY("",                         304,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 304  */
+ ENTRY("",                         305,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 305  */
+ ENTRY("",                         306,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 306  */
+ ENTRY("",                         307,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 307  */
+ ENTRY("",                         308,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 308  */
+ ENTRY("",                         309,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 309  */
+ ENTRY("getsid",                   SYS_getsid,                         getsid,                            1, CALL_DIRECT, INT)   /* 310  */
+ ENTRY("settid_with_pid",          SYS_settid_with_pid,                unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 311  */
+ ENTRY("",                         312,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 312  */
+ ENTRY("aio_fsync",                SYS_aio_fsync,                      unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 313  */
+ ENTRY("aio_return",               SYS_aio_return,                     unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 314  */
+ ENTRY("aio_suspend",              SYS_aio_suspend,                    unimpl_unix_syscall,               3, CALL_INDIRECT, VOID)   /* 315  */
+ ENTRY("aio_cancel",               SYS_aio_cancel,                     unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 316  */
+ ENTRY("aio_error",                SYS_aio_error,                      unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 317  */
+ ENTRY("aio_read",                 SYS_aio_read,                       unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 318  */
+ ENTRY("aio_write",                SYS_aio_write,                      unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 319  */
+ ENTRY("lio_listio",               SYS_lio_listio,                     unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 320  */
+ ENTRY("",                         321,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 321  */
+ ENTRY("",                         322,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 322  */
+ ENTRY("",                         323,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 323  */
+ ENTRY("mlockall",                 SYS_mlockall,                       mlockall,                          1, CALL_DIRECT, INT)   /* 324  */
+ ENTRY("munlockall",               SYS_munlockall,                     unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 325  */
+ ENTRY("",                         326,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 326  */
+ ENTRY("issetugid",                SYS_issetugid,                      issetugid,                         0, CALL_DIRECT, VOID)   /* 327  */
+ ENTRY("__pthread_kill",           SYS___pthread_kill,                 unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 328  */
+ ENTRY("pthread_sigmask",          SYS_pthread_sigmask,                pthread_sigmask,                   3, CALL_DIRECT, INT, PTR, PTR)   /* 329  */
+ ENTRY("sigwait",                  SYS_sigwait,                        sigwait,                           2, CALL_DIRECT, PTR, PTR)   /* 330  */
+ ENTRY("__disable_threadsignal",   SYS___disable_threadsignal,         unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 331  */
+ ENTRY("__pthread_markcancel",     SYS___pthread_markcancel,           unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 332  */
+ ENTRY("__pthread_canceled",       SYS___pthread_canceled,             unimpl_unix_syscall,               1, CALL_INDIRECT, VOID)   /* 333  */
+ ENTRY("__semwait_signal",         SYS___semwait_signal,               unimpl_unix_syscall,               6, CALL_INDIRECT, VOID)   /* 334  */
+ ENTRY("utrace",                   SYS_utrace,                         unimpl_unix_syscall,               2, CALL_INDIRECT, VOID)   /* 335  */
+ ENTRY("proc_info",                SYS_proc_info,                      unimpl_unix_syscall,               6, CALL_INDIRECT, VOID)   /* 336  */
+ ENTRY("",                         337,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 337  */
+ ENTRY("",                         338,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 338  */
+ ENTRY("",                         339,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 339  */
+ ENTRY("",                         340,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 340  */
+ ENTRY("",                         341,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 341  */
+ ENTRY("",                         342,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 342  */
+ ENTRY("",                         343,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 343  */
+ ENTRY("",                         344,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 344  */
+ ENTRY("",                         345,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 345  */
+ ENTRY("",                         346,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 346  */
+ ENTRY("",                         347,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 347  */
+ ENTRY("",                         348,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 348  */
+ ENTRY("",                         349,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 349  */
+ ENTRY("audit",                    SYS_audit,                          audit,                             2, CALL_DIRECT, PTR, INT)   /* 350  */
+ ENTRY("auditon",                  SYS_auditon,                        auditon,                           3, CALL_DIRECT, INT, PTR, INT)   /* 351  */
+ ENTRY("",                         352,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 352  */
+ ENTRY("getauid",                  SYS_getauid,                        getauid,                           1, CALL_DIRECT, PTR)   /* 353  */
+ ENTRY("setauid",                  SYS_setauid,                        setauid,                           1, CALL_DIRECT, PTR)   /* 354  */
+ ENTRY("getaudit",                 SYS_getaudit,                       getaudit,                          1, CALL_DIRECT, PTR)   /* 355  */
+ ENTRY("setaudit",                 SYS_setaudit,                       setaudit,                          1, CALL_DIRECT, PTR)   /* 356  */
+ ENTRY("getaudit_addr",            SYS_getaudit_addr,                  getaudit_addr,                     2, CALL_DIRECT, PTR, INT)   /* 357  */
+ ENTRY("setaudit_addr",            SYS_setaudit_addr,                  setaudit_addr,                     2, CALL_DIRECT, PTR, INT)   /* 358  */
+ ENTRY("auditctl",                 SYS_auditctl,                       auditctl,                          1, CALL_DIRECT, PTR)   /* 359  */
+ ENTRY("",                         360,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 360  */
+ ENTRY("",                         361,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 361  */
+ ENTRY("kqueue",                   SYS_kqueue,                         kqueue,                            0, CALL_DIRECT, VOID)   /* 362  */
+ ENTRY("kevent",                   SYS_kevent,                         kevent,                            6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR)   /* 363  */
+ ENTRY("lchown",                   SYS_lchown,                         lchown,                            3, CALL_DIRECT, PTR, INT , INT)   /* 364  */
+ ENTRY("stack_snapshot",           SYS_stack_snapshot,                 unimpl_unix_syscall,               4, CALL_INDIRECT, VOID)   /* 365  */
+ ENTRY("",                         366,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 366  */
+ ENTRY("",                         367,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 367  */
+ ENTRY("",                         368,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 368  */
+ ENTRY("",                         369,                                no_syscall,                        0, CALL_INDIRECT, VOID) /* 369  */
diff --git a/qemu-0.15.x/def-helper.h b/qemu-0.15.x/def-helper.h
new file mode 100644
index 0000000..8a822c7
--- /dev/null
+++ b/qemu-0.15.x/def-helper.h
@@ -0,0 +1,240 @@
+/* Helper file for declaring TCG helper functions.
+   Should be included at the start and end of target-foo/helper.h.
+
+   Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper
+   functions.  Names should be specified without the helper_ prefix, and
+   the return and argument types specified.  3 basic types are understood
+   (i32, i64 and ptr).  Additional aliases are provided for convenience and
+   to match the types used by the C helper implementation.
+
+   The target helper.h should be included in all files that use/define
+   helper functions.  THis will ensure that function prototypes are
+   consistent.  In addition it should be included an extra two times for
+   helper.c, defining:
+    GEN_HELPER 1 to produce op generation functions (gen_helper_*)
+    GEN_HELPER 2 to do runtime registration helper functions.
+ */
+
+#ifndef DEF_HELPER_H
+#define DEF_HELPER_H 1
+
+#define HELPER(name) glue(helper_, name)
+
+#define GET_TCGV_i32 GET_TCGV_I32
+#define GET_TCGV_i64 GET_TCGV_I64
+#define GET_TCGV_ptr GET_TCGV_PTR
+
+/* Some types that make sense in C, but not for TCG.  */
+#define dh_alias_i32 i32
+#define dh_alias_s32 i32
+#define dh_alias_int i32
+#define dh_alias_i64 i64
+#define dh_alias_s64 i64
+#define dh_alias_f32 i32
+#define dh_alias_f64 i64
+#if TARGET_LONG_BITS == 32
+#define dh_alias_tl i32
+#else
+#define dh_alias_tl i64
+#endif
+#define dh_alias_ptr ptr
+#define dh_alias_void void
+#define dh_alias_env ptr
+#define dh_alias(t) glue(dh_alias_, t)
+
+#define dh_ctype_i32 uint32_t
+#define dh_ctype_s32 int32_t
+#define dh_ctype_int int
+#define dh_ctype_i64 uint64_t
+#define dh_ctype_s64 int64_t
+#define dh_ctype_f32 float32
+#define dh_ctype_f64 float64
+#define dh_ctype_tl target_ulong
+#define dh_ctype_ptr void *
+#define dh_ctype_void void
+#define dh_ctype_env CPUState *
+#define dh_ctype(t) dh_ctype_##t
+
+/* We can't use glue() here because it falls foul of C preprocessor
+   recursive expansion rules.  */
+#define dh_retvar_decl0_void void
+#define dh_retvar_decl0_i32 TCGv_i32 retval
+#define dh_retvar_decl0_i64 TCGv_i64 retval
+#define dh_retvar_decl0_ptr TCGv_ptr retval
+#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
+
+#define dh_retvar_decl_void
+#define dh_retvar_decl_i32 TCGv_i32 retval,
+#define dh_retvar_decl_i64 TCGv_i64 retval,
+#define dh_retvar_decl_ptr TCGv_ptr retval,
+#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
+
+#define dh_retvar_void TCG_CALL_DUMMY_ARG
+#define dh_retvar_i32 GET_TCGV_i32(retval)
+#define dh_retvar_i64 GET_TCGV_i64(retval)
+#define dh_retvar_ptr GET_TCGV_ptr(retval)
+#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
+
+#define dh_is_64bit_void 0
+#define dh_is_64bit_i32 0
+#define dh_is_64bit_i64 1
+#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
+#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
+
+#define dh_is_signed_void 0
+#define dh_is_signed_i32 0
+#define dh_is_signed_s32 1
+#define dh_is_signed_i64 0
+#define dh_is_signed_s64 1
+#define dh_is_signed_f32 0
+#define dh_is_signed_f64 0
+#define dh_is_signed_tl  0
+#define dh_is_signed_int 1
+/* ??? This is highly specific to the host cpu.  There are even special
+   extension instructions that may be required, e.g. ia64's addp4.  But
+   for now we don't support any 64-bit targets with 32-bit pointers.  */
+#define dh_is_signed_ptr 0
+#define dh_is_signed_env dh_is_signed_ptr
+#define dh_is_signed(t) dh_is_signed_##t
+
+#define dh_sizemask(t, n) \
+  sizemask |= dh_is_64bit(t) << (n*2); \
+  sizemask |= dh_is_signed(t) << (n*2+1)
+
+#define dh_arg(t, n) \
+  args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \
+  dh_sizemask(t, n)
+
+#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n)
+
+
+#define DEF_HELPER_0(name, ret) \
+    DEF_HELPER_FLAGS_0(name, 0, ret)
+#define DEF_HELPER_1(name, ret, t1) \
+    DEF_HELPER_FLAGS_1(name, 0, ret, t1)
+#define DEF_HELPER_2(name, ret, t1, t2) \
+    DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2)
+#define DEF_HELPER_3(name, ret, t1, t2, t3) \
+    DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3)
+#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \
+    DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4)
+
+#endif /* DEF_HELPER_H */
+
+#ifndef GEN_HELPER
+/* Function prototypes.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+dh_ctype(ret) HELPER(name) (void);
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1));
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
+                                   dh_ctype(t4));
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == 1
+/* Gen functions.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
+{ \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 0, NULL); \
+}
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \
+{ \
+  TCGArg args[1]; \
+  int sizemask = 0; \
+  dh_sizemask(ret, 0); \
+  dh_arg(t1, 1); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \
+}
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2)) \
+{ \
+  TCGArg args[2]; \
+  int sizemask = 0; \
+  dh_sizemask(ret, 0); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \
+}
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
+{ \
+  TCGArg args[3]; \
+  int sizemask = 0; \
+  dh_sizemask(ret, 0); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  dh_arg(t3, 3); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 3, args); \
+}
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
+{ \
+  TCGArg args[4]; \
+  int sizemask = 0; \
+  dh_sizemask(ret, 0); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  dh_arg(t3, 3); \
+  dh_arg(t4, 4); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \
+}
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == 2
+/* Register helpers.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+tcg_register_helper(HELPER(name), #name);
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == -1
+/* Undefine macros.  */
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+#undef GEN_HELPER
+
+#endif
diff --git a/qemu-0.15.x/default-configs/alpha-linux-user.mak b/qemu-0.15.x/default-configs/alpha-linux-user.mak
new file mode 100644
index 0000000..7956e29
--- /dev/null
+++ b/qemu-0.15.x/default-configs/alpha-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for alpha-linux-user
diff --git a/qemu-0.15.x/default-configs/alpha-softmmu.mak b/qemu-0.15.x/default-configs/alpha-softmmu.mak
new file mode 100644
index 0000000..abadcff
--- /dev/null
+++ b/qemu-0.15.x/default-configs/alpha-softmmu.mak
@@ -0,0 +1,9 @@
+# Default configuration for alpha-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_VGA_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_VMWARE_VGA=y
diff --git a/qemu-0.15.x/default-configs/arm-linux-user.mak b/qemu-0.15.x/default-configs/arm-linux-user.mak
new file mode 100644
index 0000000..46d4aa2
--- /dev/null
+++ b/qemu-0.15.x/default-configs/arm-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for arm-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/arm-softmmu.mak b/qemu-0.15.x/default-configs/arm-softmmu.mak
new file mode 100644
index 0000000..8d1174f
--- /dev/null
+++ b/qemu-0.15.x/default-configs/arm-softmmu.mak
@@ -0,0 +1,28 @@
+# Default configuration for arm-softmmu
+
+include pci.mak
+CONFIG_GDBSTUB_XML=y
+CONFIG_ISA_MMIO=y
+CONFIG_NAND=y
+CONFIG_ECC=y
+CONFIG_SERIAL=y
+CONFIG_PTIMER=y
+CONFIG_SD=y
+CONFIG_MAX7310=y
+CONFIG_WM8750=y
+CONFIG_TWL92230=y
+CONFIG_TSC2005=y
+CONFIG_LM832X=y
+CONFIG_TMP105=y
+CONFIG_STELLARIS_INPUT=y
+CONFIG_SSD0303=y
+CONFIG_SSD0323=y
+CONFIG_ADS7846=y
+CONFIG_MAX111X=y
+CONFIG_SSI=y
+CONFIG_SSI_SD=y
+CONFIG_LAN9118=y
+CONFIG_SMC91C111=y
+CONFIG_DS1338=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
diff --git a/qemu-0.15.x/default-configs/armeb-linux-user.mak b/qemu-0.15.x/default-configs/armeb-linux-user.mak
new file mode 100644
index 0000000..41d0cc4
--- /dev/null
+++ b/qemu-0.15.x/default-configs/armeb-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for armeb-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/cris-linux-user.mak b/qemu-0.15.x/default-configs/cris-linux-user.mak
new file mode 100644
index 0000000..e3aec7b
--- /dev/null
+++ b/qemu-0.15.x/default-configs/cris-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for cris-linux-user
diff --git a/qemu-0.15.x/default-configs/cris-softmmu.mak b/qemu-0.15.x/default-configs/cris-softmmu.mak
new file mode 100644
index 0000000..1a479cd
--- /dev/null
+++ b/qemu-0.15.x/default-configs/cris-softmmu.mak
@@ -0,0 +1,5 @@
+# Default configuration for cris-softmmu
+
+CONFIG_NAND=y
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI02=y
diff --git a/qemu-0.15.x/default-configs/i386-bsd-user.mak b/qemu-0.15.x/default-configs/i386-bsd-user.mak
new file mode 100644
index 0000000..af1b31a
--- /dev/null
+++ b/qemu-0.15.x/default-configs/i386-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for i386-bsd-user
diff --git a/qemu-0.15.x/default-configs/i386-darwin-user.mak b/qemu-0.15.x/default-configs/i386-darwin-user.mak
new file mode 100644
index 0000000..19afd3d
--- /dev/null
+++ b/qemu-0.15.x/default-configs/i386-darwin-user.mak
@@ -0,0 +1 @@
+# Default configuration for i386-darwin-user
diff --git a/qemu-0.15.x/default-configs/i386-linux-user.mak b/qemu-0.15.x/default-configs/i386-linux-user.mak
new file mode 100644
index 0000000..8657e68
--- /dev/null
+++ b/qemu-0.15.x/default-configs/i386-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for i386-linux-user
diff --git a/qemu-0.15.x/default-configs/i386-softmmu.mak b/qemu-0.15.x/default-configs/i386-softmmu.mak
new file mode 100644
index 0000000..55589fa
--- /dev/null
+++ b/qemu-0.15.x/default-configs/i386-softmmu.mak
@@ -0,0 +1,23 @@
+# Default configuration for i386-softmmu
+
+include pci.mak
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_VMMOUSE=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_HPET=y
+CONFIG_APPLESMC=y
diff --git a/qemu-0.15.x/default-configs/lm32-softmmu.mak b/qemu-0.15.x/default-configs/lm32-softmmu.mak
new file mode 100644
index 0000000..0d19974
--- /dev/null
+++ b/qemu-0.15.x/default-configs/lm32-softmmu.mak
@@ -0,0 +1,6 @@
+# Default configuration for lm32-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_SD=y
diff --git a/qemu-0.15.x/default-configs/m68k-linux-user.mak b/qemu-0.15.x/default-configs/m68k-linux-user.mak
new file mode 100644
index 0000000..f3487aa
--- /dev/null
+++ b/qemu-0.15.x/default-configs/m68k-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for m68k-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/m68k-softmmu.mak b/qemu-0.15.x/default-configs/m68k-softmmu.mak
new file mode 100644
index 0000000..3e2ec37
--- /dev/null
+++ b/qemu-0.15.x/default-configs/m68k-softmmu.mak
@@ -0,0 +1,5 @@
+# Default configuration for m68k-softmmu
+
+include pci.mak
+CONFIG_GDBSTUB_XML=y
+CONFIG_PTIMER=y
diff --git a/qemu-0.15.x/default-configs/microblaze-linux-user.mak b/qemu-0.15.x/default-configs/microblaze-linux-user.mak
new file mode 100644
index 0000000..566fdc0
--- /dev/null
+++ b/qemu-0.15.x/default-configs/microblaze-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for microblaze-linux-user
diff --git a/qemu-0.15.x/default-configs/microblaze-softmmu.mak b/qemu-0.15.x/default-configs/microblaze-softmmu.mak
new file mode 100644
index 0000000..613edab
--- /dev/null
+++ b/qemu-0.15.x/default-configs/microblaze-softmmu.mak
@@ -0,0 +1,5 @@
+# Default configuration for microblaze-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_SERIAL=y
diff --git a/qemu-0.15.x/default-configs/microblazeel-linux-user.mak b/qemu-0.15.x/default-configs/microblazeel-linux-user.mak
new file mode 100644
index 0000000..378c6dd
--- /dev/null
+++ b/qemu-0.15.x/default-configs/microblazeel-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for microblazeel-linux-user
diff --git a/qemu-0.15.x/default-configs/microblazeel-softmmu.mak b/qemu-0.15.x/default-configs/microblazeel-softmmu.mak
new file mode 100644
index 0000000..4b40fb2
--- /dev/null
+++ b/qemu-0.15.x/default-configs/microblazeel-softmmu.mak
@@ -0,0 +1,5 @@
+# Default configuration for microblazeel-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_SERIAL=y
diff --git a/qemu-0.15.x/default-configs/mips-linux-user.mak b/qemu-0.15.x/default-configs/mips-linux-user.mak
new file mode 100644
index 0000000..31df570
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mips-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips-linux-user
diff --git a/qemu-0.15.x/default-configs/mips-softmmu.mak b/qemu-0.15.x/default-configs/mips-softmmu.mak
new file mode 100644
index 0000000..f524971
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mips-softmmu.mak
@@ -0,0 +1,28 @@
+# Default configuration for mips-softmmu
+
+include pci.mak
+CONFIG_ISA_MMIO=y
+CONFIG_ESP=y
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VGA_ISA_MM=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_PIIX4=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_RC4030=y
+CONFIG_DP8393X=y
+CONFIG_DS1225Y=y
+CONFIG_MIPSNET=y
+CONFIG_PFLASH_CFI01=y
diff --git a/qemu-0.15.x/default-configs/mips64-softmmu.mak b/qemu-0.15.x/default-configs/mips64-softmmu.mak
new file mode 100644
index 0000000..aeab6b2
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mips64-softmmu.mak
@@ -0,0 +1,28 @@
+# Default configuration for mips64-softmmu
+
+include pci.mak
+CONFIG_ISA_MMIO=y
+CONFIG_ESP=y
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VGA_ISA_MM=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_PIIX4=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_RC4030=y
+CONFIG_DP8393X=y
+CONFIG_DS1225Y=y
+CONFIG_MIPSNET=y
+CONFIG_PFLASH_CFI01=y
diff --git a/qemu-0.15.x/default-configs/mips64el-softmmu.mak b/qemu-0.15.x/default-configs/mips64el-softmmu.mak
new file mode 100644
index 0000000..8e6511c
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mips64el-softmmu.mak
@@ -0,0 +1,30 @@
+# Default configuration for mips64el-softmmu
+
+include pci.mak
+CONFIG_ISA_MMIO=y
+CONFIG_ESP=y
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VGA_ISA_MM=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_PIIX4=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_IDE_VIA=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_RC4030=y
+CONFIG_DP8393X=y
+CONFIG_DS1225Y=y
+CONFIG_MIPSNET=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_FULONG=y
diff --git a/qemu-0.15.x/default-configs/mipsel-linux-user.mak b/qemu-0.15.x/default-configs/mipsel-linux-user.mak
new file mode 100644
index 0000000..4d0e4af
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mipsel-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsel-linux-user
diff --git a/qemu-0.15.x/default-configs/mipsel-softmmu.mak b/qemu-0.15.x/default-configs/mipsel-softmmu.mak
new file mode 100644
index 0000000..a05ac25
--- /dev/null
+++ b/qemu-0.15.x/default-configs/mipsel-softmmu.mak
@@ -0,0 +1,28 @@
+# Default configuration for mipsel-softmmu
+
+include pci.mak
+CONFIG_ISA_MMIO=y
+CONFIG_ESP=y
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VGA_ISA_MM=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_PIIX4=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_RC4030=y
+CONFIG_DP8393X=y
+CONFIG_DS1225Y=y
+CONFIG_MIPSNET=y
+CONFIG_PFLASH_CFI01=y
diff --git a/qemu-0.15.x/default-configs/pci.mak b/qemu-0.15.x/default-configs/pci.mak
new file mode 100644
index 0000000..22bd350
--- /dev/null
+++ b/qemu-0.15.x/default-configs/pci.mak
@@ -0,0 +1,17 @@
+CONFIG_PCI=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
+CONFIG_NE2000_PCI=y
+CONFIG_EEPRO100_PCI=y
+CONFIG_PCNET_PCI=y
+CONFIG_PCNET_COMMON=y
+CONFIG_LSI_SCSI_PCI=y
+CONFIG_RTL8139_PCI=y
+CONFIG_E1000_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
+CONFIG_AHCI=y
diff --git a/qemu-0.15.x/default-configs/ppc-darwin-user.mak b/qemu-0.15.x/default-configs/ppc-darwin-user.mak
new file mode 100644
index 0000000..153ed12
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc-darwin-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for ppc-darwin-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/ppc-linux-user.mak b/qemu-0.15.x/default-configs/ppc-linux-user.mak
new file mode 100644
index 0000000..681a945
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for ppc-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/ppc-softmmu.mak b/qemu-0.15.x/default-configs/ppc-softmmu.mak
new file mode 100644
index 0000000..4563742
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc-softmmu.mak
@@ -0,0 +1,33 @@
+# Default configuration for ppc-softmmu
+
+include pci.mak
+CONFIG_GDBSTUB_XML=y
+CONFIG_ISA_MMIO=y
+CONFIG_ESCC=y
+CONFIG_M48T59=y
+CONFIG_VGA_PCI=y
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_DMA=y
+CONFIG_OPENPIC=y
+CONFIG_PREP_PCI=y
+CONFIG_MACIO=y
+CONFIG_CUDA=y
+CONFIG_ADB=y
+CONFIG_MAC_NVRAM=y
+CONFIG_MAC_DBDMA=y
+CONFIG_HEATHROW_PIC=y
+CONFIG_GRACKLE_PCI=y
+CONFIG_UNIN_PCI=y
+CONFIG_DEC_PCI=y
+CONFIG_PPCE500_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_CMD646=y
+CONFIG_IDE_MACIO=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_PTIMER=y
diff --git a/qemu-0.15.x/default-configs/ppc64-linux-user.mak b/qemu-0.15.x/default-configs/ppc64-linux-user.mak
new file mode 100644
index 0000000..089c08f
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc64-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for ppc64-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/ppc64-softmmu.mak b/qemu-0.15.x/default-configs/ppc64-softmmu.mak
new file mode 100644
index 0000000..d5073b3
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc64-softmmu.mak
@@ -0,0 +1,33 @@
+# Default configuration for ppc64-softmmu
+
+include pci.mak
+CONFIG_GDBSTUB_XML=y
+CONFIG_ISA_MMIO=y
+CONFIG_ESCC=y
+CONFIG_M48T59=y
+CONFIG_VGA_PCI=y
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_DMA=y
+CONFIG_OPENPIC=y
+CONFIG_PREP_PCI=y
+CONFIG_MACIO=y
+CONFIG_CUDA=y
+CONFIG_ADB=y
+CONFIG_MAC_NVRAM=y
+CONFIG_MAC_DBDMA=y
+CONFIG_HEATHROW_PIC=y
+CONFIG_GRACKLE_PCI=y
+CONFIG_UNIN_PCI=y
+CONFIG_DEC_PCI=y
+CONFIG_PPCE500_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_CMD646=y
+CONFIG_IDE_MACIO=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_PTIMER=y
diff --git a/qemu-0.15.x/default-configs/ppc64abi32-linux-user.mak b/qemu-0.15.x/default-configs/ppc64abi32-linux-user.mak
new file mode 100644
index 0000000..f038ffd
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppc64abi32-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for ppc64abi32-linux-user
+
+CONFIG_GDBSTUB_XML=y
diff --git a/qemu-0.15.x/default-configs/ppcemb-softmmu.mak b/qemu-0.15.x/default-configs/ppcemb-softmmu.mak
new file mode 100644
index 0000000..9f0730c
--- /dev/null
+++ b/qemu-0.15.x/default-configs/ppcemb-softmmu.mak
@@ -0,0 +1,33 @@
+# Default configuration for ppcemb-softmmu
+
+include pci.mak
+CONFIG_GDBSTUB_XML=y
+CONFIG_ISA_MMIO=y
+CONFIG_ESCC=y
+CONFIG_M48T59=y
+CONFIG_VGA_PCI=y
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_DMA=y
+CONFIG_OPENPIC=y
+CONFIG_PREP_PCI=y
+CONFIG_MACIO=y
+CONFIG_CUDA=y
+CONFIG_ADB=y
+CONFIG_MAC_NVRAM=y
+CONFIG_MAC_DBDMA=y
+CONFIG_HEATHROW_PIC=y
+CONFIG_GRACKLE_PCI=y
+CONFIG_UNIN_PCI=y
+CONFIG_DEC_PCI=y
+CONFIG_PPCE500_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_CMD646=y
+CONFIG_IDE_MACIO=y
+CONFIG_NE2000_ISA=y
+CONFIG_SOUND=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_PTIMER=y
diff --git a/qemu-0.15.x/default-configs/s390x-linux-user.mak b/qemu-0.15.x/default-configs/s390x-linux-user.mak
new file mode 100644
index 0000000..a243c99
--- /dev/null
+++ b/qemu-0.15.x/default-configs/s390x-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for s390x-linux-user
diff --git a/qemu-0.15.x/default-configs/s390x-softmmu.mak b/qemu-0.15.x/default-configs/s390x-softmmu.mak
new file mode 100644
index 0000000..3005729
--- /dev/null
+++ b/qemu-0.15.x/default-configs/s390x-softmmu.mak
@@ -0,0 +1 @@
+CONFIG_VIRTIO=y
diff --git a/qemu-0.15.x/default-configs/sh4-linux-user.mak b/qemu-0.15.x/default-configs/sh4-linux-user.mak
new file mode 100644
index 0000000..a469e19
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sh4-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for sh4-linux-user
diff --git a/qemu-0.15.x/default-configs/sh4-softmmu.mak b/qemu-0.15.x/default-configs/sh4-softmmu.mak
new file mode 100644
index 0000000..5c69acc
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sh4-softmmu.mak
@@ -0,0 +1,7 @@
+# Default configuration for sh4-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_ISA_MMIO=y
diff --git a/qemu-0.15.x/default-configs/sh4eb-linux-user.mak b/qemu-0.15.x/default-configs/sh4eb-linux-user.mak
new file mode 100644
index 0000000..be08ca1
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sh4eb-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for sh4eb-linux-user
diff --git a/qemu-0.15.x/default-configs/sh4eb-softmmu.mak b/qemu-0.15.x/default-configs/sh4eb-softmmu.mak
new file mode 100644
index 0000000..7cdc122
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sh4eb-softmmu.mak
@@ -0,0 +1,7 @@
+# Default configuration for sh4eb-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI02=y
+CONFIG_ISA_MMIO=y
diff --git a/qemu-0.15.x/default-configs/sparc-bsd-user.mak b/qemu-0.15.x/default-configs/sparc-bsd-user.mak
new file mode 100644
index 0000000..21e0950
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for sparc-bsd-user
diff --git a/qemu-0.15.x/default-configs/sparc-linux-user.mak b/qemu-0.15.x/default-configs/sparc-linux-user.mak
new file mode 100644
index 0000000..9c716d1
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for sparc-linux-user
diff --git a/qemu-0.15.x/default-configs/sparc-softmmu.mak b/qemu-0.15.x/default-configs/sparc-softmmu.mak
new file mode 100644
index 0000000..b0310c5
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc-softmmu.mak
@@ -0,0 +1,10 @@
+# Default configuration for sparc-softmmu
+
+CONFIG_ECC=y
+CONFIG_ESP=y
+CONFIG_ESCC=y
+CONFIG_M48T59=y
+CONFIG_PTIMER=y
+CONFIG_FDC=y
+CONFIG_EMPTY_SLOT=y
+CONFIG_PCNET_COMMON=y
diff --git a/qemu-0.15.x/default-configs/sparc32plus-linux-user.mak b/qemu-0.15.x/default-configs/sparc32plus-linux-user.mak
new file mode 100644
index 0000000..432e880
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc32plus-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for sparc32plus-linux-user
diff --git a/qemu-0.15.x/default-configs/sparc64-bsd-user.mak b/qemu-0.15.x/default-configs/sparc64-bsd-user.mak
new file mode 100644
index 0000000..b8b9eea
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc64-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for sparc64-bsd-user
diff --git a/qemu-0.15.x/default-configs/sparc64-linux-user.mak b/qemu-0.15.x/default-configs/sparc64-linux-user.mak
new file mode 100644
index 0000000..bf1bdd6
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc64-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for sparc64-linux-user
diff --git a/qemu-0.15.x/default-configs/sparc64-softmmu.mak b/qemu-0.15.x/default-configs/sparc64-softmmu.mak
new file mode 100644
index 0000000..d8f17e7
--- /dev/null
+++ b/qemu-0.15.x/default-configs/sparc64-softmmu.mak
@@ -0,0 +1,13 @@
+# Default configuration for sparc64-softmmu
+
+include pci.mak
+CONFIG_ISA_MMIO=y
+CONFIG_M48T59=y
+CONFIG_PTIMER=y
+CONFIG_VGA_PCI=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_CMD646=y
diff --git a/qemu-0.15.x/default-configs/unicore32-linux-user.mak b/qemu-0.15.x/default-configs/unicore32-linux-user.mak
new file mode 100644
index 0000000..6aafd21
--- /dev/null
+++ b/qemu-0.15.x/default-configs/unicore32-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for unicore32-linux-user
diff --git a/qemu-0.15.x/default-configs/x86_64-bsd-user.mak b/qemu-0.15.x/default-configs/x86_64-bsd-user.mak
new file mode 100644
index 0000000..73e5d34
--- /dev/null
+++ b/qemu-0.15.x/default-configs/x86_64-bsd-user.mak
@@ -0,0 +1 @@
+# Default configuration for x86_64-bsd-user
diff --git a/qemu-0.15.x/default-configs/x86_64-linux-user.mak b/qemu-0.15.x/default-configs/x86_64-linux-user.mak
new file mode 100644
index 0000000..bec1d9e
--- /dev/null
+++ b/qemu-0.15.x/default-configs/x86_64-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for x86_64-linux-user
diff --git a/qemu-0.15.x/default-configs/x86_64-softmmu.mak b/qemu-0.15.x/default-configs/x86_64-softmmu.mak
new file mode 100644
index 0000000..8895028
--- /dev/null
+++ b/qemu-0.15.x/default-configs/x86_64-softmmu.mak
@@ -0,0 +1,23 @@
+# Default configuration for x86_64-softmmu
+
+include pci.mak
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_VMMOUSE=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_HPET=y
+CONFIG_APPLESMC=y
diff --git a/qemu-0.15.x/device_tree.c b/qemu-0.15.x/device_tree.c
new file mode 100644
index 0000000..f5d5eb1
--- /dev/null
+++ b/qemu-0.15.x/device_tree.c
@@ -0,0 +1,109 @@
+/*
+ * Functions to help device tree manipulation using libfdt.
+ * It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5 at us.ibm.com>
+ *          Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "qemu-common.h"
+#include "device_tree.h"
+#include "hw/loader.h"
+
+#include <libfdt.h>
+
+void *load_device_tree(const char *filename_path, int *sizep)
+{
+    int dt_size;
+    int dt_file_load_size;
+    int ret;
+    void *fdt = NULL;
+
+    *sizep = 0;
+    dt_size = get_image_size(filename_path);
+    if (dt_size < 0) {
+        printf("Unable to get size of device tree file '%s'\n",
+            filename_path);
+        goto fail;
+    }
+
+    /* Expand to 2x size to give enough room for manipulation.  */
+    dt_size *= 2;
+    /* First allocate space in qemu for device tree */
+    fdt = qemu_mallocz(dt_size);
+
+    dt_file_load_size = load_image(filename_path, fdt);
+    if (dt_file_load_size < 0) {
+        printf("Unable to open device tree file '%s'\n",
+               filename_path);
+        goto fail;
+    }
+
+    ret = fdt_open_into(fdt, fdt, dt_size);
+    if (ret) {
+        printf("Unable to copy device tree in memory\n");
+        goto fail;
+    }
+
+    /* Check sanity of device tree */
+    if (fdt_check_header(fdt)) {
+        printf ("Device tree file loaded into memory is invalid: %s\n",
+            filename_path);
+        goto fail;
+    }
+    *sizep = dt_size;
+    return fdt;
+
+fail:
+    qemu_free(fdt);
+    return NULL;
+}
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, void *val_array, int size)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop(fdt, offset, property, val_array, size);
+}
+
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+                              const char *property, uint32_t val)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop_cell(fdt, offset, property, val);
+}
+
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+                                const char *property, const char *string)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop_string(fdt, offset, property, string);
+}
diff --git a/qemu-0.15.x/device_tree.h b/qemu-0.15.x/device_tree.h
new file mode 100644
index 0000000..cecd98f
--- /dev/null
+++ b/qemu-0.15.x/device_tree.h
@@ -0,0 +1,26 @@
+/*
+ * Header with function prototypes to help device tree manipulation using
+ * libfdt. It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5 at us.ibm.com>
+ *          Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef __DEVICE_TREE_H__
+#define __DEVICE_TREE_H__
+
+void *load_device_tree(const char *filename_path, int *sizep);
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, void *val_array, int size);
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+                              const char *property, uint32_t val);
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+                                const char *property, const char *string);
+
+#endif /* __DEVICE_TREE_H__ */
diff --git a/qemu-0.15.x/dis-asm.h b/qemu-0.15.x/dis-asm.h
new file mode 100644
index 0000000..5b07d7f
--- /dev/null
+++ b/qemu-0.15.x/dis-asm.h
@@ -0,0 +1,479 @@
+/* Interface between the opcode library and its callers.
+   Written by Cygnus Support, 1993.
+
+   The opcode library (libopcodes.a) provides instruction decoders for
+   a large variety of instruction sets, callable with an identical
+   interface, for making instruction-processing programs more independent
+   of the instruction set being processed.  */
+
+#ifndef DIS_ASM_H
+#define DIS_ASM_H
+
+#include "qemu-common.h"
+
+typedef void *PTR;
+typedef uint64_t bfd_vma;
+typedef int64_t bfd_signed_vma;
+typedef uint8_t bfd_byte;
+#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
+#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x)
+
+#define BFD64
+
+enum bfd_flavour {
+  bfd_target_unknown_flavour,
+  bfd_target_aout_flavour,
+  bfd_target_coff_flavour,
+  bfd_target_ecoff_flavour,
+  bfd_target_elf_flavour,
+  bfd_target_ieee_flavour,
+  bfd_target_nlm_flavour,
+  bfd_target_oasys_flavour,
+  bfd_target_tekhex_flavour,
+  bfd_target_srec_flavour,
+  bfd_target_ihex_flavour,
+  bfd_target_som_flavour,
+  bfd_target_os9k_flavour,
+  bfd_target_versados_flavour,
+  bfd_target_msdos_flavour,
+  bfd_target_evax_flavour
+};
+
+enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
+
+enum bfd_architecture
+{
+  bfd_arch_unknown,    /* File arch not known */
+  bfd_arch_obscure,    /* Arch known, not one of these */
+  bfd_arch_m68k,       /* Motorola 68xxx */
+#define bfd_mach_m68000 1
+#define bfd_mach_m68008 2
+#define bfd_mach_m68010 3
+#define bfd_mach_m68020 4
+#define bfd_mach_m68030 5
+#define bfd_mach_m68040 6
+#define bfd_mach_m68060 7
+#define bfd_mach_cpu32  8
+#define bfd_mach_mcf5200  9
+#define bfd_mach_mcf5206e 10
+#define bfd_mach_mcf5307  11
+#define bfd_mach_mcf5407  12
+#define bfd_mach_mcf528x  13
+#define bfd_mach_mcfv4e   14
+#define bfd_mach_mcf521x   15
+#define bfd_mach_mcf5249   16
+#define bfd_mach_mcf547x   17
+#define bfd_mach_mcf548x   18
+  bfd_arch_vax,        /* DEC Vax */
+  bfd_arch_i960,       /* Intel 960 */
+     /* The order of the following is important.
+       lower number indicates a machine type that
+       only accepts a subset of the instructions
+       available to machines with higher numbers.
+       The exception is the "ca", which is
+       incompatible with all other machines except
+       "core". */
+
+#define bfd_mach_i960_core      1
+#define bfd_mach_i960_ka_sa     2
+#define bfd_mach_i960_kb_sb     3
+#define bfd_mach_i960_mc        4
+#define bfd_mach_i960_xa        5
+#define bfd_mach_i960_ca        6
+#define bfd_mach_i960_jx        7
+#define bfd_mach_i960_hx        8
+
+  bfd_arch_a29k,       /* AMD 29000 */
+  bfd_arch_sparc,      /* SPARC */
+#define bfd_mach_sparc                 1
+/* The difference between v8plus and v9 is that v9 is a true 64 bit env.  */
+#define bfd_mach_sparc_sparclet        2
+#define bfd_mach_sparc_sparclite       3
+#define bfd_mach_sparc_v8plus          4
+#define bfd_mach_sparc_v8plusa         5 /* with ultrasparc add'ns.  */
+#define bfd_mach_sparc_sparclite_le    6
+#define bfd_mach_sparc_v9              7
+#define bfd_mach_sparc_v9a             8 /* with ultrasparc add'ns.  */
+#define bfd_mach_sparc_v8plusb         9 /* with cheetah add'ns.  */
+#define bfd_mach_sparc_v9b             10 /* with cheetah add'ns.  */
+/* Nonzero if MACH has the v9 instruction set.  */
+#define bfd_mach_sparc_v9_p(mach) \
+  ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
+   && (mach) != bfd_mach_sparc_sparclite_le)
+  bfd_arch_mips,       /* MIPS Rxxxx */
+#define bfd_mach_mips3000              3000
+#define bfd_mach_mips3900              3900
+#define bfd_mach_mips4000              4000
+#define bfd_mach_mips4010              4010
+#define bfd_mach_mips4100              4100
+#define bfd_mach_mips4300              4300
+#define bfd_mach_mips4400              4400
+#define bfd_mach_mips4600              4600
+#define bfd_mach_mips4650              4650
+#define bfd_mach_mips5000              5000
+#define bfd_mach_mips6000              6000
+#define bfd_mach_mips8000              8000
+#define bfd_mach_mips10000             10000
+#define bfd_mach_mips16                16
+  bfd_arch_i386,       /* Intel 386 */
+#define bfd_mach_i386_i386 0
+#define bfd_mach_i386_i8086 1
+#define bfd_mach_i386_i386_intel_syntax 2
+#define bfd_mach_x86_64 3
+#define bfd_mach_x86_64_intel_syntax 4
+  bfd_arch_we32k,      /* AT&T WE32xxx */
+  bfd_arch_tahoe,      /* CCI/Harris Tahoe */
+  bfd_arch_i860,       /* Intel 860 */
+  bfd_arch_romp,       /* IBM ROMP PC/RT */
+  bfd_arch_alliant,    /* Alliant */
+  bfd_arch_convex,     /* Convex */
+  bfd_arch_m88k,       /* Motorola 88xxx */
+  bfd_arch_pyramid,    /* Pyramid Technology */
+  bfd_arch_h8300,      /* Hitachi H8/300 */
+#define bfd_mach_h8300   1
+#define bfd_mach_h8300h  2
+#define bfd_mach_h8300s  3
+  bfd_arch_powerpc,    /* PowerPC */
+#define bfd_mach_ppc           0
+#define bfd_mach_ppc64         1
+#define bfd_mach_ppc_403       403
+#define bfd_mach_ppc_403gc     4030
+#define bfd_mach_ppc_e500      500
+#define bfd_mach_ppc_505       505
+#define bfd_mach_ppc_601       601
+#define bfd_mach_ppc_602       602
+#define bfd_mach_ppc_603       603
+#define bfd_mach_ppc_ec603e    6031
+#define bfd_mach_ppc_604       604
+#define bfd_mach_ppc_620       620
+#define bfd_mach_ppc_630       630
+#define bfd_mach_ppc_750       750
+#define bfd_mach_ppc_860       860
+#define bfd_mach_ppc_a35       35
+#define bfd_mach_ppc_rs64ii    642
+#define bfd_mach_ppc_rs64iii   643
+#define bfd_mach_ppc_7400      7400
+  bfd_arch_rs6000,     /* IBM RS/6000 */
+  bfd_arch_hppa,       /* HP PA RISC */
+#define bfd_mach_hppa10        10
+#define bfd_mach_hppa11        11
+#define bfd_mach_hppa20        20
+#define bfd_mach_hppa20w       25
+  bfd_arch_d10v,       /* Mitsubishi D10V */
+  bfd_arch_z8k,        /* Zilog Z8000 */
+#define bfd_mach_z8001         1
+#define bfd_mach_z8002         2
+  bfd_arch_h8500,      /* Hitachi H8/500 */
+  bfd_arch_sh,         /* Hitachi SH */
+#define bfd_mach_sh            1
+#define bfd_mach_sh2        0x20
+#define bfd_mach_sh_dsp     0x2d
+#define bfd_mach_sh2a       0x2a
+#define bfd_mach_sh2a_nofpu 0x2b
+#define bfd_mach_sh2e       0x2e
+#define bfd_mach_sh3        0x30
+#define bfd_mach_sh3_nommu  0x31
+#define bfd_mach_sh3_dsp    0x3d
+#define bfd_mach_sh3e       0x3e
+#define bfd_mach_sh4        0x40
+#define bfd_mach_sh4_nofpu  0x41
+#define bfd_mach_sh4_nommu_nofpu  0x42
+#define bfd_mach_sh4a       0x4a
+#define bfd_mach_sh4a_nofpu 0x4b
+#define bfd_mach_sh4al_dsp  0x4d
+#define bfd_mach_sh5        0x50
+  bfd_arch_alpha,      /* Dec Alpha */
+#define bfd_mach_alpha 1
+#define bfd_mach_alpha_ev4  0x10
+#define bfd_mach_alpha_ev5  0x20
+#define bfd_mach_alpha_ev6  0x30
+  bfd_arch_arm,        /* Advanced Risc Machines ARM */
+#define bfd_mach_arm_unknown	0
+#define bfd_mach_arm_2		1
+#define bfd_mach_arm_2a		2
+#define bfd_mach_arm_3		3
+#define bfd_mach_arm_3M 	4
+#define bfd_mach_arm_4 		5
+#define bfd_mach_arm_4T 	6
+#define bfd_mach_arm_5 		7
+#define bfd_mach_arm_5T		8
+#define bfd_mach_arm_5TE	9
+#define bfd_mach_arm_XScale	10
+#define bfd_mach_arm_ep9312	11
+#define bfd_mach_arm_iWMMXt	12
+#define bfd_mach_arm_iWMMXt2	13
+  bfd_arch_ns32k,      /* National Semiconductors ns32000 */
+  bfd_arch_w65,        /* WDC 65816 */
+  bfd_arch_tic30,      /* Texas Instruments TMS320C30 */
+  bfd_arch_v850,       /* NEC V850 */
+#define bfd_mach_v850          0
+  bfd_arch_arc,        /* Argonaut RISC Core */
+#define bfd_mach_arc_base 0
+  bfd_arch_m32r,       /* Mitsubishi M32R/D */
+#define bfd_mach_m32r          0  /* backwards compatibility */
+  bfd_arch_mn10200,    /* Matsushita MN10200 */
+  bfd_arch_mn10300,    /* Matsushita MN10300 */
+  bfd_arch_cris,       /* Axis CRIS */
+#define bfd_mach_cris_v0_v10   255
+#define bfd_mach_cris_v32      32
+#define bfd_mach_cris_v10_v32  1032
+  bfd_arch_microblaze, /* Xilinx MicroBlaze.  */
+  bfd_arch_ia64,      /* HP/Intel ia64 */
+#define bfd_mach_ia64_elf64    64
+#define bfd_mach_ia64_elf32    32
+  bfd_arch_last
+  };
+#define bfd_mach_s390_31 31
+#define bfd_mach_s390_64 64
+
+typedef struct symbol_cache_entry
+{
+    const char *name;
+    union
+    {
+        PTR p;
+        bfd_vma i;
+    } udata;
+} asymbol;
+
+enum dis_insn_type {
+  dis_noninsn,			/* Not a valid instruction */
+  dis_nonbranch,		/* Not a branch instruction */
+  dis_branch,			/* Unconditional branch */
+  dis_condbranch,		/* Conditional branch */
+  dis_jsr,			/* Jump to subroutine */
+  dis_condjsr,			/* Conditional jump to subroutine */
+  dis_dref,			/* Data reference instruction */
+  dis_dref2			/* Two data references in instruction */
+};
+
+/* This struct is passed into the instruction decoding routine,
+   and is passed back out into each callback.  The various fields are used
+   for conveying information from your main routine into your callbacks,
+   for passing information into the instruction decoders (such as the
+   addresses of the callback functions), or for passing information
+   back from the instruction decoders to their callers.
+
+   It must be initialized before it is first passed; this can be done
+   by hand, or using one of the initialization macros below.  */
+
+typedef struct disassemble_info {
+  fprintf_function fprintf_func;
+  FILE *stream;
+  PTR application_data;
+
+  /* Target description.  We could replace this with a pointer to the bfd,
+     but that would require one.  There currently isn't any such requirement
+     so to avoid introducing one we record these explicitly.  */
+  /* The bfd_flavour.  This can be bfd_target_unknown_flavour.  */
+  enum bfd_flavour flavour;
+  /* The bfd_arch value.  */
+  enum bfd_architecture arch;
+  /* The bfd_mach value.  */
+  unsigned long mach;
+  /* Endianness (for bi-endian cpus).  Mono-endian cpus can ignore this.  */
+  enum bfd_endian endian;
+
+  /* An array of pointers to symbols either at the location being disassembled
+     or at the start of the function being disassembled.  The array is sorted
+     so that the first symbol is intended to be the one used.  The others are
+     present for any misc. purposes.  This is not set reliably, but if it is
+     not NULL, it is correct.  */
+  asymbol **symbols;
+  /* Number of symbols in array.  */
+  int num_symbols;
+
+  /* For use by the disassembler.
+     The top 16 bits are reserved for public use (and are documented here).
+     The bottom 16 bits are for the internal use of the disassembler.  */
+  unsigned long flags;
+#define INSN_HAS_RELOC	0x80000000
+  PTR private_data;
+
+  /* Function used to get bytes to disassemble.  MEMADDR is the
+     address of the stuff to be disassembled, MYADDR is the address to
+     put the bytes in, and LENGTH is the number of bytes to read.
+     INFO is a pointer to this struct.
+     Returns an errno value or 0 for success.  */
+  int (*read_memory_func)
+    (bfd_vma memaddr, bfd_byte *myaddr, int length,
+	     struct disassemble_info *info);
+
+  /* Function which should be called if we get an error that we can't
+     recover from.  STATUS is the errno value from read_memory_func and
+     MEMADDR is the address that we were trying to read.  INFO is a
+     pointer to this struct.  */
+  void (*memory_error_func)
+    (int status, bfd_vma memaddr, struct disassemble_info *info);
+
+  /* Function called to print ADDR.  */
+  void (*print_address_func)
+    (bfd_vma addr, struct disassemble_info *info);
+
+  /* Function called to determine if there is a symbol at the given ADDR.
+     If there is, the function returns 1, otherwise it returns 0.
+     This is used by ports which support an overlay manager where
+     the overlay number is held in the top part of an address.  In
+     some circumstances we want to include the overlay number in the
+     address, (normally because there is a symbol associated with
+     that address), but sometimes we want to mask out the overlay bits.  */
+  int (* symbol_at_address_func)
+    (bfd_vma addr, struct disassemble_info * info);
+
+  /* These are for buffer_read_memory.  */
+  bfd_byte *buffer;
+  bfd_vma buffer_vma;
+  int buffer_length;
+
+  /* This variable may be set by the instruction decoder.  It suggests
+      the number of bytes objdump should display on a single line.  If
+      the instruction decoder sets this, it should always set it to
+      the same value in order to get reasonable looking output.  */
+  int bytes_per_line;
+
+  /* the next two variables control the way objdump displays the raw data */
+  /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
+  /* output will look like this:
+     00:   00000000 00000000
+     with the chunks displayed according to "display_endian". */
+  int bytes_per_chunk;
+  enum bfd_endian display_endian;
+
+  /* Results from instruction decoders.  Not all decoders yet support
+     this information.  This info is set each time an instruction is
+     decoded, and is only valid for the last such instruction.
+
+     To determine whether this decoder supports this information, set
+     insn_info_valid to 0, decode an instruction, then check it.  */
+
+  char insn_info_valid;		/* Branch info has been set. */
+  char branch_delay_insns;	/* How many sequential insn's will run before
+				   a branch takes effect.  (0 = normal) */
+  char data_size;		/* Size of data reference in insn, in bytes */
+  enum dis_insn_type insn_type;	/* Type of instruction */
+  bfd_vma target;		/* Target address of branch or dref, if known;
+				   zero if unknown.  */
+  bfd_vma target2;		/* Second target address for dref2 */
+
+  /* Command line options specific to the target disassembler.  */
+  char * disassembler_options;
+
+} disassemble_info;
+
+
+/* Standard disassemblers.  Disassemble one instruction at the given
+   target address.  Return number of bytes processed.  */
+typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
+
+int print_insn_big_mips         (bfd_vma, disassemble_info*);
+int print_insn_little_mips      (bfd_vma, disassemble_info*);
+int print_insn_i386             (bfd_vma, disassemble_info*);
+int print_insn_m68k             (bfd_vma, disassemble_info*);
+int print_insn_z8001            (bfd_vma, disassemble_info*);
+int print_insn_z8002            (bfd_vma, disassemble_info*);
+int print_insn_h8300            (bfd_vma, disassemble_info*);
+int print_insn_h8300h           (bfd_vma, disassemble_info*);
+int print_insn_h8300s           (bfd_vma, disassemble_info*);
+int print_insn_h8500            (bfd_vma, disassemble_info*);
+int print_insn_alpha            (bfd_vma, disassemble_info*);
+disassembler_ftype arc_get_disassembler (int, int);
+int print_insn_arm              (bfd_vma, disassemble_info*);
+int print_insn_sparc            (bfd_vma, disassemble_info*);
+int print_insn_big_a29k         (bfd_vma, disassemble_info*);
+int print_insn_little_a29k      (bfd_vma, disassemble_info*);
+int print_insn_i960             (bfd_vma, disassemble_info*);
+int print_insn_sh               (bfd_vma, disassemble_info*);
+int print_insn_shl              (bfd_vma, disassemble_info*);
+int print_insn_hppa             (bfd_vma, disassemble_info*);
+int print_insn_m32r             (bfd_vma, disassemble_info*);
+int print_insn_m88k             (bfd_vma, disassemble_info*);
+int print_insn_mn10200          (bfd_vma, disassemble_info*);
+int print_insn_mn10300          (bfd_vma, disassemble_info*);
+int print_insn_ns32k            (bfd_vma, disassemble_info*);
+int print_insn_big_powerpc      (bfd_vma, disassemble_info*);
+int print_insn_little_powerpc   (bfd_vma, disassemble_info*);
+int print_insn_rs6000           (bfd_vma, disassemble_info*);
+int print_insn_w65              (bfd_vma, disassemble_info*);
+int print_insn_d10v             (bfd_vma, disassemble_info*);
+int print_insn_v850             (bfd_vma, disassemble_info*);
+int print_insn_tic30            (bfd_vma, disassemble_info*);
+int print_insn_ppc              (bfd_vma, disassemble_info*);
+int print_insn_s390             (bfd_vma, disassemble_info*);
+int print_insn_crisv32          (bfd_vma, disassemble_info*);
+int print_insn_crisv10          (bfd_vma, disassemble_info*);
+int print_insn_microblaze       (bfd_vma, disassemble_info*);
+int print_insn_ia64             (bfd_vma, disassemble_info*);
+
+#if 0
+/* Fetch the disassembler for a given BFD, if that support is available.  */
+disassembler_ftype disassembler(bfd *);
+#endif
+
+
+/* This block of definitions is for particular callers who read instructions
+   into a buffer before calling the instruction decoder.  */
+
+/* Here is a function which callers may wish to use for read_memory_func.
+   It gets bytes from a buffer.  */
+int buffer_read_memory(bfd_vma, bfd_byte *, int, struct disassemble_info *);
+
+/* This function goes with buffer_read_memory.
+   It prints a message using info->fprintf_func and info->stream.  */
+void perror_memory(int, bfd_vma, struct disassemble_info *);
+
+
+/* Just print the address in hex.  This is included for completeness even
+   though both GDB and objdump provide their own (to print symbolic
+   addresses).  */
+void generic_print_address(bfd_vma, struct disassemble_info *);
+
+/* Always true.  */
+int generic_symbol_at_address(bfd_vma, struct disassemble_info *);
+
+/* Macro to initialize a disassemble_info struct.  This should be called
+   by all applications creating such a struct.  */
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
+  (INFO).flavour = bfd_target_unknown_flavour, \
+  (INFO).arch = bfd_arch_unknown, \
+  (INFO).mach = 0, \
+  (INFO).endian = BFD_ENDIAN_UNKNOWN, \
+  INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
+
+/* Call this macro to initialize only the internal variables for the
+   disassembler.  Architecture dependent things such as byte order, or machine
+   variant are not touched by this macro.  This makes things much easier for
+   GDB which must initialize these things separately.  */
+
+#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
+  (INFO).fprintf_func = (FPRINTF_FUNC), \
+  (INFO).stream = (STREAM), \
+  (INFO).symbols = NULL, \
+  (INFO).num_symbols = 0, \
+  (INFO).private_data = NULL, \
+  (INFO).buffer = NULL, \
+  (INFO).buffer_vma = 0, \
+  (INFO).buffer_length = 0, \
+  (INFO).read_memory_func = buffer_read_memory, \
+  (INFO).memory_error_func = perror_memory, \
+  (INFO).print_address_func = generic_print_address, \
+  (INFO).symbol_at_address_func = generic_symbol_at_address, \
+  (INFO).flags = 0, \
+  (INFO).bytes_per_line = 0, \
+  (INFO).bytes_per_chunk = 0, \
+  (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
+  (INFO).disassembler_options = NULL, \
+  (INFO).insn_info_valid = 0
+
+#define _(x) x
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+
+/* from libbfd */
+
+bfd_vma bfd_getl64 (const bfd_byte *addr);
+bfd_vma bfd_getl32 (const bfd_byte *addr);
+bfd_vma bfd_getb32 (const bfd_byte *addr);
+bfd_vma bfd_getl16 (const bfd_byte *addr);
+bfd_vma bfd_getb16 (const bfd_byte *addr);
+typedef bool bfd_boolean;
+
+#endif /* ! defined (DIS_ASM_H) */
diff --git a/qemu-0.15.x/disas.c b/qemu-0.15.x/disas.c
new file mode 100644
index 0000000..1334b8e
--- /dev/null
+++ b/qemu-0.15.x/disas.c
@@ -0,0 +1,437 @@
+/* General "disassemble this chunk" code.  Used for debugging. */
+#include "config.h"
+#include "dis-asm.h"
+#include "elf.h"
+#include <errno.h>
+
+#include "cpu.h"
+#include "disas.h"
+
+/* Filled in by elfload.c.  Simplistic, but will do for now. */
+struct syminfo *syminfos = NULL;
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+   Transfer them to myaddr.  */
+int
+buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
+                   struct disassemble_info *info)
+{
+    if (memaddr < info->buffer_vma
+        || memaddr + length > info->buffer_vma + info->buffer_length)
+        /* Out of bounds.  Use EIO because GDB uses it.  */
+        return EIO;
+    memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
+    return 0;
+}
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+   Transfer them to myaddr.  */
+static int
+target_read_memory (bfd_vma memaddr,
+                    bfd_byte *myaddr,
+                    int length,
+                    struct disassemble_info *info)
+{
+    cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0);
+    return 0;
+}
+
+/* Print an error message.  We can assume that this is in response to
+   an error return from buffer_read_memory.  */
+void
+perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
+{
+  if (status != EIO)
+    /* Can't happen.  */
+    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
+  else
+    /* Actually, address between memaddr and memaddr + len was
+       out of bounds.  */
+    (*info->fprintf_func) (info->stream,
+			   "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
+}
+
+/* This could be in a separate file, to save miniscule amounts of space
+   in statically linked executables.  */
+
+/* Just print the address is hex.  This is included for completeness even
+   though both GDB and objdump provide their own (to print symbolic
+   addresses).  */
+
+void
+generic_print_address (bfd_vma addr, struct disassemble_info *info)
+{
+    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
+}
+
+/* Just return the given address.  */
+
+int
+generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
+{
+  return 1;
+}
+
+bfd_vma bfd_getl64 (const bfd_byte *addr)
+{
+  unsigned long long v;
+
+  v = (unsigned long long) addr[0];
+  v |= (unsigned long long) addr[1] << 8;
+  v |= (unsigned long long) addr[2] << 16;
+  v |= (unsigned long long) addr[3] << 24;
+  v |= (unsigned long long) addr[4] << 32;
+  v |= (unsigned long long) addr[5] << 40;
+  v |= (unsigned long long) addr[6] << 48;
+  v |= (unsigned long long) addr[7] << 56;
+  return (bfd_vma) v;
+}
+
+bfd_vma bfd_getl32 (const bfd_byte *addr)
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0];
+  v |= (unsigned long) addr[1] << 8;
+  v |= (unsigned long) addr[2] << 16;
+  v |= (unsigned long) addr[3] << 24;
+  return (bfd_vma) v;
+}
+
+bfd_vma bfd_getb32 (const bfd_byte *addr)
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0] << 24;
+  v |= (unsigned long) addr[1] << 16;
+  v |= (unsigned long) addr[2] << 8;
+  v |= (unsigned long) addr[3];
+  return (bfd_vma) v;
+}
+
+bfd_vma bfd_getl16 (const bfd_byte *addr)
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0];
+  v |= (unsigned long) addr[1] << 8;
+  return (bfd_vma) v;
+}
+
+bfd_vma bfd_getb16 (const bfd_byte *addr)
+{
+  unsigned long v;
+
+  v = (unsigned long) addr[0] << 24;
+  v |= (unsigned long) addr[1] << 16;
+  return (bfd_vma) v;
+}
+
+#ifdef TARGET_ARM
+static int
+print_insn_thumb1(bfd_vma pc, disassemble_info *info)
+{
+  return print_insn_arm(pc | 1, info);
+}
+#endif
+
+/* Disassemble this for me please... (debugging). 'flags' has the following
+   values:
+    i386 - nonzero means 16 bit code
+    arm  - nonzero means thumb code
+    ppc  - nonzero means little endian
+    other targets - unused
+ */
+void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
+{
+    target_ulong pc;
+    int count;
+    struct disassemble_info disasm_info;
+    int (*print_insn)(bfd_vma pc, disassemble_info *info);
+
+    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
+
+    disasm_info.read_memory_func = target_read_memory;
+    disasm_info.buffer_vma = code;
+    disasm_info.buffer_length = size;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    disasm_info.endian = BFD_ENDIAN_BIG;
+#else
+    disasm_info.endian = BFD_ENDIAN_LITTLE;
+#endif
+#if defined(TARGET_I386)
+    if (flags == 2)
+        disasm_info.mach = bfd_mach_x86_64;
+    else if (flags == 1)
+        disasm_info.mach = bfd_mach_i386_i8086;
+    else
+        disasm_info.mach = bfd_mach_i386_i386;
+    print_insn = print_insn_i386;
+#elif defined(TARGET_ARM)
+    if (flags)
+	print_insn = print_insn_thumb1;
+    else
+	print_insn = print_insn_arm;
+#elif defined(TARGET_SPARC)
+    print_insn = print_insn_sparc;
+#ifdef TARGET_SPARC64
+    disasm_info.mach = bfd_mach_sparc_v9b;
+#endif
+#elif defined(TARGET_PPC)
+    if (flags >> 16)
+        disasm_info.endian = BFD_ENDIAN_LITTLE;
+    if (flags & 0xFFFF) {
+        /* If we have a precise definitions of the instructions set, use it */
+        disasm_info.mach = flags & 0xFFFF;
+    } else {
+#ifdef TARGET_PPC64
+        disasm_info.mach = bfd_mach_ppc64;
+#else
+        disasm_info.mach = bfd_mach_ppc;
+#endif
+    }
+    print_insn = print_insn_ppc;
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
+#elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
+    print_insn = print_insn_big_mips;
+#else
+    print_insn = print_insn_little_mips;
+#endif
+#elif defined(TARGET_SH4)
+    disasm_info.mach = bfd_mach_sh4;
+    print_insn = print_insn_sh;
+#elif defined(TARGET_ALPHA)
+    disasm_info.mach = bfd_mach_alpha_ev6;
+    print_insn = print_insn_alpha;
+#elif defined(TARGET_CRIS)
+    if (flags != 32) {
+        disasm_info.mach = bfd_mach_cris_v0_v10;
+        print_insn = print_insn_crisv10;
+    } else {
+        disasm_info.mach = bfd_mach_cris_v32;
+        print_insn = print_insn_crisv32;
+    }
+#elif defined(TARGET_S390X)
+    disasm_info.mach = bfd_mach_s390_64;
+    print_insn = print_insn_s390;
+#elif defined(TARGET_MICROBLAZE)
+    disasm_info.mach = bfd_arch_microblaze;
+    print_insn = print_insn_microblaze;
+#else
+    fprintf(out, "0x" TARGET_FMT_lx
+	    ": Asm output not supported on this arch\n", code);
+    return;
+#endif
+
+    for (pc = code; size > 0; pc += count, size -= count) {
+	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
+	count = print_insn(pc, &disasm_info);
+#if 0
+        {
+            int i;
+            uint8_t b;
+            fprintf(out, " {");
+            for(i = 0; i < count; i++) {
+                target_read_memory(pc + i, &b, 1, &disasm_info);
+                fprintf(out, " %02x", b);
+            }
+            fprintf(out, " }");
+        }
+#endif
+	fprintf(out, "\n");
+	if (count < 0)
+	    break;
+        if (size < count) {
+            fprintf(out,
+                    "Disassembler disagrees with translator over instruction "
+                    "decoding\n"
+                    "Please report this to qemu-devel at nongnu.org\n");
+            break;
+        }
+    }
+}
+
+/* Disassemble this for me please... (debugging). */
+void disas(FILE *out, void *code, unsigned long size)
+{
+    unsigned long pc;
+    int count;
+    struct disassemble_info disasm_info;
+    int (*print_insn)(bfd_vma pc, disassemble_info *info);
+
+    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
+
+    disasm_info.buffer = code;
+    disasm_info.buffer_vma = (unsigned long)code;
+    disasm_info.buffer_length = size;
+
+#ifdef HOST_WORDS_BIGENDIAN
+    disasm_info.endian = BFD_ENDIAN_BIG;
+#else
+    disasm_info.endian = BFD_ENDIAN_LITTLE;
+#endif
+#if defined(__i386__)
+    disasm_info.mach = bfd_mach_i386_i386;
+    print_insn = print_insn_i386;
+#elif defined(__x86_64__)
+    disasm_info.mach = bfd_mach_x86_64;
+    print_insn = print_insn_i386;
+#elif defined(_ARCH_PPC)
+    print_insn = print_insn_ppc;
+#elif defined(__alpha__)
+    print_insn = print_insn_alpha;
+#elif defined(__sparc__)
+    print_insn = print_insn_sparc;
+#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
+    disasm_info.mach = bfd_mach_sparc_v9b;
+#endif
+#elif defined(__arm__)
+    print_insn = print_insn_arm;
+#elif defined(__MIPSEB__)
+    print_insn = print_insn_big_mips;
+#elif defined(__MIPSEL__)
+    print_insn = print_insn_little_mips;
+#elif defined(__m68k__)
+    print_insn = print_insn_m68k;
+#elif defined(__s390__)
+    print_insn = print_insn_s390;
+#elif defined(__hppa__)
+    print_insn = print_insn_hppa;
+#elif defined(__ia64__)
+    print_insn = print_insn_ia64;
+#else
+    fprintf(out, "0x%lx: Asm output not supported on this arch\n",
+	    (long) code);
+    return;
+#endif
+    for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
+	fprintf(out, "0x%08lx:  ", pc);
+	count = print_insn(pc, &disasm_info);
+	fprintf(out, "\n");
+	if (count < 0)
+	    break;
+    }
+}
+
+/* Look up symbol for debugging purpose.  Returns "" if unknown. */
+const char *lookup_symbol(target_ulong orig_addr)
+{
+    const char *symbol = "";
+    struct syminfo *s;
+
+    for (s = syminfos; s; s = s->next) {
+        symbol = s->lookup_symbol(s, orig_addr);
+        if (symbol[0] != '\0') {
+            break;
+        }
+    }
+
+    return symbol;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#include "monitor.h"
+
+static int monitor_disas_is_physical;
+static CPUState *monitor_disas_env;
+
+static int
+monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
+                     struct disassemble_info *info)
+{
+    if (monitor_disas_is_physical) {
+        cpu_physical_memory_read(memaddr, myaddr, length);
+    } else {
+        cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
+    }
+    return 0;
+}
+
+static int GCC_FMT_ATTR(2, 3)
+monitor_fprintf(FILE *stream, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    monitor_vprintf((Monitor *)stream, fmt, ap);
+    va_end(ap);
+    return 0;
+}
+
+void monitor_disas(Monitor *mon, CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags)
+{
+    int count, i;
+    struct disassemble_info disasm_info;
+    int (*print_insn)(bfd_vma pc, disassemble_info *info);
+
+    INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
+
+    monitor_disas_env = env;
+    monitor_disas_is_physical = is_physical;
+    disasm_info.read_memory_func = monitor_read_memory;
+
+    disasm_info.buffer_vma = pc;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    disasm_info.endian = BFD_ENDIAN_BIG;
+#else
+    disasm_info.endian = BFD_ENDIAN_LITTLE;
+#endif
+#if defined(TARGET_I386)
+    if (flags == 2)
+        disasm_info.mach = bfd_mach_x86_64;
+    else if (flags == 1)
+        disasm_info.mach = bfd_mach_i386_i8086;
+    else
+        disasm_info.mach = bfd_mach_i386_i386;
+    print_insn = print_insn_i386;
+#elif defined(TARGET_ARM)
+    print_insn = print_insn_arm;
+#elif defined(TARGET_ALPHA)
+    print_insn = print_insn_alpha;
+#elif defined(TARGET_SPARC)
+    print_insn = print_insn_sparc;
+#ifdef TARGET_SPARC64
+    disasm_info.mach = bfd_mach_sparc_v9b;
+#endif
+#elif defined(TARGET_PPC)
+#ifdef TARGET_PPC64
+    disasm_info.mach = bfd_mach_ppc64;
+#else
+    disasm_info.mach = bfd_mach_ppc;
+#endif
+    print_insn = print_insn_ppc;
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
+#elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
+    print_insn = print_insn_big_mips;
+#else
+    print_insn = print_insn_little_mips;
+#endif
+#elif defined(TARGET_SH4)
+    disasm_info.mach = bfd_mach_sh4;
+    print_insn = print_insn_sh;
+#elif defined(TARGET_S390X)
+    disasm_info.mach = bfd_mach_s390_64;
+    print_insn = print_insn_s390;
+#else
+    monitor_printf(mon, "0x" TARGET_FMT_lx
+                   ": Asm output not supported on this arch\n", pc);
+    return;
+#endif
+
+    for(i = 0; i < nb_insn; i++) {
+	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
+	count = print_insn(pc, &disasm_info);
+	monitor_printf(mon, "\n");
+	if (count < 0)
+	    break;
+        pc += count;
+    }
+}
+#endif
diff --git a/qemu-0.15.x/disas.h b/qemu-0.15.x/disas.h
new file mode 100644
index 0000000..f9287f7
--- /dev/null
+++ b/qemu-0.15.x/disas.h
@@ -0,0 +1,42 @@
+#ifndef _QEMU_DISAS_H
+#define _QEMU_DISAS_H
+
+#include "qemu-common.h"
+
+#ifdef NEED_CPU_H
+/* Disassemble this for me please... (debugging). */
+void disas(FILE *out, void *code, unsigned long size);
+void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
+
+void monitor_disas(Monitor *mon, CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags);
+
+/* Look up symbol for debugging purpose.  Returns "" if unknown. */
+const char *lookup_symbol(target_ulong orig_addr);
+#endif
+
+struct syminfo;
+struct elf32_sym;
+struct elf64_sym;
+
+#if defined(CONFIG_USER_ONLY)
+typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong orig_addr);
+#else
+typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_phys_addr_t orig_addr);
+#endif
+
+struct syminfo {
+    lookup_symbol_t lookup_symbol;
+    unsigned int disas_num_syms;
+    union {
+      struct elf32_sym *elf32;
+      struct elf64_sym *elf64;
+    } disas_symtab;
+    const char *disas_strtab;
+    struct syminfo *next;
+};
+
+/* Filled in by elfload.c.  Simplistic, but will do for now. */
+extern struct syminfo *syminfos;
+
+#endif /* _QEMU_DISAS_H */
diff --git a/qemu-0.15.x/dma-helpers.c b/qemu-0.15.x/dma-helpers.c
new file mode 100644
index 0000000..ba7f897
--- /dev/null
+++ b/qemu-0.15.x/dma-helpers.c
@@ -0,0 +1,181 @@
+/*
+ * DMA helper functions
+ *
+ * Copyright (c) 2009 Red Hat
+ *
+ * This work is licensed under the terms of the GNU General Public License
+ * (GNU GPL), version 2 or later.
+ */
+
+#include "dma.h"
+#include "block_int.h"
+
+void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
+{
+    qsg->sg = qemu_malloc(alloc_hint * sizeof(ScatterGatherEntry));
+    qsg->nsg = 0;
+    qsg->nalloc = alloc_hint;
+    qsg->size = 0;
+}
+
+void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
+                     target_phys_addr_t len)
+{
+    if (qsg->nsg == qsg->nalloc) {
+        qsg->nalloc = 2 * qsg->nalloc + 1;
+        qsg->sg = qemu_realloc(qsg->sg, qsg->nalloc * sizeof(ScatterGatherEntry));
+    }
+    qsg->sg[qsg->nsg].base = base;
+    qsg->sg[qsg->nsg].len = len;
+    qsg->size += len;
+    ++qsg->nsg;
+}
+
+void qemu_sglist_destroy(QEMUSGList *qsg)
+{
+    qemu_free(qsg->sg);
+}
+
+typedef struct {
+    BlockDriverAIOCB common;
+    BlockDriverState *bs;
+    BlockDriverAIOCB *acb;
+    QEMUSGList *sg;
+    uint64_t sector_num;
+    int is_write;
+    int sg_cur_index;
+    target_phys_addr_t sg_cur_byte;
+    QEMUIOVector iov;
+    QEMUBH *bh;
+    DMAIOFunc *io_func;
+} DMAAIOCB;
+
+static void dma_bdrv_cb(void *opaque, int ret);
+
+static void reschedule_dma(void *opaque)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+
+    qemu_bh_delete(dbs->bh);
+    dbs->bh = NULL;
+    dma_bdrv_cb(opaque, 0);
+}
+
+static void continue_after_map_failure(void *opaque)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+
+    dbs->bh = qemu_bh_new(reschedule_dma, dbs);
+    qemu_bh_schedule(dbs->bh);
+}
+
+static void dma_bdrv_unmap(DMAAIOCB *dbs)
+{
+    int i;
+
+    for (i = 0; i < dbs->iov.niov; ++i) {
+        cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
+                                  dbs->iov.iov[i].iov_len, !dbs->is_write,
+                                  dbs->iov.iov[i].iov_len);
+    }
+}
+
+static void dma_bdrv_cb(void *opaque, int ret)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+    target_phys_addr_t cur_addr, cur_len;
+    void *mem;
+
+    dbs->acb = NULL;
+    dbs->sector_num += dbs->iov.size / 512;
+    dma_bdrv_unmap(dbs);
+    qemu_iovec_reset(&dbs->iov);
+
+    if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
+        dbs->common.cb(dbs->common.opaque, ret);
+        qemu_iovec_destroy(&dbs->iov);
+        qemu_aio_release(dbs);
+        return;
+    }
+
+    while (dbs->sg_cur_index < dbs->sg->nsg) {
+        cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
+        cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
+        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
+        if (!mem)
+            break;
+        qemu_iovec_add(&dbs->iov, mem, cur_len);
+        dbs->sg_cur_byte += cur_len;
+        if (dbs->sg_cur_byte == dbs->sg->sg[dbs->sg_cur_index].len) {
+            dbs->sg_cur_byte = 0;
+            ++dbs->sg_cur_index;
+        }
+    }
+
+    if (dbs->iov.size == 0) {
+        cpu_register_map_client(dbs, continue_after_map_failure);
+        return;
+    }
+
+    dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
+                            dbs->iov.size / 512, dma_bdrv_cb, dbs);
+    if (!dbs->acb) {
+        dma_bdrv_unmap(dbs);
+        qemu_iovec_destroy(&dbs->iov);
+        return;
+    }
+}
+
+static void dma_aio_cancel(BlockDriverAIOCB *acb)
+{
+    DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
+
+    if (dbs->acb) {
+        bdrv_aio_cancel(dbs->acb);
+    }
+}
+
+static AIOPool dma_aio_pool = {
+    .aiocb_size         = sizeof(DMAAIOCB),
+    .cancel             = dma_aio_cancel,
+};
+
+BlockDriverAIOCB *dma_bdrv_io(
+    BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
+    DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+    void *opaque, int is_write)
+{
+    DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
+
+    dbs->acb = NULL;
+    dbs->bs = bs;
+    dbs->sg = sg;
+    dbs->sector_num = sector_num;
+    dbs->sg_cur_index = 0;
+    dbs->sg_cur_byte = 0;
+    dbs->is_write = is_write;
+    dbs->io_func = io_func;
+    dbs->bh = NULL;
+    qemu_iovec_init(&dbs->iov, sg->nsg);
+    dma_bdrv_cb(dbs, 0);
+    if (!dbs->acb) {
+        qemu_aio_release(dbs);
+        return NULL;
+    }
+    return &dbs->common;
+}
+
+
+BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
+                                QEMUSGList *sg, uint64_t sector,
+                                void (*cb)(void *opaque, int ret), void *opaque)
+{
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0);
+}
+
+BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
+                                 QEMUSGList *sg, uint64_t sector,
+                                 void (*cb)(void *opaque, int ret), void *opaque)
+{
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1);
+}
diff --git a/qemu-0.15.x/dma.h b/qemu-0.15.x/dma.h
new file mode 100644
index 0000000..3d8324b
--- /dev/null
+++ b/qemu-0.15.x/dma.h
@@ -0,0 +1,49 @@
+/*
+ * DMA helper functions
+ *
+ * Copyright (c) 2009 Red Hat
+ *
+ * This work is licensed under the terms of the GNU General Public License
+ * (GNU GPL), version 2 or later.
+ */
+
+#ifndef DMA_H
+#define DMA_H
+
+#include <stdio.h>
+//#include "cpu.h"
+#include "hw/hw.h"
+#include "block.h"
+
+typedef struct {
+    target_phys_addr_t base;
+    target_phys_addr_t len;
+} ScatterGatherEntry;
+
+typedef struct {
+    ScatterGatherEntry *sg;
+    int nsg;
+    int nalloc;
+    target_phys_addr_t size;
+} QEMUSGList;
+
+void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
+void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
+                     target_phys_addr_t len);
+void qemu_sglist_destroy(QEMUSGList *qsg);
+
+typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *iov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+
+BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
+                              QEMUSGList *sg, uint64_t sector_num,
+                              DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+                              void *opaque, int is_write);
+BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
+                                QEMUSGList *sg, uint64_t sector,
+                                BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
+                                 QEMUSGList *sg, uint64_t sector,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+#endif
diff --git a/qemu-0.15.x/docs/blkverify.txt b/qemu-0.15.x/docs/blkverify.txt
new file mode 100644
index 0000000..d556dc4
--- /dev/null
+++ b/qemu-0.15.x/docs/blkverify.txt
@@ -0,0 +1,69 @@
+= Block driver correctness testing with blkverify =
+
+== Introduction ==
+
+This document describes how to use the blkverify protocol to test that a block
+driver is operating correctly.
+
+It is difficult to test and debug block drivers against real guests.  Often
+processes inside the guest will crash because corrupt sectors were read as part
+of the executable.  Other times obscure errors are raised by a program inside
+the guest.  These issues are extremely hard to trace back to bugs in the block
+driver.
+
+Blkverify solves this problem by catching data corruption inside QEMU the first
+time bad data is read and reporting the disk sector that is corrupted.
+
+== How it works ==
+
+The blkverify protocol has two child block devices, the "test" device and the
+"raw" device.  Read/write operations are mirrored to both devices so their
+state should always be in sync.
+
+The "raw" device is a raw image, a flat file, that has identical starting
+contents to the "test" image.  The idea is that the "raw" device will handle
+read/write operations correctly and not corrupt data.  It can be used as a
+reference for comparison against the "test" device.
+
+After a mirrored read operation completes, blkverify will compare the data and
+raise an error if it is not identical.  This makes it possible to catch the
+first instance where corrupt data is read.
+
+== Example ==
+
+Imagine raw.img has 0xcd repeated throughout its first sector:
+
+    $ ./qemu-io -c 'read -v 0 512' raw.img
+    00000000:  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
+    00000010:  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
+    [...]
+    000001e0:  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
+    000001f0:  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
+    read 512/512 bytes at offset 0
+    512.000000 bytes, 1 ops; 0.0000 sec (97.656 MiB/sec and 200000.0000 ops/sec)
+
+And test.img is corrupt, its first sector is zeroed when it shouldn't be:
+
+    $ ./qemu-io -c 'read -v 0 512' test.img
+    00000000:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    00000010:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    [...]
+    000001e0:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    000001f0:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    read 512/512 bytes at offset 0
+    512.000000 bytes, 1 ops; 0.0000 sec (81.380 MiB/sec and 166666.6667 ops/sec)
+
+This error is caught by blkverify:
+
+    $ ./qemu-io -c 'read 0 512' blkverify:a.img:b.img
+    blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0
+
+A more realistic scenario is verifying the installation of a guest OS:
+
+    $ ./qemu-img create raw.img 16G
+    $ ./qemu-img create -f qcow2 test.qcow2 16G
+    $ x86_64-softmmu/qemu-system-x86_64 -cdrom debian.iso \
+                                        -drive file=blkverify:raw.img:test.qcow2
+
+If the installation is aborted when blkverify detects corruption, use qemu-io
+to explore the contents of the disk image at the sector in question.
diff --git a/qemu-0.15.x/docs/bootindex.txt b/qemu-0.15.x/docs/bootindex.txt
new file mode 100644
index 0000000..16083b3
--- /dev/null
+++ b/qemu-0.15.x/docs/bootindex.txt
@@ -0,0 +1,43 @@
+= Bootindex propery =
+
+Block and net devices have bootindex property. This property is used to
+determine the order in which firmware will consider devices for booting
+the guest OS. If the bootindex property is not set for a device, it gets
+lowest boot priority. There is no particular order in which devices with
+unset bootindex property will be considered for booting, but they will
+still be bootable.
+
+== Example ==
+
+Lets assume we have QEMU machine with two NICs (virtio, e1000) and two
+disks (IDE, virtio):
+
+qemu -drive file=disk1.img,if=none,id=disk1
+     -device ide-drive,drive=disk1,bootindex=4
+     -drive file=disk2.img,if=none,id=disk2
+     -device virtio-blk-pci,drive=disk2,bootindex=3
+     -netdev type=user,id=net0 -device virtio-net-pci,netdev=net0,bootindex=2
+     -netdev type=user,id=net1 -device e1000,netdev=net1,bootindex=1
+
+Given the command above, firmware should try to boot from the e1000 NIC
+first.  If this fails, it should try the virtio NIC next, if this fails
+too, it should try the virtio disk, and then the IDE disk.
+
+== Limitations ==
+
+1. Some firmware has limitations on which devices can be considered for
+booting.  For instance, the PC BIOS boot specification allows only one
+disk to be bootable.  If boot from disk fails for some reason, the BIOS
+won't retry booting from other disk.  It still can try to boot from
+floppy or net, though.
+
+2. Sometimes, firmware cannot map the device path QEMU wants firmware to
+boot from to a boot method.  It doesn't happen for devices the firmware
+can natively boot from, but if firmware relies on an option ROM for
+booting, and the same option ROM is used for booting from more then one
+device, the firmware may not be able to ask the option ROM to boot from
+a particular device reliably.  For instance with PC BIOS, if a SCSI HBA
+has three bootable devices target1, target3, target5 connected to it,
+the option ROM will have a boot method for each of them, but it is not
+possible to map from boot method back to a specific target.  This is a
+shortcoming of PC BIOS boot specification.
diff --git a/qemu-0.15.x/docs/ccid.txt b/qemu-0.15.x/docs/ccid.txt
new file mode 100644
index 0000000..b8e504a
--- /dev/null
+++ b/qemu-0.15.x/docs/ccid.txt
@@ -0,0 +1,135 @@
+Qemu CCID Device Documentation.
+
+Contents
+1. USB CCID device
+2. Building
+3. Using ccid-card-emulated with hardware
+4. Using ccid-card-emulated with certificates
+5. Using ccid-card-passthru with client side hardware
+6. Using ccid-card-passthru with client side certificates
+7. Passthrough protocol scenario
+8. libcacard
+
+1. USB CCID device
+
+The USB CCID device is a USB device implementing the CCID specification, which
+lets one connect smart card readers that implement the same spec. For more
+information see the specification:
+
+ Universal Serial Bus
+ Device Class: Smart Card
+ CCID
+ Specification for
+ Integrated Circuit(s) Cards Interface Devices
+ Revision 1.1
+ April 22rd, 2005
+
+Smartcard are used for authentication, single sign on, decryption in
+public/private schemes and digital signatures. A smartcard reader on the client
+cannot be used on a guest with simple usb passthrough since it will then not be
+available on the client, possibly locking the computer when it is "removed". On
+the other hand this device can let you use the smartcard on both the client and
+the guest machine. It is also possible to have a completely virtual smart card
+reader and smart card (i.e. not backed by a physical device) using this device.
+
+2. Building
+
+The cryptographic functions and access to the physical card is done via NSS.
+
+Installing NSS:
+
+In redhat/fedora:
+    yum install nss-devel
+In ubuntu/debian:
+    apt-get install libnss3-dev
+    (not tested on ubuntu)
+
+Configuring and building:
+    ./configure --enable-smartcard && make
+
+3. Using ccid-card-emulated with hardware
+
+Assuming you have a working smartcard on the host with the current
+user, using NSS, qemu acts as another NSS client using ccid-card-emulated:
+
+    qemu -usb -device usb-ccid -device ccid-card-emualated
+
+4. Using ccid-card-emulated with certificates
+
+You must create the certificates. This is a one time process. We use NSS
+certificates:
+
+    certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1
+
+Note: you must have exactly three certificates.
+
+Assuming the current user can access the certificates (use certutil -L to
+verify), you can use the emulated card type with the certificates backend:
+
+    qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3
+
+5. Using ccid-card-passthru with client side hardware
+
+on the host specify the ccid-card-passthru device with a suitable chardev:
+
+    qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid
+
+on the client run vscclient, built when you built the libcacard library:
+    libcacard/vscclient <qemu-host> 2001
+
+6. Using ccid-card-passthru with client side certificates
+
+Run qemu as per #5, and run vscclient as follows:
+(Note: vscclient command line interface is in a state of change)
+
+    libcacard/vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" <qemu-host> 2001
+
+7. Passthrough protocol scenario
+
+This is a typical interchange of messages when using the passthru card device.
+usb-ccid is a usb device. It defaults to an unattached usb device on startup.
+usb-ccid expects a chardev and expects the protocol defined in
+cac_card/vscard_common.h to be passed over that.
+The usb-ccid device can be in one of three modes:
+ * detached
+ * attached with no card
+ * attached with card
+
+A typical interchange is: (the arrow shows who started each exchange, it can be client
+originated or guest originated)
+
+client event      |      vscclient           |    passthru    |     usb-ccid  |  guest event
+----------------------------------------------------------------------------------------------
+                  |      VSC_Init            |                |               |
+                  |      VSC_ReaderAdd       |                |     attach    |
+                  |                          |                |               |  sees new usb device.
+card inserted ->  |                          |                |               |
+                  |      VSC_ATR             |   insert       |     insert    |  see new card
+                  |                          |                |               |
+                  |      VSC_APDU            |   VSC_APDU     |               | <- guest sends APDU
+client<->physical |                          |                |               |
+card APDU exchange|                          |                |               |
+client response ->|      VSC_APDU            |   VSC_APDU     |               |  receive APDU response
+                                                    ...
+                                    [APDU<->APDU repeats several times]
+                                                    ...
+card removed  ->  |                          |                |               |
+                  |      VSC_CardRemove      |   remove       |    remove     |   card removed
+                                                    ...
+                                    [(card insert, apdu's, card remove) repeat]
+                                                    ...
+kill/quit         |                          |                |               |
+  vscclient       |                          |                |               |
+                  |      VSC_ReaderRemove    |                |    detach     |
+                  |                          |                |               |   usb device removed.
+
+
+8. libcacard
+
+ccid-card-passthru and vscclient use libcacard as the card emulator.
+libcacard implements a completely virtual CAC (DoD standard for smart cards)
+compliant card and uses NSS to actually retrive certificates and do any
+encryption using the backend (real reader + card or file backed certificates).
+
+For documentation of cac_card see README in libcacard subdirectory.
+
diff --git a/qemu-0.15.x/docs/ich9-ehci-uhci.cfg b/qemu-0.15.x/docs/ich9-ehci-uhci.cfg
new file mode 100644
index 0000000..a0e9b96
--- /dev/null
+++ b/qemu-0.15.x/docs/ich9-ehci-uhci.cfg
@@ -0,0 +1,37 @@
+###########################################################################
+#
+# You can pass this file directly to qemu using the -readconfig
+# command line switch.
+#
+# This config file creates a EHCI adapter with companion UHCI
+# controllers as multifunction device in PCI slot "1d".
+#
+# Specify "bus=ehci.0" when creating usb devices to hook them up
+# there.
+#
+
+[device "ehci"]
+  driver = "ich9-usb-ehci1"
+  addr = "1d.7"
+  multifunction = "on"
+
+[device "uhci-1"]
+  driver = "ich9-usb-uhci1"
+  addr = "1d.0"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "0"
+
+[device "uhci-2"]
+  driver = "ich9-usb-uhci2"
+  addr = "1d.1"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "2"
+
+[device "uhci-3"]
+  driver = "ich9-usb-uhci3"
+  addr = "1d.2"
+  multifunction = "on"
+  masterbus = "ehci.0"
+  firstport = "4"
diff --git a/qemu-0.15.x/docs/libcacard.txt b/qemu-0.15.x/docs/libcacard.txt
new file mode 100644
index 0000000..5dee6fa
--- /dev/null
+++ b/qemu-0.15.x/docs/libcacard.txt
@@ -0,0 +1,483 @@
+This file documents the CAC (Common Access Card) library in the libcacard
+subdirectory.
+
+Virtual Smart Card Emulator
+
+This emulator is designed to provide emulation of actual smart cards to a
+virtual card reader running in a guest virtual machine. The emulated smart
+cards can be representations of real smart cards, where the necessary functions
+such as signing, card removal/insertion, etc. are mapped to real, physical
+cards which are shared with the client machine the emulator is running on, or
+the cards could be pure software constructs.
+
+The emulator is structured to allow multiple replacable or additional pieces,
+so it can be easily modified for future requirements. The primary envisioned
+modifications are:
+
+1) The socket connection to the virtual card reader (presumably a CCID reader,
+but other ISO-7816 compatible readers could be used). The code that handles
+this is in vscclient.c.
+
+2) The virtual card low level emulation. This is currently supplied by using
+NSS. This emulation could be replaced by implementations based on other
+security libraries, including but not limitted to openssl+pkcs#11 library,
+raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles
+this is in vcard_emul_nss.c.
+
+3) Emulation for new types of cards. The current implementation emulates the
+original DoD CAC standard with separate pki containers. This emulator lives in
+cac.c. More than one card type emulator could be included. Other cards could
+be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc.
+
+--------------------
+Replacing the Socket Based Virtual Reader Interface.
+
+The current implementation contains a replacable module vscclient.c. The
+current vscclient.c implements a sockets interface to the virtual ccid reader
+on the guest. CCID commands that are pertinent to emulation are passed
+across the socket, and their responses are passed back along that same socket.
+The protocol that vscclient uses is defined in vscard_common.h and connects
+to a qemu ccid usb device. Since this socket runs as a client, vscclient.c
+implements a program with a main entry. It also handles argument parsing for
+the emulator.
+
+An application that wants to use the virtual reader can replace vscclient.c
+with it's own implementation that connects to it's own CCID reader.  The calls
+that the CCID reader can call are:
+
+      VReaderList * vreader_get_reader_list();
+
+  This function returns a list of virtual readers.  These readers may map to
+  physical devices, or simulated devices depending on vcard the back end. Each
+  reader in the list should represent a reader to the virtual machine. Virtual
+  USB address mapping is left to the CCID reader front end. This call can be
+  made any time to get an updated list. The returned list is a copy of the
+  internal list that can be referenced by the caller without locking. This copy
+  must be freed by the caller with vreader_list_delete when it is no longer
+  needed.
+
+      VReaderListEntry *vreader_list_get_first(VReaderList *);
+
+  This function gets the first entry on the reader list. Along with
+  vreader_list_get_next(), vreader_list_get_first() can be used to walk the
+  reader list returned from vreader_get_reader_list(). VReaderListEntries are
+  part of the list themselves and do not need to be freed separately from the
+  list. If there are no entries on the list, it will return NULL.
+
+      VReaderListEntry *vreader_list_get_next(VReaderListEntry *);
+
+  This function gets the next entry in the list. If there are no more entries
+  it will return NULL.
+
+      VReader * vreader_list_get_reader(VReaderListEntry *)
+
+  This function returns the reader stored in the reader List entry. Caller gets
+  a new reference to a reader. The caller must free it's reference when it is
+  finished with vreader_free().
+
+      void vreader_free(VReader *reader);
+
+   This function frees a reference to a reader. Reader's are reference counted
+   and are automatically deleted when the last reference is freed.
+
+      void vreader_list_delete(VReaderList *list);
+
+   This function frees the list, all the elements on the list, and all the
+   reader references held by the list.
+
+      VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len);
+
+  This functions simulates a card power on. Virtual cards do not care about
+  the actual voltage and other physical parameters, but it does care that the
+  card is actually on or off. Cycling the card causes the card to reset. If
+  the caller provides enough space, vreader_power_on will return the ATR of
+  the virtual card. The amount of space provided in atr should be indicated
+  in *len. The function modifies *len to be the actual length of of the
+  returned ATR.
+
+      VReaderStatus vreader_power_off(VReader *reader);
+
+  This function simulates a power off of a virtual card.
+
+      VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf,
+                                       int send_buf_len,
+                                       unsigned char *receive_buf,
+                                       int receive_buf_len);
+
+  This functions send a raw apdu to a card and returns the card's response.
+  The CCID front end should return the response back. Most of the emulation
+  is driven from these APDUs.
+
+      VReaderStatus vreader_card_is_present(VReader *reader);
+
+  This function returns whether or not the reader has a card inserted. The
+  vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return
+  VREADER_NO_CARD.
+
+       const char *vreader_get_name(VReader *reader);
+
+  This function returns the name of the reader. The name comes from the card
+  emulator level and is usually related to the name of the physical reader.
+
+       VReaderID vreader_get_id(VReader *reader);
+
+  This function returns the id of a reader. All readers start out with an id
+  of -1. The application can set the id with vreader_set_id.
+
+       VReaderStatus vreader_get_id(VReader *reader, VReaderID id);
+
+  This function sets the reader id. The application is responsible for making
+  sure that the id is unique for all readers it is actively using.
+
+       VReader *vreader_find_reader_by_id(VReaderID id);
+
+  This function returns the reader which matches the id. If two readers match,
+  only one is returned. The function returns NULL if the id is -1.
+
+       Event *vevent_wait_next_vevent();
+
+  This function blocks waiting for reader and card insertion events. There
+  will be one event for each card insertion, each card removal, each reader
+  insertion and each reader removal. At start up, events are created for all
+  the initial readers found, as well as all the cards that are inserted.
+
+       Event *vevent_get_next_vevent();
+
+  This function returns a pending event if it exists, otherwise it returns
+  NULL. It does not block.
+
+----------------
+Card Type Emulator: Adding a New Virtual Card Type
+
+The ISO 7816 card spec describes 2 types of cards:
+ 1) File system cards, where the smartcard is managed by reading and writing
+data to files in a file system. There is currently only boiler plate
+implemented for file system cards.
+ 2) VM cards, where the card has loadable applets which perform the card
+functions. The current implementation supports VM cards.
+
+In the case of VM cards, the difference between various types of cards is
+really what applets have been installed in that card. This structure is
+mirrored in card type emulators. The 7816 emulator already handles the basic
+ISO 7186 commands. Card type emulators simply need to add the virtual applets
+which emulate the real card applets. Card type emulators have exactly one
+public entry point:
+
+       VCARDStatus xxx_card_init(VCard *card, const char *flags,
+                               const unsigned char *cert[],
+                               int cert_len[],
+                               VCardKey *key[],
+                               int cert_count);
+
+  The parameters for this are:
+  card       - the virtual card structure which will prepresent this card.
+  flags      - option flags that may be specific to this card type.
+  cert       - array of binary certificates.
+  cert_len   - array of lengths of each of the certificates specified in cert.
+  key        - array of opaque key structures representing the private keys on
+               the card.
+  cert_count - number of entries in cert, cert_len, and key arrays.
+
+  Any cert, cert_len, or key with the same index are matching sets. That is
+  cert[0] is cert_len[0] long and has the corresponsing private key of key[0].
+
+The card type emulator is expected to own the VCardKeys, but it should copy
+any raw cert data it wants to save. It can create new applets and add them to
+the card using the following functions:
+
+       VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func,
+                                     VCardResetApplet reset_func,
+                                     const unsigned char *aid,
+                                     int aid_len);
+
+  This function creates a new applet. Applet structures store the following
+  information:
+     1) the AID of the applet (set by aid and aid_len).
+     2) a function to handle APDUs for this applet. (set by apdu_func, more on
+        this below).
+     3) a function to reset the applet state when the applet is selected.
+        (set by reset_func, more on this below).
+     3) applet private data, a data pointer used by the card type emulator to
+        store any data or state it needs to complete requests. (set by a
+        separate call).
+     4) applet private data free, a function used to free the applet private
+        data when the applet itself is destroyed.
+  The created applet can be added to the card with vcard_add_applet below.
+
+        void vcard_set_applet_private(VCardApplet *applet,
+                                      VCardAppletPrivate *private,
+                                      VCardAppletPrivateFree private_free);
+  This function sets the private data and the corresponding free function.
+  VCardAppletPrivate is an opaque data structure to the rest of the emulator.
+  The card type emulator can define it any way it wants by defining
+  struct VCardAppletPrivateStruct {};. If there is already a private data
+  structure on the applet, the old one is freed before the new one is set up.
+  passing two NULL clear any existing private data.
+
+         VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
+
+  Add an applet onto the list of applets attached to the card. Once an applet
+  has been added, it can be selected by it's aid, and then commands will be
+  routed to it VCardProcessAPDU function. This function adopts the applet the
+  passed int applet. Note: 2 applets with the same AID should not be added to
+  the same card. It's permissible to add more than one applet. Multiple applets
+  may have the same VCardPRocessAPDU entry point.
+
+The certs and keys should be attached to private data associated with one or
+more appropriate applets for that card. Control will come to the card type
+emulators once one of its applets are selected through the VCardProcessAPDU
+function it specified when it created the applet.
+
+The signature of VCardResetApplet is:
+        VCardStatus (*VCardResetApplet) (VCard *card, int channel);
+  This function will reset the any internal applet state that needs to be
+  cleared after a select applet call. It should return VCARD_DONE;
+
+The signature of VCardProcessAPDU is:
+        VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
+                                         VCardResponse **response);
+  This function examines the APDU and determines whether it should process
+  the apdu directly, reject the apdu as invalid, or pass the apdu on to
+  the basic 7816 emulator for processing.
+      If the 7816 emulator should process the apdu, then the VCardProcessAPDU
+  should return VCARD_NEXT.
+      If there is an error, then VCardProcessAPDU should return an error
+  response using vcard_make_response and the appropriate 7816 error code
+  (see card_7816t.h) or vcard_make_response with a card type specific error
+  code. It should then return VCARD_DONE.
+      If the apdu can be processed correctly, VCardProcessAPDU should do so,
+  set the response value appropriately for that APDU, and return VCARD_DONE.
+  VCardProcessAPDU should always set the response if it returns VCARD_DONE.
+  It should always either return VCARD_DONE or VCARD_NEXT.
+
+Parsing the APDU --
+
+Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields:
+
+   apdu->a_data - The raw apdu data bytes.
+   apdu->a_len  - The len of the raw apdu data.
+   apdu->a_body - The start of any post header parameter data.
+   apdu->a_Lc   - The parameter length value.
+   apdu->a_Le   - The expected length of any returned data.
+   apdu->a_cla  - The raw apdu class.
+   apdu->a_channel - The channel (decoded from the class).
+   apdu->a_secure_messaging_type - The decoded secure messagin type
+                                   (from class).
+   apdu->a_type - The decode class type.
+   apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS).
+   apdu->a_ins  - The instruction byte.
+   apdu->a_p1   - Parameter 1.
+   apdu->a_p2   - Parameter 2.
+
+Creating a Response --
+
+The expected result of any APDU call is a response. The card type emulator must
+set *response with an appropriate VCardResponse value if it returns VCARD_DONE.
+Reponses could be as simple as returning a 2 byte status word response, to as
+complex as returning a block of data along with a 2 byte response. Which is
+returned will depend on the semantics of the APDU. The following functions will
+create card responses.
+
+        VCardResponse *vcard_make_response(VCard7816Status status);
+
+    This is the most basic function to get a response. This function will
+    return a response the consists soley one 2 byte status code. If that status
+    code is defined in card_7816t.h, then this function is guarrenteed to
+    return a response with that status. If a cart type specific status code
+    is passed and vcard_make_response fails to allocate the appropriate memory
+    for that response, then vcard_make_response will return a VCardResponse
+    of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is
+    guarrenteed to return a valid VCardResponse.
+
+        VCardResponse *vcard_response_new(unsigned char *buf, int len,
+                                          VCard7816Status status);
+
+    This function is similar to vcard_make_response except it includes some
+    returned data with the response. It could also fail to allocate enough
+    memory, in which case it will return NULL.
+
+        VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
+                                                       unsigned char sw2);
+
+    Sometimes in 7816 the response bytes are treated as two separate bytes with
+    split meanings. This function allows you to create a response based on
+    two separate bytes. This function could fail, in which case it will return
+    NULL.
+
+       VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len,
+                                               unsigned char sw1,
+                                               unsigned char sw2);
+
+    This function is the same as vcard_response_new except you may specify
+    the status as two separate bytes like vcard_response_new_status_bytes.
+
+
+Implementing functionality ---
+
+The following helper functions access information about the current card
+and applet.
+
+        VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card,
+                                                             int channel);
+
+    This function returns any private data set by the card type emulator on
+    the currently selected applet. The card type emulator keeps track of the
+    current applet state in this data structure. Any certs and keys associated
+    with a particular applet is also stored here.
+
+        int vcard_emul_get_login_count(VCard *card);
+
+    This function returns the the number of remaing login attempts for this
+    card. If the card emulator does not know, or the card does not have a
+    way of giving this information, this function returns -1.
+
+
+         VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin,
+                                          int pin_len);
+
+    This function logins into the card and return the standard 7816 status
+    word depending on the success or failure of the call.
+
+         void vcard_emul_delete_key(VCardKey *key);
+
+     This function frees the VCardKey passed in to xxxx_card_init. The card
+     type emulator is responsible for freeing this key when it no longer needs
+     it.
+
+         VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                                           unsigned char *buffer,
+                                           int buffer_size);
+
+     This function does a raw rsa op on the buffer with the given key.
+
+The sample card type emulator is found in cac.c. It implements the cac specific
+applets.  Only those applets needed by the coolkey pkcs#11 driver on the guest
+have been implemented. To support the full range CAC middleware, a complete CAC
+card according to the CAC specs should be implemented here.
+
+------------------------------
+Virtual Card Emulator
+
+This code accesses both real smart cards and simulated smart cards through
+services provided on the client. The current implementation uses NSS, which
+already knows how to talk to various PKCS #11 modules on the client, and is
+portable to most operating systems. A particular emulator can have only one
+virtual card implementation at a time.
+
+The virtual card emulator consists of a series of virtual card services. In
+addition to the services describe above (services starting with
+vcard_emul_xxxx), the virtual card emulator also provides the following
+functions:
+
+    VCardEmulError vcard_emul_init(cont VCardEmulOptions *options);
+
+  The options structure is built by another function in the virtual card
+  interface where a string of virtual card emulator specific strings are
+  mapped to the options. The actual structure is defined by the virutal card
+  emulator and is used to determine the configuration of soft cards, or to
+  determine which physical cards to present to the guest.
+
+  The vcard_emul_init function will build up sets of readers, create any
+  threads that are needed to watch for changes in the reader state. If readers
+  have cards present in them, they are also initialized.
+
+  Readers are created with the function.
+
+          VReader *vreader_new(VReaderEmul *reader_emul,
+                               VReaderEmulFree reader_emul_free);
+
+      The freeFunc is used to free the VReaderEmul * when the reader is
+      destroyed.  The VReaderEmul structure is an opaque structure to the
+      rest of the code, but defined by the virtual card emulator, which can
+      use it to store any reader specific state.
+
+  Once the reader has been created, it can be added to the front end with the
+  call:
+
+           VReaderStatus vreader_add_reader(VReader *reader);
+
+      This function will automatically generate the appropriate new reader
+      events and add the reader to the list.
+
+  To create a new card, the virtual card emulator will call a similiar
+  function.
+
+           VCard *vcard_new(VCardEmul *card_emul,
+                            VCardEmulFree card_emul_free);
+
+      Like vreader_new, this function takes a virtual card emulator specific
+      structure which it uses to keep track of the card state.
+
+  Once the card is created, it is attached to a card type emulator with the
+  following function:
+
+            VCardStatus vcard_init(VCard *vcard, VCardEmulType type,
+                                   const char *flags,
+                                   unsigned char *const *certs,
+                                   int *cert_len,
+                                   VCardKey *key[],
+                                   int cert_count);
+
+      The vcard is the value returned from vcard_new. The type is the
+      card type emulator that this card should presented to the guest as.
+      The flags are card type emulator specific options. The certs,
+      cert_len, and keys are all arrays of length cert_count. These are the
+      the same of the parameters xxxx_card_init() accepts.
+
+   Finally the card is associated with it's reader by the call:
+
+            VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard);
+
+      This function, like vreader_add_reader, will take care of any event
+      notification for the card insert.
+
+
+    VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
+
+  Force a card that is present to appear to be removed to the guest, even if
+  that card is a physical card and is present.
+
+
+    VCardEmulError vcard_emul_force_card_insert(VReader *reader);
+
+  Force a card that has been removed by vcard_emul_force_card_remove to be
+  reinserted from the point of view of the guest. This will only work if the
+  card is physically present (which is always true fro a soft card).
+
+     void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len);
+
+  Return the virtual ATR for the card. By convention this should be the value
+  VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this
+  particular emulator. For instance the NSS emulator returns
+  {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len;
+
+     void vcard_emul_reset(VCard *card, VCardPower power)
+
+   Set the state of 'card' to the current power level and reset its internal
+   state (logout, etc).
+
+-------------------------------------------------------
+List of files and their function:
+README - This file
+card_7816.c - emulate basic 7816 functionality. Parse APDUs.
+card_7816.h - apdu and response services definitions.
+card_7816t.h - 7816 specific structures, types and definitions.
+event.c - event handling code.
+event.h - event handling services definitions.
+eventt.h - event handling structures and types
+vcard.c - handle common virtual card services like creation, destruction, and
+          applet management.
+vcard.h - common virtual card services function definitions.
+vcardt.h - comon virtual card types
+vreader.c - common virtual reader services.
+vreader.h - common virtual reader services definitions.
+vreadert.h - comon virtual reader types.
+vcard_emul_type.c - manage the card type emulators.
+vcard_emul_type.h - definitions for card type emulators.
+cac.c - card type emulator for CAC cards
+vcard_emul.h - virtual card emulator service definitions.
+vcard_emul_nss.c - virtual card emulator implementation for nss.
+vscclient.c - socket connection to guest qemu usb driver.
+vscard_common.h - common header with the guest qemu usb driver.
+mutex.h - header file for machine independent mutexes.
+link_test.c - static test to make sure all the symbols are properly defined.
diff --git a/qemu-0.15.x/docs/migration.txt b/qemu-0.15.x/docs/migration.txt
new file mode 100644
index 0000000..4848c1e
--- /dev/null
+++ b/qemu-0.15.x/docs/migration.txt
@@ -0,0 +1,303 @@
+= Migration =
+
+QEMU has code to load/save the state of the guest that it is running.
+These are two complementary operations.  Saving the state just does
+that, saves the state for each device that the guest is running.
+Restoring a guest is just the opposite operation: we need to load the
+state of each device.
+
+For this to work, QEMU has to be launched with the same arguments the
+two times.  I.e. it can only restore the state in one guest that has
+the same devices that the one it was saved (this last requirement can
+be relaxed a bit, but for now we can consider that configuration has
+to be exactly the same).
+
+Once that we are able to save/restore a guest, a new functionality is
+requested: migration.  This means that QEMU is able to start in one
+machine and being "migrated" to another machine.  I.e. being moved to
+another machine.
+
+Next was the "live migration" functionality.  This is important
+because some guests run with a lot of state (specially RAM), and it
+can take a while to move all state from one machine to another.  Live
+migration allows the guest to continue running while the state is
+transferred.  Only while the last part of the state is transferred has
+the guest to be stopped.  Typically the time that the guest is
+unresponsive during live migration is the low hundred of milliseconds
+(notice that this depends on a lot of things).
+
+=== Types of migration ===
+
+Now that we have talked about live migration, there are several ways
+to do migration:
+
+- tcp migration: do the migration using tcp sockets
+- unix migration: do the migration using unix sockets
+- exec migration: do the migration using the stdin/stdout through a process.
+- fd migration: do the migration using an file descriptor that is
+  passed to QEMU.  QEMU doesn't care how this file descriptor is opened.
+
+All these four migration protocols use the same infrastructure to
+save/restore state devices.  This infrastructure is shared with the
+savevm/loadvm functionality.
+
+=== State Live Migration ==
+
+This is used for RAM and block devices.  It is not yet ported to vmstate.
+<Fill more information here>
+
+=== What is the common infrastructure ===
+
+QEMU uses a QEMUFile abstraction to be able to do migration.  Any type
+of migration that wants to use QEMU infrastructure has to create a
+QEMUFile with:
+
+QEMUFile *qemu_fopen_ops(void *opaque,
+                         QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit,
+                         QEMUFileGetRateLimit *get_rate_limit);
+
+The functions have the following functionality:
+
+This function writes a chunk of data to a file at the given position.
+The pos argument can be ignored if the file is only used for
+streaming.  The handler should try to write all of the data it can.
+
+typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
+                                    int64_t pos, int size);
+
+Read a chunk of data from a file at the given position.  The pos argument
+can be ignored if the file is only be used for streaming.  The number of
+bytes actually read should be returned.
+
+typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
+                                    int64_t pos, int size);
+
+Close a file and return an error code.
+
+typedef int (QEMUFileCloseFunc)(void *opaque);
+
+Called to determine if the file has exceeded its bandwidth allocation.  The
+bandwidth capping is a soft limit, not a hard limit.
+
+typedef int (QEMUFileRateLimit)(void *opaque);
+
+Called to change the current bandwidth allocation. This function must return
+the new actual bandwidth. It should be new_rate if everything goes OK, and
+the old rate otherwise.
+
+typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate);
+typedef size_t (QEMUFileGetRateLimit)(void *opaque);
+
+You can use any internal state that you need using the opaque void *
+pointer that is passed to all functions.
+
+The rate limiting functions are used to limit the bandwidth used by
+QEMU migration.
+
+The important functions for us are put_buffer()/get_buffer() that
+allow to write/read a buffer into the QEMUFile.
+
+=== How to save the state of one device ==
+
+The state of a device is saved using intermediate buffers.  There are
+some helper functions to assist this saving.
+
+There is a new concept that we have to explain here: device state
+version.  When we migrate a device, we save/load the state as a series
+of fields.  Some times, due to bugs or new functionality, we need to
+change the state to store more/different information.  We use the
+version to identify each time that we do a change.  Each version is
+associated with a series of fields saved.  The save_state always saves
+the state as the newer version.  But load_state sometimes is able to
+load state from an older version.
+
+ === Legacy way ===
+
+This way is going to disappear as soon as all current users are ported to VMSTATE.
+
+Each device has to register two functions, one to save the state and
+another to load the state back.
+
+int register_savevm(DeviceState *dev,
+                    const char *idstr,
+                    int instance_id,
+                    int version_id,
+                    SaveStateHandler *save_state,
+                    LoadStateHandler *load_state,
+                    void *opaque);
+
+typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+
+The important functions for the device state format are the save_state
+and load_state.  Notice that load_state receives a version_id
+parameter to know what state format is receiving.  save_state doesn't
+have a version_id parameter because it always uses the latest version.
+
+=== VMState ===
+
+The legacy way of saving/loading state of the device had the problem
+that we have to maintain two functions in sync.  If we did one change
+in one of them and not in the other, we would get a failed migration.
+
+VMState changed the way that state is saved/loaded.  Instead of using
+a function to save the state and another to load it, it was changed to
+a declarative way of what the state consisted of.  Now VMState is able
+to interpret that definition to be able to load/save the state.  As
+the state is declared only once, it can't go out of sync in the
+save/load functions.
+
+An example (from hw/pckbd.c)
+
+static const VMStateDescription vmstate_kbd = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(write_cmd, KBDState),
+        VMSTATE_UINT8(status, KBDState),
+        VMSTATE_UINT8(mode, KBDState),
+        VMSTATE_UINT8(pending, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+We are declaring the state with name "pckbd".
+The version_id is 3, and the fields are 4 uint8_t in a KBDState structure.
+We registered this with:
+
+    vmstate_register(NULL, 0, &vmstate_kbd, s);
+
+Note: talk about how vmstate <-> qdev interact, and what the instance ids mean.
+
+You can search for VMSTATE_* macros for lots of types used in QEMU in
+hw/hw.h.
+
+=== More about versions ==
+
+You can see that there are several version fields:
+
+- version_id: the maximum version_id supported by VMState for that device.
+- minimum_version_id: the minimum version_id that VMState is able to understand
+  for that device.
+- minimum_version_id_old: For devices that were not able to port to vmstate, we can
+  assign a function that knows how to read this old state.
+
+So, VMState is able to read versions from minimum_version_id to
+version_id.  And the function load_state_old() is able to load state
+from minimum_version_id_old to minimum_version_id.  This function is
+deprecated and will be removed when no more users are left.
+
+===  Massaging functions ===
+
+Sometimes, it is not enough to be able to save the state directly
+from one structure, we need to fill the correct values there.  One
+example is when we are using kvm.  Before saving the cpu state, we
+need to ask kvm to copy to QEMU the state that it is using.  And the
+opposite when we are loading the state, we need a way to tell kvm to
+load the state for the cpu that we have just loaded from the QEMUFile.
+
+The functions to do that are inside a vmstate definition, and are called:
+
+- int (*pre_load)(void *opaque);
+
+  This function is called before we load the state of one device.
+
+- int (*post_load)(void *opaque, int version_id);
+
+  This function is called after we load the state of one device.
+
+- void (*pre_save)(void *opaque);
+
+  This function is called before we save the state of one device.
+
+Example: You can look at hpet.c, that uses the three function to
+         massage the state that is transferred.
+
+=== Subsections ===
+
+The use of version_id allows to be able to migrate from older versions
+to newer versions of a device.  But not the other way around.  This
+makes very complicated to fix bugs in stable branches.  If we need to
+add anything to the state to fix a bug, we have to disable migration
+to older versions that don't have that bug-fix (i.e. a new field).
+
+But sometimes, that bug-fix is only needed sometimes, not always.  For
+instance, if the device is in the middle of a DMA operation, it is
+using a specific functionality, ....
+
+It is impossible to create a way to make migration from any version to
+any other version to work.  But we can do better than only allowing
+migration from older versions no newer ones.  For that fields that are
+only needed sometimes, we add the idea of subsections.  A subsection
+is "like" a device vmstate, but with a particularity, it has a Boolean
+function that tells if that values are needed to be sent or not.  If
+this functions returns false, the subsection is not sent.
+
+On the receiving side, if we found a subsection for a device that we
+don't understand, we just fail the migration.  If we understand all
+the subsections, then we load the state with success.
+
+One important note is that the post_load() function is called "after"
+loading all subsections, because a newer subsection could change same
+value that it uses.
+
+Example:
+
+static bool ide_drive_pio_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return (s->status & DRQ_STAT) != 0;
+}
+
+const VMStateDescription vmstate_ide_drive_pio_state = {
+    .name = "ide_drive/pio_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ide_drive_pio_pre_save,
+    .post_load = ide_drive_pio_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(req_nb_sectors, IDEState),
+        VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
+                             vmstate_info_uint8, uint8_t),
+        VMSTATE_INT32(cur_io_buffer_offset, IDEState),
+        VMSTATE_INT32(cur_io_buffer_len, IDEState),
+        VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
+        VMSTATE_INT32(elementary_transfer_size, IDEState),
+        VMSTATE_INT32(packet_transfer_size, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_ide_drive = {
+    .name = "ide_drive",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ide_drive_post_load,
+    .fields      = (VMStateField []) {
+        .... several fields ....
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_drive_pio_state,
+            .needed = ide_drive_pio_state_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+Here we have a subsection for the pio state.  We only need to
+save/send this state when we are in the middle of a pio operation
+(that is what ide_drive_pio_state_needed() checks).  If DRQ_STAT is
+not enabled, the values on that fields are garbage and don't need to
+be sent.
diff --git a/qemu-0.15.x/docs/qapi-code-gen.txt b/qemu-0.15.x/docs/qapi-code-gen.txt
new file mode 100644
index 0000000..b7befb5
--- /dev/null
+++ b/qemu-0.15.x/docs/qapi-code-gen.txt
@@ -0,0 +1,316 @@
+= How to use the QAPI code generator =
+
+* Note: as of this writing, QMP does not use QAPI. Eventually QMP
+commands will be converted to use QAPI internally. The following
+information describes QMP/QAPI as it will exist after the
+conversion.
+
+QAPI is a native C API within QEMU which provides management-level
+functionality to internal/external users. For external
+users/processes, this interface is made available by a JSON-based
+QEMU Monitor protocol that is provided by the QMP server.
+
+To map QMP-defined interfaces to the native C QAPI implementations,
+a JSON-based schema is used to define types and function
+signatures, and a set of scripts is used to generate types/signatures,
+and marshaling/dispatch code. The QEMU Guest Agent also uses these
+scripts, paired with a seperate schema, to generate
+marshaling/dispatch code for the guest agent server running in the
+guest.
+
+This document will describe how the schemas, scripts, and resulting
+code is used.
+
+
+== QMP/Guest agent schema ==
+
+This file defines the types, commands, and events used by QMP.  It should
+fully describe the interface used by QMP.
+
+This file is designed to be loosely based on JSON although it's technically
+executable Python.  While dictionaries are used, they are parsed as
+OrderedDicts so that ordering is preserved.
+
+There are two basic syntaxes used, type definitions and command definitions.
+
+The first syntax defines a type and is represented by a dictionary.  There are
+two kinds of types that are supported: complex user-defined types, and enums.
+
+A complex type is a dictionary containing a single key who's value is a
+dictionary.  This corresponds to a struct in C or an Object in JSON.  An
+example of a complex type is:
+
+ { 'type': 'MyType',
+   'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } }
+
+The use of '*' as a prefix to the name means the member is optional.  Optional
+members should always be added to the end of the dictionary to preserve
+backwards compatibility.
+
+An enumeration type is a dictionary containing a single key who's value is a
+list of strings.  An example enumeration is:
+
+ { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
+
+Generally speaking, complex types and enums should always use CamelCase for
+the type names.
+
+Commands are defined by using a list containing three members.  The first
+member is the command name, the second member is a dictionary containing
+arguments, and the third member is the return type.
+
+An example command is:
+
+ { 'command': 'my-command',
+   'data': { 'arg1': 'str', '*arg2': 'str' },
+   'returns': 'str' ]
+
+Command names should be all lower case with words separated by a hyphen.
+
+
+== Code generation ==
+
+Schemas are fed into 3 scripts to generate all the code/files that, paired
+with the core QAPI libraries, comprise everything required to take JSON
+commands read in by a QMP/guest agent server, unmarshal the arguments into
+the underlying C types, call into the corresponding C function, and map the
+response back to a QMP/guest agent response to be returned to the user.
+
+As an example, we'll use the following schema, which describes a single
+complex user-defined type (which will produce a C struct, along with a list
+node structure that can be used to chain together a list of such types in
+case we want to accept/return a list of this type with a command), and a
+command which takes that type as a parameter and returns the same type:
+
+    mdroth at illuin:~/w/qemu2.git$ cat example-schema.json
+    { 'type': 'UserDefOne',
+      'data': { 'integer': 'int', 'string': 'str' } }
+
+    { 'command': 'my-command',
+      'data':    {'arg1': 'UserDefOne'},
+      'returns': 'UserDefOne' }
+    mdroth at illuin:~/w/qemu2.git$
+
+=== scripts/qapi-types.py ===
+
+Used to generate the C types defined by a schema. The following files are
+created:
+
+$(prefix)qapi-types.h - C types corresponding to types defined in
+                        the schema you pass in
+$(prefix)qapi-types.c - Cleanup functions for the above C types
+
+The $(prefix) is an optional parameter used as a namespace to keep the
+generated code from one schema/code-generation separated from others so code
+can be generated/used from multiple schemas without clobbering previously
+created code.
+
+Example:
+
+    mdroth at illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
+      --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    void qapi_free_UserDefOne(UserDefOne * obj)
+    {
+        QapiDeallocVisitor *md;
+        Visitor *v;
+
+        if (!obj) {
+            return;
+        }
+
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &obj, NULL, NULL);
+        qapi_dealloc_visitor_cleanup(md);
+    }
+
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+    #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+
+    #include "qapi/qapi-types-core.h"
+
+    typedef struct UserDefOne UserDefOne;
+
+    typedef struct UserDefOneList
+    {
+        UserDefOne *value;
+        struct UserDefOneList *next;
+    } UserDefOneList;
+
+    struct UserDefOne
+    {
+        int64_t integer;
+        char * string;
+    };
+
+    void qapi_free_UserDefOne(UserDefOne * obj);
+
+    #endif
+
+
+=== scripts/qapi-visit.py ===
+
+Used to generate the visitor functions used to walk through and convert
+a QObject (as provided by QMP) to a native C data structure and
+vice-versa, as well as the visitor function used to dealloc a complex
+schema-defined C type.
+
+The following files are generated:
+
+$(prefix)qapi-visit.c: visitor function for a particular C type, used
+                       to automagically convert QObjects into the
+                       corresponding C type and vice-versa, as well
+                       as for deallocating memory for an existing C
+                       type
+
+$(prefix)qapi-visit.h: declarations for previously mentioned visitor
+                       functions
+
+Example:
+
+    mdroth at illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
+        --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "example-qapi-visit.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
+    {
+        visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
+        visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
+        visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
+        visit_end_struct(m, errp);
+    }
+
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
+    {
+        GenericList *i;
+
+        visit_start_list(m, name, errp);
+
+        for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+            UserDefOneList *native_i = (UserDefOneList *)i;
+            visit_type_UserDefOne(m, &native_i->value, NULL, errp);
+        }
+
+        visit_end_list(m, errp);
+    }
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+    #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+
+    #include "qapi/qapi-visit-core.h"
+    #include "example-qapi-types.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
+
+    #endif
+    mdroth at illuin:~/w/qemu2.git$
+
+
+=== scripts/qapi-commands.py ===
+
+Used to generate the marshaling/dispatch functions for the commands defined
+in the schema. The following files are generated:
+
+$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
+                        QMP command defined in the schema. Functions
+                        generated by qapi-visit.py are used to
+                        convert QObjects recieved from the wire into
+                        function parameters, and uses the same
+                        visitor functions to convert native C return
+                        values to QObjects from transmission back
+                        over the wire.
+
+$(prefix)qmp-commands.h: Function prototypes for the QMP commands
+                         specified in the schema.
+
+Example:
+
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qemu-objects.h"
+    #include "qapi/qmp-core.h"
+    #include "qapi/qapi-visit-core.h"
+    #include "qapi/qmp-output-visitor.h"
+    #include "qapi/qmp-input-visitor.h"
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    #include "example-qmp-commands.h"
+    static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
+    {
+        QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+        QmpOutputVisitor *mo = qmp_output_visitor_new();
+        Visitor *v;
+
+        v = qmp_output_get_visitor(mo);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        qapi_dealloc_visitor_cleanup(md);
+
+
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+
+    static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+    {
+        UserDefOne * retval = NULL;
+        QmpInputVisitor *mi;
+        QapiDeallocVisitor *md;
+        Visitor *v;
+        UserDefOne * arg1 = NULL;
+
+        mi = qmp_input_visitor_new(QOBJECT(args));
+        v = qmp_input_get_visitor(mi);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+
+        if (error_is_set(errp)) {
+            goto out;
+        }
+        retval = qmp_my_command(arg1, errp);
+        qmp_marshal_output_my_command(retval, ret, errp);
+
+    out:
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        qapi_dealloc_visitor_cleanup(md);
+        return;
+    }
+
+    static void qmp_init_marshal(void)
+    {
+        qmp_register_command("my-command", qmp_marshal_input_my_command);
+    }
+
+    qapi_init(qmp_init_marshal);
+    mdroth at illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+    #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+
+    #include "example-qapi-types.h"
+    #include "error.h"
+
+    UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
+
+    #endif
+    mdroth at illuin:~/w/qemu2.git$
diff --git a/qemu-0.15.x/docs/qdev-device-use.txt b/qemu-0.15.x/docs/qdev-device-use.txt
new file mode 100644
index 0000000..057c322
--- /dev/null
+++ b/qemu-0.15.x/docs/qdev-device-use.txt
@@ -0,0 +1,416 @@
+= How to convert to -device & friends =
+
+=== Specifying Bus and Address on Bus ===
+
+In qdev, each device has a parent bus.  Some devices provide one or
+more buses for children.  You can specify a device's parent bus with
+-device parameter bus.
+
+A device typically has a device address on its parent bus.  For buses
+where this address can be configured, devices provide a bus-specific
+property.  Examples:
+
+    bus         property name       value format
+    PCI         addr                %x.%x    (dev.fn, .fn optional)
+    I2C         address             %u
+    SCSI        scsi-id             %u
+    IDE         unit                %u
+    HDA         cad                 %u
+    virtio-serial-bus  nr           %u
+    ccid-bus    slot                %u
+    USB         port                %d(.%d)*    (port.port...)
+
+Example: device i440FX-pcihost is on the root bus, and provides a PCI
+bus named pci.0.  To put a FOO device into its slot 4, use -device
+FOO,bus=/i440FX-pcihost/pci.0,addr=4.  The abbreviated form bus=pci.0
+also works as long as the bus name is unique.
+
+=== Block Devices ===
+
+A QEMU block device (drive) has a host and a guest part.
+
+In the general case, the guest device is connected to a controller
+device.  For instance, the IDE controller provides two IDE buses, each
+of which can have up to two ide-drive devices, and each ide-drive
+device is a guest part, and is connected to a host part.
+
+Except we sometimes lump controller, bus(es) and drive device(s) all
+together into a single device.  For instance, the ISA floppy
+controller is connected to up to two host drives.
+
+The old ways to define block devices define host and guest part
+together.  Sometimes, they can even define a controller device in
+addition to the block device.
+
+The new way keeps the parts separate: you create the host part with
+-drive, and guest device(s) with -device.
+
+The various old ways to define drives all boil down to the common form
+
+    -drive if=TYPE,bus=BUS,unit=UNIT,OPTS...
+
+TYPE, BUS and UNIT identify the controller device, which of its buses
+to use, and the drive's address on that bus.  Details depend on TYPE.
+
+Instead of bus=BUS,unit=UNIT, you can also say index=IDX.
+
+In the new way, this becomes something like
+
+   -drive if=none,id=DRIVE-ID,HOST-OPTS...
+   -device DEVNAME,drive=DRIVE-ID,DEV-OPTS...
+
+The old OPTS get split into HOST-OPTS and DEV-OPTS as follows:
+
+* file, format, snapshot, cache, aio, readonly, rerror, werror go into
+  HOST-OPTS.
+
+* cyls, head, secs and trans go into HOST-OPTS.  Future work: they
+  should go into DEV-OPTS instead.
+
+* serial goes into DEV-OPTS, for devices supporting serial numbers.
+  For other devices, it goes nowhere.
+
+* media is special.  In the old way, it selects disk vs. CD-ROM with
+  if=ide, if=scsi and if=xen.  The new way uses DEVNAME for that.
+  Additionally, readonly=on goes into HOST-OPTS.
+
+* addr is special, see if=virtio below.
+
+The -device argument differs in detail for each type of drive:
+
+* if=ide
+
+  -device DEVNAME,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+
+  where DEVNAME is either ide-hd or ide-cd, IDE-BUS identifies an IDE
+  bus, normally either ide.0 or ide.1, and UNIT is either 0 or 1.
+
+* if=scsi
+
+  The old way implicitly creates SCSI controllers as needed.  The new
+  way makes that explicit:
+
+  -device lsi53c895a,id=ID
+
+  As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
+  control the PCI device address.
+
+  This SCSI controller provides a single SCSI bus, named ID.0.  Put a
+  disk on it:
+
+  -device DEVNAME,drive=DRIVE-ID,bus=ID.0,scsi-id=UNIT
+
+  where DEVNAME is either scsi-hd, scsi-cd or scsi-generic.
+
+* if=floppy
+
+  -global isa-fdc.driveA=DRIVE-ID
+  -global isa-fdc.driveB=DRIVE-ID
+
+  This is -global instead of -device, because the floppy controller is
+  created automatically, and we want to configure that one, not create
+  a second one (which isn't possible anyway).
+
+  Without any -global isa-fdc,... you get an empty driveA and no
+  driveB.  You can use -nodefaults to suppress the default driveA, see
+  "Default Devices".
+
+* if=virtio
+
+  -device virtio-blk-pci,drive=DRIVE-ID,class=C,vectors=V,ioeventfd=IOEVENTFD
+
+  This lets you control PCI device class and MSI-X vectors.
+
+  IOEVENTFD controls whether or not ioeventfd is used for virtqueue
+  notify.  It can be set to on (default) or off.
+
+  As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
+  control the PCI device address.  This replaces option addr available
+  with -drive if=virtio.
+
+* if=pflash, if=mtd, if=sd, if=xen are not yet available with -device
+
+For USB devices, the old way is actually different:
+
+    -usbdevice disk:format=FMT:FILENAME
+
+Provides much less control than -drive's OPTS...  The new way fixes
+that:
+
+    -device usb-storage,drive=DRIVE-ID,removable=RMB
+
+The removable parameter gives control over the SCSI INQUIRY removable
+(RMB) bit.  USB thumbdrives usually set removable=on, while USB hard
+disks set removable=off.
+
+Bug: usb-storage pretends to be a block device, but it's really a SCSI
+controller that can serve only a single device, which it creates
+automatically.  The automatic creation guesses what kind of guest part
+to create from the host part, like -drive if=scsi.  Host and guest
+part are not cleanly separated.
+
+=== Character Devices ===
+
+A QEMU character device has a host and a guest part.
+
+The old ways to define character devices define host and guest part
+together.
+
+The new way keeps the parts separate: you create the host part with
+-chardev, and the guest device with -device.
+
+The various old ways to define a character device are all of the
+general form
+
+    -FOO FOO-OPTS...,LEGACY-CHARDEV
+
+where FOO-OPTS... is specific to -FOO, and the host part
+LEGACY-CHARDEV is the same everywhere.
+
+In the new way, this becomes
+
+    -chardev HOST-OPTS...,id=CHR-ID
+    -device DEVNAME,chardev=CHR-ID,DEV-OPTS...
+
+The appropriate DEVNAME depends on the machine type.  For type "pc":
+
+* -serial becomes -device isa-serial,iobase=IOADDR,irq=IRQ,index=IDX
+
+  This lets you control I/O ports and IRQs.
+
+* -parallel becomes -device isa-parallel,iobase=IOADDR,irq=IRQ,index=IDX
+
+  This lets you control I/O ports and IRQs.
+
+* -usbdevice serial:vendorid=VID,productid=PRID becomes
+  -device usb-serial,vendorid=VID,productid=PRID
+
+* -usbdevice braille doesn't support LEGACY-CHARDEV syntax.  It always
+  uses "braille".  With -device, this useful default is gone, so you
+  have to use something like
+
+  -device usb-braille,chardev=braille,vendorid=VID,productid=PRID
+  -chardev braille,id=braille
+
+* -virtioconsole becomes
+  -device virtio-serial-pci,class=C,vectors=V,ioeventfd=IOEVENTFD,max_ports=N
+  -device virtconsole,is_console=NUM,nr=NR,name=NAME
+
+LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
+
+* null becomes -chardev null
+
+* pty, msmouse, braille, stdio likewise
+
+* vc:WIDTHxHEIGHT becomes -chardev vc,width=WIDTH,height=HEIGHT
+
+* vc:<COLS>Cx<ROWS>C becomes -chardev vc,cols=<COLS>,rows=<ROWS>
+
+* con: becomes -chardev console
+
+* COM<NUM> becomes -chardev serial,path=<NUM>
+
+* file:FNAME becomes -chardev file,path=FNAME
+
+* pipe:FNAME becomes -chardev pipe,path=FNAME
+
+* tcp:HOST:PORT,OPTS... becomes -chardev socket,host=HOST,port=PORT,OPTS...
+
+* telnet:HOST:PORT,OPTS... becomes
+  -chardev socket,host=HOST,port=PORT,OPTS...,telnet=on
+
+* udp:HOST:PORT at LOCALADDR:LOCALPORT becomes
+  -chardev udp,host=HOST,port=PORT,localaddr=LOCALADDR,localport=LOCALPORT
+
+* unix:FNAME becomes -chardev socket,path=FNAME
+
+* /dev/parportN becomes -chardev parport,file=/dev/parportN
+
+* /dev/ppiN likewise
+
+* Any other /dev/FNAME becomes -chardev tty,path=/dev/FNAME
+
+* mon:LEGACY-CHARDEV is special: it multiplexes the monitor onto the
+  character device defined by LEGACY-CHARDEV.  -chardev provides more
+  general multiplexing instead: you can connect up to four users to a
+  single host part.  You need to pass mux=on to -chardev to enable
+  switching the input focus.
+
+QEMU uses LEGACY-CHARDEV syntax not just to set up guest devices, but
+also in various other places such as -monitor or -net
+user,guestfwd=...  You can use chardev:CHR-ID in place of
+LEGACY-CHARDEV to refer to a host part defined with -chardev.
+
+=== Network Devices ===
+
+Host and guest part of network devices have always been separate.
+
+The old way to define the guest part looks like this:
+
+    -net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
+
+Except for USB it looks like this:
+
+    -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID
+
+The new way is -device:
+
+    -device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS...
+
+DEVNAME equals MODEL, except for virtio you have to name the virtio
+device appropriate for the bus (virtio-net-pci for PCI), and for USB
+you have to use usb-net.
+
+The old name=ID parameter becomes the usual id=ID with -device.
+
+For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
+device address, as usual.  The old -net nic provides parameter addr
+for that, which is silently ignored when the NIC is not a PCI device.
+
+For virtio-net-pci, you can control whether or not ioeventfd is used for
+virtqueue notify by setting ioeventfd= to on or off (default).
+
+-net nic accepts vectors=V for all models, but it's silently ignored
+except for virtio-net-pci (model=virtio).  With -device, only devices
+that support it accept it.
+
+Not all devices are available with -device at this time.  All PCI
+devices and ne2k_isa are.
+
+Some PCI devices aren't available with -net nic, e.g. i82558a.
+
+To connect to a VLAN instead of an ordinary host part, replace
+netdev=NET-ID by vlan=VLAN.
+
+=== Graphics Devices ===
+
+Host and guest part of graphics devices have always been separate.
+
+The old way to define the guest graphics device is -vga VGA.  Not all
+machines support all -vga options.
+
+The new way is -device.  The mapping from -vga argument to -device
+depends on the machine type.  For machine "pc", it's:
+
+    std         -device VGA
+    cirrus      -device cirrus-vga
+    vmware      -device vmware-svga
+    qxl         -device qxl-vga
+    none        -nodefaults
+                disables more than just VGA, see "Default Devices"
+
+As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control
+the PCI device address.
+
+-device VGA supports properties bios-offset and bios-size, but they
+aren't used with machine type "pc".
+
+For machine "isapc", it's
+
+    std         -device isa-vga
+    cirrus      not yet available with -device
+    none        -nodefaults
+                disables more than just VGA, see "Default Devices"
+
+Bug: the new way doesn't work for machine types "pc" and "isapc",
+because it violates obscure device initialization ordering
+constraints.
+
+=== Audio Devices ===
+
+Host and guest part of audio devices have always been separate.
+
+The old way to define guest audio devices is -soundhw C1,...
+
+The new way is to define each guest audio device separately with
+-device.
+
+Map from -soundhw sound card name to -device:
+
+    ac97        -device AC97
+    cs4231a     -device cs4231a,iobase=IOADDR,irq=IRQ,dma=DMA
+    es1370      -device ES1370
+    gus         -device gus,iobase=IOADDR,irq=IRQ,dma=DMA,freq=F
+    hda         -device intel-hda,msi=MSI -device hda-duplex
+    sb16        -device sb16,iobase=IOADDR,irq=IRQ,dma=DMA,dma16=DMA16,version=V
+    adlib       not yet available with -device
+    pcspk       not yet available with -device
+
+For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
+device address, as usual.
+
+=== USB Devices ===
+
+The old way to define a virtual USB device is -usbdevice DRIVER:OPTS...
+
+The new way is -device DEVNAME,DEV-OPTS...  Details depend on DRIVER:
+
+* ccid            -device usb-ccid
+* keyboard        -device usb-kbd
+* mouse           -device usb-mouse
+* tablet          -device usb-tablet
+* wacom-tablet    -device usb-wacom-tablet
+* host:...        See "Host Device Assignment"
+* disk:...        See "Block Devices"
+* serial:...      See "Character Devices"
+* braille         See "Character Devices"
+* net:...         See "Network Devices"
+* bt:...          not yet available with -device
+
+=== Watchdog Devices ===
+
+Host and guest part of watchdog devices have always been separate.
+
+The old way to define a guest watchdog device is -watchdog DEVNAME.
+The new way is -device DEVNAME.  For PCI devices, you can add
+bus=PCI-BUS,addr=DEVFN to control the PCI device address, as usual.
+
+=== Host Device Assignment ===
+
+QEMU supports assigning host PCI devices (qemu-kvm only at this time)
+and host USB devices.
+
+The old way to assign a host PCI device is
+
+    -pcidevice host=ADDR,dma=none,id=ID
+
+The new way is
+
+    -device pci-assign,host=ADDR,iommu=IOMMU,id=ID
+
+The old dma=none becomes iommu=off with -device.
+
+The old way to assign a host USB device is
+
+    -usbdevice host:auto:BUS.ADDR:VID:PRID
+
+where any of BUS, ADDR, VID, PRID can be the wildcard *.
+
+The new way is
+
+    -device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID
+
+Omitted options match anything, just like the old way's wildcard.
+
+=== Default Devices ===
+
+QEMU creates a number of devices by default, depending on the machine
+type.
+
+-device DEVNAME... and global DEVNAME... suppress default devices for
+some DEVNAMEs:
+
+    default device      suppressing DEVNAMEs
+    CD-ROM              ide-cd, ide-drive, scsi-cd
+    isa-fdc's driveA    isa-fdc
+    parallel            isa-parallel
+    serial              isa-serial
+    VGA                 VGA, cirrus-vga, vmware-svga
+    virtioconsole       virtio-serial-pci, virtio-serial-s390, virtio-serial
+
+The default NIC is connected to a default part created along with it.
+It is *not* suppressed by configuring a NIC with -device (you may call
+that a bug).  -net and -netdev suppress the default NIC.
+
+-nodefaults suppresses all the default devices mentioned above, plus a
+few other things such as default SD-Card drive and default monitor.
diff --git a/qemu-0.15.x/docs/specs/acpi_pci_hotplug.txt b/qemu-0.15.x/docs/specs/acpi_pci_hotplug.txt
new file mode 100644
index 0000000..f0f74a7
--- /dev/null
+++ b/qemu-0.15.x/docs/specs/acpi_pci_hotplug.txt
@@ -0,0 +1,37 @@
+QEMU<->ACPI BIOS PCI hotplug interface
+--------------------------------------
+
+QEMU supports PCI hotplug via ACPI, for PCI bus 0. This document
+describes the interface between QEMU and the ACPI BIOS.
+
+ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
+-----------------------------------------
+
+Generic ACPI GPE block. Bit 1 (GPE.1) used to notify PCI hotplug/eject
+event to ACPI BIOS, via SCI interrupt.
+
+PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
+---------------------------------------------------------------
+Slot injection notification pending. One bit per slot.
+
+Read by ACPI BIOS GPE.1 handler to notify OS of injection
+events.
+
+PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
+-----------------------------------------------------
+Slot removal notification pending. One bit per slot.
+
+Read by ACPI BIOS GPE.1 handler to notify OS of removal
+events.
+
+PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
+----------------------------------------
+
+Used by ACPI BIOS _EJ0 method to request device removal. One bit per slot.
+Reads return 0.
+
+PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
+-----------------------------------------------
+
+Used by ACPI BIOS _RMV method to indicate removability status to OS. One
+bit per slot.
diff --git a/qemu-0.15.x/docs/specs/ivshmem_device_spec.txt b/qemu-0.15.x/docs/specs/ivshmem_device_spec.txt
new file mode 100644
index 0000000..23dd2ba
--- /dev/null
+++ b/qemu-0.15.x/docs/specs/ivshmem_device_spec.txt
@@ -0,0 +1,96 @@
+
+Device Specification for Inter-VM shared memory device
+------------------------------------------------------
+
+The Inter-VM shared memory device is designed to share a region of memory to
+userspace in multiple virtual guests.  The memory region does not belong to any
+guest, but is a POSIX memory object on the host.  Optionally, the device may
+support sending interrupts to other guests sharing the same memory region.
+
+
+The Inter-VM PCI device
+-----------------------
+
+*BARs*
+
+The device supports three BARs.  BAR0 is a 1 Kbyte MMIO region to support
+registers.  BAR1 is used for MSI-X when it is enabled in the device.  BAR2 is
+used to map the shared memory object from the host.  The size of BAR2 is
+specified when the guest is started and must be a power of 2 in size.
+
+*Registers*
+
+The device currently supports 4 registers of 32-bits each.  Registers
+are used for synchronization between guests sharing the same memory object when
+interrupts are supported (this requires using the shared memory server).
+
+The server assigns each VM an ID number and sends this ID number to the Qemu
+process when the guest starts.
+
+enum ivshmem_registers {
+    IntrMask = 0,
+    IntrStatus = 4,
+    IVPosition = 8,
+    Doorbell = 12
+};
+
+The first two registers are the interrupt mask and status registers.  Mask and
+status are only used with pin-based interrupts.  They are unused with MSI
+interrupts.
+
+Status Register: The status register is set to 1 when an interrupt occurs.
+
+Mask Register: The mask register is bitwise ANDed with the interrupt status
+and the result will raise an interrupt if it is non-zero.  However, since 1 is
+the only value the status will be set to, it is only the first bit of the mask
+that has any effect.  Therefore interrupts can be masked by setting the first
+bit to 0 and unmasked by setting the first bit to 1.
+
+IVPosition Register: The IVPosition register is read-only and reports the
+guest's ID number.  The guest IDs are non-negative integers.  When using the
+server, since the server is a separate process, the VM ID will only be set when
+the device is ready (shared memory is received from the server and accessible via
+the device).  If the device is not ready, the IVPosition will return -1.
+Applications should ensure that they have a valid VM ID before accessing the
+shared memory.
+
+Doorbell Register:  To interrupt another guest, a guest must write to the
+Doorbell register.  The doorbell register is 32-bits, logically divided into
+two 16-bit fields.  The high 16-bits are the guest ID to interrupt and the low
+16-bits are the interrupt vector to trigger.  The semantics of the value
+written to the doorbell depends on whether the device is using MSI or a regular
+pin-based interrupt.  In short, MSI uses vectors while regular interrupts set the
+status register.
+
+Regular Interrupts
+
+If regular interrupts are used (due to either a guest not supporting MSI or the
+user specifying not to use them on startup) then the value written to the lower
+16-bits of the Doorbell register results is arbitrary and will trigger an
+interrupt in the destination guest.
+
+Message Signalled Interrupts
+
+A ivshmem device may support multiple MSI vectors.  If so, the lower 16-bits
+written to the Doorbell register must be between 0 and the maximum number of
+vectors the guest supports.  The lower 16 bits written to the doorbell is the
+MSI vector that will be raised in the destination guest.  The number of MSI
+vectors is configurable but it is set when the VM is started.
+
+The important thing to remember with MSI is that it is only a signal, no status
+is set (since MSI interrupts are not shared).  All information other than the
+interrupt itself should be communicated via the shared memory region.  Devices
+supporting multiple MSI vectors can use different vectors to indicate different
+events have occurred.  The semantics of interrupt vectors are left to the
+user's discretion.
+
+
+Usage in the Guest
+------------------
+
+The shared memory device is intended to be used with the provided UIO driver.
+Very little configuration is needed.  The guest should map BAR0 to access the
+registers (an array of 32-bit ints allows simple writing) and map BAR2 to
+access the shared memory region itself.  The size of the shared memory region
+is specified when the guest (or shared memory server) is started.  A guest may
+map the whole shared memory region or only part of it.
diff --git a/qemu-0.15.x/docs/specs/qcow2.txt b/qemu-0.15.x/docs/specs/qcow2.txt
new file mode 100644
index 0000000..8fc3cb2
--- /dev/null
+++ b/qemu-0.15.x/docs/specs/qcow2.txt
@@ -0,0 +1,260 @@
+== General ==
+
+A qcow2 image file is organized in units of constant size, which are called
+(host) clusters. A cluster is the unit in which all allocations are done,
+both for actual guest data and for image metadata.
+
+Likewise, the virtual disk as seen by the guest is divided into (guest)
+clusters of the same size.
+
+All numbers in qcow2 are stored in Big Endian byte order.
+
+
+== Header ==
+
+The first cluster of a qcow2 image contains the file header:
+
+    Byte  0 -  3:   magic
+                    QCOW magic string ("QFI\xfb")
+
+          4 -  7:   version
+                    Version number (only valid value is 2)
+
+          8 - 15:   backing_file_offset
+                    Offset into the image file at which the backing file name
+                    is stored (NB: The string is not null terminated). 0 if the
+                    image doesn't have a backing file.
+
+         16 - 19:   backing_file_size
+                    Length of the backing file name in bytes. Must not be
+                    longer than 1023 bytes. Undefined if the image doesn't have
+                    a backing file.
+
+         20 - 23:   cluster_bits
+                    Number of bits that are used for addressing an offset
+                    within a cluster (1 << cluster_bits is the cluster size).
+                    Must not be less than 9 (i.e. 512 byte clusters).
+
+                    Note: qemu as of today has an implementation limit of 2 MB
+                    as the maximum cluster size and won't be able to open images
+                    with larger cluster sizes.
+
+         24 - 31:   size
+                    Virtual disk size in bytes
+
+         32 - 35:   crypt_method
+                    0 for no encryption
+                    1 for AES encryption
+
+         36 - 39:   l1_size
+                    Number of entries in the active L1 table
+
+         40 - 47:   l1_table_offset
+                    Offset into the image file at which the active L1 table
+                    starts. Must be aligned to a cluster boundary.
+
+         48 - 55:   refcount_table_offset
+                    Offset into the image file at which the refcount table
+                    starts. Must be aligned to a cluster boundary.
+
+         56 - 59:   refcount_table_clusters
+                    Number of clusters that the refcount table occupies
+
+         60 - 63:   nb_snapshots
+                    Number of snapshots contained in the image
+
+         64 - 71:   snapshots_offset
+                    Offset into the image file at which the snapshot table
+                    starts. Must be aligned to a cluster boundary.
+
+Directly after the image header, optional sections called header extensions can
+be stored. Each extension has a structure like the following:
+
+    Byte  0 -  3:   Header extension type:
+                        0x00000000 - End of the header extension area
+                        0xE2792ACA - Backing file format name
+                        other      - Unknown header extension, can be safely
+                                     ignored
+
+          4 -  7:   Length of the header extension data
+
+          8 -  n:   Header extension data
+
+          n -  m:   Padding to round up the header extension size to the next
+                    multiple of 8.
+
+The remaining space between the end of the header extension area and the end of
+the first cluster can be used for other data. Usually, the backing file name is
+stored there.
+
+
+== Host cluster management ==
+
+qcow2 manages the allocation of host clusters by maintaining a reference count
+for each host cluster. A refcount of 0 means that the cluster is free, 1 means
+that it is used, and >= 2 means that it is used and any write access must
+perform a COW (copy on write) operation.
+
+The refcounts are managed in a two-level table. The first level is called
+refcount table and has a variable size (which is stored in the header). The
+refcount table can cover multiple clusters, however it needs to be contiguous
+in the image file.
+
+It contains pointers to the second level structures which are called refcount
+blocks and are exactly one cluster in size.
+
+Given a offset into the image file, the refcount of its cluster can be obtained
+as follows:
+
+    refcount_block_entries = (cluster_size / sizeof(uint16_t))
+
+    refcount_block_index = (offset / cluster_size) % refcount_table_entries
+    refcount_table_index = (offset / cluster_size) / refcount_table_entries
+
+    refcount_block = load_cluster(refcount_table[refcount_table_index]);
+    return refcount_block[refcount_block_index];
+
+Refcount table entry:
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 63:    Bits 9-63 of the offset into the image file at which the
+                    refcount block starts. Must be aligned to a cluster
+                    boundary.
+
+                    If this is 0, the corresponding refcount block has not yet
+                    been allocated. All refcounts managed by this refcount block
+                    are 0.
+
+Refcount block entry:
+
+    Bit  0 - 15:    Reference count of the cluster
+
+
+== Cluster mapping ==
+
+Just as for refcounts, qcow2 uses a two-level structure for the mapping of
+guest clusters to host clusters. They are called L1 and L2 table.
+
+The L1 table has a variable size (stored in the header) and may use multiple
+clusters, however it must be contiguous in the image file. L2 tables are
+exactly one cluster in size.
+
+Given a offset into the virtual disk, the offset into the image file can be
+obtained as follows:
+
+    l2_entries = (cluster_size / sizeof(uint64_t))
+
+    l2_index = (offset / cluster_size) % l2_entries
+    l1_index = (offset / cluster_size) / l2_entries
+
+    l2_table = load_cluster(l1_table[l1_index]);
+    cluster_offset = l2_table[l2_index];
+
+    return cluster_offset + (offset % cluster_size)
+
+L1 table entry:
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 55:    Bits 9-55 of the offset into the image file at which the L2
+                    table starts. Must be aligned to a cluster boundary. If the
+                    offset is 0, the L2 table and all clusters described by this
+                    L2 table are unallocated.
+
+        56 - 62:    Reserved (set to 0)
+
+             63:    0 for an L2 table that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in the active L1 table.
+
+L2 table entry (for normal clusters):
+
+    Bit  0 -  8:    Reserved (set to 0)
+
+         9 - 55:    Bits 9-55 of host cluster offset. Must be aligned to a
+                    cluster boundary. If the offset is 0, the cluster is
+                    unallocated.
+
+        56 - 61:    Reserved (set to 0)
+
+             62:    0 (this cluster is not compressed)
+
+             63:    0 for a cluster that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in L2 tables that are reachable from the the active L1
+                    table.
+
+L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
+
+    Bit  0 -  x:    Host cluster offset. This is usually _not_ aligned to a
+                    cluster boundary!
+
+       x+1 - 61:    Compressed size of the images in sectors of 512 bytes
+
+             62:    1 (this cluster is compressed using zlib)
+
+             63:    0 for a cluster that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in L2 tables that are reachable from the the active L1
+                    table.
+
+If a cluster is unallocated, read requests shall read the data from the backing
+file. If there is no backing file or the backing file is smaller than the image,
+they shall read zeros for all parts that are not covered by the backing file.
+
+
+== Snapshots ==
+
+qcow2 supports internal snapshots. Their basic principle of operation is to
+switch the active L1 table, so that a different set of host clusters are
+exposed to the guest.
+
+When creating a snapshot, the L1 table should be copied and the refcount of all
+L2 tables and clusters reachable form this L1 table must be increased, so that
+a write causes a COW and isn't visible in other snapshots.
+
+When loading a snapshot, bit 63 of all entries in the new active L1 table and
+all L2 tables referenced by it must be reconstructed from the refcount table
+as it doesn't need to be accurate in inactive L1 tables.
+
+A directory of all snapshots is stored in the snapshot table, a contiguous area
+in the image file, whose starting offset and length are given by the header
+fields snapshots_offset and nb_snapshots. The entries of the snapshot table
+have variable length, depending on the length of ID, name and extra data.
+
+Snapshot table entry:
+
+    Byte 0 -  7:    Offset into the image file at which the L1 table for the
+                    snapshot starts. Must be aligned to a cluster boundary.
+
+         8 - 11:    Number of entries in the L1 table of the snapshots
+
+        12 - 13:    Length of the unique ID string describing the snapshot
+
+        14 - 15:    Length of the name of the snapshot
+
+        16 - 19:    Time at which the snapshot was taken in seconds since the
+                    Epoch
+
+        20 - 23:    Subsecond part of the time at which the snapshot was taken
+                    in nanoseconds
+
+        24 - 31:    Time that the guest was running until the snapshot was
+                    taken in nanoseconds
+
+        32 - 35:    Size of the VM state in bytes. 0 if no VM state is saved.
+                    If there is VM state, it starts at the first cluster
+                    described by first L1 table entry that doesn't describe a
+                    regular guest cluster (i.e. VM state is stored like guest
+                    disk content, except that it is stored at offsets that are
+                    larger than the virtual disk presented to the guest)
+
+        36 - 39:    Size of extra data in the table entry (used for future
+                    extensions of the format)
+
+        variable:   Extra data for future extensions. Must be ignored.
+
+        variable:   Unique ID string for the snapshot (not null terminated)
+
+        variable:   Name of the snapshot (not null terminated)
diff --git a/qemu-0.15.x/docs/specs/qed_spec.txt b/qemu-0.15.x/docs/specs/qed_spec.txt
new file mode 100644
index 0000000..7982e05
--- /dev/null
+++ b/qemu-0.15.x/docs/specs/qed_spec.txt
@@ -0,0 +1,138 @@
+=Specification=
+
+The file format looks like this:
+
+ +----------+----------+----------+-----+
+ | cluster0 | cluster1 | cluster2 | ... |
+ +----------+----------+----------+-----+
+
+The first cluster begins with the '''header'''.  The header contains information about where regular clusters start; this allows the header to be extensible and store extra information about the image file.  A regular cluster may be a '''data cluster''', an '''L2''', or an '''L1 table'''.  L1 and L2 tables are composed of one or more contiguous clusters.
+
+Normally the file size will be a multiple of the cluster size.  If the file size is not a multiple, extra information after the last cluster may not be preserved if data is written.  Legitimate extra information should use space between the header and the first regular cluster.
+
+All fields are little-endian.
+
+==Header==
+ Header {
+     uint32_t magic;               /* QED\0 */
+ 
+     uint32_t cluster_size;        /* in bytes */
+     uint32_t table_size;          /* for L1 and L2 tables, in clusters */
+     uint32_t header_size;         /* in clusters */
+ 
+     uint64_t features;            /* format feature bits */
+     uint64_t compat_features;     /* compat feature bits */
+     uint64_t autoclear_features;  /* self-resetting feature bits */
+
+     uint64_t l1_table_offset;     /* in bytes */
+     uint64_t image_size;          /* total logical image size, in bytes */
+ 
+     /* if (features & QED_F_BACKING_FILE) */
+     uint32_t backing_filename_offset; /* in bytes from start of header */
+     uint32_t backing_filename_size;   /* in bytes */
+ }
+
+Field descriptions:
+* ''cluster_size'' must be a power of 2 in range [2^12, 2^26].
+* ''table_size'' must be a power of 2 in range [1, 16].
+* ''header_size'' is the number of clusters used by the header and any additional information stored before regular clusters.
+* ''features'', ''compat_features'', and ''autoclear_features'' are file format extension bitmaps.  They work as follows:
+** An image with unknown ''features'' bits enabled must not be opened.  File format changes that are not backwards-compatible must use ''features'' bits.
+** An image with unknown ''compat_features'' bits enabled can be opened safely.  The unknown features are simply ignored and represent backwards-compatible changes to the file format.
+** An image with unknown ''autoclear_features'' bits enable can be opened safely after clearing the unknown bits.  This allows for backwards-compatible changes to the file format which degrade gracefully and can be re-enabled again by a new program later.
+* ''l1_table_offset'' is the offset of the first byte of the L1 table in the image file and must be a multiple of ''cluster_size''.
+* ''image_size'' is the block device size seen by the guest and must be a multiple of 512 bytes.
+* ''backing_filename_offset'' and ''backing_filename_size'' describe a string in (byte offset, byte size) form.  It is not NUL-terminated and has no alignment constraints.  The string must be stored within the first ''header_size'' clusters.  The backing filename may be an absolute path or relative to the image file.
+
+Feature bits:
+* QED_F_BACKING_FILE = 0x01.  The image uses a backing file.
+* QED_F_NEED_CHECK = 0x02.  The image needs a consistency check before use.
+* QED_F_BACKING_FORMAT_NO_PROBE = 0x04.  The backing file is a raw disk image and no file format autodetection should be attempted.  This should be used to ensure that raw backing files are never detected as an image format if they happen to contain magic constants.
+
+There are currently no defined ''compat_features'' or ''autoclear_features'' bits.
+
+Fields predicated on a feature bit are only used when that feature is set.  The fields always take up header space, regardless of whether or not the feature bit is set.
+
+==Tables==
+
+Tables provide the translation from logical offsets in the block device to cluster offsets in the file.
+
+ #define TABLE_NOFFSETS (table_size * cluster_size / sizeof(uint64_t))
+  
+ Table {
+     uint64_t offsets[TABLE_NOFFSETS];
+ }
+
+The tables are organized as follows:
+
+                    +----------+
+                    | L1 table |
+                    +----------+
+               ,------'  |  '------.
+          +----------+   |    +----------+
+          | L2 table |  ...   | L2 table |
+          +----------+        +----------+
+      ,------'  |  '------.
+ +----------+   |    +----------+
+ |   Data   |  ...   |   Data   |
+ +----------+        +----------+
+
+A table is made up of one or more contiguous clusters.  The table_size header field determines table size for an image file.  For example, cluster_size=64 KB and table_size=4 results in 256 KB tables.
+
+The logical image size must be less than or equal to the maximum possible size of clusters rooted by the L1 table:
+ header.image_size <= TABLE_NOFFSETS * TABLE_NOFFSETS * header.cluster_size
+
+L1, L2, and data cluster offsets must be aligned to header.cluster_size.  The following offsets have special meanings:
+
+===L2 table offsets===
+* 0 - unallocated.  The L2 table is not yet allocated.
+
+===Data cluster offsets===
+* 0 - unallocated.  The data cluster is not yet allocated.
+* 1 - zero.  The data cluster contents are all zeroes and no cluster is allocated.
+
+Future format extensions may wish to store per-offset information.  The least significant 12 bits of an offset are reserved for this purpose and must be set to zero.  Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed.
+
+===Unallocated L2 tables and data clusters===
+Reads to an unallocated area of the image file access the backing file.  If there is no backing file, then zeroes are produced.  The backing file may be smaller than the image file and reads of unallocated areas beyond the end of the backing file produce zeroes.
+
+Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated.  The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written.
+
+===Zero data clusters===
+Zero data clusters are a space-efficient way of storing zeroed regions of the image.
+
+Reads to a zero data cluster produce zeroes.  Note that the difference between an unallocated and a zero data cluster is that zero data clusters stop the reading of contents from the backing file.
+
+Writes to a zero data cluster cause a new data cluster to be allocated.  The new data cluster is populated with zeroes and the data being written.
+
+===Logical offset translation===
+Logical offsets are translated into cluster offsets as follows:
+
+  table_bits table_bits    cluster_bits
+  <--------> <--------> <--------------->
+ +----------+----------+-----------------+
+ | L1 index | L2 index |     byte offset |
+ +----------+----------+-----------------+
+ 
+       Structure of a logical offset
+
+ offset_mask = ~(cluster_size - 1) # mask for the image file byte offset
+ 
+ def logical_to_cluster_offset(l1_index, l2_index, byte_offset):
+   l2_offset = l1_table[l1_index]
+   l2_table = load_table(l2_offset)
+   cluster_offset = l2_table[l2_index] & offset_mask
+   return cluster_offset + byte_offset
+
+==Consistency checking==
+
+This section is informational and included to provide background on the use of the QED_F_NEED_CHECK ''features'' bit.
+
+The QED_F_NEED_CHECK bit is used to mark an image as dirty before starting an operation that could leave the image in an inconsistent state if interrupted by a crash or power failure.  A dirty image must be checked on open because its metadata may not be consistent.
+
+Consistency check includes the following invariants:
+# Each cluster is referenced once and only once.  It is an inconsistency to have a cluster referenced more than once by L1 or L2 tables.  A cluster has been leaked if it has no references.
+# Offsets must be within the image file size and must be ''cluster_size'' aligned.
+# Table offsets must at least ''table_size'' * ''cluster_size'' bytes from the end of the image file so that there is space for the entire table.
+
+The consistency check process starts by from ''l1_table_offset'' and scans all L2 tables.  After the check completes with no other errors besides leaks, the QED_F_NEED_CHECK bit can be cleared and the image can be accessed.
diff --git a/qemu-0.15.x/docs/tracing.txt b/qemu-0.15.x/docs/tracing.txt
new file mode 100644
index 0000000..c99a0f2
--- /dev/null
+++ b/qemu-0.15.x/docs/tracing.txt
@@ -0,0 +1,211 @@
+= Tracing =
+
+== Introduction ==
+
+This document describes the tracing infrastructure in QEMU and how to use it
+for debugging, profiling, and observing execution.
+
+== Quickstart ==
+
+1. Build with the 'simple' trace backend:
+
+    ./configure --trace-backend=simple
+    make
+
+2. Enable trace events you are interested in:
+
+    $EDITOR trace-events  # remove "disable" from events you want
+
+3. Run the virtual machine to produce a trace file:
+
+    qemu ... # your normal QEMU invocation
+
+4. Pretty-print the binary trace file:
+
+    ./simpletrace.py trace-events trace-*
+
+== Trace events ==
+
+There is a set of static trace events declared in the "trace-events" source
+file.  Each trace event declaration names the event, its arguments, and the
+format string which can be used for pretty-printing:
+
+    qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
+    qemu_free(void *ptr) "ptr %p"
+
+The "trace-events" file is processed by the "tracetool" script during build to
+generate code for the trace events.  Trace events are invoked directly from
+source code like this:
+
+    #include "trace.h"  /* needed for trace event prototype */
+
+    void *qemu_malloc(size_t size)
+    {
+        void *ptr;
+        if (!size && !allow_zero_malloc()) {
+            abort();
+        }
+        ptr = oom_check(malloc(size ? size : 1));
+        trace_qemu_malloc(size, ptr);  /* <-- trace event */
+        return ptr;
+    }
+
+=== Declaring trace events ===
+
+The "tracetool" script produces the trace.h header file which is included by
+every source file that uses trace events.  Since many source files include
+trace.h, it uses a minimum of types and other header files included to keep the
+namespace clean and compile times and dependencies down.
+
+Trace events should use types as follows:
+
+ * Use stdint.h types for fixed-size types.  Most offsets and guest memory
+   addresses are best represented with uint32_t or uint64_t.  Use fixed-size
+   types over primitive types whose size may change depending on the host
+   (32-bit versus 64-bit) so trace events don't truncate values or break
+   the build.
+
+ * Use void * for pointers to structs or for arrays.  The trace.h header
+   cannot include all user-defined struct declarations and it is therefore
+   necessary to use void * for pointers to structs.
+
+   Pointers (including char *) cannot be dereferenced easily (or at all) in
+   some trace backends.  If pointers are used, ensure they are meaningful by
+   themselves and do not assume the data they point to will be traced.  Do
+   not pass in string arguments.
+
+ * For everything else, use primitive scalar types (char, int, long) with the
+   appropriate signedness.
+
+Format strings should reflect the types defined in the trace event.  Take
+special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
+respectively.  This ensures portability between 32- and 64-bit platforms.  Note
+that format strings must begin and end with double quotes.  When using
+portability macros, ensure they are preceded and followed by double quotes:
+"value %"PRIx64"".
+
+=== Hints for adding new trace events ===
+
+1. Trace state changes in the code.  Interesting points in the code usually
+   involve a state change like starting, stopping, allocating, freeing.  State
+   changes are good trace events because they can be used to understand the
+   execution of the system.
+
+2. Trace guest operations.  Guest I/O accesses like reading device registers
+   are good trace events because they can be used to understand guest
+   interactions.
+
+3. Use correlator fields so the context of an individual line of trace output
+   can be understood.  For example, trace the pointer returned by malloc and
+   used as an argument to free.  This way mallocs and frees can be matched up.
+   Trace events with no context are not very useful.
+
+4. Name trace events after their function.  If there are multiple trace events
+   in one function, append a unique distinguisher at the end of the name.
+
+5. Declare trace events with the "disable" keyword.  Some trace events can
+   produce a lot of output and users are typically only interested in a subset
+   of trace events.  Marking trace events disabled by default saves the user
+   from having to manually disable noisy trace events.
+
+== Trace backends ==
+
+The "tracetool" script automates tedious trace event code generation and also
+keeps the trace event declarations independent of the trace backend.  The trace
+events are not tightly coupled to a specific trace backend, such as LTTng or
+SystemTap.  Support for trace backends can be added by extending the "tracetool"
+script.
+
+The trace backend is chosen at configure time and only one trace backend can
+be built into the binary:
+
+    ./configure --trace-backend=simple
+
+For a list of supported trace backends, try ./configure --help or see below.
+
+The following subsections describe the supported trace backends.
+
+=== Nop ===
+
+The "nop" backend generates empty trace event functions so that the compiler
+can optimize out trace events completely.  This is the default and imposes no
+performance penalty.
+
+=== Stderr ===
+
+The "stderr" backend sends trace events directly to standard error.  This
+effectively turns trace events into debug printfs.
+
+This is the simplest backend and can be used together with existing code that
+uses DPRINTF().
+
+=== Simpletrace ===
+
+The "simple" backend supports common use cases and comes as part of the QEMU
+source tree.  It may not be as powerful as platform-specific or third-party
+trace backends but it is portable.  This is the recommended trace backend
+unless you have specific needs for more advanced backends.
+
+==== Monitor commands ====
+
+* info trace
+  Display the contents of trace buffer.  This command dumps the trace buffer
+  with simple formatting.  For full pretty-printing, use the simpletrace.py
+  script on a binary trace file.
+
+  The trace buffer is written into until full.  The full trace buffer is
+  flushed and emptied.  This means the 'info trace' will display few or no
+  entries if the buffer has just been flushed.
+
+* info trace-events
+  View available trace events and their state.  State 1 means enabled, state 0
+  means disabled.
+
+* trace-event NAME on|off
+  Enable/disable a given trace event.
+
+* trace-file on|off|flush|set <path>
+  Enable/disable/flush the trace file or set the trace file name.
+
+==== Enabling/disabling trace events programmatically ====
+
+The st_change_trace_event_state() function can be used to enable or disable trace
+events at runtime inside QEMU:
+
+    #include "trace.h"
+    
+    st_change_trace_event_state("virtio_irq", true); /* enable */
+    [...]
+    st_change_trace_event_state("virtio_irq", false); /* disable */
+
+==== Analyzing trace files ====
+
+The "simple" backend produces binary trace files that can be formatted with the
+simpletrace.py script.  The script takes the "trace-events" file and the binary
+trace:
+
+    ./simpletrace.py trace-events trace-12345
+
+You must ensure that the same "trace-events" file was used to build QEMU,
+otherwise trace event declarations may have changed and output will not be
+consistent.
+
+=== LTTng Userspace Tracer ===
+
+The "ust" backend uses the LTTng Userspace Tracer library.  There are no
+monitor commands built into QEMU, instead UST utilities should be used to list,
+enable/disable, and dump traces.
+
+=== SystemTap ===
+
+The "dtrace" backend uses DTrace sdt probes but has only been tested with
+SystemTap.  When SystemTap support is detected a .stp file with wrapper probes
+is generated to make use in scripts more convenient.  This step can also be
+performed manually after a build in order to change the binary name in the .stp
+probes:
+
+    scripts/tracetool --dtrace --stap \
+                      --binary path/to/qemu-binary \
+                      --target-type system \
+                      --target-arch x86_64 \
+                      <trace-events >qemu.stp
diff --git a/qemu-0.15.x/docs/usb2.txt b/qemu-0.15.x/docs/usb2.txt
new file mode 100644
index 0000000..228aa33
--- /dev/null
+++ b/qemu-0.15.x/docs/usb2.txt
@@ -0,0 +1,146 @@
+
+USB 2.0 Quick Start
+===================
+
+The QEMU EHCI Adapter can be used with and without companion
+controllers.  See below for the companion controller mode.
+
+When not running in companion controller mode there are two completely
+separate USB busses: One USB 1.1 bus driven by the UHCI controller and
+one USB 2.0 bus driven by the EHCI controller.  Devices must be
+attached to the correct controller manually.
+
+The '-usb' switch will make qemu create the UHCI controller as part of
+the PIIX3 chipset.  The USB 1.1 bus will carry the name "usb.0".
+
+You can use the standard -device switch to add a EHCI controller to
+your virtual machine.  It is strongly recommended to specify an ID for
+the controller so the USB 2.0 bus gets a individual name, for example
+'-device usb-ehci,id=ehci".  This will give you a USB 2.0 bus named
+"ehci.0".
+
+I strongly recomment to also use -device to attach usb devices because
+you can specify the bus they should be attached to this way.  Here is
+a complete example:
+
+    qemu -M pc ${otheroptions}                           \
+        -drive if=none,id=usbstick,file=/path/to/image   \
+        -usb                                             \
+        -device usb-ehci,id=ehci                         \
+        -device usb-tablet,bus=usb.0                     \
+        -device usb-storage,bus=ehci.0,drive=usbstick
+
+This attaches a usb tablet to the UHCI adapter and a usb mass storage
+device to the EHCI adapter.
+
+
+Companion controller support
+----------------------------
+
+Companion controller support has been added recently.  The operational
+model described above with two completely separate busses still works
+fine.  Additionally the UHCI and OHCI controllers got the ability to
+attach to a usb bus created by EHCI as companion controllers.  This is
+done by specifying the masterbus and firstport properties.  masterbus
+specifies the bus name the controller should attach to.  firstport
+specifies the first port the controller should attach to, which is
+needed as usually one ehci controller with six ports has three uhci
+companion controllers with two ports each.
+
+There is a config file in docs which will do all this for you, just
+try ...
+
+    qemu -readconfig docs/ich9-ehci-uhci.cfg
+
+... then use "bus=ehci.0" to assign your usb devices to that bus.
+
+
+More USB tips & tricks
+======================
+
+Recently the usb pass through driver (also known as usb-host) and the
+qemu usb subsystem gained a few capabilities which are available only
+via qdev properties, i,e. when using '-device'.
+
+
+physical port addressing
+------------------------
+
+First you can (for all usb devices) specify the physical port where
+the device will show up in the guest.  This can be done using the
+"port" property.  UHCI has two root ports (1,2).  EHCI has four root
+ports (1-4), the emulated (1.1) USB hub has eight ports.
+
+Plugging a tablet into UHCI port 1 works like this:
+
+        -device usb-tablet,bus=usb.0,port=1
+
+Plugging a hub into UHCI port 2 works like this:
+
+        -device usb-hub,bus=usb.0,port=2
+
+Plugging a virtual usb stick into port 4 of the hub just plugged works
+this way:
+
+        -device usb-storage,bus=usb.0,port=2.4,drive=...
+
+You can do basically the same in the monitor using the device_add
+command.  If you want to unplug devices too you should specify some
+unique id which you can use to refer to the device ...
+
+        (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+        (qemu) device_del my-tablet
+
+... when unplugging it with device_del.
+
+
+USB pass through hints
+----------------------
+
+The usb-host driver has a bunch of properties to specify the device
+which should be passed to the guest:
+
+  hostbus=<nr> -- Specifies the bus number the device must be attached
+  to.
+
+  hostaddr=<nr> -- Specifies the device address the device got
+  assigned by the guest os.
+
+  hostport=<str> -- Specifies the physical port the device is attached
+  to.
+
+  vendorid=<hexnr> -- Specifies the vendor ID of the device.
+  productid=<hexnr> -- Specifies the product ID of the device.
+
+In theory you can combine all these properties as you like.  In
+practice only a few combinations are useful:
+
+  (1) vendorid+productid -- match for a specific device, pass it to
+      the guest when it shows up somewhere in the host.
+
+  (2) hostbus+hostport -- match for a specific physical port in the
+      host, any device which is plugged in there gets passed to the
+      guest.
+
+  (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
+      hostaddr isn't stable, the next time you plug in the device it
+      gets a new one ...
+
+Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
+EHCI.  That means a device plugged into the very same physical port
+may show up on different busses depending on the speed.  The port I'm
+using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
+for 1.1 devices.  Passing through any device plugged into that port
+and also assign them to the correct bus can be done this way:
+
+    qemu -M pc ${otheroptions}                           \
+        -usb                                             \
+        -device usb-ehci,id=ehci                         \
+        -device usb-host,bus=usb.0,hostbus=3,hostport=1  \
+        -device usb-host,bus=ehci.0,hostbus=1,hostport=1
+
+enjoy,
+  Gerd
+
+--
+Gerd Hoffmann <kraxel at redhat.com>
diff --git a/qemu-0.15.x/dyngen-exec.h b/qemu-0.15.x/dyngen-exec.h
new file mode 100644
index 0000000..db00fba
--- /dev/null
+++ b/qemu-0.15.x/dyngen-exec.h
@@ -0,0 +1,84 @@
+/*
+ *  dyngen defines for micro operation code
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined(__DYNGEN_EXEC_H__)
+#define __DYNGEN_EXEC_H__
+
+#include "qemu-common.h"
+
+#ifdef __OpenBSD__
+#include <sys/types.h>
+#endif
+
+/* XXX: This may be wrong for 64-bit ILP32 hosts.  */
+typedef void * host_reg_t;
+
+#if defined(__i386__)
+#define AREG0 "ebp"
+#elif defined(__x86_64__)
+#define AREG0 "r14"
+#elif defined(_ARCH_PPC)
+#define AREG0 "r27"
+#elif defined(__arm__)
+#define AREG0 "r7"
+#elif defined(__hppa__)
+#define AREG0 "r17"
+#elif defined(__mips__)
+#define AREG0 "s0"
+#elif defined(__sparc__)
+#ifdef CONFIG_SOLARIS
+#define AREG0 "g2"
+#else
+#ifdef __sparc_v9__
+#define AREG0 "g5"
+#else
+#define AREG0 "g6"
+#endif
+#endif
+#elif defined(__s390__)
+#define AREG0 "r10"
+#elif defined(__alpha__)
+/* Note $15 is the frame pointer, so anything in op-i386.c that would
+   require a frame pointer, like alloca, would probably loose.  */
+#define AREG0 "$15"
+#elif defined(__mc68000)
+#define AREG0 "%a5"
+#elif defined(__ia64__)
+#define AREG0 "r7"
+#else
+#error unsupported CPU
+#endif
+
+#define xglue(x, y) x ## y
+#define glue(x, y) xglue(x, y)
+#define stringify(s)	tostring(s)
+#define tostring(s)	#s
+
+/* The return address may point to the start of the next instruction.
+   Subtracting one gets us the call instruction itself.  */
+#if defined(__s390__) && !defined(__s390x__)
+# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+#elif defined(__arm__)
+/* Thumb return addresses have the low bit set, so we need to subtract two.
+   This is still safe in ARM mode because instructions are 4 bytes.  */
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
+#else
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
+#endif
+
+#endif /* !defined(__DYNGEN_EXEC_H__) */
diff --git a/qemu-0.15.x/elf.h b/qemu-0.15.x/elf.h
new file mode 100644
index 0000000..ffcac7e
--- /dev/null
+++ b/qemu-0.15.x/elf.h
@@ -0,0 +1,1262 @@
+#ifndef _QEMU_ELF_H
+#define _QEMU_ELF_H
+
+#include <inttypes.h>
+
+/* 32-bit ELF base types. */
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef int32_t  Elf32_Sword;
+typedef uint32_t Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Half;
+typedef int16_t	 Elf64_SHalf;
+typedef uint64_t Elf64_Off;
+typedef int32_t	 Elf64_Sword;
+typedef uint32_t Elf64_Word;
+typedef uint64_t Elf64_Xword;
+typedef int64_t  Elf64_Sxword;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL    0
+#define PT_LOAD    1
+#define PT_DYNAMIC 2
+#define PT_INTERP  3
+#define PT_NOTE    4
+#define PT_SHLIB   5
+#define PT_PHDR    6
+#define PT_LOPROC  0x70000000
+#define PT_HIPROC  0x7fffffff
+#define PT_MIPS_REGINFO		0x70000000
+#define PT_MIPS_OPTIONS		0x70000001
+
+/* Flags in the e_flags field of the header */
+/* MIPS architecture level. */
+#define EF_MIPS_ARCH_1		0x00000000	/* -mips1 code.  */
+#define EF_MIPS_ARCH_2		0x10000000	/* -mips2 code.  */
+#define EF_MIPS_ARCH_3		0x20000000	/* -mips3 code.  */
+#define EF_MIPS_ARCH_4		0x30000000	/* -mips4 code.  */
+#define EF_MIPS_ARCH_5		0x40000000	/* -mips5 code.  */
+#define EF_MIPS_ARCH_32		0x50000000	/* MIPS32 code.  */
+#define EF_MIPS_ARCH_64		0x60000000	/* MIPS64 code.  */
+
+/* The ABI of a file. */
+#define EF_MIPS_ABI_O32		0x00001000	/* O32 ABI.  */
+#define EF_MIPS_ABI_O64		0x00002000	/* O32 extended for 64 bit.  */
+
+#define EF_MIPS_NOREORDER 0x00000001
+#define EF_MIPS_PIC       0x00000002
+#define EF_MIPS_CPIC      0x00000004
+#define EF_MIPS_ABI2		0x00000020
+#define EF_MIPS_OPTIONS_FIRST	0x00000080
+#define EF_MIPS_32BITMODE	0x00000100
+#define EF_MIPS_ABI		0x0000f000
+#define EF_MIPS_ARCH      0xf0000000
+
+/* These constants define the different elf file types */
+#define ET_NONE   0
+#define ET_REL    1
+#define ET_EXEC   2
+#define ET_DYN    3
+#define ET_CORE   4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE  0
+#define EM_M32   1
+#define EM_SPARC 2
+#define EM_386   3
+#define EM_68K   4
+#define EM_88K   5
+#define EM_486   6   /* Perhaps disused */
+#define EM_860   7
+
+#define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */
+
+#define EM_PARISC      15	/* HPPA */
+
+#define EM_SPARC32PLUS 18	/* Sun's "v8plus" */
+
+#define EM_PPC	       20	/* PowerPC */
+#define EM_PPC64       21       /* PowerPC64 */
+
+#define EM_ARM		40		/* ARM */
+
+#define EM_SH	       42	/* SuperH */
+
+#define EM_SPARCV9     43	/* SPARC v9 64-bit */
+
+#define EM_IA_64	50	/* HP/Intel IA-64 */
+
+#define EM_X86_64	62	/* AMD x86-64 */
+
+#define EM_S390		22	/* IBM S/390 */
+
+#define EM_CRIS         76      /* Axis Communications 32-bit embedded processor */
+
+#define EM_V850		87	/* NEC v850 */
+
+#define EM_H8_300H      47      /* Hitachi H8/300H */
+#define EM_H8S          48      /* Hitachi H8S     */
+#define EM_LATTICEMICO32 138    /* LatticeMico32 */
+
+#define EM_UNICORE32    110     /* UniCore32 */
+
+/*
+ * This is an interim value that we will use until the committee comes
+ * up with a final number.
+ */
+#define EM_ALPHA	0x9026
+
+/* Bogus old v850 magic number, used by old tools.  */
+#define EM_CYGNUS_V850	0x9080
+
+/*
+ * This is the old interim value for S/390 architecture
+ */
+#define EM_S390_OLD     0xA390
+
+#define EM_MICROBLAZE      189
+#define EM_MICROBLAZE_OLD  0xBAAB
+
+/* This is the info that is needed to parse the dynamic section of the file */
+#define DT_NULL		0
+#define DT_NEEDED	1
+#define DT_PLTRELSZ	2
+#define DT_PLTGOT	3
+#define DT_HASH		4
+#define DT_STRTAB	5
+#define DT_SYMTAB	6
+#define DT_RELA		7
+#define DT_RELASZ	8
+#define DT_RELAENT	9
+#define DT_STRSZ	10
+#define DT_SYMENT	11
+#define DT_INIT		12
+#define DT_FINI		13
+#define DT_SONAME	14
+#define DT_RPATH 	15
+#define DT_SYMBOLIC	16
+#define DT_REL	        17
+#define DT_RELSZ	18
+#define DT_RELENT	19
+#define DT_PLTREL	20
+#define DT_DEBUG	21
+#define DT_TEXTREL	22
+#define DT_JMPREL	23
+#define DT_BINDNOW	24
+#define DT_INIT_ARRAY	25
+#define DT_FINI_ARRAY	26
+#define DT_INIT_ARRAYSZ	27
+#define DT_FINI_ARRAYSZ	28
+#define DT_RUNPATH	29
+#define DT_FLAGS	30
+#define DT_LOOS		0x6000000d
+#define DT_HIOS		0x6ffff000
+#define DT_LOPROC	0x70000000
+#define DT_HIPROC	0x7fffffff
+
+/* DT_ entries which fall between DT_VALRNGLO and DT_VALRNDHI use
+   the d_val field of the Elf*_Dyn structure.  I.e. they contain scalars.  */
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_VALRNGHI	0x6ffffdff
+
+/* DT_ entries which fall between DT_ADDRRNGLO and DT_ADDRRNGHI use
+   the d_ptr field of the Elf*_Dyn structure.  I.e. they contain pointers.  */
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_ADDRRNGHI	0x6ffffeff
+
+#define	DT_VERSYM	0x6ffffff0
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+#define DT_FLAGS_1	0x6ffffffb
+#define DT_VERDEF	0x6ffffffc
+#define DT_VERDEFNUM	0x6ffffffd
+#define DT_VERNEED	0x6ffffffe
+#define DT_VERNEEDNUM	0x6fffffff
+
+#define DT_MIPS_RLD_VERSION	0x70000001
+#define DT_MIPS_TIME_STAMP	0x70000002
+#define DT_MIPS_ICHECKSUM	0x70000003
+#define DT_MIPS_IVERSION	0x70000004
+#define DT_MIPS_FLAGS		0x70000005
+  #define RHF_NONE		  0
+  #define RHF_HARDWAY		  1
+  #define RHF_NOTPOT		  2
+#define DT_MIPS_BASE_ADDRESS	0x70000006
+#define DT_MIPS_CONFLICT	0x70000008
+#define DT_MIPS_LIBLIST		0x70000009
+#define DT_MIPS_LOCAL_GOTNO	0x7000000a
+#define DT_MIPS_CONFLICTNO	0x7000000b
+#define DT_MIPS_LIBLISTNO	0x70000010
+#define DT_MIPS_SYMTABNO	0x70000011
+#define DT_MIPS_UNREFEXTNO	0x70000012
+#define DT_MIPS_GOTSYM		0x70000013
+#define DT_MIPS_HIPAGENO	0x70000014
+#define DT_MIPS_RLD_MAP		0x70000016
+
+/* This info is needed when parsing the symbol table */
+#define STB_LOCAL  0
+#define STB_GLOBAL 1
+#define STB_WEAK   2
+
+#define STT_NOTYPE  0
+#define STT_OBJECT  1
+#define STT_FUNC    2
+#define STT_SECTION 3
+#define STT_FILE    4
+
+#define ELF_ST_BIND(x)		((x) >> 4)
+#define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
+#define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
+#define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
+#define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
+#define ELF64_ST_TYPE(x)	ELF_ST_TYPE(x)
+
+/* Symbolic values for the entries in the auxiliary table
+   put on the initial stack */
+#define AT_NULL   0	/* end of vector */
+#define AT_IGNORE 1	/* entry should be ignored */
+#define AT_EXECFD 2	/* file descriptor of program */
+#define AT_PHDR   3	/* program headers for program */
+#define AT_PHENT  4	/* size of program header entry */
+#define AT_PHNUM  5	/* number of program headers */
+#define AT_PAGESZ 6	/* system page size */
+#define AT_BASE   7	/* base address of interpreter */
+#define AT_FLAGS  8	/* flags */
+#define AT_ENTRY  9	/* entry point of program */
+#define AT_NOTELF 10	/* program is not ELF */
+#define AT_UID    11	/* real uid */
+#define AT_EUID   12	/* effective uid */
+#define AT_GID    13	/* real gid */
+#define AT_EGID   14	/* effective gid */
+#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
+#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17	/* frequency at which times() increments */
+#define AT_FPUCW  18	/* info about fpu initialization by kernel */
+#define AT_DCACHEBSIZE	19	/* data cache block size */
+#define AT_ICACHEBSIZE	20	/* instruction cache block size */
+#define AT_UCACHEBSIZE	21	/* unified cache block size */
+#define AT_IGNOREPPC	22	/* ppc only; entry should be ignored */
+#define AT_SECURE	23	/* boolean, was exec suid-like? */
+#define AT_BASE_PLATFORM 24	/* string identifying real platforms */
+#define AT_RANDOM	25	/* address of 16 random bytes */
+#define AT_EXECFN	31	/* filename of the executable */
+#define AT_SYSINFO	32	/* address of kernel entry point */
+#define AT_SYSINFO_EHDR	33	/* address of kernel vdso */
+#define AT_L1I_CACHESHAPE 34	/* shapes of the caches: */
+#define AT_L1D_CACHESHAPE 35	/*   bits 0-3: cache associativity.  */
+#define AT_L2_CACHESHAPE  36	/*   bits 4-7: log2 of line size.  */
+#define AT_L3_CACHESHAPE  37	/*   val&~255: cache size.  */
+
+typedef struct dynamic{
+  Elf32_Sword d_tag;
+  union{
+    Elf32_Sword	d_val;
+    Elf32_Addr	d_ptr;
+  } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+  Elf64_Sxword d_tag;		/* entry tag value */
+  union {
+    Elf64_Xword d_val;
+    Elf64_Addr d_ptr;
+  } d_un;
+} Elf64_Dyn;
+
+/* The following are used with relocations */
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+#define ELF64_R_SYM(i)			((i) >> 32)
+#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
+#define ELF64_R_TYPE_DATA(i)            (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
+
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+/* Not a dynamic reloc, so not included in R_386_NUM.  Used in TCG.  */
+#define R_386_PC8	23
+
+#define R_MIPS_NONE		0
+#define R_MIPS_16		1
+#define R_MIPS_32		2
+#define R_MIPS_REL32		3
+#define R_MIPS_26		4
+#define R_MIPS_HI16		5
+#define R_MIPS_LO16		6
+#define R_MIPS_GPREL16		7
+#define R_MIPS_LITERAL		8
+#define R_MIPS_GOT16		9
+#define R_MIPS_PC16		10
+#define R_MIPS_CALL16		11
+#define R_MIPS_GPREL32		12
+/* The remaining relocs are defined on Irix, although they are not
+   in the MIPS ELF ABI.  */
+#define R_MIPS_UNUSED1		13
+#define R_MIPS_UNUSED2		14
+#define R_MIPS_UNUSED3		15
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_GOTHI16		22
+#define R_MIPS_GOTLO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_CALLHI16		30
+#define R_MIPS_CALLLO16		31
+/*
+ * This range is reserved for vendor specific relocations.
+ */
+#define R_MIPS_LOVENDOR		100
+#define R_MIPS_HIVENDOR		127
+
+
+/*
+ * Sparc ELF relocation types
+ */
+#define	R_SPARC_NONE		0
+#define	R_SPARC_8		1
+#define	R_SPARC_16		2
+#define	R_SPARC_32		3
+#define	R_SPARC_DISP8		4
+#define	R_SPARC_DISP16		5
+#define	R_SPARC_DISP32		6
+#define	R_SPARC_WDISP30		7
+#define	R_SPARC_WDISP22		8
+#define	R_SPARC_HI22		9
+#define	R_SPARC_22		10
+#define	R_SPARC_13		11
+#define	R_SPARC_LO10		12
+#define	R_SPARC_GOT10		13
+#define	R_SPARC_GOT13		14
+#define	R_SPARC_GOT22		15
+#define	R_SPARC_PC10		16
+#define	R_SPARC_PC22		17
+#define	R_SPARC_WPLT30		18
+#define	R_SPARC_COPY		19
+#define	R_SPARC_GLOB_DAT	20
+#define	R_SPARC_JMP_SLOT	21
+#define	R_SPARC_RELATIVE	22
+#define	R_SPARC_UA32		23
+#define R_SPARC_PLT32		24
+#define R_SPARC_HIPLT22		25
+#define R_SPARC_LOPLT10		26
+#define R_SPARC_PCPLT32		27
+#define R_SPARC_PCPLT22		28
+#define R_SPARC_PCPLT10		29
+#define R_SPARC_10		30
+#define R_SPARC_11		31
+#define R_SPARC_64		32
+#define R_SPARC_OLO10           33
+#define R_SPARC_HH22            34
+#define R_SPARC_HM10            35
+#define R_SPARC_LM22            36
+#define R_SPARC_WDISP16		40
+#define R_SPARC_WDISP19		41
+#define R_SPARC_7		43
+#define R_SPARC_5		44
+#define R_SPARC_6		45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR       2
+#define HWCAP_SPARC_SWAP        4
+#define HWCAP_SPARC_MULDIV      8
+#define HWCAP_SPARC_V9		16
+#define HWCAP_SPARC_ULTRA3	32
+
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE	0
+#define R_68K_32	1
+#define R_68K_16	2
+#define R_68K_8		3
+#define R_68K_PC32	4
+#define R_68K_PC16	5
+#define R_68K_PC8	6
+#define R_68K_GOT32	7
+#define R_68K_GOT16	8
+#define R_68K_GOT8	9
+#define R_68K_GOT32O	10
+#define R_68K_GOT16O	11
+#define R_68K_GOT8O	12
+#define R_68K_PLT32	13
+#define R_68K_PLT16	14
+#define R_68K_PLT8	15
+#define R_68K_PLT32O	16
+#define R_68K_PLT16O	17
+#define R_68K_PLT8O	18
+#define R_68K_COPY	19
+#define R_68K_GLOB_DAT	20
+#define R_68K_JMP_SLOT	21
+#define R_68K_RELATIVE	22
+
+/*
+ * Alpha ELF relocation types
+ */
+#define R_ALPHA_NONE            0       /* No reloc */
+#define R_ALPHA_REFLONG         1       /* Direct 32 bit */
+#define R_ALPHA_REFQUAD         2       /* Direct 64 bit */
+#define R_ALPHA_GPREL32         3       /* GP relative 32 bit */
+#define R_ALPHA_LITERAL         4       /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE          5       /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP          6       /* Add displacement to GP */
+#define R_ALPHA_BRADDR          7       /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT            8       /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16          9       /* PC relative 16 bit */
+#define R_ALPHA_SREL32          10      /* PC relative 32 bit */
+#define R_ALPHA_SREL64          11      /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH       17      /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW        18      /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16         19      /* GP relative 16 bit */
+#define R_ALPHA_COPY            24      /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT        25      /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT        26      /* Create PLT entry */
+#define R_ALPHA_RELATIVE        27      /* Adjust by program base */
+#define R_ALPHA_BRSGP		28
+#define R_ALPHA_TLSGD           29
+#define R_ALPHA_TLS_LDM         30
+#define R_ALPHA_DTPMOD64        31
+#define R_ALPHA_GOTDTPREL       32
+#define R_ALPHA_DTPREL64        33
+#define R_ALPHA_DTPRELHI        34
+#define R_ALPHA_DTPRELLO        35
+#define R_ALPHA_DTPREL16        36
+#define R_ALPHA_GOTTPREL        37
+#define R_ALPHA_TPREL64         38
+#define R_ALPHA_TPRELHI         39
+#define R_ALPHA_TPRELLO         40
+#define R_ALPHA_TPREL16         41
+
+#define SHF_ALPHA_GPREL		0x10000000
+
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+/* Keep this the last entry.  */
+#ifndef R_PPC_NUM
+#define R_PPC_NUM		37
+#endif
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC     0x01
+#define EF_ARM_HASENTRY    0x02
+#define EF_ARM_INTERWORK   0x04
+#define EF_ARM_APCS_26     0x08
+#define EF_ARM_APCS_FLOAT  0x10
+#define EF_ARM_PIC         0x20
+#define EF_ALIGN8          0x40		/* 8-bit structure alignment is in use */
+#define EF_NEW_ABI         0x80
+#define EF_OLD_ABI         0x100
+
+/* Additional symbol types for Thumb */
+#define STT_ARM_TFUNC      0xd
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
+#define SHF_ARM_COMDEF     0x80000000   /* Section may be multiply defined
+					   in the input to a link step */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB          0x10000000   /* Segment contains the location
+					   addressed by the static base */
+
+/* ARM relocs.  */
+#define R_ARM_NONE		0	/* No reloc */
+#define R_ARM_PC24		1	/* PC relative 26 bit branch */
+#define R_ARM_ABS32		2	/* Direct 32 bit  */
+#define R_ARM_REL32		3	/* PC relative 32 bit */
+#define R_ARM_PC13		4
+#define R_ARM_ABS16		5	/* Direct 16 bit */
+#define R_ARM_ABS12		6	/* Direct 12 bit */
+#define R_ARM_THM_ABS5		7
+#define R_ARM_ABS8		8	/* Direct 8 bit */
+#define R_ARM_SBREL32		9
+#define R_ARM_THM_PC22		10
+#define R_ARM_THM_PC8		11
+#define R_ARM_AMP_VCALL9	12
+#define R_ARM_SWI24		13
+#define R_ARM_THM_SWI8		14
+#define R_ARM_XPC25		15
+#define R_ARM_THM_XPC22		16
+#define R_ARM_COPY		20	/* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
+#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
+#define R_ARM_RELATIVE		23	/* Adjust by program base */
+#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
+#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32		26	/* 32 bit GOT entry */
+#define R_ARM_PLT32		27	/* 32 bit PLT address */
+#define R_ARM_CALL              28
+#define R_ARM_JUMP24            29
+#define R_ARM_GNU_VTENTRY	100
+#define R_ARM_GNU_VTINHERIT	101
+#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
+#define R_ARM_THM_PC9		103	/* thumb conditional branch */
+#define R_ARM_RXPC25		249
+#define R_ARM_RSBREL32		250
+#define R_ARM_THM_RPC22		251
+#define R_ARM_RREL32		252
+#define R_ARM_RABS22		253
+#define R_ARM_RPC24		254
+#define R_ARM_RBASE		255
+/* Keep this the last entry.  */
+#define R_ARM_NUM		256
+
+/* s390 relocations defined by the ABIs */
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC rel. offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+                                           dynamic TLS code.  */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+                                           dynamic TLS code.  */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.  */
+#define R_390_TLS_TPOFF		56	/* Negate offset in static TLS
+                                           block.  */
+/* Keep this the last entry.  */
+#define R_390_NUM	57
+
+/* x86-64 relocation types */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM		16
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses are below 2GB */
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
+					      prediction.  */
+#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
+					      symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
+#define STT_HP_STUB		(STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE		0	/* No reloc.  */
+#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
+#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
+#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE	128
+#define R_PARISC_COPY		128	/* Copy relocation.  */
+#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_HIRESERVE	255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS		(PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
+#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
+#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
+#define PT_HP_STACK		(PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT	0x70000000
+#define PT_PARISC_UNWIND	0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP		0x08000000
+
+#define PF_HP_PAGE_SIZE		0x00100000
+#define PF_HP_FAR_SHARED	0x00200000
+#define PF_HP_NEAR_SHARED	0x00400000
+#define PF_HP_CODE		0x01000000
+#define PF_HP_MODIFY		0x02000000
+#define PF_HP_LAZYSWAP		0x04000000
+#define PF_HP_SBP		0x08000000
+
+/* IA-64 specific declarations.  */
+
+/* Processor specific flags for the Ehdr e_flags field.  */
+#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
+#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
+#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
+#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
+
+/* Processor specific flags for the Phdr p_flags field.  */
+#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field.  */
+#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
+#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field.  */
+#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
+#define DT_IA_64_NUM		1
+
+/* IA-64 relocations.  */
+#define R_IA64_NONE		0x00	/* none */
+#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
+#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
+#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
+#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
+#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
+#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
+#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY		0x84	/* copy relocation */
+#define R_IA64_SUB		0x85	/* Addend and symbol difference */
+#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
+#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
+#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
+
+typedef struct elf32_rel {
+  Elf32_Addr	r_offset;
+  Elf32_Word	r_info;
+} Elf32_Rel;
+
+typedef struct elf64_rel {
+  Elf64_Addr r_offset;	/* Location at which to apply the action */
+  Elf64_Xword r_info;	/* index and type of relocation */
+} Elf64_Rel;
+
+typedef struct elf32_rela{
+  Elf32_Addr	r_offset;
+  Elf32_Word	r_info;
+  Elf32_Sword	r_addend;
+} Elf32_Rela;
+
+typedef struct elf64_rela {
+  Elf64_Addr r_offset;	/* Location at which to apply the action */
+  Elf64_Xword r_info;	/* index and type of relocation */
+  Elf64_Sxword r_addend;	/* Constant addend used to compute value */
+} Elf64_Rela;
+
+typedef struct elf32_sym{
+  Elf32_Word	st_name;
+  Elf32_Addr	st_value;
+  Elf32_Word	st_size;
+  unsigned char	st_info;
+  unsigned char	st_other;
+  Elf32_Half	st_shndx;
+} Elf32_Sym;
+
+typedef struct elf64_sym {
+  Elf64_Word st_name;		/* Symbol name, index in string tbl */
+  unsigned char	st_info;	/* Type and binding attributes */
+  unsigned char	st_other;	/* No defined meaning, 0 */
+  Elf64_Half st_shndx;		/* Associated section index */
+  Elf64_Addr st_value;		/* Value of the symbol */
+  Elf64_Xword st_size;		/* Associated symbol size */
+} Elf64_Sym;
+
+
+#define EI_NIDENT	16
+
+typedef struct elf32_hdr{
+  unsigned char	e_ident[EI_NIDENT];
+  Elf32_Half	e_type;
+  Elf32_Half	e_machine;
+  Elf32_Word	e_version;
+  Elf32_Addr	e_entry;  /* Entry point */
+  Elf32_Off	e_phoff;
+  Elf32_Off	e_shoff;
+  Elf32_Word	e_flags;
+  Elf32_Half	e_ehsize;
+  Elf32_Half	e_phentsize;
+  Elf32_Half	e_phnum;
+  Elf32_Half	e_shentsize;
+  Elf32_Half	e_shnum;
+  Elf32_Half	e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+  unsigned char	e_ident[16];		/* ELF "magic number" */
+  Elf64_Half e_type;
+  Elf64_Half e_machine;
+  Elf64_Word e_version;
+  Elf64_Addr e_entry;		/* Entry point virtual address */
+  Elf64_Off e_phoff;		/* Program header table file offset */
+  Elf64_Off e_shoff;		/* Section header table file offset */
+  Elf64_Word e_flags;
+  Elf64_Half e_ehsize;
+  Elf64_Half e_phentsize;
+  Elf64_Half e_phnum;
+  Elf64_Half e_shentsize;
+  Elf64_Half e_shnum;
+  Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+   header, p_flags. */
+#define PF_R		0x4
+#define PF_W		0x2
+#define PF_X		0x1
+
+typedef struct elf32_phdr{
+  Elf32_Word	p_type;
+  Elf32_Off	p_offset;
+  Elf32_Addr	p_vaddr;
+  Elf32_Addr	p_paddr;
+  Elf32_Word	p_filesz;
+  Elf32_Word	p_memsz;
+  Elf32_Word	p_flags;
+  Elf32_Word	p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+  Elf64_Word p_type;
+  Elf64_Word p_flags;
+  Elf64_Off p_offset;		/* Segment file offset */
+  Elf64_Addr p_vaddr;		/* Segment virtual address */
+  Elf64_Addr p_paddr;		/* Segment physical address */
+  Elf64_Xword p_filesz;		/* Segment size in file */
+  Elf64_Xword p_memsz;		/* Segment size in memory */
+  Elf64_Xword p_align;		/* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+/* sh_type */
+#define SHT_NULL	0
+#define SHT_PROGBITS	1
+#define SHT_SYMTAB	2
+#define SHT_STRTAB	3
+#define SHT_RELA	4
+#define SHT_HASH	5
+#define SHT_DYNAMIC	6
+#define SHT_NOTE	7
+#define SHT_NOBITS	8
+#define SHT_REL		9
+#define SHT_SHLIB	10
+#define SHT_DYNSYM	11
+#define SHT_NUM		12
+#define SHT_LOPROC	0x70000000
+#define SHT_HIPROC	0x7fffffff
+#define SHT_LOUSER	0x80000000
+#define SHT_HIUSER	0xffffffff
+#define SHT_MIPS_LIST		0x70000000
+#define SHT_MIPS_CONFLICT	0x70000002
+#define SHT_MIPS_GPTAB		0x70000003
+#define SHT_MIPS_UCODE		0x70000004
+
+/* sh_flags */
+#define SHF_WRITE	0x1
+#define SHF_ALLOC	0x2
+#define SHF_EXECINSTR	0x4
+#define SHF_MASKPROC	0xf0000000
+#define SHF_MIPS_GPREL	0x10000000
+
+/* special section indexes */
+#define SHN_UNDEF	0
+#define SHN_LORESERVE	0xff00
+#define SHN_LOPROC	0xff00
+#define SHN_HIPROC	0xff1f
+#define SHN_ABS		0xfff1
+#define SHN_COMMON	0xfff2
+#define SHN_HIRESERVE	0xffff
+#define SHN_MIPS_ACCOMON	0xff00
+
+typedef struct elf32_shdr {
+  Elf32_Word	sh_name;
+  Elf32_Word	sh_type;
+  Elf32_Word	sh_flags;
+  Elf32_Addr	sh_addr;
+  Elf32_Off	sh_offset;
+  Elf32_Word	sh_size;
+  Elf32_Word	sh_link;
+  Elf32_Word	sh_info;
+  Elf32_Word	sh_addralign;
+  Elf32_Word	sh_entsize;
+} Elf32_Shdr;
+
+typedef struct elf64_shdr {
+  Elf64_Word sh_name;		/* Section name, index in string tbl */
+  Elf64_Word sh_type;		/* Type of section */
+  Elf64_Xword sh_flags;		/* Miscellaneous section attributes */
+  Elf64_Addr sh_addr;		/* Section virtual addr at execution */
+  Elf64_Off sh_offset;		/* Section file offset */
+  Elf64_Xword sh_size;		/* Size of section in bytes */
+  Elf64_Word sh_link;		/* Index of another section */
+  Elf64_Word sh_info;		/* Additional section information */
+  Elf64_Xword sh_addralign;	/* Section alignment */
+  Elf64_Xword sh_entsize;	/* Entry size if section holds table */
+} Elf64_Shdr;
+
+#define	EI_MAG0		0		/* e_ident[] indexes */
+#define	EI_MAG1		1
+#define	EI_MAG2		2
+#define	EI_MAG3		3
+#define	EI_CLASS	4
+#define	EI_DATA		5
+#define	EI_VERSION	6
+#define	EI_OSABI	7
+#define	EI_PAD		8
+
+#define ELFOSABI_NONE           0       /* UNIX System V ABI */
+#define ELFOSABI_SYSV           0       /* Alias.  */
+#define ELFOSABI_HPUX           1       /* HP-UX */
+#define ELFOSABI_NETBSD         2       /* NetBSD.  */
+#define ELFOSABI_LINUX          3       /* Linux.  */
+#define ELFOSABI_SOLARIS        6       /* Sun Solaris.  */
+#define ELFOSABI_AIX            7       /* IBM AIX.  */
+#define ELFOSABI_IRIX           8       /* SGI Irix.  */
+#define ELFOSABI_FREEBSD        9       /* FreeBSD.  */
+#define ELFOSABI_TRU64          10      /* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO        11      /* Novell Modesto.  */
+#define ELFOSABI_OPENBSD        12      /* OpenBSD.  */
+#define ELFOSABI_ARM            97      /* ARM */
+#define ELFOSABI_STANDALONE     255     /* Standalone (embedded) application */
+
+#define	ELFMAG0		0x7f		/* EI_MAG */
+#define	ELFMAG1		'E'
+#define	ELFMAG2		'L'
+#define	ELFMAG3		'F'
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define	ELFCLASSNONE	0		/* EI_CLASS */
+#define	ELFCLASS32	1
+#define	ELFCLASS64	2
+#define	ELFCLASSNUM	3
+
+#define ELFDATANONE	0		/* e_ident[EI_DATA] */
+#define ELFDATA2LSB	1
+#define ELFDATA2MSB	2
+
+#define EV_NONE		0		/* e_version, EI_VERSION */
+#define EV_CURRENT	1
+#define EV_NUM		2
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS	1
+#define NT_PRFPREG	2
+#define NT_PRPSINFO	3
+#define NT_TASKSTRUCT	4
+#define NT_AUXV		6
+#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
+
+
+/* Note header in a PT_NOTE section */
+typedef struct elf32_note {
+  Elf32_Word	n_namesz;	/* Name size */
+  Elf32_Word	n_descsz;	/* Content size */
+  Elf32_Word	n_type;		/* Content type */
+} Elf32_Nhdr;
+
+/* Note header in a PT_NOTE section */
+typedef struct elf64_note {
+  Elf64_Word n_namesz;	/* Name size */
+  Elf64_Word n_descsz;	/* Content size */
+  Elf64_Word n_type;	/* Content type */
+} Elf64_Nhdr;
+
+
+/* This data structure represents a PT_LOAD segment.  */
+struct elf32_fdpic_loadseg {
+  /* Core address to which the segment is mapped.  */
+  Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  Elf32_Word p_memsz;
+};
+struct elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  Elf32_Half version;
+  /* Number of segments in this map.  */
+  Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
+#ifdef ELF_CLASS
+#if ELF_CLASS == ELFCLASS32
+
+#define elfhdr		elf32_hdr
+#define elf_phdr	elf32_phdr
+#define elf_note	elf32_note
+#define elf_shdr	elf32_shdr
+#define elf_sym		elf32_sym
+#define elf_addr_t	Elf32_Off
+
+#ifdef ELF_USES_RELOCA
+# define ELF_RELOC      Elf32_Rela
+#else
+# define ELF_RELOC      Elf32_Rel
+#endif
+
+#else
+
+#define elfhdr		elf64_hdr
+#define elf_phdr	elf64_phdr
+#define elf_note	elf64_note
+#define elf_shdr	elf64_shdr
+#define elf_sym		elf64_sym
+#define elf_addr_t	Elf64_Off
+
+#ifdef ELF_USES_RELOCA
+# define ELF_RELOC      Elf64_Rela
+#else
+# define ELF_RELOC      Elf64_Rel
+#endif
+
+#endif /* ELF_CLASS */
+
+#ifndef ElfW
+# if ELF_CLASS == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+#endif /* ELF_CLASS */
+
+
+#endif /* _QEMU_ELF_H */
diff --git a/qemu-0.15.x/envlist.c b/qemu-0.15.x/envlist.c
new file mode 100644
index 0000000..f2303cd
--- /dev/null
+++ b/qemu-0.15.x/envlist.c
@@ -0,0 +1,246 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "qemu-queue.h"
+#include "envlist.h"
+
+struct envlist_entry {
+	const char *ev_var;			/* actual env value */
+	QLIST_ENTRY(envlist_entry) ev_link;
+};
+
+struct envlist {
+	QLIST_HEAD(, envlist_entry) el_entries;	/* actual entries */
+	size_t el_count;			/* number of entries */
+};
+
+static int envlist_parse(envlist_t *envlist,
+    const char *env, int (*)(envlist_t *, const char *));
+
+/*
+ * Allocates new envlist and returns pointer to that or
+ * NULL in case of error.
+ */
+envlist_t *
+envlist_create(void)
+{
+	envlist_t *envlist;
+
+	if ((envlist = malloc(sizeof (*envlist))) == NULL)
+		return (NULL);
+
+	QLIST_INIT(&envlist->el_entries);
+	envlist->el_count = 0;
+
+	return (envlist);
+}
+
+/*
+ * Releases given envlist and its entries.
+ */
+void
+envlist_free(envlist_t *envlist)
+{
+	struct envlist_entry *entry;
+
+	assert(envlist != NULL);
+
+	while (envlist->el_entries.lh_first != NULL) {
+		entry = envlist->el_entries.lh_first;
+		QLIST_REMOVE(entry, ev_link);
+
+		free((char *)entry->ev_var);
+		free(entry);
+	}
+	free(envlist);
+}
+
+/*
+ * Parses comma separated list of set/modify environment
+ * variable entries and updates given enlist accordingly.
+ *
+ * For example:
+ *     envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
+ *
+ * inserts/sets environment variables HOME and SHELL.
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int
+envlist_parse_set(envlist_t *envlist, const char *env)
+{
+	return (envlist_parse(envlist, env, &envlist_setenv));
+}
+
+/*
+ * Parses comma separated list of unset environment variable
+ * entries and removes given variables from given envlist.
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int
+envlist_parse_unset(envlist_t *envlist, const char *env)
+{
+	return (envlist_parse(envlist, env, &envlist_unsetenv));
+}
+
+/*
+ * Parses comma separated list of set, modify or unset entries
+ * and calls given callback for each entry.
+ *
+ * Returns 0 in case of success, errno otherwise.
+ */
+static int
+envlist_parse(envlist_t *envlist, const char *env,
+    int (*callback)(envlist_t *, const char *))
+{
+	char *tmpenv, *envvar;
+	char *envsave = NULL;
+
+	assert(callback != NULL);
+
+	if ((envlist == NULL) || (env == NULL))
+		return (EINVAL);
+
+	/*
+	 * We need to make temporary copy of the env string
+	 * as strtok_r(3) modifies it while it tokenizes.
+	 */
+	if ((tmpenv = strdup(env)) == NULL)
+		return (errno);
+
+	envvar = strtok_r(tmpenv, ",", &envsave);
+	while (envvar != NULL) {
+		if ((*callback)(envlist, envvar) != 0) {
+			free(tmpenv);
+			return (errno);
+		}
+		envvar = strtok_r(NULL, ",", &envsave);
+	}
+
+	free(tmpenv);
+	return (0);
+}
+
+/*
+ * Sets environment value to envlist in similar manner
+ * than putenv(3).
+ *
+ * Returns 0 in success, errno otherwise.
+ */
+int
+envlist_setenv(envlist_t *envlist, const char *env)
+{
+	struct envlist_entry *entry = NULL;
+	const char *eq_sign;
+	size_t envname_len;
+
+	if ((envlist == NULL) || (env == NULL))
+		return (EINVAL);
+
+	/* find out first equals sign in given env */
+	if ((eq_sign = strchr(env, '=')) == NULL)
+		return (EINVAL);
+	envname_len = eq_sign - env + 1;
+
+	/*
+	 * If there already exists variable with given name
+	 * we remove and release it before allocating a whole
+	 * new entry.
+	 */
+	for (entry = envlist->el_entries.lh_first; entry != NULL;
+	    entry = entry->ev_link.le_next) {
+		if (strncmp(entry->ev_var, env, envname_len) == 0)
+			break;
+	}
+
+	if (entry != NULL) {
+		QLIST_REMOVE(entry, ev_link);
+		free((char *)entry->ev_var);
+		free(entry);
+	} else {
+		envlist->el_count++;
+	}
+
+	if ((entry = malloc(sizeof (*entry))) == NULL)
+		return (errno);
+	if ((entry->ev_var = strdup(env)) == NULL) {
+		free(entry);
+		return (errno);
+	}
+	QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
+
+	return (0);
+}
+
+/*
+ * Removes given env value from envlist in similar manner
+ * than unsetenv(3).  Returns 0 in success, errno otherwise.
+ */
+int
+envlist_unsetenv(envlist_t *envlist, const char *env)
+{
+	struct envlist_entry *entry;
+	size_t envname_len;
+
+	if ((envlist == NULL) || (env == NULL))
+		return (EINVAL);
+
+	/* env is not allowed to contain '=' */
+	if (strchr(env, '=') != NULL)
+		return (EINVAL);
+
+	/*
+	 * Find out the requested entry and remove
+	 * it from the list.
+	 */
+	envname_len = strlen(env);
+	for (entry = envlist->el_entries.lh_first; entry != NULL;
+	    entry = entry->ev_link.le_next) {
+		if (strncmp(entry->ev_var, env, envname_len) == 0)
+			break;
+	}
+	if (entry != NULL) {
+		QLIST_REMOVE(entry, ev_link);
+		free((char *)entry->ev_var);
+		free(entry);
+
+		envlist->el_count--;
+	}
+	return (0);
+}
+
+/*
+ * Returns given envlist as array of strings (in same form that
+ * global variable environ is).  Caller must free returned memory
+ * by calling free(3) for each element and for the array.  Returned
+ * array and given envlist are not related (no common references).
+ *
+ * If caller provides count pointer, number of items in array is
+ * stored there.  In case of error, NULL is returned and no memory
+ * is allocated.
+ */
+char **
+envlist_to_environ(const envlist_t *envlist, size_t *count)
+{
+	struct envlist_entry *entry;
+	char **env, **penv;
+
+	penv = env = malloc((envlist->el_count + 1) * sizeof (char *));
+	if (env == NULL)
+		return (NULL);
+
+	for (entry = envlist->el_entries.lh_first; entry != NULL;
+	    entry = entry->ev_link.le_next) {
+		*(penv++) = strdup(entry->ev_var);
+	}
+	*penv = NULL; /* NULL terminate the list */
+
+	if (count != NULL)
+		*count = envlist->el_count;
+
+	return (env);
+}
diff --git a/qemu-0.15.x/envlist.h b/qemu-0.15.x/envlist.h
new file mode 100644
index 0000000..b9addcc
--- /dev/null
+++ b/qemu-0.15.x/envlist.h
@@ -0,0 +1,22 @@
+#ifndef ENVLIST_H
+#define ENVLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct envlist envlist_t;
+
+envlist_t *envlist_create(void);
+void envlist_free(envlist_t *);
+int envlist_setenv(envlist_t *, const char *);
+int envlist_unsetenv(envlist_t *, const char *);
+int envlist_parse_set(envlist_t *, const char *);
+int envlist_parse_unset(envlist_t *, const char *);
+char **envlist_to_environ(const envlist_t *, size_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ENVLIST_H */
diff --git a/qemu-0.15.x/error.c b/qemu-0.15.x/error.c
new file mode 100644
index 0000000..74d7398
--- /dev/null
+++ b/qemu-0.15.x/error.c
@@ -0,0 +1,141 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "error.h"
+#include "error_int.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+struct Error
+{
+    QDict *obj;
+    const char *fmt;
+    char *msg;
+};
+
+void error_set(Error **errp, const char *fmt, ...)
+{
+    Error *err;
+    va_list ap;
+
+    if (errp == NULL) {
+        return;
+    }
+
+    err = qemu_mallocz(sizeof(*err));
+
+    va_start(ap, fmt);
+    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+    va_end(ap);
+    err->fmt = fmt;
+
+    *errp = err;
+}
+
+bool error_is_set(Error **errp)
+{
+    return (errp && *errp);
+}
+
+const char *error_get_pretty(Error *err)
+{
+    if (err->msg == NULL) {
+        QString *str;
+        str = qerror_format(err->fmt, err->obj);
+        err->msg = qemu_strdup(qstring_get_str(str));
+        QDECREF(str);
+    }
+
+    return err->msg;
+}
+
+const char *error_get_field(Error *err, const char *field)
+{
+    if (strcmp(field, "class") == 0) {
+        return qdict_get_str(err->obj, field);
+    } else {
+        QDict *dict = qdict_get_qdict(err->obj, "data");
+        return qdict_get_str(dict, field);
+    }
+}
+
+QDict *error_get_data(Error *err)
+{
+    QDict *data = qdict_get_qdict(err->obj, "data");
+    QINCREF(data);
+    return data;
+}
+
+void error_set_field(Error *err, const char *field, const char *value)
+{
+    QDict *dict = qdict_get_qdict(err->obj, "data");
+    return qdict_put(dict, field, qstring_from_str(value));
+}
+
+void error_free(Error *err)
+{
+    if (err) {
+        QDECREF(err->obj);
+        qemu_free(err->msg);
+        qemu_free(err);
+    }
+}
+
+bool error_is_type(Error *err, const char *fmt)
+{
+    const char *error_class;
+    char *ptr;
+    char *end;
+
+    ptr = strstr(fmt, "'class': '");
+    assert(ptr != NULL);
+    ptr += strlen("'class': '");
+
+    end = strchr(ptr, '\'');
+    assert(end != NULL);
+
+    error_class = error_get_field(err, "class");
+    if (strlen(error_class) != end - ptr) {
+        return false;
+    }
+
+    return strncmp(ptr, error_class, end - ptr) == 0;
+}
+
+void error_propagate(Error **dst_err, Error *local_err)
+{
+    if (dst_err) {
+        *dst_err = local_err;
+    } else if (local_err) {
+        error_free(local_err);
+    }
+}
+
+QObject *error_get_qobject(Error *err)
+{
+    QINCREF(err->obj);
+    return QOBJECT(err->obj);
+}
+
+void error_set_qobject(Error **errp, QObject *obj)
+{
+    Error *err;
+    if (errp == NULL) {
+        return;
+    }
+    err = qemu_mallocz(sizeof(*err));
+    err->obj = qobject_to_qdict(obj);
+    qobject_incref(obj);
+
+    *errp = err;
+}
diff --git a/qemu-0.15.x/error.h b/qemu-0.15.x/error.h
new file mode 100644
index 0000000..6361f40
--- /dev/null
+++ b/qemu-0.15.x/error.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include "compiler.h"
+#include <stdbool.h>
+
+/**
+ * A class representing internal errors within QEMU.  An error has a string
+ * typename and optionally a set of named string parameters.
+ */
+typedef struct Error Error;
+
+/**
+ * Set an indirect pointer to an error given a printf-style format parameter.
+ * Currently, qerror.h defines these error formats.  This function is not
+ * meant to be used outside of QEMU.
+ */
+void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+/**
+ * Returns true if an indirect pointer to an error is pointing to a valid
+ * error object.
+ */
+bool error_is_set(Error **err);
+
+/**
+ * Get a human readable representation of an error object.
+ */
+const char *error_get_pretty(Error *err);
+
+/**
+ * Get an individual named error field.
+ */
+const char *error_get_field(Error *err, const char *field);
+
+/**
+ * Get an individual named error field.
+ */
+void error_set_field(Error *err, const char *field, const char *value);
+
+/**
+ * Propagate an error to an indirect pointer to an error.  This function will
+ * always transfer ownership of the error reference and handles the case where
+ * dst_err is NULL correctly.
+ */
+void error_propagate(Error **dst_err, Error *local_err);
+
+/**
+ * Free an error object.
+ */
+void error_free(Error *err);
+
+/**
+ * Determine if an error is of a speific type (based on the qerror format).
+ * Non-QEMU users should get the `class' field to identify the error type.
+ */
+bool error_is_type(Error *err, const char *fmt);
+
+#endif
diff --git a/qemu-0.15.x/error_int.h b/qemu-0.15.x/error_int.h
new file mode 100644
index 0000000..5e39424
--- /dev/null
+++ b/qemu-0.15.x/error_int.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QEMU_ERROR_INT_H
+#define QEMU_ERROR_INT_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+/**
+ * Internal QEMU functions for working with Error.
+ *
+ * These are used to convert QErrors to Errors
+ */
+QDict *error_get_data(Error *err);
+QObject *error_get_qobject(Error *err);
+void error_set_qobject(Error **errp, QObject *obj);
+  
+#endif
diff --git a/qemu-0.15.x/exec-all.h b/qemu-0.15.x/exec-all.h
new file mode 100644
index 0000000..9b8d62c
--- /dev/null
+++ b/qemu-0.15.x/exec-all.h
@@ -0,0 +1,347 @@
+/*
+ * internal execution defines for qemu
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _EXEC_ALL_H_
+#define _EXEC_ALL_H_
+
+#include "qemu-common.h"
+
+/* allow to see translation results - the slowdown should be negligible, so we leave it */
+#define DEBUG_DISAS
+
+/* Page tracking code uses ram addresses in system mode, and virtual
+   addresses in userspace mode.  Define tb_page_addr_t to be an appropriate
+   type.  */
+#if defined(CONFIG_USER_ONLY)
+typedef abi_ulong tb_page_addr_t;
+#else
+typedef ram_addr_t tb_page_addr_t;
+#endif
+
+/* is_jmp field values */
+#define DISAS_NEXT    0 /* next instruction can be analyzed */
+#define DISAS_JUMP    1 /* only pc was modified dynamically */
+#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP 3 /* only pc was modified statically */
+
+struct TranslationBlock;
+typedef struct TranslationBlock TranslationBlock;
+
+/* XXX: make safe guess about sizes */
+#define MAX_OP_PER_INSTR 208
+
+#if HOST_LONG_BITS == 32
+#define MAX_OPC_PARAM_PER_ARG 2
+#else
+#define MAX_OPC_PARAM_PER_ARG 1
+#endif
+#define MAX_OPC_PARAM_IARGS 4
+#define MAX_OPC_PARAM_OARGS 1
+#define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS)
+
+/* A Call op needs up to 4 + 2N parameters on 32-bit archs,
+ * and up to 4 + N parameters on 64-bit archs
+ * (N = number of input arguments + output arguments).  */
+#define MAX_OPC_PARAM (4 + (MAX_OPC_PARAM_PER_ARG * MAX_OPC_PARAM_ARGS))
+#define OPC_BUF_SIZE 640
+#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
+
+/* Maximum size a TCG op can expand to.  This is complicated because a
+   single op may require several host instructions and register reloads.
+   For now take a wild guess at 192 bytes, which should allow at least
+   a couple of fixup instructions per argument.  */
+#define TCG_MAX_OP_SIZE 192
+
+#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM)
+
+extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
+extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
+extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
+
+#include "qemu-log.h"
+
+void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
+void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
+void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb,
+                          int pc_pos);
+
+void cpu_gen_init(void);
+int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
+                 int *gen_code_size_ptr);
+int cpu_restore_state(struct TranslationBlock *tb,
+                      CPUState *env, unsigned long searched_pc);
+void cpu_resume_from_signal(CPUState *env1, void *puc);
+void cpu_io_recompile(CPUState *env, void *retaddr);
+TranslationBlock *tb_gen_code(CPUState *env, 
+                              target_ulong pc, target_ulong cs_base, int flags,
+                              int cflags);
+void cpu_exec_init(CPUState *env);
+void QEMU_NORETURN cpu_loop_exit(CPUState *env1);
+int page_unprotect(target_ulong address, unsigned long pc, void *puc);
+void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
+                                   int is_cpu_write_access);
+void tlb_flush_page(CPUState *env, target_ulong addr);
+void tlb_flush(CPUState *env, int flush_global);
+#if !defined(CONFIG_USER_ONLY)
+void tlb_set_page(CPUState *env, target_ulong vaddr,
+                  target_phys_addr_t paddr, int prot,
+                  int mmu_idx, target_ulong size);
+#endif
+
+#define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */
+
+#define CODE_GEN_PHYS_HASH_BITS     15
+#define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS)
+
+#define MIN_CODE_GEN_BUFFER_SIZE     (1024 * 1024)
+
+/* estimated block size for TB allocation */
+/* XXX: use a per code average code fragment size and modulate it
+   according to the host CPU */
+#if defined(CONFIG_SOFTMMU)
+#define CODE_GEN_AVG_BLOCK_SIZE 128
+#else
+#define CODE_GEN_AVG_BLOCK_SIZE 64
+#endif
+
+#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__)
+#define USE_DIRECT_JUMP
+#endif
+
+struct TranslationBlock {
+    target_ulong pc;   /* simulated PC corresponding to this block (EIP + CS base) */
+    target_ulong cs_base; /* CS base for this block */
+    uint64_t flags; /* flags defining in which context the code was generated */
+    uint16_t size;      /* size of target code for this block (1 <=
+                           size <= TARGET_PAGE_SIZE) */
+    uint16_t cflags;    /* compile flags */
+#define CF_COUNT_MASK  0x7fff
+#define CF_LAST_IO     0x8000 /* Last insn may be an IO access.  */
+
+    uint8_t *tc_ptr;    /* pointer to the translated code */
+    /* next matching tb for physical address. */
+    struct TranslationBlock *phys_hash_next;
+    /* first and second physical page containing code. The lower bit
+       of the pointer tells the index in page_next[] */
+    struct TranslationBlock *page_next[2];
+    tb_page_addr_t page_addr[2];
+
+    /* the following data are used to directly call another TB from
+       the code of this one. */
+    uint16_t tb_next_offset[2]; /* offset of original jump target */
+#ifdef USE_DIRECT_JUMP
+    uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
+#else
+    unsigned long tb_next[2]; /* address of jump generated code */
+#endif
+    /* list of TBs jumping to this one. This is a circular list using
+       the two least significant bits of the pointers to tell what is
+       the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
+       jmp_first */
+    struct TranslationBlock *jmp_next[2];
+    struct TranslationBlock *jmp_first;
+    uint32_t icount;
+};
+
+static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
+{
+    target_ulong tmp;
+    tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
+    return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK;
+}
+
+static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
+{
+    target_ulong tmp;
+    tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
+    return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK)
+	    | (tmp & TB_JMP_ADDR_MASK));
+}
+
+static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)
+{
+    return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1);
+}
+
+void tb_free(TranslationBlock *tb);
+void tb_flush(CPUState *env);
+void tb_link_page(TranslationBlock *tb,
+                  tb_page_addr_t phys_pc, tb_page_addr_t phys_page2);
+void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
+
+extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
+
+#if defined(USE_DIRECT_JUMP)
+
+#if defined(_ARCH_PPC)
+void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
+#define tb_set_jmp_target1 ppc_tb_set_jmp_target
+#elif defined(__i386__) || defined(__x86_64__)
+static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
+{
+    /* patch the branch destination */
+    *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
+    /* no need to flush icache explicitly */
+}
+#elif defined(__arm__)
+static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
+{
+#if !QEMU_GNUC_PREREQ(4, 1)
+    register unsigned long _beg __asm ("a1");
+    register unsigned long _end __asm ("a2");
+    register unsigned long _flg __asm ("a3");
+#endif
+
+    /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */
+    *(uint32_t *)jmp_addr =
+        (*(uint32_t *)jmp_addr & ~0xffffff)
+        | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff);
+
+#if QEMU_GNUC_PREREQ(4, 1)
+    __builtin___clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
+#else
+    /* flush icache */
+    _beg = jmp_addr;
+    _end = jmp_addr + 4;
+    _flg = 0;
+    __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
+#endif
+}
+#endif
+
+static inline void tb_set_jmp_target(TranslationBlock *tb,
+                                     int n, unsigned long addr)
+{
+    unsigned long offset;
+
+    offset = tb->tb_jmp_offset[n];
+    tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
+}
+
+#else
+
+/* set the jump target */
+static inline void tb_set_jmp_target(TranslationBlock *tb,
+                                     int n, unsigned long addr)
+{
+    tb->tb_next[n] = addr;
+}
+
+#endif
+
+static inline void tb_add_jump(TranslationBlock *tb, int n,
+                               TranslationBlock *tb_next)
+{
+    /* NOTE: this test is only needed for thread safety */
+    if (!tb->jmp_next[n]) {
+        /* patch the native jump address */
+        tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
+
+        /* add in TB jmp circular list */
+        tb->jmp_next[n] = tb_next->jmp_first;
+        tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
+    }
+}
+
+TranslationBlock *tb_find_pc(unsigned long pc_ptr);
+
+#include "qemu-lock.h"
+
+extern spinlock_t tb_lock;
+
+extern int tb_invalidated_flag;
+
+#if !defined(CONFIG_USER_ONLY)
+
+extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr);
+
+#include "softmmu_defs.h"
+
+#define ACCESS_TYPE (NB_MMU_MODES + 1)
+#define MEMSUFFIX _code
+#define env cpu_single_env
+
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#undef env
+
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
+{
+    return addr;
+}
+#else
+/* NOTE: this function can trigger an exception */
+/* NOTE2: the returned address is not exactly the physical address: it
+   is the offset relative to phys_ram_base */
+static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
+{
+    int mmu_idx, page_index, pd;
+    void *p;
+
+    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    mmu_idx = cpu_mmu_index(env1);
+    if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
+                 (addr & TARGET_PAGE_MASK))) {
+        ldub_code(addr);
+    }
+    pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
+    if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
+        cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
+#else
+        cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
+#endif
+    }
+    p = (void *)(unsigned long)addr
+        + env1->tlb_table[mmu_idx][page_index].addend;
+    return qemu_ram_addr_from_host_nofail(p);
+}
+#endif
+
+typedef void (CPUDebugExcpHandler)(CPUState *env);
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
+
+/* vl.c */
+extern int singlestep;
+
+/* cpu-exec.c */
+extern volatile sig_atomic_t exit_request;
+
+#endif
diff --git a/qemu-0.15.x/exec.c b/qemu-0.15.x/exec.c
new file mode 100644
index 0000000..2160ded
--- /dev/null
+++ b/qemu-0.15.x/exec.c
@@ -0,0 +1,4748 @@
+/*
+ *  virtual page mapping and translated block handling
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+
+#include "qemu-common.h"
+#include "cpu.h"
+#include "tcg.h"
+#include "hw/hw.h"
+#include "hw/qdev.h"
+#include "osdep.h"
+#include "kvm.h"
+#include "hw/xen.h"
+#include "qemu-timer.h"
+#if defined(CONFIG_USER_ONLY)
+#include <qemu.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/param.h>
+#if __FreeBSD_version >= 700104
+#define HAVE_KINFO_GETVMMAP
+#define sigqueue sigqueue_freebsd  /* avoid redefinition */
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <machine/profile.h>
+#define _KERNEL
+#include <sys/user.h>
+#undef _KERNEL
+#undef sigqueue
+#include <libutil.h>
+#endif
+#endif
+#else /* !CONFIG_USER_ONLY */
+#include "xen-mapcache.h"
+#include "trace.h"
+#endif
+
+//#define DEBUG_TB_INVALIDATE
+//#define DEBUG_FLUSH
+//#define DEBUG_TLB
+//#define DEBUG_UNASSIGNED
+
+/* make various TB consistency checks */
+//#define DEBUG_TB_CHECK
+//#define DEBUG_TLB_CHECK
+
+//#define DEBUG_IOPORT
+//#define DEBUG_SUBPAGE
+
+#if !defined(CONFIG_USER_ONLY)
+/* TB consistency checks only implemented for usermode emulation.  */
+#undef DEBUG_TB_CHECK
+#endif
+
+#define SMC_BITMAP_USE_THRESHOLD 10
+
+static TranslationBlock *tbs;
+static int code_gen_max_blocks;
+TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
+static int nb_tbs;
+/* any access to the tbs or the page table must use this lock */
+spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
+
+#if defined(__arm__) || defined(__sparc_v9__)
+/* The prologue must be reachable with a direct jump. ARM and Sparc64
+ have limited branch ranges (possibly also PPC) so place it in a
+ section close to code segment. */
+#define code_gen_section                                \
+    __attribute__((__section__(".gen_code")))           \
+    __attribute__((aligned (32)))
+#elif defined(_WIN32)
+/* Maximum alignment for Win32 is 16. */
+#define code_gen_section                                \
+    __attribute__((aligned (16)))
+#else
+#define code_gen_section                                \
+    __attribute__((aligned (32)))
+#endif
+
+uint8_t code_gen_prologue[1024] code_gen_section;
+static uint8_t *code_gen_buffer;
+static unsigned long code_gen_buffer_size;
+/* threshold to flush the translated code buffer */
+static unsigned long code_gen_buffer_max_size;
+static uint8_t *code_gen_ptr;
+
+#if !defined(CONFIG_USER_ONLY)
+int phys_ram_fd;
+static int in_migration;
+
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+#endif
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+   cpu_exec() */
+CPUState *cpu_single_env;
+/* 0 = Do not count executed instructions.
+   1 = Precise instruction counting.
+   2 = Adaptive rate instruction counting.  */
+int use_icount = 0;
+/* Current instruction counter.  While executing translated code this may
+   include some instructions that have not yet been executed.  */
+int64_t qemu_icount;
+
+typedef struct PageDesc {
+    /* list of TBs intersecting this ram page */
+    TranslationBlock *first_tb;
+    /* in order to optimize self modifying code, we count the number
+       of lookups we do to a given page to use a bitmap */
+    unsigned int code_write_count;
+    uint8_t *code_bitmap;
+#if defined(CONFIG_USER_ONLY)
+    unsigned long flags;
+#endif
+} PageDesc;
+
+/* In system mode we want L1_MAP to be based on ram offsets,
+   while in user mode we want it to be based on virtual addresses.  */
+#if !defined(CONFIG_USER_ONLY)
+#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS
+# define L1_MAP_ADDR_SPACE_BITS  HOST_LONG_BITS
+#else
+# define L1_MAP_ADDR_SPACE_BITS  TARGET_PHYS_ADDR_SPACE_BITS
+#endif
+#else
+# define L1_MAP_ADDR_SPACE_BITS  TARGET_VIRT_ADDR_SPACE_BITS
+#endif
+
+/* Size of the L2 (and L3, etc) page tables.  */
+#define L2_BITS 10
+#define L2_SIZE (1 << L2_BITS)
+
+/* The bits remaining after N lower levels of page tables.  */
+#define P_L1_BITS_REM \
+    ((TARGET_PHYS_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)
+#define V_L1_BITS_REM \
+    ((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)
+
+/* Size of the L1 page table.  Avoid silly small sizes.  */
+#if P_L1_BITS_REM < 4
+#define P_L1_BITS  (P_L1_BITS_REM + L2_BITS)
+#else
+#define P_L1_BITS  P_L1_BITS_REM
+#endif
+
+#if V_L1_BITS_REM < 4
+#define V_L1_BITS  (V_L1_BITS_REM + L2_BITS)
+#else
+#define V_L1_BITS  V_L1_BITS_REM
+#endif
+
+#define P_L1_SIZE  ((target_phys_addr_t)1 << P_L1_BITS)
+#define V_L1_SIZE  ((target_ulong)1 << V_L1_BITS)
+
+#define P_L1_SHIFT (TARGET_PHYS_ADDR_SPACE_BITS - TARGET_PAGE_BITS - P_L1_BITS)
+#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
+
+unsigned long qemu_real_host_page_size;
+unsigned long qemu_host_page_bits;
+unsigned long qemu_host_page_size;
+unsigned long qemu_host_page_mask;
+
+/* This is a multi-level map on the virtual address space.
+   The bottom level has pointers to PageDesc.  */
+static void *l1_map[V_L1_SIZE];
+
+#if !defined(CONFIG_USER_ONLY)
+typedef struct PhysPageDesc {
+    /* offset in host memory of the page + io_index in the low bits */
+    ram_addr_t phys_offset;
+    ram_addr_t region_offset;
+} PhysPageDesc;
+
+/* This is a multi-level map on the physical address space.
+   The bottom level has pointers to PhysPageDesc.  */
+static void *l1_phys_map[P_L1_SIZE];
+
+static void io_mem_init(void);
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static char io_mem_used[IO_MEM_NB_ENTRIES];
+static int io_mem_watch;
+#endif
+
+/* log support */
+#ifdef WIN32
+static const char *logfilename = "qemu.log";
+#else
+static const char *logfilename = "/tmp/qemu.log";
+#endif
+FILE *logfile;
+int loglevel;
+static int log_append = 0;
+
+/* statistics */
+#if !defined(CONFIG_USER_ONLY)
+static int tlb_flush_count;
+#endif
+static int tb_flush_count;
+static int tb_phys_invalidate_count;
+
+#ifdef _WIN32
+static void map_exec(void *addr, long size)
+{
+    DWORD old_protect;
+    VirtualProtect(addr, size,
+                   PAGE_EXECUTE_READWRITE, &old_protect);
+    
+}
+#else
+static void map_exec(void *addr, long size)
+{
+    unsigned long start, end, page_size;
+    
+    page_size = getpagesize();
+    start = (unsigned long)addr;
+    start &= ~(page_size - 1);
+    
+    end = (unsigned long)addr + size;
+    end += page_size - 1;
+    end &= ~(page_size - 1);
+    
+    mprotect((void *)start, end - start,
+             PROT_READ | PROT_WRITE | PROT_EXEC);
+}
+#endif
+
+static void page_init(void)
+{
+    /* NOTE: we can always suppose that qemu_host_page_size >=
+       TARGET_PAGE_SIZE */
+#ifdef _WIN32
+    {
+        SYSTEM_INFO system_info;
+
+        GetSystemInfo(&system_info);
+        qemu_real_host_page_size = system_info.dwPageSize;
+    }
+#else
+    qemu_real_host_page_size = getpagesize();
+#endif
+    if (qemu_host_page_size == 0)
+        qemu_host_page_size = qemu_real_host_page_size;
+    if (qemu_host_page_size < TARGET_PAGE_SIZE)
+        qemu_host_page_size = TARGET_PAGE_SIZE;
+    qemu_host_page_bits = 0;
+    while ((1 << qemu_host_page_bits) < qemu_host_page_size)
+        qemu_host_page_bits++;
+    qemu_host_page_mask = ~(qemu_host_page_size - 1);
+
+#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
+    {
+#ifdef HAVE_KINFO_GETVMMAP
+        struct kinfo_vmentry *freep;
+        int i, cnt;
+
+        freep = kinfo_getvmmap(getpid(), &cnt);
+        if (freep) {
+            mmap_lock();
+            for (i = 0; i < cnt; i++) {
+                unsigned long startaddr, endaddr;
+
+                startaddr = freep[i].kve_start;
+                endaddr = freep[i].kve_end;
+                if (h2g_valid(startaddr)) {
+                    startaddr = h2g(startaddr) & TARGET_PAGE_MASK;
+
+                    if (h2g_valid(endaddr)) {
+                        endaddr = h2g(endaddr);
+                        page_set_flags(startaddr, endaddr, PAGE_RESERVED);
+                    } else {
+#if TARGET_ABI_BITS <= L1_MAP_ADDR_SPACE_BITS
+                        endaddr = ~0ul;
+                        page_set_flags(startaddr, endaddr, PAGE_RESERVED);
+#endif
+                    }
+                }
+            }
+            free(freep);
+            mmap_unlock();
+        }
+#else
+        FILE *f;
+
+        last_brk = (unsigned long)sbrk(0);
+
+        f = fopen("/compat/linux/proc/self/maps", "r");
+        if (f) {
+            mmap_lock();
+
+            do {
+                unsigned long startaddr, endaddr;
+                int n;
+
+                n = fscanf (f, "%lx-%lx %*[^\n]\n", &startaddr, &endaddr);
+
+                if (n == 2 && h2g_valid(startaddr)) {
+                    startaddr = h2g(startaddr) & TARGET_PAGE_MASK;
+
+                    if (h2g_valid(endaddr)) {
+                        endaddr = h2g(endaddr);
+                    } else {
+                        endaddr = ~0ul;
+                    }
+                    page_set_flags(startaddr, endaddr, PAGE_RESERVED);
+                }
+            } while (!feof(f));
+
+            fclose(f);
+            mmap_unlock();
+        }
+#endif
+    }
+#endif
+}
+
+static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
+{
+    PageDesc *pd;
+    void **lp;
+    int i;
+
+#if defined(CONFIG_USER_ONLY)
+    /* We can't use qemu_malloc because it may recurse into a locked mutex. */
+# define ALLOC(P, SIZE)                                 \
+    do {                                                \
+        P = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,    \
+                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);   \
+    } while (0)
+#else
+# define ALLOC(P, SIZE) \
+    do { P = qemu_mallocz(SIZE); } while (0)
+#endif
+
+    /* Level 1.  Always allocated.  */
+    lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));
+
+    /* Level 2..N-1.  */
+    for (i = V_L1_SHIFT / L2_BITS - 1; i > 0; i--) {
+        void **p = *lp;
+
+        if (p == NULL) {
+            if (!alloc) {
+                return NULL;
+            }
+            ALLOC(p, sizeof(void *) * L2_SIZE);
+            *lp = p;
+        }
+
+        lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1));
+    }
+
+    pd = *lp;
+    if (pd == NULL) {
+        if (!alloc) {
+            return NULL;
+        }
+        ALLOC(pd, sizeof(PageDesc) * L2_SIZE);
+        *lp = pd;
+    }
+
+#undef ALLOC
+
+    return pd + (index & (L2_SIZE - 1));
+}
+
+static inline PageDesc *page_find(tb_page_addr_t index)
+{
+    return page_find_alloc(index, 0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
+{
+    PhysPageDesc *pd;
+    void **lp;
+    int i;
+
+    /* Level 1.  Always allocated.  */
+    lp = l1_phys_map + ((index >> P_L1_SHIFT) & (P_L1_SIZE - 1));
+
+    /* Level 2..N-1.  */
+    for (i = P_L1_SHIFT / L2_BITS - 1; i > 0; i--) {
+        void **p = *lp;
+        if (p == NULL) {
+            if (!alloc) {
+                return NULL;
+            }
+            *lp = p = qemu_mallocz(sizeof(void *) * L2_SIZE);
+        }
+        lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1));
+    }
+
+    pd = *lp;
+    if (pd == NULL) {
+        int i;
+
+        if (!alloc) {
+            return NULL;
+        }
+
+        *lp = pd = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
+
+        for (i = 0; i < L2_SIZE; i++) {
+            pd[i].phys_offset = IO_MEM_UNASSIGNED;
+            pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
+        }
+    }
+
+    return pd + (index & (L2_SIZE - 1));
+}
+
+static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
+{
+    return phys_page_find_alloc(index, 0);
+}
+
+static void tlb_protect_code(ram_addr_t ram_addr);
+static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
+                                    target_ulong vaddr);
+#define mmap_lock() do { } while(0)
+#define mmap_unlock() do { } while(0)
+#endif
+
+#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
+
+#if defined(CONFIG_USER_ONLY)
+/* Currently it is not recommended to allocate big chunks of data in
+   user mode. It will change when a dedicated libc will be used */
+#define USE_STATIC_CODE_GEN_BUFFER
+#endif
+
+#ifdef USE_STATIC_CODE_GEN_BUFFER
+static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
+               __attribute__((aligned (CODE_GEN_ALIGN)));
+#endif
+
+static void code_gen_alloc(unsigned long tb_size)
+{
+#ifdef USE_STATIC_CODE_GEN_BUFFER
+    code_gen_buffer = static_code_gen_buffer;
+    code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
+    map_exec(code_gen_buffer, code_gen_buffer_size);
+#else
+    code_gen_buffer_size = tb_size;
+    if (code_gen_buffer_size == 0) {
+#if defined(CONFIG_USER_ONLY)
+        /* in user mode, phys_ram_size is not meaningful */
+        code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
+#else
+        /* XXX: needs adjustments */
+        code_gen_buffer_size = (unsigned long)(ram_size / 4);
+#endif
+    }
+    if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
+        code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
+    /* The code gen buffer location may have constraints depending on
+       the host cpu and OS */
+#if defined(__linux__) 
+    {
+        int flags;
+        void *start = NULL;
+
+        flags = MAP_PRIVATE | MAP_ANONYMOUS;
+#if defined(__x86_64__)
+        flags |= MAP_32BIT;
+        /* Cannot map more than that */
+        if (code_gen_buffer_size > (800 * 1024 * 1024))
+            code_gen_buffer_size = (800 * 1024 * 1024);
+#elif defined(__sparc_v9__)
+        // Map the buffer below 2G, so we can use direct calls and branches
+        flags |= MAP_FIXED;
+        start = (void *) 0x60000000UL;
+        if (code_gen_buffer_size > (512 * 1024 * 1024))
+            code_gen_buffer_size = (512 * 1024 * 1024);
+#elif defined(__arm__)
+        /* Map the buffer below 32M, so we can use direct calls and branches */
+        flags |= MAP_FIXED;
+        start = (void *) 0x01000000UL;
+        if (code_gen_buffer_size > 16 * 1024 * 1024)
+            code_gen_buffer_size = 16 * 1024 * 1024;
+#elif defined(__s390x__)
+        /* Map the buffer so that we can use direct calls and branches.  */
+        /* We have a +- 4GB range on the branches; leave some slop.  */
+        if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) {
+            code_gen_buffer_size = 3ul * 1024 * 1024 * 1024;
+        }
+        start = (void *)0x90000000UL;
+#endif
+        code_gen_buffer = mmap(start, code_gen_buffer_size,
+                               PROT_WRITE | PROT_READ | PROT_EXEC,
+                               flags, -1, 0);
+        if (code_gen_buffer == MAP_FAILED) {
+            fprintf(stderr, "Could not allocate dynamic translator buffer\n");
+            exit(1);
+        }
+    }
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
+    || defined(__DragonFly__) || defined(__OpenBSD__)
+    {
+        int flags;
+        void *addr = NULL;
+        flags = MAP_PRIVATE | MAP_ANONYMOUS;
+#if defined(__x86_64__)
+        /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
+         * 0x40000000 is free */
+        flags |= MAP_FIXED;
+        addr = (void *)0x40000000;
+        /* Cannot map more than that */
+        if (code_gen_buffer_size > (800 * 1024 * 1024))
+            code_gen_buffer_size = (800 * 1024 * 1024);
+#elif defined(__sparc_v9__)
+        // Map the buffer below 2G, so we can use direct calls and branches
+        flags |= MAP_FIXED;
+        addr = (void *) 0x60000000UL;
+        if (code_gen_buffer_size > (512 * 1024 * 1024)) {
+            code_gen_buffer_size = (512 * 1024 * 1024);
+        }
+#endif
+        code_gen_buffer = mmap(addr, code_gen_buffer_size,
+                               PROT_WRITE | PROT_READ | PROT_EXEC, 
+                               flags, -1, 0);
+        if (code_gen_buffer == MAP_FAILED) {
+            fprintf(stderr, "Could not allocate dynamic translator buffer\n");
+            exit(1);
+        }
+    }
+#else
+    code_gen_buffer = qemu_malloc(code_gen_buffer_size);
+    map_exec(code_gen_buffer, code_gen_buffer_size);
+#endif
+#endif /* !USE_STATIC_CODE_GEN_BUFFER */
+    map_exec(code_gen_prologue, sizeof(code_gen_prologue));
+    code_gen_buffer_max_size = code_gen_buffer_size -
+        (TCG_MAX_OP_SIZE * OPC_BUF_SIZE);
+    code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
+    tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
+}
+
+/* Must be called before using the QEMU cpus. 'tb_size' is the size
+   (in bytes) allocated to the translation buffer. Zero means default
+   size. */
+void cpu_exec_init_all(unsigned long tb_size)
+{
+    cpu_gen_init();
+    code_gen_alloc(tb_size);
+    code_gen_ptr = code_gen_buffer;
+    page_init();
+#if !defined(CONFIG_USER_ONLY)
+    io_mem_init();
+#endif
+#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
+    /* There's no guest base to take into account, so go ahead and
+       initialize the prologue now.  */
+    tcg_prologue_init(&tcg_ctx);
+#endif
+}
+
+#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
+
+static int cpu_common_post_load(void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+
+    /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
+       version_id is increased. */
+    env->interrupt_request &= ~0x01;
+    tlb_flush(env, 1);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_cpu_common = {
+    .name = "cpu_common",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = cpu_common_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(halted, CPUState),
+        VMSTATE_UINT32(interrupt_request, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+#endif
+
+CPUState *qemu_get_cpu(int cpu)
+{
+    CPUState *env = first_cpu;
+
+    while (env) {
+        if (env->cpu_index == cpu)
+            break;
+        env = env->next_cpu;
+    }
+
+    return env;
+}
+
+void cpu_exec_init(CPUState *env)
+{
+    CPUState **penv;
+    int cpu_index;
+
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_lock();
+#endif
+    env->next_cpu = NULL;
+    penv = &first_cpu;
+    cpu_index = 0;
+    while (*penv != NULL) {
+        penv = &(*penv)->next_cpu;
+        cpu_index++;
+    }
+    env->cpu_index = cpu_index;
+    env->numa_node = 0;
+    QTAILQ_INIT(&env->breakpoints);
+    QTAILQ_INIT(&env->watchpoints);
+#ifndef CONFIG_USER_ONLY
+    env->thread_id = qemu_get_thread_id();
+#endif
+    *penv = env;
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_unlock();
+#endif
+#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
+    vmstate_register(NULL, cpu_index, &vmstate_cpu_common, env);
+    register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION,
+                    cpu_save, cpu_load, env);
+#endif
+}
+
+/* Allocate a new translation block. Flush the translation buffer if
+   too many translation blocks or too much generated code. */
+static TranslationBlock *tb_alloc(target_ulong pc)
+{
+    TranslationBlock *tb;
+
+    if (nb_tbs >= code_gen_max_blocks ||
+        (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
+        return NULL;
+    tb = &tbs[nb_tbs++];
+    tb->pc = pc;
+    tb->cflags = 0;
+    return tb;
+}
+
+void tb_free(TranslationBlock *tb)
+{
+    /* In practice this is mostly used for single use temporary TB
+       Ignore the hard cases and just back up if this TB happens to
+       be the last one generated.  */
+    if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
+        code_gen_ptr = tb->tc_ptr;
+        nb_tbs--;
+    }
+}
+
+static inline void invalidate_page_bitmap(PageDesc *p)
+{
+    if (p->code_bitmap) {
+        qemu_free(p->code_bitmap);
+        p->code_bitmap = NULL;
+    }
+    p->code_write_count = 0;
+}
+
+/* Set to NULL all the 'first_tb' fields in all PageDescs. */
+
+static void page_flush_tb_1 (int level, void **lp)
+{
+    int i;
+
+    if (*lp == NULL) {
+        return;
+    }
+    if (level == 0) {
+        PageDesc *pd = *lp;
+        for (i = 0; i < L2_SIZE; ++i) {
+            pd[i].first_tb = NULL;
+            invalidate_page_bitmap(pd + i);
+        }
+    } else {
+        void **pp = *lp;
+        for (i = 0; i < L2_SIZE; ++i) {
+            page_flush_tb_1 (level - 1, pp + i);
+        }
+    }
+}
+
+static void page_flush_tb(void)
+{
+    int i;
+    for (i = 0; i < V_L1_SIZE; i++) {
+        page_flush_tb_1(V_L1_SHIFT / L2_BITS - 1, l1_map + i);
+    }
+}
+
+/* flush all the translation blocks */
+/* XXX: tb_flush is currently not thread safe */
+void tb_flush(CPUState *env1)
+{
+    CPUState *env;
+#if defined(DEBUG_FLUSH)
+    printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
+           (unsigned long)(code_gen_ptr - code_gen_buffer),
+           nb_tbs, nb_tbs > 0 ?
+           ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
+#endif
+    if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
+        cpu_abort(env1, "Internal error: code buffer overflow\n");
+
+    nb_tbs = 0;
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
+    }
+
+    memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
+    page_flush_tb();
+
+    code_gen_ptr = code_gen_buffer;
+    /* XXX: flush processor icache at this point if cache flush is
+       expensive */
+    tb_flush_count++;
+}
+
+#ifdef DEBUG_TB_CHECK
+
+static void tb_invalidate_check(target_ulong address)
+{
+    TranslationBlock *tb;
+    int i;
+    address &= TARGET_PAGE_MASK;
+    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
+        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
+            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
+                  address >= tb->pc + tb->size)) {
+                printf("ERROR invalidate: address=" TARGET_FMT_lx
+                       " PC=%08lx size=%04x\n",
+                       address, (long)tb->pc, tb->size);
+            }
+        }
+    }
+}
+
+/* verify that all the pages have correct rights for code */
+static void tb_page_check(void)
+{
+    TranslationBlock *tb;
+    int i, flags1, flags2;
+
+    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
+        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
+            flags1 = page_get_flags(tb->pc);
+            flags2 = page_get_flags(tb->pc + tb->size - 1);
+            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
+                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
+                       (long)tb->pc, tb->size, flags1, flags2);
+            }
+        }
+    }
+}
+
+#endif
+
+/* invalidate one TB */
+static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
+                             int next_offset)
+{
+    TranslationBlock *tb1;
+    for(;;) {
+        tb1 = *ptb;
+        if (tb1 == tb) {
+            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
+            break;
+        }
+        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
+    }
+}
+
+static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
+{
+    TranslationBlock *tb1;
+    unsigned int n1;
+
+    for(;;) {
+        tb1 = *ptb;
+        n1 = (long)tb1 & 3;
+        tb1 = (TranslationBlock *)((long)tb1 & ~3);
+        if (tb1 == tb) {
+            *ptb = tb1->page_next[n1];
+            break;
+        }
+        ptb = &tb1->page_next[n1];
+    }
+}
+
+static inline void tb_jmp_remove(TranslationBlock *tb, int n)
+{
+    TranslationBlock *tb1, **ptb;
+    unsigned int n1;
+
+    ptb = &tb->jmp_next[n];
+    tb1 = *ptb;
+    if (tb1) {
+        /* find tb(n) in circular list */
+        for(;;) {
+            tb1 = *ptb;
+            n1 = (long)tb1 & 3;
+            tb1 = (TranslationBlock *)((long)tb1 & ~3);
+            if (n1 == n && tb1 == tb)
+                break;
+            if (n1 == 2) {
+                ptb = &tb1->jmp_first;
+            } else {
+                ptb = &tb1->jmp_next[n1];
+            }
+        }
+        /* now we can suppress tb(n) from the list */
+        *ptb = tb->jmp_next[n];
+
+        tb->jmp_next[n] = NULL;
+    }
+}
+
+/* reset the jump entry 'n' of a TB so that it is not chained to
+   another TB */
+static inline void tb_reset_jump(TranslationBlock *tb, int n)
+{
+    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
+}
+
+void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
+{
+    CPUState *env;
+    PageDesc *p;
+    unsigned int h, n1;
+    tb_page_addr_t phys_pc;
+    TranslationBlock *tb1, *tb2;
+
+    /* remove the TB from the hash list */
+    phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
+    h = tb_phys_hash_func(phys_pc);
+    tb_remove(&tb_phys_hash[h], tb,
+              offsetof(TranslationBlock, phys_hash_next));
+
+    /* remove the TB from the page list */
+    if (tb->page_addr[0] != page_addr) {
+        p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
+        tb_page_remove(&p->first_tb, tb);
+        invalidate_page_bitmap(p);
+    }
+    if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
+        p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
+        tb_page_remove(&p->first_tb, tb);
+        invalidate_page_bitmap(p);
+    }
+
+    tb_invalidated_flag = 1;
+
+    /* remove the TB from the hash list */
+    h = tb_jmp_cache_hash_func(tb->pc);
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->tb_jmp_cache[h] == tb)
+            env->tb_jmp_cache[h] = NULL;
+    }
+
+    /* suppress this TB from the two jump lists */
+    tb_jmp_remove(tb, 0);
+    tb_jmp_remove(tb, 1);
+
+    /* suppress any remaining jumps to this TB */
+    tb1 = tb->jmp_first;
+    for(;;) {
+        n1 = (long)tb1 & 3;
+        if (n1 == 2)
+            break;
+        tb1 = (TranslationBlock *)((long)tb1 & ~3);
+        tb2 = tb1->jmp_next[n1];
+        tb_reset_jump(tb1, n1);
+        tb1->jmp_next[n1] = NULL;
+        tb1 = tb2;
+    }
+    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
+
+    tb_phys_invalidate_count++;
+}
+
+static inline void set_bits(uint8_t *tab, int start, int len)
+{
+    int end, mask, end1;
+
+    end = start + len;
+    tab += start >> 3;
+    mask = 0xff << (start & 7);
+    if ((start & ~7) == (end & ~7)) {
+        if (start < end) {
+            mask &= ~(0xff << (end & 7));
+            *tab |= mask;
+        }
+    } else {
+        *tab++ |= mask;
+        start = (start + 8) & ~7;
+        end1 = end & ~7;
+        while (start < end1) {
+            *tab++ = 0xff;
+            start += 8;
+        }
+        if (start < end) {
+            mask = ~(0xff << (end & 7));
+            *tab |= mask;
+        }
+    }
+}
+
+static void build_page_bitmap(PageDesc *p)
+{
+    int n, tb_start, tb_end;
+    TranslationBlock *tb;
+
+    p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
+
+    tb = p->first_tb;
+    while (tb != NULL) {
+        n = (long)tb & 3;
+        tb = (TranslationBlock *)((long)tb & ~3);
+        /* NOTE: this is subtle as a TB may span two physical pages */
+        if (n == 0) {
+            /* NOTE: tb_end may be after the end of the page, but
+               it is not a problem */
+            tb_start = tb->pc & ~TARGET_PAGE_MASK;
+            tb_end = tb_start + tb->size;
+            if (tb_end > TARGET_PAGE_SIZE)
+                tb_end = TARGET_PAGE_SIZE;
+        } else {
+            tb_start = 0;
+            tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
+        }
+        set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
+        tb = tb->page_next[n];
+    }
+}
+
+TranslationBlock *tb_gen_code(CPUState *env,
+                              target_ulong pc, target_ulong cs_base,
+                              int flags, int cflags)
+{
+    TranslationBlock *tb;
+    uint8_t *tc_ptr;
+    tb_page_addr_t phys_pc, phys_page2;
+    target_ulong virt_page2;
+    int code_gen_size;
+
+    phys_pc = get_page_addr_code(env, pc);
+    tb = tb_alloc(pc);
+    if (!tb) {
+        /* flush must be done */
+        tb_flush(env);
+        /* cannot fail at this point */
+        tb = tb_alloc(pc);
+        /* Don't forget to invalidate previous TB info.  */
+        tb_invalidated_flag = 1;
+    }
+    tc_ptr = code_gen_ptr;
+    tb->tc_ptr = tc_ptr;
+    tb->cs_base = cs_base;
+    tb->flags = flags;
+    tb->cflags = cflags;
+    cpu_gen_code(env, tb, &code_gen_size);
+    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+
+    /* check next page if needed */
+    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
+    phys_page2 = -1;
+    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
+        phys_page2 = get_page_addr_code(env, virt_page2);
+    }
+    tb_link_page(tb, phys_pc, phys_page2);
+    return tb;
+}
+
+/* invalidate all TBs which intersect with the target physical page
+   starting in range [start;end[. NOTE: start and end must refer to
+   the same physical page. 'is_cpu_write_access' should be true if called
+   from a real cpu write access: the virtual CPU will exit the current
+   TB if code is modified inside this TB. */
+void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
+                                   int is_cpu_write_access)
+{
+    TranslationBlock *tb, *tb_next, *saved_tb;
+    CPUState *env = cpu_single_env;
+    tb_page_addr_t tb_start, tb_end;
+    PageDesc *p;
+    int n;
+#ifdef TARGET_HAS_PRECISE_SMC
+    int current_tb_not_found = is_cpu_write_access;
+    TranslationBlock *current_tb = NULL;
+    int current_tb_modified = 0;
+    target_ulong current_pc = 0;
+    target_ulong current_cs_base = 0;
+    int current_flags = 0;
+#endif /* TARGET_HAS_PRECISE_SMC */
+
+    p = page_find(start >> TARGET_PAGE_BITS);
+    if (!p)
+        return;
+    if (!p->code_bitmap &&
+        ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
+        is_cpu_write_access) {
+        /* build code bitmap */
+        build_page_bitmap(p);
+    }
+
+    /* we remove all the TBs in the range [start, end[ */
+    /* XXX: see if in some cases it could be faster to invalidate all the code */
+    tb = p->first_tb;
+    while (tb != NULL) {
+        n = (long)tb & 3;
+        tb = (TranslationBlock *)((long)tb & ~3);
+        tb_next = tb->page_next[n];
+        /* NOTE: this is subtle as a TB may span two physical pages */
+        if (n == 0) {
+            /* NOTE: tb_end may be after the end of the page, but
+               it is not a problem */
+            tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
+            tb_end = tb_start + tb->size;
+        } else {
+            tb_start = tb->page_addr[1];
+            tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
+        }
+        if (!(tb_end <= start || tb_start >= end)) {
+#ifdef TARGET_HAS_PRECISE_SMC
+            if (current_tb_not_found) {
+                current_tb_not_found = 0;
+                current_tb = NULL;
+                if (env->mem_io_pc) {
+                    /* now we have a real cpu fault */
+                    current_tb = tb_find_pc(env->mem_io_pc);
+                }
+            }
+            if (current_tb == tb &&
+                (current_tb->cflags & CF_COUNT_MASK) != 1) {
+                /* If we are modifying the current TB, we must stop
+                its execution. We could be more precise by checking
+                that the modification is after the current PC, but it
+                would require a specialized function to partially
+                restore the CPU state */
+
+                current_tb_modified = 1;
+                cpu_restore_state(current_tb, env, env->mem_io_pc);
+                cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+                                     &current_flags);
+            }
+#endif /* TARGET_HAS_PRECISE_SMC */
+            /* we need to do that to handle the case where a signal
+               occurs while doing tb_phys_invalidate() */
+            saved_tb = NULL;
+            if (env) {
+                saved_tb = env->current_tb;
+                env->current_tb = NULL;
+            }
+            tb_phys_invalidate(tb, -1);
+            if (env) {
+                env->current_tb = saved_tb;
+                if (env->interrupt_request && env->current_tb)
+                    cpu_interrupt(env, env->interrupt_request);
+            }
+        }
+        tb = tb_next;
+    }
+#if !defined(CONFIG_USER_ONLY)
+    /* if no code remaining, no need to continue to use slow writes */
+    if (!p->first_tb) {
+        invalidate_page_bitmap(p);
+        if (is_cpu_write_access) {
+            tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
+        }
+    }
+#endif
+#ifdef TARGET_HAS_PRECISE_SMC
+    if (current_tb_modified) {
+        /* we generate a block containing just the instruction
+           modifying the memory. It will ensure that it cannot modify
+           itself */
+        env->current_tb = NULL;
+        tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
+        cpu_resume_from_signal(env, NULL);
+    }
+#endif
+}
+
+/* len must be <= 8 and start must be a multiple of len */
+static inline void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
+{
+    PageDesc *p;
+    int offset, b;
+#if 0
+    if (1) {
+        qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
+                  cpu_single_env->mem_io_vaddr, len,
+                  cpu_single_env->eip,
+                  cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
+    }
+#endif
+    p = page_find(start >> TARGET_PAGE_BITS);
+    if (!p)
+        return;
+    if (p->code_bitmap) {
+        offset = start & ~TARGET_PAGE_MASK;
+        b = p->code_bitmap[offset >> 3] >> (offset & 7);
+        if (b & ((1 << len) - 1))
+            goto do_invalidate;
+    } else {
+    do_invalidate:
+        tb_invalidate_phys_page_range(start, start + len, 1);
+    }
+}
+
+#if !defined(CONFIG_SOFTMMU)
+static void tb_invalidate_phys_page(tb_page_addr_t addr,
+                                    unsigned long pc, void *puc)
+{
+    TranslationBlock *tb;
+    PageDesc *p;
+    int n;
+#ifdef TARGET_HAS_PRECISE_SMC
+    TranslationBlock *current_tb = NULL;
+    CPUState *env = cpu_single_env;
+    int current_tb_modified = 0;
+    target_ulong current_pc = 0;
+    target_ulong current_cs_base = 0;
+    int current_flags = 0;
+#endif
+
+    addr &= TARGET_PAGE_MASK;
+    p = page_find(addr >> TARGET_PAGE_BITS);
+    if (!p)
+        return;
+    tb = p->first_tb;
+#ifdef TARGET_HAS_PRECISE_SMC
+    if (tb && pc != 0) {
+        current_tb = tb_find_pc(pc);
+    }
+#endif
+    while (tb != NULL) {
+        n = (long)tb & 3;
+        tb = (TranslationBlock *)((long)tb & ~3);
+#ifdef TARGET_HAS_PRECISE_SMC
+        if (current_tb == tb &&
+            (current_tb->cflags & CF_COUNT_MASK) != 1) {
+                /* If we are modifying the current TB, we must stop
+                   its execution. We could be more precise by checking
+                   that the modification is after the current PC, but it
+                   would require a specialized function to partially
+                   restore the CPU state */
+
+            current_tb_modified = 1;
+            cpu_restore_state(current_tb, env, pc);
+            cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+                                 &current_flags);
+        }
+#endif /* TARGET_HAS_PRECISE_SMC */
+        tb_phys_invalidate(tb, addr);
+        tb = tb->page_next[n];
+    }
+    p->first_tb = NULL;
+#ifdef TARGET_HAS_PRECISE_SMC
+    if (current_tb_modified) {
+        /* we generate a block containing just the instruction
+           modifying the memory. It will ensure that it cannot modify
+           itself */
+        env->current_tb = NULL;
+        tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
+        cpu_resume_from_signal(env, puc);
+    }
+#endif
+}
+#endif
+
+/* add the tb in the target page and protect it if necessary */
+static inline void tb_alloc_page(TranslationBlock *tb,
+                                 unsigned int n, tb_page_addr_t page_addr)
+{
+    PageDesc *p;
+#ifndef CONFIG_USER_ONLY
+    bool page_already_protected;
+#endif
+
+    tb->page_addr[n] = page_addr;
+    p = page_find_alloc(page_addr >> TARGET_PAGE_BITS, 1);
+    tb->page_next[n] = p->first_tb;
+#ifndef CONFIG_USER_ONLY
+    page_already_protected = p->first_tb != NULL;
+#endif
+    p->first_tb = (TranslationBlock *)((long)tb | n);
+    invalidate_page_bitmap(p);
+
+#if defined(TARGET_HAS_SMC) || 1
+
+#if defined(CONFIG_USER_ONLY)
+    if (p->flags & PAGE_WRITE) {
+        target_ulong addr;
+        PageDesc *p2;
+        int prot;
+
+        /* force the host page as non writable (writes will have a
+           page fault + mprotect overhead) */
+        page_addr &= qemu_host_page_mask;
+        prot = 0;
+        for(addr = page_addr; addr < page_addr + qemu_host_page_size;
+            addr += TARGET_PAGE_SIZE) {
+
+            p2 = page_find (addr >> TARGET_PAGE_BITS);
+            if (!p2)
+                continue;
+            prot |= p2->flags;
+            p2->flags &= ~PAGE_WRITE;
+          }
+        mprotect(g2h(page_addr), qemu_host_page_size,
+                 (prot & PAGE_BITS) & ~PAGE_WRITE);
+#ifdef DEBUG_TB_INVALIDATE
+        printf("protecting code page: 0x" TARGET_FMT_lx "\n",
+               page_addr);
+#endif
+    }
+#else
+    /* if some code is already present, then the pages are already
+       protected. So we handle the case where only the first TB is
+       allocated in a physical page */
+    if (!page_already_protected) {
+        tlb_protect_code(page_addr);
+    }
+#endif
+
+#endif /* TARGET_HAS_SMC */
+}
+
+/* add a new TB and link it to the physical page tables. phys_page2 is
+   (-1) to indicate that only one page contains the TB. */
+void tb_link_page(TranslationBlock *tb,
+                  tb_page_addr_t phys_pc, tb_page_addr_t phys_page2)
+{
+    unsigned int h;
+    TranslationBlock **ptb;
+
+    /* Grab the mmap lock to stop another thread invalidating this TB
+       before we are done.  */
+    mmap_lock();
+    /* add in the physical hash table */
+    h = tb_phys_hash_func(phys_pc);
+    ptb = &tb_phys_hash[h];
+    tb->phys_hash_next = *ptb;
+    *ptb = tb;
+
+    /* add in the page list */
+    tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
+    if (phys_page2 != -1)
+        tb_alloc_page(tb, 1, phys_page2);
+    else
+        tb->page_addr[1] = -1;
+
+    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
+    tb->jmp_next[0] = NULL;
+    tb->jmp_next[1] = NULL;
+
+    /* init original jump addresses */
+    if (tb->tb_next_offset[0] != 0xffff)
+        tb_reset_jump(tb, 0);
+    if (tb->tb_next_offset[1] != 0xffff)
+        tb_reset_jump(tb, 1);
+
+#ifdef DEBUG_TB_CHECK
+    tb_page_check();
+#endif
+    mmap_unlock();
+}
+
+/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
+   tb[1].tc_ptr. Return NULL if not found */
+TranslationBlock *tb_find_pc(unsigned long tc_ptr)
+{
+    int m_min, m_max, m;
+    unsigned long v;
+    TranslationBlock *tb;
+
+    if (nb_tbs <= 0)
+        return NULL;
+    if (tc_ptr < (unsigned long)code_gen_buffer ||
+        tc_ptr >= (unsigned long)code_gen_ptr)
+        return NULL;
+    /* binary search (cf Knuth) */
+    m_min = 0;
+    m_max = nb_tbs - 1;
+    while (m_min <= m_max) {
+        m = (m_min + m_max) >> 1;
+        tb = &tbs[m];
+        v = (unsigned long)tb->tc_ptr;
+        if (v == tc_ptr)
+            return tb;
+        else if (tc_ptr < v) {
+            m_max = m - 1;
+        } else {
+            m_min = m + 1;
+        }
+    }
+    return &tbs[m_max];
+}
+
+static void tb_reset_jump_recursive(TranslationBlock *tb);
+
+static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
+{
+    TranslationBlock *tb1, *tb_next, **ptb;
+    unsigned int n1;
+
+    tb1 = tb->jmp_next[n];
+    if (tb1 != NULL) {
+        /* find head of list */
+        for(;;) {
+            n1 = (long)tb1 & 3;
+            tb1 = (TranslationBlock *)((long)tb1 & ~3);
+            if (n1 == 2)
+                break;
+            tb1 = tb1->jmp_next[n1];
+        }
+        /* we are now sure now that tb jumps to tb1 */
+        tb_next = tb1;
+
+        /* remove tb from the jmp_first list */
+        ptb = &tb_next->jmp_first;
+        for(;;) {
+            tb1 = *ptb;
+            n1 = (long)tb1 & 3;
+            tb1 = (TranslationBlock *)((long)tb1 & ~3);
+            if (n1 == n && tb1 == tb)
+                break;
+            ptb = &tb1->jmp_next[n1];
+        }
+        *ptb = tb->jmp_next[n];
+        tb->jmp_next[n] = NULL;
+
+        /* suppress the jump to next tb in generated code */
+        tb_reset_jump(tb, n);
+
+        /* suppress jumps in the tb on which we could have jumped */
+        tb_reset_jump_recursive(tb_next);
+    }
+}
+
+static void tb_reset_jump_recursive(TranslationBlock *tb)
+{
+    tb_reset_jump_recursive2(tb, 0);
+    tb_reset_jump_recursive2(tb, 1);
+}
+
+#if defined(TARGET_HAS_ICE)
+#if defined(CONFIG_USER_ONLY)
+static void breakpoint_invalidate(CPUState *env, target_ulong pc)
+{
+    tb_invalidate_phys_page_range(pc, pc + 1, 0);
+}
+#else
+static void breakpoint_invalidate(CPUState *env, target_ulong pc)
+{
+    target_phys_addr_t addr;
+    target_ulong pd;
+    ram_addr_t ram_addr;
+    PhysPageDesc *p;
+
+    addr = cpu_get_phys_page_debug(env, pc);
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+    ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
+    tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
+}
+#endif
+#endif /* TARGET_HAS_ICE */
+
+#if defined(CONFIG_USER_ONLY)
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+
+{
+}
+
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
+{
+    return -ENOSYS;
+}
+#else
+/* Add a watchpoint.  */
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
+{
+    target_ulong len_mask = ~(len - 1);
+    CPUWatchpoint *wp;
+
+    /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
+    if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
+        fprintf(stderr, "qemu: tried to set invalid watchpoint at "
+                TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
+        return -EINVAL;
+    }
+    wp = qemu_malloc(sizeof(*wp));
+
+    wp->vaddr = addr;
+    wp->len_mask = len_mask;
+    wp->flags = flags;
+
+    /* keep all GDB-injected watchpoints in front */
+    if (flags & BP_GDB)
+        QTAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
+    else
+        QTAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
+
+    tlb_flush_page(env, addr);
+
+    if (watchpoint)
+        *watchpoint = wp;
+    return 0;
+}
+
+/* Remove a specific watchpoint.  */
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
+{
+    target_ulong len_mask = ~(len - 1);
+    CPUWatchpoint *wp;
+
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if (addr == wp->vaddr && len_mask == wp->len_mask
+                && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
+            cpu_watchpoint_remove_by_ref(env, wp);
+            return 0;
+        }
+    }
+    return -ENOENT;
+}
+
+/* Remove a specific watchpoint by reference.  */
+void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
+{
+    QTAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
+
+    tlb_flush_page(env, watchpoint->vaddr);
+
+    qemu_free(watchpoint);
+}
+
+/* Remove all matching watchpoints.  */
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+    CPUWatchpoint *wp, *next;
+
+    QTAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
+        if (wp->flags & mask)
+            cpu_watchpoint_remove_by_ref(env, wp);
+    }
+}
+#endif
+
+/* Add a breakpoint.  */
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
+{
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+
+    bp = qemu_malloc(sizeof(*bp));
+
+    bp->pc = pc;
+    bp->flags = flags;
+
+    /* keep all GDB-injected breakpoints in front */
+    if (flags & BP_GDB)
+        QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
+    else
+        QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
+
+    breakpoint_invalidate(env, pc);
+
+    if (breakpoint)
+        *breakpoint = bp;
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+/* Remove a specific breakpoint.  */
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+
+    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (bp->pc == pc && bp->flags == flags) {
+            cpu_breakpoint_remove_by_ref(env, bp);
+            return 0;
+        }
+    }
+    return -ENOENT;
+#else
+    return -ENOSYS;
+#endif
+}
+
+/* Remove a specific breakpoint by reference.  */
+void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
+{
+#if defined(TARGET_HAS_ICE)
+    QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
+
+    breakpoint_invalidate(env, breakpoint->pc);
+
+    qemu_free(breakpoint);
+#endif
+}
+
+/* Remove all matching breakpoints. */
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp, *next;
+
+    QTAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
+        if (bp->flags & mask)
+            cpu_breakpoint_remove_by_ref(env, bp);
+    }
+#endif
+}
+
+/* enable or disable single step mode. EXCP_DEBUG is returned by the
+   CPU loop after each instruction */
+void cpu_single_step(CPUState *env, int enabled)
+{
+#if defined(TARGET_HAS_ICE)
+    if (env->singlestep_enabled != enabled) {
+        env->singlestep_enabled = enabled;
+        if (kvm_enabled())
+            kvm_update_guest_debug(env, 0);
+        else {
+            /* must flush all the translated code to avoid inconsistencies */
+            /* XXX: only flush what is necessary */
+            tb_flush(env);
+        }
+    }
+#endif
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+    loglevel = log_flags;
+    if (loglevel && !logfile) {
+        logfile = fopen(logfilename, log_append ? "a" : "w");
+        if (!logfile) {
+            perror(logfilename);
+            _exit(1);
+        }
+#if !defined(CONFIG_SOFTMMU)
+        /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+        {
+            static char logfile_buf[4096];
+            setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+        }
+#elif !defined(_WIN32)
+        /* Win32 doesn't support line-buffering and requires size >= 2 */
+        setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+        log_append = 1;
+    }
+    if (!loglevel && logfile) {
+        fclose(logfile);
+        logfile = NULL;
+    }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+    logfilename = strdup(filename);
+    if (logfile) {
+        fclose(logfile);
+        logfile = NULL;
+    }
+    cpu_set_log(loglevel);
+}
+
+static void cpu_unlink_tb(CPUState *env)
+{
+    /* FIXME: TB unchaining isn't SMP safe.  For now just ignore the
+       problem and hope the cpu will stop of its own accord.  For userspace
+       emulation this often isn't actually as bad as it sounds.  Often
+       signals are used primarily to interrupt blocking syscalls.  */
+    TranslationBlock *tb;
+    static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
+
+    spin_lock(&interrupt_lock);
+    tb = env->current_tb;
+    /* if the cpu is currently executing code, we must unlink it and
+       all the potentially executing TB */
+    if (tb) {
+        env->current_tb = NULL;
+        tb_reset_jump_recursive(tb);
+    }
+    spin_unlock(&interrupt_lock);
+}
+
+#ifndef CONFIG_USER_ONLY
+/* mask must never be zero, except for A20 change call */
+static void tcg_handle_interrupt(CPUState *env, int mask)
+{
+    int old_mask;
+
+    old_mask = env->interrupt_request;
+    env->interrupt_request |= mask;
+
+    /*
+     * If called from iothread context, wake the target cpu in
+     * case its halted.
+     */
+    if (!qemu_cpu_is_self(env)) {
+        qemu_cpu_kick(env);
+        return;
+    }
+
+    if (use_icount) {
+        env->icount_decr.u16.high = 0xffff;
+        if (!can_do_io(env)
+            && (mask & ~old_mask) != 0) {
+            cpu_abort(env, "Raised interrupt while not in I/O function");
+        }
+    } else {
+        cpu_unlink_tb(env);
+    }
+}
+
+CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt;
+
+#else /* CONFIG_USER_ONLY */
+
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+    cpu_unlink_tb(env);
+}
+#endif /* CONFIG_USER_ONLY */
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request &= ~mask;
+}
+
+void cpu_exit(CPUState *env)
+{
+    env->exit_request = 1;
+    cpu_unlink_tb(env);
+}
+
+const CPULogItem cpu_log_items[] = {
+    { CPU_LOG_TB_OUT_ASM, "out_asm",
+      "show generated host assembly code for each compiled TB" },
+    { CPU_LOG_TB_IN_ASM, "in_asm",
+      "show target assembly code for each compiled TB" },
+    { CPU_LOG_TB_OP, "op",
+      "show micro ops for each compiled TB" },
+    { CPU_LOG_TB_OP_OPT, "op_opt",
+      "show micro ops "
+#ifdef TARGET_I386
+      "before eflags optimization and "
+#endif
+      "after liveness analysis" },
+    { CPU_LOG_INT, "int",
+      "show interrupts/exceptions in short format" },
+    { CPU_LOG_EXEC, "exec",
+      "show trace before each executed TB (lots of logs)" },
+    { CPU_LOG_TB_CPU, "cpu",
+      "show CPU state before block translation" },
+#ifdef TARGET_I386
+    { CPU_LOG_PCALL, "pcall",
+      "show protected mode far calls/returns/exceptions" },
+    { CPU_LOG_RESET, "cpu_reset",
+      "show CPU state before CPU resets" },
+#endif
+#ifdef DEBUG_IOPORT
+    { CPU_LOG_IOPORT, "ioport",
+      "show all i/o ports accesses" },
+#endif
+    { 0, NULL, NULL },
+};
+
+#ifndef CONFIG_USER_ONLY
+static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
+    = QLIST_HEAD_INITIALIZER(memory_client_list);
+
+static void cpu_notify_set_memory(target_phys_addr_t start_addr,
+                                  ram_addr_t size,
+                                  ram_addr_t phys_offset,
+                                  bool log_dirty)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        client->set_memory(client, start_addr, size, phys_offset, log_dirty);
+    }
+}
+
+static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start,
+                                        target_phys_addr_t end)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        int r = client->sync_dirty_bitmap(client, start, end);
+        if (r < 0)
+            return r;
+    }
+    return 0;
+}
+
+static int cpu_notify_migration_log(int enable)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        int r = client->migration_log(client, enable);
+        if (r < 0)
+            return r;
+    }
+    return 0;
+}
+
+struct last_map {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    ram_addr_t phys_offset;
+};
+
+/* The l1_phys_map provides the upper P_L1_BITs of the guest physical
+ * address.  Each intermediate table provides the next L2_BITs of guest
+ * physical address space.  The number of levels vary based on host and
+ * guest configuration, making it efficient to build the final guest
+ * physical address by seeding the L1 offset and shifting and adding in
+ * each L2 offset as we recurse through them. */
+static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level,
+                                 void **lp, target_phys_addr_t addr,
+                                 struct last_map *map)
+{
+    int i;
+
+    if (*lp == NULL) {
+        return;
+    }
+    if (level == 0) {
+        PhysPageDesc *pd = *lp;
+        addr <<= L2_BITS + TARGET_PAGE_BITS;
+        for (i = 0; i < L2_SIZE; ++i) {
+            if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
+                target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS;
+
+                if (map->size &&
+                    start_addr == map->start_addr + map->size &&
+                    pd[i].phys_offset == map->phys_offset + map->size) {
+
+                    map->size += TARGET_PAGE_SIZE;
+                    continue;
+                } else if (map->size) {
+                    client->set_memory(client, map->start_addr,
+                                       map->size, map->phys_offset, false);
+                }
+
+                map->start_addr = start_addr;
+                map->size = TARGET_PAGE_SIZE;
+                map->phys_offset = pd[i].phys_offset;
+            }
+        }
+    } else {
+        void **pp = *lp;
+        for (i = 0; i < L2_SIZE; ++i) {
+            phys_page_for_each_1(client, level - 1, pp + i,
+                                 (addr << L2_BITS) | i, map);
+        }
+    }
+}
+
+static void phys_page_for_each(CPUPhysMemoryClient *client)
+{
+    int i;
+    struct last_map map = { };
+
+    for (i = 0; i < P_L1_SIZE; ++i) {
+        phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
+                             l1_phys_map + i, i, &map);
+    }
+    if (map.size) {
+        client->set_memory(client, map.start_addr, map.size, map.phys_offset,
+                           false);
+    }
+}
+
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *client)
+{
+    QLIST_INSERT_HEAD(&memory_client_list, client, list);
+    phys_page_for_each(client);
+}
+
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client)
+{
+    QLIST_REMOVE(client, list);
+}
+#endif
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+    if (strlen(s2) != n)
+        return 0;
+    return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
+    const CPULogItem *item;
+    int mask;
+    const char *p, *p1;
+
+    p = str;
+    mask = 0;
+    for(;;) {
+        p1 = strchr(p, ',');
+        if (!p1)
+            p1 = p + strlen(p);
+        if(cmp1(p,p1-p,"all")) {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                mask |= item->mask;
+            }
+        } else {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                if (cmp1(p, p1 - p, item->name))
+                    goto found;
+            }
+            return 0;
+        }
+    found:
+        mask |= item->mask;
+        if (*p1 != ',')
+            break;
+        p = p1 + 1;
+    }
+    return mask;
+}
+
+void cpu_abort(CPUState *env, const char *fmt, ...)
+{
+    va_list ap;
+    va_list ap2;
+
+    va_start(ap, fmt);
+    va_copy(ap2, ap);
+    fprintf(stderr, "qemu: fatal: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+#ifdef TARGET_I386
+    cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
+#else
+    cpu_dump_state(env, stderr, fprintf, 0);
+#endif
+    if (qemu_log_enabled()) {
+        qemu_log("qemu: fatal: ");
+        qemu_log_vprintf(fmt, ap2);
+        qemu_log("\n");
+#ifdef TARGET_I386
+        log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
+#else
+        log_cpu_state(env, 0);
+#endif
+        qemu_log_flush();
+        qemu_log_close();
+    }
+    va_end(ap2);
+    va_end(ap);
+#if defined(CONFIG_USER_ONLY)
+    {
+        struct sigaction act;
+        sigfillset(&act.sa_mask);
+        act.sa_handler = SIG_DFL;
+        sigaction(SIGABRT, &act, NULL);
+    }
+#endif
+    abort();
+}
+
+CPUState *cpu_copy(CPUState *env)
+{
+    CPUState *new_env = cpu_init(env->cpu_model_str);
+    CPUState *next_cpu = new_env->next_cpu;
+    int cpu_index = new_env->cpu_index;
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+    CPUWatchpoint *wp;
+#endif
+
+    memcpy(new_env, env, sizeof(CPUState));
+
+    /* Preserve chaining and index. */
+    new_env->next_cpu = next_cpu;
+    new_env->cpu_index = cpu_index;
+
+    /* Clone all break/watchpoints.
+       Note: Once we support ptrace with hw-debug register access, make sure
+       BP_CPU break/watchpoints are handled correctly on clone. */
+    QTAILQ_INIT(&env->breakpoints);
+    QTAILQ_INIT(&env->watchpoints);
+#if defined(TARGET_HAS_ICE)
+    QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+    }
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+                              wp->flags, NULL);
+    }
+#endif
+
+    return new_env;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+static inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
+{
+    unsigned int i;
+
+    /* Discard jump cache entries for any tb which might potentially
+       overlap the flushed page.  */
+    i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
+    memset (&env->tb_jmp_cache[i], 0, 
+            TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
+
+    i = tb_jmp_cache_hash_page(addr);
+    memset (&env->tb_jmp_cache[i], 0, 
+            TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
+}
+
+static CPUTLBEntry s_cputlb_empty_entry = {
+    .addr_read  = -1,
+    .addr_write = -1,
+    .addr_code  = -1,
+    .addend     = -1,
+};
+
+/* NOTE: if flush_global is true, also flush global entries (not
+   implemented yet) */
+void tlb_flush(CPUState *env, int flush_global)
+{
+    int i;
+
+#if defined(DEBUG_TLB)
+    printf("tlb_flush:\n");
+#endif
+    /* must reset current TB so that interrupts cannot modify the
+       links while we are modifying them */
+    env->current_tb = NULL;
+
+    for(i = 0; i < CPU_TLB_SIZE; i++) {
+        int mmu_idx;
+        for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+            env->tlb_table[mmu_idx][i] = s_cputlb_empty_entry;
+        }
+    }
+
+    memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
+
+    env->tlb_flush_addr = -1;
+    env->tlb_flush_mask = 0;
+    tlb_flush_count++;
+}
+
+static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
+{
+    if (addr == (tlb_entry->addr_read &
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
+        addr == (tlb_entry->addr_write &
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
+        addr == (tlb_entry->addr_code &
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        *tlb_entry = s_cputlb_empty_entry;
+    }
+}
+
+void tlb_flush_page(CPUState *env, target_ulong addr)
+{
+    int i;
+    int mmu_idx;
+
+#if defined(DEBUG_TLB)
+    printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
+#endif
+    /* Check if we need to flush due to large pages.  */
+    if ((addr & env->tlb_flush_mask) == env->tlb_flush_addr) {
+#if defined(DEBUG_TLB)
+        printf("tlb_flush_page: forced full flush ("
+               TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
+               env->tlb_flush_addr, env->tlb_flush_mask);
+#endif
+        tlb_flush(env, 1);
+        return;
+    }
+    /* must reset current TB so that interrupts cannot modify the
+       links while we are modifying them */
+    env->current_tb = NULL;
+
+    addr &= TARGET_PAGE_MASK;
+    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+        tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
+
+    tlb_flush_jmp_cache(env, addr);
+}
+
+/* update the TLBs so that writes to code in the virtual page 'addr'
+   can be detected */
+static void tlb_protect_code(ram_addr_t ram_addr)
+{
+    cpu_physical_memory_reset_dirty(ram_addr,
+                                    ram_addr + TARGET_PAGE_SIZE,
+                                    CODE_DIRTY_FLAG);
+}
+
+/* update the TLB so that writes in physical page 'phys_addr' are no longer
+   tested for self modifying code */
+static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
+                                    target_ulong vaddr)
+{
+    cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
+}
+
+static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
+                                         unsigned long start, unsigned long length)
+{
+    unsigned long addr;
+    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
+        if ((addr - start) < length) {
+            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
+        }
+    }
+}
+
+/* Note: start and end must be within the same ram block.  */
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+                                     int dirty_flags)
+{
+    CPUState *env;
+    unsigned long length, start1;
+    int i;
+
+    start &= TARGET_PAGE_MASK;
+    end = TARGET_PAGE_ALIGN(end);
+
+    length = end - start;
+    if (length == 0)
+        return;
+    cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
+
+    /* we modify the TLB cache so that the dirty bit will be set again
+       when accessing the range */
+    start1 = (unsigned long)qemu_safe_ram_ptr(start);
+    /* Check that we don't span multiple blocks - this breaks the
+       address comparisons below.  */
+    if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
+            != (end - 1) - start) {
+        abort();
+    }
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        int mmu_idx;
+        for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+            for(i = 0; i < CPU_TLB_SIZE; i++)
+                tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
+                                      start1, length);
+        }
+    }
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+    int ret = 0;
+    in_migration = enable;
+    ret = cpu_notify_migration_log(!!enable);
+    return ret;
+}
+
+int cpu_physical_memory_get_dirty_tracking(void)
+{
+    return in_migration;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    int ret;
+
+    ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr);
+    return ret;
+}
+
+int cpu_physical_log_start(target_phys_addr_t start_addr,
+                           ram_addr_t size)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        if (client->log_start) {
+            int r = client->log_start(client, start_addr, size);
+            if (r < 0) {
+                return r;
+            }
+        }
+    }
+    return 0;
+}
+
+int cpu_physical_log_stop(target_phys_addr_t start_addr,
+                          ram_addr_t size)
+{
+    CPUPhysMemoryClient *client;
+    QLIST_FOREACH(client, &memory_client_list, list) {
+        if (client->log_stop) {
+            int r = client->log_stop(client, start_addr, size);
+            if (r < 0) {
+                return r;
+            }
+        }
+    }
+    return 0;
+}
+
+static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
+{
+    ram_addr_t ram_addr;
+    void *p;
+
+    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+        p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+            + tlb_entry->addend);
+        ram_addr = qemu_ram_addr_from_host_nofail(p);
+        if (!cpu_physical_memory_is_dirty(ram_addr)) {
+            tlb_entry->addr_write |= TLB_NOTDIRTY;
+        }
+    }
+}
+
+/* update the TLB according to the current state of the dirty bits */
+void cpu_tlb_update_dirty(CPUState *env)
+{
+    int i;
+    int mmu_idx;
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+        for(i = 0; i < CPU_TLB_SIZE; i++)
+            tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
+    }
+}
+
+static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
+{
+    if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
+        tlb_entry->addr_write = vaddr;
+}
+
+/* update the TLB corresponding to virtual page vaddr
+   so that it is no longer dirty */
+static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
+{
+    int i;
+    int mmu_idx;
+
+    vaddr &= TARGET_PAGE_MASK;
+    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+        tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
+}
+
+/* Our TLB does not support large pages, so remember the area covered by
+   large pages and trigger a full TLB flush if these are invalidated.  */
+static void tlb_add_large_page(CPUState *env, target_ulong vaddr,
+                               target_ulong size)
+{
+    target_ulong mask = ~(size - 1);
+
+    if (env->tlb_flush_addr == (target_ulong)-1) {
+        env->tlb_flush_addr = vaddr & mask;
+        env->tlb_flush_mask = mask;
+        return;
+    }
+    /* Extend the existing region to include the new page.
+       This is a compromise between unnecessary flushes and the cost
+       of maintaining a full variable size TLB.  */
+    mask &= env->tlb_flush_mask;
+    while (((env->tlb_flush_addr ^ vaddr) & mask) != 0) {
+        mask <<= 1;
+    }
+    env->tlb_flush_addr &= mask;
+    env->tlb_flush_mask = mask;
+}
+
+/* Add a new TLB entry. At most one entry for a given virtual address
+   is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
+   supplied size is only used by tlb_flush_page.  */
+void tlb_set_page(CPUState *env, target_ulong vaddr,
+                  target_phys_addr_t paddr, int prot,
+                  int mmu_idx, target_ulong size)
+{
+    PhysPageDesc *p;
+    unsigned long pd;
+    unsigned int index;
+    target_ulong address;
+    target_ulong code_address;
+    unsigned long addend;
+    CPUTLBEntry *te;
+    CPUWatchpoint *wp;
+    target_phys_addr_t iotlb;
+
+    assert(size >= TARGET_PAGE_SIZE);
+    if (size != TARGET_PAGE_SIZE) {
+        tlb_add_large_page(env, vaddr, size);
+    }
+    p = phys_page_find(paddr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+#if defined(DEBUG_TLB)
+    printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
+           " prot=%x idx=%d pd=0x%08lx\n",
+           vaddr, paddr, prot, mmu_idx, pd);
+#endif
+
+    address = vaddr;
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+        /* IO memory case (romd handled later) */
+        address |= TLB_MMIO;
+    }
+    addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
+    if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
+        /* Normal RAM.  */
+        iotlb = pd & TARGET_PAGE_MASK;
+        if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
+            iotlb |= IO_MEM_NOTDIRTY;
+        else
+            iotlb |= IO_MEM_ROM;
+    } else {
+        /* IO handlers are currently passed a physical address.
+           It would be nice to pass an offset from the base address
+           of that region.  This would avoid having to special case RAM,
+           and avoid full address decoding in every device.
+           We can't use the high bits of pd for this because
+           IO_MEM_ROMD uses these as a ram address.  */
+        iotlb = (pd & ~TARGET_PAGE_MASK);
+        if (p) {
+            iotlb += p->region_offset;
+        } else {
+            iotlb += paddr;
+        }
+    }
+
+    code_address = address;
+    /* Make accesses to pages with watchpoints go via the
+       watchpoint trap routines.  */
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
+            /* Avoid trapping reads of pages with a write breakpoint. */
+            if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
+                iotlb = io_mem_watch + paddr;
+                address |= TLB_MMIO;
+                break;
+            }
+        }
+    }
+
+    index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    env->iotlb[mmu_idx][index] = iotlb - vaddr;
+    te = &env->tlb_table[mmu_idx][index];
+    te->addend = addend - vaddr;
+    if (prot & PAGE_READ) {
+        te->addr_read = address;
+    } else {
+        te->addr_read = -1;
+    }
+
+    if (prot & PAGE_EXEC) {
+        te->addr_code = code_address;
+    } else {
+        te->addr_code = -1;
+    }
+    if (prot & PAGE_WRITE) {
+        if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
+            (pd & IO_MEM_ROMD)) {
+            /* Write access calls the I/O callback.  */
+            te->addr_write = address | TLB_MMIO;
+        } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
+                   !cpu_physical_memory_is_dirty(pd)) {
+            te->addr_write = address | TLB_NOTDIRTY;
+        } else {
+            te->addr_write = address;
+        }
+    } else {
+        te->addr_write = -1;
+    }
+}
+
+#else
+
+void tlb_flush(CPUState *env, int flush_global)
+{
+}
+
+void tlb_flush_page(CPUState *env, target_ulong addr)
+{
+}
+
+/*
+ * Walks guest process memory "regions" one by one
+ * and calls callback function 'fn' for each region.
+ */
+
+struct walk_memory_regions_data
+{
+    walk_memory_regions_fn fn;
+    void *priv;
+    unsigned long start;
+    int prot;
+};
+
+static int walk_memory_regions_end(struct walk_memory_regions_data *data,
+                                   abi_ulong end, int new_prot)
+{
+    if (data->start != -1ul) {
+        int rc = data->fn(data->priv, data->start, end, data->prot);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    data->start = (new_prot ? end : -1ul);
+    data->prot = new_prot;
+
+    return 0;
+}
+
+static int walk_memory_regions_1(struct walk_memory_regions_data *data,
+                                 abi_ulong base, int level, void **lp)
+{
+    abi_ulong pa;
+    int i, rc;
+
+    if (*lp == NULL) {
+        return walk_memory_regions_end(data, base, 0);
+    }
+
+    if (level == 0) {
+        PageDesc *pd = *lp;
+        for (i = 0; i < L2_SIZE; ++i) {
+            int prot = pd[i].flags;
+
+            pa = base | (i << TARGET_PAGE_BITS);
+            if (prot != data->prot) {
+                rc = walk_memory_regions_end(data, pa, prot);
+                if (rc != 0) {
+                    return rc;
+                }
+            }
+        }
+    } else {
+        void **pp = *lp;
+        for (i = 0; i < L2_SIZE; ++i) {
+            pa = base | ((abi_ulong)i <<
+                (TARGET_PAGE_BITS + L2_BITS * level));
+            rc = walk_memory_regions_1(data, pa, level - 1, pp + i);
+            if (rc != 0) {
+                return rc;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
+{
+    struct walk_memory_regions_data data;
+    unsigned long i;
+
+    data.fn = fn;
+    data.priv = priv;
+    data.start = -1ul;
+    data.prot = 0;
+
+    for (i = 0; i < V_L1_SIZE; i++) {
+        int rc = walk_memory_regions_1(&data, (abi_ulong)i << V_L1_SHIFT,
+                                       V_L1_SHIFT / L2_BITS - 1, l1_map + i);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    return walk_memory_regions_end(&data, 0, 0);
+}
+
+static int dump_region(void *priv, abi_ulong start,
+    abi_ulong end, unsigned long prot)
+{
+    FILE *f = (FILE *)priv;
+
+    (void) fprintf(f, TARGET_ABI_FMT_lx"-"TARGET_ABI_FMT_lx
+        " "TARGET_ABI_FMT_lx" %c%c%c\n",
+        start, end, end - start,
+        ((prot & PAGE_READ) ? 'r' : '-'),
+        ((prot & PAGE_WRITE) ? 'w' : '-'),
+        ((prot & PAGE_EXEC) ? 'x' : '-'));
+
+    return (0);
+}
+
+/* dump memory mappings */
+void page_dump(FILE *f)
+{
+    (void) fprintf(f, "%-8s %-8s %-8s %s\n",
+            "start", "end", "size", "prot");
+    walk_memory_regions(f, dump_region);
+}
+
+int page_get_flags(target_ulong address)
+{
+    PageDesc *p;
+
+    p = page_find(address >> TARGET_PAGE_BITS);
+    if (!p)
+        return 0;
+    return p->flags;
+}
+
+/* Modify the flags of a page and invalidate the code if necessary.
+   The flag PAGE_WRITE_ORG is positioned automatically depending
+   on PAGE_WRITE.  The mmap_lock should already be held.  */
+void page_set_flags(target_ulong start, target_ulong end, int flags)
+{
+    target_ulong addr, len;
+
+    /* This function should never be called with addresses outside the
+       guest address space.  If this assert fires, it probably indicates
+       a missing call to h2g_valid.  */
+#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
+    assert(end < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
+#endif
+    assert(start < end);
+
+    start = start & TARGET_PAGE_MASK;
+    end = TARGET_PAGE_ALIGN(end);
+
+    if (flags & PAGE_WRITE) {
+        flags |= PAGE_WRITE_ORG;
+    }
+
+    for (addr = start, len = end - start;
+         len != 0;
+         len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+        PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
+
+        /* If the write protection bit is set, then we invalidate
+           the code inside.  */
+        if (!(p->flags & PAGE_WRITE) &&
+            (flags & PAGE_WRITE) &&
+            p->first_tb) {
+            tb_invalidate_phys_page(addr, 0, NULL);
+        }
+        p->flags = flags;
+    }
+}
+
+int page_check_range(target_ulong start, target_ulong len, int flags)
+{
+    PageDesc *p;
+    target_ulong end;
+    target_ulong addr;
+
+    /* This function should never be called with addresses outside the
+       guest address space.  If this assert fires, it probably indicates
+       a missing call to h2g_valid.  */
+#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
+    assert(start < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
+#endif
+
+    if (len == 0) {
+        return 0;
+    }
+    if (start + len - 1 < start) {
+        /* We've wrapped around.  */
+        return -1;
+    }
+
+    end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
+    start = start & TARGET_PAGE_MASK;
+
+    for (addr = start, len = end - start;
+         len != 0;
+         len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+        p = page_find(addr >> TARGET_PAGE_BITS);
+        if( !p )
+            return -1;
+        if( !(p->flags & PAGE_VALID) )
+            return -1;
+
+        if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
+            return -1;
+        if (flags & PAGE_WRITE) {
+            if (!(p->flags & PAGE_WRITE_ORG))
+                return -1;
+            /* unprotect the page if it was put read-only because it
+               contains translated code */
+            if (!(p->flags & PAGE_WRITE)) {
+                if (!page_unprotect(addr, 0, NULL))
+                    return -1;
+            }
+            return 0;
+        }
+    }
+    return 0;
+}
+
+/* called from signal handler: invalidate the code and unprotect the
+   page. Return TRUE if the fault was successfully handled. */
+int page_unprotect(target_ulong address, unsigned long pc, void *puc)
+{
+    unsigned int prot;
+    PageDesc *p;
+    target_ulong host_start, host_end, addr;
+
+    /* Technically this isn't safe inside a signal handler.  However we
+       know this only ever happens in a synchronous SEGV handler, so in
+       practice it seems to be ok.  */
+    mmap_lock();
+
+    p = page_find(address >> TARGET_PAGE_BITS);
+    if (!p) {
+        mmap_unlock();
+        return 0;
+    }
+
+    /* if the page was really writable, then we change its
+       protection back to writable */
+    if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) {
+        host_start = address & qemu_host_page_mask;
+        host_end = host_start + qemu_host_page_size;
+
+        prot = 0;
+        for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
+            p = page_find(addr >> TARGET_PAGE_BITS);
+            p->flags |= PAGE_WRITE;
+            prot |= p->flags;
+
+            /* and since the content will be modified, we must invalidate
+               the corresponding translated code. */
+            tb_invalidate_phys_page(addr, pc, puc);
+#ifdef DEBUG_TB_CHECK
+            tb_invalidate_check(addr);
+#endif
+        }
+        mprotect((void *)g2h(host_start), qemu_host_page_size,
+                 prot & PAGE_BITS);
+
+        mmap_unlock();
+        return 1;
+    }
+    mmap_unlock();
+    return 0;
+}
+
+static inline void tlb_set_dirty(CPUState *env,
+                                 unsigned long addr, target_ulong vaddr)
+{
+}
+#endif /* defined(CONFIG_USER_ONLY) */
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
+typedef struct subpage_t {
+    target_phys_addr_t base;
+    ram_addr_t sub_io_index[TARGET_PAGE_SIZE];
+    ram_addr_t region_offset[TARGET_PAGE_SIZE];
+} subpage_t;
+
+static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
+                             ram_addr_t memory, ram_addr_t region_offset);
+static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
+                                ram_addr_t orig_memory,
+                                ram_addr_t region_offset);
+#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
+                      need_subpage)                                     \
+    do {                                                                \
+        if (addr > start_addr)                                          \
+            start_addr2 = 0;                                            \
+        else {                                                          \
+            start_addr2 = start_addr & ~TARGET_PAGE_MASK;               \
+            if (start_addr2 > 0)                                        \
+                need_subpage = 1;                                       \
+        }                                                               \
+                                                                        \
+        if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE)        \
+            end_addr2 = TARGET_PAGE_SIZE - 1;                           \
+        else {                                                          \
+            end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
+            if (end_addr2 < TARGET_PAGE_SIZE - 1)                       \
+                need_subpage = 1;                                       \
+        }                                                               \
+    } while (0)
+
+/* register physical memory.
+   For RAM, 'size' must be a multiple of the target page size.
+   If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+   io memory page.  The address used when calling the IO function is
+   the offset from the start of the region, plus region_offset.  Both
+   start_addr and region_offset are rounded down to a page boundary
+   before calculating this offset.  This should not be a problem unless
+   the low bits of start_addr and region_offset differ.  */
+void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset,
+                                         bool log_dirty)
+{
+    target_phys_addr_t addr, end_addr;
+    PhysPageDesc *p;
+    CPUState *env;
+    ram_addr_t orig_size = size;
+    subpage_t *subpage;
+
+    assert(size);
+    cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
+
+    if (phys_offset == IO_MEM_UNASSIGNED) {
+        region_offset = start_addr;
+    }
+    region_offset &= TARGET_PAGE_MASK;
+    size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+    end_addr = start_addr + (target_phys_addr_t)size;
+
+    addr = start_addr;
+    do {
+        p = phys_page_find(addr >> TARGET_PAGE_BITS);
+        if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
+            ram_addr_t orig_memory = p->phys_offset;
+            target_phys_addr_t start_addr2, end_addr2;
+            int need_subpage = 0;
+
+            CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
+                          need_subpage);
+            if (need_subpage) {
+                if (!(orig_memory & IO_MEM_SUBPAGE)) {
+                    subpage = subpage_init((addr & TARGET_PAGE_MASK),
+                                           &p->phys_offset, orig_memory,
+                                           p->region_offset);
+                } else {
+                    subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
+                                            >> IO_MEM_SHIFT];
+                }
+                subpage_register(subpage, start_addr2, end_addr2, phys_offset,
+                                 region_offset);
+                p->region_offset = 0;
+            } else {
+                p->phys_offset = phys_offset;
+                if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+                    (phys_offset & IO_MEM_ROMD))
+                    phys_offset += TARGET_PAGE_SIZE;
+            }
+        } else {
+            p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
+            p->phys_offset = phys_offset;
+            p->region_offset = region_offset;
+            if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+                (phys_offset & IO_MEM_ROMD)) {
+                phys_offset += TARGET_PAGE_SIZE;
+            } else {
+                target_phys_addr_t start_addr2, end_addr2;
+                int need_subpage = 0;
+
+                CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
+                              end_addr2, need_subpage);
+
+                if (need_subpage) {
+                    subpage = subpage_init((addr & TARGET_PAGE_MASK),
+                                           &p->phys_offset, IO_MEM_UNASSIGNED,
+                                           addr & TARGET_PAGE_MASK);
+                    subpage_register(subpage, start_addr2, end_addr2,
+                                     phys_offset, region_offset);
+                    p->region_offset = 0;
+                }
+            }
+        }
+        region_offset += TARGET_PAGE_SIZE;
+        addr += TARGET_PAGE_SIZE;
+    } while (addr != end_addr);
+
+    /* since each CPU stores ram addresses in its TLB cache, we must
+       reset the modified entries */
+    /* XXX: slow ! */
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        tlb_flush(env, 1);
+    }
+}
+
+/* XXX: temporary until new memory mapping API */
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
+{
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p)
+        return IO_MEM_UNASSIGNED;
+    return p->phys_offset;
+}
+
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+    if (kvm_enabled())
+        kvm_coalesce_mmio_region(addr, size);
+}
+
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+    if (kvm_enabled())
+        kvm_uncoalesce_mmio_region(addr, size);
+}
+
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+    if (kvm_enabled())
+        kvm_flush_coalesced_mmio_buffer();
+}
+
+#if defined(__linux__) && !defined(TARGET_S390X)
+
+#include <sys/vfs.h>
+
+#define HUGETLBFS_MAGIC       0x958458f6
+
+static long gethugepagesize(const char *path)
+{
+    struct statfs fs;
+    int ret;
+
+    do {
+        ret = statfs(path, &fs);
+    } while (ret != 0 && errno == EINTR);
+
+    if (ret != 0) {
+        perror(path);
+        return 0;
+    }
+
+    if (fs.f_type != HUGETLBFS_MAGIC)
+        fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
+
+    return fs.f_bsize;
+}
+
+static void *file_ram_alloc(RAMBlock *block,
+                            ram_addr_t memory,
+                            const char *path)
+{
+    char *filename;
+    void *area;
+    int fd;
+#ifdef MAP_POPULATE
+    int flags;
+#endif
+    unsigned long hpagesize;
+
+    hpagesize = gethugepagesize(path);
+    if (!hpagesize) {
+        return NULL;
+    }
+
+    if (memory < hpagesize) {
+        return NULL;
+    }
+
+    if (kvm_enabled() && !kvm_has_sync_mmu()) {
+        fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n");
+        return NULL;
+    }
+
+    if (asprintf(&filename, "%s/qemu_back_mem.XXXXXX", path) == -1) {
+        return NULL;
+    }
+
+    fd = mkstemp(filename);
+    if (fd < 0) {
+        perror("unable to create backing store for hugepages");
+        free(filename);
+        return NULL;
+    }
+    unlink(filename);
+    free(filename);
+
+    memory = (memory+hpagesize-1) & ~(hpagesize-1);
+
+    /*
+     * ftruncate is not supported by hugetlbfs in older
+     * hosts, so don't bother bailing out on errors.
+     * If anything goes wrong with it under other filesystems,
+     * mmap will fail.
+     */
+    if (ftruncate(fd, memory))
+        perror("ftruncate");
+
+#ifdef MAP_POPULATE
+    /* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case
+     * MAP_PRIVATE is requested.  For mem_prealloc we mmap as MAP_SHARED
+     * to sidestep this quirk.
+     */
+    flags = mem_prealloc ? MAP_POPULATE | MAP_SHARED : MAP_PRIVATE;
+    area = mmap(0, memory, PROT_READ | PROT_WRITE, flags, fd, 0);
+#else
+    area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+    if (area == MAP_FAILED) {
+        perror("file_ram_alloc: can't mmap RAM pages");
+        close(fd);
+        return (NULL);
+    }
+    block->fd = fd;
+    return area;
+}
+#endif
+
+static ram_addr_t find_ram_offset(ram_addr_t size)
+{
+    RAMBlock *block, *next_block;
+    ram_addr_t offset = 0, mingap = ULONG_MAX;
+
+    if (QLIST_EMPTY(&ram_list.blocks))
+        return 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        ram_addr_t end, next = ULONG_MAX;
+
+        end = block->offset + block->length;
+
+        QLIST_FOREACH(next_block, &ram_list.blocks, next) {
+            if (next_block->offset >= end) {
+                next = MIN(next, next_block->offset);
+            }
+        }
+        if (next - end >= size && next - end < mingap) {
+            offset =  end;
+            mingap = next - end;
+        }
+    }
+    return offset;
+}
+
+static ram_addr_t last_ram_offset(void)
+{
+    RAMBlock *block;
+    ram_addr_t last = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next)
+        last = MAX(last, block->offset + block->length);
+
+    return last;
+}
+
+ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
+                                   ram_addr_t size, void *host)
+{
+    RAMBlock *new_block, *block;
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_mallocz(sizeof(*new_block));
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *id = dev->parent_bus->info->get_dev_path(dev);
+        if (id) {
+            snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
+            qemu_free(id);
+        }
+    }
+    pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!strcmp(block->idstr, new_block->idstr)) {
+            fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
+                    new_block->idstr);
+            abort();
+        }
+    }
+
+    new_block->offset = find_ram_offset(size);
+    if (host) {
+        new_block->host = host;
+        new_block->flags |= RAM_PREALLOC_MASK;
+    } else {
+        if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+            new_block->host = file_ram_alloc(new_block, size, mem_path);
+            if (!new_block->host) {
+                new_block->host = qemu_vmalloc(size);
+                qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
+            }
+#else
+            fprintf(stderr, "-mem-path option unsupported\n");
+            exit(1);
+#endif
+        } else {
+#if defined(TARGET_S390X) && defined(CONFIG_KVM)
+            /* S390 KVM requires the topmost vma of the RAM to be smaller than
+               an system defined value, which is at least 256GB. Larger systems
+               have larger values. We put the guest between the end of data
+               segment (system break) and this value. We use 32GB as a base to
+               have enough room for the system break to grow. */
+            new_block->host = mmap((void*)0x800000000, size,
+                                   PROT_EXEC|PROT_READ|PROT_WRITE,
+                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+            if (new_block->host == MAP_FAILED) {
+                fprintf(stderr, "Allocating RAM failed\n");
+                abort();
+            }
+#else
+            if (xen_enabled()) {
+                xen_ram_alloc(new_block->offset, size);
+            } else {
+                new_block->host = qemu_vmalloc(size);
+            }
+#endif
+            qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
+        }
+    }
+    new_block->length = size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+                                       last_ram_offset() >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    if (kvm_enabled())
+        kvm_setup_guest_memory(new_block->host, size);
+
+    return new_block->offset;
+}
+
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+{
+    return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
+}
+
+void qemu_ram_free_from_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr == block->offset) {
+            QLIST_REMOVE(block, next);
+            qemu_free(block);
+            return;
+        }
+    }
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr == block->offset) {
+            QLIST_REMOVE(block, next);
+            if (block->flags & RAM_PREALLOC_MASK) {
+                ;
+            } else if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+                if (block->fd) {
+                    munmap(block->host, block->length);
+                    close(block->fd);
+                } else {
+                    qemu_vfree(block->host);
+                }
+#else
+                abort();
+#endif
+            } else {
+#if defined(TARGET_S390X) && defined(CONFIG_KVM)
+                munmap(block->host, block->length);
+#else
+                if (xen_enabled()) {
+                    xen_invalidate_map_cache_entry(block->host);
+                } else {
+                    qemu_vfree(block->host);
+                }
+#endif
+            }
+            qemu_free(block);
+            return;
+        }
+    }
+
+}
+
+#ifndef _WIN32
+void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
+{
+    RAMBlock *block;
+    ram_addr_t offset;
+    int flags;
+    void *area, *vaddr;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        offset = addr - block->offset;
+        if (offset < block->length) {
+            vaddr = block->host + offset;
+            if (block->flags & RAM_PREALLOC_MASK) {
+                ;
+            } else {
+                flags = MAP_FIXED;
+                munmap(vaddr, length);
+                if (mem_path) {
+#if defined(__linux__) && !defined(TARGET_S390X)
+                    if (block->fd) {
+#ifdef MAP_POPULATE
+                        flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
+                            MAP_PRIVATE;
+#else
+                        flags |= MAP_PRIVATE;
+#endif
+                        area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                    flags, block->fd, offset);
+                    } else {
+                        flags |= MAP_PRIVATE | MAP_ANONYMOUS;
+                        area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                    flags, -1, 0);
+                    }
+#else
+                    abort();
+#endif
+                } else {
+#if defined(TARGET_S390X) && defined(CONFIG_KVM)
+                    flags |= MAP_SHARED | MAP_ANONYMOUS;
+                    area = mmap(vaddr, length, PROT_EXEC|PROT_READ|PROT_WRITE,
+                                flags, -1, 0);
+#else
+                    flags |= MAP_PRIVATE | MAP_ANONYMOUS;
+                    area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+                                flags, -1, 0);
+#endif
+                }
+                if (area != vaddr) {
+                    fprintf(stderr, "Could not remap addr: %lx@%lx\n",
+                            length, addr);
+                    exit(1);
+                }
+                qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
+            }
+            return;
+        }
+    }
+}
+#endif /* !_WIN32 */
+
+/* Return a host pointer to ram allocated with qemu_ram_alloc.
+   With the exception of the softmmu code in this file, this should
+   only be used for local memory (e.g. video ram) that the device owns,
+   and knows it isn't going to access beyond the end of the block.
+
+   It should not be used for general purpose DMA.
+   Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
+ */
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr - block->offset < block->length) {
+            /* Move this entry to to start of the list.  */
+            if (block != QLIST_FIRST(&ram_list.blocks)) {
+                QLIST_REMOVE(block, next);
+                QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            }
+            if (xen_enabled()) {
+                /* We need to check if the requested address is in the RAM
+                 * because we don't want to map the entire memory in QEMU.
+                 * In that case just map until the end of the page.
+                 */
+                if (block->offset == 0) {
+                    return xen_map_cache(addr, 0, 0);
+                } else if (block->host == NULL) {
+                    block->host =
+                        xen_map_cache(block->offset, block->length, 1);
+                }
+            }
+            return block->host + (addr - block->offset);
+        }
+    }
+
+    fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+    abort();
+
+    return NULL;
+}
+
+/* Return a host pointer to ram allocated with qemu_ram_alloc.
+ * Same as qemu_get_ram_ptr but avoid reordering ramblocks.
+ */
+void *qemu_safe_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr - block->offset < block->length) {
+            if (xen_enabled()) {
+                /* We need to check if the requested address is in the RAM
+                 * because we don't want to map the entire memory in QEMU.
+                 * In that case just map until the end of the page.
+                 */
+                if (block->offset == 0) {
+                    return xen_map_cache(addr, 0, 0);
+                } else if (block->host == NULL) {
+                    block->host =
+                        xen_map_cache(block->offset, block->length, 1);
+                }
+            }
+            return block->host + (addr - block->offset);
+        }
+    }
+
+    fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+    abort();
+
+    return NULL;
+}
+
+/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
+ * but takes a size argument */
+void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
+{
+    if (*size == 0) {
+        return NULL;
+    }
+    if (xen_enabled()) {
+        return xen_map_cache(addr, *size, 1);
+    } else {
+        RAMBlock *block;
+
+        QLIST_FOREACH(block, &ram_list.blocks, next) {
+            if (addr - block->offset < block->length) {
+                if (addr - block->offset + *size > block->length)
+                    *size = block->length - addr + block->offset;
+                return block->host + (addr - block->offset);
+            }
+        }
+
+        fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+        abort();
+    }
+}
+
+void qemu_put_ram_ptr(void *addr)
+{
+    trace_qemu_put_ram_ptr(addr);
+}
+
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
+{
+    RAMBlock *block;
+    uint8_t *host = ptr;
+
+    if (xen_enabled()) {
+        *ram_addr = xen_ram_addr_from_mapcache(ptr);
+        return 0;
+    }
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        /* This case append when the block is not mapped. */
+        if (block->host == NULL) {
+            continue;
+        }
+        if (host - block->host < block->length) {
+            *ram_addr = block->offset + (host - block->host);
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+/* Some of the softmmu routines need to translate from a host pointer
+   (typically a TLB entry) back to a ram offset.  */
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
+{
+    ram_addr_t ram_addr;
+
+    if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
+        fprintf(stderr, "Bad ram pointer %p\n", ptr);
+        abort();
+    }
+    return ram_addr;
+}
+
+static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
+#endif
+    return 0;
+}
+
+static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
+#endif
+    return 0;
+}
+
+static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
+#endif
+    return 0;
+}
+
+static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
+#endif
+}
+
+static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
+#endif
+}
+
+static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
+#endif
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+    cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
+#endif
+}
+
+static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
+    unassigned_mem_readb,
+    unassigned_mem_readw,
+    unassigned_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
+    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    unassigned_mem_writel,
+};
+
+static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
+                                uint32_t val)
+{
+    int dirty_flags;
+    dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
+#if !defined(CONFIG_USER_ONLY)
+        tb_invalidate_phys_page_fast(ram_addr, 1);
+        dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+#endif
+    }
+    stb_p(qemu_get_ram_ptr(ram_addr), val);
+    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
+    /* we remove the notdirty callback only if the code has been
+       flushed */
+    if (dirty_flags == 0xff)
+        tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
+}
+
+static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
+                                uint32_t val)
+{
+    int dirty_flags;
+    dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
+#if !defined(CONFIG_USER_ONLY)
+        tb_invalidate_phys_page_fast(ram_addr, 2);
+        dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+#endif
+    }
+    stw_p(qemu_get_ram_ptr(ram_addr), val);
+    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
+    /* we remove the notdirty callback only if the code has been
+       flushed */
+    if (dirty_flags == 0xff)
+        tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
+}
+
+static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
+                                uint32_t val)
+{
+    int dirty_flags;
+    dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
+#if !defined(CONFIG_USER_ONLY)
+        tb_invalidate_phys_page_fast(ram_addr, 4);
+        dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
+#endif
+    }
+    stl_p(qemu_get_ram_ptr(ram_addr), val);
+    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
+    /* we remove the notdirty callback only if the code has been
+       flushed */
+    if (dirty_flags == 0xff)
+        tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
+}
+
+static CPUReadMemoryFunc * const error_mem_read[3] = {
+    NULL, /* never used */
+    NULL, /* never used */
+    NULL, /* never used */
+};
+
+static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
+    notdirty_mem_writeb,
+    notdirty_mem_writew,
+    notdirty_mem_writel,
+};
+
+/* Generate a debug exception if a watchpoint has been hit.  */
+static void check_watchpoint(int offset, int len_mask, int flags)
+{
+    CPUState *env = cpu_single_env;
+    target_ulong pc, cs_base;
+    TranslationBlock *tb;
+    target_ulong vaddr;
+    CPUWatchpoint *wp;
+    int cpu_flags;
+
+    if (env->watchpoint_hit) {
+        /* We re-entered the check after replacing the TB. Now raise
+         * the debug interrupt so that is will trigger after the
+         * current instruction. */
+        cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
+        return;
+    }
+    vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
+    QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if ((vaddr == (wp->vaddr & len_mask) ||
+             (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
+            wp->flags |= BP_WATCHPOINT_HIT;
+            if (!env->watchpoint_hit) {
+                env->watchpoint_hit = wp;
+                tb = tb_find_pc(env->mem_io_pc);
+                if (!tb) {
+                    cpu_abort(env, "check_watchpoint: could not find TB for "
+                              "pc=%p", (void *)env->mem_io_pc);
+                }
+                cpu_restore_state(tb, env, env->mem_io_pc);
+                tb_phys_invalidate(tb, -1);
+                if (wp->flags & BP_STOP_BEFORE_ACCESS) {
+                    env->exception_index = EXCP_DEBUG;
+                } else {
+                    cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
+                    tb_gen_code(env, pc, cs_base, cpu_flags, 1);
+                }
+                cpu_resume_from_signal(env, NULL);
+            }
+        } else {
+            wp->flags &= ~BP_WATCHPOINT_HIT;
+        }
+    }
+}
+
+/* Watchpoint access routines.  Watchpoints are inserted using TLB tricks,
+   so these check for a hit then pass through to the normal out-of-line
+   phys routines.  */
+static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
+    return ldub_phys(addr);
+}
+
+static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
+    return lduw_phys(addr);
+}
+
+static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
+    return ldl_phys(addr);
+}
+
+static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
+    stb_phys(addr, val);
+}
+
+static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
+    stw_phys(addr, val);
+}
+
+static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
+    stl_phys(addr, val);
+}
+
+static CPUReadMemoryFunc * const watch_mem_read[3] = {
+    watch_mem_readb,
+    watch_mem_readw,
+    watch_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const watch_mem_write[3] = {
+    watch_mem_writeb,
+    watch_mem_writew,
+    watch_mem_writel,
+};
+
+static inline uint32_t subpage_readlen (subpage_t *mmio,
+                                        target_phys_addr_t addr,
+                                        unsigned int len)
+{
+    unsigned int idx = SUBPAGE_IDX(addr);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
+           mmio, len, addr, idx);
+#endif
+
+    addr += mmio->region_offset[idx];
+    idx = mmio->sub_io_index[idx];
+    return io_mem_read[idx][len](io_mem_opaque[idx], addr);
+}
+
+static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
+                                     uint32_t value, unsigned int len)
+{
+    unsigned int idx = SUBPAGE_IDX(addr);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n",
+           __func__, mmio, len, addr, idx, value);
+#endif
+
+    addr += mmio->region_offset[idx];
+    idx = mmio->sub_io_index[idx];
+    io_mem_write[idx][len](io_mem_opaque[idx], addr, value);
+}
+
+static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
+{
+    return subpage_readlen(opaque, addr, 0);
+}
+
+static void subpage_writeb (void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    subpage_writelen(opaque, addr, value, 0);
+}
+
+static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
+{
+    return subpage_readlen(opaque, addr, 1);
+}
+
+static void subpage_writew (void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    subpage_writelen(opaque, addr, value, 1);
+}
+
+static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
+{
+    return subpage_readlen(opaque, addr, 2);
+}
+
+static void subpage_writel (void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    subpage_writelen(opaque, addr, value, 2);
+}
+
+static CPUReadMemoryFunc * const subpage_read[] = {
+    &subpage_readb,
+    &subpage_readw,
+    &subpage_readl,
+};
+
+static CPUWriteMemoryFunc * const subpage_write[] = {
+    &subpage_writeb,
+    &subpage_writew,
+    &subpage_writel,
+};
+
+static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
+                             ram_addr_t memory, ram_addr_t region_offset)
+{
+    int idx, eidx;
+
+    if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
+        return -1;
+    idx = SUBPAGE_IDX(start);
+    eidx = SUBPAGE_IDX(end);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
+           mmio, start, end, idx, eidx, memory);
+#endif
+    if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
+        memory = IO_MEM_UNASSIGNED;
+    memory = (memory >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+    for (; idx <= eidx; idx++) {
+        mmio->sub_io_index[idx] = memory;
+        mmio->region_offset[idx] = region_offset;
+    }
+
+    return 0;
+}
+
+static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
+                                ram_addr_t orig_memory,
+                                ram_addr_t region_offset)
+{
+    subpage_t *mmio;
+    int subpage_memory;
+
+    mmio = qemu_mallocz(sizeof(subpage_t));
+
+    mmio->base = base;
+    subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio,
+                                            DEVICE_NATIVE_ENDIAN);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
+           mmio, base, TARGET_PAGE_SIZE, subpage_memory);
+#endif
+    *phys = subpage_memory | IO_MEM_SUBPAGE;
+    subpage_register(mmio, 0, TARGET_PAGE_SIZE-1, orig_memory, region_offset);
+
+    return mmio;
+}
+
+static int get_free_io_mem_idx(void)
+{
+    int i;
+
+    for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
+        if (!io_mem_used[i]) {
+            io_mem_used[i] = 1;
+            return i;
+        }
+    fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
+    return -1;
+}
+
+/*
+ * Usually, devices operate in little endian mode. There are devices out
+ * there that operate in big endian too. Each device gets byte swapped
+ * mmio if plugged onto a CPU that does the other endianness.
+ *
+ * CPU          Device           swap?
+ *
+ * little       little           no
+ * little       big              yes
+ * big          little           yes
+ * big          big              no
+ */
+
+typedef struct SwapEndianContainer {
+    CPUReadMemoryFunc *read[3];
+    CPUWriteMemoryFunc *write[3];
+    void *opaque;
+} SwapEndianContainer;
+
+static uint32_t swapendian_mem_readb (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = c->read[0](c->opaque, addr);
+    return val;
+}
+
+static uint32_t swapendian_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = bswap16(c->read[1](c->opaque, addr));
+    return val;
+}
+
+static uint32_t swapendian_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = bswap32(c->read[2](c->opaque, addr));
+    return val;
+}
+
+static CPUReadMemoryFunc * const swapendian_readfn[3]={
+    swapendian_mem_readb,
+    swapendian_mem_readw,
+    swapendian_mem_readl
+};
+
+static void swapendian_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[0](c->opaque, addr, val);
+}
+
+static void swapendian_mem_writew(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[1](c->opaque, addr, bswap16(val));
+}
+
+static void swapendian_mem_writel(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[2](c->opaque, addr, bswap32(val));
+}
+
+static CPUWriteMemoryFunc * const swapendian_writefn[3]={
+    swapendian_mem_writeb,
+    swapendian_mem_writew,
+    swapendian_mem_writel
+};
+
+static void swapendian_init(int io_index)
+{
+    SwapEndianContainer *c = qemu_malloc(sizeof(SwapEndianContainer));
+    int i;
+
+    /* Swap mmio for big endian targets */
+    c->opaque = io_mem_opaque[io_index];
+    for (i = 0; i < 3; i++) {
+        c->read[i] = io_mem_read[io_index][i];
+        c->write[i] = io_mem_write[io_index][i];
+
+        io_mem_read[io_index][i] = swapendian_readfn[i];
+        io_mem_write[io_index][i] = swapendian_writefn[i];
+    }
+    io_mem_opaque[io_index] = c;
+}
+
+static void swapendian_del(int io_index)
+{
+    if (io_mem_read[io_index][0] == swapendian_readfn[0]) {
+        qemu_free(io_mem_opaque[io_index]);
+    }
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+   function to access byte (index 0), word (index 1) and dword (index
+   2). Functions can be omitted with a NULL function pointer.
+   If io_index is non zero, the corresponding io zone is
+   modified. If it is zero, a new io zone is allocated. The return
+   value can be used with cpu_register_physical_memory(). (-1) is
+   returned if error. */
+static int cpu_register_io_memory_fixed(int io_index,
+                                        CPUReadMemoryFunc * const *mem_read,
+                                        CPUWriteMemoryFunc * const *mem_write,
+                                        void *opaque, enum device_endian endian)
+{
+    int i;
+
+    if (io_index <= 0) {
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
+    } else {
+        io_index >>= IO_MEM_SHIFT;
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+    for (i = 0; i < 3; ++i) {
+        io_mem_read[io_index][i]
+            = (mem_read[i] ? mem_read[i] : unassigned_mem_read[i]);
+    }
+    for (i = 0; i < 3; ++i) {
+        io_mem_write[io_index][i]
+            = (mem_write[i] ? mem_write[i] : unassigned_mem_write[i]);
+    }
+    io_mem_opaque[io_index] = opaque;
+
+    switch (endian) {
+    case DEVICE_BIG_ENDIAN:
+#ifndef TARGET_WORDS_BIGENDIAN
+        swapendian_init(io_index);
+#endif
+        break;
+    case DEVICE_LITTLE_ENDIAN:
+#ifdef TARGET_WORDS_BIGENDIAN
+        swapendian_init(io_index);
+#endif
+        break;
+    case DEVICE_NATIVE_ENDIAN:
+    default:
+        break;
+    }
+
+    return (io_index << IO_MEM_SHIFT);
+}
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque, enum device_endian endian)
+{
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque, endian);
+}
+
+void cpu_unregister_io_memory(int io_table_address)
+{
+    int i;
+    int io_index = io_table_address >> IO_MEM_SHIFT;
+
+    swapendian_del(io_index);
+
+    for (i=0;i < 3; i++) {
+        io_mem_read[io_index][i] = unassigned_mem_read[i];
+        io_mem_write[io_index][i] = unassigned_mem_write[i];
+    }
+    io_mem_opaque[io_index] = NULL;
+    io_mem_used[io_index] = 0;
+}
+
+static void io_mem_init(void)
+{
+    int i;
+
+    cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read,
+                                 unassigned_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
+    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read,
+                                 unassigned_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
+    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
+                                 notdirty_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
+    for (i=0; i<5; i++)
+        io_mem_used[i] = 1;
+
+    io_mem_watch = cpu_register_io_memory(watch_mem_read,
+                                          watch_mem_write, NULL,
+                                          DEVICE_NATIVE_ENDIAN);
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* physical memory access (slow version, mainly for debug) */
+#if defined(CONFIG_USER_ONLY)
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write)
+{
+    int l, flags;
+    target_ulong page;
+    void * p;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        flags = page_get_flags(page);
+        if (!(flags & PAGE_VALID))
+            return -1;
+        if (is_write) {
+            if (!(flags & PAGE_WRITE))
+                return -1;
+            /* XXX: this code should not depend on lock_user */
+            if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
+                return -1;
+            memcpy(p, buf, l);
+            unlock_user(p, addr, l);
+        } else {
+            if (!(flags & PAGE_READ))
+                return -1;
+            /* XXX: this code should not depend on lock_user */
+            if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
+                return -1;
+            memcpy(buf, p, l);
+            unlock_user(p, addr, 0);
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+    return 0;
+}
+
+#else
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+                            int len, int is_write)
+{
+    int l, io_index;
+    uint8_t *ptr;
+    uint32_t val;
+    target_phys_addr_t page;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        p = phys_page_find(page >> TARGET_PAGE_BITS);
+        if (!p) {
+            pd = IO_MEM_UNASSIGNED;
+        } else {
+            pd = p->phys_offset;
+        }
+
+        if (is_write) {
+            if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+                target_phys_addr_t addr1 = addr;
+                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                if (p)
+                    addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+                /* XXX: could force cpu_single_env to NULL to avoid
+                   potential bugs */
+                if (l >= 4 && ((addr1 & 3) == 0)) {
+                    /* 32 bit write access */
+                    val = ldl_p(buf);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr1 & 1) == 0)) {
+                    /* 16 bit write access */
+                    val = lduw_p(buf);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
+                    l = 2;
+                } else {
+                    /* 8 bit write access */
+                    val = ldub_p(buf);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
+                    l = 1;
+                }
+            } else {
+                unsigned long addr1;
+                addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+                /* RAM case */
+                ptr = qemu_get_ram_ptr(addr1);
+                memcpy(ptr, buf, l);
+                if (!cpu_physical_memory_is_dirty(addr1)) {
+                    /* invalidate code */
+                    tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
+                    /* set dirty bit */
+                    cpu_physical_memory_set_dirty_flags(
+                        addr1, (0xff & ~CODE_DIRTY_FLAG));
+                }
+                qemu_put_ram_ptr(ptr);
+            }
+        } else {
+            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+                !(pd & IO_MEM_ROMD)) {
+                target_phys_addr_t addr1 = addr;
+                /* I/O case */
+                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                if (p)
+                    addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+                if (l >= 4 && ((addr1 & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
+                    stl_p(buf, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr1 & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
+                    stw_p(buf, val);
+                    l = 2;
+                } else {
+                    /* 8 bit read access */
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
+                    stb_p(buf, val);
+                    l = 1;
+                }
+            } else {
+                /* RAM case */
+                ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
+                memcpy(buf, ptr + (addr & ~TARGET_PAGE_MASK), l);
+                qemu_put_ram_ptr(ptr);
+            }
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+}
+
+/* used for ROM loading : can write in RAM and ROM */
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len)
+{
+    int l;
+    uint8_t *ptr;
+    target_phys_addr_t page;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        p = phys_page_find(page >> TARGET_PAGE_BITS);
+        if (!p) {
+            pd = IO_MEM_UNASSIGNED;
+        } else {
+            pd = p->phys_offset;
+        }
+
+        if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
+            (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
+            !(pd & IO_MEM_ROMD)) {
+            /* do nothing */
+        } else {
+            unsigned long addr1;
+            addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+            /* ROM/RAM case */
+            ptr = qemu_get_ram_ptr(addr1);
+            memcpy(ptr, buf, l);
+            qemu_put_ram_ptr(ptr);
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+}
+
+typedef struct {
+    void *buffer;
+    target_phys_addr_t addr;
+    target_phys_addr_t len;
+} BounceBuffer;
+
+static BounceBuffer bounce;
+
+typedef struct MapClient {
+    void *opaque;
+    void (*callback)(void *opaque);
+    QLIST_ENTRY(MapClient) link;
+} MapClient;
+
+static QLIST_HEAD(map_client_list, MapClient) map_client_list
+    = QLIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+    MapClient *client = qemu_malloc(sizeof(*client));
+
+    client->opaque = opaque;
+    client->callback = callback;
+    QLIST_INSERT_HEAD(&map_client_list, client, link);
+    return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+    MapClient *client = (MapClient *)_client;
+
+    QLIST_REMOVE(client, link);
+    qemu_free(client);
+}
+
+static void cpu_notify_map_clients(void)
+{
+    MapClient *client;
+
+    while (!QLIST_EMPTY(&map_client_list)) {
+        client = QLIST_FIRST(&map_client_list);
+        client->callback(client->opaque);
+        cpu_unregister_map_client(client);
+    }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write)
+{
+    target_phys_addr_t len = *plen;
+    target_phys_addr_t todo = 0;
+    int l;
+    target_phys_addr_t page;
+    unsigned long pd;
+    PhysPageDesc *p;
+    ram_addr_t raddr = ULONG_MAX;
+    ram_addr_t rlen;
+    void *ret;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        p = phys_page_find(page >> TARGET_PAGE_BITS);
+        if (!p) {
+            pd = IO_MEM_UNASSIGNED;
+        } else {
+            pd = p->phys_offset;
+        }
+
+        if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+            if (todo || bounce.buffer) {
+                break;
+            }
+            bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
+            bounce.addr = addr;
+            bounce.len = l;
+            if (!is_write) {
+                cpu_physical_memory_read(addr, bounce.buffer, l);
+            }
+
+            *plen = l;
+            return bounce.buffer;
+        }
+        if (!todo) {
+            raddr = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        }
+
+        len -= l;
+        addr += l;
+        todo += l;
+    }
+    rlen = todo;
+    ret = qemu_ram_ptr_length(raddr, &rlen);
+    *plen = rlen;
+    return ret;
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1.  access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len)
+{
+    if (buffer != bounce.buffer) {
+        if (is_write) {
+            ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
+            while (access_len) {
+                unsigned l;
+                l = TARGET_PAGE_SIZE;
+                if (l > access_len)
+                    l = access_len;
+                if (!cpu_physical_memory_is_dirty(addr1)) {
+                    /* invalidate code */
+                    tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
+                    /* set dirty bit */
+                    cpu_physical_memory_set_dirty_flags(
+                        addr1, (0xff & ~CODE_DIRTY_FLAG));
+                }
+                addr1 += l;
+                access_len -= l;
+            }
+        }
+        if (xen_enabled()) {
+            xen_invalidate_map_cache_entry(buffer);
+        }
+        return;
+    }
+    if (is_write) {
+        cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
+    }
+    qemu_vfree(bounce.buffer);
+    bounce.buffer = NULL;
+    cpu_notify_map_clients();
+}
+
+/* warning: addr must be aligned */
+static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
+                                         enum device_endian endian)
+{
+    int io_index;
+    uint8_t *ptr;
+    uint32_t val;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+        !(pd & IO_MEM_ROMD)) {
+        /* I/O case */
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap32(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap32(val);
+        }
+#endif
+    } else {
+        /* RAM case */
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
+            (addr & ~TARGET_PAGE_MASK);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = ldl_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = ldl_be_p(ptr);
+            break;
+        default:
+            val = ldl_p(ptr);
+            break;
+        }
+    }
+    return val;
+}
+
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint32_t ldl_le_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint32_t ldl_be_phys(target_phys_addr_t addr)
+{
+    return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
+/* warning: addr must be aligned */
+static inline uint64_t ldq_phys_internal(target_phys_addr_t addr,
+                                         enum device_endian endian)
+{
+    int io_index;
+    uint8_t *ptr;
+    uint64_t val;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+        !(pd & IO_MEM_ROMD)) {
+        /* I/O case */
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+
+        /* XXX This is broken when device endian != cpu endian.
+               Fix and add "endian" variable check */
+#ifdef TARGET_WORDS_BIGENDIAN
+        val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
+        val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
+#else
+        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+        val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
+#endif
+    } else {
+        /* RAM case */
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
+            (addr & ~TARGET_PAGE_MASK);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = ldq_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = ldq_be_p(ptr);
+            break;
+        default:
+            val = ldq_p(ptr);
+            break;
+        }
+    }
+    return val;
+}
+
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint64_t ldq_le_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint64_t ldq_be_phys(target_phys_addr_t addr)
+{
+    return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
+/* XXX: optimize */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+    uint8_t val;
+    cpu_physical_memory_read(addr, &val, 1);
+    return val;
+}
+
+/* warning: addr must be aligned */
+static inline uint32_t lduw_phys_internal(target_phys_addr_t addr,
+                                          enum device_endian endian)
+{
+    int io_index;
+    uint8_t *ptr;
+    uint64_t val;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+        !(pd & IO_MEM_ROMD)) {
+        /* I/O case */
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+        val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap16(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap16(val);
+        }
+#endif
+    } else {
+        /* RAM case */
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
+            (addr & ~TARGET_PAGE_MASK);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            val = lduw_le_p(ptr);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            val = lduw_be_p(ptr);
+            break;
+        default:
+            val = lduw_p(ptr);
+            break;
+        }
+    }
+    return val;
+}
+
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
+}
+
+uint32_t lduw_le_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
+}
+
+uint32_t lduw_be_phys(target_phys_addr_t addr)
+{
+    return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
+}
+
+/* warning: addr must be aligned. The ram page is not masked as dirty
+   and the code inside is not invalidated. It is useful if the dirty
+   bits are used to track modified PTEs */
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+    } else {
+        unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        ptr = qemu_get_ram_ptr(addr1);
+        stl_p(ptr, val);
+
+        if (unlikely(in_migration)) {
+            if (!cpu_physical_memory_is_dirty(addr1)) {
+                /* invalidate code */
+                tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+                /* set dirty bit */
+                cpu_physical_memory_set_dirty_flags(
+                    addr1, (0xff & ~CODE_DIRTY_FLAG));
+            }
+        }
+    }
+}
+
+void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+#ifdef TARGET_WORDS_BIGENDIAN
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
+#else
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
+#endif
+    } else {
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
+            (addr & ~TARGET_PAGE_MASK);
+        stq_p(ptr, val);
+    }
+}
+
+/* warning: addr must be aligned */
+static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val,
+                                     enum device_endian endian)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap32(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap32(val);
+        }
+#endif
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+    } else {
+        unsigned long addr1;
+        addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        /* RAM case */
+        ptr = qemu_get_ram_ptr(addr1);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            stl_le_p(ptr, val);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            stl_be_p(ptr, val);
+            break;
+        default:
+            stl_p(ptr, val);
+            break;
+        }
+        if (!cpu_physical_memory_is_dirty(addr1)) {
+            /* invalidate code */
+            tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+            /* set dirty bit */
+            cpu_physical_memory_set_dirty_flags(addr1,
+                (0xff & ~CODE_DIRTY_FLAG));
+        }
+    }
+}
+
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
+}
+
+void stl_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
+}
+
+void stl_be_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
+}
+
+/* XXX: optimize */
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t v = val;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+
+/* warning: addr must be aligned */
+static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val,
+                                     enum device_endian endian)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+#if defined(TARGET_WORDS_BIGENDIAN)
+        if (endian == DEVICE_LITTLE_ENDIAN) {
+            val = bswap16(val);
+        }
+#else
+        if (endian == DEVICE_BIG_ENDIAN) {
+            val = bswap16(val);
+        }
+#endif
+        io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+    } else {
+        unsigned long addr1;
+        addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        /* RAM case */
+        ptr = qemu_get_ram_ptr(addr1);
+        switch (endian) {
+        case DEVICE_LITTLE_ENDIAN:
+            stw_le_p(ptr, val);
+            break;
+        case DEVICE_BIG_ENDIAN:
+            stw_be_p(ptr, val);
+            break;
+        default:
+            stw_p(ptr, val);
+            break;
+        }
+        if (!cpu_physical_memory_is_dirty(addr1)) {
+            /* invalidate code */
+            tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
+            /* set dirty bit */
+            cpu_physical_memory_set_dirty_flags(addr1,
+                (0xff & ~CODE_DIRTY_FLAG));
+        }
+    }
+}
+
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
+}
+
+void stw_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
+}
+
+void stw_be_phys(target_phys_addr_t addr, uint32_t val)
+{
+    stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
+}
+
+/* XXX: optimize */
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = tswap64(val);
+    cpu_physical_memory_write(addr, &val, 8);
+}
+
+void stq_le_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = cpu_to_le64(val);
+    cpu_physical_memory_write(addr, &val, 8);
+}
+
+void stq_be_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = cpu_to_be64(val);
+    cpu_physical_memory_write(addr, &val, 8);
+}
+
+/* virtual memory access for debug (includes writing to ROM) */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write)
+{
+    int l;
+    target_phys_addr_t phys_addr;
+    target_ulong page;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        phys_addr = cpu_get_phys_page_debug(env, page);
+        /* if no physical page mapped, return an error */
+        if (phys_addr == -1)
+            return -1;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        phys_addr += (addr & ~TARGET_PAGE_MASK);
+        if (is_write)
+            cpu_physical_memory_write_rom(phys_addr, buf, l);
+        else
+            cpu_physical_memory_rw(phys_addr, buf, l, is_write);
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+    return 0;
+}
+#endif
+
+/* in deterministic execution mode, instructions doing device I/Os
+   must be at the end of the TB */
+void cpu_io_recompile(CPUState *env, void *retaddr)
+{
+    TranslationBlock *tb;
+    uint32_t n, cflags;
+    target_ulong pc, cs_base;
+    uint64_t flags;
+
+    tb = tb_find_pc((unsigned long)retaddr);
+    if (!tb) {
+        cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", 
+                  retaddr);
+    }
+    n = env->icount_decr.u16.low + tb->icount;
+    cpu_restore_state(tb, env, (unsigned long)retaddr);
+    /* Calculate how many instructions had been executed before the fault
+       occurred.  */
+    n = n - env->icount_decr.u16.low;
+    /* Generate a new TB ending on the I/O insn.  */
+    n++;
+    /* On MIPS and SH, delay slot instructions can only be restarted if
+       they were already the first instruction in the TB.  If this is not
+       the first instruction in a TB then re-execute the preceding
+       branch.  */
+#if defined(TARGET_MIPS)
+    if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
+        env->active_tc.PC -= 4;
+        env->icount_decr.u16.low++;
+        env->hflags &= ~MIPS_HFLAG_BMASK;
+    }
+#elif defined(TARGET_SH4)
+    if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
+            && n > 1) {
+        env->pc -= 2;
+        env->icount_decr.u16.low++;
+        env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
+    }
+#endif
+    /* This should never happen.  */
+    if (n > CF_COUNT_MASK)
+        cpu_abort(env, "TB too big during recompile");
+
+    cflags = n | CF_LAST_IO;
+    pc = tb->pc;
+    cs_base = tb->cs_base;
+    flags = tb->flags;
+    tb_phys_invalidate(tb, -1);
+    /* FIXME: In theory this could raise an exception.  In practice
+       we have already translated the block once so it's probably ok.  */
+    tb_gen_code(env, pc, cs_base, flags, cflags);
+    /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
+       the first in the TB) then we end up generating a whole new TB and
+       repeating the fault, which is horribly inefficient.
+       Better would be to execute just this insn uncached, or generate a
+       second new TB.  */
+    cpu_resume_from_signal(env, NULL);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i, target_code_size, max_target_code_size;
+    int direct_jmp_count, direct_jmp2_count, cross_page;
+    TranslationBlock *tb;
+
+    target_code_size = 0;
+    max_target_code_size = 0;
+    cross_page = 0;
+    direct_jmp_count = 0;
+    direct_jmp2_count = 0;
+    for(i = 0; i < nb_tbs; i++) {
+        tb = &tbs[i];
+        target_code_size += tb->size;
+        if (tb->size > max_target_code_size)
+            max_target_code_size = tb->size;
+        if (tb->page_addr[1] != -1)
+            cross_page++;
+        if (tb->tb_next_offset[0] != 0xffff) {
+            direct_jmp_count++;
+            if (tb->tb_next_offset[1] != 0xffff) {
+                direct_jmp2_count++;
+            }
+        }
+    }
+    /* XXX: avoid using doubles ? */
+    cpu_fprintf(f, "Translation buffer state:\n");
+    cpu_fprintf(f, "gen code size       %td/%ld\n",
+                code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
+    cpu_fprintf(f, "TB count            %d/%d\n", 
+                nb_tbs, code_gen_max_blocks);
+    cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
+                nb_tbs ? target_code_size / nb_tbs : 0,
+                max_target_code_size);
+    cpu_fprintf(f, "TB avg host size    %td bytes (expansion ratio: %0.1f)\n",
+                nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
+                target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
+    cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
+            cross_page,
+            nb_tbs ? (cross_page * 100) / nb_tbs : 0);
+    cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
+                direct_jmp_count,
+                nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
+                direct_jmp2_count,
+                nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
+    cpu_fprintf(f, "\nStatistics:\n");
+    cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count);
+    cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
+    cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
+    tcg_dump_info(f, cpu_fprintf);
+}
+
+#define MMUSUFFIX _cmmu
+#define GETPC() NULL
+#define env cpu_single_env
+#define SOFTMMU_CODE_ACCESS
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+#undef env
+
+#endif
diff --git a/qemu-0.15.x/fpu/softfloat-macros.h b/qemu-0.15.x/fpu/softfloat-macros.h
new file mode 100644
index 0000000..e82ce23
--- /dev/null
+++ b/qemu-0.15.x/fpu/softfloat-macros.h
@@ -0,0 +1,749 @@
+/*
+ * QEMU float support macros
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+| This macro tests for minimum version of the GNU C compiler.
+*----------------------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define SOFTFLOAT_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0
+#endif
+
+
+/*----------------------------------------------------------------------------
+| Shifts `a' right by the number of bits given in `count'.  If any nonzero
+| bits are shifted off, they are ``jammed'' into the least significant bit of
+| the result by setting the least significant bit to 1.  The value of `count'
+| can be arbitrarily large; in particular, if `count' is greater than 32, the
+| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+| The result is stored in the location pointed to by `zPtr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void shift32RightJamming( uint32_t a, int16 count, uint32_t *zPtr )
+{
+    uint32_t z;
+
+    if ( count == 0 ) {
+        z = a;
+    }
+    else if ( count < 32 ) {
+        z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+    }
+    else {
+        z = ( a != 0 );
+    }
+    *zPtr = z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts `a' right by the number of bits given in `count'.  If any nonzero
+| bits are shifted off, they are ``jammed'' into the least significant bit of
+| the result by setting the least significant bit to 1.  The value of `count'
+| can be arbitrarily large; in particular, if `count' is greater than 64, the
+| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+| The result is stored in the location pointed to by `zPtr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void shift64RightJamming( uint64_t a, int16 count, uint64_t *zPtr )
+{
+    uint64_t z;
+
+    if ( count == 0 ) {
+        z = a;
+    }
+    else if ( count < 64 ) {
+        z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
+    }
+    else {
+        z = ( a != 0 );
+    }
+    *zPtr = z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
+| _plus_ the number of bits given in `count'.  The shifted result is at most
+| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'.  The
+| bits shifted off form a second 64-bit result as follows:  The _last_ bit
+| shifted off is the most-significant bit of the extra result, and the other
+| 63 bits of the extra result are all zero if and only if _all_but_the_last_
+| bits shifted off were all zero.  This extra result is stored in the location
+| pointed to by `z1Ptr'.  The value of `count' can be arbitrarily large.
+|     (This routine makes more sense if `a0' and `a1' are considered to form
+| a fixed-point value with binary point between `a0' and `a1'.  This fixed-
+| point value is shifted right by the number of bits given in `count', and
+| the integer part of the result is returned at the location pointed to by
+| `z0Ptr'.  The fractional part of the result may be slightly corrupted as
+| described above, and is returned at the location pointed to by `z1Ptr'.)
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shift64ExtraRightJamming(
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+    uint64_t z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1 != 0 );
+        z0 = a0>>count;
+    }
+    else {
+        if ( count == 64 ) {
+            z1 = a0 | ( a1 != 0 );
+        }
+        else {
+            z1 = ( ( a0 | a1 ) != 0 );
+        }
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+| number of bits given in `count'.  Any bits shifted off are lost.  The value
+| of `count' can be arbitrarily large; in particular, if `count' is greater
+| than 128, the result will be 0.  The result is broken into two 64-bit pieces
+| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shift128Right(
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+    uint64_t z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count );
+        z0 = a0>>count;
+    }
+    else {
+        z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+| number of bits given in `count'.  If any nonzero bits are shifted off, they
+| are ``jammed'' into the least significant bit of the result by setting the
+| least significant bit to 1.  The value of `count' can be arbitrarily large;
+| in particular, if `count' is greater than 128, the result will be either
+| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+| nonzero.  The result is broken into two 64-bit pieces which are stored at
+| the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shift128RightJamming(
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+    uint64_t z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
+        z0 = a0>>count;
+    }
+    else {
+        if ( count == 64 ) {
+            z1 = a0 | ( a1 != 0 );
+        }
+        else if ( count < 128 ) {
+            z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
+        }
+        else {
+            z1 = ( ( a0 | a1 ) != 0 );
+        }
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
+| by 64 _plus_ the number of bits given in `count'.  The shifted result is
+| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
+| stored at the locations pointed to by `z0Ptr' and `z1Ptr'.  The bits shifted
+| off form a third 64-bit result as follows:  The _last_ bit shifted off is
+| the most-significant bit of the extra result, and the other 63 bits of the
+| extra result are all zero if and only if _all_but_the_last_ bits shifted off
+| were all zero.  This extra result is stored in the location pointed to by
+| `z2Ptr'.  The value of `count' can be arbitrarily large.
+|     (This routine makes more sense if `a0', `a1', and `a2' are considered
+| to form a fixed-point value with binary point between `a1' and `a2'.  This
+| fixed-point value is shifted right by the number of bits given in `count',
+| and the integer part of the result is returned at the locations pointed to
+| by `z0Ptr' and `z1Ptr'.  The fractional part of the result may be slightly
+| corrupted as described above, and is returned at the location pointed to by
+| `z2Ptr'.)
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shift128ExtraRightJamming(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     int16 count,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
+ )
+{
+    uint64_t z0, z1, z2;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z2 = a2;
+        z1 = a1;
+        z0 = a0;
+    }
+    else {
+        if ( count < 64 ) {
+            z2 = a1<<negCount;
+            z1 = ( a0<<negCount ) | ( a1>>count );
+            z0 = a0>>count;
+        }
+        else {
+            if ( count == 64 ) {
+                z2 = a1;
+                z1 = a0;
+            }
+            else {
+                a2 |= a1;
+                if ( count < 128 ) {
+                    z2 = a0<<negCount;
+                    z1 = a0>>( count & 63 );
+                }
+                else {
+                    z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
+                    z1 = 0;
+                }
+            }
+            z0 = 0;
+        }
+        z2 |= ( a2 != 0 );
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
+| number of bits given in `count'.  Any bits shifted off are lost.  The value
+| of `count' must be less than 64.  The result is broken into two 64-bit
+| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shortShift128Left(
+     uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+
+    *z1Ptr = a1<<count;
+    *z0Ptr =
+        ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
+| by the number of bits given in `count'.  Any bits shifted off are lost.
+| The value of `count' must be less than 64.  The result is broken into three
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+| `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ shortShift192Left(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     int16 count,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
+ )
+{
+    uint64_t z0, z1, z2;
+    int8 negCount;
+
+    z2 = a2<<count;
+    z1 = a1<<count;
+    z0 = a0<<count;
+    if ( 0 < count ) {
+        negCount = ( ( - count ) & 63 );
+        z1 |= a2>>negCount;
+        z0 |= a1>>negCount;
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
+| value formed by concatenating `b0' and `b1'.  Addition is modulo 2^128, so
+| any carry out is lost.  The result is broken into two 64-bit pieces which
+| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ add128(
+     uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+    uint64_t z1;
+
+    z1 = a1 + b1;
+    *z1Ptr = z1;
+    *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
+| 192-bit value formed by concatenating `b0', `b1', and `b2'.  Addition is
+| modulo 2^192, so any carry out is lost.  The result is broken into three
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+| `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ add192(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t b2,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
+ )
+{
+    uint64_t z0, z1, z2;
+    int8 carry0, carry1;
+
+    z2 = a2 + b2;
+    carry1 = ( z2 < a2 );
+    z1 = a1 + b1;
+    carry0 = ( z1 < a1 );
+    z0 = a0 + b0;
+    z1 += carry1;
+    z0 += ( z1 < carry1 );
+    z0 += carry0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
+| 128-bit value formed by concatenating `a0' and `a1'.  Subtraction is modulo
+| 2^128, so any borrow out (carry out) is lost.  The result is broken into two
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+| `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ sub128(
+     uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+
+    *z1Ptr = a1 - b1;
+    *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
+| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
+| Subtraction is modulo 2^192, so any borrow out (carry out) is lost.  The
+| result is broken into three 64-bit pieces which are stored at the locations
+| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ sub192(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t a2,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t b2,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
+ )
+{
+    uint64_t z0, z1, z2;
+    int8 borrow0, borrow1;
+
+    z2 = a2 - b2;
+    borrow1 = ( a2 < b2 );
+    z1 = a1 - b1;
+    borrow0 = ( a1 < b1 );
+    z0 = a0 - b0;
+    z0 -= ( z1 < borrow1 );
+    z1 -= borrow1;
+    z0 -= borrow0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Multiplies `a' by `b' to obtain a 128-bit product.  The product is broken
+| into two 64-bit pieces which are stored at the locations pointed to by
+| `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
+{
+    uint32_t aHigh, aLow, bHigh, bLow;
+    uint64_t z0, zMiddleA, zMiddleB, z1;
+
+    aLow = a;
+    aHigh = a>>32;
+    bLow = b;
+    bHigh = b>>32;
+    z1 = ( (uint64_t) aLow ) * bLow;
+    zMiddleA = ( (uint64_t) aLow ) * bHigh;
+    zMiddleB = ( (uint64_t) aHigh ) * bLow;
+    z0 = ( (uint64_t) aHigh ) * bHigh;
+    zMiddleA += zMiddleB;
+    z0 += ( ( (uint64_t) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
+    zMiddleA <<= 32;
+    z1 += zMiddleA;
+    z0 += ( z1 < zMiddleA );
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
+| `b' to obtain a 192-bit product.  The product is broken into three 64-bit
+| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+| `z2Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ mul128By64To192(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t b,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr
+ )
+{
+    uint64_t z0, z1, z2, more1;
+
+    mul64To128( a1, b, &z1, &z2 );
+    mul64To128( a0, b, &z0, &more1 );
+    add128( z0, more1, 0, z1, &z0, &z1 );
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
+| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
+| product.  The product is broken into four 64-bit pieces which are stored at
+| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+*----------------------------------------------------------------------------*/
+
+INLINE void
+ mul128To256(
+     uint64_t a0,
+     uint64_t a1,
+     uint64_t b0,
+     uint64_t b1,
+     uint64_t *z0Ptr,
+     uint64_t *z1Ptr,
+     uint64_t *z2Ptr,
+     uint64_t *z3Ptr
+ )
+{
+    uint64_t z0, z1, z2, z3;
+    uint64_t more1, more2;
+
+    mul64To128( a1, b1, &z2, &z3 );
+    mul64To128( a1, b0, &z1, &more2 );
+    add128( z1, more2, 0, z2, &z1, &z2 );
+    mul64To128( a0, b0, &z0, &more1 );
+    add128( z0, more1, 0, z1, &z0, &z1 );
+    mul64To128( a0, b1, &more1, &more2 );
+    add128( more1, more2, 0, z2, &more1, &z2 );
+    add128( z0, z1, 0, more1, &z0, &z1 );
+    *z3Ptr = z3;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns an approximation to the 64-bit integer quotient obtained by dividing
+| `b' into the 128-bit value formed by concatenating `a0' and `a1'.  The
+| divisor `b' must be at least 2^63.  If q is the exact quotient truncated
+| toward zero, the approximation returned lies between q and q + 2 inclusive.
+| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
+| unsigned integer is returned.
+*----------------------------------------------------------------------------*/
+
+static uint64_t estimateDiv128To64( uint64_t a0, uint64_t a1, uint64_t b )
+{
+    uint64_t b0, b1;
+    uint64_t rem0, rem1, term0, term1;
+    uint64_t z;
+
+    if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
+    b0 = b>>32;
+    z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
+    mul64To128( b, z, &term0, &term1 );
+    sub128( a0, a1, term0, term1, &rem0, &rem1 );
+    while ( ( (int64_t) rem0 ) < 0 ) {
+        z -= LIT64( 0x100000000 );
+        b1 = b<<32;
+        add128( rem0, rem1, b0, b1, &rem0, &rem1 );
+    }
+    rem0 = ( rem0<<32 ) | ( rem1>>32 );
+    z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns an approximation to the square root of the 32-bit significand given
+| by `a'.  Considered as an integer, `a' must be at least 2^31.  If bit 0 of
+| `aExp' (the least significant bit) is 1, the integer returned approximates
+| 2^31*sqrt(`a'/2^31), where `a' is considered an integer.  If bit 0 of `aExp'
+| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30).  In either
+| case, the approximation returned lies strictly within +/-2 of the exact
+| value.
+*----------------------------------------------------------------------------*/
+
+static uint32_t estimateSqrt32( int16 aExp, uint32_t a )
+{
+    static const uint16_t sqrtOddAdjustments[] = {
+        0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+        0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+    };
+    static const uint16_t sqrtEvenAdjustments[] = {
+        0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+        0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+    };
+    int8 index;
+    uint32_t z;
+
+    index = ( a>>27 ) & 15;
+    if ( aExp & 1 ) {
+        z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ];
+        z = ( ( a / z )<<14 ) + ( z<<15 );
+        a >>= 1;
+    }
+    else {
+        z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ];
+        z = a / z + z;
+        z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+        if ( z <= a ) return (uint32_t) ( ( (int32_t) a )>>1 );
+    }
+    return ( (uint32_t) ( ( ( (uint64_t) a )<<31 ) / z ) ) + ( z>>1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the number of leading 0 bits before the most-significant 1 bit of
+| `a'.  If `a' is zero, 32 is returned.
+*----------------------------------------------------------------------------*/
+
+static int8 countLeadingZeros32( uint32_t a )
+{
+#if SOFTFLOAT_GNUC_PREREQ(3, 4)
+    if (a) {
+        return __builtin_clz(a);
+    } else {
+        return 32;
+    }
+#else
+    static const int8 countLeadingZerosHigh[] = {
+        8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    int8 shiftCount;
+
+    shiftCount = 0;
+    if ( a < 0x10000 ) {
+        shiftCount += 16;
+        a <<= 16;
+    }
+    if ( a < 0x1000000 ) {
+        shiftCount += 8;
+        a <<= 8;
+    }
+    shiftCount += countLeadingZerosHigh[ a>>24 ];
+    return shiftCount;
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns the number of leading 0 bits before the most-significant 1 bit of
+| `a'.  If `a' is zero, 64 is returned.
+*----------------------------------------------------------------------------*/
+
+static int8 countLeadingZeros64( uint64_t a )
+{
+#if SOFTFLOAT_GNUC_PREREQ(3, 4)
+    if (a) {
+        return __builtin_clzll(a);
+    } else {
+        return 64;
+    }
+#else
+    int8 shiftCount;
+
+    shiftCount = 0;
+    if ( a < ( (uint64_t) 1 )<<32 ) {
+        shiftCount += 32;
+    }
+    else {
+        a >>= 32;
+    }
+    shiftCount += countLeadingZeros32( a );
+    return shiftCount;
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
+| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
+| Otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
+{
+
+    return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
+| Otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+| than the 128-bit value formed by concatenating `b0' and `b1'.  Otherwise,
+| returns 0.
+*----------------------------------------------------------------------------*/
+
+INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
+| not equal to the 128-bit value formed by concatenating `b0' and `b1'.
+| Otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+INLINE flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
+{
+
+    return ( a0 != b0 ) || ( a1 != b1 );
+
+}
diff --git a/qemu-0.15.x/fpu/softfloat-specialize.h b/qemu-0.15.x/fpu/softfloat-specialize.h
new file mode 100644
index 0000000..c7d35a1
--- /dev/null
+++ b/qemu-0.15.x/fpu/softfloat-specialize.h
@@ -0,0 +1,816 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+| Raises the exceptions specified by `flags'.  Floating-point traps can be
+| defined here if desired.  It is currently not possible for such a trap
+| to substitute a result value.  If traps are not implemented, this routine
+| should be simply `float_exception_flags |= flags;'.
+*----------------------------------------------------------------------------*/
+
+void float_raise( int8 flags STATUS_PARAM )
+{
+    STATUS(float_exception_flags) |= flags;
+}
+
+/*----------------------------------------------------------------------------
+| Internal canonical NaN format.
+*----------------------------------------------------------------------------*/
+typedef struct {
+    flag sign;
+    uint64_t high, low;
+} commonNaNT;
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the half-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float16_is_quiet_nan(float16 a_)
+{
+    uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+    return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#else
+    return ((a & ~0x8000) >= 0x7c80);
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the half-precision floating-point value `a' is a signaling
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float16_is_signaling_nan(float16 a_)
+{
+    uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+    return ((a & ~0x8000) >= 0x7c80);
+#else
+    return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the half-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+float16 float16_maybe_silence_nan(float16 a_)
+{
+    if (float16_is_signaling_nan(a_)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+        return float16_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        uint16_t a = float16_val(a_);
+        a |= (1 << 9);
+        return make_float16(a);
+#endif
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the half-precision floating-point NaN
+| `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float16ToCommonNaN( float16 a STATUS_PARAM )
+{
+    commonNaNT z;
+
+    if ( float16_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
+    z.sign = float16_val(a) >> 15;
+    z.low = 0;
+    z.high = ((uint64_t) float16_val(a))<<54;
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the half-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float16 commonNaNToFloat16(commonNaNT a STATUS_PARAM)
+{
+    uint16_t mantissa = a.high>>54;
+
+    if (STATUS(default_nan_mode)) {
+        return float16_default_nan;
+    }
+
+    if (mantissa) {
+        return make_float16(((((uint16_t) a.sign) << 15)
+                             | (0x1F << 10) | mantissa));
+    } else {
+        return float16_default_nan;
+    }
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float32_is_quiet_nan( float32 a_ )
+{
+    uint32_t a = float32_val(a_);
+#if SNAN_BIT_IS_ONE
+    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+#else
+    return ( 0xFF800000 <= (uint32_t) ( a<<1 ) );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a signaling
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float32_is_signaling_nan( float32 a_ )
+{
+    uint32_t a = float32_val(a_);
+#if SNAN_BIT_IS_ONE
+    return ( 0xFF800000 <= (uint32_t) ( a<<1 ) );
+#else
+    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the single-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float32 float32_maybe_silence_nan( float32 a_ )
+{
+    if (float32_is_signaling_nan(a_)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+        return float32_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        uint32_t a = float32_val(a_);
+        a |= (1 << 22);
+        return make_float32(a);
+#endif
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point NaN
+| `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
+{
+    commonNaNT z;
+
+    if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
+    z.sign = float32_val(a)>>31;
+    z.low = 0;
+    z.high = ( (uint64_t) float32_val(a) )<<41;
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the single-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float32 commonNaNToFloat32( commonNaNT a STATUS_PARAM)
+{
+    uint32_t mantissa = a.high>>41;
+
+    if ( STATUS(default_nan_mode) ) {
+        return float32_default_nan;
+    }
+
+    if ( mantissa )
+        return make_float32(
+            ( ( (uint32_t) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
+    else
+        return float32_default_nan;
+}
+
+/*----------------------------------------------------------------------------
+| Select which NaN to propagate for a two-input operation.
+| IEEE754 doesn't specify all the details of this, so the
+| algorithm is target-specific.
+| The routine is passed various bits of information about the
+| two NaNs and should return 0 to select NaN a and 1 for NaN b.
+| Note that signalling NaNs are always squashed to quiet NaNs
+| by the caller, by calling floatXX_maybe_silence_nan() before
+| returning them.
+|
+| aIsLargerSignificand is only valid if both a and b are NaNs
+| of some kind, and is true if a has the larger significand,
+| or if both a and b have the same significand but a is
+| positive but b is negative. It is only needed for the x87
+| tie-break rule.
+*----------------------------------------------------------------------------*/
+
+#if defined(TARGET_ARM)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* ARM mandated NaN propagation rules: take the first of:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always quietened before returning it.
+     */
+    if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#elif defined(TARGET_MIPS)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* According to MIPS specifications, if one of the two operands is
+     * a sNaN, a new qNaN has to be generated. This is done in
+     * floatXX_maybe_silence_nan(). For qNaN inputs the specifications
+     * says: "When possible, this QNaN result is one of the operand QNaN
+     * values." In practice it seems that most implementations choose
+     * the first operand if both operands are qNaN. In short this gives
+     * the following rules:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always silenced before returning it.
+     */
+    if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#elif defined(TARGET_PPC)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                   flag aIsLargerSignificand)
+{
+    /* PowerPC propagation rules:
+     *  1. A if it sNaN or qNaN
+     *  2. B if it sNaN or qNaN
+     * A signaling NaN is always silenced before returning it.
+     */
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#else
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* This implements x87 NaN propagation rules:
+     * SNaN + QNaN => return the QNaN
+     * two SNaNs => return the one with the larger significand, silenced
+     * two QNaNs => return the one with the larger significand
+     * SNaN and a non-NaN => return the SNaN, silenced
+     * QNaN and a non-NaN => return the QNaN
+     *
+     * If we get down to comparing significands and they are the same,
+     * return the NaN with the positive sign bit (if any).
+     */
+    if (aIsSNaN) {
+        if (bIsSNaN) {
+            return aIsLargerSignificand ? 0 : 1;
+        }
+        return bIsQNaN ? 1 : 0;
+    }
+    else if (aIsQNaN) {
+        if (bIsSNaN || !bIsQNaN)
+            return 0;
+        else {
+            return aIsLargerSignificand ? 0 : 1;
+        }
+    } else {
+        return 1;
+    }
+}
+#endif
+
+/*----------------------------------------------------------------------------
+| Takes two single-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
+    uint32_t av, bv;
+
+    aIsQuietNaN = float32_is_quiet_nan( a );
+    aIsSignalingNaN = float32_is_signaling_nan( a );
+    bIsQuietNaN = float32_is_quiet_nan( b );
+    bIsSignalingNaN = float32_is_signaling_nan( b );
+    av = float32_val(a);
+    bv = float32_val(b);
+
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+
+    if ( STATUS(default_nan_mode) )
+        return float32_default_nan;
+
+    if ((uint32_t)(av<<1) < (uint32_t)(bv<<1)) {
+        aIsLargerSignificand = 0;
+    } else if ((uint32_t)(bv<<1) < (uint32_t)(av<<1)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (av < bv) ? 1 : 0;
+    }
+
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
+        return float32_maybe_silence_nan(b);
+    } else {
+        return float32_maybe_silence_nan(a);
+    }
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float64_is_quiet_nan( float64 a_ )
+{
+    uint64_t a = float64_val(a_);
+#if SNAN_BIT_IS_ONE
+    return
+           ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+        && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+#else
+    return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is a signaling
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float64_is_signaling_nan( float64 a_ )
+{
+    uint64_t a = float64_val(a_);
+#if SNAN_BIT_IS_ONE
+    return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) );
+#else
+    return
+           ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+        && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the double-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float64 float64_maybe_silence_nan( float64 a_ )
+{
+    if (float64_is_signaling_nan(a_)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+        return float64_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        uint64_t a = float64_val(a_);
+        a |= LIT64( 0x0008000000000000 );
+        return make_float64(a);
+#endif
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point NaN
+| `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
+{
+    commonNaNT z;
+
+    if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
+    z.sign = float64_val(a)>>63;
+    z.low = 0;
+    z.high = float64_val(a)<<12;
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the double-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float64 commonNaNToFloat64( commonNaNT a STATUS_PARAM)
+{
+    uint64_t mantissa = a.high>>12;
+
+    if ( STATUS(default_nan_mode) ) {
+        return float64_default_nan;
+    }
+
+    if ( mantissa )
+        return make_float64(
+              ( ( (uint64_t) a.sign )<<63 )
+            | LIT64( 0x7FF0000000000000 )
+            | ( a.high>>12 ));
+    else
+        return float64_default_nan;
+}
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
+    uint64_t av, bv;
+
+    aIsQuietNaN = float64_is_quiet_nan( a );
+    aIsSignalingNaN = float64_is_signaling_nan( a );
+    bIsQuietNaN = float64_is_quiet_nan( b );
+    bIsSignalingNaN = float64_is_signaling_nan( b );
+    av = float64_val(a);
+    bv = float64_val(b);
+
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+
+    if ( STATUS(default_nan_mode) )
+        return float64_default_nan;
+
+    if ((uint64_t)(av<<1) < (uint64_t)(bv<<1)) {
+        aIsLargerSignificand = 0;
+    } else if ((uint64_t)(bv<<1) < (uint64_t)(av<<1)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (av < bv) ? 1 : 0;
+    }
+
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
+        return float64_maybe_silence_nan(b);
+    } else {
+        return float64_maybe_silence_nan(a);
+    }
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is a
+| quiet NaN; otherwise returns 0. This slightly differs from the same
+| function for other types as floatx80 has an explicit bit.
+*----------------------------------------------------------------------------*/
+
+int floatx80_is_quiet_nan( floatx80 a )
+{
+#if SNAN_BIT_IS_ONE
+    uint64_t aLow;
+
+    aLow = a.low & ~ LIT64( 0x4000000000000000 );
+    return
+           ( ( a.high & 0x7FFF ) == 0x7FFF )
+        && (uint64_t) ( aLow<<1 )
+        && ( a.low == aLow );
+#else
+    return ( ( a.high & 0x7FFF ) == 0x7FFF )
+        && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 )));
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is a
+| signaling NaN; otherwise returns 0. This slightly differs from the same
+| function for other types as floatx80 has an explicit bit.
+*----------------------------------------------------------------------------*/
+
+int floatx80_is_signaling_nan( floatx80 a )
+{
+#if SNAN_BIT_IS_ONE
+    return ( ( a.high & 0x7FFF ) == 0x7FFF )
+        && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 )));
+#else
+    uint64_t aLow;
+
+    aLow = a.low & ~ LIT64( 0x4000000000000000 );
+    return
+           ( ( a.high & 0x7FFF ) == 0x7FFF )
+        && (uint64_t) ( aLow<<1 )
+        && ( a.low == aLow );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the extended double-precision floating point value
+| `a' is a signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_maybe_silence_nan( floatx80 a )
+{
+    if (floatx80_is_signaling_nan(a)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+        a.low = floatx80_default_nan_low;
+        a.high = floatx80_default_nan_high;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        a.low |= LIT64( 0xC000000000000000 );
+        return a;
+#endif
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point NaN `a' to the canonical NaN format.  If `a' is a signaling NaN, the
+| invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
+{
+    commonNaNT z;
+
+    if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
+    if ( a.low >> 63 ) {
+        z.sign = a.high >> 15;
+        z.low = 0;
+        z.high = a.low << 1;
+    } else {
+        z.sign = floatx80_default_nan_high >> 15;
+        z.low = 0;
+        z.high = floatx80_default_nan_low << 1;
+    }
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the extended
+| double-precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM)
+{
+    floatx80 z;
+
+    if ( STATUS(default_nan_mode) ) {
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+
+    if (a.high >> 1) {
+        z.low = LIT64( 0x8000000000000000 ) | a.high >> 1;
+        z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
+    } else {
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+    }
+
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Takes two extended double-precision floating-point values `a' and `b', one
+| of which is a NaN, and returns the appropriate NaN result.  If either `a' or
+| `b' is a signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
+
+    aIsQuietNaN = floatx80_is_quiet_nan( a );
+    aIsSignalingNaN = floatx80_is_signaling_nan( a );
+    bIsQuietNaN = floatx80_is_quiet_nan( b );
+    bIsSignalingNaN = floatx80_is_signaling_nan( b );
+
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+
+    if ( STATUS(default_nan_mode) ) {
+        a.low = floatx80_default_nan_low;
+        a.high = floatx80_default_nan_high;
+        return a;
+    }
+
+    if (a.low < b.low) {
+        aIsLargerSignificand = 0;
+    } else if (b.low < a.low) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
+    }
+
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
+        return floatx80_maybe_silence_nan(b);
+    } else {
+        return floatx80_maybe_silence_nan(a);
+    }
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float128_is_quiet_nan( float128 a )
+{
+#if SNAN_BIT_IS_ONE
+    return
+           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+#else
+    return
+           ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) )
+        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is a
+| signaling NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float128_is_signaling_nan( float128 a )
+{
+#if SNAN_BIT_IS_ONE
+    return
+           ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) )
+        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+#else
+    return
+           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the quadruple-precision floating point value `a' is
+| a signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float128 float128_maybe_silence_nan( float128 a )
+{
+    if (float128_is_signaling_nan(a)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+        a.low = float128_default_nan_low;
+        a.high = float128_default_nan_high;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        a.high |= LIT64( 0x0000800000000000 );
+        return a;
+#endif
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point NaN
+| `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
+{
+    commonNaNT z;
+
+    if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
+    z.sign = a.high>>63;
+    shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the quadruple-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float128 commonNaNToFloat128( commonNaNT a STATUS_PARAM)
+{
+    float128 z;
+
+    if ( STATUS(default_nan_mode) ) {
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+
+    shift128Right( a.high, a.low, 16, &z.high, &z.low );
+    z.high |= ( ( (uint64_t) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Takes two quadruple-precision floating-point values `a' and `b', one of
+| which is a NaN, and returns the appropriate NaN result.  If either `a' or
+| `b' is a signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
+
+    aIsQuietNaN = float128_is_quiet_nan( a );
+    aIsSignalingNaN = float128_is_signaling_nan( a );
+    bIsQuietNaN = float128_is_quiet_nan( b );
+    bIsSignalingNaN = float128_is_signaling_nan( b );
+
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+
+    if ( STATUS(default_nan_mode) ) {
+        a.low = float128_default_nan_low;
+        a.high = float128_default_nan_high;
+        return a;
+    }
+
+    if (lt128(a.high<<1, a.low, b.high<<1, b.low)) {
+        aIsLargerSignificand = 0;
+    } else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
+    }
+
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
+        return float128_maybe_silence_nan(b);
+    } else {
+        return float128_maybe_silence_nan(a);
+    }
+}
+
diff --git a/qemu-0.15.x/fpu/softfloat.c b/qemu-0.15.x/fpu/softfloat.c
new file mode 100644
index 0000000..7951a0e
--- /dev/null
+++ b/qemu-0.15.x/fpu/softfloat.c
@@ -0,0 +1,6430 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
+Package, Release 2b.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Primitive arithmetic functions, including multi-word arithmetic, and
+| division and square root approximations.  (Can be specialized to target if
+| desired.)
+*----------------------------------------------------------------------------*/
+#include "softfloat-macros.h"
+
+/*----------------------------------------------------------------------------
+| Functions and definitions to determine:  (1) whether tininess for underflow
+| is detected before or after rounding by default, (2) what (if anything)
+| happens when exceptions are raised, (3) how signaling NaNs are distinguished
+| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
+| are propagated from function inputs to output.  These details are target-
+| specific.
+*----------------------------------------------------------------------------*/
+#include "softfloat-specialize.h"
+
+void set_float_rounding_mode(int val STATUS_PARAM)
+{
+    STATUS(float_rounding_mode) = val;
+}
+
+void set_float_exception_flags(int val STATUS_PARAM)
+{
+    STATUS(float_exception_flags) = val;
+}
+
+void set_floatx80_rounding_precision(int val STATUS_PARAM)
+{
+    STATUS(floatx80_rounding_precision) = val;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the half-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint32_t extractFloat16Frac(float16 a)
+{
+    return float16_val(a) & 0x3ff;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the half-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int16 extractFloat16Exp(float16 a)
+{
+    return (float16_val(a) >> 10) & 0x1f;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloat16Sign(float16 a)
+{
+    return float16_val(a)>>15;
+}
+
+/*----------------------------------------------------------------------------
+| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
+| and 7, and returns the properly rounded 32-bit integer corresponding to the
+| input.  If `zSign' is 1, the input is negated before being converted to an
+| integer.  Bit 63 of `absZ' must be zero.  Ordinarily, the fixed-point input
+| is simply rounded to an integer, with the inexact exception raised if the
+| input cannot be represented exactly as an integer.  However, if the fixed-
+| point input is too large, the invalid exception is raised and the largest
+| positive or negative integer is returned.
+*----------------------------------------------------------------------------*/
+
+static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int8 roundIncrement, roundBits;
+    int32 z;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x40;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x7F;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = absZ & 0x7F;
+    absZ = ( absZ + roundIncrement )>>7;
+    absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+    z = absZ;
+    if ( zSign ) z = - z;
+    if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return zSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
+| `absZ1', with binary point between bits 63 and 64 (between the input words),
+| and returns the properly rounded 64-bit integer corresponding to the input.
+| If `zSign' is 1, the input is negated before being converted to an integer.
+| Ordinarily, the fixed-point input is simply rounded to an integer, with
+| the inexact exception raised if the input cannot be represented exactly as
+| an integer.  However, if the fixed-point input is too large, the invalid
+| exception is raised and the largest positive or negative integer is
+| returned.
+*----------------------------------------------------------------------------*/
+
+static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven, increment;
+    int64 z;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    increment = ( (int64_t) absZ1 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        }
+        else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && absZ1;
+            }
+            else {
+                increment = ( roundingMode == float_round_up ) && absZ1;
+            }
+        }
+    }
+    if ( increment ) {
+        ++absZ0;
+        if ( absZ0 == 0 ) goto overflow;
+        absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven );
+    }
+    z = absZ0;
+    if ( zSign ) z = - z;
+    if ( z && ( ( z < 0 ) ^ zSign ) ) {
+ overflow:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return
+              zSign ? (int64_t) LIT64( 0x8000000000000000 )
+            : LIT64( 0x7FFFFFFFFFFFFFFF );
+    }
+    if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint32_t extractFloat32Frac( float32 a )
+{
+
+    return float32_val(a) & 0x007FFFFF;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+    return ( float32_val(a)>>23 ) & 0xFF;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+    return float32_val(a)>>31;
+
+}
+
+/*----------------------------------------------------------------------------
+| If `a' is denormal and we are in flush-to-zero mode then set the
+| input-denormal exception and return zero. Otherwise just return the value.
+*----------------------------------------------------------------------------*/
+static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
+{
+    if (STATUS(flush_inputs_to_zero)) {
+        if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
+            float_raise(float_flag_input_denormal STATUS_VAR);
+            return make_float32(float32_val(a) & 0x80000000);
+        }
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal single-precision floating-point value represented
+| by the denormalized significand `aSig'.  The normalized exponent and
+| significand are stored at the locations pointed to by `zExpPtr' and
+| `zSigPtr', respectively.
+*----------------------------------------------------------------------------*/
+
+static void
+ normalizeFloat32Subnormal( uint32_t aSig, int16 *zExpPtr, uint32_t *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( aSig ) - 8;
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+| single-precision floating-point value, returning the result.  After being
+| shifted into the proper positions, the three fields are simply added
+| together to form the result.  This means that any integer portion of `zSig'
+| will be added into the exponent.  Since a properly normalized significand
+| will have an integer portion equal to 1, the `zExp' input should be 1 less
+| than the desired result exponent whenever `zSig' is a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+
+INLINE float32 packFloat32( flag zSign, int16 zExp, uint32_t zSig )
+{
+
+    return make_float32(
+          ( ( (uint32_t) zSign )<<31 ) + ( ( (uint32_t) zExp )<<23 ) + zSig);
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper single-precision floating-
+| point value corresponding to the abstract input.  Ordinarily, the abstract
+| value is simply rounded and packed into the single-precision format, with
+| the inexact exception raised if the abstract input cannot be represented
+| exactly.  However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned.  If the abstract value is too small, the input value is rounded to
+| a subnormal number, and the underflow and inexact exceptions are raised if
+| the abstract input cannot be represented exactly as a subnormal single-
+| precision floating-point number.
+|     The input significand `zSig' has its binary point between bits 30
+| and 29, which is 7 bits to the left of the usual location.  This shifted
+| significand must be normalized or smaller.  If `zSig' is not normalized,
+| `zExp' must be 0; in that case, the result returned is a subnormal number,
+| and it must not require rounding.  In the usual case that `zSig' is
+| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+| The handling of underflow and overflow follows the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int8 roundIncrement, roundBits;
+    flag isTiny;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x40;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x7F;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig & 0x7F;
+    if ( 0xFD <= (uint16_t) zExp ) {
+        if (    ( 0xFD < zExp )
+             || (    ( zExp == 0xFD )
+                  && ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
+        }
+        if ( zExp < 0 ) {
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat32(zSign, 0, 0);
+            }
+            isTiny =
+                   ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ( zSig + roundIncrement < 0x80000000 );
+            shift32RightJamming( zSig, - zExp, &zSig );
+            zExp = 0;
+            roundBits = zSig & 0x7F;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR);
+        }
+    }
+    if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
+    zSig = ( zSig + roundIncrement )>>7;
+    zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+    if ( zSig == 0 ) zExp = 0;
+    return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper single-precision floating-
+| point value corresponding to the abstract input.  This routine is just like
+| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
+| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+| floating-point exponent.
+*----------------------------------------------------------------------------*/
+
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM)
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( zSig ) - 1;
+    return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount STATUS_VAR);
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint64_t extractFloat64Frac( float64 a )
+{
+
+    return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int16 extractFloat64Exp( float64 a )
+{
+
+    return ( float64_val(a)>>52 ) & 0x7FF;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloat64Sign( float64 a )
+{
+
+    return float64_val(a)>>63;
+
+}
+
+/*----------------------------------------------------------------------------
+| If `a' is denormal and we are in flush-to-zero mode then set the
+| input-denormal exception and return zero. Otherwise just return the value.
+*----------------------------------------------------------------------------*/
+static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
+{
+    if (STATUS(flush_inputs_to_zero)) {
+        if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
+            float_raise(float_flag_input_denormal STATUS_VAR);
+            return make_float64(float64_val(a) & (1ULL << 63));
+        }
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal double-precision floating-point value represented
+| by the denormalized significand `aSig'.  The normalized exponent and
+| significand are stored at the locations pointed to by `zExpPtr' and
+| `zSigPtr', respectively.
+*----------------------------------------------------------------------------*/
+
+static void
+ normalizeFloat64Subnormal( uint64_t aSig, int16 *zExpPtr, uint64_t *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( aSig ) - 11;
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+| double-precision floating-point value, returning the result.  After being
+| shifted into the proper positions, the three fields are simply added
+| together to form the result.  This means that any integer portion of `zSig'
+| will be added into the exponent.  Since a properly normalized significand
+| will have an integer portion equal to 1, the `zExp' input should be 1 less
+| than the desired result exponent whenever `zSig' is a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+
+INLINE float64 packFloat64( flag zSign, int16 zExp, uint64_t zSig )
+{
+
+    return make_float64(
+        ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<52 ) + zSig);
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper double-precision floating-
+| point value corresponding to the abstract input.  Ordinarily, the abstract
+| value is simply rounded and packed into the double-precision format, with
+| the inexact exception raised if the abstract input cannot be represented
+| exactly.  However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned.  If the abstract value is too small, the input value is rounded
+| to a subnormal number, and the underflow and inexact exceptions are raised
+| if the abstract input cannot be represented exactly as a subnormal double-
+| precision floating-point number.
+|     The input significand `zSig' has its binary point between bits 62
+| and 61, which is 10 bits to the left of the usual location.  This shifted
+| significand must be normalized or smaller.  If `zSig' is not normalized,
+| `zExp' must be 0; in that case, the result returned is a subnormal number,
+| and it must not require rounding.  In the usual case that `zSig' is
+| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+| The handling of underflow and overflow follows the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float64 roundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int16 roundIncrement, roundBits;
+    flag isTiny;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x200;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x3FF;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig & 0x3FF;
+    if ( 0x7FD <= (uint16_t) zExp ) {
+        if (    ( 0x7FD < zExp )
+             || (    ( zExp == 0x7FD )
+                  && ( (int64_t) ( zSig + roundIncrement ) < 0 ) )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
+        }
+        if ( zExp < 0 ) {
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat64(zSign, 0, 0);
+            }
+            isTiny =
+                   ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) );
+            shift64RightJamming( zSig, - zExp, &zSig );
+            zExp = 0;
+            roundBits = zSig & 0x3FF;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR);
+        }
+    }
+    if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
+    zSig = ( zSig + roundIncrement )>>10;
+    zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
+    if ( zSig == 0 ) zExp = 0;
+    return packFloat64( zSign, zExp, zSig );
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper double-precision floating-
+| point value corresponding to the abstract input.  This routine is just like
+| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
+| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+| floating-point exponent.
+*----------------------------------------------------------------------------*/
+
+static float64
+ normalizeRoundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM)
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( zSig ) - 1;
+    return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount STATUS_VAR);
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the extended double-precision floating-point
+| value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint64_t extractFloatx80Frac( floatx80 a )
+{
+
+    return a.low;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the extended double-precision floating-point
+| value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int32 extractFloatx80Exp( floatx80 a )
+{
+
+    return a.high & 0x7FFF;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the extended double-precision floating-point value
+| `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloatx80Sign( floatx80 a )
+{
+
+    return a.high>>15;
+
+}
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal extended double-precision floating-point value
+| represented by the denormalized significand `aSig'.  The normalized exponent
+| and significand are stored at the locations pointed to by `zExpPtr' and
+| `zSigPtr', respectively.
+*----------------------------------------------------------------------------*/
+
+static void
+ normalizeFloatx80Subnormal( uint64_t aSig, int32 *zExpPtr, uint64_t *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( aSig );
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
+| extended double-precision floating-point value, returning the result.
+*----------------------------------------------------------------------------*/
+
+INLINE floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
+{
+    floatx80 z;
+
+    z.low = zSig;
+    z.high = ( ( (uint16_t) zSign )<<15 ) + zExp;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and extended significand formed by the concatenation of `zSig0' and `zSig1',
+| and returns the proper extended double-precision floating-point value
+| corresponding to the abstract input.  Ordinarily, the abstract value is
+| rounded and packed into the extended double-precision format, with the
+| inexact exception raised if the abstract input cannot be represented
+| exactly.  However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned.  If the abstract value is too small, the input value is rounded to
+| a subnormal number, and the underflow and inexact exceptions are raised if
+| the abstract input cannot be represented exactly as a subnormal extended
+| double-precision floating-point number.
+|     If `roundingPrecision' is 32 or 64, the result is rounded to the same
+| number of bits as single or double precision, respectively.  Otherwise, the
+| result is rounded to the full precision of the extended double-precision
+| format.
+|     The input significand must be normalized or smaller.  If the input
+| significand is not normalized, `zExp' must be 0; in that case, the result
+| returned is a subnormal number, and it must not require rounding.  The
+| handling of underflow and overflow follows the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static floatx80
+ roundAndPackFloatx80(
+     int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1
+ STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven, increment, isTiny;
+    int64 roundIncrement, roundMask, roundBits;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    if ( roundingPrecision == 80 ) goto precision80;
+    if ( roundingPrecision == 64 ) {
+        roundIncrement = LIT64( 0x0000000000000400 );
+        roundMask = LIT64( 0x00000000000007FF );
+    }
+    else if ( roundingPrecision == 32 ) {
+        roundIncrement = LIT64( 0x0000008000000000 );
+        roundMask = LIT64( 0x000000FFFFFFFFFF );
+    }
+    else {
+        goto precision80;
+    }
+    zSig0 |= ( zSig1 != 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = roundMask;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig0 & roundMask;
+    if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) {
+        if (    ( 0x7FFE < zExp )
+             || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
+           ) {
+            goto overflow;
+        }
+        if ( zExp <= 0 ) {
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloatx80(zSign, 0, 0);
+            }
+            isTiny =
+                   ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
+                || ( zExp < 0 )
+                || ( zSig0 <= zSig0 + roundIncrement );
+            shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
+            zExp = 0;
+            roundBits = zSig0 & roundMask;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR);
+            if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
+            zSig0 += roundIncrement;
+            if ( (int64_t) zSig0 < 0 ) zExp = 1;
+            roundIncrement = roundMask + 1;
+            if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+                roundMask |= roundIncrement;
+            }
+            zSig0 &= ~ roundMask;
+            return packFloatx80( zSign, zExp, zSig0 );
+        }
+    }
+    if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact;
+    zSig0 += roundIncrement;
+    if ( zSig0 < roundIncrement ) {
+        ++zExp;
+        zSig0 = LIT64( 0x8000000000000000 );
+    }
+    roundIncrement = roundMask + 1;
+    if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+        roundMask |= roundIncrement;
+    }
+    zSig0 &= ~ roundMask;
+    if ( zSig0 == 0 ) zExp = 0;
+    return packFloatx80( zSign, zExp, zSig0 );
+ precision80:
+    increment = ( (int64_t) zSig1 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        }
+        else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && zSig1;
+            }
+            else {
+                increment = ( roundingMode == float_round_up ) && zSig1;
+            }
+        }
+    }
+    if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) {
+        if (    ( 0x7FFE < zExp )
+             || (    ( zExp == 0x7FFE )
+                  && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
+                  && increment
+                )
+           ) {
+            roundMask = 0;
+ overflow:
+            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            if (    ( roundingMode == float_round_to_zero )
+                 || ( zSign && ( roundingMode == float_round_up ) )
+                 || ( ! zSign && ( roundingMode == float_round_down ) )
+               ) {
+                return packFloatx80( zSign, 0x7FFE, ~ roundMask );
+            }
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        if ( zExp <= 0 ) {
+            isTiny =
+                   ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
+                || ( zExp < 0 )
+                || ! increment
+                || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
+            shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
+            zExp = 0;
+            if ( isTiny && zSig1 ) float_raise( float_flag_underflow STATUS_VAR);
+            if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact;
+            if ( roundNearestEven ) {
+                increment = ( (int64_t) zSig1 < 0 );
+            }
+            else {
+                if ( zSign ) {
+                    increment = ( roundingMode == float_round_down ) && zSig1;
+                }
+                else {
+                    increment = ( roundingMode == float_round_up ) && zSig1;
+                }
+            }
+            if ( increment ) {
+                ++zSig0;
+                zSig0 &=
+                    ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+                if ( (int64_t) zSig0 < 0 ) zExp = 1;
+            }
+            return packFloatx80( zSign, zExp, zSig0 );
+        }
+    }
+    if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact;
+    if ( increment ) {
+        ++zSig0;
+        if ( zSig0 == 0 ) {
+            ++zExp;
+            zSig0 = LIT64( 0x8000000000000000 );
+        }
+        else {
+            zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+        }
+    }
+    else {
+        if ( zSig0 == 0 ) zExp = 0;
+    }
+    return packFloatx80( zSign, zExp, zSig0 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent
+| `zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
+| and returns the proper extended double-precision floating-point value
+| corresponding to the abstract input.  This routine is just like
+| `roundAndPackFloatx80' except that the input significand does not have to be
+| normalized.
+*----------------------------------------------------------------------------*/
+
+static floatx80
+ normalizeRoundAndPackFloatx80(
+     int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1
+ STATUS_PARAM)
+{
+    int8 shiftCount;
+
+    if ( zSig0 == 0 ) {
+        zSig0 = zSig1;
+        zSig1 = 0;
+        zExp -= 64;
+    }
+    shiftCount = countLeadingZeros64( zSig0 );
+    shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+    zExp -= shiftCount;
+    return
+        roundAndPackFloatx80( roundingPrecision, zSign, zExp, zSig0, zSig1 STATUS_VAR);
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the least-significant 64 fraction bits of the quadruple-precision
+| floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint64_t extractFloat128Frac1( float128 a )
+{
+
+    return a.low;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the most-significant 48 fraction bits of the quadruple-precision
+| floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE uint64_t extractFloat128Frac0( float128 a )
+{
+
+    return a.high & LIT64( 0x0000FFFFFFFFFFFF );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the quadruple-precision floating-point value
+| `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE int32 extractFloat128Exp( float128 a )
+{
+
+    return ( a.high>>48 ) & 0x7FFF;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the quadruple-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+
+INLINE flag extractFloat128Sign( float128 a )
+{
+
+    return a.high>>63;
+
+}
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal quadruple-precision floating-point value
+| represented by the denormalized significand formed by the concatenation of
+| `aSig0' and `aSig1'.  The normalized exponent is stored at the location
+| pointed to by `zExpPtr'.  The most significant 49 bits of the normalized
+| significand are stored at the location pointed to by `zSig0Ptr', and the
+| least significant 64 bits of the normalized significand are stored at the
+| location pointed to by `zSig1Ptr'.
+*----------------------------------------------------------------------------*/
+
+static void
+ normalizeFloat128Subnormal(
+     uint64_t aSig0,
+     uint64_t aSig1,
+     int32 *zExpPtr,
+     uint64_t *zSig0Ptr,
+     uint64_t *zSig1Ptr
+ )
+{
+    int8 shiftCount;
+
+    if ( aSig0 == 0 ) {
+        shiftCount = countLeadingZeros64( aSig1 ) - 15;
+        if ( shiftCount < 0 ) {
+            *zSig0Ptr = aSig1>>( - shiftCount );
+            *zSig1Ptr = aSig1<<( shiftCount & 63 );
+        }
+        else {
+            *zSig0Ptr = aSig1<<shiftCount;
+            *zSig1Ptr = 0;
+        }
+        *zExpPtr = - shiftCount - 63;
+    }
+    else {
+        shiftCount = countLeadingZeros64( aSig0 ) - 15;
+        shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
+        *zExpPtr = 1 - shiftCount;
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', the exponent `zExp', and the significand formed
+| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
+| floating-point value, returning the result.  After being shifted into the
+| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
+| added together to form the most significant 32 bits of the result.  This
+| means that any integer portion of `zSig0' will be added into the exponent.
+| Since a properly normalized significand will have an integer portion equal
+| to 1, the `zExp' input should be 1 less than the desired result exponent
+| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+
+INLINE float128
+ packFloat128( flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 )
+{
+    float128 z;
+
+    z.low = zSig1;
+    z.high = ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<48 ) + zSig0;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and extended significand formed by the concatenation of `zSig0', `zSig1',
+| and `zSig2', and returns the proper quadruple-precision floating-point value
+| corresponding to the abstract input.  Ordinarily, the abstract value is
+| simply rounded and packed into the quadruple-precision format, with the
+| inexact exception raised if the abstract input cannot be represented
+| exactly.  However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned.  If the abstract value is too small, the input value is rounded to
+| a subnormal number, and the underflow and inexact exceptions are raised if
+| the abstract input cannot be represented exactly as a subnormal quadruple-
+| precision floating-point number.
+|     The input significand must be normalized or smaller.  If the input
+| significand is not normalized, `zExp' must be 0; in that case, the result
+| returned is a subnormal number, and it must not require rounding.  In the
+| usual case that the input significand is normalized, `zExp' must be 1 less
+| than the ``true'' floating-point exponent.  The handling of underflow and
+| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float128
+ roundAndPackFloat128(
+     flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1, uint64_t zSig2 STATUS_PARAM)
+{
+    int8 roundingMode;
+    flag roundNearestEven, increment, isTiny;
+
+    roundingMode = STATUS(float_rounding_mode);
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    increment = ( (int64_t) zSig2 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        }
+        else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && zSig2;
+            }
+            else {
+                increment = ( roundingMode == float_round_up ) && zSig2;
+            }
+        }
+    }
+    if ( 0x7FFD <= (uint32_t) zExp ) {
+        if (    ( 0x7FFD < zExp )
+             || (    ( zExp == 0x7FFD )
+                  && eq128(
+                         LIT64( 0x0001FFFFFFFFFFFF ),
+                         LIT64( 0xFFFFFFFFFFFFFFFF ),
+                         zSig0,
+                         zSig1
+                     )
+                  && increment
+                )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            if (    ( roundingMode == float_round_to_zero )
+                 || ( zSign && ( roundingMode == float_round_up ) )
+                 || ( ! zSign && ( roundingMode == float_round_down ) )
+               ) {
+                return
+                    packFloat128(
+                        zSign,
+                        0x7FFE,
+                        LIT64( 0x0000FFFFFFFFFFFF ),
+                        LIT64( 0xFFFFFFFFFFFFFFFF )
+                    );
+            }
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        if ( zExp < 0 ) {
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat128(zSign, 0, 0, 0);
+            }
+            isTiny =
+                   ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ! increment
+                || lt128(
+                       zSig0,
+                       zSig1,
+                       LIT64( 0x0001FFFFFFFFFFFF ),
+                       LIT64( 0xFFFFFFFFFFFFFFFF )
+                   );
+            shift128ExtraRightJamming(
+                zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
+            zExp = 0;
+            if ( isTiny && zSig2 ) float_raise( float_flag_underflow STATUS_VAR);
+            if ( roundNearestEven ) {
+                increment = ( (int64_t) zSig2 < 0 );
+            }
+            else {
+                if ( zSign ) {
+                    increment = ( roundingMode == float_round_down ) && zSig2;
+                }
+                else {
+                    increment = ( roundingMode == float_round_up ) && zSig2;
+                }
+            }
+        }
+    }
+    if ( zSig2 ) STATUS(float_exception_flags) |= float_flag_inexact;
+    if ( increment ) {
+        add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
+        zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
+    }
+    else {
+        if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
+    }
+    return packFloat128( zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand formed by the concatenation of `zSig0' and `zSig1', and
+| returns the proper quadruple-precision floating-point value corresponding
+| to the abstract input.  This routine is just like `roundAndPackFloat128'
+| except that the input significand has fewer bits and does not have to be
+| normalized.  In all cases, `zExp' must be 1 less than the ``true'' floating-
+| point exponent.
+*----------------------------------------------------------------------------*/
+
+static float128
+ normalizeRoundAndPackFloat128(
+     flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 STATUS_PARAM)
+{
+    int8 shiftCount;
+    uint64_t zSig2;
+
+    if ( zSig0 == 0 ) {
+        zSig0 = zSig1;
+        zSig1 = 0;
+        zExp -= 64;
+    }
+    shiftCount = countLeadingZeros64( zSig0 ) - 15;
+    if ( 0 <= shiftCount ) {
+        zSig2 = 0;
+        shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+    }
+    else {
+        shift128ExtraRightJamming(
+            zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
+    }
+    zExp -= shiftCount;
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR);
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 32-bit two's complement integer `a'
+| to the single-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 int32_to_float32( int32 a STATUS_PARAM )
+{
+    flag zSign;
+
+    if ( a == 0 ) return float32_zero;
+    if ( a == (int32_t) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+    zSign = ( a < 0 );
+    return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 32-bit two's complement integer `a'
+| to the double-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 int32_to_float64( int32 a STATUS_PARAM )
+{
+    flag zSign;
+    uint32 absA;
+    int8 shiftCount;
+    uint64_t zSig;
+
+    if ( a == 0 ) return float64_zero;
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 21;
+    zSig = absA;
+    return packFloat64( zSign, 0x432 - shiftCount, zSig<<shiftCount );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 32-bit two's complement integer `a'
+| to the extended double-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 int32_to_floatx80( int32 a STATUS_PARAM )
+{
+    flag zSign;
+    uint32 absA;
+    int8 shiftCount;
+    uint64_t zSig;
+
+    if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 32;
+    zSig = absA;
+    return packFloatx80( zSign, 0x403E - shiftCount, zSig<<shiftCount );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 32-bit two's complement integer `a' to
+| the quadruple-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 int32_to_float128( int32 a STATUS_PARAM )
+{
+    flag zSign;
+    uint32 absA;
+    int8 shiftCount;
+    uint64_t zSig0;
+
+    if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 17;
+    zSig0 = absA;
+    return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 64-bit two's complement integer `a'
+| to the single-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 int64_to_float32( int64 a STATUS_PARAM )
+{
+    flag zSign;
+    uint64 absA;
+    int8 shiftCount;
+
+    if ( a == 0 ) return float32_zero;
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros64( absA ) - 40;
+    if ( 0 <= shiftCount ) {
+        return packFloat32( zSign, 0x95 - shiftCount, absA<<shiftCount );
+    }
+    else {
+        shiftCount += 7;
+        if ( shiftCount < 0 ) {
+            shift64RightJamming( absA, - shiftCount, &absA );
+        }
+        else {
+            absA <<= shiftCount;
+        }
+        return roundAndPackFloat32( zSign, 0x9C - shiftCount, absA STATUS_VAR );
+    }
+
+}
+
+float32 uint64_to_float32( uint64 a STATUS_PARAM )
+{
+    int8 shiftCount;
+
+    if ( a == 0 ) return float32_zero;
+    shiftCount = countLeadingZeros64( a ) - 40;
+    if ( 0 <= shiftCount ) {
+        return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
+    }
+    else {
+        shiftCount += 7;
+        if ( shiftCount < 0 ) {
+            shift64RightJamming( a, - shiftCount, &a );
+        }
+        else {
+            a <<= shiftCount;
+        }
+        return roundAndPackFloat32( 1 > 0, 0x9C - shiftCount, a STATUS_VAR );
+    }
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 64-bit two's complement integer `a'
+| to the double-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 int64_to_float64( int64 a STATUS_PARAM )
+{
+    flag zSign;
+
+    if ( a == 0 ) return float64_zero;
+    if ( a == (int64_t) LIT64( 0x8000000000000000 ) ) {
+        return packFloat64( 1, 0x43E, 0 );
+    }
+    zSign = ( a < 0 );
+    return normalizeRoundAndPackFloat64( zSign, 0x43C, zSign ? - a : a STATUS_VAR );
+
+}
+
+float64 uint64_to_float64( uint64 a STATUS_PARAM )
+{
+    if ( a == 0 ) return float64_zero;
+    return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 64-bit two's complement integer `a'
+| to the extended double-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 int64_to_floatx80( int64 a STATUS_PARAM )
+{
+    flag zSign;
+    uint64 absA;
+    int8 shiftCount;
+
+    if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros64( absA );
+    return packFloatx80( zSign, 0x403E - shiftCount, absA<<shiftCount );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the 64-bit two's complement integer `a' to
+| the quadruple-precision floating-point format.  The conversion is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 int64_to_float128( int64 a STATUS_PARAM )
+{
+    flag zSign;
+    uint64 absA;
+    int8 shiftCount;
+    int32 zExp;
+    uint64_t zSig0, zSig1;
+
+    if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros64( absA ) + 49;
+    zExp = 0x406E - shiftCount;
+    if ( 64 <= shiftCount ) {
+        zSig1 = 0;
+        zSig0 = absA;
+        shiftCount -= 64;
+    }
+    else {
+        zSig1 = absA;
+        zSig0 = 0;
+    }
+    shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+    return packFloat128( zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the 32-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int32 float32_to_int32( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint32_t aSig;
+    uint64_t aSig64;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( ( aExp == 0xFF ) && aSig ) aSign = 0;
+    if ( aExp ) aSig |= 0x00800000;
+    shiftCount = 0xAF - aExp;
+    aSig64 = aSig;
+    aSig64 <<= 32;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig64, shiftCount, &aSig64 );
+    return roundAndPackInt32( aSign, aSig64 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the 32-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint32_t aSig;
+    int32 z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x9E;
+    if ( 0 <= shiftCount ) {
+        if ( float32_val(a) != 0xCF000000 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+        }
+        return (int32_t) 0x80000000;
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    aSig = ( aSig | 0x00800000 )<<8;
+    z = aSig>>( - shiftCount );
+    if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    if ( aSign ) z = - z;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the 16-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint32_t aSig;
+    int32 z;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x8E;
+    if ( 0 <= shiftCount ) {
+        if ( float32_val(a) != 0xC7000000 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+                return 0x7FFF;
+            }
+        }
+        return (int32_t) 0xffff8000;
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+        return 0;
+    }
+    shiftCount -= 0x10;
+    aSig = ( aSig | 0x00800000 )<<8;
+    z = aSig>>( - shiftCount );
+    if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    if ( aSign ) {
+        z = - z;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the 64-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int64 float32_to_int64( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint32_t aSig;
+    uint64_t aSig64, aSigExtra;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = 0xBE - aExp;
+    if ( shiftCount < 0 ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+            return LIT64( 0x7FFFFFFFFFFFFFFF );
+        }
+        return (int64_t) LIT64( 0x8000000000000000 );
+    }
+    if ( aExp ) aSig |= 0x00800000;
+    aSig64 = aSig;
+    aSig64 <<= 40;
+    shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra );
+    return roundAndPackInt64( aSign, aSig64, aSigExtra STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the 64-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.  If
+| `a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+| conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint32_t aSig;
+    uint64_t aSig64;
+    int64 z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0xBE;
+    if ( 0 <= shiftCount ) {
+        if ( float32_val(a) != 0xDF000000 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+                return LIT64( 0x7FFFFFFFFFFFFFFF );
+            }
+        }
+        return (int64_t) LIT64( 0x8000000000000000 );
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    aSig64 = aSig | 0x00800000;
+    aSig64 <<= 40;
+    z = aSig64>>( - shiftCount );
+    if ( (uint64_t) ( aSig64<<( shiftCount & 63 ) ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    if ( aSign ) z = - z;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the double-precision floating-point format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float32_to_float64( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    return packFloat64( aSign, aExp + 0x380, ( (uint64_t) aSig )<<29 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the extended double-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    aSig |= 0x00800000;
+    return packFloatx80( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<40 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
+| `a' to the double-precision floating-point format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float32_to_float128( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloat128( aSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    return packFloat128( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<25, 0 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Rounds the single-precision floating-point value `a' to an integer, and
+| returns the result as a single-precision floating-point value.  The
+| operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_round_to_int( float32 a STATUS_PARAM)
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    uint32_t z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aExp = extractFloat32Exp( a );
+    if ( 0x96 <= aExp ) {
+        if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+            return propagateFloat32NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp <= 0x7E ) {
+        if ( (uint32_t) ( float32_val(a)<<1 ) == 0 ) return a;
+        STATUS(float_exception_flags) |= float_flag_inexact;
+        aSign = extractFloat32Sign( a );
+        switch ( STATUS(float_rounding_mode) ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+                return packFloat32( aSign, 0x7F, 0 );
+            }
+            break;
+         case float_round_down:
+            return make_float32(aSign ? 0xBF800000 : 0);
+         case float_round_up:
+            return make_float32(aSign ? 0x80000000 : 0x3F800000);
+        }
+        return packFloat32( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x96 - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = float32_val(a);
+    roundingMode = STATUS(float_rounding_mode);
+    if ( roundingMode == float_round_nearest_even ) {
+        z += lastBitMask>>1;
+        if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) {
+            z += roundBitsMask;
+        }
+    }
+    z &= ~ roundBitsMask;
+    if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact;
+    return make_float32(z);
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the single-precision
+| floating-point values `a' and `b'.  If `zSign' is 1, the sum is negated
+| before being returned.  `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
+{
+    int16 aExp, bExp, zExp;
+    uint32_t aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 6;
+    bSig <<= 6;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0xFF ) {
+            if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig |= 0x20000000;
+        }
+        shift32RightJamming( bSig, expDiff, &bSig );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig |= 0x20000000;
+        }
+        shift32RightJamming( aSig, - expDiff, &aSig );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0xFF ) {
+            if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( aExp == 0 ) {
+            if (STATUS(flush_to_zero)) {
+                if (aSig | bSig) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat32(zSign, 0, 0);
+            }
+            return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+        }
+        zSig = 0x40000000 + aSig + bSig;
+        zExp = aExp;
+        goto roundAndPack;
+    }
+    aSig |= 0x20000000;
+    zSig = ( aSig + bSig )<<1;
+    --zExp;
+    if ( (int32_t) zSig < 0 ) {
+        zSig = aSig + bSig;
+        ++zExp;
+    }
+ roundAndPack:
+    return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the single-
+| precision floating-point values `a' and `b'.  If `zSign' is 1, the
+| difference is negated before being returned.  `zSign' is ignored if the
+| result is a NaN.  The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
+{
+    int16 aExp, bExp, zExp;
+    uint32_t aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 7;
+    bSig <<= 7;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0xFF ) {
+        if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloat32( STATUS(float_rounding_mode) == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        return packFloat32( zSign ^ 1, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig |= 0x40000000;
+    }
+    shift32RightJamming( aSig, - expDiff, &aSig );
+    bSig |= 0x40000000;
+ bBigger:
+    zSig = bSig - aSig;
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig |= 0x40000000;
+    }
+    shift32RightJamming( bSig, expDiff, &bSig );
+    aSig |= 0x40000000;
+ aBigger:
+    zSig = aSig - bSig;
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat32( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the single-precision floating-point values `a'
+| and `b'.  The operation is performed according to the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_add( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat32Sigs( a, b, aSign STATUS_VAR);
+    }
+    else {
+        return subFloat32Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the single-precision floating-point values
+| `a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_sub( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat32Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return addFloat32Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the single-precision floating-point values
+| `a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_mul( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    uint32_t aSig, bSig;
+    uint64_t zSig64;
+    uint32_t zSig;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b STATUS_VAR );
+        }
+        if ( ( bExp | bSig ) == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        if ( ( aExp | aSig ) == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x7F;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    shift64RightJamming( ( (uint64_t) aSig ) * bSig, 32, &zSig64 );
+    zSig = zSig64;
+    if ( 0 <= (int32_t) ( zSig<<1 ) ) {
+        zSig <<= 1;
+        --zExp;
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of dividing the single-precision floating-point value `a'
+| by the corresponding value `b'.  The operation is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_div( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    uint32_t aSig, bSig, zSig;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        return packFloat32( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+                float_raise( float_flag_invalid STATUS_VAR);
+                return float32_default_nan;
+            }
+            float_raise( float_flag_divbyzero STATUS_VAR);
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x7D;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    if ( bSig <= ( aSig + aSig ) ) {
+        aSig >>= 1;
+        ++zExp;
+    }
+    zSig = ( ( (uint64_t) aSig )<<32 ) / bSig;
+    if ( ( zSig & 0x3F ) == 0 ) {
+        zSig |= ( (uint64_t) bSig * zSig != ( (uint64_t) aSig )<<32 );
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the remainder of the single-precision floating-point value `a'
+| with respect to the corresponding value `b'.  The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_rem( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp, bExp, expDiff;
+    uint32_t aSig, bSig;
+    uint32_t q;
+    uint64_t aSig64, bSig64, q64;
+    uint32_t alternateASig;
+    int32_t sigMean;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b STATUS_VAR );
+        }
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return a;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    expDiff = aExp - bExp;
+    aSig |= 0x00800000;
+    bSig |= 0x00800000;
+    if ( expDiff < 32 ) {
+        aSig <<= 8;
+        bSig <<= 8;
+        if ( expDiff < 0 ) {
+            if ( expDiff < -1 ) return a;
+            aSig >>= 1;
+        }
+        q = ( bSig <= aSig );
+        if ( q ) aSig -= bSig;
+        if ( 0 < expDiff ) {
+            q = ( ( (uint64_t) aSig )<<32 ) / bSig;
+            q >>= 32 - expDiff;
+            bSig >>= 2;
+            aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+        }
+        else {
+            aSig >>= 2;
+            bSig >>= 2;
+        }
+    }
+    else {
+        if ( bSig <= aSig ) aSig -= bSig;
+        aSig64 = ( (uint64_t) aSig )<<40;
+        bSig64 = ( (uint64_t) bSig )<<40;
+        expDiff -= 64;
+        while ( 0 < expDiff ) {
+            q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+            q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+            aSig64 = - ( ( bSig * q64 )<<38 );
+            expDiff -= 62;
+        }
+        expDiff += 64;
+        q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+        q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+        q = q64>>( 64 - expDiff );
+        bSig <<= 6;
+        aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q;
+    }
+    do {
+        alternateASig = aSig;
+        ++q;
+        aSig -= bSig;
+    } while ( 0 <= (int32_t) aSig );
+    sigMean = aSig + alternateASig;
+    if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+        aSig = alternateASig;
+    }
+    zSign = ( (int32_t) aSig < 0 );
+    if ( zSign ) aSig = - aSig;
+    return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the square root of the single-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float32_sqrt( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, zExp;
+    uint32_t aSig, zSig;
+    uint64_t rem, term;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
+        if ( ! aSign ) return a;
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig ) == 0 ) return a;
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return float32_zero;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+    aSig = ( aSig | 0x00800000 )<<8;
+    zSig = estimateSqrt32( aExp, aSig ) + 2;
+    if ( ( zSig & 0x7F ) <= 5 ) {
+        if ( zSig < 2 ) {
+            zSig = 0x7FFFFFFF;
+            goto roundAndPack;
+        }
+        aSig >>= aExp & 1;
+        term = ( (uint64_t) zSig ) * zSig;
+        rem = ( ( (uint64_t) aSig )<<32 ) - term;
+        while ( (int64_t) rem < 0 ) {
+            --zSig;
+            rem += ( ( (uint64_t) zSig )<<1 ) | 1;
+        }
+        zSig |= ( rem != 0 );
+    }
+    shift32RightJamming( zSig, 1, &zSig );
+ roundAndPack:
+    return roundAndPackFloat32( 0, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the binary exponential of the single-precision floating-point value
+| `a'. The operation is performed according to the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+|
+| Uses the following identities:
+|
+| 1. -------------------------------------------------------------------------
+|      x    x*ln(2)
+|     2  = e
+|
+| 2. -------------------------------------------------------------------------
+|                      2     3     4     5           n
+|      x        x     x     x     x     x           x
+|     e  = 1 + --- + --- + --- + --- + --- + ... + --- + ...
+|               1!    2!    3!    4!    5!          n!
+*----------------------------------------------------------------------------*/
+
+static const float64 float32_exp2_coefficients[15] =
+{
+    const_float64( 0x3ff0000000000000ll ), /*  1 */
+    const_float64( 0x3fe0000000000000ll ), /*  2 */
+    const_float64( 0x3fc5555555555555ll ), /*  3 */
+    const_float64( 0x3fa5555555555555ll ), /*  4 */
+    const_float64( 0x3f81111111111111ll ), /*  5 */
+    const_float64( 0x3f56c16c16c16c17ll ), /*  6 */
+    const_float64( 0x3f2a01a01a01a01all ), /*  7 */
+    const_float64( 0x3efa01a01a01a01all ), /*  8 */
+    const_float64( 0x3ec71de3a556c734ll ), /*  9 */
+    const_float64( 0x3e927e4fb7789f5cll ), /* 10 */
+    const_float64( 0x3e5ae64567f544e4ll ), /* 11 */
+    const_float64( 0x3e21eed8eff8d898ll ), /* 12 */
+    const_float64( 0x3de6124613a86d09ll ), /* 13 */
+    const_float64( 0x3da93974a8c07c9dll ), /* 14 */
+    const_float64( 0x3d6ae7f3e733b81fll ), /* 15 */
+};
+
+float32 float32_exp2( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+    float64 r, x, xn;
+    int i;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+
+    if ( aExp == 0xFF) {
+        if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
+        return (aSign) ? float32_zero : a;
+    }
+    if (aExp == 0) {
+        if (aSig == 0) return float32_one;
+    }
+
+    float_raise( float_flag_inexact STATUS_VAR);
+
+    /* ******************************* */
+    /* using float64 for approximation */
+    /* ******************************* */
+    x = float32_to_float64(a STATUS_VAR);
+    x = float64_mul(x, float64_ln2 STATUS_VAR);
+
+    xn = x;
+    r = float64_one;
+    for (i = 0 ; i < 15 ; i++) {
+        float64 f;
+
+        f = float64_mul(xn, float32_exp2_coefficients[i] STATUS_VAR);
+        r = float64_add(r, f STATUS_VAR);
+
+        xn = float64_mul(xn, x STATUS_VAR);
+    }
+
+    return float64_to_float32(r, status);
+}
+
+/*----------------------------------------------------------------------------
+| Returns the binary log of the single-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32 float32_log2( float32 a STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp;
+    uint32_t aSig, zSig, i;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( aSign ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
+        return a;
+    }
+
+    aExp -= 0x7F;
+    aSig |= 0x00800000;
+    zSign = aExp < 0;
+    zSig = aExp << 23;
+
+    for (i = 1 << 22; i > 0; i >>= 1) {
+        aSig = ( (uint64_t)aSig * aSig ) >> 23;
+        if ( aSig & 0x01000000 ) {
+            aSig >>= 1;
+            zSig |= i;
+        }
+    }
+
+    if ( zSign )
+        zSig = -zSig;
+
+    return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is equal to
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_eq( float32 a, float32 b STATUS_PARAM )
+{
+    uint32_t av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    av = float32_val(a);
+    bv = float32_val(b);
+    return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is less than
+| or equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_le( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint32_t av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    av = float32_val(a);
+    bv = float32_val(b);
+    if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_lt( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint32_t av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    av = float32_val(a);
+    bv = float32_val(b);
+    if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 );
+    return ( av != bv ) && ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_unordered( float32 a, float32 b STATUS_PARAM )
+{
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is equal to
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_eq_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    return ( float32_val(a) == float32_val(b) ) ||
+            ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is less than or
+| equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+| cause an exception.  Otherwise, the comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint32_t av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    av = float32_val(a);
+    bv = float32_val(b);
+    if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint32_t av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    av = float32_val(a);
+    bv = float32_val(b);
+    if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 );
+    return ( av != bv ) && ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the 32-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int32 float64_to_int32( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint64_t aSig;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x42C - aExp;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
+    return roundAndPackInt32( aSign, aSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the 32-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint64_t aSig, savedASig;
+    int32 z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( 0x41E < aExp ) {
+        if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+        goto invalid;
+    }
+    else if ( aExp < 0x3FF ) {
+        if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x433 - aExp;
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the 16-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int16 float64_to_int16_round_to_zero( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint64_t aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( 0x40E < aExp ) {
+        if ( ( aExp == 0x7FF ) && aSig ) {
+            aSign = 0;
+        }
+        goto invalid;
+    }
+    else if ( aExp < 0x3FF ) {
+        if ( aExp || aSig ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+        return 0;
+    }
+    aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x433 - aExp;
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) {
+        z = - z;
+    }
+    if ( ( (int16_t)z < 0 ) ^ aSign ) {
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return aSign ? (int32_t) 0xffff8000 : 0x7FFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the 64-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int64 float64_to_int64( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint64_t aSig, aSigExtra;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x433 - aExp;
+    if ( shiftCount <= 0 ) {
+        if ( 0x43E < aExp ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if (    ! aSign
+                 || (    ( aExp == 0x7FF )
+                      && ( aSig != LIT64( 0x0010000000000000 ) ) )
+               ) {
+                return LIT64( 0x7FFFFFFFFFFFFFFF );
+            }
+            return (int64_t) LIT64( 0x8000000000000000 );
+        }
+        aSigExtra = 0;
+        aSig <<= - shiftCount;
+    }
+    else {
+        shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
+    }
+    return roundAndPackInt64( aSign, aSig, aSigExtra STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the 64-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    uint64_t aSig;
+    int64 z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = aExp - 0x433;
+    if ( 0 <= shiftCount ) {
+        if ( 0x43E <= aExp ) {
+            if ( float64_val(a) != LIT64( 0xC3E0000000000000 ) ) {
+                float_raise( float_flag_invalid STATUS_VAR);
+                if (    ! aSign
+                     || (    ( aExp == 0x7FF )
+                          && ( aSig != LIT64( 0x0010000000000000 ) ) )
+                   ) {
+                    return LIT64( 0x7FFFFFFFFFFFFFFF );
+                }
+            }
+            return (int64_t) LIT64( 0x8000000000000000 );
+        }
+        z = aSig<<shiftCount;
+    }
+    else {
+        if ( aExp < 0x3FE ) {
+            if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+            return 0;
+        }
+        z = aSig>>( - shiftCount );
+        if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+    }
+    if ( aSign ) z = - z;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the single-precision floating-point format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float64_to_float32( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint64_t aSig;
+    uint32_t zSig;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    shift64RightJamming( aSig, 22, &aSig );
+    zSig = aSig;
+    if ( aExp || zSig ) {
+        zSig |= 0x40000000;
+        aExp -= 0x381;
+    }
+    return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR );
+
+}
+
+
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+| half-precision floating-point value, returning the result.  After being
+| shifted into the proper positions, the three fields are simply added
+| together to form the result.  This means that any integer portion of `zSig'
+| will be added into the exponent.  Since a properly normalized significand
+| will have an integer portion equal to 1, the `zExp' input should be 1 less
+| than the desired result exponent whenever `zSig' is a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+static float16 packFloat16(flag zSign, int16 zExp, uint16_t zSig)
+{
+    return make_float16(
+        (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig);
+}
+
+/* Half precision floats come in two formats: standard IEEE and "ARM" format.
+   The latter gains extra exponent range by omitting the NaN/Inf encodings.  */
+
+float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM)
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+
+    aSign = extractFloat16Sign(a);
+    aExp = extractFloat16Exp(a);
+    aSig = extractFloat16Frac(a);
+
+    if (aExp == 0x1f && ieee) {
+        if (aSig) {
+            return commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) STATUS_VAR);
+        }
+        return packFloat32(aSign, 0xff, aSig << 13);
+    }
+    if (aExp == 0) {
+        int8 shiftCount;
+
+        if (aSig == 0) {
+            return packFloat32(aSign, 0, 0);
+        }
+
+        shiftCount = countLeadingZeros32( aSig ) - 21;
+        aSig = aSig << shiftCount;
+        aExp = -shiftCount;
+    }
+    return packFloat32( aSign, aExp + 0x70, aSig << 13);
+}
+
+float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM)
+{
+    flag aSign;
+    int16 aExp;
+    uint32_t aSig;
+    uint32_t mask;
+    uint32_t increment;
+    int8 roundingMode;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if (aSig) {
+            /* Input is a NaN */
+            float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+            if (!ieee) {
+                return packFloat16(aSign, 0, 0);
+            }
+            return r;
+        }
+        /* Infinity */
+        if (!ieee) {
+            float_raise(float_flag_invalid STATUS_VAR);
+            return packFloat16(aSign, 0x1f, 0x3ff);
+        }
+        return packFloat16(aSign, 0x1f, 0);
+    }
+    if (aExp == 0 && aSig == 0) {
+        return packFloat16(aSign, 0, 0);
+    }
+    /* Decimal point between bits 22 and 23.  */
+    aSig |= 0x00800000;
+    aExp -= 0x7f;
+    if (aExp < -14) {
+        mask = 0x00ffffff;
+        if (aExp >= -24) {
+            mask >>= 25 + aExp;
+        }
+    } else {
+        mask = 0x00001fff;
+    }
+    if (aSig & mask) {
+        float_raise( float_flag_underflow STATUS_VAR );
+        roundingMode = STATUS(float_rounding_mode);
+        switch (roundingMode) {
+        case float_round_nearest_even:
+            increment = (mask + 1) >> 1;
+            if ((aSig & mask) == increment) {
+                increment = aSig & (increment << 1);
+            }
+            break;
+        case float_round_up:
+            increment = aSign ? 0 : mask;
+            break;
+        case float_round_down:
+            increment = aSign ? mask : 0;
+            break;
+        default: /* round_to_zero */
+            increment = 0;
+            break;
+        }
+        aSig += increment;
+        if (aSig >= 0x01000000) {
+            aSig >>= 1;
+            aExp++;
+        }
+    } else if (aExp < -14
+          && STATUS(float_detect_tininess) == float_tininess_before_rounding) {
+        float_raise( float_flag_underflow STATUS_VAR);
+    }
+
+    if (ieee) {
+        if (aExp > 15) {
+            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
+            return packFloat16(aSign, 0x1f, 0);
+        }
+    } else {
+        if (aExp > 16) {
+            float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR);
+            return packFloat16(aSign, 0x1f, 0x3ff);
+        }
+    }
+    if (aExp < -24) {
+        return packFloat16(aSign, 0, 0);
+    }
+    if (aExp < -14) {
+        aSig >>= -14 - aExp;
+        aExp = -14;
+    }
+    return packFloat16(aSign, aExp + 14, aSig >> 13);
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the extended double-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint64_t aSig;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    return
+        packFloatx80(
+            aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
+| `a' to the quadruple-precision floating-point format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float64_to_float128( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint64_t aSig, zSig0, zSig1;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        return packFloat128( aSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
+    return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Rounds the double-precision floating-point value `a' to an integer, and
+| returns the result as a double-precision floating-point value.  The
+| operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_round_to_int( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint64_t lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    uint64_t z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aExp = extractFloat64Exp( a );
+    if ( 0x433 <= aExp ) {
+        if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) {
+            return propagateFloat64NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp < 0x3FF ) {
+        if ( (uint64_t) ( float64_val(a)<<1 ) == 0 ) return a;
+        STATUS(float_exception_flags) |= float_flag_inexact;
+        aSign = extractFloat64Sign( a );
+        switch ( STATUS(float_rounding_mode) ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) {
+                return packFloat64( aSign, 0x3FF, 0 );
+            }
+            break;
+         case float_round_down:
+            return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0);
+         case float_round_up:
+            return make_float64(
+            aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ));
+        }
+        return packFloat64( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x433 - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = float64_val(a);
+    roundingMode = STATUS(float_rounding_mode);
+    if ( roundingMode == float_round_nearest_even ) {
+        z += lastBitMask>>1;
+        if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) {
+            z += roundBitsMask;
+        }
+    }
+    z &= ~ roundBitsMask;
+    if ( z != float64_val(a) )
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    return make_float64(z);
+
+}
+
+float64 float64_trunc_to_int( float64 a STATUS_PARAM)
+{
+    int oldmode;
+    float64 res;
+    oldmode = STATUS(float_rounding_mode);
+    STATUS(float_rounding_mode) = float_round_to_zero;
+    res = float64_round_to_int(a STATUS_VAR);
+    STATUS(float_rounding_mode) = oldmode;
+    return res;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the double-precision
+| floating-point values `a' and `b'.  If `zSign' is 1, the sum is negated
+| before being returned.  `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
+{
+    int16 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 9;
+    bSig <<= 9;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FF ) {
+            if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig |= LIT64( 0x2000000000000000 );
+        }
+        shift64RightJamming( bSig, expDiff, &bSig );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FF ) {
+            if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+            return packFloat64( zSign, 0x7FF, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig |= LIT64( 0x2000000000000000 );
+        }
+        shift64RightJamming( aSig, - expDiff, &aSig );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FF ) {
+            if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( aExp == 0 ) {
+            if (STATUS(flush_to_zero)) {
+                if (aSig | bSig) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat64(zSign, 0, 0);
+            }
+            return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+        }
+        zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
+        zExp = aExp;
+        goto roundAndPack;
+    }
+    aSig |= LIT64( 0x2000000000000000 );
+    zSig = ( aSig + bSig )<<1;
+    --zExp;
+    if ( (int64_t) zSig < 0 ) {
+        zSig = aSig + bSig;
+        ++zExp;
+    }
+ roundAndPack:
+    return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the double-
+| precision floating-point values `a' and `b'.  If `zSign' is 1, the
+| difference is negated before being returned.  `zSign' is ignored if the
+| result is a NaN.  The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
+{
+    int16 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 10;
+    bSig <<= 10;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FF ) {
+        if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloat64( STATUS(float_rounding_mode) == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        return packFloat64( zSign ^ 1, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig |= LIT64( 0x4000000000000000 );
+    }
+    shift64RightJamming( aSig, - expDiff, &aSig );
+    bSig |= LIT64( 0x4000000000000000 );
+ bBigger:
+    zSig = bSig - aSig;
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig |= LIT64( 0x4000000000000000 );
+    }
+    shift64RightJamming( bSig, expDiff, &bSig );
+    aSig |= LIT64( 0x4000000000000000 );
+ aBigger:
+    zSig = aSig - bSig;
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat64( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the double-precision floating-point values `a'
+| and `b'.  The operation is performed according to the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_add( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat64Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return subFloat64Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the double-precision floating-point values
+| `a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_sub( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat64Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return addFloat64Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the double-precision floating-point values
+| `a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_mul( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig0, zSig1;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    bSign = extractFloat64Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FF ) {
+        if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+            return propagateFloat64NaN( a, b STATUS_VAR );
+        }
+        if ( ( bExp | bSig ) == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        if ( ( aExp | aSig ) == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x3FF;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    mul64To128( aSig, bSig, &zSig0, &zSig1 );
+    zSig0 |= ( zSig1 != 0 );
+    if ( 0 <= (int64_t) ( zSig0<<1 ) ) {
+        zSig0 <<= 1;
+        --zExp;
+    }
+    return roundAndPackFloat64( zSign, zExp, zSig0 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of dividing the double-precision floating-point value `a'
+| by the corresponding value `b'.  The operation is performed according to
+| the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_div( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig;
+    uint64_t rem0, rem1;
+    uint64_t term0, term1;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    bSign = extractFloat64Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        if ( bExp == 0x7FF ) {
+            if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        return packFloat64( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+                float_raise( float_flag_invalid STATUS_VAR);
+                return float64_default_nan;
+            }
+            float_raise( float_flag_divbyzero STATUS_VAR);
+            return packFloat64( zSign, 0x7FF, 0 );
+        }
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x3FD;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    if ( bSig <= ( aSig + aSig ) ) {
+        aSig >>= 1;
+        ++zExp;
+    }
+    zSig = estimateDiv128To64( aSig, 0, bSig );
+    if ( ( zSig & 0x1FF ) <= 2 ) {
+        mul64To128( bSig, zSig, &term0, &term1 );
+        sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+        while ( (int64_t) rem0 < 0 ) {
+            --zSig;
+            add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+        }
+        zSig |= ( rem1 != 0 );
+    }
+    return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the remainder of the double-precision floating-point value `a'
+| with respect to the corresponding value `b'.  The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_rem( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp, bExp, expDiff;
+    uint64_t aSig, bSig;
+    uint64_t q, alternateASig;
+    int64_t sigMean;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    if ( aExp == 0x7FF ) {
+        if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+            return propagateFloat64NaN( a, b STATUS_VAR );
+        }
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return a;
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    expDiff = aExp - bExp;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    if ( expDiff < 0 ) {
+        if ( expDiff < -1 ) return a;
+        aSig >>= 1;
+    }
+    q = ( bSig <= aSig );
+    if ( q ) aSig -= bSig;
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        aSig = - ( ( bSig>>2 ) * q );
+        expDiff -= 62;
+    }
+    expDiff += 64;
+    if ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        q >>= 64 - expDiff;
+        bSig >>= 2;
+        aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+    }
+    else {
+        aSig >>= 2;
+        bSig >>= 2;
+    }
+    do {
+        alternateASig = aSig;
+        ++q;
+        aSig -= bSig;
+    } while ( 0 <= (int64_t) aSig );
+    sigMean = aSig + alternateASig;
+    if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+        aSig = alternateASig;
+    }
+    zSign = ( (int64_t) aSig < 0 );
+    if ( zSign ) aSig = - aSig;
+    return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the square root of the double-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float64_sqrt( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, zExp;
+    uint64_t aSig, zSig, doubleZSig;
+    uint64_t rem0, rem1, term0, term1;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, a STATUS_VAR );
+        if ( ! aSign ) return a;
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig ) == 0 ) return a;
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return float64_zero;
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
+    aSig |= LIT64( 0x0010000000000000 );
+    zSig = estimateSqrt32( aExp, aSig>>21 );
+    aSig <<= 9 - ( aExp & 1 );
+    zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 );
+    if ( ( zSig & 0x1FF ) <= 5 ) {
+        doubleZSig = zSig<<1;
+        mul64To128( zSig, zSig, &term0, &term1 );
+        sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+        while ( (int64_t) rem0 < 0 ) {
+            --zSig;
+            doubleZSig -= 2;
+            add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 );
+        }
+        zSig |= ( ( rem0 | rem1 ) != 0 );
+    }
+    return roundAndPackFloat64( 0, zExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the binary log of the double-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64 float64_log2( float64 a STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp;
+    uint64_t aSig, aSig0, aSig1, zSig, i;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( aSign ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR );
+        return a;
+    }
+
+    aExp -= 0x3FF;
+    aSig |= LIT64( 0x0010000000000000 );
+    zSign = aExp < 0;
+    zSig = (uint64_t)aExp << 52;
+    for (i = 1LL << 51; i > 0; i >>= 1) {
+        mul64To128( aSig, aSig, &aSig0, &aSig1 );
+        aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 );
+        if ( aSig & LIT64( 0x0020000000000000 ) ) {
+            aSig >>= 1;
+            zSig |= i;
+        }
+    }
+
+    if ( zSign )
+        zSig = -zSig;
+    return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is equal to the
+| corresponding value `b', and 0 otherwise.  The invalid exception is raised
+| if either operand is a NaN.  Otherwise, the comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_eq( float64 a, float64 b STATUS_PARAM )
+{
+    uint64_t av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    av = float64_val(a);
+    bv = float64_val(b);
+    return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is less than or
+| equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_le( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint64_t av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    av = float64_val(a);
+    bv = float64_val(b);
+    if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_lt( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint64_t av, bv;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    av = float64_val(a);
+    bv = float64_val(b);
+    if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 );
+    return ( av != bv ) && ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_unordered( float64 a, float64 b STATUS_PARAM )
+{
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is equal to the
+| corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_eq_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    uint64_t av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    av = float64_val(a);
+    bv = float64_val(b);
+    return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is less than or
+| equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+| cause an exception.  Otherwise, the comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint64_t av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    av = float64_val(a);
+    bv = float64_val(b);
+    if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 );
+    return ( av == bv ) || ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+    uint64_t av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    av = float64_val(a);
+    bv = float64_val(b);
+    if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 );
+    return ( av != bv ) && ( aSign ^ ( av < bv ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the 32-bit two's complement integer format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic---which means in particular that the conversion
+| is rounded according to the current rounding mode.  If `a' is a NaN, the
+| largest positive integer is returned.  Otherwise, if the conversion
+| overflows, the largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int32 floatx80_to_int32( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0;
+    shiftCount = 0x4037 - aExp;
+    if ( shiftCount <= 0 ) shiftCount = 1;
+    shift64RightJamming( aSig, shiftCount, &aSig );
+    return roundAndPackInt32( aSign, aSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the 32-bit two's complement integer format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic, except that the conversion is always rounded
+| toward zero.  If `a' is a NaN, the largest positive integer is returned.
+| Otherwise, if the conversion overflows, the largest integer with the same
+| sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( 0x401E < aExp ) {
+        if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0;
+        goto invalid;
+    }
+    else if ( aExp < 0x3FFF ) {
+        if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    shiftCount = 0x403E - aExp;
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the 64-bit two's complement integer format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic---which means in particular that the conversion
+| is rounded according to the current rounding mode.  If `a' is a NaN,
+| the largest positive integer is returned.  Otherwise, if the conversion
+| overflows, the largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int64 floatx80_to_int64( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig, aSigExtra;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    shiftCount = 0x403E - aExp;
+    if ( shiftCount <= 0 ) {
+        if ( shiftCount ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if (    ! aSign
+                 || (    ( aExp == 0x7FFF )
+                      && ( aSig != LIT64( 0x8000000000000000 ) ) )
+               ) {
+                return LIT64( 0x7FFFFFFFFFFFFFFF );
+            }
+            return (int64_t) LIT64( 0x8000000000000000 );
+        }
+        aSigExtra = 0;
+    }
+    else {
+        shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
+    }
+    return roundAndPackInt64( aSign, aSig, aSigExtra STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the 64-bit two's complement integer format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic, except that the conversion is always rounded
+| toward zero.  If `a' is a NaN, the largest positive integer is returned.
+| Otherwise, if the conversion overflows, the largest integer with the same
+| sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int64 floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig;
+    int64 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    shiftCount = aExp - 0x403E;
+    if ( 0 <= shiftCount ) {
+        aSig &= LIT64( 0x7FFFFFFFFFFFFFFF );
+        if ( ( a.high != 0xC03E ) || aSig ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if ( ! aSign || ( ( aExp == 0x7FFF ) && aSig ) ) {
+                return LIT64( 0x7FFFFFFFFFFFFFFF );
+            }
+        }
+        return (int64_t) LIT64( 0x8000000000000000 );
+    }
+    else if ( aExp < 0x3FFF ) {
+        if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    z = aSig>>( - shiftCount );
+    if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    if ( aSign ) z = - z;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the single-precision floating-point format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 floatx80_to_float32( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t aSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( aSig<<1 ) ) {
+            return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        }
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    shift64RightJamming( aSig, 33, &aSig );
+    if ( aExp || aSig ) aExp -= 0x3F81;
+    return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the double-precision floating-point format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t aSig, zSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( aSig<<1 ) ) {
+            return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        }
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    shift64RightJamming( aSig, 1, &zSig );
+    if ( aExp || aSig ) aExp -= 0x3C01;
+    return roundAndPackFloat64( aSign, aExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point value `a' to the quadruple-precision floating-point format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 floatx80_to_float128( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp;
+    uint64_t aSig, zSig0, zSig1;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) {
+        return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+    }
+    shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
+    return packFloat128( aSign, aExp, zSig0, zSig1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Rounds the extended double-precision floating-point value `a' to an integer,
+| and returns the result as an extended quadruple-precision floating-point
+| value.  The operation is performed according to the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    floatx80 z;
+
+    aExp = extractFloatx80Exp( a );
+    if ( 0x403E <= aExp ) {
+        if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
+            return propagateFloatx80NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp < 0x3FFF ) {
+        if (    ( aExp == 0 )
+             && ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
+            return a;
+        }
+        STATUS(float_exception_flags) |= float_flag_inexact;
+        aSign = extractFloatx80Sign( a );
+        switch ( STATUS(float_rounding_mode) ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x3FFE ) && (uint64_t) ( extractFloatx80Frac( a )<<1 )
+               ) {
+                return
+                    packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
+            }
+            break;
+         case float_round_down:
+            return
+                  aSign ?
+                      packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) )
+                : packFloatx80( 0, 0, 0 );
+         case float_round_up:
+            return
+                  aSign ? packFloatx80( 1, 0, 0 )
+                : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) );
+        }
+        return packFloatx80( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x403E - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = a;
+    roundingMode = STATUS(float_rounding_mode);
+    if ( roundingMode == float_round_nearest_even ) {
+        z.low += lastBitMask>>1;
+        if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+            z.low += roundBitsMask;
+        }
+    }
+    z.low &= ~ roundBitsMask;
+    if ( z.low == 0 ) {
+        ++z.high;
+        z.low = LIT64( 0x8000000000000000 );
+    }
+    if ( z.low != a.low ) STATUS(float_exception_flags) |= float_flag_inexact;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the extended double-
+| precision floating-point values `a' and `b'.  If `zSign' is 1, the sum is
+| negated before being returned.  `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM)
+{
+    int32 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig0, zSig1;
+    int32 expDiff;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FFF ) {
+            if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( bExp == 0 ) --expDiff;
+        shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FFF ) {
+            if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        if ( aExp == 0 ) ++expDiff;
+        shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FFF ) {
+            if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
+                return propagateFloatx80NaN( a, b STATUS_VAR );
+            }
+            return a;
+        }
+        zSig1 = 0;
+        zSig0 = aSig + bSig;
+        if ( aExp == 0 ) {
+            normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 );
+            goto roundAndPack;
+        }
+        zExp = aExp;
+        goto shiftRight1;
+    }
+    zSig0 = aSig + bSig;
+    if ( (int64_t) zSig0 < 0 ) goto roundAndPack;
+ shiftRight1:
+    shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
+    zSig0 |= LIT64( 0x8000000000000000 );
+    ++zExp;
+ roundAndPack:
+    return
+        roundAndPackFloatx80(
+            STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the extended
+| double-precision floating-point values `a' and `b'.  If `zSign' is 1, the
+| difference is negated before being returned.  `zSign' is ignored if the
+| result is a NaN.  The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM )
+{
+    int32 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig0, zSig1;
+    int32 expDiff;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
+            return propagateFloatx80NaN( a, b STATUS_VAR );
+        }
+        float_raise( float_flag_invalid STATUS_VAR);
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    zSig1 = 0;
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FFF ) {
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) ++expDiff;
+    shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ bBigger:
+    sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 );
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) --expDiff;
+    shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ aBigger:
+    sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 );
+    zExp = aExp;
+ normalizeRoundAndPack:
+    return
+        normalizeRoundAndPackFloatx80(
+            STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the extended double-precision floating-point
+| values `a' and `b'.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign == bSign ) {
+        return addFloatx80Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return subFloatx80Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the extended double-precision floating-
+| point values `a' and `b'.  The operation is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign == bSign ) {
+        return subFloatx80Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return addFloatx80Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the extended double-precision floating-
+| point values `a' and `b'.  The operation is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig0, zSig1;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    bSign = extractFloatx80Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if (    (uint64_t) ( aSig<<1 )
+             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
+            return propagateFloatx80NaN( a, b STATUS_VAR );
+        }
+        if ( ( bExp | bSig ) == 0 ) goto invalid;
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid STATUS_VAR);
+            z.low = floatx80_default_nan_low;
+            z.high = floatx80_default_nan_high;
+            return z;
+        }
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x3FFE;
+    mul64To128( aSig, bSig, &zSig0, &zSig1 );
+    if ( 0 < (int64_t) zSig0 ) {
+        shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
+        --zExp;
+    }
+    return
+        roundAndPackFloatx80(
+            STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of dividing the extended double-precision floating-point
+| value `a' by the corresponding value `b'.  The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    uint64_t aSig, bSig, zSig0, zSig1;
+    uint64_t rem0, rem1, rem2, term0, term1, term2;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    bSign = extractFloatx80Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        if ( bExp == 0x7FFF ) {
+            if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+            goto invalid;
+        }
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        return packFloatx80( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+                float_raise( float_flag_invalid STATUS_VAR);
+                z.low = floatx80_default_nan_low;
+                z.high = floatx80_default_nan_high;
+                return z;
+            }
+            float_raise( float_flag_divbyzero STATUS_VAR);
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x3FFE;
+    rem1 = 0;
+    if ( bSig <= aSig ) {
+        shift128Right( aSig, 0, 1, &aSig, &rem1 );
+        ++zExp;
+    }
+    zSig0 = estimateDiv128To64( aSig, rem1, bSig );
+    mul64To128( bSig, zSig0, &term0, &term1 );
+    sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
+    while ( (int64_t) rem0 < 0 ) {
+        --zSig0;
+        add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+    }
+    zSig1 = estimateDiv128To64( rem1, 0, bSig );
+    if ( (uint64_t) ( zSig1<<1 ) <= 8 ) {
+        mul64To128( bSig, zSig1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        while ( (int64_t) rem1 < 0 ) {
+            --zSig1;
+            add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
+        }
+        zSig1 |= ( ( rem1 | rem2 ) != 0 );
+    }
+    return
+        roundAndPackFloatx80(
+            STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the remainder of the extended double-precision floating-point value
+| `a' with respect to the corresponding value `b'.  The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int32 aExp, bExp, expDiff;
+    uint64_t aSig0, aSig1, bSig;
+    uint64_t q, term0, term1, alternateASig0, alternateASig1;
+    floatx80 z;
+
+    aSig0 = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    if ( aExp == 0x7FFF ) {
+        if (    (uint64_t) ( aSig0<<1 )
+             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
+            return propagateFloatx80NaN( a, b STATUS_VAR );
+        }
+        goto invalid;
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid STATUS_VAR);
+            z.low = floatx80_default_nan_low;
+            z.high = floatx80_default_nan_high;
+            return z;
+        }
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a;
+        normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+    }
+    bSig |= LIT64( 0x8000000000000000 );
+    zSign = aSign;
+    expDiff = aExp - bExp;
+    aSig1 = 0;
+    if ( expDiff < 0 ) {
+        if ( expDiff < -1 ) return a;
+        shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
+        expDiff = 0;
+    }
+    q = ( bSig <= aSig0 );
+    if ( q ) aSig0 -= bSig;
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        mul64To128( bSig, q, &term0, &term1 );
+        sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 );
+        expDiff -= 62;
+    }
+    expDiff += 64;
+    if ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        q >>= 64 - expDiff;
+        mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 );
+        sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 );
+        while ( le128( term0, term1, aSig0, aSig1 ) ) {
+            ++q;
+            sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        }
+    }
+    else {
+        term1 = 0;
+        term0 = bSig;
+    }
+    sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
+    if (    lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
+         || (    eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
+              && ( q & 1 ) )
+       ) {
+        aSig0 = alternateASig0;
+        aSig1 = alternateASig1;
+        zSign = ! zSign;
+    }
+    return
+        normalizeRoundAndPackFloatx80(
+            80, zSign, bExp + expDiff, aSig0, aSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the square root of the extended double-precision floating-point
+| value `a'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, zExp;
+    uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    floatx80 z;
+
+    aSig0 = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (uint64_t) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR );
+        if ( ! aSign ) return a;
+        goto invalid;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig0 ) == 0 ) return a;
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
+        normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+    }
+    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF;
+    zSig0 = estimateSqrt32( aExp, aSig0>>32 );
+    shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 );
+    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
+    doubleZSig0 = zSig0<<1;
+    mul64To128( zSig0, zSig0, &term0, &term1 );
+    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+    while ( (int64_t) rem0 < 0 ) {
+        --zSig0;
+        doubleZSig0 -= 2;
+        add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
+    }
+    zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
+    if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) {
+        if ( zSig1 == 0 ) zSig1 = 1;
+        mul64To128( doubleZSig0, zSig1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        mul64To128( zSig1, zSig1, &term2, &term3 );
+        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (int64_t) rem1 < 0 ) {
+            --zSig1;
+            shortShift128Left( 0, zSig1, 1, &term2, &term3 );
+            term3 |= 1;
+            term2 |= doubleZSig0;
+            add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 );
+    zSig0 |= doubleZSig0;
+    return
+        roundAndPackFloatx80(
+            STATUS(floatx80_rounding_precision), 0, zExp, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is equal
+| to the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
+{
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| less than or equal to the corresponding value `b', and 0 otherwise.  The
+| invalid exception is raised if either operand is a NaN.  The comparison is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| less than the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point values `a' and `b'
+| cannot be compared, and 0 otherwise.  The invalid exception is raised if
+| either operand is a NaN.   The comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+| cause an exception.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is less
+| than or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs
+| do not cause an exception.  Otherwise, the comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is less
+| than the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause
+| an exception.  Otherwise, the comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point values `a' and `b'
+| cannot be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.
+| The comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the 32-bit two's complement integer format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int32 float128_to_int32( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+    aSig0 |= ( aSig1 != 0 );
+    shiftCount = 0x4028 - aExp;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
+    return roundAndPackInt32( aSign, aSig0 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the 32-bit two's complement integer format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.  If
+| `a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+| conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig0, aSig1, savedASig;
+    int32 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    aSig0 |= ( aSig1 != 0 );
+    if ( 0x401E < aExp ) {
+        if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
+        goto invalid;
+    }
+    else if ( aExp < 0x3FFF ) {
+        if ( aExp || aSig0 ) STATUS(float_exception_flags) |= float_flag_inexact;
+        return 0;
+    }
+    aSig0 |= LIT64( 0x0001000000000000 );
+    shiftCount = 0x402F - aExp;
+    savedASig = aSig0;
+    aSig0 >>= shiftCount;
+    z = aSig0;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig0<<shiftCount ) != savedASig ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the 64-bit two's complement integer format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode.  If `a' is a NaN, the largest
+| positive integer is returned.  Otherwise, if the conversion overflows, the
+| largest integer with the same sign as `a' is returned.
+*----------------------------------------------------------------------------*/
+
+int64 float128_to_int64( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+    shiftCount = 0x402F - aExp;
+    if ( shiftCount <= 0 ) {
+        if ( 0x403E < aExp ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if (    ! aSign
+                 || (    ( aExp == 0x7FFF )
+                      && ( aSig1 || ( aSig0 != LIT64( 0x0001000000000000 ) ) )
+                    )
+               ) {
+                return LIT64( 0x7FFFFFFFFFFFFFFF );
+            }
+            return (int64_t) LIT64( 0x8000000000000000 );
+        }
+        shortShift128Left( aSig0, aSig1, - shiftCount, &aSig0, &aSig1 );
+    }
+    else {
+        shift64ExtraRightJamming( aSig0, aSig1, shiftCount, &aSig0, &aSig1 );
+    }
+    return roundAndPackInt64( aSign, aSig0, aSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the 64-bit two's complement integer format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int64 float128_to_int64_round_to_zero( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    uint64_t aSig0, aSig1;
+    int64 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+    shiftCount = aExp - 0x402F;
+    if ( 0 < shiftCount ) {
+        if ( 0x403E <= aExp ) {
+            aSig0 &= LIT64( 0x0000FFFFFFFFFFFF );
+            if (    ( a.high == LIT64( 0xC03E000000000000 ) )
+                 && ( aSig1 < LIT64( 0x0002000000000000 ) ) ) {
+                if ( aSig1 ) STATUS(float_exception_flags) |= float_flag_inexact;
+            }
+            else {
+                float_raise( float_flag_invalid STATUS_VAR);
+                if ( ! aSign || ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) ) {
+                    return LIT64( 0x7FFFFFFFFFFFFFFF );
+                }
+            }
+            return (int64_t) LIT64( 0x8000000000000000 );
+        }
+        z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
+        if ( (uint64_t) ( aSig1<<shiftCount ) ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+    }
+    else {
+        if ( aExp < 0x3FFF ) {
+            if ( aExp | aSig0 | aSig1 ) {
+                STATUS(float_exception_flags) |= float_flag_inexact;
+            }
+            return 0;
+        }
+        z = aSig0>>( - shiftCount );
+        if (    aSig1
+             || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+    }
+    if ( aSign ) z = - z;
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the single-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float32 float128_to_float32( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t aSig0, aSig1;
+    uint32_t zSig;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        }
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    aSig0 |= ( aSig1 != 0 );
+    shift64RightJamming( aSig0, 18, &aSig0 );
+    zSig = aSig0;
+    if ( aExp || zSig ) {
+        zSig |= 0x40000000;
+        aExp -= 0x3F81;
+    }
+    return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the double-precision floating-point format.  The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float64 float128_to_float64( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        }
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+    aSig0 |= ( aSig1 != 0 );
+    if ( aExp || aSig0 ) {
+        aSig0 |= LIT64( 0x4000000000000000 );
+        aExp -= 0x3C01;
+    }
+    return roundAndPackFloat64( aSign, aExp, aSig0 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the extended double-precision floating-point format.  The
+| conversion is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
+        }
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    else {
+        aSig0 |= LIT64( 0x0001000000000000 );
+    }
+    shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
+    return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Rounds the quadruple-precision floating-point value `a' to an integer, and
+| returns the result as a quadruple-precision floating-point value.  The
+| operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_round_to_int( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp;
+    uint64_t lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    float128 z;
+
+    aExp = extractFloat128Exp( a );
+    if ( 0x402F <= aExp ) {
+        if ( 0x406F <= aExp ) {
+            if (    ( aExp == 0x7FFF )
+                 && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
+               ) {
+                return propagateFloat128NaN( a, a STATUS_VAR );
+            }
+            return a;
+        }
+        lastBitMask = 1;
+        lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
+        roundBitsMask = lastBitMask - 1;
+        z = a;
+        roundingMode = STATUS(float_rounding_mode);
+        if ( roundingMode == float_round_nearest_even ) {
+            if ( lastBitMask ) {
+                add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
+                if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+            }
+            else {
+                if ( (int64_t) z.low < 0 ) {
+                    ++z.high;
+                    if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1;
+                }
+            }
+        }
+        else if ( roundingMode != float_round_to_zero ) {
+            if (   extractFloat128Sign( z )
+                 ^ ( roundingMode == float_round_up ) ) {
+                add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
+            }
+        }
+        z.low &= ~ roundBitsMask;
+    }
+    else {
+        if ( aExp < 0x3FFF ) {
+            if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+            STATUS(float_exception_flags) |= float_flag_inexact;
+            aSign = extractFloat128Sign( a );
+            switch ( STATUS(float_rounding_mode) ) {
+             case float_round_nearest_even:
+                if (    ( aExp == 0x3FFE )
+                     && (   extractFloat128Frac0( a )
+                          | extractFloat128Frac1( a ) )
+                   ) {
+                    return packFloat128( aSign, 0x3FFF, 0, 0 );
+                }
+                break;
+             case float_round_down:
+                return
+                      aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
+                    : packFloat128( 0, 0, 0, 0 );
+             case float_round_up:
+                return
+                      aSign ? packFloat128( 1, 0, 0, 0 )
+                    : packFloat128( 0, 0x3FFF, 0, 0 );
+            }
+            return packFloat128( aSign, 0, 0, 0 );
+        }
+        lastBitMask = 1;
+        lastBitMask <<= 0x402F - aExp;
+        roundBitsMask = lastBitMask - 1;
+        z.low = 0;
+        z.high = a.high;
+        roundingMode = STATUS(float_rounding_mode);
+        if ( roundingMode == float_round_nearest_even ) {
+            z.high += lastBitMask>>1;
+            if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
+                z.high &= ~ lastBitMask;
+            }
+        }
+        else if ( roundingMode != float_round_to_zero ) {
+            if (   extractFloat128Sign( z )
+                 ^ ( roundingMode == float_round_up ) ) {
+                z.high |= ( a.low != 0 );
+                z.high += roundBitsMask;
+            }
+        }
+        z.high &= ~ roundBitsMask;
+    }
+    if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the quadruple-precision
+| floating-point values `a' and `b'.  If `zSign' is 1, the sum is negated
+| before being returned.  `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM)
+{
+    int32 aExp, bExp, zExp;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    int32 expDiff;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FFF ) {
+            if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig0 |= LIT64( 0x0001000000000000 );
+        }
+        shift128ExtraRightJamming(
+            bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FFF ) {
+            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig0 |= LIT64( 0x0001000000000000 );
+        }
+        shift128ExtraRightJamming(
+            aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FFF ) {
+            if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+                return propagateFloat128NaN( a, b STATUS_VAR );
+            }
+            return a;
+        }
+        add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+        if ( aExp == 0 ) {
+            if (STATUS(flush_to_zero)) {
+                if (zSig0 | zSig1) {
+                    float_raise(float_flag_output_denormal STATUS_VAR);
+                }
+                return packFloat128(zSign, 0, 0, 0);
+            }
+            return packFloat128( zSign, 0, zSig0, zSig1 );
+        }
+        zSig2 = 0;
+        zSig0 |= LIT64( 0x0002000000000000 );
+        zExp = aExp;
+        goto shiftRight1;
+    }
+    aSig0 |= LIT64( 0x0001000000000000 );
+    add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+    --zExp;
+    if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
+    ++zExp;
+ shiftRight1:
+    shift128ExtraRightJamming(
+        zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ roundAndPack:
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the quadruple-
+| precision floating-point values `a' and `b'.  If `zSign' is 1, the
+| difference is negated before being returned.  `zSign' is ignored if the
+| result is a NaN.  The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM)
+{
+    int32 aExp, bExp, zExp;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+    int32 expDiff;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    expDiff = aExp - bExp;
+    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+    shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+            return propagateFloat128NaN( a, b STATUS_VAR );
+        }
+        float_raise( float_flag_invalid STATUS_VAR);
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig0 < aSig0 ) goto aBigger;
+    if ( aSig0 < bSig0 ) goto bBigger;
+    if ( bSig1 < aSig1 ) goto aBigger;
+    if ( aSig1 < bSig1 ) goto bBigger;
+    return packFloat128( STATUS(float_rounding_mode) == float_round_down, 0, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig0 |= LIT64( 0x4000000000000000 );
+    }
+    shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+    bSig0 |= LIT64( 0x4000000000000000 );
+ bBigger:
+    sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig0 |= LIT64( 0x4000000000000000 );
+    }
+    shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
+    aSig0 |= LIT64( 0x4000000000000000 );
+ aBigger:
+    sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the quadruple-precision floating-point values
+| `a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_add( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat128Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return subFloat128Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the quadruple-precision floating-point
+| values `a' and `b'.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_sub( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat128Sigs( a, b, aSign STATUS_VAR );
+    }
+    else {
+        return addFloat128Sigs( a, b, aSign STATUS_VAR );
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of multiplying the quadruple-precision floating-point
+| values `a' and `b'.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_mul( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    bSign = extractFloat128Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if (    ( aSig0 | aSig1 )
+             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+            return propagateFloat128NaN( a, b STATUS_VAR );
+        }
+        if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid STATUS_VAR);
+            z.low = float128_default_nan_low;
+            z.high = float128_default_nan_high;
+            return z;
+        }
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    zExp = aExp + bExp - 0x4000;
+    aSig0 |= LIT64( 0x0001000000000000 );
+    shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
+    mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
+    add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
+    zSig2 |= ( zSig3 != 0 );
+    if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
+        shift128ExtraRightJamming(
+            zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+        ++zExp;
+    }
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of dividing the quadruple-precision floating-point value
+| `a' by the corresponding value `b'.  The operation is performed according to
+| the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_div( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    bSign = extractFloat128Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        if ( bExp == 0x7FFF ) {
+            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+            goto invalid;
+        }
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        return packFloat128( zSign, 0, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) {
+            if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+                float_raise( float_flag_invalid STATUS_VAR);
+                z.low = float128_default_nan_low;
+                z.high = float128_default_nan_high;
+                return z;
+            }
+            float_raise( float_flag_divbyzero STATUS_VAR);
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    zExp = aExp - bExp + 0x3FFD;
+    shortShift128Left(
+        aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
+    shortShift128Left(
+        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+    if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
+        shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
+        ++zExp;
+    }
+    zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
+    mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+    sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+    while ( (int64_t) rem0 < 0 ) {
+        --zSig0;
+        add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+    }
+    zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
+    if ( ( zSig1 & 0x3FFF ) <= 4 ) {
+        mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+        sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (int64_t) rem1 < 0 ) {
+            --zSig1;
+            add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the remainder of the quadruple-precision floating-point value `a'
+| with respect to the corresponding value `b'.  The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_rem( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int32 aExp, bExp, expDiff;
+    uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
+    uint64_t allZero, alternateASig0, alternateASig1, sigMean1;
+    int64_t sigMean0;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    if ( aExp == 0x7FFF ) {
+        if (    ( aSig0 | aSig1 )
+             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+            return propagateFloat128NaN( a, b STATUS_VAR );
+        }
+        goto invalid;
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid STATUS_VAR);
+            z.low = float128_default_nan_low;
+            z.high = float128_default_nan_high;
+            return z;
+        }
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return a;
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    expDiff = aExp - bExp;
+    if ( expDiff < -1 ) return a;
+    shortShift128Left(
+        aSig0 | LIT64( 0x0001000000000000 ),
+        aSig1,
+        15 - ( expDiff < 0 ),
+        &aSig0,
+        &aSig1
+    );
+    shortShift128Left(
+        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+    q = le128( bSig0, bSig1, aSig0, aSig1 );
+    if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+        q = ( 4 < q ) ? q - 4 : 0;
+        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+        shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
+        shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
+        sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
+        expDiff -= 61;
+    }
+    if ( -64 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+        q = ( 4 < q ) ? q - 4 : 0;
+        q >>= - expDiff;
+        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+        expDiff += 52;
+        if ( expDiff < 0 ) {
+            shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+        }
+        else {
+            shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
+        }
+        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+        sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
+    }
+    else {
+        shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
+        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+    }
+    do {
+        alternateASig0 = aSig0;
+        alternateASig1 = aSig1;
+        ++q;
+        sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+    } while ( 0 <= (int64_t) aSig0 );
+    add128(
+        aSig0, aSig1, alternateASig0, alternateASig1, (uint64_t *)&sigMean0, &sigMean1 );
+    if (    ( sigMean0 < 0 )
+         || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
+        aSig0 = alternateASig0;
+        aSig1 = alternateASig1;
+    }
+    zSign = ( (int64_t) aSig0 < 0 );
+    if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
+    return
+        normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the square root of the quadruple-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+float128 float128_sqrt( float128 a STATUS_PARAM )
+{
+    flag aSign;
+    int32 aExp, zExp;
+    uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a STATUS_VAR );
+        if ( ! aSign ) return a;
+        goto invalid;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
+    aSig0 |= LIT64( 0x0001000000000000 );
+    zSig0 = estimateSqrt32( aExp, aSig0>>17 );
+    shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
+    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
+    doubleZSig0 = zSig0<<1;
+    mul64To128( zSig0, zSig0, &term0, &term1 );
+    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+    while ( (int64_t) rem0 < 0 ) {
+        --zSig0;
+        doubleZSig0 -= 2;
+        add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
+    }
+    zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
+    if ( ( zSig1 & 0x1FFF ) <= 5 ) {
+        if ( zSig1 == 0 ) zSig1 = 1;
+        mul64To128( doubleZSig0, zSig1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        mul64To128( zSig1, zSig1, &term2, &term3 );
+        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (int64_t) rem1 < 0 ) {
+            --zSig1;
+            shortShift128Left( 0, zSig1, 1, &term2, &term3 );
+            term3 |= 1;
+            term2 |= doubleZSig0;
+            add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 );
+    return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 STATUS_VAR );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is equal to
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_eq( float128 a, float128 b STATUS_PARAM )
+{
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is less than
+| or equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_le( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_lt( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN. The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_unordered( float128 a, float128 b STATUS_PARAM )
+{
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is equal to
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_eq_quiet( float128 a, float128 b STATUS_PARAM )
+{
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is less than
+| or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+| cause an exception.  Otherwise, the comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is less than
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/* misc functions */
+float32 uint32_to_float32( unsigned int a STATUS_PARAM )
+{
+    return int64_to_float32(a STATUS_VAR);
+}
+
+float64 uint32_to_float64( unsigned int a STATUS_PARAM )
+{
+    return int64_to_float64(a STATUS_VAR);
+}
+
+unsigned int float32_to_uint32( float32 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float32_to_int64(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float32_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float32_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffff) {
+        res = 0xffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+unsigned int float64_to_uint32( float64 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float64_to_int64(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float64_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+unsigned int float64_to_uint16_round_to_zero( float64 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float64_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffff) {
+        res = 0xffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
+/* FIXME: This looks broken.  */
+uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR));
+    v += float64_val(a);
+    v = float64_to_int64(make_float64(v) STATUS_VAR);
+
+    return v - INT64_MIN;
+}
+
+uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR));
+    v += float64_val(a);
+    v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR);
+
+    return v - INT64_MIN;
+}
+
+#define COMPARE(s, nan_exp)                                                  \
+INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
+                                      int is_quiet STATUS_PARAM )            \
+{                                                                            \
+    flag aSign, bSign;                                                       \
+    uint ## s ## _t av, bv;                                                  \
+    a = float ## s ## _squash_input_denormal(a STATUS_VAR);                  \
+    b = float ## s ## _squash_input_denormal(b STATUS_VAR);                  \
+                                                                             \
+    if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) &&                    \
+         extractFloat ## s ## Frac( a ) ) ||                                 \
+        ( ( extractFloat ## s ## Exp( b ) == nan_exp ) &&                    \
+          extractFloat ## s ## Frac( b ) )) {                                \
+        if (!is_quiet ||                                                     \
+            float ## s ## _is_signaling_nan( a ) ||                          \
+            float ## s ## _is_signaling_nan( b ) ) {                         \
+            float_raise( float_flag_invalid STATUS_VAR);                     \
+        }                                                                    \
+        return float_relation_unordered;                                     \
+    }                                                                        \
+    aSign = extractFloat ## s ## Sign( a );                                  \
+    bSign = extractFloat ## s ## Sign( b );                                  \
+    av = float ## s ## _val(a);                                              \
+    bv = float ## s ## _val(b);                                              \
+    if ( aSign != bSign ) {                                                  \
+        if ( (uint ## s ## _t) ( ( av | bv )<<1 ) == 0 ) {                   \
+            /* zero case */                                                  \
+            return float_relation_equal;                                     \
+        } else {                                                             \
+            return 1 - (2 * aSign);                                          \
+        }                                                                    \
+    } else {                                                                 \
+        if (av == bv) {                                                      \
+            return float_relation_equal;                                     \
+        } else {                                                             \
+            return 1 - 2 * (aSign ^ ( av < bv ));                            \
+        }                                                                    \
+    }                                                                        \
+}                                                                            \
+                                                                             \
+int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM )        \
+{                                                                            \
+    return float ## s ## _compare_internal(a, b, 0 STATUS_VAR);              \
+}                                                                            \
+                                                                             \
+int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM )  \
+{                                                                            \
+    return float ## s ## _compare_internal(a, b, 1 STATUS_VAR);              \
+}
+
+COMPARE(32, 0xff)
+COMPARE(64, 0x7ff)
+
+INLINE int floatx80_compare_internal( floatx80 a, floatx80 b,
+                                      int is_quiet STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (( ( extractFloatx80Exp( a ) == 0x7fff ) &&
+          ( extractFloatx80Frac( a )<<1 ) ) ||
+        ( ( extractFloatx80Exp( b ) == 0x7fff ) &&
+          ( extractFloatx80Frac( b )<<1 ) )) {
+        if (!is_quiet ||
+            floatx80_is_signaling_nan( a ) ||
+            floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return float_relation_unordered;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+
+        if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) &&
+             ( ( a.low | b.low ) == 0 ) ) {
+            /* zero case */
+            return float_relation_equal;
+        } else {
+            return 1 - (2 * aSign);
+        }
+    } else {
+        if (a.low == b.low && a.high == b.high) {
+            return float_relation_equal;
+        } else {
+            return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
+        }
+    }
+}
+
+int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    return floatx80_compare_internal(a, b, 0 STATUS_VAR);
+}
+
+int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    return floatx80_compare_internal(a, b, 1 STATUS_VAR);
+}
+
+INLINE int float128_compare_internal( float128 a, float128 b,
+                                      int is_quiet STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (( ( extractFloat128Exp( a ) == 0x7fff ) &&
+          ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) ||
+        ( ( extractFloat128Exp( b ) == 0x7fff ) &&
+          ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
+        if (!is_quiet ||
+            float128_is_signaling_nan( a ) ||
+            float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return float_relation_unordered;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) {
+            /* zero case */
+            return float_relation_equal;
+        } else {
+            return 1 - (2 * aSign);
+        }
+    } else {
+        if (a.low == b.low && a.high == b.high) {
+            return float_relation_equal;
+        } else {
+            return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
+        }
+    }
+}
+
+int float128_compare( float128 a, float128 b STATUS_PARAM )
+{
+    return float128_compare_internal(a, b, 0 STATUS_VAR);
+}
+
+int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    return float128_compare_internal(a, b, 1 STATUS_VAR);
+}
+
+/* min() and max() functions. These can't be implemented as
+ * 'compare and pick one input' because that would mishandle
+ * NaNs and +0 vs -0.
+ */
+#define MINMAX(s, nan_exp)                                              \
+INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
+                                        int ismin STATUS_PARAM )        \
+{                                                                       \
+    flag aSign, bSign;                                                  \
+    uint ## s ## _t av, bv;                                             \
+    a = float ## s ## _squash_input_denormal(a STATUS_VAR);             \
+    b = float ## s ## _squash_input_denormal(b STATUS_VAR);             \
+    if (float ## s ## _is_any_nan(a) ||                                 \
+        float ## s ## _is_any_nan(b)) {                                 \
+        return propagateFloat ## s ## NaN(a, b STATUS_VAR);             \
+    }                                                                   \
+    aSign = extractFloat ## s ## Sign(a);                               \
+    bSign = extractFloat ## s ## Sign(b);                               \
+    av = float ## s ## _val(a);                                         \
+    bv = float ## s ## _val(b);                                         \
+    if (aSign != bSign) {                                               \
+        if (ismin) {                                                    \
+            return aSign ? a : b;                                       \
+        } else {                                                        \
+            return aSign ? b : a;                                       \
+        }                                                               \
+    } else {                                                            \
+        if (ismin) {                                                    \
+            return (aSign ^ (av < bv)) ? a : b;                         \
+        } else {                                                        \
+            return (aSign ^ (av < bv)) ? b : a;                         \
+        }                                                               \
+    }                                                                   \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 1 STATUS_VAR);                   \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 0 STATUS_VAR);                   \
+}
+
+MINMAX(32, 0xff)
+MINMAX(64, 0x7ff)
+
+
+/* Multiply A by 2 raised to the power N.  */
+float32 float32_scalbn( float32 a, int n STATUS_PARAM )
+{
+    flag aSign;
+    int16_t aExp;
+    uint32_t aSig;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+
+    if ( aExp == 0xFF ) {
+        if ( aSig ) {
+            return propagateFloat32NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp != 0 )
+        aSig |= 0x00800000;
+    else if ( aSig == 0 )
+        return a;
+
+    if (n > 0x200) {
+        n = 0x200;
+    } else if (n < -0x200) {
+        n = -0x200;
+    }
+
+    aExp += n - 1;
+    aSig <<= 7;
+    return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
+}
+
+float64 float64_scalbn( float64 a, int n STATUS_PARAM )
+{
+    flag aSign;
+    int16_t aExp;
+    uint64_t aSig;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) {
+            return propagateFloat64NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp != 0 )
+        aSig |= LIT64( 0x0010000000000000 );
+    else if ( aSig == 0 )
+        return a;
+
+    if (n > 0x1000) {
+        n = 0x1000;
+    } else if (n < -0x1000) {
+        n = -0x1000;
+    }
+
+    aExp += n - 1;
+    aSig <<= 10;
+    return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
+}
+
+floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+
+    if ( aExp == 0x7FFF ) {
+        if ( aSig<<1 ) {
+            return propagateFloatx80NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+
+    if (aExp == 0 && aSig == 0)
+        return a;
+
+    if (n > 0x10000) {
+        n = 0x10000;
+    } else if (n < -0x10000) {
+        n = -0x10000;
+    }
+
+    aExp += n;
+    return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
+                                          aSign, aExp, aSig, 0 STATUS_VAR );
+}
+
+float128 float128_scalbn( float128 a, int n STATUS_PARAM )
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return propagateFloat128NaN( a, a STATUS_VAR );
+        }
+        return a;
+    }
+    if ( aExp != 0 )
+        aSig0 |= LIT64( 0x0001000000000000 );
+    else if ( aSig0 == 0 && aSig1 == 0 )
+        return a;
+
+    if (n > 0x10000) {
+        n = 0x10000;
+    } else if (n < -0x10000) {
+        n = -0x10000;
+    }
+
+    aExp += n - 1;
+    return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
+                                          STATUS_VAR );
+
+}
diff --git a/qemu-0.15.x/fpu/softfloat.h b/qemu-0.15.x/fpu/softfloat.h
new file mode 100644
index 0000000..bde2500
--- /dev/null
+++ b/qemu-0.15.x/fpu/softfloat.h
@@ -0,0 +1,662 @@
+/*
+ * QEMU float support
+ *
+ * Derived from SoftFloat.
+ */
+
+/*============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
+Package, Release 2b.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#ifndef SOFTFLOAT_H
+#define SOFTFLOAT_H
+
+#if defined(CONFIG_SOLARIS) && defined(CONFIG_NEEDS_LIBSUNMATH)
+#include <sunmath.h>
+#endif
+
+#include <inttypes.h>
+#include "config.h"
+
+/*----------------------------------------------------------------------------
+| Each of the following `typedef's defines the most convenient type that holds
+| integers of at least as many bits as specified.  For example, `uint8' should
+| be the most convenient type that can hold unsigned integers of as many as
+| 8 bits.  The `flag' type must be able to hold either a 0 or 1.  For most
+| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+| to the same as `int'.
+*----------------------------------------------------------------------------*/
+typedef uint8_t flag;
+typedef uint8_t uint8;
+typedef int8_t int8;
+#ifndef _AIX
+typedef int uint16;
+typedef int int16;
+#endif
+typedef unsigned int uint32;
+typedef signed int int32;
+typedef uint64_t uint64;
+typedef int64_t int64;
+
+#define LIT64( a ) a##LL
+#define INLINE static inline
+
+#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#define SNAN_BIT_IS_ONE		1
+#else
+#define SNAN_BIT_IS_ONE		0
+#endif
+
+#define STATUS_PARAM , float_status *status
+#define STATUS(field) status->field
+#define STATUS_VAR , status
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE floating-point ordering relations
+*----------------------------------------------------------------------------*/
+enum {
+    float_relation_less      = -1,
+    float_relation_equal     =  0,
+    float_relation_greater   =  1,
+    float_relation_unordered =  2
+};
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE floating-point types.
+*----------------------------------------------------------------------------*/
+/* Use structures for soft-float types.  This prevents accidentally mixing
+   them with native int/float types.  A sufficiently clever compiler and
+   sane ABI should be able to see though these structs.  However
+   x86/gcc 3.x seems to struggle a bit, so leave them disabled by default.  */
+//#define USE_SOFTFLOAT_STRUCT_TYPES
+#ifdef USE_SOFTFLOAT_STRUCT_TYPES
+typedef struct {
+    uint16_t v;
+} float16;
+#define float16_val(x) (((float16)(x)).v)
+#define make_float16(x) __extension__ ({ float16 f16_val = {x}; f16_val; })
+#define const_float16(x) { x }
+typedef struct {
+    uint32_t v;
+} float32;
+/* The cast ensures an error if the wrong type is passed.  */
+#define float32_val(x) (((float32)(x)).v)
+#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; })
+#define const_float32(x) { x }
+typedef struct {
+    uint64_t v;
+} float64;
+#define float64_val(x) (((float64)(x)).v)
+#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; })
+#define const_float64(x) { x }
+#else
+typedef uint16_t float16;
+typedef uint32_t float32;
+typedef uint64_t float64;
+#define float16_val(x) (x)
+#define float32_val(x) (x)
+#define float64_val(x) (x)
+#define make_float16(x) (x)
+#define make_float32(x) (x)
+#define make_float64(x) (x)
+#define const_float16(x) (x)
+#define const_float32(x) (x)
+#define const_float64(x) (x)
+#endif
+typedef struct {
+    uint64_t low;
+    uint16_t high;
+} floatx80;
+#define make_floatx80(exp, mant) ((floatx80) { mant, exp })
+typedef struct {
+#ifdef HOST_WORDS_BIGENDIAN
+    uint64_t high, low;
+#else
+    uint64_t low, high;
+#endif
+} float128;
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE floating-point underflow tininess-detection mode.
+*----------------------------------------------------------------------------*/
+enum {
+    float_tininess_after_rounding  = 0,
+    float_tininess_before_rounding = 1
+};
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE floating-point rounding mode.
+*----------------------------------------------------------------------------*/
+enum {
+    float_round_nearest_even = 0,
+    float_round_down         = 1,
+    float_round_up           = 2,
+    float_round_to_zero      = 3
+};
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE floating-point exception flags.
+*----------------------------------------------------------------------------*/
+enum {
+    float_flag_invalid   =  1,
+    float_flag_divbyzero =  4,
+    float_flag_overflow  =  8,
+    float_flag_underflow = 16,
+    float_flag_inexact   = 32,
+    float_flag_input_denormal = 64,
+    float_flag_output_denormal = 128
+};
+
+typedef struct float_status {
+    signed char float_detect_tininess;
+    signed char float_rounding_mode;
+    signed char float_exception_flags;
+    signed char floatx80_rounding_precision;
+    /* should denormalised results go to zero and set the inexact flag? */
+    flag flush_to_zero;
+    /* should denormalised inputs go to zero and set the input_denormal flag? */
+    flag flush_inputs_to_zero;
+    flag default_nan_mode;
+} float_status;
+
+void set_float_rounding_mode(int val STATUS_PARAM);
+void set_float_exception_flags(int val STATUS_PARAM);
+INLINE void set_float_detect_tininess(int val STATUS_PARAM)
+{
+    STATUS(float_detect_tininess) = val;
+}
+INLINE void set_flush_to_zero(flag val STATUS_PARAM)
+{
+    STATUS(flush_to_zero) = val;
+}
+INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM)
+{
+    STATUS(flush_inputs_to_zero) = val;
+}
+INLINE void set_default_nan_mode(flag val STATUS_PARAM)
+{
+    STATUS(default_nan_mode) = val;
+}
+INLINE int get_float_exception_flags(float_status *status)
+{
+    return STATUS(float_exception_flags);
+}
+void set_floatx80_rounding_precision(int val STATUS_PARAM);
+
+/*----------------------------------------------------------------------------
+| Routine to raise any or all of the software IEC/IEEE floating-point
+| exception flags.
+*----------------------------------------------------------------------------*/
+void float_raise( int8 flags STATUS_PARAM);
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE integer-to-floating-point conversion routines.
+*----------------------------------------------------------------------------*/
+float32 int32_to_float32( int32 STATUS_PARAM );
+float64 int32_to_float64( int32 STATUS_PARAM );
+float32 uint32_to_float32( unsigned int STATUS_PARAM );
+float64 uint32_to_float64( unsigned int STATUS_PARAM );
+floatx80 int32_to_floatx80( int32 STATUS_PARAM );
+float128 int32_to_float128( int32 STATUS_PARAM );
+float32 int64_to_float32( int64 STATUS_PARAM );
+float32 uint64_to_float32( uint64 STATUS_PARAM );
+float64 int64_to_float64( int64 STATUS_PARAM );
+float64 uint64_to_float64( uint64 STATUS_PARAM );
+floatx80 int64_to_floatx80( int64 STATUS_PARAM );
+float128 int64_to_float128( int64 STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software half-precision conversion routines.
+*----------------------------------------------------------------------------*/
+float16 float32_to_float16( float32, flag STATUS_PARAM );
+float32 float16_to_float32( float16, flag STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software half-precision operations.
+*----------------------------------------------------------------------------*/
+int float16_is_quiet_nan( float16 );
+int float16_is_signaling_nan( float16 );
+float16 float16_maybe_silence_nan( float16 );
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated half-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+#define float16_default_nan make_float16(0x7E00)
+#elif SNAN_BIT_IS_ONE
+#define float16_default_nan make_float16(0x7DFF)
+#else
+#define float16_default_nan make_float16(0xFE00)
+#endif
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int16 float32_to_int16_round_to_zero( float32 STATUS_PARAM );
+unsigned int float32_to_uint16_round_to_zero( float32 STATUS_PARAM );
+int32 float32_to_int32( float32 STATUS_PARAM );
+int32 float32_to_int32_round_to_zero( float32 STATUS_PARAM );
+uint32 float32_to_uint32( float32 STATUS_PARAM );
+uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
+int64 float32_to_int64( float32 STATUS_PARAM );
+int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM );
+float64 float32_to_float64( float32 STATUS_PARAM );
+floatx80 float32_to_floatx80( float32 STATUS_PARAM );
+float128 float32_to_float128( float32 STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision operations.
+*----------------------------------------------------------------------------*/
+float32 float32_round_to_int( float32 STATUS_PARAM );
+float32 float32_add( float32, float32 STATUS_PARAM );
+float32 float32_sub( float32, float32 STATUS_PARAM );
+float32 float32_mul( float32, float32 STATUS_PARAM );
+float32 float32_div( float32, float32 STATUS_PARAM );
+float32 float32_rem( float32, float32 STATUS_PARAM );
+float32 float32_sqrt( float32 STATUS_PARAM );
+float32 float32_exp2( float32 STATUS_PARAM );
+float32 float32_log2( float32 STATUS_PARAM );
+int float32_eq( float32, float32 STATUS_PARAM );
+int float32_le( float32, float32 STATUS_PARAM );
+int float32_lt( float32, float32 STATUS_PARAM );
+int float32_unordered( float32, float32 STATUS_PARAM );
+int float32_eq_quiet( float32, float32 STATUS_PARAM );
+int float32_le_quiet( float32, float32 STATUS_PARAM );
+int float32_lt_quiet( float32, float32 STATUS_PARAM );
+int float32_unordered_quiet( float32, float32 STATUS_PARAM );
+int float32_compare( float32, float32 STATUS_PARAM );
+int float32_compare_quiet( float32, float32 STATUS_PARAM );
+float32 float32_min(float32, float32 STATUS_PARAM);
+float32 float32_max(float32, float32 STATUS_PARAM);
+int float32_is_quiet_nan( float32 );
+int float32_is_signaling_nan( float32 );
+float32 float32_maybe_silence_nan( float32 );
+float32 float32_scalbn( float32, int STATUS_PARAM );
+
+INLINE float32 float32_abs(float32 a)
+{
+    /* Note that abs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
+    return make_float32(float32_val(a) & 0x7fffffff);
+}
+
+INLINE float32 float32_chs(float32 a)
+{
+    /* Note that chs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
+    return make_float32(float32_val(a) ^ 0x80000000);
+}
+
+INLINE int float32_is_infinity(float32 a)
+{
+    return (float32_val(a) & 0x7fffffff) == 0x7f800000;
+}
+
+INLINE int float32_is_neg(float32 a)
+{
+    return float32_val(a) >> 31;
+}
+
+INLINE int float32_is_zero(float32 a)
+{
+    return (float32_val(a) & 0x7fffffff) == 0;
+}
+
+INLINE int float32_is_any_nan(float32 a)
+{
+    return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL);
+}
+
+INLINE int float32_is_zero_or_denormal(float32 a)
+{
+    return (float32_val(a) & 0x7f800000) == 0;
+}
+
+INLINE float32 float32_set_sign(float32 a, int sign)
+{
+    return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31));
+}
+
+#define float32_zero make_float32(0)
+#define float32_one make_float32(0x3f800000)
+#define float32_ln2 make_float32(0x3f317218)
+#define float32_pi make_float32(0x40490fdb)
+#define float32_half make_float32(0x3f000000)
+#define float32_infinity make_float32(0x7f800000)
+
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+#define float32_default_nan make_float32(0x7FFFFFFF)
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+#define float32_default_nan make_float32(0x7FC00000)
+#elif SNAN_BIT_IS_ONE
+#define float32_default_nan make_float32(0x7FBFFFFF)
+#else
+#define float32_default_nan make_float32(0xFFC00000)
+#endif
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int16 float64_to_int16_round_to_zero( float64 STATUS_PARAM );
+unsigned int float64_to_uint16_round_to_zero( float64 STATUS_PARAM );
+int32 float64_to_int32( float64 STATUS_PARAM );
+int32 float64_to_int32_round_to_zero( float64 STATUS_PARAM );
+uint32 float64_to_uint32( float64 STATUS_PARAM );
+uint32 float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
+int64 float64_to_int64( float64 STATUS_PARAM );
+int64 float64_to_int64_round_to_zero( float64 STATUS_PARAM );
+uint64 float64_to_uint64 (float64 a STATUS_PARAM);
+uint64 float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
+float32 float64_to_float32( float64 STATUS_PARAM );
+floatx80 float64_to_floatx80( float64 STATUS_PARAM );
+float128 float64_to_float128( float64 STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision operations.
+*----------------------------------------------------------------------------*/
+float64 float64_round_to_int( float64 STATUS_PARAM );
+float64 float64_trunc_to_int( float64 STATUS_PARAM );
+float64 float64_add( float64, float64 STATUS_PARAM );
+float64 float64_sub( float64, float64 STATUS_PARAM );
+float64 float64_mul( float64, float64 STATUS_PARAM );
+float64 float64_div( float64, float64 STATUS_PARAM );
+float64 float64_rem( float64, float64 STATUS_PARAM );
+float64 float64_sqrt( float64 STATUS_PARAM );
+float64 float64_log2( float64 STATUS_PARAM );
+int float64_eq( float64, float64 STATUS_PARAM );
+int float64_le( float64, float64 STATUS_PARAM );
+int float64_lt( float64, float64 STATUS_PARAM );
+int float64_unordered( float64, float64 STATUS_PARAM );
+int float64_eq_quiet( float64, float64 STATUS_PARAM );
+int float64_le_quiet( float64, float64 STATUS_PARAM );
+int float64_lt_quiet( float64, float64 STATUS_PARAM );
+int float64_unordered_quiet( float64, float64 STATUS_PARAM );
+int float64_compare( float64, float64 STATUS_PARAM );
+int float64_compare_quiet( float64, float64 STATUS_PARAM );
+float64 float64_min(float64, float64 STATUS_PARAM);
+float64 float64_max(float64, float64 STATUS_PARAM);
+int float64_is_quiet_nan( float64 a );
+int float64_is_signaling_nan( float64 );
+float64 float64_maybe_silence_nan( float64 );
+float64 float64_scalbn( float64, int STATUS_PARAM );
+
+INLINE float64 float64_abs(float64 a)
+{
+    /* Note that abs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
+    return make_float64(float64_val(a) & 0x7fffffffffffffffLL);
+}
+
+INLINE float64 float64_chs(float64 a)
+{
+    /* Note that chs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
+    return make_float64(float64_val(a) ^ 0x8000000000000000LL);
+}
+
+INLINE int float64_is_infinity(float64 a)
+{
+    return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL;
+}
+
+INLINE int float64_is_neg(float64 a)
+{
+    return float64_val(a) >> 63;
+}
+
+INLINE int float64_is_zero(float64 a)
+{
+    return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
+}
+
+INLINE int float64_is_any_nan(float64 a)
+{
+    return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
+}
+
+INLINE int float64_is_zero_or_denormal(float64 a)
+{
+    return (float64_val(a) & 0x7ff0000000000000LL) == 0;
+}
+
+INLINE float64 float64_set_sign(float64 a, int sign)
+{
+    return make_float64((float64_val(a) & 0x7fffffffffffffffULL)
+                        | ((int64_t)sign << 63));
+}
+
+#define float64_zero make_float64(0)
+#define float64_one make_float64(0x3ff0000000000000LL)
+#define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
+#define float64_pi make_float64(0x400921fb54442d18LL)
+#define float64_half make_float64(0x3fe0000000000000LL)
+#define float64_infinity make_float64(0x7ff0000000000000LL)
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
+#elif SNAN_BIT_IS_ONE
+#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
+#else
+#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
+#endif
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE extended double-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 floatx80_to_int32( floatx80 STATUS_PARAM );
+int32 floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
+int64 floatx80_to_int64( floatx80 STATUS_PARAM );
+int64 floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
+float32 floatx80_to_float32( floatx80 STATUS_PARAM );
+float64 floatx80_to_float64( floatx80 STATUS_PARAM );
+float128 floatx80_to_float128( floatx80 STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE extended double-precision operations.
+*----------------------------------------------------------------------------*/
+floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
+floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM );
+floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM );
+floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM );
+floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM );
+floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
+floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
+int floatx80_eq( floatx80, floatx80 STATUS_PARAM );
+int floatx80_le( floatx80, floatx80 STATUS_PARAM );
+int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
+int floatx80_unordered( floatx80, floatx80 STATUS_PARAM );
+int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
+int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_is_quiet_nan( floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+floatx80 floatx80_maybe_silence_nan( floatx80 );
+floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM );
+
+INLINE floatx80 floatx80_abs(floatx80 a)
+{
+    a.high &= 0x7fff;
+    return a;
+}
+
+INLINE floatx80 floatx80_chs(floatx80 a)
+{
+    a.high ^= 0x8000;
+    return a;
+}
+
+INLINE int floatx80_is_infinity(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL;
+}
+
+INLINE int floatx80_is_neg(floatx80 a)
+{
+    return a.high >> 15;
+}
+
+INLINE int floatx80_is_zero(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0 && a.low == 0;
+}
+
+INLINE int floatx80_is_zero_or_denormal(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0;
+}
+
+INLINE int floatx80_is_any_nan(floatx80 a)
+{
+    return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
+}
+
+#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
+#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL)
+#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)
+#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL)
+#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL)
+#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision NaN.  The
+| `high' and `low' values hold the most- and least-significant bits,
+| respectively.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define floatx80_default_nan_high 0x7FFF
+#define floatx80_default_nan_low  LIT64( 0xBFFFFFFFFFFFFFFF )
+#else
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low  LIT64( 0xC000000000000000 )
+#endif
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE quadruple-precision conversion routines.
+*----------------------------------------------------------------------------*/
+int32 float128_to_int32( float128 STATUS_PARAM );
+int32 float128_to_int32_round_to_zero( float128 STATUS_PARAM );
+int64 float128_to_int64( float128 STATUS_PARAM );
+int64 float128_to_int64_round_to_zero( float128 STATUS_PARAM );
+float32 float128_to_float32( float128 STATUS_PARAM );
+float64 float128_to_float64( float128 STATUS_PARAM );
+floatx80 float128_to_floatx80( float128 STATUS_PARAM );
+
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE quadruple-precision operations.
+*----------------------------------------------------------------------------*/
+float128 float128_round_to_int( float128 STATUS_PARAM );
+float128 float128_add( float128, float128 STATUS_PARAM );
+float128 float128_sub( float128, float128 STATUS_PARAM );
+float128 float128_mul( float128, float128 STATUS_PARAM );
+float128 float128_div( float128, float128 STATUS_PARAM );
+float128 float128_rem( float128, float128 STATUS_PARAM );
+float128 float128_sqrt( float128 STATUS_PARAM );
+int float128_eq( float128, float128 STATUS_PARAM );
+int float128_le( float128, float128 STATUS_PARAM );
+int float128_lt( float128, float128 STATUS_PARAM );
+int float128_unordered( float128, float128 STATUS_PARAM );
+int float128_eq_quiet( float128, float128 STATUS_PARAM );
+int float128_le_quiet( float128, float128 STATUS_PARAM );
+int float128_lt_quiet( float128, float128 STATUS_PARAM );
+int float128_unordered_quiet( float128, float128 STATUS_PARAM );
+int float128_compare( float128, float128 STATUS_PARAM );
+int float128_compare_quiet( float128, float128 STATUS_PARAM );
+int float128_is_quiet_nan( float128 );
+int float128_is_signaling_nan( float128 );
+float128 float128_maybe_silence_nan( float128 );
+float128 float128_scalbn( float128, int STATUS_PARAM );
+
+INLINE float128 float128_abs(float128 a)
+{
+    a.high &= 0x7fffffffffffffffLL;
+    return a;
+}
+
+INLINE float128 float128_chs(float128 a)
+{
+    a.high ^= 0x8000000000000000LL;
+    return a;
+}
+
+INLINE int float128_is_infinity(float128 a)
+{
+    return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0;
+}
+
+INLINE int float128_is_neg(float128 a)
+{
+    return a.high >> 63;
+}
+
+INLINE int float128_is_zero(float128 a)
+{
+    return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
+}
+
+INLINE int float128_is_zero_or_denormal(float128 a)
+{
+    return (a.high & 0x7fff000000000000LL) == 0;
+}
+
+INLINE int float128_is_any_nan(float128 a)
+{
+    return ((a.high >> 48) & 0x7fff) == 0x7fff &&
+        ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0));
+}
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated quadruple-precision NaN.  The `high' and
+| `low' values hold the most- and least-significant bits, respectively.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
+#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
+#else
+#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
+#define float128_default_nan_low  LIT64( 0x0000000000000000 )
+#endif
+
+#endif /* !SOFTFLOAT_H */
diff --git a/qemu-0.15.x/fsdev/file-op-9p.h b/qemu-0.15.x/fsdev/file-op-9p.h
new file mode 100644
index 0000000..af9daf7
--- /dev/null
+++ b/qemu-0.15.x/fsdev/file-op-9p.h
@@ -0,0 +1,100 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _FILEOP_H
+#define _FILEOP_H
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#define SM_LOCAL_MODE_BITS    0600
+#define SM_LOCAL_DIR_MODE_BITS    0700
+
+typedef enum
+{
+    /*
+     * Server will try to set uid/gid.
+     * On failure ignore the error.
+     */
+    SM_NONE = 0,
+    /*
+     * uid/gid set on fileserver files
+     */
+    SM_PASSTHROUGH = 1,
+    /*
+     * uid/gid part of xattr
+     */
+    SM_MAPPED,
+} SecModel;
+
+typedef struct FsCred
+{
+    uid_t   fc_uid;
+    gid_t   fc_gid;
+    mode_t  fc_mode;
+    dev_t   fc_rdev;
+} FsCred;
+
+struct xattr_operations;
+
+typedef struct FsContext
+{
+    char *fs_root;
+    SecModel fs_sm;
+    uid_t uid;
+    struct xattr_operations **xops;
+} FsContext;
+
+void cred_init(FsCred *);
+
+typedef struct FileOperations
+{
+    int (*lstat)(FsContext *, const char *, struct stat *);
+    ssize_t (*readlink)(FsContext *, const char *, char *, size_t);
+    int (*chmod)(FsContext *, const char *, FsCred *);
+    int (*chown)(FsContext *, const char *, FsCred *);
+    int (*mknod)(FsContext *, const char *, FsCred *);
+    int (*utimensat)(FsContext *, const char *, const struct timespec *);
+    int (*remove)(FsContext *, const char *);
+    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
+    int (*link)(FsContext *, const char *, const char *);
+    int (*setuid)(FsContext *, uid_t);
+    int (*close)(FsContext *, int);
+    int (*closedir)(FsContext *, DIR *);
+    DIR *(*opendir)(FsContext *, const char *);
+    int (*open)(FsContext *, const char *, int);
+    int (*open2)(FsContext *, const char *, int, FsCred *);
+    void (*rewinddir)(FsContext *, DIR *);
+    off_t (*telldir)(FsContext *, DIR *);
+    struct dirent *(*readdir)(FsContext *, DIR *);
+    void (*seekdir)(FsContext *, DIR *, off_t);
+    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
+    int (*mkdir)(FsContext *, const char *, FsCred *);
+    int (*fstat)(FsContext *, int, struct stat *);
+    int (*rename)(FsContext *, const char *, const char *);
+    int (*truncate)(FsContext *, const char *, off_t);
+    int (*fsync)(FsContext *, int, int);
+    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, const char *,
+                         const char *, void *, size_t);
+    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
+    int (*lsetxattr)(FsContext *, const char *,
+                     const char *, void *, size_t, int);
+    int (*lremovexattr)(FsContext *, const char *, const char *);
+    void *opaque;
+} FileOperations;
+
+#endif
diff --git a/qemu-0.15.x/fsdev/qemu-fsdev-dummy.c b/qemu-0.15.x/fsdev/qemu-fsdev-dummy.c
new file mode 100644
index 0000000..4e700dd
--- /dev/null
+++ b/qemu-0.15.x/fsdev/qemu-fsdev-dummy.c
@@ -0,0 +1,28 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Gautham R Shenoy <ego at in.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "qemu-fsdev.h"
+#include "qemu-config.h"
+
+int qemu_fsdev_add(QemuOpts *opts)
+{
+    return 0;
+}
+
+static void fsdev_register_config(void)
+{
+    qemu_add_opts(&qemu_fsdev_opts);
+    qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
diff --git a/qemu-0.15.x/fsdev/qemu-fsdev.c b/qemu-0.15.x/fsdev/qemu-fsdev.c
new file mode 100644
index 0000000..0b33290
--- /dev/null
+++ b/qemu-0.15.x/fsdev/qemu-fsdev.c
@@ -0,0 +1,100 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Gautham R Shenoy <ego at in.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "qemu-fsdev.h"
+#include "qemu-queue.h"
+#include "osdep.h"
+#include "qemu-common.h"
+#include "qemu-config.h"
+
+static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
+    QTAILQ_HEAD_INITIALIZER(fstype_entries);
+
+static FsTypeTable FsTypes[] = {
+    { .name = "local", .ops = &local_ops},
+};
+
+int qemu_fsdev_add(QemuOpts *opts)
+{
+    struct FsTypeListEntry *fsle;
+    int i;
+    const char *fsdev_id = qemu_opts_id(opts);
+    const char *fstype = qemu_opt_get(opts, "fstype");
+    const char *path = qemu_opt_get(opts, "path");
+    const char *sec_model = qemu_opt_get(opts, "security_model");
+
+    if (!fsdev_id) {
+        fprintf(stderr, "fsdev: No id specified\n");
+        return -1;
+    }
+
+    if (fstype) {
+        for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
+            if (strcmp(FsTypes[i].name, fstype) == 0) {
+                break;
+            }
+        }
+
+        if (i == ARRAY_SIZE(FsTypes)) {
+            fprintf(stderr, "fsdev: fstype %s not found\n", fstype);
+            return -1;
+        }
+    } else {
+        fprintf(stderr, "fsdev: No fstype specified\n");
+        return -1;
+    }
+
+    if (!sec_model) {
+        fprintf(stderr, "fsdev: No security_model specified.\n");
+        return -1;
+    }
+
+    if (!path) {
+        fprintf(stderr, "fsdev: No path specified.\n");
+        return -1;
+    }
+
+    fsle = qemu_malloc(sizeof(*fsle));
+
+    fsle->fse.fsdev_id = qemu_strdup(fsdev_id);
+    fsle->fse.path = qemu_strdup(path);
+    fsle->fse.security_model = qemu_strdup(sec_model);
+    fsle->fse.ops = FsTypes[i].ops;
+
+    QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next);
+    return 0;
+
+}
+
+FsTypeEntry *get_fsdev_fsentry(char *id)
+{
+    if (id) {
+        struct FsTypeListEntry *fsle;
+
+        QTAILQ_FOREACH(fsle, &fstype_entries, next) {
+            if (strcmp(fsle->fse.fsdev_id, id) == 0) {
+                return &fsle->fse;
+            }
+        }
+    }
+    return NULL;
+}
+
+static void fsdev_register_config(void)
+{
+    qemu_add_opts(&qemu_fsdev_opts);
+    qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
+
diff --git a/qemu-0.15.x/fsdev/qemu-fsdev.h b/qemu-0.15.x/fsdev/qemu-fsdev.h
new file mode 100644
index 0000000..f9f08d3
--- /dev/null
+++ b/qemu-0.15.x/fsdev/qemu-fsdev.h
@@ -0,0 +1,55 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Gautham R Shenoy <ego at in.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_FSDEV_H
+#define QEMU_FSDEV_H
+#include "qemu-option.h"
+#include "file-op-9p.h"
+
+
+/*
+ * A table to store the various file systems and their callback operations.
+ * -----------------
+ * fstype | ops
+ * -----------------
+ *  local | local_ops
+ *  .     |
+ *  .     |
+ *  .     |
+ *  .     |
+ * -----------------
+ *  etc
+ */
+typedef struct FsTypeTable {
+    const char *name;
+    FileOperations *ops;
+} FsTypeTable;
+
+/*
+ * Structure to store the various fsdev's passed through command line.
+ */
+typedef struct FsTypeEntry {
+    char *fsdev_id;
+    char *path;
+    char *security_model;
+    FileOperations *ops;
+} FsTypeEntry;
+
+typedef struct FsTypeListEntry {
+    FsTypeEntry fse;
+    QTAILQ_ENTRY(FsTypeListEntry) next;
+} FsTypeListEntry;
+
+int qemu_fsdev_add(QemuOpts *opts);
+FsTypeEntry *get_fsdev_fsentry(char *id);
+extern FileOperations local_ops;
+#endif
diff --git a/qemu-0.15.x/gdb-xml/arm-core.xml b/qemu-0.15.x/gdb-xml/arm-core.xml
new file mode 100644
index 0000000..6012f34
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/arm-core.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+  <reg name="lr" bitsize="32"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsr" bitsize="32" regnum="25"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/arm-neon.xml b/qemu-0.15.x/gdb-xml/arm-neon.xml
new file mode 100644
index 0000000..ce3ee03
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/arm-neon.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <vector id="neon_uint8x8" type="uint8" count="8"/>
+  <vector id="neon_uint16x4" type="uint16" count="4"/>
+  <vector id="neon_uint32x2" type="uint32" count="2"/>
+  <vector id="neon_float32x2" type="ieee_single" count="2"/>
+  <union id="neon_d">
+    <field name="u8" type="neon_uint8x8"/>
+    <field name="u16" type="neon_uint16x4"/>
+    <field name="u32" type="neon_uint32x2"/>
+    <field name="u64" type="uint64"/>
+    <field name="f32" type="neon_float32x2"/>
+    <field name="f64" type="ieee_double"/>
+  </union>
+  <vector id="neon_uint8x16" type="uint8" count="16"/>
+  <vector id="neon_uint16x8" type="uint16" count="8"/>
+  <vector id="neon_uint32x4" type="uint32" count="4"/>
+  <vector id="neon_uint64x2" type="uint64" count="2"/>
+  <vector id="neon_float32x4" type="ieee_single" count="4"/>
+  <vector id="neon_float64x2" type="ieee_double" count="2"/>
+  <union id="neon_q">
+    <field name="u8" type="neon_uint8x16"/>
+    <field name="u16" type="neon_uint16x8"/>
+    <field name="u32" type="neon_uint32x4"/>
+    <field name="u64" type="neon_uint64x2"/>
+    <field name="f32" type="neon_float32x4"/>
+    <field name="f64" type="neon_float64x2"/>
+  </union>
+  <reg name="d0" bitsize="64" type="neon_d"/>
+  <reg name="d1" bitsize="64" type="neon_d"/>
+  <reg name="d2" bitsize="64" type="neon_d"/>
+  <reg name="d3" bitsize="64" type="neon_d"/>
+  <reg name="d4" bitsize="64" type="neon_d"/>
+  <reg name="d5" bitsize="64" type="neon_d"/>
+  <reg name="d6" bitsize="64" type="neon_d"/>
+  <reg name="d7" bitsize="64" type="neon_d"/>
+  <reg name="d8" bitsize="64" type="neon_d"/>
+  <reg name="d9" bitsize="64" type="neon_d"/>
+  <reg name="d10" bitsize="64" type="neon_d"/>
+  <reg name="d11" bitsize="64" type="neon_d"/>
+  <reg name="d12" bitsize="64" type="neon_d"/>
+  <reg name="d13" bitsize="64" type="neon_d"/>
+  <reg name="d14" bitsize="64" type="neon_d"/>
+  <reg name="d15" bitsize="64" type="neon_d"/>
+  <reg name="d16" bitsize="64" type="neon_d"/>
+  <reg name="d17" bitsize="64" type="neon_d"/>
+  <reg name="d18" bitsize="64" type="neon_d"/>
+  <reg name="d19" bitsize="64" type="neon_d"/>
+  <reg name="d20" bitsize="64" type="neon_d"/>
+  <reg name="d21" bitsize="64" type="neon_d"/>
+  <reg name="d22" bitsize="64" type="neon_d"/>
+  <reg name="d23" bitsize="64" type="neon_d"/>
+  <reg name="d24" bitsize="64" type="neon_d"/>
+  <reg name="d25" bitsize="64" type="neon_d"/>
+  <reg name="d26" bitsize="64" type="neon_d"/>
+  <reg name="d27" bitsize="64" type="neon_d"/>
+  <reg name="d28" bitsize="64" type="neon_d"/>
+  <reg name="d29" bitsize="64" type="neon_d"/>
+  <reg name="d30" bitsize="64" type="neon_d"/>
+  <reg name="d31" bitsize="64" type="neon_d"/>
+
+  <reg name="q0" bitsize="128" type="neon_q"/>
+  <reg name="q1" bitsize="128" type="neon_q"/>
+  <reg name="q2" bitsize="128" type="neon_q"/>
+  <reg name="q3" bitsize="128" type="neon_q"/>
+  <reg name="q4" bitsize="128" type="neon_q"/>
+  <reg name="q5" bitsize="128" type="neon_q"/>
+  <reg name="q6" bitsize="128" type="neon_q"/>
+  <reg name="q7" bitsize="128" type="neon_q"/>
+  <reg name="q8" bitsize="128" type="neon_q"/>
+  <reg name="q9" bitsize="128" type="neon_q"/>
+  <reg name="q10" bitsize="128" type="neon_q"/>
+  <reg name="q10" bitsize="128" type="neon_q"/>
+  <reg name="q12" bitsize="128" type="neon_q"/>
+  <reg name="q13" bitsize="128" type="neon_q"/>
+  <reg name="q14" bitsize="128" type="neon_q"/>
+  <reg name="q15" bitsize="128" type="neon_q"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/arm-vfp.xml b/qemu-0.15.x/gdb-xml/arm-vfp.xml
new file mode 100644
index 0000000..b20881e
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/arm-vfp.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="float"/>
+  <reg name="d1" bitsize="64" type="float"/>
+  <reg name="d2" bitsize="64" type="float"/>
+  <reg name="d3" bitsize="64" type="float"/>
+  <reg name="d4" bitsize="64" type="float"/>
+  <reg name="d5" bitsize="64" type="float"/>
+  <reg name="d6" bitsize="64" type="float"/>
+  <reg name="d7" bitsize="64" type="float"/>
+  <reg name="d8" bitsize="64" type="float"/>
+  <reg name="d9" bitsize="64" type="float"/>
+  <reg name="d10" bitsize="64" type="float"/>
+  <reg name="d11" bitsize="64" type="float"/>
+  <reg name="d12" bitsize="64" type="float"/>
+  <reg name="d13" bitsize="64" type="float"/>
+  <reg name="d14" bitsize="64" type="float"/>
+  <reg name="d15" bitsize="64" type="float"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/arm-vfp3.xml b/qemu-0.15.x/gdb-xml/arm-vfp3.xml
new file mode 100644
index 0000000..227afd8
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/arm-vfp3.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="float"/>
+  <reg name="d1" bitsize="64" type="float"/>
+  <reg name="d2" bitsize="64" type="float"/>
+  <reg name="d3" bitsize="64" type="float"/>
+  <reg name="d4" bitsize="64" type="float"/>
+  <reg name="d5" bitsize="64" type="float"/>
+  <reg name="d6" bitsize="64" type="float"/>
+  <reg name="d7" bitsize="64" type="float"/>
+  <reg name="d8" bitsize="64" type="float"/>
+  <reg name="d9" bitsize="64" type="float"/>
+  <reg name="d10" bitsize="64" type="float"/>
+  <reg name="d11" bitsize="64" type="float"/>
+  <reg name="d12" bitsize="64" type="float"/>
+  <reg name="d13" bitsize="64" type="float"/>
+  <reg name="d14" bitsize="64" type="float"/>
+  <reg name="d15" bitsize="64" type="float"/>
+  <reg name="d16" bitsize="64" type="float"/>
+  <reg name="d17" bitsize="64" type="float"/>
+  <reg name="d18" bitsize="64" type="float"/>
+  <reg name="d19" bitsize="64" type="float"/>
+  <reg name="d20" bitsize="64" type="float"/>
+  <reg name="d21" bitsize="64" type="float"/>
+  <reg name="d22" bitsize="64" type="float"/>
+  <reg name="d23" bitsize="64" type="float"/>
+  <reg name="d24" bitsize="64" type="float"/>
+  <reg name="d25" bitsize="64" type="float"/>
+  <reg name="d26" bitsize="64" type="float"/>
+  <reg name="d27" bitsize="64" type="float"/>
+  <reg name="d28" bitsize="64" type="float"/>
+  <reg name="d29" bitsize="64" type="float"/>
+  <reg name="d30" bitsize="64" type="float"/>
+  <reg name="d31" bitsize="64" type="float"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/cf-core.xml b/qemu-0.15.x/gdb-xml/cf-core.xml
new file mode 100644
index 0000000..b90af30
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/cf-core.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.coldfire.core">
+  <reg name="d0" bitsize="32"/>
+  <reg name="d1" bitsize="32"/>
+  <reg name="d2" bitsize="32"/>
+  <reg name="d3" bitsize="32"/>
+  <reg name="d4" bitsize="32"/>
+  <reg name="d5" bitsize="32"/>
+  <reg name="d6" bitsize="32"/>
+  <reg name="d7" bitsize="32"/>
+  <reg name="a0" bitsize="32" type="data_ptr"/>
+  <reg name="a1" bitsize="32" type="data_ptr"/>
+  <reg name="a2" bitsize="32" type="data_ptr"/>
+  <reg name="a3" bitsize="32" type="data_ptr"/>
+  <reg name="a4" bitsize="32" type="data_ptr"/>
+  <reg name="a5" bitsize="32" type="data_ptr"/>
+  <reg name="fp" bitsize="32" type="data_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+
+  <reg name="ps" bitsize="32"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/cf-fp.xml b/qemu-0.15.x/gdb-xml/cf-fp.xml
new file mode 100644
index 0000000..bf71c32
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/cf-fp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.coldfire.fp">
+  <reg name="fp0" bitsize="64" type="float" group="float"/>
+  <reg name="fp1" bitsize="64" type="float" group="float"/>
+  <reg name="fp2" bitsize="64" type="float" group="float"/>
+  <reg name="fp3" bitsize="64" type="float" group="float"/>
+  <reg name="fp4" bitsize="64" type="float" group="float"/>
+  <reg name="fp5" bitsize="64" type="float" group="float"/>
+  <reg name="fp6" bitsize="64" type="float" group="float"/>
+  <reg name="fp7" bitsize="64" type="float" group="float"/>
+
+  
+  <reg name="fpcontrol" bitsize="32" group="float"/>
+  <reg name="fpstatus" bitsize="32" group="float"/>,
+  <reg name="fpiaddr" bitsize="32" type="code_ptr" group="float"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/power-altivec.xml b/qemu-0.15.x/gdb-xml/power-altivec.xml
new file mode 100644
index 0000000..84f4d27
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/power-altivec.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <union id="vec128">
+    <field name="uint128" type="uint128"/>
+    <field name="v4_float" type="v4f"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v16_int8" type="v16i8"/>
+  </union>
+
+  <reg name="vr0" bitsize="128" type="vec128"/>
+  <reg name="vr1" bitsize="128" type="vec128"/>
+  <reg name="vr2" bitsize="128" type="vec128"/>
+  <reg name="vr3" bitsize="128" type="vec128"/>
+  <reg name="vr4" bitsize="128" type="vec128"/>
+  <reg name="vr5" bitsize="128" type="vec128"/>
+  <reg name="vr6" bitsize="128" type="vec128"/>
+  <reg name="vr7" bitsize="128" type="vec128"/>
+  <reg name="vr8" bitsize="128" type="vec128"/>
+  <reg name="vr9" bitsize="128" type="vec128"/>
+  <reg name="vr10" bitsize="128" type="vec128"/>
+  <reg name="vr11" bitsize="128" type="vec128"/>
+  <reg name="vr12" bitsize="128" type="vec128"/>
+  <reg name="vr13" bitsize="128" type="vec128"/>
+  <reg name="vr14" bitsize="128" type="vec128"/>
+  <reg name="vr15" bitsize="128" type="vec128"/>
+  <reg name="vr16" bitsize="128" type="vec128"/>
+  <reg name="vr17" bitsize="128" type="vec128"/>
+  <reg name="vr18" bitsize="128" type="vec128"/>
+  <reg name="vr19" bitsize="128" type="vec128"/>
+  <reg name="vr20" bitsize="128" type="vec128"/>
+  <reg name="vr21" bitsize="128" type="vec128"/>
+  <reg name="vr22" bitsize="128" type="vec128"/>
+  <reg name="vr23" bitsize="128" type="vec128"/>
+  <reg name="vr24" bitsize="128" type="vec128"/>
+  <reg name="vr25" bitsize="128" type="vec128"/>
+  <reg name="vr26" bitsize="128" type="vec128"/>
+  <reg name="vr27" bitsize="128" type="vec128"/>
+  <reg name="vr28" bitsize="128" type="vec128"/>
+  <reg name="vr29" bitsize="128" type="vec128"/>
+  <reg name="vr30" bitsize="128" type="vec128"/>
+  <reg name="vr31" bitsize="128" type="vec128"/>
+
+  <reg name="vscr" bitsize="32" group="vector"/>
+  <reg name="vrsave" bitsize="32" group="vector"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/power-core.xml b/qemu-0.15.x/gdb-xml/power-core.xml
new file mode 100644
index 0000000..0c69e8c
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/power-core.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="32" type="uint32"/>
+  <reg name="r1" bitsize="32" type="uint32"/>
+  <reg name="r2" bitsize="32" type="uint32"/>
+  <reg name="r3" bitsize="32" type="uint32"/>
+  <reg name="r4" bitsize="32" type="uint32"/>
+  <reg name="r5" bitsize="32" type="uint32"/>
+  <reg name="r6" bitsize="32" type="uint32"/>
+  <reg name="r7" bitsize="32" type="uint32"/>
+  <reg name="r8" bitsize="32" type="uint32"/>
+  <reg name="r9" bitsize="32" type="uint32"/>
+  <reg name="r10" bitsize="32" type="uint32"/>
+  <reg name="r11" bitsize="32" type="uint32"/>
+  <reg name="r12" bitsize="32" type="uint32"/>
+  <reg name="r13" bitsize="32" type="uint32"/>
+  <reg name="r14" bitsize="32" type="uint32"/>
+  <reg name="r15" bitsize="32" type="uint32"/>
+  <reg name="r16" bitsize="32" type="uint32"/>
+  <reg name="r17" bitsize="32" type="uint32"/>
+  <reg name="r18" bitsize="32" type="uint32"/>
+  <reg name="r19" bitsize="32" type="uint32"/>
+  <reg name="r20" bitsize="32" type="uint32"/>
+  <reg name="r21" bitsize="32" type="uint32"/>
+  <reg name="r22" bitsize="32" type="uint32"/>
+  <reg name="r23" bitsize="32" type="uint32"/>
+  <reg name="r24" bitsize="32" type="uint32"/>
+  <reg name="r25" bitsize="32" type="uint32"/>
+  <reg name="r26" bitsize="32" type="uint32"/>
+  <reg name="r27" bitsize="32" type="uint32"/>
+  <reg name="r28" bitsize="32" type="uint32"/>
+  <reg name="r29" bitsize="32" type="uint32"/>
+  <reg name="r30" bitsize="32" type="uint32"/>
+  <reg name="r31" bitsize="32" type="uint32"/>
+
+  <reg name="pc" bitsize="32" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="32" type="uint32"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="32" type="code_ptr"/>
+  <reg name="ctr" bitsize="32" type="uint32"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/power-fpu.xml b/qemu-0.15.x/gdb-xml/power-fpu.xml
new file mode 100644
index 0000000..3870551
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/power-fpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu">
+  <reg name="f0" bitsize="64" type="ieee_double" regnum="71"/>
+  <reg name="f1" bitsize="64" type="ieee_double"/>
+  <reg name="f2" bitsize="64" type="ieee_double"/>
+  <reg name="f3" bitsize="64" type="ieee_double"/>
+  <reg name="f4" bitsize="64" type="ieee_double"/>
+  <reg name="f5" bitsize="64" type="ieee_double"/>
+  <reg name="f6" bitsize="64" type="ieee_double"/>
+  <reg name="f7" bitsize="64" type="ieee_double"/>
+  <reg name="f8" bitsize="64" type="ieee_double"/>
+  <reg name="f9" bitsize="64" type="ieee_double"/>
+  <reg name="f10" bitsize="64" type="ieee_double"/>
+  <reg name="f11" bitsize="64" type="ieee_double"/>
+  <reg name="f12" bitsize="64" type="ieee_double"/>
+  <reg name="f13" bitsize="64" type="ieee_double"/>
+  <reg name="f14" bitsize="64" type="ieee_double"/>
+  <reg name="f15" bitsize="64" type="ieee_double"/>
+  <reg name="f16" bitsize="64" type="ieee_double"/>
+  <reg name="f17" bitsize="64" type="ieee_double"/>
+  <reg name="f18" bitsize="64" type="ieee_double"/>
+  <reg name="f19" bitsize="64" type="ieee_double"/>
+  <reg name="f20" bitsize="64" type="ieee_double"/>
+  <reg name="f21" bitsize="64" type="ieee_double"/>
+  <reg name="f22" bitsize="64" type="ieee_double"/>
+  <reg name="f23" bitsize="64" type="ieee_double"/>
+  <reg name="f24" bitsize="64" type="ieee_double"/>
+  <reg name="f25" bitsize="64" type="ieee_double"/>
+  <reg name="f26" bitsize="64" type="ieee_double"/>
+  <reg name="f27" bitsize="64" type="ieee_double"/>
+  <reg name="f28" bitsize="64" type="ieee_double"/>
+  <reg name="f29" bitsize="64" type="ieee_double"/>
+  <reg name="f30" bitsize="64" type="ieee_double"/>
+  <reg name="f31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" group="float"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/power-spe.xml b/qemu-0.15.x/gdb-xml/power-spe.xml
new file mode 100644
index 0000000..57740cc
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/power-spe.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.spe">
+  <reg name="ev0h" bitsize="32" regnum="71"/>
+  <reg name="ev1h" bitsize="32"/>
+  <reg name="ev2h" bitsize="32"/>
+  <reg name="ev3h" bitsize="32"/>
+  <reg name="ev4h" bitsize="32"/>
+  <reg name="ev5h" bitsize="32"/>
+  <reg name="ev6h" bitsize="32"/>
+  <reg name="ev7h" bitsize="32"/>
+  <reg name="ev8h" bitsize="32"/>
+  <reg name="ev9h" bitsize="32"/>
+  <reg name="ev10h" bitsize="32"/>
+  <reg name="ev11h" bitsize="32"/>
+  <reg name="ev12h" bitsize="32"/>
+  <reg name="ev13h" bitsize="32"/>
+  <reg name="ev14h" bitsize="32"/>
+  <reg name="ev15h" bitsize="32"/>
+  <reg name="ev16h" bitsize="32"/>
+  <reg name="ev17h" bitsize="32"/>
+  <reg name="ev18h" bitsize="32"/>
+  <reg name="ev19h" bitsize="32"/>
+  <reg name="ev20h" bitsize="32"/>
+  <reg name="ev21h" bitsize="32"/>
+  <reg name="ev22h" bitsize="32"/>
+  <reg name="ev23h" bitsize="32"/>
+  <reg name="ev24h" bitsize="32"/>
+  <reg name="ev25h" bitsize="32"/>
+  <reg name="ev26h" bitsize="32"/>
+  <reg name="ev27h" bitsize="32"/>
+  <reg name="ev28h" bitsize="32"/>
+  <reg name="ev29h" bitsize="32"/>
+  <reg name="ev30h" bitsize="32"/>
+  <reg name="ev31h" bitsize="32"/>
+
+  <reg name="acc" bitsize="64"/>
+  <reg name="spefscr" bitsize="32"/>
+</feature>
diff --git a/qemu-0.15.x/gdb-xml/power64-core.xml b/qemu-0.15.x/gdb-xml/power64-core.xml
new file mode 100644
index 0000000..6cc1531
--- /dev/null
+++ b/qemu-0.15.x/gdb-xml/power64-core.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="64" type="uint64"/>
+  <reg name="r1" bitsize="64" type="uint64"/>
+  <reg name="r2" bitsize="64" type="uint64"/>
+  <reg name="r3" bitsize="64" type="uint64"/>
+  <reg name="r4" bitsize="64" type="uint64"/>
+  <reg name="r5" bitsize="64" type="uint64"/>
+  <reg name="r6" bitsize="64" type="uint64"/>
+  <reg name="r7" bitsize="64" type="uint64"/>
+  <reg name="r8" bitsize="64" type="uint64"/>
+  <reg name="r9" bitsize="64" type="uint64"/>
+  <reg name="r10" bitsize="64" type="uint64"/>
+  <reg name="r11" bitsize="64" type="uint64"/>
+  <reg name="r12" bitsize="64" type="uint64"/>
+  <reg name="r13" bitsize="64" type="uint64"/>
+  <reg name="r14" bitsize="64" type="uint64"/>
+  <reg name="r15" bitsize="64" type="uint64"/>
+  <reg name="r16" bitsize="64" type="uint64"/>
+  <reg name="r17" bitsize="64" type="uint64"/>
+  <reg name="r18" bitsize="64" type="uint64"/>
+  <reg name="r19" bitsize="64" type="uint64"/>
+  <reg name="r20" bitsize="64" type="uint64"/>
+  <reg name="r21" bitsize="64" type="uint64"/>
+  <reg name="r22" bitsize="64" type="uint64"/>
+  <reg name="r23" bitsize="64" type="uint64"/>
+  <reg name="r24" bitsize="64" type="uint64"/>
+  <reg name="r25" bitsize="64" type="uint64"/>
+  <reg name="r26" bitsize="64" type="uint64"/>
+  <reg name="r27" bitsize="64" type="uint64"/>
+  <reg name="r28" bitsize="64" type="uint64"/>
+  <reg name="r29" bitsize="64" type="uint64"/>
+  <reg name="r30" bitsize="64" type="uint64"/>
+  <reg name="r31" bitsize="64" type="uint64"/>
+
+  <reg name="pc" bitsize="64" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="64" type="uint64"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="64" type="code_ptr"/>
+  <reg name="ctr" bitsize="64" type="uint64"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/qemu-0.15.x/gdbstub.c b/qemu-0.15.x/gdbstub.c
new file mode 100644
index 0000000..27b0cfa
--- /dev/null
+++ b/qemu-0.15.x/gdbstub.c
@@ -0,0 +1,2800 @@
+/*
+ * gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#ifdef CONFIG_USER_ONLY
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "qemu.h"
+#else
+#include "monitor.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#endif
+
+#define MAX_PACKET_LENGTH 4096
+
+#include "cpu.h"
+#include "qemu_socket.h"
+#include "kvm.h"
+
+
+enum {
+    GDB_SIGNAL_0 = 0,
+    GDB_SIGNAL_INT = 2,
+    GDB_SIGNAL_QUIT = 3,
+    GDB_SIGNAL_TRAP = 5,
+    GDB_SIGNAL_ABRT = 6,
+    GDB_SIGNAL_ALRM = 14,
+    GDB_SIGNAL_IO = 23,
+    GDB_SIGNAL_XCPU = 24,
+    GDB_SIGNAL_UNKNOWN = 143
+};
+
+#ifdef CONFIG_USER_ONLY
+
+/* Map target signal numbers to GDB protocol signal numbers and vice
+ * versa.  For user emulation's currently supported systems, we can
+ * assume most signals are defined.
+ */
+
+static int gdb_signal_table[] = {
+    0,
+    TARGET_SIGHUP,
+    TARGET_SIGINT,
+    TARGET_SIGQUIT,
+    TARGET_SIGILL,
+    TARGET_SIGTRAP,
+    TARGET_SIGABRT,
+    -1, /* SIGEMT */
+    TARGET_SIGFPE,
+    TARGET_SIGKILL,
+    TARGET_SIGBUS,
+    TARGET_SIGSEGV,
+    TARGET_SIGSYS,
+    TARGET_SIGPIPE,
+    TARGET_SIGALRM,
+    TARGET_SIGTERM,
+    TARGET_SIGURG,
+    TARGET_SIGSTOP,
+    TARGET_SIGTSTP,
+    TARGET_SIGCONT,
+    TARGET_SIGCHLD,
+    TARGET_SIGTTIN,
+    TARGET_SIGTTOU,
+    TARGET_SIGIO,
+    TARGET_SIGXCPU,
+    TARGET_SIGXFSZ,
+    TARGET_SIGVTALRM,
+    TARGET_SIGPROF,
+    TARGET_SIGWINCH,
+    -1, /* SIGLOST */
+    TARGET_SIGUSR1,
+    TARGET_SIGUSR2,
+#ifdef TARGET_SIGPWR
+    TARGET_SIGPWR,
+#else
+    -1,
+#endif
+    -1, /* SIGPOLL */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+#ifdef __SIGRTMIN
+    __SIGRTMIN + 1,
+    __SIGRTMIN + 2,
+    __SIGRTMIN + 3,
+    __SIGRTMIN + 4,
+    __SIGRTMIN + 5,
+    __SIGRTMIN + 6,
+    __SIGRTMIN + 7,
+    __SIGRTMIN + 8,
+    __SIGRTMIN + 9,
+    __SIGRTMIN + 10,
+    __SIGRTMIN + 11,
+    __SIGRTMIN + 12,
+    __SIGRTMIN + 13,
+    __SIGRTMIN + 14,
+    __SIGRTMIN + 15,
+    __SIGRTMIN + 16,
+    __SIGRTMIN + 17,
+    __SIGRTMIN + 18,
+    __SIGRTMIN + 19,
+    __SIGRTMIN + 20,
+    __SIGRTMIN + 21,
+    __SIGRTMIN + 22,
+    __SIGRTMIN + 23,
+    __SIGRTMIN + 24,
+    __SIGRTMIN + 25,
+    __SIGRTMIN + 26,
+    __SIGRTMIN + 27,
+    __SIGRTMIN + 28,
+    __SIGRTMIN + 29,
+    __SIGRTMIN + 30,
+    __SIGRTMIN + 31,
+    -1, /* SIGCANCEL */
+    __SIGRTMIN,
+    __SIGRTMIN + 32,
+    __SIGRTMIN + 33,
+    __SIGRTMIN + 34,
+    __SIGRTMIN + 35,
+    __SIGRTMIN + 36,
+    __SIGRTMIN + 37,
+    __SIGRTMIN + 38,
+    __SIGRTMIN + 39,
+    __SIGRTMIN + 40,
+    __SIGRTMIN + 41,
+    __SIGRTMIN + 42,
+    __SIGRTMIN + 43,
+    __SIGRTMIN + 44,
+    __SIGRTMIN + 45,
+    __SIGRTMIN + 46,
+    __SIGRTMIN + 47,
+    __SIGRTMIN + 48,
+    __SIGRTMIN + 49,
+    __SIGRTMIN + 50,
+    __SIGRTMIN + 51,
+    __SIGRTMIN + 52,
+    __SIGRTMIN + 53,
+    __SIGRTMIN + 54,
+    __SIGRTMIN + 55,
+    __SIGRTMIN + 56,
+    __SIGRTMIN + 57,
+    __SIGRTMIN + 58,
+    __SIGRTMIN + 59,
+    __SIGRTMIN + 60,
+    __SIGRTMIN + 61,
+    __SIGRTMIN + 62,
+    __SIGRTMIN + 63,
+    __SIGRTMIN + 64,
+    __SIGRTMIN + 65,
+    __SIGRTMIN + 66,
+    __SIGRTMIN + 67,
+    __SIGRTMIN + 68,
+    __SIGRTMIN + 69,
+    __SIGRTMIN + 70,
+    __SIGRTMIN + 71,
+    __SIGRTMIN + 72,
+    __SIGRTMIN + 73,
+    __SIGRTMIN + 74,
+    __SIGRTMIN + 75,
+    __SIGRTMIN + 76,
+    __SIGRTMIN + 77,
+    __SIGRTMIN + 78,
+    __SIGRTMIN + 79,
+    __SIGRTMIN + 80,
+    __SIGRTMIN + 81,
+    __SIGRTMIN + 82,
+    __SIGRTMIN + 83,
+    __SIGRTMIN + 84,
+    __SIGRTMIN + 85,
+    __SIGRTMIN + 86,
+    __SIGRTMIN + 87,
+    __SIGRTMIN + 88,
+    __SIGRTMIN + 89,
+    __SIGRTMIN + 90,
+    __SIGRTMIN + 91,
+    __SIGRTMIN + 92,
+    __SIGRTMIN + 93,
+    __SIGRTMIN + 94,
+    __SIGRTMIN + 95,
+    -1, /* SIGINFO */
+    -1, /* UNKNOWN */
+    -1, /* DEFAULT */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1
+#endif
+};
+#else
+/* In system mode we only need SIGINT and SIGTRAP; other signals
+   are not yet supported.  */
+
+enum {
+    TARGET_SIGINT = 2,
+    TARGET_SIGTRAP = 5
+};
+
+static int gdb_signal_table[] = {
+    -1,
+    -1,
+    TARGET_SIGINT,
+    -1,
+    -1,
+    TARGET_SIGTRAP
+};
+#endif
+
+#ifdef CONFIG_USER_ONLY
+static int target_signal_to_gdb (int sig)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++)
+        if (gdb_signal_table[i] == sig)
+            return i;
+    return GDB_SIGNAL_UNKNOWN;
+}
+#endif
+
+static int gdb_signal_to_target (int sig)
+{
+    if (sig < ARRAY_SIZE (gdb_signal_table))
+        return gdb_signal_table[sig];
+    else
+        return -1;
+}
+
+//#define DEBUG_GDB
+
+typedef struct GDBRegisterState {
+    int base_reg;
+    int num_regs;
+    gdb_reg_cb get_reg;
+    gdb_reg_cb set_reg;
+    const char *xml;
+    struct GDBRegisterState *next;
+} GDBRegisterState;
+
+enum RSState {
+    RS_INACTIVE,
+    RS_IDLE,
+    RS_GETLINE,
+    RS_CHKSUM1,
+    RS_CHKSUM2,
+    RS_SYSCALL,
+};
+typedef struct GDBState {
+    CPUState *c_cpu; /* current CPU for step/continue ops */
+    CPUState *g_cpu; /* current CPU for other ops */
+    CPUState *query_cpu; /* for q{f|s}ThreadInfo */
+    enum RSState state; /* parsing state */
+    char line_buf[MAX_PACKET_LENGTH];
+    int line_buf_index;
+    int line_csum;
+    uint8_t last_packet[MAX_PACKET_LENGTH + 4];
+    int last_packet_len;
+    int signal;
+#ifdef CONFIG_USER_ONLY
+    int fd;
+    int running_state;
+#else
+    CharDriverState *chr;
+    CharDriverState *mon_chr;
+#endif
+} GDBState;
+
+/* By default use no IRQs and no timers while single stepping so as to
+ * make single stepping like an ICE HW step.
+ */
+static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
+
+static GDBState *gdbserver_state;
+
+/* This is an ugly hack to cope with both new and old gdb.
+   If gdb sends qXfer:features:read then assume we're talking to a newish
+   gdb that understands target descriptions.  */
+static int gdb_has_xml;
+
+#ifdef CONFIG_USER_ONLY
+/* XXX: This is not thread safe.  Do we care?  */
+static int gdbserver_fd = -1;
+
+static int get_char(GDBState *s)
+{
+    uint8_t ch;
+    int ret;
+
+    for(;;) {
+        ret = qemu_recv(s->fd, &ch, 1, 0);
+        if (ret < 0) {
+            if (errno == ECONNRESET)
+                s->fd = -1;
+            if (errno != EINTR && errno != EAGAIN)
+                return -1;
+        } else if (ret == 0) {
+            close(s->fd);
+            s->fd = -1;
+            return -1;
+        } else {
+            break;
+        }
+    }
+    return ch;
+}
+#endif
+
+static gdb_syscall_complete_cb gdb_current_syscall_cb;
+
+static enum {
+    GDB_SYS_UNKNOWN,
+    GDB_SYS_ENABLED,
+    GDB_SYS_DISABLED,
+} gdb_syscall_mode;
+
+/* If gdb is connected when the first semihosting syscall occurs then use
+   remote gdb syscalls.  Otherwise use native file IO.  */
+int use_gdb_syscalls(void)
+{
+    if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
+        gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
+                                            : GDB_SYS_DISABLED);
+    }
+    return gdb_syscall_mode == GDB_SYS_ENABLED;
+}
+
+/* Resume execution.  */
+static inline void gdb_continue(GDBState *s)
+{
+#ifdef CONFIG_USER_ONLY
+    s->running_state = 1;
+#else
+    vm_start();
+#endif
+}
+
+static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+{
+#ifdef CONFIG_USER_ONLY
+    int ret;
+
+    while (len > 0) {
+        ret = send(s->fd, buf, len, 0);
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN)
+                return;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+#else
+    qemu_chr_write(s->chr, buf, len);
+#endif
+}
+
+static inline int fromhex(int v)
+{
+    if (v >= '0' && v <= '9')
+        return v - '0';
+    else if (v >= 'A' && v <= 'F')
+        return v - 'A' + 10;
+    else if (v >= 'a' && v <= 'f')
+        return v - 'a' + 10;
+    else
+        return 0;
+}
+
+static inline int tohex(int v)
+{
+    if (v < 10)
+        return v + '0';
+    else
+        return v - 10 + 'a';
+}
+
+static void memtohex(char *buf, const uint8_t *mem, int len)
+{
+    int i, c;
+    char *q;
+    q = buf;
+    for(i = 0; i < len; i++) {
+        c = mem[i];
+        *q++ = tohex(c >> 4);
+        *q++ = tohex(c & 0xf);
+    }
+    *q = '\0';
+}
+
+static void hextomem(uint8_t *mem, const char *buf, int len)
+{
+    int i;
+
+    for(i = 0; i < len; i++) {
+        mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
+        buf += 2;
+    }
+}
+
+/* return -1 if error, 0 if OK */
+static int put_packet_binary(GDBState *s, const char *buf, int len)
+{
+    int csum, i;
+    uint8_t *p;
+
+    for(;;) {
+        p = s->last_packet;
+        *(p++) = '$';
+        memcpy(p, buf, len);
+        p += len;
+        csum = 0;
+        for(i = 0; i < len; i++) {
+            csum += buf[i];
+        }
+        *(p++) = '#';
+        *(p++) = tohex((csum >> 4) & 0xf);
+        *(p++) = tohex((csum) & 0xf);
+
+        s->last_packet_len = p - s->last_packet;
+        put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+
+#ifdef CONFIG_USER_ONLY
+        i = get_char(s);
+        if (i < 0)
+            return -1;
+        if (i == '+')
+            break;
+#else
+        break;
+#endif
+    }
+    return 0;
+}
+
+/* return -1 if error, 0 if OK */
+static int put_packet(GDBState *s, const char *buf)
+{
+#ifdef DEBUG_GDB
+    printf("reply='%s'\n", buf);
+#endif
+
+    return put_packet_binary(s, buf, strlen(buf));
+}
+
+/* The GDB remote protocol transfers values in target byte order.  This means
+   we can use the raw memory access routines to access the value buffer.
+   Conveniently, these also handle the case where the buffer is mis-aligned.
+ */
+#define GET_REG8(val) do { \
+    stb_p(mem_buf, val); \
+    return 1; \
+    } while(0)
+#define GET_REG16(val) do { \
+    stw_p(mem_buf, val); \
+    return 2; \
+    } while(0)
+#define GET_REG32(val) do { \
+    stl_p(mem_buf, val); \
+    return 4; \
+    } while(0)
+#define GET_REG64(val) do { \
+    stq_p(mem_buf, val); \
+    return 8; \
+    } while(0)
+
+#if TARGET_LONG_BITS == 64
+#define GET_REGL(val) GET_REG64(val)
+#define ldtul_p(addr) ldq_p(addr)
+#else
+#define GET_REGL(val) GET_REG32(val)
+#define ldtul_p(addr) ldl_p(addr)
+#endif
+
+#if defined(TARGET_I386)
+
+#ifdef TARGET_X86_64
+static const int gpr_map[16] = {
+    R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
+    8, 9, 10, 11, 12, 13, 14, 15
+};
+#else
+#define gpr_map gpr_map32
+#endif
+static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+#define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25)
+
+#define IDX_IP_REG      CPU_NB_REGS
+#define IDX_FLAGS_REG   (IDX_IP_REG + 1)
+#define IDX_SEG_REGS    (IDX_FLAGS_REG + 1)
+#define IDX_FP_REGS     (IDX_SEG_REGS + 6)
+#define IDX_XMM_REGS    (IDX_FP_REGS + 16)
+#define IDX_MXCSR_REG   (IDX_XMM_REGS + CPU_NB_REGS)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < CPU_NB_REGS) {
+        if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+            GET_REG64(env->regs[gpr_map[n]]);
+        } else if (n < CPU_NB_REGS32) {
+            GET_REG32(env->regs[gpr_map32[n]]);
+        }
+    } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
+#ifdef USE_X86LDOUBLE
+        /* FIXME: byteswap float values - after fixing fpregs layout. */
+        memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
+#else
+        memset(mem_buf, 0, 10);
+#endif
+        return 10;
+    } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+        n -= IDX_XMM_REGS;
+        if (n < CPU_NB_REGS32 ||
+            (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
+            stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
+            stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
+            return 16;
+        }
+    } else {
+        switch (n) {
+        case IDX_IP_REG:
+            if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+                GET_REG64(env->eip);
+            } else {
+                GET_REG32(env->eip);
+            }
+        case IDX_FLAGS_REG: GET_REG32(env->eflags);
+
+        case IDX_SEG_REGS:     GET_REG32(env->segs[R_CS].selector);
+        case IDX_SEG_REGS + 1: GET_REG32(env->segs[R_SS].selector);
+        case IDX_SEG_REGS + 2: GET_REG32(env->segs[R_DS].selector);
+        case IDX_SEG_REGS + 3: GET_REG32(env->segs[R_ES].selector);
+        case IDX_SEG_REGS + 4: GET_REG32(env->segs[R_FS].selector);
+        case IDX_SEG_REGS + 5: GET_REG32(env->segs[R_GS].selector);
+
+        case IDX_FP_REGS + 8:  GET_REG32(env->fpuc);
+        case IDX_FP_REGS + 9:  GET_REG32((env->fpus & ~0x3800) |
+                                         (env->fpstt & 0x7) << 11);
+        case IDX_FP_REGS + 10: GET_REG32(0); /* ftag */
+        case IDX_FP_REGS + 11: GET_REG32(0); /* fiseg */
+        case IDX_FP_REGS + 12: GET_REG32(0); /* fioff */
+        case IDX_FP_REGS + 13: GET_REG32(0); /* foseg */
+        case IDX_FP_REGS + 14: GET_REG32(0); /* fooff */
+        case IDX_FP_REGS + 15: GET_REG32(0); /* fop */
+
+        case IDX_MXCSR_REG: GET_REG32(env->mxcsr);
+        }
+    }
+    return 0;
+}
+
+static int cpu_x86_gdb_load_seg(CPUState *env, int sreg, uint8_t *mem_buf)
+{
+    uint16_t selector = ldl_p(mem_buf);
+
+    if (selector != env->segs[sreg].selector) {
+#if defined(CONFIG_USER_ONLY)
+        cpu_x86_load_seg(env, sreg, selector);
+#else
+        unsigned int limit, flags;
+        target_ulong base;
+
+        if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+            base = selector << 4;
+            limit = 0xffff;
+            flags = 0;
+        } else {
+            if (!cpu_x86_get_descr_debug(env, selector, &base, &limit, &flags))
+                return 4;
+        }
+        cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags);
+#endif
+    }
+    return 4;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n < CPU_NB_REGS) {
+        if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+            env->regs[gpr_map[n]] = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        } else if (n < CPU_NB_REGS32) {
+            n = gpr_map32[n];
+            env->regs[n] &= ~0xffffffffUL;
+            env->regs[n] |= (uint32_t)ldl_p(mem_buf);
+            return 4;
+        }
+    } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
+#ifdef USE_X86LDOUBLE
+        /* FIXME: byteswap float values - after fixing fpregs layout. */
+        memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
+#endif
+        return 10;
+    } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+        n -= IDX_XMM_REGS;
+        if (n < CPU_NB_REGS32 ||
+            (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
+            env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
+            env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8);
+            return 16;
+        }
+    } else {
+        switch (n) {
+        case IDX_IP_REG:
+            if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+                env->eip = ldq_p(mem_buf);
+                return 8;
+            } else {
+                env->eip &= ~0xffffffffUL;
+                env->eip |= (uint32_t)ldl_p(mem_buf);
+                return 4;
+            }
+        case IDX_FLAGS_REG:
+            env->eflags = ldl_p(mem_buf);
+            return 4;
+
+        case IDX_SEG_REGS:     return cpu_x86_gdb_load_seg(env, R_CS, mem_buf);
+        case IDX_SEG_REGS + 1: return cpu_x86_gdb_load_seg(env, R_SS, mem_buf);
+        case IDX_SEG_REGS + 2: return cpu_x86_gdb_load_seg(env, R_DS, mem_buf);
+        case IDX_SEG_REGS + 3: return cpu_x86_gdb_load_seg(env, R_ES, mem_buf);
+        case IDX_SEG_REGS + 4: return cpu_x86_gdb_load_seg(env, R_FS, mem_buf);
+        case IDX_SEG_REGS + 5: return cpu_x86_gdb_load_seg(env, R_GS, mem_buf);
+
+        case IDX_FP_REGS + 8:
+            env->fpuc = ldl_p(mem_buf);
+            return 4;
+        case IDX_FP_REGS + 9:
+            tmp = ldl_p(mem_buf);
+            env->fpstt = (tmp >> 11) & 7;
+            env->fpus = tmp & ~0x3800;
+            return 4;
+        case IDX_FP_REGS + 10: /* ftag */  return 4;
+        case IDX_FP_REGS + 11: /* fiseg */ return 4;
+        case IDX_FP_REGS + 12: /* fioff */ return 4;
+        case IDX_FP_REGS + 13: /* foseg */ return 4;
+        case IDX_FP_REGS + 14: /* fooff */ return 4;
+        case IDX_FP_REGS + 15: /* fop */   return 4;
+
+        case IDX_MXCSR_REG:
+            env->mxcsr = ldl_p(mem_buf);
+            return 4;
+        }
+    }
+    /* Unrecognised register.  */
+    return 0;
+}
+
+#elif defined (TARGET_PPC)
+
+/* Old gdb always expects FP registers.  Newer (xml-aware) gdb only
+   expects whatever the target description contains.  Due to a
+   historical mishap the FP registers appear in between core integer
+   regs and PC, MSR, CR, and so forth.  We hack round this by giving the
+   FP regs zero size when talking to a newer gdb.  */
+#define NUM_CORE_REGS 71
+#if defined (TARGET_PPC64)
+#define GDB_CORE_XML "power64-core.xml"
+#else
+#define GDB_CORE_XML "power-core.xml"
+#endif
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        /* gprs */
+        GET_REGL(env->gpr[n]);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml)
+            return 0;
+        stfq_p(mem_buf, env->fpr[n-32]);
+        return 8;
+    } else {
+        switch (n) {
+        case 64: GET_REGL(env->nip);
+        case 65: GET_REGL(env->msr);
+        case 66:
+            {
+                uint32_t cr = 0;
+                int i;
+                for (i = 0; i < 8; i++)
+                    cr |= env->crf[i] << (32 - ((i + 1) * 4));
+                GET_REG32(cr);
+            }
+        case 67: GET_REGL(env->lr);
+        case 68: GET_REGL(env->ctr);
+        case 69: GET_REGL(env->xer);
+        case 70:
+            {
+                if (gdb_has_xml)
+                    return 0;
+                GET_REG32(0); /* fpscr */
+            }
+        }
+    }
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        /* gprs */
+        env->gpr[n] = ldtul_p(mem_buf);
+        return sizeof(target_ulong);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml)
+            return 0;
+        env->fpr[n-32] = ldfq_p(mem_buf);
+        return 8;
+    } else {
+        switch (n) {
+        case 64:
+            env->nip = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 65:
+            ppc_store_msr(env, ldtul_p(mem_buf));
+            return sizeof(target_ulong);
+        case 66:
+            {
+                uint32_t cr = ldl_p(mem_buf);
+                int i;
+                for (i = 0; i < 8; i++)
+                    env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
+                return 4;
+            }
+        case 67:
+            env->lr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 68:
+            env->ctr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 69:
+            env->xer = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 70:
+            /* fpscr */
+            if (gdb_has_xml)
+                return 0;
+            return 4;
+        }
+    }
+    return 0;
+}
+
+#elif defined (TARGET_SPARC)
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+#define NUM_CORE_REGS 86
+#else
+#define NUM_CORE_REGS 72
+#endif
+
+#ifdef TARGET_ABI32
+#define GET_REGA(val) GET_REG32(val)
+#else
+#define GET_REGA(val) GET_REGL(val)
+#endif
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        /* g0..g7 */
+        GET_REGA(env->gregs[n]);
+    }
+    if (n < 32) {
+        /* register window */
+        GET_REGA(env->regwptr[n - 8]);
+    }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    if (n < 64) {
+        /* fprs */
+        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+    }
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    switch (n) {
+    case 64: GET_REGA(env->y);
+    case 65: GET_REGA(cpu_get_psr(env));
+    case 66: GET_REGA(env->wim);
+    case 67: GET_REGA(env->tbr);
+    case 68: GET_REGA(env->pc);
+    case 69: GET_REGA(env->npc);
+    case 70: GET_REGA(env->fsr);
+    case 71: GET_REGA(0); /* csr */
+    default: GET_REGA(0);
+    }
+#else
+    if (n < 64) {
+        /* f0-f31 */
+        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+    }
+    if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        uint64_t val;
+
+        val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32;
+        val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]);
+        GET_REG64(val);
+    }
+    switch (n) {
+    case 80: GET_REGL(env->pc);
+    case 81: GET_REGL(env->npc);
+    case 82: GET_REGL((cpu_get_ccr(env) << 32) |
+                      ((env->asi & 0xff) << 24) |
+                      ((env->pstate & 0xfff) << 8) |
+                      cpu_get_cwp64(env));
+    case 83: GET_REGL(env->fsr);
+    case 84: GET_REGL(env->fprs);
+    case 85: GET_REGL(env->y);
+    }
+#endif
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+#if defined(TARGET_ABI32)
+    abi_ulong tmp;
+
+    tmp = ldl_p(mem_buf);
+#else
+    target_ulong tmp;
+
+    tmp = ldtul_p(mem_buf);
+#endif
+
+    if (n < 8) {
+        /* g0..g7 */
+        env->gregs[n] = tmp;
+    } else if (n < 32) {
+        /* register window */
+        env->regwptr[n - 8] = tmp;
+    }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    else if (n < 64) {
+        /* fprs */
+        *((uint32_t *)&env->fpr[n - 32]) = tmp;
+    } else {
+        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+        switch (n) {
+        case 64: env->y = tmp; break;
+        case 65: cpu_put_psr(env, tmp); break;
+        case 66: env->wim = tmp; break;
+        case 67: env->tbr = tmp; break;
+        case 68: env->pc = tmp; break;
+        case 69: env->npc = tmp; break;
+        case 70: env->fsr = tmp; break;
+        default: return 0;
+        }
+    }
+    return 4;
+#else
+    else if (n < 64) {
+        /* f0-f31 */
+        env->fpr[n] = ldfl_p(mem_buf);
+        return 4;
+    } else if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32;
+        *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp;
+    } else {
+        switch (n) {
+        case 80: env->pc = tmp; break;
+        case 81: env->npc = tmp; break;
+        case 82:
+            cpu_put_ccr(env, tmp >> 32);
+	    env->asi = (tmp >> 24) & 0xff;
+	    env->pstate = (tmp >> 8) & 0xfff;
+            cpu_put_cwp64(env, tmp & 0xff);
+	    break;
+        case 83: env->fsr = tmp; break;
+        case 84: env->fprs = tmp; break;
+        case 85: env->y = tmp; break;
+        default: return 0;
+        }
+    }
+    return 8;
+#endif
+}
+#elif defined (TARGET_ARM)
+
+/* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
+   whatever the target description contains.  Due to a historical mishap
+   the FPA registers appear in between core integer regs and the CPSR.
+   We hack round this by giving the FPA regs zero size when talking to a
+   newer gdb.  */
+#define NUM_CORE_REGS 26
+#define GDB_CORE_XML "arm-core.xml"
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 16) {
+        /* Core integer register.  */
+        GET_REG32(env->regs[n]);
+    }
+    if (n < 24) {
+        /* FPA registers.  */
+        if (gdb_has_xml)
+            return 0;
+        memset(mem_buf, 0, 12);
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register.  */
+        if (gdb_has_xml)
+            return 0;
+        GET_REG32(0);
+    case 25:
+        /* CPSR */
+        GET_REG32(cpsr_read(env));
+    }
+    /* Unknown register.  */
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    tmp = ldl_p(mem_buf);
+
+    /* Mask out low bit of PC to workaround gdb bugs.  This will probably
+       cause problems if we ever implement the Jazelle DBX extensions.  */
+    if (n == 15)
+        tmp &= ~1;
+
+    if (n < 16) {
+        /* Core integer register.  */
+        env->regs[n] = tmp;
+        return 4;
+    }
+    if (n < 24) { /* 16-23 */
+        /* FPA registers (ignored).  */
+        if (gdb_has_xml)
+            return 0;
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register (ignored).  */
+        if (gdb_has_xml)
+            return 0;
+        return 4;
+    case 25:
+        /* CPSR */
+        cpsr_write (env, tmp, 0xffffffff);
+        return 4;
+    }
+    /* Unknown register.  */
+    return 0;
+}
+
+#elif defined (TARGET_M68K)
+
+#define NUM_CORE_REGS 18
+
+#define GDB_CORE_XML "cf-core.xml"
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        /* D0-D7 */
+        GET_REG32(env->dregs[n]);
+    } else if (n < 16) {
+        /* A0-A7 */
+        GET_REG32(env->aregs[n - 8]);
+    } else {
+	switch (n) {
+        case 16: GET_REG32(env->sr);
+        case 17: GET_REG32(env->pc);
+        }
+    }
+    /* FP registers not included here because they vary between
+       ColdFire and m68k.  Use XML bits for these.  */
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 8) {
+        /* D0-D7 */
+        env->dregs[n] = tmp;
+    } else if (n < 16) {
+        /* A0-A7 */
+        env->aregs[n - 8] = tmp;
+    } else {
+        switch (n) {
+        case 16: env->sr = tmp; break;
+        case 17: env->pc = tmp; break;
+        default: return 0;
+        }
+    }
+    return 4;
+}
+#elif defined (TARGET_MIPS)
+
+#define NUM_CORE_REGS 73
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        GET_REGL(env->active_tc.gpr[n]);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+        if (n >= 38 && n < 70) {
+            if (env->CP0_Status & (1 << CP0St_FR))
+		GET_REGL(env->active_fpu.fpr[n - 38].d);
+            else
+		GET_REGL(env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
+        }
+        switch (n) {
+        case 70: GET_REGL((int32_t)env->active_fpu.fcr31);
+        case 71: GET_REGL((int32_t)env->active_fpu.fcr0);
+        }
+    }
+    switch (n) {
+    case 32: GET_REGL((int32_t)env->CP0_Status);
+    case 33: GET_REGL(env->active_tc.LO[0]);
+    case 34: GET_REGL(env->active_tc.HI[0]);
+    case 35: GET_REGL(env->CP0_BadVAddr);
+    case 36: GET_REGL((int32_t)env->CP0_Cause);
+    case 37: GET_REGL(env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16));
+    case 72: GET_REGL(0); /* fp */
+    case 89: GET_REGL((int32_t)env->CP0_PRid);
+    }
+    if (n >= 73 && n <= 88) {
+	/* 16 embedded regs.  */
+	GET_REGL(0);
+    }
+
+    return 0;
+}
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+static unsigned int ieee_rm[] =
+  {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+  };
+#define RESTORE_ROUNDING_MODE \
+    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    target_ulong tmp;
+
+    tmp = ldtul_p(mem_buf);
+
+    if (n < 32) {
+        env->active_tc.gpr[n] = tmp;
+        return sizeof(target_ulong);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)
+            && n >= 38 && n < 73) {
+        if (n < 70) {
+            if (env->CP0_Status & (1 << CP0St_FR))
+              env->active_fpu.fpr[n - 38].d = tmp;
+            else
+              env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
+        }
+        switch (n) {
+        case 70:
+            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
+            /* set rounding mode */
+            RESTORE_ROUNDING_MODE;
+            break;
+        case 71: env->active_fpu.fcr0 = tmp; break;
+        }
+        return sizeof(target_ulong);
+    }
+    switch (n) {
+    case 32: env->CP0_Status = tmp; break;
+    case 33: env->active_tc.LO[0] = tmp; break;
+    case 34: env->active_tc.HI[0] = tmp; break;
+    case 35: env->CP0_BadVAddr = tmp; break;
+    case 36: env->CP0_Cause = tmp; break;
+    case 37:
+        env->active_tc.PC = tmp & ~(target_ulong)1;
+        if (tmp & 1) {
+            env->hflags |= MIPS_HFLAG_M16;
+        } else {
+            env->hflags &= ~(MIPS_HFLAG_M16);
+        }
+        break;
+    case 72: /* fp, ignored */ break;
+    default: 
+	if (n > 89)
+	    return 0;
+	/* Other registers are readonly.  Ignore writes.  */
+	break;
+    }
+
+    return sizeof(target_ulong);
+}
+#elif defined (TARGET_SH4)
+
+/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
+/* FIXME: We should use XML for this.  */
+
+#define NUM_CORE_REGS 59
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            GET_REGL(env->gregs[n + 16]);
+        } else {
+            GET_REGL(env->gregs[n]);
+        }
+    } else if (n < 16) {
+        GET_REGL(env->gregs[n]);
+    } else if (n >= 25 && n < 41) {
+	GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
+    } else if (n >= 43 && n < 51) {
+	GET_REGL(env->gregs[n - 43]);
+    } else if (n >= 51 && n < 59) {
+	GET_REGL(env->gregs[n - (51 - 16)]);
+    }
+    switch (n) {
+    case 16: GET_REGL(env->pc);
+    case 17: GET_REGL(env->pr);
+    case 18: GET_REGL(env->gbr);
+    case 19: GET_REGL(env->vbr);
+    case 20: GET_REGL(env->mach);
+    case 21: GET_REGL(env->macl);
+    case 22: GET_REGL(env->sr);
+    case 23: GET_REGL(env->fpul);
+    case 24: GET_REGL(env->fpscr);
+    case 41: GET_REGL(env->ssr);
+    case 42: GET_REGL(env->spc);
+    }
+
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 8) {
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            env->gregs[n + 16] = tmp;
+        } else {
+            env->gregs[n] = tmp;
+        }
+	return 4;
+    } else if (n < 16) {
+        env->gregs[n] = tmp;
+	return 4;
+    } else if (n >= 25 && n < 41) {
+	env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp;
+	return 4;
+    } else if (n >= 43 && n < 51) {
+	env->gregs[n - 43] = tmp;
+	return 4;
+    } else if (n >= 51 && n < 59) {
+	env->gregs[n - (51 - 16)] = tmp;
+	return 4;
+    }
+    switch (n) {
+    case 16: env->pc = tmp; break;
+    case 17: env->pr = tmp; break;
+    case 18: env->gbr = tmp; break;
+    case 19: env->vbr = tmp; break;
+    case 20: env->mach = tmp; break;
+    case 21: env->macl = tmp; break;
+    case 22: env->sr = tmp; break;
+    case 23: env->fpul = tmp; break;
+    case 24: env->fpscr = tmp; break;
+    case 41: env->ssr = tmp; break;
+    case 42: env->spc = tmp; break;
+    default: return 0;
+    }
+
+    return 4;
+}
+#elif defined (TARGET_MICROBLAZE)
+
+#define NUM_CORE_REGS (32 + 5)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+	GET_REG32(env->regs[n]);
+    } else {
+	GET_REG32(env->sregs[n - 32]);
+    }
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS)
+	return 0;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+	env->regs[n] = tmp;
+    } else {
+	env->sregs[n - 32] = tmp;
+    }
+    return 4;
+}
+#elif defined (TARGET_CRIS)
+
+#define NUM_CORE_REGS 49
+
+static int
+read_register_crisv10(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 15) {
+        GET_REG32(env->regs[n]);
+    }
+
+    if (n == 15) {
+        GET_REG32(env->pc);
+    }
+
+    if (n < 32) {
+        switch (n) {
+        case 16:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 17:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 20:
+        case 21:
+            GET_REG16(env->pregs[n - 16]);
+            break;
+        default:
+            if (n >= 23) {
+                GET_REG32(env->pregs[n - 16]);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint8_t srs;
+
+    if (env->pregs[PR_VR] < 32)
+        return read_register_crisv10(env, mem_buf, n);
+
+    srs = env->pregs[PR_SRS];
+    if (n < 16) {
+	GET_REG32(env->regs[n]);
+    }
+
+    if (n >= 21 && n < 32) {
+	GET_REG32(env->pregs[n - 16]);
+    }
+    if (n >= 33 && n < 49) {
+	GET_REG32(env->sregs[srs][n - 33]);
+    }
+    switch (n) {
+    case 16: GET_REG8(env->pregs[0]);
+    case 17: GET_REG8(env->pregs[1]);
+    case 18: GET_REG32(env->pregs[2]);
+    case 19: GET_REG8(srs);
+    case 20: GET_REG16(env->pregs[4]);
+    case 32: GET_REG32(env->pc);
+    }
+
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > 49)
+	return 0;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 16) {
+	env->regs[n] = tmp;
+    }
+
+    if (n >= 21 && n < 32) {
+	env->pregs[n - 16] = tmp;
+    }
+
+    /* FIXME: Should support function regs be writable?  */
+    switch (n) {
+    case 16: return 1;
+    case 17: return 1;
+    case 18: env->pregs[PR_PID] = tmp; break;
+    case 19: return 1;
+    case 20: return 2;
+    case 32: env->pc = tmp; break;
+    }
+
+    return 4;
+}
+#elif defined (TARGET_ALPHA)
+
+#define NUM_CORE_REGS 67
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint64_t val;
+    CPU_DoubleU d;
+
+    switch (n) {
+    case 0 ... 30:
+        val = env->ir[n];
+        break;
+    case 32 ... 62:
+        d.d = env->fir[n - 32];
+        val = d.ll;
+        break;
+    case 63:
+        val = cpu_alpha_load_fpcr(env);
+        break;
+    case 64:
+        val = env->pc;
+        break;
+    case 66:
+        val = env->unique;
+        break;
+    case 31:
+    case 65:
+        /* 31 really is the zero register; 65 is unassigned in the
+           gdb protocol, but is still required to occupy 8 bytes. */
+        val = 0;
+        break;
+    default:
+        return 0;
+    }
+    GET_REGL(val);
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    target_ulong tmp = ldtul_p(mem_buf);
+    CPU_DoubleU d;
+
+    switch (n) {
+    case 0 ... 30:
+        env->ir[n] = tmp;
+        break;
+    case 32 ... 62:
+        d.ll = tmp;
+        env->fir[n - 32] = d.d;
+        break;
+    case 63:
+        cpu_alpha_store_fpcr(env, tmp);
+        break;
+    case 64:
+        env->pc = tmp;
+        break;
+    case 66:
+        env->unique = tmp;
+        break;
+    case 31:
+    case 65:
+        /* 31 really is the zero register; 65 is unassigned in the
+           gdb protocol, but is still required to occupy 8 bytes. */
+        break;
+    default:
+        return 0;
+    }
+    return 8;
+}
+#elif defined (TARGET_S390X)
+
+#define NUM_CORE_REGS S390_NUM_TOTAL_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    switch (n) {
+        case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break;
+        case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break;
+        case S390_R0_REGNUM ... S390_R15_REGNUM:
+            GET_REGL(env->regs[n-S390_R0_REGNUM]); break;
+        case S390_A0_REGNUM ... S390_A15_REGNUM:
+            GET_REG32(env->aregs[n-S390_A0_REGNUM]); break;
+        case S390_FPC_REGNUM: GET_REG32(env->fpc); break;
+        case S390_F0_REGNUM ... S390_F15_REGNUM:
+            /* XXX */
+            break;
+        case S390_PC_REGNUM: GET_REGL(env->psw.addr); break;
+        case S390_CC_REGNUM:
+            env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
+                                 env->cc_vr);
+            GET_REG32(env->cc_op);
+            break;
+    }
+
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    target_ulong tmpl;
+    uint32_t tmp32;
+    int r = 8;
+    tmpl = ldtul_p(mem_buf);
+    tmp32 = ldl_p(mem_buf);
+
+    switch (n) {
+        case S390_PSWM_REGNUM: env->psw.mask = tmpl; break;
+        case S390_PSWA_REGNUM: env->psw.addr = tmpl; break;
+        case S390_R0_REGNUM ... S390_R15_REGNUM:
+            env->regs[n-S390_R0_REGNUM] = tmpl; break;
+        case S390_A0_REGNUM ... S390_A15_REGNUM:
+            env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break;
+        case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break;
+        case S390_F0_REGNUM ... S390_F15_REGNUM:
+            /* XXX */
+            break;
+        case S390_PC_REGNUM: env->psw.addr = tmpl; break;
+        case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break;
+    }
+
+    return r;
+}
+#elif defined (TARGET_LM32)
+
+#include "hw/lm32_pic.h"
+#define NUM_CORE_REGS (32 + 7)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        GET_REG32(env->regs[n]);
+    } else {
+        switch (n) {
+        case 32:
+            GET_REG32(env->pc);
+            break;
+        /* FIXME: put in right exception ID */
+        case 33:
+            GET_REG32(0);
+            break;
+        case 34:
+            GET_REG32(env->eba);
+            break;
+        case 35:
+            GET_REG32(env->deba);
+            break;
+        case 36:
+            GET_REG32(env->ie);
+            break;
+        case 37:
+            GET_REG32(lm32_pic_get_im(env->pic_state));
+            break;
+        case 38:
+            GET_REG32(lm32_pic_get_ip(env->pic_state));
+            break;
+        }
+    }
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+        env->regs[n] = tmp;
+    } else {
+        switch (n) {
+        case 32:
+            env->pc = tmp;
+            break;
+        case 34:
+            env->eba = tmp;
+            break;
+        case 35:
+            env->deba = tmp;
+            break;
+        case 36:
+            env->ie = tmp;
+            break;
+        case 37:
+            lm32_pic_set_im(env->pic_state, tmp);
+            break;
+        case 38:
+            lm32_pic_set_ip(env->pic_state, tmp);
+            break;
+        }
+    }
+    return 4;
+}
+#else
+
+#define NUM_CORE_REGS 0
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    return 0;
+}
+
+#endif
+
+static int num_g_regs = NUM_CORE_REGS;
+
+#ifdef GDB_CORE_XML
+/* Encode data using the encoding for 'x' packets.  */
+static int memtox(char *buf, const char *mem, int len)
+{
+    char *p = buf;
+    char c;
+
+    while (len--) {
+        c = *(mem++);
+        switch (c) {
+        case '#': case '$': case '*': case '}':
+            *(p++) = '}';
+            *(p++) = c ^ 0x20;
+            break;
+        default:
+            *(p++) = c;
+            break;
+        }
+    }
+    return p - buf;
+}
+
+static const char *get_feature_xml(const char *p, const char **newp)
+{
+    size_t len;
+    int i;
+    const char *name;
+    static char target_xml[1024];
+
+    len = 0;
+    while (p[len] && p[len] != ':')
+        len++;
+    *newp = p + len;
+
+    name = NULL;
+    if (strncmp(p, "target.xml", len) == 0) {
+        /* Generate the XML description for this CPU.  */
+        if (!target_xml[0]) {
+            GDBRegisterState *r;
+
+            snprintf(target_xml, sizeof(target_xml),
+                     "<?xml version=\"1.0\"?>"
+                     "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+                     "<target>"
+                     "<xi:include href=\"%s\"/>",
+                     GDB_CORE_XML);
+
+            for (r = first_cpu->gdb_regs; r; r = r->next) {
+                pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
+                pstrcat(target_xml, sizeof(target_xml), r->xml);
+                pstrcat(target_xml, sizeof(target_xml), "\"/>");
+            }
+            pstrcat(target_xml, sizeof(target_xml), "</target>");
+        }
+        return target_xml;
+    }
+    for (i = 0; ; i++) {
+        name = xml_builtin[i][0];
+        if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
+            break;
+    }
+    return name ? xml_builtin[i][1] : NULL;
+}
+#endif
+
+static int gdb_read_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+    GDBRegisterState *r;
+
+    if (reg < NUM_CORE_REGS)
+        return cpu_gdb_read_register(env, mem_buf, reg);
+
+    for (r = env->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->get_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+    GDBRegisterState *r;
+
+    if (reg < NUM_CORE_REGS)
+        return cpu_gdb_write_register(env, mem_buf, reg);
+
+    for (r = env->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->set_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+/* Register a supplemental set of CPU registers.  If g_pos is nonzero it
+   specifies the first register number and these registers are included in
+   a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
+   gdb reading a CPU register, and set_reg is gdb modifying a CPU register.
+ */
+
+void gdb_register_coprocessor(CPUState * env,
+                             gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                             int num_regs, const char *xml, int g_pos)
+{
+    GDBRegisterState *s;
+    GDBRegisterState **p;
+    static int last_reg = NUM_CORE_REGS;
+
+    s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState));
+    s->base_reg = last_reg;
+    s->num_regs = num_regs;
+    s->get_reg = get_reg;
+    s->set_reg = set_reg;
+    s->xml = xml;
+    p = &env->gdb_regs;
+    while (*p) {
+        /* Check for duplicates.  */
+        if (strcmp((*p)->xml, xml) == 0)
+            return;
+        p = &(*p)->next;
+    }
+    /* Add to end of list.  */
+    last_reg += num_regs;
+    *p = s;
+    if (g_pos) {
+        if (g_pos != s->base_reg) {
+            fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
+                    "Expected %d got %d\n", xml, g_pos, s->base_reg);
+        } else {
+            num_g_regs = last_reg;
+        }
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+static const int xlat_gdb_type[] = {
+    [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
+    [GDB_WATCHPOINT_READ]   = BP_GDB | BP_MEM_READ,
+    [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
+};
+#endif
+
+static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *env;
+    int err = 0;
+
+    if (kvm_enabled())
+        return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
+    switch (type) {
+    case GDB_BREAKPOINT_SW:
+    case GDB_BREAKPOINT_HW:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+            if (err)
+                break;
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
+                                        NULL);
+            if (err)
+                break;
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *env;
+    int err = 0;
+
+    if (kvm_enabled())
+        return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
+    switch (type) {
+    case GDB_BREAKPOINT_SW:
+    case GDB_BREAKPOINT_HW:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_remove(env, addr, BP_GDB);
+            if (err)
+                break;
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+            if (err)
+                break;
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static void gdb_breakpoint_remove_all(void)
+{
+    CPUState *env;
+
+    if (kvm_enabled()) {
+        kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+        return;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_breakpoint_remove_all(env, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+        cpu_watchpoint_remove_all(env, BP_GDB);
+#endif
+    }
+}
+
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+#if defined(TARGET_I386)
+    cpu_synchronize_state(s->c_cpu);
+    s->c_cpu->eip = pc;
+#elif defined (TARGET_PPC)
+    s->c_cpu->nip = pc;
+#elif defined (TARGET_SPARC)
+    s->c_cpu->pc = pc;
+    s->c_cpu->npc = pc + 4;
+#elif defined (TARGET_ARM)
+    s->c_cpu->regs[15] = pc;
+#elif defined (TARGET_SH4)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_MIPS)
+    s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;
+    if (pc & 1) {
+        s->c_cpu->hflags |= MIPS_HFLAG_M16;
+    } else {
+        s->c_cpu->hflags &= ~(MIPS_HFLAG_M16);
+    }
+#elif defined (TARGET_MICROBLAZE)
+    s->c_cpu->sregs[SR_PC] = pc;
+#elif defined (TARGET_CRIS)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_ALPHA)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_S390X)
+    cpu_synchronize_state(s->c_cpu);
+    s->c_cpu->psw.addr = pc;
+#elif defined (TARGET_LM32)
+    s->c_cpu->pc = pc;
+#endif
+}
+
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+    return env->host_tid;
+#else
+    return env->cpu_index + 1;
+#endif
+}
+
+static CPUState *find_cpu(uint32_t thread_id)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (gdb_id(env) == thread_id) {
+            return env;
+        }
+    }
+
+    return NULL;
+}
+
+static int gdb_handle_packet(GDBState *s, const char *line_buf)
+{
+    CPUState *env;
+    const char *p;
+    uint32_t thread;
+    int ch, reg_size, type, res;
+    char buf[MAX_PACKET_LENGTH];
+    uint8_t mem_buf[MAX_PACKET_LENGTH];
+    uint8_t *registers;
+    target_ulong addr, len;
+
+#ifdef DEBUG_GDB
+    printf("command='%s'\n", line_buf);
+#endif
+    p = line_buf;
+    ch = *p++;
+    switch(ch) {
+    case '?':
+        /* TODO: Make this return the correct value for user-mode.  */
+        snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
+                 gdb_id(s->c_cpu));
+        put_packet(s, buf);
+        /* Remove all the breakpoints when this query is issued,
+         * because gdb is doing and initial connect and the state
+         * should be cleaned up.
+         */
+        gdb_breakpoint_remove_all();
+        break;
+    case 'c':
+        if (*p != '\0') {
+            addr = strtoull(p, (char **)&p, 16);
+            gdb_set_cpu_pc(s, addr);
+        }
+        s->signal = 0;
+        gdb_continue(s);
+	return RS_IDLE;
+    case 'C':
+        s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
+        if (s->signal == -1)
+            s->signal = 0;
+        gdb_continue(s);
+        return RS_IDLE;
+    case 'v':
+        if (strncmp(p, "Cont", 4) == 0) {
+            int res_signal, res_thread;
+
+            p += 4;
+            if (*p == '?') {
+                put_packet(s, "vCont;c;C;s;S");
+                break;
+            }
+            res = 0;
+            res_signal = 0;
+            res_thread = 0;
+            while (*p) {
+                int action, signal;
+
+                if (*p++ != ';') {
+                    res = 0;
+                    break;
+                }
+                action = *p++;
+                signal = 0;
+                if (action == 'C' || action == 'S') {
+                    signal = strtoul(p, (char **)&p, 16);
+                } else if (action != 'c' && action != 's') {
+                    res = 0;
+                    break;
+                }
+                thread = 0;
+                if (*p == ':') {
+                    thread = strtoull(p+1, (char **)&p, 16);
+                }
+                action = tolower(action);
+                if (res == 0 || (res == 'c' && action == 's')) {
+                    res = action;
+                    res_signal = signal;
+                    res_thread = thread;
+                }
+            }
+            if (res) {
+                if (res_thread != -1 && res_thread != 0) {
+                    env = find_cpu(res_thread);
+                    if (env == NULL) {
+                        put_packet(s, "E22");
+                        break;
+                    }
+                    s->c_cpu = env;
+                }
+                if (res == 's') {
+                    cpu_single_step(s->c_cpu, sstep_flags);
+                }
+                s->signal = res_signal;
+                gdb_continue(s);
+                return RS_IDLE;
+            }
+            break;
+        } else {
+            goto unknown_command;
+        }
+    case 'k':
+        /* Kill the target */
+        fprintf(stderr, "\nQEMU: Terminated via GDBstub\n");
+        exit(0);
+    case 'D':
+        /* Detach packet */
+        gdb_breakpoint_remove_all();
+        gdb_syscall_mode = GDB_SYS_DISABLED;
+        gdb_continue(s);
+        put_packet(s, "OK");
+        break;
+    case 's':
+        if (*p != '\0') {
+            addr = strtoull(p, (char **)&p, 16);
+            gdb_set_cpu_pc(s, addr);
+        }
+        cpu_single_step(s->c_cpu, sstep_flags);
+        gdb_continue(s);
+	return RS_IDLE;
+    case 'F':
+        {
+            target_ulong ret;
+            target_ulong err;
+
+            ret = strtoull(p, (char **)&p, 16);
+            if (*p == ',') {
+                p++;
+                err = strtoull(p, (char **)&p, 16);
+            } else {
+                err = 0;
+            }
+            if (*p == ',')
+                p++;
+            type = *p;
+            if (gdb_current_syscall_cb)
+                gdb_current_syscall_cb(s->c_cpu, ret, err);
+            if (type == 'C') {
+                put_packet(s, "T02");
+            } else {
+                gdb_continue(s);
+            }
+        }
+        break;
+    case 'g':
+        cpu_synchronize_state(s->g_cpu);
+        len = 0;
+        for (addr = 0; addr < num_g_regs; addr++) {
+            reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
+            len += reg_size;
+        }
+        memtohex(buf, mem_buf, len);
+        put_packet(s, buf);
+        break;
+    case 'G':
+        cpu_synchronize_state(s->g_cpu);
+        registers = mem_buf;
+        len = strlen(p) / 2;
+        hextomem((uint8_t *)registers, p, len);
+        for (addr = 0; addr < num_g_regs && len > 0; addr++) {
+            reg_size = gdb_write_register(s->g_cpu, registers, addr);
+            len -= reg_size;
+            registers += reg_size;
+        }
+        put_packet(s, "OK");
+        break;
+    case 'm':
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, NULL, 16);
+        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+            put_packet (s, "E14");
+        } else {
+            memtohex(buf, mem_buf, len);
+            put_packet(s, buf);
+        }
+        break;
+    case 'M':
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, (char **)&p, 16);
+        if (*p == ':')
+            p++;
+        hextomem(mem_buf, p, len);
+        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
+            put_packet(s, "E14");
+        else
+            put_packet(s, "OK");
+        break;
+    case 'p':
+        /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
+           This works, but can be very slow.  Anything new enough to
+           understand XML also knows how to use this properly.  */
+        if (!gdb_has_xml)
+            goto unknown_command;
+        addr = strtoull(p, (char **)&p, 16);
+        reg_size = gdb_read_register(s->g_cpu, mem_buf, addr);
+        if (reg_size) {
+            memtohex(buf, mem_buf, reg_size);
+            put_packet(s, buf);
+        } else {
+            put_packet(s, "E14");
+        }
+        break;
+    case 'P':
+        if (!gdb_has_xml)
+            goto unknown_command;
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == '=')
+            p++;
+        reg_size = strlen(p) / 2;
+        hextomem(mem_buf, p, reg_size);
+        gdb_write_register(s->g_cpu, mem_buf, addr);
+        put_packet(s, "OK");
+        break;
+    case 'Z':
+    case 'z':
+        type = strtoul(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, (char **)&p, 16);
+        if (ch == 'Z')
+            res = gdb_breakpoint_insert(addr, len, type);
+        else
+            res = gdb_breakpoint_remove(addr, len, type);
+        if (res >= 0)
+             put_packet(s, "OK");
+        else if (res == -ENOSYS)
+            put_packet(s, "");
+        else
+            put_packet(s, "E22");
+        break;
+    case 'H':
+        type = *p++;
+        thread = strtoull(p, (char **)&p, 16);
+        if (thread == -1 || thread == 0) {
+            put_packet(s, "OK");
+            break;
+        }
+        env = find_cpu(thread);
+        if (env == NULL) {
+            put_packet(s, "E22");
+            break;
+        }
+        switch (type) {
+        case 'c':
+            s->c_cpu = env;
+            put_packet(s, "OK");
+            break;
+        case 'g':
+            s->g_cpu = env;
+            put_packet(s, "OK");
+            break;
+        default:
+             put_packet(s, "E22");
+             break;
+        }
+        break;
+    case 'T':
+        thread = strtoull(p, (char **)&p, 16);
+        env = find_cpu(thread);
+
+        if (env != NULL) {
+            put_packet(s, "OK");
+        } else {
+            put_packet(s, "E22");
+        }
+        break;
+    case 'q':
+    case 'Q':
+        /* parse any 'q' packets here */
+        if (!strcmp(p,"qemu.sstepbits")) {
+            /* Query Breakpoint bit definitions */
+            snprintf(buf, sizeof(buf), "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+                     SSTEP_ENABLE,
+                     SSTEP_NOIRQ,
+                     SSTEP_NOTIMER);
+            put_packet(s, buf);
+            break;
+        } else if (strncmp(p,"qemu.sstep",10) == 0) {
+            /* Display or change the sstep_flags */
+            p += 10;
+            if (*p != '=') {
+                /* Display current setting */
+                snprintf(buf, sizeof(buf), "0x%x", sstep_flags);
+                put_packet(s, buf);
+                break;
+            }
+            p++;
+            type = strtoul(p, (char **)&p, 16);
+            sstep_flags = type;
+            put_packet(s, "OK");
+            break;
+        } else if (strcmp(p,"C") == 0) {
+            /* "Current thread" remains vague in the spec, so always return
+             *  the first CPU (gdb returns the first thread). */
+            put_packet(s, "QC1");
+            break;
+        } else if (strcmp(p,"fThreadInfo") == 0) {
+            s->query_cpu = first_cpu;
+            goto report_cpuinfo;
+        } else if (strcmp(p,"sThreadInfo") == 0) {
+        report_cpuinfo:
+            if (s->query_cpu) {
+                snprintf(buf, sizeof(buf), "m%x", gdb_id(s->query_cpu));
+                put_packet(s, buf);
+                s->query_cpu = s->query_cpu->next_cpu;
+            } else
+                put_packet(s, "l");
+            break;
+        } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
+            thread = strtoull(p+16, (char **)&p, 16);
+            env = find_cpu(thread);
+            if (env != NULL) {
+                cpu_synchronize_state(env);
+                len = snprintf((char *)mem_buf, sizeof(mem_buf),
+                               "CPU#%d [%s]", env->cpu_index,
+                               env->halted ? "halted " : "running");
+                memtohex(buf, mem_buf, len);
+                put_packet(s, buf);
+            }
+            break;
+        }
+#ifdef CONFIG_USER_ONLY
+        else if (strncmp(p, "Offsets", 7) == 0) {
+            TaskState *ts = s->c_cpu->opaque;
+
+            snprintf(buf, sizeof(buf),
+                     "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
+                     ";Bss=" TARGET_ABI_FMT_lx,
+                     ts->info->code_offset,
+                     ts->info->data_offset,
+                     ts->info->data_offset);
+            put_packet(s, buf);
+            break;
+        }
+#else /* !CONFIG_USER_ONLY */
+        else if (strncmp(p, "Rcmd,", 5) == 0) {
+            int len = strlen(p + 5);
+
+            if ((len % 2) != 0) {
+                put_packet(s, "E01");
+                break;
+            }
+            hextomem(mem_buf, p + 5, len);
+            len = len / 2;
+            mem_buf[len++] = 0;
+            qemu_chr_read(s->mon_chr, mem_buf, len);
+            put_packet(s, "OK");
+            break;
+        }
+#endif /* !CONFIG_USER_ONLY */
+        if (strncmp(p, "Supported", 9) == 0) {
+            snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
+#ifdef GDB_CORE_XML
+            pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
+#endif
+            put_packet(s, buf);
+            break;
+        }
+#ifdef GDB_CORE_XML
+        if (strncmp(p, "Xfer:features:read:", 19) == 0) {
+            const char *xml;
+            target_ulong total_len;
+
+            gdb_has_xml = 1;
+            p += 19;
+            xml = get_feature_xml(p, &p);
+            if (!xml) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+
+            if (*p == ':')
+                p++;
+            addr = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            len = strtoul(p, (char **)&p, 16);
+
+            total_len = strlen(xml);
+            if (addr > total_len) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+            if (len > (MAX_PACKET_LENGTH - 5) / 2)
+                len = (MAX_PACKET_LENGTH - 5) / 2;
+            if (len < total_len - addr) {
+                buf[0] = 'm';
+                len = memtox(buf + 1, xml + addr, len);
+            } else {
+                buf[0] = 'l';
+                len = memtox(buf + 1, xml + addr, total_len - addr);
+            }
+            put_packet_binary(s, buf, len + 1);
+            break;
+        }
+#endif
+        /* Unrecognised 'q' command.  */
+        goto unknown_command;
+
+    default:
+    unknown_command:
+        /* put empty packet */
+        buf[0] = '\0';
+        put_packet(s, buf);
+        break;
+    }
+    return RS_IDLE;
+}
+
+void gdb_set_stop_cpu(CPUState *env)
+{
+    gdbserver_state->c_cpu = env;
+    gdbserver_state->g_cpu = env;
+}
+
+#ifndef CONFIG_USER_ONLY
+static void gdb_vm_state_change(void *opaque, int running, int reason)
+{
+    GDBState *s = gdbserver_state;
+    CPUState *env = s->c_cpu;
+    char buf[256];
+    const char *type;
+    int ret;
+
+    if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
+        return;
+    }
+    switch (reason) {
+    case VMSTOP_DEBUG:
+        if (env->watchpoint_hit) {
+            switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
+            case BP_MEM_READ:
+                type = "r";
+                break;
+            case BP_MEM_ACCESS:
+                type = "a";
+                break;
+            default:
+                type = "";
+                break;
+            }
+            snprintf(buf, sizeof(buf),
+                     "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
+                     GDB_SIGNAL_TRAP, gdb_id(env), type,
+                     env->watchpoint_hit->vaddr);
+            env->watchpoint_hit = NULL;
+            goto send_packet;
+        }
+        tb_flush(env);
+        ret = GDB_SIGNAL_TRAP;
+        break;
+    case VMSTOP_USER:
+        ret = GDB_SIGNAL_INT;
+        break;
+    case VMSTOP_SHUTDOWN:
+        ret = GDB_SIGNAL_QUIT;
+        break;
+    case VMSTOP_DISKFULL:
+        ret = GDB_SIGNAL_IO;
+        break;
+    case VMSTOP_WATCHDOG:
+        ret = GDB_SIGNAL_ALRM;
+        break;
+    case VMSTOP_PANIC:
+        ret = GDB_SIGNAL_ABRT;
+        break;
+    case VMSTOP_SAVEVM:
+    case VMSTOP_LOADVM:
+        return;
+    case VMSTOP_MIGRATE:
+        ret = GDB_SIGNAL_XCPU;
+        break;
+    default:
+        ret = GDB_SIGNAL_UNKNOWN;
+        break;
+    }
+    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
+
+send_packet:
+    put_packet(s, buf);
+
+    /* disable single step if it was enabled */
+    cpu_single_step(env, 0);
+}
+#endif
+
+/* Send a gdb syscall request.
+   This accepts limited printf-style format specifiers, specifically:
+    %x  - target_ulong argument printed in hex.
+    %lx - 64-bit argument printed in hex.
+    %s  - string pointer (target_ulong) and length (int) pair.  */
+void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
+{
+    va_list va;
+    char buf[256];
+    char *p;
+    target_ulong addr;
+    uint64_t i64;
+    GDBState *s;
+
+    s = gdbserver_state;
+    if (!s)
+        return;
+    gdb_current_syscall_cb = cb;
+    s->state = RS_SYSCALL;
+#ifndef CONFIG_USER_ONLY
+    vm_stop(VMSTOP_DEBUG);
+#endif
+    s->state = RS_IDLE;
+    va_start(va, fmt);
+    p = buf;
+    *(p++) = 'F';
+    while (*fmt) {
+        if (*fmt == '%') {
+            fmt++;
+            switch (*fmt++) {
+            case 'x':
+                addr = va_arg(va, target_ulong);
+                p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr);
+                break;
+            case 'l':
+                if (*(fmt++) != 'x')
+                    goto bad_format;
+                i64 = va_arg(va, uint64_t);
+                p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64);
+                break;
+            case 's':
+                addr = va_arg(va, target_ulong);
+                p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x",
+                              addr, va_arg(va, int));
+                break;
+            default:
+            bad_format:
+                fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
+                        fmt - 1);
+                break;
+            }
+        } else {
+            *(p++) = *(fmt++);
+        }
+    }
+    *p = 0;
+    va_end(va);
+    put_packet(s, buf);
+#ifdef CONFIG_USER_ONLY
+    gdb_handlesig(s->c_cpu, 0);
+#else
+    cpu_exit(s->c_cpu);
+#endif
+}
+
+static void gdb_read_byte(GDBState *s, int ch)
+{
+    int i, csum;
+    uint8_t reply;
+
+#ifndef CONFIG_USER_ONLY
+    if (s->last_packet_len) {
+        /* Waiting for a response to the last packet.  If we see the start
+           of a new command then abandon the previous response.  */
+        if (ch == '-') {
+#ifdef DEBUG_GDB
+            printf("Got NACK, retransmitting\n");
+#endif
+            put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+        }
+#ifdef DEBUG_GDB
+        else if (ch == '+')
+            printf("Got ACK\n");
+        else
+            printf("Got '%c' when expecting ACK/NACK\n", ch);
+#endif
+        if (ch == '+' || ch == '$')
+            s->last_packet_len = 0;
+        if (ch != '$')
+            return;
+    }
+    if (vm_running) {
+        /* when the CPU is running, we cannot do anything except stop
+           it when receiving a char */
+        vm_stop(VMSTOP_USER);
+    } else
+#endif
+    {
+        switch(s->state) {
+        case RS_IDLE:
+            if (ch == '$') {
+                s->line_buf_index = 0;
+                s->state = RS_GETLINE;
+            }
+            break;
+        case RS_GETLINE:
+            if (ch == '#') {
+            s->state = RS_CHKSUM1;
+            } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+                s->state = RS_IDLE;
+            } else {
+            s->line_buf[s->line_buf_index++] = ch;
+            }
+            break;
+        case RS_CHKSUM1:
+            s->line_buf[s->line_buf_index] = '\0';
+            s->line_csum = fromhex(ch) << 4;
+            s->state = RS_CHKSUM2;
+            break;
+        case RS_CHKSUM2:
+            s->line_csum |= fromhex(ch);
+            csum = 0;
+            for(i = 0; i < s->line_buf_index; i++) {
+                csum += s->line_buf[i];
+            }
+            if (s->line_csum != (csum & 0xff)) {
+                reply = '-';
+                put_buffer(s, &reply, 1);
+                s->state = RS_IDLE;
+            } else {
+                reply = '+';
+                put_buffer(s, &reply, 1);
+                s->state = gdb_handle_packet(s, s->line_buf);
+            }
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+/* Tell the remote gdb that the process has exited.  */
+void gdb_exit(CPUState *env, int code)
+{
+  GDBState *s;
+  char buf[4];
+
+  s = gdbserver_state;
+  if (!s) {
+      return;
+  }
+#ifdef CONFIG_USER_ONLY
+  if (gdbserver_fd < 0 || s->fd < 0) {
+      return;
+  }
+#endif
+
+  snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+  put_packet(s, buf);
+
+#ifndef CONFIG_USER_ONLY
+  if (s->chr) {
+      qemu_chr_close(s->chr);
+  }
+#endif
+}
+
+#ifdef CONFIG_USER_ONLY
+int
+gdb_queuesig (void)
+{
+    GDBState *s;
+
+    s = gdbserver_state;
+
+    if (gdbserver_fd < 0 || s->fd < 0)
+        return 0;
+    else
+        return 1;
+}
+
+int
+gdb_handlesig (CPUState *env, int sig)
+{
+  GDBState *s;
+  char buf[256];
+  int n;
+
+  s = gdbserver_state;
+  if (gdbserver_fd < 0 || s->fd < 0)
+    return sig;
+
+  /* disable single step if it was enabled */
+  cpu_single_step(env, 0);
+  tb_flush(env);
+
+  if (sig != 0)
+    {
+      snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
+      put_packet(s, buf);
+    }
+  /* put_packet() might have detected that the peer terminated the 
+     connection.  */
+  if (s->fd < 0)
+      return sig;
+
+  sig = 0;
+  s->state = RS_IDLE;
+  s->running_state = 0;
+  while (s->running_state == 0) {
+      n = read (s->fd, buf, 256);
+      if (n > 0)
+        {
+          int i;
+
+          for (i = 0; i < n; i++)
+            gdb_read_byte (s, buf[i]);
+        }
+      else if (n == 0 || errno != EAGAIN)
+        {
+          /* XXX: Connection closed.  Should probably wait for annother
+             connection before continuing.  */
+          return sig;
+        }
+  }
+  sig = s->signal;
+  s->signal = 0;
+  return sig;
+}
+
+/* Tell the remote gdb that the process has exited due to SIG.  */
+void gdb_signalled(CPUState *env, int sig)
+{
+  GDBState *s;
+  char buf[4];
+
+  s = gdbserver_state;
+  if (gdbserver_fd < 0 || s->fd < 0)
+    return;
+
+  snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
+  put_packet(s, buf);
+}
+
+static void gdb_accept(void)
+{
+    GDBState *s;
+    struct sockaddr_in sockaddr;
+    socklen_t len;
+    int val, fd;
+
+    for(;;) {
+        len = sizeof(sockaddr);
+        fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
+        if (fd < 0 && errno != EINTR) {
+            perror("accept");
+            return;
+        } else if (fd >= 0) {
+#ifndef _WIN32
+            fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+            break;
+        }
+    }
+
+    /* set short latency */
+    val = 1;
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+
+    s = qemu_mallocz(sizeof(GDBState));
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
+    s->fd = fd;
+    gdb_has_xml = 0;
+
+    gdbserver_state = s;
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+}
+
+static int gdbserver_open(int port)
+{
+    struct sockaddr_in sockaddr;
+    int fd, val, ret;
+
+    fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+#ifndef _WIN32
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+    /* allow fast reuse */
+    val = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+
+    sockaddr.sin_family = AF_INET;
+    sockaddr.sin_port = htons(port);
+    sockaddr.sin_addr.s_addr = 0;
+    ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
+    if (ret < 0) {
+        perror("bind");
+        return -1;
+    }
+    ret = listen(fd, 0);
+    if (ret < 0) {
+        perror("listen");
+        return -1;
+    }
+    return fd;
+}
+
+int gdbserver_start(int port)
+{
+    gdbserver_fd = gdbserver_open(port);
+    if (gdbserver_fd < 0)
+        return -1;
+    /* accept connections */
+    gdb_accept();
+    return 0;
+}
+
+/* Disable gdb stub for child processes.  */
+void gdbserver_fork(CPUState *env)
+{
+    GDBState *s = gdbserver_state;
+    if (gdbserver_fd < 0 || s->fd < 0)
+      return;
+    close(s->fd);
+    s->fd = -1;
+    cpu_breakpoint_remove_all(env, BP_GDB);
+    cpu_watchpoint_remove_all(env, BP_GDB);
+}
+#else
+static int gdb_chr_can_receive(void *opaque)
+{
+  /* We can handle an arbitrarily large amount of data.
+   Pick the maximum packet size, which is as good as anything.  */
+  return MAX_PACKET_LENGTH;
+}
+
+static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
+{
+    int i;
+
+    for (i = 0; i < size; i++) {
+        gdb_read_byte(gdbserver_state, buf[i]);
+    }
+}
+
+static void gdb_chr_event(void *opaque, int event)
+{
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        vm_stop(VMSTOP_USER);
+        gdb_has_xml = 0;
+        break;
+    default:
+        break;
+    }
+}
+
+static void gdb_monitor_output(GDBState *s, const char *msg, int len)
+{
+    char buf[MAX_PACKET_LENGTH];
+
+    buf[0] = 'O';
+    if (len > (MAX_PACKET_LENGTH/2) - 1)
+        len = (MAX_PACKET_LENGTH/2) - 1;
+    memtohex(buf + 1, (uint8_t *)msg, len);
+    put_packet(s, buf);
+}
+
+static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    const char *p = (const char *)buf;
+    int max_sz;
+
+    max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+    for (;;) {
+        if (len <= max_sz) {
+            gdb_monitor_output(gdbserver_state, p, len);
+            break;
+        }
+        gdb_monitor_output(gdbserver_state, p, max_sz);
+        p += max_sz;
+        len -= max_sz;
+    }
+    return len;
+}
+
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+    if (vm_running) {
+        vm_stop(VMSTOP_USER);
+    }
+}
+#endif
+
+int gdbserver_start(const char *device)
+{
+    GDBState *s;
+    char gdbstub_device_name[128];
+    CharDriverState *chr = NULL;
+    CharDriverState *mon_chr;
+
+    if (!device)
+        return -1;
+    if (strcmp(device, "none") != 0) {
+        if (strstart(device, "tcp:", NULL)) {
+            /* enforce required TCP attributes */
+            snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+                     "%s,nowait,nodelay,server", device);
+            device = gdbstub_device_name;
+        }
+#ifndef _WIN32
+        else if (strcmp(device, "stdio") == 0) {
+            struct sigaction act;
+
+            memset(&act, 0, sizeof(act));
+            act.sa_handler = gdb_sigterm_handler;
+            sigaction(SIGINT, &act, NULL);
+        }
+#endif
+        chr = qemu_chr_open("gdb", device, NULL);
+        if (!chr)
+            return -1;
+
+        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+                              gdb_chr_event, NULL);
+    }
+
+    s = gdbserver_state;
+    if (!s) {
+        s = qemu_mallocz(sizeof(GDBState));
+        gdbserver_state = s;
+
+        qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+        /* Initialize a monitor terminal for gdb */
+        mon_chr = qemu_mallocz(sizeof(*mon_chr));
+        mon_chr->chr_write = gdb_monitor_write;
+        monitor_init(mon_chr, 0);
+    } else {
+        if (s->chr)
+            qemu_chr_close(s->chr);
+        mon_chr = s->mon_chr;
+        memset(s, 0, sizeof(GDBState));
+    }
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
+    s->chr = chr;
+    s->state = chr ? RS_IDLE : RS_INACTIVE;
+    s->mon_chr = mon_chr;
+
+    return 0;
+}
+#endif
diff --git a/qemu-0.15.x/gdbstub.h b/qemu-0.15.x/gdbstub.h
new file mode 100644
index 0000000..d82334f
--- /dev/null
+++ b/qemu-0.15.x/gdbstub.h
@@ -0,0 +1,44 @@
+#ifndef GDBSTUB_H
+#define GDBSTUB_H
+
+#define DEFAULT_GDBSTUB_PORT "1234"
+
+/* GDB breakpoint/watchpoint types */
+#define GDB_BREAKPOINT_SW        0
+#define GDB_BREAKPOINT_HW        1
+#define GDB_WATCHPOINT_WRITE     2
+#define GDB_WATCHPOINT_READ      3
+#define GDB_WATCHPOINT_ACCESS    4
+
+#ifdef NEED_CPU_H
+typedef void (*gdb_syscall_complete_cb)(CPUState *env,
+                                        target_ulong ret, target_ulong err);
+
+void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
+int use_gdb_syscalls(void);
+void gdb_set_stop_cpu(CPUState *env);
+void gdb_exit(CPUState *, int);
+#ifdef CONFIG_USER_ONLY
+int gdb_queuesig (void);
+int gdb_handlesig (CPUState *, int);
+void gdb_signalled(CPUState *, int);
+void gdbserver_fork(CPUState *);
+#endif
+/* Get or set a register.  Returns the size of the register.  */
+typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg);
+void gdb_register_coprocessor(CPUState *env,
+                              gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                              int num_regs, const char *xml, int g_pos);
+
+#endif
+
+#ifdef CONFIG_USER_ONLY
+int gdbserver_start(int);
+#else
+int gdbserver_start(const char *port);
+#endif
+
+/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
+extern const char *const xml_builtin[][2];
+
+#endif
diff --git a/qemu-0.15.x/gen-icount.h b/qemu-0.15.x/gen-icount.h
new file mode 100644
index 0000000..5fb3829
--- /dev/null
+++ b/qemu-0.15.x/gen-icount.h
@@ -0,0 +1,48 @@
+#include "qemu-timer.h"
+
+/* Helpers for instruction counting code generation.  */
+
+static TCGArg *icount_arg;
+static int icount_label;
+
+static inline void gen_icount_start(void)
+{
+    TCGv_i32 count;
+
+    if (!use_icount)
+        return;
+
+    icount_label = gen_new_label();
+    count = tcg_temp_local_new_i32();
+    tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32));
+    /* This is a horrid hack to allow fixing up the value later.  */
+    icount_arg = gen_opparam_ptr + 1;
+    tcg_gen_subi_i32(count, count, 0xdeadbeef);
+
+    tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
+    tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low));
+    tcg_temp_free_i32(count);
+}
+
+static void gen_icount_end(TranslationBlock *tb, int num_insns)
+{
+    if (use_icount) {
+        *icount_arg = num_insns;
+        gen_set_label(icount_label);
+        tcg_gen_exit_tb((tcg_target_long)tb + 2);
+    }
+}
+
+static inline void gen_io_start(void)
+{
+    TCGv_i32 tmp = tcg_const_i32(1);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void gen_io_end(void)
+{
+    TCGv_i32 tmp = tcg_const_i32(0);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
+    tcg_temp_free_i32(tmp);
+}
diff --git a/qemu-0.15.x/hmp-commands.hx b/qemu-0.15.x/hmp-commands.hx
new file mode 100644
index 0000000..c857827
--- /dev/null
+++ b/qemu-0.15.x/hmp-commands.hx
@@ -0,0 +1,1370 @@
+HXCOMM Use DEFHEADING() to define headings in both help text and texi
+HXCOMM Text between STEXI and ETEXI are copied to texi version and
+HXCOMM discarded from C version
+HXCOMM DEF(command, args, callback, arg_string, help) is used to construct
+HXCOMM monitor commands
+HXCOMM HXCOMM can be used for comments, discarded from both texi and C
+
+STEXI
+ at table @option
+ETEXI
+
+    {
+        .name       = "help|?",
+        .args_type  = "name:s?",
+        .params     = "[cmd]",
+        .help       = "show the help",
+        .mhandler.cmd = do_help_cmd,
+    },
+
+STEXI
+ at item help or ? [@var{cmd}]
+ at findex help
+Show the help for all commands or just for command @var{cmd}.
+ETEXI
+
+    {
+        .name       = "commit",
+        .args_type  = "device:B",
+        .params     = "device|all",
+        .help       = "commit changes to the disk images (if -snapshot is used) or backing files",
+        .mhandler.cmd = do_commit,
+    },
+
+STEXI
+ at item commit
+ at findex commit
+Commit changes to the disk images (if -snapshot is used) or backing files.
+ETEXI
+
+    {
+        .name       = "q|quit",
+        .args_type  = "",
+        .params     = "",
+        .help       = "quit the emulator",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_quit,
+    },
+
+STEXI
+ at item q or quit
+ at findex quit
+Quit the emulator.
+ETEXI
+
+    {
+        .name       = "block_resize",
+        .args_type  = "device:B,size:o",
+        .params     = "device size",
+        .help       = "resize a block image",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_resize,
+    },
+
+STEXI
+ at item block_resize
+ at findex block_resize
+Resize a block image while a guest is running.  Usually requires guest
+action to see the updated size.  Resize to a lower size is supported,
+but should be used with extreme caution.  Note that this command only
+resizes image files, it can not resize block devices like LVM volumes.
+ETEXI
+
+
+    {
+        .name       = "eject",
+        .args_type  = "force:-f,device:B",
+        .params     = "[-f] device",
+        .help       = "eject a removable medium (use -f to force it)",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_eject,
+    },
+
+STEXI
+ at item eject [-f] @var{device}
+ at findex eject
+Eject a removable medium (use -f to force it).
+ETEXI
+
+    {
+        .name       = "drive_del",
+        .args_type  = "id:s",
+        .params     = "device",
+        .help       = "remove host block device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_drive_del,
+    },
+
+STEXI
+ at item drive_del @var{device}
+ at findex drive_del
+Remove host block device.  The result is that guest generated IO is no longer
+submitted against the host device underlying the disk.  Once a drive has
+been deleted, the QEMU Block layer returns -EIO which results in IO
+errors in the guest for applications that are reading/writing to the device.
+ETEXI
+
+    {
+        .name       = "change",
+        .args_type  = "device:B,target:F,arg:s?",
+        .params     = "device filename [format]",
+        .help       = "change a removable medium, optional format",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_change,
+    },
+
+STEXI
+ at item change @var{device} @var{setting}
+ at findex change
+
+Change the configuration of a device.
+
+ at table @option
+ at item change @var{diskdevice} @var{filename} [@var{format}]
+Change the medium for a removable disk device to point to @var{filename}. eg
+
+ at example
+(qemu) change ide1-cd0 /path/to/some.iso
+ at end example
+
+ at var{format} is optional.
+
+ at item change vnc @var{display}, at var{options}
+Change the configuration of the VNC server. The valid syntax for @var{display}
+and @var{options} are described at @ref{sec_invocation}. eg
+
+ at example
+(qemu) change vnc localhost:1
+ at end example
+
+ at item change vnc password [@var{password}]
+
+Change the password associated with the VNC server. If the new password is not
+supplied, the monitor will prompt for it to be entered. VNC passwords are only
+significant up to 8 letters. eg
+
+ at example
+(qemu) change vnc password
+Password: ********
+ at end example
+
+ at end table
+ETEXI
+
+    {
+        .name       = "screendump",
+        .args_type  = "filename:F",
+        .params     = "filename",
+        .help       = "save screen into PPM image 'filename'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_screen_dump,
+    },
+
+STEXI
+ at item screendump @var{filename}
+ at findex screendump
+Save screen into PPM image @var{filename}.
+ETEXI
+
+    {
+        .name       = "logfile",
+        .args_type  = "filename:F",
+        .params     = "filename",
+        .help       = "output logs to 'filename'",
+        .mhandler.cmd = do_logfile,
+    },
+
+STEXI
+ at item logfile @var{filename}
+ at findex logfile
+Output logs to @var{filename}.
+ETEXI
+
+#ifdef CONFIG_SIMPLE_TRACE
+    {
+        .name       = "trace-event",
+        .args_type  = "name:s,option:b",
+        .params     = "name on|off",
+        .help       = "changes status of a specific trace event",
+        .mhandler.cmd = do_change_trace_event_state,
+    },
+
+STEXI
+ at item trace-event
+ at findex trace-event
+changes status of a trace event
+ETEXI
+
+    {
+        .name       = "trace-file",
+        .args_type  = "op:s?,arg:F?",
+        .params     = "on|off|flush|set [arg]",
+        .help       = "open, close, or flush trace file, or set a new file name",
+        .mhandler.cmd = do_trace_file,
+    },
+
+STEXI
+ at item trace-file on|off|flush
+ at findex trace-file
+Open, close, or flush the trace file.  If no argument is given, the status of the trace file is displayed.
+ETEXI
+#endif
+
+    {
+        .name       = "log",
+        .args_type  = "items:s",
+        .params     = "item1[,...]",
+        .help       = "activate logging of the specified items to '/tmp/qemu.log'",
+        .mhandler.cmd = do_log,
+    },
+
+STEXI
+ at item log @var{item1}[,...]
+ at findex log
+Activate logging of the specified items to @file{/tmp/qemu.log}.
+ETEXI
+
+    {
+        .name       = "savevm",
+        .args_type  = "name:s?",
+        .params     = "[tag|id]",
+        .help       = "save a VM snapshot. If no tag or id are provided, a new snapshot is created",
+        .mhandler.cmd = do_savevm,
+    },
+
+STEXI
+ at item savevm [@var{tag}|@var{id}]
+ at findex savevm
+Create a snapshot of the whole virtual machine. If @var{tag} is
+provided, it is used as human readable identifier. If there is already
+a snapshot with the same tag or ID, it is replaced. More info at
+ at ref{vm_snapshots}.
+ETEXI
+
+    {
+        .name       = "loadvm",
+        .args_type  = "name:s",
+        .params     = "tag|id",
+        .help       = "restore a VM snapshot from its tag or id",
+        .mhandler.cmd = do_loadvm,
+    },
+
+STEXI
+ at item loadvm @var{tag}|@var{id}
+ at findex loadvm
+Set the whole virtual machine to the snapshot identified by the tag
+ at var{tag} or the unique snapshot ID @var{id}.
+ETEXI
+
+    {
+        .name       = "delvm",
+        .args_type  = "name:s",
+        .params     = "tag|id",
+        .help       = "delete a VM snapshot from its tag or id",
+        .mhandler.cmd = do_delvm,
+    },
+
+STEXI
+ at item delvm @var{tag}|@var{id}
+ at findex delvm
+Delete the snapshot identified by @var{tag} or @var{id}.
+ETEXI
+
+    {
+        .name       = "singlestep",
+        .args_type  = "option:s?",
+        .params     = "[on|off]",
+        .help       = "run emulation in singlestep mode or switch to normal mode",
+        .mhandler.cmd = do_singlestep,
+    },
+
+STEXI
+ at item singlestep [off]
+ at findex singlestep
+Run the emulation in single step mode.
+If called with option off, the emulation returns to normal mode.
+ETEXI
+
+    {
+        .name       = "stop",
+        .args_type  = "",
+        .params     = "",
+        .help       = "stop emulation",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_stop,
+    },
+
+STEXI
+ at item stop
+ at findex stop
+Stop emulation.
+ETEXI
+
+    {
+        .name       = "c|cont",
+        .args_type  = "",
+        .params     = "",
+        .help       = "resume emulation",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_cont,
+    },
+
+STEXI
+ at item c or cont
+ at findex cont
+Resume emulation.
+ETEXI
+
+    {
+        .name       = "gdbserver",
+        .args_type  = "device:s?",
+        .params     = "[device]",
+        .help       = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'",
+        .mhandler.cmd = do_gdbserver,
+    },
+
+STEXI
+ at item gdbserver [@var{port}]
+ at findex gdbserver
+Start gdbserver session (default @var{port}=1234)
+ETEXI
+
+    {
+        .name       = "x",
+        .args_type  = "fmt:/,addr:l",
+        .params     = "/fmt addr",
+        .help       = "virtual memory dump starting at 'addr'",
+        .mhandler.cmd = do_memory_dump,
+    },
+
+STEXI
+ at item x/fmt @var{addr}
+ at findex x
+Virtual memory dump starting at @var{addr}.
+ETEXI
+
+    {
+        .name       = "xp",
+        .args_type  = "fmt:/,addr:l",
+        .params     = "/fmt addr",
+        .help       = "physical memory dump starting at 'addr'",
+        .mhandler.cmd = do_physical_memory_dump,
+    },
+
+STEXI
+ at item xp /@var{fmt} @var{addr}
+ at findex xp
+Physical memory dump starting at @var{addr}.
+
+ at var{fmt} is a format which tells the command how to format the
+data. Its syntax is: @option{/@{count@}@{format@}@{size@}}
+
+ at table @var
+ at item count
+is the number of items to be dumped.
+
+ at item format
+can be x (hex), d (signed decimal), u (unsigned decimal), o (octal),
+c (char) or i (asm instruction).
+
+ at item size
+can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86,
+ at code{h} or @code{w} can be specified with the @code{i} format to
+respectively select 16 or 32 bit code instruction size.
+
+ at end table
+
+Examples:
+ at itemize
+ at item
+Dump 10 instructions at the current instruction pointer:
+ at example
+(qemu) x/10i $eip
+0x90107063:  ret
+0x90107064:  sti
+0x90107065:  lea    0x0(%esi,1),%esi
+0x90107069:  lea    0x0(%edi,1),%edi
+0x90107070:  ret
+0x90107071:  jmp    0x90107080
+0x90107073:  nop
+0x90107074:  nop
+0x90107075:  nop
+0x90107076:  nop
+ at end example
+
+ at item
+Dump 80 16 bit values at the start of the video memory.
+ at smallexample
+(qemu) xp/80hx 0xb8000
+0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42
+0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41
+0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72
+0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73
+0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20
+0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720
+0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+ at end smallexample
+ at end itemize
+ETEXI
+
+    {
+        .name       = "p|print",
+        .args_type  = "fmt:/,val:l",
+        .params     = "/fmt expr",
+        .help       = "print expression value (use $reg for CPU register access)",
+        .mhandler.cmd = do_print,
+    },
+
+STEXI
+ at item p or print/@var{fmt} @var{expr}
+ at findex print
+
+Print expression value. Only the @var{format} part of @var{fmt} is
+used.
+ETEXI
+
+    {
+        .name       = "i",
+        .args_type  = "fmt:/,addr:i,index:i.",
+        .params     = "/fmt addr",
+        .help       = "I/O port read",
+        .mhandler.cmd = do_ioport_read,
+    },
+
+STEXI
+Read I/O port.
+ETEXI
+
+    {
+        .name       = "o",
+        .args_type  = "fmt:/,addr:i,val:i",
+        .params     = "/fmt addr value",
+        .help       = "I/O port write",
+        .mhandler.cmd = do_ioport_write,
+    },
+
+STEXI
+Write to I/O port.
+ETEXI
+
+    {
+        .name       = "sendkey",
+        .args_type  = "string:s,hold_time:i?",
+        .params     = "keys [hold_ms]",
+        .help       = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
+        .mhandler.cmd = do_sendkey,
+    },
+
+STEXI
+ at item sendkey @var{keys}
+ at findex sendkey
+
+Send @var{keys} to the emulator. @var{keys} could be the name of the
+key or @code{#} followed by the raw value in either decimal or hexadecimal
+format. Use @code{-} to press several keys simultaneously. Example:
+ at example
+sendkey ctrl-alt-f1
+ at end example
+
+This command is useful to send keys that your graphical user interface
+intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
+ETEXI
+
+    {
+        .name       = "system_reset",
+        .args_type  = "",
+        .params     = "",
+        .help       = "reset the system",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_system_reset,
+    },
+
+STEXI
+ at item system_reset
+ at findex system_reset
+
+Reset the system.
+ETEXI
+
+    {
+        .name       = "system_powerdown",
+        .args_type  = "",
+        .params     = "",
+        .help       = "send system power down event",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_system_powerdown,
+    },
+
+STEXI
+ at item system_powerdown
+ at findex system_powerdown
+
+Power down the system (if supported).
+ETEXI
+
+    {
+        .name       = "sum",
+        .args_type  = "start:i,size:i",
+        .params     = "addr size",
+        .help       = "compute the checksum of a memory region",
+        .mhandler.cmd = do_sum,
+    },
+
+STEXI
+ at item sum @var{addr} @var{size}
+ at findex sum
+
+Compute the checksum of a memory region.
+ETEXI
+
+    {
+        .name       = "usb_add",
+        .args_type  = "devname:s",
+        .params     = "device",
+        .help       = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')",
+        .mhandler.cmd = do_usb_add,
+    },
+
+STEXI
+ at item usb_add @var{devname}
+ at findex usb_add
+
+Add the USB device @var{devname}.  For details of available devices see
+ at ref{usb_devices}
+ETEXI
+
+    {
+        .name       = "usb_del",
+        .args_type  = "devname:s",
+        .params     = "device",
+        .help       = "remove USB device 'bus.addr'",
+        .mhandler.cmd = do_usb_del,
+    },
+
+STEXI
+ at item usb_del @var{devname}
+ at findex usb_del
+
+Remove the USB device @var{devname} from the QEMU virtual USB
+hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
+command @code{info usb} to see the devices you can remove.
+ETEXI
+
+    {
+        .name       = "device_add",
+        .args_type  = "device:O",
+        .params     = "driver[,prop=value][,...]",
+        .help       = "add device, like -device on the command line",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_device_add,
+    },
+
+STEXI
+ at item device_add @var{config}
+ at findex device_add
+
+Add device.
+ETEXI
+
+    {
+        .name       = "device_del",
+        .args_type  = "id:s",
+        .params     = "device",
+        .help       = "remove device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_device_del,
+    },
+
+STEXI
+ at item device_del @var{id}
+ at findex device_del
+
+Remove device @var{id}.
+ETEXI
+
+    {
+        .name       = "cpu",
+        .args_type  = "index:i",
+        .params     = "index",
+        .help       = "set the default CPU",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_cpu_set,
+    },
+
+STEXI
+ at item cpu @var{index}
+ at findex cpu
+Set the default CPU.
+ETEXI
+
+    {
+        .name       = "mouse_move",
+        .args_type  = "dx_str:s,dy_str:s,dz_str:s?",
+        .params     = "dx dy [dz]",
+        .help       = "send mouse move events",
+        .mhandler.cmd = do_mouse_move,
+    },
+
+STEXI
+ at item mouse_move @var{dx} @var{dy} [@var{dz}]
+ at findex mouse_move
+Move the active mouse to the specified coordinates @var{dx} @var{dy}
+with optional scroll axis @var{dz}.
+ETEXI
+
+    {
+        .name       = "mouse_button",
+        .args_type  = "button_state:i",
+        .params     = "state",
+        .help       = "change mouse button state (1=L, 2=M, 4=R)",
+        .mhandler.cmd = do_mouse_button,
+    },
+
+STEXI
+ at item mouse_button @var{val}
+ at findex mouse_button
+Change the active mouse button state @var{val} (1=L, 2=M, 4=R).
+ETEXI
+
+    {
+        .name       = "mouse_set",
+        .args_type  = "index:i",
+        .params     = "index",
+        .help       = "set which mouse device receives events",
+        .mhandler.cmd = do_mouse_set,
+    },
+
+STEXI
+ at item mouse_set @var{index}
+ at findex mouse_set
+Set which mouse device receives events at given @var{index}, index
+can be obtained with
+ at example
+info mice
+ at end example
+ETEXI
+
+#ifdef HAS_AUDIO
+    {
+        .name       = "wavcapture",
+        .args_type  = "path:F,freq:i?,bits:i?,nchannels:i?",
+        .params     = "path [frequency [bits [channels]]]",
+        .help       = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)",
+        .mhandler.cmd = do_wav_capture,
+    },
+#endif
+STEXI
+ at item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
+ at findex wavcapture
+Capture audio into @var{filename}. Using sample rate @var{frequency}
+bits per sample @var{bits} and number of channels @var{channels}.
+
+Defaults:
+ at itemize @minus
+ at item Sample rate = 44100 Hz - CD quality
+ at item Bits = 16
+ at item Number of channels = 2 - Stereo
+ at end itemize
+ETEXI
+
+#ifdef HAS_AUDIO
+    {
+        .name       = "stopcapture",
+        .args_type  = "n:i",
+        .params     = "capture index",
+        .help       = "stop capture",
+        .mhandler.cmd = do_stop_capture,
+    },
+#endif
+STEXI
+ at item stopcapture @var{index}
+ at findex stopcapture
+Stop capture with a given @var{index}, index can be obtained with
+ at example
+info capture
+ at end example
+ETEXI
+
+    {
+        .name       = "memsave",
+        .args_type  = "val:l,size:i,filename:s",
+        .params     = "addr size file",
+        .help       = "save to disk virtual memory dump starting at 'addr' of size 'size'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_memory_save,
+    },
+
+STEXI
+ at item memsave @var{addr} @var{size} @var{file}
+ at findex memsave
+save to disk virtual memory dump starting at @var{addr} of size @var{size}.
+ETEXI
+
+    {
+        .name       = "pmemsave",
+        .args_type  = "val:l,size:i,filename:s",
+        .params     = "addr size file",
+        .help       = "save to disk physical memory dump starting at 'addr' of size 'size'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_physical_memory_save,
+    },
+
+STEXI
+ at item pmemsave @var{addr} @var{size} @var{file}
+ at findex pmemsave
+save to disk physical memory dump starting at @var{addr} of size @var{size}.
+ETEXI
+
+    {
+        .name       = "boot_set",
+        .args_type  = "bootdevice:s",
+        .params     = "bootdevice",
+        .help       = "define new values for the boot device list",
+        .mhandler.cmd = do_boot_set,
+    },
+
+STEXI
+ at item boot_set @var{bootdevicelist}
+ at findex boot_set
+
+Define new values for the boot device list. Those values will override
+the values specified on the command line through the @code{-boot} option.
+
+The values that can be specified here depend on the machine type, but are
+the same that can be specified in the @code{-boot} command line option.
+ETEXI
+
+#if defined(TARGET_I386)
+    {
+        .name       = "nmi",
+        .args_type  = "",
+        .params     = "",
+        .help       = "inject an NMI on all guest's CPUs",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_inject_nmi,
+    },
+#endif
+STEXI
+ at item nmi @var{cpu}
+ at findex nmi
+Inject an NMI on the given CPU (x86 only).
+ETEXI
+
+    {
+        .name       = "migrate",
+        .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
+        .params     = "[-d] [-b] [-i] uri",
+        .help       = "migrate to URI (using -d to not wait for completion)"
+		      "\n\t\t\t -b for migration without shared storage with"
+		      " full copy of disk\n\t\t\t -i for migration without "
+		      "shared storage with incremental copy of disk "
+		      "(base image shared between src and destination)",
+        .user_print = monitor_user_noop,	
+	.mhandler.cmd_new = do_migrate,
+    },
+
+
+STEXI
+ at item migrate [-d] [-b] [-i] @var{uri}
+ at findex migrate
+Migrate to @var{uri} (using -d to not wait for completion).
+	-b for migration with full copy of disk
+	-i for migration with incremental copy of disk (base image is shared)
+ETEXI
+
+    {
+        .name       = "migrate_cancel",
+        .args_type  = "",
+        .params     = "",
+        .help       = "cancel the current VM migration",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_cancel,
+    },
+
+STEXI
+ at item migrate_cancel
+ at findex migrate_cancel
+Cancel the current VM migration.
+ETEXI
+
+    {
+        .name       = "migrate_set_speed",
+        .args_type  = "value:o",
+        .params     = "value",
+        .help       = "set maximum speed (in bytes) for migrations. "
+	"Defaults to MB if no size suffix is specified, ie. B/K/M/G/T",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_set_speed,
+    },
+
+STEXI
+ at item migrate_set_speed @var{value}
+ at findex migrate_set_speed
+Set maximum speed to @var{value} (in bytes) for migrations.
+ETEXI
+
+    {
+        .name       = "migrate_set_downtime",
+        .args_type  = "value:T",
+        .params     = "value",
+        .help       = "set maximum tolerated downtime (in seconds) for migrations",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_set_downtime,
+    },
+
+STEXI
+ at item migrate_set_downtime @var{second}
+ at findex migrate_set_downtime
+Set maximum tolerated downtime (in seconds) for migration.
+ETEXI
+
+    {
+        .name       = "client_migrate_info",
+        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+        .params     = "protocol hostname port tls-port cert-subject",
+        .help       = "send migration info to spice/vnc client",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = client_migrate_info,
+    },
+
+STEXI
+ at item client_migrate_info @var{protocol} @var{hostname} @var{port} @var{tls-port} @var{cert-subject}
+ at findex client_migrate_info
+Set the spice/vnc connection info for the migration target.  The spice/vnc
+server will ask the spice/vnc client to automatically reconnect using the
+new parameters (if specified) once the vm migration finished successfully.
+ETEXI
+
+    {
+        .name       = "snapshot_blkdev",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .help       = "initiates a live snapshot\n\t\t\t"
+                      "of device. If a new image file is specified, the\n\t\t\t"
+                      "new image file will become the new root image.\n\t\t\t"
+                      "If format is specified, the snapshot file will\n\t\t\t"
+                      "be created in that format. Otherwise the\n\t\t\t"
+                      "snapshot will be internal! (currently unsupported)",
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+STEXI
+ at item snapshot_blkdev
+ at findex snapshot_blkdev
+Snapshot device, using snapshot file as target if provided
+ETEXI
+
+#if defined(TARGET_I386)
+    {
+        .name       = "drive_add",
+        .args_type  = "pci_addr:s,opts:s",
+        .params     = "[[<domain>:]<bus>:]<slot>\n"
+                      "[file=file][,if=type][,bus=n]\n"
+                      "[,unit=m][,media=d][index=i]\n"
+                      "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
+                      "[snapshot=on|off][,cache=on|off]",
+        .help       = "add drive to PCI storage controller",
+        .mhandler.cmd = drive_hot_add,
+    },
+#endif
+
+STEXI
+ at item drive_add
+ at findex drive_add
+Add drive to PCI storage controller.
+ETEXI
+
+#if defined(TARGET_I386)
+    {
+        .name       = "pci_add",
+        .args_type  = "pci_addr:s,type:s,opts:s?",
+        .params     = "auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...",
+        .help       = "hot-add PCI device",
+        .mhandler.cmd = pci_device_hot_add,
+    },
+#endif
+
+STEXI
+ at item pci_add
+ at findex pci_add
+Hot-add PCI device.
+ETEXI
+
+#if defined(TARGET_I386)
+    {
+        .name       = "pci_del",
+        .args_type  = "pci_addr:s",
+        .params     = "[[<domain>:]<bus>:]<slot>",
+        .help       = "hot remove PCI device",
+        .mhandler.cmd = do_pci_device_hot_remove,
+    },
+#endif
+
+STEXI
+ at item pci_del
+ at findex pci_del
+Hot remove PCI device.
+ETEXI
+
+    {
+        .name       = "pcie_aer_inject_error",
+        .args_type  = "advisory_non_fatal:-a,correctable:-c,"
+	              "id:s,error_status:s,"
+	              "header0:i?,header1:i?,header2:i?,header3:i?,"
+	              "prefix0:i?,prefix1:i?,prefix2:i?,prefix3:i?",
+        .params     = "[-a] [-c] id "
+                      "<error_status> [<tlp header> [<tlp header prefix>]]",
+        .help       = "inject pcie aer error\n\t\t\t"
+	              " -a for advisory non fatal error\n\t\t\t"
+	              " -c for correctable error\n\t\t\t"
+                      "<id> = qdev device id\n\t\t\t"
+                      "<error_status> = error string or 32bit\n\t\t\t"
+                      "<tlb header> = 32bit x 4\n\t\t\t"
+                      "<tlb header prefix> = 32bit x 4",
+        .user_print  = pcie_aer_inject_error_print,
+        .mhandler.cmd_new = do_pcie_aer_inejct_error,
+    },
+
+STEXI
+ at item pcie_aer_inject_error
+ at findex pcie_aer_inject_error
+Inject PCIe AER error
+ETEXI
+
+    {
+        .name       = "host_net_add",
+        .args_type  = "device:s,opts:s?",
+        .params     = "tap|user|socket|vde|dump [options]",
+        .help       = "add host VLAN client",
+        .mhandler.cmd = net_host_device_add,
+    },
+
+STEXI
+ at item host_net_add
+ at findex host_net_add
+Add host VLAN client.
+ETEXI
+
+    {
+        .name       = "host_net_remove",
+        .args_type  = "vlan_id:i,device:s",
+        .params     = "vlan_id name",
+        .help       = "remove host VLAN client",
+        .mhandler.cmd = net_host_device_remove,
+    },
+
+STEXI
+ at item host_net_remove
+ at findex host_net_remove
+Remove host VLAN client.
+ETEXI
+
+    {
+        .name       = "netdev_add",
+        .args_type  = "netdev:O",
+        .params     = "[user|tap|socket],id=str[,prop=value][,...]",
+        .help       = "add host network device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_netdev_add,
+    },
+
+STEXI
+ at item netdev_add
+ at findex netdev_add
+Add host network device.
+ETEXI
+
+    {
+        .name       = "netdev_del",
+        .args_type  = "id:s",
+        .params     = "id",
+        .help       = "remove host network device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_netdev_del,
+    },
+
+STEXI
+ at item netdev_del
+ at findex netdev_del
+Remove host network device.
+ETEXI
+
+#ifdef CONFIG_SLIRP
+    {
+        .name       = "hostfwd_add",
+        .args_type  = "arg1:s,arg2:s?,arg3:s?",
+        .params     = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
+        .help       = "redirect TCP or UDP connections from host to guest (requires -net user)",
+        .mhandler.cmd = net_slirp_hostfwd_add,
+    },
+#endif
+STEXI
+ at item hostfwd_add
+ at findex hostfwd_add
+Redirect TCP or UDP connections from host to guest (requires -net user).
+ETEXI
+
+#ifdef CONFIG_SLIRP
+    {
+        .name       = "hostfwd_remove",
+        .args_type  = "arg1:s,arg2:s?,arg3:s?",
+        .params     = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport",
+        .help       = "remove host-to-guest TCP or UDP redirection",
+        .mhandler.cmd = net_slirp_hostfwd_remove,
+    },
+
+#endif
+STEXI
+ at item hostfwd_remove
+ at findex hostfwd_remove
+Remove host-to-guest TCP or UDP redirection.
+ETEXI
+
+    {
+        .name       = "balloon",
+        .args_type  = "value:M",
+        .params     = "target",
+        .help       = "request VM to change its memory allocation (in MB)",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = do_balloon,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+STEXI
+ at item balloon @var{value}
+ at findex balloon
+Request VM to change its memory allocation to @var{value} (in MB).
+ETEXI
+
+    {
+        .name       = "set_link",
+        .args_type  = "name:s,up:b",
+        .params     = "name on|off",
+        .help       = "change the link status of a network adapter",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_set_link,
+    },
+
+STEXI
+ at item set_link @var{name} [on|off]
+ at findex set_link
+Switch link @var{name} on (i.e. up) or off (i.e. down).
+ETEXI
+
+    {
+        .name       = "watchdog_action",
+        .args_type  = "action:s",
+        .params     = "[reset|shutdown|poweroff|pause|debug|none]",
+        .help       = "change watchdog action",
+        .mhandler.cmd = do_watchdog_action,
+    },
+
+STEXI
+ at item watchdog_action
+ at findex watchdog_action
+Change watchdog action.
+ETEXI
+
+    {
+        .name       = "acl_show",
+        .args_type  = "aclname:s",
+        .params     = "aclname",
+        .help       = "list rules in the access control list",
+        .mhandler.cmd = do_acl_show,
+    },
+
+STEXI
+ at item acl_show @var{aclname}
+ at findex acl_show
+List all the matching rules in the access control list, and the default
+policy. There are currently two named access control lists,
+ at var{vnc.x509dname} and @var{vnc.username} matching on the x509 client
+certificate distinguished name, and SASL username respectively.
+ETEXI
+
+    {
+        .name       = "acl_policy",
+        .args_type  = "aclname:s,policy:s",
+        .params     = "aclname allow|deny",
+        .help       = "set default access control list policy",
+        .mhandler.cmd = do_acl_policy,
+    },
+
+STEXI
+ at item acl_policy @var{aclname} @code{allow|deny}
+ at findex acl_policy
+Set the default access control list policy, used in the event that
+none of the explicit rules match. The default policy at startup is
+always @code{deny}.
+ETEXI
+
+    {
+        .name       = "acl_add",
+        .args_type  = "aclname:s,match:s,policy:s,index:i?",
+        .params     = "aclname match allow|deny [index]",
+        .help       = "add a match rule to the access control list",
+        .mhandler.cmd = do_acl_add,
+    },
+
+STEXI
+ at item acl_add @var{aclname} @var{match} @code{allow|deny} [@var{index}]
+ at findex acl_add
+Add a match rule to the access control list, allowing or denying access.
+The match will normally be an exact username or x509 distinguished name,
+but can optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to
+allow all users in the @code{EXAMPLE.COM} kerberos realm. The match will
+normally be appended to the end of the ACL, but can be inserted
+earlier in the list if the optional @var{index} parameter is supplied.
+ETEXI
+
+    {
+        .name       = "acl_remove",
+        .args_type  = "aclname:s,match:s",
+        .params     = "aclname match",
+        .help       = "remove a match rule from the access control list",
+        .mhandler.cmd = do_acl_remove,
+    },
+
+STEXI
+ at item acl_remove @var{aclname} @var{match}
+ at findex acl_remove
+Remove the specified match rule from the access control list.
+ETEXI
+
+    {
+        .name       = "acl_reset",
+        .args_type  = "aclname:s",
+        .params     = "aclname",
+        .help       = "reset the access control list",
+        .mhandler.cmd = do_acl_reset,
+    },
+
+STEXI
+ at item acl_reset @var{aclname}
+ at findex acl_reset
+Remove all matches from the access control list, and set the default
+policy back to @code{deny}.
+ETEXI
+
+#if defined(TARGET_I386)
+
+    {
+        .name       = "mce",
+        .args_type  = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l",
+        .params     = "[-b] cpu bank status mcgstatus addr misc",
+        .help       = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]",
+        .mhandler.cmd = do_inject_mce,
+    },
+
+#endif
+STEXI
+ at item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc}
+ at findex mce (x86)
+Inject an MCE on the given CPU (x86 only).
+ETEXI
+
+    {
+        .name       = "getfd",
+        .args_type  = "fdname:s",
+        .params     = "getfd name",
+        .help       = "receive a file descriptor via SCM rights and assign it a name",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_getfd,
+    },
+
+STEXI
+ at item getfd @var{fdname}
+ at findex getfd
+If a file descriptor is passed alongside this command using the SCM_RIGHTS
+mechanism on unix sockets, it is stored using the name @var{fdname} for
+later use by other monitor commands.
+ETEXI
+
+    {
+        .name       = "closefd",
+        .args_type  = "fdname:s",
+        .params     = "closefd name",
+        .help       = "close a file descriptor previously passed via SCM rights",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_closefd,
+    },
+
+STEXI
+ at item closefd @var{fdname}
+ at findex closefd
+Close the file descriptor previously assigned to @var{fdname} using the
+ at code{getfd} command. This is only needed if the file descriptor was never
+used by another monitor command.
+ETEXI
+
+    {
+        .name       = "block_passwd",
+        .args_type  = "device:B,password:s",
+        .params     = "block_passwd device password",
+        .help       = "set the password of encrypted block devices",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_set_passwd,
+    },
+
+STEXI
+ at item block_passwd @var{device} @var{password}
+ at findex block_passwd
+Set the encrypted device @var{device} password to @var{password}
+ETEXI
+
+    {
+        .name       = "set_password",
+        .args_type  = "protocol:s,password:s,connected:s?",
+        .params     = "protocol password action-if-connected",
+        .help       = "set spice/vnc password",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = set_password,
+    },
+
+STEXI
+ at item set_password [ vnc | spice ] password [ action-if-connected ]
+ at findex set_password
+
+Change spice/vnc password.  Use zero to make the password stay valid
+forever.  @var{action-if-connected} specifies what should happen in
+case a connection is established: @var{fail} makes the password change
+fail.  @var{disconnect} changes the password and disconnects the
+client.  @var{keep} changes the password and keeps the connection up.
+ at var{keep} is the default.
+ETEXI
+
+    {
+        .name       = "expire_password",
+        .args_type  = "protocol:s,time:s",
+        .params     = "protocol time",
+        .help       = "set spice/vnc password expire-time",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = expire_password,
+    },
+
+STEXI
+ at item expire_password [ vnc | spice ] expire-time
+ at findex expire_password
+
+Specify when a password for spice/vnc becomes
+invalid. @var{expire-time} accepts:
+
+ at table @var
+ at item now
+Invalidate password instantly.
+
+ at item never
+Password stays valid forever.
+
+ at item +nsec
+Password stays valid for @var{nsec} seconds starting now.
+
+ at item nsec
+Password is invalidated at the given time.  @var{nsec} are the seconds
+passed since 1970, i.e. unix epoch.
+
+ at end table
+ETEXI
+
+    {
+        .name       = "info",
+        .args_type  = "item:s?",
+        .params     = "[subcommand]",
+        .help       = "show various information about the system state",
+        .mhandler.cmd = do_info,
+    },
+
+STEXI
+ at item info @var{subcommand}
+ at findex info
+Show various information about the system state.
+
+ at table @option
+ at item info version
+show the version of QEMU
+ at item info network
+show the various VLANs and the associated devices
+ at item info chardev
+show the character devices
+ at item info block
+show the block devices
+ at item info blockstats
+show block device statistics
+ at item info registers
+show the cpu registers
+ at item info cpus
+show infos for each CPU
+ at item info history
+show the command line history
+ at item info irq
+show the interrupts statistics (if available)
+ at item info pic
+show i8259 (PIC) state
+ at item info pci
+show emulated PCI device info
+ at item info tlb
+show virtual to physical memory mappings (i386, SH4 and SPARC only)
+ at item info mem
+show the active virtual memory mappings (i386 only)
+ at item info jit
+show dynamic compiler info
+ at item info kvm
+show KVM information
+ at item info numa
+show NUMA information
+ at item info kvm
+show KVM information
+ at item info usb
+show USB devices plugged on the virtual USB hub
+ at item info usbhost
+show all USB host devices
+ at item info profile
+show profiling information
+ at item info capture
+show information about active capturing
+ at item info snapshots
+show list of VM snapshots
+ at item info status
+show the current VM status (running|paused)
+ at item info pcmcia
+show guest PCMCIA status
+ at item info mice
+show which guest mouse is receiving events
+ at item info vnc
+show the vnc server status
+ at item info name
+show the current VM name
+ at item info uuid
+show the current VM UUID
+ at item info cpustats
+show CPU statistics
+ at item info usernet
+show user network stack connection states
+ at item info migrate
+show migration status
+ at item info balloon
+show balloon information
+ at item info qtree
+show device tree
+ at item info qdm
+show qdev device model list
+ at item info roms
+show roms
+ at end table
+ETEXI
+
+#ifdef CONFIG_SIMPLE_TRACE
+STEXI
+ at item info trace
+show contents of trace buffer
+ at item info trace-events
+show available trace events and their state
+ETEXI
+#endif
+
+STEXI
+ at end table
+ETEXI
diff --git a/qemu-0.15.x/host-utils.c b/qemu-0.15.x/host-utils.c
new file mode 100644
index 0000000..dc96123
--- /dev/null
+++ b/qemu-0.15.x/host-utils.c
@@ -0,0 +1,105 @@
+/*
+ * Utility compute operations used by translated code.
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2007 Aurelien Jarno
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+#include "host-utils.h"
+
+//#define DEBUG_MULDIV
+
+/* Long integer helpers */
+#if !defined(__x86_64__)
+static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    *plow += a;
+    /* carry test */
+    if (*plow < a)
+        (*phigh)++;
+    *phigh += b;
+}
+
+static void neg128 (uint64_t *plow, uint64_t *phigh)
+{
+    *plow = ~*plow;
+    *phigh = ~*phigh;
+    add128(plow, phigh, 1, 0);
+}
+
+static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    uint32_t a0, a1, b0, b1;
+    uint64_t v;
+
+    a0 = a;
+    a1 = a >> 32;
+
+    b0 = b;
+    b1 = b >> 32;
+
+    v = (uint64_t)a0 * (uint64_t)b0;
+    *plow = v;
+    *phigh = 0;
+
+    v = (uint64_t)a0 * (uint64_t)b1;
+    add128(plow, phigh, v << 32, v >> 32);
+
+    v = (uint64_t)a1 * (uint64_t)b0;
+    add128(plow, phigh, v << 32, v >> 32);
+
+    v = (uint64_t)a1 * (uint64_t)b1;
+    *phigh += v;
+}
+
+/* Unsigned 64x64 -> 128 multiplication */
+void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    mul64(plow, phigh, a, b);
+#if defined(DEBUG_MULDIV)
+    printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
+           a, b, *phigh, *plow);
+#endif
+}
+
+/* Signed 64x64 -> 128 multiplication */
+void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
+{
+    int sa, sb;
+
+    sa = (a < 0);
+    if (sa)
+        a = -a;
+    sb = (b < 0);
+    if (sb)
+        b = -b;
+    mul64(plow, phigh, a, b);
+    if (sa ^ sb) {
+        neg128(plow, phigh);
+    }
+#if defined(DEBUG_MULDIV)
+    printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
+           a, b, *phigh, *plow);
+#endif
+}
+#endif /* !defined(__x86_64__) */
diff --git a/qemu-0.15.x/host-utils.h b/qemu-0.15.x/host-utils.h
new file mode 100644
index 0000000..0ddc176
--- /dev/null
+++ b/qemu-0.15.x/host-utils.h
@@ -0,0 +1,236 @@
+/*
+ * Utility compute operations used by translated code.
+ *
+ * Copyright (c) 2007 Thiemo Seufer
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "osdep.h"
+
+#if defined(__x86_64__)
+#define __HAVE_FAST_MULU64__
+static inline void mulu64(uint64_t *plow, uint64_t *phigh,
+                          uint64_t a, uint64_t b)
+{
+    __asm__ ("mul %0\n\t"
+             : "=d" (*phigh), "=a" (*plow)
+             : "a" (a), "0" (b));
+}
+#define __HAVE_FAST_MULS64__
+static inline void muls64(uint64_t *plow, uint64_t *phigh,
+                          int64_t a, int64_t b)
+{
+    __asm__ ("imul %0\n\t"
+             : "=d" (*phigh), "=a" (*plow)
+             : "a" (a), "0" (b));
+}
+#else
+void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
+void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+#endif
+
+/* Binary search for leading zeros.  */
+
+static inline int clz32(uint32_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_clz(val);
+    else
+        return 32;
+#else
+    int cnt = 0;
+
+    if (!(val & 0xFFFF0000U)) {
+        cnt += 16;
+        val <<= 16;
+    }
+    if (!(val & 0xFF000000U)) {
+        cnt += 8;
+        val <<= 8;
+    }
+    if (!(val & 0xF0000000U)) {
+        cnt += 4;
+        val <<= 4;
+    }
+    if (!(val & 0xC0000000U)) {
+        cnt += 2;
+        val <<= 2;
+    }
+    if (!(val & 0x80000000U)) {
+        cnt++;
+        val <<= 1;
+    }
+    if (!(val & 0x80000000U)) {
+        cnt++;
+    }
+    return cnt;
+#endif
+}
+
+static inline int clo32(uint32_t val)
+{
+    return clz32(~val);
+}
+
+static inline int clz64(uint64_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_clzll(val);
+    else
+        return 64;
+#else
+    int cnt = 0;
+
+    if (!(val >> 32)) {
+        cnt += 32;
+    } else {
+        val >>= 32;
+    }
+
+    return cnt + clz32(val);
+#endif
+}
+
+static inline int clo64(uint64_t val)
+{
+    return clz64(~val);
+}
+
+static inline int ctz32(uint32_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_ctz(val);
+    else
+        return 32;
+#else
+    int cnt;
+
+    cnt = 0;
+    if (!(val & 0x0000FFFFUL)) {
+        cnt += 16;
+        val >>= 16;
+    }
+    if (!(val & 0x000000FFUL)) {
+        cnt += 8;
+        val >>= 8;
+    }
+    if (!(val & 0x0000000FUL)) {
+        cnt += 4;
+        val >>= 4;
+    }
+    if (!(val & 0x00000003UL)) {
+        cnt += 2;
+        val >>= 2;
+    }
+    if (!(val & 0x00000001UL)) {
+        cnt++;
+        val >>= 1;
+    }
+    if (!(val & 0x00000001UL)) {
+        cnt++;
+    }
+
+    return cnt;
+#endif
+}
+
+static inline int cto32(uint32_t val)
+{
+    return ctz32(~val);
+}
+
+static inline int ctz64(uint64_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_ctzll(val);
+    else
+        return 64;
+#else
+    int cnt;
+
+    cnt = 0;
+    if (!((uint32_t)val)) {
+        cnt += 32;
+        val >>= 32;
+    }
+
+    return cnt + ctz32(val);
+#endif
+}
+
+static inline int cto64(uint64_t val)
+{
+    return ctz64(~val);
+}
+
+static inline int ctpop8(uint8_t val)
+{
+    val = (val & 0x55) + ((val >> 1) & 0x55);
+    val = (val & 0x33) + ((val >> 2) & 0x33);
+    val = (val & 0x0f) + ((val >> 4) & 0x0f);
+
+    return val;
+}
+
+static inline int ctpop16(uint16_t val)
+{
+    val = (val & 0x5555) + ((val >> 1) & 0x5555);
+    val = (val & 0x3333) + ((val >> 2) & 0x3333);
+    val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f);
+    val = (val & 0x00ff) + ((val >> 8) & 0x00ff);
+
+    return val;
+}
+
+static inline int ctpop32(uint32_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    return __builtin_popcount(val);
+#else
+    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
+    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
+    val = (val & 0x00ff00ff) + ((val >>  8) & 0x00ff00ff);
+    val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
+
+    return val;
+#endif
+}
+
+static inline int ctpop64(uint64_t val)
+{
+#if QEMU_GNUC_PREREQ(3, 4)
+    return __builtin_popcountll(val);
+#else
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) & 0x00ff00ff00ff00ffULL);
+    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL);
+    val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL);
+
+    return val;
+#endif
+}
diff --git a/qemu-0.15.x/hpet.h b/qemu-0.15.x/hpet.h
new file mode 100644
index 0000000..754051a
--- /dev/null
+++ b/qemu-0.15.x/hpet.h
@@ -0,0 +1,22 @@
+#ifndef	__HPET__
+#define	__HPET__ 1
+
+
+
+struct hpet_info {
+	unsigned long hi_ireqfreq;	/* Hz */
+	unsigned long hi_flags;	/* information */
+	unsigned short hi_hpet;
+	unsigned short hi_timer;
+};
+
+#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+
+#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
+#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
+#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
+#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
+#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+
+#endif				/* !__HPET__ */
diff --git a/qemu-0.15.x/hppa-dis.c b/qemu-0.15.x/hppa-dis.c
new file mode 100644
index 0000000..435da73
--- /dev/null
+++ b/qemu-0.15.x/hppa-dis.c
@@ -0,0 +1,2831 @@
+/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
+   Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003,
+   2005 Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs at cs.utah.edu).
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "dis-asm.h"
+
+/* HP PA-RISC SOM object file format:  definitions internal to BFD.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2003 Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs at cs.utah.edu).
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBHPPA_H
+#define _LIBHPPA_H
+
+#define BYTES_IN_WORD 4
+#define PA_PAGESIZE 0x1000
+
+/* The PA instruction set variants.  */
+enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25};
+
+/* HP PA-RISC relocation types */
+
+enum hppa_reloc_field_selector_type
+  {
+    R_HPPA_FSEL = 0x0,
+    R_HPPA_LSSEL = 0x1,
+    R_HPPA_RSSEL = 0x2,
+    R_HPPA_LSEL = 0x3,
+    R_HPPA_RSEL = 0x4,
+    R_HPPA_LDSEL = 0x5,
+    R_HPPA_RDSEL = 0x6,
+    R_HPPA_LRSEL = 0x7,
+    R_HPPA_RRSEL = 0x8,
+    R_HPPA_NSEL  = 0x9,
+    R_HPPA_NLSEL  = 0xa,
+    R_HPPA_NLRSEL  = 0xb,
+    R_HPPA_PSEL = 0xc,
+    R_HPPA_LPSEL = 0xd,
+    R_HPPA_RPSEL = 0xe,
+    R_HPPA_TSEL = 0xf,
+    R_HPPA_LTSEL = 0x10,
+    R_HPPA_RTSEL = 0x11,
+    R_HPPA_LTPSEL = 0x12,
+    R_HPPA_RTPSEL = 0x13
+  };
+
+/* /usr/include/reloc.h defines these to constants.  We want to use
+   them in enums, so #undef them before we start using them.  We might
+   be able to fix this another way by simply managing not to include
+   /usr/include/reloc.h, but currently GDB picks up these defines
+   somewhere.  */
+#undef e_fsel
+#undef e_lssel
+#undef e_rssel
+#undef e_lsel
+#undef e_rsel
+#undef e_ldsel
+#undef e_rdsel
+#undef e_lrsel
+#undef e_rrsel
+#undef e_nsel
+#undef e_nlsel
+#undef e_nlrsel
+#undef e_psel
+#undef e_lpsel
+#undef e_rpsel
+#undef e_tsel
+#undef e_ltsel
+#undef e_rtsel
+#undef e_one
+#undef e_two
+#undef e_pcrel
+#undef e_con
+#undef e_plabel
+#undef e_abs
+
+/* for compatibility */
+enum hppa_reloc_field_selector_type_alt
+  {
+    e_fsel = R_HPPA_FSEL,
+    e_lssel = R_HPPA_LSSEL,
+    e_rssel = R_HPPA_RSSEL,
+    e_lsel = R_HPPA_LSEL,
+    e_rsel = R_HPPA_RSEL,
+    e_ldsel = R_HPPA_LDSEL,
+    e_rdsel = R_HPPA_RDSEL,
+    e_lrsel = R_HPPA_LRSEL,
+    e_rrsel = R_HPPA_RRSEL,
+    e_nsel = R_HPPA_NSEL,
+    e_nlsel = R_HPPA_NLSEL,
+    e_nlrsel = R_HPPA_NLRSEL,
+    e_psel = R_HPPA_PSEL,
+    e_lpsel = R_HPPA_LPSEL,
+    e_rpsel = R_HPPA_RPSEL,
+    e_tsel = R_HPPA_TSEL,
+    e_ltsel = R_HPPA_LTSEL,
+    e_rtsel = R_HPPA_RTSEL,
+    e_ltpsel = R_HPPA_LTPSEL,
+    e_rtpsel = R_HPPA_RTPSEL
+  };
+
+enum hppa_reloc_expr_type
+  {
+    R_HPPA_E_ONE = 0,
+    R_HPPA_E_TWO = 1,
+    R_HPPA_E_PCREL = 2,
+    R_HPPA_E_CON = 3,
+    R_HPPA_E_PLABEL = 7,
+    R_HPPA_E_ABS = 18
+  };
+
+/* for compatibility */
+enum hppa_reloc_expr_type_alt
+  {
+    e_one = R_HPPA_E_ONE,
+    e_two = R_HPPA_E_TWO,
+    e_pcrel = R_HPPA_E_PCREL,
+    e_con = R_HPPA_E_CON,
+    e_plabel = R_HPPA_E_PLABEL,
+    e_abs = R_HPPA_E_ABS
+  };
+
+
+/* Relocations for function calls must be accompanied by parameter
+   relocation bits.  These bits describe exactly where the caller has
+   placed the function's arguments and where it expects to find a return
+   value.
+
+   Both ELF and SOM encode this information within the addend field
+   of the call relocation.  (Note this could break very badly if one
+   was to make a call like bl foo + 0x12345678).
+
+   The high order 10 bits contain parameter relocation information,
+   the low order 22 bits contain the constant offset.  */
+
+#define HPPA_R_ARG_RELOC(a)	\
+  (((a) >> 22) & 0x3ff)
+#define HPPA_R_CONSTANT(a)	\
+  ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22))
+#define HPPA_R_ADDEND(r, c)	\
+  (((r) << 22) + ((c) & 0x3fffff))
+
+
+/* Some functions to manipulate PA instructions.  */
+
+/* Declare the functions with the unused attribute to avoid warnings.  */
+static inline int sign_extend (int, int) ATTRIBUTE_UNUSED;
+static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED;
+static inline int sign_unext (int, int) ATTRIBUTE_UNUSED;
+static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED;
+static inline bfd_signed_vma hppa_field_adjust
+  (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt)
+  ATTRIBUTE_UNUSED;
+static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED;
+
+
+/* The *sign_extend functions are used to assemble various bitfields
+   taken from an instruction and return the resulting immediate
+   value.  */
+
+static inline int
+sign_extend (int x, int len)
+{
+  int signbit = (1 << (len - 1));
+  int mask = (signbit << 1) - 1;
+  return ((x & mask) ^ signbit) - signbit;
+}
+
+static inline int
+low_sign_extend (int x, int len)
+{
+  return (x >> 1) - ((x & 1) << (len - 1));
+}
+
+
+/* The re_assemble_* functions prepare an immediate value for
+   insertion into an opcode. pa-risc uses all sorts of weird bitfields
+   in the instruction to hold the value.  */
+
+static inline int
+sign_unext (int x, int len)
+{
+  int len_ones;
+
+  len_ones = (1 << len) - 1;
+
+  return x & len_ones;
+}
+
+static inline int
+low_sign_unext (int x, int len)
+{
+  int temp;
+  int sign;
+
+  sign = (x >> (len-1)) & 1;
+
+  temp = sign_unext (x, len-1);
+
+  return (temp << 1) | sign;
+}
+
+static inline int
+re_assemble_3 (int as3)
+{
+  return ((  (as3 & 4) << (13-2))
+	  | ((as3 & 3) << (13+1)));
+}
+
+static inline int
+re_assemble_12 (int as12)
+{
+  return ((  (as12 & 0x800) >> 11)
+	  | ((as12 & 0x400) >> (10 - 2))
+	  | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_14 (int as14)
+{
+  return ((  (as14 & 0x1fff) << 1)
+	  | ((as14 & 0x2000) >> 13));
+}
+
+static inline int
+re_assemble_16 (int as16)
+{
+  int s, t;
+
+  /* Unusual 16-bit encoding, for wide mode only.  */
+  t = (as16 << 1) & 0xffff;
+  s = (as16 & 0x8000);
+  return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+static inline int
+re_assemble_17 (int as17)
+{
+  return ((  (as17 & 0x10000) >> 16)
+	  | ((as17 & 0x0f800) << (16 - 11))
+	  | ((as17 & 0x00400) >> (10 - 2))
+	  | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_21 (int as21)
+{
+  return ((  (as21 & 0x100000) >> 20)
+	  | ((as21 & 0x0ffe00) >> 8)
+	  | ((as21 & 0x000180) << 7)
+	  | ((as21 & 0x00007c) << 14)
+	  | ((as21 & 0x000003) << 12));
+}
+
+static inline int
+re_assemble_22 (int as22)
+{
+  return ((  (as22 & 0x200000) >> 21)
+	  | ((as22 & 0x1f0000) << (21 - 16))
+	  | ((as22 & 0x00f800) << (16 - 11))
+	  | ((as22 & 0x000400) >> (10 - 2))
+	  | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+
+/* Handle field selectors for PA instructions.
+   The L and R (and LS, RS etc.) selectors are used in pairs to form a
+   full 32 bit address.  eg.
+
+   LDIL	L'start,%r1		; put left part into r1
+   LDW	R'start(%r1),%r2	; add r1 and right part to form address
+
+   This function returns sign extended values in all cases.
+*/
+
+static inline bfd_signed_vma
+hppa_field_adjust (bfd_vma sym_val,
+		   bfd_signed_vma addend,
+		   enum hppa_reloc_field_selector_type_alt r_field)
+{
+  bfd_signed_vma value;
+
+  value = sym_val + addend;
+  switch (r_field)
+    {
+    case e_fsel:
+      /* F: No change.  */
+      break;
+
+    case e_nsel:
+      /* N: null selector.  I don't really understand what this is all
+	 about, but HP's documentation says "this indicates that zero
+	 bits are to be used for the displacement on the instruction.
+	 This fixup is used to identify three-instruction sequences to
+	 access data (for importing shared library data)."  */
+      value = 0;
+      break;
+
+    case e_lsel:
+    case e_nlsel:
+      /* L:  Select top 21 bits.  */
+      value = value >> 11;
+      break;
+
+    case e_rsel:
+      /* R:  Select bottom 11 bits.  */
+      value = value & 0x7ff;
+      break;
+
+    case e_lssel:
+      /* LS:  Round to nearest multiple of 2048 then select top 21 bits.  */
+      value = value + 0x400;
+      value = value >> 11;
+      break;
+
+    case e_rssel:
+      /* RS:  Select bottom 11 bits for LS.
+	 We need to return a value such that 2048 * LS'x + RS'x == x.
+	 ie. RS'x = x - ((x + 0x400) & -0x800)
+	 this is just a sign extension from bit 21.  */
+      value = ((value & 0x7ff) ^ 0x400) - 0x400;
+      break;
+
+    case e_ldsel:
+      /* LD:  Round to next multiple of 2048 then select top 21 bits.
+	 Yes, if we are already on a multiple of 2048, we go up to the
+	 next one.  RD in this case will be -2048.  */
+      value = value + 0x800;
+      value = value >> 11;
+      break;
+
+    case e_rdsel:
+      /* RD:  Set bits 0-20 to one.  */
+      value = value | -0x800;
+      break;
+
+    case e_lrsel:
+    case e_nlrsel:
+      /* LR:  L with rounding of the addend to nearest 8k.  */
+      value = sym_val + ((addend + 0x1000) & -0x2000);
+      value = value >> 11;
+      break;
+
+    case e_rrsel:
+      /* RR:  R with rounding of the addend to nearest 8k.
+	 We need to return a value such that 2048 * LR'x + RR'x == x
+	 ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800))
+	 .	  = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000))
+	 .	  = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000)  */
+      value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000);
+      break;
+
+    default:
+      abort ();
+    }
+  return value;
+}
+
+/* PA-RISC OPCODES */
+#define get_opcode(insn)	(((insn) >> 26) & 0x3f)
+
+enum hppa_opcode_type
+{
+  /* None of the opcodes in the first group generate relocs, so we
+     aren't too concerned about them.  */
+  OP_SYSOP   = 0x00,
+  OP_MEMMNG  = 0x01,
+  OP_ALU     = 0x02,
+  OP_NDXMEM  = 0x03,
+  OP_SPOP    = 0x04,
+  OP_DIAG    = 0x05,
+  OP_FMPYADD = 0x06,
+  OP_UNDEF07 = 0x07,
+  OP_COPRW   = 0x09,
+  OP_COPRDW  = 0x0b,
+  OP_COPR    = 0x0c,
+  OP_FLOAT   = 0x0e,
+  OP_PRDSPEC = 0x0f,
+  OP_UNDEF15 = 0x15,
+  OP_UNDEF1d = 0x1d,
+  OP_FMPYSUB = 0x26,
+  OP_FPFUSED = 0x2e,
+  OP_SHEXDP0 = 0x34,
+  OP_SHEXDP1 = 0x35,
+  OP_SHEXDP2 = 0x36,
+  OP_UNDEF37 = 0x37,
+  OP_SHEXDP3 = 0x3c,
+  OP_SHEXDP4 = 0x3d,
+  OP_MULTMED = 0x3e,
+  OP_UNDEF3f = 0x3f,
+
+  OP_LDIL    = 0x08,
+  OP_ADDIL   = 0x0a,
+
+  OP_LDO     = 0x0d,
+  OP_LDB     = 0x10,
+  OP_LDH     = 0x11,
+  OP_LDW     = 0x12,
+  OP_LDWM    = 0x13,
+  OP_STB     = 0x18,
+  OP_STH     = 0x19,
+  OP_STW     = 0x1a,
+  OP_STWM    = 0x1b,
+
+  OP_LDD     = 0x14,
+  OP_STD     = 0x1c,
+
+  OP_FLDW    = 0x16,
+  OP_LDWL    = 0x17,
+  OP_FSTW    = 0x1e,
+  OP_STWL    = 0x1f,
+
+  OP_COMBT   = 0x20,
+  OP_COMIBT  = 0x21,
+  OP_COMBF   = 0x22,
+  OP_COMIBF  = 0x23,
+  OP_CMPBDT  = 0x27,
+  OP_ADDBT   = 0x28,
+  OP_ADDIBT  = 0x29,
+  OP_ADDBF   = 0x2a,
+  OP_ADDIBF  = 0x2b,
+  OP_CMPBDF  = 0x2f,
+  OP_BVB     = 0x30,
+  OP_BB      = 0x31,
+  OP_MOVB    = 0x32,
+  OP_MOVIB   = 0x33,
+  OP_CMPIBD  = 0x3b,
+
+  OP_COMICLR = 0x24,
+  OP_SUBI    = 0x25,
+  OP_ADDIT   = 0x2c,
+  OP_ADDI    = 0x2d,
+
+  OP_BE      = 0x38,
+  OP_BLE     = 0x39,
+  OP_BL      = 0x3a
+};
+
+
+/* Insert VALUE into INSN using R_FORMAT to determine exactly what
+   bits to change.  */
+
+static inline int
+hppa_rebuild_insn (int insn, int value, int r_format)
+{
+  switch (r_format)
+    {
+    case 11:
+      return (insn & ~ 0x7ff) | low_sign_unext (value, 11);
+
+    case 12:
+      return (insn & ~ 0x1ffd) | re_assemble_12 (value);
+
+
+    case 10:
+      return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8);
+
+    case -11:
+      return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4);
+
+    case 14:
+      return (insn & ~ 0x3fff) | re_assemble_14 (value);
+
+
+    case -10:
+      return (insn & ~ 0xfff1) | re_assemble_16 (value & -8);
+
+    case -16:
+      return (insn & ~ 0xfff9) | re_assemble_16 (value & -4);
+
+    case 16:
+      return (insn & ~ 0xffff) | re_assemble_16 (value);
+
+
+    case 17:
+      return (insn & ~ 0x1f1ffd) | re_assemble_17 (value);
+
+    case 21:
+      return (insn & ~ 0x1fffff) | re_assemble_21 (value);
+
+    case 22:
+      return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value);
+
+    case 32:
+      return value;
+
+    default:
+      abort ();
+    }
+  return insn;
+}
+
+#endif /* _LIBHPPA_H */
+/* Table of opcodes for the PA-RISC.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs at cs.utah.edu).
+
+This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler.
+
+GAS/GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS/GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS or GDB; see the file COPYING.
+If not, see <http://www.gnu.org/licenses/>. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ * Structure of an opcode table entry.
+ */
+
+/* There are two kinds of delay slot nullification: normal which is
+ * controled by the nullification bit, and conditional, which depends
+ * on the direction of the branch and its success or failure.
+ *
+ * NONE is unfortunately #defined in the hiux system include files.
+ * #undef it away.
+ */
+#undef NONE
+struct pa_opcode
+{
+    const char *name;
+    unsigned long int match;	/* Bits that must be set...  */
+    unsigned long int mask;	/* ... in these bits. */
+    const char *args;
+    enum pa_arch arch;
+    char flags;
+};
+
+/* Enables strict matching.  Opcodes with match errors are skipped
+   when this bit is set.  */
+#define FLAG_STRICT 0x1
+
+/*
+   All hppa opcodes are 32 bits.
+
+   The match component is a mask saying which bits must match a
+   particular opcode in order for an instruction to be an instance
+   of that opcode.
+
+   The args component is a string containing one character for each operand of
+   the instruction.  Characters used as a prefix allow any second character to
+   be used without conflicting with the main operand characters.
+
+   Bit positions in this description follow HP usage of lsb = 31,
+   "at" is lsb of field.
+
+   In the args field, the following characters must match exactly:
+
+	'+,() '
+
+   In the args field, the following characters are unused:
+
+	'  "         -  /   34 6789:;    '
+	'@  C         M             [\]  '
+	'`    e g                     }  '
+
+   Here are all the characters:
+
+	' !"#$%&'()*+-,./0123456789:;<=>?'
+	'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'
+	'`abcdefghijklmnopqrstuvwxyz{|}~ '
+
+Kinds of operands:
+   x    integer register field at 15.
+   b    integer register field at 10.
+   t    integer register field at 31.
+   a	integer register field at 10 and 15 (for PERMH)
+   5    5 bit immediate at 15.
+   s    2 bit space specifier at 17.
+   S    3 bit space specifier at 18.
+   V    5 bit immediate value at 31
+   i    11 bit immediate value at 31
+   j    14 bit immediate value at 31
+   k    21 bit immediate value at 31
+   l    16 bit immediate value at 31 (wide mode only, unusual encoding).
+   n	nullification for branch instructions
+   N	nullification for spop and copr instructions
+   w    12 bit branch displacement
+   W    17 bit branch displacement (PC relative)
+   X    22 bit branch displacement (PC relative)
+   z    17 bit branch displacement (just a number, not an address)
+
+Also these:
+
+   .    2 bit shift amount at 25
+   *    4 bit shift amount at 25
+   p    5 bit shift count at 26 (to support the SHD instruction) encoded as
+        31-p
+   ~    6 bit shift count at 20,22:26 encoded as 63-~.
+   P    5 bit bit position at 26
+   q    6 bit bit position at 20,22:26
+   T    5 bit field length at 31 (encoded as 32-T)
+   %	6 bit field length at 23,27:31 (variable extract/deposit)
+   |	6 bit field length at 19,27:31 (fixed extract/deposit)
+   A    13 bit immediate at 18 (to support the BREAK instruction)
+   ^	like b, but describes a control register
+   !    sar (cr11) register
+   D    26 bit immediate at 31 (to support the DIAG instruction)
+   $    9 bit immediate at 28 (to support POPBTS)
+
+   v    3 bit Special Function Unit identifier at 25
+   O    20 bit Special Function Unit operation split between 15 bits at 20
+        and 5 bits at 31
+   o    15 bit Special Function Unit operation at 20
+   2    22 bit Special Function Unit operation split between 17 bits at 20
+        and 5 bits at 31
+   1    15 bit Special Function Unit operation split between 10 bits at 20
+        and 5 bits at 31
+   0    10 bit Special Function Unit operation split between 5 bits at 20
+        and 5 bits at 31
+   u    3 bit coprocessor unit identifier at 25
+   F    Source Floating Point Operand Format Completer encoded 2 bits at 20
+   I    Source Floating Point Operand Format Completer encoded 1 bits at 20
+	(for 0xe format FP instructions)
+   G    Destination Floating Point Operand Format Completer encoded 2 bits at 18
+   H    Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub'
+        (very similar to 'F')
+
+   r	5 bit immediate value at 31 (for the break instruction)
+	(very similar to V above, except the value is unsigned instead of
+	low_sign_ext)
+   R	5 bit immediate value at 15 (for the ssm, rsm, probei instructions)
+	(same as r above, except the value is in a different location)
+   U	10 bit immediate value at 15 (for SSM, RSM on pa2.0)
+   Q	5 bit immediate value at 10 (a bit position specified in
+	the bb instruction. It's the same as r above, except the
+        value is in a different location)
+   B	5 bit immediate value at 10 (a bit position specified in
+	the bb instruction. Similar to Q, but 64 bit handling is
+	different.
+   Z    %r1 -- implicit target of addil instruction.
+   L    ,%r2 completer for new syntax branch
+   {    Source format completer for fcnv
+   _    Destination format completer for fcnv
+   h    cbit for fcmp
+   =    gfx tests for ftest
+   d    14 bit offset for single precision FP long load/store.
+   #    14 bit offset for double precision FP load long/store.
+   J    Yet another 14 bit offset for load/store with ma,mb completers.
+   K    Yet another 14 bit offset for load/store with ma,mb completers.
+   y    16 bit offset for word aligned load/store (PA2.0 wide).
+   &    16 bit offset for dword aligned load/store (PA2.0 wide).
+   <    16 bit offset for load/store with ma,mb completers (PA2.0 wide).
+   >    16 bit offset for load/store with ma,mb completers (PA2.0 wide).
+   Y    %sr0,%r31 -- implicit target of be,l instruction.
+   @	implicit immediate value of 0
+
+Completer operands all have 'c' as the prefix:
+
+   cx   indexed load and store completer.
+   cX   indexed load and store completer.  Like cx, but emits a space
+	after in disassembler.
+   cm   short load and store completer.
+   cM   short load and store completer.  Like cm, but emits a space
+        after in disassembler.
+   cq   long load and store completer (like cm, but inserted into a
+	different location in the target instruction).
+   cs   store bytes short completer.
+   cA   store bytes short completer.  Like cs, but emits a space
+        after in disassembler.
+   ce   long load/store completer for LDW/STW with a different encoding
+	than the others
+   cc   load cache control hint
+   cd   load and clear cache control hint
+   cC   store cache control hint
+   co	ordered access
+
+   cp	branch link and push completer
+   cP	branch pop completer
+   cl	branch link completer
+   cg	branch gate completer
+
+   cw	read/write completer for PROBE
+   cW	wide completer for MFCTL
+   cL	local processor completer for cache control
+   cZ   System Control Completer (to support LPA, LHA, etc.)
+
+   ci	correction completer for DCOR
+   ca	add completer
+   cy	32 bit add carry completer
+   cY	64 bit add carry completer
+   cv	signed overflow trap completer
+   ct	trap on condition completer for ADDI, SUB
+   cT	trap on condition completer for UADDCM
+   cb	32 bit borrow completer for SUB
+   cB	64 bit borrow completer for SUB
+
+   ch	left/right half completer
+   cH	signed/unsigned saturation completer
+   cS	signed/unsigned completer at 21
+   cz	zero/sign extension completer.
+   c*	permutation completer
+
+Condition operands all have '?' as the prefix:
+
+   ?f   Floating point compare conditions (encoded as 5 bits at 31)
+
+   ?a	add conditions
+   ?A	64 bit add conditions
+   ?@   add branch conditions followed by nullify
+   ?d	non-negated add branch conditions
+   ?D	negated add branch conditions
+   ?w	wide mode non-negated add branch conditions
+   ?W	wide mode negated add branch conditions
+
+   ?s   compare/subtract conditions
+   ?S	64 bit compare/subtract conditions
+   ?t   non-negated compare and branch conditions
+   ?n   32 bit compare and branch conditions followed by nullify
+   ?N   64 bit compare and branch conditions followed by nullify
+   ?Q	64 bit compare and branch conditions for CMPIB instruction
+
+   ?l   logical conditions
+   ?L	64 bit logical conditions
+
+   ?b   branch on bit conditions
+   ?B	64 bit branch on bit conditions
+
+   ?x   shift/extract/deposit conditions
+   ?X	64 bit shift/extract/deposit conditions
+   ?y   shift/extract/deposit conditions followed by nullify for conditional
+        branches
+
+   ?u   unit conditions
+   ?U   64 bit unit conditions
+
+Floating point registers all have 'f' as a prefix:
+
+   ft	target register at 31
+   fT	target register with L/R halves at 31
+   fa	operand 1 register at 10
+   fA   operand 1 register with L/R halves at 10
+   fX   Same as fA, except prints a space before register during disasm
+   fb	operand 2 register at 15
+   fB   operand 2 register with L/R halves at 15
+   fC   operand 3 register with L/R halves at 16:18,21:23
+   fe   Like fT, but encoding is different.
+   fE   Same as fe, except prints a space before register during disasm.
+   fx	target register at 15 (only for PA 2.0 long format FLDD/FSTD).
+
+Float registers for fmpyadd and fmpysub:
+
+   fi	mult operand 1 register at 10
+   fj	mult operand 2 register at 15
+   fk	mult target register at 20
+   fl	add/sub operand register at 25
+   fm	add/sub target register at 31
+
+*/
+
+
+#if 0
+/* List of characters not to put a space after.  Note that
+   "," is included, as the "spopN" operations use literal
+   commas in their completer sections.  */
+static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}";
+#endif
+
+/* The order of the opcodes in this table is significant:
+
+   * The assembler requires that all instances of the same mnemonic be
+     consecutive.  If they aren't, the assembler will bomb at runtime.
+
+   * Immediate fields use pa_get_absolute_expression to parse the
+     string.  It will generate a "bad expression" error if passed
+     a register name.  Thus, register index variants of an opcode
+     need to precede immediate variants.
+
+   * The disassembler does not care about the order of the opcodes
+     except in cases where implicit addressing is used.
+
+   Here are the rules for ordering the opcodes of a mnemonic:
+
+   1) Opcodes with FLAG_STRICT should precede opcodes without
+      FLAG_STRICT.
+
+   2) Opcodes with FLAG_STRICT should be ordered as follows:
+      register index opcodes, short immediate opcodes, and finally
+      long immediate opcodes.  When both pa10 and pa11 variants
+      of the same opcode are available, the pa10 opcode should
+      come first for correct architectural promotion.
+
+   3) When implicit addressing is available for an opcode, the
+      implicit opcode should precede the explicit opcode.
+
+   4) Opcodes without FLAG_STRICT should be ordered as follows:
+      register index opcodes, long immediate opcodes, and finally
+      short immediate opcodes.  */
+
+static const struct pa_opcode pa_opcodes[] =
+{
+
+/* Pseudo-instructions.  */
+
+{ "ldi",	0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */
+{ "ldi",	0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */
+
+{ "cmpib",	0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT},
+{ "cmpib", 	0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT},
+{ "comib", 	0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "comib", 	0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/
+{ "cmpb",	0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT},
+{ "cmpb",	0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT},
+{ "comb",	0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "comb",	0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */
+{ "addb",	0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT},
+{ "addb",	0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "addb",	0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0},
+{ "addib",	0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT},
+{ "addib",	0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "addib",	0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/
+{ "nop",	0x08000240, 0xffffffff, "", pa10, 0},      /* or 0,0,0 */
+{ "copy",	0x08000240, 0xffe0ffe0, "x,t", pa10, 0},   /* or r,0,t */
+{ "mtsar",	0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */
+
+/* Loads and Stores for integer registers.  */
+
+{ "ldd",	0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldw",	0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT},
+{ "ldw",	0x48000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldw",	0x48000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "ldh",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldh",	0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldh",	0x44000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldh",	0x44000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "ldb",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldb",	0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldb",	0x40000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldb",	0x40000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "std",	0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT},
+{ "stw",	0x68000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stw",	0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "sth",	0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "sth",	0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "sth",	0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "sth",	0x64000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "sth",	0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "stb",	0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stb",	0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stb",	0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "stb",	0x60000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stb",	0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "ldwm",	0x4c000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldwm",	0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "stwm",	0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stwm",	0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "ldwx",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldwx",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldhx",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldhx",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldbx",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldbx",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldwa",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwa",	0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwa",	0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldwa",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldwa",	0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT},
+{ "stwa",	0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stwa",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stwa",	0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT},
+{ "ldda",	0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT},
+{ "ldda",	0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldda",	0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT},
+{ "stda",	0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stda",	0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldcwx",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldcwx",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldws",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldws",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldhs",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldhs",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldbs",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldbs",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldwas",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldwas",	0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldwas",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldcws",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldcws",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "stws",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stws",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "sths",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "sths",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "stbs",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stbs",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "stwas",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stwas",	0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stwas",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stdby",	0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT},
+{ "stdby",	0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0},
+{ "stbys",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0},
+
+/* Immediate instructions.  */
+{ "ldo",	0x34000000, 0xfc000000, "l(b),x", pa20w, 0},
+{ "ldo",	0x34000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldil",	0x20000000, 0xfc000000, "k,b", pa10, 0},
+{ "addil",	0x28000000, 0xfc000000, "k,b,Z", pa10, 0},
+{ "addil",	0x28000000, 0xfc000000, "k,b", pa10, 0},
+
+/* Branching instructions.  */
+{ "b",		0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT},
+{ "b",		0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT},
+{ "b",		0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT},
+{ "b",		0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT},
+{ "b",		0xe8000000, 0xffe0e000, "nW", pa10, 0},  /* b,l foo,r0 */
+{ "bl",		0xe8000000, 0xfc00e000, "nW,b", pa10, 0},
+{ "gate",	0xe8002000, 0xfc00e000, "nW,b", pa10, 0},
+{ "blr",	0xe8004000, 0xfc00e001, "nx,b", pa10, 0},
+{ "bv",		0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0},
+{ "bv",		0xe800c000, 0xfc00fffd, "n(b)", pa10, 0},
+{ "bve",	0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT},
+{ "bve",	0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT},
+{ "bve",	0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT},
+{ "bve",	0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT},
+{ "be",		0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT},
+{ "be",		0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT},
+{ "be",		0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0},
+{ "be",		0xe0000000, 0xfc000000, "nz(b)", pa10, 0},
+{ "ble",	0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0},
+{ "movb",	0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0},
+{ "movib",	0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0},
+{ "combt",	0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0},
+{ "combf",	0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0},
+{ "comibt",	0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0},
+{ "comibf",	0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0},
+{ "addbt",	0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0},
+{ "addbf",	0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0},
+{ "addibt",	0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0},
+{ "addibf",	0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0},
+{ "bb",		0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT},
+{ "bb",		0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT},
+{ "bb",		0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT},
+{ "bb",		0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT},
+{ "bvb",	0xc0004000, 0xffe04000, "?bnx,w", pa10, 0},
+{ "clrbts",	0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT},
+{ "popbts",	0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT},
+{ "pushnom",	0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT},
+{ "pushbts",	0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT},
+
+/* Computation Instructions.  */
+
+{ "cmpclr",	0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT},
+{ "cmpclr",	0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT},
+{ "comclr",	0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "or",		0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "or",		0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "xor",	0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "xor",	0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "and",	0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "and",	0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "andcm",	0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "andcm",	0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "uxor",	0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT},
+{ "uxor",	0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "uaddcm",	0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT},
+{ "uaddcm",	0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT},
+{ "uaddcm",	0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "uaddcmt",	0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "dcor",	0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT},
+{ "dcor",	0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT},
+{ "dcor",	0x08000b80, 0xfc1f0fe0, "?ub,t",   pa10, 0},
+{ "idcor",	0x08000bc0, 0xfc1f0fe0, "?ub,t",   pa10, 0},
+{ "addi",	0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT},
+{ "addi",	0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT},
+{ "addi",	0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addio",	0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addit",	0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addito",	0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "add",	0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT},
+{ "add",	0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT},
+{ "add",	0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT},
+{ "add",	0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT},
+{ "add",	0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addl",	0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addo",	0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addc",	0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addco",	0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sub",	0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subo",	0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subb",	0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subbo",	0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subt",	0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subto",	0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "ds",		0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subi",	0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT},
+{ "subi",	0x94000000, 0xfc000800, "?si,b,x", pa10, 0},
+{ "subio",	0x94000800, 0xfc000800, "?si,b,x", pa10, 0},
+{ "cmpiclr",	0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT},
+{ "cmpiclr",	0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT},
+{ "comiclr",	0x90000000, 0xfc000800, "?si,b,x", pa10, 0},
+{ "shladd",	0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT},
+{ "shladd",	0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT},
+{ "sh1add",	0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh1addl",	0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh1addo",	0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2add",	0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2addl",	0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2addo",	0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3add",	0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3addl",	0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3addo",	0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+
+/* Subword Operation Instructions.  */
+
+{ "hadd",	0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT},
+{ "havg",	0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT},
+{ "hshl",	0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT},
+{ "hshladd",	0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT},
+{ "hshr",	0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT},
+{ "hshradd",	0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT},
+{ "hsub",	0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT},
+{ "mixh",	0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT},
+{ "mixw",	0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT},
+{ "permh",	0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT},
+
+
+/* Extract and Deposit Instructions.  */
+
+{ "shrpd",	0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT},
+{ "shrpd",	0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT},
+{ "shrpw",	0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT},
+{ "shrpw",	0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT},
+{ "vshd",	0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0},
+{ "shd",	0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0},
+{ "extrd",	0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT},
+{ "extrd",	0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT},
+{ "extrw",	0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT},
+{ "extrw",	0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT},
+{ "vextru",	0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0},
+{ "vextrs",	0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0},
+{ "extru",	0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0},
+{ "extrs",	0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0},
+{ "depd",	0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT},
+{ "depd",	0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT},
+{ "depdi",	0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT},
+{ "depdi",	0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT},
+{ "depw",	0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT},
+{ "depw",	0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT},
+{ "depwi",	0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT},
+{ "depwi",	0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT},
+{ "zvdep",	0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0},
+{ "vdep",	0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0},
+{ "zdep",	0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0},
+{ "dep",	0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0},
+{ "zvdepi",	0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0},
+{ "vdepi",	0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0},
+{ "zdepi",	0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0},
+{ "depi",	0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0},
+
+/* System Control Instructions.  */
+
+{ "break",	0x00000000, 0xfc001fe0, "r,A", pa10, 0},
+{ "rfi",	0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT},
+{ "rfi",	0x00000c00, 0xffffffff, "", pa10, 0},
+{ "rfir",	0x00000ca0, 0xffffffff, "", pa11, 0},
+{ "ssm",	0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT},
+{ "ssm",	0x00000d60, 0xffe0ffe0, "R,t", pa10, 0},
+{ "rsm",	0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT},
+{ "rsm",	0x00000e60, 0xffe0ffe0, "R,t", pa10, 0},
+{ "mtsm",	0x00001860, 0xffe0ffff, "x", pa10, 0},
+{ "ldsid",	0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0},
+{ "ldsid",	0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0},
+{ "mtsp",	0x00001820, 0xffe01fff, "x,S", pa10, 0},
+{ "mtctl",	0x00001840, 0xfc00ffff, "x,^", pa10, 0},
+{ "mtsarcm",	0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT},
+{ "mfia",	0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT},
+{ "mfsp",	0x000004a0, 0xffff1fe0, "S,t", pa10, 0},
+{ "mfctl",	0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT},
+{ "mfctl",	0x000008a0, 0xfc1fffe0, "^,t", pa10, 0},
+{ "sync",	0x00000400, 0xffffffff, "", pa10, 0},
+{ "syncdma",	0x00100400, 0xffffffff, "", pa10, 0},
+{ "probe",	0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT},
+{ "probe",	0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT},
+{ "probei",	0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT},
+{ "probei",	0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT},
+{ "prober",	0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0},
+{ "prober",	0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0},
+{ "proberi",	0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0},
+{ "proberi",	0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0},
+{ "probew",	0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0},
+{ "probew",	0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0},
+{ "probewi",	0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0},
+{ "probewi",	0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0},
+{ "lpa",	0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0},
+{ "lpa",	0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0},
+{ "lci",	0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0},
+{ "lci",	0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0},
+{ "pdtlb",	0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdtlb",	0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "pitlb",	0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT},
+{ "pitlb",	0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT},
+{ "pitlb",	0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "pdtlbe",	0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdtlbe",	0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "pitlbe",	0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "idtlba",	0x04001040, 0xfc00ffff, "x,(b)", pa10, 0},
+{ "idtlba",	0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0},
+{ "iitlba",	0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0},
+{ "idtlbp",	0x04001000, 0xfc00ffff, "x,(b)", pa10, 0},
+{ "idtlbp",	0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0},
+{ "iitlbp",	0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0},
+{ "pdc",	0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdc",	0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fdc",	0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT},
+{ "fdc",	0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT},
+{ "fdc",	0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT},
+{ "fdc",	0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT},
+{ "fdc",	0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "fdc",	0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fic",	0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT},
+{ "fic",	0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "fdce",	0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "fdce",	0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fice",	0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "diag",	0x14000000, 0xfc000000, "D", pa10, 0},
+{ "idtlbt",	0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT},
+{ "iitlbt",	0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT},
+
+/* These may be specific to certain versions of the PA.  Joel claimed
+   they were 72000 (7200?) specific.  However, I'm almost certain the
+   mtcpu/mfcpu were undocumented, but available in the older 700 machines.  */
+{ "mtcpu",	0x14001600, 0xfc00ffff, "x,^", pa10, 0},
+{ "mfcpu",	0x14001A00, 0xfc00ffff, "^,x", pa10, 0},
+{ "tocen",	0x14403600, 0xffffffff, "", pa10, 0},
+{ "tocdis",	0x14401620, 0xffffffff, "", pa10, 0},
+{ "shdwgr",	0x14402600, 0xffffffff, "", pa10, 0},
+{ "grshdw",	0x14400620, 0xffffffff, "", pa10, 0},
+
+/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either
+   the Timex FPU or the Mustang ERS (not sure which) manual.  */
+{ "gfw",	0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0},
+{ "gfw",	0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0},
+{ "gfr",	0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0},
+{ "gfr",	0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0},
+
+/* Floating Point Coprocessor Instructions.  */
+
+{ "fldw",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT},
+{ "fldw",	0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT},
+{ "fldd",	0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT},
+{ "fstw",	0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0},
+{ "fldwx",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0},
+{ "flddx",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0},
+{ "flddx",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0},
+{ "fstwx",	0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0},
+{ "fstwx",	0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0},
+{ "fstdx",	0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0},
+{ "fstdx",	0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0},
+{ "fstqx",	0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0},
+{ "fstqx",	0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0},
+{ "fldws",	0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0},
+{ "fldws",	0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0},
+{ "fldds",	0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0},
+{ "fldds",	0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0},
+{ "fstws",	0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0},
+{ "fstws",	0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0},
+{ "fstds",	0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0},
+{ "fstds",	0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0},
+{ "fstqs",	0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0},
+{ "fstqs",	0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0},
+{ "fadd",	0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fadd",	0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fsub",	0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fsub",	0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fmpy",	0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fmpy",	0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fdiv",	0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fdiv",	0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fsqrt",	0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fsqrt",	0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fabs",	0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fabs",	0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "frem",	0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "frem",	0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0},
+{ "frnd",	0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "frnd",	0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fcpy",	0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fcpy",	0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fcnvff",	0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvff",	0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvxf",	0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvxf",	0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvfx",	0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvfx",	0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvfxt",	0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvfxt",	0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fmpyfadd",	0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT},
+{ "fmpynfadd",	0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT},
+{ "fneg",	0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT},
+{ "fneg",	0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT},
+{ "fnegabs",	0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT},
+{ "fnegabs",	0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT},
+{ "fcnv",	0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT},
+{ "fcnv",	0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT},
+{ "fcmp",	0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT},
+{ "fcmp",	0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0},
+{ "fcmp",	0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0},
+{ "xmpyu",	0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0},
+{ "fmpyadd",	0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0},
+{ "fmpysub",	0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0},
+{ "ftest",	0x30002420, 0xffffffff, "", pa10, FLAG_STRICT},
+{ "ftest",	0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT},
+{ "ftest",	0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT},
+{ "fid",	0x30000000, 0xffffffff, "", pa11, 0},
+
+/* Performance Monitor Instructions.  */
+
+{ "pmdis",	0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT},
+{ "pmenb",	0x30000680, 0xffffffff, "", pa20, FLAG_STRICT},
+
+/* Assist Instructions.  */
+
+{ "spop0",	0x10000000, 0xfc000600, "v,ON", pa10, 0},
+{ "spop1",	0x10000200, 0xfc000600, "v,oNt", pa10, 0},
+{ "spop2",	0x10000400, 0xfc000600, "v,1Nb", pa10, 0},
+{ "spop3",	0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0},
+{ "copr",	0x30000000, 0xfc000000, "u,2N", pa10, 0},
+{ "cldw",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0},
+{ "cldwx",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0},
+{ "clddx",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0},
+{ "clddx",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0},
+{ "cstwx",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0},
+{ "cstwx",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0},
+{ "cstdx",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0},
+{ "cstdx",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0},
+{ "cldws",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0},
+{ "cldws",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0},
+{ "cldds",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0},
+{ "cldds",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0},
+{ "cstws",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0},
+{ "cstws",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0},
+{ "cstds",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0},
+{ "cstds",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0},
+
+/* More pseudo instructions which must follow the main table.  */
+{ "call",	0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT},
+{ "call",	0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT},
+{ "ret",	0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT},
+
+};
+
+#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0]))
+
+/* SKV 12/18/92. Added some denotations for various operands.  */
+
+#define PA_IMM11_AT_31 'i'
+#define PA_IMM14_AT_31 'j'
+#define PA_IMM21_AT_31 'k'
+#define PA_DISP12 'w'
+#define PA_DISP17 'W'
+
+#define N_HPPA_OPERAND_FORMATS 5
+
+/* Integer register names, indexed by the numbers which appear in the
+   opcodes.  */
+static const char *const reg_names[] =
+{
+  "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+  "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+  "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1",
+  "sp", "r31"
+};
+
+/* Floating point register names, indexed by the numbers which appear in the
+   opcodes.  */
+static const char *const fp_reg_names[] =
+{
+  "fpsr", "fpe2", "fpe4", "fpe6",
+  "fr4", "fr5", "fr6", "fr7", "fr8",
+  "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+  "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
+  "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31"
+};
+
+typedef unsigned int CORE_ADDR;
+
+/* Get at various relevant fields of an instruction word.  */
+
+#define MASK_5  0x1f
+#define MASK_10 0x3ff
+#define MASK_11 0x7ff
+#define MASK_14 0x3fff
+#define MASK_16 0xffff
+#define MASK_21 0x1fffff
+
+/* These macros get bit fields using HP's numbering (MSB = 0).  */
+
+#define GET_FIELD(X, FROM, TO) \
+  ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
+
+#define GET_BIT(X, WHICH) \
+  GET_FIELD (X, WHICH, WHICH)
+
+/* Some of these have been converted to 2-d arrays because they
+   consume less storage this way.  If the maintenance becomes a
+   problem, convert them back to const 1-d pointer arrays.  */
+static const char *const control_reg[] =
+{
+  "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
+  "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4",
+  "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr",
+  "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3",
+  "tr4", "tr5", "tr6", "tr7"
+};
+
+static const char *const compare_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od",
+  ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev"
+};
+static const char *const compare_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev"
+};
+static const char *const cmpib_cond_64_names[] =
+{
+  ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>"
+};
+static const char *const add_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od",
+  ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev"
+};
+static const char *const add_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev"
+};
+static const char *const wide_add_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=",
+  ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>"
+};
+static const char *const logical_cond_names[] =
+{
+  "", ",=", ",<", ",<=", 0, 0, 0, ",od",
+  ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"};
+static const char *const logical_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"};
+static const char *const unit_cond_names[] =
+{
+  "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc",
+  ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc"
+};
+static const char *const unit_cond_64_names[] =
+{
+  "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc",
+  ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc"
+};
+static const char *const shift_cond_names[] =
+{
+  "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"
+};
+static const char *const shift_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev"
+};
+static const char *const bb_cond_64_names[] =
+{
+  ",*<", ",*>="
+};
+static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"};
+static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
+static const char *const short_bytes_compl_names[] =
+{
+  "", ",b,m", ",e", ",e,m"
+};
+static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"};
+static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"};
+static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"};
+static const char *const float_comp_names[] =
+{
+  ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
+  ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
+  ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
+  ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
+};
+static const char *const signed_unsigned_names[] = {",u", ",s"};
+static const char *const mix_half_names[] = {",l", ",r"};
+static const char *const saturation_names[] = {",us", ",ss", 0, ""};
+static const char *const read_write_names[] = {",r", ",w"};
+static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" };
+
+/* For a bunch of different instructions form an index into a
+   completer name table.  */
+#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \
+			 GET_FIELD (insn, 18, 18) << 1)
+
+#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
+			(GET_FIELD ((insn), 19, 19) ? 8 : 0))
+
+/* Utility function to print registers.  Put these first, so gcc's function
+   inlining can do its stuff.  */
+
+#define fputs_filtered(STR,F)	(*info->fprintf_func) (info->stream, "%s", STR)
+
+static void
+fput_reg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0");
+}
+
+static void
+fput_fp_reg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0");
+}
+
+static void
+fput_fp_reg_r (unsigned reg, disassemble_info *info)
+{
+  /* Special case floating point exception registers.  */
+  if (reg < 4)
+    (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1);
+  else
+    (*info->fprintf_func) (info->stream, "%sR",
+			   reg ? fp_reg_names[reg] : "fr0");
+}
+
+static void
+fput_creg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", control_reg[reg]);
+}
+
+/* Print constants with sign.  */
+
+static void
+fput_const (unsigned num, disassemble_info *info)
+{
+  if ((int) num < 0)
+    (*info->fprintf_func) (info->stream, "-%x", - (int) num);
+  else
+    (*info->fprintf_func) (info->stream, "%x", num);
+}
+
+/* Routines to extract various sized constants out of hppa
+   instructions.  */
+
+/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp.  */
+static int
+extract_3 (unsigned word)
+{
+  return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
+}
+
+static int
+extract_5_load (unsigned word)
+{
+  return low_sign_extend (word >> 16 & MASK_5, 5);
+}
+
+/* Extract the immediate field from a st{bhw}s instruction.  */
+
+static int
+extract_5_store (unsigned word)
+{
+  return low_sign_extend (word & MASK_5, 5);
+}
+
+/* Extract the immediate field from a break instruction.  */
+
+static unsigned
+extract_5r_store (unsigned word)
+{
+  return (word & MASK_5);
+}
+
+/* Extract the immediate field from a {sr}sm instruction.  */
+
+static unsigned
+extract_5R_store (unsigned word)
+{
+  return (word >> 16 & MASK_5);
+}
+
+/* Extract the 10 bit immediate field from a {sr}sm instruction.  */
+
+static unsigned
+extract_10U_store (unsigned word)
+{
+  return (word >> 16 & MASK_10);
+}
+
+/* Extract the immediate field from a bb instruction.  */
+
+static unsigned
+extract_5Q_store (unsigned word)
+{
+  return (word >> 21 & MASK_5);
+}
+
+/* Extract an 11 bit immediate field.  */
+
+static int
+extract_11 (unsigned word)
+{
+  return low_sign_extend (word & MASK_11, 11);
+}
+
+/* Extract a 14 bit immediate field.  */
+
+static int
+extract_14 (unsigned word)
+{
+  return low_sign_extend (word & MASK_14, 14);
+}
+
+/* Extract a 16 bit immediate field (PA2.0 wide only).  */
+
+static int
+extract_16 (unsigned word)
+{
+  int m15, m0, m1;
+
+  m0 = GET_BIT (word, 16);
+  m1 = GET_BIT (word, 17);
+  m15 = GET_BIT (word, 31);
+  word = (word >> 1) & 0x1fff;
+  word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13);
+  return sign_extend (word, 16);
+}
+
+/* Extract a 21 bit constant.  */
+
+static int
+extract_21 (unsigned word)
+{
+  int val;
+
+  word &= MASK_21;
+  word <<= 11;
+  val = GET_FIELD (word, 20, 20);
+  val <<= 11;
+  val |= GET_FIELD (word, 9, 19);
+  val <<= 2;
+  val |= GET_FIELD (word, 5, 6);
+  val <<= 5;
+  val |= GET_FIELD (word, 0, 4);
+  val <<= 2;
+  val |= GET_FIELD (word, 7, 8);
+  return sign_extend (val, 21) << 11;
+}
+
+/* Extract a 12 bit constant from branch instructions.  */
+
+static int
+extract_12 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | (word & 0x1) << 11, 12) << 2;
+}
+
+/* Extract a 17 bit constant from branch instructions, returning the
+   19 bit signed value.  */
+
+static int
+extract_17 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | GET_FIELD (word, 11, 15) << 11
+		      | (word & 0x1) << 16, 17) << 2;
+}
+
+static int
+extract_22 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | GET_FIELD (word, 11, 15) << 11
+		      | GET_FIELD (word, 6, 10) << 16
+		      | (word & 0x1) << 21, 22) << 2;
+}
+
+/* Print one instruction.  */
+
+int
+print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
+{
+  bfd_byte buffer[4];
+  unsigned int insn, i;
+
+  {
+    int status =
+      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
+    if (status != 0)
+      {
+	(*info->memory_error_func) (status, memaddr, info);
+	return -1;
+      }
+  }
+
+  insn = bfd_getb32 (buffer);
+
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      const struct pa_opcode *opcode = &pa_opcodes[i];
+
+      if ((insn & opcode->mask) == opcode->match)
+	{
+	  const char *s;
+#ifndef BFD64
+	  if (opcode->arch == pa20w)
+	    continue;
+#endif
+	  (*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+	  if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0]))
+	    (*info->fprintf_func) (info->stream, " ");
+	  for (s = opcode->args; *s != '\0'; ++s)
+	    {
+	      switch (*s)
+		{
+		case 'x':
+		  fput_reg (GET_FIELD (insn, 11, 15), info);
+		  break;
+		case 'a':
+		case 'b':
+		  fput_reg (GET_FIELD (insn, 6, 10), info);
+		  break;
+		case '^':
+		  fput_creg (GET_FIELD (insn, 6, 10), info);
+		  break;
+		case 't':
+		  fput_reg (GET_FIELD (insn, 27, 31), info);
+		  break;
+
+		  /* Handle floating point registers.  */
+		case 'f':
+		  switch (*++s)
+		    {
+		    case 't':
+		      fput_fp_reg (GET_FIELD (insn, 27, 31), info);
+		      break;
+		    case 'T':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 27, 31), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 27, 31), info);
+		      break;
+		    case 'a':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 6, 10), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 6, 10), info);
+		      break;
+
+		      /* 'fA' will not generate a space before the regsiter
+			 name.  Normally that is fine.  Except that it
+			 causes problems with xmpyu which has no FP format
+			 completer.  */
+		    case 'X':
+		      fputs_filtered (" ", info);
+		      /* FALLTHRU */
+
+		    case 'A':
+		      if (GET_FIELD (insn, 24, 24))
+			fput_fp_reg_r (GET_FIELD (insn, 6, 10), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 6, 10), info);
+		      break;
+		    case 'b':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'B':
+		      if (GET_FIELD (insn, 19, 19))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'C':
+		      {
+			int reg = GET_FIELD (insn, 21, 22);
+			reg |= GET_FIELD (insn, 16, 18) << 2;
+			if (GET_FIELD (insn, 23, 23) != 0)
+			  fput_fp_reg_r (reg, info);
+			else
+			  fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'i':
+		      {
+			int reg = GET_FIELD (insn, 6, 10);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'j':
+		      {
+			int reg = GET_FIELD (insn, 11, 15);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'k':
+		      {
+			int reg = GET_FIELD (insn, 27, 31);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'l':
+		      {
+			int reg = GET_FIELD (insn, 21, 25);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'm':
+		      {
+			int reg = GET_FIELD (insn, 16, 20);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+
+		      /* 'fe' will not generate a space before the register
+			 name.  Normally that is fine.  Except that it
+			 causes problems with fstw fe,y(b) which has no FP
+			 format completer.  */
+		    case 'E':
+		      fputs_filtered (" ", info);
+		      /* FALLTHRU */
+
+		    case 'e':
+		      if (GET_FIELD (insn, 30, 30))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'x':
+		      fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    }
+		  break;
+
+		case '5':
+		  fput_const (extract_5_load (insn), info);
+		  break;
+		case 's':
+		  {
+		    int space = GET_FIELD (insn, 16, 17);
+		    /* Zero means implicit addressing, not use of sr0.  */
+		    if (space != 0)
+		      (*info->fprintf_func) (info->stream, "sr%d", space);
+		  }
+		  break;
+
+		case 'S':
+		  (*info->fprintf_func) (info->stream, "sr%d",
+					 extract_3 (insn));
+		  break;
+
+		  /* Handle completers.  */
+		case 'c':
+		  switch (*++s)
+		    {
+		    case 'x':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 index_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'X':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 index_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'm':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 short_ldst_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'M':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 short_ldst_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'A':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 short_bytes_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 's':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 short_bytes_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'c':
+		    case 'C':
+		      switch (GET_FIELD (insn, 20, 21))
+			{
+			case 1:
+			  (*info->fprintf_func) (info->stream, ",bc ");
+			  break;
+			case 2:
+			  (*info->fprintf_func) (info->stream, ",sl ");
+			  break;
+			default:
+			  (*info->fprintf_func) (info->stream, " ");
+			}
+		      break;
+		    case 'd':
+		      switch (GET_FIELD (insn, 20, 21))
+			{
+			case 1:
+			  (*info->fprintf_func) (info->stream, ",co ");
+			  break;
+			default:
+			  (*info->fprintf_func) (info->stream, " ");
+			}
+		      break;
+		    case 'o':
+		      (*info->fprintf_func) (info->stream, ",o");
+		      break;
+		    case 'g':
+		      (*info->fprintf_func) (info->stream, ",gate");
+		      break;
+		    case 'p':
+		      (*info->fprintf_func) (info->stream, ",l,push");
+		      break;
+		    case 'P':
+		      (*info->fprintf_func) (info->stream, ",pop");
+		      break;
+		    case 'l':
+		    case 'L':
+		      (*info->fprintf_func) (info->stream, ",l");
+		      break;
+		    case 'w':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 read_write_names[GET_FIELD (insn, 25, 25)]);
+		      break;
+		    case 'W':
+		      (*info->fprintf_func) (info->stream, ",w ");
+		      break;
+		    case 'r':
+		      if (GET_FIELD (insn, 23, 26) == 5)
+			(*info->fprintf_func) (info->stream, ",r");
+		      break;
+		    case 'Z':
+		      if (GET_FIELD (insn, 26, 26))
+			(*info->fprintf_func) (info->stream, ",m ");
+		      else
+			(*info->fprintf_func) (info->stream, " ");
+		      break;
+		    case 'i':
+		      if (GET_FIELD (insn, 25, 25))
+			(*info->fprintf_func) (info->stream, ",i");
+		      break;
+		    case 'z':
+		      if (!GET_FIELD (insn, 21, 21))
+			(*info->fprintf_func) (info->stream, ",z");
+		      break;
+		    case 'a':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'Y':
+		      (*info->fprintf_func)
+			(info->stream, ",dc%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'y':
+		      (*info->fprintf_func)
+			(info->stream, ",c%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'v':
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 't':
+		      (*info->fprintf_func) (info->stream, ",tc");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'B':
+		      (*info->fprintf_func) (info->stream, ",db");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'b':
+		      (*info->fprintf_func) (info->stream, ",b");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'T':
+		      if (GET_FIELD (insn, 25, 25))
+			(*info->fprintf_func) (info->stream, ",tc");
+		      break;
+		    case 'S':
+		      /* EXTRD/W has a following condition.  */
+		      if (*(s + 1) == '?')
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   signed_unsigned_names[GET_FIELD (insn, 21, 21)]);
+		      else
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   signed_unsigned_names[GET_FIELD (insn, 21, 21)]);
+		      break;
+		    case 'h':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 mix_half_names[GET_FIELD (insn, 17, 17)]);
+		      break;
+		    case 'H':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 saturation_names[GET_FIELD (insn, 24, 25)]);
+		      break;
+		    case '*':
+		      (*info->fprintf_func)
+			(info->stream, ",%d%d%d%d ",
+			 GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21),
+			 GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25));
+		      break;
+
+		    case 'q':
+		      {
+			int m, a;
+
+			m = GET_FIELD (insn, 28, 28);
+			a = GET_FIELD (insn, 29, 29);
+
+			if (m && !a)
+			  fputs_filtered (",ma ", info);
+			else if (m && a)
+			  fputs_filtered (",mb ", info);
+			else
+			  fputs_filtered (" ", info);
+			break;
+		      }
+
+		    case 'J':
+		      {
+			int opc = GET_FIELD (insn, 0, 5);
+
+			if (opc == 0x16 || opc == 0x1e)
+			  {
+			    if (GET_FIELD (insn, 29, 29) == 0)
+			      fputs_filtered (",ma ", info);
+			    else
+			      fputs_filtered (",mb ", info);
+			  }
+			else
+			  fputs_filtered (" ", info);
+			break;
+		      }
+
+		    case 'e':
+		      {
+			int opc = GET_FIELD (insn, 0, 5);
+
+			if (opc == 0x13 || opc == 0x1b)
+			  {
+			    if (GET_FIELD (insn, 18, 18) == 1)
+			      fputs_filtered (",mb ", info);
+			    else
+			      fputs_filtered (",ma ", info);
+			  }
+			else if (opc == 0x17 || opc == 0x1f)
+			  {
+			    if (GET_FIELD (insn, 31, 31) == 1)
+			      fputs_filtered (",ma ", info);
+			    else
+			      fputs_filtered (",mb ", info);
+			  }
+			else
+			  fputs_filtered (" ", info);
+
+			break;
+		      }
+		    }
+		  break;
+
+		  /* Handle conditions.  */
+		case '?':
+		  {
+		    s++;
+		    switch (*s)
+		      {
+		      case 'f':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   float_comp_names[GET_FIELD (insn, 27, 31)]);
+			break;
+
+			/* These four conditions are for the set of instructions
+			   which distinguish true/false conditions by opcode
+			   rather than by the 'f' bit (sigh): comb, comib,
+			   addb, addib.  */
+		      case 't':
+			fputs_filtered
+			  (compare_cond_names[GET_FIELD (insn, 16, 18)], info);
+			break;
+		      case 'n':
+			fputs_filtered
+			  (compare_cond_names[GET_FIELD (insn, 16, 18)
+					      + GET_FIELD (insn, 4, 4) * 8],
+			   info);
+			break;
+		      case 'N':
+			fputs_filtered
+			  (compare_cond_64_names[GET_FIELD (insn, 16, 18)
+						 + GET_FIELD (insn, 2, 2) * 8],
+			   info);
+			break;
+		      case 'Q':
+			fputs_filtered
+			  (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)],
+			   info);
+			break;
+		      case '@':
+			fputs_filtered
+			  (add_cond_names[GET_FIELD (insn, 16, 18)
+					  + GET_FIELD (insn, 4, 4) * 8],
+			   info);
+			break;
+		      case 's':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   compare_cond_names[GET_COND (insn)]);
+			break;
+		      case 'S':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   compare_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'a':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   add_cond_names[GET_COND (insn)]);
+			break;
+		      case 'A':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   add_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'd':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   add_cond_names[GET_FIELD (insn, 16, 18)]);
+			break;
+
+		      case 'W':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   wide_add_cond_names[GET_FIELD (insn, 16, 18) +
+					       GET_FIELD (insn, 4, 4) * 8]);
+			break;
+
+		      case 'l':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   logical_cond_names[GET_COND (insn)]);
+			break;
+		      case 'L':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   logical_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'u':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   unit_cond_names[GET_COND (insn)]);
+			break;
+		      case 'U':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   unit_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'y':
+		      case 'x':
+		      case 'b':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   shift_cond_names[GET_FIELD (insn, 16, 18)]);
+
+			/* If the next character in args is 'n', it will handle
+			   putting out the space.  */
+			if (s[1] != 'n')
+			  (*info->fprintf_func) (info->stream, " ");
+			break;
+		      case 'X':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   shift_cond_64_names[GET_FIELD (insn, 16, 18)]);
+			break;
+		      case 'B':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   bb_cond_64_names[GET_FIELD (insn, 16, 16)]);
+
+			/* If the next character in args is 'n', it will handle
+			   putting out the space.  */
+			if (s[1] != 'n')
+			  (*info->fprintf_func) (info->stream, " ");
+			break;
+		      }
+		    break;
+		  }
+
+		case 'V':
+		  fput_const (extract_5_store (insn), info);
+		  break;
+		case 'r':
+		  fput_const (extract_5r_store (insn), info);
+		  break;
+		case 'R':
+		  fput_const (extract_5R_store (insn), info);
+		  break;
+		case 'U':
+		  fput_const (extract_10U_store (insn), info);
+		  break;
+		case 'B':
+		case 'Q':
+		  fput_const (extract_5Q_store (insn), info);
+		  break;
+		case 'i':
+		  fput_const (extract_11 (insn), info);
+		  break;
+		case 'j':
+		  fput_const (extract_14 (insn), info);
+		  break;
+		case 'k':
+		  fputs_filtered ("L%", info);
+		  fput_const (extract_21 (insn), info);
+		  break;
+		case '<':
+		case 'l':
+		  /* 16-bit long disp., PA2.0 wide only.  */
+		  fput_const (extract_16 (insn), info);
+		  break;
+		case 'n':
+		  if (insn & 0x2)
+		    (*info->fprintf_func) (info->stream, ",n ");
+		  else
+		    (*info->fprintf_func) (info->stream, " ");
+		  break;
+		case 'N':
+		  if ((insn & 0x20) && s[1])
+		    (*info->fprintf_func) (info->stream, ",n ");
+		  else if (insn & 0x20)
+		    (*info->fprintf_func) (info->stream, ",n");
+		  else if (s[1])
+		    (*info->fprintf_func) (info->stream, " ");
+		  break;
+		case 'w':
+		  (*info->print_address_func)
+		    (memaddr + 8 + extract_12 (insn), info);
+		  break;
+		case 'W':
+		  /* 17 bit PC-relative branch.  */
+		  (*info->print_address_func)
+		    ((memaddr + 8 + extract_17 (insn)), info);
+		  break;
+		case 'z':
+		  /* 17 bit displacement.  This is an offset from a register
+		     so it gets disasssembled as just a number, not any sort
+		     of address.  */
+		  fput_const (extract_17 (insn), info);
+		  break;
+
+		case 'Z':
+		  /* addil %r1 implicit output.  */
+		  fputs_filtered ("r1", info);
+		  break;
+
+		case 'Y':
+		  /* be,l %sr0,%r31 implicit output.  */
+		  fputs_filtered ("sr0,r31", info);
+		  break;
+
+		case '@':
+		  (*info->fprintf_func) (info->stream, "0");
+		  break;
+
+		case '.':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 24, 25));
+		  break;
+		case '*':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 22, 25));
+		  break;
+		case '!':
+		  fputs_filtered ("sar", info);
+		  break;
+		case 'p':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 31 - GET_FIELD (insn, 22, 26));
+		  break;
+		case '~':
+		  {
+		    int num;
+		    num = GET_FIELD (insn, 20, 20) << 5;
+		    num |= GET_FIELD (insn, 22, 26);
+		    (*info->fprintf_func) (info->stream, "%d", 63 - num);
+		    break;
+		  }
+		case 'P':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 22, 26));
+		  break;
+		case 'q':
+		  {
+		    int num;
+		    num = GET_FIELD (insn, 20, 20) << 5;
+		    num |= GET_FIELD (insn, 22, 26);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case 'T':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 32 - GET_FIELD (insn, 27, 31));
+		  break;
+		case '%':
+		  {
+		    int num;
+		    num = (GET_FIELD (insn, 23, 23) + 1) * 32;
+		    num -= GET_FIELD (insn, 27, 31);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case '|':
+		  {
+		    int num;
+		    num = (GET_FIELD (insn, 19, 19) + 1) * 32;
+		    num -= GET_FIELD (insn, 27, 31);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case '$':
+		  fput_const (GET_FIELD (insn, 20, 28), info);
+		  break;
+		case 'A':
+		  fput_const (GET_FIELD (insn, 6, 18), info);
+		  break;
+		case 'D':
+		  fput_const (GET_FIELD (insn, 6, 31), info);
+		  break;
+		case 'v':
+		  (*info->fprintf_func) (info->stream, ",%d",
+					 GET_FIELD (insn, 23, 25));
+		  break;
+		case 'O':
+		  fput_const ((GET_FIELD (insn, 6,20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case 'o':
+		  fput_const (GET_FIELD (insn, 6, 20), info);
+		  break;
+		case '2':
+		  fput_const ((GET_FIELD (insn, 6, 22) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case '1':
+		  fput_const ((GET_FIELD (insn, 11, 20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case '0':
+		  fput_const ((GET_FIELD (insn, 16, 20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case 'u':
+		  (*info->fprintf_func) (info->stream, ",%d",
+					 GET_FIELD (insn, 23, 25));
+		  break;
+		case 'F':
+		  /* If no destination completer and not before a completer
+		     for fcmp, need a space here.  */
+		  if (s[1] == 'G' || s[1] == '?')
+		    fputs_filtered
+		      (float_format_names[GET_FIELD (insn, 19, 20)], info);
+		  else
+		    (*info->fprintf_func)
+		      (info->stream, "%s ",
+		       float_format_names[GET_FIELD (insn, 19, 20)]);
+		  break;
+		case 'G':
+		  (*info->fprintf_func)
+		    (info->stream, "%s ",
+		     float_format_names[GET_FIELD (insn, 17, 18)]);
+		  break;
+		case 'H':
+		  if (GET_FIELD (insn, 26, 26) == 1)
+		    (*info->fprintf_func) (info->stream, "%s ",
+					   float_format_names[0]);
+		  else
+		    (*info->fprintf_func) (info->stream, "%s ",
+					   float_format_names[1]);
+		  break;
+		case 'I':
+		  /* If no destination completer and not before a completer
+		     for fcmp, need a space here.  */
+		  if (s[1] == '?')
+		    fputs_filtered
+		      (float_format_names[GET_FIELD (insn, 20, 20)], info);
+		  else
+		    (*info->fprintf_func)
+		      (info->stream, "%s ",
+		       float_format_names[GET_FIELD (insn, 20, 20)]);
+		  break;
+
+		case 'J':
+		  fput_const (extract_14 (insn), info);
+		  break;
+
+		case '#':
+		  {
+		    int sign = GET_FIELD (insn, 31, 31);
+		    int imm10 = GET_FIELD (insn, 18, 27);
+		    int disp;
+
+		    if (sign)
+		      disp = (-1 << 10) | imm10;
+		    else
+		      disp = imm10;
+
+		    disp <<= 3;
+		    fput_const (disp, info);
+		    break;
+		  }
+		case 'K':
+		case 'd':
+		  {
+		    int sign = GET_FIELD (insn, 31, 31);
+		    int imm11 = GET_FIELD (insn, 18, 28);
+		    int disp;
+
+		    if (sign)
+		      disp = (-1 << 11) | imm11;
+		    else
+		      disp = imm11;
+
+		    disp <<= 2;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '>':
+		case 'y':
+		  {
+		    /* 16-bit long disp., PA2.0 wide only.  */
+		    int disp = extract_16 (insn);
+		    disp &= ~3;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '&':
+		  {
+		    /* 16-bit long disp., PA2.0 wide only.  */
+		    int disp = extract_16 (insn);
+		    disp &= ~7;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '_':
+		  break; /* Dealt with by '{' */
+
+		case '{':
+		  {
+		    int sub = GET_FIELD (insn, 14, 16);
+		    int df = GET_FIELD (insn, 17, 18);
+		    int sf = GET_FIELD (insn, 19, 20);
+		    const char * const * source = float_format_names;
+		    const char * const * dest = float_format_names;
+		    const char *t = "";
+
+		    if (sub == 4)
+		      {
+			fputs_filtered (",UND ", info);
+			break;
+		      }
+		    if ((sub & 3) == 3)
+		      t = ",t";
+		    if ((sub & 3) == 1)
+		      source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names;
+		    if (sub & 2)
+		      dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names;
+
+		    (*info->fprintf_func) (info->stream, "%s%s%s ",
+					   t, source[sf], dest[df]);
+		    break;
+		  }
+
+		case 'm':
+		  {
+		    int y = GET_FIELD (insn, 16, 18);
+
+		    if (y != 1)
+		      fput_const ((y ^ 1) - 1, info);
+		  }
+		  break;
+
+		case 'h':
+		  {
+		    int cbit;
+
+		    cbit = GET_FIELD (insn, 16, 18);
+
+		    if (cbit > 0)
+		      (*info->fprintf_func) (info->stream, ",%d", cbit - 1);
+		    break;
+		  }
+
+		case '=':
+		  {
+		    int cond = GET_FIELD (insn, 27, 31);
+
+		    switch (cond)
+		      {
+		      case  0: fputs_filtered (" ", info); break;
+		      case  1: fputs_filtered ("acc ", info); break;
+		      case  2: fputs_filtered ("rej ", info); break;
+		      case  5: fputs_filtered ("acc8 ", info); break;
+		      case  6: fputs_filtered ("rej8 ", info); break;
+		      case  9: fputs_filtered ("acc6 ", info); break;
+		      case 13: fputs_filtered ("acc4 ", info); break;
+		      case 17: fputs_filtered ("acc2 ", info); break;
+		      default: break;
+		      }
+		    break;
+		  }
+
+		case 'X':
+		  (*info->print_address_func)
+		    (memaddr + 8 + extract_22 (insn), info);
+		  break;
+		case 'L':
+		  fputs_filtered (",rp", info);
+		  break;
+		default:
+		  (*info->fprintf_func) (info->stream, "%c", *s);
+		  break;
+		}
+	    }
+	  return sizeof (insn);
+	}
+    }
+  (*info->fprintf_func) (info->stream, "#%8x", insn);
+  return sizeof (insn);
+}
diff --git a/qemu-0.15.x/hppa.ld b/qemu-0.15.x/hppa.ld
new file mode 100644
index 0000000..3555b3e
--- /dev/null
+++ b/qemu-0.15.x/hppa.ld
@@ -0,0 +1,211 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux",
+	      "elf32-hppa-linux")
+OUTPUT_ARCH(hppa:hppa1.1)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x08000240
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x08000240
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x08000240
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .PARISC.unwind   : { *(.PARISC.unwind) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x10000) + (. & (0x10000 - 1));
+  /* Exception handling  */
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .data           :
+  {
+    PROVIDE ($global$ = .);
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .plt            : { *(.plt) }
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/qemu-0.15.x/hw/9p.h b/qemu-0.15.x/hw/9p.h
new file mode 100644
index 0000000..d9951d6
--- /dev/null
+++ b/qemu-0.15.x/hw/9p.h
@@ -0,0 +1,24 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_9P_H
+#define QEMU_9P_H
+
+typedef struct V9fsConf
+{
+    /* tag name for the device */
+    char *tag;
+    char *fsdev_id;
+} V9fsConf;
+
+#endif
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-debug.c b/qemu-0.15.x/hw/9pfs/virtio-9p-debug.c
new file mode 100644
index 0000000..4636ad5
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-debug.c
@@ -0,0 +1,646 @@
+/*
+ * Virtio 9p PDU debug
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
+#include "virtio-9p.h"
+#include "virtio-9p-debug.h"
+
+#define BUG_ON(cond) assert(!(cond))
+
+static FILE *llogfile;
+
+static struct iovec *get_sg(V9fsPDU *pdu, int rx)
+{
+    if (rx) {
+        return pdu->elem.in_sg;
+    }
+    return pdu->elem.out_sg;
+}
+
+static int get_sg_count(V9fsPDU *pdu, int rx)
+{
+    if (rx) {
+        return pdu->elem.in_num;
+    }
+    return pdu->elem.out_num;
+
+}
+
+static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    size_t offset = *offsetp;
+    struct iovec *sg = get_sg(pdu, rx);
+    int8_t value;
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int16_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int32_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int64_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%" PRIx64, name, value);
+    *offsetp = offset;
+}
+
+static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_size, size;
+    size_t result;
+    size_t copied = 0;
+    int i = 0;
+
+    /* get the size */
+    copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
+    BUG_ON(copied != sizeof(tmp_size));
+    size = le16_to_cpupu(&tmp_size);
+    offset += copied;
+
+    fprintf(llogfile, "%s=", name);
+    for (i = 0; size && i < sg_count; i++) {
+        size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
+            len = MIN(sg[i].iov_len - offset, size);
+            result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
+            BUG_ON(result != len);
+            size -= len;
+            copied += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
+        }
+    }
+    *offsetp += copied;
+}
+
+static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_int8(pdu, rx, offsetp, "type");
+    pprint_int32(pdu, rx, offsetp, ", version");
+    pprint_int64(pdu, rx, offsetp, ", path");
+    fprintf(llogfile, "}");
+}
+
+static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_int16(pdu, rx, offsetp, "size");
+    pprint_int16(pdu, rx, offsetp, ", type");
+    pprint_int32(pdu, rx, offsetp, ", dev");
+    pprint_qid(pdu, rx, offsetp, ", qid");
+    pprint_int32(pdu, rx, offsetp, ", mode");
+    pprint_int32(pdu, rx, offsetp, ", atime");
+    pprint_int32(pdu, rx, offsetp, ", mtime");
+    pprint_int64(pdu, rx, offsetp, ", length");
+    pprint_str(pdu, rx, offsetp, ", name");
+    pprint_str(pdu, rx, offsetp, ", uid");
+    pprint_str(pdu, rx, offsetp, ", gid");
+    pprint_str(pdu, rx, offsetp, ", muid");
+    pprint_str(pdu, rx, offsetp, ", extension");
+    pprint_int32(pdu, rx, offsetp, ", uid");
+    pprint_int32(pdu, rx, offsetp, ", gid");
+    pprint_int32(pdu, rx, offsetp, ", muid");
+    fprintf(llogfile, "}");
+}
+
+static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
+                                                  const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_qid(pdu, rx, offsetp, "qid");
+    pprint_int32(pdu, rx, offsetp, ", st_mode");
+    pprint_int64(pdu, rx, offsetp, ", st_nlink");
+    pprint_int32(pdu, rx, offsetp, ", st_uid");
+    pprint_int32(pdu, rx, offsetp, ", st_gid");
+    pprint_int64(pdu, rx, offsetp, ", st_rdev");
+    pprint_int64(pdu, rx, offsetp, ", st_size");
+    pprint_int64(pdu, rx, offsetp, ", st_blksize");
+    pprint_int64(pdu, rx, offsetp, ", st_blocks");
+    pprint_int64(pdu, rx, offsetp, ", atime");
+    pprint_int64(pdu, rx, offsetp, ", atime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", mtime");
+    pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", ctime");
+    pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
+    fprintf(llogfile, "}");
+}
+
+
+
+static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_count, count, i;
+    size_t copied = 0;
+
+    fprintf(llogfile, "%s={", name);
+
+    /* Get the count */
+    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
+    BUG_ON(copied != sizeof(tmp_count));
+    count = le16_to_cpupu(&tmp_count);
+    offset += copied;
+
+    for (i = 0; i < count; i++) {
+        char str[512];
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        snprintf(str, sizeof(str), "[%d]", i);
+        pprint_str(pdu, rx, &offset, str);
+    }
+
+    fprintf(llogfile, "}");
+
+    *offsetp = offset;
+}
+
+static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_count, count, i;
+    size_t copied = 0;
+
+    fprintf(llogfile, "%s={", name);
+
+    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
+    BUG_ON(copied != sizeof(tmp_count));
+    count = le16_to_cpupu(&tmp_count);
+    offset += copied;
+
+    for (i = 0; i < count; i++) {
+        char str[512];
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        snprintf(str, sizeof(str), "[%d]", i);
+        pprint_qid(pdu, rx, &offset, str);
+    }
+
+    fprintf(llogfile, "}");
+
+    *offsetp = offset;
+}
+
+static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    struct iovec *sg = get_sg(pdu, rx);
+    unsigned int count;
+    int i;
+
+    if (rx) {
+        count = pdu->elem.in_num;
+    } else {
+        count = pdu->elem.out_num;
+    }
+
+    fprintf(llogfile, "%s={", name);
+    for (i = 0; i < count; i++) {
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
+    }
+    fprintf(llogfile, "}");
+}
+
+/* FIXME: read from a directory fid returns serialized stat_t's */
+#ifdef DEBUG_DATA
+static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    unsigned int count;
+    int32_t size;
+    int total, i, j;
+    ssize_t len;
+
+    if (rx) {
+        count = pdu->elem.in_num;
+    } else
+        count = pdu->elem.out_num;
+    }
+
+    BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
+
+    memcpy(&size, sg[0].iov_base + offset, sizeof(size));
+    offset += sizeof(size);
+
+    fprintf(llogfile, "size: %x\n", size);
+
+    sg[0].iov_base += 11; /* skip header */
+    sg[0].iov_len -= 11;
+
+    total = 0;
+    for (i = 0; i < count; i++) {
+        total += sg[i].iov_len;
+        if (total >= size) {
+            /* trim sg list so writev does the right thing */
+            sg[i].iov_len -= (total - size);
+            i++;
+            break;
+        }
+    }
+
+    fprintf(llogfile, "%s={\"", name);
+    fflush(llogfile);
+    for (j = 0; j < i; j++) {
+        if (j) {
+            fprintf(llogfile, "\", \"");
+            fflush(llogfile);
+        }
+
+        do {
+            len = writev(fileno(llogfile), &sg[j], 1);
+        } while (len == -1 && errno == EINTR);
+        fprintf(llogfile, "len == %ld: %m\n", len);
+        BUG_ON(len != sg[j].iov_len);
+    }
+    fprintf(llogfile, "\"}");
+
+    sg[0].iov_base -= 11;
+    sg[0].iov_len += 11;
+
+}
+#endif
+
+void pprint_pdu(V9fsPDU *pdu)
+{
+    size_t offset = 7;
+
+    if (llogfile == NULL) {
+        llogfile = fopen("/tmp/pdu.log", "w");
+    }
+
+    BUG_ON(!llogfile);
+
+    switch (pdu->id) {
+    case P9_TREADDIR:
+        fprintf(llogfile, "TREADDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", initial offset");
+        pprint_int32(pdu, 0, &offset, ", max count");
+        break;
+    case P9_RREADDIR:
+        fprintf(llogfile, "RREADDIR: (");
+        pprint_int32(pdu, 1, &offset, "count");
+#ifdef DEBUG_DATA
+        pprint_data(pdu, 1, &offset, ", data");
+#endif
+        break;
+    case P9_TMKDIR:
+        fprintf(llogfile, "TMKDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKDIR:
+        fprintf(llogfile, "RMKDIR: (");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
+    case P9_TVERSION:
+        fprintf(llogfile, "TVERSION: (");
+        pprint_int32(pdu, 0, &offset, "msize");
+        pprint_str(pdu, 0, &offset, ", version");
+        break;
+    case P9_RVERSION:
+        fprintf(llogfile, "RVERSION: (");
+        pprint_int32(pdu, 1, &offset, "msize");
+        pprint_str(pdu, 1, &offset, ", version");
+        break;
+    case P9_TGETATTR:
+        fprintf(llogfile, "TGETATTR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RGETATTR:
+        fprintf(llogfile, "RGETATTR: (");
+        pprint_stat_dotl(pdu, 1, &offset, "getattr");
+        break;
+    case P9_TAUTH:
+        fprintf(llogfile, "TAUTH: (");
+        pprint_int32(pdu, 0, &offset, "afid");
+        pprint_str(pdu, 0, &offset, ", uname");
+        pprint_str(pdu, 0, &offset, ", aname");
+        pprint_int32(pdu, 0, &offset, ", n_uname");
+        break;
+    case P9_RAUTH:
+        fprintf(llogfile, "RAUTH: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TATTACH:
+        fprintf(llogfile, "TATTACH: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", afid");
+        pprint_str(pdu, 0, &offset, ", uname");
+        pprint_str(pdu, 0, &offset, ", aname");
+        pprint_int32(pdu, 0, &offset, ", n_uname");
+        break;
+    case P9_RATTACH:
+        fprintf(llogfile, "RATTACH: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TERROR:
+        fprintf(llogfile, "TERROR: (");
+        break;
+    case P9_RERROR:
+        fprintf(llogfile, "RERROR: (");
+        pprint_str(pdu, 1, &offset, "ename");
+        pprint_int32(pdu, 1, &offset, ", ecode");
+        break;
+    case P9_TFLUSH:
+        fprintf(llogfile, "TFLUSH: (");
+        pprint_int16(pdu, 0, &offset, "oldtag");
+        break;
+    case P9_RFLUSH:
+        fprintf(llogfile, "RFLUSH: (");
+        break;
+    case P9_TWALK:
+        fprintf(llogfile, "TWALK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", newfid");
+        pprint_strs(pdu, 0, &offset, ", wnames");
+        break;
+    case P9_RWALK:
+        fprintf(llogfile, "RWALK: (");
+        pprint_qids(pdu, 1, &offset, "wqids");
+        break;
+    case P9_TOPEN:
+        fprintf(llogfile, "TOPEN: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", mode");
+        break;
+    case P9_ROPEN:
+        fprintf(llogfile, "ROPEN: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TCREATE:
+        fprintf(llogfile, "TCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int32(pdu, 0, &offset, ", perm");
+        pprint_int8(pdu, 0, &offset, ", mode");
+        pprint_str(pdu, 0, &offset, ", extension");
+        break;
+    case P9_RCREATE:
+        fprintf(llogfile, "RCREATE: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TSYMLINK:
+        fprintf(llogfile, "TSYMLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_str(pdu, 0, &offset, ", symname");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RSYMLINK:
+        fprintf(llogfile, "RSYMLINK: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TLCREATE:
+        fprintf(llogfile, "TLCREATE: (");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int32(pdu, 0, &offset, ", mode");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RLCREATE:
+        fprintf(llogfile, "RLCREATE: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TMKNOD:
+	fprintf(llogfile, "TMKNOD: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "major");
+        pprint_int32(pdu, 0, &offset, "minor");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKNOD:
+        fprintf(llogfile, "RMKNOD: )");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
+    case P9_TREADLINK:
+	fprintf(llogfile, "TREADLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREADLINK:
+	fprintf(llogfile, "RREADLINK: (");
+        pprint_str(pdu, 0, &offset, "target");
+        break;
+    case P9_TREAD:
+        fprintf(llogfile, "TREAD: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", offset");
+        pprint_int32(pdu, 0, &offset, ", count");
+        pprint_sg(pdu, 0, &offset, ", sg");
+        break;
+    case P9_RREAD:
+        fprintf(llogfile, "RREAD: (");
+        pprint_int32(pdu, 1, &offset, "count");
+        pprint_sg(pdu, 1, &offset, ", sg");
+        offset = 7;
+#ifdef DEBUG_DATA
+        pprint_data(pdu, 1, &offset, ", data");
+#endif
+        break;
+    case P9_TWRITE:
+        fprintf(llogfile, "TWRITE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", offset");
+        pprint_int32(pdu, 0, &offset, ", count");
+        break;
+    case P9_RWRITE:
+        fprintf(llogfile, "RWRITE: (");
+        pprint_int32(pdu, 1, &offset, "count");
+        break;
+    case P9_TCLUNK:
+        fprintf(llogfile, "TCLUNK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RCLUNK:
+        fprintf(llogfile, "RCLUNK: (");
+        break;
+    case P9_TFSYNC:
+        fprintf(llogfile, "TFSYNC: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RFSYNC:
+        fprintf(llogfile, "RFSYNC: (");
+        break;
+    case P9_TLINK:
+        fprintf(llogfile, "TLINK: (");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_int32(pdu, 0, &offset, ", fid");
+        pprint_str(pdu, 0, &offset, ", newpath");
+        break;
+    case P9_RLINK:
+        fprintf(llogfile, "RLINK: (");
+        break;
+    case P9_TREMOVE:
+        fprintf(llogfile, "TREMOVE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREMOVE:
+        fprintf(llogfile, "RREMOVE: (");
+        break;
+    case P9_TSTAT:
+        fprintf(llogfile, "TSTAT: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RSTAT:
+        fprintf(llogfile, "RSTAT: (");
+        offset += 2; /* ignored */
+        pprint_stat(pdu, 1, &offset, "stat");
+        break;
+    case P9_TWSTAT:
+        fprintf(llogfile, "TWSTAT: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        offset += 2; /* ignored */
+        pprint_stat(pdu, 0, &offset, ", stat");
+        break;
+    case P9_RWSTAT:
+        fprintf(llogfile, "RWSTAT: (");
+        break;
+    case P9_TXATTRWALK:
+        fprintf(llogfile, "TXATTRWALK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", newfid");
+        pprint_str(pdu, 0, &offset, ", xattr name");
+        break;
+    case P9_RXATTRWALK:
+        fprintf(llogfile, "RXATTRWALK: (");
+        pprint_int64(pdu, 1, &offset, "xattrsize");
+    case P9_TXATTRCREATE:
+        fprintf(llogfile, "TXATTRCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int64(pdu, 0, &offset, ", xattrsize");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        break;
+    case P9_RXATTRCREATE:
+        fprintf(llogfile, "RXATTRCREATE: (");
+        break;
+    case P9_TLOCK:
+        fprintf(llogfile, "TLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RLOCK:
+        fprintf(llogfile, "RLOCK: (");
+        pprint_int8(pdu, 0, &offset, "status");
+        break;
+    case P9_TGETLOCK:
+        fprintf(llogfile, "TGETLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RGETLOCK:
+        fprintf(llogfile, "RGETLOCK: (");
+        pprint_int8(pdu, 0, &offset, "type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    default:
+        fprintf(llogfile, "unknown(%d): (", pdu->id);
+        break;
+    }
+
+    fprintf(llogfile, ")\n");
+    /* Flush the log message out */
+    fflush(llogfile);
+}
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-debug.h b/qemu-0.15.x/hw/9pfs/virtio-9p-debug.h
new file mode 100644
index 0000000..d9a2491
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-debug.h
@@ -0,0 +1,6 @@
+#ifndef _QEMU_VIRTIO_9P_DEBUG_H
+#define _QEMU_VIRTIO_9P_DEBUG_H
+
+void pprint_pdu(V9fsPDU *pdu);
+
+#endif
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-device.c b/qemu-0.15.x/hw/9pfs/virtio-9p-device.c
new file mode 100644
index 0000000..f235236
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-device.c
@@ -0,0 +1,173 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
+#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-xattr.h"
+
+static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    features |= 1 << VIRTIO_9P_MOUNT_TAG;
+    return features;
+}
+
+static V9fsState *to_virtio_9p(VirtIODevice *vdev)
+{
+    return (V9fsState *)vdev;
+}
+
+static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    struct virtio_9p_config *cfg;
+    V9fsState *s = to_virtio_9p(vdev);
+
+    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
+                        s->tag_len);
+    stw_raw(&cfg->tag_len, s->tag_len);
+    memcpy(cfg->tag, s->tag, s->tag_len);
+    memcpy(config, cfg, s->config_size);
+    qemu_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+ {
+    V9fsState *s;
+    int i, len;
+    struct stat stat;
+    FsTypeEntry *fse;
+
+
+    s = (V9fsState *)virtio_common_init("virtio-9p",
+                                    VIRTIO_ID_9P,
+                                    sizeof(struct virtio_9p_config)+
+                                    MAX_TAG_LEN,
+                                    sizeof(V9fsState));
+
+    /* initialize pdu allocator */
+    QLIST_INIT(&s->free_list);
+    for (i = 0; i < (MAX_REQ - 1); i++) {
+        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
+    }
+
+    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
+
+    fse = get_fsdev_fsentry(conf->fsdev_id);
+
+    if (!fse) {
+        /* We don't have a fsdev identified by fsdev_id */
+        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
+        exit(1);
+    }
+
+    if (!fse->path || !conf->tag) {
+        /* we haven't specified a mount_tag or the path */
+        fprintf(stderr, "fsdev with id %s needs path "
+                "and Virtio-9p device needs mount_tag arguments\n",
+                conf->fsdev_id);
+        exit(1);
+    }
+
+    if (!strcmp(fse->security_model, "passthrough")) {
+        /* Files on the Fileserver set to client user credentials */
+        s->ctx.fs_sm = SM_PASSTHROUGH;
+        s->ctx.xops = passthrough_xattr_ops;
+    } else if (!strcmp(fse->security_model, "mapped")) {
+        /* Files on the fileserver are set to QEMU credentials.
+         * Client user credentials are saved in extended attributes.
+         */
+        s->ctx.fs_sm = SM_MAPPED;
+        s->ctx.xops = mapped_xattr_ops;
+    } else if (!strcmp(fse->security_model, "none")) {
+        /*
+         * Files on the fileserver are set to QEMU credentials.
+         */
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
+    } else {
+        fprintf(stderr, "Default to security_model=none. You may want"
+                " enable advanced security model using "
+                "security option:\n\t security_model=passthrough\n\t "
+                "security_model=mapped\n");
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
+    }
+
+    if (lstat(fse->path, &stat)) {
+        fprintf(stderr, "share path %s does not exist\n", fse->path);
+        exit(1);
+    } else if (!S_ISDIR(stat.st_mode)) {
+        fprintf(stderr, "share path %s is not a directory\n", fse->path);
+        exit(1);
+    }
+
+    s->ctx.fs_root = qemu_strdup(fse->path);
+    len = strlen(conf->tag);
+    if (len > MAX_TAG_LEN) {
+        len = MAX_TAG_LEN;
+    }
+    /* s->tag is non-NULL terminated string */
+    s->tag = qemu_malloc(len);
+    memcpy(s->tag, conf->tag, len);
+    s->tag_len = len;
+    s->ctx.uid = -1;
+
+    s->ops = fse->ops;
+    s->vdev.get_features = virtio_9p_get_features;
+    s->config_size = sizeof(struct virtio_9p_config) +
+                        s->tag_len;
+    s->vdev.get_config = virtio_9p_get_config;
+
+    return &s->vdev;
+}
+
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static PCIDeviceInfo virtio_9p_info = {
+    .qdev.name = "virtio-9p-pci",
+    .qdev.size = sizeof(VirtIOPCIProxy),
+    .init      = virtio_9p_init_pci,
+    .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id = 0x1009,
+    .revision  = VIRTIO_PCI_ABI_VERSION,
+    .class_id  = 0x2,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+        DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+        DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+        DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void virtio_9p_register_devices(void)
+{
+    pci_qdev_register(&virtio_9p_info);
+}
+
+device_init(virtio_9p_register_devices)
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-local.c b/qemu-0.15.x/hw/9pfs/virtio-9p-local.c
new file mode 100644
index 0000000..77904c3
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-local.c
@@ -0,0 +1,557 @@
+/*
+ * Virtio 9p Posix callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <attr/xattr.h>
+
+
+static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
+{
+    int err;
+    char buffer[PATH_MAX];
+    err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        /* Actual credentials are part of extended attrs */
+        uid_t tmp_uid;
+        gid_t tmp_gid;
+        mode_t tmp_mode;
+        dev_t tmp_dev;
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
+                    sizeof(uid_t)) > 0) {
+            stbuf->st_uid = tmp_uid;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
+                    sizeof(gid_t)) > 0) {
+            stbuf->st_gid = tmp_gid;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+                    &tmp_mode, sizeof(mode_t)) > 0) {
+            stbuf->st_mode = tmp_mode;
+        }
+        if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
+                        sizeof(dev_t)) > 0) {
+                stbuf->st_rdev = tmp_dev;
+        }
+    }
+    return err;
+}
+
+static int local_set_xattr(const char *path, FsCred *credp)
+{
+    int err;
+    if (credp->fc_uid != -1) {
+        err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
+                0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_gid != -1) {
+        err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
+                0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_mode != -1) {
+        err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
+                sizeof(mode_t), 0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_rdev != -1) {
+        err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
+                sizeof(dev_t), 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
+        FsCred *credp)
+{
+    char buffer[PATH_MAX];
+    if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
+        return -1;
+    }
+    if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+                credp->fc_gid) < 0) {
+        /*
+         * If we fail to change ownership and if we are
+         * using security model none. Ignore the error
+         */
+        if (fs_ctx->fs_sm != SM_NONE) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
+        char *buf, size_t bufsz)
+{
+    ssize_t tsize = -1;
+    char buffer[PATH_MAX];
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
+        if (fd == -1) {
+            return -1;
+        }
+        do {
+            tsize = read(fd, (void *)buf, bufsz);
+        } while (tsize == -1 && errno == EINTR);
+        close(fd);
+        return tsize;
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
+    }
+    return tsize;
+}
+
+static int local_close(FsContext *ctx, int fd)
+{
+    return close(fd);
+}
+
+static int local_closedir(FsContext *ctx, DIR *dir)
+{
+    return closedir(dir);
+}
+
+static int local_open(FsContext *ctx, const char *path, int flags)
+{
+    char buffer[PATH_MAX];
+    return open(rpath(ctx, path, buffer), flags);
+}
+
+static DIR *local_opendir(FsContext *ctx, const char *path)
+{
+    char buffer[PATH_MAX];
+    return opendir(rpath(ctx, path, buffer));
+}
+
+static void local_rewinddir(FsContext *ctx, DIR *dir)
+{
+    return rewinddir(dir);
+}
+
+static off_t local_telldir(FsContext *ctx, DIR *dir)
+{
+    return telldir(dir);
+}
+
+static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
+{
+    return readdir(dir);
+}
+
+static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
+{
+    return seekdir(dir, off);
+}
+
+static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    char buffer[PATH_MAX];
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
+    }
+    return -1;
+}
+
+static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+    char buffer[PATH_MAX];
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        err = mknod(rpath(fs_ctx, path, buffer),
+                SM_LOCAL_MODE_BITS|S_IFREG, 0);
+        if (err == -1) {
+            return err;
+        }
+        local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
+                credp->fc_rdev);
+        if (err == -1) {
+            return err;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+    return err;
+}
+
+static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+    char buffer[PATH_MAX];
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+        if (err == -1) {
+            return err;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFDIR;
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
+        if (err == -1) {
+            return err;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+    return err;
+}
+
+static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+{
+    int err;
+    err = fstat(fd, stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        /* Actual credentials are part of extended attrs */
+        uid_t tmp_uid;
+        gid_t tmp_gid;
+        mode_t tmp_mode;
+        dev_t tmp_dev;
+
+        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
+            stbuf->st_uid = tmp_uid;
+        }
+        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
+            stbuf->st_gid = tmp_gid;
+        }
+        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
+            stbuf->st_mode = tmp_mode;
+        }
+        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
+                stbuf->st_rdev = tmp_dev;
+        }
+    }
+    return err;
+}
+
+static int local_open2(FsContext *fs_ctx, const char *path, int flags,
+        FsCred *credp)
+{
+    int fd = -1;
+    int err = -1;
+    int serrno = 0;
+    char buffer[PATH_MAX];
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            return fd;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFREG;
+        /* Set cleint credentials in xattr */
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
+        if (fd == -1) {
+            return fd;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return fd;
+
+err_end:
+    close(fd);
+    remove(rpath(fs_ctx, path, buffer));
+    errno = serrno;
+    return err;
+}
+
+
+static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+        const char *newpath, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+    char buffer[PATH_MAX];
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        ssize_t oldpath_size, write_size;
+        fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
+                SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            return fd;
+        }
+        /* Write the oldpath (target) to the file. */
+        oldpath_size = strlen(oldpath);
+        do {
+            write_size = write(fd, (void *)oldpath, oldpath_size);
+        } while (write_size == -1 && errno == EINTR);
+
+        if (write_size != oldpath_size) {
+            serrno = errno;
+            close(fd);
+            err = -1;
+            goto err_end;
+        }
+        close(fd);
+        /* Set cleint credentials in symlink's xattr */
+        credp->fc_mode = credp->fc_mode|S_IFLNK;
+        err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
+        if (err) {
+            return err;
+        }
+        err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
+                credp->fc_gid);
+        if (err == -1) {
+            /*
+             * If we fail to change ownership and if we are
+             * using security model none. Ignore the error
+             */
+            if (fs_ctx->fs_sm != SM_NONE) {
+                serrno = errno;
+                goto err_end;
+            } else
+                err = 0;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, newpath, buffer));
+    errno = serrno;
+    return err;
+}
+
+static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+{
+    char buffer[PATH_MAX], buffer1[PATH_MAX];
+
+    return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+}
+
+static int local_truncate(FsContext *ctx, const char *path, off_t size)
+{
+    char buffer[PATH_MAX];
+    return truncate(rpath(ctx, path, buffer), size);
+}
+
+static int local_rename(FsContext *ctx, const char *oldpath,
+                        const char *newpath)
+{
+    char buffer[PATH_MAX], buffer1[PATH_MAX];
+
+    return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+}
+
+static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    char buffer[PATH_MAX];
+    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
+            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
+        return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+                credp->fc_gid);
+    } else if (fs_ctx->fs_sm == SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+                credp->fc_gid);
+    }
+    return -1;
+}
+
+static int local_utimensat(FsContext *s, const char *path,
+                           const struct timespec *buf)
+{
+    char buffer[PATH_MAX];
+    return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
+            AT_SYMLINK_NOFOLLOW);
+}
+
+static int local_remove(FsContext *ctx, const char *path)
+{
+    char buffer[PATH_MAX];
+    return remove(rpath(ctx, path, buffer));
+}
+
+static int local_fsync(FsContext *ctx, int fd, int datasync)
+{
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+{
+    char buffer[PATH_MAX];
+   return statfs(rpath(s, path, buffer), stbuf);
+}
+
+static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+                               const char *name, void *value, size_t size)
+{
+    return v9fs_get_xattr(ctx, path, name, value, size);
+}
+
+static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+                                void *value, size_t size)
+{
+    return v9fs_list_xattr(ctx, path, value, size);
+}
+
+static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+                           void *value, size_t size, int flags)
+{
+    return v9fs_set_xattr(ctx, path, name, value, size, flags);
+}
+
+static int local_lremovexattr(FsContext *ctx,
+                              const char *path, const char *name)
+{
+    return v9fs_remove_xattr(ctx, path, name);
+}
+
+
+FileOperations local_ops = {
+    .lstat = local_lstat,
+    .readlink = local_readlink,
+    .close = local_close,
+    .closedir = local_closedir,
+    .open = local_open,
+    .opendir = local_opendir,
+    .rewinddir = local_rewinddir,
+    .telldir = local_telldir,
+    .readdir = local_readdir,
+    .seekdir = local_seekdir,
+    .preadv = local_preadv,
+    .pwritev = local_pwritev,
+    .chmod = local_chmod,
+    .mknod = local_mknod,
+    .mkdir = local_mkdir,
+    .fstat = local_fstat,
+    .open2 = local_open2,
+    .symlink = local_symlink,
+    .link = local_link,
+    .truncate = local_truncate,
+    .rename = local_rename,
+    .chown = local_chown,
+    .utimensat = local_utimensat,
+    .remove = local_remove,
+    .fsync = local_fsync,
+    .statfs = local_statfs,
+    .lgetxattr = local_lgetxattr,
+    .llistxattr = local_llistxattr,
+    .lsetxattr = local_lsetxattr,
+    .lremovexattr = local_lremovexattr,
+};
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-posix-acl.c b/qemu-0.15.x/hw/9pfs/virtio-9p-posix-acl.c
new file mode 100644
index 0000000..f5b392e
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-posix-acl.c
@@ -0,0 +1,159 @@
+/*
+ * Virtio 9p system.posix* xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <attr/xattr.h>
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
+#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
+#define ACL_ACCESS "system.posix_acl_access"
+#define ACL_DEFAULT "system.posix_acl_default"
+
+static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
+}
+
+static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_ACCESS);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_ACCESS, len);
+    return 0;
+}
+
+static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
+            size, flags);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    char buffer[PATH_MAX];
+    ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remove a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
+}
+
+static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_DEFAULT);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_DEFAULT, len);
+    return 0;
+}
+
+static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
+            size, flags);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    char buffer[PATH_MAX];
+    ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remove a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+
+XattrOperations mapped_pacl_xattr = {
+    .name = "system.posix_acl_access",
+    .getxattr = mp_pacl_getxattr,
+    .setxattr = mp_pacl_setxattr,
+    .listxattr = mp_pacl_listxattr,
+    .removexattr = mp_pacl_removexattr,
+};
+
+XattrOperations mapped_dacl_xattr = {
+    .name = "system.posix_acl_default",
+    .getxattr = mp_dacl_getxattr,
+    .setxattr = mp_dacl_setxattr,
+    .listxattr = mp_dacl_listxattr,
+    .removexattr = mp_dacl_removexattr,
+};
+
+XattrOperations passthrough_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
+
+XattrOperations none_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = notsup_getxattr,
+    .setxattr = notsup_setxattr,
+    .listxattr = notsup_listxattr,
+    .removexattr = notsup_removexattr,
+};
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-xattr-user.c b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr-user.c
new file mode 100644
index 0000000..5044a3e
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr-user.c
@@ -0,0 +1,112 @@
+/*
+ * Virtio 9p user. xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    char buffer[PATH_MAX];
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = ENOATTR;
+        return -1;
+    }
+    return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+}
+
+static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+
+        /*  check if it is a mapped posix acl */
+        if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
+            /* adjust the name and size */
+            name += 12;
+            name_size -= 12;
+        } else {
+            /*
+             * Don't allow fetch of user.virtfs namesapce
+             * in case of mapped security
+             */
+            return 0;
+        }
+    }
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    char buffer[PATH_MAX];
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    char buffer[PATH_MAX];
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lremovexattr(rpath(ctx, path, buffer), name);
+}
+
+XattrOperations mapped_user_xattr = {
+    .name = "user.",
+    .getxattr = mp_user_getxattr,
+    .setxattr = mp_user_setxattr,
+    .listxattr = mp_user_listxattr,
+    .removexattr = mp_user_removexattr,
+};
+
+XattrOperations passthrough_user_xattr = {
+    .name = "user.",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.c b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.c
new file mode 100644
index 0000000..bde0b7f
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.c
@@ -0,0 +1,160 @@
+/*
+ * Virtio 9p  xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static XattrOperations *get_xattr_operations(XattrOperations **h,
+                                             const char *name)
+{
+    XattrOperations *xops;
+    for (xops = *(h)++; xops != NULL; xops = *(h)++) {
+        if (!strncmp(name, xops->name, strlen(xops->name))) {
+            return xops;
+        }
+    }
+    return NULL;
+}
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+                       const char *name, void *value, size_t size)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->getxattr(ctx, path, name, value, size);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+}
+
+ssize_t pt_listxattr(FsContext *ctx, const char *path,
+                     char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+
+/*
+ * Get the list and pass to each layer to find out whether
+ * to send the data or not
+ */
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+                        void *value, size_t vsize)
+{
+    ssize_t size = 0;
+    char buffer[PATH_MAX];
+    void *ovalue = value;
+    XattrOperations *xops;
+    char *orig_value, *orig_value_start;
+    ssize_t xattr_len, parsed_len = 0, attr_len;
+
+    /* Get the actual len */
+    xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
+    if (xattr_len <= 0) {
+        return xattr_len;
+    }
+
+    /* Now fetch the xattr and find the actual size */
+    orig_value = qemu_malloc(xattr_len);
+    xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
+
+    /* store the orig pointer */
+    orig_value_start = orig_value;
+    while (xattr_len > parsed_len) {
+        xops = get_xattr_operations(ctx->xops, orig_value);
+        if (!xops) {
+            goto next_entry;
+        }
+
+        if (!value) {
+            size += xops->listxattr(ctx, path, orig_value, value, vsize);
+        } else {
+            size = xops->listxattr(ctx, path, orig_value, value, vsize);
+            if (size < 0) {
+                goto err_out;
+            }
+            value += size;
+            vsize -= size;
+        }
+next_entry:
+        /* Got the next entry */
+        attr_len = strlen(orig_value) + 1;
+        parsed_len += attr_len;
+        orig_value += attr_len;
+    }
+    if (value) {
+        size = value - ovalue;
+    }
+
+err_out:
+    qemu_free(orig_value_start);
+    return size;
+}
+
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                   void *value, size_t size, int flags)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->setxattr(ctx, path, name, value, size, flags);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+int v9fs_remove_xattr(FsContext *ctx,
+                      const char *path, const char *name)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->removexattr(ctx, path, name);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+XattrOperations *mapped_xattr_ops[] = {
+    &mapped_user_xattr,
+    &mapped_pacl_xattr,
+    &mapped_dacl_xattr,
+    NULL,
+};
+
+XattrOperations *passthrough_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &passthrough_acl_xattr,
+    NULL,
+};
+
+/* for .user none model should be same as passthrough */
+XattrOperations *none_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &none_acl_xattr,
+    NULL,
+};
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.h b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.h
new file mode 100644
index 0000000..247e414
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p-xattr.h
@@ -0,0 +1,105 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_9P_XATTR_H
+#define _QEMU_VIRTIO_9P_XATTR_H
+
+#include <attr/xattr.h>
+
+typedef struct xattr_operations
+{
+    const char *name;
+    ssize_t (*getxattr)(FsContext *ctx, const char *path,
+                        const char *name, void *value, size_t size);
+    ssize_t (*listxattr)(FsContext *ctx, const char *path,
+                         char *name, void *value, size_t size);
+    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+                    void *value, size_t size, int flags);
+    int (*removexattr)(FsContext *ctx,
+                       const char *path, const char *name);
+} XattrOperations;
+
+
+extern XattrOperations mapped_user_xattr;
+extern XattrOperations passthrough_user_xattr;
+
+extern XattrOperations mapped_pacl_xattr;
+extern XattrOperations mapped_dacl_xattr;
+extern XattrOperations passthrough_acl_xattr;
+extern XattrOperations none_acl_xattr;
+
+extern XattrOperations *mapped_xattr_ops[];
+extern XattrOperations *passthrough_xattr_ops[];
+extern XattrOperations *none_xattr_ops[];
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
+                       void *value, size_t size);
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
+                        size_t vsize);
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                          void *value, size_t size, int flags);
+int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
+ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
+                     size_t size);
+
+static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value, size_t size)
+{
+    char buffer[PATH_MAX];
+    return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+}
+
+static inline int pt_setxattr(FsContext *ctx, const char *path,
+                              const char *name, void *value,
+                              size_t size, int flags)
+{
+    char buffer[PATH_MAX];
+    return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+                                 const char *path, const char *name)
+{
+    char buffer[PATH_MAX];
+    return lremovexattr(rpath(ctx, path, buffer), name);
+}
+
+static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+                                      const char *name, void *value,
+                                      size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline int notsup_setxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value,
+                                  size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+                                       char *name, void *value, size_t size)
+{
+    return 0;
+}
+
+static inline int notsup_removexattr(FsContext *ctx,
+                                     const char *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p.c b/qemu-0.15.x/hw/9pfs/virtio-9p.c
new file mode 100644
index 0000000..4890df6
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p.c
@@ -0,0 +1,3652 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
+#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-debug.h"
+#include "virtio-9p-xattr.h"
+
+int debug_9p_pdu;
+
+enum {
+    Oread   = 0x00,
+    Owrite  = 0x01,
+    Ordwr   = 0x02,
+    Oexec   = 0x03,
+    Oexcl   = 0x04,
+    Otrunc  = 0x10,
+    Orexec  = 0x20,
+    Orclose = 0x40,
+    Oappend = 0x80,
+};
+
+static int omode_to_uflags(int8_t mode)
+{
+    int ret = 0;
+
+    switch (mode & 3) {
+    case Oread:
+        ret = O_RDONLY;
+        break;
+    case Ordwr:
+        ret = O_RDWR;
+        break;
+    case Owrite:
+        ret = O_WRONLY;
+        break;
+    case Oexec:
+        ret = O_RDONLY;
+        break;
+    }
+
+    if (mode & Otrunc) {
+        ret |= O_TRUNC;
+    }
+
+    if (mode & Oappend) {
+        ret |= O_APPEND;
+    }
+
+    if (mode & Oexcl) {
+        ret |= O_EXCL;
+    }
+
+    return ret;
+}
+
+void cred_init(FsCred *credp)
+{
+    credp->fc_uid = -1;
+    credp->fc_gid = -1;
+    credp->fc_mode = -1;
+    credp->fc_rdev = -1;
+}
+
+static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
+{
+    return s->ops->lstat(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
+{
+    ssize_t len;
+
+    buf->data = qemu_malloc(1024);
+
+    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
+    if (len > -1) {
+        buf->size = len;
+        buf->data[len] = 0;
+    }
+
+    return len;
+}
+
+static int v9fs_do_close(V9fsState *s, int fd)
+{
+    return s->ops->close(&s->ctx, fd);
+}
+
+static int v9fs_do_closedir(V9fsState *s, DIR *dir)
+{
+    return s->ops->closedir(&s->ctx, dir);
+}
+
+static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
+{
+    return s->ops->open(&s->ctx, path->data, flags);
+}
+
+static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
+{
+    return s->ops->opendir(&s->ctx, path->data);
+}
+
+static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
+{
+    return s->ops->rewinddir(&s->ctx, dir);
+}
+
+static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
+{
+    return s->ops->telldir(&s->ctx, dir);
+}
+
+static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
+{
+    return s->ops->readdir(&s->ctx, dir);
+}
+
+static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
+{
+    return s->ops->seekdir(&s->ctx, dir, off);
+}
+
+static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
+                            int iovcnt, int64_t offset)
+{
+    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+}
+
+static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
+                       int iovcnt, int64_t offset)
+{
+    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+}
+
+static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_mode = mode;
+    return s->ops->chmod(&s->ctx, path->data, &cred);
+}
+
+static int v9fs_do_mknod(V9fsState *s, char *name,
+        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode;
+    cred.fc_rdev = dev;
+    return s->ops->mknod(&s->ctx, name, &cred);
+}
+
+static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
+                uid_t uid, gid_t gid)
+{
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode;
+
+    return s->ops->mkdir(&s->ctx, name, &cred);
+}
+
+static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
+{
+    return s->ops->fstat(&s->ctx, fd, stbuf);
+}
+
+static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
+        int flags, int mode)
+{
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode & 07777;
+
+    return s->ops->open2(&s->ctx, fullname, flags, &cred);
+}
+
+static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
+        const char *oldpath, const char *newpath, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = 0777;
+
+    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+}
+
+static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+{
+    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
+}
+
+static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
+{
+    return s->ops->truncate(&s->ctx, path->data, size);
+}
+
+static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
+                            V9fsString *newpath)
+{
+    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
+}
+
+static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+
+    return s->ops->chown(&s->ctx, path->data, &cred);
+}
+
+static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
+                                           const struct timespec times[2])
+{
+    return s->ops->utimensat(&s->ctx, path->data, times);
+}
+
+static int v9fs_do_remove(V9fsState *s, V9fsString *path)
+{
+    return s->ops->remove(&s->ctx, path->data);
+}
+
+static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
+{
+    return s->ops->fsync(&s->ctx, fd, datasync);
+}
+
+static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+{
+    return s->ops->statfs(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size)
+{
+    return s->ops->lgetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size);
+}
+
+static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
+                              void *value, size_t size)
+{
+    return s->ops->llistxattr(&s->ctx, path->data,
+                              value, size);
+}
+
+static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size, int flags)
+{
+    return s->ops->lsetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size, flags);
+}
+
+static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
+                                V9fsString *xattr_name)
+{
+    return s->ops->lremovexattr(&s->ctx, path->data,
+                                xattr_name->data);
+}
+
+
+static void v9fs_string_init(V9fsString *str)
+{
+    str->data = NULL;
+    str->size = 0;
+}
+
+static void v9fs_string_free(V9fsString *str)
+{
+    qemu_free(str->data);
+    str->data = NULL;
+    str->size = 0;
+}
+
+static void v9fs_string_null(V9fsString *str)
+{
+    v9fs_string_free(str);
+}
+
+static int number_to_string(void *arg, char type)
+{
+    unsigned int ret = 0;
+
+    switch (type) {
+    case 'u': {
+        unsigned int num = *(unsigned int *)arg;
+
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
+    case 'U': {
+        unsigned long num = *(unsigned long *)arg;
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
+    default:
+        printf("Number_to_string: Unknown number format\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+static int GCC_FMT_ATTR(2, 0)
+v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
+{
+    va_list ap2;
+    char *iter = (char *)fmt;
+    int len = 0;
+    int nr_args = 0;
+    char *arg_char_ptr;
+    unsigned int arg_uint;
+    unsigned long arg_ulong;
+
+    /* Find the number of %'s that denotes an argument */
+    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
+        nr_args++;
+        iter++;
+    }
+
+    len = strlen(fmt) - 2*nr_args;
+
+    if (!nr_args) {
+        goto alloc_print;
+    }
+
+    va_copy(ap2, ap);
+
+    iter = (char *)fmt;
+
+    /* Now parse the format string */
+    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
+        iter++;
+        switch (*iter) {
+        case 'u':
+            arg_uint = va_arg(ap2, unsigned int);
+            len += number_to_string((void *)&arg_uint, 'u');
+            break;
+        case 'l':
+            if (*++iter == 'u') {
+                arg_ulong = va_arg(ap2, unsigned long);
+                len += number_to_string((void *)&arg_ulong, 'U');
+            } else {
+                return -1;
+            }
+            break;
+        case 's':
+            arg_char_ptr = va_arg(ap2, char *);
+            len += strlen(arg_char_ptr);
+            break;
+        case 'c':
+            len += 1;
+            break;
+        default:
+            fprintf(stderr,
+		    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
+            return -1;
+        }
+        iter++;
+    }
+
+alloc_print:
+    *strp = qemu_malloc((len + 1) * sizeof(**strp));
+
+    return vsprintf(*strp, fmt, ap);
+}
+
+static void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+{
+    va_list ap;
+    int err;
+
+    v9fs_string_free(str);
+
+    va_start(ap, fmt);
+    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
+    BUG_ON(err == -1);
+    va_end(ap);
+
+    str->size = err;
+}
+
+static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+{
+    v9fs_string_free(lhs);
+    v9fs_string_sprintf(lhs, "%s", rhs->data);
+}
+
+/*
+ * Return TRUE if s1 is an ancestor of s2.
+ *
+ * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
+ * As a special case, We treat s1 as ancestor of s2 if they are same!
+ */
+static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+{
+    if (!strncmp(s1->data, s2->data, s1->size)) {
+        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static size_t v9fs_string_size(V9fsString *str)
+{
+    return str->size;
+}
+
+static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState *f;
+
+    for (f = s->fid_list; f; f = f->next) {
+        if (f->fid == fid) {
+            return f;
+        }
+    }
+
+    return NULL;
+}
+
+static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState *f;
+
+    f = lookup_fid(s, fid);
+    if (f) {
+        return NULL;
+    }
+
+    f = qemu_mallocz(sizeof(V9fsFidState));
+
+    f->fid = fid;
+    f->fid_type = P9_FID_NONE;
+
+    f->next = s->fid_list;
+    s->fid_list = f;
+
+    return f;
+}
+
+static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+{
+    int retval = 0;
+
+    if (fidp->fs.xattr.copied_len == -1) {
+        /* getxattr/listxattr fid */
+        goto free_value;
+    }
+    /*
+     * if this is fid for setxattr. clunk should
+     * result in setxattr localcall
+     */
+    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
+        /* clunk after partial write */
+        retval = -EINVAL;
+        goto free_out;
+    }
+    if (fidp->fs.xattr.len) {
+        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+                                   fidp->fs.xattr.value,
+                                   fidp->fs.xattr.len,
+                                   fidp->fs.xattr.flags);
+    } else {
+        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+    }
+free_out:
+    v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+    if (fidp->fs.xattr.value) {
+        qemu_free(fidp->fs.xattr.value);
+    }
+    return retval;
+}
+
+static int free_fid(V9fsState *s, int32_t fid)
+{
+    int retval = 0;
+    V9fsFidState **fidpp, *fidp;
+
+    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
+        if ((*fidpp)->fid == fid) {
+            break;
+        }
+    }
+
+    if (*fidpp == NULL) {
+        return -ENOENT;
+    }
+
+    fidp = *fidpp;
+    *fidpp = fidp->next;
+
+    if (fidp->fid_type == P9_FID_FILE) {
+        v9fs_do_close(s, fidp->fs.fd);
+    } else if (fidp->fid_type == P9_FID_DIR) {
+        v9fs_do_closedir(s, fidp->fs.dir);
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        retval = v9fs_xattr_fid_clunk(s, fidp);
+    }
+    v9fs_string_free(&fidp->path);
+    qemu_free(fidp);
+
+    return retval;
+}
+
+#define P9_QID_TYPE_DIR         0x80
+#define P9_QID_TYPE_SYMLINK     0x02
+
+#define P9_STAT_MODE_DIR        0x80000000
+#define P9_STAT_MODE_APPEND     0x40000000
+#define P9_STAT_MODE_EXCL       0x20000000
+#define P9_STAT_MODE_MOUNT      0x10000000
+#define P9_STAT_MODE_AUTH       0x08000000
+#define P9_STAT_MODE_TMP        0x04000000
+#define P9_STAT_MODE_SYMLINK    0x02000000
+#define P9_STAT_MODE_LINK       0x01000000
+#define P9_STAT_MODE_DEVICE     0x00800000
+#define P9_STAT_MODE_NAMED_PIPE 0x00200000
+#define P9_STAT_MODE_SOCKET     0x00100000
+#define P9_STAT_MODE_SETUID     0x00080000
+#define P9_STAT_MODE_SETGID     0x00040000
+#define P9_STAT_MODE_SETVTX     0x00010000
+
+#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
+                                P9_STAT_MODE_SYMLINK |      \
+                                P9_STAT_MODE_LINK |         \
+                                P9_STAT_MODE_DEVICE |       \
+                                P9_STAT_MODE_NAMED_PIPE |   \
+                                P9_STAT_MODE_SOCKET)
+
+/* This is the algorithm from ufs in spfs */
+static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
+{
+    size_t size;
+
+    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
+    memcpy(&qidp->path, &stbuf->st_ino, size);
+    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
+    qidp->type = 0;
+    if (S_ISDIR(stbuf->st_mode)) {
+        qidp->type |= P9_QID_TYPE_DIR;
+    }
+    if (S_ISLNK(stbuf->st_mode)) {
+        qidp->type |= P9_QID_TYPE_SYMLINK;
+    }
+}
+
+static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
+{
+    struct stat stbuf;
+    int err;
+
+    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
+    if (err) {
+        return err;
+    }
+
+    stat_to_qid(&stbuf, qidp);
+    return 0;
+}
+
+static V9fsPDU *alloc_pdu(V9fsState *s)
+{
+    V9fsPDU *pdu = NULL;
+
+    if (!QLIST_EMPTY(&s->free_list)) {
+	pdu = QLIST_FIRST(&s->free_list);
+	QLIST_REMOVE(pdu, next);
+    }
+    return pdu;
+}
+
+static void free_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    if (pdu) {
+        if (debug_9p_pdu) {
+            pprint_pdu(pdu);
+        }
+        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+    }
+}
+
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size, int pack)
+{
+    int i = 0;
+    size_t copied = 0;
+
+    for (i = 0; size && i < sg_count; i++) {
+        size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
+            len = MIN(sg[i].iov_len - offset, size);
+            if (pack) {
+                memcpy(sg[i].iov_base + offset, addr, len);
+            } else {
+                memcpy(addr, sg[i].iov_base + offset, len);
+            }
+            size -= len;
+            copied += len;
+            addr += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
+        }
+    }
+
+    return copied;
+}
+
+static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
+                         offset, size, 0);
+}
+
+static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
+                        size_t size)
+{
+    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
+                             offset, size, 1);
+}
+
+static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
+{
+    size_t pos = 0;
+    int i, j;
+    struct iovec *src_sg;
+    unsigned int num;
+
+    if (rx) {
+        src_sg = pdu->elem.in_sg;
+        num = pdu->elem.in_num;
+    } else {
+        src_sg = pdu->elem.out_sg;
+        num = pdu->elem.out_num;
+    }
+
+    j = 0;
+    for (i = 0; i < num; i++) {
+        if (offset <= pos) {
+            sg[j].iov_base = src_sg[i].iov_base;
+            sg[j].iov_len = src_sg[i].iov_len;
+            j++;
+        } else if (offset < (src_sg[i].iov_len + pos)) {
+            sg[j].iov_base = src_sg[i].iov_base;
+            sg[j].iov_len = src_sg[i].iov_len;
+            sg[j].iov_base += (offset - pos);
+            sg[j].iov_len -= (offset - pos);
+            j++;
+        }
+        pos += src_sg[i].iov_len;
+    }
+
+    return j;
+}
+
+static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+{
+    size_t old_offset = offset;
+    va_list ap;
+    int i;
+
+    va_start(ap, fmt);
+    for (i = 0; fmt[i]; i++) {
+        switch (fmt[i]) {
+        case 'b': {
+            uint8_t *valp = va_arg(ap, uint8_t *);
+            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
+            break;
+        }
+        case 'w': {
+            uint16_t val, *valp;
+            valp = va_arg(ap, uint16_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le16_to_cpu(val);
+            break;
+        }
+        case 'd': {
+            uint32_t val, *valp;
+            valp = va_arg(ap, uint32_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le32_to_cpu(val);
+            break;
+        }
+        case 'q': {
+            uint64_t val, *valp;
+            valp = va_arg(ap, uint64_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le64_to_cpu(val);
+            break;
+        }
+        case 'v': {
+            struct iovec *iov = va_arg(ap, struct iovec *);
+            int *iovcnt = va_arg(ap, int *);
+            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
+            break;
+        }
+        case 's': {
+            V9fsString *str = va_arg(ap, V9fsString *);
+            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
+            /* FIXME: sanity check str->size */
+            str->data = qemu_malloc(str->size + 1);
+            offset += pdu_unpack(str->data, pdu, offset, str->size);
+            str->data[str->size] = 0;
+            break;
+        }
+        case 'Q': {
+            V9fsQID *qidp = va_arg(ap, V9fsQID *);
+            offset += pdu_unmarshal(pdu, offset, "bdq",
+                        &qidp->type, &qidp->version, &qidp->path);
+            break;
+        }
+        case 'S': {
+            V9fsStat *statp = va_arg(ap, V9fsStat *);
+            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
+                        &statp->size, &statp->type, &statp->dev,
+                        &statp->qid, &statp->mode, &statp->atime,
+                        &statp->mtime, &statp->length,
+                        &statp->name, &statp->uid, &statp->gid,
+                        &statp->muid, &statp->extension,
+                        &statp->n_uid, &statp->n_gid,
+                        &statp->n_muid);
+            break;
+        }
+        case 'I': {
+            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
+            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
+                        &iattr->valid, &iattr->mode,
+                        &iattr->uid, &iattr->gid, &iattr->size,
+                        &iattr->atime_sec, &iattr->atime_nsec,
+                        &iattr->mtime_sec, &iattr->mtime_nsec);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    va_end(ap);
+
+    return offset - old_offset;
+}
+
+static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+{
+    size_t old_offset = offset;
+    va_list ap;
+    int i;
+
+    va_start(ap, fmt);
+    for (i = 0; fmt[i]; i++) {
+        switch (fmt[i]) {
+        case 'b': {
+            uint8_t val = va_arg(ap, int);
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'w': {
+            uint16_t val;
+            cpu_to_le16w(&val, va_arg(ap, int));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'd': {
+            uint32_t val;
+            cpu_to_le32w(&val, va_arg(ap, uint32_t));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'q': {
+            uint64_t val;
+            cpu_to_le64w(&val, va_arg(ap, uint64_t));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'v': {
+            struct iovec *iov = va_arg(ap, struct iovec *);
+            int *iovcnt = va_arg(ap, int *);
+            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
+            break;
+        }
+        case 's': {
+            V9fsString *str = va_arg(ap, V9fsString *);
+            offset += pdu_marshal(pdu, offset, "w", str->size);
+            offset += pdu_pack(pdu, offset, str->data, str->size);
+            break;
+        }
+        case 'Q': {
+            V9fsQID *qidp = va_arg(ap, V9fsQID *);
+            offset += pdu_marshal(pdu, offset, "bdq",
+                        qidp->type, qidp->version, qidp->path);
+            break;
+        }
+        case 'S': {
+            V9fsStat *statp = va_arg(ap, V9fsStat *);
+            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
+                        statp->size, statp->type, statp->dev,
+                        &statp->qid, statp->mode, statp->atime,
+                        statp->mtime, statp->length, &statp->name,
+                        &statp->uid, &statp->gid, &statp->muid,
+                        &statp->extension, statp->n_uid,
+                        statp->n_gid, statp->n_muid);
+            break;
+        }
+        case 'A': {
+            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
+            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
+                        statp->st_result_mask,
+                        &statp->qid, statp->st_mode,
+                        statp->st_uid, statp->st_gid,
+                        statp->st_nlink, statp->st_rdev,
+                        statp->st_size, statp->st_blksize, statp->st_blocks,
+                        statp->st_atime_sec, statp->st_atime_nsec,
+                        statp->st_mtime_sec, statp->st_mtime_nsec,
+                        statp->st_ctime_sec, statp->st_ctime_nsec,
+                        statp->st_btime_sec, statp->st_btime_nsec,
+                        statp->st_gen, statp->st_data_version);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    va_end(ap);
+
+    return offset - old_offset;
+}
+
+static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
+{
+    int8_t id = pdu->id + 1; /* Response */
+
+    if (len < 0) {
+        int err = -len;
+        len = 7;
+
+        if (s->proto_version != V9FS_PROTO_2000L) {
+            V9fsString str;
+
+            str.data = strerror(err);
+            str.size = strlen(str.data);
+
+            len += pdu_marshal(pdu, len, "s", &str);
+            id = P9_RERROR;
+        }
+
+        len += pdu_marshal(pdu, len, "d", err);
+
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            id = P9_RLERROR;
+        }
+    }
+
+    /* fill out the header */
+    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
+
+    /* keep these in sync */
+    pdu->size = len;
+    pdu->id = id;
+
+    /* push onto queue and notify */
+    virtqueue_push(s->vq, &pdu->elem, len);
+
+    /* FIXME: we should batch these completions */
+    virtio_notify(&s->vdev, s->vq);
+
+    free_pdu(s, pdu);
+}
+
+static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
+{
+    mode_t ret;
+
+    ret = mode & 0777;
+    if (mode & P9_STAT_MODE_DIR) {
+        ret |= S_IFDIR;
+    }
+
+    if (mode & P9_STAT_MODE_SYMLINK) {
+        ret |= S_IFLNK;
+    }
+    if (mode & P9_STAT_MODE_SOCKET) {
+        ret |= S_IFSOCK;
+    }
+    if (mode & P9_STAT_MODE_NAMED_PIPE) {
+        ret |= S_IFIFO;
+    }
+    if (mode & P9_STAT_MODE_DEVICE) {
+        if (extension && extension->data[0] == 'c') {
+            ret |= S_IFCHR;
+        } else {
+            ret |= S_IFBLK;
+        }
+    }
+
+    if (!(ret&~0777)) {
+        ret |= S_IFREG;
+    }
+
+    if (mode & P9_STAT_MODE_SETUID) {
+        ret |= S_ISUID;
+    }
+    if (mode & P9_STAT_MODE_SETGID) {
+        ret |= S_ISGID;
+    }
+    if (mode & P9_STAT_MODE_SETVTX) {
+        ret |= S_ISVTX;
+    }
+
+    return ret;
+}
+
+static int donttouch_stat(V9fsStat *stat)
+{
+    if (stat->type == -1 &&
+        stat->dev == -1 &&
+        stat->qid.type == -1 &&
+        stat->qid.version == -1 &&
+        stat->qid.path == -1 &&
+        stat->mode == -1 &&
+        stat->atime == -1 &&
+        stat->mtime == -1 &&
+        stat->length == -1 &&
+        !stat->name.size &&
+        !stat->uid.size &&
+        !stat->gid.size &&
+        !stat->muid.size &&
+        stat->n_uid == -1 &&
+        stat->n_gid == -1 &&
+        stat->n_muid == -1) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void v9fs_stat_free(V9fsStat *stat)
+{
+    v9fs_string_free(&stat->name);
+    v9fs_string_free(&stat->uid);
+    v9fs_string_free(&stat->gid);
+    v9fs_string_free(&stat->muid);
+    v9fs_string_free(&stat->extension);
+}
+
+static uint32_t stat_to_v9mode(const struct stat *stbuf)
+{
+    uint32_t mode;
+
+    mode = stbuf->st_mode & 0777;
+    if (S_ISDIR(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_DIR;
+    }
+
+    if (S_ISLNK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SYMLINK;
+    }
+
+    if (S_ISSOCK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SOCKET;
+    }
+
+    if (S_ISFIFO(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_NAMED_PIPE;
+    }
+
+    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_DEVICE;
+    }
+
+    if (stbuf->st_mode & S_ISUID) {
+        mode |= P9_STAT_MODE_SETUID;
+    }
+
+    if (stbuf->st_mode & S_ISGID) {
+        mode |= P9_STAT_MODE_SETGID;
+    }
+
+    if (stbuf->st_mode & S_ISVTX) {
+        mode |= P9_STAT_MODE_SETVTX;
+    }
+
+    return mode;
+}
+
+static int stat_to_v9stat(V9fsState *s, V9fsString *name,
+                            const struct stat *stbuf,
+                            V9fsStat *v9stat)
+{
+    int err;
+    const char *str;
+
+    memset(v9stat, 0, sizeof(*v9stat));
+
+    stat_to_qid(stbuf, &v9stat->qid);
+    v9stat->mode = stat_to_v9mode(stbuf);
+    v9stat->atime = stbuf->st_atime;
+    v9stat->mtime = stbuf->st_mtime;
+    v9stat->length = stbuf->st_size;
+
+    v9fs_string_null(&v9stat->uid);
+    v9fs_string_null(&v9stat->gid);
+    v9fs_string_null(&v9stat->muid);
+
+    v9stat->n_uid = stbuf->st_uid;
+    v9stat->n_gid = stbuf->st_gid;
+    v9stat->n_muid = 0;
+
+    v9fs_string_null(&v9stat->extension);
+
+    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_do_readlink(s, name, &v9stat->extension);
+        if (err == -1) {
+            err = -errno;
+            return err;
+        }
+        v9stat->extension.data[err] = 0;
+        v9stat->extension.size = err;
+    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
+        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
+                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
+                major(stbuf->st_rdev), minor(stbuf->st_rdev));
+    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
+        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
+                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
+    }
+
+    str = strrchr(name->data, '/');
+    if (str) {
+        str += 1;
+    } else {
+        str = name->data;
+    }
+
+    v9fs_string_sprintf(&v9stat->name, "%s", str);
+
+    v9stat->size = 61 +
+        v9fs_string_size(&v9stat->name) +
+        v9fs_string_size(&v9stat->uid) +
+        v9fs_string_size(&v9stat->gid) +
+        v9fs_string_size(&v9stat->muid) +
+        v9fs_string_size(&v9stat->extension);
+    return 0;
+}
+
+#define P9_STATS_MODE          0x00000001ULL
+#define P9_STATS_NLINK         0x00000002ULL
+#define P9_STATS_UID           0x00000004ULL
+#define P9_STATS_GID           0x00000008ULL
+#define P9_STATS_RDEV          0x00000010ULL
+#define P9_STATS_ATIME         0x00000020ULL
+#define P9_STATS_MTIME         0x00000040ULL
+#define P9_STATS_CTIME         0x00000080ULL
+#define P9_STATS_INO           0x00000100ULL
+#define P9_STATS_SIZE          0x00000200ULL
+#define P9_STATS_BLOCKS        0x00000400ULL
+
+#define P9_STATS_BTIME         0x00000800ULL
+#define P9_STATS_GEN           0x00001000ULL
+#define P9_STATS_DATA_VERSION  0x00002000ULL
+
+#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
+
+
+static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
+                            V9fsStatDotl *v9lstat)
+{
+    memset(v9lstat, 0, sizeof(*v9lstat));
+
+    v9lstat->st_mode = stbuf->st_mode;
+    v9lstat->st_nlink = stbuf->st_nlink;
+    v9lstat->st_uid = stbuf->st_uid;
+    v9lstat->st_gid = stbuf->st_gid;
+    v9lstat->st_rdev = stbuf->st_rdev;
+    v9lstat->st_size = stbuf->st_size;
+    v9lstat->st_blksize = stbuf->st_blksize;
+    v9lstat->st_blocks = stbuf->st_blocks;
+    v9lstat->st_atime_sec = stbuf->st_atime;
+    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
+    v9lstat->st_mtime_sec = stbuf->st_mtime;
+    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
+    v9lstat->st_ctime_sec = stbuf->st_ctime;
+    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
+    /* Currently we only support BASIC fields in stat */
+    v9lstat->st_result_mask = P9_STATS_BASIC;
+
+    stat_to_qid(stbuf, &v9lstat->qid);
+}
+
+static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
+{
+    while (len && *iovcnt) {
+        if (len < sg->iov_len) {
+            sg->iov_len -= len;
+            sg->iov_base += len;
+            len = 0;
+        } else {
+            len -= sg->iov_len;
+            sg++;
+            *iovcnt -= 1;
+        }
+    }
+
+    return sg;
+}
+
+static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
+{
+    int i;
+    int total = 0;
+
+    for (i = 0; i < *cnt; i++) {
+        if ((total + sg[i].iov_len) > cap) {
+            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
+            i++;
+            break;
+        }
+        total += sg[i].iov_len;
+    }
+
+    *cnt = i;
+
+    return sg;
+}
+
+static void print_sg(struct iovec *sg, int cnt)
+{
+    int i;
+
+    printf("sg[%d]: {", cnt);
+    for (i = 0; i < cnt; i++) {
+        if (i) {
+            printf(", ");
+        }
+        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
+    }
+    printf("}\n");
+}
+
+static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
+{
+    V9fsString str;
+    v9fs_string_init(&str);
+    v9fs_string_copy(&str, dst);
+    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
+    v9fs_string_free(&str);
+}
+
+static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
+{
+    V9fsString version;
+    size_t offset = 7;
+
+    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
+
+    if (!strcmp(version.data, "9P2000.u")) {
+        s->proto_version = V9FS_PROTO_2000U;
+    } else if (!strcmp(version.data, "9P2000.L")) {
+        s->proto_version = V9FS_PROTO_2000L;
+    } else {
+        v9fs_string_sprintf(&version, "unknown");
+    }
+
+    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
+    complete_pdu(s, pdu, offset);
+
+    v9fs_string_free(&version);
+}
+
+static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, afid, n_uname;
+    V9fsString uname, aname;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    size_t offset = 7;
+    ssize_t err;
+
+    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
+
+    fidp = alloc_fid(s, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    fidp->uid = n_uname;
+
+    v9fs_string_sprintf(&fidp->path, "%s", "/");
+    err = fid_to_qid(s, fidp, &qid);
+    if (err) {
+        err = -EINVAL;
+        free_fid(s, fid);
+        goto out;
+    }
+
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+
+    err = offset;
+out:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&uname);
+    v9fs_string_free(&aname);
+}
+
+static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
+    if (err) {
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_stat_free(&vs->v9stat);
+    qemu_free(vs);
+}
+
+static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsStatState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+    v9fs_stat_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_stat_free(&vs->v9stat);
+    qemu_free(vs);
+}
+
+static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
+                                                                int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsStatStateDotl *vs;
+    ssize_t err = 0;
+    V9fsFidState *fidp;
+    uint64_t request_mask;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    /* Currently we only support BASIC fields in stat, so there is no
+     * need to look at request_mask.
+     */
+    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
+    v9fs_getattr_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+/* From Linux kernel code */
+#define ATTR_MODE    (1 << 0)
+#define ATTR_UID     (1 << 1)
+#define ATTR_GID     (1 << 2)
+#define ATTR_SIZE    (1 << 3)
+#define ATTR_ATIME   (1 << 4)
+#define ATTR_MTIME   (1 << 5)
+#define ATTR_CTIME   (1 << 6)
+#define ATTR_MASK    127
+#define ATTR_ATIME_SET  (1 << 7)
+#define ATTR_MTIME_SET  (1 << 8)
+
+static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
+                                                                  int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_SIZE)) {
+        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
+    }
+    v9fs_setattr_post_truncate(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
+                                                                   int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    /* If the only valid entry in iattr is ctime we can call
+     * chown(-1,-1) to update the ctime of the file
+     */
+    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
+            ((vs->v9iattr.valid & ATTR_CTIME)
+            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+        if (!(vs->v9iattr.valid & ATTR_UID)) {
+            vs->v9iattr.uid = -1;
+        }
+        if (!(vs->v9iattr.valid & ATTR_GID)) {
+            vs->v9iattr.gid = -1;
+        }
+        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
+                                                vs->v9iattr.gid);
+    }
+    v9fs_setattr_post_chown(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+        struct timespec times[2];
+        if (vs->v9iattr.valid & ATTR_ATIME) {
+            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
+                times[0].tv_sec = vs->v9iattr.atime_sec;
+                times[0].tv_nsec = vs->v9iattr.atime_nsec;
+            } else {
+                times[0].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+
+        if (vs->v9iattr.valid & ATTR_MTIME) {
+            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
+                times[1].tv_sec = vs->v9iattr.mtime_sec;
+                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
+            } else {
+                times[1].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
+    }
+    v9fs_setattr_post_utimensat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsSetattrState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & ATTR_MODE) {
+        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
+    }
+
+    v9fs_setattr_post_chmod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
+{
+    complete_pdu(s, vs->pdu, err);
+
+    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
+        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
+            v9fs_string_free(&vs->wnames[vs->name_idx]);
+        }
+
+        qemu_free(vs->wnames);
+        qemu_free(vs->qids);
+    }
+}
+
+static void v9fs_walk_marshal(V9fsWalkState *vs)
+{
+    int i;
+    vs->offset = 7;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
+
+    for (i = 0; i < vs->nwnames; i++) {
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
+    }
+}
+
+static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
+                                                                int err)
+{
+    if (err == -1) {
+        free_fid(s, vs->newfidp->fid);
+        v9fs_string_free(&vs->path);
+        err = -ENOENT;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
+
+    vs->name_idx++;
+    if (vs->name_idx < vs->nwnames) {
+        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
+                                            vs->wnames[vs->name_idx].data);
+        v9fs_string_copy(&vs->newfidp->path, &vs->path);
+
+        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
+        v9fs_walk_post_newfid_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_string_free(&vs->path);
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
+        int err)
+{
+    if (err == -1) {
+        v9fs_string_free(&vs->path);
+        err = -ENOENT;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
+    vs->name_idx++;
+    if (vs->name_idx < vs->nwnames) {
+
+        v9fs_string_sprintf(&vs->path, "%s/%s",
+                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
+        v9fs_string_copy(&vs->fidp->path, &vs->path);
+
+        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+        v9fs_walk_post_oldfid_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_string_free(&vs->path);
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, newfid;
+    V9fsWalkState *vs;
+    int err = 0;
+    int i;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->wnames = NULL;
+    vs->qids = NULL;
+    vs->offset = 7;
+
+    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
+                                            &newfid, &vs->nwnames);
+
+    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
+        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
+
+        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
+
+        for (i = 0; i < vs->nwnames; i++) {
+            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
+                                            &vs->wnames[i]);
+        }
+    } else if (vs->nwnames > P9_MAXWELEM) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    /* FIXME: is this really valid? */
+    if (fid == newfid) {
+
+        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+        v9fs_string_init(&vs->path);
+        vs->name_idx = 0;
+
+        if (vs->name_idx < vs->nwnames) {
+            v9fs_string_sprintf(&vs->path, "%s/%s",
+                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
+            v9fs_string_copy(&vs->fidp->path, &vs->path);
+
+            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+            v9fs_walk_post_oldfid_lstat(s, vs, err);
+            return;
+        }
+    } else {
+        vs->newfidp = alloc_fid(s, newfid);
+        if (vs->newfidp == NULL) {
+            err = -EINVAL;
+            goto out;
+        }
+
+        vs->newfidp->uid = vs->fidp->uid;
+        v9fs_string_init(&vs->path);
+        vs->name_idx = 0;
+        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
+
+        if (vs->name_idx < vs->nwnames) {
+            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
+                                vs->wnames[vs->name_idx].data);
+            v9fs_string_copy(&vs->newfidp->path, &vs->path);
+
+            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
+            v9fs_walk_post_newfid_lstat(s, vs, err);
+            return;
+        }
+    }
+
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static int32_t get_iounit(V9fsState *s, V9fsString *name)
+{
+    struct statfs stbuf;
+    int32_t iounit = 0;
+
+    /*
+     * iounit should be multiples of f_bsize (host filesystem block size
+     * and as well as less than (client msize - P9_IOHDRSZ))
+     */
+    if (!v9fs_do_statfs(s, name, &stbuf)) {
+        iounit = stbuf.f_bsize;
+        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
+    }
+
+    if (!iounit) {
+        iounit = s->msize - P9_IOHDRSZ;
+    }
+    return iounit;
+}
+
+static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    if (vs->fidp->fs.dir == NULL) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_DIR;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+
+}
+
+static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
+{
+    int err;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    vs->iounit = get_iounit(s, &vs->fidp->path);
+    v9fs_open_post_getiounit(s, vs);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    int flags;
+
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+
+    if (S_ISDIR(vs->stbuf.st_mode)) {
+        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
+        v9fs_open_post_opendir(s, vs, err);
+    } else {
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            flags = vs->mode;
+            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+            /* Ignore direct disk access hint until the server supports it. */
+            flags &= ~O_DIRECT;
+        } else {
+            flags = omode_to_uflags(vs->mode);
+        }
+        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
+        v9fs_open_post_open(s, vs, err);
+    }
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsOpenState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->mode = 0;
+
+    if (s->proto_version == V9FS_PROTO_2000L) {
+        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
+    } else {
+        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
+    }
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+
+    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+
+    v9fs_open_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
+{
+    if (err == 0) {
+        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+        stat_to_qid(&vs->stbuf, &vs->qid);
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
+                vs->iounit);
+        err = vs->offset;
+    } else {
+        vs->fidp->fid_type = P9_FID_NONE;
+        err = -errno;
+        if (vs->fidp->fs.fd > 0) {
+            close(vs->fidp->fs.fd);
+        }
+    }
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
+        int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+
+out:
+    v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
+        int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    vs->iounit =  get_iounit(s, &vs->fullname);
+    v9fs_lcreate_post_get_iounit(s, vs, err);
+    return;
+
+out:
+    v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, flags, mode;
+    gid_t gid;
+    V9fsLcreateState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
+            &mode, &gid);
+
+    vs->fidp = lookup_fid(s, dfid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+             vs->name.data);
+
+    /* Ignore direct disk access hint until the server supports it. */
+    flags &= ~O_DIRECT;
+
+    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+            gid, flags, mode);
+    v9fs_lcreate_post_do_open2(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    int datasync;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        v9fs_post_do_fsync(s, pdu, err);
+        return;
+    }
+    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
+    v9fs_post_do_fsync(s, pdu, err);
+}
+
+static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+
+    err = free_fid(s, fid);
+    if (err < 0) {
+        goto out;
+    }
+
+    offset = 7;
+    err = offset;
+out:
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
+
+static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (err) {
+        goto out;
+    }
+    v9fs_stat_free(&vs->v9stat);
+    v9fs_string_free(&vs->name);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
+                                    ssize_t err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
+    if (err) {
+        goto out;
+    }
+
+    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
+                            &vs->v9stat);
+    if ((vs->len != (vs->v9stat.size + 2)) ||
+            ((vs->count + vs->len) > vs->max_count)) {
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
+        v9fs_read_post_seekdir(s, vs, err);
+        return;
+    }
+    vs->count += vs->len;
+    v9fs_stat_free(&vs->v9stat);
+    v9fs_string_free(&vs->name);
+    vs->dir_pos = vs->dent->d_off;
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_read_post_readdir(s, vs, err);
+    return;
+out:
+    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
+    v9fs_read_post_seekdir(s, vs, err);
+    return;
+
+}
+
+static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (vs->dent) {
+        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
+        v9fs_string_init(&vs->name);
+        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
+                            vs->dent->d_name);
+        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
+        v9fs_read_post_dir_lstat(s, vs, err);
+        return;
+    }
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_read_post_readdir(s, vs, err);
+    return;
+}
+
+static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
+                                       ssize_t err)
+{
+    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+    v9fs_read_post_telldir(s, vs, err);
+    return;
+}
+
+static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (err  < 0) {
+        /* IO error return the error */
+        err = -errno;
+        goto out;
+    }
+    vs->total += vs->len;
+    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
+    if (vs->total < vs->count && vs->len > 0) {
+        do {
+            if (0) {
+                print_sg(vs->sg, vs->cnt);
+            }
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+        } while (vs->len == -1 && errno == EINTR);
+        if (vs->len == -1) {
+            err  = -errno;
+        }
+        v9fs_read_post_preadv(s, vs, err);
+        return;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
+    vs->offset += vs->count;
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
+{
+    ssize_t err = 0;
+    int read_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    read_count = xattr_len - vs->off;
+    if (read_count > vs->count) {
+        read_count = vs->count;
+    } else if (read_count < 0) {
+        /*
+         * read beyond XATTR value
+         */
+        read_count = 0;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
+    vs->offset += pdu_pack(vs->pdu, vs->offset,
+                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
+                           read_count);
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->total = 0;
+    vs->len = 0;
+    vs->count = 0;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->fidp->fid_type == P9_FID_DIR) {
+        vs->max_count = vs->count;
+        vs->count = 0;
+        if (vs->off == 0) {
+            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+        }
+        v9fs_read_post_rewinddir(s, vs, err);
+        return;
+    } else if (vs->fidp->fid_type == P9_FID_FILE) {
+        vs->sg = vs->iov;
+        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
+        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+        if (vs->total <= vs->count) {
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                                    vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+            err = vs->len;
+            v9fs_read_post_preadv(s, vs, err);
+        }
+        return;
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        v9fs_xattr_read(s, vs);
+        return;
+    } else {
+        err = -EINVAL;
+    }
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+typedef struct V9fsReadDirState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    off_t saved_dir_pos;
+    struct dirent *dent;
+    int32_t count;
+    int32_t max_count;
+    size_t offset;
+    int64_t initial_offset;
+    V9fsString name;
+} V9fsReadDirState;
+
+static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
+ * size of type (1) + size of name.size (2) + strlen(name.data)
+ */
+#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
+
+static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    int len;
+    size_t size;
+
+    if (vs->dent) {
+        v9fs_string_init(&vs->name);
+        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
+
+        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
+            v9fs_readdir_post_seekdir(s, vs);
+            return;
+        }
+
+        /* Fill up just the path field of qid because the client uses
+         * only that. To fill the entire qid structure we will have
+         * to stat each dirent found, which is expensive
+         */
+        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
+        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
+        /* Fill the other fields with dummy values */
+        vs->qid.type = 0;
+        vs->qid.version = 0;
+
+        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
+                              &vs->qid, vs->dent->d_off,
+                              vs->dent->d_type, &vs->name);
+        vs->count += len;
+        v9fs_string_free(&vs->name);
+        vs->saved_dir_pos = vs->dent->d_off;
+        vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+        v9fs_readdir_post_readdir(s, vs);
+        return;
+    }
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_readdir(s, vs);
+    return;
+}
+
+static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_telldir(s, vs);
+    return;
+}
+
+static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadDirState *vs;
+    ssize_t err = 0;
+    size_t offset = 7;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->count = 0;
+
+    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
+                                                        &vs->max_count);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->initial_offset == 0) {
+        v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+    } else {
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
+    }
+
+    v9fs_readdir_post_setdir(s, vs);
+    return;
+
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
+                                   ssize_t err)
+{
+    if (err  < 0) {
+        /* IO error return the error */
+        err = -errno;
+        goto out;
+    }
+    vs->total += vs->len;
+    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
+    if (vs->total < vs->count && vs->len > 0) {
+        do {
+            if (0) {
+                print_sg(vs->sg, vs->cnt);
+            }
+            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+        } while (vs->len == -1 && errno == EINTR);
+        if (vs->len == -1) {
+            err  = -errno;
+        }
+        v9fs_write_post_pwritev(s, vs, err);
+        return;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
+{
+    int i, to_copy;
+    ssize_t err = 0;
+    int write_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    write_count = xattr_len - vs->off;
+    if (write_count > vs->count) {
+        write_count = vs->count;
+    } else if (write_count < 0) {
+        /*
+         * write beyond XATTR value len specified in
+         * xattrcreate
+         */
+        err = -ENOSPC;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
+    err = vs->offset;
+    vs->fidp->fs.xattr.copied_len += write_count;
+    /*
+     * Now copy the content from sg list
+     */
+    for (i = 0; i < vs->cnt; i++) {
+        if (write_count > vs->sg[i].iov_len) {
+            to_copy = vs->sg[i].iov_len;
+        } else {
+            to_copy = write_count;
+        }
+        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
+               vs->sg[i].iov_base, to_copy);
+        /* updating vs->off since we are not using below */
+        vs->off += to_copy;
+        write_count -= to_copy;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsWriteState *vs;
+    ssize_t err;
+
+    vs = qemu_malloc(sizeof(*vs));
+
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->sg = vs->iov;
+    vs->total = 0;
+    vs->len = 0;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
+                  vs->sg, &vs->cnt);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->fidp->fid_type == P9_FID_FILE) {
+        if (vs->fidp->fs.fd == -1) {
+            err = -EINVAL;
+            goto out;
+        }
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        /*
+         * setxattr operation
+         */
+        v9fs_xattr_write(s, vs);
+        return;
+    } else {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+    if (vs->total <= vs->count) {
+        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
+        if (vs->len > 0) {
+            vs->off += vs->len;
+        }
+        err = vs->len;
+        v9fs_write_post_pwritev(s, vs, err);
+    }
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
+{
+    int err;
+    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+    stat_to_qid(&vs->stbuf, &vs->qid);
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+    err = vs->offset;
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err == 0) {
+        vs->iounit = get_iounit(s, &vs->fidp->path);
+        v9fs_create_post_getiounit(s, vs);
+        return;
+    }
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        err = -errno;
+    }
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
+                                                                    int err)
+{
+    if (!vs->fidp->fs.dir) {
+        err = -errno;
+    }
+    vs->fidp->fid_type = P9_FID_DIR;
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
+                                                                    int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
+    v9fs_create_post_opendir(s, vs, err);
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_create_post_dir_lstat(s, vs, err);
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        vs->fidp->fid_type = P9_FID_NONE;
+        close(vs->fidp->fs.fd);
+        err = -errno;
+    }
+    v9fs_post_create(s, vs, err);
+    return;
+}
+
+static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    v9fs_create_post_fstat(s, vs, err);
+
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+
+}
+
+static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
+{
+
+    if (err == 0 || errno != ENOENT) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->perm & P9_STAT_MODE_DIR) {
+        err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
+                vs->fidp->uid, -1);
+        v9fs_create_post_mkdir(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
+                vs->fullname.data, -1);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_LINK) {
+        int32_t nfid = atoi(vs->extension.data);
+        V9fsFidState *nfidp = lookup_fid(s, nfid);
+        if (nfidp == NULL) {
+            err = -errno;
+            v9fs_post_create(s, vs, err);
+        }
+        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
+        char ctype;
+        uint32_t major, minor;
+        mode_t nmode = 0;
+
+        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
+                                        &minor) != 3) {
+            err = -errno;
+            v9fs_post_create(s, vs, err);
+        }
+
+        switch (ctype) {
+        case 'c':
+            nmode = S_IFCHR;
+            break;
+        case 'b':
+            nmode = S_IFBLK;
+            break;
+        default:
+            err = -EIO;
+            v9fs_post_create(s, vs, err);
+        }
+
+        nmode |= vs->perm & 0777;
+        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
+                makedev(major, minor), vs->fidp->uid, -1);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
+        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
+                0, vs->fidp->uid, -1);
+        v9fs_post_create(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
+        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
+                0, vs->fidp->uid, -1);
+        v9fs_post_create(s, vs, err);
+    } else {
+        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
+
+        v9fs_create_post_open2(s, vs, err);
+    }
+
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsCreateState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
+                                &vs->perm, &vs->mode, &vs->extension);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+                                                        vs->name.data);
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_create_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    qemu_free(vs);
+}
+
+static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
+{
+    if (err == 0) {
+        stat_to_qid(&vs->stbuf, &vs->qid);
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+        err = vs->offset;
+    } else {
+        err = -errno;
+    }
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->symname);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
+        int err)
+{
+    if (err) {
+        goto out;
+    }
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+out:
+    v9fs_post_symlink(s, vs, err);
+}
+
+static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid;
+    V9fsSymlinkState *vs;
+    int err = 0;
+    gid_t gid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
+            &vs->symname, &gid);
+
+    vs->dfidp = lookup_fid(s, dfid);
+    if (vs->dfidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
+            vs->name.data);
+    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
+            vs->fullname.data, gid);
+    v9fs_symlink_post_do_symlink(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->symname);
+    qemu_free(vs);
+}
+
+static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
+{
+    /* A nop call with no return */
+    complete_pdu(s, pdu, 7);
+}
+
+static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, oldfid;
+    V9fsFidState *dfidp, *oldfidp;
+    V9fsString name, fullname;
+    size_t offset = 7;
+    int err = 0;
+
+    v9fs_string_init(&fullname);
+
+    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+
+    dfidp = lookup_fid(s, dfid);
+    if (dfidp == NULL) {
+        err = -errno;
+        goto out;
+    }
+
+    oldfidp = lookup_fid(s, oldfid);
+    if (oldfidp == NULL) {
+        err = -errno;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
+    err = offset;
+    err = v9fs_do_link(s, &oldfidp->path, &fullname);
+    if (err) {
+        err = -errno;
+    }
+    v9fs_string_free(&fullname);
+
+out:
+    v9fs_string_free(&name);
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
+                                                                int err)
+{
+    if (err < 0) {
+        err = -errno;
+    } else {
+        err = vs->offset;
+    }
+
+    /* For TREMOVE we need to clunk the fid even on failed remove */
+    free_fid(s, vs->fidp->fid);
+
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsRemoveState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    err = v9fs_do_remove(s, &vs->fidp->path);
+    v9fs_remove_post_remove(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    err = vs->offset;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+    if (vs->v9stat.length != -1) {
+        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
+            err = -errno;
+        }
+    }
+    v9fs_wstat_post_truncate(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
+{
+    int err = 0;
+    char *old_name, *new_name;
+    char *end;
+
+    if (vs->newdirfid != -1) {
+        V9fsFidState *dirfidp;
+        dirfidp = lookup_fid(s, vs->newdirfid);
+
+        if (dirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+
+        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
+
+        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
+
+        strcpy(new_name, dirfidp->path.data);
+        strcat(new_name, "/");
+        strcat(new_name + dirfidp->path.size, vs->name.data);
+    } else {
+        old_name = vs->fidp->path.data;
+        end = strrchr(old_name, '/');
+        if (end) {
+            end++;
+        } else {
+            end = old_name;
+        }
+        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
+
+        strncat(new_name, old_name, end - old_name);
+        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
+    }
+
+    v9fs_string_free(&vs->name);
+    vs->name.data = qemu_strdup(new_name);
+    vs->name.size = strlen(new_name);
+
+    if (strcmp(new_name, vs->fidp->path.data) != 0) {
+        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
+            err = -errno;
+        } else {
+            V9fsFidState *fidp;
+            /*
+            * Fixup fid's pointing to the old name to
+            * start pointing to the new name
+            */
+            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
+                if (vs->fidp == fidp) {
+                    /*
+                    * we replace name of this fid towards the end so
+                    * that our below v9fs_path_is_ancestor check will
+                    * work
+                    */
+                    continue;
+                }
+                if (v9fs_path_is_ancestor(&vs->fidp->path, &fidp->path)) {
+                    /* replace the name */
+                    v9fs_fix_path(&fidp->path, &vs->name,
+                                  strlen(vs->fidp->path.data));
+                }
+            }
+            v9fs_string_copy(&vs->fidp->path, &vs->name);
+        }
+    }
+out:
+    v9fs_string_free(&vs->name);
+    return err;
+}
+
+static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
+{
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.name.size != 0) {
+        V9fsRenameState *vr;
+
+        vr = qemu_mallocz(sizeof(V9fsRenameState));
+        vr->newdirfid = -1;
+        vr->pdu = vs->pdu;
+        vr->fidp = vs->fidp;
+        vr->offset = vs->offset;
+        vr->name.size = vs->v9stat.name.size;
+        vr->name.data = qemu_strdup(vs->v9stat.name.data);
+
+        err = v9fs_complete_rename(s, vr);
+        qemu_free(vr);
+    }
+    v9fs_wstat_post_rename(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsRenameState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+
+    err = v9fs_complete_rename(s, vs);
+    v9fs_rename_post_rename(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
+        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
+                    vs->v9stat.n_gid)) {
+            err = -errno;
+        }
+    }
+    v9fs_wstat_post_chown(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
+        struct timespec times[2];
+        if (vs->v9stat.atime != -1) {
+            times[0].tv_sec = vs->v9stat.atime;
+            times[0].tv_nsec = 0;
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+        if (vs->v9stat.mtime != -1) {
+            times[1].tv_sec = vs->v9stat.mtime;
+            times[1].tv_nsec = 0;
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+
+        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
+            err = -errno;
+        }
+    }
+
+    v9fs_wstat_post_utime(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    uint32_t v9_mode;
+
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    v9_mode = stat_to_v9mode(&vs->stbuf);
+
+    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
+        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
+            /* Attempting to change the type */
+            err = -EIO;
+            goto out;
+    }
+
+    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
+                    &vs->v9stat.extension))) {
+            err = -errno;
+     }
+    v9fs_wstat_post_chmod(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsWstatState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* do we need to sync the file? */
+    if (donttouch_stat(&vs->v9stat)) {
+        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
+        v9fs_wstat_post_fsync(s, vs, err);
+        return;
+    }
+
+    if (vs->v9stat.mode != -1) {
+        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+        v9fs_wstat_post_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_wstat_post_chmod(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
+{
+    int32_t bsize_factor;
+
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    /*
+     * compute bsize factor based on host file system block size
+     * and client msize
+     */
+    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
+    if (!bsize_factor) {
+        bsize_factor = 1;
+    }
+    vs->v9statfs.f_type = vs->stbuf.f_type;
+    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
+    vs->v9statfs.f_bsize *= bsize_factor;
+    /*
+     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
+     * adjust(divide) the number of blocks, free blocks and available
+     * blocks by bsize factor
+     */
+    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
+    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
+    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
+    vs->v9statfs.f_files = vs->stbuf.f_files;
+    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
+    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
+			(unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
+    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
+         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
+         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
+         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
+         vs->v9statfs.f_namelen);
+
+out:
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+}
+
+static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
+{
+    V9fsStatfsState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
+
+    vs->fidp = lookup_fid(s, vs->fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
+    v9fs_statfs_post_statfs(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mknod_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+    int major, minor;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
+        &major, &minor, &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
+        fidp->uid, gid);
+    v9fs_mknod_post_mknod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+/*
+ * Implement posix byte range locking code
+ * Server side handling of locking code is very simple, because 9p server in
+ * QEMU can handle only one client. And most of the lock handling
+ * (like conflict, merging) etc is done by the VFS layer itself, so no need to
+ * do any thing in * qemu 9p server side lock code path.
+ * So when a TLOCK request comes, always return success
+ */
+
+static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsLockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->flock = qemu_malloc(sizeof(*vs->flock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
+                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
+                            &vs->flock->proc_id, &vs->flock->client_id);
+
+    vs->status = P9_LOCK_ERROR;
+
+    /* We support only block flag now (that too ignored currently) */
+    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->status = P9_LOCK_SUCCESS;
+out:
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->flock);
+    qemu_free(vs);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+
+static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsGetlockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->glock = qemu_malloc(sizeof(*vs->glock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
+                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
+		&vs->glock->client_id);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->glock->type = F_UNLCK;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
+                vs->glock->start, vs->glock->length, vs->glock->proc_id,
+		&vs->glock->client_id);
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->glock);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mkdir_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
+        &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
+    v9fs_mkdir_post_mkdir(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
+{
+
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                &vs->name, vs->xattr_fidp->fs.xattr.value,
+                                vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_xattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_lxattr_getvalue(V9fsState *s,
+                                      V9fsXattrState *vs, int err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_lxattr_check(V9fsState *s,
+                                   V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                 vs->xattr_fidp->fs.xattr.value,
+                                 vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_lxattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
+{
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+    int32_t fid, newfid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    vs->xattr_fidp = alloc_fid(s, newfid);
+    if (vs->xattr_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
+    if (vs->name.data[0] == 0) {
+        /*
+         * listxattr request. Get the size first
+         */
+        vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                      NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_lxattr_check(s, vs, err);
+        return;
+    } else {
+        /*
+         * specific xattr fid. We check for xattr
+         * presence also collect the xattr size
+         */
+        vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                     &vs->name, NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_xattr_check(s, vs, err);
+        return;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int flags;
+    int32_t fid;
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
+                  &fid, &vs->name, &vs->size, &flags);
+
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* Make the file fid point to xattr */
+    vs->xattr_fidp = vs->file_fidp;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = 0;
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fs.xattr.flags = flags;
+    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
+    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
+    if (vs->size)
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+    else
+        vs->xattr_fidp->fs.xattr.value = NULL;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
+                                                    int err)
+{
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->target);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadLinkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_init(&vs->target);
+    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
+    v9fs_readlink_post_readlink(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
+
+static pdu_handler_t *pdu_handlers[] = {
+    [P9_TREADDIR] = v9fs_readdir,
+    [P9_TSTATFS] = v9fs_statfs,
+    [P9_TGETATTR] = v9fs_getattr,
+    [P9_TSETATTR] = v9fs_setattr,
+    [P9_TXATTRWALK] = v9fs_xattrwalk,
+    [P9_TXATTRCREATE] = v9fs_xattrcreate,
+    [P9_TMKNOD] = v9fs_mknod,
+    [P9_TRENAME] = v9fs_rename,
+    [P9_TLOCK] = v9fs_lock,
+    [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TREADLINK] = v9fs_readlink,
+    [P9_TMKDIR] = v9fs_mkdir,
+    [P9_TVERSION] = v9fs_version,
+    [P9_TLOPEN] = v9fs_open,
+    [P9_TATTACH] = v9fs_attach,
+    [P9_TSTAT] = v9fs_stat,
+    [P9_TWALK] = v9fs_walk,
+    [P9_TCLUNK] = v9fs_clunk,
+    [P9_TFSYNC] = v9fs_fsync,
+    [P9_TOPEN] = v9fs_open,
+    [P9_TREAD] = v9fs_read,
+#if 0
+    [P9_TAUTH] = v9fs_auth,
+#endif
+    [P9_TFLUSH] = v9fs_flush,
+    [P9_TLINK] = v9fs_link,
+    [P9_TSYMLINK] = v9fs_symlink,
+    [P9_TCREATE] = v9fs_create,
+    [P9_TLCREATE] = v9fs_lcreate,
+    [P9_TWRITE] = v9fs_write,
+    [P9_TWSTAT] = v9fs_wstat,
+    [P9_TREMOVE] = v9fs_remove,
+};
+
+static void v9fs_op_not_supp(V9fsState *s, V9fsPDU *pdu)
+{
+    complete_pdu(s, pdu, -EOPNOTSUPP);
+}
+
+static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    pdu_handler_t *handler;
+
+    if (debug_9p_pdu) {
+        pprint_pdu(pdu);
+    }
+    if (pdu->id >= ARRAY_SIZE(pdu_handlers) ||
+        (pdu_handlers[pdu->id] == NULL)) {
+        handler = v9fs_op_not_supp;
+    } else {
+        handler = pdu_handlers[pdu->id];
+    }
+    handler(s, pdu);
+}
+
+void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    V9fsState *s = (V9fsState *)vdev;
+    V9fsPDU *pdu;
+    ssize_t len;
+
+    while ((pdu = alloc_pdu(s)) &&
+            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
+        uint8_t *ptr;
+
+        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
+        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
+
+        ptr = pdu->elem.out_sg[0].iov_base;
+
+        memcpy(&pdu->size, ptr, 4);
+        pdu->id = ptr[4];
+        memcpy(&pdu->tag, ptr + 5, 2);
+
+        submit_pdu(s, pdu);
+    }
+
+    free_pdu(s, pdu);
+}
diff --git a/qemu-0.15.x/hw/9pfs/virtio-9p.h b/qemu-0.15.x/hw/9pfs/virtio-9p.h
new file mode 100644
index 0000000..2bfbe62
--- /dev/null
+++ b/qemu-0.15.x/hw/9pfs/virtio-9p.h
@@ -0,0 +1,514 @@
+#ifndef _QEMU_VIRTIO_9P_H
+#define _QEMU_VIRTIO_9P_H
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+
+#include "fsdev/file-op-9p.h"
+
+/* The feature bitmap for virtio 9P */
+/* The mount point is specified in a config variable */
+#define VIRTIO_9P_MOUNT_TAG 0
+
+enum {
+    P9_TLERROR = 6,
+    P9_RLERROR,
+    P9_TSTATFS = 8,
+    P9_RSTATFS,
+    P9_TLOPEN = 12,
+    P9_RLOPEN,
+    P9_TLCREATE = 14,
+    P9_RLCREATE,
+    P9_TSYMLINK = 16,
+    P9_RSYMLINK,
+    P9_TMKNOD = 18,
+    P9_RMKNOD,
+    P9_TRENAME = 20,
+    P9_RRENAME,
+    P9_TREADLINK = 22,
+    P9_RREADLINK,
+    P9_TGETATTR = 24,
+    P9_RGETATTR,
+    P9_TSETATTR = 26,
+    P9_RSETATTR,
+    P9_TXATTRWALK = 30,
+    P9_RXATTRWALK,
+    P9_TXATTRCREATE = 32,
+    P9_RXATTRCREATE,
+    P9_TREADDIR = 40,
+    P9_RREADDIR,
+    P9_TFSYNC = 50,
+    P9_RFSYNC,
+    P9_TLOCK = 52,
+    P9_RLOCK,
+    P9_TGETLOCK = 54,
+    P9_RGETLOCK,
+    P9_TLINK = 70,
+    P9_RLINK,
+    P9_TMKDIR = 72,
+    P9_RMKDIR,
+    P9_TVERSION = 100,
+    P9_RVERSION,
+    P9_TAUTH = 102,
+    P9_RAUTH,
+    P9_TATTACH = 104,
+    P9_RATTACH,
+    P9_TERROR = 106,
+    P9_RERROR,
+    P9_TFLUSH = 108,
+    P9_RFLUSH,
+    P9_TWALK = 110,
+    P9_RWALK,
+    P9_TOPEN = 112,
+    P9_ROPEN,
+    P9_TCREATE = 114,
+    P9_RCREATE,
+    P9_TREAD = 116,
+    P9_RREAD,
+    P9_TWRITE = 118,
+    P9_RWRITE,
+    P9_TCLUNK = 120,
+    P9_RCLUNK,
+    P9_TREMOVE = 122,
+    P9_RREMOVE,
+    P9_TSTAT = 124,
+    P9_RSTAT,
+    P9_TWSTAT = 126,
+    P9_RWSTAT,
+};
+
+
+/* qid.types */
+enum {
+    P9_QTDIR = 0x80,
+    P9_QTAPPEND = 0x40,
+    P9_QTEXCL = 0x20,
+    P9_QTMOUNT = 0x10,
+    P9_QTAUTH = 0x08,
+    P9_QTTMP = 0x04,
+    P9_QTSYMLINK = 0x02,
+    P9_QTLINK = 0x01,
+    P9_QTFILE = 0x00,
+};
+
+enum p9_proto_version {
+    V9FS_PROTO_2000U = 0x01,
+    V9FS_PROTO_2000L = 0x02,
+};
+
+#define P9_NOTAG    (u16)(~0)
+#define P9_NOFID    (u32)(~0)
+#define P9_MAXWELEM 16
+static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+{
+    snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
+    return buffer;
+}
+
+/*
+ * ample room for Twrite/Rread header
+ * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
+ */
+#define P9_IOHDRSZ 24
+
+typedef struct V9fsPDU V9fsPDU;
+
+struct V9fsPDU
+{
+    uint32_t size;
+    uint16_t tag;
+    uint8_t id;
+    VirtQueueElement elem;
+    QLIST_ENTRY(V9fsPDU) next;
+};
+
+
+/* FIXME
+ * 1) change user needs to set groups and stuff
+ */
+
+/* from Linux's linux/virtio_9p.h */
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P    9
+#define MAX_REQ         128
+#define MAX_TAG_LEN     32
+
+#define BUG_ON(cond) assert(!(cond))
+
+typedef struct V9fsFidState V9fsFidState;
+
+typedef struct V9fsString
+{
+    int16_t size;
+    char *data;
+} V9fsString;
+
+typedef struct V9fsQID
+{
+    int8_t type;
+    int32_t version;
+    int64_t path;
+} V9fsQID;
+
+typedef struct V9fsStat
+{
+    int16_t size;
+    int16_t type;
+    int32_t dev;
+    V9fsQID qid;
+    int32_t mode;
+    int32_t atime;
+    int32_t mtime;
+    int64_t length;
+    V9fsString name;
+    V9fsString uid;
+    V9fsString gid;
+    V9fsString muid;
+    /* 9p2000.u */
+    V9fsString extension;
+   int32_t n_uid;
+    int32_t n_gid;
+    int32_t n_muid;
+} V9fsStat;
+
+enum {
+    P9_FID_NONE = 0,
+    P9_FID_FILE,
+    P9_FID_DIR,
+    P9_FID_XATTR,
+};
+
+typedef struct V9fsXattr
+{
+    int64_t copied_len;
+    int64_t len;
+    void *value;
+    V9fsString name;
+    int flags;
+} V9fsXattr;
+
+struct V9fsFidState
+{
+    int fid_type;
+    int32_t fid;
+    V9fsString path;
+    union {
+	int fd;
+	DIR *dir;
+	V9fsXattr xattr;
+    } fs;
+    uid_t uid;
+    V9fsFidState *next;
+};
+
+typedef struct V9fsState
+{
+    VirtIODevice vdev;
+    VirtQueue *vq;
+    V9fsPDU pdus[MAX_REQ];
+    QLIST_HEAD(, V9fsPDU) free_list;
+    V9fsFidState *fid_list;
+    FileOperations *ops;
+    FsContext ctx;
+    uint16_t tag_len;
+    uint8_t *tag;
+    size_t config_size;
+    enum p9_proto_version proto_version;
+    int32_t msize;
+} V9fsState;
+
+typedef struct V9fsCreateState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t perm;
+    int8_t mode;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString extension;
+    V9fsString fullname;
+    int iounit;
+} V9fsCreateState;
+
+typedef struct V9fsLcreateState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t iounit;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsLcreateState;
+
+typedef struct V9fsStatState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsStat v9stat;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+} V9fsStatState;
+
+typedef struct V9fsStatDotl {
+    uint64_t st_result_mask;
+    V9fsQID qid;
+    uint32_t st_mode;
+    uint32_t st_uid;
+    uint32_t st_gid;
+    uint64_t st_nlink;
+    uint64_t st_rdev;
+    uint64_t st_size;
+    uint64_t st_blksize;
+    uint64_t st_blocks;
+    uint64_t st_atime_sec;
+    uint64_t st_atime_nsec;
+    uint64_t st_mtime_sec;
+    uint64_t st_mtime_nsec;
+    uint64_t st_ctime_sec;
+    uint64_t st_ctime_nsec;
+    uint64_t st_btime_sec;
+    uint64_t st_btime_nsec;
+    uint64_t st_gen;
+    uint64_t st_data_version;
+} V9fsStatDotl;
+
+typedef struct V9fsStatStateDotl {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsStatDotl v9stat_dotl;
+    struct stat stbuf;
+} V9fsStatStateDotl;
+
+
+typedef struct V9fsWalkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    uint16_t nwnames;
+    int name_idx;
+    V9fsQID *qids;
+    V9fsFidState *fidp;
+    V9fsFidState *newfidp;
+    V9fsString path;
+    V9fsString *wnames;
+    struct stat stbuf;
+} V9fsWalkState;
+
+typedef struct V9fsOpenState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t mode;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    struct stat stbuf;
+    int iounit;
+} V9fsOpenState;
+
+typedef struct V9fsReadState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t count;
+    int32_t total;
+    int64_t off;
+    V9fsFidState *fidp;
+    struct iovec iov[128]; /* FIXME: bad, bad, bad */
+    struct iovec *sg;
+    off_t dir_pos;
+    struct dirent *dent;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsStat v9stat;
+    int32_t len;
+    int32_t cnt;
+    int32_t max_count;
+} V9fsReadState;
+
+typedef struct V9fsWriteState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t len;
+    int32_t count;
+    int32_t total;
+    int64_t off;
+    V9fsFidState *fidp;
+    struct iovec iov[128]; /* FIXME: bad, bad, bad */
+    struct iovec *sg;
+    int cnt;
+} V9fsWriteState;
+
+typedef struct V9fsRemoveState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+} V9fsRemoveState;
+
+typedef struct V9fsWstatState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    int16_t unused;
+    V9fsStat v9stat;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+} V9fsWstatState;
+
+typedef struct V9fsSymlinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString name;
+    V9fsString symname;
+    V9fsString fullname;
+    V9fsFidState *dfidp;
+    V9fsQID qid;
+    struct stat stbuf;
+} V9fsSymlinkState;
+
+typedef struct V9fsIattr
+{
+    int32_t valid;
+    int32_t mode;
+    int32_t uid;
+    int32_t gid;
+    int64_t size;
+    int64_t atime_sec;
+    int64_t atime_nsec;
+    int64_t mtime_sec;
+    int64_t mtime_nsec;
+} V9fsIattr;
+
+typedef struct V9fsSetattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsIattr v9iattr;
+    V9fsFidState *fidp;
+} V9fsSetattrState;
+
+struct virtio_9p_config
+{
+    /* number of characters in tag */
+    uint16_t tag_len;
+    /* Variable size tag name */
+    uint8_t tag[0];
+} __attribute__((packed));
+
+typedef struct V9fsStatfs
+{
+    uint32_t f_type;
+    uint32_t f_bsize;
+    uint64_t f_blocks;
+    uint64_t f_bfree;
+    uint64_t f_bavail;
+    uint64_t f_files;
+    uint64_t f_ffree;
+    uint64_t fsid_val;
+    uint32_t f_namelen;
+} V9fsStatfs;
+
+typedef struct V9fsStatfsState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t fid;
+    V9fsStatfs v9statfs;
+    V9fsFidState *fidp;
+    struct statfs stbuf;
+} V9fsStatfsState;
+
+typedef struct V9fsMkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsQID qid;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsMkState;
+
+typedef struct V9fsRenameState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    size_t offset;
+    int32_t newdirfid;
+    V9fsString name;
+} V9fsRenameState;
+
+typedef struct V9fsXattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *file_fidp;
+    V9fsFidState *xattr_fidp;
+    V9fsString name;
+    int64_t size;
+    int flags;
+    void *value;
+} V9fsXattrState;
+
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+typedef struct V9fsFlock
+{
+    uint8_t type;
+    uint32_t flags;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsFlock;
+
+typedef struct V9fsLockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    int8_t status;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsFlock *flock;
+} V9fsLockState;
+
+typedef struct V9fsGetlock
+{
+    uint8_t type;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsGetlock;
+
+typedef struct V9fsGetlockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+} V9fsGetlockState;
+
+typedef struct V9fsReadLinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString target;
+} V9fsReadLinkState;
+
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                      size_t offset, size_t size, int pack);
+
+static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
+}
+
+extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
+
+#endif
diff --git a/qemu-0.15.x/hw/a9mpcore.c b/qemu-0.15.x/hw/a9mpcore.c
new file mode 100644
index 0000000..6f108f4
--- /dev/null
+++ b/qemu-0.15.x/hw/a9mpcore.c
@@ -0,0 +1,29 @@
+/*
+ * Cortex-A9MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* 64 external IRQ lines.  */
+#define GIC_NIRQ 96
+#include "mpcore.c"
+
+static SysBusDeviceInfo mpcore_priv_info = {
+    .init = mpcore_priv_init,
+    .qdev.name  = "a9mpcore_priv",
+    .qdev.size  = sizeof(mpcore_priv_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void a9mpcore_register_devices(void)
+{
+    sysbus_register_withprop(&mpcore_priv_info);
+}
+
+device_init(a9mpcore_register_devices)
diff --git a/qemu-0.15.x/hw/ac97.c b/qemu-0.15.x/hw/ac97.c
new file mode 100644
index 0000000..0b59896
--- /dev/null
+++ b/qemu-0.15.x/hw/ac97.c
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (C) 2006 InnoTek Systemberatung GmbH
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation,
+ * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
+ * distribution. VirtualBox OSE is distributed in the hope that it will
+ * be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * If you received this file as part of a commercial VirtualBox
+ * distribution, then only the terms of your commercial VirtualBox
+ * license agreement apply instead of the previous paragraph.
+ */
+
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "pci.h"
+
+enum {
+    AC97_Reset                     = 0x00,
+    AC97_Master_Volume_Mute        = 0x02,
+    AC97_Headphone_Volume_Mute     = 0x04,
+    AC97_Master_Volume_Mono_Mute   = 0x06,
+    AC97_Master_Tone_RL            = 0x08,
+    AC97_PC_BEEP_Volume_Mute       = 0x0A,
+    AC97_Phone_Volume_Mute         = 0x0C,
+    AC97_Mic_Volume_Mute           = 0x0E,
+    AC97_Line_In_Volume_Mute       = 0x10,
+    AC97_CD_Volume_Mute            = 0x12,
+    AC97_Video_Volume_Mute         = 0x14,
+    AC97_Aux_Volume_Mute           = 0x16,
+    AC97_PCM_Out_Volume_Mute       = 0x18,
+    AC97_Record_Select             = 0x1A,
+    AC97_Record_Gain_Mute          = 0x1C,
+    AC97_Record_Gain_Mic_Mute      = 0x1E,
+    AC97_General_Purpose           = 0x20,
+    AC97_3D_Control                = 0x22,
+    AC97_AC_97_RESERVED            = 0x24,
+    AC97_Powerdown_Ctrl_Stat       = 0x26,
+    AC97_Extended_Audio_ID         = 0x28,
+    AC97_Extended_Audio_Ctrl_Stat  = 0x2A,
+    AC97_PCM_Front_DAC_Rate        = 0x2C,
+    AC97_PCM_Surround_DAC_Rate     = 0x2E,
+    AC97_PCM_LFE_DAC_Rate          = 0x30,
+    AC97_PCM_LR_ADC_Rate           = 0x32,
+    AC97_MIC_ADC_Rate              = 0x34,
+    AC97_6Ch_Vol_C_LFE_Mute        = 0x36,
+    AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
+    AC97_Vendor_Reserved           = 0x58,
+    AC97_Vendor_ID1                = 0x7c,
+    AC97_Vendor_ID2                = 0x7e
+};
+
+#define SOFT_VOLUME
+#define SR_FIFOE 16             /* rwc */
+#define SR_BCIS  8              /* rwc */
+#define SR_LVBCI 4              /* rwc */
+#define SR_CELV  2              /* ro */
+#define SR_DCH   1              /* ro */
+#define SR_VALID_MASK ((1 << 5) - 1)
+#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+#define SR_RO_MASK (SR_DCH | SR_CELV)
+#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+
+#define CR_IOCE  16             /* rw */
+#define CR_FEIE  8              /* rw */
+#define CR_LVBIE 4              /* rw */
+#define CR_RR    2              /* rw */
+#define CR_RPBM  1              /* rw */
+#define CR_VALID_MASK ((1 << 5) - 1)
+#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
+
+#define GC_WR    4              /* rw */
+#define GC_CR    2              /* rw */
+#define GC_VALID_MASK ((1 << 6) - 1)
+
+#define GS_MD3   (1<<17)        /* rw */
+#define GS_AD3   (1<<16)        /* rw */
+#define GS_RCS   (1<<15)        /* rwc */
+#define GS_B3S12 (1<<14)        /* ro */
+#define GS_B2S12 (1<<13)        /* ro */
+#define GS_B1S12 (1<<12)        /* ro */
+#define GS_S1R1  (1<<11)        /* rwc */
+#define GS_S0R1  (1<<10)        /* rwc */
+#define GS_S1CR  (1<<9)         /* ro */
+#define GS_S0CR  (1<<8)         /* ro */
+#define GS_MINT  (1<<7)         /* ro */
+#define GS_POINT (1<<6)         /* ro */
+#define GS_PIINT (1<<5)         /* ro */
+#define GS_RSRVD ((1<<4)|(1<<3))
+#define GS_MOINT (1<<2)         /* ro */
+#define GS_MIINT (1<<1)         /* ro */
+#define GS_GSCI  1              /* rwc */
+#define GS_RO_MASK (GS_B3S12|                   \
+                    GS_B2S12|                   \
+                    GS_B1S12|                   \
+                    GS_S1CR|                    \
+                    GS_S0CR|                    \
+                    GS_MINT|                    \
+                    GS_POINT|                   \
+                    GS_PIINT|                   \
+                    GS_RSRVD|                   \
+                    GS_MOINT|                   \
+                    GS_MIINT)
+#define GS_VALID_MASK ((1 << 18) - 1)
+#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
+
+#define BD_IOC (1<<31)
+#define BD_BUP (1<<30)
+
+#define EACS_VRA 1
+#define EACS_VRM 8
+
+#define VOL_MASK 0x1f
+#define MUTE_SHIFT 15
+
+#define REC_MASK 7
+enum {
+    REC_MIC = 0,
+    REC_CD,
+    REC_VIDEO,
+    REC_AUX,
+    REC_LINE_IN,
+    REC_STEREO_MIX,
+    REC_MONO_MIX,
+    REC_PHONE
+};
+
+typedef struct BD {
+    uint32_t addr;
+    uint32_t ctl_len;
+} BD;
+
+typedef struct AC97BusMasterRegs {
+    uint32_t bdbar;             /* rw 0 */
+    uint8_t civ;                /* ro 0 */
+    uint8_t lvi;                /* rw 0 */
+    uint16_t sr;                /* rw 1 */
+    uint16_t picb;              /* ro 0 */
+    uint8_t piv;                /* ro 0 */
+    uint8_t cr;                 /* rw 0 */
+    unsigned int bd_valid;
+    BD bd;
+} AC97BusMasterRegs;
+
+typedef struct AC97LinkState {
+    PCIDevice dev;
+    QEMUSoundCard card;
+    uint32_t glob_cnt;
+    uint32_t glob_sta;
+    uint32_t cas;
+    uint32_t last_samp;
+    AC97BusMasterRegs bm_regs[3];
+    uint8_t mixer_data[256];
+    SWVoiceIn *voice_pi;
+    SWVoiceOut *voice_po;
+    SWVoiceIn *voice_mc;
+    int invalid_freq[3];
+    uint8_t silence[128];
+    uint32_t base[2];
+    int bup_flag;
+} AC97LinkState;
+
+enum {
+    BUP_SET = 1,
+    BUP_LAST = 2
+};
+
+#ifdef DEBUG_AC97
+#define dolog(...) AUD_log ("ac97", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#define MKREGS(prefix, start)                   \
+enum {                                          \
+    prefix ## _BDBAR = start,                   \
+    prefix ## _CIV = start + 4,                 \
+    prefix ## _LVI = start + 5,                 \
+    prefix ## _SR = start + 6,                  \
+    prefix ## _PICB = start + 8,                \
+    prefix ## _PIV = start + 10,                \
+    prefix ## _CR = start + 11                  \
+}
+
+enum {
+    PI_INDEX = 0,
+    PO_INDEX,
+    MC_INDEX,
+    LAST_INDEX
+};
+
+MKREGS (PI, PI_INDEX * 16);
+MKREGS (PO, PO_INDEX * 16);
+MKREGS (MC, MC_INDEX * 16);
+
+enum {
+    GLOB_CNT = 0x2c,
+    GLOB_STA = 0x30,
+    CAS      = 0x34
+};
+
+#define GET_BM(index) (((index) >> 4) & 3)
+
+static void po_callback (void *opaque, int free);
+static void pi_callback (void *opaque, int avail);
+static void mc_callback (void *opaque, int avail);
+
+static void warm_reset (AC97LinkState *s)
+{
+    (void) s;
+}
+
+static void cold_reset (AC97LinkState * s)
+{
+    (void) s;
+}
+
+static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    uint8_t b[8];
+
+    cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8);
+    r->bd_valid = 1;
+    r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
+    r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
+    r->picb = r->bd.ctl_len & 0xffff;
+    dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
+           r->civ, r->bd.addr, r->bd.ctl_len >> 16,
+           r->bd.ctl_len & 0xffff,
+           (r->bd.ctl_len & 0xffff) << 1);
+}
+
+static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
+{
+    int event = 0;
+    int level = 0;
+    uint32_t new_mask = new_sr & SR_INT_MASK;
+    uint32_t old_mask = r->sr & SR_INT_MASK;
+    uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
+
+    if (new_mask ^ old_mask) {
+        /** @todo is IRQ deasserted when only one of status bits is cleared? */
+        if (!new_mask) {
+            event = 1;
+            level = 0;
+        }
+        else {
+            if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {
+                event = 1;
+                level = 1;
+            }
+            if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {
+                event = 1;
+                level = 1;
+            }
+        }
+    }
+
+    r->sr = new_sr;
+
+    dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",
+           r->sr & SR_BCIS, r->sr & SR_LVBCI,
+           r->sr,
+           event, level);
+
+    if (!event)
+        return;
+
+    if (level) {
+        s->glob_sta |= masks[r - s->bm_regs];
+        dolog ("set irq level=1\n");
+        qemu_set_irq (s->dev.irq[0], 1);
+    }
+    else {
+        s->glob_sta &= ~masks[r - s->bm_regs];
+        dolog ("set irq level=0\n");
+        qemu_set_irq (s->dev.irq[0], 0);
+    }
+}
+
+static void voice_set_active (AC97LinkState *s, int bm_index, int on)
+{
+    switch (bm_index) {
+    case PI_INDEX:
+        AUD_set_active_in (s->voice_pi, on);
+        break;
+
+    case PO_INDEX:
+        AUD_set_active_out (s->voice_po, on);
+        break;
+
+    case MC_INDEX:
+        AUD_set_active_in (s->voice_mc, on);
+        break;
+
+    default:
+        AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);
+        break;
+    }
+}
+
+static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    dolog ("reset_bm_regs\n");
+    r->bdbar = 0;
+    r->civ = 0;
+    r->lvi = 0;
+    /** todo do we need to do that? */
+    update_sr (s, r, SR_DCH);
+    r->picb = 0;
+    r->piv = 0;
+    r->cr = r->cr & CR_DONT_CLEAR_MASK;
+    r->bd_valid = 0;
+
+    voice_set_active (s, r - s->bm_regs, 0);
+    memset (s->silence, 0, sizeof (s->silence));
+}
+
+static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
+{
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_store: index %d out of bounds %zd\n",
+               i, sizeof (s->mixer_data));
+        return;
+    }
+
+    s->mixer_data[i + 0] = v & 0xff;
+    s->mixer_data[i + 1] = v >> 8;
+}
+
+static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
+{
+    uint16_t val = 0xffff;
+
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_store: index %d out of bounds %zd\n",
+               i, sizeof (s->mixer_data));
+    }
+    else {
+        val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
+    }
+
+    return val;
+}
+
+static void open_voice (AC97LinkState *s, int index, int freq)
+{
+    struct audsettings as;
+
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    if (freq > 0) {
+        s->invalid_freq[index] = 0;
+        switch (index) {
+        case PI_INDEX:
+            s->voice_pi = AUD_open_in (
+                &s->card,
+                s->voice_pi,
+                "ac97.pi",
+                s,
+                pi_callback,
+                &as
+                );
+            break;
+
+        case PO_INDEX:
+            s->voice_po = AUD_open_out (
+                &s->card,
+                s->voice_po,
+                "ac97.po",
+                s,
+                po_callback,
+                &as
+                );
+            break;
+
+        case MC_INDEX:
+            s->voice_mc = AUD_open_in (
+                &s->card,
+                s->voice_mc,
+                "ac97.mc",
+                s,
+                mc_callback,
+                &as
+                );
+            break;
+        }
+    }
+    else {
+        s->invalid_freq[index] = freq;
+        switch (index) {
+        case PI_INDEX:
+            AUD_close_in (&s->card, s->voice_pi);
+            s->voice_pi = NULL;
+            break;
+
+        case PO_INDEX:
+            AUD_close_out (&s->card, s->voice_po);
+            s->voice_po = NULL;
+            break;
+
+        case MC_INDEX:
+            AUD_close_in (&s->card, s->voice_mc);
+            s->voice_mc = NULL;
+            break;
+        }
+    }
+}
+
+static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
+{
+    uint16_t freq;
+
+    freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
+    open_voice (s, PI_INDEX, freq);
+    AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
+
+    freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
+    open_voice (s, PO_INDEX, freq);
+    AUD_set_active_out (s->voice_po, active[PO_INDEX]);
+
+    freq = mixer_load (s, AC97_MIC_ADC_Rate);
+    open_voice (s, MC_INDEX, freq);
+    AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
+}
+
+#ifdef USE_MIXER
+static void set_volume (AC97LinkState *s, int index,
+                        audmixerctl_t mt, uint32_t val)
+{
+    int mute = (val >> MUTE_SHIFT) & 1;
+    uint8_t rvol = VOL_MASK - (val & VOL_MASK);
+    uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
+    rvol = 255 * rvol / VOL_MASK;
+    lvol = 255 * lvol / VOL_MASK;
+
+#ifdef SOFT_VOLUME
+    if (index == AC97_Master_Volume_Mute) {
+        AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+    }
+    else {
+        AUD_set_volume (mt, &mute, &lvol, &rvol);
+    }
+#else
+    AUD_set_volume (mt, &mute, &lvol, &rvol);
+#endif
+
+    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
+    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
+    mixer_store (s, index, val);
+}
+
+static audrecsource_t ac97_to_aud_record_source (uint8_t i)
+{
+    switch (i) {
+    case REC_MIC:
+        return AUD_REC_MIC;
+
+    case REC_CD:
+        return AUD_REC_CD;
+
+    case REC_VIDEO:
+        return AUD_REC_VIDEO;
+
+    case REC_AUX:
+        return AUD_REC_AUX;
+
+    case REC_LINE_IN:
+        return AUD_REC_LINE_IN;
+
+    case REC_PHONE:
+        return AUD_REC_PHONE;
+
+    default:
+        dolog ("Unknown record source %d, using MIC\n", i);
+        return AUD_REC_MIC;
+    }
+}
+
+static uint8_t aud_to_ac97_record_source (audrecsource_t rs)
+{
+    switch (rs) {
+    case AUD_REC_MIC:
+        return REC_MIC;
+
+    case AUD_REC_CD:
+        return REC_CD;
+
+    case AUD_REC_VIDEO:
+        return REC_VIDEO;
+
+    case AUD_REC_AUX:
+        return REC_AUX;
+
+    case AUD_REC_LINE_IN:
+        return REC_LINE_IN;
+
+    case AUD_REC_PHONE:
+        return REC_PHONE;
+
+    default:
+        dolog ("Unknown audio recording source %d using MIC\n", rs);
+        return REC_MIC;
+    }
+}
+
+static void record_select (AC97LinkState *s, uint32_t val)
+{
+    uint8_t rs = val & REC_MASK;
+    uint8_t ls = (val >> 8) & REC_MASK;
+    audrecsource_t ars = ac97_to_aud_record_source (rs);
+    audrecsource_t als = ac97_to_aud_record_source (ls);
+    AUD_set_record_source (&als, &ars);
+    rs = aud_to_ac97_record_source (ars);
+    ls = aud_to_ac97_record_source (als);
+    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
+}
+#endif
+
+static void mixer_reset (AC97LinkState *s)
+{
+    uint8_t active[LAST_INDEX];
+
+    dolog ("mixer_reset\n");
+    memset (s->mixer_data, 0, sizeof (s->mixer_data));
+    memset (active, 0, sizeof (active));
+    mixer_store (s, AC97_Reset                   , 0x0000); /* 6940 */
+    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000);
+    mixer_store (s, AC97_PC_BEEP_Volume_Mute     , 0x0000);
+
+    mixer_store (s, AC97_Phone_Volume_Mute       , 0x8008);
+    mixer_store (s, AC97_Mic_Volume_Mute         , 0x8008);
+    mixer_store (s, AC97_CD_Volume_Mute          , 0x8808);
+    mixer_store (s, AC97_Aux_Volume_Mute         , 0x8808);
+    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x8000);
+    mixer_store (s, AC97_General_Purpose         , 0x0000);
+    mixer_store (s, AC97_3D_Control              , 0x0000);
+    mixer_store (s, AC97_Powerdown_Ctrl_Stat     , 0x000f);
+
+    /*
+     * Sigmatel 9700 (STAC9700)
+     */
+    mixer_store (s, AC97_Vendor_ID1              , 0x8384);
+    mixer_store (s, AC97_Vendor_ID2              , 0x7600); /* 7608 */
+
+    mixer_store (s, AC97_Extended_Audio_ID       , 0x0809);
+    mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
+    mixer_store (s, AC97_PCM_Front_DAC_Rate      , 0xbb80);
+    mixer_store (s, AC97_PCM_Surround_DAC_Rate   , 0xbb80);
+    mixer_store (s, AC97_PCM_LFE_DAC_Rate        , 0xbb80);
+    mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
+    mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
+
+#ifdef USE_MIXER
+    record_select (s, 0);
+    set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME  , 0x8000);
+    set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM    , 0x8808);
+    set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
+#endif
+    reset_voices (s, active);
+}
+
+/**
+ * Native audio mixer
+ * I/O Reads
+ */
+static uint32_t nam_readb (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam readb %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+static uint32_t nam_readw (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    uint32_t val = ~0U;
+    uint32_t index = addr - s->base[0];
+    s->cas = 0;
+    val = mixer_load (s, index);
+    return val;
+}
+
+static uint32_t nam_readl (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam readl %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+/**
+ * Native audio mixer
+ * I/O Writes
+ */
+static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam writeb %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    uint32_t index = addr - s->base[0];
+    s->cas = 0;
+    switch (index) {
+    case AC97_Reset:
+        mixer_reset (s);
+        break;
+    case AC97_Powerdown_Ctrl_Stat:
+        val &= ~0xf;
+        val |= mixer_load (s, index) & 0xf;
+        mixer_store (s, index, val);
+        break;
+#ifdef USE_MIXER
+    case AC97_Master_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_VOLUME, val);
+        break;
+    case AC97_PCM_Out_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_PCM, val);
+        break;
+    case AC97_Line_In_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_LINE_IN, val);
+        break;
+    case AC97_Record_Select:
+        record_select (s, val);
+        break;
+#endif
+    case AC97_Vendor_ID1:
+    case AC97_Vendor_ID2:
+        dolog ("Attempt to write vendor ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_ID:
+        dolog ("Attempt to write extended audio ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_Ctrl_Stat:
+        if (!(val & EACS_VRA)) {
+            mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
+            mixer_store (s, AC97_PCM_LR_ADC_Rate,    0xbb80);
+            open_voice (s, PI_INDEX, 48000);
+            open_voice (s, PO_INDEX, 48000);
+        }
+        if (!(val & EACS_VRM)) {
+            mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
+            open_voice (s, MC_INDEX, 48000);
+        }
+        dolog ("Setting extended audio control to %#x\n", val);
+        mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val);
+        break;
+    case AC97_PCM_Front_DAC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front DAC rate to %d\n", val);
+            open_voice (s, PO_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set front DAC rate to %d, "
+                   "but VRA is not set\n",
+                   val);
+        }
+        break;
+    case AC97_MIC_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) {
+            mixer_store (s, index, val);
+            dolog ("Set MIC ADC rate to %d\n", val);
+            open_voice (s, MC_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set MIC ADC rate to %d, "
+                   "but VRM is not set\n",
+                   val);
+        }
+        break;
+    case AC97_PCM_LR_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front LR ADC rate to %d\n", val);
+            open_voice (s, PI_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n",
+                    val);
+        }
+        break;
+    default:
+        dolog ("U nam writew %#x <- %#x\n", addr, val);
+        mixer_store (s, index, val);
+        break;
+    }
+}
+
+static void nam_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam writel %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+/**
+ * Native audio bus master
+ * I/O Reads
+ */
+static uint32_t nabm_readb (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case CAS:
+        dolog ("CAS %d\n", s->cas);
+        val = s->cas;
+        s->cas = 1;
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ;
+        dolog ("CIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->lvi;
+        dolog ("LVI[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PIV:
+    case PO_PIV:
+    case MC_PIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->piv;
+        dolog ("PIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->cr;
+        dolog ("CR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr & 0xff;
+        dolog ("SRb[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readw (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr;
+        dolog ("SR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb;
+        dolog ("PICB[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readw %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readl (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->bdbar;
+        dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ | (r->lvi << 8) | (r->sr << 16);
+        dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
+               r->civ, r->lvi, r->sr);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb | (r->piv << 16) | (r->cr << 24);
+        dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
+               val, r->picb, r->piv, r->cr);
+        break;
+    case GLOB_CNT:
+        val = s->glob_cnt;
+        dolog ("glob_cnt -> %#x\n", val);
+        break;
+    case GLOB_STA:
+        val = s->glob_sta | GS_S0CR;
+        dolog ("glob_sta -> %#x\n", val);
+        break;
+    default:
+        dolog ("U nabm readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+/**
+ * Native audio bus master
+ * I/O Writes
+ */
+static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
+            r->sr &= ~(SR_DCH | SR_CELV);
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+        }
+        r->lvi = val % 32;
+        dolog ("LVI[%d] <- %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        if (val & CR_RR) {
+            reset_bm_regs (s, r);
+        }
+        else {
+            r->cr = val & CR_VALID_MASK;
+            if (!(r->cr & CR_RPBM)) {
+                voice_set_active (s, r - s->bm_regs, 0);
+                r->sr |= SR_DCH;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+                r->sr &= ~SR_DCH;
+                voice_set_active (s, r - s->bm_regs, 1);
+            }
+        }
+        dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->bdbar = val & ~3;
+        dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n",
+               GET_BM (index), val, r->bdbar);
+        break;
+    case GLOB_CNT:
+        if (val & GC_WR)
+            warm_reset (s);
+        if (val & GC_CR)
+            cold_reset (s);
+        if (!(val & (GC_WR | GC_CR)))
+            s->glob_cnt = val & GC_VALID_MASK;
+        dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt);
+        break;
+    case GLOB_STA:
+        s->glob_sta &= ~(val & GS_WCLEAR_MASK);
+        s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
+        dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta);
+        break;
+    default:
+        dolog ("U nabm writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                        int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t written = 0;
+    int to_copy = 0;
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int copied;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        cpu_physical_memory_read (addr, tmpbuf, to_copy);
+        copied = AUD_write (s->voice_po, tmpbuf, to_copy);
+        dolog ("write_audio max=%x to_copy=%x copied=%x\n",
+               max, to_copy, copied);
+        if (!copied) {
+            *stop = 1;
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        written += copied;
+    }
+
+    if (!temp) {
+        if (to_copy < 4) {
+            dolog ("whoops\n");
+            s->last_samp = 0;
+        }
+        else {
+            s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
+        }
+    }
+
+    r->bd.addr = addr;
+    return written;
+}
+
+static void write_bup (AC97LinkState *s, int elapsed)
+{
+    dolog ("write_bup\n");
+    if (!(s->bup_flag & BUP_SET)) {
+        if (s->bup_flag & BUP_LAST) {
+            int i;
+            uint8_t *p = s->silence;
+            for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) {
+                *(uint32_t *) p = s->last_samp;
+            }
+        }
+        else {
+            memset (s->silence, 0, sizeof (s->silence));
+        }
+        s->bup_flag |= BUP_SET;
+    }
+
+    while (elapsed) {
+        int temp = audio_MIN (elapsed, sizeof (s->silence));
+        while (temp) {
+            int copied = AUD_write (s->voice_po, s->silence, temp);
+            if (!copied)
+                return;
+            temp -= copied;
+            elapsed -= copied;
+        }
+    }
+}
+
+static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                       int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t nread = 0;
+    int to_copy = 0;
+    SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
+
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int acquired;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        acquired = AUD_read (voice, tmpbuf, to_copy);
+        if (!acquired) {
+            *stop = 1;
+            break;
+        }
+        cpu_physical_memory_write (addr, tmpbuf, acquired);
+        temp -= acquired;
+        addr += acquired;
+        nread += acquired;
+    }
+
+    r->bd.addr = addr;
+    return nread;
+}
+
+static void transfer_audio (AC97LinkState *s, int index, int elapsed)
+{
+    AC97BusMasterRegs *r = &s->bm_regs[index];
+    int stop = 0;
+
+    if (s->invalid_freq[index]) {
+        AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
+                 index, s->invalid_freq[index]);
+        return;
+    }
+
+    if (r->sr & SR_DCH) {
+        if (r->cr & CR_RPBM) {
+            switch (index) {
+            case PO_INDEX:
+                write_bup (s, elapsed);
+                break;
+            }
+        }
+        return;
+    }
+
+    while ((elapsed >> 1) && !stop) {
+        int temp;
+
+        if (!r->bd_valid) {
+            dolog ("invalid bd\n");
+            fetch_bd (s, r);
+        }
+
+        if (!r->picb) {
+            dolog ("fresh bd %d is empty %#x %#x\n",
+                   r->civ, r->bd.addr, r->bd.ctl_len);
+            if (r->civ == r->lvi) {
+                r->sr |= SR_DCH; /* CELV? */
+                s->bup_flag = 0;
+                break;
+            }
+            r->sr &= ~SR_CELV;
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+            return;
+        }
+
+        switch (index) {
+        case PO_INDEX:
+            temp = write_audio (s, r, elapsed, &stop);
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+
+        case PI_INDEX:
+        case MC_INDEX:
+            temp = read_audio (s, r, elapsed, &stop);
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+        }
+
+        if (!r->picb) {
+            uint32_t new_sr = r->sr & ~SR_CELV;
+
+            if (r->bd.ctl_len & BD_IOC) {
+                new_sr |= SR_BCIS;
+            }
+
+            if (r->civ == r->lvi) {
+                dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi);
+
+                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
+                stop = 1;
+                s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+            }
+
+            update_sr (s, r, new_sr);
+        }
+    }
+}
+
+static void pi_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, PI_INDEX, avail);
+}
+
+static void mc_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, MC_INDEX, avail);
+}
+
+static void po_callback (void *opaque, int free)
+{
+    transfer_audio (opaque, PO_INDEX, free);
+}
+
+static const VMStateDescription vmstate_ac97_bm_regs = {
+    .name = "ac97_bm_regs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(bdbar, AC97BusMasterRegs),
+        VMSTATE_UINT8(civ, AC97BusMasterRegs),
+        VMSTATE_UINT8(lvi, AC97BusMasterRegs),
+        VMSTATE_UINT16(sr, AC97BusMasterRegs),
+        VMSTATE_UINT16(picb, AC97BusMasterRegs),
+        VMSTATE_UINT8(piv, AC97BusMasterRegs),
+        VMSTATE_UINT8(cr, AC97BusMasterRegs),
+        VMSTATE_UINT32(bd_valid, AC97BusMasterRegs),
+        VMSTATE_UINT32(bd.addr, AC97BusMasterRegs),
+        VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ac97_post_load (void *opaque, int version_id)
+{
+    uint8_t active[LAST_INDEX];
+    AC97LinkState *s = opaque;
+
+#ifdef USE_MIXER
+    record_select (s, mixer_load (s, AC97_Record_Select));
+#define V_(a, b) set_volume (s, a, b, mixer_load (s, a))
+    V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
+    V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
+    V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
+#undef V_
+#endif
+    active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
+    active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
+    active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
+    reset_voices (s, active);
+
+    s->bup_flag = 0;
+    s->last_samp = 0;
+    return 0;
+}
+
+static bool is_version_2 (void *opaque, int version_id)
+{
+    return version_id == 2;
+}
+
+static const VMStateDescription vmstate_ac97 = {
+    .name = "ac97",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = ac97_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, AC97LinkState),
+        VMSTATE_UINT32(glob_cnt, AC97LinkState),
+        VMSTATE_UINT32(glob_sta, AC97LinkState),
+        VMSTATE_UINT32(cas, AC97LinkState),
+        VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1,
+                             vmstate_ac97_bm_regs, AC97BusMasterRegs),
+        VMSTATE_BUFFER(mixer_data, AC97LinkState),
+        VMSTATE_UNUSED_TEST(is_version_2, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ac97_map (PCIDevice *pci_dev, int region_num,
+                      pcibus_t addr, pcibus_t size, int type)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
+    PCIDevice *d = &s->dev;
+
+    if (!region_num) {
+        s->base[0] = addr;
+        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
+        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
+        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
+        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
+        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
+        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
+    }
+    else {
+        s->base[1] = addr;
+        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
+        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
+        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
+        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
+        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
+        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
+    }
+}
+
+static void ac97_on_reset (void *opaque)
+{
+    AC97LinkState *s = opaque;
+
+    reset_bm_regs (s, &s->bm_regs[0]);
+    reset_bm_regs (s, &s->bm_regs[1]);
+    reset_bm_regs (s, &s->bm_regs[2]);
+
+    /*
+     * Reset the mixer too. The Windows XP driver seems to rely on
+     * this. At least it wants to read the vendor id before it resets
+     * the codec manually.
+     */
+    mixer_reset (s);
+}
+
+static int ac97_initfn (PCIDevice *dev)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+    uint8_t *c = s->dev.config;
+
+    /* TODO: no need to override */
+    c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
+    c[PCI_COMMAND + 1] = 0x00;
+
+    /* TODO: */
+    c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
+    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
+
+    c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
+
+    /* TODO set when bar is registered. no need to override. */
+    /* nabmar native audio mixer base address rw */
+    c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO;
+    c[PCI_BASE_ADDRESS_0 + 1] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 2] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 3] = 0x00;
+
+    /* TODO set when bar is registered. no need to override. */
+      /* nabmbar native audio bus mastering base address rw */
+    c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO;
+    c[PCI_BASE_ADDRESS_0 + 5] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
+
+    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;      /* svid subsystem vendor id rwo */
+    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
+
+    c[PCI_SUBSYSTEM_ID] = 0x00;      /* sid subsystem id rwo */
+    c[PCI_SUBSYSTEM_ID + 1] = 0x00;
+
+    c[PCI_INTERRUPT_LINE] = 0x00;      /* intr_ln interrupt line rw */
+    /* TODO: RST# value should be 0. */
+    c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
+
+    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
+                      ac97_map);
+    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
+    qemu_register_reset (ac97_on_reset, s);
+    AUD_register_card ("ac97", &s->card);
+    ac97_on_reset (s);
+    return 0;
+}
+
+int ac97_init (PCIBus *bus)
+{
+    pci_create_simple (bus, -1, "AC97");
+    return 0;
+}
+
+static PCIDeviceInfo ac97_info = {
+    .qdev.name    = "AC97",
+    .qdev.desc    = "Intel 82801AA AC97 Audio",
+    .qdev.size    = sizeof (AC97LinkState),
+    .qdev.vmsd    = &vmstate_ac97,
+    .init         = ac97_initfn,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_82801AA_5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
+};
+
+static void ac97_register (void)
+{
+    pci_qdev_register (&ac97_info);
+}
+device_init (ac97_register);
+
diff --git a/qemu-0.15.x/hw/acpi.c b/qemu-0.15.x/hw/acpi.c
new file mode 100644
index 0000000..ad40fb4
--- /dev/null
+++ b/qemu-0.15.x/hw/acpi.c
@@ -0,0 +1,396 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "sysemu.h"
+#include "hw.h"
+#include "pc.h"
+#include "acpi.h"
+
+struct acpi_table_header
+{
+    char signature [4];    /* ACPI signature (4 ASCII characters) */
+    uint32_t length;          /* Length of table, in bytes, including header */
+    uint8_t revision;         /* ACPI Specification minor version # */
+    uint8_t checksum;         /* To make sum of entire table == 0 */
+    char oem_id [6];       /* OEM identification */
+    char oem_table_id [8]; /* OEM table identification */
+    uint32_t oem_revision;    /* OEM revision number */
+    char asl_compiler_id [4]; /* ASL compiler vendor ID */
+    uint32_t asl_compiler_revision; /* ASL compiler revision number */
+} __attribute__((packed));
+
+char *acpi_tables;
+size_t acpi_tables_len;
+
+static int acpi_checksum(const uint8_t *data, int len)
+{
+    int sum, i;
+    sum = 0;
+    for(i = 0; i < len; i++)
+        sum += data[i];
+    return (-sum) & 0xff;
+}
+
+int acpi_table_add(const char *t)
+{
+    static const char *dfl_id = "QEMUQEMU";
+    char buf[1024], *p, *f;
+    struct acpi_table_header acpi_hdr;
+    unsigned long val;
+    uint32_t length;
+    struct acpi_table_header *acpi_hdr_p;
+    size_t off;
+
+    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
+  
+    if (get_param_value(buf, sizeof(buf), "sig", t)) {
+        strncpy(acpi_hdr.signature, buf, 4);
+    } else {
+        strncpy(acpi_hdr.signature, dfl_id, 4);
+    }
+    if (get_param_value(buf, sizeof(buf), "rev", t)) {
+        val = strtoul(buf, &p, 10);
+        if (val > 255 || *p != '\0')
+            goto out;
+    } else {
+        val = 1;
+    }
+    acpi_hdr.revision = (int8_t)val;
+
+    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
+        strncpy(acpi_hdr.oem_id, buf, 6);
+    } else {
+        strncpy(acpi_hdr.oem_id, dfl_id, 6);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
+        strncpy(acpi_hdr.oem_table_id, buf, 8);
+    } else {
+        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
+        val = strtol(buf, &p, 10);
+        if(*p != '\0')
+            goto out;
+    } else {
+        val = 1;
+    }
+    acpi_hdr.oem_revision = cpu_to_le32(val);
+
+    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
+        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
+    } else {
+        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
+        val = strtol(buf, &p, 10);
+        if(*p != '\0')
+            goto out;
+    } else {
+        val = 1;
+    }
+    acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
+    
+    if (!get_param_value(buf, sizeof(buf), "data", t)) {
+         buf[0] = '\0';
+    }
+
+    length = sizeof(acpi_hdr);
+
+    f = buf;
+    while (buf[0]) {
+        struct stat s;
+        char *n = strchr(f, ':');
+        if (n)
+            *n = '\0';
+        if(stat(f, &s) < 0) {
+            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
+            goto out;
+        }
+        length += s.st_size;
+        if (!n)
+            break;
+        *n = ':';
+        f = n + 1;
+    }
+
+    if (!acpi_tables) {
+        acpi_tables_len = sizeof(uint16_t);
+        acpi_tables = qemu_mallocz(acpi_tables_len);
+    }
+    acpi_tables = qemu_realloc(acpi_tables,
+                               acpi_tables_len + sizeof(uint16_t) + length);
+    p = acpi_tables + acpi_tables_len;
+    acpi_tables_len += sizeof(uint16_t) + length;
+
+    *(uint16_t*)p = cpu_to_le32(length);
+    p += sizeof(uint16_t);
+    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
+    off = sizeof(acpi_hdr);
+
+    f = buf;
+    while (buf[0]) {
+        struct stat s;
+        int fd;
+        char *n = strchr(f, ':');
+        if (n)
+            *n = '\0';
+        fd = open(f, O_RDONLY);
+
+        if(fd < 0)
+            goto out;
+        if(fstat(fd, &s) < 0) {
+            close(fd);
+            goto out;
+        }
+
+        /* off < length is necessary because file size can be changed
+           under our foot */
+        while(s.st_size && off < length) {
+            int r;
+            r = read(fd, p + off, s.st_size);
+            if (r > 0) {
+                off += r;
+                s.st_size -= r;
+            } else if ((r < 0 && errno != EINTR) || r == 0) {
+                close(fd);
+                goto out;
+            }
+        }
+
+        close(fd);
+        if (!n)
+            break;
+        f = n + 1;
+    }
+    if (off < length) {
+        /* don't pass random value in process to guest */
+        memset(p + off, 0, length - off);
+    }
+
+    acpi_hdr_p = (struct acpi_table_header*)p;
+    acpi_hdr_p->length = cpu_to_le32(length);
+    acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
+    /* increase number of tables */
+    (*(uint16_t*)acpi_tables) =
+	    cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
+    return 0;
+out:
+    if (acpi_tables) {
+        qemu_free(acpi_tables);
+        acpi_tables = NULL;
+    }
+    return -1;
+}
+
+/* ACPI PM1a EVT */
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    if (d >= overflow_time) {
+        pm1->sts |= ACPI_BITMASK_TIMER_STATUS;
+    }
+    return pm1->sts;
+}
+
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val)
+{
+    uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time);
+    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+        /* if TMRSTS is reset, then compute the new overflow time */
+        acpi_pm_tmr_calc_overflow_time(tmr);
+    }
+    pm1->sts &= ~val;
+}
+
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr)
+{
+    if (!pm1) {
+        qemu_system_shutdown_request();
+    } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+        pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+        tmr->update_sci(tmr);
+    }
+}
+
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1)
+{
+    pm1->sts = 0;
+    pm1->en = 0;
+}
+
+/* ACPI PM_TMR */
+void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable)
+{
+    int64_t expire_time;
+
+    /* schedule a timer interruption if needed */
+    if (enable) {
+        expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(),
+                               PM_TIMER_FREQUENCY);
+        qemu_mod_timer(tmr->timer, expire_time);
+    } else {
+        qemu_del_timer(tmr->timer);
+    }
+}
+
+void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
+}
+
+uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr)
+{
+    uint32_t d = acpi_pm_tmr_get_clock();;
+    return d & 0xffffff;
+}
+
+static void acpi_pm_tmr_timer(void *opaque)
+{
+    ACPIPMTimer *tmr = opaque;
+    tmr->update_sci(tmr);
+}
+
+void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci)
+{
+    tmr->update_sci = update_sci;
+    tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr);
+}
+
+void acpi_pm_tmr_reset(ACPIPMTimer *tmr)
+{
+    tmr->overflow_time = 0;
+    qemu_del_timer(tmr->timer);
+}
+
+/* ACPI PM1aCNT */
+void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3)
+{
+    pm1_cnt->cmos_s3 = cmos_s3;
+}
+
+void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val)
+{
+    pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+
+    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+        /* change suspend type */
+        uint16_t sus_typ = (val >> 10) & 7;
+        switch(sus_typ) {
+        case 0: /* soft power off */
+            qemu_system_shutdown_request();
+            break;
+        case 1:
+            /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
+               Pretend that resume was caused by power button */
+            pm1a->sts |=
+                (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
+            qemu_system_reset_request();
+            qemu_irq_raise(pm1_cnt->cmos_s3);
+        default:
+            break;
+        }
+    }
+}
+
+void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
+                         bool sci_enable, bool sci_disable)
+{
+    /* ACPI specs 3.0, 4.7.2.5 */
+    if (sci_enable) {
+        pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE;
+    } else if (sci_disable) {
+        pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE;
+    }
+}
+
+void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt)
+{
+    pm1_cnt->cnt = 0;
+    if (pm1_cnt->cmos_s3) {
+        qemu_irq_lower(pm1_cnt->cmos_s3);
+    }
+}
+
+/* ACPI GPE */
+void acpi_gpe_init(ACPIGPE *gpe, uint8_t len)
+{
+    gpe->len = len;
+    gpe->sts = qemu_mallocz(len / 2);
+    gpe->en = qemu_mallocz(len / 2);
+}
+
+void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk)
+{
+    gpe->blk = blk;
+}
+
+void acpi_gpe_reset(ACPIGPE *gpe)
+{
+    memset(gpe->sts, 0, gpe->len / 2);
+    memset(gpe->en, 0, gpe->len / 2);
+}
+
+static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr)
+{
+    uint8_t *cur = NULL;
+
+    if (addr < gpe->len / 2) {
+        cur = gpe->sts + addr;
+    } else if (addr < gpe->len) {
+        cur = gpe->en + addr - gpe->len / 2;
+    } else {
+        abort();
+    }
+
+    return cur;
+}
+
+void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val)
+{
+    uint8_t *cur;
+
+    addr -= gpe->blk;
+    cur = acpi_gpe_ioport_get_ptr(gpe, addr);
+    if (addr < gpe->len / 2) {
+        /* GPE_STS */
+        *cur = (*cur) & ~val;
+    } else if (addr < gpe->len) {
+        /* GPE_EN */
+        *cur = val;
+    } else {
+        abort();
+    }
+}
+
+uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr)
+{
+    uint8_t *cur;
+    uint32_t val;
+
+    addr -= gpe->blk;
+    cur = acpi_gpe_ioport_get_ptr(gpe, addr);
+    val = 0;
+    if (cur != NULL) {
+        val = *cur;
+    }
+
+    return val;
+}
diff --git a/qemu-0.15.x/hw/acpi.h b/qemu-0.15.x/hw/acpi.h
new file mode 100644
index 0000000..c141e65
--- /dev/null
+++ b/qemu-0.15.x/hw/acpi.h
@@ -0,0 +1,146 @@
+#ifndef QEMU_HW_ACPI_H
+#define QEMU_HW_ACPI_H
+/*
+ *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                     VA Linux Systems Japan K.K.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* from linux include/acpi/actype.h */
+/* Default ACPI register widths */
+
+#define ACPI_GPE_REGISTER_WIDTH         8
+#define ACPI_PM1_REGISTER_WIDTH         16
+#define ACPI_PM2_REGISTER_WIDTH         8
+#define ACPI_PM_TIMER_WIDTH             32
+
+/* PM Timer ticks per second (HZ) */
+#define PM_TIMER_FREQUENCY  3579545
+
+
+/* ACPI fixed hardware registers */
+
+/* from linux/drivers/acpi/acpica/aclocal.h */
+/* Masks used to access the bit_registers */
+
+/* PM1x_STS */
+#define ACPI_BITMASK_TIMER_STATUS               0x0001
+#define ACPI_BITMASK_BUS_MASTER_STATUS          0x0010
+#define ACPI_BITMASK_GLOBAL_LOCK_STATUS         0x0020
+#define ACPI_BITMASK_POWER_BUTTON_STATUS        0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_STATUS        0x0200
+#define ACPI_BITMASK_RT_CLOCK_STATUS            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_STATUS         0x4000	/* ACPI 3.0 */
+#define ACPI_BITMASK_WAKE_STATUS                0x8000
+
+#define ACPI_BITMASK_ALL_FIXED_STATUS           (\
+	ACPI_BITMASK_TIMER_STATUS          | \
+	ACPI_BITMASK_BUS_MASTER_STATUS     | \
+	ACPI_BITMASK_GLOBAL_LOCK_STATUS    | \
+	ACPI_BITMASK_POWER_BUTTON_STATUS   | \
+	ACPI_BITMASK_SLEEP_BUTTON_STATUS   | \
+	ACPI_BITMASK_RT_CLOCK_STATUS       | \
+	ACPI_BITMASK_WAKE_STATUS)
+
+/* PM1x_EN */
+#define ACPI_BITMASK_TIMER_ENABLE               0x0001
+#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE         0x0020
+#define ACPI_BITMASK_POWER_BUTTON_ENABLE        0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE        0x0200
+#define ACPI_BITMASK_RT_CLOCK_ENABLE            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE        0x4000	/* ACPI 3.0 */
+
+/* PM1x_CNT */
+#define ACPI_BITMASK_SCI_ENABLE                 0x0001
+#define ACPI_BITMASK_BUS_MASTER_RLD             0x0002
+#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE        0x0004
+#define ACPI_BITMASK_SLEEP_TYPE                 0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE               0x2000
+
+/* PM2_CNT */
+#define ACPI_BITMASK_ARB_DISABLE                0x0001
+
+/* PM_TMR */
+struct ACPIPMTimer;
+typedef struct ACPIPMTimer ACPIPMTimer;
+
+typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr);
+
+struct ACPIPMTimer {
+    QEMUTimer *timer;
+    int64_t overflow_time;
+
+    acpi_update_sci_fn update_sci;
+};
+
+void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable);
+void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr);
+uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr);
+void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci);
+void acpi_pm_tmr_reset(ACPIPMTimer *tmr);
+
+#include "qemu-timer.h"
+static inline int64_t acpi_pm_tmr_get_clock(void)
+{
+    return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
+                    get_ticks_per_sec());
+}
+
+/* PM1a_EVT: piix and ich9 don't implement PM1b. */
+struct ACPIPM1EVT
+{
+    uint16_t sts;
+    uint16_t en;
+};
+typedef struct ACPIPM1EVT ACPIPM1EVT;
+
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time);
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val);
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr);
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1);
+
+/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
+struct ACPIPM1CNT {
+    uint16_t cnt;
+
+    qemu_irq cmos_s3;
+};
+typedef struct ACPIPM1CNT ACPIPM1CNT;
+
+void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3);
+void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val);
+void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
+                         bool sci_enable, bool sci_disable);
+void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt);
+
+/* GPE0 */
+struct ACPIGPE {
+    uint32_t blk;
+    uint8_t len;
+
+    uint8_t *sts;
+    uint8_t *en;
+};
+typedef struct ACPIGPE ACPIGPE;
+
+void acpi_gpe_init(ACPIGPE *gpe, uint8_t len);
+void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk);
+void acpi_gpe_reset(ACPIGPE *gpe);
+
+void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val);
+uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr);
+
+#endif /* !QEMU_HW_ACPI_H */
diff --git a/qemu-0.15.x/hw/acpi_piix4.c b/qemu-0.15.x/hw/acpi_piix4.c
new file mode 100644
index 0000000..29f0f76
--- /dev/null
+++ b/qemu-0.15.x/hw/acpi_piix4.c
@@ -0,0 +1,573 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "hw.h"
+#include "pc.h"
+#include "apm.h"
+#include "pm_smbus.h"
+#include "pci.h"
+#include "acpi.h"
+#include "sysemu.h"
+#include "range.h"
+#include "ioport.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define PIIX4_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
+#else
+# define PIIX4_DPRINTF(format, ...)     do { } while (0)
+#endif
+
+#define ACPI_DBG_IO_ADDR  0xb044
+
+#define GPE_BASE 0xafe0
+#define GPE_LEN 4
+#define PCI_BASE 0xae00
+#define PCI_EJ_BASE 0xae08
+#define PCI_RMV_BASE 0xae0c
+
+#define PIIX4_PCI_HOTPLUG_STATUS 2
+
+struct pci_status {
+    uint32_t up;
+    uint32_t down;
+};
+
+typedef struct PIIX4PMState {
+    PCIDevice dev;
+    IORange ioport;
+    ACPIPM1EVT pm1a;
+    ACPIPM1CNT pm1_cnt;
+
+    APMState apm;
+
+    ACPIPMTimer tmr;
+
+    PMSMBus smb;
+    uint32_t smb_io_base;
+
+    qemu_irq irq;
+    qemu_irq smi_irq;
+    int kvm_enabled;
+    Notifier machine_ready;
+
+    /* for pci hotplug */
+    ACPIGPE gpe;
+    struct pci_status pci0_status;
+    uint32_t pci0_hotplug_enable;
+} PIIX4PMState;
+
+static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
+
+#define ACPI_ENABLE 0xf1
+#define ACPI_DISABLE 0xf0
+
+static void pm_update_sci(PIIX4PMState *s)
+{
+    int sci_level, pmsts;
+
+    pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+    sci_level = (((pmsts & s->pm1a.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
+        (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+
+    qemu_set_irq(s->irq, sci_level);
+    /* schedule a timer interruption if needed */
+    acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
+}
+
+static void pm_tmr_timer(ACPIPMTimer *tmr)
+{
+    PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr);
+    pm_update_sci(s);
+}
+
+static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
+                            uint64_t val)
+{
+    PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
+
+    if (width != 2) {
+        PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n",
+                      (unsigned)addr, width, (unsigned)val);
+    }
+
+    switch(addr) {
+    case 0x00:
+        acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+        pm_update_sci(s);
+        break;
+    case 0x02:
+        s->pm1a.en = val;
+        pm_update_sci(s);
+        break;
+    case 0x04:
+        acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
+        break;
+    default:
+        break;
+    }
+    PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr,
+                  (unsigned int)val);
+}
+
+static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
+                            uint64_t *data)
+{
+    PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
+    uint32_t val;
+
+    switch(addr) {
+    case 0x00:
+        val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+        break;
+    case 0x02:
+        val = s->pm1a.en;
+        break;
+    case 0x04:
+        val = s->pm1_cnt.cnt;
+        break;
+    case 0x08:
+        val = acpi_pm_tmr_get(&s->tmr);
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val);
+    *data = val;
+}
+
+static const IORangeOps pm_iorange_ops = {
+    .read = pm_ioport_read,
+    .write = pm_ioport_write,
+};
+
+static void apm_ctrl_changed(uint32_t val, void *arg)
+{
+    PIIX4PMState *s = arg;
+
+    /* ACPI specs 3.0, 4.7.2.5 */
+    acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE);
+
+    if (s->dev.config[0x5b] & (1 << 1)) {
+        if (s->smi_irq) {
+            qemu_irq_raise(s->smi_irq);
+        }
+    }
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val);
+}
+
+static void pm_io_space_update(PIIX4PMState *s)
+{
+    uint32_t pm_io_base;
+
+    if (s->dev.config[0x80] & 1) {
+        pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
+        pm_io_base &= 0xffc0;
+
+        /* XXX: need to improve memory and ioport allocation */
+        PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
+        iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64);
+        ioport_register(&s->ioport);
+    }
+}
+
+static void pm_write_config(PCIDevice *d,
+                            uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(d, address, val, len);
+    if (range_covers_byte(address, len, 0x80))
+        pm_io_space_update((PIIX4PMState *)d);
+}
+
+static int vmstate_acpi_post_load(void *opaque, int version_id)
+{
+    PIIX4PMState *s = opaque;
+
+    pm_io_space_update(s);
+    return 0;
+}
+
+#define VMSTATE_GPE_ARRAY(_field, _state)                            \
+ {                                                                   \
+     .name       = (stringify(_field)),                              \
+     .version_id = 0,                                                \
+     .num        = GPE_LEN,                                          \
+     .info       = &vmstate_info_uint16,                             \
+     .size       = sizeof(uint16_t),                                 \
+     .flags      = VMS_ARRAY | VMS_POINTER,                          \
+     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
+ }
+
+static const VMStateDescription vmstate_gpe = {
+    .name = "gpe",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_GPE_ARRAY(sts, ACPIGPE),
+        VMSTATE_GPE_ARRAY(en, ACPIGPE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_status = {
+    .name = "pci_status",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(up, struct pci_status),
+        VMSTATE_UINT32(down, struct pci_status),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_acpi = {
+    .name = "piix4_pm",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_acpi_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
+        VMSTATE_UINT16(pm1a.sts, PIIX4PMState),
+        VMSTATE_UINT16(pm1a.en, PIIX4PMState),
+        VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState),
+        VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+        VMSTATE_TIMER(tmr.timer, PIIX4PMState),
+        VMSTATE_INT64(tmr.overflow_time, PIIX4PMState),
+        VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
+        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
+                       struct pci_status),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void piix4_update_hotplug(PIIX4PMState *s)
+{
+    PCIDevice *dev = &s->dev;
+    BusState *bus = qdev_get_parent_bus(&dev->qdev);
+    DeviceState *qdev, *next;
+
+    s->pci0_hotplug_enable = ~0;
+
+    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+        PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+        int slot = PCI_SLOT(pdev->devfn);
+
+        if (info->no_hotplug) {
+            s->pci0_hotplug_enable &= ~(1 << slot);
+        }
+    }
+}
+
+static void piix4_reset(void *opaque)
+{
+    PIIX4PMState *s = opaque;
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_conf[0x58] = 0;
+    pci_conf[0x59] = 0;
+    pci_conf[0x5a] = 0;
+    pci_conf[0x5b] = 0;
+
+    if (s->kvm_enabled) {
+        /* Mark SMM as already inited (until KVM supports SMM). */
+        pci_conf[0x5B] = 0x02;
+    }
+    piix4_update_hotplug(s);
+}
+
+static void piix4_powerdown(void *opaque, int irq, int power_failing)
+{
+    PIIX4PMState *s = opaque;
+    ACPIPM1EVT *pm1a = s? &s->pm1a: NULL;
+    ACPIPMTimer *tmr = s? &s->tmr: NULL;
+
+    acpi_pm1_evt_power_down(pm1a, tmr);
+}
+
+static void piix4_pm_machine_ready(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+    pci_conf[0x63] = 0x60;
+    pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
+	(isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
+
+}
+
+static int piix4_pm_initfn(PCIDevice *dev)
+{
+    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x06] = 0x80;
+    pci_conf[0x07] = 0x02;
+    pci_conf[0x09] = 0x00;
+    pci_conf[0x3d] = 0x01; // interrupt pin 1
+
+    pci_conf[0x40] = 0x01; /* PM io base read only bit */
+
+    /* APM */
+    apm_init(&s->apm, apm_ctrl_changed, s);
+
+    register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
+
+    if (s->kvm_enabled) {
+        /* Mark SMM as already inited to prevent SMM from running.  KVM does not
+         * support SMM mode. */
+        pci_conf[0x5B] = 0x02;
+    }
+
+    /* XXX: which specification is used ? The i82731AB has different
+       mappings */
+    pci_conf[0x90] = s->smb_io_base | 1;
+    pci_conf[0x91] = s->smb_io_base >> 8;
+    pci_conf[0xd2] = 0x09;
+    register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
+    register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
+
+    acpi_pm_tmr_init(&s->tmr, pm_tmr_timer);
+    acpi_gpe_init(&s->gpe, GPE_LEN);
+
+    qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
+
+    pm_smbus_init(&s->dev.qdev, &s->smb);
+    s->machine_ready.notify = piix4_pm_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
+    qemu_register_reset(piix4_reset, s);
+    piix4_acpi_system_hot_add_init(dev->bus, s);
+
+    return 0;
+}
+
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
+                       int kvm_enabled)
+{
+    PCIDevice *dev;
+    PIIX4PMState *s;
+
+    dev = pci_create(bus, devfn, "PIIX4_PM");
+    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+
+    s = DO_UPCAST(PIIX4PMState, dev, dev);
+    s->irq = sci_irq;
+    acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3);
+    s->smi_irq = smi_irq;
+    s->kvm_enabled = kvm_enabled;
+
+    qdev_init_nofail(&dev->qdev);
+
+    return s->smb.smbus;
+}
+
+static PCIDeviceInfo piix4_pm_info = {
+    .qdev.name          = "PIIX4_PM",
+    .qdev.desc          = "PM",
+    .qdev.size          = sizeof(PIIX4PMState),
+    .qdev.vmsd          = &vmstate_acpi,
+    .qdev.no_user       = 1,
+    .no_hotplug         = 1,
+    .init               = piix4_pm_initfn,
+    .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_INTEL,
+    .device_id          = PCI_DEVICE_ID_INTEL_82371AB_3,
+    .revision           = 0x03,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
+    .qdev.props         = (Property[]) {
+        DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void piix4_pm_register(void)
+{
+    pci_qdev_register(&piix4_pm_info);
+}
+
+device_init(piix4_pm_register);
+
+static uint32_t gpe_readb(void *opaque, uint32_t addr)
+{
+    PIIX4PMState *s = opaque;
+    uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr);
+
+    PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
+    return val;
+}
+
+static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PIIX4PMState *s = opaque;
+
+    acpi_gpe_ioport_writeb(&s->gpe, addr, val);
+    pm_update_sci(s);
+
+    PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
+}
+
+static uint32_t pcihotplug_read(void *opaque, uint32_t addr)
+{
+    uint32_t val = 0;
+    struct pci_status *g = opaque;
+    switch (addr) {
+        case PCI_BASE:
+            val = g->up;
+            break;
+        case PCI_BASE + 4:
+            val = g->down;
+            break;
+        default:
+            break;
+    }
+
+    PIIX4_DPRINTF("pcihotplug read %x == %x\n", addr, val);
+    return val;
+}
+
+static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct pci_status *g = opaque;
+    switch (addr) {
+        case PCI_BASE:
+            g->up = val;
+            break;
+        case PCI_BASE + 4:
+            g->down = val;
+            break;
+   }
+
+    PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val);
+}
+
+static uint32_t pciej_read(void *opaque, uint32_t addr)
+{
+    PIIX4_DPRINTF("pciej read %x\n", addr);
+    return 0;
+}
+
+static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    BusState *bus = opaque;
+    DeviceState *qdev, *next;
+    PCIDevice *dev;
+    PCIDeviceInfo *info;
+    int slot = ffs(val) - 1;
+
+    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+        dev = DO_UPCAST(PCIDevice, qdev, qdev);
+        info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
+            qdev_free(qdev);
+        }
+    }
+
+
+    PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
+}
+
+static uint32_t pcirmv_read(void *opaque, uint32_t addr)
+{
+    PIIX4PMState *s = opaque;
+
+    return s->pci0_hotplug_enable;
+}
+
+static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    return;
+}
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+                                PCIHotplugState state);
+
+static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
+{
+    struct pci_status *pci0_status = &s->pci0_status;
+
+    register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
+    register_ioport_read(GPE_BASE, GPE_LEN, 1,  gpe_readb, s);
+    acpi_gpe_blk(&s->gpe, GPE_BASE);
+
+    register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
+    register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, pci0_status);
+
+    register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
+    register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus);
+
+    register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
+    register_ioport_read(PCI_RMV_BASE, 4, 4,  pcirmv_read, s);
+
+    pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
+}
+
+static void enable_device(PIIX4PMState *s, int slot)
+{
+    s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->pci0_status.up |= (1 << slot);
+}
+
+static void disable_device(PIIX4PMState *s, int slot)
+{
+    s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->pci0_status.down |= (1 << slot);
+}
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+				PCIHotplugState state)
+{
+    int slot = PCI_SLOT(dev->devfn);
+    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
+                                DO_UPCAST(PCIDevice, qdev, qdev));
+
+    /* Don't send event when device is enabled during qemu machine creation:
+     * it is present on boot, no hotplug event is necessary. We do send an
+     * event when the device is disabled later. */
+    if (state == PCI_COLDPLUG_ENABLED) {
+        return 0;
+    }
+
+    s->pci0_status.up = 0;
+    s->pci0_status.down = 0;
+    if (state == PCI_HOTPLUG_ENABLED) {
+        enable_device(s, slot);
+    } else {
+        disable_device(s, slot);
+    }
+
+    pm_update_sci(s);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/adb.c b/qemu-0.15.x/hw/adb.c
new file mode 100644
index 0000000..7499cdc
--- /dev/null
+++ b/qemu-0.15.x/hw/adb.c
@@ -0,0 +1,455 @@
+/*
+ * QEMU ADB support
+ *
+ * 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 "hw.h"
+#include "ppc_mac.h"
+#include "console.h"
+
+/* debug ADB */
+//#define DEBUG_ADB
+
+#ifdef DEBUG_ADB
+#define ADB_DPRINTF(fmt, ...) \
+do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define ADB_DPRINTF(fmt, ...)
+#endif
+
+/* ADB commands */
+#define ADB_BUSRESET		0x00
+#define ADB_FLUSH               0x01
+#define ADB_WRITEREG		0x08
+#define ADB_READREG		0x0c
+
+/* ADB device commands */
+#define ADB_CMD_SELF_TEST		0xff
+#define ADB_CMD_CHANGE_ID		0xfe
+#define ADB_CMD_CHANGE_ID_AND_ACT	0xfd
+#define ADB_CMD_CHANGE_ID_AND_ENABLE	0x00
+
+/* ADB default device IDs (upper 4 bits of ADB command byte) */
+#define ADB_DONGLE	1
+#define ADB_KEYBOARD	2
+#define ADB_MOUSE	3
+#define ADB_TABLET	4
+#define ADB_MODEM	5
+#define ADB_MISC	7
+
+/* error codes */
+#define ADB_RET_NOTPRESENT (-2)
+
+int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
+{
+    ADBDevice *d;
+    int devaddr, cmd, i;
+
+    cmd = buf[0] & 0xf;
+    if (cmd == ADB_BUSRESET) {
+        for(i = 0; i < s->nb_devices; i++) {
+            d = &s->devices[i];
+            if (d->devreset) {
+                d->devreset(d);
+            }
+        }
+        return 0;
+    }
+    devaddr = buf[0] >> 4;
+    for(i = 0; i < s->nb_devices; i++) {
+        d = &s->devices[i];
+        if (d->devaddr == devaddr) {
+            return d->devreq(d, obuf, buf, len);
+        }
+    }
+    return ADB_RET_NOTPRESENT;
+}
+
+/* XXX: move that to cuda ? */
+int adb_poll(ADBBusState *s, uint8_t *obuf)
+{
+    ADBDevice *d;
+    int olen, i;
+    uint8_t buf[1];
+
+    olen = 0;
+    for(i = 0; i < s->nb_devices; i++) {
+        if (s->poll_index >= s->nb_devices)
+            s->poll_index = 0;
+        d = &s->devices[s->poll_index];
+        buf[0] = ADB_READREG | (d->devaddr << 4);
+        olen = adb_request(s, obuf + 1, buf, 1);
+        /* if there is data, we poll again the same device */
+        if (olen > 0) {
+            obuf[0] = buf[0];
+            olen++;
+            break;
+        }
+        s->poll_index++;
+    }
+    return olen;
+}
+
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
+                               void *opaque)
+{
+    ADBDevice *d;
+    if (s->nb_devices >= MAX_ADB_DEVICES)
+        return NULL;
+    d = &s->devices[s->nb_devices++];
+    d->bus = s;
+    d->devaddr = devaddr;
+    d->devreq = devreq;
+    d->devreset = devreset;
+    d->opaque = opaque;
+    qemu_register_reset((QEMUResetHandler *)devreset, d);
+    return d;
+}
+
+/***************************************************************/
+/* Keyboard ADB device */
+
+typedef struct KBDState {
+    uint8_t data[128];
+    int rptr, wptr, count;
+} KBDState;
+
+static const uint8_t pc_to_adb_keycode[256] = {
+  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+ 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
+  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
+ 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+ 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+ 84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
+ 61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static void adb_kbd_put_keycode(void *opaque, int keycode)
+{
+    ADBDevice *d = opaque;
+    KBDState *s = d->opaque;
+
+    if (s->count < sizeof(s->data)) {
+        s->data[s->wptr] = keycode;
+        if (++s->wptr == sizeof(s->data))
+            s->wptr = 0;
+        s->count++;
+    }
+}
+
+static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
+{
+    static int ext_keycode;
+    KBDState *s = d->opaque;
+    int adb_keycode, keycode;
+    int olen;
+
+    olen = 0;
+    for(;;) {
+        if (s->count == 0)
+            break;
+        keycode = s->data[s->rptr];
+        if (++s->rptr == sizeof(s->data))
+            s->rptr = 0;
+        s->count--;
+
+        if (keycode == 0xe0) {
+            ext_keycode = 1;
+        } else {
+            if (ext_keycode)
+                adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
+            else
+                adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
+            obuf[0] = adb_keycode | (keycode & 0x80);
+            /* NOTE: could put a second keycode if needed */
+            obuf[1] = 0xff;
+            olen = 2;
+            ext_keycode = 0;
+            break;
+        }
+    }
+    return olen;
+}
+
+static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
+                           const uint8_t *buf, int len)
+{
+    KBDState *s = d->opaque;
+    int cmd, reg, olen;
+
+    if ((buf[0] & 0x0f) == ADB_FLUSH) {
+        /* flush keyboard fifo */
+        s->wptr = s->rptr = s->count = 0;
+        return 0;
+    }
+
+    cmd = buf[0] & 0xc;
+    reg = buf[0] & 0x3;
+    olen = 0;
+    switch(cmd) {
+    case ADB_WRITEREG:
+        switch(reg) {
+        case 2:
+            /* LED status */
+            break;
+        case 3:
+            switch(buf[2]) {
+            case ADB_CMD_SELF_TEST:
+                break;
+            case ADB_CMD_CHANGE_ID:
+            case ADB_CMD_CHANGE_ID_AND_ACT:
+            case ADB_CMD_CHANGE_ID_AND_ENABLE:
+                d->devaddr = buf[1] & 0xf;
+                break;
+            default:
+                /* XXX: check this */
+                d->devaddr = buf[1] & 0xf;
+                d->handler = buf[2];
+                break;
+            }
+        }
+        break;
+    case ADB_READREG:
+        switch(reg) {
+        case 0:
+            olen = adb_kbd_poll(d, obuf);
+            break;
+        case 1:
+            break;
+        case 2:
+            obuf[0] = 0x00; /* XXX: check this */
+            obuf[1] = 0x07; /* led status */
+            olen = 2;
+            break;
+        case 3:
+            obuf[0] = d->handler;
+            obuf[1] = d->devaddr;
+            olen = 2;
+            break;
+        }
+        break;
+    }
+    return olen;
+}
+
+static const VMStateDescription vmstate_adb_kbd = {
+    .name = "adb_kbd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BUFFER(data, KBDState),
+        VMSTATE_INT32(rptr, KBDState),
+        VMSTATE_INT32(wptr, KBDState),
+        VMSTATE_INT32(count, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int adb_kbd_reset(ADBDevice *d)
+{
+    KBDState *s = d->opaque;
+
+    d->handler = 1;
+    d->devaddr = ADB_KEYBOARD;
+    memset(s, 0, sizeof(KBDState));
+
+    return 0;
+}
+
+void adb_kbd_init(ADBBusState *bus)
+{
+    ADBDevice *d;
+    KBDState *s;
+    s = qemu_mallocz(sizeof(KBDState));
+    d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
+                            adb_kbd_reset, s);
+    qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
+    vmstate_register(NULL, -1, &vmstate_adb_kbd, s);
+}
+
+/***************************************************************/
+/* Mouse ADB device */
+
+typedef struct MouseState {
+    int buttons_state, last_buttons_state;
+    int dx, dy, dz;
+} MouseState;
+
+static void adb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    ADBDevice *d = opaque;
+    MouseState *s = d->opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    s->buttons_state = buttons_state;
+}
+
+
+static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
+{
+    MouseState *s = d->opaque;
+    int dx, dy;
+
+    if (s->last_buttons_state == s->buttons_state &&
+        s->dx == 0 && s->dy == 0)
+        return 0;
+
+    dx = s->dx;
+    if (dx < -63)
+        dx = -63;
+    else if (dx > 63)
+        dx = 63;
+
+    dy = s->dy;
+    if (dy < -63)
+        dy = -63;
+    else if (dy > 63)
+        dy = 63;
+
+    s->dx -= dx;
+    s->dy -= dy;
+    s->last_buttons_state = s->buttons_state;
+
+    dx &= 0x7f;
+    dy &= 0x7f;
+
+    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
+        dy |= 0x80;
+    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
+        dx |= 0x80;
+
+    obuf[0] = dy;
+    obuf[1] = dx;
+    return 2;
+}
+
+static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
+                             const uint8_t *buf, int len)
+{
+    MouseState *s = d->opaque;
+    int cmd, reg, olen;
+
+    if ((buf[0] & 0x0f) == ADB_FLUSH) {
+        /* flush mouse fifo */
+        s->buttons_state = s->last_buttons_state;
+        s->dx = 0;
+        s->dy = 0;
+        s->dz = 0;
+        return 0;
+    }
+
+    cmd = buf[0] & 0xc;
+    reg = buf[0] & 0x3;
+    olen = 0;
+    switch(cmd) {
+    case ADB_WRITEREG:
+        ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
+        switch(reg) {
+        case 2:
+            break;
+        case 3:
+            switch(buf[2]) {
+            case ADB_CMD_SELF_TEST:
+                break;
+            case ADB_CMD_CHANGE_ID:
+            case ADB_CMD_CHANGE_ID_AND_ACT:
+            case ADB_CMD_CHANGE_ID_AND_ENABLE:
+                d->devaddr = buf[1] & 0xf;
+                break;
+            default:
+                /* XXX: check this */
+                d->devaddr = buf[1] & 0xf;
+                break;
+            }
+        }
+        break;
+    case ADB_READREG:
+        switch(reg) {
+        case 0:
+            olen = adb_mouse_poll(d, obuf);
+            break;
+        case 1:
+            break;
+        case 3:
+            obuf[0] = d->handler;
+            obuf[1] = d->devaddr;
+            olen = 2;
+            break;
+        }
+        ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
+                    obuf[0], obuf[1]);
+        break;
+    }
+    return olen;
+}
+
+static int adb_mouse_reset(ADBDevice *d)
+{
+    MouseState *s = d->opaque;
+
+    d->handler = 2;
+    d->devaddr = ADB_MOUSE;
+    memset(s, 0, sizeof(MouseState));
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_adb_mouse = {
+    .name = "adb_mouse",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(buttons_state, MouseState),
+        VMSTATE_INT32(last_buttons_state, MouseState),
+        VMSTATE_INT32(dx, MouseState),
+        VMSTATE_INT32(dy, MouseState),
+        VMSTATE_INT32(dz, MouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void adb_mouse_init(ADBBusState *bus)
+{
+    ADBDevice *d;
+    MouseState *s;
+
+    s = qemu_mallocz(sizeof(MouseState));
+    d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
+                            adb_mouse_reset, s);
+    qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
+    vmstate_register(NULL, -1, &vmstate_adb_mouse, s);
+}
diff --git a/qemu-0.15.x/hw/adlib.c b/qemu-0.15.x/hw/adlib.c
new file mode 100644
index 0000000..4d76d57
--- /dev/null
+++ b/qemu-0.15.x/hw/adlib.c
@@ -0,0 +1,338 @@
+/*
+ * QEMU Proxy for OPL2/3 emulation by MAME team
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "isa.h"
+
+//#define DEBUG
+
+#define ADLIB_KILL_TIMERS 1
+
+#ifdef DEBUG
+#include "qemu-timer.h"
+#endif
+
+#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#ifdef HAS_YMF262
+#include "ymf262.h"
+void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
+#define SHIFT 2
+#else
+#include "fmopl.h"
+#define SHIFT 1
+#endif
+
+#define IO_READ_PROTO(name) \
+    uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name) \
+    void name (void *opaque, uint32_t nport, uint32_t val)
+
+static struct {
+    int port;
+    int freq;
+} conf = {0x220, 44100};
+
+typedef struct {
+    QEMUSoundCard card;
+    int ticking[2];
+    int enabled;
+    int active;
+    int bufpos;
+#ifdef DEBUG
+    int64_t exp[2];
+#endif
+    int16_t *mixbuf;
+    uint64_t dexp[2];
+    SWVoiceOut *voice;
+    int left, pos, samples;
+    QEMUAudioTimeStamp ats;
+#ifndef HAS_YMF262
+    FM_OPL *opl;
+#endif
+} AdlibState;
+
+static AdlibState glob_adlib;
+
+static void adlib_stop_opl_timer (AdlibState *s, size_t n)
+{
+#ifdef HAS_YMF262
+    YMF262TimerOver (0, n);
+#else
+    OPLTimerOver (s->opl, n);
+#endif
+    s->ticking[n] = 0;
+}
+
+static void adlib_kill_timers (AdlibState *s)
+{
+    size_t i;
+
+    for (i = 0; i < 2; ++i) {
+        if (s->ticking[i]) {
+            uint64_t delta;
+
+            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
+            ldebug (
+                "delta = %f dexp = %f expired => %d\n",
+                delta / 1000000.0,
+                s->dexp[i] / 1000000.0,
+                delta >= s->dexp[i]
+                );
+            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
+                adlib_stop_opl_timer (s, i);
+                AUD_init_time_stamp_out (s->voice, &s->ats);
+            }
+        }
+    }
+}
+
+static IO_WRITE_PROTO (adlib_write)
+{
+    AdlibState *s = opaque;
+    int a = nport & 3;
+    int status;
+
+    s->active = 1;
+    AUD_set_active_out (s->voice, 1);
+
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
+    status = YMF262Write (0, a, val);
+#else
+    status = OPLWrite (s->opl, a, val);
+#endif
+}
+
+static IO_READ_PROTO (adlib_read)
+{
+    AdlibState *s = opaque;
+    uint8_t data;
+    int a = nport & 3;
+
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
+    data = YMF262Read (0, a);
+#else
+    data = OPLRead (s->opl, a);
+#endif
+    return data;
+}
+
+static void timer_handler (int c, double interval_Sec)
+{
+    AdlibState *s = &glob_adlib;
+    unsigned n = c & 1;
+#ifdef DEBUG
+    double interval;
+    int64_t exp;
+#endif
+
+    if (interval_Sec == 0.0) {
+        s->ticking[n] = 0;
+        return;
+    }
+
+    s->ticking[n] = 1;
+#ifdef DEBUG
+    interval = get_ticks_per_sec() * interval_Sec;
+    exp = qemu_get_clock_ns (vm_clock) + interval;
+    s->exp[n] = exp;
+#endif
+
+    s->dexp[n] = interval_Sec * 1000000.0;
+    AUD_init_time_stamp_out (s->voice, &s->ats);
+}
+
+static int write_audio (AdlibState *s, int samples)
+{
+    int net = 0;
+    int pos = s->pos;
+
+    while (samples) {
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << SHIFT;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (SHIFT - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> SHIFT;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static void adlib_callback (void *opaque, int free)
+{
+    AdlibState *s = opaque;
+    int samples, net = 0, to_play, written;
+
+    samples = free >> SHIFT;
+    if (!(s->active && s->enabled) || !samples) {
+        return;
+    }
+
+    to_play = audio_MIN (s->left, samples);
+    while (to_play) {
+        written = write_audio (s, to_play);
+
+        if (written) {
+            s->left -= written;
+            samples -= written;
+            to_play -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            return;
+        }
+    }
+
+    samples = audio_MIN (samples, s->samples - s->pos);
+    if (!samples) {
+        return;
+    }
+
+#ifdef HAS_YMF262
+    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
+#else
+    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
+#endif
+
+    while (samples) {
+        written = write_audio (s, samples);
+
+        if (written) {
+            net += written;
+            samples -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            s->left = samples;
+            return;
+        }
+    }
+}
+
+static void Adlib_fini (AdlibState *s)
+{
+#ifdef HAS_YMF262
+    YMF262Shutdown ();
+#else
+    if (s->opl) {
+        OPLDestroy (s->opl);
+        s->opl = NULL;
+    }
+#endif
+
+    if (s->mixbuf) {
+        qemu_free (s->mixbuf);
+    }
+
+    s->active = 0;
+    s->enabled = 0;
+    AUD_remove_card (&s->card);
+}
+
+int Adlib_init (qemu_irq *pic)
+{
+    AdlibState *s = &glob_adlib;
+    struct audsettings as;
+
+#ifdef HAS_YMF262
+    if (YMF262Init (1, 14318180, conf.freq)) {
+        dolog ("YMF262Init %d failed\n", conf.freq);
+        return -1;
+    }
+    else {
+        YMF262SetTimerHandler (0, timer_handler, 0);
+        s->enabled = 1;
+    }
+#else
+    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
+    if (!s->opl) {
+        dolog ("OPLCreate %d failed\n", conf.freq);
+        return -1;
+    }
+    else {
+        OPLSetTimerHandler (s->opl, timer_handler, 0);
+        s->enabled = 1;
+    }
+#endif
+
+    as.freq = conf.freq;
+    as.nchannels = SHIFT;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = AUDIO_HOST_ENDIANNESS;
+
+    AUD_register_card ("adlib", &s->card);
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "adlib",
+        s,
+        adlib_callback,
+        &as
+        );
+    if (!s->voice) {
+        Adlib_fini (s);
+        return -1;
+    }
+
+    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
+    s->mixbuf = qemu_mallocz (s->samples << SHIFT);
+
+    register_ioport_read (0x388, 4, 1, adlib_read, s);
+    register_ioport_write (0x388, 4, 1, adlib_write, s);
+
+    register_ioport_read (conf.port, 4, 1, adlib_read, s);
+    register_ioport_write (conf.port, 4, 1, adlib_write, s);
+
+    register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
+    register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/ads7846.c b/qemu-0.15.x/hw/ads7846.c
new file mode 100644
index 0000000..9c58a5f
--- /dev/null
+++ b/qemu-0.15.x/hw/ads7846.c
@@ -0,0 +1,165 @@
+/*
+ * TI ADS7846 / TSC2046 chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "ssi.h"
+#include "console.h"
+
+typedef struct {
+    SSISlave ssidev;
+    qemu_irq interrupt;
+
+    int input[8];
+    int pressure;
+    int noise;
+
+    int cycle;
+    int output;
+} ADS7846State;
+
+/* Control-byte bitfields */
+#define CB_PD0		(1 << 0)
+#define CB_PD1		(1 << 1)
+#define CB_SER		(1 << 2)
+#define CB_MODE		(1 << 3)
+#define CB_A0		(1 << 4)
+#define CB_A1		(1 << 5)
+#define CB_A2		(1 << 6)
+#define CB_START	(1 << 7)
+
+#define X_AXIS_DMAX	3470
+#define X_AXIS_MIN	290
+#define Y_AXIS_DMAX	3450
+#define Y_AXIS_MIN	200
+
+#define ADS_VBAT	2000
+#define ADS_VAUX	2000
+#define ADS_TEMP0	2000
+#define ADS_TEMP1	3000
+#define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
+#define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
+#define ADS_Z1POS(x, y)	600
+#define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
+
+static void ads7846_int_update(ADS7846State *s)
+{
+    if (s->interrupt)
+        qemu_set_irq(s->interrupt, s->pressure == 0);
+}
+
+static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value)
+{
+    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+
+    switch (s->cycle ++) {
+    case 0:
+        if (!(value & CB_START)) {
+            s->cycle = 0;
+            break;
+        }
+
+        s->output = s->input[(value >> 4) & 7];
+
+        /* Imitate the ADC noise, some drivers expect this.  */
+        s->noise = (s->noise + 3) & 7;
+        switch ((value >> 4) & 7) {
+        case 1: s->output += s->noise ^ 2; break;
+        case 3: s->output += s->noise ^ 0; break;
+        case 4: s->output += s->noise ^ 7; break;
+        case 5: s->output += s->noise ^ 5; break;
+        }
+
+        if (value & CB_MODE)
+            s->output >>= 4;	/* 8 bits instead of 12 */
+
+        break;
+    case 1:
+        s->cycle = 0;
+        break;
+    }
+    return s->output;
+}
+
+static void ads7846_ts_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    ADS7846State *s = opaque;
+
+    if (buttons_state) {
+        x = 0x7fff - x;
+        s->input[1] = ADS_XPOS(x, y);
+        s->input[3] = ADS_Z1POS(x, y);
+        s->input[4] = ADS_Z2POS(x, y);
+        s->input[5] = ADS_YPOS(x, y);
+    }
+
+    if (s->pressure == !buttons_state) {
+        s->pressure = !!buttons_state;
+
+        ads7846_int_update(s);
+    }
+}
+
+static int ads7856_post_load(void *opaque, int version_id)
+{
+    ADS7846State *s = opaque;
+
+    s->pressure = 0;
+    ads7846_int_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ads7846 = {
+    .name = "ads7846",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ads7856_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
+        VMSTATE_INT32(noise, ADS7846State),
+        VMSTATE_INT32(cycle, ADS7846State),
+        VMSTATE_INT32(output, ADS7846State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ads7846_init(SSISlave *dev)
+{
+    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+
+    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+
+    s->input[0] = ADS_TEMP0;	/* TEMP0 */
+    s->input[2] = ADS_VBAT;	/* VBAT */
+    s->input[6] = ADS_VAUX;	/* VAUX */
+    s->input[7] = ADS_TEMP1;	/* TEMP1 */
+
+    /* We want absolute coordinates */
+    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
+                    "QEMU ADS7846-driven Touchscreen");
+
+    ads7846_int_update(s);
+
+    vmstate_register(NULL, -1, &vmstate_ads7846, s);
+    return 0;
+}
+
+static SSISlaveInfo ads7846_info = {
+    .qdev.name ="ads7846",
+    .qdev.size = sizeof(ADS7846State),
+    .init = ads7846_init,
+    .transfer = ads7846_transfer
+};
+
+static void ads7846_register_devices(void)
+{
+    ssi_register_slave(&ads7846_info);
+}
+
+device_init(ads7846_register_devices)
diff --git a/qemu-0.15.x/hw/an5206.c b/qemu-0.15.x/hw/an5206.c
new file mode 100644
index 0000000..04ca420
--- /dev/null
+++ b/qemu-0.15.x/hw/an5206.c
@@ -0,0 +1,100 @@
+/*
+ * Arnewsh 5206 ColdFire system emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "mcf.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+
+#define KERNEL_LOAD_ADDR 0x10000
+#define AN5206_MBAR_ADDR 0x10000000
+#define AN5206_RAMBAR_ADDR 0x20000000
+
+/* Stub functions for hardware that doesn't exist.  */
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
+
+/* Board init.  */
+
+static void an5206_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    target_phys_addr_t entry;
+
+    if (!cpu_model)
+        cpu_model = "m5206";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        hw_error("Unable to find m68k CPU definition\n");
+    }
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: allow changing MBAR and RAMBAR.  */
+    env->mbar = AN5206_MBAR_ADDR | 1;
+    env->rambar0 = AN5206_RAMBAR_ADDR | 1;
+
+    /* DRAM at address zero */
+    cpu_register_physical_memory(0, ram_size,
+        qemu_ram_alloc(NULL, "an5206.ram", ram_size) | IO_MEM_RAM);
+
+    /* Internal SRAM.  */
+    cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
+        qemu_ram_alloc(NULL, "an5206.sram", 512) | IO_MEM_RAM);
+
+    mcf5206_init(AN5206_MBAR_ADDR, env);
+
+    /* Load kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, 1, ELF_MACHINE, 0);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+                                          ram_size - KERNEL_LOAD_ADDR);
+        entry = KERNEL_LOAD_ADDR;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+static QEMUMachine an5206_machine = {
+    .name = "an5206",
+    .desc = "Arnewsh 5206",
+    .init = an5206_init,
+};
+
+static void an5206_machine_init(void)
+{
+    qemu_register_machine(&an5206_machine);
+}
+
+machine_init(an5206_machine_init);
diff --git a/qemu-0.15.x/hw/apb_pci.c b/qemu-0.15.x/hw/apb_pci.c
new file mode 100644
index 0000000..974c87a
--- /dev/null
+++ b/qemu-0.15.x/hw/apb_pci.c
@@ -0,0 +1,481 @@
+/*
+ * QEMU Ultrasparc APB PCI host
+ *
+ * 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.
+ */
+
+/* XXX This file and most of its contents are somewhat misnamed.  The
+   Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
+   the secondary PCI bridge.  */
+
+#include "sysbus.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "rwhandler.h"
+#include "apb_pci.h"
+#include "sysemu.h"
+
+/* debug APB */
+//#define DEBUG_APB
+
+#ifdef DEBUG_APB
+#define APB_DPRINTF(fmt, ...) \
+do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define APB_DPRINTF(fmt, ...)
+#endif
+
+/*
+ * Chipset docs:
+ * PBM: "UltraSPARC IIi User's Manual",
+ * http://www.sun.com/processors/manuals/805-0087.pdf
+ *
+ * APB: "Advanced PCI Bridge (APB) User's Manual",
+ * http://www.sun.com/processors/manuals/805-1251.pdf
+ */
+
+#define PBM_PCI_IMR_MASK    0x7fffffff
+#define PBM_PCI_IMR_ENABLED 0x80000000
+
+#define POR          (1 << 31)
+#define SOFT_POR     (1 << 30)
+#define SOFT_XIR     (1 << 29)
+#define BTN_POR      (1 << 28)
+#define BTN_XIR      (1 << 27)
+#define RESET_MASK   0xf8000000
+#define RESET_WCMASK 0x98000000
+#define RESET_WMASK  0x60000000
+
+typedef struct APBState {
+    SysBusDevice busdev;
+    PCIBus      *bus;
+    ReadWriteHandler pci_config_handler;
+    uint32_t iommu[4];
+    uint32_t pci_control[16];
+    uint32_t pci_irq_map[8];
+    uint32_t obio_irq_map[32];
+    qemu_irq pci_irqs[32];
+    uint32_t reset_control;
+    unsigned int nr_resets;
+} APBState;
+
+static void apb_config_writel (void *opaque, target_phys_addr_t addr,
+                               uint32_t val)
+{
+    APBState *s = opaque;
+
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+
+    switch (addr & 0xffff) {
+    case 0x30 ... 0x4f: /* DMA error registers */
+        /* XXX: not implemented yet */
+        break;
+    case 0x200 ... 0x20b: /* IOMMU */
+        s->iommu[(addr & 0xf) >> 2] = val;
+        break;
+    case 0x20c ... 0x3ff: /* IOMMU flush */
+        break;
+    case 0xc00 ... 0xc3f: /* PCI interrupt control */
+        if (addr & 4) {
+            s->pci_irq_map[(addr & 0x3f) >> 3] &= PBM_PCI_IMR_MASK;
+            s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+        }
+        break;
+    case 0x2000 ... 0x202f: /* PCI control */
+        s->pci_control[(addr & 0x3f) >> 2] = val;
+        break;
+    case 0xf020 ... 0xf027: /* Reset control */
+        if (addr & 4) {
+            val &= RESET_MASK;
+            s->reset_control &= ~(val & RESET_WCMASK);
+            s->reset_control |= val & RESET_WMASK;
+            if (val & SOFT_POR) {
+                s->nr_resets = 0;
+                qemu_system_reset_request();
+            } else if (val & SOFT_XIR) {
+                qemu_system_reset_request();
+            }
+        }
+        break;
+    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
+    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
+    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
+    case 0xf000 ... 0xf01f: /* FFB config, memory control */
+        /* we don't care */
+    default:
+        break;
+    }
+}
+
+static uint32_t apb_config_readl (void *opaque,
+                                  target_phys_addr_t addr)
+{
+    APBState *s = opaque;
+    uint32_t val;
+
+    switch (addr & 0xffff) {
+    case 0x30 ... 0x4f: /* DMA error registers */
+        val = 0;
+        /* XXX: not implemented yet */
+        break;
+    case 0x200 ... 0x20b: /* IOMMU */
+        val = s->iommu[(addr & 0xf) >> 2];
+        break;
+    case 0x20c ... 0x3ff: /* IOMMU flush */
+        val = 0;
+        break;
+    case 0xc00 ... 0xc3f: /* PCI interrupt control */
+        if (addr & 4) {
+            val = s->pci_irq_map[(addr & 0x3f) >> 3];
+        } else {
+            val = 0;
+        }
+        break;
+    case 0x2000 ... 0x202f: /* PCI control */
+        val = s->pci_control[(addr & 0x3f) >> 2];
+        break;
+    case 0xf020 ... 0xf027: /* Reset control */
+        if (addr & 4) {
+            val = s->reset_control;
+        } else {
+            val = 0;
+        }
+        break;
+    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
+    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
+    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
+    case 0xf000 ... 0xf01f: /* FFB config, memory control */
+        /* we don't care */
+    default:
+        val = 0;
+        break;
+    }
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, val);
+
+    return val;
+}
+
+static CPUWriteMemoryFunc * const apb_config_write[] = {
+    &apb_config_writel,
+    &apb_config_writel,
+    &apb_config_writel,
+};
+
+static CPUReadMemoryFunc * const apb_config_read[] = {
+    &apb_config_readl,
+    &apb_config_readl,
+    &apb_config_readl,
+};
+
+static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
+                                 uint32_t val, int size)
+{
+    APBState *s = container_of(h, APBState, pci_config_handler);
+
+    val = qemu_bswap_len(val, size);
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+    pci_data_write(s->bus, addr, val, size);
+}
+
+static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
+                                    int size)
+{
+    uint32_t ret;
+    APBState *s = container_of(h, APBState, pci_config_handler);
+
+    ret = pci_data_read(s->bus, addr, size);
+    ret = qemu_bswap_len(ret, size);
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
+    return ret;
+}
+
+static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    cpu_outb(addr & IOPORTS_MASK, val);
+}
+
+static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    cpu_outw(addr & IOPORTS_MASK, bswap16(val));
+}
+
+static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    cpu_outl(addr & IOPORTS_MASK, bswap32(val));
+}
+
+static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+
+    val = cpu_inb(addr & IOPORTS_MASK);
+    return val;
+}
+
+static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+
+    val = bswap16(cpu_inw(addr & IOPORTS_MASK));
+    return val;
+}
+
+static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+
+    val = bswap32(cpu_inl(addr & IOPORTS_MASK));
+    return val;
+}
+
+static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
+    &pci_apb_iowriteb,
+    &pci_apb_iowritew,
+    &pci_apb_iowritel,
+};
+
+static CPUReadMemoryFunc * const pci_apb_ioread[] = {
+    &pci_apb_ioreadb,
+    &pci_apb_ioreadw,
+    &pci_apb_ioreadl,
+};
+
+/* The APB host has an IRQ line for each IRQ line of each slot.  */
+static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
+}
+
+static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int bus_offset;
+    if (pci_dev->devfn & 1)
+        bus_offset = 16;
+    else
+        bus_offset = 0;
+    return bus_offset + irq_num;
+}
+
+static void pci_apb_set_irq(void *opaque, int irq_num, int level)
+{
+    APBState *s = opaque;
+
+    /* PCI IRQ map onto the first 32 INO.  */
+    if (irq_num < 32) {
+        if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
+            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+            qemu_set_irq(s->pci_irqs[irq_num], level);
+        } else {
+            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+            qemu_irq_lower(s->pci_irqs[irq_num]);
+        }
+    }
+}
+
+static int apb_pci_bridge_initfn(PCIDevice *dev)
+{
+    int rc;
+
+    rc = pci_bridge_initfn(dev);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /*
+     * command register:
+     * According to PCI bridge spec, after reset
+     *   bus master bit is off
+     *   memory space enable bit is off
+     * According to manual (805-1251.pdf).
+     *   the reset value should be zero unless the boot pin is tied high
+     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
+     */
+    pci_set_word(dev->config + PCI_COMMAND,
+                 PCI_COMMAND_MEMORY);
+    pci_set_word(dev->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+PCIBus *pci_apb_init(target_phys_addr_t special_base,
+                     target_phys_addr_t mem_base,
+                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    APBState *d;
+    unsigned int i;
+    PCIDevice *pci_dev;
+    PCIBridge *br;
+
+    /* Ultrasparc PBM main bus */
+    dev = qdev_create(NULL, "pbm");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    /* apb_config */
+    sysbus_mmio_map(s, 0, special_base);
+    /* PCI configuration space */
+    sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
+    /* pci_ioport */
+    sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
+    d = FROM_SYSBUS(APBState, s);
+
+    d->bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                         pci_apb_set_irq, pci_pbm_map_irq, d,
+                                         0, 32);
+    pci_bus_set_mem_base(d->bus, mem_base);
+
+    for (i = 0; i < 32; i++) {
+        sysbus_connect_irq(s, i, pic[i]);
+    }
+
+    pci_create_simple(d->bus, 0, "pbm");
+
+    /* APB secondary busses */
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus2 = pci_bridge_get_sec_bus(br);
+
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus3 = pci_bridge_get_sec_bus(br);
+
+    return d->bus;
+}
+
+static void pci_pbm_reset(DeviceState *d)
+{
+    unsigned int i;
+    APBState *s = container_of(d, APBState, busdev.qdev);
+
+    for (i = 0; i < 8; i++) {
+        s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
+    }
+
+    if (s->nr_resets++ == 0) {
+        /* Power on reset */
+        s->reset_control = POR;
+    }
+}
+
+static int pci_pbm_init_device(SysBusDevice *dev)
+{
+    APBState *s;
+    int pci_config, apb_config, pci_ioport;
+    unsigned int i;
+
+    s = FROM_SYSBUS(APBState, dev);
+    for (i = 0; i < 8; i++) {
+        s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
+    }
+    for (i = 0; i < 32; i++) {
+        sysbus_init_irq(dev, &s->pci_irqs[i]);
+    }
+
+    /* apb_config */
+    apb_config = cpu_register_io_memory(apb_config_read,
+                                        apb_config_write, s,
+                                        DEVICE_NATIVE_ENDIAN);
+    /* at region 0 */
+    sysbus_init_mmio(dev, 0x10000ULL, apb_config);
+
+    /* PCI configuration space */
+    s->pci_config_handler.read = apb_pci_config_read;
+    s->pci_config_handler.write = apb_pci_config_write;
+    pci_config = cpu_register_io_memory_simple(&s->pci_config_handler,
+                                               DEVICE_NATIVE_ENDIAN);
+    assert(pci_config >= 0);
+    /* at region 1 */
+    sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
+
+    /* pci_ioport */
+    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
+                                        pci_apb_iowrite, s,
+                                        DEVICE_NATIVE_ENDIAN);
+    /* at region 2 */
+    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
+
+    return 0;
+}
+
+static int pbm_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_COMMAND,
+                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+    pci_set_word(d->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+static PCIDeviceInfo pbm_pci_host_info = {
+    .qdev.name = "pbm",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = pbm_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SABRE,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+    .is_bridge = 1,
+};
+
+static SysBusDeviceInfo pbm_host_info = {
+    .qdev.name = "pbm",
+    .qdev.size = sizeof(APBState),
+    .qdev.reset = pci_pbm_reset,
+    .init = pci_pbm_init_device,
+};
+
+static PCIDeviceInfo pbm_pci_bridge_info = {
+    .qdev.name = "pbm-bridge",
+    .qdev.size = sizeof(PCIBridge),
+    .qdev.vmsd = &vmstate_pci_device,
+    .qdev.reset = pci_bridge_reset,
+    .init = apb_pci_bridge_initfn,
+    .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SIMBA,
+    .revision = 0x11,
+    .config_write = pci_bridge_write_config,
+    .is_bridge = 1,
+};
+
+static void pbm_register_devices(void)
+{
+    sysbus_register_withprop(&pbm_host_info);
+    pci_qdev_register(&pbm_pci_host_info);
+    pci_qdev_register(&pbm_pci_bridge_info);
+}
+
+device_init(pbm_register_devices)
diff --git a/qemu-0.15.x/hw/apb_pci.h b/qemu-0.15.x/hw/apb_pci.h
new file mode 100644
index 0000000..8869f9d
--- /dev/null
+++ b/qemu-0.15.x/hw/apb_pci.h
@@ -0,0 +1,9 @@
+#ifndef APB_PCI_H
+#define APB_PCI_H
+
+#include "qemu-common.h"
+
+PCIBus *pci_apb_init(target_phys_addr_t special_base,
+                     target_phys_addr_t mem_base,
+                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+#endif
diff --git a/qemu-0.15.x/hw/apic.c b/qemu-0.15.x/hw/apic.c
new file mode 100644
index 0000000..9febf40
--- /dev/null
+++ b/qemu-0.15.x/hw/apic.c
@@ -0,0 +1,1033 @@
+/*
+ *  APIC support
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "hw.h"
+#include "apic.h"
+#include "ioapic.h"
+#include "qemu-timer.h"
+#include "host-utils.h"
+#include "sysbus.h"
+#include "trace.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER   0
+#define APIC_LVT_THERMAL 1
+#define APIC_LVT_PERFORM 2
+#define APIC_LVT_LINT0   3
+#define APIC_LVT_LINT1   4
+#define APIC_LVT_ERROR   5
+#define APIC_LVT_NB      6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED	0
+#define APIC_DM_LOWPRI	1
+#define APIC_DM_SMI	2
+#define APIC_DM_NMI	4
+#define APIC_DM_INIT	5
+#define APIC_DM_SIPI	6
+#define APIC_DM_EXTINT	7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT	0xf
+#define APIC_DESTMODE_CLUSTER	1
+
+#define APIC_TRIGGER_EDGE  0
+#define APIC_TRIGGER_LEVEL 1
+
+#define	APIC_LVT_TIMER_PERIODIC		(1<<17)
+#define	APIC_LVT_MASKED			(1<<16)
+#define	APIC_LVT_LEVEL_TRIGGER		(1<<15)
+#define	APIC_LVT_REMOTE_IRR		(1<<14)
+#define	APIC_INPUT_POLARITY		(1<<13)
+#define	APIC_SEND_PENDING		(1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO             (1<<12)
+#define APIC_SV_ENABLE                  (1<<8)
+
+#define MAX_APICS 255
+#define MAX_APIC_WORDS 8
+
+/* Intel APIC constants: from include/asm/msidef.h */
+#define MSI_DATA_VECTOR_SHIFT		0
+#define MSI_DATA_VECTOR_MASK		0x000000ff
+#define MSI_DATA_DELIVERY_MODE_SHIFT	8
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define MSI_DATA_LEVEL_SHIFT		14
+#define MSI_ADDR_DEST_MODE_SHIFT	2
+#define MSI_ADDR_DEST_ID_SHIFT		12
+#define	MSI_ADDR_DEST_ID_MASK		0x00ffff0
+
+#define MSI_ADDR_SIZE                   0x100000
+
+typedef struct APICState APICState;
+
+struct APICState {
+    SysBusDevice busdev;
+    void *cpu_env;
+    uint32_t apicbase;
+    uint8_t id;
+    uint8_t arb_id;
+    uint8_t tpr;
+    uint32_t spurious_vec;
+    uint8_t log_dest;
+    uint8_t dest_mode;
+    uint32_t isr[8];  /* in service register */
+    uint32_t tmr[8];  /* trigger mode register */
+    uint32_t irr[8]; /* interrupt request register */
+    uint32_t lvt[APIC_LVT_NB];
+    uint32_t esr; /* error register */
+    uint32_t icr[2];
+
+    uint32_t divide_conf;
+    int count_shift;
+    uint32_t initial_count;
+    int64_t initial_count_load_time, next_time;
+    uint32_t idx;
+    QEMUTimer *timer;
+    int sipi_vector;
+    int wait_for_sipi;
+};
+
+static APICState *local_apics[MAX_APICS + 1];
+static int apic_irq_delivered;
+
+static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICState *s);
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode);
+
+/* Find first bit starting from msb */
+static int fls_bit(uint32_t value)
+{
+    return 31 - clz32(value);
+}
+
+/* Find first bit starting from lsb */
+static int ffs_bit(uint32_t value)
+{
+    return ctz32(value);
+}
+
+static inline void set_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] |= mask;
+}
+
+static inline void reset_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] &= ~mask;
+}
+
+static inline int get_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    return !!(tab[i] & mask);
+}
+
+static void apic_local_deliver(APICState *s, int vector)
+{
+    uint32_t lvt = s->lvt[vector];
+    int trigger_mode;
+
+    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
+    if (lvt & APIC_LVT_MASKED)
+        return;
+
+    switch ((lvt >> 8) & 7) {
+    case APIC_DM_SMI:
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SMI);
+        break;
+
+    case APIC_DM_NMI:
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_NMI);
+        break;
+
+    case APIC_DM_EXTINT:
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+        break;
+
+    case APIC_DM_FIXED:
+        trigger_mode = APIC_TRIGGER_EDGE;
+        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
+            (lvt & APIC_LVT_LEVEL_TRIGGER))
+            trigger_mode = APIC_TRIGGER_LEVEL;
+        apic_set_irq(s, lvt & 0xff, trigger_mode);
+    }
+}
+
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    if (level) {
+        apic_local_deliver(s, APIC_LVT_LINT0);
+    } else {
+        uint32_t lvt = s->lvt[APIC_LVT_LINT0];
+
+        switch ((lvt >> 8) & 7) {
+        case APIC_DM_FIXED:
+            if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
+                break;
+            reset_bit(s->irr, lvt & 0xff);
+            /* fall through */
+        case APIC_DM_EXTINT:
+            cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+            break;
+        }
+    }
+}
+
+#define foreach_apic(apic, deliver_bitmask, code) \
+{\
+    int __i, __j, __mask;\
+    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
+        __mask = deliver_bitmask[__i];\
+        if (__mask) {\
+            for(__j = 0; __j < 32; __j++) {\
+                if (__mask & (1 << __j)) {\
+                    apic = local_apics[__i * 32 + __j];\
+                    if (apic) {\
+                        code;\
+                    }\
+                }\
+            }\
+        }\
+    }\
+}
+
+static void apic_bus_deliver(const uint32_t *deliver_bitmask,
+                             uint8_t delivery_mode,
+                             uint8_t vector_num, uint8_t polarity,
+                             uint8_t trigger_mode)
+{
+    APICState *apic_iter;
+
+    switch (delivery_mode) {
+        case APIC_DM_LOWPRI:
+            /* XXX: search for focus processor, arbitration */
+            {
+                int i, d;
+                d = -1;
+                for(i = 0; i < MAX_APIC_WORDS; i++) {
+                    if (deliver_bitmask[i]) {
+                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
+                        break;
+                    }
+                }
+                if (d >= 0) {
+                    apic_iter = local_apics[d];
+                    if (apic_iter) {
+                        apic_set_irq(apic_iter, vector_num, trigger_mode);
+                    }
+                }
+            }
+            return;
+
+        case APIC_DM_FIXED:
+            break;
+
+        case APIC_DM_SMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
+            return;
+
+        case APIC_DM_NMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
+            return;
+
+        case APIC_DM_INIT:
+            /* normal INIT IPI sent to processors */
+            foreach_apic(apic_iter, deliver_bitmask,
+                         cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT) );
+            return;
+
+        case APIC_DM_EXTINT:
+            /* handled in I/O APIC code */
+            break;
+
+        default:
+            return;
+    }
+
+    foreach_apic(apic_iter, deliver_bitmask,
+                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
+}
+
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
+                      uint8_t delivery_mode, uint8_t vector_num,
+                      uint8_t polarity, uint8_t trigger_mode)
+{
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+
+    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+                           polarity, trigger_mode);
+
+    apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
+                     trigger_mode);
+}
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    trace_cpu_set_apic_base(val);
+
+    if (!s)
+        return;
+    s->apicbase = (val & 0xfffff000) |
+        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
+    /* if disabled, cannot be enabled again */
+    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
+        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
+        cpu_clear_apic_feature(s->cpu_env);
+        s->spurious_vec &= ~APIC_SV_ENABLE;
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
+
+    return s ? s->apicbase : 0;
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    if (!s)
+        return;
+    s->tpr = (val & 0x0f) << 4;
+    apic_update_irq(s);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    return s ? s->tpr >> 4 : 0;
+}
+
+/* return -1 if no bit is set */
+static int get_highest_priority_int(uint32_t *tab)
+{
+    int i;
+    for(i = 7; i >= 0; i--) {
+        if (tab[i] != 0) {
+            return i * 32 + fls_bit(tab[i]);
+        }
+    }
+    return -1;
+}
+
+static int apic_get_ppr(APICState *s)
+{
+    int tpr, isrv, ppr;
+
+    tpr = (s->tpr >> 4);
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        isrv = 0;
+    isrv >>= 4;
+    if (tpr >= isrv)
+        ppr = s->tpr;
+    else
+        ppr = isrv << 4;
+    return ppr;
+}
+
+static int apic_get_arb_pri(APICState *s)
+{
+    /* XXX: arbitration */
+    return 0;
+}
+
+
+/*
+ * <0 - low prio interrupt,
+ * 0  - no interrupt,
+ * >0 - interrupt number
+ */
+static int apic_irq_pending(APICState *s)
+{
+    int irrv, ppr;
+    irrv = get_highest_priority_int(s->irr);
+    if (irrv < 0) {
+        return 0;
+    }
+    ppr = apic_get_ppr(s);
+    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
+        return -1;
+    }
+
+    return irrv;
+}
+
+/* signal the CPU if an irq is pending */
+static void apic_update_irq(APICState *s)
+{
+    if (!(s->spurious_vec & APIC_SV_ENABLE)) {
+        return;
+    }
+    if (apic_irq_pending(s) > 0) {
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
+{
+    apic_irq_delivered += !get_bit(s->irr, vector_num);
+
+    trace_apic_set_irq(apic_irq_delivered);
+
+    set_bit(s->irr, vector_num);
+    if (trigger_mode)
+        set_bit(s->tmr, vector_num);
+    else
+        reset_bit(s->tmr, vector_num);
+    apic_update_irq(s);
+}
+
+static void apic_eoi(APICState *s)
+{
+    int isrv;
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        return;
+    reset_bit(s->isr, isrv);
+    if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
+        ioapic_eoi_broadcast(isrv);
+    }
+    apic_update_irq(s);
+}
+
+static int apic_find_dest(uint8_t dest)
+{
+    APICState *apic = local_apics[dest];
+    int i;
+
+    if (apic && apic->id == dest)
+        return dest;  /* shortcut in case apic->id == apic->idx */
+
+    for (i = 0; i < MAX_APICS; i++) {
+        apic = local_apics[i];
+	if (apic && apic->id == dest)
+            return i;
+        if (!apic)
+            break;
+    }
+
+    return -1;
+}
+
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode)
+{
+    APICState *apic_iter;
+    int i;
+
+    if (dest_mode == 0) {
+        if (dest == 0xff) {
+            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
+        } else {
+            int idx = apic_find_dest(dest);
+            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+            if (idx >= 0)
+                set_bit(deliver_bitmask, idx);
+        }
+    } else {
+        /* XXX: cluster mode */
+        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+        for(i = 0; i < MAX_APICS; i++) {
+            apic_iter = local_apics[i];
+            if (apic_iter) {
+                if (apic_iter->dest_mode == 0xf) {
+                    if (dest & apic_iter->log_dest)
+                        set_bit(deliver_bitmask, i);
+                } else if (apic_iter->dest_mode == 0x0) {
+                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
+                        (dest & apic_iter->log_dest & 0x0f)) {
+                        set_bit(deliver_bitmask, i);
+                    }
+                }
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    int i;
+
+    if (!s)
+        return;
+
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for(i = 0; i < APIC_LVT_NB; i++)
+        s->lvt[i] = 1 << 16; /* mask LVT */
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+}
+
+static void apic_startup(APICState *s, int vector_num)
+{
+    s->sipi_vector = vector_num;
+    cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
+}
+
+void apic_sipi(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
+
+    if (!s->wait_for_sipi)
+        return;
+    cpu_x86_load_seg_cache_sipi(s->cpu_env, s->sipi_vector);
+    s->wait_for_sipi = 0;
+}
+
+static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
+                         uint8_t delivery_mode, uint8_t vector_num,
+                         uint8_t polarity, uint8_t trigger_mode)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+    int dest_shorthand = (s->icr[0] >> 18) & 3;
+    APICState *apic_iter;
+
+    switch (dest_shorthand) {
+    case 0:
+        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+        break;
+    case 1:
+        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
+        set_bit(deliver_bitmask, s->idx);
+        break;
+    case 2:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        break;
+    case 3:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        reset_bit(deliver_bitmask, s->idx);
+        break;
+    }
+
+    switch (delivery_mode) {
+        case APIC_DM_INIT:
+            {
+                int trig_mode = (s->icr[0] >> 15) & 1;
+                int level = (s->icr[0] >> 14) & 1;
+                if (level == 0 && trig_mode == 1) {
+                    foreach_apic(apic_iter, deliver_bitmask,
+                                 apic_iter->arb_id = apic_iter->id );
+                    return;
+                }
+            }
+            break;
+
+        case APIC_DM_SIPI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                         apic_startup(apic_iter, vector_num) );
+            return;
+    }
+
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
+                     trigger_mode);
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    int intno;
+
+    /* if the APIC is installed or enabled, we let the 8259 handle the
+       IRQs */
+    if (!s)
+        return -1;
+    if (!(s->spurious_vec & APIC_SV_ENABLE))
+        return -1;
+
+    intno = apic_irq_pending(s);
+
+    if (intno == 0) {
+        return -1;
+    } else if (intno < 0) {
+        return s->spurious_vec & 0xff;
+    }
+    reset_bit(s->irr, intno);
+    set_bit(s->isr, intno);
+    apic_update_irq(s);
+    return intno;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    uint32_t lvt0;
+
+    if (!s)
+        return -1;
+
+    lvt0 = s->lvt[APIC_LVT_LINT0];
+
+    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
+        (lvt0 & APIC_LVT_MASKED) == 0)
+        return 1;
+
+    return 0;
+}
+
+static uint32_t apic_get_current_count(APICState *s)
+{
+    int64_t d;
+    uint32_t val;
+    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
+        s->count_shift;
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        /* periodic */
+        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
+    } else {
+        if (d >= s->initial_count)
+            val = 0;
+        else
+            val = s->initial_count - d;
+    }
+    return val;
+}
+
+static void apic_timer_update(APICState *s, int64_t current_time)
+{
+    int64_t next_time, d;
+
+    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
+        d = (current_time - s->initial_count_load_time) >>
+            s->count_shift;
+        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+            if (!s->initial_count)
+                goto no_timer;
+            d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
+        } else {
+            if (d >= s->initial_count)
+                goto no_timer;
+            d = (uint64_t)s->initial_count + 1;
+        }
+        next_time = s->initial_count_load_time + (d << s->count_shift);
+        qemu_mod_timer(s->timer, next_time);
+        s->next_time = next_time;
+    } else {
+    no_timer:
+        qemu_del_timer(s->timer);
+    }
+}
+
+static void apic_timer(void *opaque)
+{
+    APICState *s = opaque;
+
+    apic_local_deliver(s, APIC_LVT_TIMER);
+    apic_timer_update(s, s->next_time);
+}
+
+static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+}
+
+static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+}
+
+static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    DeviceState *d;
+    APICState *s;
+    uint32_t val;
+    int index;
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return 0;
+    }
+    s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    index = (addr >> 4) & 0xff;
+    switch(index) {
+    case 0x02: /* id */
+        val = s->id << 24;
+        break;
+    case 0x03: /* version */
+        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
+        break;
+    case 0x08:
+        val = s->tpr;
+        break;
+    case 0x09:
+        val = apic_get_arb_pri(s);
+        break;
+    case 0x0a:
+        /* ppr */
+        val = apic_get_ppr(s);
+        break;
+    case 0x0b:
+        val = 0;
+        break;
+    case 0x0d:
+        val = s->log_dest << 24;
+        break;
+    case 0x0e:
+        val = s->dest_mode << 28;
+        break;
+    case 0x0f:
+        val = s->spurious_vec;
+        break;
+    case 0x10 ... 0x17:
+        val = s->isr[index & 7];
+        break;
+    case 0x18 ... 0x1f:
+        val = s->tmr[index & 7];
+        break;
+    case 0x20 ... 0x27:
+        val = s->irr[index & 7];
+        break;
+    case 0x28:
+        val = s->esr;
+        break;
+    case 0x30:
+    case 0x31:
+        val = s->icr[index & 1];
+        break;
+    case 0x32 ... 0x37:
+        val = s->lvt[index - 0x32];
+        break;
+    case 0x38:
+        val = s->initial_count;
+        break;
+    case 0x39:
+        val = apic_get_current_count(s);
+        break;
+    case 0x3e:
+        val = s->divide_conf;
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        val = 0;
+        break;
+    }
+    trace_apic_mem_readl(addr, val);
+    return val;
+}
+
+static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
+{
+    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    /* XXX: Ignore redirection hint. */
+    apic_deliver_irq(dest, dest_mode, delivery, vector, 0, trigger_mode);
+}
+
+static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    DeviceState *d;
+    APICState *s;
+    int index = (addr >> 4) & 0xff;
+    if (addr > 0xfff || !index) {
+        /* MSI and MMIO APIC are at the same memory location,
+         * but actually not on the global bus: MSI is on PCI bus
+         * APIC is connected directly to the CPU.
+         * Mapping them on the global bus happens to work because
+         * MSI registers are reserved in APIC MMIO and vice versa. */
+        apic_send_msi(addr, val);
+        return;
+    }
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return;
+    }
+    s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    trace_apic_mem_writel(addr, val);
+
+    switch(index) {
+    case 0x02:
+        s->id = (val >> 24);
+        break;
+    case 0x03:
+        break;
+    case 0x08:
+        s->tpr = val;
+        apic_update_irq(s);
+        break;
+    case 0x09:
+    case 0x0a:
+        break;
+    case 0x0b: /* EOI */
+        apic_eoi(s);
+        break;
+    case 0x0d:
+        s->log_dest = val >> 24;
+        break;
+    case 0x0e:
+        s->dest_mode = val >> 28;
+        break;
+    case 0x0f:
+        s->spurious_vec = val & 0x1ff;
+        apic_update_irq(s);
+        break;
+    case 0x10 ... 0x17:
+    case 0x18 ... 0x1f:
+    case 0x20 ... 0x27:
+    case 0x28:
+        break;
+    case 0x30:
+        s->icr[0] = val;
+        apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
+                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
+                     (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
+        break;
+    case 0x31:
+        s->icr[1] = val;
+        break;
+    case 0x32 ... 0x37:
+        {
+            int n = index - 0x32;
+            s->lvt[n] = val;
+            if (n == APIC_LVT_TIMER)
+                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
+        }
+        break;
+    case 0x38:
+        s->initial_count = val;
+        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+        apic_timer_update(s, s->initial_count_load_time);
+        break;
+    case 0x39:
+        break;
+    case 0x3e:
+        {
+            int v;
+            s->divide_conf = val & 0xb;
+            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+            s->count_shift = (v + 1) & 7;
+        }
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        break;
+    }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    APICState *s = opaque;
+    int i;
+
+    if (version_id > 2)
+        return -EINVAL;
+
+    /* XXX: what if the base changes? (registered memory regions) */
+    qemu_get_be32s(f, &s->apicbase);
+    qemu_get_8s(f, &s->id);
+    qemu_get_8s(f, &s->arb_id);
+    qemu_get_8s(f, &s->tpr);
+    qemu_get_be32s(f, &s->spurious_vec);
+    qemu_get_8s(f, &s->log_dest);
+    qemu_get_8s(f, &s->dest_mode);
+    for (i = 0; i < 8; i++) {
+        qemu_get_be32s(f, &s->isr[i]);
+        qemu_get_be32s(f, &s->tmr[i]);
+        qemu_get_be32s(f, &s->irr[i]);
+    }
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        qemu_get_be32s(f, &s->lvt[i]);
+    }
+    qemu_get_be32s(f, &s->esr);
+    qemu_get_be32s(f, &s->icr[0]);
+    qemu_get_be32s(f, &s->icr[1]);
+    qemu_get_be32s(f, &s->divide_conf);
+    s->count_shift=qemu_get_be32(f);
+    qemu_get_be32s(f, &s->initial_count);
+    s->initial_count_load_time=qemu_get_be64(f);
+    s->next_time=qemu_get_be64(f);
+
+    if (version_id >= 2)
+        qemu_get_timer(f, s->timer);
+    return 0;
+}
+
+static const VMStateDescription vmstate_apic = {
+    .name = "apic",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(apicbase, APICState),
+        VMSTATE_UINT8(id, APICState),
+        VMSTATE_UINT8(arb_id, APICState),
+        VMSTATE_UINT8(tpr, APICState),
+        VMSTATE_UINT32(spurious_vec, APICState),
+        VMSTATE_UINT8(log_dest, APICState),
+        VMSTATE_UINT8(dest_mode, APICState),
+        VMSTATE_UINT32_ARRAY(isr, APICState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICState),
+        VMSTATE_UINT32_ARRAY(icr, APICState, 2),
+        VMSTATE_UINT32(divide_conf, APICState),
+        VMSTATE_INT32(count_shift, APICState),
+        VMSTATE_UINT32(initial_count, APICState),
+        VMSTATE_INT64(initial_count_load_time, APICState),
+        VMSTATE_INT64(next_time, APICState),
+        VMSTATE_TIMER(timer, APICState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void apic_reset(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    int bsp;
+
+    bsp = cpu_is_bsp(s->cpu_env);
+    s->apicbase = 0xfee00000 |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    apic_init_reset(d);
+
+    if (bsp) {
+        /*
+         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+         * time typically by BIOS, so PIC interrupt can be delivered to the
+         * processor when local APIC is enabled.
+         */
+        s->lvt[APIC_LVT_LINT0] = 0x700;
+    }
+}
+
+static CPUReadMemoryFunc * const apic_mem_read[3] = {
+    apic_mem_readb,
+    apic_mem_readw,
+    apic_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const apic_mem_write[3] = {
+    apic_mem_writeb,
+    apic_mem_writew,
+    apic_mem_writel,
+};
+
+static int apic_init1(SysBusDevice *dev)
+{
+    APICState *s = FROM_SYSBUS(APICState, dev);
+    int apic_io_memory;
+    static int last_apic_idx;
+
+    if (last_apic_idx >= MAX_APICS) {
+        return -1;
+    }
+    apic_io_memory = cpu_register_io_memory(apic_mem_read,
+                                            apic_mem_write, NULL,
+                                            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MSI_ADDR_SIZE, apic_io_memory);
+
+    s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
+    s->idx = last_apic_idx++;
+    local_apics[s->idx] = s;
+    return 0;
+}
+
+static SysBusDeviceInfo apic_info = {
+    .init = apic_init1,
+    .qdev.name = "apic",
+    .qdev.size = sizeof(APICState),
+    .qdev.vmsd = &vmstate_apic,
+    .qdev.reset = apic_reset,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("id", APICState, id, -1),
+        DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void apic_register_devices(void)
+{
+    sysbus_register_withprop(&apic_info);
+}
+
+device_init(apic_register_devices)
diff --git a/qemu-0.15.x/hw/apic.h b/qemu-0.15.x/hw/apic.h
new file mode 100644
index 0000000..8a0c9d0
--- /dev/null
+++ b/qemu-0.15.x/hw/apic.h
@@ -0,0 +1,27 @@
+#ifndef APIC_H
+#define APIC_H
+
+#include "qemu-common.h"
+
+/* apic.c */
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
+                             uint8_t delivery_mode,
+                             uint8_t vector_num, uint8_t polarity,
+                             uint8_t trigger_mode);
+int apic_accept_pic_intr(DeviceState *s);
+void apic_deliver_pic_intr(DeviceState *s, int level);
+int apic_get_interrupt(DeviceState *s);
+void apic_reset_irq_delivered(void);
+int apic_get_irq_delivered(void);
+void cpu_set_apic_base(DeviceState *s, uint64_t val);
+uint64_t cpu_get_apic_base(DeviceState *s);
+void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
+uint8_t cpu_get_apic_tpr(DeviceState *s);
+void apic_init_reset(DeviceState *s);
+void apic_sipi(DeviceState *s);
+
+/* pc.c */
+int cpu_is_bsp(CPUState *env);
+DeviceState *cpu_get_current_apic(void);
+
+#endif
diff --git a/qemu-0.15.x/hw/apm.c b/qemu-0.15.x/hw/apm.c
new file mode 100644
index 0000000..cdda72f
--- /dev/null
+++ b/qemu-0.15.x/hw/apm.c
@@ -0,0 +1,86 @@
+/*
+ * QEMU PC APM controller Emulation
+ * This is split out from acpi.c
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "apm.h"
+#include "hw.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define APM_DPRINTF(format, ...)       printf(format, ## __VA_ARGS__)
+#else
+# define APM_DPRINTF(format, ...)       do { } while (0)
+#endif
+
+/* fixed I/O location */
+#define APM_CNT_IOPORT  0xb2
+#define APM_STS_IOPORT  0xb3
+
+static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    APMState *apm = opaque;
+    addr &= 1;
+    APM_DPRINTF("apm_ioport_writeb addr=0x%x val=0x%02x\n", addr, val);
+    if (addr == 0) {
+        apm->apmc = val;
+
+        if (apm->callback) {
+            (apm->callback)(val, apm->arg);
+        }
+    } else {
+        apm->apms = val;
+    }
+}
+
+static uint32_t apm_ioport_readb(void *opaque, uint32_t addr)
+{
+    APMState *apm = opaque;
+    uint32_t val;
+
+    addr &= 1;
+    if (addr == 0) {
+        val = apm->apmc;
+    } else {
+        val = apm->apms;
+    }
+    APM_DPRINTF("apm_ioport_readb addr=0x%x val=0x%02x\n", addr, val);
+    return val;
+}
+
+const VMStateDescription vmstate_apm = {
+    .name = "APM State",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(apmc, APMState),
+        VMSTATE_UINT8(apms, APMState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void apm_init(APMState *apm, apm_ctrl_changed_t callback, void *arg)
+{
+    apm->callback = callback;
+    apm->arg = arg;
+
+    /* ioport 0xb2, 0xb3 */
+    register_ioport_write(APM_CNT_IOPORT, 2, 1, apm_ioport_writeb, apm);
+    register_ioport_read(APM_CNT_IOPORT, 2, 1, apm_ioport_readb, apm);
+}
diff --git a/qemu-0.15.x/hw/apm.h b/qemu-0.15.x/hw/apm.h
new file mode 100644
index 0000000..f7c741e
--- /dev/null
+++ b/qemu-0.15.x/hw/apm.h
@@ -0,0 +1,22 @@
+#ifndef APM_H
+#define APM_H
+
+#include <stdint.h>
+#include "qemu-common.h"
+#include "hw.h"
+
+typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg);
+
+typedef struct APMState {
+    uint8_t apmc;
+    uint8_t apms;
+
+    apm_ctrl_changed_t callback;
+    void *arg;
+} APMState;
+
+void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg);
+
+extern const VMStateDescription vmstate_apm;
+
+#endif /* APM_H */
diff --git a/qemu-0.15.x/hw/applesmc.c b/qemu-0.15.x/hw/applesmc.c
new file mode 100644
index 0000000..23ed328
--- /dev/null
+++ b/qemu-0.15.x/hw/applesmc.c
@@ -0,0 +1,241 @@
+/*
+ *  Apple SMC controller
+ *
+ *  Copyright (c) 2007 Alexander Graf
+ *
+ *  Authors: Alexander Graf <agraf at suse.de>
+ *           Susanne Graf <suse at csgraf.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * *****************************************************************
+ *
+ * In all Intel-based Apple hardware there is an SMC chip to control the
+ * backlight, fans and several other generic device parameters. It also
+ * contains the magic keys used to dongle Mac OS X to the device.
+ *
+ * This driver was mostly created by looking at the Linux AppleSMC driver
+ * implementation and does not support IRQ.
+ *
+ */
+
+#include "hw.h"
+#include "isa.h"
+#include "console.h"
+#include "qemu-timer.h"
+
+/* #define DEBUG_SMC */
+
+#define APPLESMC_DEFAULT_IOBASE        0x300
+/* data port used by Apple SMC */
+#define APPLESMC_DATA_PORT             0x0
+/* command/status port used by Apple SMC */
+#define APPLESMC_CMD_PORT              0x4
+#define APPLESMC_NR_PORTS              32
+#define APPLESMC_MAX_DATA_LENGTH       32
+
+#define APPLESMC_READ_CMD              0x10
+#define APPLESMC_WRITE_CMD             0x11
+#define APPLESMC_GET_KEY_BY_INDEX_CMD  0x12
+#define APPLESMC_GET_KEY_TYPE_CMD      0x13
+
+#ifdef DEBUG_SMC
+#define smc_debug(...) fprintf(stderr, "AppleSMC: " __VA_ARGS__)
+#else
+#define smc_debug(...) do { } while(0)
+#endif
+
+static char default_osk[64] = "This is a dummy key. Enter the real key "
+                              "using the -osk parameter";
+
+struct AppleSMCData {
+    uint8_t len;
+    const char *key;
+    const char *data;
+    QLIST_ENTRY(AppleSMCData) node;
+};
+
+struct AppleSMCStatus {
+    ISADevice dev;
+    uint32_t iobase;
+    uint8_t cmd;
+    uint8_t status;
+    uint8_t key[4];
+    uint8_t read_pos;
+    uint8_t data_len;
+    uint8_t data_pos;
+    uint8_t data[255];
+    uint8_t charactic[4];
+    char *osk;
+    QLIST_HEAD(, AppleSMCData) data_def;
+};
+
+static void applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("CMD Write B: %#x = %#x\n", addr, val);
+    switch(val) {
+        case APPLESMC_READ_CMD:
+            s->status = 0x0c;
+            break;
+    }
+    s->cmd = val;
+    s->read_pos = 0;
+    s->data_pos = 0;
+}
+
+static void applesmc_fill_data(struct AppleSMCStatus *s)
+{
+    struct AppleSMCData *d;
+
+    QLIST_FOREACH(d, &s->data_def, node) {
+        if (!memcmp(d->key, s->key, 4)) {
+            smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
+                      d->len, d->data);
+            memcpy(s->data, d->data, d->len);
+            return;
+        }
+    }
+}
+
+static void applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("DATA Write B: %#x = %#x\n", addr, val);
+    switch(s->cmd) {
+        case APPLESMC_READ_CMD:
+            if(s->read_pos < 4) {
+                s->key[s->read_pos] = val;
+                s->status = 0x04;
+            } else if(s->read_pos == 4) {
+                s->data_len = val;
+                s->status = 0x05;
+                s->data_pos = 0;
+                smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0],
+                          s->key[1], s->key[2], s->key[3], val);
+                applesmc_fill_data(s);
+            }
+            s->read_pos++;
+            break;
+    }
+}
+
+static uint32_t applesmc_io_data_readb(void *opaque, uint32_t addr1)
+{
+    struct AppleSMCStatus *s = opaque;
+    uint8_t retval = 0;
+
+    switch(s->cmd) {
+        case APPLESMC_READ_CMD:
+            if(s->data_pos < s->data_len) {
+                retval = s->data[s->data_pos];
+                smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
+                          retval);
+                s->data_pos++;
+                if(s->data_pos == s->data_len) {
+                    s->status = 0x00;
+                    smc_debug("EOF\n");
+                } else
+                    s->status = 0x05;
+            }
+    }
+    smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
+
+    return retval;
+}
+
+static uint32_t applesmc_io_cmd_readb(void *opaque, uint32_t addr1)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("CMD Read B: %#x\n", addr1);
+    return s->status;
+}
+
+static void applesmc_add_key(struct AppleSMCStatus *s, const char *key,
+                             int len, const char *data)
+{
+    struct AppleSMCData *def;
+
+    def = qemu_mallocz(sizeof(struct AppleSMCData));
+    def->key = key;
+    def->len = len;
+    def->data = data;
+
+    QLIST_INSERT_HEAD(&s->data_def, def, node);
+}
+
+static void qdev_applesmc_isa_reset(DeviceState *dev)
+{
+    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev.qdev, dev);
+    struct AppleSMCData *d, *next;
+
+    /* Remove existing entries */
+    QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
+        QLIST_REMOVE(d, node);
+    }
+
+    applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
+    applesmc_add_key(s, "OSK0", 32, s->osk);
+    applesmc_add_key(s, "OSK1", 32, s->osk + 32);
+    applesmc_add_key(s, "NATJ", 1, "\0");
+    applesmc_add_key(s, "MSSP", 1, "\0");
+    applesmc_add_key(s, "MSSD", 1, "\0x3");
+}
+
+static int applesmc_isa_init(ISADevice *dev)
+{
+    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev, dev);
+
+    register_ioport_read(s->iobase + APPLESMC_DATA_PORT, 4, 1,
+                         applesmc_io_data_readb, s);
+    register_ioport_read(s->iobase + APPLESMC_CMD_PORT, 4, 1,
+                         applesmc_io_cmd_readb, s);
+    register_ioport_write(s->iobase + APPLESMC_DATA_PORT, 4, 1,
+                          applesmc_io_data_writeb, s);
+    register_ioport_write(s->iobase + APPLESMC_CMD_PORT, 4, 1,
+                          applesmc_io_cmd_writeb, s);
+
+    if (!s->osk || (strlen(s->osk) != 64)) {
+        fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
+        s->osk = default_osk;
+    }
+
+    QLIST_INIT(&s->data_def);
+    qdev_applesmc_isa_reset(&dev->qdev);
+
+    return 0;
+}
+
+static ISADeviceInfo applesmc_isa_info = {
+    .qdev.name  = "isa-applesmc",
+    .qdev.size  = sizeof(struct AppleSMCStatus),
+    .qdev.reset = qdev_applesmc_isa_reset,
+    .init       = applesmc_isa_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
+                          APPLESMC_DEFAULT_IOBASE),
+        DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void applesmc_register_devices(void)
+{
+    isa_qdev_register(&applesmc_isa_info);
+}
+
+device_init(applesmc_register_devices)
diff --git a/qemu-0.15.x/hw/arm-misc.h b/qemu-0.15.x/hw/arm-misc.h
new file mode 100644
index 0000000..f8a7472
--- /dev/null
+++ b/qemu-0.15.x/hw/arm-misc.h
@@ -0,0 +1,46 @@
+/*
+ * Misc ARM declarations
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#ifndef ARM_MISC_H
+#define ARM_MISC_H 1
+
+/* The CPU is also modeled as an interrupt controller.  */
+#define ARM_PIC_CPU_IRQ 0
+#define ARM_PIC_CPU_FIQ 1
+qemu_irq *arm_pic_init_cpu(CPUState *env);
+
+/* armv7m.c */
+qemu_irq *armv7m_init(int flash_size, int sram_size,
+                      const char *kernel_filename, const char *cpu_model);
+
+/* arm_boot.c */
+struct arm_boot_info {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+    target_phys_addr_t loader_start;
+    target_phys_addr_t smp_loader_start;
+    target_phys_addr_t smp_priv_base;
+    int nb_cpus;
+    int board_id;
+    int (*atag_board)(const struct arm_boot_info *info, void *p);
+    /* Used internally by arm_boot.c */
+    int is_linux;
+    target_phys_addr_t initrd_size;
+    target_phys_addr_t entry;
+};
+void arm_load_kernel(CPUState *env, struct arm_boot_info *info);
+
+/* Multiplication factor to convert from system clock ticks to qemu timer
+   ticks.  */
+extern int system_clock_scale;
+
+#endif /* !ARM_MISC_H */
diff --git a/qemu-0.15.x/hw/arm11mpcore.c b/qemu-0.15.x/hw/arm11mpcore.c
new file mode 100644
index 0000000..b47707f
--- /dev/null
+++ b/qemu-0.15.x/hw/arm11mpcore.c
@@ -0,0 +1,112 @@
+/*
+ * ARM11MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
+   (+ 32 internal).  However my test chip only exposes/reports 32.
+   More importantly Linux falls over if more than 32 are present!  */
+#define GIC_NIRQ 64
+#include "mpcore.c"
+
+/* Dummy PIC to route IRQ lines.  The baseboard has 4 independent IRQ
+   controllers.  The output of these, plus some of the raw input lines
+   are fed into a single SMP-aware interrupt controller on the CPU.  */
+typedef struct {
+    SysBusDevice busdev;
+    SysBusDevice *priv;
+    qemu_irq cpuic[32];
+    qemu_irq rvic[4][64];
+    uint32_t num_cpu;
+} mpcore_rirq_state;
+
+/* Map baseboard IRQs onto CPU IRQ lines.  */
+static const int mpcore_irq_map[32] = {
+    -1, -1, -1, -1,  1,  2, -1, -1,
+    -1, -1,  6, -1,  4,  5, -1, -1,
+    -1, 14, 15,  0,  7,  8, -1, -1,
+    -1, -1, -1, -1,  9,  3, -1, -1,
+};
+
+static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
+{
+    mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        qemu_set_irq(s->rvic[i][irq], level);
+    }
+    if (irq < 32) {
+        irq = mpcore_irq_map[irq];
+        if (irq >= 0) {
+            qemu_set_irq(s->cpuic[irq], level);
+        }
+    }
+}
+
+static void mpcore_rirq_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+    sysbus_mmio_map(s->priv, 0, base);
+}
+
+static int realview_mpcore_init(SysBusDevice *dev)
+{
+    mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+    DeviceState *gic;
+    DeviceState *priv;
+    int n;
+    int i;
+
+    priv = qdev_create(NULL, "arm11mpcore_priv");
+    qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
+    qdev_init_nofail(priv);
+    s->priv = sysbus_from_qdev(priv);
+    sysbus_pass_irq(dev, s->priv);
+    for (i = 0; i < 32; i++) {
+        s->cpuic[i] = qdev_get_gpio_in(priv, i);
+    }
+    /* ??? IRQ routing is hardcoded to "normal" mode.  */
+    for (n = 0; n < 4; n++) {
+        gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
+                                   s->cpuic[10 + n]);
+        for (i = 0; i < 64; i++) {
+            s->rvic[n][i] = qdev_get_gpio_in(gic, i);
+        }
+    }
+    qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
+    sysbus_init_mmio_cb(dev, 0x2000, mpcore_rirq_map);
+    return 0;
+}
+
+static SysBusDeviceInfo mpcore_rirq_info = {
+    .init = realview_mpcore_init,
+    .qdev.name  = "realview_mpcore",
+    .qdev.size  = sizeof(mpcore_rirq_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static SysBusDeviceInfo mpcore_priv_info = {
+    .init = mpcore_priv_init,
+    .qdev.name  = "arm11mpcore_priv",
+    .qdev.size  = sizeof(mpcore_priv_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void arm11mpcore_register_devices(void)
+{
+    sysbus_register_withprop(&mpcore_rirq_info);
+    sysbus_register_withprop(&mpcore_priv_info);
+}
+
+device_init(arm11mpcore_register_devices)
diff --git a/qemu-0.15.x/hw/arm_boot.c b/qemu-0.15.x/hw/arm_boot.c
new file mode 100644
index 0000000..215d5de
--- /dev/null
+++ b/qemu-0.15.x/hw/arm_boot.c
@@ -0,0 +1,290 @@
+/*
+ * ARM kernel loader.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "arm-misc.h"
+#include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
+
+#define KERNEL_ARGS_ADDR 0x100
+#define KERNEL_LOAD_ADDR 0x00010000
+#define INITRD_LOAD_ADDR 0x00d00000
+
+/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
+static uint32_t bootloader[] = {
+  0xe3a00000, /* mov     r0, #0 */
+  0xe3a01000, /* mov     r1, #0x?? */
+  0xe3811c00, /* orr     r1, r1, #0x??00 */
+  0xe59f2000, /* ldr     r2, [pc, #0] */
+  0xe59ff000, /* ldr     pc, [pc, #0] */
+  0, /* Address of kernel args.  Set by integratorcp_init.  */
+  0  /* Kernel entry point.  Set by integratorcp_init.  */
+};
+
+/* Entry point for secondary CPUs.  Enable interrupt controller and
+   Issue WFI until start address is written to system controller.  */
+static uint32_t smpboot[] = {
+  0xe59f0020, /* ldr     r0, privbase */
+  0xe3a01001, /* mov     r1, #1 */
+  0xe5801100, /* str     r1, [r0, #0x100] */
+  0xe3a00201, /* mov     r0, #0x10000000 */
+  0xe3800030, /* orr     r0, #0x30 */
+  0xe320f003, /* wfi */
+  0xe5901000, /* ldr     r1, [r0] */
+  0xe1110001, /* tst     r1, r1 */
+  0x0afffffb, /* beq     <wfi> */
+  0xe12fff11, /* bx      r1 */
+  0 /* privbase: Private memory region base address.  */
+};
+
+#define WRITE_WORD(p, value) do { \
+    stl_phys_notdirty(p, value);  \
+    p += 4;                       \
+} while (0)
+
+static void set_kernel_args(const struct arm_boot_info *info,
+                int initrd_size, target_phys_addr_t base)
+{
+    target_phys_addr_t p;
+
+    p = base + KERNEL_ARGS_ADDR;
+    /* ATAG_CORE */
+    WRITE_WORD(p, 5);
+    WRITE_WORD(p, 0x54410001);
+    WRITE_WORD(p, 1);
+    WRITE_WORD(p, 0x1000);
+    WRITE_WORD(p, 0);
+    /* ATAG_MEM */
+    /* TODO: handle multiple chips on one ATAG list */
+    WRITE_WORD(p, 4);
+    WRITE_WORD(p, 0x54410002);
+    WRITE_WORD(p, info->ram_size);
+    WRITE_WORD(p, info->loader_start);
+    if (initrd_size) {
+        /* ATAG_INITRD2 */
+        WRITE_WORD(p, 4);
+        WRITE_WORD(p, 0x54420005);
+        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+        WRITE_WORD(p, initrd_size);
+    }
+    if (info->kernel_cmdline && *info->kernel_cmdline) {
+        /* ATAG_CMDLINE */
+        int cmdline_size;
+
+        cmdline_size = strlen(info->kernel_cmdline);
+        cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline,
+                                  cmdline_size + 1);
+        cmdline_size = (cmdline_size >> 2) + 1;
+        WRITE_WORD(p, cmdline_size + 2);
+        WRITE_WORD(p, 0x54410009);
+        p += cmdline_size * 4;
+    }
+    if (info->atag_board) {
+        /* ATAG_BOARD */
+        int atag_board_len;
+        uint8_t atag_board_buf[0x1000];
+
+        atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
+        WRITE_WORD(p, (atag_board_len + 8) >> 2);
+        WRITE_WORD(p, 0x414f4d50);
+        cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
+        p += atag_board_len;
+    }
+    /* ATAG_END */
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+}
+
+static void set_kernel_args_old(const struct arm_boot_info *info,
+                int initrd_size, target_phys_addr_t base)
+{
+    target_phys_addr_t p;
+    const char *s;
+
+
+    /* see linux/include/asm-arm/setup.h */
+    p = base + KERNEL_ARGS_ADDR;
+    /* page_size */
+    WRITE_WORD(p, 4096);
+    /* nr_pages */
+    WRITE_WORD(p, info->ram_size / 4096);
+    /* ramdisk_size */
+    WRITE_WORD(p, 0);
+#define FLAG_READONLY	1
+#define FLAG_RDLOAD	4
+#define FLAG_RDPROMPT	8
+    /* flags */
+    WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
+    /* rootdev */
+    WRITE_WORD(p, (31 << 8) | 0);	/* /dev/mtdblock0 */
+    /* video_num_cols */
+    WRITE_WORD(p, 0);
+    /* video_num_rows */
+    WRITE_WORD(p, 0);
+    /* video_x */
+    WRITE_WORD(p, 0);
+    /* video_y */
+    WRITE_WORD(p, 0);
+    /* memc_control_reg */
+    WRITE_WORD(p, 0);
+    /* unsigned char sounddefault */
+    /* unsigned char adfsdrives */
+    /* unsigned char bytes_per_char_h */
+    /* unsigned char bytes_per_char_v */
+    WRITE_WORD(p, 0);
+    /* pages_in_bank[4] */
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    /* pages_in_vram */
+    WRITE_WORD(p, 0);
+    /* initrd_start */
+    if (initrd_size)
+        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+    else
+        WRITE_WORD(p, 0);
+    /* initrd_size */
+    WRITE_WORD(p, initrd_size);
+    /* rd_start */
+    WRITE_WORD(p, 0);
+    /* system_rev */
+    WRITE_WORD(p, 0);
+    /* system_serial_low */
+    WRITE_WORD(p, 0);
+    /* system_serial_high */
+    WRITE_WORD(p, 0);
+    /* mem_fclk_21285 */
+    WRITE_WORD(p, 0);
+    /* zero unused fields */
+    while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
+        WRITE_WORD(p, 0);
+    }
+    s = info->kernel_cmdline;
+    if (s) {
+        cpu_physical_memory_write(p, (void *)s, strlen(s) + 1);
+    } else {
+        WRITE_WORD(p, 0);
+    }
+}
+
+static void do_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    const struct arm_boot_info *info = env->boot_info;
+
+    cpu_reset(env);
+    if (info) {
+        if (!info->is_linux) {
+            /* Jump to the entry point.  */
+            env->regs[15] = info->entry & 0xfffffffe;
+            env->thumb = info->entry & 1;
+        } else {
+            if (env == first_cpu) {
+                env->regs[15] = info->loader_start;
+                if (old_param) {
+                    set_kernel_args_old(info, info->initrd_size,
+                                        info->loader_start);
+                } else {
+                    set_kernel_args(info, info->initrd_size,
+                                    info->loader_start);
+                }
+            } else {
+                env->regs[15] = info->smp_loader_start;
+            }
+        }
+    }
+}
+
+void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
+{
+    int kernel_size;
+    int initrd_size;
+    int n;
+    int is_linux = 0;
+    uint64_t elf_entry;
+    target_phys_addr_t entry;
+    int big_endian;
+
+    /* Load the kernel.  */
+    if (!info->kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    if (info->nb_cpus == 0)
+        info->nb_cpus = 1;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    /* Assume that raw images are linux kernels, and ELF images are not.  */
+    kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, big_endian, ELF_MACHINE, 1);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
+                                  &is_linux);
+    }
+    if (kernel_size < 0) {
+        entry = info->loader_start + KERNEL_LOAD_ADDR;
+        kernel_size = load_image_targphys(info->kernel_filename, entry,
+                                          ram_size - KERNEL_LOAD_ADDR);
+        is_linux = 1;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                info->kernel_filename);
+        exit(1);
+    }
+    info->entry = entry;
+    if (is_linux) {
+        if (info->initrd_filename) {
+            initrd_size = load_image_targphys(info->initrd_filename,
+                                              info->loader_start
+                                              + INITRD_LOAD_ADDR,
+                                              ram_size - INITRD_LOAD_ADDR);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initrd '%s'\n",
+                        info->initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_size = 0;
+        }
+        bootloader[1] |= info->board_id & 0xff;
+        bootloader[2] |= (info->board_id >> 8) & 0xff;
+        bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
+        bootloader[6] = entry;
+        for (n = 0; n < sizeof(bootloader) / 4; n++) {
+            bootloader[n] = tswap32(bootloader[n]);
+        }
+        rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
+                           info->loader_start);
+        if (info->nb_cpus > 1) {
+            smpboot[10] = info->smp_priv_base;
+            for (n = 0; n < sizeof(smpboot) / 4; n++) {
+                smpboot[n] = tswap32(smpboot[n]);
+            }
+            rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+                               info->smp_loader_start);
+        }
+        info->initrd_size = initrd_size;
+    }
+    info->is_linux = is_linux;
+
+    for (; env; env = env->next_cpu) {
+        env->boot_info = info;
+        qemu_register_reset(do_cpu_reset, env);
+    }
+}
diff --git a/qemu-0.15.x/hw/arm_gic.c b/qemu-0.15.x/hw/arm_gic.c
new file mode 100644
index 0000000..fb07314
--- /dev/null
+++ b/qemu-0.15.x/hw/arm_gic.c
@@ -0,0 +1,749 @@
+/*
+ * ARM Generic/Distributed Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* This file contains implementation code for the RealView EB interrupt
+   controller, MPCore distributed interrupt controller and ARMv7-M
+   Nested Vectored Interrupt Controller.  */
+
+//#define DEBUG_GIC
+
+#ifdef DEBUG_GIC
+#define DPRINTF(fmt, ...) \
+do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#ifdef NVIC
+static const uint8_t gic_id[] =
+{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
+/* The NVIC has 16 internal vectors.  However these are not exposed
+   through the normal GIC interface.  */
+#define GIC_BASE_IRQ    32
+#else
+static const uint8_t gic_id[] =
+{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+#define GIC_BASE_IRQ    0
+#endif
+
+#define FROM_SYSBUSGIC(type, dev) \
+    DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
+
+typedef struct gic_irq_state
+{
+    /* ??? The documentation seems to imply the enable bits are global, even
+       for per-cpu interrupts.  This seems strange.  */
+    unsigned enabled:1;
+    unsigned pending:NCPU;
+    unsigned active:NCPU;
+    unsigned level:NCPU;
+    unsigned model:1; /* 0 = N:N, 1 = 1:N */
+    unsigned trigger:1; /* nonzero = edge triggered.  */
+} gic_irq_state;
+
+#define ALL_CPU_MASK ((1 << NCPU) - 1)
+#if NCPU > 1
+#define NUM_CPU(s) ((s)->num_cpu)
+#else
+#define NUM_CPU(s) 1
+#endif
+
+#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
+#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
+#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
+#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
+#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
+#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
+#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
+#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
+#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
+#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
+#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
+#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
+#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
+#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
+#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
+#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
+#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
+#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
+#define GIC_GET_PRIORITY(irq, cpu) \
+  (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])
+#ifdef NVIC
+#define GIC_TARGET(irq) 1
+#else
+#define GIC_TARGET(irq) s->irq_target[irq]
+#endif
+
+typedef struct gic_state
+{
+    SysBusDevice busdev;
+    qemu_irq parent_irq[NCPU];
+    int enabled;
+    int cpu_enabled[NCPU];
+
+    gic_irq_state irq_state[GIC_NIRQ];
+#ifndef NVIC
+    int irq_target[GIC_NIRQ];
+#endif
+    int priority1[32][NCPU];
+    int priority2[GIC_NIRQ - 32];
+    int last_active[GIC_NIRQ][NCPU];
+
+    int priority_mask[NCPU];
+    int running_irq[NCPU];
+    int running_priority[NCPU];
+    int current_pending[NCPU];
+
+#if NCPU > 1
+    int num_cpu;
+#endif
+
+    int iomemtype;
+} gic_state;
+
+/* TODO: Many places that call this routine could be optimized.  */
+/* Update interrupt status after enabled or pending bits have been changed.  */
+static void gic_update(gic_state *s)
+{
+    int best_irq;
+    int best_prio;
+    int irq;
+    int level;
+    int cpu;
+    int cm;
+
+    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
+        cm = 1 << cpu;
+        s->current_pending[cpu] = 1023;
+        if (!s->enabled || !s->cpu_enabled[cpu]) {
+	    qemu_irq_lower(s->parent_irq[cpu]);
+            return;
+        }
+        best_prio = 0x100;
+        best_irq = 1023;
+        for (irq = 0; irq < GIC_NIRQ; irq++) {
+            if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {
+                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
+                    best_prio = GIC_GET_PRIORITY(irq, cpu);
+                    best_irq = irq;
+                }
+            }
+        }
+        level = 0;
+        if (best_prio <= s->priority_mask[cpu]) {
+            s->current_pending[cpu] = best_irq;
+            if (best_prio < s->running_priority[cpu]) {
+                DPRINTF("Raised pending IRQ %d\n", best_irq);
+                level = 1;
+            }
+        }
+        qemu_set_irq(s->parent_irq[cpu], level);
+    }
+}
+
+static void __attribute__((unused))
+gic_set_pending_private(gic_state *s, int cpu, int irq)
+{
+    int cm = 1 << cpu;
+
+    if (GIC_TEST_PENDING(irq, cm))
+        return;
+
+    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
+    GIC_SET_PENDING(irq, cm);
+    gic_update(s);
+}
+
+/* Process a change in an external IRQ input.  */
+static void gic_set_irq(void *opaque, int irq, int level)
+{
+    gic_state *s = (gic_state *)opaque;
+    /* The first external input line is internal interrupt 32.  */
+    irq += 32;
+    if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
+        return;
+
+    if (level) {
+        GIC_SET_LEVEL(irq, ALL_CPU_MASK);
+        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
+            DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
+            GIC_SET_PENDING(irq, GIC_TARGET(irq));
+        }
+    } else {
+        GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
+    }
+    gic_update(s);
+}
+
+static void gic_set_running_irq(gic_state *s, int cpu, int irq)
+{
+    s->running_irq[cpu] = irq;
+    if (irq == 1023) {
+        s->running_priority[cpu] = 0x100;
+    } else {
+        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
+    }
+    gic_update(s);
+}
+
+static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
+{
+    int new_irq;
+    int cm = 1 << cpu;
+    new_irq = s->current_pending[cpu];
+    if (new_irq == 1023
+            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
+        DPRINTF("ACK no pending IRQ\n");
+        return 1023;
+    }
+    s->last_active[new_irq][cpu] = s->running_irq[cpu];
+    /* Clear pending flags for both level and edge triggered interrupts.
+       Level triggered IRQs will be reasserted once they become inactive.  */
+    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
+    gic_set_running_irq(s, cpu, new_irq);
+    DPRINTF("ACK %d\n", new_irq);
+    return new_irq;
+}
+
+static void gic_complete_irq(gic_state * s, int cpu, int irq)
+{
+    int update = 0;
+    int cm = 1 << cpu;
+    DPRINTF("EOI %d\n", irq);
+    if (s->running_irq[cpu] == 1023)
+        return; /* No active IRQ.  */
+    if (irq != 1023) {
+        /* Mark level triggered interrupts as pending if they are still
+           raised.  */
+        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
+                && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
+            DPRINTF("Set %d pending mask %x\n", irq, cm);
+            GIC_SET_PENDING(irq, cm);
+            update = 1;
+        }
+    }
+    if (irq != s->running_irq[cpu]) {
+        /* Complete an IRQ that is not currently running.  */
+        int tmp = s->running_irq[cpu];
+        while (s->last_active[tmp][cpu] != 1023) {
+            if (s->last_active[tmp][cpu] == irq) {
+                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
+                break;
+            }
+            tmp = s->last_active[tmp][cpu];
+        }
+        if (update) {
+            gic_update(s);
+        }
+    } else {
+        /* Complete the current running IRQ.  */
+        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
+    }
+}
+
+static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
+{
+    gic_state *s = (gic_state *)opaque;
+    uint32_t res;
+    int irq;
+    int i;
+    int cpu;
+    int cm;
+    int mask;
+
+    cpu = gic_get_current_cpu();
+    cm = 1 << cpu;
+    if (offset < 0x100) {
+#ifndef NVIC
+        if (offset == 0)
+            return s->enabled;
+        if (offset == 4)
+            return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+        if (offset < 0x08)
+            return 0;
+#endif
+        goto bad_reg;
+    } else if (offset < 0x200) {
+        /* Interrupt Set/Clear Enable.  */
+        if (offset < 0x180)
+            irq = (offset - 0x100) * 8;
+        else
+            irq = (offset - 0x180) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ENABLED(irq + i)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Set/Clear Pending.  */
+        if (offset < 0x280)
+            irq = (offset - 0x200) * 8;
+        else
+            irq = (offset - 0x280) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < 32) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_PENDING(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < 32) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ACTIVE(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = GIC_GET_PRIORITY(irq, cpu);
+#ifndef NVIC
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        irq = (offset - 0x800) + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq >= 29 && irq <= 31) {
+            res = cm;
+        } else {
+            res = GIC_TARGET(irq);
+        }
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 4; i++) {
+            if (GIC_TEST_MODEL(irq + i))
+                res |= (1 << (i * 2));
+            if (GIC_TEST_TRIGGER(irq + i))
+                res |= (2 << (i * 2));
+        }
+#endif
+    } else if (offset < 0xfe0) {
+        goto bad_reg;
+    } else /* offset >= 0xfe0 */ {
+        if (offset & 3) {
+            res = 0;
+        } else {
+            res = gic_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    return res;
+bad_reg:
+    hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = gic_dist_readb(opaque, offset);
+    val |= gic_dist_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+#ifdef NVIC
+    gic_state *s = (gic_state *)opaque;
+    uint32_t addr;
+    addr = offset;
+    if (addr < 0x100 || addr > 0xd00)
+        return nvic_readl(s, addr);
+#endif
+    val = gic_dist_readw(opaque, offset);
+    val |= gic_dist_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+    int irq;
+    int i;
+    int cpu;
+
+    cpu = gic_get_current_cpu();
+    if (offset < 0x100) {
+#ifdef NVIC
+        goto bad_reg;
+#else
+        if (offset == 0) {
+            s->enabled = (value & 1);
+            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
+        } else if (offset < 4) {
+            /* ignored.  */
+        } else {
+            goto bad_reg;
+        }
+#endif
+    } else if (offset < 0x180) {
+        /* Interrupt Set Enable.  */
+        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0xff;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
+                if (!GIC_TEST_ENABLED(irq + i))
+                    DPRINTF("Enabled IRQ %d\n", irq + i);
+                GIC_SET_ENABLED(irq + i);
+                /* If a raised level triggered IRQ enabled then mark
+                   is as pending.  */
+                if (GIC_TEST_LEVEL(irq + i, mask)
+                        && !GIC_TEST_TRIGGER(irq + i)) {
+                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
+                    GIC_SET_PENDING(irq + i, mask);
+                }
+            }
+        }
+    } else if (offset < 0x200) {
+        /* Interrupt Clear Enable.  */
+        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                if (GIC_TEST_ENABLED(irq + i))
+                    DPRINTF("Disabled IRQ %d\n", irq + i);
+                GIC_CLEAR_ENABLED(irq + i);
+            }
+        }
+    } else if (offset < 0x280) {
+        /* Interrupt Set Pending.  */
+        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 16)
+          irq = 0;
+
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Clear Pending.  */
+        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            /* ??? This currently clears the pending bit for all CPUs, even
+               for per-CPU interrupts.  It's unclear whether this is the
+               corect behavior.  */
+            if (value & (1 << i)) {
+                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        goto bad_reg;
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 32) {
+            s->priority1[irq][cpu] = value;
+        } else {
+            s->priority2[irq - 32] = value;
+        }
+#ifndef NVIC
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        irq = (offset - 0x800) + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 29)
+            value = 0;
+        else if (irq < 32)
+            value = ALL_CPU_MASK;
+        s->irq_target[irq] = value & ALL_CPU_MASK;
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        if (irq < 32)
+            value |= 0xaa;
+        for (i = 0; i < 4; i++) {
+            if (value & (1 << (i * 2))) {
+                GIC_SET_MODEL(irq + i);
+            } else {
+                GIC_CLEAR_MODEL(irq + i);
+            }
+            if (value & (2 << (i * 2))) {
+                GIC_SET_TRIGGER(irq + i);
+            } else {
+                GIC_CLEAR_TRIGGER(irq + i);
+            }
+        }
+#endif
+    } else {
+        /* 0xf00 is only handled for 32-bit writes.  */
+        goto bad_reg;
+    }
+    gic_update(s);
+    return;
+bad_reg:
+    hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
+}
+
+static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_dist_writeb(opaque, offset, value & 0xff);
+    gic_dist_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+#ifdef NVIC
+    uint32_t addr;
+    addr = offset;
+    if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
+        nvic_writel(s, addr, value);
+        return;
+    }
+#endif
+    if (offset == 0xf00) {
+        int cpu;
+        int irq;
+        int mask;
+
+        cpu = gic_get_current_cpu();
+        irq = value & 0x3ff;
+        switch ((value >> 24) & 3) {
+        case 0:
+            mask = (value >> 16) & ALL_CPU_MASK;
+            break;
+        case 1:
+            mask = ALL_CPU_MASK ^ (1 << cpu);
+            break;
+        case 2:
+            mask = 1 << cpu;
+            break;
+        default:
+            DPRINTF("Bad Soft Int target filter\n");
+            mask = ALL_CPU_MASK;
+            break;
+        }
+        GIC_SET_PENDING(irq, mask);
+        gic_update(s);
+        return;
+    }
+    gic_dist_writew(opaque, offset, value & 0xffff);
+    gic_dist_writew(opaque, offset + 2, value >> 16);
+}
+
+static CPUReadMemoryFunc * const gic_dist_readfn[] = {
+   gic_dist_readb,
+   gic_dist_readw,
+   gic_dist_readl
+};
+
+static CPUWriteMemoryFunc * const gic_dist_writefn[] = {
+   gic_dist_writeb,
+   gic_dist_writew,
+   gic_dist_writel
+};
+
+#ifndef NVIC
+static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->cpu_enabled[cpu];
+    case 0x04: /* Priority mask */
+        return s->priority_mask[cpu];
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        return 0;
+    case 0x0c: /* Acknowledge */
+        return gic_acknowledge_irq(s, cpu);
+    case 0x14: /* Runing Priority */
+        return s->running_priority[cpu];
+    case 0x18: /* Highest Pending Interrupt */
+        return s->current_pending[cpu];
+    default:
+        hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        s->cpu_enabled[cpu] = (value & 1);
+        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis");
+        break;
+    case 0x04: /* Priority mask */
+        s->priority_mask[cpu] = (value & 0xff);
+        break;
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        break;
+    case 0x10: /* End Of Interrupt */
+        return gic_complete_irq(s, cpu, value & 0x3ff);
+    default:
+        hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    gic_update(s);
+}
+#endif
+
+static void gic_reset(gic_state *s)
+{
+    int i;
+    memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
+    for (i = 0 ; i < NUM_CPU(s); i++) {
+        s->priority_mask[i] = 0xf0;
+        s->current_pending[i] = 1023;
+        s->running_irq[i] = 1023;
+        s->running_priority[i] = 0x100;
+#ifdef NVIC
+        /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
+        s->cpu_enabled[i] = 1;
+#else
+        s->cpu_enabled[i] = 0;
+#endif
+    }
+    for (i = 0; i < 16; i++) {
+        GIC_SET_ENABLED(i);
+        GIC_SET_TRIGGER(i);
+    }
+#ifdef NVIC
+    /* The NVIC is always enabled.  */
+    s->enabled = 1;
+#else
+    s->enabled = 0;
+#endif
+}
+
+static void gic_save(QEMUFile *f, void *opaque)
+{
+    gic_state *s = (gic_state *)opaque;
+    int i;
+    int j;
+
+    qemu_put_be32(f, s->enabled);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        qemu_put_be32(f, s->cpu_enabled[i]);
+#ifndef NVIC
+        qemu_put_be32(f, s->irq_target[i]);
+#endif
+        for (j = 0; j < 32; j++)
+            qemu_put_be32(f, s->priority1[j][i]);
+        for (j = 0; j < GIC_NIRQ; j++)
+            qemu_put_be32(f, s->last_active[j][i]);
+        qemu_put_be32(f, s->priority_mask[i]);
+        qemu_put_be32(f, s->running_irq[i]);
+        qemu_put_be32(f, s->running_priority[i]);
+        qemu_put_be32(f, s->current_pending[i]);
+    }
+    for (i = 0; i < GIC_NIRQ - 32; i++) {
+        qemu_put_be32(f, s->priority2[i]);
+    }
+    for (i = 0; i < GIC_NIRQ; i++) {
+        qemu_put_byte(f, s->irq_state[i].enabled);
+        qemu_put_byte(f, s->irq_state[i].pending);
+        qemu_put_byte(f, s->irq_state[i].active);
+        qemu_put_byte(f, s->irq_state[i].level);
+        qemu_put_byte(f, s->irq_state[i].model);
+        qemu_put_byte(f, s->irq_state[i].trigger);
+    }
+}
+
+static int gic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    gic_state *s = (gic_state *)opaque;
+    int i;
+    int j;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->enabled = qemu_get_be32(f);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        s->cpu_enabled[i] = qemu_get_be32(f);
+#ifndef NVIC
+        s->irq_target[i] = qemu_get_be32(f);
+#endif
+        for (j = 0; j < 32; j++)
+            s->priority1[j][i] = qemu_get_be32(f);
+        for (j = 0; j < GIC_NIRQ; j++)
+            s->last_active[j][i] = qemu_get_be32(f);
+        s->priority_mask[i] = qemu_get_be32(f);
+        s->running_irq[i] = qemu_get_be32(f);
+        s->running_priority[i] = qemu_get_be32(f);
+        s->current_pending[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < GIC_NIRQ - 32; i++) {
+        s->priority2[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < GIC_NIRQ; i++) {
+        s->irq_state[i].enabled = qemu_get_byte(f);
+        s->irq_state[i].pending = qemu_get_byte(f);
+        s->irq_state[i].active = qemu_get_byte(f);
+        s->irq_state[i].level = qemu_get_byte(f);
+        s->irq_state[i].model = qemu_get_byte(f);
+        s->irq_state[i].trigger = qemu_get_byte(f);
+    }
+
+    return 0;
+}
+
+#if NCPU > 1
+static void gic_init(gic_state *s, int num_cpu)
+#else
+static void gic_init(gic_state *s)
+#endif
+{
+    int i;
+
+#if NCPU > 1
+    s->num_cpu = num_cpu;
+#endif
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
+    }
+    s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
+                                          gic_dist_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
+    gic_reset(s);
+    register_savevm(NULL, "arm_gic", -1, 1, gic_save, gic_load, s);
+}
diff --git a/qemu-0.15.x/hw/arm_pic.c b/qemu-0.15.x/hw/arm_pic.c
new file mode 100644
index 0000000..985148a
--- /dev/null
+++ b/qemu-0.15.x/hw/arm_pic.c
@@ -0,0 +1,49 @@
+/*
+ * Generic ARM Programmable Interrupt Controller support.
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "arm-misc.h"
+
+/* Stub functions for hardware that doesn't exist.  */
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
+
+
+/* Input 0 is IRQ and input 1 is FIQ.  */
+static void arm_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+    switch (irq) {
+    case ARM_PIC_CPU_IRQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        break;
+    case ARM_PIC_CPU_FIQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
+        break;
+    default:
+        hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq);
+    }
+}
+
+qemu_irq *arm_pic_init_cpu(CPUState *env)
+{
+    return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2);
+}
diff --git a/qemu-0.15.x/hw/arm_sysctl.c b/qemu-0.15.x/hw/arm_sysctl.c
new file mode 100644
index 0000000..fd0c8bc
--- /dev/null
+++ b/qemu-0.15.x/hw/arm_sysctl.c
@@ -0,0 +1,371 @@
+/*
+ * Status and system control registers for ARM RealView/Versatile boards.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+#include "primecell.h"
+#include "sysemu.h"
+
+#define LOCK_VALUE 0xa05f
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t sys_id;
+    uint32_t leds;
+    uint16_t lockval;
+    uint32_t cfgdata1;
+    uint32_t cfgdata2;
+    uint32_t flags;
+    uint32_t nvflags;
+    uint32_t resetlevel;
+    uint32_t proc_id;
+    uint32_t sys_mci;
+    uint32_t sys_cfgdata;
+    uint32_t sys_cfgctrl;
+    uint32_t sys_cfgstat;
+} arm_sysctl_state;
+
+static const VMStateDescription vmstate_arm_sysctl = {
+    .name = "realview_sysctl",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(leds, arm_sysctl_state),
+        VMSTATE_UINT16(lockval, arm_sysctl_state),
+        VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
+        VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
+        VMSTATE_UINT32(flags, arm_sysctl_state),
+        VMSTATE_UINT32(nvflags, arm_sysctl_state),
+        VMSTATE_UINT32(resetlevel, arm_sysctl_state),
+        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* The PB926 actually uses a different format for
+ * its SYS_ID register. Fortunately the bits which are
+ * board type on later boards are distinct.
+ */
+#define BOARD_ID_PB926 0x100
+#define BOARD_ID_EB 0x140
+#define BOARD_ID_PBA8 0x178
+#define BOARD_ID_PBX 0x182
+#define BOARD_ID_VEXPRESS 0x190
+
+static int board_id(arm_sysctl_state *s)
+{
+    /* Extract the board ID field from the SYS_ID register value */
+    return (s->sys_id >> 16) & 0xfff;
+}
+
+static void arm_sysctl_reset(DeviceState *d)
+{
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d));
+
+    s->leds = 0;
+    s->lockval = 0;
+    s->cfgdata1 = 0;
+    s->cfgdata2 = 0;
+    s->flags = 0;
+    s->resetlevel = 0;
+}
+
+static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* ID */
+        return s->sys_id;
+    case 0x04: /* SW */
+        /* General purpose hardware switches.
+           We don't have a useful way of exposing these to the user.  */
+        return 0;
+    case 0x08: /* LED */
+        return s->leds;
+    case 0x20: /* LOCK */
+        return s->lockval;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+    case 0x24: /* 100HZ */
+        /* ??? Implement these.  */
+        return 0;
+    case 0x28: /* CFGDATA1 */
+        return s->cfgdata1;
+    case 0x2c: /* CFGDATA2 */
+        return s->cfgdata2;
+    case 0x30: /* FLAGS */
+        return s->flags;
+    case 0x38: /* NVFLAGS */
+        return s->nvflags;
+    case 0x40: /* RESETCTL */
+        if (board_id(s) == BOARD_ID_VEXPRESS) {
+            /* reserved: RAZ/WI */
+            return 0;
+        }
+        return s->resetlevel;
+    case 0x44: /* PCICTL */
+        return 1;
+    case 0x48: /* MCI */
+        return s->sys_mci;
+    case 0x4c: /* FLASH */
+        return 0;
+    case 0x50: /* CLCD */
+        return 0x1000;
+    case 0x54: /* CLCDSER */
+        return 0;
+    case 0x58: /* BOOTCS */
+        return 0;
+    case 0x5c: /* 24MHz */
+        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
+    case 0x60: /* MISC */
+        return 0;
+    case 0x84: /* PROCID0 */
+        return s->proc_id;
+    case 0x88: /* PROCID1 */
+        return 0xff000000;
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+    case 0xc0: /* SYS_TEST_OSC0 */
+    case 0xc4: /* SYS_TEST_OSC1 */
+    case 0xc8: /* SYS_TEST_OSC2 */
+    case 0xcc: /* SYS_TEST_OSC3 */
+    case 0xd0: /* SYS_TEST_OSC4 */
+        return 0;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgdata;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgctrl;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgstat;
+    default:
+    bad_reg:
+        printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t val)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+
+    switch (offset) {
+    case 0x08: /* LED */
+        s->leds = val;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+        /* ??? */
+        break;
+    case 0x20: /* LOCK */
+        if (val == LOCK_VALUE)
+            s->lockval = val;
+        else
+            s->lockval = val & 0x7fff;
+        break;
+    case 0x28: /* CFGDATA1 */
+        /* ??? Need to implement this.  */
+        s->cfgdata1 = val;
+        break;
+    case 0x2c: /* CFGDATA2 */
+        /* ??? Need to implement this.  */
+        s->cfgdata2 = val;
+        break;
+    case 0x30: /* FLAGSSET */
+        s->flags |= val;
+        break;
+    case 0x34: /* FLAGSCLR */
+        s->flags &= ~val;
+        break;
+    case 0x38: /* NVFLAGSSET */
+        s->nvflags |= val;
+        break;
+    case 0x3c: /* NVFLAGSCLR */
+        s->nvflags &= ~val;
+        break;
+    case 0x40: /* RESETCTL */
+        if (board_id(s) == BOARD_ID_VEXPRESS) {
+            /* reserved: RAZ/WI */
+            break;
+        }
+        if (s->lockval == LOCK_VALUE) {
+            s->resetlevel = val;
+            if (val & 0x100)
+                qemu_system_reset_request ();
+        }
+        break;
+    case 0x44: /* PCICTL */
+        /* nothing to do.  */
+        break;
+    case 0x4c: /* FLASH */
+    case 0x50: /* CLCD */
+    case 0x54: /* CLCDSER */
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x84: /* PROCID0 */
+    case 0x88: /* PROCID1 */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+        break;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgdata = val;
+        return;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgctrl = val & ~(3 << 18);
+        s->sys_cfgstat = 1;            /* complete */
+        switch (s->sys_cfgctrl) {
+        case 0xc0800000:            /* SYS_CFG_SHUTDOWN to motherboard */
+            qemu_system_shutdown_request();
+            break;
+        case 0xc0900000:            /* SYS_CFG_REBOOT to motherboard */
+            qemu_system_reset_request();
+            break;
+        default:
+            s->sys_cfgstat |= 2;        /* error */
+        }
+        return;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgstat = val & 3;
+        return;
+    default:
+    bad_reg:
+        printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const arm_sysctl_readfn[] = {
+   arm_sysctl_read,
+   arm_sysctl_read,
+   arm_sysctl_read
+};
+
+static CPUWriteMemoryFunc * const arm_sysctl_writefn[] = {
+   arm_sysctl_write,
+   arm_sysctl_write,
+   arm_sysctl_write
+};
+
+static void arm_sysctl_gpio_set(void *opaque, int line, int level)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+    switch (line) {
+    case ARM_SYSCTL_GPIO_MMC_WPROT:
+    {
+        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
+         * for all later boards it is bit 1.
+         */
+        int bit = 2;
+        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
+            bit = 4;
+        }
+        s->sys_mci &= ~bit;
+        if (level) {
+            s->sys_mci |= bit;
+        }
+        break;
+    }
+    case ARM_SYSCTL_GPIO_MMC_CARDIN:
+        s->sys_mci &= ~1;
+        if (level) {
+            s->sys_mci |= 1;
+        }
+        break;
+    }
+}
+
+static int arm_sysctl_init1(SysBusDevice *dev)
+{
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(arm_sysctl_readfn,
+                                       arm_sysctl_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+/* Legacy helper function.  */
+void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(dev, "sys_id", sys_id);
+    qdev_init_nofail(dev);
+    qdev_prop_set_uint32(dev, "proc_id", proc_id);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+}
+
+static SysBusDeviceInfo arm_sysctl_info = {
+    .init = arm_sysctl_init1,
+    .qdev.name  = "realview_sysctl",
+    .qdev.size  = sizeof(arm_sysctl_state),
+    .qdev.vmsd = &vmstate_arm_sysctl,
+    .qdev.reset = arm_sysctl_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
+        DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void arm_sysctl_register_devices(void)
+{
+    sysbus_register_withprop(&arm_sysctl_info);
+}
+
+device_init(arm_sysctl_register_devices)
diff --git a/qemu-0.15.x/hw/arm_timer.c b/qemu-0.15.x/hw/arm_timer.c
new file mode 100644
index 0000000..fd9448f
--- /dev/null
+++ b/qemu-0.15.x/hw/arm_timer.c
@@ -0,0 +1,341 @@
+/*
+ * ARM PrimeCell Timer modules.
+ *
+ * Copyright (c) 2005-2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* Common timer implementation.  */
+
+#define TIMER_CTRL_ONESHOT      (1 << 0)
+#define TIMER_CTRL_32BIT        (1 << 1)
+#define TIMER_CTRL_DIV1         (0 << 2)
+#define TIMER_CTRL_DIV16        (1 << 2)
+#define TIMER_CTRL_DIV256       (2 << 2)
+#define TIMER_CTRL_IE           (1 << 5)
+#define TIMER_CTRL_PERIODIC     (1 << 6)
+#define TIMER_CTRL_ENABLE       (1 << 7)
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t control;
+    uint32_t limit;
+    int freq;
+    int int_level;
+    qemu_irq irq;
+} arm_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt.  */
+
+static void arm_timer_update(arm_timer_state *s)
+{
+    /* Update interrupts.  */
+    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* TimerLoad */
+    case 6: /* TimerBGLoad */
+        return s->limit;
+    case 1: /* TimerValue */
+        return ptimer_get_count(s->timer);
+    case 2: /* TimerControl */
+        return s->control;
+    case 4: /* TimerRIS */
+        return s->int_level;
+    case 5: /* TimerMIS */
+        if ((s->control & TIMER_CTRL_IE) == 0)
+            return 0;
+        return s->int_level;
+    default:
+        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+/* Reset the timer limit after settings have changed.  */
+static void arm_timer_recalibrate(arm_timer_state *s, int reload)
+{
+    uint32_t limit;
+
+    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
+        /* Free running.  */
+        if (s->control & TIMER_CTRL_32BIT)
+            limit = 0xffffffff;
+        else
+            limit = 0xffff;
+    } else {
+          /* Periodic.  */
+          limit = s->limit;
+    }
+    ptimer_set_limit(s->timer, limit, reload);
+}
+
+static void arm_timer_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case 0: /* TimerLoad */
+        s->limit = value;
+        arm_timer_recalibrate(s, 1);
+        break;
+    case 1: /* TimerValue */
+        /* ??? Linux seems to want to write to this readonly register.
+           Ignore it.  */
+        break;
+    case 2: /* TimerControl */
+        if (s->control & TIMER_CTRL_ENABLE) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        s->control = value;
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch ((value >> 2) & 3) {
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 8; break;
+        }
+        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
+        ptimer_set_freq(s->timer, freq);
+        if (s->control & TIMER_CTRL_ENABLE) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
+        }
+        break;
+    case 3: /* TimerIntClr */
+        s->int_level = 0;
+        break;
+    case 6: /* TimerBGLoad */
+        s->limit = value;
+        arm_timer_recalibrate(s, 0);
+        break;
+    default:
+        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
+    }
+    arm_timer_update(s);
+}
+
+static void arm_timer_tick(void *opaque)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+    s->int_level = 1;
+    arm_timer_update(s);
+}
+
+static const VMStateDescription vmstate_arm_timer = {
+    .name = "arm_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(control, arm_timer_state),
+        VMSTATE_UINT32(limit, arm_timer_state),
+        VMSTATE_INT32(int_level, arm_timer_state),
+        VMSTATE_PTIMER(timer, arm_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static arm_timer_state *arm_timer_init(uint32_t freq)
+{
+    arm_timer_state *s;
+    QEMUBH *bh;
+
+    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
+    s->freq = freq;
+    s->control = TIMER_CTRL_IE;
+
+    bh = qemu_bh_new(arm_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
+    return s;
+}
+
+/* ARM PrimeCell SP804 dual timer module.
+   Docs for this device don't seem to be publicly available.  This
+   implementation is based on guesswork, the linux kernel sources and the
+   Integrator/CP timer modules.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    arm_timer_state *timer[2];
+    int level[2];
+    qemu_irq irq;
+} sp804_state;
+
+/* Merge the IRQs from the two component devices.  */
+static void sp804_set_irq(void *opaque, int irq, int level)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    s->level[irq] = level;
+    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
+}
+
+static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    /* ??? Don't know the PrimeCell ID for this device.  */
+    if (offset < 0x20) {
+        return arm_timer_read(s->timer[0], offset);
+    } else {
+        return arm_timer_read(s->timer[1], offset - 0x20);
+    }
+}
+
+static void sp804_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    if (offset < 0x20) {
+        arm_timer_write(s->timer[0], offset, value);
+    } else {
+        arm_timer_write(s->timer[1], offset - 0x20, value);
+    }
+}
+
+static CPUReadMemoryFunc * const sp804_readfn[] = {
+   sp804_read,
+   sp804_read,
+   sp804_read
+};
+
+static CPUWriteMemoryFunc * const sp804_writefn[] = {
+   sp804_write,
+   sp804_write,
+   sp804_write
+};
+
+
+static const VMStateDescription vmstate_sp804 = {
+    .name = "sp804",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int sp804_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
+    qemu_irq *qi;
+
+    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
+    sysbus_init_irq(dev, &s->irq);
+    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
+       we don't implement that.  */
+    s->timer[0] = arm_timer_init(1000000);
+    s->timer[1] = arm_timer_init(1000000);
+    s->timer[0]->irq = qi[0];
+    s->timer[1]->irq = qi[1];
+    iomemtype = cpu_register_io_memory(sp804_readfn,
+                                       sp804_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
+    return 0;
+}
+
+
+/* Integrator/CP timer module.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    arm_timer_state *timer[3];
+} icp_pit_state;
+
+static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
+{
+    icp_pit_state *s = (icp_pit_state *)opaque;
+    int n;
+
+    /* ??? Don't know the PrimeCell ID for this device.  */
+    n = offset >> 8;
+    if (n > 3) {
+        hw_error("sp804_read: Bad timer %d\n", n);
+    }
+
+    return arm_timer_read(s->timer[n], offset & 0xff);
+}
+
+static void icp_pit_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_pit_state *s = (icp_pit_state *)opaque;
+    int n;
+
+    n = offset >> 8;
+    if (n > 3) {
+        hw_error("sp804_write: Bad timer %d\n", n);
+    }
+
+    arm_timer_write(s->timer[n], offset & 0xff, value);
+}
+
+
+static CPUReadMemoryFunc * const icp_pit_readfn[] = {
+   icp_pit_read,
+   icp_pit_read,
+   icp_pit_read
+};
+
+static CPUWriteMemoryFunc * const icp_pit_writefn[] = {
+   icp_pit_write,
+   icp_pit_write,
+   icp_pit_write
+};
+
+static int icp_pit_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
+
+    /* Timer 0 runs at the system clock speed (40MHz).  */
+    s->timer[0] = arm_timer_init(40000000);
+    /* The other two timers run at 1MHz.  */
+    s->timer[1] = arm_timer_init(1000000);
+    s->timer[2] = arm_timer_init(1000000);
+
+    sysbus_init_irq(dev, &s->timer[0]->irq);
+    sysbus_init_irq(dev, &s->timer[1]->irq);
+    sysbus_init_irq(dev, &s->timer[2]->irq);
+
+    iomemtype = cpu_register_io_memory(icp_pit_readfn,
+                                       icp_pit_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    /* This device has no state to save/restore.  The component timers will
+       save themselves.  */
+    return 0;
+}
+
+static void arm_timer_register_devices(void)
+{
+    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
+    sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
+}
+
+device_init(arm_timer_register_devices)
diff --git a/qemu-0.15.x/hw/armv7m.c b/qemu-0.15.x/hw/armv7m.c
new file mode 100644
index 0000000..83f3393
--- /dev/null
+++ b/qemu-0.15.x/hw/armv7m.c
@@ -0,0 +1,262 @@
+/*
+ * ARMV7M System emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "loader.h"
+#include "elf.h"
+
+/* Bitbanded IO.  Each word corresponds to a single bit.  */
+
+/* Get the byte address of the real memory for a bitband access.  */
+static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
+{
+    uint32_t res;
+
+    res = *(uint32_t *)opaque;
+    res |= (addr & 0x1ffffff) >> 5;
+    return res;
+
+}
+
+static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
+{
+    uint8_t v;
+    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
+    return (v & (1 << ((offset >> 2) & 7))) != 0;
+}
+
+static void bitband_writeb(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    uint32_t addr;
+    uint8_t mask;
+    uint8_t v;
+    addr = bitband_addr(opaque, offset);
+    mask = (1 << ((offset >> 2) & 7));
+    cpu_physical_memory_read(addr, &v, 1);
+    if (value & 1)
+        v |= mask;
+    else
+        v &= ~mask;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+
+static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t addr;
+    uint16_t mask;
+    uint16_t v;
+    addr = bitband_addr(opaque, offset) & ~1;
+    mask = (1 << ((offset >> 2) & 15));
+    mask = tswap16(mask);
+    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
+    return (v & mask) != 0;
+}
+
+static void bitband_writew(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    uint32_t addr;
+    uint16_t mask;
+    uint16_t v;
+    addr = bitband_addr(opaque, offset) & ~1;
+    mask = (1 << ((offset >> 2) & 15));
+    mask = tswap16(mask);
+    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
+    if (value & 1)
+        v |= mask;
+    else
+        v &= ~mask;
+    cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
+}
+
+static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t addr;
+    uint32_t mask;
+    uint32_t v;
+    addr = bitband_addr(opaque, offset) & ~3;
+    mask = (1 << ((offset >> 2) & 31));
+    mask = tswap32(mask);
+    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
+    return (v & mask) != 0;
+}
+
+static void bitband_writel(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    uint32_t addr;
+    uint32_t mask;
+    uint32_t v;
+    addr = bitband_addr(opaque, offset) & ~3;
+    mask = (1 << ((offset >> 2) & 31));
+    mask = tswap32(mask);
+    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
+    if (value & 1)
+        v |= mask;
+    else
+        v &= ~mask;
+    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
+}
+
+static CPUReadMemoryFunc * const bitband_readfn[] = {
+   bitband_readb,
+   bitband_readw,
+   bitband_readl
+};
+
+static CPUWriteMemoryFunc * const bitband_writefn[] = {
+   bitband_writeb,
+   bitband_writew,
+   bitband_writel
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t base;
+} BitBandState;
+
+static int bitband_init(SysBusDevice *dev)
+{
+    BitBandState *s = FROM_SYSBUS(BitBandState, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
+                                       &s->base, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x02000000, iomemtype);
+    return 0;
+}
+
+static void armv7m_bitband_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "ARM,bitband-memory");
+    qdev_prop_set_uint32(dev, "base", 0x20000000);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
+
+    dev = qdev_create(NULL, "ARM,bitband-memory");
+    qdev_prop_set_uint32(dev, "base", 0x40000000);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
+}
+
+/* Board init.  */
+
+static void armv7m_reset(void *opaque)
+{
+    cpu_reset((CPUState *)opaque);
+}
+
+/* Init CPU and memory for a v7-M based board.
+   flash_size and sram_size are in kb.
+   Returns the NVIC array.  */
+
+qemu_irq *armv7m_init(int flash_size, int sram_size,
+                      const char *kernel_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DeviceState *nvic;
+    /* FIXME: make this local state.  */
+    static qemu_irq pic[64];
+    qemu_irq *cpu_pic;
+    int image_size;
+    uint64_t entry;
+    uint64_t lowaddr;
+    int i;
+    int big_endian;
+
+    flash_size *= 1024;
+    sram_size *= 1024;
+
+    if (!cpu_model)
+	cpu_model = "cortex-m3";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+#if 0
+    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
+       We don't have proper commandline options, so allocate half of memory
+       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
+    if (ram_size > (512 + 32) * 1024 * 1024)
+        ram_size = (512 + 32) * 1024 * 1024;
+    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
+    if (sram_size > 32 * 1024 * 1024)
+        sram_size = 32 * 1024 * 1024;
+    code_size = ram_size - sram_size;
+#endif
+
+    /* Flash programming is done via the SCU, so pretend it is ROM.  */
+    cpu_register_physical_memory(0, flash_size,
+                                 qemu_ram_alloc(NULL, "armv7m.flash",
+                                                flash_size) | IO_MEM_ROM);
+    cpu_register_physical_memory(0x20000000, sram_size,
+                                 qemu_ram_alloc(NULL, "armv7m.sram",
+                                                sram_size) | IO_MEM_RAM);
+    armv7m_bitband_init();
+
+    nvic = qdev_create(NULL, "armv7m_nvic");
+    env->nvic = nvic;
+    qdev_init_nofail(nvic);
+    cpu_pic = arm_pic_init_cpu(env);
+    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
+    for (i = 0; i < 64; i++) {
+        pic[i] = qdev_get_gpio_in(nvic, i);
+    }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
+                          NULL, big_endian, ELF_MACHINE, 1);
+    if (image_size < 0) {
+        image_size = load_image_targphys(kernel_filename, 0, flash_size);
+	lowaddr = 0;
+    }
+    if (image_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                kernel_filename);
+        exit(1);
+    }
+
+    /* Hack to map an additional page of ram at the top of the address
+       space.  This stops qemu complaining about executing code outside RAM
+       when returning from an exception.  */
+    cpu_register_physical_memory(0xfffff000, 0x1000,
+                                 qemu_ram_alloc(NULL, "armv7m.hack", 
+                                                0x1000) | IO_MEM_RAM);
+
+    qemu_register_reset(armv7m_reset, env);
+    return pic;
+}
+
+static SysBusDeviceInfo bitband_info = {
+    .init = bitband_init,
+    .qdev.name  = "ARM,bitband-memory",
+    .qdev.size  = sizeof(BitBandState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", BitBandState, base, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void armv7m_register_devices(void)
+{
+    sysbus_register_withprop(&bitband_info);
+}
+
+device_init(armv7m_register_devices)
diff --git a/qemu-0.15.x/hw/armv7m_nvic.c b/qemu-0.15.x/hw/armv7m_nvic.c
new file mode 100644
index 0000000..1df8d4d
--- /dev/null
+++ b/qemu-0.15.x/hw/armv7m_nvic.c
@@ -0,0 +1,398 @@
+/*
+ * ARM Nested Vectored Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ *
+ * The ARMv7M System controller is fairly tightly tied in with the
+ * NVIC.  Much of that is also implemented here.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+#include "arm-misc.h"
+
+/* 32 internal lines (16 used for system exceptions) plus 64 external
+   interrupt lines.  */
+#define GIC_NIRQ 96
+#define NCPU 1
+#define NVIC 1
+
+/* Only a single "CPU" interface is present.  */
+static inline int
+gic_get_current_cpu(void)
+{
+    return 0;
+}
+
+static uint32_t nvic_readl(void *opaque, uint32_t offset);
+static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
+
+#include "arm_gic.c"
+
+typedef struct {
+    gic_state gic;
+    struct {
+        uint32_t control;
+        uint32_t reload;
+        int64_t tick;
+        QEMUTimer *timer;
+    } systick;
+} nvic_state;
+
+/* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
+#define SYSTICK_SCALE 1000ULL
+
+#define SYSTICK_ENABLE    (1 << 0)
+#define SYSTICK_TICKINT   (1 << 1)
+#define SYSTICK_CLKSOURCE (1 << 2)
+#define SYSTICK_COUNTFLAG (1 << 16)
+
+int system_clock_scale;
+
+/* Conversion factor from qemu timer to SysTick frequencies.  */
+static inline int64_t systick_scale(nvic_state *s)
+{
+    if (s->systick.control & SYSTICK_CLKSOURCE)
+        return system_clock_scale;
+    else
+        return 1000;
+}
+
+static void systick_reload(nvic_state *s, int reset)
+{
+    if (reset)
+        s->systick.tick = qemu_get_clock_ns(vm_clock);
+    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
+    qemu_mod_timer(s->systick.timer, s->systick.tick);
+}
+
+static void systick_timer_tick(void * opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    s->systick.control |= SYSTICK_COUNTFLAG;
+    if (s->systick.control & SYSTICK_TICKINT) {
+        /* Trigger the interrupt.  */
+        armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+    }
+    if (s->systick.reload == 0) {
+        s->systick.control &= ~SYSTICK_ENABLE;
+    } else {
+        systick_reload(s, 0);
+    }
+}
+
+/* The external routines use the hardware vector numbering, ie. the first
+   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
+void armv7m_nvic_set_pending(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_set_pending_private(&s->gic, 0, irq);
+}
+
+/* Make pending IRQ active.  */
+int armv7m_nvic_acknowledge_irq(void *opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t irq;
+
+    irq = gic_acknowledge_irq(&s->gic, 0);
+    if (irq == 1023)
+        hw_error("Interrupt but no vector\n");
+    if (irq >= 32)
+        irq -= 16;
+    return irq;
+}
+
+void armv7m_nvic_complete_irq(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_complete_irq(&s->gic, 0, irq);
+}
+
+static uint32_t nvic_readl(void *opaque, uint32_t offset)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t val;
+    int irq;
+
+    switch (offset) {
+    case 4: /* Interrupt Control Type.  */
+        return (GIC_NIRQ / 32) - 1;
+    case 0x10: /* SysTick Control and Status.  */
+        val = s->systick.control;
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        return val;
+    case 0x14: /* SysTick Reload Value.  */
+        return s->systick.reload;
+    case 0x18: /* SysTick Current Value.  */
+        {
+            int64_t t;
+            if ((s->systick.control & SYSTICK_ENABLE) == 0)
+                return 0;
+            t = qemu_get_clock_ns(vm_clock);
+            if (t >= s->systick.tick)
+                return 0;
+            val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
+            /* The interrupt in triggered when the timer reaches zero.
+               However the counter is not reloaded until the next clock
+               tick.  This is a hack to return zero during the first tick.  */
+            if (val > s->systick.reload)
+                val = 0;
+            return val;
+        }
+    case 0x1c: /* SysTick Calibration Value.  */
+        return 10000;
+    case 0xd00: /* CPUID Base.  */
+        return cpu_single_env->cp15.c0_cpuid;
+    case 0xd04: /* Interrypt Control State.  */
+        /* VECTACTIVE */
+        val = s->gic.running_irq[0];
+        if (val == 1023) {
+            val = 0;
+        } else if (val >= 32) {
+            val -= 16;
+        }
+        /* RETTOBASE */
+        if (s->gic.running_irq[0] == 1023
+                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
+            val |= (1 << 11);
+        }
+        /* VECTPENDING */
+        if (s->gic.current_pending[0] != 1023)
+            val |= (s->gic.current_pending[0] << 12);
+        /* ISRPENDING */
+        for (irq = 32; irq < GIC_NIRQ; irq++) {
+            if (s->gic.irq_state[irq].pending) {
+                val |= (1 << 22);
+                break;
+            }
+        }
+        /* PENDSTSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
+            val |= (1 << 26);
+        /* PENDSVSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
+            val |= (1 << 28);
+        /* NMIPENDSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
+            val |= (1 << 31);
+        return val;
+    case 0xd08: /* Vector Table Offset.  */
+        return cpu_single_env->v7m.vecbase;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        return 0xfa05000;
+    case 0xd10: /* System Control.  */
+        /* TODO: Implement SLEEPONEXIT.  */
+        return 0;
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement Configuration Control bits.  */
+        return 0;
+    case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
+        irq = offset - 0xd14;
+        val = 0;
+        val |= s->gic.priority1[irq++][0];
+        val |= s->gic.priority1[irq++][0] << 8;
+        val |= s->gic.priority1[irq++][0] << 16;
+        val |= s->gic.priority1[irq][0] << 24;
+        return val;
+    case 0xd24: /* System Handler Status.  */
+        val = 0;
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+        return val;
+    case 0xd28: /* Configurable Fault Status.  */
+        /* TODO: Implement Fault Status.  */
+        hw_error("Not implemented: Configurable Fault Status.");
+        return 0;
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        /* TODO: Implement fault status registers.  */
+        goto bad_reg;
+    case 0xd40: /* PFR0.  */
+        return 0x00000030;
+    case 0xd44: /* PRF1.  */
+        return 0x00000200;
+    case 0xd48: /* DFR0.  */
+        return 0x00100000;
+    case 0xd4c: /* AFR0.  */
+        return 0x00000000;
+    case 0xd50: /* MMFR0.  */
+        return 0x00000030;
+    case 0xd54: /* MMFR1.  */
+        return 0x00000000;
+    case 0xd58: /* MMFR2.  */
+        return 0x00000000;
+    case 0xd5c: /* MMFR3.  */
+        return 0x00000000;
+    case 0xd60: /* ISAR0.  */
+        return 0x01141110;
+    case 0xd64: /* ISAR1.  */
+        return 0x02111000;
+    case 0xd68: /* ISAR2.  */
+        return 0x21112231;
+    case 0xd6c: /* ISAR3.  */
+        return 0x01111110;
+    case 0xd70: /* ISAR4.  */
+        return 0x01310102;
+    /* TODO: Implement debug registers.  */
+    default:
+    bad_reg:
+        hw_error("NVIC: Bad read offset 0x%x\n", offset);
+    }
+}
+
+static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t oldval;
+    switch (offset) {
+    case 0x10: /* SysTick Control and Status.  */
+        oldval = s->systick.control;
+        s->systick.control &= 0xfffffff8;
+        s->systick.control |= value & 7;
+        if ((oldval ^ value) & SYSTICK_ENABLE) {
+            int64_t now = qemu_get_clock_ns(vm_clock);
+            if (value & SYSTICK_ENABLE) {
+                if (s->systick.tick) {
+                    s->systick.tick += now;
+                    qemu_mod_timer(s->systick.timer, s->systick.tick);
+                } else {
+                    systick_reload(s, 1);
+                }
+            } else {
+                qemu_del_timer(s->systick.timer);
+                s->systick.tick -= now;
+                if (s->systick.tick < 0)
+                  s->systick.tick = 0;
+            }
+        } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
+            /* This is a hack. Force the timer to be reloaded
+               when the reference clock is changed.  */
+            systick_reload(s, 1);
+        }
+        break;
+    case 0x14: /* SysTick Reload Value.  */
+        s->systick.reload = value;
+        break;
+    case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
+        systick_reload(s, 1);
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        break;
+    case 0xd04: /* Interrupt Control State.  */
+        if (value & (1 << 31)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
+        }
+        if (value & (1 << 28)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
+        } else if (value & (1 << 27)) {
+            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+            gic_update(&s->gic);
+        }
+        if (value & (1 << 26)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+        } else if (value & (1 << 25)) {
+            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+            gic_update(&s->gic);
+        }
+        break;
+    case 0xd08: /* Vector Table Offset.  */
+        cpu_single_env->v7m.vecbase = value & 0xffffff80;
+        break;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        if ((value >> 16) == 0x05fa) {
+            if (value & 2) {
+                hw_error("VECTCLRACTIVE not implemented");
+            }
+            if (value & 5) {
+                hw_error("System reset");
+            }
+        }
+        break;
+    case 0xd10: /* System Control.  */
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement control registers.  */
+        goto bad_reg;
+    case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
+        {
+            int irq;
+            irq = offset - 0xd14;
+            s->gic.priority1[irq++][0] = value & 0xff;
+            s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
+            s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
+            s->gic.priority1[irq][0] = (value >> 24) & 0xff;
+            gic_update(&s->gic);
+        }
+        break;
+    case 0xd24: /* System Handler Control.  */
+        /* TODO: Real hardware allows you to set/clear the active bits
+           under some circumstances.  We don't implement this.  */
+        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        break;
+    case 0xd28: /* Configurable Fault Status.  */
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        goto bad_reg;
+    default:
+    bad_reg:
+        hw_error("NVIC: Bad write offset 0x%x\n", offset);
+    }
+}
+
+static const VMStateDescription vmstate_nvic = {
+    .name = "armv7m_nvic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(systick.control, nvic_state),
+        VMSTATE_UINT32(systick.reload, nvic_state),
+        VMSTATE_INT64(systick.tick, nvic_state),
+        VMSTATE_TIMER(systick.timer, nvic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int armv7m_nvic_init(SysBusDevice *dev)
+{
+    nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
+
+    gic_init(&s->gic);
+    cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
+    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
+    return 0;
+}
+
+static void armv7m_nvic_register_devices(void)
+{
+    sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+}
+
+device_init(armv7m_nvic_register_devices)
diff --git a/qemu-0.15.x/hw/audiodev.h b/qemu-0.15.x/hw/audiodev.h
new file mode 100644
index 0000000..8e930b2
--- /dev/null
+++ b/qemu-0.15.x/hw/audiodev.h
@@ -0,0 +1,20 @@
+/* es1370.c */
+int es1370_init(PCIBus *bus);
+
+/* sb16.c */
+int SB16_init(qemu_irq *pic);
+
+/* adlib.c */
+int Adlib_init(qemu_irq *pic);
+
+/* gus.c */
+int GUS_init(qemu_irq *pic);
+
+/* ac97.c */
+int ac97_init(PCIBus *buf);
+
+/* cs4231a.c */
+int cs4231a_init(qemu_irq *pic);
+
+/* intel-hda.c + hda-audio.c */
+int intel_hda_and_codec_init(PCIBus *bus);
diff --git a/qemu-0.15.x/hw/axis_dev88.c b/qemu-0.15.x/hw/axis_dev88.c
new file mode 100644
index 0000000..0e2135a
--- /dev/null
+++ b/qemu-0.15.x/hw/axis_dev88.c
@@ -0,0 +1,356 @@
+/*
+ * QEMU model for the AXIS devboard 88.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "sysbus.h"
+#include "net.h"
+#include "flash.h"
+#include "boards.h"
+#include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
+#include "cris-boot.h"
+
+#define D(x)
+#define DNAND(x)
+
+struct nand_state_t
+{
+    NANDFlashState *nand;
+    unsigned int rdy:1;
+    unsigned int ale:1;
+    unsigned int cle:1;
+    unsigned int ce:1;
+};
+
+static struct nand_state_t nand_state;
+static uint32_t nand_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct nand_state_t *s = opaque;
+    uint32_t r;
+    int rdy;
+
+    r = nand_getio(s->nand);
+    nand_getpins(s->nand, &rdy);
+    s->rdy = rdy;
+
+    DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
+    return r;
+}
+
+static void
+nand_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct nand_state_t *s = opaque;
+    int rdy;
+
+    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, value));
+    nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
+    nand_setio(s->nand, value);
+    nand_getpins(s->nand, &rdy);
+    s->rdy = rdy;
+}
+
+static CPUReadMemoryFunc * const nand_read[] = {
+    &nand_readl,
+    &nand_readl,
+    &nand_readl,
+};
+
+static CPUWriteMemoryFunc * const nand_write[] = {
+    &nand_writel,
+    &nand_writel,
+    &nand_writel,
+};
+
+
+struct tempsensor_t
+{
+    unsigned int shiftreg;
+    unsigned int count;
+    enum {
+        ST_OUT, ST_IN, ST_Z
+    } state;
+
+    uint16_t regs[3];
+};
+
+static void tempsensor_clkedge(struct tempsensor_t *s,
+                               unsigned int clk, unsigned int data_in)
+{
+    D(printf("%s clk=%d state=%d sr=%x\n", __func__,
+             clk, s->state, s->shiftreg));
+    if (s->count == 0) {
+        s->count = 16;
+        s->state = ST_OUT;
+    }
+    switch (s->state) {
+        case ST_OUT:
+            /* Output reg is clocked at negedge.  */
+            if (!clk) {
+                s->count--;
+                s->shiftreg <<= 1;
+                if (s->count == 0) {
+                    s->shiftreg = 0;
+                    s->state = ST_IN;
+                    s->count = 16;
+                }
+            }
+            break;
+        case ST_Z:
+            if (clk) {
+                s->count--;
+                if (s->count == 0) {
+                    s->shiftreg = 0;
+                    s->state = ST_OUT;
+                    s->count = 16;
+                }
+            }
+            break;
+        case ST_IN:
+            /* Indata is sampled at posedge.  */
+            if (clk) {
+                s->count--;
+                s->shiftreg <<= 1;
+                s->shiftreg |= data_in & 1;
+                if (s->count == 0) {
+                    D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
+                    s->regs[0] = s->shiftreg;
+                    s->state = ST_OUT;
+                    s->count = 16;
+
+                    if ((s->regs[0] & 0xff) == 0) {
+                        /* 25 degrees celcius.  */
+                        s->shiftreg = 0x0b9f;
+                    } else if ((s->regs[0] & 0xff) == 0xff) {
+                        /* Sensor ID, 0x8100 LM70.  */
+                        s->shiftreg = 0x8100;
+                    } else
+                        printf("Invalid tempsens state %x\n", s->regs[0]);
+                }
+            }
+            break;
+    }
+}
+
+
+#define RW_PA_DOUT    0x00
+#define R_PA_DIN      0x01
+#define RW_PA_OE      0x02
+#define RW_PD_DOUT    0x10
+#define R_PD_DIN      0x11
+#define RW_PD_OE      0x12
+
+static struct gpio_state_t
+{
+    struct nand_state_t *nand;
+    struct tempsensor_t tempsensor;
+    uint32_t regs[0x5c / 4];
+} gpio_state;
+
+static uint32_t gpio_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct gpio_state_t *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_PA_DIN:
+            r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
+
+            /* Encode pins from the nand.  */
+            r |= s->nand->rdy << 7;
+            break;
+        case R_PD_DIN:
+            r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
+
+            /* Encode temp sensor pins.  */
+            r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
+            break;
+
+        default:
+            r = s->regs[addr];
+            break;
+    }
+    return r;
+    D(printf("%s %x=%x\n", __func__, addr, r));
+}
+
+static void gpio_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct gpio_state_t *s = opaque;
+    D(printf("%s %x=%x\n", __func__, addr, value));
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case RW_PA_DOUT:
+            /* Decode nand pins.  */
+            s->nand->ale = !!(value & (1 << 6));
+            s->nand->cle = !!(value & (1 << 5));
+            s->nand->ce  = !!(value & (1 << 4));
+
+            s->regs[addr] = value;
+            break;
+
+        case RW_PD_DOUT:
+            /* Temp sensor clk.  */
+            if ((s->regs[addr] ^ value) & 2)
+                tempsensor_clkedge(&s->tempsensor, !!(value & 2),
+                                   !!(value & 16));
+            s->regs[addr] = value;
+            break;
+
+        default:
+            s->regs[addr] = value;
+            break;
+    }
+}
+
+static CPUReadMemoryFunc * const gpio_read[] = {
+    NULL, NULL,
+    &gpio_readl,
+};
+
+static CPUWriteMemoryFunc * const gpio_write[] = {
+    NULL, NULL,
+    &gpio_writel,
+};
+
+#define INTMEM_SIZE (128 * 1024)
+
+static struct cris_load_info li;
+
+static
+void axisdev88_init (ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DeviceState *dev;
+    SysBusDevice *s;
+    qemu_irq irq[30], nmi[2], *cpu_irq;
+    void *etraxfs_dmac;
+    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
+    int i;
+    int nand_regs;
+    int gpio_regs;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_intmem;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "crisv32";
+    }
+    env = cpu_init(cpu_model);
+
+    /* allocate RAM */
+    phys_ram = qemu_ram_alloc(NULL, "axisdev88.ram", ram_size);
+    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
+
+    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
+       internal memory.  */
+    phys_intmem = qemu_ram_alloc(NULL, "axisdev88.chipram", INTMEM_SIZE);
+    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
+                                 phys_intmem | IO_MEM_RAM);
+
+
+      /* Attach a NAND flash to CS1.  */
+    nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+    nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
+
+    gpio_state.nand = &nand_state;
+    gpio_regs = cpu_register_io_memory(gpio_read, gpio_write, &gpio_state,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x3001a000, 0x5c, gpio_regs);
+
+
+    cpu_irq = cris_pic_init_cpu(env);
+    dev = qdev_create(NULL, "etraxfs,pic");
+    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
+    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, 0x3001c000);
+    sysbus_connect_irq(s, 0, cpu_irq[0]);
+    sysbus_connect_irq(s, 1, cpu_irq[1]);
+    for (i = 0; i < 30; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+    nmi[0] = qdev_get_gpio_in(dev, 30);
+    nmi[1] = qdev_get_gpio_in(dev, 31);
+
+    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
+    for (i = 0; i < 10; i++) {
+        /* On ETRAX, odd numbered channels are inputs.  */
+        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
+    }
+
+    /* Add the two ethernet blocks.  */
+    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
+    if (nb_nics > 1)
+        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
+
+    /* The DMA Connector block is missing, hardwire things for now.  */
+    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
+    if (eth[1]) {
+        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
+        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+    }
+
+    /* 2 timers.  */
+    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
+    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
+
+    for (i = 0; i < 4; i++) {
+        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
+                             irq[0x14 + i]);
+    }
+
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    li.image_filename = kernel_filename;
+    li.cmdline = kernel_cmdline;
+    cris_load_image(env, &li);
+}
+
+static QEMUMachine axisdev88_machine = {
+    .name = "axis-dev88",
+    .desc = "AXIS devboard 88",
+    .init = axisdev88_init,
+};
+
+static void axisdev88_machine_init(void)
+{
+    qemu_register_machine(&axisdev88_machine);
+}
+
+machine_init(axisdev88_machine_init);
diff --git a/qemu-0.15.x/hw/baum.c b/qemu-0.15.x/hw/baum.c
new file mode 100644
index 0000000..33a22a7
--- /dev/null
+++ b/qemu-0.15.x/hw/baum.c
@@ -0,0 +1,643 @@
+/*
+ * QEMU Baum Braille Device
+ *
+ * Copyright (c) 2008 Samuel Thibault
+ *
+ * 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 "qemu-common.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "baum.h"
+#include <brlapi.h>
+#include <brlapi_constants.h>
+#include <brlapi_keycodes.h>
+#ifdef CONFIG_SDL
+#include <SDL_syswm.h>
+#endif
+
+#if 0
+#define DPRINTF(fmt, ...) \
+        printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define ESC 0x1B
+
+#define BAUM_REQ_DisplayData		0x01
+#define BAUM_REQ_GetVersionNumber	0x05
+#define BAUM_REQ_GetKeys		0x08
+#define BAUM_REQ_SetMode		0x12
+#define BAUM_REQ_SetProtocol		0x15
+#define BAUM_REQ_GetDeviceIdentity	0x84
+#define BAUM_REQ_GetSerialNumber	0x8A
+
+#define BAUM_RSP_CellCount		0x01
+#define BAUM_RSP_VersionNumber		0x05
+#define BAUM_RSP_ModeSetting		0x11
+#define BAUM_RSP_CommunicationChannel	0x16
+#define BAUM_RSP_PowerdownSignal	0x17
+#define BAUM_RSP_HorizontalSensors	0x20
+#define BAUM_RSP_VerticalSensors	0x21
+#define BAUM_RSP_RoutingKeys		0x22
+#define BAUM_RSP_Switches		0x23
+#define BAUM_RSP_TopKeys		0x24
+#define BAUM_RSP_HorizontalSensor	0x25
+#define BAUM_RSP_VerticalSensor		0x26
+#define BAUM_RSP_RoutingKey		0x27
+#define BAUM_RSP_FrontKeys6		0x28
+#define BAUM_RSP_BackKeys6		0x29
+#define BAUM_RSP_CommandKeys		0x2B
+#define BAUM_RSP_FrontKeys10		0x2C
+#define BAUM_RSP_BackKeys10		0x2D
+#define BAUM_RSP_EntryKeys		0x33
+#define BAUM_RSP_JoyStick		0x34
+#define BAUM_RSP_ErrorCode		0x40
+#define BAUM_RSP_InfoBlock		0x42
+#define BAUM_RSP_DeviceIdentity		0x84
+#define BAUM_RSP_SerialNumber		0x8A
+#define BAUM_RSP_BluetoothName		0x8C
+
+#define BAUM_TL1 0x01
+#define BAUM_TL2 0x02
+#define BAUM_TL3 0x04
+#define BAUM_TR1 0x08
+#define BAUM_TR2 0x10
+#define BAUM_TR3 0x20
+
+#define BUF_SIZE 256
+
+typedef struct {
+    CharDriverState *chr;
+
+    brlapi_handle_t *brlapi;
+    int brlapi_fd;
+    unsigned int x, y;
+
+    uint8_t in_buf[BUF_SIZE];
+    uint8_t in_buf_used;
+    uint8_t out_buf[BUF_SIZE];
+    uint8_t out_buf_used, out_buf_ptr;
+
+    QEMUTimer *cellCount_timer;
+} BaumDriverState;
+
+/* Let's assume NABCC by default */
+static const uint8_t nabcc_translation[256] = {
+    [0] = ' ',
+#ifndef BRLAPI_DOTS
+#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
+    ((d1?BRLAPI_DOT1:0)|\
+     (d2?BRLAPI_DOT2:0)|\
+     (d3?BRLAPI_DOT3:0)|\
+     (d4?BRLAPI_DOT4:0)|\
+     (d5?BRLAPI_DOT5:0)|\
+     (d6?BRLAPI_DOT6:0)|\
+     (d7?BRLAPI_DOT7:0)|\
+     (d8?BRLAPI_DOT8:0))
+#endif
+    [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a',
+    [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b',
+    [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c',
+    [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd',
+    [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e',
+    [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f',
+    [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g',
+    [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h',
+    [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i',
+    [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j',
+    [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k',
+    [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l',
+    [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm',
+    [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n',
+    [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o',
+    [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p',
+    [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q',
+    [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r',
+    [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's',
+    [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't',
+    [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u',
+    [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v',
+    [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w',
+    [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x',
+    [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y',
+    [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z',
+
+    [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A',
+    [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B',
+    [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C',
+    [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D',
+    [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E',
+    [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F',
+    [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G',
+    [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H',
+    [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I',
+    [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J',
+    [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K',
+    [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L',
+    [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M',
+    [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N',
+    [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O',
+    [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P',
+    [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q',
+    [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R',
+    [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S',
+    [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T',
+    [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U',
+    [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V',
+    [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W',
+    [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X',
+    [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y',
+    [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z',
+
+    [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0',
+    [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1',
+    [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2',
+    [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3',
+    [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4',
+    [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5',
+    [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6',
+    [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7',
+    [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8',
+    [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9',
+
+    [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.',
+    [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+',
+    [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-',
+    [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*',
+    [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/',
+    [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(',
+    [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')',
+
+    [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&',
+    [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#',
+
+    [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',',
+    [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';',
+    [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':',
+    [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!',
+    [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?',
+    [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"',
+    [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'',
+    [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`',
+    [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^',
+    [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~',
+    [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[',
+    [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']',
+    [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{',
+    [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}',
+    [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=',
+    [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<',
+    [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>',
+    [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$',
+    [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%',
+    [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@',
+    [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|',
+    [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\',
+    [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_',
+};
+
+/* The serial port can receive more of our data */
+static void baum_accept_input(struct CharDriverState *chr)
+{
+    BaumDriverState *baum = chr->opaque;
+    int room, first;
+
+    if (!baum->out_buf_used)
+        return;
+    room = qemu_chr_can_read(chr);
+    if (!room)
+        return;
+    if (room > baum->out_buf_used)
+        room = baum->out_buf_used;
+
+    first = BUF_SIZE - baum->out_buf_ptr;
+    if (room > first) {
+        qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first);
+        baum->out_buf_ptr = 0;
+        baum->out_buf_used -= first;
+        room -= first;
+    }
+    qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room);
+    baum->out_buf_ptr += room;
+    baum->out_buf_used -= room;
+}
+
+/* We want to send a packet */
+static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
+{
+    uint8_t io_buf[1 + 2 * len], *cur = io_buf;
+    int room;
+    *cur++ = ESC;
+    while (len--)
+        if ((*cur++ = *buf++) == ESC)
+            *cur++ = ESC;
+    room = qemu_chr_can_read(baum->chr);
+    len = cur - io_buf;
+    if (len <= room) {
+        /* Fits */
+        qemu_chr_read(baum->chr, io_buf, len);
+    } else {
+        int first;
+        uint8_t out;
+        /* Can't fit all, send what can be, and store the rest. */
+        qemu_chr_read(baum->chr, io_buf, room);
+        len -= room;
+        cur = io_buf + room;
+        if (len > BUF_SIZE - baum->out_buf_used) {
+            /* Can't even store it, drop the previous data... */
+            assert(len <= BUF_SIZE);
+            baum->out_buf_used = 0;
+            baum->out_buf_ptr = 0;
+        }
+        out = baum->out_buf_ptr;
+        baum->out_buf_used += len;
+        first = BUF_SIZE - baum->out_buf_ptr;
+        if (len > first) {
+            memcpy(baum->out_buf + out, cur, first);
+            out = 0;
+            len -= first;
+            cur += first;
+        }
+        memcpy(baum->out_buf + out, cur, len);
+    }
+}
+
+/* Called when the other end seems to have a wrong idea of our display size */
+static void baum_cellCount_timer_cb(void *opaque)
+{
+    BaumDriverState *baum = opaque;
+    uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
+    DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
+    baum_write_packet(baum, cell_count, sizeof(cell_count));
+}
+
+/* Try to interpret a whole incoming packet */
+static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
+{
+    const uint8_t *cur = buf;
+    uint8_t req = 0;
+
+    if (!len--)
+        return 0;
+    if (*cur++ != ESC) {
+        while (*cur != ESC) {
+            if (!len--)
+                return 0;
+            cur++;
+        }
+        DPRINTF("Dropped %d bytes!\n", cur - buf);
+    }
+
+#define EAT(c) do {\
+    if (!len--) \
+        return 0; \
+    if ((c = *cur++) == ESC) { \
+        if (!len--) \
+            return 0; \
+        if (*cur++ != ESC) { \
+            DPRINTF("Broken packet %#2x, tossing\n", req); \
+		if (qemu_timer_pending(baum->cellCount_timer)) { \
+                qemu_del_timer(baum->cellCount_timer); \
+                baum_cellCount_timer_cb(baum); \
+            } \
+            return (cur - 2 - buf); \
+        } \
+    } \
+} while (0)
+
+    EAT(req);
+    switch (req) {
+    case BAUM_REQ_DisplayData:
+    {
+        uint8_t cells[baum->x * baum->y], c;
+        uint8_t text[baum->x * baum->y];
+        uint8_t zero[baum->x * baum->y];
+        int cursor = BRLAPI_CURSOR_OFF;
+        int i;
+
+        /* Allow 100ms to complete the DisplayData packet */
+        qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) +
+                       get_ticks_per_sec() / 10);
+        for (i = 0; i < baum->x * baum->y ; i++) {
+            EAT(c);
+            cells[i] = c;
+            if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
+                    == (BRLAPI_DOT7|BRLAPI_DOT8)) {
+                cursor = i + 1;
+                c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
+            }
+            if (!(c = nabcc_translation[c]))
+                c = '?';
+            text[i] = c;
+        }
+        qemu_del_timer(baum->cellCount_timer);
+
+        memset(zero, 0, sizeof(zero));
+
+        brlapi_writeArguments_t wa = {
+            .displayNumber = BRLAPI_DISPLAY_DEFAULT,
+            .regionBegin = 1,
+            .regionSize = baum->x * baum->y,
+            .text = (char *)text,
+            .textSize = baum->x * baum->y,
+            .andMask = zero,
+            .orMask = cells,
+            .cursor = cursor,
+            .charset = (char *)"ISO-8859-1",
+        };
+
+        if (brlapi__write(baum->brlapi, &wa) == -1)
+            brlapi_perror("baum brlapi_write");
+        break;
+    }
+    case BAUM_REQ_SetMode:
+    {
+        uint8_t mode, setting;
+        DPRINTF("SetMode\n");
+        EAT(mode);
+        EAT(setting);
+        /* ignore */
+        break;
+    }
+    case BAUM_REQ_SetProtocol:
+    {
+        uint8_t protocol;
+        DPRINTF("SetProtocol\n");
+        EAT(protocol);
+        /* ignore */
+        break;
+    }
+    case BAUM_REQ_GetDeviceIdentity:
+    {
+        uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
+            'B','a','u','m',' ','V','a','r','i','o' };
+        DPRINTF("GetDeviceIdentity\n");
+        identity[11] = '0' + baum->x / 10;
+        identity[12] = '0' + baum->x % 10;
+        baum_write_packet(baum, identity, sizeof(identity));
+        break;
+    }
+    case BAUM_REQ_GetVersionNumber:
+    {
+        uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
+        DPRINTF("GetVersionNumber\n");
+        baum_write_packet(baum, version, sizeof(version));
+        break;
+    }
+    case BAUM_REQ_GetSerialNumber:
+    {
+        uint8_t serial[] = { BAUM_RSP_SerialNumber,
+            '0','0','0','0','0','0','0','0' };
+        DPRINTF("GetSerialNumber\n");
+        baum_write_packet(baum, serial, sizeof(serial));
+        break;
+    }
+    case BAUM_REQ_GetKeys:
+    {
+        DPRINTF("Get%0#2x\n", req);
+        /* ignore */
+        break;
+    }
+    default:
+        DPRINTF("unrecognized request %0#2x\n", req);
+        do
+            if (!len--)
+                return 0;
+        while (*cur++ != ESC);
+        cur--;
+        break;
+    }
+    return cur - buf;
+}
+
+/* The other end is writing some data.  Store it and try to interpret */
+static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    BaumDriverState *baum = chr->opaque;
+    int tocopy, cur, eaten, orig_len = len;
+
+    if (!len)
+        return 0;
+    if (!baum->brlapi)
+        return len;
+
+    while (len) {
+        /* Complete our buffer as much as possible */
+        tocopy = len;
+        if (tocopy > BUF_SIZE - baum->in_buf_used)
+            tocopy = BUF_SIZE - baum->in_buf_used;
+
+        memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
+        baum->in_buf_used += tocopy;
+        buf += tocopy;
+        len -= tocopy;
+
+        /* Interpret it as much as possible */
+        cur = 0;
+        while (cur < baum->in_buf_used &&
+                (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
+            cur += eaten;
+
+        /* Shift the remainder */
+        if (cur) {
+            memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
+            baum->in_buf_used -= cur;
+        }
+
+        /* And continue if any data left */
+    }
+    return orig_len;
+}
+
+/* The other end sent us some event */
+static void baum_send_event(CharDriverState *chr, int event)
+{
+    BaumDriverState *baum = chr->opaque;
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        break;
+    case CHR_EVENT_OPENED:
+        /* Reset state */
+        baum->in_buf_used = 0;
+        break;
+    }
+}
+
+/* Send the key code to the other end */
+static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
+    uint8_t packet[] = { type, value };
+    DPRINTF("writing key %x %x\n", type, value);
+    baum_write_packet(baum, packet, sizeof(packet));
+}
+
+/* We got some data on the BrlAPI socket */
+static void baum_chr_read(void *opaque)
+{
+    BaumDriverState *baum = opaque;
+    brlapi_keyCode_t code;
+    int ret;
+    if (!baum->brlapi)
+        return;
+    while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
+        DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
+        /* Emulate */
+        switch (code & BRLAPI_KEY_TYPE_MASK) {
+        case BRLAPI_KEY_TYPE_CMD:
+            switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
+            case BRLAPI_KEY_CMD_ROUTE:
+                baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
+                baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
+                break;
+            case 0:
+                switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
+                case BRLAPI_KEY_CMD_FWINLT:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_FWINRT:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_LNUP:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_LNDN:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_TOP:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_BOT:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_TOP_LEFT:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_BOT_LEFT:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_HOME:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                case BRLAPI_KEY_CMD_PREFMENU:
+                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
+                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
+                    break;
+                }
+            }
+            break;
+        case BRLAPI_KEY_TYPE_SYM:
+            break;
+        }
+    }
+    if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
+        brlapi_perror("baum: brlapi_readKey");
+        brlapi__closeConnection(baum->brlapi);
+        qemu_free(baum->brlapi);
+        baum->brlapi = NULL;
+    }
+}
+
+static void baum_close(struct CharDriverState *chr)
+{
+    BaumDriverState *baum = chr->opaque;
+
+    qemu_free_timer(baum->cellCount_timer);
+    if (baum->brlapi) {
+        brlapi__closeConnection(baum->brlapi);
+        qemu_free(baum->brlapi);
+    }
+    qemu_free(baum);
+}
+
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
+{
+    BaumDriverState *baum;
+    CharDriverState *chr;
+    brlapi_handle_t *handle;
+#ifdef CONFIG_SDL
+    SDL_SysWMinfo info;
+#endif
+    int tty;
+
+    baum = qemu_mallocz(sizeof(BaumDriverState));
+    baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
+
+    chr->opaque = baum;
+    chr->chr_write = baum_write;
+    chr->chr_send_event = baum_send_event;
+    chr->chr_accept_input = baum_accept_input;
+    chr->chr_close = baum_close;
+
+    handle = qemu_mallocz(brlapi_getHandleSize());
+    baum->brlapi = handle;
+
+    baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
+    if (baum->brlapi_fd == -1) {
+        brlapi_perror("baum_init: brlapi_openConnection");
+        goto fail_handle;
+    }
+
+    baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum);
+
+    if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
+        brlapi_perror("baum_init: brlapi_getDisplaySize");
+        goto fail;
+    }
+
+#ifdef CONFIG_SDL
+    memset(&info, 0, sizeof(info));
+    SDL_VERSION(&info.version);
+    if (SDL_GetWMInfo(&info))
+        tty = info.info.x11.wmwindow;
+    else
+#endif
+        tty = BRLAPI_TTY_DEFAULT;
+
+    if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
+        brlapi_perror("baum_init: brlapi_enterTtyMode");
+        goto fail;
+    }
+
+    qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
+
+    qemu_chr_generic_open(chr);
+
+    *_chr = chr;
+    return 0;
+
+fail:
+    qemu_free_timer(baum->cellCount_timer);
+    brlapi__closeConnection(handle);
+fail_handle:
+    qemu_free(handle);
+    qemu_free(chr);
+    qemu_free(baum);
+    return -EIO;
+}
diff --git a/qemu-0.15.x/hw/baum.h b/qemu-0.15.x/hw/baum.h
new file mode 100644
index 0000000..3f28cc3
--- /dev/null
+++ b/qemu-0.15.x/hw/baum.h
@@ -0,0 +1,26 @@
+/*
+ * QEMU Baum
+ *
+ * Copyright (c) 2008 Samuel Thibault
+ *
+ * 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.
+ */
+
+/* char device */
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);
diff --git a/qemu-0.15.x/hw/bitbang_i2c.c b/qemu-0.15.x/hw/bitbang_i2c.c
new file mode 100644
index 0000000..53e9c5c
--- /dev/null
+++ b/qemu-0.15.x/hw/bitbang_i2c.c
@@ -0,0 +1,231 @@
+/*
+ * Bit-Bang i2c emulation extracted from
+ * Marvell MV88W8618 / Freecom MusicPal emulation.
+ *
+ * Copyright (c) 2008 Jan Kiszka
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "bitbang_i2c.h"
+#include "sysbus.h"
+
+//#define DEBUG_BITBANG_I2C
+
+#ifdef DEBUG_BITBANG_I2C
+#define DPRINTF(fmt, ...) \
+do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+typedef enum bitbang_i2c_state {
+    STOPPED = 0,
+    SENDING_BIT7,
+    SENDING_BIT6,
+    SENDING_BIT5,
+    SENDING_BIT4,
+    SENDING_BIT3,
+    SENDING_BIT2,
+    SENDING_BIT1,
+    SENDING_BIT0,
+    WAITING_FOR_ACK,
+    RECEIVING_BIT7,
+    RECEIVING_BIT6,
+    RECEIVING_BIT5,
+    RECEIVING_BIT4,
+    RECEIVING_BIT3,
+    RECEIVING_BIT2,
+    RECEIVING_BIT1,
+    RECEIVING_BIT0,
+    SENDING_ACK,
+    SENT_NACK
+} bitbang_i2c_state;
+
+struct bitbang_i2c_interface {
+    i2c_bus *bus;
+    bitbang_i2c_state state;
+    int last_data;
+    int last_clock;
+    int device_out;
+    uint8_t buffer;
+    int current_addr;
+};
+
+static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
+{
+    DPRINTF("STOP\n");
+    if (i2c->current_addr >= 0)
+        i2c_end_transfer(i2c->bus);
+    i2c->current_addr = -1;
+    i2c->state = STOPPED;
+}
+
+/* Set device data pin.  */
+static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
+{
+    i2c->device_out = level;
+    //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
+    return level & i2c->last_data;
+}
+
+/* Leave device data pin unodified.  */
+static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
+{
+    return bitbang_i2c_ret(i2c, i2c->device_out);
+}
+
+/* Returns data line level.  */
+int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
+{
+    int data;
+
+    if (level != 0 && level != 1) {
+        abort();
+    }
+
+    if (line == BITBANG_I2C_SDA) {
+        if (level == i2c->last_data) {
+            return bitbang_i2c_nop(i2c);
+        }
+        i2c->last_data = level;
+        if (i2c->last_clock == 0) {
+            return bitbang_i2c_nop(i2c);
+        }
+        if (level == 0) {
+            DPRINTF("START\n");
+            /* START condition.  */
+            i2c->state = SENDING_BIT7;
+            i2c->current_addr = -1;
+        } else {
+            /* STOP condition.  */
+            bitbang_i2c_enter_stop(i2c);
+        }
+        return bitbang_i2c_ret(i2c, 1);
+    }
+
+    data = i2c->last_data;
+    if (i2c->last_clock == level) {
+        return bitbang_i2c_nop(i2c);
+    }
+    i2c->last_clock = level;
+    if (level == 0) {
+        /* State is set/read at the start of the clock pulse.
+           release the data line at the end.  */
+        return bitbang_i2c_ret(i2c, 1);
+    }
+    switch (i2c->state) {
+    case STOPPED:
+    case SENT_NACK:
+        return bitbang_i2c_ret(i2c, 1);
+
+    case SENDING_BIT7 ... SENDING_BIT0:
+        i2c->buffer = (i2c->buffer << 1) | data;
+        /* will end up in WAITING_FOR_ACK */
+        i2c->state++; 
+        return bitbang_i2c_ret(i2c, 1);
+
+    case WAITING_FOR_ACK:
+        if (i2c->current_addr < 0) {
+            i2c->current_addr = i2c->buffer;
+            DPRINTF("Address 0x%02x\n", i2c->current_addr);
+            i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
+                               i2c->current_addr & 1);
+        } else {
+            DPRINTF("Sent 0x%02x\n", i2c->buffer);
+            i2c_send(i2c->bus, i2c->buffer);
+        }
+        if (i2c->current_addr & 1) {
+            i2c->state = RECEIVING_BIT7;
+        } else {
+            i2c->state = SENDING_BIT7;
+        }
+        return bitbang_i2c_ret(i2c, 0);
+
+    case RECEIVING_BIT7:
+        i2c->buffer = i2c_recv(i2c->bus);
+        DPRINTF("RX byte 0x%02x\n", i2c->buffer);
+        /* Fall through... */
+    case RECEIVING_BIT6 ... RECEIVING_BIT0:
+        data = i2c->buffer >> 7;
+        /* will end up in SENDING_ACK */
+        i2c->state++;
+        i2c->buffer <<= 1;
+        return bitbang_i2c_ret(i2c, data);
+
+    case SENDING_ACK:
+        i2c->state = RECEIVING_BIT7;
+        if (data != 0) {
+            DPRINTF("NACKED\n");
+            i2c->state = SENT_NACK;
+            i2c_nack(i2c->bus);
+        } else {
+            DPRINTF("ACKED\n");
+        }
+        return bitbang_i2c_ret(i2c, 1);
+    }
+    abort();
+}
+
+bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
+{
+    bitbang_i2c_interface *s;
+
+    s = qemu_mallocz(sizeof(bitbang_i2c_interface));
+
+    s->bus = bus;
+    s->last_data = 1;
+    s->last_clock = 1;
+    s->device_out = 1;
+
+    return s;
+}
+
+/* GPIO interface.  */
+typedef struct {
+    SysBusDevice busdev;
+    bitbang_i2c_interface *bitbang;
+    int last_level;
+    qemu_irq out;
+} GPIOI2CState;
+
+static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
+{
+    GPIOI2CState *s = opaque;
+
+    level = bitbang_i2c_set(s->bitbang, irq, level);
+    if (level != s->last_level) {
+        s->last_level = level;
+        qemu_set_irq(s->out, level);
+    }
+}
+
+static int gpio_i2c_init(SysBusDevice *dev)
+{
+    GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
+    i2c_bus *bus;
+
+    sysbus_init_mmio(dev, 0x0, 0);
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+
+    qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
+    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
+
+    return 0;
+}
+
+static SysBusDeviceInfo gpio_i2c_info = {
+    .init = gpio_i2c_init,
+    .qdev.name  = "gpio_i2c",
+    .qdev.desc  = "Virtual GPIO to I2C bridge",
+    .qdev.size  = sizeof(GPIOI2CState),
+};
+
+static void bitbang_i2c_register(void)
+{
+    sysbus_register_withprop(&gpio_i2c_info);
+}
+
+device_init(bitbang_i2c_register)
diff --git a/qemu-0.15.x/hw/bitbang_i2c.h b/qemu-0.15.x/hw/bitbang_i2c.h
new file mode 100644
index 0000000..519d2dc
--- /dev/null
+++ b/qemu-0.15.x/hw/bitbang_i2c.h
@@ -0,0 +1,14 @@
+#ifndef BITBANG_I2C_H
+#define BITBANG_I2C_H
+
+#include "i2c.h"
+
+typedef struct bitbang_i2c_interface bitbang_i2c_interface;
+
+#define BITBANG_I2C_SDA 0
+#define BITBANG_I2C_SCL 1
+
+bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus);
+int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
+
+#endif
diff --git a/qemu-0.15.x/hw/blizzard.c b/qemu-0.15.x/hw/blizzard.c
new file mode 100644
index 0000000..c524550
--- /dev/null
+++ b/qemu-0.15.x/hw/blizzard.c
@@ -0,0 +1,997 @@
+/*
+ * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "console.h"
+#include "devices.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+
+typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
+
+typedef struct {
+    uint8_t reg;
+    uint32_t addr;
+    int swallow;
+
+    int pll;
+    int pll_range;
+    int pll_ctrl;
+    uint8_t pll_mode;
+    uint8_t clksel;
+    int memenable;
+    int memrefresh;
+    uint8_t timing[3];
+    int priority;
+
+    uint8_t lcd_config;
+    int x;
+    int y;
+    int skipx;
+    int skipy;
+    uint8_t hndp;
+    uint8_t vndp;
+    uint8_t hsync;
+    uint8_t vsync;
+    uint8_t pclk;
+    uint8_t u;
+    uint8_t v;
+    uint8_t yrc[2];
+    int ix[2];
+    int iy[2];
+    int ox[2];
+    int oy[2];
+
+    int enable;
+    int blank;
+    int bpp;
+    int invalidate;
+    int mx[2];
+    int my[2];
+    uint8_t mode;
+    uint8_t effect;
+    uint8_t iformat;
+    uint8_t source;
+    DisplayState *state;
+    blizzard_fn_t *line_fn_tab[2];
+    void *fb;
+
+    uint8_t hssi_config[3];
+    uint8_t tv_config;
+    uint8_t tv_timing[4];
+    uint8_t vbi;
+    uint8_t tv_x;
+    uint8_t tv_y;
+    uint8_t tv_test;
+    uint8_t tv_filter_config;
+    uint8_t tv_filter_idx;
+    uint8_t tv_filter_coeff[0x20];
+    uint8_t border_r;
+    uint8_t border_g;
+    uint8_t border_b;
+    uint8_t gamma_config;
+    uint8_t gamma_idx;
+    uint8_t gamma_lut[0x100];
+    uint8_t matrix_ena;
+    uint8_t matrix_coeff[0x12];
+    uint8_t matrix_r;
+    uint8_t matrix_g;
+    uint8_t matrix_b;
+    uint8_t pm;
+    uint8_t status;
+    uint8_t rgbgpio_dir;
+    uint8_t rgbgpio;
+    uint8_t gpio_dir;
+    uint8_t gpio;
+    uint8_t gpio_edge[2];
+    uint8_t gpio_irq;
+    uint8_t gpio_pdown;
+
+    struct {
+        int x;
+        int y;
+        int dx;
+        int dy;
+        int len;
+        int buflen;
+        void *buf;
+        void *data;
+        uint16_t *ptr;
+        int angle;
+        int pitch;
+        blizzard_fn_t line_fn;
+    } data;
+} BlizzardState;
+
+/* Bytes(!) per pixel */
+static const int blizzard_iformat_bpp[0x10] = {
+    0,
+    2,	/* RGB 5:6:5*/
+    3,	/* RGB 6:6:6 mode 1 */
+    3,	/* RGB 8:8:8 mode 1 */
+    0, 0,
+    4,	/* RGB 6:6:6 mode 2 */
+    4,	/* RGB 8:8:8 mode 2 */
+    0,	/* YUV 4:2:2 */
+    0,	/* YUV 4:2:0 */
+    0, 0, 0, 0, 0, 0,
+};
+
+static inline void blizzard_rgb2yuv(int r, int g, int b,
+                int *y, int *u, int *v)
+{
+    *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
+    *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
+    *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
+}
+
+static void blizzard_window(BlizzardState *s)
+{
+    uint8_t *src, *dst;
+    int bypp[2];
+    int bypl[3];
+    int y;
+    blizzard_fn_t fn = s->data.line_fn;
+
+    if (!fn)
+        return;
+    if (s->mx[0] > s->data.x)
+        s->mx[0] = s->data.x;
+    if (s->my[0] > s->data.y)
+        s->my[0] = s->data.y;
+    if (s->mx[1] < s->data.x + s->data.dx)
+        s->mx[1] = s->data.x + s->data.dx;
+    if (s->my[1] < s->data.y + s->data.dy)
+        s->my[1] = s->data.y + s->data.dy;
+
+    bypp[0] = s->bpp;
+    bypp[1] = (ds_get_bits_per_pixel(s->state) + 7) >> 3;
+    bypl[0] = bypp[0] * s->data.pitch;
+    bypl[1] = bypp[1] * s->x;
+    bypl[2] = bypp[0] * s->data.dx;
+
+    src = s->data.data;
+    dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
+    for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
+        fn(dst, src, bypl[2]);
+}
+
+static int blizzard_transfer_setup(BlizzardState *s)
+{
+    if (s->source > 3 || !s->bpp ||
+                    s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
+        return 0;
+
+    s->data.angle = s->effect & 3;
+    s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
+    s->data.x = s->ix[0];
+    s->data.y = s->iy[0];
+    s->data.dx = s->ix[1] - s->ix[0] + 1;
+    s->data.dy = s->iy[1] - s->iy[0] + 1;
+    s->data.len = s->bpp * s->data.dx * s->data.dy;
+    s->data.pitch = s->data.dx;
+    if (s->data.len > s->data.buflen) {
+        s->data.buf = qemu_realloc(s->data.buf, s->data.len);
+        s->data.buflen = s->data.len;
+    }
+    s->data.ptr = s->data.buf;
+    s->data.data = s->data.buf;
+    s->data.len /= 2;
+    return 1;
+}
+
+static void blizzard_reset(BlizzardState *s)
+{
+    s->reg = 0;
+    s->swallow = 0;
+
+    s->pll = 9;
+    s->pll_range = 1;
+    s->pll_ctrl = 0x14;
+    s->pll_mode = 0x32;
+    s->clksel = 0x00;
+    s->memenable = 0;
+    s->memrefresh = 0x25c;
+    s->timing[0] = 0x3f;
+    s->timing[1] = 0x13;
+    s->timing[2] = 0x21;
+    s->priority = 0;
+
+    s->lcd_config = 0x74;
+    s->x = 8;
+    s->y = 1;
+    s->skipx = 0;
+    s->skipy = 0;
+    s->hndp = 3;
+    s->vndp = 2;
+    s->hsync = 1;
+    s->vsync = 1;
+    s->pclk = 0x80;
+
+    s->ix[0] = 0;
+    s->ix[1] = 0;
+    s->iy[0] = 0;
+    s->iy[1] = 0;
+    s->ox[0] = 0;
+    s->ox[1] = 0;
+    s->oy[0] = 0;
+    s->oy[1] = 0;
+
+    s->yrc[0] = 0x00;
+    s->yrc[1] = 0x30;
+    s->u = 0;
+    s->v = 0;
+
+    s->iformat = 3;
+    s->source = 0;
+    s->bpp = blizzard_iformat_bpp[s->iformat];
+
+    s->hssi_config[0] = 0x00;
+    s->hssi_config[1] = 0x00;
+    s->hssi_config[2] = 0x01;
+    s->tv_config = 0x00;
+    s->tv_timing[0] = 0x00;
+    s->tv_timing[1] = 0x00;
+    s->tv_timing[2] = 0x00;
+    s->tv_timing[3] = 0x00;
+    s->vbi = 0x10;
+    s->tv_x = 0x14;
+    s->tv_y = 0x03;
+    s->tv_test = 0x00;
+    s->tv_filter_config = 0x80;
+    s->tv_filter_idx = 0x00;
+    s->border_r = 0x10;
+    s->border_g = 0x80;
+    s->border_b = 0x80;
+    s->gamma_config = 0x00;
+    s->gamma_idx = 0x00;
+    s->matrix_ena = 0x00;
+    memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
+    s->matrix_r = 0x00;
+    s->matrix_g = 0x00;
+    s->matrix_b = 0x00;
+    s->pm = 0x02;
+    s->status = 0x00;
+    s->rgbgpio_dir = 0x00;
+    s->gpio_dir = 0x00;
+    s->gpio_edge[0] = 0x00;
+    s->gpio_edge[1] = 0x00;
+    s->gpio_irq = 0x00;
+    s->gpio_pdown = 0xff;
+}
+
+static inline void blizzard_invalidate_display(void *opaque) {
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    s->invalidate = 1;
+}
+
+static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x00:	/* Revision Code */
+        return 0xa5;
+
+    case 0x02:	/* Configuration Readback */
+        return 0x83;	/* Macrovision OK, CNF[2:0] = 3 */
+
+    case 0x04:	/* PLL M-Divider */
+        return (s->pll - 1) | (1 << 7);
+    case 0x06:	/* PLL Lock Range Control */
+        return s->pll_range;
+    case 0x08:	/* PLL Lock Synthesis Control 0 */
+        return s->pll_ctrl & 0xff;
+    case 0x0a:	/* PLL Lock Synthesis Control 1 */
+        return s->pll_ctrl >> 8;
+    case 0x0c:	/* PLL Mode Control 0 */
+        return s->pll_mode;
+
+    case 0x0e:	/* Clock-Source Select */
+        return s->clksel;
+
+    case 0x10:	/* Memory Controller Activate */
+    case 0x14:	/* Memory Controller Bank 0 Status Flag */
+        return s->memenable;
+
+    case 0x18:	/* Auto-Refresh Interval Setting 0 */
+        return s->memrefresh & 0xff;
+    case 0x1a:	/* Auto-Refresh Interval Setting 1 */
+        return s->memrefresh >> 8;
+
+    case 0x1c:	/* Power-On Sequence Timing Control */
+        return s->timing[0];
+    case 0x1e:	/* Timing Control 0 */
+        return s->timing[1];
+    case 0x20:	/* Timing Control 1 */
+        return s->timing[2];
+
+    case 0x24:	/* Arbitration Priority Control */
+        return s->priority;
+
+    case 0x28:	/* LCD Panel Configuration */
+        return s->lcd_config;
+
+    case 0x2a:	/* LCD Horizontal Display Width */
+        return s->x >> 3;
+    case 0x2c:	/* LCD Horizontal Non-display Period */
+        return s->hndp;
+    case 0x2e:	/* LCD Vertical Display Height 0 */
+        return s->y & 0xff;
+    case 0x30:	/* LCD Vertical Display Height 1 */
+        return s->y >> 8;
+    case 0x32:	/* LCD Vertical Non-display Period */
+        return s->vndp;
+    case 0x34:	/* LCD HS Pulse-width */
+        return s->hsync;
+    case 0x36:	/* LCd HS Pulse Start Position */
+        return s->skipx >> 3;
+    case 0x38:	/* LCD VS Pulse-width */
+        return s->vsync;
+    case 0x3a:	/* LCD VS Pulse Start Position */
+        return s->skipy;
+
+    case 0x3c:	/* PCLK Polarity */
+        return s->pclk;
+
+    case 0x3e:	/* High-speed Serial Interface Tx Configuration Port 0 */
+        return s->hssi_config[0];
+    case 0x40:	/* High-speed Serial Interface Tx Configuration Port 1 */
+        return s->hssi_config[1];
+    case 0x42:	/* High-speed Serial Interface Tx Mode */
+        return s->hssi_config[2];
+    case 0x44:	/* TV Display Configuration */
+        return s->tv_config;
+    case 0x46 ... 0x4c:	/* TV Vertical Blanking Interval Data bits */
+        return s->tv_timing[(reg - 0x46) >> 1];
+    case 0x4e:	/* VBI: Closed Caption / XDS Control / Status */
+        return s->vbi;
+    case 0x50:	/* TV Horizontal Start Position */
+        return s->tv_x;
+    case 0x52:	/* TV Vertical Start Position */
+        return s->tv_y;
+    case 0x54:	/* TV Test Pattern Setting */
+        return s->tv_test;
+    case 0x56:	/* TV Filter Setting */
+        return s->tv_filter_config;
+    case 0x58:	/* TV Filter Coefficient Index */
+        return s->tv_filter_idx;
+    case 0x5a:	/* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            return s->tv_filter_coeff[s->tv_filter_idx ++];
+        return 0;
+
+    case 0x60:	/* Input YUV/RGB Translate Mode 0 */
+        return s->yrc[0];
+    case 0x62:	/* Input YUV/RGB Translate Mode 1 */
+        return s->yrc[1];
+    case 0x64:	/* U Data Fix */
+        return s->u;
+    case 0x66:	/* V Data Fix */
+        return s->v;
+
+    case 0x68:	/* Display Mode */
+        return s->mode;
+
+    case 0x6a:	/* Special Effects */
+        return s->effect;
+
+    case 0x6c:	/* Input Window X Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x6e:	/* Input Window X Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x70:	/* Input Window Y Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x72:	/* Input Window Y Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x74:	/* Input Window X End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x76:	/* Input Window X End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x78:	/* Input Window Y End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x7a:	/* Input Window Y End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x7c:	/* Output Window X Start Position 0 */
+        return s->ox[0] & 0xff;
+    case 0x7e:	/* Output Window X Start Position 1 */
+        return s->ox[0] >> 3;
+    case 0x80:	/* Output Window Y Start Position 0 */
+        return s->oy[0] & 0xff;
+    case 0x82:	/* Output Window Y Start Position 1 */
+        return s->oy[0] >> 3;
+    case 0x84:	/* Output Window X End Position 0 */
+        return s->ox[1] & 0xff;
+    case 0x86:	/* Output Window X End Position 1 */
+        return s->ox[1] >> 3;
+    case 0x88:	/* Output Window Y End Position 0 */
+        return s->oy[1] & 0xff;
+    case 0x8a:	/* Output Window Y End Position 1 */
+        return s->oy[1] >> 3;
+
+    case 0x8c:	/* Input Data Format */
+        return s->iformat;
+    case 0x8e:	/* Data Source Select */
+        return s->source;
+    case 0x90:	/* Display Memory Data Port */
+        return 0;
+
+    case 0xa8:	/* Border Color 0 */
+        return s->border_r;
+    case 0xaa:	/* Border Color 1 */
+        return s->border_g;
+    case 0xac:	/* Border Color 2 */
+        return s->border_b;
+
+    case 0xb4:	/* Gamma Correction Enable */
+        return s->gamma_config;
+    case 0xb6:	/* Gamma Correction Table Index */
+        return s->gamma_idx;
+    case 0xb8:	/* Gamma Correction Table Data */
+        return s->gamma_lut[s->gamma_idx ++];
+
+    case 0xba:	/* 3x3 Matrix Enable */
+        return s->matrix_ena;
+    case 0xbc ... 0xde:	/* Coefficient Registers */
+        return s->matrix_coeff[(reg - 0xbc) >> 1];
+    case 0xe0:	/* 3x3 Matrix Red Offset */
+        return s->matrix_r;
+    case 0xe2:	/* 3x3 Matrix Green Offset */
+        return s->matrix_g;
+    case 0xe4:	/* 3x3 Matrix Blue Offset */
+        return s->matrix_b;
+
+    case 0xe6:	/* Power-save */
+        return s->pm;
+    case 0xe8:	/* Non-display Period Control / Status */
+        return s->status | (1 << 5);
+    case 0xea:	/* RGB Interface Control */
+        return s->rgbgpio_dir;
+    case 0xec:	/* RGB Interface Status */
+        return s->rgbgpio;
+    case 0xee:	/* General-purpose IO Pins Configuration */
+        return s->gpio_dir;
+    case 0xf0:	/* General-purpose IO Pins Status / Control */
+        return s->gpio;
+    case 0xf2:	/* GPIO Positive Edge Interrupt Trigger */
+        return s->gpio_edge[0];
+    case 0xf4:	/* GPIO Negative Edge Interrupt Trigger */
+        return s->gpio_edge[1];
+    case 0xf6:	/* GPIO Interrupt Status */
+        return s->gpio_irq;
+    case 0xf8:	/* GPIO Pull-down Control */
+        return s->gpio_pdown;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        return 0;
+    }
+}
+
+static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x04:	/* PLL M-Divider */
+        s->pll = (value & 0x3f) + 1;
+        break;
+    case 0x06:	/* PLL Lock Range Control */
+        s->pll_range = value & 3;
+        break;
+    case 0x08:	/* PLL Lock Synthesis Control 0 */
+        s->pll_ctrl &= 0xf00;
+        s->pll_ctrl |= (value << 0) & 0x0ff;
+        break;
+    case 0x0a:	/* PLL Lock Synthesis Control 1 */
+        s->pll_ctrl &= 0x0ff;
+        s->pll_ctrl |= (value << 8) & 0xf00;
+        break;
+    case 0x0c:	/* PLL Mode Control 0 */
+        s->pll_mode = value & 0x77;
+        if ((value & 3) == 0 || (value & 3) == 3)
+            fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
+                    __FUNCTION__, value & 3);
+        break;
+
+    case 0x0e:	/* Clock-Source Select */
+        s->clksel = value & 0xff;
+        break;
+
+    case 0x10:	/* Memory Controller Activate */
+        s->memenable = value & 1;
+        break;
+    case 0x14:	/* Memory Controller Bank 0 Status Flag */
+        break;
+
+    case 0x18:	/* Auto-Refresh Interval Setting 0 */
+        s->memrefresh &= 0xf00;
+        s->memrefresh |= (value << 0) & 0x0ff;
+        break;
+    case 0x1a:	/* Auto-Refresh Interval Setting 1 */
+        s->memrefresh &= 0x0ff;
+        s->memrefresh |= (value << 8) & 0xf00;
+        break;
+
+    case 0x1c:	/* Power-On Sequence Timing Control */
+        s->timing[0] = value & 0x7f;
+        break;
+    case 0x1e:	/* Timing Control 0 */
+        s->timing[1] = value & 0x17;
+        break;
+    case 0x20:	/* Timing Control 1 */
+        s->timing[2] = value & 0x35;
+        break;
+
+    case 0x24:	/* Arbitration Priority Control */
+        s->priority = value & 1;
+        break;
+
+    case 0x28:	/* LCD Panel Configuration */
+        s->lcd_config = value & 0xff;
+        if (value & (1 << 7))
+            fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
+        break;
+
+    case 0x2a:	/* LCD Horizontal Display Width */
+        s->x = value << 3;
+        break;
+    case 0x2c:	/* LCD Horizontal Non-display Period */
+        s->hndp = value & 0xff;
+        break;
+    case 0x2e:	/* LCD Vertical Display Height 0 */
+        s->y &= 0x300;
+        s->y |= (value << 0) & 0x0ff;
+        break;
+    case 0x30:	/* LCD Vertical Display Height 1 */
+        s->y &= 0x0ff;
+        s->y |= (value << 8) & 0x300;
+        break;
+    case 0x32:	/* LCD Vertical Non-display Period */
+        s->vndp = value & 0xff;
+        break;
+    case 0x34:	/* LCD HS Pulse-width */
+        s->hsync = value & 0xff;
+        break;
+    case 0x36:	/* LCD HS Pulse Start Position */
+        s->skipx = value & 0xff;
+        break;
+    case 0x38:	/* LCD VS Pulse-width */
+        s->vsync = value & 0xbf;
+        break;
+    case 0x3a:	/* LCD VS Pulse Start Position */
+        s->skipy = value & 0xff;
+        break;
+
+    case 0x3c:	/* PCLK Polarity */
+        s->pclk = value & 0x82;
+        /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
+        break;
+
+    case 0x3e:	/* High-speed Serial Interface Tx Configuration Port 0 */
+        s->hssi_config[0] = value;
+        break;
+    case 0x40:	/* High-speed Serial Interface Tx Configuration Port 1 */
+        s->hssi_config[1] = value;
+        if (((value >> 4) & 3) == 3)
+            fprintf(stderr, "%s: Illegal active-data-links value\n",
+                            __FUNCTION__);
+        break;
+    case 0x42:	/* High-speed Serial Interface Tx Mode */
+        s->hssi_config[2] = value & 0xbd;
+        break;
+
+    case 0x44:	/* TV Display Configuration */
+        s->tv_config = value & 0xfe;
+        break;
+    case 0x46 ... 0x4c:	/* TV Vertical Blanking Interval Data bits 0 */
+        s->tv_timing[(reg - 0x46) >> 1] = value;
+        break;
+    case 0x4e:	/* VBI: Closed Caption / XDS Control / Status */
+        s->vbi = value;
+        break;
+    case 0x50:	/* TV Horizontal Start Position */
+        s->tv_x = value;
+        break;
+    case 0x52:	/* TV Vertical Start Position */
+        s->tv_y = value & 0x7f;
+        break;
+    case 0x54:	/* TV Test Pattern Setting */
+        s->tv_test = value;
+        break;
+    case 0x56:	/* TV Filter Setting */
+        s->tv_filter_config = value & 0xbf;
+        break;
+    case 0x58:	/* TV Filter Coefficient Index */
+        s->tv_filter_idx = value & 0x1f;
+        break;
+    case 0x5a:	/* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            s->tv_filter_coeff[s->tv_filter_idx ++] = value;
+        break;
+
+    case 0x60:	/* Input YUV/RGB Translate Mode 0 */
+        s->yrc[0] = value & 0xb0;
+        break;
+    case 0x62:	/* Input YUV/RGB Translate Mode 1 */
+        s->yrc[1] = value & 0x30;
+        break;
+    case 0x64:	/* U Data Fix */
+        s->u = value & 0xff;
+        break;
+    case 0x66:	/* V Data Fix */
+        s->v = value & 0xff;
+        break;
+
+    case 0x68:	/* Display Mode */
+        if ((s->mode ^ value) & 3)
+            s->invalidate = 1;
+        s->mode = value & 0xb7;
+        s->enable = value & 1;
+        s->blank = (value >> 1) & 1;
+        if (value & (1 << 4))
+            fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
+        break;
+
+    case 0x6a:	/* Special Effects */
+        s->effect = value & 0xfb;
+        break;
+
+    case 0x6c:	/* Input Window X Start Position 0 */
+        s->ix[0] &= 0x300;
+        s->ix[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x6e:	/* Input Window X Start Position 1 */
+        s->ix[0] &= 0x0ff;
+        s->ix[0] |= (value << 8) & 0x300;
+        break;
+    case 0x70:	/* Input Window Y Start Position 0 */
+        s->iy[0] &= 0x300;
+        s->iy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x72:	/* Input Window Y Start Position 1 */
+        s->iy[0] &= 0x0ff;
+        s->iy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x74:	/* Input Window X End Position 0 */
+        s->ix[1] &= 0x300;
+        s->ix[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x76:	/* Input Window X End Position 1 */
+        s->ix[1] &= 0x0ff;
+        s->ix[1] |= (value << 8) & 0x300;
+        break;
+    case 0x78:	/* Input Window Y End Position 0 */
+        s->iy[1] &= 0x300;
+        s->iy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7a:	/* Input Window Y End Position 1 */
+        s->iy[1] &= 0x0ff;
+        s->iy[1] |= (value << 8) & 0x300;
+        break;
+    case 0x7c:	/* Output Window X Start Position 0 */
+        s->ox[0] &= 0x300;
+        s->ox[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7e:	/* Output Window X Start Position 1 */
+        s->ox[0] &= 0x0ff;
+        s->ox[0] |= (value << 8) & 0x300;
+        break;
+    case 0x80:	/* Output Window Y Start Position 0 */
+        s->oy[0] &= 0x300;
+        s->oy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x82:	/* Output Window Y Start Position 1 */
+        s->oy[0] &= 0x0ff;
+        s->oy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x84:	/* Output Window X End Position 0 */
+        s->ox[1] &= 0x300;
+        s->ox[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x86:	/* Output Window X End Position 1 */
+        s->ox[1] &= 0x0ff;
+        s->ox[1] |= (value << 8) & 0x300;
+        break;
+    case 0x88:	/* Output Window Y End Position 0 */
+        s->oy[1] &= 0x300;
+        s->oy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x8a:	/* Output Window Y End Position 1 */
+        s->oy[1] &= 0x0ff;
+        s->oy[1] |= (value << 8) & 0x300;
+        break;
+
+    case 0x8c:	/* Input Data Format */
+        s->iformat = value & 0xf;
+        s->bpp = blizzard_iformat_bpp[s->iformat];
+        if (!s->bpp)
+            fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
+                            __FUNCTION__, s->iformat);
+        break;
+    case 0x8e:	/* Data Source Select */
+        s->source = value & 7;
+        /* Currently all windows will be "destructive overlays".  */
+        if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
+                                        s->iy[0] != s->oy[0] ||
+                                        s->ix[1] != s->ox[1] ||
+                                        s->iy[1] != s->oy[1])) ||
+                        !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
+                          (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
+            fprintf(stderr, "%s: Illegal input/output window positions\n",
+                            __FUNCTION__);
+
+        blizzard_transfer_setup(s);
+        break;
+
+    case 0x90:	/* Display Memory Data Port */
+        if (!s->data.len && !blizzard_transfer_setup(s))
+            break;
+
+        *s->data.ptr ++ = value;
+        if (-- s->data.len == 0)
+            blizzard_window(s);
+        break;
+
+    case 0xa8:	/* Border Color 0 */
+        s->border_r = value;
+        break;
+    case 0xaa:	/* Border Color 1 */
+        s->border_g = value;
+        break;
+    case 0xac:	/* Border Color 2 */
+        s->border_b = value;
+        break;
+
+    case 0xb4:	/* Gamma Correction Enable */
+        s->gamma_config = value & 0x87;
+        break;
+    case 0xb6:	/* Gamma Correction Table Index */
+        s->gamma_idx = value;
+        break;
+    case 0xb8:	/* Gamma Correction Table Data */
+        s->gamma_lut[s->gamma_idx ++] = value;
+        break;
+
+    case 0xba:	/* 3x3 Matrix Enable */
+        s->matrix_ena = value & 1;
+        break;
+    case 0xbc ... 0xde:	/* Coefficient Registers */
+        s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
+        break;
+    case 0xe0:	/* 3x3 Matrix Red Offset */
+        s->matrix_r = value;
+        break;
+    case 0xe2:	/* 3x3 Matrix Green Offset */
+        s->matrix_g = value;
+        break;
+    case 0xe4:	/* 3x3 Matrix Blue Offset */
+        s->matrix_b = value;
+        break;
+
+    case 0xe6:	/* Power-save */
+        s->pm = value & 0x83;
+        if (value & s->mode & 1)
+            fprintf(stderr, "%s: The display must be disabled before entering "
+                            "Standby Mode\n", __FUNCTION__);
+        break;
+    case 0xe8:	/* Non-display Period Control / Status */
+        s->status = value & 0x1b;
+        break;
+    case 0xea:	/* RGB Interface Control */
+        s->rgbgpio_dir = value & 0x8f;
+        break;
+    case 0xec:	/* RGB Interface Status */
+        s->rgbgpio = value & 0xcf;
+        break;
+    case 0xee:	/* General-purpose IO Pins Configuration */
+        s->gpio_dir = value;
+        break;
+    case 0xf0:	/* General-purpose IO Pins Status / Control */
+        s->gpio = value;
+        break;
+    case 0xf2:	/* GPIO Positive Edge Interrupt Trigger */
+        s->gpio_edge[0] = value;
+        break;
+    case 0xf4:	/* GPIO Negative Edge Interrupt Trigger */
+        s->gpio_edge[1] = value;
+        break;
+    case 0xf6:	/* GPIO Interrupt Status */
+        s->gpio_irq &= value;
+        break;
+    case 0xf8:	/* GPIO Pull-down Control */
+        s->gpio_pdown = value;
+        break;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+uint16_t s1d13745_read(void *opaque, int dc)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    uint16_t value = blizzard_reg_read(s, s->reg);
+
+    if (s->swallow -- > 0)
+        return 0;
+    if (dc)
+        s->reg ++;
+
+    return value;
+}
+
+void s1d13745_write(void *opaque, int dc, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    if (s->swallow -- > 0)
+        return;
+    if (dc) {
+        blizzard_reg_write(s, s->reg, value);
+
+        if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
+            s->reg += 2;
+    } else
+        s->reg = value & 0xff;
+}
+
+void s1d13745_write_block(void *opaque, int dc,
+                void *buf, size_t len, int pitch)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    while (len > 0) {
+        if (s->reg == 0x90 && dc &&
+                        (s->data.len || blizzard_transfer_setup(s)) &&
+                        len >= (s->data.len << 1)) {
+            len -= s->data.len << 1;
+            s->data.len = 0;
+            s->data.data = buf;
+            if (pitch)
+                s->data.pitch = pitch;
+            blizzard_window(s);
+            s->data.data = s->data.buf;
+            continue;
+        }
+
+        s1d13745_write(opaque, dc, *(uint16_t *) buf);
+        len -= 2;
+        buf += 2;
+    }
+
+    return;
+}
+
+static void blizzard_update_display(void *opaque)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    int y, bypp, bypl, bwidth;
+    uint8_t *src, *dst;
+
+    if (!s->enable)
+        return;
+
+    if (s->x != ds_get_width(s->state) || s->y != ds_get_height(s->state)) {
+        s->invalidate = 1;
+        qemu_console_resize(s->state, s->x, s->y);
+    }
+
+    if (s->invalidate) {
+        s->invalidate = 0;
+
+        if (s->blank) {
+            bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3;
+            memset(ds_get_data(s->state), 0, bypp * s->x * s->y);
+            return;
+        }
+
+        s->mx[0] = 0;
+        s->mx[1] = s->x;
+        s->my[0] = 0;
+        s->my[1] = s->y;
+    }
+
+    if (s->mx[1] <= s->mx[0])
+        return;
+
+    bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3;
+    bypl = bypp * s->x;
+    bwidth = bypp * (s->mx[1] - s->mx[0]);
+    y = s->my[0];
+    src = s->fb + bypl * y + bypp * s->mx[0];
+    dst = ds_get_data(s->state) + bypl * y + bypp * s->mx[0];
+    for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
+        memcpy(dst, src, bwidth);
+
+    dpy_update(s->state, s->mx[0], s->my[0],
+                    s->mx[1] - s->mx[0], y - s->my[0]);
+
+    s->mx[0] = s->x;
+    s->mx[1] = 0;
+    s->my[0] = s->y;
+    s->my[1] = 0;
+}
+
+static void blizzard_screen_dump(void *opaque, const char *filename) {
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    blizzard_update_display(opaque);
+    if (s && ds_get_data(s->state))
+        ppm_save(filename, s->state->surface);
+}
+
+#define DEPTH 8
+#include "blizzard_template.h"
+#define DEPTH 15
+#include "blizzard_template.h"
+#define DEPTH 16
+#include "blizzard_template.h"
+#define DEPTH 24
+#include "blizzard_template.h"
+#define DEPTH 32
+#include "blizzard_template.h"
+
+void *s1d13745_init(qemu_irq gpio_int)
+{
+    BlizzardState *s = (BlizzardState *) qemu_mallocz(sizeof(*s));
+
+    s->fb = qemu_malloc(0x180000);
+
+    s->state = graphic_console_init(blizzard_update_display,
+                                 blizzard_invalidate_display,
+                                 blizzard_screen_dump, NULL, s);
+
+    switch (ds_get_bits_per_pixel(s->state)) {
+    case 0:
+        s->line_fn_tab[0] = s->line_fn_tab[1] =
+                qemu_mallocz(sizeof(blizzard_fn_t) * 0x10);
+        break;
+    case 8:
+        s->line_fn_tab[0] = blizzard_draw_fn_8;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_8;
+        break;
+    case 15:
+        s->line_fn_tab[0] = blizzard_draw_fn_15;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_15;
+        break;
+    case 16:
+        s->line_fn_tab[0] = blizzard_draw_fn_16;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_16;
+        break;
+    case 24:
+        s->line_fn_tab[0] = blizzard_draw_fn_24;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_24;
+        break;
+    case 32:
+        s->line_fn_tab[0] = blizzard_draw_fn_32;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_32;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    blizzard_reset(s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/blizzard_template.h b/qemu-0.15.x/hw/blizzard_template.h
new file mode 100644
index 0000000..42f4e90
--- /dev/null
+++ b/qemu-0.15.x/hw/blizzard_template.h
@@ -0,0 +1,136 @@
+/*
+ * QEMU Epson S1D13744/S1D13745 templates
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define SKIP_PIXEL(to)		to += deststep
+#if DEPTH == 8
+# define PIXEL_TYPE		uint8_t
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from)	*to ++ = from
+#elif DEPTH == 15 || DEPTH == 16
+# define PIXEL_TYPE		uint16_t
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from)	*to ++ = from
+#elif DEPTH == 24
+# define PIXEL_TYPE		uint8_t
+# define COPY_PIXEL(to, from)	\
+    to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from)	\
+    *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
+#elif DEPTH == 32
+# define PIXEL_TYPE		uint32_t
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from)	*to ++ = from
+#else
+# error unknown bit depth
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+# define SWAP_WORDS	1
+#endif
+
+static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
+                const uint16_t *src, unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 16
+    memcpy(dest, src, width);
+#else
+    uint16_t data;
+    unsigned int r, g, b;
+    const uint16_t *end = (const void *) src + width;
+    while (src < end) {
+        data = lduw_raw(src ++);
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+#endif
+}
+
+static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
+                const uint8_t *src, unsigned int width)
+{
+    /* TODO: check if SDL 24-bit planes are not in the same format and
+     * if so, use memcpy */
+    unsigned int r[2], g[2], b[2];
+    const uint8_t *end = src + width;
+    while (src < end) {
+        g[0] = *src ++;
+        r[0] = *src ++;
+        r[1] = *src ++;
+        b[0] = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
+        b[1] = *src ++;
+        g[1] = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
+    }
+}
+
+static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
+                const uint8_t *src, unsigned int width)
+{
+    unsigned int r, g, b;
+    const uint8_t *end = src + width;
+    while (src < end) {
+        r = *src ++;
+        src ++;
+        b = *src ++;
+        g = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+}
+
+/* No rotation */
+static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
+    NULL,
+    /* RGB 5:6:5*/
+    (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
+    /* RGB 6:6:6 mode 1 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
+    /* RGB 8:8:8 mode 1 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
+    NULL, NULL,
+    /* RGB 6:6:6 mode 2 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
+    /* RGB 8:8:8 mode 2 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
+    /* YUV 4:2:2 */
+    NULL,
+    /* YUV 4:2:0 */
+    NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+/* 90deg, 180deg and 270deg rotation */
+static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
+    /* TODO */
+    [0 ... 0xf] = NULL,
+};
+
+#undef DEPTH
+#undef SKIP_PIXEL
+#undef COPY_PIXEL
+#undef COPY_PIXEL1
+#undef PIXEL_TYPE
+
+#undef SWAP_WORDS
diff --git a/qemu-0.15.x/hw/boards.h b/qemu-0.15.x/hw/boards.h
new file mode 100644
index 0000000..716fd7b
--- /dev/null
+++ b/qemu-0.15.x/hw/boards.h
@@ -0,0 +1,39 @@
+/* Declarations for use by board files for creating devices.  */
+
+#ifndef HW_BOARDS_H
+#define HW_BOARDS_H
+
+#include "qdev.h"
+
+typedef void QEMUMachineInitFunc(ram_addr_t ram_size,
+                                 const char *boot_device,
+                                 const char *kernel_filename,
+                                 const char *kernel_cmdline,
+                                 const char *initrd_filename,
+                                 const char *cpu_model);
+
+typedef struct QEMUMachine {
+    const char *name;
+    const char *alias;
+    const char *desc;
+    QEMUMachineInitFunc *init;
+    int use_scsi;
+    int max_cpus;
+    unsigned int no_serial:1,
+        no_parallel:1,
+        use_virtcon:1,
+        no_vga:1,
+        no_floppy:1,
+        no_cdrom:1,
+        no_sdcard:1;
+    int is_default;
+    const char *default_machine_opts;
+    GlobalProperty *compat_props;
+    struct QEMUMachine *next;
+} QEMUMachine;
+
+int qemu_register_machine(QEMUMachine *m);
+
+extern QEMUMachine *current_machine;
+
+#endif
diff --git a/qemu-0.15.x/hw/bonito.c b/qemu-0.15.x/hw/bonito.c
new file mode 100644
index 0000000..e8c57a3
--- /dev/null
+++ b/qemu-0.15.x/hw/bonito.c
@@ -0,0 +1,814 @@
+/*
+ * bonito north bridge support
+ *
+ * Copyright (c) 2008 yajin (yajin at vm-kernel.org)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+/*
+ * fulong 2e mini pc has a bonito north bridge.
+ */
+
+/* what is the meaning of devfn in qemu and IDSEL in bonito northbridge?
+ *
+ * devfn   pci_slot<<3  + funno
+ * one pci bus can have 32 devices and each device can have 8 functions.
+ *
+ * In bonito north bridge, pci slot = IDSEL bit - 12.
+ * For example, PCI_IDSEL_VIA686B = 17,
+ * pci slot = 17-12=5
+ *
+ * so
+ * VT686B_FUN0's devfn = (5<<3)+0
+ * VT686B_FUN1's devfn = (5<<3)+1
+ *
+ * qemu also uses pci address for north bridge to access pci config register.
+ * bus_no   [23:16]
+ * dev_no   [15:11]
+ * fun_no   [10:8]
+ * reg_no   [7:2]
+ *
+ * so function bonito_sbridge_pciaddr for the translation from
+ * north bridge address to pci address.
+ */
+
+#include <assert.h>
+
+#include "hw.h"
+#include "pci.h"
+#include "pc.h"
+#include "mips.h"
+#include "pci_host.h"
+#include "sysemu.h"
+
+//#define DEBUG_BONITO
+
+#ifdef DEBUG_BONITO
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* from linux soure code. include/asm-mips/mips-boards/bonito64.h*/
+#define BONITO_BOOT_BASE        0x1fc00000
+#define BONITO_BOOT_SIZE        0x00100000
+#define BONITO_BOOT_TOP         (BONITO_BOOT_BASE+BONITO_BOOT_SIZE-1)
+#define BONITO_FLASH_BASE       0x1c000000
+#define BONITO_FLASH_SIZE       0x03000000
+#define BONITO_FLASH_TOP        (BONITO_FLASH_BASE+BONITO_FLASH_SIZE-1)
+#define BONITO_SOCKET_BASE      0x1f800000
+#define BONITO_SOCKET_SIZE      0x00400000
+#define BONITO_SOCKET_TOP       (BONITO_SOCKET_BASE+BONITO_SOCKET_SIZE-1)
+#define BONITO_REG_BASE         0x1fe00000
+#define BONITO_REG_SIZE         0x00040000
+#define BONITO_REG_TOP          (BONITO_REG_BASE+BONITO_REG_SIZE-1)
+#define BONITO_DEV_BASE         0x1ff00000
+#define BONITO_DEV_SIZE         0x00100000
+#define BONITO_DEV_TOP          (BONITO_DEV_BASE+BONITO_DEV_SIZE-1)
+#define BONITO_PCILO_BASE       0x10000000
+#define BONITO_PCILO_BASE_VA    0xb0000000
+#define BONITO_PCILO_SIZE       0x0c000000
+#define BONITO_PCILO_TOP        (BONITO_PCILO_BASE+BONITO_PCILO_SIZE-1)
+#define BONITO_PCILO0_BASE      0x10000000
+#define BONITO_PCILO1_BASE      0x14000000
+#define BONITO_PCILO2_BASE      0x18000000
+#define BONITO_PCIHI_BASE       0x20000000
+#define BONITO_PCIHI_SIZE       0x20000000
+#define BONITO_PCIHI_TOP        (BONITO_PCIHI_BASE+BONITO_PCIHI_SIZE-1)
+#define BONITO_PCIIO_BASE       0x1fd00000
+#define BONITO_PCIIO_BASE_VA    0xbfd00000
+#define BONITO_PCIIO_SIZE       0x00010000
+#define BONITO_PCIIO_TOP        (BONITO_PCIIO_BASE+BONITO_PCIIO_SIZE-1)
+#define BONITO_PCICFG_BASE      0x1fe80000
+#define BONITO_PCICFG_SIZE      0x00080000
+#define BONITO_PCICFG_TOP       (BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
+
+
+#define BONITO_PCICONFIGBASE    0x00
+#define BONITO_REGBASE          0x100
+
+#define BONITO_PCICONFIG_BASE   (BONITO_PCICONFIGBASE+BONITO_REG_BASE)
+#define BONITO_PCICONFIG_SIZE   (0x100)
+
+#define BONITO_INTERNAL_REG_BASE  (BONITO_REGBASE+BONITO_REG_BASE)
+#define BONITO_INTERNAL_REG_SIZE  (0x70)
+
+#define BONITO_SPCICONFIG_BASE  (BONITO_PCICFG_BASE)
+#define BONITO_SPCICONFIG_SIZE  (BONITO_PCICFG_SIZE)
+
+
+
+/* 1. Bonito h/w Configuration */
+/* Power on register */
+
+#define BONITO_BONPONCFG        (0x00 >> 2)      /* 0x100 */
+#define BONITO_BONGENCFG_OFFSET 0x4
+#define BONITO_BONGENCFG        (BONITO_BONGENCFG_OFFSET>>2)   /*0x104 */
+
+/* 2. IO & IDE configuration */
+#define BONITO_IODEVCFG         (0x08 >> 2)      /* 0x108 */
+
+/* 3. IO & IDE configuration */
+#define BONITO_SDCFG            (0x0c >> 2)      /* 0x10c */
+
+/* 4. PCI address map control */
+#define BONITO_PCIMAP           (0x10 >> 2)      /* 0x110 */
+#define BONITO_PCIMEMBASECFG    (0x14 >> 2)      /* 0x114 */
+#define BONITO_PCIMAP_CFG       (0x18 >> 2)      /* 0x118 */
+
+/* 5. ICU & GPIO regs */
+/* GPIO Regs - r/w */
+#define BONITO_GPIODATA_OFFSET  0x1c
+#define BONITO_GPIODATA         (BONITO_GPIODATA_OFFSET >> 2)   /* 0x11c */
+#define BONITO_GPIOIE           (0x20 >> 2)      /* 0x120 */
+
+/* ICU Configuration Regs - r/w */
+#define BONITO_INTEDGE          (0x24 >> 2)      /* 0x124 */
+#define BONITO_INTSTEER         (0x28 >> 2)      /* 0x128 */
+#define BONITO_INTPOL           (0x2c >> 2)      /* 0x12c */
+
+/* ICU Enable Regs - IntEn & IntISR are r/o. */
+#define BONITO_INTENSET         (0x30 >> 2)      /* 0x130 */
+#define BONITO_INTENCLR         (0x34 >> 2)      /* 0x134 */
+#define BONITO_INTEN            (0x38 >> 2)      /* 0x138 */
+#define BONITO_INTISR           (0x3c >> 2)      /* 0x13c */
+
+/* PCI mail boxes */
+#define BONITO_PCIMAIL0_OFFSET    0x40
+#define BONITO_PCIMAIL1_OFFSET    0x44
+#define BONITO_PCIMAIL2_OFFSET    0x48
+#define BONITO_PCIMAIL3_OFFSET    0x4c
+#define BONITO_PCIMAIL0         (0x40 >> 2)      /* 0x140 */
+#define BONITO_PCIMAIL1         (0x44 >> 2)      /* 0x144 */
+#define BONITO_PCIMAIL2         (0x48 >> 2)      /* 0x148 */
+#define BONITO_PCIMAIL3         (0x4c >> 2)      /* 0x14c */
+
+/* 6. PCI cache */
+#define BONITO_PCICACHECTRL     (0x50 >> 2)      /* 0x150 */
+#define BONITO_PCICACHETAG      (0x54 >> 2)      /* 0x154 */
+#define BONITO_PCIBADADDR       (0x58 >> 2)      /* 0x158 */
+#define BONITO_PCIMSTAT         (0x5c >> 2)      /* 0x15c */
+
+/* 7. other*/
+#define BONITO_TIMECFG          (0x60 >> 2)      /* 0x160 */
+#define BONITO_CPUCFG           (0x64 >> 2)      /* 0x164 */
+#define BONITO_DQCFG            (0x68 >> 2)      /* 0x168 */
+#define BONITO_MEMSIZE          (0x6C >> 2)      /* 0x16c */
+
+#define BONITO_REGS             (0x70 >> 2)
+
+/* PCI config for south bridge. type 0 */
+#define BONITO_PCICONF_IDSEL_MASK      0xfffff800     /* [31:11] */
+#define BONITO_PCICONF_IDSEL_OFFSET    11
+#define BONITO_PCICONF_FUN_MASK        0x700    /* [10:8] */
+#define BONITO_PCICONF_FUN_OFFSET      8
+#define BONITO_PCICONF_REG_MASK        0xFC
+#define BONITO_PCICONF_REG_OFFSET      0
+
+
+/* idsel BIT = pci slot number +12 */
+#define PCI_SLOT_BASE              12
+#define PCI_IDSEL_VIA686B_BIT      (17)
+#define PCI_IDSEL_VIA686B          (1<<PCI_IDSEL_VIA686B_BIT)
+
+#define PCI_ADDR(busno,devno,funno,regno)  \
+    ((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
+
+typedef PCIHostState BonitoState;
+
+typedef struct PCIBonitoState
+{
+    PCIDevice dev;
+    BonitoState *pcihost;
+    uint32_t regs[BONITO_REGS];
+
+    struct bonldma {
+        uint32_t ldmactrl;
+        uint32_t ldmastat;
+        uint32_t ldmaaddr;
+        uint32_t ldmago;
+    } bonldma;
+
+    /* Based at 1fe00300, bonito Copier */
+    struct boncop {
+        uint32_t copctrl;
+        uint32_t copstat;
+        uint32_t coppaddr;
+        uint32_t copgo;
+    } boncop;
+
+    /* Bonito registers */
+    target_phys_addr_t bonito_reg_start;
+    target_phys_addr_t bonito_reg_length;
+    int bonito_reg_handle;
+
+    target_phys_addr_t bonito_pciconf_start;
+    target_phys_addr_t bonito_pciconf_length;
+    int bonito_pciconf_handle;
+
+    target_phys_addr_t bonito_spciconf_start;
+    target_phys_addr_t bonito_spciconf_length;
+    int bonito_spciconf_handle;
+
+    target_phys_addr_t bonito_pciio_start;
+    target_phys_addr_t bonito_pciio_length;
+    int bonito_pciio_handle;
+
+    target_phys_addr_t bonito_localio_start;
+    target_phys_addr_t bonito_localio_length;
+    int bonito_localio_handle;
+
+    target_phys_addr_t bonito_ldma_start;
+    target_phys_addr_t bonito_ldma_length;
+    int bonito_ldma_handle;
+
+    target_phys_addr_t bonito_cop_start;
+    target_phys_addr_t bonito_cop_length;
+    int bonito_cop_handle;
+
+} PCIBonitoState;
+
+PCIBonitoState * bonito_state;
+
+static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t saddr;
+    int reset = 0;
+
+    saddr = (addr - BONITO_REGBASE) >> 2;
+
+    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x \n", addr, val, saddr);
+    switch (saddr) {
+    case BONITO_BONPONCFG:
+    case BONITO_IODEVCFG:
+    case BONITO_SDCFG:
+    case BONITO_PCIMAP:
+    case BONITO_PCIMEMBASECFG:
+    case BONITO_PCIMAP_CFG:
+    case BONITO_GPIODATA:
+    case BONITO_GPIOIE:
+    case BONITO_INTEDGE:
+    case BONITO_INTSTEER:
+    case BONITO_INTPOL:
+    case BONITO_PCIMAIL0:
+    case BONITO_PCIMAIL1:
+    case BONITO_PCIMAIL2:
+    case BONITO_PCIMAIL3:
+    case BONITO_PCICACHECTRL:
+    case BONITO_PCICACHETAG:
+    case BONITO_PCIBADADDR:
+    case BONITO_PCIMSTAT:
+    case BONITO_TIMECFG:
+    case BONITO_CPUCFG:
+    case BONITO_DQCFG:
+    case BONITO_MEMSIZE:
+        s->regs[saddr] = val;
+        break;
+    case BONITO_BONGENCFG:
+        if (!(s->regs[saddr] & 0x04) && (val & 0x04)) {
+            reset = 1; /* bit 2 jump from 0 to 1 cause reset */
+        }
+        s->regs[saddr] = val;
+        if (reset) {
+            qemu_system_reset_request();
+        }
+        break;
+    case BONITO_INTENSET:
+        s->regs[BONITO_INTENSET] = val;
+        s->regs[BONITO_INTEN] |= val;
+        break;
+    case BONITO_INTENCLR:
+        s->regs[BONITO_INTENCLR] = val;
+        s->regs[BONITO_INTEN] &= ~val;
+        break;
+    case BONITO_INTEN:
+    case BONITO_INTISR:
+        DPRINTF("write to readonly bonito register %x \n", saddr);
+        break;
+    default:
+        DPRINTF("write to unknown bonito register %x \n", saddr);
+        break;
+    }
+}
+
+static uint32_t bonito_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - BONITO_REGBASE) >> 2;
+
+    DPRINTF("bonito_readl "TARGET_FMT_plx"  \n", addr);
+    switch (saddr) {
+    case BONITO_INTISR:
+        return s->regs[saddr];
+    default:
+        return s->regs[saddr];
+    }
+}
+
+static CPUWriteMemoryFunc * const bonito_write[] = {
+    NULL,
+    NULL,
+    bonito_writel,
+};
+
+static CPUReadMemoryFunc * const bonito_read[] = {
+    NULL,
+    NULL,
+    bonito_readl,
+};
+
+static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+
+    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    s->dev.config_write(&s->dev, addr, val, 4);
+}
+
+static uint32_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr)
+{
+
+    PCIBonitoState *s = opaque;
+
+    DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
+    return s->dev.config_read(&s->dev, addr, 4);
+}
+
+/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
+static CPUWriteMemoryFunc * const bonito_pciconf_write[] = {
+    NULL,
+    NULL,
+    bonito_pciconf_writel,
+};
+
+static CPUReadMemoryFunc * const bonito_pciconf_read[] = {
+    NULL,
+    NULL,
+    bonito_pciconf_readl,
+};
+
+static uint32_t bonito_ldma_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    PCIBonitoState *s = opaque;
+
+    val = ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)];
+
+    return val;
+}
+
+static void bonito_ldma_writel(void *opaque, target_phys_addr_t addr,
+                               uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+
+    ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)] = val & 0xffffffff;
+}
+
+static CPUWriteMemoryFunc * const bonito_ldma_write[] = {
+    NULL,
+    NULL,
+    bonito_ldma_writel,
+};
+
+static CPUReadMemoryFunc * const bonito_ldma_read[] = {
+    NULL,
+    NULL,
+    bonito_ldma_readl,
+};
+
+static uint32_t bonito_cop_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    PCIBonitoState *s = opaque;
+
+    val = ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)];
+
+    return val;
+}
+
+static void bonito_cop_writel(void *opaque, target_phys_addr_t addr,
+                              uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+
+    ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)] = val & 0xffffffff;
+}
+
+static CPUWriteMemoryFunc * const bonito_cop_write[] = {
+    NULL,
+    NULL,
+    bonito_cop_writel,
+};
+
+static CPUReadMemoryFunc * const bonito_cop_read[] = {
+    NULL,
+    NULL,
+    bonito_cop_readl,
+};
+
+static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t cfgaddr;
+    uint32_t idsel;
+    uint32_t devno;
+    uint32_t funno;
+    uint32_t regno;
+    uint32_t pciaddr;
+
+    /* support type0 pci config */
+    if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) {
+        return 0xffffffff;
+    }
+
+    cfgaddr = addr & 0xffff;
+    cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;
+
+    idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;
+    devno = ffs(idsel) - 1;
+    funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;
+    regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
+
+    if (idsel == 0) {
+        fprintf(stderr, "error in bonito pci config address" TARGET_FMT_plx
+            ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
+        exit(1);
+    }
+    pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno);
+    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d \n",
+        cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno);
+
+    return pciaddr;
+}
+
+static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x \n", addr, val);
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val & 0xff, 1);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+}
+
+static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x \n", addr, val);
+    assert((addr&0x1)==0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 2);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+}
+
+static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    assert((addr&0x3)==0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 4);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+}
+
+static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"  \n", addr);
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xff;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+
+    return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 1);
+}
+
+static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"  \n", addr);
+    assert((addr&0x1)==0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xffff;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+
+    return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 2);
+}
+
+static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"  \n", addr);
+    assert((addr&0x3) == 0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xffffffff;
+    }
+
+    /* set the pci address in s->config_reg */
+    s->pcihost->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(s->dev.config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(s->dev.config + PCI_STATUS, status);
+
+    return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 4);
+}
+
+/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
+static CPUWriteMemoryFunc * const bonito_spciconf_write[] = {
+    bonito_spciconf_writeb,
+    bonito_spciconf_writew,
+    bonito_spciconf_writel,
+};
+
+static CPUReadMemoryFunc * const bonito_spciconf_read[] = {
+    bonito_spciconf_readb,
+    bonito_spciconf_readw,
+    bonito_spciconf_readl,
+};
+
+#define BONITO_IRQ_BASE 32
+
+static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+    int internal_irq = irq_num - BONITO_IRQ_BASE;
+
+    if (bonito_state->regs[BONITO_INTEDGE] & (1<<internal_irq)) {
+        qemu_irq_pulse(*pic);
+    } else {   /* level triggered */
+        if (bonito_state->regs[BONITO_INTPOL] & (1<<internal_irq)) {
+            qemu_irq_raise(*pic);
+        } else {
+            qemu_irq_lower(*pic);
+        }
+    }
+}
+
+/* map the original irq (0~3) to bonito irq (16~47, but 16~31 are unused) */
+static int pci_bonito_map_irq(PCIDevice * pci_dev, int irq_num)
+{
+    int slot;
+
+    slot = (pci_dev->devfn >> 3);
+
+    switch (slot) {
+    case 5:   /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
+        return irq_num % 4 + BONITO_IRQ_BASE;
+    case 6:   /* FULONG2E_ATI_SLOT, VGA */
+        return 4 + BONITO_IRQ_BASE;
+    case 7:   /* FULONG2E_RTL_SLOT, RTL8139 */
+        return 5 + BONITO_IRQ_BASE;
+    case 8 ... 12: /* PCI slot 1 to 4 */
+        return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE;
+    default:  /* Unknown device, don't do any translation */
+        return irq_num;
+    }
+}
+
+static void bonito_reset(void *opaque)
+{
+    PCIBonitoState *s = opaque;
+
+    /* set the default value of north bridge registers */
+
+    s->regs[BONITO_BONPONCFG] = 0xc40;
+    s->regs[BONITO_BONGENCFG] = 0x1384;
+    s->regs[BONITO_IODEVCFG] = 0x2bff8010;
+    s->regs[BONITO_SDCFG] = 0x255e0091;
+
+    s->regs[BONITO_GPIODATA] = 0x1ff;
+    s->regs[BONITO_GPIOIE] = 0x1ff;
+    s->regs[BONITO_DQCFG] = 0x8;
+    s->regs[BONITO_MEMSIZE] = 0x10000000;
+    s->regs[BONITO_PCIMAP] = 0x6140;
+}
+
+static const VMStateDescription vmstate_bonito = {
+    .name = "Bonito",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIBonitoState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bonito_pcihost_initfn(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static int bonito_initfn(PCIDevice *dev)
+{
+    PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
+
+    /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
+    pci_config_set_prog_interface(dev->config, 0x00);
+
+    /* set the north bridge register mapping */
+    s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s,
+                                                  DEVICE_NATIVE_ENDIAN);
+    s->bonito_reg_start = BONITO_INTERNAL_REG_BASE;
+    s->bonito_reg_length = BONITO_INTERNAL_REG_SIZE;
+    cpu_register_physical_memory(s->bonito_reg_start, s->bonito_reg_length,
+                                 s->bonito_reg_handle);
+
+    /* set the north bridge pci configure  mapping */
+    s->bonito_pciconf_handle = cpu_register_io_memory(bonito_pciconf_read,
+                                                      bonito_pciconf_write, s,
+                                                      DEVICE_NATIVE_ENDIAN);
+    s->bonito_pciconf_start = BONITO_PCICONFIG_BASE;
+    s->bonito_pciconf_length = BONITO_PCICONFIG_SIZE;
+    cpu_register_physical_memory(s->bonito_pciconf_start, s->bonito_pciconf_length,
+                                 s->bonito_pciconf_handle);
+
+    /* set the south bridge pci configure  mapping */
+    s->bonito_spciconf_handle = cpu_register_io_memory(bonito_spciconf_read,
+                                                       bonito_spciconf_write, s,
+                                                       DEVICE_NATIVE_ENDIAN);
+    s->bonito_spciconf_start = BONITO_SPCICONFIG_BASE;
+    s->bonito_spciconf_length = BONITO_SPCICONFIG_SIZE;
+    cpu_register_physical_memory(s->bonito_spciconf_start, s->bonito_spciconf_length,
+                                 s->bonito_spciconf_handle);
+
+    s->bonito_ldma_handle = cpu_register_io_memory(bonito_ldma_read,
+                                                   bonito_ldma_write, s,
+                                                   DEVICE_NATIVE_ENDIAN);
+    s->bonito_ldma_start = 0xbfe00200;
+    s->bonito_ldma_length = 0x100;
+    cpu_register_physical_memory(s->bonito_ldma_start, s->bonito_ldma_length,
+                                 s->bonito_ldma_handle);
+
+    s->bonito_cop_handle = cpu_register_io_memory(bonito_cop_read,
+                                                  bonito_cop_write, s,
+                                                  DEVICE_NATIVE_ENDIAN);
+    s->bonito_cop_start = 0xbfe00300;
+    s->bonito_cop_length = 0x100;
+    cpu_register_physical_memory(s->bonito_cop_start, s->bonito_cop_length,
+                                 s->bonito_cop_handle);
+
+    /* Map PCI IO Space  0x1fd0 0000 - 0x1fd1 0000 */
+    s->bonito_pciio_start = BONITO_PCIIO_BASE;
+    s->bonito_pciio_length = BONITO_PCIIO_SIZE;
+    isa_mem_base = s->bonito_pciio_start;
+    isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length);
+
+    /* add pci local io mapping */
+    s->bonito_localio_start = BONITO_DEV_BASE;
+    s->bonito_localio_length = BONITO_DEV_SIZE;
+    isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length);
+
+    /* set the default value of north bridge pci config */
+    pci_set_word(dev->config + PCI_COMMAND, 0x0000);
+    pci_set_word(dev->config + PCI_STATUS, 0x0000);
+    pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0000);
+    pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x0000);
+
+    pci_set_byte(dev->config + PCI_INTERRUPT_LINE, 0x00);
+    pci_set_byte(dev->config + PCI_INTERRUPT_PIN, 0x01);
+    pci_set_byte(dev->config + PCI_MIN_GNT, 0x3c);
+    pci_set_byte(dev->config + PCI_MAX_LAT, 0x00);
+
+    qemu_register_reset(bonito_reset, s);
+
+    return 0;
+}
+
+PCIBus *bonito_init(qemu_irq *pic)
+{
+    DeviceState *dev;
+    PCIBus *b;
+    BonitoState *pcihost;
+    PCIBonitoState *s;
+    PCIDevice *d;
+
+    dev = qdev_create(NULL, "Bonito-pcihost");
+    pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
+    b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
+                         pci_bonito_map_irq, pic, 0x28, 32);
+    pcihost->bus = b;
+    qdev_init_nofail(dev);
+
+    d = pci_create_simple(b, PCI_DEVFN(0, 0), "Bonito");
+    s = DO_UPCAST(PCIBonitoState, dev, d);
+    s->pcihost = pcihost;
+    bonito_state = s;
+
+    return b;
+}
+
+static PCIDeviceInfo bonito_info = {
+    .qdev.name    = "Bonito",
+    .qdev.desc    = "Host bridge",
+    .qdev.size    = sizeof(PCIBonitoState),
+    .qdev.vmsd    = &vmstate_bonito,
+    .qdev.no_user = 1,
+    .init         = bonito_initfn,
+    /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
+    .vendor_id    = 0xdf53,
+    .device_id    = 0x00d5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_BRIDGE_HOST,
+};
+
+static SysBusDeviceInfo bonito_pcihost_info = {
+    .init         = bonito_pcihost_initfn,
+    .qdev.name    = "Bonito-pcihost",
+    .qdev.size    = sizeof(BonitoState),
+    .qdev.no_user = 1,
+};
+
+static void bonito_register(void)
+{
+    sysbus_register_withprop(&bonito_pcihost_info);
+    pci_qdev_register(&bonito_info);
+}
+device_init(bonito_register);
diff --git a/qemu-0.15.x/hw/bt-hci-csr.c b/qemu-0.15.x/hw/bt-hci-csr.c
new file mode 100644
index 0000000..d135ef4
--- /dev/null
+++ b/qemu-0.15.x/hw/bt-hci-csr.c
@@ -0,0 +1,453 @@
+/*
+ * Bluetooth serial HCI transport.
+ * CSR41814 HCI with H4p vendor extensions.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+#include "irq.h"
+#include "net.h"
+#include "bt.h"
+
+struct csrhci_s {
+    int enable;
+    qemu_irq *pins;
+    int pin_state;
+    int modem_state;
+    CharDriverState chr;
+#define FIFO_LEN	4096
+    int out_start;
+    int out_len;
+    int out_size;
+    uint8_t outfifo[FIFO_LEN * 2];
+    uint8_t inpkt[FIFO_LEN];
+    int in_len;
+    int in_hdr;
+    int in_data;
+    QEMUTimer *out_tm;
+    int64_t baud_delay;
+
+    bdaddr_t bd_addr;
+    struct HCIInfo *hci;
+};
+
+/* H4+ packet types */
+enum {
+    H4_CMD_PKT   = 1,
+    H4_ACL_PKT   = 2,
+    H4_SCO_PKT   = 3,
+    H4_EVT_PKT   = 4,
+    H4_NEG_PKT   = 6,
+    H4_ALIVE_PKT = 7,
+};
+
+/* CSR41814 negotiation start magic packet */
+static const uint8_t csrhci_neg_packet[] = {
+    H4_NEG_PKT, 10,
+    0x00, 0xa0, 0x01, 0x00, 0x00,
+    0x4c, 0x00, 0x96, 0x00, 0x00,
+};
+
+/* CSR41814 vendor-specific command OCFs */
+enum {
+    OCF_CSR_SEND_FIRMWARE = 0x000,
+};
+
+static inline void csrhci_fifo_wake(struct csrhci_s *s)
+{
+    if (!s->enable || !s->out_len)
+        return;
+
+    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
+    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
+                    s->chr.chr_read) {
+        s->chr.chr_read(s->chr.handler_opaque,
+                        s->outfifo + s->out_start ++, 1);
+        s->out_len --;
+        if (s->out_start >= s->out_size) {
+            s->out_start = 0;
+            s->out_size = FIFO_LEN;
+        }
+    }
+
+    if (s->out_len)
+        qemu_mod_timer(s->out_tm, qemu_get_clock_ns(vm_clock) + s->baud_delay);
+}
+
+#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
+static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
+{
+    int off = s->out_start + s->out_len;
+
+    /* TODO: do the padding here, i.e. align len */
+    s->out_len += len;
+
+    if (off < FIFO_LEN) {
+        if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
+            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+            exit(-1);
+        }
+        return s->outfifo + off;
+    }
+
+    if (s->out_len > s->out_size) {
+        fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+        exit(-1);
+    }
+
+    return s->outfifo + off - s->out_size;
+}
+
+static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
+                int type, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s, len + 2);
+
+    *ret ++ = type;
+    *ret ++ = len;
+
+    return ret;
+}
+
+static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
+                int evt, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s,
+                    len + 1 + sizeof(struct hci_event_hdr));
+
+    *ret ++ = H4_EVT_PKT;
+    ((struct hci_event_hdr *) ret)->evt = evt;
+    ((struct hci_event_hdr *) ret)->plen = len;
+
+    return ret + sizeof(struct hci_event_hdr);
+}
+
+static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
+                uint8_t *data, int len)
+{
+    int offset;
+    uint8_t *rpkt;
+
+    switch (ocf) {
+    case OCF_CSR_SEND_FIRMWARE:
+        /* Check if this is the bd_address packet */
+        if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
+            offset = 18;
+            s->bd_addr.b[0] = data[offset + 7];	/* Beyond cmd packet end(!?) */
+            s->bd_addr.b[1] = data[offset + 6];
+            s->bd_addr.b[2] = data[offset + 4];
+            s->bd_addr.b[3] = data[offset + 0];
+            s->bd_addr.b[4] = data[offset + 3];
+            s->bd_addr.b[5] = data[offset + 2];
+
+            s->hci->bdaddr_set(s->hci, s->bd_addr.b);
+            fprintf(stderr, "%s: bd_address loaded from firmware: "
+                            "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
+                            s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
+                            s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
+        }
+
+        rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
+        /* Status bytes: no error */
+        rpkt[9] = 0x00;
+        rpkt[10] = 0x00;
+        break;
+
+    default:
+        fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
+        return;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
+{
+    uint8_t *rpkt;
+    int opc;
+
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
+        if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
+            csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
+                            pkt + sizeof(struct hci_command_hdr),
+                            s->in_len - sizeof(struct hci_command_hdr) - 1);
+            return;
+        }
+
+        /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
+         * we need to send it to the HCI layer and then add our supported
+         * commands to the returned mask (such as OGF_VENDOR_CMD).  With
+         * bt-hci.c we could just have hooks for this kind of commands but
+         * we can't with bt-host.c.  */
+
+        s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_EVT_PKT:
+        goto bad_pkt;
+
+    case H4_ACL_PKT:
+        s->hci->acl_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_SCO_PKT:
+        s->hci->sco_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_NEG_PKT:
+        if (s->in_hdr != sizeof(csrhci_neg_packet) ||
+                        memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
+            fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
+            return;
+        }
+        pkt += 2;
+
+        rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
+
+        *rpkt ++ = 0x20;	/* Operational settings negotation Ok */
+        memcpy(rpkt, pkt, 7); rpkt += 7;
+        *rpkt ++ = 0xff;
+        *rpkt = 0xff;
+        break;
+
+    case H4_ALIVE_PKT:
+        if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
+            fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
+            return;
+        }
+
+        rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
+
+        *rpkt ++ = 0xcc;
+        *rpkt = 0x00;
+        break;
+
+    default:
+    bad_pkt:
+        /* TODO: error out */
+        fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
+        break;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_header_len(const uint8_t *pkt)
+{
+    switch (pkt[0]) {
+    case H4_CMD_PKT:
+        return HCI_COMMAND_HDR_SIZE;
+    case H4_EVT_PKT:
+        return HCI_EVENT_HDR_SIZE;
+    case H4_ACL_PKT:
+        return HCI_ACL_HDR_SIZE;
+    case H4_SCO_PKT:
+        return HCI_SCO_HDR_SIZE;
+    case H4_NEG_PKT:
+        return pkt[1] + 1;
+    case H4_ALIVE_PKT:
+        return 3;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_data_len(const uint8_t *pkt)
+{
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        /* It seems that vendor-specific command packets for H4+ are all
+         * one byte longer than indicated in the standard header.  */
+        if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
+            return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
+
+        return ((struct hci_command_hdr *) pkt)->plen;
+    case H4_EVT_PKT:
+        return ((struct hci_event_hdr *) pkt)->plen;
+    case H4_ACL_PKT:
+        return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
+    case H4_SCO_PKT:
+        return ((struct hci_sco_hdr *) pkt)->dlen;
+    case H4_NEG_PKT:
+    case H4_ALIVE_PKT:
+        return 0;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_write(struct CharDriverState *chr,
+                const uint8_t *buf, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int plen = s->in_len;
+
+    if (!s->enable)
+        return 0;
+
+    s->in_len += len;
+    memcpy(s->inpkt + plen, buf, len);
+
+    while (1) {
+        if (s->in_len >= 2 && plen < 2)
+            s->in_hdr = csrhci_header_len(s->inpkt) + 1;
+
+        if (s->in_len >= s->in_hdr && plen < s->in_hdr)
+            s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr;
+
+        if (s->in_len >= s->in_data) {
+            csrhci_in_packet(s, s->inpkt);
+
+            memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data);
+            s->in_len -= s->in_data;
+            s->in_hdr = INT_MAX;
+            s->in_data = INT_MAX;
+            plen = 0;
+        } else
+            break;
+    }
+
+    return len;
+}
+
+static void csrhci_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);	/* Align */
+
+    *pkt ++ = H4_EVT_PKT;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);	/* Align */
+
+    *pkt ++ = H4_ACL_PKT;
+    pkt[len & ~1] = 0;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
+{
+    QEMUSerialSetParams *ssp;
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int prev_state = s->modem_state;
+
+    switch (cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        ssp = (QEMUSerialSetParams *) arg;
+        s->baud_delay = get_ticks_per_sec() / ssp->speed;
+        /* Moments later... (but shorter than 100ms) */
+        s->modem_state |= CHR_TIOCM_CTS;
+        break;
+
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        *(int *) arg = s->modem_state;
+        break;
+
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        s->modem_state = *(int *) arg;
+        if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
+            s->modem_state &= ~CHR_TIOCM_CTS;
+        break;
+
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void csrhci_reset(struct csrhci_s *s)
+{
+    s->out_len = 0;
+    s->out_size = FIFO_LEN;
+    s->in_len = 0;
+    s->baud_delay = get_ticks_per_sec();
+    s->enable = 0;
+    s->in_hdr = INT_MAX;
+    s->in_data = INT_MAX;
+
+    s->modem_state = 0;
+    /* After a while... (but sooner than 10ms) */
+    s->modem_state |= CHR_TIOCM_CTS;
+
+    memset(&s->bd_addr, 0, sizeof(bdaddr_t));
+}
+
+static void csrhci_out_tick(void *opaque)
+{
+    csrhci_fifo_wake((struct csrhci_s *) opaque);
+}
+
+static void csrhci_pins(void *opaque, int line, int level)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    int state = s->pin_state;
+
+    s->pin_state &= ~(1 << line);
+    s->pin_state |= (!!level) << line;
+
+    if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
+        /* TODO: Disappear from lower layers */
+        csrhci_reset(s);
+    }
+
+    if (s->pin_state == 3 && state != 3) {
+        s->enable = 1;
+        /* TODO: Wake lower layers up */
+    }
+}
+
+qemu_irq *csrhci_pins_get(CharDriverState *chr)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+
+    return s->pins;
+}
+
+CharDriverState *uart_hci_init(qemu_irq wakeup)
+{
+    struct csrhci_s *s = (struct csrhci_s *)
+            qemu_mallocz(sizeof(struct csrhci_s));
+
+    s->chr.opaque = s;
+    s->chr.chr_write = csrhci_write;
+    s->chr.chr_ioctl = csrhci_ioctl;
+
+    s->hci = qemu_next_hci();
+    s->hci->opaque = s;
+    s->hci->evt_recv = csrhci_out_hci_packet_event;
+    s->hci->acl_recv = csrhci_out_hci_packet_acl;
+
+    s->out_tm = qemu_new_timer_ns(vm_clock, csrhci_out_tick, s);
+    s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
+    csrhci_reset(s);
+
+    return &s->chr;
+}
diff --git a/qemu-0.15.x/hw/bt-hci.c b/qemu-0.15.x/hw/bt-hci.c
new file mode 100644
index 0000000..41df24c
--- /dev/null
+++ b/qemu-0.15.x/hw/bt-hci.c
@@ -0,0 +1,2221 @@
+/*
+ * QEMU Bluetooth HCI logic.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "net.h"
+#include "bt.h"
+
+struct bt_hci_s {
+    uint8_t *(*evt_packet)(void *opaque);
+    void (*evt_submit)(void *opaque, int len);
+    void *opaque;
+    uint8_t evt_buf[256];
+
+    uint8_t acl_buf[4096];
+    int acl_len;
+
+    uint16_t asb_handle;
+    uint16_t psb_handle;
+
+    int last_cmd;	/* Note: Always little-endian */
+
+    struct bt_device_s *conn_req_host;
+
+    struct {
+        int inquire;
+        int periodic;
+        int responses_left;
+        int responses;
+        QEMUTimer *inquiry_done;
+        QEMUTimer *inquiry_next;
+        int inquiry_length;
+        int inquiry_period;
+        int inquiry_mode;
+
+#define HCI_HANDLE_OFFSET	0x20
+#define HCI_HANDLES_MAX		0x10
+        struct bt_hci_master_link_s {
+            struct bt_link_s *link;
+            void (*lmp_acl_data)(struct bt_link_s *link,
+                            const uint8_t *data, int start, int len);
+            QEMUTimer *acl_mode_timer;
+        } handle[HCI_HANDLES_MAX];
+        uint32_t role_bmp;
+        int last_handle;
+        int connecting;
+        bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX];
+    } lm;
+
+    uint8_t event_mask[8];
+    uint16_t voice_setting;	/* Notw: Always little-endian */
+    uint16_t conn_accept_tout;
+    QEMUTimer *conn_accept_timer;
+
+    struct HCIInfo info;
+    struct bt_device_s device;
+};
+
+#define DEFAULT_RSSI_DBM	20
+
+#define hci_from_info(ptr)	container_of((ptr), struct bt_hci_s, info)
+#define hci_from_device(ptr)	container_of((ptr), struct bt_hci_s, device)
+
+struct bt_hci_link_s {
+    struct bt_link_s btlink;
+    uint16_t handle;	/* Local */
+};
+
+/* LMP layer emulation */
+#if 0
+static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data)
+{
+    int resp, resplen, error, op, tr;
+    uint8_t respdata[17];
+
+    if (length < 1)
+        return;
+
+    tr = *data & 1;
+    op = *(data ++) >> 1;
+    resp = LMP_ACCEPTED;
+    resplen = 2;
+    respdata[1] = op;
+    error = 0;
+    length --;
+
+    if (op >= 0x7c) {	/* Extended opcode */
+        op |= *(data ++) << 8;
+        resp = LMP_ACCEPTED_EXT;
+        resplen = 4;
+        respdata[0] = op >> 8;
+        respdata[1] = op & 0xff;
+        length --;
+    }
+
+    switch (op) {
+    case LMP_ACCEPTED:
+        /* data[0]	Op code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_ACCEPTED_EXT:
+        /* data[0]	Escape op code
+         * data[1]	Extended op code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED:
+        /* data[0]	Op code
+         * data[1]	Error code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED_EXT:
+        /* data[0]	Op code
+         * data[1]	Extended op code
+         * data[2]	Error code
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_HOST_CONNECTION_REQ:
+        break;
+
+    case LMP_SETUP_COMPLETE:
+        resp = LMP_SETUP_COMPLETE;
+        resplen = 1;
+        bt->setup = 1;
+        break;
+
+    case LMP_DETACH:
+        /* data[0]	Error code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        bt->setup = 0;
+        resp = 0;
+        break;
+
+    case LMP_SUPERVISION_TIMEOUT:
+        /* data[0,1]	Supervision timeout
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_QUALITY_OF_SERVICE:
+        resp = 0;
+        /* Fall through */
+    case LMP_QOS_REQ:
+        /* data[0,1]	Poll interval
+         * data[2]	N(BC)
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_MAX_SLOT:
+        resp = 0;
+        /* Fall through */
+    case LMP_MAX_SLOT_REQ:
+        /* data[0]	Max slots
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_AU_RAND:
+    case LMP_IN_RAND:
+    case LMP_COMB_KEY:
+        /* data[0-15]	Random number
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_AU_RAND) {
+            if (bt->key_present) {
+                resp = LMP_SRES;
+                resplen = 5;
+                /* XXX: [Part H] Section 6.1 on page 801 */
+            } else {
+                error = HCI_PIN_OR_KEY_MISSING;
+                goto not_accepted;
+            }
+        } else if (op == LMP_IN_RAND) {
+            error = HCI_PAIRING_NOT_ALLOWED;
+            goto not_accepted;
+        } else {
+            /* XXX: [Part H] Section 3.2 on page 779 */
+            resp = LMP_UNIT_KEY;
+            resplen = 17;
+            memcpy(respdata + 1, bt->key, 16);
+
+            error = HCI_UNIT_LINK_KEY_USED;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_UNIT_KEY:
+        /* data[0-15]	Key
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        memcpy(bt->key, data, 16);
+        bt->key_present = 1;
+        break;
+
+    case LMP_SRES:
+        /* data[0-3]	Authentication response
+         */
+        if (length < 4) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_CLKOFFSET_REQ:
+        resp = LMP_CLKOFFSET_RES;
+        resplen = 3;
+        respdata[1] = 0x33;
+        respdata[2] = 0x33;
+        break;
+
+    case LMP_CLKOFFSET_RES:
+        /* data[0,1]	Clock offset
+         * (Slave to master only)
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_VERSION_REQ:
+    case LMP_VERSION_RES:
+        /* data[0]	VersNr
+         * data[1,2]	CompId
+         * data[3,4]	SubVersNr
+         */
+        if (length < 5) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_VERSION_REQ) {
+            resp = LMP_VERSION_RES;
+            resplen = 6;
+            respdata[1] = 0x20;
+            respdata[2] = 0xff;
+            respdata[3] = 0xff;
+            respdata[4] = 0xff;
+            respdata[5] = 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_FEATURES_REQ:
+    case LMP_FEATURES_RES:
+        /* data[0-7]	Features
+         */
+        if (length < 8) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_FEATURES_REQ) {
+            resp = LMP_FEATURES_RES;
+            resplen = 9;
+            respdata[1] = (bt->lmp_caps >> 0) & 0xff;
+            respdata[2] = (bt->lmp_caps >> 8) & 0xff;
+            respdata[3] = (bt->lmp_caps >> 16) & 0xff;
+            respdata[4] = (bt->lmp_caps >> 24) & 0xff;
+            respdata[5] = (bt->lmp_caps >> 32) & 0xff;
+            respdata[6] = (bt->lmp_caps >> 40) & 0xff;
+            respdata[7] = (bt->lmp_caps >> 48) & 0xff;
+            respdata[8] = (bt->lmp_caps >> 56) & 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_NAME_REQ:
+        /* data[0]	Name offset
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = LMP_NAME_RES;
+        resplen = 17;
+        respdata[1] = data[0];
+        respdata[2] = strlen(bt->lmp_name);
+        memset(respdata + 3, 0x00, 14);
+        if (respdata[2] > respdata[1])
+            memcpy(respdata + 3, bt->lmp_name + respdata[1],
+                            respdata[2] - respdata[1]);
+        break;
+
+    case LMP_NAME_RES:
+        /* data[0]	Name offset
+         * data[1]	Name length
+         * data[2-15]	Name fragment
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    default:
+        error = HCI_UNKNOWN_LMP_PDU;
+        /* Fall through */
+    not_accepted:
+        if (op >> 8) {
+            resp = LMP_NOT_ACCEPTED_EXT;
+            resplen = 5;
+            respdata[0] = op >> 8;
+            respdata[1] = op & 0xff;
+            respdata[2] = error;
+        } else {
+            resp = LMP_NOT_ACCEPTED;
+            resplen = 3;
+            respdata[0] = op & 0xff;
+            respdata[1] = error;
+        }
+    }
+
+    if (resp == 0)
+        return;
+
+    if (resp >> 8) {
+        respdata[0] = resp >> 8;
+        respdata[1] = resp & 0xff;
+    } else
+        respdata[0] = resp & 0xff;
+
+    respdata[0] <<= 1;
+    respdata[0] |= tr;
+}
+
+static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data)
+{
+    struct bt_device_s *slave;
+    if (length < 1)
+        return;
+
+    slave = 0;
+#if 0
+    slave = net->slave;
+#endif
+
+    switch (data[0] & 3) {
+    case LLID_ACLC:
+        bt_submit_lmp(slave, length - 1, data + 1);
+        break;
+    case LLID_ACLU_START:
+#if 0
+        bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1);
+        breka;
+#endif
+    default:
+    case LLID_ACLU_CONT:
+        break;
+    }
+}
+#endif
+
+/* HCI layer emulation */
+
+/* Note: we could ignore endiannes because unswapped handles will still
+ * be valid as connection identifiers for the guest - they don't have to
+ * be continuously allocated.  We do it though, to preserve similar
+ * behaviour between hosts.  Some things, like the BD_ADDR cannot be
+ * preserved though (for example if a real hci is used).  */
+#ifdef HOST_WORDS_BIGENDIAN
+# define HNDL(raw)	bswap16(raw)
+#else
+# define HNDL(raw)	(raw)
+#endif
+
+static const uint8_t bt_event_reserved_mask[8] = {
+    0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00,
+};
+
+static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
+                int evt, int len)
+{
+    uint8_t *packet, mask;
+    int mask_byte;
+
+    if (len > 255) {
+        fprintf(stderr, "%s: HCI event params too long (%ib)\n",
+                        __FUNCTION__, len);
+        exit(-1);
+    }
+
+    mask_byte = (evt - 1) >> 3;
+    mask = 1 << ((evt - 1) & 3);
+    if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte])
+        return NULL;
+
+    packet = hci->evt_packet(hci->opaque);
+    packet[0] = evt;
+    packet[1] = len;
+
+    return &packet[2];
+}
+
+static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
+                void *params, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, evt, len);
+
+    if (!packet)
+        return;
+
+    if (len)
+        memcpy(packet, params, len);
+
+    hci->evt_submit(hci->opaque, len + 2);
+}
+
+static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
+{
+    evt_cmd_status params = {
+        .status	= status,
+        .ncmd	= 1,
+        .opcode	= hci->last_cmd,
+    };
+
+    bt_hci_event(hci, EVT_CMD_STATUS, &params, EVT_CMD_STATUS_SIZE);
+}
+
+static inline void bt_hci_event_complete(struct bt_hci_s *hci,
+                void *ret, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
+                    len + EVT_CMD_COMPLETE_SIZE);
+    evt_cmd_complete *params = (evt_cmd_complete *) packet;
+
+    if (!packet)
+        return;
+
+    params->ncmd	= 1;
+    params->opcode	= hci->last_cmd;
+    if (len)
+        memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len);
+
+    hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2);
+}
+
+static void bt_hci_inquiry_done(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+    uint8_t status = HCI_SUCCESS;
+
+    if (!hci->lm.periodic)
+        hci->lm.inquire = 0;
+
+    /* The specification is inconsistent about this one.  Page 565 reads
+     * "The event parameters of Inquiry Complete event will have a summary
+     * of the result from the Inquiry process, which reports the number of
+     * nearby Bluetooth devices that responded [so hci->responses].", but
+     * Event Parameters (see page 729) has only Status.  */
+    bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1);
+}
+
+static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info params = {
+        .num_responses		= 1,
+        .bdaddr			= BAINIT(&slave->bd_addr),
+        .pscan_rep_mode		= 0x00,	/* R0 */
+        .pscan_period_mode	= 0x00,	/* P0 - deprecated */
+        .pscan_mode		= 0x00,	/* Standard scan - deprecated */
+        .dev_class[0]		= slave->class[0],
+        .dev_class[1]		= slave->class[1],
+        .dev_class[2]		= slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset		= slave->clkoff,	/* Note: no swapping */
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT, &params, INQUIRY_INFO_SIZE);
+}
+
+static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info_with_rssi params = {
+        .num_responses		= 1,
+        .bdaddr			= BAINIT(&slave->bd_addr),
+        .pscan_rep_mode		= 0x00,	/* R0 */
+        .pscan_period_mode	= 0x00,	/* P0 - deprecated */
+        .dev_class[0]		= slave->class[0],
+        .dev_class[1]		= slave->class[1],
+        .dev_class[2]		= slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset		= slave->clkoff,	/* Note: no swapping */
+        .rssi			= DEFAULT_RSSI_DBM,
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI,
+                    &params, INQUIRY_INFO_WITH_RSSI_SIZE);
+}
+
+static void bt_hci_inquiry_result(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    if (!slave->inquiry_scan || !hci->lm.responses_left)
+        return;
+
+    hci->lm.responses_left --;
+    hci->lm.responses ++;
+
+    switch (hci->lm.inquiry_mode) {
+    case 0x00:
+        bt_hci_inquiry_result_standard(hci, slave);
+        return;
+    case 0x01:
+        bt_hci_inquiry_result_with_rssi(hci, slave);
+        return;
+    default:
+        fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,
+                        hci->lm.inquiry_mode);
+        exit(-1);
+    }
+}
+
+static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
+{
+    qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) +
+                   muldiv64(period << 7, get_ticks_per_sec(), 100));
+}
+
+static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
+{
+    struct bt_device_s *slave;
+
+    hci->lm.inquiry_length = length;
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        /* Don't uncover ourselves.  */
+        if (slave != &hci->device)
+            bt_hci_inquiry_result(hci, slave);
+
+    /* TODO: register for a callback on a new device's addition to the
+     * scatternet so that if it's added before inquiry_length expires,
+     * an Inquiry Result is generated immediately.  Alternatively re-loop
+     * through the devices on the inquiry_length expiration and report
+     * devices not seen before.  */
+    if (hci->lm.responses_left)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length);
+    else
+        bt_hci_inquiry_done(hci);
+
+    if (hci->lm.periodic)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period);
+}
+
+static void bt_hci_inquiry_next(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    hci->lm.responses_left += hci->lm.responses;
+    hci->lm.responses = 0;
+    bt_hci_inquiry_start(hci,  hci->lm.inquiry_length);
+}
+
+static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !(handle & HCI_HANDLE_OFFSET) ||
+            handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) ||
+            !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+}
+
+static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET)));
+}
+
+static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+
+    return bt_hci_role_master(hci, handle) ? link->slave : link->host;
+}
+
+static void bt_hci_mode_tick(void *opaque);
+static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
+                struct bt_link_s *link, int master)
+{
+    hci->lm.handle[hci->lm.last_handle].link = link;
+
+    if (master) {
+        /* We are the master side of an ACL link */
+        hci->lm.role_bmp |= 1 << hci->lm.last_handle;
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->slave->lmp_acl_data;
+    } else {
+        /* We are the slave side of an ACL link */
+        hci->lm.role_bmp &= ~(1 << hci->lm.last_handle);
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->host->lmp_acl_resp;
+    }
+
+    /* Mode */
+    if (master) {
+        link->acl_mode = acl_active;
+        hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
+                qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link);
+    }
+}
+
+static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle)
+{
+    handle &= ~HCI_HANDLE_OFFSET;
+    hci->lm.handle[handle].link = NULL;
+
+    if (bt_hci_role_master(hci, handle)) {
+        qemu_del_timer(hci->lm.handle[handle].acl_mode_timer);
+        qemu_free_timer(hci->lm.handle[handle].acl_mode_timer);
+    }
+}
+
+static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    struct bt_link_s link;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave || slave == &hci->device)
+        return -ENODEV;
+
+    bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr);
+
+    link.slave = slave;
+    link.host = &hci->device;
+    link.slave->lmp_connection_request(&link);	/* Always last */
+
+    return 0;
+}
+
+static void bt_hci_connection_reject(struct bt_hci_s *hci,
+                struct bt_device_s *host, uint8_t because)
+{
+    struct bt_link_s link = {
+        .slave	= &hci->device,
+        .host	= host,
+        /* Rest uninitialised */
+    };
+
+    host->reject_reason = because;
+    host->lmp_connection_complete(&link);
+}
+
+static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    evt_conn_complete params;
+
+    params.status	= HCI_NO_CONNECTION;
+    params.handle	= 0;
+    bacpy(&params.bdaddr, bdaddr);
+    params.link_type	= ACL_LINK;
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_connection_accept(struct bt_hci_s *hci,
+                struct bt_device_s *host)
+{
+    struct bt_hci_link_s *link = qemu_mallocz(sizeof(struct bt_hci_link_s));
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        qemu_free(link);
+        bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    link->btlink.slave	= &hci->device;
+    link->btlink.host	= host;
+    link->handle = handle;
+
+    /* Link established */
+    bt_hci_lmp_link_establish(hci, &link->btlink, 0);
+
+complete:
+    params.status	= status;
+    params.handle	= HNDL(handle);
+    bacpy(&params.bdaddr, &host->bd_addr);
+    params.link_type	= ACL_LINK;
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+
+    /* Neets to be done at the very end because it can trigger a (nested)
+     * disconnected, in case the other and had cancelled the request
+     * locally.  */
+    if (status == HCI_SUCCESS) {
+        host->reject_reason = 0;
+        host->lmp_connection_complete(&link->btlink);
+    }
+}
+
+static void bt_hci_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->slave);
+    evt_conn_request params;
+
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci, link->host,
+                                 HCI_REJECTED_LIMITED_RESOURCES);
+        return;
+    }
+    hci->conn_req_host = link->host;
+    /* TODO: if masked and auto-accept, then auto-accept,
+     * if masked and not auto-accept, then auto-reject */
+    /* TODO: kick the hci->conn_accept_timer, timeout after
+     * hci->conn_accept_tout * 0.625 msec */
+
+    bacpy(&params.bdaddr, &link->host->bd_addr);
+    memcpy(&params.dev_class, &link->host->class, sizeof(params.dev_class));
+    params.link_type	= ACL_LINK;
+    bt_hci_event(hci, EVT_CONN_REQUEST, &params, EVT_CONN_REQUEST_SIZE);
+    return;
+}
+
+static void bt_hci_conn_accept_timeout(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    if (!hci->conn_req_host)
+        /* Already accepted or rejected.  If the other end cancelled the
+         * connection request then we still have to reject or accept it
+         * and then we'll get a disconnect.  */
+        return;
+
+    /* TODO */
+}
+
+/* Remove from the list of devices which we wanted to connect to and
+ * are awaiting a response from.  If the callback sees a response from
+ * a device which is not on the list it will assume it's a connection
+ * that's been cancelled by the host in the meantime and immediately
+ * try to detach the link and send a Connection Complete.  */
+static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    int i;
+
+    for (i = 0; i < hci->lm.connecting; i ++)
+        if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) {
+            if (i < -- hci->lm.connecting)
+                bacpy(&hci->lm.awaiting_bdaddr[i],
+                                &hci->lm.awaiting_bdaddr[hci->lm.connecting]);
+            return 0;
+        }
+
+    return 1;
+}
+
+static void bt_hci_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) {
+        if (!hci->device.reject_reason)
+            link->slave->lmp_disconnect_slave(link);
+        handle = 0;
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    if (hci->device.reject_reason) {
+        handle = 0;
+        status = hci->device.reject_reason;
+        goto complete;
+    }
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        link->slave->lmp_disconnect_slave(link);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    /* Link established */
+    link->handle = handle;
+    bt_hci_lmp_link_establish(hci, link, 1);
+
+complete:
+    params.status	= status;
+    params.handle	= HNDL(handle);
+    params.link_type	= ACL_LINK;
+    bacpy(&params.bdaddr, &link->slave->bd_addr);
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_disconnect(struct bt_hci_s *hci,
+                uint16_t handle, int reason)
+{
+    struct bt_link_s *btlink =
+            hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+    struct bt_hci_link_s *link;
+    evt_disconn_complete params;
+
+    if (bt_hci_role_master(hci, handle)) {
+        btlink->slave->reject_reason = reason;
+        btlink->slave->lmp_disconnect_slave(btlink);
+        /* The link pointer is invalid from now on */
+
+        goto complete;
+    }
+
+    btlink->host->reject_reason = reason;
+    btlink->host->lmp_disconnect_master(btlink);
+
+    /* We are the slave, we get to clean this burden */
+    link = (struct bt_hci_link_s *) btlink;
+    qemu_free(link);
+
+complete:
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= HCI_CONNECTION_TERMINATED;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+/* TODO: use only one function */
+static void bt_hci_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    qemu_free(link);
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    evt_remote_name_req_complete params;
+    int len;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave)
+        return -ENODEV;
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status       = HCI_SUCCESS;
+    bacpy(&params.bdaddr, &slave->bd_addr);
+    len = snprintf(params.name, sizeof(params.name),
+                    "%s", slave->lmp_name ?: "");
+    memset(params.name + len, 0, sizeof(params.name) - len);
+    bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE,
+                    &params, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_remote_features_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.features[0]	= (slave->lmp_caps >>  0) & 0xff;
+    params.features[1]	= (slave->lmp_caps >>  8) & 0xff;
+    params.features[2]	= (slave->lmp_caps >> 16) & 0xff;
+    params.features[3]	= (slave->lmp_caps >> 24) & 0xff;
+    params.features[4]	= (slave->lmp_caps >> 32) & 0xff;
+    params.features[5]	= (slave->lmp_caps >> 40) & 0xff;
+    params.features[6]	= (slave->lmp_caps >> 48) & 0xff;
+    params.features[7]	= (slave->lmp_caps >> 56) & 0xff;
+    bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    evt_read_remote_version_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.lmp_ver	= 0x03;
+    params.manufacturer	= cpu_to_le16(0xa000);
+    params.lmp_subver	= cpu_to_le16(0xa607);
+    bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE,
+                    &params, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_clock_offset_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    /* TODO: return the clkoff *differenece* */
+    params.clock_offset	= slave->clkoff;	/* Note: no swapping */
+    bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE,
+                    &params, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link,
+                uint16_t handle)
+{
+    evt_mode_change params = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .mode		= link->acl_mode,
+        .interval	= cpu_to_le16(link->acl_interval),
+    };
+
+    bt_hci_event(hci, EVT_MODE_CHANGE, &params, EVT_MODE_CHANGE_SIZE);
+}
+
+static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci,
+                struct bt_link_s *link, int mode, uint16_t interval)
+{
+    link->acl_mode = mode;
+    link->acl_interval = interval;
+
+    bt_hci_event_mode(hci, link, link->handle);
+
+    link->slave->lmp_mode_change(link);
+}
+
+static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+
+    bt_hci_event_mode(hci, btlink, link->handle);
+}
+
+static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
+                int interval, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != acl_active) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) +
+                   muldiv64(interval * 625, get_ticks_per_sec(), 1000000));
+    bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
+
+    return 0;
+}
+
+static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != mode) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_del_timer(link->acl_mode_timer);
+    bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0);
+
+    return 0;
+}
+
+static void bt_hci_mode_tick(void *opaque)
+{
+    struct bt_link_s *link = opaque;
+    struct bt_hci_s *hci = hci_from_device(link->host);
+
+    bt_hci_lmp_mode_change_master(hci, link, acl_active, 0);
+}
+
+static void bt_hci_reset(struct bt_hci_s *hci)
+{
+    hci->acl_len = 0;
+    hci->last_cmd = 0;
+    hci->lm.connecting = 0;
+
+    hci->event_mask[0] = 0xff;
+    hci->event_mask[1] = 0xff;
+    hci->event_mask[2] = 0xff;
+    hci->event_mask[3] = 0xff;
+    hci->event_mask[4] = 0xff;
+    hci->event_mask[5] = 0x1f;
+    hci->event_mask[6] = 0x00;
+    hci->event_mask[7] = 0x00;
+    hci->device.inquiry_scan = 0;
+    hci->device.page_scan = 0;
+    if (hci->device.lmp_name)
+        qemu_free((void *) hci->device.lmp_name);
+    hci->device.lmp_name = NULL;
+    hci->device.class[0] = 0x00;
+    hci->device.class[1] = 0x00;
+    hci->device.class[2] = 0x00;
+    hci->voice_setting = 0x0000;
+    hci->conn_accept_tout = 0x1f40;
+    hci->lm.inquiry_mode = 0x00;
+
+    hci->psb_handle = 0x000;
+    hci->asb_handle = 0x000;
+
+    /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */
+    qemu_del_timer(hci->lm.inquiry_done);
+    qemu_del_timer(hci->lm.inquiry_next);
+    qemu_del_timer(hci->conn_accept_timer);
+}
+
+static void bt_hci_read_local_version_rp(struct bt_hci_s *hci)
+{
+    read_local_version_rp lv = {
+        .status		= HCI_SUCCESS,
+        .hci_ver	= 0x03,
+        .hci_rev	= cpu_to_le16(0xa607),
+        .lmp_ver	= 0x03,
+        .manufacturer	= cpu_to_le16(0xa000),
+        .lmp_subver	= cpu_to_le16(0xa607),
+    };
+
+    bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE);
+}
+
+static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci)
+{
+    read_local_commands_rp lc = {
+        .status		= HCI_SUCCESS,
+        .commands	= {
+            /* Keep updated! */
+            /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */
+            0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3,
+            0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE);
+}
+
+static void bt_hci_read_local_features_rp(struct bt_hci_s *hci)
+{
+    read_local_features_rp lf = {
+        .status		= HCI_SUCCESS,
+        .features	= {
+            (hci->device.lmp_caps >>  0) & 0xff,
+            (hci->device.lmp_caps >>  8) & 0xff,
+            (hci->device.lmp_caps >> 16) & 0xff,
+            (hci->device.lmp_caps >> 24) & 0xff,
+            (hci->device.lmp_caps >> 32) & 0xff,
+            (hci->device.lmp_caps >> 40) & 0xff,
+            (hci->device.lmp_caps >> 48) & 0xff,
+            (hci->device.lmp_caps >> 56) & 0xff,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page)
+{
+    read_local_ext_features_rp lef = {
+        .status		= HCI_SUCCESS,
+        .page_num	= page,
+        .max_page_num	= 0x00,
+        .features	= {
+            /* Keep updated! */
+            0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80,
+        },
+    };
+    if (page)
+        memset(lef.features, 0, sizeof(lef.features));
+
+    bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci)
+{
+    read_buffer_size_rp bs = {
+        /* This can be made configurable, for one standard USB dongle HCI
+         * the four values are cpu_to_le16(0x0180), 0x40,
+         * cpu_to_le16(0x0008), cpu_to_le16(0x0008).  */
+        .status		= HCI_SUCCESS,
+        .acl_mtu	= cpu_to_le16(0x0200),
+        .sco_mtu	= 0,
+        .acl_max_pkt	= cpu_to_le16(0x0001),
+        .sco_max_pkt	= cpu_to_le16(0x0000),
+    };
+
+    bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE);
+}
+
+/* Deprecated in V2.0 (page 661) */
+static void bt_hci_read_country_code_rp(struct bt_hci_s *hci)
+{
+    read_country_code_rp cc ={
+        .status		= HCI_SUCCESS,
+        .country_code	= 0x00,	/* North America & Europe^1 and Japan */
+    };
+
+    bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE);
+
+    /* ^1. Except France, sorry */
+}
+
+static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci)
+{
+    read_bd_addr_rp ba = {
+        .status = HCI_SUCCESS,
+        .bdaddr = BAINIT(&hci->device.bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE);
+}
+
+static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle)
+{
+    read_link_quality_rp lq = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .link_quality	= 0xff,
+    };
+
+    if (bt_hci_handle_bad(hci, handle))
+        lq.status = HCI_NO_CONNECTION;
+
+    bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE);
+    return 0;
+}
+
+/* Generate a Command Complete event with only the Status parameter */
+static inline void bt_hci_event_complete_status(struct bt_hci_s *hci,
+                uint8_t status)
+{
+    bt_hci_event_complete(hci, &status, 1);
+}
+
+static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci,
+                uint8_t status, bdaddr_t *bd_addr)
+{
+    create_conn_cancel_rp params = {
+        .status = status,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, CREATE_CONN_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_auth_complete params = {
+        .status = HCI_SUCCESS,
+        .handle = HNDL(handle),
+    };
+
+    bt_hci_event(hci, EVT_AUTH_COMPLETE, &params, EVT_AUTH_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci,
+                uint16_t handle, uint8_t mode)
+{
+    evt_encrypt_change params = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .encrypt	= mode,
+    };
+
+    bt_hci_event(hci, EVT_ENCRYPT_CHANGE, &params, EVT_ENCRYPT_CHANGE_SIZE);
+}
+
+static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci,
+                bdaddr_t *bd_addr)
+{
+    remote_name_req_cancel_rp params = {
+        .status = HCI_INVALID_PARAMETERS,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, REMOTE_NAME_REQ_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_read_remote_ext_features_complete params = {
+        .status = HCI_UNSUPPORTED_FEATURE,
+        .handle = HNDL(handle),
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    read_lmp_handle_rp params = {
+        .status		= HCI_NO_CONNECTION,
+        .handle		= HNDL(handle),
+        .reserved	= 0,
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_LMP_HANDLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci,
+                int status, uint16_t handle, int master)
+{
+    role_discovery_rp params = {
+        .status		= status,
+        .handle		= HNDL(handle),
+        .role		= master ? 0x00 : 0x01,
+    };
+
+    bt_hci_event_complete(hci, &params, ROLE_DISCOVERY_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci,
+                int status, uint16_t handle)
+{
+    flush_rp params = {
+        .status		= status,
+        .handle		= HNDL(handle),
+    };
+
+    bt_hci_event_complete(hci, &params, FLUSH_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
+{
+    read_local_name_rp params;
+    params.status = HCI_SUCCESS;
+    memset(params.name, 0, sizeof(params.name));
+    if (hci->device.lmp_name)
+        strncpy(params.name, hci->device.lmp_name, sizeof(params.name));
+
+    bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_conn_accept_timeout(
+                struct bt_hci_s *hci)
+{
+    read_conn_accept_timeout_rp params = {
+        .status		= HCI_SUCCESS,
+        .timeout	= cpu_to_le16(hci->conn_accept_tout),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci)
+{
+    read_scan_enable_rp params = {
+        .status = HCI_SUCCESS,
+        .enable =
+                (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) |
+                (hci->device.page_scan ? SCAN_PAGE : 0),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_SCAN_ENABLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci)
+{
+    read_class_of_dev_rp params;
+
+    params.status = HCI_SUCCESS;
+    memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class));
+
+    bt_hci_event_complete(hci, &params, READ_CLASS_OF_DEV_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci)
+{
+    read_voice_setting_rp params = {
+        .status		= HCI_SUCCESS,
+        .voice_setting	= hci->voice_setting,	/* Note: no swapping */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_VOICE_SETTING_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_inquiry_mode(
+                struct bt_hci_s *hci)
+{
+    read_inquiry_mode_rp params = {
+        .status		= HCI_SUCCESS,
+        .mode		= hci->lm.inquiry_mode,
+    };
+
+    bt_hci_event_complete(hci, &params, READ_INQUIRY_MODE_RP_SIZE);
+}
+
+static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
+                uint16_t handle, int packets)
+{
+    uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1];
+    evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1);
+
+    params->num_hndl			= 1;
+    params->connection->handle		= HNDL(handle);
+    params->connection->num_packets	= cpu_to_le16(packets);
+
+    bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1));
+}
+
+static void bt_submit_hci(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t cmd;
+    int paramlen, i;
+
+    if (length < HCI_COMMAND_HDR_SIZE)
+        goto short_hci;
+
+    memcpy(&hci->last_cmd, data, 2);
+
+    cmd = (data[1] << 8) | data[0];
+    paramlen = data[2];
+    if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0)	/* NOP */
+        return;
+
+    data += HCI_COMMAND_HDR_SIZE;
+    length -= HCI_COMMAND_HDR_SIZE;
+
+    if (paramlen > length)
+        return;
+
+#define PARAM(cmd, param)	(((cmd##_cp *) data)->param)
+#define PARAM16(cmd, param)	le16_to_cpup(&PARAM(cmd, param))
+#define PARAMHANDLE(cmd)	HNDL(PARAM(cmd, handle))
+#define LENGTH_CHECK(cmd)	if (length < sizeof(cmd##_cp)) goto short_hci
+    /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp
+     * needs to be updated every time a command is implemented here!  */
+    switch (cmd) {
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY):
+        LENGTH_CHECK(inquiry);
+
+        if (PARAM(inquiry, length) < 1) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 0;
+        hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX;
+        hci->lm.responses = 0;
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
+        if (!hci->lm.inquire || hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
+        LENGTH_CHECK(periodic_inquiry);
+
+        if (!(PARAM(periodic_inquiry, length) <
+                                PARAM16(periodic_inquiry, min_period) &&
+                                PARAM16(periodic_inquiry, min_period) <
+                                PARAM16(periodic_inquiry, max_period)) ||
+                        PARAM(periodic_inquiry, length) < 1 ||
+                        PARAM16(periodic_inquiry, min_period) < 2 ||
+                        PARAM16(periodic_inquiry, max_period) < 3) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 1;
+        hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp);
+        hci->lm.responses = 0;
+        hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
+        if (!hci->lm.inquire || !hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        qemu_del_timer(hci->lm.inquiry_next);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN):
+        LENGTH_CHECK(create_conn);
+
+        if (hci->lm.connecting >= HCI_HANDLES_MAX) {
+            bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES);
+            break;
+        }
+        bt_hci_event_status(hci, HCI_SUCCESS);
+
+        if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr)))
+            bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT):
+        LENGTH_CHECK(disconnect);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) {
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_disconnect(hci, PARAMHANDLE(disconnect),
+                        PARAM(disconnect, reason));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL):
+        LENGTH_CHECK(create_conn_cancel);
+
+        if (bt_hci_lmp_connection_ready(hci,
+                                &PARAM(create_conn_cancel, bdaddr))) {
+            for (i = 0; i < HCI_HANDLES_MAX; i ++)
+                if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link &&
+                                !bacmp(&hci->lm.handle[i].link->slave->bd_addr,
+                                        &PARAM(create_conn_cancel, bdaddr)))
+                   break;
+
+            bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ?
+                            HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION,
+                            &PARAM(create_conn_cancel, bdaddr));
+        } else
+            bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS,
+                            &PARAM(create_conn_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ):
+        LENGTH_CHECK(accept_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(accept_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_accept(hci, hci->conn_req_host);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ):
+        LENGTH_CHECK(reject_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(reject_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_reject(hci, hci->conn_req_host,
+                        PARAM(reject_conn_req, reason));
+        bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED):
+        LENGTH_CHECK(auth_requested);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT):
+        LENGTH_CHECK(set_conn_encrypt);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_encrypt_change(hci,
+                            PARAMHANDLE(set_conn_encrypt),
+                            PARAM(set_conn_encrypt, encrypt));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ):
+        LENGTH_CHECK(remote_name_req);
+
+        if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL):
+        LENGTH_CHECK(remote_name_req_cancel);
+
+        bt_hci_event_complete_name_cancel(hci,
+                        &PARAM(remote_name_req_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES):
+        LENGTH_CHECK(read_remote_features);
+
+        if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES):
+        LENGTH_CHECK(read_remote_ext_features);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_read_remote_ext_features(hci,
+                            PARAMHANDLE(read_remote_ext_features));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION):
+        LENGTH_CHECK(read_remote_version);
+
+        if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET):
+        LENGTH_CHECK(read_clock_offset);
+
+        if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE):
+        LENGTH_CHECK(read_lmp_handle);
+
+        /* TODO: */
+        bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE):
+        LENGTH_CHECK(hold_mode);
+
+        if (PARAM16(hold_mode, min_interval) >
+                        PARAM16(hold_mode, max_interval) ||
+                        PARAM16(hold_mode, min_interval) < 0x0002 ||
+                        PARAM16(hold_mode, max_interval) > 0xff00 ||
+                        (PARAM16(hold_mode, min_interval) & 1) ||
+                        (PARAM16(hold_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode),
+                                PARAM16(hold_mode, max_interval),
+                                acl_hold))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE):
+        LENGTH_CHECK(park_mode);
+
+        if (PARAM16(park_mode, min_interval) >
+                        PARAM16(park_mode, max_interval) ||
+                        PARAM16(park_mode, min_interval) < 0x000e ||
+                        (PARAM16(park_mode, min_interval) & 1) ||
+                        (PARAM16(park_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode),
+                                PARAM16(park_mode, max_interval),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE):
+        LENGTH_CHECK(exit_park_mode);
+
+        if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY):
+        LENGTH_CHECK(role_discovery);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery)))
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0);
+        else
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_SUCCESS, PARAMHANDLE(role_discovery),
+                            bt_hci_role_master(hci,
+                                    PARAMHANDLE(role_discovery)));
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK):
+        LENGTH_CHECK(set_event_mask);
+
+        memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET):
+        bt_hci_reset(hci);
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT):
+        if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL)
+            /* No length check */;
+        else
+            LENGTH_CHECK(set_event_flt);
+
+        /* Filters are not implemented */
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH):
+        LENGTH_CHECK(flush);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(flush)))
+            bt_hci_event_complete_flush(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(flush));
+        else {
+            /* TODO: ordering? */
+            bt_hci_event(hci, EVT_FLUSH_OCCURRED,
+                            &PARAM(flush, handle),
+                            EVT_FLUSH_OCCURRED_SIZE);
+            bt_hci_event_complete_flush(hci,
+                            HCI_SUCCESS, PARAMHANDLE(flush));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
+        LENGTH_CHECK(change_local_name);
+
+        if (hci->device.lmp_name)
+            qemu_free((void *) hci->device.lmp_name);
+        hci->device.lmp_name = qemu_strndup(PARAM(change_local_name, name),
+                        sizeof(PARAM(change_local_name, name)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
+        bt_hci_event_complete_read_local_name(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT):
+        bt_hci_event_complete_read_conn_accept_timeout(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT):
+        /* TODO */
+        LENGTH_CHECK(write_conn_accept_timeout);
+
+        if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 ||
+                        PARAM16(write_conn_accept_timeout, timeout) > 0xb540) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
+        bt_hci_event_complete_read_scan_enable(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
+        LENGTH_CHECK(write_scan_enable);
+
+        /* TODO: check that the remaining bits are all 0 */
+        hci->device.inquiry_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY);
+        hci->device.page_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV):
+        bt_hci_event_complete_read_local_class(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
+        LENGTH_CHECK(write_class_of_dev);
+
+        memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class),
+                        sizeof(PARAM(write_class_of_dev, dev_class)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING):
+        bt_hci_event_complete_voice_setting(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING):
+        LENGTH_CHECK(write_voice_setting);
+
+        hci->voice_setting = PARAM(write_voice_setting, voice_setting);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS):
+        if (length < data[0] * 2 + 1)
+            goto short_hci;
+
+        for (i = 0; i < data[0]; i ++)
+            if (bt_hci_handle_bad(hci,
+                                    data[i * 2 + 1] | (data[i * 2 + 2] << 8)))
+                bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40)
+         * else
+         *     goto unknown_command */
+        bt_hci_event_complete_read_inquiry_mode(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80)
+         * else
+         *     goto unknown_command */
+        LENGTH_CHECK(write_inquiry_mode);
+
+        if (PARAM(write_inquiry_mode, mode) > 0x01) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
+        bt_hci_read_local_version_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS):
+        bt_hci_read_local_commands_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
+        bt_hci_read_local_features_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
+        LENGTH_CHECK(read_local_ext_features);
+
+        bt_hci_read_local_ext_features_rp(hci,
+                        PARAM(read_local_ext_features, page_num));
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE):
+        bt_hci_read_buffer_size_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE):
+        bt_hci_read_country_code_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
+        bt_hci_read_bd_addr_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY):
+        LENGTH_CHECK(read_link_quality);
+
+        bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality));
+        break;
+
+    default:
+        bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND);
+        break;
+
+    short_hci:
+        fprintf(stderr, "%s: HCI packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+    }
+}
+
+/* We could perform fragmentation here, we can't do "recombination" because
+ * at this layer the length of the payload is not know ahead, so we only
+ * know that a packet contained the last fragment of the SDU when the next
+ * SDU starts.  */
+static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
+                const uint8_t *data, int start, int len)
+{
+    struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
+
+    /* TODO: packet flags */
+    /* TODO: avoid memcpy'ing */
+
+    if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
+        fprintf(stderr, "%s: can't take ACL packets %i bytes long\n",
+                        __FUNCTION__, len);
+        return;
+    }
+    memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len);
+
+    pkt->handle = cpu_to_le16(
+                    acl_handle_pack(handle, start ? ACL_START : ACL_CONT));
+    pkt->dlen = cpu_to_le16(len);
+    hci->info.acl_recv(hci->info.opaque,
+                    hci->acl_buf, len + HCI_ACL_HDR_SIZE);
+}
+
+static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+
+    bt_hci_lmp_acl_data(hci_from_device(btlink->slave),
+                    link->handle, data, start, len);
+}
+
+static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    bt_hci_lmp_acl_data(hci_from_device(link->host),
+                    link->handle, data, start, len);
+}
+
+static void bt_submit_acl(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t handle;
+    int datalen, flags;
+    struct bt_link_s *link;
+
+    if (length < HCI_ACL_HDR_SIZE) {
+        fprintf(stderr, "%s: ACL packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        return;
+    }
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    flags = acl_flags((data[1] << 8) | data[0]);
+    datalen = (data[3] << 8) | data[2];
+    data += HCI_ACL_HDR_SIZE;
+    length -= HCI_ACL_HDR_SIZE;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid ACL handle %03x\n",
+                        __FUNCTION__, handle);
+        /* TODO: signal an error */
+        return;
+    }
+    handle &= ~HCI_HANDLE_OFFSET;
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    link = hci->lm.handle[handle].link;
+
+    if ((flags & ~3) == ACL_ACTIVE_BCAST) {
+        if (!hci->asb_handle)
+            hci->asb_handle = handle;
+        else if (handle != hci->asb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    if ((flags & ~3) == ACL_PICO_BCAST) {
+        if (!hci->psb_handle)
+            hci->psb_handle = handle;
+        else if (handle != hci->psb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS */
+    bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1);
+
+    /* Do this last as it can trigger further events even in this HCI */
+    hci->lm.handle[handle].lmp_acl_data(link, data,
+                    (flags & 3) == ACL_START, length);
+}
+
+static void bt_submit_sco(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t handle;
+    int datalen;
+
+    if (length < 3)
+        return;
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    datalen = data[2];
+    length -= 3;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid SCO handle %03x\n",
+                        __FUNCTION__, handle);
+        return;
+    }
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    /* TODO */
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous
+     * Flow Control is enabled.
+     * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and
+     * page 514.)  */
+}
+
+static uint8_t *bt_hci_evt_packet(void *opaque)
+{
+    /* TODO: allocate a packet from upper layer */
+    struct bt_hci_s *s = opaque;
+
+    return s->evt_buf;
+}
+
+static void bt_hci_evt_submit(void *opaque, int len)
+{
+    /* TODO: notify upper layer */
+    struct bt_hci_s *s = opaque;
+
+    s->info.evt_recv(s->info.opaque, s->evt_buf, len);
+}
+
+static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+
+    bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr);
+    return 0;
+}
+
+static void bt_hci_done(struct HCIInfo *info);
+static void bt_hci_destroy(struct bt_device_s *dev)
+{
+    struct bt_hci_s *hci = hci_from_device(dev);
+
+    bt_hci_done(&hci->info);
+}
+
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
+{
+    struct bt_hci_s *s = qemu_mallocz(sizeof(struct bt_hci_s));
+
+    s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s);
+    s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s);
+    s->conn_accept_timer =
+            qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s);
+
+    s->evt_packet = bt_hci_evt_packet;
+    s->evt_submit = bt_hci_evt_submit;
+    s->opaque = s;
+
+    bt_device_init(&s->device, net);
+    s->device.lmp_connection_request = bt_hci_lmp_connection_request;
+    s->device.lmp_connection_complete = bt_hci_lmp_connection_complete;
+    s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host;
+    s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave;
+    s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave;
+    s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host;
+    s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave;
+
+    /* Keep updated! */
+    /* Also keep in sync with supported commands bitmask in
+     * bt_hci_read_local_commands_rp */
+    s->device.lmp_caps = 0x8000199b7e85355fll;
+
+    bt_hci_reset(s);
+
+    s->info.cmd_send = bt_submit_hci;
+    s->info.sco_send = bt_submit_sco;
+    s->info.acl_send = bt_submit_acl;
+    s->info.bdaddr_set = bt_hci_bdaddr_set;
+
+    s->device.handle_destroy = bt_hci_destroy;
+
+    return &s->info;
+}
+
+static void bt_hci_done(struct HCIInfo *info)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    int handle;
+
+    bt_device_done(&hci->device);
+
+    if (hci->device.lmp_name)
+        qemu_free((void *) hci->device.lmp_name);
+
+    /* Be gentle and send DISCONNECT to all connected peers and those
+     * currently waiting for us to accept or reject a connection request.
+     * This frees the links.  */
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci,
+                                 hci->conn_req_host, HCI_OE_POWER_OFF);
+        return;
+    }
+
+    for (handle = HCI_HANDLE_OFFSET;
+                    handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++)
+        if (!bt_hci_handle_bad(hci, handle))
+            bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF);
+
+    /* TODO: this is not enough actually, there may be slaves from whom
+     * we have requested a connection who will soon (or not) respond with
+     * an accept or a reject, so we should also check if hci->lm.connecting
+     * is non-zero and if so, avoid freeing the hci but otherwise disappear
+     * from all qemu social life (e.g. stop scanning and request to be
+     * removed from s->device.net) and arrange for
+     * s->device.lmp_connection_complete to free the remaining bits once
+     * hci->lm.awaiting_bdaddr[] is empty.  */
+
+    qemu_free_timer(hci->lm.inquiry_done);
+    qemu_free_timer(hci->lm.inquiry_next);
+    qemu_free_timer(hci->conn_accept_timer);
+
+    qemu_free(hci);
+}
diff --git a/qemu-0.15.x/hw/bt-hid.c b/qemu-0.15.x/hw/bt-hid.c
new file mode 100644
index 0000000..09120af
--- /dev/null
+++ b/qemu-0.15.x/hw/bt-hid.c
@@ -0,0 +1,571 @@
+/*
+ * QEMU Bluetooth HID Profile wrapper for USB HID.
+ *
+ * Copyright (C) 2007-2008 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "bt.h"
+
+enum hid_transaction_req {
+    BT_HANDSHAKE			= 0x0,
+    BT_HID_CONTROL			= 0x1,
+    BT_GET_REPORT			= 0x4,
+    BT_SET_REPORT			= 0x5,
+    BT_GET_PROTOCOL			= 0x6,
+    BT_SET_PROTOCOL			= 0x7,
+    BT_GET_IDLE				= 0x8,
+    BT_SET_IDLE				= 0x9,
+    BT_DATA				= 0xa,
+    BT_DATC				= 0xb,
+};
+
+enum hid_transaction_handshake {
+    BT_HS_SUCCESSFUL			= 0x0,
+    BT_HS_NOT_READY			= 0x1,
+    BT_HS_ERR_INVALID_REPORT_ID		= 0x2,
+    BT_HS_ERR_UNSUPPORTED_REQUEST	= 0x3,
+    BT_HS_ERR_INVALID_PARAMETER		= 0x4,
+    BT_HS_ERR_UNKNOWN			= 0xe,
+    BT_HS_ERR_FATAL			= 0xf,
+};
+
+enum hid_transaction_control {
+    BT_HC_NOP				= 0x0,
+    BT_HC_HARD_RESET			= 0x1,
+    BT_HC_SOFT_RESET			= 0x2,
+    BT_HC_SUSPEND			= 0x3,
+    BT_HC_EXIT_SUSPEND			= 0x4,
+    BT_HC_VIRTUAL_CABLE_UNPLUG		= 0x5,
+};
+
+enum hid_protocol {
+    BT_HID_PROTO_BOOT			= 0,
+    BT_HID_PROTO_REPORT			= 1,
+};
+
+enum hid_boot_reportid {
+    BT_HID_BOOT_INVALID			= 0,
+    BT_HID_BOOT_KEYBOARD,
+    BT_HID_BOOT_MOUSE,
+};
+
+enum hid_data_pkt {
+    BT_DATA_OTHER			= 0,
+    BT_DATA_INPUT,
+    BT_DATA_OUTPUT,
+    BT_DATA_FEATURE,
+};
+
+#define BT_HID_MTU			48
+
+/* HID interface requests */
+#define GET_REPORT			0xa101
+#define GET_IDLE			0xa102
+#define GET_PROTOCOL			0xa103
+#define SET_REPORT			0x2109
+#define SET_IDLE			0x210a
+#define SET_PROTOCOL			0x210b
+
+struct bt_hid_device_s {
+    struct bt_l2cap_device_s btdev;
+    struct bt_l2cap_conn_params_s *control;
+    struct bt_l2cap_conn_params_s *interrupt;
+    USBDevice *usbdev;
+
+    int proto;
+    int connected;
+    int data_type;
+    int intr_state;
+    struct {
+        int len;
+        uint8_t buffer[1024];
+    } dataother, datain, dataout, feature, intrdataout;
+    enum {
+        bt_state_ready,
+        bt_state_transaction,
+        bt_state_suspend,
+    } state;
+};
+
+static void bt_hid_reset(struct bt_hid_device_s *s)
+{
+    struct bt_scatternet_s *net = s->btdev.device.net;
+
+    /* Go as far as... */
+    bt_l2cap_device_done(&s->btdev);
+    bt_l2cap_device_init(&s->btdev, net);
+
+    s->usbdev->info->handle_reset(s->usbdev);
+    s->proto = BT_HID_PROTO_REPORT;
+    s->state = bt_state_ready;
+    s->dataother.len = 0;
+    s->datain.len = 0;
+    s->dataout.len = 0;
+    s->feature.len = 0;
+    s->intrdataout.len = 0;
+    s->intr_state = 0;
+}
+
+static int bt_hid_out(struct bt_hid_device_s *s)
+{
+    USBPacket p;
+
+    if (s->data_type == BT_DATA_OUTPUT) {
+        p.pid = USB_TOKEN_OUT;
+        p.devep = 1;
+        p.data = s->dataout.buffer;
+        p.len = s->dataout.len;
+        s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
+
+        return s->dataout.len;
+    }
+
+    if (s->data_type == BT_DATA_FEATURE) {
+        /* XXX:
+         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
+         * or a SET_REPORT? */
+        p.devep = 0;
+    }
+
+    return -1;
+}
+
+static int bt_hid_in(struct bt_hid_device_s *s)
+{
+    USBPacket p;
+
+    p.pid = USB_TOKEN_IN;
+    p.devep = 1;
+    p.data = s->datain.buffer;
+    p.len = sizeof(s->datain.buffer);
+    s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
+
+    return s->datain.len;
+}
+
+static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HANDSHAKE << 4) | result;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HID_CONTROL << 4) | operation;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_disconnect(struct bt_hid_device_s *s)
+{
+    /* Disconnect s->control and s->interrupt */
+}
+
+static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
+    int plen;
+
+    do {
+        plen = MIN(len, ch->remote_mtu - 1);
+        pkt = ch->sdu_out(ch, plen + 1);
+
+        pkt[0] = hdr;
+        if (plen)
+            memcpy(pkt + 1, data, plen);
+        ch->sdu_submit(ch);
+
+        len -= plen;
+        data += plen;
+        hdr = (BT_DATC << 4) | type;
+    } while (plen == ch->remote_mtu - 1);
+}
+
+static void bt_hid_control_transaction(struct bt_hid_device_s *s,
+                const uint8_t *data, int len)
+{
+    uint8_t type, parameter;
+    int rlen, ret = -1;
+    if (len < 1)
+        return;
+
+    type = data[0] >> 4;
+    parameter = data[0] & 0xf;
+
+    switch (type) {
+    case BT_HANDSHAKE:
+    case BT_DATA:
+        switch (parameter) {
+        default:
+            /* These are not expected to be sent this direction.  */
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_HID_CONTROL:
+        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
+                                s->state == bt_state_transaction)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        switch (parameter) {
+        case BT_HC_NOP:
+            break;
+        case BT_HC_HARD_RESET:
+        case BT_HC_SOFT_RESET:
+            bt_hid_reset(s);
+            break;
+        case BT_HC_SUSPEND:
+            if (s->state == bt_state_ready)
+                s->state = bt_state_suspend;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_EXIT_SUSPEND:
+            if (s->state == bt_state_suspend)
+                s->state = bt_state_ready;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_VIRTUAL_CABLE_UNPLUG:
+            bt_hid_disconnect(s);
+            break;
+        default:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_GET_REPORT:
+        /* No ReportIDs declared.  */
+        if (((parameter & 8) && len != 3) ||
+                        (!(parameter & 8) && len != 1) ||
+                        s->state != bt_state_ready) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (parameter & 8)
+            rlen = data[2] | (data[3] << 8);
+        else
+            rlen = INT_MAX;
+        switch (parameter & 3) {
+        case BT_DATA_OTHER:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_DATA_INPUT:
+            /* Here we can as well poll s->usbdev */
+            bt_hid_send_data(s->control, BT_DATA_INPUT,
+                            s->datain.buffer, MIN(rlen, s->datain.len));
+            break;
+        case BT_DATA_OUTPUT:
+            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
+                            s->dataout.buffer, MIN(rlen, s->dataout.len));
+            break;
+        case BT_DATA_FEATURE:
+            bt_hid_send_data(s->control, BT_DATA_FEATURE,
+                            s->feature.buffer, MIN(rlen, s->feature.len));
+            break;
+        }
+        break;
+
+    case BT_SET_REPORT:
+        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
+                        (parameter & 3) == BT_DATA_OTHER ||
+                        (parameter & 3) == BT_DATA_INPUT) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->data_type = parameter & 3;
+        if (s->data_type == BT_DATA_OUTPUT) {
+            s->dataout.len = len - 1;
+            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
+        } else {
+            s->feature.len = len - 1;
+            memcpy(s->feature.buffer, data + 1, s->feature.len);
+        }
+        if (len == BT_HID_MTU)
+            s->state = bt_state_transaction;
+        else
+            bt_hid_out(s);
+        break;
+
+    case BT_GET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        *s->control->sdu_out(s->control, 1) = s->proto;
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction ||
+                        (parameter != BT_HID_PROTO_BOOT &&
+                         parameter != BT_HID_PROTO_REPORT)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->proto = parameter;
+        s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0,
+                                        NULL);
+        ret = BT_HS_SUCCESSFUL;
+        break;
+
+    case BT_GET_IDLE:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1,
+                        s->control->sdu_out(s->control, 1));
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_IDLE:
+        if (len != 2 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+
+        /* We don't need to know about the Idle Rate here really,
+         * so just pass it on to the device.  */
+        ret = s->usbdev->info->handle_control(s->usbdev, NULL,
+                        SET_IDLE, data[1], 0, 0, NULL) ?
+                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+        /* XXX: Does this generate a handshake? */
+        break;
+
+    case BT_DATC:
+        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (s->data_type == BT_DATA_OUTPUT) {
+            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
+            s->dataout.len += len - 1;
+        } else {
+            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
+            s->feature.len += len - 1;
+        }
+        if (len < BT_HID_MTU) {
+            bt_hid_out(s);
+            s->state = bt_state_ready;
+        }
+        break;
+
+    default:
+        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
+    }
+
+    if (ret != -1)
+        bt_hid_send_handshake(s, ret);
+}
+
+static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    bt_hid_control_transaction(hid, data, len);
+}
+
+static void bt_hid_datain(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    /* If suspended, wake-up and send a wake-up event first.  We might
+     * want to also inspect the input report and ignore event like
+     * mouse movements until a button event occurs.  */
+    if (hid->state == bt_state_suspend) {
+        hid->state = bt_state_ready;
+    }
+
+    if (bt_hid_in(hid) > 0)
+        /* TODO: when in boot-mode precede any Input reports with the ReportID
+         * byte, here and in GetReport/SetReport on the Control channel.  */
+        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
+                        hid->datain.buffer, hid->datain.len);
+}
+
+static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    if (len > BT_HID_MTU || len < 1)
+        goto bad;
+    if ((data[0] & 3) != BT_DATA_OUTPUT)
+        goto bad;
+    if ((data[0] >> 4) == BT_DATA) {
+        if (hid->intr_state)
+            goto bad;
+
+        hid->data_type = BT_DATA_OUTPUT;
+        hid->intrdataout.len = 0;
+    } else if ((data[0] >> 4) == BT_DATC) {
+        if (!hid->intr_state)
+            goto bad;
+    } else
+        goto bad;
+
+    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
+    hid->intrdataout.len += len - 1;
+    hid->intr_state = (len == BT_HID_MTU);
+    if (!hid->intr_state) {
+        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
+                        hid->dataout.len = hid->intrdataout.len);
+        bt_hid_out(hid);
+    }
+
+    return;
+bad:
+    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
+                    __FUNCTION__);
+}
+
+/* "Virtual cable" plug/unplug event.  */
+static void bt_hid_connected_update(struct bt_hid_device_s *hid)
+{
+    int prev = hid->connected;
+
+    hid->connected = hid->control && hid->interrupt;
+
+    /* Stop page-/inquiry-scanning when a host is connected.  */
+    hid->btdev.device.page_scan = !hid->connected;
+    hid->btdev.device.inquiry_scan = !hid->connected;
+
+    if (hid->connected && !prev) {
+        hid->usbdev->info->handle_reset(hid->usbdev);
+        hid->proto = BT_HID_PROTO_REPORT;
+    }
+
+    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
+     * isn't destroyed yet, in case we're being called from handle_destroy) */
+}
+
+static void bt_hid_close_control(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->control = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static void bt_hid_close_interrupt(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->interrupt = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->control)
+        return 1;
+
+    hid->control = params;
+    hid->control->opaque = hid;
+    hid->control->close = bt_hid_close_control;
+    hid->control->sdu_in = bt_hid_control_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->interrupt)
+        return 1;
+
+    hid->interrupt = params;
+    hid->interrupt->opaque = hid;
+    hid->interrupt->close = bt_hid_close_interrupt;
+    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static void bt_hid_destroy(struct bt_device_s *dev)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->connected)
+        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
+    bt_l2cap_device_done(&hid->btdev);
+
+    hid->usbdev->info->handle_destroy(hid->usbdev);
+
+    qemu_free(hid);
+}
+
+enum peripheral_minor_class {
+    class_other		= 0 << 4,
+    class_keyboard	= 1 << 4,
+    class_pointing	= 2 << 4,
+    class_combo		= 3 << 4,
+};
+
+static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
+                USBDevice *dev, enum peripheral_minor_class minor)
+{
+    struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
+    uint32_t class =
+            /* Format type */
+            (0 << 0) |
+            /* Device class */
+            (minor << 2) |
+            (5 << 8) |  /* "Peripheral" */
+            /* Service classes */
+            (1 << 13) | /* Limited discoverable mode */
+            (1 << 19);  /* Capturing device (?) */
+
+    bt_l2cap_device_init(&s->btdev, net);
+    bt_l2cap_sdp_init(&s->btdev);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
+                    BT_HID_MTU, bt_hid_new_control_ch);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
+                    BT_HID_MTU, bt_hid_new_interrupt_ch);
+
+    s->usbdev = dev;
+    s->btdev.device.lmp_name = s->usbdev->product_desc;
+    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+
+    s->btdev.device.handle_destroy = bt_hid_destroy;
+
+    s->btdev.device.class[0] = (class >>  0) & 0xff;
+    s->btdev.device.class[1] = (class >>  8) & 0xff;
+    s->btdev.device.class[2] = (class >> 16) & 0xff;
+
+    return &s->btdev.device;
+}
+
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
+{
+    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
+    return bt_hid_init(net, dev, class_keyboard);
+}
diff --git a/qemu-0.15.x/hw/bt-l2cap.c b/qemu-0.15.x/hw/bt-l2cap.c
new file mode 100644
index 0000000..7e2f668
--- /dev/null
+++ b/qemu-0.15.x/hw/bt-l2cap.c
@@ -0,0 +1,1362 @@
+/*
+ * QEMU Bluetooth L2CAP logic.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "bt.h"
+
+#define L2CAP_CID_MAX	0x100	/* Between 0x40 and 0x10000 */
+
+struct l2cap_instance_s {
+    struct bt_link_s *link;
+    struct bt_l2cap_device_s *dev;
+    int role;
+
+    uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_in_len;
+
+    uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_out_len;
+
+    /* Signalling channel timers.  They exist per-request but we can make
+     * sure we have no more than one outstanding request at any time.  */
+    QEMUTimer *rtx;
+    QEMUTimer *ertx;
+
+    int last_id;
+    int next_id;
+
+    struct l2cap_chan_s {
+        struct bt_l2cap_conn_params_s params;
+
+        void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
+                        const l2cap_hdr *hdr, int len);
+        int mps;
+        int min_mtu;
+
+        struct l2cap_instance_s *l2cap;
+
+        /* Only allocated channels */
+        uint16_t remote_cid;
+#define L2CAP_CFG_INIT	2
+#define L2CAP_CFG_ACC	1
+        int config_req_id; /* TODO: handle outgoing requests generically */
+        int config;
+
+        /* Only connection-oriented channels.  Note: if we allow the tx and
+         * rx traffic to be in different modes at any time, we need two.  */
+        int mode;
+
+        /* Only flow-controlled, connection-oriented channels */
+        uint8_t sdu[65536]; /* TODO: dynamically allocate */
+        int len_cur, len_total;
+        int rexmit;
+        int monitor_timeout;
+        QEMUTimer *monitor_timer;
+        QEMUTimer *retransmission_timer;
+    } *cid[L2CAP_CID_MAX];
+    /* The channel state machine states map as following:
+     * CLOSED           -> !cid[N]
+     * WAIT_CONNECT     -> never occurs
+     * WAIT_CONNECT_RSP -> never occurs
+     * CONFIG           -> cid[N] && config < 3
+     *   WAIT_CONFIG         -> never occurs, cid[N] && config == 0 && !config_r
+     *   WAIT_SEND_CONFIG    -> never occurs, cid[N] && config == 1 && !config_r
+     *   WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id
+     *   WAIT_CONFIG_RSP     -> cid[N] && config == 1 && config_req_id
+     *   WAIT_CONFIG_REQ     -> cid[N] && config == 2
+     * OPEN             -> cid[N] && config == 3
+     * WAIT_DISCONNECT  -> never occurs
+     */
+
+    struct l2cap_chan_s signalling_ch;
+    struct l2cap_chan_s group_ch;
+};
+
+struct slave_l2cap_instance_s {
+    struct bt_link_s link;	/* Underlying logical link (ACL) */
+    struct l2cap_instance_s l2cap;
+};
+
+struct bt_l2cap_psm_s {
+    int psm;
+    int min_mtu;
+    int (*new_channel)(struct bt_l2cap_device_s *device,
+                    struct bt_l2cap_conn_params_s *params);
+    struct bt_l2cap_psm_s *next;
+};
+
+static const uint16_t l2cap_fcs16_table[256] = {
+    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+
+static uint16_t l2cap_fcs16(const uint8_t *message, int len)
+{
+    uint16_t fcs = 0x0000;
+
+    while (len --)
+#if 0
+    {
+        int i;
+
+        fcs ^= *message ++;
+        for (i = 8; i; -- i)
+            if (fcs & 1)
+                fcs = (fcs >> 1) ^ 0xa001;
+            else
+                fcs = (fcs >> 1);
+    }
+#else
+        fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff];
+#endif
+
+    return fcs;
+}
+
+/* L2CAP layer logic (protocol) */
+
+static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit)
+        qemu_mod_timer(ch->retransmission_timer);
+    else
+        qemu_del_timer(ch->retransmission_timer);
+#endif
+}
+
+static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit)
+        qemu_mod_timer(ch->monitor_timer);
+    else
+        qemu_del_timer(ch->monitor_timer);
+#endif
+}
+
+static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, const void *data, int plen)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_cmd_rej *params;
+    uint16_t len;
+
+    reason = cpu_to_le16(reason);
+    len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen);
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_COMMAND_REJ;
+    hdr->ident = id;
+    memcpy(&hdr->len, &len, sizeof(hdr->len));
+    memcpy(&params->reason, &reason, sizeof(reason));
+    if (plen)
+       memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, uint16_t dcid, uint16_t scid)
+{
+    l2cap_cmd_rej_cid params = {
+        .dcid = dcid,
+        .scid = scid,
+    };
+
+    l2cap_command_reject(l2cap, id, reason, &params, L2CAP_CMD_REJ_CID_SIZE);
+}
+
+static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid, int result, int status)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+    params->result = cpu_to_le16(result);
+    params->status = cpu_to_le16(status);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
+                int dcid, int flag, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_req *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    /* TODO: unify the id sequencing */
+    l2cap->last_id = l2cap->next_id;
+    l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+
+    hdr->code = L2CAP_CONF_REQ;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len));
+
+    params->dcid = cpu_to_le16(dcid);
+    params->flags = cpu_to_le16(flag);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
+                int scid, int flag, int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONF_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len));
+
+    params->scid = cpu_to_le16(scid);
+    params->flags = cpu_to_le16(flag);
+    params->result = cpu_to_le16(result);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_disconn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_DISCONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    uint8_t *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_ECHO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(len);
+
+    memcpy(params, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
+                int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_info_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_INFO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len);
+
+    params->type = cpu_to_le16(type);
+    params->result = cpu_to_le16(result);
+    if (len)
+       memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
+#if 0
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
+#endif
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+
+static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
+{
+    int i;
+
+    for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++)
+        if (!l2cap->cid[i])
+            return i;
+
+    return L2CAP_CID_INVALID;
+}
+
+static inline struct bt_l2cap_psm_s *l2cap_psm(
+                struct bt_l2cap_device_s *device, int psm)
+{
+    struct bt_l2cap_psm_s *ret = device->first_psm;
+
+    while (ret && ret->psm != psm)
+        ret = ret->next;
+
+    return ret;
+}
+
+static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+    struct bt_l2cap_psm_s *psm_info;
+    int result, status;
+    int cid = l2cap_cid_new(l2cap);
+
+    if (cid) {
+        /* See what the channel is to be used for.. */
+        psm_info = l2cap_psm(l2cap->dev, psm);
+
+        if (psm_info) {
+            /* Device supports this use-case.  */
+            ch = qemu_mallocz(sizeof(*ch));
+            ch->params.sdu_out = l2cap_bframe_out;
+            ch->params.sdu_submit = l2cap_bframe_submit;
+            ch->frame_in = l2cap_bframe_in;
+            ch->mps = 65536;
+            ch->min_mtu = MAX(48, psm_info->min_mtu);
+            ch->params.remote_mtu = MAX(672, ch->min_mtu);
+            ch->remote_cid = source_cid;
+            ch->mode = L2CAP_MODE_BASIC;
+            ch->l2cap = l2cap;
+
+            /* Does it feel like opening yet another channel though?  */
+            if (!psm_info->new_channel(l2cap->dev, &ch->params)) {
+                l2cap->cid[cid] = ch;
+
+                result = L2CAP_CR_SUCCESS;
+                status = L2CAP_CS_NO_INFO;
+            } else {
+                qemu_free(ch);
+
+                result = L2CAP_CR_NO_MEM;
+                status = L2CAP_CS_NO_INFO;
+            }
+        } else {
+            result = L2CAP_CR_BAD_PSM;
+            status = L2CAP_CS_NO_INFO;
+        }
+    } else {
+        result = L2CAP_CR_NO_MEM;
+        status = L2CAP_CS_NO_INFO;
+    }
+
+    l2cap_connection_response(l2cap, cid, source_cid, result, status);
+
+    return ch;
+}
+
+static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
+                int cid, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+
+    /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a
+     * connection in CLOSED state still responds with a L2CAP_DisconnectRsp
+     * message on an L2CAP_DisconnectReq event.  */
+    if (unlikely(cid < L2CAP_CID_ALLOC)) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, source_cid);
+        return;
+    }
+    if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX))
+        ch = l2cap->cid[cid];
+
+    if (likely(ch)) {
+        if (ch->remote_cid != source_cid) {
+            fprintf(stderr, "%s: Ignoring a Disconnection Request with the "
+                            "invalid SCID %04x.\n", __FUNCTION__, source_cid);
+            return;
+        }
+
+        l2cap->cid[cid] = NULL;
+
+        ch->params.close(ch->params.opaque);
+        qemu_free(ch);
+    }
+
+    l2cap_disconnection_response(l2cap, cid, source_cid);
+}
+
+static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0);
+    ch->config_req_id = l2cap->last_id;
+    ch->config &= ~L2CAP_CFG_INIT;
+}
+
+static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    /* Use all default channel options and terminate negotiation.  */
+    l2cap_channel_config_null(l2cap, ch);
+}
+
+static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch, int flag,
+                const uint8_t *data, int len)
+{
+    l2cap_conf_opt *opt;
+    l2cap_conf_opt_qos *qos;
+    uint32_t val;
+    uint8_t rsp[len];
+    int result = L2CAP_CONF_SUCCESS;
+
+    data = memcpy(rsp, data, len);
+    while (len) {
+        opt = (void *) data;
+
+        if (len < L2CAP_CONF_OPT_SIZE ||
+                        len < L2CAP_CONF_OPT_SIZE + opt->len) {
+            result = L2CAP_CONF_REJECT;
+            break;
+        }
+        data += L2CAP_CONF_OPT_SIZE + opt->len;
+        len -= L2CAP_CONF_OPT_SIZE + opt->len;
+
+        switch (opt->type & 0x7f) {
+        case L2CAP_CONF_MTU:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* MTU */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < ch->min_mtu) {
+                cpu_to_le16w((void *) opt->val, ch->min_mtu);
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+
+            ch->params.remote_mtu = val;
+            break;
+
+        case L2CAP_CONF_FLUSH_TO:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Flush Timeout */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < 0x0001) {
+                opt->val[0] = 0xff;
+                opt->val[1] = 0xff;
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        case L2CAP_CONF_QOS:
+            if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+            qos = (void *) opt->val;
+
+            /* Flags */
+            val = qos->flags;
+            if (val) {
+                qos->flags = 0;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            /* Service type */
+            val = qos->service_type;
+            if (val != L2CAP_CONF_QOS_BEST_EFFORT &&
+                            val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            if (val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                /* XXX: These values should possibly be calculated
+                 * based on LM / baseband properties also.  */
+
+                /* Token rate */
+                val = le32_to_cpu(qos->token_rate);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_rate = cpu_to_le32(0x100000);
+
+                /* Token bucket size */
+                val = le32_to_cpu(qos->token_bucket_size);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_bucket_size = cpu_to_le32(65500);
+
+                /* Any Peak bandwidth value is correct to return as-is */
+                /* Any Access latency value is correct to return as-is */
+                /* Any Delay variation value is correct to return as-is */
+            }
+            break;
+
+        case L2CAP_CONF_RFC:
+            if (opt->len != 9) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Mode */
+            val = opt->val[0];
+            switch (val) {
+            case L2CAP_MODE_BASIC:
+                ch->mode = val;
+                ch->frame_in = l2cap_bframe_in;
+
+                /* All other parameters shall be ignored */
+                break;
+
+            case L2CAP_MODE_RETRANS:
+            case L2CAP_MODE_FLOWCTL:
+                ch->mode = val;
+                ch->frame_in = l2cap_iframe_in;
+                /* Note: most of these parameters refer to incoming traffic
+                 * so we don't need to save them as long as we can accept
+                 * incoming PDUs at any values of the parameters.  */
+
+                /* TxWindow size */
+                val = opt->val[1];
+                if (val < 1 || val > 32) {
+                    opt->val[1] = 32;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* MaxTransmit */
+                val = opt->val[2];
+                if (val < 1) {
+                    opt->val[2] = 1;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* Remote Retransmission time-out shouldn't affect local
+                 * operation (?) */
+
+                /* The Monitor time-out drives the local Monitor timer (?),
+                 * so save the value.  */
+                val = (opt->val[6] << 8) | opt->val[5];
+                if (val < 30) {
+                    opt->val[5] = 100 & 0xff;
+                    opt->val[6] = 100 >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->monitor_timeout = val;
+                l2cap_monitor_timer_update(ch);
+
+                /* MPS */
+                val = (opt->val[8] << 8) | opt->val[7];
+                if (val < ch->min_mtu) {
+                    opt->val[7] = ch->min_mtu & 0xff;
+                    opt->val[8] = ch->min_mtu >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->mps = val;
+                break;
+
+            default:
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        default:
+            if (!(opt->type >> 7))
+                result = L2CAP_CONF_UNKNOWN;
+            break;
+        }
+
+        if (result != L2CAP_CONF_SUCCESS)
+            break;	/* XXX: should continue? */
+    }
+
+    l2cap_configuration_response(l2cap, ch->remote_cid,
+                    flag, result, rsp, len);
+
+    return result == L2CAP_CONF_SUCCESS && !flag;
+}
+
+static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
+                int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return;
+    }
+    ch = l2cap->cid[cid];
+
+    /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to
+     * WAIT_CONFIG_REQ_RSP.  This is assuming the transition chart for OPEN
+     * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake
+     * and on options-acceptable we go back to OPEN and otherwise to
+     * WAIT_CONFIG_REQ and not the other way.  */
+    ch->config &= ~L2CAP_CFG_ACC;
+
+    if (l2cap_channel_config(l2cap, ch, flag, data, len))
+        /* Go to OPEN or WAIT_CONFIG_RSP */
+        ch->config |= L2CAP_CFG_ACC;
+
+    /* TODO: if the incoming traffic flow control or retransmission mode
+     * changed then we probably need to also generate the
+     * ConfigureChannel_Req event and set the outgoing traffic to the same
+     * mode.  */
+    if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) &&
+                    !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
+                int result, int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return 0;
+    }
+    ch = l2cap->cid[cid];
+
+    if (ch->config_req_id != l2cap->last_id)
+        return 1;
+    ch->config_req_id = 0;
+
+    if (result == L2CAP_CONF_SUCCESS) {
+        if (!flag)
+            ch->config |= L2CAP_CFG_INIT;
+        else
+            l2cap_channel_config_null(l2cap, ch);
+    } else
+        /* Retry until we succeed */
+        l2cap_channel_config_req_event(l2cap, ch);
+
+    return 0;
+}
+
+static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid);
+
+    if (!ch)
+        return;
+
+    /* Optional */
+    if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
+{
+    uint8_t data[4];
+    int len = 0;
+    int result = L2CAP_IR_SUCCESS;
+
+    switch (type) {
+    case L2CAP_IT_CL_MTU:
+        data[len ++] = l2cap->group_ch.mps & 0xff;
+        data[len ++] = l2cap->group_ch.mps >> 8;
+        break;
+
+    case L2CAP_IT_FEAT_MASK:
+        /* (Prematurely) report Flow control and Retransmission modes.  */
+        data[len ++] = 0x03;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        break;
+
+    default:
+        result = L2CAP_IR_NOTSUPP;
+    }
+
+    l2cap_info_response(l2cap, type, result, data, len);
+}
+
+static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
+                const uint8_t *params, int len)
+{
+    int err;
+
+#if 0
+    /* TODO: do the IDs really have to be in sequence?  */
+    if (!id || (id != l2cap->last_id && id != l2cap->next_id)) {
+        fprintf(stderr, "%s: out of sequence command packet ignored.\n",
+                        __FUNCTION__);
+        return;
+    }
+#else
+    l2cap->next_id = id;
+#endif
+    if (id == l2cap->next_id) {
+        l2cap->last_id = l2cap->next_id;
+        l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+    } else {
+        /* TODO: Need to re-send the same response, without re-executing
+         * the corresponding command!  */
+    }
+
+    switch (code) {
+    case L2CAP_COMMAND_REJ:
+        if (unlikely(len != 2 && len != 4 && len != 6)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue commands other than Command Reject currently.  */
+        fprintf(stderr, "%s: stray Command Reject (%02x, %04x) "
+                        "packet, ignoring.\n", __FUNCTION__, id,
+                        le16_to_cpu(((l2cap_cmd_rej *) params)->reason));
+        break;
+
+    case L2CAP_CONN_REQ:
+        if (unlikely(len != L2CAP_CONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_open_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conn_req *) params)->psm),
+                        le16_to_cpu(((l2cap_conn_req *) params)->scid));
+        break;
+
+    case L2CAP_CONN_RSP:
+        if (unlikely(len != L2CAP_CONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Connection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Connection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_CONF_REQ:
+        if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_config_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_req *) params)->dcid),
+                        ((l2cap_conf_req *) params)->data,
+                        len - L2CAP_CONF_REQ_SIZE(0));
+        break;
+
+    case L2CAP_CONF_RSP:
+        if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        if (l2cap_channel_config_rsp_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->result),
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->scid),
+                        ((l2cap_conf_rsp *) params)->data,
+                        len - L2CAP_CONF_RSP_SIZE(0)))
+            fprintf(stderr, "%s: unexpected Configure Response (%02x) "
+                            "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_DISCONN_REQ:
+        if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_close(l2cap,
+                        le16_to_cpu(((l2cap_disconn_req *) params)->dcid),
+                        le16_to_cpu(((l2cap_disconn_req *) params)->scid));
+        break;
+
+    case L2CAP_DISCONN_RSP:
+        if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Disconnection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Disconnection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_ECHO_REQ:
+        l2cap_echo_response(l2cap, params, len);
+        break;
+
+    case L2CAP_ECHO_RSP:
+        /* We never issue Echo Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Echo Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_INFO_REQ:
+        if (unlikely(len != L2CAP_INFO_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type));
+        break;
+
+    case L2CAP_INFO_RSP:
+        if (unlikely(len != L2CAP_INFO_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Information Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Information Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    default:
+        err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+    reject:
+        l2cap_command_reject(l2cap, id, err, 0, 0);
+        break;
+    }
+}
+
+static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
+{
+    ch->rexmit = enable;
+
+    l2cap_retransmission_timer_update(ch);
+    l2cap_monitor_timer_update(ch);
+}
+
+/* Command frame SDU */
+static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
+{
+    struct l2cap_instance_s *l2cap = opaque;
+    const l2cap_cmd_hdr *hdr;
+    int clen;
+
+    while (len) {
+        hdr = (void *) data;
+        if (len < L2CAP_CMD_HDR_SIZE)
+            /* TODO: signal an error */
+            return;
+        len -= L2CAP_CMD_HDR_SIZE;
+        data += L2CAP_CMD_HDR_SIZE;
+
+        clen = le16_to_cpu(hdr->len);
+        if (len < clen) {
+            l2cap_command_reject(l2cap, hdr->ident,
+                            L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0);
+            break;
+        }
+
+        l2cap_command(l2cap, hdr->code, hdr->ident, data, clen);
+        len -= clen;
+        data += clen;
+    }
+}
+
+/* Group frame SDU */
+static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
+{
+}
+
+/* Supervisory frame */
+static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
+{
+}
+
+/* Basic L2CAP mode Information frame */
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    /* We have a full SDU, no further processing */
+    ch->params.sdu_in(ch->params.opaque, hdr->data, len);
+}
+
+/* Flow Control and Retransmission mode frame */
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2));
+
+    if (len < 4)
+        goto len_error;
+    if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs)
+        goto fcs_error;
+
+    if ((hdr->data[0] >> 7) == ch->rexmit)
+        l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7));
+
+    if (hdr->data[0] & 1) {
+        if (len != 4) {
+            /* TODO: Signal an error? */
+            return;
+        }
+        return l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data));
+    }
+
+    switch (hdr->data[1] >> 6) {	/* SAR */
+    case L2CAP_SAR_NO_SEG:
+        if (ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        return ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4);
+
+    case L2CAP_SAR_START:
+        if (ch->len_total || len < 6)
+            goto seg_error;
+        if (len - 6 > ch->mps)
+            goto len_error;
+
+        ch->len_total = le16_to_cpup((void *) (hdr->data + 2));
+        if (len >= 6 + ch->len_total)
+            goto seg_error;
+
+        ch->len_cur = len - 6;
+        memcpy(ch->sdu, hdr->data + 4, ch->len_cur);
+        break;
+
+    case L2CAP_SAR_END:
+        if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        return ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total);
+
+    case L2CAP_SAR_CONT:
+        if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        ch->len_cur += len - 4;
+        break;
+
+    seg_error:
+    len_error:	/* TODO */
+    fcs_error:	/* TODO */
+        ch->len_cur = 0;
+        ch->len_total = 0;
+        break;
+    }
+}
+
+static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
+                const l2cap_hdr *frame)
+{
+    uint16_t cid = le16_to_cpu(frame->cid);
+    uint16_t len = le16_to_cpu(frame->len);
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        fprintf(stderr, "%s: frame addressed to a non-existent L2CAP "
+                        "channel %04x received.\n", __FUNCTION__, cid);
+        return;
+    }
+
+    l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len);
+}
+
+/* "Recombination" */
+static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    const l2cap_hdr *hdr = (void *) l2cap->frame_in;
+
+    if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) {
+        if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) {
+            memcpy(l2cap->frame_in + l2cap->frame_in_len, data,
+                            sizeof(l2cap->frame_in) - l2cap->frame_in_len);
+            l2cap->frame_in_len = sizeof(l2cap->frame_in);
+            /* TODO: truncate */
+            l2cap_frame_in(l2cap, hdr);
+        }
+
+        return;
+    }
+
+    memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len);
+    l2cap->frame_in_len += len;
+
+    if (len >= L2CAP_HDR_SIZE)
+        if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len))
+            l2cap_frame_in(l2cap, hdr);
+            /* There is never a start of a new PDU in the same ACL packet, so
+             * no need to memmove the remaining payload and loop.  */
+}
+
+static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap,
+                uint16_t cid, uint16_t len)
+{
+    l2cap_hdr *hdr = (void *) l2cap->frame_out;
+
+    l2cap->frame_out_len = len + L2CAP_HDR_SIZE;
+
+    hdr->cid = cpu_to_le16(cid);
+    hdr->len = cpu_to_le16(len);
+
+    return l2cap->frame_out + L2CAP_HDR_SIZE;
+}
+
+static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
+{
+    /* TODO: Fragmentation */
+    (l2cap->role ?
+     l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp)
+            (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n",
+                        __FUNCTION__,
+                        chan->remote_cid, chan->params.remote_mtu);
+        exit(-1);
+    }
+
+    return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len);
+}
+
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms;
+
+    return l2cap_pdu_submit(chan->l2cap);
+}
+
+#if 0
+/* Stub: Only used if an emulated device requests outgoing flow control */
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        /* TODO: slice into segments and queue each segment as a separate
+         * I-Frame in a FIFO of I-Frames, local to the CID.  */
+    } else {
+        /* TODO: add to the FIFO of I-Frames, local to the CID.  */
+        /* Possibly we need to return a pointer to a contiguous buffer
+         * for now and then memcpy from it into FIFOs in l2cap_iframe_submit
+         * while segmenting at the same time.  */
+    }
+    return 0;
+}
+
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm)
+{
+    /* TODO: If flow control indicates clear to send, start submitting the
+     * invidual I-Frames from the FIFO, but don't remove them from there.
+     * Kick the appropriate timer until we get an S-Frame, and only then
+     * remove from FIFO or resubmit and re-kick the timer if the timer
+     * expired.  */
+}
+#endif
+
+static void l2cap_init(struct l2cap_instance_s *l2cap,
+                struct bt_link_s *link, int role)
+{
+    l2cap->link = link;
+    l2cap->role = role;
+    l2cap->dev = (struct bt_l2cap_device_s *)
+            (role ? link->host : link->slave);
+
+    l2cap->next_id = 1;
+
+    /* Establish the signalling channel */
+    l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in;
+    l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out;
+    l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit;
+    l2cap->signalling_ch.params.opaque = l2cap;
+    l2cap->signalling_ch.params.remote_mtu = 48;
+    l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING;
+    l2cap->signalling_ch.frame_in = l2cap_bframe_in;
+    l2cap->signalling_ch.mps = 65536;
+    l2cap->signalling_ch.min_mtu = 48;
+    l2cap->signalling_ch.mode = L2CAP_MODE_BASIC;
+    l2cap->signalling_ch.l2cap = l2cap;
+    l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch;
+
+    /* Establish the connection-less data channel */
+    l2cap->group_ch.params.sdu_in = l2cap_gframe_in;
+    l2cap->group_ch.params.opaque = l2cap;
+    l2cap->group_ch.frame_in = l2cap_bframe_in;
+    l2cap->group_ch.mps = 65533;
+    l2cap->group_ch.l2cap = l2cap;
+    l2cap->group_ch.remote_cid = L2CAP_CID_INVALID;
+    l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch;
+}
+
+static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
+{
+    int cid;
+
+    /* Don't send DISCONNECT if we are currently handling a DISCONNECT
+     * sent from the other side.  */
+    if (send_disconnect) {
+        if (l2cap->role)
+            l2cap->dev->device.lmp_disconnect_slave(l2cap->link);
+            /* l2cap->link is invalid from now on.  */
+        else
+            l2cap->dev->device.lmp_disconnect_master(l2cap->link);
+    }
+
+    for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
+        if (l2cap->cid[cid]) {
+            l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
+            qemu_free(l2cap->cid[cid]);
+        }
+
+    if (l2cap->role)
+        qemu_free(l2cap);
+    else
+        qemu_free(l2cap->link);
+}
+
+/* L2CAP glue to lower layers in bluetooth stack (LMP) */
+
+static void l2cap_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave;
+    struct slave_l2cap_instance_s *l2cap;
+
+    /* Always accept - we only get called if (dev->device->page_scan).  */
+
+    l2cap = qemu_mallocz(sizeof(struct slave_l2cap_instance_s));
+    l2cap->link.slave = &dev->device;
+    l2cap->link.host = link->host;
+    l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
+
+    /* Always at the end */
+    link->host->reject_reason = 0;
+    link->host->lmp_connection_complete(&l2cap->link);
+}
+
+/* Stub */
+static void l2cap_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap;
+
+    if (dev->device.reject_reason) {
+        /* Signal to upper layer */
+        return;
+    }
+
+    l2cap = qemu_mallocz(sizeof(struct l2cap_instance_s));
+    l2cap_init(l2cap, link, 1);
+
+    link->acl_mode = acl_active;
+
+    /* Signal to upper layer */
+}
+
+/* Stub */
+static void l2cap_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    /* Signal to upper layer */
+
+    l2cap_teardown(l2cap, 0);
+}
+
+static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    l2cap_teardown(&l2cap->l2cap, 0);
+}
+
+static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    if (start)
+        l2cap->l2cap.frame_in_len = 0;
+
+    l2cap_pdu_in(&l2cap->l2cap, data, len);
+}
+
+/* Stub */
+static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    if (start)
+        l2cap->frame_in_len = 0;
+
+    l2cap_pdu_in(l2cap, data, len);
+}
+
+static void l2cap_dummy_destroy(struct bt_device_s *dev)
+{
+    struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev;
+
+    bt_l2cap_device_done(l2cap_dev);
+}
+
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net)
+{
+    bt_device_init(&dev->device, net);
+
+    dev->device.lmp_connection_request = l2cap_lmp_connection_request;
+    dev->device.lmp_connection_complete = l2cap_lmp_connection_complete;
+    dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host;
+    dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave;
+    dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave;
+    dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host;
+
+    dev->device.handle_destroy = l2cap_dummy_destroy;
+}
+
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev)
+{
+    bt_device_done(&dev->device);
+
+    /* Should keep a list of all instances and go through it and
+     * invoke l2cap_teardown() for each.  */
+}
+
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
+                int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params))
+{
+    struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm);
+
+    if (new_psm) {
+        fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n",
+                        __FUNCTION__, psm, dev->device.lmp_name);
+        exit(-1);
+    }
+
+    new_psm = qemu_mallocz(sizeof(*new_psm));
+    new_psm->psm = psm;
+    new_psm->min_mtu = min_mtu;
+    new_psm->new_channel = new_channel;
+    new_psm->next = dev->first_psm;
+    dev->first_psm = new_psm;
+}
diff --git a/qemu-0.15.x/hw/bt-sdp.c b/qemu-0.15.x/hw/bt-sdp.c
new file mode 100644
index 0000000..cdf2d95
--- /dev/null
+++ b/qemu-0.15.x/hw/bt-sdp.c
@@ -0,0 +1,967 @@
+/*
+ * Service Discover Protocol server for QEMU L2CAP devices
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "bt.h"
+
+struct bt_l2cap_sdp_state_s {
+    struct bt_l2cap_conn_params_s *channel;
+
+    struct sdp_service_record_s {
+        int match;
+
+        int *uuid;
+        int uuids;
+        struct sdp_service_attribute_s {
+            int match;
+
+            int attribute_id;
+            int len;
+            void *pair;
+        } *attribute_list;
+        int attributes;
+    } *service_list;
+    int services;
+};
+
+static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
+{
+    size_t len = *(*element) ++ & SDP_DSIZE_MASK;
+
+    if (!*left)
+        return -1;
+    (*left) --;
+
+    if (len < SDP_DSIZE_NEXT1)
+        return 1 << len;
+    else if (len == SDP_DSIZE_NEXT1) {
+        if (*left < 1)
+            return -1;
+        (*left) --;
+
+        return *(*element) ++;
+    } else if (len == SDP_DSIZE_NEXT2) {
+        if (*left < 2)
+            return -1;
+        (*left) -= 2;
+
+        len = (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    } else {
+        if (*left < 4)
+            return -1;
+        (*left) -= 4;
+
+        len = (*(*element) ++) << 24;
+        len |= (*(*element) ++) << 16;
+        len |= (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    }
+}
+
+static const uint8_t bt_base_uuid[12] = {
+    0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+};
+
+static int sdp_uuid_match(struct sdp_service_record_s *record,
+                const uint8_t *uuid, ssize_t datalen)
+{
+    int *lo, hi, val;
+
+    if (datalen == 16 || datalen == 4) {
+        if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
+            return 0;
+
+        if (uuid[0] | uuid[1])
+            return 0;
+        uuid += 2;
+    }
+
+    val = (uuid[0] << 8) | uuid[1];
+    lo = record->uuid;
+    hi = record->uuids;
+    while (hi >>= 1)
+        if (lo[hi] <= val)
+            lo += hi;
+
+    return *lo == val;
+}
+
+#define CONTINUATION_PARAM_SIZE	(1 + sizeof(int))
+#define MAX_PDU_OUT_SIZE	96	/* Arbitrary */
+#define PDU_HEADER_SIZE		5
+#define MAX_RSP_PARAM_SIZE	(MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
+                CONTINUATION_PARAM_SIZE)
+
+static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    size_t datalen;
+    int i;
+
+    if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
+        return 1;
+
+    datalen = sdp_datalen(req, len);
+    if (datalen != 2 && datalen != 4 && datalen != 16)
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
+            sdp->service_list[i].match = 1;
+
+    (*req) += datalen;
+    (*len) -= datalen;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, count, start, end, max;
+    int32_t handle;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++)
+        sdp->service_list[i].match = 0;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    len = 4;
+    count = 0;
+    end = start;
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp->service_list[i].match) {
+            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
+                handle = i;
+                memcpy(rsp + len, &handle, 4);
+                len += 4;
+                end = count + 1;
+            }
+
+            count ++;
+        }
+
+    rsp[0] = count >> 8;
+    rsp[1] = count & 0xff;
+    rsp[2] = (end - start) >> 8;
+    rsp[3] = (end - start) & 0xff;
+
+    if (end < count) {
+        rsp[len ++] = sizeof(int);
+        memcpy(rsp + len, &end, sizeof(int));
+        len += 4;
+    } else
+        rsp[len ++] = 0;
+
+    return len;
+}
+
+static int sdp_attr_match(struct sdp_service_record_s *record,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, start, end;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].attribute_id >= start &&
+                        record->attribute_list[i].attribute_id <= end)
+            record->attribute_list[i].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, start, end, max;
+    int32_t handle;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    if (len < 7)
+        return -SDP_INVALID_SYNTAX;
+    memcpy(&handle, req, 4);
+    req += 4;
+    len -= 4;
+
+    if (handle < 0 || handle > sdp->services)
+        return -SDP_INVALID_RECORD_HANDLE;
+    record = &sdp->service_list[handle];
+
+    for (i = 0; i < record->attributes; i ++)
+        record->attribute_list[i].match = 0;
+
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_attr_match(record, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_attr_match(record, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].match) {
+            if (len >= 0 && len + record->attribute_list[i].len < max) {
+                memcpy(lst + len, record->attribute_list[i].pair,
+                                record->attribute_list[i].len);
+                end = len + record->attribute_list[i].len;
+            }
+            len += record->attribute_list[i].len;
+        }
+    if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, j, start, end;
+    struct sdp_service_record_s *record;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match)
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].attribute_id >= start &&
+                                record->attribute_list[j].attribute_id <= end)
+                    record->attribute_list[j].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, j, start, end, max;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++) {
+        sdp->service_list[i].match = 0;
+            for (j = 0; j < sdp->service_list[i].attributes; j ++)
+                sdp->service_list[i].attribute_list[j].match = 0;
+    }
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_attr_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_attr_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    /* This assumes empty attribute lists are never to be returned even
+     * for matching Service Records.  In practice this shouldn't happen
+     * as the requestor will usually include the always present
+     * ServiceRecordHandle AttributeID in AttributeIDList.  */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match) {
+            len += 3;
+            seqlen = len;
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].match) {
+                    if (len >= 0)
+                        if (len + record->attribute_list[j].len < max) {
+                            memcpy(lst + len, record->attribute_list[j].pair,
+                                            record->attribute_list[j].len);
+                            end = len + record->attribute_list[j].len;
+                        }
+                    len += record->attribute_list[j].len;
+                }
+            if (seqlen == len)
+                len -= 3;
+            else if (seqlen >= 3 && seqlen < max) {
+                lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+                lst[seqlen - 2] = (len - seqlen) >> 8;
+                lst[seqlen - 1] = (len - seqlen) & 0xff;
+            }
+        }
+    if (len == 3 - start)
+        len -= 3;
+    else if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    enum bt_sdp_cmd pdu_id;
+    uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
+    int transaction_id, plen;
+    int err = 0;
+    int rsp_len = 0;
+
+    if (len < 5) {
+        fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
+        return;
+    }
+
+    pdu_id = *data ++;
+    transaction_id = (data[0] << 8) | data[1];
+    plen = (data[2] << 8) | data[3];
+    data += 4;
+    len -= 5;
+
+    if (len != plen) {
+        fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
+                        __FUNCTION__, plen, len);
+        err = SDP_INVALID_PDU_SIZE;
+        goto respond;
+    }
+
+    switch (pdu_id) {
+    case SDP_SVC_SEARCH_REQ:
+        rsp_len = sdp_svc_search(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_RSP;
+        break;
+
+    case SDP_SVC_ATTR_REQ:
+        rsp_len = sdp_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_ATTR_RSP;
+        break;
+
+    case SDP_SVC_SEARCH_ATTR_REQ:
+        rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
+        break;
+
+    case SDP_ERROR_RSP:
+    case SDP_SVC_ATTR_RSP:
+    case SDP_SVC_SEARCH_RSP:
+    case SDP_SVC_SEARCH_ATTR_RSP:
+    default:
+        fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
+                        __FUNCTION__, pdu_id);
+        err = SDP_INVALID_SYNTAX;
+        break;
+    }
+
+    if (rsp_len < 0) {
+        err = -rsp_len;
+        rsp_len = 0;
+    }
+
+respond:
+    if (err) {
+        pdu_id = SDP_ERROR_RSP;
+        rsp[rsp_len ++] = err >> 8;
+        rsp[rsp_len ++] = err & 0xff;
+    }
+
+    sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
+
+    sdu_out[0] = pdu_id;
+    sdu_out[1] = transaction_id >> 8;
+    sdu_out[2] = transaction_id & 0xff;
+    sdu_out[3] = rsp_len >> 8;
+    sdu_out[4] = rsp_len & 0xff;
+    memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
+
+    sdp->channel->sdu_submit(sdp->channel);
+}
+
+static void bt_l2cap_sdp_close_ch(void *opaque)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    int i;
+
+    for (i = 0; i < sdp->services; i ++) {
+        qemu_free(sdp->service_list[i].attribute_list->pair);
+        qemu_free(sdp->service_list[i].attribute_list);
+        qemu_free(sdp->service_list[i].uuid);
+    }
+    qemu_free(sdp->service_list);
+    qemu_free(sdp);
+}
+
+struct sdp_def_service_s {
+    uint16_t class_uuid;
+    struct sdp_def_attribute_s {
+        uint16_t id;
+        struct sdp_def_data_element_s {
+            uint8_t type;
+            union {
+                uint32_t uint;
+                const char *str;
+                struct sdp_def_data_element_s *list;
+            } value;
+        } data;
+    } attributes[];
+};
+
+/* Calculate a safe byte count to allocate that will store the given
+ * element, at the same time count elements of a UUID type.  */
+static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
+                int *uuids)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
+                    type == SDP_DTYPE_BOOL) {
+        if (type == SDP_DTYPE_UUID)
+            (*uuids) ++;
+        return 1 + (1 << (element->type & SDP_DSIZE_MASK));
+    }
+
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK) {
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+            return len;
+        } else
+            return 2 + strlen(element->value.str);
+    }
+
+    if (type != SDP_DTYPE_SEQ)
+        exit(-1);
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_max_size(element ++, uuids);
+    if (len > 255)
+        exit (-1);
+
+    return len;
+}
+
+static int sdp_attr_write(uint8_t *data,
+                struct sdp_def_data_element_s *element, int **uuid)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len = 0;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
+        data[len ++] = element->type;
+        if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
+            data[len ++] = (element->value.uint >>  24) & 0xff;
+            data[len ++] = (element->value.uint >>  16) & 0xff;
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        }
+
+        return len;
+    }
+
+    if (type == SDP_DTYPE_UUID) {
+        *(*uuid) ++ = element->value.uint;
+
+        data[len ++] = element->type;
+        data[len ++] = (element->value.uint >>  24) & 0xff;
+        data[len ++] = (element->value.uint >>  16) & 0xff;
+        data[len ++] = (element->value.uint >>  8) & 0xff;
+        data[len ++] = (element->value.uint >>  0) & 0xff;
+        memcpy(data + len, bt_base_uuid, 12);
+
+        return len + 12;
+    }
+
+    data[0] = type | SDP_DSIZE_NEXT1;
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK)
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+        else
+            len = strlen(element->value.str);
+        memcpy(data + 2, element->value.str, data[1] = len);
+
+        return len + 2;
+    }
+
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_write(data + len, element ++, uuid);
+    data[1] = len - 2;
+
+    return len;
+}
+
+static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
+                const struct sdp_service_attribute_s *b)
+{
+    return (int) b->attribute_id - a->attribute_id;
+}
+
+static int sdp_uuid_compare(const int *a, const int *b)
+{
+    return *a - *b;
+}
+
+static void sdp_service_record_build(struct sdp_service_record_s *record,
+                struct sdp_def_service_s *def, int handle)
+{
+    int len = 0;
+    uint8_t *data;
+    int *uuid;
+
+    record->uuids = 0;
+    while (def->attributes[record->attributes].data.type) {
+        len += 3;
+        len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
+                        &record->uuids);
+    }
+    record->uuids = 1 << ffs(record->uuids - 1);
+    record->attribute_list =
+            qemu_mallocz(record->attributes * sizeof(*record->attribute_list));
+    record->uuid =
+            qemu_mallocz(record->uuids * sizeof(*record->uuid));
+    data = qemu_malloc(len);
+
+    record->attributes = 0;
+    uuid = record->uuid;
+    while (def->attributes[record->attributes].data.type) {
+        record->attribute_list[record->attributes].pair = data;
+
+        len = 0;
+        data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
+        data[len ++] = def->attributes[record->attributes].id >> 8;
+        data[len ++] = def->attributes[record->attributes].id & 0xff;
+        len += sdp_attr_write(data + len,
+                        &def->attributes[record->attributes].data, &uuid);
+
+        /* Special case: assign a ServiceRecordHandle in sequence */
+        if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
+            def->attributes[record->attributes].data.value.uint = handle;
+        /* Note: we could also assign a ServiceDescription based on
+         * sdp->device.device->lmp_name.  */
+
+        record->attribute_list[record->attributes ++].len = len;
+        data += len;
+    }
+
+    /* Sort the attribute list by the AttributeID */
+    qsort(record->attribute_list, record->attributes,
+                    sizeof(*record->attribute_list),
+                    (void *) sdp_attributeid_compare);
+    /* Sort the searchable UUIDs list for bisection */
+    qsort(record->uuid, record->uuids,
+                    sizeof(*record->uuid),
+                    (void *) sdp_uuid_compare);
+}
+
+static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
+                struct sdp_def_service_s **service)
+{
+    sdp->services = 0;
+    while (service[sdp->services])
+        sdp->services ++;
+    sdp->service_list =
+            qemu_mallocz(sdp->services * sizeof(*sdp->service_list));
+
+    sdp->services = 0;
+    while (*service) {
+        sdp_service_record_build(&sdp->service_list[sdp->services],
+                        *service, sdp->services);
+        service ++;
+        sdp->services ++;
+    }
+}
+
+#define LAST { .type = 0 }
+#define SERVICE(name, attrs)				\
+    static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
+        .attributes = { attrs { .data = LAST } },	\
+    };
+#define ATTRIBUTE(attrid, val)	{ .id = glue(SDP_ATTR_, attrid), .data = val },
+#define UINT8(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_1,	\
+        .value.uint = val,				\
+    },
+#define UINT16(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_2,	\
+        .value.uint = val,				\
+    },
+#define UINT32(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_4,	\
+        .value.uint = val,				\
+    },
+#define UUID128(val)	{				\
+        .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,	\
+        .value.uint = val,				\
+    },
+#define SDP_TRUE	{				\
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
+        .value.uint = 1,				\
+    },
+#define SDP_FALSE	{				\
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
+        .value.uint = 0,				\
+    },
+#define STRING(val)	{				\
+        .type       = SDP_DTYPE_STRING,			\
+        .value.str  = val,				\
+    },
+#define ARRAY(...)	{				\
+        .type       = SDP_DTYPE_STRING | SDP_DSIZE_2,	\
+        .value.str  = (char []) { __VA_ARGS__, 0, 0 },	\
+    },
+#define URL(val)	{				\
+        .type       = SDP_DTYPE_URL,			\
+        .value.str  = val,				\
+    },
+#if 1
+#define LIST(val)	{				\
+        .type       = SDP_DTYPE_SEQ,			\
+        .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
+    },
+#endif
+
+/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
+ * in resulting SDP data representation size.  */
+
+SERVICE(hid,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
+        LIST(UUID128(HIDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
+    ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(DEVICE_RELEASE_NUMBER,	UINT16(0x0091)) /* Deprecated, remove */
+    ATTRIBUTE(PARSER_VERSION,		UINT16(0x0111))
+    /* TODO: extract from l2cap_device->device.class[0] */
+    ATTRIBUTE(DEVICE_SUBCLASS,		UINT8(0x40))
+    ATTRIBUTE(COUNTRY_CODE,		UINT8(0x15))
+    ATTRIBUTE(VIRTUAL_CABLE,		SDP_TRUE)
+    ATTRIBUTE(RECONNECT_INITIATE,	SDP_FALSE)
+    /* TODO: extract from hid->usbdev->report_desc */
+    ATTRIBUTE(DESCRIPTOR_LIST,		LIST(
+        LIST(UINT8(0x22) ARRAY(
+            0x05, 0x01,	/* Usage Page (Generic Desktop) */
+            0x09, 0x06,	/* Usage (Keyboard) */
+            0xa1, 0x01,	/* Collection (Application) */
+            0x75, 0x01,	/*   Report Size (1) */
+            0x95, 0x08,	/*   Report Count (8) */
+            0x05, 0x07,	/*   Usage Page (Key Codes) */
+            0x19, 0xe0,	/*   Usage Minimum (224) */
+            0x29, 0xe7,	/*   Usage Maximum (231) */
+            0x15, 0x00,	/*   Logical Minimum (0) */
+            0x25, 0x01,	/*   Logical Maximum (1) */
+            0x81, 0x02,	/*   Input (Data, Variable, Absolute) */
+            0x95, 0x01,	/*   Report Count (1) */
+            0x75, 0x08,	/*   Report Size (8) */
+            0x81, 0x01,	/*   Input (Constant) */
+            0x95, 0x05,	/*   Report Count (5) */
+            0x75, 0x01,	/*   Report Size (1) */
+            0x05, 0x08,	/*   Usage Page (LEDs) */
+            0x19, 0x01,	/*   Usage Minimum (1) */
+            0x29, 0x05,	/*   Usage Maximum (5) */
+            0x91, 0x02,	/*   Output (Data, Variable, Absolute) */
+            0x95, 0x01,	/*   Report Count (1) */
+            0x75, 0x03,	/*   Report Size (3) */
+            0x91, 0x01,	/*   Output (Constant) */
+            0x95, 0x06,	/*   Report Count (6) */
+            0x75, 0x08,	/*   Report Size (8) */
+            0x15, 0x00,	/*   Logical Minimum (0) */
+            0x25, 0xff,	/*   Logical Maximum (255) */
+            0x05, 0x07,	/*   Usage Page (Key Codes) */
+            0x19, 0x00,	/*   Usage Minimum (0) */
+            0x29, 0xff,	/*   Usage Maximum (255) */
+            0x81, 0x00,	/*   Input (Data, Array) */
+            0xc0	/* End Collection */
+    ))))
+    ATTRIBUTE(LANG_ID_BASE_LIST,	LIST(
+        LIST(UINT16(0x0409) UINT16(0x0100))
+    ))
+    ATTRIBUTE(SDP_DISABLE,		SDP_FALSE)
+    ATTRIBUTE(BATTERY_POWER,		SDP_TRUE)
+    ATTRIBUTE(REMOTE_WAKEUP,		SDP_TRUE)
+    ATTRIBUTE(BOOT_DEVICE,		SDP_TRUE)	/* XXX: untested */
+    ATTRIBUTE(SUPERVISION_TIMEOUT,	UINT16(0x0c80))
+    ATTRIBUTE(NORMALLY_CONNECTABLE,	SDP_TRUE)
+    ATTRIBUTE(PROFILE_VERSION,		UINT16(0x0100))
+)
+
+SERVICE(sdp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
+    ATTRIBUTE(SVCDB_STATE    , UINT32(1))
+)
+
+SERVICE(pnp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
+    ATTRIBUTE(VERSION,         UINT16(0x0100))
+    ATTRIBUTE(PRIMARY_RECORD,  SDP_TRUE)
+)
+
+static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_l2cap_sdp_state_s *sdp = qemu_mallocz(sizeof(*sdp));
+    struct sdp_def_service_s *services[] = {
+        &sdp_service_sdp_s,
+        &sdp_service_hid_s,
+        &sdp_service_pnp_s,
+        NULL,
+    };
+
+    sdp->channel = params;
+    sdp->channel->opaque = sdp;
+    sdp->channel->close = bt_l2cap_sdp_close_ch;
+    sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
+
+    sdp_service_db_build(sdp, services);
+
+    return 0;
+}
+
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
+{
+    bt_l2cap_psm_register(dev, BT_PSM_SDP,
+                    MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
+}
diff --git a/qemu-0.15.x/hw/bt.c b/qemu-0.15.x/hw/bt.c
new file mode 100644
index 0000000..34bf004
--- /dev/null
+++ b/qemu-0.15.x/hw/bt.c
@@ -0,0 +1,121 @@
+/*
+ * Convenience functions for bluetooth.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "net.h"
+#include "bt.h"
+
+/* Slave implementations can ignore this */
+static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
+{
+}
+
+/* Slaves should never receive these PDUs */
+static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
+{
+    if (link->slave->reject_reason)
+        fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
+                        __FUNCTION__);
+    else
+        fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
+                        __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
+{
+    fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+/* Slaves that don't hold any additional per link state can use these */
+static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
+{
+    struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s));
+
+    link->slave = req->slave;
+    link->host = req->host;
+
+    req->host->reject_reason = 0;
+    req->host->lmp_connection_complete(link);
+}
+
+static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    qemu_free(link);
+}
+
+static void bt_dummy_destroy(struct bt_device_s *device)
+{
+    bt_device_done(device);
+    qemu_free(device);
+}
+
+static int bt_dev_idx = 0;
+
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
+{
+    memset(dev, 0, sizeof(*dev));
+    dev->inquiry_scan = 1;
+    dev->page_scan = 1;
+
+    dev->bd_addr.b[0] = bt_dev_idx & 0xff;
+    dev->bd_addr.b[1] = bt_dev_idx >> 8;
+    dev->bd_addr.b[2] = 0xd0;
+    dev->bd_addr.b[3] = 0xba;
+    dev->bd_addr.b[4] = 0xbe;
+    dev->bd_addr.b[5] = 0xba;
+    bt_dev_idx ++;
+
+    /* Simple slave-only devices need to implement only .lmp_acl_data */
+    dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
+    dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
+    dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
+    dev->lmp_mode_change = bt_dummy_lmp_mode_change;
+    dev->lmp_connection_request = bt_dummy_lmp_connection_request;
+    dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
+
+    dev->handle_destroy = bt_dummy_destroy;
+
+    dev->net = net;
+    dev->next = net->slave;
+    net->slave = dev;
+}
+
+void bt_device_done(struct bt_device_s *dev)
+{
+    struct bt_device_s **p = &dev->net->slave;
+
+    while (*p && *p != dev)
+        p = &(*p)->next;
+    if (*p != dev) {
+        fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
+                        dev->lmp_name ?: "(null)");
+        exit(-1);
+    }
+
+    *p = dev->next;
+}
diff --git a/qemu-0.15.x/hw/bt.h b/qemu-0.15.x/hw/bt.h
new file mode 100644
index 0000000..3797254
--- /dev/null
+++ b/qemu-0.15.x/hw/bt.h
@@ -0,0 +1,2183 @@
+/*
+ * QEMU Bluetooth HCI helpers.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * Useful definitions taken from BlueZ project's headers.
+ * Copyright (C) 2000-2001  Qualcomm Incorporated
+ * Copyright (C) 2002-2003  Maxim Krasnyansky <maxk at qualcomm.com>
+ * Copyright (C) 2002-2006  Marcel Holtmann <marcel at holtmann.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* BD Address */
+typedef struct {
+    uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define BDADDR_ANY	(&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
+#define BDADDR_ALL	(&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
+#define BDADDR_LOCAL	(&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+
+/* Copy, swap, convert BD Address */
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
+{
+    return memcmp(ba1, ba2, sizeof(bdaddr_t));
+}
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+    memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+#define BAINIT(orig)	{ .b = {		\
+    (orig)->b[0], (orig)->b[1], (orig)->b[2],	\
+    (orig)->b[3], (orig)->b[4], (orig)->b[5],	\
+}, }
+
+/* The twisted structures of a bluetooth environment */
+struct bt_device_s;
+struct bt_scatternet_s;
+struct bt_piconet_s;
+struct bt_link_s;
+
+struct bt_scatternet_s {
+    struct bt_device_s *slave;
+};
+
+struct bt_link_s {
+    struct bt_device_s *slave, *host;
+    uint16_t handle;		/* Master (host) side handle */
+    uint16_t acl_interval;
+    enum {
+        acl_active,
+        acl_hold,
+        acl_sniff,
+        acl_parked,
+    } acl_mode;
+};
+
+struct bt_device_s {
+    int lt_addr;
+    bdaddr_t bd_addr;
+    int mtu;
+    int setup;
+    struct bt_scatternet_s *net;
+
+    uint8_t key[16];
+    int key_present;
+    uint8_t class[3];
+
+    uint8_t reject_reason;
+
+    uint64_t lmp_caps;
+    const char *lmp_name;
+    void (*lmp_connection_request)(struct bt_link_s *link);
+    void (*lmp_connection_complete)(struct bt_link_s *link);
+    void (*lmp_disconnect_master)(struct bt_link_s *link);
+    void (*lmp_disconnect_slave)(struct bt_link_s *link);
+    void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_mode_change)(struct bt_link_s *link);
+
+    void (*handle_destroy)(struct bt_device_s *device);
+    struct bt_device_s *next;	/* Next in the piconet/scatternet */
+
+    int inquiry_scan;
+    int page_scan;
+
+    uint16_t clkoff;	/* Note: Always little-endian */
+};
+
+/* bt.c */
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net);
+void bt_device_done(struct bt_device_s *dev);
+
+/* bt-hci.c */
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net);
+
+/* bt-vhci.c */
+void bt_vhci_init(struct HCIInfo *info);
+
+/* bt-hci-csr.c */
+enum {
+    csrhci_pin_reset,
+    csrhci_pin_wakeup,
+    __csrhci_pins,
+};
+qemu_irq *csrhci_pins_get(CharDriverState *chr);
+CharDriverState *uart_hci_init(qemu_irq wakeup);
+
+/* bt-l2cap.c */
+struct bt_l2cap_device_s;
+struct bt_l2cap_conn_params_s;
+struct bt_l2cap_psm_s;
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net);
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev);
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm,
+                int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params));
+
+struct bt_l2cap_device_s {
+    struct bt_device_s device;
+    struct bt_l2cap_psm_s *first_psm;
+};
+
+struct bt_l2cap_conn_params_s {
+    /* Input */
+    uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len);
+    void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan);
+    int remote_mtu;
+    /* Output */
+    void *opaque;
+    void (*sdu_in)(void *opaque, const uint8_t *data, int len);
+    void (*close)(void *opaque);
+};
+
+enum bt_l2cap_psm_predef {
+    BT_PSM_SDP		= 0x0001,
+    BT_PSM_RFCOMM	= 0x0003,
+    BT_PSM_TELEPHONY	= 0x0005,
+    BT_PSM_TCS		= 0x0007,
+    BT_PSM_BNEP		= 0x000f,
+    BT_PSM_HID_CTRL	= 0x0011,
+    BT_PSM_HID_INTR	= 0x0013,
+    BT_PSM_UPNP		= 0x0015,
+    BT_PSM_AVCTP	= 0x0017,
+    BT_PSM_AVDTP	= 0x0019,
+};
+
+/* bt-sdp.c */
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev);
+
+/* bt-hid.c */
+struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net);
+
+/* Link Management Protocol layer defines */
+
+#define LLID_ACLU_CONT		0x1
+#define LLID_ACLU_START		0x2
+#define LLID_ACLC		0x3
+
+enum lmp_pdu_type {
+    LMP_NAME_REQ		= 0x0001,
+    LMP_NAME_RES		= 0x0002,
+    LMP_ACCEPTED		= 0x0003,
+    LMP_NOT_ACCEPTED		= 0x0004,
+    LMP_CLKOFFSET_REQ		= 0x0005,
+    LMP_CLKOFFSET_RES		= 0x0006,
+    LMP_DETACH			= 0x0007,
+    LMP_IN_RAND			= 0x0008,
+    LMP_COMB_KEY		= 0x0009,
+    LMP_UNIT_KEY		= 0x000a,
+    LMP_AU_RAND			= 0x000b,
+    LMP_SRES			= 0x000c,
+    LMP_TEMP_RAND		= 0x000d,
+    LMP_TEMP_KEY		= 0x000e,
+    LMP_CRYPT_MODE_REQ		= 0x000f,
+    LMP_CRYPT_KEY_SIZE_REQ	= 0x0010,
+    LMP_START_ENCRYPT_REQ	= 0x0011,
+    LMP_STOP_ENCRYPT_REQ	= 0x0012,
+    LMP_SWITCH_REQ		= 0x0013,
+    LMP_HOLD			= 0x0014,
+    LMP_HOLD_REQ		= 0x0015,
+    LMP_SNIFF_REQ		= 0x0017,
+    LMP_UNSNIFF_REQ		= 0x0018,
+    LMP_LMP_PARK_REQ		= 0x0019,
+    LMP_SET_BCAST_SCAN_WND	= 0x001b,
+    LMP_MODIFY_BEACON		= 0x001c,
+    LMP_UNPARK_BD_ADDR_REQ	= 0x001d,
+    LMP_UNPARK_PM_ADDR_REQ	= 0x001e,
+    LMP_INCR_POWER_REQ		= 0x001f,
+    LMP_DECR_POWER_REQ		= 0x0020,
+    LMP_MAX_POWER		= 0x0021,
+    LMP_MIN_POWER		= 0x0022,
+    LMP_AUTO_RATE		= 0x0023,
+    LMP_PREFERRED_RATE		= 0x0024,
+    LMP_VERSION_REQ		= 0x0025,
+    LMP_VERSION_RES		= 0x0026,
+    LMP_FEATURES_REQ		= 0x0027,
+    LMP_FEATURES_RES		= 0x0028,
+    LMP_QUALITY_OF_SERVICE	= 0x0029,
+    LMP_QOS_REQ			= 0x002a,
+    LMP_RM_SCO_LINK_REQ		= 0x002b,
+    LMP_SCO_LINK_REQ		= 0x002c,
+    LMP_MAX_SLOT		= 0x002d,
+    LMP_MAX_SLOT_REQ		= 0x002e,
+    LMP_TIMING_ACCURACY_REQ	= 0x002f,
+    LMP_TIMING_ACCURACY_RES	= 0x0030,
+    LMP_SETUP_COMPLETE		= 0x0031,
+    LMP_USE_SEMIPERM_KEY	= 0x0032,
+    LMP_HOST_CONNECTION_REQ	= 0x0033,
+    LMP_SLOT_OFFSET		= 0x0034,
+    LMP_PAGE_MODE_REQ		= 0x0035,
+    LMP_PAGE_SCAN_MODE_REQ	= 0x0036,
+    LMP_SUPERVISION_TIMEOUT	= 0x0037,
+    LMP_TEST_ACTIVATE		= 0x0038,
+    LMP_TEST_CONTROL		= 0x0039,
+    LMP_CRYPT_KEY_MASK_REQ	= 0x003a,
+    LMP_CRYPT_KEY_MASK_RES	= 0x003b,
+    LMP_SET_AFH			= 0x003c,
+    LMP_ACCEPTED_EXT		= 0x7f01,
+    LMP_NOT_ACCEPTED_EXT	= 0x7f02,
+    LMP_FEATURES_REQ_EXT	= 0x7f03,
+    LMP_FEATURES_RES_EXT	= 0x7f04,
+    LMP_PACKET_TYPE_TBL_REQ	= 0x7f0b,
+    LMP_ESCO_LINK_REQ		= 0x7f0c,
+    LMP_RM_ESCO_LINK_REQ	= 0x7f0d,
+    LMP_CHANNEL_CLASS_REQ	= 0x7f10,
+    LMP_CHANNEL_CLASS		= 0x7f11,
+};
+
+/* Host Controller Interface layer defines */
+
+enum hci_packet_type {
+    HCI_COMMAND_PKT		= 0x01,
+    HCI_ACLDATA_PKT		= 0x02,
+    HCI_SCODATA_PKT		= 0x03,
+    HCI_EVENT_PKT		= 0x04,
+    HCI_VENDOR_PKT		= 0xff,
+};
+
+enum bt_packet_type {
+    HCI_2DH1	= 1 << 1,
+    HCI_3DH1	= 1 << 2,
+    HCI_DM1	= 1 << 3,
+    HCI_DH1	= 1 << 4,
+    HCI_2DH3	= 1 << 8,
+    HCI_3DH3	= 1 << 9,
+    HCI_DM3	= 1 << 10,
+    HCI_DH3	= 1 << 11,
+    HCI_2DH5	= 1 << 12,
+    HCI_3DH5	= 1 << 13,
+    HCI_DM5	= 1 << 14,
+    HCI_DH5	= 1 << 15,
+};
+
+enum sco_packet_type {
+    HCI_HV1	= 1 << 5,
+    HCI_HV2	= 1 << 6,
+    HCI_HV3	= 1 << 7,
+};
+
+enum ev_packet_type {
+    HCI_EV3	= 1 << 3,
+    HCI_EV4	= 1 << 4,
+    HCI_EV5	= 1 << 5,
+    HCI_2EV3	= 1 << 6,
+    HCI_3EV3	= 1 << 7,
+    HCI_2EV5	= 1 << 8,
+    HCI_3EV5	= 1 << 9,
+};
+
+enum hci_error_code {
+    HCI_SUCCESS				= 0x00,
+    HCI_UNKNOWN_COMMAND			= 0x01,
+    HCI_NO_CONNECTION			= 0x02,
+    HCI_HARDWARE_FAILURE		= 0x03,
+    HCI_PAGE_TIMEOUT			= 0x04,
+    HCI_AUTHENTICATION_FAILURE		= 0x05,
+    HCI_PIN_OR_KEY_MISSING		= 0x06,
+    HCI_MEMORY_FULL			= 0x07,
+    HCI_CONNECTION_TIMEOUT		= 0x08,
+    HCI_MAX_NUMBER_OF_CONNECTIONS	= 0x09,
+    HCI_MAX_NUMBER_OF_SCO_CONNECTIONS	= 0x0a,
+    HCI_ACL_CONNECTION_EXISTS		= 0x0b,
+    HCI_COMMAND_DISALLOWED		= 0x0c,
+    HCI_REJECTED_LIMITED_RESOURCES	= 0x0d,
+    HCI_REJECTED_SECURITY		= 0x0e,
+    HCI_REJECTED_PERSONAL		= 0x0f,
+    HCI_HOST_TIMEOUT			= 0x10,
+    HCI_UNSUPPORTED_FEATURE		= 0x11,
+    HCI_INVALID_PARAMETERS		= 0x12,
+    HCI_OE_USER_ENDED_CONNECTION	= 0x13,
+    HCI_OE_LOW_RESOURCES		= 0x14,
+    HCI_OE_POWER_OFF			= 0x15,
+    HCI_CONNECTION_TERMINATED		= 0x16,
+    HCI_REPEATED_ATTEMPTS		= 0x17,
+    HCI_PAIRING_NOT_ALLOWED		= 0x18,
+    HCI_UNKNOWN_LMP_PDU			= 0x19,
+    HCI_UNSUPPORTED_REMOTE_FEATURE	= 0x1a,
+    HCI_SCO_OFFSET_REJECTED		= 0x1b,
+    HCI_SCO_INTERVAL_REJECTED		= 0x1c,
+    HCI_AIR_MODE_REJECTED		= 0x1d,
+    HCI_INVALID_LMP_PARAMETERS		= 0x1e,
+    HCI_UNSPECIFIED_ERROR		= 0x1f,
+    HCI_UNSUPPORTED_LMP_PARAMETER_VALUE	= 0x20,
+    HCI_ROLE_CHANGE_NOT_ALLOWED		= 0x21,
+    HCI_LMP_RESPONSE_TIMEOUT		= 0x22,
+    HCI_LMP_ERROR_TRANSACTION_COLLISION	= 0x23,
+    HCI_LMP_PDU_NOT_ALLOWED		= 0x24,
+    HCI_ENCRYPTION_MODE_NOT_ACCEPTED	= 0x25,
+    HCI_UNIT_LINK_KEY_USED		= 0x26,
+    HCI_QOS_NOT_SUPPORTED		= 0x27,
+    HCI_INSTANT_PASSED			= 0x28,
+    HCI_PAIRING_NOT_SUPPORTED		= 0x29,
+    HCI_TRANSACTION_COLLISION		= 0x2a,
+    HCI_QOS_UNACCEPTABLE_PARAMETER	= 0x2c,
+    HCI_QOS_REJECTED			= 0x2d,
+    HCI_CLASSIFICATION_NOT_SUPPORTED	= 0x2e,
+    HCI_INSUFFICIENT_SECURITY		= 0x2f,
+    HCI_PARAMETER_OUT_OF_RANGE		= 0x30,
+    HCI_ROLE_SWITCH_PENDING		= 0x32,
+    HCI_SLOT_VIOLATION			= 0x34,
+    HCI_ROLE_SWITCH_FAILED		= 0x35,
+};
+
+enum acl_flag_bits {
+    ACL_CONT		= 1 << 0,
+    ACL_START		= 1 << 1,
+    ACL_ACTIVE_BCAST	= 1 << 2,
+    ACL_PICO_BCAST	= 1 << 3,
+};
+
+enum baseband_link_type {
+    SCO_LINK		= 0x00,
+    ACL_LINK		= 0x01,
+};
+
+enum lmp_feature_bits0 {
+    LMP_3SLOT		= 1 << 0,
+    LMP_5SLOT		= 1 << 1,
+    LMP_ENCRYPT		= 1 << 2,
+    LMP_SOFFSET		= 1 << 3,
+    LMP_TACCURACY	= 1 << 4,
+    LMP_RSWITCH		= 1 << 5,
+    LMP_HOLD_MODE	= 1 << 6,
+    LMP_SNIFF_MODE	= 1 << 7,
+};
+
+enum lmp_feature_bits1 {
+    LMP_PARK		= 1 << 0,
+    LMP_RSSI		= 1 << 1,
+    LMP_QUALITY		= 1 << 2,
+    LMP_SCO		= 1 << 3,
+    LMP_HV2		= 1 << 4,
+    LMP_HV3		= 1 << 5,
+    LMP_ULAW		= 1 << 6,
+    LMP_ALAW		= 1 << 7,
+};
+
+enum lmp_feature_bits2 {
+    LMP_CVSD		= 1 << 0,
+    LMP_PSCHEME		= 1 << 1,
+    LMP_PCONTROL	= 1 << 2,
+    LMP_TRSP_SCO	= 1 << 3,
+    LMP_BCAST_ENC	= 1 << 7,
+};
+
+enum lmp_feature_bits3 {
+    LMP_EDR_ACL_2M	= 1 << 1,
+    LMP_EDR_ACL_3M	= 1 << 2,
+    LMP_ENH_ISCAN	= 1 << 3,
+    LMP_ILACE_ISCAN	= 1 << 4,
+    LMP_ILACE_PSCAN	= 1 << 5,
+    LMP_RSSI_INQ	= 1 << 6,
+    LMP_ESCO		= 1 << 7,
+};
+
+enum lmp_feature_bits4 {
+    LMP_EV4		= 1 << 0,
+    LMP_EV5		= 1 << 1,
+    LMP_AFH_CAP_SLV	= 1 << 3,
+    LMP_AFH_CLS_SLV	= 1 << 4,
+    LMP_EDR_3SLOT	= 1 << 7,
+};
+
+enum lmp_feature_bits5 {
+    LMP_EDR_5SLOT	= 1 << 0,
+    LMP_SNIFF_SUBR	= 1 << 1,
+    LMP_AFH_CAP_MST	= 1 << 3,
+    LMP_AFH_CLS_MST	= 1 << 4,
+    LMP_EDR_ESCO_2M	= 1 << 5,
+    LMP_EDR_ESCO_3M	= 1 << 6,
+    LMP_EDR_3S_ESCO	= 1 << 7,
+};
+
+enum lmp_feature_bits6 {
+    LMP_EXT_INQ		= 1 << 0,
+};
+
+enum lmp_feature_bits7 {
+    LMP_EXT_FEAT	= 1 << 7,
+};
+
+enum hci_link_policy {
+    HCI_LP_RSWITCH	= 1 << 0,
+    HCI_LP_HOLD		= 1 << 1,
+    HCI_LP_SNIFF	= 1 << 2,
+    HCI_LP_PARK		= 1 << 3,
+};
+
+enum hci_link_mode {
+    HCI_LM_ACCEPT	= 1 << 15,
+    HCI_LM_MASTER	= 1 << 0,
+    HCI_LM_AUTH		= 1 << 1,
+    HCI_LM_ENCRYPT	= 1 << 2,
+    HCI_LM_TRUSTED	= 1 << 3,
+    HCI_LM_RELIABLE	= 1 << 4,
+    HCI_LM_SECURE	= 1 << 5,
+};
+
+/* HCI Commands */
+
+/* Link Control */
+#define OGF_LINK_CTL		0x01
+
+#define OCF_INQUIRY			0x0001
+typedef struct {
+    uint8_t	lap[3];
+    uint8_t	length;		/* 1.28s units */
+    uint8_t	num_rsp;
+} __attribute__ ((packed)) inquiry_cp;
+#define INQUIRY_CP_SIZE 5
+
+typedef struct {
+    uint8_t		status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) status_bdaddr_rp;
+#define STATUS_BDADDR_RP_SIZE 7
+
+#define OCF_INQUIRY_CANCEL		0x0002
+
+#define OCF_PERIODIC_INQUIRY		0x0003
+typedef struct {
+    uint16_t	max_period;	/* 1.28s units */
+    uint16_t	min_period;	/* 1.28s units */
+    uint8_t	lap[3];
+    uint8_t	length;		/* 1.28s units */
+    uint8_t	num_rsp;
+} __attribute__ ((packed)) periodic_inquiry_cp;
+#define PERIODIC_INQUIRY_CP_SIZE 9
+
+#define OCF_EXIT_PERIODIC_INQUIRY	0x0004
+
+#define OCF_CREATE_CONN			0x0005
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint16_t	pkt_type;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_mode;
+    uint16_t	clock_offset;
+    uint8_t	role_switch;
+} __attribute__ ((packed)) create_conn_cp;
+#define CREATE_CONN_CP_SIZE 13
+
+#define OCF_DISCONNECT			0x0006
+typedef struct {
+    uint16_t	handle;
+    uint8_t	reason;
+} __attribute__ ((packed)) disconnect_cp;
+#define DISCONNECT_CP_SIZE 3
+
+#define OCF_ADD_SCO			0x0007
+typedef struct {
+    uint16_t	handle;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) add_sco_cp;
+#define ADD_SCO_CP_SIZE 4
+
+#define OCF_CREATE_CONN_CANCEL		0x0008
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) create_conn_cancel_cp;
+#define CREATE_CONN_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) create_conn_cancel_rp;
+#define CREATE_CONN_CANCEL_RP_SIZE 7
+
+#define OCF_ACCEPT_CONN_REQ		0x0009
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) accept_conn_req_cp;
+#define ACCEPT_CONN_REQ_CP_SIZE	7
+
+#define OCF_REJECT_CONN_REQ		0x000A
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	reason;
+} __attribute__ ((packed)) reject_conn_req_cp;
+#define REJECT_CONN_REQ_CP_SIZE	7
+
+#define OCF_LINK_KEY_REPLY		0x000B
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	link_key[16];
+} __attribute__ ((packed)) link_key_reply_cp;
+#define LINK_KEY_REPLY_CP_SIZE 22
+
+#define OCF_LINK_KEY_NEG_REPLY		0x000C
+
+#define OCF_PIN_CODE_REPLY		0x000D
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pin_len;
+    uint8_t	pin_code[16];
+} __attribute__ ((packed)) pin_code_reply_cp;
+#define PIN_CODE_REPLY_CP_SIZE 23
+
+#define OCF_PIN_CODE_NEG_REPLY		0x000E
+
+#define OCF_SET_CONN_PTYPE		0x000F
+typedef struct {
+    uint16_t	 handle;
+    uint16_t	 pkt_type;
+} __attribute__ ((packed)) set_conn_ptype_cp;
+#define SET_CONN_PTYPE_CP_SIZE 4
+
+#define OCF_AUTH_REQUESTED		0x0011
+typedef struct {
+    uint16_t	 handle;
+} __attribute__ ((packed)) auth_requested_cp;
+#define AUTH_REQUESTED_CP_SIZE 2
+
+#define OCF_SET_CONN_ENCRYPT		0x0013
+typedef struct {
+    uint16_t	handle;
+    uint8_t	encrypt;
+} __attribute__ ((packed)) set_conn_encrypt_cp;
+#define SET_CONN_ENCRYPT_CP_SIZE 3
+
+#define OCF_CHANGE_CONN_LINK_KEY	0x0015
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) change_conn_link_key_cp;
+#define CHANGE_CONN_LINK_KEY_CP_SIZE 2
+
+#define OCF_MASTER_LINK_KEY		0x0017
+typedef struct {
+    uint8_t	key_flag;
+} __attribute__ ((packed)) master_link_key_cp;
+#define MASTER_LINK_KEY_CP_SIZE 1
+
+#define OCF_REMOTE_NAME_REQ		0x0019
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_mode;
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) remote_name_req_cp;
+#define REMOTE_NAME_REQ_CP_SIZE 10
+
+#define OCF_REMOTE_NAME_REQ_CANCEL	0x001A
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) remote_name_req_cancel_cp;
+#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t		status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) remote_name_req_cancel_rp;
+#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7
+
+#define OCF_READ_REMOTE_FEATURES	0x001B
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_remote_features_cp;
+#define READ_REMOTE_FEATURES_CP_SIZE 2
+
+#define OCF_READ_REMOTE_EXT_FEATURES	0x001C
+typedef struct {
+    uint16_t	handle;
+    uint8_t	page_num;
+} __attribute__ ((packed)) read_remote_ext_features_cp;
+#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3
+
+#define OCF_READ_REMOTE_VERSION		0x001D
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_remote_version_cp;
+#define READ_REMOTE_VERSION_CP_SIZE 2
+
+#define OCF_READ_CLOCK_OFFSET		0x001F
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_clock_offset_cp;
+#define READ_CLOCK_OFFSET_CP_SIZE 2
+
+#define OCF_READ_LMP_HANDLE		0x0020
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_lmp_handle_cp;
+#define READ_LMP_HANDLE_CP_SIZE 2
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	lmp_handle;
+    uint32_t	reserved;
+} __attribute__ ((packed)) read_lmp_handle_rp;
+#define READ_LMP_HANDLE_RP_SIZE 8
+
+#define OCF_SETUP_SYNC_CONN		0x0028
+typedef struct {
+    uint16_t	handle;
+    uint32_t	tx_bandwith;
+    uint32_t	rx_bandwith;
+    uint16_t	max_latency;
+    uint16_t	voice_setting;
+    uint8_t	retrans_effort;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) setup_sync_conn_cp;
+#define SETUP_SYNC_CONN_CP_SIZE 17
+
+#define OCF_ACCEPT_SYNC_CONN_REQ	0x0029
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint32_t	tx_bandwith;
+    uint32_t	rx_bandwith;
+    uint16_t	max_latency;
+    uint16_t	voice_setting;
+    uint8_t	retrans_effort;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) accept_sync_conn_req_cp;
+#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21
+
+#define OCF_REJECT_SYNC_CONN_REQ	0x002A
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	reason;
+} __attribute__ ((packed)) reject_sync_conn_req_cp;
+#define REJECT_SYNC_CONN_REQ_CP_SIZE 7
+
+/* Link Policy */
+#define OGF_LINK_POLICY		0x02
+
+#define OCF_HOLD_MODE			0x0001
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+} __attribute__ ((packed)) hold_mode_cp;
+#define HOLD_MODE_CP_SIZE 6
+
+#define OCF_SNIFF_MODE			0x0003
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+    uint16_t	attempt;
+    uint16_t	timeout;
+} __attribute__ ((packed)) sniff_mode_cp;
+#define SNIFF_MODE_CP_SIZE 10
+
+#define OCF_EXIT_SNIFF_MODE		0x0004
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) exit_sniff_mode_cp;
+#define EXIT_SNIFF_MODE_CP_SIZE 2
+
+#define OCF_PARK_MODE			0x0005
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+} __attribute__ ((packed)) park_mode_cp;
+#define PARK_MODE_CP_SIZE 6
+
+#define OCF_EXIT_PARK_MODE		0x0006
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) exit_park_mode_cp;
+#define EXIT_PARK_MODE_CP_SIZE 2
+
+#define OCF_QOS_SETUP			0x0007
+typedef struct {
+    uint8_t	service_type;		/* 1 = best effort */
+    uint32_t	token_rate;		/* Byte per seconds */
+    uint32_t	peak_bandwidth;		/* Byte per seconds */
+    uint32_t	latency;		/* Microseconds */
+    uint32_t	delay_variation;	/* Microseconds */
+} __attribute__ ((packed)) hci_qos;
+#define HCI_QOS_CP_SIZE 17
+typedef struct {
+    uint16_t 	handle;
+    uint8_t 	flags;			/* Reserved */
+    hci_qos 	qos;
+} __attribute__ ((packed)) qos_setup_cp;
+#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
+
+#define OCF_ROLE_DISCOVERY		0x0009
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) role_discovery_cp;
+#define ROLE_DISCOVERY_CP_SIZE 2
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	role;
+} __attribute__ ((packed)) role_discovery_rp;
+#define ROLE_DISCOVERY_RP_SIZE 4
+
+#define OCF_SWITCH_ROLE			0x000B
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) switch_role_cp;
+#define SWITCH_ROLE_CP_SIZE 7
+
+#define OCF_READ_LINK_POLICY		0x000C
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_link_policy_cp;
+#define READ_LINK_POLICY_CP_SIZE 2
+typedef struct {
+    uint8_t 	status;
+    uint16_t	handle;
+    uint16_t	policy;
+} __attribute__ ((packed)) read_link_policy_rp;
+#define READ_LINK_POLICY_RP_SIZE 5
+
+#define OCF_WRITE_LINK_POLICY		0x000D
+typedef struct {
+    uint16_t	handle;
+    uint16_t	policy;
+} __attribute__ ((packed)) write_link_policy_cp;
+#define WRITE_LINK_POLICY_CP_SIZE 4
+typedef struct {
+    uint8_t 	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) write_link_policy_rp;
+#define WRITE_LINK_POLICY_RP_SIZE 3
+
+#define OCF_READ_DEFAULT_LINK_POLICY	0x000E
+
+#define OCF_WRITE_DEFAULT_LINK_POLICY	0x000F
+
+#define OCF_FLOW_SPECIFICATION		0x0010
+
+#define OCF_SNIFF_SUBRATE		0x0011
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_remote_latency;
+    uint16_t	max_local_latency;
+    uint16_t	min_remote_timeout;
+    uint16_t	min_local_timeout;
+} __attribute__ ((packed)) sniff_subrate_cp;
+#define SNIFF_SUBRATE_CP_SIZE 10
+
+/* Host Controller and Baseband */
+#define OGF_HOST_CTL		0x03
+
+#define OCF_SET_EVENT_MASK		0x0001
+typedef struct {
+    uint8_t	mask[8];
+} __attribute__ ((packed)) set_event_mask_cp;
+#define SET_EVENT_MASK_CP_SIZE 8
+
+#define OCF_RESET			0x0003
+
+#define OCF_SET_EVENT_FLT		0x0005
+typedef struct {
+    uint8_t	flt_type;
+    uint8_t	cond_type;
+    uint8_t	condition[0];
+} __attribute__ ((packed)) set_event_flt_cp;
+#define SET_EVENT_FLT_CP_SIZE 2
+
+enum bt_filter_type {
+    FLT_CLEAR_ALL		= 0x00,
+    FLT_INQ_RESULT		= 0x01,
+    FLT_CONN_SETUP		= 0x02,
+};
+enum inq_result_cond_type {
+    INQ_RESULT_RETURN_ALL	= 0x00,
+    INQ_RESULT_RETURN_CLASS	= 0x01,
+    INQ_RESULT_RETURN_BDADDR	= 0x02,
+};
+enum conn_setup_cond_type {
+    CONN_SETUP_ALLOW_ALL	= 0x00,
+    CONN_SETUP_ALLOW_CLASS	= 0x01,
+    CONN_SETUP_ALLOW_BDADDR	= 0x02,
+};
+enum conn_setup_cond {
+    CONN_SETUP_AUTO_OFF		= 0x01,
+    CONN_SETUP_AUTO_ON		= 0x02,
+};
+
+#define OCF_FLUSH			0x0008
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) flush_cp;
+#define FLUSH_CP_SIZE 2
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) flush_rp;
+#define FLUSH_RP_SIZE 3
+
+#define OCF_READ_PIN_TYPE		0x0009
+typedef struct {
+    uint8_t	status;
+    uint8_t	pin_type;
+} __attribute__ ((packed)) read_pin_type_rp;
+#define READ_PIN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_PIN_TYPE		0x000A
+typedef struct {
+    uint8_t	pin_type;
+} __attribute__ ((packed)) write_pin_type_cp;
+#define WRITE_PIN_TYPE_CP_SIZE 1
+
+#define OCF_CREATE_NEW_UNIT_KEY		0x000B
+
+#define OCF_READ_STORED_LINK_KEY	0x000D
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	read_all;
+} __attribute__ ((packed)) read_stored_link_key_cp;
+#define READ_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t	status;
+    uint16_t	max_keys;
+    uint16_t	num_keys;
+} __attribute__ ((packed)) read_stored_link_key_rp;
+#define READ_STORED_LINK_KEY_RP_SIZE 5
+
+#define OCF_WRITE_STORED_LINK_KEY	0x0011
+typedef struct {
+    uint8_t	num_keys;
+    /* variable length part */
+} __attribute__ ((packed)) write_stored_link_key_cp;
+#define WRITE_STORED_LINK_KEY_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+    uint8_t	num_keys;
+} __attribute__ ((packed)) write_stored_link_key_rp;
+#define READ_WRITE_LINK_KEY_RP_SIZE 2
+
+#define OCF_DELETE_STORED_LINK_KEY	0x0012
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	delete_all;
+} __attribute__ ((packed)) delete_stored_link_key_cp;
+#define DELETE_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t	status;
+    uint16_t	num_keys;
+} __attribute__ ((packed)) delete_stored_link_key_rp;
+#define DELETE_STORED_LINK_KEY_RP_SIZE 3
+
+#define OCF_CHANGE_LOCAL_NAME		0x0013
+typedef struct {
+    char	name[248];
+} __attribute__ ((packed)) change_local_name_cp;
+#define CHANGE_LOCAL_NAME_CP_SIZE 248 
+
+#define OCF_READ_LOCAL_NAME		0x0014
+typedef struct {
+    uint8_t	status;
+    char	name[248];
+} __attribute__ ((packed)) read_local_name_rp;
+#define READ_LOCAL_NAME_RP_SIZE 249 
+
+#define OCF_READ_CONN_ACCEPT_TIMEOUT	0x0015
+typedef struct {
+    uint8_t	status;
+    uint16_t	timeout;
+} __attribute__ ((packed)) read_conn_accept_timeout_rp;
+#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_CONN_ACCEPT_TIMEOUT	0x0016
+typedef struct {
+    uint16_t	timeout;
+} __attribute__ ((packed)) write_conn_accept_timeout_cp;
+#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_PAGE_TIMEOUT		0x0017
+typedef struct {
+    uint8_t	status;
+    uint16_t	timeout;
+} __attribute__ ((packed)) read_page_timeout_rp;
+#define READ_PAGE_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_PAGE_TIMEOUT		0x0018
+typedef struct {
+    uint16_t	timeout;
+} __attribute__ ((packed)) write_page_timeout_cp;
+#define WRITE_PAGE_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_SCAN_ENABLE		0x0019
+typedef struct {
+    uint8_t	status;
+    uint8_t	enable;
+} __attribute__ ((packed)) read_scan_enable_rp;
+#define READ_SCAN_ENABLE_RP_SIZE 2
+
+#define OCF_WRITE_SCAN_ENABLE		0x001A
+typedef struct {
+    uint8_t	scan_enable;
+} __attribute__ ((packed)) write_scan_enable_cp;
+#define WRITE_SCAN_ENABLE_CP_SIZE 1
+
+enum scan_enable_bits {
+    SCAN_DISABLED		= 0,
+    SCAN_INQUIRY		= 1 << 0,
+    SCAN_PAGE			= 1 << 1,
+};
+
+#define OCF_READ_PAGE_ACTIVITY		0x001B
+typedef struct {
+    uint8_t	status;
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) read_page_activity_rp;
+#define READ_PAGE_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_PAGE_ACTIVITY		0x001C
+typedef struct {
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) write_page_activity_cp;
+#define WRITE_PAGE_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_INQ_ACTIVITY		0x001D
+typedef struct {
+    uint8_t	status;
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) read_inq_activity_rp;
+#define READ_INQ_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_INQ_ACTIVITY		0x001E
+typedef struct {
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) write_inq_activity_cp;
+#define WRITE_INQ_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_AUTH_ENABLE		0x001F
+
+#define OCF_WRITE_AUTH_ENABLE		0x0020
+
+#define AUTH_DISABLED		0x00
+#define AUTH_ENABLED		0x01
+
+#define OCF_READ_ENCRYPT_MODE		0x0021
+
+#define OCF_WRITE_ENCRYPT_MODE		0x0022
+
+#define ENCRYPT_DISABLED	0x00
+#define ENCRYPT_P2P		0x01
+#define ENCRYPT_BOTH		0x02
+
+#define OCF_READ_CLASS_OF_DEV		0x0023
+typedef struct {
+    uint8_t	status;
+    uint8_t	dev_class[3];
+} __attribute__ ((packed)) read_class_of_dev_rp;
+#define READ_CLASS_OF_DEV_RP_SIZE 4 
+
+#define OCF_WRITE_CLASS_OF_DEV		0x0024
+typedef struct {
+    uint8_t	dev_class[3];
+} __attribute__ ((packed)) write_class_of_dev_cp;
+#define WRITE_CLASS_OF_DEV_CP_SIZE 3
+
+#define OCF_READ_VOICE_SETTING		0x0025
+typedef struct {
+    uint8_t	status;
+    uint16_t	voice_setting;
+} __attribute__ ((packed)) read_voice_setting_rp;
+#define READ_VOICE_SETTING_RP_SIZE 3
+
+#define OCF_WRITE_VOICE_SETTING		0x0026
+typedef struct {
+    uint16_t	voice_setting;
+} __attribute__ ((packed)) write_voice_setting_cp;
+#define WRITE_VOICE_SETTING_CP_SIZE 2
+
+#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT	0x0027
+
+#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT	0x0028
+
+#define OCF_READ_NUM_BROADCAST_RETRANS	0x0029
+
+#define OCF_WRITE_NUM_BROADCAST_RETRANS	0x002A
+
+#define OCF_READ_HOLD_MODE_ACTIVITY	0x002B
+
+#define OCF_WRITE_HOLD_MODE_ACTIVITY	0x002C
+
+#define OCF_READ_TRANSMIT_POWER_LEVEL	0x002D
+typedef struct {
+    uint16_t	handle;
+    uint8_t	type;
+} __attribute__ ((packed)) read_transmit_power_level_cp;
+#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    int8_t	level;
+} __attribute__ ((packed)) read_transmit_power_level_rp;
+#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4
+
+#define OCF_HOST_BUFFER_SIZE		0x0033
+typedef struct {
+    uint16_t	acl_mtu;
+    uint8_t	sco_mtu;
+    uint16_t	acl_max_pkt;
+    uint16_t	sco_max_pkt;
+} __attribute__ ((packed)) host_buffer_size_cp;
+#define HOST_BUFFER_SIZE_CP_SIZE 7
+
+#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS	0x0035
+
+#define OCF_READ_LINK_SUPERVISION_TIMEOUT	0x0036
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	link_sup_to;
+} __attribute__ ((packed)) read_link_supervision_timeout_rp;
+#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5
+
+#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT	0x0037
+typedef struct {
+    uint16_t	handle;
+    uint16_t	link_sup_to;
+} __attribute__ ((packed)) write_link_supervision_timeout_cp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) write_link_supervision_timeout_rp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3
+
+#define OCF_READ_NUM_SUPPORTED_IAC	0x0038
+
+#define MAX_IAC_LAP 0x40
+#define OCF_READ_CURRENT_IAC_LAP	0x0039
+typedef struct {
+    uint8_t	status;
+    uint8_t	num_current_iac;
+    uint8_t	lap[MAX_IAC_LAP][3];
+} __attribute__ ((packed)) read_current_iac_lap_rp;
+#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
+
+#define OCF_WRITE_CURRENT_IAC_LAP	0x003A
+typedef struct {
+    uint8_t	num_current_iac;
+    uint8_t	lap[MAX_IAC_LAP][3];
+} __attribute__ ((packed)) write_current_iac_lap_cp;
+#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP
+
+#define OCF_READ_PAGE_SCAN_PERIOD_MODE	0x003B
+
+#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE	0x003C
+
+#define OCF_READ_PAGE_SCAN_MODE		0x003D
+
+#define OCF_WRITE_PAGE_SCAN_MODE	0x003E
+
+#define OCF_SET_AFH_CLASSIFICATION	0x003F
+typedef struct {
+    uint8_t	map[10];
+} __attribute__ ((packed)) set_afh_classification_cp;
+#define SET_AFH_CLASSIFICATION_CP_SIZE 10
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) set_afh_classification_rp;
+#define SET_AFH_CLASSIFICATION_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_SCAN_TYPE	0x0042
+typedef struct {
+    uint8_t	status;
+    uint8_t	type;
+} __attribute__ ((packed)) read_inquiry_scan_type_rp;
+#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_SCAN_TYPE	0x0043
+typedef struct {
+    uint8_t	type;
+} __attribute__ ((packed)) write_inquiry_scan_type_cp;
+#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_inquiry_scan_type_rp;
+#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_MODE		0x0044
+typedef struct {
+    uint8_t	status;
+    uint8_t	mode;
+} __attribute__ ((packed)) read_inquiry_mode_rp;
+#define READ_INQUIRY_MODE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_MODE		0x0045
+typedef struct {
+    uint8_t	mode;
+} __attribute__ ((packed)) write_inquiry_mode_cp;
+#define WRITE_INQUIRY_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_inquiry_mode_rp;
+#define WRITE_INQUIRY_MODE_RP_SIZE 1
+
+#define OCF_READ_PAGE_SCAN_TYPE		0x0046
+
+#define OCF_WRITE_PAGE_SCAN_TYPE	0x0047
+
+#define OCF_READ_AFH_MODE		0x0048
+typedef struct {
+    uint8_t	status;
+    uint8_t	mode;
+} __attribute__ ((packed)) read_afh_mode_rp;
+#define READ_AFH_MODE_RP_SIZE 2
+
+#define OCF_WRITE_AFH_MODE		0x0049
+typedef struct {
+    uint8_t	mode;
+} __attribute__ ((packed)) write_afh_mode_cp;
+#define WRITE_AFH_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_afh_mode_rp;
+#define WRITE_AFH_MODE_RP_SIZE 1
+
+#define OCF_READ_EXT_INQUIRY_RESPONSE	0x0051
+typedef struct {
+    uint8_t	status;
+    uint8_t	fec;
+    uint8_t	data[240];
+} __attribute__ ((packed)) read_ext_inquiry_response_rp;
+#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
+
+#define OCF_WRITE_EXT_INQUIRY_RESPONSE	0x0052
+typedef struct {
+    uint8_t	fec;
+    uint8_t	data[240];
+} __attribute__ ((packed)) write_ext_inquiry_response_cp;
+#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_ext_inquiry_response_rp;
+#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1
+
+/* Informational Parameters */
+#define OGF_INFO_PARAM		0x04
+
+#define OCF_READ_LOCAL_VERSION		0x0001
+typedef struct {
+    uint8_t	status;
+    uint8_t	hci_ver;
+    uint16_t	hci_rev;
+    uint8_t	lmp_ver;
+    uint16_t	manufacturer;
+    uint16_t	lmp_subver;
+} __attribute__ ((packed)) read_local_version_rp;
+#define READ_LOCAL_VERSION_RP_SIZE 9
+
+#define OCF_READ_LOCAL_COMMANDS		0x0002
+typedef struct {
+    uint8_t	status;
+    uint8_t	commands[64];
+} __attribute__ ((packed)) read_local_commands_rp;
+#define READ_LOCAL_COMMANDS_RP_SIZE 65
+
+#define OCF_READ_LOCAL_FEATURES		0x0003
+typedef struct {
+    uint8_t	status;
+    uint8_t	features[8];
+} __attribute__ ((packed)) read_local_features_rp;
+#define READ_LOCAL_FEATURES_RP_SIZE 9
+
+#define OCF_READ_LOCAL_EXT_FEATURES	0x0004
+typedef struct {
+    uint8_t	page_num;
+} __attribute__ ((packed)) read_local_ext_features_cp;
+#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+    uint8_t	page_num;
+    uint8_t	max_page_num;
+    uint8_t	features[8];
+} __attribute__ ((packed)) read_local_ext_features_rp;
+#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11
+
+#define OCF_READ_BUFFER_SIZE		0x0005
+typedef struct {
+    uint8_t	status;
+    uint16_t	acl_mtu;
+    uint8_t	sco_mtu;
+    uint16_t	acl_max_pkt;
+    uint16_t	sco_max_pkt;
+} __attribute__ ((packed)) read_buffer_size_rp;
+#define READ_BUFFER_SIZE_RP_SIZE 8
+
+#define OCF_READ_COUNTRY_CODE		0x0007
+typedef struct {
+    uint8_t	status;
+    uint8_t	country_code;
+} __attribute__ ((packed)) read_country_code_rp;
+#define READ_COUNTRY_CODE_RP_SIZE 2
+
+#define OCF_READ_BD_ADDR		0x0009
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) read_bd_addr_rp;
+#define READ_BD_ADDR_RP_SIZE 7
+
+/* Status params */
+#define OGF_STATUS_PARAM	0x05
+
+#define OCF_READ_FAILED_CONTACT_COUNTER		0x0001
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	counter;
+} __attribute__ ((packed)) read_failed_contact_counter_rp;
+#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_RESET_FAILED_CONTACT_COUNTER	0x0002
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) reset_failed_contact_counter_rp;
+#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_READ_LINK_QUALITY		0x0003
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_link_quality_cp;
+#define READ_LINK_QUALITY_CP_SIZE 4
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	link_quality;
+} __attribute__ ((packed)) read_link_quality_rp;
+#define READ_LINK_QUALITY_RP_SIZE 4
+
+#define OCF_READ_RSSI			0x0005
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    int8_t	rssi;
+} __attribute__ ((packed)) read_rssi_rp;
+#define READ_RSSI_RP_SIZE 4
+
+#define OCF_READ_AFH_MAP		0x0006
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	mode;
+    uint8_t	map[10];
+} __attribute__ ((packed)) read_afh_map_rp;
+#define READ_AFH_MAP_RP_SIZE 14
+
+#define OCF_READ_CLOCK			0x0007
+typedef struct {
+    uint16_t	handle;
+    uint8_t	which_clock;
+} __attribute__ ((packed)) read_clock_cp;
+#define READ_CLOCK_CP_SIZE 3
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint32_t	clock;
+    uint16_t	accuracy;
+} __attribute__ ((packed)) read_clock_rp;
+#define READ_CLOCK_RP_SIZE 9
+
+/* Testing commands */
+#define OGF_TESTING_CMD		0x3e
+
+/* Vendor specific commands */
+#define OGF_VENDOR_CMD		0x3f
+
+/* HCI Events */
+
+#define EVT_INQUIRY_COMPLETE		0x01
+
+#define EVT_INQUIRY_RESULT		0x02
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	pscan_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) inquiry_info;
+#define INQUIRY_INFO_SIZE 14
+
+#define EVT_CONN_COMPLETE		0x03
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    bdaddr_t	bdaddr;
+    uint8_t	link_type;
+    uint8_t	encr_mode;
+} __attribute__ ((packed)) evt_conn_complete;
+#define EVT_CONN_COMPLETE_SIZE 11
+
+#define EVT_CONN_REQUEST		0x04
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	dev_class[3];
+    uint8_t	link_type;
+} __attribute__ ((packed)) evt_conn_request;
+#define EVT_CONN_REQUEST_SIZE 10
+
+#define EVT_DISCONN_COMPLETE		0x05
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	reason;
+} __attribute__ ((packed)) evt_disconn_complete;
+#define EVT_DISCONN_COMPLETE_SIZE 4
+
+#define EVT_AUTH_COMPLETE		0x06
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_auth_complete;
+#define EVT_AUTH_COMPLETE_SIZE 3
+
+#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+    char	name[248];
+} __attribute__ ((packed)) evt_remote_name_req_complete;
+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
+
+#define EVT_ENCRYPT_CHANGE		0x08
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	encrypt;
+} __attribute__ ((packed)) evt_encrypt_change;
+#define EVT_ENCRYPT_CHANGE_SIZE 5
+
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE	0x09
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+}  __attribute__ ((packed)) evt_change_conn_link_key_complete;
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3
+
+#define EVT_MASTER_LINK_KEY_COMPLETE		0x0A
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	key_flag;
+} __attribute__ ((packed)) evt_master_link_key_complete;
+#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4
+
+#define EVT_READ_REMOTE_FEATURES_COMPLETE	0x0B
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	features[8];
+} __attribute__ ((packed)) evt_read_remote_features_complete;
+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_READ_REMOTE_VERSION_COMPLETE	0x0C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	lmp_ver;
+    uint16_t	manufacturer;
+    uint16_t	lmp_subver;
+} __attribute__ ((packed)) evt_read_remote_version_complete;
+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
+
+#define EVT_QOS_SETUP_COMPLETE		0x0D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	flags;			/* Reserved */
+    hci_qos	qos;
+} __attribute__ ((packed)) evt_qos_setup_complete;
+#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
+
+#define EVT_CMD_COMPLETE 		0x0E
+typedef struct {
+    uint8_t	ncmd;
+    uint16_t	opcode;
+} __attribute__ ((packed)) evt_cmd_complete;
+#define EVT_CMD_COMPLETE_SIZE 3
+
+#define EVT_CMD_STATUS 			0x0F
+typedef struct {
+    uint8_t	status;
+    uint8_t	ncmd;
+    uint16_t	opcode;
+} __attribute__ ((packed)) evt_cmd_status;
+#define EVT_CMD_STATUS_SIZE 4
+
+#define EVT_HARDWARE_ERROR		0x10
+typedef struct {
+    uint8_t	code;
+} __attribute__ ((packed)) evt_hardware_error;
+#define EVT_HARDWARE_ERROR_SIZE 1
+
+#define EVT_FLUSH_OCCURRED		0x11
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_flush_occurred;
+#define EVT_FLUSH_OCCURRED_SIZE 2
+
+#define EVT_ROLE_CHANGE			0x12
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) evt_role_change;
+#define EVT_ROLE_CHANGE_SIZE 8
+
+#define EVT_NUM_COMP_PKTS		0x13
+typedef struct {
+    uint8_t	num_hndl;
+    struct {
+        uint16_t handle;
+        uint16_t num_packets;
+    } connection[0];
+} __attribute__ ((packed)) evt_num_comp_pkts;
+#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl))
+
+#define EVT_MODE_CHANGE			0x14
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	mode;
+    uint16_t	interval;
+} __attribute__ ((packed)) evt_mode_change;
+#define EVT_MODE_CHANGE_SIZE 6
+
+#define EVT_RETURN_LINK_KEYS		0x15
+typedef struct {
+    uint8_t	num_keys;
+    /* variable length part */
+} __attribute__ ((packed)) evt_return_link_keys;
+#define EVT_RETURN_LINK_KEYS_SIZE 1
+
+#define EVT_PIN_CODE_REQ		0x16
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) evt_pin_code_req;
+#define EVT_PIN_CODE_REQ_SIZE 6
+
+#define EVT_LINK_KEY_REQ		0x17
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) evt_link_key_req;
+#define EVT_LINK_KEY_REQ_SIZE 6
+
+#define EVT_LINK_KEY_NOTIFY		0x18
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	link_key[16];
+    uint8_t	key_type;
+} __attribute__ ((packed)) evt_link_key_notify;
+#define EVT_LINK_KEY_NOTIFY_SIZE 23
+
+#define EVT_LOOPBACK_COMMAND		0x19
+
+#define EVT_DATA_BUFFER_OVERFLOW	0x1A
+typedef struct {
+    uint8_t	link_type;
+} __attribute__ ((packed)) evt_data_buffer_overflow;
+#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1
+
+#define EVT_MAX_SLOTS_CHANGE		0x1B
+typedef struct {
+    uint16_t	handle;
+    uint8_t	max_slots;
+} __attribute__ ((packed)) evt_max_slots_change;
+#define EVT_MAX_SLOTS_CHANGE_SIZE 3
+
+#define EVT_READ_CLOCK_OFFSET_COMPLETE	0x1C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) evt_read_clock_offset_complete;
+#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5
+
+#define EVT_CONN_PTYPE_CHANGED		0x1D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	ptype;
+} __attribute__ ((packed)) evt_conn_ptype_changed;
+#define EVT_CONN_PTYPE_CHANGED_SIZE 5
+
+#define EVT_QOS_VIOLATION		0x1E
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_qos_violation;
+#define EVT_QOS_VIOLATION_SIZE 2
+
+#define EVT_PSCAN_REP_MODE_CHANGE	0x20
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+} __attribute__ ((packed)) evt_pscan_rep_mode_change;
+#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7
+
+#define EVT_FLOW_SPEC_COMPLETE		0x21
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	flags;
+    uint8_t	direction;
+    hci_qos	qos;
+} __attribute__ ((packed)) evt_flow_spec_complete;
+#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE)
+
+#define EVT_INQUIRY_RESULT_WITH_RSSI	0x22
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+} __attribute__ ((packed)) inquiry_info_with_rssi;
+#define INQUIRY_INFO_WITH_RSSI_SIZE 15
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	pscan_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+} __attribute__ ((packed)) inquiry_info_with_rssi_and_pscan_mode;
+#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16
+
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE	0x23
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	page_num;
+    uint8_t	max_page_num;
+    uint8_t	features[8];
+} __attribute__ ((packed)) evt_read_remote_ext_features_complete;
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13
+
+#define EVT_SYNC_CONN_COMPLETE		0x2C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    bdaddr_t	bdaddr;
+    uint8_t	link_type;
+    uint8_t	trans_interval;
+    uint8_t	retrans_window;
+    uint16_t	rx_pkt_len;
+    uint16_t	tx_pkt_len;
+    uint8_t	air_mode;
+} __attribute__ ((packed)) evt_sync_conn_complete;
+#define EVT_SYNC_CONN_COMPLETE_SIZE 17
+
+#define EVT_SYNC_CONN_CHANGED		0x2D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	trans_interval;
+    uint8_t	retrans_window;
+    uint16_t	rx_pkt_len;
+    uint16_t	tx_pkt_len;
+} __attribute__ ((packed)) evt_sync_conn_changed;
+#define EVT_SYNC_CONN_CHANGED_SIZE 9
+
+#define EVT_SNIFF_SUBRATE		0x2E
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	max_remote_latency;
+    uint16_t	max_local_latency;
+    uint16_t	min_remote_timeout;
+    uint16_t	min_local_timeout;
+} __attribute__ ((packed)) evt_sniff_subrate;
+#define EVT_SNIFF_SUBRATE_SIZE 11
+
+#define EVT_EXTENDED_INQUIRY_RESULT	0x2F
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+    uint8_t	data[240];
+} __attribute__ ((packed)) extended_inquiry_info;
+#define EXTENDED_INQUIRY_INFO_SIZE 254
+
+#define EVT_TESTING			0xFE
+
+#define EVT_VENDOR			0xFF
+
+/* Command opcode pack/unpack */
+#define cmd_opcode_pack(ogf, ocf)	(uint16_t)((ocf & 0x03ff)|(ogf << 10))
+#define cmd_opcode_ogf(op)		(op >> 10)
+#define cmd_opcode_ocf(op)		(op & 0x03ff)
+
+/* ACL handle and flags pack/unpack */
+#define acl_handle_pack(h, f)	(uint16_t)(((h) & 0x0fff)|((f) << 12))
+#define acl_handle(h)		((h) & 0x0fff)
+#define acl_flags(h)		((h) >> 12)
+
+/* HCI Packet structures */
+#define HCI_COMMAND_HDR_SIZE	3
+#define HCI_EVENT_HDR_SIZE	2
+#define HCI_ACL_HDR_SIZE	4
+#define HCI_SCO_HDR_SIZE	3
+
+struct hci_command_hdr {
+    uint16_t 	opcode;		/* OCF & OGF */
+    uint8_t	plen;
+} __attribute__ ((packed));
+
+struct hci_event_hdr {
+    uint8_t	evt;
+    uint8_t	plen;
+} __attribute__ ((packed));
+
+struct hci_acl_hdr {
+    uint16_t	handle;		/* Handle & Flags(PB, BC) */
+    uint16_t	dlen;
+} __attribute__ ((packed));
+
+struct hci_sco_hdr {
+    uint16_t	handle;
+    uint8_t	dlen;
+} __attribute__ ((packed));
+
+/* L2CAP layer defines */
+
+enum bt_l2cap_lm_bits {
+    L2CAP_LM_MASTER	= 1 << 0,
+    L2CAP_LM_AUTH	= 1 << 1,
+    L2CAP_LM_ENCRYPT	= 1 << 2,
+    L2CAP_LM_TRUSTED	= 1 << 3,
+    L2CAP_LM_RELIABLE	= 1 << 4,
+    L2CAP_LM_SECURE	= 1 << 5,
+};
+
+enum bt_l2cap_cid_predef {
+    L2CAP_CID_INVALID	= 0x0000,
+    L2CAP_CID_SIGNALLING= 0x0001,
+    L2CAP_CID_GROUP	= 0x0002,
+    L2CAP_CID_ALLOC	= 0x0040,
+};
+
+/* L2CAP command codes */
+enum bt_l2cap_cmd {
+    L2CAP_COMMAND_REJ	= 1,
+    L2CAP_CONN_REQ,
+    L2CAP_CONN_RSP,
+    L2CAP_CONF_REQ,
+    L2CAP_CONF_RSP,
+    L2CAP_DISCONN_REQ,
+    L2CAP_DISCONN_RSP,
+    L2CAP_ECHO_REQ,
+    L2CAP_ECHO_RSP,
+    L2CAP_INFO_REQ,
+    L2CAP_INFO_RSP,
+};
+
+enum bt_l2cap_sar_bits {
+    L2CAP_SAR_NO_SEG	= 0,
+    L2CAP_SAR_START,
+    L2CAP_SAR_END,
+    L2CAP_SAR_CONT,
+};
+
+/* L2CAP structures */
+typedef struct {
+    uint16_t	len;
+    uint16_t	cid;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_hdr;
+#define L2CAP_HDR_SIZE 4
+
+typedef struct {
+    uint8_t	code;
+    uint8_t	ident;
+    uint16_t	len;
+} __attribute__ ((packed)) l2cap_cmd_hdr;
+#define L2CAP_CMD_HDR_SIZE 4
+
+typedef struct {
+    uint16_t	reason;
+} __attribute__ ((packed)) l2cap_cmd_rej;
+#define L2CAP_CMD_REJ_SIZE 2
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_cmd_rej_cid;
+#define L2CAP_CMD_REJ_CID_SIZE 4
+
+/* reject reason */
+enum bt_l2cap_rej_reason {
+    L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0,
+    L2CAP_REJ_SIG_TOOBIG,
+    L2CAP_REJ_CID_INVAL,
+};
+
+typedef struct {
+    uint16_t	psm;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_conn_req;
+#define L2CAP_CONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+    uint16_t	result;
+    uint16_t	status;
+} __attribute__ ((packed)) l2cap_conn_rsp;
+#define L2CAP_CONN_RSP_SIZE 8
+
+/* connect result */
+enum bt_l2cap_conn_res {
+    L2CAP_CR_SUCCESS	= 0,
+    L2CAP_CR_PEND,
+    L2CAP_CR_BAD_PSM,
+    L2CAP_CR_SEC_BLOCK,
+    L2CAP_CR_NO_MEM,
+};
+
+/* connect status */
+enum bt_l2cap_conn_stat {
+    L2CAP_CS_NO_INFO	= 0,
+    L2CAP_CS_AUTHEN_PEND,
+    L2CAP_CS_AUTHOR_PEND,
+};
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	flags;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_conf_req;
+#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen))
+
+typedef struct {
+    uint16_t	scid;
+    uint16_t	flags;
+    uint16_t	result;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_conf_rsp;
+#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen)
+
+enum bt_l2cap_conf_res {
+    L2CAP_CONF_SUCCESS	= 0,
+    L2CAP_CONF_UNACCEPT,
+    L2CAP_CONF_REJECT,
+    L2CAP_CONF_UNKNOWN,
+};
+
+typedef struct {
+    uint8_t	type;
+    uint8_t	len;
+    uint8_t	val[0];
+} __attribute__ ((packed)) l2cap_conf_opt;
+#define L2CAP_CONF_OPT_SIZE 2
+
+enum bt_l2cap_conf_val {
+    L2CAP_CONF_MTU	= 1,
+    L2CAP_CONF_FLUSH_TO,
+    L2CAP_CONF_QOS,
+    L2CAP_CONF_RFC,
+    L2CAP_CONF_RFC_MODE	= L2CAP_CONF_RFC,
+};
+
+typedef struct {
+    uint8_t	flags;
+    uint8_t	service_type;
+    uint32_t	token_rate;
+    uint32_t	token_bucket_size;
+    uint32_t	peak_bandwidth;
+    uint32_t	latency;
+    uint32_t	delay_variation;
+} __attribute__ ((packed)) l2cap_conf_opt_qos;
+#define L2CAP_CONF_OPT_QOS_SIZE 22
+
+enum bt_l2cap_conf_opt_qos_st {
+    L2CAP_CONF_QOS_NO_TRAFFIC = 0x00,
+    L2CAP_CONF_QOS_BEST_EFFORT,
+    L2CAP_CONF_QOS_GUARANTEED,
+};
+
+#define L2CAP_CONF_QOS_WILDCARD	0xffffffff
+
+enum bt_l2cap_mode {
+    L2CAP_MODE_BASIC	= 0,
+    L2CAP_MODE_RETRANS	= 1,
+    L2CAP_MODE_FLOWCTL	= 2,
+};
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_disconn_req;
+#define L2CAP_DISCONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_disconn_rsp;
+#define L2CAP_DISCONN_RSP_SIZE 4
+
+typedef struct {
+    uint16_t	type;
+} __attribute__ ((packed)) l2cap_info_req;
+#define L2CAP_INFO_REQ_SIZE 2
+
+typedef struct {
+    uint16_t	type;
+    uint16_t	result;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_info_rsp;
+#define L2CAP_INFO_RSP_SIZE 4
+
+/* info type */
+enum bt_l2cap_info_type {
+    L2CAP_IT_CL_MTU	= 1,
+    L2CAP_IT_FEAT_MASK,
+};
+
+/* info result */
+enum bt_l2cap_info_result {
+    L2CAP_IR_SUCCESS	= 0,
+    L2CAP_IR_NOTSUPP,
+};
+
+/* Service Discovery Protocol defines */
+/* Note that all multibyte values in lower layer protocols (above in this file)
+ * are little-endian while SDP is big-endian.  */
+
+/* Protocol UUIDs */
+enum sdp_proto_uuid {
+    SDP_UUID		= 0x0001,
+    UDP_UUID		= 0x0002,
+    RFCOMM_UUID		= 0x0003,
+    TCP_UUID		= 0x0004,
+    TCS_BIN_UUID	= 0x0005,
+    TCS_AT_UUID		= 0x0006,
+    OBEX_UUID		= 0x0008,
+    IP_UUID		= 0x0009,
+    FTP_UUID		= 0x000a,
+    HTTP_UUID		= 0x000c,
+    WSP_UUID		= 0x000e,
+    BNEP_UUID		= 0x000f,
+    UPNP_UUID		= 0x0010,
+    HIDP_UUID		= 0x0011,
+    HCRP_CTRL_UUID	= 0x0012,
+    HCRP_DATA_UUID	= 0x0014,
+    HCRP_NOTE_UUID	= 0x0016,
+    AVCTP_UUID		= 0x0017,
+    AVDTP_UUID		= 0x0019,
+    CMTP_UUID		= 0x001b,
+    UDI_UUID		= 0x001d,
+    MCAP_CTRL_UUID	= 0x001e,
+    MCAP_DATA_UUID	= 0x001f,
+    L2CAP_UUID		= 0x0100,
+};
+
+/*
+ * Service class identifiers of standard services and service groups
+ */
+enum service_class_id {
+    SDP_SERVER_SVCLASS_ID		= 0x1000,
+    BROWSE_GRP_DESC_SVCLASS_ID		= 0x1001,
+    PUBLIC_BROWSE_GROUP			= 0x1002,
+    SERIAL_PORT_SVCLASS_ID		= 0x1101,
+    LAN_ACCESS_SVCLASS_ID		= 0x1102,
+    DIALUP_NET_SVCLASS_ID		= 0x1103,
+    IRMC_SYNC_SVCLASS_ID		= 0x1104,
+    OBEX_OBJPUSH_SVCLASS_ID		= 0x1105,
+    OBEX_FILETRANS_SVCLASS_ID		= 0x1106,
+    IRMC_SYNC_CMD_SVCLASS_ID		= 0x1107,
+    HEADSET_SVCLASS_ID			= 0x1108,
+    CORDLESS_TELEPHONY_SVCLASS_ID	= 0x1109,
+    AUDIO_SOURCE_SVCLASS_ID		= 0x110a,
+    AUDIO_SINK_SVCLASS_ID		= 0x110b,
+    AV_REMOTE_TARGET_SVCLASS_ID		= 0x110c,
+    ADVANCED_AUDIO_SVCLASS_ID		= 0x110d,
+    AV_REMOTE_SVCLASS_ID		= 0x110e,
+    VIDEO_CONF_SVCLASS_ID		= 0x110f,
+    INTERCOM_SVCLASS_ID			= 0x1110,
+    FAX_SVCLASS_ID			= 0x1111,
+    HEADSET_AGW_SVCLASS_ID		= 0x1112,
+    WAP_SVCLASS_ID			= 0x1113,
+    WAP_CLIENT_SVCLASS_ID		= 0x1114,
+    PANU_SVCLASS_ID			= 0x1115,
+    NAP_SVCLASS_ID			= 0x1116,
+    GN_SVCLASS_ID			= 0x1117,
+    DIRECT_PRINTING_SVCLASS_ID		= 0x1118,
+    REFERENCE_PRINTING_SVCLASS_ID	= 0x1119,
+    IMAGING_SVCLASS_ID			= 0x111a,
+    IMAGING_RESPONDER_SVCLASS_ID	= 0x111b,
+    IMAGING_ARCHIVE_SVCLASS_ID		= 0x111c,
+    IMAGING_REFOBJS_SVCLASS_ID		= 0x111d,
+    HANDSFREE_SVCLASS_ID		= 0x111e,
+    HANDSFREE_AGW_SVCLASS_ID		= 0x111f,
+    DIRECT_PRT_REFOBJS_SVCLASS_ID	= 0x1120,
+    REFLECTED_UI_SVCLASS_ID		= 0x1121,
+    BASIC_PRINTING_SVCLASS_ID		= 0x1122,
+    PRINTING_STATUS_SVCLASS_ID		= 0x1123,
+    HID_SVCLASS_ID			= 0x1124,
+    HCR_SVCLASS_ID			= 0x1125,
+    HCR_PRINT_SVCLASS_ID		= 0x1126,
+    HCR_SCAN_SVCLASS_ID			= 0x1127,
+    CIP_SVCLASS_ID			= 0x1128,
+    VIDEO_CONF_GW_SVCLASS_ID		= 0x1129,
+    UDI_MT_SVCLASS_ID			= 0x112a,
+    UDI_TA_SVCLASS_ID			= 0x112b,
+    AV_SVCLASS_ID			= 0x112c,
+    SAP_SVCLASS_ID			= 0x112d,
+    PBAP_PCE_SVCLASS_ID			= 0x112e,
+    PBAP_PSE_SVCLASS_ID			= 0x112f,
+    PBAP_SVCLASS_ID			= 0x1130,
+    PNP_INFO_SVCLASS_ID			= 0x1200,
+    GENERIC_NETWORKING_SVCLASS_ID	= 0x1201,
+    GENERIC_FILETRANS_SVCLASS_ID	= 0x1202,
+    GENERIC_AUDIO_SVCLASS_ID		= 0x1203,
+    GENERIC_TELEPHONY_SVCLASS_ID	= 0x1204,
+    UPNP_SVCLASS_ID			= 0x1205,
+    UPNP_IP_SVCLASS_ID			= 0x1206,
+    UPNP_PAN_SVCLASS_ID			= 0x1300,
+    UPNP_LAP_SVCLASS_ID			= 0x1301,
+    UPNP_L2CAP_SVCLASS_ID		= 0x1302,
+    VIDEO_SOURCE_SVCLASS_ID		= 0x1303,
+    VIDEO_SINK_SVCLASS_ID		= 0x1304,
+    VIDEO_DISTRIBUTION_SVCLASS_ID	= 0x1305,
+    MDP_SVCLASS_ID			= 0x1400,
+    MDP_SOURCE_SVCLASS_ID		= 0x1401,
+    MDP_SINK_SVCLASS_ID			= 0x1402,
+    APPLE_AGENT_SVCLASS_ID		= 0x2112,
+};
+
+/*
+ * Standard profile descriptor identifiers; note these
+ * may be identical to some of the service classes defined above
+ */
+#define SDP_SERVER_PROFILE_ID		SDP_SERVER_SVCLASS_ID
+#define BROWSE_GRP_DESC_PROFILE_ID	BROWSE_GRP_DESC_SVCLASS_ID
+#define SERIAL_PORT_PROFILE_ID		SERIAL_PORT_SVCLASS_ID
+#define LAN_ACCESS_PROFILE_ID		LAN_ACCESS_SVCLASS_ID
+#define DIALUP_NET_PROFILE_ID		DIALUP_NET_SVCLASS_ID
+#define IRMC_SYNC_PROFILE_ID		IRMC_SYNC_SVCLASS_ID
+#define OBEX_OBJPUSH_PROFILE_ID		OBEX_OBJPUSH_SVCLASS_ID
+#define OBEX_FILETRANS_PROFILE_ID	OBEX_FILETRANS_SVCLASS_ID
+#define IRMC_SYNC_CMD_PROFILE_ID	IRMC_SYNC_CMD_SVCLASS_ID
+#define HEADSET_PROFILE_ID		HEADSET_SVCLASS_ID
+#define CORDLESS_TELEPHONY_PROFILE_ID	CORDLESS_TELEPHONY_SVCLASS_ID
+#define AUDIO_SOURCE_PROFILE_ID		AUDIO_SOURCE_SVCLASS_ID
+#define AUDIO_SINK_PROFILE_ID		AUDIO_SINK_SVCLASS_ID
+#define AV_REMOTE_TARGET_PROFILE_ID	AV_REMOTE_TARGET_SVCLASS_ID
+#define ADVANCED_AUDIO_PROFILE_ID	ADVANCED_AUDIO_SVCLASS_ID
+#define AV_REMOTE_PROFILE_ID		AV_REMOTE_SVCLASS_ID
+#define VIDEO_CONF_PROFILE_ID		VIDEO_CONF_SVCLASS_ID
+#define INTERCOM_PROFILE_ID		INTERCOM_SVCLASS_ID
+#define FAX_PROFILE_ID			FAX_SVCLASS_ID
+#define HEADSET_AGW_PROFILE_ID		HEADSET_AGW_SVCLASS_ID
+#define WAP_PROFILE_ID			WAP_SVCLASS_ID
+#define WAP_CLIENT_PROFILE_ID		WAP_CLIENT_SVCLASS_ID
+#define PANU_PROFILE_ID			PANU_SVCLASS_ID
+#define NAP_PROFILE_ID			NAP_SVCLASS_ID
+#define GN_PROFILE_ID			GN_SVCLASS_ID
+#define DIRECT_PRINTING_PROFILE_ID	DIRECT_PRINTING_SVCLASS_ID
+#define REFERENCE_PRINTING_PROFILE_ID	REFERENCE_PRINTING_SVCLASS_ID
+#define IMAGING_PROFILE_ID		IMAGING_SVCLASS_ID
+#define IMAGING_RESPONDER_PROFILE_ID	IMAGING_RESPONDER_SVCLASS_ID
+#define IMAGING_ARCHIVE_PROFILE_ID	IMAGING_ARCHIVE_SVCLASS_ID
+#define IMAGING_REFOBJS_PROFILE_ID	IMAGING_REFOBJS_SVCLASS_ID
+#define HANDSFREE_PROFILE_ID		HANDSFREE_SVCLASS_ID
+#define HANDSFREE_AGW_PROFILE_ID	HANDSFREE_AGW_SVCLASS_ID
+#define DIRECT_PRT_REFOBJS_PROFILE_ID	DIRECT_PRT_REFOBJS_SVCLASS_ID
+#define REFLECTED_UI_PROFILE_ID		REFLECTED_UI_SVCLASS_ID
+#define BASIC_PRINTING_PROFILE_ID	BASIC_PRINTING_SVCLASS_ID
+#define PRINTING_STATUS_PROFILE_ID	PRINTING_STATUS_SVCLASS_ID
+#define HID_PROFILE_ID			HID_SVCLASS_ID
+#define HCR_PROFILE_ID			HCR_SCAN_SVCLASS_ID
+#define HCR_PRINT_PROFILE_ID		HCR_PRINT_SVCLASS_ID
+#define HCR_SCAN_PROFILE_ID		HCR_SCAN_SVCLASS_ID
+#define CIP_PROFILE_ID			CIP_SVCLASS_ID
+#define VIDEO_CONF_GW_PROFILE_ID	VIDEO_CONF_GW_SVCLASS_ID
+#define UDI_MT_PROFILE_ID		UDI_MT_SVCLASS_ID
+#define UDI_TA_PROFILE_ID		UDI_TA_SVCLASS_ID
+#define AV_PROFILE_ID			AV_SVCLASS_ID
+#define SAP_PROFILE_ID			SAP_SVCLASS_ID
+#define PBAP_PCE_PROFILE_ID		PBAP_PCE_SVCLASS_ID
+#define PBAP_PSE_PROFILE_ID		PBAP_PSE_SVCLASS_ID
+#define PBAP_PROFILE_ID			PBAP_SVCLASS_ID
+#define PNP_INFO_PROFILE_ID		PNP_INFO_SVCLASS_ID
+#define GENERIC_NETWORKING_PROFILE_ID	GENERIC_NETWORKING_SVCLASS_ID
+#define GENERIC_FILETRANS_PROFILE_ID	GENERIC_FILETRANS_SVCLASS_ID
+#define GENERIC_AUDIO_PROFILE_ID	GENERIC_AUDIO_SVCLASS_ID
+#define GENERIC_TELEPHONY_PROFILE_ID	GENERIC_TELEPHONY_SVCLASS_ID
+#define UPNP_PROFILE_ID			UPNP_SVCLASS_ID
+#define UPNP_IP_PROFILE_ID		UPNP_IP_SVCLASS_ID
+#define UPNP_PAN_PROFILE_ID		UPNP_PAN_SVCLASS_ID
+#define UPNP_LAP_PROFILE_ID		UPNP_LAP_SVCLASS_ID
+#define UPNP_L2CAP_PROFILE_ID		UPNP_L2CAP_SVCLASS_ID
+#define VIDEO_SOURCE_PROFILE_ID		VIDEO_SOURCE_SVCLASS_ID
+#define VIDEO_SINK_PROFILE_ID		VIDEO_SINK_SVCLASS_ID
+#define VIDEO_DISTRIBUTION_PROFILE_ID	VIDEO_DISTRIBUTION_SVCLASS_ID
+#define MDP_PROFILE_ID			MDP_SVCLASS_ID
+#define MDP_SOURCE_PROFILE_ID		MDP_SROUCE_SVCLASS_ID
+#define MDP_SINK_PROFILE_ID		MDP_SINK_SVCLASS_ID
+#define APPLE_AGENT_PROFILE_ID		APPLE_AGENT_SVCLASS_ID
+
+/* Data Representation */
+enum bt_sdp_data_type {
+    SDP_DTYPE_NIL	= 0 << 3,
+    SDP_DTYPE_UINT	= 1 << 3,
+    SDP_DTYPE_SINT	= 2 << 3,
+    SDP_DTYPE_UUID	= 3 << 3,
+    SDP_DTYPE_STRING	= 4 << 3,
+    SDP_DTYPE_BOOL	= 5 << 3,
+    SDP_DTYPE_SEQ	= 6 << 3,
+    SDP_DTYPE_ALT	= 7 << 3,
+    SDP_DTYPE_URL	= 8 << 3,
+};
+
+enum bt_sdp_data_size {
+    SDP_DSIZE_1		= 0,
+    SDP_DSIZE_2,
+    SDP_DSIZE_4,
+    SDP_DSIZE_8,
+    SDP_DSIZE_16,
+    SDP_DSIZE_NEXT1,
+    SDP_DSIZE_NEXT2,
+    SDP_DSIZE_NEXT4,
+    SDP_DSIZE_MASK = SDP_DSIZE_NEXT4,
+};
+
+enum bt_sdp_cmd {
+    SDP_ERROR_RSP		= 0x01,
+    SDP_SVC_SEARCH_REQ		= 0x02,
+    SDP_SVC_SEARCH_RSP		= 0x03,
+    SDP_SVC_ATTR_REQ		= 0x04,
+    SDP_SVC_ATTR_RSP		= 0x05,
+    SDP_SVC_SEARCH_ATTR_REQ	= 0x06,
+    SDP_SVC_SEARCH_ATTR_RSP	= 0x07,
+};
+
+enum bt_sdp_errorcode {
+    SDP_INVALID_VERSION		= 0x0001,
+    SDP_INVALID_RECORD_HANDLE	= 0x0002,
+    SDP_INVALID_SYNTAX		= 0x0003,
+    SDP_INVALID_PDU_SIZE	= 0x0004,
+    SDP_INVALID_CSTATE		= 0x0005,
+};
+
+/*
+ * String identifiers are based on the SDP spec stating that
+ * "base attribute id of the primary (universal) language must be 0x0100"
+ *
+ * Other languages should have their own offset; e.g.:
+ * #define XXXLangBase yyyy
+ * #define AttrServiceName_XXX	0x0000+XXXLangBase
+ */
+#define SDP_PRIMARY_LANG_BASE 		0x0100
+
+enum bt_sdp_attribute_id {
+    SDP_ATTR_RECORD_HANDLE			= 0x0000,
+    SDP_ATTR_SVCLASS_ID_LIST			= 0x0001,
+    SDP_ATTR_RECORD_STATE			= 0x0002,
+    SDP_ATTR_SERVICE_ID				= 0x0003,
+    SDP_ATTR_PROTO_DESC_LIST			= 0x0004,
+    SDP_ATTR_BROWSE_GRP_LIST			= 0x0005,
+    SDP_ATTR_LANG_BASE_ATTR_ID_LIST		= 0x0006,
+    SDP_ATTR_SVCINFO_TTL			= 0x0007,
+    SDP_ATTR_SERVICE_AVAILABILITY		= 0x0008,
+    SDP_ATTR_PFILE_DESC_LIST			= 0x0009,
+    SDP_ATTR_DOC_URL				= 0x000a,
+    SDP_ATTR_CLNT_EXEC_URL			= 0x000b,
+    SDP_ATTR_ICON_URL				= 0x000c,
+    SDP_ATTR_ADD_PROTO_DESC_LIST		= 0x000d,
+
+    SDP_ATTR_SVCNAME_PRIMARY			= SDP_PRIMARY_LANG_BASE + 0,
+    SDP_ATTR_SVCDESC_PRIMARY			= SDP_PRIMARY_LANG_BASE + 1,
+    SDP_ATTR_SVCPROV_PRIMARY			= SDP_PRIMARY_LANG_BASE + 2,
+
+    SDP_ATTR_GROUP_ID				= 0x0200,
+    SDP_ATTR_IP_SUBNET				= 0x0200,
+
+    /* SDP */
+    SDP_ATTR_VERSION_NUM_LIST			= 0x0200,
+    SDP_ATTR_SVCDB_STATE			= 0x0201,
+
+    SDP_ATTR_SERVICE_VERSION			= 0x0300,
+    SDP_ATTR_EXTERNAL_NETWORK			= 0x0301,
+    SDP_ATTR_SUPPORTED_DATA_STORES_LIST		= 0x0301,
+    SDP_ATTR_FAX_CLASS1_SUPPORT			= 0x0302,
+    SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL	= 0x0302,
+    SDP_ATTR_FAX_CLASS20_SUPPORT		= 0x0303,
+    SDP_ATTR_SUPPORTED_FORMATS_LIST		= 0x0303,
+    SDP_ATTR_FAX_CLASS2_SUPPORT			= 0x0304,
+    SDP_ATTR_AUDIO_FEEDBACK_SUPPORT		= 0x0305,
+    SDP_ATTR_NETWORK_ADDRESS			= 0x0306,
+    SDP_ATTR_WAP_GATEWAY			= 0x0307,
+    SDP_ATTR_HOMEPAGE_URL			= 0x0308,
+    SDP_ATTR_WAP_STACK_TYPE			= 0x0309,
+    SDP_ATTR_SECURITY_DESC			= 0x030a,
+    SDP_ATTR_NET_ACCESS_TYPE			= 0x030b,
+    SDP_ATTR_MAX_NET_ACCESSRATE			= 0x030c,
+    SDP_ATTR_IP4_SUBNET				= 0x030d,
+    SDP_ATTR_IP6_SUBNET				= 0x030e,
+    SDP_ATTR_SUPPORTED_CAPABILITIES		= 0x0310,
+    SDP_ATTR_SUPPORTED_FEATURES			= 0x0311,
+    SDP_ATTR_SUPPORTED_FUNCTIONS		= 0x0312,
+    SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY	= 0x0313,
+    SDP_ATTR_SUPPORTED_REPOSITORIES		= 0x0314,
+
+    /* PnP Information */
+    SDP_ATTR_SPECIFICATION_ID			= 0x0200,
+    SDP_ATTR_VENDOR_ID				= 0x0201,
+    SDP_ATTR_PRODUCT_ID				= 0x0202,
+    SDP_ATTR_VERSION				= 0x0203,
+    SDP_ATTR_PRIMARY_RECORD			= 0x0204,
+    SDP_ATTR_VENDOR_ID_SOURCE			= 0x0205,
+
+    /* BT HID */
+    SDP_ATTR_DEVICE_RELEASE_NUMBER		= 0x0200,
+    SDP_ATTR_PARSER_VERSION			= 0x0201,
+    SDP_ATTR_DEVICE_SUBCLASS			= 0x0202,
+    SDP_ATTR_COUNTRY_CODE			= 0x0203,
+    SDP_ATTR_VIRTUAL_CABLE			= 0x0204,
+    SDP_ATTR_RECONNECT_INITIATE			= 0x0205,
+    SDP_ATTR_DESCRIPTOR_LIST			= 0x0206,
+    SDP_ATTR_LANG_ID_BASE_LIST			= 0x0207,
+    SDP_ATTR_SDP_DISABLE			= 0x0208,
+    SDP_ATTR_BATTERY_POWER			= 0x0209,
+    SDP_ATTR_REMOTE_WAKEUP			= 0x020a,
+    SDP_ATTR_PROFILE_VERSION			= 0x020b,
+    SDP_ATTR_SUPERVISION_TIMEOUT		= 0x020c,
+    SDP_ATTR_NORMALLY_CONNECTABLE		= 0x020d,
+    SDP_ATTR_BOOT_DEVICE			= 0x020e,
+};
diff --git a/qemu-0.15.x/hw/cbus.c b/qemu-0.15.x/hw/cbus.c
new file mode 100644
index 0000000..8ae24e0
--- /dev/null
+++ b/qemu-0.15.x/hw/cbus.c
@@ -0,0 +1,618 @@
+/*
+ * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
+ * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
+ * Based on reverse-engineering of a linux driver.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "irq.h"
+#include "devices.h"
+#include "sysemu.h"
+
+//#define DEBUG
+
+typedef struct {
+    void *opaque;
+    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
+    int addr;
+} CBusSlave;
+
+typedef struct {
+    CBus cbus;
+
+    int sel;
+    int dat;
+    int clk;
+    int bit;
+    int dir;
+    uint16_t val;
+    qemu_irq dat_out;
+
+    int addr;
+    int reg;
+    int rw;
+    enum {
+        cbus_address,
+        cbus_value,
+    } cycle;
+
+    CBusSlave *slave[8];
+} CBusPriv;
+
+static void cbus_io(CBusPriv *s)
+{
+    if (s->slave[s->addr])
+        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
+                        s->rw, s->reg, &s->val);
+    else
+        hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
+}
+
+static void cbus_cycle(CBusPriv *s)
+{
+    switch (s->cycle) {
+    case cbus_address:
+        s->addr = (s->val >> 6) & 7;
+        s->rw =   (s->val >> 5) & 1;
+        s->reg =  (s->val >> 0) & 0x1f;
+
+        s->cycle = cbus_value;
+        s->bit = 15;
+        s->dir = !s->rw;
+        s->val = 0;
+
+        if (s->rw)
+            cbus_io(s);
+        break;
+
+    case cbus_value:
+        if (!s->rw)
+            cbus_io(s);
+
+        s->cycle = cbus_address;
+        s->bit = 8;
+        s->dir = 1;
+        s->val = 0;
+        break;
+    }
+}
+
+static void cbus_clk(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    if (!s->sel && level && !s->clk) {
+        if (s->dir)
+            s->val |= s->dat << (s->bit --);
+        else
+            qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
+
+        if (s->bit < 0)
+            cbus_cycle(s);
+    }
+
+    s->clk = level;
+}
+
+static void cbus_dat(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    s->dat = level;
+}
+
+static void cbus_sel(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    if (!level) {
+        s->dir = 1;
+        s->bit = 8;
+        s->val = 0;
+    }
+
+    s->sel = level;
+}
+
+CBus *cbus_init(qemu_irq dat)
+{
+    CBusPriv *s = (CBusPriv *) qemu_mallocz(sizeof(*s));
+
+    s->dat_out = dat;
+    s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
+    s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
+    s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
+
+    s->sel = 1;
+    s->clk = 0;
+    s->dat = 0;
+
+    return &s->cbus;
+}
+
+void cbus_attach(CBus *bus, void *slave_opaque)
+{
+    CBusSlave *slave = (CBusSlave *) slave_opaque;
+    CBusPriv *s = (CBusPriv *) bus;
+
+    s->slave[slave->addr] = slave;
+}
+
+/* Retu/Vilma */
+typedef struct {
+    uint16_t irqst;
+    uint16_t irqen;
+    uint16_t cc[2];
+    int channel;
+    uint16_t result[16];
+    uint16_t sample;
+    uint16_t status;
+
+    struct {
+        uint16_t cal;
+    } rtc;
+
+    int is_vilma;
+    qemu_irq irq;
+    CBusSlave cbus;
+} CBusRetu;
+
+static void retu_interrupt_update(CBusRetu *s)
+{
+    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
+}
+
+#define RETU_REG_ASICR		0x00	/* (RO) ASIC ID & revision */
+#define RETU_REG_IDR		0x01	/* (T)  Interrupt ID */
+#define RETU_REG_IMR		0x02	/* (RW) Interrupt mask */
+#define RETU_REG_RTCDSR		0x03	/* (RW) RTC seconds register */
+#define RETU_REG_RTCHMR		0x04	/* (RO) RTC hours and minutes reg */
+#define RETU_REG_RTCHMAR	0x05	/* (RW) RTC hours and minutes set reg */
+#define RETU_REG_RTCCALR	0x06	/* (RW) RTC calibration register */
+#define RETU_REG_ADCR		0x08	/* (RW) ADC result register */
+#define RETU_REG_ADCSCR		0x09	/* (RW) ADC sample control register */
+#define RETU_REG_AFCR		0x0a	/* (RW) AFC register */
+#define RETU_REG_ANTIFR		0x0b	/* (RW) AntiF register */
+#define RETU_REG_CALIBR		0x0c	/* (RW) CalibR register*/
+#define RETU_REG_CCR1		0x0d	/* (RW) Common control register 1 */
+#define RETU_REG_CCR2		0x0e	/* (RW) Common control register 2 */
+#define RETU_REG_RCTRL_CLR	0x0f	/* (T)  Regulator clear register */
+#define RETU_REG_RCTRL_SET	0x10	/* (T)  Regulator set register */
+#define RETU_REG_TXCR		0x11	/* (RW) TxC register */
+#define RETU_REG_STATUS		0x16	/* (RO) Status register */
+#define RETU_REG_WATCHDOG	0x17	/* (RW) Watchdog register */
+#define RETU_REG_AUDTXR		0x18	/* (RW) Audio Codec Tx register */
+#define RETU_REG_AUDPAR		0x19	/* (RW) AudioPA register */
+#define RETU_REG_AUDRXR1	0x1a	/* (RW) Audio receive register 1 */
+#define RETU_REG_AUDRXR2	0x1b	/* (RW) Audio receive register 2 */
+#define RETU_REG_SGR1		0x1c	/* (RW) */
+#define RETU_REG_SCR1		0x1d	/* (RW) */
+#define RETU_REG_SGR2		0x1e	/* (RW) */
+#define RETU_REG_SCR2		0x1f	/* (RW) */
+
+/* Retu Interrupt sources */
+enum {
+    retu_int_pwr	= 0,	/* Power button */
+    retu_int_char	= 1,	/* Charger */
+    retu_int_rtcs	= 2,	/* Seconds */
+    retu_int_rtcm	= 3,	/* Minutes */
+    retu_int_rtcd	= 4,	/* Days */
+    retu_int_rtca	= 5,	/* Alarm */
+    retu_int_hook	= 6,	/* Hook */
+    retu_int_head	= 7,	/* Headset */
+    retu_int_adcs	= 8,	/* ADC sample */
+};
+
+/* Retu ADC channel wiring */
+enum {
+    retu_adc_bsi	= 1,	/* BSI */
+    retu_adc_batt_temp	= 2,	/* Battery temperature */
+    retu_adc_chg_volt	= 3,	/* Charger voltage */
+    retu_adc_head_det	= 4,	/* Headset detection */
+    retu_adc_hook_det	= 5,	/* Hook detection */
+    retu_adc_rf_gp	= 6,	/* RF GP */
+    retu_adc_tx_det	= 7,	/* Wideband Tx detection */
+    retu_adc_batt_volt	= 8,	/* Battery voltage */
+    retu_adc_sens	= 10,	/* Light sensor */
+    retu_adc_sens_temp	= 11,	/* Light sensor temperature */
+    retu_adc_bbatt_volt	= 12,	/* Backup battery voltage */
+    retu_adc_self_temp	= 13,	/* RETU temperature */
+};
+
+static inline uint16_t retu_read(CBusRetu *s, int reg)
+{
+#ifdef DEBUG
+    printf("RETU read at %02x\n", reg);
+#endif
+
+    switch (reg) {
+    case RETU_REG_ASICR:
+        return 0x0215 | (s->is_vilma << 7);
+
+    case RETU_REG_IDR:	/* TODO: Or is this ffs(s->irqst)?  */
+        return s->irqst;
+
+    case RETU_REG_IMR:
+        return s->irqen;
+
+    case RETU_REG_RTCDSR:
+    case RETU_REG_RTCHMR:
+    case RETU_REG_RTCHMAR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_RTCCALR:
+        return s->rtc.cal;
+
+    case RETU_REG_ADCR:
+        return (s->channel << 10) | s->result[s->channel];
+    case RETU_REG_ADCSCR:
+        return s->sample;
+
+    case RETU_REG_AFCR:
+    case RETU_REG_ANTIFR:
+    case RETU_REG_CALIBR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_CCR1:
+        return s->cc[0];
+    case RETU_REG_CCR2:
+        return s->cc[1];
+
+    case RETU_REG_RCTRL_CLR:
+    case RETU_REG_RCTRL_SET:
+    case RETU_REG_TXCR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_STATUS:
+        return s->status;
+
+    case RETU_REG_WATCHDOG:
+    case RETU_REG_AUDTXR:
+    case RETU_REG_AUDPAR:
+    case RETU_REG_AUDRXR1:
+    case RETU_REG_AUDRXR2:
+    case RETU_REG_SGR1:
+    case RETU_REG_SCR1:
+    case RETU_REG_SGR2:
+    case RETU_REG_SCR2:
+        /* TODO */
+        return 0x0000;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
+{
+#ifdef DEBUG
+    printf("RETU write of %04x at %02x\n", val, reg);
+#endif
+
+    switch (reg) {
+    case RETU_REG_IDR:
+        s->irqst ^= val;
+        retu_interrupt_update(s);
+        break;
+
+    case RETU_REG_IMR:
+        s->irqen = val;
+        retu_interrupt_update(s);
+        break;
+
+    case RETU_REG_RTCDSR:
+    case RETU_REG_RTCHMAR:
+        /* TODO */
+        break;
+
+    case RETU_REG_RTCCALR:
+        s->rtc.cal = val;
+        break;
+
+    case RETU_REG_ADCR:
+        s->channel = (val >> 10) & 0xf;
+        s->irqst |= 1 << retu_int_adcs;
+        retu_interrupt_update(s);
+        break;
+    case RETU_REG_ADCSCR:
+        s->sample &= ~val;
+        break;
+
+    case RETU_REG_AFCR:
+    case RETU_REG_ANTIFR:
+    case RETU_REG_CALIBR:
+
+    case RETU_REG_CCR1:
+        s->cc[0] = val;
+        break;
+    case RETU_REG_CCR2:
+        s->cc[1] = val;
+        break;
+
+    case RETU_REG_RCTRL_CLR:
+    case RETU_REG_RCTRL_SET:
+        /* TODO */
+        break;
+
+    case RETU_REG_WATCHDOG:
+        if (val == 0 && (s->cc[0] & 2))
+            qemu_system_shutdown_request();
+        break;
+
+    case RETU_REG_TXCR:
+    case RETU_REG_AUDTXR:
+    case RETU_REG_AUDPAR:
+    case RETU_REG_AUDRXR1:
+    case RETU_REG_AUDRXR2:
+    case RETU_REG_SGR1:
+    case RETU_REG_SCR1:
+    case RETU_REG_SGR2:
+    case RETU_REG_SCR2:
+        /* TODO */
+        break;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
+{
+    CBusRetu *s = (CBusRetu *) opaque;
+
+    if (rw)
+        *val = retu_read(s, reg);
+    else
+        retu_write(s, reg, *val);
+}
+
+void *retu_init(qemu_irq irq, int vilma)
+{
+    CBusRetu *s = (CBusRetu *) qemu_mallocz(sizeof(*s));
+
+    s->irq = irq;
+    s->irqen = 0xffff;
+    s->irqst = 0x0000;
+    s->status = 0x0020;
+    s->is_vilma = !!vilma;
+    s->rtc.cal = 0x01;
+    s->result[retu_adc_bsi] = 0x3c2;
+    s->result[retu_adc_batt_temp] = 0x0fc;
+    s->result[retu_adc_chg_volt] = 0x165;
+    s->result[retu_adc_head_det] = 123;
+    s->result[retu_adc_hook_det] = 1023;
+    s->result[retu_adc_rf_gp] = 0x11;
+    s->result[retu_adc_tx_det] = 0x11;
+    s->result[retu_adc_batt_volt] = 0x250;
+    s->result[retu_adc_sens] = 2;
+    s->result[retu_adc_sens_temp] = 0x11;
+    s->result[retu_adc_bbatt_volt] = 0x3d0;
+    s->result[retu_adc_self_temp] = 0x330;
+
+    s->cbus.opaque = s;
+    s->cbus.io = retu_io;
+    s->cbus.addr = 1;
+
+    return &s->cbus;
+}
+
+void retu_key_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    s->irqst |= 1 << retu_int_pwr;
+    retu_interrupt_update(s);
+
+    if (state)
+        s->status &= ~(1 << 5);
+    else
+        s->status |= 1 << 5;
+}
+
+#if 0
+static void retu_head_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    if ((s->cc[0] & 0x500) == 0x500) {	/* TODO: Which bits? */
+        /* TODO: reissue the interrupt every 100ms or so.  */
+        s->irqst |= 1 << retu_int_head;
+        retu_interrupt_update(s);
+    }
+
+    if (state)
+        s->result[retu_adc_head_det] = 50;
+    else
+        s->result[retu_adc_head_det] = 123;
+}
+
+static void retu_hook_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    if ((s->cc[0] & 0x500) == 0x500) {
+        /* TODO: reissue the interrupt every 100ms or so.  */
+        s->irqst |= 1 << retu_int_hook;
+        retu_interrupt_update(s);
+    }
+
+    if (state)
+        s->result[retu_adc_hook_det] = 50;
+    else
+        s->result[retu_adc_hook_det] = 123;
+}
+#endif
+
+/* Tahvo/Betty */
+typedef struct {
+    uint16_t irqst;
+    uint16_t irqen;
+    uint8_t charger;
+    uint8_t backlight;
+    uint16_t usbr;
+    uint16_t power;
+
+    int is_betty;
+    qemu_irq irq;
+    CBusSlave cbus;
+} CBusTahvo;
+
+static void tahvo_interrupt_update(CBusTahvo *s)
+{
+    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
+}
+
+#define TAHVO_REG_ASICR		0x00	/* (RO) ASIC ID & revision */
+#define TAHVO_REG_IDR		0x01	/* (T)  Interrupt ID */
+#define TAHVO_REG_IDSR		0x02	/* (RO) Interrupt status */
+#define TAHVO_REG_IMR		0x03	/* (RW) Interrupt mask */
+#define TAHVO_REG_CHAPWMR	0x04	/* (RW) Charger PWM */
+#define TAHVO_REG_LEDPWMR	0x05	/* (RW) LED PWM */
+#define TAHVO_REG_USBR		0x06	/* (RW) USB control */
+#define TAHVO_REG_RCR		0x07	/* (RW) Some kind of power management */
+#define TAHVO_REG_CCR1		0x08	/* (RW) Common control register 1 */
+#define TAHVO_REG_CCR2		0x09	/* (RW) Common control register 2 */
+#define TAHVO_REG_TESTR1	0x0a	/* (RW) Test register 1 */
+#define TAHVO_REG_TESTR2	0x0b	/* (RW) Test register 2 */
+#define TAHVO_REG_NOPR		0x0c	/* (RW) Number of periods */
+#define TAHVO_REG_FRR		0x0d	/* (RO) FR */
+
+static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
+{
+#ifdef DEBUG
+    printf("TAHVO read at %02x\n", reg);
+#endif
+
+    switch (reg) {
+    case TAHVO_REG_ASICR:
+        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);	/* 22 in N810 */
+
+    case TAHVO_REG_IDR:
+    case TAHVO_REG_IDSR:	/* XXX: what does this do?  */
+        return s->irqst;
+
+    case TAHVO_REG_IMR:
+        return s->irqen;
+
+    case TAHVO_REG_CHAPWMR:
+        return s->charger;
+
+    case TAHVO_REG_LEDPWMR:
+        return s->backlight;
+
+    case TAHVO_REG_USBR:
+        return s->usbr;
+
+    case TAHVO_REG_RCR:
+        return s->power;
+
+    case TAHVO_REG_CCR1:
+    case TAHVO_REG_CCR2:
+    case TAHVO_REG_TESTR1:
+    case TAHVO_REG_TESTR2:
+    case TAHVO_REG_NOPR:
+    case TAHVO_REG_FRR:
+        return 0x0000;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
+{
+#ifdef DEBUG
+    printf("TAHVO write of %04x at %02x\n", val, reg);
+#endif
+
+    switch (reg) {
+    case TAHVO_REG_IDR:
+        s->irqst ^= val;
+        tahvo_interrupt_update(s);
+        break;
+
+    case TAHVO_REG_IMR:
+        s->irqen = val;
+        tahvo_interrupt_update(s);
+        break;
+
+    case TAHVO_REG_CHAPWMR:
+        s->charger = val;
+        break;
+
+    case TAHVO_REG_LEDPWMR:
+        if (s->backlight != (val & 0x7f)) {
+            s->backlight = val & 0x7f;
+            printf("%s: LCD backlight now at %i / 127\n",
+                            __FUNCTION__, s->backlight);
+        }
+        break;
+
+    case TAHVO_REG_USBR:
+        s->usbr = val;
+        break;
+
+    case TAHVO_REG_RCR:
+        s->power = val;
+        break;
+
+    case TAHVO_REG_CCR1:
+    case TAHVO_REG_CCR2:
+    case TAHVO_REG_TESTR1:
+    case TAHVO_REG_TESTR2:
+    case TAHVO_REG_NOPR:
+    case TAHVO_REG_FRR:
+        break;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
+{
+    CBusTahvo *s = (CBusTahvo *) opaque;
+
+    if (rw)
+        *val = tahvo_read(s, reg);
+    else
+        tahvo_write(s, reg, *val);
+}
+
+void *tahvo_init(qemu_irq irq, int betty)
+{
+    CBusTahvo *s = (CBusTahvo *) qemu_mallocz(sizeof(*s));
+
+    s->irq = irq;
+    s->irqen = 0xffff;
+    s->irqst = 0x0000;
+    s->is_betty = !!betty;
+
+    s->cbus.opaque = s;
+    s->cbus.io = tahvo_io;
+    s->cbus.addr = 2;
+
+    return &s->cbus;
+}
diff --git a/qemu-0.15.x/hw/ccid-card-emulated.c b/qemu-0.15.x/hw/ccid-card-emulated.c
new file mode 100644
index 0000000..4762e85
--- /dev/null
+++ b/qemu-0.15.x/hw/ccid-card-emulated.c
@@ -0,0 +1,595 @@
+/*
+ * CCID Card Device. Emulated card.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed under the GNU LGPL, version 2 or later.
+ */
+
+/*
+ * It can be used to provide access to the local hardware in a non exclusive
+ * way, or it can use certificates. It requires the usb-ccid bus.
+ *
+ * Usage 1: standard, mirror hardware reader+card:
+ * qemu .. -usb -device usb-ccid -device ccid-card-emulated
+ *
+ * Usage 2: use certificates, no hardware required
+ * one time: create the certificates:
+ *  for i in 1 2 3; do
+ *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
+ *  done
+ * qemu .. -usb -device usb-ccid \
+ *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
+ *
+ * If you use a non default db for the certificates you can specify it using
+ * the db parameter.
+ */
+
+#include <eventt.h>
+#include <vevent.h>
+#include <vreader.h>
+#include <vcard_emul.h>
+
+#include "qemu-thread.h"
+#include "qemu-char.h"
+#include "monitor.h"
+#include "hw/ccid.h"
+
+#define DPRINTF(card, lvl, fmt, ...) \
+do {\
+    if (lvl <= card->debug) {\
+        printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
+    } \
+} while (0)
+
+#define EMULATED_DEV_NAME "ccid-card-emulated"
+
+#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
+#define BACKEND_CERTIFICATES_NAME "certificates"
+
+enum {
+    BACKEND_NSS_EMULATED = 1,
+    BACKEND_CERTIFICATES
+};
+
+#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
+
+typedef struct EmulatedState EmulatedState;
+
+enum {
+    EMUL_READER_INSERT = 0,
+    EMUL_READER_REMOVE,
+    EMUL_CARD_INSERT,
+    EMUL_CARD_REMOVE,
+    EMUL_GUEST_APDU,
+    EMUL_RESPONSE_APDU,
+    EMUL_ERROR,
+};
+
+static const char *emul_event_to_string(uint32_t emul_event)
+{
+    switch (emul_event) {
+    case EMUL_READER_INSERT:
+        return "EMUL_READER_INSERT";
+    case EMUL_READER_REMOVE:
+        return "EMUL_READER_REMOVE";
+    case EMUL_CARD_INSERT:
+        return "EMUL_CARD_INSERT";
+    case EMUL_CARD_REMOVE:
+        return "EMUL_CARD_REMOVE";
+    case EMUL_GUEST_APDU:
+        return "EMUL_GUEST_APDU";
+    case EMUL_RESPONSE_APDU:
+        return "EMUL_RESPONSE_APDU";
+    case EMUL_ERROR:
+        return "EMUL_ERROR";
+    }
+    return "UNKNOWN";
+}
+
+typedef struct EmulEvent {
+    QSIMPLEQ_ENTRY(EmulEvent) entry;
+    union {
+        struct {
+            uint32_t type;
+        } gen;
+        struct {
+            uint32_t type;
+            uint64_t code;
+        } error;
+        struct {
+            uint32_t type;
+            uint32_t len;
+            uint8_t data[];
+        } data;
+    } p;
+} EmulEvent;
+
+#define MAX_ATR_SIZE 40
+struct EmulatedState {
+    CCIDCardState base;
+    uint8_t  debug;
+    char    *backend_str;
+    uint32_t backend;
+    char    *cert1;
+    char    *cert2;
+    char    *cert3;
+    char    *db;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
+    QemuMutex event_list_mutex;
+    VReader *reader;
+    QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
+    QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
+    QemuMutex handle_apdu_mutex;
+    QemuCond handle_apdu_cond;
+    int      pipe[2];
+    int      quit_apdu_thread;
+    QemuMutex apdu_thread_quit_mutex;
+    QemuCond apdu_thread_quit_cond;
+};
+
+static void emulated_apdu_from_guest(CCIDCardState *base,
+    const uint8_t *apdu, uint32_t len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = EMUL_GUEST_APDU;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, apdu, len);
+    qemu_mutex_lock(&card->vreader_mutex);
+    QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
+    qemu_mutex_unlock(&card->vreader_mutex);
+    qemu_mutex_lock(&card->handle_apdu_mutex);
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_mutex_unlock(&card->handle_apdu_mutex);
+}
+
+static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static void emulated_push_event(EmulatedState *card, EmulEvent *event)
+{
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
+    qemu_mutex_unlock(&card->event_list_mutex);
+    if (write(card->pipe[1], card, 1) != 1) {
+        DPRINTF(card, 1, "write to pipe failed\n");
+    }
+}
+
+static void emulated_push_type(EmulatedState *card, uint32_t type)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.gen.type = type;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_error(EmulatedState *card, uint64_t code)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.error.type = EMUL_ERROR;
+    event->p.error.code = code;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_data_type(EmulatedState *card, uint32_t type,
+    const uint8_t *data, uint32_t len)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = type;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, data, len);
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_reader_insert(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_INSERT);
+}
+
+static void emulated_push_reader_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_REMOVE);
+}
+
+static void emulated_push_card_insert(EmulatedState *card,
+    const uint8_t *atr, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
+}
+
+static void emulated_push_card_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_CARD_REMOVE);
+}
+
+static void emulated_push_response_apdu(EmulatedState *card,
+    const uint8_t *apdu, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
+}
+
+#define APDU_BUF_SIZE 270
+static void *handle_apdu_thread(void* arg)
+{
+    EmulatedState *card = arg;
+    uint8_t recv_data[APDU_BUF_SIZE];
+    int recv_len;
+    VReaderStatus reader_status;
+    EmulEvent *event;
+
+    while (1) {
+        qemu_mutex_lock(&card->handle_apdu_mutex);
+        qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
+        qemu_mutex_unlock(&card->handle_apdu_mutex);
+        if (card->quit_apdu_thread) {
+            card->quit_apdu_thread = 0; /* debugging */
+            break;
+        }
+        qemu_mutex_lock(&card->vreader_mutex);
+        while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
+            event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
+            assert((unsigned long)event > 1000);
+            QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
+            if (event->p.data.type != EMUL_GUEST_APDU) {
+                DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
+                qemu_free(event);
+                continue;
+            }
+            if (card->reader == NULL) {
+                DPRINTF(card, 1, "reader is NULL\n");
+                qemu_free(event);
+                continue;
+            }
+            recv_len = sizeof(recv_data);
+            reader_status = vreader_xfr_bytes(card->reader,
+                    event->p.data.data, event->p.data.len,
+                    recv_data, &recv_len);
+            DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
+            if (reader_status == VREADER_OK) {
+                emulated_push_response_apdu(card, recv_data, recv_len);
+            } else {
+                emulated_push_error(card, reader_status);
+            }
+            qemu_free(event);
+        }
+        qemu_mutex_unlock(&card->vreader_mutex);
+    }
+    qemu_mutex_lock(&card->apdu_thread_quit_mutex);
+    qemu_cond_signal(&card->apdu_thread_quit_cond);
+    qemu_mutex_unlock(&card->apdu_thread_quit_mutex);
+    return NULL;
+}
+
+static void *event_thread(void *arg)
+{
+    int atr_len = MAX_ATR_SIZE;
+    uint8_t atr[MAX_ATR_SIZE];
+    VEvent *event = NULL;
+    EmulatedState *card = arg;
+
+    while (1) {
+        const char *reader_name;
+
+        event = vevent_wait_next_vevent();
+        if (event == NULL || event->type == VEVENT_LAST) {
+            break;
+        }
+        if (event->type != VEVENT_READER_INSERT) {
+            if (card->reader == NULL && event->reader != NULL) {
+                /* Happens after device_add followed by card remove or insert.
+                 * XXX: create synthetic add_reader events if vcard_emul_init
+                 * already called, which happens if device_del and device_add
+                 * are called */
+                card->reader = vreader_reference(event->reader);
+            } else {
+                if (event->reader != card->reader) {
+                    fprintf(stderr,
+                        "ERROR: wrong reader: quiting event_thread\n");
+                    break;
+                }
+            }
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+            /* TODO: take a specific reader. i.e. track which reader
+             * we are seeing here, check it is the one we want (the first,
+             * or by a particular name), and ignore if we don't want it.
+             */
+            reader_name = vreader_get_name(event->reader);
+            if (card->reader != NULL) {
+                DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
+                    vreader_get_name(card->reader), reader_name);
+                qemu_mutex_lock(&card->vreader_mutex);
+                vreader_free(card->reader);
+                qemu_mutex_unlock(&card->vreader_mutex);
+                emulated_push_reader_remove(card);
+            }
+            qemu_mutex_lock(&card->vreader_mutex);
+            DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
+            card->reader = vreader_reference(event->reader);
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_insert(card);
+            break;
+        case VEVENT_READER_REMOVE:
+            DPRINTF(card, 2, " READER REMOVE: %s\n",
+                    vreader_get_name(event->reader));
+            qemu_mutex_lock(&card->vreader_mutex);
+            vreader_free(card->reader);
+            card->reader = NULL;
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_remove(card);
+            break;
+        case VEVENT_CARD_INSERT:
+            /* get the ATR (intended as a response to a power on from the
+             * reader */
+            atr_len = MAX_ATR_SIZE;
+            vreader_power_on(event->reader, atr, &atr_len);
+            card->atr_length = (uint8_t)atr_len;
+            DPRINTF(card, 2, " CARD INSERT\n");
+            emulated_push_card_insert(card, atr, atr_len);
+            break;
+        case VEVENT_CARD_REMOVE:
+            DPRINTF(card, 2, " CARD REMOVE\n");
+            emulated_push_card_remove(card);
+            break;
+        case VEVENT_LAST: /* quit */
+            vevent_delete(event);
+            return NULL;
+            break;
+        default:
+            break;
+        }
+        vevent_delete(event);
+    }
+    return NULL;
+}
+
+static void pipe_read(void *opaque)
+{
+    EmulatedState *card = opaque;
+    EmulEvent *event, *next;
+    char dummy;
+    int len;
+
+    do {
+        len = read(card->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
+        DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
+        switch (event->p.gen.type) {
+        case EMUL_RESPONSE_APDU:
+            ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
+                event->p.data.len);
+            break;
+        case EMUL_READER_INSERT:
+            ccid_card_ccid_attach(&card->base);
+            break;
+        case EMUL_READER_REMOVE:
+            ccid_card_ccid_detach(&card->base);
+            break;
+        case EMUL_CARD_INSERT:
+            assert(event->p.data.len <= MAX_ATR_SIZE);
+            card->atr_length = event->p.data.len;
+            memcpy(card->atr, event->p.data.data, card->atr_length);
+            ccid_card_card_inserted(&card->base);
+            break;
+        case EMUL_CARD_REMOVE:
+            ccid_card_card_removed(&card->base);
+            break;
+        case EMUL_ERROR:
+            ccid_card_card_error(&card->base, event->p.error.code);
+            break;
+        default:
+            DPRINTF(card, 2, "unexpected event\n");
+            break;
+        }
+        qemu_free(event);
+    }
+    QSIMPLEQ_INIT(&card->event_list);
+    qemu_mutex_unlock(&card->event_list_mutex);
+}
+
+static int init_pipe_signaling(EmulatedState *card)
+{
+    if (pipe(card->pipe) < 0) {
+        DPRINTF(card, 2, "pipe creation failed\n");
+        return -1;
+    }
+    fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[0], F_SETOWN, getpid());
+    qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
+    return 0;
+}
+
+#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
+#define CERTIFICATES_ARGS_TEMPLATE\
+    "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
+
+static int wrap_vcard_emul_init(VCardEmulOptions *options)
+{
+    static int called;
+    static int options_was_null;
+
+    if (called) {
+        if ((options == NULL) != options_was_null) {
+            printf("%s: warning: running emulated with certificates"
+                   " and emulated side by side is not supported\n",
+                   __func__);
+            return VCARD_EMUL_FAIL;
+        }
+        vcard_emul_replay_insertion_events();
+        return VCARD_EMUL_OK;
+    }
+    options_was_null = (options == NULL);
+    called = 1;
+    return vcard_emul_init(options);
+}
+
+static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
+{
+    char emul_args[200];
+    VCardEmulOptions *options = NULL;
+
+    snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
+        card->db ? card->db : CERTIFICATES_DEFAULT_DB,
+        card->cert1, card->cert2, card->cert3);
+    options = vcard_emul_options(emul_args);
+    if (options == NULL) {
+        printf("%s: warning: not using certificates due to"
+               " initialization error\n", __func__);
+    }
+    return wrap_vcard_emul_init(options);
+}
+
+typedef struct EnumTable {
+    const char *name;
+    uint32_t value;
+} EnumTable;
+
+EnumTable backend_enum_table[] = {
+    {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
+    {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
+    {NULL, 0},
+};
+
+static uint32_t parse_enumeration(char *str,
+    EnumTable *table, uint32_t not_found_value)
+{
+    uint32_t ret = not_found_value;
+
+    while (table->name != NULL) {
+        if (strcmp(table->name, str) == 0) {
+            ret = table->value;
+            break;
+        }
+        table++;
+    }
+    return ret;
+}
+
+static int emulated_initfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    QemuThread thread_id;
+    VCardEmulError ret;
+    EnumTable *ptable;
+
+    QSIMPLEQ_INIT(&card->event_list);
+    QSIMPLEQ_INIT(&card->guest_apdu_list);
+    qemu_mutex_init(&card->event_list_mutex);
+    qemu_mutex_init(&card->vreader_mutex);
+    qemu_mutex_init(&card->handle_apdu_mutex);
+    qemu_cond_init(&card->handle_apdu_cond);
+    card->reader = NULL;
+    card->quit_apdu_thread = 0;
+    if (init_pipe_signaling(card) < 0) {
+        return -1;
+    }
+    card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
+    if (card->backend == 0) {
+        printf("unknown backend, must be one of:\n");
+        for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
+            printf("%s\n", ptable->name);
+        }
+        return -1;
+    }
+
+    /* TODO: a passthru backened that works on local machine. third card type?*/
+    if (card->backend == BACKEND_CERTIFICATES) {
+        if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
+            ret = emulated_initialize_vcard_from_certificates(card);
+        } else {
+            printf("%s: you must provide all three certs for"
+                   " certificates backend\n", EMULATED_DEV_NAME);
+            return -1;
+        }
+    } else {
+        if (card->backend != BACKEND_NSS_EMULATED) {
+            printf("%s: bad backend specified. The options are:\n%s (default),"
+                " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
+                BACKEND_CERTIFICATES_NAME);
+            return -1;
+        }
+        if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
+            printf("%s: unexpected cert parameters to nss emulated backend\n",
+                   EMULATED_DEV_NAME);
+            return -1;
+        }
+        /* default to mirroring the local hardware readers */
+        ret = wrap_vcard_emul_init(NULL);
+    }
+    if (ret != VCARD_EMUL_OK) {
+        printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
+        return -1;
+    }
+    qemu_thread_create(&thread_id, event_thread, card);
+    qemu_thread_create(&thread_id, handle_apdu_thread, card);
+    return 0;
+}
+
+static int emulated_exitfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
+
+    vevent_queue_vevent(vevent); /* stop vevent thread */
+    qemu_mutex_lock(&card->apdu_thread_quit_mutex);
+    card->quit_apdu_thread = 1; /* stop handle_apdu thread */
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_cond_wait(&card->apdu_thread_quit_cond,
+                      &card->apdu_thread_quit_mutex);
+    /* handle_apdu thread stopped, can destroy all of it's mutexes */
+    qemu_cond_destroy(&card->handle_apdu_cond);
+    qemu_cond_destroy(&card->apdu_thread_quit_cond);
+    qemu_mutex_destroy(&card->apdu_thread_quit_mutex);
+    qemu_mutex_destroy(&card->handle_apdu_mutex);
+    qemu_mutex_destroy(&card->vreader_mutex);
+    qemu_mutex_destroy(&card->event_list_mutex);
+    return 0;
+}
+
+static CCIDCardInfo emulated_card_info = {
+    .qdev.name = EMULATED_DEV_NAME,
+    .qdev.desc = "emulated smartcard",
+    .qdev.size = sizeof(EmulatedState),
+    .initfn = emulated_initfn,
+    .exitfn = emulated_exitfn,
+    .get_atr = emulated_get_atr,
+    .apdu_from_guest = emulated_apdu_from_guest,
+    .qdev.unplug    = qdev_simple_unplug_cb,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
+        DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
+        DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
+        DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
+        DEFINE_PROP_STRING("db", EmulatedState, db),
+        DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void ccid_card_emulated_register_devices(void)
+{
+    ccid_card_qdev_register(&emulated_card_info);
+}
+
+device_init(ccid_card_emulated_register_devices)
diff --git a/qemu-0.15.x/hw/ccid-card-passthru.c b/qemu-0.15.x/hw/ccid-card-passthru.c
new file mode 100644
index 0000000..28eb9d1
--- /dev/null
+++ b/qemu-0.15.x/hw/ccid-card-passthru.c
@@ -0,0 +1,339 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-char.h"
+#include "qemu_socket.h"
+#include "monitor.h"
+#include "hw/ccid.h"
+#include "libcacard/vscard_common.h"
+
+#define DPRINTF(card, lvl, fmt, ...)                    \
+do {                                                    \
+    if (lvl <= card->debug) {                           \
+        printf("ccid-card-passthru: " fmt , ## __VA_ARGS__);     \
+    }                                                   \
+} while (0)
+
+#define D_WARN 1
+#define D_INFO 2
+#define D_MORE_INFO 3
+#define D_VERBOSE 4
+
+/* TODO: do we still need this? */
+uint8_t DEFAULT_ATR[] = {
+/*
+ * From some example somewhere
+ * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
+ */
+
+/* From an Athena smart card */
+ 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
+ 0x13, 0x08
+};
+
+
+#define PASSTHRU_DEV_NAME "ccid-card-passthru"
+#define VSCARD_IN_SIZE 65536
+
+/* maximum size of ATR - from 7816-3 */
+#define MAX_ATR_SIZE        40
+
+typedef struct PassthruState PassthruState;
+
+struct PassthruState {
+    CCIDCardState base;
+    CharDriverState *cs;
+    uint8_t  vscard_in_data[VSCARD_IN_SIZE];
+    uint32_t vscard_in_pos;
+    uint32_t vscard_in_hdr;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    uint8_t  debug;
+};
+
+/*
+ * VSCard protocol over chardev
+ * This code should not depend on the card type.
+ */
+
+static void ccid_card_vscard_send_msg(PassthruState *s,
+        VSCMsgType type, uint32_t reader_id,
+        const uint8_t *payload, uint32_t length)
+{
+    VSCMsgHeader scr_msg_header;
+
+    scr_msg_header.type = htonl(type);
+    scr_msg_header.reader_id = htonl(reader_id);
+    scr_msg_header.length = htonl(length);
+    qemu_chr_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
+    qemu_chr_write(s->cs, payload, length);
+}
+
+static void ccid_card_vscard_send_apdu(PassthruState *s,
+    const uint8_t *apdu, uint32_t length)
+{
+    ccid_card_vscard_send_msg(
+        s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
+}
+
+static void ccid_card_vscard_send_error(PassthruState *s,
+                    uint32_t reader_id, VSCErrorCode code)
+{
+    VSCMsgError msg = {.code = htonl(code)};
+
+    ccid_card_vscard_send_msg(
+        s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
+}
+
+static void ccid_card_vscard_send_init(PassthruState *s)
+{
+    VSCMsgInit msg = {
+        .version = htonl(VSCARD_VERSION),
+        .magic = VSCARD_MAGIC,
+        .capabilities = {0}
+    };
+
+    ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
+                         (uint8_t *)&msg, sizeof(msg));
+}
+
+static int ccid_card_vscard_can_read(void *opaque)
+{
+    PassthruState *card = opaque;
+
+    return VSCARD_IN_SIZE >= card->vscard_in_pos ?
+           VSCARD_IN_SIZE - card->vscard_in_pos : 0;
+}
+
+static void ccid_card_vscard_handle_init(
+    PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
+{
+    uint32_t *capabilities;
+    int num_capabilities;
+    int i;
+
+    capabilities = init->capabilities;
+    num_capabilities =
+        1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
+    init->version = ntohl(init->version);
+    for (i = 0 ; i < num_capabilities; ++i) {
+        capabilities[i] = ntohl(capabilities[i]);
+    }
+    if (init->magic != VSCARD_MAGIC) {
+        error_report("wrong magic");
+        /* we can't disconnect the chardev */
+    }
+    if (init->version != VSCARD_VERSION) {
+        DPRINTF(card, D_WARN,
+            "got version %d, have %d", init->version, VSCARD_VERSION);
+    }
+    /* future handling of capabilities, none exist atm */
+    ccid_card_vscard_send_init(card);
+}
+
+static void ccid_card_vscard_handle_message(PassthruState *card,
+    VSCMsgHeader *scr_msg_header)
+{
+    uint8_t *data = (uint8_t *)&scr_msg_header[1];
+
+    switch (scr_msg_header->type) {
+    case VSC_ATR:
+        DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
+        if (scr_msg_header->length > MAX_ATR_SIZE) {
+            error_report("ATR size exceeds spec, ignoring");
+            ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                        VSC_GENERAL_ERROR);
+        }
+        memcpy(card->atr, data, scr_msg_header->length);
+        card->atr_length = scr_msg_header->length;
+        ccid_card_card_inserted(&card->base);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                    VSC_SUCCESS);
+        break;
+    case VSC_APDU:
+        ccid_card_send_apdu_to_guest(
+            &card->base, data, scr_msg_header->length);
+        break;
+    case VSC_CardRemove:
+        DPRINTF(card, D_INFO, "VSC_CardRemove\n");
+        ccid_card_card_removed(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    case VSC_Init:
+        ccid_card_vscard_handle_init(
+            card, scr_msg_header, (VSCMsgInit *)data);
+        break;
+    case VSC_Error:
+        ccid_card_card_error(&card->base, *(uint32_t *)data);
+        break;
+    case VSC_ReaderAdd:
+        if (ccid_card_ccid_attach(&card->base) < 0) {
+            ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
+                                      VSC_CANNOT_ADD_MORE_READERS);
+        } else {
+            ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
+                                        VSC_SUCCESS);
+        }
+        break;
+    case VSC_ReaderRemove:
+        ccid_card_ccid_detach(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    default:
+        printf("usb-ccid: chardev: unexpected message of type %X\n",
+               scr_msg_header->type);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+            VSC_GENERAL_ERROR);
+    }
+}
+
+static void ccid_card_vscard_drop_connection(PassthruState *card)
+{
+    qemu_chr_close(card->cs);
+    card->vscard_in_pos = card->vscard_in_hdr = 0;
+}
+
+static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
+{
+    PassthruState *card = opaque;
+    VSCMsgHeader *hdr;
+
+    if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
+        error_report(
+            "no room for data: pos %d +  size %d > %d. dropping connection.",
+            card->vscard_in_pos, size, VSCARD_IN_SIZE);
+        ccid_card_vscard_drop_connection(card);
+        return;
+    }
+    assert(card->vscard_in_pos < VSCARD_IN_SIZE);
+    assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
+    memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
+    card->vscard_in_pos += size;
+    hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+
+    while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
+         &&(card->vscard_in_pos - card->vscard_in_hdr >=
+                                  sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
+        hdr->reader_id = ntohl(hdr->reader_id);
+        hdr->length = ntohl(hdr->length);
+        hdr->type = ntohl(hdr->type);
+        ccid_card_vscard_handle_message(card, hdr);
+        card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
+        hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+    }
+    if (card->vscard_in_hdr == card->vscard_in_pos) {
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+    }
+}
+
+static void ccid_card_vscard_event(void *opaque, int event)
+{
+    PassthruState *card = opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+        break;
+    case CHR_EVENT_FOCUS:
+        break;
+    case CHR_EVENT_OPENED:
+        DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
+        break;
+    }
+}
+
+/* End VSCard handling */
+
+static void passthru_apdu_from_guest(
+    CCIDCardState *base, const uint8_t *apdu, uint32_t len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    if (!card->cs) {
+        printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
+        return;
+    }
+    ccid_card_vscard_send_apdu(card, apdu, len);
+}
+
+static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static int passthru_initfn(CCIDCardState *base)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    card->vscard_in_pos = 0;
+    card->vscard_in_hdr = 0;
+    if (card->cs) {
+        DPRINTF(card, D_INFO, "initing chardev\n");
+        qemu_chr_add_handlers(card->cs,
+            ccid_card_vscard_can_read,
+            ccid_card_vscard_read,
+            ccid_card_vscard_event, card);
+        ccid_card_vscard_send_init(card);
+    } else {
+        error_report("missing chardev");
+        return -1;
+    }
+    assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
+    memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
+    card->atr_length = sizeof(DEFAULT_ATR);
+    return 0;
+}
+
+static int passthru_exitfn(CCIDCardState *base)
+{
+    return 0;
+}
+
+static VMStateDescription passthru_vmstate = {
+    .name = PASSTHRU_DEV_NAME,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(vscard_in_data, PassthruState),
+        VMSTATE_UINT32(vscard_in_pos, PassthruState),
+        VMSTATE_UINT32(vscard_in_hdr, PassthruState),
+        VMSTATE_BUFFER(atr, PassthruState),
+        VMSTATE_UINT8(atr_length, PassthruState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static CCIDCardInfo passthru_card_info = {
+    .qdev.name = PASSTHRU_DEV_NAME,
+    .qdev.desc = "passthrough smartcard",
+    .qdev.size = sizeof(PassthruState),
+    .qdev.vmsd = &passthru_vmstate,
+    .initfn = passthru_initfn,
+    .exitfn = passthru_exitfn,
+    .get_atr = passthru_get_atr,
+    .apdu_from_guest = passthru_apdu_from_guest,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", PassthruState, cs),
+        DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void ccid_card_passthru_register_devices(void)
+{
+    ccid_card_qdev_register(&passthru_card_info);
+}
+
+device_init(ccid_card_passthru_register_devices)
diff --git a/qemu-0.15.x/hw/ccid.h b/qemu-0.15.x/hw/ccid.h
new file mode 100644
index 0000000..9e3abe1
--- /dev/null
+++ b/qemu-0.15.x/hw/ccid.h
@@ -0,0 +1,58 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed under the GNU LGPL, version 2 or later.
+ */
+
+#ifndef CCID_H
+#define CCID_H
+
+#include "qdev.h"
+
+typedef struct CCIDCardState CCIDCardState;
+typedef struct CCIDCardInfo CCIDCardInfo;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+    DeviceState qdev;
+    uint32_t    slot; /* For future use with multiple slot reader. */
+};
+
+/*
+ * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
+ * into the smartcard device (hw/ccid-card-*.c)
+ */
+struct CCIDCardInfo {
+    DeviceInfo qdev;
+    const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
+    void (*apdu_from_guest)(CCIDCardState *card,
+                            const uint8_t *apdu,
+                            uint32_t len);
+    int (*exitfn)(CCIDCardState *card);
+    int (*initfn)(CCIDCardState *card);
+};
+
+/*
+ * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
+ */
+void ccid_card_send_apdu_to_guest(CCIDCardState *card,
+                                  uint8_t *apdu,
+                                  uint32_t len);
+void ccid_card_card_removed(CCIDCardState *card);
+void ccid_card_card_inserted(CCIDCardState *card);
+void ccid_card_card_error(CCIDCardState *card, uint64_t error);
+void ccid_card_qdev_register(CCIDCardInfo *card);
+
+/*
+ * support guest visible insertion/removal of ccid devices based on actual
+ * devices connected/removed. Called by card implementation (passthru, local)
+ */
+int ccid_card_ccid_attach(CCIDCardState *card);
+void ccid_card_ccid_detach(CCIDCardState *card);
+
+#endif /* CCID_H */
diff --git a/qemu-0.15.x/hw/cdrom.c b/qemu-0.15.x/hw/cdrom.c
new file mode 100644
index 0000000..3b99535
--- /dev/null
+++ b/qemu-0.15.x/hw/cdrom.c
@@ -0,0 +1,155 @@
+/*
+ * 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 "qemu-common.h"
+#include "scsi.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 --git a/qemu-0.15.x/hw/cirrus_vga.c b/qemu-0.15.x/hw/cirrus_vga.c
new file mode 100644
index 0000000..f39d1f8
--- /dev/null
+++ b/qemu-0.15.x/hw/cirrus_vga.c
@@ -0,0 +1,3151 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ * 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.
+ */
+/*
+ * Reference: Finn Thogersons' VGADOC4b
+ *   available at http://home.worldonline.dk/~finth/
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "console.h"
+#include "vga_int.h"
+#include "loader.h"
+
+/*
+ * TODO:
+ *    - destination write mask support not complete (bits 5..7)
+ *    - optimize linear mappings
+ *    - optimize bitblt functions
+ */
+
+//#define DEBUG_CIRRUS
+//#define DEBUG_BITBLT
+
+/***************************************
+ *
+ *  definitions
+ *
+ ***************************************/
+
+// ID
+#define CIRRUS_ID_CLGD5422  (0x23<<2)
+#define CIRRUS_ID_CLGD5426  (0x24<<2)
+#define CIRRUS_ID_CLGD5424  (0x25<<2)
+#define CIRRUS_ID_CLGD5428  (0x26<<2)
+#define CIRRUS_ID_CLGD5430  (0x28<<2)
+#define CIRRUS_ID_CLGD5434  (0x2A<<2)
+#define CIRRUS_ID_CLGD5436  (0x2B<<2)
+#define CIRRUS_ID_CLGD5446  (0x2E<<2)
+
+// sequencer 0x07
+#define CIRRUS_SR7_BPP_VGA            0x00
+#define CIRRUS_SR7_BPP_SVGA           0x01
+#define CIRRUS_SR7_BPP_MASK           0x0e
+#define CIRRUS_SR7_BPP_8              0x00
+#define CIRRUS_SR7_BPP_16_DOUBLEVCLK  0x02
+#define CIRRUS_SR7_BPP_24             0x04
+#define CIRRUS_SR7_BPP_16             0x06
+#define CIRRUS_SR7_BPP_32             0x08
+#define CIRRUS_SR7_ISAADDR_MASK       0xe0
+
+// sequencer 0x0f
+#define CIRRUS_MEMSIZE_512k        0x08
+#define CIRRUS_MEMSIZE_1M          0x10
+#define CIRRUS_MEMSIZE_2M          0x18
+#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80	// bank switching is enabled.
+
+// sequencer 0x12
+#define CIRRUS_CURSOR_SHOW         0x01
+#define CIRRUS_CURSOR_HIDDENPEL    0x02
+#define CIRRUS_CURSOR_LARGE        0x04	// 64x64 if set, 32x32 if clear
+
+// sequencer 0x17
+#define CIRRUS_BUSTYPE_VLBFAST   0x10
+#define CIRRUS_BUSTYPE_PCI       0x20
+#define CIRRUS_BUSTYPE_VLBSLOW   0x30
+#define CIRRUS_BUSTYPE_ISA       0x38
+#define CIRRUS_MMIO_ENABLE       0x04
+#define CIRRUS_MMIO_USE_PCIADDR  0x40	// 0xb8000 if cleared.
+#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
+
+// control 0x0b
+#define CIRRUS_BANKING_DUAL             0x01
+#define CIRRUS_BANKING_GRANULARITY_16K  0x20	// set:16k, clear:4k
+
+// control 0x30
+#define CIRRUS_BLTMODE_BACKWARDS        0x01
+#define CIRRUS_BLTMODE_MEMSYSDEST       0x02
+#define CIRRUS_BLTMODE_MEMSYSSRC        0x04
+#define CIRRUS_BLTMODE_TRANSPARENTCOMP  0x08
+#define CIRRUS_BLTMODE_PATTERNCOPY      0x40
+#define CIRRUS_BLTMODE_COLOREXPAND      0x80
+#define CIRRUS_BLTMODE_PIXELWIDTHMASK   0x30
+#define CIRRUS_BLTMODE_PIXELWIDTH8      0x00
+#define CIRRUS_BLTMODE_PIXELWIDTH16     0x10
+#define CIRRUS_BLTMODE_PIXELWIDTH24     0x20
+#define CIRRUS_BLTMODE_PIXELWIDTH32     0x30
+
+// control 0x31
+#define CIRRUS_BLT_BUSY                 0x01
+#define CIRRUS_BLT_START                0x02
+#define CIRRUS_BLT_RESET                0x04
+#define CIRRUS_BLT_FIFOUSED             0x10
+#define CIRRUS_BLT_AUTOSTART            0x80
+
+// control 0x32
+#define CIRRUS_ROP_0                    0x00
+#define CIRRUS_ROP_SRC_AND_DST          0x05
+#define CIRRUS_ROP_NOP                  0x06
+#define CIRRUS_ROP_SRC_AND_NOTDST       0x09
+#define CIRRUS_ROP_NOTDST               0x0b
+#define CIRRUS_ROP_SRC                  0x0d
+#define CIRRUS_ROP_1                    0x0e
+#define CIRRUS_ROP_NOTSRC_AND_DST       0x50
+#define CIRRUS_ROP_SRC_XOR_DST          0x59
+#define CIRRUS_ROP_SRC_OR_DST           0x6d
+#define CIRRUS_ROP_NOTSRC_OR_NOTDST     0x90
+#define CIRRUS_ROP_SRC_NOTXOR_DST       0x95
+#define CIRRUS_ROP_SRC_OR_NOTDST        0xad
+#define CIRRUS_ROP_NOTSRC               0xd0
+#define CIRRUS_ROP_NOTSRC_OR_DST        0xd6
+#define CIRRUS_ROP_NOTSRC_AND_NOTDST    0xda
+
+#define CIRRUS_ROP_NOP_INDEX 2
+#define CIRRUS_ROP_SRC_INDEX 5
+
+// control 0x33
+#define CIRRUS_BLTMODEEXT_SOLIDFILL        0x04
+#define CIRRUS_BLTMODEEXT_COLOREXPINV      0x02
+#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
+
+// memory-mapped IO
+#define CIRRUS_MMIO_BLTBGCOLOR        0x00	// dword
+#define CIRRUS_MMIO_BLTFGCOLOR        0x04	// dword
+#define CIRRUS_MMIO_BLTWIDTH          0x08	// word
+#define CIRRUS_MMIO_BLTHEIGHT         0x0a	// word
+#define CIRRUS_MMIO_BLTDESTPITCH      0x0c	// word
+#define CIRRUS_MMIO_BLTSRCPITCH       0x0e	// word
+#define CIRRUS_MMIO_BLTDESTADDR       0x10	// dword
+#define CIRRUS_MMIO_BLTSRCADDR        0x14	// dword
+#define CIRRUS_MMIO_BLTWRITEMASK      0x17	// byte
+#define CIRRUS_MMIO_BLTMODE           0x18	// byte
+#define CIRRUS_MMIO_BLTROP            0x1a	// byte
+#define CIRRUS_MMIO_BLTMODEEXT        0x1b	// byte
+#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c	// word?
+#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20	// word?
+#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24	// word
+#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26	// word
+#define CIRRUS_MMIO_LINEARDRAW_END_X  0x28	// word
+#define CIRRUS_MMIO_LINEARDRAW_END_Y  0x2a	// word
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c	// byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d	// byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e	// byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f	// byte
+#define CIRRUS_MMIO_BRESENHAM_K1      0x30	// word
+#define CIRRUS_MMIO_BRESENHAM_K3      0x32	// word
+#define CIRRUS_MMIO_BRESENHAM_ERROR   0x34	// word
+#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36	// word
+#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38	// byte
+#define CIRRUS_MMIO_LINEDRAW_MODE     0x39	// byte
+#define CIRRUS_MMIO_BLTSTATUS         0x40	// byte
+
+#define CIRRUS_PNPMMIO_SIZE         0x1000
+
+#define ABS(a) ((signed)(a) > 0 ? a : -a)
+
+#define BLTUNSAFE(s) \
+    ( \
+        ( /* check dst is within bounds */ \
+            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
+                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
+                    (s)->vga.vram_size \
+        ) || \
+        ( /* check src is within bounds */ \
+            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
+                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
+                    (s)->vga.vram_size \
+        ) \
+    )
+
+struct CirrusVGAState;
+typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
+                                     uint8_t * dst, const uint8_t * src,
+				     int dstpitch, int srcpitch,
+				     int bltwidth, int bltheight);
+typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
+                              uint8_t *dst, int dst_pitch, int width, int height);
+
+typedef struct CirrusVGAState {
+    VGACommonState vga;
+
+    int cirrus_linear_io_addr;
+    int cirrus_linear_bitblt_io_addr;
+    int cirrus_mmio_io_addr;
+    uint32_t cirrus_addr_mask;
+    uint32_t linear_mmio_mask;
+    uint8_t cirrus_shadow_gr0;
+    uint8_t cirrus_shadow_gr1;
+    uint8_t cirrus_hidden_dac_lockindex;
+    uint8_t cirrus_hidden_dac_data;
+    uint32_t cirrus_bank_base[2];
+    uint32_t cirrus_bank_limit[2];
+    uint8_t cirrus_hidden_palette[48];
+    uint32_t hw_cursor_x;
+    uint32_t hw_cursor_y;
+    int cirrus_blt_pixelwidth;
+    int cirrus_blt_width;
+    int cirrus_blt_height;
+    int cirrus_blt_dstpitch;
+    int cirrus_blt_srcpitch;
+    uint32_t cirrus_blt_fgcol;
+    uint32_t cirrus_blt_bgcol;
+    uint32_t cirrus_blt_dstaddr;
+    uint32_t cirrus_blt_srcaddr;
+    uint8_t cirrus_blt_mode;
+    uint8_t cirrus_blt_modeext;
+    cirrus_bitblt_rop_t cirrus_rop;
+#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
+    uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
+    uint8_t *cirrus_srcptr;
+    uint8_t *cirrus_srcptr_end;
+    uint32_t cirrus_srccounter;
+    /* hwcursor display state */
+    int last_hw_cursor_size;
+    int last_hw_cursor_x;
+    int last_hw_cursor_y;
+    int last_hw_cursor_y_start;
+    int last_hw_cursor_y_end;
+    int real_vram_size; /* XXX: suppress that */
+    int device_id;
+    int bustype;
+} CirrusVGAState;
+
+typedef struct PCICirrusVGAState {
+    PCIDevice dev;
+    CirrusVGAState cirrus_vga;
+} PCICirrusVGAState;
+
+static uint8_t rop_to_index[256];
+
+/***************************************
+ *
+ *  prototypes.
+ *
+ ***************************************/
+
+
+static void cirrus_bitblt_reset(CirrusVGAState *s);
+static void cirrus_update_memory_access(CirrusVGAState *s);
+
+/***************************************
+ *
+ *  raster operations
+ *
+ ***************************************/
+
+static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
+                                  uint8_t *dst,const uint8_t *src,
+                                  int dstpitch,int srcpitch,
+                                  int bltwidth,int bltheight)
+{
+}
+
+static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
+                                   uint8_t *dst,
+                                   int dstpitch, int bltwidth,int bltheight)
+{
+}
+
+#define ROP_NAME 0
+#define ROP_FN(d, s) 0
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_and_dst
+#define ROP_FN(d, s) (s) & (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_and_notdst
+#define ROP_FN(d, s) (s) & (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notdst
+#define ROP_FN(d, s) ~(d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src
+#define ROP_FN(d, s) s
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME 1
+#define ROP_FN(d, s) ~0
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_and_dst
+#define ROP_FN(d, s) (~(s)) & (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_xor_dst
+#define ROP_FN(d, s) (s) ^ (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_or_dst
+#define ROP_FN(d, s) (s) | (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_or_notdst
+#define ROP_FN(d, s) (~(s)) | (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_notxor_dst
+#define ROP_FN(d, s) ~((s) ^ (d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_or_notdst
+#define ROP_FN(d, s) (s) | (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc
+#define ROP_FN(d, s) (~(s))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_or_dst
+#define ROP_FN(d, s) (~(s)) | (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_and_notdst
+#define ROP_FN(d, s) (~(s)) & (~(d))
+#include "cirrus_vga_rop.h"
+
+static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
+    cirrus_bitblt_rop_fwd_0,
+    cirrus_bitblt_rop_fwd_src_and_dst,
+    cirrus_bitblt_rop_nop,
+    cirrus_bitblt_rop_fwd_src_and_notdst,
+    cirrus_bitblt_rop_fwd_notdst,
+    cirrus_bitblt_rop_fwd_src,
+    cirrus_bitblt_rop_fwd_1,
+    cirrus_bitblt_rop_fwd_notsrc_and_dst,
+    cirrus_bitblt_rop_fwd_src_xor_dst,
+    cirrus_bitblt_rop_fwd_src_or_dst,
+    cirrus_bitblt_rop_fwd_notsrc_or_notdst,
+    cirrus_bitblt_rop_fwd_src_notxor_dst,
+    cirrus_bitblt_rop_fwd_src_or_notdst,
+    cirrus_bitblt_rop_fwd_notsrc,
+    cirrus_bitblt_rop_fwd_notsrc_or_dst,
+    cirrus_bitblt_rop_fwd_notsrc_and_notdst,
+};
+
+static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
+    cirrus_bitblt_rop_bkwd_0,
+    cirrus_bitblt_rop_bkwd_src_and_dst,
+    cirrus_bitblt_rop_nop,
+    cirrus_bitblt_rop_bkwd_src_and_notdst,
+    cirrus_bitblt_rop_bkwd_notdst,
+    cirrus_bitblt_rop_bkwd_src,
+    cirrus_bitblt_rop_bkwd_1,
+    cirrus_bitblt_rop_bkwd_notsrc_and_dst,
+    cirrus_bitblt_rop_bkwd_src_xor_dst,
+    cirrus_bitblt_rop_bkwd_src_or_dst,
+    cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
+    cirrus_bitblt_rop_bkwd_src_notxor_dst,
+    cirrus_bitblt_rop_bkwd_src_or_notdst,
+    cirrus_bitblt_rop_bkwd_notsrc,
+    cirrus_bitblt_rop_bkwd_notsrc_or_dst,
+    cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
+};
+
+#define TRANSP_ROP(name) {\
+    name ## _8,\
+    name ## _16,\
+        }
+#define TRANSP_NOP(func) {\
+    func,\
+    func,\
+        }
+
+static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst),
+};
+
+#define ROP2(name) {\
+    name ## _8,\
+    name ## _16,\
+    name ## _24,\
+    name ## _32,\
+        }
+
+#define ROP_NOP2(func) {\
+    func,\
+    func,\
+    func,\
+    func,\
+        }
+
+static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
+    ROP2(cirrus_patternfill_0),
+    ROP2(cirrus_patternfill_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_patternfill_src_and_notdst),
+    ROP2(cirrus_patternfill_notdst),
+    ROP2(cirrus_patternfill_src),
+    ROP2(cirrus_patternfill_1),
+    ROP2(cirrus_patternfill_notsrc_and_dst),
+    ROP2(cirrus_patternfill_src_xor_dst),
+    ROP2(cirrus_patternfill_src_or_dst),
+    ROP2(cirrus_patternfill_notsrc_or_notdst),
+    ROP2(cirrus_patternfill_src_notxor_dst),
+    ROP2(cirrus_patternfill_src_or_notdst),
+    ROP2(cirrus_patternfill_notsrc),
+    ROP2(cirrus_patternfill_notsrc_or_dst),
+    ROP2(cirrus_patternfill_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
+    ROP2(cirrus_colorexpand_transp_0),
+    ROP2(cirrus_colorexpand_transp_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_transp_src_and_notdst),
+    ROP2(cirrus_colorexpand_transp_notdst),
+    ROP2(cirrus_colorexpand_transp_src),
+    ROP2(cirrus_colorexpand_transp_1),
+    ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_transp_src_xor_dst),
+    ROP2(cirrus_colorexpand_transp_src_or_dst),
+    ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_transp_src_notxor_dst),
+    ROP2(cirrus_colorexpand_transp_src_or_notdst),
+    ROP2(cirrus_colorexpand_transp_notsrc),
+    ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
+    ROP2(cirrus_colorexpand_0),
+    ROP2(cirrus_colorexpand_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_src_and_notdst),
+    ROP2(cirrus_colorexpand_notdst),
+    ROP2(cirrus_colorexpand_src),
+    ROP2(cirrus_colorexpand_1),
+    ROP2(cirrus_colorexpand_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_src_xor_dst),
+    ROP2(cirrus_colorexpand_src_or_dst),
+    ROP2(cirrus_colorexpand_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_src_notxor_dst),
+    ROP2(cirrus_colorexpand_src_or_notdst),
+    ROP2(cirrus_colorexpand_notsrc),
+    ROP2(cirrus_colorexpand_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
+    ROP2(cirrus_colorexpand_pattern_transp_0),
+    ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_src),
+    ROP2(cirrus_colorexpand_pattern_transp_1),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
+    ROP2(cirrus_colorexpand_pattern_0),
+    ROP2(cirrus_colorexpand_pattern_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_pattern_src_and_notdst),
+    ROP2(cirrus_colorexpand_pattern_notdst),
+    ROP2(cirrus_colorexpand_pattern_src),
+    ROP2(cirrus_colorexpand_pattern_1),
+    ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_pattern_src_xor_dst),
+    ROP2(cirrus_colorexpand_pattern_src_or_dst),
+    ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
+    ROP2(cirrus_colorexpand_pattern_src_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_notsrc),
+    ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
+};
+
+static const cirrus_fill_t cirrus_fill[16][4] = {
+    ROP2(cirrus_fill_0),
+    ROP2(cirrus_fill_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_fill_nop),
+    ROP2(cirrus_fill_src_and_notdst),
+    ROP2(cirrus_fill_notdst),
+    ROP2(cirrus_fill_src),
+    ROP2(cirrus_fill_1),
+    ROP2(cirrus_fill_notsrc_and_dst),
+    ROP2(cirrus_fill_src_xor_dst),
+    ROP2(cirrus_fill_src_or_dst),
+    ROP2(cirrus_fill_notsrc_or_notdst),
+    ROP2(cirrus_fill_src_notxor_dst),
+    ROP2(cirrus_fill_src_or_notdst),
+    ROP2(cirrus_fill_notsrc),
+    ROP2(cirrus_fill_notsrc_or_dst),
+    ROP2(cirrus_fill_notsrc_and_notdst),
+};
+
+static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
+{
+    unsigned int color;
+    switch (s->cirrus_blt_pixelwidth) {
+    case 1:
+        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
+        break;
+    case 2:
+        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8);
+        s->cirrus_blt_fgcol = le16_to_cpu(color);
+        break;
+    case 3:
+        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
+            (s->vga.gr[0x11] << 8) | (s->vga.gr[0x13] << 16);
+        break;
+    default:
+    case 4:
+        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8) |
+            (s->vga.gr[0x13] << 16) | (s->vga.gr[0x15] << 24);
+        s->cirrus_blt_fgcol = le32_to_cpu(color);
+        break;
+    }
+}
+
+static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
+{
+    unsigned int color;
+    switch (s->cirrus_blt_pixelwidth) {
+    case 1:
+        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
+        break;
+    case 2:
+        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8);
+        s->cirrus_blt_bgcol = le16_to_cpu(color);
+        break;
+    case 3:
+        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
+            (s->vga.gr[0x10] << 8) | (s->vga.gr[0x12] << 16);
+        break;
+    default:
+    case 4:
+        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8) |
+            (s->vga.gr[0x12] << 16) | (s->vga.gr[0x14] << 24);
+        s->cirrus_blt_bgcol = le32_to_cpu(color);
+        break;
+    }
+}
+
+static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
+				     int off_pitch, int bytesperline,
+				     int lines)
+{
+    int y;
+    int off_cur;
+    int off_cur_end;
+
+    for (y = 0; y < lines; y++) {
+	off_cur = off_begin;
+	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+	off_cur &= TARGET_PAGE_MASK;
+	while (off_cur < off_cur_end) {
+	    cpu_physical_memory_set_dirty(s->vga.vram_offset + off_cur);
+	    off_cur += TARGET_PAGE_SIZE;
+	}
+	off_begin += off_pitch;
+    }
+}
+
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
+					    const uint8_t * src)
+{
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
+
+    if (BLTUNSAFE(s))
+        return 0;
+
+    (*s->cirrus_rop) (s, dst, src,
+                      s->cirrus_blt_dstpitch, 0,
+                      s->cirrus_blt_width, s->cirrus_blt_height);
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+                             s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+                             s->cirrus_blt_height);
+    return 1;
+}
+
+/* fill */
+
+static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
+{
+    cirrus_fill_t rop_func;
+
+    if (BLTUNSAFE(s))
+        return 0;
+    rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+    rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+             s->cirrus_blt_dstpitch,
+             s->cirrus_blt_width, s->cirrus_blt_height);
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+			     s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+			     s->cirrus_blt_height);
+    cirrus_bitblt_reset(s);
+    return 1;
+}
+
+/***************************************
+ *
+ *  bitblt (video-to-video)
+ *
+ ***************************************/
+
+static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
+{
+    return cirrus_bitblt_common_patterncopy(s,
+					    s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
+                                            s->cirrus_addr_mask));
+}
+
+static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
+{
+    int sx = 0, sy = 0;
+    int dx = 0, dy = 0;
+    int depth = 0;
+    int notify = 0;
+
+    /* make sure to only copy if it's a plain copy ROP */
+    if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
+        *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
+
+        int width, height;
+
+        depth = s->vga.get_bpp(&s->vga) / 8;
+        s->vga.get_resolution(&s->vga, &width, &height);
+
+        /* extra x, y */
+        sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
+        sy = (src / ABS(s->cirrus_blt_srcpitch));
+        dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
+        dy = (dst / ABS(s->cirrus_blt_dstpitch));
+
+        /* normalize width */
+        w /= depth;
+
+        /* if we're doing a backward copy, we have to adjust
+           our x/y to be the upper left corner (instead of the lower
+           right corner) */
+        if (s->cirrus_blt_dstpitch < 0) {
+            sx -= (s->cirrus_blt_width / depth) - 1;
+            dx -= (s->cirrus_blt_width / depth) - 1;
+            sy -= s->cirrus_blt_height - 1;
+            dy -= s->cirrus_blt_height - 1;
+        }
+
+        /* are we in the visible portion of memory? */
+        if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
+            (sx + w) <= width && (sy + h) <= height &&
+            (dx + w) <= width && (dy + h) <= height) {
+            notify = 1;
+        }
+    }
+
+    /* we have to flush all pending changes so that the copy
+       is generated at the appropriate moment in time */
+    if (notify)
+	vga_hw_update();
+
+    (*s->cirrus_rop) (s, s->vga.vram_ptr +
+		      (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+		      s->vga.vram_ptr +
+		      (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+		      s->cirrus_blt_width, s->cirrus_blt_height);
+
+    if (notify)
+	qemu_console_copy(s->vga.ds,
+			  sx, sy, dx, dy,
+			  s->cirrus_blt_width / depth,
+			  s->cirrus_blt_height);
+
+    /* we don't have to notify the display that this portion has
+       changed since qemu_console_copy implies this */
+
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+				s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+				s->cirrus_blt_height);
+}
+
+static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+{
+    if (BLTUNSAFE(s))
+        return 0;
+
+    cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
+            s->cirrus_blt_srcaddr - s->vga.start_addr,
+            s->cirrus_blt_width, s->cirrus_blt_height);
+
+    return 1;
+}
+
+/***************************************
+ *
+ *  bitblt (cpu-to-video)
+ *
+ ***************************************/
+
+static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
+{
+    int copy_count;
+    uint8_t *end_ptr;
+
+    if (s->cirrus_srccounter > 0) {
+        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+            cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
+        the_end:
+            s->cirrus_srccounter = 0;
+            cirrus_bitblt_reset(s);
+        } else {
+            /* at least one scan line */
+            do {
+                (*s->cirrus_rop)(s, s->vga.vram_ptr +
+                                 (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+                                  s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
+                cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
+                                         s->cirrus_blt_width, 1);
+                s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
+                s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
+                if (s->cirrus_srccounter <= 0)
+                    goto the_end;
+                /* more bytes than needed can be transfered because of
+                   word alignment, so we keep them for the next line */
+                /* XXX: keep alignment to speed up transfer */
+                end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+                copy_count = s->cirrus_srcptr_end - end_ptr;
+                memmove(s->cirrus_bltbuf, end_ptr, copy_count);
+                s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
+                s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+            } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
+        }
+    }
+}
+
+/***************************************
+ *
+ *  bitblt wrapper
+ *
+ ***************************************/
+
+static void cirrus_bitblt_reset(CirrusVGAState * s)
+{
+    int need_update;
+
+    s->vga.gr[0x31] &=
+	~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
+    need_update = s->cirrus_srcptr != &s->cirrus_bltbuf[0]
+        || s->cirrus_srcptr_end != &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
+    s->cirrus_srccounter = 0;
+    if (!need_update)
+        return;
+    cirrus_update_memory_access(s);
+}
+
+static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
+{
+    int w;
+
+    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
+    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
+
+    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+	if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+	    s->cirrus_blt_srcpitch = 8;
+	} else {
+            /* XXX: check for 24 bpp */
+	    s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
+	}
+	s->cirrus_srccounter = s->cirrus_blt_srcpitch;
+    } else {
+	if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+            w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
+            if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
+                s->cirrus_blt_srcpitch = ((w + 31) >> 5);
+            else
+                s->cirrus_blt_srcpitch = ((w + 7) >> 3);
+	} else {
+            /* always align input size to 32 bits */
+	    s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
+	}
+        s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
+    }
+    s->cirrus_srcptr = s->cirrus_bltbuf;
+    s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+    cirrus_update_memory_access(s);
+    return 1;
+}
+
+static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
+{
+    /* XXX */
+#ifdef DEBUG_BITBLT
+    printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
+#endif
+    return 0;
+}
+
+static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
+{
+    int ret;
+
+    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+	ret = cirrus_bitblt_videotovideo_patterncopy(s);
+    } else {
+	ret = cirrus_bitblt_videotovideo_copy(s);
+    }
+    if (ret)
+	cirrus_bitblt_reset(s);
+    return ret;
+}
+
+static void cirrus_bitblt_start(CirrusVGAState * s)
+{
+    uint8_t blt_rop;
+
+    s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
+
+    s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
+    s->cirrus_blt_height = (s->vga.gr[0x22] | (s->vga.gr[0x23] << 8)) + 1;
+    s->cirrus_blt_dstpitch = (s->vga.gr[0x24] | (s->vga.gr[0x25] << 8));
+    s->cirrus_blt_srcpitch = (s->vga.gr[0x26] | (s->vga.gr[0x27] << 8));
+    s->cirrus_blt_dstaddr =
+	(s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16));
+    s->cirrus_blt_srcaddr =
+	(s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16));
+    s->cirrus_blt_mode = s->vga.gr[0x30];
+    s->cirrus_blt_modeext = s->vga.gr[0x33];
+    blt_rop = s->vga.gr[0x32];
+
+#ifdef DEBUG_BITBLT
+    printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
+           blt_rop,
+           s->cirrus_blt_mode,
+           s->cirrus_blt_modeext,
+           s->cirrus_blt_width,
+           s->cirrus_blt_height,
+           s->cirrus_blt_dstpitch,
+           s->cirrus_blt_srcpitch,
+           s->cirrus_blt_dstaddr,
+           s->cirrus_blt_srcaddr,
+           s->vga.gr[0x2f]);
+#endif
+
+    switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
+    case CIRRUS_BLTMODE_PIXELWIDTH8:
+	s->cirrus_blt_pixelwidth = 1;
+	break;
+    case CIRRUS_BLTMODE_PIXELWIDTH16:
+	s->cirrus_blt_pixelwidth = 2;
+	break;
+    case CIRRUS_BLTMODE_PIXELWIDTH24:
+	s->cirrus_blt_pixelwidth = 3;
+	break;
+    case CIRRUS_BLTMODE_PIXELWIDTH32:
+	s->cirrus_blt_pixelwidth = 4;
+	break;
+    default:
+#ifdef DEBUG_BITBLT
+	printf("cirrus: bitblt - pixel width is unknown\n");
+#endif
+	goto bitblt_ignore;
+    }
+    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
+
+    if ((s->
+	 cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
+			    CIRRUS_BLTMODE_MEMSYSDEST))
+	== (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
+#ifdef DEBUG_BITBLT
+	printf("cirrus: bitblt - memory-to-memory copy is requested\n");
+#endif
+	goto bitblt_ignore;
+    }
+
+    if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
+        (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
+                               CIRRUS_BLTMODE_TRANSPARENTCOMP |
+                               CIRRUS_BLTMODE_PATTERNCOPY |
+                               CIRRUS_BLTMODE_COLOREXPAND)) ==
+         (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
+        cirrus_bitblt_fgcol(s);
+        cirrus_bitblt_solidfill(s, blt_rop);
+    } else {
+        if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
+                                   CIRRUS_BLTMODE_PATTERNCOPY)) ==
+            CIRRUS_BLTMODE_COLOREXPAND) {
+
+            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+                if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
+                    cirrus_bitblt_bgcol(s);
+                else
+                    cirrus_bitblt_fgcol(s);
+                s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            } else {
+                cirrus_bitblt_fgcol(s);
+                cirrus_bitblt_bgcol(s);
+                s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            }
+        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+                if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+                    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
+                        cirrus_bitblt_bgcol(s);
+                    else
+                        cirrus_bitblt_fgcol(s);
+                    s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+                } else {
+                    cirrus_bitblt_fgcol(s);
+                    cirrus_bitblt_bgcol(s);
+                    s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+                }
+            } else {
+                s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            }
+        } else {
+	    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+		if (s->cirrus_blt_pixelwidth > 2) {
+		    printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
+		    goto bitblt_ignore;
+		}
+		if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+		    s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+		    s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+		    s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+		} else {
+		    s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+		}
+	    } else {
+		if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+		    s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+		    s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+		    s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
+		} else {
+		    s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
+		}
+	    }
+	}
+        // setup bitblt engine.
+        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
+            if (!cirrus_bitblt_cputovideo(s))
+                goto bitblt_ignore;
+        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
+            if (!cirrus_bitblt_videotocpu(s))
+                goto bitblt_ignore;
+        } else {
+            if (!cirrus_bitblt_videotovideo(s))
+                goto bitblt_ignore;
+        }
+    }
+    return;
+  bitblt_ignore:;
+    cirrus_bitblt_reset(s);
+}
+
+static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
+{
+    unsigned old_value;
+
+    old_value = s->vga.gr[0x31];
+    s->vga.gr[0x31] = reg_value;
+
+    if (((old_value & CIRRUS_BLT_RESET) != 0) &&
+	((reg_value & CIRRUS_BLT_RESET) == 0)) {
+	cirrus_bitblt_reset(s);
+    } else if (((old_value & CIRRUS_BLT_START) == 0) &&
+	       ((reg_value & CIRRUS_BLT_START) != 0)) {
+	cirrus_bitblt_start(s);
+    }
+}
+
+
+/***************************************
+ *
+ *  basic parameters
+ *
+ ***************************************/
+
+static void cirrus_get_offsets(VGACommonState *s1,
+                               uint32_t *pline_offset,
+                               uint32_t *pstart_addr,
+                               uint32_t *pline_compare)
+{
+    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
+    uint32_t start_addr, line_offset, line_compare;
+
+    line_offset = s->vga.cr[0x13]
+	| ((s->vga.cr[0x1b] & 0x10) << 4);
+    line_offset <<= 3;
+    *pline_offset = line_offset;
+
+    start_addr = (s->vga.cr[0x0c] << 8)
+	| s->vga.cr[0x0d]
+	| ((s->vga.cr[0x1b] & 0x01) << 16)
+	| ((s->vga.cr[0x1b] & 0x0c) << 15)
+	| ((s->vga.cr[0x1d] & 0x80) << 12);
+    *pstart_addr = start_addr;
+
+    line_compare = s->vga.cr[0x18] |
+        ((s->vga.cr[0x07] & 0x10) << 4) |
+        ((s->vga.cr[0x09] & 0x40) << 3);
+    *pline_compare = line_compare;
+}
+
+static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
+{
+    uint32_t ret = 16;
+
+    switch (s->cirrus_hidden_dac_data & 0xf) {
+    case 0:
+	ret = 15;
+	break;			/* Sierra HiColor */
+    case 1:
+	ret = 16;
+	break;			/* XGA HiColor */
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: invalid DAC value %x in 16bpp\n",
+	       (s->cirrus_hidden_dac_data & 0xf));
+#endif
+	ret = 15;		/* XXX */
+	break;
+    }
+    return ret;
+}
+
+static int cirrus_get_bpp(VGACommonState *s1)
+{
+    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
+    uint32_t ret = 8;
+
+    if ((s->vga.sr[0x07] & 0x01) != 0) {
+	/* Cirrus SVGA */
+	switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) {
+	case CIRRUS_SR7_BPP_8:
+	    ret = 8;
+	    break;
+	case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
+	    ret = cirrus_get_bpp16_depth(s);
+	    break;
+	case CIRRUS_SR7_BPP_24:
+	    ret = 24;
+	    break;
+	case CIRRUS_SR7_BPP_16:
+	    ret = cirrus_get_bpp16_depth(s);
+	    break;
+	case CIRRUS_SR7_BPP_32:
+	    ret = 32;
+	    break;
+	default:
+#ifdef DEBUG_CIRRUS
+	    printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]);
+#endif
+	    ret = 8;
+	    break;
+	}
+    } else {
+	/* VGA */
+	ret = 0;
+    }
+
+    return ret;
+}
+
+static void cirrus_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+    width = (s->cr[0x01] + 1) * 8;
+    height = s->cr[0x12] |
+        ((s->cr[0x07] & 0x02) << 7) |
+        ((s->cr[0x07] & 0x40) << 3);
+    height = (height + 1);
+    /* interlace support */
+    if (s->cr[0x1a] & 0x01)
+        height = height * 2;
+    *pwidth = width;
+    *pheight = height;
+}
+
+/***************************************
+ *
+ * bank memory
+ *
+ ***************************************/
+
+static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
+{
+    unsigned offset;
+    unsigned limit;
+
+    if ((s->vga.gr[0x0b] & 0x01) != 0)	/* dual bank */
+	offset = s->vga.gr[0x09 + bank_index];
+    else			/* single bank */
+	offset = s->vga.gr[0x09];
+
+    if ((s->vga.gr[0x0b] & 0x20) != 0)
+	offset <<= 14;
+    else
+	offset <<= 12;
+
+    if (s->real_vram_size <= offset)
+	limit = 0;
+    else
+	limit = s->real_vram_size - offset;
+
+    if (((s->vga.gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
+	if (limit > 0x8000) {
+	    offset += 0x8000;
+	    limit -= 0x8000;
+	} else {
+	    limit = 0;
+	}
+    }
+
+    if (limit > 0) {
+        /* Thinking about changing bank base? First, drop the dirty bitmap information
+         * on the current location, otherwise we lose this pointer forever */
+        if (s->vga.lfb_vram_mapped) {
+            target_phys_addr_t base_addr = isa_mem_base + 0xa0000 + bank_index * 0x8000;
+            cpu_physical_sync_dirty_bitmap(base_addr, base_addr + 0x8000);
+        }
+	s->cirrus_bank_base[bank_index] = offset;
+	s->cirrus_bank_limit[bank_index] = limit;
+    } else {
+	s->cirrus_bank_base[bank_index] = 0;
+	s->cirrus_bank_limit[bank_index] = 0;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3c4-0x3c5
+ *
+ ***************************************/
+
+static int cirrus_vga_read_sr(CirrusVGAState * s)
+{
+    switch (s->vga.sr_index) {
+    case 0x00:			// Standard VGA
+    case 0x01:			// Standard VGA
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+	return s->vga.sr[s->vga.sr_index];
+    case 0x06:			// Unlock Cirrus extensions
+	return s->vga.sr[s->vga.sr_index];
+    case 0x10:
+    case 0x30:
+    case 0x50:
+    case 0x70:			// Graphics Cursor X
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:			// Graphics Cursor X
+	return s->vga.sr[0x10];
+    case 0x11:
+    case 0x31:
+    case 0x51:
+    case 0x71:			// Graphics Cursor Y
+    case 0x91:
+    case 0xb1:
+    case 0xd1:
+    case 0xf1:			// Graphics Cursor Y
+	return s->vga.sr[0x11];
+    case 0x05:			// ???
+    case 0x07:			// Extended Sequencer Mode
+    case 0x08:			// EEPROM Control
+    case 0x09:			// Scratch Register 0
+    case 0x0a:			// Scratch Register 1
+    case 0x0b:			// VCLK 0
+    case 0x0c:			// VCLK 1
+    case 0x0d:			// VCLK 2
+    case 0x0e:			// VCLK 3
+    case 0x0f:			// DRAM Control
+    case 0x12:			// Graphics Cursor Attribute
+    case 0x13:			// Graphics Cursor Pattern Address
+    case 0x14:			// Scratch Register 2
+    case 0x15:			// Scratch Register 3
+    case 0x16:			// Performance Tuning Register
+    case 0x17:			// Configuration Readback and Extended Control
+    case 0x18:			// Signature Generator Control
+    case 0x19:			// Signal Generator Result
+    case 0x1a:			// Signal Generator Result
+    case 0x1b:			// VCLK 0 Denominator & Post
+    case 0x1c:			// VCLK 1 Denominator & Post
+    case 0x1d:			// VCLK 2 Denominator & Post
+    case 0x1e:			// VCLK 3 Denominator & Post
+    case 0x1f:			// BIOS Write Enable and MCLK select
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index);
+#endif
+	return s->vga.sr[s->vga.sr_index];
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: inport sr_index %02x\n", s->vga.sr_index);
+#endif
+	return 0xff;
+	break;
+    }
+}
+
+static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
+{
+    switch (s->vga.sr_index) {
+    case 0x00:			// Standard VGA
+    case 0x01:			// Standard VGA
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+	s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index];
+	if (s->vga.sr_index == 1)
+            s->vga.update_retrace_info(&s->vga);
+        break;
+    case 0x06:			// Unlock Cirrus extensions
+	val &= 0x17;
+	if (val == 0x12) {
+	    s->vga.sr[s->vga.sr_index] = 0x12;
+	} else {
+	    s->vga.sr[s->vga.sr_index] = 0x0f;
+	}
+	break;
+    case 0x10:
+    case 0x30:
+    case 0x50:
+    case 0x70:			// Graphics Cursor X
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:			// Graphics Cursor X
+	s->vga.sr[0x10] = val;
+	s->hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
+	break;
+    case 0x11:
+    case 0x31:
+    case 0x51:
+    case 0x71:			// Graphics Cursor Y
+    case 0x91:
+    case 0xb1:
+    case 0xd1:
+    case 0xf1:			// Graphics Cursor Y
+	s->vga.sr[0x11] = val;
+	s->hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
+	break;
+    case 0x07:			// Extended Sequencer Mode
+    cirrus_update_memory_access(s);
+    case 0x08:			// EEPROM Control
+    case 0x09:			// Scratch Register 0
+    case 0x0a:			// Scratch Register 1
+    case 0x0b:			// VCLK 0
+    case 0x0c:			// VCLK 1
+    case 0x0d:			// VCLK 2
+    case 0x0e:			// VCLK 3
+    case 0x0f:			// DRAM Control
+    case 0x12:			// Graphics Cursor Attribute
+    case 0x13:			// Graphics Cursor Pattern Address
+    case 0x14:			// Scratch Register 2
+    case 0x15:			// Scratch Register 3
+    case 0x16:			// Performance Tuning Register
+    case 0x18:			// Signature Generator Control
+    case 0x19:			// Signature Generator Result
+    case 0x1a:			// Signature Generator Result
+    case 0x1b:			// VCLK 0 Denominator & Post
+    case 0x1c:			// VCLK 1 Denominator & Post
+    case 0x1d:			// VCLK 2 Denominator & Post
+    case 0x1e:			// VCLK 3 Denominator & Post
+    case 0x1f:			// BIOS Write Enable and MCLK select
+	s->vga.sr[s->vga.sr_index] = val;
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
+	       s->vga.sr_index, val);
+#endif
+	break;
+    case 0x17:			// Configuration Readback and Extended Control
+	s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
+                                   | (val & 0xc7);
+        cirrus_update_memory_access(s);
+        break;
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: outport sr_index %02x, sr_value %02x\n",
+               s->vga.sr_index, val);
+#endif
+	break;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access at 0x3c6
+ *
+ ***************************************/
+
+static int cirrus_read_hidden_dac(CirrusVGAState * s)
+{
+    if (++s->cirrus_hidden_dac_lockindex == 5) {
+        s->cirrus_hidden_dac_lockindex = 0;
+        return s->cirrus_hidden_dac_data;
+    }
+    return 0xff;
+}
+
+static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
+{
+    if (s->cirrus_hidden_dac_lockindex == 4) {
+	s->cirrus_hidden_dac_data = reg_value;
+#if defined(DEBUG_CIRRUS)
+	printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
+#endif
+    }
+    s->cirrus_hidden_dac_lockindex = 0;
+}
+
+/***************************************
+ *
+ *  I/O access at 0x3c9
+ *
+ ***************************************/
+
+static int cirrus_vga_read_palette(CirrusVGAState * s)
+{
+    int val;
+
+    if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
+        val = s->cirrus_hidden_palette[(s->vga.dac_read_index & 0x0f) * 3 +
+                                       s->vga.dac_sub_index];
+    } else {
+        val = s->vga.palette[s->vga.dac_read_index * 3 + s->vga.dac_sub_index];
+    }
+    if (++s->vga.dac_sub_index == 3) {
+	s->vga.dac_sub_index = 0;
+	s->vga.dac_read_index++;
+    }
+    return val;
+}
+
+static void cirrus_vga_write_palette(CirrusVGAState * s, int reg_value)
+{
+    s->vga.dac_cache[s->vga.dac_sub_index] = reg_value;
+    if (++s->vga.dac_sub_index == 3) {
+        if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
+            memcpy(&s->cirrus_hidden_palette[(s->vga.dac_write_index & 0x0f) * 3],
+                   s->vga.dac_cache, 3);
+        } else {
+            memcpy(&s->vga.palette[s->vga.dac_write_index * 3], s->vga.dac_cache, 3);
+        }
+        /* XXX update cursor */
+	s->vga.dac_sub_index = 0;
+	s->vga.dac_write_index++;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3ce-0x3cf
+ *
+ ***************************************/
+
+static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
+{
+    switch (reg_index) {
+    case 0x00: // Standard VGA, BGCOLOR 0x000000ff
+        return s->cirrus_shadow_gr0;
+    case 0x01: // Standard VGA, FGCOLOR 0x000000ff
+        return s->cirrus_shadow_gr1;
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+    case 0x06:			// Standard VGA
+    case 0x07:			// Standard VGA
+    case 0x08:			// Standard VGA
+        return s->vga.gr[s->vga.gr_index];
+    case 0x05:			// Standard VGA, Cirrus extended mode
+    default:
+	break;
+    }
+
+    if (reg_index < 0x3a) {
+	return s->vga.gr[reg_index];
+    } else {
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: inport gr_index %02x\n", reg_index);
+#endif
+	return 0xff;
+    }
+}
+
+static void
+cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
+{
+#if defined(DEBUG_BITBLT) && 0
+    printf("gr%02x: %02x\n", reg_index, reg_value);
+#endif
+    switch (reg_index) {
+    case 0x00:			// Standard VGA, BGCOLOR 0x000000ff
+	s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+	s->cirrus_shadow_gr0 = reg_value;
+	break;
+    case 0x01:			// Standard VGA, FGCOLOR 0x000000ff
+	s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+	s->cirrus_shadow_gr1 = reg_value;
+	break;
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+    case 0x06:			// Standard VGA
+    case 0x07:			// Standard VGA
+    case 0x08:			// Standard VGA
+	s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+        break;
+    case 0x05:			// Standard VGA, Cirrus extended mode
+	s->vga.gr[reg_index] = reg_value & 0x7f;
+        cirrus_update_memory_access(s);
+	break;
+    case 0x09:			// bank offset #0
+    case 0x0A:			// bank offset #1
+	s->vga.gr[reg_index] = reg_value;
+	cirrus_update_bank_ptr(s, 0);
+	cirrus_update_bank_ptr(s, 1);
+        cirrus_update_memory_access(s);
+        break;
+    case 0x0B:
+	s->vga.gr[reg_index] = reg_value;
+	cirrus_update_bank_ptr(s, 0);
+	cirrus_update_bank_ptr(s, 1);
+        cirrus_update_memory_access(s);
+	break;
+    case 0x10:			// BGCOLOR 0x0000ff00
+    case 0x11:			// FGCOLOR 0x0000ff00
+    case 0x12:			// BGCOLOR 0x00ff0000
+    case 0x13:			// FGCOLOR 0x00ff0000
+    case 0x14:			// BGCOLOR 0xff000000
+    case 0x15:			// FGCOLOR 0xff000000
+    case 0x20:			// BLT WIDTH 0x0000ff
+    case 0x22:			// BLT HEIGHT 0x0000ff
+    case 0x24:			// BLT DEST PITCH 0x0000ff
+    case 0x26:			// BLT SRC PITCH 0x0000ff
+    case 0x28:			// BLT DEST ADDR 0x0000ff
+    case 0x29:			// BLT DEST ADDR 0x00ff00
+    case 0x2c:			// BLT SRC ADDR 0x0000ff
+    case 0x2d:			// BLT SRC ADDR 0x00ff00
+    case 0x2f:                  // BLT WRITEMASK
+    case 0x30:			// BLT MODE
+    case 0x32:			// RASTER OP
+    case 0x33:			// BLT MODEEXT
+    case 0x34:			// BLT TRANSPARENT COLOR 0x00ff
+    case 0x35:			// BLT TRANSPARENT COLOR 0xff00
+    case 0x38:			// BLT TRANSPARENT COLOR MASK 0x00ff
+    case 0x39:			// BLT TRANSPARENT COLOR MASK 0xff00
+	s->vga.gr[reg_index] = reg_value;
+	break;
+    case 0x21:			// BLT WIDTH 0x001f00
+    case 0x23:			// BLT HEIGHT 0x001f00
+    case 0x25:			// BLT DEST PITCH 0x001f00
+    case 0x27:			// BLT SRC PITCH 0x001f00
+	s->vga.gr[reg_index] = reg_value & 0x1f;
+	break;
+    case 0x2a:			// BLT DEST ADDR 0x3f0000
+	s->vga.gr[reg_index] = reg_value & 0x3f;
+        /* if auto start mode, starts bit blt now */
+        if (s->vga.gr[0x31] & CIRRUS_BLT_AUTOSTART) {
+            cirrus_bitblt_start(s);
+        }
+	break;
+    case 0x2e:			// BLT SRC ADDR 0x3f0000
+	s->vga.gr[reg_index] = reg_value & 0x3f;
+	break;
+    case 0x31:			// BLT STATUS/START
+	cirrus_write_bitblt(s, reg_value);
+	break;
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
+	       reg_value);
+#endif
+	break;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3d4-0x3d5
+ *
+ ***************************************/
+
+static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index)
+{
+    switch (reg_index) {
+    case 0x00:			// Standard VGA
+    case 0x01:			// Standard VGA
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+    case 0x05:			// Standard VGA
+    case 0x06:			// Standard VGA
+    case 0x07:			// Standard VGA
+    case 0x08:			// Standard VGA
+    case 0x09:			// Standard VGA
+    case 0x0a:			// Standard VGA
+    case 0x0b:			// Standard VGA
+    case 0x0c:			// Standard VGA
+    case 0x0d:			// Standard VGA
+    case 0x0e:			// Standard VGA
+    case 0x0f:			// Standard VGA
+    case 0x10:			// Standard VGA
+    case 0x11:			// Standard VGA
+    case 0x12:			// Standard VGA
+    case 0x13:			// Standard VGA
+    case 0x14:			// Standard VGA
+    case 0x15:			// Standard VGA
+    case 0x16:			// Standard VGA
+    case 0x17:			// Standard VGA
+    case 0x18:			// Standard VGA
+	return s->vga.cr[s->vga.cr_index];
+    case 0x24:			// Attribute Controller Toggle Readback (R)
+        return (s->vga.ar_flip_flop << 7);
+    case 0x19:			// Interlace End
+    case 0x1a:			// Miscellaneous Control
+    case 0x1b:			// Extended Display Control
+    case 0x1c:			// Sync Adjust and Genlock
+    case 0x1d:			// Overlay Extended Control
+    case 0x22:			// Graphics Data Latches Readback (R)
+    case 0x25:			// Part Status
+    case 0x27:			// Part ID (R)
+	return s->vga.cr[s->vga.cr_index];
+    case 0x26:			// Attribute Controller Index Readback (R)
+	return s->vga.ar_index & 0x3f;
+	break;
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: inport cr_index %02x\n", reg_index);
+#endif
+	return 0xff;
+    }
+}
+
+static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value)
+{
+    switch (s->vga.cr_index) {
+    case 0x00:			// Standard VGA
+    case 0x01:			// Standard VGA
+    case 0x02:			// Standard VGA
+    case 0x03:			// Standard VGA
+    case 0x04:			// Standard VGA
+    case 0x05:			// Standard VGA
+    case 0x06:			// Standard VGA
+    case 0x07:			// Standard VGA
+    case 0x08:			// Standard VGA
+    case 0x09:			// Standard VGA
+    case 0x0a:			// Standard VGA
+    case 0x0b:			// Standard VGA
+    case 0x0c:			// Standard VGA
+    case 0x0d:			// Standard VGA
+    case 0x0e:			// Standard VGA
+    case 0x0f:			// Standard VGA
+    case 0x10:			// Standard VGA
+    case 0x11:			// Standard VGA
+    case 0x12:			// Standard VGA
+    case 0x13:			// Standard VGA
+    case 0x14:			// Standard VGA
+    case 0x15:			// Standard VGA
+    case 0x16:			// Standard VGA
+    case 0x17:			// Standard VGA
+    case 0x18:			// Standard VGA
+	/* handle CR0-7 protection */
+	if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) {
+	    /* can always write bit 4 of CR7 */
+	    if (s->vga.cr_index == 7)
+		s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10);
+	    return;
+	}
+	s->vga.cr[s->vga.cr_index] = reg_value;
+	switch(s->vga.cr_index) {
+	case 0x00:
+	case 0x04:
+	case 0x05:
+	case 0x06:
+	case 0x07:
+	case 0x11:
+	case 0x17:
+	    s->vga.update_retrace_info(&s->vga);
+	    break;
+	}
+        break;
+    case 0x19:			// Interlace End
+    case 0x1a:			// Miscellaneous Control
+    case 0x1b:			// Extended Display Control
+    case 0x1c:			// Sync Adjust and Genlock
+    case 0x1d:			// Overlay Extended Control
+	s->vga.cr[s->vga.cr_index] = reg_value;
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
+	       s->vga.cr_index, reg_value);
+#endif
+	break;
+    case 0x22:			// Graphics Data Latches Readback (R)
+    case 0x24:			// Attribute Controller Toggle Readback (R)
+    case 0x26:			// Attribute Controller Index Readback (R)
+    case 0x27:			// Part ID (R)
+	break;
+    case 0x25:			// Part Status
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: outport cr_index %02x, cr_value %02x\n",
+               s->vga.cr_index, reg_value);
+#endif
+	break;
+    }
+}
+
+/***************************************
+ *
+ *  memory-mapped I/O (bitblt)
+ *
+ ***************************************/
+
+static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
+{
+    int value = 0xff;
+
+    switch (address) {
+    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
+	value = cirrus_vga_read_gr(s, 0x00);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
+	value = cirrus_vga_read_gr(s, 0x10);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
+	value = cirrus_vga_read_gr(s, 0x12);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
+	value = cirrus_vga_read_gr(s, 0x14);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
+	value = cirrus_vga_read_gr(s, 0x01);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
+	value = cirrus_vga_read_gr(s, 0x11);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
+	value = cirrus_vga_read_gr(s, 0x13);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
+	value = cirrus_vga_read_gr(s, 0x15);
+	break;
+    case (CIRRUS_MMIO_BLTWIDTH + 0):
+	value = cirrus_vga_read_gr(s, 0x20);
+	break;
+    case (CIRRUS_MMIO_BLTWIDTH + 1):
+	value = cirrus_vga_read_gr(s, 0x21);
+	break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 0):
+	value = cirrus_vga_read_gr(s, 0x22);
+	break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 1):
+	value = cirrus_vga_read_gr(s, 0x23);
+	break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
+	value = cirrus_vga_read_gr(s, 0x24);
+	break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
+	value = cirrus_vga_read_gr(s, 0x25);
+	break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
+	value = cirrus_vga_read_gr(s, 0x26);
+	break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
+	value = cirrus_vga_read_gr(s, 0x27);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 0):
+	value = cirrus_vga_read_gr(s, 0x28);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 1):
+	value = cirrus_vga_read_gr(s, 0x29);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 2):
+	value = cirrus_vga_read_gr(s, 0x2a);
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 0):
+	value = cirrus_vga_read_gr(s, 0x2c);
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 1):
+	value = cirrus_vga_read_gr(s, 0x2d);
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 2):
+	value = cirrus_vga_read_gr(s, 0x2e);
+	break;
+    case CIRRUS_MMIO_BLTWRITEMASK:
+	value = cirrus_vga_read_gr(s, 0x2f);
+	break;
+    case CIRRUS_MMIO_BLTMODE:
+	value = cirrus_vga_read_gr(s, 0x30);
+	break;
+    case CIRRUS_MMIO_BLTROP:
+	value = cirrus_vga_read_gr(s, 0x32);
+	break;
+    case CIRRUS_MMIO_BLTMODEEXT:
+	value = cirrus_vga_read_gr(s, 0x33);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
+	value = cirrus_vga_read_gr(s, 0x34);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
+	value = cirrus_vga_read_gr(s, 0x35);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
+	value = cirrus_vga_read_gr(s, 0x38);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
+	value = cirrus_vga_read_gr(s, 0x39);
+	break;
+    case CIRRUS_MMIO_BLTSTATUS:
+	value = cirrus_vga_read_gr(s, 0x31);
+	break;
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: mmio read - address 0x%04x\n", address);
+#endif
+	break;
+    }
+
+    return (uint8_t) value;
+}
+
+static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
+				  uint8_t value)
+{
+    switch (address) {
+    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
+	cirrus_vga_write_gr(s, 0x00, value);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
+	cirrus_vga_write_gr(s, 0x10, value);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
+	cirrus_vga_write_gr(s, 0x12, value);
+	break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
+	cirrus_vga_write_gr(s, 0x14, value);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
+	cirrus_vga_write_gr(s, 0x01, value);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
+	cirrus_vga_write_gr(s, 0x11, value);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
+	cirrus_vga_write_gr(s, 0x13, value);
+	break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
+	cirrus_vga_write_gr(s, 0x15, value);
+	break;
+    case (CIRRUS_MMIO_BLTWIDTH + 0):
+	cirrus_vga_write_gr(s, 0x20, value);
+	break;
+    case (CIRRUS_MMIO_BLTWIDTH + 1):
+	cirrus_vga_write_gr(s, 0x21, value);
+	break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 0):
+	cirrus_vga_write_gr(s, 0x22, value);
+	break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 1):
+	cirrus_vga_write_gr(s, 0x23, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
+	cirrus_vga_write_gr(s, 0x24, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
+	cirrus_vga_write_gr(s, 0x25, value);
+	break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
+	cirrus_vga_write_gr(s, 0x26, value);
+	break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
+	cirrus_vga_write_gr(s, 0x27, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 0):
+	cirrus_vga_write_gr(s, 0x28, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 1):
+	cirrus_vga_write_gr(s, 0x29, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 2):
+	cirrus_vga_write_gr(s, 0x2a, value);
+	break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 3):
+	/* ignored */
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 0):
+	cirrus_vga_write_gr(s, 0x2c, value);
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 1):
+	cirrus_vga_write_gr(s, 0x2d, value);
+	break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 2):
+	cirrus_vga_write_gr(s, 0x2e, value);
+	break;
+    case CIRRUS_MMIO_BLTWRITEMASK:
+	cirrus_vga_write_gr(s, 0x2f, value);
+	break;
+    case CIRRUS_MMIO_BLTMODE:
+	cirrus_vga_write_gr(s, 0x30, value);
+	break;
+    case CIRRUS_MMIO_BLTROP:
+	cirrus_vga_write_gr(s, 0x32, value);
+	break;
+    case CIRRUS_MMIO_BLTMODEEXT:
+	cirrus_vga_write_gr(s, 0x33, value);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
+	cirrus_vga_write_gr(s, 0x34, value);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
+	cirrus_vga_write_gr(s, 0x35, value);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
+	cirrus_vga_write_gr(s, 0x38, value);
+	break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
+	cirrus_vga_write_gr(s, 0x39, value);
+	break;
+    case CIRRUS_MMIO_BLTSTATUS:
+	cirrus_vga_write_gr(s, 0x31, value);
+	break;
+    default:
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
+	       address, value);
+#endif
+	break;
+    }
+}
+
+/***************************************
+ *
+ *  write mode 4/5
+ *
+ * assume TARGET_PAGE_SIZE >= 16
+ *
+ ***************************************/
+
+static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
+					     unsigned mode,
+					     unsigned offset,
+					     uint32_t mem_value)
+{
+    int x;
+    unsigned val = mem_value;
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
+    for (x = 0; x < 8; x++) {
+	if (val & 0x80) {
+	    *dst = s->cirrus_shadow_gr1;
+	} else if (mode == 5) {
+	    *dst = s->cirrus_shadow_gr0;
+	}
+	val <<= 1;
+	dst++;
+    }
+    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
+    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 7);
+}
+
+static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
+					      unsigned mode,
+					      unsigned offset,
+					      uint32_t mem_value)
+{
+    int x;
+    unsigned val = mem_value;
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
+    for (x = 0; x < 8; x++) {
+	if (val & 0x80) {
+	    *dst = s->cirrus_shadow_gr1;
+	    *(dst + 1) = s->vga.gr[0x11];
+	} else if (mode == 5) {
+	    *dst = s->cirrus_shadow_gr0;
+	    *(dst + 1) = s->vga.gr[0x10];
+	}
+	val <<= 1;
+	dst += 2;
+    }
+    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
+    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 15);
+}
+
+/***************************************
+ *
+ *  memory access between 0xa0000-0xbffff
+ *
+ ***************************************/
+
+static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    CirrusVGAState *s = opaque;
+    unsigned bank_index;
+    unsigned bank_offset;
+    uint32_t val;
+
+    if ((s->vga.sr[0x07] & 0x01) == 0) {
+	return vga_mem_readb(s, addr);
+    }
+
+    addr &= 0x1ffff;
+
+    if (addr < 0x10000) {
+	/* XXX handle bitblt */
+	/* video memory */
+	bank_index = addr >> 15;
+	bank_offset = addr & 0x7fff;
+	if (bank_offset < s->cirrus_bank_limit[bank_index]) {
+	    bank_offset += s->cirrus_bank_base[bank_index];
+	    if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+		bank_offset <<= 4;
+	    } else if (s->vga.gr[0x0B] & 0x02) {
+		bank_offset <<= 3;
+	    }
+	    bank_offset &= s->cirrus_addr_mask;
+	    val = *(s->vga.vram_ptr + bank_offset);
+	} else
+	    val = 0xff;
+    } else if (addr >= 0x18000 && addr < 0x18100) {
+	/* memory-mapped I/O */
+	val = 0xff;
+	if ((s->vga.sr[0x17] & 0x44) == 0x04) {
+	    val = cirrus_mmio_blt_read(s, addr & 0xff);
+	}
+    } else {
+	val = 0xff;
+#ifdef DEBUG_CIRRUS
+	printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr);
+#endif
+    }
+    return val;
+}
+
+static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_vga_mem_readb(opaque, addr);
+    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_vga_mem_readb(opaque, addr);
+    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
+    v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
+    v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                  uint32_t mem_value)
+{
+    CirrusVGAState *s = opaque;
+    unsigned bank_index;
+    unsigned bank_offset;
+    unsigned mode;
+
+    if ((s->vga.sr[0x07] & 0x01) == 0) {
+	vga_mem_writeb(s, addr, mem_value);
+        return;
+    }
+
+    addr &= 0x1ffff;
+
+    if (addr < 0x10000) {
+	if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+	    /* bitblt */
+	    *s->cirrus_srcptr++ = (uint8_t) mem_value;
+	    if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+		cirrus_bitblt_cputovideo_next(s);
+	    }
+	} else {
+	    /* video memory */
+	    bank_index = addr >> 15;
+	    bank_offset = addr & 0x7fff;
+	    if (bank_offset < s->cirrus_bank_limit[bank_index]) {
+		bank_offset += s->cirrus_bank_base[bank_index];
+		if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+		    bank_offset <<= 4;
+		} else if (s->vga.gr[0x0B] & 0x02) {
+		    bank_offset <<= 3;
+		}
+		bank_offset &= s->cirrus_addr_mask;
+		mode = s->vga.gr[0x05] & 0x7;
+		if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
+		    *(s->vga.vram_ptr + bank_offset) = mem_value;
+		    cpu_physical_memory_set_dirty(s->vga.vram_offset +
+						  bank_offset);
+		} else {
+		    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
+			cirrus_mem_writeb_mode4and5_8bpp(s, mode,
+							 bank_offset,
+							 mem_value);
+		    } else {
+			cirrus_mem_writeb_mode4and5_16bpp(s, mode,
+							  bank_offset,
+							  mem_value);
+		    }
+		}
+	    }
+	}
+    } else if (addr >= 0x18000 && addr < 0x18100) {
+	/* memory-mapped I/O */
+	if ((s->vga.sr[0x17] & 0x44) == 0x04) {
+	    cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
+	}
+    } else {
+#ifdef DEBUG_CIRRUS
+        printf("cirrus: mem_writeb " TARGET_FMT_plx " value %02x\n", addr,
+               mem_value);
+#endif
+    }
+}
+
+static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
+    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
+    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = {
+    cirrus_vga_mem_readb,
+    cirrus_vga_mem_readw,
+    cirrus_vga_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const cirrus_vga_mem_write[3] = {
+    cirrus_vga_mem_writeb,
+    cirrus_vga_mem_writew,
+    cirrus_vga_mem_writel,
+};
+
+/***************************************
+ *
+ *  hardware cursor
+ *
+ ***************************************/
+
+static inline void invalidate_cursor1(CirrusVGAState *s)
+{
+    if (s->last_hw_cursor_size) {
+        vga_invalidate_scanlines(&s->vga,
+                                 s->last_hw_cursor_y + s->last_hw_cursor_y_start,
+                                 s->last_hw_cursor_y + s->last_hw_cursor_y_end);
+    }
+}
+
+static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
+{
+    const uint8_t *src;
+    uint32_t content;
+    int y, y_min, y_max;
+
+    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        src += (s->vga.sr[0x13] & 0x3c) * 256;
+        y_min = 64;
+        y_max = -1;
+        for(y = 0; y < 64; y++) {
+            content = ((uint32_t *)src)[0] |
+                ((uint32_t *)src)[1] |
+                ((uint32_t *)src)[2] |
+                ((uint32_t *)src)[3];
+            if (content) {
+                if (y < y_min)
+                    y_min = y;
+                if (y > y_max)
+                    y_max = y;
+            }
+            src += 16;
+        }
+    } else {
+        src += (s->vga.sr[0x13] & 0x3f) * 256;
+        y_min = 32;
+        y_max = -1;
+        for(y = 0; y < 32; y++) {
+            content = ((uint32_t *)src)[0] |
+                ((uint32_t *)(src + 128))[0];
+            if (content) {
+                if (y < y_min)
+                    y_min = y;
+                if (y > y_max)
+                    y_max = y;
+            }
+            src += 4;
+        }
+    }
+    if (y_min > y_max) {
+        s->last_hw_cursor_y_start = 0;
+        s->last_hw_cursor_y_end = 0;
+    } else {
+        s->last_hw_cursor_y_start = y_min;
+        s->last_hw_cursor_y_end = y_max + 1;
+    }
+}
+
+/* NOTE: we do not currently handle the cursor bitmap change, so we
+   update the cursor only if it moves. */
+static void cirrus_cursor_invalidate(VGACommonState *s1)
+{
+    CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
+    int size;
+
+    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW)) {
+        size = 0;
+    } else {
+        if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE)
+            size = 64;
+        else
+            size = 32;
+    }
+    /* invalidate last cursor and new cursor if any change */
+    if (s->last_hw_cursor_size != size ||
+        s->last_hw_cursor_x != s->hw_cursor_x ||
+        s->last_hw_cursor_y != s->hw_cursor_y) {
+
+        invalidate_cursor1(s);
+
+        s->last_hw_cursor_size = size;
+        s->last_hw_cursor_x = s->hw_cursor_x;
+        s->last_hw_cursor_y = s->hw_cursor_y;
+        /* compute the real cursor min and max y */
+        cirrus_cursor_compute_yrange(s);
+        invalidate_cursor1(s);
+    }
+}
+
+static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
+{
+    CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
+    int w, h, bpp, x1, x2, poffset;
+    unsigned int color0, color1;
+    const uint8_t *palette, *src;
+    uint32_t content;
+
+    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW))
+        return;
+    /* fast test to see if the cursor intersects with the scan line */
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        h = 64;
+    } else {
+        h = 32;
+    }
+    if (scr_y < s->hw_cursor_y ||
+        scr_y >= (s->hw_cursor_y + h))
+        return;
+
+    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        src += (s->vga.sr[0x13] & 0x3c) * 256;
+        src += (scr_y - s->hw_cursor_y) * 16;
+        poffset = 8;
+        content = ((uint32_t *)src)[0] |
+            ((uint32_t *)src)[1] |
+            ((uint32_t *)src)[2] |
+            ((uint32_t *)src)[3];
+    } else {
+        src += (s->vga.sr[0x13] & 0x3f) * 256;
+        src += (scr_y - s->hw_cursor_y) * 4;
+        poffset = 128;
+        content = ((uint32_t *)src)[0] |
+            ((uint32_t *)(src + 128))[0];
+    }
+    /* if nothing to draw, no need to continue */
+    if (!content)
+        return;
+    w = h;
+
+    x1 = s->hw_cursor_x;
+    if (x1 >= s->vga.last_scr_width)
+        return;
+    x2 = s->hw_cursor_x + w;
+    if (x2 > s->vga.last_scr_width)
+        x2 = s->vga.last_scr_width;
+    w = x2 - x1;
+    palette = s->cirrus_hidden_palette;
+    color0 = s->vga.rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
+                                 c6_to_8(palette[0x0 * 3 + 1]),
+                                 c6_to_8(palette[0x0 * 3 + 2]));
+    color1 = s->vga.rgb_to_pixel(c6_to_8(palette[0xf * 3]),
+                                 c6_to_8(palette[0xf * 3 + 1]),
+                                 c6_to_8(palette[0xf * 3 + 2]));
+    bpp = ((ds_get_bits_per_pixel(s->vga.ds) + 7) >> 3);
+    d1 += x1 * bpp;
+    switch(ds_get_bits_per_pixel(s->vga.ds)) {
+    default:
+        break;
+    case 8:
+        vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
+        break;
+    case 15:
+        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
+        break;
+    case 16:
+        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
+        break;
+    case 32:
+        vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
+        break;
+    }
+}
+
+/***************************************
+ *
+ *  LFB memory access
+ *
+ ***************************************/
+
+static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
+{
+    CirrusVGAState *s = opaque;
+    uint32_t ret;
+
+    addr &= s->cirrus_addr_mask;
+
+    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
+        ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
+	/* memory-mapped I/O */
+	ret = cirrus_mmio_blt_read(s, addr & 0xff);
+    } else if (0) {
+	/* XXX handle bitblt */
+	ret = 0xff;
+    } else {
+	/* video memory */
+	if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+	    addr <<= 4;
+	} else if (s->vga.gr[0x0B] & 0x02) {
+	    addr <<= 3;
+	}
+	addr &= s->cirrus_addr_mask;
+	ret = *(s->vga.vram_ptr + addr);
+    }
+
+    return ret;
+}
+
+static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_linear_readb(opaque, addr);
+    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_linear_readb(opaque, addr);
+    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
+    v |= cirrus_linear_readb(opaque, addr + 2) << 16;
+    v |= cirrus_linear_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    CirrusVGAState *s = opaque;
+    unsigned mode;
+
+    addr &= s->cirrus_addr_mask;
+
+    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
+        ((addr & s->linear_mmio_mask) ==  s->linear_mmio_mask)) {
+	/* memory-mapped I/O */
+	cirrus_mmio_blt_write(s, addr & 0xff, val);
+    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+	/* bitblt */
+	*s->cirrus_srcptr++ = (uint8_t) val;
+	if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+	    cirrus_bitblt_cputovideo_next(s);
+	}
+    } else {
+	/* video memory */
+	if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+	    addr <<= 4;
+	} else if (s->vga.gr[0x0B] & 0x02) {
+	    addr <<= 3;
+	}
+	addr &= s->cirrus_addr_mask;
+
+	mode = s->vga.gr[0x05] & 0x7;
+	if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
+	    *(s->vga.vram_ptr + addr) = (uint8_t) val;
+	    cpu_physical_memory_set_dirty(s->vga.vram_offset + addr);
+	} else {
+	    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
+		cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
+	    } else {
+		cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
+	    }
+	}
+    }
+}
+
+static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    cirrus_linear_writeb(opaque, addr, val & 0xff);
+    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    cirrus_linear_writeb(opaque, addr, val & 0xff);
+    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+
+static CPUReadMemoryFunc * const cirrus_linear_read[3] = {
+    cirrus_linear_readb,
+    cirrus_linear_readw,
+    cirrus_linear_readl,
+};
+
+static CPUWriteMemoryFunc * const cirrus_linear_write[3] = {
+    cirrus_linear_writeb,
+    cirrus_linear_writew,
+    cirrus_linear_writel,
+};
+
+/***************************************
+ *
+ *  system to screen memory access
+ *
+ ***************************************/
+
+
+static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    /* XXX handle bitblt */
+    ret = 0xff;
+    return ret;
+}
+
+static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_linear_bitblt_readb(opaque, addr);
+    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_linear_bitblt_readb(opaque, addr);
+    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
+    v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
+    v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    CirrusVGAState *s = opaque;
+
+    if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+	/* bitblt */
+	*s->cirrus_srcptr++ = (uint8_t) val;
+	if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+	    cirrus_bitblt_cputovideo_next(s);
+	}
+    }
+}
+
+static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
+    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
+				 uint32_t val)
+{
+    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
+    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+
+static CPUReadMemoryFunc * const cirrus_linear_bitblt_read[3] = {
+    cirrus_linear_bitblt_readb,
+    cirrus_linear_bitblt_readw,
+    cirrus_linear_bitblt_readl,
+};
+
+static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = {
+    cirrus_linear_bitblt_writeb,
+    cirrus_linear_bitblt_writew,
+    cirrus_linear_bitblt_writel,
+};
+
+static void map_linear_vram(CirrusVGAState *s)
+{
+    if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
+        s->vga.map_addr = s->vga.lfb_addr;
+        s->vga.map_end = s->vga.lfb_end;
+        cpu_register_physical_memory_log(s->vga.map_addr,
+					 s->vga.map_end - s->vga.map_addr,
+					 s->vga.vram_offset, 0, true);
+    }
+
+    if (!s->vga.map_addr)
+        return;
+
+    s->vga.lfb_vram_mapped = 0;
+
+    if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
+        && !((s->vga.sr[0x07] & 0x01) == 0)
+        && !((s->vga.gr[0x0B] & 0x14) == 0x14)
+        && !(s->vga.gr[0x0B] & 0x02)) {
+
+        cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
+					 (s->vga.vram_offset +
+					  s->cirrus_bank_base[0]) |
+					 IO_MEM_RAM, 0, true);
+        cpu_register_physical_memory_log(isa_mem_base + 0xa8000, 0x8000,
+					 (s->vga.vram_offset +
+					  s->cirrus_bank_base[1]) |
+					 IO_MEM_RAM, 0, true);
+
+        s->vga.lfb_vram_mapped = 1;
+    }
+    else {
+        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
+                                     s->vga.vga_io_memory);
+    }
+
+    vga_dirty_log_start(&s->vga);
+}
+
+static void unmap_linear_vram(CirrusVGAState *s)
+{
+    if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
+        s->vga.map_addr = s->vga.map_end = 0;
+         cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
+                                      s->cirrus_linear_io_addr);
+    }
+    cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
+                                 s->vga.vga_io_memory);
+}
+
+/* Compute the memory access functions */
+static void cirrus_update_memory_access(CirrusVGAState *s)
+{
+    unsigned mode;
+
+    if ((s->vga.sr[0x17] & 0x44) == 0x44) {
+        goto generic_io;
+    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+        goto generic_io;
+    } else {
+	if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+            goto generic_io;
+	} else if (s->vga.gr[0x0B] & 0x02) {
+            goto generic_io;
+        }
+
+	mode = s->vga.gr[0x05] & 0x7;
+	if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
+            map_linear_vram(s);
+        } else {
+        generic_io:
+            unmap_linear_vram(s);
+        }
+    }
+}
+
+
+/* I/O ports */
+
+static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr)
+{
+    CirrusVGAState *c = opaque;
+    VGACommonState *s = &c->vga;
+    int val, index;
+
+    if (vga_ioport_invalid(s, addr)) {
+	val = 0xff;
+    } else {
+	switch (addr) {
+	case 0x3c0:
+	    if (s->ar_flip_flop == 0) {
+		val = s->ar_index;
+	    } else {
+		val = 0;
+	    }
+	    break;
+	case 0x3c1:
+	    index = s->ar_index & 0x1f;
+	    if (index < 21)
+		val = s->ar[index];
+	    else
+		val = 0;
+	    break;
+	case 0x3c2:
+	    val = s->st00;
+	    break;
+	case 0x3c4:
+	    val = s->sr_index;
+	    break;
+	case 0x3c5:
+	    val = cirrus_vga_read_sr(c);
+            break;
+#ifdef DEBUG_VGA_REG
+	    printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+	    break;
+	case 0x3c6:
+	    val = cirrus_read_hidden_dac(c);
+	    break;
+	case 0x3c7:
+	    val = s->dac_state;
+	    break;
+	case 0x3c8:
+	    val = s->dac_write_index;
+	    c->cirrus_hidden_dac_lockindex = 0;
+	    break;
+        case 0x3c9:
+            val = cirrus_vga_read_palette(c);
+            break;
+	case 0x3ca:
+	    val = s->fcr;
+	    break;
+	case 0x3cc:
+	    val = s->msr;
+	    break;
+	case 0x3ce:
+	    val = s->gr_index;
+	    break;
+	case 0x3cf:
+	    val = cirrus_vga_read_gr(c, s->gr_index);
+#ifdef DEBUG_VGA_REG
+	    printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+	    break;
+	case 0x3b4:
+	case 0x3d4:
+	    val = s->cr_index;
+	    break;
+	case 0x3b5:
+	case 0x3d5:
+            val = cirrus_vga_read_cr(c, s->cr_index);
+#ifdef DEBUG_VGA_REG
+	    printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+	    break;
+	case 0x3ba:
+	case 0x3da:
+	    /* just toggle to fool polling */
+	    val = s->st01 = s->retrace(s);
+	    s->ar_flip_flop = 0;
+	    break;
+	default:
+	    val = 0x00;
+	    break;
+	}
+    }
+#if defined(DEBUG_VGA)
+    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    CirrusVGAState *c = opaque;
+    VGACommonState *s = &c->vga;
+    int index;
+
+    /* check port range access depending on color/monochrome mode */
+    if (vga_ioport_invalid(s, addr)) {
+	return;
+    }
+#ifdef DEBUG_VGA
+    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+
+    switch (addr) {
+    case 0x3c0:
+	if (s->ar_flip_flop == 0) {
+	    val &= 0x3f;
+	    s->ar_index = val;
+	} else {
+	    index = s->ar_index & 0x1f;
+	    switch (index) {
+	    case 0x00 ... 0x0f:
+		s->ar[index] = val & 0x3f;
+		break;
+	    case 0x10:
+		s->ar[index] = val & ~0x10;
+		break;
+	    case 0x11:
+		s->ar[index] = val;
+		break;
+	    case 0x12:
+		s->ar[index] = val & ~0xc0;
+		break;
+	    case 0x13:
+		s->ar[index] = val & ~0xf0;
+		break;
+	    case 0x14:
+		s->ar[index] = val & ~0xf0;
+		break;
+	    default:
+		break;
+	    }
+	}
+	s->ar_flip_flop ^= 1;
+	break;
+    case 0x3c2:
+	s->msr = val & ~0x10;
+	s->update_retrace_info(s);
+	break;
+    case 0x3c4:
+	s->sr_index = val;
+	break;
+    case 0x3c5:
+#ifdef DEBUG_VGA_REG
+	printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+	cirrus_vga_write_sr(c, val);
+        break;
+	break;
+    case 0x3c6:
+	cirrus_write_hidden_dac(c, val);
+	break;
+    case 0x3c7:
+	s->dac_read_index = val;
+	s->dac_sub_index = 0;
+	s->dac_state = 3;
+	break;
+    case 0x3c8:
+	s->dac_write_index = val;
+	s->dac_sub_index = 0;
+	s->dac_state = 0;
+	break;
+    case 0x3c9:
+        cirrus_vga_write_palette(c, val);
+        break;
+    case 0x3ce:
+	s->gr_index = val;
+	break;
+    case 0x3cf:
+#ifdef DEBUG_VGA_REG
+	printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+	cirrus_vga_write_gr(c, s->gr_index, val);
+	break;
+    case 0x3b4:
+    case 0x3d4:
+	s->cr_index = val;
+	break;
+    case 0x3b5:
+    case 0x3d5:
+#ifdef DEBUG_VGA_REG
+	printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+	cirrus_vga_write_cr(c, val);
+	break;
+    case 0x3ba:
+    case 0x3da:
+	s->fcr = val & 0x10;
+	break;
+    }
+}
+
+/***************************************
+ *
+ *  memory-mapped I/O access
+ *
+ ***************************************/
+
+static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    CirrusVGAState *s = opaque;
+
+    addr &= CIRRUS_PNPMMIO_SIZE - 1;
+
+    if (addr >= 0x100) {
+        return cirrus_mmio_blt_read(s, addr - 0x100);
+    } else {
+        return cirrus_vga_ioport_read(s, addr + 0x3c0);
+    }
+}
+
+static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_mmio_readb(opaque, addr);
+    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+
+    v = cirrus_mmio_readb(opaque, addr);
+    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
+    v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
+    v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
+			       uint32_t val)
+{
+    CirrusVGAState *s = opaque;
+
+    addr &= CIRRUS_PNPMMIO_SIZE - 1;
+
+    if (addr >= 0x100) {
+	cirrus_mmio_blt_write(s, addr - 0x100, val);
+    } else {
+        cirrus_vga_ioport_write(s, addr + 0x3c0, val);
+    }
+}
+
+static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
+			       uint32_t val)
+{
+    cirrus_mmio_writeb(opaque, addr, val & 0xff);
+    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
+			       uint32_t val)
+{
+    cirrus_mmio_writeb(opaque, addr, val & 0xff);
+    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+
+static CPUReadMemoryFunc * const cirrus_mmio_read[3] = {
+    cirrus_mmio_readb,
+    cirrus_mmio_readw,
+    cirrus_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const cirrus_mmio_write[3] = {
+    cirrus_mmio_writeb,
+    cirrus_mmio_writew,
+    cirrus_mmio_writel,
+};
+
+/* load/save state */
+
+static int cirrus_post_load(void *opaque, int version_id)
+{
+    CirrusVGAState *s = opaque;
+
+    s->vga.gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
+    s->vga.gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
+
+    cirrus_update_memory_access(s);
+    /* force refresh */
+    s->vga.graphic_mode = -1;
+    cirrus_update_bank_ptr(s, 0);
+    cirrus_update_bank_ptr(s, 1);
+    return 0;
+}
+
+static const VMStateDescription vmstate_cirrus_vga = {
+    .name = "cirrus_vga",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = cirrus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(vga.latch, CirrusVGAState),
+        VMSTATE_UINT8(vga.sr_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.sr, CirrusVGAState),
+        VMSTATE_UINT8(vga.gr_index, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_shadow_gr0, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_shadow_gr1, CirrusVGAState),
+        VMSTATE_BUFFER_START_MIDDLE(vga.gr, CirrusVGAState, 2),
+        VMSTATE_UINT8(vga.ar_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.ar, CirrusVGAState),
+        VMSTATE_INT32(vga.ar_flip_flop, CirrusVGAState),
+        VMSTATE_UINT8(vga.cr_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.cr, CirrusVGAState),
+        VMSTATE_UINT8(vga.msr, CirrusVGAState),
+        VMSTATE_UINT8(vga.fcr, CirrusVGAState),
+        VMSTATE_UINT8(vga.st00, CirrusVGAState),
+        VMSTATE_UINT8(vga.st01, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_state, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_sub_index, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_read_index, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_write_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.dac_cache, CirrusVGAState),
+        VMSTATE_BUFFER(vga.palette, CirrusVGAState),
+        VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
+        VMSTATE_UINT32(hw_cursor_x, CirrusVGAState),
+        VMSTATE_UINT32(hw_cursor_y, CirrusVGAState),
+        /* XXX: we do not save the bitblt state - we assume we do not save
+           the state when the blitter is active */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_cirrus_vga = {
+    .name = "cirrus_vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCICirrusVGAState),
+        VMSTATE_STRUCT(cirrus_vga, PCICirrusVGAState, 0,
+                       vmstate_cirrus_vga, CirrusVGAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/***************************************
+ *
+ *  initialize
+ *
+ ***************************************/
+
+static void cirrus_reset(void *opaque)
+{
+    CirrusVGAState *s = opaque;
+
+    vga_common_reset(&s->vga);
+    unmap_linear_vram(s);
+    s->vga.sr[0x06] = 0x0f;
+    if (s->device_id == CIRRUS_ID_CLGD5446) {
+        /* 4MB 64 bit memory config, always PCI */
+        s->vga.sr[0x1F] = 0x2d;		// MemClock
+        s->vga.gr[0x18] = 0x0f;             // fastest memory configuration
+        s->vga.sr[0x0f] = 0x98;
+        s->vga.sr[0x17] = 0x20;
+        s->vga.sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
+    } else {
+        s->vga.sr[0x1F] = 0x22;		// MemClock
+        s->vga.sr[0x0F] = CIRRUS_MEMSIZE_2M;
+        s->vga.sr[0x17] = s->bustype;
+        s->vga.sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
+    }
+    s->vga.cr[0x27] = s->device_id;
+
+    /* Win2K seems to assume that the pattern buffer is at 0xff
+       initially ! */
+    memset(s->vga.vram_ptr, 0xff, s->real_vram_size);
+
+    s->cirrus_hidden_dac_lockindex = 5;
+    s->cirrus_hidden_dac_data = 0;
+}
+
+static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
+{
+    int i;
+    static int inited;
+
+    if (!inited) {
+        inited = 1;
+        for(i = 0;i < 256; i++)
+            rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
+        rop_to_index[CIRRUS_ROP_0] = 0;
+        rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
+        rop_to_index[CIRRUS_ROP_NOP] = 2;
+        rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
+        rop_to_index[CIRRUS_ROP_NOTDST] = 4;
+        rop_to_index[CIRRUS_ROP_SRC] = 5;
+        rop_to_index[CIRRUS_ROP_1] = 6;
+        rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
+        rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
+        rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
+        rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
+        rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
+        rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
+        rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
+        rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
+        rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
+        s->device_id = device_id;
+        if (is_pci)
+            s->bustype = CIRRUS_BUSTYPE_PCI;
+        else
+            s->bustype = CIRRUS_BUSTYPE_ISA;
+    }
+
+    register_ioport_write(0x3c0, 16, 1, cirrus_vga_ioport_write, s);
+
+    register_ioport_write(0x3b4, 2, 1, cirrus_vga_ioport_write, s);
+    register_ioport_write(0x3d4, 2, 1, cirrus_vga_ioport_write, s);
+    register_ioport_write(0x3ba, 1, 1, cirrus_vga_ioport_write, s);
+    register_ioport_write(0x3da, 1, 1, cirrus_vga_ioport_write, s);
+
+    register_ioport_read(0x3c0, 16, 1, cirrus_vga_ioport_read, s);
+
+    register_ioport_read(0x3b4, 2, 1, cirrus_vga_ioport_read, s);
+    register_ioport_read(0x3d4, 2, 1, cirrus_vga_ioport_read, s);
+    register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s);
+    register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s);
+
+    s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read,
+                                                  cirrus_vga_mem_write, s,
+                                                  DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
+                                 s->vga.vga_io_memory);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+
+    /* I/O handler for LFB */
+    s->cirrus_linear_io_addr =
+        cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
+                               DEVICE_LITTLE_ENDIAN);
+
+    /* I/O handler for LFB */
+    s->cirrus_linear_bitblt_io_addr =
+        cpu_register_io_memory(cirrus_linear_bitblt_read,
+                               cirrus_linear_bitblt_write, s,
+                               DEVICE_LITTLE_ENDIAN);
+
+    /* I/O handler for memory-mapped I/O */
+    s->cirrus_mmio_io_addr =
+        cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s,
+                               DEVICE_LITTLE_ENDIAN);
+
+    s->real_vram_size =
+        (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
+
+    /* XXX: s->vga.vram_size must be a power of two */
+    s->cirrus_addr_mask = s->real_vram_size - 1;
+    s->linear_mmio_mask = s->real_vram_size - 256;
+
+    s->vga.get_bpp = cirrus_get_bpp;
+    s->vga.get_offsets = cirrus_get_offsets;
+    s->vga.get_resolution = cirrus_get_resolution;
+    s->vga.cursor_invalidate = cirrus_cursor_invalidate;
+    s->vga.cursor_draw_line = cirrus_cursor_draw_line;
+
+    qemu_register_reset(cirrus_reset, s);
+}
+
+/***************************************
+ *
+ *  ISA bus support
+ *
+ ***************************************/
+
+void isa_cirrus_vga_init(void)
+{
+    CirrusVGAState *s;
+
+    s = qemu_mallocz(sizeof(CirrusVGAState));
+
+    vga_common_init(&s->vga, VGA_RAM_SIZE);
+    cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
+    s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
+                                     s->vga.screen_dump, s->vga.text_update,
+                                     &s->vga);
+    vmstate_register(NULL, 0, &vmstate_cirrus_vga, s);
+    rom_add_vga(VGABIOS_CIRRUS_FILENAME);
+    /* XXX ISA-LFB support */
+}
+
+/***************************************
+ *
+ *  PCI bus support
+ *
+ ***************************************/
+
+static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
+			       pcibus_t addr, pcibus_t size, int type)
+{
+    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
+
+    /* XXX: add byte swapping apertures */
+    cpu_register_physical_memory(addr, s->vga.vram_size,
+				 s->cirrus_linear_io_addr);
+    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
+				 s->cirrus_linear_bitblt_io_addr);
+
+    s->vga.map_addr = s->vga.map_end = 0;
+    s->vga.lfb_addr = addr & TARGET_PAGE_MASK;
+    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+    /* account for overflow */
+    if (s->vga.lfb_end < addr + VGA_RAM_SIZE)
+        s->vga.lfb_end = addr + VGA_RAM_SIZE;
+
+    vga_dirty_log_start(&s->vga);
+}
+
+static void pci_cirrus_write_config(PCIDevice *d,
+                                    uint32_t address, uint32_t val, int len)
+{
+    PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
+    CirrusVGAState *s = &pvs->cirrus_vga;
+
+    pci_default_write_config(d, address, val, len);
+    if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED) {
+        s->vga.map_addr = 0;
+        s->vga.lfb_addr = 0;
+        s->vga.lfb_end = 0;
+    }
+    cirrus_update_memory_access(s);
+}
+
+static int pci_cirrus_vga_initfn(PCIDevice *dev)
+{
+     PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
+     CirrusVGAState *s = &d->cirrus_vga;
+     PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
+     int16_t device_id = info->device_id;
+
+     /* setup VGA */
+     vga_common_init(&s->vga, VGA_RAM_SIZE);
+     cirrus_init_common(s, device_id, 1);
+     s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
+                                      s->vga.screen_dump, s->vga.text_update,
+                                      &s->vga);
+
+     /* setup PCI */
+
+     /* setup memory space */
+     /* memory #0 LFB */
+     /* memory #1 memory-mapped I/O */
+     /* XXX: s->vga.vram_size must be a power of two */
+     pci_register_bar(&d->dev, 0, 0x2000000,
+                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
+     if (device_id == CIRRUS_ID_CLGD5446) {
+         pci_register_bar_simple(&d->dev, 1, CIRRUS_PNPMMIO_SIZE, 0,
+                                 s->cirrus_mmio_io_addr);
+     }
+     return 0;
+}
+
+void pci_cirrus_vga_init(PCIBus *bus)
+{
+    pci_create_simple(bus, -1, "cirrus-vga");
+}
+
+static PCIDeviceInfo cirrus_vga_info = {
+    .qdev.name    = "cirrus-vga",
+    .qdev.desc    = "Cirrus CLGD 54xx VGA",
+    .qdev.size    = sizeof(PCICirrusVGAState),
+    .qdev.vmsd    = &vmstate_pci_cirrus_vga,
+    .no_hotplug   = 1,
+    .init         = pci_cirrus_vga_initfn,
+    .romfile      = VGABIOS_CIRRUS_FILENAME,
+    .config_write = pci_cirrus_write_config,
+    .vendor_id    = PCI_VENDOR_ID_CIRRUS,
+    .device_id    = CIRRUS_ID_CLGD5446,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+};
+
+static void cirrus_vga_register(void)
+{
+    pci_qdev_register(&cirrus_vga_info);
+}
+device_init(cirrus_vga_register);
diff --git a/qemu-0.15.x/hw/cirrus_vga_rop.h b/qemu-0.15.x/hw/cirrus_vga_rop.h
new file mode 100644
index 0000000..9c7bb09
--- /dev/null
+++ b/qemu-0.15.x/hw/cirrus_vga_rop.h
@@ -0,0 +1,208 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * 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.
+ */
+
+static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
+#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
+#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#undef ROP_FN
+
+static void
+glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
+                             uint8_t *dst,const uint8_t *src,
+                             int dstpitch,int srcpitch,
+                             int bltwidth,int bltheight)
+{
+    int x,y;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+
+    if (dstpitch < 0 || srcpitch < 0) {
+        /* is 0 valid? srcpitch == 0 could be useful */
+        return;
+    }
+
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+            ROP_OP(dst, *src);
+            dst++;
+            src++;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
+                                        uint8_t *dst,const uint8_t *src,
+                                        int dstpitch,int srcpitch,
+                                        int bltwidth,int bltheight)
+{
+    int x,y;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+            ROP_OP(dst, *src);
+            dst--;
+            src--;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+						       uint8_t *dst,const uint8_t *src,
+						       int dstpitch,int srcpitch,
+						       int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+	    p = *dst;
+            ROP_OP(&p, *src);
+	    if (p != s->vga.gr[0x34]) *dst = p;
+            dst++;
+            src++;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+							uint8_t *dst,const uint8_t *src,
+							int dstpitch,int srcpitch,
+							int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+	    p = *dst;
+            ROP_OP(&p, *src);
+	    if (p != s->vga.gr[0x34]) *dst = p;
+            dst--;
+            src--;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+							uint8_t *dst,const uint8_t *src,
+							int dstpitch,int srcpitch,
+							int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+	    p1 = *dst;
+	    p2 = *(dst+1);
+            ROP_OP(&p1, *src);
+            ROP_OP(&p2, *(src + 1));
+	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
+		*dst = p1;
+		*(dst+1) = p2;
+	    }
+            dst+=2;
+            src+=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+							 uint8_t *dst,const uint8_t *src,
+							 int dstpitch,int srcpitch,
+							 int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+	    p1 = *(dst-1);
+	    p2 = *dst;
+            ROP_OP(&p1, *(src - 1));
+            ROP_OP(&p2, *src);
+	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
+		*(dst-1) = p1;
+		*dst = p2;
+	    }
+            dst-=2;
+            src-=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+#define DEPTH 8
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 16
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 24
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 32
+#include "cirrus_vga_rop2.h"
+
+#undef ROP_NAME
+#undef ROP_OP
+#undef ROP_OP_16
+#undef ROP_OP_32
diff --git a/qemu-0.15.x/hw/cirrus_vga_rop2.h b/qemu-0.15.x/hw/cirrus_vga_rop2.h
new file mode 100644
index 0000000..d28bcc6
--- /dev/null
+++ b/qemu-0.15.x/hw/cirrus_vga_rop2.h
@@ -0,0 +1,281 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * 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.
+ */
+
+#if DEPTH == 8
+#define PUTPIXEL()    ROP_OP(&d[0], col)
+#elif DEPTH == 16
+#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
+#elif DEPTH == 24
+#define PUTPIXEL()    ROP_OP(&d[0], col);        \
+                      ROP_OP(&d[1], (col >> 8)); \
+                      ROP_OP(&d[2], (col >> 16))
+#elif DEPTH == 32
+#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
+#else
+#error unsupported DEPTH
+#endif
+
+static void
+glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y, pattern_y, pattern_pitch, pattern_x;
+    unsigned int col;
+    const uint8_t *src1;
+#if DEPTH == 24
+    int skipleft = s->vga.gr[0x2f] & 0x1f;
+#else
+    int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
+#endif
+
+#if DEPTH == 8
+    pattern_pitch = 8;
+#elif DEPTH == 16
+    pattern_pitch = 16;
+#else
+    pattern_pitch = 32;
+#endif
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+    for(y = 0; y < bltheight; y++) {
+        pattern_x = skipleft;
+        d = dst + skipleft;
+        src1 = src + pattern_y * pattern_pitch;
+        for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
+#if DEPTH == 8
+            col = src1[pattern_x];
+            pattern_x = (pattern_x + 1) & 7;
+#elif DEPTH == 16
+            col = ((uint16_t *)(src1 + pattern_x))[0];
+            pattern_x = (pattern_x + 2) & 15;
+#elif DEPTH == 24
+            {
+                const uint8_t *src2 = src1 + pattern_x * 3;
+                col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
+                pattern_x = (pattern_x + 1) & 7;
+            }
+#else
+            col = ((uint32_t *)(src1 + pattern_x))[0];
+            pattern_x = (pattern_x + 4) & 31;
+#endif
+            PUTPIXEL();
+            d += (DEPTH / 8);
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+/* NOTE: srcpitch is ignored */
+static void
+glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y;
+    unsigned bits, bits_xor;
+    unsigned int col;
+    unsigned bitmask;
+    unsigned index;
+#if DEPTH == 24
+    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
+    int srcskipleft = dstskipleft / 3;
+#else
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+#endif
+
+    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
+        bits_xor = 0xff;
+        col = s->cirrus_blt_bgcol;
+    } else {
+        bits_xor = 0x00;
+        col = s->cirrus_blt_fgcol;
+    }
+
+    for(y = 0; y < bltheight; y++) {
+        bitmask = 0x80 >> srcskipleft;
+        bits = *src++ ^ bits_xor;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bitmask & 0xff) == 0) {
+                bitmask = 0x80;
+                bits = *src++ ^ bits_xor;
+            }
+            index = (bits & bitmask);
+            if (index) {
+                PUTPIXEL();
+            }
+            d += (DEPTH / 8);
+            bitmask >>= 1;
+        }
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint32_t colors[2];
+    uint8_t *d;
+    int x, y;
+    unsigned bits;
+    unsigned int col;
+    unsigned bitmask;
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+
+    colors[0] = s->cirrus_blt_bgcol;
+    colors[1] = s->cirrus_blt_fgcol;
+    for(y = 0; y < bltheight; y++) {
+        bitmask = 0x80 >> srcskipleft;
+        bits = *src++;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bitmask & 0xff) == 0) {
+                bitmask = 0x80;
+                bits = *src++;
+            }
+            col = colors[!!(bits & bitmask)];
+            PUTPIXEL();
+            d += (DEPTH / 8);
+            bitmask >>= 1;
+        }
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y, bitpos, pattern_y;
+    unsigned int bits, bits_xor;
+    unsigned int col;
+#if DEPTH == 24
+    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
+    int srcskipleft = dstskipleft / 3;
+#else
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+#endif
+
+    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
+        bits_xor = 0xff;
+        col = s->cirrus_blt_bgcol;
+    } else {
+        bits_xor = 0x00;
+        col = s->cirrus_blt_fgcol;
+    }
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+
+    for(y = 0; y < bltheight; y++) {
+        bits = src[pattern_y] ^ bits_xor;
+        bitpos = 7 - srcskipleft;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bits >> bitpos) & 1) {
+                PUTPIXEL();
+            }
+            d += (DEPTH / 8);
+            bitpos = (bitpos - 1) & 7;
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint32_t colors[2];
+    uint8_t *d;
+    int x, y, bitpos, pattern_y;
+    unsigned int bits;
+    unsigned int col;
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+
+    colors[0] = s->cirrus_blt_bgcol;
+    colors[1] = s->cirrus_blt_fgcol;
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+
+    for(y = 0; y < bltheight; y++) {
+        bits = src[pattern_y];
+        bitpos = 7 - srcskipleft;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            col = colors[(bits >> bitpos) & 1];
+            PUTPIXEL();
+            d += (DEPTH / 8);
+            bitpos = (bitpos - 1) & 7;
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState *s,
+      uint8_t *dst, int dst_pitch,
+      int width, int height)
+{
+    uint8_t *d, *d1;
+    uint32_t col;
+    int x, y;
+
+    col = s->cirrus_blt_fgcol;
+
+    d1 = dst;
+    for(y = 0; y < height; y++) {
+        d = d1;
+        for(x = 0; x < width; x += (DEPTH / 8)) {
+            PUTPIXEL();
+            d += (DEPTH / 8);
+        }
+        d1 += dst_pitch;
+    }
+}
+
+#undef DEPTH
+#undef PUTPIXEL
diff --git a/qemu-0.15.x/hw/collie.c b/qemu-0.15.x/hw/collie.c
new file mode 100644
index 0000000..156404d
--- /dev/null
+++ b/qemu-0.15.x/hw/collie.c
@@ -0,0 +1,69 @@
+/*
+ * SA-1110-based Sharp Zaurus SL-5500 platform.
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * This code is licensed under GNU GPL v2.
+ */
+#include "hw.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "devices.h"
+#include "strongarm.h"
+#include "arm-misc.h"
+#include "flash.h"
+#include "blockdev.h"
+
+static struct arm_boot_info collie_binfo = {
+    .loader_start = SA_SDCS0,
+    .ram_size = 0x20000000,
+};
+
+static void collie_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    StrongARMState *s;
+    DriveInfo *dinfo;
+    ram_addr_t phys_flash;
+
+    if (!cpu_model) {
+        cpu_model = "sa1110";
+    }
+
+    s = sa1110_init(collie_binfo.ram_size, cpu_model);
+
+    phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(SA_CS0, phys_flash,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000);
+    dinfo = drive_get(IF_PFLASH, 0, 1);
+    pflash_cfi01_register(SA_CS1, phys_flash,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    sysbus_create_simple("scoop", 0x40800000, NULL);
+
+    collie_binfo.kernel_filename = kernel_filename;
+    collie_binfo.kernel_cmdline = kernel_cmdline;
+    collie_binfo.initrd_filename = initrd_filename;
+    collie_binfo.board_id = 0x208;
+    arm_load_kernel(s->env, &collie_binfo);
+}
+
+static QEMUMachine collie_machine = {
+    .name = "collie",
+    .desc = "Collie PDA (SA-1110)",
+    .init = collie_init,
+};
+
+static void collie_machine_init(void)
+{
+    qemu_register_machine(&collie_machine);
+}
+
+machine_init(collie_machine_init)
diff --git a/qemu-0.15.x/hw/cris-boot.c b/qemu-0.15.x/hw/cris-boot.c
new file mode 100644
index 0000000..37894f8
--- /dev/null
+++ b/qemu-0.15.x/hw/cris-boot.c
@@ -0,0 +1,96 @@
+/*
+ * CRIS image loading.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw.h"
+#include "loader.h"
+#include "elf.h"
+#include "cris-boot.h"
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct cris_load_info *li;
+
+    li = env->load_info;
+
+    cpu_reset(env);
+
+    if (!li) {
+        /* nothing more to do.  */
+        return;
+    }
+
+    env->pc = li->entry;
+
+    if (li->image_filename) {
+        env->regs[8] = 0x56902387; /* RAM boot magic.  */
+        env->regs[9] = 0x40004000 + li->image_size;
+    }
+
+    if (li->cmdline) {
+        /* Let the kernel know we are modifying the cmdline.  */
+        env->regs[10] = 0x87109563;
+        env->regs[11] = 0x40000000;
+    }
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x80000000LL;
+}
+
+void cris_load_image(CPUState *env, struct cris_load_info *li)
+{
+    uint64_t entry, high;
+    int kcmdline_len;
+    int image_size;
+
+    env->load_info = li;
+    /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
+       devboard SDK.  */
+    image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
+                          &entry, NULL, &high, 0, ELF_MACHINE, 0);
+    li->entry = entry;
+    if (image_size < 0) {
+        /* Takes a kimage from the axis devboard SDK.  */
+        image_size = load_image_targphys(li->image_filename, 0x40004000,
+                                         ram_size);
+        li->entry = 0x40004000;
+    }
+
+    if (image_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                li->image_filename);
+        exit(1);
+    }
+
+    if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
+        if (kcmdline_len > 256) {
+            fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
+            exit(1);
+        }
+        pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
+    }
+    qemu_register_reset(main_cpu_reset, env);
+}
diff --git a/qemu-0.15.x/hw/cris-boot.h b/qemu-0.15.x/hw/cris-boot.h
new file mode 100644
index 0000000..e9caf8d
--- /dev/null
+++ b/qemu-0.15.x/hw/cris-boot.h
@@ -0,0 +1,11 @@
+
+struct cris_load_info
+{
+    const char *image_filename;
+    const char *cmdline;
+    int image_size;
+
+    target_phys_addr_t entry;
+};
+
+void cris_load_image(CPUState *env, struct cris_load_info *li);
diff --git a/qemu-0.15.x/hw/cris_pic_cpu.c b/qemu-0.15.x/hw/cris_pic_cpu.c
new file mode 100644
index 0000000..a92d445
--- /dev/null
+++ b/qemu-0.15.x/hw/cris_pic_cpu.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU CRIS CPU interrupt wrapper logic.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "etraxfs.h"
+
+#define D(x)
+
+void pic_info(Monitor *mon)
+{}
+void irq_info(Monitor *mon)
+{}
+
+static void cris_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
+
+    if (level)
+        cpu_interrupt(env, type);
+    else
+        cpu_reset_interrupt(env, type);
+}
+
+qemu_irq *cris_pic_init_cpu(CPUState *env)
+{
+    return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2);
+}
diff --git a/qemu-0.15.x/hw/cs4231.c b/qemu-0.15.x/hw/cs4231.c
new file mode 100644
index 0000000..a65b697
--- /dev/null
+++ b/qemu-0.15.x/hw/cs4231.c
@@ -0,0 +1,175 @@
+/*
+ * QEMU Crystal CS4231 audio chip 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 "sysbus.h"
+#include "trace.h"
+
+/*
+ * In addition to Crystal CS4231 there is a DMA controller on Sparc.
+ */
+#define CS_SIZE 0x40
+#define CS_REGS 16
+#define CS_DREGS 32
+#define CS_MAXDREG (CS_DREGS - 1)
+
+typedef struct CSState {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t regs[CS_REGS];
+    uint8_t dregs[CS_DREGS];
+} CSState;
+
+#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
+#define CS_VER 0xa0
+#define CS_CDC_VER 0x8a
+
+static void cs_reset(DeviceState *d)
+{
+    CSState *s = container_of(d, CSState, busdev.qdev);
+
+    memset(s->regs, 0, CS_REGS * 4);
+    memset(s->dregs, 0, CS_DREGS);
+    s->dregs[12] = CS_CDC_VER;
+    s->dregs[25] = CS_VER;
+}
+
+static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    CSState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 1:
+        switch (CS_RAP(s)) {
+        case 3: // Write only
+            ret = 0;
+            break;
+        default:
+            ret = s->dregs[CS_RAP(s)];
+            break;
+        }
+        trace_cs4231_mem_readl_dreg(CS_RAP(s), ret);
+        break;
+    default:
+        ret = s->regs[saddr];
+        trace_cs4231_mem_readl_reg(saddr, ret);
+        break;
+    }
+    return ret;
+}
+
+static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CSState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val);
+    switch (saddr) {
+    case 1:
+        trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val);
+        switch(CS_RAP(s)) {
+        case 11:
+        case 25: // Read only
+            break;
+        case 12:
+            val &= 0x40;
+            val |= CS_CDC_VER; // Codec version
+            s->dregs[CS_RAP(s)] = val;
+            break;
+        default:
+            s->dregs[CS_RAP(s)] = val;
+            break;
+        }
+        break;
+    case 2: // Read only
+        break;
+    case 4:
+        if (val & 1) {
+            cs_reset(&s->busdev.qdev);
+        }
+        val &= 0x7f;
+        s->regs[saddr] = val;
+        break;
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const cs_mem_read[3] = {
+    cs_mem_readl,
+    cs_mem_readl,
+    cs_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const cs_mem_write[3] = {
+    cs_mem_writel,
+    cs_mem_writel,
+    cs_mem_writel,
+};
+
+static const VMStateDescription vmstate_cs4231 = {
+    .name ="cs4231",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
+        VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int cs4231_init1(SysBusDevice *dev)
+{
+    int io;
+    CSState *s = FROM_SYSBUS(CSState, dev);
+
+    io = cpu_register_io_memory(cs_mem_read, cs_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, CS_SIZE, io);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+static SysBusDeviceInfo cs4231_info = {
+    .init = cs4231_init1,
+    .qdev.name  = "SUNW,CS4231",
+    .qdev.size  = sizeof(CSState),
+    .qdev.vmsd  = &vmstate_cs4231,
+    .qdev.reset = cs_reset,
+    .qdev.props = (Property[]) {
+        {.name = NULL}
+    }
+};
+
+static void cs4231_register_devices(void)
+{
+    sysbus_register_withprop(&cs4231_info);
+}
+
+device_init(cs4231_register_devices)
diff --git a/qemu-0.15.x/hw/cs4231a.c b/qemu-0.15.x/hw/cs4231a.c
new file mode 100644
index 0000000..598f032
--- /dev/null
+++ b/qemu-0.15.x/hw/cs4231a.c
@@ -0,0 +1,686 @@
+/*
+ * QEMU Crystal CS4231 audio chip 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 "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "isa.h"
+#include "qdev.h"
+#include "qemu-timer.h"
+
+/*
+  Missing features:
+  ADC
+  Loopback
+  Timer
+  ADPCM
+  More...
+*/
+
+/* #define DEBUG */
+/* #define DEBUG_XLAW */
+
+static struct {
+    int aci_counter;
+} conf = {1};
+
+#ifdef DEBUG
+#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
+#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
+
+#define CS_REGS 16
+#define CS_DREGS 32
+
+typedef struct CSState {
+    ISADevice dev;
+    QEMUSoundCard card;
+    qemu_irq pic;
+    uint32_t regs[CS_REGS];
+    uint8_t dregs[CS_DREGS];
+    uint32_t irq;
+    uint32_t dma;
+    uint32_t port;
+    int shift;
+    int dma_running;
+    int audio_free;
+    int transferred;
+    int aci_counter;
+    SWVoiceOut *voice;
+    int16_t *tab;
+} CSState;
+
+#define IO_READ_PROTO(name)                             \
+    static uint32_t name (void *opaque, uint32_t addr)
+
+#define IO_WRITE_PROTO(name)                                            \
+    static void name (void *opaque, uint32_t addr, uint32_t val)
+
+#define GET_SADDR(addr) (addr & 3)
+
+#define MODE2 (1 << 6)
+#define MCE (1 << 6)
+#define PMCE (1 << 4)
+#define CMCE (1 << 5)
+#define TE (1 << 6)
+#define PEN (1 << 0)
+#define INT (1 << 0)
+#define IEN (1 << 1)
+#define PPIO (1 << 6)
+#define PI (1 << 4)
+#define CI (1 << 5)
+#define TI (1 << 6)
+
+enum {
+    Index_Address,
+    Index_Data,
+    Status,
+    PIO_Data
+};
+
+enum {
+    Left_ADC_Input_Control,
+    Right_ADC_Input_Control,
+    Left_AUX1_Input_Control,
+    Right_AUX1_Input_Control,
+    Left_AUX2_Input_Control,
+    Right_AUX2_Input_Control,
+    Left_DAC_Output_Control,
+    Right_DAC_Output_Control,
+    FS_And_Playback_Data_Format,
+    Interface_Configuration,
+    Pin_Control,
+    Error_Status_And_Initialization,
+    MODE_And_ID,
+    Loopback_Control,
+    Playback_Upper_Base_Count,
+    Playback_Lower_Base_Count,
+    Alternate_Feature_Enable_I,
+    Alternate_Feature_Enable_II,
+    Left_Line_Input_Control,
+    Right_Line_Input_Control,
+    Timer_Low_Base,
+    Timer_High_Base,
+    RESERVED,
+    Alternate_Feature_Enable_III,
+    Alternate_Feature_Status,
+    Version_Chip_ID,
+    Mono_Input_And_Output_Control,
+    RESERVED_2,
+    Capture_Data_Format,
+    RESERVED_3,
+    Capture_Upper_Base_Count,
+    Capture_Lower_Base_Count
+};
+
+static int freqs[2][8] = {
+    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
+    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
+};
+
+/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
+static int16_t MuLawDecompressTable[256] =
+{
+     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
+       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
+       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
+       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
+       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
+       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
+        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
+      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
+       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
+       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
+       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
+       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
+       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
+       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
+        876,   844,   812,   780,   748,   716,   684,   652,
+        620,   588,   556,   524,   492,   460,   428,   396,
+        372,   356,   340,   324,   308,   292,   276,   260,
+        244,   228,   212,   196,   180,   164,   148,   132,
+        120,   112,   104,    96,    88,    80,    72,    64,
+         56,    48,    40,    32,    24,    16,     8,     0
+};
+
+static int16_t ALawDecompressTable[256] =
+{
+     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
+     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
+     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
+     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
+     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
+     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
+     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
+     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
+     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
+     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
+      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
+      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
+      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
+      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
+      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
+      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+      344,   328,   376,   360,   280,   264,   312,   296,
+      472,   456,   504,   488,   408,   392,   440,   424,
+      88,    72,   120,   104,    24,     8,    56,    40,
+      216,   200,   248,   232,   152,   136,   184,   168,
+      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
+      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
+      688,   656,   752,   720,   560,   528,   624,   592,
+      944,   912,  1008,   976,   816,   784,   880,   848
+};
+
+static void cs_reset (void *opaque)
+{
+    CSState *s = opaque;
+
+    s->regs[Index_Address] = 0x40;
+    s->regs[Index_Data]    = 0x00;
+    s->regs[Status]        = 0x00;
+    s->regs[PIO_Data]      = 0x00;
+
+    s->dregs[Left_ADC_Input_Control]          = 0x00;
+    s->dregs[Right_ADC_Input_Control]         = 0x00;
+    s->dregs[Left_AUX1_Input_Control]         = 0x88;
+    s->dregs[Right_AUX1_Input_Control]        = 0x88;
+    s->dregs[Left_AUX2_Input_Control]         = 0x88;
+    s->dregs[Right_AUX2_Input_Control]        = 0x88;
+    s->dregs[Left_DAC_Output_Control]         = 0x80;
+    s->dregs[Right_DAC_Output_Control]        = 0x80;
+    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
+    s->dregs[Interface_Configuration]         = 0x08;
+    s->dregs[Pin_Control]                     = 0x00;
+    s->dregs[Error_Status_And_Initialization] = 0x00;
+    s->dregs[MODE_And_ID]                     = 0x8a;
+    s->dregs[Loopback_Control]                = 0x00;
+    s->dregs[Playback_Upper_Base_Count]       = 0x00;
+    s->dregs[Playback_Lower_Base_Count]       = 0x00;
+    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
+    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
+    s->dregs[Left_Line_Input_Control]         = 0x88;
+    s->dregs[Right_Line_Input_Control]        = 0x88;
+    s->dregs[Timer_Low_Base]                  = 0x00;
+    s->dregs[Timer_High_Base]                 = 0x00;
+    s->dregs[RESERVED]                        = 0x00;
+    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
+    s->dregs[Alternate_Feature_Status]        = 0x00;
+    s->dregs[Version_Chip_ID]                 = 0xa0;
+    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
+    s->dregs[RESERVED_2]                      = 0x00;
+    s->dregs[Capture_Data_Format]             = 0x00;
+    s->dregs[RESERVED_3]                      = 0x00;
+    s->dregs[Capture_Upper_Base_Count]        = 0x00;
+    s->dregs[Capture_Lower_Base_Count]        = 0x00;
+}
+
+static void cs_audio_callback (void *opaque, int free)
+{
+    CSState *s = opaque;
+    s->audio_free = free;
+}
+
+static void cs_reset_voices (CSState *s, uint32_t val)
+{
+    int xtal;
+    struct audsettings as;
+
+#ifdef DEBUG_XLAW
+    if (val == 0 || val == 32)
+        val = (1 << 4) | (1 << 5);
+#endif
+
+    xtal = val & 1;
+    as.freq = freqs[xtal][(val >> 1) & 7];
+
+    if (as.freq == -1) {
+        lerr ("unsupported frequency (val=%#x)\n", val);
+        goto error;
+    }
+
+    as.nchannels = (val & (1 << 4)) ? 2 : 1;
+    as.endianness = 0;
+    s->tab = NULL;
+
+    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
+    case 0:
+        as.fmt = AUD_FMT_U8;
+        s->shift = as.nchannels == 2;
+        break;
+
+    case 1:
+        s->tab = MuLawDecompressTable;
+        goto x_law;
+    case 3:
+        s->tab = ALawDecompressTable;
+    x_law:
+        as.fmt = AUD_FMT_S16;
+        as.endianness = AUDIO_HOST_ENDIANNESS;
+        s->shift = as.nchannels == 2;
+        break;
+
+    case 6:
+        as.endianness = 1;
+    case 2:
+        as.fmt = AUD_FMT_S16;
+        s->shift = as.nchannels;
+        break;
+
+    case 7:
+    case 4:
+        lerr ("attempt to use reserved format value (%#x)\n", val);
+        goto error;
+
+    case 5:
+        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
+        goto error;
+    }
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "cs4231a",
+        s,
+        cs_audio_callback,
+        &as
+        );
+
+    if (s->dregs[Interface_Configuration] & PEN) {
+        if (!s->dma_running) {
+            DMA_hold_DREQ (s->dma);
+            AUD_set_active_out (s->voice, 1);
+            s->transferred = 0;
+        }
+        s->dma_running = 1;
+    }
+    else {
+        if (s->dma_running) {
+            DMA_release_DREQ (s->dma);
+            AUD_set_active_out (s->voice, 0);
+        }
+        s->dma_running = 0;
+    }
+    return;
+
+ error:
+    if (s->dma_running) {
+        DMA_release_DREQ (s->dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+}
+
+IO_READ_PROTO (cs_read)
+{
+    CSState *s = opaque;
+    uint32_t saddr, iaddr, ret;
+
+    saddr = GET_SADDR (addr);
+    iaddr = ~0U;
+
+    switch (saddr) {
+    case Index_Address:
+        ret = s->regs[saddr] & ~0x80;
+        break;
+
+    case Index_Data:
+        if (!(s->dregs[MODE_And_ID] & MODE2))
+            iaddr = s->regs[Index_Address] & 0x0f;
+        else
+            iaddr = s->regs[Index_Address] & 0x1f;
+
+        ret = s->dregs[iaddr];
+        if (iaddr == Error_Status_And_Initialization) {
+            /* keep SEAL happy */
+            if (s->aci_counter) {
+                ret |= 1 << 5;
+                s->aci_counter -= 1;
+            }
+        }
+        break;
+
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
+    return ret;
+}
+
+IO_WRITE_PROTO (cs_write)
+{
+    CSState *s = opaque;
+    uint32_t saddr, iaddr;
+
+    saddr = GET_SADDR (addr);
+
+    switch (saddr) {
+    case Index_Address:
+        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
+            && (s->dregs[Interface_Configuration] & (3 << 3)))
+            s->aci_counter = conf.aci_counter;
+
+        s->regs[Index_Address] = val & ~(1 << 7);
+        break;
+
+    case Index_Data:
+        if (!(s->dregs[MODE_And_ID] & MODE2))
+            iaddr = s->regs[Index_Address] & 0x0f;
+        else
+            iaddr = s->regs[Index_Address] & 0x1f;
+
+        switch (iaddr) {
+        case RESERVED:
+        case RESERVED_2:
+        case RESERVED_3:
+            lwarn ("attempt to write %#x to reserved indirect register %d\n",
+                   val, iaddr);
+            break;
+
+        case FS_And_Playback_Data_Format:
+            if (s->regs[Index_Address] & MCE) {
+                cs_reset_voices (s, val);
+            }
+            else {
+                if (s->dregs[Alternate_Feature_Status] & PMCE) {
+                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
+                    cs_reset_voices (s, val);
+                }
+                else {
+                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
+                           s->regs[Index_Address],
+                           s->dregs[Alternate_Feature_Status],
+                           val);
+                    break;
+                }
+            }
+            s->dregs[iaddr] = val;
+            break;
+
+        case Interface_Configuration:
+            val &= ~(1 << 5);   /* D5 is reserved */
+            s->dregs[iaddr] = val;
+            if (val & PPIO) {
+                lwarn ("PIO is not supported (%#x)\n", val);
+                break;
+            }
+            if (val & PEN) {
+                if (!s->dma_running) {
+                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
+                }
+            }
+            else {
+                if (s->dma_running) {
+                    DMA_release_DREQ (s->dma);
+                    AUD_set_active_out (s->voice, 0);
+                    s->dma_running = 0;
+                }
+            }
+            break;
+
+        case Error_Status_And_Initialization:
+            lwarn ("attempt to write to read only register %d\n", iaddr);
+            break;
+
+        case MODE_And_ID:
+            dolog ("val=%#x\n", val);
+            if (val & MODE2)
+                s->dregs[iaddr] |= MODE2;
+            else
+                s->dregs[iaddr] &= ~MODE2;
+            break;
+
+        case Alternate_Feature_Enable_I:
+            if (val & TE)
+                lerr ("timer is not yet supported\n");
+            s->dregs[iaddr] = val;
+            break;
+
+        case Alternate_Feature_Status:
+            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
+                /* XXX: TI CI */
+                qemu_irq_lower (s->pic);
+                s->regs[Status] &= ~INT;
+            }
+            s->dregs[iaddr] = val;
+            break;
+
+        case Version_Chip_ID:
+            lwarn ("write to Version_Chip_ID register %#x\n", val);
+            s->dregs[iaddr] = val;
+            break;
+
+        default:
+            s->dregs[iaddr] = val;
+            break;
+        }
+        dolog ("written value %#x to indirect register %d\n", val, iaddr);
+        break;
+
+    case Status:
+        if (s->regs[Status] & INT) {
+            qemu_irq_lower (s->pic);
+        }
+        s->regs[Status] &= ~INT;
+        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
+        break;
+
+    case PIO_Data:
+        lwarn ("attempt to write value %#x to PIO register\n", val);
+        break;
+    }
+}
+
+static int cs_write_audio (CSState *s, int nchan, int dma_pos,
+                           int dma_len, int len)
+{
+    int temp, net;
+    uint8_t tmpbuf[4096];
+
+    temp = len;
+    net = 0;
+
+    while (temp) {
+        int left = dma_len - dma_pos;
+        int copied;
+        size_t to_copy;
+
+        to_copy = audio_MIN (temp, left);
+        if (to_copy > sizeof (tmpbuf)) {
+            to_copy = sizeof (tmpbuf);
+        }
+
+        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
+        if (s->tab) {
+            int i;
+            int16_t linbuf[4096];
+
+            for (i = 0; i < copied; ++i)
+                linbuf[i] = s->tab[tmpbuf[i]];
+            copied = AUD_write (s->voice, linbuf, copied << 1);
+            copied >>= 1;
+        }
+        else {
+            copied = AUD_write (s->voice, tmpbuf, copied);
+        }
+
+        temp -= copied;
+        dma_pos = (dma_pos + copied) % dma_len;
+        net += copied;
+
+        if (!copied) {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    CSState *s = opaque;
+    int copy, written;
+    int till = -1;
+
+    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
+
+    if (s->dregs[Pin_Control] & IEN) {
+        till = (s->dregs[Playback_Lower_Base_Count]
+            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
+        till -= s->transferred;
+        copy = audio_MIN (till, copy);
+    }
+
+    if ((copy <= 0) || (dma_len <= 0)) {
+        return dma_pos;
+    }
+
+    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
+
+    dma_pos = (dma_pos + written) % dma_len;
+    s->audio_free -= (written << (s->tab != NULL));
+
+    if (written == till) {
+        s->regs[Status] |= INT;
+        s->dregs[Alternate_Feature_Status] |= PI;
+        s->transferred = 0;
+        qemu_irq_raise (s->pic);
+    }
+    else {
+        s->transferred += written;
+    }
+
+    return dma_pos;
+}
+
+static int cs4231a_pre_load (void *opaque)
+{
+    CSState *s = opaque;
+
+    if (s->dma_running) {
+        DMA_release_DREQ (s->dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+    s->dma_running = 0;
+    return 0;
+}
+
+static int cs4231a_post_load (void *opaque, int version_id)
+{
+    CSState *s = opaque;
+
+    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
+        s->dma_running = 0;
+        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_cs4231a = {
+    .name = "cs4231a",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_load = cs4231a_pre_load,
+    .post_load = cs4231a_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
+        VMSTATE_BUFFER(dregs, CSState),
+        VMSTATE_INT32(dma_running, CSState),
+        VMSTATE_INT32(audio_free, CSState),
+        VMSTATE_INT32(transferred, CSState),
+        VMSTATE_INT32(aci_counter, CSState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int cs4231a_initfn (ISADevice *dev)
+{
+    CSState *s = DO_UPCAST (CSState, dev, dev);
+    int i;
+
+    isa_init_irq (dev, &s->pic, s->irq);
+
+    for (i = 0; i < 4; i++) {
+        isa_init_ioport(dev, i);
+        register_ioport_write (s->port + i, 1, 1, cs_write, s);
+        register_ioport_read (s->port + i, 1, 1, cs_read, s);
+    }
+
+    DMA_register_channel (s->dma, cs_dma_read, s);
+
+    qemu_register_reset (cs_reset, s);
+    cs_reset (s);
+
+    AUD_register_card ("cs4231a", &s->card);
+    return 0;
+}
+
+int cs4231a_init (qemu_irq *pic)
+{
+    isa_create_simple ("cs4231a");
+    return 0;
+}
+
+static ISADeviceInfo cs4231a_info = {
+    .qdev.name     = "cs4231a",
+    .qdev.desc     = "Crystal Semiconductor CS4231A",
+    .qdev.size     = sizeof (CSState),
+    .qdev.vmsd     = &vmstate_cs4231a,
+    .init          = cs4231a_initfn,
+    .qdev.props    = (Property[]) {
+        DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
+        DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
+        DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
+        DEFINE_PROP_END_OF_LIST (),
+    },
+};
+
+static void cs4231a_register (void)
+{
+    isa_qdev_register (&cs4231a_info);
+}
+device_init (cs4231a_register)
diff --git a/qemu-0.15.x/hw/cuda.c b/qemu-0.15.x/hw/cuda.c
new file mode 100644
index 0000000..065c362
--- /dev/null
+++ b/qemu-0.15.x/hw/cuda.c
@@ -0,0 +1,745 @@
+/*
+ * QEMU PowerMac CUDA device support
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc_mac.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+
+/* XXX: implement all timer modes */
+
+/* debug CUDA */
+//#define DEBUG_CUDA
+
+/* debug CUDA packets */
+//#define DEBUG_CUDA_PACKET
+
+#ifdef DEBUG_CUDA
+#define CUDA_DPRINTF(fmt, ...)                                  \
+    do { printf("CUDA: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define CUDA_DPRINTF(fmt, ...)
+#endif
+
+/* Bits in B data register: all active low */
+#define TREQ		0x08		/* Transfer request (input) */
+#define TACK		0x10		/* Transfer acknowledge (output) */
+#define TIP		0x20		/* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#define SR_EXT		0x0c		/* Shift on external clock */
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET		0x80		/* set bits in IER */
+#define IER_CLR		0		/* clear bits in IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+#define T1_INT          0x40            /* Timer 1 interrupt */
+#define T2_INT          0x20            /* Timer 2 interrupt */
+
+/* Bits in ACR */
+#define T1MODE          0xc0            /* Timer 1 mode */
+#define T1MODE_CONT     0x40            /*  continuous interrupts */
+
+/* commands (1st byte) */
+#define ADB_PACKET	0
+#define CUDA_PACKET	1
+#define ERROR_PACKET	2
+#define TIMER_PACKET	3
+#define POWER_PACKET	4
+#define MACIIC_PACKET	5
+#define PMU_PACKET	6
+
+
+/* CUDA commands (2nd byte) */
+#define CUDA_WARM_START			0x0
+#define CUDA_AUTOPOLL			0x1
+#define CUDA_GET_6805_ADDR		0x2
+#define CUDA_GET_TIME			0x3
+#define CUDA_GET_PRAM			0x7
+#define CUDA_SET_6805_ADDR		0x8
+#define CUDA_SET_TIME			0x9
+#define CUDA_POWERDOWN			0xa
+#define CUDA_POWERUP_TIME		0xb
+#define CUDA_SET_PRAM			0xc
+#define CUDA_MS_RESET			0xd
+#define CUDA_SEND_DFAC			0xe
+#define CUDA_BATTERY_SWAP_SENSE		0x10
+#define CUDA_RESET_SYSTEM		0x11
+#define CUDA_SET_IPL			0x12
+#define CUDA_FILE_SERVER_FLAG		0x13
+#define CUDA_SET_AUTO_RATE		0x14
+#define CUDA_GET_AUTO_RATE		0x16
+#define CUDA_SET_DEVICE_LIST		0x19
+#define CUDA_GET_DEVICE_LIST		0x1a
+#define CUDA_SET_ONE_SECOND_MODE	0x1b
+#define CUDA_SET_POWER_MESSAGES		0x21
+#define CUDA_GET_SET_IIC		0x22
+#define CUDA_WAKEUP			0x23
+#define CUDA_TIMER_TICKLE		0x24
+#define CUDA_COMBINED_FORMAT_IIC	0x25
+
+#define CUDA_TIMER_FREQ (4700000 / 6)
+#define CUDA_ADB_POLL_FREQ 50
+
+/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
+#define RTC_OFFSET                      2082844800
+
+typedef struct CUDATimer {
+    int index;
+    uint16_t latch;
+    uint16_t counter_value; /* counter value at load time */
+    int64_t load_time;
+    int64_t next_irq_time;
+    QEMUTimer *timer;
+} CUDATimer;
+
+typedef struct CUDAState {
+    /* cuda registers */
+    uint8_t b;      /* B-side data */
+    uint8_t a;      /* A-side data */
+    uint8_t dirb;   /* B-side direction (1=output) */
+    uint8_t dira;   /* A-side direction (1=output) */
+    uint8_t sr;     /* Shift register */
+    uint8_t acr;    /* Auxiliary control register */
+    uint8_t pcr;    /* Peripheral control register */
+    uint8_t ifr;    /* Interrupt flag register */
+    uint8_t ier;    /* Interrupt enable register */
+    uint8_t anh;    /* A-side data, no handshake */
+
+    CUDATimer timers[2];
+
+    uint32_t tick_offset;
+
+    uint8_t last_b; /* last value of B register */
+    uint8_t last_acr; /* last value of B register */
+
+    int data_in_size;
+    int data_in_index;
+    int data_out_index;
+
+    qemu_irq irq;
+    uint8_t autopoll;
+    uint8_t data_in[128];
+    uint8_t data_out[16];
+    QEMUTimer *adb_poll_timer;
+} CUDAState;
+
+static CUDAState cuda_state;
+ADBBusState adb_bus;
+
+static void cuda_update(CUDAState *s);
+static void cuda_receive_packet_from_host(CUDAState *s,
+                                          const uint8_t *data, int len);
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
+                              int64_t current_time);
+
+static void cuda_update_irq(CUDAState *s)
+{
+    if (s->ifr & s->ier & (SR_INT | T1_INT)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static unsigned int get_counter(CUDATimer *s)
+{
+    int64_t d;
+    unsigned int counter;
+
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->load_time,
+                 CUDA_TIMER_FREQ, get_ticks_per_sec());
+    if (s->index == 0) {
+        /* the timer goes down from latch to -1 (period of latch + 2) */
+        if (d <= (s->counter_value + 1)) {
+            counter = (s->counter_value - d) & 0xffff;
+        } else {
+            counter = (d - (s->counter_value + 1)) % (s->latch + 2);
+            counter = (s->latch - counter) & 0xffff;
+        }
+    } else {
+        counter = (s->counter_value - d) & 0xffff;
+    }
+    return counter;
+}
+
+static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
+{
+    CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
+    ti->load_time = qemu_get_clock_ns(vm_clock);
+    ti->counter_value = val;
+    cuda_timer_update(s, ti, ti->load_time);
+}
+
+static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
+{
+    int64_t d, next_time;
+    unsigned int counter;
+
+    /* current counter value */
+    d = muldiv64(current_time - s->load_time,
+                 CUDA_TIMER_FREQ, get_ticks_per_sec());
+    /* the timer goes down from latch to -1 (period of latch + 2) */
+    if (d <= (s->counter_value + 1)) {
+        counter = (s->counter_value - d) & 0xffff;
+    } else {
+        counter = (d - (s->counter_value + 1)) % (s->latch + 2);
+        counter = (s->latch - counter) & 0xffff;
+    }
+
+    /* Note: we consider the irq is raised on 0 */
+    if (counter == 0xffff) {
+        next_time = d + s->latch + 1;
+    } else if (counter == 0) {
+        next_time = d + s->latch + 2;
+    } else {
+        next_time = d + counter;
+    }
+    CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
+                 s->latch, d, next_time - d);
+    next_time = muldiv64(next_time, get_ticks_per_sec(), CUDA_TIMER_FREQ) +
+        s->load_time;
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
+                              int64_t current_time)
+{
+    if (!ti->timer)
+        return;
+    if ((s->acr & T1MODE) != T1MODE_CONT) {
+        qemu_del_timer(ti->timer);
+    } else {
+        ti->next_irq_time = get_next_irq_time(ti, current_time);
+        qemu_mod_timer(ti->timer, ti->next_irq_time);
+    }
+}
+
+static void cuda_timer1(void *opaque)
+{
+    CUDAState *s = opaque;
+    CUDATimer *ti = &s->timers[0];
+
+    cuda_timer_update(s, ti, ti->next_irq_time);
+    s->ifr |= T1_INT;
+    cuda_update_irq(s);
+}
+
+static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
+{
+    CUDAState *s = opaque;
+    uint32_t val;
+
+    addr = (addr >> 9) & 0xf;
+    switch(addr) {
+    case 0:
+        val = s->b;
+        break;
+    case 1:
+        val = s->a;
+        break;
+    case 2:
+        val = s->dirb;
+        break;
+    case 3:
+        val = s->dira;
+        break;
+    case 4:
+        val = get_counter(&s->timers[0]) & 0xff;
+        s->ifr &= ~T1_INT;
+        cuda_update_irq(s);
+        break;
+    case 5:
+        val = get_counter(&s->timers[0]) >> 8;
+        cuda_update_irq(s);
+        break;
+    case 6:
+        val = s->timers[0].latch & 0xff;
+        break;
+    case 7:
+        /* XXX: check this */
+        val = (s->timers[0].latch >> 8) & 0xff;
+        break;
+    case 8:
+        val = get_counter(&s->timers[1]) & 0xff;
+        s->ifr &= ~T2_INT;
+        break;
+    case 9:
+        val = get_counter(&s->timers[1]) >> 8;
+        break;
+    case 10:
+        val = s->sr;
+        s->ifr &= ~SR_INT;
+        cuda_update_irq(s);
+        break;
+    case 11:
+        val = s->acr;
+        break;
+    case 12:
+        val = s->pcr;
+        break;
+    case 13:
+        val = s->ifr;
+        if (s->ifr & s->ier)
+            val |= 0x80;
+        break;
+    case 14:
+        val = s->ier | 0x80;
+        break;
+    default:
+    case 15:
+        val = s->anh;
+        break;
+    }
+    if (addr != 13 || val != 0) {
+        CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
+    }
+
+    return val;
+}
+
+static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    CUDAState *s = opaque;
+
+    addr = (addr >> 9) & 0xf;
+    CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);
+
+    switch(addr) {
+    case 0:
+        s->b = val;
+        cuda_update(s);
+        break;
+    case 1:
+        s->a = val;
+        break;
+    case 2:
+        s->dirb = val;
+        break;
+    case 3:
+        s->dira = val;
+        break;
+    case 4:
+        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 5:
+        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
+        s->ifr &= ~T1_INT;
+        set_counter(s, &s->timers[0], s->timers[0].latch);
+        break;
+    case 6:
+        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 7:
+        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
+        s->ifr &= ~T1_INT;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 8:
+        s->timers[1].latch = val;
+        set_counter(s, &s->timers[1], val);
+        break;
+    case 9:
+        set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
+        break;
+    case 10:
+        s->sr = val;
+        break;
+    case 11:
+        s->acr = val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        cuda_update(s);
+        break;
+    case 12:
+        s->pcr = val;
+        break;
+    case 13:
+        /* reset bits */
+        s->ifr &= ~val;
+        cuda_update_irq(s);
+        break;
+    case 14:
+        if (val & IER_SET) {
+            /* set bits */
+            s->ier |= val & 0x7f;
+        } else {
+            /* reset bits */
+            s->ier &= ~val;
+        }
+        cuda_update_irq(s);
+        break;
+    default:
+    case 15:
+        s->anh = val;
+        break;
+    }
+}
+
+/* NOTE: TIP and TREQ are negated */
+static void cuda_update(CUDAState *s)
+{
+    int packet_received, len;
+
+    packet_received = 0;
+    if (!(s->b & TIP)) {
+        /* transfer requested from host */
+
+        if (s->acr & SR_OUT) {
+            /* data output */
+            if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
+                if (s->data_out_index < sizeof(s->data_out)) {
+                    CUDA_DPRINTF("send: %02x\n", s->sr);
+                    s->data_out[s->data_out_index++] = s->sr;
+                    s->ifr |= SR_INT;
+                    cuda_update_irq(s);
+                }
+            }
+        } else {
+            if (s->data_in_index < s->data_in_size) {
+                /* data input */
+                if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
+                    s->sr = s->data_in[s->data_in_index++];
+                    CUDA_DPRINTF("recv: %02x\n", s->sr);
+                    /* indicate end of transfer */
+                    if (s->data_in_index >= s->data_in_size) {
+                        s->b = (s->b | TREQ);
+                    }
+                    s->ifr |= SR_INT;
+                    cuda_update_irq(s);
+                }
+            }
+        }
+    } else {
+        /* no transfer requested: handle sync case */
+        if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
+            /* update TREQ state each time TACK change state */
+            if (s->b & TACK)
+                s->b = (s->b | TREQ);
+            else
+                s->b = (s->b & ~TREQ);
+            s->ifr |= SR_INT;
+            cuda_update_irq(s);
+        } else {
+            if (!(s->last_b & TIP)) {
+                /* handle end of host to cuda transfer */
+                packet_received = (s->data_out_index > 0);
+                /* always an IRQ at the end of transfer */
+                s->ifr |= SR_INT;
+                cuda_update_irq(s);
+            }
+            /* signal if there is data to read */
+            if (s->data_in_index < s->data_in_size) {
+                s->b = (s->b & ~TREQ);
+            }
+        }
+    }
+
+    s->last_acr = s->acr;
+    s->last_b = s->b;
+
+    /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
+       recursively */
+    if (packet_received) {
+        len = s->data_out_index;
+        s->data_out_index = 0;
+        cuda_receive_packet_from_host(s, s->data_out, len);
+    }
+}
+
+static void cuda_send_packet_to_host(CUDAState *s,
+                                     const uint8_t *data, int len)
+{
+#ifdef DEBUG_CUDA_PACKET
+    {
+        int i;
+        printf("cuda_send_packet_to_host:\n");
+        for(i = 0; i < len; i++)
+            printf(" %02x", data[i]);
+        printf("\n");
+    }
+#endif
+    memcpy(s->data_in, data, len);
+    s->data_in_size = len;
+    s->data_in_index = 0;
+    cuda_update(s);
+    s->ifr |= SR_INT;
+    cuda_update_irq(s);
+}
+
+static void cuda_adb_poll(void *opaque)
+{
+    CUDAState *s = opaque;
+    uint8_t obuf[ADB_MAX_OUT_LEN + 2];
+    int olen;
+
+    olen = adb_poll(&adb_bus, obuf + 2);
+    if (olen > 0) {
+        obuf[0] = ADB_PACKET;
+        obuf[1] = 0x40; /* polled data */
+        cuda_send_packet_to_host(s, obuf, olen + 2);
+    }
+    qemu_mod_timer(s->adb_poll_timer,
+                   qemu_get_clock_ns(vm_clock) +
+                   (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+}
+
+static void cuda_receive_packet(CUDAState *s,
+                                const uint8_t *data, int len)
+{
+    uint8_t obuf[16];
+    int autopoll;
+    uint32_t ti;
+
+    switch(data[0]) {
+    case CUDA_AUTOPOLL:
+        autopoll = (data[1] != 0);
+        if (autopoll != s->autopoll) {
+            s->autopoll = autopoll;
+            if (autopoll) {
+                qemu_mod_timer(s->adb_poll_timer,
+                               qemu_get_clock_ns(vm_clock) +
+                               (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+            } else {
+                qemu_del_timer(s->adb_poll_timer);
+            }
+        }
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = data[1];
+        cuda_send_packet_to_host(s, obuf, 2);
+        break;
+    case CUDA_SET_TIME:
+        ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
+        s->tick_offset = ti - (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        obuf[2] = 0;
+        cuda_send_packet_to_host(s, obuf, 3);
+        break;
+    case CUDA_GET_TIME:
+        ti = s->tick_offset + (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        obuf[2] = 0;
+        obuf[3] = ti >> 24;
+        obuf[4] = ti >> 16;
+        obuf[5] = ti >> 8;
+        obuf[6] = ti;
+        cuda_send_packet_to_host(s, obuf, 7);
+        break;
+    case CUDA_FILE_SERVER_FLAG:
+    case CUDA_SET_DEVICE_LIST:
+    case CUDA_SET_AUTO_RATE:
+    case CUDA_SET_POWER_MESSAGES:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        break;
+    case CUDA_POWERDOWN:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        qemu_system_shutdown_request();
+        break;
+    case CUDA_RESET_SYSTEM:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        qemu_system_reset_request();
+        break;
+    default:
+        break;
+    }
+}
+
+static void cuda_receive_packet_from_host(CUDAState *s,
+                                          const uint8_t *data, int len)
+{
+#ifdef DEBUG_CUDA_PACKET
+    {
+        int i;
+        printf("cuda_receive_packet_from_host:\n");
+        for(i = 0; i < len; i++)
+            printf(" %02x", data[i]);
+        printf("\n");
+    }
+#endif
+    switch(data[0]) {
+    case ADB_PACKET:
+        {
+            uint8_t obuf[ADB_MAX_OUT_LEN + 2];
+            int olen;
+            olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
+            if (olen > 0) {
+                obuf[0] = ADB_PACKET;
+                obuf[1] = 0x00;
+            } else {
+                /* error */
+                obuf[0] = ADB_PACKET;
+                obuf[1] = -olen;
+                olen = 0;
+            }
+            cuda_send_packet_to_host(s, obuf, olen + 2);
+        }
+        break;
+    case CUDA_PACKET:
+        cuda_receive_packet(s, data + 1, len - 1);
+        break;
+    }
+}
+
+static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+}
+
+static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+}
+
+static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static CPUWriteMemoryFunc * const cuda_write[] = {
+    &cuda_writeb,
+    &cuda_writew,
+    &cuda_writel,
+};
+
+static CPUReadMemoryFunc * const cuda_read[] = {
+    &cuda_readb,
+    &cuda_readw,
+    &cuda_readl,
+};
+
+static bool cuda_timer_exist(void *opaque, int version_id)
+{
+    CUDATimer *s = opaque;
+
+    return s->timer != NULL;
+}
+
+static const VMStateDescription vmstate_cuda_timer = {
+    .name = "cuda_timer",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT16(latch, CUDATimer),
+        VMSTATE_UINT16(counter_value, CUDATimer),
+        VMSTATE_INT64(load_time, CUDATimer),
+        VMSTATE_INT64(next_irq_time, CUDATimer),
+        VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_cuda = {
+    .name = "cuda",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(a, CUDAState),
+        VMSTATE_UINT8(b, CUDAState),
+        VMSTATE_UINT8(dira, CUDAState),
+        VMSTATE_UINT8(dirb, CUDAState),
+        VMSTATE_UINT8(sr, CUDAState),
+        VMSTATE_UINT8(acr, CUDAState),
+        VMSTATE_UINT8(pcr, CUDAState),
+        VMSTATE_UINT8(ifr, CUDAState),
+        VMSTATE_UINT8(ier, CUDAState),
+        VMSTATE_UINT8(anh, CUDAState),
+        VMSTATE_INT32(data_in_size, CUDAState),
+        VMSTATE_INT32(data_in_index, CUDAState),
+        VMSTATE_INT32(data_out_index, CUDAState),
+        VMSTATE_UINT8(autopoll, CUDAState),
+        VMSTATE_BUFFER(data_in, CUDAState),
+        VMSTATE_BUFFER(data_out, CUDAState),
+        VMSTATE_UINT32(tick_offset, CUDAState),
+        VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
+                             vmstate_cuda_timer, CUDATimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void cuda_reset(void *opaque)
+{
+    CUDAState *s = opaque;
+
+    s->b = 0;
+    s->a = 0;
+    s->dirb = 0;
+    s->dira = 0;
+    s->sr = 0;
+    s->acr = 0;
+    s->pcr = 0;
+    s->ifr = 0;
+    s->ier = 0;
+    //    s->ier = T1_INT | SR_INT;
+    s->anh = 0;
+    s->data_in_size = 0;
+    s->data_in_index = 0;
+    s->data_out_index = 0;
+    s->autopoll = 0;
+
+    s->timers[0].latch = 0xffff;
+    set_counter(s, &s->timers[0], 0xffff);
+
+    s->timers[1].latch = 0;
+    set_counter(s, &s->timers[1], 0xffff);
+}
+
+void cuda_init (int *cuda_mem_index, qemu_irq irq)
+{
+    struct tm tm;
+    CUDAState *s = &cuda_state;
+
+    s->irq = irq;
+
+    s->timers[0].index = 0;
+    s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s);
+
+    s->timers[1].index = 1;
+
+    qemu_get_timedate(&tm, 0);
+    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
+
+    s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
+    *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s,
+                                             DEVICE_NATIVE_ENDIAN);
+    vmstate_register(NULL, -1, &vmstate_cuda, s);
+    qemu_register_reset(cuda_reset, s);
+}
diff --git a/qemu-0.15.x/hw/debugcon.c b/qemu-0.15.x/hw/debugcon.c
new file mode 100644
index 0000000..5ee6821
--- /dev/null
+++ b/qemu-0.15.x/hw/debugcon.c
@@ -0,0 +1,107 @@
+/*
+ * QEMU Bochs-style debug console ("port E9") emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ * Copyright (c) Intel Corporation; author: H. Peter Anvin
+ *
+ * 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 "hw.h"
+#include "qemu-char.h"
+#include "isa.h"
+#include "pc.h"
+
+//#define DEBUG_DEBUGCON
+
+typedef struct DebugconState {
+    CharDriverState *chr;
+    uint32_t readback;
+} DebugconState;
+
+typedef struct ISADebugconState {
+    ISADevice dev;
+    uint32_t iobase;
+    DebugconState state;
+} ISADebugconState;
+
+static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    DebugconState *s = opaque;
+    unsigned char ch = val;
+
+#ifdef DEBUG_DEBUGCON
+    printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
+#endif
+
+    qemu_chr_write(s->chr, &ch, 1);
+}
+
+
+static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr)
+{
+    DebugconState *s = opaque;
+
+#ifdef DEBUG_DEBUGCON
+    printf("debugcon: read addr=0x%04x\n", addr);
+#endif
+
+    return s->readback;
+}
+
+static void debugcon_init_core(DebugconState *s)
+{
+    if (!s->chr) {
+        fprintf(stderr, "Can't create debugcon device, empty char device\n");
+        exit(1);
+    }
+
+    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+}
+
+static int debugcon_isa_initfn(ISADevice *dev)
+{
+    ISADebugconState *isa = DO_UPCAST(ISADebugconState, dev, dev);
+    DebugconState *s = &isa->state;
+
+    debugcon_init_core(s);
+    register_ioport_write(isa->iobase, 1, 1, debugcon_ioport_write, s);
+    register_ioport_read(isa->iobase, 1, 1, debugcon_ioport_read, s);
+    return 0;
+}
+
+static ISADeviceInfo debugcon_isa_info = {
+    .qdev.name  = "isa-debugcon",
+    .qdev.size  = sizeof(ISADebugconState),
+    .init       = debugcon_isa_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+        DEFINE_PROP_CHR("chardev",  ISADebugconState, state.chr),
+        DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void debugcon_register_devices(void)
+{
+    isa_qdev_register(&debugcon_isa_info);
+}
+
+device_init(debugcon_register_devices)
diff --git a/qemu-0.15.x/hw/dec_pci.c b/qemu-0.15.x/hw/dec_pci.c
new file mode 100644
index 0000000..a35f382
--- /dev/null
+++ b/qemu-0.15.x/hw/dec_pci.c
@@ -0,0 +1,121 @@
+/*
+ * QEMU DEC 21154 PCI bridge
+ *
+ * Copyright (c) 2006-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "dec_pci.h"
+#include "sysbus.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
+
+/* debug DEC */
+//#define DEBUG_DEC
+
+#ifdef DEBUG_DEC
+#define DEC_DPRINTF(fmt, ...)                               \
+    do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DEC_DPRINTF(fmt, ...)
+#endif
+
+typedef struct DECState {
+    SysBusDevice busdev;
+    PCIHostState host_state;
+} DECState;
+
+static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num;
+}
+
+static PCIDeviceInfo dec_21154_pci_bridge_info = {
+    .qdev.name = "dec-21154-p2p-bridge",
+    .qdev.desc = "DEC 21154 PCI-PCI bridge",
+    .qdev.size = sizeof(PCIBridge),
+    .qdev.vmsd = &vmstate_pci_device,
+    .qdev.reset = pci_bridge_reset,
+    .init = pci_bridge_initfn,
+    .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
+    .config_write = pci_bridge_write_config,
+    .is_bridge = 1,
+};
+
+PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
+{
+    PCIDevice *dev;
+    PCIBridge *br;
+
+    dev = pci_create_multifunction(parent_bus, devfn, false,
+                                   "dec-21154-p2p-bridge");
+    br = DO_UPCAST(PCIBridge, dev, dev);
+    pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
+    qdev_init_nofail(&dev->qdev);
+    return pci_bridge_get_sec_bus(br);
+}
+
+static int pci_dec_21154_init_device(SysBusDevice *dev)
+{
+    DECState *s;
+    int pci_mem_config, pci_mem_data;
+
+    s = FROM_SYSBUS(DECState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    return 0;
+}
+
+static int dec_21154_pci_host_init(PCIDevice *d)
+{
+    /* PCI2PCI bridge same values as PearPC - check this */
+    return 0;
+}
+
+static PCIDeviceInfo dec_21154_pci_host_info = {
+    .qdev.name = "dec-21154",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = dec_21154_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
+    .revision = 0x02,
+    .class_id = PCI_CLASS_BRIDGE_PCI,
+    .is_bridge  = 1,
+};
+
+static void dec_register_devices(void)
+{
+    sysbus_register_dev("dec-21154", sizeof(DECState),
+                        pci_dec_21154_init_device);
+    pci_qdev_register(&dec_21154_pci_host_info);
+    pci_qdev_register(&dec_21154_pci_bridge_info);
+}
+
+device_init(dec_register_devices)
diff --git a/qemu-0.15.x/hw/dec_pci.h b/qemu-0.15.x/hw/dec_pci.h
new file mode 100644
index 0000000..79264ba
--- /dev/null
+++ b/qemu-0.15.x/hw/dec_pci.h
@@ -0,0 +1,8 @@
+#ifndef DEC_PCI_H
+#define DEC_PCI_H
+
+#include "qemu-common.h"
+
+PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
+
+#endif
diff --git a/qemu-0.15.x/hw/device-hotplug.c b/qemu-0.15.x/hw/device-hotplug.c
new file mode 100644
index 0000000..8b2ed7a
--- /dev/null
+++ b/qemu-0.15.x/hw/device-hotplug.c
@@ -0,0 +1,46 @@
+/*
+ * QEMU device hotplug helpers
+ *
+ * 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 "hw.h"
+#include "boards.h"
+#include "net.h"
+#include "blockdev.h"
+
+DriveInfo *add_init_drive(const char *optstr)
+{
+    DriveInfo *dinfo;
+    QemuOpts *opts;
+
+    opts = drive_def(optstr);
+    if (!opts)
+        return NULL;
+
+    dinfo = drive_init(opts, current_machine->use_scsi);
+    if (!dinfo) {
+        qemu_opts_del(opts);
+        return NULL;
+    }
+
+    return dinfo;
+}
diff --git a/qemu-0.15.x/hw/devices.h b/qemu-0.15.x/hw/devices.h
new file mode 100644
index 0000000..c788373
--- /dev/null
+++ b/qemu-0.15.x/hw/devices.h
@@ -0,0 +1,70 @@
+#ifndef QEMU_DEVICES_H
+#define QEMU_DEVICES_H
+
+/* Devices that have nowhere better to go.  */
+
+/* smc91c111.c */
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+
+/* lan9118.c */
+void lan9118_init(NICInfo *, uint32_t, qemu_irq);
+
+/* tsc210x.c */
+uWireSlave *tsc2102_init(qemu_irq pint);
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
+I2SCodec *tsc210x_codec(uWireSlave *chip);
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info);
+void tsc210x_key_event(uWireSlave *chip, int key, int down);
+
+/* tsc2005.c */
+void *tsc2005_init(qemu_irq pintdav);
+uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
+
+/* stellaris_input.c */
+void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
+
+/* blizzard.c */
+void *s1d13745_init(qemu_irq gpio_int);
+void s1d13745_write(void *opaque, int dc, uint16_t value);
+void s1d13745_write_block(void *opaque, int dc,
+                void *buf, size_t len, int pitch);
+uint16_t s1d13745_read(void *opaque, int dc);
+
+/* cbus.c */
+typedef struct {
+    qemu_irq clk;
+    qemu_irq dat;
+    qemu_irq sel;
+} CBus;
+CBus *cbus_init(qemu_irq dat_out);
+void cbus_attach(CBus *bus, void *slave_opaque);
+
+void *retu_init(qemu_irq irq, int vilma);
+void *tahvo_init(qemu_irq irq, int betty);
+
+void retu_key_event(void *retu, int state);
+
+/* tusb6010.c */
+typedef struct TUSBState TUSBState;
+TUSBState *tusb6010_init(qemu_irq intr);
+int tusb6010_sync_io(TUSBState *s);
+int tusb6010_async_io(TUSBState *s);
+void tusb6010_power(TUSBState *s, int on);
+
+/* tc6393xb.c */
+typedef struct TC6393xbState TC6393xbState;
+#define TC6393XB_RAM	0x110000 /* amount of ram for Video and USB */
+TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq);
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
+                    qemu_irq handler);
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
+
+/* sm501.c */
+void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+                CharDriverState *chr);
+
+#endif
diff --git a/qemu-0.15.x/hw/dma.c b/qemu-0.15.x/hw/dma.c
new file mode 100644
index 0000000..8a7302a
--- /dev/null
+++ b/qemu-0.15.x/hw/dma.c
@@ -0,0 +1,555 @@
+/*
+ * QEMU DMA emulation
+ *
+ * Copyright (c) 2003-2004 Vassili Karpov (malc)
+ *
+ * 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 "hw.h"
+#include "isa.h"
+
+/* #define DEBUG_DMA */
+
+#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#ifdef DEBUG_DMA
+#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#else
+#define linfo(...)
+#define ldebug(...)
+#endif
+
+struct dma_regs {
+    int now[2];
+    uint16_t base[2];
+    uint8_t mode;
+    uint8_t page;
+    uint8_t pageh;
+    uint8_t dack;
+    uint8_t eop;
+    DMA_transfer_handler transfer_handler;
+    void *opaque;
+};
+
+#define ADDR 0
+#define COUNT 1
+
+static struct dma_cont {
+    uint8_t status;
+    uint8_t command;
+    uint8_t mask;
+    uint8_t flip_flop;
+    int dshift;
+    struct dma_regs regs[4];
+    qemu_irq *cpu_request_exit;
+} dma_controllers[2];
+
+enum {
+    CMD_MEMORY_TO_MEMORY = 0x01,
+    CMD_FIXED_ADDRESS    = 0x02,
+    CMD_BLOCK_CONTROLLER = 0x04,
+    CMD_COMPRESSED_TIME  = 0x08,
+    CMD_CYCLIC_PRIORITY  = 0x10,
+    CMD_EXTENDED_WRITE   = 0x20,
+    CMD_LOW_DREQ         = 0x40,
+    CMD_LOW_DACK         = 0x80,
+    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
+    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
+    | CMD_LOW_DREQ | CMD_LOW_DACK
+
+};
+
+static void DMA_run (void);
+
+static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
+
+static void write_page (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel %#x %#x\n", nport, data);
+        return;
+    }
+    d->regs[ichan].page = data;
+}
+
+static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel %#x %#x\n", nport, data);
+        return;
+    }
+    d->regs[ichan].pageh = data;
+}
+
+static uint32_t read_page (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel read %#x\n", nport);
+        return 0;
+    }
+    return d->regs[ichan].page;
+}
+
+static uint32_t read_pageh (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel read %#x\n", nport);
+        return 0;
+    }
+    return d->regs[ichan].pageh;
+}
+
+static inline void init_chan (struct dma_cont *d, int ichan)
+{
+    struct dma_regs *r;
+
+    r = d->regs + ichan;
+    r->now[ADDR] = r->base[ADDR] << d->dshift;
+    r->now[COUNT] = 0;
+}
+
+static inline int getff (struct dma_cont *d)
+{
+    int ff;
+
+    ff = d->flip_flop;
+    d->flip_flop = !ff;
+    return ff;
+}
+
+static uint32_t read_chan (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int ichan, nreg, iport, ff, val, dir;
+    struct dma_regs *r;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    ichan = iport >> 1;
+    nreg = iport & 1;
+    r = d->regs + ichan;
+
+    dir = ((r->mode >> 5) & 1) ? -1 : 1;
+    ff = getff (d);
+    if (nreg)
+        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
+    else
+        val = r->now[ADDR] + r->now[COUNT] * dir;
+
+    ldebug ("read_chan %#x -> %d\n", iport, val);
+    return (val >> (d->dshift + (ff << 3))) & 0xff;
+}
+
+static void write_chan (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int iport, ichan, nreg;
+    struct dma_regs *r;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    ichan = iport >> 1;
+    nreg = iport & 1;
+    r = d->regs + ichan;
+    if (getff (d)) {
+        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
+        init_chan (d, ichan);
+    } else {
+        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
+    }
+}
+
+static void write_cont (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int iport, ichan = 0;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    switch (iport) {
+    case 0x08:                  /* command */
+        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
+            dolog ("command %#x not supported\n", data);
+            return;
+        }
+        d->command = data;
+        break;
+
+    case 0x09:
+        ichan = data & 3;
+        if (data & 4) {
+            d->status |= 1 << (ichan + 4);
+        }
+        else {
+            d->status &= ~(1 << (ichan + 4));
+        }
+        d->status &= ~(1 << ichan);
+        DMA_run();
+        break;
+
+    case 0x0a:                  /* single mask */
+        if (data & 4)
+            d->mask |= 1 << (data & 3);
+        else
+            d->mask &= ~(1 << (data & 3));
+        DMA_run();
+        break;
+
+    case 0x0b:                  /* mode */
+        {
+            ichan = data & 3;
+#ifdef DEBUG_DMA
+            {
+                int op, ai, dir, opmode;
+                op = (data >> 2) & 3;
+                ai = (data >> 4) & 1;
+                dir = (data >> 5) & 1;
+                opmode = (data >> 6) & 3;
+
+                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
+                       ichan, op, ai, dir, opmode);
+            }
+#endif
+            d->regs[ichan].mode = data;
+            break;
+        }
+
+    case 0x0c:                  /* clear flip flop */
+        d->flip_flop = 0;
+        break;
+
+    case 0x0d:                  /* reset */
+        d->flip_flop = 0;
+        d->mask = ~0;
+        d->status = 0;
+        d->command = 0;
+        break;
+
+    case 0x0e:                  /* clear mask for all channels */
+        d->mask = 0;
+        DMA_run();
+        break;
+
+    case 0x0f:                  /* write mask for all channels */
+        d->mask = data;
+        DMA_run();
+        break;
+
+    default:
+        dolog ("unknown iport %#x\n", iport);
+        break;
+    }
+
+#ifdef DEBUG_DMA
+    if (0xc != iport) {
+        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
+               nport, ichan, data);
+    }
+#endif
+}
+
+static uint32_t read_cont (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int iport, val;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    switch (iport) {
+    case 0x08:                  /* status */
+        val = d->status;
+        d->status &= 0xf0;
+        break;
+    case 0x0f:                  /* mask */
+        val = d->mask;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+
+    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
+    return val;
+}
+
+int DMA_get_channel_mode (int nchan)
+{
+    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
+}
+
+void DMA_hold_DREQ (int nchan)
+{
+    int ncont, ichan;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+    linfo ("held cont=%d chan=%d\n", ncont, ichan);
+    dma_controllers[ncont].status |= 1 << (ichan + 4);
+    DMA_run();
+}
+
+void DMA_release_DREQ (int nchan)
+{
+    int ncont, ichan;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+    linfo ("released cont=%d chan=%d\n", ncont, ichan);
+    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
+    DMA_run();
+}
+
+static void channel_run (int ncont, int ichan)
+{
+    int n;
+    struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
+#ifdef DEBUG_DMA
+    int dir, opmode;
+
+    dir = (r->mode >> 5) & 1;
+    opmode = (r->mode >> 6) & 3;
+
+    if (dir) {
+        dolog ("DMA in address decrement mode\n");
+    }
+    if (opmode != 1) {
+        dolog ("DMA not in single mode select %#x\n", opmode);
+    }
+#endif
+
+    n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
+                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
+    r->now[COUNT] = n;
+    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
+}
+
+static QEMUBH *dma_bh;
+
+static void DMA_run (void)
+{
+    struct dma_cont *d;
+    int icont, ichan;
+    int rearm = 0;
+
+    d = dma_controllers;
+
+    for (icont = 0; icont < 2; icont++, d++) {
+        for (ichan = 0; ichan < 4; ichan++) {
+            int mask;
+
+            mask = 1 << ichan;
+
+            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
+                channel_run (icont, ichan);
+                rearm = 1;
+            }
+        }
+    }
+
+    if (rearm)
+        qemu_bh_schedule_idle(dma_bh);
+}
+
+static void DMA_run_bh(void *unused)
+{
+    DMA_run();
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+    struct dma_regs *r;
+    int ichan, ncont;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+
+    r = dma_controllers[ncont].regs + ichan;
+    r->transfer_handler = transfer_handler;
+    r->opaque = opaque;
+}
+
+int DMA_read_memory (int nchan, void *buf, int pos, int len)
+{
+    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
+    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+
+    if (r->mode & 0x20) {
+        int i;
+        uint8_t *p = buf;
+
+        cpu_physical_memory_read (addr - pos - len, buf, len);
+        /* What about 16bit transfers? */
+        for (i = 0; i < len >> 1; i++) {
+            uint8_t b = p[len - i - 1];
+            p[i] = b;
+        }
+    }
+    else
+        cpu_physical_memory_read (addr + pos, buf, len);
+
+    return len;
+}
+
+int DMA_write_memory (int nchan, void *buf, int pos, int len)
+{
+    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
+    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+
+    if (r->mode & 0x20) {
+        int i;
+        uint8_t *p = buf;
+
+        cpu_physical_memory_write (addr - pos - len, buf, len);
+        /* What about 16bit transfers? */
+        for (i = 0; i < len; i++) {
+            uint8_t b = p[len - i - 1];
+            p[i] = b;
+        }
+    }
+    else
+        cpu_physical_memory_write (addr + pos, buf, len);
+
+    return len;
+}
+
+/* request the emulator to transfer a new DMA memory block ASAP */
+void DMA_schedule(int nchan)
+{
+    struct dma_cont *d = &dma_controllers[nchan > 3];
+
+    qemu_irq_pulse(*d->cpu_request_exit);
+}
+
+static void dma_reset(void *opaque)
+{
+    struct dma_cont *d = opaque;
+    write_cont (d, (0x0d << d->dshift), 0);
+}
+
+static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
+           nchan, dma_pos, dma_len);
+    return dma_pos;
+}
+
+/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
+static void dma_init2(struct dma_cont *d, int base, int dshift,
+                      int page_base, int pageh_base,
+                      qemu_irq *cpu_request_exit)
+{
+    static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
+    int i;
+
+    d->dshift = dshift;
+    d->cpu_request_exit = cpu_request_exit;
+    for (i = 0; i < 8; i++) {
+        register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
+        register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
+    }
+    for (i = 0; i < ARRAY_SIZE (page_port_list); i++) {
+        register_ioport_write (page_base + page_port_list[i], 1, 1,
+                               write_page, d);
+        register_ioport_read (page_base + page_port_list[i], 1, 1,
+                              read_page, d);
+        if (pageh_base >= 0) {
+            register_ioport_write (pageh_base + page_port_list[i], 1, 1,
+                                   write_pageh, d);
+            register_ioport_read (pageh_base + page_port_list[i], 1, 1,
+                                  read_pageh, d);
+        }
+    }
+    for (i = 0; i < 8; i++) {
+        register_ioport_write (base + ((i + 8) << dshift), 1, 1,
+                               write_cont, d);
+        register_ioport_read (base + ((i + 8) << dshift), 1, 1,
+                              read_cont, d);
+    }
+    qemu_register_reset(dma_reset, d);
+    dma_reset(d);
+    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
+        d->regs[i].transfer_handler = dma_phony_handler;
+    }
+}
+
+static const VMStateDescription vmstate_dma_regs = {
+    .name = "dma_regs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_ARRAY(now, struct dma_regs, 2),
+        VMSTATE_UINT16_ARRAY(base, struct dma_regs, 2),
+        VMSTATE_UINT8(mode, struct dma_regs),
+        VMSTATE_UINT8(page, struct dma_regs),
+        VMSTATE_UINT8(pageh, struct dma_regs),
+        VMSTATE_UINT8(dack, struct dma_regs),
+        VMSTATE_UINT8(eop, struct dma_regs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int dma_post_load(void *opaque, int version_id)
+{
+    DMA_run();
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_dma = {
+    .name = "dma",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = dma_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(command, struct dma_cont),
+        VMSTATE_UINT8(mask, struct dma_cont),
+        VMSTATE_UINT8(flip_flop, struct dma_cont),
+        VMSTATE_INT32(dshift, struct dma_cont),
+        VMSTATE_STRUCT_ARRAY(regs, struct dma_cont, 4, 1, vmstate_dma_regs, struct dma_regs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
+              high_page_enable ? 0x480 : -1, cpu_request_exit);
+    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
+              high_page_enable ? 0x488 : -1, cpu_request_exit);
+    vmstate_register (NULL, 0, &vmstate_dma, &dma_controllers[0]);
+    vmstate_register (NULL, 1, &vmstate_dma, &dma_controllers[1]);
+
+    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
+}
diff --git a/qemu-0.15.x/hw/dp8393x.c b/qemu-0.15.x/hw/dp8393x.c
new file mode 100644
index 0000000..1bcd8ee
--- /dev/null
+++ b/qemu-0.15.x/hw/dp8393x.c
@@ -0,0 +1,914 @@
+/*
+ * QEMU NS SONIC DP8393x netcard
+ *
+ * Copyright (c) 2008-2009 Herve Poussineau
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "net.h"
+#include "mips.h"
+
+//#define DEBUG_SONIC
+
+/* Calculate CRCs properly on Rx packets */
+#define SONIC_CALCULATE_RXCRC
+
+#if defined(SONIC_CALCULATE_RXCRC)
+/* For crc32 */
+#include <zlib.h>
+#endif
+
+#ifdef DEBUG_SONIC
+#define DPRINTF(fmt, ...) \
+do { printf("sonic: " fmt , ##  __VA_ARGS__); } while (0)
+static const char* reg_names[] = {
+    "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
+    "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
+    "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
+    "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
+    "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
+    "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
+    "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
+    "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define SONIC_ERROR(fmt, ...) \
+do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+#define SONIC_CR     0x00
+#define SONIC_DCR    0x01
+#define SONIC_RCR    0x02
+#define SONIC_TCR    0x03
+#define SONIC_IMR    0x04
+#define SONIC_ISR    0x05
+#define SONIC_UTDA   0x06
+#define SONIC_CTDA   0x07
+#define SONIC_TPS    0x08
+#define SONIC_TFC    0x09
+#define SONIC_TSA0   0x0a
+#define SONIC_TSA1   0x0b
+#define SONIC_TFS    0x0c
+#define SONIC_URDA   0x0d
+#define SONIC_CRDA   0x0e
+#define SONIC_CRBA0  0x0f
+#define SONIC_CRBA1  0x10
+#define SONIC_RBWC0  0x11
+#define SONIC_RBWC1  0x12
+#define SONIC_EOBC   0x13
+#define SONIC_URRA   0x14
+#define SONIC_RSA    0x15
+#define SONIC_REA    0x16
+#define SONIC_RRP    0x17
+#define SONIC_RWP    0x18
+#define SONIC_TRBA0  0x19
+#define SONIC_TRBA1  0x1a
+#define SONIC_LLFA   0x1f
+#define SONIC_TTDA   0x20
+#define SONIC_CEP    0x21
+#define SONIC_CAP2   0x22
+#define SONIC_CAP1   0x23
+#define SONIC_CAP0   0x24
+#define SONIC_CE     0x25
+#define SONIC_CDP    0x26
+#define SONIC_CDC    0x27
+#define SONIC_SR     0x28
+#define SONIC_WT0    0x29
+#define SONIC_WT1    0x2a
+#define SONIC_RSC    0x2b
+#define SONIC_CRCT   0x2c
+#define SONIC_FAET   0x2d
+#define SONIC_MPT    0x2e
+#define SONIC_MDT    0x2f
+#define SONIC_DCR2   0x3f
+
+#define SONIC_CR_HTX     0x0001
+#define SONIC_CR_TXP     0x0002
+#define SONIC_CR_RXDIS   0x0004
+#define SONIC_CR_RXEN    0x0008
+#define SONIC_CR_STP     0x0010
+#define SONIC_CR_ST      0x0020
+#define SONIC_CR_RST     0x0080
+#define SONIC_CR_RRRA    0x0100
+#define SONIC_CR_LCAM    0x0200
+#define SONIC_CR_MASK    0x03bf
+
+#define SONIC_DCR_DW     0x0020
+#define SONIC_DCR_LBR    0x2000
+#define SONIC_DCR_EXBUS  0x8000
+
+#define SONIC_RCR_PRX    0x0001
+#define SONIC_RCR_LBK    0x0002
+#define SONIC_RCR_FAER   0x0004
+#define SONIC_RCR_CRCR   0x0008
+#define SONIC_RCR_CRS    0x0020
+#define SONIC_RCR_LPKT   0x0040
+#define SONIC_RCR_BC     0x0080
+#define SONIC_RCR_MC     0x0100
+#define SONIC_RCR_LB0    0x0200
+#define SONIC_RCR_LB1    0x0400
+#define SONIC_RCR_AMC    0x0800
+#define SONIC_RCR_PRO    0x1000
+#define SONIC_RCR_BRD    0x2000
+#define SONIC_RCR_RNT    0x4000
+
+#define SONIC_TCR_PTX    0x0001
+#define SONIC_TCR_BCM    0x0002
+#define SONIC_TCR_FU     0x0004
+#define SONIC_TCR_EXC    0x0040
+#define SONIC_TCR_CRSL   0x0080
+#define SONIC_TCR_NCRS   0x0100
+#define SONIC_TCR_EXD    0x0400
+#define SONIC_TCR_CRCI   0x2000
+#define SONIC_TCR_PINT   0x8000
+
+#define SONIC_ISR_RBE    0x0020
+#define SONIC_ISR_RDE    0x0040
+#define SONIC_ISR_TC     0x0080
+#define SONIC_ISR_TXDN   0x0200
+#define SONIC_ISR_PKTRX  0x0400
+#define SONIC_ISR_PINT   0x0800
+#define SONIC_ISR_LCD    0x1000
+
+typedef struct dp8393xState {
+    /* Hardware */
+    int it_shift;
+    qemu_irq irq;
+#ifdef DEBUG_SONIC
+    int irq_level;
+#endif
+    QEMUTimer *watchdog;
+    int64_t wt_last_update;
+    NICConf conf;
+    NICState *nic;
+    int mmio_index;
+
+    /* Registers */
+    uint8_t cam[16][6];
+    uint16_t regs[0x40];
+
+    /* Temporaries */
+    uint8_t tx_buffer[0x10000];
+    int loopback_packet;
+
+    /* Memory access */
+    void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
+    void* mem_opaque;
+} dp8393xState;
+
+static void dp8393x_update_irq(dp8393xState *s)
+{
+    int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
+
+#ifdef DEBUG_SONIC
+    if (level != s->irq_level) {
+        s->irq_level = level;
+        if (level) {
+            DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
+        } else {
+            DPRINTF("lower irq\n");
+        }
+    }
+#endif
+
+    qemu_set_irq(s->irq, level);
+}
+
+static void do_load_cam(dp8393xState *s)
+{
+    uint16_t data[8];
+    int width, size;
+    uint16_t index = 0;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+    size = sizeof(uint16_t) * 4 * width;
+
+    while (s->regs[SONIC_CDC] & 0x1f) {
+        /* Fill current entry */
+        s->memory_rw(s->mem_opaque,
+            (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+            (uint8_t *)data, size, 0);
+        s->cam[index][0] = data[1 * width] & 0xff;
+        s->cam[index][1] = data[1 * width] >> 8;
+        s->cam[index][2] = data[2 * width] & 0xff;
+        s->cam[index][3] = data[2 * width] >> 8;
+        s->cam[index][4] = data[3 * width] & 0xff;
+        s->cam[index][5] = data[3 * width] >> 8;
+        DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
+            s->cam[index][0], s->cam[index][1], s->cam[index][2],
+            s->cam[index][3], s->cam[index][4], s->cam[index][5]);
+        /* Move to next entry */
+        s->regs[SONIC_CDC]--;
+        s->regs[SONIC_CDP] += size;
+        index++;
+    }
+
+    /* Read CAM enable */
+    s->memory_rw(s->mem_opaque,
+        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+        (uint8_t *)data, size, 0);
+    s->regs[SONIC_CE] = data[0 * width];
+    DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
+    s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
+    dp8393x_update_irq(s);
+}
+
+static void do_read_rra(dp8393xState *s)
+{
+    uint16_t data[8];
+    int width, size;
+
+    /* Read memory */
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+    size = sizeof(uint16_t) * 4 * width;
+    s->memory_rw(s->mem_opaque,
+        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
+        (uint8_t *)data, size, 0);
+
+    /* Update SONIC registers */
+    s->regs[SONIC_CRBA0] = data[0 * width];
+    s->regs[SONIC_CRBA1] = data[1 * width];
+    s->regs[SONIC_RBWC0] = data[2 * width];
+    s->regs[SONIC_RBWC1] = data[3 * width];
+    DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
+        s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
+        s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
+
+    /* Go to next entry */
+    s->regs[SONIC_RRP] += size;
+
+    /* Handle wrap */
+    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
+        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
+    }
+
+    /* Check resource exhaustion */
+    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
+    {
+        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
+        dp8393x_update_irq(s);
+    }
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
+}
+
+static void do_software_reset(dp8393xState *s)
+{
+    qemu_del_timer(s->watchdog);
+
+    s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
+    s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
+}
+
+static void set_next_tick(dp8393xState *s)
+{
+    uint32_t ticks;
+    int64_t delay;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        qemu_del_timer(s->watchdog);
+        return;
+    }
+
+    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+    s->wt_last_update = qemu_get_clock_ns(vm_clock);
+    delay = get_ticks_per_sec() * ticks / 5000000;
+    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
+}
+
+static void update_wt_regs(dp8393xState *s)
+{
+    int64_t elapsed;
+    uint32_t val;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        qemu_del_timer(s->watchdog);
+        return;
+    }
+
+    elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
+    val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+    val -= elapsed / 5000000;
+    s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
+    s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
+    set_next_tick(s);
+
+}
+
+static void do_start_timer(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_STP;
+    set_next_tick(s);
+}
+
+static void do_stop_timer(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_ST;
+    update_wt_regs(s);
+}
+
+static void do_receiver_enable(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
+}
+
+static void do_receiver_disable(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
+}
+
+static void do_transmit_packets(dp8393xState *s)
+{
+    uint16_t data[12];
+    int width, size;
+    int tx_len, len;
+    uint16_t i;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+    while (1) {
+        /* Read memory */
+        DPRINTF("Transmit packet at %08x\n",
+                (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
+        size = sizeof(uint16_t) * 6 * width;
+        s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
+        s->memory_rw(s->mem_opaque,
+            ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
+            (uint8_t *)data, size, 0);
+        tx_len = 0;
+
+        /* Update registers */
+        s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
+        s->regs[SONIC_TPS] = data[1 * width];
+        s->regs[SONIC_TFC] = data[2 * width];
+        s->regs[SONIC_TSA0] = data[3 * width];
+        s->regs[SONIC_TSA1] = data[4 * width];
+        s->regs[SONIC_TFS] = data[5 * width];
+
+        /* Handle programmable interrupt */
+        if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
+            s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
+        } else {
+            s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
+        }
+
+        for (i = 0; i < s->regs[SONIC_TFC]; ) {
+            /* Append fragment */
+            len = s->regs[SONIC_TFS];
+            if (tx_len + len > sizeof(s->tx_buffer)) {
+                len = sizeof(s->tx_buffer) - tx_len;
+            }
+            s->memory_rw(s->mem_opaque,
+                (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
+                &s->tx_buffer[tx_len], len, 0);
+            tx_len += len;
+
+            i++;
+            if (i != s->regs[SONIC_TFC]) {
+                /* Read next fragment details */
+                size = sizeof(uint16_t) * 3 * width;
+                s->memory_rw(s->mem_opaque,
+                    ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
+                    (uint8_t *)data, size, 0);
+                s->regs[SONIC_TSA0] = data[0 * width];
+                s->regs[SONIC_TSA1] = data[1 * width];
+                s->regs[SONIC_TFS] = data[2 * width];
+            }
+        }
+
+        /* Handle Ethernet checksum */
+        if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
+            /* Don't append FCS there, to look like slirp packets
+             * which don't have one */
+        } else {
+            /* Remove existing FCS */
+            tx_len -= 4;
+        }
+
+        if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
+            /* Loopback */
+            s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
+            if (s->nic->nc.info->can_receive(&s->nic->nc)) {
+                s->loopback_packet = 1;
+                s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len);
+            }
+        } else {
+            /* Transmit packet */
+            qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len);
+        }
+        s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
+
+        /* Write status */
+        data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
+        size = sizeof(uint16_t) * width;
+        s->memory_rw(s->mem_opaque,
+            (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
+            (uint8_t *)data, size, 1);
+
+        if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
+            /* Read footer of packet */
+            size = sizeof(uint16_t) * width;
+            s->memory_rw(s->mem_opaque,
+                ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
+                (uint8_t *)data, size, 0);
+            s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
+            if (data[0 * width] & 0x1) {
+                /* EOL detected */
+                break;
+            }
+        }
+    }
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
+    s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
+    dp8393x_update_irq(s);
+}
+
+static void do_halt_transmission(dp8393xState *s)
+{
+    /* Nothing to do */
+}
+
+static void do_command(dp8393xState *s, uint16_t command)
+{
+    if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
+        s->regs[SONIC_CR] &= ~SONIC_CR_RST;
+        return;
+    }
+
+    s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
+
+    if (command & SONIC_CR_HTX)
+        do_halt_transmission(s);
+    if (command & SONIC_CR_TXP)
+        do_transmit_packets(s);
+    if (command & SONIC_CR_RXDIS)
+        do_receiver_disable(s);
+    if (command & SONIC_CR_RXEN)
+        do_receiver_enable(s);
+    if (command & SONIC_CR_STP)
+        do_stop_timer(s);
+    if (command & SONIC_CR_ST)
+        do_start_timer(s);
+    if (command & SONIC_CR_RST)
+        do_software_reset(s);
+    if (command & SONIC_CR_RRRA)
+        do_read_rra(s);
+    if (command & SONIC_CR_LCAM)
+        do_load_cam(s);
+}
+
+static uint16_t read_register(dp8393xState *s, int reg)
+{
+    uint16_t val = 0;
+
+    switch (reg) {
+        /* Update data before reading it */
+        case SONIC_WT0:
+        case SONIC_WT1:
+            update_wt_regs(s);
+            val = s->regs[reg];
+            break;
+        /* Accept read to some registers only when in reset mode */
+        case SONIC_CAP2:
+        case SONIC_CAP1:
+        case SONIC_CAP0:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
+                val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
+            }
+            break;
+        /* All other registers have no special contrainst */
+        default:
+            val = s->regs[reg];
+    }
+
+    DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
+
+    return val;
+}
+
+static void write_register(dp8393xState *s, int reg, uint16_t val)
+{
+    DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
+
+    switch (reg) {
+        /* Command register */
+        case SONIC_CR:
+            do_command(s, val);;
+            break;
+        /* Prevent write to read-only registers */
+        case SONIC_CAP2:
+        case SONIC_CAP1:
+        case SONIC_CAP0:
+        case SONIC_SR:
+        case SONIC_MDT:
+            DPRINTF("writing to reg %d invalid\n", reg);
+            break;
+        /* Accept write to some registers only when in reset mode */
+        case SONIC_DCR:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                s->regs[reg] = val & 0xbfff;
+            } else {
+                DPRINTF("writing to DCR invalid\n");
+            }
+            break;
+        case SONIC_DCR2:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                s->regs[reg] = val & 0xf017;
+            } else {
+                DPRINTF("writing to DCR2 invalid\n");
+            }
+            break;
+        /* 12 lower bytes are Read Only */
+        case SONIC_TCR:
+            s->regs[reg] = val & 0xf000;
+            break;
+        /* 9 lower bytes are Read Only */
+        case SONIC_RCR:
+            s->regs[reg] = val & 0xffe0;
+            break;
+        /* Ignore most significant bit */
+        case SONIC_IMR:
+            s->regs[reg] = val & 0x7fff;
+            dp8393x_update_irq(s);
+            break;
+        /* Clear bits by writing 1 to them */
+        case SONIC_ISR:
+            val &= s->regs[reg];
+            s->regs[reg] &= ~val;
+            if (val & SONIC_ISR_RBE) {
+                do_read_rra(s);
+            }
+            dp8393x_update_irq(s);
+            break;
+        /* Ignore least significant bit */
+        case SONIC_RSA:
+        case SONIC_REA:
+        case SONIC_RRP:
+        case SONIC_RWP:
+            s->regs[reg] = val & 0xfffe;
+            break;
+        /* Invert written value for some registers */
+        case SONIC_CRCT:
+        case SONIC_FAET:
+        case SONIC_MPT:
+            s->regs[reg] = val ^ 0xffff;
+            break;
+        /* All other registers have no special contrainst */
+        default:
+            s->regs[reg] = val;
+    }
+
+    if (reg == SONIC_WT0 || reg == SONIC_WT1) {
+        set_next_tick(s);
+    }
+}
+
+static void dp8393x_watchdog(void *opaque)
+{
+    dp8393xState *s = opaque;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        return;
+    }
+
+    s->regs[SONIC_WT1] = 0xffff;
+    s->regs[SONIC_WT0] = 0xffff;
+    set_next_tick(s);
+
+    /* Signal underflow */
+    s->regs[SONIC_ISR] |= SONIC_ISR_TC;
+    dp8393x_update_irq(s);
+}
+
+static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
+{
+    dp8393xState *s = opaque;
+    int reg;
+
+    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+        return 0;
+    }
+
+    reg = addr >> s->it_shift;
+    return read_register(s, reg);
+}
+
+static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
+    return (v >> (8 * (addr & 0x1))) & 0xff;
+}
+
+static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = dp8393x_readw(opaque, addr);
+    v |= dp8393x_readw(opaque, addr + 2) << 16;
+    return v;
+}
+
+static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    dp8393xState *s = opaque;
+    int reg;
+
+    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+        return;
+    }
+
+    reg = addr >> s->it_shift;
+
+    write_register(s, reg, (uint16_t)val);
+}
+
+static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
+
+    switch (addr & 3) {
+    case 0:
+        val = val | (old_val & 0xff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0x00ff);
+        break;
+    }
+    dp8393x_writew(opaque, addr & ~0x1, val);
+}
+
+static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    dp8393x_writew(opaque, addr, val & 0xffff);
+    dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
+}
+
+static CPUReadMemoryFunc * const dp8393x_read[3] = {
+    dp8393x_readb,
+    dp8393x_readw,
+    dp8393x_readl,
+};
+
+static CPUWriteMemoryFunc * const dp8393x_write[3] = {
+    dp8393x_writeb,
+    dp8393x_writew,
+    dp8393x_writel,
+};
+
+static int nic_can_receive(VLANClientState *nc)
+{
+    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
+        return 0;
+    if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
+        return 0;
+    return 1;
+}
+
+static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    int i;
+
+    /* Check for runt packet (remember that checksum is not there) */
+    if (size < 64 - 4) {
+        return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
+    }
+
+    /* Check promiscuous mode */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
+        return 0;
+    }
+
+    /* Check multicast packets */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
+        return SONIC_RCR_MC;
+    }
+
+    /* Check broadcast */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
+        return SONIC_RCR_BC;
+    }
+
+    /* Check CAM */
+    for (i = 0; i < 16; i++) {
+        if (s->regs[SONIC_CE] & (1 << i)) {
+             /* Entry enabled */
+             if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
+                 return 0;
+             }
+        }
+    }
+
+    return -1;
+}
+
+static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
+{
+    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    uint16_t data[10];
+    int packet_type;
+    uint32_t available, address;
+    int width, rx_len = size;
+    uint32_t checksum;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+    s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
+        SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
+
+    packet_type = receive_filter(s, buf, size);
+    if (packet_type < 0) {
+        DPRINTF("packet not for netcard\n");
+        return -1;
+    }
+
+    /* XXX: Check byte ordering */
+
+    /* Check for EOL */
+    if (s->regs[SONIC_LLFA] & 0x1) {
+        /* Are we still in resource exhaustion? */
+        size = sizeof(uint16_t) * 1 * width;
+        address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
+        s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
+        if (data[0 * width] & 0x1) {
+            /* Still EOL ; stop reception */
+            return -1;
+        } else {
+            s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+        }
+    }
+
+    /* Save current position */
+    s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
+    s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
+
+    /* Calculate the ethernet checksum */
+#ifdef SONIC_CALCULATE_RXCRC
+    checksum = cpu_to_le32(crc32(0, buf, rx_len));
+#else
+    checksum = 0;
+#endif
+
+    /* Put packet into RBA */
+    DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
+    address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
+    s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
+    address += rx_len;
+    s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
+    rx_len += 4;
+    s->regs[SONIC_CRBA1] = address >> 16;
+    s->regs[SONIC_CRBA0] = address & 0xffff;
+    available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
+    available -= rx_len / 2;
+    s->regs[SONIC_RBWC1] = available >> 16;
+    s->regs[SONIC_RBWC0] = available & 0xffff;
+
+    /* Update status */
+    if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
+        s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
+    }
+    s->regs[SONIC_RCR] |= packet_type;
+    s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
+    if (s->loopback_packet) {
+        s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
+        s->loopback_packet = 0;
+    }
+
+    /* Write status to memory */
+    DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
+    data[0 * width] = s->regs[SONIC_RCR]; /* status */
+    data[1 * width] = rx_len; /* byte count */
+    data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
+    data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
+    data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
+    size = sizeof(uint16_t) * 5 * width;
+    s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
+
+    /* Move to next descriptor */
+    size = sizeof(uint16_t) * width;
+    s->memory_rw(s->mem_opaque,
+        ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
+        (uint8_t *)data, size, 0);
+    s->regs[SONIC_LLFA] = data[0 * width];
+    if (s->regs[SONIC_LLFA] & 0x1) {
+        /* EOL detected */
+        s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
+    } else {
+        data[0 * width] = 0; /* in_use */
+        s->memory_rw(s->mem_opaque,
+            ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
+            (uint8_t *)data, size, 1);
+        s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+        s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
+        s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
+
+        if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
+            /* Read next RRA */
+            do_read_rra(s);
+        }
+    }
+
+    /* Done */
+    dp8393x_update_irq(s);
+
+    return size;
+}
+
+static void nic_reset(void *opaque)
+{
+    dp8393xState *s = opaque;
+    qemu_del_timer(s->watchdog);
+
+    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
+    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
+    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
+    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
+    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
+    s->regs[SONIC_IMR] = 0;
+    s->regs[SONIC_ISR] = 0;
+    s->regs[SONIC_DCR2] = 0;
+    s->regs[SONIC_EOBC] = 0x02F8;
+    s->regs[SONIC_RSC] = 0;
+    s->regs[SONIC_CE] = 0;
+    s->regs[SONIC_RSC] = 0;
+
+    /* Network cable is connected */
+    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
+
+    dp8393x_update_irq(s);
+}
+
+static void nic_cleanup(VLANClientState *nc)
+{
+    dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    cpu_unregister_io_memory(s->mmio_index);
+
+    qemu_del_timer(s->watchdog);
+    qemu_free_timer(s->watchdog);
+
+    qemu_free(s);
+}
+
+static NetClientInfo net_dp83932_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = nic_can_receive,
+    .receive = nic_receive,
+    .cleanup = nic_cleanup,
+};
+
+void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
+                  qemu_irq irq, void* mem_opaque,
+                  void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
+{
+    dp8393xState *s;
+
+    qemu_check_nic_model(nd, "dp83932");
+
+    s = qemu_mallocz(sizeof(dp8393xState));
+
+    s->mem_opaque = mem_opaque;
+    s->memory_rw = memory_rw;
+    s->it_shift = it_shift;
+    s->irq = irq;
+    s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
+    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
+
+    s->conf.macaddr = nd->macaddr;
+    s->conf.vlan = nd->vlan;
+    s->conf.peer = nd->netdev;
+
+    s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
+
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    qemu_register_reset(nic_reset, s);
+    nic_reset(s);
+
+    s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
+}
diff --git a/qemu-0.15.x/hw/ds1225y.c b/qemu-0.15.x/hw/ds1225y.c
new file mode 100644
index 0000000..662d7b5
--- /dev/null
+++ b/qemu-0.15.x/hw/ds1225y.c
@@ -0,0 +1,184 @@
+/*
+ * QEMU NVRAM emulation for DS1225Y chip
+ *
+ * Copyright (c) 2007-2008 Hervé Poussineau
+ *
+ * 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 "sysbus.h"
+#include "trace.h"
+
+typedef struct {
+    DeviceState qdev;
+    uint32_t chip_size;
+    char *filename;
+    QEMUFile *file;
+    uint8_t *contents;
+} NvRamState;
+
+static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
+{
+    NvRamState *s = opaque;
+    uint32_t val;
+
+    val = s->contents[addr];
+    trace_nvram_read(addr, val);
+    return val;
+}
+
+static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = nvram_readb(opaque, addr);
+    v |= nvram_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = nvram_readb(opaque, addr);
+    v |= nvram_readb(opaque, addr + 1) << 8;
+    v |= nvram_readb(opaque, addr + 2) << 16;
+    v |= nvram_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    NvRamState *s = opaque;
+
+    val &= 0xff;
+    trace_nvram_write(addr, s->contents[addr], val);
+
+    s->contents[addr] = val;
+    if (s->file) {
+        qemu_fseek(s->file, addr, SEEK_SET);
+        qemu_put_byte(s->file, (int)val);
+        qemu_fflush(s->file);
+    }
+}
+
+static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    nvram_writeb(opaque, addr, val & 0xff);
+    nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    nvram_writeb(opaque, addr, val & 0xff);
+    nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    nvram_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+static CPUReadMemoryFunc * const nvram_read[] = {
+    &nvram_readb,
+    &nvram_readw,
+    &nvram_readl,
+};
+
+static CPUWriteMemoryFunc * const nvram_write[] = {
+    &nvram_writeb,
+    &nvram_writew,
+    &nvram_writel,
+};
+
+static int nvram_post_load(void *opaque, int version_id)
+{
+    NvRamState *s = opaque;
+
+    /* Close file, as filename may has changed in load/store process */
+    if (s->file) {
+        qemu_fclose(s->file);
+    }
+
+    /* Write back nvram contents */
+    s->file = qemu_fopen(s->filename, "wb");
+    if (s->file) {
+        /* Write back contents, as 'wb' mode cleaned the file */
+        qemu_put_buffer(s->file, s->contents, s->chip_size);
+        qemu_fflush(s->file);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_nvram = {
+    .name = "nvram",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = nvram_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
+                              vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    NvRamState nvram;
+} SysBusNvRamState;
+
+static int nvram_sysbus_initfn(SysBusDevice *dev)
+{
+    NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
+    QEMUFile *file;
+    int s_io;
+
+    s->contents = qemu_mallocz(s->chip_size);
+
+    s_io = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                  DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, s->chip_size, s_io);
+
+    /* Read current file */
+    file = qemu_fopen(s->filename, "rb");
+    if (file) {
+        /* Read nvram contents */
+        qemu_get_buffer(file, s->contents, s->chip_size);
+        qemu_fclose(file);
+    }
+    nvram_post_load(s, 0);
+
+    return 0;
+}
+
+static SysBusDeviceInfo nvram_sysbus_info = {
+    .qdev.name  = "ds1225y",
+    .qdev.size  = sizeof(SysBusNvRamState),
+    .qdev.vmsd  = &vmstate_nvram,
+    .init       = nvram_sysbus_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+        DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void nvram_register(void)
+{
+    sysbus_register_withprop(&nvram_sysbus_info);
+}
+
+device_init(nvram_register)
diff --git a/qemu-0.15.x/hw/ds1338.c b/qemu-0.15.x/hw/ds1338.c
new file mode 100644
index 0000000..3522af5
--- /dev/null
+++ b/qemu-0.15.x/hw/ds1338.c
@@ -0,0 +1,132 @@
+/*
+ * MAXIM DS1338 I2C RTC+NVRAM
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "i2c.h"
+
+typedef struct {
+    i2c_slave i2c;
+    time_t offset;
+    struct tm now;
+    uint8_t nvram[56];
+    int ptr;
+    int addr_byte;
+} DS1338State;
+
+static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+
+    switch (event) {
+    case I2C_START_RECV:
+        qemu_get_timedate(&s->now, s->offset);
+        s->nvram[0] = to_bcd(s->now.tm_sec);
+        s->nvram[1] = to_bcd(s->now.tm_min);
+        if (s->nvram[2] & 0x40) {
+            s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40;
+            if (s->now.tm_hour >= 12) {
+                s->nvram[2] |= 0x20;
+            }
+        } else {
+            s->nvram[2] = to_bcd(s->now.tm_hour);
+        }
+        s->nvram[3] = to_bcd(s->now.tm_wday) + 1;
+        s->nvram[4] = to_bcd(s->now.tm_mday);
+        s->nvram[5] = to_bcd(s->now.tm_mon) + 1;
+        s->nvram[6] = to_bcd(s->now.tm_year - 100);
+        break;
+    case I2C_START_SEND:
+        s->addr_byte = 1;
+        break;
+    default:
+        break;
+    }
+}
+
+static int ds1338_recv(i2c_slave *i2c)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+    uint8_t res;
+
+    res  = s->nvram[s->ptr];
+    s->ptr = (s->ptr + 1) & 0xff;
+    return res;
+}
+
+static int ds1338_send(i2c_slave *i2c, uint8_t data)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+    if (s->addr_byte) {
+        s->ptr = data;
+        s->addr_byte = 0;
+        return 0;
+    }
+    s->nvram[s->ptr - 8] = data;
+    if (data < 8) {
+        qemu_get_timedate(&s->now, s->offset);
+        switch(data) {
+        case 0:
+            /* TODO: Implement CH (stop) bit.  */
+            s->now.tm_sec = from_bcd(data & 0x7f);
+            break;
+        case 1:
+            s->now.tm_min = from_bcd(data & 0x7f);
+            break;
+        case 2:
+            if (data & 0x40) {
+                if (data & 0x20) {
+                    data = from_bcd(data & 0x4f) + 11;
+                } else {
+                    data = from_bcd(data & 0x1f) - 1;
+                }
+            } else {
+                data = from_bcd(data);
+            }
+            s->now.tm_hour = data;
+            break;
+        case 3:
+            s->now.tm_wday = from_bcd(data & 7) - 1;
+            break;
+        case 4:
+            s->now.tm_mday = from_bcd(data & 0x3f);
+            break;
+        case 5:
+            s->now.tm_mon = from_bcd(data & 0x1f) - 1;
+        case 6:
+            s->now.tm_year = from_bcd(data) + 100;
+            break;
+        case 7:
+            /* Control register. Currently ignored.  */
+            break;
+        }
+        s->offset = qemu_timedate_diff(&s->now);
+    }
+    s->ptr = (s->ptr + 1) & 0xff;
+    return 0;
+}
+
+static int ds1338_init(i2c_slave *i2c)
+{
+    return 0;
+}
+
+static I2CSlaveInfo ds1338_info = {
+    .qdev.name = "ds1338",
+    .qdev.size = sizeof(DS1338State),
+    .init = ds1338_init,
+    .event = ds1338_event,
+    .recv = ds1338_recv,
+    .send = ds1338_send,
+};
+
+static void ds1338_register_devices(void)
+{
+    i2c_register_slave(&ds1338_info);
+}
+
+device_init(ds1338_register_devices)
diff --git a/qemu-0.15.x/hw/dummy_m68k.c b/qemu-0.15.x/hw/dummy_m68k.c
new file mode 100644
index 0000000..eed9e38
--- /dev/null
+++ b/qemu-0.15.x/hw/dummy_m68k.c
@@ -0,0 +1,79 @@
+/*
+ * Dummy board with just RAM and CPU for use as an ISS.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+
+#define KERNEL_LOAD_ADDR 0x10000
+
+/* Board init.  */
+
+static void dummy_m68k_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    target_phys_addr_t entry;
+
+    if (!cpu_model)
+        cpu_model = "cfv4e";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find m68k CPU definition\n");
+        exit(1);
+    }
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+
+    /* RAM at address zero */
+    cpu_register_physical_memory(0, ram_size,
+        qemu_ram_alloc(NULL, "dummy_m68k.ram", ram_size) | IO_MEM_RAM);
+
+    /* Load kernel.  */
+    if (kernel_filename) {
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               NULL, NULL, 1, ELF_MACHINE, 0);
+        entry = elf_entry;
+        if (kernel_size < 0) {
+            kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+        }
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
+            entry = KERNEL_LOAD_ADDR;
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    } else {
+        entry = 0;
+    }
+    env->pc = entry;
+}
+
+static QEMUMachine dummy_m68k_machine = {
+    .name = "dummy",
+    .desc = "Dummy board",
+    .init = dummy_m68k_init,
+};
+
+static void dummy_m68k_machine_init(void)
+{
+    qemu_register_machine(&dummy_m68k_machine);
+}
+
+machine_init(dummy_m68k_machine_init);
diff --git a/qemu-0.15.x/hw/e1000.c b/qemu-0.15.x/hw/e1000.c
new file mode 100644
index 0000000..96d84f9
--- /dev/null
+++ b/qemu-0.15.x/hw/e1000.c
@@ -0,0 +1,1235 @@
+/*
+ * QEMU e1000 emulation
+ *
+ * Software developer's manual:
+ * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ *
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hw.h"
+#include "pci.h"
+#include "net.h"
+#include "net/checksum.h"
+#include "loader.h"
+#include "sysemu.h"
+
+#include "e1000_hw.h"
+
+#define E1000_DEBUG
+
+#ifdef E1000_DEBUG
+enum {
+    DEBUG_GENERAL,	DEBUG_IO,	DEBUG_MMIO,	DEBUG_INTERRUPT,
+    DEBUG_RX,		DEBUG_TX,	DEBUG_MDIC,	DEBUG_EEPROM,
+    DEBUG_UNKNOWN,	DEBUG_TXSUM,	DEBUG_TXERR,	DEBUG_RXERR,
+    DEBUG_RXFILTER,	DEBUG_NOTYET,
+};
+#define DBGBIT(x)	(1<<DEBUG_##x)
+static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
+
+#define	DBGOUT(what, fmt, ...) do { \
+    if (debugflags & DBGBIT(what)) \
+        fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
+    } while (0)
+#else
+#define	DBGOUT(what, fmt, ...) do {} while (0)
+#endif
+
+#define IOPORT_SIZE       0x40
+#define PNPMMIO_SIZE      0x20000
+#define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
+
+/*
+ * HW models:
+ *  E1000_DEV_ID_82540EM works with Windows and Linux
+ *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22,
+ *	appears to perform better than 82540EM, but breaks with Linux 2.6.18
+ *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
+ *  Others never tested
+ */
+enum { E1000_DEVID = E1000_DEV_ID_82540EM };
+
+/*
+ * May need to specify additional MAC-to-PHY entries --
+ * Intel's Windows driver refuses to initialize unless they match
+ */
+enum {
+    PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?		0xcc2 :
+                   E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?	0xc30 :
+                   /* default to E1000_DEV_ID_82540EM */	0xc20
+};
+
+typedef struct E1000State_st {
+    PCIDevice dev;
+    NICState *nic;
+    NICConf conf;
+    int mmio_index;
+
+    uint32_t mac_reg[0x8000];
+    uint16_t phy_reg[0x20];
+    uint16_t eeprom_data[64];
+
+    uint32_t rxbuf_size;
+    uint32_t rxbuf_min_shift;
+    int check_rxov;
+    struct e1000_tx {
+        unsigned char header[256];
+        unsigned char vlan_header[4];
+        /* Fields vlan and data must not be reordered or separated. */
+        unsigned char vlan[4];
+        unsigned char data[0x10000];
+        uint16_t size;
+        unsigned char sum_needed;
+        unsigned char vlan_needed;
+        uint8_t ipcss;
+        uint8_t ipcso;
+        uint16_t ipcse;
+        uint8_t tucss;
+        uint8_t tucso;
+        uint16_t tucse;
+        uint8_t hdr_len;
+        uint16_t mss;
+        uint32_t paylen;
+        uint16_t tso_frames;
+        char tse;
+        int8_t ip;
+        int8_t tcp;
+        char cptse;     // current packet tse bit
+    } tx;
+
+    struct {
+        uint32_t val_in;	// shifted in from guest driver
+        uint16_t bitnum_in;
+        uint16_t bitnum_out;
+        uint16_t reading;
+        uint32_t old_eecd;
+    } eecd_state;
+} E1000State;
+
+#define	defreg(x)	x = (E1000_##x>>2)
+enum {
+    defreg(CTRL),	defreg(EECD),	defreg(EERD),	defreg(GPRC),
+    defreg(GPTC),	defreg(ICR),	defreg(ICS),	defreg(IMC),
+    defreg(IMS),	defreg(LEDCTL),	defreg(MANC),	defreg(MDIC),
+    defreg(MPC),	defreg(PBA),	defreg(RCTL),	defreg(RDBAH),
+    defreg(RDBAL),	defreg(RDH),	defreg(RDLEN),	defreg(RDT),
+    defreg(STATUS),	defreg(SWSM),	defreg(TCTL),	defreg(TDBAH),
+    defreg(TDBAL),	defreg(TDH),	defreg(TDLEN),	defreg(TDT),
+    defreg(TORH),	defreg(TORL),	defreg(TOTH),	defreg(TOTL),
+    defreg(TPR),	defreg(TPT),	defreg(TXDCTL),	defreg(WUFC),
+    defreg(RA),		defreg(MTA),	defreg(CRCERRS),defreg(VFTA),
+    defreg(VET),
+};
+
+enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
+static const char phy_regcap[0x20] = {
+    [PHY_STATUS] = PHY_R,	[M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
+    [PHY_ID1] = PHY_R,		[M88E1000_PHY_SPEC_CTRL] = PHY_RW,
+    [PHY_CTRL] = PHY_RW,	[PHY_1000T_CTRL] = PHY_RW,
+    [PHY_LP_ABILITY] = PHY_R,	[PHY_1000T_STATUS] = PHY_R,
+    [PHY_AUTONEG_ADV] = PHY_RW,	[M88E1000_RX_ERR_CNTR] = PHY_R,
+    [PHY_ID2] = PHY_R,		[M88E1000_PHY_SPEC_STATUS] = PHY_R
+};
+
+static void
+ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
+           pcibus_t size, int type)
+{
+    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
+           " size=0x%08"FMT_PCIBUS"\n", addr, size);
+}
+
+static void
+set_interrupt_cause(E1000State *s, int index, uint32_t val)
+{
+    if (val)
+        val |= E1000_ICR_INT_ASSERTED;
+    s->mac_reg[ICR] = val;
+    s->mac_reg[ICS] = val;
+    qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
+}
+
+static void
+set_ics(E1000State *s, int index, uint32_t val)
+{
+    DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
+        s->mac_reg[IMS]);
+    set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
+}
+
+static int
+rxbufsize(uint32_t v)
+{
+    v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
+         E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
+         E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
+    switch (v) {
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
+        return 16384;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
+        return 8192;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
+        return 4096;
+    case E1000_RCTL_SZ_1024:
+        return 1024;
+    case E1000_RCTL_SZ_512:
+        return 512;
+    case E1000_RCTL_SZ_256:
+        return 256;
+    }
+    return 2048;
+}
+
+static void
+set_ctrl(E1000State *s, int index, uint32_t val)
+{
+    /* RST is self clearing */
+    s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+}
+
+static void
+set_rx_control(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[RCTL] = val;
+    s->rxbuf_size = rxbufsize(val);
+    s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
+    DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
+           s->mac_reg[RCTL]);
+}
+
+static void
+set_mdic(E1000State *s, int index, uint32_t val)
+{
+    uint32_t data = val & E1000_MDIC_DATA_MASK;
+    uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+
+    if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
+        val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
+    else if (val & E1000_MDIC_OP_READ) {
+        DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
+        if (!(phy_regcap[addr] & PHY_R)) {
+            DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
+            val |= E1000_MDIC_ERROR;
+        } else
+            val = (val ^ data) | s->phy_reg[addr];
+    } else if (val & E1000_MDIC_OP_WRITE) {
+        DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
+        if (!(phy_regcap[addr] & PHY_W)) {
+            DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
+            val |= E1000_MDIC_ERROR;
+        } else
+            s->phy_reg[addr] = data;
+    }
+    s->mac_reg[MDIC] = val | E1000_MDIC_READY;
+    set_ics(s, 0, E1000_ICR_MDAC);
+}
+
+static uint32_t
+get_eecd(E1000State *s, int index)
+{
+    uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
+
+    DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
+           s->eecd_state.bitnum_out, s->eecd_state.reading);
+    if (!s->eecd_state.reading ||
+        ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
+          ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
+        ret |= E1000_EECD_DO;
+    return ret;
+}
+
+static void
+set_eecd(E1000State *s, int index, uint32_t val)
+{
+    uint32_t oldval = s->eecd_state.old_eecd;
+
+    s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
+            E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
+    if (!(E1000_EECD_CS & val))			// CS inactive; nothing to do
+	return;
+    if (E1000_EECD_CS & (val ^ oldval)) {	// CS rise edge; reset state
+	s->eecd_state.val_in = 0;
+	s->eecd_state.bitnum_in = 0;
+	s->eecd_state.bitnum_out = 0;
+	s->eecd_state.reading = 0;
+    }
+    if (!(E1000_EECD_SK & (val ^ oldval)))	// no clock edge
+        return;
+    if (!(E1000_EECD_SK & val)) {		// falling edge
+        s->eecd_state.bitnum_out++;
+        return;
+    }
+    s->eecd_state.val_in <<= 1;
+    if (val & E1000_EECD_DI)
+        s->eecd_state.val_in |= 1;
+    if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
+        s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
+        s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
+            EEPROM_READ_OPCODE_MICROWIRE);
+    }
+    DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
+           s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
+           s->eecd_state.reading);
+}
+
+static uint32_t
+flash_eerd_read(E1000State *s, int x)
+{
+    unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
+
+    if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
+        return (s->mac_reg[EERD]);
+
+    if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
+        return (E1000_EEPROM_RW_REG_DONE | r);
+
+    return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
+           E1000_EEPROM_RW_REG_DONE | r);
+}
+
+static void
+putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
+{
+    uint32_t sum;
+
+    if (cse && cse < n)
+        n = cse + 1;
+    if (sloc < n-1) {
+        sum = net_checksum_add(n-css, data+css);
+        cpu_to_be16wu((uint16_t *)(data + sloc),
+                      net_checksum_finish(sum));
+    }
+}
+
+static inline int
+vlan_enabled(E1000State *s)
+{
+    return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
+}
+
+static inline int
+vlan_rx_filter_enabled(E1000State *s)
+{
+    return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
+}
+
+static inline int
+is_vlan_packet(E1000State *s, const uint8_t *buf)
+{
+    return (be16_to_cpup((uint16_t *)(buf + 12)) ==
+                le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+}
+
+static inline int
+is_vlan_txd(uint32_t txd_lower)
+{
+    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
+}
+
+/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
+ * fill it in, just pad descriptor length by 4 bytes unless guest
+ * told us to strip it off the packet. */
+static inline int
+fcs_len(E1000State *s)
+{
+    return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
+}
+
+static void
+xmit_seg(E1000State *s)
+{
+    uint16_t len, *sp;
+    unsigned int frames = s->tx.tso_frames, css, sofar, n;
+    struct e1000_tx *tp = &s->tx;
+
+    if (tp->tse && tp->cptse) {
+        css = tp->ipcss;
+        DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
+               frames, tp->size, css);
+        if (tp->ip) {		// IPv4
+            cpu_to_be16wu((uint16_t *)(tp->data+css+2),
+                          tp->size - css);
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
+                          be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
+        } else			// IPv6
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
+                          tp->size - css);
+        css = tp->tucss;
+        len = tp->size - css;
+        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
+        if (tp->tcp) {
+            sofar = frames * tp->mss;
+            cpu_to_be32wu((uint32_t *)(tp->data+css+4),	// seq
+                be32_to_cpupu((uint32_t *)(tp->data+css+4))+sofar);
+            if (tp->paylen - sofar > tp->mss)
+                tp->data[css + 13] &= ~9;		// PSH, FIN
+        } else	// UDP
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);
+        if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
+            unsigned int phsum;
+            // add pseudo-header length before checksum calculation
+            sp = (uint16_t *)(tp->data + tp->tucso);
+            phsum = be16_to_cpup(sp) + len;
+            phsum = (phsum >> 16) + (phsum & 0xffff);
+            cpu_to_be16wu(sp, phsum);
+        }
+        tp->tso_frames++;
+    }
+
+    if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
+        putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
+    if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
+        putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
+    if (tp->vlan_needed) {
+        memmove(tp->vlan, tp->data, 4);
+        memmove(tp->data, tp->data + 4, 8);
+        memcpy(tp->data + 8, tp->vlan_header, 4);
+        qemu_send_packet(&s->nic->nc, tp->vlan, tp->size + 4);
+    } else
+        qemu_send_packet(&s->nic->nc, tp->data, tp->size);
+    s->mac_reg[TPT]++;
+    s->mac_reg[GPTC]++;
+    n = s->mac_reg[TOTL];
+    if ((s->mac_reg[TOTL] += s->tx.size) < n)
+        s->mac_reg[TOTH]++;
+}
+
+static void
+process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
+{
+    uint32_t txd_lower = le32_to_cpu(dp->lower.data);
+    uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
+    unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
+    unsigned int msh = 0xfffff, hdr = 0;
+    uint64_t addr;
+    struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
+    struct e1000_tx *tp = &s->tx;
+
+    if (dtype == E1000_TXD_CMD_DEXT) {	// context descriptor
+        op = le32_to_cpu(xp->cmd_and_length);
+        tp->ipcss = xp->lower_setup.ip_fields.ipcss;
+        tp->ipcso = xp->lower_setup.ip_fields.ipcso;
+        tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
+        tp->tucss = xp->upper_setup.tcp_fields.tucss;
+        tp->tucso = xp->upper_setup.tcp_fields.tucso;
+        tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
+        tp->paylen = op & 0xfffff;
+        tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
+        tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
+        tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
+        tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
+        tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
+        tp->tso_frames = 0;
+        if (tp->tucso == 0) {	// this is probably wrong
+            DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
+            tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
+        }
+        return;
+    } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
+        // data descriptor
+        if (tp->size == 0) {
+            tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+        }
+        tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
+    } else {
+        // legacy descriptor
+        tp->cptse = 0;
+    }
+
+    if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
+        (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
+        tp->vlan_needed = 1;
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header),
+                      le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
+                      le16_to_cpu(dp->upper.fields.special));
+    }
+        
+    addr = le64_to_cpu(dp->buffer_addr);
+    if (tp->tse && tp->cptse) {
+        hdr = tp->hdr_len;
+        msh = hdr + tp->mss;
+        do {
+            bytes = split_size;
+            if (tp->size + bytes > msh)
+                bytes = msh - tp->size;
+            cpu_physical_memory_read(addr, tp->data + tp->size, bytes);
+            if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
+                memmove(tp->header, tp->data, hdr);
+            tp->size = sz;
+            addr += bytes;
+            if (sz == msh) {
+                xmit_seg(s);
+                memmove(tp->data, tp->header, hdr);
+                tp->size = hdr;
+            }
+        } while (split_size -= bytes);
+    } else if (!tp->tse && tp->cptse) {
+        // context descriptor TSE is not set, while data descriptor TSE is set
+        DBGOUT(TXERR, "TCP segmentaion Error\n");
+    } else {
+        cpu_physical_memory_read(addr, tp->data + tp->size, split_size);
+        tp->size += split_size;
+    }
+
+    if (!(txd_lower & E1000_TXD_CMD_EOP))
+        return;
+    if (!(tp->tse && tp->cptse && tp->size < hdr))
+        xmit_seg(s);
+    tp->tso_frames = 0;
+    tp->sum_needed = 0;
+    tp->vlan_needed = 0;
+    tp->size = 0;
+    tp->cptse = 0;
+}
+
+static uint32_t
+txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp)
+{
+    uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
+
+    if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
+        return 0;
+    txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
+                ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
+    dp->upper.data = cpu_to_le32(txd_upper);
+    cpu_physical_memory_write(base + ((char *)&dp->upper - (char *)dp),
+                              (void *)&dp->upper, sizeof(dp->upper));
+    return E1000_ICR_TXDW;
+}
+
+static uint64_t tx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[TDBAH];
+    uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
+static void
+start_xmit(E1000State *s)
+{
+    target_phys_addr_t base;
+    struct e1000_tx_desc desc;
+    uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
+
+    if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
+        DBGOUT(TX, "tx disabled\n");
+        return;
+    }
+
+    while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
+        base = tx_desc_base(s) +
+               sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
+        cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
+
+        DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
+               (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
+               desc.upper.data);
+
+        process_tx_desc(s, &desc);
+        cause |= txdesc_writeback(base, &desc);
+
+        if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
+            s->mac_reg[TDH] = 0;
+        /*
+         * the following could happen only if guest sw assigns
+         * bogus values to TDT/TDLEN.
+         * there's nothing too intelligent we could do about this.
+         */
+        if (s->mac_reg[TDH] == tdh_start) {
+            DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
+                   tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
+            break;
+        }
+    }
+    set_ics(s, 0, cause);
+}
+
+static int
+receive_filter(E1000State *s, const uint8_t *buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    static const int mta_shift[] = {4, 3, 2, 0};
+    uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
+
+    if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
+        uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
+        uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
+                                     ((vid >> 5) & 0x7f));
+        if ((vfta & (1 << (vid & 0x1f))) == 0)
+            return 0;
+    }
+
+    if (rctl & E1000_RCTL_UPE)			// promiscuous
+        return 1;
+
+    if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE))	// promiscuous mcast
+        return 1;
+
+    if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast))
+        return 1;
+
+    for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
+        if (!(rp[1] & E1000_RAH_AV))
+            continue;
+        ra[0] = cpu_to_le32(rp[0]);
+        ra[1] = cpu_to_le32(rp[1]);
+        if (!memcmp(buf, (uint8_t *)ra, 6)) {
+            DBGOUT(RXFILTER,
+                   "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   (int)(rp - s->mac_reg - RA)/2,
+                   buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+            return 1;
+        }
+    }
+    DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+    f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
+    f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
+    if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f)))
+        return 1;
+    DBGOUT(RXFILTER,
+           "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
+           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+           (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
+           s->mac_reg[MTA + (f >> 5)]);
+
+    return 0;
+}
+
+static void
+e1000_set_link_status(VLANClientState *nc)
+{
+    E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    uint32_t old_status = s->mac_reg[STATUS];
+
+    if (nc->link_down)
+        s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+    else
+        s->mac_reg[STATUS] |= E1000_STATUS_LU;
+
+    if (s->mac_reg[STATUS] != old_status)
+        set_ics(s, 0, E1000_ICR_LSC);
+}
+
+static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
+{
+    int bufs;
+    /* Fast-path short packets */
+    if (total_size <= s->rxbuf_size) {
+        return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
+    }
+    if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
+        bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
+        bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
+            s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else {
+        return false;
+    }
+    return total_size <= bufs * s->rxbuf_size;
+}
+
+static int
+e1000_can_receive(VLANClientState *nc)
+{
+    E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
+}
+
+static uint64_t rx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[RDBAH];
+    uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
+static ssize_t
+e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    struct e1000_rx_desc desc;
+    target_phys_addr_t base;
+    unsigned int n, rdt;
+    uint32_t rdh_start;
+    uint16_t vlan_special = 0;
+    uint8_t vlan_status = 0, vlan_offset = 0;
+    uint8_t min_buf[MIN_BUF_SIZE];
+    size_t desc_offset;
+    size_t desc_size;
+    size_t total_size;
+
+    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
+        return -1;
+
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+
+    if (!receive_filter(s, buf, size))
+        return size;
+
+    if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
+        vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
+        memmove((uint8_t *)buf + 4, buf, 12);
+        vlan_status = E1000_RXD_STAT_VP;
+        vlan_offset = 4;
+        size -= 4;
+    }
+
+    rdh_start = s->mac_reg[RDH];
+    desc_offset = 0;
+    total_size = size + fcs_len(s);
+    if (!e1000_has_rxbufs(s, total_size)) {
+            set_ics(s, 0, E1000_ICS_RXO);
+            return -1;
+    }
+    do {
+        desc_size = total_size - desc_offset;
+        if (desc_size > s->rxbuf_size) {
+            desc_size = s->rxbuf_size;
+        }
+        base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
+        cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
+        desc.special = vlan_special;
+        desc.status |= (vlan_status | E1000_RXD_STAT_DD);
+        if (desc.buffer_addr) {
+            if (desc_offset < size) {
+                size_t copy_size = size - desc_offset;
+                if (copy_size > s->rxbuf_size) {
+                    copy_size = s->rxbuf_size;
+                }
+                cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
+                                          (void *)(buf + desc_offset + vlan_offset),
+                                          copy_size);
+            }
+            desc_offset += desc_size;
+            desc.length = cpu_to_le16(desc_size);
+            if (desc_offset >= total_size) {
+                desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
+            } else {
+                /* Guest zeroing out status is not a hardware requirement.
+                   Clear EOP in case guest didn't do it. */
+                desc.status &= ~E1000_RXD_STAT_EOP;
+            }
+        } else { // as per intel docs; skip descriptors with null buf addr
+            DBGOUT(RX, "Null RX descriptor!!\n");
+        }
+        cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
+
+        if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
+            s->mac_reg[RDH] = 0;
+        s->check_rxov = 1;
+        /* see comment in start_xmit; same here */
+        if (s->mac_reg[RDH] == rdh_start) {
+            DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
+                   rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
+            set_ics(s, 0, E1000_ICS_RXO);
+            return -1;
+        }
+    } while (desc_offset < total_size);
+
+    s->mac_reg[GPRC]++;
+    s->mac_reg[TPR]++;
+    /* TOR - Total Octets Received:
+     * This register includes bytes received in a packet from the <Destination
+     * Address> field through the <CRC> field, inclusively.
+     */
+    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
+    if (n < s->mac_reg[TORL])
+        s->mac_reg[TORH]++;
+    s->mac_reg[TORL] = n;
+
+    n = E1000_ICS_RXT0;
+    if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
+        rdt += s->mac_reg[RDLEN] / sizeof(desc);
+    if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
+        s->rxbuf_min_shift)
+        n |= E1000_ICS_RXDMT0;
+
+    set_ics(s, 0, n);
+
+    return size;
+}
+
+static uint32_t
+mac_readreg(E1000State *s, int index)
+{
+    return s->mac_reg[index];
+}
+
+static uint32_t
+mac_icr_read(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[ICR];
+
+    DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
+    set_interrupt_cause(s, 0, 0);
+    return ret;
+}
+
+static uint32_t
+mac_read_clr4(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[index];
+
+    s->mac_reg[index] = 0;
+    return ret;
+}
+
+static uint32_t
+mac_read_clr8(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[index];
+
+    s->mac_reg[index] = 0;
+    s->mac_reg[index-1] = 0;
+    return ret;
+}
+
+static void
+mac_writereg(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val;
+}
+
+static void
+set_rdt(E1000State *s, int index, uint32_t val)
+{
+    s->check_rxov = 0;
+    s->mac_reg[index] = val & 0xffff;
+}
+
+static void
+set_16bit(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val & 0xffff;
+}
+
+static void
+set_dlen(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val & 0xfff80;
+}
+
+static void
+set_tctl(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val;
+    s->mac_reg[TDT] &= 0xffff;
+    start_xmit(s);
+}
+
+static void
+set_icr(E1000State *s, int index, uint32_t val)
+{
+    DBGOUT(INTERRUPT, "set_icr %x\n", val);
+    set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
+}
+
+static void
+set_imc(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[IMS] &= ~val;
+    set_ics(s, 0, 0);
+}
+
+static void
+set_ims(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[IMS] |= val;
+    set_ics(s, 0, 0);
+}
+
+#define getreg(x)	[x] = mac_readreg
+static uint32_t (*macreg_readops[])(E1000State *, int) = {
+    getreg(PBA),	getreg(RCTL),	getreg(TDH),	getreg(TXDCTL),
+    getreg(WUFC),	getreg(TDT),	getreg(CTRL),	getreg(LEDCTL),
+    getreg(MANC),	getreg(MDIC),	getreg(SWSM),	getreg(STATUS),
+    getreg(TORL),	getreg(TOTL),	getreg(IMS),	getreg(TCTL),
+    getreg(RDH),	getreg(RDT),	getreg(VET),	getreg(ICS),
+    getreg(TDBAL),	getreg(TDBAH),	getreg(RDBAH),	getreg(RDBAL),
+    getreg(TDLEN),	getreg(RDLEN),
+
+    [TOTH] = mac_read_clr8,	[TORH] = mac_read_clr8,	[GPRC] = mac_read_clr4,
+    [GPTC] = mac_read_clr4,	[TPR] = mac_read_clr4,	[TPT] = mac_read_clr4,
+    [ICR] = mac_icr_read,	[EECD] = get_eecd,	[EERD] = flash_eerd_read,
+    [CRCERRS ... MPC] = &mac_readreg,
+    [RA ... RA+31] = &mac_readreg,
+    [MTA ... MTA+127] = &mac_readreg,
+    [VFTA ... VFTA+127] = &mac_readreg,
+};
+enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
+
+#define putreg(x)	[x] = mac_writereg
+static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
+    putreg(PBA),	putreg(EERD),	putreg(SWSM),	putreg(WUFC),
+    putreg(TDBAL),	putreg(TDBAH),	putreg(TXDCTL),	putreg(RDBAH),
+    putreg(RDBAL),	putreg(LEDCTL), putreg(VET),
+    [TDLEN] = set_dlen,	[RDLEN] = set_dlen,	[TCTL] = set_tctl,
+    [TDT] = set_tctl,	[MDIC] = set_mdic,	[ICS] = set_ics,
+    [TDH] = set_16bit,	[RDH] = set_16bit,	[RDT] = set_rdt,
+    [IMC] = set_imc,	[IMS] = set_ims,	[ICR] = set_icr,
+    [EECD] = set_eecd,	[RCTL] = set_rx_control, [CTRL] = set_ctrl,
+    [RA ... RA+31] = &mac_writereg,
+    [MTA ... MTA+127] = &mac_writereg,
+    [VFTA ... VFTA+127] = &mac_writereg,
+};
+enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
+
+static void
+e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    E1000State *s = opaque;
+    unsigned int index = (addr & 0x1ffff) >> 2;
+
+    if (index < NWRITEOPS && macreg_writeops[index]) {
+        macreg_writeops[index](s, index, val);
+    } else if (index < NREADOPS && macreg_readops[index]) {
+        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
+    } else {
+        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
+               index<<2, val);
+    }
+}
+
+static void
+e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    // emulate hw without byte enables: no RMW
+    e1000_mmio_writel(opaque, addr & ~3,
+                      (val & 0xffff) << (8*(addr & 3)));
+}
+
+static void
+e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    // emulate hw without byte enables: no RMW
+    e1000_mmio_writel(opaque, addr & ~3,
+                      (val & 0xff) << (8*(addr & 3)));
+}
+
+static uint32_t
+e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    E1000State *s = opaque;
+    unsigned int index = (addr & 0x1ffff) >> 2;
+
+    if (index < NREADOPS && macreg_readops[index])
+    {
+        return macreg_readops[index](s, index);
+    }
+    DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
+    return 0;
+}
+
+static uint32_t
+e1000_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
+            (8 * (addr & 3))) & 0xff;
+}
+
+static uint32_t
+e1000_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
+            (8 * (addr & 3))) & 0xffff;
+}
+
+static bool is_version_1(void *opaque, int version_id)
+{
+    return version_id == 1;
+}
+
+static const VMStateDescription vmstate_e1000 = {
+    .name = "e1000",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, E1000State),
+        VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
+        VMSTATE_UNUSED(4), /* Was mmio_base.  */
+        VMSTATE_UINT32(rxbuf_size, E1000State),
+        VMSTATE_UINT32(rxbuf_min_shift, E1000State),
+        VMSTATE_UINT32(eecd_state.val_in, E1000State),
+        VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
+        VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
+        VMSTATE_UINT16(eecd_state.reading, E1000State),
+        VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
+        VMSTATE_UINT8(tx.ipcss, E1000State),
+        VMSTATE_UINT8(tx.ipcso, E1000State),
+        VMSTATE_UINT16(tx.ipcse, E1000State),
+        VMSTATE_UINT8(tx.tucss, E1000State),
+        VMSTATE_UINT8(tx.tucso, E1000State),
+        VMSTATE_UINT16(tx.tucse, E1000State),
+        VMSTATE_UINT32(tx.paylen, E1000State),
+        VMSTATE_UINT8(tx.hdr_len, E1000State),
+        VMSTATE_UINT16(tx.mss, E1000State),
+        VMSTATE_UINT16(tx.size, E1000State),
+        VMSTATE_UINT16(tx.tso_frames, E1000State),
+        VMSTATE_UINT8(tx.sum_needed, E1000State),
+        VMSTATE_INT8(tx.ip, E1000State),
+        VMSTATE_INT8(tx.tcp, E1000State),
+        VMSTATE_BUFFER(tx.header, E1000State),
+        VMSTATE_BUFFER(tx.data, E1000State),
+        VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
+        VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
+        VMSTATE_UINT32(mac_reg[CTRL], E1000State),
+        VMSTATE_UINT32(mac_reg[EECD], E1000State),
+        VMSTATE_UINT32(mac_reg[EERD], E1000State),
+        VMSTATE_UINT32(mac_reg[GPRC], E1000State),
+        VMSTATE_UINT32(mac_reg[GPTC], E1000State),
+        VMSTATE_UINT32(mac_reg[ICR], E1000State),
+        VMSTATE_UINT32(mac_reg[ICS], E1000State),
+        VMSTATE_UINT32(mac_reg[IMC], E1000State),
+        VMSTATE_UINT32(mac_reg[IMS], E1000State),
+        VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[MANC], E1000State),
+        VMSTATE_UINT32(mac_reg[MDIC], E1000State),
+        VMSTATE_UINT32(mac_reg[MPC], E1000State),
+        VMSTATE_UINT32(mac_reg[PBA], E1000State),
+        VMSTATE_UINT32(mac_reg[RCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
+        VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
+        VMSTATE_UINT32(mac_reg[RDH], E1000State),
+        VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
+        VMSTATE_UINT32(mac_reg[RDT], E1000State),
+        VMSTATE_UINT32(mac_reg[STATUS], E1000State),
+        VMSTATE_UINT32(mac_reg[SWSM], E1000State),
+        VMSTATE_UINT32(mac_reg[TCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
+        VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
+        VMSTATE_UINT32(mac_reg[TDH], E1000State),
+        VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
+        VMSTATE_UINT32(mac_reg[TDT], E1000State),
+        VMSTATE_UINT32(mac_reg[TORH], E1000State),
+        VMSTATE_UINT32(mac_reg[TORL], E1000State),
+        VMSTATE_UINT32(mac_reg[TOTH], E1000State),
+        VMSTATE_UINT32(mac_reg[TOTL], E1000State),
+        VMSTATE_UINT32(mac_reg[TPR], E1000State),
+        VMSTATE_UINT32(mac_reg[TPT], E1000State),
+        VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[WUFC], E1000State),
+        VMSTATE_UINT32(mac_reg[VET], E1000State),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const uint16_t e1000_eeprom_template[64] = {
+    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
+    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
+    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
+    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
+    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
+};
+
+static const uint16_t phy_reg_init[] = {
+    [PHY_CTRL] = 0x1140,			[PHY_STATUS] = 0x796d, // link initially up
+    [PHY_ID1] = 0x141,				[PHY_ID2] = PHY_ID2_INIT,
+    [PHY_1000T_CTRL] = 0x0e00,			[M88E1000_PHY_SPEC_CTRL] = 0x360,
+    [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,	[PHY_AUTONEG_ADV] = 0xde1,
+    [PHY_LP_ABILITY] = 0x1e0,			[PHY_1000T_STATUS] = 0x3c00,
+    [M88E1000_PHY_SPEC_STATUS] = 0xac00,
+};
+
+static const uint32_t mac_reg_init[] = {
+    [PBA] =     0x00100030,
+    [LEDCTL] =  0x602,
+    [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+                E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
+    [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
+                E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
+                E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
+                E1000_STATUS_LU,
+    [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
+                E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
+                E1000_MANC_RMCP_EN,
+};
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
+    e1000_mmio_writeb,	e1000_mmio_writew,	e1000_mmio_writel
+};
+
+static CPUReadMemoryFunc * const e1000_mmio_read[] = {
+    e1000_mmio_readb,	e1000_mmio_readw,	e1000_mmio_readl
+};
+
+static void
+e1000_mmio_map(PCIDevice *pci_dev, int region_num,
+                pcibus_t addr, pcibus_t size, int type)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+    int i;
+    const uint32_t excluded_regs[] = {
+        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
+        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
+    };
+
+
+    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
+           addr, size);
+
+    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
+    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
+
+    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
+        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
+                                     excluded_regs[i + 1] -
+                                     excluded_regs[i] - 4);
+}
+
+static void
+e1000_cleanup(VLANClientState *nc)
+{
+    E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static int
+pci_e1000_uninit(PCIDevice *dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, dev);
+
+    cpu_unregister_io_memory(d->mmio_index);
+    qemu_del_vlan_client(&d->nic->nc);
+    return 0;
+}
+
+static void e1000_reset(void *opaque)
+{
+    E1000State *d = opaque;
+
+    memset(d->phy_reg, 0, sizeof d->phy_reg);
+    memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+    memset(d->mac_reg, 0, sizeof d->mac_reg);
+    memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
+    d->rxbuf_min_shift = 1;
+    memset(&d->tx, 0, sizeof d->tx);
+}
+
+static NetClientInfo net_e1000_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = e1000_can_receive,
+    .receive = e1000_receive,
+    .cleanup = e1000_cleanup,
+    .link_status_changed = e1000_set_link_status,
+};
+
+static int pci_e1000_init(PCIDevice *pci_dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+    uint8_t *pci_conf;
+    uint16_t checksum = 0;
+    int i;
+    uint8_t *macaddr;
+
+    pci_conf = d->dev.config;
+
+    /* TODO: we have no capabilities, so why is this bit set? */
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
+    /* TODO: RST# value should be 0, PCI spec 6.2.4 */
+    pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
+
+    /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */
+    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+
+    d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
+            e1000_mmio_write, d, DEVICE_LITTLE_ENDIAN);
+
+    pci_register_bar(&d->dev, 0, PNPMMIO_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
+
+    pci_register_bar(&d->dev, 1, IOPORT_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+
+    memmove(d->eeprom_data, e1000_eeprom_template,
+        sizeof e1000_eeprom_template);
+    qemu_macaddr_default_if_unset(&d->conf.macaddr);
+    macaddr = d->conf.macaddr.a;
+    for (i = 0; i < 3; i++)
+        d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
+    for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
+        checksum += d->eeprom_data[i];
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+    d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
+
+    d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
+                          d->dev.qdev.info->name, d->dev.qdev.id, d);
+
+    qemu_format_nic_info_str(&d->nic->nc, macaddr);
+
+    add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
+    return 0;
+}
+
+static void qdev_e1000_reset(DeviceState *dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev.qdev, dev);
+    e1000_reset(d);
+}
+
+static PCIDeviceInfo e1000_info = {
+    .qdev.name  = "e1000",
+    .qdev.desc  = "Intel Gigabit Ethernet",
+    .qdev.size  = sizeof(E1000State),
+    .qdev.reset = qdev_e1000_reset,
+    .qdev.vmsd  = &vmstate_e1000,
+    .init       = pci_e1000_init,
+    .exit       = pci_e1000_uninit,
+    .romfile    = "pxe-e1000.rom",
+    .vendor_id  = PCI_VENDOR_ID_INTEL,
+    .device_id  = E1000_DEVID,
+    .revision   = 0x03,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(E1000State, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void e1000_register_devices(void)
+{
+    pci_qdev_register(&e1000_info);
+}
+
+device_init(e1000_register_devices)
diff --git a/qemu-0.15.x/hw/e1000_hw.h b/qemu-0.15.x/hw/e1000_hw.h
new file mode 100644
index 0000000..9bd8a4b
--- /dev/null
+++ b/qemu-0.15.x/hw/e1000_hw.h
@@ -0,0 +1,864 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2006 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, see <http://www.gnu.org/licenses/>.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
+#define E1000_DEV_ID_82571EB_COPPER      0x105E
+#define E1000_DEV_ID_82571EB_FIBER       0x105F
+#define E1000_DEV_ID_82571EB_SERDES      0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEV_ID_82572EI_COPPER      0x107D
+#define E1000_DEV_ID_82572EI_FIBER       0x107E
+#define E1000_DEV_ID_82572EI_SERDES      0x107F
+#define E1000_DEV_ID_82572EI             0x10B9
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+#define E1000_DEV_ID_82573L              0x109A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
+#define E1000_DEV_ID_ICH8_IGP_C          0x104B
+#define E1000_DEV_ID_ICH8_IFE            0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G          0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M          0x104D
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM register */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_RDTR1    0x02820  /* RX Delay Timer (1) - RW */
+#define E1000_RDBAL1   0x02900  /* RX Descriptor Base Address Low (1) - RW */
+#define E1000_RDBAH1   0x02904  /* RX Descriptor Base Address High (1) - RW */
+#define E1000_RDLEN1   0x02908  /* RX Descriptor Length (1) - RW */
+#define E1000_RDH1     0x02910  /* RX Descriptor Head (1) - RW */
+#define E1000_RDT1     0x02918  /* RX Descriptor Tail (1) - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG  0x0001
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RDBAL0   E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
+#define E1000_RDBAH0   E1000_RDBAH /* RX Desc Base Address High (0) - RW */
+#define E1000_RDLEN0   E1000_RDLEN /* RX Desc Length (0) - RW */
+#define E1000_RDH0     E1000_RDH   /* RX Desc Head (0) - RW */
+#define E1000_RDT0     E1000_RDT   /* RX Desc Tail (0) - RW */
+#define E1000_RDTR0    E1000_RDTR  /* RX Delay Timer (0) - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control queue 0 - RW */
+#define E1000_RXDCTL1  0x02928  /* RX Descriptor Control queue 1 - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0    0x03840  /* TX Arbitration Count (0) */
+#define E1000_TDBAL1   0x03900  /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1   0x03904  /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1   0x03908  /* TX Desc Length (1) - RW */
+#define E1000_TDH1     0x03910  /* TX Desc Head (1) - RW */
+#define E1000_TDT1     0x03918  /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1  0x03928  /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1    0x03940  /* TX Arbitration Count (1) */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA     0x0003C  /* PHY address - RW */
+#define E1000_MANC2H     0x05860  /* Managment Control To Host - RW */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD      E1000_ICR_SRPD
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMC_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW       E1000_ICR_DSW
+#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMC_EPRST     E1000_ICR_EPRST
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion
+                                                   by EEPROM/Flash */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+                                         * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
+
+#define E1000_SHADOW_RAM_WORDS     2048
+#define E1000_ICH_NVM_SIG_WORD     0x13
+#define E1000_ICH_NVM_SIG_MASK     0xC0
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT                 0x0003
+#define EEPROM_ID_LED_SETTINGS        0x0004
+#define EEPROM_VERSION                0x0005
+#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
+#define EEPROM_INIT_CONTROL1_REG      0x000A
+#define EEPROM_INIT_CONTROL2_REG      0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
+#define EEPROM_INIT_3GIO_3            0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
+#define EEPROM_CFG                    0x0012
+#define EEPROM_FLASH_VERSION          0x0032
+#define EEPROM_CHECKSUM_REG           0x003F
+
+#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
+#define E1000_EEPROM_CFG_DONE_PORT_1  0x00080000   /* ...for second port */
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
+                                             * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN         0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+#endif /* _E1000_HW_H_ */
diff --git a/qemu-0.15.x/hw/ecc.c b/qemu-0.15.x/hw/ecc.c
new file mode 100644
index 0000000..a75408b
--- /dev/null
+++ b/qemu-0.15.x/hw/ecc.c
@@ -0,0 +1,88 @@
+/*
+ * Calculate Error-correcting Codes. Used by NAND Flash controllers
+ * (not by NAND chips).
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "flash.h"
+
+/*
+ * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+};
+
+/* Update ECC parity count.  */
+uint8_t ecc_digest(ECCState *s, uint8_t sample)
+{
+    uint8_t idx = nand_ecc_precalc_table[sample];
+
+    s->cp ^= idx & 0x3f;
+    if (idx & 0x40) {
+        s->lp[0] ^= ~s->count;
+        s->lp[1] ^= s->count;
+    }
+    s->count ++;
+
+    return sample;
+}
+
+/* Reinitialise the counters.  */
+void ecc_reset(ECCState *s)
+{
+    s->lp[0] = 0x0000;
+    s->lp[1] = 0x0000;
+    s->cp = 0x00;
+    s->count = 0;
+}
+
+/* Save/restore */
+VMStateDescription vmstate_ecc_state = {
+    .name = "ecc-state",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(cp, ECCState),
+        VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
+        VMSTATE_UINT16(count, ECCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
diff --git a/qemu-0.15.x/hw/eccmemctl.c b/qemu-0.15.x/hw/eccmemctl.c
new file mode 100644
index 0000000..2bda87b
--- /dev/null
+++ b/qemu-0.15.x/hw/eccmemctl.c
@@ -0,0 +1,332 @@
+/*
+ * QEMU Sparc Sun4m ECC memory controller emulation
+ *
+ * Copyright (c) 2007 Robert Reif
+ *
+ * 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 "sysbus.h"
+#include "trace.h"
+
+/* There are 3 versions of this chip used in SMP sun4m systems:
+ * MCC (version 0, implementation 0) SS-600MP
+ * EMC (version 0, implementation 1) SS-10
+ * SMC (version 0, implementation 2) SS-10SX and SS-20
+ *
+ * Chipset docs:
+ * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
+ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
+ */
+
+#define ECC_MCC        0x00000000
+#define ECC_EMC        0x10000000
+#define ECC_SMC        0x20000000
+
+/* Register indexes */
+#define ECC_MER        0               /* Memory Enable Register */
+#define ECC_MDR        1               /* Memory Delay Register */
+#define ECC_MFSR       2               /* Memory Fault Status Register */
+#define ECC_VCR        3               /* Video Configuration Register */
+#define ECC_MFAR0      4               /* Memory Fault Address Register 0 */
+#define ECC_MFAR1      5               /* Memory Fault Address Register 1 */
+#define ECC_DR         6               /* Diagnostic Register */
+#define ECC_ECR0       7               /* Event Count Register 0 */
+#define ECC_ECR1       8               /* Event Count Register 1 */
+
+/* ECC fault control register */
+#define ECC_MER_EE     0x00000001      /* Enable ECC checking */
+#define ECC_MER_EI     0x00000002      /* Enable Interrupts on
+                                          correctable errors */
+#define ECC_MER_MRR0   0x00000004      /* SIMM 0 */
+#define ECC_MER_MRR1   0x00000008      /* SIMM 1 */
+#define ECC_MER_MRR2   0x00000010      /* SIMM 2 */
+#define ECC_MER_MRR3   0x00000020      /* SIMM 3 */
+#define ECC_MER_MRR4   0x00000040      /* SIMM 4 */
+#define ECC_MER_MRR5   0x00000080      /* SIMM 5 */
+#define ECC_MER_MRR6   0x00000100      /* SIMM 6 */
+#define ECC_MER_MRR7   0x00000200      /* SIMM 7 */
+#define ECC_MER_REU    0x00000100      /* Memory Refresh Enable (600MP) */
+#define ECC_MER_MRR    0x000003fc      /* MRR mask */
+#define ECC_MER_A      0x00000400      /* Memory controller addr map select */
+#define ECC_MER_DCI    0x00000800      /* Disables Coherent Invalidate ACK */
+#define ECC_MER_VER    0x0f000000      /* Version */
+#define ECC_MER_IMPL   0xf0000000      /* Implementation */
+#define ECC_MER_MASK_0 0x00000103      /* Version 0 (MCC) mask */
+#define ECC_MER_MASK_1 0x00000bff      /* Version 1 (EMC) mask */
+#define ECC_MER_MASK_2 0x00000bff      /* Version 2 (SMC) mask */
+
+/* ECC memory delay register */
+#define ECC_MDR_RRI    0x000003ff      /* Refresh Request Interval */
+#define ECC_MDR_MI     0x00001c00      /* MIH Delay */
+#define ECC_MDR_CI     0x0000e000      /* Coherent Invalidate Delay */
+#define ECC_MDR_MDL    0x001f0000      /* MBus Master arbitration delay */
+#define ECC_MDR_MDH    0x03e00000      /* MBus Master arbitration delay */
+#define ECC_MDR_GAD    0x7c000000      /* Graphics Arbitration Delay */
+#define ECC_MDR_RSC    0x80000000      /* Refresh load control */
+#define ECC_MDR_MASK   0x7fffffff
+
+/* ECC fault status register */
+#define ECC_MFSR_CE    0x00000001      /* Correctable error */
+#define ECC_MFSR_BS    0x00000002      /* C2 graphics bad slot access */
+#define ECC_MFSR_TO    0x00000004      /* Timeout on write */
+#define ECC_MFSR_UE    0x00000008      /* Uncorrectable error */
+#define ECC_MFSR_DW    0x000000f0      /* Index of double word in block */
+#define ECC_MFSR_SYND  0x0000ff00      /* Syndrome for correctable error */
+#define ECC_MFSR_ME    0x00010000      /* Multiple errors */
+#define ECC_MFSR_C2ERR 0x00020000      /* C2 graphics error */
+
+/* ECC fault address register 0 */
+#define ECC_MFAR0_PADDR 0x0000000f     /* PA[32-35] */
+#define ECC_MFAR0_TYPE  0x000000f0     /* Transaction type */
+#define ECC_MFAR0_SIZE  0x00000700     /* Transaction size */
+#define ECC_MFAR0_CACHE 0x00000800     /* Mapped cacheable */
+#define ECC_MFAR0_LOCK  0x00001000     /* Error occurred in atomic cycle */
+#define ECC_MFAR0_BMODE 0x00002000     /* Boot mode */
+#define ECC_MFAR0_VADDR 0x003fc000     /* VA[12-19] (superset bits) */
+#define ECC_MFAR0_S     0x08000000     /* Supervisor mode */
+#define ECC_MFARO_MID   0xf0000000     /* Module ID */
+
+/* ECC diagnostic register */
+#define ECC_DR_CBX     0x00000001
+#define ECC_DR_CB0     0x00000002
+#define ECC_DR_CB1     0x00000004
+#define ECC_DR_CB2     0x00000008
+#define ECC_DR_CB4     0x00000010
+#define ECC_DR_CB8     0x00000020
+#define ECC_DR_CB16    0x00000040
+#define ECC_DR_CB32    0x00000080
+#define ECC_DR_DMODE   0x00000c00
+
+#define ECC_NREGS      9
+#define ECC_SIZE       (ECC_NREGS * sizeof(uint32_t))
+
+#define ECC_DIAG_SIZE  4
+#define ECC_DIAG_MASK  (ECC_DIAG_SIZE - 1)
+
+typedef struct ECCState {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t regs[ECC_NREGS];
+    uint8_t diag[ECC_DIAG_SIZE];
+    uint32_t version;
+} ECCState;
+
+static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    ECCState *s = opaque;
+
+    switch (addr >> 2) {
+    case ECC_MER:
+        if (s->version == ECC_MCC)
+            s->regs[ECC_MER] = (val & ECC_MER_MASK_0);
+        else if (s->version == ECC_EMC)
+            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
+        else if (s->version == ECC_SMC)
+            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
+        trace_ecc_mem_writel_mer(val);
+        break;
+    case ECC_MDR:
+        s->regs[ECC_MDR] =  val & ECC_MDR_MASK;
+        trace_ecc_mem_writel_mdr(val);
+        break;
+    case ECC_MFSR:
+        s->regs[ECC_MFSR] =  val;
+        qemu_irq_lower(s->irq);
+        trace_ecc_mem_writel_mfsr(val);
+        break;
+    case ECC_VCR:
+        s->regs[ECC_VCR] =  val;
+        trace_ecc_mem_writel_vcr(val);
+        break;
+    case ECC_DR:
+        s->regs[ECC_DR] =  val;
+        trace_ecc_mem_writel_dr(val);
+        break;
+    case ECC_ECR0:
+        s->regs[ECC_ECR0] =  val;
+        trace_ecc_mem_writel_ecr0(val);
+        break;
+    case ECC_ECR1:
+        s->regs[ECC_ECR0] =  val;
+        trace_ecc_mem_writel_ecr1(val);
+        break;
+    }
+}
+
+static uint32_t ecc_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    ECCState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr >> 2) {
+    case ECC_MER:
+        ret = s->regs[ECC_MER];
+        trace_ecc_mem_readl_mer(ret);
+        break;
+    case ECC_MDR:
+        ret = s->regs[ECC_MDR];
+        trace_ecc_mem_readl_mdr(ret);
+        break;
+    case ECC_MFSR:
+        ret = s->regs[ECC_MFSR];
+        trace_ecc_mem_readl_mfsr(ret);
+        break;
+    case ECC_VCR:
+        ret = s->regs[ECC_VCR];
+        trace_ecc_mem_readl_vcr(ret);
+        break;
+    case ECC_MFAR0:
+        ret = s->regs[ECC_MFAR0];
+        trace_ecc_mem_readl_mfar0(ret);
+        break;
+    case ECC_MFAR1:
+        ret = s->regs[ECC_MFAR1];
+        trace_ecc_mem_readl_mfar1(ret);
+        break;
+    case ECC_DR:
+        ret = s->regs[ECC_DR];
+        trace_ecc_mem_readl_dr(ret);
+        break;
+    case ECC_ECR0:
+        ret = s->regs[ECC_ECR0];
+        trace_ecc_mem_readl_ecr0(ret);
+        break;
+    case ECC_ECR1:
+        ret = s->regs[ECC_ECR0];
+        trace_ecc_mem_readl_ecr1(ret);
+        break;
+    }
+    return ret;
+}
+
+static CPUReadMemoryFunc * const ecc_mem_read[3] = {
+    NULL,
+    NULL,
+    ecc_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const ecc_mem_write[3] = {
+    NULL,
+    NULL,
+    ecc_mem_writel,
+};
+
+static void ecc_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    ECCState *s = opaque;
+
+    trace_ecc_diag_mem_writeb(addr, val);
+    s->diag[addr & ECC_DIAG_MASK] = val;
+}
+
+static uint32_t ecc_diag_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    ECCState *s = opaque;
+    uint32_t ret = s->diag[(int)addr];
+
+    trace_ecc_diag_mem_readb(addr, ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const ecc_diag_mem_read[3] = {
+    ecc_diag_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const ecc_diag_mem_write[3] = {
+    ecc_diag_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static const VMStateDescription vmstate_ecc = {
+    .name ="ECC",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS),
+        VMSTATE_BUFFER(diag, ECCState),
+        VMSTATE_UINT32(version, ECCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ecc_reset(DeviceState *d)
+{
+    ECCState *s = container_of(d, ECCState, busdev.qdev);
+
+    if (s->version == ECC_MCC)
+        s->regs[ECC_MER] &= ECC_MER_REU;
+    else
+        s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR |
+                             ECC_MER_DCI);
+    s->regs[ECC_MDR] = 0x20;
+    s->regs[ECC_MFSR] = 0;
+    s->regs[ECC_VCR] = 0;
+    s->regs[ECC_MFAR0] = 0x07c00000;
+    s->regs[ECC_MFAR1] = 0;
+    s->regs[ECC_DR] = 0;
+    s->regs[ECC_ECR0] = 0;
+    s->regs[ECC_ECR1] = 0;
+}
+
+static int ecc_init1(SysBusDevice *dev)
+{
+    int ecc_io_memory;
+    ECCState *s = FROM_SYSBUS(ECCState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->regs[0] = s->version;
+    ecc_io_memory = cpu_register_io_memory(ecc_mem_read, ecc_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, ECC_SIZE, ecc_io_memory);
+
+    if (s->version == ECC_MCC) { // SS-600MP only
+        ecc_io_memory = cpu_register_io_memory(ecc_diag_mem_read,
+                                               ecc_diag_mem_write, s,
+                                               DEVICE_NATIVE_ENDIAN);
+        sysbus_init_mmio(dev, ECC_DIAG_SIZE, ecc_io_memory);
+    }
+
+    return 0;
+}
+
+static SysBusDeviceInfo ecc_info = {
+    .init = ecc_init1,
+    .qdev.name  = "eccmemctl",
+    .qdev.size  = sizeof(ECCState),
+    .qdev.vmsd  = &vmstate_ecc,
+    .qdev.reset = ecc_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("version", ECCState, version, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+
+static void ecc_register_devices(void)
+{
+    sysbus_register_withprop(&ecc_info);
+}
+
+device_init(ecc_register_devices)
diff --git a/qemu-0.15.x/hw/eepro100.c b/qemu-0.15.x/hw/eepro100.c
new file mode 100644
index 0000000..9b6f4a5
--- /dev/null
+++ b/qemu-0.15.x/hw/eepro100.c
@@ -0,0 +1,2178 @@
+/*
+ * QEMU i8255x (PRO100) emulation
+ *
+ * Copyright (C) 2006-2011 Stefan Weil
+ *
+ * Portions of the code are copies from grub / etherboot eepro100.c
+ * and linux e100.c.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) version 3 or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Tested features (i82559):
+ *      PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
+ *      Linux networking (i386) ok
+ *
+ * Untested:
+ *      Windows networking
+ *
+ * References:
+ *
+ * Intel 8255x 10/100 Mbps Ethernet Controller Family
+ * Open Source Software Developer Manual
+ *
+ * TODO:
+ *      * PHY emulation should be separated from nic emulation.
+ *        Most nic emulations could share the same phy code.
+ *      * i82550 is untested. It is programmed like the i82559.
+ *      * i82562 is untested. It is programmed like the i82559.
+ *      * Power management (i82558 and later) is not implemented.
+ *      * Wake-on-LAN is not implemented.
+ */
+
+#include <stddef.h>             /* offsetof */
+#include "hw.h"
+#include "pci.h"
+#include "net.h"
+#include "eeprom93xx.h"
+#include "sysemu.h"
+
+/* QEMU sends frames smaller than 60 bytes to ethernet nics.
+ * Such frames are rejected by real nics and their emulations.
+ * To avoid this behaviour, other nic emulations pad received
+ * frames. The following definition enables this padding for
+ * eepro100, too. We keep the define around in case it might
+ * become useful the future if the core networking is ever
+ * changed to pad short packets itself. */
+#define CONFIG_PAD_RECEIVED_FRAMES
+
+#define KiB 1024
+
+/* Debug EEPRO100 card. */
+#if 0
+# define DEBUG_EEPRO100
+#endif
+
+#ifdef DEBUG_EEPRO100
+#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+/* Set flags to 0 to disable debug output. */
+#define INT     1       /* interrupt related actions */
+#define MDI     1       /* mdi related actions */
+#define OTHER   1
+#define RXTX    1
+#define EEPROM  1       /* eeprom related actions */
+
+#define TRACE(flag, command) ((flag) ? (command) : (void)0)
+
+#define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+/* This driver supports several different devices which are declared here. */
+#define i82550          0x82550
+#define i82551          0x82551
+#define i82557A         0x82557a
+#define i82557B         0x82557b
+#define i82557C         0x82557c
+#define i82558A         0x82558a
+#define i82558B         0x82558b
+#define i82559A         0x82559a
+#define i82559B         0x82559b
+#define i82559C         0x82559c
+#define i82559ER        0x82559e
+#define i82562          0x82562
+#define i82801          0x82801
+
+/* Use 64 word EEPROM. TODO: could be a runtime option. */
+#define EEPROM_SIZE     64
+
+#define PCI_MEM_SIZE            (4 * KiB)
+#define PCI_IO_SIZE             64
+#define PCI_FLASH_SIZE          (128 * KiB)
+
+#define BIT(n) (1 << (n))
+#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
+
+/* The SCB accepts the following controls for the Tx and Rx units: */
+#define  CU_NOP         0x0000  /* No operation. */
+#define  CU_START       0x0010  /* CU start. */
+#define  CU_RESUME      0x0020  /* CU resume. */
+#define  CU_STATSADDR   0x0040  /* Load dump counters address. */
+#define  CU_SHOWSTATS   0x0050  /* Dump statistical counters. */
+#define  CU_CMD_BASE    0x0060  /* Load CU base address. */
+#define  CU_DUMPSTATS   0x0070  /* Dump and reset statistical counters. */
+#define  CU_SRESUME     0x00a0  /* CU static resume. */
+
+#define  RU_NOP         0x0000
+#define  RX_START       0x0001
+#define  RX_RESUME      0x0002
+#define  RU_ABORT       0x0004
+#define  RX_ADDR_LOAD   0x0006
+#define  RX_RESUMENR    0x0007
+#define INT_MASK        0x0100
+#define DRVR_INT        0x0200  /* Driver generated interrupt. */
+
+typedef struct {
+    PCIDeviceInfo pci;
+    uint32_t device;
+    uint8_t stats_size;
+    bool has_extended_tcb_support;
+    bool power_management;
+} E100PCIDeviceInfo;
+
+/* Offsets to the various registers.
+   All accesses need not be longword aligned. */
+typedef enum {
+    SCBStatus = 0,              /* Status Word. */
+    SCBAck = 1,
+    SCBCmd = 2,                 /* Rx/Command Unit command and status. */
+    SCBIntmask = 3,
+    SCBPointer = 4,             /* General purpose pointer. */
+    SCBPort = 8,                /* Misc. commands and operands.  */
+    SCBflash = 12,              /* Flash memory control. */
+    SCBeeprom = 14,             /* EEPROM control. */
+    SCBCtrlMDI = 16,            /* MDI interface control. */
+    SCBEarlyRx = 20,            /* Early receive byte count. */
+    SCBFlow = 24,               /* Flow Control. */
+    SCBpmdr = 27,               /* Power Management Driver. */
+    SCBgctrl = 28,              /* General Control. */
+    SCBgstat = 29,              /* General Status. */
+} E100RegisterOffset;
+
+/* A speedo3 transmit buffer descriptor with two buffers... */
+typedef struct {
+    uint16_t status;
+    uint16_t command;
+    uint32_t link;              /* void * */
+    uint32_t tbd_array_addr;    /* transmit buffer descriptor array address. */
+    uint16_t tcb_bytes;         /* transmit command block byte count (in lower 14 bits */
+    uint8_t tx_threshold;       /* transmit threshold */
+    uint8_t tbd_count;          /* TBD number */
+#if 0
+    /* This constitutes two "TBD" entries: hdr and data */
+    uint32_t tx_buf_addr0;  /* void *, header of frame to be transmitted.  */
+    int32_t  tx_buf_size0;  /* Length of Tx hdr. */
+    uint32_t tx_buf_addr1;  /* void *, data to be transmitted.  */
+    int32_t  tx_buf_size1;  /* Length of Tx data. */
+#endif
+} eepro100_tx_t;
+
+/* Receive frame descriptor. */
+typedef struct {
+    int16_t status;
+    uint16_t command;
+    uint32_t link;              /* struct RxFD * */
+    uint32_t rx_buf_addr;       /* void * */
+    uint16_t count;
+    uint16_t size;
+    /* Ethernet frame data follows. */
+} eepro100_rx_t;
+
+typedef enum {
+    COMMAND_EL = BIT(15),
+    COMMAND_S = BIT(14),
+    COMMAND_I = BIT(13),
+    COMMAND_NC = BIT(4),
+    COMMAND_SF = BIT(3),
+    COMMAND_CMD = BITS(2, 0),
+} scb_command_bit;
+
+typedef enum {
+    STATUS_C = BIT(15),
+    STATUS_OK = BIT(13),
+} scb_status_bit;
+
+typedef struct {
+    uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
+             tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+             tx_multiple_collisions, tx_total_collisions;
+    uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
+             rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+             rx_short_frame_errors;
+    uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+    uint16_t xmt_tco_frames, rcv_tco_frames;
+    /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
+    uint32_t reserved[4];
+} eepro100_stats_t;
+
+typedef enum {
+    cu_idle = 0,
+    cu_suspended = 1,
+    cu_active = 2,
+    cu_lpq_active = 2,
+    cu_hqp_active = 3
+} cu_state_t;
+
+typedef enum {
+    ru_idle = 0,
+    ru_suspended = 1,
+    ru_no_resources = 2,
+    ru_ready = 4
+} ru_state_t;
+
+typedef struct {
+    PCIDevice dev;
+    /* Hash register (multicast mask array, multiple individual addresses). */
+    uint8_t mult[8];
+    int mmio_index;
+    NICState *nic;
+    NICConf conf;
+    uint8_t scb_stat;           /* SCB stat/ack byte */
+    uint8_t int_stat;           /* PCI interrupt status */
+    /* region must not be saved by nic_save. */
+    uint32_t region1;           /* PCI region 1 address */
+    uint16_t mdimem[32];
+    eeprom_t *eeprom;
+    uint32_t device;            /* device variant */
+    /* (cu_base + cu_offset) address the next command block in the command block list. */
+    uint32_t cu_base;           /* CU base address */
+    uint32_t cu_offset;         /* CU address offset */
+    /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
+    uint32_t ru_base;           /* RU base address */
+    uint32_t ru_offset;         /* RU address offset */
+    uint32_t statsaddr;         /* pointer to eepro100_stats_t */
+
+    /* Temporary status information (no need to save these values),
+     * used while processing CU commands. */
+    eepro100_tx_t tx;           /* transmit buffer descriptor */
+    uint32_t cb_address;        /* = cu_base + cu_offset */
+
+    /* Statistical counters. Also used for wake-up packet (i82559). */
+    eepro100_stats_t statistics;
+
+    /* Data in mem is always in the byte order of the controller (le).
+     * It must be dword aligned to allow direct access to 32 bit values. */
+    uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));;
+
+    /* Configuration bytes. */
+    uint8_t configuration[22];
+
+    /* vmstate for each particular nic */
+    VMStateDescription *vmstate;
+
+    /* Quasi static device properties (no need to save them). */
+    uint16_t stats_size;
+    bool has_extended_tcb_support;
+} EEPRO100State;
+
+/* Word indices in EEPROM. */
+typedef enum {
+    EEPROM_CNFG_MDIX  = 0x03,
+    EEPROM_ID         = 0x05,
+    EEPROM_PHY_ID     = 0x06,
+    EEPROM_VENDOR_ID  = 0x0c,
+    EEPROM_CONFIG_ASF = 0x0d,
+    EEPROM_DEVICE_ID  = 0x23,
+    EEPROM_SMBUS_ADDR = 0x90,
+} EEPROMOffset;
+
+/* Bit values for EEPROM ID word. */
+typedef enum {
+    EEPROM_ID_MDM = BIT(0),     /* Modem */
+    EEPROM_ID_STB = BIT(1),     /* Standby Enable */
+    EEPROM_ID_WMR = BIT(2),     /* ??? */
+    EEPROM_ID_WOL = BIT(5),     /* Wake on LAN */
+    EEPROM_ID_DPD = BIT(6),     /* Deep Power Down */
+    EEPROM_ID_ALT = BIT(7),     /* */
+    /* BITS(10, 8) device revision */
+    EEPROM_ID_BD = BIT(11),     /* boot disable */
+    EEPROM_ID_ID = BIT(13),     /* id bit */
+    /* BITS(15, 14) signature */
+    EEPROM_ID_VALID = BIT(14),  /* signature for valid eeprom */
+} eeprom_id_bit;
+
+/* Default values for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_default[] = {
+    /* MDI Registers 0 - 6, 7 */
+    0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 8 - 15 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 16 - 31 */
+    0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+/* Readonly mask for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_mask[] = {
+    0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+/* Read a 16 bit little endian value from physical memory. */
+static uint16_t e100_ldw_le_phys(target_phys_addr_t addr)
+{
+    /* Load 16 bit (little endian) word from emulated hardware. */
+    uint16_t val;
+    cpu_physical_memory_read(addr, &val, sizeof(val));
+    return le16_to_cpu(val);
+}
+
+/* Read a 32 bit little endian value from physical memory. */
+static uint32_t e100_ldl_le_phys(target_phys_addr_t addr)
+{
+    /* Load 32 bit (little endian) word from emulated hardware. */
+    uint32_t val;
+    cpu_physical_memory_read(addr, &val, sizeof(val));
+    return le32_to_cpu(val);
+}
+
+/* Write a 16 bit little endian value to physical memory. */
+static void e100_stw_le_phys(target_phys_addr_t addr, uint16_t val)
+{
+    val = cpu_to_le16(val);
+    cpu_physical_memory_write(addr, &val, sizeof(val));
+}
+
+/* Write a 32 bit little endian value to physical memory. */
+static void e100_stl_le_phys(target_phys_addr_t addr, uint32_t val)
+{
+    val = cpu_to_le32(val);
+    cpu_physical_memory_write(addr, &val, sizeof(val));
+}
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static unsigned compute_mcast_idx(const uint8_t * ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry) {
+                crc = ((crc ^ POLYNOMIAL) | carry);
+            }
+        }
+    }
+    return (crc & BITS(7, 2)) >> 2;
+}
+
+/* Read a 16 bit control/status (CSR) register. */
+static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    return le16_to_cpup((uint16_t *)&s->mem[addr]);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    return le32_to_cpup((uint32_t *)&s->mem[addr]);
+}
+
+/* Write a 16 bit control/status (CSR) register. */
+static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
+                            uint16_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    cpu_to_le16w((uint16_t *)&s->mem[addr], val);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
+                            uint32_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    cpu_to_le32w((uint32_t *)&s->mem[addr], val);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *nic_dump(const uint8_t * buf, unsigned size)
+{
+    static char dump[3 * 16 + 1];
+    char *p = &dump[0];
+    if (size > 16) {
+        size = 16;
+    }
+    while (size-- > 0) {
+        p += sprintf(p, " %02x", *buf++);
+    }
+    return dump;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+enum scb_stat_ack {
+    stat_ack_not_ours = 0x00,
+    stat_ack_sw_gen = 0x04,
+    stat_ack_rnr = 0x10,
+    stat_ack_cu_idle = 0x20,
+    stat_ack_frame_rx = 0x40,
+    stat_ack_cu_cmd_done = 0x80,
+    stat_ack_not_present = 0xFF,
+    stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+    stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+static void disable_interrupt(EEPRO100State * s)
+{
+    if (s->int_stat) {
+        TRACE(INT, logout("interrupt disabled\n"));
+        qemu_irq_lower(s->dev.irq[0]);
+        s->int_stat = 0;
+    }
+}
+
+static void enable_interrupt(EEPRO100State * s)
+{
+    if (!s->int_stat) {
+        TRACE(INT, logout("interrupt enabled\n"));
+        qemu_irq_raise(s->dev.irq[0]);
+        s->int_stat = 1;
+    }
+}
+
+static void eepro100_acknowledge(EEPRO100State * s)
+{
+    s->scb_stat &= ~s->mem[SCBAck];
+    s->mem[SCBAck] = s->scb_stat;
+    if (s->scb_stat == 0) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
+{
+    uint8_t mask = ~s->mem[SCBIntmask];
+    s->mem[SCBAck] |= status;
+    status = s->scb_stat = s->mem[SCBAck];
+    status &= (mask | 0x0f);
+#if 0
+    status &= (~s->mem[SCBIntmask] | 0x0xf);
+#endif
+    if (status && (mask & 0x01)) {
+        /* SCB mask and SCB Bit M do not disable interrupt. */
+        enable_interrupt(s);
+    } else if (s->int_stat) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_cx_interrupt(EEPRO100State * s)
+{
+    /* CU completed action command. */
+    /* Transmit not ok (82557 only, not in emulation). */
+    eepro100_interrupt(s, 0x80);
+}
+
+static void eepro100_cna_interrupt(EEPRO100State * s)
+{
+    /* CU left the active state. */
+    eepro100_interrupt(s, 0x20);
+}
+
+static void eepro100_fr_interrupt(EEPRO100State * s)
+{
+    /* RU received a complete frame. */
+    eepro100_interrupt(s, 0x40);
+}
+
+static void eepro100_rnr_interrupt(EEPRO100State * s)
+{
+    /* RU is not ready. */
+    eepro100_interrupt(s, 0x10);
+}
+
+static void eepro100_mdi_interrupt(EEPRO100State * s)
+{
+    /* MDI completed read or write cycle. */
+    eepro100_interrupt(s, 0x08);
+}
+
+static void eepro100_swi_interrupt(EEPRO100State * s)
+{
+    /* Software has requested an interrupt. */
+    eepro100_interrupt(s, 0x04);
+}
+
+#if 0
+static void eepro100_fcp_interrupt(EEPRO100State * s)
+{
+    /* Flow control pause interrupt (82558 and later). */
+    eepro100_interrupt(s, 0x01);
+}
+#endif
+
+static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
+{
+    uint32_t device = s->device;
+    uint8_t *pci_conf = s->dev.config;
+
+    TRACE(OTHER, logout("%p\n", s));
+
+    /* PCI Status */
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
+                                        PCI_STATUS_FAST_BACK);
+    /* PCI Latency Timer */
+    pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
+    /* Capability Pointer is set by PCI framework. */
+    /* Interrupt Line */
+    /* Interrupt Pin */
+    pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1);      /* interrupt pin A */
+    /* Minimum Grant */
+    pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
+    /* Maximum Latency */
+    pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
+
+    s->stats_size = e100_device->stats_size;
+    s->has_extended_tcb_support = e100_device->has_extended_tcb_support;
+
+    switch (device) {
+    case i82550:
+    case i82551:
+    case i82557A:
+    case i82557B:
+    case i82557C:
+    case i82558A:
+    case i82558B:
+    case i82559A:
+    case i82559B:
+    case i82559ER:
+    case i82562:
+    case i82801:
+    case i82559C:
+        break;
+    default:
+        logout("Device %X is undefined!\n", device);
+    }
+
+    /* Standard TxCB. */
+    s->configuration[6] |= BIT(4);
+
+    /* Standard statistical counters. */
+    s->configuration[6] |= BIT(5);
+
+    if (s->stats_size == 80) {
+        /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
+        if (s->configuration[6] & BIT(2)) {
+            /* TCO statistical counters. */
+            assert(s->configuration[6] & BIT(5));
+        } else {
+            if (s->configuration[6] & BIT(5)) {
+                /* No extended statistical counters, i82557 compatible. */
+                s->stats_size = 64;
+            } else {
+                /* i82558 compatible. */
+                s->stats_size = 76;
+            }
+        }
+    } else {
+        if (s->configuration[6] & BIT(5)) {
+            /* No extended statistical counters. */
+            s->stats_size = 64;
+        }
+    }
+    assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
+
+    if (e100_device->power_management) {
+        /* Power Management Capabilities */
+        int cfg_offset = 0xdc;
+        int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
+                                   cfg_offset, PCI_PM_SIZEOF);
+        assert(r >= 0);
+        pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
+#if 0 /* TODO: replace dummy code for power management emulation. */
+        /* TODO: Power Management Control / Status. */
+        pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
+        /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
+        pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
+#endif
+    }
+
+#if EEPROM_SIZE > 0
+    if (device == i82557C || device == i82558B || device == i82559C) {
+        /*
+        TODO: get vendor id from EEPROM for i82557C or later.
+        TODO: get device id from EEPROM for i82557C or later.
+        TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
+        TODO: header type is determined by EEPROM for i82559.
+        TODO: get subsystem id from EEPROM for i82557C or later.
+        TODO: get subsystem vendor id from EEPROM for i82557C or later.
+        TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
+        TODO: capability pointer depends on EEPROM for i82558.
+        */
+        logout("Get device id and revision from EEPROM!!!\n");
+    }
+#endif /* EEPROM_SIZE > 0 */
+}
+
+static void nic_selective_reset(EEPRO100State * s)
+{
+    size_t i;
+    uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
+#if 0
+    eeprom93xx_reset(s->eeprom);
+#endif
+    memcpy(eeprom_contents, s->conf.macaddr.a, 6);
+    eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
+    if (s->device == i82557B || s->device == i82557C)
+        eeprom_contents[5] = 0x0100;
+    eeprom_contents[EEPROM_PHY_ID] = 1;
+    uint16_t sum = 0;
+    for (i = 0; i < EEPROM_SIZE - 1; i++) {
+        sum += eeprom_contents[i];
+    }
+    eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
+    TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
+
+    memset(s->mem, 0, sizeof(s->mem));
+    e100_write_reg4(s, SCBCtrlMDI, BIT(21));
+
+    assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
+    memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
+}
+
+static void nic_reset(void *opaque)
+{
+    EEPRO100State *s = opaque;
+    TRACE(OTHER, logout("%p\n", s));
+    /* TODO: Clearing of hash register for selective reset, too? */
+    memset(&s->mult[0], 0, sizeof(s->mult));
+    nic_selective_reset(s);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char * const e100_reg[PCI_IO_SIZE / 4] = {
+    "Command/Status",
+    "General Pointer",
+    "Port",
+    "EEPROM/Flash Control",
+    "MDI Control",
+    "Receive DMA Byte Count",
+    "Flow Control",
+    "General Status/Control"
+};
+
+static char *regname(uint32_t addr)
+{
+    static char buf[32];
+    if (addr < PCI_IO_SIZE) {
+        const char *r = e100_reg[addr / 4];
+        if (r != 0) {
+            snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
+        } else {
+            snprintf(buf, sizeof(buf), "0x%02x", addr);
+        }
+    } else {
+        snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
+    }
+    return buf;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+/*****************************************************************************
+ *
+ * Command emulation.
+ *
+ ****************************************************************************/
+
+#if 0
+static uint16_t eepro100_read_command(EEPRO100State * s)
+{
+    uint16_t val = 0xffff;
+    TRACE(OTHER, logout("val=0x%04x\n", val));
+    return val;
+}
+#endif
+
+/* Commands that can be put in a command list entry. */
+enum commands {
+    CmdNOp = 0,
+    CmdIASetup = 1,
+    CmdConfigure = 2,
+    CmdMulticastList = 3,
+    CmdTx = 4,
+    CmdTDR = 5,                 /* load microcode */
+    CmdDump = 6,
+    CmdDiagnose = 7,
+
+    /* And some extra flags: */
+    CmdSuspend = 0x4000,        /* Suspend after completion. */
+    CmdIntr = 0x2000,           /* Interrupt after completion. */
+    CmdTxFlex = 0x0008,         /* Use "Flexible mode" for CmdTx command. */
+};
+
+static cu_state_t get_cu_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
+}
+
+static void set_cu_state(EEPRO100State * s, cu_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
+}
+
+static ru_state_t get_ru_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
+}
+
+static void set_ru_state(EEPRO100State * s, ru_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
+}
+
+static void dump_statistics(EEPRO100State * s)
+{
+    /* Dump statistical data. Most data is never changed by the emulation
+     * and always 0, so we first just copy the whole block and then those
+     * values which really matter.
+     * Number of data should check configuration!!!
+     */
+    cpu_physical_memory_write(s->statsaddr, &s->statistics, s->stats_size);
+    e100_stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
+    e100_stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
+    e100_stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
+    e100_stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
+#if 0
+    e100_stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
+    e100_stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
+    missing("CU dump statistical counters");
+#endif
+}
+
+static void read_cb(EEPRO100State *s)
+{
+    cpu_physical_memory_read(s->cb_address, &s->tx, sizeof(s->tx));
+    s->tx.status = le16_to_cpu(s->tx.status);
+    s->tx.command = le16_to_cpu(s->tx.command);
+    s->tx.link = le32_to_cpu(s->tx.link);
+    s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
+    s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
+}
+
+static void tx_command(EEPRO100State *s)
+{
+    uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
+    uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
+    /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
+    uint8_t buf[2600];
+    uint16_t size = 0;
+    uint32_t tbd_address = s->cb_address + 0x10;
+    TRACE(RXTX, logout
+        ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
+         tbd_array, tcb_bytes, s->tx.tbd_count));
+
+    if (tcb_bytes > 2600) {
+        logout("TCB byte count too large, using 2600\n");
+        tcb_bytes = 2600;
+    }
+    if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
+        logout
+            ("illegal values of TBD array address and TCB byte count!\n");
+    }
+    assert(tcb_bytes <= sizeof(buf));
+    while (size < tcb_bytes) {
+        uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+        uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
+#if 0
+        uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
+#endif
+        tbd_address += 8;
+        TRACE(RXTX, logout
+            ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+             tx_buffer_address, tx_buffer_size));
+        tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+        cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                 tx_buffer_size);
+        size += tx_buffer_size;
+    }
+    if (tbd_array == 0xffffffff) {
+        /* Simplified mode. Was already handled by code above. */
+    } else {
+        /* Flexible mode. */
+        uint8_t tbd_count = 0;
+        if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
+            /* Extended Flexible TCB. */
+            for (; tbd_count < 2; tbd_count++) {
+                uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+                uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
+                uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
+                tbd_address += 8;
+                TRACE(RXTX, logout
+                    ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                     tx_buffer_address, tx_buffer_size));
+                tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+                cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                         tx_buffer_size);
+                size += tx_buffer_size;
+                if (tx_buffer_el & 1) {
+                    break;
+                }
+            }
+        }
+        tbd_address = tbd_array;
+        for (; tbd_count < s->tx.tbd_count; tbd_count++) {
+            uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+            uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
+            uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
+            tbd_address += 8;
+            TRACE(RXTX, logout
+                ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                 tx_buffer_address, tx_buffer_size));
+            tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+            cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                     tx_buffer_size);
+            size += tx_buffer_size;
+            if (tx_buffer_el & 1) {
+                break;
+            }
+        }
+    }
+    TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
+    qemu_send_packet(&s->nic->nc, buf, size);
+    s->statistics.tx_good_frames++;
+    /* Transmit with bad status would raise an CX/TNO interrupt.
+     * (82557 only). Emulation never has bad status. */
+#if 0
+    eepro100_cx_interrupt(s);
+#endif
+}
+
+static void set_multicast_list(EEPRO100State *s)
+{
+    uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
+    uint16_t i;
+    memset(&s->mult[0], 0, sizeof(s->mult));
+    TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
+    for (i = 0; i < multicast_count; i += 6) {
+        uint8_t multicast_addr[6];
+        cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6);
+        TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
+        unsigned mcast_idx = compute_mcast_idx(multicast_addr);
+        assert(mcast_idx < 64);
+        s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
+    }
+}
+
+static void action_command(EEPRO100State *s)
+{
+    for (;;) {
+        bool bit_el;
+        bool bit_s;
+        bool bit_i;
+        bool bit_nc;
+        uint16_t ok_status = STATUS_OK;
+        s->cb_address = s->cu_base + s->cu_offset;
+        read_cb(s);
+        bit_el = ((s->tx.command & COMMAND_EL) != 0);
+        bit_s = ((s->tx.command & COMMAND_S) != 0);
+        bit_i = ((s->tx.command & COMMAND_I) != 0);
+        bit_nc = ((s->tx.command & COMMAND_NC) != 0);
+#if 0
+        bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
+#endif
+        s->cu_offset = s->tx.link;
+        TRACE(OTHER,
+              logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
+                     s->tx.status, s->tx.command, s->tx.link));
+        switch (s->tx.command & COMMAND_CMD) {
+        case CmdNOp:
+            /* Do nothing. */
+            break;
+        case CmdIASetup:
+            cpu_physical_memory_read(s->cb_address + 8, &s->conf.macaddr.a[0], 6);
+            TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
+            break;
+        case CmdConfigure:
+            cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
+                                     sizeof(s->configuration));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[16],
+                                ARRAY_SIZE(s->configuration) - 16)));
+            if (s->configuration[20] & BIT(6)) {
+                TRACE(OTHER, logout("Multiple IA bit\n"));
+            }
+            break;
+        case CmdMulticastList:
+            set_multicast_list(s);
+            break;
+        case CmdTx:
+            if (bit_nc) {
+                missing("CmdTx: NC = 0");
+                ok_status = 0;
+                break;
+            }
+            tx_command(s);
+            break;
+        case CmdTDR:
+            TRACE(OTHER, logout("load microcode\n"));
+            /* Starting with offset 8, the command contains
+             * 64 dwords microcode which we just ignore here. */
+            break;
+        case CmdDiagnose:
+            TRACE(OTHER, logout("diagnose\n"));
+            /* Make sure error flag is not set. */
+            s->tx.status = 0;
+            break;
+        default:
+            missing("undefined command");
+            ok_status = 0;
+            break;
+        }
+        /* Write new status. */
+        e100_stw_le_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
+        if (bit_i) {
+            /* CU completed action. */
+            eepro100_cx_interrupt(s);
+        }
+        if (bit_el) {
+            /* CU becomes idle. Terminate command loop. */
+            set_cu_state(s, cu_idle);
+            eepro100_cna_interrupt(s);
+            break;
+        } else if (bit_s) {
+            /* CU becomes suspended. Terminate command loop. */
+            set_cu_state(s, cu_suspended);
+            eepro100_cna_interrupt(s);
+            break;
+        } else {
+            /* More entries in list. */
+            TRACE(OTHER, logout("CU list with at least one more entry\n"));
+        }
+    }
+    TRACE(OTHER, logout("CU list empty\n"));
+    /* List is empty. Now CU is idle or suspended. */
+}
+
+static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+{
+    cu_state_t cu_state;
+    switch (val) {
+    case CU_NOP:
+        /* No operation. */
+        break;
+    case CU_START:
+        cu_state = get_cu_state(s);
+        if (cu_state != cu_idle && cu_state != cu_suspended) {
+            /* Intel documentation says that CU must be idle or suspended
+             * for the CU start command. */
+            logout("unexpected CU state is %u\n", cu_state);
+        }
+        set_cu_state(s, cu_active);
+        s->cu_offset = e100_read_reg4(s, SCBPointer);
+        action_command(s);
+        break;
+    case CU_RESUME:
+        if (get_cu_state(s) != cu_suspended) {
+            logout("bad CU resume from CU state %u\n", get_cu_state(s));
+            /* Workaround for bad Linux eepro100 driver which resumes
+             * from idle state. */
+#if 0
+            missing("cu resume");
+#endif
+            set_cu_state(s, cu_suspended);
+        }
+        if (get_cu_state(s) == cu_suspended) {
+            TRACE(OTHER, logout("CU resuming\n"));
+            set_cu_state(s, cu_active);
+            action_command(s);
+        }
+        break;
+    case CU_STATSADDR:
+        /* Load dump counters address. */
+        s->statsaddr = e100_read_reg4(s, SCBPointer);
+        TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
+        break;
+    case CU_SHOWSTATS:
+        /* Dump statistical counters. */
+        TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
+        dump_statistics(s);
+        e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
+        break;
+    case CU_CMD_BASE:
+        /* Load CU base. */
+        TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
+        s->cu_base = e100_read_reg4(s, SCBPointer);
+        break;
+    case CU_DUMPSTATS:
+        /* Dump and reset statistical counters. */
+        TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
+        dump_statistics(s);
+        e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
+        memset(&s->statistics, 0, sizeof(s->statistics));
+        break;
+    case CU_SRESUME:
+        /* CU static resume. */
+        missing("CU static resume");
+        break;
+    default:
+        missing("Undefined CU command");
+    }
+}
+
+static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
+{
+    switch (val) {
+    case RU_NOP:
+        /* No operation. */
+        break;
+    case RX_START:
+        /* RU start. */
+        if (get_ru_state(s) != ru_idle) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
+#if 0
+            assert(!"wrong RU state");
+#endif
+        }
+        set_ru_state(s, ru_ready);
+        s->ru_offset = e100_read_reg4(s, SCBPointer);
+        TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
+        break;
+    case RX_RESUME:
+        /* Restart RU. */
+        if (get_ru_state(s) != ru_suspended) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s),
+                   ru_suspended);
+#if 0
+            assert(!"wrong RU state");
+#endif
+        }
+        set_ru_state(s, ru_ready);
+        break;
+    case RU_ABORT:
+        /* RU abort. */
+        if (get_ru_state(s) == ru_ready) {
+            eepro100_rnr_interrupt(s);
+        }
+        set_ru_state(s, ru_idle);
+        break;
+    case RX_ADDR_LOAD:
+        /* Load RU base. */
+        TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
+        s->ru_base = e100_read_reg4(s, SCBPointer);
+        break;
+    default:
+        logout("val=0x%02x (undefined RU command)\n", val);
+        missing("Undefined SU command");
+    }
+}
+
+static void eepro100_write_command(EEPRO100State * s, uint8_t val)
+{
+    eepro100_ru_command(s, val & 0x0f);
+    eepro100_cu_command(s, val & 0xf0);
+    if ((val) == 0) {
+        TRACE(OTHER, logout("val=0x%02x\n", val));
+    }
+    /* Clear command byte after command was accepted. */
+    s->mem[SCBCmd] = 0;
+}
+
+/*****************************************************************************
+ *
+ * EEPROM emulation.
+ *
+ ****************************************************************************/
+
+#define EEPROM_CS       0x02
+#define EEPROM_SK       0x01
+#define EEPROM_DI       0x04
+#define EEPROM_DO       0x08
+
+static uint16_t eepro100_read_eeprom(EEPRO100State * s)
+{
+    uint16_t val = e100_read_reg2(s, SCBeeprom);
+    if (eeprom93xx_read(s->eeprom)) {
+        val |= EEPROM_DO;
+    } else {
+        val &= ~EEPROM_DO;
+    }
+    TRACE(EEPROM, logout("val=0x%04x\n", val));
+    return val;
+}
+
+static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
+{
+    TRACE(EEPROM, logout("val=0x%02x\n", val));
+
+    /* mask unwritable bits */
+#if 0
+    val = SET_MASKED(val, 0x31, eeprom->value);
+#endif
+
+    int eecs = ((val & EEPROM_CS) != 0);
+    int eesk = ((val & EEPROM_SK) != 0);
+    int eedi = ((val & EEPROM_DI) != 0);
+    eeprom93xx_write(eeprom, eecs, eesk, eedi);
+}
+
+/*****************************************************************************
+ *
+ * MDI emulation.
+ *
+ ****************************************************************************/
+
+#if defined(DEBUG_EEPRO100)
+static const char * const mdi_op_name[] = {
+    "opcode 0",
+    "write",
+    "read",
+    "opcode 3"
+};
+
+static const char * const mdi_reg_name[] = {
+    "Control",
+    "Status",
+    "PHY Identification (Word 1)",
+    "PHY Identification (Word 2)",
+    "Auto-Negotiation Advertisement",
+    "Auto-Negotiation Link Partner Ability",
+    "Auto-Negotiation Expansion"
+};
+
+static const char *reg2name(uint8_t reg)
+{
+    static char buffer[10];
+    const char *p = buffer;
+    if (reg < ARRAY_SIZE(mdi_reg_name)) {
+        p = mdi_reg_name[reg];
+    } else {
+        snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
+    }
+    return p;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+static uint32_t eepro100_read_mdi(EEPRO100State * s)
+{
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
+
+#ifdef DEBUG_EEPRO100
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+#endif
+    /* Emulation takes no time to finish MDI transaction. */
+    val |= BIT(28);
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                      val, raiseint, mdi_op_name[opcode], phy,
+                      reg2name(reg), data));
+    return val;
+}
+
+static void eepro100_write_mdi(EEPRO100State *s)
+{
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+          val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
+    if (phy != 1) {
+        /* Unsupported PHY address. */
+#if 0
+        logout("phy must be 1 but is %u\n", phy);
+#endif
+        data = 0;
+    } else if (opcode != 1 && opcode != 2) {
+        /* Unsupported opcode. */
+        logout("opcode must be 1 or 2 but is %u\n", opcode);
+        data = 0;
+    } else if (reg > 6) {
+        /* Unsupported register. */
+        logout("register must be 0...6 but is %u\n", reg);
+        data = 0;
+    } else {
+        TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                          val, raiseint, mdi_op_name[opcode], phy,
+                          reg2name(reg), data));
+        if (opcode == 1) {
+            /* MDI write */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                    data = s->mdimem[reg];
+                } else {
+                    /* Restart Auto Configuration = Normal Operation */
+                    data &= ~0x0200;
+                }
+                break;
+            case 1:            /* Status Register */
+                missing("not writable");
+                data = s->mdimem[reg];
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+                missing("not implemented");
+                break;
+            case 4:            /* Auto-Negotiation Advertisement Register */
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+            default:
+                missing("not implemented");
+            }
+            s->mdimem[reg] = data;
+        } else if (opcode == 2) {
+            /* MDI read */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                }
+                break;
+            case 1:            /* Status Register */
+                s->mdimem[reg] |= 0x0020;
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+            case 4:            /* Auto-Negotiation Advertisement Register */
+                break;
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                s->mdimem[reg] = 0x41fe;
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+                s->mdimem[reg] = 0x0001;
+                break;
+            }
+            data = s->mdimem[reg];
+        }
+        /* Emulation takes no time to finish MDI transaction.
+         * Set MDI bit in SCB status register. */
+        s->mem[SCBAck] |= 0x08;
+        val |= BIT(28);
+        if (raiseint) {
+            eepro100_mdi_interrupt(s);
+        }
+    }
+    val = (val & 0xffff0000) + data;
+    e100_write_reg4(s, SCBCtrlMDI, val);
+}
+
+/*****************************************************************************
+ *
+ * Port emulation.
+ *
+ ****************************************************************************/
+
+#define PORT_SOFTWARE_RESET     0
+#define PORT_SELFTEST           1
+#define PORT_SELECTIVE_RESET    2
+#define PORT_DUMP               3
+#define PORT_SELECTION_MASK     3
+
+typedef struct {
+    uint32_t st_sign;           /* Self Test Signature */
+    uint32_t st_result;         /* Self Test Results */
+} eepro100_selftest_t;
+
+static uint32_t eepro100_read_port(EEPRO100State * s)
+{
+    return 0;
+}
+
+static void eepro100_write_port(EEPRO100State *s)
+{
+    uint32_t val = e100_read_reg4(s, SCBPort);
+    uint32_t address = (val & ~PORT_SELECTION_MASK);
+    uint8_t selection = (val & PORT_SELECTION_MASK);
+    switch (selection) {
+    case PORT_SOFTWARE_RESET:
+        nic_reset(s);
+        break;
+    case PORT_SELFTEST:
+        TRACE(OTHER, logout("selftest address=0x%08x\n", address));
+        eepro100_selftest_t data;
+        cpu_physical_memory_read(address, &data, sizeof(data));
+        data.st_sign = 0xffffffff;
+        data.st_result = 0;
+        cpu_physical_memory_write(address, &data, sizeof(data));
+        break;
+    case PORT_SELECTIVE_RESET:
+        TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
+        nic_selective_reset(s);
+        break;
+    default:
+        logout("val=0x%08x\n", val);
+        missing("unknown port selection");
+    }
+}
+
+/*****************************************************************************
+ *
+ * General hardware emulation.
+ *
+ ****************************************************************************/
+
+static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
+{
+    uint8_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = s->mem[addr];
+    }
+
+    switch (addr) {
+    case SCBStatus:
+    case SCBAck:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+#if 0
+        val = eepro100_read_command(s);
+#endif
+        break;
+    case SCBIntmask:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+    case SCBCtrlMDI + 3:
+        val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBpmdr:       /* Power Management Driver Register */
+        val = 0;
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBgctrl:      /* General Control Register */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBgstat:      /* General Status Register */
+        /* 100 Mbps full duplex, valid link */
+        val = 0x07;
+        TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte read");
+    }
+    return val;
+}
+
+static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
+{
+    uint16_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = e100_read_reg2(s, addr);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 2:
+        val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word read");
+    }
+    return val;
+}
+
+static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
+{
+    uint32_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = e100_read_reg4(s, addr);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPointer:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        val = eepro100_read_port(s);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBflash:
+        val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI:
+        val = eepro100_read_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword read");
+    }
+    return val;
+}
+
+static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
+{
+    /* SCBStatus is readonly. */
+    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
+        s->mem[addr] = val;
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBAck:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_command(s, val);
+        break;
+    case SCBIntmask:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        if (val & BIT(1)) {
+            eepro100_swi_interrupt(s);
+        }
+        eepro100_interrupt(s, 0);
+        break;
+    case SCBPointer:
+    case SCBPointer + 1:
+    case SCBPointer + 2:
+    case SCBPointer + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort:
+    case SCBPort + 1:
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBFlow:       /* does not exist on 82557 */
+    case SCBFlow + 1:
+    case SCBFlow + 2:
+    case SCBpmdr:       /* does not exist on 82557 */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte write");
+    }
+}
+
+static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
+{
+    /* SCBStatus is readonly. */
+    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
+        e100_write_reg2(s, addr, val);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        s->mem[SCBAck] = (val >> 8);
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_command(s, val);
+        eepro100_write1(s, SCBIntmask, val >> 8);
+        break;
+    case SCBPointer:
+    case SCBPointer + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word write");
+    }
+}
+
+static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
+{
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        e100_write_reg4(s, addr, val);
+    }
+
+    switch (addr) {
+    case SCBPointer:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBflash:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        val = val >> 16;
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword write");
+    }
+}
+
+/*****************************************************************************
+ *
+ * Port mapped I/O.
+ *
+ ****************************************************************************/
+
+static uint32_t ioport_read1(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s\n", regname(addr));
+#endif
+    return eepro100_read1(s, addr - s->region1);
+}
+
+static uint32_t ioport_read2(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+    return eepro100_read2(s, addr - s->region1);
+}
+
+static uint32_t ioport_read4(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+    return eepro100_read4(s, addr - s->region1);
+}
+
+static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s val=0x%02x\n", regname(addr), val);
+#endif
+    eepro100_write1(s, addr - s->region1, val);
+}
+
+static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    eepro100_write2(s, addr - s->region1, val);
+}
+
+static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    eepro100_write4(s, addr - s->region1, val);
+}
+
+/***********************************************************/
+/* PCI EEPRO100 definitions */
+
+static void pci_map(PCIDevice * pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
+
+    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
+          "size=0x%08"FMT_PCIBUS", type=%d\n",
+          region_num, addr, size, type));
+
+    assert(region_num == 1);
+    register_ioport_write(addr, size, 1, ioport_write1, s);
+    register_ioport_read(addr, size, 1, ioport_read1, s);
+    register_ioport_write(addr, size, 2, ioport_write2, s);
+    register_ioport_read(addr, size, 2, ioport_read2, s);
+    register_ioport_write(addr, size, 4, ioport_write4, s);
+    register_ioport_read(addr, size, 4, ioport_read4, s);
+
+    s->region1 = addr;
+}
+
+/*****************************************************************************
+ *
+ * Memory mapped I/O.
+ *
+ ****************************************************************************/
+
+static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s val=0x%02x\n", regname(addr), val);
+#endif
+    eepro100_write1(s, addr, val);
+}
+
+static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s val=0x%02x\n", regname(addr), val);
+#endif
+    eepro100_write2(s, addr, val);
+}
+
+static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s val=0x%02x\n", regname(addr), val);
+#endif
+    eepro100_write4(s, addr, val);
+}
+
+static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s\n", regname(addr));
+#endif
+    return eepro100_read1(s, addr);
+}
+
+static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s\n", regname(addr));
+#endif
+    return eepro100_read2(s, addr);
+}
+
+static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+#if 0
+    logout("addr=%s\n", regname(addr));
+#endif
+    return eepro100_read4(s, addr);
+}
+
+static CPUWriteMemoryFunc * const pci_mmio_write[] = {
+    pci_mmio_writeb,
+    pci_mmio_writew,
+    pci_mmio_writel
+};
+
+static CPUReadMemoryFunc * const pci_mmio_read[] = {
+    pci_mmio_readb,
+    pci_mmio_readw,
+    pci_mmio_readl
+};
+
+static int nic_can_receive(VLANClientState *nc)
+{
+    EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    TRACE(RXTX, logout("%p\n", s));
+    return get_ru_state(s) == ru_ready;
+#if 0
+    return !eepro100_buffer_full(s);
+#endif
+}
+
+static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
+{
+    /* TODO:
+     * - Magic packets should set bit 30 in power management driver register.
+     * - Interesting packets should set bit 29 in power management driver register.
+     */
+    EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    uint16_t rfd_status = 0xa000;
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    uint8_t min_buf[60];
+#endif
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+#endif
+
+    if (s->configuration[8] & 0x80) {
+        /* CSMA is disabled. */
+        logout("%p received while CSMA is disabled\n", s);
+        return -1;
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
+    } else if (size < 64 && (s->configuration[7] & BIT(0))) {
+        /* Short frame and configuration byte 7/0 (discard short receive) set:
+         * Short frame is discarded */
+        logout("%p received short frame (%zu byte)\n", s, size);
+        s->statistics.rx_short_frame_errors++;
+        return -1;
+#endif
+    } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
+        /* Long frame and configuration byte 18/3 (long receive ok) not set:
+         * Long frames are discarded. */
+        logout("%p received long frame (%zu byte), ignored\n", s, size);
+        return -1;
+    } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) {       /* !!! */
+        /* Frame matches individual address. */
+        /* TODO: check configuration byte 15/4 (ignore U/L). */
+        TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
+    } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
+        /* Broadcast frame. */
+        TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
+        rfd_status |= 0x0002;
+    } else if (buf[0] & 0x01) {
+        /* Multicast frame. */
+        TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
+        if (s->configuration[21] & BIT(3)) {
+          /* Multicast all bit is set, receive all multicast frames. */
+        } else {
+          unsigned mcast_idx = compute_mcast_idx(buf);
+          assert(mcast_idx < 64);
+          if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            /* Multicast frame is allowed in hash table. */
+          } else if (s->configuration[15] & BIT(0)) {
+              /* Promiscuous: receive all. */
+              rfd_status |= 0x0004;
+          } else {
+              TRACE(RXTX, logout("%p multicast ignored\n", s));
+              return -1;
+          }
+        }
+        /* TODO: Next not for promiscuous mode? */
+        rfd_status |= 0x0002;
+    } else if (s->configuration[15] & BIT(0)) {
+        /* Promiscuous: receive all. */
+        TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
+        rfd_status |= 0x0004;
+    } else if (s->configuration[20] & BIT(6)) {
+        /* Multiple IA bit set. */
+        unsigned mcast_idx = compute_mcast_idx(buf);
+        assert(mcast_idx < 64);
+        if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+        } else {
+            TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+            return -1;
+        }
+    } else {
+        TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
+              nic_dump(buf, size)));
+        return size;
+    }
+
+    if (get_ru_state(s) != ru_ready) {
+        /* No resources available. */
+        logout("no resources, state=%u\n", get_ru_state(s));
+        /* TODO: RNR interrupt only at first failed frame? */
+        eepro100_rnr_interrupt(s);
+        s->statistics.rx_resource_errors++;
+#if 0
+        assert(!"no resources");
+#endif
+        return -1;
+    }
+    /* !!! */
+    eepro100_rx_t rx;
+    cpu_physical_memory_read(s->ru_base + s->ru_offset, &rx,
+                             sizeof(eepro100_rx_t));
+    uint16_t rfd_command = le16_to_cpu(rx.command);
+    uint16_t rfd_size = le16_to_cpu(rx.size);
+
+    if (size > rfd_size) {
+        logout("Receive buffer (%" PRId16 " bytes) too small for data "
+            "(%zu bytes); data truncated\n", rfd_size, size);
+        size = rfd_size;
+    }
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
+    if (size < 64) {
+        rfd_status |= 0x0080;
+    }
+#endif
+    TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
+          rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
+    e100_stw_le_phys(s->ru_base + s->ru_offset +
+                     offsetof(eepro100_rx_t, status), rfd_status);
+    e100_stw_le_phys(s->ru_base + s->ru_offset +
+                     offsetof(eepro100_rx_t, count), size);
+    /* Early receive interrupt not supported. */
+#if 0
+    eepro100_er_interrupt(s);
+#endif
+    /* Receive CRC Transfer not supported. */
+    if (s->configuration[18] & BIT(2)) {
+        missing("Receive CRC Transfer");
+        return -1;
+    }
+    /* TODO: check stripping enable bit. */
+#if 0
+    assert(!(s->configuration[17] & BIT(0)));
+#endif
+    cpu_physical_memory_write(s->ru_base + s->ru_offset +
+                              sizeof(eepro100_rx_t), buf, size);
+    s->statistics.rx_good_frames++;
+    eepro100_fr_interrupt(s);
+    s->ru_offset = le32_to_cpu(rx.link);
+    if (rfd_command & COMMAND_EL) {
+        /* EL bit is set, so this was the last frame. */
+        logout("receive: Running out of frames\n");
+        set_ru_state(s, ru_suspended);
+    }
+    if (rfd_command & COMMAND_S) {
+        /* S bit is set. */
+        set_ru_state(s, ru_suspended);
+    }
+    return size;
+}
+
+static const VMStateDescription vmstate_eepro100 = {
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, EEPRO100State),
+        VMSTATE_UNUSED(32),
+        VMSTATE_BUFFER(mult, EEPRO100State),
+        VMSTATE_BUFFER(mem, EEPRO100State),
+        /* Save all members of struct between scb_stat and mem. */
+        VMSTATE_UINT8(scb_stat, EEPRO100State),
+        VMSTATE_UINT8(int_stat, EEPRO100State),
+        VMSTATE_UNUSED(3*4),
+        VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
+        VMSTATE_UNUSED(19*4),
+        VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
+        /* The eeprom should be saved and restored by its own routines. */
+        VMSTATE_UINT32(device, EEPRO100State),
+        /* TODO check device. */
+        VMSTATE_UINT32(cu_base, EEPRO100State),
+        VMSTATE_UINT32(cu_offset, EEPRO100State),
+        VMSTATE_UINT32(ru_base, EEPRO100State),
+        VMSTATE_UINT32(ru_offset, EEPRO100State),
+        VMSTATE_UINT32(statsaddr, EEPRO100State),
+        /* Save eepro100_stats_t statistics. */
+        VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
+        VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
+        VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
+        /* Configuration bytes. */
+        VMSTATE_BUFFER(configuration, EEPRO100State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void nic_cleanup(VLANClientState *nc)
+{
+    EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static int pci_nic_uninit(PCIDevice *pci_dev)
+{
+    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
+
+    cpu_unregister_io_memory(s->mmio_index);
+    vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+    eeprom93xx_free(&pci_dev->qdev, s->eeprom);
+    qemu_del_vlan_client(&s->nic->nc);
+    return 0;
+}
+
+static NetClientInfo net_eepro100_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = nic_can_receive,
+    .receive = nic_receive,
+    .cleanup = nic_cleanup,
+};
+
+static int e100_nic_init(PCIDevice *pci_dev)
+{
+    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
+    E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
+                                               pci_dev->qdev.info);
+
+    TRACE(OTHER, logout("\n"));
+
+    s->device = e100_device->device;
+
+    e100_pci_reset(s, e100_device);
+
+    /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
+     * i82559 and later support 64 or 256 word EEPROM. */
+    s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
+
+    /* Handler for memory-mapped I/O */
+    s->mmio_index =
+        cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
+                               DEVICE_LITTLE_ENDIAN);
+
+    pci_register_bar_simple(&s->dev, 0, PCI_MEM_SIZE,
+                            PCI_BASE_ADDRESS_MEM_PREFETCH, s->mmio_index);
+
+    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
+                           pci_map);
+    pci_register_bar_simple(&s->dev, 2, PCI_FLASH_SIZE, 0, s->mmio_index);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
+    assert(s->region1 == 0);
+
+    nic_reset(s);
+
+    s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
+                          pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    TRACE(OTHER, logout("%s\n", s->nic->nc.info_str));
+
+    qemu_register_reset(nic_reset, s);
+
+    s->vmstate = qemu_malloc(sizeof(vmstate_eepro100));
+    memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
+    s->vmstate->name = s->nic->nc.model;
+    vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
+
+    add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
+    return 0;
+}
+
+static E100PCIDeviceInfo e100_devices[] = {
+    {
+        .pci.qdev.name = "i82550",
+        .pci.qdev.desc = "Intel i82550 Ethernet",
+        .device = i82550,
+        /* TODO: check device id. */
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* Revision ID: 0x0c, 0x0d, 0x0e. */
+        .pci.revision = 0x0e,
+        /* TODO: check size of statistical counters. */
+        .stats_size = 80,
+        /* TODO: check extended tcb support. */
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82551",
+        .pci.qdev.desc = "Intel i82551 Ethernet",
+        .device = i82551,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* Revision ID: 0x0f, 0x10. */
+        .pci.revision = 0x0f,
+        /* TODO: check size of statistical counters. */
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82557a",
+        .pci.qdev.desc = "Intel i82557A Ethernet",
+        .device = i82557A,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x01,
+        .power_management = false,
+    },{
+        .pci.qdev.name = "i82557b",
+        .pci.qdev.desc = "Intel i82557B Ethernet",
+        .device = i82557B,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x02,
+        .power_management = false,
+    },{
+        .pci.qdev.name = "i82557c",
+        .pci.qdev.desc = "Intel i82557C Ethernet",
+        .device = i82557C,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x03,
+        .power_management = false,
+    },{
+        .pci.qdev.name = "i82558a",
+        .pci.qdev.desc = "Intel i82558A Ethernet",
+        .device = i82558A,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x04,
+        .stats_size = 76,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82558b",
+        .pci.qdev.desc = "Intel i82558B Ethernet",
+        .device = i82558B,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x05,
+        .stats_size = 76,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82559a",
+        .pci.qdev.desc = "Intel i82559A Ethernet",
+        .device = i82559A,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x06,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82559b",
+        .pci.qdev.desc = "Intel i82559B Ethernet",
+        .device = i82559B,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x07,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82559c",
+        .pci.qdev.desc = "Intel i82559C Ethernet",
+        .device = i82559C,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+#if 0
+        .pci.revision = 0x08,
+#endif
+        /* TODO: Windows wants revision id 0x0c. */
+        .pci.revision = 0x0c,
+#if EEPROM_SIZE > 0
+        .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+        .pci.subsystem_id = 0x0040,
+#endif
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82559er",
+        .pci.qdev.desc = "Intel i82559ER Ethernet",
+        .device = i82559ER,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.revision = 0x09,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .pci.qdev.name = "i82562",
+        .pci.qdev.desc = "Intel i82562 Ethernet",
+        .device = i82562,
+        /* TODO: check device id. */
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* TODO: wrong revision id. */
+        .pci.revision = 0x0e,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        /* Toshiba Tecra 8200. */
+        .pci.qdev.name = "i82801",
+        .pci.qdev.desc = "Intel i82801 Ethernet",
+        .device = i82801,
+        .pci.device_id = 0x2449,
+        .pci.revision = 0x03,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    }
+};
+
+static Property e100_properties[] = {
+    DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void eepro100_register_devices(void)
+{
+    size_t i;
+    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+        PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
+        /* We use the same rom file for all device ids.
+           QEMU fixes the device id during rom load. */
+        pci_dev->vendor_id = PCI_VENDOR_ID_INTEL;
+        pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
+        pci_dev->romfile = "pxe-eepro100.rom";
+        pci_dev->init = e100_nic_init;
+        pci_dev->exit = pci_nic_uninit;
+        pci_dev->qdev.props = e100_properties;
+        pci_dev->qdev.size = sizeof(EEPRO100State);
+        pci_qdev_register(pci_dev);
+    }
+}
+
+device_init(eepro100_register_devices)
diff --git a/qemu-0.15.x/hw/eeprom93xx.c b/qemu-0.15.x/hw/eeprom93xx.c
new file mode 100644
index 0000000..7b21f98
--- /dev/null
+++ b/qemu-0.15.x/hw/eeprom93xx.c
@@ -0,0 +1,337 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Emulation for serial EEPROMs:
+ * NMC93C06 256-Bit (16 x 16)
+ * NMC93C46 1024-Bit (64 x 16)
+ * NMC93C56 2028 Bit (128 x 16)
+ * NMC93C66 4096 Bit (256 x 16)
+ * Compatible devices include FM93C46 and others.
+ *
+ * Other drivers use these interface functions:
+ * eeprom93xx_new   - add a new EEPROM (with 16, 64 or 256 words)
+ * eeprom93xx_free  - destroy EEPROM
+ * eeprom93xx_read  - read data from the EEPROM
+ * eeprom93xx_write - write data to the EEPROM
+ * eeprom93xx_data  - get EEPROM data array for external manipulation
+ *
+ * Todo list:
+ * - No emulation of EEPROM timings.
+ */
+
+#include "hw.h"
+#include "eeprom93xx.h"
+
+/* Debug EEPROM emulation. */
+//~ #define DEBUG_EEPROM
+
+#ifdef DEBUG_EEPROM
+#define logout(fmt, ...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+#define EEPROM_INSTANCE  0
+#define OLD_EEPROM_VERSION 20061112
+#define EEPROM_VERSION (OLD_EEPROM_VERSION + 1)
+
+#if 0
+typedef enum {
+  eeprom_read  = 0x80,   /* read register xx */
+  eeprom_write = 0x40,   /* write register xx */
+  eeprom_erase = 0xc0,   /* erase register xx */
+  eeprom_ewen  = 0x30,   /* erase / write enable */
+  eeprom_ewds  = 0x00,   /* erase / write disable */
+  eeprom_eral  = 0x20,   /* erase all registers */
+  eeprom_wral  = 0x10,   /* write all registers */
+  eeprom_amask = 0x0f,
+  eeprom_imask = 0xf0
+} eeprom_instruction_t;
+#endif
+
+#ifdef DEBUG_EEPROM
+static const char *opstring[] = {
+  "extended", "write", "read", "erase"
+};
+#endif
+
+struct _eeprom_t {
+    uint8_t  tick;
+    uint8_t  address;
+    uint8_t  command;
+    uint8_t  writable;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedo;
+
+    uint8_t  addrbits;
+    uint16_t size;
+    uint16_t data;
+    uint16_t contents[0];
+};
+
+/* Code for saving and restoring of EEPROM state. */
+
+/* Restore an uint16_t from an uint8_t
+   This is a Big hack, but it is how the old state did it.
+ */
+
+static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size)
+{
+    uint16_t *v = pv;
+    *v = qemu_get_ubyte(f);
+    return 0;
+}
+
+static void put_unused(QEMUFile *f, void *pv, size_t size)
+{
+    fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n");
+    fprintf(stderr, "Never should be used to write a new state.\n");
+    exit(0);
+}
+
+static const VMStateInfo vmstate_hack_uint16_from_uint8 = {
+    .name = "uint16_from_uint8",
+    .get  = get_uint16_from_uint8,
+    .put  = put_unused,
+};
+
+#define VMSTATE_UINT16_HACK_TEST(_f, _s, _t)                           \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint16_from_uint8, uint16_t)
+
+static bool is_old_eeprom_version(void *opaque, int version_id)
+{
+    return version_id == OLD_EEPROM_VERSION;
+}
+
+static const VMStateDescription vmstate_eeprom = {
+    .name = "eeprom",
+    .version_id = EEPROM_VERSION,
+    .minimum_version_id = OLD_EEPROM_VERSION,
+    .minimum_version_id_old = OLD_EEPROM_VERSION,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(tick, eeprom_t),
+        VMSTATE_UINT8(address, eeprom_t),
+        VMSTATE_UINT8(command, eeprom_t),
+        VMSTATE_UINT8(writable, eeprom_t),
+
+        VMSTATE_UINT8(eecs, eeprom_t),
+        VMSTATE_UINT8(eesk, eeprom_t),
+        VMSTATE_UINT8(eedo, eeprom_t),
+
+        VMSTATE_UINT8(addrbits, eeprom_t),
+        VMSTATE_UINT16_HACK_TEST(size, eeprom_t, is_old_eeprom_version),
+        VMSTATE_UNUSED_TEST(is_old_eeprom_version, 1),
+        VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION),
+        VMSTATE_UINT16(data, eeprom_t),
+        VMSTATE_VARRAY_UINT16_UNSAFE(contents, eeprom_t, size, 0,
+                                     vmstate_info_uint16, uint16_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
+{
+    uint8_t tick = eeprom->tick;
+    uint8_t eedo = eeprom->eedo;
+    uint16_t address = eeprom->address;
+    uint8_t command = eeprom->command;
+
+    logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
+           eecs, eesk, eedi, eedo, tick);
+
+    if (! eeprom->eecs && eecs) {
+        /* Start chip select cycle. */
+        logout("Cycle start, waiting for 1st start bit (0)\n");
+        tick = 0;
+        command = 0x0;
+        address = 0x0;
+    } else if (eeprom->eecs && ! eecs) {
+        /* End chip select cycle. This triggers write / erase. */
+        if (eeprom->writable) {
+            uint8_t subcommand = address >> (eeprom->addrbits - 2);
+            if (command == 0 && subcommand == 2) {
+                /* Erase all. */
+                for (address = 0; address < eeprom->size; address++) {
+                    eeprom->contents[address] = 0xffff;
+                }
+            } else if (command == 3) {
+                /* Erase word. */
+                eeprom->contents[address] = 0xffff;
+            } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
+                if (command == 1) {
+                    /* Write word. */
+                    eeprom->contents[address] &= eeprom->data;
+                } else if (command == 0 && subcommand == 1) {
+                    /* Write all. */
+                    for (address = 0; address < eeprom->size; address++) {
+                        eeprom->contents[address] &= eeprom->data;
+                    }
+                }
+            }
+        }
+        /* Output DO is tristate, read results in 1. */
+        eedo = 1;
+    } else if (eecs && ! eeprom->eesk && eesk) {
+        /* Raising edge of clock shifts data in. */
+        if (tick == 0) {
+            /* Wait for 1st start bit. */
+            if (eedi == 0) {
+                logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
+                tick++;
+            } else {
+                logout("wrong 1st start bit (is 1, should be 0)\n");
+                tick = 2;
+                //~ assert(!"wrong start bit");
+            }
+        } else if (tick == 1) {
+            /* Wait for 2nd start bit. */
+            if (eedi != 0) {
+                logout("Got correct 2nd start bit, getting command + address\n");
+                tick++;
+            } else {
+                logout("1st start bit is longer than needed\n");
+            }
+        } else if (tick < 2 + 2) {
+            /* Got 2 start bits, transfer 2 opcode bits. */
+            tick++;
+            command <<= 1;
+            if (eedi) {
+                command += 1;
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits) {
+            /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
+            tick++;
+            address = ((address << 1) | eedi);
+            if (tick == 2 + 2 + eeprom->addrbits) {
+                logout("%s command, address = 0x%02x (value 0x%04x)\n",
+                       opstring[command], address, eeprom->contents[address]);
+                if (command == 2) {
+                    eedo = 0;
+                }
+                address = address % eeprom->size;
+                if (command == 0) {
+                    /* Command code in upper 2 bits of address. */
+                    switch (address >> (eeprom->addrbits - 2)) {
+                        case 0:
+                            logout("write disable command\n");
+                            eeprom->writable = 0;
+                            break;
+                        case 1:
+                            logout("write all command\n");
+                            break;
+                        case 2:
+                            logout("erase all command\n");
+                            break;
+                        case 3:
+                            logout("write enable command\n");
+                            eeprom->writable = 1;
+                            break;
+                    }
+                } else {
+                    /* Read, write or erase word. */
+                    eeprom->data = eeprom->contents[address];
+                }
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
+            /* Transfer 16 data bits. */
+            tick++;
+            if (command == 2) {
+                /* Read word. */
+                eedo = ((eeprom->data & 0x8000) != 0);
+            }
+            eeprom->data <<= 1;
+            eeprom->data += eedi;
+        } else {
+            logout("additional unneeded tick, not processed\n");
+        }
+    }
+    /* Save status of EEPROM. */
+    eeprom->tick = tick;
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedo = eedo;
+    eeprom->address = address;
+    eeprom->command = command;
+}
+
+uint16_t eeprom93xx_read(eeprom_t *eeprom)
+{
+    /* Return status of pin DO (0 or 1). */
+    logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
+    return (eeprom->eedo);
+}
+
+#if 0
+void eeprom93xx_reset(eeprom_t *eeprom)
+{
+    /* prepare eeprom */
+    logout("eeprom = 0x%p\n", eeprom);
+    eeprom->tick = 0;
+    eeprom->command = 0;
+}
+#endif
+
+eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
+{
+    /* Add a new EEPROM (with 16, 64 or 256 words). */
+    eeprom_t *eeprom;
+    uint8_t addrbits;
+
+    switch (nwords) {
+        case 16:
+        case 64:
+            addrbits = 6;
+            break;
+        case 128:
+        case 256:
+            addrbits = 8;
+            break;
+        default:
+            assert(!"Unsupported EEPROM size, fallback to 64 words!");
+            nwords = 64;
+            addrbits = 6;
+    }
+
+    eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2);
+    eeprom->size = nwords;
+    eeprom->addrbits = addrbits;
+    /* Output DO is tristate, read results in 1. */
+    eeprom->eedo = 1;
+    logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
+    vmstate_register(dev, 0, &vmstate_eeprom, eeprom);
+    return eeprom;
+}
+
+void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
+{
+    /* Destroy EEPROM. */
+    logout("eeprom = 0x%p\n", eeprom);
+    vmstate_unregister(dev, &vmstate_eeprom, eeprom);
+    qemu_free(eeprom);
+}
+
+uint16_t *eeprom93xx_data(eeprom_t *eeprom)
+{
+    /* Get EEPROM data array. */
+    return &eeprom->contents[0];
+}
+
+/* eof */
diff --git a/qemu-0.15.x/hw/eeprom93xx.h b/qemu-0.15.x/hw/eeprom93xx.h
new file mode 100644
index 0000000..8ba0e28
--- /dev/null
+++ b/qemu-0.15.x/hw/eeprom93xx.h
@@ -0,0 +1,40 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EEPROM93XX_H
+#define EEPROM93XX_H
+
+typedef struct _eeprom_t eeprom_t;
+
+/* Create a new EEPROM with (nwords * 2) bytes. */
+eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords);
+
+/* Destroy an existing EEPROM. */
+void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom);
+
+/* Read from the EEPROM. */
+uint16_t eeprom93xx_read(eeprom_t *eeprom);
+
+/* Write to the EEPROM. */
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi);
+
+/* Get EEPROM data array. */
+uint16_t *eeprom93xx_data(eeprom_t *eeprom);
+
+#endif /* EEPROM93XX_H */
diff --git a/qemu-0.15.x/hw/elf_ops.h b/qemu-0.15.x/hw/elf_ops.h
new file mode 100644
index 0000000..0bd7235
--- /dev/null
+++ b/qemu-0.15.x/hw/elf_ops.h
@@ -0,0 +1,297 @@
+static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);			/* Object file type */
+    bswap16s(&ehdr->e_machine);		/* Architecture */
+    bswap32s(&ehdr->e_version);		/* Object file version */
+    bswapSZs(&ehdr->e_entry);		/* Entry point virtual address */
+    bswapSZs(&ehdr->e_phoff);		/* Program header table file offset */
+    bswapSZs(&ehdr->e_shoff);		/* Section header table file offset */
+    bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
+}
+
+static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
+{
+    bswap32s(&phdr->p_type);			/* Segment type */
+    bswapSZs(&phdr->p_offset);		/* Segment file offset */
+    bswapSZs(&phdr->p_vaddr);		/* Segment virtual address */
+    bswapSZs(&phdr->p_paddr);		/* Segment physical address */
+    bswapSZs(&phdr->p_filesz);		/* Segment size in file */
+    bswapSZs(&phdr->p_memsz);		/* Segment size in memory */
+    bswap32s(&phdr->p_flags);		/* Segment flags */
+    bswapSZs(&phdr->p_align);		/* Segment alignment */
+}
+
+static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswapSZs(&shdr->sh_flags);
+    bswapSZs(&shdr->sh_addr);
+    bswapSZs(&shdr->sh_offset);
+    bswapSZs(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswapSZs(&shdr->sh_addralign);
+    bswapSZs(&shdr->sh_entsize);
+}
+
+static void glue(bswap_sym, SZ)(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswapSZs(&sym->st_value);
+    bswapSZs(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+
+static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
+                                               int n, int type)
+{
+    int i;
+    for(i=0;i<n;i++) {
+        if (shdr_table[i].sh_type == type)
+            return shdr_table + i;
+    }
+    return NULL;
+}
+
+static int glue(symfind, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *key = (struct elf_sym *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (key->st_value < sym->st_value) {
+        result = -1;
+    } else if (key->st_value >= sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
+                                           target_phys_addr_t orig_addr)
+{
+    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
+    struct elf_sym key;
+    struct elf_sym *sym;
+
+    key.st_value = orig_addr;
+
+    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
+    if (sym != NULL) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+static int glue(symcmp, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
+                                  int clear_lsb)
+{
+    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
+    struct elf_sym *syms = NULL;
+    struct syminfo *s;
+    int nsyms, i;
+    char *str = NULL;
+
+    shdr_table = load_at(fd, ehdr->e_shoff,
+                         sizeof(struct elf_shdr) * ehdr->e_shnum);
+    if (!shdr_table)
+        return -1;
+
+    if (must_swab) {
+        for (i = 0; i < ehdr->e_shnum; i++) {
+            glue(bswap_shdr, SZ)(shdr_table + i);
+        }
+    }
+
+    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
+    if (!symtab)
+        goto fail;
+    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
+    if (!syms)
+        goto fail;
+
+    nsyms = symtab->sh_size / sizeof(struct elf_sym);
+
+    i = 0;
+    while (i < nsyms) {
+        if (must_swab)
+            glue(bswap_sym, SZ)(&syms[i]);
+        /* We are only interested in function symbols.
+           Throw everything else away.  */
+        if (syms[i].st_shndx == SHN_UNDEF ||
+                syms[i].st_shndx >= SHN_LORESERVE ||
+                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            nsyms--;
+            if (i < nsyms) {
+                syms[i] = syms[nsyms];
+            }
+            continue;
+        }
+        if (clear_lsb) {
+            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
+        }
+        i++;
+    }
+    if (nsyms) {
+        syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+
+        qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+        for (i = 0; i < nsyms - 1; i++) {
+            if (syms[i].st_size == 0) {
+                syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
+            }
+        }
+    } else {
+        qemu_free(syms);
+        syms = NULL;
+    }
+
+    /* String table */
+    if (symtab->sh_link >= ehdr->e_shnum)
+        goto fail;
+    strtab = &shdr_table[symtab->sh_link];
+
+    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
+    if (!str)
+        goto fail;
+
+    /* Commit */
+    s = qemu_mallocz(sizeof(*s));
+    s->lookup_symbol = glue(lookup_symbol, SZ);
+    glue(s->disas_symtab.elf, SZ) = syms;
+    s->disas_num_syms = nsyms;
+    s->disas_strtab = str;
+    s->next = syminfos;
+    syminfos = s;
+    qemu_free(shdr_table);
+    return 0;
+ fail:
+    qemu_free(syms);
+    qemu_free(str);
+    qemu_free(shdr_table);
+    return -1;
+}
+
+static int glue(load_elf, SZ)(const char *name, int fd,
+                              uint64_t (*translate_fn)(void *, uint64_t),
+                              void *translate_opaque,
+                              int must_swab, uint64_t *pentry,
+                              uint64_t *lowaddr, uint64_t *highaddr,
+                              int elf_machine, int clear_lsb)
+{
+    struct elfhdr ehdr;
+    struct elf_phdr *phdr = NULL, *ph;
+    int size, i, total_size;
+    elf_word mem_size;
+    uint64_t addr, low = (uint64_t)-1, high = 0;
+    uint8_t *data = NULL;
+    char label[128];
+
+    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+        goto fail;
+    if (must_swab) {
+        glue(bswap_ehdr, SZ)(&ehdr);
+    }
+
+    switch (elf_machine) {
+        case EM_PPC64:
+            if (EM_PPC64 != ehdr.e_machine)
+                if (EM_PPC != ehdr.e_machine)
+                    goto fail;
+            break;
+        case EM_X86_64:
+            if (EM_X86_64 != ehdr.e_machine)
+                if (EM_386 != ehdr.e_machine)
+                    goto fail;
+            break;
+        case EM_MICROBLAZE:
+            if (EM_MICROBLAZE != ehdr.e_machine)
+                if (EM_MICROBLAZE_OLD != ehdr.e_machine)
+                    goto fail;
+            break;
+        default:
+            if (elf_machine != ehdr.e_machine)
+                goto fail;
+    }
+
+    if (pentry)
+   	*pentry = (uint64_t)(elf_sword)ehdr.e_entry;
+
+    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
+
+    size = ehdr.e_phnum * sizeof(phdr[0]);
+    lseek(fd, ehdr.e_phoff, SEEK_SET);
+    phdr = qemu_mallocz(size);
+    if (!phdr)
+        goto fail;
+    if (read(fd, phdr, size) != size)
+        goto fail;
+    if (must_swab) {
+        for(i = 0; i < ehdr.e_phnum; i++) {
+            ph = &phdr[i];
+            glue(bswap_phdr, SZ)(ph);
+        }
+    }
+
+    total_size = 0;
+    for(i = 0; i < ehdr.e_phnum; i++) {
+        ph = &phdr[i];
+        if (ph->p_type == PT_LOAD) {
+            mem_size = ph->p_memsz;
+            /* XXX: avoid allocating */
+            data = qemu_mallocz(mem_size);
+            if (ph->p_filesz > 0) {
+                if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
+                    goto fail;
+                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
+                    goto fail;
+            }
+            /* address_offset is hack for kernel images that are
+               linked at the wrong physical address.  */
+            if (translate_fn) {
+                addr = translate_fn(translate_opaque, ph->p_paddr);
+            } else {
+                addr = ph->p_paddr;
+            }
+
+            snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
+            rom_add_blob_fixed(label, data, mem_size, addr);
+
+            total_size += mem_size;
+            if (addr < low)
+                low = addr;
+            if ((addr + mem_size) > high)
+                high = addr + mem_size;
+
+            qemu_free(data);
+            data = NULL;
+        }
+    }
+    qemu_free(phdr);
+    if (lowaddr)
+        *lowaddr = (uint64_t)(elf_sword)low;
+    if (highaddr)
+        *highaddr = (uint64_t)(elf_sword)high;
+    return total_size;
+ fail:
+    qemu_free(data);
+    qemu_free(phdr);
+    return -1;
+}
diff --git a/qemu-0.15.x/hw/empty_slot.c b/qemu-0.15.x/hw/empty_slot.c
new file mode 100644
index 0000000..da8adc4
--- /dev/null
+++ b/qemu-0.15.x/hw/empty_slot.c
@@ -0,0 +1,96 @@
+/*
+ * QEMU Empty Slot
+ *
+ * The empty_slot device emulates known to a bus but not connected devices.
+ *
+ * Copyright (c) 2010 Artyom Tarasenko
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
+ * version.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "empty_slot.h"
+
+//#define DEBUG_EMPTY_SLOT
+
+#ifdef DEBUG_EMPTY_SLOT
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("empty_slot: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+typedef struct EmptySlot {
+    SysBusDevice busdev;
+    uint64_t size;
+} EmptySlot;
+
+static uint32_t empty_slot_readl(void *opaque, target_phys_addr_t addr)
+{
+    DPRINTF("read from " TARGET_FMT_plx "\n", addr);
+    return 0;
+}
+
+static void empty_slot_writel(void *opaque, target_phys_addr_t addr,
+                              uint32_t val)
+{
+    DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", val, addr);
+}
+
+CPUReadMemoryFunc * const empty_slot_read[3] = {
+    empty_slot_readl,
+    empty_slot_readl,
+    empty_slot_readl,
+};
+
+static CPUWriteMemoryFunc * const empty_slot_write[3] = {
+    empty_slot_writel,
+    empty_slot_writel,
+    empty_slot_writel,
+};
+
+void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size)
+{
+    if (slot_size > 0) {
+        /* Only empty slots larger than 0 byte need handling. */
+        DeviceState *dev;
+        SysBusDevice *s;
+        EmptySlot *e;
+
+        dev = qdev_create(NULL, "empty_slot");
+        s = sysbus_from_qdev(dev);
+        e = FROM_SYSBUS(EmptySlot, s);
+        e->size = slot_size;
+
+        qdev_init_nofail(dev);
+
+        sysbus_mmio_map(s, 0, addr);
+    }
+}
+
+static int empty_slot_init1(SysBusDevice *dev)
+{
+    EmptySlot *s = FROM_SYSBUS(EmptySlot, dev);
+    ram_addr_t empty_slot_offset;
+
+    empty_slot_offset = cpu_register_io_memory(empty_slot_read,
+                                               empty_slot_write, s,
+                                               DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, s->size, empty_slot_offset | IO_MEM_RAM);
+    return 0;
+}
+
+static SysBusDeviceInfo empty_slot_info = {
+    .init = empty_slot_init1,
+    .qdev.name  = "empty_slot",
+    .qdev.size  = sizeof(EmptySlot),
+};
+
+static void empty_slot_register_devices(void)
+{
+    sysbus_register_withprop(&empty_slot_info);
+}
+
+device_init(empty_slot_register_devices);
diff --git a/qemu-0.15.x/hw/empty_slot.h b/qemu-0.15.x/hw/empty_slot.h
new file mode 100644
index 0000000..78dc91d
--- /dev/null
+++ b/qemu-0.15.x/hw/empty_slot.h
@@ -0,0 +1,2 @@
+/* empty_slot.c */
+void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size);
diff --git a/qemu-0.15.x/hw/es1370.c b/qemu-0.15.x/hw/es1370.c
new file mode 100644
index 0000000..1ed62b7
--- /dev/null
+++ b/qemu-0.15.x/hw/es1370.c
@@ -0,0 +1,1051 @@
+/*
+ * QEMU ES1370 emulation
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/* #define DEBUG_ES1370 */
+/* #define VERBOSE_ES1370 */
+#define SILENT_ES1370
+
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "pci.h"
+
+/* Missing stuff:
+   SCTRL_P[12](END|ST)INC
+   SCTRL_P1SCTRLD
+   SCTRL_P2DACSEN
+   CTRL_DAC_SYNC
+   MIDI
+   non looped mode
+   surely more
+*/
+
+/*
+  Following macros and samplerate array were copied verbatim from
+  Linux kernel 2.4.30: drivers/sound/es1370.c
+
+  Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer at alumni.ethz.ch)
+*/
+
+/* Start blatant GPL violation */
+
+#define ES1370_REG_CONTROL        0x00
+#define ES1370_REG_STATUS         0x04
+#define ES1370_REG_UART_DATA      0x08
+#define ES1370_REG_UART_STATUS    0x09
+#define ES1370_REG_UART_CONTROL   0x09
+#define ES1370_REG_UART_TEST      0x0a
+#define ES1370_REG_MEMPAGE        0x0c
+#define ES1370_REG_CODEC          0x10
+#define ES1370_REG_SERIAL_CONTROL 0x20
+#define ES1370_REG_DAC1_SCOUNT    0x24
+#define ES1370_REG_DAC2_SCOUNT    0x28
+#define ES1370_REG_ADC_SCOUNT     0x2c
+
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
+
+static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
+
+#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
+#define DAC2_DIVTOSR(x) (1411200/((x)+2))
+
+#define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
+#define CTRL_XCTL1      0x40000000  /* electret mic bias */
+#define CTRL_OPEN       0x20000000  /* no function, can be read and written */
+#define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
+#define CTRL_SH_PCLKDIV 16
+#define CTRL_MSFMTSEL   0x00008000  /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
+#define CTRL_M_SBB      0x00004000  /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
+#define CTRL_WTSRSEL    0x00003000  /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
+#define CTRL_SH_WTSRSEL 12
+#define CTRL_DAC_SYNC   0x00000800  /* 1 = DAC2 runs off DAC1 clock */
+#define CTRL_CCB_INTRM  0x00000400  /* 1 = CCB "voice" ints enabled */
+#define CTRL_M_CB       0x00000200  /* recording source: 0 = ADC, 1 = MPEG */
+#define CTRL_XCTL0      0x00000100  /* 0 = Line in, 1 = Line out */
+#define CTRL_BREQ       0x00000080  /* 1 = test mode (internal mem test) */
+#define CTRL_DAC1_EN    0x00000040  /* enable DAC1 */
+#define CTRL_DAC2_EN    0x00000020  /* enable DAC2 */
+#define CTRL_ADC_EN     0x00000010  /* enable ADC */
+#define CTRL_UART_EN    0x00000008  /* enable MIDI uart */
+#define CTRL_JYSTK_EN   0x00000004  /* enable Joystick port (presumably at address 0x200) */
+#define CTRL_CDC_EN     0x00000002  /* enable serial (CODEC) interface */
+#define CTRL_SERR_DIS   0x00000001  /* 1 = disable PCI SERR signal */
+
+#define STAT_INTR       0x80000000  /* wired or of all interrupt bits */
+#define STAT_CSTAT      0x00000400  /* 1 = codec busy or codec write in progress */
+#define STAT_CBUSY      0x00000200  /* 1 = codec busy */
+#define STAT_CWRIP      0x00000100  /* 1 = codec write in progress */
+#define STAT_VC         0x00000060  /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
+#define STAT_SH_VC      5
+#define STAT_MCCB       0x00000010  /* CCB int pending */
+#define STAT_UART       0x00000008  /* UART int pending */
+#define STAT_DAC1       0x00000004  /* DAC1 int pending */
+#define STAT_DAC2       0x00000002  /* DAC2 int pending */
+#define STAT_ADC        0x00000001  /* ADC int pending */
+
+#define USTAT_RXINT     0x80        /* UART rx int pending */
+#define USTAT_TXINT     0x04        /* UART tx int pending */
+#define USTAT_TXRDY     0x02        /* UART tx ready */
+#define USTAT_RXRDY     0x01        /* UART rx ready */
+
+#define UCTRL_RXINTEN   0x80        /* 1 = enable RX ints */
+#define UCTRL_TXINTEN   0x60        /* TX int enable field mask */
+#define UCTRL_ENA_TXINT 0x20        /* enable TX int */
+#define UCTRL_CNTRL     0x03        /* control field */
+#define UCTRL_CNTRL_SWR 0x03        /* software reset command */
+
+#define SCTRL_P2ENDINC    0x00380000  /*  */
+#define SCTRL_SH_P2ENDINC 19
+#define SCTRL_P2STINC     0x00070000  /*  */
+#define SCTRL_SH_P2STINC  16
+#define SCTRL_R1LOOPSEL   0x00008000  /* 0 = loop mode */
+#define SCTRL_P2LOOPSEL   0x00004000  /* 0 = loop mode */
+#define SCTRL_P1LOOPSEL   0x00002000  /* 0 = loop mode */
+#define SCTRL_P2PAUSE     0x00001000  /* 1 = pause mode */
+#define SCTRL_P1PAUSE     0x00000800  /* 1 = pause mode */
+#define SCTRL_R1INTEN     0x00000400  /* enable interrupt */
+#define SCTRL_P2INTEN     0x00000200  /* enable interrupt */
+#define SCTRL_P1INTEN     0x00000100  /* enable interrupt */
+#define SCTRL_P1SCTRLD    0x00000080  /* reload sample count register for DAC1 */
+#define SCTRL_P2DACSEN    0x00000040  /* 1 = DAC2 play back last sample when disabled */
+#define SCTRL_R1SEB       0x00000020  /* 1 = 16bit */
+#define SCTRL_R1SMB       0x00000010  /* 1 = stereo */
+#define SCTRL_R1FMT       0x00000030  /* format mask */
+#define SCTRL_SH_R1FMT    4
+#define SCTRL_P2SEB       0x00000008  /* 1 = 16bit */
+#define SCTRL_P2SMB       0x00000004  /* 1 = stereo */
+#define SCTRL_P2FMT       0x0000000c  /* format mask */
+#define SCTRL_SH_P2FMT    2
+#define SCTRL_P1SEB       0x00000002  /* 1 = 16bit */
+#define SCTRL_P1SMB       0x00000001  /* 1 = stereo */
+#define SCTRL_P1FMT       0x00000003  /* format mask */
+#define SCTRL_SH_P1FMT    0
+
+/* End blatant GPL violation */
+
+#define NB_CHANNELS 3
+#define DAC1_CHANNEL 0
+#define DAC2_CHANNEL 1
+#define ADC_CHANNEL 2
+
+#define IO_READ_PROTO(n) \
+static uint32_t n (void *opaque, uint32_t addr)
+#define IO_WRITE_PROTO(n) \
+static void n (void *opaque, uint32_t addr, uint32_t val)
+
+static void es1370_dac1_callback (void *opaque, int free);
+static void es1370_dac2_callback (void *opaque, int free);
+static void es1370_adc_callback (void *opaque, int avail);
+
+#ifdef DEBUG_ES1370
+
+#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
+
+static void print_ctl (uint32_t val)
+{
+    char buf[1024];
+
+    buf[0] = '\0';
+#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
+    a (ADC_STOP);
+    a (XCTL1);
+    a (OPEN);
+    a (MSFMTSEL);
+    a (M_SBB);
+    a (DAC_SYNC);
+    a (CCB_INTRM);
+    a (M_CB);
+    a (XCTL0);
+    a (BREQ);
+    a (DAC1_EN);
+    a (DAC2_EN);
+    a (ADC_EN);
+    a (UART_EN);
+    a (JYSTK_EN);
+    a (CDC_EN);
+    a (SERR_DIS);
+#undef a
+    AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
+             (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
+             DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+             dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
+             buf);
+}
+
+static void print_sctl (uint32_t val)
+{
+    static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
+    char buf[1024];
+
+    buf[0] = '\0';
+
+#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
+#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
+    b (R1LOOPSEL);
+    b (P2LOOPSEL);
+    b (P1LOOPSEL);
+    a (P2PAUSE);
+    a (P1PAUSE);
+    a (R1INTEN);
+    a (P2INTEN);
+    a (P1INTEN);
+    a (P1SCTRLD);
+    a (P2DACSEN);
+    if (buf[0]) {
+        strcat (buf, "\n        ");
+    }
+    else {
+        buf[0] = ' ';
+        buf[1] = '\0';
+    }
+#undef b
+#undef a
+    AUD_log ("es1370",
+             "%s"
+             "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
+             buf,
+             (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
+             (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
+             fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
+        );
+}
+#else
+#define ldebug(...)
+#define print_ctl(...)
+#define print_sctl(...)
+#endif
+
+#ifdef VERBOSE_ES1370
+#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#ifndef SILENT_ES1370
+#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
+#else
+#define lwarn(...)
+#endif
+
+struct chan {
+    uint32_t shift;
+    uint32_t leftover;
+    uint32_t scount;
+    uint32_t frame_addr;
+    uint32_t frame_cnt;
+};
+
+typedef struct ES1370State {
+    PCIDevice dev;
+    QEMUSoundCard card;
+    struct chan chan[NB_CHANNELS];
+    SWVoiceOut *dac_voice[2];
+    SWVoiceIn *adc_voice;
+
+    uint32_t ctl;
+    uint32_t status;
+    uint32_t mempage;
+    uint32_t codec;
+    uint32_t sctl;
+} ES1370State;
+
+struct chan_bits {
+    uint32_t ctl_en;
+    uint32_t stat_int;
+    uint32_t sctl_pause;
+    uint32_t sctl_inten;
+    uint32_t sctl_fmt;
+    uint32_t sctl_sh_fmt;
+    uint32_t sctl_loopsel;
+    void (*calc_freq) (ES1370State *s, uint32_t ctl,
+                       uint32_t *old_freq, uint32_t *new_freq);
+};
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq);
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq);
+
+static const struct chan_bits es1370_chan_bits[] = {
+    {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
+     SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
+     es1370_dac1_calc_freq},
+
+    {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
+     SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
+     es1370_dac2_and_adc_calc_freq},
+
+    {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
+     SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
+     es1370_dac2_and_adc_calc_freq}
+};
+
+static void es1370_update_status (ES1370State *s, uint32_t new_status)
+{
+    uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
+
+    if (level) {
+        s->status = new_status | STAT_INTR;
+    }
+    else {
+        s->status = new_status & ~STAT_INTR;
+    }
+    qemu_set_irq (s->dev.irq[0], !!level);
+}
+
+static void es1370_reset (ES1370State *s)
+{
+    size_t i;
+
+    s->ctl = 1;
+    s->status = 0x60;
+    s->mempage = 0;
+    s->codec = 0;
+    s->sctl = 0;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        d->scount = 0;
+        d->leftover = 0;
+        if (i == ADC_CHANNEL) {
+            AUD_close_in (&s->card, s->adc_voice);
+            s->adc_voice = NULL;
+        }
+        else {
+            AUD_close_out (&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = NULL;
+        }
+    }
+    qemu_irq_lower (s->dev.irq[0]);
+}
+
+static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
+{
+    uint32_t new_status = s->status;
+
+    if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
+        new_status &= ~STAT_DAC1;
+    }
+
+    if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
+        new_status &= ~STAT_DAC2;
+    }
+
+    if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
+        new_status &= ~STAT_ADC;
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq)
+
+{
+    *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+    *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+}
+
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq)
+
+{
+    uint32_t old_pclkdiv, new_pclkdiv;
+
+    new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    *new_freq = DAC2_DIVTOSR (new_pclkdiv);
+    *old_freq = DAC2_DIVTOSR (old_pclkdiv);
+}
+
+static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
+{
+    size_t i;
+    uint32_t old_freq, new_freq, old_fmt, new_fmt;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        const struct chan_bits *b = &es1370_chan_bits[i];
+
+        new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+        old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+
+        b->calc_freq (s, ctl, &old_freq, &new_freq);
+
+        if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
+            d->shift = (new_fmt & 1) + (new_fmt >> 1);
+            ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n",
+                    i,
+                    new_freq,
+                    1 << (new_fmt & 1),
+                    (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
+                    d->shift);
+            if (new_freq) {
+                struct audsettings as;
+
+                as.freq = new_freq;
+                as.nchannels = 1 << (new_fmt & 1);
+                as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
+                as.endianness = 0;
+
+                if (i == ADC_CHANNEL) {
+                    s->adc_voice =
+                        AUD_open_in (
+                            &s->card,
+                            s->adc_voice,
+                            "es1370.adc",
+                            s,
+                            es1370_adc_callback,
+                            &as
+                            );
+                }
+                else {
+                    s->dac_voice[i] =
+                        AUD_open_out (
+                            &s->card,
+                            s->dac_voice[i],
+                            i ? "es1370.dac2" : "es1370.dac1",
+                            s,
+                            i ? es1370_dac2_callback : es1370_dac1_callback,
+                            &as
+                            );
+                }
+            }
+        }
+
+        if (((ctl ^ s->ctl) & b->ctl_en)
+            || ((sctl ^ s->sctl) & b->sctl_pause)) {
+            int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
+
+            if (i == ADC_CHANNEL) {
+                AUD_set_active_in (s->adc_voice, on);
+            }
+            else {
+                AUD_set_active_out (s->dac_voice[i], on);
+            }
+        }
+    }
+
+    s->ctl = ctl;
+    s->sctl = sctl;
+}
+
+static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
+{
+    addr &= 0xff;
+    if (addr >= 0x30 && addr <= 0x3f)
+        addr |= s->mempage << 8;
+    return addr;
+}
+
+IO_WRITE_PROTO (es1370_writeb)
+{
+    ES1370State *s = opaque;
+    uint32_t shift, mask;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        shift = (addr - ES1370_REG_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+    case ES1370_REG_SERIAL_CONTROL + 1:
+    case ES1370_REG_SERIAL_CONTROL + 2:
+    case ES1370_REG_SERIAL_CONTROL + 3:
+        shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->sctl & ~mask) | ((val & 0xff) << shift);
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+    default:
+        lwarn ("writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writew)
+{
+    ES1370State *s = opaque;
+    addr = es1370_fixup (s, addr);
+    uint32_t shift, mask;
+    struct chan *d = &s->chan[0];
+
+    switch (addr) {
+    case ES1370_REG_CODEC:
+        dolog ("ignored codec write address %#x, data %#x\n",
+               (val >> 8) & 0xff, val & 0xff);
+        s->codec = val;
+        break;
+
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 2:
+        shift = (addr != ES1370_REG_CONTROL) << 4;
+        mask = 0xffff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (d->scount & ~0xffff) | (val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writel)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val & 0xf;
+        break;
+
+    case ES1370_REG_SERIAL_CONTROL:
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (val & 0xffff) | (d->scount & ~0xffff);
+        ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n",
+                d - &s->chan[0], val >> 16, (val & 0xffff));
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        d->frame_addr = val;
+        ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val);
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        lwarn ("writing to phantom frame count %#x\n", val);
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        lwarn ("writing to phantom frame address %#x\n", val);
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        d->frame_cnt = val;
+        d->leftover = 0;
+        ldebug ("chan %d frame count %d, buffer size %d\n",
+                d - &s->chan[0], val >> 16, val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_READ_PROTO (es1370_readb)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case 0x1b:                  /* Legacy */
+        lwarn ("Attempt to read from legacy register\n");
+        val = 5;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CONTROL + 0:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
+        break;
+    case ES1370_REG_STATUS + 0:
+    case ES1370_REG_STATUS + 1:
+    case ES1370_REG_STATUS + 2:
+    case ES1370_REG_STATUS + 3:
+        val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
+        break;
+    default:
+        val = ~0;
+        lwarn ("readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+IO_READ_PROTO (es1370_readw)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_ADC_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT + 2:
+        val = d->scount >> 16;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt & 0xffff;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT + 2:
+        val = d->frame_cnt >> 16;
+        break;
+
+    default:
+        val = ~0;
+        lwarn ("readw %#x -> %#x\n", addr, val);
+        break;
+    }
+
+    return val;
+}
+
+IO_READ_PROTO (es1370_readl)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        val = s->ctl;
+        break;
+    case ES1370_REG_STATUS:
+        val = s->status;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CODEC:
+        val = s->codec;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+        val = s->sctl;
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        val = d->scount;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t curr_count = d->scount >> 16;
+            uint32_t count = d->scount & 0xffff;
+
+            curr_count <<= d->shift;
+            count <<= d->shift;
+            dolog ("read scount curr %d, total %d\n", curr_count, count);
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
+            uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
+            if (curr > size)
+                dolog ("read framecnt curr %d, size %d %d\n", curr, size,
+                       curr > size);
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        val = d->frame_addr;
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        val = ~0U;
+        lwarn ("reading from phantom frame count\n");
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        val = ~0U;
+        lwarn ("reading from phantom frame address\n");
+        break;
+
+    default:
+        val = ~0U;
+        lwarn ("readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+
+static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
+                                   int max, int *irq)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = d->frame_addr;
+    int sc = d->scount & 0xffff;
+    int csc = d->scount >> 16;
+    int csc_bytes = (csc + 1) << d->shift;
+    int cnt = d->frame_cnt >> 16;
+    int size = d->frame_cnt & 0xffff;
+    int left = ((size - cnt + 1) << 2) + d->leftover;
+    int transfered = 0;
+    int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
+    int index = d - &s->chan[0];
+
+    addr += (cnt << 2) + d->leftover;
+
+    if (index == ADC_CHANNEL) {
+        while (temp) {
+            int acquired, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
+            if (!acquired)
+                break;
+
+            cpu_physical_memory_write (addr, tmpbuf, acquired);
+
+            temp -= acquired;
+            addr += acquired;
+            transfered += acquired;
+        }
+    }
+    else {
+        SWVoiceOut *voice = s->dac_voice[index];
+
+        while (temp) {
+            int copied, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            cpu_physical_memory_read (addr, tmpbuf, to_copy);
+            copied = AUD_write (voice, tmpbuf, to_copy);
+            if (!copied)
+                break;
+            temp -= copied;
+            addr += copied;
+            transfered += copied;
+        }
+    }
+
+    if (csc_bytes == transfered) {
+        *irq = 1;
+        d->scount = sc | (sc << 16);
+        ldebug ("sc = %d, rate = %f\n",
+                (sc + 1) << d->shift,
+                (sc + 1) / (double) 44100);
+    }
+    else {
+        *irq = 0;
+        d->scount = sc | (((csc_bytes - transfered - 1) >> d->shift) << 16);
+    }
+
+    cnt += (transfered + d->leftover) >> 2;
+
+    if (s->sctl & loop_sel) {
+        /* Bah, how stupid is that having a 0 represent true value?
+           i just spent few hours on this shit */
+        AUD_log ("es1370: warning", "non looping mode\n");
+    }
+    else {
+        d->frame_cnt = size;
+
+        if ((uint32_t) cnt <= d->frame_cnt)
+            d->frame_cnt |= cnt << 16;
+    }
+
+    d->leftover = (transfered + d->leftover) & 3;
+}
+
+static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
+{
+    uint32_t new_status = s->status;
+    int max_bytes, irq;
+    struct chan *d = &s->chan[chan];
+    const struct chan_bits *b = &es1370_chan_bits[chan];
+
+    if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
+        return;
+    }
+
+    max_bytes = free_or_avail;
+    max_bytes &= ~((1 << d->shift) - 1);
+    if (!max_bytes) {
+        return;
+    }
+
+    es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
+
+    if (irq) {
+        if (s->sctl & b->sctl_inten) {
+            new_status |= b->stat_int;
+        }
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC1_CHANNEL, free);
+}
+
+static void es1370_dac2_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC2_CHANNEL, free);
+}
+
+static void es1370_adc_callback (void *opaque, int avail)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, ADC_CHANNEL, avail);
+}
+
+static void es1370_map (PCIDevice *pci_dev, int region_num,
+                        pcibus_t addr, pcibus_t size, int type)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
+
+    (void) region_num;
+    (void) size;
+    (void) type;
+
+    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
+    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
+    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
+
+    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
+    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
+    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
+}
+
+static const VMStateDescription vmstate_es1370_channel = {
+    .name = "es1370_channel",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(shift, struct chan),
+        VMSTATE_UINT32(leftover, struct chan),
+        VMSTATE_UINT32(scount, struct chan),
+        VMSTATE_UINT32(frame_addr, struct chan),
+        VMSTATE_UINT32(frame_cnt, struct chan),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int es1370_post_load (void *opaque, int version_id)
+{
+    uint32_t ctl, sctl;
+    ES1370State *s = opaque;
+    size_t i;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        if (i == ADC_CHANNEL) {
+            if (s->adc_voice) {
+                AUD_close_in (&s->card, s->adc_voice);
+                s->adc_voice = NULL;
+            }
+        }
+        else {
+            if (s->dac_voice[i]) {
+                AUD_close_out (&s->card, s->dac_voice[i]);
+                s->dac_voice[i] = NULL;
+            }
+        }
+    }
+
+    ctl = s->ctl;
+    sctl = s->sctl;
+    s->ctl = 0;
+    s->sctl = 0;
+    es1370_update_voices (s, ctl, sctl);
+    return 0;
+}
+
+static const VMStateDescription vmstate_es1370 = {
+    .name = "es1370",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = es1370_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, ES1370State),
+        VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2,
+                             vmstate_es1370_channel, struct chan),
+        VMSTATE_UINT32(ctl, ES1370State),
+        VMSTATE_UINT32(status, ES1370State),
+        VMSTATE_UINT32(mempage, ES1370State),
+        VMSTATE_UINT32(codec, ES1370State),
+        VMSTATE_UINT32(sctl, ES1370State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void es1370_on_reset (void *opaque)
+{
+    ES1370State *s = opaque;
+    es1370_reset (s);
+}
+
+static int es1370_initfn (PCIDevice *dev)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
+    uint8_t *c = s->dev.config;
+
+    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
+
+#if 0
+    c[PCI_CAPABILITY_LIST] = 0xdc;
+    c[PCI_INTERRUPT_LINE] = 10;
+    c[0xdc] = 0x00;
+#endif
+
+    /* TODO: RST# value should be 0. */
+    c[PCI_INTERRUPT_PIN] = 1;
+    c[PCI_MIN_GNT] = 0x0c;
+    c[PCI_MAX_LAT] = 0x80;
+
+    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
+    qemu_register_reset (es1370_on_reset, s);
+
+    AUD_register_card ("es1370", &s->card);
+    es1370_reset (s);
+    return 0;
+}
+
+int es1370_init (PCIBus *bus)
+{
+    pci_create_simple (bus, -1, "ES1370");
+    return 0;
+}
+
+static PCIDeviceInfo es1370_info = {
+    .qdev.name    = "ES1370",
+    .qdev.desc    = "ENSONIQ AudioPCI ES1370",
+    .qdev.size    = sizeof (ES1370State),
+    .qdev.vmsd    = &vmstate_es1370,
+    .init         = es1370_initfn,
+    .vendor_id    = PCI_VENDOR_ID_ENSONIQ,
+    .device_id    = PCI_DEVICE_ID_ENSONIQ_ES1370,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
+#if 1
+    .subsystem_vendor_id = 0x4942,
+    .subsystem_id = 0x4c4c,
+#else
+    .subsystem_vendor_id = 0x1274,
+    .subsystem_id = 0x1371,
+#endif
+};
+
+static void es1370_register (void)
+{
+    pci_qdev_register (&es1370_info);
+}
+device_init (es1370_register);
+
diff --git a/qemu-0.15.x/hw/escc.c b/qemu-0.15.x/hw/escc.c
new file mode 100644
index 0000000..f6fd919
--- /dev/null
+++ b/qemu-0.15.x/hw/escc.c
@@ -0,0 +1,961 @@
+/*
+ * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
+ *
+ * Copyright (c) 2003-2005 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 "hw.h"
+#include "sysbus.h"
+#include "escc.h"
+#include "qemu-char.h"
+#include "console.h"
+
+/* debug serial */
+//#define DEBUG_SERIAL
+
+/* debug keyboard */
+//#define DEBUG_KBD
+
+/* debug mouse */
+//#define DEBUG_MOUSE
+
+/*
+ * Chipset docs:
+ * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
+ * http://www.zilog.com/docs/serial/scc_escc_um.pdf
+ *
+ * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
+ * (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
+ * mouse and keyboard ports don't implement all functions and they are
+ * only asynchronous. There is no DMA.
+ *
+ * Z85C30 is also used on PowerMacs. There are some small differences
+ * between Sparc version (sunzilog) and PowerMac (pmac):
+ *  Offset between control and data registers
+ *  There is some kind of lockup bug, but we can ignore it
+ *  CTS is inverted
+ *  DMA on pmac using DBDMA chip
+ *  pmac can do IRDA and faster rates, sunzilog can only do 38400
+ *  pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
+ */
+
+/*
+ * Modifications:
+ *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
+ *                                  serial mouse queue.
+ *                                  Implemented serial mouse protocol.
+ *
+ *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
+ */
+
+#ifdef DEBUG_SERIAL
+#define SER_DPRINTF(fmt, ...)                                   \
+    do { printf("SER: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define SER_DPRINTF(fmt, ...)
+#endif
+#ifdef DEBUG_KBD
+#define KBD_DPRINTF(fmt, ...)                                   \
+    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define KBD_DPRINTF(fmt, ...)
+#endif
+#ifdef DEBUG_MOUSE
+#define MS_DPRINTF(fmt, ...)                                    \
+    do { printf("MSC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define MS_DPRINTF(fmt, ...)
+#endif
+
+typedef enum {
+    chn_a, chn_b,
+} ChnID;
+
+#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
+
+typedef enum {
+    ser, kbd, mouse,
+} ChnType;
+
+#define SERIO_QUEUE_SIZE 256
+
+typedef struct {
+    uint8_t data[SERIO_QUEUE_SIZE];
+    int rptr, wptr, count;
+} SERIOQueue;
+
+#define SERIAL_REGS 16
+typedef struct ChannelState {
+    qemu_irq irq;
+    uint32_t reg;
+    uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
+    ChnID chn; // this channel, A (base+4) or B (base+0)
+    ChnType type;
+    struct ChannelState *otherchn;
+    uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
+    SERIOQueue queue;
+    CharDriverState *chr;
+    int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
+    int disabled;
+    int clock;
+    uint32_t vmstate_dummy;
+} ChannelState;
+
+struct SerialState {
+    SysBusDevice busdev;
+    struct ChannelState chn[2];
+    uint32_t it_shift;
+    int mmio_index;
+    uint32_t disabled;
+    uint32_t frequency;
+};
+
+#define SERIAL_CTRL 0
+#define SERIAL_DATA 1
+
+#define W_CMD     0
+#define CMD_PTR_MASK   0x07
+#define CMD_CMD_MASK   0x38
+#define CMD_HI         0x08
+#define CMD_CLR_TXINT  0x28
+#define CMD_CLR_IUS    0x38
+#define W_INTR    1
+#define INTR_INTALL    0x01
+#define INTR_TXINT     0x02
+#define INTR_RXMODEMSK 0x18
+#define INTR_RXINT1ST  0x08
+#define INTR_RXINTALL  0x10
+#define W_IVEC    2
+#define W_RXCTRL  3
+#define RXCTRL_RXEN    0x01
+#define W_TXCTRL1 4
+#define TXCTRL1_PAREN  0x01
+#define TXCTRL1_PAREV  0x02
+#define TXCTRL1_1STOP  0x04
+#define TXCTRL1_1HSTOP 0x08
+#define TXCTRL1_2STOP  0x0c
+#define TXCTRL1_STPMSK 0x0c
+#define TXCTRL1_CLK1X  0x00
+#define TXCTRL1_CLK16X 0x40
+#define TXCTRL1_CLK32X 0x80
+#define TXCTRL1_CLK64X 0xc0
+#define TXCTRL1_CLKMSK 0xc0
+#define W_TXCTRL2 5
+#define TXCTRL2_TXEN   0x08
+#define TXCTRL2_BITMSK 0x60
+#define TXCTRL2_5BITS  0x00
+#define TXCTRL2_7BITS  0x20
+#define TXCTRL2_6BITS  0x40
+#define TXCTRL2_8BITS  0x60
+#define W_SYNC1   6
+#define W_SYNC2   7
+#define W_TXBUF   8
+#define W_MINTR   9
+#define MINTR_STATUSHI 0x10
+#define MINTR_RST_MASK 0xc0
+#define MINTR_RST_B    0x40
+#define MINTR_RST_A    0x80
+#define MINTR_RST_ALL  0xc0
+#define W_MISC1  10
+#define W_CLOCK  11
+#define CLOCK_TRXC     0x08
+#define W_BRGLO  12
+#define W_BRGHI  13
+#define W_MISC2  14
+#define MISC2_PLLDIS   0x30
+#define W_EXTINT 15
+#define EXTINT_DCD     0x08
+#define EXTINT_SYNCINT 0x10
+#define EXTINT_CTSINT  0x20
+#define EXTINT_TXUNDRN 0x40
+#define EXTINT_BRKINT  0x80
+
+#define R_STATUS  0
+#define STATUS_RXAV    0x01
+#define STATUS_ZERO    0x02
+#define STATUS_TXEMPTY 0x04
+#define STATUS_DCD     0x08
+#define STATUS_SYNC    0x10
+#define STATUS_CTS     0x20
+#define STATUS_TXUNDRN 0x40
+#define STATUS_BRK     0x80
+#define R_SPEC    1
+#define SPEC_ALLSENT   0x01
+#define SPEC_BITS8     0x06
+#define R_IVEC    2
+#define IVEC_TXINTB    0x00
+#define IVEC_LONOINT   0x06
+#define IVEC_LORXINTA  0x0c
+#define IVEC_LORXINTB  0x04
+#define IVEC_LOTXINTA  0x08
+#define IVEC_HINOINT   0x60
+#define IVEC_HIRXINTA  0x30
+#define IVEC_HIRXINTB  0x20
+#define IVEC_HITXINTA  0x10
+#define R_INTR    3
+#define INTR_EXTINTB   0x01
+#define INTR_TXINTB    0x02
+#define INTR_RXINTB    0x04
+#define INTR_EXTINTA   0x08
+#define INTR_TXINTA    0x10
+#define INTR_RXINTA    0x20
+#define R_IPEN    4
+#define R_TXCTRL1 5
+#define R_TXCTRL2 6
+#define R_BC      7
+#define R_RXBUF   8
+#define R_RXCTRL  9
+#define R_MISC   10
+#define R_MISC1  11
+#define R_BRGLO  12
+#define R_BRGHI  13
+#define R_MISC1I 14
+#define R_EXTINT 15
+
+static void handle_kbd_command(ChannelState *s, int val);
+static int serial_can_receive(void *opaque);
+static void serial_receive_byte(ChannelState *s, int ch);
+
+static void clear_queue(void *opaque)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+    q->rptr = q->wptr = q->count = 0;
+}
+
+static void put_queue(void *opaque, int b)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+
+    SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
+    if (q->count >= SERIO_QUEUE_SIZE)
+        return;
+    q->data[q->wptr] = b;
+    if (++q->wptr == SERIO_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    serial_receive_byte(s, 0);
+}
+
+static uint32_t get_queue(void *opaque)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+    int val;
+
+    if (q->count == 0) {
+        return 0;
+    } else {
+        val = q->data[q->rptr];
+        if (++q->rptr == SERIO_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+    }
+    SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+    if (q->count > 0)
+        serial_receive_byte(s, 0);
+    return val;
+}
+
+static int escc_update_irq_chn(ChannelState *s)
+{
+    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
+         // tx ints enabled, pending
+         ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
+           ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
+          s->rxint == 1) || // rx ints enabled, pending
+         ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
+          (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
+        return 1;
+    }
+    return 0;
+}
+
+static void escc_update_irq(ChannelState *s)
+{
+    int irq;
+
+    irq = escc_update_irq_chn(s);
+    irq |= escc_update_irq_chn(s->otherchn);
+
+    SER_DPRINTF("IRQ = %d\n", irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static void escc_reset_chn(ChannelState *s)
+{
+    int i;
+
+    s->reg = 0;
+    for (i = 0; i < SERIAL_REGS; i++) {
+        s->rregs[i] = 0;
+        s->wregs[i] = 0;
+    }
+    s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
+    s->wregs[W_MINTR] = MINTR_RST_ALL;
+    s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
+    s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
+    s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
+        EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
+    if (s->disabled)
+        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
+            STATUS_CTS | STATUS_TXUNDRN;
+    else
+        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
+    s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
+
+    s->rx = s->tx = 0;
+    s->rxint = s->txint = 0;
+    s->rxint_under_svc = s->txint_under_svc = 0;
+    s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+    clear_queue(s);
+}
+
+static void escc_reset(DeviceState *d)
+{
+    SerialState *s = container_of(d, SerialState, busdev.qdev);
+
+    escc_reset_chn(&s->chn[0]);
+    escc_reset_chn(&s->chn[1]);
+}
+
+static inline void set_rxint(ChannelState *s)
+{
+    s->rxint = 1;
+    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+       than chn_a rx/tx/special_condition service*/
+    s->rxint_under_svc = 1;
+    if (s->chn == chn_a) {
+        s->rregs[R_INTR] |= INTR_RXINTA;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+    } else {
+        s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HIRXINTB;
+        else
+            s->rregs[R_IVEC] = IVEC_LORXINTB;
+    }
+    escc_update_irq(s);
+}
+
+static inline void set_txint(ChannelState *s)
+{
+    s->txint = 1;
+    if (!s->rxint_under_svc) {
+        s->txint_under_svc = 1;
+        if (s->chn == chn_a) {
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->rregs[R_INTR] |= INTR_TXINTA;
+            }
+            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+                s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
+            else
+                s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
+        } else {
+            s->rregs[R_IVEC] = IVEC_TXINTB;
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+            }
+        }
+    escc_update_irq(s);
+    }
+}
+
+static inline void clr_rxint(ChannelState *s)
+{
+    s->rxint = 0;
+    s->rxint_under_svc = 0;
+    if (s->chn == chn_a) {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
+        s->rregs[R_INTR] &= ~INTR_RXINTA;
+    } else {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->rregs[R_IVEC] = IVEC_LONOINT;
+        s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
+    }
+    if (s->txint)
+        set_txint(s);
+    escc_update_irq(s);
+}
+
+static inline void clr_txint(ChannelState *s)
+{
+    s->txint = 0;
+    s->txint_under_svc = 0;
+    if (s->chn == chn_a) {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
+        s->rregs[R_INTR] &= ~INTR_TXINTA;
+    } else {
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->rregs[R_IVEC] = IVEC_LONOINT;
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
+    }
+    if (s->rxint)
+        set_rxint(s);
+    escc_update_irq(s);
+}
+
+static void escc_update_parameters(ChannelState *s)
+{
+    int speed, parity, data_bits, stop_bits;
+    QEMUSerialSetParams ssp;
+
+    if (!s->chr || s->type != ser)
+        return;
+
+    if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
+        if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+        parity = 'N';
+    }
+    if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+    switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
+    case TXCTRL2_5BITS:
+        data_bits = 5;
+        break;
+    case TXCTRL2_7BITS:
+        data_bits = 7;
+        break;
+    case TXCTRL2_6BITS:
+        data_bits = 6;
+        break;
+    default:
+    case TXCTRL2_8BITS:
+        data_bits = 8;
+        break;
+    }
+    speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
+    switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
+    case TXCTRL1_CLK1X:
+        break;
+    case TXCTRL1_CLK16X:
+        speed /= 16;
+        break;
+    case TXCTRL1_CLK32X:
+        speed /= 32;
+        break;
+    default:
+    case TXCTRL1_CLK64X:
+        speed /= 64;
+        break;
+    }
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
+                speed, parity, data_bits, stop_bits);
+    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+}
+
+static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SerialState *serial = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    int newreg, channel;
+
+    val &= 0xff;
+    saddr = (addr >> serial->it_shift) & 1;
+    channel = (addr >> (serial->it_shift + 1)) & 1;
+    s = &serial->chn[channel];
+    switch (saddr) {
+    case SERIAL_CTRL:
+        SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
+                    val & 0xff);
+        newreg = 0;
+        switch (s->reg) {
+        case W_CMD:
+            newreg = val & CMD_PTR_MASK;
+            val &= CMD_CMD_MASK;
+            switch (val) {
+            case CMD_HI:
+                newreg |= CMD_HI;
+                break;
+            case CMD_CLR_TXINT:
+                clr_txint(s);
+                break;
+            case CMD_CLR_IUS:
+                if (s->rxint_under_svc) {
+                    s->rxint_under_svc = 0;
+                    if (s->txint) {
+                        set_txint(s);
+                    }
+                } else if (s->txint_under_svc) {
+                    s->txint_under_svc = 0;
+                }
+                escc_update_irq(s);
+                break;
+            default:
+                break;
+            }
+            break;
+        case W_INTR ... W_RXCTRL:
+        case W_SYNC1 ... W_TXBUF:
+        case W_MISC1 ... W_CLOCK:
+        case W_MISC2 ... W_EXTINT:
+            s->wregs[s->reg] = val;
+            break;
+        case W_TXCTRL1:
+        case W_TXCTRL2:
+            s->wregs[s->reg] = val;
+            escc_update_parameters(s);
+            break;
+        case W_BRGLO:
+        case W_BRGHI:
+            s->wregs[s->reg] = val;
+            s->rregs[s->reg] = val;
+            escc_update_parameters(s);
+            break;
+        case W_MINTR:
+            switch (val & MINTR_RST_MASK) {
+            case 0:
+            default:
+                break;
+            case MINTR_RST_B:
+                escc_reset_chn(&serial->chn[0]);
+                return;
+            case MINTR_RST_A:
+                escc_reset_chn(&serial->chn[1]);
+                return;
+            case MINTR_RST_ALL:
+                escc_reset(&serial->busdev.qdev);
+                return;
+            }
+            break;
+        default:
+            break;
+        }
+        if (s->reg == 0)
+            s->reg = newreg;
+        else
+            s->reg = 0;
+        break;
+    case SERIAL_DATA:
+        SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
+        s->tx = val;
+        if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
+            if (s->chr)
+                qemu_chr_write(s->chr, &s->tx, 1);
+            else if (s->type == kbd && !s->disabled) {
+                handle_kbd_command(s, val);
+            }
+        }
+        s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
+        s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
+        set_txint(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *serial = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    uint32_t ret;
+    int channel;
+
+    saddr = (addr >> serial->it_shift) & 1;
+    channel = (addr >> (serial->it_shift + 1)) & 1;
+    s = &serial->chn[channel];
+    switch (saddr) {
+    case SERIAL_CTRL:
+        SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
+                    s->rregs[s->reg]);
+        ret = s->rregs[s->reg];
+        s->reg = 0;
+        return ret;
+    case SERIAL_DATA:
+        s->rregs[R_STATUS] &= ~STATUS_RXAV;
+        clr_rxint(s);
+        if (s->type == kbd || s->type == mouse)
+            ret = get_queue(s);
+        else
+            ret = s->rx;
+        SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
+        if (s->chr)
+            qemu_chr_accept_input(s->chr);
+        return ret;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static int serial_can_receive(void *opaque)
+{
+    ChannelState *s = opaque;
+    int ret;
+
+    if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
+        || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
+        // char already available
+        ret = 0;
+    else
+        ret = 1;
+    return ret;
+}
+
+static void serial_receive_byte(ChannelState *s, int ch)
+{
+    SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
+    s->rregs[R_STATUS] |= STATUS_RXAV;
+    s->rx = ch;
+    set_rxint(s);
+}
+
+static void serial_receive_break(ChannelState *s)
+{
+    s->rregs[R_STATUS] |= STATUS_BRK;
+    escc_update_irq(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    ChannelState *s = opaque;
+    serial_receive_byte(s, buf[0]);
+}
+
+static void serial_event(void *opaque, int event)
+{
+    ChannelState *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+static CPUReadMemoryFunc * const escc_mem_read[3] = {
+    escc_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const escc_mem_write[3] = {
+    escc_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static const VMStateDescription vmstate_escc_chn = {
+    .name ="escc_chn",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(vmstate_dummy, ChannelState),
+        VMSTATE_UINT32(reg, ChannelState),
+        VMSTATE_UINT32(rxint, ChannelState),
+        VMSTATE_UINT32(txint, ChannelState),
+        VMSTATE_UINT32(rxint_under_svc, ChannelState),
+        VMSTATE_UINT32(txint_under_svc, ChannelState),
+        VMSTATE_UINT8(rx, ChannelState),
+        VMSTATE_UINT8(tx, ChannelState),
+        VMSTATE_BUFFER(wregs, ChannelState),
+        VMSTATE_BUFFER(rregs, ChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_escc = {
+    .name ="escc",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
+                             ChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+              CharDriverState *chrA, CharDriverState *chrB,
+              int clock, int it_shift)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    SerialState *d;
+
+    dev = qdev_create(NULL, "escc");
+    qdev_prop_set_uint32(dev, "disabled", 0);
+    qdev_prop_set_uint32(dev, "frequency", clock);
+    qdev_prop_set_uint32(dev, "it_shift", it_shift);
+    qdev_prop_set_chr(dev, "chrB", chrB);
+    qdev_prop_set_chr(dev, "chrA", chrA);
+    qdev_prop_set_uint32(dev, "chnBtype", ser);
+    qdev_prop_set_uint32(dev, "chnAtype", ser);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irqB);
+    sysbus_connect_irq(s, 1, irqA);
+    if (base) {
+        sysbus_mmio_map(s, 0, base);
+    }
+
+    d = FROM_SYSBUS(SerialState, s);
+    return d->mmio_index;
+}
+
+static const uint8_t keycodes[128] = {
+    127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
+    54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
+    104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
+    14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
+    113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
+    90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
+    0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
+};
+
+static const uint8_t e0_keycodes[128] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
+    113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
+};
+
+static void sunkbd_event(void *opaque, int ch)
+{
+    ChannelState *s = opaque;
+    int release = ch & 0x80;
+
+    KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
+                "press");
+    switch (ch) {
+    case 58: // Caps lock press
+        s->caps_lock_mode ^= 1;
+        if (s->caps_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 69: // Num lock press
+        s->num_lock_mode ^= 1;
+        if (s->num_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 186: // Caps lock release
+        s->caps_lock_mode ^= 2;
+        if (s->caps_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 197: // Num lock release
+        s->num_lock_mode ^= 2;
+        if (s->num_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 0xe0:
+        s->e0_mode = 1;
+        return;
+    default:
+        break;
+    }
+    if (s->e0_mode) {
+        s->e0_mode = 0;
+        ch = e0_keycodes[ch & 0x7f];
+    } else {
+        ch = keycodes[ch & 0x7f];
+    }
+    KBD_DPRINTF("Translated keycode %2.2x\n", ch);
+    put_queue(s, ch | release);
+}
+
+static void handle_kbd_command(ChannelState *s, int val)
+{
+    KBD_DPRINTF("Command %d\n", val);
+    if (s->led_mode) { // Ignore led byte
+        s->led_mode = 0;
+        return;
+    }
+    switch (val) {
+    case 1: // Reset, return type code
+        clear_queue(s);
+        put_queue(s, 0xff);
+        put_queue(s, 4); // Type 4
+        put_queue(s, 0x7f);
+        break;
+    case 0xe: // Set leds
+        s->led_mode = 1;
+        break;
+    case 7: // Query layout
+    case 0xf:
+        clear_queue(s);
+        put_queue(s, 0xfe);
+        put_queue(s, 0); // XXX, layout?
+        break;
+    default:
+        break;
+    }
+}
+
+static void sunmouse_event(void *opaque,
+                               int dx, int dy, int dz, int buttons_state)
+{
+    ChannelState *s = opaque;
+    int ch;
+
+    MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
+
+    ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+
+    if (buttons_state & MOUSE_EVENT_LBUTTON)
+        ch ^= 0x4;
+    if (buttons_state & MOUSE_EVENT_MBUTTON)
+        ch ^= 0x2;
+    if (buttons_state & MOUSE_EVENT_RBUTTON)
+        ch ^= 0x1;
+
+    put_queue(s, ch);
+
+    ch = dx;
+
+    if (ch > 127)
+        ch = 127;
+    else if (ch < -127)
+        ch = -127;
+
+    put_queue(s, ch & 0xff);
+
+    ch = -dy;
+
+    if (ch > 127)
+        ch = 127;
+    else if (ch < -127)
+        ch = -127;
+
+    put_queue(s, ch & 0xff);
+
+    // MSC protocol specify two extra motion bytes
+
+    put_queue(s, 0);
+    put_queue(s, 0);
+}
+
+void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
+                               int disabled, int clock, int it_shift)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "escc");
+    qdev_prop_set_uint32(dev, "disabled", disabled);
+    qdev_prop_set_uint32(dev, "frequency", clock);
+    qdev_prop_set_uint32(dev, "it_shift", it_shift);
+    qdev_prop_set_chr(dev, "chrB", NULL);
+    qdev_prop_set_chr(dev, "chrA", NULL);
+    qdev_prop_set_uint32(dev, "chnBtype", mouse);
+    qdev_prop_set_uint32(dev, "chnAtype", kbd);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_connect_irq(s, 1, irq);
+    sysbus_mmio_map(s, 0, base);
+}
+
+static int escc_init1(SysBusDevice *dev)
+{
+    SerialState *s = FROM_SYSBUS(SerialState, dev);
+    int io;
+    unsigned int i;
+
+    s->chn[0].disabled = s->disabled;
+    s->chn[1].disabled = s->disabled;
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(dev, &s->chn[i].irq);
+        s->chn[i].chn = 1 - i;
+        s->chn[i].clock = s->frequency / 2;
+        if (s->chn[i].chr) {
+            qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+                                  serial_receive1, serial_event, &s->chn[i]);
+        }
+    }
+    s->chn[0].otherchn = &s->chn[1];
+    s->chn[1].otherchn = &s->chn[0];
+
+    io = cpu_register_io_memory(escc_mem_read, escc_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, ESCC_SIZE << s->it_shift, io);
+    s->mmio_index = io;
+
+    if (s->chn[0].type == mouse) {
+        qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
+                                     "QEMU Sun Mouse");
+    }
+    if (s->chn[1].type == kbd) {
+        qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+    }
+
+    return 0;
+}
+
+static SysBusDeviceInfo escc_info = {
+    .init = escc_init1,
+    .qdev.name  = "escc",
+    .qdev.size  = sizeof(SerialState),
+    .qdev.vmsd  = &vmstate_escc,
+    .qdev.reset = escc_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", SerialState, frequency,   0),
+        DEFINE_PROP_UINT32("it_shift",  SerialState, it_shift,    0),
+        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
+        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
+        DEFINE_PROP_UINT32("chnBtype",  SerialState, chn[0].type, 0),
+        DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
+        DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+        DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void escc_register_devices(void)
+{
+    sysbus_register_withprop(&escc_info);
+}
+
+device_init(escc_register_devices)
diff --git a/qemu-0.15.x/hw/escc.h b/qemu-0.15.x/hw/escc.h
new file mode 100644
index 0000000..015b9d0
--- /dev/null
+++ b/qemu-0.15.x/hw/escc.h
@@ -0,0 +1,8 @@
+/* escc.c */
+#define ESCC_SIZE 4
+int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+              CharDriverState *chrA, CharDriverState *chrB,
+              int clock, int it_shift);
+
+void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
+                               int disabled, int clock, int it_shift);
diff --git a/qemu-0.15.x/hw/esp.c b/qemu-0.15.x/hw/esp.c
new file mode 100644
index 0000000..9ddd637
--- /dev/null
+++ b/qemu-0.15.x/hw/esp.c
@@ -0,0 +1,772 @@
+/*
+ * QEMU ESP/NCR53C9x emulation
+ *
+ * Copyright (c) 2005-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 "sysbus.h"
+#include "scsi.h"
+#include "esp.h"
+
+/* debug ESP card */
+//#define DEBUG_ESP
+
+/*
+ * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
+ * also produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
+ */
+
+#ifdef DEBUG_ESP
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("ESP: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define ESP_ERROR(fmt, ...)                                             \
+    do { printf("ESP ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+#define ESP_REGS 16
+#define TI_BUFSZ 16
+
+typedef struct ESPState ESPState;
+
+struct ESPState {
+    SysBusDevice busdev;
+    uint32_t it_shift;
+    qemu_irq irq;
+    uint8_t rregs[ESP_REGS];
+    uint8_t wregs[ESP_REGS];
+    int32_t ti_size;
+    uint32_t ti_rptr, ti_wptr;
+    uint8_t ti_buf[TI_BUFSZ];
+    uint32_t status;
+    uint32_t dma;
+    SCSIBus bus;
+    SCSIDevice *current_dev;
+    SCSIRequest *current_req;
+    uint8_t cmdbuf[TI_BUFSZ];
+    uint32_t cmdlen;
+    uint32_t do_cmd;
+
+    /* The amount of data left in the current DMA transfer.  */
+    uint32_t dma_left;
+    /* The size of the current DMA transfer.  Zero if no transfer is in
+       progress.  */
+    uint32_t dma_counter;
+    uint8_t *async_buf;
+    uint32_t async_len;
+
+    ESPDMAMemoryReadWriteFunc dma_memory_read;
+    ESPDMAMemoryReadWriteFunc dma_memory_write;
+    void *dma_opaque;
+    int dma_enabled;
+    void (*dma_cb)(ESPState *s);
+};
+
+#define ESP_TCLO   0x0
+#define ESP_TCMID  0x1
+#define ESP_FIFO   0x2
+#define ESP_CMD    0x3
+#define ESP_RSTAT  0x4
+#define ESP_WBUSID 0x4
+#define ESP_RINTR  0x5
+#define ESP_WSEL   0x5
+#define ESP_RSEQ   0x6
+#define ESP_WSYNTP 0x6
+#define ESP_RFLAGS 0x7
+#define ESP_WSYNO  0x7
+#define ESP_CFG1   0x8
+#define ESP_RRES1  0x9
+#define ESP_WCCF   0x9
+#define ESP_RRES2  0xa
+#define ESP_WTEST  0xa
+#define ESP_CFG2   0xb
+#define ESP_CFG3   0xc
+#define ESP_RES3   0xd
+#define ESP_TCHI   0xe
+#define ESP_RES4   0xf
+
+#define CMD_DMA 0x80
+#define CMD_CMD 0x7f
+
+#define CMD_NOP      0x00
+#define CMD_FLUSH    0x01
+#define CMD_RESET    0x02
+#define CMD_BUSRESET 0x03
+#define CMD_TI       0x10
+#define CMD_ICCS     0x11
+#define CMD_MSGACC   0x12
+#define CMD_PAD      0x18
+#define CMD_SATN     0x1a
+#define CMD_SEL      0x41
+#define CMD_SELATN   0x42
+#define CMD_SELATNS  0x43
+#define CMD_ENSEL    0x44
+
+#define STAT_DO 0x00
+#define STAT_DI 0x01
+#define STAT_CD 0x02
+#define STAT_ST 0x03
+#define STAT_MO 0x06
+#define STAT_MI 0x07
+#define STAT_PIO_MASK 0x06
+
+#define STAT_TC 0x10
+#define STAT_PE 0x20
+#define STAT_GE 0x40
+#define STAT_INT 0x80
+
+#define BUSID_DID 0x07
+
+#define INTR_FC 0x08
+#define INTR_BS 0x10
+#define INTR_DC 0x20
+#define INTR_RST 0x80
+
+#define SEQ_0 0x0
+#define SEQ_CD 0x4
+
+#define CFG1_RESREPT 0x40
+
+#define TCHI_FAS100A 0x4
+
+static void esp_raise_irq(ESPState *s)
+{
+    if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
+        s->rregs[ESP_RSTAT] |= STAT_INT;
+        qemu_irq_raise(s->irq);
+        DPRINTF("Raise IRQ\n");
+    }
+}
+
+static void esp_lower_irq(ESPState *s)
+{
+    if (s->rregs[ESP_RSTAT] & STAT_INT) {
+        s->rregs[ESP_RSTAT] &= ~STAT_INT;
+        qemu_irq_lower(s->irq);
+        DPRINTF("Lower IRQ\n");
+    }
+}
+
+static void esp_dma_enable(void *opaque, int irq, int level)
+{
+    DeviceState *d = opaque;
+    ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+    if (level) {
+        s->dma_enabled = 1;
+        DPRINTF("Raise enable\n");
+        if (s->dma_cb) {
+            s->dma_cb(s);
+            s->dma_cb = NULL;
+        }
+    } else {
+        DPRINTF("Lower enable\n");
+        s->dma_enabled = 0;
+    }
+}
+
+static void esp_request_cancelled(SCSIRequest *req)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    if (req == s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
+static uint32_t get_cmd(ESPState *s, uint8_t *buf)
+{
+    uint32_t dmalen;
+    int target;
+
+    target = s->wregs[ESP_WBUSID] & BUSID_DID;
+    if (s->dma) {
+        dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+        s->dma_memory_read(s->dma_opaque, buf, dmalen);
+    } else {
+        dmalen = s->ti_size;
+        memcpy(buf, s->ti_buf, dmalen);
+        buf[0] = buf[2] >> 5;
+    }
+    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
+
+    s->ti_size = 0;
+    s->ti_rptr = 0;
+    s->ti_wptr = 0;
+
+    if (s->current_req) {
+        /* Started a new command before the old one finished.  Cancel it.  */
+        scsi_req_cancel(s->current_req);
+        s->async_len = 0;
+    }
+
+    if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) {
+        // No such drive
+        s->rregs[ESP_RSTAT] = 0;
+        s->rregs[ESP_RINTR] = INTR_DC;
+        s->rregs[ESP_RSEQ] = SEQ_0;
+        esp_raise_irq(s);
+        return 0;
+    }
+    s->current_dev = s->bus.devs[target];
+    return dmalen;
+}
+
+static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
+{
+    int32_t datalen;
+    int lun;
+
+    DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
+    lun = busid & 7;
+    s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL);
+    datalen = scsi_req_enqueue(s->current_req, buf);
+    s->ti_size = datalen;
+    if (datalen != 0) {
+        s->rregs[ESP_RSTAT] = STAT_TC;
+        s->dma_left = 0;
+        s->dma_counter = 0;
+        if (datalen > 0) {
+            s->rregs[ESP_RSTAT] |= STAT_DI;
+        } else {
+            s->rregs[ESP_RSTAT] |= STAT_DO;
+        }
+        scsi_req_continue(s->current_req);
+    }
+    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+    s->rregs[ESP_RSEQ] = SEQ_CD;
+    esp_raise_irq(s);
+}
+
+static void do_cmd(ESPState *s, uint8_t *buf)
+{
+    uint8_t busid = buf[0];
+
+    do_busid_cmd(s, &buf[1], busid);
+}
+
+static void handle_satn(ESPState *s)
+{
+    uint8_t buf[32];
+    int len;
+
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_satn;
+        return;
+    }
+    len = get_cmd(s, buf);
+    if (len)
+        do_cmd(s, buf);
+}
+
+static void handle_s_without_atn(ESPState *s)
+{
+    uint8_t buf[32];
+    int len;
+
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_s_without_atn;
+        return;
+    }
+    len = get_cmd(s, buf);
+    if (len) {
+        do_busid_cmd(s, buf, 0);
+    }
+}
+
+static void handle_satn_stop(ESPState *s)
+{
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_satn_stop;
+        return;
+    }
+    s->cmdlen = get_cmd(s, s->cmdbuf);
+    if (s->cmdlen) {
+        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
+        s->do_cmd = 1;
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
+        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        esp_raise_irq(s);
+    }
+}
+
+static void write_response(ESPState *s)
+{
+    DPRINTF("Transfer status (status=%d)\n", s->status);
+    s->ti_buf[0] = s->status;
+    s->ti_buf[1] = 0;
+    if (s->dma) {
+        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
+        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+    } else {
+        s->ti_size = 2;
+        s->ti_rptr = 0;
+        s->ti_wptr = 0;
+        s->rregs[ESP_RFLAGS] = 2;
+    }
+    esp_raise_irq(s);
+}
+
+static void esp_dma_done(ESPState *s)
+{
+    s->rregs[ESP_RSTAT] |= STAT_TC;
+    s->rregs[ESP_RINTR] = INTR_BS;
+    s->rregs[ESP_RSEQ] = 0;
+    s->rregs[ESP_RFLAGS] = 0;
+    s->rregs[ESP_TCLO] = 0;
+    s->rregs[ESP_TCMID] = 0;
+    esp_raise_irq(s);
+}
+
+static void esp_do_dma(ESPState *s)
+{
+    uint32_t len;
+    int to_device;
+
+    to_device = (s->ti_size < 0);
+    len = s->dma_left;
+    if (s->do_cmd) {
+        DPRINTF("command len %d + %d\n", s->cmdlen, len);
+        s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
+        s->ti_size = 0;
+        s->cmdlen = 0;
+        s->do_cmd = 0;
+        do_cmd(s, s->cmdbuf);
+        return;
+    }
+    if (s->async_len == 0) {
+        /* Defer until data is available.  */
+        return;
+    }
+    if (len > s->async_len) {
+        len = s->async_len;
+    }
+    if (to_device) {
+        s->dma_memory_read(s->dma_opaque, s->async_buf, len);
+    } else {
+        s->dma_memory_write(s->dma_opaque, s->async_buf, len);
+    }
+    s->dma_left -= len;
+    s->async_buf += len;
+    s->async_len -= len;
+    if (to_device)
+        s->ti_size += len;
+    else
+        s->ti_size -= len;
+    if (s->async_len == 0) {
+        scsi_req_continue(s->current_req);
+        /* If there is still data to be read from the device then
+           complete the DMA operation immediately.  Otherwise defer
+           until the scsi layer has completed.  */
+        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
+            return;
+        }
+    }
+
+    /* Partially filled a scsi buffer. Complete immediately.  */
+    esp_dma_done(s);
+}
+
+static void esp_command_complete(SCSIRequest *req, uint32_t status)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    DPRINTF("SCSI Command complete\n");
+    if (s->ti_size != 0) {
+        DPRINTF("SCSI command completed unexpectedly\n");
+    }
+    s->ti_size = 0;
+    s->dma_left = 0;
+    s->async_len = 0;
+    if (status) {
+        DPRINTF("Command failed\n");
+    }
+    s->status = status;
+    s->rregs[ESP_RSTAT] = STAT_ST;
+    esp_dma_done(s);
+    if (s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
+static void esp_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
+    s->async_len = len;
+    s->async_buf = scsi_req_get_buf(req);
+    if (s->dma_left) {
+        esp_do_dma(s);
+    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
+        /* If this was the last part of a DMA transfer then the
+           completion interrupt is deferred to here.  */
+        esp_dma_done(s);
+    }
+}
+
+static void handle_ti(ESPState *s)
+{
+    uint32_t dmalen, minlen;
+
+    dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+    if (dmalen==0) {
+      dmalen=0x10000;
+    }
+    s->dma_counter = dmalen;
+
+    if (s->do_cmd)
+        minlen = (dmalen < 32) ? dmalen : 32;
+    else if (s->ti_size < 0)
+        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
+    else
+        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+    DPRINTF("Transfer Information len %d\n", minlen);
+    if (s->dma) {
+        s->dma_left = minlen;
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        esp_do_dma(s);
+    } else if (s->do_cmd) {
+        DPRINTF("command len %d\n", s->cmdlen);
+        s->ti_size = 0;
+        s->cmdlen = 0;
+        s->do_cmd = 0;
+        do_cmd(s, s->cmdbuf);
+        return;
+    }
+}
+
+static void esp_hard_reset(DeviceState *d)
+{
+    ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+    memset(s->rregs, 0, ESP_REGS);
+    memset(s->wregs, 0, ESP_REGS);
+    s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
+    s->ti_size = 0;
+    s->ti_rptr = 0;
+    s->ti_wptr = 0;
+    s->dma = 0;
+    s->do_cmd = 0;
+    s->dma_cb = NULL;
+
+    s->rregs[ESP_CFG1] = 7;
+}
+
+static void esp_soft_reset(DeviceState *d)
+{
+    ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+    qemu_irq_lower(s->irq);
+    esp_hard_reset(d);
+}
+
+static void parent_esp_reset(void *opaque, int irq, int level)
+{
+    if (level) {
+        esp_soft_reset(opaque);
+    }
+}
+
+static void esp_gpio_demux(void *opaque, int irq, int level)
+{
+    switch (irq) {
+    case 0:
+        parent_esp_reset(opaque, irq, level);
+        break;
+    case 1:
+        esp_dma_enable(opaque, irq, level);
+        break;
+    }
+}
+
+static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    ESPState *s = opaque;
+    uint32_t saddr, old_val;
+
+    saddr = addr >> s->it_shift;
+    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
+    switch (saddr) {
+    case ESP_FIFO:
+        if (s->ti_size > 0) {
+            s->ti_size--;
+            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
+                /* Data out.  */
+                ESP_ERROR("PIO data read not implemented\n");
+                s->rregs[ESP_FIFO] = 0;
+            } else {
+                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
+            }
+            esp_raise_irq(s);
+        }
+        if (s->ti_size == 0) {
+            s->ti_rptr = 0;
+            s->ti_wptr = 0;
+        }
+        break;
+    case ESP_RINTR:
+        /* Clear sequence step, interrupt register and all status bits
+           except TC */
+        old_val = s->rregs[ESP_RINTR];
+        s->rregs[ESP_RINTR] = 0;
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        esp_lower_irq(s);
+
+        return old_val;
+    default:
+        break;
+    }
+    return s->rregs[saddr];
+}
+
+static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    ESPState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> s->it_shift;
+    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr],
+            val);
+    switch (saddr) {
+    case ESP_TCLO:
+    case ESP_TCMID:
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        break;
+    case ESP_FIFO:
+        if (s->do_cmd) {
+            s->cmdbuf[s->cmdlen++] = val & 0xff;
+        } else if (s->ti_size == TI_BUFSZ - 1) {
+            ESP_ERROR("fifo overrun\n");
+        } else {
+            s->ti_size++;
+            s->ti_buf[s->ti_wptr++] = val & 0xff;
+        }
+        break;
+    case ESP_CMD:
+        s->rregs[saddr] = val;
+        if (val & CMD_DMA) {
+            s->dma = 1;
+            /* Reload DMA counter.  */
+            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
+            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
+        } else {
+            s->dma = 0;
+        }
+        switch(val & CMD_CMD) {
+        case CMD_NOP:
+            DPRINTF("NOP (%2.2x)\n", val);
+            break;
+        case CMD_FLUSH:
+            DPRINTF("Flush FIFO (%2.2x)\n", val);
+            //s->ti_size = 0;
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSEQ] = 0;
+            s->rregs[ESP_RFLAGS] = 0;
+            break;
+        case CMD_RESET:
+            DPRINTF("Chip reset (%2.2x)\n", val);
+            esp_soft_reset(&s->busdev.qdev);
+            break;
+        case CMD_BUSRESET:
+            DPRINTF("Bus reset (%2.2x)\n", val);
+            s->rregs[ESP_RINTR] = INTR_RST;
+            if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
+                esp_raise_irq(s);
+            }
+            break;
+        case CMD_TI:
+            handle_ti(s);
+            break;
+        case CMD_ICCS:
+            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
+            write_response(s);
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSTAT] |= STAT_MI;
+            break;
+        case CMD_MSGACC:
+            DPRINTF("Message Accepted (%2.2x)\n", val);
+            s->rregs[ESP_RINTR] = INTR_DC;
+            s->rregs[ESP_RSEQ] = 0;
+            s->rregs[ESP_RFLAGS] = 0;
+            esp_raise_irq(s);
+            break;
+        case CMD_PAD:
+            DPRINTF("Transfer padding (%2.2x)\n", val);
+            s->rregs[ESP_RSTAT] = STAT_TC;
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSEQ] = 0;
+            break;
+        case CMD_SATN:
+            DPRINTF("Set ATN (%2.2x)\n", val);
+            break;
+        case CMD_SEL:
+            DPRINTF("Select without ATN (%2.2x)\n", val);
+            handle_s_without_atn(s);
+            break;
+        case CMD_SELATN:
+            DPRINTF("Select with ATN (%2.2x)\n", val);
+            handle_satn(s);
+            break;
+        case CMD_SELATNS:
+            DPRINTF("Select with ATN & stop (%2.2x)\n", val);
+            handle_satn_stop(s);
+            break;
+        case CMD_ENSEL:
+            DPRINTF("Enable selection (%2.2x)\n", val);
+            s->rregs[ESP_RINTR] = 0;
+            break;
+        default:
+            ESP_ERROR("Unhandled ESP command (%2.2x)\n", val);
+            break;
+        }
+        break;
+    case ESP_WBUSID ... ESP_WSYNO:
+        break;
+    case ESP_CFG1:
+        s->rregs[saddr] = val;
+        break;
+    case ESP_WCCF ... ESP_WTEST:
+        break;
+    case ESP_CFG2 ... ESP_RES4:
+        s->rregs[saddr] = val;
+        break;
+    default:
+        ESP_ERROR("invalid write of 0x%02x at [0x%x]\n", val, saddr);
+        return;
+    }
+    s->wregs[saddr] = val;
+}
+
+static CPUReadMemoryFunc * const esp_mem_read[3] = {
+    esp_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const esp_mem_write[3] = {
+    esp_mem_writeb,
+    NULL,
+    esp_mem_writeb,
+};
+
+static const VMStateDescription vmstate_esp = {
+    .name ="esp",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_BUFFER(rregs, ESPState),
+        VMSTATE_BUFFER(wregs, ESPState),
+        VMSTATE_INT32(ti_size, ESPState),
+        VMSTATE_UINT32(ti_rptr, ESPState),
+        VMSTATE_UINT32(ti_wptr, ESPState),
+        VMSTATE_BUFFER(ti_buf, ESPState),
+        VMSTATE_UINT32(status, ESPState),
+        VMSTATE_UINT32(dma, ESPState),
+        VMSTATE_BUFFER(cmdbuf, ESPState),
+        VMSTATE_UINT32(cmdlen, ESPState),
+        VMSTATE_UINT32(do_cmd, ESPState),
+        VMSTATE_UINT32(dma_left, ESPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void esp_init(target_phys_addr_t espaddr, int it_shift,
+              ESPDMAMemoryReadWriteFunc dma_memory_read,
+              ESPDMAMemoryReadWriteFunc dma_memory_write,
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    ESPState *esp;
+
+    dev = qdev_create(NULL, "esp");
+    esp = DO_UPCAST(ESPState, busdev.qdev, dev);
+    esp->dma_memory_read = dma_memory_read;
+    esp->dma_memory_write = dma_memory_write;
+    esp->dma_opaque = dma_opaque;
+    esp->it_shift = it_shift;
+    /* XXX for now until rc4030 has been changed to use DMA enable signal */
+    esp->dma_enabled = 1;
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, espaddr);
+    *reset = qdev_get_gpio_in(dev, 0);
+    *dma_enable = qdev_get_gpio_in(dev, 1);
+}
+
+static const struct SCSIBusOps esp_scsi_ops = {
+    .transfer_data = esp_transfer_data,
+    .complete = esp_command_complete,
+    .cancel = esp_request_cancelled
+};
+
+static int esp_init1(SysBusDevice *dev)
+{
+    ESPState *s = FROM_SYSBUS(ESPState, dev);
+    int esp_io_memory;
+
+    sysbus_init_irq(dev, &s->irq);
+    assert(s->it_shift != -1);
+
+    esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
+
+    qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
+
+    scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops);
+    return scsi_bus_legacy_handle_cmdline(&s->bus);
+}
+
+static SysBusDeviceInfo esp_info = {
+    .init = esp_init1,
+    .qdev.name  = "esp",
+    .qdev.size  = sizeof(ESPState),
+    .qdev.vmsd  = &vmstate_esp,
+    .qdev.reset = esp_hard_reset,
+    .qdev.props = (Property[]) {
+        {.name = NULL}
+    }
+};
+
+static void esp_register_devices(void)
+{
+    sysbus_register_withprop(&esp_info);
+}
+
+device_init(esp_register_devices)
diff --git a/qemu-0.15.x/hw/esp.h b/qemu-0.15.x/hw/esp.h
new file mode 100644
index 0000000..62bfd4d
--- /dev/null
+++ b/qemu-0.15.x/hw/esp.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_ESP_H
+#define QEMU_HW_ESP_H
+
+/* esp.c */
+#define ESP_MAX_DEVS 7
+typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
+void esp_init(target_phys_addr_t espaddr, int it_shift,
+              ESPDMAMemoryReadWriteFunc dma_memory_read,
+              ESPDMAMemoryReadWriteFunc dma_memory_write,
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable);
+
+#endif
diff --git a/qemu-0.15.x/hw/etraxfs.c b/qemu-0.15.x/hw/etraxfs.c
new file mode 100644
index 0000000..b84d74a
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs.c
@@ -0,0 +1,159 @@
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "sysbus.h"
+#include "boards.h"
+#include "net.h"
+#include "flash.h"
+#include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
+#include "cris-boot.h"
+#include "blockdev.h"
+
+#define FLASH_SIZE 0x2000000
+#define INTMEM_SIZE (128 * 1024)
+
+static struct cris_load_info li;
+
+static void flash_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
+static
+void bareetraxfs_init (ram_addr_t ram_size,
+                       const char *boot_device,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    CPUState *env;
+    qemu_irq irq[30], nmi[2], *cpu_irq; 
+    void *etraxfs_dmac;
+    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
+    DriveInfo *dinfo;
+    int i;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    ram_addr_t phys_intmem;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "crisv32";
+    }
+    env = cpu_init(cpu_model);
+
+    /* allocate RAM */
+    phys_ram = qemu_ram_alloc(NULL, "etraxfs.ram", ram_size);
+    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
+
+    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
+       internal memory.  */
+    phys_intmem = qemu_ram_alloc(NULL, "etraxfs.chipram", INTMEM_SIZE);
+    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
+                                 phys_intmem | IO_MEM_RAM);
+
+
+    phys_flash = qemu_ram_alloc(NULL, "etraxfs.flash", FLASH_SIZE);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi02_register(0x0, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 2, 0x0000, 0x0000, 0x0000, 0x0000,
+                          0x555, 0x2aa, 0);
+    cpu_irq = cris_pic_init_cpu(env);
+    dev = qdev_create(NULL, "etraxfs,pic");
+    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
+    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, 0x3001c000);
+    sysbus_connect_irq(s, 0, cpu_irq[0]);
+    sysbus_connect_irq(s, 1, cpu_irq[1]);
+    for (i = 0; i < 30; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+    nmi[0] = qdev_get_gpio_in(dev, 30);
+    nmi[1] = qdev_get_gpio_in(dev, 31);
+
+    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
+    for (i = 0; i < 10; i++) {
+        /* On ETRAX, odd numbered channels are inputs.  */
+        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
+    }
+
+    /* Add the two ethernet blocks.  */
+    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
+    if (nb_nics > 1)
+        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
+
+    /* The DMA Connector block is missing, hardwire things for now.  */
+    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
+    if (eth[1]) {
+        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
+        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+    }
+
+    /* 2 timers.  */
+    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
+    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
+
+    for (i = 0; i < 4; i++) {
+        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
+                             irq[0x14 + i]); 
+    }
+
+    if (kernel_filename) {
+        li.image_filename = kernel_filename;
+        li.cmdline = kernel_cmdline;
+        cris_load_image(env, &li);
+    } else {
+        if (!dinfo) {
+            fprintf(stderr,
+                    "Provide a kernel image or a flash image to boot from.\n");
+           exit(1);
+        }
+
+        /* Nothing more to do for flash images, those boot from addr 0.  */
+        qemu_register_reset(flash_cpu_reset, env);
+    }
+}
+
+static QEMUMachine bareetraxfs_machine = {
+    .name = "bareetraxfs",
+    .desc = "Bare ETRAX FS board",
+    .init = bareetraxfs_init,
+    .is_default = 1,
+};
+
+static void bareetraxfs_machine_init(void)
+{
+    qemu_register_machine(&bareetraxfs_machine);
+}
+
+machine_init(bareetraxfs_machine_init);
diff --git a/qemu-0.15.x/hw/etraxfs.h b/qemu-0.15.x/hw/etraxfs.h
new file mode 100644
index 0000000..01fb9d3
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs.h
@@ -0,0 +1,28 @@
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "etraxfs_dma.h"
+
+qemu_irq *cris_pic_init_cpu(CPUState *env);
+void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr);
diff --git a/qemu-0.15.x/hw/etraxfs_dma.c b/qemu-0.15.x/hw/etraxfs_dma.c
new file mode 100644
index 0000000..c205ec1
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_dma.c
@@ -0,0 +1,756 @@
+/*
+ * QEMU ETRAX DMA Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include <sys/time.h>
+#include "hw.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+
+#include "etraxfs_dma.h"
+
+#define D(x)
+
+#define RW_DATA           (0x0 / 4)
+#define RW_SAVED_DATA     (0x58 / 4)
+#define RW_SAVED_DATA_BUF (0x5c / 4)
+#define RW_GROUP          (0x60 / 4)
+#define RW_GROUP_DOWN     (0x7c / 4)
+#define RW_CMD            (0x80 / 4)
+#define RW_CFG            (0x84 / 4)
+#define RW_STAT           (0x88 / 4)
+#define RW_INTR_MASK      (0x8c / 4)
+#define RW_ACK_INTR       (0x90 / 4)
+#define R_INTR            (0x94 / 4)
+#define R_MASKED_INTR     (0x98 / 4)
+#define RW_STREAM_CMD     (0x9c / 4)
+
+#define DMA_REG_MAX       (0x100 / 4)
+
+/* descriptors */
+
+// ------------------------------------------------------------ dma_descr_group
+typedef struct dma_descr_group {
+  uint32_t                      next;
+  unsigned                      eol        : 1;
+  unsigned                      tol        : 1;
+  unsigned                      bol        : 1;
+  unsigned                                 : 1;
+  unsigned                      intr       : 1;
+  unsigned                                 : 2;
+  unsigned                      en         : 1;
+  unsigned                                 : 7;
+  unsigned                      dis        : 1;
+  unsigned                      md         : 16;
+  struct dma_descr_group       *up;
+  union {
+    struct dma_descr_context   *context;
+    struct dma_descr_group     *group;
+  }                             down;
+} dma_descr_group;
+
+// ---------------------------------------------------------- dma_descr_context
+typedef struct dma_descr_context {
+  uint32_t                      next;
+  unsigned                      eol        : 1;
+  unsigned                                 : 3;
+  unsigned                      intr       : 1;
+  unsigned                                 : 1;
+  unsigned                      store_mode : 1;
+  unsigned                      en         : 1;
+  unsigned                                 : 7;
+  unsigned                      dis        : 1;
+  unsigned                      md0        : 16;
+  unsigned                      md1;
+  unsigned                      md2;
+  unsigned                      md3;
+  unsigned                      md4;
+  uint32_t                      saved_data;
+  uint32_t                      saved_data_buf;
+} dma_descr_context;
+
+// ------------------------------------------------------------- dma_descr_data
+typedef struct dma_descr_data {
+  uint32_t                      next;
+  uint32_t                      buf;
+  unsigned                      eol        : 1;
+  unsigned                                 : 2;
+  unsigned                      out_eop    : 1;
+  unsigned                      intr       : 1;
+  unsigned                      wait       : 1;
+  unsigned                                 : 2;
+  unsigned                                 : 3;
+  unsigned                      in_eop     : 1;
+  unsigned                                 : 4;
+  unsigned                      md         : 16;
+  uint32_t                      after;
+} dma_descr_data;
+
+/* Constants */
+enum {
+  regk_dma_ack_pkt                         = 0x00000100,
+  regk_dma_anytime                         = 0x00000001,
+  regk_dma_array                           = 0x00000008,
+  regk_dma_burst                           = 0x00000020,
+  regk_dma_client                          = 0x00000002,
+  regk_dma_copy_next                       = 0x00000010,
+  regk_dma_copy_up                         = 0x00000020,
+  regk_dma_data_at_eol                     = 0x00000001,
+  regk_dma_dis_c                           = 0x00000010,
+  regk_dma_dis_g                           = 0x00000020,
+  regk_dma_idle                            = 0x00000001,
+  regk_dma_intern                          = 0x00000004,
+  regk_dma_load_c                          = 0x00000200,
+  regk_dma_load_c_n                        = 0x00000280,
+  regk_dma_load_c_next                     = 0x00000240,
+  regk_dma_load_d                          = 0x00000140,
+  regk_dma_load_g                          = 0x00000300,
+  regk_dma_load_g_down                     = 0x000003c0,
+  regk_dma_load_g_next                     = 0x00000340,
+  regk_dma_load_g_up                       = 0x00000380,
+  regk_dma_next_en                         = 0x00000010,
+  regk_dma_next_pkt                        = 0x00000010,
+  regk_dma_no                              = 0x00000000,
+  regk_dma_only_at_wait                    = 0x00000000,
+  regk_dma_restore                         = 0x00000020,
+  regk_dma_rst                             = 0x00000001,
+  regk_dma_running                         = 0x00000004,
+  regk_dma_rw_cfg_default                  = 0x00000000,
+  regk_dma_rw_cmd_default                  = 0x00000000,
+  regk_dma_rw_intr_mask_default            = 0x00000000,
+  regk_dma_rw_stat_default                 = 0x00000101,
+  regk_dma_rw_stream_cmd_default           = 0x00000000,
+  regk_dma_save_down                       = 0x00000020,
+  regk_dma_save_up                         = 0x00000020,
+  regk_dma_set_reg                         = 0x00000050,
+  regk_dma_set_w_size1                     = 0x00000190,
+  regk_dma_set_w_size2                     = 0x000001a0,
+  regk_dma_set_w_size4                     = 0x000001c0,
+  regk_dma_stopped                         = 0x00000002,
+  regk_dma_store_c                         = 0x00000002,
+  regk_dma_store_descr                     = 0x00000000,
+  regk_dma_store_g                         = 0x00000004,
+  regk_dma_store_md                        = 0x00000001,
+  regk_dma_sw                              = 0x00000008,
+  regk_dma_update_down                     = 0x00000020,
+  regk_dma_yes                             = 0x00000001
+};
+
+enum dma_ch_state
+{
+	RST = 1,
+	STOPPED = 2,
+	RUNNING = 4
+};
+
+struct fs_dma_channel
+{
+	qemu_irq irq;
+	struct etraxfs_dma_client *client;
+
+	/* Internal status.  */
+	int stream_cmd_src;
+	enum dma_ch_state state;
+
+	unsigned int input : 1;
+	unsigned int eol : 1;
+
+	struct dma_descr_group current_g;
+	struct dma_descr_context current_c;
+	struct dma_descr_data current_d;
+
+	/* Controll registers.  */
+	uint32_t regs[DMA_REG_MAX];
+};
+
+struct fs_dma_ctrl
+{
+	int map;
+	int nr_channels;
+	struct fs_dma_channel *channels;
+
+        QEMUBH *bh;
+};
+
+static void DMA_run(void *opaque);
+static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
+
+static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
+{
+	return ctrl->channels[c].regs[reg];
+}
+
+static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
+{
+	return channel_reg(ctrl, c, RW_CFG) & 2;
+}
+
+static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
+{
+	return (channel_reg(ctrl, c, RW_CFG) & 1)
+		&& ctrl->channels[c].client;
+}
+
+static inline int fs_channel(target_phys_addr_t addr)
+{
+	/* Every channel has a 0x2000 ctrl register map.  */
+	return addr >> 13;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
+{
+	target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP);
+
+	/* Load and decode. FIXME: handle endianness.  */
+	cpu_physical_memory_read (addr, 
+				  (void *) &ctrl->channels[c].current_g, 
+				  sizeof ctrl->channels[c].current_g);
+}
+
+static void dump_c(int ch, struct dma_descr_context *c)
+{
+	printf("%s ch=%d\n", __func__, ch);
+	printf("next=%x\n", c->next);
+	printf("saved_data=%x\n", c->saved_data);
+	printf("saved_data_buf=%x\n", c->saved_data_buf);
+	printf("eol=%x\n", (uint32_t) c->eol);
+}
+
+static void dump_d(int ch, struct dma_descr_data *d)
+{
+	printf("%s ch=%d\n", __func__, ch);
+	printf("next=%x\n", d->next);
+	printf("buf=%x\n", d->buf);
+	printf("after=%x\n", d->after);
+	printf("intr=%x\n", (uint32_t) d->intr);
+	printf("out_eop=%x\n", (uint32_t) d->out_eop);
+	printf("in_eop=%x\n", (uint32_t) d->in_eop);
+	printf("eol=%x\n", (uint32_t) d->eol);
+}
+#endif
+
+static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
+{
+	target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
+
+	/* Load and decode. FIXME: handle endianness.  */
+	cpu_physical_memory_read (addr, 
+				  (void *) &ctrl->channels[c].current_c, 
+				  sizeof ctrl->channels[c].current_c);
+
+	D(dump_c(c, &ctrl->channels[c].current_c));
+	/* I guess this should update the current pos.  */
+	ctrl->channels[c].regs[RW_SAVED_DATA] =
+		(uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
+	ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+		(uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
+}
+
+static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
+{
+	target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA);
+
+	/* Load and decode. FIXME: handle endianness.  */
+	D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+	cpu_physical_memory_read (addr,
+				  (void *) &ctrl->channels[c].current_d, 
+				  sizeof ctrl->channels[c].current_d);
+
+	D(dump_d(c, &ctrl->channels[c].current_d));
+	ctrl->channels[c].regs[RW_DATA] = addr;
+}
+
+static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
+{
+	target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
+
+	/* Encode and store. FIXME: handle endianness.  */
+	D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+	D(dump_d(c, &ctrl->channels[c].current_d));
+	cpu_physical_memory_write (addr,
+				  (void *) &ctrl->channels[c].current_c,
+				  sizeof ctrl->channels[c].current_c);
+}
+
+static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
+{
+	target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA);
+
+	/* Encode and store. FIXME: handle endianness.  */
+	D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+	cpu_physical_memory_write (addr,
+				  (void *) &ctrl->channels[c].current_d, 
+				  sizeof ctrl->channels[c].current_d);
+}
+
+static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
+{
+	/* FIXME:  */
+}
+
+static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
+{
+	if (ctrl->channels[c].client)
+	{
+		ctrl->channels[c].eol = 0;
+		ctrl->channels[c].state = RUNNING;
+		if (!ctrl->channels[c].input)
+			channel_out_run(ctrl, c);
+	} else
+		printf("WARNING: starting DMA ch %d with no client\n", c);
+
+        qemu_bh_schedule_idle(ctrl->bh);
+}
+
+static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
+{
+	if (!channel_en(ctrl, c) 
+	    || channel_stopped(ctrl, c)
+	    || ctrl->channels[c].state != RUNNING
+	    /* Only reload the current data descriptor if it has eol set.  */
+	    || !ctrl->channels[c].current_d.eol) {
+		D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", 
+			 c, ctrl->channels[c].state,
+			 channel_stopped(ctrl, c),
+			 channel_en(ctrl,c),
+			 ctrl->channels[c].eol));
+		D(dump_d(c, &ctrl->channels[c].current_d));
+		return;
+	}
+
+	/* Reload the current descriptor.  */
+	channel_load_d(ctrl, c);
+
+	/* If the current descriptor cleared the eol flag and we had already
+	   reached eol state, do the continue.  */
+	if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
+		D(printf("continue %d ok %x\n", c,
+			 ctrl->channels[c].current_d.next));
+		ctrl->channels[c].regs[RW_SAVED_DATA] =
+			(uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
+		channel_load_d(ctrl, c);
+		ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+			(uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
+
+		channel_start(ctrl, c);
+	}
+	ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+		(uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
+}
+
+static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
+{
+	unsigned int cmd = v & ((1 << 10) - 1);
+
+	D(printf("%s ch=%d cmd=%x\n",
+		 __func__, c, cmd));
+	if (cmd & regk_dma_load_d) {
+		channel_load_d(ctrl, c);
+		if (cmd & regk_dma_burst)
+			channel_start(ctrl, c);
+	}
+
+	if (cmd & regk_dma_load_c) {
+		channel_load_c(ctrl, c);
+	}
+}
+
+static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
+{
+	D(printf("%s %d\n", __func__, c));
+        ctrl->channels[c].regs[R_INTR] &=
+		~(ctrl->channels[c].regs[RW_ACK_INTR]);
+
+        ctrl->channels[c].regs[R_MASKED_INTR] =
+		ctrl->channels[c].regs[R_INTR]
+		& ctrl->channels[c].regs[RW_INTR_MASK];
+
+	D(printf("%s: chan=%d masked_intr=%x\n", __func__, 
+		 c,
+		 ctrl->channels[c].regs[R_MASKED_INTR]));
+
+        qemu_set_irq(ctrl->channels[c].irq,
+		     !!ctrl->channels[c].regs[R_MASKED_INTR]);
+}
+
+static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
+{
+	uint32_t len;
+	uint32_t saved_data_buf;
+	unsigned char buf[2 * 1024];
+
+	if (ctrl->channels[c].eol)
+		return 0;
+
+	do {
+		D(printf("ch=%d buf=%x after=%x\n",
+			 c,
+			 (uint32_t)ctrl->channels[c].current_d.buf,
+			 (uint32_t)ctrl->channels[c].current_d.after));
+
+		channel_load_d(ctrl, c);
+		saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
+		len = (uint32_t)(unsigned long)
+			ctrl->channels[c].current_d.after;
+		len -= saved_data_buf;
+
+		if (len > sizeof buf)
+			len = sizeof buf;
+		cpu_physical_memory_read (saved_data_buf, buf, len);
+
+		D(printf("channel %d pushes %x %u bytes\n", c, 
+			 saved_data_buf, len));
+
+		if (ctrl->channels[c].client->client.push)
+			ctrl->channels[c].client->client.push(
+				ctrl->channels[c].client->client.opaque,
+				buf, len);
+		else
+			printf("WARNING: DMA ch%d dataloss,"
+			       " no attached client.\n", c);
+
+		saved_data_buf += len;
+
+		if (saved_data_buf == (uint32_t)(unsigned long)
+				ctrl->channels[c].current_d.after) {
+			/* Done. Step to next.  */
+			if (ctrl->channels[c].current_d.out_eop) {
+				/* TODO: signal eop to the client.  */
+				D(printf("signal eop\n"));
+			}
+			if (ctrl->channels[c].current_d.intr) {
+				/* TODO: signal eop to the client.  */
+				/* data intr.  */
+				D(printf("signal intr %d eol=%d\n",
+					len, ctrl->channels[c].current_d.eol));
+				ctrl->channels[c].regs[R_INTR] |= (1 << 2);
+				channel_update_irq(ctrl, c);
+			}
+			channel_store_d(ctrl, c);
+			if (ctrl->channels[c].current_d.eol) {
+				D(printf("channel %d EOL\n", c));
+				ctrl->channels[c].eol = 1;
+
+				/* Mark the context as disabled.  */
+				ctrl->channels[c].current_c.dis = 1;
+				channel_store_c(ctrl, c);
+
+				channel_stop(ctrl, c);
+			} else {
+				ctrl->channels[c].regs[RW_SAVED_DATA] =
+					(uint32_t)(unsigned long)ctrl->
+						channels[c].current_d.next;
+				/* Load new descriptor.  */
+				channel_load_d(ctrl, c);
+				saved_data_buf = (uint32_t)(unsigned long)
+					ctrl->channels[c].current_d.buf;
+			}
+
+			ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+							saved_data_buf;
+			D(dump_d(c, &ctrl->channels[c].current_d));
+		}
+		ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
+	} while (!ctrl->channels[c].eol);
+	return 1;
+}
+
+static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, 
+			      unsigned char *buf, int buflen, int eop)
+{
+	uint32_t len;
+	uint32_t saved_data_buf;
+
+	if (ctrl->channels[c].eol == 1)
+		return 0;
+
+	channel_load_d(ctrl, c);
+	saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
+	len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
+	len -= saved_data_buf;
+	
+	if (len > buflen)
+		len = buflen;
+
+	cpu_physical_memory_write (saved_data_buf, buf, len);
+	saved_data_buf += len;
+
+	if (saved_data_buf ==
+	    (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
+	    || eop) {
+		uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
+
+		D(printf("in dscr end len=%d\n", 
+			 ctrl->channels[c].current_d.after
+			 - ctrl->channels[c].current_d.buf));
+		ctrl->channels[c].current_d.after = saved_data_buf;
+
+		/* Done. Step to next.  */
+		if (ctrl->channels[c].current_d.intr) {
+			/* TODO: signal eop to the client.  */
+			/* data intr.  */
+			ctrl->channels[c].regs[R_INTR] |= 3;
+		}
+		if (eop) {
+			ctrl->channels[c].current_d.in_eop = 1;
+			ctrl->channels[c].regs[R_INTR] |= 8;
+		}
+		if (r_intr != ctrl->channels[c].regs[R_INTR])
+			channel_update_irq(ctrl, c);
+
+		channel_store_d(ctrl, c);
+		D(dump_d(c, &ctrl->channels[c].current_d));
+
+		if (ctrl->channels[c].current_d.eol) {
+			D(printf("channel %d EOL\n", c));
+			ctrl->channels[c].eol = 1;
+
+			/* Mark the context as disabled.  */
+			ctrl->channels[c].current_c.dis = 1;
+			channel_store_c(ctrl, c);
+
+			channel_stop(ctrl, c);
+		} else {
+			ctrl->channels[c].regs[RW_SAVED_DATA] =
+				(uint32_t)(unsigned long)ctrl->
+					channels[c].current_d.next;
+			/* Load new descriptor.  */
+			channel_load_d(ctrl, c);
+			saved_data_buf = (uint32_t)(unsigned long)
+				ctrl->channels[c].current_d.buf;
+		}
+	}
+
+	ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
+	return len;
+}
+
+static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
+{
+	if (ctrl->channels[c].client->client.pull) {
+		ctrl->channels[c].client->client.pull(
+			ctrl->channels[c].client->client.opaque);
+		return 1;
+	} else
+		return 0;
+}
+
+static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr)
+{
+        hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr);
+        return 0;
+}
+
+static uint32_t
+dma_readl (void *opaque, target_phys_addr_t addr)
+{
+        struct fs_dma_ctrl *ctrl = opaque;
+	int c;
+	uint32_t r = 0;
+
+	/* Make addr relative to this channel and bounded to nr regs.  */
+	c = fs_channel(addr);
+	addr &= 0xff;
+	addr >>= 2;
+	switch (addr)
+	{
+		case RW_STAT:
+			r = ctrl->channels[c].state & 7;
+			r |= ctrl->channels[c].eol << 5;
+			r |= ctrl->channels[c].stream_cmd_src << 8;
+			break;
+
+		default:
+			r = ctrl->channels[c].regs[addr];
+			D(printf ("%s c=%d addr=" TARGET_FMT_plx "\n",
+				  __func__, c, addr));
+			break;
+	}
+	return r;
+}
+
+static void
+dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+        hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr);
+}
+
+static void
+dma_update_state(struct fs_dma_ctrl *ctrl, int c)
+{
+	if ((ctrl->channels[c].regs[RW_CFG] & 1) != 3) {
+		if (ctrl->channels[c].regs[RW_CFG] & 2)
+			ctrl->channels[c].state = STOPPED;
+		if (!(ctrl->channels[c].regs[RW_CFG] & 1))
+			ctrl->channels[c].state = RST;
+	}
+}
+
+static void
+dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+        struct fs_dma_ctrl *ctrl = opaque;
+	int c;
+
+        /* Make addr relative to this channel and bounded to nr regs.  */
+	c = fs_channel(addr);
+        addr &= 0xff;
+        addr >>= 2;
+        switch (addr)
+	{
+		case RW_DATA:
+			ctrl->channels[c].regs[addr] = value;
+			break;
+
+		case RW_CFG:
+			ctrl->channels[c].regs[addr] = value;
+			dma_update_state(ctrl, c);
+			break;
+		case RW_CMD:
+			/* continue.  */
+			if (value & ~1)
+				printf("Invalid store to ch=%d RW_CMD %x\n",
+				       c, value);
+			ctrl->channels[c].regs[addr] = value;
+			channel_continue(ctrl, c);
+			break;
+
+		case RW_SAVED_DATA:
+		case RW_SAVED_DATA_BUF:
+		case RW_GROUP:
+		case RW_GROUP_DOWN:
+			ctrl->channels[c].regs[addr] = value;
+			break;
+
+		case RW_ACK_INTR:
+		case RW_INTR_MASK:
+			ctrl->channels[c].regs[addr] = value;
+			channel_update_irq(ctrl, c);
+			if (addr == RW_ACK_INTR)
+				ctrl->channels[c].regs[RW_ACK_INTR] = 0;
+			break;
+
+		case RW_STREAM_CMD:
+			if (value & ~1023)
+				printf("Invalid store to ch=%d "
+				       "RW_STREAMCMD %x\n",
+				       c, value);
+			ctrl->channels[c].regs[addr] = value;
+			D(printf("stream_cmd ch=%d\n", c));
+			channel_stream_cmd(ctrl, c, value);
+			break;
+
+	        default:
+			D(printf ("%s c=%d " TARGET_FMT_plx "\n",
+				__func__, c, addr));
+			break;
+        }
+}
+
+static CPUReadMemoryFunc * const dma_read[] = {
+	&dma_rinvalid,
+	&dma_rinvalid,
+	&dma_readl,
+};
+
+static CPUWriteMemoryFunc * const dma_write[] = {
+	&dma_winvalid,
+	&dma_winvalid,
+	&dma_writel,
+};
+
+static int etraxfs_dmac_run(void *opaque)
+{
+	struct fs_dma_ctrl *ctrl = opaque;
+	int i;
+	int p = 0;
+
+	for (i = 0; 
+	     i < ctrl->nr_channels;
+	     i++)
+	{
+		if (ctrl->channels[i].state == RUNNING)
+		{
+			if (ctrl->channels[i].input) {
+				p += channel_in_run(ctrl, i);
+			} else {
+				p += channel_out_run(ctrl, i);
+			}
+		}
+	}
+	return p;
+}
+
+int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
+		       void *buf, int len, int eop)
+{
+	return channel_in_process(client->ctrl, client->channel, 
+				  buf, len, eop);
+}
+
+/* Connect an IRQ line with a channel.  */
+void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
+{
+	struct fs_dma_ctrl *ctrl = opaque;
+	ctrl->channels[c].irq = *line;
+	ctrl->channels[c].input = input;
+}
+
+void etraxfs_dmac_connect_client(void *opaque, int c, 
+				 struct etraxfs_dma_client *cl)
+{
+	struct fs_dma_ctrl *ctrl = opaque;
+	cl->ctrl = ctrl;
+	cl->channel = c;
+	ctrl->channels[c].client = cl;
+}
+
+
+static void DMA_run(void *opaque)
+{
+    struct fs_dma_ctrl *etraxfs_dmac = opaque;
+    int p = 1;
+
+    if (vm_running)
+        p = etraxfs_dmac_run(etraxfs_dmac);
+
+    if (p)
+        qemu_bh_schedule_idle(etraxfs_dmac->bh);
+}
+
+void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels)
+{
+	struct fs_dma_ctrl *ctrl = NULL;
+
+	ctrl = qemu_mallocz(sizeof *ctrl);
+
+        ctrl->bh = qemu_bh_new(DMA_run, ctrl);
+
+	ctrl->nr_channels = nr_channels;
+	ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels);
+
+	ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl, DEVICE_NATIVE_ENDIAN);
+	cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map);
+	return ctrl;
+}
diff --git a/qemu-0.15.x/hw/etraxfs_dma.h b/qemu-0.15.x/hw/etraxfs_dma.h
new file mode 100644
index 0000000..96408ab
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_dma.h
@@ -0,0 +1,22 @@
+struct etraxfs_dma_client
+{
+	/* DMA controller. */
+	int channel;
+	void *ctrl;
+
+	/* client.  */
+	struct
+	{
+		int (*push)(void *opaque, unsigned char *buf, int len);
+		void (*pull)(void *opaque);
+		void *opaque;
+	} client;
+};
+
+void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels);
+void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line,
+			  int input);
+void etraxfs_dmac_connect_client(void *opaque, int c, 
+				 struct etraxfs_dma_client *cl);
+int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
+		       void *buf, int len, int eop);
diff --git a/qemu-0.15.x/hw/etraxfs_eth.c b/qemu-0.15.x/hw/etraxfs_eth.c
new file mode 100644
index 0000000..dff5f55
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_eth.c
@@ -0,0 +1,613 @@
+/*
+ * QEMU ETRAX Ethernet Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include "hw.h"
+#include "net.h"
+#include "etraxfs.h"
+
+#define D(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+/* 
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the 
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+struct qemu_phy
+{
+	uint32_t regs[32];
+
+	int link;
+
+	unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+	void (*write)(struct qemu_phy *phy, unsigned int req, 
+		      unsigned int data);
+};
+
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+	int regnum;
+	unsigned r = 0;
+
+	regnum = req & 0x1f;
+
+	switch (regnum) {
+		case 1:
+			if (!phy->link)
+				break;
+			/* MR1.	 */
+			/* Speeds and modes.  */
+			r |= (1 << 13) | (1 << 14);
+			r |= (1 << 11) | (1 << 12);
+			r |= (1 << 5); /* Autoneg complete.  */
+			r |= (1 << 3); /* Autoneg able.	 */
+			r |= (1 << 2); /* link.	 */
+			break;
+		case 5:
+			/* Link partner ability.
+			   We are kind; always agree with whatever best mode
+			   the guest advertises.  */
+			r = 1 << 14; /* Success.  */
+			/* Copy advertised modes.  */
+			r |= phy->regs[4] & (15 << 5);
+			/* Autoneg support.  */
+			r |= 1;
+			break;
+		case 18:
+		{
+			/* Diagnostics reg.  */
+			int duplex = 0;
+			int speed_100 = 0;
+
+			if (!phy->link)
+				break;
+
+			/* Are we advertising 100 half or 100 duplex ? */
+			speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+			speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+			/* Are we advertising 10 duplex or 100 duplex ? */
+			duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+			duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+			r = (speed_100 << 10) | (duplex << 11);
+		}
+		break;
+
+		default:
+			r = phy->regs[regnum];
+			break;
+	}
+	D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+	return r;
+}
+
+static void 
+tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+	int regnum;
+
+	regnum = req & 0x1f;
+	D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+	switch (regnum) {
+		default:
+			phy->regs[regnum] = data;
+			break;
+	}
+}
+
+static void 
+tdk_init(struct qemu_phy *phy)
+{
+	phy->regs[0] = 0x3100;
+	/* PHY Id.  */
+	phy->regs[2] = 0x0300;
+	phy->regs[3] = 0xe400;
+	/* Autonegotiation advertisement reg.  */
+	phy->regs[4] = 0x01E1;
+	phy->link = 1;
+
+	phy->read = tdk_read;
+	phy->write = tdk_write;
+}
+
+struct qemu_mdio
+{
+	/* bus.	 */
+	int mdc;
+	int mdio;
+
+	/* decoder.  */
+	enum {
+		PREAMBLE,
+		SOF,
+		OPC,
+		ADDR,
+		REQ,
+		TURNAROUND,
+		DATA
+	} state;
+	unsigned int drive;
+
+	unsigned int cnt;
+	unsigned int addr;
+	unsigned int opc;
+	unsigned int req;
+	unsigned int data;
+
+	struct qemu_phy *devs[32];
+};
+
+static void 
+mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+	bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void 
+mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+	bus->devs[addr & 0x1f] = NULL;	
+}
+#endif
+
+static void mdio_read_req(struct qemu_mdio *bus)
+{
+	struct qemu_phy *phy;
+
+	phy = bus->devs[bus->addr];
+	if (phy && phy->read)
+		bus->data = phy->read(phy, bus->req);
+	else 
+		bus->data = 0xffff;
+}
+
+static void mdio_write_req(struct qemu_mdio *bus)
+{
+	struct qemu_phy *phy;
+
+	phy = bus->devs[bus->addr];
+	if (phy && phy->write)
+		phy->write(phy, bus->req, bus->data);
+}
+
+static void mdio_cycle(struct qemu_mdio *bus)
+{
+	bus->cnt++;
+
+	D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
+		bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
+#if 0
+	if (bus->mdc)
+		printf("%d", bus->mdio);
+#endif
+	switch (bus->state)
+	{
+		case PREAMBLE:
+			if (bus->mdc) {
+				if (bus->cnt >= (32 * 2) && !bus->mdio) {
+					bus->cnt = 0;
+					bus->state = SOF;
+					bus->data = 0;
+				}
+			}
+			break;
+		case SOF:
+			if (bus->mdc) {
+				if (bus->mdio != 1)
+					printf("WARNING: no SOF\n");
+				if (bus->cnt == 1*2) {
+					bus->cnt = 0;
+					bus->opc = 0;
+					bus->state = OPC;
+				}
+			}
+			break;
+		case OPC:
+			if (bus->mdc) {
+				bus->opc <<= 1;
+				bus->opc |= bus->mdio & 1;
+				if (bus->cnt == 2*2) {
+					bus->cnt = 0;
+					bus->addr = 0;
+					bus->state = ADDR;
+				}
+			}
+			break;
+		case ADDR:
+			if (bus->mdc) {
+				bus->addr <<= 1;
+				bus->addr |= bus->mdio & 1;
+
+				if (bus->cnt == 5*2) {
+					bus->cnt = 0;
+					bus->req = 0;
+					bus->state = REQ;
+				}
+			}
+			break;
+		case REQ:
+			if (bus->mdc) {
+				bus->req <<= 1;
+				bus->req |= bus->mdio & 1;
+				if (bus->cnt == 5*2) {
+					bus->cnt = 0;
+					bus->state = TURNAROUND;
+				}
+			}
+			break;
+		case TURNAROUND:
+			if (bus->mdc && bus->cnt == 2*2) {
+				bus->mdio = 0;
+				bus->cnt = 0;
+
+				if (bus->opc == 2) {
+					bus->drive = 1;
+					mdio_read_req(bus);
+					bus->mdio = bus->data & 1;
+				}
+				bus->state = DATA;
+			}
+			break;
+		case DATA:			
+			if (!bus->mdc) {
+				if (bus->drive) {
+					bus->mdio = !!(bus->data & (1 << 15));
+					bus->data <<= 1;
+				}
+			} else {
+				if (!bus->drive) {
+					bus->data <<= 1;
+					bus->data |= bus->mdio;
+				}
+				if (bus->cnt == 16 * 2) {
+					bus->cnt = 0;
+					bus->state = PREAMBLE;
+					if (!bus->drive)
+						mdio_write_req(bus);
+					bus->drive = 0;
+				}
+			}
+			break;
+		default:
+			break;
+	}
+}
+
+/* ETRAX-FS Ethernet MAC block starts here.  */
+
+#define RW_MA0_LO	  0x00
+#define RW_MA0_HI	  0x01
+#define RW_MA1_LO	  0x02
+#define RW_MA1_HI	  0x03
+#define RW_GA_LO	  0x04
+#define RW_GA_HI	  0x05
+#define RW_GEN_CTRL	  0x06
+#define RW_REC_CTRL	  0x07
+#define RW_TR_CTRL	  0x08
+#define RW_CLR_ERR	  0x09
+#define RW_MGM_CTRL	  0x0a
+#define R_STAT		  0x0b
+#define FS_ETH_MAX_REGS	  0x17
+
+struct fs_eth
+{
+	NICState *nic;
+	NICConf conf;
+	int ethregs;
+
+	/* Two addrs in the filter.  */
+	uint8_t macaddr[2][6];
+	uint32_t regs[FS_ETH_MAX_REGS];
+
+	struct etraxfs_dma_client *dma_out;
+	struct etraxfs_dma_client *dma_in;
+
+	/* MDIO bus.  */
+	struct qemu_mdio mdio_bus;
+	unsigned int phyaddr;
+	int duplex_mismatch;
+
+	/* PHY.	 */
+	struct qemu_phy phy;
+};
+
+static void eth_validate_duplex(struct fs_eth *eth)
+{
+	struct qemu_phy *phy;
+	unsigned int phy_duplex;
+	unsigned int mac_duplex;
+	int new_mm = 0;
+
+	phy = eth->mdio_bus.devs[eth->phyaddr];
+	phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
+	mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
+
+	if (mac_duplex != phy_duplex)
+		new_mm = 1;
+
+	if (eth->regs[RW_GEN_CTRL] & 1) {
+		if (new_mm != eth->duplex_mismatch) {
+			if (new_mm)
+				printf("HW: WARNING "
+				       "ETH duplex mismatch MAC=%d PHY=%d\n",
+				       mac_duplex, phy_duplex);
+			else
+				printf("HW: ETH duplex ok.\n");
+		}
+		eth->duplex_mismatch = new_mm;
+	}
+}
+
+static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+{
+	struct fs_eth *eth = opaque;
+	uint32_t r = 0;
+
+	addr >>= 2;
+
+	switch (addr) {
+		case R_STAT:
+			r = eth->mdio_bus.mdio & 1;
+			break;
+	default:
+		r = eth->regs[addr];
+		D(printf ("%s %x\n", __func__, addr * 4));
+		break;
+	}
+	return r;
+}
+
+static void eth_update_ma(struct fs_eth *eth, int ma)
+{
+	int reg;
+	int i = 0;
+
+	ma &= 1;
+
+	reg = RW_MA0_LO;
+	if (ma)
+		reg = RW_MA1_LO;
+
+	eth->macaddr[ma][i++] = eth->regs[reg];
+	eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
+	eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
+	eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
+	eth->macaddr[ma][i++] = eth->regs[reg + 1];
+	eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
+
+	D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
+		 eth->macaddr[ma][0], eth->macaddr[ma][1],
+		 eth->macaddr[ma][2], eth->macaddr[ma][3],
+		 eth->macaddr[ma][4], eth->macaddr[ma][5]));
+}
+
+static void
+eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+	struct fs_eth *eth = opaque;
+
+	addr >>= 2;
+	switch (addr)
+	{
+		case RW_MA0_LO:
+		case RW_MA0_HI:
+			eth->regs[addr] = value;
+			eth_update_ma(eth, 0);
+			break;
+		case RW_MA1_LO:
+		case RW_MA1_HI:
+			eth->regs[addr] = value;
+			eth_update_ma(eth, 1);
+			break;
+
+		case RW_MGM_CTRL:
+			/* Attach an MDIO/PHY abstraction.  */
+			if (value & 2)
+				eth->mdio_bus.mdio = value & 1;
+			if (eth->mdio_bus.mdc != (value & 4)) {
+				mdio_cycle(&eth->mdio_bus);
+				eth_validate_duplex(eth);
+			}
+			eth->mdio_bus.mdc = !!(value & 4);
+			eth->regs[addr] = value;
+			break;
+
+		case RW_REC_CTRL:
+			eth->regs[addr] = value;
+			eth_validate_duplex(eth);
+			break;
+
+		default:
+			eth->regs[addr] = value;
+			D(printf ("%s %x %x\n",
+				  __func__, addr, value));
+			break;
+	}
+}
+
+/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
+   filter dropping group addresses we have not joined.	The filter has 64
+   bits (m). The has function is a simple nible xor of the group addr.	*/
+static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
+{
+	unsigned int hsh;
+	int m_individual = eth->regs[RW_REC_CTRL] & 4;
+	int match;
+
+	/* First bit on the wire of a MAC address signals multicast or
+	   physical address.  */
+	if (!m_individual && !(sa[0] & 1))
+		return 0;
+
+	/* Calculate the hash index for the GA registers. */
+	hsh = 0;
+	hsh ^= (*sa) & 0x3f;
+	hsh ^= ((*sa) >> 6) & 0x03;
+	++sa;
+	hsh ^= ((*sa) << 2) & 0x03c;
+	hsh ^= ((*sa) >> 4) & 0xf;
+	++sa;
+	hsh ^= ((*sa) << 4) & 0x30;
+	hsh ^= ((*sa) >> 2) & 0x3f;
+	++sa;
+	hsh ^= (*sa) & 0x3f;
+	hsh ^= ((*sa) >> 6) & 0x03;
+	++sa;
+	hsh ^= ((*sa) << 2) & 0x03c;
+	hsh ^= ((*sa) >> 4) & 0xf;
+	++sa;
+	hsh ^= ((*sa) << 4) & 0x30;
+	hsh ^= ((*sa) >> 2) & 0x3f;
+
+	hsh &= 63;
+	if (hsh > 31)
+		match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
+	else
+		match = eth->regs[RW_GA_LO] & (1 << hsh);
+	D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
+		 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
+	return match;
+}
+
+static int eth_can_receive(VLANClientState *nc)
+{
+	return 1;
+}
+
+static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+	unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+	int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
+	int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
+	int r_bcast = eth->regs[RW_REC_CTRL] & 8;
+
+	if (size < 12)
+		return -1;
+
+	D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
+		 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+		 use_ma0, use_ma1, r_bcast));
+	       
+	/* Does the frame get through the address filters?  */
+	if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
+	    && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
+	    && (!r_bcast || memcmp(buf, sa_bcast, 6))
+	    && !eth_match_groupaddr(eth, buf))
+		return size;
+
+	/* FIXME: Find another way to pass on the fake csum.  */
+	etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
+
+        return size;
+}
+
+static int eth_tx_push(void *opaque, unsigned char *buf, int len)
+{
+	struct fs_eth *eth = opaque;
+
+	D(printf("%s buf=%p len=%d\n", __func__, buf, len));
+	qemu_send_packet(&eth->nic->nc, buf, len);
+	return len;
+}
+
+static void eth_set_link(VLANClientState *nc)
+{
+	struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+	D(printf("%s %d\n", __func__, nc->link_down));
+	eth->phy.link = !nc->link_down;
+}
+
+static CPUReadMemoryFunc * const eth_read[] = {
+	NULL, NULL,
+	&eth_readl,
+};
+
+static CPUWriteMemoryFunc * const eth_write[] = {
+	NULL, NULL,
+	&eth_writel,
+};
+
+static void eth_cleanup(VLANClientState *nc)
+{
+	struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+
+        cpu_unregister_io_memory(eth->ethregs);
+
+        qemu_free(eth->dma_out);
+        qemu_free(eth);
+}
+
+static NetClientInfo net_etraxfs_info = {
+	.type = NET_CLIENT_TYPE_NIC,
+	.size = sizeof(NICState),
+	.can_receive = eth_can_receive,
+	.receive = eth_receive,
+	.cleanup = eth_cleanup,
+	.link_status_changed = eth_set_link,
+};
+
+void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
+{
+	struct etraxfs_dma_client *dma = NULL;	
+	struct fs_eth *eth = NULL;
+
+	qemu_check_nic_model(nd, "fseth");
+
+	dma = qemu_mallocz(sizeof *dma * 2);
+	eth = qemu_mallocz(sizeof *eth);
+
+	dma[0].client.push = eth_tx_push;
+	dma[0].client.opaque = eth;
+	dma[1].client.opaque = eth;
+	dma[1].client.pull = NULL;
+
+	eth->dma_out = dma;
+	eth->dma_in = dma + 1;
+
+	/* Connect the phy.  */
+	eth->phyaddr = phyaddr & 0x1f;
+	tdk_init(&eth->phy);
+	mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
+
+	eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth,
+                                              DEVICE_NATIVE_ENDIAN);
+	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
+
+	eth->conf.macaddr = nd->macaddr;
+	eth->conf.vlan = nd->vlan;
+	eth->conf.peer = nd->netdev;
+
+	eth->nic = qemu_new_nic(&net_etraxfs_info, &eth->conf,
+				nd->model, nd->name, eth);
+
+	return dma;
+}
diff --git a/qemu-0.15.x/hw/etraxfs_pic.c b/qemu-0.15.x/hw/etraxfs_pic.c
new file mode 100644
index 0000000..4feffda
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_pic.c
@@ -0,0 +1,169 @@
+/*
+ * QEMU ETRAX Interrupt Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+//#include "pc.h"
+//#include "etraxfs.h"
+
+#define D(x)
+
+#define R_RW_MASK   0
+#define R_R_VECT    1
+#define R_R_MASKED_VECT 2
+#define R_R_NMI     3
+#define R_R_GURU    4
+#define R_MAX       5
+
+struct etrax_pic
+{
+    SysBusDevice busdev;
+    void *interrupt_vector;
+    qemu_irq parent_irq;
+    qemu_irq parent_nmi;
+    uint32_t regs[R_MAX];
+};
+
+static void pic_update(struct etrax_pic *fs)
+{   
+    uint32_t vector = 0;
+    int i;
+
+    fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
+
+    /* The ETRAX interrupt controller signals interrupts to teh core
+       through an interrupt request wire and an irq vector bus. If 
+       multiple interrupts are simultaneously active it chooses vector 
+       0x30 and lets the sw choose the priorities.  */
+    if (fs->regs[R_R_MASKED_VECT]) {
+        uint32_t mv = fs->regs[R_R_MASKED_VECT];
+        for (i = 0; i < 31; i++) {
+            if (mv & 1) {
+                vector = 0x31 + i;
+                /* Check for multiple interrupts.  */
+                if (mv > 1)
+                    vector = 0x30;
+                break;
+            }
+            mv >>= 1;
+        }
+    }
+
+    if (fs->interrupt_vector) {
+        /* hack alert: ptr property */
+        *(uint32_t*)(fs->interrupt_vector) = vector;
+    }
+    qemu_set_irq(fs->parent_irq, !!vector);
+}
+
+static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct etrax_pic *fs = opaque;
+    uint32_t rval;
+
+    rval = fs->regs[addr >> 2];
+    D(printf("%s %x=%x\n", __func__, addr, rval));
+    return rval;
+}
+
+static void
+pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct etrax_pic *fs = opaque;
+    D(printf("%s addr=%x val=%x\n", __func__, addr, value));
+
+    if (addr == R_RW_MASK) {
+        fs->regs[R_RW_MASK] = value;
+        pic_update(fs);
+    }
+}
+
+static CPUReadMemoryFunc * const pic_read[] = {
+    NULL, NULL,
+    &pic_readl,
+};
+
+static CPUWriteMemoryFunc * const pic_write[] = {
+    NULL, NULL,
+    &pic_writel,
+};
+
+static void nmi_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+    uint32_t mask;
+
+    mask = 1 << irq;
+    if (level)
+        fs->regs[R_R_NMI] |= mask;
+    else
+        fs->regs[R_R_NMI] &= ~mask;
+
+    qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+
+    if (irq >= 30)
+        return nmi_handler(opaque, irq, level);
+
+    irq -= 1;
+    fs->regs[R_R_VECT] &= ~(1 << irq);
+    fs->regs[R_R_VECT] |= (!!level << irq);
+    pic_update(fs);
+}
+
+static int etraxfs_pic_init(SysBusDevice *dev)
+{
+    struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
+    int intr_vect_regs;
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    sysbus_init_irq(dev, &s->parent_nmi);
+
+    intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s,
+                                            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
+    return 0;
+}
+
+static SysBusDeviceInfo etraxfs_pic_info = {
+    .init = etraxfs_pic_init,
+    .qdev.name  = "etraxfs,pic",
+    .qdev.size  = sizeof(struct etrax_pic),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void etraxfs_pic_register(void)
+{
+    sysbus_register_withprop(&etraxfs_pic_info);
+}
+
+device_init(etraxfs_pic_register)
diff --git a/qemu-0.15.x/hw/etraxfs_ser.c b/qemu-0.15.x/hw/etraxfs_ser.c
new file mode 100644
index 0000000..b917d4d
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_ser.c
@@ -0,0 +1,234 @@
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+
+#define D(x)
+
+#define RW_TR_CTRL     (0x00 / 4)
+#define RW_TR_DMA_EN   (0x04 / 4)
+#define RW_REC_CTRL    (0x08 / 4)
+#define RW_DOUT        (0x1c / 4)
+#define RS_STAT_DIN    (0x20 / 4)
+#define R_STAT_DIN     (0x24 / 4)
+#define RW_INTR_MASK   (0x2c / 4)
+#define RW_ACK_INTR    (0x30 / 4)
+#define R_INTR         (0x34 / 4)
+#define R_MASKED_INTR  (0x38 / 4)
+#define R_MAX          (0x3c / 4)
+
+#define STAT_DAV     16
+#define STAT_TR_IDLE 22
+#define STAT_TR_RDY  24
+
+struct etrax_serial
+{
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    int pending_tx;
+
+    uint8_t rx_fifo[16];
+    unsigned int rx_fifo_pos;
+    unsigned int rx_fifo_len;
+
+    /* Control registers.  */
+    uint32_t regs[R_MAX];
+};
+
+static void ser_update_irq(struct etrax_serial *s)
+{
+
+    if (s->rx_fifo_len) {
+        s->regs[R_INTR] |= 8;
+    } else {
+        s->regs[R_INTR] &= ~8;
+    }
+
+    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
+    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
+}
+
+static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct etrax_serial *s = opaque;
+    D(CPUState *env = s->env);
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_STAT_DIN:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+            if (s->rx_fifo_len) {
+                r |= 1 << STAT_DAV;
+            }
+            r |= 1 << STAT_TR_RDY;
+            r |= 1 << STAT_TR_IDLE;
+            break;
+        case RS_STAT_DIN:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+            if (s->rx_fifo_len) {
+                r |= 1 << STAT_DAV;
+                s->rx_fifo_len--;
+            }
+            r |= 1 << STAT_TR_RDY;
+            r |= 1 << STAT_TR_IDLE;
+            break;
+        default:
+            r = s->regs[addr];
+            D(printf ("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
+            break;
+    }
+    return r;
+}
+
+static void
+ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct etrax_serial *s = opaque;
+    unsigned char ch = value;
+    D(CPUState *env = s->env);
+
+    D(printf ("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
+    addr >>= 2;
+    switch (addr)
+    {
+        case RW_DOUT:
+            qemu_chr_write(s->chr, &ch, 1);
+            s->regs[R_INTR] |= 3;
+            s->pending_tx = 1;
+            s->regs[addr] = value;
+            break;
+        case RW_ACK_INTR:
+            if (s->pending_tx) {
+                value &= ~1;
+                s->pending_tx = 0;
+                D(printf("fixedup value=%x r_intr=%x\n", value, s->regs[R_INTR]));
+            }
+            s->regs[addr] = value;
+            s->regs[R_INTR] &= ~value;
+            D(printf("r_intr=%x\n", s->regs[R_INTR]));
+            break;
+        default:
+            s->regs[addr] = value;
+            break;
+    }
+    ser_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const ser_read[] = {
+    NULL, NULL,
+    &ser_readl,
+};
+
+static CPUWriteMemoryFunc * const ser_write[] = {
+    NULL, NULL,
+    &ser_writel,
+};
+
+static void serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+    struct etrax_serial *s = opaque;
+    int i;
+
+    /* Got a byte.  */
+    if (s->rx_fifo_len >= 16) {
+        printf("WARNING: UART dropped char.\n");
+        return;
+    }
+
+    for (i = 0; i < size; i++) { 
+        s->rx_fifo[s->rx_fifo_pos] = buf[i];
+        s->rx_fifo_pos++;
+        s->rx_fifo_pos &= 15;
+        s->rx_fifo_len++;
+    }
+
+    ser_update_irq(s);
+}
+
+static int serial_can_receive(void *opaque)
+{
+    struct etrax_serial *s = opaque;
+    int r;
+
+    /* Is the receiver enabled?  */
+    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
+        return 0;
+    }
+
+    r = sizeof(s->rx_fifo) - s->rx_fifo_len;
+    return r;
+}
+
+static void serial_event(void *opaque, int event)
+{
+
+}
+
+static void etraxfs_ser_reset(DeviceState *d)
+{
+    struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
+
+    /* transmitter begins ready and idle.  */
+    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
+    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
+
+    s->regs[RW_REC_CTRL] = 0x10000;
+
+}
+
+static int etraxfs_ser_init(SysBusDevice *dev)
+{
+    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
+    int ser_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+    ser_regs = cpu_register_io_memory(ser_read, ser_write, s,
+                                      DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, ser_regs);
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr)
+        qemu_chr_add_handlers(s->chr,
+                      serial_can_receive, serial_receive,
+                      serial_event, s);
+    return 0;
+}
+
+static SysBusDeviceInfo etraxfs_ser_info = {
+    .init = etraxfs_ser_init,
+    .qdev.name  = "etraxfs,serial",
+    .qdev.size  = sizeof(struct etrax_serial),
+    .qdev.reset = etraxfs_ser_reset,
+};
+
+static void etraxfs_serial_register(void)
+{
+    sysbus_register_withprop(&etraxfs_ser_info);
+}
+
+device_init(etraxfs_serial_register)
diff --git a/qemu-0.15.x/hw/etraxfs_timer.c b/qemu-0.15.x/hw/etraxfs_timer.c
new file mode 100644
index 0000000..b08e574
--- /dev/null
+++ b/qemu-0.15.x/hw/etraxfs_timer.c
@@ -0,0 +1,336 @@
+/*
+ * QEMU ETRAX Timers
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "sysbus.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#define D(x)
+
+#define RW_TMR0_DIV   0x00
+#define R_TMR0_DATA   0x04
+#define RW_TMR0_CTRL  0x08
+#define RW_TMR1_DIV   0x10
+#define R_TMR1_DATA   0x14
+#define RW_TMR1_CTRL  0x18
+#define R_TIME        0x38
+#define RW_WD_CTRL    0x40
+#define R_WD_STAT     0x44
+#define RW_INTR_MASK  0x48
+#define RW_ACK_INTR   0x4c
+#define R_INTR        0x50
+#define R_MASKED_INTR 0x54
+
+struct etrax_timer {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    qemu_irq nmi;
+
+    QEMUBH *bh_t0;
+    QEMUBH *bh_t1;
+    QEMUBH *bh_wd;
+    ptimer_state *ptimer_t0;
+    ptimer_state *ptimer_t1;
+    ptimer_state *ptimer_wd;
+
+    int wd_hits;
+
+    /* Control registers.  */
+    uint32_t rw_tmr0_div;
+    uint32_t r_tmr0_data;
+    uint32_t rw_tmr0_ctrl;
+
+    uint32_t rw_tmr1_div;
+    uint32_t r_tmr1_data;
+    uint32_t rw_tmr1_ctrl;
+
+    uint32_t rw_wd_ctrl;
+
+    uint32_t rw_intr_mask;
+    uint32_t rw_ack_intr;
+    uint32_t r_intr;
+    uint32_t r_masked_intr;
+};
+
+static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct etrax_timer *t = opaque;
+    uint32_t r = 0;
+
+    switch (addr) {
+    case R_TMR0_DATA:
+        r = ptimer_get_count(t->ptimer_t0);
+        break;
+    case R_TMR1_DATA:
+        r = ptimer_get_count(t->ptimer_t1);
+        break;
+    case R_TIME:
+        r = qemu_get_clock_ns(vm_clock) / 10;
+        break;
+    case RW_INTR_MASK:
+        r = t->rw_intr_mask;
+        break;
+    case R_MASKED_INTR:
+        r = t->r_intr & t->rw_intr_mask;
+        break;
+    default:
+        D(printf ("%s %x\n", __func__, addr));
+        break;
+    }
+    return r;
+}
+
+static void update_ctrl(struct etrax_timer *t, int tnum)
+{
+    unsigned int op;
+    unsigned int freq;
+    unsigned int freq_hz;
+    unsigned int div;
+    uint32_t ctrl;
+
+    ptimer_state *timer;
+
+    if (tnum == 0) {
+        ctrl = t->rw_tmr0_ctrl;
+        div = t->rw_tmr0_div;
+        timer = t->ptimer_t0;
+    } else {
+        ctrl = t->rw_tmr1_ctrl;
+        div = t->rw_tmr1_div;
+        timer = t->ptimer_t1;
+    }
+
+
+    op = ctrl & 3;
+    freq = ctrl >> 2;
+    freq_hz = 32000000;
+
+    switch (freq)
+    {
+    case 0:
+    case 1:
+        D(printf ("extern or disabled timer clock?\n"));
+        break;
+    case 4: freq_hz =  29493000; break;
+    case 5: freq_hz =  32000000; break;
+    case 6: freq_hz =  32768000; break;
+    case 7: freq_hz = 100000000; break;
+    default:
+        abort();
+        break;
+    }
+
+    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
+    ptimer_set_freq(timer, freq_hz);
+    ptimer_set_limit(timer, div, 0);
+
+    switch (op)
+    {
+        case 0:
+            /* Load.  */
+            ptimer_set_limit(timer, div, 1);
+            break;
+        case 1:
+            /* Hold.  */
+            ptimer_stop(timer);
+            break;
+        case 2:
+            /* Run.  */
+            ptimer_run(timer, 0);
+            break;
+        default:
+            abort();
+            break;
+    }
+}
+
+static void timer_update_irq(struct etrax_timer *t)
+{
+    t->r_intr &= ~(t->rw_ack_intr);
+    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
+
+    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
+    qemu_set_irq(t->irq, !!t->r_masked_intr);
+}
+
+static void timer0_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 1;
+    timer_update_irq(t);
+}
+
+static void timer1_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 2;
+    timer_update_irq(t);
+}
+
+static void watchdog_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    if (t->wd_hits == 0) {
+        /* real hw gives a single tick before reseting but we are
+           a bit friendlier to compensate for our slower execution.  */
+        ptimer_set_count(t->ptimer_wd, 10);
+        ptimer_run(t->ptimer_wd, 1);
+        qemu_irq_raise(t->nmi);
+    }
+    else
+        qemu_system_reset_request();
+
+    t->wd_hits++;
+}
+
+static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
+{
+    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
+    unsigned int wd_key = t->rw_wd_ctrl >> 9;
+    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
+    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
+    unsigned int new_cmd = (value >> 8) & 1;
+
+    /* If the watchdog is enabled, they written key must match the
+       complement of the previous.  */
+    wd_key = ~wd_key & ((1 << 7) - 1);
+
+    if (wd_en && wd_key != new_key)
+        return;
+
+    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
+         wd_en, new_key, wd_key, new_cmd, wd_cnt));
+
+    if (t->wd_hits)
+        qemu_irq_lower(t->nmi);
+
+    t->wd_hits = 0;
+
+    ptimer_set_freq(t->ptimer_wd, 760);
+    if (wd_cnt == 0)
+        wd_cnt = 256;
+    ptimer_set_count(t->ptimer_wd, wd_cnt);
+    if (new_cmd)
+        ptimer_run(t->ptimer_wd, 1);
+    else
+        ptimer_stop(t->ptimer_wd);
+
+    t->rw_wd_ctrl = value;
+}
+
+static void
+timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct etrax_timer *t = opaque;
+
+    switch (addr)
+    {
+        case RW_TMR0_DIV:
+            t->rw_tmr0_div = value;
+            break;
+        case RW_TMR0_CTRL:
+            D(printf ("RW_TMR0_CTRL=%x\n", value));
+            t->rw_tmr0_ctrl = value;
+            update_ctrl(t, 0);
+            break;
+        case RW_TMR1_DIV:
+            t->rw_tmr1_div = value;
+            break;
+        case RW_TMR1_CTRL:
+            D(printf ("RW_TMR1_CTRL=%x\n", value));
+            t->rw_tmr1_ctrl = value;
+            update_ctrl(t, 1);
+            break;
+        case RW_INTR_MASK:
+            D(printf ("RW_INTR_MASK=%x\n", value));
+            t->rw_intr_mask = value;
+            timer_update_irq(t);
+            break;
+        case RW_WD_CTRL:
+            timer_watchdog_update(t, value);
+            break;
+        case RW_ACK_INTR:
+            t->rw_ack_intr = value;
+            timer_update_irq(t);
+            t->rw_ack_intr = 0;
+            break;
+        default:
+            printf ("%s " TARGET_FMT_plx " %x\n",
+                __func__, addr, value);
+            break;
+    }
+}
+
+static CPUReadMemoryFunc * const timer_read[] = {
+    NULL, NULL,
+    &timer_readl,
+};
+
+static CPUWriteMemoryFunc * const timer_write[] = {
+    NULL, NULL,
+    &timer_writel,
+};
+
+static void etraxfs_timer_reset(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+
+    ptimer_stop(t->ptimer_t0);
+    ptimer_stop(t->ptimer_t1);
+    ptimer_stop(t->ptimer_wd);
+    t->rw_wd_ctrl = 0;
+    t->r_intr = 0;
+    t->rw_intr_mask = 0;
+    qemu_irq_lower(t->irq);
+}
+
+static int etraxfs_timer_init(SysBusDevice *dev)
+{
+    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
+    int timer_regs;
+
+    t->bh_t0 = qemu_bh_new(timer0_hit, t);
+    t->bh_t1 = qemu_bh_new(timer1_hit, t);
+    t->bh_wd = qemu_bh_new(watchdog_hit, t);
+    t->ptimer_t0 = ptimer_init(t->bh_t0);
+    t->ptimer_t1 = ptimer_init(t->bh_t1);
+    t->ptimer_wd = ptimer_init(t->bh_wd);
+
+    sysbus_init_irq(dev, &t->irq);
+    sysbus_init_irq(dev, &t->nmi);
+
+    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
+                                        DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x5c, timer_regs);
+
+    qemu_register_reset(etraxfs_timer_reset, t);
+    return 0;
+}
+
+static void etraxfs_timer_register(void)
+{
+    sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
+                        etraxfs_timer_init);
+}
+
+device_init(etraxfs_timer_register)
diff --git a/qemu-0.15.x/hw/event_notifier.c b/qemu-0.15.x/hw/event_notifier.c
new file mode 100644
index 0000000..13f3656
--- /dev/null
+++ b/qemu-0.15.x/hw/event_notifier.c
@@ -0,0 +1,62 @@
+/*
+ * event notifier support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "hw.h"
+#include "event_notifier.h"
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+int event_notifier_init(EventNotifier *e, int active)
+{
+#ifdef CONFIG_EVENTFD
+    int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
+    if (fd < 0)
+        return -errno;
+    e->fd = fd;
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+void event_notifier_cleanup(EventNotifier *e)
+{
+    close(e->fd);
+}
+
+int event_notifier_get_fd(EventNotifier *e)
+{
+    return e->fd;
+}
+
+int event_notifier_test_and_clear(EventNotifier *e)
+{
+    uint64_t value;
+    int r = read(e->fd, &value, sizeof(value));
+    return r == sizeof(value);
+}
+
+int event_notifier_test(EventNotifier *e)
+{
+    uint64_t value;
+    int r = read(e->fd, &value, sizeof(value));
+    if (r == sizeof(value)) {
+        /* restore previous value. */
+        int s = write(e->fd, &value, sizeof(value));
+        /* never blocks because we use EFD_SEMAPHORE.
+         * If we didn't we'd get EAGAIN on overflow
+         * and we'd have to write code to ignore it. */
+        assert(s == sizeof(value));
+    }
+    return r == sizeof(value);
+}
diff --git a/qemu-0.15.x/hw/event_notifier.h b/qemu-0.15.x/hw/event_notifier.h
new file mode 100644
index 0000000..24117ea
--- /dev/null
+++ b/qemu-0.15.x/hw/event_notifier.h
@@ -0,0 +1,16 @@
+#ifndef QEMU_EVENT_NOTIFIER_H
+#define QEMU_EVENT_NOTIFIER_H
+
+#include "qemu-common.h"
+
+struct EventNotifier {
+	int fd;
+};
+
+int event_notifier_init(EventNotifier *, int active);
+void event_notifier_cleanup(EventNotifier *);
+int event_notifier_get_fd(EventNotifier *);
+int event_notifier_test_and_clear(EventNotifier *);
+int event_notifier_test(EventNotifier *);
+
+#endif
diff --git a/qemu-0.15.x/hw/fdc.c b/qemu-0.15.x/hw/fdc.c
new file mode 100644
index 0000000..9fdbc75
--- /dev/null
+++ b/qemu-0.15.x/hw/fdc.c
@@ -0,0 +1,1983 @@
+/*
+ * QEMU Floppy disk emulator (Intel 82078)
+ *
+ * Copyright (c) 2003, 2007 Jocelyn Mayer
+ * Copyright (c) 2008 Hervé Poussineau
+ *
+ * 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.
+ */
+/*
+ * The controller is used in Sun4m systems in a slightly different
+ * way. There are changes in DOR register and DMA is not available.
+ */
+
+#include "hw.h"
+#include "fdc.h"
+#include "qemu-error.h"
+#include "qemu-timer.h"
+#include "isa.h"
+#include "sysbus.h"
+#include "qdev-addr.h"
+#include "blockdev.h"
+#include "sysemu.h"
+
+/********************************************************/
+/* debug Floppy devices */
+//#define DEBUG_FLOPPY
+
+#ifdef DEBUG_FLOPPY
+#define FLOPPY_DPRINTF(fmt, ...)                                \
+    do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define FLOPPY_DPRINTF(fmt, ...)
+#endif
+
+#define FLOPPY_ERROR(fmt, ...)                                          \
+    do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+/********************************************************/
+/* Floppy drive emulation                               */
+
+#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
+#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
+
+/* Will always be a fixed parameter for us */
+#define FD_SECTOR_LEN          512
+#define FD_SECTOR_SC           2   /* Sector size code */
+#define FD_RESET_SENSEI_COUNT  4   /* Number of sense interrupts on RESET */
+
+/* Floppy disk drive emulation */
+typedef enum FDiskFlags {
+    FDISK_DBL_SIDES  = 0x01,
+} FDiskFlags;
+
+typedef struct FDrive {
+    BlockDriverState *bs;
+    /* Drive status */
+    FDriveType drive;
+    uint8_t perpendicular;    /* 2.88 MB access mode    */
+    /* Position */
+    uint8_t head;
+    uint8_t track;
+    uint8_t sect;
+    /* Media */
+    FDiskFlags flags;
+    uint8_t last_sect;        /* Nb sector per track    */
+    uint8_t max_track;        /* Nb of tracks           */
+    uint16_t bps;             /* Bytes per sector       */
+    uint8_t ro;               /* Is read-only           */
+} FDrive;
+
+static void fd_init(FDrive *drv)
+{
+    /* Drive */
+    drv->drive = FDRIVE_DRV_NONE;
+    drv->perpendicular = 0;
+    /* Disk */
+    drv->last_sect = 0;
+    drv->max_track = 0;
+}
+
+static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
+                          uint8_t last_sect)
+{
+    return (((track * 2) + head) * last_sect) + sect - 1;
+}
+
+/* Returns current position, in sectors, for given drive */
+static int fd_sector(FDrive *drv)
+{
+    return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect);
+}
+
+/* Seek to a new position:
+ * returns 0 if already on right track
+ * returns 1 if track changed
+ * returns 2 if track is invalid
+ * returns 3 if sector is invalid
+ * returns 4 if seek is disabled
+ */
+static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
+                   int enable_seek)
+{
+    uint32_t sector;
+    int ret;
+
+    if (track > drv->max_track ||
+        (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
+        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
+                       head, track, sect, 1,
+                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
+                       drv->max_track, drv->last_sect);
+        return 2;
+    }
+    if (sect > drv->last_sect) {
+        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
+                       head, track, sect, 1,
+                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
+                       drv->max_track, drv->last_sect);
+        return 3;
+    }
+    sector = fd_sector_calc(head, track, sect, drv->last_sect);
+    ret = 0;
+    if (sector != fd_sector(drv)) {
+#if 0
+        if (!enable_seek) {
+            FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
+                         head, track, sect, 1, drv->max_track, drv->last_sect);
+            return 4;
+        }
+#endif
+        drv->head = head;
+        if (drv->track != track)
+            ret = 1;
+        drv->track = track;
+        drv->sect = sect;
+    }
+
+    return ret;
+}
+
+/* Set drive back to track 0 */
+static void fd_recalibrate(FDrive *drv)
+{
+    FLOPPY_DPRINTF("recalibrate\n");
+    drv->head = 0;
+    drv->track = 0;
+    drv->sect = 1;
+}
+
+/* Revalidate a disk drive after a disk change */
+static void fd_revalidate(FDrive *drv)
+{
+    int nb_heads, max_track, last_sect, ro;
+    FDriveType drive;
+
+    FLOPPY_DPRINTF("revalidate\n");
+    if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
+        ro = bdrv_is_read_only(drv->bs);
+        bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
+                                      &last_sect, drv->drive, &drive);
+        if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
+            FLOPPY_DPRINTF("User defined disk (%d %d %d)",
+                           nb_heads - 1, max_track, last_sect);
+        } else {
+            FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
+                           max_track, last_sect, ro ? "ro" : "rw");
+        }
+        if (nb_heads == 1) {
+            drv->flags &= ~FDISK_DBL_SIDES;
+        } else {
+            drv->flags |= FDISK_DBL_SIDES;
+        }
+        drv->max_track = max_track;
+        drv->last_sect = last_sect;
+        drv->ro = ro;
+        drv->drive = drive;
+    } else {
+        FLOPPY_DPRINTF("No disk in drive\n");
+        drv->last_sect = 0;
+        drv->max_track = 0;
+        drv->flags &= ~FDISK_DBL_SIDES;
+    }
+}
+
+/********************************************************/
+/* Intel 82078 floppy disk controller emulation          */
+
+typedef struct FDCtrl FDCtrl;
+
+static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
+static void fdctrl_reset_fifo(FDCtrl *fdctrl);
+static int fdctrl_transfer_handler (void *opaque, int nchan,
+                                    int dma_pos, int dma_len);
+static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0);
+
+static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
+static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
+static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
+static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
+static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
+static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
+static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
+
+enum {
+    FD_DIR_WRITE   = 0,
+    FD_DIR_READ    = 1,
+    FD_DIR_SCANE   = 2,
+    FD_DIR_SCANL   = 3,
+    FD_DIR_SCANH   = 4,
+};
+
+enum {
+    FD_STATE_MULTI  = 0x01,	/* multi track flag */
+    FD_STATE_FORMAT = 0x02,	/* format flag */
+    FD_STATE_SEEK   = 0x04,	/* seek flag */
+};
+
+enum {
+    FD_REG_SRA = 0x00,
+    FD_REG_SRB = 0x01,
+    FD_REG_DOR = 0x02,
+    FD_REG_TDR = 0x03,
+    FD_REG_MSR = 0x04,
+    FD_REG_DSR = 0x04,
+    FD_REG_FIFO = 0x05,
+    FD_REG_DIR = 0x07,
+};
+
+enum {
+    FD_CMD_READ_TRACK = 0x02,
+    FD_CMD_SPECIFY = 0x03,
+    FD_CMD_SENSE_DRIVE_STATUS = 0x04,
+    FD_CMD_WRITE = 0x05,
+    FD_CMD_READ = 0x06,
+    FD_CMD_RECALIBRATE = 0x07,
+    FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
+    FD_CMD_WRITE_DELETED = 0x09,
+    FD_CMD_READ_ID = 0x0a,
+    FD_CMD_READ_DELETED = 0x0c,
+    FD_CMD_FORMAT_TRACK = 0x0d,
+    FD_CMD_DUMPREG = 0x0e,
+    FD_CMD_SEEK = 0x0f,
+    FD_CMD_VERSION = 0x10,
+    FD_CMD_SCAN_EQUAL = 0x11,
+    FD_CMD_PERPENDICULAR_MODE = 0x12,
+    FD_CMD_CONFIGURE = 0x13,
+    FD_CMD_LOCK = 0x14,
+    FD_CMD_VERIFY = 0x16,
+    FD_CMD_POWERDOWN_MODE = 0x17,
+    FD_CMD_PART_ID = 0x18,
+    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
+    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
+    FD_CMD_SAVE = 0x2e,
+    FD_CMD_OPTION = 0x33,
+    FD_CMD_RESTORE = 0x4e,
+    FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
+    FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
+    FD_CMD_FORMAT_AND_WRITE = 0xcd,
+    FD_CMD_RELATIVE_SEEK_IN = 0xcf,
+};
+
+enum {
+    FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
+    FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
+    FD_CONFIG_POLL  = 0x10, /* Poll enabled */
+    FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
+    FD_CONFIG_EIS   = 0x40, /* No implied seeks */
+};
+
+enum {
+    FD_SR0_EQPMT    = 0x10,
+    FD_SR0_SEEK     = 0x20,
+    FD_SR0_ABNTERM  = 0x40,
+    FD_SR0_INVCMD   = 0x80,
+    FD_SR0_RDYCHG   = 0xc0,
+};
+
+enum {
+    FD_SR1_EC       = 0x80, /* End of cylinder */
+};
+
+enum {
+    FD_SR2_SNS      = 0x04, /* Scan not satisfied */
+    FD_SR2_SEH      = 0x08, /* Scan equal hit */
+};
+
+enum {
+    FD_SRA_DIR      = 0x01,
+    FD_SRA_nWP      = 0x02,
+    FD_SRA_nINDX    = 0x04,
+    FD_SRA_HDSEL    = 0x08,
+    FD_SRA_nTRK0    = 0x10,
+    FD_SRA_STEP     = 0x20,
+    FD_SRA_nDRV2    = 0x40,
+    FD_SRA_INTPEND  = 0x80,
+};
+
+enum {
+    FD_SRB_MTR0     = 0x01,
+    FD_SRB_MTR1     = 0x02,
+    FD_SRB_WGATE    = 0x04,
+    FD_SRB_RDATA    = 0x08,
+    FD_SRB_WDATA    = 0x10,
+    FD_SRB_DR0      = 0x20,
+};
+
+enum {
+#if MAX_FD == 4
+    FD_DOR_SELMASK  = 0x03,
+#else
+    FD_DOR_SELMASK  = 0x01,
+#endif
+    FD_DOR_nRESET   = 0x04,
+    FD_DOR_DMAEN    = 0x08,
+    FD_DOR_MOTEN0   = 0x10,
+    FD_DOR_MOTEN1   = 0x20,
+    FD_DOR_MOTEN2   = 0x40,
+    FD_DOR_MOTEN3   = 0x80,
+};
+
+enum {
+#if MAX_FD == 4
+    FD_TDR_BOOTSEL  = 0x0c,
+#else
+    FD_TDR_BOOTSEL  = 0x04,
+#endif
+};
+
+enum {
+    FD_DSR_DRATEMASK= 0x03,
+    FD_DSR_PWRDOWN  = 0x40,
+    FD_DSR_SWRESET  = 0x80,
+};
+
+enum {
+    FD_MSR_DRV0BUSY = 0x01,
+    FD_MSR_DRV1BUSY = 0x02,
+    FD_MSR_DRV2BUSY = 0x04,
+    FD_MSR_DRV3BUSY = 0x08,
+    FD_MSR_CMDBUSY  = 0x10,
+    FD_MSR_NONDMA   = 0x20,
+    FD_MSR_DIO      = 0x40,
+    FD_MSR_RQM      = 0x80,
+};
+
+enum {
+    FD_DIR_DSKCHG   = 0x80,
+};
+
+#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
+#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
+#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
+
+struct FDCtrl {
+    /* Controller's identification */
+    uint8_t version;
+    /* HW */
+    qemu_irq irq;
+    int dma_chann;
+    /* Controller state */
+    QEMUTimer *result_timer;
+    uint8_t sra;
+    uint8_t srb;
+    uint8_t dor;
+    uint8_t dor_vmstate; /* only used as temp during vmstate */
+    uint8_t tdr;
+    uint8_t dsr;
+    uint8_t msr;
+    uint8_t cur_drv;
+    uint8_t status0;
+    uint8_t status1;
+    uint8_t status2;
+    /* Command FIFO */
+    uint8_t *fifo;
+    int32_t fifo_size;
+    uint32_t data_pos;
+    uint32_t data_len;
+    uint8_t data_state;
+    uint8_t data_dir;
+    uint8_t eot; /* last wanted sector */
+    /* States kept only to be returned back */
+    /* Timers state */
+    uint8_t timer0;
+    uint8_t timer1;
+    /* precompensation */
+    uint8_t precomp_trk;
+    uint8_t config;
+    uint8_t lock;
+    /* Power down config (also with status regB access mode */
+    uint8_t pwrd;
+    /* Sun4m quirks? */
+    int sun4m;
+    /* Floppy drives */
+    uint8_t num_floppies;
+    FDrive drives[MAX_FD];
+    int reset_sensei;
+};
+
+typedef struct FDCtrlSysBus {
+    SysBusDevice busdev;
+    struct FDCtrl state;
+} FDCtrlSysBus;
+
+typedef struct FDCtrlISABus {
+    ISADevice busdev;
+    struct FDCtrl state;
+    int32_t bootindexA;
+    int32_t bootindexB;
+} FDCtrlISABus;
+
+static uint32_t fdctrl_read (void *opaque, uint32_t reg)
+{
+    FDCtrl *fdctrl = opaque;
+    uint32_t retval;
+
+    switch (reg) {
+    case FD_REG_SRA:
+        retval = fdctrl_read_statusA(fdctrl);
+        break;
+    case FD_REG_SRB:
+        retval = fdctrl_read_statusB(fdctrl);
+        break;
+    case FD_REG_DOR:
+        retval = fdctrl_read_dor(fdctrl);
+        break;
+    case FD_REG_TDR:
+        retval = fdctrl_read_tape(fdctrl);
+        break;
+    case FD_REG_MSR:
+        retval = fdctrl_read_main_status(fdctrl);
+        break;
+    case FD_REG_FIFO:
+        retval = fdctrl_read_data(fdctrl);
+        break;
+    case FD_REG_DIR:
+        retval = fdctrl_read_dir(fdctrl);
+        break;
+    default:
+        retval = (uint32_t)(-1);
+        break;
+    }
+    FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
+
+    return retval;
+}
+
+static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
+{
+    FDCtrl *fdctrl = opaque;
+
+    FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
+
+    switch (reg) {
+    case FD_REG_DOR:
+        fdctrl_write_dor(fdctrl, value);
+        break;
+    case FD_REG_TDR:
+        fdctrl_write_tape(fdctrl, value);
+        break;
+    case FD_REG_DSR:
+        fdctrl_write_rate(fdctrl, value);
+        break;
+    case FD_REG_FIFO:
+        fdctrl_write_data(fdctrl, value);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t fdctrl_read_port (void *opaque, uint32_t reg)
+{
+    return fdctrl_read(opaque, reg & 7);
+}
+
+static void fdctrl_write_port (void *opaque, uint32_t reg, uint32_t value)
+{
+    fdctrl_write(opaque, reg & 7, value);
+}
+
+static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
+{
+    return fdctrl_read(opaque, (uint32_t)reg);
+}
+
+static void fdctrl_write_mem (void *opaque,
+                              target_phys_addr_t reg, uint32_t value)
+{
+    fdctrl_write(opaque, (uint32_t)reg, value);
+}
+
+static CPUReadMemoryFunc * const fdctrl_mem_read[3] = {
+    fdctrl_read_mem,
+    fdctrl_read_mem,
+    fdctrl_read_mem,
+};
+
+static CPUWriteMemoryFunc * const fdctrl_mem_write[3] = {
+    fdctrl_write_mem,
+    fdctrl_write_mem,
+    fdctrl_write_mem,
+};
+
+static CPUReadMemoryFunc * const fdctrl_mem_read_strict[3] = {
+    fdctrl_read_mem,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
+    fdctrl_write_mem,
+    NULL,
+    NULL,
+};
+
+static const VMStateDescription vmstate_fdrive = {
+    .name = "fdrive",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(head, FDrive),
+        VMSTATE_UINT8(track, FDrive),
+        VMSTATE_UINT8(sect, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void fdc_pre_save(void *opaque)
+{
+    FDCtrl *s = opaque;
+
+    s->dor_vmstate = s->dor | GET_CUR_DRV(s);
+}
+
+static int fdc_post_load(void *opaque, int version_id)
+{
+    FDCtrl *s = opaque;
+
+    SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
+    s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
+    return 0;
+}
+
+static const VMStateDescription vmstate_fdc = {
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .pre_save = fdc_pre_save,
+    .post_load = fdc_post_load,
+    .fields      = (VMStateField []) {
+        /* Controller State */
+        VMSTATE_UINT8(sra, FDCtrl),
+        VMSTATE_UINT8(srb, FDCtrl),
+        VMSTATE_UINT8(dor_vmstate, FDCtrl),
+        VMSTATE_UINT8(tdr, FDCtrl),
+        VMSTATE_UINT8(dsr, FDCtrl),
+        VMSTATE_UINT8(msr, FDCtrl),
+        VMSTATE_UINT8(status0, FDCtrl),
+        VMSTATE_UINT8(status1, FDCtrl),
+        VMSTATE_UINT8(status2, FDCtrl),
+        /* Command FIFO */
+        VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
+                             uint8_t),
+        VMSTATE_UINT32(data_pos, FDCtrl),
+        VMSTATE_UINT32(data_len, FDCtrl),
+        VMSTATE_UINT8(data_state, FDCtrl),
+        VMSTATE_UINT8(data_dir, FDCtrl),
+        VMSTATE_UINT8(eot, FDCtrl),
+        /* States kept only to be returned back */
+        VMSTATE_UINT8(timer0, FDCtrl),
+        VMSTATE_UINT8(timer1, FDCtrl),
+        VMSTATE_UINT8(precomp_trk, FDCtrl),
+        VMSTATE_UINT8(config, FDCtrl),
+        VMSTATE_UINT8(lock, FDCtrl),
+        VMSTATE_UINT8(pwrd, FDCtrl),
+        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
+        VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
+                             vmstate_fdrive, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void fdctrl_external_reset_sysbus(DeviceState *d)
+{
+    FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
+    FDCtrl *s = &sys->state;
+
+    fdctrl_reset(s, 0);
+}
+
+static void fdctrl_external_reset_isa(DeviceState *d)
+{
+    FDCtrlISABus *isa = container_of(d, FDCtrlISABus, busdev.qdev);
+    FDCtrl *s = &isa->state;
+
+    fdctrl_reset(s, 0);
+}
+
+static void fdctrl_handle_tc(void *opaque, int irq, int level)
+{
+    //FDCtrl *s = opaque;
+
+    if (level) {
+        // XXX
+        FLOPPY_DPRINTF("TC pulsed\n");
+    }
+}
+
+/* Change IRQ state */
+static void fdctrl_reset_irq(FDCtrl *fdctrl)
+{
+    if (!(fdctrl->sra & FD_SRA_INTPEND))
+        return;
+    FLOPPY_DPRINTF("Reset interrupt\n");
+    qemu_set_irq(fdctrl->irq, 0);
+    fdctrl->sra &= ~FD_SRA_INTPEND;
+}
+
+static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
+{
+    /* Sparc mutation */
+    if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
+        /* XXX: not sure */
+        fdctrl->msr &= ~FD_MSR_CMDBUSY;
+        fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
+        fdctrl->status0 = status0;
+        return;
+    }
+    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
+        qemu_set_irq(fdctrl->irq, 1);
+        fdctrl->sra |= FD_SRA_INTPEND;
+    }
+    fdctrl->reset_sensei = 0;
+    fdctrl->status0 = status0;
+    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
+}
+
+/* Reset controller */
+static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
+{
+    int i;
+
+    FLOPPY_DPRINTF("reset controller\n");
+    fdctrl_reset_irq(fdctrl);
+    /* Initialise controller */
+    fdctrl->sra = 0;
+    fdctrl->srb = 0xc0;
+    if (!fdctrl->drives[1].bs)
+        fdctrl->sra |= FD_SRA_nDRV2;
+    fdctrl->cur_drv = 0;
+    fdctrl->dor = FD_DOR_nRESET;
+    fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
+    fdctrl->msr = FD_MSR_RQM;
+    /* FIFO state */
+    fdctrl->data_pos = 0;
+    fdctrl->data_len = 0;
+    fdctrl->data_state = 0;
+    fdctrl->data_dir = FD_DIR_WRITE;
+    for (i = 0; i < MAX_FD; i++)
+        fd_recalibrate(&fdctrl->drives[i]);
+    fdctrl_reset_fifo(fdctrl);
+    if (do_irq) {
+        fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
+        fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
+    }
+}
+
+static inline FDrive *drv0(FDCtrl *fdctrl)
+{
+    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
+}
+
+static inline FDrive *drv1(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
+        return &fdctrl->drives[1];
+    else
+        return &fdctrl->drives[0];
+}
+
+#if MAX_FD == 4
+static inline FDrive *drv2(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
+        return &fdctrl->drives[2];
+    else
+        return &fdctrl->drives[1];
+}
+
+static inline FDrive *drv3(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
+        return &fdctrl->drives[3];
+    else
+        return &fdctrl->drives[2];
+}
+#endif
+
+static FDrive *get_cur_drv(FDCtrl *fdctrl)
+{
+    switch (fdctrl->cur_drv) {
+        case 0: return drv0(fdctrl);
+        case 1: return drv1(fdctrl);
+#if MAX_FD == 4
+        case 2: return drv2(fdctrl);
+        case 3: return drv3(fdctrl);
+#endif
+        default: return NULL;
+    }
+}
+
+/* Status A register : 0x00 (read-only) */
+static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->sra;
+
+    FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Status B register : 0x01 (read-only) */
+static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->srb;
+
+    FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Digital output register : 0x02 */
+static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->dor;
+
+    /* Selected drive */
+    retval |= fdctrl->cur_drv;
+    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
+{
+    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
+
+    /* Motors */
+    if (value & FD_DOR_MOTEN0)
+        fdctrl->srb |= FD_SRB_MTR0;
+    else
+        fdctrl->srb &= ~FD_SRB_MTR0;
+    if (value & FD_DOR_MOTEN1)
+        fdctrl->srb |= FD_SRB_MTR1;
+    else
+        fdctrl->srb &= ~FD_SRB_MTR1;
+
+    /* Drive */
+    if (value & 1)
+        fdctrl->srb |= FD_SRB_DR0;
+    else
+        fdctrl->srb &= ~FD_SRB_DR0;
+
+    /* Reset */
+    if (!(value & FD_DOR_nRESET)) {
+        if (fdctrl->dor & FD_DOR_nRESET) {
+            FLOPPY_DPRINTF("controller enter RESET state\n");
+        }
+    } else {
+        if (!(fdctrl->dor & FD_DOR_nRESET)) {
+            FLOPPY_DPRINTF("controller out of RESET state\n");
+            fdctrl_reset(fdctrl, 1);
+            fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+        }
+    }
+    /* Selected drive */
+    fdctrl->cur_drv = value & FD_DOR_SELMASK;
+
+    fdctrl->dor = value;
+}
+
+/* Tape drive register : 0x03 */
+static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->tdr;
+
+    FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
+{
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
+    /* Disk boot selection indicator */
+    fdctrl->tdr = value & FD_TDR_BOOTSEL;
+    /* Tape indicators: never allow */
+}
+
+/* Main status register : 0x04 (read) */
+static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->msr;
+
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    fdctrl->dor |= FD_DOR_nRESET;
+
+    /* Sparc mutation */
+    if (fdctrl->sun4m) {
+        retval |= FD_MSR_DIO;
+        fdctrl_reset_irq(fdctrl);
+    };
+
+    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Data select rate register : 0x04 (write) */
+static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
+{
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
+    /* Reset: autoclear */
+    if (value & FD_DSR_SWRESET) {
+        fdctrl->dor &= ~FD_DOR_nRESET;
+        fdctrl_reset(fdctrl, 1);
+        fdctrl->dor |= FD_DOR_nRESET;
+    }
+    if (value & FD_DSR_PWRDOWN) {
+        fdctrl_reset(fdctrl, 1);
+    }
+    fdctrl->dsr = value;
+}
+
+static int fdctrl_media_changed(FDrive *drv)
+{
+    int ret;
+
+    if (!drv->bs)
+        return 0;
+    ret = bdrv_media_changed(drv->bs);
+    if (ret) {
+        fd_revalidate(drv);
+    }
+    return ret;
+}
+
+/* Digital input register : 0x07 (read-only) */
+static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
+{
+    uint32_t retval = 0;
+
+    if (fdctrl_media_changed(drv0(fdctrl))
+     || fdctrl_media_changed(drv1(fdctrl))
+#if MAX_FD == 4
+     || fdctrl_media_changed(drv2(fdctrl))
+     || fdctrl_media_changed(drv3(fdctrl))
+#endif
+        )
+        retval |= FD_DIR_DSKCHG;
+    if (retval != 0) {
+        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
+    }
+
+    return retval;
+}
+
+/* FIFO state control */
+static void fdctrl_reset_fifo(FDCtrl *fdctrl)
+{
+    fdctrl->data_dir = FD_DIR_WRITE;
+    fdctrl->data_pos = 0;
+    fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
+}
+
+/* Set FIFO status for the host to read */
+static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, int do_irq)
+{
+    fdctrl->data_dir = FD_DIR_READ;
+    fdctrl->data_len = fifo_len;
+    fdctrl->data_pos = 0;
+    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
+    if (do_irq)
+        fdctrl_raise_irq(fdctrl, 0x00);
+}
+
+/* Set an error: unimplemented/unknown command */
+static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
+{
+    FLOPPY_ERROR("unimplemented command 0x%02x\n", fdctrl->fifo[0]);
+    fdctrl->fifo[0] = FD_SR0_INVCMD;
+    fdctrl_set_fifo(fdctrl, 1, 0);
+}
+
+/* Seek to next sector */
+static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
+{
+    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
+                   cur_drv->head, cur_drv->track, cur_drv->sect,
+                   fd_sector(cur_drv));
+    /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
+       error in fact */
+    if (cur_drv->sect >= cur_drv->last_sect ||
+        cur_drv->sect == fdctrl->eot) {
+        cur_drv->sect = 1;
+        if (FD_MULTI_TRACK(fdctrl->data_state)) {
+            if (cur_drv->head == 0 &&
+                (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
+                cur_drv->head = 1;
+            } else {
+                cur_drv->head = 0;
+                cur_drv->track++;
+                if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
+                    return 0;
+            }
+        } else {
+            cur_drv->track++;
+            return 0;
+        }
+        FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
+                       cur_drv->head, cur_drv->track,
+                       cur_drv->sect, fd_sector(cur_drv));
+    } else {
+        cur_drv->sect++;
+    }
+    return 1;
+}
+
+/* Callback for transfer end (stop or abort) */
+static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
+                                 uint8_t status1, uint8_t status2)
+{
+    FDrive *cur_drv;
+
+    cur_drv = get_cur_drv(fdctrl);
+    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
+                   status0, status1, status2,
+                   status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl));
+    fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+    fdctrl->fifo[1] = status1;
+    fdctrl->fifo[2] = status2;
+    fdctrl->fifo[3] = cur_drv->track;
+    fdctrl->fifo[4] = cur_drv->head;
+    fdctrl->fifo[5] = cur_drv->sect;
+    fdctrl->fifo[6] = FD_SECTOR_SC;
+    fdctrl->data_dir = FD_DIR_READ;
+    if (!(fdctrl->msr & FD_MSR_NONDMA)) {
+        DMA_release_DREQ(fdctrl->dma_chann);
+    }
+    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
+    fdctrl->msr &= ~FD_MSR_NONDMA;
+    fdctrl_set_fifo(fdctrl, 7, 1);
+}
+
+/* Prepare a data transfer (either DMA or FIFO) */
+static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+    uint8_t kh, kt, ks;
+    int did_seek = 0;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    kt = fdctrl->fifo[2];
+    kh = fdctrl->fifo[3];
+    ks = fdctrl->fifo[4];
+    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
+                   GET_CUR_DRV(fdctrl), kh, kt, ks,
+                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
+    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
+    case 2:
+        /* sect too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 3:
+        /* track too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 4:
+        /* No seek enabled */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 1:
+        did_seek = 1;
+        break;
+    default:
+        break;
+    }
+
+    /* Set the FIFO state */
+    fdctrl->data_dir = direction;
+    fdctrl->data_pos = 0;
+    fdctrl->msr |= FD_MSR_CMDBUSY;
+    if (fdctrl->fifo[0] & 0x80)
+        fdctrl->data_state |= FD_STATE_MULTI;
+    else
+        fdctrl->data_state &= ~FD_STATE_MULTI;
+    if (did_seek)
+        fdctrl->data_state |= FD_STATE_SEEK;
+    else
+        fdctrl->data_state &= ~FD_STATE_SEEK;
+    if (fdctrl->fifo[5] == 00) {
+        fdctrl->data_len = fdctrl->fifo[8];
+    } else {
+        int tmp;
+        fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
+        tmp = (fdctrl->fifo[6] - ks + 1);
+        if (fdctrl->fifo[0] & 0x80)
+            tmp += fdctrl->fifo[6];
+        fdctrl->data_len *= tmp;
+    }
+    fdctrl->eot = fdctrl->fifo[6];
+    if (fdctrl->dor & FD_DOR_DMAEN) {
+        int dma_mode;
+        /* DMA transfer are enabled. Check if DMA channel is well programmed */
+        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
+        dma_mode = (dma_mode >> 2) & 3;
+        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
+                       dma_mode, direction,
+                       (128 << fdctrl->fifo[5]) *
+                       (cur_drv->last_sect - ks + 1), fdctrl->data_len);
+        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
+              direction == FD_DIR_SCANH) && dma_mode == 0) ||
+            (direction == FD_DIR_WRITE && dma_mode == 2) ||
+            (direction == FD_DIR_READ && dma_mode == 1)) {
+            /* No access is allowed until DMA transfer has completed */
+            fdctrl->msr &= ~FD_MSR_RQM;
+            /* Now, we just have to wait for the DMA controller to
+             * recall us...
+             */
+            DMA_hold_DREQ(fdctrl->dma_chann);
+            DMA_schedule(fdctrl->dma_chann);
+            return;
+        } else {
+            FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
+        }
+    }
+    FLOPPY_DPRINTF("start non-DMA transfer\n");
+    fdctrl->msr |= FD_MSR_NONDMA;
+    if (direction != FD_DIR_WRITE)
+        fdctrl->msr |= FD_MSR_DIO;
+    /* IO based transfer: calculate len */
+    fdctrl_raise_irq(fdctrl, 0x00);
+
+    return;
+}
+
+/* Prepare a transfer of deleted data */
+static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
+{
+    FLOPPY_ERROR("fdctrl_start_transfer_del() unimplemented\n");
+
+    /* We don't handle deleted data,
+     * so we don't return *ANYTHING*
+     */
+    fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+}
+
+/* handlers for DMA transfers */
+static int fdctrl_transfer_handler (void *opaque, int nchan,
+                                    int dma_pos, int dma_len)
+{
+    FDCtrl *fdctrl;
+    FDrive *cur_drv;
+    int len, start_pos, rel_pos;
+    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
+
+    fdctrl = opaque;
+    if (fdctrl->msr & FD_MSR_RQM) {
+        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
+        return 0;
+    }
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
+        fdctrl->data_dir == FD_DIR_SCANH)
+        status2 = FD_SR2_SNS;
+    if (dma_len > fdctrl->data_len)
+        dma_len = fdctrl->data_len;
+    if (cur_drv->bs == NULL) {
+        if (fdctrl->data_dir == FD_DIR_WRITE)
+            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+        else
+            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        len = 0;
+        goto transfer_error;
+    }
+    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
+    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
+        len = dma_len - fdctrl->data_pos;
+        if (len + rel_pos > FD_SECTOR_LEN)
+            len = FD_SECTOR_LEN - rel_pos;
+        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
+                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
+                       fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
+                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
+                       fd_sector(cur_drv) * FD_SECTOR_LEN);
+        if (fdctrl->data_dir != FD_DIR_WRITE ||
+            len < FD_SECTOR_LEN || rel_pos != 0) {
+            /* READ & SCAN commands and realign to a sector for WRITE */
+            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
+                          fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
+                               fd_sector(cur_drv));
+                /* Sure, image size is too small... */
+                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+            }
+        }
+        switch (fdctrl->data_dir) {
+        case FD_DIR_READ:
+            /* READ commands */
+            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
+                              fdctrl->data_pos, len);
+            break;
+        case FD_DIR_WRITE:
+            /* WRITE commands */
+            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
+                             fdctrl->data_pos, len);
+            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
+                           fdctrl->fifo, 1) < 0) {
+                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+                fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+                goto transfer_error;
+            }
+            break;
+        default:
+            /* SCAN commands */
+            {
+                uint8_t tmpbuf[FD_SECTOR_LEN];
+                int ret;
+                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
+                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
+                if (ret == 0) {
+                    status2 = FD_SR2_SEH;
+                    goto end_transfer;
+                }
+                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
+                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
+                    status2 = 0x00;
+                    goto end_transfer;
+                }
+            }
+            break;
+        }
+        fdctrl->data_pos += len;
+        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
+        if (rel_pos == 0) {
+            /* Seek to next sector */
+            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
+                break;
+        }
+    }
+ end_transfer:
+    len = fdctrl->data_pos - start_pos;
+    FLOPPY_DPRINTF("end transfer %d %d %d\n",
+                   fdctrl->data_pos, len, fdctrl->data_len);
+    if (fdctrl->data_dir == FD_DIR_SCANE ||
+        fdctrl->data_dir == FD_DIR_SCANL ||
+        fdctrl->data_dir == FD_DIR_SCANH)
+        status2 = FD_SR2_SEH;
+    if (FD_DID_SEEK(fdctrl->data_state))
+        status0 |= FD_SR0_SEEK;
+    fdctrl->data_len -= len;
+    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
+ transfer_error:
+
+    return len;
+}
+
+/* Data register : 0x05 */
+static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
+{
+    FDrive *cur_drv;
+    uint32_t retval = 0;
+    int pos;
+
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
+        FLOPPY_ERROR("controller not ready for reading\n");
+        return 0;
+    }
+    pos = fdctrl->data_pos;
+    if (fdctrl->msr & FD_MSR_NONDMA) {
+        pos %= FD_SECTOR_LEN;
+        if (pos == 0) {
+            if (fdctrl->data_pos != 0)
+                if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+                    FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                                   fd_sector(cur_drv));
+                    return 0;
+                }
+            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("error getting sector %d\n",
+                               fd_sector(cur_drv));
+                /* Sure, image size is too small... */
+                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+            }
+        }
+    }
+    retval = fdctrl->fifo[pos];
+    if (++fdctrl->data_pos == fdctrl->data_len) {
+        fdctrl->data_pos = 0;
+        /* Switch from transfer mode to status mode
+         * then from status mode to command mode
+         */
+        if (fdctrl->msr & FD_MSR_NONDMA) {
+            fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
+        } else {
+            fdctrl_reset_fifo(fdctrl);
+            fdctrl_reset_irq(fdctrl);
+        }
+    }
+    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_format_sector(FDCtrl *fdctrl)
+{
+    FDrive *cur_drv;
+    uint8_t kh, kt, ks;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    kt = fdctrl->fifo[6];
+    kh = fdctrl->fifo[7];
+    ks = fdctrl->fifo[8];
+    FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
+                   GET_CUR_DRV(fdctrl), kh, kt, ks,
+                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
+    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
+    case 2:
+        /* sect too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 3:
+        /* track too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 4:
+        /* No seek enabled */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 1:
+        fdctrl->data_state |= FD_STATE_SEEK;
+        break;
+    default:
+        break;
+    }
+    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+    if (cur_drv->bs == NULL ||
+        bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+        FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+    } else {
+        if (cur_drv->sect == cur_drv->last_sect) {
+            fdctrl->data_state &= ~FD_STATE_FORMAT;
+            /* Last sector done */
+            if (FD_DID_SEEK(fdctrl->data_state))
+                fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
+            else
+                fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+        } else {
+            /* More to do */
+            fdctrl->data_pos = 0;
+            fdctrl->data_len = 4;
+        }
+    }
+}
+
+static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
+    fdctrl->fifo[0] = fdctrl->lock << 4;
+    fdctrl_set_fifo(fdctrl, 1, fdctrl->lock);
+}
+
+static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Drives position */
+    fdctrl->fifo[0] = drv0(fdctrl)->track;
+    fdctrl->fifo[1] = drv1(fdctrl)->track;
+#if MAX_FD == 4
+    fdctrl->fifo[2] = drv2(fdctrl)->track;
+    fdctrl->fifo[3] = drv3(fdctrl)->track;
+#else
+    fdctrl->fifo[2] = 0;
+    fdctrl->fifo[3] = 0;
+#endif
+    /* timers */
+    fdctrl->fifo[4] = fdctrl->timer0;
+    fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
+    fdctrl->fifo[6] = cur_drv->last_sect;
+    fdctrl->fifo[7] = (fdctrl->lock << 7) |
+        (cur_drv->perpendicular << 2);
+    fdctrl->fifo[8] = fdctrl->config;
+    fdctrl->fifo[9] = fdctrl->precomp_trk;
+    fdctrl_set_fifo(fdctrl, 10, 0);
+}
+
+static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
+{
+    /* Controller's version */
+    fdctrl->fifo[0] = fdctrl->version;
+    fdctrl_set_fifo(fdctrl, 1, 1);
+}
+
+static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->fifo[0] = 0x41; /* Stepping 1 */
+    fdctrl_set_fifo(fdctrl, 1, 0);
+}
+
+static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Drives position */
+    drv0(fdctrl)->track = fdctrl->fifo[3];
+    drv1(fdctrl)->track = fdctrl->fifo[4];
+#if MAX_FD == 4
+    drv2(fdctrl)->track = fdctrl->fifo[5];
+    drv3(fdctrl)->track = fdctrl->fifo[6];
+#endif
+    /* timers */
+    fdctrl->timer0 = fdctrl->fifo[7];
+    fdctrl->timer1 = fdctrl->fifo[8];
+    cur_drv->last_sect = fdctrl->fifo[9];
+    fdctrl->lock = fdctrl->fifo[10] >> 7;
+    cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
+    fdctrl->config = fdctrl->fifo[11];
+    fdctrl->precomp_trk = fdctrl->fifo[12];
+    fdctrl->pwrd = fdctrl->fifo[13];
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    fdctrl->fifo[0] = 0;
+    fdctrl->fifo[1] = 0;
+    /* Drives position */
+    fdctrl->fifo[2] = drv0(fdctrl)->track;
+    fdctrl->fifo[3] = drv1(fdctrl)->track;
+#if MAX_FD == 4
+    fdctrl->fifo[4] = drv2(fdctrl)->track;
+    fdctrl->fifo[5] = drv3(fdctrl)->track;
+#else
+    fdctrl->fifo[4] = 0;
+    fdctrl->fifo[5] = 0;
+#endif
+    /* timers */
+    fdctrl->fifo[6] = fdctrl->timer0;
+    fdctrl->fifo[7] = fdctrl->timer1;
+    fdctrl->fifo[8] = cur_drv->last_sect;
+    fdctrl->fifo[9] = (fdctrl->lock << 7) |
+        (cur_drv->perpendicular << 2);
+    fdctrl->fifo[10] = fdctrl->config;
+    fdctrl->fifo[11] = fdctrl->precomp_trk;
+    fdctrl->fifo[12] = fdctrl->pwrd;
+    fdctrl->fifo[13] = 0;
+    fdctrl->fifo[14] = 0;
+    fdctrl_set_fifo(fdctrl, 15, 1);
+}
+
+static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* XXX: should set main status register to busy */
+    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
+    qemu_mod_timer(fdctrl->result_timer,
+                   qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
+}
+
+static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl->data_state |= FD_STATE_FORMAT;
+    if (fdctrl->fifo[0] & 0x80)
+        fdctrl->data_state |= FD_STATE_MULTI;
+    else
+        fdctrl->data_state &= ~FD_STATE_MULTI;
+    fdctrl->data_state &= ~FD_STATE_SEEK;
+    cur_drv->bps =
+        fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
+#if 0
+    cur_drv->last_sect =
+        cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
+        fdctrl->fifo[3] / 2;
+#else
+    cur_drv->last_sect = fdctrl->fifo[3];
+#endif
+    /* TODO: implement format using DMA expected by the Bochs BIOS
+     * and Linux fdformat (read 3 bytes per sector via DMA and fill
+     * the sector with the specified fill byte
+     */
+    fdctrl->data_state &= ~FD_STATE_FORMAT;
+    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+}
+
+static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
+    fdctrl->timer1 = fdctrl->fifo[2] >> 1;
+    if (fdctrl->fifo[2] & 1)
+        fdctrl->dor &= ~FD_DOR_DMAEN;
+    else
+        fdctrl->dor |= FD_DOR_DMAEN;
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
+    /* 1 Byte status back */
+    fdctrl->fifo[0] = (cur_drv->ro << 6) |
+        (cur_drv->track == 0 ? 0x10 : 0x00) |
+        (cur_drv->head << 2) |
+        GET_CUR_DRV(fdctrl) |
+        0x28;
+    fdctrl_set_fifo(fdctrl, 1, 0);
+}
+
+static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fd_recalibrate(cur_drv);
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
+}
+
+static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if(fdctrl->reset_sensei > 0) {
+        fdctrl->fifo[0] =
+            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
+        fdctrl->reset_sensei--;
+    } else {
+        /* XXX: status0 handling is broken for read/write
+           commands, so we do this hack. It should be suppressed
+           ASAP */
+        fdctrl->fifo[0] =
+            FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+    }
+
+    fdctrl->fifo[1] = cur_drv->track;
+    fdctrl_set_fifo(fdctrl, 2, 0);
+    fdctrl_reset_irq(fdctrl);
+    fdctrl->status0 = FD_SR0_RDYCHG;
+}
+
+static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl_reset_fifo(fdctrl);
+    if (fdctrl->fifo[2] > cur_drv->max_track) {
+        fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
+    } else {
+        cur_drv->track = fdctrl->fifo[2];
+        /* Raise Interrupt */
+        fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
+    }
+}
+
+static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if (fdctrl->fifo[1] & 0x80)
+        cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->config = fdctrl->fifo[2];
+    fdctrl->precomp_trk =  fdctrl->fifo[3];
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->pwrd = fdctrl->fifo[1];
+    fdctrl->fifo[0] = fdctrl->fifo[1];
+    fdctrl_set_fifo(fdctrl, 1, 1);
+}
+
+static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
+{
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
+        /* Command parameters done */
+        if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
+            fdctrl->fifo[0] = fdctrl->fifo[1];
+            fdctrl->fifo[2] = 0;
+            fdctrl->fifo[3] = 0;
+            fdctrl_set_fifo(fdctrl, 4, 1);
+        } else {
+            fdctrl_reset_fifo(fdctrl);
+        }
+    } else if (fdctrl->data_len > 7) {
+        /* ERROR */
+        fdctrl->fifo[0] = 0x80 |
+            (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+        fdctrl_set_fifo(fdctrl, 1, 1);
+    }
+}
+
+static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
+        cur_drv->track = cur_drv->max_track - 1;
+    } else {
+        cur_drv->track += fdctrl->fifo[2];
+    }
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
+}
+
+static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->fifo[2] > cur_drv->track) {
+        cur_drv->track = 0;
+    } else {
+        cur_drv->track -= fdctrl->fifo[2];
+    }
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
+}
+
+static const struct {
+    uint8_t value;
+    uint8_t mask;
+    const char* name;
+    int parameters;
+    void (*handler)(FDCtrl *fdctrl, int direction);
+    int direction;
+} handlers[] = {
+    { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
+    { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
+    { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
+    { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
+    { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
+    { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
+    { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
+    { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
+    { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
+    { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
+    { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
+    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
+    { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
+    { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
+    { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
+    { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
+    { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
+    { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
+    { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
+    { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
+    { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
+    { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
+    { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
+    { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
+    { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
+    { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
+    { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
+    { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
+    { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
+    { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
+    { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
+    { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
+};
+/* Associate command to an index in the 'handlers' array */
+static uint8_t command_to_handler[256];
+
+static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
+{
+    FDrive *cur_drv;
+    int pos;
+
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
+        FLOPPY_ERROR("controller not ready for writing\n");
+        return;
+    }
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    /* Is it write command time ? */
+    if (fdctrl->msr & FD_MSR_NONDMA) {
+        /* FIFO data write */
+        pos = fdctrl->data_pos++;
+        pos %= FD_SECTOR_LEN;
+        fdctrl->fifo[pos] = value;
+        if (pos == FD_SECTOR_LEN - 1 ||
+            fdctrl->data_pos == fdctrl->data_len) {
+            cur_drv = get_cur_drv(fdctrl);
+            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+                return;
+            }
+            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+                FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                               fd_sector(cur_drv));
+                return;
+            }
+        }
+        /* Switch from transfer mode to status mode
+         * then from status mode to command mode
+         */
+        if (fdctrl->data_pos == fdctrl->data_len)
+            fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
+        return;
+    }
+    if (fdctrl->data_pos == 0) {
+        /* Command */
+        pos = command_to_handler[value & 0xff];
+        FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
+        fdctrl->data_len = handlers[pos].parameters + 1;
+    }
+
+    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
+    fdctrl->fifo[fdctrl->data_pos++] = value;
+    if (fdctrl->data_pos == fdctrl->data_len) {
+        /* We now have all parameters
+         * and will be able to treat the command
+         */
+        if (fdctrl->data_state & FD_STATE_FORMAT) {
+            fdctrl_format_sector(fdctrl);
+            return;
+        }
+
+        pos = command_to_handler[fdctrl->fifo[0] & 0xff];
+        FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
+        (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
+    }
+}
+
+static void fdctrl_result_timer(void *opaque)
+{
+    FDCtrl *fdctrl = opaque;
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Pretend we are spinning.
+     * This is needed for Coherent, which uses READ ID to check for
+     * sector interleaving.
+     */
+    if (cur_drv->last_sect != 0) {
+        cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
+    }
+    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+}
+
+/* Init functions */
+static int fdctrl_connect_drives(FDCtrl *fdctrl)
+{
+    unsigned int i;
+    FDrive *drive;
+
+    for (i = 0; i < MAX_FD; i++) {
+        drive = &fdctrl->drives[i];
+
+        if (drive->bs) {
+            if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+                error_report("fdc doesn't support drive option werror");
+                return -1;
+            }
+            if (bdrv_get_on_error(drive->bs, 1) != BLOCK_ERR_REPORT) {
+                error_report("fdc doesn't support drive option rerror");
+                return -1;
+            }
+        }
+
+        fd_init(drive);
+        fd_revalidate(drive);
+        if (drive->bs) {
+            bdrv_set_removable(drive->bs, 1);
+        }
+    }
+    return 0;
+}
+
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        target_phys_addr_t mmio_base, DriveInfo **fds)
+{
+    FDCtrl *fdctrl;
+    DeviceState *dev;
+    FDCtrlSysBus *sys;
+
+    dev = qdev_create(NULL, "sysbus-fdc");
+    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
+    fdctrl = &sys->state;
+    fdctrl->dma_chann = dma_chann; /* FIXME */
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(dev);
+    sysbus_connect_irq(&sys->busdev, 0, irq);
+    sysbus_mmio_map(&sys->busdev, 0, mmio_base);
+}
+
+void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc)
+{
+    DeviceState *dev;
+    FDCtrlSysBus *sys;
+
+    dev = qdev_create(NULL, "SUNW,fdtwo");
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
+    }
+    qdev_init_nofail(dev);
+    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
+    sysbus_connect_irq(&sys->busdev, 0, irq);
+    sysbus_mmio_map(&sys->busdev, 0, io_base);
+    *fdc_tc = qdev_get_gpio_in(dev, 0);
+}
+
+static int fdctrl_init_common(FDCtrl *fdctrl)
+{
+    int i, j;
+    static int command_tables_inited = 0;
+
+    /* Fill 'command_to_handler' lookup table */
+    if (!command_tables_inited) {
+        command_tables_inited = 1;
+        for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
+            for (j = 0; j < sizeof(command_to_handler); j++) {
+                if ((j & handlers[i].mask) == handlers[i].value) {
+                    command_to_handler[j] = i;
+                }
+            }
+        }
+    }
+
+    FLOPPY_DPRINTF("init controller\n");
+    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
+    fdctrl->fifo_size = 512;
+    fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
+                                          fdctrl_result_timer, fdctrl);
+
+    fdctrl->version = 0x90; /* Intel 82078 controller */
+    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
+    fdctrl->num_floppies = MAX_FD;
+
+    if (fdctrl->dma_chann != -1)
+        DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
+    return fdctrl_connect_drives(fdctrl);
+}
+
+static int isabus_fdc_init1(ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int iobase = 0x3f0;
+    int isairq = 6;
+    int dma_chann = 2;
+    int ret;
+
+    register_ioport_read(iobase + 0x01, 5, 1,
+                         &fdctrl_read_port, fdctrl);
+    register_ioport_read(iobase + 0x07, 1, 1,
+                         &fdctrl_read_port, fdctrl);
+    register_ioport_write(iobase + 0x01, 5, 1,
+                          &fdctrl_write_port, fdctrl);
+    register_ioport_write(iobase + 0x07, 1, 1,
+                          &fdctrl_write_port, fdctrl);
+    isa_init_ioport_range(dev, iobase, 6);
+    isa_init_ioport(dev, iobase + 7);
+
+    isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
+    fdctrl->dma_chann = dma_chann;
+
+    qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
+    ret = fdctrl_init_common(fdctrl);
+
+    add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy at 0");
+    add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy at 1");
+
+    return ret;
+}
+
+static int sysbus_fdc_init1(SysBusDevice *dev)
+{
+    FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
+    FDCtrl *fdctrl = &sys->state;
+    int io;
+    int ret;
+
+    io = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x08, io);
+    sysbus_init_irq(dev, &fdctrl->irq);
+    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
+    fdctrl->dma_chann = -1;
+
+    qdev_set_legacy_instance_id(&dev->qdev, io, 2);
+    ret = fdctrl_init_common(fdctrl);
+
+    return ret;
+}
+
+static int sun4m_fdc_init1(SysBusDevice *dev)
+{
+    FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
+    int io;
+
+    io = cpu_register_io_memory(fdctrl_mem_read_strict,
+                                fdctrl_mem_write_strict, fdctrl,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x08, io);
+    sysbus_init_irq(dev, &fdctrl->irq);
+    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
+
+    fdctrl->sun4m = 1;
+    qdev_set_legacy_instance_id(&dev->qdev, io, 2);
+    return fdctrl_init_common(fdctrl);
+}
+
+static const VMStateDescription vmstate_isa_fdc ={
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static ISADeviceInfo isa_fdc_info = {
+    .init = isabus_fdc_init1,
+    .qdev.name  = "isa-fdc",
+    .qdev.fw_name  = "fdc",
+    .qdev.size  = sizeof(FDCtrlISABus),
+    .qdev.no_user = 1,
+    .qdev.vmsd  = &vmstate_isa_fdc,
+    .qdev.reset = fdctrl_external_reset_isa,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
+        DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
+        DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
+        DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_sysbus_fdc ={
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo sysbus_fdc_info = {
+    .init = sysbus_fdc_init1,
+    .qdev.name  = "sysbus-fdc",
+    .qdev.size  = sizeof(FDCtrlSysBus),
+    .qdev.vmsd  = &vmstate_sysbus_fdc,
+    .qdev.reset = fdctrl_external_reset_sysbus,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
+        DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo sun4m_fdc_info = {
+    .init = sun4m_fdc_init1,
+    .qdev.name  = "SUNW,fdtwo",
+    .qdev.size  = sizeof(FDCtrlSysBus),
+    .qdev.vmsd  = &vmstate_sysbus_fdc,
+    .qdev.reset = fdctrl_external_reset_sysbus,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void fdc_register_devices(void)
+{
+    isa_qdev_register(&isa_fdc_info);
+    sysbus_register_withprop(&sysbus_fdc_info);
+    sysbus_register_withprop(&sun4m_fdc_info);
+}
+
+device_init(fdc_register_devices)
diff --git a/qemu-0.15.x/hw/fdc.h b/qemu-0.15.x/hw/fdc.h
new file mode 100644
index 0000000..09f73c6
--- /dev/null
+++ b/qemu-0.15.x/hw/fdc.h
@@ -0,0 +1,31 @@
+#ifndef HW_FDC_H
+#define HW_FDC_H
+
+#include "isa.h"
+#include "blockdev.h"
+
+/* fdc.c */
+#define MAX_FD 2
+
+static inline void fdctrl_init_isa(DriveInfo **fds)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-fdc");
+    if (!dev) {
+        return;
+    }
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(&dev->qdev);
+}
+
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        target_phys_addr_t mmio_base, DriveInfo **fds);
+void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc);
+#endif
diff --git a/qemu-0.15.x/hw/firmware_abi.h b/qemu-0.15.x/hw/firmware_abi.h
new file mode 100644
index 0000000..5e6e5d4
--- /dev/null
+++ b/qemu-0.15.x/hw/firmware_abi.h
@@ -0,0 +1,73 @@
+#ifndef FIRMWARE_ABI_H
+#define FIRMWARE_ABI_H
+
+/* OpenBIOS NVRAM partition */
+struct OpenBIOS_nvpart_v1 {
+    uint8_t signature;
+    uint8_t checksum;
+    uint16_t len; // BE, length divided by 16
+    char name[12];
+};
+
+#define OPENBIOS_PART_SYSTEM 0x70
+#define OPENBIOS_PART_FREE 0x7f
+
+static inline void
+OpenBIOS_finish_partition(struct OpenBIOS_nvpart_v1 *header, uint32_t size)
+{
+    unsigned int i, sum;
+    uint8_t *tmpptr;
+
+    // Length divided by 16
+    header->len = cpu_to_be16(size >> 4);
+
+    // Checksum
+    tmpptr = (uint8_t *)header;
+    sum = *tmpptr;
+    for (i = 0; i < 14; i++) {
+        sum += tmpptr[2 + i];
+        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+    }
+    header->checksum = sum & 0xff;
+}
+
+static inline uint32_t
+OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const char *str)
+{
+    uint32_t len;
+
+    len = strlen(str) + 1;
+    memcpy(&nvram[addr], str, len);
+
+    return addr + len;
+}
+
+/* Sun IDPROM structure at the end of NVRAM */
+/* from http://www.squirrel.com/squirrel/sun-nvram-hostid.faq.html */
+struct Sun_nvram {
+    uint8_t type;       /* always 01 */
+    uint8_t machine_id; /* first byte of host id (machine type) */
+    uint8_t macaddr[6]; /* 6 byte ethernet address (first 3 bytes 08, 00, 20) */
+    uint8_t date[4];    /* date of manufacture */
+    uint8_t hostid[3];  /* remaining 3 bytes of host id (serial number) */
+    uint8_t checksum;   /* bitwise xor of previous bytes */
+};
+
+static inline void
+Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id)
+{
+    uint8_t tmp, *tmpptr;
+    unsigned int i;
+
+    header->type = 1;
+    header->machine_id = machine_id & 0xff;
+    memcpy(&header->macaddr, macaddr, 6);
+    /* Calculate checksum */
+    tmp = 0;
+    tmpptr = (uint8_t *)header;
+    for (i = 0; i < 15; i++)
+        tmp ^= tmpptr[i];
+
+    header->checksum = tmp;
+}
+#endif /* FIRMWARE_ABI_H */
diff --git a/qemu-0.15.x/hw/flash.h b/qemu-0.15.x/hw/flash.h
new file mode 100644
index 0000000..c22e1a9
--- /dev/null
+++ b/qemu-0.15.x/hw/flash.h
@@ -0,0 +1,54 @@
+/* NOR flash devices */
+typedef struct pflash_t pflash_t;
+
+/* pflash_cfi01.c */
+pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs,
+                                uint32_t sector_len, int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3, int be);
+
+/* pflash_cfi02.c */
+pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int nb_mappings, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3,
+                                uint16_t unlock_addr0, uint16_t unlock_addr1,
+                                int be);
+
+/* nand.c */
+typedef struct NANDFlashState NANDFlashState;
+NANDFlashState *nand_init(int manf_id, int chip_id);
+void nand_done(NANDFlashState *s);
+void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd);
+void nand_getpins(NANDFlashState *s, int *rb);
+void nand_setio(NANDFlashState *s, uint8_t value);
+uint8_t nand_getio(NANDFlashState *s);
+
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
+#define NAND_MFR_RENESAS	0x07
+#define NAND_MFR_STMICRO	0x20
+#define NAND_MFR_HYNIX		0xad
+#define NAND_MFR_MICRON		0x2c
+
+/* onenand.c */
+void onenand_base_update(void *opaque, target_phys_addr_t new);
+void onenand_base_unmap(void *opaque);
+void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
+void *onenand_raw_otp(void *opaque);
+
+/* ecc.c */
+typedef struct {
+    uint8_t cp;		/* Column parity */
+    uint16_t lp[2];	/* Line parity */
+    uint16_t count;
+} ECCState;
+
+uint8_t ecc_digest(ECCState *s, uint8_t sample);
+void ecc_reset(ECCState *s);
+extern VMStateDescription vmstate_ecc_state;
diff --git a/qemu-0.15.x/hw/fmopl.c b/qemu-0.15.x/hw/fmopl.c
new file mode 100644
index 0000000..d8a0f36
--- /dev/null
+++ b/qemu-0.15.x/hw/fmopl.c
@@ -0,0 +1,1395 @@
+/*
+**
+** File: fmopl.c -- software implementation of FM sound generator
+**
+** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
+**
+** Version 0.37a
+**
+*/
+
+/*
+	preliminary :
+	Problem :
+	note:
+*/
+
+/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define INLINE		static inline
+#define HAS_YM3812	1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+//#include "driver.h"		/* use M.A.M.E. */
+#include "fmopl.h"
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/* -------------------- for debug --------------------- */
+/* #define OPL_OUTPUT_LOG */
+#ifdef OPL_OUTPUT_LOG
+static FILE *opl_dbg_fp = NULL;
+static FM_OPL *opl_dbg_opl[16];
+static int opl_dbg_maxchip,opl_dbg_chip;
+#endif
+
+/* -------------------- preliminary define section --------------------- */
+/* attack/decay rate time rate */
+#define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */
+#define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */
+
+#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
+
+#define FREQ_BITS 24			/* frequency turn          */
+
+/* counter bits = 20 , octerve 7 */
+#define FREQ_RATE   (1<<(FREQ_BITS-20))
+#define TL_BITS    (FREQ_BITS+2)
+
+/* final output shift , limit minimum and maximum */
+#define OPL_OUTSB   (TL_BITS+3-16)		/* OPL output final shift 16bit */
+#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
+#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
+
+/* -------------------- quality selection --------------------- */
+
+/* sinwave entries */
+/* used static memory = SIN_ENT * 4 (byte) */
+#define SIN_ENT 2048
+
+/* output level entries (envelope,sinwave) */
+/* envelope counter lower bits */
+#define ENV_BITS 16
+/* envelope output entries */
+#define EG_ENT   4096
+/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
+/* used static  memory = EG_ENT*4 (byte)                     */
+
+#define EG_OFF   ((2*EG_ENT)<<ENV_BITS)  /* OFF          */
+#define EG_DED   EG_OFF
+#define EG_DST   (EG_ENT<<ENV_BITS)      /* DECAY  START */
+#define EG_AED   EG_DST
+#define EG_AST   0                       /* ATTACK START */
+
+#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */
+
+/* LFO table entries */
+#define VIB_ENT 512
+#define VIB_SHIFT (32-9)
+#define AMS_ENT 512
+#define AMS_SHIFT (32-9)
+
+#define VIB_RATE 256
+
+/* -------------------- local defines , macros --------------------- */
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* envelope phase */
+#define ENV_MOD_RR  0x00
+#define ENV_MOD_DR  0x01
+#define ENV_MOD_AR  0x02
+
+/* -------------------- tables --------------------- */
+static const int slot_array[32]=
+{
+	 0, 2, 4, 1, 3, 5,-1,-1,
+	 6, 8,10, 7, 9,11,-1,-1,
+	12,14,16,13,15,17,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1
+};
+
+/* key scale level */
+/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
+#define DV (EG_STEP/2)
+static const UINT32 KSL_TABLE[8*16]=
+{
+	/* OCT 0 */
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	/* OCT 1 */
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+	 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+	/* OCT 2 */
+	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+	 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+	 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+	 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+	/* OCT 3 */
+	 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+	 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+	 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+	 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+	/* OCT 4 */
+	 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+	 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+	 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+	10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+	/* OCT 5 */
+	 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+	 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+	12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+	13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+	/* OCT 6 */
+	 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+	12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+	15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+	16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+	/* OCT 7 */
+	 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+	15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+	18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+	19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain lebel table (3db per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
+static const INT32 SL_TABLE[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
+/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
+/* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
+/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
+static INT32 *TL_TABLE;
+
+/* pointers to TL_TABLE with sinwave output offset */
+static INT32 **SIN_TABLE;
+
+/* LFO table */
+static INT32 *AMS_TABLE;
+static INT32 *VIB_TABLE;
+
+/* envelope output curve table */
+/* attack + decay + OFF */
+static INT32 ENV_CURVE[2*EG_ENT+1];
+
+/* multiple table */
+#define ML 2
+static const UINT32 MUL_TABLE[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
+   0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+   8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* dummy attack / decay rate ( when rate == 0 ) */
+static INT32 RATE_0[16]=
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/* -------------------- static state --------------------- */
+
+/* lock level of common table */
+static int num_lock = 0;
+
+/* work table */
+static void *cur_chip = NULL;	/* current chip point */
+/* currenct chip state */
+/* static OPLSAMPLE  *bufL,*bufR; */
+static OPL_CH *S_CH;
+static OPL_CH *E_CH;
+OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
+
+static INT32 outd[1];
+static INT32 ams;
+static INT32 vib;
+INT32  *ams_table;
+INT32  *vib_table;
+static INT32 amsIncr;
+static INT32 vibIncr;
+static INT32 feedback2;		/* connect for SLOT 2 */
+
+/* log output level */
+#define LOG_ERR  3      /* ERROR       */
+#define LOG_WAR  2      /* WARNING     */
+#define LOG_INF  1      /* INFORMATION */
+
+//#define LOG_LEVEL LOG_INF
+#define LOG_LEVEL	LOG_ERR
+
+//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
+#define LOG(n,x)
+
+/* --------------------- subroutines  --------------------- */
+
+INLINE int Limit( int val, int max, int min ) {
+	if ( val > max )
+		val = max;
+	else if ( val < min )
+		val = min;
+
+	return val;
+}
+
+/* status set and IRQ handling */
+INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
+{
+	/* set status flag */
+	OPL->status |= flag;
+	if(!(OPL->status & 0x80))
+	{
+		if(OPL->status & OPL->statusmask)
+		{	/* IRQ on */
+			OPL->status |= 0x80;
+			/* callback user interrupt handler (IRQ is OFF to ON) */
+			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
+		}
+	}
+}
+
+/* status reset and IRQ handling */
+INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
+{
+	/* reset status flag */
+	OPL->status &=~flag;
+	if((OPL->status & 0x80))
+	{
+		if (!(OPL->status & OPL->statusmask) )
+		{
+			OPL->status &= 0x7f;
+			/* callback user interrupt handler (IRQ is ON to OFF) */
+			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
+		}
+	}
+}
+
+/* IRQ mask set */
+INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
+{
+	OPL->statusmask = flag;
+	/* IRQ handling check */
+	OPL_STATUS_SET(OPL,0);
+	OPL_STATUS_RESET(OPL,0);
+}
+
+/* ----- key on  ----- */
+INLINE void OPL_KEYON(OPL_SLOT *SLOT)
+{
+	/* sin wave restart */
+	SLOT->Cnt = 0;
+	/* set attack */
+	SLOT->evm = ENV_MOD_AR;
+	SLOT->evs = SLOT->evsa;
+	SLOT->evc = EG_AST;
+	SLOT->eve = EG_AED;
+}
+/* ----- key off ----- */
+INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
+{
+	if( SLOT->evm > ENV_MOD_RR)
+	{
+		/* set envelope counter from envleope output */
+		SLOT->evm = ENV_MOD_RR;
+		if( !(SLOT->evc&EG_DST) )
+			//SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
+			SLOT->evc = EG_DST;
+		SLOT->eve = EG_DED;
+		SLOT->evs = SLOT->evsr;
+	}
+}
+
+/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
+/* return : envelope output */
+INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+{
+	/* calcrate envelope generator */
+	if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
+	{
+		switch( SLOT->evm ){
+		case ENV_MOD_AR: /* ATTACK -> DECAY1 */
+			/* next DR */
+			SLOT->evm = ENV_MOD_DR;
+			SLOT->evc = EG_DST;
+			SLOT->eve = SLOT->SL;
+			SLOT->evs = SLOT->evsd;
+			break;
+		case ENV_MOD_DR: /* DECAY -> SL or RR */
+			SLOT->evc = SLOT->SL;
+			SLOT->eve = EG_DED;
+			if(SLOT->eg_typ)
+			{
+				SLOT->evs = 0;
+			}
+			else
+			{
+				SLOT->evm = ENV_MOD_RR;
+				SLOT->evs = SLOT->evsr;
+			}
+			break;
+		case ENV_MOD_RR: /* RR -> OFF */
+			SLOT->evc = EG_OFF;
+			SLOT->eve = EG_OFF+1;
+			SLOT->evs = 0;
+			break;
+		}
+	}
+	/* calcrate envelope */
+	return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
+}
+
+/* set algorythm connection */
+static void set_algorythm( OPL_CH *CH)
+{
+	INT32 *carrier = &outd[0];
+	CH->connect1 = CH->CON ? carrier : &feedback2;
+	CH->connect2 = carrier;
+}
+
+/* ---------- frequency counter for operater update ---------- */
+INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
+{
+	int ksr;
+
+	/* frequency step counter */
+	SLOT->Incr = CH->fc * SLOT->mul;
+	ksr = CH->kcode >> SLOT->KSR;
+
+	if( SLOT->ksr != ksr )
+	{
+		SLOT->ksr = ksr;
+		/* attack , decay rate recalcration */
+		SLOT->evsa = SLOT->AR[ksr];
+		SLOT->evsd = SLOT->DR[ksr];
+		SLOT->evsr = SLOT->RR[ksr];
+	}
+	SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(FM_OPL *OPL,int slot,int v)
+{
+	OPL_CH   *CH   = &OPL->P_CH[slot/2];
+	OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+	SLOT->mul    = MUL_TABLE[v&0x0f];
+	SLOT->KSR    = (v&0x10) ? 0 : 2;
+	SLOT->eg_typ = (v&0x20)>>5;
+	SLOT->vib    = (v&0x40);
+	SLOT->ams    = (v&0x80);
+	CALC_FCSLOT(CH,SLOT);
+}
+
+/* set ksl & tl */
+INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
+{
+	OPL_CH   *CH   = &OPL->P_CH[slot/2];
+	OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+	int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
+
+	SLOT->ksl = ksl ? 3-ksl : 31;
+	SLOT->TL  = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
+
+	if( !(OPL->mode&0x80) )
+	{	/* not CSM latch total level */
+		SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+	}
+}
+
+/* set attack rate & decay rate  */
+INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
+{
+	OPL_CH   *CH   = &OPL->P_CH[slot/2];
+	OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+	int ar = v>>4;
+	int dr = v&0x0f;
+
+	SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
+	SLOT->evsa = SLOT->AR[SLOT->ksr];
+	if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
+
+	SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
+	SLOT->evsd = SLOT->DR[SLOT->ksr];
+	if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
+{
+	OPL_CH   *CH   = &OPL->P_CH[slot/2];
+	OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+	int sl = v>>4;
+	int rr = v & 0x0f;
+
+	SLOT->SL = SL_TABLE[sl];
+	if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
+	SLOT->RR = &OPL->DR_TABLE[rr<<2];
+	SLOT->evsr = SLOT->RR[SLOT->ksr];
+	if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
+}
+
+/* operator output calcrator */
+#define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
+/* ---------- calcrate one of channel ---------- */
+INLINE void OPL_CALC_CH( OPL_CH *CH )
+{
+	UINT32 env_out;
+	OPL_SLOT *SLOT;
+
+	feedback2 = 0;
+	/* SLOT 1 */
+	SLOT = &CH->SLOT[SLOT1];
+	env_out=OPL_CALC_SLOT(SLOT);
+	if( env_out < EG_ENT-1 )
+	{
+		/* PG */
+		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+		else          SLOT->Cnt += SLOT->Incr;
+		/* connectoion */
+		if(CH->FB)
+		{
+			int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
+			CH->op1_out[1] = CH->op1_out[0];
+			*CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
+		}
+		else
+		{
+			*CH->connect1 += OP_OUT(SLOT,env_out,0);
+		}
+	}else
+	{
+		CH->op1_out[1] = CH->op1_out[0];
+		CH->op1_out[0] = 0;
+	}
+	/* SLOT 2 */
+	SLOT = &CH->SLOT[SLOT2];
+	env_out=OPL_CALC_SLOT(SLOT);
+	if( env_out < EG_ENT-1 )
+	{
+		/* PG */
+		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+		else          SLOT->Cnt += SLOT->Incr;
+		/* connectoion */
+		outd[0] += OP_OUT(SLOT,env_out, feedback2);
+	}
+}
+
+/* ---------- calcrate rythm block ---------- */
+#define WHITE_NOISE_db 6.0
+INLINE void OPL_CALC_RH( OPL_CH *CH )
+{
+	UINT32 env_tam,env_sd,env_top,env_hh;
+	int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
+	INT32 tone8;
+
+	OPL_SLOT *SLOT;
+	int env_out;
+
+	/* BD : same as FM serial mode and output level is large */
+	feedback2 = 0;
+	/* SLOT 1 */
+	SLOT = &CH[6].SLOT[SLOT1];
+	env_out=OPL_CALC_SLOT(SLOT);
+	if( env_out < EG_ENT-1 )
+	{
+		/* PG */
+		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+		else          SLOT->Cnt += SLOT->Incr;
+		/* connectoion */
+		if(CH[6].FB)
+		{
+			int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
+			CH[6].op1_out[1] = CH[6].op1_out[0];
+			feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
+		}
+		else
+		{
+			feedback2 = OP_OUT(SLOT,env_out,0);
+		}
+	}else
+	{
+		feedback2 = 0;
+		CH[6].op1_out[1] = CH[6].op1_out[0];
+		CH[6].op1_out[0] = 0;
+	}
+	/* SLOT 2 */
+	SLOT = &CH[6].SLOT[SLOT2];
+	env_out=OPL_CALC_SLOT(SLOT);
+	if( env_out < EG_ENT-1 )
+	{
+		/* PG */
+		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+		else          SLOT->Cnt += SLOT->Incr;
+		/* connectoion */
+		outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
+	}
+
+	// SD  (17) = mul14[fnum7] + white noise
+	// TAM (15) = mul15[fnum8]
+	// TOP (18) = fnum6(mul18[fnum8]+whitenoise)
+	// HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
+	env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
+	env_tam=OPL_CALC_SLOT(SLOT8_1);
+	env_top=OPL_CALC_SLOT(SLOT8_2);
+	env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
+
+	/* PG */
+	if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
+	else             SLOT7_1->Cnt += 2*SLOT7_1->Incr;
+	if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
+	else             SLOT7_2->Cnt += (CH[7].fc*8);
+	if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
+	else             SLOT8_1->Cnt += SLOT8_1->Incr;
+	if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
+	else             SLOT8_2->Cnt += (CH[8].fc*48);
+
+	tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
+
+	/* SD */
+	if( env_sd < EG_ENT-1 )
+		outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
+	/* TAM */
+	if( env_tam < EG_ENT-1 )
+		outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
+	/* TOP-CY */
+	if( env_top < EG_ENT-1 )
+		outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
+	/* HH */
+	if( env_hh  < EG_ENT-1 )
+		outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
+}
+
+/* ----------- initialize time tabls ----------- */
+static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
+{
+	int i;
+	double rate;
+
+	/* make attack rate & decay rate tables */
+	for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
+	for (i = 4;i <= 60;i++){
+		rate  = OPL->freqbase;						/* frequency rate */
+		if( i < 60 ) rate *= 1.0+(i&3)*0.25;		/* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
+		rate *= 1<<((i>>2)-1);						/* b2-5 : shift bit */
+		rate *= (double)(EG_ENT<<ENV_BITS);
+		OPL->AR_TABLE[i] = rate / ARRATE;
+		OPL->DR_TABLE[i] = rate / DRRATE;
+	}
+	for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++)
+	{
+		OPL->AR_TABLE[i] = EG_AED-1;
+		OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
+	}
+#if 0
+	for (i = 0;i < 64 ;i++){	/* make for overflow area */
+		LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i,
+			((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
+			((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
+	}
+#endif
+}
+
+/* ---------- generic table initialize ---------- */
+static int OPLOpenTable( void )
+{
+	int s,t;
+	double rate;
+	int i,j;
+	double pom;
+
+	/* allocate dynamic tables */
+	if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+		return 0;
+	if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+	{
+		free(TL_TABLE);
+		return 0;
+	}
+	if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+	{
+		free(TL_TABLE);
+		free(SIN_TABLE);
+		return 0;
+	}
+	if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+	{
+		free(TL_TABLE);
+		free(SIN_TABLE);
+		free(AMS_TABLE);
+		return 0;
+	}
+	/* make total level table */
+	for (t = 0;t < EG_ENT-1 ;t++){
+		rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20);	/* dB -> voltage */
+		TL_TABLE[       t] =  (int)rate;
+		TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
+/*		LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
+	}
+	/* fill volume off area */
+	for ( t = EG_ENT-1; t < TL_MAX ;t++){
+		TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
+	}
+
+	/* make sinwave table (total level offet) */
+	/* degree 0 = degree 180                   = off */
+	SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];
+	for (s = 1;s <= SIN_ENT/4;s++){
+		pom = sin(2*PI*s/SIN_ENT); /* sin     */
+		pom = 20*log10(1/pom);	   /* decibel */
+		j = pom / EG_STEP;         /* TL_TABLE steps */
+
+        /* degree 0   -  90    , degree 180 -  90 : plus section */
+		SIN_TABLE[          s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
+        /* degree 180 - 270    , degree 360 - 270 : minus section */
+		SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT  -s] = &TL_TABLE[TL_MAX+j];
+/*		LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
+	}
+	for (s = 0;s < SIN_ENT;s++)
+	{
+		SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
+		SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
+		SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
+	}
+
+	/* envelope counter -> envelope output table */
+	for (i=0; i<EG_ENT; i++)
+	{
+		/* ATTACK curve */
+		pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
+		/* if( pom >= EG_ENT ) pom = EG_ENT-1; */
+		ENV_CURVE[i] = (int)pom;
+		/* DECAY ,RELEASE curve */
+		ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
+	}
+	/* off */
+	ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
+	/* make LFO ams table */
+	for (i=0; i<AMS_ENT; i++)
+	{
+		pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
+		AMS_TABLE[i]         = (1.0/EG_STEP)*pom; /* 1dB   */
+		AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
+	}
+	/* make LFO vibrate table */
+	for (i=0; i<VIB_ENT; i++)
+	{
+		/* 100cent = 1seminote = 6% ?? */
+		pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
+		VIB_TABLE[i]         = VIB_RATE + (pom*0.07); /* +- 7cent */
+		VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
+		/* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
+	}
+	return 1;
+}
+
+
+static void OPLCloseTable( void )
+{
+	free(TL_TABLE);
+	free(SIN_TABLE);
+	free(AMS_TABLE);
+	free(VIB_TABLE);
+}
+
+/* CSM Key Controll */
+INLINE void CSMKeyControll(OPL_CH *CH)
+{
+	OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
+	OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
+	/* all key off */
+	OPL_KEYOFF(slot1);
+	OPL_KEYOFF(slot2);
+	/* total level latch */
+	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+	/* key on */
+	CH->op1_out[0] = CH->op1_out[1] = 0;
+	OPL_KEYON(slot1);
+	OPL_KEYON(slot2);
+}
+
+/* ---------- opl initialize ---------- */
+static void OPL_initalize(FM_OPL *OPL)
+{
+	int fn;
+
+	/* frequency base */
+	OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;
+	/* Timer base time */
+	OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
+	/* make time tables */
+	init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
+	/* make fnumber -> increment counter table */
+	for( fn=0 ; fn < 1024 ; fn++ )
+	{
+		OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
+	}
+	/* LFO freq.table */
+	OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
+	OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
+}
+
+/* ---------- write a OPL registers ---------- */
+static void OPLWriteReg(FM_OPL *OPL, int r, int v)
+{
+	OPL_CH *CH;
+	int slot;
+	int block_fnum;
+
+	switch(r&0xe0)
+	{
+	case 0x00: /* 00-1f:controll */
+		switch(r&0x1f)
+		{
+		case 0x01:
+			/* wave selector enable */
+			if(OPL->type&OPL_TYPE_WAVESEL)
+			{
+				OPL->wavesel = v&0x20;
+				if(!OPL->wavesel)
+				{
+					/* preset compatible mode */
+					int c;
+					for(c=0;c<OPL->max_ch;c++)
+					{
+						OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+						OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
+					}
+				}
+			}
+			return;
+		case 0x02:	/* Timer 1 */
+			OPL->T[0] = (256-v)*4;
+			break;
+		case 0x03:	/* Timer 2 */
+			OPL->T[1] = (256-v)*16;
+			return;
+		case 0x04:	/* IRQ clear / mask and Timer enable */
+			if(v&0x80)
+			{	/* IRQ flag clear */
+				OPL_STATUS_RESET(OPL,0x7f);
+			}
+			else
+			{	/* set IRQ mask ,timer enable*/
+				UINT8 st1 = v&1;
+				UINT8 st2 = (v>>1)&1;
+				/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
+				OPL_STATUS_RESET(OPL,v&0x78);
+				OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
+				/* timer 2 */
+				if(OPL->st[1] != st2)
+				{
+					double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
+					OPL->st[1] = st2;
+					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
+				}
+				/* timer 1 */
+				if(OPL->st[0] != st1)
+				{
+					double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
+					OPL->st[0] = st1;
+					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
+				}
+			}
+			return;
+#if BUILD_Y8950
+		case 0x06:		/* Key Board OUT */
+			if(OPL->type&OPL_TYPE_KEYBOARD)
+			{
+				if(OPL->keyboardhandler_w)
+					OPL->keyboardhandler_w(OPL->keyboard_param,v);
+				else
+					LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
+			}
+			return;
+		case 0x07:	/* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
+			if(OPL->type&OPL_TYPE_ADPCM)
+				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+			return;
+		case 0x08:	/* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
+			OPL->mode = v;
+			v&=0x1f;	/* for DELTA-T unit */
+		case 0x09:		/* START ADD */
+		case 0x0a:
+		case 0x0b:		/* STOP ADD  */
+		case 0x0c:
+		case 0x0d:		/* PRESCALE   */
+		case 0x0e:
+		case 0x0f:		/* ADPCM data */
+		case 0x10: 		/* DELTA-N    */
+		case 0x11: 		/* DELTA-N    */
+		case 0x12: 		/* EG-CTRL    */
+			if(OPL->type&OPL_TYPE_ADPCM)
+				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+			return;
+#if 0
+		case 0x15:		/* DAC data    */
+		case 0x16:
+		case 0x17:		/* SHIFT    */
+			return;
+		case 0x18:		/* I/O CTRL (Direction) */
+			if(OPL->type&OPL_TYPE_IO)
+				OPL->portDirection = v&0x0f;
+			return;
+		case 0x19:		/* I/O DATA */
+			if(OPL->type&OPL_TYPE_IO)
+			{
+				OPL->portLatch = v;
+				if(OPL->porthandler_w)
+					OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
+			}
+			return;
+		case 0x1a:		/* PCM data */
+			return;
+#endif
+#endif
+		}
+		break;
+	case 0x20:	/* am,vib,ksr,eg type,mul */
+		slot = slot_array[r&0x1f];
+		if(slot == -1) return;
+		set_mul(OPL,slot,v);
+		return;
+	case 0x40:
+		slot = slot_array[r&0x1f];
+		if(slot == -1) return;
+		set_ksl_tl(OPL,slot,v);
+		return;
+	case 0x60:
+		slot = slot_array[r&0x1f];
+		if(slot == -1) return;
+		set_ar_dr(OPL,slot,v);
+		return;
+	case 0x80:
+		slot = slot_array[r&0x1f];
+		if(slot == -1) return;
+		set_sl_rr(OPL,slot,v);
+		return;
+	case 0xa0:
+		switch(r)
+		{
+		case 0xbd:
+			/* amsep,vibdep,r,bd,sd,tom,tc,hh */
+			{
+			UINT8 rkey = OPL->rythm^v;
+			OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
+			OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
+			OPL->rythm  = v&0x3f;
+			if(OPL->rythm&0x20)
+			{
+#if 0
+				usrintf_showmessage("OPL Rythm mode select");
+#endif
+				/* BD key on/off */
+				if(rkey&0x10)
+				{
+					if(v&0x10)
+					{
+						OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
+						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
+						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
+					}
+					else
+					{
+						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
+						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
+					}
+				}
+				/* SD key on/off */
+				if(rkey&0x08)
+				{
+					if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
+					else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
+				}/* TAM key on/off */
+				if(rkey&0x04)
+				{
+					if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
+					else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
+				}
+				/* TOP-CY key on/off */
+				if(rkey&0x02)
+				{
+					if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
+					else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
+				}
+				/* HH key on/off */
+				if(rkey&0x01)
+				{
+					if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
+					else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
+				}
+			}
+			}
+			return;
+		}
+		/* keyon,block,fnum */
+		if( (r&0x0f) > 8) return;
+		CH = &OPL->P_CH[r&0x0f];
+		if(!(r&0x10))
+		{	/* a0-a8 */
+			block_fnum  = (CH->block_fnum&0x1f00) | v;
+		}
+		else
+		{	/* b0-b8 */
+			int keyon = (v>>5)&1;
+			block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
+			if(CH->keyon != keyon)
+			{
+				if( (CH->keyon=keyon) )
+				{
+					CH->op1_out[0] = CH->op1_out[1] = 0;
+					OPL_KEYON(&CH->SLOT[SLOT1]);
+					OPL_KEYON(&CH->SLOT[SLOT2]);
+				}
+				else
+				{
+					OPL_KEYOFF(&CH->SLOT[SLOT1]);
+					OPL_KEYOFF(&CH->SLOT[SLOT2]);
+				}
+			}
+		}
+		/* update */
+		if(CH->block_fnum != block_fnum)
+		{
+			int blockRv = 7-(block_fnum>>10);
+			int fnum   = block_fnum&0x3ff;
+			CH->block_fnum = block_fnum;
+
+			CH->ksl_base = KSL_TABLE[block_fnum>>6];
+			CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
+			CH->kcode = CH->block_fnum>>9;
+			if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
+			CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+			CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+		}
+		return;
+	case 0xc0:
+		/* FB,C */
+		if( (r&0x0f) > 8) return;
+		CH = &OPL->P_CH[r&0x0f];
+		{
+		int feedback = (v>>1)&7;
+		CH->FB   = feedback ? (8+1) - feedback : 0;
+		CH->CON = v&1;
+		set_algorythm(CH);
+		}
+		return;
+	case 0xe0: /* wave type */
+		slot = slot_array[r&0x1f];
+		if(slot == -1) return;
+		CH = &OPL->P_CH[slot/2];
+		if(OPL->wavesel)
+		{
+			/* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
+			CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
+		}
+		return;
+	}
+}
+
+/* lock/unlock for common table */
+static int OPL_LockTable(void)
+{
+	num_lock++;
+	if(num_lock>1) return 0;
+	/* first time */
+	cur_chip = NULL;
+	/* allocate total level table (128kb space) */
+	if( !OPLOpenTable() )
+	{
+		num_lock--;
+		return -1;
+	}
+	return 0;
+}
+
+static void OPL_UnLockTable(void)
+{
+	if(num_lock) num_lock--;
+	if(num_lock) return;
+	/* last time */
+	cur_chip = NULL;
+	OPLCloseTable();
+}
+
+#if (BUILD_YM3812 || BUILD_YM3526)
+/*******************************************************************************/
+/*		YM3812 local section                                                   */
+/*******************************************************************************/
+
+/* ---------- update one of chip ----------- */
+void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+{
+    int i;
+	int data;
+	OPLSAMPLE *buf = buffer;
+	UINT32 amsCnt  = OPL->amsCnt;
+	UINT32 vibCnt  = OPL->vibCnt;
+	UINT8 rythm = OPL->rythm&0x20;
+	OPL_CH *CH,*R_CH;
+
+	if( (void *)OPL != cur_chip ){
+		cur_chip = (void *)OPL;
+		/* channel pointers */
+		S_CH = OPL->P_CH;
+		E_CH = &S_CH[9];
+		/* rythm slot */
+		SLOT7_1 = &S_CH[7].SLOT[SLOT1];
+		SLOT7_2 = &S_CH[7].SLOT[SLOT2];
+		SLOT8_1 = &S_CH[8].SLOT[SLOT1];
+		SLOT8_2 = &S_CH[8].SLOT[SLOT2];
+		/* LFO state */
+		amsIncr = OPL->amsIncr;
+		vibIncr = OPL->vibIncr;
+		ams_table = OPL->ams_table;
+		vib_table = OPL->vib_table;
+	}
+	R_CH = rythm ? &S_CH[6] : E_CH;
+    for( i=0; i < length ; i++ )
+	{
+		/*            channel A         channel B         channel C      */
+		/* LFO */
+		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
+		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
+		outd[0] = 0;
+		/* FM part */
+		for(CH=S_CH ; CH < R_CH ; CH++)
+			OPL_CALC_CH(CH);
+		/* Rythn part */
+		if(rythm)
+			OPL_CALC_RH(S_CH);
+		/* limit check */
+		data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
+		/* store to sound buffer */
+		buf[i] = data >> OPL_OUTSB;
+	}
+
+	OPL->amsCnt = amsCnt;
+	OPL->vibCnt = vibCnt;
+#ifdef OPL_OUTPUT_LOG
+	if(opl_dbg_fp)
+	{
+		for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
+			if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
+		fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256);
+	}
+#endif
+}
+#endif /* (BUILD_YM3812 || BUILD_YM3526) */
+
+#if BUILD_Y8950
+
+void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+{
+    int i;
+	int data;
+	OPLSAMPLE *buf = buffer;
+	UINT32 amsCnt  = OPL->amsCnt;
+	UINT32 vibCnt  = OPL->vibCnt;
+	UINT8 rythm = OPL->rythm&0x20;
+	OPL_CH *CH,*R_CH;
+	YM_DELTAT *DELTAT = OPL->deltat;
+
+	/* setup DELTA-T unit */
+	YM_DELTAT_DECODE_PRESET(DELTAT);
+
+	if( (void *)OPL != cur_chip ){
+		cur_chip = (void *)OPL;
+		/* channel pointers */
+		S_CH = OPL->P_CH;
+		E_CH = &S_CH[9];
+		/* rythm slot */
+		SLOT7_1 = &S_CH[7].SLOT[SLOT1];
+		SLOT7_2 = &S_CH[7].SLOT[SLOT2];
+		SLOT8_1 = &S_CH[8].SLOT[SLOT1];
+		SLOT8_2 = &S_CH[8].SLOT[SLOT2];
+		/* LFO state */
+		amsIncr = OPL->amsIncr;
+		vibIncr = OPL->vibIncr;
+		ams_table = OPL->ams_table;
+		vib_table = OPL->vib_table;
+	}
+	R_CH = rythm ? &S_CH[6] : E_CH;
+    for( i=0; i < length ; i++ )
+	{
+		/*            channel A         channel B         channel C      */
+		/* LFO */
+		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
+		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
+		outd[0] = 0;
+		/* deltaT ADPCM */
+		if( DELTAT->portstate )
+			YM_DELTAT_ADPCM_CALC(DELTAT);
+		/* FM part */
+		for(CH=S_CH ; CH < R_CH ; CH++)
+			OPL_CALC_CH(CH);
+		/* Rythn part */
+		if(rythm)
+			OPL_CALC_RH(S_CH);
+		/* limit check */
+		data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
+		/* store to sound buffer */
+		buf[i] = data >> OPL_OUTSB;
+	}
+	OPL->amsCnt = amsCnt;
+	OPL->vibCnt = vibCnt;
+	/* deltaT START flag */
+	if( !DELTAT->portstate )
+		OPL->status &= 0xfe;
+}
+#endif
+
+/* ---------- reset one of chip ---------- */
+void OPLResetChip(FM_OPL *OPL)
+{
+	int c,s;
+	int i;
+
+	/* reset chip */
+	OPL->mode   = 0;	/* normal mode */
+	OPL_STATUS_RESET(OPL,0x7f);
+	/* reset with register write */
+	OPLWriteReg(OPL,0x01,0); /* wabesel disable */
+	OPLWriteReg(OPL,0x02,0); /* Timer1 */
+	OPLWriteReg(OPL,0x03,0); /* Timer2 */
+	OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
+	for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
+	/* reset OPerator paramater */
+	for( c = 0 ; c < OPL->max_ch ; c++ )
+	{
+		OPL_CH *CH = &OPL->P_CH[c];
+		/* OPL->P_CH[c].PAN = OPN_CENTER; */
+		for(s = 0 ; s < 2 ; s++ )
+		{
+			/* wave table */
+			CH->SLOT[s].wavetable = &SIN_TABLE[0];
+			/* CH->SLOT[s].evm = ENV_MOD_RR; */
+			CH->SLOT[s].evc = EG_OFF;
+			CH->SLOT[s].eve = EG_OFF+1;
+			CH->SLOT[s].evs = 0;
+		}
+	}
+#if BUILD_Y8950
+	if(OPL->type&OPL_TYPE_ADPCM)
+	{
+		YM_DELTAT *DELTAT = OPL->deltat;
+
+		DELTAT->freqbase = OPL->freqbase;
+		DELTAT->output_pointer = outd;
+		DELTAT->portshift = 5;
+		DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
+		YM_DELTAT_ADPCM_Reset(DELTAT,0);
+	}
+#endif
+}
+
+/* ----------  Create one of vietual YM3812 ----------       */
+/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
+FM_OPL *OPLCreate(int type, int clock, int rate)
+{
+	char *ptr;
+	FM_OPL *OPL;
+	int state_size;
+	int max_ch = 9; /* normaly 9 channels */
+
+	if( OPL_LockTable() ==-1) return NULL;
+	/* allocate OPL state space */
+	state_size  = sizeof(FM_OPL);
+	state_size += sizeof(OPL_CH)*max_ch;
+#if BUILD_Y8950
+	if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
+#endif
+	/* allocate memory block */
+	ptr = malloc(state_size);
+	if(ptr==NULL) return NULL;
+	/* clear */
+	memset(ptr,0,state_size);
+	OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
+	OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
+#if BUILD_Y8950
+	if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
+#endif
+	/* set channel state pointer */
+	OPL->type  = type;
+	OPL->clock = clock;
+	OPL->rate  = rate;
+	OPL->max_ch = max_ch;
+	/* init grobal tables */
+	OPL_initalize(OPL);
+	/* reset chip */
+	OPLResetChip(OPL);
+#ifdef OPL_OUTPUT_LOG
+	if(!opl_dbg_fp)
+	{
+		opl_dbg_fp = fopen("opllog.opl","wb");
+		opl_dbg_maxchip = 0;
+	}
+	if(opl_dbg_fp)
+	{
+		opl_dbg_opl[opl_dbg_maxchip] = OPL;
+		fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip,
+			type,
+			clock&0xff,
+			(clock/0x100)&0xff,
+			(clock/0x10000)&0xff,
+			(clock/0x1000000)&0xff);
+		opl_dbg_maxchip++;
+	}
+#endif
+	return OPL;
+}
+
+/* ----------  Destroy one of vietual YM3812 ----------       */
+void OPLDestroy(FM_OPL *OPL)
+{
+#ifdef OPL_OUTPUT_LOG
+	if(opl_dbg_fp)
+	{
+		fclose(opl_dbg_fp);
+		opl_dbg_fp = NULL;
+	}
+#endif
+	OPL_UnLockTable();
+	free(OPL);
+}
+
+/* ----------  Option handlers ----------       */
+
+void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
+{
+	OPL->TimerHandler   = TimerHandler;
+	OPL->TimerParam = channelOffset;
+}
+void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
+{
+	OPL->IRQHandler     = IRQHandler;
+	OPL->IRQParam = param;
+}
+void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
+{
+	OPL->UpdateHandler = UpdateHandler;
+	OPL->UpdateParam = param;
+}
+#if BUILD_Y8950
+void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
+{
+	OPL->porthandler_w = PortHandler_w;
+	OPL->porthandler_r = PortHandler_r;
+	OPL->port_param = param;
+}
+
+void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
+{
+	OPL->keyboardhandler_w = KeyboardHandler_w;
+	OPL->keyboardhandler_r = KeyboardHandler_r;
+	OPL->keyboard_param = param;
+}
+#endif
+/* ---------- YM3812 I/O interface ---------- */
+int OPLWrite(FM_OPL *OPL,int a,int v)
+{
+	if( !(a&1) )
+	{	/* address port */
+		OPL->address = v & 0xff;
+	}
+	else
+	{	/* data port */
+		if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+#ifdef OPL_OUTPUT_LOG
+	if(opl_dbg_fp)
+	{
+		for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
+			if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
+		fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v);
+	}
+#endif
+		OPLWriteReg(OPL,OPL->address,v);
+	}
+	return OPL->status>>7;
+}
+
+unsigned char OPLRead(FM_OPL *OPL,int a)
+{
+	if( !(a&1) )
+	{	/* status port */
+		return OPL->status & (OPL->statusmask|0x80);
+	}
+	/* data port */
+	switch(OPL->address)
+	{
+	case 0x05: /* KeyBoard IN */
+		if(OPL->type&OPL_TYPE_KEYBOARD)
+		{
+			if(OPL->keyboardhandler_r)
+				return OPL->keyboardhandler_r(OPL->keyboard_param);
+			else {
+				LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
+			}
+		}
+		return 0;
+#if 0
+	case 0x0f: /* ADPCM-DATA  */
+		return 0;
+#endif
+	case 0x19: /* I/O DATA    */
+		if(OPL->type&OPL_TYPE_IO)
+		{
+			if(OPL->porthandler_r)
+				return OPL->porthandler_r(OPL->port_param);
+			else {
+				LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
+			}
+		}
+		return 0;
+	case 0x1a: /* PCM-DATA    */
+		return 0;
+	}
+	return 0;
+}
+
+int OPLTimerOver(FM_OPL *OPL,int c)
+{
+	if( c )
+	{	/* Timer B */
+		OPL_STATUS_SET(OPL,0x20);
+	}
+	else
+	{	/* Timer A */
+		OPL_STATUS_SET(OPL,0x40);
+		/* CSM mode key,TL controll */
+		if( OPL->mode & 0x80 )
+		{	/* CSM mode total level latch and auto key on */
+			int ch;
+			if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+			for(ch=0;ch<9;ch++)
+				CSMKeyControll( &OPL->P_CH[ch] );
+		}
+	}
+	/* reload timer */
+	if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
+	return OPL->status>>7;
+}
diff --git a/qemu-0.15.x/hw/fmopl.h b/qemu-0.15.x/hw/fmopl.h
new file mode 100644
index 0000000..a01ff90
--- /dev/null
+++ b/qemu-0.15.x/hw/fmopl.h
@@ -0,0 +1,174 @@
+#ifndef __FMOPL_H_
+#define __FMOPL_H_
+
+/* --- select emulation chips --- */
+#define BUILD_YM3812 (HAS_YM3812)
+//#define BUILD_YM3526 (HAS_YM3526)
+//#define BUILD_Y8950  (HAS_Y8950)
+
+/* --- system optimize --- */
+/* select bit size of output : 8 or 16 */
+#define OPL_OUTPUT_BIT 16
+
+/* compiler dependence */
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+typedef unsigned char	UINT8;   /* unsigned  8bit */
+typedef unsigned short	UINT16;  /* unsigned 16bit */
+typedef unsigned int	UINT32;  /* unsigned 32bit */
+typedef signed char		INT8;    /* signed  8bit   */
+typedef signed short	INT16;   /* signed 16bit   */
+typedef signed int		INT32;   /* signed 32bit   */
+#endif
+
+#if (OPL_OUTPUT_BIT==16)
+typedef INT16 OPLSAMPLE;
+#endif
+#if (OPL_OUTPUT_BIT==8)
+typedef unsigned char  OPLSAMPLE;
+#endif
+
+
+#if BUILD_Y8950
+#include "ymdeltat.h"
+#endif
+
+typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
+typedef void (*OPL_IRQHANDLER)(int param,int irq);
+typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
+typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
+typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
+
+/* !!!!! here is private section , do not access there member direct !!!!! */
+
+#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
+#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
+#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
+#define OPL_TYPE_IO        0x08  /* I/O port */
+
+/* Saving is necessary for member of the 'R' mark for suspend/resume */
+/* ---------- OPL one of slot  ---------- */
+typedef struct fm_opl_slot {
+	INT32 TL;		/* total level     :TL << 8            */
+	INT32 TLL;		/* adjusted now TL                     */
+	UINT8  KSR;		/* key scale rate  :(shift down bit)   */
+	INT32 *AR;		/* attack rate     :&AR_TABLE[AR<<2]   */
+	INT32 *DR;		/* decay rate      :&DR_TALBE[DR<<2]   */
+	INT32 SL;		/* sustin level    :SL_TALBE[SL]       */
+	INT32 *RR;		/* release rate    :&DR_TABLE[RR<<2]   */
+	UINT8 ksl;		/* keyscale level  :(shift down bits)  */
+	UINT8 ksr;		/* key scale rate  :kcode>>KSR         */
+	UINT32 mul;		/* multiple        :ML_TABLE[ML]       */
+	UINT32 Cnt;		/* frequency count :                   */
+	UINT32 Incr;	/* frequency step  :                   */
+	/* envelope generator state */
+	UINT8 eg_typ;	/* envelope type flag                  */
+	UINT8 evm;		/* envelope phase                      */
+	INT32 evc;		/* envelope counter                    */
+	INT32 eve;		/* envelope counter end point          */
+	INT32 evs;		/* envelope counter step               */
+	INT32 evsa;	/* envelope step for AR :AR[ksr]           */
+	INT32 evsd;	/* envelope step for DR :DR[ksr]           */
+	INT32 evsr;	/* envelope step for RR :RR[ksr]           */
+	/* LFO */
+	UINT8 ams;		/* ams flag                            */
+	UINT8 vib;		/* vibrate flag                        */
+	/* wave selector */
+	INT32 **wavetable;
+}OPL_SLOT;
+
+/* ---------- OPL one of channel  ---------- */
+typedef struct fm_opl_channel {
+	OPL_SLOT SLOT[2];
+	UINT8 CON;			/* connection type                     */
+	UINT8 FB;			/* feed back       :(shift down bit)   */
+	INT32 *connect1;	/* slot1 output pointer                */
+	INT32 *connect2;	/* slot2 output pointer                */
+	INT32 op1_out[2];	/* slot1 output for selfeedback        */
+	/* phase generator state */
+	UINT32  block_fnum;	/* block+fnum      :                   */
+	UINT8 kcode;		/* key code        : KeyScaleCode      */
+	UINT32  fc;			/* Freq. Increment base                */
+	UINT32  ksl_base;	/* KeyScaleLevel Base step             */
+	UINT8 keyon;		/* key on/off flag                     */
+} OPL_CH;
+
+/* OPL state */
+typedef struct fm_opl_f {
+	UINT8 type;			/* chip type                         */
+	int clock;			/* master clock  (Hz)                */
+	int rate;			/* sampling rate (Hz)                */
+	double freqbase;	/* frequency base                    */
+	double TimerBase;	/* Timer base time (==sampling time) */
+	UINT8 address;		/* address register                  */
+	UINT8 status;		/* status flag                       */
+	UINT8 statusmask;	/* status mask                       */
+	UINT32 mode;		/* Reg.08 : CSM , notesel,etc.       */
+	/* Timer */
+	int T[2];			/* timer counter                     */
+	UINT8 st[2];		/* timer enable                      */
+	/* FM channel slots */
+	OPL_CH *P_CH;		/* pointer of CH                     */
+	int	max_ch;			/* maximum channel                   */
+	/* Rythm sention */
+	UINT8 rythm;		/* Rythm mode , key flag */
+#if BUILD_Y8950
+	/* Delta-T ADPCM unit (Y8950) */
+	YM_DELTAT *deltat;			/* DELTA-T ADPCM       */
+#endif
+	/* Keyboard / I/O interface unit (Y8950) */
+	UINT8 portDirection;
+	UINT8 portLatch;
+	OPL_PORTHANDLER_R porthandler_r;
+	OPL_PORTHANDLER_W porthandler_w;
+	int port_param;
+	OPL_PORTHANDLER_R keyboardhandler_r;
+	OPL_PORTHANDLER_W keyboardhandler_w;
+	int keyboard_param;
+	/* time tables */
+	INT32 AR_TABLE[75];	/* atttack rate tables */
+	INT32 DR_TABLE[75];	/* decay rate tables   */
+	UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
+	/* LFO */
+	INT32 *ams_table;
+	INT32 *vib_table;
+	INT32 amsCnt;
+	INT32 amsIncr;
+	INT32 vibCnt;
+	INT32 vibIncr;
+	/* wave selector enable flag */
+	UINT8 wavesel;
+	/* external event callback handler */
+	OPL_TIMERHANDLER  TimerHandler;		/* TIMER handler   */
+	int TimerParam;						/* TIMER parameter */
+	OPL_IRQHANDLER    IRQHandler;		/* IRQ handler    */
+	int IRQParam;						/* IRQ parameter  */
+	OPL_UPDATEHANDLER UpdateHandler;	/* stream update handler   */
+	int UpdateParam;					/* stream update parameter */
+} FM_OPL;
+
+/* ---------- Generic interface section ---------- */
+#define OPL_TYPE_YM3526 (0)
+#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
+#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
+
+FM_OPL *OPLCreate(int type, int clock, int rate);
+void OPLDestroy(FM_OPL *OPL);
+void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
+void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
+void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
+/* Y8950 port handlers */
+void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
+void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
+
+void OPLResetChip(FM_OPL *OPL);
+int OPLWrite(FM_OPL *OPL,int a,int v);
+unsigned char OPLRead(FM_OPL *OPL,int a);
+int OPLTimerOver(FM_OPL *OPL,int c);
+
+/* YM3626/YM3812 local section */
+void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+#endif
diff --git a/qemu-0.15.x/hw/framebuffer.c b/qemu-0.15.x/hw/framebuffer.c
new file mode 100644
index 0000000..56cf16e
--- /dev/null
+++ b/qemu-0.15.x/hw/framebuffer.c
@@ -0,0 +1,119 @@
+/*
+ * Framebuffer device helper routines
+ *
+ * Copyright (c) 2009 CodeSourcery
+ * Written by Paul Brook <paul at codesourcery.com>
+ *
+ * This code is licensed under the GNU GPLv2.
+ */
+
+/* TODO:
+   - Do something similar for framebuffers with local ram
+   - Handle rotation here instead of hacking dest_pitch
+   - Use common pixel conversion routines instead of per-device drawfn
+   - Remove all DisplayState knowledge from devices.
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "framebuffer.h"
+
+/* Render an image from a shared memory framebuffer.  */
+   
+void framebuffer_update_display(
+    DisplayState *ds,
+    target_phys_addr_t base,
+    int cols, /* Width in pixels.  */
+    int rows, /* Leight in pixels.  */
+    int src_width, /* Length of source line, in bytes.  */
+    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
+    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
+    int invalidate, /* nonzero to redraw the whole image.  */
+    drawfn fn,
+    void *opaque,
+    int *first_row, /* Input and output.  */
+    int *last_row /* Output only */)
+{
+    target_phys_addr_t src_len;
+    uint8_t *dest;
+    uint8_t *src;
+    uint8_t *src_base;
+    int first, last = 0;
+    int dirty;
+    int i;
+    ram_addr_t addr;
+    ram_addr_t pd;
+    ram_addr_t pd2;
+
+    i = *first_row;
+    *first_row = -1;
+    src_len = src_width * rows;
+
+    cpu_physical_sync_dirty_bitmap(base, base + src_len);
+    pd = cpu_get_physical_page_desc(base);
+    pd2 = cpu_get_physical_page_desc(base + src_len - 1);
+    /* We should reall check that this is a continuous ram region.
+       Instead we just check that the first and last pages are
+       both ram, and the right distance apart.  */
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
+        || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+        return;
+    }
+    pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
+    if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
+        return;
+    }
+
+    src_base = cpu_physical_memory_map(base, &src_len, 0);
+    /* If we can't map the framebuffer then bail.  We could try harder,
+       but it's not really worth it as dirty flag tracking will probably
+       already have failed above.  */
+    if (!src_base)
+        return;
+    if (src_len != src_width * rows) {
+        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+        return;
+    }
+    src = src_base;
+    dest = ds_get_data(ds);
+    if (dest_col_pitch < 0)
+        dest -= dest_col_pitch * (cols - 1);
+    if (dest_row_pitch < 0) {
+        dest -= dest_row_pitch * (rows - 1);
+    }
+    first = -1;
+    addr = pd;
+
+    addr += i * src_width;
+    src += i * src_width;
+    dest += i * dest_row_pitch;
+
+    for (; i < rows; i++) {
+        target_phys_addr_t dirty_offset;
+        dirty = 0;
+        dirty_offset = 0;
+        while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
+            dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset,
+                                                   VGA_DIRTY_FLAG);
+            dirty_offset += TARGET_PAGE_SIZE;
+        }
+
+        if (dirty || invalidate) {
+            fn(opaque, dest, src, cols, dest_col_pitch);
+            if (first == -1)
+                first = i;
+            last = i;
+        }
+        addr += src_width;
+        src += src_width;
+        dest += dest_row_pitch;
+    }
+    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+    if (first < 0) {
+        return;
+    }
+    cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG);
+    *first_row = first;
+    *last_row = last;
+    return;
+}
diff --git a/qemu-0.15.x/hw/framebuffer.h b/qemu-0.15.x/hw/framebuffer.h
new file mode 100644
index 0000000..a3a2146
--- /dev/null
+++ b/qemu-0.15.x/hw/framebuffer.h
@@ -0,0 +1,22 @@
+#ifndef QEMU_FRAMEBUFFER_H
+#define QEMU_FRAMEBUFFER_H
+
+/* Framebuffer device helper routines.  */
+
+typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
+
+void framebuffer_update_display(
+    DisplayState *ds,
+    target_phys_addr_t base,
+    int cols,
+    int rows,
+    int src_width,
+    int dest_row_pitch,
+    int dest_col_pitch,
+    int invalidate,
+    drawfn fn,
+    void *opaque,
+    int *first_row,
+    int *last_row);
+
+#endif
diff --git a/qemu-0.15.x/hw/fw_cfg.c b/qemu-0.15.x/hw/fw_cfg.c
new file mode 100644
index 0000000..34e7526
--- /dev/null
+++ b/qemu-0.15.x/hw/fw_cfg.c
@@ -0,0 +1,407 @@
+/*
+ * QEMU Firmware configuration device emulation
+ *
+ * Copyright (c) 2008 Gleb Natapov
+ *
+ * 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 "hw.h"
+#include "sysemu.h"
+#include "isa.h"
+#include "fw_cfg.h"
+#include "sysbus.h"
+
+/* debug firmware config */
+//#define DEBUG_FW_CFG
+
+#ifdef DEBUG_FW_CFG
+#define FW_CFG_DPRINTF(fmt, ...)                        \
+    do { printf("FW_CFG: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define FW_CFG_DPRINTF(fmt, ...)
+#endif
+
+#define FW_CFG_SIZE 2
+
+typedef struct FWCfgEntry {
+    uint32_t len;
+    uint8_t *data;
+    void *callback_opaque;
+    FWCfgCallback callback;
+} FWCfgEntry;
+
+struct FWCfgState {
+    SysBusDevice busdev;
+    uint32_t ctl_iobase, data_iobase;
+    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
+    FWCfgFiles *files;
+    uint16_t cur_entry;
+    uint32_t cur_offset;
+    Notifier machine_ready;
+};
+
+static void fw_cfg_write(FWCfgState *s, uint8_t value)
+{
+    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
+    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
+
+    FW_CFG_DPRINTF("write %d\n", value);
+
+    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
+        e->data[s->cur_offset++] = value;
+        if (s->cur_offset == e->len) {
+            e->callback(e->callback_opaque, e->data);
+            s->cur_offset = 0;
+        }
+    }
+}
+
+static int fw_cfg_select(FWCfgState *s, uint16_t key)
+{
+    int ret;
+
+    s->cur_offset = 0;
+    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
+        s->cur_entry = FW_CFG_INVALID;
+        ret = 0;
+    } else {
+        s->cur_entry = key;
+        ret = 1;
+    }
+
+    FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not ");
+
+    return ret;
+}
+
+static uint8_t fw_cfg_read(FWCfgState *s)
+{
+    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
+    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
+    uint8_t ret;
+
+    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
+        ret = 0;
+    else
+        ret = e->data[s->cur_offset++];
+
+    FW_CFG_DPRINTF("read %d\n", ret);
+
+    return ret;
+}
+
+static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr)
+{
+    return fw_cfg_read(opaque);
+}
+
+static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value)
+{
+    fw_cfg_write(opaque, (uint8_t)value);
+}
+
+static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value)
+{
+    fw_cfg_select(opaque, (uint16_t)value);
+}
+
+static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    return fw_cfg_read(opaque);
+}
+
+static void fw_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    fw_cfg_write(opaque, (uint8_t)value);
+}
+
+static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    fw_cfg_select(opaque, (uint16_t)value);
+}
+
+static CPUReadMemoryFunc * const fw_cfg_ctl_mem_read[3] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const fw_cfg_ctl_mem_write[3] = {
+    NULL,
+    fw_cfg_mem_writew,
+    NULL,
+};
+
+static CPUReadMemoryFunc * const fw_cfg_data_mem_read[3] = {
+    fw_cfg_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const fw_cfg_data_mem_write[3] = {
+    fw_cfg_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void fw_cfg_reset(DeviceState *d)
+{
+    FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
+
+    fw_cfg_select(s, 0);
+}
+
+/* Save restore 32 bit int as uint16_t
+   This is a Big hack, but it is how the old state did it.
+   Or we broke compatibility in the state, or we can't use struct tm
+ */
+
+static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    *v = qemu_get_be16(f);
+    return 0;
+}
+
+static void put_unused(QEMUFile *f, void *pv, size_t size)
+{
+    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
+    fprintf(stderr, "This functions shouldn't be called.\n");
+}
+
+static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
+    .name = "int32_as_uint16",
+    .get  = get_uint32_as_uint16,
+    .put  = put_unused,
+};
+
+#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
+
+
+static bool is_version_1(void *opaque, int version_id)
+{
+    return version_id == 1;
+}
+
+static const VMStateDescription vmstate_fw_cfg = {
+    .name = "fw_cfg",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(cur_entry, FWCfgState),
+        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
+        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len)
+{
+    int arch = !!(key & FW_CFG_ARCH_LOCAL);
+
+    key &= FW_CFG_ENTRY_MASK;
+
+    if (key >= FW_CFG_MAX_ENTRY)
+        return 0;
+
+    s->entries[arch][key].data = data;
+    s->entries[arch][key].len = len;
+
+    return 1;
+}
+
+int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
+{
+    uint16_t *copy;
+
+    copy = qemu_malloc(sizeof(value));
+    *copy = cpu_to_le16(value);
+    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
+}
+
+int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
+{
+    uint32_t *copy;
+
+    copy = qemu_malloc(sizeof(value));
+    *copy = cpu_to_le32(value);
+    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
+}
+
+int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
+{
+    uint64_t *copy;
+
+    copy = qemu_malloc(sizeof(value));
+    *copy = cpu_to_le64(value);
+    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
+}
+
+int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
+                        void *callback_opaque, uint8_t *data, size_t len)
+{
+    int arch = !!(key & FW_CFG_ARCH_LOCAL);
+
+    if (!(key & FW_CFG_WRITE_CHANNEL))
+        return 0;
+
+    key &= FW_CFG_ENTRY_MASK;
+
+    if (key >= FW_CFG_MAX_ENTRY || len > 65535)
+        return 0;
+
+    s->entries[arch][key].data = data;
+    s->entries[arch][key].len = len;
+    s->entries[arch][key].callback_opaque = callback_opaque;
+    s->entries[arch][key].callback = callback;
+
+    return 1;
+}
+
+int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
+                    uint32_t len)
+{
+    int i, index;
+
+    if (!s->files) {
+        int dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
+        s->files = qemu_mallocz(dsize);
+        fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, (uint8_t*)s->files, dsize);
+    }
+
+    index = be32_to_cpu(s->files->count);
+    if (index == FW_CFG_FILE_SLOTS) {
+        fprintf(stderr, "fw_cfg: out of file slots\n");
+        return 0;
+    }
+
+    fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
+
+    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
+            filename);
+    for (i = 0; i < index; i++) {
+        if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
+            FW_CFG_DPRINTF("%s: skip duplicate: %s\n", __FUNCTION__,
+                           s->files->f[index].name);
+            return 1;
+        }
+    }
+
+    s->files->f[index].size   = cpu_to_be32(len);
+    s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
+    FW_CFG_DPRINTF("%s: #%d: %s (%d bytes)\n", __FUNCTION__,
+                   index, s->files->f[index].name, len);
+
+    s->files->count = cpu_to_be32(index+1);
+    return 1;
+}
+
+static void fw_cfg_machine_ready(struct Notifier *n, void *data)
+{
+    uint32_t len;
+    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
+    char *bootindex = get_boot_devices_list(&len);
+
+    fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
+}
+
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
+                        target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    FWCfgState *s;
+
+    dev = qdev_create(NULL, "fw_cfg");
+    qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
+    qdev_prop_set_uint32(dev, "data_iobase", data_port);
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+
+    s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
+
+    if (ctl_addr) {
+        sysbus_mmio_map(d, 0, ctl_addr);
+    }
+    if (data_addr) {
+        sysbus_mmio_map(d, 1, data_addr);
+    }
+    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4);
+    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
+    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
+    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
+    fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
+
+
+    s->machine_ready.notify = fw_cfg_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
+
+    return s;
+}
+
+static int fw_cfg_init1(SysBusDevice *dev)
+{
+    FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
+    int io_ctl_memory, io_data_memory;
+
+    io_ctl_memory = cpu_register_io_memory(fw_cfg_ctl_mem_read,
+                                           fw_cfg_ctl_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, FW_CFG_SIZE, io_ctl_memory);
+
+    io_data_memory = cpu_register_io_memory(fw_cfg_data_mem_read,
+                                            fw_cfg_data_mem_write, s,
+                                            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, FW_CFG_SIZE, io_data_memory);
+
+    if (s->ctl_iobase) {
+        register_ioport_write(s->ctl_iobase, 2, 2, fw_cfg_io_writew, s);
+    }
+    if (s->data_iobase) {
+        register_ioport_read(s->data_iobase, 1, 1, fw_cfg_io_readb, s);
+        register_ioport_write(s->data_iobase, 1, 1, fw_cfg_io_writeb, s);
+    }
+    return 0;
+}
+
+static SysBusDeviceInfo fw_cfg_info = {
+    .init = fw_cfg_init1,
+    .qdev.name = "fw_cfg",
+    .qdev.size = sizeof(FWCfgState),
+    .qdev.vmsd = &vmstate_fw_cfg,
+    .qdev.reset = fw_cfg_reset,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
+        DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void fw_cfg_register_devices(void)
+{
+    sysbus_register_withprop(&fw_cfg_info);
+}
+
+device_init(fw_cfg_register_devices)
diff --git a/qemu-0.15.x/hw/fw_cfg.h b/qemu-0.15.x/hw/fw_cfg.h
new file mode 100644
index 0000000..856bf91
--- /dev/null
+++ b/qemu-0.15.x/hw/fw_cfg.h
@@ -0,0 +1,70 @@
+#ifndef FW_CFG_H
+#define FW_CFG_H
+
+#define FW_CFG_SIGNATURE        0x00
+#define FW_CFG_ID               0x01
+#define FW_CFG_UUID             0x02
+#define FW_CFG_RAM_SIZE         0x03
+#define FW_CFG_NOGRAPHIC        0x04
+#define FW_CFG_NB_CPUS          0x05
+#define FW_CFG_MACHINE_ID       0x06
+#define FW_CFG_KERNEL_ADDR      0x07
+#define FW_CFG_KERNEL_SIZE      0x08
+#define FW_CFG_KERNEL_CMDLINE   0x09
+#define FW_CFG_INITRD_ADDR      0x0a
+#define FW_CFG_INITRD_SIZE      0x0b
+#define FW_CFG_BOOT_DEVICE      0x0c
+#define FW_CFG_NUMA             0x0d
+#define FW_CFG_BOOT_MENU        0x0e
+#define FW_CFG_MAX_CPUS         0x0f
+#define FW_CFG_KERNEL_ENTRY     0x10
+#define FW_CFG_KERNEL_DATA      0x11
+#define FW_CFG_INITRD_DATA      0x12
+#define FW_CFG_CMDLINE_ADDR     0x13
+#define FW_CFG_CMDLINE_SIZE     0x14
+#define FW_CFG_CMDLINE_DATA     0x15
+#define FW_CFG_SETUP_ADDR       0x16
+#define FW_CFG_SETUP_SIZE       0x17
+#define FW_CFG_SETUP_DATA       0x18
+#define FW_CFG_FILE_DIR         0x19
+
+#define FW_CFG_FILE_FIRST       0x20
+#define FW_CFG_FILE_SLOTS       0x10
+#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST+FW_CFG_FILE_SLOTS)
+
+#define FW_CFG_WRITE_CHANNEL    0x4000
+#define FW_CFG_ARCH_LOCAL       0x8000
+#define FW_CFG_ENTRY_MASK       ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
+
+#define FW_CFG_INVALID          0xffff
+
+#ifndef NO_QEMU_PROTOS
+typedef struct FWCfgFile {
+    uint32_t  size;        /* file size */
+    uint16_t  select;      /* write this to 0x510 to read it */
+    uint16_t  reserved;
+    char      name[56];
+} FWCfgFile;
+
+typedef struct FWCfgFiles {
+    uint32_t  count;
+    FWCfgFile f[];
+} FWCfgFiles;
+
+typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
+
+typedef struct FWCfgState FWCfgState;
+int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len);
+int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
+int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
+int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
+int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
+                        void *callback_opaque, uint8_t *data, size_t len);
+int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data,
+                    uint32_t len);
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
+                        target_phys_addr_t crl_addr, target_phys_addr_t data_addr);
+
+#endif /* NO_QEMU_PROTOS */
+
+#endif
diff --git a/qemu-0.15.x/hw/g364fb.c b/qemu-0.15.x/hw/g364fb.c
new file mode 100644
index 0000000..a41e988
--- /dev/null
+++ b/qemu-0.15.x/hw/g364fb.c
@@ -0,0 +1,615 @@
+/*
+ * QEMU G364 framebuffer Emulator.
+ *
+ * Copyright (c) 2007-2009 Herve Poussineau
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "mips.h"
+#include "console.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_G364
+
+#ifdef DEBUG_G364
+#define DPRINTF(fmt, ...) \
+do { printf("g364: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "g364 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
+typedef struct G364State {
+    /* hardware */
+    uint8_t *vram;
+    ram_addr_t vram_offset;
+    int vram_size;
+    qemu_irq irq;
+    /* registers */
+    uint8_t color_palette[256][3];
+    uint8_t cursor_palette[3][3];
+    uint16_t cursor[512];
+    uint32_t cursor_position;
+    uint32_t ctla;
+    uint32_t top_of_screen;
+    uint32_t width, height; /* in pixels */
+    /* display refresh support */
+    DisplayState *ds;
+    int depth;
+    int blanked;
+} G364State;
+
+#define REG_ID       0x000000
+#define REG_BOOT     0x080000
+#define REG_DISPLAY  0x080118
+#define REG_VDISPLAY 0x080150
+#define REG_CTLA     0x080300
+#define REG_TOP      0x080400
+#define REG_CURS_PAL 0x080508
+#define REG_CURS_POS 0x080638
+#define REG_CLR_PAL  0x080800
+#define REG_CURS_PAT 0x081000
+#define REG_RESET    0x180000
+
+#define CTLA_FORCE_BLANK 0x00000400
+#define CTLA_NO_CURSOR   0x00800000
+
+static inline int check_dirty(ram_addr_t page)
+{
+    return cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+}
+
+static inline void reset_dirty(G364State *s,
+                               ram_addr_t page_min, ram_addr_t page_max)
+{
+    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE - 1,
+                                    VGA_DIRTY_FLAG);
+}
+
+static void g364fb_draw_graphic8(G364State *s)
+{
+    int i, w;
+    uint8_t *vram;
+    uint8_t *data_display, *dd;
+    ram_addr_t page, page_min, page_max;
+    int x, y;
+    int xmin, xmax;
+    int ymin, ymax;
+    int xcursor, ycursor;
+    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            rgb_to_pixel = rgb_to_pixel8;
+            w = 1;
+            break;
+        case 15:
+            rgb_to_pixel = rgb_to_pixel15;
+            w = 2;
+            break;
+        case 16:
+            rgb_to_pixel = rgb_to_pixel16;
+            w = 2;
+            break;
+        case 32:
+            rgb_to_pixel = rgb_to_pixel32;
+            w = 4;
+            break;
+        default:
+            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            return;
+    }
+
+    page = s->vram_offset;
+    page_min = (ram_addr_t)-1;
+    page_max = 0;
+
+    x = y = 0;
+    xmin = s->width;
+    xmax = 0;
+    ymin = s->height;
+    ymax = 0;
+
+    if (!(s->ctla & CTLA_NO_CURSOR)) {
+        xcursor = s->cursor_position >> 12;
+        ycursor = s->cursor_position & 0xfff;
+    } else {
+        xcursor = ycursor = -65;
+    }
+
+    vram = s->vram + s->top_of_screen;
+    /* XXX: out of range in vram? */
+    data_display = dd = ds_get_data(s->ds);
+    while (y < s->height) {
+        if (check_dirty(page)) {
+            if (y < ymin)
+                ymin = ymax = y;
+            if (page_min == (ram_addr_t)-1)
+                page_min = page;
+            page_max = page;
+            if (x < xmin)
+                xmin = x;
+            for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+                uint8_t index;
+                unsigned int color;
+                if (unlikely((y >= ycursor && y < ycursor + 64) &&
+                    (x >= xcursor && x < xcursor + 64))) {
+                    /* pointer area */
+                    int xdiff = x - xcursor;
+                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
+                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
+                    if (likely(op == 0)) {
+                        /* transparent */
+                        index = *vram;
+                        color = (*rgb_to_pixel)(
+                            s->color_palette[index][0],
+                            s->color_palette[index][1],
+                            s->color_palette[index][2]);
+                    } else {
+                        /* get cursor color */
+                        index = op - 1;
+                        color = (*rgb_to_pixel)(
+                            s->cursor_palette[index][0],
+                            s->cursor_palette[index][1],
+                            s->cursor_palette[index][2]);
+                    }
+                } else {
+                    /* normal area */
+                    index = *vram;
+                    color = (*rgb_to_pixel)(
+                        s->color_palette[index][0],
+                        s->color_palette[index][1],
+                        s->color_palette[index][2]);
+                }
+                memcpy(dd, &color, w);
+                dd += w;
+                x++;
+                vram++;
+                if (x == s->width) {
+                    xmax = s->width - 1;
+                    y++;
+                    if (y == s->height) {
+                        ymax = s->height - 1;
+                        goto done;
+                    }
+                    data_display = dd = data_display + ds_get_linesize(s->ds);
+                    xmin = 0;
+                    x = 0;
+                }
+            }
+            if (x > xmax)
+                xmax = x;
+            if (y > ymax)
+                ymax = y;
+        } else {
+            int dy;
+            if (page_min != (ram_addr_t)-1) {
+                reset_dirty(s, page_min, page_max);
+                page_min = (ram_addr_t)-1;
+                page_max = 0;
+                dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+                xmin = s->width;
+                xmax = 0;
+                ymin = s->height;
+                ymax = 0;
+            }
+            x += TARGET_PAGE_SIZE;
+            dy = x / s->width;
+            x = x % s->width;
+            y += dy;
+            vram += TARGET_PAGE_SIZE;
+            data_display += dy * ds_get_linesize(s->ds);
+            dd = data_display + x * w;
+        }
+        page += TARGET_PAGE_SIZE;
+    }
+
+done:
+    if (page_min != (ram_addr_t)-1) {
+        dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+        reset_dirty(s, page_min, page_max);
+    }
+}
+
+static void g364fb_draw_blank(G364State *s)
+{
+    int i, w;
+    uint8_t *d;
+
+    if (s->blanked) {
+        /* Screen is already blank. No need to redraw it */
+        return;
+    }
+
+    w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+    d = ds_get_data(s->ds);
+    for (i = 0; i < s->height; i++) {
+        memset(d, 0, w);
+        d += ds_get_linesize(s->ds);
+    }
+
+    dpy_update(s->ds, 0, 0, s->width, s->height);
+    s->blanked = 1;
+}
+
+static void g364fb_update_display(void *opaque)
+{
+    G364State *s = opaque;
+
+    if (s->width == 0 || s->height == 0)
+        return;
+
+    if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) {
+        qemu_console_resize(s->ds, s->width, s->height);
+    }
+
+    if (s->ctla & CTLA_FORCE_BLANK) {
+        g364fb_draw_blank(s);
+    } else if (s->depth == 8) {
+        g364fb_draw_graphic8(s);
+    } else {
+        BADF("unknown guest depth %d\n", s->depth);
+    }
+
+    qemu_irq_raise(s->irq);
+}
+
+static inline void g364fb_invalidate_display(void *opaque)
+{
+    G364State *s = opaque;
+    int i;
+
+    s->blanked = 0;
+    for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    }
+}
+
+static void g364fb_reset(void *opaque)
+{
+    G364State *s = opaque;
+    qemu_irq_lower(s->irq);
+
+    memset(s->color_palette, 0, sizeof(s->color_palette));
+    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
+    memset(s->cursor, 0, sizeof(s->cursor));
+    s->cursor_position = 0;
+    s->ctla = 0;
+    s->top_of_screen = 0;
+    s->width = s->height = 0;
+    memset(s->vram, 0, s->vram_size);
+    g364fb_invalidate_display(opaque);
+}
+
+static void g364fb_screen_dump(void *opaque, const char *filename)
+{
+    G364State *s = opaque;
+    int y, x;
+    uint8_t index;
+    uint8_t *data_buffer;
+    FILE *f;
+
+    if (s->depth != 8) {
+        BADF("unknown guest depth %d\n", s->depth);
+        return;
+    }
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return;
+
+    if (s->ctla & CTLA_FORCE_BLANK) {
+        /* blank screen */
+        fprintf(f, "P4\n%d %d\n",
+            s->width, s->height);
+        for (y = 0; y < s->height; y++)
+            for (x = 0; x < s->width; x++)
+                fputc(0, f);
+    } else {
+        data_buffer = s->vram + s->top_of_screen;
+        fprintf(f, "P6\n%d %d\n%d\n",
+            s->width, s->height, 255);
+        for (y = 0; y < s->height; y++)
+            for (x = 0; x < s->width; x++, data_buffer++) {
+                index = *data_buffer;
+                fputc(s->color_palette[index][0], f);
+                fputc(s->color_palette[index][1], f);
+                fputc(s->color_palette[index][2], f);
+        }
+    }
+
+    fclose(f);
+}
+
+/* called for accesses to io ports */
+static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
+{
+    G364State *s = opaque;
+    uint32_t val;
+
+    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
+        /* cursor pattern */
+        int idx = (addr - REG_CURS_PAT) >> 3;
+        val = s->cursor[idx];
+    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
+        /* cursor palette */
+        int idx = (addr - REG_CURS_PAL) >> 3;
+        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
+        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
+        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
+    } else {
+        switch (addr) {
+            case REG_ID:
+                val = 0x10; /* Mips G364 */
+                break;
+            case REG_DISPLAY:
+                val = s->width / 4;
+                break;
+            case REG_VDISPLAY:
+                val = s->height * 2;
+                break;
+            case REG_CTLA:
+                val = s->ctla;
+                break;
+            default:
+            {
+                BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
+                val = 0;
+                break;
+            }
+        }
+    }
+
+    DPRINTF("read 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+
+    return val;
+}
+
+static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
+    if (addr & 0x2)
+        return v >> 16;
+    else
+        return v & 0xffff;
+}
+
+static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
+    return (v >> (8 * (addr & 0x3))) & 0xff;
+}
+
+static void g364fb_update_depth(G364State *s)
+{
+    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
+    s->depth = depths[(s->ctla & 0x00700000) >> 20];
+}
+
+static void g364_invalidate_cursor_position(G364State *s)
+{
+    int ymin, ymax, start, end, i;
+
+    /* invalidate only near the cursor */
+    ymin = s->cursor_position & 0xfff;
+    ymax = MIN(s->height, ymin + 64);
+    start = ymin * ds_get_linesize(s->ds);
+    end = (ymax + 1) * ds_get_linesize(s->ds);
+
+    for (i = start; i < end; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    }
+}
+
+static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    G364State *s = opaque;
+
+    DPRINTF("write 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+
+    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
+        /* color palette */
+        int idx = (addr - REG_CLR_PAL) >> 3;
+        s->color_palette[idx][0] = (val >> 16) & 0xff;
+        s->color_palette[idx][1] = (val >> 8) & 0xff;
+        s->color_palette[idx][2] = val & 0xff;
+        g364fb_invalidate_display(s);
+    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
+        /* cursor pattern */
+        int idx = (addr - REG_CURS_PAT) >> 3;
+        s->cursor[idx] = val;
+        g364fb_invalidate_display(s);
+    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
+        /* cursor palette */
+        int idx = (addr - REG_CURS_PAL) >> 3;
+        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
+        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
+        s->cursor_palette[idx][2] = val & 0xff;
+        g364fb_invalidate_display(s);
+    } else {
+        switch (addr) {
+            case REG_ID: /* Card identifier; read-only */
+            case REG_BOOT: /* Boot timing */
+            case 0x80108: /* Line timing: half sync */
+            case 0x80110: /* Line timing: back porch */
+            case 0x80120: /* Line timing: short display */
+            case 0x80128: /* Frame timing: broad pulse */
+            case 0x80130: /* Frame timing: v sync */
+            case 0x80138: /* Frame timing: v preequalise */
+            case 0x80140: /* Frame timing: v postequalise */
+            case 0x80148: /* Frame timing: v blank */
+            case 0x80158: /* Line timing: line time */
+            case 0x80160: /* Frame store: line start */
+            case 0x80168: /* vram cycle: mem init */
+            case 0x80170: /* vram cycle: transfer delay */
+            case 0x80200: /* vram cycle: mask register */
+                /* ignore */
+                break;
+            case REG_TOP:
+                s->top_of_screen = val;
+                g364fb_invalidate_display(s);
+                break;
+            case REG_DISPLAY:
+                s->width = val * 4;
+                break;
+            case REG_VDISPLAY:
+                s->height = val / 2;
+                break;
+            case REG_CTLA:
+                s->ctla = val;
+                g364fb_update_depth(s);
+                g364fb_invalidate_display(s);
+                break;
+            case REG_CURS_POS:
+                g364_invalidate_cursor_position(s);
+                s->cursor_position = val;
+                g364_invalidate_cursor_position(s);
+                break;
+            case REG_RESET:
+                g364fb_reset(s);
+                break;
+            default:
+                BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+                break;
+        }
+    }
+    qemu_irq_lower(s->irq);
+}
+
+static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
+
+    if (addr & 0x2)
+        val = (val << 16) | (old_val & 0x0000ffff);
+    else
+        val = val | (old_val & 0xffff0000);
+    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
+}
+
+static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
+
+    switch (addr & 3) {
+    case 0:
+        val = val | (old_val & 0xffffff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0xffff00ff);
+        break;
+    case 2:
+        val = (val << 16) | (old_val & 0xff00ffff);
+        break;
+    case 3:
+        val = (val << 24) | (old_val & 0x00ffffff);
+        break;
+    }
+    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
+}
+
+static CPUReadMemoryFunc * const g364fb_ctrl_read[3] = {
+    g364fb_ctrl_readb,
+    g364fb_ctrl_readw,
+    g364fb_ctrl_readl,
+};
+
+static CPUWriteMemoryFunc * const g364fb_ctrl_write[3] = {
+    g364fb_ctrl_writeb,
+    g364fb_ctrl_writew,
+    g364fb_ctrl_writel,
+};
+
+static int g364fb_load(QEMUFile *f, void *opaque, int version_id)
+{
+    G364State *s = opaque;
+    unsigned int i, vram_size;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    vram_size = qemu_get_be32(f);
+    if (vram_size < s->vram_size)
+        return -EINVAL;
+    qemu_get_buffer(f, s->vram, s->vram_size);
+    for (i = 0; i < 256; i++)
+        qemu_get_buffer(f, s->color_palette[i], 3);
+    for (i = 0; i < 3; i++)
+        qemu_get_buffer(f, s->cursor_palette[i], 3);
+    qemu_get_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
+    s->cursor_position = qemu_get_be32(f);
+    s->ctla = qemu_get_be32(f);
+    s->top_of_screen = qemu_get_be32(f);
+    s->width = qemu_get_be32(f);
+    s->height = qemu_get_be32(f);
+
+    /* force refresh */
+    g364fb_update_depth(s);
+    g364fb_invalidate_display(s);
+
+    return 0;
+}
+
+static void g364fb_save(QEMUFile *f, void *opaque)
+{
+    G364State *s = opaque;
+    int i;
+
+    qemu_put_be32(f, s->vram_size);
+    qemu_put_buffer(f, s->vram, s->vram_size);
+    for (i = 0; i < 256; i++)
+        qemu_put_buffer(f, s->color_palette[i], 3);
+    for (i = 0; i < 3; i++)
+        qemu_put_buffer(f, s->cursor_palette[i], 3);
+    qemu_put_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
+    qemu_put_be32(f, s->cursor_position);
+    qemu_put_be32(f, s->ctla);
+    qemu_put_be32(f, s->top_of_screen);
+    qemu_put_be32(f, s->width);
+    qemu_put_be32(f, s->height);
+}
+
+int g364fb_mm_init(target_phys_addr_t vram_base,
+                   target_phys_addr_t ctrl_base, int it_shift,
+                   qemu_irq irq)
+{
+    G364State *s;
+    int io_ctrl;
+
+    s = qemu_mallocz(sizeof(G364State));
+
+    s->vram_size = 8 * 1024 * 1024;
+    s->vram_offset = qemu_ram_alloc(NULL, "g364fb.vram", s->vram_size);
+    s->vram = qemu_get_ram_ptr(s->vram_offset);
+    s->irq = irq;
+
+    qemu_register_reset(g364fb_reset, s);
+    register_savevm(NULL, "g364fb", 0, 1, g364fb_save, g364fb_load, s);
+    g364fb_reset(s);
+
+    s->ds = graphic_console_init(g364fb_update_display,
+                                 g364fb_invalidate_display,
+                                 g364fb_screen_dump, NULL, s);
+
+    cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset);
+
+    io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s,
+                                     DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/grackle_pci.c b/qemu-0.15.x/hw/grackle_pci.c
new file mode 100644
index 0000000..cee07e0
--- /dev/null
+++ b/qemu-0.15.x/hw/grackle_pci.c
@@ -0,0 +1,128 @@
+/*
+ * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
+ *
+ * Copyright (c) 2006-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "sysbus.h"
+#include "ppc_mac.h"
+#include "pci.h"
+#include "pci_host.h"
+
+/* debug Grackle */
+//#define DEBUG_GRACKLE
+
+#ifdef DEBUG_GRACKLE
+#define GRACKLE_DPRINTF(fmt, ...)                               \
+    do { printf("GRACKLE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define GRACKLE_DPRINTF(fmt, ...)
+#endif
+
+typedef struct GrackleState {
+    SysBusDevice busdev;
+    PCIHostState host_state;
+} GrackleState;
+
+/* Don't know if this matches real hardware, but it agrees with OHW.  */
+static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return (irq_num + (pci_dev->devfn >> 3)) & 3;
+}
+
+static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    GRACKLE_DPRINTF("set_irq num %d level %d\n", irq_num, level);
+    qemu_set_irq(pic[irq_num + 0x15], level);
+}
+
+static void pci_grackle_reset(void *opaque)
+{
+}
+
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    GrackleState *d;
+
+    dev = qdev_create(NULL, "grackle");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(GrackleState, s);
+    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                         pci_grackle_set_irq,
+                                         pci_grackle_map_irq,
+                                         pic, 0, 4);
+
+    pci_create_simple(d->host_state.bus, 0, "grackle");
+
+    sysbus_mmio_map(s, 0, base);
+    sysbus_mmio_map(s, 1, base + 0x00200000);
+
+    return d->host_state.bus;
+}
+
+static int pci_grackle_init_device(SysBusDevice *dev)
+{
+    GrackleState *s;
+    int pci_mem_config, pci_mem_data;
+
+    s = FROM_SYSBUS(GrackleState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+
+    qemu_register_reset(pci_grackle_reset, &s->host_state);
+    return 0;
+}
+
+static int grackle_pci_host_init(PCIDevice *d)
+{
+    d->config[0x09] = 0x01;
+    return 0;
+}
+
+static PCIDeviceInfo grackle_pci_host_info = {
+    .qdev.name = "grackle",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = grackle_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+    .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static void grackle_register_devices(void)
+{
+    sysbus_register_dev("grackle", sizeof(GrackleState),
+                        pci_grackle_init_device);
+    pci_qdev_register(&grackle_pci_host_info);
+}
+
+device_init(grackle_register_devices)
diff --git a/qemu-0.15.x/hw/grlib.h b/qemu-0.15.x/hw/grlib.h
new file mode 100644
index 0000000..fdf4b11
--- /dev/null
+++ b/qemu-0.15.x/hw/grlib.h
@@ -0,0 +1,126 @@
+/*
+ * QEMU GRLIB Components
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 _GRLIB_H_
+#define _GRLIB_H_
+
+#include "qdev.h"
+#include "sysbus.h"
+
+/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ */
+
+/* IRQMP */
+
+typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level);
+
+void grlib_irqmp_ack(DeviceState *dev, int intno);
+
+static inline
+DeviceState *grlib_irqmp_create(target_phys_addr_t   base,
+                                CPUState            *env,
+                                qemu_irq           **cpu_irqs,
+                                uint32_t             nr_irqs,
+                                set_pil_in_fn        set_pil_in)
+{
+    DeviceState *dev;
+
+    assert(cpu_irqs != NULL);
+
+    dev = qdev_create(NULL, "grlib,irqmp");
+    qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
+    qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    env->irq_manager = dev;
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
+                                   dev,
+                                   nr_irqs);
+
+    return dev;
+}
+
+/* GPTimer */
+
+static inline
+DeviceState *grlib_gptimer_create(target_phys_addr_t  base,
+                                  uint32_t            nr_timers,
+                                  uint32_t            freq,
+                                  qemu_irq           *cpu_irqs,
+                                  int                 base_irq)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "grlib,gptimer");
+    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
+    qdev_prop_set_uint32(dev, "frequency", freq);
+    qdev_prop_set_uint32(dev, "irq-line", base_irq);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    for (i = 0; i < nr_timers; i++) {
+        sysbus_connect_irq(sysbus_from_qdev(dev), i, cpu_irqs[base_irq + i]);
+    }
+
+    return dev;
+}
+
+/* APB UART */
+
+static inline
+DeviceState *grlib_apbuart_create(target_phys_addr_t  base,
+                                  CharDriverState    *serial,
+                                  qemu_irq            irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "grlib,apbuart");
+    qdev_prop_set_chr(dev, "chrdev", serial);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* ! _GRLIB_H_ */
diff --git a/qemu-0.15.x/hw/grlib_apbuart.c b/qemu-0.15.x/hw/grlib_apbuart.c
new file mode 100644
index 0000000..169a56e
--- /dev/null
+++ b/qemu-0.15.x/hw/grlib_apbuart.c
@@ -0,0 +1,187 @@
+/*
+ * QEMU GRLIB APB UART Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+
+#include "trace.h"
+
+#define UART_REG_SIZE 20     /* Size of memory mapped registers */
+
+/* UART status register fields */
+#define UART_DATA_READY           (1 <<  0)
+#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
+#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
+#define UART_BREAK_RECEIVED       (1 <<  3)
+#define UART_OVERRUN              (1 <<  4)
+#define UART_PARITY_ERROR         (1 <<  5)
+#define UART_FRAMING_ERROR        (1 <<  6)
+#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
+#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
+#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
+#define UART_RECEIVE_FIFO_FULL    (1 << 10)
+
+/* UART control register fields */
+#define UART_RECEIVE_ENABLE          (1 <<  0)
+#define UART_TRANSMIT_ENABLE         (1 <<  1)
+#define UART_RECEIVE_INTERRUPT       (1 <<  2)
+#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
+#define UART_PARITY_SELECT           (1 <<  4)
+#define UART_PARITY_ENABLE           (1 <<  5)
+#define UART_FLOW_CONTROL            (1 <<  6)
+#define UART_LOOPBACK                (1 <<  7)
+#define UART_EXTERNAL_CLOCK          (1 <<  8)
+#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
+#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
+#define UART_FIFO_DEBUG_MODE         (1 << 11)
+#define UART_OUTPUT_ENABLE           (1 << 12)
+#define UART_FIFO_AVAILABLE          (1 << 31)
+
+/* Memory mapped register offsets */
+#define DATA_OFFSET       0x00
+#define STATUS_OFFSET     0x04
+#define CONTROL_OFFSET    0x08
+#define SCALER_OFFSET     0x0C  /* not supported */
+#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
+
+typedef struct UART {
+    SysBusDevice busdev;
+
+    qemu_irq irq;
+
+    CharDriverState *chr;
+
+    /* registers */
+    uint32_t receive;
+    uint32_t status;
+    uint32_t control;
+} UART;
+
+static int grlib_apbuart_can_receive(void *opaque)
+{
+    UART *uart = opaque;
+
+    return !!(uart->status & UART_DATA_READY);
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    UART *uart = opaque;
+
+    uart->receive  = *buf;
+    uart->status  |= UART_DATA_READY;
+
+    if (uart->control & UART_RECEIVE_INTERRUPT) {
+        qemu_irq_pulse(uart->irq);
+    }
+}
+
+static void grlib_apbuart_event(void *opaque, int event)
+{
+    trace_grlib_apbuart_event(event);
+}
+
+static void
+grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    UART          *uart = opaque;
+    unsigned char  c    = 0;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case DATA_OFFSET:
+        c = value & 0xFF;
+        qemu_chr_write(uart->chr, &c, 1);
+        return;
+
+    case STATUS_OFFSET:
+        /* Read Only */
+        return;
+
+    case CONTROL_OFFSET:
+        /* Not supported */
+        return;
+
+    case SCALER_OFFSET:
+        /* Not supported */
+        return;
+
+    default:
+        break;
+    }
+
+    trace_grlib_apbuart_writel_unknown(addr, value);
+}
+
+static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
+    NULL, NULL, NULL,
+};
+
+static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
+    NULL, NULL, grlib_apbuart_writel,
+};
+
+static int grlib_apbuart_init(SysBusDevice *dev)
+{
+    UART *uart      = FROM_SYSBUS(typeof(*uart), dev);
+    int   uart_regs = 0;
+
+    qemu_chr_add_handlers(uart->chr,
+                          grlib_apbuart_can_receive,
+                          grlib_apbuart_receive,
+                          grlib_apbuart_event,
+                          uart);
+
+    sysbus_init_irq(dev, &uart->irq);
+
+    uart_regs = cpu_register_io_memory(grlib_apbuart_read,
+                                       grlib_apbuart_write,
+                                       uart, DEVICE_NATIVE_ENDIAN);
+    if (uart_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
+
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+    .init       = grlib_apbuart_init,
+    .qdev.name  = "grlib,apbuart",
+    .qdev.size  = sizeof(UART),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chrdev", UART, chr),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void grlib_gptimer_register(void)
+{
+    sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/qemu-0.15.x/hw/grlib_gptimer.c b/qemu-0.15.x/hw/grlib_gptimer.c
new file mode 100644
index 0000000..99e9033
--- /dev/null
+++ b/qemu-0.15.x/hw/grlib_gptimer.c
@@ -0,0 +1,394 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "sysbus.h"
+#include "qemu-timer.h"
+
+#include "trace.h"
+
+#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE      (1 << 0)
+#define GPTIMER_RESTART     (1 << 1)
+#define GPTIMER_LOAD        (1 << 2)
+#define GPTIMER_INT_ENABLE  (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET         0x00
+#define SCALER_RELOAD_OFFSET  0x04
+#define CONFIG_OFFSET         0x08
+#define COUNTER_OFFSET        0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE            0x10
+
+typedef struct GPTimer     GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer {
+    QEMUBH *bh;
+    struct ptimer_state *ptimer;
+
+    qemu_irq     irq;
+    int          id;
+    GPTimerUnit *unit;
+
+    /* registers */
+    uint32_t counter;
+    uint32_t reload;
+    uint32_t config;
+};
+
+struct GPTimerUnit {
+    SysBusDevice  busdev;
+
+    uint32_t nr_timers;         /* Number of timers available */
+    uint32_t freq_hz;           /* System frequency */
+    uint32_t irq_line;          /* Base irq line */
+
+    GPTimer *timers;
+
+    /* registers */
+    uint32_t scaler;
+    uint32_t reload;
+    uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+
+    ptimer_stop(timer->ptimer);
+
+    if (!(timer->config & GPTIMER_ENABLE)) {
+        /* Timer disabled */
+        trace_grlib_gptimer_disabled(timer->id, timer->config);
+        return;
+    }
+
+    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+       underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
+
+    ptimer_set_count(timer->ptimer, timer->counter + 1);
+    ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_restart(timer->id, timer->reload);
+
+    timer->counter = timer->reload;
+    grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+    int i = 0;
+    uint32_t value = 0;
+
+    assert(unit != NULL);
+
+    if (scaler > 0) {
+        value = unit->freq_hz / (scaler + 1);
+    } else {
+        value = unit->freq_hz;
+    }
+
+    trace_grlib_gptimer_set_scaler(scaler, value);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        ptimer_set_freq(unit->timers[i].ptimer, value);
+    }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+    GPTimer *timer = opaque;
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_hit(timer->id);
+
+    /* Timer expired */
+
+    if (timer->config & GPTIMER_INT_ENABLE) {
+        /* Set the pending bit (only unset by write in the config register) */
+        timer->config |= GPTIMER_INT_PENDING;
+        qemu_irq_pulse(timer->irq);
+    }
+
+    if (timer->config & GPTIMER_RESTART) {
+        grlib_gptimer_restart(timer);
+    }
+}
+
+static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
+{
+    GPTimerUnit        *unit  = opaque;
+    target_phys_addr_t  timer_addr;
+    int                 id;
+    uint32_t            value = 0;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
+        return unit->scaler;
+
+    case SCALER_RELOAD_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->reload);
+        return unit->reload;
+
+    case CONFIG_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->config);
+        return unit->config;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            value = ptimer_get_count(unit->timers[id].ptimer);
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case COUNTER_RELOAD_OFFSET:
+            value = unit->timers[id].reload;
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
+            return unit->timers[id].config;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_readl(-1, addr, 0);
+    return 0;
+}
+
+static void
+grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    GPTimerUnit        *unit = opaque;
+    target_phys_addr_t  timer_addr;
+    int                 id;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->scaler = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
+        return;
+
+    case SCALER_RELOAD_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->reload = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->reload);
+        grlib_gptimer_set_scaler(unit, value);
+        return;
+
+    case CONFIG_OFFSET:
+        /* Read Only (disable timer freeze not supported) */
+        trace_grlib_gptimer_writel(-1, addr, 0);
+        return;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].counter = value;
+            grlib_gptimer_enable(&unit->timers[id]);
+            return;
+
+        case COUNTER_RELOAD_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].reload = value;
+            return;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+
+            if (value & GPTIMER_INT_PENDING) {
+                /* clear pending bit */
+                value &= ~GPTIMER_INT_PENDING;
+            } else {
+                /* keep pending bit */
+                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+            }
+
+            unit->timers[id].config = value;
+
+            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
+               bits are present, we just have to call restart. */
+
+            if (value & GPTIMER_LOAD) {
+                grlib_gptimer_restart(&unit->timers[id]);
+            } else if (value & GPTIMER_ENABLE) {
+                grlib_gptimer_enable(&unit->timers[id]);
+            }
+
+            /* These fields must always be read as 0 */
+            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+            unit->timers[id].config = value;
+            return;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_writel(-1, addr, value);
+}
+
+static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
+    NULL, NULL, grlib_gptimer_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
+    NULL, NULL, grlib_gptimer_writel,
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+    int          i    = 0;
+
+    assert(unit != NULL);
+
+    unit->scaler = 0;
+    unit->reload = 0;
+    unit->config = 0;
+
+    unit->config  = unit->nr_timers;
+    unit->config |= unit->irq_line << 3;
+    unit->config |= 1 << 8;     /* separate interrupt */
+    unit->config |= 1 << 9;     /* Disable timer freeze */
+
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->counter = 0;
+        timer->reload = 0;
+        timer->config = 0;
+        ptimer_stop(timer->ptimer);
+        ptimer_set_count(timer->ptimer, 0);
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
+    unsigned int  i;
+    int           timer_regs;
+
+    assert(unit->nr_timers > 0);
+    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+
+    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->unit   = unit;
+        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
+        timer->ptimer = ptimer_init(timer->bh);
+        timer->id     = i;
+
+        /* One IRQ line for each timer */
+        sysbus_init_irq(dev, &timer->irq);
+
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+
+    timer_regs = cpu_register_io_memory(grlib_gptimer_read,
+                                        grlib_gptimer_write,
+                                        unit, DEVICE_NATIVE_ENDIAN);
+    if (timer_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
+                     timer_regs);
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+    .init       = grlib_gptimer_init,
+    .qdev.name  = "grlib,gptimer",
+    .qdev.reset = grlib_gptimer_reset,
+    .qdev.size  = sizeof(GPTimerUnit),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
+        DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
+        DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void grlib_gptimer_register(void)
+{
+    sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/qemu-0.15.x/hw/grlib_irqmp.c b/qemu-0.15.x/hw/grlib_irqmp.c
new file mode 100644
index 0000000..b8738fc
--- /dev/null
+++ b/qemu-0.15.x/hw/grlib_irqmp.c
@@ -0,0 +1,376 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "sysbus.h"
+#include "cpu.h"
+
+#include "grlib.h"
+
+#include "trace.h"
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET     0x00
+#define PENDING_OFFSET   0x04
+#define FORCE0_OFFSET    0x08
+#define CLEAR_OFFSET     0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET      0x40
+#define FORCE_OFFSET     0x80
+#define EXTENDED_OFFSET  0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP {
+    SysBusDevice busdev;
+
+    void *set_pil_in;
+    void *set_pil_in_opaque;
+
+    IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState {
+    uint32_t level;
+    uint32_t pending;
+    uint32_t clear;
+    uint32_t broadcast;
+
+    uint32_t mask[IRQMP_MAX_CPU];
+    uint32_t force[IRQMP_MAX_CPU];
+    uint32_t extended[IRQMP_MAX_CPU];
+
+    IRQMP    *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+    uint32_t      pend   = 0;
+    uint32_t      level0 = 0;
+    uint32_t      level1 = 0;
+    set_pil_in_fn set_pil_in;
+
+    assert(state != NULL);
+    assert(state->parent != NULL);
+
+    /* IRQ for CPU 0 (no SMP support) */
+    pend = (state->pending | state->force[0])
+        & state->mask[0];
+
+    level0 = pend & ~state->level;
+    level1 = pend &  state->level;
+
+    trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
+                                 state->mask[0], level1, level0);
+
+    set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
+
+    /* Trigger level1 interrupt first and level0 if there is no level1 */
+    if (level1 != 0) {
+        set_pil_in(state->parent->set_pil_in_opaque, level1);
+    } else {
+        set_pil_in(state->parent->set_pil_in_opaque, level0);
+    }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+    SysBusDevice *sdev;
+    IRQMP        *irqmp;
+    IRQMPState   *state;
+    uint32_t      mask;
+
+    assert(dev != NULL);
+
+    sdev = sysbus_from_qdev(dev);
+    assert(sdev != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
+    assert(irqmp != NULL);
+
+    state = irqmp->state;
+    assert(state != NULL);
+
+    intno &= 15;
+    mask = 1 << intno;
+
+    trace_grlib_irqmp_ack(intno);
+
+    /* Clear registers */
+    state->pending  &= ~mask;
+    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+    grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+    IRQMP      *irqmp;
+    IRQMPState *s;
+    int         i = 0;
+
+    assert(opaque != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), sysbus_from_qdev(opaque));
+    assert(irqmp != NULL);
+
+    s = irqmp->state;
+    assert(s         != NULL);
+    assert(s->parent != NULL);
+
+
+    if (level) {
+        trace_grlib_irqmp_set_irq(irq);
+
+        if (s->broadcast & 1 << irq) {
+            /* Broadcasted IRQ */
+            for (i = 0; i < IRQMP_MAX_CPU; i++) {
+                s->force[i] |= 1 << irq;
+            }
+        } else {
+            s->pending |= 1 << irq;
+        }
+        grlib_irqmp_check_irqs(s);
+
+    }
+}
+
+static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        return state->level;
+
+    case PENDING_OFFSET:
+        return state->pending;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+        return state->force[0];
+
+    case CLEAR_OFFSET:
+    case MP_STATUS_OFFSET:
+        /* Always read as 0 */
+        return 0;
+
+    case BROADCAST_OFFSET:
+        return state->broadcast;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->mask[cpu];
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->force[cpu];
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->extended[cpu];
+    }
+
+    trace_grlib_irqmp_readl_unknown(addr);
+    return 0;
+}
+
+static void
+grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        value &= 0xFFFF << 1; /* clean up the value */
+        state->level = value;
+        return;
+
+    case PENDING_OFFSET:
+        /* Read Only */
+        return;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+
+        value &= 0xFFFE; /* clean up the value */
+        state->force[0] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+
+    case CLEAR_OFFSET:
+        value &= ~1; /* clean up the value */
+        state->pending &= ~value;
+        return;
+
+    case MP_STATUS_OFFSET:
+        /* Read Only (no SMP support) */
+        return;
+
+    case BROADCAST_OFFSET:
+        value &= 0xFFFE; /* clean up the value */
+        state->broadcast = value;
+        return;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= ~1; /* clean up the value */
+        state->mask[cpu] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        uint32_t force = value & 0xFFFE;
+        uint32_t clear = (value >> 16) & 0xFFFE;
+        uint32_t old   = state->force[cpu];
+
+        state->force[cpu] = (old | force) & ~clear;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= 0xF; /* clean up the value */
+        state->extended[cpu] = value;
+        return;
+    }
+
+    trace_grlib_irqmp_writel_unknown(addr, value);
+}
+
+static CPUReadMemoryFunc * const grlib_irqmp_read[] = {
+    NULL, NULL, &grlib_irqmp_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_irqmp_write[] = {
+    NULL, NULL, &grlib_irqmp_writel,
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+    assert(irqmp        != NULL);
+    assert(irqmp->state != NULL);
+
+    memset(irqmp->state, 0, sizeof *irqmp->state);
+    irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+    IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
+    int    irqmp_regs;
+
+    assert(irqmp != NULL);
+
+    /* Check parameters */
+    if (irqmp->set_pil_in == NULL) {
+        return -1;
+    }
+
+    irqmp_regs = cpu_register_io_memory(grlib_irqmp_read,
+                                        grlib_irqmp_write,
+                                        irqmp, DEVICE_NATIVE_ENDIAN);
+
+    irqmp->state = qemu_mallocz(sizeof *irqmp->state);
+
+    if (irqmp_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, IRQMP_REG_SIZE, irqmp_regs);
+
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_irqmp_info = {
+    .init = grlib_irqmp_init,
+    .qdev.name  = "grlib,irqmp",
+    .qdev.reset = grlib_irqmp_reset,
+    .qdev.size  = sizeof(IRQMP),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+        DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void grlib_irqmp_register(void)
+{
+    sysbus_register_withprop(&grlib_irqmp_info);
+}
+
+device_init(grlib_irqmp_register)
diff --git a/qemu-0.15.x/hw/gt64xxx.c b/qemu-0.15.x/hw/gt64xxx.c
new file mode 100644
index 0000000..8e1f6a0
--- /dev/null
+++ b/qemu-0.15.x/hw/gt64xxx.c
@@ -0,0 +1,1153 @@
+/*
+ * QEMU GT64120 PCI host
+ *
+ * Copyright (c) 2006,2007 Aurelien Jarno
+ *
+ * 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 "hw.h"
+#include "mips.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "pc.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define GT_REGS			(0x1000 >> 2)
+
+/* CPU Configuration */
+#define GT_CPU    		(0x000 >> 2)
+#define GT_MULTI    		(0x120 >> 2)
+
+/* CPU Address Decode */
+#define GT_SCS10LD    		(0x008 >> 2)
+#define GT_SCS10HD    		(0x010 >> 2)
+#define GT_SCS32LD    		(0x018 >> 2)
+#define GT_SCS32HD    		(0x020 >> 2)
+#define GT_CS20LD    		(0x028 >> 2)
+#define GT_CS20HD    		(0x030 >> 2)
+#define GT_CS3BOOTLD    	(0x038 >> 2)
+#define GT_CS3BOOTHD    	(0x040 >> 2)
+#define GT_PCI0IOLD    		(0x048 >> 2)
+#define GT_PCI0IOHD    		(0x050 >> 2)
+#define GT_PCI0M0LD    		(0x058 >> 2)
+#define GT_PCI0M0HD    		(0x060 >> 2)
+#define GT_PCI0M1LD    		(0x080 >> 2)
+#define GT_PCI0M1HD    		(0x088 >> 2)
+#define GT_PCI1IOLD    		(0x090 >> 2)
+#define GT_PCI1IOHD    		(0x098 >> 2)
+#define GT_PCI1M0LD    		(0x0a0 >> 2)
+#define GT_PCI1M0HD    		(0x0a8 >> 2)
+#define GT_PCI1M1LD    		(0x0b0 >> 2)
+#define GT_PCI1M1HD    		(0x0b8 >> 2)
+#define GT_ISD    		(0x068 >> 2)
+
+#define GT_SCS10AR    		(0x0d0 >> 2)
+#define GT_SCS32AR    		(0x0d8 >> 2)
+#define GT_CS20R    		(0x0e0 >> 2)
+#define GT_CS3BOOTR    		(0x0e8 >> 2)
+
+#define GT_PCI0IOREMAP    	(0x0f0 >> 2)
+#define GT_PCI0M0REMAP    	(0x0f8 >> 2)
+#define GT_PCI0M1REMAP    	(0x100 >> 2)
+#define GT_PCI1IOREMAP    	(0x108 >> 2)
+#define GT_PCI1M0REMAP    	(0x110 >> 2)
+#define GT_PCI1M1REMAP    	(0x118 >> 2)
+
+/* CPU Error Report */
+#define GT_CPUERR_ADDRLO    	(0x070 >> 2)
+#define GT_CPUERR_ADDRHI    	(0x078 >> 2)
+#define GT_CPUERR_DATALO    	(0x128 >> 2)		/* GT-64120A only  */
+#define GT_CPUERR_DATAHI    	(0x130 >> 2)		/* GT-64120A only  */
+#define GT_CPUERR_PARITY    	(0x138 >> 2)		/* GT-64120A only  */
+
+/* CPU Sync Barrier */
+#define GT_PCI0SYNC    		(0x0c0 >> 2)
+#define GT_PCI1SYNC    		(0x0c8 >> 2)
+
+/* SDRAM and Device Address Decode */
+#define GT_SCS0LD    		(0x400 >> 2)
+#define GT_SCS0HD    		(0x404 >> 2)
+#define GT_SCS1LD    		(0x408 >> 2)
+#define GT_SCS1HD    		(0x40c >> 2)
+#define GT_SCS2LD    		(0x410 >> 2)
+#define GT_SCS2HD    		(0x414 >> 2)
+#define GT_SCS3LD    		(0x418 >> 2)
+#define GT_SCS3HD    		(0x41c >> 2)
+#define GT_CS0LD    		(0x420 >> 2)
+#define GT_CS0HD    		(0x424 >> 2)
+#define GT_CS1LD    		(0x428 >> 2)
+#define GT_CS1HD    		(0x42c >> 2)
+#define GT_CS2LD    		(0x430 >> 2)
+#define GT_CS2HD    		(0x434 >> 2)
+#define GT_CS3LD    		(0x438 >> 2)
+#define GT_CS3HD    		(0x43c >> 2)
+#define GT_BOOTLD    		(0x440 >> 2)
+#define GT_BOOTHD    		(0x444 >> 2)
+#define GT_ADERR    		(0x470 >> 2)
+
+/* SDRAM Configuration */
+#define GT_SDRAM_CFG    	(0x448 >> 2)
+#define GT_SDRAM_OPMODE    	(0x474 >> 2)
+#define GT_SDRAM_BM    		(0x478 >> 2)
+#define GT_SDRAM_ADDRDECODE    	(0x47c >> 2)
+
+/* SDRAM Parameters */
+#define GT_SDRAM_B0    		(0x44c >> 2)
+#define GT_SDRAM_B1    		(0x450 >> 2)
+#define GT_SDRAM_B2    		(0x454 >> 2)
+#define GT_SDRAM_B3    		(0x458 >> 2)
+
+/* Device Parameters */
+#define GT_DEV_B0    		(0x45c >> 2)
+#define GT_DEV_B1    		(0x460 >> 2)
+#define GT_DEV_B2    		(0x464 >> 2)
+#define GT_DEV_B3    		(0x468 >> 2)
+#define GT_DEV_BOOT    		(0x46c >> 2)
+
+/* ECC */
+#define GT_ECC_ERRDATALO	(0x480 >> 2)		/* GT-64120A only  */
+#define GT_ECC_ERRDATAHI	(0x484 >> 2)		/* GT-64120A only  */
+#define GT_ECC_MEM		(0x488 >> 2)		/* GT-64120A only  */
+#define GT_ECC_CALC		(0x48c >> 2)		/* GT-64120A only  */
+#define GT_ECC_ERRADDR		(0x490 >> 2)		/* GT-64120A only  */
+
+/* DMA Record */
+#define GT_DMA0_CNT    		(0x800 >> 2)
+#define GT_DMA1_CNT    		(0x804 >> 2)
+#define GT_DMA2_CNT    		(0x808 >> 2)
+#define GT_DMA3_CNT    		(0x80c >> 2)
+#define GT_DMA0_SA    		(0x810 >> 2)
+#define GT_DMA1_SA    		(0x814 >> 2)
+#define GT_DMA2_SA    		(0x818 >> 2)
+#define GT_DMA3_SA    		(0x81c >> 2)
+#define GT_DMA0_DA    		(0x820 >> 2)
+#define GT_DMA1_DA    		(0x824 >> 2)
+#define GT_DMA2_DA    		(0x828 >> 2)
+#define GT_DMA3_DA    		(0x82c >> 2)
+#define GT_DMA0_NEXT    	(0x830 >> 2)
+#define GT_DMA1_NEXT    	(0x834 >> 2)
+#define GT_DMA2_NEXT    	(0x838 >> 2)
+#define GT_DMA3_NEXT    	(0x83c >> 2)
+#define GT_DMA0_CUR    		(0x870 >> 2)
+#define GT_DMA1_CUR    		(0x874 >> 2)
+#define GT_DMA2_CUR    		(0x878 >> 2)
+#define GT_DMA3_CUR    		(0x87c >> 2)
+
+/* DMA Channel Control */
+#define GT_DMA0_CTRL    	(0x840 >> 2)
+#define GT_DMA1_CTRL    	(0x844 >> 2)
+#define GT_DMA2_CTRL    	(0x848 >> 2)
+#define GT_DMA3_CTRL    	(0x84c >> 2)
+
+/* DMA Arbiter */
+#define GT_DMA_ARB    		(0x860 >> 2)
+
+/* Timer/Counter */
+#define GT_TC0    		(0x850 >> 2)
+#define GT_TC1    		(0x854 >> 2)
+#define GT_TC2    		(0x858 >> 2)
+#define GT_TC3    		(0x85c >> 2)
+#define GT_TC_CONTROL    	(0x864 >> 2)
+
+/* PCI Internal */
+#define GT_PCI0_CMD    		(0xc00 >> 2)
+#define GT_PCI0_TOR    		(0xc04 >> 2)
+#define GT_PCI0_BS_SCS10    	(0xc08 >> 2)
+#define GT_PCI0_BS_SCS32    	(0xc0c >> 2)
+#define GT_PCI0_BS_CS20    	(0xc10 >> 2)
+#define GT_PCI0_BS_CS3BT    	(0xc14 >> 2)
+#define GT_PCI1_IACK    	(0xc30 >> 2)
+#define GT_PCI0_IACK    	(0xc34 >> 2)
+#define GT_PCI0_BARE    	(0xc3c >> 2)
+#define GT_PCI0_PREFMBR    	(0xc40 >> 2)
+#define GT_PCI0_SCS10_BAR    	(0xc48 >> 2)
+#define GT_PCI0_SCS32_BAR    	(0xc4c >> 2)
+#define GT_PCI0_CS20_BAR    	(0xc50 >> 2)
+#define GT_PCI0_CS3BT_BAR    	(0xc54 >> 2)
+#define GT_PCI0_SSCS10_BAR    	(0xc58 >> 2)
+#define GT_PCI0_SSCS32_BAR    	(0xc5c >> 2)
+#define GT_PCI0_SCS3BT_BAR    	(0xc64 >> 2)
+#define GT_PCI1_CMD    		(0xc80 >> 2)
+#define GT_PCI1_TOR    		(0xc84 >> 2)
+#define GT_PCI1_BS_SCS10    	(0xc88 >> 2)
+#define GT_PCI1_BS_SCS32    	(0xc8c >> 2)
+#define GT_PCI1_BS_CS20    	(0xc90 >> 2)
+#define GT_PCI1_BS_CS3BT    	(0xc94 >> 2)
+#define GT_PCI1_BARE    	(0xcbc >> 2)
+#define GT_PCI1_PREFMBR    	(0xcc0 >> 2)
+#define GT_PCI1_SCS10_BAR    	(0xcc8 >> 2)
+#define GT_PCI1_SCS32_BAR    	(0xccc >> 2)
+#define GT_PCI1_CS20_BAR    	(0xcd0 >> 2)
+#define GT_PCI1_CS3BT_BAR    	(0xcd4 >> 2)
+#define GT_PCI1_SSCS10_BAR    	(0xcd8 >> 2)
+#define GT_PCI1_SSCS32_BAR    	(0xcdc >> 2)
+#define GT_PCI1_SCS3BT_BAR    	(0xce4 >> 2)
+#define GT_PCI1_CFGADDR    	(0xcf0 >> 2)
+#define GT_PCI1_CFGDATA    	(0xcf4 >> 2)
+#define GT_PCI0_CFGADDR    	(0xcf8 >> 2)
+#define GT_PCI0_CFGDATA    	(0xcfc >> 2)
+
+/* Interrupts */
+#define GT_INTRCAUSE    	(0xc18 >> 2)
+#define GT_INTRMASK    		(0xc1c >> 2)
+#define GT_PCI0_ICMASK    	(0xc24 >> 2)
+#define GT_PCI0_SERR0MASK    	(0xc28 >> 2)
+#define GT_CPU_INTSEL    	(0xc70 >> 2)
+#define GT_PCI0_INTSEL    	(0xc74 >> 2)
+#define GT_HINTRCAUSE    	(0xc98 >> 2)
+#define GT_HINTRMASK    	(0xc9c >> 2)
+#define GT_PCI0_HICMASK    	(0xca4 >> 2)
+#define GT_PCI1_SERR1MASK    	(0xca8 >> 2)
+
+#define PCI_MAPPING_ENTRY(regname)            \
+    target_phys_addr_t regname ##_start;      \
+    target_phys_addr_t regname ##_length;     \
+    int regname ##_handle
+
+typedef struct GT64120State {
+    SysBusDevice busdev;
+    PCIHostState pci;
+    uint32_t regs[GT_REGS];
+    PCI_MAPPING_ENTRY(PCI0IO);
+    PCI_MAPPING_ENTRY(ISD);
+} GT64120State;
+
+/* Adjust range to avoid touching space which isn't mappable via PCI */
+/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000
+                                    0x1fc00000 - 0x1fd00000  */
+static void check_reserved_space (target_phys_addr_t *start,
+                                  target_phys_addr_t *length)
+{
+    target_phys_addr_t begin = *start;
+    target_phys_addr_t end = *start + *length;
+
+    if (end >= 0x1e000000LL && end < 0x1f100000LL)
+        end = 0x1e000000LL;
+    if (begin >= 0x1e000000LL && begin < 0x1f100000LL)
+        begin = 0x1f100000LL;
+    if (end >= 0x1fc00000LL && end < 0x1fd00000LL)
+        end = 0x1fc00000LL;
+    if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL)
+        begin = 0x1fd00000LL;
+    /* XXX: This is broken when a reserved range splits the requested range */
+    if (end >= 0x1f100000LL && begin < 0x1e000000LL)
+        end = 0x1e000000LL;
+    if (end >= 0x1fd00000LL && begin < 0x1fc00000LL)
+        end = 0x1fc00000LL;
+
+    *start = begin;
+    *length = end - begin;
+}
+
+static void gt64120_isd_mapping(GT64120State *s)
+{
+    target_phys_addr_t start = s->regs[GT_ISD] << 21;
+    target_phys_addr_t length = 0x1000;
+
+    if (s->ISD_length)
+        cpu_register_physical_memory(s->ISD_start, s->ISD_length,
+                                     IO_MEM_UNASSIGNED);
+    check_reserved_space(&start, &length);
+    length = 0x1000;
+    /* Map new address */
+    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx" -> "TARGET_FMT_plx"@"TARGET_FMT_plx", %x\n", s->ISD_length, s->ISD_start,
+            length, start, s->ISD_handle);
+    s->ISD_start = start;
+    s->ISD_length = length;
+    cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle);
+}
+
+static void gt64120_pci_mapping(GT64120State *s)
+{
+    /* Update IO mapping */
+    if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
+    {
+      /* Unmap old IO address */
+      if (s->PCI0IO_length)
+      {
+        cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED);
+      }
+      /* Map new IO address */
+      s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
+      s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
+      isa_mem_base = s->PCI0IO_start;
+      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
+    }
+}
+
+static void gt64120_writel (void *opaque, target_phys_addr_t addr,
+                            uint32_t val)
+{
+    GT64120State *s = opaque;
+    uint32_t saddr;
+
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
+
+    saddr = (addr & 0xfff) >> 2;
+    switch (saddr) {
+
+    /* CPU Configuration */
+    case GT_CPU:
+        s->regs[GT_CPU] = val;
+        break;
+    case GT_MULTI:
+	/* Read-only register as only one GT64xxx is present on the CPU bus */
+        break;
+
+    /* CPU Address Decode */
+    case GT_PCI0IOLD:
+        s->regs[GT_PCI0IOLD]    = val & 0x00007fff;
+        s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
+        gt64120_pci_mapping(s);
+        break;
+    case GT_PCI0M0LD:
+        s->regs[GT_PCI0M0LD]    = val & 0x00007fff;
+        s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI0M1LD:
+        s->regs[GT_PCI0M1LD]    = val & 0x00007fff;
+        s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1IOLD:
+        s->regs[GT_PCI1IOLD]    = val & 0x00007fff;
+        s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1M0LD:
+        s->regs[GT_PCI1M0LD]    = val & 0x00007fff;
+        s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1M1LD:
+        s->regs[GT_PCI1M1LD]    = val & 0x00007fff;
+        s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI0IOHD:
+        s->regs[saddr] = val & 0x0000007f;
+        gt64120_pci_mapping(s);
+        break;
+    case GT_PCI0M0HD:
+    case GT_PCI0M1HD:
+    case GT_PCI1IOHD:
+    case GT_PCI1M0HD:
+    case GT_PCI1M1HD:
+        s->regs[saddr] = val & 0x0000007f;
+        break;
+    case GT_ISD:
+        s->regs[saddr] = val & 0x00007fff;
+        gt64120_isd_mapping(s);
+        break;
+
+    case GT_PCI0IOREMAP:
+    case GT_PCI0M0REMAP:
+    case GT_PCI0M1REMAP:
+    case GT_PCI1IOREMAP:
+    case GT_PCI1M0REMAP:
+    case GT_PCI1M1REMAP:
+        s->regs[saddr] = val & 0x000007ff;
+        break;
+
+    /* CPU Error Report */
+    case GT_CPUERR_ADDRLO:
+    case GT_CPUERR_ADDRHI:
+    case GT_CPUERR_DATALO:
+    case GT_CPUERR_DATAHI:
+    case GT_CPUERR_PARITY:
+	/* Read-only registers, do nothing */
+        break;
+
+    /* CPU Sync Barrier */
+    case GT_PCI0SYNC:
+    case GT_PCI1SYNC:
+	/* Read-only registers, do nothing */
+        break;
+
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        /* Accept and ignore SDRAM interleave configuration */
+        s->regs[saddr] = val;
+        break;
+
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        /* Not implemented */
+        DPRINTF ("Unimplemented device register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* ECC */
+    case GT_ECC_ERRDATALO:
+    case GT_ECC_ERRDATAHI:
+    case GT_ECC_MEM:
+    case GT_ECC_CALC:
+    case GT_ECC_ERRADDR:
+        /* Read-only registers, do nothing */
+        break;
+
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        /* Not implemented */
+        DPRINTF ("Unimplemented timer register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* PCI Internal */
+    case GT_PCI0_CMD:
+    case GT_PCI1_CMD:
+        s->regs[saddr] = val & 0x0401fc0f;
+        break;
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        /* not implemented */
+        break;
+    case GT_PCI0_CFGADDR:
+        s->pci.config_reg = val & 0x80fffffc;
+        break;
+    case GT_PCI0_CFGDATA:
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+            val = bswap32(val);
+        if (s->pci.config_reg & (1u << 31))
+            pci_data_write(s->pci.bus, s->pci.config_reg, val, 4);
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        /* not really implemented */
+        s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
+        s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
+        DPRINTF("INTRCAUSE %x\n", val);
+        break;
+    case GT_INTRMASK:
+        s->regs[saddr] = val & 0x3c3ffffe;
+        DPRINTF("INTRMASK %x\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        s->regs[saddr] = val & 0x03fffffe;
+        DPRINTF("ICMASK %x\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        s->regs[saddr] = val & 0x0000003f;
+        DPRINTF("SERR0MASK %x\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        /* not implemented */
+        break;
+
+    /* SDRAM Parameters */
+    case GT_SDRAM_B0:
+    case GT_SDRAM_B1:
+    case GT_SDRAM_B2:
+    case GT_SDRAM_B3:
+        /* We don't simulate electrical parameters of the SDRAM.
+           Accept, but ignore the values. */
+        s->regs[saddr] = val;
+        break;
+
+    default:
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
+        break;
+    }
+}
+
+static uint32_t gt64120_readl (void *opaque,
+                               target_phys_addr_t addr)
+{
+    GT64120State *s = opaque;
+    uint32_t val;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfff) >> 2;
+    switch (saddr) {
+
+    /* CPU Configuration */
+    case GT_MULTI:
+        /* Only one GT64xxx is present on the CPU bus, return
+           the initial value */
+        val = s->regs[saddr];
+        break;
+
+    /* CPU Error Report */
+    case GT_CPUERR_ADDRLO:
+    case GT_CPUERR_ADDRHI:
+    case GT_CPUERR_DATALO:
+    case GT_CPUERR_DATAHI:
+    case GT_CPUERR_PARITY:
+        /* Emulated memory has no error, always return the initial
+           values */
+        val = s->regs[saddr];
+        break;
+
+    /* CPU Sync Barrier */
+    case GT_PCI0SYNC:
+    case GT_PCI1SYNC:
+        /* Reading those register should empty all FIFO on the PCI
+           bus, which are not emulated. The return value should be
+           a random value that should be ignored. */
+        val = 0xc000ffee;
+        break;
+
+    /* ECC */
+    case GT_ECC_ERRDATALO:
+    case GT_ECC_ERRDATAHI:
+    case GT_ECC_MEM:
+    case GT_ECC_CALC:
+    case GT_ECC_ERRADDR:
+        /* Emulated memory has no error, always return the initial
+           values */
+        val = s->regs[saddr];
+        break;
+
+    case GT_CPU:
+    case GT_SCS10LD:
+    case GT_SCS10HD:
+    case GT_SCS32LD:
+    case GT_SCS32HD:
+    case GT_CS20LD:
+    case GT_CS20HD:
+    case GT_CS3BOOTLD:
+    case GT_CS3BOOTHD:
+    case GT_SCS10AR:
+    case GT_SCS32AR:
+    case GT_CS20R:
+    case GT_CS3BOOTR:
+    case GT_PCI0IOLD:
+    case GT_PCI0M0LD:
+    case GT_PCI0M1LD:
+    case GT_PCI1IOLD:
+    case GT_PCI1M0LD:
+    case GT_PCI1M1LD:
+    case GT_PCI0IOHD:
+    case GT_PCI0M0HD:
+    case GT_PCI0M1HD:
+    case GT_PCI1IOHD:
+    case GT_PCI1M0HD:
+    case GT_PCI1M1HD:
+    case GT_PCI0IOREMAP:
+    case GT_PCI0M0REMAP:
+    case GT_PCI0M1REMAP:
+    case GT_PCI1IOREMAP:
+    case GT_PCI1M0REMAP:
+    case GT_PCI1M1REMAP:
+    case GT_ISD:
+        val = s->regs[saddr];
+        break;
+    case GT_PCI0_IACK:
+        /* Read the IRQ number */
+        val = pic_read_irq(isa_pic);
+        break;
+
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+        val = s->regs[saddr];
+        break;
+
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        val = s->regs[saddr];
+        break;
+
+    /* SDRAM Parameters */
+    case GT_SDRAM_B0:
+    case GT_SDRAM_B1:
+    case GT_SDRAM_B2:
+    case GT_SDRAM_B3:
+        /* We don't simulate electrical parameters of the SDRAM.
+           Just return the last written value. */
+        val = s->regs[saddr];
+        break;
+
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        val = s->regs[saddr];
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        val = s->regs[saddr];
+        break;
+
+    /* PCI Internal */
+    case GT_PCI0_CFGADDR:
+        val = s->pci.config_reg;
+        break;
+    case GT_PCI0_CFGDATA:
+        if (!(s->pci.config_reg & (1 << 31)))
+            val = 0xffffffff;
+        else
+            val = pci_data_read(s->pci.bus, s->pci.config_reg, 4);
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+            val = bswap32(val);
+        break;
+
+    case GT_PCI0_CMD:
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_CMD:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        val = s->regs[saddr];
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        val = s->regs[saddr];
+        DPRINTF("INTRCAUSE %x\n", val);
+        break;
+    case GT_INTRMASK:
+        val = s->regs[saddr];
+        DPRINTF("INTRMASK %x\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        val = s->regs[saddr];
+        DPRINTF("ICMASK %x\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        val = s->regs[saddr];
+        DPRINTF("SERR0MASK %x\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        val = s->regs[saddr];
+        break;
+
+    default:
+        val = s->regs[saddr];
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
+        break;
+    }
+
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
+
+    return val;
+}
+
+static CPUWriteMemoryFunc * const gt64120_write[] = {
+    &gt64120_writel,
+    &gt64120_writel,
+    &gt64120_writel,
+};
+
+static CPUReadMemoryFunc * const gt64120_read[] = {
+    &gt64120_readl,
+    &gt64120_readl,
+    &gt64120_readl,
+};
+
+static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot;
+
+    slot = (pci_dev->devfn >> 3);
+
+    switch (slot) {
+      /* PIIX4 USB */
+      case 10:
+        return 3;
+      /* AMD 79C973 Ethernet */
+      case 11:
+        return 1;
+      /* Crystal 4281 Sound */
+      case 12:
+        return 2;
+      /* PCI slot 1 to 4 */
+      case 18 ... 21:
+        return ((slot - 18) + irq_num) & 0x03;
+      /* Unknown device, don't do any translation */
+      default:
+        return irq_num;
+    }
+}
+
+static int pci_irq_levels[4];
+
+static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    int i, pic_irq, pic_level;
+    qemu_irq *pic = opaque;
+
+    pci_irq_levels[irq_num] = level;
+
+    /* now we change the pic irq level according to the piix irq mappings */
+    /* XXX: optimize */
+    pic_irq = piix4_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 == piix4_dev->config[0x60 + i])
+                pic_level |= pci_irq_levels[i];
+        }
+        qemu_set_irq(pic[pic_irq], pic_level);
+    }
+}
+
+
+static void gt64120_reset(void *opaque)
+{
+    GT64120State *s = opaque;
+
+    /* FIXME: Malta specific hw assumptions ahead */
+
+    /* CPU Configuration */
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_CPU]           = 0x00000000;
+#else
+    s->regs[GT_CPU]           = 0x00001000;
+#endif
+    s->regs[GT_MULTI]         = 0x00000003;
+
+    /* CPU Address decode */
+    s->regs[GT_SCS10LD]       = 0x00000000;
+    s->regs[GT_SCS10HD]       = 0x00000007;
+    s->regs[GT_SCS32LD]       = 0x00000008;
+    s->regs[GT_SCS32HD]       = 0x0000000f;
+    s->regs[GT_CS20LD]        = 0x000000e0;
+    s->regs[GT_CS20HD]        = 0x00000070;
+    s->regs[GT_CS3BOOTLD]     = 0x000000f8;
+    s->regs[GT_CS3BOOTHD]     = 0x0000007f;
+
+    s->regs[GT_PCI0IOLD]      = 0x00000080;
+    s->regs[GT_PCI0IOHD]      = 0x0000000f;
+    s->regs[GT_PCI0M0LD]      = 0x00000090;
+    s->regs[GT_PCI0M0HD]      = 0x0000001f;
+    s->regs[GT_ISD]           = 0x000000a0;
+    s->regs[GT_PCI0M1LD]      = 0x00000790;
+    s->regs[GT_PCI0M1HD]      = 0x0000001f;
+    s->regs[GT_PCI1IOLD]      = 0x00000100;
+    s->regs[GT_PCI1IOHD]      = 0x0000000f;
+    s->regs[GT_PCI1M0LD]      = 0x00000110;
+    s->regs[GT_PCI1M0HD]      = 0x0000001f;
+    s->regs[GT_PCI1M1LD]      = 0x00000120;
+    s->regs[GT_PCI1M1HD]      = 0x0000002f;
+
+    s->regs[GT_SCS10AR]       = 0x00000000;
+    s->regs[GT_SCS32AR]       = 0x00000008;
+    s->regs[GT_CS20R]         = 0x000000e0;
+    s->regs[GT_CS3BOOTR]      = 0x000000f8;
+
+    s->regs[GT_PCI0IOREMAP]   = 0x00000080;
+    s->regs[GT_PCI0M0REMAP]   = 0x00000090;
+    s->regs[GT_PCI0M1REMAP]   = 0x00000790;
+    s->regs[GT_PCI1IOREMAP]   = 0x00000100;
+    s->regs[GT_PCI1M0REMAP]   = 0x00000110;
+    s->regs[GT_PCI1M1REMAP]   = 0x00000120;
+
+    /* CPU Error Report */
+    s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
+    s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
+    s->regs[GT_CPUERR_DATALO] = 0xffffffff;
+    s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
+    s->regs[GT_CPUERR_PARITY] = 0x000000ff;
+
+    /* CPU Sync Barrier */
+    s->regs[GT_PCI0SYNC]      = 0x00000000;
+    s->regs[GT_PCI1SYNC]      = 0x00000000;
+
+    /* SDRAM and Device Address Decode */
+    s->regs[GT_SCS0LD]        = 0x00000000;
+    s->regs[GT_SCS0HD]        = 0x00000007;
+    s->regs[GT_SCS1LD]        = 0x00000008;
+    s->regs[GT_SCS1HD]        = 0x0000000f;
+    s->regs[GT_SCS2LD]        = 0x00000010;
+    s->regs[GT_SCS2HD]        = 0x00000017;
+    s->regs[GT_SCS3LD]        = 0x00000018;
+    s->regs[GT_SCS3HD]        = 0x0000001f;
+    s->regs[GT_CS0LD]         = 0x000000c0;
+    s->regs[GT_CS0HD]         = 0x000000c7;
+    s->regs[GT_CS1LD]         = 0x000000c8;
+    s->regs[GT_CS1HD]         = 0x000000cf;
+    s->regs[GT_CS2LD]         = 0x000000d0;
+    s->regs[GT_CS2HD]         = 0x000000df;
+    s->regs[GT_CS3LD]         = 0x000000f0;
+    s->regs[GT_CS3HD]         = 0x000000fb;
+    s->regs[GT_BOOTLD]        = 0x000000fc;
+    s->regs[GT_BOOTHD]        = 0x000000ff;
+    s->regs[GT_ADERR]         = 0xffffffff;
+
+    /* SDRAM Configuration */
+    s->regs[GT_SDRAM_CFG]     = 0x00000200;
+    s->regs[GT_SDRAM_OPMODE]  = 0x00000000;
+    s->regs[GT_SDRAM_BM]      = 0x00000007;
+    s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002;
+
+    /* SDRAM Parameters */
+    s->regs[GT_SDRAM_B0]      = 0x00000005;
+    s->regs[GT_SDRAM_B1]      = 0x00000005;
+    s->regs[GT_SDRAM_B2]      = 0x00000005;
+    s->regs[GT_SDRAM_B3]      = 0x00000005;
+
+    /* ECC */
+    s->regs[GT_ECC_ERRDATALO] = 0x00000000;
+    s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
+    s->regs[GT_ECC_MEM]       = 0x00000000;
+    s->regs[GT_ECC_CALC]      = 0x00000000;
+    s->regs[GT_ECC_ERRADDR]   = 0x00000000;
+
+    /* Device Parameters */
+    s->regs[GT_DEV_B0]        = 0x386fffff;
+    s->regs[GT_DEV_B1]        = 0x386fffff;
+    s->regs[GT_DEV_B2]        = 0x386fffff;
+    s->regs[GT_DEV_B3]        = 0x386fffff;
+    s->regs[GT_DEV_BOOT]      = 0x146fffff;
+
+    /* DMA registers are all zeroed at reset */
+
+    /* Timer/Counter */
+    s->regs[GT_TC0]           = 0xffffffff;
+    s->regs[GT_TC1]           = 0x00ffffff;
+    s->regs[GT_TC2]           = 0x00ffffff;
+    s->regs[GT_TC3]           = 0x00ffffff;
+    s->regs[GT_TC_CONTROL]    = 0x00000000;
+
+    /* PCI Internal */
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_PCI0_CMD]      = 0x00000000;
+#else
+    s->regs[GT_PCI0_CMD]      = 0x00010001;
+#endif
+    s->regs[GT_PCI0_TOR]      = 0x0000070f;
+    s->regs[GT_PCI0_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI0_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI0_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_BARE]     = 0x0000000f;
+    s->regs[GT_PCI0_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI0_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000;
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_PCI1_CMD]      = 0x00000000;
+#else
+    s->regs[GT_PCI1_CMD]      = 0x00010001;
+#endif
+    s->regs[GT_PCI1_TOR]      = 0x0000070f;
+    s->regs[GT_PCI1_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI1_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI1_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_BARE]     = 0x0000000f;
+    s->regs[GT_PCI1_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI1_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_CFGADDR]  = 0x00000000;
+    s->regs[GT_PCI1_CFGDATA]  = 0x00000000;
+    s->regs[GT_PCI0_CFGADDR]  = 0x00000000;
+
+    /* Interrupt registers are all zeroed at reset */
+
+    gt64120_isd_mapping(s);
+    gt64120_pci_mapping(s);
+}
+
+PCIBus *gt64120_register(qemu_irq *pic)
+{
+    SysBusDevice *s;
+    GT64120State *d;
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "gt64120");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(GT64120State, s);
+    d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                  gt64120_pci_set_irq, gt64120_pci_map_irq,
+                                  pic, PCI_DEVFN(18, 0), 4);
+    d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
+                                           DEVICE_NATIVE_ENDIAN);
+
+    pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
+    return d->pci.bus;
+}
+
+static int gt64120_init(SysBusDevice *dev)
+{
+    GT64120State *s;
+
+    s = FROM_SYSBUS(GT64120State, dev);
+
+    /* FIXME: This value is computed from registers during reset, but some
+       devices (e.g. VGA card) need to know it when they are registered.
+       This also mean that changing the register to change the mapping
+       does not fully work. */
+    isa_mem_base = 0x10000000;
+    qemu_register_reset(gt64120_reset, s);
+    return 0;
+}
+
+static int gt64120_pci_init(PCIDevice *d)
+{
+    /* FIXME: Malta specific hw assumptions ahead */
+    pci_set_word(d->config + PCI_COMMAND, 0);
+    pci_set_word(d->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_config_set_prog_interface(d->config, 0);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
+    pci_set_byte(d->config + 0x3d, 0x01);
+
+    return 0;
+}
+
+static PCIDeviceInfo gt64120_pci_info = {
+    .qdev.name = "gt64120_pci",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = gt64120_pci_init,
+    .vendor_id = PCI_VENDOR_ID_MARVELL,
+    .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
+    .revision  = 0x10,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static void gt64120_pci_register_devices(void)
+{
+    sysbus_register_dev("gt64120", sizeof(GT64120State),
+                        gt64120_init);
+    pci_qdev_register(&gt64120_pci_info);
+}
+
+device_init(gt64120_pci_register_devices)
diff --git a/qemu-0.15.x/hw/gumstix.c b/qemu-0.15.x/hw/gumstix.c
new file mode 100644
index 0000000..853f7e1
--- /dev/null
+++ b/qemu-0.15.x/hw/gumstix.c
@@ -0,0 +1,140 @@
+/*
+ * Gumstix Platforms
+ *
+ * Copyright (c) 2007 by Thorsten Zitterell <info at bitmux.org>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+ 
+/* 
+ * Example usage:
+ * 
+ * connex:
+ * =======
+ * create image:
+ * # dd of=flash bs=1k count=16k if=/dev/zero
+ * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
+ * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
+ * start it:
+ * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
+ *
+ * verdex:
+ * =======
+ * create image:
+ * # dd of=flash bs=1k count=32k if=/dev/zero
+ * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
+ * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
+ * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
+ * start it:
+ * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "net.h"
+#include "flash.h"
+#include "devices.h"
+#include "boards.h"
+#include "blockdev.h"
+
+static const int sector_len = 128 * 1024;
+
+static void connex_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    PXA2xxState *cpu;
+    DriveInfo *dinfo;
+    int be;
+
+    uint32_t connex_rom = 0x01000000;
+    uint32_t connex_ram = 0x04000000;
+
+    cpu = pxa255_init(connex_ram);
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "A flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "connext.rom",
+                                                          connex_rom),
+                               dinfo->bdrv, sector_len, connex_rom / sector_len,
+                               2, 0, 0, 0, 0, be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* Interrupt line of NIC is connected to GPIO line 36 */
+    smc91c111_init(&nd_table[0], 0x04000300,
+                    qdev_get_gpio_in(cpu->gpio, 36));
+}
+
+static void verdex_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    PXA2xxState *cpu;
+    DriveInfo *dinfo;
+    int be;
+
+    uint32_t verdex_rom = 0x02000000;
+    uint32_t verdex_ram = 0x10000000;
+
+    cpu = pxa270_init(verdex_ram, cpu_model ?: "pxa270-c0");
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "A flash image must be given with the "
+                "'pflash' parameter\n");
+        exit(1);
+    }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "verdex.rom",
+                                                          verdex_rom),
+                               dinfo->bdrv, sector_len, verdex_rom / sector_len,
+                               2, 0, 0, 0, 0, be)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+        exit(1);
+    }
+
+    /* Interrupt line of NIC is connected to GPIO line 99 */
+    smc91c111_init(&nd_table[0], 0x04000300,
+                    qdev_get_gpio_in(cpu->gpio, 99));
+}
+
+static QEMUMachine connex_machine = {
+    .name = "connex",
+    .desc = "Gumstix Connex (PXA255)",
+    .init = connex_init,
+};
+
+static QEMUMachine verdex_machine = {
+    .name = "verdex",
+    .desc = "Gumstix Verdex (PXA270)",
+    .init = verdex_init,
+};
+
+static void gumstix_machine_init(void)
+{
+    qemu_register_machine(&connex_machine);
+    qemu_register_machine(&verdex_machine);
+}
+
+machine_init(gumstix_machine_init);
diff --git a/qemu-0.15.x/hw/gus.c b/qemu-0.15.x/hw/gus.c
new file mode 100644
index 0000000..ff9e7c7
--- /dev/null
+++ b/qemu-0.15.x/hw/gus.c
@@ -0,0 +1,322 @@
+/*
+ * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
+ *
+ * Copyright (c) 2002-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "isa.h"
+#include "gusemu.h"
+#include "gustate.h"
+
+#define dolog(...) AUD_log ("audio", __VA_ARGS__)
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GUS_ENDIANNESS 1
+#else
+#define GUS_ENDIANNESS 0
+#endif
+
+#define IO_READ_PROTO(name) \
+    static uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name) \
+    static void name (void *opaque, uint32_t nport, uint32_t val)
+
+typedef struct GUSState {
+    ISADevice dev;
+    GUSEmuState emu;
+    QEMUSoundCard card;
+    uint32_t freq;
+    uint32_t port;
+    int pos, left, shift, irqs;
+    GUSsample *mixbuf;
+    uint8_t himem[1024 * 1024 + 32 + 4096];
+    int samples;
+    SWVoiceOut *voice;
+    int64_t last_ticks;
+    qemu_irq pic;
+} GUSState;
+
+IO_READ_PROTO (gus_readb)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 1);
+}
+
+IO_READ_PROTO (gus_readw)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 2);
+}
+
+IO_WRITE_PROTO (gus_writeb)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 1, val);
+}
+
+IO_WRITE_PROTO (gus_writew)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 2, val);
+}
+
+static int write_audio (GUSState *s, int samples)
+{
+    int net = 0;
+    int pos = s->pos;
+
+    while (samples) {
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << s->shift;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (s->shift - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> s->shift;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static void GUS_callback (void *opaque, int free)
+{
+    int samples, to_play, net = 0;
+    GUSState *s = opaque;
+
+    samples = free >> s->shift;
+    to_play = audio_MIN (samples, s->left);
+
+    while (to_play) {
+        int written = write_audio (s, to_play);
+
+        if (!written) {
+            goto reset;
+        }
+
+        s->left -= written;
+        to_play -= written;
+        samples -= written;
+        net += written;
+    }
+
+    samples = audio_MIN (samples, s->samples);
+    if (samples) {
+        gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
+
+        while (samples) {
+            int written = write_audio (s, samples);
+            if (!written) {
+                break;
+            }
+            samples -= written;
+            net += written;
+        }
+    }
+    s->left = samples;
+
+ reset:
+    gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq));
+}
+
+int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
+{
+    GUSState *s = emu->opaque;
+    /* qemu_irq_lower (s->pic); */
+    qemu_irq_raise (s->pic);
+    s->irqs += n;
+    ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
+    return n;
+}
+
+void GUS_irqclear (GUSEmuState *emu, int hwirq)
+{
+    GUSState *s = emu->opaque;
+    ldebug ("irqclear %d %d\n", hwirq, s->irqs);
+    qemu_irq_lower (s->pic);
+    s->irqs -= 1;
+#ifdef IRQ_STORM
+    if (s->irqs > 0) {
+        qemu_irq_raise (s->pic[hwirq]);
+    }
+#endif
+}
+
+void GUS_dmarequest (GUSEmuState *der)
+{
+    /* GUSState *s = (GUSState *) der; */
+    ldebug ("dma request %d\n", der->gusdma);
+    DMA_hold_DREQ (der->gusdma);
+}
+
+static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    GUSState *s = opaque;
+    char tmpbuf[4096];
+    int pos = dma_pos, mode, left = dma_len - dma_pos;
+
+    ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
+    mode = DMA_get_channel_mode (s->emu.gusdma);
+    while (left) {
+        int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
+        int copied;
+
+        ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
+        copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
+        gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
+        left -= copied;
+        pos += copied;
+    }
+
+    if (0 == ((mode >> 4) & 1)) {
+        DMA_release_DREQ (s->emu.gusdma);
+    }
+    return dma_len;
+}
+
+static const VMStateDescription vmstate_gus = {
+    .name = "gus",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(pos, GUSState),
+        VMSTATE_INT32(left, GUSState),
+        VMSTATE_INT32(shift, GUSState),
+        VMSTATE_INT32(irqs, GUSState),
+        VMSTATE_INT32(samples, GUSState),
+        VMSTATE_INT64(last_ticks, GUSState),
+        VMSTATE_BUFFER(himem, GUSState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int gus_initfn (ISADevice *dev)
+{
+    GUSState *s = DO_UPCAST(GUSState, dev, dev);
+    struct audsettings as;
+
+    AUD_register_card ("gus", &s->card);
+
+    as.freq = s->freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = GUS_ENDIANNESS;
+
+    s->voice = AUD_open_out (
+        &s->card,
+        NULL,
+        "gus",
+        s,
+        GUS_callback,
+        &as
+        );
+
+    if (!s->voice) {
+        AUD_remove_card (&s->card);
+        return -1;
+    }
+
+    s->shift = 2;
+    s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
+    s->mixbuf = qemu_mallocz (s->samples << s->shift);
+
+    register_ioport_write (s->port, 1, 1, gus_writeb, s);
+    register_ioport_write (s->port, 1, 2, gus_writew, s);
+    isa_init_ioport_range(dev, s->port, 2);
+
+    register_ioport_read ((s->port + 0x100) & 0xf00, 1, 1, gus_readb, s);
+    register_ioport_read ((s->port + 0x100) & 0xf00, 1, 2, gus_readw, s);
+    isa_init_ioport_range(dev, (s->port + 0x100) & 0xf00, 2);
+
+    register_ioport_write (s->port + 6, 10, 1, gus_writeb, s);
+    register_ioport_write (s->port + 6, 10, 2, gus_writew, s);
+    register_ioport_read (s->port + 6, 10, 1, gus_readb, s);
+    register_ioport_read (s->port + 6, 10, 2, gus_readw, s);
+    isa_init_ioport_range(dev, s->port + 6, 10);
+
+
+    register_ioport_write (s->port + 0x100, 8, 1, gus_writeb, s);
+    register_ioport_write (s->port + 0x100, 8, 2, gus_writew, s);
+    register_ioport_read (s->port + 0x100, 8, 1, gus_readb, s);
+    register_ioport_read (s->port + 0x100, 8, 2, gus_readw, s);
+    isa_init_ioport_range(dev, s->port + 0x100, 8);
+
+    DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
+    s->emu.himemaddr = s->himem;
+    s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
+    s->emu.opaque = s;
+    isa_init_irq (dev, &s->pic, s->emu.gusirq);
+
+    AUD_set_active_out (s->voice, 1);
+
+    return 0;
+}
+
+int GUS_init (qemu_irq *pic)
+{
+    isa_create_simple ("gus");
+    return 0;
+}
+
+static ISADeviceInfo gus_info = {
+    .qdev.name     = "gus",
+    .qdev.desc     = "Gravis Ultrasound GF1",
+    .qdev.size     = sizeof (GUSState),
+    .qdev.vmsd     = &vmstate_gus,
+    .init          = gus_initfn,
+    .qdev.props    = (Property[]) {
+        DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
+        DEFINE_PROP_HEX32  ("iobase",  GUSState, port,        0x240),
+        DEFINE_PROP_UINT32 ("irq",     GUSState, emu.gusirq,  7),
+        DEFINE_PROP_UINT32 ("dma",     GUSState, emu.gusdma,  3),
+        DEFINE_PROP_END_OF_LIST (),
+    },
+};
+
+static void gus_register (void)
+{
+    isa_qdev_register (&gus_info);
+}
+device_init (gus_register)
diff --git a/qemu-0.15.x/hw/gusemu.h b/qemu-0.15.x/hw/gusemu.h
new file mode 100644
index 0000000..5093767
--- /dev/null
+++ b/qemu-0.15.x/hw/gusemu.h
@@ -0,0 +1,105 @@
+/*
+ * GUSEMU32 - API
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 GUSEMU_H
+#define GUSEMU_H
+
+/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
+
+#if defined _WIN32 && defined _MSC_VER /* doesnt support other win32 compilers yet, do it yourself... */
+ typedef unsigned char GUSbyte;
+ typedef unsigned short GUSword;
+ typedef unsigned int GUSdword;
+ typedef signed char GUSchar;
+ typedef signed short GUSsample;
+#else
+ #include <stdint.h>
+ typedef int8_t GUSchar;
+ typedef uint8_t GUSbyte;
+ typedef uint16_t GUSword;
+ typedef uint32_t GUSdword;
+ typedef int16_t GUSsample;
+#endif
+
+typedef struct _GUSEmuState
+{
+ GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ uint32_t gusirq;
+ uint32_t gusdma;
+ unsigned int timer1fraction;
+ unsigned int timer2fraction;
+ void *opaque;
+} GUSEmuState;
+
+/* ** Callback functions needed: */
+/* NMI is defined as hwirq=-1 (not supported (yet?)) */
+/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
+/* Level triggered IRQ simulations normally return 1 */
+/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
+int  GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
+void GUS_irqclear(  GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
+void GUS_dmarequest(GUSEmuState *state);            /* used by gus_write() only - can be left empty for mixer functions */
+
+/* ** ISA bus interface functions: */
+
+/* Port I/O handlers */
+/* support the following ports: */
+/* 2x0,2x6,2x8...2xF,3x0...3x7;  */
+/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
+/* data is passed in host byte order */
+unsigned int gus_read( GUSEmuState *state, int port, int size);
+void         gus_write(GUSEmuState *state, int port, int size, unsigned int data);
+/* size is given in bytes (1 for byte, 2 for word) */
+
+/* DMA data transfer function */
+/* data pointed to is passed in native x86 order */
+void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
+/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
+/* (might be immediately if the DMA controller was programmed first) */
+/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
+/* do not forget to update DMA states after the call, including the DREQ and TC flags */
+/* it is possible to break down a single transfer into multiple ones, but take care that: */
+/* -dma_count is actually count-1 */
+/* -before and during a transfer, DREQ is set and TC cleared */
+/* -when calling gus_dma_transferdata(), TC is only set true for call transfering the last byte */
+/* -after the last transfer, DREQ is cleared and TC is set */
+
+/* ** GF1 mixer emulation functions: */
+/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
+/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
+/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
+/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
+/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
+
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
+/* recommended range: 10 < numsamples < 100 */
+/* lower values may result in increased rounding error, higher values often cause audible timing delays */
+
+void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
+/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
+/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
+/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
+
+#endif  /* gusemu.h */
diff --git a/qemu-0.15.x/hw/gusemu_hal.c b/qemu-0.15.x/hw/gusemu_hal.c
new file mode 100644
index 0000000..c6f9537
--- /dev/null
+++ b/qemu-0.15.x/hw/gusemu_hal.c
@@ -0,0 +1,554 @@
+/*
+ * GUSEMU32 - bus interface part
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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.
+ */
+
+/*
+ * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
+ */
+
+#include "gustate.h"
+#include "gusemu.h"
+
+#define GUSregb(position) (*            (gusptr+(position)))
+#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+
+/* size given in bytes */
+unsigned int gus_read(GUSEmuState * state, int port, int size)
+{
+    int             value_read = 0;
+
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+        /* MixerCtrlReg (read not supported on GUS classic) */
+        /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
+    case 0x206:                          /* IRQstatReg / SB2x6IRQ */
+        /* adlib/sb bits set in port handlers */
+        /* timer/voice bits set in gus_irqgen() */
+        /* dma bit set in gus_dma_transferdata */
+        /* midi not implemented yet */
+        return GUSregb(IRQStatReg2x6);
+    /* case 0x308:                       */ /* AdLib388 */
+    case 0x208:
+        if (GUSregb(GUS45TimerCtrl) & 1)
+            return GUSregb(TimerStatus2x8);
+        return GUSregb(AdLibStatus2x8);  /* AdLibStatus */
+    case 0x309:                          /* AdLib389 */
+    case 0x209:
+        return GUSregb(AdLibData2x9);    /* AdLibData */
+    case 0x20A:
+        return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
+
+#if 0
+    case 0x20B:                          /* GUS hidden registers (read not supported on GUS classic) */
+        switch (GUSregb(RegCtrl_2xF) & 0x07)
+        {
+        case 0:                                 /* IRQ/DMA select */
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                return GUSregb(IRQ_2xB);        /* control register select bit */
+            else
+                return GUSregb(DMA_2xB);
+            /* case 1-5:                        */ /* general purpose emulation regs  */
+            /*  return ...                      */ /* + status reset reg (write only) */
+        case 6:
+            return GUSregb(Jumper_2xB);         /* Joystick/MIDI enable (JumperReg) */
+        default:;
+        }
+        break;
+#endif
+
+    case 0x20C:                          /* SB2xCd */
+        value_read = GUSregb(SB2xCd);
+        if (GUSregb(StatRead_2xF) & 0x20)
+            GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
+        return value_read;
+        /* case 0x20D:                   */ /* SB2xD is write only -> 2xE writes to it*/
+    case 0x20E:
+        if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
+        {
+            GUSregb(StatRead_2xF) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        return GUSregb(SB2xE);           /* SB2xE */
+    case 0x20F:                          /* StatRead_2xF */
+        /*set/clear fixed bits */
+        /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
+        value_read = (GUSregb(StatRead_2xF) & 0xf9);
+        if (GUSregb(MixerCtrlReg2x0) & 0x08)
+            value_read |= 2;    /* DMA/IRQ enabled flag */
+        return value_read;
+    /* case 0x300:                      */ /* MIDI (not implemented) */
+    /* case 0x301:                      */ /* MIDI (not implemented) */
+    case 0x302:
+        return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
+    case 0x303:
+        return GUSregb(FunkSelReg3x3);  /* FunkSelReg */
+    case 0x304:                         /* DataRegLoByte3x4 + DataRegWord3x4 */
+    case 0x305:                         /* DataRegHiByte3x5 */
+        switch (GUSregb(FunkSelReg3x3))
+        {
+    /* common functions */
+        case 0x41:                      /* DramDMAContrReg */
+            value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
+            GUSregb(GUS41DMACtrl) &= 0xbb;
+            if (state->gusdma >= 4)
+                value_read |= 0x04;
+            if (GUSregb(IRQStatReg2x6) & 0x80)
+            {
+                value_read |= 0x40;
+                GUSregb(IRQStatReg2x6) &= 0x7f;
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+            }
+            return (GUSbyte) value_read;
+            /* DramDMAmemPosReg */
+            /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
+            /* 43h+44h write only */
+        case 0x45:
+            return GUSregb(GUS45TimerCtrl);         /* TimerCtrlReg */
+            /* 46h+47h write only */
+            /* 48h: samp freq - write only */
+        case 0x49:
+            return GUSregb(GUS49SampCtrl) & 0xbf;   /* SampCtrlReg */
+        /* case 4bh:                                */ /* joystick trim not supported */
+        /* case 0x4c: return GUSregb(GUS4cReset);   */ /* GUSreset: write only*/
+    /* voice specific functions */
+        case 0x80:
+        case 0x81:
+        case 0x82:
+        case 0x83:
+        case 0x84:
+        case 0x85:
+        case 0x86:
+        case 0x87:
+        case 0x88:
+        case 0x89:
+        case 0x8a:
+        case 0x8b:
+        case 0x8c:
+        case 0x8d:
+            {
+                int             offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
+                value_read = GUSregw(offset);
+            }
+            break;
+    /* voice unspecific functions */
+        case 0x8e:                                  /* NumVoice */
+            return GUSregb(NumVoices);
+        case 0x8f:                                  /* irqstatreg */
+            /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
+            return GUSregb(SynVoiceIRQ8f);
+        default:
+            return 0xffff;
+        }
+        if (size == 1)
+        {
+            if ((port & 0xff0f) == 0x305)
+                value_read = value_read >> 8;
+            value_read &= 0xff;
+        }
+        return (GUSword) value_read;
+    /* case 0x306:                                  */ /* Mixer/Version info */
+        /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
+    case 0x307:                                     /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            return *adr;
+        }
+    default:;
+    }
+    return 0xffff;
+}
+
+void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
+{
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+    case 0x200:                 /* MixerCtrlReg */
+        GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+        break;
+    case 0x206:                 /* IRQstatReg / SB2x6IRQ */
+        if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
+        {
+            GUSregb(TimerStatus2x8) |= 0x08;
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        break;
+    case 0x308:                /* AdLib 388h */
+    case 0x208:                /* AdLibCommandReg */
+        GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+        break;
+    case 0x309:                /* AdLib 389h */
+    case 0x209:                /* AdLibDataReg */
+        if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
+        {
+            if (data & 0x80)
+                GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
+            else
+                GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+        }
+        else
+        {
+            GUSregb(AdLibData2x9) = (GUSbyte) data;
+            if (GUSregb(GUS45TimerCtrl) & 0x02)
+            {
+                GUSregb(TimerStatus2x8) |= 0x01;
+                GUSregb(IRQStatReg2x6) = 0x10;
+                GUS_irqrequest(state, state->gusirq, 1);
+            }
+        }
+        break;
+    case 0x20A:
+        GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+        break;                 /* AdLibStatus2x8 */
+    case 0x20B:                /* GUS hidden registers */
+        switch (GUSregb(RegCtrl_2xF) & 0x7)
+        {
+        case 0:
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+            else
+                GUSregb(DMA_2xB) = (GUSbyte) data;
+            break;
+            /* case 1-4: general purpose emulation regs */
+        case 5:                                    /* clear stat reg 2xF */
+            GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
+            if (!GUSregb(IRQStatReg2x6))
+                GUS_irqclear(state, state->gusirq);
+            break;
+        case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
+            GUSregb(Jumper_2xB) = (GUSbyte) data;
+            break;
+        default:;
+        }
+        break;
+    case 0x20C:                /* SB2xCd */
+        if (GUSregb(GUS45TimerCtrl) & 0x20)
+        {
+            GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    case 0x20D:                /* SB2xCd no IRQ */
+        GUSregb(SB2xCd) = (GUSbyte) data;
+        break;
+    case 0x20E:                /* SB2xE */
+        GUSregb(SB2xE) = (GUSbyte) data;
+        break;
+    case 0x20F:
+        GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+        break;                 /* CtrlReg2xF */
+    case 0x302:                /* VoiceSelReg */
+        GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+        break;
+    case 0x303:                /* FunkSelReg */
+        GUSregb(FunkSelReg3x3) = (GUSbyte) data;
+        if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+        {
+            int             voice;
+            if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicewavetableirq) & (1 << voice))
+                    {
+                        GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
+                        if (!GUSregd(voicewavetableirq))
+                            GUSregb(IRQStatReg2x6) &= 0xdf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicevolrampirq) & (1 << voice))
+                    {
+                        GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
+                        if (!GUSregd(voicevolrampirq))
+                            GUSregb(IRQStatReg2x6) &= 0xbf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
+        }
+        break;
+    case 0x304:
+    case 0x305:
+        {
+            GUSword         writedata = (GUSword) data;
+            GUSword         readmask = 0x0000;
+            if (size == 1)
+            {
+                readmask = 0xff00;
+                writedata &= 0xff;
+                if ((port & 0xff0f) == 0x305)
+                {
+                    writedata = (GUSword) (writedata << 8);
+                    readmask = 0x00ff;
+                }
+            }
+            switch (GUSregb(FunkSelReg3x3))
+            {
+                /* voice specific functions */
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0c:
+            case 0x0d:
+                {
+                    int             offset;
+                    if (!(GUSregb(GUS4cReset) & 0x01))
+                        break;  /* reset flag active? */
+                    offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                    offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
+                    GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+                }
+                break;
+                /* voice unspecific functions */
+            case 0x0e:         /* NumVoices */
+                GUSregb(NumVoices) = (GUSbyte) data;
+                break;
+            /* case 0x0f:      */ /* read only */
+                /* common functions */
+            case 0x41:         /* DramDMAContrReg */
+                GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+                if (data & 0x01)
+                    GUS_dmarequest(state);
+                break;
+            case 0x42:         /* DramDMAmemPosReg */
+                GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
+                GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
+                break;
+            case 0x43:         /* DRAMaddrLo */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
+                break;
+            case 0x44:         /* DRAMaddrHi */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
+                break;
+            case 0x45:         /* TCtrlReg */
+                GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+                if (!(data & 0x20))
+                    GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
+                if (!(data & 0x02))
+                    GUSregb(TimerStatus2x8) &= 0xfe;    /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
+                if (!(GUSregb(TimerStatus2x8) & 0x19))
+                    GUSregb(IRQStatReg2x6) &= 0xef;     /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
+                /* catch up delayed timer IRQs: */
+                if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
+                {
+                    if (GUSregb(TimerDataReg2x9) & 1)   /* start timer 1 (80us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                            GUSregb(TimerStatus2x8) |= 0xc0;    /* maskable bits */
+                        if (data & 4) /* timer1 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 4;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 4;        /* timer 1 irq pending */
+                        }
+                    }
+                    if (GUSregb(TimerDataReg2x9) & 2)   /* start timer 2 (320us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                            GUSregb(TimerStatus2x8) |= 0xa0;    /* maskable bits */
+                        if (data & 8) /* timer2 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 2;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 8;        /* timer 2 irq pending */
+                        }
+                    }
+                    GUSregw(TimerIRQs)--;
+                    if (GUSregw(BusyTimerIRQs) > 1)
+                        GUSregw(BusyTimerIRQs)--;
+                    else
+                        GUSregw(BusyTimerIRQs) =
+                            GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
+                }
+                else
+                    GUSregw(TimerIRQs) = 0;
+
+                if (!(data & 0x04))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xfb;
+                }
+                if (!(data & 0x08))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xf7;
+                }
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+                break;
+            case 0x46:          /* Counter1 */
+                GUSregb(GUS46Counter1) = (GUSbyte) data;
+                break;
+            case 0x47:          /* Counter2 */
+                GUSregb(GUS47Counter2) = (GUSbyte) data;
+                break;
+            /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
+            case 0x49:          /* SampCtrlReg */
+                GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+                break;
+            /* case 0x4b:       */ /* joystick trim not emulated */
+            case 0x4c:          /* GUSreset */
+                GUSregb(GUS4cReset) = (GUSbyte) data;
+                if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
+                {
+                    GUSregd(voicewavetableirq) = 0;
+                    GUSregd(voicevolrampirq) = 0;
+                    GUSregw(TimerIRQs) = 0;
+                    GUSregw(BusyTimerIRQs) = 0;
+                    GUSregb(NumVoices) = 0xcd;
+                    GUSregb(IRQStatReg2x6) = 0;
+                    GUSregb(TimerStatus2x8) = 0;
+                    GUSregb(AdLibData2x9) = 0;
+                    GUSregb(TimerDataReg2x9) = 0;
+                    GUSregb(GUS41DMACtrl) = 0;
+                    GUSregb(GUS45TimerCtrl) = 0;
+                    GUSregb(GUS49SampCtrl) = 0;
+                    GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
+                    GUS_irqclear(state, state->gusirq);
+                }
+                /* IRQ enable bit checked elsewhere */
+                /* EnableDAC bit may be used by external callers */
+                break;
+            }
+        }
+        break;
+    case 0x307:                /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            *adr = (GUSbyte) data;
+        }
+        break;
+    }
+}
+
+/* Attention when breaking up a single DMA transfer to multiple ones:
+ * it may lead to multiple terminal count interrupts and broken transfers:
+ *
+ * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
+ * 2. The callback may generate a TC irq (if the register was set up to do so)
+ * 3. The irq may result in the program using the GUS to reprogram the GUS
+ *
+ * Some programs also decide to upload by just checking if TC occurs
+ * (via interrupt or a cleared GUS dma flag)
+ * and then start the next transfer, without checking DMA state
+ *
+ * Thus: Always make sure to set the TC flag correctly!
+ *
+ * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
+ * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
+ * GUSemu also uses this register to support byte-granular transfers for better compatibility
+ * with emulators other than GUSemu32
+ */
+
+void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
+{
+    /* this function gets called by the callback function as soon as a DMA transfer is about to start
+     * dma_addr is a translated address within accessible memory, not the physical one,
+     * count is (real dma count register)+1
+     * note that the amount of bytes transfered is fully determined by values in the DMA registers
+     * do not forget to update DMA states after transferring the entire block:
+     * DREQ cleared & TC asserted after the _whole_ transfer */
+
+    char           *srcaddr;
+    char           *destaddr;
+    char            msbmask = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+
+    srcaddr = dma_addr; /* system memory address */
+    {
+        int             offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
+        if (state->gusdma >= 4)
+            offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
+        destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */
+    }
+
+    GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
+    GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+
+    if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
+    {
+        char           *tmpaddr = destaddr;
+        destaddr = srcaddr;
+        srcaddr = tmpaddr;
+    }
+
+    if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
+        msbmask = (const char) 0x80;    /* invert MSB */
+    for (; count > 0; count--)
+    {
+        if (GUSregb(GUS41DMACtrl) & 0x40)
+            *(destaddr++) = *(srcaddr++);               /* 16 bit lobyte */
+        else
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
+        if (state->gusdma >= 4)
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
+    }
+
+    if (TC)
+    {
+        (GUSregb(GUS41DMACtrl)) &= 0xfe;        /* clear DMA request bit */
+        if (GUSregb(GUS41DMACtrl) & 0x20)       /* DMA terminal count IRQ */
+        {
+            GUSregb(IRQStatReg2x6) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    }
+}
diff --git a/qemu-0.15.x/hw/gusemu_mixer.c b/qemu-0.15.x/hw/gusemu_mixer.c
new file mode 100644
index 0000000..6d8d9ce
--- /dev/null
+++ b/qemu-0.15.x/hw/gusemu_mixer.c
@@ -0,0 +1,240 @@
+/*
+ * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 "gusemu.h"
+#include "gustate.h"
+
+#define GUSregb(position)  (*            (gusptr+(position)))
+#define GUSregw(position)  (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position)  (*(GUSdword *)(gusptr+(position)))
+
+#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+
+/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
+void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
+                   GUSsample *bufferpos)
+{
+    /* note that byte registers are stored in the upper half of each voice register! */
+    GUSbyte        *gusptr;
+    int             Voice;
+    GUSword        *voiceptr;
+
+    unsigned int    count;
+    for (count = 0; count < numsamples * 2; count++)
+        *(bufferpos + count) = 0;       /* clear */
+
+    gusptr = state->gusdatapos;
+    voiceptr = (GUSword *) gusptr;
+    if (!(GUSregb(GUS4cReset) & 0x01))  /* reset flag active? */
+        return;
+
+    for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
+    {
+        if (GUSvoice(wVSRControl)        &  0x200)
+            GUSvoice(wVSRControl)        |= 0x100; /* voice stop request */
+        if (GUSvoice(wVSRVolRampControl) &  0x200)
+            GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
+        if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
+        {
+            unsigned int    sample;
+
+            unsigned int    LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
+            unsigned int    LoopEnd   = (GUSvoice(wVSRLoopEndHi)   << 16) | GUSvoice(wVSRLoopEndLo);   /* 23.9 format */
+            unsigned int    CurrPos   = (GUSvoice(wVSRCurrPosHi)   << 16) | GUSvoice(wVSRCurrPosLo);   /* 23.9 format */
+            int             VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
+                                             ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
+
+            int             PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
+
+            unsigned int    Volume32   = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
+            unsigned int    StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
+            unsigned int    EndVol32   = (GUSvoice(wVSRVolRampEndVol)   & 0xff00) * 32;
+            int             VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
+            VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
+
+            if (GUSvoice(wVSRControl) & 0x4000)
+                VoiceIncrement    = -VoiceIncrement;    /* reverse playback */
+            if (GUSvoice(wVSRVolRampControl) & 0x4000)
+                VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
+
+            for (sample = 0; sample < numsamples; sample++)
+            {
+                int             sample1, sample2, Volume;
+                if (GUSvoice(wVSRControl) & 0x400)      /* 16bit */
+                {
+                    int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
+                    sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
+                }
+                else            /* 8bit */
+                {
+                    int offset = (CurrPos >> 9) & 0xfffff;
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr) * 256;
+                    sample2 = (*(adr + 1)) * 256;
+                }
+
+                Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
+                sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
+                sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
+                sample1 += sample2;
+
+                if (!(GUSvoice(wVSRVolRampControl) & 0x100))
+                {
+                    Volume32 += VolumeIncrement32;
+                    if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
+                    {
+                        if (GUSvoice(wVSRVolRampControl) & 0x2000)
+                            GUSvoice(wVSRVolRampControl) |= 0x8000;     /* volramp IRQ enabled? -> IRQ wait flag */
+                        if (GUSvoice(wVSRVolRampControl) & 0x800)       /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRVolRampControl) & 0x1000)  /* bidir. loop */
+                            {
+                                GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
+                                VolumeIncrement32 = -VolumeIncrement32;
+                            }
+                            else
+                                Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
+                        }
+                        else
+                        {
+                            GUSvoice(wVSRVolRampControl) |= 0x100;
+                            Volume32 =
+                                (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
+                        }
+                    }
+                }
+                if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000)  /* volramp IRQ set and enabled? */
+                {
+                    GUSregd(voicevolrampirq) |= 1 << Voice;             /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicevolrampirq) &= (~(1 << Voice));        /* clear irq slot */
+                    GUSvoice(wVSRVolRampControl) &= 0x7f00;
+                }
+
+                if (!(GUSvoice(wVSRControl) & 0x100))
+                {
+                    CurrPos += VoiceIncrement;
+                    if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
+                    {
+                        if (GUSvoice(wVSRControl) & 0x2000)
+                            GUSvoice(wVSRControl) |= 0x8000;       /* voice IRQ enabled -> IRQ wait flag */
+                        if (GUSvoice(wVSRControl) & 0x800)         /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRControl) & 0x1000)    /* pingpong loop */
+                            {
+                                GUSvoice(wVSRControl) ^= 0x4000;   /* toggle dir */
+                                VoiceIncrement = -VoiceIncrement;
+                            }
+                            else
+                                CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
+                        }
+                        else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
+                            GUSvoice(wVSRControl) |= 0x100;        /* loop disabled, rollover check */
+                    }
+                }
+                if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000)    /* wavetable IRQ set and enabled? */
+                {
+                    GUSregd(voicewavetableirq) |= 1 << Voice;      /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
+                    GUSvoice(wVSRControl) &= 0x7f00;
+                }
+
+                /* mix samples into buffer */
+                *(bufferpos + 2 * sample)     += (GUSsample) ((sample1 * PanningPos) >> 4);        /* right */
+                *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+            }
+            /* write back voice and volume */
+            GUSvoice(wVSRCurrVol)   = Volume32 / 32;
+            GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
+            GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
+        }
+        voiceptr += 16; /* next voice */
+    }
+}
+
+void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
+/* time given in microseconds */
+{
+    int             requestedIRQs = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
+    {
+        unsigned int    timer1fraction = state->timer1fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
+        state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 4)     /* timer1 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 4;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 4;    /* timer 1 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
+    {
+        unsigned int timer2fraction = state->timer2fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
+        state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 8)     /* timer2 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 2;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 8;    /* timer 2 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
+    {
+        if (GUSregd(voicewavetableirq))
+            GUSregb(IRQStatReg2x6) |= 0x20;
+        if (GUSregd(voicevolrampirq))
+            GUSregb(IRQStatReg2x6) |= 0x40;
+    }
+    if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
+        requestedIRQs++;
+    if (GUSregb(IRQStatReg2x6))
+        GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
+}
diff --git a/qemu-0.15.x/hw/gustate.h b/qemu-0.15.x/hw/gustate.h
new file mode 100644
index 0000000..ece903a
--- /dev/null
+++ b/qemu-0.15.x/hw/gustate.h
@@ -0,0 +1,132 @@
+/*
+ * GUSEMU32 - persistent GUS register state
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 GUSTATE_H
+#define GUSTATE_H
+
+/*state block offset*/
+#define gusdata (0)
+
+/* data stored using this structure is in host byte order! */
+
+/*access type*/
+#define PortRead  (0)
+#define PortWrite (1)
+
+#define Port8Bitacc  (0)
+#define Port16Bitacc (1)
+
+/*voice register offsets (in bytes)*/
+#define VSRegs (0)
+#define VSRControl          (0)
+#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
+#define VSRFreq             (2)
+#define VSRLoopStartHi      (4)
+#define VSRLoopStartLo      (6)
+#define VSRLoopEndHi        (8)
+#define VSRLoopEndLo       (10)
+#define VSRVolRampRate     (12)
+#define VSRVolRampStartVol (14)
+#define VSRVolRampEndVol   (16)
+#define VSRCurrVol         (18)
+#define VSRCurrPosHi       (20)
+#define VSRCurrPosLo       (22)
+#define VSRPanning         (24)
+#define VSRVolRampControl  (26)
+
+/*voice register offsets (in words)*/
+#define wVSRegs (0)
+#define wVSRControl         (0)
+#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
+#define wVSRFreq            (1)
+#define wVSRLoopStartHi     (2)
+#define wVSRLoopStartLo     (3)
+#define wVSRLoopEndHi       (4)
+#define wVSRLoopEndLo       (5)
+#define wVSRVolRampRate     (6)
+#define wVSRVolRampStartVol (7)
+#define wVSRVolRampEndVol   (8)
+#define wVSRCurrVol         (9)
+#define wVSRCurrPosHi      (10)
+#define wVSRCurrPosLo      (11)
+#define wVSRPanning        (12)
+#define wVSRVolRampControl (13)
+
+/*GUS register state block: 32 voices, padding filled with remaining registers*/
+#define DataRegLoByte3x4  (VSRVolRampControl+2)
+#define  DataRegWord3x4 (DataRegLoByte3x4)
+#define DataRegHiByte3x5  (VSRVolRampControl+2       +1)
+#define DMA_2xB (VSRVolRampControl+2+2)
+#define IRQ_2xB (VSRVolRampControl+2+3)
+
+#define RegCtrl_2xF       (VSRVolRampControl+2+(16*2))
+#define Jumper_2xB        (VSRVolRampControl+2+(16*2)+1)
+#define GUS42DMAStart     (VSRVolRampControl+2+(16*2)+2)
+
+#define GUS43DRAMIOlo     (VSRVolRampControl+2+(16*2)*2)
+#define  GUSDRAMPOS24bit (GUS43DRAMIOlo)
+#define GUS44DRAMIOhi     (VSRVolRampControl+2+(16*2)*2+2)
+
+#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define voicevolrampirq   (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define startvoices       (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
+
+#define IRQStatReg2x6     (VSRVolRampControl+2+(16*2)*6)
+#define TimerStatus2x8    (VSRVolRampControl+2+(16*2)*6+1)
+#define TimerDataReg2x9   (VSRVolRampControl+2+(16*2)*6+2)
+#define MixerCtrlReg2x0   (VSRVolRampControl+2+(16*2)*6+3)
+
+#define VoiceSelReg3x2    (VSRVolRampControl+2+(16*2)*7)
+#define FunkSelReg3x3     (VSRVolRampControl+2+(16*2)*7+1)
+#define AdLibStatus2x8    (VSRVolRampControl+2+(16*2)*7+2)
+#define StatRead_2xF      (VSRVolRampControl+2+(16*2)*7+3)
+
+#define GUS48SampSpeed    (VSRVolRampControl+2+(16*2)*8)
+#define GUS41DMACtrl      (VSRVolRampControl+2+(16*2)*8+1)
+#define GUS45TimerCtrl    (VSRVolRampControl+2+(16*2)*8+2)
+#define GUS46Counter1     (VSRVolRampControl+2+(16*2)*8+3)
+
+#define GUS47Counter2     (VSRVolRampControl+2+(16*2)*9)
+#define GUS49SampCtrl     (VSRVolRampControl+2+(16*2)*9+1)
+#define GUS4cReset        (VSRVolRampControl+2+(16*2)*9+2)
+#define NumVoices         (VSRVolRampControl+2+(16*2)*9+3)
+
+#define TimerIRQs         (VSRVolRampControl+2+(16*2)*10)   /* delayed IRQ, statistics */
+#define BusyTimerIRQs     (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
+
+#define AdLibCommand2xA   (VSRVolRampControl+2+(16*2)*11)
+#define AdLibData2x9      (VSRVolRampControl+2+(16*2)*11+1)
+#define SB2xCd            (VSRVolRampControl+2+(16*2)*11+2)
+#define SB2xE             (VSRVolRampControl+2+(16*2)*11+3)
+
+#define SynVoiceIRQ8f     (VSRVolRampControl+2+(16*2)*12)
+#define GUS50DMAHigh      (VSRVolRampControl+2+(16*2)*12+1)
+
+#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
+
+#define gusdataend (VSRegsEnd+4)
+
+#endif  /* gustate.h */
diff --git a/qemu-0.15.x/hw/hda-audio.c b/qemu-0.15.x/hw/hda-audio.c
new file mode 100644
index 0000000..c699d6f
--- /dev/null
+++ b/qemu-0.15.x/hw/hda-audio.c
@@ -0,0 +1,926 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+#include "audio/audio.h"
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct desc_param {
+    uint32_t id;
+    uint32_t val;
+} desc_param;
+
+typedef struct desc_node {
+    uint32_t nid;
+    const char *name;
+    const desc_param *params;
+    uint32_t nparams;
+    uint32_t config;
+    uint32_t pinctl;
+    uint32_t *conn;
+    uint32_t stindex;
+} desc_node;
+
+typedef struct desc_codec {
+    const char *name;
+    uint32_t iid;
+    const desc_node *nodes;
+    uint32_t nnodes;
+} desc_codec;
+
+static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
+{
+    int i;
+
+    for (i = 0; i < node->nparams; i++) {
+        if (node->params[i].id == id) {
+            return &node->params[i];
+        }
+    }
+    return NULL;
+}
+
+static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
+{
+    int i;
+
+    for (i = 0; i < codec->nnodes; i++) {
+        if (codec->nodes[i].nid == nid) {
+            return &codec->nodes[i];
+        }
+    }
+    return NULL;
+}
+
+static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
+{
+    if (format & AC_FMT_TYPE_NON_PCM) {
+        return;
+    }
+
+    as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
+
+    switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
+    case 1: as->freq *= 2; break;
+    case 2: as->freq *= 3; break;
+    case 3: as->freq *= 4; break;
+    }
+
+    switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
+    case 1: as->freq /= 2; break;
+    case 2: as->freq /= 3; break;
+    case 3: as->freq /= 4; break;
+    case 4: as->freq /= 5; break;
+    case 5: as->freq /= 6; break;
+    case 6: as->freq /= 7; break;
+    case 7: as->freq /= 8; break;
+    }
+
+    switch (format & AC_FMT_BITS_MASK) {
+    case AC_FMT_BITS_8:  as->fmt = AUD_FMT_S8;  break;
+    case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
+    case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
+    }
+
+    as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
+}
+
+/* -------------------------------------------------------------------------- */
+/*
+ * HDA codec descriptions
+ */
+
+/* some defines */
+
+#define QEMU_HDA_ID_VENDOR  0x1af4
+#define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x10)
+#define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x20)
+
+#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 |       \
+                              0x1fc /* 16 -> 96 kHz */)
+#define QEMU_HDA_AMP_NONE    (0)
+#define QEMU_HDA_AMP_STEPS   0x4a
+
+#ifdef CONFIG_MIXEMU
+#define QEMU_HDA_AMP_CAPS                                               \
+    (AC_AMPCAP_MUTE |                                                   \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)    |                \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |                \
+     (3                  << AC_AMPCAP_STEP_SIZE_SHIFT))
+#else
+#define QEMU_HDA_AMP_CAPS    QEMU_HDA_AMP_NONE
+#endif
+
+/* common: audio output widget */
+static const desc_param common_params_audio_dac[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_OUT_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },
+};
+
+/* common: pin widget (line-out) */
+static const desc_param common_params_audio_lineout[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_OUT,
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* output: root node */
+static const desc_param output_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* output: audio function */
+static const desc_param output_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020002,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* output: nodes */
+static const desc_node output_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = output_params_root,
+        .nparams = ARRAY_SIZE(output_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = output_params_audio_func,
+        .nparams = ARRAY_SIZE(output_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    }
+};
+
+/* output: codec */
+static const desc_codec output = {
+    .name   = "output",
+    .iid    = QEMU_HDA_ID_OUTPUT,
+    .nodes  = output_nodes,
+    .nnodes = ARRAY_SIZE(output_nodes),
+};
+
+/* duplex: root node */
+static const desc_param duplex_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* duplex: audio input widget */
+static const desc_param duplex_params_audio_adc[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_IN_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* duplex: pin widget (line-in) */
+static const desc_param duplex_params_audio_linein[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_IN,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* duplex: audio function */
+static const desc_param duplex_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020004,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* duplex: nodes */
+static const desc_node duplex_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = duplex_params_root,
+        .nparams = ARRAY_SIZE(duplex_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = duplex_params_audio_func,
+        .nparams = ARRAY_SIZE(duplex_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    },{
+        .nid     = 4,
+        .name    = "adc",
+        .params  = duplex_params_audio_adc,
+        .nparams = ARRAY_SIZE(duplex_params_audio_adc),
+        .stindex = 1,
+        .conn    = (uint32_t[]) { 5 },
+    },{
+        .nid     = 5,
+        .name    = "in",
+        .params  = duplex_params_audio_linein,
+        .nparams = ARRAY_SIZE(duplex_params_audio_linein),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_IN      << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x20),
+        .pinctl  = AC_PINCTL_IN_EN,
+    }
+};
+
+/* duplex: codec */
+static const desc_codec duplex = {
+    .name   = "duplex",
+    .iid    = QEMU_HDA_ID_DUPLEX,
+    .nodes  = duplex_nodes,
+    .nnodes = ARRAY_SIZE(duplex_nodes),
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const char *fmt2name[] = {
+    [ AUD_FMT_U8  ] = "PCM-U8",
+    [ AUD_FMT_S8  ] = "PCM-S8",
+    [ AUD_FMT_U16 ] = "PCM-U16",
+    [ AUD_FMT_S16 ] = "PCM-S16",
+    [ AUD_FMT_U32 ] = "PCM-U32",
+    [ AUD_FMT_S32 ] = "PCM-S32",
+};
+
+typedef struct HDAAudioState HDAAudioState;
+typedef struct HDAAudioStream HDAAudioStream;
+
+struct HDAAudioStream {
+    HDAAudioState *state;
+    const desc_node *node;
+    bool output, running;
+    uint32_t stream;
+    uint32_t channel;
+    uint32_t format;
+    uint32_t gain_left, gain_right;
+    bool mute_left, mute_right;
+    struct audsettings as;
+    union {
+        SWVoiceIn *in;
+        SWVoiceOut *out;
+    } voice;
+    uint8_t buf[HDA_BUFFER_SIZE];
+    uint32_t bpos;
+};
+
+struct HDAAudioState {
+    HDACodecDevice hda;
+    const char *name;
+
+    QEMUSoundCard card;
+    const desc_codec *desc;
+    HDAAudioStream st[4];
+    bool running[16];
+
+    /* properties */
+    uint32_t debug;
+};
+
+static void hda_audio_input_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int recv = 0;
+    int len;
+    bool rc;
+
+    while (avail - recv >= sizeof(st->buf)) {
+        if (st->bpos != sizeof(st->buf)) {
+            len = AUD_read(st->voice.in, st->buf + st->bpos,
+                           sizeof(st->buf) - st->bpos);
+            st->bpos += len;
+            recv += len;
+            if (st->bpos != sizeof(st->buf)) {
+                break;
+            }
+        }
+        rc = hda_codec_xfer(&st->state->hda, st->stream, false,
+                            st->buf, sizeof(st->buf));
+        if (!rc) {
+            break;
+        }
+        st->bpos = 0;
+    }
+}
+
+static void hda_audio_output_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int sent = 0;
+    int len;
+    bool rc;
+
+    while (avail - sent >= sizeof(st->buf)) {
+        if (st->bpos == sizeof(st->buf)) {
+            rc = hda_codec_xfer(&st->state->hda, st->stream, true,
+                                st->buf, sizeof(st->buf));
+            if (!rc) {
+                break;
+            }
+            st->bpos = 0;
+        }
+        len = AUD_write(st->voice.out, st->buf + st->bpos,
+                        sizeof(st->buf) - st->bpos);
+        st->bpos += len;
+        sent += len;
+        if (st->bpos != sizeof(st->buf)) {
+            break;
+        }
+    }
+}
+
+static void hda_audio_set_running(HDAAudioStream *st, bool running)
+{
+    if (st->node == NULL) {
+        return;
+    }
+    if (st->running == running) {
+        return;
+    }
+    st->running = running;
+    dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
+           st->running ? "on" : "off", st->stream);
+    if (st->output) {
+        AUD_set_active_out(st->voice.out, st->running);
+    } else {
+        AUD_set_active_in(st->voice.in, st->running);
+    }
+}
+
+static void hda_audio_set_amp(HDAAudioStream *st)
+{
+    bool muted;
+    uint32_t left, right;
+
+    if (st->node == NULL) {
+        return;
+    }
+
+    muted = st->mute_left && st->mute_right;
+    left  = st->mute_left  ? 0 : st->gain_left;
+    right = st->mute_right ? 0 : st->gain_right;
+
+    left = left * 255 / QEMU_HDA_AMP_STEPS;
+    right = right * 255 / QEMU_HDA_AMP_STEPS;
+
+    if (st->output) {
+        AUD_set_volume_out(st->voice.out, muted, left, right);
+    } else {
+        AUD_set_volume_in(st->voice.in, muted, left, right);
+    }
+}
+
+static void hda_audio_setup(HDAAudioStream *st)
+{
+    if (st->node == NULL) {
+        return;
+    }
+
+    dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
+           st->node->name, st->as.nchannels,
+           fmt2name[st->as.fmt], st->as.freq);
+
+    if (st->output) {
+        st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
+                                     st->node->name, st,
+                                     hda_audio_output_cb, &st->as);
+    } else {
+        st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
+                                   st->node->name, st,
+                                   hda_audio_input_cb, &st->as);
+    }
+}
+
+static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node = NULL;
+    const desc_param *param;
+    uint32_t verb, payload, response, count, shift;
+
+    if ((data & 0x70000) == 0x70000) {
+        /* 12/8 id/payload */
+        verb = (data >> 8) & 0xfff;
+        payload = data & 0x00ff;
+    } else {
+        /* 4/16 id/payload */
+        verb = (data >> 8) & 0xf00;
+        payload = data & 0xffff;
+    }
+
+    node = hda_codec_find_node(a->desc, nid);
+    if (node == NULL) {
+        goto fail;
+    }
+    dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node->name, verb, payload);
+
+    switch (verb) {
+    /* all nodes */
+    case AC_VERB_PARAMETERS:
+        param = hda_codec_find_param(node, payload);
+        if (param == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, param->val);
+        break;
+    case AC_VERB_GET_SUBSYSTEM_ID:
+        hda_codec_response(hda, true, a->desc->iid);
+        break;
+
+    /* all functions */
+    case AC_VERB_GET_CONNECT_LIST:
+        param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
+        count = param ? param->val : 0;
+        response = 0;
+        shift = 0;
+        while (payload < count && shift < 32) {
+            response |= node->conn[payload] << shift;
+            payload++;
+            shift += 8;
+        }
+        hda_codec_response(hda, true, response);
+        break;
+
+    /* pin widget */
+    case AC_VERB_GET_CONFIG_DEFAULT:
+        hda_codec_response(hda, true, node->config);
+        break;
+    case AC_VERB_GET_PIN_WIDGET_CONTROL:
+        hda_codec_response(hda, true, node->pinctl);
+        break;
+    case AC_VERB_SET_PIN_WIDGET_CONTROL:
+        if (node->pinctl != payload) {
+            dprint(a, 1, "unhandled pin control bit\n");
+        }
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* audio in/out widget */
+    case AC_VERB_SET_CHANNEL_STREAMID:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_audio_set_running(st, false);
+        st->stream = (payload >> 4) & 0x0f;
+        st->channel = payload & 0x0f;
+        dprint(a, 2, "%s: stream %d, channel %d\n",
+               st->node->name, st->stream, st->channel);
+        hda_audio_set_running(st, a->running[st->stream]);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_CONV:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        response = st->stream << 4 | st->channel;
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        st->format = payload;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, st->format);
+        break;
+    case AC_VERB_GET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        if (payload & AC_AMP_GET_LEFT) {
+            response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
+        } else {
+            response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
+        }
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        dprint(a, 1, "amp (%s): %s%s%s%s index %d  gain %3d %s\n",
+               st->node->name,
+               (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
+               (payload & AC_AMP_SET_INPUT)  ? "i" : "-",
+               (payload & AC_AMP_SET_LEFT)   ? "l" : "-",
+               (payload & AC_AMP_SET_RIGHT)  ? "r" : "-",
+               (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
+               (payload & AC_AMP_GAIN),
+               (payload & AC_AMP_MUTE) ? "muted" : "");
+        if (payload & AC_AMP_SET_LEFT) {
+            st->gain_left = payload & AC_AMP_GAIN;
+            st->mute_left = payload & AC_AMP_MUTE;
+        }
+        if (payload & AC_AMP_SET_RIGHT) {
+            st->gain_right = payload & AC_AMP_GAIN;
+            st->mute_right = payload & AC_AMP_MUTE;
+        }
+        hda_audio_set_amp(st);
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* not supported */
+    case AC_VERB_SET_POWER_STATE:
+    case AC_VERB_GET_POWER_STATE:
+    case AC_VERB_GET_SDI_SELECT:
+        hda_codec_response(hda, true, 0);
+        break;
+    default:
+        goto fail;
+    }
+    return;
+
+fail:
+    dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node ? node->name : "?", verb, payload);
+    hda_codec_response(hda, true, 0);
+}
+
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    int s;
+
+    a->running[stnr] = running;
+    for (s = 0; s < ARRAY_SIZE(a->st); s++) {
+        if (a->st[s].node == NULL) {
+            continue;
+        }
+        if (a->st[s].stream != stnr) {
+            continue;
+        }
+        hda_audio_set_running(&a->st[s], running);
+    }
+}
+
+static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node;
+    const desc_param *param;
+    uint32_t i, type;
+
+    a->desc = desc;
+    a->name = a->hda.qdev.info->name;
+    dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
+
+    AUD_register_card("hda", &a->card);
+    for (i = 0; i < a->desc->nnodes; i++) {
+        node = a->desc->nodes + i;
+        param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
+        if (NULL == param)
+            continue;
+        type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+        switch (type) {
+        case AC_WID_AUD_OUT:
+        case AC_WID_AUD_IN:
+            assert(node->stindex < ARRAY_SIZE(a->st));
+            st = a->st + node->stindex;
+            st->state = a;
+            st->node = node;
+            if (type == AC_WID_AUD_OUT) {
+                /* unmute output by default */
+                st->gain_left = QEMU_HDA_AMP_STEPS;
+                st->gain_right = QEMU_HDA_AMP_STEPS;
+                st->bpos = sizeof(st->buf);
+                st->output = true;
+            } else {
+                st->output = false;
+            }
+            st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
+                (1 << AC_FMT_CHAN_SHIFT);
+            hda_codec_parse_fmt(st->format, &st->as);
+            hda_audio_setup(st);
+            break;
+        }
+    }
+    return 0;
+}
+
+static int hda_audio_exit(HDACodecDevice *hda)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL) {
+            continue;
+        }
+        if (st->output) {
+            AUD_close_out(&a->card, st->voice.out);
+        } else {
+            AUD_close_in(&a->card, st->voice.in);
+        }
+    }
+    AUD_remove_card(&a->card);
+    return 0;
+}
+
+static int hda_audio_post_load(void *opaque, int version)
+{
+    HDAAudioState *a = opaque;
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL)
+            continue;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_audio_set_amp(st);
+        hda_audio_set_running(st, a->running[st->stream]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hda_audio_stream = {
+    .name = "hda-audio-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(stream, HDAAudioStream),
+        VMSTATE_UINT32(channel, HDAAudioStream),
+        VMSTATE_UINT32(format, HDAAudioStream),
+        VMSTATE_UINT32(gain_left, HDAAudioStream),
+        VMSTATE_UINT32(gain_right, HDAAudioStream),
+        VMSTATE_BOOL(mute_left, HDAAudioStream),
+        VMSTATE_BOOL(mute_right, HDAAudioStream),
+        VMSTATE_UINT32(bpos, HDAAudioStream),
+        VMSTATE_BUFFER(buf, HDAAudioStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_hda_audio = {
+    .name = "hda-audio",
+    .version_id = 1,
+    .post_load = hda_audio_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
+                             vmstate_hda_audio_stream,
+                             HDAAudioStream),
+        VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property hda_audio_properties[] = {
+    DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int hda_audio_init_output(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &output);
+}
+
+static int hda_audio_init_duplex(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &duplex);
+}
+
+static HDACodecDeviceInfo hda_audio_info_output = {
+    .qdev.name    = "hda-output",
+    .qdev.desc    = "HDA Audio Codec, output-only",
+    .qdev.size    = sizeof(HDAAudioState),
+    .qdev.vmsd    = &vmstate_hda_audio,
+    .qdev.props   = hda_audio_properties,
+    .init         = hda_audio_init_output,
+    .exit         = hda_audio_exit,
+    .command      = hda_audio_command,
+    .stream       = hda_audio_stream,
+};
+
+static HDACodecDeviceInfo hda_audio_info_duplex = {
+    .qdev.name    = "hda-duplex",
+    .qdev.desc    = "HDA Audio Codec, duplex",
+    .qdev.size    = sizeof(HDAAudioState),
+    .qdev.vmsd    = &vmstate_hda_audio,
+    .qdev.props   = hda_audio_properties,
+    .init         = hda_audio_init_duplex,
+    .exit         = hda_audio_exit,
+    .command      = hda_audio_command,
+    .stream       = hda_audio_stream,
+};
+
+static void hda_audio_register(void)
+{
+    hda_codec_register(&hda_audio_info_output);
+    hda_codec_register(&hda_audio_info_duplex);
+}
+device_init(hda_audio_register);
diff --git a/qemu-0.15.x/hw/heathrow_pic.c b/qemu-0.15.x/hw/heathrow_pic.c
new file mode 100644
index 0000000..5fd71a0
--- /dev/null
+++ b/qemu-0.15.x/hw/heathrow_pic.c
@@ -0,0 +1,218 @@
+/*
+ * Heathrow PIC support (OldWorld PowerMac)
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc_mac.h"
+
+/* debug PIC */
+//#define DEBUG_PIC
+
+#ifdef DEBUG_PIC
+#define PIC_DPRINTF(fmt, ...)                                   \
+    do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define PIC_DPRINTF(fmt, ...)
+#endif
+
+typedef struct HeathrowPIC {
+    uint32_t events;
+    uint32_t mask;
+    uint32_t levels;
+    uint32_t level_triggered;
+} HeathrowPIC;
+
+typedef struct HeathrowPICS {
+    HeathrowPIC pics[2];
+    qemu_irq *irqs;
+} HeathrowPICS;
+
+static inline int check_irq(HeathrowPIC *pic)
+{
+    return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
+}
+
+/* update the CPU irq state */
+static void heathrow_pic_update(HeathrowPICS *s)
+{
+    if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
+        qemu_irq_raise(s->irqs[0]);
+    } else {
+        qemu_irq_lower(s->irqs[0]);
+    }
+}
+
+static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int n;
+
+    n = ((addr & 0xfff) - 0x10) >> 4;
+    PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+    if (n >= 2)
+        return;
+    pic = &s->pics[n];
+    switch(addr & 0xf) {
+    case 0x04:
+        pic->mask = value;
+        heathrow_pic_update(s);
+        break;
+    case 0x08:
+        /* do not reset level triggered IRQs */
+        value &= ~pic->level_triggered;
+        pic->events &= ~value;
+        heathrow_pic_update(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int n;
+    uint32_t value;
+
+    n = ((addr & 0xfff) - 0x10) >> 4;
+    if (n >= 2) {
+        value = 0;
+    } else {
+        pic = &s->pics[n];
+        switch(addr & 0xf) {
+        case 0x0:
+            value = pic->events;
+            break;
+        case 0x4:
+            value = pic->mask;
+            break;
+        case 0xc:
+            value = pic->levels;
+            break;
+        default:
+            value = 0;
+            break;
+        }
+    }
+    PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+    return value;
+}
+
+static CPUWriteMemoryFunc * const pic_write[] = {
+    &pic_writel,
+    &pic_writel,
+    &pic_writel,
+};
+
+static CPUReadMemoryFunc * const pic_read[] = {
+    &pic_readl,
+    &pic_readl,
+    &pic_readl,
+};
+
+
+static void heathrow_pic_set_irq(void *opaque, int num, int level)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int irq_bit;
+
+#if defined(DEBUG)
+    {
+        static int last_level[64];
+        if (last_level[num] != level) {
+            PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
+            last_level[num] = level;
+        }
+    }
+#endif
+    pic = &s->pics[1 - (num >> 5)];
+    irq_bit = 1 << (num & 0x1f);
+    if (level) {
+        pic->events |= irq_bit & ~pic->level_triggered;
+        pic->levels |= irq_bit;
+    } else {
+        pic->levels &= ~irq_bit;
+    }
+    heathrow_pic_update(s);
+}
+
+static const VMStateDescription vmstate_heathrow_pic_one = {
+    .name = "heathrow_pic_one",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(events, HeathrowPIC),
+        VMSTATE_UINT32(mask, HeathrowPIC),
+        VMSTATE_UINT32(levels, HeathrowPIC),
+        VMSTATE_UINT32(level_triggered, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_heathrow_pic = {
+    .name = "heathrow_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
+                             vmstate_heathrow_pic_one, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void heathrow_pic_reset_one(HeathrowPIC *s)
+{
+    memset(s, '\0', sizeof(HeathrowPIC));
+}
+
+static void heathrow_pic_reset(void *opaque)
+{
+    HeathrowPICS *s = opaque;
+
+    heathrow_pic_reset_one(&s->pics[0]);
+    heathrow_pic_reset_one(&s->pics[1]);
+
+    s->pics[0].level_triggered = 0;
+    s->pics[1].level_triggered = 0x1ff00000;
+}
+
+qemu_irq *heathrow_pic_init(int *pmem_index,
+                            int nb_cpus, qemu_irq **irqs)
+{
+    HeathrowPICS *s;
+
+    s = qemu_mallocz(sizeof(HeathrowPICS));
+    /* only 1 CPU */
+    s->irqs = irqs[0];
+    *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
+                                         DEVICE_LITTLE_ENDIAN);
+
+    vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
+    qemu_register_reset(heathrow_pic_reset, s);
+    return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
+}
diff --git a/qemu-0.15.x/hw/hpet.c b/qemu-0.15.x/hw/hpet.c
new file mode 100644
index 0000000..4eda33d
--- /dev/null
+++ b/qemu-0.15.x/hw/hpet.c
@@ -0,0 +1,745 @@
+/*
+ *  High Precisition Event Timer emulation
+ *
+ *  Copyright (c) 2007 Alexander Graf
+ *  Copyright (c) 2008 IBM Corporation
+ *
+ *  Authors: Beth Kon <bkon at us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * *****************************************************************
+ *
+ * This driver attempts to emulate an HPET device in software.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "console.h"
+#include "qemu-timer.h"
+#include "hpet_emul.h"
+#include "sysbus.h"
+#include "mc146818rtc.h"
+
+//#define HPET_DEBUG
+#ifdef HPET_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define HPET_MSI_SUPPORT        0
+
+struct HPETState;
+typedef struct HPETTimer {  /* timers */
+    uint8_t tn;             /*timer number*/
+    QEMUTimer *qemu_timer;
+    struct HPETState *state;
+    /* Memory-mapped, software visible timer registers */
+    uint64_t config;        /* configuration/cap */
+    uint64_t cmp;           /* comparator */
+    uint64_t fsb;           /* FSB route */
+    /* Hidden register state */
+    uint64_t period;        /* Last value written to comparator */
+    uint8_t wrap_flag;      /* timer pop will indicate wrap for one-shot 32-bit
+                             * mode. Next pop will be actual timer expiration.
+                             */
+} HPETTimer;
+
+typedef struct HPETState {
+    SysBusDevice busdev;
+    uint64_t hpet_offset;
+    qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
+    uint32_t flags;
+    uint8_t rtc_irq_level;
+    uint8_t num_timers;
+    HPETTimer timer[HPET_MAX_TIMERS];
+
+    /* Memory-mapped, software visible registers */
+    uint64_t capability;        /* capabilities */
+    uint64_t config;            /* configuration */
+    uint64_t isr;               /* interrupt status reg */
+    uint64_t hpet_counter;      /* main counter */
+    uint8_t  hpet_id;           /* instance id */
+} HPETState;
+
+static uint32_t hpet_in_legacy_mode(HPETState *s)
+{
+    return s->config & HPET_CFG_LEGACY;
+}
+
+static uint32_t timer_int_route(struct HPETTimer *timer)
+{
+    return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
+}
+
+static uint32_t timer_fsb_route(HPETTimer *t)
+{
+    return t->config & HPET_TN_FSB_ENABLE;
+}
+
+static uint32_t hpet_enabled(HPETState *s)
+{
+    return s->config & HPET_CFG_ENABLE;
+}
+
+static uint32_t timer_is_periodic(HPETTimer *t)
+{
+    return t->config & HPET_TN_PERIODIC;
+}
+
+static uint32_t timer_enabled(HPETTimer *t)
+{
+    return t->config & HPET_TN_ENABLE;
+}
+
+static uint32_t hpet_time_after(uint64_t a, uint64_t b)
+{
+    return ((int32_t)(b) - (int32_t)(a) < 0);
+}
+
+static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
+{
+    return ((int64_t)(b) - (int64_t)(a) < 0);
+}
+
+static uint64_t ticks_to_ns(uint64_t value)
+{
+    return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
+}
+
+static uint64_t ns_to_ticks(uint64_t value)
+{
+    return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
+}
+
+static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
+{
+    new &= mask;
+    new |= old & ~mask;
+    return new;
+}
+
+static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+    return (!(old & mask) && (new & mask));
+}
+
+static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+    return ((old & mask) && !(new & mask));
+}
+
+static uint64_t hpet_get_ticks(HPETState *s)
+{
+    return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset);
+}
+
+/*
+ * calculate diff between comparator value and current ticks
+ */
+static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
+{
+
+    if (t->config & HPET_TN_32BIT) {
+        uint32_t diff, cmp;
+
+        cmp = (uint32_t)t->cmp;
+        diff = cmp - (uint32_t)current;
+        diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
+        return (uint64_t)diff;
+    } else {
+        uint64_t diff, cmp;
+
+        cmp = t->cmp;
+        diff = cmp - current;
+        diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
+        return diff;
+    }
+}
+
+static void update_irq(struct HPETTimer *timer, int set)
+{
+    uint64_t mask;
+    HPETState *s;
+    int route;
+
+    if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
+        /* if LegacyReplacementRoute bit is set, HPET specification requires
+         * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
+         * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
+         */
+        route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
+    } else {
+        route = timer_int_route(timer);
+    }
+    s = timer->state;
+    mask = 1 << timer->tn;
+    if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
+        s->isr &= ~mask;
+        if (!timer_fsb_route(timer)) {
+            qemu_irq_lower(s->irqs[route]);
+        }
+    } else if (timer_fsb_route(timer)) {
+        stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
+    } else if (timer->config & HPET_TN_TYPE_LEVEL) {
+        s->isr |= mask;
+        qemu_irq_raise(s->irqs[route]);
+    } else {
+        s->isr &= ~mask;
+        qemu_irq_pulse(s->irqs[route]);
+    }
+}
+
+static void hpet_pre_save(void *opaque)
+{
+    HPETState *s = opaque;
+
+    /* save current counter value */
+    s->hpet_counter = hpet_get_ticks(s);
+}
+
+static int hpet_pre_load(void *opaque)
+{
+    HPETState *s = opaque;
+
+    /* version 1 only supports 3, later versions will load the actual value */
+    s->num_timers = HPET_MIN_TIMERS;
+    return 0;
+}
+
+static int hpet_post_load(void *opaque, int version_id)
+{
+    HPETState *s = opaque;
+
+    /* Recalculate the offset between the main counter and guest time */
+    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
+
+    /* Push number of timers into capability returned via HPET_ID */
+    s->capability &= ~HPET_ID_NUM_TIM_MASK;
+    s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
+    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
+
+    /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
+    s->flags &= ~(1 << HPET_MSI_SUPPORT);
+    if (s->timer[0].config & HPET_TN_FSB_CAP) {
+        s->flags |= 1 << HPET_MSI_SUPPORT;
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hpet_timer = {
+    .name = "hpet_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(tn, HPETTimer),
+        VMSTATE_UINT64(config, HPETTimer),
+        VMSTATE_UINT64(cmp, HPETTimer),
+        VMSTATE_UINT64(fsb, HPETTimer),
+        VMSTATE_UINT64(period, HPETTimer),
+        VMSTATE_UINT8(wrap_flag, HPETTimer),
+        VMSTATE_TIMER(qemu_timer, HPETTimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_hpet = {
+    .name = "hpet",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = hpet_pre_save,
+    .pre_load = hpet_pre_load,
+    .post_load = hpet_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(config, HPETState),
+        VMSTATE_UINT64(isr, HPETState),
+        VMSTATE_UINT64(hpet_counter, HPETState),
+        VMSTATE_UINT8_V(num_timers, HPETState, 2),
+        VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
+                                    vmstate_hpet_timer, HPETTimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * timer expiration callback
+ */
+static void hpet_timer(void *opaque)
+{
+    HPETTimer *t = opaque;
+    uint64_t diff;
+
+    uint64_t period = t->period;
+    uint64_t cur_tick = hpet_get_ticks(t->state);
+
+    if (timer_is_periodic(t) && period != 0) {
+        if (t->config & HPET_TN_32BIT) {
+            while (hpet_time_after(cur_tick, t->cmp)) {
+                t->cmp = (uint32_t)(t->cmp + t->period);
+            }
+        } else {
+            while (hpet_time_after64(cur_tick, t->cmp)) {
+                t->cmp += period;
+            }
+        }
+        diff = hpet_calculate_diff(t, cur_tick);
+        qemu_mod_timer(t->qemu_timer,
+                       qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
+    } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+        if (t->wrap_flag) {
+            diff = hpet_calculate_diff(t, cur_tick);
+            qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) +
+                           (int64_t)ticks_to_ns(diff));
+            t->wrap_flag = 0;
+        }
+    }
+    update_irq(t, 1);
+}
+
+static void hpet_set_timer(HPETTimer *t)
+{
+    uint64_t diff;
+    uint32_t wrap_diff;  /* how many ticks until we wrap? */
+    uint64_t cur_tick = hpet_get_ticks(t->state);
+
+    /* whenever new timer is being set up, make sure wrap_flag is 0 */
+    t->wrap_flag = 0;
+    diff = hpet_calculate_diff(t, cur_tick);
+
+    /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
+     * counter wraps in addition to an interrupt with comparator match.
+     */
+    if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+        wrap_diff = 0xffffffff - (uint32_t)cur_tick;
+        if (wrap_diff < (uint32_t)diff) {
+            diff = wrap_diff;
+            t->wrap_flag = 1;
+        }
+    }
+    qemu_mod_timer(t->qemu_timer,
+                   qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
+}
+
+static void hpet_del_timer(HPETTimer *t)
+{
+    qemu_del_timer(t->qemu_timer);
+    update_irq(t, 0);
+}
+
+#ifdef HPET_DEBUG
+static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+    printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
+    return 0;
+}
+
+static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+    printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
+    return 0;
+}
+#endif
+
+static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+    HPETState *s = opaque;
+    uint64_t cur_tick, index;
+
+    DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
+    index = addr;
+    /*address range of all TN regs*/
+    if (index >= 0x100 && index <= 0x3ff) {
+        uint8_t timer_id = (addr - 0x100) / 0x20;
+        HPETTimer *timer = &s->timer[timer_id];
+
+        if (timer_id > s->num_timers) {
+            DPRINTF("qemu: timer id out of range\n");
+            return 0;
+        }
+
+        switch ((addr - 0x100) % 0x20) {
+        case HPET_TN_CFG:
+            return timer->config;
+        case HPET_TN_CFG + 4: // Interrupt capabilities
+            return timer->config >> 32;
+        case HPET_TN_CMP: // comparator register
+            return timer->cmp;
+        case HPET_TN_CMP + 4:
+            return timer->cmp >> 32;
+        case HPET_TN_ROUTE:
+            return timer->fsb;
+        case HPET_TN_ROUTE + 4:
+            return timer->fsb >> 32;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_readl\n");
+            break;
+        }
+    } else {
+        switch (index) {
+        case HPET_ID:
+            return s->capability;
+        case HPET_PERIOD:
+            return s->capability >> 32;
+        case HPET_CFG:
+            return s->config;
+        case HPET_CFG + 4:
+            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
+            return 0;
+        case HPET_COUNTER:
+            if (hpet_enabled(s)) {
+                cur_tick = hpet_get_ticks(s);
+            } else {
+                cur_tick = s->hpet_counter;
+            }
+            DPRINTF("qemu: reading counter  = %" PRIx64 "\n", cur_tick);
+            return cur_tick;
+        case HPET_COUNTER + 4:
+            if (hpet_enabled(s)) {
+                cur_tick = hpet_get_ticks(s);
+            } else {
+                cur_tick = s->hpet_counter;
+            }
+            DPRINTF("qemu: reading counter + 4  = %" PRIx64 "\n", cur_tick);
+            return cur_tick >> 32;
+        case HPET_STATUS:
+            return s->isr;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_readl\n");
+            break;
+        }
+    }
+    return 0;
+}
+
+#ifdef HPET_DEBUG
+static void hpet_ram_writeb(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    printf("qemu: invalid hpet_write b at %" PRIx64 " = %#x\n",
+           addr, value);
+}
+
+static void hpet_ram_writew(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    printf("qemu: invalid hpet_write w at %" PRIx64 " = %#x\n",
+           addr, value);
+}
+#endif
+
+static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    int i;
+    HPETState *s = opaque;
+    uint64_t old_val, new_val, val, index;
+
+    DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
+    index = addr;
+    old_val = hpet_ram_readl(opaque, addr);
+    new_val = value;
+
+    /*address range of all TN regs*/
+    if (index >= 0x100 && index <= 0x3ff) {
+        uint8_t timer_id = (addr - 0x100) / 0x20;
+        HPETTimer *timer = &s->timer[timer_id];
+
+        DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
+        if (timer_id > s->num_timers) {
+            DPRINTF("qemu: timer id out of range\n");
+            return;
+        }
+        switch ((addr - 0x100) % 0x20) {
+        case HPET_TN_CFG:
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
+            if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
+                update_irq(timer, 0);
+            }
+            val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
+            timer->config = (timer->config & 0xffffffff00000000ULL) | val;
+            if (new_val & HPET_TN_32BIT) {
+                timer->cmp = (uint32_t)timer->cmp;
+                timer->period = (uint32_t)timer->period;
+            }
+            if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+                hpet_set_timer(timer);
+            } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+                hpet_del_timer(timer);
+            }
+            break;
+        case HPET_TN_CFG + 4: // Interrupt capabilities
+            DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
+            break;
+        case HPET_TN_CMP: // comparator register
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
+            if (timer->config & HPET_TN_32BIT) {
+                new_val = (uint32_t)new_val;
+            }
+            if (!timer_is_periodic(timer)
+                || (timer->config & HPET_TN_SETVAL)) {
+                timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
+            }
+            if (timer_is_periodic(timer)) {
+                /*
+                 * FIXME: Clamp period to reasonable min value?
+                 * Clamp period to reasonable max value
+                 */
+                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+                timer->period =
+                    (timer->period & 0xffffffff00000000ULL) | new_val;
+            }
+            timer->config &= ~HPET_TN_SETVAL;
+            if (hpet_enabled(s)) {
+                hpet_set_timer(timer);
+            }
+            break;
+        case HPET_TN_CMP + 4: // comparator register high order
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
+            if (!timer_is_periodic(timer)
+                || (timer->config & HPET_TN_SETVAL)) {
+                timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
+            } else {
+                /*
+                 * FIXME: Clamp period to reasonable min value?
+                 * Clamp period to reasonable max value
+                 */
+                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+                timer->period =
+                    (timer->period & 0xffffffffULL) | new_val << 32;
+                }
+                timer->config &= ~HPET_TN_SETVAL;
+                if (hpet_enabled(s)) {
+                    hpet_set_timer(timer);
+                }
+                break;
+        case HPET_TN_ROUTE:
+            timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
+            break;
+        case HPET_TN_ROUTE + 4:
+            timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
+            break;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_writel\n");
+            break;
+        }
+        return;
+    } else {
+        switch (index) {
+        case HPET_ID:
+            return;
+        case HPET_CFG:
+            val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+            s->config = (s->config & 0xffffffff00000000ULL) | val;
+            if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+                /* Enable main counter and interrupt generation. */
+                s->hpet_offset =
+                    ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
+                for (i = 0; i < s->num_timers; i++) {
+                    if ((&s->timer[i])->cmp != ~0ULL) {
+                        hpet_set_timer(&s->timer[i]);
+                    }
+                }
+            } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+                /* Halt main counter and disable interrupt generation. */
+                s->hpet_counter = hpet_get_ticks(s);
+                for (i = 0; i < s->num_timers; i++) {
+                    hpet_del_timer(&s->timer[i]);
+                }
+            }
+            /* i8254 and RTC are disabled when HPET is in legacy mode */
+            if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+                hpet_pit_disable();
+                qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
+            } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+                hpet_pit_enable();
+                qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
+            }
+            break;
+        case HPET_CFG + 4:
+            DPRINTF("qemu: invalid HPET_CFG+4 write \n");
+            break;
+        case HPET_STATUS:
+            val = new_val & s->isr;
+            for (i = 0; i < s->num_timers; i++) {
+                if (val & (1 << i)) {
+                    update_irq(&s->timer[i], 0);
+                }
+            }
+            break;
+        case HPET_COUNTER:
+            if (hpet_enabled(s)) {
+                DPRINTF("qemu: Writing counter while HPET enabled!\n");
+            }
+            s->hpet_counter =
+                (s->hpet_counter & 0xffffffff00000000ULL) | value;
+            DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
+                    value, s->hpet_counter);
+            break;
+        case HPET_COUNTER + 4:
+            if (hpet_enabled(s)) {
+                DPRINTF("qemu: Writing counter while HPET enabled!\n");
+            }
+            s->hpet_counter =
+                (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
+            DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
+                    value, s->hpet_counter);
+            break;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_writel\n");
+            break;
+        }
+    }
+}
+
+static CPUReadMemoryFunc * const hpet_ram_read[] = {
+#ifdef HPET_DEBUG
+    hpet_ram_readb,
+    hpet_ram_readw,
+#else
+    NULL,
+    NULL,
+#endif
+    hpet_ram_readl,
+};
+
+static CPUWriteMemoryFunc * const hpet_ram_write[] = {
+#ifdef HPET_DEBUG
+    hpet_ram_writeb,
+    hpet_ram_writew,
+#else
+    NULL,
+    NULL,
+#endif
+    hpet_ram_writel,
+};
+
+static void hpet_reset(DeviceState *d)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d));
+    int i;
+    static int count = 0;
+
+    for (i = 0; i < s->num_timers; i++) {
+        HPETTimer *timer = &s->timer[i];
+
+        hpet_del_timer(timer);
+        timer->cmp = ~0ULL;
+        timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
+        if (s->flags & (1 << HPET_MSI_SUPPORT)) {
+            timer->config |= HPET_TN_FSB_CAP;
+        }
+        /* advertise availability of ioapic inti2 */
+        timer->config |=  0x00000004ULL << 32;
+        timer->period = 0ULL;
+        timer->wrap_flag = 0;
+    }
+
+    s->hpet_counter = 0ULL;
+    s->hpet_offset = 0ULL;
+    s->config = 0ULL;
+    if (count > 0) {
+        /* we don't enable pit when hpet_reset is first called (by hpet_init)
+         * because hpet is taking over for pit here. On subsequent invocations,
+         * hpet_reset is called due to system reset. At this point control must
+         * be returned to pit until SW reenables hpet.
+         */
+        hpet_pit_enable();
+    }
+    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
+    hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
+    count = 1;
+}
+
+static void hpet_handle_rtc_irq(void *opaque, int n, int level)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, opaque);
+
+    s->rtc_irq_level = level;
+    if (!hpet_in_legacy_mode(s)) {
+        qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+    }
+}
+
+static int hpet_init(SysBusDevice *dev)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, dev);
+    int i, iomemtype;
+    HPETTimer *timer;
+
+    if (hpet_cfg.count == UINT8_MAX) {
+        /* first instance */
+        hpet_cfg.count = 0;
+    }
+
+    if (hpet_cfg.count == 8) {
+        fprintf(stderr, "Only 8 instances of HPET is allowed\n");
+        return -1;
+    }
+
+    s->hpet_id = hpet_cfg.count++;
+
+    for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
+        sysbus_init_irq(dev, &s->irqs[i]);
+    }
+
+    if (s->num_timers < HPET_MIN_TIMERS) {
+        s->num_timers = HPET_MIN_TIMERS;
+    } else if (s->num_timers > HPET_MAX_TIMERS) {
+        s->num_timers = HPET_MAX_TIMERS;
+    }
+    for (i = 0; i < HPET_MAX_TIMERS; i++) {
+        timer = &s->timer[i];
+        timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer);
+        timer->tn = i;
+        timer->state = s;
+    }
+
+    /* 64-bit main counter; LegacyReplacementRoute. */
+    s->capability = 0x8086a001ULL;
+    s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
+    s->capability |= ((HPET_CLK_PERIOD) << 32);
+
+    qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
+
+    /* HPET Area */
+    iomemtype = cpu_register_io_memory(hpet_ram_read,
+                                       hpet_ram_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x400, iomemtype);
+    return 0;
+}
+
+static SysBusDeviceInfo hpet_device_info = {
+    .qdev.name    = "hpet",
+    .qdev.size    = sizeof(HPETState),
+    .qdev.no_user = 1,
+    .qdev.vmsd    = &vmstate_hpet,
+    .qdev.reset   = hpet_reset,
+    .init         = hpet_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+        DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void hpet_register_device(void)
+{
+    sysbus_register_withprop(&hpet_device_info);
+}
+
+device_init(hpet_register_device)
diff --git a/qemu-0.15.x/hw/hpet_emul.h b/qemu-0.15.x/hw/hpet_emul.h
new file mode 100644
index 0000000..8bf312a
--- /dev/null
+++ b/qemu-0.15.x/hw/hpet_emul.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU Emulated HPET support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Beth Kon   <bkon at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_HPET_EMUL_H
+#define QEMU_HPET_EMUL_H
+
+#define HPET_BASE               0xfed00000
+#define HPET_CLK_PERIOD         10000000ULL /* 10000000 femtoseconds == 10ns*/
+
+#define FS_PER_NS 1000000
+#define HPET_MIN_TIMERS         3
+#define HPET_MAX_TIMERS         32
+
+#define HPET_NUM_IRQ_ROUTES     32
+
+#define HPET_CFG_ENABLE 0x001
+#define HPET_CFG_LEGACY 0x002
+
+#define HPET_ID         0x000
+#define HPET_PERIOD     0x004
+#define HPET_CFG        0x010
+#define HPET_STATUS     0x020
+#define HPET_COUNTER    0x0f0
+#define HPET_TN_CFG     0x000
+#define HPET_TN_CMP     0x008
+#define HPET_TN_ROUTE   0x010
+#define HPET_CFG_WRITE_MASK  0x3
+
+#define HPET_ID_NUM_TIM_SHIFT   8
+#define HPET_ID_NUM_TIM_MASK    0x1f00
+
+#define HPET_TN_TYPE_LEVEL       0x002
+#define HPET_TN_ENABLE           0x004
+#define HPET_TN_PERIODIC         0x008
+#define HPET_TN_PERIODIC_CAP     0x010
+#define HPET_TN_SIZE_CAP         0x020
+#define HPET_TN_SETVAL           0x040
+#define HPET_TN_32BIT            0x100
+#define HPET_TN_INT_ROUTE_MASK  0x3e00
+#define HPET_TN_FSB_ENABLE      0x4000
+#define HPET_TN_FSB_CAP         0x8000
+#define HPET_TN_CFG_WRITE_MASK  0x7f4e
+#define HPET_TN_INT_ROUTE_SHIFT      9
+#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
+#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
+
+struct hpet_fw_entry
+{
+    uint32_t event_timer_block_id;
+    uint64_t address;
+    uint16_t min_tick;
+    uint8_t page_prot;
+} __attribute__ ((packed));
+
+struct hpet_fw_config
+{
+    uint8_t count;
+    struct hpet_fw_entry hpet[8];
+} __attribute__ ((packed));
+
+extern struct hpet_fw_config hpet_cfg;
+#endif
diff --git a/qemu-0.15.x/hw/hw.h b/qemu-0.15.x/hw/hw.h
new file mode 100644
index 0000000..9dd7096
--- /dev/null
+++ b/qemu-0.15.x/hw/hw.h
@@ -0,0 +1,925 @@
+/* Declarations for use by hardware emulation.  */
+#ifndef QEMU_HW_H
+#define QEMU_HW_H
+
+#include "qemu-common.h"
+
+#if defined(TARGET_PHYS_ADDR_BITS) && !defined(NEED_CPU_H)
+#include "cpu-common.h"
+#endif
+
+#include "ioport.h"
+#include "irq.h"
+
+/* VM Load/Save */
+
+/* This function writes a chunk of data to a file at the given position.
+ * The pos argument can be ignored if the file is only being used for
+ * streaming.  The handler should try to write all of the data it can.
+ */
+typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Read a chunk of data from a file at the given position.  The pos argument
+ * can be ignored if the file is only be used for streaming.  The number of
+ * bytes actually read should be returned.
+ */
+typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Close a file and return an error code */
+typedef int (QEMUFileCloseFunc)(void *opaque);
+
+/* Called to determine if the file has exceeded it's bandwidth allocation.  The
+ * bandwidth capping is a soft limit, not a hard limit.
+ */
+typedef int (QEMUFileRateLimit)(void *opaque);
+
+/* Called to change the current bandwidth allocation. This function must return
+ * the new actual bandwidth. It should be new_rate if everything goes ok, and
+ * the old rate otherwise
+ */
+typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate);
+typedef int64_t (QEMUFileGetRateLimit)(void *opaque);
+
+QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit,
+			 QEMUFileGetRateLimit *get_rate_limit);
+QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
+QEMUFile *qemu_fopen_socket(int fd);
+QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+int qemu_stdio_fd(QEMUFile *f);
+void qemu_fflush(QEMUFile *f);
+int qemu_fclose(QEMUFile *f);
+void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
+void qemu_put_byte(QEMUFile *f, int v);
+
+static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, (int)v);
+}
+
+#define qemu_put_sbyte qemu_put_byte
+
+void qemu_put_be16(QEMUFile *f, unsigned int v);
+void qemu_put_be32(QEMUFile *f, unsigned int v);
+void qemu_put_be64(QEMUFile *f, uint64_t v);
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
+int qemu_get_byte(QEMUFile *f);
+
+static inline unsigned int qemu_get_ubyte(QEMUFile *f)
+{
+    return (unsigned int)qemu_get_byte(f);
+}
+
+#define qemu_get_sbyte qemu_get_byte
+
+unsigned int qemu_get_be16(QEMUFile *f);
+unsigned int qemu_get_be32(QEMUFile *f);
+uint64_t qemu_get_be64(QEMUFile *f);
+int qemu_file_rate_limit(QEMUFile *f);
+int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
+int64_t qemu_file_get_rate_limit(QEMUFile *f);
+int qemu_file_has_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f);
+
+/* Try to send any outstanding data.  This function is useful when output is
+ * halted due to rate limiting or EAGAIN errors occur as it can be used to
+ * resume output. */
+void qemu_file_put_notify(QEMUFile *f);
+
+static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
+{
+    qemu_put_be64(f, *pv);
+}
+
+static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv)
+{
+    qemu_put_be32(f, *pv);
+}
+
+static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv)
+{
+    qemu_put_be16(f, *pv);
+}
+
+static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv)
+{
+    qemu_put_byte(f, *pv);
+}
+
+static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv)
+{
+    *pv = qemu_get_be64(f);
+}
+
+static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv)
+{
+    *pv = qemu_get_be32(f);
+}
+
+static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv)
+{
+    *pv = qemu_get_be16(f);
+}
+
+static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv)
+{
+    *pv = qemu_get_byte(f);
+}
+
+// Signed versions for type safety
+static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size)
+{
+    qemu_put_buffer(f, (const uint8_t *)buf, size);
+}
+
+static inline void qemu_put_sbe16(QEMUFile *f, int v)
+{
+    qemu_put_be16(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe32(QEMUFile *f, int v)
+{
+    qemu_put_be32(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe64(QEMUFile *f, int64_t v)
+{
+    qemu_put_be64(f, (uint64_t)v);
+}
+
+static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size)
+{
+    return qemu_get_buffer(f, (uint8_t *)buf, size);
+}
+
+static inline int qemu_get_sbe16(QEMUFile *f)
+{
+    return (int)qemu_get_be16(f);
+}
+
+static inline int qemu_get_sbe32(QEMUFile *f)
+{
+    return (int)qemu_get_be32(f);
+}
+
+static inline int64_t qemu_get_sbe64(QEMUFile *f)
+{
+    return (int64_t)qemu_get_be64(f);
+}
+
+static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv)
+{
+    qemu_put_8s(f, (const uint8_t *)pv);
+}
+
+static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv)
+{
+    qemu_put_be16s(f, (const uint16_t *)pv);
+}
+
+static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv)
+{
+    qemu_put_be32s(f, (const uint32_t *)pv);
+}
+
+static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv)
+{
+    qemu_put_be64s(f, (const uint64_t *)pv);
+}
+
+static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv)
+{
+    qemu_get_8s(f, (uint8_t *)pv);
+}
+
+static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv)
+{
+    qemu_get_be16s(f, (uint16_t *)pv);
+}
+
+static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv)
+{
+    qemu_get_be32s(f, (uint32_t *)pv);
+}
+
+static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
+{
+    qemu_get_be64s(f, (uint64_t *)pv);
+}
+
+#ifdef NEED_CPU_H
+#if TARGET_LONG_BITS == 64
+#define qemu_put_betl qemu_put_be64
+#define qemu_get_betl qemu_get_be64
+#define qemu_put_betls qemu_put_be64s
+#define qemu_get_betls qemu_get_be64s
+#define qemu_put_sbetl qemu_put_sbe64
+#define qemu_get_sbetl qemu_get_sbe64
+#define qemu_put_sbetls qemu_put_sbe64s
+#define qemu_get_sbetls qemu_get_sbe64s
+#else
+#define qemu_put_betl qemu_put_be32
+#define qemu_get_betl qemu_get_be32
+#define qemu_put_betls qemu_put_be32s
+#define qemu_get_betls qemu_get_be32s
+#define qemu_put_sbetl qemu_put_sbe32
+#define qemu_get_sbetl qemu_get_sbe32
+#define qemu_put_sbetls qemu_put_sbe32s
+#define qemu_get_sbetls qemu_get_sbe32s
+#endif
+#endif
+
+int64_t qemu_ftell(QEMUFile *f);
+int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
+
+typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
+typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
+                                 void *opaque);
+typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+
+int register_savevm(DeviceState *dev,
+                    const char *idstr,
+                    int instance_id,
+                    int version_id,
+                    SaveStateHandler *save_state,
+                    LoadStateHandler *load_state,
+                    void *opaque);
+
+int register_savevm_live(DeviceState *dev,
+                         const char *idstr,
+                         int instance_id,
+                         int version_id,
+                         SaveSetParamsHandler *set_params,
+			 SaveLiveStateHandler *save_live_state,
+                         SaveStateHandler *save_state,
+                         LoadStateHandler *load_state,
+                         void *opaque);
+
+void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+                                                                void *opaque);
+
+typedef void QEMUResetHandler(void *opaque);
+
+void qemu_register_reset(QEMUResetHandler *func, void *opaque);
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
+
+/* handler to set the boot_device order for a specific type of QEMUMachine */
+/* return 0 if success */
+typedef int QEMUBootSetHandler(void *opaque, const char *boot_devices);
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
+int qemu_boot_set(const char *boot_devices);
+
+typedef struct VMStateInfo VMStateInfo;
+typedef struct VMStateDescription VMStateDescription;
+
+struct VMStateInfo {
+    const char *name;
+    int (*get)(QEMUFile *f, void *pv, size_t size);
+    void (*put)(QEMUFile *f, void *pv, size_t size);
+};
+
+enum VMStateFlags {
+    VMS_SINGLE           = 0x001,
+    VMS_POINTER          = 0x002,
+    VMS_ARRAY            = 0x004,
+    VMS_STRUCT           = 0x008,
+    VMS_VARRAY_INT32     = 0x010,  /* Array with size in int32_t field*/
+    VMS_BUFFER           = 0x020,  /* static sized buffer */
+    VMS_ARRAY_OF_POINTER = 0x040,
+    VMS_VARRAY_UINT16    = 0x080,  /* Array with size in uint16_t field */
+    VMS_VBUFFER          = 0x100,  /* Buffer with size in int32_t field */
+    VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
+    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
+    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
+};
+
+typedef struct {
+    const char *name;
+    size_t offset;
+    size_t size;
+    size_t start;
+    int num;
+    size_t num_offset;
+    size_t size_offset;
+    const VMStateInfo *info;
+    enum VMStateFlags flags;
+    const VMStateDescription *vmsd;
+    int version_id;
+    bool (*field_exists)(void *opaque, int version_id);
+} VMStateField;
+
+typedef struct VMStateSubsection {
+    const VMStateDescription *vmsd;
+    bool (*needed)(void *opaque);
+} VMStateSubsection;
+
+struct VMStateDescription {
+    const char *name;
+    int version_id;
+    int minimum_version_id;
+    int minimum_version_id_old;
+    LoadStateHandler *load_state_old;
+    int (*pre_load)(void *opaque);
+    int (*post_load)(void *opaque, int version_id);
+    void (*pre_save)(void *opaque);
+    VMStateField *fields;
+    const VMStateSubsection *subsections;
+};
+
+extern const VMStateInfo vmstate_info_bool;
+
+extern const VMStateInfo vmstate_info_int8;
+extern const VMStateInfo vmstate_info_int16;
+extern const VMStateInfo vmstate_info_int32;
+extern const VMStateInfo vmstate_info_int64;
+
+extern const VMStateInfo vmstate_info_uint8_equal;
+extern const VMStateInfo vmstate_info_uint16_equal;
+extern const VMStateInfo vmstate_info_int32_equal;
+extern const VMStateInfo vmstate_info_uint32_equal;
+extern const VMStateInfo vmstate_info_int32_le;
+
+extern const VMStateInfo vmstate_info_uint8;
+extern const VMStateInfo vmstate_info_uint16;
+extern const VMStateInfo vmstate_info_uint32;
+extern const VMStateInfo vmstate_info_uint64;
+
+extern const VMStateInfo vmstate_info_timer;
+extern const VMStateInfo vmstate_info_ptimer;
+extern const VMStateInfo vmstate_info_buffer;
+extern const VMStateInfo vmstate_info_unused_buffer;
+
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+
+#define vmstate_offset_value(_state, _field, _type)                  \
+    (offsetof(_state, _field) +                                      \
+     type_check(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_pointer(_state, _field, _type)                \
+    (offsetof(_state, _field) +                                      \
+     type_check_pointer(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_array(_state, _field, _type, _num)            \
+    (offsetof(_state, _field) +                                      \
+     type_check_array(_type, typeof_field(_state, _field), _num))
+
+#define vmstate_offset_sub_array(_state, _field, _type, _start)      \
+    (offsetof(_state, _field[_start]))
+
+#define vmstate_offset_buffer(_state, _field)                        \
+    vmstate_offset_array(_state, _field, uint8_t,                    \
+                         sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = sizeof(_type),                                   \
+    .info         = &(_info),                                        \
+    .flags        = VMS_SINGLE,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_POINTER(_field, _state, _version, _info, _type) {    \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_SINGLE|VMS_POINTER,                            \
+    .offset     = vmstate_offset_value(_state, _field, _type),       \
+}
+
+#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) {  \
+    .name       = (stringify(_field)),                               \
+    .info       = &(_info),                                          \
+    .field_exists = (_test),                                         \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_SINGLE|VMS_POINTER,                            \
+    .offset     = vmstate_offset_value(_state, _field, _type),       \
+}
+
+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY,                                         \
+    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
+    .name         = (stringify(_field)),                              \
+    .field_exists = (_test),                                          \
+    .num          = (_num),                                           \
+    .info         = &(_info),                                         \
+    .size         = sizeof(_type),                                    \
+    .flags        = VMS_ARRAY,                                        \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY,                                         \
+    .offset     = vmstate_offset_sub_array(_state, _field, _type, _start), \
+}
+
+#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_INT32,                                  \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_INT32|VMS_POINTER,                      \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_UINT32|VMS_POINTER,                     \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_UINT16,                                 \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .field_exists = (_test),                                         \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_POINTER,                          \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY|VMS_ARRAY_OF_POINTER,                    \
+    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .num          = (_num),                                          \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_ARRAY,                            \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT,       \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT,      \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_INT32,                       \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = (_size - _start),                                \
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_BUFFER,                                      \
+    .offset       = vmstate_offset_buffer(_state, _field) + _start,  \
+}
+
+#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .size         = (_multiply),                                      \
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_MULTIPLY,                        \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, int32_t),\
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .size       = (_size),                                           \
+    .info       = &(_info),                                          \
+    .flags      = VMS_BUFFER,                                        \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) {              \
+    .name         = "unused",                                        \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .size         = (_size),                                         \
+    .info         = &vmstate_info_unused_buffer,                     \
+    .flags        = VMS_BUFFER,                                      \
+}
+extern const VMStateDescription vmstate_pci_device;
+
+#define VMSTATE_PCI_DEVICE(_field, _state) {                         \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pci_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+}
+
+#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pci_device,                               \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, PCIDevice), \
+}
+
+extern const VMStateDescription vmstate_pcie_device;
+
+#define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
+    .name       = (stringify(_field)),                               \
+    .version_id = 2,                                                 \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pcie_device,                              \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+}
+
+extern const VMStateDescription vmstate_i2c_slave;
+
+#define VMSTATE_I2C_SLAVE(_field, _state) {                          \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(i2c_slave),                                 \
+    .vmsd       = &vmstate_i2c_slave,                                \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, i2c_slave),   \
+}
+
+extern const VMStateDescription vmstate_usb_device;
+
+#define VMSTATE_USB_DEVICE(_field, _state) {                         \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(USBDevice),                                 \
+    .vmsd       = &vmstate_usb_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
+}
+
+#define vmstate_offset_macaddr(_state, _field)                       \
+    vmstate_offset_array(_state, _field.a, uint8_t,                \
+                         sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_MACADDR(_field, _state) {                            \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(MACAddr),                                   \
+    .info       = &vmstate_info_buffer,                              \
+    .flags      = VMS_BUFFER,                                        \
+    .offset     = vmstate_offset_macaddr(_state, _field),            \
+}
+
+extern const VMStateDescription vmstate_ptimer;
+
+#define VMSTATE_PTIMER(_field, _state) {                             \
+    .name       = (stringify(_field)),                               \
+    .version_id = (1),                                               \
+    .vmsd       = &vmstate_ptimer,                                   \
+    .size       = sizeof(ptimer_state *),                            \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, ptimer_state), \
+}
+
+/* _f : field name
+   _f_n : num of elements field_name
+   _n : num of elements
+   _s : struct state name
+   _v : version
+*/
+
+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type)        \
+    VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+
+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type)        \
+    VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
+    VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
+
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+    VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
+            _vmsd, _type)
+
+#define VMSTATE_BOOL_V(_f, _s, _v)                                    \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_INT8_V(_f, _s, _v)                                    \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_BOOL(_f, _s)                                          \
+    VMSTATE_BOOL_V(_f, _s, 0)
+
+#define VMSTATE_INT8(_f, _s)                                          \
+    VMSTATE_INT8_V(_f, _s, 0)
+#define VMSTATE_INT16(_f, _s)                                         \
+    VMSTATE_INT16_V(_f, _s, 0)
+#define VMSTATE_INT32(_f, _s)                                         \
+    VMSTATE_INT32_V(_f, _s, 0)
+#define VMSTATE_INT64(_f, _s)                                         \
+    VMSTATE_INT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8(_f, _s)                                         \
+    VMSTATE_UINT8_V(_f, _s, 0)
+#define VMSTATE_UINT16(_f, _s)                                        \
+    VMSTATE_UINT16_V(_f, _s, 0)
+#define VMSTATE_UINT32(_f, _s)                                        \
+    VMSTATE_UINT32_V(_f, _s, 0)
+#define VMSTATE_UINT64(_f, _s)                                        \
+    VMSTATE_UINT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
+
+#define VMSTATE_UINT16_EQUAL(_f, _s)                                  \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v)                            \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_INT32_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
+
+#define VMSTATE_UINT32_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+
+#define VMSTATE_INT32_LE(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+
+#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT32_TEST(_f, _s, _t)                                  \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_TIMER_TEST(_f, _s, _test)                             \
+    VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_TIMER(_f, _s)                                         \
+    VMSTATE_TIMER_TEST(_f, _s, NULL)
+
+#define VMSTATE_TIMER_ARRAY(_f, _s, _n)                              \
+    VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
+    VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT16_ARRAY(_f, _s, _n)                               \
+    VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT8_ARRAY(_f, _s, _n)                               \
+    VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
+
+#define VMSTATE_INT16_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t)
+
+#define VMSTATE_INT32_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num)                \
+    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_INT64_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_BUFFER_V(_f, _s, _v)                                  \
+    VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER(_f, _s)                                        \
+    VMSTATE_BUFFER_V(_f, _s, 0)
+
+#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size)                         \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
+    VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size)                        \
+    VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size)                    \
+    VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
+
+#define VMSTATE_BUFFER_TEST(_f, _s, _test)                            \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size)        \
+    VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
+
+#define VMSTATE_UNUSED_V(_v, _size)                                   \
+    VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
+
+#define VMSTATE_UNUSED(_size)                                         \
+    VMSTATE_UNUSED_V(0, _size)
+
+#define VMSTATE_UNUSED_TEST(_test, _size)                             \
+    VMSTATE_UNUSED_BUFFER(_test, 0, _size)
+
+#ifdef NEED_CPU_H
+#if TARGET_LONG_BITS == 64
+#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
+    VMSTATE_UINT64_V(_f, _s, _v)
+#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
+#else
+#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
+    VMSTATE_UINT32_V(_f, _s, _v)
+#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
+#endif
+#define VMSTATE_UINTTL(_f, _s)                                        \
+    VMSTATE_UINTTL_V(_f, _s, 0)
+#define VMSTATE_UINTTL_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
+
+#endif
+
+#define VMSTATE_END_OF_LIST()                                         \
+    {}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, int version_id);
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+                        void *opaque);
+int vmstate_register(DeviceState *dev, int instance_id,
+                     const VMStateDescription *vmsd, void *base);
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+                                   const VMStateDescription *vmsd,
+                                   void *base, int alias_id,
+                                   int required_for_version);
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+                        void *opaque);
+#endif
diff --git a/qemu-0.15.x/hw/i2c.c b/qemu-0.15.x/hw/i2c.c
new file mode 100644
index 0000000..49b9ecb
--- /dev/null
+++ b/qemu-0.15.x/hw/i2c.c
@@ -0,0 +1,196 @@
+/*
+ * QEMU I2C bus interface.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "i2c.h"
+
+struct i2c_bus
+{
+    BusState qbus;
+    i2c_slave *current_dev;
+    i2c_slave *dev;
+    uint8_t saved_address;
+};
+
+static struct BusInfo i2c_bus_info = {
+    .name = "I2C",
+    .size = sizeof(i2c_bus),
+    .props = (Property[]) {
+        DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void i2c_bus_pre_save(void *opaque)
+{
+    i2c_bus *bus = opaque;
+
+    bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
+}
+
+static int i2c_bus_post_load(void *opaque, int version_id)
+{
+    i2c_bus *bus = opaque;
+
+    /* The bus is loaded before attached devices, so load and save the
+       current device id.  Devices will check themselves as loaded.  */
+    bus->current_dev = NULL;
+    return 0;
+}
+
+static const VMStateDescription vmstate_i2c_bus = {
+    .name = "i2c_bus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = i2c_bus_pre_save,
+    .post_load = i2c_bus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(saved_address, i2c_bus),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Create a new I2C bus.  */
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
+{
+    i2c_bus *bus;
+
+    bus = FROM_QBUS(i2c_bus, qbus_create(&i2c_bus_info, parent, name));
+    vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
+    return bus;
+}
+
+void i2c_set_slave_address(i2c_slave *dev, uint8_t address)
+{
+    dev->address = address;
+}
+
+/* Return nonzero if bus is busy.  */
+int i2c_bus_busy(i2c_bus *bus)
+{
+    return bus->current_dev != NULL;
+}
+
+/* Returns non-zero if the address is not valid.  */
+/* TODO: Make this handle multiple masters.  */
+int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
+{
+    DeviceState *qdev;
+    i2c_slave *slave = NULL;
+
+    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+        i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
+        if (candidate->address == address) {
+            slave = candidate;
+            break;
+        }
+    }
+
+    if (!slave)
+        return 1;
+
+    /* If the bus is already busy, assume this is a repeated
+       start condition.  */
+    bus->current_dev = slave;
+    slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+    return 0;
+}
+
+void i2c_end_transfer(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return;
+
+    dev->info->event(dev, I2C_FINISH);
+
+    bus->current_dev = NULL;
+}
+
+int i2c_send(i2c_bus *bus, uint8_t data)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return -1;
+
+    return dev->info->send(dev, data);
+}
+
+int i2c_recv(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return -1;
+
+    return dev->info->recv(dev);
+}
+
+void i2c_nack(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return;
+
+    dev->info->event(dev, I2C_NACK);
+}
+
+static int i2c_slave_post_load(void *opaque, int version_id)
+{
+    i2c_slave *dev = opaque;
+    i2c_bus *bus;
+    bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
+    if (bus->saved_address == dev->address) {
+        bus->current_dev = dev;
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_i2c_slave = {
+    .name = "i2c_slave",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = i2c_slave_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(address, i2c_slave),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
+{
+    I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
+    i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
+
+    s->info = info;
+
+    return info->init(s);
+}
+
+void i2c_register_slave(I2CSlaveInfo *info)
+{
+    assert(info->qdev.size >= sizeof(i2c_slave));
+    info->qdev.init = i2c_slave_qdev_init;
+    info->qdev.bus_info = &i2c_bus_info;
+    qdev_register(&info->qdev);
+}
+
+DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->qbus, name);
+    qdev_prop_set_uint8(dev, "address", addr);
+    qdev_init_nofail(dev);
+    return dev;
+}
diff --git a/qemu-0.15.x/hw/i2c.h b/qemu-0.15.x/hw/i2c.h
new file mode 100644
index 0000000..5514402
--- /dev/null
+++ b/qemu-0.15.x/hw/i2c.h
@@ -0,0 +1,77 @@
+#ifndef QEMU_I2C_H
+#define QEMU_I2C_H
+
+#include "qdev.h"
+
+/* The QEMU I2C implementation only supports simple transfers that complete
+   immediately.  It does not support slave devices that need to be able to
+   defer their response (eg. CPU slave interfaces where the data is supplied
+   by the device driver in response to an interrupt).  */
+
+enum i2c_event {
+    I2C_START_RECV,
+    I2C_START_SEND,
+    I2C_FINISH,
+    I2C_NACK /* Masker NACKed a receive byte.  */
+};
+
+/* Master to slave.  */
+typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
+/* Slave to master.  */
+typedef int (*i2c_recv_cb)(i2c_slave *s);
+/* Notify the slave of a bus state change.  */
+typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+
+typedef int (*i2c_slave_initfn)(i2c_slave *dev);
+
+typedef struct {
+    DeviceInfo qdev;
+
+    /* Callbacks provided by the device.  */
+    i2c_slave_initfn init;
+    i2c_event_cb event;
+    i2c_recv_cb recv;
+    i2c_send_cb send;
+} I2CSlaveInfo;
+
+struct i2c_slave
+{
+    DeviceState qdev;
+    I2CSlaveInfo *info;
+
+    /* Remaining fields for internal use by the I2C code.  */
+    uint8_t address;
+};
+
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
+void i2c_set_slave_address(i2c_slave *dev, uint8_t address);
+int i2c_bus_busy(i2c_bus *bus);
+int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv);
+void i2c_end_transfer(i2c_bus *bus);
+void i2c_nack(i2c_bus *bus);
+int i2c_send(i2c_bus *bus, uint8_t data);
+int i2c_recv(i2c_bus *bus);
+
+#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(i2c_slave, qdev, dev)
+#define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
+
+void i2c_register_slave(I2CSlaveInfo *type);
+
+DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
+
+/* wm8750.c */
+void wm8750_data_req_set(DeviceState *dev,
+                void (*data_req)(void *, int, int), void *opaque);
+void wm8750_dac_dat(void *opaque, uint32_t sample);
+uint32_t wm8750_adc_dat(void *opaque);
+void *wm8750_dac_buffer(void *opaque, int samples);
+void wm8750_dac_commit(void *opaque);
+void wm8750_set_bclk_in(void *opaque, int new_hz);
+
+/* tmp105.c */
+void tmp105_set(i2c_slave *i2c, int temp);
+
+/* lm832x.c */
+void lm832x_key_event(i2c_slave *i2c, int key, int state);
+
+#endif
diff --git a/qemu-0.15.x/hw/i8254.c b/qemu-0.15.x/hw/i8254.c
new file mode 100644
index 0000000..a9ca9f6
--- /dev/null
+++ b/qemu-0.15.x/hw/i8254.c
@@ -0,0 +1,546 @@
+/*
+ * QEMU 8253/8254 interval timer 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 "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_PIT
+
+#define RW_STATE_LSB 1
+#define RW_STATE_MSB 2
+#define RW_STATE_WORD0 3
+#define RW_STATE_WORD1 4
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    uint16_t latched_count;
+    uint8_t count_latched;
+    uint8_t status_latched;
+    uint8_t status;
+    uint8_t read_state;
+    uint8_t write_state;
+    uint8_t write_latch;
+    uint8_t rw_mode;
+    uint8_t mode;
+    uint8_t bcd; /* not supported */
+    uint8_t gate; /* timer start */
+    int64_t count_load_time;
+    /* irq handling */
+    int64_t next_transition_time;
+    QEMUTimer *irq_timer;
+    qemu_irq irq;
+} PITChannelState;
+
+typedef struct PITState {
+    ISADevice dev;
+    uint32_t irq;
+    uint32_t iobase;
+    PITChannelState channels[3];
+} PITState;
+
+static PITState pit_state;
+
+static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
+
+static int pit_get_count(PITChannelState *s)
+{
+    uint64_t d;
+    int counter;
+
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch(s->mode) {
+    case 0:
+    case 1:
+    case 4:
+    case 5:
+        counter = (s->count - d) & 0xffff;
+        break;
+    case 3:
+        /* XXX: may be incorrect for odd counts */
+        counter = s->count - ((2 * d) % s->count);
+        break;
+    default:
+        counter = s->count - (d % s->count);
+        break;
+    }
+    return counter;
+}
+
+/* get pit output bit */
+static int pit_get_out1(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d;
+    int out;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch(s->mode) {
+    default:
+    case 0:
+        out = (d >= s->count);
+        break;
+    case 1:
+        out = (d < s->count);
+        break;
+    case 2:
+        if ((d % s->count) == 0 && d != 0)
+            out = 1;
+        else
+            out = 0;
+        break;
+    case 3:
+        out = (d % s->count) < ((s->count + 1) >> 1);
+        break;
+    case 4:
+    case 5:
+        out = (d == s->count);
+        break;
+    }
+    return out;
+}
+
+int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s = &pit->channels[channel];
+    return pit_get_out1(s, current_time);
+}
+
+/* return -1 if no transition will occur.  */
+static int64_t pit_get_next_transition_time(PITChannelState *s,
+                                            int64_t current_time)
+{
+    uint64_t d, next_time, base;
+    int period2;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch(s->mode) {
+    default:
+    case 0:
+    case 1:
+        if (d < s->count)
+            next_time = s->count;
+        else
+            return -1;
+        break;
+    case 2:
+        base = (d / s->count) * s->count;
+        if ((d - base) == 0 && d != 0)
+            next_time = base + s->count;
+        else
+            next_time = base + s->count + 1;
+        break;
+    case 3:
+        base = (d / s->count) * s->count;
+        period2 = ((s->count + 1) >> 1);
+        if ((d - base) < period2)
+            next_time = base + period2;
+        else
+            next_time = base + s->count;
+        break;
+    case 4:
+    case 5:
+        if (d < s->count)
+            next_time = s->count;
+        else if (d == s->count)
+            next_time = s->count + 1;
+        else
+            return -1;
+        break;
+    }
+    /* convert to timer units */
+    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
+                                              PIT_FREQ);
+    /* fix potential rounding problems */
+    /* XXX: better solution: use a clock at PIT_FREQ Hz */
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+/* val must be 0 or 1 */
+void pit_set_gate(ISADevice *dev, int channel, int val)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s = &pit->channels[channel];
+
+    switch(s->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 5:
+        if (s->gate < val) {
+            /* restart counting on rising edge */
+            s->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(s, s->count_load_time);
+        }
+        break;
+    case 2:
+    case 3:
+        if (s->gate < val) {
+            /* restart counting on rising edge */
+            s->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(s, s->count_load_time);
+        }
+        /* XXX: disable/enable counting */
+        break;
+    }
+    s->gate = val;
+}
+
+int pit_get_gate(ISADevice *dev, int channel)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s = &pit->channels[channel];
+    return s->gate;
+}
+
+int pit_get_initial_count(ISADevice *dev, int channel)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s = &pit->channels[channel];
+    return s->count;
+}
+
+int pit_get_mode(ISADevice *dev, int channel)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s = &pit->channels[channel];
+    return s->mode;
+}
+
+static inline void pit_load_count(PITChannelState *s, int val)
+{
+    if (val == 0)
+        val = 0x10000;
+    s->count_load_time = qemu_get_clock_ns(vm_clock);
+    s->count = val;
+    pit_irq_timer_update(s, s->count_load_time);
+}
+
+/* if already latched, do not latch again */
+static void pit_latch_count(PITChannelState *s)
+{
+    if (!s->count_latched) {
+        s->latched_count = pit_get_count(s);
+        s->count_latched = s->rw_mode;
+    }
+}
+
+static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PITState *pit = opaque;
+    int channel, access;
+    PITChannelState *s;
+
+    addr &= 3;
+    if (addr == 3) {
+        channel = val >> 6;
+        if (channel == 3) {
+            /* read back command */
+            for(channel = 0; channel < 3; channel++) {
+                s = &pit->channels[channel];
+                if (val & (2 << channel)) {
+                    if (!(val & 0x20)) {
+                        pit_latch_count(s);
+                    }
+                    if (!(val & 0x10) && !s->status_latched) {
+                        /* status latch */
+                        /* XXX: add BCD and null count */
+                        s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
+                            (s->rw_mode << 4) |
+                            (s->mode << 1) |
+                            s->bcd;
+                        s->status_latched = 1;
+                    }
+                }
+            }
+        } else {
+            s = &pit->channels[channel];
+            access = (val >> 4) & 3;
+            if (access == 0) {
+                pit_latch_count(s);
+            } else {
+                s->rw_mode = access;
+                s->read_state = access;
+                s->write_state = access;
+
+                s->mode = (val >> 1) & 7;
+                s->bcd = val & 1;
+                /* XXX: update irq timer ? */
+            }
+        }
+    } else {
+        s = &pit->channels[addr];
+        switch(s->write_state) {
+        default:
+        case RW_STATE_LSB:
+            pit_load_count(s, val);
+            break;
+        case RW_STATE_MSB:
+            pit_load_count(s, val << 8);
+            break;
+        case RW_STATE_WORD0:
+            s->write_latch = val;
+            s->write_state = RW_STATE_WORD1;
+            break;
+        case RW_STATE_WORD1:
+            pit_load_count(s, s->write_latch | (val << 8));
+            s->write_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+}
+
+static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
+{
+    PITState *pit = opaque;
+    int ret, count;
+    PITChannelState *s;
+
+    addr &= 3;
+    s = &pit->channels[addr];
+    if (s->status_latched) {
+        s->status_latched = 0;
+        ret = s->status;
+    } else if (s->count_latched) {
+        switch(s->count_latched) {
+        default:
+        case RW_STATE_LSB:
+            ret = s->latched_count & 0xff;
+            s->count_latched = 0;
+            break;
+        case RW_STATE_MSB:
+            ret = s->latched_count >> 8;
+            s->count_latched = 0;
+            break;
+        case RW_STATE_WORD0:
+            ret = s->latched_count & 0xff;
+            s->count_latched = RW_STATE_MSB;
+            break;
+        }
+    } else {
+        switch(s->read_state) {
+        default:
+        case RW_STATE_LSB:
+            count = pit_get_count(s);
+            ret = count & 0xff;
+            break;
+        case RW_STATE_MSB:
+            count = pit_get_count(s);
+            ret = (count >> 8) & 0xff;
+            break;
+        case RW_STATE_WORD0:
+            count = pit_get_count(s);
+            ret = count & 0xff;
+            s->read_state = RW_STATE_WORD1;
+            break;
+        case RW_STATE_WORD1:
+            count = pit_get_count(s);
+            ret = (count >> 8) & 0xff;
+            s->read_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+    return ret;
+}
+
+static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
+{
+    int64_t expire_time;
+    int irq_level;
+
+    if (!s->irq_timer)
+        return;
+    expire_time = pit_get_next_transition_time(s, current_time);
+    irq_level = pit_get_out1(s, current_time);
+    qemu_set_irq(s->irq, irq_level);
+#ifdef DEBUG_PIT
+    printf("irq_level=%d next_delay=%f\n",
+           irq_level,
+           (double)(expire_time - current_time) / get_ticks_per_sec());
+#endif
+    s->next_transition_time = expire_time;
+    if (expire_time != -1)
+        qemu_mod_timer(s->irq_timer, expire_time);
+    else
+        qemu_del_timer(s->irq_timer);
+}
+
+static void pit_irq_timer(void *opaque)
+{
+    PITChannelState *s = opaque;
+
+    pit_irq_timer_update(s, s->next_transition_time);
+}
+
+static const VMStateDescription vmstate_pit_channel = {
+    .name = "pit channel",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(count, PITChannelState),
+        VMSTATE_UINT16(latched_count, PITChannelState),
+        VMSTATE_UINT8(count_latched, PITChannelState),
+        VMSTATE_UINT8(status_latched, PITChannelState),
+        VMSTATE_UINT8(status, PITChannelState),
+        VMSTATE_UINT8(read_state, PITChannelState),
+        VMSTATE_UINT8(write_state, PITChannelState),
+        VMSTATE_UINT8(write_latch, PITChannelState),
+        VMSTATE_UINT8(rw_mode, PITChannelState),
+        VMSTATE_UINT8(mode, PITChannelState),
+        VMSTATE_UINT8(bcd, PITChannelState),
+        VMSTATE_UINT8(gate, PITChannelState),
+        VMSTATE_INT64(count_load_time, PITChannelState),
+        VMSTATE_INT64(next_transition_time, PITChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    PITState *pit = opaque;
+    PITChannelState *s;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    for(i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->count=qemu_get_be32(f);
+        qemu_get_be16s(f, &s->latched_count);
+        qemu_get_8s(f, &s->count_latched);
+        qemu_get_8s(f, &s->status_latched);
+        qemu_get_8s(f, &s->status);
+        qemu_get_8s(f, &s->read_state);
+        qemu_get_8s(f, &s->write_state);
+        qemu_get_8s(f, &s->write_latch);
+        qemu_get_8s(f, &s->rw_mode);
+        qemu_get_8s(f, &s->mode);
+        qemu_get_8s(f, &s->bcd);
+        qemu_get_8s(f, &s->gate);
+        s->count_load_time=qemu_get_be64(f);
+        if (s->irq_timer) {
+            s->next_transition_time=qemu_get_be64(f);
+            qemu_get_timer(f, s->irq_timer);
+        }
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit = {
+    .name = "i8254",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = pit_load_old,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
+        VMSTATE_TIMER(channels[0].irq_timer, PITState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pit_reset(DeviceState *dev)
+{
+    PITState *pit = container_of(dev, PITState, dev.qdev);
+    PITChannelState *s;
+    int i;
+
+    for(i = 0;i < 3; i++) {
+        s = &pit->channels[i];
+        s->mode = 3;
+        s->gate = (i != 2);
+        pit_load_count(s, 0);
+    }
+}
+
+/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
+void hpet_pit_disable(void) {
+    PITChannelState *s;
+    s = &pit_state.channels[0];
+    if (s->irq_timer)
+        qemu_del_timer(s->irq_timer);
+}
+
+/* When HPET is reset or leaving legacy mode, it must reenable i8254
+ * timer 0
+ */
+
+void hpet_pit_enable(void)
+{
+    PITState *pit = &pit_state;
+    PITChannelState *s;
+    s = &pit->channels[0];
+    s->mode = 3;
+    s->gate = 1;
+    pit_load_count(s, 0);
+}
+
+static int pit_initfn(ISADevice *dev)
+{
+    PITState *pit = DO_UPCAST(PITState, dev, dev);
+    PITChannelState *s;
+
+    s = &pit->channels[0];
+    /* the timer 0 is connected to an IRQ */
+    s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
+    s->irq = isa_get_irq(pit->irq);
+
+    register_ioport_write(pit->iobase, 4, 1, pit_ioport_write, pit);
+    register_ioport_read(pit->iobase, 3, 1, pit_ioport_read, pit);
+    isa_init_ioport(dev, pit->iobase);
+
+    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+
+    return 0;
+}
+
+static ISADeviceInfo pit_info = {
+    .qdev.name     = "isa-pit",
+    .qdev.size     = sizeof(PITState),
+    .qdev.vmsd     = &vmstate_pit,
+    .qdev.reset    = pit_reset,
+    .qdev.no_user  = 1,
+    .init          = pit_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
+        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pit_register(void)
+{
+    isa_qdev_register(&pit_info);
+}
+device_init(pit_register)
diff --git a/qemu-0.15.x/hw/i8259.c b/qemu-0.15.x/hw/i8259.c
new file mode 100644
index 0000000..84d330d
--- /dev/null
+++ b/qemu-0.15.x/hw/i8259.c
@@ -0,0 +1,539 @@
+/*
+ * QEMU 8259 interrupt controller 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 "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "monitor.h"
+#include "qemu-timer.h"
+
+/* debug PIC */
+//#define DEBUG_PIC
+
+#ifdef DEBUG_PIC
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+//#define DEBUG_IRQ_LATENCY
+//#define DEBUG_IRQ_COUNT
+
+typedef struct PicState {
+    uint8_t last_irr; /* edge detection */
+    uint8_t irr; /* interrupt request register */
+    uint8_t imr; /* interrupt mask register */
+    uint8_t isr; /* interrupt service register */
+    uint8_t priority_add; /* highest irq priority */
+    uint8_t irq_base;
+    uint8_t read_reg_select;
+    uint8_t poll;
+    uint8_t special_mask;
+    uint8_t init_state;
+    uint8_t auto_eoi;
+    uint8_t rotate_on_auto_eoi;
+    uint8_t special_fully_nested_mode;
+    uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
+    uint8_t elcr; /* PIIX edge/trigger selection*/
+    uint8_t elcr_mask;
+    PicState2 *pics_state;
+} PicState;
+
+struct PicState2 {
+    /* 0 is master pic, 1 is slave pic */
+    /* XXX: better separation between the two pics */
+    PicState pics[2];
+    qemu_irq parent_irq;
+    void *irq_request_opaque;
+};
+
+#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
+static int irq_level[16];
+#endif
+#ifdef DEBUG_IRQ_COUNT
+static uint64_t irq_count[16];
+#endif
+PicState2 *isa_pic;
+
+/* set irq level. If an edge is detected, then the IRR is set to 1 */
+static inline void pic_set_irq1(PicState *s, int irq, int level)
+{
+    int mask;
+    mask = 1 << irq;
+    if (s->elcr & mask) {
+        /* level triggered */
+        if (level) {
+            s->irr |= mask;
+            s->last_irr |= mask;
+        } else {
+            s->irr &= ~mask;
+            s->last_irr &= ~mask;
+        }
+    } else {
+        /* edge triggered */
+        if (level) {
+            if ((s->last_irr & mask) == 0)
+                s->irr |= mask;
+            s->last_irr |= mask;
+        } else {
+            s->last_irr &= ~mask;
+        }
+    }
+}
+
+/* return the highest priority found in mask (highest = smallest
+   number). Return 8 if no irq */
+static inline int get_priority(PicState *s, int mask)
+{
+    int priority;
+    if (mask == 0)
+        return 8;
+    priority = 0;
+    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+        priority++;
+    return priority;
+}
+
+/* return the pic wanted interrupt. return -1 if none */
+static int pic_get_irq(PicState *s)
+{
+    int mask, cur_priority, priority;
+
+    mask = s->irr & ~s->imr;
+    priority = get_priority(s, mask);
+    if (priority == 8)
+        return -1;
+    /* compute current priority. If special fully nested mode on the
+       master, the IRQ coming from the slave is not taken into account
+       for the priority computation. */
+    mask = s->isr;
+    if (s->special_mask)
+        mask &= ~s->imr;
+    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+        mask &= ~(1 << 2);
+    cur_priority = get_priority(s, mask);
+    if (priority < cur_priority) {
+        /* higher priority found: an irq should be generated */
+        return (priority + s->priority_add) & 7;
+    } else {
+        return -1;
+    }
+}
+
+/* raise irq to CPU if necessary. must be called every time the active
+   irq may change */
+/* XXX: should not export it, but it is needed for an APIC kludge */
+void pic_update_irq(PicState2 *s)
+{
+    int irq2, irq;
+
+    /* first look at slave pic */
+    irq2 = pic_get_irq(&s->pics[1]);
+    if (irq2 >= 0) {
+        /* if irq request by slave pic, signal master PIC */
+        pic_set_irq1(&s->pics[0], 2, 1);
+        pic_set_irq1(&s->pics[0], 2, 0);
+    }
+    /* look at requested irq */
+    irq = pic_get_irq(&s->pics[0]);
+    if (irq >= 0) {
+#if defined(DEBUG_PIC)
+        {
+            int i;
+            for(i = 0; i < 2; i++) {
+                printf("pic%d: imr=%x irr=%x padd=%d\n",
+                       i, s->pics[i].imr, s->pics[i].irr,
+                       s->pics[i].priority_add);
+
+            }
+        }
+        printf("pic: cpu_interrupt\n");
+#endif
+        qemu_irq_raise(s->parent_irq);
+    }
+
+/* all targets should do this rather than acking the IRQ in the cpu */
+#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
+    else {
+        qemu_irq_lower(s->parent_irq);
+    }
+#endif
+}
+
+#ifdef DEBUG_IRQ_LATENCY
+int64_t irq_time[16];
+#endif
+
+static void i8259_set_irq(void *opaque, int irq, int level)
+{
+    PicState2 *s = opaque;
+
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
+    if (level != irq_level[irq]) {
+        DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
+        irq_level[irq] = level;
+#ifdef DEBUG_IRQ_COUNT
+	if (level == 1)
+	    irq_count[irq]++;
+#endif
+    }
+#endif
+#ifdef DEBUG_IRQ_LATENCY
+    if (level) {
+        irq_time[irq] = qemu_get_clock_ns(vm_clock);
+    }
+#endif
+    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+    pic_update_irq(s);
+}
+
+/* acknowledge interrupt 'irq' */
+static inline void pic_intack(PicState *s, int irq)
+{
+    if (s->auto_eoi) {
+        if (s->rotate_on_auto_eoi)
+            s->priority_add = (irq + 1) & 7;
+    } else {
+        s->isr |= (1 << irq);
+    }
+    /* We don't clear a level sensitive interrupt here */
+    if (!(s->elcr & (1 << irq)))
+        s->irr &= ~(1 << irq);
+}
+
+int pic_read_irq(PicState2 *s)
+{
+    int irq, irq2, intno;
+
+    irq = pic_get_irq(&s->pics[0]);
+    if (irq >= 0) {
+        pic_intack(&s->pics[0], irq);
+        if (irq == 2) {
+            irq2 = pic_get_irq(&s->pics[1]);
+            if (irq2 >= 0) {
+                pic_intack(&s->pics[1], irq2);
+            } else {
+                /* spurious IRQ on slave controller */
+                irq2 = 7;
+            }
+            intno = s->pics[1].irq_base + irq2;
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
+            irq = irq2 + 8;
+#endif
+        } else {
+            intno = s->pics[0].irq_base + irq;
+        }
+    } else {
+        /* spurious IRQ on host controller */
+        irq = 7;
+        intno = s->pics[0].irq_base + irq;
+    }
+    pic_update_irq(s);
+
+#ifdef DEBUG_IRQ_LATENCY
+    printf("IRQ%d latency=%0.3fus\n",
+           irq,
+           (double)(qemu_get_clock_ns(vm_clock) -
+                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
+#endif
+    DPRINTF("pic_interrupt: irq=%d\n", irq);
+    return intno;
+}
+
+static void pic_reset(void *opaque)
+{
+    PicState *s = opaque;
+
+    s->last_irr = 0;
+    s->irr = 0;
+    s->imr = 0;
+    s->isr = 0;
+    s->priority_add = 0;
+    s->irq_base = 0;
+    s->read_reg_select = 0;
+    s->poll = 0;
+    s->special_mask = 0;
+    s->init_state = 0;
+    s->auto_eoi = 0;
+    s->rotate_on_auto_eoi = 0;
+    s->special_fully_nested_mode = 0;
+    s->init4 = 0;
+    s->single_mode = 0;
+    /* Note: ELCR is not reset */
+}
+
+static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PicState *s = opaque;
+    int priority, cmd, irq;
+
+    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
+    addr &= 1;
+    if (addr == 0) {
+        if (val & 0x10) {
+            /* init */
+            pic_reset(s);
+            /* deassert a pending interrupt */
+            qemu_irq_lower(s->pics_state->parent_irq);
+            s->init_state = 1;
+            s->init4 = val & 1;
+            s->single_mode = val & 2;
+            if (val & 0x08)
+                hw_error("level sensitive irq not supported");
+        } else if (val & 0x08) {
+            if (val & 0x04)
+                s->poll = 1;
+            if (val & 0x02)
+                s->read_reg_select = val & 1;
+            if (val & 0x40)
+                s->special_mask = (val >> 5) & 1;
+        } else {
+            cmd = val >> 5;
+            switch(cmd) {
+            case 0:
+            case 4:
+                s->rotate_on_auto_eoi = cmd >> 2;
+                break;
+            case 1: /* end of interrupt */
+            case 5:
+                priority = get_priority(s, s->isr);
+                if (priority != 8) {
+                    irq = (priority + s->priority_add) & 7;
+                    s->isr &= ~(1 << irq);
+                    if (cmd == 5)
+                        s->priority_add = (irq + 1) & 7;
+                    pic_update_irq(s->pics_state);
+                }
+                break;
+            case 3:
+                irq = val & 7;
+                s->isr &= ~(1 << irq);
+                pic_update_irq(s->pics_state);
+                break;
+            case 6:
+                s->priority_add = (val + 1) & 7;
+                pic_update_irq(s->pics_state);
+                break;
+            case 7:
+                irq = val & 7;
+                s->isr &= ~(1 << irq);
+                s->priority_add = (irq + 1) & 7;
+                pic_update_irq(s->pics_state);
+                break;
+            default:
+                /* no operation */
+                break;
+            }
+        }
+    } else {
+        switch(s->init_state) {
+        case 0:
+            /* normal mode */
+            s->imr = val;
+            pic_update_irq(s->pics_state);
+            break;
+        case 1:
+            s->irq_base = val & 0xf8;
+            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
+            break;
+        case 2:
+            if (s->init4) {
+                s->init_state = 3;
+            } else {
+                s->init_state = 0;
+            }
+            break;
+        case 3:
+            s->special_fully_nested_mode = (val >> 4) & 1;
+            s->auto_eoi = (val >> 1) & 1;
+            s->init_state = 0;
+            break;
+        }
+    }
+}
+
+static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
+{
+    int ret;
+
+    ret = pic_get_irq(s);
+    if (ret >= 0) {
+        if (addr1 >> 7) {
+            s->pics_state->pics[0].isr &= ~(1 << 2);
+            s->pics_state->pics[0].irr &= ~(1 << 2);
+        }
+        s->irr &= ~(1 << ret);
+        s->isr &= ~(1 << ret);
+        if (addr1 >> 7 || ret != 2)
+            pic_update_irq(s->pics_state);
+    } else {
+        ret = 0x07;
+        pic_update_irq(s->pics_state);
+    }
+
+    return ret;
+}
+
+static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
+{
+    PicState *s = opaque;
+    unsigned int addr;
+    int ret;
+
+    addr = addr1;
+    addr &= 1;
+    if (s->poll) {
+        ret = pic_poll_read(s, addr1);
+        s->poll = 0;
+    } else {
+        if (addr == 0) {
+            if (s->read_reg_select)
+                ret = s->isr;
+            else
+                ret = s->irr;
+        } else {
+            ret = s->imr;
+        }
+    }
+    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr1, ret);
+    return ret;
+}
+
+/* memory mapped interrupt status */
+/* XXX: may be the same than pic_read_irq() */
+uint32_t pic_intack_read(PicState2 *s)
+{
+    int ret;
+
+    ret = pic_poll_read(&s->pics[0], 0x00);
+    if (ret == 2)
+        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
+    /* Prepare for ISR read */
+    s->pics[0].read_reg_select = 1;
+
+    return ret;
+}
+
+static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PicState *s = opaque;
+    s->elcr = val & s->elcr_mask;
+}
+
+static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
+{
+    PicState *s = opaque;
+    return s->elcr;
+}
+
+static const VMStateDescription vmstate_pic = {
+    .name = "i8259",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(last_irr, PicState),
+        VMSTATE_UINT8(irr, PicState),
+        VMSTATE_UINT8(imr, PicState),
+        VMSTATE_UINT8(isr, PicState),
+        VMSTATE_UINT8(priority_add, PicState),
+        VMSTATE_UINT8(irq_base, PicState),
+        VMSTATE_UINT8(read_reg_select, PicState),
+        VMSTATE_UINT8(poll, PicState),
+        VMSTATE_UINT8(special_mask, PicState),
+        VMSTATE_UINT8(init_state, PicState),
+        VMSTATE_UINT8(auto_eoi, PicState),
+        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
+        VMSTATE_UINT8(special_fully_nested_mode, PicState),
+        VMSTATE_UINT8(init4, PicState),
+        VMSTATE_UINT8(single_mode, PicState),
+        VMSTATE_UINT8(elcr, PicState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* XXX: add generic master/slave system */
+static void pic_init1(int io_addr, int elcr_addr, PicState *s)
+{
+    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
+    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
+    if (elcr_addr >= 0) {
+        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
+        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
+    }
+    vmstate_register(NULL, io_addr, &vmstate_pic, s);
+    qemu_register_reset(pic_reset, s);
+}
+
+void pic_info(Monitor *mon)
+{
+    int i;
+    PicState *s;
+
+    if (!isa_pic)
+        return;
+
+    for(i=0;i<2;i++) {
+        s = &isa_pic->pics[i];
+        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
+                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
+                       i, s->irr, s->imr, s->isr, s->priority_add,
+                       s->irq_base, s->read_reg_select, s->elcr,
+                       s->special_fully_nested_mode);
+    }
+}
+
+void irq_info(Monitor *mon)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    int i;
+    int64_t count;
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 16; i++) {
+        count = irq_count[i];
+        if (count > 0)
+            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+    }
+#endif
+}
+
+qemu_irq *i8259_init(qemu_irq parent_irq)
+{
+    PicState2 *s;
+
+    s = qemu_mallocz(sizeof(PicState2));
+    pic_init1(0x20, 0x4d0, &s->pics[0]);
+    pic_init1(0xa0, 0x4d1, &s->pics[1]);
+    s->pics[0].elcr_mask = 0xf8;
+    s->pics[1].elcr_mask = 0xde;
+    s->parent_irq = parent_irq;
+    s->pics[0].pics_state = s;
+    s->pics[1].pics_state = s;
+    isa_pic = s;
+    return qemu_allocate_irqs(i8259_set_irq, s, 16);
+}
diff --git a/qemu-0.15.x/hw/ide.h b/qemu-0.15.x/hw/ide.h
new file mode 100644
index 0000000..34d9394
--- /dev/null
+++ b/qemu-0.15.x/hw/ide.h
@@ -0,0 +1,34 @@
+#ifndef HW_IDE_H
+#define HW_IDE_H
+
+#include "isa.h"
+#include "pci.h"
+
+#define MAX_IDE_DEVS	2
+
+/* ide-isa.c */
+ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
+                        DriveInfo *hd0, DriveInfo *hd1);
+
+/* ide-pci.c */
+void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
+                         int secondary_ide_enabled);
+PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+
+/* ide-macio.c */
+int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
+		   void *dbdma, int channel, qemu_irq dma_irq);
+
+/* ide-mmio.c */
+void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
+                    qemu_irq irq, int shift,
+                    DriveInfo *hd0, DriveInfo *hd1);
+
+void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
+
+/* ide/core.c */
+void ide_drive_get(DriveInfo **hd, int max_bus);
+
+#endif /* HW_IDE_H */
diff --git a/qemu-0.15.x/hw/ide/ahci.c b/qemu-0.15.x/hw/ide/ahci.c
new file mode 100644
index 0000000..1f008a3
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/ahci.c
@@ -0,0 +1,1168 @@
+/*
+ * QEMU AHCI Emulation
+ *
+ * Copyright (c) 2010 qiaochong at loongson.cn
+ * Copyright (c) 2010 Roland Elek <elek.roland at gmail.com>
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt at gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <hw/hw.h>
+#include <hw/msi.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+
+#include "monitor.h"
+#include "dma.h"
+#include "cpu-common.h"
+#include "internal.h"
+#include <hw/ide/pci.h>
+#include <hw/ide/ahci.h>
+
+/* #define DEBUG_AHCI */
+
+#ifdef DEBUG_AHCI
+#define DPRINTF(port, fmt, ...) \
+do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
+     fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(port, fmt, ...) do {} while(0)
+#endif
+
+static void check_cmd(AHCIState *s, int port);
+static int handle_cmd(AHCIState *s,int port,int slot);
+static void ahci_reset_port(AHCIState *s, int port);
+static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
+static void ahci_init_d2h(AHCIDevice *ad);
+
+static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
+{
+    uint32_t val;
+    AHCIPortRegs *pr;
+    pr = &s->dev[port].port_regs;
+
+    switch (offset) {
+    case PORT_LST_ADDR:
+        val = pr->lst_addr;
+        break;
+    case PORT_LST_ADDR_HI:
+        val = pr->lst_addr_hi;
+        break;
+    case PORT_FIS_ADDR:
+        val = pr->fis_addr;
+        break;
+    case PORT_FIS_ADDR_HI:
+        val = pr->fis_addr_hi;
+        break;
+    case PORT_IRQ_STAT:
+        val = pr->irq_stat;
+        break;
+    case PORT_IRQ_MASK:
+        val = pr->irq_mask;
+        break;
+    case PORT_CMD:
+        val = pr->cmd;
+        break;
+    case PORT_TFDATA:
+        val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) |
+              s->dev[port].port.ifs[0].status;
+        break;
+    case PORT_SIG:
+        val = pr->sig;
+        break;
+    case PORT_SCR_STAT:
+        if (s->dev[port].port.ifs[0].bs) {
+            val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
+                  SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
+        } else {
+            val = SATA_SCR_SSTATUS_DET_NODEV;
+        }
+        break;
+    case PORT_SCR_CTL:
+        val = pr->scr_ctl;
+        break;
+    case PORT_SCR_ERR:
+        val = pr->scr_err;
+        break;
+    case PORT_SCR_ACT:
+        pr->scr_act &= ~s->dev[port].finished;
+        s->dev[port].finished = 0;
+        val = pr->scr_act;
+        break;
+    case PORT_CMD_ISSUE:
+        val = pr->cmd_issue;
+        break;
+    case PORT_RESERVED:
+    default:
+        val = 0;
+    }
+    DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
+    return val;
+
+}
+
+static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
+{
+    struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+
+    DPRINTF(0, "raise irq\n");
+
+    if (msi_enabled(&d->card)) {
+        msi_notify(&d->card, 0);
+    } else {
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
+{
+    struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+
+    DPRINTF(0, "lower irq\n");
+
+    if (!msi_enabled(&d->card)) {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void ahci_check_irq(AHCIState *s)
+{
+    int i;
+
+    DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
+
+    for (i = 0; i < s->ports; i++) {
+        AHCIPortRegs *pr = &s->dev[i].port_regs;
+        if (pr->irq_stat & pr->irq_mask) {
+            s->control_regs.irqstatus |= (1 << i);
+        }
+    }
+
+    if (s->control_regs.irqstatus &&
+        (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
+            ahci_irq_raise(s, NULL);
+    } else {
+        ahci_irq_lower(s, NULL);
+    }
+}
+
+static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
+                             int irq_type)
+{
+    DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
+            irq_type, d->port_regs.irq_mask & irq_type);
+
+    d->port_regs.irq_stat |= irq_type;
+    ahci_check_irq(s);
+}
+
+static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
+{
+    target_phys_addr_t len = wanted;
+
+    if (*ptr) {
+        cpu_physical_memory_unmap(*ptr, len, 1, len);
+    }
+
+    *ptr = cpu_physical_memory_map(addr, &len, 1);
+    if (len < wanted) {
+        cpu_physical_memory_unmap(*ptr, len, 1, len);
+        *ptr = NULL;
+    }
+}
+
+static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+
+    DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
+    switch (offset) {
+        case PORT_LST_ADDR:
+            pr->lst_addr = val;
+            map_page(&s->dev[port].lst,
+                     ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
+            s->dev[port].cur_cmd = NULL;
+            break;
+        case PORT_LST_ADDR_HI:
+            pr->lst_addr_hi = val;
+            map_page(&s->dev[port].lst,
+                     ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
+            s->dev[port].cur_cmd = NULL;
+            break;
+        case PORT_FIS_ADDR:
+            pr->fis_addr = val;
+            map_page(&s->dev[port].res_fis,
+                     ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+            break;
+        case PORT_FIS_ADDR_HI:
+            pr->fis_addr_hi = val;
+            map_page(&s->dev[port].res_fis,
+                     ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+            break;
+        case PORT_IRQ_STAT:
+            pr->irq_stat &= ~val;
+            break;
+        case PORT_IRQ_MASK:
+            pr->irq_mask = val & 0xfdc000ff;
+            ahci_check_irq(s);
+            break;
+        case PORT_CMD:
+            pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
+
+            if (pr->cmd & PORT_CMD_START) {
+                pr->cmd |= PORT_CMD_LIST_ON;
+            }
+
+            if (pr->cmd & PORT_CMD_FIS_RX) {
+                pr->cmd |= PORT_CMD_FIS_ON;
+            }
+
+            /* XXX usually the FIS would be pending on the bus here and
+                   issuing deferred until the OS enables FIS receival.
+                   Instead, we only submit it once - which works in most
+                   cases, but is a hack. */
+            if ((pr->cmd & PORT_CMD_FIS_ON) &&
+                !s->dev[port].init_d2h_sent) {
+                ahci_init_d2h(&s->dev[port]);
+                s->dev[port].init_d2h_sent = 1;
+            }
+
+            check_cmd(s, port);
+            break;
+        case PORT_TFDATA:
+            s->dev[port].port.ifs[0].error = (val >> 8) & 0xff;
+            s->dev[port].port.ifs[0].status = val & 0xff;
+            break;
+        case PORT_SIG:
+            pr->sig = val;
+            break;
+        case PORT_SCR_STAT:
+            pr->scr_stat = val;
+            break;
+        case PORT_SCR_CTL:
+            if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
+                ((val & AHCI_SCR_SCTL_DET) == 0)) {
+                ahci_reset_port(s, port);
+            }
+            pr->scr_ctl = val;
+            break;
+        case PORT_SCR_ERR:
+            pr->scr_err &= ~val;
+            break;
+        case PORT_SCR_ACT:
+            /* RW1 */
+            pr->scr_act |= val;
+            break;
+        case PORT_CMD_ISSUE:
+            pr->cmd_issue |= val;
+            check_cmd(s, port);
+            break;
+        default:
+            break;
+    }
+}
+
+static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
+{
+    AHCIState *s = ptr;
+    uint32_t val = 0;
+
+    addr = addr & 0xfff;
+    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
+        switch (addr) {
+        case HOST_CAP:
+            val = s->control_regs.cap;
+            break;
+        case HOST_CTL:
+            val = s->control_regs.ghc;
+            break;
+        case HOST_IRQ_STAT:
+            val = s->control_regs.irqstatus;
+            break;
+        case HOST_PORTS_IMPL:
+            val = s->control_regs.impl;
+            break;
+        case HOST_VERSION:
+            val = s->control_regs.version;
+            break;
+        }
+
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
+               (addr < (AHCI_PORT_REGS_START_ADDR +
+                (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
+        val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
+                             addr & AHCI_PORT_ADDR_OFFSET_MASK);
+    }
+
+    return val;
+}
+
+
+
+static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    AHCIState *s = ptr;
+    addr = addr & 0xfff;
+
+    /* Only aligned reads are allowed on AHCI */
+    if (addr & 3) {
+        fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
+                TARGET_FMT_plx "\n", addr);
+        return;
+    }
+
+    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+
+        switch (addr) {
+            case HOST_CAP: /* R/WO, RO */
+                /* FIXME handle R/WO */
+                break;
+            case HOST_CTL: /* R/W */
+                if (val & HOST_CTL_RESET) {
+                    DPRINTF(-1, "HBA Reset\n");
+                    ahci_reset(container_of(s, AHCIPCIState, ahci));
+                } else {
+                    s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
+                    ahci_check_irq(s);
+                }
+                break;
+            case HOST_IRQ_STAT: /* R/WC, RO */
+                s->control_regs.irqstatus &= ~val;
+                ahci_check_irq(s);
+                break;
+            case HOST_PORTS_IMPL: /* R/WO, RO */
+                /* FIXME handle R/WO */
+                break;
+            case HOST_VERSION: /* RO */
+                /* FIXME report write? */
+                break;
+            default:
+                DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
+        }
+    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
+               (addr < (AHCI_PORT_REGS_START_ADDR +
+                (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
+        ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
+                        addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
+    }
+
+}
+
+static CPUReadMemoryFunc * const ahci_readfn[3]={
+    ahci_mem_readl,
+    ahci_mem_readl,
+    ahci_mem_readl
+};
+
+static CPUWriteMemoryFunc * const ahci_writefn[3]={
+    ahci_mem_writel,
+    ahci_mem_writel,
+    ahci_mem_writel
+};
+
+static void ahci_reg_init(AHCIState *s)
+{
+    int i;
+
+    s->control_regs.cap = (s->ports - 1) |
+                          (AHCI_NUM_COMMAND_SLOTS << 8) |
+                          (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
+                          HOST_CAP_NCQ | HOST_CAP_AHCI;
+
+    s->control_regs.impl = (1 << s->ports) - 1;
+
+    s->control_regs.version = AHCI_VERSION_1_0;
+
+    for (i = 0; i < s->ports; i++) {
+        s->dev[i].port_state = STATE_RUN;
+    }
+}
+
+static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
+                                 QEMUSGList *sglist)
+{
+    uint32_t i = 0;
+    uint32_t total = 0, once;
+    ScatterGatherEntry *cur_prd;
+    uint32_t sgcount;
+
+    cur_prd = sglist->sg;
+    sgcount = sglist->nsg;
+    for (i = 0; len && sgcount; i++) {
+        once = MIN(cur_prd->len, len);
+        cpu_physical_memory_read(cur_prd->base, buffer, once);
+        cur_prd++;
+        sgcount--;
+        len -= once;
+        buffer += once;
+        total += once;
+    }
+
+    return total;
+}
+
+static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
+                                QEMUSGList *sglist)
+{
+    uint32_t i = 0;
+    uint32_t total = 0, once;
+    ScatterGatherEntry *cur_prd;
+    uint32_t sgcount;
+
+    DPRINTF(-1, "total: 0x%x bytes\n", len);
+
+    cur_prd = sglist->sg;
+    sgcount = sglist->nsg;
+    for (i = 0; len && sgcount; i++) {
+        once = MIN(cur_prd->len, len);
+        DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base);
+        cpu_physical_memory_write(cur_prd->base, buffer, once);
+        cur_prd++;
+        sgcount--;
+        len -= once;
+        buffer += once;
+        total += once;
+    }
+
+    return total;
+}
+
+static void check_cmd(AHCIState *s, int port)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+    int slot;
+
+    if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
+        for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
+            if ((pr->cmd_issue & (1 << slot)) &&
+                !handle_cmd(s, port, slot)) {
+                pr->cmd_issue &= ~(1 << slot);
+            }
+        }
+    }
+}
+
+static void ahci_check_cmd_bh(void *opaque)
+{
+    AHCIDevice *ad = opaque;
+
+    qemu_bh_delete(ad->check_bh);
+    ad->check_bh = NULL;
+
+    if ((ad->busy_slot != -1) &&
+        !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
+        /* no longer busy */
+        ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
+        ad->busy_slot = -1;
+    }
+
+    check_cmd(ad->hba, ad->port_no);
+}
+
+static void ahci_init_d2h(AHCIDevice *ad)
+{
+    uint8_t init_fis[0x20];
+    IDEState *ide_state = &ad->port.ifs[0];
+
+    memset(init_fis, 0, sizeof(init_fis));
+
+    init_fis[4] = 1;
+    init_fis[12] = 1;
+
+    if (ide_state->drive_kind == IDE_CD) {
+        init_fis[5] = ide_state->lcyl;
+        init_fis[6] = ide_state->hcyl;
+    }
+
+    ahci_write_fis_d2h(ad, init_fis);
+}
+
+static void ahci_reset_port(AHCIState *s, int port)
+{
+    AHCIDevice *d = &s->dev[port];
+    AHCIPortRegs *pr = &d->port_regs;
+    IDEState *ide_state = &d->port.ifs[0];
+    int i;
+
+    DPRINTF(port, "reset port\n");
+
+    ide_bus_reset(&d->port);
+    ide_state->ncq_queues = AHCI_MAX_CMDS;
+
+    pr->irq_stat = 0;
+    pr->irq_mask = 0;
+    pr->scr_stat = 0;
+    pr->scr_ctl = 0;
+    pr->scr_err = 0;
+    pr->scr_act = 0;
+    d->busy_slot = -1;
+    d->init_d2h_sent = 0;
+
+    ide_state = &s->dev[port].port.ifs[0];
+    if (!ide_state->bs) {
+        return;
+    }
+
+    /* reset ncq queue */
+    for (i = 0; i < AHCI_MAX_CMDS; i++) {
+        NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
+        if (!ncq_tfs->used) {
+            continue;
+        }
+
+        if (ncq_tfs->aiocb) {
+            bdrv_aio_cancel(ncq_tfs->aiocb);
+            ncq_tfs->aiocb = NULL;
+        }
+
+        qemu_sglist_destroy(&ncq_tfs->sglist);
+        ncq_tfs->used = 0;
+    }
+
+    s->dev[port].port_state = STATE_RUN;
+    if (!ide_state->bs) {
+        s->dev[port].port_regs.sig = 0;
+        ide_state->status = SEEK_STAT | WRERR_STAT;
+    } else if (ide_state->drive_kind == IDE_CD) {
+        s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM;
+        ide_state->lcyl = 0x14;
+        ide_state->hcyl = 0xeb;
+        DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
+        ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
+    } else {
+        s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
+        ide_state->status = SEEK_STAT | WRERR_STAT;
+    }
+
+    ide_state->error = 1;
+    ahci_init_d2h(d);
+}
+
+static void debug_print_fis(uint8_t *fis, int cmd_len)
+{
+#ifdef DEBUG_AHCI
+    int i;
+
+    fprintf(stderr, "fis:");
+    for (i = 0; i < cmd_len; i++) {
+        if ((i & 0xf) == 0) {
+            fprintf(stderr, "\n%02x:",i);
+        }
+        fprintf(stderr, "%02x ",fis[i]);
+    }
+    fprintf(stderr, "\n");
+#endif
+}
+
+static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+    IDEState *ide_state;
+    uint8_t *sdb_fis;
+
+    if (!s->dev[port].res_fis ||
+        !(pr->cmd & PORT_CMD_FIS_RX)) {
+        return;
+    }
+
+    sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS];
+    ide_state = &s->dev[port].port.ifs[0];
+
+    /* clear memory */
+    *(uint32_t*)sdb_fis = 0;
+
+    /* write values */
+    sdb_fis[0] = ide_state->error;
+    sdb_fis[2] = ide_state->status & 0x77;
+    s->dev[port].finished |= finished;
+    *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
+
+    ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
+}
+
+static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
+{
+    AHCIPortRegs *pr = &ad->port_regs;
+    uint8_t *d2h_fis;
+    int i;
+    target_phys_addr_t cmd_len = 0x80;
+    int cmd_mapped = 0;
+
+    if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
+        return;
+    }
+
+    if (!cmd_fis) {
+        /* map cmd_fis */
+        uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
+        cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 0);
+        cmd_mapped = 1;
+    }
+
+    d2h_fis = &ad->res_fis[RES_FIS_RFIS];
+
+    d2h_fis[0] = 0x34;
+    d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
+    d2h_fis[2] = ad->port.ifs[0].status;
+    d2h_fis[3] = ad->port.ifs[0].error;
+
+    d2h_fis[4] = cmd_fis[4];
+    d2h_fis[5] = cmd_fis[5];
+    d2h_fis[6] = cmd_fis[6];
+    d2h_fis[7] = cmd_fis[7];
+    d2h_fis[8] = cmd_fis[8];
+    d2h_fis[9] = cmd_fis[9];
+    d2h_fis[10] = cmd_fis[10];
+    d2h_fis[11] = cmd_fis[11];
+    d2h_fis[12] = cmd_fis[12];
+    d2h_fis[13] = cmd_fis[13];
+    for (i = 14; i < 0x20; i++) {
+        d2h_fis[i] = 0;
+    }
+
+    if (d2h_fis[2] & ERR_STAT) {
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
+    }
+
+    ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
+
+    if (cmd_mapped) {
+        cpu_physical_memory_unmap(cmd_fis, cmd_len, 0, cmd_len);
+    }
+}
+
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+{
+    AHCICmdHdr *cmd = ad->cur_cmd;
+    uint32_t opts = le32_to_cpu(cmd->opts);
+    uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
+    int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
+    target_phys_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
+    target_phys_addr_t real_prdt_len = prdt_len;
+    uint8_t *prdt;
+    int i;
+    int r = 0;
+
+    if (!sglist_alloc_hint) {
+        DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
+        return -1;
+    }
+
+    /* map PRDT */
+    if (!(prdt = cpu_physical_memory_map(prdt_addr, &prdt_len, 0))){
+        DPRINTF(ad->port_no, "map failed\n");
+        return -1;
+    }
+
+    if (prdt_len < real_prdt_len) {
+        DPRINTF(ad->port_no, "mapped less than expected\n");
+        r = -1;
+        goto out;
+    }
+
+    /* Get entries in the PRDT, init a qemu sglist accordingly */
+    if (sglist_alloc_hint > 0) {
+        AHCI_SG *tbl = (AHCI_SG *)prdt;
+
+        qemu_sglist_init(sglist, sglist_alloc_hint);
+        for (i = 0; i < sglist_alloc_hint; i++) {
+            /* flags_size is zero-based */
+            qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
+                            le32_to_cpu(tbl[i].flags_size) + 1);
+        }
+    }
+
+out:
+    cpu_physical_memory_unmap(prdt, prdt_len, 0, prdt_len);
+    return r;
+}
+
+static void ncq_cb(void *opaque, int ret)
+{
+    NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
+    IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
+
+    /* Clear bit for this tag in SActive */
+    ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
+
+    if (ret < 0) {
+        /* error */
+        ide_state->error = ABRT_ERR;
+        ide_state->status = READY_STAT | ERR_STAT;
+        ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
+    } else {
+        ide_state->status = READY_STAT | SEEK_STAT;
+    }
+
+    ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
+                       (1 << ncq_tfs->tag));
+
+    DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
+            ncq_tfs->tag);
+
+    qemu_sglist_destroy(&ncq_tfs->sglist);
+    ncq_tfs->used = 0;
+}
+
+static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
+                                int slot)
+{
+    NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
+    uint8_t tag = ncq_fis->tag >> 3;
+    NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag];
+
+    if (ncq_tfs->used) {
+        /* error - already in use */
+        fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
+        return;
+    }
+
+    ncq_tfs->used = 1;
+    ncq_tfs->drive = &s->dev[port];
+    ncq_tfs->slot = slot;
+    ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
+                   ((uint64_t)ncq_fis->lba4 << 32) |
+                   ((uint64_t)ncq_fis->lba3 << 24) |
+                   ((uint64_t)ncq_fis->lba2 << 16) |
+                   ((uint64_t)ncq_fis->lba1 << 8) |
+                   (uint64_t)ncq_fis->lba0;
+
+    /* Note: We calculate the sector count, but don't currently rely on it.
+     * The total size of the DMA buffer tells us the transfer size instead. */
+    ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
+                                ncq_fis->sector_count_low;
+
+    DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
+            ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
+            s->dev[port].port.ifs[0].nb_sectors - 1);
+
+    ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+    ncq_tfs->tag = tag;
+
+    switch(ncq_fis->command) {
+        case READ_FPDMA_QUEUED:
+            DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
+                    ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
+            ncq_tfs->is_read = 1;
+
+            DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
+                                           &ncq_tfs->sglist, ncq_tfs->lba,
+                                           ncq_cb, ncq_tfs);
+            break;
+        case WRITE_FPDMA_QUEUED:
+            DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
+                    ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
+            ncq_tfs->is_read = 0;
+
+            DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
+                                            &ncq_tfs->sglist, ncq_tfs->lba,
+                                            ncq_cb, ncq_tfs);
+            break;
+        default:
+            DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
+            qemu_sglist_destroy(&ncq_tfs->sglist);
+            break;
+    }
+}
+
+static int handle_cmd(AHCIState *s, int port, int slot)
+{
+    IDEState *ide_state;
+    uint32_t opts;
+    uint64_t tbl_addr;
+    AHCICmdHdr *cmd;
+    uint8_t *cmd_fis;
+    target_phys_addr_t cmd_len;
+
+    if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
+        /* Engine currently busy, try again later */
+        DPRINTF(port, "engine busy\n");
+        return -1;
+    }
+
+    cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
+
+    if (!s->dev[port].lst) {
+        DPRINTF(port, "error: lst not given but cmd handled");
+        return -1;
+    }
+
+    /* remember current slot handle for later */
+    s->dev[port].cur_cmd = cmd;
+
+    opts = le32_to_cpu(cmd->opts);
+    tbl_addr = le64_to_cpu(cmd->tbl_addr);
+
+    cmd_len = 0x80;
+    cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 1);
+
+    if (!cmd_fis) {
+        DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
+        return -1;
+    }
+
+    /* The device we are working for */
+    ide_state = &s->dev[port].port.ifs[0];
+
+    if (!ide_state->bs) {
+        DPRINTF(port, "error: guest accessed unused port");
+        goto out;
+    }
+
+    debug_print_fis(cmd_fis, 0x90);
+    //debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
+
+    switch (cmd_fis[0]) {
+        case SATA_FIS_TYPE_REGISTER_H2D:
+            break;
+        default:
+            DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
+                          "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
+                          cmd_fis[2]);
+            goto out;
+            break;
+    }
+
+    switch (cmd_fis[1]) {
+        case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
+            break;
+        case 0:
+            break;
+        default:
+            DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
+                          "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
+                          cmd_fis[2]);
+            goto out;
+            break;
+    }
+
+    switch (s->dev[port].port_state) {
+        case STATE_RUN:
+            if (cmd_fis[15] & ATA_SRST) {
+                s->dev[port].port_state = STATE_RESET;
+            }
+            break;
+        case STATE_RESET:
+            if (!(cmd_fis[15] & ATA_SRST)) {
+                ahci_reset_port(s, port);
+            }
+            break;
+    }
+
+    if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) {
+
+        /* Check for NCQ command */
+        if ((cmd_fis[2] == READ_FPDMA_QUEUED) ||
+            (cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
+            process_ncq_command(s, port, cmd_fis, slot);
+            goto out;
+        }
+
+        /* Decompose the FIS  */
+        ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
+        ide_state->feature = cmd_fis[3];
+        if (!ide_state->nsector) {
+            ide_state->nsector = 256;
+        }
+
+        if (ide_state->drive_kind != IDE_CD) {
+            /*
+             * We set the sector depending on the sector defined in the FIS.
+             * Unfortunately, the spec isn't exactly obvious on this one.
+             *
+             * Apparently LBA48 commands set fis bytes 10,9,8,6,5,4 to the
+             * 48 bit sector number. ATA_CMD_READ_DMA_EXT is an example for
+             * such a command.
+             *
+             * Non-LBA48 commands however use 7[lower 4 bits],6,5,4 to define a
+             * 28-bit sector number. ATA_CMD_READ_DMA is an example for such
+             * a command.
+             *
+             * Since the spec doesn't explicitly state what each field should
+             * do, I simply assume non-used fields as reserved and OR everything
+             * together, independent of the command.
+             */
+            ide_set_sector(ide_state, ((uint64_t)cmd_fis[10] << 40)
+                                    | ((uint64_t)cmd_fis[9] << 32)
+                                    /* This is used for LBA48 commands */
+                                    | ((uint64_t)cmd_fis[8] << 24)
+                                    /* This is used for non-LBA48 commands */
+                                    | ((uint64_t)(cmd_fis[7] & 0xf) << 24)
+                                    | ((uint64_t)cmd_fis[6] << 16)
+                                    | ((uint64_t)cmd_fis[5] << 8)
+                                    | cmd_fis[4]);
+        }
+
+        /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
+         * table to ide_state->io_buffer
+         */
+        if (opts & AHCI_CMD_ATAPI) {
+            memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
+            ide_state->lcyl = 0x14;
+            ide_state->hcyl = 0xeb;
+            debug_print_fis(ide_state->io_buffer, 0x10);
+            ide_state->feature = IDE_FEATURE_DMA;
+            s->dev[port].done_atapi_packet = 0;
+            /* XXX send PIO setup FIS */
+        }
+
+        ide_state->error = 0;
+
+        /* Reset transferred byte counter */
+        cmd->status = 0;
+
+        /* We're ready to process the command in FIS byte 2. */
+        ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
+
+        if (s->dev[port].port.ifs[0].status & READY_STAT) {
+            ahci_write_fis_d2h(&s->dev[port], cmd_fis);
+        }
+    }
+
+out:
+    cpu_physical_memory_unmap(cmd_fis, cmd_len, 1, cmd_len);
+
+    if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
+        /* async command, complete later */
+        s->dev[port].busy_slot = slot;
+        return -1;
+    }
+
+    /* done handling the command */
+    return 0;
+}
+
+/* DMA dev <-> ram */
+static int ahci_start_transfer(IDEDMA *dma)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
+    /* write == ram -> device */
+    uint32_t opts = le32_to_cpu(ad->cur_cmd->opts);
+    int is_write = opts & AHCI_CMD_WRITE;
+    int is_atapi = opts & AHCI_CMD_ATAPI;
+    int has_sglist = 0;
+
+    if (is_atapi && !ad->done_atapi_packet) {
+        /* already prepopulated iobuffer */
+        ad->done_atapi_packet = 1;
+        goto out;
+    }
+
+    if (!ahci_populate_sglist(ad, &s->sg)) {
+        has_sglist = 1;
+    }
+
+    DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
+            is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
+            has_sglist ? "" : "o");
+
+    if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
+        read_from_sglist(s->data_ptr, size, &s->sg);
+    }
+
+    if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
+        write_to_sglist(s->data_ptr, size, &s->sg);
+    }
+
+    /* update number of transferred bytes */
+    ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size);
+
+out:
+    /* declare that we processed everything */
+    s->data_ptr = s->data_end;
+
+    if (has_sglist) {
+        qemu_sglist_destroy(&s->sg);
+    }
+
+    s->end_transfer_func(s);
+
+    if (!(s->status & DRQ_STAT)) {
+        /* done with DMA */
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+    }
+
+    return 0;
+}
+
+static void ahci_start_dma(IDEDMA *dma, IDEState *s,
+                           BlockDriverCompletionFunc *dma_cb)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+
+    DPRINTF(ad->port_no, "\n");
+    ad->dma_cb = dma_cb;
+    ad->dma_status |= BM_STATUS_DMAING;
+    dma_cb(s, 0);
+}
+
+static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    int i;
+
+    ahci_populate_sglist(ad, &s->sg);
+
+    s->io_buffer_size = 0;
+    for (i = 0; i < s->sg.nsg; i++) {
+        s->io_buffer_size += s->sg.sg[i].len;
+    }
+
+    DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
+    return s->io_buffer_size != 0;
+}
+
+static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    uint8_t *p = s->io_buffer + s->io_buffer_index;
+    int l = s->io_buffer_size - s->io_buffer_index;
+
+    if (ahci_populate_sglist(ad, &s->sg)) {
+        return 0;
+    }
+
+    if (is_write) {
+        write_to_sglist(p, l, &s->sg);
+    } else {
+        read_from_sglist(p, l, &s->sg);
+    }
+
+    /* update number of transferred bytes */
+    ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
+    s->io_buffer_index += l;
+
+    DPRINTF(ad->port_no, "len=%#x\n", l);
+
+    return 1;
+}
+
+static int ahci_dma_set_unit(IDEDMA *dma, int unit)
+{
+    /* only a single unit per link */
+    return 0;
+}
+
+static int ahci_dma_add_status(IDEDMA *dma, int status)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    ad->dma_status |= status;
+    DPRINTF(ad->port_no, "set status: %x\n", status);
+
+    if (status & BM_STATUS_INT) {
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+    }
+
+    return 0;
+}
+
+static int ahci_dma_set_inactive(IDEDMA *dma)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+
+    DPRINTF(ad->port_no, "dma done\n");
+
+    /* update d2h status */
+    ahci_write_fis_d2h(ad, NULL);
+
+    ad->dma_cb = NULL;
+
+    if (!ad->check_bh) {
+        /* maybe we still have something to process, check later */
+        ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
+        qemu_bh_schedule(ad->check_bh);
+    }
+
+    return 0;
+}
+
+static void ahci_irq_set(void *opaque, int n, int level)
+{
+}
+
+static void ahci_dma_restart_cb(void *opaque, int running, int reason)
+{
+}
+
+static int ahci_dma_reset(IDEDMA *dma)
+{
+    return 0;
+}
+
+static const IDEDMAOps ahci_dma_ops = {
+    .start_dma = ahci_start_dma,
+    .start_transfer = ahci_start_transfer,
+    .prepare_buf = ahci_dma_prepare_buf,
+    .rw_buf = ahci_dma_rw_buf,
+    .set_unit = ahci_dma_set_unit,
+    .add_status = ahci_dma_add_status,
+    .set_inactive = ahci_dma_set_inactive,
+    .restart_cb = ahci_dma_restart_cb,
+    .reset = ahci_dma_reset,
+};
+
+void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
+{
+    qemu_irq *irqs;
+    int i;
+
+    s->ports = ports;
+    s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports);
+    ahci_reg_init(s);
+    s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
+
+    for (i = 0; i < s->ports; i++) {
+        AHCIDevice *ad = &s->dev[i];
+
+        ide_bus_new(&ad->port, qdev, i);
+        ide_init2(&ad->port, irqs[i]);
+
+        ad->hba = s;
+        ad->port_no = i;
+        ad->port.dma = &ad->dma;
+        ad->port.dma->ops = &ahci_dma_ops;
+        ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
+    }
+}
+
+void ahci_uninit(AHCIState *s)
+{
+    qemu_free(s->dev);
+}
+
+void ahci_reset(void *opaque)
+{
+    struct AHCIPCIState *d = opaque;
+    int i;
+
+    d->ahci.control_regs.irqstatus = 0;
+    d->ahci.control_regs.ghc = 0;
+
+    for (i = 0; i < d->ahci.ports; i++) {
+        ahci_reset_port(&d->ahci, i);
+    }
+}
diff --git a/qemu-0.15.x/hw/ide/ahci.h b/qemu-0.15.x/hw/ide/ahci.h
new file mode 100644
index 0000000..dc86951
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/ahci.h
@@ -0,0 +1,330 @@
+/*
+ * QEMU AHCI Emulation
+ *
+ * Copyright (c) 2010 qiaochong at loongson.cn
+ * Copyright (c) 2010 Roland Elek <elek.roland at gmail.com>
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt at gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef HW_IDE_AHCI_H
+#define HW_IDE_AHCI_H
+
+#define AHCI_PCI_BAR              5
+#define AHCI_MAX_PORTS            32
+#define AHCI_MAX_SG               168 /* hardware max is 64K */
+#define AHCI_DMA_BOUNDARY         0xffffffff
+#define AHCI_USE_CLUSTERING       0
+#define AHCI_MAX_CMDS             32
+#define AHCI_CMD_SZ               32
+#define AHCI_CMD_SLOT_SZ          (AHCI_MAX_CMDS * AHCI_CMD_SZ)
+#define AHCI_RX_FIS_SZ            256
+#define AHCI_CMD_TBL_CDB          0x40
+#define AHCI_CMD_TBL_HDR_SZ       0x80
+#define AHCI_CMD_TBL_SZ           (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
+#define AHCI_CMD_TBL_AR_SZ        (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
+#define AHCI_PORT_PRIV_DMA_SZ     (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
+                                   AHCI_RX_FIS_SZ)
+
+#define AHCI_IRQ_ON_SG            (1 << 31)
+#define AHCI_CMD_ATAPI            (1 << 5)
+#define AHCI_CMD_WRITE            (1 << 6)
+#define AHCI_CMD_PREFETCH         (1 << 7)
+#define AHCI_CMD_RESET            (1 << 8)
+#define AHCI_CMD_CLR_BUSY         (1 << 10)
+
+#define RX_FIS_D2H_REG            0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB                0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK                0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP                  0x00 /* host capabilities */
+#define HOST_CTL                  0x04 /* global host control */
+#define HOST_IRQ_STAT             0x08 /* interrupt status */
+#define HOST_PORTS_IMPL           0x0c /* bitmap of implemented ports */
+#define HOST_VERSION              0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET            (1 << 0)  /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN           (1 << 1)  /* global IRQ enable */
+#define HOST_CTL_AHCI_EN          (1 << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC              (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI             (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO              (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS              (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ              (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64               (1 << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR             0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI          0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR             0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI          0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT             0x10 /* interrupt status */
+#define PORT_IRQ_MASK             0x14 /* interrupt enable/disable mask */
+#define PORT_CMD                  0x18 /* port command */
+#define PORT_TFDATA               0x20 /* taskfile data */
+#define PORT_SIG                  0x24 /* device TF signature */
+#define PORT_SCR_STAT             0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL              0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR              0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT              0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE            0x38 /* command issue */
+#define PORT_RESERVED             0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES        (1 << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR           (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR         (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR    (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR           (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL      (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW         (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP          (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY           (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK         (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT          (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE          (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS          (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS          (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS         (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS         (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS      (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE           (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR |   \
+                                   PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY |    \
+                                   PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR            (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR |     \
+                                   PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ              (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |     \
+                                   PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |  \
+                                   PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI            (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON          (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON           (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX           (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO              (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON         (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP          (1 << 1) /* Spin up device */
+#define PORT_CMD_START            (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK         (0xf << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE       (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL      (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER      (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_IRQ_STAT_DHRS        (1 << 0) /* Device to Host Register FIS */
+#define PORT_IRQ_STAT_PSS         (1 << 1) /* PIO Setup FIS */
+#define PORT_IRQ_STAT_DSS         (1 << 2) /* DMA Setup FIS */
+#define PORT_IRQ_STAT_SDBS        (1 << 3) /* Set Device Bits */
+#define PORT_IRQ_STAT_UFS         (1 << 4) /* Unknown FIS */
+#define PORT_IRQ_STAT_DPS         (1 << 5) /* Descriptor Processed */
+#define PORT_IRQ_STAT_PCS         (1 << 6) /* Port Connect Change Status */
+#define PORT_IRQ_STAT_DMPS        (1 << 7) /* Device Mechanical Presence
+                                              Status */
+#define PORT_IRQ_STAT_PRCS        (1 << 22) /* File Ready Status */
+#define PORT_IRQ_STAT_IPMS        (1 << 23) /* Incorrect Port Multiplier
+                                               Status */
+#define PORT_IRQ_STAT_OFS         (1 << 24) /* Overflow Status */
+#define PORT_IRQ_STAT_INFS        (1 << 26) /* Interface Non-Fatal Error
+                                               Status */
+#define PORT_IRQ_STAT_IFS         (1 << 27) /* Interface Fatal Error */
+#define PORT_IRQ_STAT_HBDS        (1 << 28) /* Host Bus Data Error Status */
+#define PORT_IRQ_STAT_HBFS        (1 << 29) /* Host Bus Fatal Error Status */
+#define PORT_IRQ_STAT_TFES        (1 << 30) /* Task File Error Status */
+#define PORT_IRQ_STAT_CPDS        (1 << 31) /* Code Port Detect Status */
+
+/* ap->flags bits */
+#define AHCI_FLAG_NO_NCQ                  (1 << 24)
+#define AHCI_FLAG_IGN_IRQ_IF_ERR          (1 << 25) /* ignore IRQ_IF_ERR */
+#define AHCI_FLAG_HONOR_PI                (1 << 26) /* honor PORTS_IMPL */
+#define AHCI_FLAG_IGN_SERR_INTERNAL       (1 << 27) /* ignore SERR_INTERNAL */
+#define AHCI_FLAG_32BIT_ONLY              (1 << 28) /* force 32bit */
+
+#define ATA_SRST                          (1 << 2)  /* software reset */
+
+#define STATE_RUN                         0
+#define STATE_RESET                       1
+
+#define SATA_SCR_SSTATUS_DET_NODEV        0x0
+#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
+
+#define SATA_SCR_SSTATUS_SPD_NODEV        0x00
+#define SATA_SCR_SSTATUS_SPD_GEN1         0x10
+
+#define SATA_SCR_SSTATUS_IPM_NODEV        0x000
+#define SATA_SCR_SSTATUS_IPM_ACTIVE       0X100
+
+#define AHCI_SCR_SCTL_DET                 0xf
+
+#define SATA_FIS_TYPE_REGISTER_H2D        0x27
+#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
+
+#define AHCI_CMD_HDR_CMD_FIS_LEN           0x1f
+#define AHCI_CMD_HDR_PRDT_LEN              16
+
+#define SATA_SIGNATURE_CDROM               0xeb140000
+#define SATA_SIGNATURE_DISK                0x00000101
+
+#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
+                                            /* Shouldn't this be 0x2c? */
+
+#define AHCI_PORT_REGS_START_ADDR          0x100
+#define AHCI_PORT_ADDR_OFFSET_MASK         0x7f
+#define AHCI_PORT_ADDR_OFFSET_LEN          0x80
+
+#define AHCI_NUM_COMMAND_SLOTS             31
+#define AHCI_SUPPORTED_SPEED               20
+#define AHCI_SUPPORTED_SPEED_GEN1          1
+#define AHCI_VERSION_1_0                   0x10000
+
+#define AHCI_PROGMODE_MAJOR_REV_1          1
+
+#define AHCI_COMMAND_TABLE_ACMD            0x40
+
+#define IDE_FEATURE_DMA                    1
+
+#define READ_FPDMA_QUEUED                  0x60
+#define WRITE_FPDMA_QUEUED                 0x61
+
+#define RES_FIS_DSFIS                      0x00
+#define RES_FIS_PSFIS                      0x20
+#define RES_FIS_RFIS                       0x40
+#define RES_FIS_SDBFIS                     0x58
+#define RES_FIS_UFIS                       0x60
+
+typedef struct AHCIControlRegs {
+    uint32_t    cap;
+    uint32_t    ghc;
+    uint32_t    irqstatus;
+    uint32_t    impl;
+    uint32_t    version;
+} AHCIControlRegs;
+
+typedef struct AHCIPortRegs {
+    uint32_t    lst_addr;
+    uint32_t    lst_addr_hi;
+    uint32_t    fis_addr;
+    uint32_t    fis_addr_hi;
+    uint32_t    irq_stat;
+    uint32_t    irq_mask;
+    uint32_t    cmd;
+    uint32_t    unused0;
+    uint32_t    tfdata;
+    uint32_t    sig;
+    uint32_t    scr_stat;
+    uint32_t    scr_ctl;
+    uint32_t    scr_err;
+    uint32_t    scr_act;
+    uint32_t    cmd_issue;
+    uint32_t    reserved;
+} AHCIPortRegs;
+
+typedef struct AHCICmdHdr {
+    uint32_t    opts;
+    uint32_t    status;
+    uint64_t    tbl_addr;
+    uint32_t    reserved[4];
+} __attribute__ ((packed)) AHCICmdHdr;
+
+typedef struct AHCI_SG {
+    uint64_t    addr;
+    uint32_t    reserved;
+    uint32_t    flags_size;
+} __attribute__ ((packed)) AHCI_SG;
+
+typedef struct AHCIDevice AHCIDevice;
+
+typedef struct NCQTransferState {
+    AHCIDevice *drive;
+    BlockDriverAIOCB *aiocb;
+    QEMUSGList sglist;
+    int is_read;
+    uint16_t sector_count;
+    uint64_t lba;
+    uint8_t tag;
+    int slot;
+    int used;
+} NCQTransferState;
+
+struct AHCIDevice {
+    IDEDMA dma;
+    IDEBus port;
+    int port_no;
+    uint32_t port_state;
+    uint32_t finished;
+    AHCIPortRegs port_regs;
+    struct AHCIState *hba;
+    QEMUBH *check_bh;
+    uint8_t *lst;
+    uint8_t *res_fis;
+    int dma_status;
+    int done_atapi_packet;
+    int busy_slot;
+    int init_d2h_sent;
+    BlockDriverCompletionFunc *dma_cb;
+    AHCICmdHdr *cur_cmd;
+    NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
+};
+
+typedef struct AHCIState {
+    AHCIDevice *dev;
+    AHCIControlRegs control_regs;
+    int mem;
+    int ports;
+    qemu_irq irq;
+} AHCIState;
+
+typedef struct AHCIPCIState {
+    PCIDevice card;
+    AHCIState ahci;
+} AHCIPCIState;
+
+typedef struct NCQFrame {
+    uint8_t fis_type;
+    uint8_t c;
+    uint8_t command;
+    uint8_t sector_count_low;
+    uint8_t lba0;
+    uint8_t lba1;
+    uint8_t lba2;
+    uint8_t fua;
+    uint8_t lba3;
+    uint8_t lba4;
+    uint8_t lba5;
+    uint8_t sector_count_high;
+    uint8_t tag;
+    uint8_t reserved5;
+    uint8_t reserved6;
+    uint8_t control;
+    uint8_t reserved7;
+    uint8_t reserved8;
+    uint8_t reserved9;
+    uint8_t reserved10;
+} __attribute__ ((packed)) NCQFrame;
+
+void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
+void ahci_uninit(AHCIState *s);
+
+void ahci_reset(void *opaque);
+
+#endif /* HW_IDE_AHCI_H */
diff --git a/qemu-0.15.x/hw/ide/atapi.c b/qemu-0.15.x/hw/ide/atapi.c
new file mode 100644
index 0000000..fe2fb0b
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/atapi.c
@@ -0,0 +1,1138 @@
+/*
+ * QEMU ATAPI Emulation
+ *
+ * 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 "hw/ide/internal.h"
+#include "hw/scsi.h"
+
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
+
+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 inline void cpu_to_ube16(uint8_t *buf, int val)
+{
+    buf[0] = val >> 8;
+    buf[1] = val & 0xff;
+}
+
+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 & 0xff;
+}
+
+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 inline int media_present(IDEState *s)
+{
+    return (s->nb_sectors > 0);
+}
+
+/* XXX: DVDs that could fit on a CD will be reported as a CD */
+static inline int media_is_dvd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
+}
+
+static inline int media_is_cd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
+}
+
+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;
+}
+
+void ide_atapi_cmd_ok(IDEState *s)
+{
+    s->error = 0;
+    s->status = READY_STAT | SEEK_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    ide_set_irq(s->bus);
+}
+
+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->bus);
+}
+
+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 */
+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 | SEEK_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+        ide_set_irq(s->bus);
+#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;
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
+        } 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);
+            }
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
+            ide_set_irq(s->bus);
+#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 | SEEK_STAT | DRQ_STAT;
+        s->bus->dma->ops->start_dma(s->bus->dma, s,
+                                   ide_atapi_cmd_read_dma_cb);
+    } else {
+        s->status = READY_STAT | SEEK_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 | SEEK_STAT;
+    ide_atapi_cmd_reply_end(s);
+}
+
+static void ide_atapi_cmd_check_status(IDEState *s)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("atapi_cmd_check_status\n");
+#endif
+    s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
+    s->status = ERR_STAT;
+    s->nsector = 0;
+    ide_set_irq(s->bus);
+}
+/* ATAPI DMA support */
+
+/* XXX: handle read errors */
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+    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 (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0)
+            goto eot;
+    }
+
+    if (s->packet_transfer_size <= 0) {
+        s->status = READY_STAT | SEEK_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+        ide_set_irq(s->bus);
+    eot:
+        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+        ide_set_inactive(s);
+        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 > (IDE_DMA_BUF_SECTORS / 4))
+            n = (IDE_DMA_BUF_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
+    s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
+    s->bus->dma->iov.iov_len = n * 4 * 512;
+    qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
+    s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2,
+                                       &s->bus->dma->qiov, n * 4,
+                                       ide_atapi_cmd_read_dma_cb, s);
+    if (!s->bus->dma->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 | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->bus->dma->ops->start_dma(s->bus->dma, 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 inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
+                                            uint16_t profile)
+{
+    uint8_t *buf_profile = buf + 12; /* start of profiles */
+
+    buf_profile += ((*index) * 4); /* start of indexed profile */
+    cpu_to_ube16 (buf_profile, profile);
+    buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
+
+    /* each profile adds 4 bytes to the response */
+    (*index)++;
+    buf[11] += 4; /* Additional Length */
+
+    return 4;
+}
+
+static int ide_dvd_read_structure(IDEState *s, int format,
+                                  const uint8_t *packet, uint8_t *buf)
+{
+    switch (format) {
+        case 0x0: /* Physical format information */
+            {
+                int layer = packet[6];
+                uint64_t total_sectors;
+
+                if (layer != 0)
+                    return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+                total_sectors = s->nb_sectors >> 2;
+                if (total_sectors == 0) {
+                    return -ASC_MEDIUM_NOT_PRESENT;
+                }
+
+                buf[4] = 1;   /* DVD-ROM, part version 1 */
+                buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+                buf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+                buf[7] = 0;   /* default densities */
+
+                /* FIXME: 0x30000 per spec? */
+                cpu_to_ube32(buf + 8, 0); /* start sector */
+                cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
+                cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
+
+                /* Size of buffer, not including 2 byte size field */
+                cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+                /* 2k data + 4 byte header */
+                return (2048 + 4);
+            }
+
+        case 0x01: /* DVD copyright information */
+            buf[4] = 0; /* no copyright data */
+            buf[5] = 0; /* no region restrictions */
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 4 + 2);
+
+            /* 4 byte header + 4 byte data */
+            return (4 + 4);
+
+        case 0x03: /* BCA information - invalid field for no BCA info */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+        case 0x04: /* DVD disc manufacturing information */
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+            /* 2k data + 4 byte header */
+            return (2048 + 4);
+
+        case 0xff:
+            /*
+             * This lists all the command capabilities above.  Add new ones
+             * in order and update the length and buffer return values.
+             */
+
+            buf[4] = 0x00; /* Physical format */
+            buf[5] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
+
+            buf[8] = 0x01; /* Copyright info */
+            buf[9] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
+
+            buf[12] = 0x03; /* BCA info */
+            buf[13] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
+
+            buf[16] = 0x04; /* Manufacturing info */
+            buf[17] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 16 + 2);
+
+            /* data written + 4 byte header */
+            return (16 + 4);
+
+        default: /* TODO: formats beyond DVD-ROM requires */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+    }
+}
+
+static unsigned int event_status_media(IDEState *s,
+                                       uint8_t *buf)
+{
+    enum media_event_code {
+        MEC_NO_CHANGE = 0,       /* Status unchanged */
+        MEC_EJECT_REQUESTED,     /* received a request from user to eject */
+        MEC_NEW_MEDIA,           /* new media inserted and ready for access */
+        MEC_MEDIA_REMOVAL,       /* only for media changers */
+        MEC_MEDIA_CHANGED,       /* only for media changers */
+        MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */
+        MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */
+    };
+    enum media_status {
+        MS_TRAY_OPEN = 1,
+        MS_MEDIA_PRESENT = 2,
+    };
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->bs->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* Event notification descriptor */
+    event_code = MEC_NO_CHANGE;
+    if (media_status != MS_TRAY_OPEN && s->events.new_media) {
+        event_code = MEC_NEW_MEDIA;
+        s->events.new_media = false;
+    }
+
+    buf[4] = event_code;
+    buf[5] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    buf[6] = 0;
+    buf[7] = 0;
+
+    return 8; /* We wrote to 4 extra bytes from the header */
+}
+
+static void cmd_get_event_status_notification(IDEState *s,
+                                              uint8_t *buf)
+{
+    const uint8_t *packet = buf;
+
+    struct {
+        uint8_t opcode;
+        uint8_t polled;        /* lsb bit is polled; others are reserved */
+        uint8_t reserved2[2];
+        uint8_t class;
+        uint8_t reserved3[2];
+        uint16_t len;
+        uint8_t control;
+    } __attribute__((packed)) *gesn_cdb;
+
+    struct {
+        uint16_t len;
+        uint8_t notification_class;
+        uint8_t supported_events;
+    } __attribute((packed)) *gesn_event_header;
+
+    enum notification_class_request_type {
+        NCR_RESERVED1 = 1 << 0,
+        NCR_OPERATIONAL_CHANGE = 1 << 1,
+        NCR_POWER_MANAGEMENT = 1 << 2,
+        NCR_EXTERNAL_REQUEST = 1 << 3,
+        NCR_MEDIA = 1 << 4,
+        NCR_MULTI_HOST = 1 << 5,
+        NCR_DEVICE_BUSY = 1 << 6,
+        NCR_RESERVED2 = 1 << 7,
+    };
+    enum event_notification_class_field {
+        ENC_NO_EVENTS = 0,
+        ENC_OPERATIONAL_CHANGE,
+        ENC_POWER_MANAGEMENT,
+        ENC_EXTERNAL_REQUEST,
+        ENC_MEDIA,
+        ENC_MULTIPLE_HOSTS,
+        ENC_DEVICE_BUSY,
+        ENC_RESERVED,
+    };
+    unsigned int max_len, used_len;
+
+    gesn_cdb = (void *)packet;
+    gesn_event_header = (void *)buf;
+
+    max_len = be16_to_cpu(gesn_cdb->len);
+
+    /* It is fine by the MMC spec to not support async mode operations */
+    if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */
+        /* Only polling is supported, asynchronous mode is not. */
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        return;
+    }
+
+    /* polling mode operation */
+
+    /*
+     * These are the supported events.
+     *
+     * We currently only support requests of the 'media' type.
+     */
+    gesn_event_header->supported_events = NCR_MEDIA;
+
+    /*
+     * We use |= below to set the class field; other bits in this byte
+     * are reserved now but this is useful to do if we have to use the
+     * reserved fields later.
+     */
+    gesn_event_header->notification_class = 0;
+
+    /*
+     * Responses to requests are to be based on request priority.  The
+     * notification_class_request_type enum above specifies the
+     * priority: upper elements are higher prio than lower ones.
+     */
+    if (gesn_cdb->class & NCR_MEDIA) {
+        gesn_event_header->notification_class |= ENC_MEDIA;
+        used_len = event_status_media(s, buf);
+    } else {
+        gesn_event_header->notification_class = 0x80; /* No event available */
+        used_len = sizeof(*gesn_event_header);
+    }
+    gesn_event_header->len = cpu_to_be16(used_len
+                                         - sizeof(*gesn_event_header));
+    ide_atapi_cmd_reply(s, used_len, max_len);
+}
+
+static void cmd_request_sense(IDEState *s, uint8_t *buf)
+{
+    int max_len = buf[4];
+
+    memset(buf, 0, 18);
+    buf[0] = 0x70 | (1 << 7);
+    buf[2] = s->sense_key;
+    buf[7] = 10;
+    buf[12] = s->asc;
+
+    if (s->sense_key == SENSE_UNIT_ATTENTION) {
+        s->sense_key = SENSE_NONE;
+    }
+
+    ide_atapi_cmd_reply(s, 18, max_len);
+}
+
+static void cmd_inquiry(IDEState *s, uint8_t *buf)
+{
+    int max_len = buf[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 DVD-ROM");
+    padstr8(buf + 32, 4, s->version);
+    ide_atapi_cmd_reply(s, 36, max_len);
+}
+
+static void cmd_get_configuration(IDEState *s, uint8_t *buf)
+{
+    uint32_t len;
+    uint8_t index = 0;
+    int max_len;
+
+    /* only feature 0 is supported */
+    if (buf[2] != 0 || buf[3] != 0) {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        return;
+    }
+
+    /* XXX: could result in alignment problems in some architectures */
+    max_len = ube16_to_cpu(buf + 7);
+
+    /*
+     * XXX: avoid overflow for io_buffer if max_len is bigger than
+     *      the size of that buffer (dimensioned to max number of
+     *      sectors to transfer at once)
+     *
+     *      Only a problem if the feature/profiles grow.
+     */
+    if (max_len > 512) {
+        /* XXX: assume 1 sector */
+        max_len = 512;
+    }
+
+    memset(buf, 0, max_len);
+    /*
+     * the number of sectors from the media tells us which profile
+     * to use as current.  0 means there is no media
+     */
+    if (media_is_dvd(s)) {
+        cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
+    } else if (media_is_cd(s)) {
+        cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
+    }
+
+    buf[10] = 0x02 | 0x01; /* persistent and current */
+    len = 12; /* headers: 8 + 4 */
+    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
+    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
+    cpu_to_ube32(buf, len - 4); /* data length */
+
+    ide_atapi_cmd_reply(s, len, max_len);
+}
+
+static void cmd_mode_sense(IDEState *s, uint8_t *buf)
+{
+    int action, code;
+    int max_len;
+
+    if (buf[0] == GPCMD_MODE_SENSE_10) {
+        max_len = ube16_to_cpu(buf + 7);
+    } else {
+        max_len = buf[4];
+    }
+
+    action = buf[2] >> 6;
+    code = buf[2] & 0x3f;
+
+    switch(action) {
+    case 0: /* current values */
+        switch(code) {
+        case GPMODE_R_W_ERROR_PAGE: /* 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 GPMODE_AUDIO_CTL_PAGE:
+            cpu_to_ube16(&buf[0], 24 + 6);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            /* Fill with CDROM audio volume */
+            buf[17] = 0;
+            buf[19] = 0;
+            buf[21] = 0;
+            buf[23] = 0;
+
+            ide_atapi_cmd_reply(s, 24, max_len);
+            break;
+        case GPMODE_CAPABILITIES_PAGE:
+            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] = 0x00;
+            buf[11] = 0x00;
+
+            /* Claim PLAY_AUDIO capability (0x01) since some Linux
+               code checks for this to automount media. */
+            buf[12] = 0x71;
+            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;
+    }
+    return;
+
+error_cmd:
+    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+}
+
+static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
+{
+    /* Not Ready Conditions are already handled in ide_atapi_cmd(), so if we
+     * come here, we know that it's ready. */
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
+{
+    bdrv_set_locked(s->bs, buf[4] & 1);
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_read(IDEState *s, uint8_t* buf)
+{
+    int nb_sectors, lba;
+
+    if (buf[0] == GPCMD_READ_10) {
+        nb_sectors = ube16_to_cpu(buf + 7);
+    } else {
+        nb_sectors = ube32_to_cpu(buf + 6);
+    }
+
+    lba = ube32_to_cpu(buf + 2);
+    if (nb_sectors == 0) {
+        ide_atapi_cmd_ok(s);
+        return;
+    }
+
+    ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
+}
+
+static void cmd_read_cd(IDEState *s, uint8_t* buf)
+{
+    int nb_sectors, lba, transfer_request;
+
+    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
+    lba = ube32_to_cpu(buf + 2);
+
+    if (nb_sectors == 0) {
+        ide_atapi_cmd_ok(s);
+        return;
+    }
+
+    transfer_request = buf[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;
+    }
+}
+
+static void cmd_seek(IDEState *s, uint8_t* buf)
+{
+    unsigned int lba;
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    lba = ube32_to_cpu(buf + 2);
+    if (lba >= total_sectors) {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+        return;
+    }
+
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
+{
+    int start, eject, sense, err = 0;
+    start = buf[4] & 1;
+    eject = (buf[4] >> 1) & 1;
+
+    if (eject) {
+        err = bdrv_eject(s->bs, !start);
+    }
+
+    switch (err) {
+    case 0:
+        ide_atapi_cmd_ok(s);
+        break;
+    case -EBUSY:
+        sense = SENSE_NOT_READY;
+        if (bdrv_is_inserted(s->bs)) {
+            sense = SENSE_ILLEGAL_REQUEST;
+        }
+        ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+        break;
+    default:
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        break;
+    }
+}
+
+static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
+{
+    int max_len = ube16_to_cpu(buf + 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);
+}
+
+static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
+{
+    int format, msf, start_track, len;
+    int max_len;
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    max_len = ube16_to_cpu(buf + 7);
+    format = buf[9] >> 6;
+    msf = (buf[1] >> 1) & 1;
+    start_track = buf[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);
+    }
+}
+
+static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
+{
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    /* 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);
+}
+
+static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
+{
+    int max_len;
+    int media = buf[1];
+    int format = buf[7];
+    int ret;
+
+    max_len = ube16_to_cpu(buf + 8);
+
+    if (format < 0xff) {
+        if (media_is_cd(s)) {
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INCOMPATIBLE_FORMAT);
+            return;
+        } else if (!media_present(s)) {
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INV_FIELD_IN_CMD_PACKET);
+            return;
+        }
+    }
+
+    memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
+           IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
+
+    switch (format) {
+        case 0x00 ... 0x7f:
+        case 0xff:
+            if (media == 0) {
+                ret = ide_dvd_read_structure(s, format, buf, buf);
+
+                if (ret < 0) {
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
+                } else {
+                    ide_atapi_cmd_reply(s, ret, max_len);
+                }
+
+                break;
+            }
+            /* TODO: BD support, fall through for now */
+
+        /* Generic disk structures */
+        case 0x80: /* TODO: AACS volume identifier */
+        case 0x81: /* TODO: AACS media serial number */
+        case 0x82: /* TODO: AACS media identifier */
+        case 0x83: /* TODO: AACS media key block */
+        case 0x90: /* TODO: List of recognized format layers */
+        case 0xc0: /* TODO: Write protection status */
+        default:
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INV_FIELD_IN_CMD_PACKET);
+            break;
+    }
+}
+
+static void cmd_set_speed(IDEState *s, uint8_t* buf)
+{
+    ide_atapi_cmd_ok(s);
+}
+
+enum {
+    /*
+     * Only commands flagged as ALLOW_UA are allowed to run under a
+     * unit attention condition. (See MMC-5, section 4.1.6.1)
+     */
+    ALLOW_UA = 0x01,
+
+    /*
+     * Commands flagged with CHECK_READY can only execute if a medium is present.
+     * Otherwise they report the Not Ready Condition. (See MMC-5, section
+     * 4.1.8)
+     */
+    CHECK_READY = 0x02,
+};
+
+static const struct {
+    void (*handler)(IDEState *s, uint8_t *buf);
+    int flags;
+} atapi_cmd_table[0x100] = {
+    [ 0x00 ] = { cmd_test_unit_ready,               CHECK_READY },
+    [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
+    [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
+    [ 0x1a ] = { cmd_mode_sense, /* (6) */          0 },
+    [ 0x1b ] = { cmd_start_stop_unit,               0 },
+    [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
+    [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
+    [ 0x28 ] = { cmd_read, /* (10) */               0 },
+    [ 0x2b ] = { cmd_seek,                          CHECK_READY },
+    [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
+    [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
+    [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
+    [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
+    [ 0xa8 ] = { cmd_read, /* (12) */               0 },
+    [ 0xad ] = { cmd_read_dvd_structure,            0 },
+    [ 0xbb ] = { cmd_set_speed,                     0 },
+    [ 0xbd ] = { cmd_mechanism_status,              0 },
+    [ 0xbe ] = { cmd_read_cd,                       0 },
+};
+
+void ide_atapi_cmd(IDEState *s)
+{
+    uint8_t *buf;
+
+    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", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+    /*
+     * If there's a UNIT_ATTENTION condition pending, only command flagged with
+     * ALLOW_UA are allowed to complete. with other commands getting a CHECK
+     * condition response unless a higher priority status, defined by the drive
+     * here, is pending.
+     */
+    if (s->sense_key == SENSE_UNIT_ATTENTION &&
+        !(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA)) {
+        ide_atapi_cmd_check_status(s);
+        return;
+    }
+    /*
+     * When a CD gets changed, we have to report an ejected state and
+     * then a loaded state to guests so that they detect tray
+     * open/close and media change events.  Guests that do not use
+     * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
+     * states rely on this behavior.
+     */
+    if (bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+
+        s->cdrom_changed = 0;
+        s->sense_key = SENSE_UNIT_ATTENTION;
+        s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
+        return;
+    }
+
+    /* Report a Not Ready condition if appropriate for the command */
+    if ((atapi_cmd_table[s->io_buffer[0]].flags & CHECK_READY) &&
+        (!media_present(s) || !bdrv_is_inserted(s->bs)))
+    {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        return;
+    }
+
+    /* Execute the command */
+    if (atapi_cmd_table[s->io_buffer[0]].handler) {
+        atapi_cmd_table[s->io_buffer[0]].handler(s, buf);
+        return;
+    }
+
+    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
+}
diff --git a/qemu-0.15.x/hw/ide/cmd646.c b/qemu-0.15.x/hw/ide/cmd646.c
new file mode 100644
index 0000000..56302b5
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/cmd646.c
@@ -0,0 +1,296 @@
+/*
+ * QEMU IDE Emulation: PCI cmd646 support.
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "sysemu.h"
+#include "dma.h"
+
+#include <hw/ide/pci.h>
+
+/* 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
+
+static void cmd646_update_irq(PCIIDEState *d);
+
+static void ide_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    IDEBus *bus;
+
+    if (region_num <= 3) {
+        bus = &d->bus[(region_num >> 1)];
+        if (region_num & 1) {
+            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
+            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
+        } else {
+            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
+            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
+
+            /* data ports */
+            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
+            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
+            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
+            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
+        }
+    }
+}
+
+static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
+                                   uint32_t addr)
+{
+    uint32_t val;
+
+    switch(addr & 3) {
+    case 0:
+        val = bm->cmd;
+        break;
+    case 1:
+        val = pci_dev->dev.config[MRDMODE];
+        break;
+    case 2:
+        val = bm->status;
+        break;
+    case 3:
+        if (bm == &pci_dev->bmdma[0]) {
+            val = pci_dev->dev.config[UDIDETCR0];
+        } else {
+            val = pci_dev->dev.config[UDIDETCR1];
+        }
+        break;
+    default:
+        val = 0xff;
+        break;
+    }
+#ifdef DEBUG_IDE
+    printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static uint32_t bmdma_readb_0(void *opaque, uint32_t addr)
+{
+    PCIIDEState *pci_dev = opaque;
+    BMDMAState *bm = &pci_dev->bmdma[0];
+
+    return bmdma_readb_common(pci_dev, bm, addr);
+}
+
+static uint32_t bmdma_readb_1(void *opaque, uint32_t addr)
+{
+    PCIIDEState *pci_dev = opaque;
+    BMDMAState *bm = &pci_dev->bmdma[1];
+
+    return bmdma_readb_common(pci_dev, bm, addr);
+}
+
+static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
+                                uint32_t addr, uint32_t val)
+{
+#ifdef DEBUG_IDE
+    printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    switch(addr & 3) {
+    case 0:
+        bmdma_cmd_writeb(bm, addr, val);
+        break;
+    case 1:
+        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:
+        if (bm == &pci_dev->bmdma[0])
+            pci_dev->dev.config[UDIDETCR0] = val;
+        else
+            pci_dev->dev.config[UDIDETCR1] = val;
+        break;
+    }
+}
+
+static void bmdma_writeb_0(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIIDEState *pci_dev = opaque;
+    BMDMAState *bm = &pci_dev->bmdma[0];
+
+    bmdma_writeb_common(pci_dev, bm, addr, val);
+}
+
+static void bmdma_writeb_1(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIIDEState *pci_dev = opaque;
+    BMDMAState *bm = &pci_dev->bmdma[1];
+
+    bmdma_writeb_common(pci_dev, bm, addr, val);
+}
+
+static void bmdma_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    int i;
+
+    for(i = 0;i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        if (i == 0) {
+            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
+            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
+        } else {
+            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
+            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
+        }
+
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
+        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);
+}
+
+static void cmd646_reset(void *opaque)
+{
+    PCIIDEState *d = opaque;
+    unsigned int i;
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_reset(&d->bus[i]);
+    }
+}
+
+/* CMD646 PCI IDE controller */
+static int pci_cmd646_ide_initfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    uint8_t *pci_conf = d->dev.config;
+    qemu_irq *irq;
+    int i;
+
+    pci_conf[PCI_CLASS_PROG] = 0x8f;
+
+    pci_conf[0x51] = 0x04; // enable IDE0
+    if (d->secondary) {
+        /* XXX: if not enabled, really disable the seconday IDE controller */
+        pci_conf[0x51] |= 0x08; /* enable IDE1 */
+    }
+
+    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
+    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
+    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
+    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
+    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+
+    /* TODO: RST# value should be 0 */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
+
+    irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
+    for (i = 0; i < 2; i++) {
+        ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+        ide_init2(&d->bus[i], irq[i]);
+
+        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        d->bmdma[i].bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i].dma);
+    }
+
+    vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
+    qemu_register_reset(cmd646_reset, d);
+    return 0;
+}
+
+void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
+                         int secondary_ide_enabled)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, -1, "cmd646-ide");
+    qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
+    qdev_init_nofail(&dev->qdev);
+
+    pci_ide_create_devs(dev, hd_table);
+}
+
+static PCIDeviceInfo cmd646_ide_info[] = {
+    {
+        .qdev.name    = "cmd646-ide",
+        .qdev.size    = sizeof(PCIIDEState),
+        .init         = pci_cmd646_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_CMD,
+        .device_id    = PCI_DEVICE_ID_CMD_646,
+        .revision     = 0x07, // IDE controller revision
+        .class_id     = PCI_CLASS_STORAGE_IDE,
+        .qdev.props   = (Property[]) {
+            DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+    },{
+        /* end of list */
+    }
+};
+
+static void cmd646_ide_register(void)
+{
+    pci_qdev_register_many(cmd646_ide_info);
+}
+device_init(cmd646_ide_register);
diff --git a/qemu-0.15.x/hw/ide/core.c b/qemu-0.15.x/hw/ide/core.c
new file mode 100644
index 0000000..d145b19
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/core.c
@@ -0,0 +1,2104 @@
+/*
+ * QEMU IDE disk and CD/DVD-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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include "qemu-error.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "dma.h"
+#include "blockdev.h"
+
+#include <hw/ide/internal.h>
+
+/* These values were based on a Seagate ST3500418AS but have been modified
+   to make more sense in QEMU */
+static const int smart_attributes[][12] = {
+    /* id,  flags, hflags, val, wrst, raw (6 bytes), threshold */
+    /* raw read error rate*/
+    { 0x01, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
+    /* spin up */
+    { 0x03, 0x03, 0x00, 0x64, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* start stop count */
+    { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14},
+    /* remapped sectors */
+    { 0x05, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24},
+    /* power on hours */
+    { 0x09, 0x03, 0x00, 0x64, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* power cycle count */
+    { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+    /* airflow-temperature-celsius */
+    { 190,  0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
+    /* end of list */
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static int ide_handle_rw_error(IDEState *s, int error, int op);
+static void ide_dummy_transfer_stop(IDEState *s);
+
+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 = ' ';
+        str[i^1] = v;
+    }
+}
+
+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;
+    IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
+
+    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);
+    padstr((char *)(p + 10), s->drive_serial_str, 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((char *)(p + 23), s->version, 8); /* firmware version */
+    padstr((char *)(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 + 62, 0x07); /* single word dma0-2 supported */
+    put_le16(p + 63, 0x07); /* mdma0-2 supported */
+    put_le16(p + 64, 0x03); /* pio3-4 supported */
+    put_le16(p + 65, 120);
+    put_le16(p + 66, 120);
+    put_le16(p + 67, 120);
+    put_le16(p + 68, 120);
+    if (dev && dev->conf.discard_granularity) {
+        put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
+    }
+
+    if (s->ncq_queues) {
+        put_le16(p + 75, s->ncq_queues - 1);
+        /* NCQ supported */
+        put_le16(p + 76, (1 << 8));
+    }
+
+    put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
+    put_le16(p + 81, 0x16); /* conforms to ata5 */
+    /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
+    put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
+    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+    put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+    /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
+    put_le16(p + 84, (1 << 14) | 0);
+    /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
+    if (bdrv_enable_write_cache(s->bs))
+         put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
+    else
+         put_le16(p + 85, (1 << 14) | 1);
+    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+    put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+    /* 14=set to 1, 1=smart self test, 0=smart error logging */
+    put_le16(p + 87, (1 << 14) | 0);
+    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);
+
+    if (dev && dev->conf.physical_block_size)
+        put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+    if (dev && dev->conf.discard_granularity) {
+        put_le16(p + 169, 1); /* TRIM support */
+    }
+
+    memcpy(s->identify_data, p, sizeof(s->identify_data));
+    s->identify_set = 1;
+}
+
+static void ide_atapi_identify(IDEState *s)
+{
+    uint16_t *p;
+
+    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));
+    padstr((char *)(p + 10), s->drive_serial_str, 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((char *)(p + 23), s->version, 8); /* firmware version */
+    padstr((char *)(p + 27), "QEMU DVD-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 + 62, 7);  /* single word dma0-2 supported */
+    put_le16(p + 63, 7);  /* mdma0-2 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 */
+#endif
+    put_le16(p + 64, 3); /* pio3-4 supported */
+    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 */
+
+    if (s->ncq_queues) {
+        put_le16(p + 75, s->ncq_queues - 1);
+        /* NCQ supported */
+        put_le16(p + 76, (1 << 8));
+    }
+
+    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;
+
+    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 */
+    padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
+    put_le16(p + 22, 0x0004);			/* ECC bytes */
+    padstr((char *) (p + 23), s->version, 8);	/* Firmware Revision */
+    padstr((char *) (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->drive_kind == IDE_CD) {
+        s->lcyl = 0x14;
+        s->hcyl = 0xeb;
+    } else if (s->bs) {
+        s->lcyl = 0;
+        s->hcyl = 0;
+    } else {
+        s->lcyl = 0xff;
+        s->hcyl = 0xff;
+    }
+}
+
+typedef struct TrimAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} TrimAIOCB;
+
+static void trim_aio_cancel(BlockDriverAIOCB *acb)
+{
+    TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
+
+    qemu_bh_delete(iocb->bh);
+    iocb->bh = NULL;
+    qemu_aio_release(iocb);
+}
+
+static AIOPool trim_aio_pool = {
+    .aiocb_size         = sizeof(TrimAIOCB),
+    .cancel             = trim_aio_cancel,
+};
+
+static void ide_trim_bh_cb(void *opaque)
+{
+    TrimAIOCB *iocb = opaque;
+
+    iocb->common.cb(iocb->common.opaque, iocb->ret);
+
+    qemu_bh_delete(iocb->bh);
+    iocb->bh = NULL;
+
+    qemu_aio_release(iocb);
+}
+
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    TrimAIOCB *iocb;
+    int i, j, ret;
+
+    iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
+    iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
+    iocb->ret = 0;
+
+    for (j = 0; j < qiov->niov; j++) {
+        uint64_t *buffer = qiov->iov[j].iov_base;
+
+        for (i = 0; i < qiov->iov[j].iov_len / 8; i++) {
+            /* 6-byte LBA + 2-byte range per entry */
+            uint64_t entry = le64_to_cpu(buffer[i]);
+            uint64_t sector = entry & 0x0000ffffffffffffULL;
+            uint16_t count = entry >> 48;
+
+            if (count == 0) {
+                break;
+            }
+
+            ret = bdrv_discard(bs, sector, count);
+            if (!iocb->ret) {
+                iocb->ret = ret;
+            }
+        }
+    }
+
+    qemu_bh_schedule(iocb->bh);
+
+    return &iocb->common;
+}
+
+static inline void ide_abort_command(IDEState *s)
+{
+    s->status = READY_STAT | ERR_STAT;
+    s->error = ABRT_ERR;
+}
+
+/* prepare data transfer and tell what to do after */
+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;
+    }
+    s->bus->dma->ops->start_transfer(s->bus->dma);
+}
+
+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;
+}
+
+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;
+}
+
+void ide_set_sector(IDEState *s, int64_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_rw_error(IDEState *s) {
+    ide_abort_command(s);
+    ide_set_irq(s->bus);
+}
+
+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=%" PRId64 "\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);
+        if (ret != 0) {
+            if (ide_handle_rw_error(s, -ret,
+                BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
+            {
+                return;
+            }
+        }
+        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
+        ide_set_irq(s->bus);
+        ide_set_sector(s, sector_num + n);
+        s->nsector -= n;
+    }
+}
+
+static void dma_buf_commit(IDEState *s, int is_write)
+{
+    qemu_sglist_destroy(&s->sg);
+}
+
+void ide_set_inactive(IDEState *s)
+{
+    s->bus->dma->aiocb = NULL;
+    s->bus->dma->ops->set_inactive(s->bus->dma);
+}
+
+void ide_dma_error(IDEState *s)
+{
+    ide_transfer_stop(s);
+    s->error = ABRT_ERR;
+    s->status = READY_STAT | ERR_STAT;
+    ide_set_inactive(s);
+    ide_set_irq(s->bus);
+}
+
+static int ide_handle_rw_error(IDEState *s, int error, int op)
+{
+    int is_read = (op & BM_STATUS_RETRY_READ);
+    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+
+    if (action == BLOCK_ERR_IGNORE) {
+        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+        return 0;
+    }
+
+    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+            || action == BLOCK_ERR_STOP_ANY) {
+        s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
+        s->bus->error_status = op;
+        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+        vm_stop(VMSTOP_DISKFULL);
+    } else {
+        if (op & BM_STATUS_DMA_RETRY) {
+            dma_buf_commit(s, 0);
+            ide_dma_error(s);
+        } else {
+            ide_rw_error(s);
+        }
+        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+    }
+
+    return 1;
+}
+
+void ide_dma_cb(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+    int n;
+    int64_t sector_num;
+
+handle_rw_error:
+    if (ret < 0) {
+        int op = BM_STATUS_DMA_RETRY;
+
+        if (s->dma_cmd == IDE_DMA_READ)
+            op |= BM_STATUS_RETRY_READ;
+        else if (s->dma_cmd == IDE_DMA_TRIM)
+            op |= BM_STATUS_RETRY_TRIM;
+
+        if (ide_handle_rw_error(s, -ret, op)) {
+            return;
+        }
+    }
+
+    n = s->io_buffer_size >> 9;
+    sector_num = ide_get_sector(s);
+    if (n > 0) {
+        dma_buf_commit(s, ide_cmd_is_read(s));
+        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->bus);
+        goto eot;
+    }
+
+    /* launch next transfer */
+    n = s->nsector;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = n * 512;
+    if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
+        /* The PRDs were too short. Reset the Active bit, but don't raise an
+         * interrupt. */
+        goto eot;
+    }
+
+#ifdef DEBUG_AIO
+    printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
+           sector_num, n, s->dma_cmd);
+#endif
+
+    switch (s->dma_cmd) {
+    case IDE_DMA_READ:
+        s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
+                                           ide_dma_cb, s);
+        break;
+    case IDE_DMA_WRITE:
+        s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
+                                            ide_dma_cb, s);
+        break;
+    case IDE_DMA_TRIM:
+        s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+                                         ide_issue_trim, ide_dma_cb, s, 1);
+        break;
+    }
+
+    if (!s->bus->dma->aiocb) {
+        ret = -1;
+        goto handle_rw_error;
+    }
+    return;
+
+eot:
+   ide_set_inactive(s);
+}
+
+static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
+{
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    s->dma_cmd = dma_cmd;
+    s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
+}
+
+static void ide_sector_write_timer_cb(void *opaque)
+{
+    IDEState *s = opaque;
+    ide_set_irq(s->bus);
+}
+
+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=%" PRId64 "\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);
+
+    if (ret != 0) {
+        if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+            return;
+    }
+
+    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);
+
+    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_ns(vm_clock) + (get_ticks_per_sec() / 1000));
+    } else {
+        ide_set_irq(s->bus);
+    }
+}
+
+static void ide_flush_cb(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+
+    if (ret < 0) {
+        /* XXX: What sector number to set here? */
+        if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
+            return;
+        }
+    }
+
+    s->status = READY_STAT | SEEK_STAT;
+    ide_set_irq(s->bus);
+}
+
+void ide_flush_cache(IDEState *s)
+{
+    BlockDriverAIOCB *acb;
+
+    if (s->bs == NULL) {
+        ide_flush_cb(s, 0);
+        return;
+    }
+
+    acb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
+    if (acb == NULL) {
+        ide_flush_cb(s, -EIO);
+    }
+}
+
+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, int reason)
+{
+    IDEState *s = opaque;
+    uint64_t nb_sectors;
+
+    if (!(reason & CHANGE_MEDIA)) {
+        return;
+    }
+
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    s->nb_sectors = nb_sectors;
+
+    /*
+     * First indicate to the guest that a CD has been removed.  That's
+     * done on the next command the guest sends us.
+     *
+     * Then we set SENSE_UNIT_ATTENTION, by which the guest will
+     * detect a new CD in the drive.  See ide_atapi_cmd() for details.
+     */
+    s->cdrom_changed = 1;
+    s->events.new_media = true;
+    ide_set_irq(s->bus);
+}
+
+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(IDEBus *bus)
+{
+    /* any write clears HOB high bit of device control register */
+    bus->ifs[0].select &= ~(1 << 7);
+    bus->ifs[1].select &= ~(1 << 7);
+}
+
+void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEBus *bus = opaque;
+
+#ifdef DEBUG_IDE
+    printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
+#endif
+
+    addr &= 7;
+
+    /* ignore writes to command block while busy with previous command */
+    if (addr != 7 && (idebus_active_if(bus)->status & (BUSY_STAT|DRQ_STAT)))
+        return;
+
+    switch(addr) {
+    case 0:
+        break;
+    case 1:
+	ide_clear_hob(bus);
+        /* NOTE: data is written to the two drives */
+	bus->ifs[0].hob_feature = bus->ifs[0].feature;
+	bus->ifs[1].hob_feature = bus->ifs[1].feature;
+        bus->ifs[0].feature = val;
+        bus->ifs[1].feature = val;
+        break;
+    case 2:
+	ide_clear_hob(bus);
+	bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
+	bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
+        bus->ifs[0].nsector = val;
+        bus->ifs[1].nsector = val;
+        break;
+    case 3:
+	ide_clear_hob(bus);
+	bus->ifs[0].hob_sector = bus->ifs[0].sector;
+	bus->ifs[1].hob_sector = bus->ifs[1].sector;
+        bus->ifs[0].sector = val;
+        bus->ifs[1].sector = val;
+        break;
+    case 4:
+	ide_clear_hob(bus);
+	bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
+	bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
+        bus->ifs[0].lcyl = val;
+        bus->ifs[1].lcyl = val;
+        break;
+    case 5:
+	ide_clear_hob(bus);
+	bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
+	bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
+        bus->ifs[0].hcyl = val;
+        bus->ifs[1].hcyl = val;
+        break;
+    case 6:
+	/* FIXME: HOB readback uses bit 7 */
+        bus->ifs[0].select = (val & ~0x10) | 0xa0;
+        bus->ifs[1].select = (val | 0x10) | 0xa0;
+        /* select drive */
+        bus->unit = (val >> 4) & 1;
+        break;
+    default:
+    case 7:
+        /* command */
+        ide_exec_cmd(bus, val);
+        break;
+    }
+}
+
+
+void ide_exec_cmd(IDEBus *bus, uint32_t val)
+{
+    IDEState *s;
+    int n;
+    int lba48 = 0;
+
+#if defined(DEBUG_IDE)
+    printf("ide: CMD=%02x\n", val);
+#endif
+    s = idebus_active_if(bus);
+    /* ignore commands to non existant slave */
+    if (s != bus->ifs && !s->bs)
+        return;
+
+    /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
+    if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
+        return;
+
+    switch(val) {
+    case WIN_DSM:
+        switch (s->feature) {
+        case DSM_TRIM:
+            if (!s->bs) {
+                goto abort_cmd;
+            }
+            ide_sector_start_dma(s, IDE_DMA_TRIM);
+            break;
+        default:
+            goto abort_cmd;
+        }
+        break;
+    case WIN_IDENTIFY:
+        if (s->bs && s->drive_kind != IDE_CD) {
+            if (s->drive_kind != IDE_CFATA)
+                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->drive_kind == IDE_CD) {
+                ide_set_signature(s);
+            }
+            ide_abort_command(s);
+        }
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SPECIFY:
+    case WIN_RECAL:
+        s->error = 0;
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SETMULT:
+        if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
+            /* Disable Read and Write Multiple */
+            s->mult_sectors = 0;
+            s->status = READY_STAT | SEEK_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 | SEEK_STAT;
+        }
+        ide_set_irq(s->bus);
+        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 | SEEK_STAT;
+        ide_set_irq(s->bus);
+        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_start_dma(s, IDE_DMA_READ);
+        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_start_dma(s, IDE_DMA_WRITE);
+        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 | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_CHECKPOWERMODE1:
+    case WIN_CHECKPOWERMODE2:
+        s->error = 0;
+        s->nsector = 0xff; /* device active or idle */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        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->bus);
+            break;
+        case 0x03: { /* set transfer mode */
+		uint8_t val = s->nsector & 0x07;
+            uint16_t *identify_data = (uint16_t *)s->identify_data;
+
+		switch (s->nsector >> 3) {
+		case 0x00: /* pio default */
+		case 0x01: /* pio mode */
+			put_le16(identify_data + 62,0x07);
+			put_le16(identify_data + 63,0x07);
+			put_le16(identify_data + 88,0x3f);
+			break;
+                case 0x02: /* sigle word dma mode*/
+			put_le16(identify_data + 62,0x07 | (1 << (val + 8)));
+			put_le16(identify_data + 63,0x07);
+			put_le16(identify_data + 88,0x3f);
+			break;
+		case 0x04: /* mdma mode */
+			put_le16(identify_data + 62,0x07);
+			put_le16(identify_data + 63,0x07 | (1 << (val + 8)));
+			put_le16(identify_data + 88,0x3f);
+			break;
+		case 0x08: /* udma mode */
+			put_le16(identify_data + 62,0x07);
+			put_le16(identify_data + 63,0x07);
+			put_le16(identify_data + 88,0x3f | (1 << (val + 8)));
+			break;
+		default:
+			goto abort_cmd;
+		}
+            s->status = READY_STAT | SEEK_STAT;
+            ide_set_irq(s->bus);
+            break;
+	}
+        default:
+            goto abort_cmd;
+        }
+        break;
+    case WIN_FLUSH_CACHE:
+    case WIN_FLUSH_CACHE_EXT:
+        ide_flush_cache(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->bus);
+        break;
+    case WIN_SEEK:
+        if(s->drive_kind == IDE_CD)
+            goto abort_cmd;
+        /* XXX: Check that seek is within bounds */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+        /* ATAPI commands */
+    case WIN_PIDENTIFY:
+        if (s->drive_kind == IDE_CD) {
+            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->bus);
+        break;
+    case WIN_DIAGNOSE:
+        ide_set_signature(s);
+        if (s->drive_kind == IDE_CD)
+            s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
+                            * devices to return a clear status register
+                            * with READY_STAT *not* set. */
+        else
+            s->status = READY_STAT | SEEK_STAT;
+        s->error = 0x01; /* Device 0 passed, Device 1 passed or not
+                          * present.
+                          */
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SRST:
+        if (s->drive_kind != IDE_CD)
+            goto abort_cmd;
+        ide_set_signature(s);
+        s->status = 0x00; /* NOTE: READY is _not_ set */
+        s->error = 0x01;
+        break;
+    case WIN_PACKETCMD:
+        if (s->drive_kind != IDE_CD)
+            goto abort_cmd;
+        /* overlapping commands not supported */
+        if (s->feature & 0x02)
+            goto abort_cmd;
+        s->status = READY_STAT | SEEK_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->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        s->error = 0x09;    /* miscellaneous error */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case CFA_ERASE_SECTORS:
+    case CFA_WEAR_LEVEL:
+        if (s->drive_kind != IDE_CFATA)
+            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 | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case CFA_TRANSLATE_SECTOR:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        s->error = 0x00;
+        s->status = READY_STAT | SEEK_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->bus);
+        break;
+    case CFA_ACCESS_METADATA_STORAGE:
+        if (s->drive_kind != IDE_CFATA)
+            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->bus);
+        break;
+    case IBM_SENSE_CONDITION:
+        if (s->drive_kind != IDE_CFATA)
+            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 | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+
+	case WIN_SMART:
+	if (s->drive_kind == IDE_CD)
+		goto abort_cmd;
+	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
+		goto abort_cmd;
+	if (!s->smart_enabled && s->feature != SMART_ENABLE)
+		goto abort_cmd;
+	switch (s->feature) {
+	case SMART_DISABLE:
+		s->smart_enabled = 0;
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
+	case SMART_ENABLE:
+		s->smart_enabled = 1;
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
+	case SMART_ATTR_AUTOSAVE:
+		switch (s->sector) {
+		case 0x00:
+		s->smart_autosave = 0;
+		break;
+		case 0xf1:
+		s->smart_autosave = 1;
+		break;
+		default:
+		goto abort_cmd;
+		}
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
+	case SMART_STATUS:
+		if (!s->smart_errors) {
+		s->hcyl = 0xc2;
+		s->lcyl = 0x4f;
+		} else {
+		s->hcyl = 0x2c;
+		s->lcyl = 0xf4;
+		}
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
+	case SMART_READ_THRESH:
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01; /* smart struct version */
+		for (n=0; n<30; n++) {
+		if (smart_attributes[n][0] == 0)
+			break;
+		s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
+		s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
+		}
+		for (n=0; n<511; n++) /* checksum */
+		s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		s->status = READY_STAT | SEEK_STAT;
+		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+		ide_set_irq(s->bus);
+		break;
+	case SMART_READ_DATA:
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01; /* smart struct version */
+		for (n=0; n<30; n++) {
+		    if (smart_attributes[n][0] == 0) {
+			break;
+		    }
+		    int i;
+		    for(i = 0; i < 11; i++) {
+			s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];
+		    }
+		}
+		s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);
+		if (s->smart_selftest_count == 0) {
+		s->io_buffer[363] = 0;
+		} else {
+		s->io_buffer[363] =
+			s->smart_selftest_data[3 + 
+					   (s->smart_selftest_count - 1) *
+					   24];
+		}
+		s->io_buffer[364] = 0x20; 
+		s->io_buffer[365] = 0x01; 
+		/* offline data collection capacity: execute + self-test*/
+		s->io_buffer[367] = (1<<4 | 1<<3 | 1); 
+		s->io_buffer[368] = 0x03; /* smart capability (1) */
+		s->io_buffer[369] = 0x00; /* smart capability (2) */
+		s->io_buffer[370] = 0x01; /* error logging supported */
+		s->io_buffer[372] = 0x02; /* minutes for poll short test */
+		s->io_buffer[373] = 0x36; /* minutes for poll ext test */
+		s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
+
+		for (n=0; n<511; n++) 
+		s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		s->status = READY_STAT | SEEK_STAT;
+		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+		ide_set_irq(s->bus);
+		break;
+	case SMART_READ_LOG:
+		switch (s->sector) {
+		case 0x01: /* summary smart error log */
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01;
+		s->io_buffer[1] = 0x00; /* no error entries */
+		s->io_buffer[452] = s->smart_errors & 0xff;
+		s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
+
+		for (n=0; n<511; n++)
+			s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		break;
+		case 0x06: /* smart self test log */
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01;
+		if (s->smart_selftest_count == 0) {
+			s->io_buffer[508] = 0;
+		} else {
+			s->io_buffer[508] = s->smart_selftest_count;
+			for (n=2; n<506; n++) 
+			s->io_buffer[n] = s->smart_selftest_data[n];
+		}
+		for (n=0; n<511; n++)
+			s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		break;
+		default:
+		goto abort_cmd;
+		}
+		s->status = READY_STAT | SEEK_STAT;
+		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+		ide_set_irq(s->bus);
+		break;
+	case SMART_EXECUTE_OFFLINE:
+		switch (s->sector) {
+		case 0: /* off-line routine */
+		case 1: /* short self test */
+		case 2: /* extended self test */
+		s->smart_selftest_count++;
+		if(s->smart_selftest_count > 21)
+			s->smart_selftest_count = 0;
+		n = 2 + (s->smart_selftest_count - 1) * 24;
+		s->smart_selftest_data[n] = s->sector;
+		s->smart_selftest_data[n+1] = 0x00; /* OK and finished */
+		s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */
+		s->smart_selftest_data[n+3] = 0x12; /* hour count msb */
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
+		default:
+		goto abort_cmd;
+		}
+		break;
+	default:
+		goto abort_cmd;
+	}
+	break;
+    default:
+    abort_cmd:
+        ide_abort_command(s);
+        ide_set_irq(s->bus);
+        break;
+    }
+}
+
+uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    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 ((!bus->ifs[0].bs && !bus->ifs[1].bs) ||
+            (s != bus->ifs && !s->bs))
+            ret = 0;
+        else if (!hob)
+            ret = s->error;
+	else
+	    ret = s->hob_feature;
+        break;
+    case 2:
+        if (!bus->ifs[0].bs && !bus->ifs[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->nsector & 0xff;
+	else
+	    ret = s->hob_nsector;
+        break;
+    case 3:
+        if (!bus->ifs[0].bs && !bus->ifs[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->sector;
+	else
+	    ret = s->hob_sector;
+        break;
+    case 4:
+        if (!bus->ifs[0].bs && !bus->ifs[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->lcyl;
+	else
+	    ret = s->hob_lcyl;
+        break;
+    case 5:
+        if (!bus->ifs[0].bs && !bus->ifs[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->hcyl;
+	else
+	    ret = s->hob_hcyl;
+        break;
+    case 6:
+        if (!bus->ifs[0].bs && !bus->ifs[1].bs)
+            ret = 0;
+        else
+            ret = s->select;
+        break;
+    default:
+    case 7:
+        if ((!bus->ifs[0].bs && !bus->ifs[1].bs) ||
+            (s != bus->ifs && !s->bs))
+            ret = 0;
+        else
+            ret = s->status;
+        qemu_irq_lower(bus->irq);
+        break;
+    }
+#ifdef DEBUG_IDE
+    printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
+#endif
+    return ret;
+}
+
+uint32_t ide_status_read(void *opaque, uint32_t addr)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    int ret;
+
+    if ((!bus->ifs[0].bs && !bus->ifs[1].bs) ||
+        (s != bus->ifs && !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;
+}
+
+void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEBus *bus = 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 (!(bus->cmd & IDE_CMD_RESET) &&
+        (val & IDE_CMD_RESET)) {
+        /* reset low to high */
+        for(i = 0;i < 2; i++) {
+            s = &bus->ifs[i];
+            s->status = BUSY_STAT | SEEK_STAT;
+            s->error = 0x01;
+        }
+    } else if ((bus->cmd & IDE_CMD_RESET) &&
+               !(val & IDE_CMD_RESET)) {
+        /* high to low */
+        for(i = 0;i < 2; i++) {
+            s = &bus->ifs[i];
+            if (s->drive_kind == IDE_CD)
+                s->status = 0x00; /* NOTE: READY is _not_ set */
+            else
+                s->status = READY_STAT | SEEK_STAT;
+            ide_set_signature(s);
+        }
+    }
+
+    bus->cmd = val;
+}
+
+/*
+ * Returns true if the running PIO transfer is a PIO out (i.e. data is
+ * transferred from the device to the guest), false if it's a PIO in
+ */
+static bool ide_is_pio_out(IDEState *s)
+{
+    if (s->end_transfer_func == ide_sector_write ||
+        s->end_transfer_func == ide_atapi_cmd) {
+        return false;
+    } else if (s->end_transfer_func == ide_sector_read ||
+               s->end_transfer_func == ide_transfer_stop ||
+               s->end_transfer_func == ide_atapi_cmd_reply_end ||
+               s->end_transfer_func == ide_dummy_transfer_stop) {
+        return true;
+    }
+
+    abort();
+}
+
+void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    uint8_t *p;
+
+    /* PIO data access allowed only when DRQ bit is set. The result of a write
+     * during PIO out is indeterminate, just ignore it. */
+    if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
+        return;
+    }
+
+    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);
+}
+
+uint32_t ide_data_readw(void *opaque, uint32_t addr)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    uint8_t *p;
+    int ret;
+
+    /* PIO data access allowed only when DRQ bit is set. The result of a read
+     * during PIO in is indeterminate, return 0 and don't move forward. */
+    if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
+        return 0;
+    }
+
+    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;
+}
+
+void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    uint8_t *p;
+
+    /* PIO data access allowed only when DRQ bit is set. The result of a write
+     * during PIO out is indeterminate, just ignore it. */
+    if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
+        return;
+    }
+
+    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);
+}
+
+uint32_t ide_data_readl(void *opaque, uint32_t addr)
+{
+    IDEBus *bus = opaque;
+    IDEState *s = idebus_active_if(bus);
+    uint8_t *p;
+    int ret;
+
+    /* PIO data access allowed only when DRQ bit is set. The result of a read
+     * during PIO in is indeterminate, return 0 and don't move forward. */
+    if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
+        return 0;
+    }
+
+    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)
+{
+#ifdef DEBUG_IDE
+    printf("ide: reset\n");
+#endif
+    if (s->drive_kind == IDE_CFATA)
+        s->mult_sectors = 0;
+    else
+        s->mult_sectors = MAX_MULT_SECTORS;
+    /* ide regs */
+    s->feature = 0;
+    s->error = 0;
+    s->nsector = 0;
+    s->sector = 0;
+    s->lcyl = 0;
+    s->hcyl = 0;
+
+    /* lba48 */
+    s->hob_feature = 0;
+    s->hob_sector = 0;
+    s->hob_nsector = 0;
+    s->hob_lcyl = 0;
+    s->hob_hcyl = 0;
+
+    s->select = 0xa0;
+    s->status = READY_STAT | SEEK_STAT;
+
+    s->lba48 = 0;
+
+    /* ATAPI specific */
+    s->sense_key = 0;
+    s->asc = 0;
+    s->cdrom_changed = 0;
+    s->packet_transfer_size = 0;
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = 0;
+    s->cd_sector_size = 0;
+    s->atapi_dma = 0;
+    /* ATA DMA state */
+    s->io_buffer_size = 0;
+    s->req_nb_sectors = 0;
+
+    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;
+}
+
+void ide_bus_reset(IDEBus *bus)
+{
+    bus->unit = 0;
+    bus->cmd = 0;
+    ide_reset(&bus->ifs[0]);
+    ide_reset(&bus->ifs[1]);
+    ide_clear_hob(bus);
+
+    /* pending async DMA */
+    if (bus->dma->aiocb) {
+#ifdef DEBUG_AIO
+        printf("aio_cancel\n");
+#endif
+        bdrv_aio_cancel(bus->dma->aiocb);
+        bus->dma->aiocb = NULL;
+    }
+
+    /* reset dma provider too */
+    bus->dma->ops->reset(bus->dma);
+}
+
+int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
+                   const char *version, const char *serial)
+{
+    int cylinders, heads, secs;
+    uint64_t nb_sectors;
+
+    s->bs = bs;
+    s->drive_kind = kind;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+    bdrv_guess_geometry(bs, &cylinders, &heads, &secs);
+    if (cylinders < 1 || cylinders > 16383) {
+        error_report("cyls must be between 1 and 16383");
+        return -1;
+    }
+    if (heads < 1 || heads > 16) {
+        error_report("heads must be between 1 and 16");
+        return -1;
+    }
+    if (secs < 1 || secs > 63) {
+        error_report("secs must be between 1 and 63");
+        return -1;
+    }
+    s->cylinders = cylinders;
+    s->heads = heads;
+    s->sectors = secs;
+    s->nb_sectors = nb_sectors;
+    /* The SMART values should be preserved across power cycles
+       but they aren't.  */
+    s->smart_enabled = 1;
+    s->smart_autosave = 1;
+    s->smart_errors = 0;
+    s->smart_selftest_count = 0;
+    if (kind == IDE_CD) {
+        bdrv_set_change_cb(bs, cdrom_change_cb, s);
+        bs->buffer_alignment = 2048;
+    } else {
+        if (!bdrv_is_inserted(s->bs)) {
+            error_report("Device needs media, but drive is empty");
+            return -1;
+        }
+        if (bdrv_is_read_only(bs)) {
+            error_report("Can't use a read-only drive");
+            return -1;
+        }
+    }
+    if (serial) {
+        strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str));
+    } else {
+        snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
+                 "QM%05d", s->drive_serial);
+    }
+    if (version) {
+        pstrcpy(s->version, sizeof(s->version), version);
+    } else {
+        pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
+    }
+
+    ide_reset(s);
+    bdrv_set_removable(bs, s->drive_kind == IDE_CD);
+    return 0;
+}
+
+static void ide_init1(IDEBus *bus, int unit)
+{
+    static int drive_serial = 1;
+    IDEState *s = &bus->ifs[unit];
+
+    s->bus = bus;
+    s->unit = unit;
+    s->drive_serial = drive_serial++;
+    /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
+    s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
+    s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
+    memset(s->io_buffer, 0, s->io_buffer_total_len);
+
+    s->smart_selftest_data = qemu_blockalign(s->bs, 512);
+    memset(s->smart_selftest_data, 0, 512);
+
+    s->sector_write_timer = qemu_new_timer_ns(vm_clock,
+                                           ide_sector_write_timer_cb, s);
+}
+
+static void ide_nop_start(IDEDMA *dma, IDEState *s,
+                          BlockDriverCompletionFunc *cb)
+{
+}
+
+static int ide_nop(IDEDMA *dma)
+{
+    return 0;
+}
+
+static int ide_nop_int(IDEDMA *dma, int x)
+{
+    return 0;
+}
+
+static void ide_nop_restart(void *opaque, int x, int y)
+{
+}
+
+static const IDEDMAOps ide_dma_nop_ops = {
+    .start_dma      = ide_nop_start,
+    .start_transfer = ide_nop,
+    .prepare_buf    = ide_nop_int,
+    .rw_buf         = ide_nop_int,
+    .set_unit       = ide_nop_int,
+    .add_status     = ide_nop_int,
+    .set_inactive   = ide_nop,
+    .restart_cb     = ide_nop_restart,
+    .reset          = ide_nop,
+};
+
+static IDEDMA ide_dma_nop = {
+    .ops = &ide_dma_nop_ops,
+    .aiocb = NULL,
+};
+
+void ide_init2(IDEBus *bus, qemu_irq irq)
+{
+    int i;
+
+    for(i = 0; i < 2; i++) {
+        ide_init1(bus, i);
+        ide_reset(&bus->ifs[i]);
+    }
+    bus->irq = irq;
+    bus->dma = &ide_dma_nop;
+}
+
+/* TODO convert users to qdev and remove */
+void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
+                                    DriveInfo *hd1, qemu_irq irq)
+{
+    int i;
+    DriveInfo *dinfo;
+
+    for(i = 0; i < 2; i++) {
+        dinfo = i == 0 ? hd0 : hd1;
+        ide_init1(bus, i);
+        if (dinfo) {
+            if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
+                               dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
+                               *dinfo->serial ? dinfo->serial : NULL) < 0) {
+                error_report("Can't set up IDE drive %s", dinfo->id);
+                exit(1);
+            }
+        } else {
+            ide_reset(&bus->ifs[i]);
+        }
+    }
+    bus->irq = irq;
+    bus->dma = &ide_dma_nop;
+}
+
+void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
+{
+    register_ioport_write(iobase, 8, 1, ide_ioport_write, bus);
+    register_ioport_read(iobase, 8, 1, ide_ioport_read, bus);
+    if (iobase2) {
+        register_ioport_read(iobase2, 1, 1, ide_status_read, bus);
+        register_ioport_write(iobase2, 1, 1, ide_cmd_write, bus);
+    }
+
+    /* data ports */
+    register_ioport_write(iobase, 2, 2, ide_data_writew, bus);
+    register_ioport_read(iobase, 2, 2, ide_data_readw, bus);
+    register_ioport_write(iobase, 4, 4, ide_data_writel, bus);
+    register_ioport_read(iobase, 4, 4, ide_data_readl, bus);
+}
+
+static bool is_identify_set(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    return s->identify_set != 0;
+}
+
+static EndTransferFunc* transfer_end_table[] = {
+        ide_sector_read,
+        ide_sector_write,
+        ide_transfer_stop,
+        ide_atapi_cmd_reply_end,
+        ide_atapi_cmd,
+        ide_dummy_transfer_stop,
+};
+
+static int transfer_end_table_idx(EndTransferFunc *fn)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
+        if (transfer_end_table[i] == fn)
+            return i;
+
+    return -1;
+}
+
+static int ide_drive_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    if (version_id < 3) {
+        if (s->sense_key == SENSE_UNIT_ATTENTION &&
+            s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
+            s->cdrom_changed = 1;
+        }
+    }
+    return 0;
+}
+
+static int ide_drive_pio_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
+        return -EINVAL;
+    }
+    s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+    s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+    s->data_end = s->data_ptr + s->cur_io_buffer_len;
+
+    return 0;
+}
+
+static void ide_drive_pio_pre_save(void *opaque)
+{
+    IDEState *s = opaque;
+    int idx;
+
+    s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
+    s->cur_io_buffer_len = s->data_end - s->data_ptr;
+
+    idx = transfer_end_table_idx(s->end_transfer_func);
+    if (idx == -1) {
+        fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
+                        __func__);
+        s->end_transfer_fn_idx = 2;
+    } else {
+        s->end_transfer_fn_idx = idx;
+    }
+}
+
+static bool ide_drive_pio_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return ((s->status & DRQ_STAT) != 0)
+        || (s->bus->error_status & BM_STATUS_PIO_RETRY);
+}
+
+static bool ide_atapi_gesn_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->events.new_media || s->events.eject_request;
+}
+
+static bool ide_error_needed(void *opaque)
+{
+    IDEBus *bus = opaque;
+
+    return (bus->error_status != 0);
+}
+
+/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
+const VMStateDescription vmstate_ide_atapi_gesn_state = {
+    .name ="ide_drive/atapi/gesn_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_BOOL(events.new_media, IDEState),
+        VMSTATE_BOOL(events.eject_request, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_ide_drive_pio_state = {
+    .name = "ide_drive/pio_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ide_drive_pio_pre_save,
+    .post_load = ide_drive_pio_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(req_nb_sectors, IDEState),
+        VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
+			     vmstate_info_uint8, uint8_t),
+        VMSTATE_INT32(cur_io_buffer_offset, IDEState),
+        VMSTATE_INT32(cur_io_buffer_len, IDEState),
+        VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
+        VMSTATE_INT32(elementary_transfer_size, IDEState),
+        VMSTATE_INT32(packet_transfer_size, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_ide_drive = {
+    .name = "ide_drive",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ide_drive_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(mult_sectors, IDEState),
+        VMSTATE_INT32(identify_set, IDEState),
+        VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
+        VMSTATE_UINT8(feature, IDEState),
+        VMSTATE_UINT8(error, IDEState),
+        VMSTATE_UINT32(nsector, IDEState),
+        VMSTATE_UINT8(sector, IDEState),
+        VMSTATE_UINT8(lcyl, IDEState),
+        VMSTATE_UINT8(hcyl, IDEState),
+        VMSTATE_UINT8(hob_feature, IDEState),
+        VMSTATE_UINT8(hob_sector, IDEState),
+        VMSTATE_UINT8(hob_nsector, IDEState),
+        VMSTATE_UINT8(hob_lcyl, IDEState),
+        VMSTATE_UINT8(hob_hcyl, IDEState),
+        VMSTATE_UINT8(select, IDEState),
+        VMSTATE_UINT8(status, IDEState),
+        VMSTATE_UINT8(lba48, IDEState),
+        VMSTATE_UINT8(sense_key, IDEState),
+        VMSTATE_UINT8(asc, IDEState),
+        VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_drive_pio_state,
+            .needed = ide_drive_pio_state_needed,
+        }, {
+            .vmsd = &vmstate_ide_atapi_gesn_state,
+            .needed = ide_atapi_gesn_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+const VMStateDescription vmstate_ide_error_status = {
+    .name ="ide_bus/error",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32(error_status, IDEBus),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_ide_bus = {
+    .name = "ide_bus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(cmd, IDEBus),
+        VMSTATE_UINT8(unit, IDEBus),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_error_status,
+            .needed = ide_error_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+void ide_drive_get(DriveInfo **hd, int max_bus)
+{
+    int i;
+
+    if (drive_get_max_bus(IF_IDE) >= max_bus) {
+        fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus);
+        exit(1);
+    }
+
+    for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) {
+        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+    }
+}
diff --git a/qemu-0.15.x/hw/ide/ich.c b/qemu-0.15.x/hw/ide/ich.c
new file mode 100644
index 0000000..054e073
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/ich.c
@@ -0,0 +1,142 @@
+/*
+ * QEMU ICH Emulation
+ *
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt at gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * lspci dump of a ICH-9 real device
+ *
+ * 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
+ *         Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
+ *         Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
+ *         Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+ *         Latency: 0
+ *         Interrupt: pin B routed to IRQ 222
+ *         Region 0: I/O ports at d000 [size=8]
+ *         Region 1: I/O ports at cc00 [size=4]
+ *         Region 2: I/O ports at c880 [size=8]
+ *         Region 3: I/O ports at c800 [size=4]
+ *         Region 4: I/O ports at c480 [size=32]
+ *         Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
+ *         Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
+ *                 Address: fee0f00c  Data: 41d9
+ *         Capabilities: [70] Power Management version 3
+ *                 Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
+ *                 Status: D0 PME-Enable- DSel=0 DScale=0 PME-
+ *         Capabilities: [a8] SATA HBA <?>
+ *         Capabilities: [b0] Vendor Specific Information <?>
+ *         Kernel driver in use: ahci
+ *         Kernel modules: ahci
+ * 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
+ * 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
+ * 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
+ * 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
+ * 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
+ * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
+ * 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
+ * 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
+ * a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
+ * b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
+ * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
+ *
+ */
+
+#include <hw/hw.h>
+#include <hw/msi.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/pci.h>
+#include <hw/ide/ahci.h>
+
+static int pci_ich9_ahci_init(PCIDevice *dev)
+{
+    struct AHCIPCIState *d;
+    d = DO_UPCAST(struct AHCIPCIState, card, dev);
+
+    ahci_init(&d->ahci, &dev->qdev, 6);
+
+    pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
+
+    d->card.config[PCI_CACHE_LINE_SIZE] = 0x08;  /* Cache line size */
+    d->card.config[PCI_LATENCY_TIMER]   = 0x00;  /* Latency timer */
+    pci_config_set_interrupt_pin(d->card.config, 1);
+
+    /* XXX Software should program this register */
+    d->card.config[0x90]   = 1 << 6; /* Address Map Register - AHCI mode */
+
+    qemu_register_reset(ahci_reset, d);
+
+    msi_init(dev, 0x50, 1, true, false);
+    d->ahci.irq = d->card.irq[0];
+
+    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
+    pci_register_bar_simple(&d->card, 5, 0x1000, 0, d->ahci.mem);
+
+    return 0;
+}
+
+static int pci_ich9_uninit(PCIDevice *dev)
+{
+    struct AHCIPCIState *d;
+    d = DO_UPCAST(struct AHCIPCIState, card, dev);
+
+    msi_uninit(dev);
+    qemu_unregister_reset(ahci_reset, d);
+    ahci_uninit(&d->ahci);
+
+    return 0;
+}
+
+static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
+                                  uint32_t val, int len)
+{
+    pci_default_write_config(pci, addr, val, len);
+    msi_write_config(pci, addr, val, len);
+}
+
+static PCIDeviceInfo ich_ahci_info[] = {
+    {
+        .qdev.name    = "ich9-ahci",
+        .qdev.alias   = "ahci",
+        .qdev.size    = sizeof(AHCIPCIState),
+        .init         = pci_ich9_ahci_init,
+        .exit         = pci_ich9_uninit,
+        .config_write = pci_ich9_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801IR,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_STORAGE_SATA,
+    },{
+        /* end of list */
+    }
+};
+
+static void ich_ahci_register(void)
+{
+    pci_qdev_register_many(ich_ahci_info);
+}
+device_init(ich_ahci_register);
diff --git a/qemu-0.15.x/hw/ide/internal.h b/qemu-0.15.x/hw/ide/internal.h
new file mode 100644
index 0000000..02e805f
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/internal.h
@@ -0,0 +1,615 @@
+#ifndef HW_IDE_INTERNAL_H
+#define HW_IDE_INTERNAL_H
+
+/*
+ * QEMU IDE Emulation -- internal header file
+ * only files in hw/ide/ are supposed to include this file.
+ * non-internal declarations are in hw/ide.h
+ */
+#include <hw/ide.h>
+#include "block_int.h"
+#include "iorange.h"
+#include "dma.h"
+
+/* debug IDE devices */
+//#define DEBUG_IDE
+//#define DEBUG_IDE_ATAPI
+//#define DEBUG_AIO
+#define USE_DMA_CDROM
+
+typedef struct IDEBus IDEBus;
+typedef struct IDEDevice IDEDevice;
+typedef struct IDEDeviceInfo IDEDeviceInfo;
+typedef struct IDEState IDEState;
+typedef struct IDEDMA IDEDMA;
+typedef struct IDEDMAOps IDEDMAOps;
+
+/* 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->0x05 Reserved
+ */
+#define WIN_DSM                         0x06
+/*
+ *      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
+
+#define IDE_DMA_BUF_SECTORS 256
+
+/* feature values for Data Set Management */
+#define DSM_TRIM                        0x01
+
+#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
+#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
+#endif
+
+/* 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
+
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
+#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_MAY_HAVE_CHANGED          0x28
+#define ASC_INCOMPATIBLE_FORMAT              0x30
+#define ASC_MEDIUM_NOT_PRESENT               0x3a
+#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
+#define ASC_MEDIA_REMOVAL_PREVENTED          0x53
+
+#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
+
+#define SMART_READ_DATA       0xd0
+#define SMART_READ_THRESH     0xd1
+#define SMART_ATTR_AUTOSAVE   0xd2
+#define SMART_SAVE_ATTR       0xd3
+#define SMART_EXECUTE_OFFLINE 0xd4
+#define SMART_READ_LOG        0xd5
+#define SMART_WRITE_LOG       0xd6
+#define SMART_ENABLE          0xd8
+#define SMART_DISABLE         0xd9
+#define SMART_STATUS          0xda
+
+typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind;
+
+typedef void EndTransferFunc(IDEState *);
+
+typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *);
+typedef int DMAFunc(IDEDMA *);
+typedef int DMAIntFunc(IDEDMA *, int);
+typedef void DMARestartFunc(void *, int, int);
+
+struct unreported_events {
+    bool eject_request;
+    bool new_media;
+};
+
+enum ide_dma_cmd {
+    IDE_DMA_READ,
+    IDE_DMA_WRITE,
+    IDE_DMA_TRIM,
+};
+
+#define ide_cmd_is_read(s) \
+	((s)->dma_cmd == IDE_DMA_READ)
+
+/* NOTE: IDEState represents in fact one drive */
+struct IDEState {
+    IDEBus *bus;
+    uint8_t unit;
+    /* ide config */
+    IDEDriveKind drive_kind;
+    int cylinders, heads, sectors;
+    int64_t nb_sectors;
+    int mult_sectors;
+    int identify_set;
+    uint8_t identify_data[512];
+    int drive_serial;
+    char drive_serial_str[21];
+    /* 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;
+
+    /* set for lba48 access */
+    uint8_t lba48;
+    BlockDriverState *bs;
+    char version[9];
+    /* ATAPI specific */
+    struct unreported_events events;
+    uint8_t sense_key;
+    uint8_t asc;
+    uint8_t cdrom_changed;
+    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;
+    QEMUSGList sg;
+    /* PIO transfer handling */
+    int req_nb_sectors; /* number of sectors per interrupt */
+    EndTransferFunc *end_transfer_func;
+    uint8_t *data_ptr;
+    uint8_t *data_end;
+    uint8_t *io_buffer;
+    /* PIO save/restore */
+    int32_t io_buffer_total_len;
+    int cur_io_buffer_offset;
+    int cur_io_buffer_len;
+    uint8_t end_transfer_fn_idx;
+    QEMUTimer *sector_write_timer; /* only used for win2k install hack */
+    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;
+    enum ide_dma_cmd dma_cmd;
+    /* SMART */
+    uint8_t smart_enabled;
+    uint8_t smart_autosave;
+    int smart_errors;
+    uint8_t smart_selftest_count;
+    uint8_t *smart_selftest_data;
+    /* AHCI */
+    int ncq_queues;
+};
+
+struct IDEDMAOps {
+    DMAStartFunc *start_dma;
+    DMAFunc *start_transfer;
+    DMAIntFunc *prepare_buf;
+    DMAIntFunc *rw_buf;
+    DMAIntFunc *set_unit;
+    DMAIntFunc *add_status;
+    DMAFunc *set_inactive;
+    DMARestartFunc *restart_cb;
+    DMAFunc *reset;
+};
+
+struct IDEDMA {
+    const struct IDEDMAOps *ops;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    BlockDriverAIOCB *aiocb;
+};
+
+struct IDEBus {
+    BusState qbus;
+    IDEDevice *master;
+    IDEDevice *slave;
+    IDEState ifs[2];
+    int bus_id;
+    IDEDMA *dma;
+    uint8_t unit;
+    uint8_t cmd;
+    qemu_irq irq;
+
+    int error_status;
+};
+
+struct IDEDevice {
+    DeviceState qdev;
+    uint32_t unit;
+    BlockConf conf;
+    char *version;
+    char *serial;
+};
+
+typedef int (*ide_qdev_initfn)(IDEDevice *dev);
+struct IDEDeviceInfo {
+    DeviceInfo qdev;
+    ide_qdev_initfn init;
+};
+
+#define BM_STATUS_DMAING 0x01
+#define BM_STATUS_ERROR  0x02
+#define BM_STATUS_INT    0x04
+
+/* FIXME These are not status register bits */
+#define BM_STATUS_DMA_RETRY  0x08
+#define BM_STATUS_PIO_RETRY  0x10
+#define BM_STATUS_RETRY_READ  0x20
+#define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_STATUS_RETRY_TRIM 0x80
+
+#define BM_MIGRATION_COMPAT_STATUS_BITS \
+        (BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
+        BM_STATUS_RETRY_READ | BM_STATUS_RETRY_FLUSH)
+
+#define BM_CMD_START     0x01
+#define BM_CMD_READ      0x08
+
+static inline IDEState *idebus_active_if(IDEBus *bus)
+{
+    return bus->ifs + bus->unit;
+}
+
+static inline void ide_set_irq(IDEBus *bus)
+{
+    if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) {
+        qemu_irq_raise(bus->irq);
+    }
+}
+
+/* hw/ide/core.c */
+extern const VMStateDescription vmstate_ide_bus;
+
+#define VMSTATE_IDE_BUS(_field, _state)                          \
+    VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_bus, IDEBus)
+
+#define VMSTATE_IDE_BUS_ARRAY(_field, _state, _num)              \
+    VMSTATE_STRUCT_ARRAY(_field, _state, _num, 1, vmstate_ide_bus, IDEBus)
+
+extern const VMStateDescription vmstate_ide_drive;
+
+#define VMSTATE_IDE_DRIVES(_field, _state) \
+    VMSTATE_STRUCT_ARRAY(_field, _state, 2, 3, vmstate_ide_drive, IDEState)
+
+void ide_bus_reset(IDEBus *bus);
+int64_t ide_get_sector(IDEState *s);
+void ide_set_sector(IDEState *s, int64_t sector_num);
+
+void ide_dma_error(IDEState *s);
+
+void ide_atapi_cmd_ok(IDEState *s);
+void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
+void ide_atapi_io_error(IDEState *s, int ret);
+
+void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ide_ioport_read(void *opaque, uint32_t addr1);
+uint32_t ide_status_read(void *opaque, uint32_t addr);
+void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val);
+void ide_data_writew(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ide_data_readw(void *opaque, uint32_t addr);
+void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ide_data_readl(void *opaque, uint32_t addr);
+
+int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
+                   const char *version, const char *serial);
+void ide_init2(IDEBus *bus, qemu_irq irq);
+void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
+                                    DriveInfo *hd1, qemu_irq irq);
+void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
+
+void ide_exec_cmd(IDEBus *bus, uint32_t val);
+void ide_dma_cb(void *opaque, int ret);
+void ide_sector_write(IDEState *s);
+void ide_sector_read(IDEState *s);
+void ide_flush_cache(IDEState *s);
+
+void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                        EndTransferFunc *end_transfer_func);
+void ide_transfer_stop(IDEState *s);
+void ide_set_inactive(IDEState *s);
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+/* hw/ide/atapi.c */
+void ide_atapi_cmd(IDEState *s);
+void ide_atapi_cmd_reply_end(IDEState *s);
+
+/* hw/ide/qdev.c */
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
+IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
+
+#endif /* HW_IDE_INTERNAL_H */
diff --git a/qemu-0.15.x/hw/ide/isa.c b/qemu-0.15.x/hw/ide/isa.c
new file mode 100644
index 0000000..4ac7453
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/isa.c
@@ -0,0 +1,119 @@
+/*
+ * QEMU IDE Emulation: ISA Bus support.
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/internal.h>
+
+/***********************************************************/
+/* ISA IDE definitions */
+
+typedef struct ISAIDEState {
+    ISADevice dev;
+    IDEBus    bus;
+    uint32_t  iobase;
+    uint32_t  iobase2;
+    uint32_t  isairq;
+    qemu_irq  irq;
+} ISAIDEState;
+
+static void isa_ide_reset(DeviceState *d)
+{
+    ISAIDEState *s = container_of(d, ISAIDEState, dev.qdev);
+
+    ide_bus_reset(&s->bus);
+}
+
+static const VMStateDescription vmstate_ide_isa = {
+    .name = "isa-ide",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_IDE_BUS(bus, ISAIDEState),
+        VMSTATE_IDE_DRIVES(bus.ifs, ISAIDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int isa_ide_initfn(ISADevice *dev)
+{
+    ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
+
+    ide_bus_new(&s->bus, &s->dev.qdev, 0);
+    ide_init_ioport(&s->bus, s->iobase, s->iobase2);
+    isa_init_irq(dev, &s->irq, s->isairq);
+    isa_init_ioport_range(dev, s->iobase, 8);
+    isa_init_ioport(dev, s->iobase2);
+    ide_init2(&s->bus, s->irq);
+    vmstate_register(&dev->qdev, 0, &vmstate_ide_isa, s);
+    return 0;
+};
+
+ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
+                        DriveInfo *hd0, DriveInfo *hd1)
+{
+    ISADevice *dev;
+    ISAIDEState *s;
+
+    dev = isa_create("isa-ide");
+    qdev_prop_set_uint32(&dev->qdev, "iobase",  iobase);
+    qdev_prop_set_uint32(&dev->qdev, "iobase2", iobase2);
+    qdev_prop_set_uint32(&dev->qdev, "irq",     isairq);
+    if (qdev_init(&dev->qdev) < 0)
+        return NULL;
+
+    s = DO_UPCAST(ISAIDEState, dev, dev);
+    if (hd0)
+        ide_create_drive(&s->bus, 0, hd0);
+    if (hd1)
+        ide_create_drive(&s->bus, 1, hd1);
+    return dev;
+}
+
+static ISADeviceInfo isa_ide_info = {
+    .qdev.name  = "isa-ide",
+    .qdev.fw_name  = "ide",
+    .qdev.size  = sizeof(ISAIDEState),
+    .init       = isa_ide_initfn,
+    .qdev.reset = isa_ide_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase",  ISAIDEState, iobase,  0x1f0),
+        DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
+        DEFINE_PROP_UINT32("irq",    ISAIDEState, isairq,  14),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void isa_ide_register_devices(void)
+{
+    isa_qdev_register(&isa_ide_info);
+}
+
+device_init(isa_ide_register_devices)
diff --git a/qemu-0.15.x/hw/ide/macio.c b/qemu-0.15.x/hw/ide/macio.c
new file mode 100644
index 0000000..7daeb31
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/macio.c
@@ -0,0 +1,337 @@
+/*
+ * QEMU IDE Emulation: MacIO support.
+ *
+ * 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 <hw/hw.h>
+#include <hw/ppc_mac.h>
+#include <hw/mac_dbdma.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/internal.h>
+
+/***********************************************************/
+/* MacIO based PowerPC IDE */
+
+typedef struct MACIOIDEState {
+    IDEBus bus;
+    BlockDriverAIOCB *aiocb;
+} MACIOIDEState;
+
+#define MACIO_PAGE_SIZE 4096
+
+static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
+{
+    DBDMA_io *io = opaque;
+    MACIOIDEState *m = io->opaque;
+    IDEState *s = idebus_active_if(&m->bus);
+
+    if (ret < 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
+        ide_atapi_io_error(s, ret);
+        io->dma_end(opaque);
+        return;
+    }
+
+    if (s->io_buffer_size > 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
+
+        s->packet_transfer_size -= s->io_buffer_size;
+
+        s->io_buffer_index += s->io_buffer_size;
+	s->lba += s->io_buffer_index >> 11;
+        s->io_buffer_index &= 0x7ff;
+    }
+
+    if (s->packet_transfer_size <= 0)
+        ide_atapi_cmd_ok(s);
+
+    if (io->len == 0) {
+        io->dma_end(opaque);
+        return;
+    }
+
+    /* launch next transfer */
+
+    s->io_buffer_size = io->len;
+
+    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
+    qemu_sglist_add(&s->sg, io->addr, io->len);
+    io->addr += io->len;
+    io->len = 0;
+
+    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
+                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
+                             pmac_ide_atapi_transfer_cb, io);
+    if (!m->aiocb) {
+        qemu_sglist_destroy(&s->sg);
+        /* Note: media not present is the most likely case */
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+        io->dma_end(opaque);
+        return;
+    }
+}
+
+static void pmac_ide_transfer_cb(void *opaque, int ret)
+{
+    DBDMA_io *io = opaque;
+    MACIOIDEState *m = io->opaque;
+    IDEState *s = idebus_active_if(&m->bus);
+    int n;
+    int64_t sector_num;
+
+    if (ret < 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
+	ide_dma_error(s);
+        io->dma_end(io);
+        return;
+    }
+
+    sector_num = ide_get_sector(s);
+    if (s->io_buffer_size > 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
+        n = (s->io_buffer_size + 0x1ff) >> 9;
+        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->bus);
+    }
+
+    /* end of DMA ? */
+
+    if (io->len == 0) {
+        io->dma_end(io);
+	return;
+    }
+
+    /* launch next transfer */
+
+    s->io_buffer_index = 0;
+    s->io_buffer_size = io->len;
+
+    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
+    qemu_sglist_add(&s->sg, io->addr, io->len);
+    io->addr += io->len;
+    io->len = 0;
+
+    switch (s->dma_cmd) {
+    case IDE_DMA_READ:
+        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
+		                 pmac_ide_transfer_cb, io);
+        break;
+    case IDE_DMA_WRITE:
+        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
+		                  pmac_ide_transfer_cb, io);
+        break;
+    case IDE_DMA_TRIM:
+        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+                               ide_issue_trim, pmac_ide_transfer_cb, s, 1);
+        break;
+    }
+
+    if (!m->aiocb)
+        pmac_ide_transfer_cb(io, -1);
+}
+
+static void pmac_ide_transfer(DBDMA_io *io)
+{
+    MACIOIDEState *m = io->opaque;
+    IDEState *s = idebus_active_if(&m->bus);
+
+    s->io_buffer_size = 0;
+    if (s->drive_kind == IDE_CD) {
+        pmac_ide_atapi_transfer_cb(io, 0);
+        return;
+    }
+
+    pmac_ide_transfer_cb(io, 0);
+}
+
+static void pmac_ide_flush(DBDMA_io *io)
+{
+    MACIOIDEState *m = io->opaque;
+
+    if (m->aiocb)
+        qemu_aio_flush();
+}
+
+/* PowerMac IDE memory IO */
+static void pmac_ide_writeb (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    switch (addr) {
+    case 1 ... 7:
+        ide_ioport_write(&d->bus, addr, val);
+        break;
+    case 8:
+    case 22:
+        ide_cmd_write(&d->bus, 0, val);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
+{
+    uint8_t retval;
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    switch (addr) {
+    case 1 ... 7:
+        retval = ide_ioport_read(&d->bus, addr);
+        break;
+    case 8:
+    case 22:
+        retval = ide_status_read(&d->bus, 0);
+        break;
+    default:
+        retval = 0xFF;
+        break;
+    }
+    return retval;
+}
+
+static void pmac_ide_writew (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    val = bswap16(val);
+    if (addr == 0) {
+        ide_data_writew(&d->bus, 0, val);
+    }
+}
+
+static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
+{
+    uint16_t retval;
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    if (addr == 0) {
+        retval = ide_data_readw(&d->bus, 0);
+    } else {
+        retval = 0xFFFF;
+    }
+    retval = bswap16(retval);
+    return retval;
+}
+
+static void pmac_ide_writel (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    val = bswap32(val);
+    if (addr == 0) {
+        ide_data_writel(&d->bus, 0, val);
+    }
+}
+
+static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
+{
+    uint32_t retval;
+    MACIOIDEState *d = opaque;
+
+    addr = (addr & 0xFFF) >> 4;
+    if (addr == 0) {
+        retval = ide_data_readl(&d->bus, 0);
+    } else {
+        retval = 0xFFFFFFFF;
+    }
+    retval = bswap32(retval);
+    return retval;
+}
+
+static CPUWriteMemoryFunc * const pmac_ide_write[] = {
+    pmac_ide_writeb,
+    pmac_ide_writew,
+    pmac_ide_writel,
+};
+
+static CPUReadMemoryFunc * const pmac_ide_read[] = {
+    pmac_ide_readb,
+    pmac_ide_readw,
+    pmac_ide_readl,
+};
+
+static const VMStateDescription vmstate_pmac = {
+    .name = "ide",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_IDE_BUS(bus, MACIOIDEState),
+        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pmac_ide_reset(void *opaque)
+{
+    MACIOIDEState *d = opaque;
+
+    ide_bus_reset(&d->bus);
+}
+
+/* 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 (DriveInfo **hd_table, qemu_irq irq,
+		   void *dbdma, int channel, qemu_irq dma_irq)
+{
+    MACIOIDEState *d;
+    int pmac_ide_memory;
+
+    d = qemu_mallocz(sizeof(MACIOIDEState));
+    ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
+
+    if (dbdma)
+        DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
+
+    pmac_ide_memory = cpu_register_io_memory(pmac_ide_read,
+                                             pmac_ide_write, d,
+                                             DEVICE_NATIVE_ENDIAN);
+    vmstate_register(NULL, 0, &vmstate_pmac, d);
+    qemu_register_reset(pmac_ide_reset, d);
+
+    return pmac_ide_memory;
+}
diff --git a/qemu-0.15.x/hw/ide/microdrive.c b/qemu-0.15.x/hw/ide/microdrive.c
new file mode 100644
index 0000000..9fbbf0e
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/microdrive.c
@@ -0,0 +1,550 @@
+/*
+ * QEMU IDE Emulation: microdrive (CF / PCMCIA)
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pcmcia.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/internal.h>
+
+/***********************************************************/
+/* CF-ATA Microdrive */
+
+#define METADATA_SIZE	0x20
+
+/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface.  */
+typedef struct {
+    IDEBus bus;
+    PCMCIACardState 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;
+    uint8_t cycle;
+} MicroDriveState;
+
+/* 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(MicroDriveState *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)
+{
+    MicroDriveState *s = opaque;
+    if (level)
+        s->stat |= STAT_INT;
+    else
+        s->stat &= ~STAT_INT;
+
+    md_interrupt_update(s);
+}
+
+static void md_reset(MicroDriveState *s)
+{
+    s->opt = OPT_MODE_MMAP;
+    s->stat = 0;
+    s->pins = 0;
+    s->cycle = 0;
+    s->ctrl = 0;
+    ide_bus_reset(&s->bus);
+}
+
+static uint8_t md_attr_read(void *opaque, uint32_t at)
+{
+    MicroDriveState *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)
+{
+    MicroDriveState *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)
+{
+    MicroDriveState *s = opaque;
+    IDEState *ifs;
+    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->bus, 0);
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ret = s->io >> 8;
+        else {
+            s->io = ide_data_readw(&s->bus, 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->bus, 0x1);
+    case 0xe:	/* Alternate Status */
+        ifs = idebus_active_if(&s->bus);
+        if (ifs->bs)
+            return ifs->status;
+        else
+            return 0;
+    case 0xf:	/* Device Address */
+        ifs = idebus_active_if(&s->bus);
+        return 0xc2 | ((~ifs->select << 2) & 0x3c);
+    default:
+        return ide_ioport_read(&s->bus, at);
+    }
+
+    return 0;
+}
+
+static void md_common_write(void *opaque, uint32_t at, uint16_t value)
+{
+    MicroDriveState *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->bus, 0, value);
+        break;
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ide_data_writew(&s->bus, 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->bus, 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->bus, at, value);
+    }
+}
+
+static const VMStateDescription vmstate_microdrive = {
+    .name = "microdrive",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(opt, MicroDriveState),
+        VMSTATE_UINT8(stat, MicroDriveState),
+        VMSTATE_UINT8(pins, MicroDriveState),
+        VMSTATE_UINT8(ctrl, MicroDriveState),
+        VMSTATE_UINT16(io, MicroDriveState),
+        VMSTATE_UINT8(cycle, MicroDriveState),
+        VMSTATE_IDE_BUS(bus, MicroDriveState),
+        VMSTATE_IDE_DRIVES(bus.ifs, MicroDriveState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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)
+{
+    MicroDriveState *md = 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)
+{
+    MicroDriveState *md = opaque;
+    md_reset(md);
+    return 0;
+}
+
+PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv)
+{
+    MicroDriveState *md = (MicroDriveState *) qemu_mallocz(sizeof(MicroDriveState));
+    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_with_non_qdev_drives(&md->bus, bdrv, NULL,
+                                   qemu_allocate_irqs(md_set_irq, md, 1)[0]);
+    md->bus.ifs[0].drive_kind = IDE_CFATA;
+    md->bus.ifs[0].mdata_size = METADATA_SIZE;
+    md->bus.ifs[0].mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
+
+    vmstate_register(NULL, -1, &vmstate_microdrive, md);
+
+    return &md->card;
+}
diff --git a/qemu-0.15.x/hw/ide/mmio.c b/qemu-0.15.x/hw/ide/mmio.c
new file mode 100644
index 0000000..10f6f40
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/mmio.c
@@ -0,0 +1,140 @@
+/*
+ * QEMU IDE Emulation: mmio support (for embedded).
+ *
+ * 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 <hw/hw.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/internal.h>
+
+/***********************************************************/
+/* MMIO based ide port
+ * This emulates IDE device connected directly to the CPU bus without
+ * dedicated ide controller, which is often seen on embedded boards.
+ */
+
+typedef struct {
+    IDEBus bus;
+    int shift;
+} MMIOState;
+
+static void mmio_ide_reset(void *opaque)
+{
+    MMIOState *s = opaque;
+
+    ide_bus_reset(&s->bus);
+}
+
+static uint32_t mmio_ide_read (void *opaque, target_phys_addr_t addr)
+{
+    MMIOState *s = opaque;
+    addr >>= s->shift;
+    if (addr & 7)
+        return ide_ioport_read(&s->bus, addr);
+    else
+        return ide_data_readw(&s->bus, 0);
+}
+
+static void mmio_ide_write (void *opaque, target_phys_addr_t addr,
+	uint32_t val)
+{
+    MMIOState *s = opaque;
+    addr >>= s->shift;
+    if (addr & 7)
+        ide_ioport_write(&s->bus, addr, val);
+    else
+        ide_data_writew(&s->bus, 0, val);
+}
+
+static CPUReadMemoryFunc * const mmio_ide_reads[] = {
+    mmio_ide_read,
+    mmio_ide_read,
+    mmio_ide_read,
+};
+
+static CPUWriteMemoryFunc * const mmio_ide_writes[] = {
+    mmio_ide_write,
+    mmio_ide_write,
+    mmio_ide_write,
+};
+
+static uint32_t mmio_ide_status_read (void *opaque, target_phys_addr_t addr)
+{
+    MMIOState *s= opaque;
+    return ide_status_read(&s->bus, 0);
+}
+
+static void mmio_ide_cmd_write (void *opaque, target_phys_addr_t addr,
+	uint32_t val)
+{
+    MMIOState *s = opaque;
+    ide_cmd_write(&s->bus, 0, val);
+}
+
+static CPUReadMemoryFunc * const mmio_ide_status[] = {
+    mmio_ide_status_read,
+    mmio_ide_status_read,
+    mmio_ide_status_read,
+};
+
+static CPUWriteMemoryFunc * const mmio_ide_cmd[] = {
+    mmio_ide_cmd_write,
+    mmio_ide_cmd_write,
+    mmio_ide_cmd_write,
+};
+
+static const VMStateDescription vmstate_ide_mmio = {
+    .name = "mmio-ide",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_IDE_BUS(bus, MMIOState),
+        VMSTATE_IDE_DRIVES(bus.ifs, MMIOState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
+                    qemu_irq irq, int shift,
+                    DriveInfo *hd0, DriveInfo *hd1)
+{
+    MMIOState *s = qemu_mallocz(sizeof(MMIOState));
+    int mem1, mem2;
+
+    ide_init2_with_non_qdev_drives(&s->bus, hd0, hd1, irq);
+
+    s->shift = shift;
+
+    mem1 = cpu_register_io_memory(mmio_ide_reads, mmio_ide_writes, s,
+                                  DEVICE_NATIVE_ENDIAN);
+    mem2 = cpu_register_io_memory(mmio_ide_status, mmio_ide_cmd, s,
+                                  DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(membase, 16 << shift, mem1);
+    cpu_register_physical_memory(membase2, 2 << shift, mem2);
+    vmstate_register(NULL, 0, &vmstate_ide_mmio, s);
+    qemu_register_reset(mmio_ide_reset, s);
+}
+
diff --git a/qemu-0.15.x/hw/ide/pci.c b/qemu-0.15.x/hw/ide/pci.c
new file mode 100644
index 0000000..9f3050a
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/pci.c
@@ -0,0 +1,530 @@
+/*
+ * QEMU IDE Emulation: PCI Bus support.
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "dma.h"
+
+#include <hw/ide/pci.h>
+
+#define BMDMA_PAGE_SIZE 4096
+
+static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
+                            BlockDriverCompletionFunc *dma_cb)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    bm->unit = s->unit;
+    bm->dma_cb = dma_cb;
+    bm->cur_prd_last = 0;
+    bm->cur_prd_addr = 0;
+    bm->cur_prd_len = 0;
+    bm->sector_num = ide_get_sector(s);
+    bm->nsector = s->nsector;
+
+    if (bm->status & BM_STATUS_DMAING) {
+        bm->dma_cb(bmdma_active_if(bm), 0);
+    }
+}
+
+/* return 0 if buffer completed */
+static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    IDEState *s = bmdma_active_if(bm);
+    struct {
+        uint32_t addr;
+        uint32_t size;
+    } prd;
+    int l, len;
+
+    qemu_sglist_init(&s->sg, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1);
+    s->io_buffer_size = 0;
+    for(;;) {
+        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) >= BMDMA_PAGE_SIZE)
+                return s->io_buffer_size != 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);
+        }
+        l = bm->cur_prd_len;
+        if (l > 0) {
+            qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
+            bm->cur_prd_addr += l;
+            bm->cur_prd_len -= l;
+            s->io_buffer_size += l;
+        }
+    }
+    return 1;
+}
+
+/* return 0 if buffer completed */
+static int bmdma_rw_buf(IDEDMA *dma, int is_write)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    IDEState *s = bmdma_active_if(bm);
+    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) >= BMDMA_PAGE_SIZE)
+                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;
+}
+
+static int bmdma_set_unit(IDEDMA *dma, int unit)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    bm->unit = unit;
+
+    return 0;
+}
+
+static int bmdma_add_status(IDEDMA *dma, int status)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    bm->status |= status;
+
+    return 0;
+}
+
+static int bmdma_set_inactive(IDEDMA *dma)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    bm->status &= ~BM_STATUS_DMAING;
+    bm->dma_cb = NULL;
+    bm->unit = -1;
+
+    return 0;
+}
+
+static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
+{
+    IDEState *s = bmdma_active_if(bm);
+
+    ide_set_sector(s, bm->sector_num);
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    s->nsector = bm->nsector;
+    s->dma_cmd = dma_cmd;
+    bm->cur_addr = bm->addr;
+    bm->dma_cb = ide_dma_cb;
+    bmdma_start_dma(&bm->dma, s, bm->dma_cb);
+}
+
+/* TODO This should be common IDE code */
+static void bmdma_restart_bh(void *opaque)
+{
+    BMDMAState *bm = opaque;
+    IDEBus *bus = bm->bus;
+    int is_read;
+    int error_status;
+
+    qemu_bh_delete(bm->bh);
+    bm->bh = NULL;
+
+    if (bm->unit == (uint8_t) -1) {
+        return;
+    }
+
+    is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
+
+    /* The error status must be cleared before resubmitting the request: The
+     * request may fail again, and this case can only be distinguished if the
+     * called function can set a new error status. */
+    error_status = bus->error_status;
+    bus->error_status = 0;
+
+    if (error_status & BM_STATUS_DMA_RETRY) {
+        if (error_status & BM_STATUS_RETRY_TRIM) {
+            bmdma_restart_dma(bm, IDE_DMA_TRIM);
+        } else {
+            bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+        }
+    } else if (error_status & BM_STATUS_PIO_RETRY) {
+        if (is_read) {
+            ide_sector_read(bmdma_active_if(bm));
+        } else {
+            ide_sector_write(bmdma_active_if(bm));
+        }
+    } else if (error_status & BM_STATUS_RETRY_FLUSH) {
+        ide_flush_cache(bmdma_active_if(bm));
+    }
+}
+
+static void bmdma_restart_cb(void *opaque, int running, int reason)
+{
+    IDEDMA *dma = opaque;
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    if (!running)
+        return;
+
+    if (!bm->bh) {
+        bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma);
+        qemu_bh_schedule(bm->bh);
+    }
+}
+
+static void bmdma_cancel(BMDMAState *bm)
+{
+    if (bm->status & BM_STATUS_DMAING) {
+        /* cancel DMA request */
+        bmdma_set_inactive(&bm->dma);
+    }
+}
+
+static int bmdma_reset(IDEDMA *dma)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+#ifdef DEBUG_IDE
+    printf("ide: dma_reset\n");
+#endif
+    bmdma_cancel(bm);
+    bm->cmd = 0;
+    bm->status = 0;
+    bm->addr = 0;
+    bm->cur_addr = 0;
+    bm->cur_prd_last = 0;
+    bm->cur_prd_addr = 0;
+    bm->cur_prd_len = 0;
+    bm->sector_num = 0;
+    bm->nsector = 0;
+
+    return 0;
+}
+
+static int bmdma_start_transfer(IDEDMA *dma)
+{
+    return 0;
+}
+
+static void bmdma_irq(void *opaque, int n, int level)
+{
+    BMDMAState *bm = opaque;
+
+    if (!level) {
+        /* pass through lower */
+        qemu_set_irq(bm->irq, level);
+        return;
+    }
+
+    bm->status |= BM_STATUS_INT;
+
+    /* trigger the real irq */
+    qemu_set_irq(bm->irq, level);
+}
+
+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
+
+    /* Ignore writes to SSBM if it keeps the old value */
+    if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
+        if (!(val & BM_CMD_START)) {
+            /*
+             * We can't cancel Scatter Gather DMA in the middle of the
+             * operation or a partial (not full) DMA transfer would reach
+             * the storage so we wait for completion instead (we beahve
+             * like if the DMA was completed by the time the guest trying
+             * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
+             * set).
+             *
+             * In the future we'll be able to safely cancel the I/O if the
+             * whole DMA operation will be submitted to disk with a single
+             * aio operation with preadv/pwritev.
+             */
+            if (bm->bus->dma->aiocb) {
+                qemu_aio_flush();
+                assert(bm->bus->dma->aiocb == NULL);
+                assert((bm->status & BM_STATUS_DMAING) == 0);
+            }
+        } else {
+            bm->cur_addr = bm->addr;
+            if (!(bm->status & BM_STATUS_DMAING)) {
+                bm->status |= BM_STATUS_DMAING;
+                /* start dma transfer if possible */
+                if (bm->dma_cb)
+                    bm->dma_cb(bmdma_active_if(bm), 0);
+            }
+        }
+    }
+
+    bm->cmd = val & 0x09;
+}
+
+static void bmdma_addr_read(IORange *ioport, uint64_t addr,
+                            unsigned width, uint64_t *data)
+{
+    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    uint32_t mask = (1ULL << (width * 8)) - 1;
+
+    *data = (bm->addr >> (addr * 8)) & mask;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, (unsigned)*data);
+#endif
+}
+
+static void bmdma_addr_write(IORange *ioport, uint64_t addr,
+                             unsigned width, uint64_t data)
+{
+    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    int shift = addr * 8;
+    uint32_t mask = (1ULL << (width * 8)) - 1;
+
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, (unsigned)data);
+#endif
+    bm->addr &= ~(mask << shift);
+    bm->addr |= ((data & mask) << shift) & ~3;
+}
+
+const IORangeOps bmdma_addr_ioport_ops = {
+    .read = bmdma_addr_read,
+    .write = bmdma_addr_write,
+};
+
+static bool ide_bmdma_current_needed(void *opaque)
+{
+    BMDMAState *bm = opaque;
+
+    return (bm->cur_prd_len != 0);
+}
+
+static bool ide_bmdma_status_needed(void *opaque)
+{
+    BMDMAState *bm = opaque;
+
+    /* Older versions abused some bits in the status register for internal
+     * error state. If any of these bits are set, we must add a subsection to
+     * transfer the real status register */
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    return ((bm->status & abused_bits) != 0);
+}
+
+static void ide_bmdma_pre_save(void *opaque)
+{
+    BMDMAState *bm = opaque;
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    bm->migration_compat_status =
+        (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
+}
+
+/* This function accesses bm->bus->error_status which is loaded only after
+ * BMDMA itself. This is why the function is called from ide_pci_post_load
+ * instead of being registered with VMState where it would run too early. */
+static int ide_bmdma_post_load(void *opaque, int version_id)
+{
+    BMDMAState *bm = opaque;
+    uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+    if (bm->status == 0) {
+        bm->status = bm->migration_compat_status & ~abused_bits;
+        bm->bus->error_status |= bm->migration_compat_status & abused_bits;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_bmdma_current = {
+    .name = "ide bmdma_current",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(cur_addr, BMDMAState),
+        VMSTATE_UINT32(cur_prd_last, BMDMAState),
+        VMSTATE_UINT32(cur_prd_addr, BMDMAState),
+        VMSTATE_UINT32(cur_prd_len, BMDMAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_bmdma_status = {
+    .name ="ide bmdma/status",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(status, BMDMAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_bmdma = {
+    .name = "ide bmdma",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save  = ide_bmdma_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(cmd, BMDMAState),
+        VMSTATE_UINT8(migration_compat_status, BMDMAState),
+        VMSTATE_UINT32(addr, BMDMAState),
+        VMSTATE_INT64(sector_num, BMDMAState),
+        VMSTATE_UINT32(nsector, BMDMAState),
+        VMSTATE_UINT8(unit, BMDMAState),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_bmdma_current,
+            .needed = ide_bmdma_current_needed,
+        }, {
+            .vmsd = &vmstate_bmdma_status,
+            .needed = ide_bmdma_status_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+static int ide_pci_post_load(void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for(i = 0; i < 2; i++) {
+        /* current versions always store 0/1, but older version
+           stored bigger values. We only need last bit */
+        d->bmdma[i].unit &= 1;
+        ide_bmdma_post_load(&d->bmdma[i], -1);
+    }
+
+    return 0;
+}
+
+const VMStateDescription vmstate_ide_pci = {
+    .name = "ide",
+    .version_id = 3,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ide_pci_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIIDEState),
+        VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0,
+                             vmstate_bmdma, BMDMAState),
+        VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2),
+        VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState),
+        VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    static const int bus[4]  = { 0, 0, 1, 1 };
+    static const int unit[4] = { 0, 1, 0, 1 };
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        if (hd_table[i] == NULL)
+            continue;
+        ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]);
+    }
+}
+
+static const struct IDEDMAOps bmdma_ops = {
+    .start_dma = bmdma_start_dma,
+    .start_transfer = bmdma_start_transfer,
+    .prepare_buf = bmdma_prepare_buf,
+    .rw_buf = bmdma_rw_buf,
+    .set_unit = bmdma_set_unit,
+    .add_status = bmdma_add_status,
+    .set_inactive = bmdma_set_inactive,
+    .restart_cb = bmdma_restart_cb,
+    .reset = bmdma_reset,
+};
+
+void bmdma_init(IDEBus *bus, BMDMAState *bm)
+{
+    qemu_irq *irq;
+
+    if (bus->dma == &bm->dma) {
+        return;
+    }
+
+    bm->dma.ops = &bmdma_ops;
+    bus->dma = &bm->dma;
+    bm->irq = bus->irq;
+    irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
+    bus->irq = *irq;
+}
diff --git a/qemu-0.15.x/hw/ide/pci.h b/qemu-0.15.x/hw/ide/pci.h
new file mode 100644
index 0000000..b4f3691
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/pci.h
@@ -0,0 +1,52 @@
+#ifndef HW_IDE_PCI_H
+#define HW_IDE_PCI_H
+
+#include <hw/ide/internal.h>
+
+typedef struct BMDMAState {
+    IDEDMA dma;
+    uint8_t cmd;
+    uint8_t status;
+    uint32_t addr;
+
+    IDEBus *bus;
+    /* current transfer state */
+    uint32_t cur_addr;
+    uint32_t cur_prd_last;
+    uint32_t cur_prd_addr;
+    uint32_t cur_prd_len;
+    uint8_t unit;
+    BlockDriverCompletionFunc *dma_cb;
+    int64_t sector_num;
+    uint32_t nsector;
+    IORange addr_ioport;
+    QEMUBH *bh;
+    qemu_irq irq;
+
+    /* Bit 0-2 and 7:   BM status register
+     * Bit 3-6:         bus->error_status */
+    uint8_t migration_compat_status;
+} BMDMAState;
+
+typedef struct PCIIDEState {
+    PCIDevice dev;
+    IDEBus bus[2];
+    BMDMAState bmdma[2];
+    uint32_t secondary; /* used only for cmd646 */
+} PCIIDEState;
+
+
+static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
+{
+    assert(bmdma->unit != (uint8_t)-1);
+    return bmdma->bus->ifs + bmdma->unit;
+}
+
+
+void bmdma_init(IDEBus *bus, BMDMAState *bm);
+void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
+extern const IORangeOps bmdma_addr_ioport_ops;
+void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
+
+extern const VMStateDescription vmstate_ide_pci;
+#endif
diff --git a/qemu-0.15.x/hw/ide/piix.c b/qemu-0.15.x/hw/ide/piix.c
new file mode 100644
index 0000000..84f72b0
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/piix.c
@@ -0,0 +1,202 @@
+/*
+ * QEMU IDE Emulation: PCI PIIX3/4 support.
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "sysemu.h"
+#include "dma.h"
+
+#include <hw/ide/pci.h>
+
+static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    uint32_t val;
+
+    switch(addr & 3) {
+    case 0:
+        val = bm->cmd;
+        break;
+    case 2:
+        val = bm->status;
+        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;
+#ifdef DEBUG_IDE
+    printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    switch(addr & 3) {
+    case 2:
+        bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
+        break;
+    }
+}
+
+static void bmdma_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    int i;
+
+    for(i = 0;i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        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);
+
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
+        addr += 8;
+    }
+}
+
+static void piix3_reset(void *opaque)
+{
+    PCIIDEState *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_reset(&d->bus[i]);
+    }
+
+    /* TODO: this is the default. do not override. */
+    pci_conf[PCI_COMMAND] = 0x00;
+    /* TODO: this is the default. do not override. */
+    pci_conf[PCI_COMMAND + 1] = 0x00;
+    /* TODO: use pci_set_word */
+    pci_conf[PCI_STATUS] = PCI_STATUS_FAST_BACK;
+    pci_conf[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
+    pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
+}
+
+static void pci_piix_init_ports(PCIIDEState *d) {
+    int i;
+    struct {
+        int iobase;
+        int iobase2;
+        int isairq;
+    } port_info[] = {
+        {0x1f0, 0x3f6, 14},
+        {0x170, 0x376, 15},
+    };
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
+
+        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        d->bmdma[i].bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i].dma);
+    }
+}
+
+static int pci_piix_ide_initfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    uint8_t *pci_conf = d->dev.config;
+
+    pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
+
+    qemu_register_reset(piix3_reset, d);
+
+    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+
+    vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
+
+    pci_piix_init_ports(d);
+
+    return 0;
+}
+
+/* hd_table must contain 4 block drivers */
+/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
+PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create_simple(bus, devfn, "piix3-ide");
+    pci_ide_create_devs(dev, hd_table);
+    return dev;
+}
+
+/* hd_table must contain 4 block drivers */
+/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
+PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create_simple(bus, devfn, "piix4-ide");
+    pci_ide_create_devs(dev, hd_table);
+    return dev;
+}
+
+static PCIDeviceInfo piix_ide_info[] = {
+    {
+        .qdev.name    = "piix3-ide",
+        .qdev.size    = sizeof(PCIIDEState),
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = pci_piix_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
+    },{
+        .qdev.name    = "piix4-ide",
+        .qdev.size    = sizeof(PCIIDEState),
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = pci_piix_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
+    },{
+        /* end of list */
+    }
+};
+
+static void piix_ide_register(void)
+{
+    pci_qdev_register_many(piix_ide_info);
+}
+device_init(piix_ide_register);
diff --git a/qemu-0.15.x/hw/ide/qdev.c b/qemu-0.15.x/hw/ide/qdev.c
new file mode 100644
index 0000000..6bd8d20
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/qdev.c
@@ -0,0 +1,227 @@
+/*
+ * ide bus support for qdev.
+ *
+ * Copyright (c) 2009 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <hw/hw.h>
+#include "dma.h"
+#include "qemu-error.h"
+#include <hw/ide/internal.h>
+#include "blockdev.h"
+#include "sysemu.h"
+
+/* --------------------------------- */
+
+static char *idebus_get_fw_dev_path(DeviceState *dev);
+
+static struct BusInfo ide_bus_info = {
+    .name  = "IDE",
+    .size  = sizeof(IDEBus),
+    .get_fw_dev_path = idebus_get_fw_dev_path,
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
+{
+    qbus_create_inplace(&idebus->qbus, &ide_bus_info, dev, NULL);
+    idebus->bus_id = bus_id;
+}
+
+static char *idebus_get_fw_dev_path(DeviceState *dev)
+{
+    char path[30];
+
+    snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev),
+             ((IDEBus*)dev->parent_bus)->bus_id);
+
+    return strdup(path);
+}
+
+static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev);
+    IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base);
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
+
+    if (!dev->conf.bs) {
+        error_report("No drive specified");
+        goto err;
+    }
+    if (dev->unit == -1) {
+        dev->unit = bus->master ? 1 : 0;
+    }
+    switch (dev->unit) {
+    case 0:
+        if (bus->master) {
+            error_report("IDE unit %d is in use", dev->unit);
+            goto err;
+        }
+        bus->master = dev;
+        break;
+    case 1:
+        if (bus->slave) {
+            error_report("IDE unit %d is in use", dev->unit);
+            goto err;
+        }
+        bus->slave = dev;
+        break;
+    default:
+        error_report("Invalid IDE unit %d", dev->unit);
+        goto err;
+    }
+    return info->init(dev);
+
+err:
+    return -1;
+}
+
+static void ide_qdev_register(IDEDeviceInfo *info)
+{
+    info->qdev.init = ide_qdev_init;
+    info->qdev.bus_info = &ide_bus_info;
+    qdev_register(&info->qdev);
+}
+
+IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
+    qdev_prop_set_uint32(dev, "unit", unit);
+    qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
+    qdev_init_nofail(dev);
+    return DO_UPCAST(IDEDevice, qdev, dev);
+}
+
+void ide_get_bs(BlockDriverState *bs[], BusState *qbus)
+{
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qbus);
+    bs[0] = bus->master ? bus->master->conf.bs : NULL;
+    bs[1] = bus->slave  ? bus->slave->conf.bs  : NULL;
+}
+
+/* --------------------------------- */
+
+typedef struct IDEDrive {
+    IDEDevice dev;
+} IDEDrive;
+
+static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
+{
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
+    IDEState *s = bus->ifs + dev->unit;
+    const char *serial;
+    DriveInfo *dinfo;
+
+    if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
+        error_report("discard_granularity must be 512 for ide");
+        return -1;
+    }
+
+    serial = dev->serial;
+    if (!serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(dev->conf.bs);
+        if (*dinfo->serial) {
+            serial = dinfo->serial;
+        }
+    }
+
+    if (ide_init_drive(s, dev->conf.bs, kind, dev->version, serial) < 0) {
+        return -1;
+    }
+
+    if (!dev->version) {
+        dev->version = qemu_strdup(s->version);
+    }
+    if (!dev->serial) {
+        dev->serial = qemu_strdup(s->drive_serial_str);
+    }
+
+    add_boot_device_path(dev->conf.bootindex, &dev->qdev,
+                         dev->unit ? "/disk at 1" : "/disk at 0");
+
+    return 0;
+}
+
+static int ide_hd_initfn(IDEDevice *dev)
+{
+    return ide_dev_initfn(dev, IDE_HD);
+}
+
+static int ide_cd_initfn(IDEDevice *dev)
+{
+    return ide_dev_initfn(dev, IDE_CD);
+}
+
+static int ide_drive_initfn(IDEDevice *dev)
+{
+    DriveInfo *dinfo = drive_get_by_blockdev(dev->conf.bs);
+
+    return ide_dev_initfn(dev, dinfo->media_cd ? IDE_CD : IDE_HD);
+}
+
+#define DEFINE_IDE_DEV_PROPERTIES()                     \
+    DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),        \
+    DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
+    DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial)
+
+static IDEDeviceInfo ide_dev_info[] = {
+    {
+        .qdev.name    = "ide-hd",
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE disk",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_hd_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "ide-cd",
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE CD-ROM",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_cd_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "ide-drive", /* legacy -device ide-drive */
+        .qdev.fw_name = "drive",
+        .qdev.desc    = "virtual IDE disk or CD-ROM (legacy)",
+        .qdev.size    = sizeof(IDEDrive),
+        .init         = ide_drive_initfn,
+        .qdev.props   = (Property[]) {
+            DEFINE_IDE_DEV_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    }
+};
+
+static void ide_dev_register(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
+        ide_qdev_register(&ide_dev_info[i]);
+    }
+}
+device_init(ide_dev_register);
diff --git a/qemu-0.15.x/hw/ide/via.c b/qemu-0.15.x/hw/ide/via.c
new file mode 100644
index 0000000..3474c37
--- /dev/null
+++ b/qemu-0.15.x/hw/ide/via.c
@@ -0,0 +1,200 @@
+/*
+ * QEMU IDE Emulation: PCI VIA82C686B support.
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2010 Huacai Chen <zltjiangshi at gmail.com>
+ *
+ * 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 <hw/hw.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+#include <hw/isa.h>
+#include "block.h"
+#include "block_int.h"
+#include "sysemu.h"
+#include "dma.h"
+
+#include <hw/ide/pci.h>
+
+static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    uint32_t val;
+
+    switch (addr & 3) {
+    case 0:
+        val = bm->cmd;
+        break;
+    case 2:
+        val = bm->status;
+        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;
+#ifdef DEBUG_IDE
+    printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    switch (addr & 3) {
+    case 2:
+        bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
+        break;
+    default:;
+    }
+}
+
+static void bmdma_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    int i;
+
+    for(i = 0;i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+
+        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);
+
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
+        addr += 8;
+    }
+}
+
+static void via_reset(void *opaque)
+{
+    PCIIDEState *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_reset(&d->bus[i]);
+    }
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */
+    pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
+
+    /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
+    pci_set_long(pci_conf + 0x40, 0x0a090600);
+    /* IDE misc configuration 1/2/3 */
+    pci_set_long(pci_conf + 0x44, 0x00c00068);
+    /* IDE Timing control */
+    pci_set_long(pci_conf + 0x48, 0xa8a8a8a8);
+    /* IDE Address Setup Time */
+    pci_set_long(pci_conf + 0x4c, 0x000000ff);
+    /* UltraDMA Extended Timing Control*/
+    pci_set_long(pci_conf + 0x50, 0x07070707);
+    /* UltraDMA FIFO Control */
+    pci_set_long(pci_conf + 0x54, 0x00000004);
+    /* IDE primary sector size */
+    pci_set_long(pci_conf + 0x60, 0x00000200);
+    /* IDE secondary sector size */
+    pci_set_long(pci_conf + 0x68, 0x00000200);
+    /* PCI PM Block */
+    pci_set_long(pci_conf + 0xc0, 0x00020001);
+}
+
+static void vt82c686b_init_ports(PCIIDEState *d) {
+    int i;
+    struct {
+        int iobase;
+        int iobase2;
+        int isairq;
+    } port_info[] = {
+        {0x1f0, 0x3f6, 14},
+        {0x170, 0x376, 15},
+    };
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
+
+        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        d->bmdma[i].bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i].dma);
+    }
+}
+
+/* via ide func */
+static int vt82c686b_ide_initfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
+    uint8_t *pci_conf = d->dev.config;
+
+    pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
+    pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
+
+    qemu_register_reset(via_reset, d);
+    pci_register_bar(&d->dev, 4, 0x10,
+                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+
+    vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
+
+    vt82c686b_init_ports(d);
+
+    return 0;
+}
+
+void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create_simple(bus, devfn, "via-ide");
+    pci_ide_create_devs(dev, hd_table);
+}
+
+static PCIDeviceInfo via_ide_info = {
+    .qdev.name    = "via-ide",
+    .qdev.size    = sizeof(PCIIDEState),
+    .qdev.no_user = 1,
+    .init         = vt82c686b_ide_initfn,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_IDE,
+    .revision     = 0x06,
+    .class_id     = PCI_CLASS_STORAGE_IDE,
+};
+
+static void via_ide_register(void)
+{
+    pci_qdev_register(&via_ide_info);
+}
+device_init(via_ide_register);
diff --git a/qemu-0.15.x/hw/integratorcp.c b/qemu-0.15.x/hw/integratorcp.c
new file mode 100644
index 0000000..2814108
--- /dev/null
+++ b/qemu-0.15.x/hw/integratorcp.c
@@ -0,0 +1,544 @@
+/*
+ * ARM Integrator CP System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "sysbus.h"
+#include "primecell.h"
+#include "devices.h"
+#include "boards.h"
+#include "arm-misc.h"
+#include "net.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t memsz;
+    uint32_t flash_offset;
+    uint32_t cm_osc;
+    uint32_t cm_ctrl;
+    uint32_t cm_lock;
+    uint32_t cm_auxosc;
+    uint32_t cm_sdram;
+    uint32_t cm_init;
+    uint32_t cm_flags;
+    uint32_t cm_nvflags;
+    uint32_t int_level;
+    uint32_t irq_enabled;
+    uint32_t fiq_enabled;
+} integratorcm_state;
+
+static uint8_t integrator_spd[128] = {
+   128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
+   0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
+};
+
+static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    if (offset >= 0x100 && offset < 0x200) {
+        /* CM_SPD */
+        if (offset >= 0x180)
+            return 0;
+        return integrator_spd[offset >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* CM_ID */
+        return 0x411a3001;
+    case 1: /* CM_PROC */
+        return 0;
+    case 2: /* CM_OSC */
+        return s->cm_osc;
+    case 3: /* CM_CTRL */
+        return s->cm_ctrl;
+    case 4: /* CM_STAT */
+        return 0x00100000;
+    case 5: /* CM_LOCK */
+        if (s->cm_lock == 0xa05f) {
+            return 0x1a05f;
+        } else {
+            return s->cm_lock;
+        }
+    case 6: /* CM_LMBUSCNT */
+        /* ??? High frequency timer.  */
+        hw_error("integratorcm_read: CM_LMBUSCNT");
+    case 7: /* CM_AUXOSC */
+        return s->cm_auxosc;
+    case 8: /* CM_SDRAM */
+        return s->cm_sdram;
+    case 9: /* CM_INIT */
+        return s->cm_init;
+    case 10: /* CM_REFCT */
+        /* ??? High frequency timer.  */
+        hw_error("integratorcm_read: CM_REFCT");
+    case 12: /* CM_FLAGS */
+        return s->cm_flags;
+    case 14: /* CM_NVFLAGS */
+        return s->cm_nvflags;
+    case 16: /* CM_IRQ_STAT */
+        return s->int_level & s->irq_enabled;
+    case 17: /* CM_IRQ_RSTAT */
+        return s->int_level;
+    case 18: /* CM_IRQ_ENSET */
+        return s->irq_enabled;
+    case 20: /* CM_SOFT_INTSET */
+        return s->int_level & 1;
+    case 24: /* CM_FIQ_STAT */
+        return s->int_level & s->fiq_enabled;
+    case 25: /* CM_FIQ_RSTAT */
+        return s->int_level;
+    case 26: /* CM_FIQ_ENSET */
+        return s->fiq_enabled;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        return 0;
+    default:
+        hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
+                 (int)offset);
+        return 0;
+    }
+}
+
+static void integratorcm_do_remap(integratorcm_state *s, int flash)
+{
+    if (flash) {
+        cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
+    } else {
+        cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
+    }
+    //??? tlb_flush (cpu_single_env, 1);
+}
+
+static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
+{
+    if (value & 8) {
+        hw_error("Board reset\n");
+    }
+    if ((s->cm_init ^ value) & 4) {
+        integratorcm_do_remap(s, (value & 4) == 0);
+    }
+    if ((s->cm_init ^ value) & 1) {
+        printf("Green LED %s\n", (value & 1) ? "on" : "off");
+    }
+    s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
+}
+
+static void integratorcm_update(integratorcm_state *s)
+{
+    /* ??? The CPU irq/fiq is raised when either the core module or base PIC
+       are active.  */
+    if (s->int_level & (s->irq_enabled | s->fiq_enabled))
+        hw_error("Core module interrupt\n");
+}
+
+static void integratorcm_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    switch (offset >> 2) {
+    case 2: /* CM_OSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_osc = value;
+        break;
+    case 3: /* CM_CTRL */
+        integratorcm_set_ctrl(s, value);
+        break;
+    case 5: /* CM_LOCK */
+        s->cm_lock = value & 0xffff;
+        break;
+    case 7: /* CM_AUXOSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_auxosc = value;
+        break;
+    case 8: /* CM_SDRAM */
+        s->cm_sdram = value;
+        break;
+    case 9: /* CM_INIT */
+        /* ??? This can change the memory bus frequency.  */
+        s->cm_init = value;
+        break;
+    case 12: /* CM_FLAGSS */
+        s->cm_flags |= value;
+        break;
+    case 13: /* CM_FLAGSC */
+        s->cm_flags &= ~value;
+        break;
+    case 14: /* CM_NVFLAGSS */
+        s->cm_nvflags |= value;
+        break;
+    case 15: /* CM_NVFLAGSS */
+        s->cm_nvflags &= ~value;
+        break;
+    case 18: /* CM_IRQ_ENSET */
+        s->irq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 19: /* CM_IRQ_ENCLR */
+        s->irq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 20: /* CM_SOFT_INTSET */
+        s->int_level |= (value & 1);
+        integratorcm_update(s);
+        break;
+    case 21: /* CM_SOFT_INTCLR */
+        s->int_level &= ~(value & 1);
+        integratorcm_update(s);
+        break;
+    case 26: /* CM_FIQ_ENSET */
+        s->fiq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 27: /* CM_FIQ_ENCLR */
+        s->fiq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        break;
+    default:
+        hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
+                 (int)offset);
+        break;
+    }
+}
+
+/* Integrator/CM control registers.  */
+
+static CPUReadMemoryFunc * const integratorcm_readfn[] = {
+   integratorcm_read,
+   integratorcm_read,
+   integratorcm_read
+};
+
+static CPUWriteMemoryFunc * const integratorcm_writefn[] = {
+   integratorcm_write,
+   integratorcm_write,
+   integratorcm_write
+};
+
+static int integratorcm_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev);
+
+    s->cm_osc = 0x01000048;
+    /* ??? What should the high bits of this value be?  */
+    s->cm_auxosc = 0x0007feff;
+    s->cm_sdram = 0x00011122;
+    if (s->memsz >= 256) {
+        integrator_spd[31] = 64;
+        s->cm_sdram |= 0x10;
+    } else if (s->memsz >= 128) {
+        integrator_spd[31] = 32;
+        s->cm_sdram |= 0x0c;
+    } else if (s->memsz >= 64) {
+        integrator_spd[31] = 16;
+        s->cm_sdram |= 0x08;
+    } else if (s->memsz >= 32) {
+        integrator_spd[31] = 4;
+        s->cm_sdram |= 0x04;
+    } else {
+        integrator_spd[31] = 2;
+    }
+    memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
+    s->cm_init = 0x00000112;
+    s->flash_offset = qemu_ram_alloc(NULL, "integrator.flash", 0x100000);
+
+    iomemtype = cpu_register_io_memory(integratorcm_readfn,
+                                       integratorcm_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x00800000, iomemtype);
+    integratorcm_do_remap(s, 1);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+/* Integrator/CP hardware emulation.  */
+/* Primary interrupt controller.  */
+
+typedef struct icp_pic_state
+{
+  SysBusDevice busdev;
+  uint32_t level;
+  uint32_t irq_enabled;
+  uint32_t fiq_enabled;
+  qemu_irq parent_irq;
+  qemu_irq parent_fiq;
+} icp_pic_state;
+
+static void icp_pic_update(icp_pic_state *s)
+{
+    uint32_t flags;
+
+    flags = (s->level & s->irq_enabled);
+    qemu_set_irq(s->parent_irq, flags != 0);
+    flags = (s->level & s->fiq_enabled);
+    qemu_set_irq(s->parent_fiq, flags != 0);
+}
+
+static void icp_pic_set_irq(void *opaque, int irq, int level)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+    if (level)
+        s->level |= 1 << irq;
+    else
+        s->level &= ~(1 << irq);
+    icp_pic_update(s);
+}
+
+static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* IRQ_STATUS */
+        return s->level & s->irq_enabled;
+    case 1: /* IRQ_RAWSTAT */
+        return s->level;
+    case 2: /* IRQ_ENABLESET */
+        return s->irq_enabled;
+    case 4: /* INT_SOFTSET */
+        return s->level & 1;
+    case 8: /* FRQ_STATUS */
+        return s->level & s->fiq_enabled;
+    case 9: /* FRQ_RAWSTAT */
+        return s->level;
+    case 10: /* FRQ_ENABLESET */
+        return s->fiq_enabled;
+    case 3: /* IRQ_ENABLECLR */
+    case 5: /* INT_SOFTCLR */
+    case 11: /* FRQ_ENABLECLR */
+    default:
+        printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void icp_pic_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 2: /* IRQ_ENABLESET */
+        s->irq_enabled |= value;
+        break;
+    case 3: /* IRQ_ENABLECLR */
+        s->irq_enabled &= ~value;
+        break;
+    case 4: /* INT_SOFTSET */
+        if (value & 1)
+            icp_pic_set_irq(s, 0, 1);
+        break;
+    case 5: /* INT_SOFTCLR */
+        if (value & 1)
+            icp_pic_set_irq(s, 0, 0);
+        break;
+    case 10: /* FRQ_ENABLESET */
+        s->fiq_enabled |= value;
+        break;
+    case 11: /* FRQ_ENABLECLR */
+        s->fiq_enabled &= ~value;
+        break;
+    case 0: /* IRQ_STATUS */
+    case 1: /* IRQ_RAWSTAT */
+    case 8: /* FRQ_STATUS */
+    case 9: /* FRQ_RAWSTAT */
+    default:
+        printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+    icp_pic_update(s);
+}
+
+static CPUReadMemoryFunc * const icp_pic_readfn[] = {
+   icp_pic_read,
+   icp_pic_read,
+   icp_pic_read
+};
+
+static CPUWriteMemoryFunc * const icp_pic_writefn[] = {
+   icp_pic_write,
+   icp_pic_write,
+   icp_pic_write
+};
+
+static int icp_pic_init(SysBusDevice *dev)
+{
+    icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev);
+    int iomemtype;
+
+    qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    sysbus_init_irq(dev, &s->parent_fiq);
+    iomemtype = cpu_register_io_memory(icp_pic_readfn,
+                                       icp_pic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x00800000, iomemtype);
+    return 0;
+}
+
+/* CP control registers.  */
+static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset)
+{
+    switch (offset >> 2) {
+    case 0: /* CP_IDFIELD */
+        return 0x41034003;
+    case 1: /* CP_FLASHPROG */
+        return 0;
+    case 2: /* CP_INTREG */
+        return 0;
+    case 3: /* CP_DECODE */
+        return 0x11;
+    default:
+        hw_error("icp_control_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void icp_control_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    switch (offset >> 2) {
+    case 1: /* CP_FLASHPROG */
+    case 2: /* CP_INTREG */
+    case 3: /* CP_DECODE */
+        /* Nothing interesting implemented yet.  */
+        break;
+    default:
+        hw_error("icp_control_write: Bad offset %x\n", (int)offset);
+    }
+}
+static CPUReadMemoryFunc * const icp_control_readfn[] = {
+   icp_control_read,
+   icp_control_read,
+   icp_control_read
+};
+
+static CPUWriteMemoryFunc * const icp_control_writefn[] = {
+   icp_control_write,
+   icp_control_write,
+   icp_control_write
+};
+
+static void icp_control_init(uint32_t base)
+{
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(icp_control_readfn,
+                                       icp_control_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00800000, iomemtype);
+    /* ??? Save/restore.  */
+}
+
+
+/* Board init.  */
+
+static struct arm_boot_info integrator_binfo = {
+    .loader_start = 0x0,
+    .board_id = 0x113,
+};
+
+static void integratorcp_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    ram_addr_t ram_offset;
+    qemu_irq pic[32];
+    qemu_irq *cpu_pic;
+    DeviceState *dev;
+    int i;
+
+    if (!cpu_model)
+        cpu_model = "arm926";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    ram_offset = qemu_ram_alloc(NULL, "integrator.ram", ram_size);
+    /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
+    /* ??? RAM should repeat to fill physical memory space.  */
+    /* SDRAM at address zero*/
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    /* And again at address 0x80000000 */
+    cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
+
+    dev = qdev_create(NULL, "integrator_core");
+    qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
+
+    cpu_pic = arm_pic_init_cpu(env);
+    dev = sysbus_create_varargs("integrator_pic", 0x14000000,
+                                cpu_pic[ARM_PIC_CPU_IRQ],
+                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+    for (i = 0; i < 32; i++) {
+        pic[i] = qdev_get_gpio_in(dev, i);
+    }
+    sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
+    sysbus_create_varargs("integrator_pit", 0x13000000,
+                          pic[5], pic[6], pic[7], NULL);
+    sysbus_create_simple("pl031", 0x15000000, pic[8]);
+    sysbus_create_simple("pl011", 0x16000000, pic[1]);
+    sysbus_create_simple("pl011", 0x17000000, pic[2]);
+    icp_control_init(0xcb000000);
+    sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
+    sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
+    sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
+    if (nd_table[0].vlan)
+        smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
+
+    sysbus_create_simple("pl110", 0xc0000000, pic[22]);
+
+    integrator_binfo.ram_size = ram_size;
+    integrator_binfo.kernel_filename = kernel_filename;
+    integrator_binfo.kernel_cmdline = kernel_cmdline;
+    integrator_binfo.initrd_filename = initrd_filename;
+    arm_load_kernel(env, &integrator_binfo);
+}
+
+static QEMUMachine integratorcp_machine = {
+    .name = "integratorcp",
+    .desc = "ARM Integrator/CP (ARM926EJ-S)",
+    .init = integratorcp_init,
+    .is_default = 1,
+};
+
+static void integratorcp_machine_init(void)
+{
+    qemu_register_machine(&integratorcp_machine);
+}
+
+machine_init(integratorcp_machine_init);
+
+static SysBusDeviceInfo core_info = {
+    .init = integratorcm_init,
+    .qdev.name  = "integrator_core",
+    .qdev.size  = sizeof(integratorcm_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void integratorcp_register_devices(void)
+{
+    sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init);
+    sysbus_register_withprop(&core_info);
+}
+
+device_init(integratorcp_register_devices)
diff --git a/qemu-0.15.x/hw/intel-hda-defs.h b/qemu-0.15.x/hw/intel-hda-defs.h
new file mode 100644
index 0000000..2e37e5b
--- /dev/null
+++ b/qemu-0.15.x/hw/intel-hda-defs.h
@@ -0,0 +1,717 @@
+#ifndef HW_INTEL_HDA_DEFS_H
+#define HW_INTEL_HDA_DEFS_H
+
+/* qemu */
+#define HDA_BUFFER_SIZE 256
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_intel.c                                  */
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP			0x00
+#define   ICH6_GCAP_64OK	(1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO	(3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS		(31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS		(15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS		(15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN			0x02
+#define ICH6_REG_VMAJ			0x03
+#define ICH6_REG_OUTPAY			0x04
+#define ICH6_REG_INPAY			0x06
+#define ICH6_REG_GCTL			0x08
+#define   ICH6_GCTL_RESET	(1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL	(1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL	(1 << 8)   /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN			0x0c
+#define ICH6_REG_STATESTS		0x0e
+#define ICH6_REG_GSTS			0x10
+#define   ICH6_GSTS_FSTS	(1 << 1)   /* flush status */
+#define ICH6_REG_INTCTL			0x20
+#define ICH6_REG_INTSTS			0x24
+#define ICH6_REG_WALLCLK		0x30	/* 24Mhz source */
+#define ICH6_REG_SYNC			0x34
+#define ICH6_REG_CORBLBASE		0x40
+#define ICH6_REG_CORBUBASE		0x44
+#define ICH6_REG_CORBWP			0x48
+#define ICH6_REG_CORBRP			0x4a
+#define   ICH6_CORBRP_RST	(1 << 15)  /* read pointer reset */
+#define ICH6_REG_CORBCTL		0x4c
+#define   ICH6_CORBCTL_RUN	(1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE	(1 << 0)   /* enable memory error irq */
+#define ICH6_REG_CORBSTS		0x4d
+#define   ICH6_CORBSTS_CMEI	(1 << 0)   /* memory error indication */
+#define ICH6_REG_CORBSIZE		0x4e
+
+#define ICH6_REG_RIRBLBASE		0x50
+#define ICH6_REG_RIRBUBASE		0x54
+#define ICH6_REG_RIRBWP			0x58
+#define   ICH6_RIRBWP_RST	(1 << 15)  /* write pointer reset */
+#define ICH6_REG_RINTCNT		0x5a
+#define ICH6_REG_RIRBCTL		0x5c
+#define   ICH6_RBCTL_IRQ_EN	(1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN	(1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN	(1 << 2)   /* enable overrun irq */
+#define ICH6_REG_RIRBSTS		0x5d
+#define   ICH6_RBSTS_IRQ	(1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN	(1 << 2)   /* overrun irq */
+#define ICH6_REG_RIRBSIZE		0x5e
+
+#define ICH6_REG_IC			0x60
+#define ICH6_REG_IR			0x64
+#define ICH6_REG_IRS			0x68
+#define   ICH6_IRS_VALID	(1<<1)
+#define   ICH6_IRS_BUSY		(1<<0)
+
+#define ICH6_REG_DPLBASE		0x70
+#define ICH6_REG_DPUBASE		0x74
+#define   ICH6_DPLBASE_ENABLE	0x1	/* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL			0x00
+#define ICH6_REG_SD_STS			0x03
+#define ICH6_REG_SD_LPIB		0x04
+#define ICH6_REG_SD_CBL			0x08
+#define ICH6_REG_SD_LVI			0x0c
+#define ICH6_REG_SD_FIFOW		0x0e
+#define ICH6_REG_SD_FIFOSIZE		0x10
+#define ICH6_REG_SD_FORMAT		0x12
+#define ICH6_REG_SD_BDLPL		0x18
+#define ICH6_REG_SD_BDLPU		0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL	0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE	4
+#define ICH6_NUM_PLAYBACK	4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE		5
+#define ULI_NUM_PLAYBACK	6
+
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_NUM_CAPTURE	0
+#define ATIHDMI_NUM_PLAYBACK	1
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE	3
+#define TERA_NUM_PLAYBACK	4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV		16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE		4096
+#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
+#define AZX_MAX_FRAG		32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE	0x01
+#define RIRB_INT_OVERRUN	0x04
+#define RIRB_INT_MASK		0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS		8
+#define AZX_DEFAULT_CODECS	4
+#define STATESTS_INT_MASK	((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
+#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
+#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
+#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT	20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
+#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
+#define SD_INT_COMPLETE		0x04	/* completion interrupt */
+#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+				 SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM	0xff	   /* all stream interrupts */
+#define ICH6_INT_CTRL_EN	0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES	256
+#define ICH6_MAX_RIRB_ENTRIES	256
+
+/* position fix mode */
+enum {
+	POS_FIX_AUTO,
+	POS_FIX_LPIB,
+	POS_FIX_POSBUF,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
+#define NVIDIA_HDA_ISTRM_COH          0x4d
+#define NVIDIA_HDA_OSTRM_COH          0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT      0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET	0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID		0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_codec.h                                  */
+
+/*
+ * nodes
+ */
+#define	AC_NODE_ROOT		0x00
+
+/*
+ * function group types
+ */
+enum {
+	AC_GRP_AUDIO_FUNCTION = 0x01,
+	AC_GRP_MODEM_FUNCTION = 0x02,
+};
+	
+/*
+ * widget types
+ */
+enum {
+	AC_WID_AUD_OUT,		/* Audio Out */
+	AC_WID_AUD_IN,		/* Audio In */
+	AC_WID_AUD_MIX,		/* Audio Mixer */
+	AC_WID_AUD_SEL,		/* Audio Selector */
+	AC_WID_PIN,		/* Pin Complex */
+	AC_WID_POWER,		/* Power */
+	AC_WID_VOL_KNB,		/* Volume Knob */
+	AC_WID_BEEP,		/* Beep Generator */
+	AC_WID_VENDOR = 0x0f	/* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT		0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE		0x0b00
+#define AC_VERB_GET_PROC_COEF			0x0c00
+#define AC_VERB_GET_COEF_INDEX			0x0d00
+#define AC_VERB_PARAMETERS			0x0f00
+#define AC_VERB_GET_CONNECT_SEL			0x0f01
+#define AC_VERB_GET_CONNECT_LIST		0x0f02
+#define AC_VERB_GET_PROC_STATE			0x0f03
+#define AC_VERB_GET_SDI_SELECT			0x0f04
+#define AC_VERB_GET_POWER_STATE			0x0f05
+#define AC_VERB_GET_CONV			0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL		0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE	0x0f08
+#define AC_VERB_GET_PIN_SENSE			0x0f09
+#define AC_VERB_GET_BEEP_CONTROL		0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE		0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT_1		0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2		0x0f0e /* unused */
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL		0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_GPIO_DATA			0x0f15
+#define AC_VERB_GET_GPIO_MASK			0x0f16
+#define AC_VERB_GET_GPIO_DIRECTION		0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK		0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK	0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK		0x0f1a
+#define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
+/* f20: AFG/MFG */
+#define AC_VERB_GET_SUBSYSTEM_ID		0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT		0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE		0x0f2e
+#define AC_VERB_GET_HDMI_ELDD			0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX		0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA		0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT		0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL		0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT		0x0f34
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT		0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE		0x300
+#define AC_VERB_SET_PROC_COEF			0x400
+#define AC_VERB_SET_COEF_INDEX			0x500
+#define AC_VERB_SET_CONNECT_SEL			0x701
+#define AC_VERB_SET_PROC_STATE			0x703
+#define AC_VERB_SET_SDI_SELECT			0x704
+#define AC_VERB_SET_POWER_STATE			0x705
+#define AC_VERB_SET_CHANNEL_STREAMID		0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL		0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE		0x708
+#define AC_VERB_SET_PIN_SENSE			0x709
+#define AC_VERB_SET_BEEP_CONTROL		0x70a
+#define AC_VERB_SET_EAPD_BTLENABLE		0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1		0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2		0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL		0x70f
+#define AC_VERB_SET_GPIO_DATA			0x715
+#define AC_VERB_SET_GPIO_MASK			0x716
+#define AC_VERB_SET_GPIO_DIRECTION		0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK		0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK	0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK		0x71a
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0	0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3	0x71f
+#define AC_VERB_SET_EAPD				0x788
+#define AC_VERB_SET_CODEC_RESET			0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT		0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX		0x730
+#define AC_VERB_SET_HDMI_DIP_DATA		0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT		0x732
+#define AC_VERB_SET_HDMI_CP_CTRL		0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT		0x734
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID		0x00
+#define AC_PAR_SUBSYSTEM_ID		0x01
+#define AC_PAR_REV_ID			0x02
+#define AC_PAR_NODE_COUNT		0x04
+#define AC_PAR_FUNCTION_TYPE		0x05
+#define AC_PAR_AUDIO_FG_CAP		0x08
+#define AC_PAR_AUDIO_WIDGET_CAP		0x09
+#define AC_PAR_PCM			0x0a
+#define AC_PAR_STREAM			0x0b
+#define AC_PAR_PIN_CAP			0x0c
+#define AC_PAR_AMP_IN_CAP		0x0d
+#define AC_PAR_CONNLIST_LEN		0x0e
+#define AC_PAR_POWER_STATE		0x0f
+#define AC_PAR_PROC_CAP			0x10
+#define AC_PAR_GPIO_CAP			0x11
+#define AC_PAR_AMP_OUT_CAP		0x12
+#define AC_PAR_VOL_KNB_CAP		0x13
+#define AC_PAR_HDMI_LPCM_CAP		0x20
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE			(0xff<<0)
+#define AC_FGT_TYPE_SHIFT		0
+#define AC_FGT_UNSOL_CAP		(1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY		(0xf<<0)
+#define AC_AFG_IN_DELAY			(0xf<<8)
+#define AC_AFG_BEEP_GEN			(1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO			(1<<0)	/* stereo I/O */
+#define AC_WCAP_IN_AMP			(1<<1)	/* AMP-in present */
+#define AC_WCAP_OUT_AMP			(1<<2)	/* AMP-out present */
+#define AC_WCAP_AMP_OVRD		(1<<3)	/* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD		(1<<4)	/* format override */
+#define AC_WCAP_STRIPE			(1<<5)	/* stripe */
+#define AC_WCAP_PROC_WID		(1<<6)	/* Proc Widget */
+#define AC_WCAP_UNSOL_CAP		(1<<7)	/* Unsol capable */
+#define AC_WCAP_CONN_LIST		(1<<8)	/* connection list */
+#define AC_WCAP_DIGITAL			(1<<9)	/* digital I/O */
+#define AC_WCAP_POWER			(1<<10)	/* power control */
+#define AC_WCAP_LR_SWAP			(1<<11)	/* L/R swap */
+#define AC_WCAP_CP_CAPS			(1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT		(7<<13)	/* channel count ext */
+#define AC_WCAP_DELAY			(0xf<<16)
+#define AC_WCAP_DELAY_SHIFT		16
+#define AC_WCAP_TYPE			(0xf<<20)
+#define AC_WCAP_TYPE_SHIFT		20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES			(0xfff << 0)
+#define AC_SUPPCM_BITS_8		(1<<16)
+#define AC_SUPPCM_BITS_16		(1<<17)
+#define AC_SUPPCM_BITS_20		(1<<18)
+#define AC_SUPPCM_BITS_24		(1<<19)
+#define AC_SUPPCM_BITS_32		(1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM			(1<<0)
+#define AC_SUPFMT_FLOAT32		(1<<1)
+#define AC_SUPFMT_AC3			(1<<2)
+
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT		(0xff<<0)
+#define AC_GPIO_O_COUNT			(0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT		8
+#define AC_GPIO_I_COUNT			(0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT		16
+#define AC_GPIO_UNSOLICITED		(1<<30)
+#define AC_GPIO_WAKE			(1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL			(0xf<<0)
+#define AC_CONV_STREAM			(0xf<<4)
+#define AC_CONV_STREAM_SHIFT		4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT			(0xf<<0)
+
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT		0
+#define AC_FMT_CHAN_MASK		(0x0f << 0)
+#define AC_FMT_BITS_SHIFT		4
+#define AC_FMT_BITS_MASK		(7 << 4)
+#define AC_FMT_BITS_8			(0 << 4)
+#define AC_FMT_BITS_16			(1 << 4)
+#define AC_FMT_BITS_20			(2 << 4)
+#define AC_FMT_BITS_24			(3 << 4)
+#define AC_FMT_BITS_32			(4 << 4)
+#define AC_FMT_DIV_SHIFT		8
+#define AC_FMT_DIV_MASK			(7 << 8)
+#define AC_FMT_MULT_SHIFT		11
+#define AC_FMT_MULT_MASK		(7 << 11)
+#define AC_FMT_BASE_SHIFT		14
+#define AC_FMT_BASE_48K			(0 << 14)
+#define AC_FMT_BASE_44K			(1 << 14)
+#define AC_FMT_TYPE_SHIFT		15
+#define AC_FMT_TYPE_PCM			(0 << 15)
+#define AC_FMT_TYPE_NON_PCM		(1 << 15)
+
+/* Unsolicited response control */
+#define AC_UNSOL_TAG			(0x3f<<0)
+#define AC_UNSOL_ENABLED		(1<<7)
+#define AC_USRSP_EN			AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG		(0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT		26
+#define AC_UNSOL_RES_SUBTAG		(0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT	21
+#define AC_UNSOL_RES_ELDV		(1<<1)	/* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD			(1<<0)	/* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE		(1<<1)	/* content protection */
+#define AC_UNSOL_RES_CP_READY		(1<<0)	/* content protection */
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
+#define AC_PINCAP_PRES_DETECT		(1<<2)	/* presence detect capable */
+#define AC_PINCAP_HP_DRV		(1<<3)	/* headphone drive capable */
+#define AC_PINCAP_OUT			(1<<4)	/* output capable */
+#define AC_PINCAP_IN			(1<<5)	/* input capable */
+#define AC_PINCAP_BALANCE		(1<<6)	/* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ *       but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP		(1<<7)	/* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ *       in HD-audio specification
+ */
+#define AC_PINCAP_HDMI			(1<<7)	/* HDMI pin */
+#define AC_PINCAP_DP			(1<<24)	/* DisplayPort pin, can
+						 * coexist with AC_PINCAP_HDMI
+						 */
+#define AC_PINCAP_VREF			(0x37<<8)
+#define AC_PINCAP_VREF_SHIFT		8
+#define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
+#define AC_PINCAP_HBR			(1<<27)	/* High Bit Rate */
+/* Vref status (used in pin cap) */
+#define AC_PINCAP_VREF_HIZ		(1<<0)	/* Hi-Z */
+#define AC_PINCAP_VREF_50		(1<<1)	/* 50% */
+#define AC_PINCAP_VREF_GRD		(1<<2)	/* ground */
+#define AC_PINCAP_VREF_80		(1<<4)	/* 80% */
+#define AC_PINCAP_VREF_100		(1<<5)	/* 100% */
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET		(0x7f<<0)  /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT		0
+#define AC_AMPCAP_NUM_STEPS		(0x7f<<8)  /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT	8
+#define AC_AMPCAP_STEP_SIZE		(0x7f<<16) /* step size 0-32dB
+						    * in 0.25dB
+						    */
+#define AC_AMPCAP_STEP_SIZE_SHIFT	16
+#define AC_AMPCAP_MUTE			(1<<31)    /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT		31
+
+/* Connection list */
+#define AC_CLIST_LENGTH			(0x7f<<0)
+#define AC_CLIST_LONG			(1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP			(1<<0)
+#define AC_PWRST_D1SUP			(1<<1)
+#define AC_PWRST_D2SUP			(1<<2)
+#define AC_PWRST_D3SUP			(1<<3)
+#define AC_PWRST_D3COLDSUP		(1<<4)
+#define AC_PWRST_S3D3COLDSUP		(1<<29)
+#define AC_PWRST_CLKSTOP		(1<<30)
+#define AC_PWRST_EPSS			(1U<<31)
+
+/* Power state values */
+#define AC_PWRST_SETTING		(0xf<<0)
+#define AC_PWRST_ACTUAL			(0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT		4
+#define AC_PWRST_D0			0x00
+#define AC_PWRST_D1			0x01
+#define AC_PWRST_D2			0x02
+#define AC_PWRST_D3			0x03
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN			(1<<0)
+#define AC_PCAP_NUM_COEF		(0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT		8
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
+#define AC_KNBCAP_DELTA			(1<<7)
+
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS		(0x0f<<0) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_48K_NO_CHNS		(0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT		(1<<8)	/* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT		(1<<9)	/* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS		(0x0f<<10) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_96K_NO_CHNS		(0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT		(1<<18)	/* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT		(1<<19)	/* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS		(0x0f<<20) /* max channels w/ CP-on */	
+#define AC_LPCMCAP_192K_NO_CHNS		(0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT		(1<<28)	/* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT		(1<<29)	/* 24b bitrate supported */
+#define AC_LPCMCAP_44K			(1<<30)	/* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS		(1<<31)	/* 44.1kHz-multiplies support */
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE			(1<<7)
+#define AC_AMP_GAIN			(0x7f)
+#define AC_AMP_GET_INDEX		(0xf<<0)
+
+#define AC_AMP_GET_LEFT			(1<<13)
+#define AC_AMP_GET_RIGHT		(0<<13)
+#define AC_AMP_GET_OUTPUT		(1<<15)
+#define AC_AMP_GET_INPUT		(0<<15)
+
+#define AC_AMP_SET_INDEX		(0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT		8
+#define AC_AMP_SET_RIGHT		(1<<12)
+#define AC_AMP_SET_LEFT			(1<<13)
+#define AC_AMP_SET_INPUT		(1<<14)
+#define AC_AMP_SET_OUTPUT		(1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE			(1<<0)
+#define AC_DIG1_V			(1<<1)
+#define AC_DIG1_VCFG			(1<<2)
+#define AC_DIG1_EMPHASIS		(1<<3)
+#define AC_DIG1_COPYRIGHT		(1<<4)
+#define AC_DIG1_NONAUDIO		(1<<5)
+#define AC_DIG1_PROFESSIONAL		(1<<6)
+#define AC_DIG1_LEVEL			(1<<7)
+
+/* DIGITAL2 bits */
+#define AC_DIG2_CC			(0x7f<<0)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_EPT			(0x3<<0)
+#define AC_PINCTL_EPT_NATIVE		0
+#define AC_PINCTL_EPT_HBR		3
+#define AC_PINCTL_VREFEN		(0x7<<0)
+#define AC_PINCTL_VREF_HIZ		0	/* Hi-Z */
+#define AC_PINCTL_VREF_50		1	/* 50% */
+#define AC_PINCTL_VREF_GRD		2	/* ground */
+#define AC_PINCTL_VREF_80		4	/* 80% */
+#define AC_PINCTL_VREF_100		5	/* 100% */
+#define AC_PINCTL_IN_EN			(1<<5)
+#define AC_PINCTL_OUT_EN		(1<<6)
+#define AC_PINCTL_HP_EN			(1<<7)
+
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK	(0x7fffffff)
+#define AC_PINSENSE_PRESENCE		(1<<31)
+#define AC_PINSENSE_ELDV		(1<<30)	/* ELD valid (HDMI) */
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED		(1<<0)
+#define AC_EAPDBTL_EAPD			(1<<1)
+#define AC_EAPDBTL_LR_SWAP		(1<<2)
+
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID		(1<<31)
+#define AC_ELDD_ELD_DATA		0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF		(1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX		(0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX		(0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX		(0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK			(0x3<<6)
+#define AC_DIPXMIT_DISABLE		(0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE			(0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST			(0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES			(1<<9) /* current encryption state */
+#define AC_CPCTRL_READY			(1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG		(0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE			(3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT		(0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN			(0xf<<4) /* converter channel number */
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE		(0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
+#define AC_DEFCFG_ASSOC_SHIFT		4
+#define AC_DEFCFG_MISC			(0xf<<8)
+#define AC_DEFCFG_MISC_SHIFT		8
+#define AC_DEFCFG_MISC_NO_PRESENCE	(1<<0)
+#define AC_DEFCFG_COLOR			(0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT		12
+#define AC_DEFCFG_CONN_TYPE		(0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT	16
+#define AC_DEFCFG_DEVICE		(0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT		20
+#define AC_DEFCFG_LOCATION		(0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT	24
+#define AC_DEFCFG_PORT_CONN		(0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT	30
+
+/* device device types (0x0-0xf) */
+enum {
+	AC_JACK_LINE_OUT,
+	AC_JACK_SPEAKER,
+	AC_JACK_HP_OUT,
+	AC_JACK_CD,
+	AC_JACK_SPDIF_OUT,
+	AC_JACK_DIG_OTHER_OUT,
+	AC_JACK_MODEM_LINE_SIDE,
+	AC_JACK_MODEM_HAND_SIDE,
+	AC_JACK_LINE_IN,
+	AC_JACK_AUX,
+	AC_JACK_MIC_IN,
+	AC_JACK_TELEPHONY,
+	AC_JACK_SPDIF_IN,
+	AC_JACK_DIG_OTHER_IN,
+	AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+	AC_JACK_CONN_UNKNOWN,
+	AC_JACK_CONN_1_8,
+	AC_JACK_CONN_1_4,
+	AC_JACK_CONN_ATAPI,
+	AC_JACK_CONN_RCA,
+	AC_JACK_CONN_OPTICAL,
+	AC_JACK_CONN_OTHER_DIGITAL,
+	AC_JACK_CONN_OTHER_ANALOG,
+	AC_JACK_CONN_DIN,
+	AC_JACK_CONN_XLR,
+	AC_JACK_CONN_RJ11,
+	AC_JACK_CONN_COMB,
+	AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+	AC_JACK_COLOR_UNKNOWN,
+	AC_JACK_COLOR_BLACK,
+	AC_JACK_COLOR_GREY,
+	AC_JACK_COLOR_BLUE,
+	AC_JACK_COLOR_GREEN,
+	AC_JACK_COLOR_RED,
+	AC_JACK_COLOR_ORANGE,
+	AC_JACK_COLOR_YELLOW,
+	AC_JACK_COLOR_PURPLE,
+	AC_JACK_COLOR_PINK,
+	AC_JACK_COLOR_WHITE = 0xe,
+	AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+	AC_JACK_LOC_NONE,
+	AC_JACK_LOC_REAR,
+	AC_JACK_LOC_FRONT,
+	AC_JACK_LOC_LEFT,
+	AC_JACK_LOC_RIGHT,
+	AC_JACK_LOC_TOP,
+	AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+	AC_JACK_LOC_EXTERNAL = 0x00,
+	AC_JACK_LOC_INTERNAL = 0x10,
+	AC_JACK_LOC_SEPARATE = 0x20,
+	AC_JACK_LOC_OTHER    = 0x30,
+};
+enum {
+	/* external on primary chasis */
+	AC_JACK_LOC_REAR_PANEL = 0x07,
+	AC_JACK_LOC_DRIVE_BAY,
+	/* internal */
+	AC_JACK_LOC_RISER = 0x17,
+	AC_JACK_LOC_HDMI,
+	AC_JACK_LOC_ATAPI,
+	/* others */
+	AC_JACK_LOC_MOBILE_IN = 0x37,
+	AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+	AC_JACK_PORT_COMPLEX,
+	AC_JACK_PORT_NONE,
+	AC_JACK_PORT_FIXED,
+	AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS	32
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS	0x0f
+
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS		10
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/qemu-0.15.x/hw/intel-hda.c b/qemu-0.15.x/hw/intel-hda.c
new file mode 100644
index 0000000..5a2bc3a
--- /dev/null
+++ b/qemu-0.15.x/hw/intel-hda.c
@@ -0,0 +1,1284 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "msi.h"
+#include "qemu-timer.h"
+#include "audiodev.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus                                                               */
+
+static struct BusInfo hda_codec_bus_info = {
+    .name      = "HDA",
+    .size      = sizeof(HDACodecBus),
+    .props     = (Property[]) {
+        DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+                        hda_codec_response_func response,
+                        hda_codec_xfer_func xfer)
+{
+    qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+    bus->response = response;
+    bus->xfer = xfer;
+}
+
+static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
+    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+    HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+
+    dev->info = info;
+    if (dev->cad == -1) {
+        dev->cad = bus->next_cad;
+    }
+    if (dev->cad >= 15) {
+        return -1;
+    }
+    bus->next_cad = dev->cad + 1;
+    return info->init(dev);
+}
+
+static int hda_codec_dev_exit(DeviceState *qdev)
+{
+    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+
+    if (dev->info->exit) {
+        dev->info->exit(dev);
+    }
+    return 0;
+}
+
+void hda_codec_register(HDACodecDeviceInfo *info)
+{
+    info->qdev.init = hda_codec_dev_init;
+    info->qdev.exit = hda_codec_dev_exit;
+    info->qdev.bus_info = &hda_codec_bus_info;
+    qdev_register(&info->qdev);
+}
+
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
+{
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (cdev->cad == cad) {
+            return cdev;
+        }
+    }
+    return NULL;
+}
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    bus->response(dev, solicited, response);
+}
+
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    return bus->xfer(dev, stnr, output, buf, len);
+}
+
+/* --------------------------------------------------------------------- */
+/* intel hda emulation                                                   */
+
+typedef struct IntelHDAStream IntelHDAStream;
+typedef struct IntelHDAState IntelHDAState;
+typedef struct IntelHDAReg IntelHDAReg;
+
+typedef struct bpl {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flags;
+} bpl;
+
+struct IntelHDAStream {
+    /* registers */
+    uint32_t ctl;
+    uint32_t lpib;
+    uint32_t cbl;
+    uint32_t lvi;
+    uint32_t fmt;
+    uint32_t bdlp_lbase;
+    uint32_t bdlp_ubase;
+
+    /* state */
+    bpl      *bpl;
+    uint32_t bentries;
+    uint32_t bsize, be, bp;
+};
+
+struct IntelHDAState {
+    PCIDevice pci;
+    const char *name;
+    HDACodecBus codecs;
+
+    /* registers */
+    uint32_t g_ctl;
+    uint32_t wake_en;
+    uint32_t state_sts;
+    uint32_t int_ctl;
+    uint32_t int_sts;
+    uint32_t wall_clk;
+
+    uint32_t corb_lbase;
+    uint32_t corb_ubase;
+    uint32_t corb_rp;
+    uint32_t corb_wp;
+    uint32_t corb_ctl;
+    uint32_t corb_sts;
+    uint32_t corb_size;
+
+    uint32_t rirb_lbase;
+    uint32_t rirb_ubase;
+    uint32_t rirb_wp;
+    uint32_t rirb_cnt;
+    uint32_t rirb_ctl;
+    uint32_t rirb_sts;
+    uint32_t rirb_size;
+
+    uint32_t dp_lbase;
+    uint32_t dp_ubase;
+
+    uint32_t icw;
+    uint32_t irr;
+    uint32_t ics;
+
+    /* streams */
+    IntelHDAStream st[8];
+
+    /* state */
+    int mmio_addr;
+    uint32_t rirb_count;
+    int64_t wall_base_ns;
+
+    /* debug logging */
+    const IntelHDAReg *last_reg;
+    uint32_t last_val;
+    uint32_t last_write;
+    uint32_t last_sec;
+    uint32_t repeat_count;
+
+    /* properties */
+    uint32_t debug;
+    uint32_t msi;
+};
+
+struct IntelHDAReg {
+    const char *name;      /* register name */
+    uint32_t   size;       /* size in bytes */
+    uint32_t   reset;      /* reset value */
+    uint32_t   wmask;      /* write mask */
+    uint32_t   wclear;     /* write 1 to clear bits */
+    uint32_t   offset;     /* location in IntelHDAState */
+    uint32_t   shift;      /* byte access entries for dwords */
+    uint32_t   stream;
+    void       (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
+    void       (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
+};
+
+static void intel_hda_reset(DeviceState *dev);
+
+/* --------------------------------------------------------------------- */
+
+static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase)
+{
+    target_phys_addr_t addr;
+
+#if TARGET_PHYS_ADDR_BITS == 32
+    addr = lbase;
+#else
+    addr = ubase;
+    addr <<= 32;
+    addr |= lbase;
+#endif
+    return addr;
+}
+
+static void intel_hda_update_int_sts(IntelHDAState *d)
+{
+    uint32_t sts = 0;
+    uint32_t i;
+
+    /* update controller status */
+    if (d->rirb_sts & ICH6_RBSTS_IRQ) {
+        sts |= (1 << 30);
+    }
+    if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
+        sts |= (1 << 30);
+    }
+    if (d->state_sts & d->wake_en) {
+        sts |= (1 << 30);
+    }
+
+    /* update stream status */
+    for (i = 0; i < 8; i++) {
+        /* buffer completion interrupt */
+        if (d->st[i].ctl & (1 << 26)) {
+            sts |= (1 << i);
+        }
+    }
+
+    /* update global status */
+    if (sts & d->int_ctl) {
+        sts |= (1 << 31);
+    }
+
+    d->int_sts = sts;
+}
+
+static void intel_hda_update_irq(IntelHDAState *d)
+{
+    int msi = d->msi && msi_enabled(&d->pci);
+    int level;
+
+    intel_hda_update_int_sts(d);
+    if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
+        level = 1;
+    } else {
+        level = 0;
+    }
+    dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+           level, msi ? "msi" : "intx");
+    if (msi) {
+        if (level) {
+            msi_notify(&d->pci, 0);
+        }
+    } else {
+        qemu_set_irq(d->pci.irq[0], level);
+    }
+}
+
+static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
+{
+    uint32_t cad, nid, data;
+    HDACodecDevice *codec;
+
+    cad = (verb >> 28) & 0x0f;
+    if (verb & (1 << 27)) {
+        /* indirect node addressing, not specified in HDA 1.0 */
+        dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
+        return -1;
+    }
+    nid = (verb >> 20) & 0x7f;
+    data = verb & 0xfffff;
+
+    codec = hda_codec_find(&d->codecs, cad);
+    if (codec == NULL) {
+        dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
+        return -1;
+    }
+    codec->info->command(codec, nid, data);
+    return 0;
+}
+
+static void intel_hda_corb_run(IntelHDAState *d)
+{
+    target_phys_addr_t addr;
+    uint32_t rp, verb;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
+        intel_hda_send_command(d, d->icw);
+        return;
+    }
+
+    for (;;) {
+        if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
+            dprint(d, 2, "%s: !run\n", __FUNCTION__);
+            return;
+        }
+        if ((d->corb_rp & 0xff) == d->corb_wp) {
+            dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
+            return;
+        }
+        if (d->rirb_count == d->rirb_cnt) {
+            dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
+            return;
+        }
+
+        rp = (d->corb_rp + 1) & 0xff;
+        addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
+        verb = ldl_le_phys(addr + 4*rp);
+        d->corb_rp = rp;
+
+        dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
+        intel_hda_send_command(d, verb);
+    }
+}
+
+static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    target_phys_addr_t addr;
+    uint32_t wp, ex;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
+               __FUNCTION__, response, dev->cad);
+        d->irr = response;
+        d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
+        d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
+        return;
+    }
+
+    if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
+        dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
+        return;
+    }
+
+    ex = (solicited ? 0 : (1 << 4)) | dev->cad;
+    wp = (d->rirb_wp + 1) & 0xff;
+    addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
+    stl_le_phys(addr + 8*wp, response);
+    stl_le_phys(addr + 8*wp + 4, ex);
+    d->rirb_wp = wp;
+
+    dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
+           __FUNCTION__, wp, response, ex);
+
+    d->rirb_count++;
+    if (d->rirb_count == d->rirb_cnt) {
+        dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    } else if ((d->corb_rp & 0xff) == d->corb_wp) {
+        dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
+               d->rirb_count, d->rirb_cnt);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    }
+}
+
+static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                           uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    IntelHDAStream *st = NULL;
+    target_phys_addr_t addr;
+    uint32_t s, copy, left;
+    bool irq = false;
+
+    for (s = 0; s < ARRAY_SIZE(d->st); s++) {
+        if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
+            st = d->st + s;
+            break;
+        }
+    }
+    if (st == NULL) {
+        return false;
+    }
+    if (st->bpl == NULL) {
+        return false;
+    }
+    if (st->ctl & (1 << 26)) {
+        /*
+         * Wait with the next DMA xfer until the guest
+         * has acked the buffer completion interrupt
+         */
+        return false;
+    }
+
+    left = len;
+    while (left > 0) {
+        copy = left;
+        if (copy > st->bsize - st->lpib)
+            copy = st->bsize - st->lpib;
+        if (copy > st->bpl[st->be].len - st->bp)
+            copy = st->bpl[st->be].len - st->bp;
+
+        dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
+               st->be, st->bp, st->bpl[st->be].len, copy);
+
+        cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp,
+                               buf, copy, !output);
+        st->lpib += copy;
+        st->bp += copy;
+        buf += copy;
+        left -= copy;
+
+        if (st->bpl[st->be].len == st->bp) {
+            /* bpl entry filled */
+            if (st->bpl[st->be].flags & 0x01) {
+                irq = true;
+            }
+            st->bp = 0;
+            st->be++;
+            if (st->be == st->bentries) {
+                /* bpl wrap around */
+                st->be = 0;
+                st->lpib = 0;
+            }
+        }
+    }
+    if (d->dp_lbase & 0x01) {
+        addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
+        stl_le_phys(addr + 8*s, st->lpib);
+    }
+    dprint(d, 3, "dma: --\n");
+
+    if (irq) {
+        st->ctl |= (1 << 26); /* buffer completion interrupt */
+        intel_hda_update_irq(d);
+    }
+    return true;
+}
+
+static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
+{
+    target_phys_addr_t addr;
+    uint8_t buf[16];
+    uint32_t i;
+
+    addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
+    st->bentries = st->lvi +1;
+    qemu_free(st->bpl);
+    st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+    for (i = 0; i < st->bentries; i++, addr += 16) {
+        cpu_physical_memory_read(addr, buf, 16);
+        st->bpl[i].addr  = le64_to_cpu(*(uint64_t *)buf);
+        st->bpl[i].len   = le32_to_cpu(*(uint32_t *)(buf + 8));
+        st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
+        dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
+               i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
+    }
+
+    st->bsize = st->cbl;
+    st->lpib  = 0;
+    st->be    = 0;
+    st->bp    = 0;
+}
+
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+{
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (cdev->info->stream) {
+            cdev->info->stream(cdev, stream, running);
+        }
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
+        intel_hda_reset(&d->pci.qdev);
+    }
+}
+
+static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    int64_t ns;
+
+    ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns;
+    d->wall_clk = (uint32_t)(ns * 24 / 1000);  /* 24 MHz */
+}
+
+static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->rirb_wp & ICH6_RIRBWP_RST) {
+        d->rirb_wp = 0;
+    }
+}
+
+static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+
+    if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
+        /* cleared ICH6_RBSTS_IRQ */
+        d->rirb_count = 0;
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->ics & ICH6_IRS_BUSY) {
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    IntelHDAStream *st = d->st + reg->stream;
+
+    if (st->ctl & 0x01) {
+        /* reset */
+        dprint(d, 1, "st #%d: reset\n", reg->stream);
+        st->ctl = 0;
+    }
+    if ((st->ctl & 0x02) != (old & 0x02)) {
+        uint32_t stnr = (st->ctl >> 20) & 0x0f;
+        /* run bit flipped */
+        if (st->ctl & 0x02) {
+            /* start */
+            dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
+                   reg->stream, stnr, st->cbl);
+            intel_hda_parse_bdl(d, st);
+            intel_hda_notify_codecs(d, stnr, true);
+        } else {
+            /* stop */
+            dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
+            intel_hda_notify_codecs(d, stnr, false);
+        }
+    }
+    intel_hda_update_irq(d);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
+
+static const struct IntelHDAReg regtab[] = {
+    /* global */
+    [ ICH6_REG_GCAP ] = {
+        .name     = "GCAP",
+        .size     = 2,
+        .reset    = 0x4401,
+    },
+    [ ICH6_REG_VMIN ] = {
+        .name     = "VMIN",
+        .size     = 1,
+    },
+    [ ICH6_REG_VMAJ ] = {
+        .name     = "VMAJ",
+        .size     = 1,
+        .reset    = 1,
+    },
+    [ ICH6_REG_OUTPAY ] = {
+        .name     = "OUTPAY",
+        .size     = 2,
+        .reset    = 0x3c,
+    },
+    [ ICH6_REG_INPAY ] = {
+        .name     = "INPAY",
+        .size     = 2,
+        .reset    = 0x1d,
+    },
+    [ ICH6_REG_GCTL ] = {
+        .name     = "GCTL",
+        .size     = 4,
+        .wmask    = 0x0103,
+        .offset   = offsetof(IntelHDAState, g_ctl),
+        .whandler = intel_hda_set_g_ctl,
+    },
+    [ ICH6_REG_WAKEEN ] = {
+        .name     = "WAKEEN",
+        .size     = 2,
+        .wmask    = 0x7fff,
+        .offset   = offsetof(IntelHDAState, wake_en),
+        .whandler = intel_hda_set_wake_en,
+    },
+    [ ICH6_REG_STATESTS ] = {
+        .name     = "STATESTS",
+        .size     = 2,
+        .wmask    = 0x7fff,
+        .wclear   = 0x7fff,
+        .offset   = offsetof(IntelHDAState, state_sts),
+        .whandler = intel_hda_set_state_sts,
+    },
+
+    /* interrupts */
+    [ ICH6_REG_INTCTL ] = {
+        .name     = "INTCTL",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_ctl),
+        .whandler = intel_hda_set_int_ctl,
+    },
+    [ ICH6_REG_INTSTS ] = {
+        .name     = "INTSTS",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .wclear   = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_sts),
+    },
+
+    /* misc */
+    [ ICH6_REG_WALLCLK ] = {
+        .name     = "WALLCLK",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+    [ ICH6_REG_WALLCLK + 0x2000 ] = {
+        .name     = "WALLCLK(alias)",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+
+    /* dma engine */
+    [ ICH6_REG_CORBLBASE ] = {
+        .name     = "CORBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, corb_lbase),
+    },
+    [ ICH6_REG_CORBUBASE ] = {
+        .name     = "CORBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, corb_ubase),
+    },
+    [ ICH6_REG_CORBWP ] = {
+        .name     = "CORBWP",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, corb_wp),
+        .whandler = intel_hda_set_corb_wp,
+    },
+    [ ICH6_REG_CORBRP ] = {
+        .name     = "CORBRP",
+        .size     = 2,
+        .wmask    = 0x80ff,
+        .offset   = offsetof(IntelHDAState, corb_rp),
+    },
+    [ ICH6_REG_CORBCTL ] = {
+        .name     = "CORBCTL",
+        .size     = 1,
+        .wmask    = 0x03,
+        .offset   = offsetof(IntelHDAState, corb_ctl),
+        .whandler = intel_hda_set_corb_ctl,
+    },
+    [ ICH6_REG_CORBSTS ] = {
+        .name     = "CORBSTS",
+        .size     = 1,
+        .wmask    = 0x01,
+        .wclear   = 0x01,
+        .offset   = offsetof(IntelHDAState, corb_sts),
+    },
+    [ ICH6_REG_CORBSIZE ] = {
+        .name     = "CORBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, corb_size),
+    },
+    [ ICH6_REG_RIRBLBASE ] = {
+        .name     = "RIRBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, rirb_lbase),
+    },
+    [ ICH6_REG_RIRBUBASE ] = {
+        .name     = "RIRBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, rirb_ubase),
+    },
+    [ ICH6_REG_RIRBWP ] = {
+        .name     = "RIRBWP",
+        .size     = 2,
+        .wmask    = 0x8000,
+        .offset   = offsetof(IntelHDAState, rirb_wp),
+        .whandler = intel_hda_set_rirb_wp,
+    },
+    [ ICH6_REG_RINTCNT ] = {
+        .name     = "RINTCNT",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, rirb_cnt),
+    },
+    [ ICH6_REG_RIRBCTL ] = {
+        .name     = "RIRBCTL",
+        .size     = 1,
+        .wmask    = 0x07,
+        .offset   = offsetof(IntelHDAState, rirb_ctl),
+    },
+    [ ICH6_REG_RIRBSTS ] = {
+        .name     = "RIRBSTS",
+        .size     = 1,
+        .wmask    = 0x05,
+        .wclear   = 0x05,
+        .offset   = offsetof(IntelHDAState, rirb_sts),
+        .whandler = intel_hda_set_rirb_sts,
+    },
+    [ ICH6_REG_RIRBSIZE ] = {
+        .name     = "RIRBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, rirb_size),
+    },
+
+    [ ICH6_REG_DPLBASE ] = {
+        .name     = "DPLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff81,
+        .offset   = offsetof(IntelHDAState, dp_lbase),
+    },
+    [ ICH6_REG_DPUBASE ] = {
+        .name     = "DPUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, dp_ubase),
+    },
+
+    [ ICH6_REG_IC ] = {
+        .name     = "ICW",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, icw),
+    },
+    [ ICH6_REG_IR ] = {
+        .name     = "IRR",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, irr),
+    },
+    [ ICH6_REG_IRS ] = {
+        .name     = "ICS",
+        .size     = 2,
+        .wmask    = 0x0003,
+        .wclear   = 0x0002,
+        .offset   = offsetof(IntelHDAState, ics),
+        .whandler = intel_hda_set_ics,
+    },
+
+#define HDA_STREAM(_t, _i)                                            \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0x1cff001f,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(stnr)",                    \
+        .size     = 1,                                                \
+        .shift    = 16,                                               \
+        .wmask    = 0x00ff0000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_STS)] = {                                \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(sts)",                     \
+        .size     = 1,                                                \
+        .shift    = 24,                                               \
+        .wmask    = 0x1c000000,                                       \
+        .wclear   = 0x1c000000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = {                              \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB",                         \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = {                     \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB(alias)",                  \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CBL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CBL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].cbl),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LVI) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LVI",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x00ff,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].lvi),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = {                          \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FIFOS",                        \
+        .size     = 2,                                                \
+        .reset    = HDA_BUFFER_SIZE,                                  \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FMT",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x7f7f,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].fmt),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPL",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffff80,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_lbase),       \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPU",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_ubase),       \
+    },                                                                \
+
+    HDA_STREAM("IN", 0)
+    HDA_STREAM("IN", 1)
+    HDA_STREAM("IN", 2)
+    HDA_STREAM("IN", 3)
+
+    HDA_STREAM("OUT", 4)
+    HDA_STREAM("OUT", 5)
+    HDA_STREAM("OUT", 6)
+    HDA_STREAM("OUT", 7)
+
+};
+
+static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, target_phys_addr_t addr)
+{
+    const IntelHDAReg *reg;
+
+    if (addr >= sizeof(regtab)/sizeof(regtab[0])) {
+        goto noreg;
+    }
+    reg = regtab+addr;
+    if (reg->name == NULL) {
+        goto noreg;
+    }
+    return reg;
+
+noreg:
+    dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
+    return NULL;
+}
+
+static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    uint8_t *addr = (void*)d;
+
+    addr += reg->offset;
+    return (uint32_t*)addr;
+}
+
+static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
+                                uint32_t wmask)
+{
+    uint32_t *addr;
+    uint32_t old;
+
+    if (!reg) {
+        return;
+    }
+
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (d->last_write && d->last_reg == reg && d->last_val == val) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
+            d->last_write = 1;
+            d->last_reg   = reg;
+            d->last_val   = val;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    assert(reg->offset != 0);
+
+    addr = intel_hda_reg_addr(d, reg);
+    old = *addr;
+
+    if (reg->shift) {
+        val <<= reg->shift;
+        wmask <<= reg->shift;
+    }
+    wmask &= reg->wmask;
+    *addr &= ~wmask;
+    *addr |= wmask & val;
+    *addr &= ~(val & reg->wclear);
+
+    if (reg->whandler) {
+        reg->whandler(d, reg, old);
+    }
+}
+
+static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
+                                   uint32_t rmask)
+{
+    uint32_t *addr, ret;
+
+    if (!reg) {
+        return 0;
+    }
+
+    if (reg->rhandler) {
+        reg->rhandler(d, reg);
+    }
+
+    if (reg->offset == 0) {
+        /* constant read-only register */
+        ret = reg->reset;
+    } else {
+        addr = intel_hda_reg_addr(d, reg);
+        ret = *addr;
+        if (reg->shift) {
+            ret >>= reg->shift;
+        }
+        ret &= rmask;
+    }
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "read  %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
+            d->last_write = 0;
+            d->last_reg   = reg;
+            d->last_val   = ret;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    return ret;
+}
+
+static void intel_hda_regs_reset(IntelHDAState *d)
+{
+    uint32_t *addr;
+    int i;
+
+    for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) {
+        if (regtab[i].name == NULL) {
+            continue;
+        }
+        if (regtab[i].offset == 0) {
+            continue;
+        }
+        addr = intel_hda_reg_addr(d, regtab + i);
+        *addr = regtab[i].reset;
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xff);
+}
+
+static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffff);
+}
+
+static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffffffff);
+}
+
+static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xff);
+}
+
+static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffff);
+}
+
+static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffffffff);
+}
+
+static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
+    intel_hda_mmio_readb,
+    intel_hda_mmio_readw,
+    intel_hda_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
+    intel_hda_mmio_writeb,
+    intel_hda_mmio_writew,
+    intel_hda_mmio_writel,
+};
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_reset(DeviceState *dev)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    intel_hda_regs_reset(d);
+    d->wall_base_ns = qemu_get_clock_ns(vm_clock);
+
+    /* reset codecs */
+    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (qdev->info->reset) {
+            qdev->info->reset(qdev);
+        }
+        d->state_sts |= (1 << cdev->cad);
+    }
+    intel_hda_update_irq(d);
+}
+
+static int intel_hda_init(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+    uint8_t *conf = d->pci.config;
+
+    d->name = d->pci.qdev.info->name;
+
+    pci_config_set_interrupt_pin(conf, 1);
+
+    /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
+    conf[0x40] = 0x01;
+
+    d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
+                                          intel_hda_mmio_write, d,
+                                          DEVICE_NATIVE_ENDIAN);
+    pci_register_bar_simple(&d->pci, 0, 0x4000, 0, d->mmio_addr);
+    if (d->msi) {
+        msi_init(&d->pci, 0x50, 1, true, false);
+    }
+
+    hda_codec_bus_init(&d->pci.qdev, &d->codecs,
+                       intel_hda_response, intel_hda_xfer);
+
+    return 0;
+}
+
+static int intel_hda_exit(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    msi_uninit(&d->pci);
+    cpu_unregister_io_memory(d->mmio_addr);
+    return 0;
+}
+
+static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
+                                   uint32_t val, int len)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    pci_default_write_config(pci, addr, val, len);
+    if (d->msi) {
+        msi_write_config(pci, addr, val, len);
+    }
+}
+
+static int intel_hda_post_load(void *opaque, int version)
+{
+    IntelHDAState* d = opaque;
+    int i;
+
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(d->st); i++) {
+        if (d->st[i].ctl & 0x02) {
+            intel_hda_parse_bdl(d, &d->st[i]);
+        }
+    }
+    intel_hda_update_irq(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intel_hda_stream = {
+    .name = "intel-hda-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(ctl, IntelHDAStream),
+        VMSTATE_UINT32(lpib, IntelHDAStream),
+        VMSTATE_UINT32(cbl, IntelHDAStream),
+        VMSTATE_UINT32(lvi, IntelHDAStream),
+        VMSTATE_UINT32(fmt, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intel_hda = {
+    .name = "intel-hda",
+    .version_id = 1,
+    .post_load = intel_hda_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci, IntelHDAState),
+
+        /* registers */
+        VMSTATE_UINT32(g_ctl, IntelHDAState),
+        VMSTATE_UINT32(wake_en, IntelHDAState),
+        VMSTATE_UINT32(state_sts, IntelHDAState),
+        VMSTATE_UINT32(int_ctl, IntelHDAState),
+        VMSTATE_UINT32(int_sts, IntelHDAState),
+        VMSTATE_UINT32(wall_clk, IntelHDAState),
+        VMSTATE_UINT32(corb_lbase, IntelHDAState),
+        VMSTATE_UINT32(corb_ubase, IntelHDAState),
+        VMSTATE_UINT32(corb_rp, IntelHDAState),
+        VMSTATE_UINT32(corb_wp, IntelHDAState),
+        VMSTATE_UINT32(corb_ctl, IntelHDAState),
+        VMSTATE_UINT32(corb_sts, IntelHDAState),
+        VMSTATE_UINT32(corb_size, IntelHDAState),
+        VMSTATE_UINT32(rirb_lbase, IntelHDAState),
+        VMSTATE_UINT32(rirb_ubase, IntelHDAState),
+        VMSTATE_UINT32(rirb_wp, IntelHDAState),
+        VMSTATE_UINT32(rirb_cnt, IntelHDAState),
+        VMSTATE_UINT32(rirb_ctl, IntelHDAState),
+        VMSTATE_UINT32(rirb_sts, IntelHDAState),
+        VMSTATE_UINT32(rirb_size, IntelHDAState),
+        VMSTATE_UINT32(dp_lbase, IntelHDAState),
+        VMSTATE_UINT32(dp_ubase, IntelHDAState),
+        VMSTATE_UINT32(icw, IntelHDAState),
+        VMSTATE_UINT32(irr, IntelHDAState),
+        VMSTATE_UINT32(ics, IntelHDAState),
+        VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
+                             vmstate_intel_hda_stream,
+                             IntelHDAStream),
+
+        /* additional state info */
+        VMSTATE_UINT32(rirb_count, IntelHDAState),
+        VMSTATE_INT64(wall_base_ns, IntelHDAState),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo intel_hda_info = {
+    .qdev.name    = "intel-hda",
+    .qdev.desc    = "Intel HD Audio Controller",
+    .qdev.size    = sizeof(IntelHDAState),
+    .qdev.vmsd    = &vmstate_intel_hda,
+    .qdev.reset   = intel_hda_reset,
+    .init         = intel_hda_init,
+    .exit         = intel_hda_exit,
+    .config_write = intel_hda_write_config,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = 0x2668,
+    .revision     = 1,
+    .class_id     = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+        DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void intel_hda_register(void)
+{
+    pci_qdev_register(&intel_hda_info);
+}
+device_init(intel_hda_register);
+
+/*
+ * create intel hda controller with codec attached to it,
+ * so '-soundhw hda' works.
+ */
+int intel_hda_and_codec_init(PCIBus *bus)
+{
+    PCIDevice *controller;
+    BusState *hdabus;
+    DeviceState *codec;
+
+    controller = pci_create_simple(bus, -1, "intel-hda");
+    hdabus = QLIST_FIRST(&controller->qdev.child_bus);
+    codec = qdev_create(hdabus, "hda-duplex");
+    qdev_init_nofail(codec);
+    return 0;
+}
+
diff --git a/qemu-0.15.x/hw/intel-hda.h b/qemu-0.15.x/hw/intel-hda.h
new file mode 100644
index 0000000..4e44e38
--- /dev/null
+++ b/qemu-0.15.x/hw/intel-hda.h
@@ -0,0 +1,62 @@
+#ifndef HW_INTEL_HDA_H
+#define HW_INTEL_HDA_H
+
+#include "qdev.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus                                                               */
+
+typedef struct HDACodecBus HDACodecBus;
+typedef struct HDACodecDevice HDACodecDevice;
+typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
+
+typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
+                                        bool solicited, uint32_t response);
+typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
+                                    uint32_t stnr, bool output,
+                                    uint8_t *buf, uint32_t len);
+
+struct HDACodecBus {
+    BusState qbus;
+    uint32_t next_cad;
+    hda_codec_response_func response;
+    hda_codec_xfer_func xfer;
+};
+
+struct HDACodecDevice {
+    DeviceState         qdev;
+    HDACodecDeviceInfo  *info;
+    uint32_t            cad;    /* codec address */
+};
+
+struct HDACodecDeviceInfo {
+    DeviceInfo qdev;
+    int (*init)(HDACodecDevice *dev);
+    int (*exit)(HDACodecDevice *dev);
+    void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
+    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+                        hda_codec_response_func response,
+                        hda_codec_xfer_func xfer);
+void hda_codec_register(HDACodecDeviceInfo *info);
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len);
+
+/* --------------------------------------------------------------------- */
+
+#define dprint(_dev, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_dev->debug >= _level) {                                    \
+            fprintf(stderr, "%s: ", _dev->name);                        \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/qemu-0.15.x/hw/ioapic.c b/qemu-0.15.x/hw/ioapic.c
new file mode 100644
index 0000000..6c26e82
--- /dev/null
+++ b/qemu-0.15.x/hw/ioapic.c
@@ -0,0 +1,359 @@
+/*
+ *  ioapic.c IOAPIC emulation logic
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ *  Split the ioapic logic from apic.c
+ *  Xiantao Zhang <xiantao.zhang at intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "apic.h"
+#include "ioapic.h"
+#include "qemu-timer.h"
+#include "host-utils.h"
+#include "sysbus.h"
+
+//#define DEBUG_IOAPIC
+
+#ifdef DEBUG_IOAPIC
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define MAX_IOAPICS                     1
+
+#define IOAPIC_VERSION                  0x11
+
+#define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_MASKED_SHIFT         16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
+#define IOAPIC_LVT_POLARITY_SHIFT       13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
+#define IOAPIC_LVT_DEST_MODE_SHIFT      11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
+
+#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE             0
+#define IOAPIC_TRIGGER_LEVEL            1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED                 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY       0x1
+#define IOAPIC_DM_PMI                   0x2
+#define IOAPIC_DM_NMI                   0x4
+#define IOAPIC_DM_INIT                  0x5
+#define IOAPIC_DM_SIPI                  0x6
+#define IOAPIC_DM_EXTINT                0x7
+#define IOAPIC_DM_MASK                  0x7
+
+#define IOAPIC_VECTOR_MASK              0xff
+
+#define IOAPIC_IOREGSEL                 0x00
+#define IOAPIC_IOWIN                    0x10
+
+#define IOAPIC_REG_ID                   0x00
+#define IOAPIC_REG_VER                  0x01
+#define IOAPIC_REG_ARB                  0x02
+#define IOAPIC_REG_REDTBL_BASE          0x10
+#define IOAPIC_ID                       0x00
+
+#define IOAPIC_ID_SHIFT                 24
+#define IOAPIC_ID_MASK                  0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT        16
+
+typedef struct IOAPICState IOAPICState;
+
+struct IOAPICState {
+    SysBusDevice busdev;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+static IOAPICState *ioapics[MAX_IOAPICS];
+
+static void ioapic_service(IOAPICState *s)
+{
+    uint8_t i;
+    uint8_t trig_mode;
+    uint8_t vector;
+    uint8_t delivery_mode;
+    uint32_t mask;
+    uint64_t entry;
+    uint8_t dest;
+    uint8_t dest_mode;
+    uint8_t polarity;
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        mask = 1 << i;
+        if (s->irr & mask) {
+            entry = s->ioredtbl[i];
+            if (!(entry & IOAPIC_LVT_MASKED)) {
+                trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
+                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
+                dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
+                delivery_mode =
+                    (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
+                polarity = (entry >> IOAPIC_LVT_POLARITY_SHIFT) & 1;
+                if (trig_mode == IOAPIC_TRIGGER_EDGE) {
+                    s->irr &= ~mask;
+                } else {
+                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
+                }
+                if (delivery_mode == IOAPIC_DM_EXTINT) {
+                    vector = pic_read_irq(isa_pic);
+                } else {
+                    vector = entry & IOAPIC_VECTOR_MASK;
+                }
+                apic_deliver_irq(dest, dest_mode, delivery_mode,
+                                 vector, polarity, trig_mode);
+            }
+        }
+    }
+}
+
+static void ioapic_set_irq(void *opaque, int vector, int level)
+{
+    IOAPICState *s = opaque;
+
+    /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
+     * to GSI 2.  GSI maps to ioapic 1-1.  This is not
+     * the cleanest way of doing it but it should work. */
+
+    DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
+    if (vector == 0) {
+        vector = 2;
+    }
+    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
+        uint32_t mask = 1 << vector;
+        uint64_t entry = s->ioredtbl[vector];
+
+        if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
+            IOAPIC_TRIGGER_LEVEL) {
+            /* level triggered */
+            if (level) {
+                s->irr |= mask;
+                ioapic_service(s);
+            } else {
+                s->irr &= ~mask;
+            }
+        } else {
+            /* According to the 82093AA manual, we must ignore edge requests
+             * if the input pin is masked. */
+            if (level && !(entry & IOAPIC_LVT_MASKED)) {
+                s->irr |= mask;
+                ioapic_service(s);
+            }
+        }
+    }
+}
+
+void ioapic_eoi_broadcast(int vector)
+{
+    IOAPICState *s;
+    uint64_t entry;
+    int i, n;
+
+    for (i = 0; i < MAX_IOAPICS; i++) {
+        s = ioapics[i];
+        if (!s) {
+            continue;
+        }
+        for (n = 0; n < IOAPIC_NUM_PINS; n++) {
+            entry = s->ioredtbl[n];
+            if ((entry & IOAPIC_LVT_REMOTE_IRR)
+                && (entry & IOAPIC_VECTOR_MASK) == vector) {
+                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
+                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
+                    ioapic_service(s);
+                }
+            }
+        }
+    }
+}
+
+static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    IOAPICState *s = opaque;
+    int index;
+    uint32_t val = 0;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        val = s->ioregsel;
+        break;
+    case IOAPIC_IOWIN:
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            val = s->id << IOAPIC_ID_SHIFT;
+            break;
+        case IOAPIC_REG_VER:
+            val = IOAPIC_VERSION |
+                ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
+            break;
+        case IOAPIC_REG_ARB:
+            val = 0;
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    val = s->ioredtbl[index] >> 32;
+                } else {
+                    val = s->ioredtbl[index] & 0xffffffff;
+                }
+            }
+        }
+        DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
+        break;
+    }
+    return val;
+}
+
+static void
+ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IOAPICState *s = opaque;
+    int index;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        s->ioregsel = val;
+        break;
+    case IOAPIC_IOWIN:
+        DPRINTF("write: %08x = %08x\n", s->ioregsel, val);
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
+            break;
+        case IOAPIC_REG_VER:
+        case IOAPIC_REG_ARB:
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    s->ioredtbl[index] &= 0xffffffff;
+                    s->ioredtbl[index] |= (uint64_t)val << 32;
+                } else {
+                    s->ioredtbl[index] &= ~0xffffffffULL;
+                    s->ioredtbl[index] |= val;
+                }
+                ioapic_service(s);
+            }
+        }
+        break;
+    }
+}
+
+static int ioapic_post_load(void *opaque, int version_id)
+{
+    IOAPICState *s = opaque;
+
+    if (version_id == 1) {
+        /* set sane value */
+        s->irr = 0;
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_ioapic = {
+    .name = "ioapic",
+    .version_id = 3,
+    .post_load = ioapic_post_load,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICState),
+        VMSTATE_UINT8(ioregsel, IOAPICState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ioapic_reset(DeviceState *d)
+{
+    IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+static CPUReadMemoryFunc * const ioapic_mem_read[3] = {
+    ioapic_mem_readl,
+    ioapic_mem_readl,
+    ioapic_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const ioapic_mem_write[3] = {
+    ioapic_mem_writel,
+    ioapic_mem_writel,
+    ioapic_mem_writel,
+};
+
+static int ioapic_init1(SysBusDevice *dev)
+{
+    IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
+    int io_memory;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    io_memory = cpu_register_io_memory(ioapic_mem_read,
+                                       ioapic_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, io_memory);
+
+    qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+
+    ioapics[ioapic_no++] = s;
+
+    return 0;
+}
+
+static SysBusDeviceInfo ioapic_info = {
+    .init = ioapic_init1,
+    .qdev.name = "ioapic",
+    .qdev.size = sizeof(IOAPICState),
+    .qdev.vmsd = &vmstate_ioapic,
+    .qdev.reset = ioapic_reset,
+    .qdev.no_user = 1,
+};
+
+static void ioapic_register_devices(void)
+{
+    sysbus_register_withprop(&ioapic_info);
+}
+
+device_init(ioapic_register_devices)
diff --git a/qemu-0.15.x/hw/ioapic.h b/qemu-0.15.x/hw/ioapic.h
new file mode 100644
index 0000000..cb2642a
--- /dev/null
+++ b/qemu-0.15.x/hw/ioapic.h
@@ -0,0 +1,20 @@
+/*
+ *  ioapic.c IOAPIC emulation logic
+ *
+ *  Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+void ioapic_eoi_broadcast(int vector);
diff --git a/qemu-0.15.x/hw/ioh3420.c b/qemu-0.15.x/hw/ioh3420.c
new file mode 100644
index 0000000..a6bfbb9
--- /dev/null
+++ b/qemu-0.15.x/hw/ioh3420.c
@@ -0,0 +1,245 @@
+/*
+ * ioh3420.c
+ * Intel X58 north bridge IOH
+ * PCI Express root port device id 3420
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "ioh3420.h"
+
+#define PCI_DEVICE_ID_IOH_EPORT         0x3420  /* D0:F0 express mode */
+#define PCI_DEVICE_ID_IOH_REV           0x2
+#define IOH_EP_SSVID_OFFSET             0x40
+#define IOH_EP_SSVID_SVID               PCI_VENDOR_ID_INTEL
+#define IOH_EP_SSVID_SSID               0
+#define IOH_EP_MSI_OFFSET               0x60
+#define IOH_EP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
+#define IOH_EP_MSI_NR_VECTOR            2
+#define IOH_EP_EXP_OFFSET               0x90
+#define IOH_EP_AER_OFFSET               0x100
+
+/*
+ * If two MSI vector are allocated, Advanced Error Interrupt Message Number
+ * is 1. otherwise 0.
+ * 17.12.5.10 RPERRSTS,  32:27 bit Advanced Error Interrupt Message Number.
+ */
+static uint8_t ioh3420_aer_vector(const PCIDevice *d)
+{
+    switch (msi_nr_vectors_allocated(d)) {
+    case 1:
+        return 0;
+    case 2:
+        return 1;
+    case 4:
+    case 8:
+    case 16:
+    case 32:
+    default:
+        break;
+    }
+    abort();
+    return 0;
+}
+
+static void ioh3420_aer_vector_update(PCIDevice *d)
+{
+    pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
+}
+
+static void ioh3420_write_config(PCIDevice *d,
+                                   uint32_t address, uint32_t val, int len)
+{
+    uint32_t root_cmd =
+        pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
+
+    pci_bridge_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    ioh3420_aer_vector_update(d);
+    pcie_cap_slot_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+    pcie_aer_root_write_config(d, address, val, len, root_cmd);
+}
+
+static void ioh3420_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    ioh3420_aer_vector_update(d);
+    pcie_cap_root_reset(d);
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pcie_aer_root_reset(d);
+    pci_bridge_reset(qdev);
+    pci_bridge_disable_base_limit(d);
+}
+
+static int ioh3420_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+    int tmp;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
+                               IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        goto err_pcie_cap;
+        return rc;
+    }
+    pcie_cap_root_init(d);
+    rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+    pcie_aer_root_init(d);
+    ioh3420_aer_vector_update(d);
+    return 0;
+
+err:
+    pcie_chassis_del_slot(s);
+err_pcie_cap:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    tmp = pci_bridge_exitfn(d);
+    assert(!tmp);
+    return rc;
+}
+
+static int ioh3420_exitfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+
+    pcie_aer_exit(d);
+    pcie_chassis_del_slot(s);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                         const char *bus_name, pci_map_irq_fn map_irq,
+                         uint8_t port, uint8_t chassis, uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_ioh3420 = {
+    .name = "ioh-3240-express-root-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
+                       vmstate_pcie_aer_log, PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo ioh3420_info = {
+    .qdev.name = "ioh3420",
+    .qdev.desc = "Intel IOH device id 3420 PCIE Root Port",
+    .qdev.size = sizeof(PCIESlot),
+    .qdev.reset = ioh3420_reset,
+    .qdev.vmsd = &vmstate_ioh3420,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = ioh3420_write_config,
+    .init = ioh3420_initfn,
+    .exit = ioh3420_exitfn,
+    .vendor_id = PCI_VENDOR_ID_INTEL,
+    .device_id = PCI_DEVICE_ID_IOH_EPORT,
+    .revision = PCI_DEVICE_ID_IOH_REV,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+        DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+                           port.br.dev.exp.aer_log.log_max,
+                           PCIE_AER_LOG_MAX_DEFAULT),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ioh3420_register(void)
+{
+    pci_qdev_register(&ioh3420_info);
+}
+
+device_init(ioh3420_register);
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/qemu-0.15.x/hw/ioh3420.h b/qemu-0.15.x/hw/ioh3420.h
new file mode 100644
index 0000000..68c523a
--- /dev/null
+++ b/qemu-0.15.x/hw/ioh3420.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_IOH3420_H
+#define QEMU_IOH3420_H
+
+#include "pcie_port.h"
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                       const char *bus_name, pci_map_irq_fn map_irq,
+                       uint8_t port, uint8_t chassis, uint16_t slot);
+
+#endif /* QEMU_IOH3420_H */
diff --git a/qemu-0.15.x/hw/irq.c b/qemu-0.15.x/hw/irq.c
new file mode 100644
index 0000000..4035a8c
--- /dev/null
+++ b/qemu-0.15.x/hw/irq.c
@@ -0,0 +1,92 @@
+/*
+ * 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 "qemu-common.h"
+#include "irq.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+    if (!irq)
+        return;
+
+    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;
+}
+
+void qemu_free_irqs(qemu_irq *s)
+{
+    qemu_free(s[0]);
+    qemu_free(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)
+{
+    /* The default state for IRQs is low, so raise the output now.  */
+    qemu_irq_raise(irq);
+    return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
+}
+
+static void qemu_splitirq(void *opaque, int line, int level)
+{
+    struct IRQState **irq = opaque;
+    irq[0]->handler(irq[0]->opaque, irq[0]->n, level);
+    irq[1]->handler(irq[1]->opaque, irq[1]->n, level);
+}
+
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
+{
+    qemu_irq *s = qemu_mallocz(2 * sizeof(qemu_irq));
+    s[0] = irq1;
+    s[1] = irq2;
+    return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
+}
diff --git a/qemu-0.15.x/hw/irq.h b/qemu-0.15.x/hw/irq.h
new file mode 100644
index 0000000..389ed7a
--- /dev/null
+++ b/qemu-0.15.x/hw/irq.h
@@ -0,0 +1,36 @@
+#ifndef QEMU_IRQ_H
+#define QEMU_IRQ_H
+
+/* Generic IRQ/GPIO pin infrastructure.  */
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+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);
+}
+
+static inline void qemu_irq_pulse(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+    qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs.  */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+void qemu_free_irqs(qemu_irq *s);
+
+/* Returns a new IRQ with opposite polarity.  */
+qemu_irq qemu_irq_invert(qemu_irq irq);
+
+/* Returns a new IRQ which feeds into both the passed IRQs */
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
+
+#endif
diff --git a/qemu-0.15.x/hw/isa-bus.c b/qemu-0.15.x/hw/isa-bus.c
new file mode 100644
index 0000000..2765543
--- /dev/null
+++ b/qemu-0.15.x/hw/isa-bus.c
@@ -0,0 +1,205 @@
+/*
+ * isa bus support for qdev.
+ *
+ * Copyright (c) 2009 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "isa.h"
+
+struct ISABus {
+    BusState qbus;
+    qemu_irq *irqs;
+};
+static ISABus *isabus;
+target_phys_addr_t isa_mem_base = 0;
+
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *isabus_get_fw_dev_path(DeviceState *dev);
+
+static struct BusInfo isa_bus_info = {
+    .name      = "ISA",
+    .size      = sizeof(ISABus),
+    .print_dev = isabus_dev_print,
+    .get_fw_dev_path = isabus_get_fw_dev_path,
+};
+
+ISABus *isa_bus_new(DeviceState *dev)
+{
+    if (isabus) {
+        fprintf(stderr, "Can't create a second ISA bus\n");
+        return NULL;
+    }
+    if (NULL == dev) {
+        dev = qdev_create(NULL, "isabus-bridge");
+        qdev_init_nofail(dev);
+    }
+
+    isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL));
+    return isabus;
+}
+
+void isa_bus_irqs(qemu_irq *irqs)
+{
+    isabus->irqs = irqs;
+}
+
+/*
+ * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
+ *
+ * This function is only for special cases such as the 'ferr', and
+ * temporary use for normal devices until they are converted to qdev.
+ */
+qemu_irq isa_get_irq(int isairq)
+{
+    if (isairq < 0 || isairq > 15) {
+        hw_error("isa irq %d invalid", isairq);
+    }
+    return isabus->irqs[isairq];
+}
+
+void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
+{
+    assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
+    dev->isairq[dev->nirqs] = isairq;
+    *p = isa_get_irq(isairq);
+    dev->nirqs++;
+}
+
+static void isa_init_ioport_one(ISADevice *dev, uint16_t ioport)
+{
+    assert(dev->nioports < ARRAY_SIZE(dev->ioports));
+    dev->ioports[dev->nioports++] = ioport;
+}
+
+static int isa_cmp_ports(const void *p1, const void *p2)
+{
+    return *(uint16_t*)p1 - *(uint16_t*)p2;
+}
+
+void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length)
+{
+    int i;
+    for (i = start; i < start + length; i++) {
+        isa_init_ioport_one(dev, i);
+    }
+    qsort(dev->ioports, dev->nioports, sizeof(dev->ioports[0]), isa_cmp_ports);
+}
+
+void isa_init_ioport(ISADevice *dev, uint16_t ioport)
+{
+    isa_init_ioport_range(dev, ioport, 1);
+}
+
+static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
+    ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base);
+
+    dev->isairq[0] = -1;
+    dev->isairq[1] = -1;
+
+    return info->init(dev);
+}
+
+void isa_qdev_register(ISADeviceInfo *info)
+{
+    info->qdev.init = isa_qdev_init;
+    info->qdev.bus_info = &isa_bus_info;
+    qdev_register(&info->qdev);
+}
+
+ISADevice *isa_create(const char *name)
+{
+    DeviceState *dev;
+
+    if (!isabus) {
+        hw_error("Tried to create isa device %s with no isa bus present.",
+                 name);
+    }
+    dev = qdev_create(&isabus->qbus, name);
+    return DO_UPCAST(ISADevice, qdev, dev);
+}
+
+ISADevice *isa_try_create(const char *name)
+{
+    DeviceState *dev;
+
+    if (!isabus) {
+        hw_error("Tried to create isa device %s with no isa bus present.",
+                 name);
+    }
+    dev = qdev_try_create(&isabus->qbus, name);
+    return DO_UPCAST(ISADevice, qdev, dev);
+}
+
+ISADevice *isa_create_simple(const char *name)
+{
+    ISADevice *dev;
+
+    dev = isa_create(name);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+}
+
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
+
+    if (d->isairq[1] != -1) {
+        monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
+                       d->isairq[0], d->isairq[1]);
+    } else if (d->isairq[0] != -1) {
+        monitor_printf(mon, "%*sisa irq %d\n", indent, "",
+                       d->isairq[0]);
+    }
+}
+
+static int isabus_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static SysBusDeviceInfo isabus_bridge_info = {
+    .init = isabus_bridge_init,
+    .qdev.name  = "isabus-bridge",
+    .qdev.fw_name  = "isa",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.no_user = 1,
+};
+
+static void isabus_register_devices(void)
+{
+    sysbus_register_withprop(&isabus_bridge_info);
+}
+
+static char *isabus_get_fw_dev_path(DeviceState *dev)
+{
+    ISADevice *d = (ISADevice*)dev;
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+    if (d->nioports) {
+        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioports[0]);
+    }
+
+    return strdup(path);
+}
+
+device_init(isabus_register_devices)
diff --git a/qemu-0.15.x/hw/isa.h b/qemu-0.15.x/hw/isa.h
new file mode 100644
index 0000000..d2b6126
--- /dev/null
+++ b/qemu-0.15.x/hw/isa.h
@@ -0,0 +1,53 @@
+#ifndef HW_ISA_H
+#define HW_ISA_H
+
+/* ISA bus */
+
+#include "ioport.h"
+#include "qdev.h"
+
+typedef struct ISABus ISABus;
+typedef struct ISADevice ISADevice;
+typedef struct ISADeviceInfo ISADeviceInfo;
+
+struct ISADevice {
+    DeviceState qdev;
+    uint32_t isairq[2];
+    int nirqs;
+    uint16_t ioports[32];
+    int nioports;
+};
+
+typedef int (*isa_qdev_initfn)(ISADevice *dev);
+struct ISADeviceInfo {
+    DeviceInfo qdev;
+    isa_qdev_initfn init;
+};
+
+ISABus *isa_bus_new(DeviceState *dev);
+void isa_bus_irqs(qemu_irq *irqs);
+qemu_irq isa_get_irq(int isairq);
+void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
+void isa_init_ioport(ISADevice *dev, uint16_t ioport);
+void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
+void isa_qdev_register(ISADeviceInfo *info);
+ISADevice *isa_create(const char *name);
+ISADevice *isa_try_create(const char *name);
+ISADevice *isa_create_simple(const char *name);
+
+extern target_phys_addr_t isa_mem_base;
+
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size);
+
+/* dma.c */
+int DMA_get_channel_mode (int nchan);
+int DMA_read_memory (int nchan, void *buf, int pos, int size);
+int DMA_write_memory (int nchan, void *buf, int pos, int size);
+void DMA_hold_DREQ (int nchan);
+void DMA_release_DREQ (int nchan);
+void DMA_schedule(int nchan);
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit);
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque);
+#endif
diff --git a/qemu-0.15.x/hw/isa_mmio.c b/qemu-0.15.x/hw/isa_mmio.c
new file mode 100644
index 0000000..ca957fb
--- /dev/null
+++ b/qemu-0.15.x/hw/isa_mmio.c
@@ -0,0 +1,82 @@
+/*
+ * Memory mapped access to ISA IO space.
+ *
+ * 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 "hw.h"
+#include "isa.h"
+
+static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    cpu_outb(addr & IOPORTS_MASK, val);
+}
+
+static void isa_mmio_writew(void *opaque, target_phys_addr_t addr,
+                               uint32_t val)
+{
+    cpu_outw(addr & IOPORTS_MASK, val);
+}
+
+static void isa_mmio_writel(void *opaque, target_phys_addr_t addr,
+                               uint32_t val)
+{
+    cpu_outl(addr & IOPORTS_MASK, val);
+}
+
+static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inb(addr & IOPORTS_MASK);
+}
+
+static uint32_t isa_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inw(addr & IOPORTS_MASK);
+}
+
+static uint32_t isa_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inl(addr & IOPORTS_MASK);
+}
+
+static CPUWriteMemoryFunc * const isa_mmio_write[] = {
+    &isa_mmio_writeb,
+    &isa_mmio_writew,
+    &isa_mmio_writel,
+};
+
+static CPUReadMemoryFunc * const isa_mmio_read[] = {
+    &isa_mmio_readb,
+    &isa_mmio_readw,
+    &isa_mmio_readl,
+};
+
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
+{
+    int isa_mmio_iomemtype;
+
+    isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read,
+                                                isa_mmio_write,
+                                                NULL,
+                                                DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
+}
diff --git a/qemu-0.15.x/hw/ivshmem.c b/qemu-0.15.x/hw/ivshmem.c
new file mode 100644
index 0000000..3055dd2
--- /dev/null
+++ b/qemu-0.15.x/hw/ivshmem.c
@@ -0,0 +1,827 @@
+/*
+ * Inter-VM Shared Memory PCI device.
+ *
+ * Author:
+ *      Cam Macdonell <cam at cs.ualberta.ca>
+ *
+ * Based On: cirrus_vga.c
+ *          Copyright (c) 2004 Fabrice Bellard
+ *          Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ *      and rtl8139.c
+ *          Copyright (c) 2006 Igor Kovalenko
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "msix.h"
+#include "kvm.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#define IVSHMEM_IOEVENTFD   0
+#define IVSHMEM_MSI     1
+
+#define IVSHMEM_PEER    0
+#define IVSHMEM_MASTER  1
+
+#define IVSHMEM_REG_BAR_SIZE 0x100
+
+//#define DEBUG_IVSHMEM
+#ifdef DEBUG_IVSHMEM
+#define IVSHMEM_DPRINTF(fmt, ...)        \
+    do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define IVSHMEM_DPRINTF(fmt, ...)
+#endif
+
+typedef struct Peer {
+    int nb_eventfds;
+    int *eventfds;
+} Peer;
+
+typedef struct EventfdEntry {
+    PCIDevice *pdev;
+    int vector;
+} EventfdEntry;
+
+typedef struct IVShmemState {
+    PCIDevice dev;
+    uint32_t intrmask;
+    uint32_t intrstatus;
+    uint32_t doorbell;
+
+    CharDriverState **eventfd_chr;
+    CharDriverState *server_chr;
+    int ivshmem_mmio_io_addr;
+
+    pcibus_t mmio_addr;
+    pcibus_t shm_pci_addr;
+    uint64_t ivshmem_offset;
+    uint64_t ivshmem_size; /* size of shared memory region */
+    int shm_fd; /* shared memory file descriptor */
+
+    Peer *peers;
+    int nb_peers; /* how many guests we have space for */
+    int max_peer; /* maximum numbered peer */
+
+    int vm_id;
+    uint32_t vectors;
+    uint32_t features;
+    EventfdEntry *eventfd_table;
+
+    char * shmobj;
+    char * sizearg;
+    char * role;
+    int role_val;   /* scalar to avoid multiple string comparisons */
+} IVShmemState;
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+    INTRMASK = 0,
+    INTRSTATUS = 4,
+    IVPOSITION = 8,
+    DOORBELL = 12,
+};
+
+static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
+                                                    unsigned int feature) {
+    return (ivs->features & (1 << feature));
+}
+
+static inline bool is_power_of_two(uint64_t x) {
+    return (x & (x - 1)) == 0;
+}
+
+static void ivshmem_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+    s->shm_pci_addr = addr;
+
+    if (s->ivshmem_offset > 0) {
+        cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+                                                            s->ivshmem_offset);
+    }
+
+    IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+        PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
+
+}
+
+/* accessing registers - based on rtl8139 */
+static void ivshmem_update_irq(IVShmemState *s, int val)
+{
+    int isr;
+    isr = (s->intrstatus & s->intrmask) & 0xffffffff;
+
+    /* don't print ISR resets */
+    if (isr) {
+        IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
+           isr ? 1 : 0, s->intrstatus, s->intrmask);
+    }
+
+    qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
+
+    s->intrmask = val;
+
+    ivshmem_update_irq(s, val);
+}
+
+static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrmask;
+
+    IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
+
+    return ret;
+}
+
+static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
+
+    s->intrstatus = val;
+
+    ivshmem_update_irq(s, val);
+    return;
+}
+
+static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrstatus;
+
+    /* reading ISR clears all interrupts */
+    s->intrstatus = 0;
+
+    ivshmem_update_irq(s, 0);
+
+    return ret;
+}
+
+static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
+                                                            uint32_t val)
+{
+
+    IVSHMEM_DPRINTF("We shouldn't be writing words\n");
+}
+
+static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
+                                                            uint32_t val)
+{
+    IVShmemState *s = opaque;
+
+    uint64_t write_one = 1;
+    uint16_t dest = val >> 16;
+    uint16_t vector = val & 0xff;
+
+    addr &= 0xfc;
+
+    IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
+    switch (addr)
+    {
+        case INTRMASK:
+            ivshmem_IntrMask_write(s, val);
+            break;
+
+        case INTRSTATUS:
+            ivshmem_IntrStatus_write(s, val);
+            break;
+
+        case DOORBELL:
+            /* check that dest VM ID is reasonable */
+            if (dest > s->max_peer) {
+                IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
+                break;
+            }
+
+            /* check doorbell range */
+            if (vector < s->peers[dest].nb_eventfds) {
+                IVSHMEM_DPRINTF("Writing %" PRId64 " to VM %d on vector %d\n",
+                                                    write_one, dest, vector);
+                if (write(s->peers[dest].eventfds[vector],
+                                                    &(write_one), 8) != 8) {
+                    IVSHMEM_DPRINTF("error writing to eventfd\n");
+                }
+            }
+            break;
+        default:
+            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
+    }
+}
+
+static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
+                                                                uint32_t val)
+{
+    IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
+}
+
+static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
+{
+
+    IVSHMEM_DPRINTF("We shouldn't be reading words\n");
+    return 0;
+}
+
+static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
+{
+
+    IVShmemState *s = opaque;
+    uint32_t ret;
+
+    switch (addr)
+    {
+        case INTRMASK:
+            ret = ivshmem_IntrMask_read(s);
+            break;
+
+        case INTRSTATUS:
+            ret = ivshmem_IntrStatus_read(s);
+            break;
+
+        case IVPOSITION:
+            /* return my VM ID if the memory is mapped */
+            if (s->shm_fd > 0) {
+                ret = s->vm_id;
+            } else {
+                ret = -1;
+            }
+            break;
+
+        default:
+            IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
+            ret = 0;
+    }
+
+    return ret;
+}
+
+static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
+
+    return 0;
+}
+
+static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
+    ivshmem_io_readb,
+    ivshmem_io_readw,
+    ivshmem_io_readl,
+};
+
+static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
+    ivshmem_io_writeb,
+    ivshmem_io_writew,
+    ivshmem_io_writel,
+};
+
+static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IVShmemState *s = opaque;
+
+    ivshmem_IntrStatus_write(s, *buf);
+
+    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
+}
+
+static int ivshmem_can_receive(void * opaque)
+{
+    return 8;
+}
+
+static void ivshmem_event(void *opaque, int event)
+{
+    IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
+}
+
+static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+
+    EventfdEntry *entry = opaque;
+    PCIDevice *pdev = entry->pdev;
+
+    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
+    msix_notify(pdev, entry->vector);
+}
+
+static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
+                                                                    int vector)
+{
+    /* create a event character device based on the passed eventfd */
+    IVShmemState *s = opaque;
+    CharDriverState * chr;
+
+    chr = qemu_chr_open_eventfd(eventfd);
+
+    if (chr == NULL) {
+        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
+        exit(-1);
+    }
+
+    /* if MSI is supported we need multiple interrupts */
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        s->eventfd_table[vector].pdev = &s->dev;
+        s->eventfd_table[vector].vector = vector;
+
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
+                      ivshmem_event, &s->eventfd_table[vector]);
+    } else {
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
+                      ivshmem_event, s);
+    }
+
+    return chr;
+
+}
+
+static int check_shm_size(IVShmemState *s, int fd) {
+    /* check that the guest isn't going to try and map more memory than the
+     * the object has allocated return -1 to indicate error */
+
+    struct stat buf;
+
+    fstat(fd, &buf);
+
+    if (s->ivshmem_size > buf.st_size) {
+        fprintf(stderr,
+                "IVSHMEM ERROR: Requested memory size greater"
+                " than shared object size (%" PRIu64 " > %" PRIu64")\n",
+                s->ivshmem_size, (uint64_t)buf.st_size);
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* create the shared memory BAR when we are not using the server, so we can
+ * create the BAR and map the memory immediately */
+static void create_shared_memory_BAR(IVShmemState *s, int fd) {
+
+    void * ptr;
+
+    s->shm_fd = fd;
+
+    ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+    s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
+                                                        s->ivshmem_size, ptr);
+
+    /* region for shared memory */
+    pci_register_bar(&s->dev, 2, s->ivshmem_size,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+}
+
+static void close_guest_eventfds(IVShmemState *s, int posn)
+{
+    int i, guest_curr_max;
+
+    guest_curr_max = s->peers[posn].nb_eventfds;
+
+    for (i = 0; i < guest_curr_max; i++) {
+        kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
+                    s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
+        close(s->peers[posn].eventfds[i]);
+    }
+
+    qemu_free(s->peers[posn].eventfds);
+    s->peers[posn].nb_eventfds = 0;
+}
+
+static void setup_ioeventfds(IVShmemState *s) {
+
+    int i, j;
+
+    for (i = 0; i <= s->max_peer; i++) {
+        for (j = 0; j < s->peers[i].nb_eventfds; j++) {
+            kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
+                    s->mmio_addr + DOORBELL, (i << 16) | j, 1);
+        }
+    }
+}
+
+/* this function increase the dynamic storage need to store data about other
+ * guests */
+static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+
+    int j, old_nb_alloc;
+
+    old_nb_alloc = s->nb_peers;
+
+    while (new_min_size >= s->nb_peers)
+        s->nb_peers = s->nb_peers * 2;
+
+    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+    s->peers = qemu_realloc(s->peers, s->nb_peers * sizeof(Peer));
+
+    /* zero out new pointers */
+    for (j = old_nb_alloc; j < s->nb_peers; j++) {
+        s->peers[j].eventfds = NULL;
+        s->peers[j].nb_eventfds = 0;
+    }
+}
+
+static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+{
+    IVShmemState *s = opaque;
+    int incoming_fd, tmp_fd;
+    int guest_max_eventfd;
+    long incoming_posn;
+
+    memcpy(&incoming_posn, buf, sizeof(long));
+    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
+    tmp_fd = qemu_chr_get_msgfd(s->server_chr);
+    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+
+    /* make sure we have enough space for this guest */
+    if (incoming_posn >= s->nb_peers) {
+        increase_dynamic_storage(s, incoming_posn);
+    }
+
+    if (tmp_fd == -1) {
+        /* if posn is positive and unseen before then this is our posn*/
+        if ((incoming_posn >= 0) &&
+                            (s->peers[incoming_posn].eventfds == NULL)) {
+            /* receive our posn */
+            s->vm_id = incoming_posn;
+            return;
+        } else {
+            /* otherwise an fd == -1 means an existing guest has gone away */
+            IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
+            close_guest_eventfds(s, incoming_posn);
+            return;
+        }
+    }
+
+    /* because of the implementation of get_msgfd, we need a dup */
+    incoming_fd = dup(tmp_fd);
+
+    if (incoming_fd == -1) {
+        fprintf(stderr, "could not allocate file descriptor %s\n",
+                                                            strerror(errno));
+        return;
+    }
+
+    /* if the position is -1, then it's shared memory region fd */
+    if (incoming_posn == -1) {
+
+        void * map_ptr;
+
+        s->max_peer = 0;
+
+        if (check_shm_size(s, incoming_fd) == -1) {
+            exit(-1);
+        }
+
+        /* mmap the region and map into the BAR2 */
+        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                                                            incoming_fd, 0);
+        s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
+                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
+
+        IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+                         PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
+                         s->ivshmem_offset, s->ivshmem_size);
+
+        if (s->shm_pci_addr > 0) {
+            /* map memory into BAR2 */
+            cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+                                                            s->ivshmem_offset);
+        }
+
+        /* only store the fd if it is successfully mapped */
+        s->shm_fd = incoming_fd;
+
+        return;
+    }
+
+    /* each guest has an array of eventfds, and we keep track of how many
+     * guests for each VM */
+    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
+
+    if (guest_max_eventfd == 0) {
+        /* one eventfd per MSI vector */
+        s->peers[incoming_posn].eventfds = (int *) qemu_malloc(s->vectors *
+                                                                sizeof(int));
+    }
+
+    /* this is an eventfd for a particular guest VM */
+    IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
+                                            guest_max_eventfd, incoming_fd);
+    s->peers[incoming_posn].eventfds[guest_max_eventfd] = incoming_fd;
+
+    /* increment count for particular guest */
+    s->peers[incoming_posn].nb_eventfds++;
+
+    /* keep track of the maximum VM ID */
+    if (incoming_posn > s->max_peer) {
+        s->max_peer = incoming_posn;
+    }
+
+    if (incoming_posn == s->vm_id) {
+        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
+                   s->peers[s->vm_id].eventfds[guest_max_eventfd],
+                   guest_max_eventfd);
+    }
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
+                        (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
+            fprintf(stderr, "ivshmem: ioeventfd not available\n");
+        }
+    }
+
+    return;
+}
+
+static void ivshmem_reset(DeviceState *d)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
+
+    s->intrstatus = 0;
+    return;
+}
+
+static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+    s->mmio_addr = addr;
+    cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
+                                                s->ivshmem_mmio_io_addr);
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        setup_ioeventfds(s);
+    }
+}
+
+static uint64_t ivshmem_get_size(IVShmemState * s) {
+
+    uint64_t value;
+    char *ptr;
+
+    value = strtoull(s->sizearg, &ptr, 10);
+    switch (*ptr) {
+        case 0: case 'M': case 'm':
+            value <<= 20;
+            break;
+        case 'G': case 'g':
+            value <<= 30;
+            break;
+        default:
+            fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
+            exit(1);
+    }
+
+    /* BARs must be a power of 2 */
+    if (!is_power_of_two(value)) {
+        fprintf(stderr, "ivshmem: size must be power of 2\n");
+        exit(1);
+    }
+
+    return value;
+}
+
+static void ivshmem_setup_msi(IVShmemState * s) {
+
+    int i;
+
+    /* allocate the MSI-X vectors */
+
+    if (!msix_init(&s->dev, s->vectors, 1, 0)) {
+        pci_register_bar(&s->dev, 1,
+                         msix_bar_size(&s->dev),
+                         PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         msix_mmio_map);
+        IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
+    } else {
+        IVSHMEM_DPRINTF("msix initialization failed\n");
+        exit(1);
+    }
+
+    /* 'activate' the vectors */
+    for (i = 0; i < s->vectors; i++) {
+        msix_vector_use(&s->dev, i);
+    }
+
+    /* allocate Qemu char devices for receiving interrupts */
+    s->eventfd_table = qemu_mallocz(s->vectors * sizeof(EventfdEntry));
+}
+
+static void ivshmem_save(QEMUFile* f, void *opaque)
+{
+    IVShmemState *proxy = opaque;
+
+    IVSHMEM_DPRINTF("ivshmem_save\n");
+    pci_device_save(&proxy->dev, f);
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_save(&proxy->dev, f);
+    } else {
+        qemu_put_be32(f, proxy->intrstatus);
+        qemu_put_be32(f, proxy->intrmask);
+    }
+
+}
+
+static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
+{
+    IVSHMEM_DPRINTF("ivshmem_load\n");
+
+    IVShmemState *proxy = opaque;
+    int ret, i;
+
+    if (version_id > 0) {
+        return -EINVAL;
+    }
+
+    if (proxy->role_val == IVSHMEM_PEER) {
+        fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
+        return -EINVAL;
+    }
+
+    ret = pci_device_load(&proxy->dev, f);
+    if (ret) {
+        return ret;
+    }
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_load(&proxy->dev, f);
+        for (i = 0; i < proxy->vectors; i++) {
+            msix_vector_use(&proxy->dev, i);
+        }
+    } else {
+        proxy->intrstatus = qemu_get_be32(f);
+        proxy->intrmask = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
+static int pci_ivshmem_init(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+    uint8_t *pci_conf;
+
+    if (s->sizearg == NULL)
+        s->ivshmem_size = 4 << 20; /* 4 MB default */
+    else {
+        s->ivshmem_size = ivshmem_get_size(s);
+    }
+
+    register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+                                                                        dev);
+
+    /* IRQFD requires MSI */
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
+        !ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
+        exit(1);
+    }
+
+    /* check that role is reasonable */
+    if (s->role) {
+        if (strncmp(s->role, "peer", 5) == 0) {
+            s->role_val = IVSHMEM_PEER;
+        } else if (strncmp(s->role, "master", 7) == 0) {
+            s->role_val = IVSHMEM_MASTER;
+        } else {
+            fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
+            exit(1);
+        }
+    } else {
+        s->role_val = IVSHMEM_MASTER; /* default */
+    }
+
+    if (s->role_val == IVSHMEM_PEER) {
+        register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
+    }
+
+    pci_conf = s->dev.config;
+    pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+    pci_config_set_interrupt_pin(pci_conf, 1);
+
+    s->shm_pci_addr = 0;
+    s->ivshmem_offset = 0;
+    s->shm_fd = 0;
+
+    s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
+                                    ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
+    /* region for registers*/
+    pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+
+    if ((s->server_chr != NULL) &&
+                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
+        /* if we get a UNIX socket as the parameter we will talk
+         * to the ivshmem server to receive the memory region */
+
+        if (s->shmobj != NULL) {
+            fprintf(stderr, "WARNING: do not specify both 'chardev' "
+                                                "and 'shm' with ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
+                                                    s->server_chr->filename);
+
+        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+            ivshmem_setup_msi(s);
+        }
+
+        /* we allocate enough space for 16 guests and grow as needed */
+        s->nb_peers = 16;
+        s->vm_id = -1;
+
+        /* allocate/initialize space for interrupt handling */
+        s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
+
+        pci_register_bar(&s->dev, 2, s->ivshmem_size,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+
+        s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
+
+        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+                     ivshmem_event, s);
+    } else {
+        /* just map the file immediately, we're not using a server */
+        int fd;
+
+        if (s->shmobj == NULL) {
+            fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
+
+        /* try opening with O_EXCL and if it succeeds zero the memory
+         * by truncating to 0 */
+        if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
+           /* truncate file to length PCI device's memory */
+            if (ftruncate(fd, s->ivshmem_size) != 0) {
+                fprintf(stderr, "ivshmem: could not truncate shared file\n");
+            }
+
+        } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
+            fprintf(stderr, "ivshmem: could not open shared file\n");
+            exit(-1);
+
+        }
+
+        if (check_shm_size(s, fd) == -1) {
+            exit(-1);
+        }
+
+        create_shared_memory_BAR(s, fd);
+
+    }
+
+    return 0;
+}
+
+static int pci_ivshmem_uninit(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+
+    cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+    unregister_savevm(&dev->qdev, "ivshmem", s);
+
+    return 0;
+}
+
+static PCIDeviceInfo ivshmem_info = {
+    .qdev.name  = "ivshmem",
+    .qdev.size  = sizeof(IVShmemState),
+    .qdev.reset = ivshmem_reset,
+    .init       = pci_ivshmem_init,
+    .exit       = pci_ivshmem_uninit,
+    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id  = 0x1110,
+    .class_id   = PCI_CLASS_MEMORY_RAM,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+        DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+        DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+        DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+        DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+        DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+        DEFINE_PROP_STRING("role", IVShmemState, role),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ivshmem_register_devices(void)
+{
+    pci_qdev_register(&ivshmem_info);
+}
+
+device_init(ivshmem_register_devices)
diff --git a/qemu-0.15.x/hw/jazz_led.c b/qemu-0.15.x/hw/jazz_led.c
new file mode 100644
index 0000000..1dc22cf
--- /dev/null
+++ b/qemu-0.15.x/hw/jazz_led.c
@@ -0,0 +1,328 @@
+/*
+ * QEMU JAZZ LED emulator.
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * 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 "hw.h"
+#include "mips.h"
+#include "console.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_LED
+
+#ifdef DEBUG_LED
+#define DPRINTF(fmt, ...) \
+do { printf("jazz led: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "jazz led ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
+typedef enum {
+    REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
+} screen_state_t;
+
+typedef struct LedState {
+    uint8_t segments;
+    DisplayState *ds;
+    screen_state_t state;
+} LedState;
+
+static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
+{
+    LedState *s = opaque;
+    uint32_t val;
+
+    switch (addr) {
+        case 0:
+            val = s->segments;
+            break;
+        default:
+            BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
+            val = 0;
+    }
+
+    DPRINTF("read addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
+    return val;
+}
+
+static uint32_t led_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = led_readb(opaque, addr) << 8;
+    v |= led_readb(opaque, addr + 1);
+#else
+    v = led_readb(opaque, addr);
+    v |= led_readb(opaque, addr + 1) << 8;
+#endif
+    return v;
+}
+
+static uint32_t led_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = led_readb(opaque, addr) << 24;
+    v |= led_readb(opaque, addr + 1) << 16;
+    v |= led_readb(opaque, addr + 2) << 8;
+    v |= led_readb(opaque, addr + 3);
+#else
+    v = led_readb(opaque, addr);
+    v |= led_readb(opaque, addr + 1) << 8;
+    v |= led_readb(opaque, addr + 2) << 16;
+    v |= led_readb(opaque, addr + 3) << 24;
+#endif
+    return v;
+}
+
+static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LedState *s = opaque;
+
+    DPRINTF("write addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
+    switch (addr) {
+        case 0:
+            s->segments = val;
+            s->state |= REDRAW_SEGMENTS;
+            break;
+        default:
+            BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+            break;
+    }
+}
+
+static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    led_writeb(opaque, addr, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 1, val & 0xff);
+#else
+    led_writeb(opaque, addr, val & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+#endif
+}
+
+static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    led_writeb(opaque, addr, (val >> 24) & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 16) & 0xff);
+    led_writeb(opaque, addr + 2, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 3, val & 0xff);
+#else
+    led_writeb(opaque, addr, val & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    led_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+#endif
+}
+
+static CPUReadMemoryFunc * const led_read[3] = {
+    led_readb,
+    led_readw,
+    led_readl,
+};
+
+static CPUWriteMemoryFunc * const led_write[3] = {
+    led_writeb,
+    led_writew,
+    led_writel,
+};
+
+/***********************************************************/
+/* jazz_led display */
+
+static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color)
+{
+    uint8_t *d;
+    int x, bpp;
+
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d = ds_get_data(ds) + ds_get_linesize(ds) * posy + bpp * posx1;
+    switch(bpp) {
+        case 1:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint8_t *)d) = color;
+                d++;
+            }
+            break;
+        case 2:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint16_t *)d) = color;
+                d += 2;
+            }
+            break;
+        case 4:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint32_t *)d) = color;
+                d += 4;
+            }
+            break;
+    }
+}
+
+static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color)
+{
+    uint8_t *d;
+    int y, bpp;
+
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d = ds_get_data(ds) + ds_get_linesize(ds) * posy1 + bpp * posx;
+    switch(bpp) {
+        case 1:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint8_t *)d) = color;
+                d += ds_get_linesize(ds);
+            }
+            break;
+        case 2:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint16_t *)d) = color;
+                d += ds_get_linesize(ds);
+            }
+            break;
+        case 4:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint32_t *)d) = color;
+                d += ds_get_linesize(ds);
+            }
+            break;
+    }
+}
+
+static void jazz_led_update_display(void *opaque)
+{
+    LedState *s = opaque;
+    DisplayState *ds = s->ds;
+    uint8_t *d1;
+    uint32_t color_segment, color_led;
+    int y, bpp;
+
+    if (s->state & REDRAW_BACKGROUND) {
+        /* clear screen */
+        bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+        d1 = ds_get_data(ds);
+        for (y = 0; y < ds_get_height(ds); y++) {
+            memset(d1, 0x00, ds_get_width(ds) * bpp);
+            d1 += ds_get_linesize(ds);
+        }
+    }
+
+    if (s->state & REDRAW_SEGMENTS) {
+        /* set colors according to bpp */
+        switch (ds_get_bits_per_pixel(ds)) {
+            case 8:
+                color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
+                break;
+            case 15:
+                color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
+                break;
+            case 16:
+                color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
+            case 24:
+                color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
+                break;
+            case 32:
+                color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
+                break;
+            default:
+                return;
+        }
+
+        /* display segments */
+        draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0);
+        draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0);
+        draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0);
+        draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0);
+        draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0);
+        draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0);
+        draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0);
+
+        /* display led */
+        if (!(s->segments & 0x01))
+            color_led = 0; /* black */
+        draw_horizontal_line(ds, 68, 50, 50, color_led);
+        draw_horizontal_line(ds, 69, 49, 51, color_led);
+        draw_horizontal_line(ds, 70, 48, 52, color_led);
+        draw_horizontal_line(ds, 71, 49, 51, color_led);
+        draw_horizontal_line(ds, 72, 50, 50, color_led);
+    }
+
+    s->state = REDRAW_NONE;
+    dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
+}
+
+static void jazz_led_invalidate_display(void *opaque)
+{
+    LedState *s = opaque;
+    s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+}
+
+static void jazz_led_screen_dump(void *opaque, const char *filename)
+{
+    printf("jazz_led_screen_dump() not implemented\n");
+}
+
+static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
+{
+    LedState *s = opaque;
+    char buf[2];
+
+    dpy_cursor(s->ds, -1, -1);
+    qemu_console_resize(s->ds, 2, 1);
+
+    /* TODO: draw the segments */
+    snprintf(buf, 2, "%02hhx\n", s->segments);
+    console_write_ch(chardata++, 0x00200100 | buf[0]);
+    console_write_ch(chardata++, 0x00200100 | buf[1]);
+
+    dpy_update(s->ds, 0, 0, 2, 1);
+}
+
+void jazz_led_init(target_phys_addr_t base)
+{
+    LedState *s;
+    int io;
+
+    s = qemu_mallocz(sizeof(LedState));
+
+    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+
+    io = cpu_register_io_memory(led_read, led_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 1, io);
+
+    s->ds = graphic_console_init(jazz_led_update_display,
+                                 jazz_led_invalidate_display,
+                                 jazz_led_screen_dump,
+                                 jazz_led_text_update, s);
+    qemu_console_resize(s->ds, 60, 80);
+}
diff --git a/qemu-0.15.x/hw/kvmclock.c b/qemu-0.15.x/hw/kvmclock.c
new file mode 100644
index 0000000..692ad18
--- /dev/null
+++ b/qemu-0.15.x/hw/kvmclock.c
@@ -0,0 +1,120 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka at siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "kvm.h"
+#include "kvmclock.h"
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+
+typedef struct KVMClockState {
+    SysBusDevice busdev;
+    uint64_t clock;
+    bool clock_valid;
+} KVMClockState;
+
+static void kvmclock_pre_save(void *opaque)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+    int ret;
+
+    if (s->clock_valid) {
+        return;
+    }
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+        data.clock = 0;
+    }
+    s->clock = data.clock;
+    /*
+     * If the VM is stopped, declare the clock state valid to avoid re-reading
+     * it on next vmsave (which would return a different value). Will be reset
+     * when the VM is continued.
+     */
+    s->clock_valid = !vm_running;
+}
+
+static int kvmclock_post_load(void *opaque, int version_id)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+
+    data.clock = s->clock;
+    data.flags = 0;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
+}
+
+static void kvmclock_vm_state_change(void *opaque, int running, int reason)
+{
+    KVMClockState *s = opaque;
+
+    if (running) {
+        s->clock_valid = false;
+    }
+}
+
+static int kvmclock_init(SysBusDevice *dev)
+{
+    KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
+
+    qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
+    return 0;
+}
+
+static const VMStateDescription kvmclock_vmsd = {
+    .name = "kvmclock",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvmclock_pre_save,
+    .post_load = kvmclock_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(clock, KVMClockState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo kvmclock_info = {
+    .qdev.name = "kvmclock",
+    .qdev.size = sizeof(KVMClockState),
+    .qdev.vmsd = &kvmclock_vmsd,
+    .qdev.no_user = 1,
+    .init = kvmclock_init,
+};
+
+/* Note: Must be called after VCPU initialization. */
+void kvmclock_create(void)
+{
+    if (kvm_enabled() &&
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE)
+#ifdef KVM_FEATURE_CLOCKSOURCE2
+        || (1ULL << KVM_FEATURE_CLOCKSOURCE2)
+#endif
+    )) {
+        sysbus_create_simple("kvmclock", -1, NULL);
+    }
+}
+
+static void kvmclock_register_device(void)
+{
+    if (kvm_enabled()) {
+        sysbus_register_withprop(&kvmclock_info);
+    }
+}
+
+device_init(kvmclock_register_device);
diff --git a/qemu-0.15.x/hw/kvmclock.h b/qemu-0.15.x/hw/kvmclock.h
new file mode 100644
index 0000000..252ea13
--- /dev/null
+++ b/qemu-0.15.x/hw/kvmclock.h
@@ -0,0 +1,24 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka at siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifdef CONFIG_KVM
+
+void kvmclock_create(void);
+
+#else /* CONFIG_KVM */
+
+static inline void kvmclock_create(void)
+{
+}
+
+#endif /* !CONFIG_KVM */
diff --git a/qemu-0.15.x/hw/lan9118.c b/qemu-0.15.x/hw/lan9118.c
new file mode 100644
index 0000000..73a8661
--- /dev/null
+++ b/qemu-0.15.x/hw/lan9118.c
@@ -0,0 +1,1196 @@
+/*
+ * SMSC LAN9118 Ethernet interface emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU GPL v2
+ */
+
+#include "sysbus.h"
+#include "net.h"
+#include "devices.h"
+#include "sysemu.h"
+/* For crc32 */
+#include <zlib.h>
+
+//#define DEBUG_LAN9118
+
+#ifdef DEBUG_LAN9118
+#define DPRINTF(fmt, ...) \
+do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define CSR_ID_REV      0x50
+#define CSR_IRQ_CFG     0x54
+#define CSR_INT_STS     0x58
+#define CSR_INT_EN      0x5c
+#define CSR_BYTE_TEST   0x64
+#define CSR_FIFO_INT    0x68
+#define CSR_RX_CFG      0x6c
+#define CSR_TX_CFG      0x70
+#define CSR_HW_CFG      0x74
+#define CSR_RX_DP_CTRL  0x78
+#define CSR_RX_FIFO_INF 0x7c
+#define CSR_TX_FIFO_INF 0x80
+#define CSR_PMT_CTRL    0x84
+#define CSR_GPIO_CFG    0x88
+#define CSR_GPT_CFG     0x8c
+#define CSR_GPT_CNT     0x90
+#define CSR_WORD_SWAP   0x98
+#define CSR_FREE_RUN    0x9c
+#define CSR_RX_DROP     0xa0
+#define CSR_MAC_CSR_CMD 0xa4
+#define CSR_MAC_CSR_DATA 0xa8
+#define CSR_AFC_CFG     0xac
+#define CSR_E2P_CMD     0xb0
+#define CSR_E2P_DATA    0xb4
+
+/* IRQ_CFG */
+#define IRQ_INT         0x00001000
+#define IRQ_EN          0x00000100
+#define IRQ_POL         0x00000010
+#define IRQ_TYPE        0x00000001
+
+/* INT_STS/INT_EN */
+#define SW_INT          0x80000000
+#define TXSTOP_INT      0x02000000
+#define RXSTOP_INT      0x01000000
+#define RXDFH_INT       0x00800000
+#define TX_IOC_INT      0x00200000
+#define RXD_INT         0x00100000
+#define GPT_INT         0x00080000
+#define PHY_INT         0x00040000
+#define PME_INT         0x00020000
+#define TXSO_INT        0x00010000
+#define RWT_INT         0x00008000
+#define RXE_INT         0x00004000
+#define TXE_INT         0x00002000
+#define TDFU_INT        0x00000800
+#define TDFO_INT        0x00000400
+#define TDFA_INT        0x00000200
+#define TSFF_INT        0x00000100
+#define TSFL_INT        0x00000080
+#define RXDF_INT        0x00000040
+#define RDFL_INT        0x00000020
+#define RSFF_INT        0x00000010
+#define RSFL_INT        0x00000008
+#define GPIO2_INT       0x00000004
+#define GPIO1_INT       0x00000002
+#define GPIO0_INT       0x00000001
+#define RESERVED_INT    0x7c001000
+
+#define MAC_CR          1
+#define MAC_ADDRH       2
+#define MAC_ADDRL       3
+#define MAC_HASHH       4
+#define MAC_HASHL       5
+#define MAC_MII_ACC     6
+#define MAC_MII_DATA    7
+#define MAC_FLOW        8
+#define MAC_VLAN1       9 /* TODO */
+#define MAC_VLAN2       10 /* TODO */
+#define MAC_WUFF        11 /* TODO */
+#define MAC_WUCSR       12 /* TODO */
+
+#define MAC_CR_RXALL    0x80000000
+#define MAC_CR_RCVOWN   0x00800000
+#define MAC_CR_LOOPBK   0x00200000
+#define MAC_CR_FDPX     0x00100000
+#define MAC_CR_MCPAS    0x00080000
+#define MAC_CR_PRMS     0x00040000
+#define MAC_CR_INVFILT  0x00020000
+#define MAC_CR_PASSBAD  0x00010000
+#define MAC_CR_HO       0x00008000
+#define MAC_CR_HPFILT   0x00002000
+#define MAC_CR_LCOLL    0x00001000
+#define MAC_CR_BCAST    0x00000800
+#define MAC_CR_DISRTY   0x00000400
+#define MAC_CR_PADSTR   0x00000100
+#define MAC_CR_BOLMT    0x000000c0
+#define MAC_CR_DFCHK    0x00000020
+#define MAC_CR_TXEN     0x00000008
+#define MAC_CR_RXEN     0x00000004
+#define MAC_CR_RESERVED 0x7f404213
+
+#define PHY_INT_ENERGYON            0x80
+#define PHY_INT_AUTONEG_COMPLETE    0x40
+#define PHY_INT_FAULT               0x20
+#define PHY_INT_DOWN                0x10
+#define PHY_INT_AUTONEG_LP          0x08
+#define PHY_INT_PARFAULT            0x04
+#define PHY_INT_AUTONEG_PAGE        0x02
+
+#define GPT_TIMER_EN    0x20000000
+
+enum tx_state {
+    TX_IDLE,
+    TX_B,
+    TX_DATA
+};
+
+typedef struct {
+    enum tx_state state;
+    uint32_t cmd_a;
+    uint32_t cmd_b;
+    int buffer_size;
+    int offset;
+    int pad;
+    int fifo_used;
+    int len;
+    uint8_t data[2048];
+} LAN9118Packet;
+
+typedef struct {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+    int mmio_index;
+    ptimer_state *timer;
+
+    uint32_t irq_cfg;
+    uint32_t int_sts;
+    uint32_t int_en;
+    uint32_t fifo_int;
+    uint32_t rx_cfg;
+    uint32_t tx_cfg;
+    uint32_t hw_cfg;
+    uint32_t pmt_ctrl;
+    uint32_t gpio_cfg;
+    uint32_t gpt_cfg;
+    uint32_t word_swap;
+    uint32_t free_timer_start;
+    uint32_t mac_cmd;
+    uint32_t mac_data;
+    uint32_t afc_cfg;
+    uint32_t e2p_cmd;
+    uint32_t e2p_data;
+
+    uint32_t mac_cr;
+    uint32_t mac_hashh;
+    uint32_t mac_hashl;
+    uint32_t mac_mii_acc;
+    uint32_t mac_mii_data;
+    uint32_t mac_flow;
+
+    uint32_t phy_status;
+    uint32_t phy_control;
+    uint32_t phy_advertise;
+    uint32_t phy_int;
+    uint32_t phy_int_mask;
+
+    int eeprom_writable;
+    uint8_t eeprom[128];
+
+    int tx_fifo_size;
+    LAN9118Packet *txp;
+    LAN9118Packet tx_packet;
+
+    int tx_status_fifo_used;
+    int tx_status_fifo_head;
+    uint32_t tx_status_fifo[512];
+
+    int rx_status_fifo_size;
+    int rx_status_fifo_used;
+    int rx_status_fifo_head;
+    uint32_t rx_status_fifo[896];
+    int rx_fifo_size;
+    int rx_fifo_used;
+    int rx_fifo_head;
+    uint32_t rx_fifo[3360];
+    int rx_packet_size_head;
+    int rx_packet_size_tail;
+    int rx_packet_size[1024];
+
+    int rxp_offset;
+    int rxp_size;
+    int rxp_pad;
+} lan9118_state;
+
+static void lan9118_update(lan9118_state *s)
+{
+    int level;
+
+    /* TODO: Implement FIFO level IRQs.  */
+    level = (s->int_sts & s->int_en) != 0;
+    if (level) {
+        s->irq_cfg |= IRQ_INT;
+    } else {
+        s->irq_cfg &= ~IRQ_INT;
+    }
+    if ((s->irq_cfg & IRQ_EN) == 0) {
+        level = 0;
+    }
+    if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
+        /* Interrupt is active low unless we're configured as
+         * active-high polarity, push-pull type.
+         */
+        level = !level;
+    }
+    qemu_set_irq(s->irq, level);
+}
+
+static void lan9118_mac_changed(lan9118_state *s)
+{
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+}
+
+static void lan9118_reload_eeprom(lan9118_state *s)
+{
+    int i;
+    if (s->eeprom[0] != 0xa5) {
+        s->e2p_cmd &= ~0x10;
+        DPRINTF("MACADDR load failed\n");
+        return;
+    }
+    for (i = 0; i < 6; i++) {
+        s->conf.macaddr.a[i] = s->eeprom[i + 1];
+    }
+    s->e2p_cmd |= 0x10;
+    DPRINTF("MACADDR loaded from eeprom\n");
+    lan9118_mac_changed(s);
+}
+
+static void phy_update_irq(lan9118_state *s)
+{
+    if (s->phy_int & s->phy_int_mask) {
+        s->int_sts |= PHY_INT;
+    } else {
+        s->int_sts &= ~PHY_INT;
+    }
+    lan9118_update(s);
+}
+
+static void phy_update_link(lan9118_state *s)
+{
+    /* Autonegotiation status mirrors link status.  */
+    if (s->nic->nc.link_down) {
+        s->phy_status &= ~0x0024;
+        s->phy_int |= PHY_INT_DOWN;
+    } else {
+        s->phy_status |= 0x0024;
+        s->phy_int |= PHY_INT_ENERGYON;
+        s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+    }
+    phy_update_irq(s);
+}
+
+static void lan9118_set_link(VLANClientState *nc)
+{
+    phy_update_link(DO_UPCAST(NICState, nc, nc)->opaque);
+}
+
+static void phy_reset(lan9118_state *s)
+{
+    s->phy_status = 0x7809;
+    s->phy_control = 0x3000;
+    s->phy_advertise = 0x01e1;
+    s->phy_int_mask = 0;
+    s->phy_int = 0;
+    phy_update_link(s);
+}
+
+static void lan9118_reset(DeviceState *d)
+{
+    lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d));
+    s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
+    s->int_sts = 0;
+    s->int_en = 0;
+    s->fifo_int = 0x48000000;
+    s->rx_cfg = 0;
+    s->tx_cfg = 0;
+    s->hw_cfg = 0x00050000;
+    s->pmt_ctrl &= 0x45;
+    s->gpio_cfg = 0;
+    s->txp->fifo_used = 0;
+    s->txp->state = TX_IDLE;
+    s->txp->cmd_a = 0xffffffffu;
+    s->txp->cmd_b = 0xffffffffu;
+    s->txp->len = 0;
+    s->txp->fifo_used = 0;
+    s->tx_fifo_size = 4608;
+    s->tx_status_fifo_used = 0;
+    s->rx_status_fifo_size = 704;
+    s->rx_fifo_size = 2640;
+    s->rx_fifo_used = 0;
+    s->rx_status_fifo_size = 176;
+    s->rx_status_fifo_used = 0;
+    s->rxp_offset = 0;
+    s->rxp_size = 0;
+    s->rxp_pad = 0;
+    s->rx_packet_size_tail = s->rx_packet_size_head;
+    s->rx_packet_size[s->rx_packet_size_head] = 0;
+    s->mac_cmd = 0;
+    s->mac_data = 0;
+    s->afc_cfg = 0;
+    s->e2p_cmd = 0;
+    s->e2p_data = 0;
+    s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40;
+
+    ptimer_stop(s->timer);
+    ptimer_set_count(s->timer, 0xffff);
+    s->gpt_cfg = 0xffff;
+
+    s->mac_cr = MAC_CR_PRMS;
+    s->mac_hashh = 0;
+    s->mac_hashl = 0;
+    s->mac_mii_acc = 0;
+    s->mac_mii_data = 0;
+    s->mac_flow = 0;
+
+    phy_reset(s);
+
+    s->eeprom_writable = 0;
+    lan9118_reload_eeprom(s);
+}
+
+static int lan9118_can_receive(VLANClientState *nc)
+{
+    return 1;
+}
+
+static void rx_fifo_push(lan9118_state *s, uint32_t val)
+{
+    int fifo_pos;
+    fifo_pos = s->rx_fifo_head + s->rx_fifo_used;
+    if (fifo_pos >= s->rx_fifo_size)
+      fifo_pos -= s->rx_fifo_size;
+    s->rx_fifo[fifo_pos] = val;
+    s->rx_fifo_used++;
+}
+
+/* Return nonzero if the packet is accepted by the filter.  */
+static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
+{
+    int multicast;
+    uint32_t hash;
+
+    if (s->mac_cr & MAC_CR_PRMS) {
+        return 1;
+    }
+    if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+        addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+        return (s->mac_cr & MAC_CR_BCAST) == 0;
+    }
+
+    multicast = addr[0] & 1;
+    if (multicast &&s->mac_cr & MAC_CR_MCPAS) {
+        return 1;
+    }
+    if (multicast ? (s->mac_cr & MAC_CR_HPFILT) == 0
+                  : (s->mac_cr & MAC_CR_HO) == 0) {
+        /* Exact matching.  */
+        hash = memcmp(addr, s->conf.macaddr.a, 6);
+        if (s->mac_cr & MAC_CR_INVFILT) {
+            return hash != 0;
+        } else {
+            return hash == 0;
+        }
+    } else {
+        /* Hash matching  */
+        hash = (crc32(~0, addr, 6) >> 26);
+        if (hash & 0x20) {
+            return (s->mac_hashh >> (hash & 0x1f)) & 1;
+        } else {
+            return (s->mac_hashl >> (hash & 0x1f)) & 1;
+        }
+    }
+}
+
+static ssize_t lan9118_receive(VLANClientState *nc, const uint8_t *buf,
+                               size_t size)
+{
+    lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int fifo_len;
+    int offset;
+    int src_pos;
+    int n;
+    int filter;
+    uint32_t val;
+    uint32_t crc;
+    uint32_t status;
+
+    if ((s->mac_cr & MAC_CR_RXEN) == 0) {
+        return -1;
+    }
+
+    if (size >= 2048 || size < 14) {
+        return -1;
+    }
+
+    /* TODO: Implement FIFO overflow notification.  */
+    if (s->rx_status_fifo_used == s->rx_status_fifo_size) {
+        return -1;
+    }
+
+    filter = lan9118_filter(s, buf);
+    if (!filter && (s->mac_cr & MAC_CR_RXALL) == 0) {
+        return size;
+    }
+
+    offset = (s->rx_cfg >> 8) & 0x1f;
+    n = offset & 3;
+    fifo_len = (size + n + 3) >> 2;
+    /* Add a word for the CRC.  */
+    fifo_len++;
+    if (s->rx_fifo_size - s->rx_fifo_used < fifo_len) {
+        return -1;
+    }
+
+    DPRINTF("Got packet len:%d fifo:%d filter:%s\n",
+            (int)size, fifo_len, filter ? "pass" : "fail");
+    val = 0;
+    crc = bswap32(crc32(~0, buf, size));
+    for (src_pos = 0; src_pos < size; src_pos++) {
+        val = (val >> 8) | ((uint32_t)buf[src_pos] << 24);
+        n++;
+        if (n == 4) {
+            n = 0;
+            rx_fifo_push(s, val);
+            val = 0;
+        }
+    }
+    if (n) {
+        val >>= ((4 - n) * 8);
+        val |= crc << (n * 8);
+        rx_fifo_push(s, val);
+        val = crc >> ((4 - n) * 8);
+        rx_fifo_push(s, val);
+    } else {
+        rx_fifo_push(s, crc);
+    }
+    n = s->rx_status_fifo_head + s->rx_status_fifo_used;
+    if (n >= s->rx_status_fifo_size) {
+        n -= s->rx_status_fifo_size;
+    }
+    s->rx_packet_size[s->rx_packet_size_tail] = fifo_len;
+    s->rx_packet_size_tail = (s->rx_packet_size_tail + 1023) & 1023;
+    s->rx_status_fifo_used++;
+
+    status = (size + 4) << 16;
+    if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
+        buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
+        status |= 0x00002000;
+    } else if (buf[0] & 1) {
+        status |= 0x00000400;
+    }
+    if (!filter) {
+        status |= 0x40000000;
+    }
+    s->rx_status_fifo[n] = status;
+
+    if (s->rx_status_fifo_used > (s->fifo_int & 0xff)) {
+        s->int_sts |= RSFL_INT;
+    }
+    lan9118_update(s);
+
+    return size;
+}
+
+static uint32_t rx_fifo_pop(lan9118_state *s)
+{
+    int n;
+    uint32_t val;
+
+    if (s->rxp_size == 0 && s->rxp_pad == 0) {
+        s->rxp_size = s->rx_packet_size[s->rx_packet_size_head];
+        s->rx_packet_size[s->rx_packet_size_head] = 0;
+        if (s->rxp_size != 0) {
+            s->rx_packet_size_head = (s->rx_packet_size_head + 1023) & 1023;
+            s->rxp_offset = (s->rx_cfg >> 10) & 7;
+            n = s->rxp_offset + s->rxp_size;
+            switch (s->rx_cfg >> 30) {
+            case 1:
+                n = (-n) & 3;
+                break;
+            case 2:
+                n = (-n) & 7;
+                break;
+            default:
+                n = 0;
+                break;
+            }
+            s->rxp_pad = n;
+            DPRINTF("Pop packet size:%d offset:%d pad: %d\n",
+                    s->rxp_size, s->rxp_offset, s->rxp_pad);
+        }
+    }
+    if (s->rxp_offset > 0) {
+        s->rxp_offset--;
+        val = 0;
+    } else if (s->rxp_size > 0) {
+        s->rxp_size--;
+        val = s->rx_fifo[s->rx_fifo_head++];
+        if (s->rx_fifo_head >= s->rx_fifo_size) {
+            s->rx_fifo_head -= s->rx_fifo_size;
+        }
+        s->rx_fifo_used--;
+    } else if (s->rxp_pad > 0) {
+        s->rxp_pad--;
+        val =  0;
+    } else {
+        DPRINTF("RX underflow\n");
+        s->int_sts |= RXE_INT;
+        val =  0;
+    }
+    lan9118_update(s);
+    return val;
+}
+
+static void do_tx_packet(lan9118_state *s)
+{
+    int n;
+    uint32_t status;
+
+    /* FIXME: Honor TX disable, and allow queueing of packets.  */
+    if (s->phy_control & 0x4000)  {
+        /* This assumes the receive routine doesn't touch the VLANClient.  */
+        lan9118_receive(&s->nic->nc, s->txp->data, s->txp->len);
+    } else {
+        qemu_send_packet(&s->nic->nc, s->txp->data, s->txp->len);
+    }
+    s->txp->fifo_used = 0;
+
+    if (s->tx_status_fifo_used == 512) {
+        /* Status FIFO full */
+        return;
+    }
+    /* Add entry to status FIFO.  */
+    status = s->txp->cmd_b & 0xffff0000u;
+    DPRINTF("Sent packet tag:%04x len %d\n", status >> 16, s->txp->len);
+    n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511;
+    s->tx_status_fifo[n] = status;
+    s->tx_status_fifo_used++;
+    if (s->tx_status_fifo_used == 512) {
+        s->int_sts |= TSFF_INT;
+        /* TODO: Stop transmission.  */
+    }
+}
+
+static uint32_t rx_status_fifo_pop(lan9118_state *s)
+{
+    uint32_t val;
+
+    val = s->rx_status_fifo[s->rx_status_fifo_head];
+    if (s->rx_status_fifo_used != 0) {
+        s->rx_status_fifo_used--;
+        s->rx_status_fifo_head++;
+        if (s->rx_status_fifo_head >= s->rx_status_fifo_size) {
+            s->rx_status_fifo_head -= s->rx_status_fifo_size;
+        }
+        /* ??? What value should be returned when the FIFO is empty?  */
+        DPRINTF("RX status pop 0x%08x\n", val);
+    }
+    return val;
+}
+
+static uint32_t tx_status_fifo_pop(lan9118_state *s)
+{
+    uint32_t val;
+
+    val = s->tx_status_fifo[s->tx_status_fifo_head];
+    if (s->tx_status_fifo_used != 0) {
+        s->tx_status_fifo_used--;
+        s->tx_status_fifo_head = (s->tx_status_fifo_head + 1) & 511;
+        /* ??? What value should be returned when the FIFO is empty?  */
+    }
+    return val;
+}
+
+static void tx_fifo_push(lan9118_state *s, uint32_t val)
+{
+    int n;
+
+    if (s->txp->fifo_used == s->tx_fifo_size) {
+        s->int_sts |= TDFO_INT;
+        return;
+    }
+    switch (s->txp->state) {
+    case TX_IDLE:
+        s->txp->cmd_a = val & 0x831f37ff;
+        s->txp->fifo_used++;
+        s->txp->state = TX_B;
+        break;
+    case TX_B:
+        if (s->txp->cmd_a & 0x2000) {
+            /* First segment */
+            s->txp->cmd_b = val;
+            s->txp->fifo_used++;
+            s->txp->buffer_size = s->txp->cmd_a & 0x7ff;
+            s->txp->offset = (s->txp->cmd_a >> 16) & 0x1f;
+            /* End alignment does not include command words.  */
+            n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
+            switch ((n >> 24) & 3) {
+            case 1:
+                n = (-n) & 3;
+                break;
+            case 2:
+                n = (-n) & 7;
+                break;
+            default:
+                n = 0;
+            }
+            s->txp->pad = n;
+            s->txp->len = 0;
+        }
+        DPRINTF("Block len:%d offset:%d pad:%d cmd %08x\n",
+                s->txp->buffer_size, s->txp->offset, s->txp->pad,
+                s->txp->cmd_a);
+        s->txp->state = TX_DATA;
+        break;
+    case TX_DATA:
+        if (s->txp->offset >= 4) {
+            s->txp->offset -= 4;
+            break;
+        }
+        if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
+            s->txp->pad--;
+        } else {
+            n = 4;
+            while (s->txp->offset) {
+                val >>= 8;
+                n--;
+                s->txp->offset--;
+            }
+            /* Documentation is somewhat unclear on the ordering of bytes
+               in FIFO words.  Empirical results show it to be little-endian.
+               */
+            /* TODO: FIFO overflow checking.  */
+            while (n--) {
+                s->txp->data[s->txp->len] = val & 0xff;
+                s->txp->len++;
+                val >>= 8;
+                s->txp->buffer_size--;
+            }
+            s->txp->fifo_used++;
+        }
+        if (s->txp->buffer_size <= 0 && s->txp->pad == 0) {
+            if (s->txp->cmd_a & 0x1000) {
+                do_tx_packet(s);
+            }
+            if (s->txp->cmd_a & 0x80000000) {
+                s->int_sts |= TX_IOC_INT;
+            }
+            s->txp->state = TX_IDLE;
+        }
+        break;
+    }
+}
+
+static uint32_t do_phy_read(lan9118_state *s, int reg)
+{
+    uint32_t val;
+
+    switch (reg) {
+    case 0: /* Basic Control */
+        return s->phy_control;
+    case 1: /* Basic Status */
+        return s->phy_status;
+    case 2: /* ID1 */
+        return 0x0007;
+    case 3: /* ID2 */
+        return 0xc0d1;
+    case 4: /* Auto-neg advertisment */
+        return s->phy_advertise;
+    case 5: /* Auto-neg Link Partner Ability */
+        return 0x0f71;
+    case 6: /* Auto-neg Expansion */
+        return 1;
+        /* TODO 17, 18, 27, 29, 30, 31 */
+    case 29: /* Interrupt source.  */
+        val = s->phy_int;
+        s->phy_int = 0;
+        phy_update_irq(s);
+        return val;
+    case 30: /* Interrupt mask */
+        return s->phy_int_mask;
+    default:
+        BADF("PHY read reg %d\n", reg);
+        return 0;
+    }
+}
+
+static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
+{
+    switch (reg) {
+    case 0: /* Basic Control */
+        if (val & 0x8000) {
+            phy_reset(s);
+            break;
+        }
+        s->phy_control = val & 0x7980;
+        /* Complete autonegotiation immediately.  */
+        if (val & 0x1000) {
+            s->phy_status |= 0x0020;
+        }
+        break;
+    case 4: /* Auto-neg advertisment */
+        s->phy_advertise = (val & 0x2d7f) | 0x80;
+        break;
+        /* TODO 17, 18, 27, 31 */
+    case 30: /* Interrupt mask */
+        s->phy_int_mask = val & 0xff;
+        phy_update_irq(s);
+        break;
+    default:
+        BADF("PHY write reg %d = 0x%04x\n", reg, val);
+    }
+}
+
+static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
+{
+    switch (reg) {
+    case MAC_CR:
+        if ((s->mac_cr & MAC_CR_RXEN) != 0 && (val & MAC_CR_RXEN) == 0) {
+            s->int_sts |= RXSTOP_INT;
+        }
+        s->mac_cr = val & ~MAC_CR_RESERVED;
+        DPRINTF("MAC_CR: %08x\n", val);
+        break;
+    case MAC_ADDRH:
+        s->conf.macaddr.a[4] = val & 0xff;
+        s->conf.macaddr.a[5] = (val >> 8) & 0xff;
+        lan9118_mac_changed(s);
+        break;
+    case MAC_ADDRL:
+        s->conf.macaddr.a[0] = val & 0xff;
+        s->conf.macaddr.a[1] = (val >> 8) & 0xff;
+        s->conf.macaddr.a[2] = (val >> 16) & 0xff;
+        s->conf.macaddr.a[3] = (val >> 24) & 0xff;
+        lan9118_mac_changed(s);
+        break;
+    case MAC_HASHH:
+        s->mac_hashh = val;
+        break;
+    case MAC_HASHL:
+        s->mac_hashl = val;
+        break;
+    case MAC_MII_ACC:
+        s->mac_mii_acc = val & 0xffc2;
+        if (val & 2) {
+            DPRINTF("PHY write %d = 0x%04x\n",
+                    (val >> 6) & 0x1f, s->mac_mii_data);
+            do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
+        } else {
+            s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
+            DPRINTF("PHY read %d = 0x%04x\n",
+                    (val >> 6) & 0x1f, s->mac_mii_data);
+        }
+        break;
+    case MAC_MII_DATA:
+        s->mac_mii_data = val & 0xffff;
+        break;
+    case MAC_FLOW:
+        s->mac_flow = val & 0xffff0000;
+        break;
+    case MAC_VLAN1:
+        /* Writing to this register changes a condition for
+         * FrameTooLong bit in rx_status.  Since we do not set
+         * FrameTooLong anyway, just ignore write to this.
+         */
+        break;
+    default:
+        hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
+                 s->mac_cmd & 0xf, val);
+    }
+}
+
+static uint32_t do_mac_read(lan9118_state *s, int reg)
+{
+    switch (reg) {
+    case MAC_CR:
+        return s->mac_cr;
+    case MAC_ADDRH:
+        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+    case MAC_ADDRL:
+        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+    case MAC_HASHH:
+        return s->mac_hashh;
+        break;
+    case MAC_HASHL:
+        return s->mac_hashl;
+        break;
+    case MAC_MII_ACC:
+        return s->mac_mii_acc;
+    case MAC_MII_DATA:
+        return s->mac_mii_data;
+    case MAC_FLOW:
+        return s->mac_flow;
+    default:
+        hw_error("lan9118: Unimplemented MAC register read: %d\n",
+                 s->mac_cmd & 0xf);
+    }
+}
+
+static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
+{
+    s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
+    switch (cmd) {
+    case 0:
+        s->e2p_data = s->eeprom[addr];
+        DPRINTF("EEPROM Read %d = 0x%02x\n", addr, s->e2p_data);
+        break;
+    case 1:
+        s->eeprom_writable = 0;
+        DPRINTF("EEPROM Write Disable\n");
+        break;
+    case 2: /* EWEN */
+        s->eeprom_writable = 1;
+        DPRINTF("EEPROM Write Enable\n");
+        break;
+    case 3: /* WRITE */
+        if (s->eeprom_writable) {
+            s->eeprom[addr] &= s->e2p_data;
+            DPRINTF("EEPROM Write %d = 0x%02x\n", addr, s->e2p_data);
+        } else {
+            DPRINTF("EEPROM Write %d (ignored)\n", addr);
+        }
+        break;
+    case 4: /* WRAL */
+        if (s->eeprom_writable) {
+            for (addr = 0; addr < 128; addr++) {
+                s->eeprom[addr] &= s->e2p_data;
+            }
+            DPRINTF("EEPROM Write All 0x%02x\n", s->e2p_data);
+        } else {
+            DPRINTF("EEPROM Write All (ignored)\n");
+        }
+    case 5: /* ERASE */
+        if (s->eeprom_writable) {
+            s->eeprom[addr] = 0xff;
+            DPRINTF("EEPROM Erase %d\n", addr);
+        } else {
+            DPRINTF("EEPROM Erase %d (ignored)\n", addr);
+        }
+        break;
+    case 6: /* ERAL */
+        if (s->eeprom_writable) {
+            memset(s->eeprom, 0xff, 128);
+            DPRINTF("EEPROM Erase All\n");
+        } else {
+            DPRINTF("EEPROM Erase All (ignored)\n");
+        }
+        break;
+    case 7: /* RELOAD */
+        lan9118_reload_eeprom(s);
+        break;
+    }
+}
+
+static void lan9118_tick(void *opaque)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+    if (s->int_en & GPT_INT) {
+        s->int_sts |= GPT_INT;
+    }
+    lan9118_update(s);
+}
+
+static void lan9118_writel(void *opaque, target_phys_addr_t offset,
+                           uint32_t val)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+    offset &= 0xff;
+    
+    //DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
+    if (offset >= 0x20 && offset < 0x40) {
+        /* TX FIFO */
+        tx_fifo_push(s, val);
+        return;
+    }
+    switch (offset) {
+    case CSR_IRQ_CFG:
+        /* TODO: Implement interrupt deassertion intervals.  */
+        val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
+        s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
+        break;
+    case CSR_INT_STS:
+        s->int_sts &= ~val;
+        break;
+    case CSR_INT_EN:
+        s->int_en = val & ~RESERVED_INT;
+        s->int_sts |= val & SW_INT;
+        break;
+    case CSR_FIFO_INT:
+        DPRINTF("FIFO INT levels %08x\n", val);
+        s->fifo_int = val;
+        break;
+    case CSR_RX_CFG:
+        if (val & 0x8000) {
+            /* RX_DUMP */
+            s->rx_fifo_used = 0;
+            s->rx_status_fifo_used = 0;
+            s->rx_packet_size_tail = s->rx_packet_size_head;
+            s->rx_packet_size[s->rx_packet_size_head] = 0;
+        }
+        s->rx_cfg = val & 0xcfff1ff0;
+        break;
+    case CSR_TX_CFG:
+        if (val & 0x8000) {
+            s->tx_status_fifo_used = 0;
+        }
+        if (val & 0x4000) {
+            s->txp->state = TX_IDLE;
+            s->txp->fifo_used = 0;
+            s->txp->cmd_a = 0xffffffff;
+        }
+        s->tx_cfg = val & 6;
+        break;
+    case CSR_HW_CFG:
+        if (val & 1) {
+            /* SRST */
+            lan9118_reset(&s->busdev.qdev);
+        } else {
+            s->hw_cfg = val & 0x003f300;
+        }
+        break;
+    case CSR_RX_DP_CTRL:
+        if (val & 0x80000000) {
+            /* Skip forward to next packet.  */
+            s->rxp_pad = 0;
+            s->rxp_offset = 0;
+            if (s->rxp_size == 0) {
+                /* Pop a word to start the next packet.  */
+                rx_fifo_pop(s);
+                s->rxp_pad = 0;
+                s->rxp_offset = 0;
+            }
+            s->rx_fifo_head += s->rxp_size;
+            if (s->rx_fifo_head >= s->rx_fifo_size) {
+                s->rx_fifo_head -= s->rx_fifo_size;
+            }
+        }
+        break;
+    case CSR_PMT_CTRL:
+        if (val & 0x400) {
+            phy_reset(s);
+        }
+        s->pmt_ctrl &= ~0x34e;
+        s->pmt_ctrl |= (val & 0x34e);
+        break;
+    case CSR_GPIO_CFG:
+        /* Probably just enabling LEDs.  */
+        s->gpio_cfg = val & 0x7777071f;
+        break;
+    case CSR_GPT_CFG:
+        if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {
+            if (val & GPT_TIMER_EN) {
+                ptimer_set_count(s->timer, val & 0xffff);
+                ptimer_run(s->timer, 0);
+            } else {
+                ptimer_stop(s->timer);
+                ptimer_set_count(s->timer, 0xffff);
+            }
+        }
+        s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);
+        break;
+    case CSR_WORD_SWAP:
+        /* Ignored because we're in 32-bit mode.  */
+        s->word_swap = val;
+        break;
+    case CSR_MAC_CSR_CMD:
+        s->mac_cmd = val & 0x4000000f;
+        if (val & 0x80000000) {
+            if (val & 0x40000000) {
+                s->mac_data = do_mac_read(s, val & 0xf);
+                DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);
+            } else {
+                DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);
+                do_mac_write(s, val & 0xf, s->mac_data);
+            }
+        }
+        break;
+    case CSR_MAC_CSR_DATA:
+        s->mac_data = val;
+        break;
+    case CSR_AFC_CFG:
+        s->afc_cfg = val & 0x00ffffff;
+        break;
+    case CSR_E2P_CMD:
+        lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);
+        break;
+    case CSR_E2P_DATA:
+        s->e2p_data = val & 0xff;
+        break;
+
+    default:
+        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, val);
+        break;
+    }
+    lan9118_update(s);
+}
+
+static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+
+    //DPRINTF("Read reg 0x%02x\n", (int)offset);
+    if (offset < 0x20) {
+        /* RX FIFO */
+        return rx_fifo_pop(s);
+    }
+    switch (offset) {
+    case 0x40:
+        return rx_status_fifo_pop(s);
+    case 0x44:
+        return s->rx_status_fifo[s->tx_status_fifo_head];
+    case 0x48:
+        return tx_status_fifo_pop(s);
+    case 0x4c:
+        return s->tx_status_fifo[s->tx_status_fifo_head];
+    case CSR_ID_REV:
+        return 0x01180001;
+    case CSR_IRQ_CFG:
+        return s->irq_cfg;
+    case CSR_INT_STS:
+        return s->int_sts;
+    case CSR_INT_EN:
+        return s->int_en;
+    case CSR_BYTE_TEST:
+        return 0x87654321;
+    case CSR_FIFO_INT:
+        return s->fifo_int;
+    case CSR_RX_CFG:
+        return s->rx_cfg;
+    case CSR_TX_CFG:
+        return s->tx_cfg;
+    case CSR_HW_CFG:
+        return s->hw_cfg | 0x4;
+    case CSR_RX_DP_CTRL:
+        return 0;
+    case CSR_RX_FIFO_INF:
+        return (s->rx_status_fifo_used << 16) | (s->rx_fifo_used << 2);
+    case CSR_TX_FIFO_INF:
+        return (s->tx_status_fifo_used << 16)
+               | (s->tx_fifo_size - s->txp->fifo_used);
+    case CSR_PMT_CTRL:
+        return s->pmt_ctrl;
+    case CSR_GPIO_CFG:
+        return s->gpio_cfg;
+    case CSR_GPT_CFG:
+        return s->gpt_cfg;
+    case CSR_GPT_CNT:
+        return ptimer_get_count(s->timer);
+    case CSR_WORD_SWAP:
+        return s->word_swap;
+    case CSR_FREE_RUN:
+        return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start;
+    case CSR_RX_DROP:
+        /* TODO: Implement dropped frames counter.  */
+        return 0;
+    case CSR_MAC_CSR_CMD:
+        return s->mac_cmd;
+    case CSR_MAC_CSR_DATA:
+        return s->mac_data;
+    case CSR_AFC_CFG:
+        return s->afc_cfg;
+    case CSR_E2P_CMD:
+        return s->e2p_cmd;
+    case CSR_E2P_DATA:
+        return s->e2p_data;
+    }
+    hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
+    return 0;
+}
+
+static CPUReadMemoryFunc * const lan9118_readfn[] = {
+    lan9118_readl,
+    lan9118_readl,
+    lan9118_readl
+};
+
+static CPUWriteMemoryFunc * const lan9118_writefn[] = {
+    lan9118_writel,
+    lan9118_writel,
+    lan9118_writel
+};
+
+static void lan9118_cleanup(VLANClientState *nc)
+{
+    lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_lan9118_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = lan9118_can_receive,
+    .receive = lan9118_receive,
+    .cleanup = lan9118_cleanup,
+    .link_status_changed = lan9118_set_link,
+};
+
+static int lan9118_init1(SysBusDevice *dev)
+{
+    lan9118_state *s = FROM_SYSBUS(lan9118_state, dev);
+    QEMUBH *bh;
+    int i;
+
+    s->mmio_index = cpu_register_io_memory(lan9118_readfn,
+                                           lan9118_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x100, s->mmio_index);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    s->eeprom[0] = 0xa5;
+    for (i = 0; i < 6; i++) {
+        s->eeprom[i + 1] = s->conf.macaddr.a[i];
+    }
+    s->pmt_ctrl = 1;
+    s->txp = &s->tx_packet;
+
+    bh = qemu_bh_new(lan9118_tick, s);
+    s->timer = ptimer_init(bh);
+    ptimer_set_freq(s->timer, 10000);
+    ptimer_set_limit(s->timer, 0xffff, 1);
+
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+static SysBusDeviceInfo lan9118_info = {
+    .init = lan9118_init1,
+    .qdev.name  = "lan9118",
+    .qdev.size  = sizeof(lan9118_state),
+    .qdev.reset = lan9118_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lan9118_register_devices(void)
+{
+    sysbus_register_withprop(&lan9118_info);
+}
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "lan9118");
+    dev = qdev_create(NULL, "lan9118");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+device_init(lan9118_register_devices)
diff --git a/qemu-0.15.x/hw/lance.c b/qemu-0.15.x/hw/lance.c
new file mode 100644
index 0000000..ddb1cbb
--- /dev/null
+++ b/qemu-0.15.x/hw/lance.c
@@ -0,0 +1,160 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */
+
+#include "sysbus.h"
+#include "net.h"
+#include "qemu-timer.h"
+#include "qemu_socket.h"
+#include "sun4m.h"
+#include "pcnet.h"
+#include "trace.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    PCNetState state;
+} SysBusPCNetState;
+
+static void parent_lance_reset(void *opaque, int irq, int level)
+{
+    SysBusPCNetState *d = opaque;
+    if (level)
+        pcnet_h_reset(&d->state);
+}
+
+static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    SysBusPCNetState *d = opaque;
+
+    trace_lance_mem_writew(addr, val & 0xffff);
+    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
+}
+
+static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    SysBusPCNetState *d = opaque;
+    uint32_t val;
+
+    val = pcnet_ioport_readw(&d->state, addr);
+    trace_lance_mem_readw(addr, val & 0xffff);
+    return val & 0xffff;
+}
+
+static CPUReadMemoryFunc * const lance_mem_read[3] = {
+    NULL,
+    lance_mem_readw,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const lance_mem_write[3] = {
+    NULL,
+    lance_mem_writew,
+    NULL,
+};
+
+static void lance_cleanup(VLANClientState *nc)
+{
+    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    pcnet_common_cleanup(d);
+}
+
+static NetClientInfo net_lance_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .cleanup = lance_cleanup,
+};
+
+static const VMStateDescription vmstate_lance = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int lance_init(SysBusDevice *dev)
+{
+    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
+    PCNetState *s = &d->state;
+
+    s->mmio_index =
+        cpu_register_io_memory(lance_mem_read, lance_mem_write, d,
+                               DEVICE_NATIVE_ENDIAN);
+
+    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
+
+    sysbus_init_mmio(dev, 4, s->mmio_index);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->phys_mem_read = ledma_memory_read;
+    s->phys_mem_write = ledma_memory_write;
+    return pcnet_common_init(&dev->qdev, s, &net_lance_info);
+}
+
+static void lance_reset(DeviceState *dev)
+{
+    SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static SysBusDeviceInfo lance_info = {
+    .init       = lance_init,
+    .qdev.name  = "lance",
+    .qdev.fw_name  = "ethernet",
+    .qdev.size  = sizeof(SysBusPCNetState),
+    .qdev.reset = lance_reset,
+    .qdev.vmsd  = &vmstate_lance,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+        DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lance_register_devices(void)
+{
+    sysbus_register_withprop(&lance_info);
+}
+device_init(lance_register_devices)
diff --git a/qemu-0.15.x/hw/leon3.c b/qemu-0.15.x/hw/leon3.c
new file mode 100644
index 0000000..919f49f
--- /dev/null
+++ b/qemu-0.15.x/hw/leon3.c
@@ -0,0 +1,217 @@
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "trace.h"
+
+#include "grlib.h"
+
+/* Default system clock.  */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME        "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+    CPUState *env;
+    uint32_t  entry;            /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s   = (ResetData *)opaque;
+    CPUState  *env = s->env;
+
+    cpu_reset(env);
+
+    env->halted = 0;
+    env->pc     = s->entry;
+    env->npc    = s->entry + 4;
+}
+
+void leon3_irq_ack(void *irq_manager, int intno)
+{
+    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+}
+
+static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
+{
+    CPUState *env = (CPUState *)opaque;
+
+    assert(env != NULL);
+
+    env->pil_in = pil_in;
+
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index) {
+                    trace_leon3_set_irq(i);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        trace_leon3_reset_irq(env->interrupt_index & 15);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void leon3_generic_hw_init(ram_addr_t  ram_size,
+                                  const char *boot_device,
+                                  const char *kernel_filename,
+                                  const char *kernel_cmdline,
+                                  const char *initrd_filename,
+                                  const char *cpu_model)
+{
+    CPUState   *env;
+    ram_addr_t  ram_offset, prom_offset;
+    int         ret;
+    char       *filename;
+    qemu_irq   *cpu_irqs = NULL;
+    int         bios_size;
+    int         prom_size;
+    ResetData  *reset_info;
+
+    /* Init CPU */
+    if (!cpu_model) {
+        cpu_model = "LEON3";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    cpu_sparc_set_id(env, 0);
+
+    /* Reset data */
+    reset_info        = qemu_mallocz(sizeof(ResetData));
+    reset_info->env   = env;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate IRQ manager */
+    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
+
+    env->qemu_irq_ack = leon3_irq_manager;
+
+    /* Allocate RAM */
+    if ((uint64_t)ram_size > (1UL << 30)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum 1G\n",
+                (unsigned int)(ram_size / (1024 * 1024)));
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
+    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+
+    /* Allocate BIOS */
+    prom_size = 8 * 1024 * 1024; /* 8Mb */
+    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
+    cpu_register_physical_memory(0x00000000, prom_size,
+                                 prom_offset | IO_MEM_ROM);
+
+    /* Load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    bios_size = get_image_size(filename);
+
+    if (bios_size > prom_size) {
+        fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
+                filename);
+        exit(1);
+    }
+
+    if (bios_size > 0) {
+        ret = load_image_targphys(filename, 0x00000000, bios_size);
+        if (ret < 0 || ret > prom_size) {
+            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+            exit(1);
+        }
+    } else if (kernel_filename == NULL) {
+        fprintf(stderr, "Can't read bios image %s\n", filename);
+        exit(1);
+    }
+
+    /* Can directly load an application. */
+    if (kernel_filename != NULL) {
+        long     kernel_size;
+        uint64_t entry;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1 /* big endian */, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        if (bios_size <= 0) {
+            /* If there is no bios/monitor, start the application.  */
+            env->pc = entry;
+            env->npc = entry + 4;
+            reset_info->entry = entry;
+        }
+    }
+
+    /* Allocate timers */
+    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+    /* Allocate uart */
+    if (serial_hds[0]) {
+        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+    }
+}
+
+QEMUMachine leon3_generic_machine = {
+    .name     = "leon3_generic",
+    .desc     = "Leon-3 generic",
+    .init     = leon3_generic_hw_init,
+    .use_scsi = 0,
+};
+
+static void leon3_machine_init(void)
+{
+    qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
diff --git a/qemu-0.15.x/hw/lm32.h b/qemu-0.15.x/hw/lm32.h
new file mode 100644
index 0000000..0a67632
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32.h
@@ -0,0 +1,25 @@
+
+#include "qemu-common.h"
+
+static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+
+    dev = qdev_create(NULL, "lm32-pic");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+    sysbus_connect_irq(d, 0, cpu_irq);
+
+    return dev;
+}
+
+static inline DeviceState *lm32_juart_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "lm32-juart");
+    qdev_init_nofail(dev);
+
+    return dev;
+}
diff --git a/qemu-0.15.x/hw/lm32_boards.c b/qemu-0.15.x/hw/lm32_boards.c
new file mode 100644
index 0000000..6462923
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_boards.c
@@ -0,0 +1,304 @@
+/*
+ *  QEMU models for LatticeMico32 uclinux and evr32 boards.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "blockdev.h"
+#include "elf.h"
+#include "lm32_hwsetup.h"
+#include "lm32.h"
+
+typedef struct {
+    CPUState *env;
+    target_phys_addr_t bootstrap_pc;
+    target_phys_addr_t flash_base;
+    target_phys_addr_t hwsetup_base;
+    target_phys_addr_t initrd_base;
+    size_t initrd_size;
+    target_phys_addr_t cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPUState *env = reset_info->env;
+
+    cpu_reset(env);
+
+    /* init defaults */
+    env->pc = (uint32_t)reset_info->bootstrap_pc;
+    env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
+    env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
+    env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
+    env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
+        reset_info->initrd_size);
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void lm32_evr_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq *cpu_irq, irq[32];
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    target_phys_addr_t flash_base  = 0x04000000;
+    size_t flash_sector_size       = 256 * 1024;
+    size_t flash_size              = 32 * 1024 * 1024;
+    target_phys_addr_t ram_base    = 0x08000000;
+    size_t ram_size                = 64 * 1024 * 1024;
+    target_phys_addr_t timer0_base = 0x80002000;
+    target_phys_addr_t uart0_base  = 0x80006000;
+    target_phys_addr_t timer1_base = 0x8000a000;
+    int uart0_irq                  = 0;
+    int timer0_irq                 = 1;
+    int timer1_irq                 = 3;
+
+    reset_info = qemu_mallocz(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    phys_ram = qemu_ram_alloc(NULL, "lm32_evr.sdram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "lm32_evr.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq *cpu_irq, irq[32];
+    HWSetup *hw;
+    ResetInfo *reset_info;
+    int i;
+
+    /* memory map */
+    target_phys_addr_t flash_base   = 0x04000000;
+    size_t flash_sector_size        = 256 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    target_phys_addr_t ram_base     = 0x08000000;
+    size_t ram_size                 = 64 * 1024 * 1024;
+    target_phys_addr_t uart0_base   = 0x80000000;
+    target_phys_addr_t timer0_base  = 0x80002000;
+    target_phys_addr_t timer1_base  = 0x80010000;
+    target_phys_addr_t timer2_base  = 0x80012000;
+    int uart0_irq                   = 0;
+    int timer0_irq                  = 1;
+    int timer1_irq                  = 20;
+    int timer2_irq                  = 21;
+    target_phys_addr_t hwsetup_base = 0x0bffe000;
+    target_phys_addr_t cmdline_base = 0x0bfff000;
+    target_phys_addr_t initrd_base  = 0x08400000;
+    size_t initrd_max               = 0x01000000;
+
+    reset_info = qemu_mallocz(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    phys_ram = qemu_ram_alloc(NULL, "lm32_uclinux.sdram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "lm32_uclinux.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+    sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* generate a rom with the hardware description */
+    hw = hwsetup_init();
+    hwsetup_add_cpu(hw, "LM32", 75000000);
+    hwsetup_add_flash(hw, "flash", flash_base, flash_size);
+    hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
+    hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
+    hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
+    hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
+    hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
+    hwsetup_add_trailer(hw);
+    hwsetup_create_rom(hw, hwsetup_base);
+    hwsetup_free(hw);
+
+    reset_info->hwsetup_base = hwsetup_base;
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = initrd_base;
+        reset_info->initrd_size = initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine lm32_evr_machine = {
+    .name = "lm32-evr",
+    .desc = "LatticeMico32 EVR32 eval system",
+    .init = lm32_evr_init,
+    .is_default = 1
+};
+
+static QEMUMachine lm32_uclinux_machine = {
+    .name = "lm32-uclinux",
+    .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems",
+    .init = lm32_uclinux_init,
+    .is_default = 0
+};
+
+static void lm32_machine_init(void)
+{
+    qemu_register_machine(&lm32_uclinux_machine);
+    qemu_register_machine(&lm32_evr_machine);
+}
+
+machine_init(lm32_machine_init);
diff --git a/qemu-0.15.x/hw/lm32_hwsetup.h b/qemu-0.15.x/hw/lm32_hwsetup.h
new file mode 100644
index 0000000..9f47821
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_hwsetup.h
@@ -0,0 +1,178 @@
+/*
+ *  LatticeMico32 hwsetup helper functions.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * These are helper functions for creating the hardware description blob used
+ * in the Theobroma's uClinux port.
+ */
+
+#ifndef QEMU_HW_LM32_HWSETUP_H
+#define QEMU_HW_LM32_HWSETUP_H
+
+#include "qemu-common.h"
+#include "loader.h"
+
+typedef struct {
+    void *data;
+    void *ptr;
+} HWSetup;
+
+enum hwsetup_tag {
+    HWSETUP_TAG_EOL         = 0,
+    HWSETUP_TAG_CPU         = 1,
+    HWSETUP_TAG_ASRAM       = 2,
+    HWSETUP_TAG_FLASH       = 3,
+    HWSETUP_TAG_SDRAM       = 4,
+    HWSETUP_TAG_OCM         = 5,
+    HWSETUP_TAG_DDR_SDRAM   = 6,
+    HWSETUP_TAG_DDR2_SDRAM  = 7,
+    HWSETUP_TAG_TIMER       = 8,
+    HWSETUP_TAG_UART        = 9,
+    HWSETUP_TAG_GPIO        = 10,
+    HWSETUP_TAG_TRISPEEDMAC = 11,
+    HWSETUP_TAG_I2CM        = 12,
+    HWSETUP_TAG_LEDS        = 13,
+    HWSETUP_TAG_7SEG        = 14,
+    HWSETUP_TAG_SPI_S       = 15,
+    HWSETUP_TAG_SPI_M       = 16,
+};
+
+static inline HWSetup *hwsetup_init(void)
+{
+    HWSetup *hw;
+
+    hw = qemu_malloc(sizeof(HWSetup));
+    hw->data = qemu_mallocz(TARGET_PAGE_SIZE);
+    hw->ptr = hw->data;
+
+    return hw;
+}
+
+static inline void hwsetup_free(HWSetup *hw)
+{
+    qemu_free(hw->data);
+    qemu_free(hw);
+}
+
+static inline void hwsetup_create_rom(HWSetup *hw,
+        target_phys_addr_t base)
+{
+    rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base);
+}
+
+static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
+{
+    stb_p(hw->ptr, u);
+    hw->ptr += 1;
+}
+
+static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
+{
+    stl_p(hw->ptr, u);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
+{
+    stl_p(hw->ptr, t);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_str(HWSetup *hw, const char *str)
+{
+    strncpy(hw->ptr, str, 31); /* make sure last byte is zero */
+    hw->ptr += 32;
+}
+
+static inline void hwsetup_add_trailer(HWSetup *hw)
+{
+    hwsetup_add_u32(hw, 8); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
+}
+
+static inline void hwsetup_add_cpu(HWSetup *hw,
+        const char *name, uint32_t frequency)
+{
+    hwsetup_add_u32(hw, 44); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, frequency);
+}
+
+static inline void hwsetup_add_flash(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 52); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+    hwsetup_add_u8(hw, 8); /* read latency */
+    hwsetup_add_u8(hw, 8); /* write latency */
+    hwsetup_add_u8(hw, 25); /* address width */
+    hwsetup_add_u8(hw, 32); /* data width */
+}
+
+static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 48); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+}
+
+static inline void hwsetup_add_timer(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u8(hw, 1); /* wr_tickcount */
+    hwsetup_add_u8(hw, 1); /* rd_tickcount */
+    hwsetup_add_u8(hw, 1); /* start_stop_control */
+    hwsetup_add_u8(hw, 32); /* counter_width */
+    hwsetup_add_u32(hw, 20); /* reload_ticks */
+    hwsetup_add_u8(hw, irq);
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+}
+
+static inline void hwsetup_add_uart(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_UART);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, 115200); /* baudrate */
+    hwsetup_add_u8(hw, 8); /* databits */
+    hwsetup_add_u8(hw, 1); /* stopbits */
+    hwsetup_add_u8(hw, 1); /* use_interrupt */
+    hwsetup_add_u8(hw, 1); /* block_on_transmit */
+    hwsetup_add_u8(hw, 1); /* block_on_receive */
+    hwsetup_add_u8(hw, 4); /* rx_buffer_size */
+    hwsetup_add_u8(hw, 4); /* tx_buffer_size */
+    hwsetup_add_u8(hw, irq);
+}
+
+#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/qemu-0.15.x/hw/lm32_juart.c b/qemu-0.15.x/hw/lm32_juart.c
new file mode 100644
index 0000000..fddcf7e
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_juart.c
@@ -0,0 +1,150 @@
+/*
+ *  LatticeMico32 JTAG UART model.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+
+#include "lm32_juart.h"
+
+enum {
+    LM32_JUART_MIN_SAVE_VERSION = 0,
+    LM32_JUART_CURRENT_SAVE_VERSION = 0,
+    LM32_JUART_MAX_SAVE_VERSION = 0,
+};
+
+enum {
+    JTX_FULL = (1<<8),
+};
+
+enum {
+    JRX_FULL = (1<<8),
+};
+
+struct LM32JuartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+
+    uint32_t jtx;
+    uint32_t jrx;
+};
+typedef struct LM32JuartState LM32JuartState;
+
+uint32_t lm32_juart_get_jtx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jtx(s->jtx);
+    return s->jtx;
+}
+
+uint32_t lm32_juart_get_jrx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jrx(s->jrx);
+    return s->jrx;
+}
+
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+    unsigned char ch = jtx & 0xff;
+
+    trace_lm32_juart_set_jtx(s->jtx);
+
+    s->jtx = jtx;
+    if (s->chr) {
+        qemu_chr_write(s->chr, &ch, 1);
+    }
+}
+
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_set_jrx(s->jrx);
+    s->jrx &= ~JRX_FULL;
+}
+
+static void juart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32JuartState *s = opaque;
+
+    s->jrx = *buf | JRX_FULL;
+}
+
+static int juart_can_rx(void *opaque)
+{
+    LM32JuartState *s = opaque;
+
+    return !(s->jrx & JRX_FULL);
+}
+
+static void juart_event(void *opaque, int event)
+{
+}
+
+static void juart_reset(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    s->jtx = 0;
+    s->jrx = 0;
+}
+
+static int lm32_juart_init(SysBusDevice *dev)
+{
+    LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_juart = {
+    .name = "lm32-juart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(jtx, LM32JuartState),
+        VMSTATE_UINT32(jrx, LM32JuartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_juart_info = {
+    .init = lm32_juart_init,
+    .qdev.name  = "lm32-juart",
+    .qdev.size  = sizeof(LM32JuartState),
+    .qdev.vmsd  = &vmstate_lm32_juart,
+    .qdev.reset = juart_reset,
+};
+
+static void lm32_juart_register(void)
+{
+    sysbus_register_withprop(&lm32_juart_info);
+}
+
+device_init(lm32_juart_register)
diff --git a/qemu-0.15.x/hw/lm32_juart.h b/qemu-0.15.x/hw/lm32_juart.h
new file mode 100644
index 0000000..67fc586
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_juart.h
@@ -0,0 +1,11 @@
+#ifndef QEMU_HW_LM32_JUART_H
+#define QEMU_HW_LM32_JUART_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_juart_get_jtx(DeviceState *d);
+uint32_t lm32_juart_get_jrx(DeviceState *d);
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
+
+#endif /* QEMU_HW_LM32_JUART_H */
diff --git a/qemu-0.15.x/hw/lm32_pic.c b/qemu-0.15.x/hw/lm32_pic.c
new file mode 100644
index 0000000..02941a7
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_pic.c
@@ -0,0 +1,190 @@
+/*
+ *  LatticeMico32 CPU interrupt controller logic.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "lm32_pic.h"
+
+struct LM32PicState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+    uint32_t im;        /* interrupt mask */
+    uint32_t ip;        /* interrupt pending */
+    uint32_t irq_state;
+
+    /* statistics */
+    uint32_t stats_irq_count[32];
+};
+typedef struct LM32PicState LM32PicState;
+
+static LM32PicState *pic;
+void pic_info(Monitor *mon)
+{
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
+            pic->im, pic->ip, pic->irq_state);
+}
+
+void irq_info(Monitor *mon)
+{
+    int i;
+    uint32_t count;
+
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = pic->stats_irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %u\n", i, count);
+        }
+    }
+}
+
+static void update_irq(LM32PicState *s)
+{
+    s->ip |= s->irq_state;
+
+    if (s->ip & s->im) {
+        trace_lm32_pic_raise_irq();
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        trace_lm32_pic_lower_irq();
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    LM32PicState *s = opaque;
+
+    assert(irq < 32);
+    trace_lm32_pic_interrupt(irq, level);
+
+    if (level) {
+        s->irq_state |= (1 << irq);
+        s->stats_irq_count[irq]++;
+    } else {
+        s->irq_state &= ~(1 << irq);
+    }
+
+    update_irq(s);
+}
+
+void lm32_pic_set_im(DeviceState *d, uint32_t im)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_im(im);
+    s->im = im;
+
+    update_irq(s);
+}
+
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_ip(ip);
+
+    /* ack interrupt */
+    s->ip &= ~ip;
+
+    update_irq(s);
+}
+
+uint32_t lm32_pic_get_im(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_im(s->im);
+    return s->im;
+}
+
+uint32_t lm32_pic_get_ip(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_ip(s->ip);
+    return s->ip;
+}
+
+static void pic_reset(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+    int i;
+
+    s->im = 0;
+    s->ip = 0;
+    s->irq_state = 0;
+    for (i = 0; i < 32; i++) {
+        s->stats_irq_count[i] = 0;
+    }
+}
+
+static int lm32_pic_init(SysBusDevice *dev)
+{
+    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+
+    pic = s;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_pic = {
+    .name = "lm32-pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(im, LM32PicState),
+        VMSTATE_UINT32(ip, LM32PicState),
+        VMSTATE_UINT32(irq_state, LM32PicState),
+        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_pic_info = {
+    .init = lm32_pic_init,
+    .qdev.name  = "lm32-pic",
+    .qdev.size  = sizeof(LM32PicState),
+    .qdev.vmsd  = &vmstate_lm32_pic,
+    .qdev.reset = pic_reset,
+};
+
+static void lm32_pic_register(void)
+{
+    sysbus_register_withprop(&lm32_pic_info);
+}
+
+device_init(lm32_pic_register)
diff --git a/qemu-0.15.x/hw/lm32_pic.h b/qemu-0.15.x/hw/lm32_pic.h
new file mode 100644
index 0000000..e6479b8
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_pic.h
@@ -0,0 +1,11 @@
+#ifndef QEMU_HW_LM32_PIC_H
+#define QEMU_HW_LM32_PIC_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_pic_get_ip(DeviceState *d);
+uint32_t lm32_pic_get_im(DeviceState *d);
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
+void lm32_pic_set_im(DeviceState *d, uint32_t im);
+
+#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/qemu-0.15.x/hw/lm32_sys.c b/qemu-0.15.x/hw/lm32_sys.c
new file mode 100644
index 0000000..e5ff962
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_sys.c
@@ -0,0 +1,161 @@
+/*
+ *  QEMU model of the LatticeMico32 system control block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This model is mainly intended for testing purposes and doesn't fit to any
+ * real hardware. On the one hand it provides a control register (R_CTRL) on
+ * the other hand it supports the lm32 tests.
+ *
+ * A write to the control register causes a system shutdown.
+ * Tests first write the pointer to a test name to the test name register
+ * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
+ * the test is passed or any non-zero value to it if the test is failed.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "qemu-error.h"
+#include "sysemu.h"
+#include "qemu-log.h"
+
+enum {
+    R_CTRL = 0,
+    R_PASSFAIL,
+    R_TESTNAME,
+    R_MAX
+};
+
+#define MAX_TESTNAME_LEN 16
+
+struct LM32SysState {
+    SysBusDevice busdev;
+    uint32_t base;
+    uint32_t regs[R_MAX];
+    uint8_t testname[MAX_TESTNAME_LEN];
+};
+typedef struct LM32SysState LM32SysState;
+
+static void copy_testname(LM32SysState *s)
+{
+    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
+            MAX_TESTNAME_LEN);
+    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
+}
+
+static void sys_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32SysState *s = opaque;
+    char *testname;
+
+    trace_lm32_sys_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        qemu_system_shutdown_request();
+        break;
+    case R_PASSFAIL:
+        s->regs[addr] = value;
+        testname = (char *)s->testname;
+        qemu_log("TC  %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+        break;
+    case R_TESTNAME:
+        s->regs[addr] = value;
+        copy_testname(s);
+        break;
+
+    default:
+        error_report("lm32_sys: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sys_read_fn[] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const sys_write_fn[] = {
+    NULL,
+    NULL,
+    &sys_write,
+};
+
+static void sys_reset(DeviceState *d)
+{
+    LM32SysState *s = container_of(d, LM32SysState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->testname, 0, MAX_TESTNAME_LEN);
+}
+
+static int lm32_sys_init(SysBusDevice *dev)
+{
+    LM32SysState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sys_regs;
+
+    sys_regs = cpu_register_io_memory(sys_read_fn, sys_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sys_regs);
+
+    /* Note: This device is not created in the board initialization,
+     * instead it has to be added with the -device parameter. Therefore,
+     * the device maps itself. */
+    sysbus_mmio_map(dev, 0, s->base);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_sys = {
+    .name = "lm32-sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
+        VMSTATE_BUFFER(testname, LM32SysState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_sys_info = {
+    .init = lm32_sys_init,
+    .qdev.name  = "lm32-sys",
+    .qdev.size  = sizeof(LM32SysState),
+    .qdev.vmsd  = &vmstate_lm32_sys,
+    .qdev.reset = sys_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_sys_register(void)
+{
+    sysbus_register_withprop(&lm32_sys_info);
+}
+
+device_init(lm32_sys_register)
diff --git a/qemu-0.15.x/hw/lm32_timer.c b/qemu-0.15.x/hw/lm32_timer.c
new file mode 100644
index 0000000..49cbb22
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_timer.c
@@ -0,0 +1,222 @@
+/*
+ *  QEMU model of the LatticeMico32 timer block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32timer.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-timer.h"
+#include "qemu-error.h"
+
+#define DEFAULT_FREQUENCY (50*1000000)
+
+enum {
+    R_SR = 0,
+    R_CR,
+    R_PERIOD,
+    R_SNAPSHOT,
+    R_MAX
+};
+
+enum {
+    SR_TO    = (1 << 0),
+    SR_RUN   = (1 << 1),
+};
+
+enum {
+    CR_ITO   = (1 << 0),
+    CR_CONT  = (1 << 1),
+    CR_START = (1 << 2),
+    CR_STOP  = (1 << 3),
+};
+
+struct LM32TimerState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    qemu_irq irq;
+    uint32_t freq_hz;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32TimerState LM32TimerState;
+
+static void timer_update_irq(LM32TimerState *s)
+{
+    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
+
+    trace_lm32_timer_irq_state(state);
+    qemu_set_irq(s->irq, state);
+}
+
+static uint32_t timer_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32TimerState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+    case R_CR:
+    case R_PERIOD:
+        r = s->regs[addr];
+        break;
+    case R_SNAPSHOT:
+        r = (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    default:
+        error_report("lm32_timer: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_timer_memory_read(addr << 2, r);
+    return r;
+}
+
+static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+        s->regs[R_SR] &= ~SR_TO;
+        break;
+    case R_CR:
+        s->regs[R_CR] = value;
+        if (s->regs[R_CR] & CR_START) {
+            ptimer_run(s->ptimer, 1);
+        }
+        if (s->regs[R_CR] & CR_STOP) {
+            ptimer_stop(s->ptimer);
+        }
+        break;
+    case R_PERIOD:
+        s->regs[R_PERIOD] = value;
+        ptimer_set_count(s->ptimer, value);
+        break;
+    case R_SNAPSHOT:
+        error_report("lm32_timer: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_timer: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    timer_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const timer_read_fn[] = {
+    NULL,
+    NULL,
+    &timer_read,
+};
+
+static CPUWriteMemoryFunc * const timer_write_fn[] = {
+    NULL,
+    NULL,
+    &timer_write,
+};
+
+static void timer_hit(void *opaque)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_hit();
+
+    s->regs[R_SR] |= SR_TO;
+
+    if (s->regs[R_CR] & CR_CONT) {
+        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
+        ptimer_run(s->ptimer, 1);
+    }
+    timer_update_irq(s);
+}
+
+static void timer_reset(DeviceState *d)
+{
+    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    ptimer_stop(s->ptimer);
+}
+
+static int lm32_timer_init(SysBusDevice *dev)
+{
+    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
+    int timer_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, s->freq_hz);
+
+    timer_regs = cpu_register_io_memory(timer_read_fn, timer_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, timer_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_timer = {
+    .name = "lm32-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, LM32TimerState),
+        VMSTATE_UINT32(freq_hz, LM32TimerState),
+        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_timer_info = {
+    .init = lm32_timer_init,
+    .qdev.name  = "lm32-timer",
+    .qdev.size  = sizeof(LM32TimerState),
+    .qdev.vmsd  = &vmstate_lm32_timer,
+    .qdev.reset = timer_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_timer_register(void)
+{
+    sysbus_register_withprop(&lm32_timer_info);
+}
+
+device_init(lm32_timer_register)
diff --git a/qemu-0.15.x/hw/lm32_uart.c b/qemu-0.15.x/hw/lm32_uart.c
new file mode 100644
index 0000000..09090e9
--- /dev/null
+++ b/qemu-0.15.x/hw/lm32_uart.c
@@ -0,0 +1,288 @@
+/*
+ *  QEMU model of the LatticeMico32 UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32uart.pdf
+ */
+
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+#include "qemu-error.h"
+
+enum {
+    R_RXTX = 0,
+    R_IER,
+    R_IIR,
+    R_LCR,
+    R_MCR,
+    R_LSR,
+    R_MSR,
+    R_DIV,
+    R_MAX
+};
+
+enum {
+    IER_RBRI = (1<<0),
+    IER_THRI = (1<<1),
+    IER_RLSI = (1<<2),
+    IER_MSI  = (1<<3),
+};
+
+enum {
+    IIR_STAT = (1<<0),
+    IIR_ID0  = (1<<1),
+    IIR_ID1  = (1<<2),
+};
+
+enum {
+    LCR_WLS0 = (1<<0),
+    LCR_WLS1 = (1<<1),
+    LCR_STB  = (1<<2),
+    LCR_PEN  = (1<<3),
+    LCR_EPS  = (1<<4),
+    LCR_SP   = (1<<5),
+    LCR_SB   = (1<<6),
+};
+
+enum {
+    MCR_DTR  = (1<<0),
+    MCR_RTS  = (1<<1),
+};
+
+enum {
+    LSR_DR   = (1<<0),
+    LSR_OE   = (1<<1),
+    LSR_PE   = (1<<2),
+    LSR_FE   = (1<<3),
+    LSR_BI   = (1<<4),
+    LSR_THRE = (1<<5),
+    LSR_TEMT = (1<<6),
+};
+
+enum {
+    MSR_DCTS = (1<<0),
+    MSR_DDSR = (1<<1),
+    MSR_TERI = (1<<2),
+    MSR_DDCD = (1<<3),
+    MSR_CTS  = (1<<4),
+    MSR_DSR  = (1<<5),
+    MSR_RI   = (1<<6),
+    MSR_DCD  = (1<<7),
+};
+
+struct LM32UartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32UartState LM32UartState;
+
+static void uart_update_irq(LM32UartState *s)
+{
+    unsigned int irq;
+
+    if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
+            && (s->regs[R_IER] & IER_RLSI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
+    } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1;
+    } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID0;
+    } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
+        irq = 1;
+        s->regs[R_IIR] = 0;
+    } else {
+        irq = 0;
+        s->regs[R_IIR] = IIR_STAT;
+    }
+
+    trace_lm32_uart_irq_state(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32UartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[R_RXTX];
+        s->regs[R_LSR] &= ~LSR_DR;
+        uart_update_irq(s);
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        r = s->regs[addr];
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        error_report("lm32_uart: read access to write only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_uart_memory_read(addr << 2, r);
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32UartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_lm32_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_write(s->chr, &ch, 1);
+        }
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        error_report("lm32_uart: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    uart_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const uart_read_fn[] = {
+    NULL,
+    NULL,
+    &uart_read,
+};
+
+static CPUWriteMemoryFunc * const uart_write_fn[] = {
+    NULL,
+    NULL,
+    &uart_write,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32UartState *s = opaque;
+
+    if (s->regs[R_LSR] & LSR_DR) {
+        s->regs[R_LSR] |= LSR_OE;
+    }
+
+    s->regs[R_LSR] |= LSR_DR;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    LM32UartState *s = opaque;
+
+    return !(s->regs[R_LSR] & LSR_DR);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void uart_reset(DeviceState *d)
+{
+    LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+}
+
+static int lm32_uart_init(SysBusDevice *dev)
+{
+    LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_uart = {
+    .name = "lm32-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_uart_info = {
+    .init = lm32_uart_init,
+    .qdev.name  = "lm32-uart",
+    .qdev.size  = sizeof(LM32UartState),
+    .qdev.vmsd  = &vmstate_lm32_uart,
+    .qdev.reset = uart_reset,
+};
+
+static void lm32_uart_register(void)
+{
+    sysbus_register_withprop(&lm32_uart_info);
+}
+
+device_init(lm32_uart_register)
diff --git a/qemu-0.15.x/hw/lm832x.c b/qemu-0.15.x/hw/lm832x.c
new file mode 100644
index 0000000..590a4cc
--- /dev/null
+++ b/qemu-0.15.x/hw/lm832x.c
@@ -0,0 +1,512 @@
+/*
+ * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "i2c.h"
+#include "qemu-timer.h"
+#include "console.h"
+
+typedef struct {
+    i2c_slave i2c;
+    uint8_t i2c_dir;
+    uint8_t i2c_cycle;
+    uint8_t reg;
+
+    qemu_irq nirq;
+    uint16_t model;
+
+    struct {
+        qemu_irq out[2];
+        int in[2][2];
+    } mux;
+
+    uint8_t config;
+    uint8_t status;
+    uint8_t acttime;
+    uint8_t error;
+    uint8_t clock;
+
+    struct {
+        uint16_t pull;
+        uint16_t mask;
+        uint16_t dir;
+        uint16_t level;
+        qemu_irq out[16];
+    } gpio;
+
+    struct {
+        uint8_t dbnctime;
+        uint8_t size;
+        uint8_t start;
+        uint8_t len;
+        uint8_t fifo[16];
+    } kbd;
+
+    struct {
+        uint16_t file[256];
+	uint8_t faddr;
+        uint8_t addr[3];
+        QEMUTimer *tm[3];
+    } pwm;
+} LM823KbdState;
+
+#define INT_KEYPAD		(1 << 0)
+#define INT_ERROR		(1 << 3)
+#define INT_NOINIT		(1 << 4)
+#define INT_PWMEND(n)		(1 << (5 + n))
+
+#define ERR_BADPAR		(1 << 0)
+#define ERR_CMDUNK		(1 << 1)
+#define ERR_KEYOVR		(1 << 2)
+#define ERR_FIFOOVR		(1 << 6)
+
+static void lm_kbd_irq_update(LM823KbdState *s)
+{
+    qemu_set_irq(s->nirq, !s->status);
+}
+
+static void lm_kbd_gpio_update(LM823KbdState *s)
+{
+}
+
+static void lm_kbd_reset(LM823KbdState *s)
+{
+    s->config = 0x80;
+    s->status = INT_NOINIT;
+    s->acttime = 125;
+    s->kbd.dbnctime = 3;
+    s->kbd.size = 0x33;
+    s->clock = 0x08;
+
+    lm_kbd_irq_update(s);
+    lm_kbd_gpio_update(s);
+}
+
+static void lm_kbd_error(LM823KbdState *s, int err)
+{
+    s->error |= err;
+    s->status |= INT_ERROR;
+    lm_kbd_irq_update(s);
+}
+
+static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
+{
+}
+
+static void lm_kbd_pwm_start(LM823KbdState *s, int line)
+{
+    lm_kbd_pwm_tick(s, line);
+}
+
+static void lm_kbd_pwm0_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 0);
+}
+static void lm_kbd_pwm1_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 1);
+}
+static void lm_kbd_pwm2_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 2);
+}
+
+enum {
+    LM832x_CMD_READ_ID		= 0x80, /* Read chip ID. */
+    LM832x_CMD_WRITE_CFG	= 0x81, /* Set configuration item. */
+    LM832x_CMD_READ_INT		= 0x82, /* Get interrupt status. */
+    LM832x_CMD_RESET		= 0x83, /* Reset, same as external one */
+    LM823x_CMD_WRITE_PULL_DOWN	= 0x84, /* Select GPIO pull-up/down. */
+    LM832x_CMD_WRITE_PORT_SEL	= 0x85, /* Select GPIO in/out. */
+    LM832x_CMD_WRITE_PORT_STATE	= 0x86, /* Set GPIO pull-up/down. */
+    LM832x_CMD_READ_PORT_SEL	= 0x87, /* Get GPIO in/out. */
+    LM832x_CMD_READ_PORT_STATE	= 0x88, /* Get GPIO pull-up/down. */
+    LM832x_CMD_READ_FIFO	= 0x89, /* Read byte from FIFO. */
+    LM832x_CMD_RPT_READ_FIFO	= 0x8a, /* Read FIFO (no increment). */
+    LM832x_CMD_SET_ACTIVE	= 0x8b, /* Set active time. */
+    LM832x_CMD_READ_ERROR	= 0x8c, /* Get error status. */
+    LM832x_CMD_READ_ROTATOR	= 0x8e, /* Read rotator status. */
+    LM832x_CMD_SET_DEBOUNCE	= 0x8f, /* Set debouncing time. */
+    LM832x_CMD_SET_KEY_SIZE	= 0x90, /* Set keypad size. */
+    LM832x_CMD_READ_KEY_SIZE	= 0x91, /* Get keypad size. */
+    LM832x_CMD_READ_CFG		= 0x92, /* Get configuration item. */
+    LM832x_CMD_WRITE_CLOCK	= 0x93, /* Set clock config. */
+    LM832x_CMD_READ_CLOCK	= 0x94, /* Get clock config. */
+    LM832x_CMD_PWM_WRITE	= 0x95, /* Write PWM script. */
+    LM832x_CMD_PWM_START	= 0x96, /* Start PWM engine. */
+    LM832x_CMD_PWM_STOP		= 0x97, /* Stop PWM engine. */
+    LM832x_GENERAL_ERROR	= 0xff, /* There was one error.
+                                           Previously was represented by -1
+                                           This is not a command */
+};
+
+#define LM832x_MAX_KPX		8
+#define LM832x_MAX_KPY		12
+
+static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
+{
+    int ret;
+
+    switch (reg) {
+    case LM832x_CMD_READ_ID:
+        ret = 0x0400;
+        break;
+
+    case LM832x_CMD_READ_INT:
+        ret = s->status;
+        if (!(s->status & INT_NOINIT)) {
+            s->status = 0;
+            lm_kbd_irq_update(s);
+        }
+        break;
+
+    case LM832x_CMD_READ_PORT_SEL:
+        ret = s->gpio.dir;
+        break;
+    case LM832x_CMD_READ_PORT_STATE:
+        ret = s->gpio.mask;
+        break;
+
+    case LM832x_CMD_READ_FIFO:
+        if (s->kbd.len <= 1)
+            return 0x00;
+
+        /* Example response from the two commands after a INT_KEYPAD
+         * interrupt caused by the key 0x3c being pressed:
+         * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         *     READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         *
+         * 55 is the code of the key release event serviced in the previous
+         * interrupt handling.
+         *
+         * TODO: find out whether the FIFO is advanced a single character
+         * before reading every byte or the whole size of the FIFO at the
+         * last LM832x_CMD_READ_FIFO.  This affects LM832x_CMD_RPT_READ_FIFO
+         * output in cases where there are more than one event in the FIFO.
+         * Assume 0xbc and 0x3c events are in the FIFO:
+         * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
+         *     READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
+         * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
+         */
+        s->kbd.start ++;
+        s->kbd.start &= sizeof(s->kbd.fifo) - 1;
+        s->kbd.len --;
+
+        return s->kbd.fifo[s->kbd.start];
+    case LM832x_CMD_RPT_READ_FIFO:
+        if (byte >= s->kbd.len)
+            return 0x00;
+
+        return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
+
+    case LM832x_CMD_READ_ERROR:
+        return s->error;
+
+    case LM832x_CMD_READ_ROTATOR:
+        return 0;
+
+    case LM832x_CMD_READ_KEY_SIZE:
+        return s->kbd.size;
+
+    case LM832x_CMD_READ_CFG:
+        return s->config & 0xf;
+
+    case LM832x_CMD_READ_CLOCK:
+        return (s->clock & 0xfc) | 2;
+
+    default:
+        lm_kbd_error(s, ERR_CMDUNK);
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
+        return 0x00;
+    }
+
+    return ret >> (byte << 3);
+}
+
+static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
+{
+    switch (reg) {
+    case LM832x_CMD_WRITE_CFG:
+        s->config = value;
+        /* This must be done whenever s->mux.in is updated (never).  */
+        if ((s->config >> 1) & 1)			/* MUX1EN */
+            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
+        if ((s->config >> 3) & 1)			/* MUX2EN */
+            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
+        /* TODO: check that this is issued only following the chip reset
+         * and not in the middle of operation and that it is followed by
+         * the GPIO ports re-resablishing through WRITE_PORT_SEL and
+         * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
+         * warnings.  */
+        s->status = 0;
+        lm_kbd_irq_update(s);
+        s->kbd.len = 0;
+        s->kbd.start = 0;
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM832x_CMD_RESET:
+        if (value == 0xaa)
+            lm_kbd_reset(s);
+        else
+            lm_kbd_error(s, ERR_BADPAR);
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM823x_CMD_WRITE_PULL_DOWN:
+        if (!byte)
+            s->gpio.pull = value;
+        else {
+            s->gpio.pull |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_WRITE_PORT_SEL:
+        if (!byte)
+            s->gpio.dir = value;
+        else {
+            s->gpio.dir |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_WRITE_PORT_STATE:
+        if (!byte)
+            s->gpio.mask = value;
+        else {
+            s->gpio.mask |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+
+    case LM832x_CMD_SET_ACTIVE:
+        s->acttime = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM832x_CMD_SET_DEBOUNCE:
+        s->kbd.dbnctime = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!value)
+            lm_kbd_error(s, ERR_BADPAR);
+        break;
+
+    case LM832x_CMD_SET_KEY_SIZE:
+        s->kbd.size = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if (
+                        (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
+                        (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
+            lm_kbd_error(s, ERR_BADPAR);
+        break;
+
+    case LM832x_CMD_WRITE_CLOCK:
+        s->clock = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if ((value & 3) && (value & 3) != 3) {
+            lm_kbd_error(s, ERR_BADPAR);
+            fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
+                            __FUNCTION__);
+        }
+        /* TODO: Validate that the command is only issued once */
+        break;
+
+    case LM832x_CMD_PWM_WRITE:
+        if (byte == 0) {
+            if (!(value & 3) || (value >> 2) > 59) {
+                lm_kbd_error(s, ERR_BADPAR);
+                s->reg = LM832x_GENERAL_ERROR;
+                break;
+            }
+
+            s->pwm.faddr = value;
+            s->pwm.file[s->pwm.faddr] = 0;
+        } else if (byte == 1) {
+            s->pwm.file[s->pwm.faddr] |= value << 8;
+        } else if (byte == 2) {
+            s->pwm.file[s->pwm.faddr] |= value << 0;
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_PWM_START:
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!(value & 3) || (value >> 2) > 59) {
+            lm_kbd_error(s, ERR_BADPAR);
+            break;
+        }
+
+        s->pwm.addr[(value & 3) - 1] = value >> 2;
+        lm_kbd_pwm_start(s, (value & 3) - 1);
+        break;
+    case LM832x_CMD_PWM_STOP:
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!(value & 3)) {
+            lm_kbd_error(s, ERR_BADPAR);
+            break;
+        }
+
+        qemu_del_timer(s->pwm.tm[(value & 3) - 1]);
+        break;
+
+    case LM832x_GENERAL_ERROR:
+        lm_kbd_error(s, ERR_BADPAR);
+        break;
+    default:
+        lm_kbd_error(s, ERR_CMDUNK);
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
+
+    switch (event) {
+    case I2C_START_RECV:
+    case I2C_START_SEND:
+        s->i2c_cycle = 0;
+        s->i2c_dir = (event == I2C_START_SEND);
+        break;
+
+    default:
+        break;
+    }
+}
+
+static int lm_i2c_rx(i2c_slave *i2c)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
+
+    return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
+}
+
+static int lm_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+    LM823KbdState *s = (LM823KbdState *) i2c;
+
+    if (!s->i2c_cycle)
+        s->reg = data;
+    else
+        lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
+    s->i2c_cycle ++;
+
+    return 0;
+}
+
+static int lm_kbd_post_load(void *opaque, int version_id)
+{
+    LM823KbdState *s = opaque;
+
+    lm_kbd_irq_update(s);
+    lm_kbd_gpio_update(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm_kbd = {
+    .name = "LM8323",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = lm_kbd_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_I2C_SLAVE(i2c, LM823KbdState),
+        VMSTATE_UINT8(i2c_dir, LM823KbdState),
+        VMSTATE_UINT8(i2c_cycle, LM823KbdState),
+        VMSTATE_UINT8(reg, LM823KbdState),
+        VMSTATE_UINT8(config, LM823KbdState),
+        VMSTATE_UINT8(status, LM823KbdState),
+        VMSTATE_UINT8(acttime, LM823KbdState),
+        VMSTATE_UINT8(error, LM823KbdState),
+        VMSTATE_UINT8(clock, LM823KbdState),
+        VMSTATE_UINT16(gpio.pull, LM823KbdState),
+        VMSTATE_UINT16(gpio.mask, LM823KbdState),
+        VMSTATE_UINT16(gpio.dir, LM823KbdState),
+        VMSTATE_UINT16(gpio.level, LM823KbdState),
+        VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
+        VMSTATE_UINT8(kbd.size, LM823KbdState),
+        VMSTATE_UINT8(kbd.start, LM823KbdState),
+        VMSTATE_UINT8(kbd.len, LM823KbdState),
+        VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
+        VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
+        VMSTATE_UINT8(pwm.faddr, LM823KbdState),
+        VMSTATE_BUFFER(pwm.addr, LM823KbdState),
+        VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static int lm8323_init(i2c_slave *i2c)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
+
+    s->model = 0x8323;
+    s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s);
+    s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s);
+    s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s);
+    qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1);
+
+    lm_kbd_reset(s);
+
+    qemu_register_reset((void *) lm_kbd_reset, s);
+    return 0;
+}
+
+void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
+{
+    LM823KbdState *s = (LM823KbdState *) i2c;
+
+    if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
+        return;
+
+    if (s->kbd.len >= sizeof(s->kbd.fifo)) {
+        lm_kbd_error(s, ERR_FIFOOVR);
+        return;
+    }
+
+    s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
+            key | (state << 7);
+
+    /* We never set ERR_KEYOVR because we support multiple keys fine.  */
+    s->status |= INT_KEYPAD;
+    lm_kbd_irq_update(s);
+}
+
+static I2CSlaveInfo lm8323_info = {
+    .qdev.name = "lm8323",
+    .qdev.size = sizeof(LM823KbdState),
+    .qdev.vmsd = &vmstate_lm_kbd,
+    .init = lm8323_init,
+    .event = lm_i2c_event,
+    .recv = lm_i2c_rx,
+    .send = lm_i2c_tx
+};
+
+static void lm832x_register_devices(void)
+{
+    i2c_register_slave(&lm8323_info);
+}
+
+device_init(lm832x_register_devices)
diff --git a/qemu-0.15.x/hw/loader.c b/qemu-0.15.x/hw/loader.c
new file mode 100644
index 0000000..35d792e
--- /dev/null
+++ b/qemu-0.15.x/hw/loader.c
@@ -0,0 +1,795 @@
+/*
+ * QEMU Executable loader
+ *
+ * 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.
+ *
+ * Gunzip functionality in this file is derived from u-boot:
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "disas.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "uboot_image.h"
+#include "loader.h"
+#include "fw_cfg.h"
+
+#include <zlib.h>
+
+static int roms_loaded;
+
+/* return the size or -1 if error */
+int get_image_size(const char *filename)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    close(fd);
+    return size;
+}
+
+/* return the size or -1 if error */
+/* deprecated, because caller does not specify buffer size! */
+int load_image(const char *filename, uint8_t *addr)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+    if (read(fd, addr, size) != size) {
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return size;
+}
+
+/* read()-like version */
+int read_targphys(const char *name,
+                  int fd, target_phys_addr_t dst_addr, size_t nbytes)
+{
+    uint8_t *buf;
+    size_t did;
+
+    buf = qemu_malloc(nbytes);
+    did = read(fd, buf, nbytes);
+    if (did > 0)
+        rom_add_blob_fixed("read", buf, did, dst_addr);
+    qemu_free(buf);
+    return did;
+}
+
+/* return the size or -1 if error */
+int load_image_targphys(const char *filename,
+			target_phys_addr_t addr, int max_sz)
+{
+    int size;
+
+    size = get_image_size(filename);
+    if (size > 0)
+        rom_add_file_fixed(filename, addr, -1);
+    return size;
+}
+
+void pstrcpy_targphys(const char *name, target_phys_addr_t dest, int buf_size,
+                      const char *source)
+{
+    const char *nulp;
+    char *ptr;
+
+    if (buf_size <= 0) return;
+    nulp = memchr(source, 0, buf_size);
+    if (nulp) {
+        rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
+    } else {
+        rom_add_blob_fixed(name, source, buf_size, dest);
+        ptr = rom_ptr(dest + buf_size - 1);
+        *ptr = 0;
+    }
+}
+
+/* A.OUT loader */
+
+struct exec
+{
+  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
+  uint32_t a_text;   /* length of text, in bytes */
+  uint32_t a_data;   /* length of data, in bytes */
+  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
+  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
+  uint32_t a_entry;  /* start address */
+  uint32_t a_trsize; /* length of relocation info for text, in bytes */
+  uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+static void bswap_ahdr(struct exec *e)
+{
+    bswap32s(&e->a_info);
+    bswap32s(&e->a_text);
+    bswap32s(&e->a_data);
+    bswap32s(&e->a_bss);
+    bswap32s(&e->a_syms);
+    bswap32s(&e->a_entry);
+    bswap32s(&e->a_trsize);
+    bswap32s(&e->a_drsize);
+}
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x)							\
+    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :	\
+     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
+#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
+
+#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
+
+#define N_DATADDR(x, target_page_size) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
+
+
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+              int bswap_needed, target_phys_addr_t target_page_size)
+{
+    int fd, size, ret;
+    struct exec e;
+    uint32_t magic;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, &e, sizeof(e));
+    if (size < 0)
+        goto fail;
+
+    if (bswap_needed) {
+        bswap_ahdr(&e);
+    }
+
+    magic = N_MAGIC(e);
+    switch (magic) {
+    case ZMAGIC:
+    case QMAGIC:
+    case OMAGIC:
+        if (e.a_text + e.a_data > max_sz)
+            goto fail;
+	lseek(fd, N_TXTOFF(e), SEEK_SET);
+	size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
+	if (size < 0)
+	    goto fail;
+	break;
+    case NMAGIC:
+        if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
+            goto fail;
+	lseek(fd, N_TXTOFF(e), SEEK_SET);
+	size = read_targphys(filename, fd, addr, e.a_text);
+	if (size < 0)
+	    goto fail;
+        ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
+                            e.a_data);
+	if (ret < 0)
+	    goto fail;
+	size += ret;
+	break;
+    default:
+	goto fail;
+    }
+    close(fd);
+    return size;
+ fail:
+    close(fd);
+    return -1;
+}
+
+/* ELF loader */
+
+static void *load_at(int fd, int offset, int size)
+{
+    void *ptr;
+    if (lseek(fd, offset, SEEK_SET) < 0)
+        return NULL;
+    ptr = qemu_malloc(size);
+    if (read(fd, ptr, size) != size) {
+        qemu_free(ptr);
+        return NULL;
+    }
+    return ptr;
+}
+
+#ifdef ELF_CLASS
+#undef ELF_CLASS
+#endif
+
+#define ELF_CLASS   ELFCLASS32
+#include "elf.h"
+
+#define SZ		32
+#define elf_word        uint32_t
+#define elf_sword        int32_t
+#define bswapSZs	bswap32s
+#include "elf_ops.h"
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef elf_sword
+#undef bswapSZs
+#undef SZ
+#define elfhdr		elf64_hdr
+#define elf_phdr	elf64_phdr
+#define elf_note	elf64_note
+#define elf_shdr	elf64_shdr
+#define elf_sym		elf64_sym
+#define elf_word        uint64_t
+#define elf_sword        int64_t
+#define bswapSZs	bswap64s
+#define SZ		64
+#include "elf_ops.h"
+
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
+             uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
+{
+    int fd, data_order, target_data_order, must_swab, ret;
+    uint8_t e_ident[EI_NIDENT];
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        perror(filename);
+        return -1;
+    }
+    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+        goto fail;
+    if (e_ident[0] != ELFMAG0 ||
+        e_ident[1] != ELFMAG1 ||
+        e_ident[2] != ELFMAG2 ||
+        e_ident[3] != ELFMAG3)
+        goto fail;
+#ifdef HOST_WORDS_BIGENDIAN
+    data_order = ELFDATA2MSB;
+#else
+    data_order = ELFDATA2LSB;
+#endif
+    must_swab = data_order != e_ident[EI_DATA];
+    if (big_endian) {
+        target_data_order = ELFDATA2MSB;
+    } else {
+        target_data_order = ELFDATA2LSB;
+    }
+
+    if (target_data_order != e_ident[EI_DATA]) {
+        goto fail;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    if (e_ident[EI_CLASS] == ELFCLASS64) {
+        ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
+                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+    } else {
+        ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
+                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+    }
+
+    close(fd);
+    return ret;
+
+ fail:
+    close(fd);
+    return -1;
+}
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef HOST_WORDS_BIGENDIAN
+    bswap32s(&hdr->ih_magic);
+    bswap32s(&hdr->ih_hcrc);
+    bswap32s(&hdr->ih_time);
+    bswap32s(&hdr->ih_size);
+    bswap32s(&hdr->ih_load);
+    bswap32s(&hdr->ih_ep);
+    bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+
+#define ZALLOC_ALIGNMENT	16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = qemu_malloc(size);
+
+    return (p);
+}
+
+static void zfree(void *x, void *addr)
+{
+    qemu_free(addr);
+}
+
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+/* This is the maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES 0x800000
+
+static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+                      size_t srclen)
+{
+    z_stream s;
+    ssize_t dstbytes;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+        puts ("Error: Bad gzipped data\n");
+        return -1;
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+        i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & COMMENT) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & HEAD_CRC) != 0)
+        i += 2;
+    if (i >= srclen) {
+        puts ("Error: gunzip out of data in header\n");
+        return -1;
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+        printf ("Error: inflateInit2() returned %d\n", r);
+        return (-1);
+    }
+    s.next_in = src + i;
+    s.avail_in = srclen - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+        printf ("Error: inflate() returned %d\n", r);
+        return -1;
+    }
+    dstbytes = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+
+    return dstbytes;
+}
+
+/* Load a U-Boot image.  */
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+                target_phys_addr_t *loadaddr, int *is_linux)
+{
+    int fd;
+    int size;
+    uboot_image_header_t h;
+    uboot_image_header_t *hdr = &h;
+    uint8_t *data = NULL;
+    int ret = -1;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, hdr, sizeof(uboot_image_header_t));
+    if (size < 0)
+        goto out;
+
+    bswap_uboot_header(hdr);
+
+    if (hdr->ih_magic != IH_MAGIC)
+        goto out;
+
+    /* TODO: Implement other image types.  */
+    if (hdr->ih_type != IH_TYPE_KERNEL) {
+        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+        goto out;
+    }
+
+    switch (hdr->ih_comp) {
+    case IH_COMP_NONE:
+    case IH_COMP_GZIP:
+        break;
+    default:
+        fprintf(stderr,
+                "Unable to load u-boot images with compression type %d\n",
+                hdr->ih_comp);
+        goto out;
+    }
+
+    /* TODO: Check CPU type.  */
+    if (is_linux) {
+        if (hdr->ih_os == IH_OS_LINUX)
+            *is_linux = 1;
+        else
+            *is_linux = 0;
+    }
+
+    *ep = hdr->ih_ep;
+    data = qemu_malloc(hdr->ih_size);
+
+    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+        fprintf(stderr, "Error reading file\n");
+        goto out;
+    }
+
+    if (hdr->ih_comp == IH_COMP_GZIP) {
+        uint8_t *compressed_data;
+        size_t max_bytes;
+        ssize_t bytes;
+
+        compressed_data = data;
+        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
+        data = qemu_malloc(max_bytes);
+
+        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+        qemu_free(compressed_data);
+        if (bytes < 0) {
+            fprintf(stderr, "Unable to decompress gzipped image!\n");
+            goto out;
+        }
+        hdr->ih_size = bytes;
+    }
+
+    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
+
+    if (loadaddr)
+        *loadaddr = hdr->ih_load;
+
+    ret = hdr->ih_size;
+
+out:
+    if (data)
+        qemu_free(data);
+    close(fd);
+    return ret;
+}
+
+/*
+ * Functions for reboot-persistent memory regions.
+ *  - used for vga bios and option roms.
+ *  - also linux kernel (-kernel / -initrd).
+ */
+
+typedef struct Rom Rom;
+
+struct Rom {
+    char *name;
+    char *path;
+    size_t romsize;
+    uint8_t *data;
+    int isrom;
+    char *fw_dir;
+    char *fw_file;
+
+    target_phys_addr_t addr;
+    QTAILQ_ENTRY(Rom) next;
+};
+
+static FWCfgState *fw_cfg;
+static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
+
+static void rom_insert(Rom *rom)
+{
+    Rom *item;
+
+    if (roms_loaded) {
+        hw_error ("ROM images must be loaded at startup\n");
+    }
+
+    /* list is ordered by load address */
+    QTAILQ_FOREACH(item, &roms, next) {
+        if (rom->addr >= item->addr)
+            continue;
+        QTAILQ_INSERT_BEFORE(item, rom, next);
+        return;
+    }
+    QTAILQ_INSERT_TAIL(&roms, rom, next);
+}
+
+int rom_add_file(const char *file, const char *fw_dir,
+                 target_phys_addr_t addr, int32_t bootindex)
+{
+    Rom *rom;
+    int rc, fd = -1;
+    char devpath[100];
+
+    rom = qemu_mallocz(sizeof(*rom));
+    rom->name = qemu_strdup(file);
+    rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
+    if (rom->path == NULL) {
+        rom->path = qemu_strdup(file);
+    }
+
+    fd = open(rom->path, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        fprintf(stderr, "Could not open option rom '%s': %s\n",
+                rom->path, strerror(errno));
+        goto err;
+    }
+
+    if (fw_dir) {
+        rom->fw_dir  = qemu_strdup(fw_dir);
+        rom->fw_file = qemu_strdup(file);
+    }
+    rom->addr    = addr;
+    rom->romsize = lseek(fd, 0, SEEK_END);
+    rom->data    = qemu_mallocz(rom->romsize);
+    lseek(fd, 0, SEEK_SET);
+    rc = read(fd, rom->data, rom->romsize);
+    if (rc != rom->romsize) {
+        fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n",
+                rom->name, rc, rom->romsize);
+        goto err;
+    }
+    close(fd);
+    rom_insert(rom);
+    if (rom->fw_file && fw_cfg) {
+        const char *basename;
+        char fw_file_name[56];
+
+        basename = strrchr(rom->fw_file, '/');
+        if (basename) {
+            basename++;
+        } else {
+            basename = rom->fw_file;
+        }
+        snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
+                 basename);
+        fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize);
+        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
+    } else {
+        snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
+    }
+
+    add_boot_device_path(bootindex, NULL, devpath);
+    return 0;
+
+err:
+    if (fd != -1)
+        close(fd);
+    qemu_free(rom->data);
+    qemu_free(rom->path);
+    qemu_free(rom->name);
+    qemu_free(rom);
+    return -1;
+}
+
+int rom_add_blob(const char *name, const void *blob, size_t len,
+                 target_phys_addr_t addr)
+{
+    Rom *rom;
+
+    rom = qemu_mallocz(sizeof(*rom));
+    rom->name    = qemu_strdup(name);
+    rom->addr    = addr;
+    rom->romsize = len;
+    rom->data    = qemu_mallocz(rom->romsize);
+    memcpy(rom->data, blob, len);
+    rom_insert(rom);
+    return 0;
+}
+
+int rom_add_vga(const char *file)
+{
+    return rom_add_file(file, "vgaroms", 0, -1);
+}
+
+int rom_add_option(const char *file, int32_t bootindex)
+{
+    return rom_add_file(file, "genroms", 0, bootindex);
+}
+
+static void rom_reset(void *unused)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->data == NULL) {
+            continue;
+        }
+        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
+        if (rom->isrom) {
+            /* rom needs to be written only once */
+            qemu_free(rom->data);
+            rom->data = NULL;
+        }
+    }
+}
+
+int rom_load_all(void)
+{
+    target_phys_addr_t addr = 0;
+    int memtype;
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (addr > rom->addr) {
+            fprintf(stderr, "rom: requested regions overlap "
+                    "(rom %s. free=0x" TARGET_FMT_plx
+                    ", addr=0x" TARGET_FMT_plx ")\n",
+                    rom->name, addr, rom->addr);
+            return -1;
+        }
+        addr  = rom->addr;
+        addr += rom->romsize;
+        memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT);
+        if (memtype == IO_MEM_ROM)
+            rom->isrom = 1;
+    }
+    qemu_register_reset(rom_reset, NULL);
+    roms_loaded = 1;
+    return 0;
+}
+
+void rom_set_fw(void *f)
+{
+    fw_cfg = f;
+}
+
+static Rom *find_rom(target_phys_addr_t addr)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->addr > addr) {
+            continue;
+        }
+        if (rom->addr + rom->romsize < addr) {
+            continue;
+        }
+        return rom;
+    }
+    return NULL;
+}
+
+/*
+ * Copies memory from registered ROMs to dest. Any memory that is contained in
+ * a ROM between addr and addr + size is copied. Note that this can involve
+ * multiple ROMs, which need not start at addr and need not end at addr + size.
+ */
+int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
+{
+    target_phys_addr_t end = addr + size;
+    uint8_t *s, *d = dest;
+    size_t l = 0;
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->addr + rom->romsize < addr) {
+            continue;
+        }
+        if (rom->addr > end) {
+            break;
+        }
+        if (!rom->data) {
+            continue;
+        }
+
+        d = dest + (rom->addr - addr);
+        s = rom->data;
+        l = rom->romsize;
+
+        if ((d + l) > (dest + size)) {
+            l = dest - d;
+        }
+
+        memcpy(d, s, l);
+    }
+
+    return (d + l) - dest;
+}
+
+void *rom_ptr(target_phys_addr_t addr)
+{
+    Rom *rom;
+
+    rom = find_rom(addr);
+    if (!rom || !rom->data)
+        return NULL;
+    return rom->data + (addr - rom->addr);
+}
+
+void do_info_roms(Monitor *mon)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (!rom->fw_file) {
+            monitor_printf(mon, "addr=" TARGET_FMT_plx
+                           " size=0x%06zx mem=%s name=\"%s\" \n",
+                           rom->addr, rom->romsize,
+                           rom->isrom ? "rom" : "ram",
+                           rom->name);
+        } else {
+            monitor_printf(mon, "fw=%s/%s"
+                           " size=0x%06zx name=\"%s\" \n",
+                           rom->fw_dir,
+                           rom->fw_file,
+                           rom->romsize,
+                           rom->name);
+        }
+    }
+}
diff --git a/qemu-0.15.x/hw/loader.h b/qemu-0.15.x/hw/loader.h
new file mode 100644
index 0000000..fc6bdff
--- /dev/null
+++ b/qemu-0.15.x/hw/loader.h
@@ -0,0 +1,48 @@
+#ifndef LOADER_H
+#define LOADER_H
+
+/* loader.c */
+int get_image_size(const char *filename);
+int load_image(const char *filename, uint8_t *addr); /* deprecated */
+int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
+int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
+             uint64_t *highaddr, int big_endian, int elf_machine,
+             int clear_lsb);
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+              int bswap_needed, target_phys_addr_t target_page_size);
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+                target_phys_addr_t *loadaddr, int *is_linux);
+
+int read_targphys(const char *name,
+                  int fd, target_phys_addr_t dst_addr, size_t nbytes);
+void pstrcpy_targphys(const char *name,
+                      target_phys_addr_t dest, int buf_size,
+                      const char *source);
+
+
+int rom_add_file(const char *file, const char *fw_dir,
+                 target_phys_addr_t addr, int32_t bootindex);
+int rom_add_blob(const char *name, const void *blob, size_t len,
+                 target_phys_addr_t addr);
+int rom_load_all(void);
+void rom_set_fw(void *f);
+int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size);
+void *rom_ptr(target_phys_addr_t addr);
+void do_info_roms(Monitor *mon);
+
+#define rom_add_file_fixed(_f, _a, _i)          \
+    rom_add_file(_f, NULL, _a, _i)
+#define rom_add_blob_fixed(_f, _b, _l, _a)      \
+    rom_add_blob(_f, _b, _l, _a)
+
+#define PC_ROM_MIN_VGA     0xc0000
+#define PC_ROM_MIN_OPTION  0xc8000
+#define PC_ROM_MAX         0xe0000
+#define PC_ROM_ALIGN       0x800
+#define PC_ROM_SIZE        (PC_ROM_MAX - PC_ROM_MIN_VGA)
+
+int rom_add_vga(const char *file);
+int rom_add_option(const char *file, int32_t bootindex);
+
+#endif
diff --git a/qemu-0.15.x/hw/lsi53c895a.c b/qemu-0.15.x/hw/lsi53c895a.c
new file mode 100644
index 0000000..e9904c4
--- /dev/null
+++ b/qemu-0.15.x/hw/lsi53c895a.c
@@ -0,0 +1,2299 @@
+/*
+ * QEMU LSI53C895A SCSI Host Bus Adapter emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+/* ??? Need to check if the {read,write}[wl] routines work properly on
+   big-endian targets.  */
+
+#include <assert.h>
+
+#include "hw.h"
+#include "pci.h"
+#include "scsi.h"
+#include "block_int.h"
+
+//#define DEBUG_LSI
+//#define DEBUG_LSI_REG
+
+#ifdef DEBUG_LSI
+#define DPRINTF(fmt, ...) \
+do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define LSI_MAX_DEVS 7
+
+#define LSI_SCNTL0_TRG    0x01
+#define LSI_SCNTL0_AAP    0x02
+#define LSI_SCNTL0_EPC    0x08
+#define LSI_SCNTL0_WATN   0x10
+#define LSI_SCNTL0_START  0x20
+
+#define LSI_SCNTL1_SST    0x01
+#define LSI_SCNTL1_IARB   0x02
+#define LSI_SCNTL1_AESP   0x04
+#define LSI_SCNTL1_RST    0x08
+#define LSI_SCNTL1_CON    0x10
+#define LSI_SCNTL1_DHP    0x20
+#define LSI_SCNTL1_ADB    0x40
+#define LSI_SCNTL1_EXC    0x80
+
+#define LSI_SCNTL2_WSR    0x01
+#define LSI_SCNTL2_VUE0   0x02
+#define LSI_SCNTL2_VUE1   0x04
+#define LSI_SCNTL2_WSS    0x08
+#define LSI_SCNTL2_SLPHBEN 0x10
+#define LSI_SCNTL2_SLPMD  0x20
+#define LSI_SCNTL2_CHM    0x40
+#define LSI_SCNTL2_SDU    0x80
+
+#define LSI_ISTAT0_DIP    0x01
+#define LSI_ISTAT0_SIP    0x02
+#define LSI_ISTAT0_INTF   0x04
+#define LSI_ISTAT0_CON    0x08
+#define LSI_ISTAT0_SEM    0x10
+#define LSI_ISTAT0_SIGP   0x20
+#define LSI_ISTAT0_SRST   0x40
+#define LSI_ISTAT0_ABRT   0x80
+
+#define LSI_ISTAT1_SI     0x01
+#define LSI_ISTAT1_SRUN   0x02
+#define LSI_ISTAT1_FLSH   0x04
+
+#define LSI_SSTAT0_SDP0   0x01
+#define LSI_SSTAT0_RST    0x02
+#define LSI_SSTAT0_WOA    0x04
+#define LSI_SSTAT0_LOA    0x08
+#define LSI_SSTAT0_AIP    0x10
+#define LSI_SSTAT0_OLF    0x20
+#define LSI_SSTAT0_ORF    0x40
+#define LSI_SSTAT0_ILF    0x80
+
+#define LSI_SIST0_PAR     0x01
+#define LSI_SIST0_RST     0x02
+#define LSI_SIST0_UDC     0x04
+#define LSI_SIST0_SGE     0x08
+#define LSI_SIST0_RSL     0x10
+#define LSI_SIST0_SEL     0x20
+#define LSI_SIST0_CMP     0x40
+#define LSI_SIST0_MA      0x80
+
+#define LSI_SIST1_HTH     0x01
+#define LSI_SIST1_GEN     0x02
+#define LSI_SIST1_STO     0x04
+#define LSI_SIST1_SBMC    0x10
+
+#define LSI_SOCL_IO       0x01
+#define LSI_SOCL_CD       0x02
+#define LSI_SOCL_MSG      0x04
+#define LSI_SOCL_ATN      0x08
+#define LSI_SOCL_SEL      0x10
+#define LSI_SOCL_BSY      0x20
+#define LSI_SOCL_ACK      0x40
+#define LSI_SOCL_REQ      0x80
+
+#define LSI_DSTAT_IID     0x01
+#define LSI_DSTAT_SIR     0x04
+#define LSI_DSTAT_SSI     0x08
+#define LSI_DSTAT_ABRT    0x10
+#define LSI_DSTAT_BF      0x20
+#define LSI_DSTAT_MDPE    0x40
+#define LSI_DSTAT_DFE     0x80
+
+#define LSI_DCNTL_COM     0x01
+#define LSI_DCNTL_IRQD    0x02
+#define LSI_DCNTL_STD     0x04
+#define LSI_DCNTL_IRQM    0x08
+#define LSI_DCNTL_SSM     0x10
+#define LSI_DCNTL_PFEN    0x20
+#define LSI_DCNTL_PFF     0x40
+#define LSI_DCNTL_CLSE    0x80
+
+#define LSI_DMODE_MAN     0x01
+#define LSI_DMODE_BOF     0x02
+#define LSI_DMODE_ERMP    0x04
+#define LSI_DMODE_ERL     0x08
+#define LSI_DMODE_DIOM    0x10
+#define LSI_DMODE_SIOM    0x20
+
+#define LSI_CTEST2_DACK   0x01
+#define LSI_CTEST2_DREQ   0x02
+#define LSI_CTEST2_TEOP   0x04
+#define LSI_CTEST2_PCICIE 0x08
+#define LSI_CTEST2_CM     0x10
+#define LSI_CTEST2_CIO    0x20
+#define LSI_CTEST2_SIGP   0x40
+#define LSI_CTEST2_DDIR   0x80
+
+#define LSI_CTEST5_BL2    0x04
+#define LSI_CTEST5_DDIR   0x08
+#define LSI_CTEST5_MASR   0x10
+#define LSI_CTEST5_DFSN   0x20
+#define LSI_CTEST5_BBCK   0x40
+#define LSI_CTEST5_ADCK   0x80
+
+#define LSI_CCNTL0_DILS   0x01
+#define LSI_CCNTL0_DISFC  0x10
+#define LSI_CCNTL0_ENNDJ  0x20
+#define LSI_CCNTL0_PMJCTL 0x40
+#define LSI_CCNTL0_ENPMJ  0x80
+
+#define LSI_CCNTL1_EN64DBMV  0x01
+#define LSI_CCNTL1_EN64TIBMV 0x02
+#define LSI_CCNTL1_64TIMOD   0x04
+#define LSI_CCNTL1_DDAC      0x08
+#define LSI_CCNTL1_ZMOD      0x80
+
+/* Enable Response to Reselection */
+#define LSI_SCID_RRE      0x60
+
+#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
+
+#define PHASE_DO          0
+#define PHASE_DI          1
+#define PHASE_CMD         2
+#define PHASE_ST          3
+#define PHASE_MO          6
+#define PHASE_MI          7
+#define PHASE_MASK        7
+
+/* Maximum length of MSG IN data.  */
+#define LSI_MAX_MSGIN_LEN 8
+
+/* Flag set if this is a tagged command.  */
+#define LSI_TAG_VALID     (1 << 16)
+
+typedef struct lsi_request {
+    SCSIRequest *req;
+    uint32_t tag;
+    uint32_t dma_len;
+    uint8_t *dma_buf;
+    uint32_t pending;
+    int out;
+    QTAILQ_ENTRY(lsi_request) next;
+} lsi_request;
+
+typedef struct {
+    PCIDevice dev;
+    int mmio_io_addr;
+    int ram_io_addr;
+    uint32_t script_ram_base;
+
+    int carry; /* ??? Should this be an a visible register somewhere?  */
+    int status;
+    /* Action to take at the end of a MSG IN phase.
+       0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN.  */
+    int msg_action;
+    int msg_len;
+    uint8_t msg[LSI_MAX_MSGIN_LEN];
+    /* 0 if SCRIPTS are running or stopped.
+     * 1 if a Wait Reselect instruction has been issued.
+     * 2 if processing DMA from lsi_execute_script.
+     * 3 if a DMA operation is in progress.  */
+    int waiting;
+    SCSIBus bus;
+    int current_lun;
+    /* The tag is a combination of the device ID and the SCSI tag.  */
+    uint32_t select_tag;
+    int command_complete;
+    QTAILQ_HEAD(, lsi_request) queue;
+    lsi_request *current;
+
+    uint32_t dsa;
+    uint32_t temp;
+    uint32_t dnad;
+    uint32_t dbc;
+    uint8_t istat0;
+    uint8_t istat1;
+    uint8_t dcmd;
+    uint8_t dstat;
+    uint8_t dien;
+    uint8_t sist0;
+    uint8_t sist1;
+    uint8_t sien0;
+    uint8_t sien1;
+    uint8_t mbox0;
+    uint8_t mbox1;
+    uint8_t dfifo;
+    uint8_t ctest2;
+    uint8_t ctest3;
+    uint8_t ctest4;
+    uint8_t ctest5;
+    uint8_t ccntl0;
+    uint8_t ccntl1;
+    uint32_t dsp;
+    uint32_t dsps;
+    uint8_t dmode;
+    uint8_t dcntl;
+    uint8_t scntl0;
+    uint8_t scntl1;
+    uint8_t scntl2;
+    uint8_t scntl3;
+    uint8_t sstat0;
+    uint8_t sstat1;
+    uint8_t scid;
+    uint8_t sxfer;
+    uint8_t socl;
+    uint8_t sdid;
+    uint8_t ssid;
+    uint8_t sfbr;
+    uint8_t stest1;
+    uint8_t stest2;
+    uint8_t stest3;
+    uint8_t sidl;
+    uint8_t stime0;
+    uint8_t respid0;
+    uint8_t respid1;
+    uint32_t mmrs;
+    uint32_t mmws;
+    uint32_t sfs;
+    uint32_t drs;
+    uint32_t sbms;
+    uint32_t dbms;
+    uint32_t dnad64;
+    uint32_t pmjad1;
+    uint32_t pmjad2;
+    uint32_t rbc;
+    uint32_t ua;
+    uint32_t ia;
+    uint32_t sbc;
+    uint32_t csbc;
+    uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
+    uint8_t sbr;
+
+    /* Script ram is stored as 32-bit words in host byteorder.  */
+    uint32_t script_ram[2048];
+} LSIState;
+
+static inline int lsi_irq_on_rsl(LSIState *s)
+{
+    return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
+}
+
+static void lsi_soft_reset(LSIState *s)
+{
+    lsi_request *p;
+
+    DPRINTF("Reset\n");
+    s->carry = 0;
+
+    s->msg_action = 0;
+    s->msg_len = 0;
+    s->waiting = 0;
+    s->dsa = 0;
+    s->dnad = 0;
+    s->dbc = 0;
+    s->temp = 0;
+    memset(s->scratch, 0, sizeof(s->scratch));
+    s->istat0 = 0;
+    s->istat1 = 0;
+    s->dcmd = 0x40;
+    s->dstat = LSI_DSTAT_DFE;
+    s->dien = 0;
+    s->sist0 = 0;
+    s->sist1 = 0;
+    s->sien0 = 0;
+    s->sien1 = 0;
+    s->mbox0 = 0;
+    s->mbox1 = 0;
+    s->dfifo = 0;
+    s->ctest2 = LSI_CTEST2_DACK;
+    s->ctest3 = 0;
+    s->ctest4 = 0;
+    s->ctest5 = 0;
+    s->ccntl0 = 0;
+    s->ccntl1 = 0;
+    s->dsp = 0;
+    s->dsps = 0;
+    s->dmode = 0;
+    s->dcntl = 0;
+    s->scntl0 = 0xc0;
+    s->scntl1 = 0;
+    s->scntl2 = 0;
+    s->scntl3 = 0;
+    s->sstat0 = 0;
+    s->sstat1 = 0;
+    s->scid = 7;
+    s->sxfer = 0;
+    s->socl = 0;
+    s->sdid = 0;
+    s->ssid = 0;
+    s->stest1 = 0;
+    s->stest2 = 0;
+    s->stest3 = 0;
+    s->sidl = 0;
+    s->stime0 = 0;
+    s->respid0 = 0x80;
+    s->respid1 = 0;
+    s->mmrs = 0;
+    s->mmws = 0;
+    s->sfs = 0;
+    s->drs = 0;
+    s->sbms = 0;
+    s->dbms = 0;
+    s->dnad64 = 0;
+    s->pmjad1 = 0;
+    s->pmjad2 = 0;
+    s->rbc = 0;
+    s->ua = 0;
+    s->ia = 0;
+    s->sbc = 0;
+    s->csbc = 0;
+    s->sbr = 0;
+    while (!QTAILQ_EMPTY(&s->queue)) {
+        p = QTAILQ_FIRST(&s->queue);
+        QTAILQ_REMOVE(&s->queue, p, next);
+        qemu_free(p);
+    }
+    if (s->current) {
+        qemu_free(s->current);
+        s->current = NULL;
+    }
+}
+
+static int lsi_dma_40bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
+        return 1;
+    return 0;
+}
+
+static int lsi_dma_ti64bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
+        return 1;
+    return 0;
+}
+
+static int lsi_dma_64bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
+        return 1;
+    return 0;
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset);
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
+static void lsi_execute_script(LSIState *s);
+static void lsi_reselect(LSIState *s, lsi_request *p);
+
+static inline uint32_t read_dword(LSIState *s, uint32_t addr)
+{
+    uint32_t buf;
+
+    /* Optimize reading from SCRIPTS RAM.  */
+    if ((addr & 0xffffe000) == s->script_ram_base) {
+        return s->script_ram[(addr & 0x1fff) >> 2];
+    }
+    cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
+    return cpu_to_le32(buf);
+}
+
+static void lsi_stop_script(LSIState *s)
+{
+    s->istat1 &= ~LSI_ISTAT1_SRUN;
+}
+
+static void lsi_update_irq(LSIState *s)
+{
+    int level;
+    static int last_level;
+    lsi_request *p;
+
+    /* It's unclear whether the DIP/SIP bits should be cleared when the
+       Interrupt Status Registers are cleared or when istat0 is read.
+       We currently do the formwer, which seems to work.  */
+    level = 0;
+    if (s->dstat) {
+        if (s->dstat & s->dien)
+            level = 1;
+        s->istat0 |= LSI_ISTAT0_DIP;
+    } else {
+        s->istat0 &= ~LSI_ISTAT0_DIP;
+    }
+
+    if (s->sist0 || s->sist1) {
+        if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
+            level = 1;
+        s->istat0 |= LSI_ISTAT0_SIP;
+    } else {
+        s->istat0 &= ~LSI_ISTAT0_SIP;
+    }
+    if (s->istat0 & LSI_ISTAT0_INTF)
+        level = 1;
+
+    if (level != last_level) {
+        DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
+                level, s->dstat, s->sist1, s->sist0);
+        last_level = level;
+    }
+    qemu_set_irq(s->dev.irq[0], level);
+
+    if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
+        DPRINTF("Handled IRQs & disconnected, looking for pending "
+                "processes\n");
+        QTAILQ_FOREACH(p, &s->queue, next) {
+            if (p->pending) {
+                lsi_reselect(s, p);
+                break;
+            }
+        }
+    }
+}
+
+/* Stop SCRIPTS execution and raise a SCSI interrupt.  */
+static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
+{
+    uint32_t mask0;
+    uint32_t mask1;
+
+    DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
+            stat1, stat0, s->sist1, s->sist0);
+    s->sist0 |= stat0;
+    s->sist1 |= stat1;
+    /* Stop processor on fatal or unmasked interrupt.  As a special hack
+       we don't stop processing when raising STO.  Instead continue
+       execution and stop at the next insn that accesses the SCSI bus.  */
+    mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
+    mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
+    mask1 &= ~LSI_SIST1_STO;
+    if (s->sist0 & mask0 || s->sist1 & mask1) {
+        lsi_stop_script(s);
+    }
+    lsi_update_irq(s);
+}
+
+/* Stop SCRIPTS execution and raise a DMA interrupt.  */
+static void lsi_script_dma_interrupt(LSIState *s, int stat)
+{
+    DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
+    s->dstat |= stat;
+    lsi_update_irq(s);
+    lsi_stop_script(s);
+}
+
+static inline void lsi_set_phase(LSIState *s, int phase)
+{
+    s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
+}
+
+static void lsi_bad_phase(LSIState *s, int out, int new_phase)
+{
+    /* Trigger a phase mismatch.  */
+    if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
+        if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
+            s->dsp = out ? s->pmjad1 : s->pmjad2;
+        } else {
+            s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
+        }
+        DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
+    } else {
+        DPRINTF("Phase mismatch interrupt\n");
+        lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+        lsi_stop_script(s);
+    }
+    lsi_set_phase(s, new_phase);
+}
+
+
+/* Resume SCRIPTS execution after a DMA operation.  */
+static void lsi_resume_script(LSIState *s)
+{
+    if (s->waiting != 2) {
+        s->waiting = 0;
+        lsi_execute_script(s);
+    } else {
+        s->waiting = 0;
+    }
+}
+
+static void lsi_disconnect(LSIState *s)
+{
+    s->scntl1 &= ~LSI_SCNTL1_CON;
+    s->sstat1 &= ~PHASE_MASK;
+}
+
+static void lsi_bad_selection(LSIState *s, uint32_t id)
+{
+    DPRINTF("Selected absent target %d\n", id);
+    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
+    lsi_disconnect(s);
+}
+
+/* Initiate a SCSI layer data transfer.  */
+static void lsi_do_dma(LSIState *s, int out)
+{
+    uint32_t count, id;
+    target_phys_addr_t addr;
+    SCSIDevice *dev;
+
+    assert(s->current);
+    if (!s->current->dma_len) {
+        /* Wait until data is available.  */
+        DPRINTF("DMA no data available\n");
+        return;
+    }
+
+    id = (s->current->tag >> 8) & 0xf;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
+    count = s->dbc;
+    if (count > s->current->dma_len)
+        count = s->current->dma_len;
+
+    addr = s->dnad;
+    /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
+    if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
+        addr |= ((uint64_t)s->dnad64 << 32);
+    else if (s->dbms)
+        addr |= ((uint64_t)s->dbms << 32);
+    else if (s->sbms)
+        addr |= ((uint64_t)s->sbms << 32);
+
+    DPRINTF("DMA addr=0x" TARGET_FMT_plx " len=%d\n", addr, count);
+    s->csbc += count;
+    s->dnad += count;
+    s->dbc -= count;
+     if (s->current->dma_buf == NULL) {
+        s->current->dma_buf = scsi_req_get_buf(s->current->req);
+    }
+    /* ??? Set SFBR to first data byte.  */
+    if (out) {
+        cpu_physical_memory_read(addr, s->current->dma_buf, count);
+    } else {
+        cpu_physical_memory_write(addr, s->current->dma_buf, count);
+    }
+    s->current->dma_len -= count;
+    if (s->current->dma_len == 0) {
+        s->current->dma_buf = NULL;
+        scsi_req_continue(s->current->req);
+    } else {
+        s->current->dma_buf += count;
+        lsi_resume_script(s);
+    }
+}
+
+
+/* Add a command to the queue.  */
+static void lsi_queue_command(LSIState *s)
+{
+    lsi_request *p = s->current;
+
+    DPRINTF("Queueing tag=0x%x\n", p->tag);
+    assert(s->current != NULL);
+    assert(s->current->dma_len == 0);
+    QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
+    s->current = NULL;
+
+    p->pending = 0;
+    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+}
+
+/* Queue a byte for a MSG IN phase.  */
+static void lsi_add_msg_byte(LSIState *s, uint8_t data)
+{
+    if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
+        BADF("MSG IN data too long\n");
+    } else {
+        DPRINTF("MSG IN 0x%02x\n", data);
+        s->msg[s->msg_len++] = data;
+    }
+}
+
+/* Perform reselection to continue a command.  */
+static void lsi_reselect(LSIState *s, lsi_request *p)
+{
+    int id;
+
+    assert(s->current == NULL);
+    QTAILQ_REMOVE(&s->queue, p, next);
+    s->current = p;
+
+    id = (p->tag >> 8) & 0xf;
+    s->ssid = id | 0x80;
+    /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
+    if (!(s->dcntl & LSI_DCNTL_COM)) {
+        s->sfbr = 1 << (id & 0x7);
+    }
+    DPRINTF("Reselected target %d\n", id);
+    s->scntl1 |= LSI_SCNTL1_CON;
+    lsi_set_phase(s, PHASE_MI);
+    s->msg_action = p->out ? 2 : 3;
+    s->current->dma_len = p->pending;
+    lsi_add_msg_byte(s, 0x80);
+    if (s->current->tag & LSI_TAG_VALID) {
+        lsi_add_msg_byte(s, 0x20);
+        lsi_add_msg_byte(s, p->tag & 0xff);
+    }
+
+    if (lsi_irq_on_rsl(s)) {
+        lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
+    }
+}
+
+static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
+{
+    lsi_request *p;
+
+    QTAILQ_FOREACH(p, &s->queue, next) {
+        if (p->tag == tag) {
+            return p;
+        }
+    }
+
+    return NULL;
+}
+
+static void lsi_request_cancelled(SCSIRequest *req)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    lsi_request *p = req->hba_private;
+
+    if (s->current && req == s->current->req) {
+        scsi_req_unref(req);
+        qemu_free(s->current);
+        s->current = NULL;
+        return;
+    }
+
+    if (p) {
+        QTAILQ_REMOVE(&s->queue, p, next);
+        scsi_req_unref(req);
+        qemu_free(p);
+    }
+}
+
+/* Record that data is available for a queued command.  Returns zero if
+   the device was reselected, nonzero if the IO is deferred.  */
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
+{
+    lsi_request *p = req->hba_private;
+
+    if (p->pending) {
+        BADF("Multiple IO pending for request %p\n", p);
+    }
+    p->pending = len;
+    /* Reselect if waiting for it, or if reselection triggers an IRQ
+       and the bus is free.
+       Since no interrupt stacking is implemented in the emulation, it
+       is also required that there are no pending interrupts waiting
+       for service from the device driver. */
+    if (s->waiting == 1 ||
+        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
+         !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
+        /* Reselect device.  */
+        lsi_reselect(s, p);
+        return 0;
+    } else {
+        DPRINTF("Queueing IO tag=0x%x\n", tag);
+        p->pending = len;
+        return 1;
+    }
+}
+
+ /* Callback to indicate that the SCSI layer has completed a command.  */
+static void lsi_command_complete(SCSIRequest *req, uint32_t status)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    int out;
+
+    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+    DPRINTF("Command complete status=%d\n", (int)status);
+    s->status = status;
+    s->command_complete = 2;
+    if (s->waiting && s->dbc != 0) {
+        /* Raise phase mismatch for short transfers.  */
+        lsi_bad_phase(s, out, PHASE_ST);
+    } else {
+        lsi_set_phase(s, PHASE_ST);
+    }
+
+    if (s->current && req == s->current->req) {
+        scsi_req_unref(s->current->req);
+        qemu_free(s->current);
+        s->current = NULL;
+    }
+    lsi_resume_script(s);
+}
+
+ /* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    int out;
+
+    if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
+        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
+        if (lsi_queue_req(s, req, len)) {
+            return;
+        }
+    }
+
+    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+
+    /* host adapter (re)connected */
+    DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
+    s->current->dma_len = len;
+    s->command_complete = 1;
+    if (s->waiting) {
+        if (s->waiting == 1 || s->dbc == 0) {
+            lsi_resume_script(s);
+        } else {
+            lsi_do_dma(s, out);
+        }
+    }
+}
+
+static void lsi_do_command(LSIState *s)
+{
+    SCSIDevice *dev;
+    uint8_t buf[16];
+    uint32_t id;
+    int n;
+
+    DPRINTF("Send command len=%d\n", s->dbc);
+    if (s->dbc > 16)
+        s->dbc = 16;
+    cpu_physical_memory_read(s->dnad, buf, s->dbc);
+    s->sfbr = buf[0];
+    s->command_complete = 0;
+
+    id = (s->select_tag >> 8) & 0xf;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
+    assert(s->current == NULL);
+    s->current = qemu_mallocz(sizeof(lsi_request));
+    s->current->tag = s->select_tag;
+    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun,
+                                   s->current);
+
+    n = scsi_req_enqueue(s->current->req, buf);
+    if (n) {
+        if (n > 0) {
+            lsi_set_phase(s, PHASE_DI);
+        } else if (n < 0) {
+            lsi_set_phase(s, PHASE_DO);
+        }
+        scsi_req_continue(s->current->req);
+    }
+    if (!s->command_complete) {
+        if (n) {
+            /* Command did not complete immediately so disconnect.  */
+            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
+            lsi_add_msg_byte(s, 4); /* DISCONNECT */
+            /* wait data */
+            lsi_set_phase(s, PHASE_MI);
+            s->msg_action = 1;
+            lsi_queue_command(s);
+        } else {
+            /* wait command complete */
+            lsi_set_phase(s, PHASE_DI);
+        }
+    }
+}
+
+static void lsi_do_status(LSIState *s)
+{
+    uint8_t status;
+    DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
+    if (s->dbc != 1)
+        BADF("Bad Status move\n");
+    s->dbc = 1;
+    status = s->status;
+    s->sfbr = status;
+    cpu_physical_memory_write(s->dnad, &status, 1);
+    lsi_set_phase(s, PHASE_MI);
+    s->msg_action = 1;
+    lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
+}
+
+static void lsi_do_msgin(LSIState *s)
+{
+    int len;
+    DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
+    s->sfbr = s->msg[0];
+    len = s->msg_len;
+    if (len > s->dbc)
+        len = s->dbc;
+    cpu_physical_memory_write(s->dnad, s->msg, len);
+    /* Linux drivers rely on the last byte being in the SIDL.  */
+    s->sidl = s->msg[len - 1];
+    s->msg_len -= len;
+    if (s->msg_len) {
+        memmove(s->msg, s->msg + len, s->msg_len);
+    } else {
+        /* ??? Check if ATN (not yet implemented) is asserted and maybe
+           switch to PHASE_MO.  */
+        switch (s->msg_action) {
+        case 0:
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        case 1:
+            lsi_disconnect(s);
+            break;
+        case 2:
+            lsi_set_phase(s, PHASE_DO);
+            break;
+        case 3:
+            lsi_set_phase(s, PHASE_DI);
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+/* Read the next byte during a MSGOUT phase.  */
+static uint8_t lsi_get_msgbyte(LSIState *s)
+{
+    uint8_t data;
+    cpu_physical_memory_read(s->dnad, &data, 1);
+    s->dnad++;
+    s->dbc--;
+    return data;
+}
+
+/* Skip the next n bytes during a MSGOUT phase. */
+static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
+{
+    s->dnad += n;
+    s->dbc  -= n;
+}
+
+static void lsi_do_msgout(LSIState *s)
+{
+    uint8_t msg;
+    int len;
+    uint32_t current_tag;
+    lsi_request *current_req, *p, *p_next;
+    int id;
+
+    if (s->current) {
+        current_tag = s->current->tag;
+        current_req = s->current;
+    } else {
+        current_tag = s->select_tag;
+        current_req = lsi_find_by_tag(s, current_tag);
+    }
+    id = (current_tag >> 8) & 0xf;
+
+    DPRINTF("MSG out len=%d\n", s->dbc);
+    while (s->dbc) {
+        msg = lsi_get_msgbyte(s);
+        s->sfbr = msg;
+
+        switch (msg) {
+        case 0x04:
+            DPRINTF("MSG: Disconnect\n");
+            lsi_disconnect(s);
+            break;
+        case 0x08:
+            DPRINTF("MSG: No Operation\n");
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        case 0x01:
+            len = lsi_get_msgbyte(s);
+            msg = lsi_get_msgbyte(s);
+            (void)len; /* avoid a warning about unused variable*/
+            DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
+            switch (msg) {
+            case 1:
+                DPRINTF("SDTR (ignored)\n");
+                lsi_skip_msgbytes(s, 2);
+                break;
+            case 3:
+                DPRINTF("WDTR (ignored)\n");
+                lsi_skip_msgbytes(s, 1);
+                break;
+            default:
+                goto bad;
+            }
+            break;
+        case 0x20: /* SIMPLE queue */
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
+            break;
+        case 0x21: /* HEAD of queue */
+            BADF("HEAD queue not implemented\n");
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            break;
+        case 0x22: /* ORDERED queue */
+            BADF("ORDERED queue not implemented\n");
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            break;
+        case 0x0d:
+            /* The ABORT TAG message clears the current I/O process only. */
+            DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
+            if (current_req) {
+                scsi_req_cancel(current_req->req);
+            }
+            lsi_disconnect(s);
+            break;
+        case 0x06:
+        case 0x0e:
+        case 0x0c:
+            /* The ABORT message clears all I/O processes for the selecting
+               initiator on the specified logical unit of the target. */
+            if (msg == 0x06) {
+                DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
+            }
+            /* The CLEAR QUEUE message clears all I/O processes for all
+               initiators on the specified logical unit of the target. */
+            if (msg == 0x0e) {
+                DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
+            }
+            /* The BUS DEVICE RESET message clears all I/O processes for all
+               initiators on all logical units of the target. */
+            if (msg == 0x0c) {
+                DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
+            }
+
+            /* clear the current I/O process */
+            if (s->current) {
+                scsi_req_cancel(s->current->req);
+            }
+
+            /* As the current implemented devices scsi_disk and scsi_generic
+               only support one LUN, we don't need to keep track of LUNs.
+               Clearing I/O processes for other initiators could be possible
+               for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
+               device, but this is currently not implemented (and seems not
+               to be really necessary). So let's simply clear all queued
+               commands for the current device: */
+            id = current_tag & 0x0000ff00;
+            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
+                if ((p->tag & 0x0000ff00) == id) {
+                    scsi_req_cancel(p->req);
+                }
+            }
+
+            lsi_disconnect(s);
+            break;
+        default:
+            if ((msg & 0x80) == 0) {
+                goto bad;
+            }
+            s->current_lun = msg & 7;
+            DPRINTF("Select LUN %d\n", s->current_lun);
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        }
+    }
+    return;
+bad:
+    BADF("Unimplemented message 0x%02x\n", msg);
+    lsi_set_phase(s, PHASE_MI);
+    lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
+    s->msg_action = 0;
+}
+
+/* Sign extend a 24-bit value.  */
+static inline int32_t sxt24(int32_t n)
+{
+    return (n << 8) >> 8;
+}
+
+#define LSI_BUF_SIZE 4096
+static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
+{
+    int n;
+    uint8_t buf[LSI_BUF_SIZE];
+
+    DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
+    while (count) {
+        n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
+        cpu_physical_memory_read(src, buf, n);
+        cpu_physical_memory_write(dest, buf, n);
+        src += n;
+        dest += n;
+        count -= n;
+    }
+}
+
+static void lsi_wait_reselect(LSIState *s)
+{
+    lsi_request *p;
+
+    DPRINTF("Wait Reselect\n");
+
+    QTAILQ_FOREACH(p, &s->queue, next) {
+        if (p->pending) {
+            lsi_reselect(s, p);
+            break;
+        }
+    }
+    if (s->current == NULL) {
+        s->waiting = 1;
+    }
+}
+
+static void lsi_execute_script(LSIState *s)
+{
+    uint32_t insn;
+    uint32_t addr, addr_high;
+    int opcode;
+    int insn_processed = 0;
+
+    s->istat1 |= LSI_ISTAT1_SRUN;
+again:
+    insn_processed++;
+    insn = read_dword(s, s->dsp);
+    if (!insn) {
+        /* If we receive an empty opcode increment the DSP by 4 bytes
+           instead of 8 and execute the next opcode at that location */
+        s->dsp += 4;
+        goto again;
+    }
+    addr = read_dword(s, s->dsp + 4);
+    addr_high = 0;
+    DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
+    s->dsps = addr;
+    s->dcmd = insn >> 24;
+    s->dsp += 8;
+    switch (insn >> 30) {
+    case 0: /* Block move.  */
+        if (s->sist1 & LSI_SIST1_STO) {
+            DPRINTF("Delayed select timeout\n");
+            lsi_stop_script(s);
+            break;
+        }
+        s->dbc = insn & 0xffffff;
+        s->rbc = s->dbc;
+        /* ??? Set ESA.  */
+        s->ia = s->dsp - 8;
+        if (insn & (1 << 29)) {
+            /* Indirect addressing.  */
+            addr = read_dword(s, addr);
+        } else if (insn & (1 << 28)) {
+            uint32_t buf[2];
+            int32_t offset;
+            /* Table indirect addressing.  */
+
+            /* 32-bit Table indirect */
+            offset = sxt24(addr);
+            cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
+            /* byte count is stored in bits 0:23 only */
+            s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
+            s->rbc = s->dbc;
+            addr = cpu_to_le32(buf[1]);
+
+            /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
+             * table, bits [31:24] */
+            if (lsi_dma_40bit(s))
+                addr_high = cpu_to_le32(buf[0]) >> 24;
+            else if (lsi_dma_ti64bit(s)) {
+                int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
+                switch (selector) {
+                case 0 ... 0x0f:
+                    /* offset index into scratch registers since
+                     * TI64 mode can use registers C to R */
+                    addr_high = s->scratch[2 + selector];
+                    break;
+                case 0x10:
+                    addr_high = s->mmrs;
+                    break;
+                case 0x11:
+                    addr_high = s->mmws;
+                    break;
+                case 0x12:
+                    addr_high = s->sfs;
+                    break;
+                case 0x13:
+                    addr_high = s->drs;
+                    break;
+                case 0x14:
+                    addr_high = s->sbms;
+                    break;
+                case 0x15:
+                    addr_high = s->dbms;
+                    break;
+                default:
+                    BADF("Illegal selector specified (0x%x > 0x15)"
+                         " for 64-bit DMA block move", selector);
+                    break;
+                }
+            }
+        } else if (lsi_dma_64bit(s)) {
+            /* fetch a 3rd dword if 64-bit direct move is enabled and
+               only if we're not doing table indirect or indirect addressing */
+            s->dbms = read_dword(s, s->dsp);
+            s->dsp += 4;
+            s->ia = s->dsp - 12;
+        }
+        if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
+            DPRINTF("Wrong phase got %d expected %d\n",
+                    s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
+            lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+            break;
+        }
+        s->dnad = addr;
+        s->dnad64 = addr_high;
+        switch (s->sstat1 & 0x7) {
+        case PHASE_DO:
+            s->waiting = 2;
+            lsi_do_dma(s, 1);
+            if (s->waiting)
+                s->waiting = 3;
+            break;
+        case PHASE_DI:
+            s->waiting = 2;
+            lsi_do_dma(s, 0);
+            if (s->waiting)
+                s->waiting = 3;
+            break;
+        case PHASE_CMD:
+            lsi_do_command(s);
+            break;
+        case PHASE_ST:
+            lsi_do_status(s);
+            break;
+        case PHASE_MO:
+            lsi_do_msgout(s);
+            break;
+        case PHASE_MI:
+            lsi_do_msgin(s);
+            break;
+        default:
+            BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
+            exit(1);
+        }
+        s->dfifo = s->dbc & 0xff;
+        s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
+        s->sbc = s->dbc;
+        s->rbc -= s->dbc;
+        s->ua = addr + s->dbc;
+        break;
+
+    case 1: /* IO or Read/Write instruction.  */
+        opcode = (insn >> 27) & 7;
+        if (opcode < 5) {
+            uint32_t id;
+
+            if (insn & (1 << 25)) {
+                id = read_dword(s, s->dsa + sxt24(insn));
+            } else {
+                id = insn;
+            }
+            id = (id >> 16) & 0xf;
+            if (insn & (1 << 26)) {
+                addr = s->dsp + sxt24(addr);
+            }
+            s->dnad = addr;
+            switch (opcode) {
+            case 0: /* Select */
+                s->sdid = id;
+                if (s->scntl1 & LSI_SCNTL1_CON) {
+                    DPRINTF("Already reselected, jumping to alternative address\n");
+                    s->dsp = s->dnad;
+                    break;
+                }
+                s->sstat0 |= LSI_SSTAT0_WOA;
+                s->scntl1 &= ~LSI_SCNTL1_IARB;
+                if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
+                    lsi_bad_selection(s, id);
+                    break;
+                }
+                DPRINTF("Selected target %d%s\n",
+                        id, insn & (1 << 3) ? " ATN" : "");
+                /* ??? Linux drivers compain when this is set.  Maybe
+                   it only applies in low-level mode (unimplemented).
+                lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
+                s->select_tag = id << 8;
+                s->scntl1 |= LSI_SCNTL1_CON;
+                if (insn & (1 << 3)) {
+                    s->socl |= LSI_SOCL_ATN;
+                }
+                lsi_set_phase(s, PHASE_MO);
+                break;
+            case 1: /* Disconnect */
+                DPRINTF("Wait Disconnect\n");
+                s->scntl1 &= ~LSI_SCNTL1_CON;
+                break;
+            case 2: /* Wait Reselect */
+                if (!lsi_irq_on_rsl(s)) {
+                    lsi_wait_reselect(s);
+                }
+                break;
+            case 3: /* Set */
+                DPRINTF("Set%s%s%s%s\n",
+                        insn & (1 << 3) ? " ATN" : "",
+                        insn & (1 << 6) ? " ACK" : "",
+                        insn & (1 << 9) ? " TM" : "",
+                        insn & (1 << 10) ? " CC" : "");
+                if (insn & (1 << 3)) {
+                    s->socl |= LSI_SOCL_ATN;
+                    lsi_set_phase(s, PHASE_MO);
+                }
+                if (insn & (1 << 9)) {
+                    BADF("Target mode not implemented\n");
+                    exit(1);
+                }
+                if (insn & (1 << 10))
+                    s->carry = 1;
+                break;
+            case 4: /* Clear */
+                DPRINTF("Clear%s%s%s%s\n",
+                        insn & (1 << 3) ? " ATN" : "",
+                        insn & (1 << 6) ? " ACK" : "",
+                        insn & (1 << 9) ? " TM" : "",
+                        insn & (1 << 10) ? " CC" : "");
+                if (insn & (1 << 3)) {
+                    s->socl &= ~LSI_SOCL_ATN;
+                }
+                if (insn & (1 << 10))
+                    s->carry = 0;
+                break;
+            }
+        } else {
+            uint8_t op0;
+            uint8_t op1;
+            uint8_t data8;
+            int reg;
+            int operator;
+#ifdef DEBUG_LSI
+            static const char *opcode_names[3] =
+                {"Write", "Read", "Read-Modify-Write"};
+            static const char *operator_names[8] =
+                {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
+#endif
+
+            reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
+            data8 = (insn >> 8) & 0xff;
+            opcode = (insn >> 27) & 7;
+            operator = (insn >> 24) & 7;
+            DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
+                    opcode_names[opcode - 5], reg,
+                    operator_names[operator], data8, s->sfbr,
+                    (insn & (1 << 23)) ? " SFBR" : "");
+            op0 = op1 = 0;
+            switch (opcode) {
+            case 5: /* From SFBR */
+                op0 = s->sfbr;
+                op1 = data8;
+                break;
+            case 6: /* To SFBR */
+                if (operator)
+                    op0 = lsi_reg_readb(s, reg);
+                op1 = data8;
+                break;
+            case 7: /* Read-modify-write */
+                if (operator)
+                    op0 = lsi_reg_readb(s, reg);
+                if (insn & (1 << 23)) {
+                    op1 = s->sfbr;
+                } else {
+                    op1 = data8;
+                }
+                break;
+            }
+
+            switch (operator) {
+            case 0: /* move */
+                op0 = op1;
+                break;
+            case 1: /* Shift left */
+                op1 = op0 >> 7;
+                op0 = (op0 << 1) | s->carry;
+                s->carry = op1;
+                break;
+            case 2: /* OR */
+                op0 |= op1;
+                break;
+            case 3: /* XOR */
+                op0 ^= op1;
+                break;
+            case 4: /* AND */
+                op0 &= op1;
+                break;
+            case 5: /* SHR */
+                op1 = op0 & 1;
+                op0 = (op0 >> 1) | (s->carry << 7);
+                s->carry = op1;
+                break;
+            case 6: /* ADD */
+                op0 += op1;
+                s->carry = op0 < op1;
+                break;
+            case 7: /* ADC */
+                op0 += op1 + s->carry;
+                if (s->carry)
+                    s->carry = op0 <= op1;
+                else
+                    s->carry = op0 < op1;
+                break;
+            }
+
+            switch (opcode) {
+            case 5: /* From SFBR */
+            case 7: /* Read-modify-write */
+                lsi_reg_writeb(s, reg, op0);
+                break;
+            case 6: /* To SFBR */
+                s->sfbr = op0;
+                break;
+            }
+        }
+        break;
+
+    case 2: /* Transfer Control.  */
+        {
+            int cond;
+            int jmp;
+
+            if ((insn & 0x002e0000) == 0) {
+                DPRINTF("NOP\n");
+                break;
+            }
+            if (s->sist1 & LSI_SIST1_STO) {
+                DPRINTF("Delayed select timeout\n");
+                lsi_stop_script(s);
+                break;
+            }
+            cond = jmp = (insn & (1 << 19)) != 0;
+            if (cond == jmp && (insn & (1 << 21))) {
+                DPRINTF("Compare carry %d\n", s->carry == jmp);
+                cond = s->carry != 0;
+            }
+            if (cond == jmp && (insn & (1 << 17))) {
+                DPRINTF("Compare phase %d %c= %d\n",
+                        (s->sstat1 & PHASE_MASK),
+                        jmp ? '=' : '!',
+                        ((insn >> 24) & 7));
+                cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
+            }
+            if (cond == jmp && (insn & (1 << 18))) {
+                uint8_t mask;
+
+                mask = (~insn >> 8) & 0xff;
+                DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
+                        s->sfbr, mask, jmp ? '=' : '!', insn & mask);
+                cond = (s->sfbr & mask) == (insn & mask);
+            }
+            if (cond == jmp) {
+                if (insn & (1 << 23)) {
+                    /* Relative address.  */
+                    addr = s->dsp + sxt24(addr);
+                }
+                switch ((insn >> 27) & 7) {
+                case 0: /* Jump */
+                    DPRINTF("Jump to 0x%08x\n", addr);
+                    s->dsp = addr;
+                    break;
+                case 1: /* Call */
+                    DPRINTF("Call 0x%08x\n", addr);
+                    s->temp = s->dsp;
+                    s->dsp = addr;
+                    break;
+                case 2: /* Return */
+                    DPRINTF("Return to 0x%08x\n", s->temp);
+                    s->dsp = s->temp;
+                    break;
+                case 3: /* Interrupt */
+                    DPRINTF("Interrupt 0x%08x\n", s->dsps);
+                    if ((insn & (1 << 20)) != 0) {
+                        s->istat0 |= LSI_ISTAT0_INTF;
+                        lsi_update_irq(s);
+                    } else {
+                        lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
+                    }
+                    break;
+                default:
+                    DPRINTF("Illegal transfer control\n");
+                    lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
+                    break;
+                }
+            } else {
+                DPRINTF("Control condition failed\n");
+            }
+        }
+        break;
+
+    case 3:
+        if ((insn & (1 << 29)) == 0) {
+            /* Memory move.  */
+            uint32_t dest;
+            /* ??? The docs imply the destination address is loaded into
+               the TEMP register.  However the Linux drivers rely on
+               the value being presrved.  */
+            dest = read_dword(s, s->dsp);
+            s->dsp += 4;
+            lsi_memcpy(s, dest, addr, insn & 0xffffff);
+        } else {
+            uint8_t data[7];
+            int reg;
+            int n;
+            int i;
+
+            if (insn & (1 << 28)) {
+                addr = s->dsa + sxt24(addr);
+            }
+            n = (insn & 7);
+            reg = (insn >> 16) & 0xff;
+            if (insn & (1 << 24)) {
+                cpu_physical_memory_read(addr, data, n);
+                DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
+                        addr, *(int *)data);
+                for (i = 0; i < n; i++) {
+                    lsi_reg_writeb(s, reg + i, data[i]);
+                }
+            } else {
+                DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+                for (i = 0; i < n; i++) {
+                    data[i] = lsi_reg_readb(s, reg + i);
+                }
+                cpu_physical_memory_write(addr, data, n);
+            }
+        }
+    }
+    if (insn_processed > 10000 && !s->waiting) {
+        /* Some windows drivers make the device spin waiting for a memory
+           location to change.  If we have been executed a lot of code then
+           assume this is the case and force an unexpected device disconnect.
+           This is apparently sufficient to beat the drivers into submission.
+         */
+        if (!(s->sien0 & LSI_SIST0_UDC))
+            fprintf(stderr, "inf. loop with UDC masked\n");
+        lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
+        lsi_disconnect(s);
+    } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
+        if (s->dcntl & LSI_DCNTL_SSM) {
+            lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
+        } else {
+            goto again;
+        }
+    }
+    DPRINTF("SCRIPTS execution stopped\n");
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+    uint8_t tmp;
+#define CASE_GET_REG24(name, addr) \
+    case addr: return s->name & 0xff; \
+    case addr + 1: return (s->name >> 8) & 0xff; \
+    case addr + 2: return (s->name >> 16) & 0xff;
+
+#define CASE_GET_REG32(name, addr) \
+    case addr: return s->name & 0xff; \
+    case addr + 1: return (s->name >> 8) & 0xff; \
+    case addr + 2: return (s->name >> 16) & 0xff; \
+    case addr + 3: return (s->name >> 24) & 0xff;
+
+#ifdef DEBUG_LSI_REG
+    DPRINTF("Read reg %x\n", offset);
+#endif
+    switch (offset) {
+    case 0x00: /* SCNTL0 */
+        return s->scntl0;
+    case 0x01: /* SCNTL1 */
+        return s->scntl1;
+    case 0x02: /* SCNTL2 */
+        return s->scntl2;
+    case 0x03: /* SCNTL3 */
+        return s->scntl3;
+    case 0x04: /* SCID */
+        return s->scid;
+    case 0x05: /* SXFER */
+        return s->sxfer;
+    case 0x06: /* SDID */
+        return s->sdid;
+    case 0x07: /* GPREG0 */
+        return 0x7f;
+    case 0x08: /* Revision ID */
+        return 0x00;
+    case 0xa: /* SSID */
+        return s->ssid;
+    case 0xb: /* SBCL */
+        /* ??? This is not correct. However it's (hopefully) only
+           used for diagnostics, so should be ok.  */
+        return 0;
+    case 0xc: /* DSTAT */
+        tmp = s->dstat | 0x80;
+        if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
+            s->dstat = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x0d: /* SSTAT0 */
+        return s->sstat0;
+    case 0x0e: /* SSTAT1 */
+        return s->sstat1;
+    case 0x0f: /* SSTAT2 */
+        return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
+    CASE_GET_REG32(dsa, 0x10)
+    case 0x14: /* ISTAT0 */
+        return s->istat0;
+    case 0x15: /* ISTAT1 */
+        return s->istat1;
+    case 0x16: /* MBOX0 */
+        return s->mbox0;
+    case 0x17: /* MBOX1 */
+        return s->mbox1;
+    case 0x18: /* CTEST0 */
+        return 0xff;
+    case 0x19: /* CTEST1 */
+        return 0;
+    case 0x1a: /* CTEST2 */
+        tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
+        if (s->istat0 & LSI_ISTAT0_SIGP) {
+            s->istat0 &= ~LSI_ISTAT0_SIGP;
+            tmp |= LSI_CTEST2_SIGP;
+        }
+        return tmp;
+    case 0x1b: /* CTEST3 */
+        return s->ctest3;
+    CASE_GET_REG32(temp, 0x1c)
+    case 0x20: /* DFIFO */
+        return 0;
+    case 0x21: /* CTEST4 */
+        return s->ctest4;
+    case 0x22: /* CTEST5 */
+        return s->ctest5;
+    case 0x23: /* CTEST6 */
+         return 0;
+    CASE_GET_REG24(dbc, 0x24)
+    case 0x27: /* DCMD */
+        return s->dcmd;
+    CASE_GET_REG32(dnad, 0x28)
+    CASE_GET_REG32(dsp, 0x2c)
+    CASE_GET_REG32(dsps, 0x30)
+    CASE_GET_REG32(scratch[0], 0x34)
+    case 0x38: /* DMODE */
+        return s->dmode;
+    case 0x39: /* DIEN */
+        return s->dien;
+    case 0x3a: /* SBR */
+        return s->sbr;
+    case 0x3b: /* DCNTL */
+        return s->dcntl;
+    case 0x40: /* SIEN0 */
+        return s->sien0;
+    case 0x41: /* SIEN1 */
+        return s->sien1;
+    case 0x42: /* SIST0 */
+        tmp = s->sist0;
+        s->sist0 = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x43: /* SIST1 */
+        tmp = s->sist1;
+        s->sist1 = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x46: /* MACNTL */
+        return 0x0f;
+    case 0x47: /* GPCNTL0 */
+        return 0x0f;
+    case 0x48: /* STIME0 */
+        return s->stime0;
+    case 0x4a: /* RESPID0 */
+        return s->respid0;
+    case 0x4b: /* RESPID1 */
+        return s->respid1;
+    case 0x4d: /* STEST1 */
+        return s->stest1;
+    case 0x4e: /* STEST2 */
+        return s->stest2;
+    case 0x4f: /* STEST3 */
+        return s->stest3;
+    case 0x50: /* SIDL */
+        /* This is needed by the linux drivers.  We currently only update it
+           during the MSG IN phase.  */
+        return s->sidl;
+    case 0x52: /* STEST4 */
+        return 0xe0;
+    case 0x56: /* CCNTL0 */
+        return s->ccntl0;
+    case 0x57: /* CCNTL1 */
+        return s->ccntl1;
+    case 0x58: /* SBDL */
+        /* Some drivers peek at the data bus during the MSG IN phase.  */
+        if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
+            return s->msg[0];
+        return 0;
+    case 0x59: /* SBDL high */
+        return 0;
+    CASE_GET_REG32(mmrs, 0xa0)
+    CASE_GET_REG32(mmws, 0xa4)
+    CASE_GET_REG32(sfs, 0xa8)
+    CASE_GET_REG32(drs, 0xac)
+    CASE_GET_REG32(sbms, 0xb0)
+    CASE_GET_REG32(dbms, 0xb4)
+    CASE_GET_REG32(dnad64, 0xb8)
+    CASE_GET_REG32(pmjad1, 0xc0)
+    CASE_GET_REG32(pmjad2, 0xc4)
+    CASE_GET_REG32(rbc, 0xc8)
+    CASE_GET_REG32(ua, 0xcc)
+    CASE_GET_REG32(ia, 0xd4)
+    CASE_GET_REG32(sbc, 0xd8)
+    CASE_GET_REG32(csbc, 0xdc)
+    }
+    if (offset >= 0x5c && offset < 0xa0) {
+        int n;
+        int shift;
+        n = (offset - 0x58) >> 2;
+        shift = (offset & 3) * 8;
+        return (s->scratch[n] >> shift) & 0xff;
+    }
+    BADF("readb 0x%x\n", offset);
+    exit(1);
+#undef CASE_GET_REG24
+#undef CASE_GET_REG32
+}
+
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
+{
+#define CASE_SET_REG24(name, addr) \
+    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
+    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
+    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
+
+#define CASE_SET_REG32(name, addr) \
+    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
+    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
+    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
+    case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
+
+#ifdef DEBUG_LSI_REG
+    DPRINTF("Write reg %x = %02x\n", offset, val);
+#endif
+    switch (offset) {
+    case 0x00: /* SCNTL0 */
+        s->scntl0 = val;
+        if (val & LSI_SCNTL0_START) {
+            BADF("Start sequence not implemented\n");
+        }
+        break;
+    case 0x01: /* SCNTL1 */
+        s->scntl1 = val & ~LSI_SCNTL1_SST;
+        if (val & LSI_SCNTL1_IARB) {
+            BADF("Immediate Arbritration not implemented\n");
+        }
+        if (val & LSI_SCNTL1_RST) {
+            if (!(s->sstat0 & LSI_SSTAT0_RST)) {
+                DeviceState *dev;
+                int id;
+
+                for (id = 0; id < s->bus.ndev; id++) {
+                    if (s->bus.devs[id]) {
+                        dev = &s->bus.devs[id]->qdev;
+                        dev->info->reset(dev);
+                    }
+                }
+                s->sstat0 |= LSI_SSTAT0_RST;
+                lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
+            }
+        } else {
+            s->sstat0 &= ~LSI_SSTAT0_RST;
+        }
+        break;
+    case 0x02: /* SCNTL2 */
+        val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
+        s->scntl2 = val;
+        break;
+    case 0x03: /* SCNTL3 */
+        s->scntl3 = val;
+        break;
+    case 0x04: /* SCID */
+        s->scid = val;
+        break;
+    case 0x05: /* SXFER */
+        s->sxfer = val;
+        break;
+    case 0x06: /* SDID */
+        if ((val & 0xf) != (s->ssid & 0xf))
+            BADF("Destination ID does not match SSID\n");
+        s->sdid = val & 0xf;
+        break;
+    case 0x07: /* GPREG0 */
+        break;
+    case 0x08: /* SFBR */
+        /* The CPU is not allowed to write to this register.  However the
+           SCRIPTS register move instructions are.  */
+        s->sfbr = val;
+        break;
+    case 0x0a: case 0x0b:
+        /* Openserver writes to these readonly registers on startup */
+	return;
+    case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+        /* Linux writes to these readonly registers on startup.  */
+        return;
+    CASE_SET_REG32(dsa, 0x10)
+    case 0x14: /* ISTAT0 */
+        s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
+        if (val & LSI_ISTAT0_ABRT) {
+            lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
+        }
+        if (val & LSI_ISTAT0_INTF) {
+            s->istat0 &= ~LSI_ISTAT0_INTF;
+            lsi_update_irq(s);
+        }
+        if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
+            DPRINTF("Woken by SIGP\n");
+            s->waiting = 0;
+            s->dsp = s->dnad;
+            lsi_execute_script(s);
+        }
+        if (val & LSI_ISTAT0_SRST) {
+            lsi_soft_reset(s);
+        }
+        break;
+    case 0x16: /* MBOX0 */
+        s->mbox0 = val;
+        break;
+    case 0x17: /* MBOX1 */
+        s->mbox1 = val;
+        break;
+    case 0x1a: /* CTEST2 */
+	s->ctest2 = val & LSI_CTEST2_PCICIE;
+	break;
+    case 0x1b: /* CTEST3 */
+        s->ctest3 = val & 0x0f;
+        break;
+    CASE_SET_REG32(temp, 0x1c)
+    case 0x21: /* CTEST4 */
+        if (val & 7) {
+           BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
+        }
+        s->ctest4 = val;
+        break;
+    case 0x22: /* CTEST5 */
+        if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
+            BADF("CTEST5 DMA increment not implemented\n");
+        }
+        s->ctest5 = val;
+        break;
+    CASE_SET_REG24(dbc, 0x24)
+    CASE_SET_REG32(dnad, 0x28)
+    case 0x2c: /* DSP[0:7] */
+        s->dsp &= 0xffffff00;
+        s->dsp |= val;
+        break;
+    case 0x2d: /* DSP[8:15] */
+        s->dsp &= 0xffff00ff;
+        s->dsp |= val << 8;
+        break;
+    case 0x2e: /* DSP[16:23] */
+        s->dsp &= 0xff00ffff;
+        s->dsp |= val << 16;
+        break;
+    case 0x2f: /* DSP[24:31] */
+        s->dsp &= 0x00ffffff;
+        s->dsp |= val << 24;
+        if ((s->dmode & LSI_DMODE_MAN) == 0
+            && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+            lsi_execute_script(s);
+        break;
+    CASE_SET_REG32(dsps, 0x30)
+    CASE_SET_REG32(scratch[0], 0x34)
+    case 0x38: /* DMODE */
+        if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
+            BADF("IO mappings not implemented\n");
+        }
+        s->dmode = val;
+        break;
+    case 0x39: /* DIEN */
+        s->dien = val;
+        lsi_update_irq(s);
+        break;
+    case 0x3a: /* SBR */
+        s->sbr = val;
+        break;
+    case 0x3b: /* DCNTL */
+        s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+        if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+            lsi_execute_script(s);
+        break;
+    case 0x40: /* SIEN0 */
+        s->sien0 = val;
+        lsi_update_irq(s);
+        break;
+    case 0x41: /* SIEN1 */
+        s->sien1 = val;
+        lsi_update_irq(s);
+        break;
+    case 0x47: /* GPCNTL0 */
+        break;
+    case 0x48: /* STIME0 */
+        s->stime0 = val;
+        break;
+    case 0x49: /* STIME1 */
+        if (val & 0xf) {
+            DPRINTF("General purpose timer not implemented\n");
+            /* ??? Raising the interrupt immediately seems to be sufficient
+               to keep the FreeBSD driver happy.  */
+            lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
+        }
+        break;
+    case 0x4a: /* RESPID0 */
+        s->respid0 = val;
+        break;
+    case 0x4b: /* RESPID1 */
+        s->respid1 = val;
+        break;
+    case 0x4d: /* STEST1 */
+        s->stest1 = val;
+        break;
+    case 0x4e: /* STEST2 */
+        if (val & 1) {
+            BADF("Low level mode not implemented\n");
+        }
+        s->stest2 = val;
+        break;
+    case 0x4f: /* STEST3 */
+        if (val & 0x41) {
+            BADF("SCSI FIFO test mode not implemented\n");
+        }
+        s->stest3 = val;
+        break;
+    case 0x56: /* CCNTL0 */
+        s->ccntl0 = val;
+        break;
+    case 0x57: /* CCNTL1 */
+        s->ccntl1 = val;
+        break;
+    CASE_SET_REG32(mmrs, 0xa0)
+    CASE_SET_REG32(mmws, 0xa4)
+    CASE_SET_REG32(sfs, 0xa8)
+    CASE_SET_REG32(drs, 0xac)
+    CASE_SET_REG32(sbms, 0xb0)
+    CASE_SET_REG32(dbms, 0xb4)
+    CASE_SET_REG32(dnad64, 0xb8)
+    CASE_SET_REG32(pmjad1, 0xc0)
+    CASE_SET_REG32(pmjad2, 0xc4)
+    CASE_SET_REG32(rbc, 0xc8)
+    CASE_SET_REG32(ua, 0xcc)
+    CASE_SET_REG32(ia, 0xd4)
+    CASE_SET_REG32(sbc, 0xd8)
+    CASE_SET_REG32(csbc, 0xdc)
+    default:
+        if (offset >= 0x5c && offset < 0xa0) {
+            int n;
+            int shift;
+            n = (offset - 0x58) >> 2;
+            shift = (offset & 3) * 8;
+            s->scratch[n] &= ~(0xff << shift);
+            s->scratch[n] |= (val & 0xff) << shift;
+        } else {
+            BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
+        }
+    }
+#undef CASE_SET_REG24
+#undef CASE_SET_REG32
+}
+
+static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+
+    lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+
+    addr &= 0xff;
+    lsi_reg_writeb(s, addr, val & 0xff);
+    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+}
+
+static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+
+    addr &= 0xff;
+    lsi_reg_writeb(s, addr, val & 0xff);
+    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
+    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
+}
+
+static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+
+    return lsi_reg_readb(s, addr & 0xff);
+}
+
+static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0xff;
+    val = lsi_reg_readb(s, addr);
+    val |= lsi_reg_readb(s, addr + 1) << 8;
+    return val;
+}
+
+static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+    addr &= 0xff;
+    val = lsi_reg_readb(s, addr);
+    val |= lsi_reg_readb(s, addr + 1) << 8;
+    val |= lsi_reg_readb(s, addr + 2) << 16;
+    val |= lsi_reg_readb(s, addr + 3) << 24;
+    return val;
+}
+
+static CPUReadMemoryFunc * const lsi_mmio_readfn[3] = {
+    lsi_mmio_readb,
+    lsi_mmio_readw,
+    lsi_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const lsi_mmio_writefn[3] = {
+    lsi_mmio_writeb,
+    lsi_mmio_writew,
+    lsi_mmio_writel,
+};
+
+static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+    uint32_t newval;
+    int shift;
+
+    addr &= 0x1fff;
+    newval = s->script_ram[addr >> 2];
+    shift = (addr & 3) * 8;
+    newval &= ~(0xff << shift);
+    newval |= val << shift;
+    s->script_ram[addr >> 2] = newval;
+}
+
+static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+    uint32_t newval;
+
+    addr &= 0x1fff;
+    newval = s->script_ram[addr >> 2];
+    if (addr & 2) {
+        newval = (newval & 0xffff) | (val << 16);
+    } else {
+        newval = (newval & 0xffff0000) | val;
+    }
+    s->script_ram[addr >> 2] = newval;
+}
+
+
+static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+
+    addr &= 0x1fff;
+    s->script_ram[addr >> 2] = val;
+}
+
+static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1fff;
+    val = s->script_ram[addr >> 2];
+    val >>= (addr & 3) * 8;
+    return val & 0xff;
+}
+
+static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1fff;
+    val = s->script_ram[addr >> 2];
+    if (addr & 2)
+        val >>= 16;
+    return val;
+}
+
+static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+    LSIState *s = opaque;
+
+    addr &= 0x1fff;
+    return s->script_ram[addr >> 2];
+}
+
+static CPUReadMemoryFunc * const lsi_ram_readfn[3] = {
+    lsi_ram_readb,
+    lsi_ram_readw,
+    lsi_ram_readl,
+};
+
+static CPUWriteMemoryFunc * const lsi_ram_writefn[3] = {
+    lsi_ram_writeb,
+    lsi_ram_writew,
+    lsi_ram_writel,
+};
+
+static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
+{
+    LSIState *s = opaque;
+    return lsi_reg_readb(s, addr & 0xff);
+}
+
+static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+    addr &= 0xff;
+    val = lsi_reg_readb(s, addr);
+    val |= lsi_reg_readb(s, addr + 1) << 8;
+    return val;
+}
+
+static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+    addr &= 0xff;
+    val = lsi_reg_readb(s, addr);
+    val |= lsi_reg_readb(s, addr + 1) << 8;
+    val |= lsi_reg_readb(s, addr + 2) << 16;
+    val |= lsi_reg_readb(s, addr + 3) << 24;
+    return val;
+}
+
+static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+    lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+    addr &= 0xff;
+    lsi_reg_writeb(s, addr, val & 0xff);
+    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+}
+
+static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    LSIState *s = opaque;
+    addr &= 0xff;
+    lsi_reg_writeb(s, addr, val & 0xff);
+    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
+    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
+}
+
+static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
+                           pcibus_t addr, pcibus_t size, int type)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
+
+    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
+
+    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
+    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
+    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
+    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
+    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
+    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
+}
+
+static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
+                            pcibus_t addr, pcibus_t size, int type)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
+
+    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
+    s->script_ram_base = addr;
+    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
+}
+
+static void lsi_scsi_reset(DeviceState *dev)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
+
+    lsi_soft_reset(s);
+}
+
+static void lsi_pre_save(void *opaque)
+{
+    LSIState *s = opaque;
+
+    if (s->current) {
+        assert(s->current->dma_buf == NULL);
+        assert(s->current->dma_len == 0);
+    }
+    assert(QTAILQ_EMPTY(&s->queue));
+}
+
+static const VMStateDescription vmstate_lsi_scsi = {
+    .name = "lsiscsi",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = lsi_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, LSIState),
+
+        VMSTATE_INT32(carry, LSIState),
+        VMSTATE_INT32(status, LSIState),
+        VMSTATE_INT32(msg_action, LSIState),
+        VMSTATE_INT32(msg_len, LSIState),
+        VMSTATE_BUFFER(msg, LSIState),
+        VMSTATE_INT32(waiting, LSIState),
+
+        VMSTATE_UINT32(dsa, LSIState),
+        VMSTATE_UINT32(temp, LSIState),
+        VMSTATE_UINT32(dnad, LSIState),
+        VMSTATE_UINT32(dbc, LSIState),
+        VMSTATE_UINT8(istat0, LSIState),
+        VMSTATE_UINT8(istat1, LSIState),
+        VMSTATE_UINT8(dcmd, LSIState),
+        VMSTATE_UINT8(dstat, LSIState),
+        VMSTATE_UINT8(dien, LSIState),
+        VMSTATE_UINT8(sist0, LSIState),
+        VMSTATE_UINT8(sist1, LSIState),
+        VMSTATE_UINT8(sien0, LSIState),
+        VMSTATE_UINT8(sien1, LSIState),
+        VMSTATE_UINT8(mbox0, LSIState),
+        VMSTATE_UINT8(mbox1, LSIState),
+        VMSTATE_UINT8(dfifo, LSIState),
+        VMSTATE_UINT8(ctest2, LSIState),
+        VMSTATE_UINT8(ctest3, LSIState),
+        VMSTATE_UINT8(ctest4, LSIState),
+        VMSTATE_UINT8(ctest5, LSIState),
+        VMSTATE_UINT8(ccntl0, LSIState),
+        VMSTATE_UINT8(ccntl1, LSIState),
+        VMSTATE_UINT32(dsp, LSIState),
+        VMSTATE_UINT32(dsps, LSIState),
+        VMSTATE_UINT8(dmode, LSIState),
+        VMSTATE_UINT8(dcntl, LSIState),
+        VMSTATE_UINT8(scntl0, LSIState),
+        VMSTATE_UINT8(scntl1, LSIState),
+        VMSTATE_UINT8(scntl2, LSIState),
+        VMSTATE_UINT8(scntl3, LSIState),
+        VMSTATE_UINT8(sstat0, LSIState),
+        VMSTATE_UINT8(sstat1, LSIState),
+        VMSTATE_UINT8(scid, LSIState),
+        VMSTATE_UINT8(sxfer, LSIState),
+        VMSTATE_UINT8(socl, LSIState),
+        VMSTATE_UINT8(sdid, LSIState),
+        VMSTATE_UINT8(ssid, LSIState),
+        VMSTATE_UINT8(sfbr, LSIState),
+        VMSTATE_UINT8(stest1, LSIState),
+        VMSTATE_UINT8(stest2, LSIState),
+        VMSTATE_UINT8(stest3, LSIState),
+        VMSTATE_UINT8(sidl, LSIState),
+        VMSTATE_UINT8(stime0, LSIState),
+        VMSTATE_UINT8(respid0, LSIState),
+        VMSTATE_UINT8(respid1, LSIState),
+        VMSTATE_UINT32(mmrs, LSIState),
+        VMSTATE_UINT32(mmws, LSIState),
+        VMSTATE_UINT32(sfs, LSIState),
+        VMSTATE_UINT32(drs, LSIState),
+        VMSTATE_UINT32(sbms, LSIState),
+        VMSTATE_UINT32(dbms, LSIState),
+        VMSTATE_UINT32(dnad64, LSIState),
+        VMSTATE_UINT32(pmjad1, LSIState),
+        VMSTATE_UINT32(pmjad2, LSIState),
+        VMSTATE_UINT32(rbc, LSIState),
+        VMSTATE_UINT32(ua, LSIState),
+        VMSTATE_UINT32(ia, LSIState),
+        VMSTATE_UINT32(sbc, LSIState),
+        VMSTATE_UINT32(csbc, LSIState),
+        VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
+        VMSTATE_UINT8(sbr, LSIState),
+
+        VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 2048 * sizeof(uint32_t)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int lsi_scsi_uninit(PCIDevice *d)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, d);
+
+    cpu_unregister_io_memory(s->mmio_io_addr);
+    cpu_unregister_io_memory(s->ram_io_addr);
+
+    return 0;
+}
+
+static const struct SCSIBusOps lsi_scsi_ops = {
+    .transfer_data = lsi_transfer_data,
+    .complete = lsi_command_complete,
+    .cancel = lsi_request_cancelled
+};
+
+static int lsi_scsi_init(PCIDevice *dev)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+
+    /* PCI latency timer = 255 */
+    pci_conf[PCI_LATENCY_TIMER] = 0xff;
+    /* TODO: RST# value should be 0 */
+    /* Interrupt pin 1 */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn,
+                                             lsi_mmio_writefn, s,
+                                             DEVICE_NATIVE_ENDIAN);
+    s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn,
+                                            lsi_ram_writefn, s,
+                                            DEVICE_NATIVE_ENDIAN);
+
+    pci_register_bar(&s->dev, 0, 256,
+                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
+    pci_register_bar_simple(&s->dev, 1, 0x400, 0, s->mmio_io_addr);
+    pci_register_bar(&s->dev, 2, 0x2000,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
+    QTAILQ_INIT(&s->queue);
+
+    scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
+    if (!dev->qdev.hotplugged) {
+        return scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+    return 0;
+}
+
+static PCIDeviceInfo lsi_info = {
+    .qdev.name  = "lsi53c895a",
+    .qdev.alias = "lsi",
+    .qdev.size  = sizeof(LSIState),
+    .qdev.reset = lsi_scsi_reset,
+    .qdev.vmsd  = &vmstate_lsi_scsi,
+    .init       = lsi_scsi_init,
+    .exit       = lsi_scsi_uninit,
+    .vendor_id  = PCI_VENDOR_ID_LSI_LOGIC,
+    .device_id  = PCI_DEVICE_ID_LSI_53C895A,
+    .class_id   = PCI_CLASS_STORAGE_SCSI,
+    .subsystem_id = 0x1000,
+};
+
+static void lsi53c895a_register_devices(void)
+{
+    pci_qdev_register(&lsi_info);
+}
+
+device_init(lsi53c895a_register_devices);
diff --git a/qemu-0.15.x/hw/m48t59.c b/qemu-0.15.x/hw/m48t59.c
new file mode 100644
index 0000000..537c0f7
--- /dev/null
+++ b/qemu-0.15.x/hw/m48t59.c
@@ -0,0 +1,752 @@
+/*
+ * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
+ *
+ * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "nvram.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "isa.h"
+
+//#define DEBUG_NVRAM
+
+#if defined(DEBUG_NVRAM)
+#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
+#else
+#define NVRAM_PRINTF(fmt, ...) do { } while (0)
+#endif
+
+/*
+ * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
+ * alarm and a watchdog timer and related control registers. In the
+ * PPC platform there is also a nvram lock function.
+ */
+
+/*
+ * Chipset docs:
+ * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
+ * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
+ * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
+ */
+
+struct M48t59State {
+    /* Model parameters */
+    uint32_t type; // 2 = m48t02, 8 = m48t08, 59 = m48t59
+    /* Hardware parameters */
+    qemu_irq IRQ;
+    uint32_t io_base;
+    uint32_t size;
+    /* RTC management */
+    time_t   time_offset;
+    time_t   stop_time;
+    /* Alarm & watchdog */
+    struct tm alarm;
+    struct QEMUTimer *alrm_timer;
+    struct QEMUTimer *wd_timer;
+    /* NVRAM storage */
+    uint8_t  lock;
+    uint16_t addr;
+    uint8_t *buffer;
+};
+
+typedef struct M48t59ISAState {
+    ISADevice busdev;
+    M48t59State state;
+} M48t59ISAState;
+
+typedef struct M48t59SysBusState {
+    SysBusDevice busdev;
+    M48t59State state;
+} M48t59SysBusState;
+
+/* Fake timer functions */
+
+/* Alarm management */
+static void alarm_cb (void *opaque)
+{
+    struct tm tm;
+    uint64_t next_time;
+    M48t59State *NVRAM = opaque;
+
+    qemu_set_irq(NVRAM->IRQ, 1);
+    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
+	(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
+	(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+	(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a month */
+        qemu_get_timedate(&tm, NVRAM->time_offset);
+        tm.tm_mon++;
+        if (tm.tm_mon == 13) {
+            tm.tm_mon = 1;
+            tm.tm_year++;
+        }
+        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
+	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a day */
+        next_time = 24 * 60 * 60;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once an hour */
+        next_time = 60 * 60;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
+	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a minute */
+        next_time = 60;
+    } else {
+        /* Repeat once a second */
+        next_time = 1;
+    }
+    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
+                    next_time * 1000);
+    qemu_set_irq(NVRAM->IRQ, 0);
+}
+
+static void set_alarm(M48t59State *NVRAM)
+{
+    int diff;
+    if (NVRAM->alrm_timer != NULL) {
+        qemu_del_timer(NVRAM->alrm_timer);
+        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
+        if (diff > 0)
+            qemu_mod_timer(NVRAM->alrm_timer, diff * 1000);
+    }
+}
+
+/* RTC management helpers */
+static inline void get_time(M48t59State *NVRAM, struct tm *tm)
+{
+    qemu_get_timedate(tm, NVRAM->time_offset);
+}
+
+static void set_time(M48t59State *NVRAM, struct tm *tm)
+{
+    NVRAM->time_offset = qemu_timedate_diff(tm);
+    set_alarm(NVRAM);
+}
+
+/* Watchdog management */
+static void watchdog_cb (void *opaque)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM->buffer[0x1FF0] |= 0x80;
+    if (NVRAM->buffer[0x1FF7] & 0x80) {
+	NVRAM->buffer[0x1FF7] = 0x00;
+	NVRAM->buffer[0x1FFC] &= ~0x40;
+        /* May it be a hw CPU Reset instead ? */
+        qemu_system_reset_request();
+    } else {
+	qemu_set_irq(NVRAM->IRQ, 1);
+	qemu_set_irq(NVRAM->IRQ, 0);
+    }
+}
+
+static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
+{
+    uint64_t interval; /* in 1/16 seconds */
+
+    NVRAM->buffer[0x1FF0] &= ~0x80;
+    if (NVRAM->wd_timer != NULL) {
+        qemu_del_timer(NVRAM->wd_timer);
+        if (value != 0) {
+            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
+            qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
+                           ((interval * 1000) >> 4));
+        }
+    }
+}
+
+/* Direct access to NVRAM */
+void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    M48t59State *NVRAM = opaque;
+    struct tm tm;
+    int tmp;
+
+    if (addr > 0x1FF8 && addr < 0x2000)
+	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
+
+    /* check for NVRAM access */
+    if ((NVRAM->type == 2 && addr < 0x7f8) ||
+        (NVRAM->type == 8 && addr < 0x1ff8) ||
+        (NVRAM->type == 59 && addr < 0x1ff0))
+        goto do_write;
+
+    /* TOD access */
+    switch (addr) {
+    case 0x1FF0:
+        /* flags register : read-only */
+        break;
+    case 0x1FF1:
+        /* unused */
+        break;
+    case 0x1FF2:
+        /* alarm seconds */
+        tmp = from_bcd(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            NVRAM->alarm.tm_sec = tmp;
+            NVRAM->buffer[0x1FF2] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF3:
+        /* alarm minutes */
+        tmp = from_bcd(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            NVRAM->alarm.tm_min = tmp;
+            NVRAM->buffer[0x1FF3] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF4:
+        /* alarm hours */
+        tmp = from_bcd(val & 0x3F);
+        if (tmp >= 0 && tmp <= 23) {
+            NVRAM->alarm.tm_hour = tmp;
+            NVRAM->buffer[0x1FF4] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF5:
+        /* alarm date */
+        tmp = from_bcd(val & 0x1F);
+        if (tmp != 0) {
+            NVRAM->alarm.tm_mday = tmp;
+            NVRAM->buffer[0x1FF5] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF6:
+        /* interrupts */
+        NVRAM->buffer[0x1FF6] = val;
+        break;
+    case 0x1FF7:
+        /* watchdog */
+        NVRAM->buffer[0x1FF7] = val;
+        set_up_watchdog(NVRAM, val);
+        break;
+    case 0x1FF8:
+    case 0x07F8:
+        /* control */
+       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
+        break;
+    case 0x1FF9:
+    case 0x07F9:
+        /* seconds (BCD) */
+	tmp = from_bcd(val & 0x7F);
+	if (tmp >= 0 && tmp <= 59) {
+	    get_time(NVRAM, &tm);
+	    tm.tm_sec = tmp;
+	    set_time(NVRAM, &tm);
+	}
+        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
+	    if (val & 0x80) {
+		NVRAM->stop_time = time(NULL);
+	    } else {
+		NVRAM->time_offset += NVRAM->stop_time - time(NULL);
+		NVRAM->stop_time = 0;
+	    }
+	}
+        NVRAM->buffer[addr] = val & 0x80;
+        break;
+    case 0x1FFA:
+    case 0x07FA:
+        /* minutes (BCD) */
+	tmp = from_bcd(val & 0x7F);
+	if (tmp >= 0 && tmp <= 59) {
+	    get_time(NVRAM, &tm);
+	    tm.tm_min = tmp;
+	    set_time(NVRAM, &tm);
+	}
+        break;
+    case 0x1FFB:
+    case 0x07FB:
+        /* hours (BCD) */
+	tmp = from_bcd(val & 0x3F);
+	if (tmp >= 0 && tmp <= 23) {
+	    get_time(NVRAM, &tm);
+	    tm.tm_hour = tmp;
+	    set_time(NVRAM, &tm);
+	}
+        break;
+    case 0x1FFC:
+    case 0x07FC:
+        /* day of the week / century */
+	tmp = from_bcd(val & 0x07);
+	get_time(NVRAM, &tm);
+	tm.tm_wday = tmp;
+	set_time(NVRAM, &tm);
+        NVRAM->buffer[addr] = val & 0x40;
+        break;
+    case 0x1FFD:
+    case 0x07FD:
+        /* date */
+	tmp = from_bcd(val & 0x1F);
+	if (tmp != 0) {
+	    get_time(NVRAM, &tm);
+	    tm.tm_mday = tmp;
+	    set_time(NVRAM, &tm);
+	}
+        break;
+    case 0x1FFE:
+    case 0x07FE:
+        /* month */
+	tmp = from_bcd(val & 0x1F);
+	if (tmp >= 1 && tmp <= 12) {
+	    get_time(NVRAM, &tm);
+	    tm.tm_mon = tmp - 1;
+	    set_time(NVRAM, &tm);
+	}
+        break;
+    case 0x1FFF:
+    case 0x07FF:
+        /* year */
+	tmp = from_bcd(val);
+	if (tmp >= 0 && tmp <= 99) {
+	    get_time(NVRAM, &tm);
+            if (NVRAM->type == 8)
+                tm.tm_year = from_bcd(val) + 68; // Base year is 1968
+            else
+                tm.tm_year = from_bcd(val);
+	    set_time(NVRAM, &tm);
+	}
+        break;
+    default:
+        /* Check lock registers state */
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
+            break;
+    do_write:
+        if (addr < NVRAM->size) {
+            NVRAM->buffer[addr] = val & 0xFF;
+	}
+        break;
+    }
+}
+
+uint32_t m48t59_read (void *opaque, uint32_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    struct tm tm;
+    uint32_t retval = 0xFF;
+
+    /* check for NVRAM access */
+    if ((NVRAM->type == 2 && addr < 0x078f) ||
+        (NVRAM->type == 8 && addr < 0x1ff8) ||
+        (NVRAM->type == 59 && addr < 0x1ff0))
+        goto do_read;
+
+    /* TOD access */
+    switch (addr) {
+    case 0x1FF0:
+        /* flags register */
+	goto do_read;
+    case 0x1FF1:
+        /* unused */
+	retval = 0;
+        break;
+    case 0x1FF2:
+        /* alarm seconds */
+	goto do_read;
+    case 0x1FF3:
+        /* alarm minutes */
+	goto do_read;
+    case 0x1FF4:
+        /* alarm hours */
+	goto do_read;
+    case 0x1FF5:
+        /* alarm date */
+	goto do_read;
+    case 0x1FF6:
+        /* interrupts */
+	goto do_read;
+    case 0x1FF7:
+	/* A read resets the watchdog */
+	set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
+	goto do_read;
+    case 0x1FF8:
+    case 0x07F8:
+        /* control */
+	goto do_read;
+    case 0x1FF9:
+    case 0x07F9:
+        /* seconds (BCD) */
+        get_time(NVRAM, &tm);
+        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
+        break;
+    case 0x1FFA:
+    case 0x07FA:
+        /* minutes (BCD) */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_min);
+        break;
+    case 0x1FFB:
+    case 0x07FB:
+        /* hours (BCD) */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_hour);
+        break;
+    case 0x1FFC:
+    case 0x07FC:
+        /* day of the week / century */
+        get_time(NVRAM, &tm);
+        retval = NVRAM->buffer[addr] | tm.tm_wday;
+        break;
+    case 0x1FFD:
+    case 0x07FD:
+        /* date */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_mday);
+        break;
+    case 0x1FFE:
+    case 0x07FE:
+        /* month */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_mon + 1);
+        break;
+    case 0x1FFF:
+    case 0x07FF:
+        /* year */
+        get_time(NVRAM, &tm);
+        if (NVRAM->type == 8)
+            retval = to_bcd(tm.tm_year - 68); // Base year is 1968
+        else
+            retval = to_bcd(tm.tm_year);
+        break;
+    default:
+        /* Check lock registers state */
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
+            break;
+    do_read:
+        if (addr < NVRAM->size) {
+            retval = NVRAM->buffer[addr];
+	}
+        break;
+    }
+    if (addr > 0x1FF9 && addr < 0x2000)
+       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
+
+    return retval;
+}
+
+void m48t59_set_addr (void *opaque, uint32_t addr)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM->addr = addr;
+}
+
+void m48t59_toggle_lock (void *opaque, int lock)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM->lock ^= 1 << lock;
+}
+
+/* IO access to NVRAM */
+static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    M48t59State *NVRAM = opaque;
+
+    addr -= NVRAM->io_base;
+    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
+    switch (addr) {
+    case 0:
+        NVRAM->addr &= ~0x00FF;
+        NVRAM->addr |= val;
+        break;
+    case 1:
+        NVRAM->addr &= ~0xFF00;
+        NVRAM->addr |= val << 8;
+        break;
+    case 3:
+        m48t59_write(NVRAM, val, NVRAM->addr);
+        NVRAM->addr = 0x0000;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    addr -= NVRAM->io_base;
+    switch (addr) {
+    case 3:
+        retval = m48t59_read(NVRAM, NVRAM->addr);
+        break;
+    default:
+        retval = -1;
+        break;
+    }
+    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
+
+    return retval;
+}
+
+static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, value & 0xff);
+}
+
+static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 1, value & 0xff);
+}
+
+static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
+    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
+    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 3, value & 0xff);
+}
+
+static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr);
+    return retval;
+}
+
+static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr) << 8;
+    retval |= m48t59_read(NVRAM, addr + 1);
+    return retval;
+}
+
+static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr) << 24;
+    retval |= m48t59_read(NVRAM, addr + 1) << 16;
+    retval |= m48t59_read(NVRAM, addr + 2) << 8;
+    retval |= m48t59_read(NVRAM, addr + 3);
+    return retval;
+}
+
+static CPUWriteMemoryFunc * const nvram_write[] = {
+    &nvram_writeb,
+    &nvram_writew,
+    &nvram_writel,
+};
+
+static CPUReadMemoryFunc * const nvram_read[] = {
+    &nvram_readb,
+    &nvram_readw,
+    &nvram_readl,
+};
+
+static const VMStateDescription vmstate_m48t59 = {
+    .name = "m48t59",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(lock, M48t59State),
+        VMSTATE_UINT16(addr, M48t59State),
+        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void m48t59_reset_common(M48t59State *NVRAM)
+{
+    NVRAM->addr = 0;
+    NVRAM->lock = 0;
+    if (NVRAM->alrm_timer != NULL)
+        qemu_del_timer(NVRAM->alrm_timer);
+
+    if (NVRAM->wd_timer != NULL)
+        qemu_del_timer(NVRAM->wd_timer);
+}
+
+static void m48t59_reset_isa(DeviceState *d)
+{
+    M48t59ISAState *isa = container_of(d, M48t59ISAState, busdev.qdev);
+    M48t59State *NVRAM = &isa->state;
+
+    m48t59_reset_common(NVRAM);
+}
+
+static void m48t59_reset_sysbus(DeviceState *d)
+{
+    M48t59SysBusState *sys = container_of(d, M48t59SysBusState, busdev.qdev);
+    M48t59State *NVRAM = &sys->state;
+
+    m48t59_reset_common(NVRAM);
+}
+
+/* Initialisation routine */
+M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
+                         uint32_t io_base, uint16_t size, int type)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    M48t59SysBusState *d;
+    M48t59State *state;
+
+    dev = qdev_create(NULL, "m48t59");
+    qdev_prop_set_uint32(dev, "type", type);
+    qdev_prop_set_uint32(dev, "size", size);
+    qdev_prop_set_uint32(dev, "io_base", io_base);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(M48t59SysBusState, s);
+    state = &d->state;
+    sysbus_connect_irq(s, 0, IRQ);
+    if (io_base != 0) {
+        register_ioport_read(io_base, 0x04, 1, NVRAM_readb, state);
+        register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, state);
+    }
+    if (mem_base != 0) {
+        sysbus_mmio_map(s, 0, mem_base);
+    }
+
+    return state;
+}
+
+M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
+{
+    M48t59ISAState *d;
+    ISADevice *dev;
+    M48t59State *s;
+
+    dev = isa_create("m48t59_isa");
+    qdev_prop_set_uint32(&dev->qdev, "type", type);
+    qdev_prop_set_uint32(&dev->qdev, "size", size);
+    qdev_prop_set_uint32(&dev->qdev, "io_base", io_base);
+    qdev_init_nofail(&dev->qdev);
+    d = DO_UPCAST(M48t59ISAState, busdev, dev);
+    s = &d->state;
+
+    if (io_base != 0) {
+        register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
+        register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+        isa_init_ioport_range(dev, io_base, 4);
+    }
+
+    return s;
+}
+
+static void m48t59_init_common(M48t59State *s)
+{
+    s->buffer = qemu_mallocz(s->size);
+    if (s->type == 59) {
+        s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
+        s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
+    }
+    qemu_get_timedate(&s->alarm, 0);
+
+    vmstate_register(NULL, -1, &vmstate_m48t59, s);
+}
+
+static int m48t59_init_isa1(ISADevice *dev)
+{
+    M48t59ISAState *d = DO_UPCAST(M48t59ISAState, busdev, dev);
+    M48t59State *s = &d->state;
+
+    isa_init_irq(dev, &s->IRQ, 8);
+    m48t59_init_common(s);
+
+    return 0;
+}
+
+static int m48t59_init1(SysBusDevice *dev)
+{
+    M48t59SysBusState *d = FROM_SYSBUS(M48t59SysBusState, dev);
+    M48t59State *s = &d->state;
+    int mem_index;
+
+    sysbus_init_irq(dev, &s->IRQ);
+
+    mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, s->size, mem_index);
+    m48t59_init_common(s);
+
+    return 0;
+}
+
+static ISADeviceInfo m48t59_isa_info = {
+    .init = m48t59_init_isa1,
+    .qdev.name = "m48t59_isa",
+    .qdev.size = sizeof(M48t59ISAState),
+    .qdev.reset = m48t59_reset_isa,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
+        DEFINE_PROP_UINT32("type",    M48t59ISAState, state.type,    -1),
+        DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base,  0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static SysBusDeviceInfo m48t59_info = {
+    .init = m48t59_init1,
+    .qdev.name  = "m48t59",
+    .qdev.size = sizeof(M48t59SysBusState),
+    .qdev.reset = m48t59_reset_sysbus,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
+        DEFINE_PROP_UINT32("type",    M48t59SysBusState, state.type,    -1),
+        DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void m48t59_register_devices(void)
+{
+    sysbus_register_withprop(&m48t59_info);
+    isa_qdev_register(&m48t59_isa_info);
+}
+
+device_init(m48t59_register_devices)
diff --git a/qemu-0.15.x/hw/mac_dbdma.c b/qemu-0.15.x/hw/mac_dbdma.c
new file mode 100644
index 0000000..ed4458e
--- /dev/null
+++ b/qemu-0.15.x/hw/mac_dbdma.c
@@ -0,0 +1,859 @@
+/*
+ * PowerMac descriptor-based DMA emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
+ *
+ *   Definitions for using the Apple Descriptor-Based DMA controller
+ *   in Power Macintosh computers.
+ *
+ *   Copyright (C) 1996 Paul Mackerras.
+ *
+ * some parts from mol 0.9.71
+ *
+ *   Descriptor based DMA emulation
+ *
+ *   Copyright (C) 1998-2004 Samuel Rydh (samuel at ibrium.se)
+ *
+ * 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 "hw.h"
+#include "isa.h"
+#include "mac_dbdma.h"
+
+/* debug DBDMA */
+//#define DEBUG_DBDMA
+
+#ifdef DEBUG_DBDMA
+#define DBDMA_DPRINTF(fmt, ...)                                 \
+    do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBDMA_DPRINTF(fmt, ...)
+#endif
+
+/*
+ */
+
+/*
+ * DBDMA control/status registers.  All little-endian.
+ */
+
+#define DBDMA_CONTROL         0x00
+#define DBDMA_STATUS          0x01
+#define DBDMA_CMDPTR_HI       0x02
+#define DBDMA_CMDPTR_LO       0x03
+#define DBDMA_INTR_SEL        0x04
+#define DBDMA_BRANCH_SEL      0x05
+#define DBDMA_WAIT_SEL        0x06
+#define DBDMA_XFER_MODE       0x07
+#define DBDMA_DATA2PTR_HI     0x08
+#define DBDMA_DATA2PTR_LO     0x09
+#define DBDMA_RES1            0x0A
+#define DBDMA_ADDRESS_HI      0x0B
+#define DBDMA_BRANCH_ADDR_HI  0x0C
+#define DBDMA_RES2            0x0D
+#define DBDMA_RES3            0x0E
+#define DBDMA_RES4            0x0F
+
+#define DBDMA_REGS            16
+#define DBDMA_SIZE            (DBDMA_REGS * sizeof(uint32_t))
+
+#define DBDMA_CHANNEL_SHIFT   7
+#define DBDMA_CHANNEL_SIZE    (1 << DBDMA_CHANNEL_SHIFT)
+
+#define DBDMA_CHANNELS        (0x1000 >> DBDMA_CHANNEL_SHIFT)
+
+/* Bits in control and status registers */
+
+#define RUN	0x8000
+#define PAUSE	0x4000
+#define FLUSH	0x2000
+#define WAKE	0x1000
+#define DEAD	0x0800
+#define ACTIVE	0x0400
+#define BT	0x0100
+#define DEVSTAT	0x00ff
+
+/*
+ * DBDMA command structure.  These fields are all little-endian!
+ */
+
+typedef struct dbdma_cmd {
+    uint16_t req_count;	  /* requested byte transfer count */
+    uint16_t command;	  /* command word (has bit-fields) */
+    uint32_t phy_addr;	  /* physical data address */
+    uint32_t cmd_dep;	  /* command-dependent field */
+    uint16_t res_count;	  /* residual count after completion */
+    uint16_t xfer_status; /* transfer status */
+} dbdma_cmd;
+
+/* DBDMA command values in command field */
+
+#define COMMAND_MASK    0xf000
+#define OUTPUT_MORE	0x0000	/* transfer memory data to stream */
+#define OUTPUT_LAST	0x1000	/* ditto followed by end marker */
+#define INPUT_MORE	0x2000	/* transfer stream data to memory */
+#define INPUT_LAST	0x3000	/* ditto, expect end marker */
+#define STORE_WORD	0x4000	/* write word (4 bytes) to device reg */
+#define LOAD_WORD	0x5000	/* read word (4 bytes) from device reg */
+#define DBDMA_NOP	0x6000	/* do nothing */
+#define DBDMA_STOP	0x7000	/* suspend processing */
+
+/* Key values in command field */
+
+#define KEY_MASK        0x0700
+#define KEY_STREAM0	0x0000	/* usual data stream */
+#define KEY_STREAM1	0x0100	/* control/status stream */
+#define KEY_STREAM2	0x0200	/* device-dependent stream */
+#define KEY_STREAM3	0x0300	/* device-dependent stream */
+#define KEY_STREAM4	0x0400	/* reserved */
+#define KEY_REGS	0x0500	/* device register space */
+#define KEY_SYSTEM	0x0600	/* system memory-mapped space */
+#define KEY_DEVICE	0x0700	/* device memory-mapped space */
+
+/* Interrupt control values in command field */
+
+#define INTR_MASK       0x0030
+#define INTR_NEVER	0x0000	/* don't interrupt */
+#define INTR_IFSET	0x0010	/* intr if condition bit is 1 */
+#define INTR_IFCLR	0x0020	/* intr if condition bit is 0 */
+#define INTR_ALWAYS	0x0030	/* always interrupt */
+
+/* Branch control values in command field */
+
+#define BR_MASK         0x000c
+#define BR_NEVER	0x0000	/* don't branch */
+#define BR_IFSET	0x0004	/* branch if condition bit is 1 */
+#define BR_IFCLR	0x0008	/* branch if condition bit is 0 */
+#define BR_ALWAYS	0x000c	/* always branch */
+
+/* Wait control values in command field */
+
+#define WAIT_MASK       0x0003
+#define WAIT_NEVER	0x0000	/* don't wait */
+#define WAIT_IFSET	0x0001	/* wait if condition bit is 1 */
+#define WAIT_IFCLR	0x0002	/* wait if condition bit is 0 */
+#define WAIT_ALWAYS	0x0003	/* always wait */
+
+typedef struct DBDMA_channel {
+    int channel;
+    uint32_t regs[DBDMA_REGS];
+    qemu_irq irq;
+    DBDMA_io io;
+    DBDMA_rw rw;
+    DBDMA_flush flush;
+    dbdma_cmd current;
+    int processing;
+} DBDMA_channel;
+
+typedef struct {
+    DBDMA_channel channels[DBDMA_CHANNELS];
+} DBDMAState;
+
+#ifdef DEBUG_DBDMA
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
+{
+    printf("dbdma_cmd %p\n", cmd);
+    printf("    req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
+    printf("    command 0x%04x\n", le16_to_cpu(cmd->command));
+    printf("    phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
+    printf("    cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
+    printf("    res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
+    printf("    xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
+}
+#else
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
+{
+}
+#endif
+static void dbdma_cmdptr_load(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
+                  ch->regs[DBDMA_CMDPTR_LO]);
+    cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
+                             (uint8_t*)&ch->current, sizeof(dbdma_cmd));
+}
+
+static void dbdma_cmdptr_save(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
+                  ch->regs[DBDMA_CMDPTR_LO]);
+    DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
+                  le16_to_cpu(ch->current.xfer_status),
+                  le16_to_cpu(ch->current.res_count));
+    cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
+                              (uint8_t*)&ch->current, sizeof(dbdma_cmd));
+}
+
+static void kill_channel(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("kill_channel\n");
+
+    ch->regs[DBDMA_STATUS] |= DEAD;
+    ch->regs[DBDMA_STATUS] &= ~ACTIVE;
+
+    qemu_irq_raise(ch->irq);
+}
+
+static void conditional_interrupt(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t intr;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_interrupt\n");
+
+    intr = le16_to_cpu(current->command) & INTR_MASK;
+
+    switch(intr) {
+    case INTR_NEVER:  /* don't interrupt */
+        return;
+    case INTR_ALWAYS: /* always interrupt */
+        qemu_irq_raise(ch->irq);
+        return;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(intr) {
+    case INTR_IFSET:  /* intr if condition bit is 1 */
+        if (cond)
+            qemu_irq_raise(ch->irq);
+        return;
+    case INTR_IFCLR:  /* intr if condition bit is 0 */
+        if (!cond)
+            qemu_irq_raise(ch->irq);
+        return;
+    }
+}
+
+static int conditional_wait(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t wait;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_wait\n");
+
+    wait = le16_to_cpu(current->command) & WAIT_MASK;
+
+    switch(wait) {
+    case WAIT_NEVER:  /* don't wait */
+        return 0;
+    case WAIT_ALWAYS: /* always wait */
+        return 1;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(wait) {
+    case WAIT_IFSET:  /* wait if condition bit is 1 */
+        if (cond)
+            return 1;
+        return 0;
+    case WAIT_IFCLR:  /* wait if condition bit is 0 */
+        if (!cond)
+            return 1;
+        return 0;
+    }
+    return 0;
+}
+
+static void next(DBDMA_channel *ch)
+{
+    uint32_t cp;
+
+    ch->regs[DBDMA_STATUS] &= ~BT;
+
+    cp = ch->regs[DBDMA_CMDPTR_LO];
+    ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
+    dbdma_cmdptr_load(ch);
+}
+
+static void branch(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+
+    ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
+    ch->regs[DBDMA_STATUS] |= BT;
+    dbdma_cmdptr_load(ch);
+}
+
+static void conditional_branch(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t br;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_branch\n");
+
+    /* check if we must branch */
+
+    br = le16_to_cpu(current->command) & BR_MASK;
+
+    switch(br) {
+    case BR_NEVER:  /* don't branch */
+        next(ch);
+        return;
+    case BR_ALWAYS: /* always branch */
+        branch(ch);
+        return;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(br) {
+    case BR_IFSET:  /* branch if condition bit is 1 */
+        if (cond)
+            branch(ch);
+        else
+            next(ch);
+        return;
+    case BR_IFCLR:  /* branch if condition bit is 0 */
+        if (!cond)
+            branch(ch);
+        else
+            next(ch);
+        return;
+    }
+}
+
+static QEMUBH *dbdma_bh;
+static void channel_run(DBDMA_channel *ch);
+
+static void dbdma_end(DBDMA_io *io)
+{
+    DBDMA_channel *ch = io->channel;
+    dbdma_cmd *current = &ch->current;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    current->res_count = cpu_to_le16(io->len);
+    dbdma_cmdptr_save(ch);
+    if (io->is_last)
+        ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    conditional_branch(ch);
+
+wait:
+    ch->processing = 0;
+    if ((ch->regs[DBDMA_STATUS] & RUN) &&
+        (ch->regs[DBDMA_STATUS] & ACTIVE))
+        channel_run(ch);
+}
+
+static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
+                        uint16_t req_count, int is_last)
+{
+    DBDMA_DPRINTF("start_output\n");
+
+    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+     * are not implemented in the mac-io chip
+     */
+
+    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
+    if (!addr || key > KEY_STREAM3) {
+        kill_channel(ch);
+        return;
+    }
+
+    ch->io.addr = addr;
+    ch->io.len = req_count;
+    ch->io.is_last = is_last;
+    ch->io.dma_end = dbdma_end;
+    ch->io.is_dma_out = 1;
+    ch->processing = 1;
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
+}
+
+static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
+                       uint16_t req_count, int is_last)
+{
+    DBDMA_DPRINTF("start_input\n");
+
+    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+     * are not implemented in the mac-io chip
+     */
+
+    if (!addr || key > KEY_STREAM3) {
+        kill_channel(ch);
+        return;
+    }
+
+    ch->io.addr = addr;
+    ch->io.len = req_count;
+    ch->io.is_last = is_last;
+    ch->io.dma_end = dbdma_end;
+    ch->io.is_dma_out = 0;
+    ch->processing = 1;
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
+}
+
+static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
+                     uint16_t len)
+{
+    dbdma_cmd *current = &ch->current;
+    uint32_t val;
+
+    DBDMA_DPRINTF("load_word\n");
+
+    /* only implements KEY_SYSTEM */
+
+    if (key != KEY_SYSTEM) {
+        printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
+        kill_channel(ch);
+        return;
+    }
+
+    cpu_physical_memory_read(addr, (uint8_t*)&val, len);
+
+    if (len == 2)
+        val = (val << 16) | (current->cmd_dep & 0x0000ffff);
+    else if (len == 1)
+        val = (val << 24) | (current->cmd_dep & 0x00ffffff);
+
+    current->cmd_dep = val;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+    ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    next(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
+                      uint16_t len)
+{
+    dbdma_cmd *current = &ch->current;
+    uint32_t val;
+
+    DBDMA_DPRINTF("store_word\n");
+
+    /* only implements KEY_SYSTEM */
+
+    if (key != KEY_SYSTEM) {
+        printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
+        kill_channel(ch);
+        return;
+    }
+
+    val = current->cmd_dep;
+    if (len == 2)
+        val >>= 16;
+    else if (len == 1)
+        val >>= 24;
+
+    cpu_physical_memory_write(addr, (uint8_t*)&val, len);
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+    ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    next(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void nop(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+
+    conditional_interrupt(ch);
+    conditional_branch(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void stop(DBDMA_channel *ch)
+{
+    ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
+
+    /* the stop command does not increment command pointer */
+}
+
+static void channel_run(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t cmd, key;
+    uint16_t req_count;
+    uint32_t phy_addr;
+
+    DBDMA_DPRINTF("channel_run\n");
+    dump_dbdma_cmd(current);
+
+    /* clear WAKE flag at command fetch */
+
+    ch->regs[DBDMA_STATUS] &= ~WAKE;
+
+    cmd = le16_to_cpu(current->command) & COMMAND_MASK;
+
+    switch (cmd) {
+    case DBDMA_NOP:
+        nop(ch);
+	return;
+
+    case DBDMA_STOP:
+        stop(ch);
+	return;
+    }
+
+    key = le16_to_cpu(current->command) & 0x0700;
+    req_count = le16_to_cpu(current->req_count);
+    phy_addr = le32_to_cpu(current->phy_addr);
+
+    if (key == KEY_STREAM4) {
+        printf("command %x, invalid key 4\n", cmd);
+        kill_channel(ch);
+        return;
+    }
+
+    switch (cmd) {
+    case OUTPUT_MORE:
+        start_output(ch, key, phy_addr, req_count, 0);
+	return;
+
+    case OUTPUT_LAST:
+        start_output(ch, key, phy_addr, req_count, 1);
+	return;
+
+    case INPUT_MORE:
+        start_input(ch, key, phy_addr, req_count, 0);
+	return;
+
+    case INPUT_LAST:
+        start_input(ch, key, phy_addr, req_count, 1);
+	return;
+    }
+
+    if (key < KEY_REGS) {
+        printf("command %x, invalid key %x\n", cmd, key);
+        key = KEY_SYSTEM;
+    }
+
+    /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
+     * and BRANCH is invalid
+     */
+
+    req_count = req_count & 0x0007;
+    if (req_count & 0x4) {
+        req_count = 4;
+        phy_addr &= ~3;
+    } else if (req_count & 0x2) {
+        req_count = 2;
+        phy_addr &= ~1;
+    } else
+        req_count = 1;
+
+    switch (cmd) {
+    case LOAD_WORD:
+        load_word(ch, key, phy_addr, req_count);
+	return;
+
+    case STORE_WORD:
+        store_word(ch, key, phy_addr, req_count);
+	return;
+    }
+}
+
+static void DBDMA_run(DBDMAState *s)
+{
+    int channel;
+
+    for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
+        DBDMA_channel *ch = &s->channels[channel];
+        uint32_t status = ch->regs[DBDMA_STATUS];
+        if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
+            channel_run(ch);
+        }
+    }
+}
+
+static void DBDMA_run_bh(void *opaque)
+{
+    DBDMAState *s = opaque;
+
+    DBDMA_DPRINTF("DBDMA_run_bh\n");
+
+    DBDMA_run(s);
+}
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+                            DBDMA_rw rw, DBDMA_flush flush,
+                            void *opaque)
+{
+    DBDMAState *s = dbdma;
+    DBDMA_channel *ch = &s->channels[nchan];
+
+    DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
+
+    ch->irq = irq;
+    ch->channel = nchan;
+    ch->rw = rw;
+    ch->flush = flush;
+    ch->io.opaque = opaque;
+    ch->io.channel = ch;
+}
+
+void DBDMA_schedule(void)
+{
+    qemu_notify_event();
+}
+
+static void
+dbdma_control_write(DBDMA_channel *ch)
+{
+    uint16_t mask, value;
+    uint32_t status;
+
+    mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
+    value = ch->regs[DBDMA_CONTROL] & 0xffff;
+
+    value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
+
+    status = ch->regs[DBDMA_STATUS];
+
+    status = (value & mask) | (status & ~mask);
+
+    if (status & WAKE)
+        status |= ACTIVE;
+    if (status & RUN) {
+        status |= ACTIVE;
+        status &= ~DEAD;
+    }
+    if (status & PAUSE)
+        status &= ~ACTIVE;
+    if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
+        /* RUN is cleared */
+        status &= ~(ACTIVE|DEAD);
+    }
+
+    DBDMA_DPRINTF("    status 0x%08x\n", status);
+
+    ch->regs[DBDMA_STATUS] = status;
+
+    if (status & ACTIVE)
+        qemu_bh_schedule(dbdma_bh);
+    if ((status & FLUSH) && ch->flush)
+        ch->flush(&ch->io);
+}
+
+static void dbdma_writel (void *opaque,
+                          target_phys_addr_t addr, uint32_t value)
+{
+    int channel = addr >> DBDMA_CHANNEL_SHIFT;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
+    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
+
+    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+    /* cmdptr cannot be modified if channel is RUN or ACTIVE */
+
+    if (reg == DBDMA_CMDPTR_LO &&
+        (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
+	return;
+
+    ch->regs[reg] = value;
+
+    switch(reg) {
+    case DBDMA_CONTROL:
+        dbdma_control_write(ch);
+        break;
+    case DBDMA_CMDPTR_LO:
+        /* 16-byte aligned */
+        ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
+        dbdma_cmdptr_load(ch);
+        break;
+    case DBDMA_STATUS:
+    case DBDMA_INTR_SEL:
+    case DBDMA_BRANCH_SEL:
+    case DBDMA_WAIT_SEL:
+        /* nothing to do */
+        break;
+    case DBDMA_XFER_MODE:
+    case DBDMA_CMDPTR_HI:
+    case DBDMA_DATA2PTR_HI:
+    case DBDMA_DATA2PTR_LO:
+    case DBDMA_ADDRESS_HI:
+    case DBDMA_BRANCH_ADDR_HI:
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        /* unused */
+        break;
+    }
+}
+
+static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t value;
+    int channel = addr >> DBDMA_CHANNEL_SHIFT;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
+    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
+
+    value = ch->regs[reg];
+
+    DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
+    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+    switch(reg) {
+    case DBDMA_CONTROL:
+        value = 0;
+        break;
+    case DBDMA_STATUS:
+    case DBDMA_CMDPTR_LO:
+    case DBDMA_INTR_SEL:
+    case DBDMA_BRANCH_SEL:
+    case DBDMA_WAIT_SEL:
+        /* nothing to do */
+        break;
+    case DBDMA_XFER_MODE:
+    case DBDMA_CMDPTR_HI:
+    case DBDMA_DATA2PTR_HI:
+    case DBDMA_DATA2PTR_LO:
+    case DBDMA_ADDRESS_HI:
+    case DBDMA_BRANCH_ADDR_HI:
+        /* unused */
+        value = 0;
+        break;
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        /* reserved */
+        break;
+    }
+
+    return value;
+}
+
+static CPUWriteMemoryFunc * const dbdma_write[] = {
+    NULL,
+    NULL,
+    dbdma_writel,
+};
+
+static CPUReadMemoryFunc * const dbdma_read[] = {
+    NULL,
+    NULL,
+    dbdma_readl,
+};
+
+static const VMStateDescription vmstate_dbdma_channel = {
+    .name = "dbdma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_dbdma = {
+    .name = "dbdma",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
+                             vmstate_dbdma_channel, DBDMA_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void dbdma_reset(void *opaque)
+{
+    DBDMAState *s = opaque;
+    int i;
+
+    for (i = 0; i < DBDMA_CHANNELS; i++)
+        memset(s->channels[i].regs, 0, DBDMA_SIZE);
+}
+
+void* DBDMA_init (int *dbdma_mem_index)
+{
+    DBDMAState *s;
+
+    s = qemu_mallocz(sizeof(DBDMAState));
+
+    *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
+                                              DEVICE_LITTLE_ENDIAN);
+    vmstate_register(NULL, -1, &vmstate_dbdma, s);
+    qemu_register_reset(dbdma_reset, s);
+
+    dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/mac_dbdma.h b/qemu-0.15.x/hw/mac_dbdma.h
new file mode 100644
index 0000000..d236c5b
--- /dev/null
+++ b/qemu-0.15.x/hw/mac_dbdma.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * 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.
+ */
+
+typedef struct DBDMA_io DBDMA_io;
+
+typedef void (*DBDMA_flush)(DBDMA_io *io);
+typedef void (*DBDMA_rw)(DBDMA_io *io);
+typedef void (*DBDMA_end)(DBDMA_io *io);
+struct DBDMA_io {
+    void *opaque;
+    void *channel;
+    target_phys_addr_t addr;
+    int len;
+    int is_last;
+    int is_dma_out;
+    DBDMA_end dma_end;
+};
+
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+                            DBDMA_rw rw, DBDMA_flush flush,
+                            void *opaque);
+void DBDMA_schedule(void);
+void* DBDMA_init (int *dbdma_mem_index);
diff --git a/qemu-0.15.x/hw/mac_nvram.c b/qemu-0.15.x/hw/mac_nvram.c
new file mode 100644
index 0000000..61e53d2
--- /dev/null
+++ b/qemu-0.15.x/hw/mac_nvram.c
@@ -0,0 +1,187 @@
+/*
+ * PowerMac NVRAM emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "firmware_abi.h"
+#include "sysemu.h"
+#include "ppc_mac.h"
+
+/* debug NVR */
+//#define DEBUG_NVR
+
+#ifdef DEBUG_NVR
+#define NVR_DPRINTF(fmt, ...)                                   \
+    do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define NVR_DPRINTF(fmt, ...)
+#endif
+
+struct MacIONVRAMState {
+    uint32_t size;
+    int mem_index;
+    unsigned int it_shift;
+    uint8_t *data;
+};
+
+#define DEF_SYSTEM_SIZE 0xc10
+
+/* Direct access to NVRAM */
+uint32_t macio_nvram_read (void *opaque, uint32_t addr)
+{
+    MacIONVRAMState *s = opaque;
+    uint32_t ret;
+
+    if (addr < s->size)
+        ret = s->data[addr];
+    else
+        ret = -1;
+    NVR_DPRINTF("read addr %04x val %x\n", addr, ret);
+
+    return ret;
+}
+
+void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    MacIONVRAMState *s = opaque;
+
+    NVR_DPRINTF("write addr %04x val %x\n", addr, val);
+    if (addr < s->size)
+        s->data[addr] = val;
+}
+
+/* macio style NVRAM device */
+static void macio_nvram_writeb (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    MacIONVRAMState *s = opaque;
+
+    addr = (addr >> s->it_shift) & (s->size - 1);
+    s->data[addr] = value;
+    NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value);
+}
+
+static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
+{
+    MacIONVRAMState *s = opaque;
+    uint32_t value;
+
+    addr = (addr >> s->it_shift) & (s->size - 1);
+    value = s->data[addr];
+    NVR_DPRINTF("readb addr %04x val %x\n", (int)addr, value);
+
+    return value;
+}
+
+static CPUWriteMemoryFunc * const nvram_write[] = {
+    &macio_nvram_writeb,
+    &macio_nvram_writeb,
+    &macio_nvram_writeb,
+};
+
+static CPUReadMemoryFunc * const nvram_read[] = {
+    &macio_nvram_readb,
+    &macio_nvram_readb,
+    &macio_nvram_readb,
+};
+
+static const VMStateDescription vmstate_macio_nvram = {
+    .name = "macio_nvram",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static void macio_nvram_reset(void *opaque)
+{
+}
+
+MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+                                   unsigned int it_shift)
+{
+    MacIONVRAMState *s;
+
+    s = qemu_mallocz(sizeof(MacIONVRAMState));
+    s->data = qemu_mallocz(size);
+    s->size = size;
+    s->it_shift = it_shift;
+
+    s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                          DEVICE_NATIVE_ENDIAN);
+    *mem_index = s->mem_index;
+    vmstate_register(NULL, -1, &vmstate_macio_nvram, s);
+    qemu_register_reset(macio_nvram_reset, s);
+
+    return s;
+}
+
+void macio_nvram_map (void *opaque, target_phys_addr_t mem_base)
+{
+    MacIONVRAMState *s;
+
+    s = opaque;
+    cpu_register_physical_memory(mem_base, s->size << s->it_shift,
+                                 s->mem_index);
+}
+
+/* Set up a system OpenBIOS NVRAM partition */
+void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len)
+{
+    unsigned int i;
+    uint32_t start = 0, end;
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)nvr->data;
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(nvr->data, end, prom_envs[i]);
+
+    // End marker
+    nvr->data[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    /* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
+       new variables. */
+    if (end < DEF_SYSTEM_SIZE)
+        end = DEF_SYSTEM_SIZE;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = len;
+    OpenBIOS_finish_partition(part_header, end - start);
+}
diff --git a/qemu-0.15.x/hw/macio.c b/qemu-0.15.x/hw/macio.c
new file mode 100644
index 0000000..789ca55
--- /dev/null
+++ b/qemu-0.15.x/hw/macio.c
@@ -0,0 +1,118 @@
+/*
+ * PowerMac MacIO device emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc_mac.h"
+#include "pci.h"
+#include "escc.h"
+
+typedef struct macio_state_t macio_state_t;
+struct macio_state_t {
+    int is_oldworld;
+    int pic_mem_index;
+    int dbdma_mem_index;
+    int cuda_mem_index;
+    int escc_mem_index;
+    void *nvram;
+    int nb_ide;
+    int ide_mem_index[4];
+};
+
+static void macio_map (PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    macio_state_t *macio_state;
+    int i;
+
+    macio_state = (macio_state_t *)(pci_dev + 1);
+    if (macio_state->pic_mem_index >= 0) {
+        if (macio_state->is_oldworld) {
+            /* Heathrow PIC */
+            cpu_register_physical_memory(addr + 0x00000, 0x1000,
+                                         macio_state->pic_mem_index);
+        } else {
+            /* OpenPIC */
+            cpu_register_physical_memory(addr + 0x40000, 0x40000,
+                                         macio_state->pic_mem_index);
+        }
+    }
+    if (macio_state->dbdma_mem_index >= 0) {
+        cpu_register_physical_memory(addr + 0x08000, 0x1000,
+                                     macio_state->dbdma_mem_index);
+    }
+    if (macio_state->escc_mem_index >= 0) {
+        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE << 4,
+                                     macio_state->escc_mem_index);
+    }
+    if (macio_state->cuda_mem_index >= 0) {
+        cpu_register_physical_memory(addr + 0x16000, 0x2000,
+                                     macio_state->cuda_mem_index);
+    }
+    for (i = 0; i < macio_state->nb_ide; i++) {
+        if (macio_state->ide_mem_index[i] >= 0) {
+            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
+                                         macio_state->ide_mem_index[i]);
+        }
+    }
+    if (macio_state->nvram != NULL)
+        macio_nvram_map(macio_state->nvram, addr + 0x60000);
+}
+
+void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
+                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
+                 int nb_ide, int *ide_mem_index, int escc_mem_index)
+{
+    PCIDevice *d;
+    macio_state_t *macio_state;
+    int i;
+
+    d = pci_register_device(bus, "macio",
+                            sizeof(PCIDevice) + sizeof(macio_state_t),
+                            -1, NULL, NULL);
+    macio_state = (macio_state_t *)(d + 1);
+    macio_state->is_oldworld = is_oldworld;
+    macio_state->pic_mem_index = pic_mem_index;
+    macio_state->dbdma_mem_index = dbdma_mem_index;
+    macio_state->cuda_mem_index = cuda_mem_index;
+    macio_state->escc_mem_index = escc_mem_index;
+    macio_state->nvram = nvram;
+    if (nb_ide > 4)
+        nb_ide = 4;
+    macio_state->nb_ide = nb_ide;
+    for (i = 0; i < nb_ide; i++)
+        macio_state->ide_mem_index[i] = ide_mem_index[i];
+    for (; i < 4; i++)
+        macio_state->ide_mem_index[i] = -1;
+    /* Note: this code is strongly inspirated from the corresponding code
+       in PearPC */
+
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+    pci_config_set_device_id(d->config, device_id);
+    pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
+
+    d->config[0x3d] = 0x01; // interrupt on pin 1
+
+    pci_register_bar(d, 0, 0x80000,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
+}
diff --git a/qemu-0.15.x/hw/mainstone.c b/qemu-0.15.x/hw/mainstone.c
new file mode 100644
index 0000000..4792f0e
--- /dev/null
+++ b/qemu-0.15.x/hw/mainstone.c
@@ -0,0 +1,188 @@
+/*
+ * PXA270-based Intel Mainstone platforms.
+ *
+ * Copyright (c) 2007 by Armin Kuster <akuster at kama-aina.net> or
+ *                                    <akuster at mvista.com>
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "pxa.h"
+#include "arm-misc.h"
+#include "net.h"
+#include "devices.h"
+#include "boards.h"
+#include "flash.h"
+#include "blockdev.h"
+#include "sysbus.h"
+
+/* Device addresses */
+#define MST_FPGA_PHYS	0x08000000
+#define MST_ETH_PHYS	0x10000300
+#define MST_FLASH_0		0x00000000
+#define MST_FLASH_1		0x04000000
+
+/* IRQ definitions */
+#define MMC_IRQ       0
+#define USIM_IRQ      1
+#define USBC_IRQ      2
+#define ETHERNET_IRQ  3
+#define AC97_IRQ      4
+#define PEN_IRQ       5
+#define MSINS_IRQ     6
+#define EXBRD_IRQ     7
+#define S0_CD_IRQ     9
+#define S0_STSCHG_IRQ 10
+#define S0_IRQ        11
+#define S1_CD_IRQ     13
+#define S1_STSCHG_IRQ 14
+#define S1_IRQ        15
+
+static struct keymap map[0xE0] = {
+    [0 ... 0xDF] = { -1, -1 },
+    [0x1e] = {0,0}, /* a */
+    [0x30] = {0,1}, /* b */
+    [0x2e] = {0,2}, /* c */
+    [0x20] = {0,3}, /* d */
+    [0x12] = {0,4}, /* e */
+    [0x21] = {0,5}, /* f */
+    [0x22] = {1,0}, /* g */
+    [0x23] = {1,1}, /* h */
+    [0x17] = {1,2}, /* i */
+    [0x24] = {1,3}, /* j */
+    [0x25] = {1,4}, /* k */
+    [0x26] = {1,5}, /* l */
+    [0x32] = {2,0}, /* m */
+    [0x31] = {2,1}, /* n */
+    [0x18] = {2,2}, /* o */
+    [0x19] = {2,3}, /* p */
+    [0x10] = {2,4}, /* q */
+    [0x13] = {2,5}, /* r */
+    [0x1f] = {3,0}, /* s */
+    [0x14] = {3,1}, /* t */
+    [0x16] = {3,2}, /* u */
+    [0x2f] = {3,3}, /* v */
+    [0x11] = {3,4}, /* w */
+    [0x2d] = {3,5}, /* x */
+    [0x15] = {4,2}, /* y */
+    [0x2c] = {4,3}, /* z */
+    [0xc7] = {5,0}, /* Home */
+    [0x2a] = {5,1}, /* shift */
+    [0x39] = {5,2}, /* space */
+    [0x39] = {5,3}, /* space */
+    [0x1c] = {5,5}, /*  enter */
+    [0xc8] = {6,0}, /* up */
+    [0xd0] = {6,1}, /* down */
+    [0xcb] = {6,2}, /* left */
+    [0xcd] = {6,3}, /* right */
+};
+
+enum mainstone_model_e { mainstone };
+
+#define MAINSTONE_RAM	0x04000000
+#define MAINSTONE_ROM	0x00800000
+#define MAINSTONE_FLASH	0x02000000
+
+static struct arm_boot_info mainstone_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void mainstone_common_init(ram_addr_t ram_size,
+                const char *kernel_filename,
+                const char *kernel_cmdline, const char *initrd_filename,
+                const char *cpu_model, enum mainstone_model_e model, int arm_id)
+{
+    uint32_t sector_len = 256 * 1024;
+    target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
+    PXA2xxState *cpu;
+    DeviceState *mst_irq;
+    DriveInfo *dinfo;
+    int i;
+    int be;
+
+    if (!cpu_model)
+        cpu_model = "pxa270-c5";
+
+    /* Setup CPU & memory */
+    cpu = pxa270_init(mainstone_binfo.ram_size, cpu_model);
+    cpu_register_physical_memory(0, MAINSTONE_ROM,
+                    qemu_ram_alloc(NULL, "mainstone.rom",
+                                   MAINSTONE_ROM) | IO_MEM_ROM);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    /* There are two 32MiB flash devices on the board */
+    for (i = 0; i < 2; i ++) {
+        dinfo = drive_get(IF_PFLASH, 0, i);
+        if (!dinfo) {
+            fprintf(stderr, "Two flash images must be given with the "
+                    "'pflash' parameter\n");
+            exit(1);
+        }
+
+        if (!pflash_cfi01_register(mainstone_flash_base[i],
+                                   qemu_ram_alloc(NULL, i ? "mainstone.flash1" :
+                                                  "mainstone.flash0",
+                                                  MAINSTONE_FLASH),
+                                   dinfo->bdrv, sector_len,
+                                   MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
+                                   be)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+            exit(1);
+        }
+    }
+
+    mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
+                    qdev_get_gpio_in(cpu->gpio, 0));
+
+    /* setup keypad */
+    printf("map addr %p\n", &map);
+    pxa27x_register_keypad(cpu->kp, map, 0xe0);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
+
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+            qdev_get_gpio_in(mst_irq, S0_IRQ),
+            qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+            qdev_get_gpio_in(mst_irq, S1_IRQ),
+            qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
+
+    smc91c111_init(&nd_table[0], MST_ETH_PHYS,
+                    qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
+
+    mainstone_binfo.kernel_filename = kernel_filename;
+    mainstone_binfo.kernel_cmdline = kernel_cmdline;
+    mainstone_binfo.initrd_filename = initrd_filename;
+    mainstone_binfo.board_id = arm_id;
+    arm_load_kernel(cpu->env, &mainstone_binfo);
+}
+
+static void mainstone_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    mainstone_common_init(ram_size, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196);
+}
+
+static QEMUMachine mainstone2_machine = {
+    .name = "mainstone",
+    .desc = "Mainstone II (PXA27x)",
+    .init = mainstone_init,
+};
+
+static void mainstone_machine_init(void)
+{
+    qemu_register_machine(&mainstone2_machine);
+}
+
+machine_init(mainstone_machine_init);
diff --git a/qemu-0.15.x/hw/marvell_88w8618_audio.c b/qemu-0.15.x/hw/marvell_88w8618_audio.c
new file mode 100644
index 0000000..f8c5242
--- /dev/null
+++ b/qemu-0.15.x/hw/marvell_88w8618_audio.c
@@ -0,0 +1,299 @@
+/*
+ * Marvell 88w8618 audio emulation extracted from
+ * Marvell MV88w8618 / Freecom MusicPal emulation.
+ *
+ * Copyright (c) 2008 Jan Kiszka
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "sysbus.h"
+#include "hw.h"
+#include "i2c.h"
+#include "sysbus.h"
+#include "audio/audio.h"
+
+#define MP_AUDIO_SIZE           0x00001000
+
+/* Audio register offsets */
+#define MP_AUDIO_PLAYBACK_MODE  0x00
+#define MP_AUDIO_CLOCK_DIV      0x18
+#define MP_AUDIO_IRQ_STATUS     0x20
+#define MP_AUDIO_IRQ_ENABLE     0x24
+#define MP_AUDIO_TX_START_LO    0x28
+#define MP_AUDIO_TX_THRESHOLD   0x2C
+#define MP_AUDIO_TX_STATUS      0x38
+#define MP_AUDIO_TX_START_HI    0x40
+
+/* Status register and IRQ enable bits */
+#define MP_AUDIO_TX_HALF        (1 << 6)
+#define MP_AUDIO_TX_FULL        (1 << 7)
+
+/* Playback mode bits */
+#define MP_AUDIO_16BIT_SAMPLE   (1 << 0)
+#define MP_AUDIO_PLAYBACK_EN    (1 << 7)
+#define MP_AUDIO_CLOCK_24MHZ    (1 << 9)
+#define MP_AUDIO_MONO           (1 << 14)
+
+typedef struct mv88w8618_audio_state {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t playback_mode;
+    uint32_t status;
+    uint32_t irq_enable;
+    uint32_t phys_buf;
+    uint32_t target_buffer;
+    uint32_t threshold;
+    uint32_t play_pos;
+    uint32_t last_free;
+    uint32_t clock_div;
+    DeviceState *wm;
+} mv88w8618_audio_state;
+
+static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
+{
+    mv88w8618_audio_state *s = opaque;
+    int16_t *codec_buffer;
+    int8_t buf[4096];
+    int8_t *mem_buffer;
+    int pos, block_size;
+
+    if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
+        return;
+    }
+    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
+        free_out <<= 1;
+    }
+    if (!(s->playback_mode & MP_AUDIO_MONO)) {
+        free_out <<= 1;
+    }
+    block_size = s->threshold / 2;
+    if (free_out - s->last_free < block_size) {
+        return;
+    }
+    if (block_size > 4096) {
+        return;
+    }
+    cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf,
+                             block_size);
+    mem_buffer = buf;
+    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
+        if (s->playback_mode & MP_AUDIO_MONO) {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
+            for (pos = 0; pos < block_size; pos += 2) {
+                *codec_buffer++ = *(int16_t *)mem_buffer;
+                *codec_buffer++ = *(int16_t *)mem_buffer;
+                mem_buffer += 2;
+            }
+        } else {
+            memcpy(wm8750_dac_buffer(s->wm, block_size >> 2),
+                   (uint32_t *)mem_buffer, block_size);
+        }
+    } else {
+        if (s->playback_mode & MP_AUDIO_MONO) {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size);
+            for (pos = 0; pos < block_size; pos++) {
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer);
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+            }
+        } else {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
+            for (pos = 0; pos < block_size; pos += 2) {
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+            }
+        }
+    }
+    wm8750_dac_commit(s->wm);
+
+    s->last_free = free_out - block_size;
+
+    if (s->play_pos == 0) {
+        s->status |= MP_AUDIO_TX_HALF;
+        s->play_pos = block_size;
+    } else {
+        s->status |= MP_AUDIO_TX_FULL;
+        s->play_pos = 0;
+    }
+
+    if (s->status & s->irq_enable) {
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s)
+{
+    int rate;
+
+    if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) {
+        rate = 24576000 / 64; /* 24.576MHz */
+    } else {
+        rate = 11289600 / 64; /* 11.2896MHz */
+    }
+    rate /= ((s->clock_div >> 8) & 0xff) + 1;
+
+    wm8750_set_bclk_in(s->wm, rate);
+}
+
+static uint32_t mv88w8618_audio_read(void *opaque, target_phys_addr_t offset)
+{
+    mv88w8618_audio_state *s = opaque;
+
+    switch (offset) {
+    case MP_AUDIO_PLAYBACK_MODE:
+        return s->playback_mode;
+
+    case MP_AUDIO_CLOCK_DIV:
+        return s->clock_div;
+
+    case MP_AUDIO_IRQ_STATUS:
+        return s->status;
+
+    case MP_AUDIO_IRQ_ENABLE:
+        return s->irq_enable;
+
+    case MP_AUDIO_TX_STATUS:
+        return s->play_pos >> 2;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_audio_write(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+    mv88w8618_audio_state *s = opaque;
+
+    switch (offset) {
+    case MP_AUDIO_PLAYBACK_MODE:
+        if (value & MP_AUDIO_PLAYBACK_EN &&
+            !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
+            s->status = 0;
+            s->last_free = 0;
+            s->play_pos = 0;
+        }
+        s->playback_mode = value;
+        mv88w8618_audio_clock_update(s);
+        break;
+
+    case MP_AUDIO_CLOCK_DIV:
+        s->clock_div = value;
+        s->last_free = 0;
+        s->play_pos = 0;
+        mv88w8618_audio_clock_update(s);
+        break;
+
+    case MP_AUDIO_IRQ_STATUS:
+        s->status &= ~value;
+        break;
+
+    case MP_AUDIO_IRQ_ENABLE:
+        s->irq_enable = value;
+        if (s->status & s->irq_enable) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_AUDIO_TX_START_LO:
+        s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
+        s->target_buffer = s->phys_buf;
+        s->play_pos = 0;
+        s->last_free = 0;
+        break;
+
+    case MP_AUDIO_TX_THRESHOLD:
+        s->threshold = (value + 1) * 4;
+        break;
+
+    case MP_AUDIO_TX_START_HI:
+        s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
+        s->target_buffer = s->phys_buf;
+        s->play_pos = 0;
+        s->last_free = 0;
+        break;
+    }
+}
+
+static void mv88w8618_audio_reset(DeviceState *d)
+{
+    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state,
+                                           sysbus_from_qdev(d));
+
+    s->playback_mode = 0;
+    s->status = 0;
+    s->irq_enable = 0;
+    s->clock_div = 0;
+    s->threshold = 0;
+    s->phys_buf = 0;
+}
+
+static CPUReadMemoryFunc * const mv88w8618_audio_readfn[] = {
+    mv88w8618_audio_read,
+    mv88w8618_audio_read,
+    mv88w8618_audio_read
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_audio_writefn[] = {
+    mv88w8618_audio_write,
+    mv88w8618_audio_write,
+    mv88w8618_audio_write
+};
+
+static int mv88w8618_audio_init(SysBusDevice *dev)
+{
+    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
+
+    iomemtype = cpu_register_io_memory(mv88w8618_audio_readfn,
+                                       mv88w8618_audio_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_AUDIO_SIZE, iomemtype);
+
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_audio_vmsd = {
+    .name = "mv88w8618_audio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
+        VMSTATE_UINT32(status, mv88w8618_audio_state),
+        VMSTATE_UINT32(irq_enable, mv88w8618_audio_state),
+        VMSTATE_UINT32(phys_buf, mv88w8618_audio_state),
+        VMSTATE_UINT32(target_buffer, mv88w8618_audio_state),
+        VMSTATE_UINT32(threshold, mv88w8618_audio_state),
+        VMSTATE_UINT32(play_pos, mv88w8618_audio_state),
+        VMSTATE_UINT32(last_free, mv88w8618_audio_state),
+        VMSTATE_UINT32(clock_div, mv88w8618_audio_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo mv88w8618_audio_info = {
+    .init = mv88w8618_audio_init,
+    .qdev.name  = "mv88w8618_audio",
+    .qdev.size  = sizeof(mv88w8618_audio_state),
+    .qdev.reset = mv88w8618_audio_reset,
+    .qdev.vmsd  = &mv88w8618_audio_vmsd,
+    .qdev.props = (Property[]) {
+        {
+            .name   = "wm8750",
+            .info   = &qdev_prop_ptr,
+            .offset = offsetof(mv88w8618_audio_state, wm),
+        },
+        {/* end of list */}
+    }
+};
+
+static void mv88w8618_register_devices(void)
+{
+    sysbus_register_withprop(&mv88w8618_audio_info);
+}
+
+device_init(mv88w8618_register_devices)
diff --git a/qemu-0.15.x/hw/max111x.c b/qemu-0.15.x/hw/max111x.c
new file mode 100644
index 0000000..70cd1af
--- /dev/null
+++ b/qemu-0.15.x/hw/max111x.c
@@ -0,0 +1,173 @@
+/*
+ * Maxim MAX1110/1111 ADC chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPLv2.
+ */
+
+#include "ssi.h"
+
+typedef struct {
+    SSISlave ssidev;
+    qemu_irq interrupt;
+    uint8_t tb1, rb2, rb3;
+    int cycle;
+
+    uint8_t input[8];
+    int inputs, com;
+} MAX111xState;
+
+/* Control-byte bitfields */
+#define CB_PD0		(1 << 0)
+#define CB_PD1		(1 << 1)
+#define CB_SGL		(1 << 2)
+#define CB_UNI		(1 << 3)
+#define CB_SEL0		(1 << 4)
+#define CB_SEL1		(1 << 5)
+#define CB_SEL2		(1 << 6)
+#define CB_START	(1 << 7)
+
+#define CHANNEL_NUM(v, b0, b1, b2)	\
+			((((v) >> (2 + (b0))) & 4) |	\
+			 (((v) >> (3 + (b1))) & 2) |	\
+			 (((v) >> (4 + (b2))) & 1))
+
+static uint32_t max111x_read(MAX111xState *s)
+{
+    if (!s->tb1)
+        return 0;
+
+    switch (s->cycle ++) {
+    case 1:
+        return s->rb2;
+    case 2:
+        return s->rb3;
+    }
+
+    return 0;
+}
+
+/* Interpret a control-byte */
+static void max111x_write(MAX111xState *s, uint32_t value)
+{
+    int measure, chan;
+
+    /* Ignore the value if START bit is zero */
+    if (!(value & CB_START))
+        return;
+
+    s->cycle = 0;
+
+    if (!(value & CB_PD1)) {
+        s->tb1 = 0;
+        return;
+    }
+
+    s->tb1 = value;
+
+    if (s->inputs == 8)
+        chan = CHANNEL_NUM(value, 1, 0, 2);
+    else
+        chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
+
+    if (value & CB_SGL)
+        measure = s->input[chan] - s->com;
+    else
+        measure = s->input[chan] - s->input[chan ^ 1];
+
+    if (!(value & CB_UNI))
+        measure ^= 0x80;
+
+    s->rb2 = (measure >> 2) & 0x3f;
+    s->rb3 = (measure << 6) & 0xc0;
+
+    /* FIXME: When should the IRQ be lowered?  */
+    qemu_irq_raise(s->interrupt);
+}
+
+static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+    max111x_write(s, value);
+    return max111x_read(s);
+}
+
+static const VMStateDescription vmstate_max111x = {
+    .name = "max111x",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(tb1, MAX111xState),
+        VMSTATE_UINT8(rb2, MAX111xState),
+        VMSTATE_UINT8(rb3, MAX111xState),
+        VMSTATE_INT32_EQUAL(inputs, MAX111xState),
+        VMSTATE_INT32(com, MAX111xState),
+        VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
+                                   vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int max111x_init(SSISlave *dev, int inputs)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+
+    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+
+    s->inputs = inputs;
+    /* TODO: add a user interface for setting these */
+    s->input[0] = 0xf0;
+    s->input[1] = 0xe0;
+    s->input[2] = 0xd0;
+    s->input[3] = 0xc0;
+    s->input[4] = 0xb0;
+    s->input[5] = 0xa0;
+    s->input[6] = 0x90;
+    s->input[7] = 0x80;
+    s->com = 0;
+
+    vmstate_register(&dev->qdev, -1, &vmstate_max111x, s);
+    return 0;
+}
+
+static int max1110_init(SSISlave *dev)
+{
+    return max111x_init(dev, 8);
+}
+
+static int max1111_init(SSISlave *dev)
+{
+    return max111x_init(dev, 4);
+}
+
+void max111x_set_input(DeviceState *dev, int line, uint8_t value)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev));
+    assert(line >= 0 && line < s->inputs);
+    s->input[line] = value;
+}
+
+static SSISlaveInfo max1110_info = {
+    .qdev.name = "max1110",
+    .qdev.size = sizeof(MAX111xState),
+    .init = max1110_init,
+    .transfer = max111x_transfer
+};
+
+static SSISlaveInfo max1111_info = {
+    .qdev.name = "max1111",
+    .qdev.size = sizeof(MAX111xState),
+    .init = max1111_init,
+    .transfer = max111x_transfer
+};
+
+static void max111x_register_devices(void)
+{
+    ssi_register_slave(&max1110_info);
+    ssi_register_slave(&max1111_info);
+}
+
+device_init(max111x_register_devices)
diff --git a/qemu-0.15.x/hw/max7310.c b/qemu-0.15.x/hw/max7310.c
new file mode 100644
index 0000000..c1bdb2e
--- /dev/null
+++ b/qemu-0.15.x/hw/max7310.c
@@ -0,0 +1,204 @@
+/*
+ * MAX7310 8-port GPIO expansion chip.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "i2c.h"
+
+typedef struct {
+    i2c_slave i2c;
+    int i2c_command_byte;
+    int len;
+
+    uint8_t level;
+    uint8_t direction;
+    uint8_t polarity;
+    uint8_t status;
+    uint8_t command;
+    qemu_irq handler[8];
+    qemu_irq *gpio_in;
+} MAX7310State;
+
+static void max7310_reset(DeviceState *dev)
+{
+    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE_FROM_QDEV(dev));
+    s->level &= s->direction;
+    s->direction = 0xff;
+    s->polarity = 0xf0;
+    s->status = 0x01;
+    s->command = 0x00;
+}
+
+static int max7310_rx(i2c_slave *i2c)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+
+    switch (s->command) {
+    case 0x00:	/* Input port */
+        return s->level ^ s->polarity;
+        break;
+
+    case 0x01:	/* Output port */
+        return s->level & ~s->direction;
+        break;
+
+    case 0x02:	/* Polarity inversion */
+        return s->polarity;
+
+    case 0x03:	/* Configuration */
+        return s->direction;
+
+    case 0x04:	/* Timeout */
+        return s->status;
+        break;
+
+    case 0xff:	/* Reserved */
+        return 0xff;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        break;
+    }
+    return 0xff;
+}
+
+static int max7310_tx(i2c_slave *i2c, uint8_t data)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+    uint8_t diff;
+    int line;
+
+    if (s->len ++ > 1) {
+#ifdef VERBOSE
+        printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        return 1;
+    }
+
+    if (s->i2c_command_byte) {
+        s->command = data;
+        s->i2c_command_byte = 0;
+        return 0;
+    }
+
+    switch (s->command) {
+    case 0x01:	/* Output port */
+        for (diff = (data ^ s->level) & ~s->direction; diff;
+                        diff &= ~(1 << line)) {
+            line = ffs(diff) - 1;
+            if (s->handler[line])
+                qemu_set_irq(s->handler[line], (data >> line) & 1);
+        }
+        s->level = (s->level & s->direction) | (data & ~s->direction);
+        break;
+
+    case 0x02:	/* Polarity inversion */
+        s->polarity = data;
+        break;
+
+    case 0x03:	/* Configuration */
+        s->level &= ~(s->direction ^ data);
+        s->direction = data;
+        break;
+
+    case 0x04:	/* Timeout */
+        s->status = data;
+        break;
+
+    case 0x00:	/* Input port - ignore writes */
+	break;
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        return 1;
+    }
+
+    return 0;
+}
+
+static void max7310_event(i2c_slave *i2c, enum i2c_event event)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+    s->len = 0;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_command_byte = 1;
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->len == 1)
+            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+static const VMStateDescription vmstate_max7310 = {
+    .name = "max7310",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(i2c_command_byte, MAX7310State),
+        VMSTATE_INT32(len, MAX7310State),
+        VMSTATE_UINT8(level, MAX7310State),
+        VMSTATE_UINT8(direction, MAX7310State),
+        VMSTATE_UINT8(polarity, MAX7310State),
+        VMSTATE_UINT8(status, MAX7310State),
+        VMSTATE_UINT8(command, MAX7310State),
+        VMSTATE_I2C_SLAVE(i2c, MAX7310State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void max7310_gpio_set(void *opaque, int line, int level)
+{
+    MAX7310State *s = (MAX7310State *) opaque;
+    if (line >= ARRAY_SIZE(s->handler) || line  < 0)
+        hw_error("bad GPIO line");
+
+    if (level)
+        s->level |= s->direction & (1 << line);
+    else
+        s->level &= ~(s->direction & (1 << line));
+}
+
+/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
+ * but also accepts sequences that are not SMBus so return an I2C device.  */
+static int max7310_init(i2c_slave *i2c)
+{
+    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
+
+    qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
+    qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
+
+    return 0;
+}
+
+static I2CSlaveInfo max7310_info = {
+    .qdev.name = "max7310",
+    .qdev.size = sizeof(MAX7310State),
+    .qdev.vmsd = &vmstate_max7310,
+    .qdev.reset = max7310_reset,
+    .init = max7310_init,
+    .event = max7310_event,
+    .recv = max7310_rx,
+    .send = max7310_tx
+};
+
+static void max7310_register_devices(void)
+{
+    i2c_register_slave(&max7310_info);
+}
+
+device_init(max7310_register_devices)
diff --git a/qemu-0.15.x/hw/mc146818rtc.c b/qemu-0.15.x/hw/mc146818rtc.c
new file mode 100644
index 0000000..feb3b25
--- /dev/null
+++ b/qemu-0.15.x/hw/mc146818rtc.c
@@ -0,0 +1,677 @@
+/*
+ * 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 "hw.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "pc.h"
+#include "apic.h"
+#include "isa.h"
+#include "mc146818rtc.h"
+
+//#define DEBUG_CMOS
+//#define DEBUG_COALESCED
+
+#ifdef DEBUG_CMOS
+# define CMOS_DPRINTF(format, ...)      printf(format, ## __VA_ARGS__)
+#else
+# define CMOS_DPRINTF(format, ...)      do { } while (0)
+#endif
+
+#ifdef DEBUG_COALESCED
+# define DPRINTF_C(format, ...)      printf(format, ## __VA_ARGS__)
+#else
+# define DPRINTF_C(format, ...)      do { } while (0)
+#endif
+
+#define RTC_REINJECT_ON_ACK_COUNT 20
+
+#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
+#define REG_B_SQWE 0x08
+#define REG_B_DM   0x04
+#define REG_B_24H  0x02
+
+#define REG_C_UF   0x10
+#define REG_C_IRQF 0x80
+#define REG_C_PF   0x40
+#define REG_C_AF   0x20
+
+typedef struct RTCState {
+    ISADevice dev;
+    uint8_t cmos_data[128];
+    uint8_t cmos_index;
+    struct tm current_tm;
+    int32_t base_year;
+    qemu_irq irq;
+    qemu_irq sqw_irq;
+    int it_shift;
+    /* periodic timer */
+    QEMUTimer *periodic_timer;
+    int64_t next_periodic_time;
+    /* second update */
+    int64_t next_second_time;
+    uint16_t irq_reinject_on_ack_count;
+    uint32_t irq_coalesced;
+    uint32_t period;
+    QEMUTimer *coalesced_timer;
+    QEMUTimer *second_timer;
+    QEMUTimer *second_timer2;
+    Notifier clock_reset_notifier;
+} RTCState;
+
+static void rtc_set_time(RTCState *s);
+static void rtc_copy_date(RTCState *s);
+
+#ifdef TARGET_I386
+static void rtc_coalesced_timer_update(RTCState *s)
+{
+    if (s->irq_coalesced == 0) {
+        qemu_del_timer(s->coalesced_timer);
+    } else {
+        /* divide each RTC interval to 2 - 8 smaller intervals */
+        int c = MIN(s->irq_coalesced, 7) + 1; 
+        int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
+            muldiv64(s->period / c, get_ticks_per_sec(), 32768);
+        qemu_mod_timer(s->coalesced_timer, next_clock);
+    }
+}
+
+static void rtc_coalesced_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    if (s->irq_coalesced != 0) {
+        apic_reset_irq_delivered();
+        s->cmos_data[RTC_REG_C] |= 0xc0;
+        DPRINTF_C("cmos: injecting from timer\n");
+        qemu_irq_raise(s->irq);
+        if (apic_get_irq_delivered()) {
+            s->irq_coalesced--;
+            DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
+                      s->irq_coalesced);
+        }
+    }
+
+    rtc_coalesced_timer_update(s);
+}
+#endif
+
+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)
+            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
+        if (period_code <= 2)
+            period_code += 7;
+        /* period in 32 Khz cycles */
+        period = 1 << (period_code - 1);
+#ifdef TARGET_I386
+        if (period != s->period) {
+            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
+            DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
+        }
+        s->period = period;
+#endif
+        /* compute 32 khz clock */
+        cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec());
+        next_irq_clock = (cur_clock & ~(period - 1)) + period;
+        s->next_periodic_time =
+            muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1;
+        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
+    } else {
+#ifdef TARGET_I386
+        s->irq_coalesced = 0;
+#endif
+        qemu_del_timer(s->periodic_timer);
+    }
+}
+
+static void rtc_periodic_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    rtc_timer_update(s, s->next_periodic_time);
+    if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
+        s->cmos_data[RTC_REG_C] |= 0xc0;
+#ifdef TARGET_I386
+        if(rtc_td_hack) {
+            if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
+                s->irq_reinject_on_ack_count = 0;		
+            apic_reset_irq_delivered();
+            qemu_irq_raise(s->irq);
+            if (!apic_get_irq_delivered()) {
+                s->irq_coalesced++;
+                rtc_coalesced_timer_update(s);
+                DPRINTF_C("cmos: coalesced irqs increased to %d\n",
+                          s->irq_coalesced);
+            }
+        } else
+#endif
+        qemu_irq_raise(s->irq);
+    }
+    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
+        /* Not square wave at all but we don't want 2048Hz interrupts!
+           Must be seen as a pulse.  */
+        qemu_irq_raise(s->sqw_irq);
+    }
+}
+
+static 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 {
+        CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
+                     s->cmos_index, data);
+        switch(s->cmos_index) {
+        case RTC_SECONDS_ALARM:
+        case RTC_MINUTES_ALARM:
+        case RTC_HOURS_ALARM:
+            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)) {
+                rtc_set_time(s);
+            }
+            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);
+            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            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) {
+                    rtc_set_time(s);
+                }
+            }
+            if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
+                !(data & REG_B_SET)) {
+                /* If the time format has changed and not in set mode,
+                   update the registers immediately. */
+                s->cmos_data[RTC_REG_B] = data;
+                rtc_copy_date(s);
+            } else {
+                s->cmos_data[RTC_REG_B] = data;
+            }
+            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            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 rtc_to_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
+        return a;
+    } else {
+        return ((a / 10) << 4) | (a % 10);
+    }
+}
+
+static inline int rtc_from_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
+        return a;
+    } else {
+        return ((a >> 4) * 10) + (a & 0x0f);
+    }
+}
+
+static void rtc_set_time(RTCState *s)
+{
+    struct tm *tm = &s->current_tm;
+
+    tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
+    tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
+    tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
+        (s->cmos_data[RTC_HOURS] & 0x80)) {
+        tm->tm_hour += 12;
+    }
+    tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
+    tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
+    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
+    tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
+
+    rtc_change_mon_event(tm);
+}
+
+static void rtc_copy_date(RTCState *s)
+{
+    const struct tm *tm = &s->current_tm;
+    int year;
+
+    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
+    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
+    if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
+        /* 24 hour format */
+        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
+    } else {
+        /* 12 hour format */
+        s->cmos_data[RTC_HOURS] = rtc_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] = rtc_to_bcd(s, tm->tm_wday + 1);
+    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
+    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
+    year = (tm->tm_year - s->base_year) % 100;
+    if (year < 0)
+        year += 100;
+    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
+}
+
+/* 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 += get_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 = (get_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 ||
+             rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
+            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
+             rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
+            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
+             rtc_from_bcd(s, 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 */
+    s->cmos_data[RTC_REG_C] |= REG_C_UF;
+    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
+        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+        qemu_irq_raise(s->irq);
+    }
+
+    /* clear update in progress bit */
+    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+
+    s->next_second_time += get_ticks_per_sec();
+    qemu_mod_timer(s->second_timer, s->next_second_time);
+}
+
+static 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:
+        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);
+#ifdef TARGET_I386
+            if(s->irq_coalesced &&
+                    s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
+                s->irq_reinject_on_ack_count++;
+                apic_reset_irq_delivered();
+                DPRINTF_C("cmos: injecting on ack\n");
+                qemu_irq_raise(s->irq);
+                if (apic_get_irq_delivered()) {
+                    s->irq_coalesced--;
+                    DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
+                              s->irq_coalesced);
+                }
+                break;
+            }
+#endif
+
+            s->cmos_data[RTC_REG_C] = 0x00;
+            break;
+        default:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        }
+        CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
+                     s->cmos_index, ret);
+        return ret;
+    }
+}
+
+void rtc_set_memory(ISADevice *dev, int addr, int val)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    if (addr >= 0 && addr <= 127)
+        s->cmos_data[addr] = val;
+}
+
+void rtc_set_date(ISADevice *dev, const struct tm *tm)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    s->current_tm = *tm;
+    rtc_copy_date(s);
+}
+
+/* PC cmos mappings */
+#define REG_IBM_CENTURY_BYTE        0x32
+#define REG_IBM_PS2_CENTURY_BYTE    0x37
+
+static void rtc_set_date_from_host(ISADevice *dev)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    struct tm tm;
+    int val;
+
+    /* set the CMOS date */
+    qemu_get_timedate(&tm, 0);
+    rtc_set_date(dev, &tm);
+
+    val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
+    rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
+    rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val);
+}
+
+static int rtc_post_load(void *opaque, int version_id)
+{
+#ifdef TARGET_I386
+    RTCState *s = opaque;
+
+    if (version_id >= 2) {
+        if (rtc_td_hack) {
+            rtc_coalesced_timer_update(s);
+        }
+    }
+#endif
+    return 0;
+}
+
+static const VMStateDescription vmstate_rtc = {
+    .name = "mc146818rtc",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = rtc_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_BUFFER(cmos_data, RTCState),
+        VMSTATE_UINT8(cmos_index, RTCState),
+        VMSTATE_INT32(current_tm.tm_sec, RTCState),
+        VMSTATE_INT32(current_tm.tm_min, RTCState),
+        VMSTATE_INT32(current_tm.tm_hour, RTCState),
+        VMSTATE_INT32(current_tm.tm_wday, RTCState),
+        VMSTATE_INT32(current_tm.tm_mday, RTCState),
+        VMSTATE_INT32(current_tm.tm_mon, RTCState),
+        VMSTATE_INT32(current_tm.tm_year, RTCState),
+        VMSTATE_TIMER(periodic_timer, RTCState),
+        VMSTATE_INT64(next_periodic_time, RTCState),
+        VMSTATE_INT64(next_second_time, RTCState),
+        VMSTATE_TIMER(second_timer, RTCState),
+        VMSTATE_TIMER(second_timer2, RTCState),
+        VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
+        VMSTATE_UINT32_V(period, RTCState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtc_notify_clock_reset(Notifier *notifier, void *data)
+{
+    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
+    int64_t now = *(int64_t *)data;
+
+    rtc_set_date_from_host(&s->dev);
+    s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+    rtc_timer_update(s, now);
+#ifdef TARGET_I386
+    if (rtc_td_hack) {
+        rtc_coalesced_timer_update(s);
+    }
+#endif
+}
+
+static void rtc_reset(void *opaque)
+{
+    RTCState *s = opaque;
+
+    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
+    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
+
+    qemu_irq_lower(s->irq);
+
+#ifdef TARGET_I386
+    if (rtc_td_hack)
+	    s->irq_coalesced = 0;
+#endif
+}
+
+static int rtc_initfn(ISADevice *dev)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    int base = 0x70;
+
+    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;
+
+    rtc_set_date_from_host(dev);
+
+    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
+#ifdef TARGET_I386
+    if (rtc_td_hack)
+        s->coalesced_timer =
+            qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
+#endif
+    s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
+    s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
+
+    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
+    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
+
+    s->next_second_time =
+        qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+
+    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
+    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+    isa_init_ioport_range(dev, base, 2);
+
+    qdev_set_legacy_instance_id(&dev->qdev, base, 2);
+    qemu_register_reset(rtc_reset, s);
+    return 0;
+}
+
+ISADevice *rtc_init(int base_year, qemu_irq intercept_irq)
+{
+    ISADevice *dev;
+    RTCState *s;
+
+    dev = isa_create("mc146818rtc");
+    s = DO_UPCAST(RTCState, dev, dev);
+    qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
+    qdev_init_nofail(&dev->qdev);
+    if (intercept_irq) {
+        s->irq = intercept_irq;
+    } else {
+        isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
+    }
+    return dev;
+}
+
+static ISADeviceInfo mc146818rtc_info = {
+    .qdev.name     = "mc146818rtc",
+    .qdev.size     = sizeof(RTCState),
+    .qdev.no_user  = 1,
+    .qdev.vmsd     = &vmstate_rtc,
+    .init          = rtc_initfn,
+    .qdev.props    = (Property[]) {
+        DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void mc146818rtc_register(void)
+{
+    isa_qdev_register(&mc146818rtc_info);
+}
+device_init(mc146818rtc_register)
diff --git a/qemu-0.15.x/hw/mc146818rtc.h b/qemu-0.15.x/hw/mc146818rtc.h
new file mode 100644
index 0000000..575968c
--- /dev/null
+++ b/qemu-0.15.x/hw/mc146818rtc.h
@@ -0,0 +1,12 @@
+#ifndef MC146818RTC_H
+#define MC146818RTC_H
+
+#include "isa.h"
+
+#define RTC_ISA_IRQ 8
+
+ISADevice *rtc_init(int base_year, qemu_irq intercept_irq);
+void rtc_set_memory(ISADevice *dev, int addr, int val);
+void rtc_set_date(ISADevice *dev, const struct tm *tm);
+
+#endif /* !MC146818RTC_H */
diff --git a/qemu-0.15.x/hw/mcf.h b/qemu-0.15.x/hw/mcf.h
new file mode 100644
index 0000000..91f2821
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf.h
@@ -0,0 +1,21 @@
+#ifndef HW_MCF_H
+#define HW_MCF_H
+/* Motorola ColdFire device prototypes.  */
+
+/* mcf_uart.c */
+uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr);
+void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val);
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr);
+void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
+                      CharDriverState *chr);
+
+/* mcf_intc.c */
+qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env);
+
+/* mcf_fec.c */
+void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq);
+
+/* mcf5206.c */
+qemu_irq *mcf5206_init(uint32_t base, CPUState *env);
+
+#endif
diff --git a/qemu-0.15.x/hw/mcf5206.c b/qemu-0.15.x/hw/mcf5206.c
new file mode 100644
index 0000000..fce282d
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf5206.c
@@ -0,0 +1,541 @@
+/*
+ * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw.h"
+#include "mcf.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+
+/* General purpose timer module.  */
+typedef struct {
+    uint16_t tmr;
+    uint16_t trr;
+    uint16_t tcr;
+    uint16_t ter;
+    ptimer_state *timer;
+    qemu_irq irq;
+    int irq_state;
+} m5206_timer_state;
+
+#define TMR_RST 0x01
+#define TMR_CLK 0x06
+#define TMR_FRR 0x08
+#define TMR_ORI 0x10
+#define TMR_OM  0x20
+#define TMR_CE  0xc0
+
+#define TER_CAP 0x01
+#define TER_REF 0x02
+
+static void m5206_timer_update(m5206_timer_state *s)
+{
+    if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void m5206_timer_reset(m5206_timer_state *s)
+{
+    s->tmr = 0;
+    s->trr = 0;
+}
+
+static void m5206_timer_recalibrate(m5206_timer_state *s)
+{
+    int prescale;
+    int mode;
+
+    ptimer_stop(s->timer);
+
+    if ((s->tmr & TMR_RST) == 0)
+        return;
+
+    prescale = (s->tmr >> 8) + 1;
+    mode = (s->tmr >> 1) & 3;
+    if (mode == 2)
+        prescale *= 16;
+
+    if (mode == 3 || mode == 0)
+        hw_error("m5206_timer: mode %d not implemented\n", mode);
+    if ((s->tmr & TMR_FRR) == 0)
+        hw_error("m5206_timer: free running mode not implemented\n");
+
+    /* Assume 66MHz system clock.  */
+    ptimer_set_freq(s->timer, 66000000 / prescale);
+
+    ptimer_set_limit(s->timer, s->trr, 0);
+
+    ptimer_run(s->timer, 0);
+}
+
+static void m5206_timer_trigger(void *opaque)
+{
+    m5206_timer_state *s = (m5206_timer_state *)opaque;
+    s->ter |= TER_REF;
+    m5206_timer_update(s);
+}
+
+static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
+{
+    switch (addr) {
+    case 0:
+        return s->tmr;
+    case 4:
+        return s->trr;
+    case 8:
+        return s->tcr;
+    case 0xc:
+        return s->trr - ptimer_get_count(s->timer);
+    case 0x11:
+        return s->ter;
+    default:
+        return 0;
+    }
+}
+
+static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
+{
+    switch (addr) {
+    case 0:
+        if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
+            m5206_timer_reset(s);
+        }
+        s->tmr = val;
+        m5206_timer_recalibrate(s);
+        break;
+    case 4:
+        s->trr = val;
+        m5206_timer_recalibrate(s);
+        break;
+    case 8:
+        s->tcr = val;
+        break;
+    case 0xc:
+        ptimer_set_count(s->timer, val);
+        break;
+    case 0x11:
+        s->ter &= ~val;
+        break;
+    default:
+        break;
+    }
+    m5206_timer_update(s);
+}
+
+static m5206_timer_state *m5206_timer_init(qemu_irq irq)
+{
+    m5206_timer_state *s;
+    QEMUBH *bh;
+
+    s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
+    bh = qemu_bh_new(m5206_timer_trigger, s);
+    s->timer = ptimer_init(bh);
+    s->irq = irq;
+    m5206_timer_reset(s);
+    return s;
+}
+
+/* System Integration Module.  */
+
+typedef struct {
+    CPUState *env;
+    m5206_timer_state *timer[2];
+    void *uart[2];
+    uint8_t scr;
+    uint8_t icr[14];
+    uint16_t imr; /* 1 == interrupt is masked.  */
+    uint16_t ipr;
+    uint8_t rsr;
+    uint8_t swivr;
+    uint8_t par;
+    /* Include the UART vector registers here.  */
+    uint8_t uivr[2];
+} m5206_mbar_state;
+
+/* Interrupt controller.  */
+
+static int m5206_find_pending_irq(m5206_mbar_state *s)
+{
+    int level;
+    int vector;
+    uint16_t active;
+    int i;
+
+    level = 0;
+    vector = 0;
+    active = s->ipr & ~s->imr;
+    if (!active)
+        return 0;
+
+    for (i = 1; i < 14; i++) {
+        if (active & (1 << i)) {
+            if ((s->icr[i] & 0x1f) > level) {
+                level = s->icr[i] & 0x1f;
+                vector = i;
+            }
+        }
+    }
+
+    if (level < 4)
+        vector = 0;
+
+    return vector;
+}
+
+static void m5206_mbar_update(m5206_mbar_state *s)
+{
+    int irq;
+    int vector;
+    int level;
+
+    irq = m5206_find_pending_irq(s);
+    if (irq) {
+        int tmp;
+        tmp = s->icr[irq];
+        level = (tmp >> 2) & 7;
+        if (tmp & 0x80) {
+            /* Autovector.  */
+            vector = 24 + level;
+        } else {
+            switch (irq) {
+            case 8: /* SWT */
+                vector = s->swivr;
+                break;
+            case 12: /* UART1 */
+                vector = s->uivr[0];
+                break;
+            case 13: /* UART2 */
+                vector = s->uivr[1];
+                break;
+            default:
+                /* Unknown vector.  */
+                fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
+                vector = 0xf;
+                break;
+            }
+        }
+    } else {
+        level = 0;
+        vector = 0;
+    }
+    m68k_set_irq_level(s->env, level, vector);
+}
+
+static void m5206_mbar_set_irq(void *opaque, int irq, int level)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    if (level) {
+        s->ipr |= 1 << irq;
+    } else {
+        s->ipr &= ~(1 << irq);
+    }
+    m5206_mbar_update(s);
+}
+
+/* System Integration Module.  */
+
+static void m5206_mbar_reset(m5206_mbar_state *s)
+{
+    s->scr = 0xc0;
+    s->icr[1] = 0x04;
+    s->icr[2] = 0x08;
+    s->icr[3] = 0x0c;
+    s->icr[4] = 0x10;
+    s->icr[5] = 0x14;
+    s->icr[6] = 0x18;
+    s->icr[7] = 0x1c;
+    s->icr[8] = 0x1c;
+    s->icr[9] = 0x80;
+    s->icr[10] = 0x80;
+    s->icr[11] = 0x80;
+    s->icr[12] = 0x00;
+    s->icr[13] = 0x00;
+    s->imr = 0x3ffe;
+    s->rsr = 0x80;
+    s->swivr = 0x0f;
+    s->par = 0;
+}
+
+static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
+{
+    if (offset >= 0x100 && offset < 0x120) {
+        return m5206_timer_read(s->timer[0], offset - 0x100);
+    } else if (offset >= 0x120 && offset < 0x140) {
+        return m5206_timer_read(s->timer[1], offset - 0x120);
+    } else if (offset >= 0x140 && offset < 0x160) {
+        return mcf_uart_read(s->uart[0], offset - 0x140);
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        return mcf_uart_read(s->uart[1], offset - 0x180);
+    }
+    switch (offset) {
+    case 0x03: return s->scr;
+    case 0x14 ... 0x20: return s->icr[offset - 0x13];
+    case 0x36: return s->imr;
+    case 0x3a: return s->ipr;
+    case 0x40: return s->rsr;
+    case 0x41: return 0;
+    case 0x42: return s->swivr;
+    case 0x50:
+        /* DRAM mask register.  */
+        /* FIXME: currently hardcoded to 128Mb.  */
+        {
+            uint32_t mask = ~0;
+            while (mask > ram_size)
+                mask >>= 1;
+            return mask & 0x0ffe0000;
+        }
+    case 0x5c: return 1; /* DRAM bank 1 empty.  */
+    case 0xcb: return s->par;
+    case 0x170: return s->uivr[0];
+    case 0x1b0: return s->uivr[1];
+    }
+    hw_error("Bad MBAR read offset 0x%x", (int)offset);
+    return 0;
+}
+
+static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
+                             uint32_t value)
+{
+    if (offset >= 0x100 && offset < 0x120) {
+        m5206_timer_write(s->timer[0], offset - 0x100, value);
+        return;
+    } else if (offset >= 0x120 && offset < 0x140) {
+        m5206_timer_write(s->timer[1], offset - 0x120, value);
+        return;
+    } else if (offset >= 0x140 && offset < 0x160) {
+        mcf_uart_write(s->uart[0], offset - 0x140, value);
+        return;
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        mcf_uart_write(s->uart[1], offset - 0x180, value);
+        return;
+    }
+    switch (offset) {
+    case 0x03:
+        s->scr = value;
+        break;
+    case 0x14 ... 0x20:
+        s->icr[offset - 0x13] = value;
+        m5206_mbar_update(s);
+        break;
+    case 0x36:
+        s->imr = value;
+        m5206_mbar_update(s);
+        break;
+    case 0x40:
+        s->rsr &= ~value;
+        break;
+    case 0x41:
+        /* TODO: implement watchdog.  */
+        break;
+    case 0x42:
+        s->swivr = value;
+        break;
+    case 0xcb:
+        s->par = value;
+        break;
+    case 0x170:
+        s->uivr[0] = value;
+        break;
+    case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
+        /* Not implemented: UART Output port bits.  */
+        break;
+    case 0x1b0:
+        s->uivr[1] = value;
+        break;
+    default:
+        hw_error("Bad MBAR write offset 0x%x", (int)offset);
+        break;
+    }
+}
+
+/* Internal peripherals use a variety of register widths.
+   This lookup table allows a single routine to handle all of them.  */
+static const int m5206_mbar_width[] =
+{
+  /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
+  /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
+  /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
+  /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
+  /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
+  /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+  /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+  /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+};
+
+static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
+static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
+
+static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR read offset 0x%x", (int)offset);
+    }
+    if (m5206_mbar_width[offset >> 2] > 1) {
+        uint16_t val;
+        val = m5206_mbar_readw(opaque, offset & ~1);
+        if ((offset & 1) == 0) {
+            val >>= 8;
+        }
+        return val & 0xff;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR read offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 2) {
+        uint32_t val;
+        val = m5206_mbar_readl(opaque, offset & ~3);
+        if ((offset & 3) == 0)
+            val >>= 16;
+        return val & 0xffff;
+    } else if (width < 2) {
+        uint16_t val;
+        val = m5206_mbar_readb(opaque, offset) << 8;
+        val |= m5206_mbar_readb(opaque, offset + 1);
+        return val;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR read offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width < 4) {
+        uint32_t val;
+        val = m5206_mbar_readw(opaque, offset) << 16;
+        val |= m5206_mbar_readw(opaque, offset + 2);
+        return val;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
+                              uint32_t value);
+static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
+                              uint32_t value);
+
+static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 1) {
+        uint32_t tmp;
+        tmp = m5206_mbar_readw(opaque, offset & ~1);
+        if (offset & 1) {
+            tmp = (tmp & 0xff00) | value;
+        } else {
+            tmp = (tmp & 0x00ff) | (value << 8);
+        }
+        m5206_mbar_writew(opaque, offset & ~1, tmp);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 2) {
+        uint32_t tmp;
+        tmp = m5206_mbar_readl(opaque, offset & ~3);
+        if (offset & 3) {
+            tmp = (tmp & 0xffff0000) | value;
+        } else {
+            tmp = (tmp & 0x0000ffff) | (value << 16);
+        }
+        m5206_mbar_writel(opaque, offset & ~3, tmp);
+        return;
+    } else if (width < 2) {
+        m5206_mbar_writeb(opaque, offset, value >> 8);
+        m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        hw_error("Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width < 4) {
+        m5206_mbar_writew(opaque, offset, value >> 16);
+        m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static CPUReadMemoryFunc * const m5206_mbar_readfn[] = {
+   m5206_mbar_readb,
+   m5206_mbar_readw,
+   m5206_mbar_readl
+};
+
+static CPUWriteMemoryFunc * const m5206_mbar_writefn[] = {
+   m5206_mbar_writeb,
+   m5206_mbar_writew,
+   m5206_mbar_writel
+};
+
+qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
+{
+    m5206_mbar_state *s;
+    qemu_irq *pic;
+    int iomemtype;
+
+    s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
+    iomemtype = cpu_register_io_memory(m5206_mbar_readfn,
+                                       m5206_mbar_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+    pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
+    s->timer[0] = m5206_timer_init(pic[9]);
+    s->timer[1] = m5206_timer_init(pic[10]);
+    s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
+    s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
+    s->env = env;
+
+    m5206_mbar_reset(s);
+    return pic;
+}
diff --git a/qemu-0.15.x/hw/mcf5208.c b/qemu-0.15.x/hw/mcf5208.c
new file mode 100644
index 0000000..78fbc5f
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf5208.c
@@ -0,0 +1,306 @@
+/*
+ * Motorola ColdFire MCF5208 SoC emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw.h"
+#include "mcf.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "net.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+
+#define SYS_FREQ 66000000
+
+#define PCSR_EN         0x0001
+#define PCSR_RLD        0x0002
+#define PCSR_PIF        0x0004
+#define PCSR_PIE        0x0008
+#define PCSR_OVW        0x0010
+#define PCSR_DBG        0x0020
+#define PCSR_DOZE       0x0040
+#define PCSR_PRE_SHIFT  8
+#define PCSR_PRE_MASK   0x0f00
+
+typedef struct {
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint16_t pcsr;
+    uint16_t pmr;
+    uint16_t pcntr;
+} m5208_timer_state;
+
+static void m5208_timer_update(m5208_timer_state *s)
+{
+    if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void m5208_timer_write(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    int prescale;
+    int limit;
+    switch (offset) {
+    case 0:
+        /* The PIF bit is set-to-clear.  */
+        if (value & PCSR_PIF) {
+            s->pcsr &= ~PCSR_PIF;
+            value &= ~PCSR_PIF;
+        }
+        /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
+        if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
+            s->pcsr = value;
+            m5208_timer_update(s);
+            return;
+        }
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_stop(s->timer);
+
+        s->pcsr = value;
+
+        prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
+        ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
+        if (s->pcsr & PCSR_RLD)
+            limit = s->pmr;
+        else
+            limit = 0xffff;
+        ptimer_set_limit(s->timer, limit, 0);
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_run(s->timer, 0);
+        break;
+    case 2:
+        s->pmr = value;
+        s->pcsr &= ~PCSR_PIF;
+        if ((s->pcsr & PCSR_RLD) == 0) {
+            if (s->pcsr & PCSR_OVW)
+                ptimer_set_count(s->timer, value);
+        } else {
+            ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
+        }
+        break;
+    case 4:
+        break;
+    default:
+        hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+    m5208_timer_update(s);
+}
+
+static void m5208_timer_trigger(void *opaque)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    s->pcsr |= PCSR_PIF;
+    m5208_timer_update(s);
+}
+
+static uint32_t m5208_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    switch (addr) {
+    case 0:
+        return s->pcsr;
+    case 2:
+        return s->pmr;
+    case 4:
+        return ptimer_get_count(s->timer);
+    default:
+        hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static CPUReadMemoryFunc * const m5208_timer_readfn[] = {
+   m5208_timer_read,
+   m5208_timer_read,
+   m5208_timer_read
+};
+
+static CPUWriteMemoryFunc * const m5208_timer_writefn[] = {
+   m5208_timer_write,
+   m5208_timer_write,
+   m5208_timer_write
+};
+
+static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
+{
+    switch (addr) {
+    case 0x110: /* SDCS0 */
+        {
+            int n;
+            for (n = 0; n < 32; n++) {
+                if (ram_size < (2u << n))
+                    break;
+            }
+            return (n - 1)  | 0x40000000;
+        }
+    case 0x114: /* SDCS1 */
+        return 0;
+
+    default:
+        hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void m5208_sys_write(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
+}
+
+static CPUReadMemoryFunc * const m5208_sys_readfn[] = {
+   m5208_sys_read,
+   m5208_sys_read,
+   m5208_sys_read
+};
+
+static CPUWriteMemoryFunc * const m5208_sys_writefn[] = {
+   m5208_sys_write,
+   m5208_sys_write,
+   m5208_sys_write
+};
+
+static void mcf5208_sys_init(qemu_irq *pic)
+{
+    int iomemtype;
+    m5208_timer_state *s;
+    QEMUBH *bh;
+    int i;
+
+    iomemtype = cpu_register_io_memory(m5208_sys_readfn,
+                                       m5208_sys_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
+    /* SDRAMC.  */
+    cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
+    /* Timers.  */
+    for (i = 0; i < 2; i++) {
+        s = (m5208_timer_state *)qemu_mallocz(sizeof(m5208_timer_state));
+        bh = qemu_bh_new(m5208_timer_trigger, s);
+        s->timer = ptimer_init(bh);
+        iomemtype = cpu_register_io_memory(m5208_timer_readfn,
+                                           m5208_timer_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+        cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
+                                     iomemtype);
+        s->irq = pic[4 + i];
+    }
+}
+
+static void mcf5208evb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    target_phys_addr_t entry;
+    qemu_irq *pic;
+
+    if (!cpu_model)
+        cpu_model = "m5208";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find m68k CPU definition\n");
+        exit(1);
+    }
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: Configure BARs.  */
+
+    /* DRAM at 0x40000000 */
+    cpu_register_physical_memory(0x40000000, ram_size,
+        qemu_ram_alloc(NULL, "mcf5208.ram", ram_size) | IO_MEM_RAM);
+
+    /* Internal SRAM.  */
+    cpu_register_physical_memory(0x80000000, 16384,
+        qemu_ram_alloc(NULL, "mcf5208.sram", 16384) | IO_MEM_RAM);
+
+    /* Internal peripherals.  */
+    pic = mcf_intc_init(0xfc048000, env);
+
+    mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]);
+    mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
+    mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
+
+    mcf5208_sys_init(pic);
+
+    if (nb_nics > 1) {
+        fprintf(stderr, "Too many NICs\n");
+        exit(1);
+    }
+    if (nd_table[0].vlan)
+        mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36);
+
+    /*  0xfc000000 SCM.  */
+    /*  0xfc004000 XBS.  */
+    /*  0xfc008000 FlexBus CS.  */
+    /* 0xfc030000 FEC.  */
+    /*  0xfc040000 SCM + Power management.  */
+    /*  0xfc044000 eDMA.  */
+    /* 0xfc048000 INTC.  */
+    /*  0xfc058000 I2C.  */
+    /*  0xfc05c000 QSPI.  */
+    /* 0xfc060000 UART0.  */
+    /* 0xfc064000 UART0.  */
+    /* 0xfc068000 UART0.  */
+    /*  0xfc070000 DMA timers.  */
+    /* 0xfc080000 PIT0.  */
+    /* 0xfc084000 PIT1.  */
+    /*  0xfc088000 EPORT.  */
+    /*  0xfc08c000 Watchdog.  */
+    /*  0xfc090000 clock module.  */
+    /*  0xfc0a0000 CCM + reset.  */
+    /*  0xfc0a4000 GPIO.  */
+    /* 0xfc0a8000 SDRAM controller.  */
+
+    /* Load kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                           NULL, NULL, 1, ELF_MACHINE, 0);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image_targphys(kernel_filename, 0x40000000,
+                                          ram_size);
+        entry = 0x40000000;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+static QEMUMachine mcf5208evb_machine = {
+    .name = "mcf5208evb",
+    .desc = "MCF5206EVB",
+    .init = mcf5208evb_init,
+    .is_default = 1,
+};
+
+static void mcf5208evb_machine_init(void)
+{
+    qemu_register_machine(&mcf5208evb_machine);
+}
+
+machine_init(mcf5208evb_machine_init);
diff --git a/qemu-0.15.x/hw/mcf_fec.c b/qemu-0.15.x/hw/mcf_fec.c
new file mode 100644
index 0000000..748eb590
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf_fec.c
@@ -0,0 +1,481 @@
+/*
+ * ColdFire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw.h"
+#include "net.h"
+#include "mcf.h"
+/* For crc32 */
+#include <zlib.h>
+
+//#define DEBUG_FEC 1
+
+#ifdef DEBUG_FEC
+#define DPRINTF(fmt, ...) \
+do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+    qemu_irq *irq;
+    int mmio_index;
+    NICState *nic;
+    NICConf conf;
+    uint32_t irq_state;
+    uint32_t eir;
+    uint32_t eimr;
+    int rx_enabled;
+    uint32_t rx_descriptor;
+    uint32_t tx_descriptor;
+    uint32_t ecr;
+    uint32_t mmfr;
+    uint32_t mscr;
+    uint32_t rcr;
+    uint32_t tcr;
+    uint32_t tfwr;
+    uint32_t rfsr;
+    uint32_t erdsr;
+    uint32_t etdsr;
+    uint32_t emrbr;
+} mcf_fec_state;
+
+#define FEC_INT_HB   0x80000000
+#define FEC_INT_BABR 0x40000000
+#define FEC_INT_BABT 0x20000000
+#define FEC_INT_GRA  0x10000000
+#define FEC_INT_TXF  0x08000000
+#define FEC_INT_TXB  0x04000000
+#define FEC_INT_RXF  0x02000000
+#define FEC_INT_RXB  0x01000000
+#define FEC_INT_MII  0x00800000
+#define FEC_INT_EB   0x00400000
+#define FEC_INT_LC   0x00200000
+#define FEC_INT_RL   0x00100000
+#define FEC_INT_UN   0x00080000
+
+#define FEC_EN      2
+#define FEC_RESET   1
+
+/* Map interrupt flags onto IRQ lines.  */
+#define FEC_NUM_IRQ 13
+static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
+    FEC_INT_TXF,
+    FEC_INT_TXB,
+    FEC_INT_UN,
+    FEC_INT_RL,
+    FEC_INT_RXF,
+    FEC_INT_RXB,
+    FEC_INT_MII,
+    FEC_INT_LC,
+    FEC_INT_HB,
+    FEC_INT_GRA,
+    FEC_INT_EB,
+    FEC_INT_BABT,
+    FEC_INT_BABR
+};
+
+/* Buffer Descriptor.  */
+typedef struct {
+    uint16_t flags;
+    uint16_t length;
+    uint32_t data;
+} mcf_fec_bd;
+
+#define FEC_BD_R    0x8000
+#define FEC_BD_E    0x8000
+#define FEC_BD_O1   0x4000
+#define FEC_BD_W    0x2000
+#define FEC_BD_O2   0x1000
+#define FEC_BD_L    0x0800
+#define FEC_BD_TC   0x0400
+#define FEC_BD_ABC  0x0200
+#define FEC_BD_M    0x0100
+#define FEC_BD_BC   0x0080
+#define FEC_BD_MC   0x0040
+#define FEC_BD_LG   0x0020
+#define FEC_BD_NO   0x0010
+#define FEC_BD_CR   0x0004
+#define FEC_BD_OV   0x0002
+#define FEC_BD_TR   0x0001
+
+static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
+    be16_to_cpus(&bd->flags);
+    be16_to_cpus(&bd->length);
+    be32_to_cpus(&bd->data);
+}
+
+static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    mcf_fec_bd tmp;
+    tmp.flags = cpu_to_be16(bd->flags);
+    tmp.length = cpu_to_be16(bd->length);
+    tmp.data = cpu_to_be32(bd->data);
+    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
+}
+
+static void mcf_fec_update(mcf_fec_state *s)
+{
+    uint32_t active;
+    uint32_t changed;
+    uint32_t mask;
+    int i;
+
+    active = s->eir & s->eimr;
+    changed = active ^s->irq_state;
+    for (i = 0; i < FEC_NUM_IRQ; i++) {
+        mask = mcf_fec_irq_map[i];
+        if (changed & mask) {
+            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
+            qemu_set_irq(s->irq[i], (active & mask) != 0);
+        }
+    }
+    s->irq_state = active;
+}
+
+static void mcf_fec_do_tx(mcf_fec_state *s)
+{
+    uint32_t addr;
+    mcf_fec_bd bd;
+    int frame_size;
+    int len;
+    uint8_t frame[FEC_MAX_FRAME_SIZE];
+    uint8_t *ptr;
+
+    DPRINTF("do_tx\n");
+    ptr = frame;
+    frame_size = 0;
+    addr = s->tx_descriptor;
+    while (1) {
+        mcf_fec_read_bd(&bd, addr);
+        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
+                addr, bd.flags, bd.length, bd.data);
+        if ((bd.flags & FEC_BD_R) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = bd.length;
+        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+            len = FEC_MAX_FRAME_SIZE - frame_size;
+            s->eir |= FEC_INT_BABT;
+        }
+        cpu_physical_memory_read(bd.data, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.flags & FEC_BD_L) {
+            /* Last buffer in frame.  */
+            DPRINTF("Sending packet\n");
+            qemu_send_packet(&s->nic->nc, frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->eir |= FEC_INT_TXF;
+        }
+        s->eir |= FEC_INT_TXB;
+        bd.flags &= ~FEC_BD_R;
+        /* Write back the modified descriptor.  */
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->etdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->tx_descriptor = addr;
+}
+
+static void mcf_fec_enable_rx(mcf_fec_state *s)
+{
+    mcf_fec_bd bd;
+
+    mcf_fec_read_bd(&bd, s->rx_descriptor);
+    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
+    if (!s->rx_enabled)
+        DPRINTF("RX buffer full\n");
+}
+
+static void mcf_fec_reset(mcf_fec_state *s)
+{
+    s->eir = 0;
+    s->eimr = 0;
+    s->rx_enabled = 0;
+    s->ecr = 0;
+    s->mscr = 0;
+    s->rcr = 0x05ee0001;
+    s->tcr = 0;
+    s->tfwr = 0;
+    s->rfsr = 0x500;
+}
+
+static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004: return s->eir;
+    case 0x008: return s->eimr;
+    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+    case 0x014: return 0; /* TDAR */
+    case 0x024: return s->ecr;
+    case 0x040: return s->mmfr;
+    case 0x044: return s->mscr;
+    case 0x064: return 0; /* MIBC */
+    case 0x084: return s->rcr;
+    case 0x0c4: return s->tcr;
+    case 0x0e4: /* PALR */
+        return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
+              | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
+        break;
+    case 0x0e8: /* PAUR */
+        return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
+    case 0x0ec: return 0x10000; /* OPD */
+    case 0x118: return 0;
+    case 0x11c: return 0;
+    case 0x120: return 0;
+    case 0x124: return 0;
+    case 0x144: return s->tfwr;
+    case 0x14c: return 0x600;
+    case 0x150: return s->rfsr;
+    case 0x180: return s->erdsr;
+    case 0x184: return s->etdsr;
+    case 0x188: return s->emrbr;
+    default:
+        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004:
+        s->eir &= ~value;
+        break;
+    case 0x008:
+        s->eimr = value;
+        break;
+    case 0x010: /* RDAR */
+        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+            DPRINTF("RX enable\n");
+            mcf_fec_enable_rx(s);
+        }
+        break;
+    case 0x014: /* TDAR */
+        if (s->ecr & FEC_EN) {
+            mcf_fec_do_tx(s);
+        }
+        break;
+    case 0x024:
+        s->ecr = value;
+        if (value & FEC_RESET) {
+            DPRINTF("Reset\n");
+            mcf_fec_reset(s);
+        }
+        if ((s->ecr & FEC_EN) == 0) {
+            s->rx_enabled = 0;
+        }
+        break;
+    case 0x040:
+        /* TODO: Implement MII.  */
+        s->mmfr = value;
+        break;
+    case 0x044:
+        s->mscr = value & 0xfe;
+        break;
+    case 0x064:
+        /* TODO: Implement MIB.  */
+        break;
+    case 0x084:
+        s->rcr = value & 0x07ff003f;
+        /* TODO: Implement LOOP mode.  */
+        break;
+    case 0x0c4: /* TCR */
+        /* We transmit immediately, so raise GRA immediately.  */
+        s->tcr = value;
+        if (value & 1)
+            s->eir |= FEC_INT_GRA;
+        break;
+    case 0x0e4: /* PALR */
+        s->conf.macaddr.a[0] = value >> 24;
+        s->conf.macaddr.a[1] = value >> 16;
+        s->conf.macaddr.a[2] = value >> 8;
+        s->conf.macaddr.a[3] = value;
+        break;
+    case 0x0e8: /* PAUR */
+        s->conf.macaddr.a[4] = value >> 24;
+        s->conf.macaddr.a[5] = value >> 16;
+        break;
+    case 0x0ec:
+        /* OPD */
+        break;
+    case 0x118:
+    case 0x11c:
+    case 0x120:
+    case 0x124:
+        /* TODO: implement MAC hash filtering.  */
+        break;
+    case 0x144:
+        s->tfwr = value & 3;
+        break;
+    case 0x14c:
+        /* FRBR writes ignored.  */
+        break;
+    case 0x150:
+        s->rfsr = (value & 0x3fc) | 0x400;
+        break;
+    case 0x180:
+        s->erdsr = value & ~3;
+        s->rx_descriptor = s->erdsr;
+        break;
+    case 0x184:
+        s->etdsr = value & ~3;
+        s->tx_descriptor = s->etdsr;
+        break;
+    case 0x188:
+        s->emrbr = value & 0x7f0;
+        break;
+    default:
+        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
+    }
+    mcf_fec_update(s);
+}
+
+static int mcf_fec_can_receive(VLANClientState *nc)
+{
+    mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    return s->rx_enabled;
+}
+
+static ssize_t mcf_fec_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    mcf_fec_bd bd;
+    uint32_t flags = 0;
+    uint32_t addr;
+    uint32_t crc;
+    uint32_t buf_addr;
+    uint8_t *crc_ptr;
+    unsigned int buf_len;
+
+    DPRINTF("do_rx len %d\n", size);
+    if (!s->rx_enabled) {
+        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
+    }
+    /* 4 bytes for the CRC.  */
+    size += 4;
+    crc = cpu_to_be32(crc32(~0, buf, size));
+    crc_ptr = (uint8_t *)&crc;
+    /* Huge frames are truncted.  */
+    if (size > FEC_MAX_FRAME_SIZE) {
+        size = FEC_MAX_FRAME_SIZE;
+        flags |= FEC_BD_TR | FEC_BD_LG;
+    }
+    /* Frames larger than the user limit just set error flags.  */
+    if (size > (s->rcr >> 16)) {
+        flags |= FEC_BD_LG;
+    }
+    addr = s->rx_descriptor;
+    while (size > 0) {
+        mcf_fec_read_bd(&bd, addr);
+        if ((bd.flags & FEC_BD_E) == 0) {
+            /* No descriptors available.  Bail out.  */
+            /* FIXME: This is wrong.  We should probably either save the
+               remainder for when more RX buffers are available, or
+               flag an error.  */
+            fprintf(stderr, "mcf_fec: Lost end of frame\n");
+            break;
+        }
+        buf_len = (size <= s->emrbr) ? size: s->emrbr;
+        bd.length = buf_len;
+        size -= buf_len;
+        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
+        /* The last 4 bytes are the CRC.  */
+        if (size < 4)
+            buf_len += size - 4;
+        buf_addr = bd.data;
+        cpu_physical_memory_write(buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
+            crc_ptr += 4 - size;
+        }
+        bd.flags &= ~FEC_BD_E;
+        if (size == 0) {
+            /* Last buffer in frame.  */
+            bd.flags |= flags | FEC_BD_L;
+            DPRINTF("rx frame flags %04x\n", bd.flags);
+            s->eir |= FEC_INT_RXF;
+        } else {
+            s->eir |= FEC_INT_RXB;
+        }
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->erdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->rx_descriptor = addr;
+    mcf_fec_enable_rx(s);
+    mcf_fec_update(s);
+    return size;
+}
+
+static CPUReadMemoryFunc * const mcf_fec_readfn[] = {
+   mcf_fec_read,
+   mcf_fec_read,
+   mcf_fec_read
+};
+
+static CPUWriteMemoryFunc * const mcf_fec_writefn[] = {
+   mcf_fec_write,
+   mcf_fec_write,
+   mcf_fec_write
+};
+
+static void mcf_fec_cleanup(VLANClientState *nc)
+{
+    mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    cpu_unregister_io_memory(s->mmio_index);
+
+    qemu_free(s);
+}
+
+static NetClientInfo net_mcf_fec_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = mcf_fec_can_receive,
+    .receive = mcf_fec_receive,
+    .cleanup = mcf_fec_cleanup,
+};
+
+void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
+{
+    mcf_fec_state *s;
+
+    qemu_check_nic_model(nd, "mcf_fec");
+
+    s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
+    s->irq = irq;
+    s->mmio_index = cpu_register_io_memory(mcf_fec_readfn,
+                                           mcf_fec_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x400, s->mmio_index);
+
+    s->conf.macaddr = nd->macaddr;
+    s->conf.vlan = nd->vlan;
+    s->conf.peer = nd->netdev;
+
+    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
+
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+}
diff --git a/qemu-0.15.x/hw/mcf_intc.c b/qemu-0.15.x/hw/mcf_intc.c
new file mode 100644
index 0000000..6cb0a09
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf_intc.c
@@ -0,0 +1,157 @@
+/*
+ * ColdFire Interrupt Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw.h"
+#include "mcf.h"
+
+typedef struct {
+    uint64_t ipr;
+    uint64_t imr;
+    uint64_t ifr;
+    uint64_t enabled;
+    uint8_t icr[64];
+    CPUState *env;
+    int active_vector;
+} mcf_intc_state;
+
+static void mcf_intc_update(mcf_intc_state *s)
+{
+    uint64_t active;
+    int i;
+    int best;
+    int best_level;
+
+    active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
+    best_level = 0;
+    best = 64;
+    if (active) {
+        for (i = 0; i < 64; i++) {
+            if ((active & 1) != 0 && s->icr[i] >= best_level) {
+                best_level = s->icr[i];
+                best = i;
+            }
+            active >>= 1;
+        }
+    }
+    s->active_vector = ((best == 64) ? 24 : (best + 64));
+    m68k_set_irq_level(s->env, best_level, s->active_vector);
+}
+
+static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr)
+{
+    int offset;
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    offset = addr & 0xff;
+    if (offset >= 0x40 && offset < 0x80) {
+        return s->icr[offset - 0x40];
+    }
+    switch (offset) {
+    case 0x00:
+        return (uint32_t)(s->ipr >> 32);
+    case 0x04:
+        return (uint32_t)s->ipr;
+    case 0x08:
+        return (uint32_t)(s->imr >> 32);
+    case 0x0c:
+        return (uint32_t)s->imr;
+    case 0x10:
+        return (uint32_t)(s->ifr >> 32);
+    case 0x14:
+        return (uint32_t)s->ifr;
+    case 0xe0: /* SWIACK.  */
+        return s->active_vector;
+    case 0xe1: case 0xe2: case 0xe3: case 0xe4:
+    case 0xe5: case 0xe6: case 0xe7:
+        /* LnIACK */
+        hw_error("mcf_intc_read: LnIACK not implemented\n");
+    default:
+        return 0;
+    }
+}
+
+static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    int offset;
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    offset = addr & 0xff;
+    if (offset >= 0x40 && offset < 0x80) {
+        int n = offset - 0x40;
+        s->icr[n] = val;
+        if (val == 0)
+            s->enabled &= ~(1ull << n);
+        else
+            s->enabled |= (1ull << n);
+        mcf_intc_update(s);
+        return;
+    }
+    switch (offset) {
+    case 0x00: case 0x04:
+        /* Ignore IPR writes.  */
+        return;
+    case 0x08:
+        s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
+        break;
+    case 0x0c:
+        s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
+        break;
+    default:
+        hw_error("mcf_intc_write: Bad write offset %d\n", offset);
+        break;
+    }
+    mcf_intc_update(s);
+}
+
+static void mcf_intc_set_irq(void *opaque, int irq, int level)
+{
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    if (irq >= 64)
+        return;
+    if (level)
+        s->ipr |= 1ull << irq;
+    else
+        s->ipr &= ~(1ull << irq);
+    mcf_intc_update(s);
+}
+
+static void mcf_intc_reset(mcf_intc_state *s)
+{
+    s->imr = ~0ull;
+    s->ipr = 0;
+    s->ifr = 0;
+    s->enabled = 0;
+    memset(s->icr, 0, 64);
+    s->active_vector = 24;
+}
+
+static CPUReadMemoryFunc * const mcf_intc_readfn[] = {
+   mcf_intc_read,
+   mcf_intc_read,
+   mcf_intc_read
+};
+
+static CPUWriteMemoryFunc * const mcf_intc_writefn[] = {
+   mcf_intc_write,
+   mcf_intc_write,
+   mcf_intc_write
+};
+
+qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
+{
+    mcf_intc_state *s;
+    int iomemtype;
+
+    s = qemu_mallocz(sizeof(mcf_intc_state));
+    s->env = env;
+    mcf_intc_reset(s);
+
+    iomemtype = cpu_register_io_memory(mcf_intc_readfn,
+                                       mcf_intc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
+}
diff --git a/qemu-0.15.x/hw/mcf_uart.c b/qemu-0.15.x/hw/mcf_uart.c
new file mode 100644
index 0000000..905e116
--- /dev/null
+++ b/qemu-0.15.x/hw/mcf_uart.c
@@ -0,0 +1,310 @@
+/*
+ * ColdFire UART emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw.h"
+#include "mcf.h"
+#include "qemu-char.h"
+
+typedef struct {
+    uint8_t mr[2];
+    uint8_t sr;
+    uint8_t isr;
+    uint8_t imr;
+    uint8_t bg1;
+    uint8_t bg2;
+    uint8_t fifo[4];
+    uint8_t tb;
+    int current_mr;
+    int fifo_len;
+    int tx_enabled;
+    int rx_enabled;
+    qemu_irq irq;
+    CharDriverState *chr;
+} mcf_uart_state;
+
+/* UART Status Register bits.  */
+#define MCF_UART_RxRDY  0x01
+#define MCF_UART_FFULL  0x02
+#define MCF_UART_TxRDY  0x04
+#define MCF_UART_TxEMP  0x08
+#define MCF_UART_OE     0x10
+#define MCF_UART_PE     0x20
+#define MCF_UART_FE     0x40
+#define MCF_UART_RB     0x80
+
+/* Interrupt flags.  */
+#define MCF_UART_TxINT  0x01
+#define MCF_UART_RxINT  0x02
+#define MCF_UART_DBINT  0x04
+#define MCF_UART_COSINT 0x80
+
+/* UMR1 flags.  */
+#define MCF_UART_BC0    0x01
+#define MCF_UART_BC1    0x02
+#define MCF_UART_PT     0x04
+#define MCF_UART_PM0    0x08
+#define MCF_UART_PM1    0x10
+#define MCF_UART_ERR    0x20
+#define MCF_UART_RxIRQ  0x40
+#define MCF_UART_RxRTS  0x80
+
+static void mcf_uart_update(mcf_uart_state *s)
+{
+    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
+    if (s->sr & MCF_UART_TxRDY)
+        s->isr |= MCF_UART_TxINT;
+    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
+                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
+        s->isr |= MCF_UART_RxINT;
+
+    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
+}
+
+uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    case 0x00:
+        return s->mr[s->current_mr];
+    case 0x04:
+        return s->sr;
+    case 0x0c:
+        {
+            uint8_t val;
+            int i;
+
+            if (s->fifo_len == 0)
+                return 0;
+
+            val = s->fifo[0];
+            s->fifo_len--;
+            for (i = 0; i < s->fifo_len; i++)
+                s->fifo[i] = s->fifo[i + 1];
+            s->sr &= ~MCF_UART_FFULL;
+            if (s->fifo_len == 0)
+                s->sr &= ~MCF_UART_RxRDY;
+            mcf_uart_update(s);
+            qemu_chr_accept_input(s->chr);
+            return val;
+        }
+    case 0x10:
+        /* TODO: Implement IPCR.  */
+        return 0;
+    case 0x14:
+        return s->isr;
+    case 0x18:
+        return s->bg1;
+    case 0x1c:
+        return s->bg2;
+    default:
+        return 0;
+    }
+}
+
+/* Update TxRDY flag and set data if present and enabled.  */
+static void mcf_uart_do_tx(mcf_uart_state *s)
+{
+    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
+        if (s->chr)
+            qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
+        s->sr |= MCF_UART_TxEMP;
+    }
+    if (s->tx_enabled) {
+        s->sr |= MCF_UART_TxRDY;
+    } else {
+        s->sr &= ~MCF_UART_TxRDY;
+    }
+}
+
+static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
+{
+    /* Misc command.  */
+    switch ((cmd >> 4) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Reset mode register pointer.  */
+        s->current_mr = 0;
+        break;
+    case 2: /* Reset receiver.  */
+        s->rx_enabled = 0;
+        s->fifo_len = 0;
+        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
+        break;
+    case 3: /* Reset transmitter.  */
+        s->tx_enabled = 0;
+        s->sr |= MCF_UART_TxEMP;
+        s->sr &= ~MCF_UART_TxRDY;
+        break;
+    case 4: /* Reset error status.  */
+        break;
+    case 5: /* Reset break-change interrupt.  */
+        s->isr &= ~MCF_UART_DBINT;
+        break;
+    case 6: /* Start break.  */
+    case 7: /* Stop break.  */
+        break;
+    }
+
+    /* Transmitter command.  */
+    switch ((cmd >> 2) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->tx_enabled = 1;
+        mcf_uart_do_tx(s);
+        break;
+    case 2: /* Disable.  */
+        s->tx_enabled = 0;
+        mcf_uart_do_tx(s);
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "mcf_uart: Bad TX command\n");
+        break;
+    }
+
+    /* Receiver command.  */
+    switch (cmd & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->rx_enabled = 1;
+        break;
+    case 2:
+        s->rx_enabled = 0;
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "mcf_uart: Bad RX command\n");
+        break;
+    }
+}
+
+void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    case 0x00:
+        s->mr[s->current_mr] = val;
+        s->current_mr = 1;
+        break;
+    case 0x04:
+        /* CSR is ignored.  */
+        break;
+    case 0x08: /* Command Register.  */
+        mcf_do_command(s, val);
+        break;
+    case 0x0c: /* Transmit Buffer.  */
+        s->sr &= ~MCF_UART_TxEMP;
+        s->tb = val;
+        mcf_uart_do_tx(s);
+        break;
+    case 0x10:
+        /* ACR is ignored.  */
+        break;
+    case 0x14:
+        s->imr = val;
+        break;
+    default:
+        break;
+    }
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_reset(mcf_uart_state *s)
+{
+    s->fifo_len = 0;
+    s->mr[0] = 0;
+    s->mr[1] = 0;
+    s->sr = MCF_UART_TxEMP;
+    s->tx_enabled = 0;
+    s->rx_enabled = 0;
+    s->isr = 0;
+    s->imr = 0;
+}
+
+static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
+{
+    /* Break events overwrite the last byte if the fifo is full.  */
+    if (s->fifo_len == 4)
+        s->fifo_len--;
+
+    s->fifo[s->fifo_len] = data;
+    s->fifo_len++;
+    s->sr |= MCF_UART_RxRDY;
+    if (s->fifo_len == 4)
+        s->sr |= MCF_UART_FFULL;
+
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_event(void *opaque, int event)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        s->isr |= MCF_UART_DBINT;
+        mcf_uart_push_byte(s, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+static int mcf_uart_can_receive(void *opaque)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
+}
+
+static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    mcf_uart_push_byte(s, buf[0]);
+}
+
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+{
+    mcf_uart_state *s;
+
+    s = qemu_mallocz(sizeof(mcf_uart_state));
+    s->chr = chr;
+    s->irq = irq;
+    if (chr) {
+        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+                              mcf_uart_event, s);
+    }
+    mcf_uart_reset(s);
+    return s;
+}
+
+
+static CPUReadMemoryFunc * const mcf_uart_readfn[] = {
+   mcf_uart_read,
+   mcf_uart_read,
+   mcf_uart_read
+};
+
+static CPUWriteMemoryFunc * const mcf_uart_writefn[] = {
+   mcf_uart_write,
+   mcf_uart_write,
+   mcf_uart_write
+};
+
+void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
+                      CharDriverState *chr)
+{
+    mcf_uart_state *s;
+    int iomemtype;
+
+    s = mcf_uart_init(irq, chr);
+    iomemtype = cpu_register_io_memory(mcf_uart_readfn,
+                                       mcf_uart_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x40, iomemtype);
+}
diff --git a/qemu-0.15.x/hw/microblaze_pic_cpu.c b/qemu-0.15.x/hw/microblaze_pic_cpu.c
new file mode 100644
index 0000000..7c59382
--- /dev/null
+++ b/qemu-0.15.x/hw/microblaze_pic_cpu.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU MicroBlaze CPU interrupt wrapper logic.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw.h"
+#include "pc.h"
+
+#define D(x)
+
+void pic_info(Monitor *mon)
+{}
+void irq_info(Monitor *mon)
+{}
+
+static void microblaze_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+    int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
+
+    if (level)
+        cpu_interrupt(env, type);
+    else
+        cpu_reset_interrupt(env, type);
+}
+
+qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+qemu_irq *microblaze_pic_init_cpu(CPUState *env)
+{
+    return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2);
+}
diff --git a/qemu-0.15.x/hw/milkymist-ac97.c b/qemu-0.15.x/hw/milkymist-ac97.c
new file mode 100644
index 0000000..6104732
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-ac97.c
@@ -0,0 +1,335 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/ac97.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "audio/audio.h"
+#include "qemu-error.h"
+
+enum {
+    R_AC97_CTRL = 0,
+    R_AC97_ADDR,
+    R_AC97_DATAOUT,
+    R_AC97_DATAIN,
+    R_D_CTRL,
+    R_D_ADDR,
+    R_D_REMAINING,
+    R_RESERVED,
+    R_U_CTRL,
+    R_U_ADDR,
+    R_U_REMAINING,
+    R_MAX
+};
+
+enum {
+    AC97_CTRL_RQEN  = (1<<0),
+    AC97_CTRL_WRITE = (1<<1),
+};
+
+enum {
+    CTRL_EN = (1<<0),
+};
+
+struct MilkymistAC97State {
+    SysBusDevice busdev;
+
+    QEMUSoundCard card;
+    SWVoiceIn *voice_in;
+    SWVoiceOut *voice_out;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq crrequest_irq;
+    qemu_irq crreply_irq;
+    qemu_irq dmar_irq;
+    qemu_irq dmaw_irq;
+};
+typedef struct MilkymistAC97State MilkymistAC97State;
+
+static void update_voices(MilkymistAC97State *s)
+{
+    if (s->regs[R_D_CTRL] & CTRL_EN) {
+        AUD_set_active_out(s->voice_out, 1);
+    } else {
+        AUD_set_active_out(s->voice_out, 0);
+    }
+
+    if (s->regs[R_U_CTRL] & CTRL_EN) {
+        AUD_set_active_in(s->voice_in, 1);
+    } else {
+        AUD_set_active_in(s->voice_in, 0);
+    }
+}
+
+static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistAC97State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_CTRL:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_CTRL:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_ac97: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_ac97_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistAC97State *s = opaque;
+
+    trace_milkymist_ac97_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+        /* always raise an IRQ according to the direction */
+        if (value & AC97_CTRL_RQEN) {
+            if (value & AC97_CTRL_WRITE) {
+                trace_milkymist_ac97_pulse_irq_crrequest();
+                qemu_irq_pulse(s->crrequest_irq);
+            } else {
+                trace_milkymist_ac97_pulse_irq_crreply();
+                qemu_irq_pulse(s->crreply_irq);
+            }
+        }
+
+        /* RQEN is self clearing */
+        s->regs[addr] = value & ~AC97_CTRL_RQEN;
+        break;
+    case R_D_CTRL:
+    case R_U_CTRL:
+        s->regs[addr] = value;
+        update_voices(s);
+        break;
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_ac97: write access to unknown register 0x"
+                TARGET_FMT_plx, addr);
+        break;
+    }
+
+}
+
+static CPUReadMemoryFunc * const ac97_read_fn[] = {
+    NULL,
+    NULL,
+    &ac97_read,
+};
+
+static CPUWriteMemoryFunc * const ac97_write_fn[] = {
+    NULL,
+    NULL,
+    &ac97_write,
+};
+
+static void ac97_in_cb(void *opaque, int avail_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_U_REMAINING];
+    int temp = audio_MIN(remaining, avail_b);
+    uint32_t addr = s->regs[R_U_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_in_cb(avail_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int acquired, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        acquired = AUD_read(s->voice_in, buf, to_copy);
+        if (!acquired) {
+            break;
+        }
+
+        cpu_physical_memory_write(addr, buf, acquired);
+
+        temp -= acquired;
+        addr += acquired;
+        transferred += acquired;
+    }
+
+    trace_milkymist_ac97_in_cb_transferred(transferred);
+
+    s->regs[R_U_ADDR] = addr;
+    s->regs[R_U_REMAINING] -= transferred;
+
+    if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmaw();
+        qemu_irq_pulse(s->dmaw_irq);
+    }
+}
+
+static void ac97_out_cb(void *opaque, int free_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_D_REMAINING];
+    int temp = audio_MIN(remaining, free_b);
+    uint32_t addr = s->regs[R_D_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_out_cb(free_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int copied, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        cpu_physical_memory_read(addr, buf, to_copy);
+        copied = AUD_write(s->voice_out, buf, to_copy);
+        if (!copied) {
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        transferred += copied;
+    }
+
+    trace_milkymist_ac97_out_cb_transferred(transferred);
+
+    s->regs[R_D_ADDR] = addr;
+    s->regs[R_D_REMAINING] -= transferred;
+
+    if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmar();
+        qemu_irq_pulse(s->dmar_irq);
+    }
+}
+
+static void milkymist_ac97_reset(DeviceState *d)
+{
+    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    AUD_set_active_in(s->voice_in, 0);
+    AUD_set_active_out(s->voice_out, 0);
+}
+
+static int ac97_post_load(void *opaque, int version_id)
+{
+    MilkymistAC97State *s = opaque;
+
+    update_voices(s);
+
+    return 0;
+}
+
+static int milkymist_ac97_init(SysBusDevice *dev)
+{
+    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
+    int ac97_regs;
+
+    struct audsettings as;
+    sysbus_init_irq(dev, &s->crrequest_irq);
+    sysbus_init_irq(dev, &s->crreply_irq);
+    sysbus_init_irq(dev, &s->dmar_irq);
+    sysbus_init_irq(dev, &s->dmaw_irq);
+
+    AUD_register_card("Milkymist AC'97", &s->card);
+
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 1;
+
+    s->voice_in = AUD_open_in(&s->card, s->voice_in,
+            "mm_ac97.in", s, ac97_in_cb, &as);
+    s->voice_out = AUD_open_out(&s->card, s->voice_out,
+            "mm_ac97.out", s, ac97_out_cb, &as);
+
+    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_ac97 = {
+    .name = "milkymist-ac97",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ac97_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_ac97_info = {
+    .init = milkymist_ac97_init,
+    .qdev.name  = "milkymist-ac97",
+    .qdev.size  = sizeof(MilkymistAC97State),
+    .qdev.vmsd  = &vmstate_milkymist_ac97,
+    .qdev.reset = milkymist_ac97_reset,
+};
+
+static void milkymist_ac97_register(void)
+{
+    sysbus_register_withprop(&milkymist_ac97_info);
+}
+
+device_init(milkymist_ac97_register)
diff --git a/qemu-0.15.x/hw/milkymist-hpdmc.c b/qemu-0.15.x/hw/milkymist-hpdmc.c
new file mode 100644
index 0000000..c0962fb
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-hpdmc.c
@@ -0,0 +1,161 @@
+/*
+ *  QEMU model of the Milkymist High Performance Dynamic Memory Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/hpdmc.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+enum {
+    R_SYSTEM = 0,
+    R_BYPASS,
+    R_TIMING,
+    R_IODELAY,
+    R_MAX
+};
+
+enum {
+    IODELAY_DQSDELAY_RDY = (1<<5),
+    IODELAY_PLL1_LOCKED  = (1<<6),
+    IODELAY_PLL2_LOCKED  = (1<<7),
+};
+
+struct MilkymistHpdmcState {
+    SysBusDevice busdev;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistHpdmcState MilkymistHpdmcState;
+
+static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistHpdmcState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+    case R_IODELAY:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_hpdmc_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistHpdmcState *s = opaque;
+
+    trace_milkymist_hpdmc_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+        s->regs[addr] = value;
+        break;
+    case R_IODELAY:
+        /* ignore writes */
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const hpdmc_read_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_read,
+};
+
+static CPUWriteMemoryFunc * const hpdmc_write_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_write,
+};
+
+static void milkymist_hpdmc_reset(DeviceState *d)
+{
+    MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
+                         | IODELAY_PLL2_LOCKED;
+}
+
+static int milkymist_hpdmc_init(SysBusDevice *dev)
+{
+    MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
+    int hpdmc_regs;
+
+    hpdmc_regs = cpu_register_io_memory(hpdmc_read_fn, hpdmc_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, hpdmc_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_hpdmc = {
+    .name = "milkymist-hpdmc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_hpdmc_info = {
+    .init = milkymist_hpdmc_init,
+    .qdev.name  = "milkymist-hpdmc",
+    .qdev.size  = sizeof(MilkymistHpdmcState),
+    .qdev.vmsd  = &vmstate_milkymist_hpdmc,
+    .qdev.reset = milkymist_hpdmc_reset,
+};
+
+static void milkymist_hpdmc_register(void)
+{
+    sysbus_register_withprop(&milkymist_hpdmc_info);
+}
+
+device_init(milkymist_hpdmc_register)
diff --git a/qemu-0.15.x/hw/milkymist-hw.h b/qemu-0.15.x/hw/milkymist-hw.h
new file mode 100644
index 0000000..20de68e
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-hw.h
@@ -0,0 +1,224 @@
+#ifndef QEMU_HW_MILKYMIST_H
+#define QEMU_HW_MILKYMIST_H
+
+#include "qdev.h"
+#include "qdev-addr.h"
+
+static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-uart");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-hpdmc");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-memcard");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base,
+        uint32_t fb_offset, uint32_t fb_mask)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-vgafb");
+    qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
+    qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base,
+        qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
+        uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
+        uint32_t gpio_strappings)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-sysctl");
+    qdev_prop_set_uint32(dev, "frequency", freq_hz);
+    qdev_prop_set_uint32(dev, "systemid", system_id);
+    qdev_prop_set_uint32(dev, "capabilities", capabilities);
+    qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, gpio_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, timer0_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, timer1_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_pfpu_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-pfpu");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+#ifdef CONFIG_OPENGL
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+#endif
+
+static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+#ifdef CONFIG_OPENGL
+    DeviceState *dev;
+    Display *d;
+    GLXFBConfig *configs;
+    int nelements;
+    int ver_major, ver_minor;
+
+    if (display_type == DT_NOGRAPHIC) {
+        return NULL;
+    }
+
+    /* check that GLX will work */
+    d = XOpenDisplay(NULL);
+    if (d == NULL) {
+        return NULL;
+    }
+
+    if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
+        /* Yeah, sometimes getting the GLX version can fail.
+         * Isn't X beautiful? */
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
+        printf("Your GLX version is %d.%d,"
+          "but TMU emulation needs at least 1.3. TMU disabled.\n",
+          ver_major, ver_minor);
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    XFree(configs);
+    XCloseDisplay(d);
+
+    dev = qdev_create(NULL, "milkymist-tmu2");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+#else
+    return NULL;
+#endif
+}
+
+static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base,
+        qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
+        qemu_irq dmaw_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-ac97");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, crrequest_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, crreply_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, dmar_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 3, dmaw_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac");
+    dev = qdev_create(NULL, "milkymist-minimac");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac2_create(target_phys_addr_t base,
+        target_phys_addr_t buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac2");
+    dev = qdev_create(NULL, "milkymist-minimac2");
+    qdev_prop_set_taddr(dev, "buffers_base", buffers_base);
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base,
+        qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
+        uint32_t dmem_base, uint32_t dmem_size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-softusb");
+    qdev_prop_set_uint32(dev, "pmem_base", pmem_base);
+    qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
+    qdev_prop_set_uint32(dev, "dmem_base", dmem_base);
+    qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* QEMU_HW_MILKYMIST_H */
diff --git a/qemu-0.15.x/hw/milkymist-memcard.c b/qemu-0.15.x/hw/milkymist-memcard.c
new file mode 100644
index 0000000..22dc377
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-memcard.c
@@ -0,0 +1,294 @@
+/*
+ *  QEMU model of the Milkymist SD Card Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/memcard.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-error.h"
+#include "blockdev.h"
+#include "sd.h"
+
+enum {
+    ENABLE_CMD_TX   = (1<<0),
+    ENABLE_CMD_RX   = (1<<1),
+    ENABLE_DAT_TX   = (1<<2),
+    ENABLE_DAT_RX   = (1<<3),
+};
+
+enum {
+    PENDING_CMD_TX   = (1<<0),
+    PENDING_CMD_RX   = (1<<1),
+    PENDING_DAT_TX   = (1<<2),
+    PENDING_DAT_RX   = (1<<3),
+};
+
+enum {
+    START_CMD_TX    = (1<<0),
+    START_DAT_RX    = (1<<1),
+};
+
+enum {
+    R_CLK2XDIV = 0,
+    R_ENABLE,
+    R_PENDING,
+    R_START,
+    R_CMD,
+    R_DAT,
+    R_MAX
+};
+
+struct MilkymistMemcardState {
+    SysBusDevice busdev;
+    SDState *card;
+
+    int command_write_ptr;
+    int response_read_ptr;
+    int response_len;
+    int ignore_next_cmd;
+    int enabled;
+    uint8_t command[6];
+    uint8_t response[17];
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistMemcardState MilkymistMemcardState;
+
+static void update_pending_bits(MilkymistMemcardState *s)
+{
+    /* transmits are instantaneous, thus tx pending bits are never set */
+    s->regs[R_PENDING] = 0;
+    /* if rx is enabled the corresponding pending bits are always set */
+    if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
+        s->regs[R_PENDING] |= PENDING_CMD_RX;
+    }
+    if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
+        s->regs[R_PENDING] |= PENDING_DAT_RX;
+    }
+}
+
+static void memcard_sd_command(MilkymistMemcardState *s)
+{
+    SDRequest req;
+
+    req.cmd = s->command[0] & 0x3f;
+    req.arg = (s->command[1] << 24) | (s->command[2] << 16)
+              | (s->command[3] << 8) | s->command[4];
+    req.crc = s->command[5];
+
+    s->response[0] = req.cmd;
+    s->response_len = sd_do_command(s->card, &req, s->response+1);
+    s->response_read_ptr = 0;
+
+    if (s->response_len == 16) {
+        /* R2 response */
+        s->response[0] = 0x3f;
+        s->response_len += 1;
+    } else if (s->response_len == 4) {
+        /* no crc calculation, insert dummy byte */
+        s->response[5] = 0;
+        s->response_len += 2;
+    }
+
+    if (req.cmd == 0) {
+        /* next write is a dummy byte to clock the initialization of the sd
+         * card */
+        s->ignore_next_cmd = 1;
+    }
+}
+
+static uint32_t memcard_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMemcardState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CMD:
+        if (!s->enabled) {
+            r = 0xff;
+        } else {
+            r = s->response[s->response_read_ptr++];
+            if (s->response_read_ptr > s->response_len) {
+                error_report("milkymist_memcard: "
+                        "read more cmd bytes than available. Clipping.");
+                s->response_read_ptr = 0;
+            }
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            r = 0xffffffff;
+        } else {
+            r = 0;
+            r |= sd_read_data(s->card) << 24;
+            r |= sd_read_data(s->card) << 16;
+            r |= sd_read_data(s->card) << 8;
+            r |= sd_read_data(s->card);
+        }
+        break;
+    case R_CLK2XDIV:
+    case R_ENABLE:
+    case R_PENDING:
+    case R_START:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_memcard: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_memcard_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMemcardState *s = opaque;
+
+    trace_milkymist_memcard_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_PENDING:
+        /* clear rx pending bits */
+        s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
+        update_pending_bits(s);
+        break;
+    case R_CMD:
+        if (!s->enabled) {
+            break;
+        }
+        if (s->ignore_next_cmd) {
+            s->ignore_next_cmd = 0;
+            break;
+        }
+        s->command[s->command_write_ptr] = value & 0xff;
+        s->command_write_ptr = (s->command_write_ptr + 1) % 6;
+        if (s->command_write_ptr == 0) {
+            memcard_sd_command(s);
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            break;
+        }
+        sd_write_data(s->card, (value >> 24) & 0xff);
+        sd_write_data(s->card, (value >> 16) & 0xff);
+        sd_write_data(s->card, (value >> 8) & 0xff);
+        sd_write_data(s->card, value & 0xff);
+        break;
+    case R_ENABLE:
+        s->regs[addr] = value;
+        update_pending_bits(s);
+        break;
+    case R_CLK2XDIV:
+    case R_START:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_memcard: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const memcard_read_fn[] = {
+    NULL,
+    NULL,
+    &memcard_read,
+};
+
+static CPUWriteMemoryFunc * const memcard_write_fn[] = {
+    NULL,
+    NULL,
+    &memcard_write,
+};
+
+static void milkymist_memcard_reset(DeviceState *d)
+{
+    MilkymistMemcardState *s =
+            container_of(d, MilkymistMemcardState, busdev.qdev);
+    int i;
+
+    s->command_write_ptr = 0;
+    s->response_read_ptr = 0;
+    s->response_len = 0;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_memcard_init(SysBusDevice *dev)
+{
+    MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
+    DriveInfo *dinfo;
+    int memcard_regs;
+
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
+
+    memcard_regs = cpu_register_io_memory(memcard_read_fn, memcard_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, memcard_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_memcard = {
+    .name = "milkymist-memcard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_len, MilkymistMemcardState),
+        VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
+        VMSTATE_INT32(enabled, MilkymistMemcardState),
+        VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
+        VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_memcard_info = {
+    .init = milkymist_memcard_init,
+    .qdev.name  = "milkymist-memcard",
+    .qdev.size  = sizeof(MilkymistMemcardState),
+    .qdev.vmsd  = &vmstate_milkymist_memcard,
+    .qdev.reset = milkymist_memcard_reset,
+};
+
+static void milkymist_memcard_register(void)
+{
+    sysbus_register_withprop(&milkymist_memcard_info);
+}
+
+device_init(milkymist_memcard_register)
diff --git a/qemu-0.15.x/hw/milkymist-minimac2.c b/qemu-0.15.x/hw/milkymist-minimac2.c
new file mode 100644
index 0000000..cd36026
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-minimac2.c
@@ -0,0 +1,539 @@
+/*
+ *  QEMU model of the Milkymist minimac2 block.
+ *
+ *  Copyright (c) 2011 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "net.h"
+#include "qemu-error.h"
+#include "qdev-addr.h"
+
+#include <zlib.h>
+
+enum {
+    R_SETUP = 0,
+    R_MDIO,
+    R_STATE0,
+    R_COUNT0,
+    R_STATE1,
+    R_COUNT1,
+    R_TXCOUNT,
+    R_MAX
+};
+
+enum {
+    SETUP_PHY_RST = (1<<0),
+};
+
+enum {
+    MDIO_DO  = (1<<0),
+    MDIO_DI  = (1<<1),
+    MDIO_OE  = (1<<2),
+    MDIO_CLK = (1<<3),
+};
+
+enum {
+    STATE_EMPTY   = 0,
+    STATE_LOADED  = 1,
+    STATE_PENDING = 2,
+};
+
+enum {
+    MDIO_OP_WRITE = 1,
+    MDIO_OP_READ  = 2,
+};
+
+enum mdio_state {
+    MDIO_STATE_IDLE,
+    MDIO_STATE_READING,
+    MDIO_STATE_WRITING,
+};
+
+enum {
+    R_PHY_ID1  = 2,
+    R_PHY_ID2  = 3,
+    R_PHY_MAX  = 32
+};
+
+#define MINIMAC2_MTU 1530
+#define MINIMAC2_BUFFER_SIZE 2048
+
+struct MilkymistMinimac2MdioState {
+    int last_clk;
+    int count;
+    uint32_t data;
+    uint16_t data_out;
+    int state;
+
+    uint8_t phy_addr;
+    uint8_t reg_addr;
+};
+typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
+
+struct MilkymistMinimac2State {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    char *phy_model;
+    target_phys_addr_t buffers_base;
+
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+
+    MilkymistMinimac2MdioState mdio;
+
+    uint16_t phy_regs[R_PHY_MAX];
+
+    uint8_t *rx0_buf;
+    uint8_t *rx1_buf;
+    uint8_t *tx_buf;
+};
+typedef struct MilkymistMinimac2State MilkymistMinimac2State;
+
+static const uint8_t preamble_sfd[] = {
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
+};
+
+static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
+{
+    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
+
+    /* nop */
+}
+
+static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr)
+{
+    uint16_t r = s->phy_regs[reg_addr];
+
+    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
+
+    return r;
+}
+
+static void minimac2_update_mdio(MilkymistMinimac2State *s)
+{
+    MilkymistMinimac2MdioState *m = &s->mdio;
+
+    /* detect rising clk edge */
+    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
+        /* shift data in */
+        int bit = ((s->regs[R_MDIO] & MDIO_DO)
+                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
+        m->data = (m->data << 1) | bit;
+
+        /* check for sync */
+        if (m->data == 0xffffffff) {
+            m->count = 32;
+        }
+
+        if (m->count == 16) {
+            uint8_t start = (m->data >> 14) & 0x3;
+            uint8_t op = (m->data >> 12) & 0x3;
+            uint8_t ta = (m->data) & 0x3;
+
+            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
+                m->state = MDIO_STATE_WRITING;
+            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
+                m->state = MDIO_STATE_READING;
+            } else {
+                m->state = MDIO_STATE_IDLE;
+            }
+
+            if (m->state != MDIO_STATE_IDLE) {
+                m->phy_addr = (m->data >> 7) & 0x1f;
+                m->reg_addr = (m->data >> 2) & 0x1f;
+            }
+
+            if (m->state == MDIO_STATE_READING) {
+                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
+                        m->reg_addr);
+            }
+        }
+
+        if (m->count < 16 && m->state == MDIO_STATE_READING) {
+            int bit = (m->data_out & 0x8000) ? 1 : 0;
+            m->data_out <<= 1;
+
+            if (bit) {
+                s->regs[R_MDIO] |= MDIO_DI;
+            } else {
+                s->regs[R_MDIO] &= ~MDIO_DI;
+            }
+        }
+
+        if (m->count == 0 && m->state) {
+            if (m->state == MDIO_STATE_WRITING) {
+                uint16_t data = m->data & 0xffff;
+                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
+            }
+            m->state = MDIO_STATE_IDLE;
+        }
+        m->count--;
+    }
+
+    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
+}
+
+static size_t assemble_frame(uint8_t *buf, size_t size,
+        const uint8_t *payload, size_t payload_size)
+{
+    uint32_t crc;
+
+    if (size < payload_size + 12) {
+        error_report("milkymist_minimac2: received too big ethernet frame");
+        return 0;
+    }
+
+    /* prepend preamble and sfd */
+    memcpy(buf, preamble_sfd, 8);
+
+    /* now copy the payload */
+    memcpy(buf + 8, payload, payload_size);
+
+    /* pad frame if needed */
+    if (payload_size < 60) {
+        memset(buf + payload_size + 8, 0, 60 - payload_size);
+        payload_size = 60;
+    }
+
+    /* append fcs */
+    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
+    memcpy(buf + payload_size + 8, &crc, 4);
+
+    return payload_size + 12;
+}
+
+static void minimac2_tx(MilkymistMinimac2State *s)
+{
+    uint32_t txcount = s->regs[R_TXCOUNT];
+    uint8_t *buf = s->tx_buf;
+
+    if (txcount < 64) {
+        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
+                txcount, 64);
+        goto err;
+    }
+
+    if (txcount > MINIMAC2_MTU) {
+        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
+                txcount, MINIMAC2_MTU);
+        goto err;
+    }
+
+    if (memcmp(buf, preamble_sfd, 8) != 0) {
+        error_report("milkymist_minimac2: frame doesn't contain the preamble "
+                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
+                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+        goto err;
+    }
+
+    trace_milkymist_minimac2_tx_frame(txcount - 12);
+
+    /* send packet, skipping preamble and sfd */
+    qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12);
+
+    s->regs[R_TXCOUNT] = 0;
+
+err:
+    trace_milkymist_minimac2_pulse_irq_tx();
+    qemu_irq_pulse(s->tx_irq);
+}
+
+static void update_rx_interrupt(MilkymistMinimac2State *s)
+{
+    if (s->regs[R_STATE0] == STATE_PENDING
+            || s->regs[R_STATE1] == STATE_PENDING) {
+        trace_milkymist_minimac2_raise_irq_rx();
+        qemu_irq_raise(s->rx_irq);
+    } else {
+        trace_milkymist_minimac2_lower_irq_rx();
+        qemu_irq_lower(s->rx_irq);
+    }
+}
+
+static ssize_t minimac2_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    uint32_t r_count;
+    uint32_t r_state;
+    uint8_t *rx_buf;
+
+    size_t frame_size;
+
+    trace_milkymist_minimac2_rx_frame(buf, size);
+
+    /* choose appropriate slot */
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        r_count = R_COUNT0;
+        r_state = R_STATE0;
+        rx_buf = s->rx0_buf;
+    } else if (s->regs[R_STATE1] == STATE_LOADED) {
+        r_count = R_COUNT1;
+        r_state = R_STATE1;
+        rx_buf = s->rx1_buf;
+    } else {
+        trace_milkymist_minimac2_drop_rx_frame(buf);
+        return size;
+    }
+
+    /* assemble frame */
+    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
+
+    if (frame_size == 0) {
+        return size;
+    }
+
+    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
+
+    /* update slot */
+    s->regs[r_count] = frame_size;
+    s->regs[r_state] = STATE_PENDING;
+
+    update_rx_interrupt(s);
+
+    return size;
+}
+
+static uint32_t
+minimac2_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMinimac2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SETUP:
+    case R_MDIO:
+    case R_STATE0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_COUNT1:
+    case R_TXCOUNT:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_minimac2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_minimac2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+minimac2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMinimac2State *s = opaque;
+
+    trace_milkymist_minimac2_memory_read(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_MDIO:
+    {
+        /* MDIO_DI is read only */
+        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
+        s->regs[R_MDIO] = value;
+        if (mdio_di) {
+            s->regs[R_MDIO] |= mdio_di;
+        } else {
+            s->regs[R_MDIO] &= ~mdio_di;
+        }
+
+        minimac2_update_mdio(s);
+    } break;
+    case R_TXCOUNT:
+        s->regs[addr] = value;
+        if (value > 0) {
+            minimac2_tx(s);
+        }
+        break;
+    case R_STATE0:
+    case R_STATE1:
+        s->regs[addr] = value;
+        update_rx_interrupt(s);
+        break;
+    case R_SETUP:
+    case R_COUNT0:
+    case R_COUNT1:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_minimac2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const minimac2_read_fn[] = {
+    NULL,
+    NULL,
+    &minimac2_read,
+};
+
+static CPUWriteMemoryFunc * const minimac2_write_fn[] = {
+    NULL,
+    NULL,
+    &minimac2_write,
+};
+
+static int minimac2_can_rx(VLANClientState *nc)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE1] == STATE_LOADED) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void minimac2_cleanup(VLANClientState *nc)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static void milkymist_minimac2_reset(DeviceState *d)
+{
+    MilkymistMinimac2State *s =
+            container_of(d, MilkymistMinimac2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < R_PHY_MAX; i++) {
+        s->phy_regs[i] = 0;
+    }
+
+    /* defaults */
+    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
+    s->phy_regs[R_PHY_ID2] = 0x161a;
+}
+
+static NetClientInfo net_milkymist_minimac2_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = minimac2_can_rx,
+    .receive = minimac2_rx,
+    .cleanup = minimac2_cleanup,
+};
+
+static int milkymist_minimac2_init(SysBusDevice *dev)
+{
+    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
+    int regs;
+    ram_addr_t buffers;
+    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    regs = cpu_register_io_memory(minimac2_read_fn, minimac2_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, regs);
+
+    /* register buffers memory */
+    buffers = qemu_ram_alloc(NULL, "milkymist_minimac2.buffers", buffers_size);
+    s->rx0_buf = qemu_get_ram_ptr(buffers);
+    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
+    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
+
+    cpu_register_physical_memory(s->buffers_base, buffers_size,
+            buffers | IO_MEM_RAM);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
+    .name = "milkymist-minimac2-mdio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
+        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
+        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_milkymist_minimac2 = {
+    .name = "milkymist-minimac2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
+        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
+        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
+                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_minimac2_info = {
+    .init = milkymist_minimac2_init,
+    .qdev.name  = "milkymist-minimac2",
+    .qdev.size  = sizeof(MilkymistMinimac2State),
+    .qdev.vmsd  = &vmstate_milkymist_minimac2,
+    .qdev.reset = milkymist_minimac2_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
+                buffers_base, 0),
+        DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+        DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_minimac2_register(void)
+{
+    sysbus_register_withprop(&milkymist_minimac2_info);
+}
+
+device_init(milkymist_minimac2_register)
diff --git a/qemu-0.15.x/hw/milkymist-pfpu.c b/qemu-0.15.x/hw/milkymist-pfpu.c
new file mode 100644
index 0000000..306d1ce
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-pfpu.c
@@ -0,0 +1,536 @@
+/*
+ *  QEMU model of the Milkymist programmable FPU.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/pfpu.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "qemu-error.h"
+#include <math.h>
+
+/* #define TRACE_EXEC */
+
+#ifdef TRACE_EXEC
+#    define D_EXEC(x) x
+#else
+#    define D_EXEC(x)
+#endif
+
+enum {
+    R_CTL = 0,
+    R_MESHBASE,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_CODEPAGE,
+    R_VERTICES,
+    R_COLLISIONS,
+    R_STRAYWRITES,
+    R_LASTDMA,
+    R_PC,
+    R_DREGBASE,
+    R_CODEBASE,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY = (1<<0),
+};
+
+enum {
+    OP_NOP = 0,
+    OP_FADD,
+    OP_FSUB,
+    OP_FMUL,
+    OP_FABS,
+    OP_F2I,
+    OP_I2F,
+    OP_VECTOUT,
+    OP_SIN,
+    OP_COS,
+    OP_ABOVE,
+    OP_EQUAL,
+    OP_COPY,
+    OP_IF,
+    OP_TSIGN,
+    OP_QUAKE,
+};
+
+enum {
+    GPR_X = 0,
+    GPR_Y = 1,
+    GPR_FLAGS = 2,
+};
+
+enum {
+    LATENCY_FADD = 5,
+    LATENCY_FSUB = 5,
+    LATENCY_FMUL = 7,
+    LATENCY_FABS = 2,
+    LATENCY_F2I = 2,
+    LATENCY_I2F = 3,
+    LATENCY_VECTOUT = 0,
+    LATENCY_SIN = 4,
+    LATENCY_COS = 4,
+    LATENCY_ABOVE = 2,
+    LATENCY_EQUAL = 2,
+    LATENCY_COPY = 2,
+    LATENCY_IF = 2,
+    LATENCY_TSIGN = 2,
+    LATENCY_QUAKE = 2,
+    MAX_LATENCY = 7
+};
+
+#define GPR_BEGIN       0x100
+#define GPR_END         0x17f
+#define MICROCODE_BEGIN 0x200
+#define MICROCODE_END   0x3ff
+#define MICROCODE_WORDS 2048
+
+#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
+
+#ifdef TRACE_EXEC
+static const char *opcode_to_str[] = {
+    "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
+    "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
+};
+#endif
+
+struct MilkymistPFPUState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+    uint32_t gp_regs[128];
+    uint32_t microcode[MICROCODE_WORDS];
+
+    int output_queue_pos;
+    uint32_t output_queue[MAX_LATENCY];
+};
+typedef struct MilkymistPFPUState MilkymistPFPUState;
+
+static inline target_phys_addr_t
+get_dma_address(uint32_t base, uint32_t x, uint32_t y)
+{
+    return base + 8 * (128 * y + x);
+}
+
+static inline void
+output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
+{
+    s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
+}
+
+static inline uint32_t
+output_queue_remove(MilkymistPFPUState *s)
+{
+    return s->output_queue[s->output_queue_pos];
+}
+
+static inline void
+output_queue_advance(MilkymistPFPUState *s)
+{
+    s->output_queue[s->output_queue_pos] = 0;
+    s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
+}
+
+static int pfpu_decode_insn(MilkymistPFPUState *s)
+{
+    uint32_t pc = s->regs[R_PC];
+    uint32_t insn = s->microcode[pc];
+    uint32_t reg_a = (insn >> 18) & 0x7f;
+    uint32_t reg_b = (insn >> 11) & 0x7f;
+    uint32_t op = (insn >> 7) & 0xf;
+    uint32_t reg_d = insn & 0x7f;
+    uint32_t r = 0;
+    int latency = 0;
+
+    switch (op) {
+    case OP_NOP:
+        break;
+    case OP_FADD:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a + b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FADD;
+        D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FSUB:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a - b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FSUB;
+        D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FMUL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a * b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FMUL;
+        D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FABS:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float t = fabsf(a);
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FABS;
+        D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_F2I:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        int32_t t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_F2I;
+        D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
+    } break;
+    case OP_I2F:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_I2F;
+        D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_VECTOUT:
+    {
+        uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
+        uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
+        target_phys_addr_t dma_ptr =
+            get_dma_address(s->regs[R_MESHBASE],
+                    s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
+        cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4);
+        cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4);
+        s->regs[R_LASTDMA] = dma_ptr + 4;
+        D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
+        trace_milkymist_pfpu_vectout(a, b, dma_ptr);
+    } break;
+    case OP_SIN:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_SIN;
+        D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_COS:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_COS;
+        D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_ABOVE:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a > b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_ABOVE;
+        D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_EQUAL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a == b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_EQUAL;
+        D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_COPY:
+    {
+        r = s->gp_regs[reg_a];
+        latency = LATENCY_COPY;
+        D_EXEC(qemu_log("COPY"));
+    } break;
+    case OP_IF:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        uint32_t f = s->gp_regs[GPR_FLAGS];
+        float t = (f != 0) ? a : b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_IF;
+        D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
+    } break;
+    case OP_TSIGN:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (b < 0) ? -a : a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_TSIGN;
+        D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_QUAKE:
+    {
+        uint32_t a = s->gp_regs[reg_a];
+        r = 0x5f3759df - (a >> 1);
+        latency = LATENCY_QUAKE;
+        D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
+    } break;
+
+    default:
+        error_report("milkymist_pfpu: unknown opcode %d", op);
+        break;
+    }
+
+    if (!reg_d) {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency));
+    } else {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency, reg_d));
+    }
+
+    if (op == OP_VECTOUT) {
+        return 0;
+    }
+
+    /* store output for this cycle */
+    if (reg_d) {
+        uint32_t val = output_queue_remove(s);
+        D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
+        s->gp_regs[reg_d] = val;
+    }
+
+    output_queue_advance(s);
+
+    /* store op output */
+    if (op != OP_NOP) {
+        output_queue_insert(s, r, latency-1);
+    }
+
+    /* advance PC */
+    s->regs[R_PC]++;
+
+    return 1;
+};
+
+static void pfpu_start(MilkymistPFPUState *s)
+{
+    int x, y;
+    int i;
+
+    for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
+        for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
+            D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
+
+            /* set current position */
+            s->gp_regs[GPR_X] = x;
+            s->gp_regs[GPR_Y] = y;
+
+            /* run microcode on this position */
+            i = 0;
+            while (pfpu_decode_insn(s)) {
+                /* decode at most MICROCODE_WORDS instructions */
+                if (i++ >= MICROCODE_WORDS) {
+                    error_report("milkymist_pfpu: too many instructions "
+                            "executed in microcode. No VECTOUT?");
+                    break;
+                }
+            }
+
+            /* reset pc for next run */
+            s->regs[R_PC] = 0;
+        }
+    }
+
+    s->regs[R_VERTICES] = x * y;
+
+    trace_milkymist_pfpu_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
+{
+    return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
+}
+
+static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistPFPUState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        r = s->regs[addr];
+        break;
+    case GPR_BEGIN ... GPR_END:
+        r = s->gp_regs[addr - GPR_BEGIN];
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        r = s->microcode[get_microcode_address(s, addr)];
+        break;
+
+    default:
+        error_report("milkymist_pfpu: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_pfpu_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistPFPUState *s = opaque;
+
+    trace_milkymist_pfpu_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        if (value & CTL_START_BUSY) {
+            pfpu_start(s);
+        }
+        break;
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        s->regs[addr] = value;
+        break;
+    case GPR_BEGIN ...  GPR_END:
+        s->gp_regs[addr - GPR_BEGIN] = value;
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        s->microcode[get_microcode_address(s, addr)] = value;
+        break;
+
+    default:
+        error_report("milkymist_pfpu: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pfpu_read_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_read,
+};
+
+static CPUWriteMemoryFunc * const pfpu_write_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_write,
+};
+
+static void milkymist_pfpu_reset(DeviceState *d)
+{
+    MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < 128; i++) {
+        s->gp_regs[i] = 0;
+    }
+    for (i = 0; i < MICROCODE_WORDS; i++) {
+        s->microcode[i] = 0;
+    }
+    s->output_queue_pos = 0;
+    for (i = 0; i < MAX_LATENCY; i++) {
+        s->output_queue[i] = 0;
+    }
+}
+
+static int milkymist_pfpu_init(SysBusDevice *dev)
+{
+    MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
+    int pfpu_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    pfpu_regs = cpu_register_io_memory(pfpu_read_fn, pfpu_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MICROCODE_END * 4, pfpu_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_pfpu = {
+    .name = "milkymist-pfpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
+        VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
+        VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
+        VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
+        VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_pfpu_info = {
+    .init = milkymist_pfpu_init,
+    .qdev.name  = "milkymist-pfpu",
+    .qdev.size  = sizeof(MilkymistPFPUState),
+    .qdev.vmsd  = &vmstate_milkymist_pfpu,
+    .qdev.reset = milkymist_pfpu_reset,
+};
+
+static void milkymist_pfpu_register(void)
+{
+    sysbus_register_withprop(&milkymist_pfpu_info);
+}
+
+device_init(milkymist_pfpu_register)
diff --git a/qemu-0.15.x/hw/milkymist-softusb.c b/qemu-0.15.x/hw/milkymist-softusb.c
new file mode 100644
index 0000000..abf7b59
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-softusb.c
@@ -0,0 +1,372 @@
+/*
+ *  QEMU model of the Milkymist SoftUSB block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "usb.h"
+#include "qemu-error.h"
+
+enum {
+    R_CTRL = 0,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+#define COMLOC_DEBUG_PRODUCE 0x1000
+#define COMLOC_DEBUG_BASE    0x1001
+#define COMLOC_MEVT_PRODUCE  0x1101
+#define COMLOC_MEVT_BASE     0x1102
+#define COMLOC_KEVT_PRODUCE  0x1142
+#define COMLOC_KEVT_BASE     0x1143
+
+struct MilkymistSoftUsbState {
+    SysBusDevice busdev;
+    USBBus usbbus;
+    USBPort usbport[2];
+    USBDevice *usbdev;
+
+    qemu_irq irq;
+
+    /* device properties */
+    uint32_t pmem_base;
+    uint32_t pmem_size;
+    uint32_t dmem_base;
+    uint32_t dmem_size;
+
+    /* device registers */
+    uint32_t regs[R_MAX];
+
+    /* mouse state */
+    int mouse_dx;
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons_state;
+
+    /* keyboard state */
+    uint8_t kbd_usb_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSoftUsbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_softusb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_softusb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    trace_milkymist_softusb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_softusb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const softusb_read_fn[] = {
+    NULL,
+    NULL,
+    &softusb_read,
+};
+
+static CPUWriteMemoryFunc * const softusb_write_fn[] = {
+    NULL,
+    NULL,
+    &softusb_write,
+};
+
+static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: read dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: write dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: read pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->pmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: write pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+    uint8_t buf[4];
+
+    buf[0] = s->mouse_buttons_state;
+    buf[1] = s->mouse_dx;
+    buf[2] = s->mouse_dy;
+    buf[3] = s->mouse_dz;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4);
+    m = (m + 1) & 0xf;
+    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_kevt(m);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8);
+    m = (m + 1) & 0x7;
+    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_mouse_event(void *opaque,
+       int dx, int dy, int dz, int buttons_state)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state);
+
+    s->mouse_dx = dx;
+    s->mouse_dy = dy;
+    s->mouse_dz = dz;
+    s->mouse_buttons_state = buttons_state;
+
+    softusb_mouse_changed(s);
+}
+
+static void softusb_usbdev_datain(void *opaque)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    USBPacket p;
+
+    p.pid = USB_TOKEN_IN;
+    p.devep = 1;
+    p.data = s->kbd_usb_buffer;
+    p.len = sizeof(s->kbd_usb_buffer);
+    s->usbdev->info->handle_data(s->usbdev, &p);
+
+    softusb_kbd_changed(s);
+}
+
+static void softusb_attach(USBPort *port)
+{
+}
+
+static void softusb_detach(USBPort *port)
+{
+}
+
+static void softusb_child_detach(USBPort *port, USBDevice *child)
+{
+}
+
+static USBPortOps softusb_ops = {
+    .attach = softusb_attach,
+    .detach = softusb_detach,
+    .child_detach = softusb_child_detach,
+};
+
+static USBBusOps softusb_bus_ops = {
+};
+
+static void milkymist_softusb_reset(DeviceState *d)
+{
+    MilkymistSoftUsbState *s =
+            container_of(d, MilkymistSoftUsbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    s->mouse_dx = 0;
+    s->mouse_dy = 0;
+    s->mouse_dz = 0;
+    s->mouse_buttons_state = 0;
+    memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer));
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int softusb_regs;
+    ram_addr_t pmem_ram;
+    ram_addr_t dmem_ram;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, softusb_regs);
+
+    /* register pmem and dmem */
+    pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size);
+    cpu_register_physical_memory(s->pmem_base, s->pmem_size,
+            pmem_ram | IO_MEM_RAM);
+    dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size);
+    cpu_register_physical_memory(s->dmem_base, s->dmem_size,
+            dmem_ram | IO_MEM_RAM);
+
+    qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
+
+    /* create our usb bus */
+    usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
+
+    /* our two ports */
+    /* FIXME: claim to support full speed devices. qemu mouse and keyboard
+     * report themselves as full speed devices. */
+    usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+    usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+
+    /* and finally create an usb keyboard */
+    s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
+    usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain);
+    s->usbdev->info->handle_reset(s->usbdev);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_softusb = {
+    .name = "milkymist-softusb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
+        VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState),
+        VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_softusb_info = {
+    .init = milkymist_softusb_init,
+    .qdev.name  = "milkymist-softusb",
+    .qdev.size  = sizeof(MilkymistSoftUsbState),
+    .qdev.vmsd  = &vmstate_milkymist_softusb,
+    .qdev.reset = milkymist_softusb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
+        ),
+        DEFINE_PROP_UINT32(
+                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_softusb_register(void)
+{
+    sysbus_register_withprop(&milkymist_softusb_info);
+}
+
+device_init(milkymist_softusb_register)
diff --git a/qemu-0.15.x/hw/milkymist-sysctl.c b/qemu-0.15.x/hw/milkymist-sysctl.c
new file mode 100644
index 0000000..7b2d544
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-sysctl.c
@@ -0,0 +1,318 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/sysctl.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-timer.h"
+#include "qemu-error.h"
+
+enum {
+    CTRL_ENABLE      = (1<<0),
+    CTRL_AUTORESTART = (1<<1),
+};
+
+enum {
+    ICAP_READY       = (1<<0),
+};
+
+enum {
+    R_GPIO_IN = 0,
+    R_GPIO_OUT,
+    R_GPIO_INTEN,
+    R_RESERVED0,
+    R_TIMER0_CONTROL,
+    R_TIMER0_COMPARE,
+    R_TIMER0_COUNTER,
+    R_RESERVED1,
+    R_TIMER1_CONTROL,
+    R_TIMER1_COMPARE,
+    R_TIMER1_COUNTER,
+    R_RESERVED2,
+    R_RESERVED3,
+    R_ICAP,
+    R_CAPABILITIES,
+    R_SYSTEM_ID,
+    R_MAX
+};
+
+struct MilkymistSysctlState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh0;
+    QEMUBH *bh1;
+    ptimer_state *ptimer0;
+    ptimer_state *ptimer1;
+
+    uint32_t freq_hz;
+    uint32_t capabilities;
+    uint32_t systemid;
+    uint32_t strappings;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq gpio_irq;
+    qemu_irq timer0_irq;
+    qemu_irq timer1_irq;
+};
+typedef struct MilkymistSysctlState MilkymistSysctlState;
+
+static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
+{
+    trace_milkymist_sysctl_icap_write(value);
+    switch (value & 0xffff) {
+    case 0x000e:
+        qemu_system_shutdown_request();
+        break;
+    }
+}
+
+static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSysctlState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_TIMER0_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer0);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER0_COMPARE] - r;
+        break;
+    case R_TIMER1_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer1);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER1_COMPARE] - r;
+        break;
+    case R_GPIO_IN:
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_CONTROL:
+    case R_TIMER0_COMPARE:
+    case R_TIMER1_CONTROL:
+    case R_TIMER1_COMPARE:
+    case R_ICAP:
+    case R_CAPABILITIES:
+    case R_SYSTEM_ID:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_sysctl: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_sysctl_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSysctlState *s = opaque;
+
+    trace_milkymist_sysctl_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_COUNTER:
+    case R_TIMER1_COUNTER:
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_COMPARE:
+        ptimer_set_limit(s->ptimer0, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER1_COMPARE:
+        ptimer_set_limit(s->ptimer1, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer0();
+            ptimer_set_count(s->ptimer0,
+                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
+            ptimer_run(s->ptimer0, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer0();
+            ptimer_stop(s->ptimer0);
+        }
+        break;
+    case R_TIMER1_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_set_count(s->ptimer1,
+                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
+            ptimer_run(s->ptimer1, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer1);
+        }
+        break;
+    case R_ICAP:
+        sysctl_icap_write(s, value);
+        break;
+    case R_SYSTEM_ID:
+        qemu_system_reset_request();
+        break;
+
+    case R_GPIO_IN:
+    case R_CAPABILITIES:
+        error_report("milkymist_sysctl: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_sysctl: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sysctl_read_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_read,
+};
+
+static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_write,
+};
+
+static void timer0_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer0();
+        ptimer_stop(s->ptimer0);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer0();
+    qemu_irq_pulse(s->timer0_irq);
+}
+
+static void timer1_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer1();
+        ptimer_stop(s->ptimer1);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer1();
+    qemu_irq_pulse(s->timer1_irq);
+}
+
+static void milkymist_sysctl_reset(DeviceState *d)
+{
+    MilkymistSysctlState *s =
+            container_of(d, MilkymistSysctlState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    ptimer_stop(s->ptimer0);
+    ptimer_stop(s->ptimer1);
+
+    /* defaults */
+    s->regs[R_ICAP] = ICAP_READY;
+    s->regs[R_SYSTEM_ID] = s->systemid;
+    s->regs[R_CAPABILITIES] = s->capabilities;
+    s->regs[R_GPIO_IN] = s->strappings;
+}
+
+static int milkymist_sysctl_init(SysBusDevice *dev)
+{
+    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sysctl_regs;
+
+    sysbus_init_irq(dev, &s->gpio_irq);
+    sysbus_init_irq(dev, &s->timer0_irq);
+    sysbus_init_irq(dev, &s->timer1_irq);
+
+    s->bh0 = qemu_bh_new(timer0_hit, s);
+    s->bh1 = qemu_bh_new(timer1_hit, s);
+    s->ptimer0 = ptimer_init(s->bh0);
+    s->ptimer1 = ptimer_init(s->bh1);
+    ptimer_set_freq(s->ptimer0, s->freq_hz);
+    ptimer_set_freq(s->ptimer1, s->freq_hz);
+
+    sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_sysctl = {
+    .name = "milkymist-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
+        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
+        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_sysctl_info = {
+    .init = milkymist_sysctl_init,
+    .qdev.name  = "milkymist-sysctl",
+    .qdev.size  = sizeof(MilkymistSysctlState),
+    .qdev.vmsd  = &vmstate_milkymist_sysctl,
+    .qdev.reset = milkymist_sysctl_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+                freq_hz, 80000000),
+        DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+                capabilities, 0x00000000),
+        DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+                systemid, 0x10014d31),
+        DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+                strappings, 0x00000001),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_sysctl_register(void)
+{
+    sysbus_register_withprop(&milkymist_sysctl_info);
+}
+
+device_init(milkymist_sysctl_register)
diff --git a/qemu-0.15.x/hw/milkymist-tmu2.c b/qemu-0.15.x/hw/milkymist-tmu2.c
new file mode 100644
index 0000000..790cdcb
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-tmu2.c
@@ -0,0 +1,481 @@
+/*
+ *  QEMU model of the Milkymist texture mapping unit.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *  Copyright (c) 2010 Sebastien Bourdeauducq
+ *                       <sebastien.bourdeauducq at lekernel.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/tmu2.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+enum {
+    R_CTL = 0,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_BRIGHTNESS,
+    R_CHROMAKEY,
+    R_VERTICESADDR,
+    R_TEXFBUF,
+    R_TEXHRES,
+    R_TEXVRES,
+    R_TEXHMASK,
+    R_TEXVMASK,
+    R_DSTFBUF,
+    R_DSTHRES,
+    R_DSTVRES,
+    R_DSTHOFFSET,
+    R_DSTVOFFSET,
+    R_DSTSQUAREW,
+    R_DSTSQUAREH,
+    R_ALPHA,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY  = (1<<0),
+    CTL_CHROMAKEY   = (1<<1),
+};
+
+enum {
+    MAX_BRIGHTNESS = 63,
+    MAX_ALPHA      = 63,
+};
+
+enum {
+    MESH_MAXSIZE = 128,
+};
+
+struct vertex {
+    int x;
+    int y;
+} __attribute__((packed));
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+
+    Display *dpy;
+    GLXFBConfig glx_fb_config;
+    GLXContext glx_context;
+};
+typedef struct MilkymistTMU2State MilkymistTMU2State;
+
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+
+static int tmu2_glx_init(MilkymistTMU2State *s)
+{
+    GLXFBConfig *configs;
+    int nelements;
+
+    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
+    if (s->dpy == NULL) {
+        return 1;
+    }
+
+    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        return 1;
+    }
+
+    s->glx_fb_config = *configs;
+    XFree(configs);
+
+    /* FIXME: call glXDestroyContext() */
+    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
+            GLX_RGBA_TYPE, NULL, 1);
+    if (s->glx_context == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
+        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
+{
+    int x, y;
+    int x0, y0, x1, y1;
+    int u0, v0, u1, v1, u2, v2, u3, v3;
+    double xscale = 1.0 / ((double)(64 * texhres));
+    double yscale = 1.0 / ((double)(64 * texvres));
+
+    glLoadIdentity();
+    glTranslatef(ho, vo, 0);
+    glEnable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+
+    for (y = 0; y < vmeshlast; y++) {
+        y0 = y * sh;
+        y1 = y0 + sh;
+        for (x = 0; x < hmeshlast; x++) {
+            x0 = x * sw;
+            x1 = x0 + sw;
+
+            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
+            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
+            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
+            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
+            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
+            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
+            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
+            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
+
+            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
+            glVertex3i(x0, y0, 0);
+            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
+            glVertex3i(x1, y0, 0);
+            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
+            glVertex3i(x1, y1, 0);
+            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
+            glVertex3i(x0, y1, 0);
+        }
+    }
+
+    glEnd();
+}
+
+static void tmu2_start(MilkymistTMU2State *s)
+{
+    int pbuffer_attrib[6] = {
+        GLX_PBUFFER_WIDTH,
+        0,
+        GLX_PBUFFER_HEIGHT,
+        0,
+        GLX_PRESERVED_CONTENTS,
+        True
+    };
+
+    GLXPbuffer pbuffer;
+    GLuint texture;
+    void *fb;
+    target_phys_addr_t fb_len;
+    void *mesh;
+    target_phys_addr_t mesh_len;
+    float m;
+
+    trace_milkymist_tmu2_start();
+
+    /* Create and set up a suitable OpenGL context */
+    pbuffer_attrib[1] = s->regs[R_DSTHRES];
+    pbuffer_attrib[3] = s->regs[R_DSTVRES];
+    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
+    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
+
+    /* Fixup endianness. TODO: would it work on BE hosts? */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
+
+    /* Row alignment */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_PACK_ALIGNMENT, 2);
+
+    /* Read the QEMU source framebuffer into an OpenGL texture */
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
+    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+
+    /* Set up texturing options */
+    /* WARNING:
+     * Many cases of TMU2 masking are not supported by OpenGL.
+     * We only implement the most common ones:
+     *  - full bilinear filtering vs. nearest texel
+     *  - texture clamping vs. texture wrapping
+     */
+    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    /* Translucency and decay */
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
+    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
+
+    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+
+    /* Map the texture */
+    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
+    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
+    if (mesh == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    tmu2_gl_map((struct vertex *)mesh,
+        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
+        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
+        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
+    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
+
+    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
+
+    /* Free OpenGL allocs */
+    glDeleteTextures(1, &texture);
+    glXMakeContextCurrent(s->dpy, None, None, NULL);
+    glXDestroyPbuffer(s->dpy, pbuffer);
+
+    s->regs[R_CTL] &= ~CTL_START_BUSY;
+
+    trace_milkymist_tmu2_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistTMU2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_BRIGHTNESS:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_tmu2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_tmu2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void tmu2_check_registers(MilkymistTMU2State *s)
+{
+    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
+        error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned");
+    }
+}
+
+static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistTMU2State *s = opaque;
+
+    trace_milkymist_tmu2_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        s->regs[addr] = value;
+        if (value & CTL_START_BUSY) {
+            tmu2_start(s);
+        }
+        break;
+    case R_BRIGHTNESS:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_tmu2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    tmu2_check_registers(s);
+}
+
+static CPUReadMemoryFunc * const tmu2_read_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_read,
+};
+
+static CPUWriteMemoryFunc * const tmu2_write_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_write,
+};
+
+static void milkymist_tmu2_reset(DeviceState *d)
+{
+    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_tmu2_init(SysBusDevice *dev)
+{
+    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
+    int tmu2_regs;
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    tmu2_regs = cpu_register_io_memory(tmu2_read_fn, tmu2_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, tmu2_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_tmu2 = {
+    .name = "milkymist-tmu2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_tmu2_info = {
+    .init = milkymist_tmu2_init,
+    .qdev.name  = "milkymist-tmu2",
+    .qdev.size  = sizeof(MilkymistTMU2State),
+    .qdev.vmsd  = &vmstate_milkymist_tmu2,
+    .qdev.reset = milkymist_tmu2_reset,
+};
+
+static void milkymist_tmu2_register(void)
+{
+    sysbus_register_withprop(&milkymist_tmu2_info);
+}
+
+device_init(milkymist_tmu2_register)
diff --git a/qemu-0.15.x/hw/milkymist-uart.c b/qemu-0.15.x/hw/milkymist-uart.c
new file mode 100644
index 0000000..56c90da
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-uart.c
@@ -0,0 +1,180 @@
+/*
+ *  QEMU model of the Milkymist UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/uart.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+#include "qemu-error.h"
+
+enum {
+    R_RXTX = 0,
+    R_DIV,
+    R_MAX
+};
+
+struct MilkymistUartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistUartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+    case R_DIV:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_uart_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistUartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_milkymist_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_write(s->chr, &ch, 1);
+        }
+        trace_milkymist_uart_pulse_irq_tx();
+        qemu_irq_pulse(s->tx_irq);
+        break;
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const uart_read_fn[] = {
+    NULL,
+    NULL,
+    &uart_read,
+};
+
+static CPUWriteMemoryFunc * const uart_write_fn[] = {
+    NULL,
+    NULL,
+    &uart_write,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    MilkymistUartState *s = opaque;
+
+    s->regs[R_RXTX] = *buf;
+    trace_milkymist_uart_pulse_irq_rx();
+    qemu_irq_pulse(s->rx_irq);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    return 1;
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void milkymist_uart_reset(DeviceState *d)
+{
+    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_uart = {
+    .name = "milkymist-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_uart_info = {
+    .init = milkymist_uart_init,
+    .qdev.name  = "milkymist-uart",
+    .qdev.size  = sizeof(MilkymistUartState),
+    .qdev.vmsd  = &vmstate_milkymist_uart,
+    .qdev.reset = milkymist_uart_reset,
+};
+
+static void milkymist_uart_register(void)
+{
+    sysbus_register_withprop(&milkymist_uart_info);
+}
+
+device_init(milkymist_uart_register)
diff --git a/qemu-0.15.x/hw/milkymist-vgafb.c b/qemu-0.15.x/hw/milkymist-vgafb.c
new file mode 100644
index 0000000..2e55e42
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-vgafb.c
@@ -0,0 +1,321 @@
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "framebuffer.h"
+#include "pixel_ops.h"
+#include "qemu-error.h"
+
+#define BITS 8
+#include "milkymist-vgafb_template.h"
+#define BITS 15
+#include "milkymist-vgafb_template.h"
+#define BITS 16
+#include "milkymist-vgafb_template.h"
+#define BITS 24
+#include "milkymist-vgafb_template.h"
+#define BITS 32
+#include "milkymist-vgafb_template.h"
+
+enum {
+    R_CTRL = 0,
+    R_HRES,
+    R_HSYNC_START,
+    R_HSYNC_END,
+    R_HSCAN,
+    R_VRES,
+    R_VSYNC_START,
+    R_VSYNC_END,
+    R_VSCAN,
+    R_BASEADDRESS,
+    R_BASEADDRESS_ACT,
+    R_BURST_COUNT,
+    R_SOURCE_CLOCK,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+struct MilkymistVgafbState {
+    SysBusDevice busdev;
+    DisplayState *ds;
+
+    int invalidate;
+    uint32_t fb_offset;
+    uint32_t fb_mask;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistVgafbState MilkymistVgafbState;
+
+static int vgafb_enabled(MilkymistVgafbState *s)
+{
+    return !(s->regs[R_CTRL] & CTRL_RESET);
+}
+
+static void vgafb_update_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    int dest_width = s->regs[R_HRES];
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 8:
+        fn = draw_line_8;
+        break;
+    case 15:
+        fn = draw_line_15;
+        dest_width *= 2;
+        break;
+    case 16:
+        fn = draw_line_16;
+        dest_width *= 2;
+        break;
+    case 24:
+        fn = draw_line_24;
+        dest_width *= 3;
+        break;
+    case 32:
+        fn = draw_line_32;
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+    framebuffer_update_display(s->ds,
+                               s->regs[R_BASEADDRESS] + s->fb_offset,
+                               s->regs[R_HRES],
+                               s->regs[R_VRES],
+                               s->regs[R_HRES] * 2,
+                               dest_width,
+                               0,
+                               s->invalidate,
+                               fn,
+                               NULL,
+                               &first, &last);
+
+    if (first >= 0) {
+        dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void vgafb_invalidate_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    s->invalidate = 1;
+}
+
+static void vgafb_resize(MilkymistVgafbState *s)
+{
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]);
+    s->invalidate = 1;
+}
+
+static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistVgafbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HRES:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VRES:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BASEADDRESS:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        r = s->regs[addr];
+    break;
+    case R_BASEADDRESS_ACT:
+        r = s->regs[R_BASEADDRESS];
+    break;
+
+    default:
+        error_report("milkymist_vgafb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_vgafb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistVgafbState *s = opaque;
+
+    trace_milkymist_vgafb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        s->regs[addr] = value;
+        break;
+    case R_BASEADDRESS:
+        if (value & 0x1f) {
+            error_report("milkymist_vgafb: framebuffer base address have to "
+                     "be 32 byte aligned");
+            break;
+        }
+        s->regs[addr] = value & s->fb_mask;
+        s->invalidate = 1;
+        break;
+    case R_HRES:
+    case R_VRES:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_BASEADDRESS_ACT:
+        error_report("milkymist_vgafb: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_vgafb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const vgafb_read_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_read
+};
+
+static CPUWriteMemoryFunc * const vgafb_write_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_write
+};
+
+static void milkymist_vgafb_reset(DeviceState *d)
+{
+    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+    s->regs[R_HRES] = 640;
+    s->regs[R_VRES] = 480;
+    s->regs[R_BASEADDRESS] = 0;
+}
+
+static int milkymist_vgafb_init(SysBusDevice *dev)
+{
+    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int vgafb_regs;
+
+    vgafb_regs = cpu_register_io_memory(vgafb_read_fn, vgafb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, vgafb_regs);
+
+    s->ds = graphic_console_init(vgafb_update_display,
+                                 vgafb_invalidate_display,
+                                 NULL, NULL, s);
+
+    return 0;
+}
+
+static int vgafb_post_load(void *opaque, int version_id)
+{
+    vgafb_invalidate_display(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_vgafb = {
+    .name = "milkymist-vgafb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vgafb_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_vgafb_info = {
+    .init = milkymist_vgafb_init,
+    .qdev.name  = "milkymist-vgafb",
+    .qdev.size  = sizeof(MilkymistVgafbState),
+    .qdev.vmsd  = &vmstate_milkymist_vgafb,
+    .qdev.reset = milkymist_vgafb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+        DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_vgafb_register(void)
+{
+    sysbus_register_withprop(&milkymist_vgafb_info);
+}
+
+device_init(milkymist_vgafb_register)
diff --git a/qemu-0.15.x/hw/milkymist-vgafb_template.h b/qemu-0.15.x/hw/milkymist-vgafb_template.h
new file mode 100644
index 0000000..69af9ef
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist-vgafb_template.h
@@ -0,0 +1,74 @@
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if BITS == 8
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *to = rgb_to_pixel8(r, g, b);              \
+        to += 1;                                   \
+    } while (0)
+#elif BITS == 15
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 16
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 24
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        uint32 tmp = rgb_to_pixel24(r, g, b);      \
+        *(to++) =         tmp & 0xff;              \
+        *(to++) =  (tmp >> 8) & 0xff;              \
+        *(to++) = (tmp >> 16) & 0xff;              \
+    } while (0)
+#elif BITS == 32
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
+        to += 4;                                   \
+    } while (0)
+#else
+#error unknown bit depth
+#endif
+
+static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
+        int width, int deststep)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    while (width--) {
+        rgb565 = lduw_raw(s);
+        r = ((rgb565 >> 11) & 0x1f) << 3;
+        g = ((rgb565 >>  5) & 0x3f) << 2;
+        b = ((rgb565 >>  0) & 0x1f) << 3;
+        COPY_PIXEL(d, r, g, b);
+        s += 2;
+    }
+}
+
+#undef BITS
+#undef COPY_PIXEL
diff --git a/qemu-0.15.x/hw/milkymist.c b/qemu-0.15.x/hw/milkymist.c
new file mode 100644
index 0000000..7879840
--- /dev/null
+++ b/qemu-0.15.x/hw/milkymist.c
@@ -0,0 +1,216 @@
+/*
+ *  QEMU model for the Milkymist board.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "milkymist-hw.h"
+#include "lm32.h"
+
+#define BIOS_FILENAME    "mmone-bios.bin"
+#define BIOS_OFFSET      0x00860000
+#define BIOS_SIZE        (512*1024)
+#define KERNEL_LOAD_ADDR 0x40000000
+
+typedef struct {
+    CPUState *env;
+    target_phys_addr_t bootstrap_pc;
+    target_phys_addr_t flash_base;
+    target_phys_addr_t initrd_base;
+    size_t initrd_size;
+    target_phys_addr_t cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPUState *env = reset_info->env;
+
+    cpu_reset(env);
+
+    /* init defaults */
+    env->pc = reset_info->bootstrap_pc;
+    env->regs[R_R1] = reset_info->cmdline_base;
+    env->regs[R_R2] = reset_info->initrd_base;
+    env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void
+milkymist_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    ram_addr_t phys_sdram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+    int i;
+    char *bios_filename;
+    ResetInfo *reset_info;
+
+    /* memory map */
+    target_phys_addr_t flash_base   = 0x00000000;
+    size_t flash_sector_size        = 128 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    target_phys_addr_t sdram_base   = 0x40000000;
+    size_t sdram_size               = 128 * 1024 * 1024;
+
+    target_phys_addr_t initrd_base  = sdram_base + 0x1002000;
+    target_phys_addr_t cmdline_base = sdram_base + 0x1000000;
+    size_t initrd_max = sdram_size - 0x1002000;
+
+    reset_info = qemu_mallocz(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    cpu_lm32_set_phys_msb_ignore(env, 1);
+
+    phys_sdram = qemu_ram_alloc(NULL, "milkymist.sdram", sdram_size);
+    cpu_register_physical_memory(sdram_base, sdram_size,
+            phys_sdram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "milkymist.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Numonyx JS28F256J3F105 */
+    pflash_cfi01_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 2,
+                          0x00, 0x89, 0x00, 0x1d, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    /* load bios rom */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    if (bios_filename) {
+        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
+    }
+
+    reset_info->bootstrap_pc = BIOS_OFFSET;
+
+    /* if no kernel is given no valid bios rom is a fatal error */
+    if (!kernel_filename && !dinfo && !bios_filename) {
+        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    milkymist_uart_create(0x60000000, irq[0], irq[1]);
+    milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
+            80000000, 0x10014d31, 0x0000041f, 0x00000001);
+    milkymist_hpdmc_create(0x60002000);
+    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
+    milkymist_memcard_create(0x60004000);
+    milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]);
+    milkymist_pfpu_create(0x60006000, irq[9]);
+    milkymist_tmu2_create(0x60007000, irq[10]);
+    milkymist_minimac2_create(0x60008000, 0x30000000, irq[11], irq[12]);
+    milkymist_softusb_create(0x6000f000, irq[17],
+            0x20000000, 0x1000, 0x20020000, 0x2000);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    if (kernel_filename) {
+        uint64_t entry;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, sdram_base,
+                                              sdram_size);
+            reset_info->bootstrap_pc = sdram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = (uint32_t)cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = (uint32_t)initrd_base;
+        reset_info->initrd_size = (uint32_t)initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine milkymist_machine = {
+    .name = "milkymist",
+    .desc = "Milkymist One",
+    .init = milkymist_init,
+    .is_default = 0
+};
+
+static void milkymist_machine_init(void)
+{
+    qemu_register_machine(&milkymist_machine);
+}
+
+machine_init(milkymist_machine_init);
diff --git a/qemu-0.15.x/hw/mips-bios.h b/qemu-0.15.x/hw/mips-bios.h
new file mode 100644
index 0000000..b4b88ac
--- /dev/null
+++ b/qemu-0.15.x/hw/mips-bios.h
@@ -0,0 +1,8 @@
+#include "cpu.h"
+
+#define BIOS_SIZE (4 * 1024 * 1024)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BIOS_FILENAME "mips_bios.bin"
+#else
+#define BIOS_FILENAME "mipsel_bios.bin"
+#endif
diff --git a/qemu-0.15.x/hw/mips.h b/qemu-0.15.x/hw/mips.h
new file mode 100644
index 0000000..cae5f4c
--- /dev/null
+++ b/qemu-0.15.x/hw/mips.h
@@ -0,0 +1,36 @@
+#ifndef HW_MIPS_H
+#define HW_MIPS_H
+/* Definitions for mips board emulation.  */
+
+/* gt64xxx.c */
+PCIBus *gt64120_register(qemu_irq *pic);
+
+/* bonito.c */
+PCIBus *bonito_init(qemu_irq *pic);
+
+/* g364fb.c */
+int g364fb_mm_init(target_phys_addr_t vram_base,
+                   target_phys_addr_t ctrl_base, int it_shift,
+                   qemu_irq irq);
+
+/* mipsnet.c */
+void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
+
+/* jazz_led.c */
+void jazz_led_init(target_phys_addr_t base);
+
+/* rc4030.c */
+typedef struct rc4030DMAState *rc4030_dma;
+void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
+void rc4030_dma_read(void *dma, uint8_t *buf, int len);
+void rc4030_dma_write(void *dma, uint8_t *buf, int len);
+
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+                  qemu_irq **irqs, rc4030_dma **dmas);
+
+/* dp8393x.c */
+void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
+                  qemu_irq irq, void* mem_opaque,
+                  void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write));
+
+#endif
diff --git a/qemu-0.15.x/hw/mips_addr.c b/qemu-0.15.x/hw/mips_addr.c
new file mode 100644
index 0000000..aa1c7d8
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_addr.c
@@ -0,0 +1,34 @@
+/*
+ * QEMU MIPS address translation support
+ *
+ * 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 "hw.h"
+#include "mips_cpudevs.h"
+
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
+{
+    return addr & 0x7fffffffll;
+}
+
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
+{
+    return addr | ~0x7fffffffll;
+}
diff --git a/qemu-0.15.x/hw/mips_cpudevs.h b/qemu-0.15.x/hw/mips_cpudevs.h
new file mode 100644
index 0000000..db82b41
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_cpudevs.h
@@ -0,0 +1,15 @@
+#ifndef HW_MIPS_CPUDEVS_H
+#define HW_MIPS_CPUDEVS_H
+/* Definitions for MIPS CPU internal devices.  */
+
+/* mips_addr.c */
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
+
+/* mips_int.c */
+void cpu_mips_irq_init_cpu(CPUState *env);
+
+/* mips_timer.c */
+void cpu_mips_clock_init(CPUState *);
+
+#endif
diff --git a/qemu-0.15.x/hw/mips_fulong2e.c b/qemu-0.15.x/hw/mips_fulong2e.c
new file mode 100644
index 0000000..420fada
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_fulong2e.c
@@ -0,0 +1,394 @@
+/*
+ * QEMU fulong 2e mini pc support
+ *
+ * Copyright (c) 2008 yajin (yajin at vm-kernel.org)
+ * Copyright (c) 2009 chenming (chenming at rdc.faw.com.cn)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
+ * This code is licensed under the GNU GPL v2.
+ */
+
+/*
+ * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
+ * http://www.linux-mips.org/wiki/Fulong
+ *
+ * Loongson 2e user manual:
+ * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "net.h"
+#include "boards.h"
+#include "smbus.h"
+#include "block.h"
+#include "flash.h"
+#include "mips.h"
+#include "mips_cpudevs.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "audio/audio.h"
+#include "qemu-log.h"
+#include "loader.h"
+#include "mips-bios.h"
+#include "ide.h"
+#include "elf.h"
+#include "vt82c686.h"
+#include "mc146818rtc.h"
+#include "blockdev.h"
+
+#define DEBUG_FULONG2E_INIT
+
+#define ENVP_ADDR       0x80002000l
+#define ENVP_NB_ENTRIES	 	16
+#define ENVP_ENTRY_SIZE	 	256
+
+#define MAX_IDE_BUS 2
+
+/*
+ * PMON is not part of qemu and released with BSD license, anyone
+ * who want to build a pmon binary please first git-clone the source
+ * from the git repository at:
+ * http://www.loongson.cn/support/git/pmon
+ * Then follow the "Compile Guide" available at:
+ * http://dev.lemote.com/code/pmon
+ *
+ * Notes:
+ * 1, don't use the source at http://dev.lemote.com/http_git/pmon.git
+ * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware"
+ * in the "Compile Guide".
+ */
+#define FULONG_BIOSNAME "pmon_fulong2e.bin"
+
+/* PCI SLOT in fulong 2e */
+#define FULONG2E_VIA_SLOT        5
+#define FULONG2E_ATI_SLOT        6
+#define FULONG2E_RTL8139_SLOT    7
+
+static ISADevice *pit;
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
+{
+    va_list ap;
+    int32_t table_addr;
+
+    if (index >= ENVP_NB_ENTRIES)
+        return;
+
+    if (string == NULL) {
+        prom_buf[index] = 0;
+        return;
+    }
+
+    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
+
+    va_start(ap, string);
+    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
+    va_end(ap);
+}
+
+static int64_t load_kernel (CPUState *env)
+{
+    int64_t kernel_entry, kernel_low, kernel_high;
+    int index = 0;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    uint32_t *prom_buf;
+    long prom_size;
+
+    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
+                 (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
+                 (uint64_t *)&kernel_high, 0, ELF_MACHINE, 1) < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                     initrd_offset, ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Setup prom parameters. */
+    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+    prom_buf = qemu_malloc(prom_size);
+
+    prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
+    if (initrd_size > 0) {
+        prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
+                 loaderparams.kernel_cmdline);
+    } else {
+        prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
+    }
+
+    /* Setup minimum environment variables */
+    prom_set(prom_buf, index++, "busclock=33000000");
+    prom_set(prom_buf, index++, "cpuclock=100000000");
+    prom_set(prom_buf, index++, "memsize=%i", loaderparams.ram_size/1024/1024);
+    prom_set(prom_buf, index++, "modetty0=38400n8r");
+    prom_set(prom_buf, index++, NULL);
+
+    rom_add_blob_fixed("prom", prom_buf, prom_size,
+                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
+
+    return kernel_entry;
+}
+
+static void write_bootloader (CPUState *env, uint8_t *base, int64_t kernel_addr)
+{
+    uint32_t *p;
+
+    /* Small bootloader */
+    p = (uint32_t *) base;
+
+    stl_raw(p++, 0x0bf00010);                                      /* j 0x1fc00040 */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* Second part of the bootloader */
+    p = (uint32_t *) (base + 0x040);
+
+    stl_raw(p++, 0x3c040000);                                      /* lui a0, 0 */
+    stl_raw(p++, 0x34840002);                                      /* ori a0, a0, 2 */
+    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
+    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a0, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));      /* lui a3, high(env->ram_size) */
+    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));   /* ori a3, a3, low(env->ram_size) */
+    stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff));     /* lui ra, high(kernel_addr) */;
+    stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff));             /* ori ra, ra, low(kernel_addr) */
+    stl_raw(p++, 0x03e00008);                                      /* jr ra */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+}
+
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    /* TODO: 2E reset stuff */
+    if (loaderparams.kernel_filename) {
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+    }
+}
+
+uint8_t eeprom_spd[0x80] = {
+    0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70,
+    0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01,
+    0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50,
+    0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00,
+    0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32,
+    0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42,
+    0x20,0x30,0x20
+};
+
+/* Audio support */
+static void audio_init (PCIBus *pci_bus)
+{
+    vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
+    vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
+}
+
+/* Network support */
+static void network_init (void)
+{
+    int i;
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        const char *default_devaddr = NULL;
+
+        if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) {
+            /* The fulong board has a RTL8139 card using PCI SLOT 7 */
+            default_devaddr = "07";
+        }
+
+        pci_nic_init_nofail(nd, "rtl8139", default_devaddr);
+    }
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    char *filename;
+    unsigned long ram_offset, bios_offset;
+    long bios_size;
+    int64_t kernel_entry;
+    qemu_irq *i8259;
+    qemu_irq *cpu_exit_irq;
+    int via_devfn;
+    PCIBus *pci_bus;
+    i2c_bus *smbus;
+    int i;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    CPUState *env;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "Loongson-2E";
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    register_savevm(NULL, "cpu", 0, 3, cpu_save, cpu_load, env);
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* fulong 2e has 256M ram. */
+    ram_size = 256 * 1024 * 1024;
+
+    /* fulong 2e has a 1M flash.Winbond W39L040AP70Z */
+    bios_size = 1024 * 1024;
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
+    bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
+
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+    cpu_register_physical_memory(0x1fc00000LL,
+					   bios_size, bios_offset | IO_MEM_ROM);
+
+    /* We do not support flash operation, just loading pmon.bin as raw BIOS.
+     * Please use -L to set the BIOS path and -bios to set bios name. */
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        kernel_entry = load_kernel (env);
+        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+    } else {
+        if (bios_name == NULL) {
+                bios_name = FULONG_BIOSNAME;
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image_targphys(filename, 0x1fc00000LL,
+                                            BIOS_SIZE);
+            qemu_free(filename);
+        } else {
+            bios_size = -1;
+        }
+
+        if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+            fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name);
+            exit(1);
+        }
+    }
+
+    /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Interrupt controller */
+    /* The 8259 -> IP5  */
+    i8259 = i8259_init(env->irq[5]);
+
+    /* North bridge, Bonito --> IP2 */
+    pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
+
+    /* South bridge */
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
+    if (via_devfn < 0) {
+        fprintf(stderr, "vt82c686b_init error \n");
+        exit(1);
+    }
+
+    isa_bus_irqs(i8259);
+    vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
+    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));
+    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));
+
+    smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
+                              0xeee1, NULL);
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
+
+    /* init other devices */
+    pit = pit_init(0x40, 0);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    /* Super I/O */
+    isa_create_simple("i8042");
+
+    rtc_init(2000, NULL);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    if (parallel_hds[0]) {
+        parallel_init(0, parallel_hds[0]);
+    }
+
+    /* Sound card */
+    audio_init(pci_bus);
+    /* Network card */
+    network_init();
+}
+
+QEMUMachine mips_fulong2e_machine = {
+    .name = "fulong2e",
+    .desc = "Fulong 2e mini pc",
+    .init = mips_fulong2e_init,
+};
+
+static void mips_fulong2e_machine_init(void)
+{
+    qemu_register_machine(&mips_fulong2e_machine);
+}
+
+machine_init(mips_fulong2e_machine_init);
diff --git a/qemu-0.15.x/hw/mips_int.c b/qemu-0.15.x/hw/mips_int.c
new file mode 100644
index 0000000..477f6ab
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_int.c
@@ -0,0 +1,65 @@
+/*
+ * QEMU MIPS interrupt support
+ *
+ * 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 "hw.h"
+#include "mips_cpudevs.h"
+#include "cpu.h"
+
+static void cpu_mips_irq_request(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+
+    if (irq < 0 || irq > 7)
+        return;
+
+    if (level) {
+        env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
+    } else {
+        env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
+    }
+
+    if (env->CP0_Cause & CP0Ca_IP_mask) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void cpu_mips_irq_init_cpu(CPUState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+    for (i = 0; i < 8; i++) {
+        env->irq[i] = qi[i];
+    }
+}
+
+void cpu_mips_soft_irq(CPUState *env, int irq, int level)
+{
+    if (irq < 0 || irq > 2) {
+        return;
+    }
+
+    qemu_set_irq(env->irq[irq], level);
+}
diff --git a/qemu-0.15.x/hw/mips_jazz.c b/qemu-0.15.x/hw/mips_jazz.c
new file mode 100644
index 0000000..f6ab6dc
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_jazz.c
@@ -0,0 +1,320 @@
+/*
+ * QEMU MIPS Jazz support
+ *
+ * Copyright (c) 2007-2008 Hervé Poussineau
+ *
+ * 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 "hw.h"
+#include "mips.h"
+#include "mips_cpudevs.h"
+#include "pc.h"
+#include "isa.h"
+#include "fdc.h"
+#include "sysemu.h"
+#include "arch_init.h"
+#include "boards.h"
+#include "net.h"
+#include "esp.h"
+#include "mips-bios.h"
+#include "loader.h"
+#include "mc146818rtc.h"
+#include "blockdev.h"
+#include "sysbus.h"
+
+enum jazz_model_e
+{
+    JAZZ_MAGNUM,
+    JAZZ_PICA61,
+};
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
+static uint32_t rtc_readb(void *opaque, target_phys_addr_t addr)
+{
+    return cpu_inw(0x71);
+}
+
+static void rtc_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outw(0x71, val & 0xff);
+}
+
+static CPUReadMemoryFunc * const rtc_read[3] = {
+    rtc_readb,
+    rtc_readb,
+    rtc_readb,
+};
+
+static CPUWriteMemoryFunc * const rtc_write[3] = {
+    rtc_writeb,
+    rtc_writeb,
+    rtc_writeb,
+};
+
+static void dma_dummy_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+}
+
+static CPUReadMemoryFunc * const dma_dummy_read[3] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const dma_dummy_write[3] = {
+    dma_dummy_writeb,
+    dma_dummy_writeb,
+    dma_dummy_writeb,
+};
+
+#define MAGNUM_BIOS_SIZE_MAX 0x7e000
+#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static
+void mips_jazz_init (ram_addr_t ram_size,
+                     const char *cpu_model,
+                     enum jazz_model_e jazz_model)
+{
+    char *filename;
+    int bios_size, n;
+    CPUState *env;
+    qemu_irq *rc4030, *i8259;
+    rc4030_dma *dmas;
+    void* rc4030_opaque;
+    int s_rtc, s_dma_dummy;
+    NICInfo *nd;
+    DeviceState *dev;
+    SysBusDevice *sysbus;
+    ISADevice *pit;
+    DriveInfo *fds[MAX_FD];
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq *cpu_exit_irq;
+    ram_addr_t ram_offset;
+    ram_addr_t bios_offset;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */
+        cpu_model = "24Kf";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "mips_jazz.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+    bios_offset = qemu_ram_alloc(NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
+    cpu_register_physical_memory(0x1fc00000LL,
+                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    cpu_register_physical_memory(0xfff00000LL,
+                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+    /* load the BIOS image. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = load_image_targphys(filename, 0xfff00000LL,
+                                        MAGNUM_BIOS_SIZE);
+        qemu_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
+        fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Chipset */
+    rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas);
+    s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
+
+    /* ISA devices */
+    i8259 = i8259_init(env->irq[4]);
+    isa_bus_new(NULL);
+    isa_bus_irqs(i8259);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+    pit = pit_init(0x40, 0);
+    pcspk_init(pit);
+
+    /* ISA IO space at 0x90000000 */
+    isa_mmio_init(0x90000000, 0x01000000);
+    isa_mem_base = 0x11000000;
+
+    /* Video card */
+    switch (jazz_model) {
+    case JAZZ_MAGNUM:
+        g364fb_mm_init(0x40000000, 0x60000000, 0, rc4030[3]);
+        break;
+    case JAZZ_PICA61:
+        isa_vga_mm_init(0x40000000, 0x60000000, 0);
+        break;
+    default:
+        break;
+    }
+
+    /* Network controller */
+    for (n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (!nd->model)
+            nd->model = qemu_strdup("dp83932");
+        if (strcmp(nd->model, "dp83932") == 0) {
+            dp83932_init(nd, 0x80001000, 2, rc4030[4],
+                         rc4030_opaque, rc4030_dma_memory_rw);
+            break;
+        } else if (strcmp(nd->model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported NICs: dp83932\n");
+            exit(1);
+        } else {
+            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
+            exit(1);
+        }
+    }
+
+    /* SCSI adapter */
+    esp_init(0x80002000, 0,
+             rc4030_dma_read, rc4030_dma_write, dmas[0],
+             rc4030[5], &esp_reset, &dma_enable);
+
+    /* Floppy */
+    if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
+        fprintf(stderr, "qemu: too many floppy drives\n");
+        exit(1);
+    }
+    for (n = 0; n < MAX_FD; n++) {
+        fds[n] = drive_get(IF_FLOPPY, 0, n);
+    }
+    fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
+
+    /* Real time clock */
+    rtc_init(1980, NULL);
+    s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL,
+                                   DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
+
+    /* Keyboard (i8042) */
+    i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0x1000, 0x1);
+
+    /* Serial ports */
+    if (serial_hds[0]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 1);
+#else
+        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 0);
+#endif
+    }
+    if (serial_hds[1]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 1);
+#else
+        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 0);
+#endif
+    }
+
+    /* Parallel port */
+    if (parallel_hds[0])
+        parallel_mm_init(0x80008000, 0, rc4030[0], parallel_hds[0]);
+
+    /* Sound card */
+    /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
+    audio_init(i8259, NULL);
+
+    /* NVRAM */
+    dev = qdev_create(NULL, "ds1225y");
+    qdev_init_nofail(dev);
+    sysbus = sysbus_from_qdev(dev);
+    sysbus_mmio_map(sysbus, 0, 0x80009000);
+
+    /* LED indicator */
+    jazz_led_init(0x8000f000);
+}
+
+static
+void mips_magnum_init (ram_addr_t ram_size,
+                       const char *boot_device,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    mips_jazz_init(ram_size, cpu_model, JAZZ_MAGNUM);
+}
+
+static
+void mips_pica61_init (ram_addr_t ram_size,
+                       const char *boot_device,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    mips_jazz_init(ram_size, cpu_model, JAZZ_PICA61);
+}
+
+static QEMUMachine mips_magnum_machine = {
+    .name = "magnum",
+    .desc = "MIPS Magnum",
+    .init = mips_magnum_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine mips_pica61_machine = {
+    .name = "pica61",
+    .desc = "Acer Pica 61",
+    .init = mips_pica61_init,
+    .use_scsi = 1,
+};
+
+static void mips_jazz_machine_init(void)
+{
+    qemu_register_machine(&mips_magnum_machine);
+    qemu_register_machine(&mips_pica61_machine);
+}
+
+machine_init(mips_jazz_machine_init);
diff --git a/qemu-0.15.x/hw/mips_malta.c b/qemu-0.15.x/hw/mips_malta.c
new file mode 100644
index 0000000..ed2a483
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_malta.c
@@ -0,0 +1,966 @@
+/*
+ * QEMU Malta board support
+ *
+ * Copyright (c) 2006 Aurelien Jarno
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "net.h"
+#include "boards.h"
+#include "smbus.h"
+#include "block.h"
+#include "flash.h"
+#include "mips.h"
+#include "mips_cpudevs.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "vmware_vga.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "arch_init.h"
+#include "boards.h"
+#include "qemu-log.h"
+#include "mips-bios.h"
+#include "ide.h"
+#include "loader.h"
+#include "elf.h"
+#include "mc146818rtc.h"
+#include "blockdev.h"
+
+//#define DEBUG_BOARD_INIT
+
+#define ENVP_ADDR		0x80002000l
+#define ENVP_NB_ENTRIES	 	16
+#define ENVP_ENTRY_SIZE	 	256
+
+#define MAX_IDE_BUS 2
+
+typedef struct {
+    uint32_t leds;
+    uint32_t brk;
+    uint32_t gpout;
+    uint32_t i2cin;
+    uint32_t i2coe;
+    uint32_t i2cout;
+    uint32_t i2csel;
+    CharDriverState *display;
+    char display_text[9];
+    SerialState *uart;
+} MaltaFPGAState;
+
+static ISADevice *pit;
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+/* Malta FPGA */
+static void malta_fpga_update_display(void *opaque)
+{
+    char leds_text[9];
+    int i;
+    MaltaFPGAState *s = opaque;
+
+    for (i = 7 ; i >= 0 ; i--) {
+        if (s->leds & (1 << i))
+            leds_text[i] = '#';
+        else
+            leds_text[i] = ' ';
+    }
+    leds_text[8] = '\0';
+
+    qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
+    qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+}
+
+/*
+ * EEPROM 24C01 / 24C02 emulation.
+ *
+ * Emulation for serial EEPROMs:
+ * 24C01 - 1024 bit (128 x 8)
+ * 24C02 - 2048 bit (256 x 8)
+ *
+ * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
+ */
+
+//~ #define DEBUG
+
+#if defined(DEBUG)
+#  define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#  define logout(fmt, ...) ((void)0)
+#endif
+
+struct _eeprom24c0x_t {
+  uint8_t tick;
+  uint8_t address;
+  uint8_t command;
+  uint8_t ack;
+  uint8_t scl;
+  uint8_t sda;
+  uint8_t data;
+  //~ uint16_t size;
+  uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t eeprom = {
+    .contents = {
+        /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
+        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
+        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
+        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
+        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
+        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
+        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
+    },
+};
+
+static uint8_t eeprom24c0x_read(void)
+{
+    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
+        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
+    return eeprom.sda;
+}
+
+static void eeprom24c0x_write(int scl, int sda)
+{
+    if (eeprom.scl && scl && (eeprom.sda != sda)) {
+        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
+        if (!sda) {
+            eeprom.tick = 1;
+            eeprom.command = 0;
+        }
+    } else if (eeprom.tick == 0 && !eeprom.ack) {
+        /* Waiting for start. */
+        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    } else if (!eeprom.scl && scl) {
+        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+        if (eeprom.ack) {
+            logout("\ti2c ack bit = 0\n");
+            sda = 0;
+            eeprom.ack = 0;
+        } else if (eeprom.sda == sda) {
+            uint8_t bit = (sda != 0);
+            logout("\ti2c bit = %d\n", bit);
+            if (eeprom.tick < 9) {
+                eeprom.command <<= 1;
+                eeprom.command += bit;
+                eeprom.tick++;
+                if (eeprom.tick == 9) {
+                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
+                    eeprom.ack = 1;
+                }
+            } else if (eeprom.tick < 17) {
+                if (eeprom.command & 1) {
+                    sda = ((eeprom.data & 0x80) != 0);
+                }
+                eeprom.address <<= 1;
+                eeprom.address += bit;
+                eeprom.tick++;
+                eeprom.data <<= 1;
+                if (eeprom.tick == 17) {
+                    eeprom.data = eeprom.contents[eeprom.address];
+                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
+                    eeprom.ack = 1;
+                    eeprom.tick = 0;
+                }
+            } else if (eeprom.tick >= 17) {
+                sda = 0;
+            }
+        } else {
+            logout("\tsda changed with raising scl\n");
+        }
+    } else {
+        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    }
+    eeprom.scl = scl;
+    eeprom.sda = sda;
+}
+
+static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
+{
+    MaltaFPGAState *s = opaque;
+    uint32_t val = 0;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfffff);
+
+    switch (saddr) {
+
+    /* SWITCH Register */
+    case 0x00200:
+        val = 0x00000000;		/* All switches closed */
+        break;
+
+    /* STATUS Register */
+    case 0x00208:
+#ifdef TARGET_WORDS_BIGENDIAN
+        val = 0x00000012;
+#else
+        val = 0x00000010;
+#endif
+        break;
+
+    /* JMPRS Register */
+    case 0x00210:
+        val = 0x00;
+        break;
+
+    /* LEDBAR Register */
+    case 0x00408:
+        val = s->leds;
+        break;
+
+    /* BRKRES Register */
+    case 0x00508:
+        val = s->brk;
+        break;
+
+    /* UART Registers are handled directly by the serial device */
+
+    /* GPOUT Register */
+    case 0x00a00:
+        val = s->gpout;
+        break;
+
+    /* XXX: implement a real I2C controller */
+
+    /* GPINP Register */
+    case 0x00a08:
+        /* IN = OUT until a real I2C control is implemented */
+        if (s->i2csel)
+            val = s->i2cout;
+        else
+            val = 0x00;
+        break;
+
+    /* I2CINP Register */
+    case 0x00b00:
+        val = ((s->i2cin & ~1) | eeprom24c0x_read());
+        break;
+
+    /* I2COE Register */
+    case 0x00b08:
+        val = s->i2coe;
+        break;
+
+    /* I2COUT Register */
+    case 0x00b10:
+        val = s->i2cout;
+        break;
+
+    /* I2CSEL Register */
+    case 0x00b18:
+        val = s->i2csel;
+        break;
+
+    default:
+#if 0
+        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
+                addr);
+#endif
+        break;
+    }
+    return val;
+}
+
+static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
+                              uint32_t val)
+{
+    MaltaFPGAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfffff);
+
+    switch (saddr) {
+
+    /* SWITCH Register */
+    case 0x00200:
+        break;
+
+    /* JMPRS Register */
+    case 0x00210:
+        break;
+
+    /* LEDBAR Register */
+    /* XXX: implement a 8-LED array */
+    case 0x00408:
+        s->leds = val & 0xff;
+        break;
+
+    /* ASCIIWORD Register */
+    case 0x00410:
+        snprintf(s->display_text, 9, "%08X", val);
+        malta_fpga_update_display(s);
+        break;
+
+    /* ASCIIPOS0 to ASCIIPOS7 Registers */
+    case 0x00418:
+    case 0x00420:
+    case 0x00428:
+    case 0x00430:
+    case 0x00438:
+    case 0x00440:
+    case 0x00448:
+    case 0x00450:
+        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
+        malta_fpga_update_display(s);
+        break;
+
+    /* SOFTRES Register */
+    case 0x00500:
+        if (val == 0x42)
+            qemu_system_reset_request ();
+        break;
+
+    /* BRKRES Register */
+    case 0x00508:
+        s->brk = val & 0xff;
+        break;
+
+    /* UART Registers are handled directly by the serial device */
+
+    /* GPOUT Register */
+    case 0x00a00:
+        s->gpout = val & 0xff;
+        break;
+
+    /* I2COE Register */
+    case 0x00b08:
+        s->i2coe = val & 0x03;
+        break;
+
+    /* I2COUT Register */
+    case 0x00b10:
+        eeprom24c0x_write(val & 0x02, val & 0x01);
+        s->i2cout = val;
+        break;
+
+    /* I2CSEL Register */
+    case 0x00b18:
+        s->i2csel = val & 0x01;
+        break;
+
+    default:
+#if 0
+        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
+                addr);
+#endif
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const malta_fpga_read[] = {
+   malta_fpga_readl,
+   malta_fpga_readl,
+   malta_fpga_readl
+};
+
+static CPUWriteMemoryFunc * const malta_fpga_write[] = {
+   malta_fpga_writel,
+   malta_fpga_writel,
+   malta_fpga_writel
+};
+
+static void malta_fpga_reset(void *opaque)
+{
+    MaltaFPGAState *s = opaque;
+
+    s->leds   = 0x00;
+    s->brk    = 0x0a;
+    s->gpout  = 0x00;
+    s->i2cin  = 0x3;
+    s->i2coe  = 0x0;
+    s->i2cout = 0x3;
+    s->i2csel = 0x1;
+
+    s->display_text[8] = '\0';
+    snprintf(s->display_text, 9, "        ");
+}
+
+static void malta_fpga_led_init(CharDriverState *chr)
+{
+    qemu_chr_printf(chr, "\e[HMalta LEDBAR\r\n");
+    qemu_chr_printf(chr, "+--------+\r\n");
+    qemu_chr_printf(chr, "+        +\r\n");
+    qemu_chr_printf(chr, "+--------+\r\n");
+    qemu_chr_printf(chr, "\n");
+    qemu_chr_printf(chr, "Malta ASCII\r\n");
+    qemu_chr_printf(chr, "+--------+\r\n");
+    qemu_chr_printf(chr, "+        +\r\n");
+    qemu_chr_printf(chr, "+--------+\r\n");
+}
+
+static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
+{
+    MaltaFPGAState *s;
+    int malta;
+
+    s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
+
+    malta = cpu_register_io_memory(malta_fpga_read,
+                                   malta_fpga_write, s,
+                                   DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(base, 0x900, malta);
+    /* 0xa00 is less than a page, so will still get the right offsets.  */
+    cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
+
+    s->display = qemu_chr_open("fpga", "vc:320x200", malta_fpga_led_init);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 1);
+#else
+    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 0);
+#endif
+
+    malta_fpga_reset(s);
+    qemu_register_reset(malta_fpga_reset, s);
+
+    return s;
+}
+
+/* Network support */
+static void network_init(void)
+{
+    int i;
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        const char *default_devaddr = NULL;
+
+        if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
+            /* The malta board has a PCNet card using PCI SLOT 11 */
+            default_devaddr = "0b";
+
+        pci_nic_init_nofail(nd, "pcnet", default_devaddr);
+    }
+}
+
+/* ROM and pseudo bootloader
+
+   The following code implements a very very simple bootloader. It first
+   loads the registers a0 to a3 to the values expected by the OS, and
+   then jump at the kernel address.
+
+   The bootloader should pass the locations of the kernel arguments and
+   environment variables tables. Those tables contain the 32-bit address
+   of NULL terminated strings. The environment variables table should be
+   terminated by a NULL address.
+
+   For a simpler implementation, the number of kernel arguments is fixed
+   to two (the name of the kernel and the command line), and the two
+   tables are actually the same one.
+
+   The registers a0 to a3 should contain the following values:
+     a0 - number of kernel arguments
+     a1 - 32-bit address of the kernel arguments table
+     a2 - 32-bit address of the environment variables table
+     a3 - RAM size in bytes
+*/
+
+static void write_bootloader (CPUState *env, uint8_t *base,
+                              int64_t kernel_entry)
+{
+    uint32_t *p;
+
+    /* Small bootloader */
+    p = (uint32_t *)base;
+    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* YAMON service vector */
+    stl_raw(base + 0x500, 0xbfc00580);      /* start: */
+    stl_raw(base + 0x504, 0xbfc0083c);      /* print_count: */
+    stl_raw(base + 0x520, 0xbfc00580);      /* start: */
+    stl_raw(base + 0x52c, 0xbfc00800);      /* flush_cache: */
+    stl_raw(base + 0x534, 0xbfc00808);      /* print: */
+    stl_raw(base + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
+    stl_raw(base + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
+    stl_raw(base + 0x540, 0xbfc00800);      /* reg_ic_isr: */
+    stl_raw(base + 0x544, 0xbfc00800);      /* unred_ic_isr: */
+    stl_raw(base + 0x548, 0xbfc00800);      /* reg_esr: */
+    stl_raw(base + 0x54c, 0xbfc00800);      /* unreg_esr: */
+    stl_raw(base + 0x550, 0xbfc00800);      /* getchar: */
+    stl_raw(base + 0x554, 0xbfc00800);      /* syscon_read: */
+
+
+    /* Second part of the bootloader */
+    p = (uint32_t *) (base + 0x580);
+    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
+    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
+    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
+    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
+    stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
+    stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
+    stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
+
+    /* Load BAR registers as done by YAMON */
+    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
+#else
+    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
+#endif
+    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
+
+    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
+#else
+    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
+#endif
+    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
+#else
+    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
+#endif
+    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
+#else
+    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
+#endif
+    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
+#else
+    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
+#endif
+    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
+#else
+    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
+#endif
+    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
+#else
+    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
+#endif
+    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
+
+    /* Jump to kernel code */
+    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
+    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
+    stl_raw(p++, 0x03e00008);                                      /* jr ra */
+    stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* YAMON subroutines */
+    p = (uint32_t *) (base + 0x800);
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
+   /* 808 YAMON print */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x08000205);                                     /* j 814 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x83c YAMON print_count */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
+    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x870 */
+    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
+    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
+    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
+    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
+
+}
+
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
+{
+    va_list ap;
+    int32_t table_addr;
+
+    if (index >= ENVP_NB_ENTRIES)
+        return;
+
+    if (string == NULL) {
+        prom_buf[index] = 0;
+        return;
+    }
+
+    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
+
+    va_start(ap, string);
+    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
+    va_end(ap);
+}
+
+/* Kernel */
+static int64_t load_kernel (void)
+{
+    int64_t kernel_entry, kernel_high;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    int big_endian;
+    uint32_t *prom_buf;
+    long prom_size;
+    int prom_index = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
+                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
+                 big_endian, ELF_MACHINE, 1) < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Setup prom parameters. */
+    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+    prom_buf = qemu_malloc(prom_size);
+
+    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
+    if (initrd_size > 0) {
+        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
+                 loaderparams.kernel_cmdline);
+    } else {
+        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
+    }
+
+    prom_set(prom_buf, prom_index++, "memsize");
+    prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
+    prom_set(prom_buf, prom_index++, "modetty0");
+    prom_set(prom_buf, prom_index++, "38400n8r");
+    prom_set(prom_buf, prom_index++, NULL);
+
+    rom_add_blob_fixed("prom", prom_buf, prom_size,
+                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
+
+    return kernel_entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+
+    /* The bootloader does not need to be rewritten as it is located in a
+       read only location. The kernel location and the arguments table
+       location does not change. */
+    if (loaderparams.kernel_filename) {
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+    }
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+static
+void mips_malta_init (ram_addr_t ram_size,
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    char *filename;
+    ram_addr_t ram_offset;
+    ram_addr_t bios_offset;
+    target_long bios_size;
+    int64_t kernel_entry;
+    PCIBus *pci_bus;
+    CPUState *env;
+    qemu_irq *i8259;
+    qemu_irq *cpu_exit_irq;
+    int piix4_devfn;
+    i2c_bus *smbus;
+    int i;
+    DriveInfo *dinfo;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *fd[MAX_FD];
+    int fl_idx = 0;
+    int fl_sectors = 0;
+    int be;
+
+    /* Make sure the first 3 serial ports are associated with a device. */
+    for(i = 0; i < 3; i++) {
+        if (!serial_hds[i]) {
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_open(label, "null", NULL);
+        }
+    }
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "20Kc";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* allocate RAM */
+    if (ram_size > (256 << 20)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+                ((unsigned int)ram_size / (1 << 20)));
+        exit(1);
+    }
+    ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size);
+    bios_offset = qemu_ram_alloc(NULL, "mips_malta.bios", BIOS_SIZE);
+
+
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+    /* Map the bios at two physical locations, as on the real board. */
+    cpu_register_physical_memory(0x1e000000LL,
+                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    cpu_register_physical_memory(0x1fc00000LL,
+                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    /* FPGA */
+    malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+
+    /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
+    if (kernel_filename) {
+        /* Write a small bootloader to the flash location. */
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        kernel_entry = load_kernel();
+        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+    } else {
+        dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+        if (dinfo) {
+            /* Load firmware from flash. */
+            bios_size = 0x400000;
+            fl_sectors = bios_size >> 16;
+#ifdef DEBUG_BOARD_INIT
+            printf("Register parallel flash %d size " TARGET_FMT_lx " at "
+                   "offset %08lx addr %08llx '%s' %x\n",
+                   fl_idx, bios_size, bios_offset, 0x1e000000LL,
+                   bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+#endif
+            pflash_cfi01_register(0x1e000000LL, bios_offset,
+                                  dinfo->bdrv, 65536, fl_sectors,
+                                  4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+            fl_idx++;
+        } else {
+            /* Load a BIOS image. */
+            if (bios_name == NULL)
+                bios_name = BIOS_FILENAME;
+            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+            if (filename) {
+                bios_size = load_image_targphys(filename, 0x1fc00000LL,
+                                                BIOS_SIZE);
+                qemu_free(filename);
+            } else {
+                bios_size = -1;
+            }
+            if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+                fprintf(stderr,
+                        "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                        bios_name);
+                exit(1);
+            }
+        }
+        /* In little endian mode the 32bit words in the bios are swapped,
+           a neat trick which allows bi-endian firmware. */
+#ifndef TARGET_WORDS_BIGENDIAN
+        {
+            uint32_t *addr = qemu_get_ram_ptr(bios_offset);;
+            uint32_t *end = addr + bios_size;
+            while (addr < end) {
+                bswap32s(addr);
+            }
+        }
+#endif
+    }
+
+    /* Board ID = 0x420 (Malta Board with CoreLV)
+       XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
+       map to the board ID. */
+    stl_p(qemu_get_ram_ptr(bios_offset) + 0x10, 0x00000420);
+
+    /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Interrupt controller */
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    i8259 = i8259_init(env->irq[2]);
+
+    /* Northbridge */
+    pci_bus = gt64120_register(i8259);
+
+    /* Southbridge */
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    piix4_devfn = piix4_init(pci_bus, 80);
+    isa_bus_irqs(i8259);
+    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
+    usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
+    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9),
+                          NULL, NULL, 0);
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(smbus, 8, NULL, 0);
+    pit = pit_init(0x40, 0);
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    /* Super I/O */
+    isa_create_simple("i8042");
+
+    rtc_init(2000, NULL);
+    serial_isa_init(0, serial_hds[0]);
+    serial_isa_init(1, serial_hds[1]);
+    if (parallel_hds[0])
+        parallel_init(0, parallel_hds[0]);
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(fd);
+
+    /* Sound card */
+    audio_init(NULL, pci_bus);
+
+    /* Network card */
+    network_init();
+
+    /* Optional PCI video card */
+    if (cirrus_vga_enabled) {
+        pci_cirrus_vga_init(pci_bus);
+    } else if (vmsvga_enabled) {
+        if (!pci_vmsvga_init(pci_bus)) {
+            fprintf(stderr, "Warning: vmware_vga not available,"
+                    " using standard VGA instead\n");
+            pci_vga_init(pci_bus);
+        }
+    } else if (std_vga_enabled) {
+        pci_vga_init(pci_bus);
+    }
+}
+
+static QEMUMachine mips_malta_machine = {
+    .name = "malta",
+    .desc = "MIPS Malta Core LV",
+    .init = mips_malta_init,
+    .is_default = 1,
+};
+
+static void mips_malta_machine_init(void)
+{
+    qemu_register_machine(&mips_malta_machine);
+}
+
+machine_init(mips_malta_machine_init);
diff --git a/qemu-0.15.x/hw/mips_mipssim.c b/qemu-0.15.x/hw/mips_mipssim.c
new file mode 100644
index 0000000..380a7eb
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_mipssim.c
@@ -0,0 +1,212 @@
+/*
+ * QEMU/mipssim emulation
+ *
+ * Emulates a very simple machine model similiar to the one use by the
+ * proprietary MIPS emulator.
+ * 
+ * Copyright (c) 2007 Thiemo Seufer
+ *
+ * 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 "hw.h"
+#include "mips.h"
+#include "mips_cpudevs.h"
+#include "pc.h"
+#include "isa.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "mips-bios.h"
+#include "loader.h"
+#include "elf.h"
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+typedef struct ResetData {
+    CPUState *env;
+    uint64_t vector;
+} ResetData;
+
+static int64_t load_kernel(void)
+{
+    int64_t entry, kernel_high;
+    long kernel_size;
+    long initrd_size;
+    ram_addr_t initrd_offset;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
+                           NULL, (uint64_t *)&entry, NULL,
+                           (uint64_t *)&kernel_high, big_endian,
+                           ELF_MACHINE, 1);
+    if (kernel_size >= 0) {
+        if ((entry & ~0x7fffffffULL) == 0x80000000)
+            entry = (int32_t)entry;
+    } else {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > loaderparams.ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                initrd_offset, loaderparams.ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+    return entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUState *env = s->env;
+
+    cpu_reset(env);
+    env->active_tc.PC = s->vector & ~(target_ulong)1;
+    if (s->vector & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static void
+mips_mipssim_init (ram_addr_t ram_size,
+                   const char *boot_device,
+                   const char *kernel_filename, const char *kernel_cmdline,
+                   const char *initrd_filename, const char *cpu_model)
+{
+    char *filename;
+    ram_addr_t ram_offset;
+    ram_addr_t bios_offset;
+    CPUState *env;
+    ResetData *reset_info;
+    int bios_size;
+
+    /* Init CPUs. */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "5Kf";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info->env = env;
+    reset_info->vector = env->active_tc.PC;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate RAM. */
+    ram_offset = qemu_ram_alloc(NULL, "mips_mipssim.ram", ram_size);
+    bios_offset = qemu_ram_alloc(NULL, "mips_mipssim.bios", BIOS_SIZE);
+
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+    /* Map the BIOS / boot exception handler. */
+    cpu_register_physical_memory(0x1fc00000LL,
+                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    /* Load a BIOS / boot exception handler image. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
+        qemu_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
+        /* Bail out if we have neither a kernel image nor boot vector code. */
+        fprintf(stderr,
+                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                filename);
+        exit(1);
+    } else {
+        /* We have a boot vector start address. */
+        env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
+    }
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        reset_info->vector = load_kernel();
+    }
+
+    /* Init CPU internal devices. */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* Register 64 KB of ISA IO space at 0x1fd00000. */
+    isa_mmio_init(0x1fd00000, 0x00010000);
+
+    /* A single 16450 sits at offset 0x3f8. It is attached to
+       MIPS CPU INT2, which is interrupt 4. */
+    if (serial_hds[0])
+        serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]);
+
+    if (nd_table[0].vlan)
+        /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
+        mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
+}
+
+static QEMUMachine mips_mipssim_machine = {
+    .name = "mipssim",
+    .desc = "MIPS MIPSsim platform",
+    .init = mips_mipssim_init,
+};
+
+static void mips_mipssim_machine_init(void)
+{
+    qemu_register_machine(&mips_mipssim_machine);
+}
+
+machine_init(mips_mipssim_machine_init);
diff --git a/qemu-0.15.x/hw/mips_r4k.c b/qemu-0.15.x/hw/mips_r4k.c
new file mode 100644
index 0000000..2834a46
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_r4k.c
@@ -0,0 +1,310 @@
+/*
+ * QEMU/MIPS pseudo-board
+ *
+ * emulates a simple machine with ISA-like bus.
+ * ISA IO space mapped to the 0x14000000 (PHYS) and
+ * ISA memory at the 0x10000000 (PHYS, 16Mb in size).
+ * All peripherial devices are attached to this "bus" with
+ * the standard PC ISA addresses.
+*/
+#include "hw.h"
+#include "mips.h"
+#include "mips_cpudevs.h"
+#include "pc.h"
+#include "isa.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "flash.h"
+#include "qemu-log.h"
+#include "mips-bios.h"
+#include "ide.h"
+#include "loader.h"
+#include "elf.h"
+#include "mc146818rtc.h"
+#include "blockdev.h"
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+static ISADevice *pit; /* PIT i8254 */
+
+/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
+			      uint32_t val)
+{
+    if ((addr & 0xffff) == 0 && val == 42)
+        qemu_system_reset_request ();
+    else if ((addr & 0xffff) == 4 && val == 42)
+        qemu_system_shutdown_request ();
+}
+
+static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static CPUWriteMemoryFunc * const mips_qemu_write[] = {
+    &mips_qemu_writel,
+    &mips_qemu_writel,
+    &mips_qemu_writel,
+};
+
+static CPUReadMemoryFunc * const mips_qemu_read[] = {
+    &mips_qemu_readl,
+    &mips_qemu_readl,
+    &mips_qemu_readl,
+};
+
+static int mips_qemu_iomemtype = 0;
+
+typedef struct ResetData {
+    CPUState *env;
+    uint64_t vector;
+} ResetData;
+
+static int64_t load_kernel(void)
+{
+    int64_t entry, kernel_high;
+    long kernel_size, initrd_size, params_size;
+    ram_addr_t initrd_offset;
+    uint32_t *params_buf;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+    kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
+                           NULL, (uint64_t *)&entry, NULL,
+                           (uint64_t *)&kernel_high, big_endian,
+                           ELF_MACHINE, 1);
+    if (kernel_size >= 0) {
+        if ((entry & ~0x7fffffffULL) == 0x80000000)
+            entry = (int32_t)entry;
+    } else {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                loaderparams.kernel_filename);
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size (loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Store command line.  */
+    params_size = 264;
+    params_buf = qemu_malloc(params_size);
+
+    params_buf[0] = tswap32(ram_size);
+    params_buf[1] = tswap32(0x12345678);
+
+    if (initrd_size > 0) {
+        snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
+                 cpu_mips_phys_to_kseg0(NULL, initrd_offset),
+                 initrd_size, loaderparams.kernel_cmdline);
+    } else {
+        snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline);
+    }
+
+    rom_add_blob_fixed("params", params_buf, params_size,
+                       (16 << 20) - 264);
+
+    return entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUState *env = s->env;
+
+    cpu_reset(env);
+    env->active_tc.PC = s->vector;
+}
+
+static const int sector_len = 32 * 1024;
+static
+void mips_r4k_init (ram_addr_t ram_size,
+                    const char *boot_device,
+                    const char *kernel_filename, const char *kernel_cmdline,
+                    const char *initrd_filename, const char *cpu_model)
+{
+    char *filename;
+    ram_addr_t ram_offset;
+    ram_addr_t bios_offset;
+    int bios_size;
+    CPUState *env;
+    ResetData *reset_info;
+    int i;
+    qemu_irq *i8259;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *dinfo;
+    int be;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info->env = env;
+    reset_info->vector = env->active_tc.PC;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* allocate RAM */
+    if (ram_size > (256 << 20)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+                ((unsigned int)ram_size / (1 << 20)));
+        exit(1);
+    }
+    ram_offset = qemu_ram_alloc(NULL, "mips_r4k.ram", ram_size);
+
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+    if (!mips_qemu_iomemtype) {
+        mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read,
+                                                     mips_qemu_write, NULL,
+                                                     DEVICE_NATIVE_ENDIAN);
+    }
+    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
+
+    /* Try to load a BIOS image. If this fails, we continue regardless,
+       but initialize the hardware ourselves. When a kernel gets
+       preloaded we also initialize the hardware, since the BIOS wasn't
+       run. */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+    if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
+        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", BIOS_SIZE);
+	cpu_register_physical_memory(0x1fc00000, BIOS_SIZE,
+                                     bios_offset | IO_MEM_ROM);
+
+        load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
+    } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
+        uint32_t mips_rom = 0x00400000;
+        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", mips_rom);
+        if (!pflash_cfi01_register(0x1fc00000, bios_offset,
+                                   dinfo->bdrv, sector_len,
+                                   mips_rom / sector_len,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+	}
+    }
+    else {
+	/* not fatal */
+        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
+		bios_name);
+    }
+    if (filename) {
+        qemu_free(filename);
+    }
+
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        reset_info->vector = load_kernel();
+    }
+
+    /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+
+    /* The PIC is attached to the MIPS CPU INT0 pin */
+    i8259 = i8259_init(env->irq[2]);
+    isa_bus_new(NULL);
+    isa_bus_irqs(i8259);
+
+    rtc_init(2000, NULL);
+
+    /* Register 64 KB of ISA IO space at 0x14000000 */
+    isa_mmio_init(0x14000000, 0x00010000);
+    isa_mem_base = 0x10000000;
+
+    pit = pit_init(0x40, 0);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    isa_vga_init();
+
+    if (nd_table[0].vlan)
+        isa_ne2000_init(0x300, 9, &nd_table[0]);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    for(i = 0; i < MAX_IDE_BUS; i++)
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                     hd[MAX_IDE_DEVS * i],
+		     hd[MAX_IDE_DEVS * i + 1]);
+
+    isa_create_simple("i8042");
+}
+
+static QEMUMachine mips_machine = {
+    .name = "mips",
+    .desc = "mips r4k platform",
+    .init = mips_r4k_init,
+};
+
+static void mips_machine_init(void)
+{
+    qemu_register_machine(&mips_machine);
+}
+
+machine_init(mips_machine_init);
diff --git a/qemu-0.15.x/hw/mips_timer.c b/qemu-0.15.x/hw/mips_timer.c
new file mode 100644
index 0000000..cf6ac69
--- /dev/null
+++ b/qemu-0.15.x/hw/mips_timer.c
@@ -0,0 +1,147 @@
+/*
+ * QEMU MIPS timer support
+ *
+ * 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 "hw.h"
+#include "mips_cpudevs.h"
+#include "qemu-timer.h"
+
+#define TIMER_FREQ	100 * 1000 * 1000
+
+/* XXX: do not use a global */
+uint32_t cpu_mips_get_random (CPUState *env)
+{
+    static uint32_t lfsr = 1;
+    static uint32_t prev_idx = 0;
+    uint32_t idx;
+    /* Don't return same value twice, so get another value */
+    do {
+        lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
+        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
+    } while (idx == prev_idx);
+    prev_idx = idx;
+    return idx;
+}
+
+/* MIPS R4K timer */
+static void cpu_mips_timer_update(CPUState *env)
+{
+    uint64_t now, next;
+    uint32_t wait;
+
+    now = qemu_get_clock_ns(vm_clock);
+    wait = env->CP0_Compare - env->CP0_Count -
+	    (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
+    qemu_mod_timer(env->timer, next);
+}
+
+/* Expire the timer.  */
+static void cpu_mips_timer_expire(CPUState *env)
+{
+    cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2) {
+        env->CP0_Cause |= 1 << CP0Ca_TI;
+    }
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUState *env)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+        return env->CP0_Count;
+    } else {
+        uint64_t now;
+
+        now = qemu_get_clock_ns(vm_clock);
+        if (qemu_timer_pending(env->timer)
+            && qemu_timer_expired(env->timer, now)) {
+            /* The timer has already expired.  */
+            cpu_mips_timer_expire(env);
+        }
+
+        return env->CP0_Count +
+            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+    }
+}
+
+void cpu_mips_store_count (CPUState *env, uint32_t count)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        env->CP0_Count = count;
+    else {
+        /* Store new count register */
+        env->CP0_Count =
+            count - (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
+                                       TIMER_FREQ, get_ticks_per_sec());
+        /* Update timer timer */
+        cpu_mips_timer_update(env);
+    }
+}
+
+void cpu_mips_store_compare (CPUState *env, uint32_t value)
+{
+    env->CP0_Compare = value;
+    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
+        cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2)
+        env->CP0_Cause &= ~(1 << CP0Ca_TI);
+    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+void cpu_mips_start_count(CPUState *env)
+{
+    cpu_mips_store_count(env, env->CP0_Count);
+}
+
+void cpu_mips_stop_count(CPUState *env)
+{
+    /* Store the current value */
+    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock_ns(vm_clock),
+                                         TIMER_FREQ, get_ticks_per_sec());
+}
+
+static void mips_timer_cb (void *opaque)
+{
+    CPUState *env;
+
+    env = opaque;
+#if 0
+    qemu_log("%s\n", __func__);
+#endif
+
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return;
+
+    /* ??? This callback should occur when the counter is exactly equal to
+       the comparator value.  Offset the count by one to avoid immediately
+       retriggering the callback before any virtual time has passed.  */
+    env->CP0_Count++;
+    cpu_mips_timer_expire(env);
+    env->CP0_Count--;
+}
+
+void cpu_mips_clock_init (CPUState *env)
+{
+    env->timer = qemu_new_timer_ns(vm_clock, &mips_timer_cb, env);
+    env->CP0_Compare = 0;
+    cpu_mips_store_count(env, 1);
+}
diff --git a/qemu-0.15.x/hw/mipsnet.c b/qemu-0.15.x/hw/mipsnet.c
new file mode 100644
index 0000000..0db3ba7
--- /dev/null
+++ b/qemu-0.15.x/hw/mipsnet.c
@@ -0,0 +1,273 @@
+#include "hw.h"
+#include "mips.h"
+#include "net.h"
+#include "isa.h"
+
+//#define DEBUG_MIPSNET_SEND
+//#define DEBUG_MIPSNET_RECEIVE
+//#define DEBUG_MIPSNET_DATA
+//#define DEBUG_MIPSNET_IRQ
+
+/* MIPSnet register offsets */
+
+#define MIPSNET_DEV_ID		0x00
+#define MIPSNET_BUSY		0x08
+#define MIPSNET_RX_DATA_COUNT	0x0c
+#define MIPSNET_TX_DATA_COUNT	0x10
+#define MIPSNET_INT_CTL		0x14
+# define MIPSNET_INTCTL_TXDONE		0x00000001
+# define MIPSNET_INTCTL_RXDONE		0x00000002
+# define MIPSNET_INTCTL_TESTBIT		0x80000000
+#define MIPSNET_INTERRUPT_INFO	0x18
+#define MIPSNET_RX_DATA_BUFFER	0x1c
+#define MIPSNET_TX_DATA_BUFFER	0x20
+
+#define MAX_ETH_FRAME_SIZE	1514
+
+typedef struct MIPSnetState {
+    uint32_t busy;
+    uint32_t rx_count;
+    uint32_t rx_read;
+    uint32_t tx_count;
+    uint32_t tx_written;
+    uint32_t intctl;
+    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
+    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
+    int io_base;
+    qemu_irq irq;
+    NICState *nic;
+    NICConf conf;
+} MIPSnetState;
+
+static void mipsnet_reset(MIPSnetState *s)
+{
+    s->busy = 1;
+    s->rx_count = 0;
+    s->rx_read = 0;
+    s->tx_count = 0;
+    s->tx_written = 0;
+    s->intctl = 0;
+    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
+    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
+}
+
+static void mipsnet_update_irq(MIPSnetState *s)
+{
+    int isr = !!s->intctl;
+#ifdef DEBUG_MIPSNET_IRQ
+    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
+#endif
+    qemu_set_irq(s->irq, isr);
+}
+
+static int mipsnet_buffer_full(MIPSnetState *s)
+{
+    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
+        return 1;
+    return 0;
+}
+
+static int mipsnet_can_receive(VLANClientState *nc)
+{
+    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (s->busy)
+        return 0;
+    return !mipsnet_buffer_full(s);
+}
+
+static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+#ifdef DEBUG_MIPSNET_RECEIVE
+    printf("mipsnet: receiving len=%zu\n", size);
+#endif
+    if (!mipsnet_can_receive(nc))
+        return -1;
+
+    s->busy = 1;
+
+    /* Just accept everything. */
+
+    /* Write packet data. */
+    memcpy(s->rx_buffer, buf, size);
+
+    s->rx_count = size;
+    s->rx_read = 0;
+
+    /* Now we can signal we have received something. */
+    s->intctl |= MIPSNET_INTCTL_RXDONE;
+    mipsnet_update_irq(s);
+
+    return size;
+}
+
+static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
+{
+    MIPSnetState *s = opaque;
+    int ret = 0;
+
+    addr &= 0x3f;
+    switch (addr) {
+    case MIPSNET_DEV_ID:
+	ret = be32_to_cpu(0x4d495053);		/* MIPS */
+        break;
+    case MIPSNET_DEV_ID + 4:
+	ret = be32_to_cpu(0x4e455430);		/* NET0 */
+        break;
+    case MIPSNET_BUSY:
+	ret = s->busy;
+        break;
+    case MIPSNET_RX_DATA_COUNT:
+	ret = s->rx_count;
+        break;
+    case MIPSNET_TX_DATA_COUNT:
+	ret = s->tx_count;
+        break;
+    case MIPSNET_INT_CTL:
+	ret = s->intctl;
+        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
+        break;
+    case MIPSNET_INTERRUPT_INFO:
+        /* XXX: This seems to be a per-VPE interrupt number. */
+	ret = 0;
+        break;
+    case MIPSNET_RX_DATA_BUFFER:
+        if (s->rx_count) {
+            s->rx_count--;
+            ret = s->rx_buffer[s->rx_read++];
+        }
+        break;
+    /* Reads as zero. */
+    case MIPSNET_TX_DATA_BUFFER:
+    default:
+        break;
+    }
+#ifdef DEBUG_MIPSNET_DATA
+    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
+#endif
+    return ret;
+}
+
+static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    MIPSnetState *s = opaque;
+
+    addr &= 0x3f;
+#ifdef DEBUG_MIPSNET_DATA
+    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
+#endif
+    switch (addr) {
+    case MIPSNET_TX_DATA_COUNT:
+	s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
+        s->tx_written = 0;
+        break;
+    case MIPSNET_INT_CTL:
+        if (val & MIPSNET_INTCTL_TXDONE) {
+            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
+        } else if (val & MIPSNET_INTCTL_RXDONE) {
+            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
+        } else if (val & MIPSNET_INTCTL_TESTBIT) {
+            mipsnet_reset(s);
+            s->intctl |= MIPSNET_INTCTL_TESTBIT;
+        } else if (!val) {
+            /* ACK testbit interrupt, flag was cleared on read. */
+        }
+        s->busy = !!s->intctl;
+        mipsnet_update_irq(s);
+        break;
+    case MIPSNET_TX_DATA_BUFFER:
+        s->tx_buffer[s->tx_written++] = val;
+        if (s->tx_written == s->tx_count) {
+            /* Send buffer. */
+#ifdef DEBUG_MIPSNET_SEND
+            printf("mipsnet: sending len=%d\n", s->tx_count);
+#endif
+            qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
+            s->tx_count = s->tx_written = 0;
+            s->intctl |= MIPSNET_INTCTL_TXDONE;
+            s->busy = 1;
+            mipsnet_update_irq(s);
+        }
+        break;
+    /* Read-only registers */
+    case MIPSNET_DEV_ID:
+    case MIPSNET_BUSY:
+    case MIPSNET_RX_DATA_COUNT:
+    case MIPSNET_INTERRUPT_INFO:
+    case MIPSNET_RX_DATA_BUFFER:
+    default:
+        break;
+    }
+}
+
+static const VMStateDescription vmstate_mipsnet = {
+    .name = "mipsnet",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(busy, MIPSnetState),
+        VMSTATE_UINT32(rx_count, MIPSnetState),
+        VMSTATE_UINT32(rx_read, MIPSnetState),
+        VMSTATE_UINT32(tx_count, MIPSnetState),
+        VMSTATE_UINT32(tx_written, MIPSnetState),
+        VMSTATE_UINT32(intctl, MIPSnetState),
+        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
+        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mipsnet_cleanup(VLANClientState *nc)
+{
+    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    vmstate_unregister(NULL, &vmstate_mipsnet, s);
+
+    isa_unassign_ioport(s->io_base, 36);
+
+    qemu_free(s);
+}
+
+static NetClientInfo net_mipsnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = mipsnet_can_receive,
+    .receive = mipsnet_receive,
+    .cleanup = mipsnet_cleanup,
+};
+
+void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
+{
+    MIPSnetState *s;
+
+    qemu_check_nic_model(nd, "mipsnet");
+
+    s = qemu_mallocz(sizeof(MIPSnetState));
+
+    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
+    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
+    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
+    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
+    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
+    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+
+    s->io_base = base;
+    s->irq = irq;
+
+    if (nd) {
+        s->conf.macaddr = nd->macaddr;
+        s->conf.vlan = nd->vlan;
+        s->conf.peer = nd->netdev;
+
+        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+                              nd->model, nd->name, s);
+
+        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    }
+
+    mipsnet_reset(s);
+    vmstate_register(NULL, 0, &vmstate_mipsnet, s);
+}
diff --git a/qemu-0.15.x/hw/mpc8544_guts.c b/qemu-0.15.x/hw/mpc8544_guts.c
new file mode 100644
index 0000000..c685f3e
--- /dev/null
+++ b/qemu-0.15.x/hw/mpc8544_guts.c
@@ -0,0 +1,135 @@
+/*
+ * QEMU PowerPC MPC8544 global util pseudo-device
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <alex at csgraf.de>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of  the GNU General  Public License as published by
+ * the Free Software Foundation;  either version 2 of the  License, or
+ * (at your option) any later version.
+ *
+ * *****************************************************************
+ *
+ * The documentation for this device is noted in the MPC8544 documentation,
+ * file name "MPC8544ERM.pdf". You can easily find it on the web.
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+
+#define MPC8544_GUTS_MMIO_SIZE        0x1000
+#define MPC8544_GUTS_RSTCR_RESET      0x02
+
+#define MPC8544_GUTS_ADDR_PORPLLSR    0x00
+#define MPC8544_GUTS_ADDR_PORBMSR     0x04
+#define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
+#define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
+#define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
+#define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
+#define MPC8544_GUTS_ADDR_GPPORCR     0x20
+#define MPC8544_GUTS_ADDR_GPIOCR      0x30
+#define MPC8544_GUTS_ADDR_GPOUTDR     0x40
+#define MPC8544_GUTS_ADDR_GPINDR      0x50
+#define MPC8544_GUTS_ADDR_PMUXCR      0x60
+#define MPC8544_GUTS_ADDR_DEVDISR     0x70
+#define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
+#define MPC8544_GUTS_ADDR_MCPSUMR     0x90
+#define MPC8544_GUTS_ADDR_RSTRSCR     0x94
+#define MPC8544_GUTS_ADDR_PVR         0xA0
+#define MPC8544_GUTS_ADDR_SVR         0xA4
+#define MPC8544_GUTS_ADDR_RSTCR       0xB0
+#define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
+#define MPC8544_GUTS_ADDR_DDRCSR      0xB20
+#define MPC8544_GUTS_ADDR_DDRCDR      0xB24
+#define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
+#define MPC8544_GUTS_ADDR_CLKOCR      0xE00
+#define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
+#define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
+#define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
+
+struct GutsState {
+    SysBusDevice busdev;
+};
+
+typedef struct GutsState GutsState;
+
+static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t value = 0;
+    CPUState *env = cpu_single_env;
+
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_PVR:
+        value = env->spr[SPR_PVR];
+        break;
+    case MPC8544_GUTS_ADDR_SVR:
+        value = env->spr[SPR_E500_SVR];
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
+        break;
+    }
+
+    return value;
+}
+
+static CPUReadMemoryFunc * const mpc8544_guts_read[] = {
+    NULL,
+    NULL,
+    &mpc8544_guts_read32,
+};
+
+static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_RSTCR:
+        if (value & MPC8544_GUTS_RSTCR_RESET) {
+            qemu_system_reset_request();
+        }
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register write: %x = %x\n",
+                (int)addr, value);
+        break;
+    }
+}
+
+static CPUWriteMemoryFunc * const mpc8544_guts_write[] = {
+    NULL,
+    NULL,
+    &mpc8544_guts_write32,
+};
+
+static int mpc8544_guts_initfn(SysBusDevice *dev)
+{
+    GutsState *s;
+    int iomem;
+
+    s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev));
+
+    iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s,
+                                   DEVICE_BIG_ENDIAN);
+    sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem);
+
+    return 0;
+}
+
+static SysBusDeviceInfo mpc8544_guts_info = {
+    .init         = mpc8544_guts_initfn,
+    .qdev.name    = "mpc8544-guts",
+    .qdev.size    = sizeof(GutsState),
+};
+
+static void mpc8544_guts_register(void)
+{
+    sysbus_register_withprop(&mpc8544_guts_info);
+}
+device_init(mpc8544_guts_register);
diff --git a/qemu-0.15.x/hw/mpcore.c b/qemu-0.15.x/hw/mpcore.c
new file mode 100644
index 0000000..d778507
--- /dev/null
+++ b/qemu-0.15.x/hw/mpcore.c
@@ -0,0 +1,286 @@
+/*
+ * ARM MPCore internal peripheral emulation (common code).
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+#define NCPU 4
+
+static inline int
+gic_get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* MPCore private memory region.  */
+
+typedef struct {
+    uint32_t count;
+    uint32_t load;
+    uint32_t control;
+    uint32_t status;
+    uint32_t old_status;
+    int64_t tick;
+    QEMUTimer *timer;
+    struct mpcore_priv_state *mpcore;
+    int id; /* Encodes both timer/watchdog and CPU.  */
+} mpcore_timer_state;
+
+typedef struct mpcore_priv_state {
+    gic_state gic;
+    uint32_t scu_control;
+    int iomemtype;
+    mpcore_timer_state timer[8];
+    uint32_t num_cpu;
+} mpcore_priv_state;
+
+/* Per-CPU Timers.  */
+
+static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
+{
+    if (s->status & ~s->old_status) {
+        gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
+    }
+    s->old_status = s->status;
+}
+
+/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
+static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s)
+{
+    return (((s->control >> 8) & 0xff) + 1) * 10;
+}
+
+static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
+{
+    if (s->count == 0)
+        return;
+    if (restart)
+        s->tick = qemu_get_clock_ns(vm_clock);
+    s->tick += (int64_t)s->count * mpcore_timer_scale(s);
+    qemu_mod_timer(s->timer, s->tick);
+}
+
+static void mpcore_timer_tick(void *opaque)
+{
+    mpcore_timer_state *s = (mpcore_timer_state *)opaque;
+    s->status = 1;
+    if (s->control & 2) {
+        s->count = s->load;
+        mpcore_timer_reload(s, 0);
+    } else {
+        s->count = 0;
+    }
+    mpcore_timer_update_irq(s);
+}
+
+static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
+{
+    int64_t val;
+    switch (offset) {
+    case 0: /* Load */
+        return s->load;
+        /* Fall through.  */
+    case 4: /* Counter.  */
+        if (((s->control & 1) == 0) || (s->count == 0))
+            return 0;
+        /* Slow and ugly, but hopefully won't happen too often.  */
+        val = s->tick - qemu_get_clock_ns(vm_clock);
+        val /= mpcore_timer_scale(s);
+        if (val < 0)
+            val = 0;
+        return val;
+    case 8: /* Control.  */
+        return s->control;
+    case 12: /* Interrupt status.  */
+        return s->status;
+    default:
+        return 0;
+    }
+}
+
+static void mpcore_timer_write(mpcore_timer_state *s, int offset,
+                               uint32_t value)
+{
+    int64_t old;
+    switch (offset) {
+    case 0: /* Load */
+        s->load = value;
+        /* Fall through.  */
+    case 4: /* Counter.  */
+        if ((s->control & 1) && s->count) {
+            /* Cancel the previous timer.  */
+            qemu_del_timer(s->timer);
+        }
+        s->count = value;
+        if (s->control & 1) {
+            mpcore_timer_reload(s, 1);
+        }
+        break;
+    case 8: /* Control.  */
+        old = s->control;
+        s->control = value;
+        if (((old & 1) == 0) && (value & 1)) {
+            if (s->count == 0 && (s->control & 2))
+                s->count = s->load;
+            mpcore_timer_reload(s, 1);
+        }
+        break;
+    case 12: /* Interrupt status.  */
+        s->status &= ~value;
+        mpcore_timer_update_irq(s);
+        break;
+    }
+}
+
+static void mpcore_timer_init(mpcore_priv_state *mpcore,
+                              mpcore_timer_state *s, int id)
+{
+    s->id = id;
+    s->mpcore = mpcore;
+    s->timer = qemu_new_timer_ns(vm_clock, mpcore_timer_tick, s);
+}
+
+
+/* Per-CPU private memory mapped IO.  */
+
+static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    int id;
+    offset &= 0xfff;
+    if (offset < 0x100) {
+        /* SCU */
+        switch (offset) {
+        case 0x00: /* Control.  */
+            return s->scu_control;
+        case 0x04: /* Configuration.  */
+            id = ((1 << s->num_cpu) - 1) << 4;
+            return id | (s->num_cpu - 1);
+        case 0x08: /* CPU status.  */
+            return 0;
+        case 0x0c: /* Invalidate all.  */
+            return 0;
+        default:
+            goto bad_reg;
+        }
+    } else if (offset < 0x600) {
+        /* Interrupt controller.  */
+        if (offset < 0x200) {
+            id = gic_get_current_cpu();
+        } else {
+            id = (offset - 0x200) >> 8;
+            if (id >= s->num_cpu) {
+                return 0;
+            }
+        }
+        return gic_cpu_read(&s->gic, id, offset & 0xff);
+    } else if (offset < 0xb00) {
+        /* Timers.  */
+        if (offset < 0x700) {
+            id = gic_get_current_cpu();
+        } else {
+            id = (offset - 0x700) >> 8;
+            if (id >= s->num_cpu) {
+                return 0;
+            }
+        }
+        id <<= 1;
+        if (offset & 0x20)
+          id++;
+        return mpcore_timer_read(&s->timer[id], offset & 0xf);
+    }
+bad_reg:
+    hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+    int id;
+    offset &= 0xfff;
+    if (offset < 0x100) {
+        /* SCU */
+        switch (offset) {
+        case 0: /* Control register.  */
+            s->scu_control = value & 1;
+            break;
+        case 0x0c: /* Invalidate all.  */
+            /* This is a no-op as cache is not emulated.  */
+            break;
+        default:
+            goto bad_reg;
+        }
+    } else if (offset < 0x600) {
+        /* Interrupt controller.  */
+        if (offset < 0x200) {
+            id = gic_get_current_cpu();
+        } else {
+            id = (offset - 0x200) >> 8;
+        }
+        if (id < s->num_cpu) {
+            gic_cpu_write(&s->gic, id, offset & 0xff, value);
+        }
+    } else if (offset < 0xb00) {
+        /* Timers.  */
+        if (offset < 0x700) {
+            id = gic_get_current_cpu();
+        } else {
+            id = (offset - 0x700) >> 8;
+        }
+        if (id < s->num_cpu) {
+            id <<= 1;
+            if (offset & 0x20)
+              id++;
+            mpcore_timer_write(&s->timer[id], offset & 0xf, value);
+        }
+        return;
+    }
+    return;
+bad_reg:
+    hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+}
+
+static CPUReadMemoryFunc * const mpcore_priv_readfn[] = {
+   mpcore_priv_read,
+   mpcore_priv_read,
+   mpcore_priv_read
+};
+
+static CPUWriteMemoryFunc * const mpcore_priv_writefn[] = {
+   mpcore_priv_write,
+   mpcore_priv_write,
+   mpcore_priv_write
+};
+
+static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+    cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+    cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+}
+
+static int mpcore_priv_init(SysBusDevice *dev)
+{
+    mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+    int i;
+
+    gic_init(&s->gic, s->num_cpu);
+    s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn,
+                                          mpcore_priv_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
+    for (i = 0; i < s->num_cpu * 2; i++) {
+        mpcore_timer_init(s, &s->timer[i], i);
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/msi.c b/qemu-0.15.x/hw/msi.c
new file mode 100644
index 0000000..f214fcf
--- /dev/null
+++ b/qemu-0.15.x/hw/msi.c
@@ -0,0 +1,352 @@
+/*
+ * msi.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msi.h"
+#include "range.h"
+
+/* Eventually those constants should go to Linux pci_regs.h */
+#define PCI_MSI_PENDING_32      0x10
+#define PCI_MSI_PENDING_64      0x14
+
+/* PCI_MSI_ADDRESS_LO */
+#define PCI_MSI_ADDRESS_LO_MASK         (~0x3)
+
+/* If we get rid of cap allocator, we won't need those. */
+#define PCI_MSI_32_SIZEOF       0x0a
+#define PCI_MSI_64_SIZEOF       0x0e
+#define PCI_MSI_32M_SIZEOF      0x14
+#define PCI_MSI_64M_SIZEOF      0x18
+
+#define PCI_MSI_VECTORS_MAX     32
+
+/* If we get rid of cap allocator, we won't need this. */
+static inline uint8_t msi_cap_sizeof(uint16_t flags)
+{
+    switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
+    case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
+        return PCI_MSI_64M_SIZEOF;
+    case PCI_MSI_FLAGS_64BIT:
+        return PCI_MSI_64_SIZEOF;
+    case PCI_MSI_FLAGS_MASKBIT:
+        return PCI_MSI_32M_SIZEOF;
+    case 0:
+        return PCI_MSI_32_SIZEOF;
+    default:
+        abort();
+        break;
+    }
+    return 0;
+}
+
+//#define MSI_DEBUG
+
+#ifdef MSI_DEBUG
+# define MSI_DPRINTF(fmt, ...)                                          \
+    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define MSI_DPRINTF(fmt, ...)  do { } while (0)
+#endif
+#define MSI_DEV_PRINTF(dev, fmt, ...)                                   \
+    MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+static inline unsigned int msi_nr_vectors(uint16_t flags)
+{
+    return 1U <<
+        ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
+}
+
+static inline uint8_t msi_flags_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_FLAGS;
+}
+
+static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_ADDRESS_LO;
+}
+
+static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_ADDRESS_HI;
+}
+
+static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
+}
+
+static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
+}
+
+static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32);
+}
+
+bool msi_enabled(const PCIDevice *dev)
+{
+    return msi_present(dev) &&
+        (pci_get_word(dev->config + msi_flags_off(dev)) &
+         PCI_MSI_FLAGS_ENABLE);
+}
+
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+             unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
+{
+    unsigned int vectors_order;
+    uint16_t flags;
+    uint8_t cap_size;
+    int config_offset;
+    MSI_DEV_PRINTF(dev,
+                   "init offset: 0x%"PRIx8" vector: %"PRId8
+                   " 64bit %d mask %d\n",
+                   offset, nr_vectors, msi64bit, msi_per_vector_mask);
+
+    assert(!(nr_vectors & (nr_vectors - 1)));   /* power of 2 */
+    assert(nr_vectors > 0);
+    assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
+    /* the nr of MSI vectors is up to 32 */
+    vectors_order = ffs(nr_vectors) - 1;
+
+    flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+    if (msi64bit) {
+        flags |= PCI_MSI_FLAGS_64BIT;
+    }
+    if (msi_per_vector_mask) {
+        flags |= PCI_MSI_FLAGS_MASKBIT;
+    }
+
+    cap_size = msi_cap_sizeof(flags);
+    config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
+    if (config_offset < 0) {
+        return config_offset;
+    }
+
+    dev->msi_cap = config_offset;
+    dev->cap_present |= QEMU_PCI_CAP_MSI;
+
+    pci_set_word(dev->config + msi_flags_off(dev), flags);
+    pci_set_word(dev->wmask + msi_flags_off(dev),
+                 PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+    pci_set_long(dev->wmask + msi_address_lo_off(dev),
+                 PCI_MSI_ADDRESS_LO_MASK);
+    if (msi64bit) {
+        pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
+    }
+    pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
+
+    if (msi_per_vector_mask) {
+        /* Make mask bits 0 to nr_vectors - 1 writable. */
+        pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
+                     0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
+    }
+    return config_offset;
+}
+
+void msi_uninit(struct PCIDevice *dev)
+{
+    uint16_t flags;
+    uint8_t cap_size;
+
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSI)) {
+        return;
+    }
+    flags = pci_get_word(dev->config + msi_flags_off(dev));
+    cap_size = msi_cap_sizeof(flags);
+    pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
+    dev->cap_present &= ~QEMU_PCI_CAP_MSI;
+
+    MSI_DEV_PRINTF(dev, "uninit\n");
+}
+
+void msi_reset(PCIDevice *dev)
+{
+    uint16_t flags;
+    bool msi64bit;
+
+    flags = pci_get_word(dev->config + msi_flags_off(dev));
+    flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+    msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+
+    pci_set_word(dev->config + msi_flags_off(dev), flags);
+    pci_set_long(dev->config + msi_address_lo_off(dev), 0);
+    if (msi64bit) {
+        pci_set_long(dev->config + msi_address_hi_off(dev), 0);
+    }
+    pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
+    if (flags & PCI_MSI_FLAGS_MASKBIT) {
+        pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
+        pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
+    }
+    MSI_DEV_PRINTF(dev, "reset\n");
+}
+
+static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    uint32_t mask;
+    assert(vector < PCI_MSI_VECTORS_MAX);
+
+    if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
+        return false;
+    }
+
+    mask = pci_get_long(dev->config +
+                        msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
+    return mask & (1U << vector);
+}
+
+void msi_notify(PCIDevice *dev, unsigned int vector)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+    unsigned int nr_vectors = msi_nr_vectors(flags);
+    uint64_t address;
+    uint32_t data;
+
+    assert(vector < nr_vectors);
+    if (msi_is_masked(dev, vector)) {
+        assert(flags & PCI_MSI_FLAGS_MASKBIT);
+        pci_long_test_and_set_mask(
+            dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+        MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
+        return;
+    }
+
+    if (msi64bit) {
+        address = pci_get_quad(dev->config + msi_address_lo_off(dev));
+    } else {
+        address = pci_get_long(dev->config + msi_address_lo_off(dev));
+    }
+
+    /* upper bit 31:16 is zero */
+    data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
+    if (nr_vectors > 1) {
+        data &= ~(nr_vectors - 1);
+        data |= vector;
+    }
+
+    MSI_DEV_PRINTF(dev,
+                   "notify vector 0x%x"
+                   " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
+                   vector, address, data);
+    stl_le_phys(address, data);
+}
+
+/* call this function after updating configs by pci_default_write_config(). */
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+    bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
+    unsigned int nr_vectors;
+    uint8_t log_num_vecs;
+    uint8_t log_max_vecs;
+    unsigned int vector;
+    uint32_t pending;
+
+    if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+        return;
+    }
+
+#ifdef MSI_DEBUG
+    MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
+                   addr, val, len);
+    MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
+                   flags,
+                   pci_get_long(dev->config + msi_address_lo_off(dev)));
+    if (msi64bit) {
+        fprintf(stderr, " address-hi: 0x%"PRIx32,
+                pci_get_long(dev->config + msi_address_hi_off(dev)));
+    }
+    fprintf(stderr, " data: 0x%"PRIx16,
+            pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
+    if (flags & PCI_MSI_FLAGS_MASKBIT) {
+        fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
+                pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
+                pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
+    }
+    fprintf(stderr, "\n");
+#endif
+
+    if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
+        return;
+    }
+
+    /*
+     * Now MSI is enabled, clear INTx# interrupts.
+     * the driver is prohibited from writing enable bit to mask
+     * a service request. But the guest OS could do this.
+     * So we just discard the interrupts as moderate fallback.
+     *
+     * 6.8.3.3. Enabling Operation
+     *   While enabled for MSI or MSI-X operation, a function is prohibited
+     *   from using its INTx# pin (if implemented) to request
+     *   service (MSI, MSI-X, and INTx# are mutually exclusive).
+     */
+    pci_device_deassert_intx(dev);
+
+    /*
+     * nr_vectors might be set bigger than capable. So clamp it.
+     * This is not legal by spec, so we can do anything we like,
+     * just don't crash the host
+     */
+    log_num_vecs =
+        (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+    log_max_vecs =
+        (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+    if (log_num_vecs > log_max_vecs) {
+        flags &= ~PCI_MSI_FLAGS_QSIZE;
+        flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+        pci_set_word(dev->config + msi_flags_off(dev), flags);
+    }
+
+    if (!msi_per_vector_mask) {
+        /* if per vector masking isn't supported,
+           there is no pending interrupt. */
+        return;
+    }
+
+    nr_vectors = msi_nr_vectors(flags);
+
+    /* This will discard pending interrupts, if any. */
+    pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
+    pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
+    pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
+
+    /* deliver pending interrupts which are unmasked */
+    for (vector = 0; vector < nr_vectors; ++vector) {
+        if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
+            continue;
+        }
+
+        pci_long_test_and_clear_mask(
+            dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+        msi_notify(dev, vector);
+    }
+}
+
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    return msi_nr_vectors(flags);
+}
diff --git a/qemu-0.15.x/hw/msi.h b/qemu-0.15.x/hw/msi.h
new file mode 100644
index 0000000..5766018
--- /dev/null
+++ b/qemu-0.15.x/hw/msi.h
@@ -0,0 +1,41 @@
+/*
+ * msi.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_MSI_H
+#define QEMU_MSI_H
+
+#include "qemu-common.h"
+#include "pci.h"
+
+bool msi_enabled(const PCIDevice *dev);
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+             unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
+void msi_uninit(struct PCIDevice *dev);
+void msi_reset(PCIDevice *dev);
+void msi_notify(PCIDevice *dev, unsigned int vector);
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
+
+static inline bool msi_present(const PCIDevice *dev)
+{
+    return dev->cap_present & QEMU_PCI_CAP_MSI;
+}
+
+#endif /* QEMU_MSI_H */
diff --git a/qemu-0.15.x/hw/msix.c b/qemu-0.15.x/hw/msix.c
new file mode 100644
index 0000000..e67e700
--- /dev/null
+++ b/qemu-0.15.x/hw/msix.c
@@ -0,0 +1,410 @@
+/*
+ * MSI-X device support
+ *
+ * This module includes support for MSI-X in pci devices.
+ *
+ * Author: Michael S. Tsirkin <mst at redhat.com>
+ *
+ *  Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (mst at redhat.com)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "hw.h"
+#include "msix.h"
+#include "pci.h"
+#include "range.h"
+
+#define MSIX_CAP_LENGTH 12
+
+/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
+#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
+#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
+#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
+
+/* How much space does an MSIX table need. */
+/* The spec requires giving the table structure
+ * a 4K aligned region all by itself. */
+#define MSIX_PAGE_SIZE 0x1000
+/* Reserve second half of the page for pending bits */
+#define MSIX_PAGE_PENDING (MSIX_PAGE_SIZE / 2)
+#define MSIX_MAX_ENTRIES 32
+
+
+/* Flag for interrupt controller to declare MSI-X support */
+int msix_supported;
+
+/* Add MSI-X capability to the config space for the device. */
+/* Given a bar and its size, add MSI-X table on top of it
+ * and fill MSI-X capability in the config space.
+ * Original bar size must be a power of 2 or 0.
+ * New bar size is returned. */
+static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
+                           unsigned bar_nr, unsigned bar_size)
+{
+    int config_offset;
+    uint8_t *config;
+    uint32_t new_size;
+
+    if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1)
+        return -EINVAL;
+    if (bar_size > 0x80000000)
+        return -ENOSPC;
+
+    /* Add space for MSI-X structures */
+    if (!bar_size) {
+        new_size = MSIX_PAGE_SIZE;
+    } else if (bar_size < MSIX_PAGE_SIZE) {
+        bar_size = MSIX_PAGE_SIZE;
+        new_size = MSIX_PAGE_SIZE * 2;
+    } else {
+        new_size = bar_size * 2;
+    }
+
+    pdev->msix_bar_size = new_size;
+    config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
+                                       0, MSIX_CAP_LENGTH);
+    if (config_offset < 0)
+        return config_offset;
+    config = pdev->config + config_offset;
+
+    pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
+    /* Table on top of BAR */
+    pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
+    /* Pending bits on top of that */
+    pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
+                 bar_nr);
+    pdev->msix_cap = config_offset;
+    /* Make flags bit writable. */
+    pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
+	    MSIX_MASKALL_MASK;
+    return 0;
+}
+
+static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIDevice *dev = opaque;
+    unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
+    void *page = dev->msix_table_page;
+
+    return pci_get_long(page + offset);
+}
+
+static uint32_t msix_mmio_read_unallowed(void *opaque, target_phys_addr_t addr)
+{
+    fprintf(stderr, "MSI-X: only dword read is allowed!\n");
+    return 0;
+}
+
+static uint8_t msix_pending_mask(int vector)
+{
+    return 1 << (vector % 8);
+}
+
+static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
+{
+    return dev->msix_table_page + MSIX_PAGE_PENDING + vector / 8;
+}
+
+static int msix_is_pending(PCIDevice *dev, int vector)
+{
+    return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
+}
+
+static void msix_set_pending(PCIDevice *dev, int vector)
+{
+    *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
+}
+
+static void msix_clr_pending(PCIDevice *dev, int vector)
+{
+    *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
+}
+
+static int msix_function_masked(PCIDevice *dev)
+{
+    return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
+}
+
+static int msix_is_masked(PCIDevice *dev, int vector)
+{
+    unsigned offset =
+        vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
+    return msix_function_masked(dev) ||
+	   dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
+}
+
+static void msix_handle_mask_update(PCIDevice *dev, int vector)
+{
+    if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
+        msix_clr_pending(dev, vector);
+        msix_notify(dev, vector);
+    }
+}
+
+/* Handle MSI-X capability config write. */
+void msix_write_config(PCIDevice *dev, uint32_t addr,
+                       uint32_t val, int len)
+{
+    unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
+    int vector;
+
+    if (!range_covers_byte(addr, len, enable_pos)) {
+        return;
+    }
+
+    if (!msix_enabled(dev)) {
+        return;
+    }
+
+    pci_device_deassert_intx(dev);
+
+    if (msix_function_masked(dev)) {
+        return;
+    }
+
+    for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+        msix_handle_mask_update(dev, vector);
+    }
+}
+
+static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    PCIDevice *dev = opaque;
+    unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
+    int vector = offset / PCI_MSIX_ENTRY_SIZE;
+    pci_set_long(dev->msix_table_page + offset, val);
+    msix_handle_mask_update(dev, vector);
+}
+
+static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr,
+                                      uint32_t val)
+{
+    fprintf(stderr, "MSI-X: only dword write is allowed!\n");
+}
+
+static CPUWriteMemoryFunc * const msix_mmio_write[] = {
+    msix_mmio_write_unallowed, msix_mmio_write_unallowed, msix_mmio_writel
+};
+
+static CPUReadMemoryFunc * const msix_mmio_read[] = {
+    msix_mmio_read_unallowed, msix_mmio_read_unallowed, msix_mmio_readl
+};
+
+/* Should be called from device's map method. */
+void msix_mmio_map(PCIDevice *d, int region_num,
+                   pcibus_t addr, pcibus_t size, int type)
+{
+    uint8_t *config = d->config + d->msix_cap;
+    uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
+    uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
+    /* TODO: for assigned devices, we'll want to make it possible to map
+     * pending bits separately in case they are in a separate bar. */
+    int table_bir = table & PCI_MSIX_FLAGS_BIRMASK;
+
+    if (table_bir != region_num)
+        return;
+    if (size <= offset)
+        return;
+    cpu_register_physical_memory(addr + offset, size - offset,
+                                 d->msix_mmio_index);
+}
+
+static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
+{
+    int vector;
+    for (vector = 0; vector < nentries; ++vector) {
+        unsigned offset =
+            vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
+        dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
+    }
+}
+
+/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
+ * modified, it should be retrieved with msix_bar_size. */
+int msix_init(struct PCIDevice *dev, unsigned short nentries,
+              unsigned bar_nr, unsigned bar_size)
+{
+    int ret;
+    /* Nothing to do if MSI is not supported by interrupt controller */
+    if (!msix_supported)
+        return -ENOTSUP;
+
+    if (nentries > MSIX_MAX_ENTRIES)
+        return -EINVAL;
+
+    dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
+                                        sizeof *dev->msix_entry_used);
+
+    dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
+    msix_mask_all(dev, nentries);
+
+    dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read,
+                                                  msix_mmio_write, dev,
+                                                  DEVICE_NATIVE_ENDIAN);
+    if (dev->msix_mmio_index == -1) {
+        ret = -EBUSY;
+        goto err_index;
+    }
+
+    dev->msix_entries_nr = nentries;
+    ret = msix_add_config(dev, nentries, bar_nr, bar_size);
+    if (ret)
+        goto err_config;
+
+    dev->cap_present |= QEMU_PCI_CAP_MSIX;
+    return 0;
+
+err_config:
+    dev->msix_entries_nr = 0;
+    cpu_unregister_io_memory(dev->msix_mmio_index);
+err_index:
+    qemu_free(dev->msix_table_page);
+    dev->msix_table_page = NULL;
+    qemu_free(dev->msix_entry_used);
+    dev->msix_entry_used = NULL;
+    return ret;
+}
+
+static void msix_free_irq_entries(PCIDevice *dev)
+{
+    int vector;
+
+    for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+        dev->msix_entry_used[vector] = 0;
+        msix_clr_pending(dev, vector);
+    }
+}
+
+/* Clean up resources for the device. */
+int msix_uninit(PCIDevice *dev)
+{
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+        return 0;
+    pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
+    dev->msix_cap = 0;
+    msix_free_irq_entries(dev);
+    dev->msix_entries_nr = 0;
+    cpu_unregister_io_memory(dev->msix_mmio_index);
+    qemu_free(dev->msix_table_page);
+    dev->msix_table_page = NULL;
+    qemu_free(dev->msix_entry_used);
+    dev->msix_entry_used = NULL;
+    dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
+    return 0;
+}
+
+void msix_save(PCIDevice *dev, QEMUFile *f)
+{
+    unsigned n = dev->msix_entries_nr;
+
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+        return;
+    }
+
+    qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
+    qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
+}
+
+/* Should be called after restoring the config space. */
+void msix_load(PCIDevice *dev, QEMUFile *f)
+{
+    unsigned n = dev->msix_entries_nr;
+
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+        return;
+    }
+
+    msix_free_irq_entries(dev);
+    qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
+    qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
+}
+
+/* Does device support MSI-X? */
+int msix_present(PCIDevice *dev)
+{
+    return dev->cap_present & QEMU_PCI_CAP_MSIX;
+}
+
+/* Is MSI-X enabled? */
+int msix_enabled(PCIDevice *dev)
+{
+    return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
+        (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
+         MSIX_ENABLE_MASK);
+}
+
+/* Size of bar where MSI-X table resides, or 0 if MSI-X not supported. */
+uint32_t msix_bar_size(PCIDevice *dev)
+{
+    return (dev->cap_present & QEMU_PCI_CAP_MSIX) ?
+        dev->msix_bar_size : 0;
+}
+
+/* Send an MSI-X message */
+void msix_notify(PCIDevice *dev, unsigned vector)
+{
+    uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
+    uint64_t address;
+    uint32_t data;
+
+    if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
+        return;
+    if (msix_is_masked(dev, vector)) {
+        msix_set_pending(dev, vector);
+        return;
+    }
+
+    address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
+    data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
+    stl_le_phys(address, data);
+}
+
+void msix_reset(PCIDevice *dev)
+{
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+        return;
+    msix_free_irq_entries(dev);
+    dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
+	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
+    memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
+    msix_mask_all(dev, dev->msix_entries_nr);
+}
+
+/* PCI spec suggests that devices make it possible for software to configure
+ * less vectors than supported by the device, but does not specify a standard
+ * mechanism for devices to do so.
+ *
+ * We support this by asking devices to declare vectors software is going to
+ * actually use, and checking this on the notification path. Devices that
+ * don't want to follow the spec suggestion can declare all vectors as used. */
+
+/* Mark vector as used. */
+int msix_vector_use(PCIDevice *dev, unsigned vector)
+{
+    if (vector >= dev->msix_entries_nr)
+        return -EINVAL;
+    dev->msix_entry_used[vector]++;
+    return 0;
+}
+
+/* Mark vector as unused. */
+void msix_vector_unuse(PCIDevice *dev, unsigned vector)
+{
+    if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
+        return;
+    }
+    if (--dev->msix_entry_used[vector]) {
+        return;
+    }
+    msix_clr_pending(dev, vector);
+}
+
+void msix_unuse_all_vectors(PCIDevice *dev)
+{
+    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+        return;
+    msix_free_irq_entries(dev);
+}
diff --git a/qemu-0.15.x/hw/msix.h b/qemu-0.15.x/hw/msix.h
new file mode 100644
index 0000000..a9f7993
--- /dev/null
+++ b/qemu-0.15.x/hw/msix.h
@@ -0,0 +1,36 @@
+#ifndef QEMU_MSIX_H
+#define QEMU_MSIX_H
+
+#include "qemu-common.h"
+#include "pci.h"
+
+int msix_init(PCIDevice *pdev, unsigned short nentries,
+              unsigned bar_nr, unsigned bar_size);
+
+void msix_write_config(PCIDevice *pci_dev, uint32_t address,
+                       uint32_t val, int len);
+
+void msix_mmio_map(PCIDevice *pci_dev, int region_num,
+                   pcibus_t addr, pcibus_t size, int type);
+
+int msix_uninit(PCIDevice *d);
+
+void msix_save(PCIDevice *dev, QEMUFile *f);
+void msix_load(PCIDevice *dev, QEMUFile *f);
+
+int msix_enabled(PCIDevice *dev);
+int msix_present(PCIDevice *dev);
+
+uint32_t msix_bar_size(PCIDevice *dev);
+
+int msix_vector_use(PCIDevice *dev, unsigned vector);
+void msix_vector_unuse(PCIDevice *dev, unsigned vector);
+void msix_unuse_all_vectors(PCIDevice *dev);
+
+void msix_notify(PCIDevice *dev, unsigned vector);
+
+void msix_reset(PCIDevice *dev);
+
+extern int msix_supported;
+
+#endif
diff --git a/qemu-0.15.x/hw/msmouse.c b/qemu-0.15.x/hw/msmouse.c
new file mode 100644
index 0000000..67c6cd4
--- /dev/null
+++ b/qemu-0.15.x/hw/msmouse.c
@@ -0,0 +1,79 @@
+/*
+ * QEMU Microsoft serial mouse emulation
+ *
+ * Copyright (c) 2008 Lubomir Rintel
+ *
+ * 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 <stdlib.h>
+#include "../qemu-common.h"
+#include "../qemu-char.h"
+#include "../console.h"
+#include "msmouse.h"
+
+#define MSMOUSE_LO6(n) ((n) & 0x3f)
+#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
+
+static void msmouse_event(void *opaque,
+                          int dx, int dy, int dz, int buttons_state)
+{
+    CharDriverState *chr = (CharDriverState *)opaque;
+
+    unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
+
+    /* Movement deltas */
+    bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
+    bytes[1] |= MSMOUSE_LO6(dx);
+    bytes[2] |= MSMOUSE_LO6(dy);
+
+    /* Buttons */
+    bytes[0] |= (buttons_state & 0x01 ? 0x20 : 0x00);
+    bytes[0] |= (buttons_state & 0x02 ? 0x10 : 0x00);
+    bytes[3] |= (buttons_state & 0x04 ? 0x20 : 0x00);
+
+    /* We always send the packet of, so that we do not have to keep track
+       of previous state of the middle button. This can potentially confuse
+       some very old drivers for two button mice though. */
+    qemu_chr_read(chr, bytes, 4);
+}
+
+static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
+{
+    /* Ignore writes to mouse port */
+    return len;
+}
+
+static void msmouse_chr_close (struct CharDriverState *chr)
+{
+    qemu_free (chr);
+}
+
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = msmouse_chr_write;
+    chr->chr_close = msmouse_chr_close;
+
+    qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
+
+    *_chr = chr;
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/msmouse.h b/qemu-0.15.x/hw/msmouse.h
new file mode 100644
index 0000000..8b853b3
--- /dev/null
+++ b/qemu-0.15.x/hw/msmouse.h
@@ -0,0 +1,2 @@
+/* msmouse.c */
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr);
diff --git a/qemu-0.15.x/hw/mst_fpga.c b/qemu-0.15.x/hw/mst_fpga.c
new file mode 100644
index 0000000..4e47574
--- /dev/null
+++ b/qemu-0.15.x/hw/mst_fpga.c
@@ -0,0 +1,255 @@
+/*
+ * PXA270-based Intel Mainstone platforms.
+ * FPGA driver
+ *
+ * Copyright (c) 2007 by Armin Kuster <akuster at kama-aina.net> or
+ *                                    <akuster at mvista.com>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+/* Mainstone FPGA for extern irqs */
+#define FPGA_GPIO_PIN	0
+#define MST_NUM_IRQS	16
+#define MST_LEDDAT1		0x10
+#define MST_LEDDAT2		0x14
+#define MST_LEDCTRL		0x40
+#define MST_GPSWR		0x60
+#define MST_MSCWR1		0x80
+#define MST_MSCWR2		0x84
+#define MST_MSCWR3		0x88
+#define MST_MSCRD		0x90
+#define MST_INTMSKENA	0xc0
+#define MST_INTSETCLR	0xd0
+#define MST_PCMCIA0		0xe0
+#define MST_PCMCIA1		0xe4
+
+#define MST_PCMCIAx_READY	(1 << 10)
+#define MST_PCMCIAx_nCD		(1 << 5)
+
+#define MST_PCMCIA_CD0_IRQ	9
+#define MST_PCMCIA_CD1_IRQ	13
+
+typedef struct mst_irq_state{
+	SysBusDevice busdev;
+
+	qemu_irq parent;
+
+	uint32_t prev_level;
+	uint32_t leddat1;
+	uint32_t leddat2;
+	uint32_t ledctrl;
+	uint32_t gpswr;
+	uint32_t mscwr1;
+	uint32_t mscwr2;
+	uint32_t mscwr3;
+	uint32_t mscrd;
+	uint32_t intmskena;
+	uint32_t intsetclr;
+	uint32_t pcmcia0;
+	uint32_t pcmcia1;
+}mst_irq_state;
+
+static void
+mst_fpga_set_irq(void *opaque, int irq, int level)
+{
+	mst_irq_state *s = (mst_irq_state *)opaque;
+	uint32_t oldint = s->intsetclr & s->intmskena;
+
+	if (level)
+		s->prev_level |= 1u << irq;
+	else
+		s->prev_level &= ~(1u << irq);
+
+	switch(irq) {
+	case MST_PCMCIA_CD0_IRQ:
+		if (level)
+			s->pcmcia0 &= ~MST_PCMCIAx_nCD;
+		else
+			s->pcmcia0 |=  MST_PCMCIAx_nCD;
+		break;
+	case MST_PCMCIA_CD1_IRQ:
+		if (level)
+			s->pcmcia1 &= ~MST_PCMCIAx_nCD;
+		else
+			s->pcmcia1 |=  MST_PCMCIAx_nCD;
+		break;
+	}
+
+	if ((s->intmskena & (1u << irq)) && level)
+		s->intsetclr |= 1u << irq;
+
+	if (oldint != (s->intsetclr & s->intmskena))
+		qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+}
+
+
+static uint32_t
+mst_fpga_readb(void *opaque, target_phys_addr_t addr)
+{
+	mst_irq_state *s = (mst_irq_state *) opaque;
+
+	switch (addr) {
+	case MST_LEDDAT1:
+		return s->leddat1;
+	case MST_LEDDAT2:
+		return s->leddat2;
+	case MST_LEDCTRL:
+		return s->ledctrl;
+	case MST_GPSWR:
+		return s->gpswr;
+	case MST_MSCWR1:
+		return s->mscwr1;
+	case MST_MSCWR2:
+		return s->mscwr2;
+	case MST_MSCWR3:
+		return s->mscwr3;
+	case MST_MSCRD:
+		return s->mscrd;
+	case MST_INTMSKENA:
+		return s->intmskena;
+	case MST_INTSETCLR:
+		return s->intsetclr;
+	case MST_PCMCIA0:
+		return s->pcmcia0;
+	case MST_PCMCIA1:
+		return s->pcmcia1;
+	default:
+		printf("Mainstone - mst_fpga_readb: Bad register offset "
+			"0x" TARGET_FMT_plx " \n", addr);
+	}
+	return 0;
+}
+
+static void
+mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+	mst_irq_state *s = (mst_irq_state *) opaque;
+	value &= 0xffffffff;
+
+	switch (addr) {
+	case MST_LEDDAT1:
+		s->leddat1 = value;
+		break;
+	case MST_LEDDAT2:
+		s->leddat2 = value;
+		break;
+	case MST_LEDCTRL:
+		s->ledctrl = value;
+		break;
+	case MST_GPSWR:
+		s->gpswr = value;
+		break;
+	case MST_MSCWR1:
+		s->mscwr1 = value;
+		break;
+	case MST_MSCWR2:
+		s->mscwr2 = value;
+		break;
+	case MST_MSCWR3:
+		s->mscwr3 = value;
+		break;
+	case MST_MSCRD:
+		s->mscrd =  value;
+		break;
+	case MST_INTMSKENA:	/* Mask interrupt */
+		s->intmskena = (value & 0xFEEFF);
+		qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+		break;
+	case MST_INTSETCLR:	/* clear or set interrupt */
+		s->intsetclr = (value & 0xFEEFF);
+		qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+		break;
+		/* For PCMCIAx allow the to change only power and reset */
+	case MST_PCMCIA0:
+		s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
+		break;
+	case MST_PCMCIA1:
+		s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
+		break;
+	default:
+		printf("Mainstone - mst_fpga_writeb: Bad register offset "
+			"0x" TARGET_FMT_plx " \n", addr);
+	}
+}
+
+static CPUReadMemoryFunc * const mst_fpga_readfn[] = {
+	mst_fpga_readb,
+	mst_fpga_readb,
+	mst_fpga_readb,
+};
+static CPUWriteMemoryFunc * const mst_fpga_writefn[] = {
+	mst_fpga_writeb,
+	mst_fpga_writeb,
+	mst_fpga_writeb,
+};
+
+
+static int mst_fpga_post_load(void *opaque, int version_id)
+{
+	mst_irq_state *s = (mst_irq_state *) opaque;
+
+	qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+	return 0;
+}
+
+static int mst_fpga_init(SysBusDevice *dev)
+{
+	mst_irq_state *s;
+	int iomemtype;
+
+	s = FROM_SYSBUS(mst_irq_state, dev);
+
+	s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+	s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+
+	sysbus_init_irq(dev, &s->parent);
+
+	/* alloc the external 16 irqs */
+	qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS);
+
+	iomemtype = cpu_register_io_memory(mst_fpga_readfn,
+		mst_fpga_writefn, s, DEVICE_NATIVE_ENDIAN);
+	sysbus_init_mmio(dev, 0x00100000, iomemtype);
+	return 0;
+}
+
+static VMStateDescription vmstate_mst_fpga_regs = {
+	.name = "mainstone_fpga",
+	.version_id = 0,
+	.minimum_version_id = 0,
+	.minimum_version_id_old = 0,
+	.post_load = mst_fpga_post_load,
+	.fields = (VMStateField []) {
+		VMSTATE_UINT32(prev_level, mst_irq_state),
+		VMSTATE_UINT32(leddat1, mst_irq_state),
+		VMSTATE_UINT32(leddat2, mst_irq_state),
+		VMSTATE_UINT32(ledctrl, mst_irq_state),
+		VMSTATE_UINT32(gpswr, mst_irq_state),
+		VMSTATE_UINT32(mscwr1, mst_irq_state),
+		VMSTATE_UINT32(mscwr2, mst_irq_state),
+		VMSTATE_UINT32(mscwr3, mst_irq_state),
+		VMSTATE_UINT32(mscrd, mst_irq_state),
+		VMSTATE_UINT32(intmskena, mst_irq_state),
+		VMSTATE_UINT32(intsetclr, mst_irq_state),
+		VMSTATE_UINT32(pcmcia0, mst_irq_state),
+		VMSTATE_UINT32(pcmcia1, mst_irq_state),
+		VMSTATE_END_OF_LIST(),
+	},
+};
+
+static SysBusDeviceInfo mst_fpga_info = {
+	.init = mst_fpga_init,
+	.qdev.name = "mainstone-fpga",
+	.qdev.desc = "Mainstone II FPGA",
+	.qdev.size = sizeof(mst_irq_state),
+	.qdev.vmsd = &vmstate_mst_fpga_regs,
+};
+
+static void mst_fpga_register(void)
+{
+	sysbus_register_withprop(&mst_fpga_info);
+}
+device_init(mst_fpga_register);
diff --git a/qemu-0.15.x/hw/multiboot.c b/qemu-0.15.x/hw/multiboot.c
new file mode 100644
index 0000000..2426e84
--- /dev/null
+++ b/qemu-0.15.x/hw/multiboot.c
@@ -0,0 +1,339 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * 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 "hw.h"
+#include "fw_cfg.h"
+#include "multiboot.h"
+#include "loader.h"
+#include "elf.h"
+#include "sysemu.h"
+
+/* Show multiboot debug output */
+//#define DEBUG_MULTIBOOT
+
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
+#define MULTIBOOT_STRUCT_ADDR 0x9000
+
+#if MULTIBOOT_STRUCT_ADDR > 0xf0000
+#error multiboot struct needs to fit in 16 bit real mode
+#endif
+
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+typedef struct {
+    /* buffer holding kernel, cmdlines and mb_infos */
+    void *mb_buf;
+    /* address in target */
+    target_phys_addr_t mb_buf_phys;
+    /* size of mb_buf in bytes */
+    unsigned mb_buf_size;
+    /* offset of mb-info's in bytes */
+    target_phys_addr_t offset_mbinfo;
+    /* offset in buffer for cmdlines in bytes */
+    target_phys_addr_t offset_cmdlines;
+    /* offset of modules in bytes */
+    target_phys_addr_t offset_mods;
+    /* available slots for mb modules infos */
+    int mb_mods_avail;
+    /* currently used slots of mb modules */
+    int mb_mods_count;
+} MultibootState;
+
+static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
+{
+    target_phys_addr_t p = s->offset_cmdlines;
+    char *b = (char *)s->mb_buf + p;
+
+    get_opt_value(b, strlen(cmdline) + 1, cmdline);
+    s->offset_cmdlines += strlen(b) + 1;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(MultibootState *s,
+                       target_phys_addr_t start, target_phys_addr_t end,
+                       target_phys_addr_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
+             s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header)
+{
+    int i, is_multiboot = 0;
+    uint32_t flags = 0;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+    MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
+    uint8_t *mb_bootinfo_data;
+
+    /* Ok, let's see if it is a multiboot image.
+       The header is 12x32bit long, so the latest entry may be 8192 - 48. */
+    for (i = 0; i < (8192 - 48); i += 4) {
+        if (ldl_p(header+i) == 0x1BADB002) {
+            uint32_t checksum = ldl_p(header+i+8);
+            flags = ldl_p(header+i+4);
+            checksum += flags;
+            checksum += (uint32_t)0x1BADB002;
+            if (!checksum) {
+                is_multiboot = 1;
+                break;
+            }
+        }
+    }
+
+    if (!is_multiboot)
+        return 0; /* no multiboot */
+
+    mb_debug("qemu: I believe we found a multiboot image!\n");
+    memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
+
+    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
+        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+    }
+    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
+        uint64_t elf_entry;
+        uint64_t elf_low, elf_high;
+        int kernel_size;
+        fclose(f);
+
+        if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
+            fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+            exit(1);
+        }
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_low, &elf_high, 0, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = elf_low;
+        mb_kernel_size = elf_high - elf_low;
+        mh_entry_addr = elf_entry;
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
+            fprintf(stderr, "Error while fetching elf kernel from rom\n");
+            exit(1);
+        }
+
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
+    } else {
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+        uint32_t mh_header_addr = ldl_p(header+i+12);
+        mh_load_addr = ldl_p(header+i+16);
+        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+
+        mh_entry_addr = ldl_p(header+i+28);
+        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
+        uint32_t mh_mode_type = ldl_p(header+i+32);
+        uint32_t mh_width = ldl_p(header+i+36);
+        uint32_t mh_height = ldl_p(header+i+40);
+        uint32_t mh_depth = ldl_p(header+i+44); */
+
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_kernel_size, mh_load_addr);
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        fseek(f, mb_kernel_text_offset, SEEK_SET);
+        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
+            fprintf(stderr, "fread() failed\n");
+            exit(1);
+        }
+        fclose(f);
+    }
+
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while (*(r = get_opt_value(NULL, 0, r))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
+
+    if (initrd_filename) {
+        char *next_initrd, not_last;
+
+        mbs.offset_mods = mbs.mb_buf_size;
+
+        do {
+            char *next_space;
+            int mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
+
+            next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
+            not_last = *next_initrd;
+            *next_initrd = '\0';
+            /* if a space comes after the module filename, treat everything
+               after that as parameters */
+            target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
+            if ((next_space = strchr(initrd_filename, ' ')))
+                *next_space = '\0';
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
+            mb_mod_length = get_image_size(initrd_filename);
+            if (mb_mod_length < 0) {
+                fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
+                exit(1);
+            }
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: "TARGET_FMT_plx"\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
+            initrd_filename = next_initrd+1;
+        } while (not_last);
+    }
+
+    /* Commandline support */
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
+             kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   (ram_size / 1024) - 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
+
+    /* save bootinfo off the stack */
+    mb_bootinfo_data = qemu_malloc(sizeof(bootinfo));
+    memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo));
+
+    /* Pass variables to option rom */
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo));
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
+                     sizeof(bootinfo));
+
+    option_rom[nb_option_roms].name = "multiboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
+    nb_option_roms++;
+
+    return 1; /* yes, we are multiboot */
+}
diff --git a/qemu-0.15.x/hw/multiboot.h b/qemu-0.15.x/hw/multiboot.h
new file mode 100644
index 0000000..98fb1b7
--- /dev/null
+++ b/qemu-0.15.x/hw/multiboot.h
@@ -0,0 +1,12 @@
+#ifndef QEMU_MULTIBOOT_H
+#define QEMU_MULTIBOOT_H
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header);
+
+#endif
diff --git a/qemu-0.15.x/hw/musicpal.c b/qemu-0.15.x/hw/musicpal.c
new file mode 100644
index 0000000..63dd391
--- /dev/null
+++ b/qemu-0.15.x/hw/musicpal.c
@@ -0,0 +1,1665 @@
+/*
+ * Marvell MV88W8618 / Freecom MusicPal emulation.
+ *
+ * Copyright (c) 2008 Jan Kiszka
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "block.h"
+#include "flash.h"
+#include "console.h"
+#include "i2c.h"
+#include "blockdev.h"
+
+#define MP_MISC_BASE            0x80002000
+#define MP_MISC_SIZE            0x00001000
+
+#define MP_ETH_BASE             0x80008000
+#define MP_ETH_SIZE             0x00001000
+
+#define MP_WLAN_BASE            0x8000C000
+#define MP_WLAN_SIZE            0x00000800
+
+#define MP_UART1_BASE           0x8000C840
+#define MP_UART2_BASE           0x8000C940
+
+#define MP_GPIO_BASE            0x8000D000
+#define MP_GPIO_SIZE            0x00001000
+
+#define MP_FLASHCFG_BASE        0x90006000
+#define MP_FLASHCFG_SIZE        0x00001000
+
+#define MP_AUDIO_BASE           0x90007000
+
+#define MP_PIC_BASE             0x90008000
+#define MP_PIC_SIZE             0x00001000
+
+#define MP_PIT_BASE             0x90009000
+#define MP_PIT_SIZE             0x00001000
+
+#define MP_LCD_BASE             0x9000c000
+#define MP_LCD_SIZE             0x00001000
+
+#define MP_SRAM_BASE            0xC0000000
+#define MP_SRAM_SIZE            0x00020000
+
+#define MP_RAM_DEFAULT_SIZE     32*1024*1024
+#define MP_FLASH_SIZE_MAX       32*1024*1024
+
+#define MP_TIMER1_IRQ           4
+#define MP_TIMER2_IRQ           5
+#define MP_TIMER3_IRQ           6
+#define MP_TIMER4_IRQ           7
+#define MP_EHCI_IRQ             8
+#define MP_ETH_IRQ              9
+#define MP_UART1_IRQ            11
+#define MP_UART2_IRQ            11
+#define MP_GPIO_IRQ             12
+#define MP_RTC_IRQ              28
+#define MP_AUDIO_IRQ            30
+
+/* Wolfson 8750 I2C address */
+#define MP_WM_ADDR              0x1A
+
+/* Ethernet register offsets */
+#define MP_ETH_SMIR             0x010
+#define MP_ETH_PCXR             0x408
+#define MP_ETH_SDCMR            0x448
+#define MP_ETH_ICR              0x450
+#define MP_ETH_IMR              0x458
+#define MP_ETH_FRDP0            0x480
+#define MP_ETH_FRDP1            0x484
+#define MP_ETH_FRDP2            0x488
+#define MP_ETH_FRDP3            0x48C
+#define MP_ETH_CRDP0            0x4A0
+#define MP_ETH_CRDP1            0x4A4
+#define MP_ETH_CRDP2            0x4A8
+#define MP_ETH_CRDP3            0x4AC
+#define MP_ETH_CTDP0            0x4E0
+#define MP_ETH_CTDP1            0x4E4
+#define MP_ETH_CTDP2            0x4E8
+#define MP_ETH_CTDP3            0x4EC
+
+/* MII PHY access */
+#define MP_ETH_SMIR_DATA        0x0000FFFF
+#define MP_ETH_SMIR_ADDR        0x03FF0000
+#define MP_ETH_SMIR_OPCODE      (1 << 26) /* Read value */
+#define MP_ETH_SMIR_RDVALID     (1 << 27)
+
+/* PHY registers */
+#define MP_ETH_PHY1_BMSR        0x00210000
+#define MP_ETH_PHY1_PHYSID1     0x00410000
+#define MP_ETH_PHY1_PHYSID2     0x00610000
+
+#define MP_PHY_BMSR_LINK        0x0004
+#define MP_PHY_BMSR_AUTONEG     0x0008
+
+#define MP_PHY_88E3015          0x01410E20
+
+/* TX descriptor status */
+#define MP_ETH_TX_OWN           (1 << 31)
+
+/* RX descriptor status */
+#define MP_ETH_RX_OWN           (1 << 31)
+
+/* Interrupt cause/mask bits */
+#define MP_ETH_IRQ_RX_BIT       0
+#define MP_ETH_IRQ_RX           (1 << MP_ETH_IRQ_RX_BIT)
+#define MP_ETH_IRQ_TXHI_BIT     2
+#define MP_ETH_IRQ_TXLO_BIT     3
+
+/* Port config bits */
+#define MP_ETH_PCXR_2BSM_BIT    28 /* 2-byte incoming suffix */
+
+/* SDMA command bits */
+#define MP_ETH_CMD_TXHI         (1 << 23)
+#define MP_ETH_CMD_TXLO         (1 << 22)
+
+typedef struct mv88w8618_tx_desc {
+    uint32_t cmdstat;
+    uint16_t res;
+    uint16_t bytes;
+    uint32_t buffer;
+    uint32_t next;
+} mv88w8618_tx_desc;
+
+typedef struct mv88w8618_rx_desc {
+    uint32_t cmdstat;
+    uint16_t bytes;
+    uint16_t buffer_size;
+    uint32_t buffer;
+    uint32_t next;
+} mv88w8618_rx_desc;
+
+typedef struct mv88w8618_eth_state {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t smir;
+    uint32_t icr;
+    uint32_t imr;
+    int mmio_index;
+    uint32_t vlan_header;
+    uint32_t tx_queue[2];
+    uint32_t rx_queue[4];
+    uint32_t frx_queue[4];
+    uint32_t cur_rx[4];
+    NICState *nic;
+    NICConf conf;
+} mv88w8618_eth_state;
+
+static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+    cpu_to_le32s(&desc->cmdstat);
+    cpu_to_le16s(&desc->bytes);
+    cpu_to_le16s(&desc->buffer_size);
+    cpu_to_le32s(&desc->buffer);
+    cpu_to_le32s(&desc->next);
+    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+    le32_to_cpus(&desc->cmdstat);
+    le16_to_cpus(&desc->bytes);
+    le16_to_cpus(&desc->buffer_size);
+    le32_to_cpus(&desc->buffer);
+    le32_to_cpus(&desc->next);
+}
+
+static int eth_can_receive(VLANClientState *nc)
+{
+    return 1;
+}
+
+static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    uint32_t desc_addr;
+    mv88w8618_rx_desc desc;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        desc_addr = s->cur_rx[i];
+        if (!desc_addr) {
+            continue;
+        }
+        do {
+            eth_rx_desc_get(desc_addr, &desc);
+            if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
+                cpu_physical_memory_write(desc.buffer + s->vlan_header,
+                                          buf, size);
+                desc.bytes = size + s->vlan_header;
+                desc.cmdstat &= ~MP_ETH_RX_OWN;
+                s->cur_rx[i] = desc.next;
+
+                s->icr |= MP_ETH_IRQ_RX;
+                if (s->icr & s->imr) {
+                    qemu_irq_raise(s->irq);
+                }
+                eth_rx_desc_put(desc_addr, &desc);
+                return size;
+            }
+            desc_addr = desc.next;
+        } while (desc_addr != s->rx_queue[i]);
+    }
+    return size;
+}
+
+static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+    cpu_to_le32s(&desc->cmdstat);
+    cpu_to_le16s(&desc->res);
+    cpu_to_le16s(&desc->bytes);
+    cpu_to_le32s(&desc->buffer);
+    cpu_to_le32s(&desc->next);
+    cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+    cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+    le32_to_cpus(&desc->cmdstat);
+    le16_to_cpus(&desc->res);
+    le16_to_cpus(&desc->bytes);
+    le32_to_cpus(&desc->buffer);
+    le32_to_cpus(&desc->next);
+}
+
+static void eth_send(mv88w8618_eth_state *s, int queue_index)
+{
+    uint32_t desc_addr = s->tx_queue[queue_index];
+    mv88w8618_tx_desc desc;
+    uint32_t next_desc;
+    uint8_t buf[2048];
+    int len;
+
+    do {
+        eth_tx_desc_get(desc_addr, &desc);
+        next_desc = desc.next;
+        if (desc.cmdstat & MP_ETH_TX_OWN) {
+            len = desc.bytes;
+            if (len < 2048) {
+                cpu_physical_memory_read(desc.buffer, buf, len);
+                qemu_send_packet(&s->nic->nc, buf, len);
+            }
+            desc.cmdstat &= ~MP_ETH_TX_OWN;
+            s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
+            eth_tx_desc_put(desc_addr, &desc);
+        }
+        desc_addr = next_desc;
+    } while (desc_addr != s->tx_queue[queue_index]);
+}
+
+static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
+{
+    mv88w8618_eth_state *s = opaque;
+
+    switch (offset) {
+    case MP_ETH_SMIR:
+        if (s->smir & MP_ETH_SMIR_OPCODE) {
+            switch (s->smir & MP_ETH_SMIR_ADDR) {
+            case MP_ETH_PHY1_BMSR:
+                return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
+                       MP_ETH_SMIR_RDVALID;
+            case MP_ETH_PHY1_PHYSID1:
+                return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
+            case MP_ETH_PHY1_PHYSID2:
+                return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
+            default:
+                return MP_ETH_SMIR_RDVALID;
+            }
+        }
+        return 0;
+
+    case MP_ETH_ICR:
+        return s->icr;
+
+    case MP_ETH_IMR:
+        return s->imr;
+
+    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
+        return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
+
+    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
+        return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
+
+    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
+        return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    mv88w8618_eth_state *s = opaque;
+
+    switch (offset) {
+    case MP_ETH_SMIR:
+        s->smir = value;
+        break;
+
+    case MP_ETH_PCXR:
+        s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
+        break;
+
+    case MP_ETH_SDCMR:
+        if (value & MP_ETH_CMD_TXHI) {
+            eth_send(s, 1);
+        }
+        if (value & MP_ETH_CMD_TXLO) {
+            eth_send(s, 0);
+        }
+        if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_ETH_ICR:
+        s->icr &= value;
+        break;
+
+    case MP_ETH_IMR:
+        s->imr = value;
+        if (s->icr & s->imr) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
+        s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
+        break;
+
+    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
+        s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
+            s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
+        break;
+
+    case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
+        s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const mv88w8618_eth_readfn[] = {
+    mv88w8618_eth_read,
+    mv88w8618_eth_read,
+    mv88w8618_eth_read
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = {
+    mv88w8618_eth_write,
+    mv88w8618_eth_write,
+    mv88w8618_eth_write
+};
+
+static void eth_cleanup(VLANClientState *nc)
+{
+    mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_mv88w8618_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_receive,
+    .receive = eth_receive,
+    .cleanup = eth_cleanup,
+};
+
+static int mv88w8618_eth_init(SysBusDevice *dev)
+{
+    mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn,
+                                           mv88w8618_eth_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_eth_vmsd = {
+    .name = "mv88w8618_eth",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(smir, mv88w8618_eth_state),
+        VMSTATE_UINT32(icr, mv88w8618_eth_state),
+        VMSTATE_UINT32(imr, mv88w8618_eth_state),
+        VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
+        VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
+        VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
+        VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
+        VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo mv88w8618_eth_info = {
+    .init = mv88w8618_eth_init,
+    .qdev.name = "mv88w8618_eth",
+    .qdev.size = sizeof(mv88w8618_eth_state),
+    .qdev.vmsd = &mv88w8618_eth_vmsd,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+/* LCD register offsets */
+#define MP_LCD_IRQCTRL          0x180
+#define MP_LCD_IRQSTAT          0x184
+#define MP_LCD_SPICTRL          0x1ac
+#define MP_LCD_INST             0x1bc
+#define MP_LCD_DATA             0x1c0
+
+/* Mode magics */
+#define MP_LCD_SPI_DATA         0x00100011
+#define MP_LCD_SPI_CMD          0x00104011
+#define MP_LCD_SPI_INVALID      0x00000000
+
+/* Commmands */
+#define MP_LCD_INST_SETPAGE0    0xB0
+/* ... */
+#define MP_LCD_INST_SETPAGE7    0xB7
+
+#define MP_LCD_TEXTCOLOR        0xe0e0ff /* RRGGBB */
+
+typedef struct musicpal_lcd_state {
+    SysBusDevice busdev;
+    uint32_t brightness;
+    uint32_t mode;
+    uint32_t irqctrl;
+    uint32_t page;
+    uint32_t page_off;
+    DisplayState *ds;
+    uint8_t video_ram[128*64/8];
+} musicpal_lcd_state;
+
+static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
+{
+    switch (s->brightness) {
+    case 7:
+        return col;
+    case 0:
+        return 0;
+    default:
+        return (col * s->brightness) / 7;
+    }
+}
+
+#define SET_LCD_PIXEL(depth, type) \
+static inline void glue(set_lcd_pixel, depth) \
+        (musicpal_lcd_state *s, int x, int y, type col) \
+{ \
+    int dx, dy; \
+    type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \
+\
+    for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
+        for (dx = 0; dx < 3; dx++, pixel++) \
+            *pixel = col; \
+}
+SET_LCD_PIXEL(8, uint8_t)
+SET_LCD_PIXEL(16, uint16_t)
+SET_LCD_PIXEL(32, uint32_t)
+
+#include "pixel_ops.h"
+
+static void lcd_refresh(void *opaque)
+{
+    musicpal_lcd_state *s = opaque;
+    int x, y, col;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+#define LCD_REFRESH(depth, func) \
+    case depth: \
+        col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
+                   scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
+                   scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
+        for (x = 0; x < 128; x++) { \
+            for (y = 0; y < 64; y++) { \
+                if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
+                    glue(set_lcd_pixel, depth)(s, x, y, col); \
+                } else { \
+                    glue(set_lcd_pixel, depth)(s, x, y, 0); \
+                } \
+            } \
+        } \
+        break;
+    LCD_REFRESH(8, rgb_to_pixel8)
+    LCD_REFRESH(16, rgb_to_pixel16)
+    LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ?
+                     rgb_to_pixel32bgr : rgb_to_pixel32))
+    default:
+        hw_error("unsupported colour depth %i\n",
+                  ds_get_bits_per_pixel(s->ds));
+    }
+
+    dpy_update(s->ds, 0, 0, 128*3, 64*3);
+}
+
+static void lcd_invalidate(void *opaque)
+{
+}
+
+static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
+{
+    musicpal_lcd_state *s = opaque;
+    s->brightness &= ~(1 << irq);
+    s->brightness |= level << irq;
+}
+
+static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
+{
+    musicpal_lcd_state *s = opaque;
+
+    switch (offset) {
+    case MP_LCD_IRQCTRL:
+        return s->irqctrl;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    musicpal_lcd_state *s = opaque;
+
+    switch (offset) {
+    case MP_LCD_IRQCTRL:
+        s->irqctrl = value;
+        break;
+
+    case MP_LCD_SPICTRL:
+        if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
+            s->mode = value;
+        } else {
+            s->mode = MP_LCD_SPI_INVALID;
+        }
+        break;
+
+    case MP_LCD_INST:
+        if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
+            s->page = value - MP_LCD_INST_SETPAGE0;
+            s->page_off = 0;
+        }
+        break;
+
+    case MP_LCD_DATA:
+        if (s->mode == MP_LCD_SPI_CMD) {
+            if (value >= MP_LCD_INST_SETPAGE0 &&
+                value <= MP_LCD_INST_SETPAGE7) {
+                s->page = value - MP_LCD_INST_SETPAGE0;
+                s->page_off = 0;
+            }
+        } else if (s->mode == MP_LCD_SPI_DATA) {
+            s->video_ram[s->page*128 + s->page_off] = value;
+            s->page_off = (s->page_off + 1) & 127;
+        }
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const musicpal_lcd_readfn[] = {
+    musicpal_lcd_read,
+    musicpal_lcd_read,
+    musicpal_lcd_read
+};
+
+static CPUWriteMemoryFunc * const musicpal_lcd_writefn[] = {
+    musicpal_lcd_write,
+    musicpal_lcd_write,
+    musicpal_lcd_write
+};
+
+static int musicpal_lcd_init(SysBusDevice *dev)
+{
+    musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
+    int iomemtype;
+
+    s->brightness = 7;
+
+    iomemtype = cpu_register_io_memory(musicpal_lcd_readfn,
+                                       musicpal_lcd_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype);
+
+    s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
+                                 NULL, NULL, s);
+    qemu_console_resize(s->ds, 128*3, 64*3);
+
+    qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_lcd_vmsd = {
+    .name = "musicpal_lcd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(brightness, musicpal_lcd_state),
+        VMSTATE_UINT32(mode, musicpal_lcd_state),
+        VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
+        VMSTATE_UINT32(page, musicpal_lcd_state),
+        VMSTATE_UINT32(page_off, musicpal_lcd_state),
+        VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo musicpal_lcd_info = {
+    .init = musicpal_lcd_init,
+    .qdev.name = "musicpal_lcd",
+    .qdev.size = sizeof(musicpal_lcd_state),
+    .qdev.vmsd = &musicpal_lcd_vmsd,
+};
+
+/* PIC register offsets */
+#define MP_PIC_STATUS           0x00
+#define MP_PIC_ENABLE_SET       0x08
+#define MP_PIC_ENABLE_CLR       0x0C
+
+typedef struct mv88w8618_pic_state
+{
+    SysBusDevice busdev;
+    uint32_t level;
+    uint32_t enabled;
+    qemu_irq parent_irq;
+} mv88w8618_pic_state;
+
+static void mv88w8618_pic_update(mv88w8618_pic_state *s)
+{
+    qemu_set_irq(s->parent_irq, (s->level & s->enabled));
+}
+
+static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    if (level) {
+        s->level |= 1 << irq;
+    } else {
+        s->level &= ~(1 << irq);
+    }
+    mv88w8618_pic_update(s);
+}
+
+static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    switch (offset) {
+    case MP_PIC_STATUS:
+        return s->level & s->enabled;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    mv88w8618_pic_state *s = opaque;
+
+    switch (offset) {
+    case MP_PIC_ENABLE_SET:
+        s->enabled |= value;
+        break;
+
+    case MP_PIC_ENABLE_CLR:
+        s->enabled &= ~value;
+        s->level &= ~value;
+        break;
+    }
+    mv88w8618_pic_update(s);
+}
+
+static void mv88w8618_pic_reset(DeviceState *d)
+{
+    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state,
+                                         sysbus_from_qdev(d));
+
+    s->level = 0;
+    s->enabled = 0;
+}
+
+static CPUReadMemoryFunc * const mv88w8618_pic_readfn[] = {
+    mv88w8618_pic_read,
+    mv88w8618_pic_read,
+    mv88w8618_pic_read
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_pic_writefn[] = {
+    mv88w8618_pic_write,
+    mv88w8618_pic_write,
+    mv88w8618_pic_write
+};
+
+static int mv88w8618_pic_init(SysBusDevice *dev)
+{
+    mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
+    int iomemtype;
+
+    qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn,
+                                       mv88w8618_pic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_pic_vmsd = {
+    .name = "mv88w8618_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, mv88w8618_pic_state),
+        VMSTATE_UINT32(enabled, mv88w8618_pic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo mv88w8618_pic_info = {
+    .init = mv88w8618_pic_init,
+    .qdev.name = "mv88w8618_pic",
+    .qdev.size = sizeof(mv88w8618_pic_state),
+    .qdev.reset = mv88w8618_pic_reset,
+    .qdev.vmsd = &mv88w8618_pic_vmsd,
+};
+
+/* PIT register offsets */
+#define MP_PIT_TIMER1_LENGTH    0x00
+/* ... */
+#define MP_PIT_TIMER4_LENGTH    0x0C
+#define MP_PIT_CONTROL          0x10
+#define MP_PIT_TIMER1_VALUE     0x14
+/* ... */
+#define MP_PIT_TIMER4_VALUE     0x20
+#define MP_BOARD_RESET          0x34
+
+/* Magic board reset value (probably some watchdog behind it) */
+#define MP_BOARD_RESET_MAGIC    0x10000
+
+typedef struct mv88w8618_timer_state {
+    ptimer_state *ptimer;
+    uint32_t limit;
+    int freq;
+    qemu_irq irq;
+} mv88w8618_timer_state;
+
+typedef struct mv88w8618_pit_state {
+    SysBusDevice busdev;
+    mv88w8618_timer_state timer[4];
+} mv88w8618_pit_state;
+
+static void mv88w8618_timer_tick(void *opaque)
+{
+    mv88w8618_timer_state *s = opaque;
+
+    qemu_irq_raise(s->irq);
+}
+
+static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
+                                 uint32_t freq)
+{
+    QEMUBH *bh;
+
+    sysbus_init_irq(dev, &s->irq);
+    s->freq = freq;
+
+    bh = qemu_bh_new(mv88w8618_timer_tick, s);
+    s->ptimer = ptimer_init(bh);
+}
+
+static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
+{
+    mv88w8618_pit_state *s = opaque;
+    mv88w8618_timer_state *t;
+
+    switch (offset) {
+    case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
+        t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
+        return ptimer_get_count(t->ptimer);
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    mv88w8618_pit_state *s = opaque;
+    mv88w8618_timer_state *t;
+    int i;
+
+    switch (offset) {
+    case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
+        t = &s->timer[offset >> 2];
+        t->limit = value;
+        if (t->limit > 0) {
+            ptimer_set_limit(t->ptimer, t->limit, 1);
+        } else {
+            ptimer_stop(t->ptimer);
+        }
+        break;
+
+    case MP_PIT_CONTROL:
+        for (i = 0; i < 4; i++) {
+            t = &s->timer[i];
+            if (value & 0xf && t->limit > 0) {
+                ptimer_set_limit(t->ptimer, t->limit, 0);
+                ptimer_set_freq(t->ptimer, t->freq);
+                ptimer_run(t->ptimer, 0);
+            } else {
+                ptimer_stop(t->ptimer);
+            }
+            value >>= 4;
+        }
+        break;
+
+    case MP_BOARD_RESET:
+        if (value == MP_BOARD_RESET_MAGIC) {
+            qemu_system_reset_request();
+        }
+        break;
+    }
+}
+
+static void mv88w8618_pit_reset(DeviceState *d)
+{
+    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state,
+                                         sysbus_from_qdev(d));
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        ptimer_stop(s->timer[i].ptimer);
+        s->timer[i].limit = 0;
+    }
+}
+
+static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = {
+    mv88w8618_pit_read,
+    mv88w8618_pit_read,
+    mv88w8618_pit_read
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_pit_writefn[] = {
+    mv88w8618_pit_write,
+    mv88w8618_pit_write,
+    mv88w8618_pit_write
+};
+
+static int mv88w8618_pit_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
+    int i;
+
+    /* Letting them all run at 1 MHz is likely just a pragmatic
+     * simplification. */
+    for (i = 0; i < 4; i++) {
+        mv88w8618_timer_init(dev, &s->timer[i], 1000000);
+    }
+
+    iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn,
+                                       mv88w8618_pit_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_timer_vmsd = {
+    .name = "timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
+        VMSTATE_UINT32(limit, mv88w8618_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription mv88w8618_pit_vmsd = {
+    .name = "mv88w8618_pit",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
+                             mv88w8618_timer_vmsd, mv88w8618_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo mv88w8618_pit_info = {
+    .init = mv88w8618_pit_init,
+    .qdev.name  = "mv88w8618_pit",
+    .qdev.size  = sizeof(mv88w8618_pit_state),
+    .qdev.reset = mv88w8618_pit_reset,
+    .qdev.vmsd  = &mv88w8618_pit_vmsd,
+};
+
+/* Flash config register offsets */
+#define MP_FLASHCFG_CFGR0    0x04
+
+typedef struct mv88w8618_flashcfg_state {
+    SysBusDevice busdev;
+    uint32_t cfgr0;
+} mv88w8618_flashcfg_state;
+
+static uint32_t mv88w8618_flashcfg_read(void *opaque,
+                                        target_phys_addr_t offset)
+{
+    mv88w8618_flashcfg_state *s = opaque;
+
+    switch (offset) {
+    case MP_FLASHCFG_CFGR0:
+        return s->cfgr0;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
+                                     uint32_t value)
+{
+    mv88w8618_flashcfg_state *s = opaque;
+
+    switch (offset) {
+    case MP_FLASHCFG_CFGR0:
+        s->cfgr0 = value;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const mv88w8618_flashcfg_readfn[] = {
+    mv88w8618_flashcfg_read,
+    mv88w8618_flashcfg_read,
+    mv88w8618_flashcfg_read
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_flashcfg_writefn[] = {
+    mv88w8618_flashcfg_write,
+    mv88w8618_flashcfg_write,
+    mv88w8618_flashcfg_write
+};
+
+static int mv88w8618_flashcfg_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev);
+
+    s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
+    iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn,
+                                       mv88w8618_flashcfg_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype);
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_flashcfg_vmsd = {
+    .name = "mv88w8618_flashcfg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo mv88w8618_flashcfg_info = {
+    .init = mv88w8618_flashcfg_init,
+    .qdev.name  = "mv88w8618_flashcfg",
+    .qdev.size  = sizeof(mv88w8618_flashcfg_state),
+    .qdev.vmsd  = &mv88w8618_flashcfg_vmsd,
+};
+
+/* Misc register offsets */
+#define MP_MISC_BOARD_REVISION  0x18
+
+#define MP_BOARD_REVISION       0x31
+
+static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
+{
+    switch (offset) {
+    case MP_MISC_BOARD_REVISION:
+        return MP_BOARD_REVISION;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_misc_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+}
+
+static CPUReadMemoryFunc * const musicpal_misc_readfn[] = {
+    musicpal_misc_read,
+    musicpal_misc_read,
+    musicpal_misc_read,
+};
+
+static CPUWriteMemoryFunc * const musicpal_misc_writefn[] = {
+    musicpal_misc_write,
+    musicpal_misc_write,
+    musicpal_misc_write,
+};
+
+static void musicpal_misc_init(void)
+{
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(musicpal_misc_readfn,
+                                       musicpal_misc_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype);
+}
+
+/* WLAN register offsets */
+#define MP_WLAN_MAGIC1          0x11c
+#define MP_WLAN_MAGIC2          0x124
+
+static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
+{
+    switch (offset) {
+    /* Workaround to allow loading the binary-only wlandrv.ko crap
+     * from the original Freecom firmware. */
+    case MP_WLAN_MAGIC1:
+        return ~3;
+    case MP_WLAN_MAGIC2:
+        return -1;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+}
+
+static CPUReadMemoryFunc * const mv88w8618_wlan_readfn[] = {
+    mv88w8618_wlan_read,
+    mv88w8618_wlan_read,
+    mv88w8618_wlan_read,
+};
+
+static CPUWriteMemoryFunc * const mv88w8618_wlan_writefn[] = {
+    mv88w8618_wlan_write,
+    mv88w8618_wlan_write,
+    mv88w8618_wlan_write,
+};
+
+static int mv88w8618_wlan_init(SysBusDevice *dev)
+{
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn,
+                                       mv88w8618_wlan_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype);
+    return 0;
+}
+
+/* GPIO register offsets */
+#define MP_GPIO_OE_LO           0x008
+#define MP_GPIO_OUT_LO          0x00c
+#define MP_GPIO_IN_LO           0x010
+#define MP_GPIO_IER_LO          0x014
+#define MP_GPIO_IMR_LO          0x018
+#define MP_GPIO_ISR_LO          0x020
+#define MP_GPIO_OE_HI           0x508
+#define MP_GPIO_OUT_HI          0x50c
+#define MP_GPIO_IN_HI           0x510
+#define MP_GPIO_IER_HI          0x514
+#define MP_GPIO_IMR_HI          0x518
+#define MP_GPIO_ISR_HI          0x520
+
+/* GPIO bits & masks */
+#define MP_GPIO_LCD_BRIGHTNESS  0x00070000
+#define MP_GPIO_I2C_DATA_BIT    29
+#define MP_GPIO_I2C_CLOCK_BIT   30
+
+/* LCD brightness bits in GPIO_OE_HI */
+#define MP_OE_LCD_BRIGHTNESS    0x0007
+
+typedef struct musicpal_gpio_state {
+    SysBusDevice busdev;
+    uint32_t lcd_brightness;
+    uint32_t out_state;
+    uint32_t in_state;
+    uint32_t ier;
+    uint32_t imr;
+    uint32_t isr;
+    qemu_irq irq;
+    qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
+} musicpal_gpio_state;
+
+static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
+    int i;
+    uint32_t brightness;
+
+    /* compute brightness ratio */
+    switch (s->lcd_brightness) {
+    case 0x00000007:
+        brightness = 0;
+        break;
+
+    case 0x00020000:
+        brightness = 1;
+        break;
+
+    case 0x00020001:
+        brightness = 2;
+        break;
+
+    case 0x00040000:
+        brightness = 3;
+        break;
+
+    case 0x00010006:
+        brightness = 4;
+        break;
+
+    case 0x00020005:
+        brightness = 5;
+        break;
+
+    case 0x00040003:
+        brightness = 6;
+        break;
+
+    case 0x00030004:
+    default:
+        brightness = 7;
+    }
+
+    /* set lcd brightness GPIOs  */
+    for (i = 0; i <= 2; i++) {
+        qemu_set_irq(s->out[i], (brightness >> i) & 1);
+    }
+}
+
+static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
+{
+    musicpal_gpio_state *s = opaque;
+    uint32_t mask = 1 << pin;
+    uint32_t delta = level << pin;
+    uint32_t old = s->in_state & mask;
+
+    s->in_state &= ~mask;
+    s->in_state |= delta;
+
+    if ((old ^ delta) &&
+        ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
+        s->isr = mask;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    musicpal_gpio_state *s = opaque;
+
+    switch (offset) {
+    case MP_GPIO_OE_HI: /* used for LCD brightness control */
+        return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
+
+    case MP_GPIO_OUT_LO:
+        return s->out_state & 0xFFFF;
+    case MP_GPIO_OUT_HI:
+        return s->out_state >> 16;
+
+    case MP_GPIO_IN_LO:
+        return s->in_state & 0xFFFF;
+    case MP_GPIO_IN_HI:
+        return s->in_state >> 16;
+
+    case MP_GPIO_IER_LO:
+        return s->ier & 0xFFFF;
+    case MP_GPIO_IER_HI:
+        return s->ier >> 16;
+
+    case MP_GPIO_IMR_LO:
+        return s->imr & 0xFFFF;
+    case MP_GPIO_IMR_HI:
+        return s->imr >> 16;
+
+    case MP_GPIO_ISR_LO:
+        return s->isr & 0xFFFF;
+    case MP_GPIO_ISR_HI:
+        return s->isr >> 16;
+
+    default:
+        return 0;
+    }
+}
+
+static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    musicpal_gpio_state *s = opaque;
+    switch (offset) {
+    case MP_GPIO_OE_HI: /* used for LCD brightness control */
+        s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
+                         (value & MP_OE_LCD_BRIGHTNESS);
+        musicpal_gpio_brightness_update(s);
+        break;
+
+    case MP_GPIO_OUT_LO:
+        s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_OUT_HI:
+        s->out_state = (s->out_state & 0xFFFF) | (value << 16);
+        s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
+                            (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
+        musicpal_gpio_brightness_update(s);
+        qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
+        qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
+        break;
+
+    case MP_GPIO_IER_LO:
+        s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_IER_HI:
+        s->ier = (s->ier & 0xFFFF) | (value << 16);
+        break;
+
+    case MP_GPIO_IMR_LO:
+        s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
+        break;
+    case MP_GPIO_IMR_HI:
+        s->imr = (s->imr & 0xFFFF) | (value << 16);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const musicpal_gpio_readfn[] = {
+    musicpal_gpio_read,
+    musicpal_gpio_read,
+    musicpal_gpio_read,
+};
+
+static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = {
+    musicpal_gpio_write,
+    musicpal_gpio_write,
+    musicpal_gpio_write,
+};
+
+static void musicpal_gpio_reset(DeviceState *d)
+{
+    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state,
+                                         sysbus_from_qdev(d));
+
+    s->lcd_brightness = 0;
+    s->out_state = 0;
+    s->in_state = 0xffffffff;
+    s->ier = 0;
+    s->imr = 0;
+    s->isr = 0;
+}
+
+static int musicpal_gpio_init(SysBusDevice *dev)
+{
+    musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    iomemtype = cpu_register_io_memory(musicpal_gpio_readfn,
+                                       musicpal_gpio_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype);
+
+    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
+
+    qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_gpio_vmsd = {
+    .name = "musicpal_gpio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
+        VMSTATE_UINT32(out_state, musicpal_gpio_state),
+        VMSTATE_UINT32(in_state, musicpal_gpio_state),
+        VMSTATE_UINT32(ier, musicpal_gpio_state),
+        VMSTATE_UINT32(imr, musicpal_gpio_state),
+        VMSTATE_UINT32(isr, musicpal_gpio_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo musicpal_gpio_info = {
+    .init = musicpal_gpio_init,
+    .qdev.name  = "musicpal_gpio",
+    .qdev.size  = sizeof(musicpal_gpio_state),
+    .qdev.reset = musicpal_gpio_reset,
+    .qdev.vmsd  = &musicpal_gpio_vmsd,
+};
+
+/* Keyboard codes & masks */
+#define KEY_RELEASED            0x80
+#define KEY_CODE                0x7f
+
+#define KEYCODE_TAB             0x0f
+#define KEYCODE_ENTER           0x1c
+#define KEYCODE_F               0x21
+#define KEYCODE_M               0x32
+
+#define KEYCODE_EXTENDED        0xe0
+#define KEYCODE_UP              0x48
+#define KEYCODE_DOWN            0x50
+#define KEYCODE_LEFT            0x4b
+#define KEYCODE_RIGHT           0x4d
+
+#define MP_KEY_WHEEL_VOL       (1 << 0)
+#define MP_KEY_WHEEL_VOL_INV   (1 << 1)
+#define MP_KEY_WHEEL_NAV       (1 << 2)
+#define MP_KEY_WHEEL_NAV_INV   (1 << 3)
+#define MP_KEY_BTN_FAVORITS    (1 << 4)
+#define MP_KEY_BTN_MENU        (1 << 5)
+#define MP_KEY_BTN_VOLUME      (1 << 6)
+#define MP_KEY_BTN_NAVIGATION  (1 << 7)
+
+typedef struct musicpal_key_state {
+    SysBusDevice busdev;
+    uint32_t kbd_extended;
+    uint32_t pressed_keys;
+    qemu_irq out[8];
+} musicpal_key_state;
+
+static void musicpal_key_event(void *opaque, int keycode)
+{
+    musicpal_key_state *s = opaque;
+    uint32_t event = 0;
+    int i;
+
+    if (keycode == KEYCODE_EXTENDED) {
+        s->kbd_extended = 1;
+        return;
+    }
+
+    if (s->kbd_extended) {
+        switch (keycode & KEY_CODE) {
+        case KEYCODE_UP:
+            event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
+            break;
+
+        case KEYCODE_DOWN:
+            event = MP_KEY_WHEEL_NAV;
+            break;
+
+        case KEYCODE_LEFT:
+            event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
+            break;
+
+        case KEYCODE_RIGHT:
+            event = MP_KEY_WHEEL_VOL;
+            break;
+        }
+    } else {
+        switch (keycode & KEY_CODE) {
+        case KEYCODE_F:
+            event = MP_KEY_BTN_FAVORITS;
+            break;
+
+        case KEYCODE_TAB:
+            event = MP_KEY_BTN_VOLUME;
+            break;
+
+        case KEYCODE_ENTER:
+            event = MP_KEY_BTN_NAVIGATION;
+            break;
+
+        case KEYCODE_M:
+            event = MP_KEY_BTN_MENU;
+            break;
+        }
+        /* Do not repeat already pressed buttons */
+        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
+            event = 0;
+        }
+    }
+
+    if (event) {
+        /* Raise GPIO pin first if repeating a key */
+        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
+            for (i = 0; i <= 7; i++) {
+                if (event & (1 << i)) {
+                    qemu_set_irq(s->out[i], 1);
+                }
+            }
+        }
+        for (i = 0; i <= 7; i++) {
+            if (event & (1 << i)) {
+                qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
+            }
+        }
+        if (keycode & KEY_RELEASED) {
+            s->pressed_keys &= ~event;
+        } else {
+            s->pressed_keys |= event;
+        }
+    }
+
+    s->kbd_extended = 0;
+}
+
+static int musicpal_key_init(SysBusDevice *dev)
+{
+    musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev);
+
+    sysbus_init_mmio(dev, 0x0, 0);
+
+    s->kbd_extended = 0;
+    s->pressed_keys = 0;
+
+    qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
+
+    qemu_add_kbd_event_handler(musicpal_key_event, s);
+
+    return 0;
+}
+
+static const VMStateDescription musicpal_key_vmsd = {
+    .name = "musicpal_key",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(kbd_extended, musicpal_key_state),
+        VMSTATE_UINT32(pressed_keys, musicpal_key_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo musicpal_key_info = {
+    .init = musicpal_key_init,
+    .qdev.name  = "musicpal_key",
+    .qdev.size  = sizeof(musicpal_key_state),
+    .qdev.vmsd  = &musicpal_key_vmsd,
+};
+
+static struct arm_boot_info musicpal_binfo = {
+    .loader_start = 0x0,
+    .board_id = 0x20e,
+};
+
+static void musicpal_init(ram_addr_t ram_size,
+               const char *boot_device,
+               const char *kernel_filename, const char *kernel_cmdline,
+               const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    qemu_irq *cpu_pic;
+    qemu_irq pic[32];
+    DeviceState *dev;
+    DeviceState *i2c_dev;
+    DeviceState *lcd_dev;
+    DeviceState *key_dev;
+    DeviceState *wm8750_dev;
+    SysBusDevice *s;
+    i2c_bus *i2c;
+    int i;
+    unsigned long flash_size;
+    DriveInfo *dinfo;
+    ram_addr_t sram_off;
+
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    cpu_pic = arm_pic_init_cpu(env);
+
+    /* For now we use a fixed - the original - RAM size */
+    cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,
+                                 qemu_ram_alloc(NULL, "musicpal.ram",
+                                                MP_RAM_DEFAULT_SIZE));
+
+    sram_off = qemu_ram_alloc(NULL, "musicpal.sram", MP_SRAM_SIZE);
+    cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);
+
+    dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
+                               cpu_pic[ARM_PIC_CPU_IRQ]);
+    for (i = 0; i < 32; i++) {
+        pic[i] = qdev_get_gpio_in(dev, i);
+    }
+    sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ],
+                          pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
+                          pic[MP_TIMER4_IRQ], NULL);
+
+    if (serial_hds[0]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
+                       serial_hds[0], 1, 1);
+#else
+        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
+                       serial_hds[0], 1, 0);
+#endif
+    }
+    if (serial_hds[1]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
+                       serial_hds[1], 1, 1);
+#else
+        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
+                       serial_hds[1], 1, 0);
+#endif
+    }
+
+    /* Register flash */
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        flash_size = bdrv_getlength(dinfo->bdrv);
+        if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
+            flash_size != 32*1024*1024) {
+            fprintf(stderr, "Invalid flash image size\n");
+            exit(1);
+        }
+
+        /*
+         * The original U-Boot accesses the flash at 0xFE000000 instead of
+         * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
+         * image is smaller than 32 MB.
+         */
+#ifdef TARGET_WORDS_BIGENDIAN
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
+                              "musicpal.flash", flash_size),
+                              dinfo->bdrv, 0x10000,
+                              (flash_size + 0xffff) >> 16,
+                              MP_FLASH_SIZE_MAX / flash_size,
+                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
+                              0x5555, 0x2AAA, 1);
+#else
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
+                              "musicpal.flash", flash_size),
+                              dinfo->bdrv, 0x10000,
+                              (flash_size + 0xffff) >> 16,
+                              MP_FLASH_SIZE_MAX / flash_size,
+                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
+                              0x5555, 0x2AAA, 0);
+#endif
+
+    }
+    sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL);
+
+    qemu_check_nic_model(&nd_table[0], "mv88w8618");
+    dev = qdev_create(NULL, "mv88w8618_eth");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, MP_ETH_BASE);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[MP_ETH_IRQ]);
+
+    sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
+
+    musicpal_misc_init();
+
+    dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
+    i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
+
+    lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL);
+    key_dev = sysbus_create_simple("musicpal_key", -1, NULL);
+
+    /* I2C read data */
+    qdev_connect_gpio_out(i2c_dev, 0,
+                          qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
+    /* I2C data */
+    qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
+    /* I2C clock */
+    qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
+
+    for (i = 0; i < 3; i++) {
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
+    }
+    for (i = 0; i < 4; i++) {
+        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
+    }
+    for (i = 4; i < 8; i++) {
+        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
+    }
+
+    wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
+    dev = qdev_create(NULL, "mv88w8618_audio");
+    s = sysbus_from_qdev(dev);
+    qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
+    sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
+
+    musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
+    musicpal_binfo.kernel_filename = kernel_filename;
+    musicpal_binfo.kernel_cmdline = kernel_cmdline;
+    musicpal_binfo.initrd_filename = initrd_filename;
+    arm_load_kernel(env, &musicpal_binfo);
+}
+
+static QEMUMachine musicpal_machine = {
+    .name = "musicpal",
+    .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
+    .init = musicpal_init,
+};
+
+static void musicpal_machine_init(void)
+{
+    qemu_register_machine(&musicpal_machine);
+}
+
+machine_init(musicpal_machine_init);
+
+static void musicpal_register_devices(void)
+{
+    sysbus_register_withprop(&mv88w8618_pic_info);
+    sysbus_register_withprop(&mv88w8618_pit_info);
+    sysbus_register_withprop(&mv88w8618_flashcfg_info);
+    sysbus_register_withprop(&mv88w8618_eth_info);
+    sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice),
+                        mv88w8618_wlan_init);
+    sysbus_register_withprop(&musicpal_lcd_info);
+    sysbus_register_withprop(&musicpal_gpio_info);
+    sysbus_register_withprop(&musicpal_key_info);
+}
+
+device_init(musicpal_register_devices)
diff --git a/qemu-0.15.x/hw/nand.c b/qemu-0.15.x/hw/nand.c
new file mode 100644
index 0000000..37e51d7
--- /dev/null
+++ b/qemu-0.15.x/hw/nand.c
@@ -0,0 +1,666 @@
+/*
+ * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
+ * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
+ * Samsung Electronic.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#ifndef NAND_IO
+
+# include "hw.h"
+# include "flash.h"
+# include "blockdev.h"
+/* FIXME: Pass block device as an argument.  */
+
+# define NAND_CMD_READ0		0x00
+# define NAND_CMD_READ1		0x01
+# define NAND_CMD_READ2		0x50
+# define NAND_CMD_LPREAD2	0x30
+# define NAND_CMD_NOSERIALREAD2	0x35
+# define NAND_CMD_RANDOMREAD1	0x05
+# define NAND_CMD_RANDOMREAD2	0xe0
+# define NAND_CMD_READID	0x90
+# define NAND_CMD_RESET		0xff
+# define NAND_CMD_PAGEPROGRAM1	0x80
+# define NAND_CMD_PAGEPROGRAM2	0x10
+# define NAND_CMD_CACHEPROGRAM2	0x15
+# define NAND_CMD_BLOCKERASE1	0x60
+# define NAND_CMD_BLOCKERASE2	0xd0
+# define NAND_CMD_READSTATUS	0x70
+# define NAND_CMD_COPYBACKPRG1	0x85
+
+# define NAND_IOSTATUS_ERROR	(1 << 0)
+# define NAND_IOSTATUS_PLANE0	(1 << 1)
+# define NAND_IOSTATUS_PLANE1	(1 << 2)
+# define NAND_IOSTATUS_PLANE2	(1 << 3)
+# define NAND_IOSTATUS_PLANE3	(1 << 4)
+# define NAND_IOSTATUS_BUSY	(1 << 6)
+# define NAND_IOSTATUS_UNPROTCT	(1 << 7)
+
+# define MAX_PAGE		0x800
+# define MAX_OOB		0x40
+
+struct NANDFlashState {
+    uint8_t manf_id, chip_id;
+    int size, pages;
+    int page_shift, oob_shift, erase_shift, addr_shift;
+    uint8_t *storage;
+    BlockDriverState *bdrv;
+    int mem_oob;
+
+    uint8_t cle, ale, ce, wp, gnd;
+
+    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
+    uint8_t *ioaddr;
+    int iolen;
+
+    uint32_t cmd, addr;
+    int addrlen;
+    int status;
+    int offset;
+
+    void (*blk_write)(NANDFlashState *s);
+    void (*blk_erase)(NANDFlashState *s);
+    void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+
+    uint32_t ioaddr_vmstate;
+};
+
+# define NAND_NO_AUTOINCR	0x00000001
+# define NAND_BUSWIDTH_16	0x00000002
+# define NAND_NO_PADDING	0x00000004
+# define NAND_CACHEPRG		0x00000008
+# define NAND_COPYBACK		0x00000010
+# define NAND_IS_AND		0x00000020
+# define NAND_4PAGE_ARRAY	0x00000040
+# define NAND_NO_READRDY	0x00000100
+# define NAND_SAMSUNG_LP	(NAND_NO_PADDING | NAND_COPYBACK)
+
+# define NAND_IO
+
+# define PAGE(addr)		((addr) >> ADDR_SHIFT)
+# define PAGE_START(page)	(PAGE(page) * (PAGE_SIZE + OOB_SIZE))
+# define PAGE_MASK		((1 << ADDR_SHIFT) - 1)
+# define OOB_SHIFT		(PAGE_SHIFT - 5)
+# define OOB_SIZE		(1 << OOB_SHIFT)
+# define SECTOR(addr)		((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
+# define SECTOR_OFFSET(addr)	((addr) & ((511 >> PAGE_SHIFT) << 8))
+
+# define PAGE_SIZE		256
+# define PAGE_SHIFT		8
+# define PAGE_SECTORS		1
+# define ADDR_SHIFT		8
+# include "nand.c"
+# define PAGE_SIZE		512
+# define PAGE_SHIFT		9
+# define PAGE_SECTORS		1
+# define ADDR_SHIFT		8
+# include "nand.c"
+# define PAGE_SIZE		2048
+# define PAGE_SHIFT		11
+# define PAGE_SECTORS		4
+# define ADDR_SHIFT		16
+# include "nand.c"
+
+/* Information based on Linux drivers/mtd/nand/nand_ids.c */
+static const struct {
+    int size;
+    int width;
+    int page_shift;
+    int erase_shift;
+    uint32_t options;
+} nand_flash_ids[0x100] = {
+    [0 ... 0xff] = { 0 },
+
+    [0x6e] = { 1,	8,	8, 4, 0 },
+    [0x64] = { 2,	8,	8, 4, 0 },
+    [0x6b] = { 4,	8,	9, 4, 0 },
+    [0xe8] = { 1,	8,	8, 4, 0 },
+    [0xec] = { 1,	8,	8, 4, 0 },
+    [0xea] = { 2,	8,	8, 4, 0 },
+    [0xd5] = { 4,	8,	9, 4, 0 },
+    [0xe3] = { 4,	8,	9, 4, 0 },
+    [0xe5] = { 4,	8,	9, 4, 0 },
+    [0xd6] = { 8,	8,	9, 4, 0 },
+
+    [0x39] = { 8,	8,	9, 4, 0 },
+    [0xe6] = { 8,	8,	9, 4, 0 },
+    [0x49] = { 8,	16,	9, 4, NAND_BUSWIDTH_16 },
+    [0x59] = { 8,	16,	9, 4, NAND_BUSWIDTH_16 },
+
+    [0x33] = { 16,	8,	9, 5, 0 },
+    [0x73] = { 16,	8,	9, 5, 0 },
+    [0x43] = { 16,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x53] = { 16,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x35] = { 32,	8,	9, 5, 0 },
+    [0x75] = { 32,	8,	9, 5, 0 },
+    [0x45] = { 32,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x55] = { 32,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x36] = { 64,	8,	9, 5, 0 },
+    [0x76] = { 64,	8,	9, 5, 0 },
+    [0x46] = { 64,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x56] = { 64,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x78] = { 128,	8,	9, 5, 0 },
+    [0x39] = { 128,	8,	9, 5, 0 },
+    [0x79] = { 128,	8,	9, 5, 0 },
+    [0x72] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x49] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x74] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x59] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x71] = { 256,	8,	9, 5, 0 },
+
+    /*
+     * These are the new chips with large page size. The pagesize and the
+     * erasesize is determined from the extended id bytes
+     */
+# define LP_OPTIONS	(NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+# define LP_OPTIONS16	(LP_OPTIONS | NAND_BUSWIDTH_16)
+
+    /* 512 Megabit */
+    [0xa2] = { 64,	8,	0, 0, LP_OPTIONS },
+    [0xf2] = { 64,	8,	0, 0, LP_OPTIONS },
+    [0xb2] = { 64,	16,	0, 0, LP_OPTIONS16 },
+    [0xc2] = { 64,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 1 Gigabit */
+    [0xa1] = { 128,	8,	0, 0, LP_OPTIONS },
+    [0xf1] = { 128,	8,	0, 0, LP_OPTIONS },
+    [0xb1] = { 128,	16,	0, 0, LP_OPTIONS16 },
+    [0xc1] = { 128,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 2 Gigabit */
+    [0xaa] = { 256,	8,	0, 0, LP_OPTIONS },
+    [0xda] = { 256,	8,	0, 0, LP_OPTIONS },
+    [0xba] = { 256,	16,	0, 0, LP_OPTIONS16 },
+    [0xca] = { 256,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 4 Gigabit */
+    [0xac] = { 512,	8,	0, 0, LP_OPTIONS },
+    [0xdc] = { 512,	8,	0, 0, LP_OPTIONS },
+    [0xbc] = { 512,	16,	0, 0, LP_OPTIONS16 },
+    [0xcc] = { 512,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 8 Gigabit */
+    [0xa3] = { 1024,	8,	0, 0, LP_OPTIONS },
+    [0xd3] = { 1024,	8,	0, 0, LP_OPTIONS },
+    [0xb3] = { 1024,	16,	0, 0, LP_OPTIONS16 },
+    [0xc3] = { 1024,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 16 Gigabit */
+    [0xa5] = { 2048,	8,	0, 0, LP_OPTIONS },
+    [0xd5] = { 2048,	8,	0, 0, LP_OPTIONS },
+    [0xb5] = { 2048,	16,	0, 0, LP_OPTIONS16 },
+    [0xc5] = { 2048,	16,	0, 0, LP_OPTIONS16 },
+};
+
+static void nand_reset(NANDFlashState *s)
+{
+    s->cmd = NAND_CMD_READ0;
+    s->addr = 0;
+    s->addrlen = 0;
+    s->iolen = 0;
+    s->offset = 0;
+    s->status &= NAND_IOSTATUS_UNPROTCT;
+}
+
+static void nand_command(NANDFlashState *s)
+{
+    unsigned int offset;
+    switch (s->cmd) {
+    case NAND_CMD_READ0:
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_READID:
+        s->io[0] = s->manf_id;
+        s->io[1] = s->chip_id;
+        s->io[2] = 'Q';		/* Don't-care byte (often 0xa5) */
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+            s->io[3] = 0x15;	/* Page Size, Block Size, Spare Size.. */
+        else
+            s->io[3] = 0xc0;	/* Multi-plane */
+        s->ioaddr = s->io;
+        s->iolen = 4;
+        break;
+
+    case NAND_CMD_RANDOMREAD2:
+    case NAND_CMD_NOSERIALREAD2:
+        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
+            break;
+        offset = s->addr & ((1 << s->addr_shift) - 1);
+        s->blk_load(s, s->addr, offset);
+        if (s->gnd)
+            s->iolen = (1 << s->page_shift) - offset;
+        else
+            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+        break;
+
+    case NAND_CMD_RESET:
+        nand_reset(s);
+        break;
+
+    case NAND_CMD_PAGEPROGRAM1:
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_PAGEPROGRAM2:
+        if (s->wp) {
+            s->blk_write(s);
+        }
+        break;
+
+    case NAND_CMD_BLOCKERASE1:
+        break;
+
+    case NAND_CMD_BLOCKERASE2:
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+            s->addr <<= 16;
+        else
+            s->addr <<= 8;
+
+        if (s->wp) {
+            s->blk_erase(s);
+        }
+        break;
+
+    case NAND_CMD_READSTATUS:
+        s->io[0] = s->status;
+        s->ioaddr = s->io;
+        s->iolen = 1;
+        break;
+
+    default:
+        printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
+    }
+}
+
+static void nand_pre_save(void *opaque)
+{
+    NANDFlashState *s = opaque;
+
+    s->ioaddr_vmstate = s->ioaddr - s->io;
+}
+
+static int nand_post_load(void *opaque, int version_id)
+{
+    NANDFlashState *s = opaque;
+
+    if (s->ioaddr_vmstate > sizeof(s->io)) {
+        return -EINVAL;
+    }
+    s->ioaddr = s->io + s->ioaddr_vmstate;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_nand = {
+    .name = "nand",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = nand_pre_save,
+    .post_load = nand_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(cle, NANDFlashState),
+        VMSTATE_UINT8(ale, NANDFlashState),
+        VMSTATE_UINT8(ce, NANDFlashState),
+        VMSTATE_UINT8(wp, NANDFlashState),
+        VMSTATE_UINT8(gnd, NANDFlashState),
+        VMSTATE_BUFFER(io, NANDFlashState),
+        VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
+        VMSTATE_INT32(iolen, NANDFlashState),
+        VMSTATE_UINT32(cmd, NANDFlashState),
+        VMSTATE_UINT32(addr, NANDFlashState),
+        VMSTATE_INT32(addrlen, NANDFlashState),
+        VMSTATE_INT32(status, NANDFlashState),
+        VMSTATE_INT32(offset, NANDFlashState),
+        /* XXX: do we want to save s->storage too? */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
+ * outputs are R/B and eight I/O pins.
+ *
+ * CE, WP and R/B are active low.
+ */
+void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd)
+{
+    s->cle = cle;
+    s->ale = ale;
+    s->ce = ce;
+    s->wp = wp;
+    s->gnd = gnd;
+    if (wp)
+        s->status |= NAND_IOSTATUS_UNPROTCT;
+    else
+        s->status &= ~NAND_IOSTATUS_UNPROTCT;
+}
+
+void nand_getpins(NANDFlashState *s, int *rb)
+{
+    *rb = 1;
+}
+
+void nand_setio(NANDFlashState *s, uint8_t value)
+{
+    if (!s->ce && s->cle) {
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
+                return;
+            if (value == NAND_CMD_RANDOMREAD1) {
+                s->addr &= ~((1 << s->addr_shift) - 1);
+                s->addrlen = 0;
+                return;
+            }
+        }
+        if (value == NAND_CMD_READ0)
+            s->offset = 0;
+	else if (value == NAND_CMD_READ1) {
+            s->offset = 0x100;
+            value = NAND_CMD_READ0;
+        }
+	else if (value == NAND_CMD_READ2) {
+            s->offset = 1 << s->page_shift;
+            value = NAND_CMD_READ0;
+        }
+
+        s->cmd = value;
+
+        if (s->cmd == NAND_CMD_READSTATUS ||
+                s->cmd == NAND_CMD_PAGEPROGRAM2 ||
+                s->cmd == NAND_CMD_BLOCKERASE1 ||
+                s->cmd == NAND_CMD_BLOCKERASE2 ||
+                s->cmd == NAND_CMD_NOSERIALREAD2 ||
+                s->cmd == NAND_CMD_RANDOMREAD2 ||
+                s->cmd == NAND_CMD_RESET)
+            nand_command(s);
+
+        if (s->cmd != NAND_CMD_RANDOMREAD2) {
+            s->addrlen = 0;
+        }
+    }
+
+    if (s->ale) {
+        unsigned int shift = s->addrlen * 8;
+        unsigned int mask = ~(0xff << shift);
+        unsigned int v = value << shift;
+
+        s->addr = (s->addr & mask) | v;
+        s->addrlen ++;
+
+        if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
+            nand_command(s);
+
+        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                s->addrlen == 3 && (
+                    s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1))
+            nand_command(s);
+        if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+               s->addrlen == 4 && (
+                    s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1))
+            nand_command(s);
+    }
+
+    if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
+        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
+            s->io[s->iolen ++] = value;
+    } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
+        if ((s->addr & ((1 << s->addr_shift) - 1)) <
+                (1 << s->page_shift) + (1 << s->oob_shift)) {
+            s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
+            s->addr ++;
+        }
+    }
+}
+
+uint8_t nand_getio(NANDFlashState *s)
+{
+    int offset;
+
+    /* Allow sequential reading */
+    if (!s->iolen && s->cmd == NAND_CMD_READ0) {
+        offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        s->offset = 0;
+
+        s->blk_load(s, s->addr, offset);
+        if (s->gnd)
+            s->iolen = (1 << s->page_shift) - offset;
+        else
+            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+    }
+
+    if (s->ce || s->iolen <= 0)
+        return 0;
+
+    s->iolen --;
+    s->addr++;
+    return *(s->ioaddr ++);
+}
+
+NANDFlashState *nand_init(int manf_id, int chip_id)
+{
+    int pagesize;
+    NANDFlashState *s;
+    DriveInfo *dinfo;
+
+    if (nand_flash_ids[chip_id].size == 0) {
+        hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
+    }
+
+    s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
+    dinfo = drive_get(IF_MTD, 0, 0);
+    if (dinfo)
+        s->bdrv = dinfo->bdrv;
+    s->manf_id = manf_id;
+    s->chip_id = chip_id;
+    s->size = nand_flash_ids[s->chip_id].size << 20;
+    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+        s->page_shift = 11;
+        s->erase_shift = 6;
+    } else {
+        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    }
+
+    switch (1 << s->page_shift) {
+    case 256:
+        nand_init_256(s);
+        break;
+    case 512:
+        nand_init_512(s);
+        break;
+    case 2048:
+        nand_init_2048(s);
+        break;
+    default:
+        hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
+    }
+
+    pagesize = 1 << s->oob_shift;
+    s->mem_oob = 1;
+    if (s->bdrv && bdrv_getlength(s->bdrv) >=
+                    (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+        pagesize = 0;
+        s->mem_oob = 0;
+    }
+
+    if (!s->bdrv)
+        pagesize += 1 << s->page_shift;
+    if (pagesize)
+        s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
+                        0xff, s->pages * pagesize);
+    /* Give s->ioaddr a sane value in case we save state before it
+       is used.  */
+    s->ioaddr = s->io;
+
+    vmstate_register(NULL, -1, &vmstate_nand, s);
+
+    return s;
+}
+
+void nand_done(NANDFlashState *s)
+{
+    if (s->bdrv) {
+        bdrv_close(s->bdrv);
+        bdrv_delete(s->bdrv);
+    }
+
+    if (!s->bdrv || s->mem_oob)
+        qemu_free(s->storage);
+
+    qemu_free(s);
+}
+
+#else
+
+/* Program a single page */
+static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
+{
+    uint32_t off, page, sector, soff;
+    uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
+    if (PAGE(s->addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+                        s->offset, s->io, s->iolen);
+    } else if (s->mem_oob) {
+        sector = SECTOR(s->addr);
+        off = (s->addr & PAGE_MASK) + s->offset;
+        soff = SECTOR_OFFSET(s->addr);
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
+            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            return;
+        }
+
+        memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+        if (off + s->iolen > PAGE_SIZE) {
+            page = PAGE(s->addr);
+            memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+                            MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
+        }
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+    } else {
+        off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
+        sector = off >> 9;
+        soff = off & 0x1ff;
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
+            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            return;
+        }
+
+        memcpy(iobuf + soff, s->io, s->iolen);
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+    }
+    s->offset = 0;
+}
+
+/* Erase a single block */
+static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
+{
+    uint32_t i, page, addr;
+    uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
+    addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
+
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        memset(s->storage + PAGE_START(addr),
+                        0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
+    } else if (s->mem_oob) {
+        memset(s->storage + (PAGE(addr) << OOB_SHIFT),
+                        0xff, OOB_SIZE << s->erase_shift);
+        i = SECTOR(addr);
+        page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
+        for (; i < page; i ++)
+            if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
+                printf("%s: write error in sector %i\n", __FUNCTION__, i);
+    } else {
+        addr = PAGE_START(addr);
+        page = addr >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+        memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+
+        memset(iobuf, 0xff, 0x200);
+        i = (addr & ~0x1ff) + 0x200;
+        for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
+                        i < addr; i += 0x200)
+            if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
+                printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+
+        page = i >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+        memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+    }
+}
+
+static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
+                uint32_t addr, int offset)
+{
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (s->bdrv) {
+        if (s->mem_oob) {
+            if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
+                printf("%s: read error in sector %i\n",
+                                __FUNCTION__, SECTOR(addr));
+            memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
+                            s->storage + (PAGE(s->addr) << OOB_SHIFT),
+                            OOB_SIZE);
+            s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
+        } else {
+            if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
+                                    s->io, (PAGE_SECTORS + 2)) == -1)
+                printf("%s: read error in sector %i\n",
+                                __FUNCTION__, PAGE_START(addr) >> 9);
+            s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
+        }
+    } else {
+        memcpy(s->io, s->storage + PAGE_START(s->addr) +
+                        offset, PAGE_SIZE + OOB_SIZE - offset);
+        s->ioaddr = s->io;
+    }
+}
+
+static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
+{
+    s->oob_shift = PAGE_SHIFT - 5;
+    s->pages = s->size >> PAGE_SHIFT;
+    s->addr_shift = ADDR_SHIFT;
+
+    s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
+    s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
+    s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
+}
+
+# undef PAGE_SIZE
+# undef PAGE_SHIFT
+# undef PAGE_SECTORS
+# undef ADDR_SHIFT
+#endif	/* NAND_IO */
diff --git a/qemu-0.15.x/hw/ne2000-isa.c b/qemu-0.15.x/hw/ne2000-isa.c
new file mode 100644
index 0000000..e41dbba
--- /dev/null
+++ b/qemu-0.15.x/hw/ne2000-isa.c
@@ -0,0 +1,112 @@
+/*
+ * QEMU NE2000 emulation -- isa bus windup
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "qdev.h"
+#include "net.h"
+#include "ne2000.h"
+
+typedef struct ISANE2000State {
+    ISADevice dev;
+    uint32_t iobase;
+    uint32_t isairq;
+    NE2000State ne2000;
+} ISANE2000State;
+
+static void isa_ne2000_cleanup(VLANClientState *nc)
+{
+    NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_ne2000_isa_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = ne2000_can_receive,
+    .receive = ne2000_receive,
+    .cleanup = isa_ne2000_cleanup,
+};
+
+static const VMStateDescription vmstate_isa_ne2000 = {
+    .name = "ne2000",
+    .version_id = 2,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(ne2000, ISANE2000State, 0, vmstate_ne2000, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int isa_ne2000_initfn(ISADevice *dev)
+{
+    ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev);
+    NE2000State *s = &isa->ne2000;
+
+    register_ioport_write(isa->iobase, 16, 1, ne2000_ioport_write, s);
+    register_ioport_read(isa->iobase, 16, 1, ne2000_ioport_read, s);
+    isa_init_ioport_range(dev, isa->iobase, 16);
+
+    register_ioport_write(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_write, s);
+    register_ioport_read(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_read, s);
+    register_ioport_write(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_write, s);
+    register_ioport_read(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_read, s);
+    isa_init_ioport_range(dev, isa->iobase + 0x10, 2);
+
+    register_ioport_write(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
+    register_ioport_read(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+    isa_init_ioport(dev, isa->iobase + 0x1f);
+
+    isa_init_irq(dev, &s->irq, isa->isairq);
+
+    qemu_macaddr_default_if_unset(&s->c.macaddr);
+    ne2000_reset(s);
+
+    s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
+
+    return 0;
+}
+
+static ISADeviceInfo ne2000_isa_info = {
+    .qdev.name  = "ne2k_isa",
+    .qdev.size  = sizeof(ISANE2000State),
+    .init       = isa_ne2000_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
+        DEFINE_PROP_UINT32("irq",   ISANE2000State, isairq, 9),
+        DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void ne2000_isa_register_devices(void)
+{
+    isa_qdev_register(&ne2000_isa_info);
+}
+
+device_init(ne2000_isa_register_devices)
diff --git a/qemu-0.15.x/hw/ne2000.c b/qemu-0.15.x/hw/ne2000.c
new file mode 100644
index 0000000..f8acaae
--- /dev/null
+++ b/qemu-0.15.x/hw/ne2000.c
@@ -0,0 +1,781 @@
+/*
+ * QEMU NE2000 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 "hw.h"
+#include "pci.h"
+#include "net.h"
+#include "ne2000.h"
+#include "loader.h"
+#include "sysemu.h"
+
+/* debug NE2000 card */
+//#define DEBUG_NE2000
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+#define E8390_CMD	0x00  /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO	0x01	/* Low byte of current local dma addr  RD */
+#define EN0_STARTPG	0x01	/* Starting page of ring bfr WR */
+#define EN0_CLDAHI	0x02	/* High byte of current local dma addr  RD */
+#define EN0_STOPPG	0x02	/* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY	0x03	/* Boundary page of ring bfr RD WR */
+#define EN0_TSR		0x04	/* Transmit status reg RD */
+#define EN0_TPSR	0x04	/* Transmit starting page WR */
+#define EN0_NCR		0x05	/* Number of collision reg RD */
+#define EN0_TCNTLO	0x05	/* Low  byte of tx byte count WR */
+#define EN0_FIFO	0x06	/* FIFO RD */
+#define EN0_TCNTHI	0x06	/* High byte of tx byte count WR */
+#define EN0_ISR		0x07	/* Interrupt status reg RD WR */
+#define EN0_CRDALO	0x08	/* low byte of current remote dma address RD */
+#define EN0_RSARLO	0x08	/* Remote start address reg 0 */
+#define EN0_CRDAHI	0x09	/* high byte, current remote dma address RD */
+#define EN0_RSARHI	0x09	/* Remote start address reg 1 */
+#define EN0_RCNTLO	0x0a	/* Remote byte count reg WR */
+#define EN0_RTL8029ID0	0x0a	/* Realtek ID byte #1 RD */
+#define EN0_RCNTHI	0x0b	/* Remote byte count reg WR */
+#define EN0_RTL8029ID1	0x0b	/* Realtek ID byte #2 RD */
+#define EN0_RSR		0x0c	/* rx status reg RD */
+#define EN0_RXCR	0x0c	/* RX configuration reg WR */
+#define EN0_TXCR	0x0d	/* TX configuration reg WR */
+#define EN0_COUNTER0	0x0d	/* Rcv alignment error counter RD */
+#define EN0_DCFG	0x0e	/* Data configuration reg WR */
+#define EN0_COUNTER1	0x0e	/* Rcv CRC error counter RD */
+#define EN0_IMR		0x0f	/* Interrupt mask reg WR */
+#define EN0_COUNTER2	0x0f	/* Rcv missed frame error counter RD */
+
+#define EN1_PHYS        0x11
+#define EN1_CURPAG      0x17
+#define EN1_MULT        0x18
+
+#define EN2_STARTPG	0x21	/* Starting page of ring bfr RD */
+#define EN2_STOPPG	0x22	/* Ending page +1 of ring bfr RD */
+
+#define EN3_CONFIG0	0x33
+#define EN3_CONFIG1	0x34
+#define EN3_CONFIG2	0x35
+#define EN3_CONFIG3	0x36
+
+/*  Register accessed at EN_CMD, the 8390 base addr.  */
+#define E8390_STOP	0x01	/* Stop and reset the chip */
+#define E8390_START	0x02	/* Start the chip, clear reset */
+#define E8390_TRANS	0x04	/* Transmit a frame */
+#define E8390_RREAD	0x08	/* Remote read */
+#define E8390_RWRITE	0x10	/* Remote write  */
+#define E8390_NODMA	0x20	/* Remote DMA */
+#define E8390_PAGE0	0x00	/* Select page chip registers */
+#define E8390_PAGE1	0x40	/* using the two high-order bits */
+#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX	0x01	/* Receiver, no error */
+#define ENISR_TX	0x02	/* Transmitter, no error */
+#define ENISR_RX_ERR	0x04	/* Receiver, with error */
+#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
+#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
+#define ENISR_COUNTERS	0x20	/* Counters need emptying */
+#define ENISR_RDC	0x40	/* remote dma complete */
+#define ENISR_RESET	0x80	/* Reset completed */
+#define ENISR_ALL	0x3f	/* Interrupts we will enable */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK	0x01	/* Received a good packet */
+#define ENRSR_CRC	0x02	/* CRC error */
+#define ENRSR_FAE	0x04	/* frame alignment error */
+#define ENRSR_FO	0x08	/* FIFO overrun */
+#define ENRSR_MPA	0x10	/* missed pkt */
+#define ENRSR_PHY	0x20	/* physical/multicast address */
+#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
+#define ENRSR_DEF	0x80	/* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01	/* Packet transmitted without error */
+#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04	/* The transmit collided at least once. */
+#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
+
+typedef struct PCINE2000State {
+    PCIDevice dev;
+    NE2000State ne2000;
+} PCINE2000State;
+
+void ne2000_reset(NE2000State *s)
+{
+    int i;
+
+    s->isr = ENISR_RESET;
+    memcpy(s->mem, &s->c.macaddr, 6);
+    s->mem[14] = 0x57;
+    s->mem[15] = 0x57;
+
+    /* duplicate prom data */
+    for(i = 15;i >= 0; i--) {
+        s->mem[2 * i] = s->mem[i];
+        s->mem[2 * i + 1] = s->mem[i];
+    }
+}
+
+static void ne2000_update_irq(NE2000State *s)
+{
+    int isr;
+    isr = (s->isr & s->imr) & 0x7f;
+#if defined(DEBUG_NE2000)
+    printf("NE2000: Set IRQ to %d (%02x %02x)\n",
+	   isr ? 1 : 0, s->isr, s->imr);
+#endif
+    qemu_set_irq(s->irq, (isr != 0));
+}
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static int compute_mcast_idx(const uint8_t *ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ POLYNOMIAL) | carry);
+        }
+    }
+    return (crc >> 26);
+}
+
+static int ne2000_buffer_full(NE2000State *s)
+{
+    int avail, index, boundary;
+
+    index = s->curpag << 8;
+    boundary = s->boundary << 8;
+    if (index < boundary)
+        avail = boundary - index;
+    else
+        avail = (s->stop - s->start) - (index - boundary);
+    if (avail < (MAX_ETH_FRAME_SIZE + 4))
+        return 1;
+    return 0;
+}
+
+int ne2000_can_receive(VLANClientState *nc)
+{
+    NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (s->cmd & E8390_STOP)
+        return 1;
+    return !ne2000_buffer_full(s);
+}
+
+#define MIN_BUF_SIZE 60
+
+ssize_t ne2000_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
+{
+    NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int size = size_;
+    uint8_t *p;
+    unsigned int total_len, next, avail, len, index, mcast_idx;
+    uint8_t buf1[60];
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(DEBUG_NE2000)
+    printf("NE2000: received len=%d\n", size);
+#endif
+
+    if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
+        return -1;
+
+    /* XXX: check this */
+    if (s->rxcr & 0x10) {
+        /* promiscuous: receive all */
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->rxcr & 0x04))
+                return size;
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->rxcr & 0x08))
+                return size;
+            mcast_idx = compute_mcast_idx(buf);
+            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+                return size;
+        } else if (s->mem[0] == buf[0] &&
+                   s->mem[2] == buf[1] &&
+                   s->mem[4] == buf[2] &&
+                   s->mem[6] == buf[3] &&
+                   s->mem[8] == buf[4] &&
+                   s->mem[10] == buf[5]) {
+            /* match */
+        } else {
+            return size;
+        }
+    }
+
+
+    /* if too small buffer, then expand it */
+    if (size < MIN_BUF_SIZE) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        buf = buf1;
+        size = MIN_BUF_SIZE;
+    }
+
+    index = s->curpag << 8;
+    /* 4 bytes for header */
+    total_len = size + 4;
+    /* address for next packet (4 bytes for CRC) */
+    next = index + ((total_len + 4 + 255) & ~0xff);
+    if (next >= s->stop)
+        next -= (s->stop - s->start);
+    /* prepare packet header */
+    p = s->mem + index;
+    s->rsr = ENRSR_RXOK; /* receive status */
+    /* XXX: check this */
+    if (buf[0] & 0x01)
+        s->rsr |= ENRSR_PHY;
+    p[0] = s->rsr;
+    p[1] = next >> 8;
+    p[2] = total_len;
+    p[3] = total_len >> 8;
+    index += 4;
+
+    /* write packet data */
+    while (size > 0) {
+        if (index <= s->stop)
+            avail = s->stop - index;
+        else
+            avail = 0;
+        len = size;
+        if (len > avail)
+            len = avail;
+        memcpy(s->mem + index, buf, len);
+        buf += len;
+        index += len;
+        if (index == s->stop)
+            index = s->start;
+        size -= len;
+    }
+    s->curpag = next >> 8;
+
+    /* now we can signal we have received something */
+    s->isr |= ENISR_RX;
+    ne2000_update_irq(s);
+
+    return size_;
+}
+
+void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+    int offset, page, index;
+
+    addr &= 0xf;
+#ifdef DEBUG_NE2000
+    printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
+#endif
+    if (addr == E8390_CMD) {
+        /* control register */
+        s->cmd = val;
+        if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
+            s->isr &= ~ENISR_RESET;
+            /* test specific case: zero length transfer */
+            if ((val & (E8390_RREAD | E8390_RWRITE)) &&
+                s->rcnt == 0) {
+                s->isr |= ENISR_RDC;
+                ne2000_update_irq(s);
+            }
+            if (val & E8390_TRANS) {
+                index = (s->tpsr << 8);
+                /* XXX: next 2 lines are a hack to make netware 3.11 work */
+                if (index >= NE2000_PMEM_END)
+                    index -= NE2000_PMEM_SIZE;
+                /* fail safe: check range on the transmitted length  */
+                if (index + s->tcnt <= NE2000_PMEM_END) {
+                    qemu_send_packet(&s->nic->nc, s->mem + index, s->tcnt);
+                }
+                /* signal end of transfer */
+                s->tsr = ENTSR_PTX;
+                s->isr |= ENISR_TX;
+                s->cmd &= ~E8390_TRANS;
+                ne2000_update_irq(s);
+            }
+        }
+    } else {
+        page = s->cmd >> 6;
+        offset = addr | (page << 4);
+        switch(offset) {
+        case EN0_STARTPG:
+            s->start = val << 8;
+            break;
+        case EN0_STOPPG:
+            s->stop = val << 8;
+            break;
+        case EN0_BOUNDARY:
+            s->boundary = val;
+            break;
+        case EN0_IMR:
+            s->imr = val;
+            ne2000_update_irq(s);
+            break;
+        case EN0_TPSR:
+            s->tpsr = val;
+            break;
+        case EN0_TCNTLO:
+            s->tcnt = (s->tcnt & 0xff00) | val;
+            break;
+        case EN0_TCNTHI:
+            s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
+            break;
+        case EN0_RSARLO:
+            s->rsar = (s->rsar & 0xff00) | val;
+            break;
+        case EN0_RSARHI:
+            s->rsar = (s->rsar & 0x00ff) | (val << 8);
+            break;
+        case EN0_RCNTLO:
+            s->rcnt = (s->rcnt & 0xff00) | val;
+            break;
+        case EN0_RCNTHI:
+            s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
+            break;
+        case EN0_RXCR:
+            s->rxcr = val;
+            break;
+        case EN0_DCFG:
+            s->dcfg = val;
+            break;
+        case EN0_ISR:
+            s->isr &= ~(val & 0x7f);
+            ne2000_update_irq(s);
+            break;
+        case EN1_PHYS ... EN1_PHYS + 5:
+            s->phys[offset - EN1_PHYS] = val;
+            break;
+        case EN1_CURPAG:
+            s->curpag = val;
+            break;
+        case EN1_MULT ... EN1_MULT + 7:
+            s->mult[offset - EN1_MULT] = val;
+            break;
+        }
+    }
+}
+
+uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int offset, page, ret;
+
+    addr &= 0xf;
+    if (addr == E8390_CMD) {
+        ret = s->cmd;
+    } else {
+        page = s->cmd >> 6;
+        offset = addr | (page << 4);
+        switch(offset) {
+        case EN0_TSR:
+            ret = s->tsr;
+            break;
+        case EN0_BOUNDARY:
+            ret = s->boundary;
+            break;
+        case EN0_ISR:
+            ret = s->isr;
+            break;
+	case EN0_RSARLO:
+	    ret = s->rsar & 0x00ff;
+	    break;
+	case EN0_RSARHI:
+	    ret = s->rsar >> 8;
+	    break;
+        case EN1_PHYS ... EN1_PHYS + 5:
+            ret = s->phys[offset - EN1_PHYS];
+            break;
+        case EN1_CURPAG:
+            ret = s->curpag;
+            break;
+        case EN1_MULT ... EN1_MULT + 7:
+            ret = s->mult[offset - EN1_MULT];
+            break;
+        case EN0_RSR:
+            ret = s->rsr;
+            break;
+        case EN2_STARTPG:
+            ret = s->start >> 8;
+            break;
+        case EN2_STOPPG:
+            ret = s->stop >> 8;
+            break;
+	case EN0_RTL8029ID0:
+	    ret = 0x50;
+	    break;
+	case EN0_RTL8029ID1:
+	    ret = 0x43;
+	    break;
+	case EN3_CONFIG0:
+	    ret = 0;		/* 10baseT media */
+	    break;
+	case EN3_CONFIG2:
+	    ret = 0x40;		/* 10baseT active */
+	    break;
+	case EN3_CONFIG3:
+	    ret = 0x40;		/* Full duplex */
+	    break;
+        default:
+            ret = 0x00;
+            break;
+        }
+    }
+#ifdef DEBUG_NE2000
+    printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
+#endif
+    return ret;
+}
+
+static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        s->mem[addr] = val;
+    }
+}
+
+static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
+    }
+}
+
+static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
+    }
+}
+
+static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
+{
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return s->mem[addr];
+    } else {
+        return 0xff;
+    }
+}
+
+static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return le16_to_cpu(*(uint16_t *)(s->mem + addr));
+    } else {
+        return 0xffff;
+    }
+}
+
+static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return le32_to_cpupu((uint32_t *)(s->mem + addr));
+    } else {
+        return 0xffffffff;
+    }
+}
+
+static inline void ne2000_dma_update(NE2000State *s, int len)
+{
+    s->rsar += len;
+    /* wrap */
+    /* XXX: check what to do if rsar > stop */
+    if (s->rsar == s->stop)
+        s->rsar = s->start;
+
+    if (s->rcnt <= len) {
+        s->rcnt = 0;
+        /* signal end of transfer */
+        s->isr |= ENISR_RDC;
+        ne2000_update_irq(s);
+    } else {
+        s->rcnt -= len;
+    }
+}
+
+void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic write val=0x%04x\n", val);
+#endif
+    if (s->rcnt == 0)
+        return;
+    if (s->dcfg & 0x01) {
+        /* 16 bit access */
+        ne2000_mem_writew(s, s->rsar, val);
+        ne2000_dma_update(s, 2);
+    } else {
+        /* 8 bit access */
+        ne2000_mem_writeb(s, s->rsar, val);
+        ne2000_dma_update(s, 1);
+    }
+}
+
+uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int ret;
+
+    if (s->dcfg & 0x01) {
+        /* 16 bit access */
+        ret = ne2000_mem_readw(s, s->rsar);
+        ne2000_dma_update(s, 2);
+    } else {
+        /* 8 bit access */
+        ret = ne2000_mem_readb(s, s->rsar);
+        ne2000_dma_update(s, 1);
+    }
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic read val=0x%04x\n", ret);
+#endif
+    return ret;
+}
+
+static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic writel val=0x%04x\n", val);
+#endif
+    if (s->rcnt == 0)
+        return;
+    /* 32 bit access */
+    ne2000_mem_writel(s, s->rsar, val);
+    ne2000_dma_update(s, 4);
+}
+
+static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int ret;
+
+    /* 32 bit access */
+    ret = ne2000_mem_readl(s, s->rsar);
+    ne2000_dma_update(s, 4);
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic readl val=0x%04x\n", ret);
+#endif
+    return ret;
+}
+
+void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    /* nothing to do (end of reset pulse) */
+}
+
+uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    ne2000_reset(s);
+    return 0;
+}
+
+static int ne2000_post_load(void* opaque, int version_id)
+{
+    NE2000State* s = opaque;
+
+    if (version_id < 2) {
+        s->rxcr = 0x0c;
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_ne2000 = {
+    .name = "ne2000",
+    .version_id = 2,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ne2000_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8_V(rxcr, NE2000State, 2),
+        VMSTATE_UINT8(cmd, NE2000State),
+        VMSTATE_UINT32(start, NE2000State),
+        VMSTATE_UINT32(stop, NE2000State),
+        VMSTATE_UINT8(boundary, NE2000State),
+        VMSTATE_UINT8(tsr, NE2000State),
+        VMSTATE_UINT8(tpsr, NE2000State),
+        VMSTATE_UINT16(tcnt, NE2000State),
+        VMSTATE_UINT16(rcnt, NE2000State),
+        VMSTATE_UINT32(rsar, NE2000State),
+        VMSTATE_UINT8(rsr, NE2000State),
+        VMSTATE_UINT8(isr, NE2000State),
+        VMSTATE_UINT8(dcfg, NE2000State),
+        VMSTATE_UINT8(imr, NE2000State),
+        VMSTATE_BUFFER(phys, NE2000State),
+        VMSTATE_UINT8(curpag, NE2000State),
+        VMSTATE_BUFFER(mult, NE2000State),
+        VMSTATE_UNUSED(4), /* was irq */
+        VMSTATE_BUFFER(mem, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_ne2000 = {
+    .name = "ne2000",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCINE2000State),
+        VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/***********************************************************/
+/* PCI NE2000 definitions */
+
+static void ne2000_map(PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s = &d->ne2000;
+
+    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
+    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
+
+    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
+    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
+    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
+    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
+    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
+    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
+
+    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
+    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+}
+
+static void ne2000_cleanup(VLANClientState *nc)
+{
+    NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_ne2000_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = ne2000_can_receive,
+    .receive = ne2000_receive,
+    .cleanup = ne2000_cleanup,
+};
+
+static int pci_ne2000_init(PCIDevice *pci_dev)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s;
+    uint8_t *pci_conf;
+
+    pci_conf = d->dev.config;
+    /* TODO: RST# value should be 0. PCI spec 6.2.4 */
+    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+
+    pci_register_bar(&d->dev, 0, 0x100,
+                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
+    s = &d->ne2000;
+    s->irq = d->dev.irq[0];
+
+    qemu_macaddr_default_if_unset(&s->c.macaddr);
+    ne2000_reset(s);
+
+    s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
+                          pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
+
+    if (!pci_dev->qdev.hotplugged) {
+        static int loaded = 0;
+        if (!loaded) {
+            rom_add_option("pxe-ne2k_pci.rom", -1);
+            loaded = 1;
+        }
+    }
+
+    add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
+    return 0;
+}
+
+static int pci_ne2000_exit(PCIDevice *pci_dev)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s = &d->ne2000;
+
+    qemu_del_vlan_client(&s->nic->nc);
+    return 0;
+}
+
+static PCIDeviceInfo ne2000_info = {
+    .qdev.name  = "ne2k_pci",
+    .qdev.size  = sizeof(PCINE2000State),
+    .qdev.vmsd  = &vmstate_pci_ne2000,
+    .init       = pci_ne2000_init,
+    .exit       = pci_ne2000_exit,
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8029,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ne2000_register_devices(void)
+{
+    pci_qdev_register(&ne2000_info);
+}
+
+device_init(ne2000_register_devices)
diff --git a/qemu-0.15.x/hw/ne2000.h b/qemu-0.15.x/hw/ne2000.h
new file mode 100644
index 0000000..54fdfca
--- /dev/null
+++ b/qemu-0.15.x/hw/ne2000.h
@@ -0,0 +1,39 @@
+#define NE2000_PMEM_SIZE    (32*1024)
+#define NE2000_PMEM_START   (16*1024)
+#define NE2000_PMEM_END     (NE2000_PMEM_SIZE+NE2000_PMEM_START)
+#define NE2000_MEM_SIZE     NE2000_PMEM_END
+
+typedef struct NE2000State {
+    uint8_t cmd;
+    uint32_t start;
+    uint32_t stop;
+    uint8_t boundary;
+    uint8_t tsr;
+    uint8_t tpsr;
+    uint16_t tcnt;
+    uint16_t rcnt;
+    uint32_t rsar;
+    uint8_t rsr;
+    uint8_t rxcr;
+    uint8_t isr;
+    uint8_t dcfg;
+    uint8_t imr;
+    uint8_t phys[6]; /* mac address */
+    uint8_t curpag;
+    uint8_t mult[8]; /* multicast mask array */
+    qemu_irq irq;
+    NICState *nic;
+    NICConf c;
+    uint8_t mem[NE2000_MEM_SIZE];
+} NE2000State;
+
+void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ne2000_ioport_read(void *opaque, uint32_t addr);
+void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr);
+void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr);
+extern const VMStateDescription vmstate_ne2000;
+void ne2000_reset(NE2000State *s);
+int ne2000_can_receive(VLANClientState *vc);
+ssize_t ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size_);
diff --git a/qemu-0.15.x/hw/nseries.c b/qemu-0.15.x/hw/nseries.c
new file mode 100644
index 0000000..2f84f53
--- /dev/null
+++ b/qemu-0.15.x/hw/nseries.c
@@ -0,0 +1,1417 @@
+/*
+ * Nokia N-series internet tablets.
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "omap.h"
+#include "arm-misc.h"
+#include "irq.h"
+#include "console.h"
+#include "boards.h"
+#include "i2c.h"
+#include "devices.h"
+#include "flash.h"
+#include "hw.h"
+#include "bt.h"
+#include "loader.h"
+
+/* Nokia N8x0 support */
+struct n800_s {
+    struct omap_mpu_state_s *cpu;
+
+    struct rfbi_chip_s blizzard;
+    struct {
+        void *opaque;
+        uint32_t (*txrx)(void *opaque, uint32_t value, int len);
+        uWireSlave *chip;
+    } ts;
+    i2c_bus *i2c;
+
+    int keymap[0x80];
+    i2c_slave *kbd;
+
+    TUSBState *usb;
+    void *retu;
+    void *tahvo;
+    void *nand;
+};
+
+/* GPIO pins */
+#define N8X0_TUSB_ENABLE_GPIO		0
+#define N800_MMC2_WP_GPIO		8
+#define N800_UNKNOWN_GPIO0		9	/* out */
+#define N810_MMC2_VIOSD_GPIO		9
+#define N810_HEADSET_AMP_GPIO		10
+#define N800_CAM_TURN_GPIO		12
+#define N810_GPS_RESET_GPIO		12
+#define N800_BLIZZARD_POWERDOWN_GPIO	15
+#define N800_MMC1_WP_GPIO		23
+#define N810_MMC2_VSD_GPIO		23
+#define N8X0_ONENAND_GPIO		26
+#define N810_BLIZZARD_RESET_GPIO	30
+#define N800_UNKNOWN_GPIO2		53	/* out */
+#define N8X0_TUSB_INT_GPIO		58
+#define N8X0_BT_WKUP_GPIO		61
+#define N8X0_STI_GPIO			62
+#define N8X0_CBUS_SEL_GPIO		64
+#define N8X0_CBUS_DAT_GPIO		65
+#define N8X0_CBUS_CLK_GPIO		66
+#define N8X0_WLAN_IRQ_GPIO		87
+#define N8X0_BT_RESET_GPIO		92
+#define N8X0_TEA5761_CS_GPIO		93
+#define N800_UNKNOWN_GPIO		94
+#define N810_TSC_RESET_GPIO		94
+#define N800_CAM_ACT_GPIO		95
+#define N810_GPS_WAKEUP_GPIO		95
+#define N8X0_MMC_CS_GPIO		96
+#define N8X0_WLAN_PWR_GPIO		97
+#define N8X0_BT_HOST_WKUP_GPIO		98
+#define N810_SPEAKER_AMP_GPIO		101
+#define N810_KB_LOCK_GPIO		102
+#define N800_TSC_TS_GPIO		103
+#define N810_TSC_TS_GPIO		106
+#define N8X0_HEADPHONE_GPIO		107
+#define N8X0_RETU_GPIO			108
+#define N800_TSC_KP_IRQ_GPIO		109
+#define N810_KEYBOARD_GPIO		109
+#define N800_BAT_COVER_GPIO		110
+#define N810_SLIDE_GPIO			110
+#define N8X0_TAHVO_GPIO			111
+#define N800_UNKNOWN_GPIO4		112	/* out */
+#define N810_SLEEPX_LED_GPIO		112
+#define N800_TSC_RESET_GPIO		118	/* ? */
+#define N810_AIC33_RESET_GPIO		118
+#define N800_TSC_UNKNOWN_GPIO		119	/* out */
+#define N8X0_TMP105_GPIO		125
+
+/* Config */
+#define BT_UART				0
+#define XLDR_LL_UART			1
+
+/* Addresses on the I2C bus 0 */
+#define N810_TLV320AIC33_ADDR		0x18	/* Audio CODEC */
+#define N8X0_TCM825x_ADDR		0x29	/* Camera */
+#define N810_LP5521_ADDR		0x32	/* LEDs */
+#define N810_TSL2563_ADDR		0x3d	/* Light sensor */
+#define N810_LM8323_ADDR		0x45	/* Keyboard */
+/* Addresses on the I2C bus 1 */
+#define N8X0_TMP105_ADDR		0x48	/* Temperature sensor */
+#define N8X0_MENELAUS_ADDR		0x72	/* Power management */
+
+/* Chipselects on GPMC NOR interface */
+#define N8X0_ONENAND_CS			0
+#define N8X0_USB_ASYNC_CS		1
+#define N8X0_USB_SYNC_CS		4
+
+#define N8X0_BD_ADDR			0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
+
+static void n800_mmc_cs_cb(void *opaque, int line, int level)
+{
+    /* TODO: this seems to actually be connected to the menelaus, to
+     * which also both MMC slots connect.  */
+    omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
+
+    printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
+}
+
+static void n8x0_gpio_setup(struct n800_s *s)
+{
+    qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1);
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]);
+
+    qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]);
+}
+
+#define MAEMO_CAL_HEADER(...)				\
+    'C',  'o',  'n',  'F',  0x02, 0x00, 0x04, 0x00,	\
+    __VA_ARGS__,					\
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+static const uint8_t n8x0_cal_wlan_mac[] = {
+    MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
+    0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
+    0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+    0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
+    0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t n8x0_cal_bt_id[] = {
+    MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
+    0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
+    0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
+    N8X0_BD_ADDR,
+};
+
+static void n8x0_nand_setup(struct n800_s *s)
+{
+    char *otp_region;
+
+    /* Either ec40xx or ec48xx are OK for the ID */
+    omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
+                    onenand_base_unmap,
+                    (s->nand = onenand_init(0xec4800, 1,
+                                            omap2_gpio_in_get(s->cpu->gpif,
+                                                    N8X0_ONENAND_GPIO)[0])));
+    otp_region = onenand_raw_otp(s->nand);
+
+    memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
+    memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
+    /* XXX: in theory should also update the OOB for both pages */
+}
+
+static void n8x0_i2c_setup(struct n800_s *s)
+{
+    DeviceState *dev;
+    qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0];
+
+    /* Attach the CPU on one end of our I2C bus.  */
+    s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
+
+    /* Attach a menelaus PM chip */
+    dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR);
+    qdev_connect_gpio_out(dev, 3, s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]);
+
+    /* Attach a TMP105 PM chip (A0 wired to ground) */
+    dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
+    qdev_connect_gpio_out(dev, 0, tmp_irq);
+}
+
+/* Touchscreen and keypad controller */
+static MouseTransformInfo n800_pointercal = {
+    .x = 800,
+    .y = 480,
+    .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
+};
+
+static MouseTransformInfo n810_pointercal = {
+    .x = 800,
+    .y = 480,
+    .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
+};
+
+#define RETU_KEYCODE	61	/* F3 */
+
+static void n800_key_event(void *opaque, int keycode)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    int code = s->keymap[keycode & 0x7f];
+
+    if (code == -1) {
+        if ((keycode & 0x7f) == RETU_KEYCODE)
+            retu_key_event(s->retu, !(keycode & 0x80));
+        return;
+    }
+
+    tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
+}
+
+static const int n800_keys[16] = {
+    -1,
+    72,	/* Up */
+    63,	/* Home (F5) */
+    -1,
+    75,	/* Left */
+    28,	/* Enter */
+    77,	/* Right */
+    -1,
+     1,	/* Cycle (ESC) */
+    80,	/* Down */
+    62,	/* Menu (F4) */
+    -1,
+    66,	/* Zoom- (F8) */
+    64,	/* FullScreen (F6) */
+    65,	/* Zoom+ (F7) */
+    -1,
+};
+
+static void n800_tsc_kbd_setup(struct n800_s *s)
+{
+    int i;
+
+    /* XXX: are the three pins inverted inside the chip between the
+     * tsc and the cpu (N4111)?  */
+    qemu_irq penirq = NULL;	/* NC */
+    qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0];
+    qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0];
+
+    s->ts.chip = tsc2301_init(penirq, kbirq, dav);
+    s->ts.opaque = s->ts.chip->opaque;
+    s->ts.txrx = tsc210x_txrx;
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < 0x10; i ++)
+        if (n800_keys[i] >= 0)
+            s->keymap[n800_keys[i]] = i;
+
+    qemu_add_kbd_event_handler(n800_key_event, s);
+
+    tsc210x_set_transform(s->ts.chip, &n800_pointercal);
+}
+
+static void n810_tsc_setup(struct n800_s *s)
+{
+    qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0];
+
+    s->ts.opaque = tsc2005_init(pintdav);
+    s->ts.txrx = tsc2005_txrx;
+
+    tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
+}
+
+/* N810 Keyboard controller */
+static void n810_key_event(void *opaque, int keycode)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    int code = s->keymap[keycode & 0x7f];
+
+    if (code == -1) {
+        if ((keycode & 0x7f) == RETU_KEYCODE)
+            retu_key_event(s->retu, !(keycode & 0x80));
+        return;
+    }
+
+    lm832x_key_event(s->kbd, code, !(keycode & 0x80));
+}
+
+#define M	0
+
+static int n810_keys[0x80] = {
+    [0x01] = 16,	/* Q */
+    [0x02] = 37,	/* K */
+    [0x03] = 24,	/* O */
+    [0x04] = 25,	/* P */
+    [0x05] = 14,	/* Backspace */
+    [0x06] = 30,	/* A */
+    [0x07] = 31,	/* S */
+    [0x08] = 32,	/* D */
+    [0x09] = 33,	/* F */
+    [0x0a] = 34,	/* G */
+    [0x0b] = 35,	/* H */
+    [0x0c] = 36,	/* J */
+
+    [0x11] = 17,	/* W */
+    [0x12] = 62,	/* Menu (F4) */
+    [0x13] = 38,	/* L */
+    [0x14] = 40,	/* ' (Apostrophe) */
+    [0x16] = 44,	/* Z */
+    [0x17] = 45,	/* X */
+    [0x18] = 46,	/* C */
+    [0x19] = 47,	/* V */
+    [0x1a] = 48,	/* B */
+    [0x1b] = 49,	/* N */
+    [0x1c] = 42,	/* Shift (Left shift) */
+    [0x1f] = 65,	/* Zoom+ (F7) */
+
+    [0x21] = 18,	/* E */
+    [0x22] = 39,	/* ; (Semicolon) */
+    [0x23] = 12,	/* - (Minus) */
+    [0x24] = 13,	/* = (Equal) */
+    [0x2b] = 56,	/* Fn (Left Alt) */
+    [0x2c] = 50,	/* M */
+    [0x2f] = 66,	/* Zoom- (F8) */
+
+    [0x31] = 19,	/* R */
+    [0x32] = 29 | M,	/* Right Ctrl */
+    [0x34] = 57,	/* Space */
+    [0x35] = 51,	/* , (Comma) */
+    [0x37] = 72 | M,	/* Up */
+    [0x3c] = 82 | M,	/* Compose (Insert) */
+    [0x3f] = 64,	/* FullScreen (F6) */
+
+    [0x41] = 20,	/* T */
+    [0x44] = 52,	/* . (Dot) */
+    [0x46] = 77 | M,	/* Right */
+    [0x4f] = 63,	/* Home (F5) */
+    [0x51] = 21,	/* Y */
+    [0x53] = 80 | M,	/* Down */
+    [0x55] = 28,	/* Enter */
+    [0x5f] =  1,	/* Cycle (ESC) */
+
+    [0x61] = 22,	/* U */
+    [0x64] = 75 | M,	/* Left */
+
+    [0x71] = 23,	/* I */
+#if 0
+    [0x75] = 28 | M,	/* KP Enter (KP Enter) */
+#else
+    [0x75] = 15,	/* KP Enter (Tab) */
+#endif
+};
+
+#undef M
+
+static void n810_kbd_setup(struct n800_s *s)
+{
+    qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0];
+    DeviceState *dev;
+    int i;
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < 0x80; i ++)
+        if (n810_keys[i] > 0)
+            s->keymap[n810_keys[i]] = i;
+
+    qemu_add_kbd_event_handler(n810_key_event, s);
+
+    /* Attach the LM8322 keyboard to the I2C bus,
+     * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
+    dev = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
+    qdev_connect_gpio_out(dev, 0, kbd_irq);
+}
+
+/* LCD MIPI DBI-C controller (URAL) */
+struct mipid_s {
+    int resp[4];
+    int param[4];
+    int p;
+    int pm;
+    int cmd;
+
+    int sleep;
+    int booster;
+    int te;
+    int selfcheck;
+    int partial;
+    int normal;
+    int vscr;
+    int invert;
+    int onoff;
+    int gamma;
+    uint32_t id;
+};
+
+static void mipid_reset(struct mipid_s *s)
+{
+    if (!s->sleep)
+        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
+
+    s->pm = 0;
+    s->cmd = 0;
+
+    s->sleep = 1;
+    s->booster = 0;
+    s->selfcheck =
+            (1 << 7) |	/* Register loading OK.  */
+            (1 << 5) |	/* The chip is attached.  */
+            (1 << 4);	/* Display glass still in one piece.  */
+    s->te = 0;
+    s->partial = 0;
+    s->normal = 1;
+    s->vscr = 0;
+    s->invert = 0;
+    s->onoff = 1;
+    s->gamma = 0;
+}
+
+static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
+{
+    struct mipid_s *s = (struct mipid_s *) opaque;
+    uint8_t ret;
+
+    if (len > 9)
+        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
+
+    if (s->p >= ARRAY_SIZE(s->resp))
+        ret = 0;
+    else
+        ret = s->resp[s->p ++];
+    if (s->pm --> 0)
+        s->param[s->pm] = cmd;
+    else
+        s->cmd = cmd;
+
+    switch (s->cmd) {
+    case 0x00:	/* NOP */
+        break;
+
+    case 0x01:	/* SWRESET */
+        mipid_reset(s);
+        break;
+
+    case 0x02:	/* BSTROFF */
+        s->booster = 0;
+        break;
+    case 0x03:	/* BSTRON */
+        s->booster = 1;
+        break;
+
+    case 0x04:	/* RDDID */
+        s->p = 0;
+        s->resp[0] = (s->id >> 16) & 0xff;
+        s->resp[1] = (s->id >>  8) & 0xff;
+        s->resp[2] = (s->id >>  0) & 0xff;
+        break;
+
+    case 0x06:	/* RD_RED */
+    case 0x07:	/* RD_GREEN */
+        /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
+         * for the bootloader one needs to change this.  */
+    case 0x08:	/* RD_BLUE */
+        s->p = 0;
+        /* TODO: return first pixel components */
+        s->resp[0] = 0x01;
+        break;
+
+    case 0x09:	/* RDDST */
+        s->p = 0;
+        s->resp[0] = s->booster << 7;
+        s->resp[1] = (5 << 4) | (s->partial << 2) |
+                (s->sleep << 1) | s->normal;
+        s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
+                (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
+        s->resp[3] = s->gamma << 6;
+        break;
+
+    case 0x0a:	/* RDDPM */
+        s->p = 0;
+        s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
+                (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
+        break;
+    case 0x0b:	/* RDDMADCTR */
+        s->p = 0;
+        s->resp[0] = 0;
+        break;
+    case 0x0c:	/* RDDCOLMOD */
+        s->p = 0;
+        s->resp[0] = 5;	/* 65K colours */
+        break;
+    case 0x0d:	/* RDDIM */
+        s->p = 0;
+        s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
+        break;
+    case 0x0e:	/* RDDSM */
+        s->p = 0;
+        s->resp[0] = s->te << 7;
+        break;
+    case 0x0f:	/* RDDSDR */
+        s->p = 0;
+        s->resp[0] = s->selfcheck;
+        break;
+
+    case 0x10:	/* SLPIN */
+        s->sleep = 1;
+        break;
+    case 0x11:	/* SLPOUT */
+        s->sleep = 0;
+        s->selfcheck ^= 1 << 6;	/* POFF self-diagnosis Ok */
+        break;
+
+    case 0x12:	/* PTLON */
+        s->partial = 1;
+        s->normal = 0;
+        s->vscr = 0;
+        break;
+    case 0x13:	/* NORON */
+        s->partial = 0;
+        s->normal = 1;
+        s->vscr = 0;
+        break;
+
+    case 0x20:	/* INVOFF */
+        s->invert = 0;
+        break;
+    case 0x21:	/* INVON */
+        s->invert = 1;
+        break;
+
+    case 0x22:	/* APOFF */
+    case 0x23:	/* APON */
+        goto bad_cmd;
+
+    case 0x25:	/* WRCNTR */
+        if (s->pm < 0)
+            s->pm = 1;
+        goto bad_cmd;
+
+    case 0x26:	/* GAMSET */
+        if (!s->pm)
+            s->gamma = ffs(s->param[0] & 0xf) - 1;
+        else if (s->pm < 0)
+            s->pm = 1;
+        break;
+
+    case 0x28:	/* DISPOFF */
+        s->onoff = 0;
+        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
+        break;
+    case 0x29:	/* DISPON */
+        s->onoff = 1;
+        fprintf(stderr, "%s: Display on\n", __FUNCTION__);
+        break;
+
+    case 0x2a:	/* CASET */
+    case 0x2b:	/* RASET */
+    case 0x2c:	/* RAMWR */
+    case 0x2d:	/* RGBSET */
+    case 0x2e:	/* RAMRD */
+    case 0x30:	/* PTLAR */
+    case 0x33:	/* SCRLAR */
+        goto bad_cmd;
+
+    case 0x34:	/* TEOFF */
+        s->te = 0;
+        break;
+    case 0x35:	/* TEON */
+        if (!s->pm)
+            s->te = 1;
+        else if (s->pm < 0)
+            s->pm = 1;
+        break;
+
+    case 0x36:	/* MADCTR */
+        goto bad_cmd;
+
+    case 0x37:	/* VSCSAD */
+        s->partial = 0;
+        s->normal = 0;
+        s->vscr = 1;
+        break;
+
+    case 0x38:	/* IDMOFF */
+    case 0x39:	/* IDMON */
+    case 0x3a:	/* COLMOD */
+        goto bad_cmd;
+
+    case 0xb0:	/* CLKINT / DISCTL */
+    case 0xb1:	/* CLKEXT */
+        if (s->pm < 0)
+            s->pm = 2;
+        break;
+
+    case 0xb4:	/* FRMSEL */
+        break;
+
+    case 0xb5:	/* FRM8SEL */
+    case 0xb6:	/* TMPRNG / INIESC */
+    case 0xb7:	/* TMPHIS / NOP2 */
+    case 0xb8:	/* TMPREAD / MADCTL */
+    case 0xba:	/* DISTCTR */
+    case 0xbb:	/* EPVOL */
+        goto bad_cmd;
+
+    case 0xbd:	/* Unknown */
+        s->p = 0;
+        s->resp[0] = 0;
+        s->resp[1] = 1;
+        break;
+
+    case 0xc2:	/* IFMOD */
+        if (s->pm < 0)
+            s->pm = 2;
+        break;
+
+    case 0xc6:	/* PWRCTL */
+    case 0xc7:	/* PPWRCTL */
+    case 0xd0:	/* EPWROUT */
+    case 0xd1:	/* EPWRIN */
+    case 0xd4:	/* RDEV */
+    case 0xd5:	/* RDRR */
+        goto bad_cmd;
+
+    case 0xda:	/* RDID1 */
+        s->p = 0;
+        s->resp[0] = (s->id >> 16) & 0xff;
+        break;
+    case 0xdb:	/* RDID2 */
+        s->p = 0;
+        s->resp[0] = (s->id >>  8) & 0xff;
+        break;
+    case 0xdc:	/* RDID3 */
+        s->p = 0;
+        s->resp[0] = (s->id >>  0) & 0xff;
+        break;
+
+    default:
+    bad_cmd:
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
+        break;
+    }
+
+    return ret;
+}
+
+static void *mipid_init(void)
+{
+    struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s));
+
+    s->id = 0x838f03;
+    mipid_reset(s);
+
+    return s;
+}
+
+static void n8x0_spi_setup(struct n800_s *s)
+{
+    void *tsc = s->ts.opaque;
+    void *mipid = mipid_init();
+
+    omap_mcspi_attach(s->cpu->mcspi[0], s->ts.txrx, tsc, 0);
+    omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1);
+}
+
+/* This task is normally performed by the bootloader.  If we're loading
+ * a kernel directly, we need to enable the Blizzard ourselves.  */
+static void n800_dss_init(struct rfbi_chip_s *chip)
+{
+    uint8_t *fb_blank;
+
+    chip->write(chip->opaque, 0, 0x2a);		/* LCD Width register */
+    chip->write(chip->opaque, 1, 0x64);
+    chip->write(chip->opaque, 0, 0x2c);		/* LCD HNDP register */
+    chip->write(chip->opaque, 1, 0x1e);
+    chip->write(chip->opaque, 0, 0x2e);		/* LCD Height 0 register */
+    chip->write(chip->opaque, 1, 0xe0);
+    chip->write(chip->opaque, 0, 0x30);		/* LCD Height 1 register */
+    chip->write(chip->opaque, 1, 0x01);
+    chip->write(chip->opaque, 0, 0x32);		/* LCD VNDP register */
+    chip->write(chip->opaque, 1, 0x06);
+    chip->write(chip->opaque, 0, 0x68);		/* Display Mode register */
+    chip->write(chip->opaque, 1, 1);		/* Enable bit */
+
+    chip->write(chip->opaque, 0, 0x6c);	
+    chip->write(chip->opaque, 1, 0x00);		/* Input X Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Input X Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Input Y Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Input Y Start Position */
+    chip->write(chip->opaque, 1, 0x1f);		/* Input X End Position */
+    chip->write(chip->opaque, 1, 0x03);		/* Input X End Position */
+    chip->write(chip->opaque, 1, 0xdf);		/* Input Y End Position */
+    chip->write(chip->opaque, 1, 0x01);		/* Input Y End Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Output X Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Output X Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Output Y Start Position */
+    chip->write(chip->opaque, 1, 0x00);		/* Output Y Start Position */
+    chip->write(chip->opaque, 1, 0x1f);		/* Output X End Position */
+    chip->write(chip->opaque, 1, 0x03);		/* Output X End Position */
+    chip->write(chip->opaque, 1, 0xdf);		/* Output Y End Position */
+    chip->write(chip->opaque, 1, 0x01);		/* Output Y End Position */
+    chip->write(chip->opaque, 1, 0x01);		/* Input Data Format */
+    chip->write(chip->opaque, 1, 0x01);		/* Data Source Select */
+
+    fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
+    /* Display Memory Data Port */
+    chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
+    qemu_free(fb_blank);
+}
+
+static void n8x0_dss_setup(struct n800_s *s)
+{
+    s->blizzard.opaque = s1d13745_init(NULL);
+    s->blizzard.block = s1d13745_write_block;
+    s->blizzard.write = s1d13745_write;
+    s->blizzard.read = s1d13745_read;
+
+    omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard);
+}
+
+static void n8x0_cbus_setup(struct n800_s *s)
+{
+    qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0];
+    qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0];
+    qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0];
+
+    CBus *cbus = cbus_init(dat_out);
+
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk);
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat);
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel);
+
+    cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
+    cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
+}
+
+static void n8x0_uart_setup(struct n800_s *s)
+{
+    CharDriverState *radio = uart_hci_init(
+                    omap2_gpio_in_get(s->cpu->gpif,
+                            N8X0_BT_HOST_WKUP_GPIO)[0]);
+
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO,
+                    csrhci_pins_get(radio)[csrhci_pin_reset]);
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO,
+                    csrhci_pins_get(radio)[csrhci_pin_wakeup]);
+
+    omap_uart_attach(s->cpu->uart[BT_UART], radio);
+}
+
+static void n8x0_usb_power_cb(void *opaque, int line, int level)
+{
+    struct n800_s *s = opaque;
+
+    tusb6010_power(s->usb, level);
+}
+
+static void n8x0_usb_setup(struct n800_s *s)
+{
+    qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0];
+    qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0];
+    TUSBState *tusb = tusb6010_init(tusb_irq);
+
+    /* Using the NOR interface */
+    omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS,
+                    tusb6010_async_io(tusb), NULL, NULL, tusb);
+    omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS,
+                    tusb6010_sync_io(tusb), NULL, NULL, tusb);
+
+    s->usb = tusb;
+    omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
+}
+
+/* Setup done before the main bootloader starts by some early setup code
+ * - used when we want to run the main bootloader in emulation.  This
+ * isn't documented.  */
+static uint32_t n800_pinout[104] = {
+    0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
+    0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
+    0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
+    0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
+    0x01241800, 0x18181818, 0x000000f0, 0x01300000,
+    0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
+    0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
+    0x007c0000, 0x00000000, 0x00000088, 0x00840000,
+    0x00000000, 0x00000094, 0x00980300, 0x0f180003,
+    0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
+    0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
+    0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
+    0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
+    0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
+    0x00000000, 0x00000038, 0x00340000, 0x00000000,
+    0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
+    0x005c0808, 0x08080808, 0x08080058, 0x00540808,
+    0x08080808, 0x0808006c, 0x00680808, 0x08080808,
+    0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
+    0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
+    0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
+    0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
+    0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
+    0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
+    0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
+    0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
+};
+
+static void n800_setup_nolo_tags(void *sram_base)
+{
+    int i;
+    uint32_t *p = sram_base + 0x8000;
+    uint32_t *v = sram_base + 0xa000;
+
+    memset(p, 0, 0x3000);
+
+    strcpy((void *) (p + 0), "QEMU N800");
+
+    strcpy((void *) (p + 8), "F5");
+
+    stl_raw(p + 10, 0x04f70000);
+    strcpy((void *) (p + 9), "RX-34");
+
+    /* RAM size in MB? */
+    stl_raw(p + 12, 0x80);
+
+    /* Pointer to the list of tags */
+    stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000);
+
+    /* The NOLO tags start here */
+    p = sram_base + 0x9000;
+#define ADD_TAG(tag, len)				\
+    stw_raw((uint16_t *) p + 0, tag);			\
+    stw_raw((uint16_t *) p + 1, len); p ++;		\
+    stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
+
+    /* OMAP STI console? Pin out settings? */
+    ADD_TAG(0x6e01, 414);
+    for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++)
+        stl_raw(v ++, n800_pinout[i]);
+
+    /* Kernel memsize? */
+    ADD_TAG(0x6e05, 1);
+    stl_raw(v ++, 2);
+
+    /* NOLO serial console */
+    ADD_TAG(0x6e02, 4);
+    stl_raw(v ++, XLDR_LL_UART);	/* UART number (1 - 3) */
+
+#if 0
+    /* CBUS settings (Retu/AVilma) */
+    ADD_TAG(0x6e03, 6);
+    stw_raw((uint16_t *) v + 0, 65);	/* CBUS GPIO0 */
+    stw_raw((uint16_t *) v + 1, 66);	/* CBUS GPIO1 */
+    stw_raw((uint16_t *) v + 2, 64);	/* CBUS GPIO2 */
+    v += 2;
+#endif
+
+    /* Nokia ASIC BB5 (Retu/Tahvo) */
+    ADD_TAG(0x6e0a, 4);
+    stw_raw((uint16_t *) v + 0, 111);	/* "Retu" interrupt GPIO */
+    stw_raw((uint16_t *) v + 1, 108);	/* "Tahvo" interrupt GPIO */
+    v ++;
+
+    /* LCD console? */
+    ADD_TAG(0x6e04, 4);
+    stw_raw((uint16_t *) v + 0, 30);	/* ??? */
+    stw_raw((uint16_t *) v + 1, 24);	/* ??? */
+    v ++;
+
+#if 0
+    /* LCD settings */
+    ADD_TAG(0x6e06, 2);
+    stw_raw((uint16_t *) (v ++), 15);	/* ??? */
+#endif
+
+    /* I^2C (Menelaus) */
+    ADD_TAG(0x6e07, 4);
+    stl_raw(v ++, 0x00720000);		/* ??? */
+
+    /* Unknown */
+    ADD_TAG(0x6e0b, 6);
+    stw_raw((uint16_t *) v + 0, 94);	/* ??? */
+    stw_raw((uint16_t *) v + 1, 23);	/* ??? */
+    stw_raw((uint16_t *) v + 2, 0);	/* ??? */
+    v += 2;
+
+    /* OMAP gpio switch info */
+    ADD_TAG(0x6e0c, 80);
+    strcpy((void *) v, "bat_cover");	v += 3;
+    stw_raw((uint16_t *) v + 0, 110);	/* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 1);	/* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "cam_act");	v += 3;
+    stw_raw((uint16_t *) v + 0, 95);	/* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 32);	/* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "cam_turn");	v += 3;
+    stw_raw((uint16_t *) v + 0, 12);	/* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 33);	/* GPIO num ??? */
+    v += 2;
+    strcpy((void *) v, "headphone");	v += 3;
+    stw_raw((uint16_t *) v + 0, 107);	/* GPIO num ??? */
+    stw_raw((uint16_t *) v + 1, 17);	/* GPIO num ??? */
+    v += 2;
+
+    /* Bluetooth */
+    ADD_TAG(0x6e0e, 12);
+    stl_raw(v ++, 0x5c623d01);		/* ??? */
+    stl_raw(v ++, 0x00000201);		/* ??? */
+    stl_raw(v ++, 0x00000000);		/* ??? */
+
+    /* CX3110x WLAN settings */
+    ADD_TAG(0x6e0f, 8);
+    stl_raw(v ++, 0x00610025);		/* ??? */
+    stl_raw(v ++, 0xffff0057);		/* ??? */
+
+    /* MMC host settings */
+    ADD_TAG(0x6e10, 12);
+    stl_raw(v ++, 0xffff000f);		/* ??? */
+    stl_raw(v ++, 0xffffffff);		/* ??? */
+    stl_raw(v ++, 0x00000060);		/* ??? */
+
+    /* OneNAND chip select */
+    ADD_TAG(0x6e11, 10);
+    stl_raw(v ++, 0x00000401);		/* ??? */
+    stl_raw(v ++, 0x0002003a);		/* ??? */
+    stl_raw(v ++, 0x00000002);		/* ??? */
+
+    /* TEA5761 sensor settings */
+    ADD_TAG(0x6e12, 2);
+    stl_raw(v ++, 93);			/* GPIO num ??? */
+
+#if 0
+    /* Unknown tag */
+    ADD_TAG(6e09, 0);
+
+    /* Kernel UART / console */
+    ADD_TAG(6e12, 0);
+#endif
+
+    /* End of the list */
+    stl_raw(p ++, 0x00000000);
+    stl_raw(p ++, 0x00000000);
+}
+
+/* This task is normally performed by the bootloader.  If we're loading
+ * a kernel directly, we need to set up GPMC mappings ourselves.  */
+static void n800_gpmc_init(struct n800_s *s)
+{
+    uint32_t config7 =
+            (0xf << 8) |	/* MASKADDRESS */
+            (1 << 6) |		/* CSVALID */
+            (4 << 0);		/* BASEADDRESS */
+
+    cpu_physical_memory_write(0x6800a078,		/* GPMC_CONFIG7_0 */
+                    (void *) &config7, sizeof(config7));
+}
+
+/* Setup sequence done by the bootloader */
+static void n8x0_boot_init(void *opaque)
+{
+    struct n800_s *s = (struct n800_s *) opaque;
+    uint32_t buf;
+
+    /* PRCM setup */
+#define omap_writel(addr, val)	\
+    buf = (val);			\
+    cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf))
+
+    omap_writel(0x48008060, 0x41);		/* PRCM_CLKSRC_CTRL */
+    omap_writel(0x48008070, 1);			/* PRCM_CLKOUT_CTRL */
+    omap_writel(0x48008078, 0);			/* PRCM_CLKEMUL_CTRL */
+    omap_writel(0x48008090, 0);			/* PRCM_VOLTSETUP */
+    omap_writel(0x48008094, 0);			/* PRCM_CLKSSETUP */
+    omap_writel(0x48008098, 0);			/* PRCM_POLCTRL */
+    omap_writel(0x48008140, 2);			/* CM_CLKSEL_MPU */
+    omap_writel(0x48008148, 0);			/* CM_CLKSTCTRL_MPU */
+    omap_writel(0x48008158, 1);			/* RM_RSTST_MPU */
+    omap_writel(0x480081c8, 0x15);		/* PM_WKDEP_MPU */
+    omap_writel(0x480081d4, 0x1d4);		/* PM_EVGENCTRL_MPU */
+    omap_writel(0x480081d8, 0);			/* PM_EVEGENONTIM_MPU */
+    omap_writel(0x480081dc, 0);			/* PM_EVEGENOFFTIM_MPU */
+    omap_writel(0x480081e0, 0xc);		/* PM_PWSTCTRL_MPU */
+    omap_writel(0x48008200, 0x047e7ff7);	/* CM_FCLKEN1_CORE */
+    omap_writel(0x48008204, 0x00000004);	/* CM_FCLKEN2_CORE */
+    omap_writel(0x48008210, 0x047e7ff1);	/* CM_ICLKEN1_CORE */
+    omap_writel(0x48008214, 0x00000004);	/* CM_ICLKEN2_CORE */
+    omap_writel(0x4800821c, 0x00000000);	/* CM_ICLKEN4_CORE */
+    omap_writel(0x48008230, 0);			/* CM_AUTOIDLE1_CORE */
+    omap_writel(0x48008234, 0);			/* CM_AUTOIDLE2_CORE */
+    omap_writel(0x48008238, 7);			/* CM_AUTOIDLE3_CORE */
+    omap_writel(0x4800823c, 0);			/* CM_AUTOIDLE4_CORE */
+    omap_writel(0x48008240, 0x04360626);	/* CM_CLKSEL1_CORE */
+    omap_writel(0x48008244, 0x00000014);	/* CM_CLKSEL2_CORE */
+    omap_writel(0x48008248, 0);			/* CM_CLKSTCTRL_CORE */
+    omap_writel(0x48008300, 0x00000000);	/* CM_FCLKEN_GFX */
+    omap_writel(0x48008310, 0x00000000);	/* CM_ICLKEN_GFX */
+    omap_writel(0x48008340, 0x00000001);	/* CM_CLKSEL_GFX */
+    omap_writel(0x48008400, 0x00000004);	/* CM_FCLKEN_WKUP */
+    omap_writel(0x48008410, 0x00000004);	/* CM_ICLKEN_WKUP */
+    omap_writel(0x48008440, 0x00000000);	/* CM_CLKSEL_WKUP */
+    omap_writel(0x48008500, 0x000000cf);	/* CM_CLKEN_PLL */
+    omap_writel(0x48008530, 0x0000000c);	/* CM_AUTOIDLE_PLL */
+    omap_writel(0x48008540,			/* CM_CLKSEL1_PLL */
+                    (0x78 << 12) | (6 << 8));
+    omap_writel(0x48008544, 2);			/* CM_CLKSEL2_PLL */
+
+    /* GPMC setup */
+    n800_gpmc_init(s);
+
+    /* Video setup */
+    n800_dss_init(&s->blizzard);
+
+    /* CPU setup */
+    s->cpu->env->GE = 0x5;
+
+    /* If the machine has a slided keyboard, open it */
+    if (s->kbd)
+        qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]);
+}
+
+#define OMAP_TAG_NOKIA_BT	0x4e01
+#define OMAP_TAG_WLAN_CX3110X	0x4e02
+#define OMAP_TAG_CBUS		0x4e03
+#define OMAP_TAG_EM_ASIC_BB5	0x4e04
+
+static struct omap_gpiosw_info_s {
+    const char *name;
+    int line;
+    int type;
+} n800_gpiosw_info[] = {
+    {
+        "bat_cover", N800_BAT_COVER_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    }, {
+        "cam_act", N800_CAM_ACT_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY,
+    }, {
+        "cam_turn", N800_CAM_TURN_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
+    }, {
+        "headphone", N8X0_HEADPHONE_GPIO,
+        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
+    },
+    { NULL }
+}, n810_gpiosw_info[] = {
+    {
+        "gps_reset", N810_GPS_RESET_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "gps_wakeup", N810_GPS_WAKEUP_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "headphone", N8X0_HEADPHONE_GPIO,
+        OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
+    }, {
+        "kb_lock", N810_KB_LOCK_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    }, {
+        "sleepx_led", N810_SLEEPX_LED_GPIO,
+        OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
+    }, {
+        "slide", N810_SLIDE_GPIO,
+        OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
+    },
+    { NULL }
+};
+
+static struct omap_partition_info_s {
+    uint32_t offset;
+    uint32_t size;
+    int mask;
+    const char *name;
+} n800_part_info[] = {
+    { 0x00000000, 0x00020000, 0x3, "bootloader" },
+    { 0x00020000, 0x00060000, 0x0, "config" },
+    { 0x00080000, 0x00200000, 0x0, "kernel" },
+    { 0x00280000, 0x00200000, 0x3, "initfs" },
+    { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
+
+    { 0, 0, 0, NULL }
+}, n810_part_info[] = {
+    { 0x00000000, 0x00020000, 0x3, "bootloader" },
+    { 0x00020000, 0x00060000, 0x0, "config" },
+    { 0x00080000, 0x00220000, 0x0, "kernel" },
+    { 0x002a0000, 0x00400000, 0x0, "initfs" },
+    { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
+
+    { 0, 0, 0, NULL }
+};
+
+static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }};
+
+static int n8x0_atag_setup(void *p, int model)
+{
+    uint8_t *b;
+    uint16_t *w;
+    uint32_t *l;
+    struct omap_gpiosw_info_s *gpiosw;
+    struct omap_partition_info_s *partition;
+    const char *tag;
+
+    w = p;
+
+    stw_raw(w ++, OMAP_TAG_UART);		/* u16 tag */
+    stw_raw(w ++, 4);				/* u16 len */
+    stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
+    w ++;
+
+#if 0
+    stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE);	/* u16 tag */
+    stw_raw(w ++, 4);				/* u16 len */
+    stw_raw(w ++, XLDR_LL_UART + 1);		/* u8 console_uart */
+    stw_raw(w ++, 115200);			/* u32 console_speed */
+#endif
+
+    stw_raw(w ++, OMAP_TAG_LCD);		/* u16 tag */
+    stw_raw(w ++, 36);				/* u16 len */
+    strcpy((void *) w, "QEMU LCD panel");	/* char panel_name[16] */
+    w += 8;
+    strcpy((void *) w, "blizzard");		/* char ctrl_name[16] */
+    w += 8;
+    stw_raw(w ++, N810_BLIZZARD_RESET_GPIO);	/* TODO: n800 s16 nreset_gpio */
+    stw_raw(w ++, 24);				/* u8 data_lines */
+
+    stw_raw(w ++, OMAP_TAG_CBUS);		/* u16 tag */
+    stw_raw(w ++, 8);				/* u16 len */
+    stw_raw(w ++, N8X0_CBUS_CLK_GPIO);		/* s16 clk_gpio */
+    stw_raw(w ++, N8X0_CBUS_DAT_GPIO);		/* s16 dat_gpio */
+    stw_raw(w ++, N8X0_CBUS_SEL_GPIO);		/* s16 sel_gpio */
+    w ++;
+
+    stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5);	/* u16 tag */
+    stw_raw(w ++, 4);				/* u16 len */
+    stw_raw(w ++, N8X0_RETU_GPIO);		/* s16 retu_irq_gpio */
+    stw_raw(w ++, N8X0_TAHVO_GPIO);		/* s16 tahvo_irq_gpio */
+
+    gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
+    for (; gpiosw->name; gpiosw ++) {
+        stw_raw(w ++, OMAP_TAG_GPIO_SWITCH);	/* u16 tag */
+        stw_raw(w ++, 20);			/* u16 len */
+        strcpy((void *) w, gpiosw->name);	/* char name[12] */
+        w += 6;
+        stw_raw(w ++, gpiosw->line);		/* u16 gpio */
+        stw_raw(w ++, gpiosw->type);
+        stw_raw(w ++, 0);
+        stw_raw(w ++, 0);
+    }
+
+    stw_raw(w ++, OMAP_TAG_NOKIA_BT);		/* u16 tag */
+    stw_raw(w ++, 12);				/* u16 len */
+    b = (void *) w;
+    stb_raw(b ++, 0x01);			/* u8 chip_type	(CSR) */
+    stb_raw(b ++, N8X0_BT_WKUP_GPIO);		/* u8 bt_wakeup_gpio */
+    stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO);	/* u8 host_wakeup_gpio */
+    stb_raw(b ++, N8X0_BT_RESET_GPIO);		/* u8 reset_gpio */
+    stb_raw(b ++, BT_UART + 1);			/* u8 bt_uart */
+    memcpy(b, &n8x0_bd_addr, 6);		/* u8 bd_addr[6] */
+    b += 6;
+    stb_raw(b ++, 0x02);			/* u8 bt_sysclk (38.4) */
+    w = (void *) b;
+
+    stw_raw(w ++, OMAP_TAG_WLAN_CX3110X);	/* u16 tag */
+    stw_raw(w ++, 8);				/* u16 len */
+    stw_raw(w ++, 0x25);			/* u8 chip_type */
+    stw_raw(w ++, N8X0_WLAN_PWR_GPIO);		/* s16 power_gpio */
+    stw_raw(w ++, N8X0_WLAN_IRQ_GPIO);		/* s16 irq_gpio */
+    stw_raw(w ++, -1);				/* s16 spi_cs_gpio */
+
+    stw_raw(w ++, OMAP_TAG_MMC);		/* u16 tag */
+    stw_raw(w ++, 16);				/* u16 len */
+    if (model == 810) {
+        stw_raw(w ++, 0x23f);			/* unsigned flags */
+        stw_raw(w ++, -1);			/* s16 power_pin */
+        stw_raw(w ++, -1);			/* s16 switch_pin */
+        stw_raw(w ++, -1);			/* s16 wp_pin */
+        stw_raw(w ++, 0x240);			/* unsigned flags */
+        stw_raw(w ++, 0xc000);			/* s16 power_pin */
+        stw_raw(w ++, 0x0248);			/* s16 switch_pin */
+        stw_raw(w ++, 0xc000);			/* s16 wp_pin */
+    } else {
+        stw_raw(w ++, 0xf);			/* unsigned flags */
+        stw_raw(w ++, -1);			/* s16 power_pin */
+        stw_raw(w ++, -1);			/* s16 switch_pin */
+        stw_raw(w ++, -1);			/* s16 wp_pin */
+        stw_raw(w ++, 0);			/* unsigned flags */
+        stw_raw(w ++, 0);			/* s16 power_pin */
+        stw_raw(w ++, 0);			/* s16 switch_pin */
+        stw_raw(w ++, 0);			/* s16 wp_pin */
+    }
+
+    stw_raw(w ++, OMAP_TAG_TEA5761);		/* u16 tag */
+    stw_raw(w ++, 4);				/* u16 len */
+    stw_raw(w ++, N8X0_TEA5761_CS_GPIO);	/* u16 enable_gpio */
+    w ++;
+
+    partition = (model == 810) ? n810_part_info : n800_part_info;
+    for (; partition->name; partition ++) {
+        stw_raw(w ++, OMAP_TAG_PARTITION);	/* u16 tag */
+        stw_raw(w ++, 28);			/* u16 len */
+        strcpy((void *) w, partition->name);	/* char name[16] */
+        l = (void *) (w + 8);
+        stl_raw(l ++, partition->size);		/* unsigned int size */
+        stl_raw(l ++, partition->offset);	/* unsigned int offset */
+        stl_raw(l ++, partition->mask);		/* unsigned int mask_flags */
+        w = (void *) l;
+    }
+
+    stw_raw(w ++, OMAP_TAG_BOOT_REASON);	/* u16 tag */
+    stw_raw(w ++, 12);				/* u16 len */
+#if 0
+    strcpy((void *) w, "por");			/* char reason_str[12] */
+    strcpy((void *) w, "charger");		/* char reason_str[12] */
+    strcpy((void *) w, "32wd_to");		/* char reason_str[12] */
+    strcpy((void *) w, "sw_rst");		/* char reason_str[12] */
+    strcpy((void *) w, "mbus");			/* char reason_str[12] */
+    strcpy((void *) w, "unknown");		/* char reason_str[12] */
+    strcpy((void *) w, "swdg_to");		/* char reason_str[12] */
+    strcpy((void *) w, "sec_vio");		/* char reason_str[12] */
+    strcpy((void *) w, "pwr_key");		/* char reason_str[12] */
+    strcpy((void *) w, "rtc_alarm");		/* char reason_str[12] */
+#else
+    strcpy((void *) w, "pwr_key");		/* char reason_str[12] */
+#endif
+    w += 6;
+
+    tag = (model == 810) ? "RX-44" : "RX-34";
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */
+    stw_raw(w ++, 24);				/* u16 len */
+    strcpy((void *) w, "product");		/* char component[12] */
+    w += 6;
+    strcpy((void *) w, tag);			/* char version[12] */
+    w += 6;
+
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */
+    stw_raw(w ++, 24);				/* u16 len */
+    strcpy((void *) w, "hw-build");		/* char component[12] */
+    w += 6;
+    strcpy((void *) w, "QEMU " QEMU_VERSION);	/* char version[12] */
+    w += 6;
+
+    tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
+    stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */
+    stw_raw(w ++, 24);				/* u16 len */
+    strcpy((void *) w, "nolo");			/* char component[12] */
+    w += 6;
+    strcpy((void *) w, tag);			/* char version[12] */
+    w += 6;
+
+    return (void *) w - p;
+}
+
+static int n800_atag_setup(const struct arm_boot_info *info, void *p)
+{
+    return n8x0_atag_setup(p, 800);
+}
+
+static int n810_atag_setup(const struct arm_boot_info *info, void *p)
+{
+    return n8x0_atag_setup(p, 810);
+}
+
+static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
+                const char *kernel_filename,
+                const char *kernel_cmdline, const char *initrd_filename,
+                const char *cpu_model, struct arm_boot_info *binfo, int model)
+{
+    struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s));
+    int sdram_size = binfo->ram_size;
+    DisplayState *ds;
+
+    s->cpu = omap2420_mpu_init(sdram_size, cpu_model);
+
+    /* Setup peripherals
+     *
+     * Believed external peripherals layout in the N810:
+     * (spi bus 1)
+     *   tsc2005
+     *   lcd_mipid
+     * (spi bus 2)
+     *   Conexant cx3110x (WLAN)
+     *   optional: pc2400m (WiMAX)
+     * (i2c bus 0)
+     *   TLV320AIC33 (audio codec)
+     *   TCM825x (camera by Toshiba)
+     *   lp5521 (clever LEDs)
+     *   tsl2563 (light sensor, hwmon, model 7, rev. 0)
+     *   lm8323 (keypad, manf 00, rev 04)
+     * (i2c bus 1)
+     *   tmp105 (temperature sensor, hwmon)
+     *   menelaus (pm)
+     * (somewhere on i2c - maybe N800-only)
+     *   tea5761 (FM tuner)
+     * (serial 0)
+     *   GPS
+     * (some serial port)
+     *   csr41814 (Bluetooth)
+     */
+    n8x0_gpio_setup(s);
+    n8x0_nand_setup(s);
+    n8x0_i2c_setup(s);
+    if (model == 800)
+        n800_tsc_kbd_setup(s);
+    else if (model == 810) {
+        n810_tsc_setup(s);
+        n810_kbd_setup(s);
+    }
+    n8x0_spi_setup(s);
+    n8x0_dss_setup(s);
+    n8x0_cbus_setup(s);
+    n8x0_uart_setup(s);
+    if (usb_enabled)
+        n8x0_usb_setup(s);
+
+    if (kernel_filename) {
+        /* Or at the linux loader.  */
+        binfo->kernel_filename = kernel_filename;
+        binfo->kernel_cmdline = kernel_cmdline;
+        binfo->initrd_filename = initrd_filename;
+        arm_load_kernel(s->cpu->env, binfo);
+
+        qemu_register_reset(n8x0_boot_init, s);
+    }
+
+    if (option_rom[0].name && (boot_device[0] == 'n' || !kernel_filename)) {
+        int rom_size;
+        uint8_t nolo_tags[0x10000];
+        /* No, wait, better start at the ROM.  */
+        s->cpu->env->regs[15] = OMAP2_Q2_BASE + 0x400000;
+
+        /* This is intended for loading the `secondary.bin' program from
+         * Nokia images (the NOLO bootloader).  The entry point seems
+         * to be at OMAP2_Q2_BASE + 0x400000.
+         *
+         * The `2nd.bin' files contain some kind of earlier boot code and
+         * for them the entry point needs to be set to OMAP2_SRAM_BASE.
+         *
+         * The code above is for loading the `zImage' file from Nokia
+         * images.  */
+        rom_size = load_image_targphys(option_rom[0].name,
+                                       OMAP2_Q2_BASE + 0x400000,
+                                       sdram_size - 0x400000);
+        printf("%i bytes of image loaded\n", rom_size);
+
+        n800_setup_nolo_tags(nolo_tags);
+        cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
+    }
+    /* FIXME: We shouldn't really be doing this here.  The LCD controller
+       will set the size once configured, so this just sets an initial
+       size until the guest activates the display.  */
+    ds = get_displaystate();
+    ds->surface = qemu_resize_displaysurface(ds, 800, 480);
+    dpy_resize(ds);
+}
+
+static struct arm_boot_info n800_binfo = {
+    .loader_start = OMAP2_Q2_BASE,
+    /* Actually two chips of 0x4000000 bytes each */
+    .ram_size = 0x08000000,
+    .board_id = 0x4f7,
+    .atag_board = n800_atag_setup,
+};
+
+static struct arm_boot_info n810_binfo = {
+    .loader_start = OMAP2_Q2_BASE,
+    /* Actually two chips of 0x4000000 bytes each */
+    .ram_size = 0x08000000,
+    /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
+     * used by some older versions of the bootloader and 5555 is used
+     * instead (including versions that shipped with many devices).  */
+    .board_id = 0x60c,
+    .atag_board = n810_atag_setup,
+};
+
+static void n800_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    return n8x0_init(ram_size, boot_device,
+                    kernel_filename, kernel_cmdline, initrd_filename,
+                    cpu_model, &n800_binfo, 800);
+}
+
+static void n810_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    return n8x0_init(ram_size, boot_device,
+                    kernel_filename, kernel_cmdline, initrd_filename,
+                    cpu_model, &n810_binfo, 810);
+}
+
+static QEMUMachine n800_machine = {
+    .name = "n800",
+    .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)",
+    .init = n800_init,
+};
+
+static QEMUMachine n810_machine = {
+    .name = "n810",
+    .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)",
+    .init = n810_init,
+};
+
+static void nseries_machine_init(void)
+{
+    qemu_register_machine(&n800_machine);
+    qemu_register_machine(&n810_machine);
+}
+
+machine_init(nseries_machine_init);
diff --git a/qemu-0.15.x/hw/nvram.h b/qemu-0.15.x/hw/nvram.h
new file mode 100644
index 0000000..0f55b24
--- /dev/null
+++ b/qemu-0.15.x/hw/nvram.h
@@ -0,0 +1,42 @@
+#ifndef NVRAM_H
+#define NVRAM_H
+
+/* NVRAM helpers */
+typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr);
+typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val);
+typedef struct nvram_t {
+    void *opaque;
+    nvram_read_t read_fn;
+    nvram_write_t write_fn;
+} nvram_t;
+
+void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value);
+uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr);
+void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value);
+uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr);
+void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value);
+uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
+void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
+                       const char *str, uint32_t max);
+int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
+void NVRAM_set_crc (nvram_t *nvram, uint32_t addr,
+                    uint32_t start, uint32_t count);
+int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
+                          const char *arch,
+                          uint32_t RAM_size, int boot_device,
+                          uint32_t kernel_image, uint32_t kernel_size,
+                          const char *cmdline,
+                          uint32_t initrd_image, uint32_t initrd_size,
+                          uint32_t NVRAM_image,
+                          int width, int height, int depth);
+typedef struct M48t59State M48t59State;
+
+void m48t59_write (void *private, uint32_t addr, uint32_t val);
+uint32_t m48t59_read (void *private, uint32_t addr);
+void m48t59_toggle_lock (void *private, int lock);
+M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type);
+M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
+                         uint32_t io_base, uint16_t size, int type);
+void m48t59_set_addr (void *opaque, uint32_t addr);
+
+#endif /* !NVRAM_H */
diff --git a/qemu-0.15.x/hw/omap.h b/qemu-0.15.x/hw/omap.h
new file mode 100644
index 0000000..c227a82
--- /dev/null
+++ b/qemu-0.15.x/hw/omap.h
@@ -0,0 +1,1141 @@
+/*
+ * Texas Instruments OMAP processors.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef hw_omap_h
+# define hw_omap_h		"omap.h"
+
+# define OMAP_EMIFS_BASE	0x00000000
+# define OMAP2_Q0_BASE		0x00000000
+# define OMAP_CS0_BASE		0x00000000
+# define OMAP_CS1_BASE		0x04000000
+# define OMAP_CS2_BASE		0x08000000
+# define OMAP_CS3_BASE		0x0c000000
+# define OMAP_EMIFF_BASE	0x10000000
+# define OMAP_IMIF_BASE		0x20000000
+# define OMAP_LOCALBUS_BASE	0x30000000
+# define OMAP2_Q1_BASE		0x40000000
+# define OMAP2_L4_BASE		0x48000000
+# define OMAP2_SRAM_BASE	0x40200000
+# define OMAP2_L3_BASE		0x68000000
+# define OMAP2_Q2_BASE		0x80000000
+# define OMAP2_Q3_BASE		0xc0000000
+# define OMAP_MPUI_BASE		0xe1000000
+
+# define OMAP730_SRAM_SIZE	0x00032000
+# define OMAP15XX_SRAM_SIZE	0x00030000
+# define OMAP16XX_SRAM_SIZE	0x00004000
+# define OMAP1611_SRAM_SIZE	0x0003e800
+# define OMAP242X_SRAM_SIZE	0x000a0000
+# define OMAP243X_SRAM_SIZE	0x00010000
+# define OMAP_CS0_SIZE		0x04000000
+# define OMAP_CS1_SIZE		0x04000000
+# define OMAP_CS2_SIZE		0x04000000
+# define OMAP_CS3_SIZE		0x04000000
+
+/* omap_clk.c */
+struct omap_mpu_state_s;
+typedef struct clk *omap_clk;
+omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name);
+void omap_clk_init(struct omap_mpu_state_s *mpu);
+void omap_clk_adduser(struct clk *clk, qemu_irq user);
+void omap_clk_get(omap_clk clk);
+void omap_clk_put(omap_clk clk);
+void omap_clk_onoff(omap_clk clk, int on);
+void omap_clk_canidle(omap_clk clk, int can);
+void omap_clk_setrate(omap_clk clk, int divide, int multiply);
+int64_t omap_clk_getrate(omap_clk clk);
+void omap_clk_reparent(omap_clk clk, omap_clk parent);
+
+/* OMAP2 l4 Interconnect */
+struct omap_l4_s;
+struct omap_l4_region_s {
+    target_phys_addr_t offset;
+    size_t size;
+    int access;
+};
+struct omap_l4_agent_info_s {
+    int ta;
+    int region;
+    int regions;
+    int ta_region;
+};
+struct omap_target_agent_s {
+    struct omap_l4_s *bus;
+    int regions;
+    const struct omap_l4_region_s *start;
+    target_phys_addr_t base;
+    uint32_t component;
+    uint32_t control;
+    uint32_t status;
+};
+struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num);
+
+struct omap_target_agent_s;
+struct omap_target_agent_s *omap_l4ta_get(
+    struct omap_l4_s *bus,
+    const struct omap_l4_region_s *regions,
+    const struct omap_l4_agent_info_s *agents,
+    int cs);
+target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
+                int iotype);
+int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                CPUWriteMemoryFunc * const *mem_write, void *opaque);
+
+/* OMAP interrupt controller */
+struct omap_intr_handler_s;
+struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
+                unsigned long size, unsigned char nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
+struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+                int size, int nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq,
+                omap_clk fclk, omap_clk iclk);
+void omap_inth_reset(struct omap_intr_handler_s *s);
+qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n);
+
+/* OMAP2 SDRAM controller */
+struct omap_sdrc_s;
+struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
+void omap_sdrc_reset(struct omap_sdrc_s *s);
+
+/* OMAP2 general purpose memory controller */
+struct omap_gpmc_s;
+struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq);
+void omap_gpmc_reset(struct omap_gpmc_s *s);
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
+                void (*base_upd)(void *opaque, target_phys_addr_t new),
+                void (*unmap)(void *opaque), void *opaque);
+
+/*
+ * Common IRQ numbers for level 1 interrupt handler
+ * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
+ */
+# define OMAP_INT_CAMERA		1
+# define OMAP_INT_FIQ			3
+# define OMAP_INT_RTDX			6
+# define OMAP_INT_DSP_MMU_ABORT		7
+# define OMAP_INT_HOST			8
+# define OMAP_INT_ABORT			9
+# define OMAP_INT_BRIDGE_PRIV		13
+# define OMAP_INT_GPIO_BANK1		14
+# define OMAP_INT_UART3			15
+# define OMAP_INT_TIMER3		16
+# define OMAP_INT_DMA_CH0_6		19
+# define OMAP_INT_DMA_CH1_7		20
+# define OMAP_INT_DMA_CH2_8		21
+# define OMAP_INT_DMA_CH3		22
+# define OMAP_INT_DMA_CH4		23
+# define OMAP_INT_DMA_CH5		24
+# define OMAP_INT_DMA_LCD		25
+# define OMAP_INT_TIMER1		26
+# define OMAP_INT_WD_TIMER		27
+# define OMAP_INT_BRIDGE_PUB		28
+# define OMAP_INT_TIMER2		30
+# define OMAP_INT_LCD_CTRL		31
+
+/*
+ * Common OMAP-15xx IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_15XX_IH2_IRQ		0
+# define OMAP_INT_15XX_LB_MMU		17
+# define OMAP_INT_15XX_LOCAL_BUS	29
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1510_SPI_TX		4
+# define OMAP_INT_1510_SPI_RX		5
+# define OMAP_INT_1510_DSP_MAILBOX1	10
+# define OMAP_INT_1510_DSP_MAILBOX2	11
+
+/*
+ * OMAP-310 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_310_McBSP2_TX		4
+# define OMAP_INT_310_McBSP2_RX		5
+# define OMAP_INT_310_HSB_MAILBOX1	12
+# define OMAP_INT_310_HSAB_MMU		18
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1610_IH2_IRQ		0
+# define OMAP_INT_1610_IH2_FIQ		2
+# define OMAP_INT_1610_McBSP2_TX	4
+# define OMAP_INT_1610_McBSP2_RX	5
+# define OMAP_INT_1610_DSP_MAILBOX1	10
+# define OMAP_INT_1610_DSP_MAILBOX2	11
+# define OMAP_INT_1610_LCD_LINE		12
+# define OMAP_INT_1610_GPTIMER1		17
+# define OMAP_INT_1610_GPTIMER2		18
+# define OMAP_INT_1610_SSR_FIFO_0	29
+
+/*
+ * OMAP-730 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_730_IH2_FIQ		0
+# define OMAP_INT_730_IH2_IRQ		1
+# define OMAP_INT_730_USB_NON_ISO	2
+# define OMAP_INT_730_USB_ISO		3
+# define OMAP_INT_730_ICR		4
+# define OMAP_INT_730_EAC		5
+# define OMAP_INT_730_GPIO_BANK1	6
+# define OMAP_INT_730_GPIO_BANK2	7
+# define OMAP_INT_730_GPIO_BANK3	8
+# define OMAP_INT_730_McBSP2TX		10
+# define OMAP_INT_730_McBSP2RX		11
+# define OMAP_INT_730_McBSP2RX_OVF	12
+# define OMAP_INT_730_LCD_LINE		14
+# define OMAP_INT_730_GSM_PROTECT	15
+# define OMAP_INT_730_TIMER3		16
+# define OMAP_INT_730_GPIO_BANK5	17
+# define OMAP_INT_730_GPIO_BANK6	18
+# define OMAP_INT_730_SPGIO_WR		29
+
+/*
+ * Common IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_KEYBOARD		1
+# define OMAP_INT_uWireTX		2
+# define OMAP_INT_uWireRX		3
+# define OMAP_INT_I2C			4
+# define OMAP_INT_MPUIO			5
+# define OMAP_INT_USB_HHC_1		6
+# define OMAP_INT_McBSP3TX		10
+# define OMAP_INT_McBSP3RX		11
+# define OMAP_INT_McBSP1TX		12
+# define OMAP_INT_McBSP1RX		13
+# define OMAP_INT_UART1			14
+# define OMAP_INT_UART2			15
+# define OMAP_INT_USB_W2FC		20
+# define OMAP_INT_1WIRE			21
+# define OMAP_INT_OS_TIMER		22
+# define OMAP_INT_OQN			23
+# define OMAP_INT_GAUGE_32K		24
+# define OMAP_INT_RTC_TIMER		25
+# define OMAP_INT_RTC_ALARM		26
+# define OMAP_INT_DSP_MMU		28
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1510_BT_MCSI1TX	16
+# define OMAP_INT_1510_BT_MCSI1RX	17
+# define OMAP_INT_1510_SoSSI_MATCH	19
+# define OMAP_INT_1510_MEM_STICK	27
+# define OMAP_INT_1510_COM_SPI_RO	31
+
+/*
+ * OMAP-310 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_310_FAC		0
+# define OMAP_INT_310_USB_HHC_2		7
+# define OMAP_INT_310_MCSI1_FE		16
+# define OMAP_INT_310_MCSI2_FE		17
+# define OMAP_INT_310_USB_W2FC_ISO	29
+# define OMAP_INT_310_USB_W2FC_NON_ISO	30
+# define OMAP_INT_310_McBSP2RX_OF	31
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1610_FAC		0
+# define OMAP_INT_1610_USB_HHC_2	7
+# define OMAP_INT_1610_USB_OTG		8
+# define OMAP_INT_1610_SoSSI		9
+# define OMAP_INT_1610_BT_MCSI1TX	16
+# define OMAP_INT_1610_BT_MCSI1RX	17
+# define OMAP_INT_1610_SoSSI_MATCH	19
+# define OMAP_INT_1610_MEM_STICK	27
+# define OMAP_INT_1610_McBSP2RX_OF	31
+# define OMAP_INT_1610_STI		32
+# define OMAP_INT_1610_STI_WAKEUP	33
+# define OMAP_INT_1610_GPTIMER3		34
+# define OMAP_INT_1610_GPTIMER4		35
+# define OMAP_INT_1610_GPTIMER5		36
+# define OMAP_INT_1610_GPTIMER6		37
+# define OMAP_INT_1610_GPTIMER7		38
+# define OMAP_INT_1610_GPTIMER8		39
+# define OMAP_INT_1610_GPIO_BANK2	40
+# define OMAP_INT_1610_GPIO_BANK3	41
+# define OMAP_INT_1610_MMC2		42
+# define OMAP_INT_1610_CF		43
+# define OMAP_INT_1610_WAKE_UP_REQ	46
+# define OMAP_INT_1610_GPIO_BANK4	48
+# define OMAP_INT_1610_SPI		49
+# define OMAP_INT_1610_DMA_CH6		53
+# define OMAP_INT_1610_DMA_CH7		54
+# define OMAP_INT_1610_DMA_CH8		55
+# define OMAP_INT_1610_DMA_CH9		56
+# define OMAP_INT_1610_DMA_CH10		57
+# define OMAP_INT_1610_DMA_CH11		58
+# define OMAP_INT_1610_DMA_CH12		59
+# define OMAP_INT_1610_DMA_CH13		60
+# define OMAP_INT_1610_DMA_CH14		61
+# define OMAP_INT_1610_DMA_CH15		62
+# define OMAP_INT_1610_NAND		63
+
+/*
+ * OMAP-730 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_730_HW_ERRORS		0
+# define OMAP_INT_730_NFIQ_PWR_FAIL	1
+# define OMAP_INT_730_CFCD		2
+# define OMAP_INT_730_CFIREQ		3
+# define OMAP_INT_730_I2C		4
+# define OMAP_INT_730_PCC		5
+# define OMAP_INT_730_MPU_EXT_NIRQ	6
+# define OMAP_INT_730_SPI_100K_1	7
+# define OMAP_INT_730_SYREN_SPI		8
+# define OMAP_INT_730_VLYNQ		9
+# define OMAP_INT_730_GPIO_BANK4	10
+# define OMAP_INT_730_McBSP1TX		11
+# define OMAP_INT_730_McBSP1RX		12
+# define OMAP_INT_730_McBSP1RX_OF	13
+# define OMAP_INT_730_UART_MODEM_IRDA_2	14
+# define OMAP_INT_730_UART_MODEM_1	15
+# define OMAP_INT_730_MCSI		16
+# define OMAP_INT_730_uWireTX		17
+# define OMAP_INT_730_uWireRX		18
+# define OMAP_INT_730_SMC_CD		19
+# define OMAP_INT_730_SMC_IREQ		20
+# define OMAP_INT_730_HDQ_1WIRE		21
+# define OMAP_INT_730_TIMER32K		22
+# define OMAP_INT_730_MMC_SDIO		23
+# define OMAP_INT_730_UPLD		24
+# define OMAP_INT_730_USB_HHC_1		27
+# define OMAP_INT_730_USB_HHC_2		28
+# define OMAP_INT_730_USB_GENI		29
+# define OMAP_INT_730_USB_OTG		30
+# define OMAP_INT_730_CAMERA_IF		31
+# define OMAP_INT_730_RNG		32
+# define OMAP_INT_730_DUAL_MODE_TIMER	33
+# define OMAP_INT_730_DBB_RF_EN		34
+# define OMAP_INT_730_MPUIO_KEYPAD	35
+# define OMAP_INT_730_SHA1_MD5		36
+# define OMAP_INT_730_SPI_100K_2	37
+# define OMAP_INT_730_RNG_IDLE		38
+# define OMAP_INT_730_MPUIO		39
+# define OMAP_INT_730_LLPC_LCD_CTRL_OFF	40
+# define OMAP_INT_730_LLPC_OE_FALLING	41
+# define OMAP_INT_730_LLPC_OE_RISING	42
+# define OMAP_INT_730_LLPC_VSYNC	43
+# define OMAP_INT_730_WAKE_UP_REQ	46
+# define OMAP_INT_730_DMA_CH6		53
+# define OMAP_INT_730_DMA_CH7		54
+# define OMAP_INT_730_DMA_CH8		55
+# define OMAP_INT_730_DMA_CH9		56
+# define OMAP_INT_730_DMA_CH10		57
+# define OMAP_INT_730_DMA_CH11		58
+# define OMAP_INT_730_DMA_CH12		59
+# define OMAP_INT_730_DMA_CH13		60
+# define OMAP_INT_730_DMA_CH14		61
+# define OMAP_INT_730_DMA_CH15		62
+# define OMAP_INT_730_NAND		63
+
+/*
+ * OMAP-24xx common IRQ numbers
+ */
+# define OMAP_INT_24XX_STI		4
+# define OMAP_INT_24XX_SYS_NIRQ		7
+# define OMAP_INT_24XX_L3_IRQ		10
+# define OMAP_INT_24XX_PRCM_MPU_IRQ	11
+# define OMAP_INT_24XX_SDMA_IRQ0	12
+# define OMAP_INT_24XX_SDMA_IRQ1	13
+# define OMAP_INT_24XX_SDMA_IRQ2	14
+# define OMAP_INT_24XX_SDMA_IRQ3	15
+# define OMAP_INT_243X_MCBSP2_IRQ	16
+# define OMAP_INT_243X_MCBSP3_IRQ	17
+# define OMAP_INT_243X_MCBSP4_IRQ	18
+# define OMAP_INT_243X_MCBSP5_IRQ	19
+# define OMAP_INT_24XX_GPMC_IRQ		20
+# define OMAP_INT_24XX_GUFFAW_IRQ	21
+# define OMAP_INT_24XX_IVA_IRQ		22
+# define OMAP_INT_24XX_EAC_IRQ		23
+# define OMAP_INT_24XX_CAM_IRQ		24
+# define OMAP_INT_24XX_DSS_IRQ		25
+# define OMAP_INT_24XX_MAIL_U0_MPU	26
+# define OMAP_INT_24XX_DSP_UMA		27
+# define OMAP_INT_24XX_DSP_MMU		28
+# define OMAP_INT_24XX_GPIO_BANK1	29
+# define OMAP_INT_24XX_GPIO_BANK2	30
+# define OMAP_INT_24XX_GPIO_BANK3	31
+# define OMAP_INT_24XX_GPIO_BANK4	32
+# define OMAP_INT_243X_GPIO_BANK5	33
+# define OMAP_INT_24XX_MAIL_U3_MPU	34
+# define OMAP_INT_24XX_WDT3		35
+# define OMAP_INT_24XX_WDT4		36
+# define OMAP_INT_24XX_GPTIMER1		37
+# define OMAP_INT_24XX_GPTIMER2		38
+# define OMAP_INT_24XX_GPTIMER3		39
+# define OMAP_INT_24XX_GPTIMER4		40
+# define OMAP_INT_24XX_GPTIMER5		41
+# define OMAP_INT_24XX_GPTIMER6		42
+# define OMAP_INT_24XX_GPTIMER7		43
+# define OMAP_INT_24XX_GPTIMER8		44
+# define OMAP_INT_24XX_GPTIMER9		45
+# define OMAP_INT_24XX_GPTIMER10	46
+# define OMAP_INT_24XX_GPTIMER11	47
+# define OMAP_INT_24XX_GPTIMER12	48
+# define OMAP_INT_24XX_PKA_IRQ		50
+# define OMAP_INT_24XX_SHA1MD5_IRQ	51
+# define OMAP_INT_24XX_RNG_IRQ		52
+# define OMAP_INT_24XX_MG_IRQ		53
+# define OMAP_INT_24XX_I2C1_IRQ		56
+# define OMAP_INT_24XX_I2C2_IRQ		57
+# define OMAP_INT_24XX_MCBSP1_IRQ_TX	59
+# define OMAP_INT_24XX_MCBSP1_IRQ_RX	60
+# define OMAP_INT_24XX_MCBSP2_IRQ_TX	62
+# define OMAP_INT_24XX_MCBSP2_IRQ_RX	63
+# define OMAP_INT_243X_MCBSP1_IRQ	64
+# define OMAP_INT_24XX_MCSPI1_IRQ	65
+# define OMAP_INT_24XX_MCSPI2_IRQ	66
+# define OMAP_INT_24XX_SSI1_IRQ0	67
+# define OMAP_INT_24XX_SSI1_IRQ1	68
+# define OMAP_INT_24XX_SSI2_IRQ0	69
+# define OMAP_INT_24XX_SSI2_IRQ1	70
+# define OMAP_INT_24XX_SSI_GDD_IRQ	71
+# define OMAP_INT_24XX_UART1_IRQ	72
+# define OMAP_INT_24XX_UART2_IRQ	73
+# define OMAP_INT_24XX_UART3_IRQ	74
+# define OMAP_INT_24XX_USB_IRQ_GEN	75
+# define OMAP_INT_24XX_USB_IRQ_NISO	76
+# define OMAP_INT_24XX_USB_IRQ_ISO	77
+# define OMAP_INT_24XX_USB_IRQ_HGEN	78
+# define OMAP_INT_24XX_USB_IRQ_HSOF	79
+# define OMAP_INT_24XX_USB_IRQ_OTG	80
+# define OMAP_INT_24XX_VLYNQ_IRQ	81
+# define OMAP_INT_24XX_MMC_IRQ		83
+# define OMAP_INT_24XX_MS_IRQ		84
+# define OMAP_INT_24XX_FAC_IRQ		85
+# define OMAP_INT_24XX_MCSPI3_IRQ	91
+# define OMAP_INT_243X_HS_USB_MC	92
+# define OMAP_INT_243X_HS_USB_DMA	93
+# define OMAP_INT_243X_CARKIT		94
+# define OMAP_INT_34XX_GPTIMER12	95
+
+/* omap_dma.c */
+enum omap_dma_model {
+    omap_dma_3_0,
+    omap_dma_3_1,
+    omap_dma_3_2,
+    omap_dma_4,
+};
+
+struct soc_dma_s;
+struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model);
+struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk);
+void omap_dma_reset(struct soc_dma_s *s);
+
+struct dma_irq_map {
+    int ih;
+    int intr;
+};
+
+/* Only used in OMAP DMA 3.x gigacells */
+enum omap_dma_port {
+    emiff = 0,
+    emifs,
+    imif,	/* omap16xx: ocp_t1 */
+    tipb,
+    local,	/* omap16xx: ocp_t2 */
+    tipb_mpui,
+    __omap_dma_port_last,
+};
+
+typedef enum {
+    constant = 0,
+    post_incremented,
+    single_index,
+    double_index,
+} omap_dma_addressing_t;
+
+/* Only used in OMAP DMA 3.x gigacells */
+struct omap_dma_lcd_channel_s {
+    enum omap_dma_port src;
+    target_phys_addr_t src_f1_top;
+    target_phys_addr_t src_f1_bottom;
+    target_phys_addr_t src_f2_top;
+    target_phys_addr_t src_f2_bottom;
+
+    /* Used in OMAP DMA 3.2 gigacell */
+    unsigned char brust_f1;
+    unsigned char pack_f1;
+    unsigned char data_type_f1;
+    unsigned char brust_f2;
+    unsigned char pack_f2;
+    unsigned char data_type_f2;
+    unsigned char end_prog;
+    unsigned char repeat;
+    unsigned char auto_init;
+    unsigned char priority;
+    unsigned char fs;
+    unsigned char running;
+    unsigned char bs;
+    unsigned char omap_3_1_compatible_disable;
+    unsigned char dst;
+    unsigned char lch_type;
+    int16_t element_index_f1;
+    int16_t element_index_f2;
+    int32_t frame_index_f1;
+    int32_t frame_index_f2;
+    uint16_t elements_f1;
+    uint16_t frames_f1;
+    uint16_t elements_f2;
+    uint16_t frames_f2;
+    omap_dma_addressing_t mode_f1;
+    omap_dma_addressing_t mode_f2;
+
+    /* Destination port is fixed.  */
+    int interrupts;
+    int condition;
+    int dual;
+
+    int current_frame;
+    target_phys_addr_t phys_framebuffer[2];
+    qemu_irq irq;
+    struct omap_mpu_state_s *mpu;
+} *omap_dma_get_lcdch(struct soc_dma_s *s);
+
+/*
+ * DMA request numbers for OMAP1
+ * See /usr/include/asm-arm/arch-omap/dma.h in Linux.
+ */
+# define OMAP_DMA_NO_DEVICE		0
+# define OMAP_DMA_MCSI1_TX		1
+# define OMAP_DMA_MCSI1_RX		2
+# define OMAP_DMA_I2C_RX		3
+# define OMAP_DMA_I2C_TX		4
+# define OMAP_DMA_EXT_NDMA_REQ0		5
+# define OMAP_DMA_EXT_NDMA_REQ1		6
+# define OMAP_DMA_UWIRE_TX		7
+# define OMAP_DMA_MCBSP1_TX		8
+# define OMAP_DMA_MCBSP1_RX		9
+# define OMAP_DMA_MCBSP3_TX		10
+# define OMAP_DMA_MCBSP3_RX		11
+# define OMAP_DMA_UART1_TX		12
+# define OMAP_DMA_UART1_RX		13
+# define OMAP_DMA_UART2_TX		14
+# define OMAP_DMA_UART2_RX		15
+# define OMAP_DMA_MCBSP2_TX		16
+# define OMAP_DMA_MCBSP2_RX		17
+# define OMAP_DMA_UART3_TX		18
+# define OMAP_DMA_UART3_RX		19
+# define OMAP_DMA_CAMERA_IF_RX		20
+# define OMAP_DMA_MMC_TX		21
+# define OMAP_DMA_MMC_RX		22
+# define OMAP_DMA_NAND			23	/* Not in OMAP310 */
+# define OMAP_DMA_IRQ_LCD_LINE		24	/* Not in OMAP310 */
+# define OMAP_DMA_MEMORY_STICK		25	/* Not in OMAP310 */
+# define OMAP_DMA_USB_W2FC_RX0		26
+# define OMAP_DMA_USB_W2FC_RX1		27
+# define OMAP_DMA_USB_W2FC_RX2		28
+# define OMAP_DMA_USB_W2FC_TX0		29
+# define OMAP_DMA_USB_W2FC_TX1		30
+# define OMAP_DMA_USB_W2FC_TX2		31
+
+/* These are only for 1610 */
+# define OMAP_DMA_CRYPTO_DES_IN		32
+# define OMAP_DMA_SPI_TX		33
+# define OMAP_DMA_SPI_RX		34
+# define OMAP_DMA_CRYPTO_HASH		35
+# define OMAP_DMA_CCP_ATTN		36
+# define OMAP_DMA_CCP_FIFO_NOT_EMPTY	37
+# define OMAP_DMA_CMT_APE_TX_CHAN_0	38
+# define OMAP_DMA_CMT_APE_RV_CHAN_0	39
+# define OMAP_DMA_CMT_APE_TX_CHAN_1	40
+# define OMAP_DMA_CMT_APE_RV_CHAN_1	41
+# define OMAP_DMA_CMT_APE_TX_CHAN_2	42
+# define OMAP_DMA_CMT_APE_RV_CHAN_2	43
+# define OMAP_DMA_CMT_APE_TX_CHAN_3	44
+# define OMAP_DMA_CMT_APE_RV_CHAN_3	45
+# define OMAP_DMA_CMT_APE_TX_CHAN_4	46
+# define OMAP_DMA_CMT_APE_RV_CHAN_4	47
+# define OMAP_DMA_CMT_APE_TX_CHAN_5	48
+# define OMAP_DMA_CMT_APE_RV_CHAN_5	49
+# define OMAP_DMA_CMT_APE_TX_CHAN_6	50
+# define OMAP_DMA_CMT_APE_RV_CHAN_6	51
+# define OMAP_DMA_CMT_APE_TX_CHAN_7	52
+# define OMAP_DMA_CMT_APE_RV_CHAN_7	53
+# define OMAP_DMA_MMC2_TX		54
+# define OMAP_DMA_MMC2_RX		55
+# define OMAP_DMA_CRYPTO_DES_OUT	56
+
+/*
+ * DMA request numbers for the OMAP2
+ */
+# define OMAP24XX_DMA_NO_DEVICE		0
+# define OMAP24XX_DMA_XTI_DMA		1	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ0	2
+# define OMAP24XX_DMA_EXT_DMAREQ1	3
+# define OMAP24XX_DMA_GPMC		4
+# define OMAP24XX_DMA_GFX		5	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_DSS		6
+# define OMAP24XX_DMA_VLYNQ_TX		7	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_CWT		8	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_TX		9	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_RX		10	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_TX		11	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_RX		12	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_SHA1MD5_RX	13	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ2	14
+# define OMAP24XX_DMA_EXT_DMAREQ3	15
+# define OMAP24XX_DMA_EXT_DMAREQ4	16
+# define OMAP24XX_DMA_EAC_AC_RD		17
+# define OMAP24XX_DMA_EAC_AC_WR		18
+# define OMAP24XX_DMA_EAC_MD_UL_RD	19
+# define OMAP24XX_DMA_EAC_MD_UL_WR	20
+# define OMAP24XX_DMA_EAC_MD_DL_RD	21
+# define OMAP24XX_DMA_EAC_MD_DL_WR	22
+# define OMAP24XX_DMA_EAC_BT_UL_RD	23
+# define OMAP24XX_DMA_EAC_BT_UL_WR	24
+# define OMAP24XX_DMA_EAC_BT_DL_RD	25
+# define OMAP24XX_DMA_EAC_BT_DL_WR	26
+# define OMAP24XX_DMA_I2C1_TX		27
+# define OMAP24XX_DMA_I2C1_RX		28
+# define OMAP24XX_DMA_I2C2_TX		29
+# define OMAP24XX_DMA_I2C2_RX		30
+# define OMAP24XX_DMA_MCBSP1_TX		31
+# define OMAP24XX_DMA_MCBSP1_RX		32
+# define OMAP24XX_DMA_MCBSP2_TX		33
+# define OMAP24XX_DMA_MCBSP2_RX		34
+# define OMAP24XX_DMA_SPI1_TX0		35
+# define OMAP24XX_DMA_SPI1_RX0		36
+# define OMAP24XX_DMA_SPI1_TX1		37
+# define OMAP24XX_DMA_SPI1_RX1		38
+# define OMAP24XX_DMA_SPI1_TX2		39
+# define OMAP24XX_DMA_SPI1_RX2		40
+# define OMAP24XX_DMA_SPI1_TX3		41
+# define OMAP24XX_DMA_SPI1_RX3		42
+# define OMAP24XX_DMA_SPI2_TX0		43
+# define OMAP24XX_DMA_SPI2_RX0		44
+# define OMAP24XX_DMA_SPI2_TX1		45
+# define OMAP24XX_DMA_SPI2_RX1		46
+
+# define OMAP24XX_DMA_UART1_TX		49
+# define OMAP24XX_DMA_UART1_RX		50
+# define OMAP24XX_DMA_UART2_TX		51
+# define OMAP24XX_DMA_UART2_RX		52
+# define OMAP24XX_DMA_UART3_TX		53
+# define OMAP24XX_DMA_UART3_RX		54
+# define OMAP24XX_DMA_USB_W2FC_TX0	55
+# define OMAP24XX_DMA_USB_W2FC_RX0	56
+# define OMAP24XX_DMA_USB_W2FC_TX1	57
+# define OMAP24XX_DMA_USB_W2FC_RX1	58
+# define OMAP24XX_DMA_USB_W2FC_TX2	59
+# define OMAP24XX_DMA_USB_W2FC_RX2	60
+# define OMAP24XX_DMA_MMC1_TX		61
+# define OMAP24XX_DMA_MMC1_RX		62
+# define OMAP24XX_DMA_MS		63	/* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ5	64
+
+/* omap[123].c */
+/* OMAP2 gp timer */
+struct omap_gp_timer_s;
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk);
+void omap_gp_timer_reset(struct omap_gp_timer_s *s);
+
+/* OMAP2 sysctimer */
+struct omap_synctimer_s;
+struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
+void omap_synctimer_reset(struct omap_synctimer_s *s);
+
+struct omap_uart_s;
+struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
+struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
+void omap_uart_reset(struct omap_uart_s *s);
+void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
+
+struct omap_mpuio_s;
+struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+                qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
+                omap_clk clk);
+qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
+void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
+void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
+
+/* omap1 gpio module interface */
+struct omap_gpio_s;
+struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk);
+void omap_gpio_reset(struct omap_gpio_s *s);
+qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
+void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
+
+/* omap2 gpio interface */
+struct omap_gpif_s;
+struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
+void omap_gpif_reset(struct omap_gpif_s *s);
+qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
+void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
+
+struct uWireSlave {
+    uint16_t (*receive)(void *opaque);
+    void (*send)(void *opaque, uint16_t data);
+    void *opaque;
+};
+struct omap_uwire_s;
+struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
+                qemu_irq *irq, qemu_irq dma, omap_clk clk);
+void omap_uwire_attach(struct omap_uwire_s *s,
+                uWireSlave *slave, int chipselect);
+
+/* OMAP2 spi */
+struct omap_mcspi_s;
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
+                int chipselect);
+void omap_mcspi_reset(struct omap_mcspi_s *s);
+
+struct I2SCodec {
+    void *opaque;
+
+    /* The CPU can call this if it is generating the clock signal on the
+     * i2s port.  The CODEC can ignore it if it is set up as a clock
+     * master and generates its own clock.  */
+    void (*set_rate)(void *opaque, int in, int out);
+
+    void (*tx_swallow)(void *opaque);
+    qemu_irq rx_swallow;
+    qemu_irq tx_start;
+
+    int tx_rate;
+    int cts;
+    int rx_rate;
+    int rts;
+
+    struct i2s_fifo_s {
+        uint8_t *fifo;
+        int len;
+        int start;
+        int size;
+    } in, out;
+};
+struct omap_mcbsp_s;
+struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
+                qemu_irq *irq, qemu_irq *dma, omap_clk clk);
+void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
+
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu);
+
+/* omap_lcdc.c */
+struct omap_lcd_panel_s;
+void omap_lcdc_reset(struct omap_lcd_panel_s *s);
+struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
+                struct omap_dma_lcd_channel_s *dma,
+                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
+
+/* omap_dss.c */
+struct rfbi_chip_s {
+    void *opaque;
+    void (*write)(void *opaque, int dc, uint16_t value);
+    void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
+    uint16_t (*read)(void *opaque, int dc);
+};
+struct omap_dss_s;
+void omap_dss_reset(struct omap_dss_s *s);
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                target_phys_addr_t l3_base,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2);
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
+
+/* omap_mmc.c */
+struct omap_mmc_s;
+struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
+                BlockDriverState *bd,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk);
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk);
+void omap_mmc_reset(struct omap_mmc_s *s);
+void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
+void omap_mmc_enable(struct omap_mmc_s *s, int enable);
+
+/* omap_i2c.c */
+struct omap_i2c_s;
+struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq *dma, omap_clk clk);
+struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk);
+void omap_i2c_reset(struct omap_i2c_s *s);
+i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
+
+# define cpu_is_omap310(cpu)		(cpu->mpu_model == omap310)
+# define cpu_is_omap1510(cpu)		(cpu->mpu_model == omap1510)
+# define cpu_is_omap1610(cpu)		(cpu->mpu_model == omap1610)
+# define cpu_is_omap1710(cpu)		(cpu->mpu_model == omap1710)
+# define cpu_is_omap2410(cpu)		(cpu->mpu_model == omap2410)
+# define cpu_is_omap2420(cpu)		(cpu->mpu_model == omap2420)
+# define cpu_is_omap2430(cpu)		(cpu->mpu_model == omap2430)
+# define cpu_is_omap3430(cpu)		(cpu->mpu_model == omap3430)
+
+# define cpu_is_omap15xx(cpu)		\
+        (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
+# define cpu_is_omap16xx(cpu)		\
+        (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
+# define cpu_is_omap24xx(cpu)		\
+        (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
+
+# define cpu_class_omap1(cpu)		\
+        (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
+# define cpu_class_omap2(cpu)		cpu_is_omap24xx(cpu)
+# define cpu_class_omap3(cpu)		cpu_is_omap3430(cpu)
+
+struct omap_mpu_state_s {
+    enum omap_mpu_model {
+        omap310,
+        omap1510,
+        omap1610,
+        omap1710,
+        omap2410,
+        omap2420,
+        omap2422,
+        omap2423,
+        omap2430,
+        omap3430,
+    } mpu_model;
+
+    CPUState *env;
+
+    qemu_irq *irq[2];
+    qemu_irq *drq;
+
+    qemu_irq wakeup;
+
+    struct omap_dma_port_if_s {
+        uint32_t (*read[3])(struct omap_mpu_state_s *s,
+                        target_phys_addr_t offset);
+        void (*write[3])(struct omap_mpu_state_s *s,
+                        target_phys_addr_t offset, uint32_t value);
+        int (*addr_valid)(struct omap_mpu_state_s *s,
+                        target_phys_addr_t addr);
+    } port[__omap_dma_port_last];
+
+    unsigned long sdram_size;
+    unsigned long sram_size;
+
+    /* MPUI-TIPB peripherals */
+    struct omap_uart_s *uart[3];
+
+    struct omap_gpio_s *gpio;
+
+    struct omap_mcbsp_s *mcbsp1;
+    struct omap_mcbsp_s *mcbsp3;
+
+    /* MPU public TIPB peripherals */
+    struct omap_32khz_timer_s *os_timer;
+
+    struct omap_mmc_s *mmc;
+
+    struct omap_mpuio_s *mpuio;
+
+    struct omap_uwire_s *microwire;
+
+    struct {
+        uint8_t output;
+        uint8_t level;
+        uint8_t enable;
+        int clk;
+    } pwl;
+
+    struct {
+        uint8_t frc;
+        uint8_t vrc;
+        uint8_t gcr;
+        omap_clk clk;
+    } pwt;
+
+    struct omap_i2c_s *i2c[2];
+
+    struct omap_rtc_s *rtc;
+
+    struct omap_mcbsp_s *mcbsp2;
+
+    struct omap_lpg_s *led[2];
+
+    /* MPU private TIPB peripherals */
+    struct omap_intr_handler_s *ih[2];
+
+    struct soc_dma_s *dma;
+
+    struct omap_mpu_timer_s *timer[3];
+    struct omap_watchdog_timer_s *wdt;
+
+    struct omap_lcd_panel_s *lcd;
+
+    uint32_t ulpd_pm_regs[21];
+    int64_t ulpd_gauge_start;
+
+    uint32_t func_mux_ctrl[14];
+    uint32_t comp_mode_ctrl[1];
+    uint32_t pull_dwn_ctrl[4];
+    uint32_t gate_inh_ctrl[1];
+    uint32_t voltage_ctrl[1];
+    uint32_t test_dbg_ctrl[1];
+    uint32_t mod_conf_ctrl[1];
+    int compat1509;
+
+    uint32_t mpui_ctrl;
+
+    struct omap_tipb_bridge_s *private_tipb;
+    struct omap_tipb_bridge_s *public_tipb;
+
+    uint32_t tcmi_regs[17];
+
+    struct dpll_ctl_s {
+        uint16_t mode;
+        omap_clk dpll;
+    } dpll[3];
+
+    omap_clk clks;
+    struct {
+        int cold_start;
+        int clocking_scheme;
+        uint16_t arm_ckctl;
+        uint16_t arm_idlect1;
+        uint16_t arm_idlect2;
+        uint16_t arm_ewupct;
+        uint16_t arm_rstct1;
+        uint16_t arm_rstct2;
+        uint16_t arm_ckout1;
+        int dpll1_mode;
+        uint16_t dsp_idlect1;
+        uint16_t dsp_idlect2;
+        uint16_t dsp_rstct2;
+    } clkm;
+
+    /* OMAP2-only peripherals */
+    struct omap_l4_s *l4;
+
+    struct omap_gp_timer_s *gptimer[12];
+    struct omap_synctimer_s *synctimer;
+
+    struct omap_prcm_s *prcm;
+    struct omap_sdrc_s *sdrc;
+    struct omap_gpmc_s *gpmc;
+    struct omap_sysctl_s *sysc;
+
+    struct omap_gpif_s *gpif;
+
+    struct omap_mcspi_s *mcspi[2];
+
+    struct omap_dss_s *dss;
+
+    struct omap_eac_s *eac;
+};
+
+/* omap1.c */
+struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+                const char *core);
+
+/* omap2.c */
+struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
+                const char *core);
+
+# if TARGET_PHYS_ADDR_BITS == 32
+#  define OMAP_FMT_plx "%#08x"
+# elif TARGET_PHYS_ADDR_BITS == 64
+#  define OMAP_FMT_plx "%#08" PRIx64
+# else
+#  error TARGET_PHYS_ADDR_BITS undefined
+# endif
+
+uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr);
+void omap_badwidth_write8(void *opaque, target_phys_addr_t addr,
+                uint32_t value);
+uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr);
+void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
+                uint32_t value);
+uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr);
+void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
+                uint32_t value);
+
+void omap_mpu_wakeup(void *opaque, int irq, int req);
+
+# define OMAP_BAD_REG(paddr)		\
+        fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+# define OMAP_RO_REG(paddr)		\
+        fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+
+/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
+   (Board-specifc tags are not here)  */
+#define OMAP_TAG_CLOCK		0x4f01
+#define OMAP_TAG_MMC		0x4f02
+#define OMAP_TAG_SERIAL_CONSOLE	0x4f03
+#define OMAP_TAG_USB		0x4f04
+#define OMAP_TAG_LCD		0x4f05
+#define OMAP_TAG_GPIO_SWITCH	0x4f06
+#define OMAP_TAG_UART		0x4f07
+#define OMAP_TAG_FBMEM		0x4f08
+#define OMAP_TAG_STI_CONSOLE	0x4f09
+#define OMAP_TAG_CAMERA_SENSOR	0x4f0a
+#define OMAP_TAG_PARTITION	0x4f0b
+#define OMAP_TAG_TEA5761	0x4f10
+#define OMAP_TAG_TMP105		0x4f11
+#define OMAP_TAG_BOOT_REASON	0x4f80
+#define OMAP_TAG_FLASH_PART_STR	0x4f81
+#define OMAP_TAG_VERSION_STR	0x4f82
+
+enum {
+    OMAP_GPIOSW_TYPE_COVER	= 0 << 4,
+    OMAP_GPIOSW_TYPE_CONNECTION	= 1 << 4,
+    OMAP_GPIOSW_TYPE_ACTIVITY	= 2 << 4,
+};
+
+#define OMAP_GPIOSW_INVERTED	0x0001
+#define OMAP_GPIOSW_OUTPUT	0x0002
+
+# define TCMI_VERBOSE			1
+//# define MEM_VERBOSE			1
+
+# ifdef TCMI_VERBOSE
+#  define OMAP_8B_REG(paddr)		\
+        fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+#  define OMAP_16B_REG(paddr)		\
+        fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+#  define OMAP_32B_REG(paddr)		\
+        fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+# else
+#  define OMAP_8B_REG(paddr)
+#  define OMAP_16B_REG(paddr)
+#  define OMAP_32B_REG(paddr)
+# endif
+
+# define OMAP_MPUI_REG_MASK		0x000007ff
+
+# ifdef MEM_VERBOSE
+struct io_fn {
+    CPUReadMemoryFunc * const *mem_read;
+    CPUWriteMemoryFunc * const *mem_write;
+    void *opaque;
+    int in;
+};
+
+static uint32_t io_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct io_fn *s = opaque;
+    uint32_t ret;
+
+    s->in ++;
+    ret = s->mem_read[0](s->opaque, addr);
+    s->in --;
+    if (!s->in)
+        fprintf(stderr, "%08x ---> %02x\n", (uint32_t) addr, ret);
+    return ret;
+}
+static uint32_t io_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct io_fn *s = opaque;
+    uint32_t ret;
+
+    s->in ++;
+    ret = s->mem_read[1](s->opaque, addr);
+    s->in --;
+    if (!s->in)
+        fprintf(stderr, "%08x ---> %04x\n", (uint32_t) addr, ret);
+    return ret;
+}
+static uint32_t io_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct io_fn *s = opaque;
+    uint32_t ret;
+
+    s->in ++;
+    ret = s->mem_read[2](s->opaque, addr);
+    s->in --;
+    if (!s->in)
+        fprintf(stderr, "%08x ---> %08x\n", (uint32_t) addr, ret);
+    return ret;
+}
+static void io_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct io_fn *s = opaque;
+
+    if (!s->in)
+        fprintf(stderr, "%08x <--- %02x\n", (uint32_t) addr, value);
+    s->in ++;
+    s->mem_write[0](s->opaque, addr, value);
+    s->in --;
+}
+static void io_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct io_fn *s = opaque;
+
+    if (!s->in)
+        fprintf(stderr, "%08x <--- %04x\n", (uint32_t) addr, value);
+    s->in ++;
+    s->mem_write[1](s->opaque, addr, value);
+    s->in --;
+}
+static void io_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct io_fn *s = opaque;
+
+    if (!s->in)
+        fprintf(stderr, "%08x <--- %08x\n", (uint32_t) addr, value);
+    s->in ++;
+    s->mem_write[2](s->opaque, addr, value);
+    s->in --;
+}
+
+static CPUReadMemoryFunc * const io_readfn[] = { io_readb, io_readh, io_readw, };
+static CPUWriteMemoryFunc * const io_writefn[] = { io_writeb, io_writeh, io_writew, };
+
+inline static int debug_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                                           CPUWriteMemoryFunc * const *mem_write,
+                                           void *opaque)
+{
+    struct io_fn *s = qemu_malloc(sizeof(struct io_fn));
+
+    s->mem_read = mem_read;
+    s->mem_write = mem_write;
+    s->opaque = opaque;
+    s->in = 0;
+    return cpu_register_io_memory(io_readfn, io_writefn, s,
+                                  DEVICE_NATIVE_ENDIAN);
+}
+#  define cpu_register_io_memory	debug_register_io_memory
+# endif
+
+/* Define when we want to reduce the number of IO regions registered.  */
+/*# define L4_MUX_HACK*/
+
+#endif /* hw_omap_h */
diff --git a/qemu-0.15.x/hw/omap1.c b/qemu-0.15.x/hw/omap1.c
new file mode 100644
index 0000000..364c26f
--- /dev/null
+++ b/qemu-0.15.x/hw/omap1.c
@@ -0,0 +1,3894 @@
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "soc_dma.h"
+/* We use pc-style serial ports.  */
+#include "pc.h"
+#include "blockdev.h"
+#include "range.h"
+
+/* Should signal the TCMI/GPMC */
+uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
+{
+    uint8_t ret;
+
+    OMAP_8B_REG(addr);
+    cpu_physical_memory_read(addr, (void *) &ret, 1);
+    return ret;
+}
+
+void omap_badwidth_write8(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    uint8_t val8 = value;
+
+    OMAP_8B_REG(addr);
+    cpu_physical_memory_write(addr, (void *) &val8, 1);
+}
+
+uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr)
+{
+    uint16_t ret;
+
+    OMAP_16B_REG(addr);
+    cpu_physical_memory_read(addr, (void *) &ret, 2);
+    return ret;
+}
+
+void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    uint16_t val16 = value;
+
+    OMAP_16B_REG(addr);
+    cpu_physical_memory_write(addr, (void *) &val16, 2);
+}
+
+uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    OMAP_32B_REG(addr);
+    cpu_physical_memory_read(addr, (void *) &ret, 4);
+    return ret;
+}
+
+void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_32B_REG(addr);
+    cpu_physical_memory_write(addr, (void *) &value, 4);
+}
+
+/* MPU OS timers */
+struct omap_mpu_timer_s {
+    qemu_irq irq;
+    omap_clk clk;
+    uint32_t val;
+    int64_t time;
+    QEMUTimer *timer;
+    QEMUBH *tick;
+    int64_t rate;
+    int it_ena;
+
+    int enable;
+    int ptv;
+    int ar;
+    int st;
+    uint32_t reset_val;
+};
+
+static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
+{
+    uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time;
+
+    if (timer->st && timer->enable && timer->rate)
+        return timer->val - muldiv64(distance >> (timer->ptv + 1),
+                                     timer->rate, get_ticks_per_sec());
+    else
+        return timer->val;
+}
+
+static inline void omap_timer_sync(struct omap_mpu_timer_s *timer)
+{
+    timer->val = omap_timer_read(timer);
+    timer->time = qemu_get_clock_ns(vm_clock);
+}
+
+static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
+{
+    int64_t expires;
+
+    if (timer->enable && timer->st && timer->rate) {
+        timer->val = timer->reset_val;	/* Should skip this on clk enable */
+        expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1),
+                           get_ticks_per_sec(), timer->rate);
+
+        /* If timer expiry would be sooner than in about 1 ms and
+         * auto-reload isn't set, then fire immediately.  This is a hack
+         * to make systems like PalmOS run in acceptable time.  PalmOS
+         * sets the interval to a very low value and polls the status bit
+         * in a busy loop when it wants to sleep just a couple of CPU
+         * ticks.  */
+        if (expires > (get_ticks_per_sec() >> 10) || timer->ar)
+            qemu_mod_timer(timer->timer, timer->time + expires);
+        else
+            qemu_bh_schedule(timer->tick);
+    } else
+        qemu_del_timer(timer->timer);
+}
+
+static void omap_timer_fire(void *opaque)
+{
+    struct omap_mpu_timer_s *timer = opaque;
+
+    if (!timer->ar) {
+        timer->val = 0;
+        timer->st = 0;
+    }
+
+    if (timer->it_ena)
+        /* Edge-triggered irq */
+        qemu_irq_pulse(timer->irq);
+}
+
+static void omap_timer_tick(void *opaque)
+{
+    struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
+
+    omap_timer_sync(timer);
+    omap_timer_fire(timer);
+    omap_timer_update(timer);
+}
+
+static void omap_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
+
+    omap_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_timer_update(timer);
+}
+
+static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CNTL_TIMER */
+        return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
+
+    case 0x04:	/* LOAD_TIM */
+        break;
+
+    case 0x08:	/* READ_TIM */
+        return omap_timer_read(s);
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CNTL_TIMER */
+        omap_timer_sync(s);
+        s->enable = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = value & 1;
+        omap_timer_update(s);
+        return;
+
+    case 0x04:	/* LOAD_TIM */
+        s->reset_val = value;
+        return;
+
+    case 0x08:	/* READ_TIM */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_mpu_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mpu_timer_read,
+};
+
+static CPUWriteMemoryFunc * const omap_mpu_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mpu_timer_write,
+};
+
+static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
+{
+    qemu_del_timer(s->timer);
+    s->enable = 0;
+    s->reset_val = 31337;
+    s->val = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->it_ena = 1;
+}
+
+static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_timer_s));
+
+    s->irq = irq;
+    s->clk = clk;
+    s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s);
+    s->tick = qemu_bh_new(omap_timer_fire, s);
+    omap_mpu_timer_reset(s);
+    omap_timer_clk_setup(s);
+
+    iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn,
+                    omap_mpu_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* Watchdog timer */
+struct omap_watchdog_timer_s {
+    struct omap_mpu_timer_s timer;
+    uint8_t last_wr;
+    int mode;
+    int free;
+    int reset;
+};
+
+static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CNTL_TIMER */
+        return (s->timer.ptv << 9) | (s->timer.ar << 8) |
+                (s->timer.st << 7) | (s->free << 1);
+
+    case 0x04:	/* READ_TIMER */
+        return omap_timer_read(&s->timer);
+
+    case 0x08:	/* TIMER_MODE */
+        return s->mode << 15;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CNTL_TIMER */
+        omap_timer_sync(&s->timer);
+        s->timer.ptv = (value >> 9) & 7;
+        s->timer.ar = (value >> 8) & 1;
+        s->timer.st = (value >> 7) & 1;
+        s->free = (value >> 1) & 1;
+        omap_timer_update(&s->timer);
+        break;
+
+    case 0x04:	/* LOAD_TIMER */
+        s->timer.reset_val = value & 0xffff;
+        break;
+
+    case 0x08:	/* TIMER_MODE */
+        if (!s->mode && ((value >> 15) & 1))
+            omap_clk_get(s->timer.clk);
+        s->mode |= (value >> 15) & 1;
+        if (s->last_wr == 0xf5) {
+            if ((value & 0xff) == 0xa0) {
+                if (s->mode) {
+                    s->mode = 0;
+                    omap_clk_put(s->timer.clk);
+                }
+            } else {
+                /* XXX: on T|E hardware somehow this has no effect,
+                 * on Zire 71 it works as specified.  */
+                s->reset = 1;
+                qemu_system_reset_request();
+            }
+        }
+        s->last_wr = value & 0xff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_wd_timer_readfn[] = {
+    omap_badwidth_read16,
+    omap_wd_timer_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_wd_timer_writefn[] = {
+    omap_badwidth_write16,
+    omap_wd_timer_write,
+    omap_badwidth_write16,
+};
+
+static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
+{
+    qemu_del_timer(s->timer.timer);
+    if (!s->mode)
+        omap_clk_get(s->timer.clk);
+    s->mode = 1;
+    s->free = 1;
+    s->reset = 0;
+    s->timer.enable = 1;
+    s->timer.it_ena = 1;
+    s->timer.reset_val = 0xffff;
+    s->timer.val = 0;
+    s->timer.st = 0;
+    s->timer.ptv = 0;
+    s->timer.ar = 0;
+    omap_timer_update(&s->timer);
+}
+
+static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
+            qemu_mallocz(sizeof(struct omap_watchdog_timer_s));
+
+    s->timer.irq = irq;
+    s->timer.clk = clk;
+    s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
+    omap_wd_timer_reset(s);
+    omap_timer_clk_setup(&s->timer);
+
+    iomemtype = cpu_register_io_memory(omap_wd_timer_readfn,
+                    omap_wd_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* 32-kHz timer */
+struct omap_32khz_timer_s {
+    struct omap_mpu_timer_s timer;
+};
+
+static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* TVR */
+        return s->timer.reset_val;
+
+    case 0x04:	/* TCR */
+        return omap_timer_read(&s->timer);
+
+    case 0x08:	/* CR */
+        return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* TVR */
+        s->timer.reset_val = value & 0x00ffffff;
+        break;
+
+    case 0x04:	/* TCR */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x08:	/* CR */
+        s->timer.ar = (value >> 3) & 1;
+        s->timer.it_ena = (value >> 2) & 1;
+        if (s->timer.st != (value & 1) || (value & 2)) {
+            omap_timer_sync(&s->timer);
+            s->timer.enable = value & 1;
+            s->timer.st = value & 1;
+            omap_timer_update(&s->timer);
+        }
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_os_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_os_timer_read,
+};
+
+static CPUWriteMemoryFunc * const omap_os_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_os_timer_write,
+};
+
+static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
+{
+    qemu_del_timer(s->timer.timer);
+    s->timer.enable = 0;
+    s->timer.it_ena = 0;
+    s->timer.reset_val = 0x00ffffff;
+    s->timer.val = 0;
+    s->timer.st = 0;
+    s->timer.ptv = 0;
+    s->timer.ar = 1;
+}
+
+static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
+            qemu_mallocz(sizeof(struct omap_32khz_timer_s));
+
+    s->timer.irq = irq;
+    s->timer.clk = clk;
+    s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
+    omap_os_timer_reset(s);
+    omap_timer_clk_setup(&s->timer);
+
+    iomemtype = cpu_register_io_memory(omap_os_timer_readfn,
+                    omap_os_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    return s;
+}
+
+/* Ultra Low-Power Device Module */
+static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    uint16_t ret;
+
+    switch (addr) {
+    case 0x14:	/* IT_STATUS */
+        ret = s->ulpd_pm_regs[addr >> 2];
+        s->ulpd_pm_regs[addr >> 2] = 0;
+        qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]);
+        return ret;
+
+    case 0x18:	/* Reserved */
+    case 0x1c:	/* Reserved */
+    case 0x20:	/* Reserved */
+    case 0x28:	/* Reserved */
+    case 0x2c:	/* Reserved */
+        OMAP_BAD_REG(addr);
+    case 0x00:	/* COUNTER_32_LSB */
+    case 0x04:	/* COUNTER_32_MSB */
+    case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
+    case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
+    case 0x10:	/* GAUGING_CTRL */
+    case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
+    case 0x30:	/* CLOCK_CTRL */
+    case 0x34:	/* SOFT_REQ */
+    case 0x38:	/* COUNTER_32_FIQ */
+    case 0x3c:	/* DPLL_CTRL */
+    case 0x40:	/* STATUS_REQ */
+        /* XXX: check clk::usecount state for every clock */
+    case 0x48:	/* LOCL_TIME */
+    case 0x4c:	/* APLL_CTRL */
+    case 0x50:	/* POWER_CTRL */
+        return s->ulpd_pm_regs[addr >> 2];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    if (diff & (1 << 4))				/* USB_MCLK_EN */
+        omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1);
+    if (diff & (1 << 5))				/* DIS_USB_PVCI_CLK */
+        omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);
+}
+
+static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    if (diff & (1 << 0))				/* SOFT_DPLL_REQ */
+        omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1);
+    if (diff & (1 << 1))				/* SOFT_COM_REQ */
+        omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1);
+    if (diff & (1 << 2))				/* SOFT_SDW_REQ */
+        omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1);
+    if (diff & (1 << 3))				/* SOFT_USB_REQ */
+        omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);
+}
+
+static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int64_t now, ticks;
+    int div, mult;
+    static const int bypass_div[4] = { 1, 2, 4, 4 };
+    uint16_t diff;
+
+    switch (addr) {
+    case 0x00:	/* COUNTER_32_LSB */
+    case 0x04:	/* COUNTER_32_MSB */
+    case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
+    case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
+    case 0x14:	/* IT_STATUS */
+    case 0x40:	/* STATUS_REQ */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* GAUGING_CTRL */
+        /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
+        if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) {
+            now = qemu_get_clock_ns(vm_clock);
+
+            if (value & 1)
+                s->ulpd_gauge_start = now;
+            else {
+                now -= s->ulpd_gauge_start;
+
+                /* 32-kHz ticks */
+                ticks = muldiv64(now, 32768, get_ticks_per_sec());
+                s->ulpd_pm_regs[0x00 >> 2] = (ticks >>  0) & 0xffff;
+                s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff;
+                if (ticks >> 32)	/* OVERFLOW_32K */
+                    s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2;
+
+                /* High frequency ticks */
+                ticks = muldiv64(now, 12000000, get_ticks_per_sec());
+                s->ulpd_pm_regs[0x08 >> 2] = (ticks >>  0) & 0xffff;
+                s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff;
+                if (ticks >> 32)	/* OVERFLOW_HI_FREQ */
+                    s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
+
+                s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;	/* IT_GAUGING */
+                qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]);
+            }
+        }
+        s->ulpd_pm_regs[addr >> 2] = value;
+        break;
+
+    case 0x18:	/* Reserved */
+    case 0x1c:	/* Reserved */
+    case 0x20:	/* Reserved */
+    case 0x28:	/* Reserved */
+    case 0x2c:	/* Reserved */
+        OMAP_BAD_REG(addr);
+    case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
+    case 0x38:	/* COUNTER_32_FIQ */
+    case 0x48:	/* LOCL_TIME */
+    case 0x50:	/* POWER_CTRL */
+        s->ulpd_pm_regs[addr >> 2] = value;
+        break;
+
+    case 0x30:	/* CLOCK_CTRL */
+        diff = s->ulpd_pm_regs[addr >> 2] ^ value;
+        s->ulpd_pm_regs[addr >> 2] = value & 0x3f;
+        omap_ulpd_clk_update(s, diff, value);
+        break;
+
+    case 0x34:	/* SOFT_REQ */
+        diff = s->ulpd_pm_regs[addr >> 2] ^ value;
+        s->ulpd_pm_regs[addr >> 2] = value & 0x1f;
+        omap_ulpd_req_update(s, diff, value);
+        break;
+
+    case 0x3c:	/* DPLL_CTRL */
+        /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is
+         * omitted altogether, probably a typo.  */
+        /* This register has identical semantics with DPLL(1:3) control
+         * registers, see omap_dpll_write() */
+        diff = s->ulpd_pm_regs[addr >> 2] & value;
+        s->ulpd_pm_regs[addr >> 2] = value & 0x2fff;
+        if (diff & (0x3ff << 2)) {
+            if (value & (1 << 4)) {			/* PLL_ENABLE */
+                div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
+                mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
+            } else {
+                div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
+                mult = 1;
+            }
+            omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult);
+        }
+
+        /* Enter the desired mode.  */
+        s->ulpd_pm_regs[addr >> 2] =
+                (s->ulpd_pm_regs[addr >> 2] & 0xfffe) |
+                ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1);
+
+        /* Act as if the lock is restored.  */
+        s->ulpd_pm_regs[addr >> 2] |= 2;
+        break;
+
+    case 0x4c:	/* APLL_CTRL */
+        diff = s->ulpd_pm_regs[addr >> 2] & value;
+        s->ulpd_pm_regs[addr >> 2] = value & 0xf;
+        if (diff & (1 << 0))				/* APLL_NDPLL_SWITCH */
+            omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s,
+                                    (value & (1 << 0)) ? "apll" : "dpll4"));
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_ulpd_pm_readfn[] = {
+    omap_badwidth_read16,
+    omap_ulpd_pm_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_ulpd_pm_writefn[] = {
+    omap_badwidth_write16,
+    omap_ulpd_pm_write,
+    omap_badwidth_write16,
+};
+
+static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
+{
+    mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x18 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x1c >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x20 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff;
+    mpu->ulpd_pm_regs[0x28 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x2c >> 2] = 0x01;
+    omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000);
+    mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000;
+    omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000);
+    mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211;
+    mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */
+    mpu->ulpd_pm_regs[0x48 >> 2] = 0x960;
+    mpu->ulpd_pm_regs[0x4c >> 2] = 0x08;
+    mpu->ulpd_pm_regs[0x50 >> 2] = 0x08;
+    omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4);
+    omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
+}
+
+static void omap_ulpd_pm_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_ulpd_pm_readfn,
+                    omap_ulpd_pm_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+    omap_ulpd_pm_reset(mpu);
+}
+
+/* OMAP Pin Configuration */
+static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* FUNC_MUX_CTRL_0 */
+    case 0x04:	/* FUNC_MUX_CTRL_1 */
+    case 0x08:	/* FUNC_MUX_CTRL_2 */
+        return s->func_mux_ctrl[addr >> 2];
+
+    case 0x0c:	/* COMP_MODE_CTRL_0 */
+        return s->comp_mode_ctrl[0];
+
+    case 0x10:	/* FUNC_MUX_CTRL_3 */
+    case 0x14:	/* FUNC_MUX_CTRL_4 */
+    case 0x18:	/* FUNC_MUX_CTRL_5 */
+    case 0x1c:	/* FUNC_MUX_CTRL_6 */
+    case 0x20:	/* FUNC_MUX_CTRL_7 */
+    case 0x24:	/* FUNC_MUX_CTRL_8 */
+    case 0x28:	/* FUNC_MUX_CTRL_9 */
+    case 0x2c:	/* FUNC_MUX_CTRL_A */
+    case 0x30:	/* FUNC_MUX_CTRL_B */
+    case 0x34:	/* FUNC_MUX_CTRL_C */
+    case 0x38:	/* FUNC_MUX_CTRL_D */
+        return s->func_mux_ctrl[(addr >> 2) - 1];
+
+    case 0x40:	/* PULL_DWN_CTRL_0 */
+    case 0x44:	/* PULL_DWN_CTRL_1 */
+    case 0x48:	/* PULL_DWN_CTRL_2 */
+    case 0x4c:	/* PULL_DWN_CTRL_3 */
+        return s->pull_dwn_ctrl[(addr & 0xf) >> 2];
+
+    case 0x50:	/* GATE_INH_CTRL_0 */
+        return s->gate_inh_ctrl[0];
+
+    case 0x60:	/* VOLTAGE_CTRL_0 */
+        return s->voltage_ctrl[0];
+
+    case 0x70:	/* TEST_DBG_CTRL_0 */
+        return s->test_dbg_ctrl[0];
+
+    case 0x80:	/* MOD_CONF_CTRL_0 */
+        return s->mod_conf_ctrl[0];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (s->compat1509) {
+        if (diff & (1 << 9))			/* BLUETOOTH */
+            omap_clk_onoff(omap_findclk(s, "bt_mclk_out"),
+                            (~value >> 9) & 1);
+        if (diff & (1 << 7))			/* USB.CLKO */
+            omap_clk_onoff(omap_findclk(s, "usb.clko"),
+                            (value >> 7) & 1);
+    }
+}
+
+static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (s->compat1509) {
+        if (diff & (1 << 31))			/* MCBSP3_CLK_HIZ_DI */
+            omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"),
+                            (value >> 31) & 1);
+        if (diff & (1 << 1))			/* CLK32K */
+            omap_clk_onoff(omap_findclk(s, "clk32k_out"),
+                            (~value >> 1) & 1);
+    }
+}
+
+static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (diff & (1 << 31))			/* CONF_MOD_UART3_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart3_ck"),
+                         omap_findclk(s, ((value >> 31) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 30))			/* CONF_MOD_UART2_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart2_ck"),
+                         omap_findclk(s, ((value >> 30) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 29))			/* CONF_MOD_UART1_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart1_ck"),
+                         omap_findclk(s, ((value >> 29) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 23))			/* CONF_MOD_MMC_SD_CLK_REQ_R */
+         omap_clk_reparent(omap_findclk(s, "mmc_ck"),
+                         omap_findclk(s, ((value >> 23) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 12))			/* CONF_MOD_COM_MCLK_12_48_S */
+         omap_clk_reparent(omap_findclk(s, "com_mclk_out"),
+                         omap_findclk(s, ((value >> 12) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 9))			/* CONF_MOD_USB_HOST_HHC_UHO */
+         omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1);
+}
+
+static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    uint32_t diff;
+
+    switch (addr) {
+    case 0x00:	/* FUNC_MUX_CTRL_0 */
+        diff = s->func_mux_ctrl[addr >> 2] ^ value;
+        s->func_mux_ctrl[addr >> 2] = value;
+        omap_pin_funcmux0_update(s, diff, value);
+        return;
+
+    case 0x04:	/* FUNC_MUX_CTRL_1 */
+        diff = s->func_mux_ctrl[addr >> 2] ^ value;
+        s->func_mux_ctrl[addr >> 2] = value;
+        omap_pin_funcmux1_update(s, diff, value);
+        return;
+
+    case 0x08:	/* FUNC_MUX_CTRL_2 */
+        s->func_mux_ctrl[addr >> 2] = value;
+        return;
+
+    case 0x0c:	/* COMP_MODE_CTRL_0 */
+        s->comp_mode_ctrl[0] = value;
+        s->compat1509 = (value != 0x0000eaef);
+        omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]);
+        omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]);
+        return;
+
+    case 0x10:	/* FUNC_MUX_CTRL_3 */
+    case 0x14:	/* FUNC_MUX_CTRL_4 */
+    case 0x18:	/* FUNC_MUX_CTRL_5 */
+    case 0x1c:	/* FUNC_MUX_CTRL_6 */
+    case 0x20:	/* FUNC_MUX_CTRL_7 */
+    case 0x24:	/* FUNC_MUX_CTRL_8 */
+    case 0x28:	/* FUNC_MUX_CTRL_9 */
+    case 0x2c:	/* FUNC_MUX_CTRL_A */
+    case 0x30:	/* FUNC_MUX_CTRL_B */
+    case 0x34:	/* FUNC_MUX_CTRL_C */
+    case 0x38:	/* FUNC_MUX_CTRL_D */
+        s->func_mux_ctrl[(addr >> 2) - 1] = value;
+        return;
+
+    case 0x40:	/* PULL_DWN_CTRL_0 */
+    case 0x44:	/* PULL_DWN_CTRL_1 */
+    case 0x48:	/* PULL_DWN_CTRL_2 */
+    case 0x4c:	/* PULL_DWN_CTRL_3 */
+        s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value;
+        return;
+
+    case 0x50:	/* GATE_INH_CTRL_0 */
+        s->gate_inh_ctrl[0] = value;
+        return;
+
+    case 0x60:	/* VOLTAGE_CTRL_0 */
+        s->voltage_ctrl[0] = value;
+        return;
+
+    case 0x70:	/* TEST_DBG_CTRL_0 */
+        s->test_dbg_ctrl[0] = value;
+        return;
+
+    case 0x80:	/* MOD_CONF_CTRL_0 */
+        diff = s->mod_conf_ctrl[0] ^ value;
+        s->mod_conf_ctrl[0] = value;
+        omap_pin_modconf1_update(s, diff, value);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_pin_cfg_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_pin_cfg_read,
+};
+
+static CPUWriteMemoryFunc * const omap_pin_cfg_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_pin_cfg_write,
+};
+
+static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
+{
+    /* Start in Compatibility Mode.  */
+    mpu->compat1509 = 1;
+    omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0);
+    omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0);
+    omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0);
+    memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl));
+    memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl));
+    memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl));
+    memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl));
+    memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl));
+    memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl));
+    memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
+}
+
+static void omap_pin_cfg_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_pin_cfg_readfn,
+                    omap_pin_cfg_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+    omap_pin_cfg_reset(mpu);
+}
+
+/* Device Identification, Die Identification */
+static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0xfffe1800:	/* DIE_ID_LSB */
+        return 0xc9581f0e;
+    case 0xfffe1804:	/* DIE_ID_MSB */
+        return 0xa8858bfa;
+
+    case 0xfffe2000:	/* PRODUCT_ID_LSB */
+        return 0x00aaaafc;
+    case 0xfffe2004:	/* PRODUCT_ID_MSB */
+        return 0xcafeb574;
+
+    case 0xfffed400:	/* JTAG_ID_LSB */
+        switch (s->mpu_model) {
+        case omap310:
+            return 0x03310315;
+        case omap1510:
+            return 0x03310115;
+        default:
+            hw_error("%s: bad mpu model\n", __FUNCTION__);
+        }
+        break;
+
+    case 0xfffed404:	/* JTAG_ID_MSB */
+        switch (s->mpu_model) {
+        case omap310:
+            return 0xfb57402f;
+        case omap1510:
+            return 0xfb47002f;
+        default:
+            hw_error("%s: bad mpu model\n", __FUNCTION__);
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_id_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc * const omap_id_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_id_read,
+};
+
+static CPUWriteMemoryFunc * const omap_id_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_id_write,
+};
+
+static void omap_id_init(struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_id_readfn,
+                    omap_id_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory_offset(0xfffe1800, 0x800, iomemtype, 0xfffe1800);
+    cpu_register_physical_memory_offset(0xfffed400, 0x100, iomemtype, 0xfffed400);
+    if (!cpu_is_omap15xx(mpu))
+        cpu_register_physical_memory_offset(0xfffe2000, 0x800, iomemtype, 0xfffe2000);
+}
+
+/* MPUI Control (Dummy) */
+static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CTRL */
+        return s->mpui_ctrl;
+    case 0x04:	/* DEBUG_ADDR */
+        return 0x01ffffff;
+    case 0x08:	/* DEBUG_DATA */
+        return 0xffffffff;
+    case 0x0c:	/* DEBUG_FLAG */
+        return 0x00000800;
+    case 0x10:	/* STATUS */
+        return 0x00000000;
+
+    /* Not in OMAP310 */
+    case 0x14:	/* DSP_STATUS */
+    case 0x18:	/* DSP_BOOT_CONFIG */
+        return 0x00000000;
+    case 0x1c:	/* DSP_MPUI_CONFIG */
+        return 0x0000ffff;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* CTRL */
+        s->mpui_ctrl = value & 0x007fffff;
+        break;
+
+    case 0x04:	/* DEBUG_ADDR */
+    case 0x08:	/* DEBUG_DATA */
+    case 0x0c:	/* DEBUG_FLAG */
+    case 0x10:	/* STATUS */
+    /* Not in OMAP310 */
+    case 0x14:	/* DSP_STATUS */
+        OMAP_RO_REG(addr);
+    case 0x18:	/* DSP_BOOT_CONFIG */
+    case 0x1c:	/* DSP_MPUI_CONFIG */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_mpui_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mpui_read,
+};
+
+static CPUWriteMemoryFunc * const omap_mpui_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mpui_write,
+};
+
+static void omap_mpui_reset(struct omap_mpu_state_s *s)
+{
+    s->mpui_ctrl = 0x0003ff1b;
+}
+
+static void omap_mpui_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_mpui_readfn,
+                    omap_mpui_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    omap_mpui_reset(mpu);
+}
+
+/* TIPB Bridges */
+struct omap_tipb_bridge_s {
+    qemu_irq abort;
+
+    int width_intr;
+    uint16_t control;
+    uint16_t alloc;
+    uint16_t buffer;
+    uint16_t enh_control;
+};
+
+static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* TIPB_CNTL */
+        return s->control;
+    case 0x04:	/* TIPB_BUS_ALLOC */
+        return s->alloc;
+    case 0x08:	/* MPU_TIPB_CNTL */
+        return s->buffer;
+    case 0x0c:	/* ENHANCED_TIPB_CNTL */
+        return s->enh_control;
+    case 0x10:	/* ADDRESS_DBG */
+    case 0x14:	/* DATA_DEBUG_LOW */
+    case 0x18:	/* DATA_DEBUG_HIGH */
+        return 0xffff;
+    case 0x1c:	/* DEBUG_CNTR_SIG */
+        return 0x00f8;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* TIPB_CNTL */
+        s->control = value & 0xffff;
+        break;
+
+    case 0x04:	/* TIPB_BUS_ALLOC */
+        s->alloc = value & 0x003f;
+        break;
+
+    case 0x08:	/* MPU_TIPB_CNTL */
+        s->buffer = value & 0x0003;
+        break;
+
+    case 0x0c:	/* ENHANCED_TIPB_CNTL */
+        s->width_intr = !(value & 2);
+        s->enh_control = value & 0x000f;
+        break;
+
+    case 0x10:	/* ADDRESS_DBG */
+    case 0x14:	/* DATA_DEBUG_LOW */
+    case 0x18:	/* DATA_DEBUG_HIGH */
+    case 0x1c:	/* DEBUG_CNTR_SIG */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_tipb_bridge_readfn[] = {
+    omap_badwidth_read16,
+    omap_tipb_bridge_read,
+    omap_tipb_bridge_read,
+};
+
+static CPUWriteMemoryFunc * const omap_tipb_bridge_writefn[] = {
+    omap_badwidth_write16,
+    omap_tipb_bridge_write,
+    omap_tipb_bridge_write,
+};
+
+static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
+{
+    s->control = 0xffff;
+    s->alloc = 0x0009;
+    s->buffer = 0x0000;
+    s->enh_control = 0x000f;
+}
+
+static struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
+                qemu_irq abort_irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
+            qemu_mallocz(sizeof(struct omap_tipb_bridge_s));
+
+    s->abort = abort_irq;
+    omap_tipb_bridge_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn,
+                    omap_tipb_bridge_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* Dummy Traffic Controller's Memory Interface */
+static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    uint32_t ret;
+
+    switch (addr) {
+    case 0x00:	/* IMIF_PRIO */
+    case 0x04:	/* EMIFS_PRIO */
+    case 0x08:	/* EMIFF_PRIO */
+    case 0x0c:	/* EMIFS_CONFIG */
+    case 0x10:	/* EMIFS_CS0_CONFIG */
+    case 0x14:	/* EMIFS_CS1_CONFIG */
+    case 0x18:	/* EMIFS_CS2_CONFIG */
+    case 0x1c:	/* EMIFS_CS3_CONFIG */
+    case 0x24:	/* EMIFF_MRS */
+    case 0x28:	/* TIMEOUT1 */
+    case 0x2c:	/* TIMEOUT2 */
+    case 0x30:	/* TIMEOUT3 */
+    case 0x3c:	/* EMIFF_SDRAM_CONFIG_2 */
+    case 0x40:	/* EMIFS_CFG_DYN_WAIT */
+        return s->tcmi_regs[addr >> 2];
+
+    case 0x20:	/* EMIFF_SDRAM_CONFIG */
+        ret = s->tcmi_regs[addr >> 2];
+        s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */
+        /* XXX: We can try using the VGA_DIRTY flag for this */
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* IMIF_PRIO */
+    case 0x04:	/* EMIFS_PRIO */
+    case 0x08:	/* EMIFF_PRIO */
+    case 0x10:	/* EMIFS_CS0_CONFIG */
+    case 0x14:	/* EMIFS_CS1_CONFIG */
+    case 0x18:	/* EMIFS_CS2_CONFIG */
+    case 0x1c:	/* EMIFS_CS3_CONFIG */
+    case 0x20:	/* EMIFF_SDRAM_CONFIG */
+    case 0x24:	/* EMIFF_MRS */
+    case 0x28:	/* TIMEOUT1 */
+    case 0x2c:	/* TIMEOUT2 */
+    case 0x30:	/* TIMEOUT3 */
+    case 0x3c:	/* EMIFF_SDRAM_CONFIG_2 */
+    case 0x40:	/* EMIFS_CFG_DYN_WAIT */
+        s->tcmi_regs[addr >> 2] = value;
+        break;
+    case 0x0c:	/* EMIFS_CONFIG */
+        s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_tcmi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_tcmi_read,
+};
+
+static CPUWriteMemoryFunc * const omap_tcmi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_tcmi_write,
+};
+
+static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
+{
+    mpu->tcmi_regs[0x00 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x04 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x08 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x0c >> 2] = 0x00000010;
+    mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x20 >> 2] = 0x00618800;
+    mpu->tcmi_regs[0x24 >> 2] = 0x00000037;
+    mpu->tcmi_regs[0x28 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x2c >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x30 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x3c >> 2] = 0x00000003;
+    mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
+}
+
+static void omap_tcmi_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_tcmi_readfn,
+                    omap_tcmi_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+    omap_tcmi_reset(mpu);
+}
+
+/* Digital phase-locked loops control */
+static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
+{
+    struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
+
+    if (addr == 0x00)	/* CTL_REG */
+        return s->mode;
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
+    uint16_t diff;
+    static const int bypass_div[4] = { 1, 2, 4, 4 };
+    int div, mult;
+
+    if (addr == 0x00) {	/* CTL_REG */
+        /* See omap_ulpd_pm_write() too */
+        diff = s->mode & value;
+        s->mode = value & 0x2fff;
+        if (diff & (0x3ff << 2)) {
+            if (value & (1 << 4)) {			/* PLL_ENABLE */
+                div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
+                mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
+            } else {
+                div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
+                mult = 1;
+            }
+            omap_clk_setrate(s->dpll, div, mult);
+        }
+
+        /* Enter the desired mode.  */
+        s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1);
+
+        /* Act as if the lock is restored.  */
+        s->mode |= 2;
+    } else {
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_dpll_readfn[] = {
+    omap_badwidth_read16,
+    omap_dpll_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_dpll_writefn[] = {
+    omap_badwidth_write16,
+    omap_dpll_write,
+    omap_badwidth_write16,
+};
+
+static void omap_dpll_reset(struct dpll_ctl_s *s)
+{
+    s->mode = 0x2002;
+    omap_clk_setrate(s->dpll, 1, 1);
+}
+
+static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
+                omap_clk clk)
+{
+    int iomemtype = cpu_register_io_memory(omap_dpll_readfn,
+                    omap_dpll_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    s->dpll = clk;
+    omap_dpll_reset(s);
+
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+}
+
+/* MPU Clock/Reset/Power Mode Control */
+static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* ARM_CKCTL */
+        return s->clkm.arm_ckctl;
+
+    case 0x04:	/* ARM_IDLECT1 */
+        return s->clkm.arm_idlect1;
+
+    case 0x08:	/* ARM_IDLECT2 */
+        return s->clkm.arm_idlect2;
+
+    case 0x0c:	/* ARM_EWUPCT */
+        return s->clkm.arm_ewupct;
+
+    case 0x10:	/* ARM_RSTCT1 */
+        return s->clkm.arm_rstct1;
+
+    case 0x14:	/* ARM_RSTCT2 */
+        return s->clkm.arm_rstct2;
+
+    case 0x18:	/* ARM_SYSST */
+        return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start;
+
+    case 0x1c:	/* ARM_CKOUT1 */
+        return s->clkm.arm_ckout1;
+
+    case 0x20:	/* ARM_CKOUT2 */
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (diff & (1 << 14)) {				/* ARM_INTHCK_SEL */
+        if (value & (1 << 14))
+            /* Reserved */;
+        else {
+            clk = omap_findclk(s, "arminth_ck");
+            omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
+        }
+    }
+    if (diff & (1 << 12)) {				/* ARM_TIMXO */
+        clk = omap_findclk(s, "armtim_ck");
+        if (value & (1 << 12))
+            omap_clk_reparent(clk, omap_findclk(s, "clkin"));
+        else
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
+    }
+    /* XXX: en_dspck */
+    if (diff & (3 << 10)) {				/* DSPMMUDIV */
+        clk = omap_findclk(s, "dspmmu_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1);
+    }
+    if (diff & (3 << 8)) {				/* TCDIV */
+        clk = omap_findclk(s, "tc_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1);
+    }
+    if (diff & (3 << 6)) {				/* DSPDIV */
+        clk = omap_findclk(s, "dsp_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1);
+    }
+    if (diff & (3 << 4)) {				/* ARMDIV */
+        clk = omap_findclk(s, "arm_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1);
+    }
+    if (diff & (3 << 2)) {				/* LCDDIV */
+        clk = omap_findclk(s, "lcd_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1);
+    }
+    if (diff & (3 << 0)) {				/* PERDIV */
+        clk = omap_findclk(s, "armper_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1);
+    }
+}
+
+static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (value & (1 << 11))				/* SETARM_IDLE */
+        cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+    if (!(value & (1 << 10)))				/* WKUP_MODE */
+        qemu_system_shutdown_request();	/* XXX: disable wakeup from IRQ */
+
+#define SET_CANIDLE(clock, bit)				\
+    if (diff & (1 << bit)) {				\
+        clk = omap_findclk(s, clock);			\
+        omap_clk_canidle(clk, (value >> bit) & 1);	\
+    }
+    SET_CANIDLE("mpuwd_ck", 0)				/* IDLWDT_ARM */
+    SET_CANIDLE("armxor_ck", 1)				/* IDLXORP_ARM */
+    SET_CANIDLE("mpuper_ck", 2)				/* IDLPER_ARM */
+    SET_CANIDLE("lcd_ck", 3)				/* IDLLCD_ARM */
+    SET_CANIDLE("lb_ck", 4)				/* IDLLB_ARM */
+    SET_CANIDLE("hsab_ck", 5)				/* IDLHSAB_ARM */
+    SET_CANIDLE("tipb_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("dma_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("tc_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("dpll1", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("dpll2", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("dpll3", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("mpui_ck", 8)				/* IDLAPI_ARM */
+    SET_CANIDLE("armtim_ck", 9)				/* IDLTIM_ARM */
+}
+
+static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+#define SET_ONOFF(clock, bit)				\
+    if (diff & (1 << bit)) {				\
+        clk = omap_findclk(s, clock);			\
+        omap_clk_onoff(clk, (value >> bit) & 1);	\
+    }
+    SET_ONOFF("mpuwd_ck", 0)				/* EN_WDTCK */
+    SET_ONOFF("armxor_ck", 1)				/* EN_XORPCK */
+    SET_ONOFF("mpuper_ck", 2)				/* EN_PERCK */
+    SET_ONOFF("lcd_ck", 3)				/* EN_LCDCK */
+    SET_ONOFF("lb_ck", 4)				/* EN_LBCK */
+    SET_ONOFF("hsab_ck", 5)				/* EN_HSABCK */
+    SET_ONOFF("mpui_ck", 6)				/* EN_APICK */
+    SET_ONOFF("armtim_ck", 7)				/* EN_TIMCK */
+    SET_CANIDLE("dma_ck", 8)				/* DMACK_REQ */
+    SET_ONOFF("arm_gpio_ck", 9)				/* EN_GPIOCK */
+    SET_ONOFF("lbfree_ck", 10)				/* EN_LBFREECK */
+}
+
+static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (diff & (3 << 4)) {				/* TCLKOUT */
+        clk = omap_findclk(s, "tclk_out");
+        switch ((value >> 4) & 3) {
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen3"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
+            omap_clk_onoff(clk, 1);
+            break;
+        default:
+            omap_clk_onoff(clk, 0);
+        }
+    }
+    if (diff & (3 << 2)) {				/* DCLKOUT */
+        clk = omap_findclk(s, "dclk_out");
+        switch ((value >> 2) & 3) {
+        case 0:
+            omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck"));
+            break;
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen2"));
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "dsp_ck"));
+            break;
+        case 3:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
+            break;
+        }
+    }
+    if (diff & (3 << 0)) {				/* ACLKOUT */
+        clk = omap_findclk(s, "aclk_out");
+        switch ((value >> 0) & 3) {
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "arm_ck"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 3:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
+            omap_clk_onoff(clk, 1);
+            break;
+        default:
+            omap_clk_onoff(clk, 0);
+        }
+    }
+}
+
+static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    uint16_t diff;
+    omap_clk clk;
+    static const char *clkschemename[8] = {
+        "fully synchronous", "fully asynchronous", "synchronous scalable",
+        "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
+    };
+
+    switch (addr) {
+    case 0x00:	/* ARM_CKCTL */
+        diff = s->clkm.arm_ckctl ^ value;
+        s->clkm.arm_ckctl = value & 0x7fff;
+        omap_clkm_ckctl_update(s, diff, value);
+        return;
+
+    case 0x04:	/* ARM_IDLECT1 */
+        diff = s->clkm.arm_idlect1 ^ value;
+        s->clkm.arm_idlect1 = value & 0x0fff;
+        omap_clkm_idlect1_update(s, diff, value);
+        return;
+
+    case 0x08:	/* ARM_IDLECT2 */
+        diff = s->clkm.arm_idlect2 ^ value;
+        s->clkm.arm_idlect2 = value & 0x07ff;
+        omap_clkm_idlect2_update(s, diff, value);
+        return;
+
+    case 0x0c:	/* ARM_EWUPCT */
+        s->clkm.arm_ewupct = value & 0x003f;
+        return;
+
+    case 0x10:	/* ARM_RSTCT1 */
+        diff = s->clkm.arm_rstct1 ^ value;
+        s->clkm.arm_rstct1 = value & 0x0007;
+        if (value & 9) {
+            qemu_system_reset_request();
+            s->clkm.cold_start = 0xa;
+        }
+        if (diff & ~value & 4) {				/* DSP_RST */
+            omap_mpui_reset(s);
+            omap_tipb_bridge_reset(s->private_tipb);
+            omap_tipb_bridge_reset(s->public_tipb);
+        }
+        if (diff & 2) {						/* DSP_EN */
+            clk = omap_findclk(s, "dsp_ck");
+            omap_clk_canidle(clk, (~value >> 1) & 1);
+        }
+        return;
+
+    case 0x14:	/* ARM_RSTCT2 */
+        s->clkm.arm_rstct2 = value & 0x0001;
+        return;
+
+    case 0x18:	/* ARM_SYSST */
+        if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) {
+            s->clkm.clocking_scheme = (value >> 11) & 7;
+            printf("%s: clocking scheme set to %s\n", __FUNCTION__,
+                            clkschemename[s->clkm.clocking_scheme]);
+        }
+        s->clkm.cold_start &= value & 0x3f;
+        return;
+
+    case 0x1c:	/* ARM_CKOUT1 */
+        diff = s->clkm.arm_ckout1 ^ value;
+        s->clkm.arm_ckout1 = value & 0x003f;
+        omap_clkm_ckout1_update(s, diff, value);
+        return;
+
+    case 0x20:	/* ARM_CKOUT2 */
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_clkm_readfn[] = {
+    omap_badwidth_read16,
+    omap_clkm_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_clkm_writefn[] = {
+    omap_badwidth_write16,
+    omap_clkm_write,
+    omap_badwidth_write16,
+};
+
+static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x04:	/* DSP_IDLECT1 */
+        return s->clkm.dsp_idlect1;
+
+    case 0x08:	/* DSP_IDLECT2 */
+        return s->clkm.dsp_idlect2;
+
+    case 0x14:	/* DSP_RSTCT2 */
+        return s->clkm.dsp_rstct2;
+
+    case 0x18:	/* DSP_SYSST */
+        return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start |
+                (s->env->halted << 6);	/* Quite useless... */
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    SET_CANIDLE("dspxor_ck", 1);			/* IDLXORP_DSP */
+}
+
+static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    SET_ONOFF("dspxor_ck", 1);				/* EN_XORPCK */
+}
+
+static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    uint16_t diff;
+
+    switch (addr) {
+    case 0x04:	/* DSP_IDLECT1 */
+        diff = s->clkm.dsp_idlect1 ^ value;
+        s->clkm.dsp_idlect1 = value & 0x01f7;
+        omap_clkdsp_idlect1_update(s, diff, value);
+        break;
+
+    case 0x08:	/* DSP_IDLECT2 */
+        s->clkm.dsp_idlect2 = value & 0x0037;
+        diff = s->clkm.dsp_idlect1 ^ value;
+        omap_clkdsp_idlect2_update(s, diff, value);
+        break;
+
+    case 0x14:	/* DSP_RSTCT2 */
+        s->clkm.dsp_rstct2 = value & 0x0001;
+        break;
+
+    case 0x18:	/* DSP_SYSST */
+        s->clkm.cold_start &= value & 0x3f;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_clkdsp_readfn[] = {
+    omap_badwidth_read16,
+    omap_clkdsp_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_clkdsp_writefn[] = {
+    omap_badwidth_write16,
+    omap_clkdsp_write,
+    omap_badwidth_write16,
+};
+
+static void omap_clkm_reset(struct omap_mpu_state_s *s)
+{
+    if (s->wdt && s->wdt->reset)
+        s->clkm.cold_start = 0x6;
+    s->clkm.clocking_scheme = 0;
+    omap_clkm_ckctl_update(s, ~0, 0x3000);
+    s->clkm.arm_ckctl = 0x3000;
+    omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400);
+    s->clkm.arm_idlect1 = 0x0400;
+    omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100);
+    s->clkm.arm_idlect2 = 0x0100;
+    s->clkm.arm_ewupct = 0x003f;
+    s->clkm.arm_rstct1 = 0x0000;
+    s->clkm.arm_rstct2 = 0x0000;
+    s->clkm.arm_ckout1 = 0x0015;
+    s->clkm.dpll1_mode = 0x2002;
+    omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040);
+    s->clkm.dsp_idlect1 = 0x0040;
+    omap_clkdsp_idlect2_update(s, ~0, 0x0000);
+    s->clkm.dsp_idlect2 = 0x0000;
+    s->clkm.dsp_rstct2 = 0x0000;
+}
+
+static void omap_clkm_init(target_phys_addr_t mpu_base,
+                target_phys_addr_t dsp_base, struct omap_mpu_state_s *s)
+{
+    int iomemtype[2] = {
+        cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s,
+                               DEVICE_NATIVE_ENDIAN),
+        cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s,
+                               DEVICE_NATIVE_ENDIAN),
+    };
+
+    s->clkm.arm_idlect1 = 0x03ff;
+    s->clkm.arm_idlect2 = 0x0100;
+    s->clkm.dsp_idlect1 = 0x0002;
+    omap_clkm_reset(s);
+    s->clkm.cold_start = 0x3a;
+
+    cpu_register_physical_memory(mpu_base, 0x100, iomemtype[0]);
+    cpu_register_physical_memory(dsp_base, 0x1000, iomemtype[1]);
+}
+
+/* MPU I/O */
+struct omap_mpuio_s {
+    qemu_irq irq;
+    qemu_irq kbd_irq;
+    qemu_irq *in;
+    qemu_irq handler[16];
+    qemu_irq wakeup;
+
+    uint16_t inputs;
+    uint16_t outputs;
+    uint16_t dir;
+    uint16_t edge;
+    uint16_t mask;
+    uint16_t ints;
+
+    uint16_t debounce;
+    uint16_t latch;
+    uint8_t event;
+
+    uint8_t buttons[5];
+    uint8_t row_latch;
+    uint8_t cols;
+    int kbd_mask;
+    int clk;
+};
+
+static void omap_mpuio_set(void *opaque, int line, int level)
+{
+    struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
+    uint16_t prev = s->inputs;
+
+    if (level)
+        s->inputs |= 1 << line;
+    else
+        s->inputs &= ~(1 << line);
+
+    if (((1 << line) & s->dir & ~s->mask) && s->clk) {
+        if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) {
+            s->ints |= 1 << line;
+            qemu_irq_raise(s->irq);
+            /* TODO: wakeup */
+        }
+        if ((s->event & (1 << 0)) &&		/* SET_GPIO_EVENT_MODE */
+                (s->event >> 1) == line)	/* PIN_SELECT */
+            s->latch = s->inputs;
+    }
+}
+
+static void omap_mpuio_kbd_update(struct omap_mpuio_s *s)
+{
+    int i;
+    uint8_t *row, rows = 0, cols = ~s->cols;
+
+    for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1)
+        if (*row & cols)
+            rows |= i;
+
+    qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk);
+    s->row_latch = ~rows;
+}
+
+static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x00:	/* INPUT_LATCH */
+        return s->inputs;
+
+    case 0x04:	/* OUTPUT_REG */
+        return s->outputs;
+
+    case 0x08:	/* IO_CNTL */
+        return s->dir;
+
+    case 0x10:	/* KBR_LATCH */
+        return s->row_latch;
+
+    case 0x14:	/* KBC_REG */
+        return s->cols;
+
+    case 0x18:	/* GPIO_EVENT_MODE_REG */
+        return s->event;
+
+    case 0x1c:	/* GPIO_INT_EDGE_REG */
+        return s->edge;
+
+    case 0x20:	/* KBD_INT */
+        return (~s->row_latch & 0x1f) && !s->kbd_mask;
+
+    case 0x24:	/* GPIO_INT */
+        ret = s->ints;
+        s->ints &= s->mask;
+        if (ret)
+            qemu_irq_lower(s->irq);
+        return ret;
+
+    case 0x28:	/* KBD_MASKIT */
+        return s->kbd_mask;
+
+    case 0x2c:	/* GPIO_MASKIT */
+        return s->mask;
+
+    case 0x30:	/* GPIO_DEBOUNCING_REG */
+        return s->debounce;
+
+    case 0x34:	/* GPIO_LATCH_REG */
+        return s->latch;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mpuio_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t diff;
+    int ln;
+
+    switch (offset) {
+    case 0x04:	/* OUTPUT_REG */
+        diff = (s->outputs ^ value) & ~s->dir;
+        s->outputs = value;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x08:	/* IO_CNTL */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x14:	/* KBC_REG */
+        s->cols = value;
+        omap_mpuio_kbd_update(s);
+        break;
+
+    case 0x18:	/* GPIO_EVENT_MODE_REG */
+        s->event = value & 0x1f;
+        break;
+
+    case 0x1c:	/* GPIO_INT_EDGE_REG */
+        s->edge = value;
+        break;
+
+    case 0x28:	/* KBD_MASKIT */
+        s->kbd_mask = value & 1;
+        omap_mpuio_kbd_update(s);
+        break;
+
+    case 0x2c:	/* GPIO_MASKIT */
+        s->mask = value;
+        break;
+
+    case 0x30:	/* GPIO_DEBOUNCING_REG */
+        s->debounce = value & 0x1ff;
+        break;
+
+    case 0x00:	/* INPUT_LATCH */
+    case 0x10:	/* KBR_LATCH */
+    case 0x20:	/* KBD_INT */
+    case 0x24:	/* GPIO_INT */
+    case 0x34:	/* GPIO_LATCH_REG */
+        OMAP_RO_REG(addr);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_mpuio_readfn[] = {
+    omap_badwidth_read16,
+    omap_mpuio_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_mpuio_writefn[] = {
+    omap_badwidth_write16,
+    omap_mpuio_write,
+    omap_badwidth_write16,
+};
+
+static void omap_mpuio_reset(struct omap_mpuio_s *s)
+{
+    s->inputs = 0;
+    s->outputs = 0;
+    s->dir = ~0;
+    s->event = 0;
+    s->edge = 0;
+    s->kbd_mask = 0;
+    s->mask = 0;
+    s->debounce = 0;
+    s->latch = 0;
+    s->ints = 0;
+    s->row_latch = 0x1f;
+    s->clk = 1;
+}
+
+static void omap_mpuio_onoff(void *opaque, int line, int on)
+{
+    struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
+
+    s->clk = on;
+    if (on)
+        omap_mpuio_kbd_update(s);
+}
+
+struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+                qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
+                omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mpuio_s *s = (struct omap_mpuio_s *)
+            qemu_mallocz(sizeof(struct omap_mpuio_s));
+
+    s->irq = gpio_int;
+    s->kbd_irq = kbd_int;
+    s->wakeup = wakeup;
+    s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16);
+    omap_mpuio_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_mpuio_readfn,
+                    omap_mpuio_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]);
+
+    return s;
+}
+
+qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s)
+{
+    return s->in;
+}
+
+void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler)
+{
+    if (line >= 16 || line < 0)
+        hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
+    s->handler[line] = handler;
+}
+
+void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down)
+{
+    if (row >= 5 || row < 0)
+        hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row);
+
+    if (down)
+        s->buttons[row] |= 1 << col;
+    else
+        s->buttons[row] &= ~(1 << col);
+
+    omap_mpuio_kbd_update(s);
+}
+
+/* MicroWire Interface */
+struct omap_uwire_s {
+    qemu_irq txirq;
+    qemu_irq rxirq;
+    qemu_irq txdrq;
+
+    uint16_t txbuf;
+    uint16_t rxbuf;
+    uint16_t control;
+    uint16_t setup[5];
+
+    uWireSlave *chip[4];
+};
+
+static void omap_uwire_transfer_start(struct omap_uwire_s *s)
+{
+    int chipselect = (s->control >> 10) & 3;		/* INDEX */
+    uWireSlave *slave = s->chip[chipselect];
+
+    if ((s->control >> 5) & 0x1f) {			/* NB_BITS_WR */
+        if (s->control & (1 << 12))			/* CS_CMD */
+            if (slave && slave->send)
+                slave->send(slave->opaque,
+                                s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
+        s->control &= ~(1 << 14);			/* CSRB */
+        /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
+         * a DRQ.  When is the level IRQ supposed to be reset?  */
+    }
+
+    if ((s->control >> 0) & 0x1f) {			/* NB_BITS_RD */
+        if (s->control & (1 << 12))			/* CS_CMD */
+            if (slave && slave->receive)
+                s->rxbuf = slave->receive(slave->opaque);
+        s->control |= 1 << 15;				/* RDRB */
+        /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
+         * a DRQ.  When is the level IRQ supposed to be reset?  */
+    }
+}
+
+static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* RDR */
+        s->control &= ~(1 << 15);			/* RDRB */
+        return s->rxbuf;
+
+    case 0x04:	/* CSR */
+        return s->control;
+
+    case 0x08:	/* SR1 */
+        return s->setup[0];
+    case 0x0c:	/* SR2 */
+        return s->setup[1];
+    case 0x10:	/* SR3 */
+        return s->setup[2];
+    case 0x14:	/* SR4 */
+        return s->setup[3];
+    case 0x18:	/* SR5 */
+        return s->setup[4];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_uwire_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* TDR */
+        s->txbuf = value;				/* TD */
+        if ((s->setup[4] & (1 << 2)) &&			/* AUTO_TX_EN */
+                        ((s->setup[4] & (1 << 3)) ||	/* CS_TOGGLE_TX_EN */
+                         (s->control & (1 << 12)))) {	/* CS_CMD */
+            s->control |= 1 << 14;			/* CSRB */
+            omap_uwire_transfer_start(s);
+        }
+        break;
+
+    case 0x04:	/* CSR */
+        s->control = value & 0x1fff;
+        if (value & (1 << 13))				/* START */
+            omap_uwire_transfer_start(s);
+        break;
+
+    case 0x08:	/* SR1 */
+        s->setup[0] = value & 0x003f;
+        break;
+
+    case 0x0c:	/* SR2 */
+        s->setup[1] = value & 0x0fc0;
+        break;
+
+    case 0x10:	/* SR3 */
+        s->setup[2] = value & 0x0003;
+        break;
+
+    case 0x14:	/* SR4 */
+        s->setup[3] = value & 0x0001;
+        break;
+
+    case 0x18:	/* SR5 */
+        s->setup[4] = value & 0x000f;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_uwire_readfn[] = {
+    omap_badwidth_read16,
+    omap_uwire_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_uwire_writefn[] = {
+    omap_badwidth_write16,
+    omap_uwire_write,
+    omap_badwidth_write16,
+};
+
+static void omap_uwire_reset(struct omap_uwire_s *s)
+{
+    s->control = 0;
+    s->setup[0] = 0;
+    s->setup[1] = 0;
+    s->setup[2] = 0;
+    s->setup[3] = 0;
+    s->setup[4] = 0;
+}
+
+struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
+                qemu_irq *irq, qemu_irq dma, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_uwire_s *s = (struct omap_uwire_s *)
+            qemu_mallocz(sizeof(struct omap_uwire_s));
+
+    s->txirq = irq[0];
+    s->rxirq = irq[1];
+    s->txdrq = dma;
+    omap_uwire_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_uwire_readfn,
+                    omap_uwire_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    return s;
+}
+
+void omap_uwire_attach(struct omap_uwire_s *s,
+                uWireSlave *slave, int chipselect)
+{
+    if (chipselect < 0 || chipselect > 3) {
+        fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
+        exit(-1);
+    }
+
+    s->chip[chipselect] = slave;
+}
+
+/* Pseudonoise Pulse-Width Light Modulator */
+static void omap_pwl_update(struct omap_mpu_state_s *s)
+{
+    int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0;
+
+    if (output != s->pwl.output) {
+        s->pwl.output = output;
+        printf("%s: Backlight now at %i/256\n", __FUNCTION__, output);
+    }
+}
+
+static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* PWL_LEVEL */
+        return s->pwl.level;
+    case 0x04:	/* PWL_CTRL */
+        return s->pwl.enable;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* PWL_LEVEL */
+        s->pwl.level = value;
+        omap_pwl_update(s);
+        break;
+    case 0x04:	/* PWL_CTRL */
+        s->pwl.enable = value & 1;
+        omap_pwl_update(s);
+        break;
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_pwl_readfn[] = {
+    omap_pwl_read,
+    omap_badwidth_read8,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_pwl_writefn[] = {
+    omap_pwl_write,
+    omap_badwidth_write8,
+    omap_badwidth_write8,
+};
+
+static void omap_pwl_reset(struct omap_mpu_state_s *s)
+{
+    s->pwl.output = 0;
+    s->pwl.level = 0;
+    s->pwl.enable = 0;
+    s->pwl.clk = 1;
+    omap_pwl_update(s);
+}
+
+static void omap_pwl_clk_update(void *opaque, int line, int on)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    s->pwl.clk = on;
+    omap_pwl_update(s);
+}
+
+static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+                omap_clk clk)
+{
+    int iomemtype;
+
+    omap_pwl_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_pwl_readfn,
+                    omap_pwl_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
+}
+
+/* Pulse-Width Tone module */
+static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* FRC */
+        return s->pwt.frc;
+    case 0x04:	/* VCR */
+        return s->pwt.vrc;
+    case 0x08:	/* GCR */
+        return s->pwt.gcr;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* FRC */
+        s->pwt.frc = value & 0x3f;
+        break;
+    case 0x04:	/* VRC */
+        if ((value ^ s->pwt.vrc) & 1) {
+            if (value & 1)
+                printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
+                                /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
+                                ((omap_clk_getrate(s->pwt.clk) >> 3) /
+                                 /* Pre-multiplexer divider */
+                                 ((s->pwt.gcr & 2) ? 1 : 154) /
+                                 /* Octave multiplexer */
+                                 (2 << (value & 3)) *
+                                 /* 101/107 divider */
+                                 ((value & (1 << 2)) ? 101 : 107) *
+                                 /*  49/55 divider */
+                                 ((value & (1 << 3)) ?  49 : 55) *
+                                 /*  50/63 divider */
+                                 ((value & (1 << 4)) ?  50 : 63) *
+                                 /*  80/127 divider */
+                                 ((value & (1 << 5)) ?  80 : 127) /
+                                 (107 * 55 * 63 * 127)));
+            else
+                printf("%s: silence!\n", __FUNCTION__);
+        }
+        s->pwt.vrc = value & 0x7f;
+        break;
+    case 0x08:	/* GCR */
+        s->pwt.gcr = value & 3;
+        break;
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_pwt_readfn[] = {
+    omap_pwt_read,
+    omap_badwidth_read8,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_pwt_writefn[] = {
+    omap_pwt_write,
+    omap_badwidth_write8,
+    omap_badwidth_write8,
+};
+
+static void omap_pwt_reset(struct omap_mpu_state_s *s)
+{
+    s->pwt.frc = 0;
+    s->pwt.vrc = 0;
+    s->pwt.gcr = 0;
+}
+
+static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+                omap_clk clk)
+{
+    int iomemtype;
+
+    s->pwt.clk = clk;
+    omap_pwt_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_pwt_readfn,
+                    omap_pwt_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+}
+
+/* Real-time Clock module */
+struct omap_rtc_s {
+    qemu_irq irq;
+    qemu_irq alarm;
+    QEMUTimer *clk;
+
+    uint8_t interrupts;
+    uint8_t status;
+    int16_t comp_reg;
+    int running;
+    int pm_am;
+    int auto_comp;
+    int round;
+    struct tm alarm_tm;
+    time_t alarm_ti;
+
+    struct tm current_tm;
+    time_t ti;
+    uint64_t tick;
+};
+
+static void omap_rtc_interrupts_update(struct omap_rtc_s *s)
+{
+    /* s->alarm is level-triggered */
+    qemu_set_irq(s->alarm, (s->status >> 6) & 1);
+}
+
+static void omap_rtc_alarm_update(struct omap_rtc_s *s)
+{
+    s->alarm_ti = mktimegm(&s->alarm_tm);
+    if (s->alarm_ti == -1)
+        printf("%s: conversion failed\n", __FUNCTION__);
+}
+
+static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint8_t i;
+
+    switch (offset) {
+    case 0x00:	/* SECONDS_REG */
+        return to_bcd(s->current_tm.tm_sec);
+
+    case 0x04:	/* MINUTES_REG */
+        return to_bcd(s->current_tm.tm_min);
+
+    case 0x08:	/* HOURS_REG */
+        if (s->pm_am)
+            return ((s->current_tm.tm_hour > 11) << 7) |
+                    to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1);
+        else
+            return to_bcd(s->current_tm.tm_hour);
+
+    case 0x0c:	/* DAYS_REG */
+        return to_bcd(s->current_tm.tm_mday);
+
+    case 0x10:	/* MONTHS_REG */
+        return to_bcd(s->current_tm.tm_mon + 1);
+
+    case 0x14:	/* YEARS_REG */
+        return to_bcd(s->current_tm.tm_year % 100);
+
+    case 0x18:	/* WEEK_REG */
+        return s->current_tm.tm_wday;
+
+    case 0x20:	/* ALARM_SECONDS_REG */
+        return to_bcd(s->alarm_tm.tm_sec);
+
+    case 0x24:	/* ALARM_MINUTES_REG */
+        return to_bcd(s->alarm_tm.tm_min);
+
+    case 0x28:	/* ALARM_HOURS_REG */
+        if (s->pm_am)
+            return ((s->alarm_tm.tm_hour > 11) << 7) |
+                    to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1);
+        else
+            return to_bcd(s->alarm_tm.tm_hour);
+
+    case 0x2c:	/* ALARM_DAYS_REG */
+        return to_bcd(s->alarm_tm.tm_mday);
+
+    case 0x30:	/* ALARM_MONTHS_REG */
+        return to_bcd(s->alarm_tm.tm_mon + 1);
+
+    case 0x34:	/* ALARM_YEARS_REG */
+        return to_bcd(s->alarm_tm.tm_year % 100);
+
+    case 0x40:	/* RTC_CTRL_REG */
+        return (s->pm_am << 3) | (s->auto_comp << 2) |
+                (s->round << 1) | s->running;
+
+    case 0x44:	/* RTC_STATUS_REG */
+        i = s->status;
+        s->status &= ~0x3d;
+        return i;
+
+    case 0x48:	/* RTC_INTERRUPTS_REG */
+        return s->interrupts;
+
+    case 0x4c:	/* RTC_COMP_LSB_REG */
+        return ((uint16_t) s->comp_reg) & 0xff;
+
+    case 0x50:	/* RTC_COMP_MSB_REG */
+        return ((uint16_t) s->comp_reg) >> 8;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    struct tm new_tm;
+    time_t ti[2];
+
+    switch (offset) {
+    case 0x00:	/* SECONDS_REG */
+#ifdef ALMDEBUG
+        printf("RTC SEC_REG <-- %02x\n", value);
+#endif
+        s->ti -= s->current_tm.tm_sec;
+        s->ti += from_bcd(value);
+        return;
+
+    case 0x04:	/* MINUTES_REG */
+#ifdef ALMDEBUG
+        printf("RTC MIN_REG <-- %02x\n", value);
+#endif
+        s->ti -= s->current_tm.tm_min * 60;
+        s->ti += from_bcd(value) * 60;
+        return;
+
+    case 0x08:	/* HOURS_REG */
+#ifdef ALMDEBUG
+        printf("RTC HRS_REG <-- %02x\n", value);
+#endif
+        s->ti -= s->current_tm.tm_hour * 3600;
+        if (s->pm_am) {
+            s->ti += (from_bcd(value & 0x3f) & 12) * 3600;
+            s->ti += ((value >> 7) & 1) * 43200;
+        } else
+            s->ti += from_bcd(value & 0x3f) * 3600;
+        return;
+
+    case 0x0c:	/* DAYS_REG */
+#ifdef ALMDEBUG
+        printf("RTC DAY_REG <-- %02x\n", value);
+#endif
+        s->ti -= s->current_tm.tm_mday * 86400;
+        s->ti += from_bcd(value) * 86400;
+        return;
+
+    case 0x10:	/* MONTHS_REG */
+#ifdef ALMDEBUG
+        printf("RTC MTH_REG <-- %02x\n", value);
+#endif
+        memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
+        new_tm.tm_mon = from_bcd(value);
+        ti[0] = mktimegm(&s->current_tm);
+        ti[1] = mktimegm(&new_tm);
+
+        if (ti[0] != -1 && ti[1] != -1) {
+            s->ti -= ti[0];
+            s->ti += ti[1];
+        } else {
+            /* A less accurate version */
+            s->ti -= s->current_tm.tm_mon * 2592000;
+            s->ti += from_bcd(value) * 2592000;
+        }
+        return;
+
+    case 0x14:	/* YEARS_REG */
+#ifdef ALMDEBUG
+        printf("RTC YRS_REG <-- %02x\n", value);
+#endif
+        memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
+        new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100);
+        ti[0] = mktimegm(&s->current_tm);
+        ti[1] = mktimegm(&new_tm);
+
+        if (ti[0] != -1 && ti[1] != -1) {
+            s->ti -= ti[0];
+            s->ti += ti[1];
+        } else {
+            /* A less accurate version */
+            s->ti -= (s->current_tm.tm_year % 100) * 31536000;
+            s->ti += from_bcd(value) * 31536000;
+        }
+        return;
+
+    case 0x18:	/* WEEK_REG */
+        return;	/* Ignored */
+
+    case 0x20:	/* ALARM_SECONDS_REG */
+#ifdef ALMDEBUG
+        printf("ALM SEC_REG <-- %02x\n", value);
+#endif
+        s->alarm_tm.tm_sec = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x24:	/* ALARM_MINUTES_REG */
+#ifdef ALMDEBUG
+        printf("ALM MIN_REG <-- %02x\n", value);
+#endif
+        s->alarm_tm.tm_min = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x28:	/* ALARM_HOURS_REG */
+#ifdef ALMDEBUG
+        printf("ALM HRS_REG <-- %02x\n", value);
+#endif
+        if (s->pm_am)
+            s->alarm_tm.tm_hour =
+                    ((from_bcd(value & 0x3f)) % 12) +
+                    ((value >> 7) & 1) * 12;
+        else
+            s->alarm_tm.tm_hour = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x2c:	/* ALARM_DAYS_REG */
+#ifdef ALMDEBUG
+        printf("ALM DAY_REG <-- %02x\n", value);
+#endif
+        s->alarm_tm.tm_mday = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x30:	/* ALARM_MONTHS_REG */
+#ifdef ALMDEBUG
+        printf("ALM MON_REG <-- %02x\n", value);
+#endif
+        s->alarm_tm.tm_mon = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x34:	/* ALARM_YEARS_REG */
+#ifdef ALMDEBUG
+        printf("ALM YRS_REG <-- %02x\n", value);
+#endif
+        s->alarm_tm.tm_year = from_bcd(value);
+        omap_rtc_alarm_update(s);
+        return;
+
+    case 0x40:	/* RTC_CTRL_REG */
+#ifdef ALMDEBUG
+        printf("RTC CONTROL <-- %02x\n", value);
+#endif
+        s->pm_am = (value >> 3) & 1;
+        s->auto_comp = (value >> 2) & 1;
+        s->round = (value >> 1) & 1;
+        s->running = value & 1;
+        s->status &= 0xfd;
+        s->status |= s->running << 1;
+        return;
+
+    case 0x44:	/* RTC_STATUS_REG */
+#ifdef ALMDEBUG
+        printf("RTC STATUSL <-- %02x\n", value);
+#endif
+        s->status &= ~((value & 0xc0) ^ 0x80);
+        omap_rtc_interrupts_update(s);
+        return;
+
+    case 0x48:	/* RTC_INTERRUPTS_REG */
+#ifdef ALMDEBUG
+        printf("RTC INTRS <-- %02x\n", value);
+#endif
+        s->interrupts = value;
+        return;
+
+    case 0x4c:	/* RTC_COMP_LSB_REG */
+#ifdef ALMDEBUG
+        printf("RTC COMPLSB <-- %02x\n", value);
+#endif
+        s->comp_reg &= 0xff00;
+        s->comp_reg |= 0x00ff & value;
+        return;
+
+    case 0x50:	/* RTC_COMP_MSB_REG */
+#ifdef ALMDEBUG
+        printf("RTC COMPMSB <-- %02x\n", value);
+#endif
+        s->comp_reg &= 0x00ff;
+        s->comp_reg |= 0xff00 & (value << 8);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_rtc_readfn[] = {
+    omap_rtc_read,
+    omap_badwidth_read8,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_rtc_writefn[] = {
+    omap_rtc_write,
+    omap_badwidth_write8,
+    omap_badwidth_write8,
+};
+
+static void omap_rtc_tick(void *opaque)
+{
+    struct omap_rtc_s *s = opaque;
+
+    if (s->round) {
+        /* Round to nearest full minute.  */
+        if (s->current_tm.tm_sec < 30)
+            s->ti -= s->current_tm.tm_sec;
+        else
+            s->ti += 60 - s->current_tm.tm_sec;
+
+        s->round = 0;
+    }
+
+    memcpy(&s->current_tm, localtime(&s->ti), sizeof(s->current_tm));
+
+    if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) {
+        s->status |= 0x40;
+        omap_rtc_interrupts_update(s);
+    }
+
+    if (s->interrupts & 0x04)
+        switch (s->interrupts & 3) {
+        case 0:
+            s->status |= 0x04;
+            qemu_irq_pulse(s->irq);
+            break;
+        case 1:
+            if (s->current_tm.tm_sec)
+                break;
+            s->status |= 0x08;
+            qemu_irq_pulse(s->irq);
+            break;
+        case 2:
+            if (s->current_tm.tm_sec || s->current_tm.tm_min)
+                break;
+            s->status |= 0x10;
+            qemu_irq_pulse(s->irq);
+            break;
+        case 3:
+            if (s->current_tm.tm_sec ||
+                            s->current_tm.tm_min || s->current_tm.tm_hour)
+                break;
+            s->status |= 0x20;
+            qemu_irq_pulse(s->irq);
+            break;
+        }
+
+    /* Move on */
+    if (s->running)
+        s->ti ++;
+    s->tick += 1000;
+
+    /*
+     * Every full hour add a rough approximation of the compensation
+     * register to the 32kHz Timer (which drives the RTC) value. 
+     */
+    if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min)
+        s->tick += s->comp_reg * 1000 / 32768;
+
+    qemu_mod_timer(s->clk, s->tick);
+}
+
+static void omap_rtc_reset(struct omap_rtc_s *s)
+{
+    struct tm tm;
+
+    s->interrupts = 0;
+    s->comp_reg = 0;
+    s->running = 0;
+    s->pm_am = 0;
+    s->auto_comp = 0;
+    s->round = 0;
+    s->tick = qemu_get_clock_ms(rt_clock);
+    memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
+    s->alarm_tm.tm_mday = 0x01;
+    s->status = 1 << 7;
+    qemu_get_timedate(&tm, 0);
+    s->ti = mktimegm(&tm);
+
+    omap_rtc_alarm_update(s);
+    omap_rtc_tick(s);
+}
+
+static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
+                qemu_irq *irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_rtc_s *s = (struct omap_rtc_s *)
+            qemu_mallocz(sizeof(struct omap_rtc_s));
+
+    s->irq = irq[0];
+    s->alarm = irq[1];
+    s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s);
+
+    omap_rtc_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_rtc_readfn,
+                    omap_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    return s;
+}
+
+/* Multi-channel Buffered Serial Port interfaces */
+struct omap_mcbsp_s {
+    qemu_irq txirq;
+    qemu_irq rxirq;
+    qemu_irq txdrq;
+    qemu_irq rxdrq;
+
+    uint16_t spcr[2];
+    uint16_t rcr[2];
+    uint16_t xcr[2];
+    uint16_t srgr[2];
+    uint16_t mcr[2];
+    uint16_t pcr;
+    uint16_t rcer[8];
+    uint16_t xcer[8];
+    int tx_rate;
+    int rx_rate;
+    int tx_req;
+    int rx_req;
+
+    I2SCodec *codec;
+    QEMUTimer *source_timer;
+    QEMUTimer *sink_timer;
+};
+
+static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
+{
+    int irq;
+
+    switch ((s->spcr[0] >> 4) & 3) {			/* RINTM */
+    case 0:
+        irq = (s->spcr[0] >> 1) & 1;			/* RRDY */
+        break;
+    case 3:
+        irq = (s->spcr[0] >> 3) & 1;			/* RSYNCERR */
+        break;
+    default:
+        irq = 0;
+        break;
+    }
+
+    if (irq)
+        qemu_irq_pulse(s->rxirq);
+
+    switch ((s->spcr[1] >> 4) & 3) {			/* XINTM */
+    case 0:
+        irq = (s->spcr[1] >> 1) & 1;			/* XRDY */
+        break;
+    case 3:
+        irq = (s->spcr[1] >> 3) & 1;			/* XSYNCERR */
+        break;
+    default:
+        irq = 0;
+        break;
+    }
+
+    if (irq)
+        qemu_irq_pulse(s->txirq);
+}
+
+static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s)
+{
+    if ((s->spcr[0] >> 1) & 1)				/* RRDY */
+        s->spcr[0] |= 1 << 2;				/* RFULL */
+    s->spcr[0] |= 1 << 1;				/* RRDY */
+    qemu_irq_raise(s->rxdrq);
+    omap_mcbsp_intr_update(s);
+}
+
+static void omap_mcbsp_source_tick(void *opaque)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+    static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
+
+    if (!s->rx_rate)
+        return;
+    if (s->rx_req)
+        printf("%s: Rx FIFO overrun\n", __FUNCTION__);
+
+    s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
+
+    omap_mcbsp_rx_newdata(s);
+    qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec());
+}
+
+static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
+{
+    if (!s->codec || !s->codec->rts)
+        omap_mcbsp_source_tick(s);
+    else if (s->codec->in.len) {
+        s->rx_req = s->codec->in.len;
+        omap_mcbsp_rx_newdata(s);
+    }
+}
+
+static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
+{
+    qemu_del_timer(s->source_timer);
+}
+
+static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s)
+{
+    s->spcr[0] &= ~(1 << 1);				/* RRDY */
+    qemu_irq_lower(s->rxdrq);
+    omap_mcbsp_intr_update(s);
+}
+
+static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s)
+{
+    s->spcr[1] |= 1 << 1;				/* XRDY */
+    qemu_irq_raise(s->txdrq);
+    omap_mcbsp_intr_update(s);
+}
+
+static void omap_mcbsp_sink_tick(void *opaque)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+    static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
+
+    if (!s->tx_rate)
+        return;
+    if (s->tx_req)
+        printf("%s: Tx FIFO underrun\n", __FUNCTION__);
+
+    s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
+
+    omap_mcbsp_tx_newdata(s);
+    qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec());
+}
+
+static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
+{
+    if (!s->codec || !s->codec->cts)
+        omap_mcbsp_sink_tick(s);
+    else if (s->codec->out.size) {
+        s->tx_req = s->codec->out.size;
+        omap_mcbsp_tx_newdata(s);
+    }
+}
+
+static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s)
+{
+    s->spcr[1] &= ~(1 << 1);				/* XRDY */
+    qemu_irq_lower(s->txdrq);
+    omap_mcbsp_intr_update(s);
+    if (s->codec && s->codec->cts)
+        s->codec->tx_swallow(s->codec->opaque);
+}
+
+static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s)
+{
+    s->tx_req = 0;
+    omap_mcbsp_tx_done(s);
+    qemu_del_timer(s->sink_timer);
+}
+
+static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
+{
+    int prev_rx_rate, prev_tx_rate;
+    int rx_rate = 0, tx_rate = 0;
+    int cpu_rate = 1500000;	/* XXX */
+
+    /* TODO: check CLKSTP bit */
+    if (s->spcr[1] & (1 << 6)) {			/* GRST */
+        if (s->spcr[0] & (1 << 0)) {			/* RRST */
+            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
+                            (s->pcr & (1 << 8))) {	/* CLKRM */
+                if (~s->pcr & (1 << 7))			/* SCLKME */
+                    rx_rate = cpu_rate /
+                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
+            } else
+                if (s->codec)
+                    rx_rate = s->codec->rx_rate;
+        }
+
+        if (s->spcr[1] & (1 << 0)) {			/* XRST */
+            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
+                            (s->pcr & (1 << 9))) {	/* CLKXM */
+                if (~s->pcr & (1 << 7))			/* SCLKME */
+                    tx_rate = cpu_rate /
+                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
+            } else
+                if (s->codec)
+                    tx_rate = s->codec->tx_rate;
+        }
+    }
+    prev_tx_rate = s->tx_rate;
+    prev_rx_rate = s->rx_rate;
+    s->tx_rate = tx_rate;
+    s->rx_rate = rx_rate;
+
+    if (s->codec)
+        s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate);
+
+    if (!prev_tx_rate && tx_rate)
+        omap_mcbsp_tx_start(s);
+    else if (s->tx_rate && !tx_rate)
+        omap_mcbsp_tx_stop(s);
+
+    if (!prev_rx_rate && rx_rate)
+        omap_mcbsp_rx_start(s);
+    else if (prev_tx_rate && !tx_rate)
+        omap_mcbsp_rx_stop(s);
+}
+
+static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x00:	/* DRR2 */
+        if (((s->rcr[0] >> 5) & 7) < 3)			/* RWDLEN1 */
+            return 0x0000;
+        /* Fall through.  */
+    case 0x02:	/* DRR1 */
+        if (s->rx_req < 2) {
+            printf("%s: Rx FIFO underrun\n", __FUNCTION__);
+            omap_mcbsp_rx_done(s);
+        } else {
+            s->tx_req -= 2;
+            if (s->codec && s->codec->in.len >= 2) {
+                ret = s->codec->in.fifo[s->codec->in.start ++] << 8;
+                ret |= s->codec->in.fifo[s->codec->in.start ++];
+                s->codec->in.len -= 2;
+            } else
+                ret = 0x0000;
+            if (!s->tx_req)
+                omap_mcbsp_rx_done(s);
+            return ret;
+        }
+        return 0x0000;
+
+    case 0x04:	/* DXR2 */
+    case 0x06:	/* DXR1 */
+        return 0x0000;
+
+    case 0x08:	/* SPCR2 */
+        return s->spcr[1];
+    case 0x0a:	/* SPCR1 */
+        return s->spcr[0];
+    case 0x0c:	/* RCR2 */
+        return s->rcr[1];
+    case 0x0e:	/* RCR1 */
+        return s->rcr[0];
+    case 0x10:	/* XCR2 */
+        return s->xcr[1];
+    case 0x12:	/* XCR1 */
+        return s->xcr[0];
+    case 0x14:	/* SRGR2 */
+        return s->srgr[1];
+    case 0x16:	/* SRGR1 */
+        return s->srgr[0];
+    case 0x18:	/* MCR2 */
+        return s->mcr[1];
+    case 0x1a:	/* MCR1 */
+        return s->mcr[0];
+    case 0x1c:	/* RCERA */
+        return s->rcer[0];
+    case 0x1e:	/* RCERB */
+        return s->rcer[1];
+    case 0x20:	/* XCERA */
+        return s->xcer[0];
+    case 0x22:	/* XCERB */
+        return s->xcer[1];
+    case 0x24:	/* PCR0 */
+        return s->pcr;
+    case 0x26:	/* RCERC */
+        return s->rcer[2];
+    case 0x28:	/* RCERD */
+        return s->rcer[3];
+    case 0x2a:	/* XCERC */
+        return s->xcer[2];
+    case 0x2c:	/* XCERD */
+        return s->xcer[3];
+    case 0x2e:	/* RCERE */
+        return s->rcer[4];
+    case 0x30:	/* RCERF */
+        return s->rcer[5];
+    case 0x32:	/* XCERE */
+        return s->xcer[4];
+    case 0x34:	/* XCERF */
+        return s->xcer[5];
+    case 0x36:	/* RCERG */
+        return s->rcer[6];
+    case 0x38:	/* RCERH */
+        return s->rcer[7];
+    case 0x3a:	/* XCERG */
+        return s->xcer[6];
+    case 0x3c:	/* XCERH */
+        return s->xcer[7];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* DRR2 */
+    case 0x02:	/* DRR1 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x04:	/* DXR2 */
+        if (((s->xcr[0] >> 5) & 7) < 3)			/* XWDLEN1 */
+            return;
+        /* Fall through.  */
+    case 0x06:	/* DXR1 */
+        if (s->tx_req > 1) {
+            s->tx_req -= 2;
+            if (s->codec && s->codec->cts) {
+                s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
+                s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff;
+            }
+            if (s->tx_req < 2)
+                omap_mcbsp_tx_done(s);
+        } else
+            printf("%s: Tx FIFO overrun\n", __FUNCTION__);
+        return;
+
+    case 0x08:	/* SPCR2 */
+        s->spcr[1] &= 0x0002;
+        s->spcr[1] |= 0x03f9 & value;
+        s->spcr[1] |= 0x0004 & (value << 2);		/* XEMPTY := XRST */
+        if (~value & 1)					/* XRST */
+            s->spcr[1] &= ~6;
+        omap_mcbsp_req_update(s);
+        return;
+    case 0x0a:	/* SPCR1 */
+        s->spcr[0] &= 0x0006;
+        s->spcr[0] |= 0xf8f9 & value;
+        if (value & (1 << 15))				/* DLB */
+            printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
+        if (~value & 1) {				/* RRST */
+            s->spcr[0] &= ~6;
+            s->rx_req = 0;
+            omap_mcbsp_rx_done(s);
+        }
+        omap_mcbsp_req_update(s);
+        return;
+
+    case 0x0c:	/* RCR2 */
+        s->rcr[1] = value & 0xffff;
+        return;
+    case 0x0e:	/* RCR1 */
+        s->rcr[0] = value & 0x7fe0;
+        return;
+    case 0x10:	/* XCR2 */
+        s->xcr[1] = value & 0xffff;
+        return;
+    case 0x12:	/* XCR1 */
+        s->xcr[0] = value & 0x7fe0;
+        return;
+    case 0x14:	/* SRGR2 */
+        s->srgr[1] = value & 0xffff;
+        omap_mcbsp_req_update(s);
+        return;
+    case 0x16:	/* SRGR1 */
+        s->srgr[0] = value & 0xffff;
+        omap_mcbsp_req_update(s);
+        return;
+    case 0x18:	/* MCR2 */
+        s->mcr[1] = value & 0x03e3;
+        if (value & 3)					/* XMCM */
+            printf("%s: Tx channel selection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+    case 0x1a:	/* MCR1 */
+        s->mcr[0] = value & 0x03e1;
+        if (value & 1)					/* RMCM */
+            printf("%s: Rx channel selection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+    case 0x1c:	/* RCERA */
+        s->rcer[0] = value & 0xffff;
+        return;
+    case 0x1e:	/* RCERB */
+        s->rcer[1] = value & 0xffff;
+        return;
+    case 0x20:	/* XCERA */
+        s->xcer[0] = value & 0xffff;
+        return;
+    case 0x22:	/* XCERB */
+        s->xcer[1] = value & 0xffff;
+        return;
+    case 0x24:	/* PCR0 */
+        s->pcr = value & 0x7faf;
+        return;
+    case 0x26:	/* RCERC */
+        s->rcer[2] = value & 0xffff;
+        return;
+    case 0x28:	/* RCERD */
+        s->rcer[3] = value & 0xffff;
+        return;
+    case 0x2a:	/* XCERC */
+        s->xcer[2] = value & 0xffff;
+        return;
+    case 0x2c:	/* XCERD */
+        s->xcer[3] = value & 0xffff;
+        return;
+    case 0x2e:	/* RCERE */
+        s->rcer[4] = value & 0xffff;
+        return;
+    case 0x30:	/* RCERF */
+        s->rcer[5] = value & 0xffff;
+        return;
+    case 0x32:	/* XCERE */
+        s->xcer[4] = value & 0xffff;
+        return;
+    case 0x34:	/* XCERF */
+        s->xcer[5] = value & 0xffff;
+        return;
+    case 0x36:	/* RCERG */
+        s->rcer[6] = value & 0xffff;
+        return;
+    case 0x38:	/* RCERH */
+        s->rcer[7] = value & 0xffff;
+        return;
+    case 0x3a:	/* XCERG */
+        s->xcer[6] = value & 0xffff;
+        return;
+    case 0x3c:	/* XCERH */
+        s->xcer[7] = value & 0xffff;
+        return;
+    }
+
+    OMAP_BAD_REG(addr);
+}
+
+static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    if (offset == 0x04) {				/* DXR */
+        if (((s->xcr[0] >> 5) & 7) < 3)			/* XWDLEN1 */
+            return;
+        if (s->tx_req > 3) {
+            s->tx_req -= 4;
+            if (s->codec && s->codec->cts) {
+                s->codec->out.fifo[s->codec->out.len ++] =
+                        (value >> 24) & 0xff;
+                s->codec->out.fifo[s->codec->out.len ++] =
+                        (value >> 16) & 0xff;
+                s->codec->out.fifo[s->codec->out.len ++] =
+                        (value >> 8) & 0xff;
+                s->codec->out.fifo[s->codec->out.len ++] =
+                        (value >> 0) & 0xff;
+            }
+            if (s->tx_req < 4)
+                omap_mcbsp_tx_done(s);
+        } else
+            printf("%s: Tx FIFO overrun\n", __FUNCTION__);
+        return;
+    }
+
+    omap_badwidth_write16(opaque, addr, value);
+}
+
+static CPUReadMemoryFunc * const omap_mcbsp_readfn[] = {
+    omap_badwidth_read16,
+    omap_mcbsp_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_mcbsp_writefn[] = {
+    omap_badwidth_write16,
+    omap_mcbsp_writeh,
+    omap_mcbsp_writew,
+};
+
+static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
+{
+    memset(&s->spcr, 0, sizeof(s->spcr));
+    memset(&s->rcr, 0, sizeof(s->rcr));
+    memset(&s->xcr, 0, sizeof(s->xcr));
+    s->srgr[0] = 0x0001;
+    s->srgr[1] = 0x2000;
+    memset(&s->mcr, 0, sizeof(s->mcr));
+    memset(&s->pcr, 0, sizeof(s->pcr));
+    memset(&s->rcer, 0, sizeof(s->rcer));
+    memset(&s->xcer, 0, sizeof(s->xcer));
+    s->tx_req = 0;
+    s->rx_req = 0;
+    s->tx_rate = 0;
+    s->rx_rate = 0;
+    qemu_del_timer(s->source_timer);
+    qemu_del_timer(s->sink_timer);
+}
+
+struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
+                qemu_irq *irq, qemu_irq *dma, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
+            qemu_mallocz(sizeof(struct omap_mcbsp_s));
+
+    s->txirq = irq[0];
+    s->rxirq = irq[1];
+    s->txdrq = dma[0];
+    s->rxdrq = dma[1];
+    s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s);
+    s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s);
+    omap_mcbsp_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_mcbsp_readfn,
+                    omap_mcbsp_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    return s;
+}
+
+static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+
+    if (s->rx_rate) {
+        s->rx_req = s->codec->in.len;
+        omap_mcbsp_rx_newdata(s);
+    }
+}
+
+static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
+{
+    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
+
+    if (s->tx_rate) {
+        s->tx_req = s->codec->out.size;
+        omap_mcbsp_tx_newdata(s);
+    }
+}
+
+void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave)
+{
+    s->codec = slave;
+    slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0];
+    slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0];
+}
+
+/* LED Pulse Generators */
+struct omap_lpg_s {
+    QEMUTimer *tm;
+
+    uint8_t control;
+    uint8_t power;
+    int64_t on;
+    int64_t period;
+    int clk;
+    int cycle;
+};
+
+static void omap_lpg_tick(void *opaque)
+{
+    struct omap_lpg_s *s = opaque;
+
+    if (s->cycle)
+        qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->period - s->on);
+    else
+        qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->on);
+
+    s->cycle = !s->cycle;
+    printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
+}
+
+static void omap_lpg_update(struct omap_lpg_s *s)
+{
+    int64_t on, period = 1, ticks = 1000;
+    static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 };
+
+    if (~s->control & (1 << 6))					/* LPGRES */
+        on = 0;
+    else if (s->control & (1 << 7))				/* PERM_ON */
+        on = period;
+    else {
+        period = muldiv64(ticks, per[s->control & 7],		/* PERCTRL */
+                        256 / 32);
+        on = (s->clk && s->power) ? muldiv64(ticks,
+                        per[(s->control >> 3) & 7], 256) : 0;	/* ONCTRL */
+    }
+
+    qemu_del_timer(s->tm);
+    if (on == period && s->on < s->period)
+        printf("%s: LED is on\n", __FUNCTION__);
+    else if (on == 0 && s->on)
+        printf("%s: LED is off\n", __FUNCTION__);
+    else if (on && (on != s->on || period != s->period)) {
+        s->cycle = 0;
+        s->on = on;
+        s->period = period;
+        omap_lpg_tick(s);
+        return;
+    }
+
+    s->on = on;
+    s->period = period;
+}
+
+static void omap_lpg_reset(struct omap_lpg_s *s)
+{
+    s->control = 0x00;
+    s->power = 0x00;
+    s->clk = 1;
+    omap_lpg_update(s);
+}
+
+static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* LCR */
+        return s->control;
+
+    case 0x04:	/* PMR */
+        return s->power;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* LCR */
+        if (~value & (1 << 6))					/* LPGRES */
+            omap_lpg_reset(s);
+        s->control = value & 0xff;
+        omap_lpg_update(s);
+        return;
+
+    case 0x04:	/* PMR */
+        s->power = value & 0x01;
+        omap_lpg_update(s);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_lpg_readfn[] = {
+    omap_lpg_read,
+    omap_badwidth_read8,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_lpg_writefn[] = {
+    omap_lpg_write,
+    omap_badwidth_write8,
+    omap_badwidth_write8,
+};
+
+static void omap_lpg_clk_update(void *opaque, int line, int on)
+{
+    struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
+
+    s->clk = on;
+    omap_lpg_update(s);
+}
+
+static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_lpg_s *s = (struct omap_lpg_s *)
+            qemu_mallocz(sizeof(struct omap_lpg_s));
+
+    s->tm = qemu_new_timer_ms(rt_clock, omap_lpg_tick, s);
+
+    omap_lpg_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_lpg_readfn,
+                    omap_lpg_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
+
+    return s;
+}
+
+/* MPUI Peripheral Bridge configuration */
+static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
+{
+    if (addr == OMAP_MPUI_BASE)	/* CMR */
+        return 0xfe4d;
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static CPUReadMemoryFunc * const omap_mpui_io_readfn[] = {
+    omap_badwidth_read16,
+    omap_mpui_io_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_mpui_io_writefn[] = {
+    omap_badwidth_write16,
+    omap_badwidth_write16,
+    omap_badwidth_write16,
+};
+
+static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn,
+                    omap_mpui_io_writefn, mpu, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype);
+}
+
+/* General chip reset */
+static void omap1_mpu_reset(void *opaque)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    omap_inth_reset(mpu->ih[0]);
+    omap_inth_reset(mpu->ih[1]);
+    omap_dma_reset(mpu->dma);
+    omap_mpu_timer_reset(mpu->timer[0]);
+    omap_mpu_timer_reset(mpu->timer[1]);
+    omap_mpu_timer_reset(mpu->timer[2]);
+    omap_wd_timer_reset(mpu->wdt);
+    omap_os_timer_reset(mpu->os_timer);
+    omap_lcdc_reset(mpu->lcd);
+    omap_ulpd_pm_reset(mpu);
+    omap_pin_cfg_reset(mpu);
+    omap_mpui_reset(mpu);
+    omap_tipb_bridge_reset(mpu->private_tipb);
+    omap_tipb_bridge_reset(mpu->public_tipb);
+    omap_dpll_reset(&mpu->dpll[0]);
+    omap_dpll_reset(&mpu->dpll[1]);
+    omap_dpll_reset(&mpu->dpll[2]);
+    omap_uart_reset(mpu->uart[0]);
+    omap_uart_reset(mpu->uart[1]);
+    omap_uart_reset(mpu->uart[2]);
+    omap_mmc_reset(mpu->mmc);
+    omap_mpuio_reset(mpu->mpuio);
+    omap_gpio_reset(mpu->gpio);
+    omap_uwire_reset(mpu->microwire);
+    omap_pwl_reset(mpu);
+    omap_pwt_reset(mpu);
+    omap_i2c_reset(mpu->i2c[0]);
+    omap_rtc_reset(mpu->rtc);
+    omap_mcbsp_reset(mpu->mcbsp1);
+    omap_mcbsp_reset(mpu->mcbsp2);
+    omap_mcbsp_reset(mpu->mcbsp3);
+    omap_lpg_reset(mpu->led[0]);
+    omap_lpg_reset(mpu->led[1]);
+    omap_clkm_reset(mpu);
+    cpu_reset(mpu->env);
+}
+
+static const struct omap_map_s {
+    target_phys_addr_t phys_dsp;
+    target_phys_addr_t phys_mpu;
+    uint32_t size;
+    const char *name;
+} omap15xx_dsp_mm[] = {
+    /* Strobe 0 */
+    { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" },		/* CS0 */
+    { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" },		/* CS1 */
+    { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" },		/* CS3 */
+    { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" },	/* CS4 */
+    { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" },	/* CS5 */
+    { 0xe1013000, 0xfffb3000, 0x800, "uWire" },			/* CS6 */
+    { 0xe1013800, 0xfffb3800, 0x800, "I^2C" },			/* CS7 */
+    { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" },		/* CS8 */
+    { 0xe1014800, 0xfffb4800, 0x800, "RTC" },			/* CS9 */
+    { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" },			/* CS10 */
+    { 0xe1015800, 0xfffb5800, 0x800, "PWL" },			/* CS11 */
+    { 0xe1016000, 0xfffb6000, 0x800, "PWT" },			/* CS12 */
+    { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" },		/* CS14 */
+    { 0xe1017800, 0xfffb7800, 0x800, "MMC" },			/* CS15 */
+    { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" },		/* CS18 */
+    { 0xe1019800, 0xfffb9800, 0x800, "UART3" },			/* CS19 */
+    { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" },		/* CS25 */
+    /* Strobe 1 */
+    { 0xe101e000, 0xfffce000, 0x800, "GPIOs" },			/* CS28 */
+
+    { 0 }
+};
+
+static void omap_setup_dsp_mapping(const struct omap_map_s *map)
+{
+    int io;
+
+    for (; map->phys_dsp; map ++) {
+        io = cpu_get_physical_page_desc(map->phys_mpu);
+
+        cpu_register_physical_memory(map->phys_dsp, map->size, io);
+    }
+}
+
+void omap_mpu_wakeup(void *opaque, int irq, int req)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    if (mpu->env->halted)
+        cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB);
+}
+
+static const struct dma_irq_map omap1_dma_irq_map[] = {
+    { 0, OMAP_INT_DMA_CH0_6 },
+    { 0, OMAP_INT_DMA_CH1_7 },
+    { 0, OMAP_INT_DMA_CH2_8 },
+    { 0, OMAP_INT_DMA_CH3 },
+    { 0, OMAP_INT_DMA_CH4 },
+    { 0, OMAP_INT_DMA_CH5 },
+    { 1, OMAP_INT_1610_DMA_CH6 },
+    { 1, OMAP_INT_1610_DMA_CH7 },
+    { 1, OMAP_INT_1610_DMA_CH8 },
+    { 1, OMAP_INT_1610_DMA_CH9 },
+    { 1, OMAP_INT_1610_DMA_CH10 },
+    { 1, OMAP_INT_1610_DMA_CH11 },
+    { 1, OMAP_INT_1610_DMA_CH12 },
+    { 1, OMAP_INT_1610_DMA_CH13 },
+    { 1, OMAP_INT_1610_DMA_CH14 },
+    { 1, OMAP_INT_1610_DMA_CH15 }
+};
+
+/* DMA ports for OMAP1 */
+static int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr);
+}
+
+static int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE,
+                             addr);
+}
+
+static int omap_validate_imif_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);
+}
+
+static int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr);
+}
+
+static int omap_validate_local_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr);
+}
+
+static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
+}
+
+struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+                const char *core)
+{
+    int i;
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_state_s));
+    ram_addr_t imif_base, emiff_base;
+    qemu_irq *cpu_irq;
+    qemu_irq dma_irqs[6];
+    DriveInfo *dinfo;
+
+    if (!core)
+        core = "ti925t";
+
+    /* Core */
+    s->mpu_model = omap310;
+    s->env = cpu_init(core);
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->sdram_size = sdram_size;
+    s->sram_size = OMAP15XX_SRAM_SIZE;
+
+    s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
+
+    /* Clocks */
+    omap_clk_init(s);
+
+    /* Memory-mapped stuff */
+    cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size,
+                    (emiff_base = qemu_ram_alloc(NULL, "omap1.dram",
+                                                 s->sdram_size)) | IO_MEM_RAM);
+    cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size,
+                    (imif_base = qemu_ram_alloc(NULL, "omap1.sram",
+                                                s->sram_size)) | IO_MEM_RAM);
+
+    omap_clkm_init(0xfffece00, 0xe1008000, s);
+
+    cpu_irq = arm_pic_init_cpu(s->env);
+    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
+                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
+                    omap_findclk(s, "arminth_ck"));
+    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1],
+                    omap_inth_get_pin(s->ih[0], OMAP_INT_15XX_IH2_IRQ),
+		    NULL, omap_findclk(s, "arminth_ck"));
+
+    for (i = 0; i < 6; i ++)
+        dma_irqs[i] =
+                s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr];
+    s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
+                           s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
+
+    s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
+    s->port[emifs    ].addr_valid = omap_validate_emifs_addr;
+    s->port[imif     ].addr_valid = omap_validate_imif_addr;
+    s->port[tipb     ].addr_valid = omap_validate_tipb_addr;
+    s->port[local    ].addr_valid = omap_validate_local_addr;
+    s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
+
+    /* Register SDRAM and SRAM DMA ports for fast transfers.  */
+    soc_dma_port_add_mem_ram(s->dma,
+                    emiff_base, OMAP_EMIFF_BASE, s->sdram_size);
+    soc_dma_port_add_mem_ram(s->dma,
+                    imif_base, OMAP_IMIF_BASE, s->sram_size);
+
+    s->timer[0] = omap_mpu_timer_init(0xfffec500,
+                    s->irq[0][OMAP_INT_TIMER1],
+                    omap_findclk(s, "mputim_ck"));
+    s->timer[1] = omap_mpu_timer_init(0xfffec600,
+                    s->irq[0][OMAP_INT_TIMER2],
+                    omap_findclk(s, "mputim_ck"));
+    s->timer[2] = omap_mpu_timer_init(0xfffec700,
+                    s->irq[0][OMAP_INT_TIMER3],
+                    omap_findclk(s, "mputim_ck"));
+
+    s->wdt = omap_wd_timer_init(0xfffec800,
+                    s->irq[0][OMAP_INT_WD_TIMER],
+                    omap_findclk(s, "armwdt_ck"));
+
+    s->os_timer = omap_os_timer_init(0xfffb9000,
+                    s->irq[1][OMAP_INT_OS_TIMER],
+                    omap_findclk(s, "clk32-kHz"));
+
+    s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
+                    omap_dma_get_lcdch(s->dma), imif_base, emiff_base,
+                    omap_findclk(s, "lcd_ck"));
+
+    omap_ulpd_pm_init(0xfffe0800, s);
+    omap_pin_cfg_init(0xfffe1000, s);
+    omap_id_init(s);
+
+    omap_mpui_init(0xfffec900, s);
+
+    s->private_tipb = omap_tipb_bridge_init(0xfffeca00,
+                    s->irq[0][OMAP_INT_BRIDGE_PRIV],
+                    omap_findclk(s, "tipb_ck"));
+    s->public_tipb = omap_tipb_bridge_init(0xfffed300,
+                    s->irq[0][OMAP_INT_BRIDGE_PUB],
+                    omap_findclk(s, "tipb_ck"));
+
+    omap_tcmi_init(0xfffecc00, s);
+
+    s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
+                    omap_findclk(s, "uart1_ck"),
+                    omap_findclk(s, "uart1_ck"),
+                    s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
+                    "uart1",
+                    serial_hds[0]);
+    s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
+                    omap_findclk(s, "uart2_ck"),
+                    omap_findclk(s, "uart2_ck"),
+                    s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
+                    "uart2",
+                    serial_hds[0] ? serial_hds[1] : NULL);
+    s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
+                    omap_findclk(s, "uart3_ck"),
+                    omap_findclk(s, "uart3_ck"),
+                    s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
+                    "uart3",
+                    serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+
+    omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
+    omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
+    omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
+
+    dinfo = drive_get(IF_SD, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = omap_mmc_init(0xfffb7800, dinfo->bdrv,
+                    s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX],
+                    omap_findclk(s, "mmc_ck"));
+
+    s->mpuio = omap_mpuio_init(0xfffb5000,
+                    s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
+                    s->wakeup, omap_findclk(s, "clk32-kHz"));
+
+    s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1],
+                    omap_findclk(s, "arm_gpio_ck"));
+
+    s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
+                    s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
+
+    omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck"));
+    omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck"));
+
+    s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
+                    &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
+
+    s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
+                    omap_findclk(s, "clk32-kHz"));
+
+    s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
+                    &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
+    s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
+                    &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
+    s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
+                    &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
+
+    s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
+    s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz"));
+
+    /* Register mappings not currenlty implemented:
+     * MCSI2 Comm	fffb2000 - fffb27ff (not mapped on OMAP310)
+     * MCSI1 Bluetooth	fffb2800 - fffb2fff (not mapped on OMAP310)
+     * USB W2FC		fffb4000 - fffb47ff
+     * Camera Interface	fffb6800 - fffb6fff
+     * USB Host		fffba000 - fffba7ff
+     * FAC		fffba800 - fffbafff
+     * HDQ/1-Wire	fffbc000 - fffbc7ff
+     * TIPB switches	fffbc800 - fffbcfff
+     * Mailbox		fffcf000 - fffcf7ff
+     * Local bus IF	fffec100 - fffec1ff
+     * Local bus MMU	fffec200 - fffec2ff
+     * DSP MMU		fffed200 - fffed2ff
+     */
+
+    omap_setup_dsp_mapping(omap15xx_dsp_mm);
+    omap_setup_mpui_io(s);
+
+    qemu_register_reset(omap1_mpu_reset, s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap2.c b/qemu-0.15.x/hw/omap2.c
new file mode 100644
index 0000000..0f13272
--- /dev/null
+++ b/qemu-0.15.x/hw/omap2.c
@@ -0,0 +1,2616 @@
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "blockdev.h"
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "flash.h"
+#include "soc_dma.h"
+#include "audio/audio.h"
+
+/* Enhanced Audio Controller (CODEC only) */
+struct omap_eac_s {
+    qemu_irq irq;
+
+    uint16_t sysconfig;
+    uint8_t config[4];
+    uint8_t control;
+    uint8_t address;
+    uint16_t data;
+    uint8_t vtol;
+    uint8_t vtsl;
+    uint16_t mixer;
+    uint16_t gain[4];
+    uint8_t att;
+    uint16_t max[7];
+
+    struct {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t, int);
+        void *opaque;
+
+#define EAC_BUF_LEN 1024
+        uint32_t rxbuf[EAC_BUF_LEN];
+        int rxoff;
+        int rxlen;
+        int rxavail;
+        uint32_t txbuf[EAC_BUF_LEN];
+        int txlen;
+        int txavail;
+
+        int enable;
+        int rate;
+
+        uint16_t config[4];
+
+        /* These need to be moved to the actual codec */
+        QEMUSoundCard card;
+        SWVoiceIn *in_voice;
+        SWVoiceOut *out_voice;
+        int hw_enable;
+    } codec;
+
+    struct {
+        uint8_t control;
+        uint16_t config;
+    } modem, bt;
+};
+
+static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
+{
+    qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1);	/* AURDI */
+}
+
+static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
+{
+    qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
+                    ((s->codec.config[1] >> 12) & 1));		/* DMAREN */
+}
+
+static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
+{
+    qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail &&
+                    ((s->codec.config[1] >> 11) & 1));		/* DMAWEN */
+}
+
+static inline void omap_eac_in_refill(struct omap_eac_s *s)
+{
+    int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
+    int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
+    int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
+    int recv = 1;
+    uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
+
+    left -= leftwrap;
+    start = 0;
+    while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
+                                    leftwrap)) > 0) {	/* Be defensive */
+        start += recv;
+        leftwrap -= recv;
+    }
+    if (recv <= 0)
+        s->codec.rxavail = 0;
+    else
+        s->codec.rxavail -= start >> 2;
+    s->codec.rxlen += start >> 2;
+
+    if (recv > 0 && left > 0) {
+        start = 0;
+        while (left && (recv = AUD_read(s->codec.in_voice,
+                                        (uint8_t *) s->codec.rxbuf + start,
+                                        left)) > 0) {	/* Be defensive */
+            start += recv;
+            left -= recv;
+        }
+        if (recv <= 0)
+            s->codec.rxavail = 0;
+        else
+            s->codec.rxavail -= start >> 2;
+        s->codec.rxlen += start >> 2;
+    }
+}
+
+static inline void omap_eac_out_empty(struct omap_eac_s *s)
+{
+    int left = s->codec.txlen << 2;
+    int start = 0;
+    int sent = 1;
+
+    while (left && (sent = AUD_write(s->codec.out_voice,
+                                    (uint8_t *) s->codec.txbuf + start,
+                                    left)) > 0) {	/* Be defensive */
+        start += sent;
+        left -= sent;
+    }
+
+    if (!sent) {
+        s->codec.txavail = 0;
+        omap_eac_out_dmarequest_update(s);
+    }
+
+    if (start)
+        s->codec.txlen = 0;
+}
+
+static void omap_eac_in_cb(void *opaque, int avail_b)
+{
+    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
+
+    s->codec.rxavail = avail_b >> 2;
+    omap_eac_in_refill(s);
+    /* TODO: possibly discard current buffer if overrun */
+    omap_eac_in_dmarequest_update(s);
+}
+
+static void omap_eac_out_cb(void *opaque, int free_b)
+{
+    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
+
+    s->codec.txavail = free_b >> 2;
+    if (s->codec.txlen)
+        omap_eac_out_empty(s);
+    else
+        omap_eac_out_dmarequest_update(s);
+}
+
+static void omap_eac_enable_update(struct omap_eac_s *s)
+{
+    s->codec.enable = !(s->codec.config[1] & 1) &&		/* EACPWD */
+            (s->codec.config[1] & 2) &&				/* AUDEN */
+            s->codec.hw_enable;
+}
+
+static const int omap_eac_fsint[4] = {
+    8000,
+    11025,
+    22050,
+    44100,
+};
+
+static const int omap_eac_fsint2[8] = {
+    8000,
+    11025,
+    22050,
+    44100,
+    48000,
+    0, 0, 0,
+};
+
+static const int omap_eac_fsint3[16] = {
+    8000,
+    11025,
+    16000,
+    22050,
+    24000,
+    32000,
+    44100,
+    48000,
+    0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static void omap_eac_rate_update(struct omap_eac_s *s)
+{
+    int fsint[3];
+
+    fsint[2] = (s->codec.config[3] >> 9) & 0xf;
+    fsint[1] = (s->codec.config[2] >> 0) & 0x7;
+    fsint[0] = (s->codec.config[0] >> 6) & 0x3;
+    if (fsint[2] < 0xf)
+        s->codec.rate = omap_eac_fsint3[fsint[2]];
+    else if (fsint[1] < 0x7)
+        s->codec.rate = omap_eac_fsint2[fsint[1]];
+    else
+        s->codec.rate = omap_eac_fsint[fsint[0]];
+}
+
+static void omap_eac_volume_update(struct omap_eac_s *s)
+{
+    /* TODO */
+}
+
+static void omap_eac_format_update(struct omap_eac_s *s)
+{
+    struct audsettings fmt;
+
+    /* The hardware buffers at most one sample */
+    if (s->codec.rxlen)
+        s->codec.rxlen = 1;
+
+    if (s->codec.in_voice) {
+        AUD_set_active_in(s->codec.in_voice, 0);
+        AUD_close_in(&s->codec.card, s->codec.in_voice);
+        s->codec.in_voice = NULL;
+    }
+    if (s->codec.out_voice) {
+        omap_eac_out_empty(s);
+        AUD_set_active_out(s->codec.out_voice, 0);
+        AUD_close_out(&s->codec.card, s->codec.out_voice);
+        s->codec.out_voice = NULL;
+        s->codec.txavail = 0;
+    }
+    /* Discard what couldn't be written */
+    s->codec.txlen = 0;
+
+    omap_eac_enable_update(s);
+    if (!s->codec.enable)
+        return;
+
+    omap_eac_rate_update(s);
+    fmt.endianness = ((s->codec.config[0] >> 8) & 1);		/* LI_BI */
+    fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1;	/* MN_ST */
+    fmt.freq = s->codec.rate;
+    /* TODO: signedness possibly depends on the CODEC hardware - or
+     * does I2S specify it?  */
+    /* All register writes are 16 bits so we we store 16-bit samples
+     * in the buffers regardless of AGCFR[B8_16] value.  */
+    fmt.fmt = AUD_FMT_U16;
+
+    s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice,
+                    "eac.codec.in", s, omap_eac_in_cb, &fmt);
+    s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice,
+                    "eac.codec.out", s, omap_eac_out_cb, &fmt);
+
+    omap_eac_volume_update(s);
+
+    AUD_set_active_in(s->codec.in_voice, 1);
+    AUD_set_active_out(s->codec.out_voice, 1);
+}
+
+static void omap_eac_reset(struct omap_eac_s *s)
+{
+    s->sysconfig = 0;
+    s->config[0] = 0x0c;
+    s->config[1] = 0x09;
+    s->config[2] = 0xab;
+    s->config[3] = 0x03;
+    s->control = 0x00;
+    s->address = 0x00;
+    s->data = 0x0000;
+    s->vtol = 0x00;
+    s->vtsl = 0x00;
+    s->mixer = 0x0000;
+    s->gain[0] = 0xe7e7;
+    s->gain[1] = 0x6767;
+    s->gain[2] = 0x6767;
+    s->gain[3] = 0x6767;
+    s->att = 0xce;
+    s->max[0] = 0;
+    s->max[1] = 0;
+    s->max[2] = 0;
+    s->max[3] = 0;
+    s->max[4] = 0;
+    s->max[5] = 0;
+    s->max[6] = 0;
+
+    s->modem.control = 0x00;
+    s->modem.config = 0x0000;
+    s->bt.control = 0x00;
+    s->bt.config = 0x0000;
+    s->codec.config[0] = 0x0649;
+    s->codec.config[1] = 0x0000;
+    s->codec.config[2] = 0x0007;
+    s->codec.config[3] = 0x1ffc;
+    s->codec.rxoff = 0;
+    s->codec.rxlen = 0;
+    s->codec.txlen = 0;
+    s->codec.rxavail = 0;
+    s->codec.txavail = 0;
+
+    omap_eac_format_update(s);
+    omap_eac_interrupt_update(s);
+}
+
+static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
+    uint32_t ret;
+
+    switch (addr) {
+    case 0x000:	/* CPCFR1 */
+        return s->config[0];
+    case 0x004:	/* CPCFR2 */
+        return s->config[1];
+    case 0x008:	/* CPCFR3 */
+        return s->config[2];
+    case 0x00c:	/* CPCFR4 */
+        return s->config[3];
+
+    case 0x010:	/* CPTCTL */
+        return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) |
+                ((s->codec.txlen < s->codec.txavail) << 5);
+
+    case 0x014:	/* CPTTADR */
+        return s->address;
+    case 0x018:	/* CPTDATL */
+        return s->data & 0xff;
+    case 0x01c:	/* CPTDATH */
+        return s->data >> 8;
+    case 0x020:	/* CPTVSLL */
+        return s->vtol;
+    case 0x024:	/* CPTVSLH */
+        return s->vtsl | (3 << 5);	/* CRDY1 | CRDY2 */
+    case 0x040:	/* MPCTR */
+        return s->modem.control;
+    case 0x044:	/* MPMCCFR */
+        return s->modem.config;
+    case 0x060:	/* BPCTR */
+        return s->bt.control;
+    case 0x064:	/* BPMCCFR */
+        return s->bt.config;
+    case 0x080:	/* AMSCFR */
+        return s->mixer;
+    case 0x084:	/* AMVCTR */
+        return s->gain[0];
+    case 0x088:	/* AM1VCTR */
+        return s->gain[1];
+    case 0x08c:	/* AM2VCTR */
+        return s->gain[2];
+    case 0x090:	/* AM3VCTR */
+        return s->gain[3];
+    case 0x094:	/* ASTCTR */
+        return s->att;
+    case 0x098:	/* APD1LCR */
+        return s->max[0];
+    case 0x09c:	/* APD1RCR */
+        return s->max[1];
+    case 0x0a0:	/* APD2LCR */
+        return s->max[2];
+    case 0x0a4:	/* APD2RCR */
+        return s->max[3];
+    case 0x0a8:	/* APD3LCR */
+        return s->max[4];
+    case 0x0ac:	/* APD3RCR */
+        return s->max[5];
+    case 0x0b0:	/* APD4R */
+        return s->max[6];
+    case 0x0b4:	/* ADWR */
+        /* This should be write-only?  Docs list it as read-only.  */
+        return 0x0000;
+    case 0x0b8:	/* ADRDR */
+        if (likely(s->codec.rxlen > 1)) {
+            ret = s->codec.rxbuf[s->codec.rxoff ++];
+            s->codec.rxlen --;
+            s->codec.rxoff &= EAC_BUF_LEN - 1;
+            return ret;
+        } else if (s->codec.rxlen) {
+            ret = s->codec.rxbuf[s->codec.rxoff ++];
+            s->codec.rxlen --;
+            s->codec.rxoff &= EAC_BUF_LEN - 1;
+            if (s->codec.rxavail)
+                omap_eac_in_refill(s);
+            omap_eac_in_dmarequest_update(s);
+            return ret;
+        }
+        return 0x0000;
+    case 0x0bc:	/* AGCFR */
+        return s->codec.config[0];
+    case 0x0c0:	/* AGCTR */
+        return s->codec.config[1] | ((s->codec.config[1] & 2) << 14);
+    case 0x0c4:	/* AGCFR2 */
+        return s->codec.config[2];
+    case 0x0c8:	/* AGCFR3 */
+        return s->codec.config[3];
+    case 0x0cc:	/* MBPDMACTR */
+    case 0x0d0:	/* MPDDMARR */
+    case 0x0d8:	/* MPUDMARR */
+    case 0x0e4:	/* BPDDMARR */
+    case 0x0ec:	/* BPUDMARR */
+        return 0x0000;
+
+    case 0x100:	/* VERSION_NUMBER */
+        return 0x0010;
+
+    case 0x104:	/* SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x108:	/* SYSSTATUS */
+        return 1 | 0xe;					/* RESETDONE | stuff */
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_eac_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
+
+    switch (addr) {
+    case 0x098:	/* APD1LCR */
+    case 0x09c:	/* APD1RCR */
+    case 0x0a0:	/* APD2LCR */
+    case 0x0a4:	/* APD2RCR */
+    case 0x0a8:	/* APD3LCR */
+    case 0x0ac:	/* APD3RCR */
+    case 0x0b0:	/* APD4R */
+    case 0x0b8:	/* ADRDR */
+    case 0x0d0:	/* MPDDMARR */
+    case 0x0d8:	/* MPUDMARR */
+    case 0x0e4:	/* BPDDMARR */
+    case 0x0ec:	/* BPUDMARR */
+    case 0x100:	/* VERSION_NUMBER */
+    case 0x108:	/* SYSSTATUS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x000:	/* CPCFR1 */
+        s->config[0] = value & 0xff;
+        omap_eac_format_update(s);
+        break;
+    case 0x004:	/* CPCFR2 */
+        s->config[1] = value & 0xff;
+        omap_eac_format_update(s);
+        break;
+    case 0x008:	/* CPCFR3 */
+        s->config[2] = value & 0xff;
+        omap_eac_format_update(s);
+        break;
+    case 0x00c:	/* CPCFR4 */
+        s->config[3] = value & 0xff;
+        omap_eac_format_update(s);
+        break;
+
+    case 0x010:	/* CPTCTL */
+        /* Assuming TXF and TXE bits are read-only... */
+        s->control = value & 0x5f;
+        omap_eac_interrupt_update(s);
+        break;
+
+    case 0x014:	/* CPTTADR */
+        s->address = value & 0xff;
+        break;
+    case 0x018:	/* CPTDATL */
+        s->data &= 0xff00;
+        s->data |= value & 0xff;
+        break;
+    case 0x01c:	/* CPTDATH */
+        s->data &= 0x00ff;
+        s->data |= value << 8;
+        break;
+    case 0x020:	/* CPTVSLL */
+        s->vtol = value & 0xf8;
+        break;
+    case 0x024:	/* CPTVSLH */
+        s->vtsl = value & 0x9f;
+        break;
+    case 0x040:	/* MPCTR */
+        s->modem.control = value & 0x8f;
+        break;
+    case 0x044:	/* MPMCCFR */
+        s->modem.config = value & 0x7fff;
+        break;
+    case 0x060:	/* BPCTR */
+        s->bt.control = value & 0x8f;
+        break;
+    case 0x064:	/* BPMCCFR */
+        s->bt.config = value & 0x7fff;
+        break;
+    case 0x080:	/* AMSCFR */
+        s->mixer = value & 0x0fff;
+        break;
+    case 0x084:	/* AMVCTR */
+        s->gain[0] = value & 0xffff;
+        break;
+    case 0x088:	/* AM1VCTR */
+        s->gain[1] = value & 0xff7f;
+        break;
+    case 0x08c:	/* AM2VCTR */
+        s->gain[2] = value & 0xff7f;
+        break;
+    case 0x090:	/* AM3VCTR */
+        s->gain[3] = value & 0xff7f;
+        break;
+    case 0x094:	/* ASTCTR */
+        s->att = value & 0xff;
+        break;
+
+    case 0x0b4:	/* ADWR */
+        s->codec.txbuf[s->codec.txlen ++] = value;
+        if (unlikely(s->codec.txlen == EAC_BUF_LEN ||
+                                s->codec.txlen == s->codec.txavail)) {
+            if (s->codec.txavail)
+                omap_eac_out_empty(s);
+            /* Discard what couldn't be written */
+            s->codec.txlen = 0;
+        }
+        break;
+
+    case 0x0bc:	/* AGCFR */
+        s->codec.config[0] = value & 0x07ff;
+        omap_eac_format_update(s);
+        break;
+    case 0x0c0:	/* AGCTR */
+        s->codec.config[1] = value & 0x780f;
+        omap_eac_format_update(s);
+        break;
+    case 0x0c4:	/* AGCFR2 */
+        s->codec.config[2] = value & 0x003f;
+        omap_eac_format_update(s);
+        break;
+    case 0x0c8:	/* AGCFR3 */
+        s->codec.config[3] = value & 0xffff;
+        omap_eac_format_update(s);
+        break;
+    case 0x0cc:	/* MBPDMACTR */
+    case 0x0d4:	/* MPDDMAWR */
+    case 0x0e0:	/* MPUDMAWR */
+    case 0x0e8:	/* BPDDMAWR */
+    case 0x0f0:	/* BPUDMAWR */
+        break;
+
+    case 0x104:	/* SYSCONFIG */
+        if (value & (1 << 1))				/* SOFTRESET */
+            omap_eac_reset(s);
+        s->sysconfig = value & 0x31d;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_eac_readfn[] = {
+    omap_badwidth_read16,
+    omap_eac_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_eac_writefn[] = {
+    omap_badwidth_write16,
+    omap_eac_write,
+    omap_badwidth_write16,
+};
+
+static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_eac_s *s = (struct omap_eac_s *)
+            qemu_mallocz(sizeof(struct omap_eac_s));
+
+    s->irq = irq;
+    s->codec.rxdrq = *drq ++;
+    s->codec.txdrq = *drq;
+    omap_eac_reset(s);
+
+    AUD_register_card("OMAP EAC", &s->codec.card);
+
+    iomemtype = cpu_register_io_memory(omap_eac_readfn,
+                    omap_eac_writefn, s, DEVICE_NATIVE_ENDIAN);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+/* STI/XTI (emulation interface) console - reverse engineered only */
+struct omap_sti_s {
+    qemu_irq irq;
+    CharDriverState *chr;
+
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t clkcontrol;
+    uint32_t serial_config;
+};
+
+#define STI_TRACE_CONSOLE_CHANNEL	239
+#define STI_TRACE_CONTROL_CHANNEL	253
+
+static inline void omap_sti_interrupt_update(struct omap_sti_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static void omap_sti_reset(struct omap_sti_s *s)
+{
+    s->sysconfig = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->clkcontrol = 0;
+    s->serial_config = 0;
+
+    omap_sti_interrupt_update(s);
+}
+
+static uint32_t omap_sti_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_sti_s *s = (struct omap_sti_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* STI_REVISION */
+        return 0x10;
+
+    case 0x10:	/* STI_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x14:	/* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
+        return 0x00;
+
+    case 0x18:	/* STI_IRQSTATUS */
+        return s->irqst;
+
+    case 0x1c:	/* STI_IRQSETEN / STI_IRQCLREN */
+        return s->irqen;
+
+    case 0x24:	/* STI_ER / STI_DR / XTI_TRACESELECT */
+    case 0x28:	/* STI_RX_DR / XTI_RXDATA */
+        /* TODO */
+        return 0;
+
+    case 0x2c:	/* STI_CLK_CTRL / XTI_SCLKCRTL */
+        return s->clkcontrol;
+
+    case 0x30:	/* STI_SERIAL_CFG / XTI_SCONFIG */
+        return s->serial_config;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sti_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sti_s *s = (struct omap_sti_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* STI_REVISION */
+    case 0x14:	/* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10:	/* STI_SYSCONFIG */
+        if (value & (1 << 1))				/* SOFTRESET */
+            omap_sti_reset(s);
+        s->sysconfig = value & 0xfe;
+        break;
+
+    case 0x18:	/* STI_IRQSTATUS */
+        s->irqst &= ~value;
+        omap_sti_interrupt_update(s);
+        break;
+
+    case 0x1c:	/* STI_IRQSETEN / STI_IRQCLREN */
+        s->irqen = value & 0xffff;
+        omap_sti_interrupt_update(s);
+        break;
+
+    case 0x2c:	/* STI_CLK_CTRL / XTI_SCLKCRTL */
+        s->clkcontrol = value & 0xff;
+        break;
+
+    case 0x30:	/* STI_SERIAL_CFG / XTI_SCONFIG */
+        s->serial_config = value & 0xff;
+        break;
+
+    case 0x24:	/* STI_ER / STI_DR / XTI_TRACESELECT */
+    case 0x28:	/* STI_RX_DR / XTI_RXDATA */
+        /* TODO */
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_sti_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_sti_read,
+};
+
+static CPUWriteMemoryFunc * const omap_sti_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_sti_write,
+};
+
+static uint32_t omap_sti_fifo_read(void *opaque, target_phys_addr_t addr)
+{
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sti_fifo_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sti_s *s = (struct omap_sti_s *) opaque;
+    int ch = addr >> 6;
+    uint8_t byte = value;
+
+    if (ch == STI_TRACE_CONTROL_CHANNEL) {
+        /* Flush channel <i>value</i>.  */
+        qemu_chr_write(s->chr, (const uint8_t *) "\r", 1);
+    } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
+        if (value == 0xc0 || value == 0xc3) {
+            /* Open channel <i>ch</i>.  */
+        } else if (value == 0x00)
+            qemu_chr_write(s->chr, (const uint8_t *) "\n", 1);
+        else
+            qemu_chr_write(s->chr, &byte, 1);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_sti_fifo_readfn[] = {
+    omap_sti_fifo_read,
+    omap_badwidth_read8,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_sti_fifo_writefn[] = {
+    omap_sti_fifo_write,
+    omap_badwidth_write8,
+    omap_badwidth_write8,
+};
+
+static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
+                target_phys_addr_t channel_base, qemu_irq irq, omap_clk clk,
+                CharDriverState *chr)
+{
+    int iomemtype;
+    struct omap_sti_s *s = (struct omap_sti_s *)
+            qemu_mallocz(sizeof(struct omap_sti_s));
+
+    s->irq = irq;
+    omap_sti_reset(s);
+
+    s->chr = chr ?: qemu_chr_open("null", "null", NULL);
+
+    iomemtype = l4_register_io_memory(omap_sti_readfn,
+                    omap_sti_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    iomemtype = cpu_register_io_memory(omap_sti_fifo_readfn,
+                    omap_sti_fifo_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(channel_base, 0x10000, iomemtype);
+
+    return s;
+}
+
+/* L4 Interconnect */
+#define L4TA(n)		(n)
+#define L4TAO(n)	((n) + 39)
+
+static const struct omap_l4_region_s omap_l4_region[125] = {
+    [  1] = { 0x40800,  0x800, 32          }, /* Initiator agent */
+    [  2] = { 0x41000, 0x1000, 32          }, /* Link agent */
+    [  0] = { 0x40000,  0x800, 32          }, /* Address and protection */
+    [  3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */
+    [  4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */
+    [  5] = { 0x04000, 0x1000, 32 | 16     }, /* 32K Timer */
+    [  6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */
+    [  7] = { 0x08000,  0x800, 32          }, /* PRCM Region A */
+    [  8] = { 0x08800,  0x800, 32          }, /* PRCM Region B */
+    [  9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */
+    [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */
+    [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */
+    [ 12] = { 0x14000, 0x1000, 32          }, /* Test/emulation (TAP) */
+    [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */
+    [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */
+    [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */
+    [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */
+    [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */
+    [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */
+    [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */
+    [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */
+    [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */
+    [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */
+    [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */
+    [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */
+    [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */
+    [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */
+    [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */
+    [ 28] = { 0x50000,  0x400, 32 | 16 | 8 }, /* Display top */
+    [ 29] = { 0x50400,  0x400, 32 | 16 | 8 }, /* Display control */
+    [ 30] = { 0x50800,  0x400, 32 | 16 | 8 }, /* Display RFBI */
+    [ 31] = { 0x50c00,  0x400, 32 | 16 | 8 }, /* Display encoder */
+    [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */
+    [ 33] = { 0x52000,  0x400, 32 | 16 | 8 }, /* Camera top */
+    [ 34] = { 0x52400,  0x400, 32 | 16 | 8 }, /* Camera core */
+    [ 35] = { 0x52800,  0x400, 32 | 16 | 8 }, /* Camera DMA */
+    [ 36] = { 0x52c00,  0x400, 32 | 16 | 8 }, /* Camera MMU */
+    [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */
+    [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */
+    [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */
+    [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */
+    [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */
+    [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */
+    [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */
+    [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */
+    [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */
+    [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */
+    [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */
+    [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */
+    [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */
+    [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */
+    [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */
+    [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */
+    [ 53] = { 0x66000,  0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */
+    [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */
+    [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */
+    [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */
+    [ 57] = { 0x6a000, 0x1000,      16 | 8 }, /* UART1 */
+    [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */
+    [ 59] = { 0x6c000, 0x1000,      16 | 8 }, /* UART2 */
+    [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */
+    [ 61] = { 0x6e000, 0x1000,      16 | 8 }, /* UART3 */
+    [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */
+    [ 63] = { 0x70000, 0x1000,      16     }, /* I2C1 */
+    [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */
+    [ 65] = { 0x72000, 0x1000,      16     }, /* I2C2 */
+    [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */
+    [ 67] = { 0x74000, 0x1000,      16     }, /* McBSP1 */
+    [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */
+    [ 69] = { 0x76000, 0x1000,      16     }, /* McBSP2 */
+    [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */
+    [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */
+    [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */
+    [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */
+    [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */
+    [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */
+    [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */
+    [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */
+    [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */
+    [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */
+    [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */
+    [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */
+    [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */
+    [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */
+    [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */
+    [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */
+    [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */
+    [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */
+    [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */
+    [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */
+    [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */
+    [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */
+    [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */
+    [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */
+    [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */
+    [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */
+    [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */
+    [ 97] = { 0x90000, 0x1000,      16     }, /* EAC */
+    [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */
+    [ 99] = { 0x92000, 0x1000,      16     }, /* FAC */
+    [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */
+    [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */
+    [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */
+    [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */
+    [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */
+    [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */
+    [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */
+    [107] = { 0x9c000, 0x1000,      16 | 8 }, /* MMC SDIO */
+    [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */
+    [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */
+    [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */
+    [111] = { 0xa0000, 0x1000, 32          }, /* RNG */
+    [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */
+    [113] = { 0xa2000, 0x1000, 32          }, /* DES3DES */
+    [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */
+    [115] = { 0xa4000, 0x1000, 32          }, /* SHA1MD5 */
+    [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */
+    [117] = { 0xa6000, 0x1000, 32          }, /* AES */
+    [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */
+    [119] = { 0xa8000, 0x2000, 32          }, /* PKA */
+    [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */
+    [121] = { 0xb0000, 0x1000, 32          }, /* MG */
+    [122] = { 0xb1000, 0x1000, 32 | 16 | 8 },
+    [123] = { 0xb2000, 0x1000, 32          }, /* HDQ/1-Wire */
+    [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
+};
+
+static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = {
+    { 0,           0, 3, 2 }, /* L4IA initiatior agent */
+    { L4TAO(1),    3, 2, 1 }, /* Control and pinout module */
+    { L4TAO(2),    5, 2, 1 }, /* 32K timer */
+    { L4TAO(3),    7, 3, 2 }, /* PRCM */
+    { L4TA(1),    10, 2, 1 }, /* BCM */
+    { L4TA(2),    12, 2, 1 }, /* Test JTAG */
+    { L4TA(3),    14, 6, 3 }, /* Quad GPIO */
+    { L4TA(4),    20, 4, 3 }, /* WD timer 1/2 */
+    { L4TA(7),    24, 2, 1 }, /* GP timer 1 */
+    { L4TA(9),    26, 2, 1 }, /* ATM11 ETB */
+    { L4TA(10),   28, 5, 4 }, /* Display subsystem */
+    { L4TA(11),   33, 5, 4 }, /* Camera subsystem */
+    { L4TA(12),   38, 2, 1 }, /* sDMA */
+    { L4TA(13),   40, 5, 4 }, /* SSI */
+    { L4TAO(4),   45, 2, 1 }, /* USB */
+    { L4TA(14),   47, 2, 1 }, /* Win Tracer1 */
+    { L4TA(15),   49, 2, 1 }, /* Win Tracer2 */
+    { L4TA(16),   51, 2, 1 }, /* Win Tracer3 */
+    { L4TA(17),   53, 2, 1 }, /* Win Tracer4 */
+    { L4TA(18),   55, 2, 1 }, /* XTI */
+    { L4TA(19),   57, 2, 1 }, /* UART1 */
+    { L4TA(20),   59, 2, 1 }, /* UART2 */
+    { L4TA(21),   61, 2, 1 }, /* UART3 */
+    { L4TAO(5),   63, 2, 1 }, /* I2C1 */
+    { L4TAO(6),   65, 2, 1 }, /* I2C2 */
+    { L4TAO(7),   67, 2, 1 }, /* McBSP1 */
+    { L4TAO(8),   69, 2, 1 }, /* McBSP2 */
+    { L4TA(5),    71, 2, 1 }, /* WD Timer 3 (DSP) */
+    { L4TA(6),    73, 2, 1 }, /* WD Timer 4 (IVA) */
+    { L4TA(8),    75, 2, 1 }, /* GP Timer 2 */
+    { L4TA(22),   77, 2, 1 }, /* GP Timer 3 */
+    { L4TA(23),   79, 2, 1 }, /* GP Timer 4 */
+    { L4TA(24),   81, 2, 1 }, /* GP Timer 5 */
+    { L4TA(25),   83, 2, 1 }, /* GP Timer 6 */
+    { L4TA(26),   85, 2, 1 }, /* GP Timer 7 */
+    { L4TA(27),   87, 2, 1 }, /* GP Timer 8 */
+    { L4TA(28),   89, 2, 1 }, /* GP Timer 9 */
+    { L4TA(29),   91, 2, 1 }, /* GP Timer 10 */
+    { L4TA(30),   93, 2, 1 }, /* GP Timer 11 */
+    { L4TA(31),   95, 2, 1 }, /* GP Timer 12 */
+    { L4TA(32),   97, 2, 1 }, /* EAC */
+    { L4TA(33),   99, 2, 1 }, /* FAC */
+    { L4TA(34),  101, 2, 1 }, /* IPC */
+    { L4TA(35),  103, 2, 1 }, /* SPI1 */
+    { L4TA(36),  105, 2, 1 }, /* SPI2 */
+    { L4TAO(9),  107, 2, 1 }, /* MMC SDIO */
+    { L4TAO(10), 109, 2, 1 },
+    { L4TAO(11), 111, 2, 1 }, /* RNG */
+    { L4TAO(12), 113, 2, 1 }, /* DES3DES */
+    { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */
+    { L4TA(37),  117, 2, 1 }, /* AES */
+    { L4TA(38),  119, 2, 1 }, /* PKA */
+    { -1,        121, 2, 1 },
+    { L4TA(39),  123, 2, 1 }, /* HDQ/1-Wire */
+};
+
+#define omap_l4ta(bus, cs)	\
+    omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs))
+#define omap_l4tao(bus, cs)	\
+    omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs))
+
+/* Power, Reset, and Clock Management */
+struct omap_prcm_s {
+    qemu_irq irq[3];
+    struct omap_mpu_state_s *mpu;
+
+    uint32_t irqst[3];
+    uint32_t irqen[3];
+
+    uint32_t sysconfig;
+    uint32_t voltctrl;
+    uint32_t scratch[20];
+
+    uint32_t clksrc[1];
+    uint32_t clkout[1];
+    uint32_t clkemul[1];
+    uint32_t clkpol[1];
+    uint32_t clksel[8];
+    uint32_t clken[12];
+    uint32_t clkctrl[4];
+    uint32_t clkidle[7];
+    uint32_t setuptime[2];
+
+    uint32_t wkup[3];
+    uint32_t wken[3];
+    uint32_t wkst[3];
+    uint32_t rst[4];
+    uint32_t rstctrl[1];
+    uint32_t power[4];
+    uint32_t rsttime_wkup;
+
+    uint32_t ev;
+    uint32_t evtime[2];
+
+    int dpll_lock, apll_lock[2];
+};
+
+static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
+{
+    qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]);
+    /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */
+}
+
+static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
+    uint32_t ret;
+
+    switch (addr) {
+    case 0x000:	/* PRCM_REVISION */
+        return 0x10;
+
+    case 0x010:	/* PRCM_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x018:	/* PRCM_IRQSTATUS_MPU */
+        return s->irqst[0];
+
+    case 0x01c:	/* PRCM_IRQENABLE_MPU */
+        return s->irqen[0];
+
+    case 0x050:	/* PRCM_VOLTCTRL */
+        return s->voltctrl;
+    case 0x054:	/* PRCM_VOLTST */
+        return s->voltctrl & 3;
+
+    case 0x060:	/* PRCM_CLKSRC_CTRL */
+        return s->clksrc[0];
+    case 0x070:	/* PRCM_CLKOUT_CTRL */
+        return s->clkout[0];
+    case 0x078:	/* PRCM_CLKEMUL_CTRL */
+        return s->clkemul[0];
+    case 0x080:	/* PRCM_CLKCFG_CTRL */
+    case 0x084:	/* PRCM_CLKCFG_STATUS */
+        return 0;
+
+    case 0x090:	/* PRCM_VOLTSETUP */
+        return s->setuptime[0];
+
+    case 0x094:	/* PRCM_CLKSSETUP */
+        return s->setuptime[1];
+
+    case 0x098:	/* PRCM_POLCTRL */
+        return s->clkpol[0];
+
+    case 0x0b0:	/* GENERAL_PURPOSE1 */
+    case 0x0b4:	/* GENERAL_PURPOSE2 */
+    case 0x0b8:	/* GENERAL_PURPOSE3 */
+    case 0x0bc:	/* GENERAL_PURPOSE4 */
+    case 0x0c0:	/* GENERAL_PURPOSE5 */
+    case 0x0c4:	/* GENERAL_PURPOSE6 */
+    case 0x0c8:	/* GENERAL_PURPOSE7 */
+    case 0x0cc:	/* GENERAL_PURPOSE8 */
+    case 0x0d0:	/* GENERAL_PURPOSE9 */
+    case 0x0d4:	/* GENERAL_PURPOSE10 */
+    case 0x0d8:	/* GENERAL_PURPOSE11 */
+    case 0x0dc:	/* GENERAL_PURPOSE12 */
+    case 0x0e0:	/* GENERAL_PURPOSE13 */
+    case 0x0e4:	/* GENERAL_PURPOSE14 */
+    case 0x0e8:	/* GENERAL_PURPOSE15 */
+    case 0x0ec:	/* GENERAL_PURPOSE16 */
+    case 0x0f0:	/* GENERAL_PURPOSE17 */
+    case 0x0f4:	/* GENERAL_PURPOSE18 */
+    case 0x0f8:	/* GENERAL_PURPOSE19 */
+    case 0x0fc:	/* GENERAL_PURPOSE20 */
+        return s->scratch[(addr - 0xb0) >> 2];
+
+    case 0x140:	/* CM_CLKSEL_MPU */
+        return s->clksel[0];
+    case 0x148:	/* CM_CLKSTCTRL_MPU */
+        return s->clkctrl[0];
+
+    case 0x158:	/* RM_RSTST_MPU */
+        return s->rst[0];
+    case 0x1c8:	/* PM_WKDEP_MPU */
+        return s->wkup[0];
+    case 0x1d4:	/* PM_EVGENCTRL_MPU */
+        return s->ev;
+    case 0x1d8:	/* PM_EVEGENONTIM_MPU */
+        return s->evtime[0];
+    case 0x1dc:	/* PM_EVEGENOFFTIM_MPU */
+        return s->evtime[1];
+    case 0x1e0:	/* PM_PWSTCTRL_MPU */
+        return s->power[0];
+    case 0x1e4:	/* PM_PWSTST_MPU */
+        return 0;
+
+    case 0x200:	/* CM_FCLKEN1_CORE */
+        return s->clken[0];
+    case 0x204:	/* CM_FCLKEN2_CORE */
+        return s->clken[1];
+    case 0x210:	/* CM_ICLKEN1_CORE */
+        return s->clken[2];
+    case 0x214:	/* CM_ICLKEN2_CORE */
+        return s->clken[3];
+    case 0x21c:	/* CM_ICLKEN4_CORE */
+        return s->clken[4];
+
+    case 0x220:	/* CM_IDLEST1_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x7ffffff9;
+    case 0x224:	/* CM_IDLEST2_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x00000007;
+    case 0x22c:	/* CM_IDLEST4_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x0000001f;
+
+    case 0x230:	/* CM_AUTOIDLE1_CORE */
+        return s->clkidle[0];
+    case 0x234:	/* CM_AUTOIDLE2_CORE */
+        return s->clkidle[1];
+    case 0x238:	/* CM_AUTOIDLE3_CORE */
+        return s->clkidle[2];
+    case 0x23c:	/* CM_AUTOIDLE4_CORE */
+        return s->clkidle[3];
+
+    case 0x240:	/* CM_CLKSEL1_CORE */
+        return s->clksel[1];
+    case 0x244:	/* CM_CLKSEL2_CORE */
+        return s->clksel[2];
+
+    case 0x248:	/* CM_CLKSTCTRL_CORE */
+        return s->clkctrl[1];
+
+    case 0x2a0:	/* PM_WKEN1_CORE */
+        return s->wken[0];
+    case 0x2a4:	/* PM_WKEN2_CORE */
+        return s->wken[1];
+
+    case 0x2b0:	/* PM_WKST1_CORE */
+        return s->wkst[0];
+    case 0x2b4:	/* PM_WKST2_CORE */
+        return s->wkst[1];
+    case 0x2c8:	/* PM_WKDEP_CORE */
+        return 0x1e;
+
+    case 0x2e0:	/* PM_PWSTCTRL_CORE */
+        return s->power[1];
+    case 0x2e4:	/* PM_PWSTST_CORE */
+        return 0x000030 | (s->power[1] & 0xfc00);
+
+    case 0x300:	/* CM_FCLKEN_GFX */
+        return s->clken[5];
+    case 0x310:	/* CM_ICLKEN_GFX */
+        return s->clken[6];
+    case 0x320:	/* CM_IDLEST_GFX */
+        /* TODO: check the actual iclk status */
+        return 0x00000001;
+    case 0x340:	/* CM_CLKSEL_GFX */
+        return s->clksel[3];
+    case 0x348:	/* CM_CLKSTCTRL_GFX */
+        return s->clkctrl[2];
+    case 0x350:	/* RM_RSTCTRL_GFX */
+        return s->rstctrl[0];
+    case 0x358:	/* RM_RSTST_GFX */
+        return s->rst[1];
+    case 0x3c8:	/* PM_WKDEP_GFX */
+        return s->wkup[1];
+
+    case 0x3e0:	/* PM_PWSTCTRL_GFX */
+        return s->power[2];
+    case 0x3e4:	/* PM_PWSTST_GFX */
+        return s->power[2] & 3;
+
+    case 0x400:	/* CM_FCLKEN_WKUP */
+        return s->clken[7];
+    case 0x410:	/* CM_ICLKEN_WKUP */
+        return s->clken[8];
+    case 0x420:	/* CM_IDLEST_WKUP */
+        /* TODO: check the actual iclk status */
+        return 0x0000003f;
+    case 0x430:	/* CM_AUTOIDLE_WKUP */
+        return s->clkidle[4];
+    case 0x440:	/* CM_CLKSEL_WKUP */
+        return s->clksel[4];
+    case 0x450:	/* RM_RSTCTRL_WKUP */
+        return 0;
+    case 0x454:	/* RM_RSTTIME_WKUP */
+        return s->rsttime_wkup;
+    case 0x458:	/* RM_RSTST_WKUP */
+        return s->rst[2];
+    case 0x4a0:	/* PM_WKEN_WKUP */
+        return s->wken[2];
+    case 0x4b0:	/* PM_WKST_WKUP */
+        return s->wkst[2];
+
+    case 0x500:	/* CM_CLKEN_PLL */
+        return s->clken[9];
+    case 0x520:	/* CM_IDLEST_CKGEN */
+        ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
+        if (!(s->clksel[6] & 3))
+            /* Core uses 32-kHz clock */
+            ret |= 3 << 0;
+        else if (!s->dpll_lock)
+            /* DPLL not locked, core uses ref_clk */
+            ret |= 1 << 0;
+        else
+            /* Core uses DPLL */
+            ret |= 2 << 0;
+        return ret;
+    case 0x530:	/* CM_AUTOIDLE_PLL */
+        return s->clkidle[5];
+    case 0x540:	/* CM_CLKSEL1_PLL */
+        return s->clksel[5];
+    case 0x544:	/* CM_CLKSEL2_PLL */
+        return s->clksel[6];
+
+    case 0x800:	/* CM_FCLKEN_DSP */
+        return s->clken[10];
+    case 0x810:	/* CM_ICLKEN_DSP */
+        return s->clken[11];
+    case 0x820:	/* CM_IDLEST_DSP */
+        /* TODO: check the actual iclk status */
+        return 0x00000103;
+    case 0x830:	/* CM_AUTOIDLE_DSP */
+        return s->clkidle[6];
+    case 0x840:	/* CM_CLKSEL_DSP */
+        return s->clksel[7];
+    case 0x848:	/* CM_CLKSTCTRL_DSP */
+        return s->clkctrl[3];
+    case 0x850:	/* RM_RSTCTRL_DSP */
+        return 0;
+    case 0x858:	/* RM_RSTST_DSP */
+        return s->rst[3];
+    case 0x8c8:	/* PM_WKDEP_DSP */
+        return s->wkup[2];
+    case 0x8e0:	/* PM_PWSTCTRL_DSP */
+        return s->power[3];
+    case 0x8e4:	/* PM_PWSTST_DSP */
+        return 0x008030 | (s->power[3] & 0x3003);
+
+    case 0x8f0:	/* PRCM_IRQSTATUS_DSP */
+        return s->irqst[1];
+    case 0x8f4:	/* PRCM_IRQENABLE_DSP */
+        return s->irqen[1];
+
+    case 0x8f8:	/* PRCM_IRQSTATUS_IVA */
+        return s->irqst[2];
+    case 0x8fc:	/* PRCM_IRQENABLE_IVA */
+        return s->irqen[2];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_prcm_apll_update(struct omap_prcm_s *s)
+{
+    int mode[2];
+
+    mode[0] = (s->clken[9] >> 6) & 3;
+    s->apll_lock[0] = (mode[0] == 3);
+    mode[1] = (s->clken[9] >> 2) & 3;
+    s->apll_lock[1] = (mode[1] == 3);
+    /* TODO: update clocks */
+
+    if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2)
+        fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
+                        __FUNCTION__);
+}
+
+static void omap_prcm_dpll_update(struct omap_prcm_s *s)
+{
+    omap_clk dpll = omap_findclk(s->mpu, "dpll");
+    omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
+    omap_clk core = omap_findclk(s->mpu, "core_clk");
+    int mode = (s->clken[9] >> 0) & 3;
+    int mult, div;
+
+    mult = (s->clksel[5] >> 12) & 0x3ff;
+    div = (s->clksel[5] >> 8) & 0xf;
+    if (mult == 0 || mult == 1)
+        mode = 1;	/* Bypass */
+
+    s->dpll_lock = 0;
+    switch (mode) {
+    case 0:
+        fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__);
+        break;
+    case 1:	/* Low-power bypass mode (Default) */
+    case 2:	/* Fast-relock bypass mode */
+        omap_clk_setrate(dpll, 1, 1);
+        omap_clk_setrate(dpll_x2, 1, 1);
+        break;
+    case 3:	/* Lock mode */
+        s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)).  */
+
+        omap_clk_setrate(dpll, div + 1, mult);
+        omap_clk_setrate(dpll_x2, div + 1, mult * 2);
+        break;
+    }
+
+    switch ((s->clksel[6] >> 0) & 3) {
+    case 0:
+        omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
+        break;
+    case 1:
+        omap_clk_reparent(core, dpll);
+        break;
+    case 2:
+        /* Default */
+        omap_clk_reparent(core, dpll_x2);
+        break;
+    case 3:
+        fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__);
+        break;
+    }
+}
+
+static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
+
+    switch (addr) {
+    case 0x000:	/* PRCM_REVISION */
+    case 0x054:	/* PRCM_VOLTST */
+    case 0x084:	/* PRCM_CLKCFG_STATUS */
+    case 0x1e4:	/* PM_PWSTST_MPU */
+    case 0x220:	/* CM_IDLEST1_CORE */
+    case 0x224:	/* CM_IDLEST2_CORE */
+    case 0x22c:	/* CM_IDLEST4_CORE */
+    case 0x2c8:	/* PM_WKDEP_CORE */
+    case 0x2e4:	/* PM_PWSTST_CORE */
+    case 0x320:	/* CM_IDLEST_GFX */
+    case 0x3e4:	/* PM_PWSTST_GFX */
+    case 0x420:	/* CM_IDLEST_WKUP */
+    case 0x520:	/* CM_IDLEST_CKGEN */
+    case 0x820:	/* CM_IDLEST_DSP */
+    case 0x8e4:	/* PM_PWSTST_DSP */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x010:	/* PRCM_SYSCONFIG */
+        s->sysconfig = value & 1;
+        break;
+
+    case 0x018:	/* PRCM_IRQSTATUS_MPU */
+        s->irqst[0] &= ~value;
+        omap_prcm_int_update(s, 0);
+        break;
+    case 0x01c:	/* PRCM_IRQENABLE_MPU */
+        s->irqen[0] = value & 0x3f;
+        omap_prcm_int_update(s, 0);
+        break;
+
+    case 0x050:	/* PRCM_VOLTCTRL */
+        s->voltctrl = value & 0xf1c3;
+        break;
+
+    case 0x060:	/* PRCM_CLKSRC_CTRL */
+        s->clksrc[0] = value & 0xdb;
+        /* TODO update clocks */
+        break;
+
+    case 0x070:	/* PRCM_CLKOUT_CTRL */
+        s->clkout[0] = value & 0xbbbb;
+        /* TODO update clocks */
+        break;
+
+    case 0x078:	/* PRCM_CLKEMUL_CTRL */
+        s->clkemul[0] = value & 1;
+        /* TODO update clocks */
+        break;
+
+    case 0x080:	/* PRCM_CLKCFG_CTRL */
+        break;
+
+    case 0x090:	/* PRCM_VOLTSETUP */
+        s->setuptime[0] = value & 0xffff;
+        break;
+    case 0x094:	/* PRCM_CLKSSETUP */
+        s->setuptime[1] = value & 0xffff;
+        break;
+
+    case 0x098:	/* PRCM_POLCTRL */
+        s->clkpol[0] = value & 0x701;
+        break;
+
+    case 0x0b0:	/* GENERAL_PURPOSE1 */
+    case 0x0b4:	/* GENERAL_PURPOSE2 */
+    case 0x0b8:	/* GENERAL_PURPOSE3 */
+    case 0x0bc:	/* GENERAL_PURPOSE4 */
+    case 0x0c0:	/* GENERAL_PURPOSE5 */
+    case 0x0c4:	/* GENERAL_PURPOSE6 */
+    case 0x0c8:	/* GENERAL_PURPOSE7 */
+    case 0x0cc:	/* GENERAL_PURPOSE8 */
+    case 0x0d0:	/* GENERAL_PURPOSE9 */
+    case 0x0d4:	/* GENERAL_PURPOSE10 */
+    case 0x0d8:	/* GENERAL_PURPOSE11 */
+    case 0x0dc:	/* GENERAL_PURPOSE12 */
+    case 0x0e0:	/* GENERAL_PURPOSE13 */
+    case 0x0e4:	/* GENERAL_PURPOSE14 */
+    case 0x0e8:	/* GENERAL_PURPOSE15 */
+    case 0x0ec:	/* GENERAL_PURPOSE16 */
+    case 0x0f0:	/* GENERAL_PURPOSE17 */
+    case 0x0f4:	/* GENERAL_PURPOSE18 */
+    case 0x0f8:	/* GENERAL_PURPOSE19 */
+    case 0x0fc:	/* GENERAL_PURPOSE20 */
+        s->scratch[(addr - 0xb0) >> 2] = value;
+        break;
+
+    case 0x140:	/* CM_CLKSEL_MPU */
+        s->clksel[0] = value & 0x1f;
+        /* TODO update clocks */
+        break;
+    case 0x148:	/* CM_CLKSTCTRL_MPU */
+        s->clkctrl[0] = value & 0x1f;
+        break;
+
+    case 0x158:	/* RM_RSTST_MPU */
+        s->rst[0] &= ~value;
+        break;
+    case 0x1c8:	/* PM_WKDEP_MPU */
+        s->wkup[0] = value & 0x15;
+        break;
+
+    case 0x1d4:	/* PM_EVGENCTRL_MPU */
+        s->ev = value & 0x1f;
+        break;
+    case 0x1d8:	/* PM_EVEGENONTIM_MPU */
+        s->evtime[0] = value;
+        break;
+    case 0x1dc:	/* PM_EVEGENOFFTIM_MPU */
+        s->evtime[1] = value;
+        break;
+
+    case 0x1e0:	/* PM_PWSTCTRL_MPU */
+        s->power[0] = value & 0xc0f;
+        break;
+
+    case 0x200:	/* CM_FCLKEN1_CORE */
+        s->clken[0] = value & 0xbfffffff;
+        /* TODO update clocks */
+        /* The EN_EAC bit only gets/puts func_96m_clk.  */
+        break;
+    case 0x204:	/* CM_FCLKEN2_CORE */
+        s->clken[1] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x210:	/* CM_ICLKEN1_CORE */
+        s->clken[2] = value & 0xfffffff9;
+        /* TODO update clocks */
+        /* The EN_EAC bit only gets/puts core_l4_iclk.  */
+        break;
+    case 0x214:	/* CM_ICLKEN2_CORE */
+        s->clken[3] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x21c:	/* CM_ICLKEN4_CORE */
+        s->clken[4] = value & 0x0000001f;
+        /* TODO update clocks */
+        break;
+
+    case 0x230:	/* CM_AUTOIDLE1_CORE */
+        s->clkidle[0] = value & 0xfffffff9;
+        /* TODO update clocks */
+        break;
+    case 0x234:	/* CM_AUTOIDLE2_CORE */
+        s->clkidle[1] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x238:	/* CM_AUTOIDLE3_CORE */
+        s->clkidle[2] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x23c:	/* CM_AUTOIDLE4_CORE */
+        s->clkidle[3] = value & 0x0000001f;
+        /* TODO update clocks */
+        break;
+
+    case 0x240:	/* CM_CLKSEL1_CORE */
+        s->clksel[1] = value & 0x0fffbf7f;
+        /* TODO update clocks */
+        break;
+
+    case 0x244:	/* CM_CLKSEL2_CORE */
+        s->clksel[2] = value & 0x00fffffc;
+        /* TODO update clocks */
+        break;
+
+    case 0x248:	/* CM_CLKSTCTRL_CORE */
+        s->clkctrl[1] = value & 0x7;
+        break;
+
+    case 0x2a0:	/* PM_WKEN1_CORE */
+        s->wken[0] = value & 0x04667ff8;
+        break;
+    case 0x2a4:	/* PM_WKEN2_CORE */
+        s->wken[1] = value & 0x00000005;
+        break;
+
+    case 0x2b0:	/* PM_WKST1_CORE */
+        s->wkst[0] &= ~value;
+        break;
+    case 0x2b4:	/* PM_WKST2_CORE */
+        s->wkst[1] &= ~value;
+        break;
+
+    case 0x2e0:	/* PM_PWSTCTRL_CORE */
+        s->power[1] = (value & 0x00fc3f) | (1 << 2);
+        break;
+
+    case 0x300:	/* CM_FCLKEN_GFX */
+        s->clken[5] = value & 6;
+        /* TODO update clocks */
+        break;
+    case 0x310:	/* CM_ICLKEN_GFX */
+        s->clken[6] = value & 1;
+        /* TODO update clocks */
+        break;
+    case 0x340:	/* CM_CLKSEL_GFX */
+        s->clksel[3] = value & 7;
+        /* TODO update clocks */
+        break;
+    case 0x348:	/* CM_CLKSTCTRL_GFX */
+        s->clkctrl[2] = value & 1;
+        break;
+    case 0x350:	/* RM_RSTCTRL_GFX */
+        s->rstctrl[0] = value & 1;
+        /* TODO: reset */
+        break;
+    case 0x358:	/* RM_RSTST_GFX */
+        s->rst[1] &= ~value;
+        break;
+    case 0x3c8:	/* PM_WKDEP_GFX */
+        s->wkup[1] = value & 0x13;
+        break;
+    case 0x3e0:	/* PM_PWSTCTRL_GFX */
+        s->power[2] = (value & 0x00c0f) | (3 << 2);
+        break;
+
+    case 0x400:	/* CM_FCLKEN_WKUP */
+        s->clken[7] = value & 0xd;
+        /* TODO update clocks */
+        break;
+    case 0x410:	/* CM_ICLKEN_WKUP */
+        s->clken[8] = value & 0x3f;
+        /* TODO update clocks */
+        break;
+    case 0x430:	/* CM_AUTOIDLE_WKUP */
+        s->clkidle[4] = value & 0x0000003f;
+        /* TODO update clocks */
+        break;
+    case 0x440:	/* CM_CLKSEL_WKUP */
+        s->clksel[4] = value & 3;
+        /* TODO update clocks */
+        break;
+    case 0x450:	/* RM_RSTCTRL_WKUP */
+        /* TODO: reset */
+        if (value & 2)
+            qemu_system_reset_request();
+        break;
+    case 0x454:	/* RM_RSTTIME_WKUP */
+        s->rsttime_wkup = value & 0x1fff;
+        break;
+    case 0x458:	/* RM_RSTST_WKUP */
+        s->rst[2] &= ~value;
+        break;
+    case 0x4a0:	/* PM_WKEN_WKUP */
+        s->wken[2] = value & 0x00000005;
+        break;
+    case 0x4b0:	/* PM_WKST_WKUP */
+        s->wkst[2] &= ~value;
+        break;
+
+    case 0x500:	/* CM_CLKEN_PLL */
+        if (value & 0xffffff30)
+            fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
+                            "future compatiblity\n", __FUNCTION__);
+        if ((s->clken[9] ^ value) & 0xcc) {
+            s->clken[9] &= ~0xcc;
+            s->clken[9] |= value & 0xcc;
+            omap_prcm_apll_update(s);
+        }
+        if ((s->clken[9] ^ value) & 3) {
+            s->clken[9] &= ~3;
+            s->clken[9] |= value & 3;
+            omap_prcm_dpll_update(s);
+        }
+        break;
+    case 0x530:	/* CM_AUTOIDLE_PLL */
+        s->clkidle[5] = value & 0x000000cf;
+        /* TODO update clocks */
+        break;
+    case 0x540:	/* CM_CLKSEL1_PLL */
+        if (value & 0xfc4000d7)
+            fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
+                            "future compatiblity\n", __FUNCTION__);
+        if ((s->clksel[5] ^ value) & 0x003fff00) {
+            s->clksel[5] = value & 0x03bfff28;
+            omap_prcm_dpll_update(s);
+        }
+        /* TODO update the other clocks */
+
+        s->clksel[5] = value & 0x03bfff28;
+        break;
+    case 0x544:	/* CM_CLKSEL2_PLL */
+        if (value & ~3)
+            fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
+                            "future compatiblity\n", __FUNCTION__);
+        if (s->clksel[6] != (value & 3)) {
+            s->clksel[6] = value & 3;
+            omap_prcm_dpll_update(s);
+        }
+        break;
+
+    case 0x800:	/* CM_FCLKEN_DSP */
+        s->clken[10] = value & 0x501;
+        /* TODO update clocks */
+        break;
+    case 0x810:	/* CM_ICLKEN_DSP */
+        s->clken[11] = value & 0x2;
+        /* TODO update clocks */
+        break;
+    case 0x830:	/* CM_AUTOIDLE_DSP */
+        s->clkidle[6] = value & 0x2;
+        /* TODO update clocks */
+        break;
+    case 0x840:	/* CM_CLKSEL_DSP */
+        s->clksel[7] = value & 0x3fff;
+        /* TODO update clocks */
+        break;
+    case 0x848:	/* CM_CLKSTCTRL_DSP */
+        s->clkctrl[3] = value & 0x101;
+        break;
+    case 0x850:	/* RM_RSTCTRL_DSP */
+        /* TODO: reset */
+        break;
+    case 0x858:	/* RM_RSTST_DSP */
+        s->rst[3] &= ~value;
+        break;
+    case 0x8c8:	/* PM_WKDEP_DSP */
+        s->wkup[2] = value & 0x13;
+        break;
+    case 0x8e0:	/* PM_PWSTCTRL_DSP */
+        s->power[3] = (value & 0x03017) | (3 << 2);
+        break;
+
+    case 0x8f0:	/* PRCM_IRQSTATUS_DSP */
+        s->irqst[1] &= ~value;
+        omap_prcm_int_update(s, 1);
+        break;
+    case 0x8f4:	/* PRCM_IRQENABLE_DSP */
+        s->irqen[1] = value & 0x7;
+        omap_prcm_int_update(s, 1);
+        break;
+
+    case 0x8f8:	/* PRCM_IRQSTATUS_IVA */
+        s->irqst[2] &= ~value;
+        omap_prcm_int_update(s, 2);
+        break;
+    case 0x8fc:	/* PRCM_IRQENABLE_IVA */
+        s->irqen[2] = value & 0x7;
+        omap_prcm_int_update(s, 2);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_prcm_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_prcm_read,
+};
+
+static CPUWriteMemoryFunc * const omap_prcm_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_prcm_write,
+};
+
+static void omap_prcm_reset(struct omap_prcm_s *s)
+{
+    s->sysconfig = 0;
+    s->irqst[0] = 0;
+    s->irqst[1] = 0;
+    s->irqst[2] = 0;
+    s->irqen[0] = 0;
+    s->irqen[1] = 0;
+    s->irqen[2] = 0;
+    s->voltctrl = 0x1040;
+    s->ev = 0x14;
+    s->evtime[0] = 0;
+    s->evtime[1] = 0;
+    s->clkctrl[0] = 0;
+    s->clkctrl[1] = 0;
+    s->clkctrl[2] = 0;
+    s->clkctrl[3] = 0;
+    s->clken[1] = 7;
+    s->clken[3] = 7;
+    s->clken[4] = 0;
+    s->clken[5] = 0;
+    s->clken[6] = 0;
+    s->clken[7] = 0xc;
+    s->clken[8] = 0x3e;
+    s->clken[9] = 0x0d;
+    s->clken[10] = 0;
+    s->clken[11] = 0;
+    s->clkidle[0] = 0;
+    s->clkidle[2] = 7;
+    s->clkidle[3] = 0;
+    s->clkidle[4] = 0;
+    s->clkidle[5] = 0x0c;
+    s->clkidle[6] = 0;
+    s->clksel[0] = 0x01;
+    s->clksel[1] = 0x02100121;
+    s->clksel[2] = 0x00000000;
+    s->clksel[3] = 0x01;
+    s->clksel[4] = 0;
+    s->clksel[7] = 0x0121;
+    s->wkup[0] = 0x15;
+    s->wkup[1] = 0x13;
+    s->wkup[2] = 0x13;
+    s->wken[0] = 0x04667ff8;
+    s->wken[1] = 0x00000005;
+    s->wken[2] = 5;
+    s->wkst[0] = 0;
+    s->wkst[1] = 0;
+    s->wkst[2] = 0;
+    s->power[0] = 0x00c;
+    s->power[1] = 4;
+    s->power[2] = 0x0000c;
+    s->power[3] = 0x14;
+    s->rstctrl[0] = 1;
+    s->rst[3] = 1;
+    omap_prcm_apll_update(s);
+    omap_prcm_dpll_update(s);
+}
+
+static void omap_prcm_coldreset(struct omap_prcm_s *s)
+{
+    s->setuptime[0] = 0;
+    s->setuptime[1] = 0;
+    memset(&s->scratch, 0, sizeof(s->scratch));
+    s->rst[0] = 0x01;
+    s->rst[1] = 0x00;
+    s->rst[2] = 0x01;
+    s->clken[0] = 0;
+    s->clken[2] = 0;
+    s->clkidle[1] = 0;
+    s->clksel[5] = 0;
+    s->clksel[6] = 2;
+    s->clksrc[0] = 0x43;
+    s->clkout[0] = 0x0303;
+    s->clkemul[0] = 0;
+    s->clkpol[0] = 0x100;
+    s->rsttime_wkup = 0x1002;
+
+    omap_prcm_reset(s);
+}
+
+static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
+                qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap_prcm_s *s = (struct omap_prcm_s *)
+            qemu_mallocz(sizeof(struct omap_prcm_s));
+
+    s->irq[0] = mpu_int;
+    s->irq[1] = dsp_int;
+    s->irq[2] = iva_int;
+    s->mpu = mpu;
+    omap_prcm_coldreset(s);
+
+    iomemtype = l4_register_io_memory(omap_prcm_readfn,
+                    omap_prcm_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+    omap_l4_attach(ta, 1, iomemtype);
+
+    return s;
+}
+
+/* System and Pinout control */
+struct omap_sysctl_s {
+    struct omap_mpu_state_s *mpu;
+
+    uint32_t sysconfig;
+    uint32_t devconfig;
+    uint32_t psaconfig;
+    uint32_t padconf[0x45];
+    uint8_t obs;
+    uint32_t msuspendmux[5];
+};
+
+static uint32_t omap_sysctl_read8(void *opaque, target_phys_addr_t addr)
+{
+
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+    int pad_offset, byte_offset;
+    int value;
+
+    switch (addr) {
+    case 0x030 ... 0x140:	/* CONTROL_PADCONF - only used in the POP */
+        pad_offset = (addr - 0x30) >> 2;
+        byte_offset = (addr - 0x30) & (4 - 1);
+
+        value = s->padconf[pad_offset];
+        value = (value >> (byte_offset * 8)) & 0xff;
+
+        return value;
+
+    default:
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+
+    switch (addr) {
+    case 0x000:	/* CONTROL_REVISION */
+        return 0x20;
+
+    case 0x010:	/* CONTROL_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x030 ... 0x140:	/* CONTROL_PADCONF - only used in the POP */
+        return s->padconf[(addr - 0x30) >> 2];
+
+    case 0x270:	/* CONTROL_DEBOBS */
+        return s->obs;
+
+    case 0x274:	/* CONTROL_DEVCONF */
+        return s->devconfig;
+
+    case 0x28c:	/* CONTROL_EMU_SUPPORT */
+        return 0;
+
+    case 0x290:	/* CONTROL_MSUSPENDMUX_0 */
+        return s->msuspendmux[0];
+    case 0x294:	/* CONTROL_MSUSPENDMUX_1 */
+        return s->msuspendmux[1];
+    case 0x298:	/* CONTROL_MSUSPENDMUX_2 */
+        return s->msuspendmux[2];
+    case 0x29c:	/* CONTROL_MSUSPENDMUX_3 */
+        return s->msuspendmux[3];
+    case 0x2a0:	/* CONTROL_MSUSPENDMUX_4 */
+        return s->msuspendmux[4];
+    case 0x2a4:	/* CONTROL_MSUSPENDMUX_5 */
+        return 0;
+
+    case 0x2b8:	/* CONTROL_PSA_CTRL */
+        return s->psaconfig;
+    case 0x2bc:	/* CONTROL_PSA_CMD */
+    case 0x2c0:	/* CONTROL_PSA_VALUE */
+        return 0;
+
+    case 0x2b0:	/* CONTROL_SEC_CTRL */
+        return 0x800000f1;
+    case 0x2d0:	/* CONTROL_SEC_EMU */
+        return 0x80000015;
+    case 0x2d4:	/* CONTROL_SEC_TAP */
+        return 0x8000007f;
+    case 0x2b4:	/* CONTROL_SEC_TEST */
+    case 0x2f0:	/* CONTROL_SEC_STATUS */
+    case 0x2f4:	/* CONTROL_SEC_ERR_STATUS */
+        /* Secure mode is not present on general-pusrpose device.  Outside
+         * secure mode these values cannot be read or written.  */
+        return 0;
+
+    case 0x2d8:	/* CONTROL_OCM_RAM_PERM */
+        return 0xff;
+    case 0x2dc:	/* CONTROL_OCM_PUB_RAM_ADD */
+    case 0x2e0:	/* CONTROL_EXT_SEC_RAM_START_ADD */
+    case 0x2e4:	/* CONTROL_EXT_SEC_RAM_STOP_ADD */
+        /* No secure mode so no Extended Secure RAM present.  */
+        return 0;
+
+    case 0x2f8:	/* CONTROL_STATUS */
+        /* Device Type => General-purpose */
+        return 0x0300;
+    case 0x2fc:	/* CONTROL_GENERAL_PURPOSE_STATUS */
+
+    case 0x300:	/* CONTROL_RPUB_KEY_H_0 */
+    case 0x304:	/* CONTROL_RPUB_KEY_H_1 */
+    case 0x308:	/* CONTROL_RPUB_KEY_H_2 */
+    case 0x30c:	/* CONTROL_RPUB_KEY_H_3 */
+        return 0xdecafbad;
+
+    case 0x310:	/* CONTROL_RAND_KEY_0 */
+    case 0x314:	/* CONTROL_RAND_KEY_1 */
+    case 0x318:	/* CONTROL_RAND_KEY_2 */
+    case 0x31c:	/* CONTROL_RAND_KEY_3 */
+    case 0x320:	/* CONTROL_CUST_KEY_0 */
+    case 0x324:	/* CONTROL_CUST_KEY_1 */
+    case 0x330:	/* CONTROL_TEST_KEY_0 */
+    case 0x334:	/* CONTROL_TEST_KEY_1 */
+    case 0x338:	/* CONTROL_TEST_KEY_2 */
+    case 0x33c:	/* CONTROL_TEST_KEY_3 */
+    case 0x340:	/* CONTROL_TEST_KEY_4 */
+    case 0x344:	/* CONTROL_TEST_KEY_5 */
+    case 0x348:	/* CONTROL_TEST_KEY_6 */
+    case 0x34c:	/* CONTROL_TEST_KEY_7 */
+    case 0x350:	/* CONTROL_TEST_KEY_8 */
+    case 0x354:	/* CONTROL_TEST_KEY_9 */
+        /* Can only be accessed in secure mode and when C_FieldAccEnable
+         * bit is set in CONTROL_SEC_CTRL.
+         * TODO: otherwise an interconnect access error is generated.  */
+        return 0;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sysctl_write8(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+    int pad_offset, byte_offset;
+    int prev_value;
+
+    switch (addr) {
+    case 0x030 ... 0x140:	/* CONTROL_PADCONF - only used in the POP */
+        pad_offset = (addr - 0x30) >> 2;
+        byte_offset = (addr - 0x30) & (4 - 1);
+
+        prev_value = s->padconf[pad_offset];
+        prev_value &= ~(0xff << (byte_offset * 8));
+        prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f;
+        s->padconf[pad_offset] = prev_value;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        break;
+    }
+}
+
+static void omap_sysctl_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+
+    switch (addr) {
+    case 0x000:	/* CONTROL_REVISION */
+    case 0x2a4:	/* CONTROL_MSUSPENDMUX_5 */
+    case 0x2c0:	/* CONTROL_PSA_VALUE */
+    case 0x2f8:	/* CONTROL_STATUS */
+    case 0x2fc:	/* CONTROL_GENERAL_PURPOSE_STATUS */
+    case 0x300:	/* CONTROL_RPUB_KEY_H_0 */
+    case 0x304:	/* CONTROL_RPUB_KEY_H_1 */
+    case 0x308:	/* CONTROL_RPUB_KEY_H_2 */
+    case 0x30c:	/* CONTROL_RPUB_KEY_H_3 */
+    case 0x310:	/* CONTROL_RAND_KEY_0 */
+    case 0x314:	/* CONTROL_RAND_KEY_1 */
+    case 0x318:	/* CONTROL_RAND_KEY_2 */
+    case 0x31c:	/* CONTROL_RAND_KEY_3 */
+    case 0x320:	/* CONTROL_CUST_KEY_0 */
+    case 0x324:	/* CONTROL_CUST_KEY_1 */
+    case 0x330:	/* CONTROL_TEST_KEY_0 */
+    case 0x334:	/* CONTROL_TEST_KEY_1 */
+    case 0x338:	/* CONTROL_TEST_KEY_2 */
+    case 0x33c:	/* CONTROL_TEST_KEY_3 */
+    case 0x340:	/* CONTROL_TEST_KEY_4 */
+    case 0x344:	/* CONTROL_TEST_KEY_5 */
+    case 0x348:	/* CONTROL_TEST_KEY_6 */
+    case 0x34c:	/* CONTROL_TEST_KEY_7 */
+    case 0x350:	/* CONTROL_TEST_KEY_8 */
+    case 0x354:	/* CONTROL_TEST_KEY_9 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x010:	/* CONTROL_SYSCONFIG */
+        s->sysconfig = value & 0x1e;
+        break;
+
+    case 0x030 ... 0x140:	/* CONTROL_PADCONF - only used in the POP */
+        /* XXX: should check constant bits */
+        s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f;
+        break;
+
+    case 0x270:	/* CONTROL_DEBOBS */
+        s->obs = value & 0xff;
+        break;
+
+    case 0x274:	/* CONTROL_DEVCONF */
+        s->devconfig = value & 0xffffc7ff;
+        break;
+
+    case 0x28c:	/* CONTROL_EMU_SUPPORT */
+        break;
+
+    case 0x290:	/* CONTROL_MSUSPENDMUX_0 */
+        s->msuspendmux[0] = value & 0x3fffffff;
+        break;
+    case 0x294:	/* CONTROL_MSUSPENDMUX_1 */
+        s->msuspendmux[1] = value & 0x3fffffff;
+        break;
+    case 0x298:	/* CONTROL_MSUSPENDMUX_2 */
+        s->msuspendmux[2] = value & 0x3fffffff;
+        break;
+    case 0x29c:	/* CONTROL_MSUSPENDMUX_3 */
+        s->msuspendmux[3] = value & 0x3fffffff;
+        break;
+    case 0x2a0:	/* CONTROL_MSUSPENDMUX_4 */
+        s->msuspendmux[4] = value & 0x3fffffff;
+        break;
+
+    case 0x2b8:	/* CONTROL_PSA_CTRL */
+        s->psaconfig = value & 0x1c;
+        s->psaconfig |= (value & 0x20) ? 2 : 1;
+        break;
+    case 0x2bc:	/* CONTROL_PSA_CMD */
+        break;
+
+    case 0x2b0:	/* CONTROL_SEC_CTRL */
+    case 0x2b4:	/* CONTROL_SEC_TEST */
+    case 0x2d0:	/* CONTROL_SEC_EMU */
+    case 0x2d4:	/* CONTROL_SEC_TAP */
+    case 0x2d8:	/* CONTROL_OCM_RAM_PERM */
+    case 0x2dc:	/* CONTROL_OCM_PUB_RAM_ADD */
+    case 0x2e0:	/* CONTROL_EXT_SEC_RAM_START_ADD */
+    case 0x2e4:	/* CONTROL_EXT_SEC_RAM_STOP_ADD */
+    case 0x2f0:	/* CONTROL_SEC_STATUS */
+    case 0x2f4:	/* CONTROL_SEC_ERR_STATUS */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_sysctl_readfn[] = {
+    omap_sysctl_read8,
+    omap_badwidth_read32,	/* TODO */
+    omap_sysctl_read,
+};
+
+static CPUWriteMemoryFunc * const omap_sysctl_writefn[] = {
+    omap_sysctl_write8,
+    omap_badwidth_write32,	/* TODO */
+    omap_sysctl_write,
+};
+
+static void omap_sysctl_reset(struct omap_sysctl_s *s)
+{
+    /* (power-on reset) */
+    s->sysconfig = 0;
+    s->obs = 0;
+    s->devconfig = 0x0c000000;
+    s->msuspendmux[0] = 0x00000000;
+    s->msuspendmux[1] = 0x00000000;
+    s->msuspendmux[2] = 0x00000000;
+    s->msuspendmux[3] = 0x00000000;
+    s->msuspendmux[4] = 0x00000000;
+    s->psaconfig = 1;
+
+    s->padconf[0x00] = 0x000f0f0f;
+    s->padconf[0x01] = 0x00000000;
+    s->padconf[0x02] = 0x00000000;
+    s->padconf[0x03] = 0x00000000;
+    s->padconf[0x04] = 0x00000000;
+    s->padconf[0x05] = 0x00000000;
+    s->padconf[0x06] = 0x00000000;
+    s->padconf[0x07] = 0x00000000;
+    s->padconf[0x08] = 0x08080800;
+    s->padconf[0x09] = 0x08080808;
+    s->padconf[0x0a] = 0x08080808;
+    s->padconf[0x0b] = 0x08080808;
+    s->padconf[0x0c] = 0x08080808;
+    s->padconf[0x0d] = 0x08080800;
+    s->padconf[0x0e] = 0x08080808;
+    s->padconf[0x0f] = 0x08080808;
+    s->padconf[0x10] = 0x18181808;	/* | 0x07070700 if SBoot3 */
+    s->padconf[0x11] = 0x18181818;	/* | 0x07070707 if SBoot3 */
+    s->padconf[0x12] = 0x18181818;	/* | 0x07070707 if SBoot3 */
+    s->padconf[0x13] = 0x18181818;	/* | 0x07070707 if SBoot3 */
+    s->padconf[0x14] = 0x18181818;	/* | 0x00070707 if SBoot3 */
+    s->padconf[0x15] = 0x18181818;
+    s->padconf[0x16] = 0x18181818;	/* | 0x07000000 if SBoot3 */
+    s->padconf[0x17] = 0x1f001f00;
+    s->padconf[0x18] = 0x1f1f1f1f;
+    s->padconf[0x19] = 0x00000000;
+    s->padconf[0x1a] = 0x1f180000;
+    s->padconf[0x1b] = 0x00001f1f;
+    s->padconf[0x1c] = 0x1f001f00;
+    s->padconf[0x1d] = 0x00000000;
+    s->padconf[0x1e] = 0x00000000;
+    s->padconf[0x1f] = 0x08000000;
+    s->padconf[0x20] = 0x08080808;
+    s->padconf[0x21] = 0x08080808;
+    s->padconf[0x22] = 0x0f080808;
+    s->padconf[0x23] = 0x0f0f0f0f;
+    s->padconf[0x24] = 0x000f0f0f;
+    s->padconf[0x25] = 0x1f1f1f0f;
+    s->padconf[0x26] = 0x080f0f1f;
+    s->padconf[0x27] = 0x070f1808;
+    s->padconf[0x28] = 0x0f070707;
+    s->padconf[0x29] = 0x000f0f1f;
+    s->padconf[0x2a] = 0x0f0f0f1f;
+    s->padconf[0x2b] = 0x08000000;
+    s->padconf[0x2c] = 0x0000001f;
+    s->padconf[0x2d] = 0x0f0f1f00;
+    s->padconf[0x2e] = 0x1f1f0f0f;
+    s->padconf[0x2f] = 0x0f1f1f1f;
+    s->padconf[0x30] = 0x0f0f0f0f;
+    s->padconf[0x31] = 0x0f1f0f1f;
+    s->padconf[0x32] = 0x0f0f0f0f;
+    s->padconf[0x33] = 0x0f1f0f1f;
+    s->padconf[0x34] = 0x1f1f0f0f;
+    s->padconf[0x35] = 0x0f0f1f1f;
+    s->padconf[0x36] = 0x0f0f1f0f;
+    s->padconf[0x37] = 0x0f0f0f0f;
+    s->padconf[0x38] = 0x1f18180f;
+    s->padconf[0x39] = 0x1f1f1f1f;
+    s->padconf[0x3a] = 0x00001f1f;
+    s->padconf[0x3b] = 0x00000000;
+    s->padconf[0x3c] = 0x00000000;
+    s->padconf[0x3d] = 0x0f0f0f0f;
+    s->padconf[0x3e] = 0x18000f0f;
+    s->padconf[0x3f] = 0x00070000;
+    s->padconf[0x40] = 0x00000707;
+    s->padconf[0x41] = 0x0f1f0700;
+    s->padconf[0x42] = 0x1f1f070f;
+    s->padconf[0x43] = 0x0008081f;
+    s->padconf[0x44] = 0x00000800;
+}
+
+static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
+                omap_clk iclk, struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *)
+            qemu_mallocz(sizeof(struct omap_sysctl_s));
+
+    s->mpu = mpu;
+    omap_sysctl_reset(s);
+
+    iomemtype = l4_register_io_memory(omap_sysctl_readfn,
+                    omap_sysctl_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+/* General chip reset */
+static void omap2_mpu_reset(void *opaque)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    omap_inth_reset(mpu->ih[0]);
+    omap_dma_reset(mpu->dma);
+    omap_prcm_reset(mpu->prcm);
+    omap_sysctl_reset(mpu->sysc);
+    omap_gp_timer_reset(mpu->gptimer[0]);
+    omap_gp_timer_reset(mpu->gptimer[1]);
+    omap_gp_timer_reset(mpu->gptimer[2]);
+    omap_gp_timer_reset(mpu->gptimer[3]);
+    omap_gp_timer_reset(mpu->gptimer[4]);
+    omap_gp_timer_reset(mpu->gptimer[5]);
+    omap_gp_timer_reset(mpu->gptimer[6]);
+    omap_gp_timer_reset(mpu->gptimer[7]);
+    omap_gp_timer_reset(mpu->gptimer[8]);
+    omap_gp_timer_reset(mpu->gptimer[9]);
+    omap_gp_timer_reset(mpu->gptimer[10]);
+    omap_gp_timer_reset(mpu->gptimer[11]);
+    omap_synctimer_reset(mpu->synctimer);
+    omap_sdrc_reset(mpu->sdrc);
+    omap_gpmc_reset(mpu->gpmc);
+    omap_dss_reset(mpu->dss);
+    omap_uart_reset(mpu->uart[0]);
+    omap_uart_reset(mpu->uart[1]);
+    omap_uart_reset(mpu->uart[2]);
+    omap_mmc_reset(mpu->mmc);
+    omap_gpif_reset(mpu->gpif);
+    omap_mcspi_reset(mpu->mcspi[0]);
+    omap_mcspi_reset(mpu->mcspi[1]);
+    omap_i2c_reset(mpu->i2c[0]);
+    omap_i2c_reset(mpu->i2c[1]);
+    cpu_reset(mpu->env);
+}
+
+static int omap2_validate_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return 1;
+}
+
+static const struct dma_irq_map omap2_dma_irq_map[] = {
+    { 0, OMAP_INT_24XX_SDMA_IRQ0 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ1 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ2 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ3 },
+};
+
+struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
+                const char *core)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_state_s));
+    ram_addr_t sram_base, q2_base;
+    qemu_irq *cpu_irq;
+    qemu_irq dma_irqs[4];
+    omap_clk gpio_clks[4];
+    DriveInfo *dinfo;
+    int i;
+
+    /* Core */
+    s->mpu_model = omap2420;
+    s->env = cpu_init(core ?: "arm1136-r2");
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->sdram_size = sdram_size;
+    s->sram_size = OMAP242X_SRAM_SIZE;
+
+    s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
+
+    /* Clocks */
+    omap_clk_init(s);
+
+    /* Memory-mapped stuff */
+    cpu_register_physical_memory(OMAP2_Q2_BASE, s->sdram_size,
+                    (q2_base = qemu_ram_alloc(NULL, "omap2.dram",
+                                              s->sdram_size)) | IO_MEM_RAM);
+    cpu_register_physical_memory(OMAP2_SRAM_BASE, s->sram_size,
+                    (sram_base = qemu_ram_alloc(NULL, "omap2.sram",
+                                                s->sram_size)) | IO_MEM_RAM);
+
+    s->l4 = omap_l4_init(OMAP2_L4_BASE, 54);
+
+    /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
+    cpu_irq = arm_pic_init_cpu(s->env);
+    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
+                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
+                    omap_findclk(s, "mpu_intc_fclk"),
+                    omap_findclk(s, "mpu_intc_iclk"));
+
+    s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
+                    s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s);
+
+    s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
+                    omap_findclk(s, "omapctrl_iclk"), s);
+
+    for (i = 0; i < 4; i ++)
+        dma_irqs[i] =
+                s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr];
+    s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
+                    omap_findclk(s, "sdma_iclk"),
+                    omap_findclk(s, "sdma_fclk"));
+    s->port->addr_valid = omap2_validate_addr;
+
+    /* Register SDRAM and SRAM ports for fast DMA transfers.  */
+    soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size);
+    soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
+
+    s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
+                    s->irq[0][OMAP_INT_24XX_UART1_IRQ],
+                    omap_findclk(s, "uart1_fclk"),
+                    omap_findclk(s, "uart1_iclk"),
+                    s->drq[OMAP24XX_DMA_UART1_TX],
+                    s->drq[OMAP24XX_DMA_UART1_RX],
+                    "uart1",
+                    serial_hds[0]);
+    s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
+                    s->irq[0][OMAP_INT_24XX_UART2_IRQ],
+                    omap_findclk(s, "uart2_fclk"),
+                    omap_findclk(s, "uart2_iclk"),
+                    s->drq[OMAP24XX_DMA_UART2_TX],
+                    s->drq[OMAP24XX_DMA_UART2_RX],
+                    "uart2",
+                    serial_hds[0] ? serial_hds[1] : NULL);
+    s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
+                    s->irq[0][OMAP_INT_24XX_UART3_IRQ],
+                    omap_findclk(s, "uart3_fclk"),
+                    omap_findclk(s, "uart3_iclk"),
+                    s->drq[OMAP24XX_DMA_UART3_TX],
+                    s->drq[OMAP24XX_DMA_UART3_RX],
+                    "uart3",
+                    serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+
+    s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER1],
+                    omap_findclk(s, "wu_gpt1_clk"),
+                    omap_findclk(s, "wu_l4_iclk"));
+    s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER2],
+                    omap_findclk(s, "core_gpt2_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER3],
+                    omap_findclk(s, "core_gpt3_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER4],
+                    omap_findclk(s, "core_gpt4_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER5],
+                    omap_findclk(s, "core_gpt5_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER6],
+                    omap_findclk(s, "core_gpt6_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER7],
+                    omap_findclk(s, "core_gpt7_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER8],
+                    omap_findclk(s, "core_gpt8_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER9],
+                    omap_findclk(s, "core_gpt9_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER10],
+                    omap_findclk(s, "core_gpt10_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER11],
+                    omap_findclk(s, "core_gpt11_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER12],
+                    omap_findclk(s, "core_gpt12_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+
+    omap_tap_init(omap_l4ta(s->l4, 2), s);
+
+    s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s,
+                    omap_findclk(s, "clk32-kHz"),
+                    omap_findclk(s, "core_l4_iclk"));
+
+    s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
+                    s->irq[0][OMAP_INT_24XX_I2C1_IRQ],
+                    &s->drq[OMAP24XX_DMA_I2C1_TX],
+                    omap_findclk(s, "i2c1.fclk"),
+                    omap_findclk(s, "i2c1.iclk"));
+    s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
+                    s->irq[0][OMAP_INT_24XX_I2C2_IRQ],
+                    &s->drq[OMAP24XX_DMA_I2C2_TX],
+                    omap_findclk(s, "i2c2.fclk"),
+                    omap_findclk(s, "i2c2.iclk"));
+
+    gpio_clks[0] = omap_findclk(s, "gpio1_dbclk");
+    gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
+    gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
+    gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
+    s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
+                    &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
+                    gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
+
+    s->sdrc = omap_sdrc_init(0x68009000);
+    s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
+
+    dinfo = drive_get(IF_SD, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
+                    s->irq[0][OMAP_INT_24XX_MMC_IRQ],
+                    &s->drq[OMAP24XX_DMA_MMC1_TX],
+                    omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
+
+    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
+                    s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ],
+                    &s->drq[OMAP24XX_DMA_SPI1_TX0],
+                    omap_findclk(s, "spi1_fclk"),
+                    omap_findclk(s, "spi1_iclk"));
+    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
+                    s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ],
+                    &s->drq[OMAP24XX_DMA_SPI2_TX0],
+                    omap_findclk(s, "spi2_fclk"),
+                    omap_findclk(s, "spi2_iclk"));
+
+    s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800,
+                    /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
+                    s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
+                    omap_findclk(s, "dss_54m_clk"),
+                    omap_findclk(s, "dss_l3_iclk"),
+                    omap_findclk(s, "dss_l4_iclk"));
+
+    omap_sti_init(omap_l4ta(s->l4, 18), 0x54000000,
+                    s->irq[0][OMAP_INT_24XX_STI], omap_findclk(s, "emul_ck"),
+                    serial_hds[0] && serial_hds[1] && serial_hds[2] ?
+                    serial_hds[3] : NULL);
+
+    s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
+                    s->irq[0][OMAP_INT_24XX_EAC_IRQ],
+                    /* Ten consecutive lines */
+                    &s->drq[OMAP24XX_DMA_EAC_AC_RD],
+                    omap_findclk(s, "func_96m_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+
+    /* All register mappings (includin those not currenlty implemented):
+     * SystemControlMod	48000000 - 48000fff
+     * SystemControlL4	48001000 - 48001fff
+     * 32kHz Timer Mod	48004000 - 48004fff
+     * 32kHz Timer L4	48005000 - 48005fff
+     * PRCM ModA	48008000 - 480087ff
+     * PRCM ModB	48008800 - 48008fff
+     * PRCM L4		48009000 - 48009fff
+     * TEST-BCM Mod	48012000 - 48012fff
+     * TEST-BCM L4	48013000 - 48013fff
+     * TEST-TAP Mod	48014000 - 48014fff
+     * TEST-TAP L4	48015000 - 48015fff
+     * GPIO1 Mod	48018000 - 48018fff
+     * GPIO Top		48019000 - 48019fff
+     * GPIO2 Mod	4801a000 - 4801afff
+     * GPIO L4		4801b000 - 4801bfff
+     * GPIO3 Mod	4801c000 - 4801cfff
+     * GPIO4 Mod	4801e000 - 4801efff
+     * WDTIMER1 Mod	48020000 - 48010fff
+     * WDTIMER Top	48021000 - 48011fff
+     * WDTIMER2 Mod	48022000 - 48012fff
+     * WDTIMER L4	48023000 - 48013fff
+     * WDTIMER3 Mod	48024000 - 48014fff
+     * WDTIMER3 L4	48025000 - 48015fff
+     * WDTIMER4 Mod	48026000 - 48016fff
+     * WDTIMER4 L4	48027000 - 48017fff
+     * GPTIMER1 Mod	48028000 - 48018fff
+     * GPTIMER1 L4	48029000 - 48019fff
+     * GPTIMER2 Mod	4802a000 - 4801afff
+     * GPTIMER2 L4	4802b000 - 4801bfff
+     * L4-Config AP	48040000 - 480407ff
+     * L4-Config IP	48040800 - 48040fff
+     * L4-Config LA	48041000 - 48041fff
+     * ARM11ETB Mod	48048000 - 48049fff
+     * ARM11ETB L4	4804a000 - 4804afff
+     * DISPLAY Top	48050000 - 480503ff
+     * DISPLAY DISPC	48050400 - 480507ff
+     * DISPLAY RFBI	48050800 - 48050bff
+     * DISPLAY VENC	48050c00 - 48050fff
+     * DISPLAY L4	48051000 - 48051fff
+     * CAMERA Top	48052000 - 480523ff
+     * CAMERA core	48052400 - 480527ff
+     * CAMERA DMA	48052800 - 48052bff
+     * CAMERA MMU	48052c00 - 48052fff
+     * CAMERA L4	48053000 - 48053fff
+     * SDMA Mod		48056000 - 48056fff
+     * SDMA L4		48057000 - 48057fff
+     * SSI Top		48058000 - 48058fff
+     * SSI GDD		48059000 - 48059fff
+     * SSI Port1	4805a000 - 4805afff
+     * SSI Port2	4805b000 - 4805bfff
+     * SSI L4		4805c000 - 4805cfff
+     * USB Mod		4805e000 - 480fefff
+     * USB L4		4805f000 - 480fffff
+     * WIN_TRACER1 Mod	48060000 - 48060fff
+     * WIN_TRACER1 L4	48061000 - 48061fff
+     * WIN_TRACER2 Mod	48062000 - 48062fff
+     * WIN_TRACER2 L4	48063000 - 48063fff
+     * WIN_TRACER3 Mod	48064000 - 48064fff
+     * WIN_TRACER3 L4	48065000 - 48065fff
+     * WIN_TRACER4 Top	48066000 - 480660ff
+     * WIN_TRACER4 ETT	48066100 - 480661ff
+     * WIN_TRACER4 WT	48066200 - 480662ff
+     * WIN_TRACER4 L4	48067000 - 48067fff
+     * XTI Mod		48068000 - 48068fff
+     * XTI L4		48069000 - 48069fff
+     * UART1 Mod	4806a000 - 4806afff
+     * UART1 L4		4806b000 - 4806bfff
+     * UART2 Mod	4806c000 - 4806cfff
+     * UART2 L4		4806d000 - 4806dfff
+     * UART3 Mod	4806e000 - 4806efff
+     * UART3 L4		4806f000 - 4806ffff
+     * I2C1 Mod		48070000 - 48070fff
+     * I2C1 L4		48071000 - 48071fff
+     * I2C2 Mod		48072000 - 48072fff
+     * I2C2 L4		48073000 - 48073fff
+     * McBSP1 Mod	48074000 - 48074fff
+     * McBSP1 L4	48075000 - 48075fff
+     * McBSP2 Mod	48076000 - 48076fff
+     * McBSP2 L4	48077000 - 48077fff
+     * GPTIMER3 Mod	48078000 - 48078fff
+     * GPTIMER3 L4	48079000 - 48079fff
+     * GPTIMER4 Mod	4807a000 - 4807afff
+     * GPTIMER4 L4	4807b000 - 4807bfff
+     * GPTIMER5 Mod	4807c000 - 4807cfff
+     * GPTIMER5 L4	4807d000 - 4807dfff
+     * GPTIMER6 Mod	4807e000 - 4807efff
+     * GPTIMER6 L4	4807f000 - 4807ffff
+     * GPTIMER7 Mod	48080000 - 48080fff
+     * GPTIMER7 L4	48081000 - 48081fff
+     * GPTIMER8 Mod	48082000 - 48082fff
+     * GPTIMER8 L4	48083000 - 48083fff
+     * GPTIMER9 Mod	48084000 - 48084fff
+     * GPTIMER9 L4	48085000 - 48085fff
+     * GPTIMER10 Mod	48086000 - 48086fff
+     * GPTIMER10 L4	48087000 - 48087fff
+     * GPTIMER11 Mod	48088000 - 48088fff
+     * GPTIMER11 L4	48089000 - 48089fff
+     * GPTIMER12 Mod	4808a000 - 4808afff
+     * GPTIMER12 L4	4808b000 - 4808bfff
+     * EAC Mod		48090000 - 48090fff
+     * EAC L4		48091000 - 48091fff
+     * FAC Mod		48092000 - 48092fff
+     * FAC L4		48093000 - 48093fff
+     * MAILBOX Mod	48094000 - 48094fff
+     * MAILBOX L4	48095000 - 48095fff
+     * SPI1 Mod		48098000 - 48098fff
+     * SPI1 L4		48099000 - 48099fff
+     * SPI2 Mod		4809a000 - 4809afff
+     * SPI2 L4		4809b000 - 4809bfff
+     * MMC/SDIO Mod	4809c000 - 4809cfff
+     * MMC/SDIO L4	4809d000 - 4809dfff
+     * MS_PRO Mod	4809e000 - 4809efff
+     * MS_PRO L4	4809f000 - 4809ffff
+     * RNG Mod		480a0000 - 480a0fff
+     * RNG L4		480a1000 - 480a1fff
+     * DES3DES Mod	480a2000 - 480a2fff
+     * DES3DES L4	480a3000 - 480a3fff
+     * SHA1MD5 Mod	480a4000 - 480a4fff
+     * SHA1MD5 L4	480a5000 - 480a5fff
+     * AES Mod		480a6000 - 480a6fff
+     * AES L4		480a7000 - 480a7fff
+     * PKA Mod		480a8000 - 480a9fff
+     * PKA L4		480aa000 - 480aafff
+     * MG Mod		480b0000 - 480b0fff
+     * MG L4		480b1000 - 480b1fff
+     * HDQ/1-wire Mod	480b2000 - 480b2fff
+     * HDQ/1-wire L4	480b3000 - 480b3fff
+     * MPU interrupt	480fe000 - 480fefff
+     * STI channel base	54000000 - 5400ffff
+     * IVA RAM		5c000000 - 5c01ffff
+     * IVA ROM		5c020000 - 5c027fff
+     * IMG_BUF_A	5c040000 - 5c040fff
+     * IMG_BUF_B	5c042000 - 5c042fff
+     * VLCDS		5c048000 - 5c0487ff
+     * IMX_COEF		5c049000 - 5c04afff
+     * IMX_CMD		5c051000 - 5c051fff
+     * VLCDQ		5c053000 - 5c0533ff
+     * VLCDH		5c054000 - 5c054fff
+     * SEQ_CMD		5c055000 - 5c055fff
+     * IMX_REG		5c056000 - 5c0560ff
+     * VLCD_REG		5c056100 - 5c0561ff
+     * SEQ_REG		5c056200 - 5c0562ff
+     * IMG_BUF_REG	5c056300 - 5c0563ff
+     * SEQIRQ_REG	5c056400 - 5c0564ff
+     * OCP_REG		5c060000 - 5c060fff
+     * SYSC_REG		5c070000 - 5c070fff
+     * MMU_REG		5d000000 - 5d000fff
+     * sDMA R		68000400 - 680005ff
+     * sDMA W		68000600 - 680007ff
+     * Display Control	68000800 - 680009ff
+     * DSP subsystem	68000a00 - 68000bff
+     * MPU subsystem	68000c00 - 68000dff
+     * IVA subsystem	68001000 - 680011ff
+     * USB		68001200 - 680013ff
+     * Camera		68001400 - 680015ff
+     * VLYNQ (firewall)	68001800 - 68001bff
+     * VLYNQ		68001e00 - 68001fff
+     * SSI		68002000 - 680021ff
+     * L4		68002400 - 680025ff
+     * DSP (firewall)	68002800 - 68002bff
+     * DSP subsystem	68002e00 - 68002fff
+     * IVA (firewall)	68003000 - 680033ff
+     * IVA		68003600 - 680037ff
+     * GFX		68003a00 - 68003bff
+     * CMDWR emulation	68003c00 - 68003dff
+     * SMS		68004000 - 680041ff
+     * OCM		68004200 - 680043ff
+     * GPMC		68004400 - 680045ff
+     * RAM (firewall)	68005000 - 680053ff
+     * RAM (err login)	68005400 - 680057ff
+     * ROM (firewall)	68005800 - 68005bff
+     * ROM (err login)	68005c00 - 68005fff
+     * GPMC (firewall)	68006000 - 680063ff
+     * GPMC (err login)	68006400 - 680067ff
+     * SMS (err login)	68006c00 - 68006fff
+     * SMS registers	68008000 - 68008fff
+     * SDRC registers	68009000 - 68009fff
+     * GPMC registers	6800a000   6800afff
+     */
+
+    qemu_register_reset(omap2_mpu_reset, s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_clk.c b/qemu-0.15.x/hw/omap_clk.c
new file mode 100644
index 0000000..6bcabef
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_clk.c
@@ -0,0 +1,1260 @@
+/*
+ * OMAP clocks.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "omap.h"
+
+struct clk {
+    const char *name;
+    const char *alias;
+    struct clk *parent;
+    struct clk *child1;
+    struct clk *sibling;
+#define ALWAYS_ENABLED		(1 << 0)
+#define CLOCK_IN_OMAP310	(1 << 10)
+#define CLOCK_IN_OMAP730	(1 << 11)
+#define CLOCK_IN_OMAP1510	(1 << 12)
+#define CLOCK_IN_OMAP16XX	(1 << 13)
+#define CLOCK_IN_OMAP242X	(1 << 14)
+#define CLOCK_IN_OMAP243X	(1 << 15)
+#define CLOCK_IN_OMAP343X	(1 << 16)
+    uint32_t flags;
+    int id;
+
+    int running;		/* Is currently ticking */
+    int enabled;		/* Is enabled, regardless of its input clk */
+    unsigned long rate;		/* Current rate (if .running) */
+    unsigned int divisor;	/* Rate relative to input (if .enabled) */
+    unsigned int multiplier;	/* Rate relative to input (if .enabled) */
+    qemu_irq users[16];		/* Who to notify on change */
+    int usecount;		/* Automatically idle when unused */
+};
+
+static struct clk xtal_osc12m = {
+    .name	= "xtal_osc_12m",
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk xtal_osc32k = {
+    .name	= "xtal_osc_32k",
+    .rate	= 32768,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+};
+
+static struct clk ck_ref = {
+    .name	= "ck_ref",
+    .alias	= "clkin",
+    .parent	= &xtal_osc12m,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
+static struct clk dpll1 = {
+    .name	= "dpll1",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dpll2 = {
+    .name	= "dpll2",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll3 = {
+    .name	= "dpll3",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll4 = {
+    .name	= "dpll4",
+    .parent	= &ck_ref,
+    .multiplier	= 4,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk apll = {
+    .name	= "apll",
+    .parent	= &ck_ref,
+    .multiplier	= 48,
+    .divisor	= 12,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_48m = {
+    .name	= "ck_48m",
+    .parent	= &dpll4,	/* either dpll4 or apll */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_dpll1out = {
+    .name	= "ck_dpll1out",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk sossi_ck = {
+    .name	= "ck_sossi",
+    .parent	= &ck_dpll1out,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk clkm1 = {
+    .name	= "clkm1",
+    .alias	= "ck_gen1",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm2 = {
+    .name	= "clkm2",
+    .alias	= "ck_gen2",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm3 = {
+    .name	= "clkm3",
+    .alias	= "ck_gen3",
+    .parent	= &dpll1,	/* either dpll1 or ck_ref */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arm_ck = {
+    .name	= "arm_ck",
+    .alias	= "mpu_ck",
+    .parent	= &clkm1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk armper_ck = {
+    .name	= "armper_ck",
+    .alias	= "mpuper_ck",
+    .parent	= &clkm1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk arm_gpio_ck = {
+    .name	= "arm_gpio_ck",
+    .alias	= "mpu_gpio_ck",
+    .parent	= &clkm1,
+    .divisor	= 1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk armxor_ck = {
+    .name	= "armxor_ck",
+    .alias	= "mpuxor_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armtim_ck = {
+    .name	= "armtim_ck",
+    .alias	= "mputim_ck",
+    .parent	= &ck_ref,	/* either CLKIN or DPLL1 */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armwdt_ck = {
+    .name	= "armwdt_ck",
+    .alias	= "mpuwd_ck",
+    .parent	= &clkm1,
+    .divisor	= 14,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck16xx = {
+    .name	= "arminth_ck",
+    .parent	= &arm_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    /* Note: On 16xx the frequency can be divided by 2 by programming
+     * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+     *
+     * 1510 version is in TC clocks.
+     */
+};
+
+static struct clk dsp_ck = {
+    .name	= "dsp_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspmmu_ck = {
+    .name	= "dspmmu_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dspper_ck = {
+    .name	= "dspper_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspxor_ck = {
+    .name	= "dspxor_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dsptim_ck = {
+    .name	= "dsptim_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc_ck = {
+    .name	= "tc_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck15xx = {
+    .name	= "arminth_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+    /* Note: On 1510 the frequency follows TC_CK
+     *
+     * 16xx version is in MPU clocks.
+     */
+};
+
+static struct clk tipb_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "tipb_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk l3_ocpi_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "l3_ocpi_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc1_ck = {
+    .name	= "tc1_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc2_ck = {
+    .name	= "tc2_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dma_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "dma_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dma_lcdfree_ck = {
+    .name	= "dma_lcdfree_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk api_ck = {
+    .name	= "api_ck",
+    .alias	= "mpui_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk lb_ck = {
+    .name	= "lb_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk lbfree_ck = {
+    .name	= "lbfree_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk hsab_ck = {
+    .name	= "hsab_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk rhea1_ck = {
+    .name	= "rhea1_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk rhea2_ck = {
+    .name	= "rhea2_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk lcd_ck_16xx = {
+    .name	= "lcd_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
+};
+
+static struct clk lcd_ck_1510 = {
+    .name	= "lcd_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk uart1_1510 = {
+    .name	= "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart1_16xx = {
+    .name	= "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk uart2_ck = {
+    .name	= "uart2_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk uart3_1510 = {
+    .name	= "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart3_16xx = {
+    .name	= "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_clk0 = {	/* 6 MHz output on W4_USB_CLK0 */
+    .name	= "usb_clk0",
+    .alias	= "usb.clko",
+    /* Direct from ULPD, no parent */
+    .rate	= 6000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck1510 = {
+    .name	= "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate	= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck16xx = {
+    .name	= "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate	= 48000000,
+    /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_w2fc_mclk = {
+    .name	= "usb_w2fc_mclk",
+    .alias	= "usb_w2fc_ck",
+    .parent	= &ck_48m,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mclk_1510 = {
+    .name	= "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_310 = {
+    .name	= "bt_mclk_out",	/* Alias midi_mclk_out? */
+    .parent	= &armper_ck,
+    .flags	= CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_310 = {
+    .name	= "com_mclk_out",
+    .parent	= &armper_ck,
+    .flags	= CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_16xx = {
+    .name	= "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk bclk_1510 = {
+    .name	= "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_16xx = {
+    .name	= "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mmc1_ck = {
+    .name	= "mmc_ck",
+    .id		= 1,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk mmc2_ck = {
+    .name	= "mmc_ck",
+    .id		= 2,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk cam_mclk = {
+    .name	= "cam.mclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    .rate	= 12000000,
+};
+
+static struct clk cam_exclk = {
+    .name	= "cam.exclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    /* Either 12M from cam.mclk or 48M from dpll4 */
+    .parent	= &cam_mclk,
+};
+
+static struct clk cam_lclk = {
+    .name	= "cam.lclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk i2c_fck = {
+    .name	= "i2c_fck",
+    .id		= 1,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+    .parent	= &armxor_ck,
+};
+
+static struct clk i2c_ick = {
+    .name	= "i2c_ick",
+    .id		= 1,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    .parent	= &armper_ck,
+};
+
+static struct clk clk32k = {
+    .name	= "clk32-kHz",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent	= &xtal_osc32k,
+};
+
+static struct clk ref_clk = {
+    .name	= "ref_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 12000000,	/* 12 MHz or 13 MHz or 19.2 MHz */
+    /*.parent	= sys.xtalin */
+};
+
+static struct clk apll_96m = {
+    .name	= "apll_96m",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 96000000,
+    /*.parent	= ref_clk */
+};
+
+static struct clk apll_54m = {
+    .name	= "apll_54m",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 54000000,
+    /*.parent	= ref_clk */
+};
+
+static struct clk sys_clk = {
+    .name	= "sys_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 32768,
+    /*.parent	= sys.xtalin */
+};
+
+static struct clk sleep_clk = {
+    .name	= "sleep_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 32768,
+    /*.parent	= sys.xtalin */
+};
+
+static struct clk dpll_ck = {
+    .name	= "dpll",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent	= &ref_clk,
+};
+
+static struct clk dpll_x2_ck = {
+    .name	= "dpll_x2",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent	= &ref_clk,
+};
+
+static struct clk wdt1_sys_clk = {
+    .name	= "wdt1_sys_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate	= 32768,
+    /*.parent	= sys.xtalin */
+};
+
+static struct clk func_96m_clk = {
+    .name	= "func_96m_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor	= 1,
+    .parent	= &apll_96m,
+};
+
+static struct clk func_48m_clk = {
+    .name	= "func_48m_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor	= 2,
+    .parent	= &apll_96m,
+};
+
+static struct clk func_12m_clk = {
+    .name	= "func_12m_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor	= 8,
+    .parent	= &apll_96m,
+};
+
+static struct clk func_54m_clk = {
+    .name	= "func_54m_clk",
+    .flags	= CLOCK_IN_OMAP242X,
+    .divisor	= 1,
+    .parent	= &apll_54m,
+};
+
+static struct clk sys_clkout = {
+    .name	= "clkout",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk sys_clkout2 = {
+    .name	= "clkout2",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_clk = {
+    .name	= "core_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &dpll_x2_ck,	/* Switchable between dpll_ck and clk32k */
+};
+
+static struct clk l3_clk = {
+    .name	= "l3_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk core_l4_iclk = {
+    .name	= "core_l4_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &l3_clk,
+};
+
+static struct clk wu_l4_iclk = {
+    .name	= "wu_l4_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &l3_clk,
+};
+
+static struct clk core_l3_iclk = {
+    .name	= "core_l3_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk core_l4_usb_clk = {
+    .name	= "core_l4_usb_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &l3_clk,
+};
+
+static struct clk wu_gpt1_clk = {
+    .name	= "wu_gpt1_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk wu_32k_clk = {
+    .name	= "wu_32k_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk uart1_fclk = {
+    .name	= "uart1_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_48m_clk,
+};
+
+static struct clk uart1_iclk = {
+    .name	= "uart1_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk uart2_fclk = {
+    .name	= "uart2_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_48m_clk,
+};
+
+static struct clk uart2_iclk = {
+    .name	= "uart2_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk uart3_fclk = {
+    .name	= "uart3_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_48m_clk,
+};
+
+static struct clk uart3_iclk = {
+    .name	= "uart3_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk mpu_fclk = {
+    .name	= "mpu_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk mpu_iclk = {
+    .name	= "mpu_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk int_m_fclk = {
+    .name	= "int_m_fclk",
+    .alias	= "mpu_intc_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk int_m_iclk = {
+    .name	= "int_m_iclk",
+    .alias	= "mpu_intc_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_clk,
+};
+
+static struct clk core_gpt2_clk = {
+    .name	= "core_gpt2_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt3_clk = {
+    .name	= "core_gpt3_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt4_clk = {
+    .name	= "core_gpt4_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt5_clk = {
+    .name	= "core_gpt5_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt6_clk = {
+    .name	= "core_gpt6_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt7_clk = {
+    .name	= "core_gpt7_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt8_clk = {
+    .name	= "core_gpt8_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt9_clk = {
+    .name	= "core_gpt9_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt10_clk = {
+    .name	= "core_gpt10_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt11_clk = {
+    .name	= "core_gpt11_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk core_gpt12_clk = {
+    .name	= "core_gpt12_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &sys_clk,
+};
+
+static struct clk mcbsp1_clk = {
+    .name	= "mcbsp1_cg",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor	= 2,
+    .parent	= &func_96m_clk,
+};
+
+static struct clk mcbsp2_clk = {
+    .name	= "mcbsp2_cg",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor	= 2,
+    .parent	= &func_96m_clk,
+};
+
+static struct clk emul_clk = {
+    .name	= "emul_ck",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_54m_clk,
+};
+
+static struct clk sdma_fclk = {
+    .name	= "sdma_fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &l3_clk,
+};
+
+static struct clk sdma_iclk = {
+    .name	= "sdma_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l3_iclk, /* core_l4_iclk for the configuration port */
+};
+
+static struct clk i2c1_fclk = {
+    .name	= "i2c1.fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_12m_clk,
+    .divisor	= 1,
+};
+
+static struct clk i2c1_iclk = {
+    .name	= "i2c1.iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk i2c2_fclk = {
+    .name	= "i2c2.fclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_12m_clk,
+    .divisor	= 1,
+};
+
+static struct clk i2c2_iclk = {
+    .name	= "i2c2.iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk gpio_dbclk[4] = {
+    {
+        .name	= "gpio1_dbclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &wu_32k_clk,
+    }, {
+        .name	= "gpio2_dbclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &wu_32k_clk,
+    }, {
+        .name	= "gpio3_dbclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &wu_32k_clk,
+    }, {
+        .name	= "gpio4_dbclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &wu_32k_clk,
+    },
+};
+
+static struct clk gpio_iclk = {
+    .name	= "gpio_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &wu_l4_iclk,
+};
+
+static struct clk mmc_fck = {
+    .name	= "mmc_fclk",
+    .flags	= CLOCK_IN_OMAP242X,
+    .parent	= &func_96m_clk,
+};
+
+static struct clk mmc_ick = {
+    .name	= "mmc_iclk",
+    .flags	= CLOCK_IN_OMAP242X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk spi_fclk[3] = {
+    {
+        .name	= "spi1_fclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &func_48m_clk,
+    }, {
+        .name	= "spi2_fclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &func_48m_clk,
+    }, {
+        .name	= "spi3_fclk",
+        .flags	= CLOCK_IN_OMAP243X,
+        .parent	= &func_48m_clk,
+    },
+};
+
+static struct clk dss_clk[2] = {
+    {
+        .name	= "dss_clk1",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &core_clk,
+    }, {
+        .name	= "dss_clk2",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &sys_clk,
+    },
+};
+
+static struct clk dss_54m_clk = {
+    .name	= "dss_54m_clk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &func_54m_clk,
+};
+
+static struct clk dss_l3_iclk = {
+    .name	= "dss_l3_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l3_iclk,
+};
+
+static struct clk dss_l4_iclk = {
+    .name	= "dss_l4_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk spi_iclk[3] = {
+    {
+        .name	= "spi1_iclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &core_l4_iclk,
+    }, {
+        .name	= "spi2_iclk",
+        .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent	= &core_l4_iclk,
+    }, {
+        .name	= "spi3_iclk",
+        .flags	= CLOCK_IN_OMAP243X,
+        .parent	= &core_l4_iclk,
+    },
+};
+
+static struct clk omapctrl_clk = {
+    .name	= "omapctrl_iclk",
+    .flags	= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    /* XXX Should be in WKUP domain */
+    .parent	= &core_l4_iclk,
+};
+
+static struct clk *onchip_clks[] = {
+    /* OMAP 1 */
+
+    /* non-ULPD clocks */
+    &xtal_osc12m,
+    &xtal_osc32k,
+    &ck_ref,
+    &dpll1,
+    &dpll2,
+    &dpll3,
+    &dpll4,
+    &apll,
+    &ck_48m,
+    /* CK_GEN1 clocks */
+    &clkm1,
+    &ck_dpll1out,
+    &sossi_ck,
+    &arm_ck,
+    &armper_ck,
+    &arm_gpio_ck,
+    &armxor_ck,
+    &armtim_ck,
+    &armwdt_ck,
+    &arminth_ck15xx,  &arminth_ck16xx,
+    /* CK_GEN2 clocks */
+    &clkm2,
+    &dsp_ck,
+    &dspmmu_ck,
+    &dspper_ck,
+    &dspxor_ck,
+    &dsptim_ck,
+    /* CK_GEN3 clocks */
+    &clkm3,
+    &tc_ck,
+    &tipb_ck,
+    &l3_ocpi_ck,
+    &tc1_ck,
+    &tc2_ck,
+    &dma_ck,
+    &dma_lcdfree_ck,
+    &api_ck,
+    &lb_ck,
+    &lbfree_ck,
+    &hsab_ck,
+    &rhea1_ck,
+    &rhea2_ck,
+    &lcd_ck_16xx,
+    &lcd_ck_1510,
+    /* ULPD clocks */
+    &uart1_1510,
+    &uart1_16xx,
+    &uart2_ck,
+    &uart3_1510,
+    &uart3_16xx,
+    &usb_clk0,
+    &usb_hhc_ck1510, &usb_hhc_ck16xx,
+    &mclk_1510,  &mclk_16xx, &mclk_310,
+    &bclk_1510,  &bclk_16xx, &bclk_310,
+    &mmc1_ck,
+    &mmc2_ck,
+    &cam_mclk,
+    &cam_exclk,
+    &cam_lclk,
+    &clk32k,
+    &usb_w2fc_mclk,
+    /* Virtual clocks */
+    &i2c_fck,
+    &i2c_ick,
+
+    /* OMAP 2 */
+
+    &ref_clk,
+    &apll_96m,
+    &apll_54m,
+    &sys_clk,
+    &sleep_clk,
+    &dpll_ck,
+    &dpll_x2_ck,
+    &wdt1_sys_clk,
+    &func_96m_clk,
+    &func_48m_clk,
+    &func_12m_clk,
+    &func_54m_clk,
+    &sys_clkout,
+    &sys_clkout2,
+    &core_clk,
+    &l3_clk,
+    &core_l4_iclk,
+    &wu_l4_iclk,
+    &core_l3_iclk,
+    &core_l4_usb_clk,
+    &wu_gpt1_clk,
+    &wu_32k_clk,
+    &uart1_fclk,
+    &uart1_iclk,
+    &uart2_fclk,
+    &uart2_iclk,
+    &uart3_fclk,
+    &uart3_iclk,
+    &mpu_fclk,
+    &mpu_iclk,
+    &int_m_fclk,
+    &int_m_iclk,
+    &core_gpt2_clk,
+    &core_gpt3_clk,
+    &core_gpt4_clk,
+    &core_gpt5_clk,
+    &core_gpt6_clk,
+    &core_gpt7_clk,
+    &core_gpt8_clk,
+    &core_gpt9_clk,
+    &core_gpt10_clk,
+    &core_gpt11_clk,
+    &core_gpt12_clk,
+    &mcbsp1_clk,
+    &mcbsp2_clk,
+    &emul_clk,
+    &sdma_fclk,
+    &sdma_iclk,
+    &i2c1_fclk,
+    &i2c1_iclk,
+    &i2c2_fclk,
+    &i2c2_iclk,
+    &gpio_dbclk[0],
+    &gpio_dbclk[1],
+    &gpio_dbclk[2],
+    &gpio_dbclk[3],
+    &gpio_iclk,
+    &mmc_fck,
+    &mmc_ick,
+    &spi_fclk[0],
+    &spi_iclk[0],
+    &spi_fclk[1],
+    &spi_iclk[1],
+    &spi_fclk[2],
+    &spi_iclk[2],
+    &dss_clk[0],
+    &dss_clk[1],
+    &dss_54m_clk,
+    &dss_l3_iclk,
+    &dss_l4_iclk,
+    &omapctrl_clk,
+
+    NULL
+};
+
+void omap_clk_adduser(struct clk *clk, qemu_irq user)
+{
+    qemu_irq *i;
+
+    for (i = clk->users; *i; i ++);
+    *i = user;
+}
+
+struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name)
+{
+    struct clk *i;
+
+    for (i = mpu->clks; i->name; i ++)
+        if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
+            return i;
+    hw_error("%s: %s not found\n", __FUNCTION__, name);
+}
+
+void omap_clk_get(struct clk *clk)
+{
+    clk->usecount ++;
+}
+
+void omap_clk_put(struct clk *clk)
+{
+    if (!(clk->usecount --))
+        hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name);
+}
+
+static void omap_clk_update(struct clk *clk)
+{
+    int parent, running;
+    qemu_irq *user;
+    struct clk *i;
+
+    if (clk->parent)
+        parent = clk->parent->running;
+    else
+        parent = 1;
+
+    running = parent && (clk->enabled ||
+                    ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
+    if (clk->running != running) {
+        clk->running = running;
+        for (user = clk->users; *user; user ++)
+            qemu_set_irq(*user, running);
+        for (i = clk->child1; i; i = i->sibling)
+            omap_clk_update(i);
+    }
+}
+
+static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate,
+                unsigned long int div, unsigned long int mult)
+{
+    struct clk *i;
+    qemu_irq *user;
+
+    clk->rate = muldiv64(rate, mult, div);
+    if (clk->running)
+        for (user = clk->users; *user; user ++)
+            qemu_irq_raise(*user);
+    for (i = clk->child1; i; i = i->sibling)
+        omap_clk_rate_update_full(i, rate,
+                        div * i->divisor, mult * i->multiplier);
+}
+
+static void omap_clk_rate_update(struct clk *clk)
+{
+    struct clk *i;
+    unsigned long int div, mult = div = 1;
+
+    for (i = clk; i->parent; i = i->parent) {
+        div *= i->divisor;
+        mult *= i->multiplier;
+    }
+
+    omap_clk_rate_update_full(clk, i->rate, div, mult);
+}
+
+void omap_clk_reparent(struct clk *clk, struct clk *parent)
+{
+    struct clk **p;
+
+    if (clk->parent) {
+        for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
+        *p = clk->sibling;
+    }
+
+    clk->parent = parent;
+    if (parent) {
+        clk->sibling = parent->child1;
+        parent->child1 = clk;
+        omap_clk_update(clk);
+        omap_clk_rate_update(clk);
+    } else
+        clk->sibling = NULL;
+}
+
+void omap_clk_onoff(struct clk *clk, int on)
+{
+    clk->enabled = on;
+    omap_clk_update(clk);
+}
+
+void omap_clk_canidle(struct clk *clk, int can)
+{
+    if (can)
+        omap_clk_put(clk);
+    else
+        omap_clk_get(clk);
+}
+
+void omap_clk_setrate(struct clk *clk, int divide, int multiply)
+{
+    clk->divisor = divide;
+    clk->multiplier = multiply;
+    omap_clk_rate_update(clk);
+}
+
+int64_t omap_clk_getrate(omap_clk clk)
+{
+    return clk->rate;
+}
+
+void omap_clk_init(struct omap_mpu_state_s *mpu)
+{
+    struct clk **i, *j, *k;
+    int count;
+    int flag;
+
+    if (cpu_is_omap310(mpu))
+        flag = CLOCK_IN_OMAP310;
+    else if (cpu_is_omap1510(mpu))
+        flag = CLOCK_IN_OMAP1510;
+    else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
+        flag = CLOCK_IN_OMAP242X;
+    else if (cpu_is_omap2430(mpu))
+        flag = CLOCK_IN_OMAP243X;
+    else if (cpu_is_omap3430(mpu))
+        flag = CLOCK_IN_OMAP243X;
+    else
+        return;
+
+    for (i = onchip_clks, count = 0; *i; i ++)
+        if ((*i)->flags & flag)
+            count ++;
+    mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1));
+    for (i = onchip_clks, j = mpu->clks; *i; i ++)
+        if ((*i)->flags & flag) {
+            memcpy(j, *i, sizeof(struct clk));
+            for (k = mpu->clks; k < j; k ++)
+                if (j->parent && !strcmp(j->parent->name, k->name)) {
+                    j->parent = k;
+                    j->sibling = k->child1;
+                    k->child1 = j;
+                } else if (k->parent && !strcmp(k->parent->name, j->name)) {
+                    k->parent = j;
+                    k->sibling = j->child1;
+                    j->child1 = k;
+                }
+            j->divisor = j->divisor ?: 1;
+            j->multiplier = j->multiplier ?: 1;
+            j ++;
+        }
+    for (j = mpu->clks; count --; j ++) {
+        omap_clk_update(j);
+        omap_clk_rate_update(j);
+    }
+}
diff --git a/qemu-0.15.x/hw/omap_dma.c b/qemu-0.15.x/hw/omap_dma.c
new file mode 100644
index 0000000..8e2dcc9
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_dma.c
@@ -0,0 +1,2082 @@
+/*
+ * TI OMAP DMA gigacell.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2007-2008 Lauro Ramos Venancio  <lauro.venancio at indt.org.br>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "omap.h"
+#include "irq.h"
+#include "soc_dma.h"
+
+struct omap_dma_channel_s {
+    /* transfer data */
+    int burst[2];
+    int pack[2];
+    int endian[2];
+    int endian_lock[2];
+    int translate[2];
+    enum omap_dma_port port[2];
+    target_phys_addr_t addr[2];
+    omap_dma_addressing_t mode[2];
+    uint32_t elements;
+    uint16_t frames;
+    int32_t frame_index[2];
+    int16_t element_index[2];
+    int data_type;
+
+    /* transfer type */
+    int transparent_copy;
+    int constant_fill;
+    uint32_t color;
+    int prefetch;
+
+    /* auto init and linked channel data */
+    int end_prog;
+    int repeat;
+    int auto_init;
+    int link_enabled;
+    int link_next_ch;
+
+    /* interruption data */
+    int interrupts;
+    int status;
+    int cstatus;
+
+    /* state data */
+    int active;
+    int enable;
+    int sync;
+    int src_sync;
+    int pending_request;
+    int waiting_end_prog;
+    uint16_t cpc;
+    int set_update;
+
+    /* sync type */
+    int fs;
+    int bs;
+
+    /* compatibility */
+    int omap_3_1_compatible_disable;
+
+    qemu_irq irq;
+    struct omap_dma_channel_s *sibling;
+
+    struct omap_dma_reg_set_s {
+        target_phys_addr_t src, dest;
+        int frame;
+        int element;
+        int pck_element;
+        int frame_delta[2];
+        int elem_delta[2];
+        int frames;
+        int elements;
+        int pck_elements;
+    } active_set;
+
+    struct soc_dma_ch_s *dma;
+
+    /* unused parameters */
+    int write_mode;
+    int priority;
+    int interleave_disabled;
+    int type;
+    int suspend;
+    int buf_disable;
+};
+
+struct omap_dma_s {
+    struct soc_dma_s *dma;
+
+    struct omap_mpu_state_s *mpu;
+    omap_clk clk;
+    qemu_irq irq[4];
+    void (*intr_update)(struct omap_dma_s *s);
+    enum omap_dma_model model;
+    int omap_3_1_mapping_disabled;
+
+    uint32_t gcr;
+    uint32_t ocp;
+    uint32_t caps[5];
+    uint32_t irqen[4];
+    uint32_t irqstat[4];
+
+    int chans;
+    struct omap_dma_channel_s ch[32];
+    struct omap_dma_lcd_channel_s lcd_ch;
+};
+
+/* Interrupts */
+#define TIMEOUT_INTR    (1 << 0)
+#define EVENT_DROP_INTR (1 << 1)
+#define HALF_FRAME_INTR (1 << 2)
+#define END_FRAME_INTR  (1 << 3)
+#define LAST_FRAME_INTR (1 << 4)
+#define END_BLOCK_INTR  (1 << 5)
+#define SYNC            (1 << 6)
+#define END_PKT_INTR	(1 << 7)
+#define TRANS_ERR_INTR	(1 << 8)
+#define MISALIGN_INTR	(1 << 11)
+
+static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
+{
+    return s->intr_update(s);
+}
+
+static void omap_dma_channel_load(struct omap_dma_channel_s *ch)
+{
+    struct omap_dma_reg_set_s *a = &ch->active_set;
+    int i, normal;
+    int omap_3_1 = !ch->omap_3_1_compatible_disable;
+
+    /*
+     * TODO: verify address ranges and alignment
+     * TODO: port endianness
+     */
+
+    a->src = ch->addr[0];
+    a->dest = ch->addr[1];
+    a->frames = ch->frames;
+    a->elements = ch->elements;
+    a->pck_elements = ch->frame_index[!ch->src_sync];
+    a->frame = 0;
+    a->element = 0;
+    a->pck_element = 0;
+
+    if (unlikely(!ch->elements || !ch->frames)) {
+        printf("%s: bad DMA request\n", __FUNCTION__);
+        return;
+    }
+
+    for (i = 0; i < 2; i ++)
+        switch (ch->mode[i]) {
+        case constant:
+            a->elem_delta[i] = 0;
+            a->frame_delta[i] = 0;
+            break;
+        case post_incremented:
+            a->elem_delta[i] = ch->data_type;
+            a->frame_delta[i] = 0;
+            break;
+        case single_index:
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
+            a->frame_delta[i] = 0;
+            break;
+        case double_index:
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
+            a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] -
+                    ch->element_index[omap_3_1 ? 0 : i];
+            break;
+        default:
+            break;
+        }
+
+    normal = !ch->transparent_copy && !ch->constant_fill &&
+            /* FIFO is big-endian so either (ch->endian[n] == 1) OR
+             * (ch->endian_lock[n] == 1) mean no endianism conversion.  */
+            (ch->endian[0] | ch->endian_lock[0]) ==
+            (ch->endian[1] | ch->endian_lock[1]);
+    for (i = 0; i < 2; i ++) {
+        /* TODO: for a->frame_delta[i] > 0 still use the fast path, just
+         * limit min_elems in omap_dma_transfer_setup to the nearest frame
+         * end.  */
+        if (!a->elem_delta[i] && normal &&
+                        (a->frames == 1 || !a->frame_delta[i]))
+            ch->dma->type[i] = soc_dma_access_const;
+        else if (a->elem_delta[i] == ch->data_type && normal &&
+                        (a->frames == 1 || !a->frame_delta[i]))
+            ch->dma->type[i] = soc_dma_access_linear;
+        else
+            ch->dma->type[i] = soc_dma_access_other;
+
+        ch->dma->vaddr[i] = ch->addr[i];
+    }
+    soc_dma_ch_update(ch->dma);
+}
+
+static void omap_dma_activate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (!ch->active) {
+        if (ch->set_update) {
+            /* It's not clear when the active set is supposed to be
+             * loaded from registers.  We're already loading it when the
+             * channel is enabled, and for some guests this is not enough
+             * but that may be also because of a race condition (no
+             * delays in qemu) in the guest code, which we're just
+             * working around here.  */
+            omap_dma_channel_load(ch);
+            ch->set_update = 0;
+        }
+
+        ch->active = 1;
+        soc_dma_set_request(ch->dma, 1);
+        if (ch->sync)
+            ch->status |= SYNC;
+    }
+}
+
+static void omap_dma_deactivate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    /* Update cpc */
+    ch->cpc = ch->active_set.dest & 0xffff;
+
+    if (ch->pending_request && !ch->waiting_end_prog && ch->enable) {
+        /* Don't deactivate the channel */
+        ch->pending_request = 0;
+        return;
+    }
+
+    /* Don't deactive the channel if it is synchronized and the DMA request is
+       active */
+    if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync)))
+        return;
+
+    if (ch->active) {
+        ch->active = 0;
+        ch->status &= ~SYNC;
+        soc_dma_set_request(ch->dma, 0);
+    }
+}
+
+static void omap_dma_enable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (!ch->enable) {
+        ch->enable = 1;
+        ch->waiting_end_prog = 0;
+        omap_dma_channel_load(ch);
+        /* TODO: theoretically if ch->sync && ch->prefetch &&
+         * !s->dma->drqbmp[ch->sync], we should also activate and fetch
+         * from source and then stall until signalled.  */
+        if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync)))
+            omap_dma_activate_channel(s, ch);
+    }
+}
+
+static void omap_dma_disable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->enable) {
+        ch->enable = 0;
+        /* Discard any pending request */
+        ch->pending_request = 0;
+        omap_dma_deactivate_channel(s, ch);
+    }
+}
+
+static void omap_dma_channel_end_prog(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->waiting_end_prog) {
+        ch->waiting_end_prog = 0;
+        if (!ch->sync || ch->pending_request) {
+            ch->pending_request = 0;
+            omap_dma_activate_channel(s, ch);
+        }
+    }
+}
+
+static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+
+    /* First three interrupts are shared between two channels each. */
+    if (ch[0].status | ch[6].status)
+        qemu_irq_raise(ch[0].irq);
+    if (ch[1].status | ch[7].status)
+        qemu_irq_raise(ch[1].irq);
+    if (ch[2].status | ch[8].status)
+        qemu_irq_raise(ch[2].irq);
+    if (ch[3].status)
+        qemu_irq_raise(ch[3].irq);
+    if (ch[4].status)
+        qemu_irq_raise(ch[4].irq);
+    if (ch[5].status)
+        qemu_irq_raise(ch[5].irq);
+}
+
+static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    int i;
+
+    for (i = s->chans; i; ch ++, i --)
+        if (ch->status)
+            qemu_irq_raise(ch->irq);
+}
+
+static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
+{
+    s->omap_3_1_mapping_disabled = 0;
+    s->chans = 9;
+    s->intr_update = omap_dma_interrupts_3_1_update;
+}
+
+static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
+{
+    s->omap_3_1_mapping_disabled = 1;
+    s->chans = 16;
+    s->intr_update = omap_dma_interrupts_3_2_update;
+}
+
+static void omap_dma_process_request(struct omap_dma_s *s, int request)
+{
+    int channel;
+    int drop_event = 0;
+    struct omap_dma_channel_s *ch = s->ch;
+
+    for (channel = 0; channel < s->chans; channel ++, ch ++) {
+        if (ch->enable && ch->sync == request) {
+            if (!ch->active)
+                omap_dma_activate_channel(s, ch);
+            else if (!ch->pending_request)
+                ch->pending_request = 1;
+            else {
+                /* Request collision */
+                /* Second request received while processing other request */
+                ch->status |= EVENT_DROP_INTR;
+                drop_event = 1;
+            }
+        }
+    }
+
+    if (drop_event)
+        omap_dma_interrupts_update(s);
+}
+
+static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
+{
+    uint8_t value[4];
+    struct omap_dma_channel_s *ch = dma->opaque;
+    struct omap_dma_reg_set_s *a = &ch->active_set;
+    int bytes = dma->bytes;
+#ifdef MULTI_REQ
+    uint16_t status = ch->status;
+#endif
+
+    do {
+        /* Transfer a single element */
+        /* FIXME: check the endianness */
+        if (!ch->constant_fill)
+            cpu_physical_memory_read(a->src, value, ch->data_type);
+        else
+            *(uint32_t *) value = ch->color;
+
+        if (!ch->transparent_copy || *(uint32_t *) value != ch->color)
+            cpu_physical_memory_write(a->dest, value, ch->data_type);
+
+        a->src += a->elem_delta[0];
+        a->dest += a->elem_delta[1];
+        a->element ++;
+
+#ifndef MULTI_REQ
+        if (a->element == a->elements) {
+            /* End of Frame */
+            a->element = 0;
+            a->src += a->frame_delta[0];
+            a->dest += a->frame_delta[1];
+            a->frame ++;
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync)
+                ch->cpc = a->dest & 0xffff;
+        }
+    } while ((bytes -= ch->data_type));
+#else
+        /* If the channel is element synchronized, deactivate it */
+        if (ch->sync && !ch->fs && !ch->bs)
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If it is the last frame, set the LAST_FRAME interrupt */
+        if (a->element == 1 && a->frame == a->frames - 1)
+            if (ch->interrupts & LAST_FRAME_INTR)
+                ch->status |= LAST_FRAME_INTR;
+
+        /* If the half of the frame was reached, set the HALF_FRAME
+           interrupt */
+        if (a->element == (a->elements >> 1))
+            if (ch->interrupts & HALF_FRAME_INTR)
+                ch->status |= HALF_FRAME_INTR;
+
+        if (ch->fs && ch->bs) {
+            a->pck_element ++;
+            /* Check if a full packet has beed transferred.  */
+            if (a->pck_element == a->pck_elements) {
+                a->pck_element = 0;
+
+                /* Set the END_PKT interrupt */
+                if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
+                    ch->status |= END_PKT_INTR;
+
+                /* If the channel is packet-synchronized, deactivate it */
+                if (ch->sync)
+                    omap_dma_deactivate_channel(s, ch);
+            }
+        }
+
+        if (a->element == a->elements) {
+            /* End of Frame */
+            a->element = 0;
+            a->src += a->frame_delta[0];
+            a->dest += a->frame_delta[1];
+            a->frame ++;
+
+            /* If the channel is frame synchronized, deactivate it */
+            if (ch->sync && ch->fs && !ch->bs)
+                omap_dma_deactivate_channel(s, ch);
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync)
+                ch->cpc = a->dest & 0xffff;
+
+            /* Set the END_FRAME interrupt */
+            if (ch->interrupts & END_FRAME_INTR)
+                ch->status |= END_FRAME_INTR;
+
+            if (a->frame == a->frames) {
+                /* End of Block */
+                /* Disable the channel */
+
+                if (ch->omap_3_1_compatible_disable) {
+                    omap_dma_disable_channel(s, ch);
+                    if (ch->link_enabled)
+                        omap_dma_enable_channel(s,
+                                        &s->ch[ch->link_next_ch]);
+                } else {
+                    if (!ch->auto_init)
+                        omap_dma_disable_channel(s, ch);
+                    else if (ch->repeat || ch->end_prog)
+                        omap_dma_channel_load(ch);
+                    else {
+                        ch->waiting_end_prog = 1;
+                        omap_dma_deactivate_channel(s, ch);
+                    }
+                }
+
+                if (ch->interrupts & END_BLOCK_INTR)
+                    ch->status |= END_BLOCK_INTR;
+            }
+        }
+    } while (status == ch->status && ch->active);
+
+    omap_dma_interrupts_update(s);
+#endif
+}
+
+enum {
+    omap_dma_intr_element_sync,
+    omap_dma_intr_last_frame,
+    omap_dma_intr_half_frame,
+    omap_dma_intr_frame,
+    omap_dma_intr_frame_sync,
+    omap_dma_intr_packet,
+    omap_dma_intr_packet_sync,
+    omap_dma_intr_block,
+    __omap_dma_intr_last,
+};
+
+static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
+{
+    struct omap_dma_port_if_s *src_p, *dest_p;
+    struct omap_dma_reg_set_s *a;
+    struct omap_dma_channel_s *ch = dma->opaque;
+    struct omap_dma_s *s = dma->dma->opaque;
+    int frames, min_elems, elements[__omap_dma_intr_last];
+
+    a = &ch->active_set;
+
+    src_p = &s->mpu->port[ch->port[0]];
+    dest_p = &s->mpu->port[ch->port[1]];
+    if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
+                    (!dest_p->addr_valid(s->mpu, a->dest))) {
+#if 0
+        /* Bus time-out */
+        if (ch->interrupts & TIMEOUT_INTR)
+            ch->status |= TIMEOUT_INTR;
+        omap_dma_deactivate_channel(s, ch);
+        continue;
+#endif
+        printf("%s: Bus time-out in DMA%i operation\n",
+                        __FUNCTION__, dma->num);
+    }
+
+    min_elems = INT_MAX;
+
+    /* Check all the conditions that terminate the transfer starting
+     * with those that can occur the soonest.  */
+#define INTR_CHECK(cond, id, nelements)	\
+    if (cond) {			\
+        elements[id] = nelements;	\
+        if (elements[id] < min_elems)	\
+            min_elems = elements[id];	\
+    } else				\
+        elements[id] = INT_MAX;
+
+    /* Elements */
+    INTR_CHECK(
+                    ch->sync && !ch->fs && !ch->bs,
+                    omap_dma_intr_element_sync,
+                    1)
+
+    /* Frames */
+    /* TODO: for transfers where entire frames can be read and written
+     * using memcpy() but a->frame_delta is non-zero, try to still do
+     * transfers using soc_dma but limit min_elems to a->elements - ...
+     * See also the TODO in omap_dma_channel_load.  */
+    INTR_CHECK(
+                    (ch->interrupts & LAST_FRAME_INTR) &&
+                    ((a->frame < a->frames - 1) || !a->element),
+                    omap_dma_intr_last_frame,
+                    (a->frames - a->frame - 2) * a->elements +
+                    (a->elements - a->element + 1))
+    INTR_CHECK(
+                    ch->interrupts & HALF_FRAME_INTR,
+                    omap_dma_intr_half_frame,
+                    (a->elements >> 1) +
+                    (a->element >= (a->elements >> 1) ? a->elements : 0) -
+                    a->element)
+    INTR_CHECK(
+                    ch->sync && ch->fs && (ch->interrupts & END_FRAME_INTR),
+                    omap_dma_intr_frame,
+                    a->elements - a->element)
+    INTR_CHECK(
+                    ch->sync && ch->fs && !ch->bs,
+                    omap_dma_intr_frame_sync,
+                    a->elements - a->element)
+
+    /* Packets */
+    INTR_CHECK(
+                    ch->fs && ch->bs &&
+                    (ch->interrupts & END_PKT_INTR) && !ch->src_sync,
+                    omap_dma_intr_packet,
+                    a->pck_elements - a->pck_element)
+    INTR_CHECK(
+                    ch->fs && ch->bs && ch->sync,
+                    omap_dma_intr_packet_sync,
+                    a->pck_elements - a->pck_element)
+
+    /* Blocks */
+    INTR_CHECK(
+                    1,
+                    omap_dma_intr_block,
+                    (a->frames - a->frame - 1) * a->elements +
+                    (a->elements - a->element))
+
+    dma->bytes = min_elems * ch->data_type;
+
+    /* Set appropriate interrupts and/or deactivate channels */
+
+#ifdef MULTI_REQ
+    /* TODO: should all of this only be done if dma->update, and otherwise
+     * inside omap_dma_transfer_generic below - check what's faster.  */
+    if (dma->update) {
+#endif
+
+        /* If the channel is element synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_element_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If it is the last frame, set the LAST_FRAME interrupt */
+        if (min_elems == elements[omap_dma_intr_last_frame])
+            ch->status |= LAST_FRAME_INTR;
+
+        /* If exactly half of the frame was reached, set the HALF_FRAME
+           interrupt */
+        if (min_elems == elements[omap_dma_intr_half_frame])
+            ch->status |= HALF_FRAME_INTR;
+
+        /* If a full packet has been transferred, set the END_PKT interrupt */
+        if (min_elems == elements[omap_dma_intr_packet])
+            ch->status |= END_PKT_INTR;
+
+        /* If the channel is packet-synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_packet_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If the channel is frame synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_frame_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* Set the END_FRAME interrupt */
+        if (min_elems == elements[omap_dma_intr_frame])
+            ch->status |= END_FRAME_INTR;
+
+        if (min_elems == elements[omap_dma_intr_block]) {
+            /* End of Block */
+            /* Disable the channel */
+
+            if (ch->omap_3_1_compatible_disable) {
+                omap_dma_disable_channel(s, ch);
+                if (ch->link_enabled)
+                    omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]);
+            } else {
+                if (!ch->auto_init)
+                    omap_dma_disable_channel(s, ch);
+                else if (ch->repeat || ch->end_prog)
+                    omap_dma_channel_load(ch);
+                else {
+                    ch->waiting_end_prog = 1;
+                    omap_dma_deactivate_channel(s, ch);
+                }
+            }
+
+            if (ch->interrupts & END_BLOCK_INTR)
+                ch->status |= END_BLOCK_INTR;
+        }
+
+        /* Update packet number */
+        if (ch->fs && ch->bs) {
+            a->pck_element += min_elems;
+            a->pck_element %= a->pck_elements;
+        }
+
+        /* TODO: check if we really need to update anything here or perhaps we
+         * can skip part of this.  */
+#ifndef MULTI_REQ
+        if (dma->update) {
+#endif
+            a->element += min_elems;
+
+            frames = a->element / a->elements;
+            a->element = a->element % a->elements;
+            a->frame += frames;
+            a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
+            a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync && frames)
+                ch->cpc = a->dest & 0xffff;
+
+            /* TODO: if the destination port is IMIF or EMIFF, set the dirty
+             * bits on it.  */
+#ifndef MULTI_REQ
+        }
+#else
+    }
+#endif
+
+    omap_dma_interrupts_update(s);
+}
+
+void omap_dma_reset(struct soc_dma_s *dma)
+{
+    int i;
+    struct omap_dma_s *s = dma->opaque;
+
+    soc_dma_reset(s->dma);
+    if (s->model < omap_dma_4)
+        s->gcr = 0x0004;
+    else
+        s->gcr = 0x00010010;
+    s->ocp = 0x00000000;
+    memset(&s->irqstat, 0, sizeof(s->irqstat));
+    memset(&s->irqen, 0, sizeof(s->irqen));
+    s->lcd_ch.src = emiff;
+    s->lcd_ch.condition = 0;
+    s->lcd_ch.interrupts = 0;
+    s->lcd_ch.dual = 0;
+    if (s->model < omap_dma_4)
+        omap_dma_enable_3_1_mapping(s);
+    for (i = 0; i < s->chans; i ++) {
+        s->ch[i].suspend = 0;
+        s->ch[i].prefetch = 0;
+        s->ch[i].buf_disable = 0;
+        s->ch[i].src_sync = 0;
+        memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
+        memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
+        memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
+        memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
+        memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
+        memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian));
+        memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock));
+        memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate));
+        s->ch[i].write_mode = 0;
+        s->ch[i].data_type = 0;
+        s->ch[i].transparent_copy = 0;
+        s->ch[i].constant_fill = 0;
+        s->ch[i].color = 0x00000000;
+        s->ch[i].end_prog = 0;
+        s->ch[i].repeat = 0;
+        s->ch[i].auto_init = 0;
+        s->ch[i].link_enabled = 0;
+        if (s->model < omap_dma_4)
+            s->ch[i].interrupts = 0x0003;
+        else
+            s->ch[i].interrupts = 0x0000;
+        s->ch[i].status = 0;
+        s->ch[i].cstatus = 0;
+        s->ch[i].active = 0;
+        s->ch[i].enable = 0;
+        s->ch[i].sync = 0;
+        s->ch[i].pending_request = 0;
+        s->ch[i].waiting_end_prog = 0;
+        s->ch[i].cpc = 0x0000;
+        s->ch[i].fs = 0;
+        s->ch[i].bs = 0;
+        s->ch[i].omap_3_1_compatible_disable = 0;
+        memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
+        s->ch[i].priority = 0;
+        s->ch[i].interleave_disabled = 0;
+        s->ch[i].type = 0;
+    }
+}
+
+static int omap_dma_ch_reg_read(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch, int reg, uint16_t *value)
+{
+    switch (reg) {
+    case 0x00:	/* SYS_DMA_CSDP_CH0 */
+        *value = (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->port[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->port[0] << 2) |
+                (ch->data_type >> 1);
+        break;
+
+    case 0x02:	/* SYS_DMA_CCR_CH0 */
+        if (s->model <= omap_dma_3_1)
+            *value = 0 << 10;			/* FIFO_FLUSH reads as 0 */
+        else
+            *value = ch->omap_3_1_compatible_disable << 10;
+        *value |= (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (ch->end_prog << 11) |
+                (ch->repeat << 9) |
+                (ch->auto_init << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | ch->sync;
+        break;
+
+    case 0x04:	/* SYS_DMA_CICR_CH0 */
+        *value = ch->interrupts;
+        break;
+
+    case 0x06:	/* SYS_DMA_CSR_CH0 */
+        *value = ch->status;
+        ch->status &= SYNC;
+        if (!ch->omap_3_1_compatible_disable && ch->sibling) {
+            *value |= (ch->sibling->status & 0x3f) << 6;
+            ch->sibling->status &= SYNC;
+        }
+        qemu_irq_lower(ch->irq);
+        break;
+
+    case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
+        *value = ch->addr[0] & 0x0000ffff;
+        break;
+
+    case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
+        *value = ch->addr[0] >> 16;
+        break;
+
+    case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
+        *value = ch->addr[1] & 0x0000ffff;
+        break;
+
+    case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
+        *value = ch->addr[1] >> 16;
+        break;
+
+    case 0x10:	/* SYS_DMA_CEN_CH0 */
+        *value = ch->elements;
+        break;
+
+    case 0x12:	/* SYS_DMA_CFN_CH0 */
+        *value = ch->frames;
+        break;
+
+    case 0x14:	/* SYS_DMA_CFI_CH0 */
+        *value = ch->frame_index[0];
+        break;
+
+    case 0x16:	/* SYS_DMA_CEI_CH0 */
+        *value = ch->element_index[0];
+        break;
+
+    case 0x18:	/* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        if (ch->omap_3_1_compatible_disable)
+            *value = ch->active_set.src & 0xffff;	/* CSAC */
+        else
+            *value = ch->cpc;
+        break;
+
+    case 0x1a:	/* DMA_CDAC */
+        *value = ch->active_set.dest & 0xffff;	/* CDAC */
+        break;
+
+    case 0x1c:	/* DMA_CDEI */
+        *value = ch->element_index[1];
+        break;
+
+    case 0x1e:	/* DMA_CDFI */
+        *value = ch->frame_index[1];
+        break;
+
+    case 0x20:	/* DMA_COLOR_L */
+        *value = ch->color & 0xffff;
+        break;
+
+    case 0x22:	/* DMA_COLOR_U */
+        *value = ch->color >> 16;
+        break;
+
+    case 0x24:	/* DMA_CCR2 */
+        *value = (ch->bs << 2) |
+                (ch->transparent_copy << 1) |
+                ch->constant_fill;
+        break;
+
+    case 0x28:	/* DMA_CLNK_CTRL */
+        *value = (ch->link_enabled << 15) |
+                (ch->link_next_ch & 0xf);
+        break;
+
+    case 0x2a:	/* DMA_LCH_CTRL */
+        *value = (ch->interleave_disabled << 15) |
+                ch->type;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_ch_reg_write(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00:	/* SYS_DMA_CSDP_CH0 */
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
+        ch->data_type = 1 << (value & 3);
+        if (ch->port[0] >= __omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            ch->port[0]);
+        if (ch->port[1] >= __omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            ch->port[1]);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
+        break;
+
+    case 0x02:	/* SYS_DMA_CCR_CH0 */
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->end_prog = (value & 0x0800) >> 11;
+        if (s->model >= omap_dma_3_2)
+            ch->omap_3_1_compatible_disable  = (value >> 10) & 0x1;
+        ch->repeat = (value & 0x0200) >> 9;
+        ch->auto_init = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        ch->sync = value & 0x001f;
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        if (ch->end_prog)
+            omap_dma_channel_end_prog(s, ch);
+
+        break;
+
+    case 0x04:	/* SYS_DMA_CICR_CH0 */
+        ch->interrupts = value & 0x3f;
+        break;
+
+    case 0x06:	/* SYS_DMA_CSR_CH0 */
+        OMAP_RO_REG((target_phys_addr_t) reg);
+        break;
+
+    case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
+        ch->addr[0] &= 0xffff0000;
+        ch->addr[0] |= value;
+        break;
+
+    case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
+        ch->addr[0] &= 0x0000ffff;
+        ch->addr[0] |= (uint32_t) value << 16;
+        break;
+
+    case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
+        ch->addr[1] &= 0xffff0000;
+        ch->addr[1] |= value;
+        break;
+
+    case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
+        ch->addr[1] &= 0x0000ffff;
+        ch->addr[1] |= (uint32_t) value << 16;
+        break;
+
+    case 0x10:	/* SYS_DMA_CEN_CH0 */
+        ch->elements = value;
+        break;
+
+    case 0x12:	/* SYS_DMA_CFN_CH0 */
+        ch->frames = value;
+        break;
+
+    case 0x14:	/* SYS_DMA_CFI_CH0 */
+        ch->frame_index[0] = (int16_t) value;
+        break;
+
+    case 0x16:	/* SYS_DMA_CEI_CH0 */
+        ch->element_index[0] = (int16_t) value;
+        break;
+
+    case 0x18:	/* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        OMAP_RO_REG((target_phys_addr_t) reg);
+        break;
+
+    case 0x1c:	/* DMA_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        break;
+
+    case 0x1e:	/* DMA_CDFI */
+        ch->frame_index[1] = (int16_t) value;
+        break;
+
+    case 0x20:	/* DMA_COLOR_L */
+        ch->color &= 0xffff0000;
+        ch->color |= value;
+        break;
+
+    case 0x22:	/* DMA_COLOR_U */
+        ch->color &= 0xffff;
+        ch->color |= value << 16;
+        break;
+
+    case 0x24:	/* DMA_CCR2 */
+        ch->bs = (value >> 2) & 0x1;
+        ch->transparent_copy = (value >> 1) & 0x1;
+        ch->constant_fill = value & 0x1;
+        break;
+
+    case 0x28:	/* DMA_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        if (value & (1 << 14)) {			/* Stop_Lnk */
+            ch->link_enabled = 0;
+            omap_dma_disable_channel(s, ch);
+        }
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x2a:	/* DMA_LCH_CTRL */
+        ch->interleave_disabled = (value >> 15) & 0x1;
+        ch->type = value & 0xf;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
+    switch (offset) {
+    case 0xbc0:	/* DMA_LCD_CSDP */
+        s->brust_f2 = (value >> 14) & 0x3;
+        s->pack_f2 = (value >> 13) & 0x1;
+        s->data_type_f2 = (1 << ((value >> 11) & 0x3));
+        s->brust_f1 = (value >> 7) & 0x3;
+        s->pack_f1 = (value >> 6) & 0x1;
+        s->data_type_f1 = (1 << ((value >> 0) & 0x3));
+        break;
+
+    case 0xbc2:	/* DMA_LCD_CCR */
+        s->mode_f2 = (value >> 14) & 0x3;
+        s->mode_f1 = (value >> 12) & 0x3;
+        s->end_prog = (value >> 11) & 0x1;
+        s->omap_3_1_compatible_disable = (value >> 10) & 0x1;
+        s->repeat = (value >> 9) & 0x1;
+        s->auto_init = (value >> 8) & 0x1;
+        s->running = (value >> 7) & 0x1;
+        s->priority = (value >> 6) & 0x1;
+        s->bs = (value >> 4) & 0x1;
+        break;
+
+    case 0xbc4:	/* DMA_LCD_CTRL */
+        s->dst = (value >> 8) & 0x1;
+        s->src = ((value >> 6) & 0x3) << 1;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
+
+    case 0xbc8:	/* TOP_B1_L */
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbca:	/* TOP_B1_U */
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
+
+    case 0xbcc:	/* BOT_B1_L */
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbce:	/* BOT_B1_U */
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd0:	/* TOP_B2_L */
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbd2:	/* TOP_B2_U */
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd4:	/* BOT_B2_L */
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbd6:	/* BOT_B2_U */
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd8:	/* DMA_LCD_SRC_EI_B1 */
+        s->element_index_f1 = value;
+        break;
+
+    case 0xbda:	/* DMA_LCD_SRC_FI_B1_L */
+        s->frame_index_f1 &= 0xffff0000;
+        s->frame_index_f1 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf4:	/* DMA_LCD_SRC_FI_B1_U */
+        s->frame_index_f1 &= 0x0000ffff;
+        s->frame_index_f1 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbdc:	/* DMA_LCD_SRC_EI_B2 */
+        s->element_index_f2 = value;
+        break;
+
+    case 0xbde:	/* DMA_LCD_SRC_FI_B2_L */
+        s->frame_index_f2 &= 0xffff0000;
+        s->frame_index_f2 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf6:	/* DMA_LCD_SRC_FI_B2_U */
+        s->frame_index_f2 &= 0x0000ffff;
+        s->frame_index_f2 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbe0:	/* DMA_LCD_SRC_EN_B1 */
+        s->elements_f1 = value;
+        break;
+
+    case 0xbe4:	/* DMA_LCD_SRC_FN_B1 */
+        s->frames_f1 = value;
+        break;
+
+    case 0xbe2:	/* DMA_LCD_SRC_EN_B2 */
+        s->elements_f2 = value;
+        break;
+
+    case 0xbe6:	/* DMA_LCD_SRC_FN_B2 */
+        s->frames_f2 = value;
+        break;
+
+    case 0xbea:	/* DMA_LCD_LCH_CTRL */
+        s->lch_type = value & 0xf;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
+{
+    switch (offset) {
+    case 0xbc0:	/* DMA_LCD_CSDP */
+        *ret = (s->brust_f2 << 14) |
+            (s->pack_f2 << 13) |
+            ((s->data_type_f2 >> 1) << 11) |
+            (s->brust_f1 << 7) |
+            (s->pack_f1 << 6) |
+            ((s->data_type_f1 >> 1) << 0);
+        break;
+
+    case 0xbc2:	/* DMA_LCD_CCR */
+        *ret = (s->mode_f2 << 14) |
+            (s->mode_f1 << 12) |
+            (s->end_prog << 11) |
+            (s->omap_3_1_compatible_disable << 10) |
+            (s->repeat << 9) |
+            (s->auto_init << 8) |
+            (s->running << 7) |
+            (s->priority << 6) |
+            (s->bs << 4);
+        break;
+
+    case 0xbc4:	/* DMA_LCD_CTRL */
+        qemu_irq_lower(s->irq);
+        *ret = (s->dst << 8) |
+            ((s->src & 0x6) << 5) |
+            (s->condition << 3) |
+            (s->interrupts << 1) |
+            s->dual;
+        break;
+
+    case 0xbc8:	/* TOP_B1_L */
+        *ret = s->src_f1_top & 0xffff;
+        break;
+
+    case 0xbca:	/* TOP_B1_U */
+        *ret = s->src_f1_top >> 16;
+        break;
+
+    case 0xbcc:	/* BOT_B1_L */
+        *ret = s->src_f1_bottom & 0xffff;
+        break;
+
+    case 0xbce:	/* BOT_B1_U */
+        *ret = s->src_f1_bottom >> 16;
+        break;
+
+    case 0xbd0:	/* TOP_B2_L */
+        *ret = s->src_f2_top & 0xffff;
+        break;
+
+    case 0xbd2:	/* TOP_B2_U */
+        *ret = s->src_f2_top >> 16;
+        break;
+
+    case 0xbd4:	/* BOT_B2_L */
+        *ret = s->src_f2_bottom & 0xffff;
+        break;
+
+    case 0xbd6:	/* BOT_B2_U */
+        *ret = s->src_f2_bottom >> 16;
+        break;
+
+    case 0xbd8:	/* DMA_LCD_SRC_EI_B1 */
+        *ret = s->element_index_f1;
+        break;
+
+    case 0xbda:	/* DMA_LCD_SRC_FI_B1_L */
+        *ret = s->frame_index_f1 & 0xffff;
+        break;
+
+    case 0xbf4:	/* DMA_LCD_SRC_FI_B1_U */
+        *ret = s->frame_index_f1 >> 16;
+        break;
+
+    case 0xbdc:	/* DMA_LCD_SRC_EI_B2 */
+        *ret = s->element_index_f2;
+        break;
+
+    case 0xbde:	/* DMA_LCD_SRC_FI_B2_L */
+        *ret = s->frame_index_f2 & 0xffff;
+        break;
+
+    case 0xbf6:	/* DMA_LCD_SRC_FI_B2_U */
+        *ret = s->frame_index_f2 >> 16;
+        break;
+
+    case 0xbe0:	/* DMA_LCD_SRC_EN_B1 */
+        *ret = s->elements_f1;
+        break;
+
+    case 0xbe4:	/* DMA_LCD_SRC_FN_B1 */
+        *ret = s->frames_f1;
+        break;
+
+    case 0xbe2:	/* DMA_LCD_SRC_EN_B2 */
+        *ret = s->elements_f2;
+        break;
+
+    case 0xbe6:	/* DMA_LCD_SRC_FN_B2 */
+        *ret = s->frames_f2;
+        break;
+
+    case 0xbea:	/* DMA_LCD_LCH_CTRL */
+        *ret = s->lch_type;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
+    switch (offset) {
+    case 0x300:	/* SYS_DMA_LCD_CTRL */
+        s->src = (value & 0x40) ? imif : emiff;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
+
+    case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
+
+    case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= value << 16;
+        break;
+
+    case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= value << 16;
+        break;
+
+    case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= value << 16;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
+{
+    int i;
+
+    switch (offset) {
+    case 0x300:	/* SYS_DMA_LCD_CTRL */
+        i = s->condition;
+        s->condition = 0;
+        qemu_irq_lower(s->irq);
+        *ret = ((s->src == imif) << 6) | (i << 3) |
+                (s->interrupts << 1) | s->dual;
+        break;
+
+    case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
+        *ret = s->src_f1_top & 0xffff;
+        break;
+
+    case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
+        *ret = s->src_f1_top >> 16;
+        break;
+
+    case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
+        *ret = s->src_f1_bottom & 0xffff;
+        break;
+
+    case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
+        *ret = s->src_f1_bottom >> 16;
+        break;
+
+    case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
+        *ret = s->src_f2_top & 0xffff;
+        break;
+
+    case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
+        *ret = s->src_f2_top >> 16;
+        break;
+
+    case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
+        *ret = s->src_f2_bottom & 0xffff;
+        break;
+
+    case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
+        *ret = s->src_f2_bottom >> 16;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
+{
+    switch (offset) {
+    case 0x400:	/* SYS_DMA_GCR */
+        s->gcr = value;
+        break;
+
+    case 0x404:	/* DMA_GSCR */
+        if (value & 0x8)
+            omap_dma_disable_3_1_mapping(s);
+        else
+            omap_dma_enable_3_1_mapping(s);
+        break;
+
+    case 0x408:	/* DMA_GRST */
+        if (value & 0x1)
+            omap_dma_reset(s->dma);
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
+                uint16_t *ret)
+{
+    switch (offset) {
+    case 0x400:	/* SYS_DMA_GCR */
+        *ret = s->gcr;
+        break;
+
+    case 0x404:	/* DMA_GSCR */
+        *ret = s->omap_3_1_mapping_disabled << 3;
+        break;
+
+    case 0x408:	/* DMA_GRST */
+        *ret = 0;
+        break;
+
+    case 0x442:	/* DMA_HW_ID */
+    case 0x444:	/* DMA_PCh2_ID */
+    case 0x446:	/* DMA_PCh0_ID */
+    case 0x448:	/* DMA_PCh1_ID */
+    case 0x44a:	/* DMA_PChG_ID */
+    case 0x44c:	/* DMA_PChD_ID */
+        *ret = 1;
+        break;
+
+    case 0x44e:	/* DMA_CAPS_0_U */
+        *ret = (s->caps[0] >> 16) & 0xffff;
+        break;
+    case 0x450:	/* DMA_CAPS_0_L */
+        *ret = (s->caps[0] >>  0) & 0xffff;
+        break;
+
+    case 0x452:	/* DMA_CAPS_1_U */
+        *ret = (s->caps[1] >> 16) & 0xffff;
+        break;
+    case 0x454:	/* DMA_CAPS_1_L */
+        *ret = (s->caps[1] >>  0) & 0xffff;
+        break;
+
+    case 0x456:	/* DMA_CAPS_2 */
+        *ret = s->caps[2];
+        break;
+
+    case 0x458:	/* DMA_CAPS_3 */
+        *ret = s->caps[3];
+        break;
+
+    case 0x45a:	/* DMA_CAPS_4 */
+        *ret = s->caps[4];
+        break;
+
+    case 0x460:	/* DMA_PCh2_SR */
+    case 0x480:	/* DMA_PCh0_SR */
+    case 0x482:	/* DMA_PCh1_SR */
+    case 0x4c0:	/* DMA_PChD_SR_0 */
+        printf("%s: Physical Channel Status Registers not implemented.\n",
+               __FUNCTION__);
+        *ret = 0xff;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch;
+    uint16_t ret;
+
+    switch (addr) {
+    case 0x300 ... 0x3fe:
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_read(&s->lcd_ch, addr, &ret))
+                break;
+            return ret;
+        }
+        /* Fall through. */
+    case 0x000 ... 0x2fe:
+        reg = addr & 0x3f;
+        ch = (addr >> 6) & 0x0f;
+        if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret))
+            break;
+        return ret;
+
+    case 0x404 ... 0x4fe:
+        if (s->model <= omap_dma_3_1)
+            break;
+        /* Fall through. */
+    case 0x400:
+        if (omap_dma_sys_read(s, addr, &ret))
+            break;
+        return ret;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_read(&s->lcd_ch, addr, &ret))
+                break;
+            return ret;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dma_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch;
+
+    switch (addr) {
+    case 0x300 ... 0x3fe:
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_write(&s->lcd_ch, addr, value))
+                break;
+            return;
+        }
+        /* Fall through.  */
+    case 0x000 ... 0x2fe:
+        reg = addr & 0x3f;
+        ch = (addr >> 6) & 0x0f;
+        if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value))
+            break;
+        return;
+
+    case 0x404 ... 0x4fe:
+        if (s->model <= omap_dma_3_1)
+            break;
+    case 0x400:
+        /* Fall through. */
+        if (omap_dma_sys_write(s, addr, value))
+            break;
+        return;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_write(&s->lcd_ch, addr, value))
+                break;
+            return;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc * const omap_dma_readfn[] = {
+    omap_badwidth_read16,
+    omap_dma_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_dma_writefn[] = {
+    omap_badwidth_write16,
+    omap_dma_write,
+    omap_badwidth_write16,
+};
+
+static void omap_dma_request(void *opaque, int drq, int req)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    /* The request pins are level triggered in QEMU.  */
+    if (req) {
+        if (~s->dma->drqbmp & (1 << drq)) {
+            s->dma->drqbmp |= 1 << drq;
+            omap_dma_process_request(s, drq);
+        }
+    } else
+        s->dma->drqbmp &= ~(1 << drq);
+}
+
+/* XXX: this won't be needed once soc_dma knows about clocks.  */
+static void omap_dma_clk_update(void *opaque, int line, int on)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int i;
+
+    s->dma->freq = omap_clk_getrate(s->clk);
+
+    for (i = 0; i < s->chans; i ++)
+        if (s->ch[i].active)
+            soc_dma_set_request(s->ch[i].dma, on);
+}
+
+static void omap_dma_setcaps(struct omap_dma_s *s)
+{
+    switch (s->model) {
+    default:
+    case omap_dma_3_1:
+        break;
+    case omap_dma_3_2:
+    case omap_dma_4:
+        /* XXX Only available for sDMA */
+        s->caps[0] =
+                (1 << 19) |	/* Constant Fill Capability */
+                (1 << 18);	/* Transparent BLT Capability */
+        s->caps[1] =
+                (1 << 1);	/* 1-bit palettized capability (DMA 3.2 only) */
+        s->caps[2] =
+                (1 << 8) |	/* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
+                (1 << 7) |	/* DST_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 6) |	/* DST_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 5) |	/* DST_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 4) |	/* DST_CONST_ADRS_CPBLTY */
+                (1 << 3) |	/* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 2) |	/* SRC_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 1) |	/* SRC_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 0);	/* SRC_CONST_ADRS_CPBLTY */
+        s->caps[3] =
+                (1 << 6) |	/* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 7) |	/* PKT_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 5) |	/* CHANNEL_CHAINING_CPBLTY */
+                (1 << 4) |	/* LCh_INTERLEAVE_CPBLTY */
+                (1 << 3) |	/* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
+                (1 << 2) |	/* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
+                (1 << 1) |	/* FRAME_SYNCHR_CPBLTY */
+                (1 << 0);	/* ELMNT_SYNCHR_CPBLTY */
+        s->caps[4] =
+                (1 << 7) |	/* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
+                (1 << 6) |	/* SYNC_STATUS_CPBLTY */
+                (1 << 5) |	/* BLOCK_INTERRUPT_CPBLTY */
+                (1 << 4) |	/* LAST_FRAME_INTERRUPT_CPBLTY */
+                (1 << 3) |	/* FRAME_INTERRUPT_CPBLTY */
+                (1 << 2) |	/* HALF_FRAME_INTERRUPT_CPBLTY */
+                (1 << 1) |	/* EVENT_DROP_INTERRUPT_CPBLTY */
+                (1 << 0);	/* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
+        break;
+    }
+}
+
+struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model)
+{
+    int iomemtype, num_irqs, memsize, i;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            qemu_mallocz(sizeof(struct omap_dma_s));
+
+    if (model <= omap_dma_3_1) {
+        num_irqs = 6;
+        memsize = 0x800;
+    } else {
+        num_irqs = 16;
+        memsize = 0xc00;
+    }
+    s->model = model;
+    s->mpu = mpu;
+    s->clk = clk;
+    s->lcd_ch.irq = lcd_irq;
+    s->lcd_ch.mpu = mpu;
+
+    s->dma = soc_dma_init((model <= omap_dma_3_1) ? 9 : 16);
+    s->dma->freq = omap_clk_getrate(clk);
+    s->dma->transfer_fn = omap_dma_transfer_generic;
+    s->dma->setup_fn = omap_dma_transfer_setup;
+    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
+    s->dma->opaque = s;
+
+    while (num_irqs --)
+        s->ch[num_irqs].irq = irqs[num_irqs];
+    for (i = 0; i < 3; i ++) {
+        s->ch[i].sibling = &s->ch[i + 6];
+        s->ch[i + 6].sibling = &s->ch[i];
+    }
+    for (i = (model <= omap_dma_3_1) ? 8 : 15; i >= 0; i --) {
+        s->ch[i].dma = &s->dma->ch[i];
+        s->dma->ch[i].opaque = &s->ch[i];
+    }
+
+    omap_dma_setcaps(s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    omap_dma_reset(s->dma);
+    omap_dma_clk_update(s, 0, 1);
+
+    iomemtype = cpu_register_io_memory(omap_dma_readfn,
+                    omap_dma_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, memsize, iomemtype);
+
+    mpu->drq = s->dma->drq;
+
+    return s->dma;
+}
+
+static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    uint32_t bmp, bit;
+
+    for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
+        if (ch->status) {
+            bmp |= bit;
+            ch->cstatus |= ch->status;
+            ch->status = 0;
+        }
+    if ((s->irqstat[0] |= s->irqen[0] & bmp))
+        qemu_irq_raise(s->irq[0]);
+    if ((s->irqstat[1] |= s->irqen[1] & bmp))
+        qemu_irq_raise(s->irq[1]);
+    if ((s->irqstat[2] |= s->irqen[2] & bmp))
+        qemu_irq_raise(s->irq[2]);
+    if ((s->irqstat[3] |= s->irqen[3] & bmp))
+        qemu_irq_raise(s->irq[3]);
+}
+
+static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int irqn = 0, chnum;
+    struct omap_dma_channel_s *ch;
+
+    switch (addr) {
+    case 0x00:	/* DMA4_REVISION */
+        return 0x40;
+
+    case 0x14:	/* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+    case 0x10:	/* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+    case 0x0c:	/* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+    case 0x08:	/* DMA4_IRQSTATUS_L0 */
+        return s->irqstat[irqn];
+
+    case 0x24:	/* DMA4_IRQENABLE_L3 */
+        irqn ++;
+    case 0x20:	/* DMA4_IRQENABLE_L2 */
+        irqn ++;
+    case 0x1c:	/* DMA4_IRQENABLE_L1 */
+        irqn ++;
+    case 0x18:	/* DMA4_IRQENABLE_L0 */
+        return s->irqen[irqn];
+
+    case 0x28:	/* DMA4_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x2c:	/* DMA4_OCP_SYSCONFIG */
+        return s->ocp;
+
+    case 0x64:	/* DMA4_CAPS_0 */
+        return s->caps[0];
+    case 0x6c:	/* DMA4_CAPS_2 */
+        return s->caps[2];
+    case 0x70:	/* DMA4_CAPS_3 */
+        return s->caps[3];
+    case 0x74:	/* DMA4_CAPS_4 */
+        return s->caps[4];
+
+    case 0x78:	/* DMA4_GCR */
+        return s->gcr;
+
+    case 0x80 ... 0xfff:
+        addr -= 0x80;
+        chnum = addr / 0x60;
+        ch = s->ch + chnum;
+        addr -= chnum * 0x60;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+
+    /* Per-channel registers */
+    switch (addr) {
+    case 0x00:	/* DMA4_CCR */
+        return (ch->buf_disable << 25) |
+                (ch->src_sync << 24) |
+                (ch->prefetch << 23) |
+                ((ch->sync & 0x60) << 14) |
+                (ch->bs << 18) |
+                (ch->transparent_copy << 17) |
+                (ch->constant_fill << 16) |
+                (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (0 << 10) | (0 << 9) |
+                (ch->suspend << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | (ch->sync & 0x1f);
+
+    case 0x04:	/* DMA4_CLNK_CTRL */
+        return (ch->link_enabled << 15) | ch->link_next_ch;
+
+    case 0x08:	/* DMA4_CICR */
+        return ch->interrupts;
+
+    case 0x0c:	/* DMA4_CSR */
+        return ch->cstatus;
+
+    case 0x10:	/* DMA4_CSDP */
+        return (ch->endian[0] << 21) |
+                (ch->endian_lock[0] << 20) |
+                (ch->endian[1] << 19) |
+                (ch->endian_lock[1] << 18) |
+                (ch->write_mode << 16) |
+                (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->translate[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->translate[0] << 2) |
+                (ch->data_type >> 1);
+
+    case 0x14:	/* DMA4_CEN */
+        return ch->elements;
+
+    case 0x18:	/* DMA4_CFN */
+        return ch->frames;
+
+    case 0x1c:	/* DMA4_CSSA */
+        return ch->addr[0];
+
+    case 0x20:	/* DMA4_CDSA */
+        return ch->addr[1];
+
+    case 0x24:	/* DMA4_CSEI */
+        return ch->element_index[0];
+
+    case 0x28:	/* DMA4_CSFI */
+        return ch->frame_index[0];
+
+    case 0x2c:	/* DMA4_CDEI */
+        return ch->element_index[1];
+
+    case 0x30:	/* DMA4_CDFI */
+        return ch->frame_index[1];
+
+    case 0x34:	/* DMA4_CSAC */
+        return ch->active_set.src & 0xffff;
+
+    case 0x38:	/* DMA4_CDAC */
+        return ch->active_set.dest & 0xffff;
+
+    case 0x3c:	/* DMA4_CCEN */
+        return ch->active_set.element;
+
+    case 0x40:	/* DMA4_CCFN */
+        return ch->active_set.frame;
+
+    case 0x44:	/* DMA4_COLOR */
+        /* XXX only in sDMA */
+        return ch->color;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+}
+
+static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int chnum, irqn = 0;
+    struct omap_dma_channel_s *ch;
+
+    switch (addr) {
+    case 0x14:	/* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+    case 0x10:	/* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+    case 0x0c:	/* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+    case 0x08:	/* DMA4_IRQSTATUS_L0 */
+        s->irqstat[irqn] &= ~value;
+        if (!s->irqstat[irqn])
+            qemu_irq_lower(s->irq[irqn]);
+        return;
+
+    case 0x24:	/* DMA4_IRQENABLE_L3 */
+        irqn ++;
+    case 0x20:	/* DMA4_IRQENABLE_L2 */
+        irqn ++;
+    case 0x1c:	/* DMA4_IRQENABLE_L1 */
+        irqn ++;
+    case 0x18:	/* DMA4_IRQENABLE_L0 */
+        s->irqen[irqn] = value;
+        return;
+
+    case 0x2c:	/* DMA4_OCP_SYSCONFIG */
+        if (value & 2)						/* SOFTRESET */
+            omap_dma_reset(s->dma);
+        s->ocp = value & 0x3321;
+        if (((s->ocp >> 12) & 3) == 3)				/* MIDLEMODE */
+            fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
+        return;
+
+    case 0x78:	/* DMA4_GCR */
+        s->gcr = value & 0x00ff00ff;
+	if ((value & 0xff) == 0x00)		/* MAX_CHANNEL_FIFO_DEPTH */
+            fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__);
+        return;
+
+    case 0x80 ... 0xfff:
+        addr -= 0x80;
+        chnum = addr / 0x60;
+        ch = s->ch + chnum;
+        addr -= chnum * 0x60;
+        break;
+
+    case 0x00:	/* DMA4_REVISION */
+    case 0x28:	/* DMA4_SYSSTATUS */
+    case 0x64:	/* DMA4_CAPS_0 */
+    case 0x6c:	/* DMA4_CAPS_2 */
+    case 0x70:	/* DMA4_CAPS_3 */
+    case 0x74:	/* DMA4_CAPS_4 */
+        OMAP_RO_REG(addr);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+
+    /* Per-channel registers */
+    switch (addr) {
+    case 0x00:	/* DMA4_CCR */
+        ch->buf_disable = (value >> 25) & 1;
+        ch->src_sync = (value >> 24) & 1;	/* XXX For CamDMA must be 1 */
+        if (ch->buf_disable && !ch->src_sync)
+            fprintf(stderr, "%s: Buffering disable is not allowed in "
+                            "destination synchronised mode\n", __FUNCTION__);
+        ch->prefetch = (value >> 23) & 1;
+        ch->bs = (value >> 18) & 1;
+        ch->transparent_copy = (value >> 17) & 1;
+        ch->constant_fill = (value >> 16) & 1;
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->suspend = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1])
+            fprintf(stderr, "%s: For a packet transfer at least one port "
+                            "must be constant-addressed\n", __FUNCTION__);
+        ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
+        /* XXX must be 0x01 for CamDMA */
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        break;
+
+    case 0x04:	/* DMA4_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x08:	/* DMA4_CICR */
+        ch->interrupts = value & 0x09be;
+        break;
+
+    case 0x0c:	/* DMA4_CSR */
+        ch->cstatus &= ~value;
+        break;
+
+    case 0x10:	/* DMA4_CSDP */
+        ch->endian[0] =(value >> 21) & 1;
+        ch->endian_lock[0] =(value >> 20) & 1;
+        ch->endian[1] =(value >> 19) & 1;
+        ch->endian_lock[1] =(value >> 18) & 1;
+        if (ch->endian[0] != ch->endian[1])
+            fprintf(stderr, "%s: DMA endiannes conversion enable attempt\n",
+                            __FUNCTION__);
+        ch->write_mode = (value >> 16) & 3;
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->translate[1] = (value & 0x1e00) >> 9;
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->translate[0] = (value & 0x003c) >> 2;
+        if (ch->translate[0] | ch->translate[1])
+            fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
+                            __FUNCTION__);
+        ch->data_type = 1 << (value & 3);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
+        break;
+
+    case 0x14:	/* DMA4_CEN */
+        ch->set_update = 1;
+        ch->elements = value & 0xffffff;
+        break;
+
+    case 0x18:	/* DMA4_CFN */
+        ch->frames = value & 0xffff;
+        ch->set_update = 1;
+        break;
+
+    case 0x1c:	/* DMA4_CSSA */
+        ch->addr[0] = (target_phys_addr_t) (uint32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x20:	/* DMA4_CDSA */
+        ch->addr[1] = (target_phys_addr_t) (uint32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x24:	/* DMA4_CSEI */
+        ch->element_index[0] = (int16_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x28:	/* DMA4_CSFI */
+        ch->frame_index[0] = (int32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x2c:	/* DMA4_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x30:	/* DMA4_CDFI */
+        ch->frame_index[1] = (int32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x44:	/* DMA4_COLOR */
+        /* XXX only in sDMA */
+        ch->color = value;
+        break;
+
+    case 0x34:	/* DMA4_CSAC */
+    case 0x38:	/* DMA4_CDAC */
+    case 0x3c:	/* DMA4_CCEN */
+    case 0x40:	/* DMA4_CCFN */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_dma4_readfn[] = {
+    omap_badwidth_read16,
+    omap_dma4_read,
+    omap_dma4_read,
+};
+
+static CPUWriteMemoryFunc * const omap_dma4_writefn[] = {
+    omap_badwidth_write16,
+    omap_dma4_write,
+    omap_dma4_write,
+};
+
+struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk)
+{
+    int iomemtype, i;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            qemu_mallocz(sizeof(struct omap_dma_s));
+
+    s->model = omap_dma_4;
+    s->chans = chans;
+    s->mpu = mpu;
+    s->clk = fclk;
+
+    s->dma = soc_dma_init(s->chans);
+    s->dma->freq = omap_clk_getrate(fclk);
+    s->dma->transfer_fn = omap_dma_transfer_generic;
+    s->dma->setup_fn = omap_dma_transfer_setup;
+    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
+    s->dma->opaque = s;
+    for (i = 0; i < s->chans; i ++) {
+        s->ch[i].dma = &s->dma->ch[i];
+        s->dma->ch[i].opaque = &s->ch[i];
+    }
+
+    memcpy(&s->irq, irqs, sizeof(s->irq));
+    s->intr_update = omap_dma_interrupts_4_update;
+
+    omap_dma_setcaps(s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    omap_dma_reset(s->dma);
+    omap_dma_clk_update(s, 0, !!s->dma->freq);
+
+    iomemtype = cpu_register_io_memory(omap_dma4_readfn,
+                    omap_dma4_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x1000, iomemtype);
+
+    mpu->drq = s->dma->drq;
+
+    return s->dma;
+}
+
+struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
+{
+    struct omap_dma_s *s = dma->opaque;
+
+    return &s->lcd_ch;
+}
diff --git a/qemu-0.15.x/hw/omap_dss.c b/qemu-0.15.x/hw/omap_dss.c
new file mode 100644
index 0000000..afe287a
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_dss.c
@@ -0,0 +1,1068 @@
+/*
+ * OMAP2 Display Subsystem.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "console.h"
+#include "omap.h"
+
+struct omap_dss_s {
+    qemu_irq irq;
+    qemu_irq drq;
+    DisplayState *state;
+
+    int autoidle;
+    int control;
+    int enable;
+
+    struct omap_dss_panel_s {
+        int enable;
+        int nx;
+        int ny;
+
+        int x;
+        int y;
+    } dig, lcd;
+
+    struct {
+        uint32_t idlemode;
+        uint32_t irqst;
+        uint32_t irqen;
+        uint32_t control;
+        uint32_t config;
+        uint32_t capable;
+        uint32_t timing[4];
+        int line;
+        uint32_t bg[2];
+        uint32_t trans[2];
+
+        struct omap_dss_plane_s {
+            int enable;
+            int bpp;
+            int posx;
+            int posy;
+            int nx;
+            int ny;
+
+            target_phys_addr_t addr[3];
+
+            uint32_t attr;
+            uint32_t tresh;
+            int rowinc;
+            int colinc;
+            int wininc;
+        } l[3];
+
+        int invalidate;
+        uint16_t palette[256];
+    } dispc;
+
+    struct {
+        int idlemode;
+        uint32_t control;
+        int enable;
+        int pixels;
+        int busy;
+        int skiplines;
+        uint16_t rxbuf;
+        uint32_t config[2];
+        uint32_t time[4];
+        uint32_t data[6];
+        uint16_t vsync;
+        uint16_t hsync;
+        struct rfbi_chip_s *chip[2];
+    } rfbi;
+};
+
+static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+{
+    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+}
+
+static void omap_rfbi_reset(struct omap_dss_s *s)
+{
+    s->rfbi.idlemode = 0;
+    s->rfbi.control = 2;
+    s->rfbi.enable = 0;
+    s->rfbi.pixels = 0;
+    s->rfbi.skiplines = 0;
+    s->rfbi.busy = 0;
+    s->rfbi.config[0] = 0x00310000;
+    s->rfbi.config[1] = 0x00310000;
+    s->rfbi.time[0] = 0;
+    s->rfbi.time[1] = 0;
+    s->rfbi.time[2] = 0;
+    s->rfbi.time[3] = 0;
+    s->rfbi.data[0] = 0;
+    s->rfbi.data[1] = 0;
+    s->rfbi.data[2] = 0;
+    s->rfbi.data[3] = 0;
+    s->rfbi.data[4] = 0;
+    s->rfbi.data[5] = 0;
+    s->rfbi.vsync = 0;
+    s->rfbi.hsync = 0;
+}
+
+void omap_dss_reset(struct omap_dss_s *s)
+{
+    s->autoidle = 0;
+    s->control = 0;
+    s->enable = 0;
+
+    s->dig.enable = 0;
+    s->dig.nx = 1;
+    s->dig.ny = 1;
+
+    s->lcd.enable = 0;
+    s->lcd.nx = 1;
+    s->lcd.ny = 1;
+
+    s->dispc.idlemode = 0;
+    s->dispc.irqst = 0;
+    s->dispc.irqen = 0;
+    s->dispc.control = 0;
+    s->dispc.config = 0;
+    s->dispc.capable = 0x161;
+    s->dispc.timing[0] = 0;
+    s->dispc.timing[1] = 0;
+    s->dispc.timing[2] = 0;
+    s->dispc.timing[3] = 0;
+    s->dispc.line = 0;
+    s->dispc.bg[0] = 0;
+    s->dispc.bg[1] = 0;
+    s->dispc.trans[0] = 0;
+    s->dispc.trans[1] = 0;
+
+    s->dispc.l[0].enable = 0;
+    s->dispc.l[0].bpp = 0;
+    s->dispc.l[0].addr[0] = 0;
+    s->dispc.l[0].addr[1] = 0;
+    s->dispc.l[0].addr[2] = 0;
+    s->dispc.l[0].posx = 0;
+    s->dispc.l[0].posy = 0;
+    s->dispc.l[0].nx = 1;
+    s->dispc.l[0].ny = 1;
+    s->dispc.l[0].attr = 0;
+    s->dispc.l[0].tresh = 0;
+    s->dispc.l[0].rowinc = 1;
+    s->dispc.l[0].colinc = 1;
+    s->dispc.l[0].wininc = 0;
+
+    omap_rfbi_reset(s);
+    omap_dispc_interrupt_update(s);
+}
+
+static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* DSS_REVISIONNUMBER */
+        return 0x20;
+
+    case 0x10:	/* DSS_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14:	/* DSS_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x40:	/* DSS_CONTROL */
+        return s->control;
+
+    case 0x50:	/* DSS_PSA_LCD_REG_1 */
+    case 0x54:	/* DSS_PSA_LCD_REG_2 */
+    case 0x58:	/* DSS_PSA_VIDEO_REG */
+        /* TODO: fake some values when appropriate s->control bits are set */
+        return 0;
+
+    case 0x5c:	/* DSS_STATUS */
+        return 1 + (s->control & 1);
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_diss_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* DSS_REVISIONNUMBER */
+    case 0x14:	/* DSS_SYSSTATUS */
+    case 0x50:	/* DSS_PSA_LCD_REG_1 */
+    case 0x54:	/* DSS_PSA_LCD_REG_2 */
+    case 0x58:	/* DSS_PSA_VIDEO_REG */
+    case 0x5c:	/* DSS_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* DSS_SYSCONFIG */
+        if (value & 2)						/* SOFTRESET */
+            omap_dss_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40:	/* DSS_CONTROL */
+        s->control = value & 0x3dd;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_diss1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_diss_read,
+};
+
+static CPUWriteMemoryFunc * const omap_diss1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_diss_write,
+};
+
+static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x000:	/* DISPC_REVISION */
+        return 0x20;
+
+    case 0x010:	/* DISPC_SYSCONFIG */
+        return s->dispc.idlemode;
+
+    case 0x014:	/* DISPC_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x018:	/* DISPC_IRQSTATUS */
+        return s->dispc.irqst;
+
+    case 0x01c:	/* DISPC_IRQENABLE */
+        return s->dispc.irqen;
+
+    case 0x040:	/* DISPC_CONTROL */
+        return s->dispc.control;
+
+    case 0x044:	/* DISPC_CONFIG */
+        return s->dispc.config;
+
+    case 0x048:	/* DISPC_CAPABLE */
+        return s->dispc.capable;
+
+    case 0x04c:	/* DISPC_DEFAULT_COLOR0 */
+        return s->dispc.bg[0];
+    case 0x050:	/* DISPC_DEFAULT_COLOR1 */
+        return s->dispc.bg[1];
+    case 0x054:	/* DISPC_TRANS_COLOR0 */
+        return s->dispc.trans[0];
+    case 0x058:	/* DISPC_TRANS_COLOR1 */
+        return s->dispc.trans[1];
+
+    case 0x05c:	/* DISPC_LINE_STATUS */
+        return 0x7ff;
+    case 0x060:	/* DISPC_LINE_NUMBER */
+        return s->dispc.line;
+
+    case 0x064:	/* DISPC_TIMING_H */
+        return s->dispc.timing[0];
+    case 0x068:	/* DISPC_TIMING_V */
+        return s->dispc.timing[1];
+    case 0x06c:	/* DISPC_POL_FREQ */
+        return s->dispc.timing[2];
+    case 0x070:	/* DISPC_DIVISOR */
+        return s->dispc.timing[3];
+
+    case 0x078:	/* DISPC_SIZE_DIG */
+        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
+    case 0x07c:	/* DISPC_SIZE_LCD */
+        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
+
+    case 0x080:	/* DISPC_GFX_BA0 */
+        return s->dispc.l[0].addr[0];
+    case 0x084:	/* DISPC_GFX_BA1 */
+        return s->dispc.l[0].addr[1];
+    case 0x088:	/* DISPC_GFX_POSITION */
+        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+    case 0x08c:	/* DISPC_GFX_SIZE */
+        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+    case 0x0a0:	/* DISPC_GFX_ATTRIBUTES */
+        return s->dispc.l[0].attr;
+    case 0x0a4:	/* DISPC_GFX_FIFO_TRESHOLD */
+        return s->dispc.l[0].tresh;
+    case 0x0a8:	/* DISPC_GFX_FIFO_SIZE_STATUS */
+        return 256;
+    case 0x0ac:	/* DISPC_GFX_ROW_INC */
+        return s->dispc.l[0].rowinc;
+    case 0x0b0:	/* DISPC_GFX_PIXEL_INC */
+        return s->dispc.l[0].colinc;
+    case 0x0b4:	/* DISPC_GFX_WINDOW_SKIP */
+        return s->dispc.l[0].wininc;
+    case 0x0b8:	/* DISPC_GFX_TABLE_BA */
+        return s->dispc.l[0].addr[2];
+
+    case 0x0bc:	/* DISPC_VID1_BA0 */
+    case 0x0c0:	/* DISPC_VID1_BA1 */
+    case 0x0c4:	/* DISPC_VID1_POSITION */
+    case 0x0c8:	/* DISPC_VID1_SIZE */
+    case 0x0cc:	/* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:	/* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d4:	/* DISPC_VID1_FIFO_SIZE_STATUS */
+    case 0x0d8:	/* DISPC_VID1_ROW_INC */
+    case 0x0dc:	/* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:	/* DISPC_VID1_FIR */
+    case 0x0e4:	/* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:	/* DISPC_VID1_ACCU0 */
+    case 0x0ec:	/* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:	/* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:	/* DISPC_VID2_BA0 */
+    case 0x150:	/* DISPC_VID2_BA1 */
+    case 0x154:	/* DISPC_VID2_POSITION */
+    case 0x158:	/* DISPC_VID2_SIZE */
+    case 0x15c:	/* DISPC_VID2_ATTRIBUTES */
+    case 0x160:	/* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x164:	/* DISPC_VID2_FIFO_SIZE_STATUS */
+    case 0x168:	/* DISPC_VID2_ROW_INC */
+    case 0x16c:	/* DISPC_VID2_PIXEL_INC */
+    case 0x170:	/* DISPC_VID2_FIR */
+    case 0x174:	/* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:	/* DISPC_VID2_ACCU0 */
+    case 0x17c:	/* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:	/* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:	/* DISPC_DATA_CYCLE1 */
+    case 0x1d8:	/* DISPC_DATA_CYCLE2 */
+    case 0x1dc:	/* DISPC_DATA_CYCLE3 */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_disc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x010:	/* DISPC_SYSCONFIG */
+        if (value & 2)						/* SOFTRESET */
+            omap_dss_reset(s);
+        s->dispc.idlemode = value & 0x301b;
+        break;
+
+    case 0x018:	/* DISPC_IRQSTATUS */
+        s->dispc.irqst &= ~value;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x01c:	/* DISPC_IRQENABLE */
+        s->dispc.irqen = value & 0xffff;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x040:	/* DISPC_CONTROL */
+        s->dispc.control = value & 0x07ff9fff;
+        s->dig.enable = (value >> 1) & 1;
+        s->lcd.enable = (value >> 0) & 1;
+        if (value & (1 << 12))			/* OVERLAY_OPTIMIZATION */
+            if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
+                 fprintf(stderr, "%s: Overlay Optimization when no overlay "
+                                 "region effectively exists leads to "
+                                 "unpredictable behaviour!\n", __FUNCTION__);
+        if (value & (1 << 6)) {				/* GODIGITAL */
+            /* XXX: Shadowed fields are:
+             * s->dispc.config
+             * s->dispc.capable
+             * s->dispc.bg[0]
+             * s->dispc.bg[1]
+             * s->dispc.trans[0]
+             * s->dispc.trans[1]
+             * s->dispc.line
+             * s->dispc.timing[0]
+             * s->dispc.timing[1]
+             * s->dispc.timing[2]
+             * s->dispc.timing[3]
+             * s->lcd.nx
+             * s->lcd.ny
+             * s->dig.nx
+             * s->dig.ny
+             * s->dispc.l[0].addr[0]
+             * s->dispc.l[0].addr[1]
+             * s->dispc.l[0].addr[2]
+             * s->dispc.l[0].posx
+             * s->dispc.l[0].posy
+             * s->dispc.l[0].nx
+             * s->dispc.l[0].ny
+             * s->dispc.l[0].tresh
+             * s->dispc.l[0].rowinc
+             * s->dispc.l[0].colinc
+             * s->dispc.l[0].wininc
+             * All they need to be loaded here from their shadow registers.
+             */
+        }
+        if (value & (1 << 5)) {				/* GOLCD */
+             /* XXX: Likewise for LCD here.  */
+        }
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x044:	/* DISPC_CONFIG */
+        s->dispc.config = value & 0x3fff;
+        /* XXX:
+         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
+         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
+         */
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x048:	/* DISPC_CAPABLE */
+        s->dispc.capable = value & 0x3ff;
+        break;
+
+    case 0x04c:	/* DISPC_DEFAULT_COLOR0 */
+        s->dispc.bg[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x050:	/* DISPC_DEFAULT_COLOR1 */
+        s->dispc.bg[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x054:	/* DISPC_TRANS_COLOR0 */
+        s->dispc.trans[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x058:	/* DISPC_TRANS_COLOR1 */
+        s->dispc.trans[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x060:	/* DISPC_LINE_NUMBER */
+        s->dispc.line = value & 0x7ff;
+        break;
+
+    case 0x064:	/* DISPC_TIMING_H */
+        s->dispc.timing[0] = value & 0x0ff0ff3f;
+        break;
+    case 0x068:	/* DISPC_TIMING_V */
+        s->dispc.timing[1] = value & 0x0ff0ff3f;
+        break;
+    case 0x06c:	/* DISPC_POL_FREQ */
+        s->dispc.timing[2] = value & 0x0003ffff;
+        break;
+    case 0x070:	/* DISPC_DIVISOR */
+        s->dispc.timing[3] = value & 0x00ff00ff;
+        break;
+
+    case 0x078:	/* DISPC_SIZE_DIG */
+        s->dig.nx = ((value >>  0) & 0x7ff) + 1;		/* PPL */
+        s->dig.ny = ((value >> 16) & 0x7ff) + 1;		/* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x07c:	/* DISPC_SIZE_LCD */
+        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;		/* PPL */
+        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;		/* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x080:	/* DISPC_GFX_BA0 */
+        s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x084:	/* DISPC_GFX_BA1 */
+        s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x088:	/* DISPC_GFX_POSITION */
+        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);		/* GFXPOSX */
+        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);		/* GFXPOSY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x08c:	/* DISPC_GFX_SIZE */
+        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;		/* GFXSIZEX */
+        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;		/* GFXSIZEY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a0:	/* DISPC_GFX_ATTRIBUTES */
+        s->dispc.l[0].attr = value & 0x7ff;
+        if (value & (3 << 9))
+            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
+                            __FUNCTION__);
+        s->dispc.l[0].enable = value & 1;
+        s->dispc.l[0].bpp = (value >> 1) & 0xf;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a4:	/* DISPC_GFX_FIFO_TRESHOLD */
+        s->dispc.l[0].tresh = value & 0x01ff01ff;
+        break;
+    case 0x0ac:	/* DISPC_GFX_ROW_INC */
+        s->dispc.l[0].rowinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b0:	/* DISPC_GFX_PIXEL_INC */
+        s->dispc.l[0].colinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b4:	/* DISPC_GFX_WINDOW_SKIP */
+        s->dispc.l[0].wininc = value;
+        break;
+    case 0x0b8:	/* DISPC_GFX_TABLE_BA */
+        s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x0bc:	/* DISPC_VID1_BA0 */
+    case 0x0c0:	/* DISPC_VID1_BA1 */
+    case 0x0c4:	/* DISPC_VID1_POSITION */
+    case 0x0c8:	/* DISPC_VID1_SIZE */
+    case 0x0cc:	/* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:	/* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d8:	/* DISPC_VID1_ROW_INC */
+    case 0x0dc:	/* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:	/* DISPC_VID1_FIR */
+    case 0x0e4:	/* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:	/* DISPC_VID1_ACCU0 */
+    case 0x0ec:	/* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:	/* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:	/* DISPC_VID2_BA0 */
+    case 0x150:	/* DISPC_VID2_BA1 */
+    case 0x154:	/* DISPC_VID2_POSITION */
+    case 0x158:	/* DISPC_VID2_SIZE */
+    case 0x15c:	/* DISPC_VID2_ATTRIBUTES */
+    case 0x160:	/* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x168:	/* DISPC_VID2_ROW_INC */
+    case 0x16c:	/* DISPC_VID2_PIXEL_INC */
+    case 0x170:	/* DISPC_VID2_FIR */
+    case 0x174:	/* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:	/* DISPC_VID2_ACCU0 */
+    case 0x17c:	/* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:	/* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:	/* DISPC_DATA_CYCLE1 */
+    case 0x1d8:	/* DISPC_DATA_CYCLE2 */
+    case 0x1dc:	/* DISPC_DATA_CYCLE3 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_disc1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_disc_read,
+};
+
+static CPUWriteMemoryFunc * const omap_disc1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_disc_write,
+};
+
+static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
+{
+    if (!s->rfbi.busy)
+        return;
+
+    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
+
+    s->rfbi.busy = 0;
+}
+
+static void omap_rfbi_transfer_start(struct omap_dss_s *s)
+{
+    void *data;
+    target_phys_addr_t len;
+    target_phys_addr_t data_addr;
+    int pitch;
+    static void *bounce_buffer;
+    static target_phys_addr_t bounce_len;
+
+    if (!s->rfbi.enable || s->rfbi.busy)
+        return;
+
+    if (s->rfbi.control & (1 << 1)) {				/* BYPASS */
+        /* TODO: in non-Bypass mode we probably need to just assert the
+         * DRQ and wait for DMA to write the pixels.  */
+        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
+        return;
+    }
+
+    if (!(s->dispc.control & (1 << 11)))			/* RFBIMODE */
+        return;
+    /* TODO: check that LCD output is enabled in DISPC.  */
+
+    s->rfbi.busy = 1;
+
+    len = s->rfbi.pixels * 2;
+
+    data_addr = s->dispc.l[0].addr[0];
+    data = cpu_physical_memory_map(data_addr, &len, 0);
+    if (data && len != s->rfbi.pixels * 2) {
+        cpu_physical_memory_unmap(data, len, 0, 0);
+        data = NULL;
+        len = s->rfbi.pixels * 2;
+    }
+    if (!data) {
+        if (len > bounce_len) {
+            bounce_buffer = qemu_realloc(bounce_buffer, len);
+        }
+        data = bounce_buffer;
+        cpu_physical_memory_read(data_addr, data, len);
+    }
+
+    /* TODO bpp */
+    s->rfbi.pixels = 0;
+
+    /* TODO: negative values */
+    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
+
+    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
+    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+
+    if (data != bounce_buffer) {
+        cpu_physical_memory_unmap(data, len, 0, len);
+    }
+
+    omap_rfbi_transfer_stop(s);
+
+    /* TODO */
+    s->dispc.irqst |= 1;					/* FRAMEDONE */
+    omap_dispc_interrupt_update(s);
+}
+
+static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* RFBI_REVISION */
+        return 0x10;
+
+    case 0x10:	/* RFBI_SYSCONFIG */
+        return s->rfbi.idlemode;
+
+    case 0x14:	/* RFBI_SYSSTATUS */
+        return 1 | (s->rfbi.busy << 8);				/* RESETDONE */
+
+    case 0x40:	/* RFBI_CONTROL */
+        return s->rfbi.control;
+
+    case 0x44:	/* RFBI_PIXELCNT */
+        return s->rfbi.pixels;
+
+    case 0x48:	/* RFBI_LINE_NUMBER */
+        return s->rfbi.skiplines;
+
+    case 0x58:	/* RFBI_READ */
+    case 0x5c:	/* RFBI_STATUS */
+        return s->rfbi.rxbuf;
+
+    case 0x60:	/* RFBI_CONFIG0 */
+        return s->rfbi.config[0];
+    case 0x64:	/* RFBI_ONOFF_TIME0 */
+        return s->rfbi.time[0];
+    case 0x68:	/* RFBI_CYCLE_TIME0 */
+        return s->rfbi.time[1];
+    case 0x6c:	/* RFBI_DATA_CYCLE1_0 */
+        return s->rfbi.data[0];
+    case 0x70:	/* RFBI_DATA_CYCLE2_0 */
+        return s->rfbi.data[1];
+    case 0x74:	/* RFBI_DATA_CYCLE3_0 */
+        return s->rfbi.data[2];
+
+    case 0x78:	/* RFBI_CONFIG1 */
+        return s->rfbi.config[1];
+    case 0x7c:	/* RFBI_ONOFF_TIME1 */
+        return s->rfbi.time[2];
+    case 0x80:	/* RFBI_CYCLE_TIME1 */
+        return s->rfbi.time[3];
+    case 0x84:	/* RFBI_DATA_CYCLE1_1 */
+        return s->rfbi.data[3];
+    case 0x88:	/* RFBI_DATA_CYCLE2_1 */
+        return s->rfbi.data[4];
+    case 0x8c:	/* RFBI_DATA_CYCLE3_1 */
+        return s->rfbi.data[5];
+
+    case 0x90:	/* RFBI_VSYNC_WIDTH */
+        return s->rfbi.vsync;
+    case 0x94:	/* RFBI_HSYNC_WIDTH */
+        return s->rfbi.hsync;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    switch (addr) {
+    case 0x10:	/* RFBI_SYSCONFIG */
+        if (value & 2)						/* SOFTRESET */
+            omap_rfbi_reset(s);
+        s->rfbi.idlemode = value & 0x19;
+        break;
+
+    case 0x40:	/* RFBI_CONTROL */
+        s->rfbi.control = value & 0xf;
+        s->rfbi.enable = value & 1;
+        if (value & (1 << 4) &&					/* ITE */
+                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
+            omap_rfbi_transfer_start(s);
+        break;
+
+    case 0x44:	/* RFBI_PIXELCNT */
+        s->rfbi.pixels = value;
+        break;
+
+    case 0x48:	/* RFBI_LINE_NUMBER */
+        s->rfbi.skiplines = value & 0x7ff;
+        break;
+
+    case 0x4c:	/* RFBI_CMD */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
+        break;
+    case 0x50:	/* RFBI_PARAM */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+        break;
+    case 0x54:	/* RFBI_DATA */
+        /* TODO: take into account the format set up in s->rfbi.config[?] and
+         * s->rfbi.data[?], but special-case the most usual scenario so that
+         * speed doesn't suffer.  */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
+        }
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
+        }
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+    case 0x58:	/* RFBI_READ */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x5c:	/* RFBI_STATUS */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x60:	/* RFBI_CONFIG0 */
+        s->rfbi.config[0] = value & 0x003f1fff;
+        break;
+
+    case 0x64:	/* RFBI_ONOFF_TIME0 */
+        s->rfbi.time[0] = value & 0x3fffffff;
+        break;
+    case 0x68:	/* RFBI_CYCLE_TIME0 */
+        s->rfbi.time[1] = value & 0x0fffffff;
+        break;
+    case 0x6c:	/* RFBI_DATA_CYCLE1_0 */
+        s->rfbi.data[0] = value & 0x0f1f0f1f;
+        break;
+    case 0x70:	/* RFBI_DATA_CYCLE2_0 */
+        s->rfbi.data[1] = value & 0x0f1f0f1f;
+        break;
+    case 0x74:	/* RFBI_DATA_CYCLE3_0 */
+        s->rfbi.data[2] = value & 0x0f1f0f1f;
+        break;
+    case 0x78:	/* RFBI_CONFIG1 */
+        s->rfbi.config[1] = value & 0x003f1fff;
+        break;
+
+    case 0x7c:	/* RFBI_ONOFF_TIME1 */
+        s->rfbi.time[2] = value & 0x3fffffff;
+        break;
+    case 0x80:	/* RFBI_CYCLE_TIME1 */
+        s->rfbi.time[3] = value & 0x0fffffff;
+        break;
+    case 0x84:	/* RFBI_DATA_CYCLE1_1 */
+        s->rfbi.data[3] = value & 0x0f1f0f1f;
+        break;
+    case 0x88:	/* RFBI_DATA_CYCLE2_1 */
+        s->rfbi.data[4] = value & 0x0f1f0f1f;
+        break;
+    case 0x8c:	/* RFBI_DATA_CYCLE3_1 */
+        s->rfbi.data[5] = value & 0x0f1f0f1f;
+        break;
+
+    case 0x90:	/* RFBI_VSYNC_WIDTH */
+        s->rfbi.vsync = value & 0xffff;
+        break;
+    case 0x94:	/* RFBI_HSYNC_WIDTH */
+        s->rfbi.hsync = value & 0xffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_rfbi1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_rfbi_read,
+};
+
+static CPUWriteMemoryFunc * const omap_rfbi1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_rfbi_write,
+};
+
+static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr)
+{
+    switch (addr) {
+    case 0x00:	/* REV_ID */
+    case 0x04:	/* STATUS */
+    case 0x08:	/* F_CONTROL */
+    case 0x10:	/* VIDOUT_CTRL */
+    case 0x14:	/* SYNC_CTRL */
+    case 0x1c:	/* LLEN */
+    case 0x20:	/* FLENS */
+    case 0x24:	/* HFLTR_CTRL */
+    case 0x28:	/* CC_CARR_WSS_CARR */
+    case 0x2c:	/* C_PHASE */
+    case 0x30:	/* GAIN_U */
+    case 0x34:	/* GAIN_V */
+    case 0x38:	/* GAIN_Y */
+    case 0x3c:	/* BLACK_LEVEL */
+    case 0x40:	/* BLANK_LEVEL */
+    case 0x44:	/* X_COLOR */
+    case 0x48:	/* M_CONTROL */
+    case 0x4c:	/* BSTAMP_WSS_DATA */
+    case 0x50:	/* S_CARR */
+    case 0x54:	/* LINE21 */
+    case 0x58:	/* LN_SEL */
+    case 0x5c:	/* L21__WC_CTL */
+    case 0x60:	/* HTRIGGER_VTRIGGER */
+    case 0x64:	/* SAVID__EAVID */
+    case 0x68:	/* FLEN__FAL */
+    case 0x6c:	/* LAL__PHASE_RESET */
+    case 0x70:	/* HS_INT_START_STOP_X */
+    case 0x74:	/* HS_EXT_START_STOP_X */
+    case 0x78:	/* VS_INT_START_X */
+    case 0x7c:	/* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80:	/* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84:	/* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88:	/* VS_EXT_STOP_Y */
+    case 0x90:	/* AVID_START_STOP_X */
+    case 0x94:	/* AVID_START_STOP_Y */
+    case 0xa0:	/* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4:	/* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8:	/* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0:	/* TVDETGP_INT_START_STOP_X */
+    case 0xb4:	/* TVDETGP_INT_START_STOP_Y */
+    case 0xb8:	/* GEN_CTRL */
+    case 0xc4:	/* DAC_TST__DAC_A */
+    case 0xc8:	/* DAC_B__DAC_C */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_venc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    switch (addr) {
+    case 0x08:	/* F_CONTROL */
+    case 0x10:	/* VIDOUT_CTRL */
+    case 0x14:	/* SYNC_CTRL */
+    case 0x1c:	/* LLEN */
+    case 0x20:	/* FLENS */
+    case 0x24:	/* HFLTR_CTRL */
+    case 0x28:	/* CC_CARR_WSS_CARR */
+    case 0x2c:	/* C_PHASE */
+    case 0x30:	/* GAIN_U */
+    case 0x34:	/* GAIN_V */
+    case 0x38:	/* GAIN_Y */
+    case 0x3c:	/* BLACK_LEVEL */
+    case 0x40:	/* BLANK_LEVEL */
+    case 0x44:	/* X_COLOR */
+    case 0x48:	/* M_CONTROL */
+    case 0x4c:	/* BSTAMP_WSS_DATA */
+    case 0x50:	/* S_CARR */
+    case 0x54:	/* LINE21 */
+    case 0x58:	/* LN_SEL */
+    case 0x5c:	/* L21__WC_CTL */
+    case 0x60:	/* HTRIGGER_VTRIGGER */
+    case 0x64:	/* SAVID__EAVID */
+    case 0x68:	/* FLEN__FAL */
+    case 0x6c:	/* LAL__PHASE_RESET */
+    case 0x70:	/* HS_INT_START_STOP_X */
+    case 0x74:	/* HS_EXT_START_STOP_X */
+    case 0x78:	/* VS_INT_START_X */
+    case 0x7c:	/* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80:	/* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84:	/* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88:	/* VS_EXT_STOP_Y */
+    case 0x90:	/* AVID_START_STOP_X */
+    case 0x94:	/* AVID_START_STOP_Y */
+    case 0xa0:	/* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4:	/* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8:	/* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0:	/* TVDETGP_INT_START_STOP_X */
+    case 0xb4:	/* TVDETGP_INT_START_STOP_Y */
+    case 0xb8:	/* GEN_CTRL */
+    case 0xc4:	/* DAC_TST__DAC_A */
+    case 0xc8:	/* DAC_B__DAC_C */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_venc1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_venc_read,
+};
+
+static CPUWriteMemoryFunc * const omap_venc1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_venc_write,
+};
+
+static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr)
+{
+    switch (addr) {
+    case 0x0a8:	/* SBIMERRLOGA */
+    case 0x0b0:	/* SBIMERRLOG */
+    case 0x190:	/* SBIMSTATE */
+    case 0x198:	/* SBTMSTATE_L */
+    case 0x19c:	/* SBTMSTATE_H */
+    case 0x1a8:	/* SBIMCONFIG_L */
+    case 0x1ac:	/* SBIMCONFIG_H */
+    case 0x1f8:	/* SBID_L */
+    case 0x1fc:	/* SBID_H */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_im3_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    switch (addr) {
+    case 0x0b0:	/* SBIMERRLOG */
+    case 0x190:	/* SBIMSTATE */
+    case 0x198:	/* SBTMSTATE_L */
+    case 0x19c:	/* SBTMSTATE_H */
+    case 0x1a8:	/* SBIMCONFIG_L */
+    case 0x1ac:	/* SBIMCONFIG_H */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_im3_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_im3_read,
+};
+
+static CPUWriteMemoryFunc * const omap_im3_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_im3_write,
+};
+
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                target_phys_addr_t l3_base,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2)
+{
+    int iomemtype[5];
+    struct omap_dss_s *s = (struct omap_dss_s *)
+            qemu_mallocz(sizeof(struct omap_dss_s));
+
+    s->irq = irq;
+    s->drq = drq;
+    omap_dss_reset(s);
+
+    iomemtype[0] = l4_register_io_memory(omap_diss1_readfn,
+                    omap_diss1_writefn, s);
+    iomemtype[1] = l4_register_io_memory(omap_disc1_readfn,
+                    omap_disc1_writefn, s);
+    iomemtype[2] = l4_register_io_memory(omap_rfbi1_readfn,
+                    omap_rfbi1_writefn, s);
+    iomemtype[3] = l4_register_io_memory(omap_venc1_readfn,
+                    omap_venc1_writefn, s);
+    iomemtype[4] = cpu_register_io_memory(omap_im3_readfn,
+                    omap_im3_writefn, s, DEVICE_NATIVE_ENDIAN);
+    omap_l4_attach(ta, 0, iomemtype[0]);
+    omap_l4_attach(ta, 1, iomemtype[1]);
+    omap_l4_attach(ta, 2, iomemtype[2]);
+    omap_l4_attach(ta, 3, iomemtype[3]);
+    cpu_register_physical_memory(l3_base, 0x1000, iomemtype[4]);
+
+#if 0
+    s->state = graphic_console_init(omap_update_display,
+                                    omap_invalidate_display, omap_screen_dump, s);
+#endif
+
+    return s;
+}
+
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
+{
+    if (cs < 0 || cs > 1)
+        hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
+    s->rfbi.chip[cs] = chip;
+}
diff --git a/qemu-0.15.x/hw/omap_gpio.c b/qemu-0.15.x/hw/omap_gpio.c
new file mode 100644
index 0000000..478f7d9
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_gpio.c
@@ -0,0 +1,725 @@
+/*
+ * TI OMAP processors GPIO emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "omap.h"
+/* General-Purpose I/O */
+struct omap_gpio_s {
+    qemu_irq irq;
+    qemu_irq *in;
+    qemu_irq handler[16];
+
+    uint16_t inputs;
+    uint16_t outputs;
+    uint16_t dir;
+    uint16_t edge;
+    uint16_t mask;
+    uint16_t ints;
+    uint16_t pins;
+};
+
+static void omap_gpio_set(void *opaque, int line, int level)
+{
+    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    uint16_t prev = s->inputs;
+
+    if (level)
+        s->inputs |= 1 << line;
+    else
+        s->inputs &= ~(1 << line);
+
+    if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
+                    (1 << line) & s->dir & ~s->mask) {
+        s->ints |= 1 << line;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* DATA_INPUT */
+        return s->inputs & s->pins;
+
+    case 0x04:	/* DATA_OUTPUT */
+        return s->outputs;
+
+    case 0x08:	/* DIRECTION_CONTROL */
+        return s->dir;
+
+    case 0x0c:	/* INTERRUPT_CONTROL */
+        return s->edge;
+
+    case 0x10:	/* INTERRUPT_MASK */
+        return s->mask;
+
+    case 0x14:	/* INTERRUPT_STATUS */
+        return s->ints;
+
+    case 0x18:	/* PIN_CONTROL (not in OMAP310) */
+        OMAP_BAD_REG(addr);
+        return s->pins;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpio_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t diff;
+    int ln;
+
+    switch (offset) {
+    case 0x00:	/* DATA_INPUT */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x04:	/* DATA_OUTPUT */
+        diff = (s->outputs ^ value) & ~s->dir;
+        s->outputs = value;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x08:	/* DIRECTION_CONTROL */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x0c:	/* INTERRUPT_CONTROL */
+        s->edge = value;
+        break;
+
+    case 0x10:	/* INTERRUPT_MASK */
+        s->mask = value;
+        break;
+
+    case 0x14:	/* INTERRUPT_STATUS */
+        s->ints &= ~value;
+        if (!s->ints)
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x18:	/* PIN_CONTROL (not in OMAP310 TRM) */
+        OMAP_BAD_REG(addr);
+        s->pins = value;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+/* *Some* sources say the memory region is 32-bit.  */
+static CPUReadMemoryFunc * const omap_gpio_readfn[] = {
+    omap_badwidth_read16,
+    omap_gpio_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_gpio_writefn[] = {
+    omap_badwidth_write16,
+    omap_gpio_write,
+    omap_badwidth_write16,
+};
+
+void omap_gpio_reset(struct omap_gpio_s *s)
+{
+    s->inputs = 0;
+    s->outputs = ~0;
+    s->dir = ~0;
+    s->edge = ~0;
+    s->mask = ~0;
+    s->ints = 0;
+    s->pins = ~0;
+}
+
+struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_gpio_s *s = (struct omap_gpio_s *)
+            qemu_mallocz(sizeof(struct omap_gpio_s));
+
+    s->irq = irq;
+    s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
+    omap_gpio_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_gpio_readfn,
+                    omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x1000, iomemtype);
+
+    return s;
+}
+
+qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
+{
+    return s->in;
+}
+
+void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler)
+{
+    if (line >= 16 || line < 0)
+        hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
+    s->handler[line] = handler;
+}
+
+/* General-Purpose Interface of OMAP2 */
+struct omap2_gpio_s {
+    qemu_irq irq[2];
+    qemu_irq wkup;
+    qemu_irq *in;
+    qemu_irq handler[32];
+
+    uint8_t config[2];
+    uint32_t inputs;
+    uint32_t outputs;
+    uint32_t dir;
+    uint32_t level[2];
+    uint32_t edge[2];
+    uint32_t mask[2];
+    uint32_t wumask;
+    uint32_t ints[2];
+    uint32_t debounce;
+    uint8_t delay;
+};
+
+static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
+                int line)
+{
+    qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
+}
+
+static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
+{
+    if (!(s->config[0] & (1 << 2)))			/* ENAWAKEUP */
+        return;
+    if (!(s->config[0] & (3 << 3)))			/* Force Idle */
+        return;
+    if (!(s->wumask & (1 << line)))
+        return;
+
+    qemu_irq_raise(s->wkup);
+}
+
+static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
+                uint32_t diff)
+{
+    int ln;
+
+    s->outputs ^= diff;
+    diff &= ~s->dir;
+    while ((ln = ffs(diff))) {
+        ln --;
+        qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
+        diff &= ~(1 << ln);
+    }
+}
+
+static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
+{
+    s->ints[line] |= s->dir &
+            ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
+    omap2_gpio_module_int_update(s, line);
+}
+
+static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
+{
+    s->ints[0] |= 1 << line;
+    omap2_gpio_module_int_update(s, 0);
+    s->ints[1] |= 1 << line;
+    omap2_gpio_module_int_update(s, 1);
+    omap2_gpio_module_wake(s, line);
+}
+
+static void omap2_gpio_module_set(void *opaque, int line, int level)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+
+    if (level) {
+        if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
+            omap2_gpio_module_int(s, line);
+        s->inputs |= 1 << line;
+    } else {
+        if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
+            omap2_gpio_module_int(s, line);
+        s->inputs &= ~(1 << line);
+    }
+}
+
+static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
+{
+    s->config[0] = 0;
+    s->config[1] = 2;
+    s->ints[0] = 0;
+    s->ints[1] = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+    s->wumask = 0;
+    s->dir = ~0;
+    s->level[0] = 0;
+    s->level[1] = 0;
+    s->edge[0] = 0;
+    s->edge[1] = 0;
+    s->debounce = 0;
+    s->delay = 0;
+}
+
+static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* GPIO_REVISION */
+        return 0x18;
+
+    case 0x10:	/* GPIO_SYSCONFIG */
+        return s->config[0];
+
+    case 0x14:	/* GPIO_SYSSTATUS */
+        return 0x01;
+
+    case 0x18:	/* GPIO_IRQSTATUS1 */
+        return s->ints[0];
+
+    case 0x1c:	/* GPIO_IRQENABLE1 */
+    case 0x60:	/* GPIO_CLEARIRQENABLE1 */
+    case 0x64:	/* GPIO_SETIRQENABLE1 */
+        return s->mask[0];
+
+    case 0x20:	/* GPIO_WAKEUPENABLE */
+    case 0x80:	/* GPIO_CLEARWKUENA */
+    case 0x84:	/* GPIO_SETWKUENA */
+        return s->wumask;
+
+    case 0x28:	/* GPIO_IRQSTATUS2 */
+        return s->ints[1];
+
+    case 0x2c:	/* GPIO_IRQENABLE2 */
+    case 0x70:	/* GPIO_CLEARIRQENABLE2 */
+    case 0x74:	/* GPIO_SETIREQNEABLE2 */
+        return s->mask[1];
+
+    case 0x30:	/* GPIO_CTRL */
+        return s->config[1];
+
+    case 0x34:	/* GPIO_OE */
+        return s->dir;
+
+    case 0x38:	/* GPIO_DATAIN */
+        return s->inputs;
+
+    case 0x3c:	/* GPIO_DATAOUT */
+    case 0x90:	/* GPIO_CLEARDATAOUT */
+    case 0x94:	/* GPIO_SETDATAOUT */
+        return s->outputs;
+
+    case 0x40:	/* GPIO_LEVELDETECT0 */
+        return s->level[0];
+
+    case 0x44:	/* GPIO_LEVELDETECT1 */
+        return s->level[1];
+
+    case 0x48:	/* GPIO_RISINGDETECT */
+        return s->edge[0];
+
+    case 0x4c:	/* GPIO_FALLINGDETECT */
+        return s->edge[1];
+
+    case 0x50:	/* GPIO_DEBOUNCENABLE */
+        return s->debounce;
+
+    case 0x54:	/* GPIO_DEBOUNCINGTIME */
+        return s->delay;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    uint32_t diff;
+    int ln;
+
+    switch (addr) {
+    case 0x00:	/* GPIO_REVISION */
+    case 0x14:	/* GPIO_SYSSTATUS */
+    case 0x38:	/* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* GPIO_SYSCONFIG */
+        if (((value >> 3) & 3) == 3)
+            fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
+        if (value & 2)
+            omap2_gpio_module_reset(s);
+        s->config[0] = value & 0x1d;
+        break;
+
+    case 0x18:	/* GPIO_IRQSTATUS1 */
+        if (s->ints[0] & value) {
+            s->ints[0] &= ~value;
+            omap2_gpio_module_level_update(s, 0);
+        }
+        break;
+
+    case 0x1c:	/* GPIO_IRQENABLE1 */
+        s->mask[0] = value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x20:	/* GPIO_WAKEUPENABLE */
+        s->wumask = value;
+        break;
+
+    case 0x28:	/* GPIO_IRQSTATUS2 */
+        if (s->ints[1] & value) {
+            s->ints[1] &= ~value;
+            omap2_gpio_module_level_update(s, 1);
+        }
+        break;
+
+    case 0x2c:	/* GPIO_IRQENABLE2 */
+        s->mask[1] = value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x30:	/* GPIO_CTRL */
+        s->config[1] = value & 7;
+        break;
+
+    case 0x34:	/* GPIO_OE */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            diff &= ~(1 <<-- ln);
+            qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+        }
+
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x3c:	/* GPIO_DATAOUT */
+        omap2_gpio_module_out_update(s, s->outputs ^ value);
+        break;
+
+    case 0x40:	/* GPIO_LEVELDETECT0 */
+        s->level[0] = value;
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x44:	/* GPIO_LEVELDETECT1 */
+        s->level[1] = value;
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x48:	/* GPIO_RISINGDETECT */
+        s->edge[0] = value;
+        break;
+
+    case 0x4c:	/* GPIO_FALLINGDETECT */
+        s->edge[1] = value;
+        break;
+
+    case 0x50:	/* GPIO_DEBOUNCENABLE */
+        s->debounce = value;
+        break;
+
+    case 0x54:	/* GPIO_DEBOUNCINGTIME */
+        s->delay = value;
+        break;
+
+    case 0x60:	/* GPIO_CLEARIRQENABLE1 */
+        s->mask[0] &= ~value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x64:	/* GPIO_SETIRQENABLE1 */
+        s->mask[0] |= value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x70:	/* GPIO_CLEARIRQENABLE2 */
+        s->mask[1] &= ~value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x74:	/* GPIO_SETIREQNEABLE2 */
+        s->mask[1] |= value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x80:	/* GPIO_CLEARWKUENA */
+        s->wumask &= ~value;
+        break;
+
+    case 0x84:	/* GPIO_SETWKUENA */
+        s->wumask |= value;
+        break;
+
+    case 0x90:	/* GPIO_CLEARDATAOUT */
+        omap2_gpio_module_out_update(s, s->outputs & value);
+        break;
+
+    case 0x94:	/* GPIO_SETDATAOUT */
+        omap2_gpio_module_out_update(s, ~s->outputs & value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr)
+{
+    return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3);
+}
+
+static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    uint32_t cur = 0;
+    uint32_t mask = 0xffff;
+
+    switch (addr & ~3) {
+    case 0x00:	/* GPIO_REVISION */
+    case 0x14:	/* GPIO_SYSSTATUS */
+    case 0x38:	/* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* GPIO_SYSCONFIG */
+    case 0x1c:	/* GPIO_IRQENABLE1 */
+    case 0x20:	/* GPIO_WAKEUPENABLE */
+    case 0x2c:	/* GPIO_IRQENABLE2 */
+    case 0x30:	/* GPIO_CTRL */
+    case 0x34:	/* GPIO_OE */
+    case 0x3c:	/* GPIO_DATAOUT */
+    case 0x40:	/* GPIO_LEVELDETECT0 */
+    case 0x44:	/* GPIO_LEVELDETECT1 */
+    case 0x48:	/* GPIO_RISINGDETECT */
+    case 0x4c:	/* GPIO_FALLINGDETECT */
+    case 0x50:	/* GPIO_DEBOUNCENABLE */
+    case 0x54:	/* GPIO_DEBOUNCINGTIME */
+        cur = omap2_gpio_module_read(opaque, addr & ~3) &
+                ~(mask << ((addr & 3) << 3));
+
+        /* Fall through.  */
+    case 0x18:	/* GPIO_IRQSTATUS1 */
+    case 0x28:	/* GPIO_IRQSTATUS2 */
+    case 0x60:	/* GPIO_CLEARIRQENABLE1 */
+    case 0x64:	/* GPIO_SETIRQENABLE1 */
+    case 0x70:	/* GPIO_CLEARIRQENABLE2 */
+    case 0x74:	/* GPIO_SETIREQNEABLE2 */
+    case 0x80:	/* GPIO_CLEARWKUENA */
+    case 0x84:	/* GPIO_SETWKUENA */
+    case 0x90:	/* GPIO_CLEARDATAOUT */
+    case 0x94:	/* GPIO_SETDATAOUT */
+        value <<= (addr & 3) << 3;
+        omap2_gpio_module_write(opaque, addr, cur | value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap2_gpio_module_readfn[] = {
+    omap2_gpio_module_readp,
+    omap2_gpio_module_readp,
+    omap2_gpio_module_read,
+};
+
+static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = {
+    omap2_gpio_module_writep,
+    omap2_gpio_module_writep,
+    omap2_gpio_module_write,
+};
+
+static void omap2_gpio_module_init(struct omap2_gpio_s *s,
+                struct omap_target_agent_s *ta, int region,
+                qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+
+    s->irq[0] = mpu;
+    s->irq[1] = dsp;
+    s->wkup = wkup;
+    s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
+
+    iomemtype = l4_register_io_memory(omap2_gpio_module_readfn,
+                    omap2_gpio_module_writefn, s);
+    omap_l4_attach(ta, region, iomemtype);
+}
+
+struct omap_gpif_s {
+    struct omap2_gpio_s module[5];
+    int modules;
+
+    int autoidle;
+    int gpo;
+};
+
+void omap_gpif_reset(struct omap_gpif_s *s)
+{
+    int i;
+
+    for (i = 0; i < s->modules; i ++)
+        omap2_gpio_module_reset(s->module + i);
+
+    s->autoidle = 0;
+    s->gpo = 0;
+}
+
+static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* IPGENERICOCPSPL_REVISION */
+        return 0x18;
+
+    case 0x10:	/* IPGENERICOCPSPL_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14:	/* IPGENERICOCPSPL_SYSSTATUS */
+        return 0x01;
+
+    case 0x18:	/* IPGENERICOCPSPL_IRQSTATUS */
+        return 0x00;
+
+    case 0x40:	/* IPGENERICOCPSPL_GPO */
+        return s->gpo;
+
+    case 0x50:	/* IPGENERICOCPSPL_GPI */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* IPGENERICOCPSPL_REVISION */
+    case 0x14:	/* IPGENERICOCPSPL_SYSSTATUS */
+    case 0x18:	/* IPGENERICOCPSPL_IRQSTATUS */
+    case 0x50:	/* IPGENERICOCPSPL_GPI */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* IPGENERICOCPSPL_SYSCONFIG */
+        if (value & (1 << 1))					/* SOFTRESET */
+            omap_gpif_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40:	/* IPGENERICOCPSPL_GPO */
+        s->gpo = value & 1;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = {
+    omap_gpif_top_read,
+    omap_gpif_top_read,
+    omap_gpif_top_read,
+};
+
+static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = {
+    omap_gpif_top_write,
+    omap_gpif_top_write,
+    omap_gpif_top_write,
+};
+
+struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+{
+    int iomemtype, i;
+    struct omap_gpif_s *s = (struct omap_gpif_s *)
+            qemu_mallocz(sizeof(struct omap_gpif_s));
+    int region[4] = { 0, 2, 4, 5 };
+
+    s->modules = modules;
+    for (i = 0; i < modules; i ++)
+        omap2_gpio_module_init(s->module + i, ta, region[i],
+                              irq[i], NULL, NULL, fclk[i], iclk);
+
+    omap_gpif_reset(s);
+
+    iomemtype = l4_register_io_memory(omap_gpif_top_readfn,
+                    omap_gpif_top_writefn, s);
+    omap_l4_attach(ta, 1, iomemtype);
+
+    return s;
+}
+
+qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+{
+    if (start >= s->modules * 32 || start < 0)
+        hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
+    return s->module[start >> 5].in + (start & 31);
+}
+
+void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
+{
+    if (line >= s->modules * 32 || line < 0)
+        hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
+    s->module[line >> 5].handler[line & 31] = handler;
+}
diff --git a/qemu-0.15.x/hw/omap_gpmc.c b/qemu-0.15.x/hw/omap_gpmc.c
new file mode 100644
index 0000000..8bf3343
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_gpmc.c
@@ -0,0 +1,419 @@
+/*
+ * TI OMAP general purpose memory controller emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ * Original code written by Andrzej Zaborowski <andrew at openedhand.com>
+ * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "flash.h"
+#include "omap.h"
+
+/* General-Purpose Memory Controller */
+struct omap_gpmc_s {
+    qemu_irq irq;
+
+    uint8_t sysconfig;
+    uint16_t irqst;
+    uint16_t irqen;
+    uint16_t timeout;
+    uint16_t config;
+    uint32_t prefconfig[2];
+    int prefcontrol;
+    int preffifo;
+    int prefcount;
+    struct omap_gpmc_cs_file_s {
+        uint32_t config[7];
+        target_phys_addr_t base;
+        size_t size;
+        int iomemtype;
+        void (*base_update)(void *opaque, target_phys_addr_t new);
+        void (*unmap)(void *opaque);
+        void *opaque;
+    } cs_file[8];
+    int ecc_cs;
+    int ecc_ptr;
+    uint32_t ecc_cfg;
+    ECCState ecc[9];
+};
+
+static void omap_gpmc_int_update(struct omap_gpmc_s *s)
+{
+    qemu_set_irq(s->irq, s->irqen & s->irqst);
+}
+
+static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask)
+{
+    /* TODO: check for overlapping regions and report access errors */
+    if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) ||
+                    (base < 0 || base >= 0x40) ||
+                    (base & 0x0f & ~mask)) {
+        fprintf(stderr, "%s: wrong cs address mapping/decoding!\n",
+                        __FUNCTION__);
+        return;
+    }
+
+    if (!f->opaque)
+        return;
+
+    f->base = base << 24;
+    f->size = (0x0fffffff & ~(mask << 24)) + 1;
+    /* TODO: rather than setting the size of the mapping (which should be
+     * constant), the mask should cause wrapping of the address space, so
+     * that the same memory becomes accessible at every <i>size</i> bytes
+     * starting from <i>base</i>.  */
+    if (f->iomemtype)
+        cpu_register_physical_memory(f->base, f->size, f->iomemtype);
+
+    if (f->base_update)
+        f->base_update(f->opaque, f->base);
+}
+
+static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f)
+{
+    if (f->size) {
+        if (f->unmap)
+            f->unmap(f->opaque);
+        if (f->iomemtype)
+            cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED);
+        f->base = 0;
+        f->size = 0;
+    }
+}
+
+void omap_gpmc_reset(struct omap_gpmc_s *s)
+{
+    int i;
+
+    s->sysconfig = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    omap_gpmc_int_update(s);
+    s->timeout = 0;
+    s->config = 0xa00;
+    s->prefconfig[0] = 0x00004000;
+    s->prefconfig[1] = 0x00000000;
+    s->prefcontrol = 0;
+    s->preffifo = 0;
+    s->prefcount = 0;
+    for (i = 0; i < 8; i ++) {
+        if (s->cs_file[i].config[6] & (1 << 6))			/* CSVALID */
+            omap_gpmc_cs_unmap(s->cs_file + i);
+        s->cs_file[i].config[0] = i ? 1 << 12 : 0;
+        s->cs_file[i].config[1] = 0x101001;
+        s->cs_file[i].config[2] = 0x020201;
+        s->cs_file[i].config[3] = 0x10031003;
+        s->cs_file[i].config[4] = 0x10f1111;
+        s->cs_file[i].config[5] = 0;
+        s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
+        if (s->cs_file[i].config[6] & (1 << 6))			/* CSVALID */
+            omap_gpmc_cs_map(&s->cs_file[i],
+                            s->cs_file[i].config[6] & 0x1f,	/* MASKADDR */
+                        (s->cs_file[i].config[6] >> 8 & 0xf));	/* BASEADDR */
+    }
+    omap_gpmc_cs_map(s->cs_file, 0, 0xf);
+    s->ecc_cs = 0;
+    s->ecc_ptr = 0;
+    s->ecc_cfg = 0x3fcff000;
+    for (i = 0; i < 9; i ++)
+        ecc_reset(&s->ecc[i]);
+}
+
+static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    switch (addr) {
+    case 0x000:	/* GPMC_REVISION */
+        return 0x20;
+
+    case 0x010:	/* GPMC_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x014:	/* GPMC_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x018:	/* GPMC_IRQSTATUS */
+        return s->irqst;
+
+    case 0x01c:	/* GPMC_IRQENABLE */
+        return s->irqen;
+
+    case 0x040:	/* GPMC_TIMEOUT_CONTROL */
+        return s->timeout;
+
+    case 0x044:	/* GPMC_ERR_ADDRESS */
+    case 0x048:	/* GPMC_ERR_TYPE */
+        return 0;
+
+    case 0x050:	/* GPMC_CONFIG */
+        return s->config;
+
+    case 0x054:	/* GPMC_STATUS */
+        return 0x001;
+
+    case 0x060 ... 0x1d4:
+        cs = (addr - 0x060) / 0x30;
+        addr -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (addr) {
+            case 0x60:	/* GPMC_CONFIG1 */
+                return f->config[0];
+            case 0x64:	/* GPMC_CONFIG2 */
+                return f->config[1];
+            case 0x68:	/* GPMC_CONFIG3 */
+                return f->config[2];
+            case 0x6c:	/* GPMC_CONFIG4 */
+                return f->config[3];
+            case 0x70:	/* GPMC_CONFIG5 */
+                return f->config[4];
+            case 0x74:	/* GPMC_CONFIG6 */
+                return f->config[5];
+            case 0x78:	/* GPMC_CONFIG7 */
+                return f->config[6];
+            case 0x84:	/* GPMC_NAND_DATA */
+                return 0;
+        }
+        break;
+
+    case 0x1e0:	/* GPMC_PREFETCH_CONFIG1 */
+        return s->prefconfig[0];
+    case 0x1e4:	/* GPMC_PREFETCH_CONFIG2 */
+        return s->prefconfig[1];
+    case 0x1ec:	/* GPMC_PREFETCH_CONTROL */
+        return s->prefcontrol;
+    case 0x1f0:	/* GPMC_PREFETCH_STATUS */
+        return (s->preffifo << 24) |
+                ((s->preffifo >
+                  ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) |
+                s->prefcount;
+
+    case 0x1f4:	/* GPMC_ECC_CONFIG */
+        return s->ecc_cs;
+    case 0x1f8:	/* GPMC_ECC_CONTROL */
+        return s->ecc_ptr;
+    case 0x1fc:	/* GPMC_ECC_SIZE_CONFIG */
+        return s->ecc_cfg;
+    case 0x200 ... 0x220:	/* GPMC_ECC_RESULT */
+        cs = (addr & 0x1f) >> 2;
+        /* TODO: check correctness */
+        return
+                ((s->ecc[cs].cp    &  0x07) <<  0) |
+                ((s->ecc[cs].cp    &  0x38) << 13) |
+                ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
+                ((s->ecc[cs].lp[1] & 0x1ff) << 19);
+
+    case 0x230:	/* GPMC_TESTMODE_CTRL */
+        return 0;
+    case 0x234:	/* GPMC_PSA_LSB */
+    case 0x238:	/* GPMC_PSA_MSB */
+        return 0x00000000;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    switch (addr) {
+    case 0x000:	/* GPMC_REVISION */
+    case 0x014:	/* GPMC_SYSSTATUS */
+    case 0x054:	/* GPMC_STATUS */
+    case 0x1f0:	/* GPMC_PREFETCH_STATUS */
+    case 0x200 ... 0x220:	/* GPMC_ECC_RESULT */
+    case 0x234:	/* GPMC_PSA_LSB */
+    case 0x238:	/* GPMC_PSA_MSB */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x010:	/* GPMC_SYSCONFIG */
+        if ((value >> 3) == 0x3)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+                            __FUNCTION__, value >> 3);
+        if (value & 2)
+            omap_gpmc_reset(s);
+        s->sysconfig = value & 0x19;
+        break;
+
+    case 0x018:	/* GPMC_IRQSTATUS */
+        s->irqen = ~value;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x01c:	/* GPMC_IRQENABLE */
+        s->irqen = value & 0xf03;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x040:	/* GPMC_TIMEOUT_CONTROL */
+        s->timeout = value & 0x1ff1;
+        break;
+
+    case 0x044:	/* GPMC_ERR_ADDRESS */
+    case 0x048:	/* GPMC_ERR_TYPE */
+        break;
+
+    case 0x050:	/* GPMC_CONFIG */
+        s->config = value & 0xf13;
+        break;
+
+    case 0x060 ... 0x1d4:
+        cs = (addr - 0x060) / 0x30;
+        addr -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (addr) {
+            case 0x60:	/* GPMC_CONFIG1 */
+                f->config[0] = value & 0xffef3e13;
+                break;
+            case 0x64:	/* GPMC_CONFIG2 */
+                f->config[1] = value & 0x001f1f8f;
+                break;
+            case 0x68:	/* GPMC_CONFIG3 */
+                f->config[2] = value & 0x001f1f8f;
+                break;
+            case 0x6c:	/* GPMC_CONFIG4 */
+                f->config[3] = value & 0x1f8f1f8f;
+                break;
+            case 0x70:	/* GPMC_CONFIG5 */
+                f->config[4] = value & 0x0f1f1f1f;
+                break;
+            case 0x74:	/* GPMC_CONFIG6 */
+                f->config[5] = value & 0x00000fcf;
+                break;
+            case 0x78:	/* GPMC_CONFIG7 */
+                if ((f->config[6] ^ value) & 0xf7f) {
+                    if (f->config[6] & (1 << 6))		/* CSVALID */
+                        omap_gpmc_cs_unmap(f);
+                    if (value & (1 << 6))			/* CSVALID */
+                        omap_gpmc_cs_map(f, value & 0x1f,	/* MASKADDR */
+                                        (value >> 8 & 0xf));	/* BASEADDR */
+                }
+                f->config[6] = value & 0x00000f7f;
+                break;
+            case 0x7c:	/* GPMC_NAND_COMMAND */
+            case 0x80:	/* GPMC_NAND_ADDRESS */
+            case 0x84:	/* GPMC_NAND_DATA */
+                break;
+
+            default:
+                goto bad_reg;
+        }
+        break;
+
+    case 0x1e0:	/* GPMC_PREFETCH_CONFIG1 */
+        s->prefconfig[0] = value & 0x7f8f7fbf;
+        /* TODO: update interrupts, fifos, dmas */
+        break;
+
+    case 0x1e4:	/* GPMC_PREFETCH_CONFIG2 */
+        s->prefconfig[1] = value & 0x3fff;
+        break;
+
+    case 0x1ec:	/* GPMC_PREFETCH_CONTROL */
+        s->prefcontrol = value & 1;
+        if (s->prefcontrol) {
+            if (s->prefconfig[0] & 1)
+                s->preffifo = 0x40;
+            else
+                s->preffifo = 0x00;
+        }
+        /* TODO: start */
+        break;
+
+    case 0x1f4:	/* GPMC_ECC_CONFIG */
+        s->ecc_cs = 0x8f;
+        break;
+    case 0x1f8:	/* GPMC_ECC_CONTROL */
+        if (value & (1 << 8))
+            for (cs = 0; cs < 9; cs ++)
+                ecc_reset(&s->ecc[cs]);
+        s->ecc_ptr = value & 0xf;
+        if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
+            s->ecc_ptr = 0;
+            s->ecc_cs &= ~1;
+        }
+        break;
+    case 0x1fc:	/* GPMC_ECC_SIZE_CONFIG */
+        s->ecc_cfg = value & 0x3fcff1ff;
+        break;
+    case 0x230:	/* GPMC_TESTMODE_CTRL */
+        if (value & 7)
+            fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
+        break;
+
+    default:
+    bad_reg:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_gpmc_readfn[] = {
+    omap_badwidth_read32,	/* TODO */
+    omap_badwidth_read32,	/* TODO */
+    omap_gpmc_read,
+};
+
+static CPUWriteMemoryFunc * const omap_gpmc_writefn[] = {
+    omap_badwidth_write32,	/* TODO */
+    omap_badwidth_write32,	/* TODO */
+    omap_gpmc_write,
+};
+
+struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
+{
+    int iomemtype;
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *)
+            qemu_mallocz(sizeof(struct omap_gpmc_s));
+
+    omap_gpmc_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_gpmc_readfn,
+                    omap_gpmc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x1000, iomemtype);
+
+    return s;
+}
+
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
+                void (*base_upd)(void *opaque, target_phys_addr_t new),
+                void (*unmap)(void *opaque), void *opaque)
+{
+    struct omap_gpmc_cs_file_s *f;
+
+    if (cs < 0 || cs >= 8) {
+        fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+    f = &s->cs_file[cs];
+
+    f->iomemtype = iomemtype;
+    f->base_update = base_upd;
+    f->unmap = unmap;
+    f->opaque = opaque;
+
+    if (f->config[6] & (1 << 6))				/* CSVALID */
+        omap_gpmc_cs_map(f, f->config[6] & 0x1f,		/* MASKADDR */
+                        (f->config[6] >> 8 & 0xf));		/* BASEADDR */
+}
diff --git a/qemu-0.15.x/hw/omap_gptimer.c b/qemu-0.15.x/hw/omap_gptimer.c
new file mode 100644
index 0000000..f2a424f
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_gptimer.c
@@ -0,0 +1,484 @@
+/*
+ * TI OMAP2 general purpose timers emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "omap.h"
+
+/* GP timers */
+struct omap_gp_timer_s {
+    qemu_irq irq;
+    qemu_irq wkup;
+    qemu_irq in;
+    qemu_irq out;
+    omap_clk clk;
+    QEMUTimer *timer;
+    QEMUTimer *match;
+    struct omap_target_agent_s *ta;
+
+    int in_val;
+    int out_val;
+    int64_t time;
+    int64_t rate;
+    int64_t ticks_per_sec;
+
+    int16_t config;
+    int status;
+    int it_ena;
+    int wu_ena;
+    int enable;
+    int inout;
+    int capt2;
+    int pt;
+    enum {
+        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
+    } trigger;
+    enum {
+        gpt_capture_none, gpt_capture_rising,
+        gpt_capture_falling, gpt_capture_both
+    } capture;
+    int scpwm;
+    int ce;
+    int pre;
+    int ptv;
+    int ar;
+    int st;
+    int posted;
+    uint32_t val;
+    uint32_t load_val;
+    uint32_t capture_val[2];
+    uint32_t match_val;
+    int capt_num;
+
+    uint16_t writeh;	/* LSB */
+    uint16_t readh;	/* MSB */
+};
+
+#define GPT_TCAR_IT	(1 << 2)
+#define GPT_OVF_IT	(1 << 1)
+#define GPT_MAT_IT	(1 << 0)
+
+static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
+{
+    if (timer->it_ena & it) {
+        if (!timer->status)
+            qemu_irq_raise(timer->irq);
+
+        timer->status |= it;
+        /* Or are the status bits set even when masked?
+         * i.e. is masking applied before or after the status register?  */
+    }
+
+    if (timer->wu_ena & it)
+        qemu_irq_pulse(timer->wkup);
+}
+
+static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
+{
+    if (!timer->inout && timer->out_val != level) {
+        timer->out_val = level;
+        qemu_set_irq(timer->out, level);
+    }
+}
+
+static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
+{
+    uint64_t distance;
+
+    if (timer->st && timer->rate) {
+        distance = qemu_get_clock_ns(vm_clock) - timer->time;
+        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
+
+        if (distance >= 0xffffffff - timer->val)
+            return 0xffffffff;
+        else
+            return timer->val + distance;
+    } else
+        return timer->val;
+}
+
+static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
+{
+    if (timer->st) {
+        timer->val = omap_gp_timer_read(timer);
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+}
+
+static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
+{
+    int64_t expires, matches;
+
+    if (timer->st && timer->rate) {
+        expires = muldiv64(0x100000000ll - timer->val,
+                        timer->ticks_per_sec, timer->rate);
+        qemu_mod_timer(timer->timer, timer->time + expires);
+
+        if (timer->ce && timer->match_val >= timer->val) {
+            matches = muldiv64(timer->match_val - timer->val,
+                            timer->ticks_per_sec, timer->rate);
+            qemu_mod_timer(timer->match, timer->time + matches);
+        } else
+            qemu_del_timer(timer->match);
+    } else {
+        qemu_del_timer(timer->timer);
+        qemu_del_timer(timer->match);
+        omap_gp_timer_out(timer, timer->scpwm);
+    }
+}
+
+static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
+{
+    if (timer->pt)
+        /* TODO in overflow-and-match mode if the first event to
+         * occur is the match, don't toggle.  */
+        omap_gp_timer_out(timer, !timer->out_val);
+    else
+        /* TODO inverted pulse on timer->out_val == 1?  */
+        qemu_irq_pulse(timer->out);
+}
+
+static void omap_gp_timer_tick(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (!timer->ar) {
+        timer->st = 0;
+        timer->val = 0;
+    } else {
+        timer->val = timer->load_val;
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+
+    if (timer->trigger == gpt_trigger_overflow ||
+                    timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_OVF_IT);
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_match(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_MAT_IT);
+}
+
+static void omap_gp_timer_input(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int trigger;
+
+    switch (s->capture) {
+    default:
+    case gpt_capture_none:
+        trigger = 0;
+        break;
+    case gpt_capture_rising:
+        trigger = !s->in_val && on;
+        break;
+    case gpt_capture_falling:
+        trigger = s->in_val && !on;
+        break;
+    case gpt_capture_both:
+        trigger = (s->in_val == !on);
+        break;
+    }
+    s->in_val = on;
+
+    if (s->inout && trigger && s->capt_num < 2) {
+        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
+
+        if (s->capt2 == s->capt_num ++)
+            omap_gp_timer_intr(s, GPT_TCAR_IT);
+    }
+}
+
+static void omap_gp_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    omap_gp_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+void omap_gp_timer_reset(struct omap_gp_timer_s *s)
+{
+    s->config = 0x000;
+    s->status = 0;
+    s->it_ena = 0;
+    s->wu_ena = 0;
+    s->inout = 0;
+    s->capt2 = 0;
+    s->capt_num = 0;
+    s->pt = 0;
+    s->trigger = gpt_trigger_none;
+    s->capture = gpt_capture_none;
+    s->scpwm = 0;
+    s->ce = 0;
+    s->pre = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->posted = 1;
+    s->val = 0x00000000;
+    s->load_val = 0x00000000;
+    s->capture_val[0] = 0x00000000;
+    s->capture_val[1] = 0x00000000;
+    s->match_val = 0x00000000;
+    omap_gp_timer_update(s);
+}
+
+static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* TIDR */
+        return 0x21;
+
+    case 0x10:	/* TIOCP_CFG */
+        return s->config;
+
+    case 0x14:	/* TISTAT */
+        /* ??? When's this bit reset? */
+        return 1;						/* RESETDONE */
+
+    case 0x18:	/* TISR */
+        return s->status;
+
+    case 0x1c:	/* TIER */
+        return s->it_ena;
+
+    case 0x20:	/* TWER */
+        return s->wu_ena;
+
+    case 0x24:	/* TCLR */
+        return (s->inout << 14) |
+                (s->capt2 << 13) |
+                (s->pt << 12) |
+                (s->trigger << 10) |
+                (s->capture << 8) |
+                (s->scpwm << 7) |
+                (s->ce << 6) |
+                (s->pre << 5) |
+                (s->ptv << 2) |
+                (s->ar << 1) |
+                (s->st << 0);
+
+    case 0x28:	/* TCRR */
+        return omap_gp_timer_read(s);
+
+    case 0x2c:	/* TLDR */
+        return s->load_val;
+
+    case 0x30:	/* TTGR */
+        return 0xffffffff;
+
+    case 0x34:	/* TWPS */
+        return 0x00000000;	/* No posted writes pending.  */
+
+    case 0x38:	/* TMAR */
+        return s->match_val;
+
+    case 0x3c:	/* TCAR1 */
+        return s->capture_val[0];
+
+    case 0x40:	/* TSICR */
+        return s->posted << 2;
+
+    case 0x44:	/* TCAR2 */
+        return s->capture_val[1];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_gp_timer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_gp_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_gp_timer_readh,
+    omap_gp_timer_readw,
+};
+
+static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* TIDR */
+    case 0x14:	/* TISTAT */
+    case 0x34:	/* TWPS */
+    case 0x3c:	/* TCAR1 */
+    case 0x44:	/* TCAR2 */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* TIOCP_CFG */
+        s->config = value & 0x33d;
+        if (((value >> 3) & 3) == 3)				/* IDLEMODE */
+            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
+                            __FUNCTION__);
+        if (value & 2)						/* SOFTRESET */
+            omap_gp_timer_reset(s);
+        break;
+
+    case 0x18:	/* TISR */
+        if (value & GPT_TCAR_IT)
+            s->capt_num = 0;
+        if (s->status && !(s->status &= ~value))
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x1c:	/* TIER */
+        s->it_ena = value & 7;
+        break;
+
+    case 0x20:	/* TWER */
+        s->wu_ena = value & 7;
+        break;
+
+    case 0x24:	/* TCLR */
+        omap_gp_timer_sync(s);
+        s->inout = (value >> 14) & 1;
+        s->capt2 = (value >> 13) & 1;
+        s->pt = (value >> 12) & 1;
+        s->trigger = (value >> 10) & 3;
+        if (s->capture == gpt_capture_none &&
+                        ((value >> 8) & 3) != gpt_capture_none)
+            s->capt_num = 0;
+        s->capture = (value >> 8) & 3;
+        s->scpwm = (value >> 7) & 1;
+        s->ce = (value >> 6) & 1;
+        s->pre = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = (value >> 0) & 1;
+        if (s->inout && s->trigger != gpt_trigger_none)
+            fprintf(stderr, "%s: GP timer pin must be an output "
+                            "for this trigger mode\n", __FUNCTION__);
+        if (!s->inout && s->capture != gpt_capture_none)
+            fprintf(stderr, "%s: GP timer pin must be an input "
+                            "for this capture mode\n", __FUNCTION__);
+        if (s->trigger == gpt_trigger_none)
+            omap_gp_timer_out(s, s->scpwm);
+        /* TODO: make sure this doesn't overflow 32-bits */
+        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x28:	/* TCRR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x2c:	/* TLDR */
+        s->load_val = value;
+        break;
+
+    case 0x30:	/* TTGR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = s->load_val;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x38:	/* TMAR */
+        omap_gp_timer_sync(s);
+        s->match_val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x40:	/* TSICR */
+        s->posted = (value >> 2) & 1;
+        if (value & 2)	/* How much exactly are we supposed to reset? */
+            omap_gp_timer_reset(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    if (addr & 2)
+        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
+    else
+        s->writeh = (uint16_t) value;
+}
+
+static CPUWriteMemoryFunc * const omap_gp_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_gp_timer_writeh,
+    omap_gp_timer_write,
+};
+
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
+            qemu_mallocz(sizeof(struct omap_gp_timer_s));
+
+    s->ta = ta;
+    s->irq = irq;
+    s->clk = fclk;
+    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
+    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
+    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
+    omap_gp_timer_reset(s);
+    omap_gp_timer_clk_setup(s);
+
+    iomemtype = l4_register_io_memory(omap_gp_timer_readfn,
+                    omap_gp_timer_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_i2c.c b/qemu-0.15.x/hw/omap_i2c.c
new file mode 100644
index 0000000..5cabb5a
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_i2c.c
@@ -0,0 +1,470 @@
+/*
+ * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
+ *
+ * Copyright (C) 2007 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "i2c.h"
+#include "omap.h"
+
+struct omap_i2c_s {
+    qemu_irq irq;
+    qemu_irq drq[2];
+    i2c_bus *bus;
+
+    uint8_t revision;
+    uint8_t mask;
+    uint16_t stat;
+    uint16_t dma;
+    uint16_t count;
+    int count_cur;
+    uint32_t fifo;
+    int rxlen;
+    int txlen;
+    uint16_t control;
+    uint16_t addr[2];
+    uint8_t divider;
+    uint8_t times[2];
+    uint16_t test;
+};
+
+#define OMAP2_INTR_REV	0x34
+#define OMAP2_GC_REV	0x34
+
+static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
+{
+    qemu_set_irq(s->irq, s->stat & s->mask);
+    if ((s->dma >> 15) & 1)					/* RDMA_EN */
+        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);		/* RRDY */
+    if ((s->dma >> 7) & 1)					/* XDMA_EN */
+        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);		/* XRDY */
+}
+
+static void omap_i2c_fifo_run(struct omap_i2c_s *s)
+{
+    int ack = 1;
+
+    if (!i2c_bus_busy(s->bus))
+        return;
+
+    if ((s->control >> 2) & 1) {				/* RM */
+        if ((s->control >> 1) & 1) {				/* STP */
+            i2c_end_transfer(s->bus);
+            s->control &= ~(1 << 1);				/* STP */
+            s->count_cur = s->count;
+            s->txlen = 0;
+        } else if ((s->control >> 9) & 1) {			/* TRX */
+            while (ack && s->txlen)
+                ack = (i2c_send(s->bus,
+                                        (s->fifo >> ((-- s->txlen) << 3)) &
+                                        0xff) >= 0);
+            s->stat |= 1 << 4;					/* XRDY */
+        } else {
+            while (s->rxlen < 4)
+                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
+            s->stat |= 1 << 3;					/* RRDY */
+        }
+    } else {
+        if ((s->control >> 9) & 1) {				/* TRX */
+            while (ack && s->count_cur && s->txlen) {
+                ack = (i2c_send(s->bus,
+                                        (s->fifo >> ((-- s->txlen) << 3)) &
+                                        0xff) >= 0);
+                s->count_cur --;
+            }
+            if (ack && s->count_cur)
+                s->stat |= 1 << 4;				/* XRDY */
+            else
+                s->stat &= ~(1 << 4);				/* XRDY */
+            if (!s->count_cur) {
+                s->stat |= 1 << 2;				/* ARDY */
+                s->control &= ~(1 << 10);			/* MST */
+            }
+        } else {
+            while (s->count_cur && s->rxlen < 4) {
+                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
+                s->count_cur --;
+            }
+            if (s->rxlen)
+                s->stat |= 1 << 3;				/* RRDY */
+            else
+                s->stat &= ~(1 << 3);				/* RRDY */
+        }
+        if (!s->count_cur) {
+            if ((s->control >> 1) & 1) {			/* STP */
+                i2c_end_transfer(s->bus);
+                s->control &= ~(1 << 1);			/* STP */
+                s->count_cur = s->count;
+                s->txlen = 0;
+            } else {
+                s->stat |= 1 << 2;				/* ARDY */
+                s->control &= ~(1 << 10);			/* MST */
+            }
+        }
+    }
+
+    s->stat |= (!ack) << 1;					/* NACK */
+    if (!ack)
+        s->control &= ~(1 << 1);				/* STP */
+}
+
+void omap_i2c_reset(struct omap_i2c_s *s)
+{
+    s->mask = 0;
+    s->stat = 0;
+    s->dma = 0;
+    s->count = 0;
+    s->count_cur = 0;
+    s->fifo = 0;
+    s->rxlen = 0;
+    s->txlen = 0;
+    s->control = 0;
+    s->addr[0] = 0;
+    s->addr[1] = 0;
+    s->divider = 0;
+    s->times[0] = 0;
+    s->times[1] = 0;
+    s->test = 0;
+}
+
+static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x00:	/* I2C_REV */
+        return s->revision;					/* REV */
+
+    case 0x04:	/* I2C_IE */
+        return s->mask;
+
+    case 0x08:	/* I2C_STAT */
+        return s->stat | (i2c_bus_busy(s->bus) << 12);
+
+    case 0x0c:	/* I2C_IV */
+        if (s->revision >= OMAP2_INTR_REV)
+            break;
+        ret = ffs(s->stat & s->mask);
+        if (ret)
+            s->stat ^= 1 << (ret - 1);
+        omap_i2c_interrupts_update(s);
+        return ret;
+
+    case 0x10:	/* I2C_SYSS */
+        return (s->control >> 15) & 1;				/* I2C_EN */
+
+    case 0x14:	/* I2C_BUF */
+        return s->dma;
+
+    case 0x18:	/* I2C_CNT */
+        return s->count_cur;					/* DCOUNT */
+
+    case 0x1c:	/* I2C_DATA */
+        ret = 0;
+        if (s->control & (1 << 14)) {				/* BE */
+            ret |= ((s->fifo >> 0) & 0xff) << 8;
+            ret |= ((s->fifo >> 8) & 0xff) << 0;
+        } else {
+            ret |= ((s->fifo >> 8) & 0xff) << 8;
+            ret |= ((s->fifo >> 0) & 0xff) << 0;
+        }
+        if (s->rxlen == 1) {
+            s->stat |= 1 << 15;					/* SBD */
+            s->rxlen = 0;
+        } else if (s->rxlen > 1) {
+            if (s->rxlen > 2)
+                s->fifo >>= 16;
+            s->rxlen -= 2;
+        } else {
+            /* XXX: remote access (qualifier) error - what's that?  */
+        }
+        if (!s->rxlen) {
+            s->stat &= ~(1 << 3);				/* RRDY */
+            if (((s->control >> 10) & 1) &&			/* MST */
+                            ((~s->control >> 9) & 1)) {		/* TRX */
+                s->stat |= 1 << 2;				/* ARDY */
+                s->control &= ~(1 << 10);			/* MST */
+            }
+        }
+        s->stat &= ~(1 << 11);					/* ROVR */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        return ret;
+
+    case 0x20:	/* I2C_SYSC */
+        return 0;
+
+    case 0x24:	/* I2C_CON */
+        return s->control;
+
+    case 0x28:	/* I2C_OA */
+        return s->addr[0];
+
+    case 0x2c:	/* I2C_SA */
+        return s->addr[1];
+
+    case 0x30:	/* I2C_PSC */
+        return s->divider;
+
+    case 0x34:	/* I2C_SCLL */
+        return s->times[0];
+
+    case 0x38:	/* I2C_SCLH */
+        return s->times[1];
+
+    case 0x3c:	/* I2C_SYSTEST */
+        if (s->test & (1 << 15)) {				/* ST_EN */
+            s->test ^= 0xa;
+            return s->test;
+        } else
+            return s->test & ~0x300f;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    int nack;
+
+    switch (offset) {
+    case 0x00:	/* I2C_REV */
+    case 0x0c:	/* I2C_IV */
+    case 0x10:	/* I2C_SYSS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x04:	/* I2C_IE */
+        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
+        break;
+
+    case 0x08:	/* I2C_STAT */
+        if (s->revision < OMAP2_INTR_REV) {
+            OMAP_RO_REG(addr);
+            return;
+        }
+
+        /* RRDY and XRDY are reset by hardware. (in all versions???) */
+        s->stat &= ~(value & 0x27);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    case 0x14:	/* I2C_BUF */
+        s->dma = value & 0x8080;
+        if (value & (1 << 15))					/* RDMA_EN */
+            s->mask &= ~(1 << 3);				/* RRDY_IE */
+        if (value & (1 << 7))					/* XDMA_EN */
+            s->mask &= ~(1 << 4);				/* XRDY_IE */
+        break;
+
+    case 0x18:	/* I2C_CNT */
+        s->count = value;					/* DCOUNT */
+        break;
+
+    case 0x1c:	/* I2C_DATA */
+        if (s->txlen > 2) {
+            /* XXX: remote access (qualifier) error - what's that?  */
+            break;
+        }
+        s->fifo <<= 16;
+        s->txlen += 2;
+        if (s->control & (1 << 14)) {				/* BE */
+            s->fifo |= ((value >> 8) & 0xff) << 8;
+            s->fifo |= ((value >> 0) & 0xff) << 0;
+        } else {
+            s->fifo |= ((value >> 0) & 0xff) << 8;
+            s->fifo |= ((value >> 8) & 0xff) << 0;
+        }
+        s->stat &= ~(1 << 10);					/* XUDF */
+        if (s->txlen > 2)
+            s->stat &= ~(1 << 4);				/* XRDY */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    case 0x20:	/* I2C_SYSC */
+        if (s->revision < OMAP2_INTR_REV) {
+            OMAP_BAD_REG(addr);
+            return;
+        }
+
+        if (value & 2)
+            omap_i2c_reset(s);
+        break;
+
+    case 0x24:	/* I2C_CON */
+        s->control = value & 0xcf87;
+        if (~value & (1 << 15)) {				/* I2C_EN */
+            if (s->revision < OMAP2_INTR_REV)
+                omap_i2c_reset(s);
+            break;
+        }
+        if ((value & (1 << 15)) && !(value & (1 << 10))) {	/* MST */
+            fprintf(stderr, "%s: I^2C slave mode not supported\n",
+                            __FUNCTION__);
+            break;
+        }
+        if ((value & (1 << 15)) && value & (1 << 8)) {		/* XA */
+            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
+                            __FUNCTION__);
+            break;
+        }
+        if ((value & (1 << 15)) && value & (1 << 0)) {		/* STT */
+            nack = !!i2c_start_transfer(s->bus, s->addr[1],	/* SA */
+                            (~value >> 9) & 1);			/* TRX */
+            s->stat |= nack << 1;				/* NACK */
+            s->control &= ~(1 << 0);				/* STT */
+            s->fifo = 0;
+            if (nack)
+                s->control &= ~(1 << 1);			/* STP */
+            else {
+                s->count_cur = s->count;
+                omap_i2c_fifo_run(s);
+            }
+            omap_i2c_interrupts_update(s);
+        }
+        break;
+
+    case 0x28:	/* I2C_OA */
+        s->addr[0] = value & 0x3ff;
+        break;
+
+    case 0x2c:	/* I2C_SA */
+        s->addr[1] = value & 0x3ff;
+        break;
+
+    case 0x30:	/* I2C_PSC */
+        s->divider = value;
+        break;
+
+    case 0x34:	/* I2C_SCLL */
+        s->times[0] = value;
+        break;
+
+    case 0x38:	/* I2C_SCLH */
+        s->times[1] = value;
+        break;
+
+    case 0x3c:	/* I2C_SYSTEST */
+        s->test = value & 0xf80f;
+        if (value & (1 << 11))					/* SBB */
+            if (s->revision >= OMAP2_INTR_REV) {
+                s->stat |= 0x3f;
+                omap_i2c_interrupts_update(s);
+            }
+        if (value & (1 << 15))					/* ST_EN */
+            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x1c:	/* I2C_DATA */
+        if (s->txlen > 2) {
+            /* XXX: remote access (qualifier) error - what's that?  */
+            break;
+        }
+        s->fifo <<= 8;
+        s->txlen += 1;
+        s->fifo |= value & 0xff;
+        s->stat &= ~(1 << 10);					/* XUDF */
+        if (s->txlen > 2)
+            s->stat &= ~(1 << 4);				/* XRDY */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_i2c_readfn[] = {
+    omap_badwidth_read16,
+    omap_i2c_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_i2c_writefn[] = {
+    omap_i2c_writeb,	/* Only the last fifo write can be 8 bit.  */
+    omap_i2c_write,
+    omap_badwidth_write16,
+};
+
+struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq *dma, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_i2c_s *s = (struct omap_i2c_s *)
+            qemu_mallocz(sizeof(struct omap_i2c_s));
+
+    /* TODO: set a value greater or equal to real hardware */
+    s->revision = 0x11;
+    s->irq = irq;
+    s->drq[0] = dma[0];
+    s->drq[1] = dma[1];
+    s->bus = i2c_init_bus(NULL, "i2c");
+    omap_i2c_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_i2c_readfn,
+                    omap_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    return s;
+}
+
+struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_i2c_s *s = (struct omap_i2c_s *)
+            qemu_mallocz(sizeof(struct omap_i2c_s));
+
+    s->revision = 0x34;
+    s->irq = irq;
+    s->drq[0] = dma[0];
+    s->drq[1] = dma[1];
+    s->bus = i2c_init_bus(NULL, "i2c");
+    omap_i2c_reset(s);
+
+    iomemtype = l4_register_io_memory(omap_i2c_readfn,
+                    omap_i2c_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
+{
+    return s->bus;
+}
diff --git a/qemu-0.15.x/hw/omap_intc.c b/qemu-0.15.x/hw/omap_intc.c
new file mode 100644
index 0000000..001e20b
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_intc.c
@@ -0,0 +1,598 @@
+/*
+ * TI OMAP interrupt controller emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "omap.h"
+
+/* Interrupt Handlers */
+struct omap_intr_handler_bank_s {
+    uint32_t irqs;
+    uint32_t inputs;
+    uint32_t mask;
+    uint32_t fiq;
+    uint32_t sens_edge;
+    uint32_t swi;
+    unsigned char priority[32];
+};
+
+struct omap_intr_handler_s {
+    qemu_irq *pins;
+    qemu_irq parent_intr[2];
+    unsigned char nbanks;
+    int level_only;
+
+    /* state */
+    uint32_t new_agr[2];
+    int sir_intr[2];
+    int autoidle;
+    uint32_t mask;
+    struct omap_intr_handler_bank_s bank[];
+};
+
+inline qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n)
+{
+    return s->pins[n];
+}
+
+static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i, j, sir_intr, p_intr, p, f;
+    uint32_t level;
+    sir_intr = 0;
+    p_intr = 255;
+
+    /* Find the interrupt line with the highest dynamic priority.
+     * Note: 0 denotes the hightest priority.
+     * If all interrupts have the same priority, the default order is IRQ_N,
+     * IRQ_N-1,...,IRQ_0. */
+    for (j = 0; j < s->nbanks; ++j) {
+        level = s->bank[j].irqs & ~s->bank[j].mask &
+                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
+        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
+                        level >>= f) {
+            p = s->bank[j].priority[i];
+            if (p <= p_intr) {
+                p_intr = p;
+                sir_intr = 32 * j + i;
+            }
+            f = ffs(level >> 1);
+        }
+    }
+    s->sir_intr[is_fiq] = sir_intr;
+}
+
+static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i;
+    uint32_t has_intr = 0;
+
+    for (i = 0; i < s->nbanks; ++i)
+        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
+                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
+
+    if (s->new_agr[is_fiq] & has_intr & s->mask) {
+        s->new_agr[is_fiq] = 0;
+        omap_inth_sir_update(s, is_fiq);
+        qemu_set_irq(s->parent_intr[is_fiq], 1);
+    }
+}
+
+#define INT_FALLING_EDGE	0
+#define INT_LOW_LEVEL		1
+
+static void omap_set_intr(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->irqs & (1 << n);
+        if (~bank->sens_edge & (1 << n))
+            rise &= ~bank->inputs;
+
+        bank->inputs |= (1 << n);
+        if (rise) {
+            bank->irqs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else {
+        rise = bank->sens_edge & bank->irqs & (1 << n);
+        bank->irqs &= ~rise;
+        bank->inputs &= ~(1 << n);
+    }
+}
+
+/* Simplified version with no edge detection */
+static void omap_set_intr_noedge(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->inputs & (1 << n);
+        if (rise) {
+            bank->irqs |= bank->inputs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else
+        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
+}
+
+static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    int line_no;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00:	/* ITR */
+        return bank->irqs;
+
+    case 0x04:	/* MIR */
+        return bank->mask;
+
+    case 0x10:	/* SIR_IRQ_CODE */
+    case 0x14:  /* SIR_FIQ_CODE */
+        if (bank_no != 0)
+            break;
+        line_no = s->sir_intr[(offset - 0x10) >> 2];
+        bank = &s->bank[line_no >> 5];
+        i = line_no & 31;
+        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
+            bank->irqs &= ~(1 << i);
+        return line_no;
+
+    case 0x18:	/* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        return 0;
+
+    case 0x1c:	/* ILR0 */
+    case 0x20:	/* ILR1 */
+    case 0x24:	/* ILR2 */
+    case 0x28:	/* ILR3 */
+    case 0x2c:	/* ILR4 */
+    case 0x30:	/* ILR5 */
+    case 0x34:	/* ILR6 */
+    case 0x38:	/* ILR7 */
+    case 0x3c:	/* ILR8 */
+    case 0x40:	/* ILR9 */
+    case 0x44:	/* ILR10 */
+    case 0x48:	/* ILR11 */
+    case 0x4c:	/* ILR12 */
+    case 0x50:	/* ILR13 */
+    case 0x54:	/* ILR14 */
+    case 0x58:	/* ILR15 */
+    case 0x5c:	/* ILR16 */
+    case 0x60:	/* ILR17 */
+    case 0x64:	/* ILR18 */
+    case 0x68:	/* ILR19 */
+    case 0x6c:	/* ILR20 */
+    case 0x70:	/* ILR21 */
+    case 0x74:	/* ILR22 */
+    case 0x78:	/* ILR23 */
+    case 0x7c:	/* ILR24 */
+    case 0x80:	/* ILR25 */
+    case 0x84:	/* ILR26 */
+    case 0x88:	/* ILR27 */
+    case 0x8c:	/* ILR28 */
+    case 0x90:	/* ILR29 */
+    case 0x94:	/* ILR30 */
+    case 0x98:	/* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        return (bank->priority[i] << 2) |
+                (((bank->sens_edge >> i) & 1) << 1) |
+                ((bank->fiq >> i) & 1);
+
+    case 0x9c:	/* ISR */
+        return 0x00000000;
+
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_inth_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00:	/* ITR */
+        /* Important: ignore the clearing if the IRQ is level-triggered and
+           the input bit is 1 */
+        bank->irqs &= value | (bank->inputs & bank->sens_edge);
+        return;
+
+    case 0x04:	/* MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x10:	/* SIR_IRQ_CODE */
+    case 0x14:	/* SIR_FIQ_CODE */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x18:	/* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        if (value & 2) {
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x1c:	/* ILR0 */
+    case 0x20:	/* ILR1 */
+    case 0x24:	/* ILR2 */
+    case 0x28:	/* ILR3 */
+    case 0x2c:	/* ILR4 */
+    case 0x30:	/* ILR5 */
+    case 0x34:	/* ILR6 */
+    case 0x38:	/* ILR7 */
+    case 0x3c:	/* ILR8 */
+    case 0x40:	/* ILR9 */
+    case 0x44:	/* ILR10 */
+    case 0x48:	/* ILR11 */
+    case 0x4c:	/* ILR12 */
+    case 0x50:	/* ILR13 */
+    case 0x54:	/* ILR14 */
+    case 0x58:	/* ILR15 */
+    case 0x5c:	/* ILR16 */
+    case 0x60:	/* ILR17 */
+    case 0x64:	/* ILR18 */
+    case 0x68:	/* ILR19 */
+    case 0x6c:	/* ILR20 */
+    case 0x70:	/* ILR21 */
+    case 0x74:	/* ILR22 */
+    case 0x78:	/* ILR23 */
+    case 0x7c:	/* ILR24 */
+    case 0x80:	/* ILR25 */
+    case 0x84:	/* ILR26 */
+    case 0x88:	/* ILR27 */
+    case 0x8c:	/* ILR28 */
+    case 0x90:	/* ILR29 */
+    case 0x94:	/* ILR30 */
+    case 0x98:	/* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        bank->priority[i] = (value >> 2) & 0x1f;
+        bank->sens_edge &= ~(1 << i);
+        bank->sens_edge |= ((value >> 1) & 1) << i;
+        bank->fiq &= ~(1 << i);
+        bank->fiq |= (value & 1) << i;
+        return;
+
+    case 0x9c:	/* ISR */
+        for (i = 0; i < 32; i ++)
+            if (value & (1 << i)) {
+                omap_set_intr(s, 32 * bank_no + i, 1);
+                return;
+            }
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc * const omap_inth_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_inth_read,
+};
+
+static CPUWriteMemoryFunc * const omap_inth_writefn[] = {
+    omap_inth_write,
+    omap_inth_write,
+    omap_inth_write,
+};
+
+void omap_inth_reset(struct omap_intr_handler_s *s)
+{
+    int i;
+
+    for (i = 0; i < s->nbanks; ++i){
+        s->bank[i].irqs = 0x00000000;
+        s->bank[i].mask = 0xffffffff;
+        s->bank[i].sens_edge = 0x00000000;
+        s->bank[i].fiq = 0x00000000;
+        s->bank[i].inputs = 0x00000000;
+        s->bank[i].swi = 0x00000000;
+        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
+
+        if (s->level_only)
+            s->bank[i].sens_edge = 0xffffffff;
+    }
+
+    s->new_agr[0] = ~0;
+    s->new_agr[1] = ~0;
+    s->sir_intr[0] = 0;
+    s->sir_intr[1] = 0;
+    s->autoidle = 0;
+    s->mask = ~0;
+
+    qemu_set_irq(s->parent_intr[0], 0);
+    qemu_set_irq(s->parent_intr[1], 0);
+}
+
+struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
+                unsigned long size, unsigned char nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
+            qemu_mallocz(sizeof(struct omap_intr_handler_s) +
+                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
+
+    s->parent_intr[0] = parent_irq;
+    s->parent_intr[1] = parent_fiq;
+    s->nbanks = nbanks;
+    s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
+    if (pins)
+        *pins = s->pins;
+
+    omap_inth_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_inth_readfn,
+                    omap_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, size, iomemtype);
+
+    return s;
+}
+
+static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        }
+    }
+
+    switch (offset) {
+    case 0x00:	/* INTC_REVISION */
+        return 0x21;
+
+    case 0x10:	/* INTC_SYSCONFIG */
+        return (s->autoidle >> 2) & 1;
+
+    case 0x14:	/* INTC_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x40:	/* INTC_SIR_IRQ */
+        return s->sir_intr[0];
+
+    case 0x44:	/* INTC_SIR_FIQ */
+        return s->sir_intr[1];
+
+    case 0x48:	/* INTC_CONTROL */
+        return (!s->mask) << 2;					/* GLOBALMASK */
+
+    case 0x4c:	/* INTC_PROTECTION */
+        return 0;
+
+    case 0x50:	/* INTC_IDLE */
+        return s->autoidle & 3;
+
+    /* Per-bank registers */
+    case 0x80:	/* INTC_ITR */
+        return bank->inputs;
+
+    case 0x84:	/* INTC_MIR */
+        return bank->mask;
+
+    case 0x88:	/* INTC_MIR_CLEAR */
+    case 0x8c:	/* INTC_MIR_SET */
+        return 0;
+
+    case 0x90:	/* INTC_ISR_SET */
+        return bank->swi;
+
+    case 0x94:	/* INTC_ISR_CLEAR */
+        return 0;
+
+    case 0x98:	/* INTC_PENDING_IRQ */
+        return bank->irqs & ~bank->mask & ~bank->fiq;
+
+    case 0x9c:	/* INTC_PENDING_FIQ */
+        return bank->irqs & ~bank->mask & bank->fiq;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:	/* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        return (bank->priority[line_no] << 2) |
+                ((bank->fiq >> line_no) & 1);
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        }
+    }
+
+    switch (offset) {
+    case 0x10:	/* INTC_SYSCONFIG */
+        s->autoidle &= 4;
+        s->autoidle |= (value & 1) << 2;
+        if (value & 2)						/* SOFTRESET */
+            omap_inth_reset(s);
+        return;
+
+    case 0x48:	/* INTC_CONTROL */
+        s->mask = (value & 4) ? 0 : ~0;				/* GLOBALMASK */
+        if (value & 2) {					/* NEWFIQAGR */
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {					/* NEWIRQAGR */
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x4c:	/* INTC_PROTECTION */
+        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
+         * for every register, see Chapter 3 and 4 for privileged mode.  */
+        if (value & 1)
+            fprintf(stderr, "%s: protection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+
+    case 0x50:	/* INTC_IDLE */
+        s->autoidle &= ~3;
+        s->autoidle |= value & 3;
+        return;
+
+    /* Per-bank registers */
+    case 0x84:	/* INTC_MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x88:	/* INTC_MIR_CLEAR */
+        bank->mask &= ~value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x8c:	/* INTC_MIR_SET */
+        bank->mask |= value;
+        return;
+
+    case 0x90:	/* INTC_ISR_SET */
+        bank->irqs |= bank->swi |= value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x94:	/* INTC_ISR_CLEAR */
+        bank->swi &= ~value;
+        bank->irqs = bank->swi & bank->inputs;
+        return;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:	/* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        bank->priority[line_no] = (value >> 2) & 0x3f;
+        bank->fiq &= ~(1 << line_no);
+        bank->fiq |= (value & 1) << line_no;
+        return;
+
+    case 0x00:	/* INTC_REVISION */
+    case 0x14:	/* INTC_SYSSTATUS */
+    case 0x40:	/* INTC_SIR_IRQ */
+    case 0x44:	/* INTC_SIR_FIQ */
+    case 0x80:	/* INTC_ITR */
+    case 0x98:	/* INTC_PENDING_IRQ */
+    case 0x9c:	/* INTC_PENDING_FIQ */
+        OMAP_RO_REG(addr);
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc * const omap2_inth_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap2_inth_read,
+};
+
+static CPUWriteMemoryFunc * const omap2_inth_writefn[] = {
+    omap2_inth_write,
+    omap2_inth_write,
+    omap2_inth_write,
+};
+
+struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+                int size, int nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq,
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
+            qemu_mallocz(sizeof(struct omap_intr_handler_s) +
+                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
+
+    s->parent_intr[0] = parent_irq;
+    s->parent_intr[1] = parent_fiq;
+    s->nbanks = nbanks;
+    s->level_only = 1;
+    s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
+    if (pins)
+        *pins = s->pins;
+
+    omap_inth_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap2_inth_readfn,
+                    omap2_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, size, iomemtype);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_l4.c b/qemu-0.15.x/hw/omap_l4.c
new file mode 100644
index 0000000..4af0ca8
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_l4.c
@@ -0,0 +1,272 @@
+/*
+ * TI OMAP L4 interconnect emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "omap.h"
+
+#ifdef L4_MUX_HACK
+static int omap_l4_io_entries;
+static int omap_cpu_io_entry;
+static struct omap_l4_entry {
+        CPUReadMemoryFunc * const *mem_read;
+        CPUWriteMemoryFunc * const *mem_write;
+        void *opaque;
+} *omap_l4_io_entry;
+static CPUReadMemoryFunc * const *omap_l4_io_readb_fn;
+static CPUReadMemoryFunc * const *omap_l4_io_readh_fn;
+static CPUReadMemoryFunc * const *omap_l4_io_readw_fn;
+static CPUWriteMemoryFunc * const *omap_l4_io_writeb_fn;
+static CPUWriteMemoryFunc * const *omap_l4_io_writeh_fn;
+static CPUWriteMemoryFunc * const *omap_l4_io_writew_fn;
+static void **omap_l4_io_opaque;
+
+int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                CPUWriteMemoryFunc * const *mem_write, void *opaque)
+{
+    omap_l4_io_entry[omap_l4_io_entries].mem_read = mem_read;
+    omap_l4_io_entry[omap_l4_io_entries].mem_write = mem_write;
+    omap_l4_io_entry[omap_l4_io_entries].opaque = opaque;
+
+    return omap_l4_io_entries ++;
+}
+
+static uint32_t omap_l4_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_readb_fn[i](omap_l4_io_opaque[i], addr);
+}
+
+static uint32_t omap_l4_io_readh(void *opaque, target_phys_addr_t addr)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_readh_fn[i](omap_l4_io_opaque[i], addr);
+}
+
+static uint32_t omap_l4_io_readw(void *opaque, target_phys_addr_t addr)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_readw_fn[i](omap_l4_io_opaque[i], addr);
+}
+
+static void omap_l4_io_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_writeb_fn[i](omap_l4_io_opaque[i], addr, value);
+}
+
+static void omap_l4_io_writeh(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_writeh_fn[i](omap_l4_io_opaque[i], addr, value);
+}
+
+static void omap_l4_io_writew(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS;
+
+    return omap_l4_io_writew_fn[i](omap_l4_io_opaque[i], addr, value);
+}
+
+static CPUReadMemoryFunc * const omap_l4_io_readfn[] = {
+    omap_l4_io_readb,
+    omap_l4_io_readh,
+    omap_l4_io_readw,
+};
+
+static CPUWriteMemoryFunc * const omap_l4_io_writefn[] = {
+    omap_l4_io_writeb,
+    omap_l4_io_writeh,
+    omap_l4_io_writew,
+};
+#else
+int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                          CPUWriteMemoryFunc * const *mem_write,
+                          void *opaque)
+{
+    return cpu_register_io_memory(mem_read, mem_write, opaque,
+                                  DEVICE_NATIVE_ENDIAN);
+}
+#endif
+
+struct omap_l4_s {
+    target_phys_addr_t base;
+    int ta_num;
+    struct omap_target_agent_s ta[0];
+};
+
+struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
+{
+    struct omap_l4_s *bus = qemu_mallocz(
+                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
+
+    bus->ta_num = ta_num;
+    bus->base = base;
+
+#ifdef L4_MUX_HACK
+    omap_l4_io_entries = 1;
+    omap_l4_io_entry = qemu_mallocz(125 * sizeof(*omap_l4_io_entry));
+
+    omap_cpu_io_entry =
+            cpu_register_io_memory(omap_l4_io_readfn,
+                            omap_l4_io_writefn, bus, DEVICE_NATIVE_ENDIAN);
+# define L4_PAGES	(0xb4000 / TARGET_PAGE_SIZE)
+    omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_readh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_readw_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writeb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writeh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_writew_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
+    omap_l4_io_opaque = qemu_mallocz(sizeof(void *) * L4_PAGES);
+#endif
+
+    return bus;
+}
+
+static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* COMPONENT */
+        return s->component;
+
+    case 0x20:	/* AGENT_CONTROL */
+        return s->control;
+
+    case 0x28:	/* AGENT_STATUS */
+        return s->status;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_l4ta_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* COMPONENT */
+    case 0x28:	/* AGENT_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x20:	/* AGENT_CONTROL */
+        s->control = value & 0x01000700;
+        if (value & 1)					/* OCP_RESET */
+            s->status &= ~1;				/* REQ_TIMEOUT */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_l4ta_readfn[] = {
+    omap_badwidth_read16,
+    omap_l4ta_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_l4ta_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_l4ta_write,
+};
+
+struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
+        const struct omap_l4_region_s *regions,
+	const struct omap_l4_agent_info_s *agents,
+	int cs)
+{
+    int i, iomemtype;
+    struct omap_target_agent_s *ta = NULL;
+    const struct omap_l4_agent_info_s *info = NULL;
+
+    for (i = 0; i < bus->ta_num; i ++)
+        if (agents[i].ta == cs) {
+            ta = &bus->ta[i];
+            info = &agents[i];
+            break;
+        }
+    if (!ta) {
+        fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+
+    ta->bus = bus;
+    ta->start = &regions[info->region];
+    ta->regions = info->regions;
+
+    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    ta->status = 0x00000000;
+    ta->control = 0x00000200;	/* XXX 01000200 for L4TAO */
+
+    iomemtype = l4_register_io_memory(omap_l4ta_readfn,
+                    omap_l4ta_writefn, ta);
+    ta->base = omap_l4_attach(ta, info->ta_region, iomemtype);
+
+    return ta;
+}
+
+target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
+                int iotype)
+{
+    target_phys_addr_t base;
+    ssize_t size;
+#ifdef L4_MUX_HACK
+    int i;
+#endif
+
+    if (region < 0 || region >= ta->regions) {
+        fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
+        exit(-1);
+    }
+
+    base = ta->bus->base + ta->start[region].offset;
+    size = ta->start[region].size;
+    if (iotype) {
+#ifndef L4_MUX_HACK
+        cpu_register_physical_memory(base, size, iotype);
+#else
+        cpu_register_physical_memory(base, size, omap_cpu_io_entry);
+        i = (base - ta->bus->base) / TARGET_PAGE_SIZE;
+        for (; size > 0; size -= TARGET_PAGE_SIZE, i ++) {
+            omap_l4_io_readb_fn[i] = omap_l4_io_entry[iotype].mem_read[0];
+            omap_l4_io_readh_fn[i] = omap_l4_io_entry[iotype].mem_read[1];
+            omap_l4_io_readw_fn[i] = omap_l4_io_entry[iotype].mem_read[2];
+            omap_l4_io_writeb_fn[i] = omap_l4_io_entry[iotype].mem_write[0];
+            omap_l4_io_writeh_fn[i] = omap_l4_io_entry[iotype].mem_write[1];
+            omap_l4_io_writew_fn[i] = omap_l4_io_entry[iotype].mem_write[2];
+            omap_l4_io_opaque[i] = omap_l4_io_entry[iotype].opaque;
+        }
+#endif
+    }
+
+    return base;
+}
diff --git a/qemu-0.15.x/hw/omap_lcd_template.h b/qemu-0.15.x/hw/omap_lcd_template.h
new file mode 100644
index 0000000..2fb96f8
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_lcd_template.h
@@ -0,0 +1,175 @@
+/*
+ * QEMU OMAP LCD Emulator templates
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * 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.
+ */
+
+#if DEPTH == 8
+# define BPP 1
+# define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+# define BPP 2
+# define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+# define BPP 4
+# define PIXEL_TYPE uint32_t
+#else
+# error unsupport depth
+#endif
+
+/*
+ * 2-bit colour
+ */
+static void glue(draw_line2_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 4;
+    } while (width > 0);
+}
+
+/*
+ * 4-bit colour
+ */
+static void glue(draw_line4_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 4;
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 2;
+    } while (width > 0);
+}
+
+/*
+ * 8-bit colour
+ */
+static void glue(draw_line8_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v] >> 4) & 0xf0;
+        g = pal[v] & 0xf0;
+        b = (pal[v] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s ++;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 12-bit colour
+ */
+static void glue(draw_line12_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 4) & 0xf0;
+        g = v & 0xf0;
+        b = (v << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 16-bit colour
+ */
+static void glue(draw_line16_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+#endif
+}
+
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
diff --git a/qemu-0.15.x/hw/omap_lcdc.c b/qemu-0.15.x/hw/omap_lcdc.c
new file mode 100644
index 0000000..0c2c550
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_lcdc.c
@@ -0,0 +1,461 @@
+/*
+ * OMAP LCD controller.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "console.h"
+#include "omap.h"
+#include "framebuffer.h"
+
+struct omap_lcd_panel_s {
+    qemu_irq irq;
+    DisplayState *state;
+    ram_addr_t imif_base;
+    ram_addr_t emiff_base;
+
+    int plm;
+    int tft;
+    int mono;
+    int enable;
+    int width;
+    int height;
+    int interrupts;
+    uint32_t timing[3];
+    uint32_t subpanel;
+    uint32_t ctrl;
+
+    struct omap_dma_lcd_channel_s *dma;
+    uint16_t palette[256];
+    int palette_done;
+    int frame_done;
+    int invalidate;
+    int sync_error;
+};
+
+static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
+{
+    if (s->frame_done && (s->interrupts & 1)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->palette_done && (s->interrupts & 2)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->sync_error) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    qemu_irq_lower(s->irq);
+}
+
+#include "pixel_ops.h"
+
+#define draw_line_func drawfn
+
+#define DEPTH 8
+#include "omap_lcd_template.h"
+#define DEPTH 15
+#include "omap_lcd_template.h"
+#define DEPTH 16
+#include "omap_lcd_template.h"
+#define DEPTH 32
+#include "omap_lcd_template.h"
+
+static draw_line_func draw_line_table2[33] = {
+    [0 ... 32]	= NULL,
+    [8]		= draw_line2_8,
+    [15]	= draw_line2_15,
+    [16]	= draw_line2_16,
+    [32]	= draw_line2_32,
+}, draw_line_table4[33] = {
+    [0 ... 32]	= NULL,
+    [8]		= draw_line4_8,
+    [15]	= draw_line4_15,
+    [16]	= draw_line4_16,
+    [32]	= draw_line4_32,
+}, draw_line_table8[33] = {
+    [0 ... 32]	= NULL,
+    [8]		= draw_line8_8,
+    [15]	= draw_line8_15,
+    [16]	= draw_line8_16,
+    [32]	= draw_line8_32,
+}, draw_line_table12[33] = {
+    [0 ... 32]	= NULL,
+    [8]		= draw_line12_8,
+    [15]	= draw_line12_15,
+    [16]	= draw_line12_16,
+    [32]	= draw_line12_32,
+}, draw_line_table16[33] = {
+    [0 ... 32]	= NULL,
+    [8]		= draw_line16_8,
+    [15]	= draw_line16_15,
+    [16]	= draw_line16_16,
+    [32]	= draw_line16_32,
+};
+
+static void omap_update_display(void *opaque)
+{
+    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
+    draw_line_func draw_line;
+    int size, height, first, last;
+    int width, linesize, step, bpp, frame_offset;
+    target_phys_addr_t frame_base;
+
+    if (!omap_lcd || omap_lcd->plm == 1 ||
+                    !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state))
+        return;
+
+    frame_offset = 0;
+    if (omap_lcd->plm != 2) {
+        cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
+                                  omap_lcd->dma->current_frame],
+                                 (void *)omap_lcd->palette, 0x200);
+        switch (omap_lcd->palette[0] >> 12 & 7) {
+        case 3 ... 7:
+            frame_offset += 0x200;
+            break;
+        default:
+            frame_offset += 0x20;
+        }
+    }
+
+    /* Colour depth */
+    switch ((omap_lcd->palette[0] >> 12) & 7) {
+    case 1:
+        draw_line = draw_line_table2[ds_get_bits_per_pixel(omap_lcd->state)];
+        bpp = 2;
+        break;
+
+    case 2:
+        draw_line = draw_line_table4[ds_get_bits_per_pixel(omap_lcd->state)];
+        bpp = 4;
+        break;
+
+    case 3:
+        draw_line = draw_line_table8[ds_get_bits_per_pixel(omap_lcd->state)];
+        bpp = 8;
+        break;
+
+    case 4 ... 7:
+        if (!omap_lcd->tft)
+            draw_line = draw_line_table12[ds_get_bits_per_pixel(omap_lcd->state)];
+        else
+            draw_line = draw_line_table16[ds_get_bits_per_pixel(omap_lcd->state)];
+        bpp = 16;
+        break;
+
+    default:
+        /* Unsupported at the moment.  */
+        return;
+    }
+
+    /* Resolution */
+    width = omap_lcd->width;
+    if (width != ds_get_width(omap_lcd->state) ||
+            omap_lcd->height != ds_get_height(omap_lcd->state)) {
+        qemu_console_resize(omap_lcd->state,
+                            omap_lcd->width, omap_lcd->height);
+        omap_lcd->invalidate = 1;
+    }
+
+    if (omap_lcd->dma->current_frame == 0)
+        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
+    else
+        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
+
+    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
+        omap_lcd->sync_error = 1;
+        omap_lcd_interrupts(omap_lcd);
+        omap_lcd->enable = 0;
+        return;
+    }
+
+    /* Content */
+    frame_base = omap_lcd->dma->phys_framebuffer[
+            omap_lcd->dma->current_frame] + frame_offset;
+    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
+    if (omap_lcd->dma->interrupts & 1)
+        qemu_irq_raise(omap_lcd->dma->irq);
+    if (omap_lcd->dma->dual)
+        omap_lcd->dma->current_frame ^= 1;
+
+    if (!ds_get_bits_per_pixel(omap_lcd->state))
+        return;
+
+    first = 0;
+    height = omap_lcd->height;
+    if (omap_lcd->subpanel & (1 << 31)) {
+        if (omap_lcd->subpanel & (1 << 29))
+            first = (omap_lcd->subpanel >> 16) & 0x3ff;
+        else
+            height = (omap_lcd->subpanel >> 16) & 0x3ff;
+        /* TODO: fill the rest of the panel with DPD */
+    }
+
+    step = width * bpp >> 3;
+    linesize = ds_get_linesize(omap_lcd->state);
+    framebuffer_update_display(omap_lcd->state,
+                               frame_base, width, height,
+                               step, linesize, 0,
+                               omap_lcd->invalidate,
+                               draw_line, omap_lcd->palette,
+                               &first, &last);
+    if (first >= 0) {
+        dpy_update(omap_lcd->state, 0, first, width, last - first + 1);
+    }
+    omap_lcd->invalidate = 0;
+}
+
+static int ppm_save(const char *filename, uint8_t *data,
+                int w, int h, int linesize)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    unsigned int v;
+    int y, x, bpp;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return -1;
+    fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+    d1 = data;
+    bpp = linesize / w;
+    for (y = 0; y < h; y ++) {
+        d = d1;
+        for (x = 0; x < w; x ++) {
+            v = *(uint32_t *) d;
+            switch (bpp) {
+            case 2:
+                fputc((v >> 8) & 0xf8, f);
+                fputc((v >> 3) & 0xfc, f);
+                fputc((v << 3) & 0xf8, f);
+                break;
+            case 3:
+            case 4:
+            default:
+                fputc((v >> 16) & 0xff, f);
+                fputc((v >> 8) & 0xff, f);
+                fputc((v) & 0xff, f);
+                break;
+            }
+            d += bpp;
+        }
+        d1 += linesize;
+    }
+    fclose(f);
+    return 0;
+}
+
+static void omap_screen_dump(void *opaque, const char *filename) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_update_display(opaque);
+    if (omap_lcd && ds_get_data(omap_lcd->state))
+        ppm_save(filename, ds_get_data(omap_lcd->state),
+                omap_lcd->width, omap_lcd->height,
+                ds_get_linesize(omap_lcd->state));
+}
+
+static void omap_invalidate_display(void *opaque) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_lcd->invalidate = 1;
+}
+
+static void omap_lcd_update(struct omap_lcd_panel_s *s) {
+    if (!s->enable) {
+        s->dma->current_frame = -1;
+        s->sync_error = 0;
+        if (s->plm != 1)
+            s->frame_done = 1;
+        omap_lcd_interrupts(s);
+        return;
+    }
+
+    if (s->dma->current_frame == -1) {
+        s->frame_done = 0;
+        s->palette_done = 0;
+        s->dma->current_frame = 0;
+    }
+
+    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_top) ||
+                    !s->dma->mpu->port[
+                    s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_bottom) ||
+                    (s->dma->dual &&
+                     (!s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_top) ||
+                      !s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_bottom)))) {
+        s->dma->condition |= 1 << 2;
+        if (s->dma->interrupts & (1 << 1))
+            qemu_irq_raise(s->dma->irq);
+        s->enable = 0;
+        return;
+    }
+
+    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
+    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
+
+    if (s->plm != 2 && !s->palette_done) {
+        cpu_physical_memory_read(
+            s->dma->phys_framebuffer[s->dma->current_frame],
+            (void *)s->palette, 0x200);
+        s->palette_done = 1;
+        omap_lcd_interrupts(s);
+    }
+}
+
+static uint32_t omap_lcdc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* LCD_CONTROL */
+        return (s->tft << 23) | (s->plm << 20) |
+                (s->tft << 7) | (s->interrupts << 3) |
+                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
+
+    case 0x04:	/* LCD_TIMING0 */
+        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
+
+    case 0x08:	/* LCD_TIMING1 */
+        return (s->timing[1] << 10) | (s->height - 1);
+
+    case 0x0c:	/* LCD_TIMING2 */
+        return s->timing[2] | 0xfc000000;
+
+    case 0x10:	/* LCD_STATUS */
+        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
+
+    case 0x14:	/* LCD_SUBPANEL */
+        return s->subpanel;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_lcdc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* LCD_CONTROL */
+        s->plm = (value >> 20) & 3;
+        s->tft = (value >> 7) & 1;
+        s->interrupts = (value >> 3) & 3;
+        s->mono = (value >> 1) & 1;
+        s->ctrl = value & 0x01cff300;
+        if (s->enable != (value & 1)) {
+            s->enable = value & 1;
+            omap_lcd_update(s);
+        }
+        break;
+
+    case 0x04:	/* LCD_TIMING0 */
+        s->timing[0] = value >> 10;
+        s->width = (value & 0x3ff) + 1;
+        break;
+
+    case 0x08:	/* LCD_TIMING1 */
+        s->timing[1] = value >> 10;
+        s->height = (value & 0x3ff) + 1;
+        break;
+
+    case 0x0c:	/* LCD_TIMING2 */
+        s->timing[2] = value;
+        break;
+
+    case 0x10:	/* LCD_STATUS */
+        break;
+
+    case 0x14:	/* LCD_SUBPANEL */
+        s->subpanel = value & 0xa1ffffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_lcdc_readfn[] = {
+    omap_lcdc_read,
+    omap_lcdc_read,
+    omap_lcdc_read,
+};
+
+static CPUWriteMemoryFunc * const omap_lcdc_writefn[] = {
+    omap_lcdc_write,
+    omap_lcdc_write,
+    omap_lcdc_write,
+};
+
+void omap_lcdc_reset(struct omap_lcd_panel_s *s)
+{
+    s->dma->current_frame = -1;
+    s->plm = 0;
+    s->tft = 0;
+    s->mono = 0;
+    s->enable = 0;
+    s->width = 0;
+    s->height = 0;
+    s->interrupts = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->timing[2] = 0;
+    s->subpanel = 0;
+    s->palette_done = 0;
+    s->frame_done = 0;
+    s->sync_error = 0;
+    s->invalidate = 1;
+    s->subpanel = 0;
+    s->ctrl = 0;
+}
+
+struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
+                struct omap_dma_lcd_channel_s *dma,
+                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
+            qemu_mallocz(sizeof(struct omap_lcd_panel_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->imif_base = imif_base;
+    s->emiff_base = emiff_base;
+    omap_lcdc_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_lcdc_readfn,
+                    omap_lcdc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    s->state = graphic_console_init(omap_update_display,
+                                    omap_invalidate_display,
+                                    omap_screen_dump, NULL, s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_mmc.c b/qemu-0.15.x/hw/omap_mmc.c
new file mode 100644
index 0000000..e9ec2f3
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_mmc.c
@@ -0,0 +1,641 @@
+/*
+ * OMAP on-chip MMC/SD host emulation.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "omap.h"
+#include "sd.h"
+
+struct omap_mmc_s {
+    qemu_irq irq;
+    qemu_irq *dma;
+    qemu_irq coverswitch;
+    omap_clk clk;
+    SDState *card;
+    uint16_t last_cmd;
+    uint16_t sdio;
+    uint16_t rsp[8];
+    uint32_t arg;
+    int lines;
+    int dw;
+    int mode;
+    int enable;
+    int be;
+    int rev;
+    uint16_t status;
+    uint16_t mask;
+    uint8_t cto;
+    uint16_t dto;
+    int clkdiv;
+    uint16_t fifo[32];
+    int fifo_start;
+    int fifo_len;
+    uint16_t blen;
+    uint16_t blen_counter;
+    uint16_t nblk;
+    uint16_t nblk_counter;
+    int tx_dma;
+    int rx_dma;
+    int af_level;
+    int ae_level;
+
+    int ddir;
+    int transfer;
+
+    int cdet_wakeup;
+    int cdet_enable;
+    int cdet_state;
+    qemu_irq cdet;
+};
+
+static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
+{
+    qemu_set_irq(s->irq, !!(s->status & s->mask));
+}
+
+static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
+{
+    if (!host->transfer && !host->fifo_len) {
+        host->status &= 0xf3ff;
+        return;
+    }
+
+    if (host->fifo_len > host->af_level && host->ddir) {
+        if (host->rx_dma) {
+            host->status &= 0xfbff;
+            qemu_irq_raise(host->dma[1]);
+        } else
+            host->status |= 0x0400;
+    } else {
+        host->status &= 0xfbff;
+        qemu_irq_lower(host->dma[1]);
+    }
+
+    if (host->fifo_len < host->ae_level && !host->ddir) {
+        if (host->tx_dma) {
+            host->status &= 0xf7ff;
+            qemu_irq_raise(host->dma[0]);
+        } else
+            host->status |= 0x0800;
+    } else {
+        qemu_irq_lower(host->dma[0]);
+        host->status &= 0xf7ff;
+    }
+}
+
+typedef enum {
+    sd_nore = 0,	/* no response */
+    sd_r1,		/* normal response command */
+    sd_r2,		/* CID, CSD registers */
+    sd_r3,		/* OCR register */
+    sd_r6 = 6,		/* Published RCA response */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
+                sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
+{
+    uint32_t rspstatus, mask;
+    int rsplen, timeout;
+    SDRequest request;
+    uint8_t response[16];
+
+    if (init && cmd == 0) {
+        host->status |= 0x0001;
+        return;
+    }
+
+    if (resptype == sd_r1 && busy)
+        resptype = sd_r1b;
+
+    if (type == sd_adtc) {
+        host->fifo_start = 0;
+        host->fifo_len = 0;
+        host->transfer = 1;
+        host->ddir = dir;
+    } else
+        host->transfer = 0;
+    timeout = 0;
+    mask = 0;
+    rspstatus = 0;
+
+    request.cmd = cmd;
+    request.arg = host->arg;
+    request.crc = 0; /* FIXME */
+
+    rsplen = sd_do_command(host->card, &request, response);
+
+    /* TODO: validate CRCs */
+    switch (resptype) {
+    case sd_nore:
+        rsplen = 0;
+        break;
+
+    case sd_r1:
+    case sd_r1b:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
+                ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
+                LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
+                CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
+                CID_CSD_OVERWRITE;
+        if (host->sdio & (1 << 13))
+            mask |= AKE_SEQ_ERROR;
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        break;
+
+    case sd_r2:
+        if (rsplen < 16) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        if (rspstatus & 0x80000000)
+            host->status &= 0xe000;
+        else
+            host->status |= 0x1000;
+        break;
+
+    case sd_r6:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = 0xe000 | AKE_SEQ_ERROR;
+        rspstatus = (response[2] << 8) | (response[3] << 0);
+    }
+
+    if (rspstatus & mask)
+        host->status |= 0x4000;
+    else
+        host->status &= 0xb000;
+
+    if (rsplen)
+        for (rsplen = 0; rsplen < 8; rsplen ++)
+            host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
+                    (response[(rsplen << 1) | 0] << 8);
+
+    if (timeout)
+        host->status |= 0x0080;
+    else if (cmd == 12)
+        host->status |= 0x0005;	/* Makes it more real */
+    else
+        host->status |= 0x0001;
+}
+
+static void omap_mmc_transfer(struct omap_mmc_s *host)
+{
+    uint8_t value;
+
+    if (!host->transfer)
+        return;
+
+    while (1) {
+        if (host->ddir) {
+            if (host->fifo_len > host->af_level)
+                break;
+
+            value = sd_read_data(host->card);
+            host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
+            if (-- host->blen_counter) {
+                value = sd_read_data(host->card);
+                host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
+                        value << 8;
+                host->blen_counter --;
+            }
+
+            host->fifo_len ++;
+        } else {
+            if (!host->fifo_len)
+                break;
+
+            value = host->fifo[host->fifo_start] & 0xff;
+            sd_write_data(host->card, value);
+            if (-- host->blen_counter) {
+                value = host->fifo[host->fifo_start] >> 8;
+                sd_write_data(host->card, value);
+                host->blen_counter --;
+            }
+
+            host->fifo_start ++;
+            host->fifo_len --;
+            host->fifo_start &= 31;
+        }
+
+        if (host->blen_counter == 0) {
+            host->nblk_counter --;
+            host->blen_counter = host->blen;
+
+            if (host->nblk_counter == 0) {
+                host->nblk_counter = host->nblk;
+                host->transfer = 0;
+                host->status |= 0x0008;
+                break;
+            }
+        }
+    }
+}
+
+static void omap_mmc_update(void *opaque)
+{
+    struct omap_mmc_s *s = opaque;
+    omap_mmc_transfer(s);
+    omap_mmc_fifolevel_update(s);
+    omap_mmc_interrupts_update(s);
+}
+
+void omap_mmc_reset(struct omap_mmc_s *host)
+{
+    host->last_cmd = 0;
+    memset(host->rsp, 0, sizeof(host->rsp));
+    host->arg = 0;
+    host->dw = 0;
+    host->mode = 0;
+    host->enable = 0;
+    host->status = 0;
+    host->mask = 0;
+    host->cto = 0;
+    host->dto = 0;
+    host->fifo_len = 0;
+    host->blen = 0;
+    host->blen_counter = 0;
+    host->nblk = 0;
+    host->nblk_counter = 0;
+    host->tx_dma = 0;
+    host->rx_dma = 0;
+    host->ae_level = 0x00;
+    host->af_level = 0x1f;
+    host->transfer = 0;
+    host->cdet_wakeup = 0;
+    host->cdet_enable = 0;
+    qemu_set_irq(host->coverswitch, host->cdet_state);
+    host->clkdiv = 0;
+}
+
+static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
+{
+    uint16_t i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+    offset &= OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* MMC_CMD */
+        return s->last_cmd;
+
+    case 0x04:	/* MMC_ARGL */
+        return s->arg & 0x0000ffff;
+
+    case 0x08:	/* MMC_ARGH */
+        return s->arg >> 16;
+
+    case 0x0c:	/* MMC_CON */
+        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | 
+                (s->be << 10) | s->clkdiv;
+
+    case 0x10:	/* MMC_STAT */
+        return s->status;
+
+    case 0x14:	/* MMC_IE */
+        return s->mask;
+
+    case 0x18:	/* MMC_CTO */
+        return s->cto;
+
+    case 0x1c:	/* MMC_DTO */
+        return s->dto;
+
+    case 0x20:	/* MMC_DATA */
+        /* TODO: support 8-bit access */
+        i = s->fifo[s->fifo_start];
+        if (s->fifo_len == 0) {
+            printf("MMC: FIFO underrun\n");
+            return i;
+        }
+        s->fifo_start ++;
+        s->fifo_len --;
+        s->fifo_start &= 31;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        return i;
+
+    case 0x24:	/* MMC_BLEN */
+        return s->blen_counter;
+
+    case 0x28:	/* MMC_NBLK */
+        return s->nblk_counter;
+
+    case 0x2c:	/* MMC_BUF */
+        return (s->rx_dma << 15) | (s->af_level << 8) |
+            (s->tx_dma << 7) | s->ae_level;
+
+    case 0x30:	/* MMC_SPI */
+        return 0x0000;
+    case 0x34:	/* MMC_SDIO */
+        return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
+    case 0x38:	/* MMC_SYST */
+        return 0x0000;
+
+    case 0x3c:	/* MMC_REV */
+        return s->rev;
+
+    case 0x40:	/* MMC_RSP0 */
+    case 0x44:	/* MMC_RSP1 */
+    case 0x48:	/* MMC_RSP2 */
+    case 0x4c:	/* MMC_RSP3 */
+    case 0x50:	/* MMC_RSP4 */
+    case 0x54:	/* MMC_RSP5 */
+    case 0x58:	/* MMC_RSP6 */
+    case 0x5c:	/* MMC_RSP7 */
+        return s->rsp[(offset - 0x40) >> 2];
+
+    /* OMAP2-specific */
+    case 0x60:	/* MMC_IOSR */
+    case 0x64:	/* MMC_SYSC */
+        return 0;
+    case 0x68:	/* MMC_SYSS */
+        return 1;						/* RSTD */
+    }
+
+    OMAP_BAD_REG(offset);
+    return 0;
+}
+
+static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    int i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+    offset &= OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x00:	/* MMC_CMD */
+        if (!s->enable)
+            break;
+
+        s->last_cmd = value;
+        for (i = 0; i < 8; i ++)
+            s->rsp[i] = 0x0000;
+        omap_mmc_command(s, value & 63, (value >> 15) & 1,
+                (sd_cmd_type_t) ((value >> 12) & 3),
+                (value >> 11) & 1,
+                (sd_rsp_type_t) ((value >> 8) & 7),
+                (value >> 7) & 1);
+        omap_mmc_update(s);
+        break;
+
+    case 0x04:	/* MMC_ARGL */
+        s->arg &= 0xffff0000;
+        s->arg |= 0x0000ffff & value;
+        break;
+
+    case 0x08:	/* MMC_ARGH */
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case 0x0c:	/* MMC_CON */
+        s->dw = (value >> 15) & 1;
+        s->mode = (value >> 12) & 3;
+        s->enable = (value >> 11) & 1;
+        s->be = (value >> 10) & 1;
+        s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff);
+        if (s->mode != 0)
+            printf("SD mode %i unimplemented!\n", s->mode);
+        if (s->be != 0)
+            printf("SD FIFO byte sex unimplemented!\n");
+        if (s->dw != 0 && s->lines < 4)
+            printf("4-bit SD bus enabled\n");
+        if (!s->enable)
+            omap_mmc_reset(s);
+        break;
+
+    case 0x10:	/* MMC_STAT */
+        s->status &= ~value;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x14:	/* MMC_IE */
+        s->mask = value & 0x7fff;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x18:	/* MMC_CTO */
+        s->cto = value & 0xff;
+        if (s->cto > 0xfd && s->rev <= 1)
+            printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
+        break;
+
+    case 0x1c:	/* MMC_DTO */
+        s->dto = value & 0xffff;
+        break;
+
+    case 0x20:	/* MMC_DATA */
+        /* TODO: support 8-bit access */
+        if (s->fifo_len == 32)
+            break;
+        s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
+        s->fifo_len ++;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x24:	/* MMC_BLEN */
+        s->blen = (value & 0x07ff) + 1;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x28:	/* MMC_NBLK */
+        s->nblk = (value & 0x07ff) + 1;
+        s->nblk_counter = s->nblk;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x2c:	/* MMC_BUF */
+        s->rx_dma = (value >> 15) & 1;
+        s->af_level = (value >> 8) & 0x1f;
+        s->tx_dma = (value >> 7) & 1;
+        s->ae_level = value & 0x1f;
+
+        if (s->rx_dma)
+            s->status &= 0xfbff;
+        if (s->tx_dma)
+            s->status &= 0xf7ff;
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    /* SPI, SDIO and TEST modes unimplemented */
+    case 0x30:	/* MMC_SPI (OMAP1 only) */
+        break;
+    case 0x34:	/* MMC_SDIO */
+        s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
+        s->cdet_wakeup = (value >> 9) & 1;
+        s->cdet_enable = (value >> 2) & 1;
+        break;
+    case 0x38:	/* MMC_SYST */
+        break;
+
+    case 0x3c:	/* MMC_REV */
+    case 0x40:	/* MMC_RSP0 */
+    case 0x44:	/* MMC_RSP1 */
+    case 0x48:	/* MMC_RSP2 */
+    case 0x4c:	/* MMC_RSP3 */
+    case 0x50:	/* MMC_RSP4 */
+    case 0x54:	/* MMC_RSP5 */
+    case 0x58:	/* MMC_RSP6 */
+    case 0x5c:	/* MMC_RSP7 */
+        OMAP_RO_REG(offset);
+        break;
+
+    /* OMAP2-specific */
+    case 0x60:	/* MMC_IOSR */
+        if (value & 0xf)
+            printf("MMC: SDIO bits used!\n");
+        break;
+    case 0x64:	/* MMC_SYSC */
+        if (value & (1 << 2))					/* SRTS */
+            omap_mmc_reset(s);
+        break;
+    case 0x68:	/* MMC_SYSS */
+        OMAP_RO_REG(offset);
+        break;
+
+    default:
+        OMAP_BAD_REG(offset);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_mmc_readfn[] = {
+    omap_badwidth_read16,
+    omap_mmc_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc * const omap_mmc_writefn[] = {
+    omap_badwidth_write16,
+    omap_mmc_write,
+    omap_badwidth_write16,
+};
+
+static void omap_mmc_cover_cb(void *opaque, int line, int level)
+{
+    struct omap_mmc_s *host = (struct omap_mmc_s *) opaque;
+
+    if (!host->cdet_state && level) {
+        host->status |= 0x0002;
+        omap_mmc_interrupts_update(host);
+        if (host->cdet_wakeup) {
+            /* TODO: Assert wake-up */
+        }
+    }
+
+    if (host->cdet_state != level) {
+        qemu_set_irq(host->coverswitch, level);
+        host->cdet_state = level;
+    }
+}
+
+struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
+                BlockDriverState *bd,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            qemu_mallocz(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = clk;
+    s->lines = 1;	/* TODO: needs to be settable per-board */
+    s->rev = 1;
+
+    omap_mmc_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_mmc_readfn,
+                    omap_mmc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x800, iomemtype);
+
+    /* Instantiate the storage */
+    s->card = sd_init(bd, 0);
+
+    return s;
+}
+
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            qemu_mallocz(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = fclk;
+    s->lines = 4;
+    s->rev = 2;
+
+    omap_mmc_reset(s);
+
+    iomemtype = l4_register_io_memory(omap_mmc_readfn,
+                    omap_mmc_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    /* Instantiate the storage */
+    s->card = sd_init(bd, 0);
+
+    s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
+    sd_set_cb(s->card, NULL, s->cdet);
+
+    return s;
+}
+
+void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
+{
+    if (s->cdet) {
+        sd_set_cb(s->card, ro, s->cdet);
+        s->coverswitch = cover;
+        qemu_set_irq(cover, s->cdet_state);
+    } else
+        sd_set_cb(s->card, ro, cover);
+}
+
+void omap_mmc_enable(struct omap_mmc_s *s, int enable)
+{
+    sd_enable(s->card, enable);
+}
diff --git a/qemu-0.15.x/hw/omap_sdrc.c b/qemu-0.15.x/hw/omap_sdrc.c
new file mode 100644
index 0000000..e183762
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_sdrc.c
@@ -0,0 +1,165 @@
+/*
+ * TI OMAP SDRAM controller emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "omap.h"
+
+/* SDRAM Controller Subsystem */
+struct omap_sdrc_s {
+    uint8_t config;
+};
+
+void omap_sdrc_reset(struct omap_sdrc_s *s)
+{
+    s->config = 0x10;
+}
+
+static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* SDRC_REVISION */
+        return 0x20;
+
+    case 0x10:	/* SDRC_SYSCONFIG */
+        return s->config;
+
+    case 0x14:	/* SDRC_SYSSTATUS */
+        return 1;						/* RESETDONE */
+
+    case 0x40:	/* SDRC_CS_CFG */
+    case 0x44:	/* SDRC_SHARING */
+    case 0x48:	/* SDRC_ERR_ADDR */
+    case 0x4c:	/* SDRC_ERR_TYPE */
+    case 0x60:	/* SDRC_DLLA_SCTRL */
+    case 0x64:	/* SDRC_DLLA_STATUS */
+    case 0x68:	/* SDRC_DLLB_CTRL */
+    case 0x6c:	/* SDRC_DLLB_STATUS */
+    case 0x70:	/* SDRC_POWER */
+    case 0x80:	/* SDRC_MCFG_0 */
+    case 0x84:	/* SDRC_MR_0 */
+    case 0x88:	/* SDRC_EMR1_0 */
+    case 0x8c:	/* SDRC_EMR2_0 */
+    case 0x90:	/* SDRC_EMR3_0 */
+    case 0x94:	/* SDRC_DCDL1_CTRL */
+    case 0x98:	/* SDRC_DCDL2_CTRL */
+    case 0x9c:	/* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0:	/* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4:	/* SDRC_RFR_CTRL_0 */
+    case 0xa8:	/* SDRC_MANUAL_0 */
+    case 0xb0:	/* SDRC_MCFG_1 */
+    case 0xb4:	/* SDRC_MR_1 */
+    case 0xb8:	/* SDRC_EMR1_1 */
+    case 0xbc:	/* SDRC_EMR2_1 */
+    case 0xc0:	/* SDRC_EMR3_1 */
+    case 0xc4:	/* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8:	/* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4:	/* SDRC_RFR_CTRL_1 */
+    case 0xd8:	/* SDRC_MANUAL_1 */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sdrc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* SDRC_REVISION */
+    case 0x14:	/* SDRC_SYSSTATUS */
+    case 0x48:	/* SDRC_ERR_ADDR */
+    case 0x64:	/* SDRC_DLLA_STATUS */
+    case 0x6c:	/* SDRC_DLLB_STATUS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10:	/* SDRC_SYSCONFIG */
+        if ((value >> 3) != 0x2)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+                            __FUNCTION__, value >> 3);
+        if (value & 2)
+            omap_sdrc_reset(s);
+        s->config = value & 0x18;
+        break;
+
+    case 0x40:	/* SDRC_CS_CFG */
+    case 0x44:	/* SDRC_SHARING */
+    case 0x4c:	/* SDRC_ERR_TYPE */
+    case 0x60:	/* SDRC_DLLA_SCTRL */
+    case 0x68:	/* SDRC_DLLB_CTRL */
+    case 0x70:	/* SDRC_POWER */
+    case 0x80:	/* SDRC_MCFG_0 */
+    case 0x84:	/* SDRC_MR_0 */
+    case 0x88:	/* SDRC_EMR1_0 */
+    case 0x8c:	/* SDRC_EMR2_0 */
+    case 0x90:	/* SDRC_EMR3_0 */
+    case 0x94:	/* SDRC_DCDL1_CTRL */
+    case 0x98:	/* SDRC_DCDL2_CTRL */
+    case 0x9c:	/* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0:	/* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4:	/* SDRC_RFR_CTRL_0 */
+    case 0xa8:	/* SDRC_MANUAL_0 */
+    case 0xb0:	/* SDRC_MCFG_1 */
+    case 0xb4:	/* SDRC_MR_1 */
+    case 0xb8:	/* SDRC_EMR1_1 */
+    case 0xbc:	/* SDRC_EMR2_1 */
+    case 0xc0:	/* SDRC_EMR3_1 */
+    case 0xc4:	/* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8:	/* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4:	/* SDRC_RFR_CTRL_1 */
+    case 0xd8:	/* SDRC_MANUAL_1 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_sdrc_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_sdrc_read,
+};
+
+static CPUWriteMemoryFunc * const omap_sdrc_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_sdrc_write,
+};
+
+struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
+{
+    int iomemtype;
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *)
+            qemu_mallocz(sizeof(struct omap_sdrc_s));
+
+    omap_sdrc_reset(s);
+
+    iomemtype = cpu_register_io_memory(omap_sdrc_readfn,
+                    omap_sdrc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x1000, iomemtype);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_spi.c b/qemu-0.15.x/hw/omap_spi.c
new file mode 100644
index 0000000..a6b0349
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_spi.c
@@ -0,0 +1,346 @@
+/*
+ * TI OMAP processor's Multichannel SPI emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Original code for OMAP2 by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw.h"
+#include "omap.h"
+
+/* Multichannel SPI */
+struct omap_mcspi_s {
+    qemu_irq irq;
+    int chnum;
+
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t wken;
+    uint32_t control;
+
+    struct omap_mcspi_ch_s {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t, int);
+        void *opaque;
+
+        uint32_t tx;
+        uint32_t rx;
+
+        uint32_t config;
+        uint32_t status;
+        uint32_t control;
+    } ch[4];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
+{
+    qemu_set_irq(ch->txdrq,
+                    (ch->control & 1) &&		/* EN */
+                    (ch->config & (1 << 14)) &&		/* DMAW */
+                    (ch->status & (1 << 1)) &&		/* TXS */
+                    ((ch->config >> 12) & 3) != 1);	/* TRM */
+    qemu_set_irq(ch->rxdrq,
+                    (ch->control & 1) &&		/* EN */
+                    (ch->config & (1 << 15)) &&		/* DMAW */
+                    (ch->status & (1 << 0)) &&		/* RXS */
+                    ((ch->config >> 12) & 3) != 2);	/* TRM */
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+    struct omap_mcspi_ch_s *ch = s->ch + chnum;
+
+    if (!(ch->control & 1))				/* EN */
+        return;
+    if ((ch->status & (1 << 0)) &&			/* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&	/* TRM */
+                    !(ch->config & (1 << 19)))		/* TURBO */
+        goto intr_update;
+    if ((ch->status & (1 << 1)) &&			/* TXS */
+                    ((ch->config >> 12) & 3) != 1)	/* TRM */
+        goto intr_update;
+
+    if (!(s->control & 1) ||				/* SINGLE */
+                    (ch->config & (1 << 20))) {		/* FORCE */
+        if (ch->txrx)
+            ch->rx = ch->txrx(ch->opaque, ch->tx,	/* WL */
+                            1 + (0x1f & (ch->config >> 7)));
+    }
+
+    ch->tx = 0;
+    ch->status |= 1 << 2;				/* EOT */
+    ch->status |= 1 << 1;				/* TXS */
+    if (((ch->config >> 12) & 3) != 2)			/* TRM */
+        ch->status |= 1 << 0;				/* RXS */
+
+intr_update:
+    if ((ch->status & (1 << 0)) &&			/* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&	/* TRM */
+                    !(ch->config & (1 << 19)))		/* TURBO */
+        s->irqst |= 1 << (2 + 4 * chnum);		/* RX_FULL */
+    if ((ch->status & (1 << 1)) &&			/* TXS */
+                    ((ch->config >> 12) & 3) != 1)	/* TRM */
+        s->irqst |= 1 << (0 + 4 * chnum);		/* TX_EMPTY */
+    omap_mcspi_interrupt_update(s);
+    omap_mcspi_dmarequest_update(ch);
+}
+
+void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+    int ch;
+
+    s->sysconfig = 0;
+    s->systest = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->wken = 0;
+    s->control = 4;
+
+    for (ch = 0; ch < 4; ch ++) {
+        s->ch[ch].config = 0x060000;
+        s->ch[ch].status = 2;				/* TXS */
+        s->ch[ch].control = 0;
+
+        omap_mcspi_dmarequest_update(s->ch + ch);
+    }
+
+    omap_mcspi_interrupt_update(s);
+}
+
+static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+    uint32_t ret;
+
+    switch (addr) {
+    case 0x00:	/* MCSPI_REVISION */
+        return 0x91;
+
+    case 0x10:	/* MCSPI_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x14:	/* MCSPI_SYSSTATUS */
+        return 1;					/* RESETDONE */
+
+    case 0x18:	/* MCSPI_IRQSTATUS */
+        return s->irqst;
+
+    case 0x1c:	/* MCSPI_IRQENABLE */
+        return s->irqen;
+
+    case 0x20:	/* MCSPI_WAKEUPENABLE */
+        return s->wken;
+
+    case 0x24:	/* MCSPI_SYST */
+        return s->systest;
+
+    case 0x28:	/* MCSPI_MODULCTRL */
+        return s->control;
+
+    case 0x68: ch ++;
+    case 0x54: ch ++;
+    case 0x40: ch ++;
+    case 0x2c:	/* MCSPI_CHCONF */
+        return s->ch[ch].config;
+
+    case 0x6c: ch ++;
+    case 0x58: ch ++;
+    case 0x44: ch ++;
+    case 0x30:	/* MCSPI_CHSTAT */
+        return s->ch[ch].status;
+
+    case 0x70: ch ++;
+    case 0x5c: ch ++;
+    case 0x48: ch ++;
+    case 0x34:	/* MCSPI_CHCTRL */
+        return s->ch[ch].control;
+
+    case 0x74: ch ++;
+    case 0x60: ch ++;
+    case 0x4c: ch ++;
+    case 0x38:	/* MCSPI_TX */
+        return s->ch[ch].tx;
+
+    case 0x78: ch ++;
+    case 0x64: ch ++;
+    case 0x50: ch ++;
+    case 0x3c:	/* MCSPI_RX */
+        s->ch[ch].status &= ~(1 << 0);			/* RXS */
+        ret = s->ch[ch].rx;
+        omap_mcspi_transfer_run(s, ch);
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+
+    switch (addr) {
+    case 0x00:	/* MCSPI_REVISION */
+    case 0x14:	/* MCSPI_SYSSTATUS */
+    case 0x30:	/* MCSPI_CHSTAT0 */
+    case 0x3c:	/* MCSPI_RX0 */
+    case 0x44:	/* MCSPI_CHSTAT1 */
+    case 0x50:	/* MCSPI_RX1 */
+    case 0x58:	/* MCSPI_CHSTAT2 */
+    case 0x64:	/* MCSPI_RX2 */
+    case 0x6c:	/* MCSPI_CHSTAT3 */
+    case 0x78:	/* MCSPI_RX3 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10:	/* MCSPI_SYSCONFIG */
+        if (value & (1 << 1))				/* SOFTRESET */
+            omap_mcspi_reset(s);
+        s->sysconfig = value & 0x31d;
+        break;
+
+    case 0x18:	/* MCSPI_IRQSTATUS */
+        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+            s->irqst &= ~value;
+            omap_mcspi_interrupt_update(s);
+        }
+        break;
+
+    case 0x1c:	/* MCSPI_IRQENABLE */
+        s->irqen = value & 0x1777f;
+        omap_mcspi_interrupt_update(s);
+        break;
+
+    case 0x20:	/* MCSPI_WAKEUPENABLE */
+        s->wken = value & 1;
+        break;
+
+    case 0x24:	/* MCSPI_SYST */
+        if (s->control & (1 << 3))			/* SYSTEM_TEST */
+            if (value & (1 << 11)) {			/* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->systest = value & 0xfff;
+        break;
+
+    case 0x28:	/* MCSPI_MODULCTRL */
+        if (value & (1 << 3))				/* SYSTEM_TEST */
+            if (s->systest & (1 << 11)) {		/* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->control = value & 0xf;
+        break;
+
+    case 0x68: ch ++;
+    case 0x54: ch ++;
+    case 0x40: ch ++;
+    case 0x2c:	/* MCSPI_CHCONF */
+        if ((value ^ s->ch[ch].config) & (3 << 14))	/* DMAR | DMAW */
+            omap_mcspi_dmarequest_update(s->ch + ch);
+        if (((value >> 12) & 3) == 3)			/* TRM */
+            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
+        if (((value >> 7) & 0x1f) < 3)			/* WL */
+            fprintf(stderr, "%s: invalid WL value (%i)\n",
+                            __FUNCTION__, (value >> 7) & 0x1f);
+        s->ch[ch].config = value & 0x7fffff;
+        break;
+
+    case 0x70: ch ++;
+    case 0x5c: ch ++;
+    case 0x48: ch ++;
+    case 0x34:	/* MCSPI_CHCTRL */
+        if (value & ~s->ch[ch].control & 1) {		/* EN */
+            s->ch[ch].control |= 1;
+            omap_mcspi_transfer_run(s, ch);
+        } else
+            s->ch[ch].control = value & 1;
+        break;
+
+    case 0x74: ch ++;
+    case 0x60: ch ++;
+    case 0x4c: ch ++;
+    case 0x38:	/* MCSPI_TX */
+        s->ch[ch].tx = value;
+        s->ch[ch].status &= ~(1 << 1);			/* TXS */
+        omap_mcspi_transfer_run(s, ch);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_mcspi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mcspi_read,
+};
+
+static CPUWriteMemoryFunc * const omap_mcspi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mcspi_write,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+            qemu_mallocz(sizeof(struct omap_mcspi_s));
+    struct omap_mcspi_ch_s *ch = s->ch;
+
+    s->irq = irq;
+    s->chnum = chnum;
+    while (chnum --) {
+        ch->txdrq = *drq ++;
+        ch->rxdrq = *drq ++;
+        ch ++;
+    }
+    omap_mcspi_reset(s);
+
+    iomemtype = l4_register_io_memory(omap_mcspi_readfn,
+                    omap_mcspi_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
+                int chipselect)
+{
+    if (chipselect < 0 || chipselect >= s->chnum)
+        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
+
+    s->ch[chipselect].txrx = txrx;
+    s->ch[chipselect].opaque = opaque;
+}
diff --git a/qemu-0.15.x/hw/omap_sx1.c b/qemu-0.15.x/hw/omap_sx1.c
new file mode 100644
index 0000000..a7b687b
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_sx1.c
@@ -0,0 +1,253 @@
+/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
+ *
+ *   Copyright (C) 2008
+ * 	Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
+ *   Copyright (C) 2007 Vladimir Ananiev <vovan888 at gmail.com>
+ *
+ *   based on PalmOne's (TM) PDAs support (palm.c)
+ */
+
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "console.h"
+#include "omap.h"
+#include "boards.h"
+#include "arm-misc.h"
+#include "flash.h"
+#include "blockdev.h"
+
+/*****************************************************************************/
+/* Siemens SX1 Cellphone V1 */
+/* - ARM OMAP310 processor
+ * - SRAM                192 kB
+ * - SDRAM                32 MB at 0x10000000
+ * - Boot flash           16 MB at 0x00000000
+ * - Application flash     8 MB at 0x04000000
+ * - 3 serial ports
+ * - 1 SecureDigital
+ * - 1 LCD display
+ * - 1 RTC
+ */
+
+/*****************************************************************************/
+/* Siemens SX1 Cellphone V2 */
+/* - ARM OMAP310 processor
+ * - SRAM                192 kB
+ * - SDRAM                32 MB at 0x10000000
+ * - Boot flash           32 MB at 0x00000000
+ * - 3 serial ports
+ * - 1 SecureDigital
+ * - 1 LCD display
+ * - 1 RTC
+ */
+
+static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+
+    return *val >> ((offset & 3) << 3);
+}
+
+static uint32_t static_readh(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+
+    return *val >> ((offset & 1) << 3);
+}
+
+static uint32_t static_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+
+    return *val >> ((offset & 0) << 3);
+}
+
+static void static_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+#ifdef SPY
+    printf("%s: value %08lx written at " PA_FMT "\n",
+                    __FUNCTION__, value, offset);
+#endif
+}
+
+static CPUReadMemoryFunc * const static_readfn[] = {
+    static_readb,
+    static_readh,
+    static_readw,
+};
+
+static CPUWriteMemoryFunc * const static_writefn[] = {
+    static_write,
+    static_write,
+    static_write,
+};
+
+#define sdram_size	0x02000000
+#define sector_size	(128 * 1024)
+#define flash0_size	(16 * 1024 * 1024)
+#define flash1_size	( 8 * 1024 * 1024)
+#define flash2_size	(32 * 1024 * 1024)
+#define total_ram_v1	(sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE)
+#define total_ram_v2	(sdram_size + flash2_size + OMAP15XX_SRAM_SIZE)
+
+static struct arm_boot_info sx1_binfo = {
+    .loader_start = OMAP_EMIFF_BASE,
+    .ram_size = sdram_size,
+    .board_id = 0x265,
+};
+
+static void sx1_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model,
+                const int version)
+{
+    struct omap_mpu_state_s *cpu;
+    int io;
+    static uint32_t cs0val = 0x00213090;
+    static uint32_t cs1val = 0x00215070;
+    static uint32_t cs2val = 0x00001139;
+    static uint32_t cs3val = 0x00001139;
+    DriveInfo *dinfo;
+    int fl_idx;
+    uint32_t flash_size = flash0_size;
+    int be;
+
+    if (version == 2) {
+        flash_size = flash2_size;
+    }
+
+    cpu = omap310_mpu_init(sx1_binfo.ram_size, cpu_model);
+
+    /* External Flash (EMIFS) */
+    cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
+                                 qemu_ram_alloc(NULL, "omap_sx1.flash0-0",
+                                                flash_size) | IO_MEM_ROM);
+
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
+                    OMAP_CS0_SIZE - flash_size, io);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
+
+    fl_idx = 0;
+#ifdef TARGET_WORDS_BIGENDIAN
+    be = 1;
+#else
+    be = 0;
+#endif
+
+    if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
+        if (!pflash_cfi01_register(OMAP_CS0_BASE, qemu_ram_alloc(NULL,
+                                   "omap_sx1.flash0-1", flash_size),
+                                   dinfo->bdrv, sector_size,
+                                   flash_size / sector_size,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
+                           fl_idx);
+        }
+        fl_idx++;
+    }
+
+    if ((version == 1) &&
+            (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
+        cpu_register_physical_memory(OMAP_CS1_BASE, flash1_size,
+                                     qemu_ram_alloc(NULL, "omap_sx1.flash1-0",
+                                                    flash1_size) | IO_MEM_ROM);
+        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                    DEVICE_NATIVE_ENDIAN);
+        cpu_register_physical_memory(OMAP_CS1_BASE + flash1_size,
+                        OMAP_CS1_SIZE - flash1_size, io);
+
+        if (!pflash_cfi01_register(OMAP_CS1_BASE, qemu_ram_alloc(NULL,
+                                   "omap_sx1.flash1-1", flash1_size),
+                                   dinfo->bdrv, sector_size,
+                                   flash1_size / sector_size,
+                                   4, 0, 0, 0, 0, be)) {
+            fprintf(stderr, "qemu: Error registering flash memory %d.\n",
+                           fl_idx);
+        }
+        fl_idx++;
+    } else {
+        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                    DEVICE_NATIVE_ENDIAN);
+        cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
+    }
+
+    if (!kernel_filename && !fl_idx) {
+        fprintf(stderr, "Kernel or Flash image must be specified\n");
+        exit(1);
+    }
+
+    /* Load the kernel.  */
+    if (kernel_filename) {
+        sx1_binfo.kernel_filename = kernel_filename;
+        sx1_binfo.kernel_cmdline = kernel_cmdline;
+        sx1_binfo.initrd_filename = initrd_filename;
+        arm_load_kernel(cpu->env, &sx1_binfo);
+    }
+
+    /* TODO: fix next line */
+    //~ qemu_console_resize(ds, 640, 480);
+}
+
+static void sx1_init_v1(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    sx1_init(ram_size, boot_device, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, 1);
+}
+
+static void sx1_init_v2(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    sx1_init(ram_size, boot_device, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, 2);
+}
+
+static QEMUMachine sx1_machine_v2 = {
+    .name = "sx1",
+    .desc = "Siemens SX1 (OMAP310) V2",
+    .init = sx1_init_v2,
+};
+
+static QEMUMachine sx1_machine_v1 = {
+    .name = "sx1-v1",
+    .desc = "Siemens SX1 (OMAP310) V1",
+    .init = sx1_init_v1,
+};
+
+static void sx1_machine_init(void)
+{
+    qemu_register_machine(&sx1_machine_v2);
+    qemu_register_machine(&sx1_machine_v1);
+}
+
+machine_init(sx1_machine_init);
diff --git a/qemu-0.15.x/hw/omap_synctimer.c b/qemu-0.15.x/hw/omap_synctimer.c
new file mode 100644
index 0000000..67f65e6
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_synctimer.c
@@ -0,0 +1,96 @@
+/*
+ * TI OMAP2 32kHz sync timer emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "omap.h"
+struct omap_synctimer_s {
+    uint32_t val;
+    uint16_t readh;
+};
+
+/* 32-kHz Sync Timer of the OMAP2 */
+static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
+    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
+}
+
+void omap_synctimer_reset(struct omap_synctimer_s *s)
+{
+    s->val = omap_synctimer_read(s);
+}
+
+static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+
+    switch (addr) {
+    case 0x00:	/* 32KSYNCNT_REV */
+        return 0x21;
+
+    case 0x10:	/* CR */
+        return omap_synctimer_read(s) - s->val;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_synctimer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static CPUReadMemoryFunc * const omap_synctimer_readfn[] = {
+    omap_badwidth_read32,
+    omap_synctimer_readh,
+    omap_synctimer_readw,
+};
+
+static void omap_synctimer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUWriteMemoryFunc * const omap_synctimer_writefn[] = {
+    omap_badwidth_write32,
+    omap_synctimer_write,
+    omap_synctimer_write,
+};
+
+struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_synctimer_s *s = qemu_mallocz(sizeof(*s));
+
+    omap_synctimer_reset(s);
+    omap_l4_attach(ta, 0, l4_register_io_memory(
+                      omap_synctimer_readfn, omap_synctimer_writefn, s));
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/omap_tap.c b/qemu-0.15.x/hw/omap_tap.c
new file mode 100644
index 0000000..1f18ddd
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_tap.c
@@ -0,0 +1,112 @@
+/*
+ * TI OMAP TEST-Chip-level TAP emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "omap.h"
+
+/* TEST-Chip-level TAP */
+static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0x204:	/* IDCODE_reg */
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0x5b5d902f;	/* ES 2.2 */
+        case omap2430:
+            return 0x5b68a02f;	/* ES 2.2 */
+        case omap3430:
+            return 0x1b7ae02f;	/* ES 2 */
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x208:	/* PRODUCTION_ID_reg for OMAP2 */
+    case 0x210:	/* PRODUCTION_ID_reg for OMAP3 */
+        switch (s->mpu_model) {
+        case omap2420:
+            return 0x000254f0;	/* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
+        case omap2422:
+            return 0x000400f0;
+        case omap2423:
+            return 0x000800f0;
+        case omap2430:
+            return 0x000000f0;
+        case omap3430:
+            return 0x000000f0;
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x20c:
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0xcafeb5d9;	/* ES 2.2 */
+        case omap2430:
+            return 0xcafeb68a;	/* ES 2.2 */
+        case omap3430:
+            return 0xcafeb7ae;	/* ES 2 */
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x218:	/* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x21c:	/* DIE_ID_reg */
+        return 0x54 << 24;
+    case 0x220:	/* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x224:	/* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tap_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc * const omap_tap_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_tap_read,
+};
+
+static CPUWriteMemoryFunc * const omap_tap_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_tap_write,
+};
+
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu)
+{
+    omap_l4_attach(ta, 0, l4_register_io_memory(
+                            omap_tap_readfn, omap_tap_writefn, mpu));
+}
diff --git a/qemu-0.15.x/hw/omap_uart.c b/qemu-0.15.x/hw/omap_uart.c
new file mode 100644
index 0000000..9cee81d
--- /dev/null
+++ b/qemu-0.15.x/hw/omap_uart.c
@@ -0,0 +1,196 @@
+/*
+ * TI OMAP processors UART emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-char.h"
+#include "hw.h"
+#include "omap.h"
+/* We use pc-style serial ports.  */
+#include "pc.h"
+
+/* UARTs */
+struct omap_uart_s {
+    target_phys_addr_t base;
+    SerialState *serial; /* TODO */
+    struct omap_target_agent_s *ta;
+    omap_clk fclk;
+    qemu_irq irq;
+
+    uint8_t eblr;
+    uint8_t syscontrol;
+    uint8_t wkup;
+    uint8_t cfps;
+    uint8_t mdr[2];
+    uint8_t scr;
+    uint8_t clksel;
+};
+
+void omap_uart_reset(struct omap_uart_s *s)
+{
+    s->eblr = 0x00;
+    s->syscontrol = 0;
+    s->wkup = 0x3f;
+    s->cfps = 0x69;
+    s->clksel = 0;
+}
+
+struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *)
+            qemu_mallocz(sizeof(struct omap_uart_s));
+
+    s->base = base;
+    s->fclk = fclk;
+    s->irq = irq;
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
+                               chr ?: qemu_chr_open(label, "null", NULL), 1,
+                               1);
+#else
+    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
+                               chr ?: qemu_chr_open(label, "null", NULL), 1,
+                               0);
+#endif
+    return s;
+}
+
+static uint32_t omap_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+    addr &= 0xff;
+    switch (addr) {
+    case 0x20:	/* MDR1 */
+        return s->mdr[0];
+    case 0x24:	/* MDR2 */
+        return s->mdr[1];
+    case 0x40:	/* SCR */
+        return s->scr;
+    case 0x44:	/* SSR */
+        return 0x0;
+    case 0x48:	/* EBLR (OMAP2) */
+        return s->eblr;
+    case 0x4C:	/* OSC_12M_SEL (OMAP1) */
+        return s->clksel;
+    case 0x50:	/* MVR */
+        return 0x30;
+    case 0x54:	/* SYSC (OMAP2) */
+        return s->syscontrol;
+    case 0x58:	/* SYSS (OMAP2) */
+        return 1;
+    case 0x5c:	/* WER (OMAP2) */
+        return s->wkup;
+    case 0x60:	/* CFPS (OMAP2) */
+        return s->cfps;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_uart_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+    addr &= 0xff;
+    switch (addr) {
+    case 0x20:	/* MDR1 */
+        s->mdr[0] = value & 0x7f;
+        break;
+    case 0x24:	/* MDR2 */
+        s->mdr[1] = value & 0xff;
+        break;
+    case 0x40:	/* SCR */
+        s->scr = value & 0xff;
+        break;
+    case 0x48:	/* EBLR (OMAP2) */
+        s->eblr = value & 0xff;
+        break;
+    case 0x4C:	/* OSC_12M_SEL (OMAP1) */
+        s->clksel = value & 1;
+        break;
+    case 0x44:	/* SSR */
+    case 0x50:	/* MVR */
+    case 0x58:	/* SYSS (OMAP2) */
+        OMAP_RO_REG(addr);
+        break;
+    case 0x54:	/* SYSC (OMAP2) */
+        s->syscontrol = value & 0x1d;
+        if (value & 2)
+            omap_uart_reset(s);
+        break;
+    case 0x5c:	/* WER (OMAP2) */
+        s->wkup = value & 0x7f;
+        break;
+    case 0x60:	/* CFPS (OMAP2) */
+        s->cfps = value & 0xff;
+        break;
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc * const omap_uart_readfn[] = {
+    omap_uart_read,
+    omap_uart_read,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc * const omap_uart_writefn[] = {
+    omap_uart_write,
+    omap_uart_write,
+    omap_badwidth_write8,
+};
+
+struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
+{
+    target_phys_addr_t base = omap_l4_attach(ta, 0, 0);
+    struct omap_uart_s *s = omap_uart_init(base, irq,
+                    fclk, iclk, txdma, rxdma, label, chr);
+    int iomemtype = cpu_register_io_memory(omap_uart_readfn,
+                    omap_uart_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    s->ta = ta;
+
+    cpu_register_physical_memory(base + 0x20, 0x100, iomemtype);
+
+    return s;
+}
+
+void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
+{
+    /* TODO: Should reuse or destroy current s->serial */
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->serial = serial_mm_init(s->base, 2, s->irq,
+                               omap_clk_getrate(s->fclk) / 16,
+                               chr ?: qemu_chr_open("null", "null", NULL), 1,
+                               1);
+#else
+    s->serial = serial_mm_init(s->base, 2, s->irq,
+                               omap_clk_getrate(s->fclk) / 16,
+                               chr ?: qemu_chr_open("null", "null", NULL), 1,
+                               0);
+#endif
+}
diff --git a/qemu-0.15.x/hw/onenand.c b/qemu-0.15.x/hw/onenand.c
new file mode 100644
index 0000000..71c1ab4
--- /dev/null
+++ b/qemu-0.15.x/hw/onenand.c
@@ -0,0 +1,661 @@
+/*
+ * OneNAND flash memories emulation.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "hw.h"
+#include "flash.h"
+#include "irq.h"
+#include "blockdev.h"
+
+/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
+#define PAGE_SHIFT	11
+
+/* Fixed */
+#define BLOCK_SHIFT	(PAGE_SHIFT + 6)
+
+typedef struct {
+    uint32_t id;
+    int shift;
+    target_phys_addr_t base;
+    qemu_irq intr;
+    qemu_irq rdy;
+    BlockDriverState *bdrv;
+    BlockDriverState *bdrv_cur;
+    uint8_t *image;
+    uint8_t *otp;
+    uint8_t *current;
+    ram_addr_t ram;
+    uint8_t *boot[2];
+    uint8_t *data[2][2];
+    int iomemtype;
+    int cycle;
+    int otpmode;
+
+    uint16_t addr[8];
+    uint16_t unladdr[8];
+    int bufaddr;
+    int count;
+    uint16_t command;
+    uint16_t config[2];
+    uint16_t status;
+    uint16_t intstatus;
+    uint16_t wpstatus;
+
+    ECCState ecc;
+
+    int density_mask;
+    int secs;
+    int secs_cur;
+    int blocks;
+    uint8_t *blockwp;
+} OneNANDState;
+
+enum {
+    ONEN_BUF_BLOCK = 0,
+    ONEN_BUF_BLOCK2 = 1,
+    ONEN_BUF_DEST_BLOCK = 2,
+    ONEN_BUF_DEST_PAGE = 3,
+    ONEN_BUF_PAGE = 7,
+};
+
+enum {
+    ONEN_ERR_CMD = 1 << 10,
+    ONEN_ERR_ERASE = 1 << 11,
+    ONEN_ERR_PROG = 1 << 12,
+    ONEN_ERR_LOAD = 1 << 13,
+};
+
+enum {
+    ONEN_INT_RESET = 1 << 4,
+    ONEN_INT_ERASE = 1 << 5,
+    ONEN_INT_PROG = 1 << 6,
+    ONEN_INT_LOAD = 1 << 7,
+    ONEN_INT = 1 << 15,
+};
+
+enum {
+    ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
+    ONEN_LOCK_LOCKED = 1 << 1,
+    ONEN_LOCK_UNLOCKED = 1 << 2,
+};
+
+void onenand_base_update(void *opaque, target_phys_addr_t new)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+
+    s->base = new;
+
+    /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
+     * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
+     * write boot commands.  Also take note of the BWPS bit.  */
+    cpu_register_physical_memory(s->base + (0x0000 << s->shift),
+                    0x0200 << s->shift, s->iomemtype);
+    cpu_register_physical_memory(s->base + (0x0200 << s->shift),
+                    0xbe00 << s->shift,
+                    (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM);
+    if (s->iomemtype)
+        cpu_register_physical_memory_offset(s->base + (0xc000 << s->shift),
+                    0x4000 << s->shift, s->iomemtype, (0xc000 << s->shift));
+}
+
+void onenand_base_unmap(void *opaque)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+
+    cpu_register_physical_memory(s->base,
+                    0x10000 << s->shift, IO_MEM_UNASSIGNED);
+}
+
+static void onenand_intr_update(OneNANDState *s)
+{
+    qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
+}
+
+/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
+static void onenand_reset(OneNANDState *s, int cold)
+{
+    memset(&s->addr, 0, sizeof(s->addr));
+    s->command = 0;
+    s->count = 1;
+    s->bufaddr = 0;
+    s->config[0] = 0x40c0;
+    s->config[1] = 0x0000;
+    onenand_intr_update(s);
+    qemu_irq_raise(s->rdy);
+    s->status = 0x0000;
+    s->intstatus = cold ? 0x8080 : 0x8010;
+    s->unladdr[0] = 0;
+    s->unladdr[1] = 0;
+    s->wpstatus = 0x0002;
+    s->cycle = 0;
+    s->otpmode = 0;
+    s->bdrv_cur = s->bdrv;
+    s->current = s->image;
+    s->secs_cur = s->secs;
+
+    if (cold) {
+        /* Lock the whole flash */
+        memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
+
+        if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0)
+            hw_error("%s: Loading the BootRAM failed.\n", __FUNCTION__);
+    }
+}
+
+static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
+                void *dest)
+{
+    if (s->bdrv_cur)
+        return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
+    else if (sec + secn > s->secs_cur)
+        return 1;
+
+    memcpy(dest, s->current + (sec << 9), secn << 9);
+
+    return 0;
+}
+
+static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
+                void *src)
+{
+    if (s->bdrv_cur)
+        return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
+    else if (sec + secn > s->secs_cur)
+        return 1;
+
+    memcpy(s->current + (sec << 9), src, secn << 9);
+
+    return 0;
+}
+
+static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
+                void *dest)
+{
+    uint8_t buf[512];
+
+    if (s->bdrv_cur) {
+        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
+            return 1;
+        memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
+    } else if (sec + secn > s->secs_cur)
+        return 1;
+    else
+        memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
+ 
+    return 0;
+}
+
+static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
+                void *src)
+{
+    uint8_t buf[512];
+
+    if (s->bdrv_cur) {
+        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
+            return 1;
+        memcpy(buf + ((sec & 31) << 4), src, secn << 4);
+        return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
+    } else if (sec + secn > s->secs_cur)
+        return 1;
+
+    memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
+ 
+    return 0;
+}
+
+static inline int onenand_erase(OneNANDState *s, int sec, int num)
+{
+    /* TODO: optimise */
+    uint8_t buf[512];
+
+    memset(buf, 0xff, sizeof(buf));
+    for (; num > 0; num --, sec ++) {
+        if (onenand_prog_main(s, sec, 1, buf))
+            return 1;
+        if (onenand_prog_spare(s, sec, 1, buf))
+            return 1;
+    }
+
+    return 0;
+}
+
+static void onenand_command(OneNANDState *s, int cmd)
+{
+    int b;
+    int sec;
+    void *buf;
+#define SETADDR(block, page)			\
+    sec = (s->addr[page] & 3) +			\
+            ((((s->addr[page] >> 2) & 0x3f) +	\
+              (((s->addr[block] & 0xfff) |	\
+                (s->addr[block] >> 15 ?		\
+                 s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
+#define SETBUF_M()				\
+    buf = (s->bufaddr & 8) ?			\
+            s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0];	\
+    buf += (s->bufaddr & 3) << 9;
+#define SETBUF_S()				\
+    buf = (s->bufaddr & 8) ?			\
+            s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];	\
+    buf += (s->bufaddr & 3) << 4;
+
+    switch (cmd) {
+    case 0x00:	/* Load single/multiple sector data unit into buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_M()
+        if (onenand_load_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+
+#if 0
+        SETBUF_S()
+        if (onenand_load_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+#endif
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
+        break;
+    case 0x13:	/* Load single/multiple spare sector into buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_S()
+        if (onenand_load_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
+        break;
+    case 0x80:	/* Program single/multiple sector data unit from buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_M()
+        if (onenand_prog_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+#if 0
+        SETBUF_S()
+        if (onenand_prog_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+#endif
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+    case 0x1a:	/* Program single/multiple spare area sector from buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_S()
+        if (onenand_prog_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+    case 0x1b:	/* Copy-back program */
+        SETBUF_S()
+
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+        if (onenand_load_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
+        if (onenand_prog_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        /* TODO: spare areas */
+
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+
+    case 0x23:	/* Unlock NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        /* XXX the previous (?) area should be locked automatically */
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
+        }
+        break;
+    case 0x27:	/* Unlock All NAND array blocks */
+        s->intstatus |= ONEN_INT;
+
+        for (b = 0; b < s->blocks; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
+        }
+        break;
+
+    case 0x2a:	/* Lock NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
+        }
+        break;
+    case 0x2c:	/* Lock-tight NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
+                continue;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
+        }
+        break;
+
+    case 0x71:	/* Erase-Verify-Read */
+        s->intstatus |= ONEN_INT;
+        break;
+    case 0x95:	/* Multi-block erase */
+        qemu_irq_pulse(s->intr);
+        /* Fall through.  */
+    case 0x94:	/* Block erase */
+        sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
+                        (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
+                << (BLOCK_SHIFT - 9);
+        if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
+
+        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
+        break;
+    case 0xb0:	/* Erase suspend */
+        break;
+    case 0x30:	/* Erase resume */
+        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
+        break;
+
+    case 0xf0:	/* Reset NAND Flash core */
+        onenand_reset(s, 0);
+        break;
+    case 0xf3:	/* Reset OneNAND */
+        onenand_reset(s, 0);
+        break;
+
+    case 0x65:	/* OTP Access */
+        s->intstatus |= ONEN_INT;
+        s->bdrv_cur = NULL;
+        s->current = s->otp;
+        s->secs_cur = 1 << (BLOCK_SHIFT - 9);
+        s->addr[ONEN_BUF_BLOCK] = 0;
+        s->otpmode = 1;
+        break;
+
+    default:
+        s->status |= ONEN_ERR_CMD;
+        s->intstatus |= ONEN_INT;
+        fprintf(stderr, "%s: unknown OneNAND command %x\n",
+                        __FUNCTION__, cmd);
+    }
+
+    onenand_intr_update(s);
+}
+
+static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+    int offset = addr >> s->shift;
+
+    switch (offset) {
+    case 0x0000 ... 0xc000:
+        return lduw_le_p(s->boot[0] + addr);
+
+    case 0xf000:	/* Manufacturer ID */
+        return (s->id >> 16) & 0xff;
+    case 0xf001:	/* Device ID */
+        return (s->id >>  8) & 0xff;
+    /* TODO: get the following values from a real chip!  */
+    case 0xf002:	/* Version ID */
+        return (s->id >>  0) & 0xff;
+    case 0xf003:	/* Data Buffer size */
+        return 1 << PAGE_SHIFT;
+    case 0xf004:	/* Boot Buffer size */
+        return 0x200;
+    case 0xf005:	/* Amount of buffers */
+        return 1 | (2 << 8);
+    case 0xf006:	/* Technology */
+        return 0;
+
+    case 0xf100 ... 0xf107:	/* Start addresses */
+        return s->addr[offset - 0xf100];
+
+    case 0xf200:	/* Start buffer */
+        return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
+
+    case 0xf220:	/* Command */
+        return s->command;
+    case 0xf221:	/* System Configuration 1 */
+        return s->config[0] & 0xffe0;
+    case 0xf222:	/* System Configuration 2 */
+        return s->config[1];
+
+    case 0xf240:	/* Controller Status */
+        return s->status;
+    case 0xf241:	/* Interrupt */
+        return s->intstatus;
+    case 0xf24c:	/* Unlock Start Block Address */
+        return s->unladdr[0];
+    case 0xf24d:	/* Unlock End Block Address */
+        return s->unladdr[1];
+    case 0xf24e:	/* Write Protection Status */
+        return s->wpstatus;
+
+    case 0xff00:	/* ECC Status */
+        return 0x00;
+    case 0xff01:	/* ECC Result of main area data */
+    case 0xff02:	/* ECC Result of spare area data */
+    case 0xff03:	/* ECC Result of main area data */
+    case 0xff04:	/* ECC Result of spare area data */
+        hw_error("%s: imeplement ECC\n", __FUNCTION__);
+        return 0x0000;
+    }
+
+    fprintf(stderr, "%s: unknown OneNAND register %x\n",
+                    __FUNCTION__, offset);
+    return 0;
+}
+
+static void onenand_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+    int offset = addr >> s->shift;
+    int sec;
+
+    switch (offset) {
+    case 0x0000 ... 0x01ff:
+    case 0x8000 ... 0x800f:
+        if (s->cycle) {
+            s->cycle = 0;
+
+            if (value == 0x0000) {
+                SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+                onenand_load_main(s, sec,
+                                1 << (PAGE_SHIFT - 9), s->data[0][0]);
+                s->addr[ONEN_BUF_PAGE] += 4;
+                s->addr[ONEN_BUF_PAGE] &= 0xff;
+            }
+            break;
+        }
+
+        switch (value) {
+        case 0x00f0:	/* Reset OneNAND */
+            onenand_reset(s, 0);
+            break;
+
+        case 0x00e0:	/* Load Data into Buffer */
+            s->cycle = 1;
+            break;
+
+        case 0x0090:	/* Read Identification Data */
+            memset(s->boot[0], 0, 3 << s->shift);
+            s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
+            s->boot[0][1 << s->shift] = (s->id >>  8) & 0xff;
+            s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
+            break;
+
+        default:
+            fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
+                            __FUNCTION__, value);
+        }
+        break;
+
+    case 0xf100 ... 0xf107:	/* Start addresses */
+        s->addr[offset - 0xf100] = value;
+        break;
+
+    case 0xf200:	/* Start buffer */
+        s->bufaddr = (value >> 8) & 0xf;
+        if (PAGE_SHIFT == 11)
+            s->count = (value & 3) ?: 4;
+        else if (PAGE_SHIFT == 10)
+            s->count = (value & 1) ?: 2;
+        break;
+
+    case 0xf220:	/* Command */
+        if (s->intstatus & (1 << 15))
+            break;
+        s->command = value;
+        onenand_command(s, s->command);
+        break;
+    case 0xf221:	/* System Configuration 1 */
+        s->config[0] = value;
+        onenand_intr_update(s);
+        qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
+        break;
+    case 0xf222:	/* System Configuration 2 */
+        s->config[1] = value;
+        break;
+
+    case 0xf241:	/* Interrupt */
+        s->intstatus &= value;
+        if ((1 << 15) & ~s->intstatus)
+            s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
+                            ONEN_ERR_PROG | ONEN_ERR_LOAD);
+        onenand_intr_update(s);
+        break;
+    case 0xf24c:	/* Unlock Start Block Address */
+        s->unladdr[0] = value & (s->blocks - 1);
+        /* For some reason we have to set the end address to by default
+         * be same as start because the software forgets to write anything
+         * in there.  */
+        s->unladdr[1] = value & (s->blocks - 1);
+        break;
+    case 0xf24d:	/* Unlock End Block Address */
+        s->unladdr[1] = value & (s->blocks - 1);
+        break;
+
+    default:
+        fprintf(stderr, "%s: unknown OneNAND register %x\n",
+                        __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const onenand_readfn[] = {
+    onenand_read,	/* TODO */
+    onenand_read,
+    onenand_read,
+};
+
+static CPUWriteMemoryFunc * const onenand_writefn[] = {
+    onenand_write,	/* TODO */
+    onenand_write,
+    onenand_write,
+};
+
+void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+{
+    OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
+    DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
+    uint32_t size = 1 << (24 + ((id >> 12) & 7));
+    void *ram;
+
+    s->shift = regshift;
+    s->intr = irq;
+    s->rdy = NULL;
+    s->id = id;
+    s->blocks = size >> BLOCK_SHIFT;
+    s->secs = size >> 9;
+    s->blockwp = qemu_malloc(s->blocks);
+    s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
+    s->iomemtype = cpu_register_io_memory(onenand_readfn,
+                    onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
+    if (!dinfo)
+        s->image = memset(qemu_malloc(size + (size >> 5)),
+                        0xff, size + (size >> 5));
+    else
+        s->bdrv = dinfo->bdrv;
+    s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
+                    0xff, (64 + 2) << PAGE_SHIFT);
+    s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
+    ram = qemu_get_ram_ptr(s->ram);
+    s->boot[0] = ram + (0x0000 << s->shift);
+    s->boot[1] = ram + (0x8000 << s->shift);
+    s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
+    s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
+    s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
+    s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
+
+    onenand_reset(s, 1);
+
+    return s;
+}
+
+void *onenand_raw_otp(void *opaque)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+
+    return s->otp;
+}
diff --git a/qemu-0.15.x/hw/openpic.c b/qemu-0.15.x/hw/openpic.c
new file mode 100644
index 0000000..6d2cf99
--- /dev/null
+++ b/qemu-0.15.x/hw/openpic.c
@@ -0,0 +1,1686 @@
+/*
+ * OpenPIC emulation
+ *
+ * Copyright (c) 2004 Jocelyn Mayer
+ *
+ * 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.
+ */
+/*
+ *
+ * Based on OpenPic implementations:
+ * - Intel GW80314 I/O companion chip developer's manual
+ * - Motorola MPC8245 & MPC8540 user manuals.
+ * - Motorola MCP750 (aka Raven) programmer manual.
+ * - Motorola Harrier programmer manuel
+ *
+ * Serial interrupts, as implemented in Raven chipset are not supported yet.
+ *
+ */
+#include "hw.h"
+#include "ppc_mac.h"
+#include "pci.h"
+#include "openpic.h"
+
+//#define DEBUG_OPENPIC
+
+#ifdef DEBUG_OPENPIC
+#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define USE_MPCxxx /* Intel model is broken, for now */
+
+#if defined (USE_INTEL_GW80314)
+/* Intel GW80314 I/O Companion chip */
+
+#define MAX_CPU     4
+#define MAX_IRQ    32
+#define MAX_DBL     4
+#define MAX_MBX     4
+#define MAX_TMR     4
+#define VECTOR_BITS 8
+#define MAX_IPI     0
+
+#define VID (0x00000000)
+
+#elif defined(USE_MPCxxx)
+
+#define MAX_CPU     2
+#define MAX_IRQ   128
+#define MAX_DBL     0
+#define MAX_MBX     0
+#define MAX_TMR     4
+#define VECTOR_BITS 8
+#define MAX_IPI     4
+#define VID         0x03 /* MPIC version ID */
+#define VENI        0x00000000 /* Vendor ID */
+
+enum {
+    IRQ_IPVP = 0,
+    IRQ_IDE,
+};
+
+/* OpenPIC */
+#define OPENPIC_MAX_CPU      2
+#define OPENPIC_MAX_IRQ     64
+#define OPENPIC_EXT_IRQ     48
+#define OPENPIC_MAX_TMR      MAX_TMR
+#define OPENPIC_MAX_IPI      MAX_IPI
+
+/* Interrupt definitions */
+#define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
+#define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
+#define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
+#if OPENPIC_MAX_IPI > 0
+#define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
+#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
+#else
+#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
+#define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
+#endif
+
+/* MPIC */
+#define MPIC_MAX_CPU      1
+#define MPIC_MAX_EXT     12
+#define MPIC_MAX_INT     64
+#define MPIC_MAX_MSG      4
+#define MPIC_MAX_MSI      8
+#define MPIC_MAX_TMR      MAX_TMR
+#define MPIC_MAX_IPI      MAX_IPI
+#define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
+
+/* Interrupt definitions */
+#define MPIC_EXT_IRQ      0
+#define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
+#define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
+#define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
+#define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
+#define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
+
+#define MPIC_GLB_REG_START        0x0
+#define MPIC_GLB_REG_SIZE         0x10F0
+#define MPIC_TMR_REG_START        0x10F0
+#define MPIC_TMR_REG_SIZE         0x220
+#define MPIC_EXT_REG_START        0x10000
+#define MPIC_EXT_REG_SIZE         0x180
+#define MPIC_INT_REG_START        0x10200
+#define MPIC_INT_REG_SIZE         0x800
+#define MPIC_MSG_REG_START        0x11600
+#define MPIC_MSG_REG_SIZE         0x100
+#define MPIC_MSI_REG_START        0x11C00
+#define MPIC_MSI_REG_SIZE         0x100
+#define MPIC_CPU_REG_START        0x20000
+#define MPIC_CPU_REG_SIZE         0x100
+
+enum mpic_ide_bits {
+    IDR_EP     = 0,
+    IDR_CI0     = 1,
+    IDR_CI1     = 2,
+    IDR_P1     = 30,
+    IDR_P0     = 31,
+};
+
+#else
+#error "Please select which OpenPic implementation is to be emulated"
+#endif
+
+#define OPENPIC_PAGE_SIZE 4096
+
+#define BF_WIDTH(_bits_) \
+(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
+
+static inline void set_bit (uint32_t *field, int bit)
+{
+    field[bit >> 5] |= 1 << (bit & 0x1F);
+}
+
+static inline void reset_bit (uint32_t *field, int bit)
+{
+    field[bit >> 5] &= ~(1 << (bit & 0x1F));
+}
+
+static inline int test_bit (uint32_t *field, int bit)
+{
+    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
+}
+
+enum {
+    IRQ_EXTERNAL = 0x01,
+    IRQ_INTERNAL = 0x02,
+    IRQ_TIMER    = 0x04,
+    IRQ_SPECIAL  = 0x08,
+};
+
+typedef struct IRQ_queue_t {
+    uint32_t queue[BF_WIDTH(MAX_IRQ)];
+    int next;
+    int priority;
+} IRQ_queue_t;
+
+typedef struct IRQ_src_t {
+    uint32_t ipvp;  /* IRQ vector/priority register */
+    uint32_t ide;   /* IRQ destination register */
+    int type;
+    int last_cpu;
+    int pending;    /* TRUE if IRQ is pending */
+} IRQ_src_t;
+
+enum IPVP_bits {
+    IPVP_MASK     = 31,
+    IPVP_ACTIVITY = 30,
+    IPVP_MODE     = 29,
+    IPVP_POLARITY = 23,
+    IPVP_SENSE    = 22,
+};
+#define IPVP_PRIORITY_MASK     (0x1F << 16)
+#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
+#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
+#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
+
+typedef struct IRQ_dst_t {
+    uint32_t tfrr;
+    uint32_t pctp; /* CPU current task priority */
+    uint32_t pcsr; /* CPU sensitivity register */
+    IRQ_queue_t raised;
+    IRQ_queue_t servicing;
+    qemu_irq *irqs;
+} IRQ_dst_t;
+
+typedef struct openpic_t {
+    PCIDevice pci_dev;
+    int mem_index;
+    /* Global registers */
+    uint32_t frep; /* Feature reporting register */
+    uint32_t glbc; /* Global configuration register  */
+    uint32_t micr; /* MPIC interrupt configuration register */
+    uint32_t veni; /* Vendor identification register */
+    uint32_t pint; /* Processor initialization register */
+    uint32_t spve; /* Spurious vector register */
+    uint32_t tifr; /* Timer frequency reporting register */
+    /* Source registers */
+    IRQ_src_t src[MAX_IRQ];
+    /* Local registers per output pin */
+    IRQ_dst_t dst[MAX_CPU];
+    int nb_cpus;
+    /* Timer registers */
+    struct {
+        uint32_t ticc;  /* Global timer current count register */
+        uint32_t tibc;  /* Global timer base count register */
+    } timers[MAX_TMR];
+#if MAX_DBL > 0
+    /* Doorbell registers */
+    uint32_t dar;        /* Doorbell activate register */
+    struct {
+        uint32_t dmr;    /* Doorbell messaging register */
+    } doorbells[MAX_DBL];
+#endif
+#if MAX_MBX > 0
+    /* Mailbox registers */
+    struct {
+        uint32_t mbr;    /* Mailbox register */
+    } mailboxes[MAX_MAILBOXES];
+#endif
+    /* IRQ out is used when in bypass mode (not implemented) */
+    qemu_irq irq_out;
+    int max_irq;
+    int irq_ipi0;
+    int irq_tim0;
+    void (*reset) (void *);
+    void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
+} openpic_t;
+
+static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
+{
+    set_bit(q->queue, n_IRQ);
+}
+
+static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
+{
+    reset_bit(q->queue, n_IRQ);
+}
+
+static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
+{
+    return test_bit(q->queue, n_IRQ);
+}
+
+static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
+{
+    int next, i;
+    int priority;
+
+    next = -1;
+    priority = -1;
+    for (i = 0; i < opp->max_irq; i++) {
+        if (IRQ_testbit(q, i)) {
+            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
+                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
+            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
+                next = i;
+                priority = IPVP_PRIORITY(opp->src[i].ipvp);
+            }
+        }
+    }
+    q->next = next;
+    q->priority = priority;
+}
+
+static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
+{
+    if (q->next == -1) {
+        /* XXX: optimize */
+        IRQ_check(opp, q);
+    }
+
+    return q->next;
+}
+
+static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
+{
+    IRQ_dst_t *dst;
+    IRQ_src_t *src;
+    int priority;
+
+    dst = &opp->dst[n_CPU];
+    src = &opp->src[n_IRQ];
+    priority = IPVP_PRIORITY(src->ipvp);
+    if (priority <= dst->pctp) {
+        /* Too low priority */
+        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
+        return;
+    }
+    if (IRQ_testbit(&dst->raised, n_IRQ)) {
+        /* Interrupt miss */
+        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
+        return;
+    }
+    set_bit(&src->ipvp, IPVP_ACTIVITY);
+    IRQ_setbit(&dst->raised, n_IRQ);
+    if (priority < dst->raised.priority) {
+        /* An higher priority IRQ is already raised */
+        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->raised.next, n_CPU);
+        return;
+    }
+    IRQ_get_next(opp, &dst->raised);
+    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
+        priority <= dst->servicing.priority) {
+        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->servicing.next, n_CPU);
+        /* Already servicing a higher priority IRQ */
+        return;
+    }
+    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
+    opp->irq_raise(opp, n_CPU, src);
+}
+
+/* update pic state because registers for n_IRQ have changed value */
+static void openpic_update_irq(openpic_t *opp, int n_IRQ)
+{
+    IRQ_src_t *src;
+    int i;
+
+    src = &opp->src[n_IRQ];
+
+    if (!src->pending) {
+        /* no irq pending */
+        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
+        return;
+    }
+    if (test_bit(&src->ipvp, IPVP_MASK)) {
+        /* Interrupt source is disabled */
+        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
+        return;
+    }
+    if (IPVP_PRIORITY(src->ipvp) == 0) {
+        /* Priority set to zero */
+        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
+        return;
+    }
+    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
+        /* IRQ already active */
+        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
+        return;
+    }
+    if (src->ide == 0x00000000) {
+        /* No target */
+        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
+        return;
+    }
+
+    if (src->ide == (1 << src->last_cpu)) {
+        /* Only one CPU is allowed to receive this IRQ */
+        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
+    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
+        /* Directed delivery mode */
+        for (i = 0; i < opp->nb_cpus; i++) {
+            if (test_bit(&src->ide, i))
+                IRQ_local_pipe(opp, i, n_IRQ);
+        }
+    } else {
+        /* Distributed delivery mode */
+        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+            if (i == opp->nb_cpus)
+                i = 0;
+            if (test_bit(&src->ide, i)) {
+                IRQ_local_pipe(opp, i, n_IRQ);
+                src->last_cpu = i;
+                break;
+            }
+        }
+    }
+}
+
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
+{
+    openpic_t *opp = opaque;
+    IRQ_src_t *src;
+
+    src = &opp->src[n_IRQ];
+    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
+            n_IRQ, level, src->ipvp);
+    if (test_bit(&src->ipvp, IPVP_SENSE)) {
+        /* level-sensitive irq */
+        src->pending = level;
+        if (!level)
+            reset_bit(&src->ipvp, IPVP_ACTIVITY);
+    } else {
+        /* edge-sensitive irq */
+        if (level)
+            src->pending = 1;
+    }
+    openpic_update_irq(opp, n_IRQ);
+}
+
+static void openpic_reset (void *opaque)
+{
+    openpic_t *opp = (openpic_t *)opaque;
+    int i;
+
+    opp->glbc = 0x80000000;
+    /* Initialise controller registers */
+    opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
+    opp->veni = VENI;
+    opp->pint = 0x00000000;
+    opp->spve = 0x000000FF;
+    opp->tifr = 0x003F7A00;
+    /* ? */
+    opp->micr = 0x00000000;
+    /* Initialise IRQ sources */
+    for (i = 0; i < opp->max_irq; i++) {
+        opp->src[i].ipvp = 0xA0000000;
+        opp->src[i].ide  = 0x00000000;
+    }
+    /* Initialise IRQ destinations */
+    for (i = 0; i < MAX_CPU; i++) {
+        opp->dst[i].pctp      = 0x0000000F;
+        opp->dst[i].pcsr      = 0x00000000;
+        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
+        opp->dst[i].raised.next = -1;
+        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
+        opp->dst[i].servicing.next = -1;
+    }
+    /* Initialise timers */
+    for (i = 0; i < MAX_TMR; i++) {
+        opp->timers[i].ticc = 0x00000000;
+        opp->timers[i].tibc = 0x80000000;
+    }
+    /* Initialise doorbells */
+#if MAX_DBL > 0
+    opp->dar = 0x00000000;
+    for (i = 0; i < MAX_DBL; i++) {
+        opp->doorbells[i].dmr  = 0x00000000;
+    }
+#endif
+    /* Initialise mailboxes */
+#if MAX_MBX > 0
+    for (i = 0; i < MAX_MBX; i++) { /* ? */
+        opp->mailboxes[i].mbr   = 0x00000000;
+    }
+#endif
+    /* Go out of RESET state */
+    opp->glbc = 0x00000000;
+}
+
+static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
+{
+    uint32_t retval;
+
+    switch (reg) {
+    case IRQ_IPVP:
+        retval = opp->src[n_IRQ].ipvp;
+        break;
+    case IRQ_IDE:
+        retval = opp->src[n_IRQ].ide;
+        break;
+    }
+
+    return retval;
+}
+
+static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
+                                 uint32_t reg, uint32_t val)
+{
+    uint32_t tmp;
+
+    switch (reg) {
+    case IRQ_IPVP:
+        /* NOTE: not fully accurate for special IRQs, but simple and
+           sufficient */
+        /* ACTIVITY bit is read-only */
+        opp->src[n_IRQ].ipvp =
+            (opp->src[n_IRQ].ipvp & 0x40000000) |
+            (val & 0x800F00FF);
+        openpic_update_irq(opp, n_IRQ);
+        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
+                n_IRQ, val, opp->src[n_IRQ].ipvp);
+        break;
+    case IRQ_IDE:
+        tmp = val & 0xC0000000;
+        tmp |= val & ((1 << MAX_CPU) - 1);
+        opp->src[n_IRQ].ide = tmp;
+        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
+        break;
+    }
+}
+
+#if 0 // Code provision for Intel model
+#if MAX_DBL > 0
+static uint32_t read_doorbell_register (openpic_t *opp,
+                                        int n_dbl, uint32_t offset)
+{
+    uint32_t retval;
+
+    switch (offset) {
+    case DBL_IPVP_OFFSET:
+        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
+        break;
+    case DBL_IDE_OFFSET:
+        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
+        break;
+    case DBL_DMR_OFFSET:
+        retval = opp->doorbells[n_dbl].dmr;
+        break;
+    }
+
+    return retval;
+}
+
+static void write_doorbell_register (penpic_t *opp, int n_dbl,
+                                     uint32_t offset, uint32_t value)
+{
+    switch (offset) {
+    case DBL_IVPR_OFFSET:
+        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
+        break;
+    case DBL_IDE_OFFSET:
+        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
+        break;
+    case DBL_DMR_OFFSET:
+        opp->doorbells[n_dbl].dmr = value;
+        break;
+    }
+}
+#endif
+
+#if MAX_MBX > 0
+static uint32_t read_mailbox_register (openpic_t *opp,
+                                       int n_mbx, uint32_t offset)
+{
+    uint32_t retval;
+
+    switch (offset) {
+    case MBX_MBR_OFFSET:
+        retval = opp->mailboxes[n_mbx].mbr;
+        break;
+    case MBX_IVPR_OFFSET:
+        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
+        break;
+    case MBX_DMR_OFFSET:
+        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
+        break;
+    }
+
+    return retval;
+}
+
+static void write_mailbox_register (openpic_t *opp, int n_mbx,
+                                    uint32_t address, uint32_t value)
+{
+    switch (offset) {
+    case MBX_MBR_OFFSET:
+        opp->mailboxes[n_mbx].mbr = value;
+        break;
+    case MBX_IVPR_OFFSET:
+        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
+        break;
+    case MBX_DMR_OFFSET:
+        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
+        break;
+    }
+}
+#endif
+#endif /* 0 : Code provision for Intel model */
+
+static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    openpic_t *opp = opaque;
+    IRQ_dst_t *dst;
+    int idx;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr &= 0xFF;
+    switch (addr) {
+    case 0x00: /* FREP */
+        break;
+    case 0x20: /* GLBC */
+        if (val & 0x80000000 && opp->reset)
+            opp->reset(opp);
+        opp->glbc = val & ~0x80000000;
+        break;
+    case 0x80: /* VENI */
+        break;
+    case 0x90: /* PINT */
+        for (idx = 0; idx < opp->nb_cpus; idx++) {
+            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
+                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
+                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            }
+        }
+        opp->pint = val;
+        break;
+#if MAX_IPI > 0
+    case 0xA0: /* IPI_IPVP */
+    case 0xB0:
+    case 0xC0:
+    case 0xD0:
+        {
+            int idx;
+            idx = (addr - 0xA0) >> 4;
+            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
+        }
+        break;
+#endif
+    case 0xE0: /* SPVE */
+        opp->spve = val & 0x000000FF;
+        break;
+    case 0xF0: /* TIFR */
+        opp->tifr = val;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *opp = opaque;
+    uint32_t retval;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr &= 0xFF;
+    switch (addr) {
+    case 0x00: /* FREP */
+        retval = opp->frep;
+        break;
+    case 0x20: /* GLBC */
+        retval = opp->glbc;
+        break;
+    case 0x80: /* VENI */
+        retval = opp->veni;
+        break;
+    case 0x90: /* PINT */
+        retval = 0x00000000;
+        break;
+#if MAX_IPI > 0
+    case 0xA0: /* IPI_IPVP */
+    case 0xB0:
+    case 0xC0:
+    case 0xD0:
+        {
+            int idx;
+            idx = (addr - 0xA0) >> 4;
+            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
+        }
+        break;
+#endif
+    case 0xE0: /* SPVE */
+        retval = opp->spve;
+        break;
+    case 0xF0: /* TIFR */
+        retval = opp->tifr;
+        break;
+    default:
+        break;
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    openpic_t *opp = opaque;
+    int idx;
+
+    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr -= 0x1100;
+    addr &= 0xFFFF;
+    idx = (addr & 0xFFF0) >> 6;
+    addr = addr & 0x30;
+    switch (addr) {
+    case 0x00: /* TICC */
+        break;
+    case 0x10: /* TIBC */
+        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
+            (val & 0x80000000) == 0 &&
+            (opp->timers[idx].tibc & 0x80000000) != 0)
+            opp->timers[idx].ticc &= ~0x80000000;
+        opp->timers[idx].tibc = val;
+        break;
+    case 0x20: /* TIVP */
+        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
+        break;
+    case 0x30: /* TIDE */
+        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
+        break;
+    }
+}
+
+static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
+{
+    openpic_t *opp = opaque;
+    uint32_t retval;
+    int idx;
+
+    DPRINTF("%s: addr %08x\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr -= 0x1100;
+    addr &= 0xFFFF;
+    idx = (addr & 0xFFF0) >> 6;
+    addr = addr & 0x30;
+    switch (addr) {
+    case 0x00: /* TICC */
+        retval = opp->timers[idx].ticc;
+        break;
+    case 0x10: /* TIBC */
+        retval = opp->timers[idx].tibc;
+        break;
+    case 0x20: /* TIPV */
+        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
+        break;
+    case 0x30: /* TIDE */
+        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
+        break;
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    openpic_t *opp = opaque;
+    int idx;
+
+    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr = addr & 0xFFF0;
+    idx = addr >> 5;
+    if (addr & 0x10) {
+        /* EXDE / IFEDE / IEEDE */
+        write_IRQreg(opp, idx, IRQ_IDE, val);
+    } else {
+        /* EXVP / IFEVP / IEEVP */
+        write_IRQreg(opp, idx, IRQ_IPVP, val);
+    }
+}
+
+static uint32_t openpic_src_read (void *opaque, uint32_t addr)
+{
+    openpic_t *opp = opaque;
+    uint32_t retval;
+    int idx;
+
+    DPRINTF("%s: addr %08x\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr = addr & 0xFFF0;
+    idx = addr >> 5;
+    if (addr & 0x10) {
+        /* EXDE / IFEDE / IEEDE */
+        retval = read_IRQreg(opp, idx, IRQ_IDE);
+    } else {
+        /* EXVP / IFEVP / IEEVP */
+        retval = read_IRQreg(opp, idx, IRQ_IPVP);
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    openpic_t *opp = opaque;
+    IRQ_src_t *src;
+    IRQ_dst_t *dst;
+    int idx, s_IRQ, n_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr &= 0x1FFF0;
+    idx = addr / 0x1000;
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+#if MAX_IPI > 0
+    case 0x40: /* PIPD */
+    case 0x50:
+    case 0x60:
+    case 0x70:
+        idx = (addr - 0x40) >> 4;
+        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
+        break;
+#endif
+    case 0x80: /* PCTP */
+        dst->pctp = val & 0x0000000F;
+        break;
+    case 0x90: /* WHOAMI */
+        /* Read-only register */
+        break;
+    case 0xA0: /* PIAC */
+        /* Read-only register */
+        break;
+    case 0xB0: /* PEOI */
+        DPRINTF("PEOI\n");
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        IRQ_resetbit(&dst->servicing, s_IRQ);
+        dst->servicing.next = -1;
+        /* Set up next servicing IRQ */
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        /* Check queued interrupts. */
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        src = &opp->src[n_IRQ];
+        if (n_IRQ != -1 &&
+            (s_IRQ == -1 ||
+             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+                    idx, n_IRQ);
+            opp->irq_raise(opp, idx, src);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *opp = opaque;
+    IRQ_src_t *src;
+    IRQ_dst_t *dst;
+    uint32_t retval;
+    int idx, n_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr &= 0x1FFF0;
+    idx = addr / 0x1000;
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+    case 0x80: /* PCTP */
+        retval = dst->pctp;
+        break;
+    case 0x90: /* WHOAMI */
+        retval = idx;
+        break;
+    case 0xA0: /* PIAC */
+        DPRINTF("Lower OpenPIC INT output\n");
+        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        DPRINTF("PIAC: irq=%d\n", n_IRQ);
+        if (n_IRQ == -1) {
+            /* No more interrupt pending */
+            retval = IPVP_VECTOR(opp->spve);
+        } else {
+            src = &opp->src[n_IRQ];
+            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
+                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
+                /* - Spurious level-sensitive IRQ
+                 * - Priorities has been changed
+                 *   and the pending IRQ isn't allowed anymore
+                 */
+                reset_bit(&src->ipvp, IPVP_ACTIVITY);
+                retval = IPVP_VECTOR(opp->spve);
+            } else {
+                /* IRQ enter servicing state */
+                IRQ_setbit(&dst->servicing, n_IRQ);
+                retval = IPVP_VECTOR(src->ipvp);
+            }
+            IRQ_resetbit(&dst->raised, n_IRQ);
+            dst->raised.next = -1;
+            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
+                /* edge-sensitive IRQ */
+                reset_bit(&src->ipvp, IPVP_ACTIVITY);
+                src->pending = 0;
+            }
+        }
+        break;
+    case 0xB0: /* PEOI */
+        retval = 0;
+        break;
+#if MAX_IPI > 0
+    case 0x40: /* IDE */
+    case 0x50:
+        idx = (addr - 0x40) >> 4;
+        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
+        break;
+#endif
+    default:
+        break;
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_buggy_write (void *opaque,
+                                 target_phys_addr_t addr, uint32_t val)
+{
+    printf("Invalid OPENPIC write access !\n");
+}
+
+static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
+{
+    printf("Invalid OPENPIC read access !\n");
+
+    return -1;
+}
+
+static void openpic_writel (void *opaque,
+                            target_phys_addr_t addr, uint32_t val)
+{
+    openpic_t *opp = opaque;
+
+    addr &= 0x3FFFF;
+    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
+    if (addr < 0x1100) {
+        /* Global registers */
+        openpic_gbl_write(opp, addr, val);
+    } else if (addr < 0x10000) {
+        /* Timers registers */
+        openpic_timer_write(opp, addr, val);
+    } else if (addr < 0x20000) {
+        /* Source registers */
+        openpic_src_write(opp, addr, val);
+    } else {
+        /* CPU registers */
+        openpic_cpu_write(opp, addr, val);
+    }
+}
+
+static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
+{
+    openpic_t *opp = opaque;
+    uint32_t retval;
+
+    addr &= 0x3FFFF;
+    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
+    if (addr < 0x1100) {
+        /* Global registers */
+        retval = openpic_gbl_read(opp, addr);
+    } else if (addr < 0x10000) {
+        /* Timers registers */
+        retval = openpic_timer_read(opp, addr);
+    } else if (addr < 0x20000) {
+        /* Source registers */
+        retval = openpic_src_read(opp, addr);
+    } else {
+        /* CPU registers */
+        retval = openpic_cpu_read(opp, addr);
+    }
+
+    return retval;
+}
+
+static CPUWriteMemoryFunc * const openpic_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &openpic_writel,
+};
+
+static CPUReadMemoryFunc * const openpic_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &openpic_readl,
+};
+
+static void openpic_map(PCIDevice *pci_dev, int region_num,
+                        pcibus_t addr, pcibus_t size, int type)
+{
+    openpic_t *opp;
+
+    DPRINTF("Map OpenPIC\n");
+    opp = (openpic_t *)pci_dev;
+    /* Global registers */
+    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
+            addr + 0x1000, addr + 0x1000 + 0x100);
+    /* Timer registers */
+    DPRINTF("Register OPENPIC timer %08x => %08x\n",
+            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
+    /* Interrupt source registers */
+    DPRINTF("Register OPENPIC src   %08x => %08x\n",
+            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
+    /* Per CPU registers */
+    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
+            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
+    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
+#if 0 // Don't implement ISU for now
+    opp_io_memory = cpu_register_io_memory(openpic_src_read,
+                                           openpic_src_write, NULL
+                                           DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
+                                 opp_io_memory);
+#endif
+}
+
+static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
+        qemu_put_be32s(f, &q->queue[i]);
+
+    qemu_put_sbe32s(f, &q->next);
+    qemu_put_sbe32s(f, &q->priority);
+}
+
+static void openpic_save(QEMUFile* f, void *opaque)
+{
+    openpic_t *opp = (openpic_t *)opaque;
+    unsigned int i;
+
+    qemu_put_be32s(f, &opp->frep);
+    qemu_put_be32s(f, &opp->glbc);
+    qemu_put_be32s(f, &opp->micr);
+    qemu_put_be32s(f, &opp->veni);
+    qemu_put_be32s(f, &opp->pint);
+    qemu_put_be32s(f, &opp->spve);
+    qemu_put_be32s(f, &opp->tifr);
+
+    for (i = 0; i < opp->max_irq; i++) {
+        qemu_put_be32s(f, &opp->src[i].ipvp);
+        qemu_put_be32s(f, &opp->src[i].ide);
+        qemu_put_sbe32s(f, &opp->src[i].type);
+        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_put_sbe32s(f, &opp->src[i].pending);
+    }
+
+    qemu_put_sbe32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_put_be32s(f, &opp->dst[i].tfrr);
+        qemu_put_be32s(f, &opp->dst[i].pctp);
+        qemu_put_be32s(f, &opp->dst[i].pcsr);
+        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_put_be32s(f, &opp->timers[i].ticc);
+        qemu_put_be32s(f, &opp->timers[i].tibc);
+    }
+
+#if MAX_DBL > 0
+    qemu_put_be32s(f, &opp->dar);
+
+    for (i = 0; i < MAX_DBL; i++) {
+        qemu_put_be32s(f, &opp->doorbells[i].dmr);
+    }
+#endif
+
+#if MAX_MBX > 0
+    for (i = 0; i < MAX_MAILBOXES; i++) {
+        qemu_put_be32s(f, &opp->mailboxes[i].mbr);
+    }
+#endif
+
+    pci_device_save(&opp->pci_dev, f);
+}
+
+static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
+        qemu_get_be32s(f, &q->queue[i]);
+
+    qemu_get_sbe32s(f, &q->next);
+    qemu_get_sbe32s(f, &q->priority);
+}
+
+static int openpic_load(QEMUFile* f, void *opaque, int version_id)
+{
+    openpic_t *opp = (openpic_t *)opaque;
+    unsigned int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &opp->frep);
+    qemu_get_be32s(f, &opp->glbc);
+    qemu_get_be32s(f, &opp->micr);
+    qemu_get_be32s(f, &opp->veni);
+    qemu_get_be32s(f, &opp->pint);
+    qemu_get_be32s(f, &opp->spve);
+    qemu_get_be32s(f, &opp->tifr);
+
+    for (i = 0; i < opp->max_irq; i++) {
+        qemu_get_be32s(f, &opp->src[i].ipvp);
+        qemu_get_be32s(f, &opp->src[i].ide);
+        qemu_get_sbe32s(f, &opp->src[i].type);
+        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_get_sbe32s(f, &opp->src[i].pending);
+    }
+
+    qemu_get_sbe32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_get_be32s(f, &opp->dst[i].tfrr);
+        qemu_get_be32s(f, &opp->dst[i].pctp);
+        qemu_get_be32s(f, &opp->dst[i].pcsr);
+        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_get_be32s(f, &opp->timers[i].ticc);
+        qemu_get_be32s(f, &opp->timers[i].tibc);
+    }
+
+#if MAX_DBL > 0
+    qemu_get_be32s(f, &opp->dar);
+
+    for (i = 0; i < MAX_DBL; i++) {
+        qemu_get_be32s(f, &opp->doorbells[i].dmr);
+    }
+#endif
+
+#if MAX_MBX > 0
+    for (i = 0; i < MAX_MAILBOXES; i++) {
+        qemu_get_be32s(f, &opp->mailboxes[i].mbr);
+    }
+#endif
+
+    return pci_device_load(&opp->pci_dev, f);
+}
+
+static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
+{
+    qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+}
+
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out)
+{
+    openpic_t *opp;
+    uint8_t *pci_conf;
+    int i, m;
+
+    /* XXX: for now, only one CPU is supported */
+    if (nb_cpus != 1)
+        return NULL;
+    if (bus) {
+        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
+                                               -1, NULL, NULL);
+        pci_conf = opp->pci_dev.config;
+        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
+        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
+        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
+        pci_conf[0x3d] = 0x00; // no interrupt pin
+
+        /* Register I/O spaces */
+        pci_register_bar(&opp->pci_dev, 0, 0x40000,
+                               PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
+    } else {
+        opp = qemu_mallocz(sizeof(openpic_t));
+    }
+    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
+                                            DEVICE_LITTLE_ENDIAN);
+
+    //    isu_base &= 0xFFFC0000;
+    opp->nb_cpus = nb_cpus;
+    opp->max_irq = OPENPIC_MAX_IRQ;
+    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
+    opp->irq_tim0 = OPENPIC_IRQ_TIM0;
+    /* Set IRQ types */
+    for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
+        opp->src[i].type = IRQ_EXTERNAL;
+    }
+    for (; i < OPENPIC_IRQ_TIM0; i++) {
+        opp->src[i].type = IRQ_SPECIAL;
+    }
+#if MAX_IPI > 0
+    m = OPENPIC_IRQ_IPI0;
+#else
+    m = OPENPIC_IRQ_DBL0;
+#endif
+    for (; i < m; i++) {
+        opp->src[i].type = IRQ_TIMER;
+    }
+    for (; i < OPENPIC_MAX_IRQ; i++) {
+        opp->src[i].type = IRQ_INTERNAL;
+    }
+    for (i = 0; i < nb_cpus; i++)
+        opp->dst[i].irqs = irqs[i];
+    opp->irq_out = irq_out;
+
+    register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
+                    openpic_save, openpic_load, opp);
+    qemu_register_reset(openpic_reset, opp);
+
+    opp->irq_raise = openpic_irq_raise;
+    opp->reset = openpic_reset;
+
+    if (pmem_index)
+        *pmem_index = opp->mem_index;
+
+    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
+}
+
+static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
+{
+    int n_ci = IDR_CI0 - n_CPU;
+
+    if(test_bit(&src->ide, n_ci)) {
+        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
+    }
+    else {
+        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+    }
+}
+
+static void mpic_reset (void *opaque)
+{
+    openpic_t *mpp = (openpic_t *)opaque;
+    int i;
+
+    mpp->glbc = 0x80000000;
+    /* Initialise controller registers */
+    mpp->frep = 0x004f0002;
+    mpp->veni = VENI;
+    mpp->pint = 0x00000000;
+    mpp->spve = 0x0000FFFF;
+    /* Initialise IRQ sources */
+    for (i = 0; i < mpp->max_irq; i++) {
+        mpp->src[i].ipvp = 0x80800000;
+        mpp->src[i].ide  = 0x00000001;
+    }
+    /* Initialise IRQ destinations */
+    for (i = 0; i < MAX_CPU; i++) {
+        mpp->dst[i].pctp      = 0x0000000F;
+        mpp->dst[i].tfrr      = 0x00000000;
+        memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
+        mpp->dst[i].raised.next = -1;
+        memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
+        mpp->dst[i].servicing.next = -1;
+    }
+    /* Initialise timers */
+    for (i = 0; i < MAX_TMR; i++) {
+        mpp->timers[i].ticc = 0x00000000;
+        mpp->timers[i].tibc = 0x80000000;
+    }
+    /* Go out of RESET state */
+    mpp->glbc = 0x00000000;
+}
+
+static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx, cpu;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr &= 0xFFFF;
+    cpu = addr >> 12;
+    idx = (addr >> 6) & 0x3;
+    switch (addr & 0x30) {
+    case 0x00: /* gtccr */
+        break;
+    case 0x10: /* gtbcr */
+        if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
+            (val & 0x80000000) == 0 &&
+            (mpp->timers[idx].tibc & 0x80000000) != 0)
+            mpp->timers[idx].ticc &= ~0x80000000;
+        mpp->timers[idx].tibc = val;
+        break;
+    case 0x20: /* GTIVPR */
+        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
+        break;
+    case 0x30: /* GTIDR & TFRR */
+        if ((addr & 0xF0) == 0xF0)
+            mpp->dst[cpu].tfrr = val;
+        else
+            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
+        break;
+    }
+}
+
+static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx, cpu;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr &= 0xFFFF;
+    cpu = addr >> 12;
+    idx = (addr >> 6) & 0x3;
+    switch (addr & 0x30) {
+    case 0x00: /* gtccr */
+        retval = mpp->timers[idx].ticc;
+        break;
+    case 0x10: /* gtbcr */
+        retval = mpp->timers[idx].tibc;
+        break;
+    case 0x20: /* TIPV */
+        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
+        break;
+    case 0x30: /* TIDR */
+        if ((addr &0xF0) == 0XF0)
+            retval = mpp->dst[cpu].tfrr;
+        else
+            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
+        break;
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx = MPIC_EXT_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+
+    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_EXT_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            write_IRQreg(mpp, idx, IRQ_IDE, val);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+        }
+    }
+}
+
+static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx = MPIC_EXT_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+
+    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_EXT_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+        }
+        DPRINTF("%s: => %08x\n", __func__, retval);
+    }
+
+    return retval;
+}
+
+static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx = MPIC_INT_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+
+    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_INT_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            write_IRQreg(mpp, idx, IRQ_IDE, val);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+        }
+    }
+}
+
+static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx = MPIC_INT_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+
+    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_INT_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+        }
+        DPRINTF("%s: => %08x\n", __func__, retval);
+    }
+
+    return retval;
+}
+
+static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx = MPIC_MSG_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+
+    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_MSG_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            write_IRQreg(mpp, idx, IRQ_IDE, val);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+        }
+    }
+}
+
+static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx = MPIC_MSG_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+
+    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_MSG_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+        }
+        DPRINTF("%s: => %08x\n", __func__, retval);
+    }
+
+    return retval;
+}
+
+static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx = MPIC_MSI_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+
+    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_MSI_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            write_IRQreg(mpp, idx, IRQ_IDE, val);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+        }
+    }
+}
+static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx = MPIC_MSI_IRQ;
+
+    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+
+    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
+    if (addr < MPIC_MSI_REG_SIZE) {
+        idx += (addr & 0xFFF0) >> 5;
+        if (addr & 0x10) {
+            /* EXDE / IFEDE / IEEDE */
+            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+        } else {
+            /* EXVP / IFEVP / IEEVP */
+            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+        }
+        DPRINTF("%s: => %08x\n", __func__, retval);
+    }
+
+    return retval;
+}
+
+static CPUWriteMemoryFunc * const mpic_glb_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &openpic_gbl_write,
+};
+
+static CPUReadMemoryFunc * const mpic_glb_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &openpic_gbl_read,
+};
+
+static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_timer_write,
+};
+
+static CPUReadMemoryFunc * const mpic_tmr_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_timer_read,
+};
+
+static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &openpic_cpu_write,
+};
+
+static CPUReadMemoryFunc * const mpic_cpu_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &openpic_cpu_read,
+};
+
+static CPUWriteMemoryFunc * const mpic_ext_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_src_ext_write,
+};
+
+static CPUReadMemoryFunc * const mpic_ext_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_src_ext_read,
+};
+
+static CPUWriteMemoryFunc * const mpic_int_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_src_int_write,
+};
+
+static CPUReadMemoryFunc * const mpic_int_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_src_int_read,
+};
+
+static CPUWriteMemoryFunc * const mpic_msg_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_src_msg_write,
+};
+
+static CPUReadMemoryFunc * const mpic_msg_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_src_msg_read,
+};
+static CPUWriteMemoryFunc * const mpic_msi_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_src_msi_write,
+};
+
+static CPUReadMemoryFunc * const mpic_msi_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_src_msi_read,
+};
+
+qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out)
+{
+    openpic_t *mpp;
+    int i;
+    struct {
+        CPUReadMemoryFunc * const *read;
+        CPUWriteMemoryFunc * const *write;
+        target_phys_addr_t start_addr;
+        ram_addr_t size;
+    } const list[] = {
+        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
+        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
+        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
+        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
+        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
+        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
+        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
+    };
+
+    /* XXX: for now, only one CPU is supported */
+    if (nb_cpus != 1)
+        return NULL;
+
+    mpp = qemu_mallocz(sizeof(openpic_t));
+
+    for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
+        int mem_index;
+
+        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
+                                           DEVICE_BIG_ENDIAN);
+        if (mem_index < 0) {
+            goto free;
+        }
+        cpu_register_physical_memory(base + list[i].start_addr,
+                                     list[i].size, mem_index);
+    }
+
+    mpp->nb_cpus = nb_cpus;
+    mpp->max_irq = MPIC_MAX_IRQ;
+    mpp->irq_ipi0 = MPIC_IPI_IRQ;
+    mpp->irq_tim0 = MPIC_TMR_IRQ;
+
+    for (i = 0; i < nb_cpus; i++)
+        mpp->dst[i].irqs = irqs[i];
+    mpp->irq_out = irq_out;
+
+    mpp->irq_raise = mpic_irq_raise;
+    mpp->reset = mpic_reset;
+
+    register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
+    qemu_register_reset(mpic_reset, mpp);
+
+    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
+
+free:
+    qemu_free(mpp);
+    return NULL;
+}
diff --git a/qemu-0.15.x/hw/openpic.h b/qemu-0.15.x/hw/openpic.h
new file mode 100644
index 0000000..0957c1f
--- /dev/null
+++ b/qemu-0.15.x/hw/openpic.h
@@ -0,0 +1,18 @@
+#if !defined(__OPENPIC_H__)
+#define __OPENPIC_H__
+
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
+enum {
+    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
+    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
+    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
+    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
+    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
+    OPENPIC_OUTPUT_NB,
+};
+
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out);
+qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out);
+#endif /* __OPENPIC_H__ */
diff --git a/qemu-0.15.x/hw/palm.c b/qemu-0.15.x/hw/palm.c
new file mode 100644
index 0000000..f22d777
--- /dev/null
+++ b/qemu-0.15.x/hw/palm.c
@@ -0,0 +1,289 @@
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "audio/audio.h"
+#include "sysemu.h"
+#include "console.h"
+#include "omap.h"
+#include "boards.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "loader.h"
+
+static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 3) << 3);
+}
+
+static uint32_t static_readh(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 1) << 3);
+}
+
+static uint32_t static_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 0) << 3);
+}
+
+static void static_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+#ifdef SPY
+    printf("%s: value %08lx written at " PA_FMT "\n",
+                    __FUNCTION__, value, offset);
+#endif
+}
+
+static CPUReadMemoryFunc * const static_readfn[] = {
+    static_readb,
+    static_readh,
+    static_readw,
+};
+
+static CPUWriteMemoryFunc * const static_writefn[] = {
+    static_write,
+    static_write,
+    static_write,
+};
+
+/* Palm Tunsgten|E support */
+
+/* Shared GPIOs */
+#define PALMTE_USBDETECT_GPIO	0
+#define PALMTE_USB_OR_DC_GPIO	1
+#define PALMTE_TSC_GPIO		4
+#define PALMTE_PINTDAV_GPIO	6
+#define PALMTE_MMC_WP_GPIO	8
+#define PALMTE_MMC_POWER_GPIO	9
+#define PALMTE_HDQ_GPIO		11
+#define PALMTE_HEADPHONES_GPIO	14
+#define PALMTE_SPEAKER_GPIO	15
+/* MPU private GPIOs */
+#define PALMTE_DC_GPIO		2
+#define PALMTE_MMC_SWITCH_GPIO	4
+#define PALMTE_MMC1_GPIO	6
+#define PALMTE_MMC2_GPIO	7
+#define PALMTE_MMC3_GPIO	11
+
+static MouseTransformInfo palmte_pointercal = {
+    .x = 320,
+    .y = 320,
+    .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
+};
+
+static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
+{
+    uWireSlave *tsc;
+
+    tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]);
+
+    omap_uwire_attach(cpu->microwire, tsc, 0);
+    omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
+
+    tsc210x_set_transform(tsc, &palmte_pointercal);
+}
+
+static struct {
+    int row;
+    int column;
+} palmte_keymap[0x80] = {
+    [0 ... 0x7f] = { -1, -1 },
+    [0x3b] = { 0, 0 },	/* F1	-> Calendar */
+    [0x3c] = { 1, 0 },	/* F2	-> Contacts */
+    [0x3d] = { 2, 0 },	/* F3	-> Tasks List */
+    [0x3e] = { 3, 0 },	/* F4	-> Note Pad */
+    [0x01] = { 4, 0 },	/* Esc	-> Power */
+    [0x4b] = { 0, 1 },	/* 	   Left */
+    [0x50] = { 1, 1 },	/* 	   Down */
+    [0x48] = { 2, 1 },	/*	   Up */
+    [0x4d] = { 3, 1 },	/*	   Right */
+    [0x4c] = { 4, 1 },	/* 	   Centre */
+    [0x39] = { 4, 1 },	/* Spc	-> Centre */
+};
+
+static void palmte_button_event(void *opaque, int keycode)
+{
+    struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque;
+
+    if (palmte_keymap[keycode & 0x7f].row != -1)
+        omap_mpuio_key(cpu->mpuio,
+                        palmte_keymap[keycode & 0x7f].row,
+                        palmte_keymap[keycode & 0x7f].column,
+                        !(keycode & 0x80));
+}
+
+static void palmte_onoff_gpios(void *opaque, int line, int level)
+{
+    switch (line) {
+    case 0:
+        printf("%s: current to MMC/SD card %sabled.\n",
+                        __FUNCTION__, level ? "dis" : "en");
+        break;
+    case 1:
+        printf("%s: internal speaker amplifier %s.\n",
+                        __FUNCTION__, level ? "down" : "on");
+        break;
+
+    /* These LCD & Audio output signals have not been identified yet.  */
+    case 2:
+    case 3:
+    case 4:
+        printf("%s: LCD GPIO%i %s.\n",
+                        __FUNCTION__, line - 1, level ? "high" : "low");
+        break;
+    case 5:
+    case 6:
+        printf("%s: Audio GPIO%i %s.\n",
+                        __FUNCTION__, line - 4, level ? "high" : "low");
+        break;
+    }
+}
+
+static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
+{
+    qemu_irq *misc_gpio;
+
+    omap_mmc_handlers(cpu->mmc,
+                    omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO],
+                    qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
+                            [PALMTE_MMC_SWITCH_GPIO]));
+
+    misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
+    omap_gpio_out_set(cpu->gpio, PALMTE_MMC_POWER_GPIO,	misc_gpio[0]);
+    omap_gpio_out_set(cpu->gpio, PALMTE_SPEAKER_GPIO,	misc_gpio[1]);
+    omap_gpio_out_set(cpu->gpio, 11,			misc_gpio[2]);
+    omap_gpio_out_set(cpu->gpio, 12,			misc_gpio[3]);
+    omap_gpio_out_set(cpu->gpio, 13,			misc_gpio[4]);
+    omap_mpuio_out_set(cpu->mpuio, 1,			misc_gpio[5]);
+    omap_mpuio_out_set(cpu->mpuio, 3,			misc_gpio[6]);
+
+    /* Reset some inputs to initial state.  */
+    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USBDETECT_GPIO]);
+    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USB_OR_DC_GPIO]);
+    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[4]);
+    qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_HEADPHONES_GPIO]);
+    qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
+    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
+}
+
+static struct arm_boot_info palmte_binfo = {
+    .loader_start = OMAP_EMIFF_BASE,
+    .ram_size = 0x02000000,
+    .board_id = 0x331,
+};
+
+static void palmte_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    struct omap_mpu_state_s *cpu;
+    int flash_size = 0x00800000;
+    int sdram_size = palmte_binfo.ram_size;
+    int io;
+    static uint32_t cs0val = 0xffffffff;
+    static uint32_t cs1val = 0x0000e1a0;
+    static uint32_t cs2val = 0x0000e1a0;
+    static uint32_t cs3val = 0xe1a0e1a0;
+    int rom_size, rom_loaded = 0;
+    DisplayState *ds = get_displaystate();
+
+    cpu = omap310_mpu_init(sdram_size, cpu_model);
+
+    /* External Flash (EMIFS) */
+    cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
+                                 qemu_ram_alloc(NULL, "palmte.flash",
+                                                flash_size) | IO_MEM_ROM);
+
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
+                    OMAP_CS0_SIZE - flash_size, io);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
+
+    palmte_microwire_setup(cpu);
+
+    qemu_add_kbd_event_handler(palmte_button_event, cpu);
+
+    palmte_gpio_setup(cpu);
+
+    /* Setup initial (reset) machine state */
+    if (nb_option_roms) {
+        rom_size = get_image_size(option_rom[0].name);
+        if (rom_size > flash_size) {
+            fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
+                            __FUNCTION__, rom_size, flash_size);
+            rom_size = 0;
+        }
+        if (rom_size > 0) {
+            rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
+                                           flash_size);
+            rom_loaded = 1;
+        }
+        if (rom_size < 0) {
+            fprintf(stderr, "%s: error loading '%s'\n",
+                            __FUNCTION__, option_rom[0].name);
+        }
+    }
+
+    if (!rom_loaded && !kernel_filename) {
+        fprintf(stderr, "Kernel or ROM image must be specified\n");
+        exit(1);
+    }
+
+    /* Load the kernel.  */
+    if (kernel_filename) {
+        palmte_binfo.kernel_filename = kernel_filename;
+        palmte_binfo.kernel_cmdline = kernel_cmdline;
+        palmte_binfo.initrd_filename = initrd_filename;
+        arm_load_kernel(cpu->env, &palmte_binfo);
+    }
+
+    /* FIXME: We shouldn't really be doing this here.  The LCD controller
+       will set the size once configured, so this just sets an initial
+       size until the guest activates the display.  */
+    ds->surface = qemu_resize_displaysurface(ds, 320, 320);
+    dpy_resize(ds);
+}
+
+static QEMUMachine palmte_machine = {
+    .name = "cheetah",
+    .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
+    .init = palmte_init,
+};
+
+static void palmte_machine_init(void)
+{
+    qemu_register_machine(&palmte_machine);
+}
+
+machine_init(palmte_machine_init);
diff --git a/qemu-0.15.x/hw/parallel.c b/qemu-0.15.x/hw/parallel.c
new file mode 100644
index 0000000..cc853a5
--- /dev/null
+++ b/qemu-0.15.x/hw/parallel.c
@@ -0,0 +1,598 @@
+/*
+ * QEMU Parallel PORT emulation
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2007 Marko Kohtala
+ *
+ * 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 "hw.h"
+#include "qemu-char.h"
+#include "isa.h"
+#include "pc.h"
+#include "sysemu.h"
+
+//#define DEBUG_PARALLEL
+
+#ifdef DEBUG_PARALLEL
+#define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
+#else
+#define pdebug(fmt, ...) ((void)0)
+#endif
+
+#define PARA_REG_DATA 0
+#define PARA_REG_STS 1
+#define PARA_REG_CTR 2
+#define PARA_REG_EPP_ADDR 3
+#define PARA_REG_EPP_DATA 4
+
+/*
+ * These are the definitions for the Printer Status Register
+ */
+#define PARA_STS_BUSY	0x80	/* Busy complement */
+#define PARA_STS_ACK	0x40	/* Acknowledge */
+#define PARA_STS_PAPER	0x20	/* Out of paper */
+#define PARA_STS_ONLINE	0x10	/* Online */
+#define PARA_STS_ERROR	0x08	/* Error complement */
+#define PARA_STS_TMOUT	0x01	/* EPP timeout */
+
+/*
+ * These are the definitions for the Printer Control Register
+ */
+#define PARA_CTR_DIR	0x20	/* Direction (1=read, 0=write) */
+#define PARA_CTR_INTEN	0x10	/* IRQ Enable */
+#define PARA_CTR_SELECT	0x08	/* Select In complement */
+#define PARA_CTR_INIT	0x04	/* Initialize Printer complement */
+#define PARA_CTR_AUTOLF	0x02	/* Auto linefeed complement */
+#define PARA_CTR_STROBE	0x01	/* Strobe complement */
+
+#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
+
+typedef struct ParallelState {
+    uint8_t dataw;
+    uint8_t datar;
+    uint8_t status;
+    uint8_t control;
+    qemu_irq irq;
+    int irq_pending;
+    CharDriverState *chr;
+    int hw_driver;
+    int epp_timeout;
+    uint32_t last_read_offset; /* For debugging */
+    /* Memory-mapped interface */
+    int it_shift;
+} ParallelState;
+
+typedef struct ISAParallelState {
+    ISADevice dev;
+    uint32_t index;
+    uint32_t iobase;
+    uint32_t isairq;
+    ParallelState state;
+} ISAParallelState;
+
+static void parallel_update_irq(ParallelState *s)
+{
+    if (s->irq_pending)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void
+parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+
+    pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        s->dataw = val;
+        parallel_update_irq(s);
+        break;
+    case PARA_REG_CTR:
+        val |= 0xc0;
+        if ((val & PARA_CTR_INIT) == 0 ) {
+            s->status = PARA_STS_BUSY;
+            s->status |= PARA_STS_ACK;
+            s->status |= PARA_STS_ONLINE;
+            s->status |= PARA_STS_ERROR;
+        }
+        else if (val & PARA_CTR_SELECT) {
+            if (val & PARA_CTR_STROBE) {
+                s->status &= ~PARA_STS_BUSY;
+                if ((s->control & PARA_CTR_STROBE) == 0)
+                    qemu_chr_write(s->chr, &s->dataw, 1);
+            } else {
+                if (s->control & PARA_CTR_INTEN) {
+                    s->irq_pending = 1;
+                }
+            }
+        }
+        parallel_update_irq(s);
+        s->control = val;
+        break;
+    }
+}
+
+static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint8_t parm = val;
+    int dir;
+
+    /* Sometimes programs do several writes for timing purposes on old
+       HW. Take care not to waste time on writes that do nothing. */
+
+    s->last_read_offset = ~0U;
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        if (s->dataw == val)
+            return;
+        pdebug("wd%02x\n", val);
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        s->dataw = val;
+        break;
+    case PARA_REG_STS:
+        pdebug("ws%02x\n", val);
+        if (val & PARA_STS_TMOUT)
+            s->epp_timeout = 0;
+        break;
+    case PARA_REG_CTR:
+        val |= 0xc0;
+        if (s->control == val)
+            return;
+        pdebug("wc%02x\n", val);
+
+        if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
+            if (val & PARA_CTR_DIR) {
+                dir = 1;
+            } else {
+                dir = 0;
+            }
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
+            parm &= ~PARA_CTR_DIR;
+        }
+
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        s->control = val;
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP address cycle, so do nothing */
+            pdebug("wa%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("wa%02x t\n", val);
+            }
+            else
+                pdebug("wa%02x\n", val);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("we%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("we%02x t\n", val);
+            }
+            else
+                pdebug("we%02x\n", val);
+        }
+        break;
+    }
+}
+
+static void
+parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint16_t eppdata = cpu_to_le16(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%04x s\n", val);
+        return;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%04x t\n", val);
+    }
+    else
+        pdebug("we%04x\n", val);
+}
+
+static void
+parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint32_t eppdata = cpu_to_le32(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%08x s\n", val);
+        return;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%08x t\n", val);
+    }
+    else
+        pdebug("we%08x\n", val);
+}
+
+static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret = 0xff;
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        if (s->control & PARA_CTR_DIR)
+            ret = s->datar;
+        else
+            ret = s->dataw;
+        break;
+    case PARA_REG_STS:
+        ret = s->status;
+        s->irq_pending = 0;
+        if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
+            /* XXX Fixme: wait 5 microseconds */
+            if (s->status & PARA_STS_ACK)
+                s->status &= ~PARA_STS_ACK;
+            else {
+                /* XXX Fixme: wait 5 microseconds */
+                s->status |= PARA_STS_ACK;
+                s->status |= PARA_STS_BUSY;
+            }
+        }
+        parallel_update_irq(s);
+        break;
+    case PARA_REG_CTR:
+        ret = s->control;
+        break;
+    }
+    pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
+    return ret;
+}
+
+static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint8_t ret = 0xff;
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        if (s->last_read_offset != addr || s->datar != ret)
+            pdebug("rd%02x\n", ret);
+        s->datar = ret;
+        break;
+    case PARA_REG_STS:
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        ret &= ~PARA_STS_TMOUT;
+        if (s->epp_timeout)
+            ret |= PARA_STS_TMOUT;
+        if (s->last_read_offset != addr || s->status != ret)
+            pdebug("rs%02x\n", ret);
+        s->status = ret;
+        break;
+    case PARA_REG_CTR:
+        /* s->control has some bits fixed to 1. It is zero only when
+           it has not been yet written to.  */
+        if (s->control == 0) {
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+            s->control = ret;
+        }
+        else {
+            ret = s->control;
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP addr cycle, so do nothing */
+            pdebug("ra%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("ra%02x t\n", ret);
+            }
+            else
+                pdebug("ra%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("re%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("re%02x t\n", ret);
+            }
+            else
+                pdebug("re%02x\n", ret);
+        }
+        break;
+    }
+    s->last_read_offset = addr;
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint16_t eppdata = ~0;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%04x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le16_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%04x t\n", ret);
+    }
+    else
+        pdebug("re%04x\n", ret);
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint32_t eppdata = ~0U;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%08x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le32_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%08x t\n", ret);
+    }
+    else
+        pdebug("re%08x\n", ret);
+    return ret;
+}
+
+static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    pdebug("wecp%d=%02x\n", addr & 7, val);
+}
+
+static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
+{
+    uint8_t ret = 0xff;
+
+    pdebug("recp%d:%02x\n", addr & 7, ret);
+    return ret;
+}
+
+static void parallel_reset(void *opaque)
+{
+    ParallelState *s = opaque;
+
+    s->datar = ~0;
+    s->dataw = ~0;
+    s->status = PARA_STS_BUSY;
+    s->status |= PARA_STS_ACK;
+    s->status |= PARA_STS_ONLINE;
+    s->status |= PARA_STS_ERROR;
+    s->status |= PARA_STS_TMOUT;
+    s->control = PARA_CTR_SELECT;
+    s->control |= PARA_CTR_INIT;
+    s->control |= 0xc0;
+    s->irq_pending = 0;
+    s->hw_driver = 0;
+    s->epp_timeout = 0;
+    s->last_read_offset = ~0U;
+}
+
+static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+
+static int parallel_isa_initfn(ISADevice *dev)
+{
+    static int index;
+    ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
+    ParallelState *s = &isa->state;
+    int base;
+    uint8_t dummy;
+
+    if (!s->chr) {
+        fprintf(stderr, "Can't create parallel device, empty char device\n");
+        exit(1);
+    }
+
+    if (isa->index == -1)
+        isa->index = index;
+    if (isa->index >= MAX_PARALLEL_PORTS)
+        return -1;
+    if (isa->iobase == -1)
+        isa->iobase = isa_parallel_io[isa->index];
+    index++;
+
+    base = isa->iobase;
+    isa_init_irq(dev, &s->irq, isa->isairq);
+    qemu_register_reset(parallel_reset, s);
+
+    if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+        s->hw_driver = 1;
+        s->status = dummy;
+    }
+
+    if (s->hw_driver) {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
+        isa_init_ioport_range(dev, base, 8);
+
+        register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
+        register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
+        register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
+        register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
+        isa_init_ioport(dev, base+4);
+        register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
+        register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
+        isa_init_ioport_range(dev, base+0x400, 8);
+    }
+    else {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
+        isa_init_ioport_range(dev, base, 8);
+    }
+    return 0;
+}
+
+/* Memory mapped interface */
+static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
+}
+
+static void parallel_mm_writeb (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
+}
+
+static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
+}
+
+static void parallel_mm_writew (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
+}
+
+static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift);
+}
+
+static void parallel_mm_writel (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc * const parallel_mm_read_sw[] = {
+    &parallel_mm_readb,
+    &parallel_mm_readw,
+    &parallel_mm_readl,
+};
+
+static CPUWriteMemoryFunc * const parallel_mm_write_sw[] = {
+    &parallel_mm_writeb,
+    &parallel_mm_writew,
+    &parallel_mm_writel,
+};
+
+/* If fd is zero, it means that the parallel device uses the console */
+bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr)
+{
+    ParallelState *s;
+    int io_sw;
+
+    s = qemu_mallocz(sizeof(ParallelState));
+    s->irq = irq;
+    s->chr = chr;
+    s->it_shift = it_shift;
+    qemu_register_reset(parallel_reset, s);
+
+    io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw,
+                                   s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 8 << it_shift, io_sw);
+    return true;
+}
+
+static ISADeviceInfo parallel_isa_info = {
+    .qdev.name  = "isa-parallel",
+    .qdev.size  = sizeof(ISAParallelState),
+    .init       = parallel_isa_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
+        DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
+        DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
+        DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void parallel_register_devices(void)
+{
+    isa_qdev_register(&parallel_isa_info);
+}
+
+device_init(parallel_register_devices)
diff --git a/qemu-0.15.x/hw/pc.c b/qemu-0.15.x/hw/pc.c
new file mode 100644
index 0000000..a3e8539
--- /dev/null
+++ b/qemu-0.15.x/hw/pc.c
@@ -0,0 +1,1171 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "apic.h"
+#include "fdc.h"
+#include "ide.h"
+#include "pci.h"
+#include "vmware_vga.h"
+#include "monitor.h"
+#include "fw_cfg.h"
+#include "hpet_emul.h"
+#include "smbios.h"
+#include "loader.h"
+#include "elf.h"
+#include "multiboot.h"
+#include "mc146818rtc.h"
+#include "msix.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "blockdev.h"
+#include "ui/qemu-spice.h"
+
+/* output Bochs bios info messages */
+//#define DEBUG_BIOS
+
+/* debug PC/ISA interrupts */
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define BIOS_FILENAME "bios.bin"
+
+#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
+
+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
+#define ACPI_DATA_SIZE       0x10000
+#define BIOS_CFG_IOPORT 0x510
+#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
+#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
+
+#define MSI_ADDR_BASE 0xfee00000
+
+#define E820_NR_ENTRIES		16
+
+struct e820_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+} __attribute((__packed__, __aligned__(4)));
+
+struct e820_table {
+    uint32_t count;
+    struct e820_entry entry[E820_NR_ENTRIES];
+} __attribute((__packed__, __aligned__(4)));
+
+static struct e820_table e820_table;
+struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
+
+void isa_irq_handler(void *opaque, int n, int level)
+{
+    IsaIrqState *isa = (IsaIrqState *)opaque;
+
+    DPRINTF("isa_irqs: %s irq %d\n", level? "raise" : "lower", n);
+    if (n < 16) {
+        qemu_set_irq(isa->i8259[n], level);
+    }
+    if (isa->ioapic)
+        qemu_set_irq(isa->ioapic[n], level);
+};
+
+static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
+{
+}
+
+/* MSDOS compatibility mode FPU exception support */
+static qemu_irq ferr_irq;
+
+void pc_register_ferr_irq(qemu_irq irq)
+{
+    ferr_irq = irq;
+}
+
+/* XXX: add IGNNE support */
+void cpu_set_ferr(CPUX86State *s)
+{
+    qemu_irq_raise(ferr_irq);
+}
+
+static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
+{
+    qemu_irq_lower(ferr_irq);
+}
+
+/* TSC handling */
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_ticks();
+}
+
+/* SMM support */
+
+static cpu_set_smm_t smm_set;
+static void *smm_arg;
+
+void cpu_smm_register(cpu_set_smm_t callback, void *arg)
+{
+    assert(smm_set == NULL);
+    assert(smm_arg == NULL);
+    smm_set = callback;
+    smm_arg = arg;
+}
+
+void cpu_smm_update(CPUState *env)
+{
+    if (smm_set && smm_arg && env == first_cpu)
+        smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
+}
+
+
+/* IRQ handling */
+int cpu_get_pic_interrupt(CPUState *env)
+{
+    int intno;
+
+    intno = apic_get_interrupt(env->apic_state);
+    if (intno >= 0) {
+        /* set irq request if a PIC irq is still pending */
+        /* XXX: improve that */
+        pic_update_irq(isa_pic);
+        return intno;
+    }
+    /* read the irq from the PIC */
+    if (!apic_accept_pic_intr(env->apic_state)) {
+        return -1;
+    }
+
+    intno = pic_read_irq(isa_pic);
+    return intno;
+}
+
+static void pic_irq_request(void *opaque, int irq, int level)
+{
+    CPUState *env = first_cpu;
+
+    DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
+    if (env->apic_state) {
+        while (env) {
+            if (apic_accept_pic_intr(env->apic_state)) {
+                apic_deliver_pic_intr(env->apic_state, level);
+            }
+            env = env->next_cpu;
+        }
+    } else {
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+/* PC cmos mappings */
+
+#define REG_EQUIPMENT_BYTE          0x14
+
+static int cmos_get_fd_drive_type(FDriveType fd0)
+{
+    int val;
+
+    switch (fd0) {
+    case FDRIVE_DRV_144:
+        /* 1.44 Mb 3"5 drive */
+        val = 4;
+        break;
+    case FDRIVE_DRV_288:
+        /* 2.88 Mb 3"5 drive */
+        val = 5;
+        break;
+    case FDRIVE_DRV_120:
+        /* 1.2 Mb 5"5 drive */
+        val = 2;
+        break;
+    case FDRIVE_DRV_NONE:
+    default:
+        val = 0;
+        break;
+    }
+    return val;
+}
+
+static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd,
+                         ISADevice *s)
+{
+    int cylinders, heads, sectors;
+    bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
+    rtc_set_memory(s, type_ofs, 47);
+    rtc_set_memory(s, info_ofs, cylinders);
+    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 2, heads);
+    rtc_set_memory(s, info_ofs + 3, 0xff);
+    rtc_set_memory(s, info_ofs + 4, 0xff);
+    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
+    rtc_set_memory(s, info_ofs + 6, cylinders);
+    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
+    rtc_set_memory(s, info_ofs + 8, sectors);
+}
+
+/* convert boot_device letter to something recognizable by the bios */
+static int boot_device2nibble(char boot_device)
+{
+    switch(boot_device) {
+    case 'a':
+    case 'b':
+        return 0x01; /* floppy boot */
+    case 'c':
+        return 0x02; /* hard drive boot */
+    case 'd':
+        return 0x03; /* CD-ROM boot */
+    case 'n':
+        return 0x04; /* Network boot */
+    }
+    return 0;
+}
+
+static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
+{
+#define PC_MAX_BOOT_DEVICES 3
+    int nbds, bds[3] = { 0, };
+    int i;
+
+    nbds = strlen(boot_device);
+    if (nbds > PC_MAX_BOOT_DEVICES) {
+        error_report("Too many boot devices for PC");
+        return(1);
+    }
+    for (i = 0; i < nbds; i++) {
+        bds[i] = boot_device2nibble(boot_device[i]);
+        if (bds[i] == 0) {
+            error_report("Invalid boot device for PC: '%c'",
+                         boot_device[i]);
+            return(1);
+        }
+    }
+    rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
+    rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
+    return(0);
+}
+
+static int pc_boot_set(void *opaque, const char *boot_device)
+{
+    return set_boot_dev(opaque, boot_device, 0);
+}
+
+typedef struct pc_cmos_init_late_arg {
+    ISADevice *rtc_state;
+    BusState *idebus0, *idebus1;
+} pc_cmos_init_late_arg;
+
+static void pc_cmos_init_late(void *opaque)
+{
+    pc_cmos_init_late_arg *arg = opaque;
+    ISADevice *s = arg->rtc_state;
+    int val;
+    BlockDriverState *hd_table[4];
+    int i;
+
+    ide_get_bs(hd_table, arg->idebus0);
+    ide_get_bs(hd_table + 2, arg->idebus1);
+
+    rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
+    if (hd_table[0])
+        cmos_init_hd(0x19, 0x1b, hd_table[0], s);
+    if (hd_table[1])
+        cmos_init_hd(0x1a, 0x24, hd_table[1], s);
+
+    val = 0;
+    for (i = 0; i < 4; i++) {
+        if (hd_table[i]) {
+            int cylinders, heads, sectors, translation;
+            /* NOTE: bdrv_get_geometry_hint() returns the physical
+                geometry.  It is always such that: 1 <= sects <= 63, 1
+                <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
+                geometry can be different if a translation is done. */
+            translation = bdrv_get_translation_hint(hd_table[i]);
+            if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
+                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
+                    /* No translation. */
+                    translation = 0;
+                } else {
+                    /* LBA translation. */
+                    translation = 1;
+                }
+            } else {
+                translation--;
+            }
+            val |= translation << (i * 2);
+        }
+    }
+    rtc_set_memory(s, 0x39, val);
+
+    qemu_unregister_reset(pc_cmos_init_late, opaque);
+}
+
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                  const char *boot_device,
+                  BusState *idebus0, BusState *idebus1,
+                  ISADevice *s)
+{
+    int val, nb, nb_heads, max_track, last_sect, i;
+    FDriveType fd_type[2];
+    DriveInfo *fd[2];
+    static pc_cmos_init_late_arg arg;
+
+    /* various important CMOS locations needed by PC/Bochs bios */
+
+    /* memory size */
+    val = 640; /* base memory in K */
+    rtc_set_memory(s, 0x15, val);
+    rtc_set_memory(s, 0x16, val >> 8);
+
+    val = (ram_size / 1024) - 1024;
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x17, val);
+    rtc_set_memory(s, 0x18, val >> 8);
+    rtc_set_memory(s, 0x30, val);
+    rtc_set_memory(s, 0x31, val >> 8);
+
+    if (above_4g_mem_size) {
+        rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
+        rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
+        rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32);
+    }
+
+    if (ram_size > (16 * 1024 * 1024))
+        val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
+    else
+        val = 0;
+    if (val > 65535)
+        val = 65535;
+    rtc_set_memory(s, 0x34, val);
+    rtc_set_memory(s, 0x35, val >> 8);
+
+    /* set the number of CPU */
+    rtc_set_memory(s, 0x5f, smp_cpus - 1);
+
+    /* set boot devices, and disable floppy signature check if requested */
+    if (set_boot_dev(s, boot_device, fd_bootchk)) {
+        exit(1);
+    }
+
+    /* floppy type */
+    for (i = 0; i < 2; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+        if (fd[i] && bdrv_is_inserted(fd[i]->bdrv)) {
+            bdrv_get_floppy_geometry_hint(fd[i]->bdrv, &nb_heads, &max_track,
+                                          &last_sect, FDRIVE_DRV_NONE,
+                                          &fd_type[i]);
+        } else {
+            fd_type[i] = FDRIVE_DRV_NONE;
+        }
+    }
+    val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
+        cmos_get_fd_drive_type(fd_type[1]);
+    rtc_set_memory(s, 0x10, val);
+
+    val = 0;
+    nb = 0;
+    if (fd_type[0] < FDRIVE_DRV_NONE) {
+        nb++;
+    }
+    if (fd_type[1] < FDRIVE_DRV_NONE) {
+        nb++;
+    }
+    switch (nb) {
+    case 0:
+        break;
+    case 1:
+        val |= 0x01; /* 1 drive, ready for boot */
+        break;
+    case 2:
+        val |= 0x41; /* 2 drives, ready for boot */
+        break;
+    }
+    val |= 0x02; /* FPU is there */
+    val |= 0x04; /* PS/2 mouse installed */
+    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
+
+    /* hard drives */
+    arg.rtc_state = s;
+    arg.idebus0 = idebus0;
+    arg.idebus1 = idebus1;
+    qemu_register_reset(pc_cmos_init_late, &arg);
+}
+
+/* port 92 stuff: could be split off */
+typedef struct Port92State {
+    ISADevice dev;
+    uint8_t outport;
+    qemu_irq *a20_out;
+} Port92State;
+
+static void port92_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    Port92State *s = opaque;
+
+    DPRINTF("port92: write 0x%02x\n", val);
+    s->outport = val;
+    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    if (val & 1) {
+        qemu_system_reset_request();
+    }
+}
+
+static uint32_t port92_read(void *opaque, uint32_t addr)
+{
+    Port92State *s = opaque;
+    uint32_t ret;
+
+    ret = s->outport;
+    DPRINTF("port92: read 0x%02x\n", ret);
+    return ret;
+}
+
+static void port92_init(ISADevice *dev, qemu_irq *a20_out)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_port92_isa = {
+    .name = "port92",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(outport, Port92State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void port92_reset(DeviceState *d)
+{
+    Port92State *s = container_of(d, Port92State, dev.qdev);
+
+    s->outport &= ~1;
+}
+
+static int port92_initfn(ISADevice *dev)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    register_ioport_read(0x92, 1, 1, port92_read, s);
+    register_ioport_write(0x92, 1, 1, port92_write, s);
+    isa_init_ioport(dev, 0x92);
+    s->outport = 0;
+    return 0;
+}
+
+static ISADeviceInfo port92_info = {
+    .qdev.name     = "port92",
+    .qdev.size     = sizeof(Port92State),
+    .qdev.vmsd     = &vmstate_port92_isa,
+    .qdev.no_user  = 1,
+    .qdev.reset    = port92_reset,
+    .init          = port92_initfn,
+};
+
+static void port92_register(void)
+{
+    isa_qdev_register(&port92_info);
+}
+device_init(port92_register)
+
+static void handle_a20_line_change(void *opaque, int irq, int level)
+{
+    CPUState *cpu = opaque;
+
+    /* XXX: send to all CPUs ? */
+    /* XXX: add logic to handle multiple A20 line sources */
+    cpu_x86_set_a20(cpu, level);
+}
+
+/***********************************************************/
+/* Bochs BIOS debug ports */
+
+static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    static const char shutdown_str[8] = "Shutdown";
+    static int shutdown_index = 0;
+
+    switch(addr) {
+        /* Bochs BIOS messages */
+    case 0x400:
+    case 0x401:
+        /* used to be panic, now unused */
+        break;
+    case 0x402:
+    case 0x403:
+#ifdef DEBUG_BIOS
+        fprintf(stderr, "%c", val);
+#endif
+        break;
+    case 0x8900:
+        /* same as Bochs power off */
+        if (val == shutdown_str[shutdown_index]) {
+            shutdown_index++;
+            if (shutdown_index == 8) {
+                shutdown_index = 0;
+                qemu_system_shutdown_request();
+            }
+        } else {
+            shutdown_index = 0;
+        }
+        break;
+
+        /* LGPL'ed VGA BIOS messages */
+    case 0x501:
+    case 0x502:
+        fprintf(stderr, "VGA BIOS panic, line %d\n", val);
+        exit(1);
+    case 0x500:
+    case 0x503:
+#ifdef DEBUG_BIOS
+        fprintf(stderr, "%c", val);
+#endif
+        break;
+    }
+}
+
+int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+    int index = le32_to_cpu(e820_table.count);
+    struct e820_entry *entry;
+
+    if (index >= E820_NR_ENTRIES)
+        return -EBUSY;
+    entry = &e820_table.entry[index++];
+
+    entry->address = cpu_to_le64(address);
+    entry->length = cpu_to_le64(length);
+    entry->type = cpu_to_le32(type);
+
+    e820_table.count = cpu_to_le32(index);
+    return index;
+}
+
+static void *bochs_bios_init(void)
+{
+    void *fw_cfg;
+    uint8_t *smbios_table;
+    size_t smbios_len;
+    uint64_t *numa_fw_cfg;
+    int i, j;
+
+    register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
+    register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
+    register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL);
+    register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
+    register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
+
+    register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
+    register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
+    register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
+    register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
+
+    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
+                     acpi_tables_len);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+
+    smbios_table = smbios_get_table(&smbios_len);
+    if (smbios_table)
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
+                         smbios_table, smbios_len);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table,
+                     sizeof(struct e820_table));
+
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, (uint8_t *)&hpet_cfg,
+                     sizeof(struct hpet_fw_config));
+    /* allocate memory for the NUMA channel: one (64bit) word for the number
+     * of nodes, one word for each VCPU->node and one word for each node to
+     * hold the amount of memory.
+     */
+    numa_fw_cfg = qemu_mallocz((1 + smp_cpus + nb_numa_nodes) * 8);
+    numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
+    for (i = 0; i < smp_cpus; i++) {
+        for (j = 0; j < nb_numa_nodes; j++) {
+            if (node_cpumask[j] & (1 << i)) {
+                numa_fw_cfg[i + 1] = cpu_to_le64(j);
+                break;
+            }
+        }
+    }
+    for (i = 0; i < nb_numa_nodes; i++) {
+        numa_fw_cfg[smp_cpus + 1 + i] = cpu_to_le64(node_mem[i]);
+    }
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, (uint8_t *)numa_fw_cfg,
+                     (1 + smp_cpus + nb_numa_nodes) * 8);
+
+    return fw_cfg;
+}
+
+static long get_file_size(FILE *f)
+{
+    long where, size;
+
+    /* XXX: on Unix systems, using fstat() probably makes more sense */
+
+    where = ftell(f);
+    fseek(f, 0, SEEK_END);
+    size = ftell(f);
+    fseek(f, where, SEEK_SET);
+
+    return size;
+}
+
+static void load_linux(void *fw_cfg,
+                       const char *kernel_filename,
+		       const char *initrd_filename,
+		       const char *kernel_cmdline,
+                       target_phys_addr_t max_ram_size)
+{
+    uint16_t protocol;
+    int setup_size, kernel_size, initrd_size = 0, cmdline_size;
+    uint32_t initrd_max;
+    uint8_t header[8192], *setup, *kernel, *initrd_data;
+    target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
+    FILE *f;
+    char *vmode;
+
+    /* Align to 16 bytes as a paranoia measure */
+    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
+
+    /* load the kernel header */
+    f = fopen(kernel_filename, "rb");
+    if (!f || !(kernel_size = get_file_size(f)) ||
+	fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
+	MIN(ARRAY_SIZE(header), kernel_size)) {
+	fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
+		kernel_filename, strerror(errno));
+	exit(1);
+    }
+
+    /* kernel protocol version */
+#if 0
+    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
+#endif
+    if (ldl_p(header+0x202) == 0x53726448)
+	protocol = lduw_p(header+0x206);
+    else {
+	/* This looks like a multiboot kernel. If it is, let's stop
+	   treating it like a Linux kernel. */
+        if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
+                           kernel_cmdline, kernel_size, header))
+            return;
+	protocol = 0;
+    }
+
+    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
+	/* Low kernel */
+	real_addr    = 0x90000;
+	cmdline_addr = 0x9a000 - cmdline_size;
+	prot_addr    = 0x10000;
+    } else if (protocol < 0x202) {
+	/* High but ancient kernel */
+	real_addr    = 0x90000;
+	cmdline_addr = 0x9a000 - cmdline_size;
+	prot_addr    = 0x100000;
+    } else {
+	/* High and recent kernel */
+	real_addr    = 0x10000;
+	cmdline_addr = 0x20000;
+	prot_addr    = 0x100000;
+    }
+
+#if 0
+    fprintf(stderr,
+	    "qemu: real_addr     = 0x" TARGET_FMT_plx "\n"
+	    "qemu: cmdline_addr  = 0x" TARGET_FMT_plx "\n"
+	    "qemu: prot_addr     = 0x" TARGET_FMT_plx "\n",
+	    real_addr,
+	    cmdline_addr,
+	    prot_addr);
+#endif
+
+    /* highest address for loading the initrd */
+    if (protocol >= 0x203)
+	initrd_max = ldl_p(header+0x22c);
+    else
+	initrd_max = 0x37ffffff;
+
+    if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
+    	initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
+                     (uint8_t*)strdup(kernel_cmdline),
+                     strlen(kernel_cmdline)+1);
+
+    if (protocol >= 0x202) {
+	stl_p(header+0x228, cmdline_addr);
+    } else {
+	stw_p(header+0x20, 0xA33F);
+	stw_p(header+0x22, cmdline_addr-real_addr);
+    }
+
+    /* handle vga= parameter */
+    vmode = strstr(kernel_cmdline, "vga=");
+    if (vmode) {
+        unsigned int video_mode;
+        /* skip "vga=" */
+        vmode += 4;
+        if (!strncmp(vmode, "normal", 6)) {
+            video_mode = 0xffff;
+        } else if (!strncmp(vmode, "ext", 3)) {
+            video_mode = 0xfffe;
+        } else if (!strncmp(vmode, "ask", 3)) {
+            video_mode = 0xfffd;
+        } else {
+            video_mode = strtol(vmode, NULL, 0);
+        }
+        stw_p(header+0x1fa, video_mode);
+    }
+
+    /* loader type */
+    /* High nybble = B reserved for Qemu; low nybble is revision number.
+       If this code is substantially changed, you may want to consider
+       incrementing the revision. */
+    if (protocol >= 0x200)
+	header[0x210] = 0xB0;
+
+    /* heap */
+    if (protocol >= 0x201) {
+	header[0x211] |= 0x80;	/* CAN_USE_HEAP */
+	stw_p(header+0x224, cmdline_addr-real_addr-0x200);
+    }
+
+    /* load initrd */
+    if (initrd_filename) {
+	if (protocol < 0x200) {
+	    fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
+	    exit(1);
+	}
+
+	initrd_size = get_image_size(initrd_filename);
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: error reading initrd %s\n",
+                    initrd_filename);
+            exit(1);
+        }
+
+        initrd_addr = (initrd_max-initrd_size) & ~4095;
+
+        initrd_data = qemu_malloc(initrd_size);
+        load_image(initrd_filename, initrd_data);
+
+        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
+
+	stl_p(header+0x218, initrd_addr);
+	stl_p(header+0x21c, initrd_size);
+    }
+
+    /* load kernel and setup */
+    setup_size = header[0x1f1];
+    if (setup_size == 0)
+	setup_size = 4;
+    setup_size = (setup_size+1)*512;
+    kernel_size -= setup_size;
+
+    setup  = qemu_malloc(setup_size);
+    kernel = qemu_malloc(kernel_size);
+    fseek(f, 0, SEEK_SET);
+    if (fread(setup, 1, setup_size, f) != setup_size) {
+        fprintf(stderr, "fread() failed\n");
+        exit(1);
+    }
+    if (fread(kernel, 1, kernel_size, f) != kernel_size) {
+        fprintf(stderr, "fread() failed\n");
+        exit(1);
+    }
+    fclose(f);
+    memcpy(setup, header, MIN(sizeof(header), setup_size));
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
+
+    option_rom[nb_option_roms].name = "linuxboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
+    nb_option_roms++;
+}
+
+#define NE2000_NB_MAX 6
+
+static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
+                                              0x280, 0x380 };
+static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
+
+static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
+
+void pc_init_ne2k_isa(NICInfo *nd)
+{
+    static int nb_ne2k = 0;
+
+    if (nb_ne2k == NE2000_NB_MAX)
+        return;
+    isa_ne2000_init(ne2000_io[nb_ne2k],
+                    ne2000_irq[nb_ne2k], nd);
+    nb_ne2k++;
+}
+
+int cpu_is_bsp(CPUState *env)
+{
+    /* We hard-wire the BSP to the first CPU. */
+    return env->cpu_index == 0;
+}
+
+DeviceState *cpu_get_current_apic(void)
+{
+    if (cpu_single_env) {
+        return cpu_single_env->apic_state;
+    } else {
+        return NULL;
+    }
+}
+
+static DeviceState *apic_init(void *env, uint8_t apic_id)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    static int apic_mapped;
+
+    dev = qdev_create(NULL, "apic");
+    qdev_prop_set_uint8(dev, "id", apic_id);
+    qdev_prop_set_ptr(dev, "cpu_env", env);
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+
+    /* XXX: mapping more APICs at the same memory location */
+    if (apic_mapped == 0) {
+        /* NOTE: the APIC is directly connected to the CPU - it is not
+           on the global memory bus. */
+        /* XXX: what if the base changes? */
+        sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        apic_mapped = 1;
+    }
+
+    msix_supported = 1;
+
+    return dev;
+}
+
+/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
+   BIOS will read it and start S3 resume at POST Entry */
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+    ISADevice *s = opaque;
+
+    if (level) {
+        rtc_set_memory(s, 0xF, 0xFE);
+    }
+}
+
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
+{
+    CPUState *s = opaque;
+
+    if (level) {
+        cpu_interrupt(s, CPU_INTERRUPT_SMI);
+    }
+}
+
+static void pc_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->halted = !cpu_is_bsp(env);
+}
+
+static CPUState *pc_new_cpu(const char *cpu_model)
+{
+    CPUState *env;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find x86 CPU definition\n");
+        exit(1);
+    }
+    if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
+        env->cpuid_apic_id = env->cpu_index;
+        env->apic_state = apic_init(env, env->cpuid_apic_id);
+    }
+    qemu_register_reset(pc_cpu_reset, env);
+    pc_cpu_reset(env);
+    return env;
+}
+
+void pc_cpus_init(const char *cpu_model)
+{
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+
+    for(i = 0; i < smp_cpus; i++) {
+        pc_new_cpu(cpu_model);
+    }
+}
+
+void pc_memory_init(const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size)
+{
+    char *filename;
+    int ret, linux_boot, i;
+    ram_addr_t ram_addr, bios_offset, option_rom_offset;
+    int bios_size, isa_bios_size;
+    void *fw_cfg;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* allocate RAM */
+    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
+                              below_4g_mem_size + above_4g_mem_size);
+    cpu_register_physical_memory(0, 0xa0000, ram_addr);
+    cpu_register_physical_memory(0x100000,
+                 below_4g_mem_size - 0x100000,
+                 ram_addr + 0x100000);
+    if (above_4g_mem_size > 0) {
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     ram_addr + below_4g_mem_size);
+    }
+
+    /* BIOS load */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size <= 0 ||
+        (bios_size % 65536) != 0) {
+        goto bios_error;
+    }
+    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
+    if (ret != 0) {
+    bios_error:
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
+        exit(1);
+    }
+    if (filename) {
+        qemu_free(filename);
+    }
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = bios_size;
+    if (isa_bios_size > (128 * 1024))
+        isa_bios_size = 128 * 1024;
+    cpu_register_physical_memory(0x100000 - isa_bios_size,
+                                 isa_bios_size,
+                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
+
+    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
+    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
+
+    /* map all the bios at the top of memory */
+    cpu_register_physical_memory((uint32_t)(-bios_size),
+                                 bios_size, bios_offset | IO_MEM_ROM);
+
+    fw_cfg = bochs_bios_init();
+    rom_set_fw(fw_cfg);
+
+    if (linux_boot) {
+        load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
+    }
+
+    for (i = 0; i < nb_option_roms; i++) {
+        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
+    }
+}
+
+qemu_irq *pc_allocate_cpu_irq(void)
+{
+    return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+
+void pc_vga_init(PCIBus *pci_bus)
+{
+    if (cirrus_vga_enabled) {
+        if (pci_bus) {
+            pci_cirrus_vga_init(pci_bus);
+        } else {
+            isa_cirrus_vga_init();
+        }
+    } else if (vmsvga_enabled) {
+        if (pci_bus) {
+            if (!pci_vmsvga_init(pci_bus)) {
+                fprintf(stderr, "Warning: vmware_vga not available,"
+                        " using standard VGA instead\n");
+                pci_vga_init(pci_bus);
+            }
+        } else {
+            fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+        }
+#ifdef CONFIG_SPICE
+    } else if (qxl_enabled) {
+        if (pci_bus)
+            pci_create_simple(pci_bus, -1, "qxl-vga");
+        else
+            fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
+#endif
+    } else if (std_vga_enabled) {
+        if (pci_bus) {
+            pci_vga_init(pci_bus);
+        } else {
+            isa_vga_init();
+        }
+    }
+
+    /*
+     * sga does not suppress normal vga output. So a machine can have both a
+     * vga card and sga manually enabled. Output will be seen on both.
+     * For nographic case, sga is enabled at all times
+     */
+    if (display_type == DT_NOGRAPHIC) {
+        isa_create_simple("sga");
+    }
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+void pc_basic_device_init(qemu_irq *isa_irq,
+                          ISADevice **rtc_state,
+                          bool no_vmport)
+{
+    int i;
+    DriveInfo *fd[MAX_FD];
+    qemu_irq rtc_irq = NULL;
+    qemu_irq *a20_line;
+    ISADevice *i8042, *port92, *vmmouse, *pit;
+    qemu_irq *cpu_exit_irq;
+
+    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+
+    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+
+    if (!no_hpet) {
+        DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
+
+        if (hpet) {
+            for (i = 0; i < 24; i++) {
+                sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
+            }
+            rtc_irq = qdev_get_gpio_in(hpet, 0);
+        }
+    }
+    *rtc_state = rtc_init(2000, rtc_irq);
+
+    qemu_register_boot_set(pc_boot_set, *rtc_state);
+
+    pit = pit_init(0x40, 0);
+    pcspk_init(pit);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(i, parallel_hds[i]);
+        }
+    }
+
+    a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
+    i8042 = isa_create_simple("i8042");
+    i8042_setup_a20_line(i8042, &a20_line[0]);
+    if (!no_vmport) {
+        vmport_init();
+        vmmouse = isa_try_create("vmmouse");
+    } else {
+        vmmouse = NULL;
+    }
+    if (vmmouse) {
+        qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
+        qdev_init_nofail(&vmmouse->qdev);
+    }
+    port92 = isa_create_simple("port92");
+    port92_init(port92, &a20_line[1]);
+
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
+
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(fd);
+}
+
+void pc_pci_device_init(PCIBus *pci_bus)
+{
+    int max_bus;
+    int bus;
+
+    max_bus = drive_get_max_bus(IF_SCSI);
+    for (bus = 0; bus <= max_bus; bus++) {
+        pci_create_simple(pci_bus, -1, "lsi53c895a");
+    }
+}
diff --git a/qemu-0.15.x/hw/pc.h b/qemu-0.15.x/hw/pc.h
new file mode 100644
index 0000000..6d5730b
--- /dev/null
+++ b/qemu-0.15.x/hw/pc.h
@@ -0,0 +1,241 @@
+#ifndef HW_PC_H
+#define HW_PC_H
+
+#include "qemu-common.h"
+#include "ioport.h"
+#include "isa.h"
+#include "fdc.h"
+#include "net.h"
+
+/* PC-style peripherals (also used by other machines).  */
+
+/* serial.c */
+
+SerialState *serial_init(int base, qemu_irq irq, int baudbase,
+                         CharDriverState *chr);
+SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
+                             qemu_irq irq, int baudbase,
+                             CharDriverState *chr, int ioregister,
+                             int be);
+static inline bool serial_isa_init(int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-serial");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
+
+void serial_set_frequency(SerialState *s, uint32_t frequency);
+
+/* parallel.c */
+static inline bool parallel_init(int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-parallel");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
+
+bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr);
+
+/* i8259.c */
+
+typedef struct PicState2 PicState2;
+extern PicState2 *isa_pic;
+void pic_set_irq(int irq, int level);
+void pic_set_irq_new(void *opaque, int irq, int level);
+qemu_irq *i8259_init(qemu_irq parent_irq);
+int pic_read_irq(PicState2 *s);
+void pic_update_irq(PicState2 *s);
+uint32_t pic_intack_read(PicState2 *s);
+void pic_info(Monitor *mon);
+void irq_info(Monitor *mon);
+
+/* ISA */
+#define IOAPIC_NUM_PINS 0x18
+
+typedef struct isa_irq_state {
+    qemu_irq *i8259;
+    qemu_irq ioapic[IOAPIC_NUM_PINS];
+} IsaIrqState;
+
+void isa_irq_handler(void *opaque, int n, int level);
+
+/* i8254.c */
+
+#define PIT_FREQ 1193182
+
+static inline ISADevice *pit_init(int base, int irq)
+{
+    ISADevice *dev;
+
+    dev = isa_create("isa-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void pit_set_gate(ISADevice *dev, int channel, int val);
+int pit_get_gate(ISADevice *dev, int channel);
+int pit_get_initial_count(ISADevice *dev, int channel);
+int pit_get_mode(ISADevice *dev, int channel);
+int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
+
+void hpet_pit_disable(void);
+void hpet_pit_enable(void);
+
+/* vmport.c */
+static inline void vmport_init(void)
+{
+    isa_create_simple("vmport");
+}
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
+void vmmouse_get_data(uint32_t *data);
+void vmmouse_set_data(const uint32_t *data);
+
+/* pckbd.c */
+
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   target_phys_addr_t base, ram_addr_t size,
+                   target_phys_addr_t mask);
+void i8042_isa_mouse_fake_event(void *opaque);
+void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
+
+/* pc.c */
+extern int fd_bootchk;
+
+void pc_register_ferr_irq(qemu_irq irq);
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level);
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
+
+void pc_cpus_init(const char *cpu_model);
+void pc_memory_init(const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size);
+qemu_irq *pc_allocate_cpu_irq(void);
+void pc_vga_init(PCIBus *pci_bus);
+void pc_basic_device_init(qemu_irq *isa_irq,
+                          ISADevice **rtc_state,
+                          bool no_vmport);
+void pc_init_ne2k_isa(NICInfo *nd);
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                  const char *boot_device,
+                  BusState *ide0, BusState *ide1,
+                  ISADevice *s);
+void pc_pci_device_init(PCIBus *pci_bus);
+
+typedef void (*cpu_set_smm_t)(int smm, void *arg);
+void cpu_smm_register(cpu_set_smm_t callback, void *arg);
+
+/* acpi.c */
+extern int acpi_enabled;
+extern char *acpi_tables;
+extern size_t acpi_tables_len;
+
+void acpi_bios_init(void);
+int acpi_table_add(const char *table_desc);
+
+/* acpi_piix.c */
+
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
+                       int kvm_enabled);
+void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
+
+/* hpet.c */
+extern int no_hpet;
+
+/* pcspk.c */
+void pcspk_init(ISADevice *pit);
+int pcspk_audio_init(qemu_irq *pic);
+
+/* piix_pci.c */
+struct PCII440FXState;
+typedef struct PCII440FXState PCII440FXState;
+
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
+void i440fx_init_memory_mappings(PCII440FXState *d);
+
+/* piix4.c */
+extern PCIDevice *piix4_dev;
+int piix4_init(PCIBus *bus, int devfn);
+
+/* vga.c */
+enum vga_retrace_method {
+    VGA_RETRACE_DUMB,
+    VGA_RETRACE_PRECISE
+};
+
+extern enum vga_retrace_method vga_retrace_method;
+
+static inline int isa_vga_init(void)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create("isa-vga");
+    if (!dev) {
+        fprintf(stderr, "Warning: isa-vga not available\n");
+        return 0;
+    }
+    qdev_init_nofail(&dev->qdev);
+    return 1;
+}
+
+int pci_vga_init(PCIBus *bus);
+int isa_vga_mm_init(target_phys_addr_t vram_base,
+                    target_phys_addr_t ctrl_base, int it_shift);
+
+/* cirrus_vga.c */
+void pci_cirrus_vga_init(PCIBus *bus);
+void isa_cirrus_vga_init(void);
+
+/* ne2000.c */
+static inline bool isa_ne2000_init(int base, int irq, NICInfo *nd)
+{
+    ISADevice *dev;
+
+    qemu_check_nic_model(nd, "ne2k_isa");
+
+    dev = isa_try_create("ne2k_isa");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq",    irq);
+    qdev_set_nic_properties(&dev->qdev, nd);
+    qdev_init_nofail(&dev->qdev);
+    return true;
+}
+
+/* e820 types */
+#define E820_RAM        1
+#define E820_RESERVED   2
+#define E820_ACPI       3
+#define E820_NVS        4
+#define E820_UNUSABLE   5
+
+int e820_add_entry(uint64_t, uint64_t, uint32_t);
+
+#endif
diff --git a/qemu-0.15.x/hw/pc_piix.c b/qemu-0.15.x/hw/pc_piix.c
new file mode 100644
index 0000000..c5c16b4
--- /dev/null
+++ b/qemu-0.15.x/hw/pc_piix.c
@@ -0,0 +1,495 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "apic.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "usb-ohci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "kvm.h"
+#include "kvmclock.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "arch_init.h"
+#include "blockdev.h"
+#include "smbus.h"
+#include "xen.h"
+#ifdef CONFIG_XEN
+#  include <xen/hvm/hvm_info_table.h>
+#endif
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
+static void ioapic_init(IsaIrqState *isa_irq_state)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "ioapic");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+    sysbus_mmio_map(d, 0, 0xfec00000);
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        isa_irq_state->ioapic[i] = qdev_get_gpio_in(dev, i);
+    }
+}
+
+/* PC hardware initialisation */
+static void pc_init1(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename,
+                     const char *kernel_cmdline,
+                     const char *initrd_filename,
+                     const char *cpu_model,
+                     int pci_enabled,
+                     int kvmclock_enabled)
+{
+    int i;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size;
+    PCIBus *pci_bus;
+    PCII440FXState *i440fx_state;
+    int piix3_devfn = -1;
+    qemu_irq *cpu_irq;
+    qemu_irq *isa_irq;
+    qemu_irq *i8259;
+    qemu_irq *cmos_s3;
+    qemu_irq *smi_irq;
+    IsaIrqState *isa_irq_state;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BusState *idebus[MAX_IDE_BUS];
+    ISADevice *rtc_state;
+
+    pc_cpus_init(cpu_model);
+
+    if (kvmclock_enabled) {
+        kvmclock_create();
+    }
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        above_4g_mem_size = 0;
+        below_4g_mem_size = ram_size;
+    }
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        pc_memory_init(kernel_filename, kernel_cmdline, initrd_filename,
+                       below_4g_mem_size, above_4g_mem_size);
+    }
+
+    if (!xen_enabled()) {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(cpu_irq[0]);
+    } else {
+        i8259 = xen_interrupt_controller_init();
+    }
+    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+    isa_irq_state->i8259 = i8259;
+    if (pci_enabled) {
+        ioapic_init(isa_irq_state);
+    }
+    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+    if (pci_enabled) {
+        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+    } else {
+        pci_bus = NULL;
+        i440fx_state = NULL;
+        isa_bus_new(NULL);
+    }
+    isa_bus_irqs(isa_irq);
+
+    pc_register_ferr_irq(isa_get_irq(13));
+
+    pc_vga_init(pci_enabled? pci_bus: NULL);
+
+    if (xen_enabled()) {
+        pci_create_simple(pci_bus, -1, "xen-platform");
+    }
+
+    /* init basic PC hardware */
+    pc_basic_device_init(isa_irq, &rtc_state, xen_enabled());
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
+            pc_init_ne2k_isa(nd);
+        else
+            pci_nic_init_nofail(nd, "e1000", NULL);
+    }
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    if (pci_enabled) {
+        PCIDevice *dev;
+        dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+    } else {
+        for(i = 0; i < MAX_IDE_BUS; i++) {
+            ISADevice *dev;
+            dev = isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+            idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0");
+        }
+    }
+
+    audio_init(isa_irq, pci_enabled ? pci_bus : NULL);
+
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+                 idebus[0], idebus[1], rtc_state);
+
+    if (pci_enabled && usb_enabled) {
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (pci_enabled && acpi_enabled) {
+        i2c_bus *smbus;
+
+        if (!xen_enabled()) {
+            cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+        } else {
+            cmos_s3 = qemu_allocate_irqs(xen_cmos_set_s3_resume, rtc_state, 1);
+        }
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                              isa_get_irq(9), *cmos_s3, *smi_irq,
+                              kvm_enabled());
+        smbus_eeprom_init(smbus, 8, NULL, 0);
+    }
+
+    if (i440fx_state) {
+        i440fx_init_memory_mappings(i440fx_state);
+    }
+
+    if (pci_enabled) {
+        pc_pci_device_init(pci_bus);
+    }
+}
+
+static void pc_init_pci(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    pc_init1(ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 1);
+}
+
+static void pc_init_pci_no_kvmclock(ram_addr_t ram_size,
+                                    const char *boot_device,
+                                    const char *kernel_filename,
+                                    const char *kernel_cmdline,
+                                    const char *initrd_filename,
+                                    const char *cpu_model)
+{
+    pc_init1(ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1, 0);
+}
+
+static void pc_init_isa(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    if (cpu_model == NULL)
+        cpu_model = "486";
+    pc_init1(ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 0, 1);
+}
+
+#ifdef CONFIG_XEN
+static void pc_xen_hvm_init(ram_addr_t ram_size,
+                            const char *boot_device,
+                            const char *kernel_filename,
+                            const char *kernel_cmdline,
+                            const char *initrd_filename,
+                            const char *cpu_model)
+{
+    if (xen_hvm_init() != 0) {
+        hw_error("xen hardware virtual machine initialisation failed");
+    }
+    pc_init_pci_no_kvmclock(ram_size, boot_device,
+                            kernel_filename, kernel_cmdline,
+                            initrd_filename, cpu_model);
+    xen_vcpu_init();
+}
+#endif
+
+static QEMUMachine pc_machine = {
+    .name = "pc-0.14",
+    .alias = "pc",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .is_default = 1,
+};
+
+static QEMUMachine pc_machine_v0_13 = {
+    .name = "pc-0.13",
+    .desc = "Standard PC",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-9p-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    },
+};
+
+static QEMUMachine pc_machine_v0_12 = {
+    .name = "pc-0.12",
+    .desc = "Standard PC",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-serial-pci",
+            .property = "max_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    }
+};
+
+static QEMUMachine pc_machine_v0_11 = {
+    .name = "pc-0.11",
+    .desc = "Standard PC, qemu 0.11",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-blk-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "max_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "ide-drive",
+            .property = "ver",
+            .value    = "0.11",
+        },{
+            .driver   = "scsi-disk",
+            .property = "ver",
+            .value    = "0.11",
+        },{
+            .driver   = "PCI",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    }
+};
+
+static QEMUMachine pc_machine_v0_10 = {
+    .name = "pc-0.10",
+    .desc = "Standard PC, qemu 0.10",
+    .init = pc_init_pci_no_kvmclock,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-blk-pci",
+            .property = "class",
+            .value    = stringify(PCI_CLASS_STORAGE_OTHER),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "class",
+            .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "max_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "ide-drive",
+            .property = "ver",
+            .value    = "0.10",
+        },{
+            .driver   = "scsi-disk",
+            .property = "ver",
+            .value    = "0.10",
+        },{
+            .driver   = "PCI",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    },
+};
+
+static QEMUMachine isapc_machine = {
+    .name = "isapc",
+    .desc = "ISA-only PC",
+    .init = pc_init_isa,
+    .max_cpus = 1,
+};
+
+#ifdef CONFIG_XEN
+static QEMUMachine xenfv_machine = {
+    .name = "xenfv",
+    .desc = "Xen Fully-virtualized PC",
+    .init = pc_xen_hvm_init,
+    .max_cpus = HVM_MAX_VCPUS,
+    .default_machine_opts = "accel=xen",
+};
+#endif
+
+static void pc_machine_init(void)
+{
+    qemu_register_machine(&pc_machine);
+    qemu_register_machine(&pc_machine_v0_13);
+    qemu_register_machine(&pc_machine_v0_12);
+    qemu_register_machine(&pc_machine_v0_11);
+    qemu_register_machine(&pc_machine_v0_10);
+    qemu_register_machine(&isapc_machine);
+#ifdef CONFIG_XEN
+    qemu_register_machine(&xenfv_machine);
+#endif
+}
+
+machine_init(pc_machine_init);
diff --git a/qemu-0.15.x/hw/pci-hotplug.c b/qemu-0.15.x/hw/pci-hotplug.c
new file mode 100644
index 0000000..b59be2a
--- /dev/null
+++ b/qemu-0.15.x/hw/pci-hotplug.c
@@ -0,0 +1,292 @@
+/*
+ * QEMU PCI hotplug support
+ *
+ * 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 "hw.h"
+#include "boards.h"
+#include "pci.h"
+#include "net.h"
+#include "pc.h"
+#include "monitor.h"
+#include "scsi.h"
+#include "virtio-blk.h"
+#include "qemu-config.h"
+#include "blockdev.h"
+
+#if defined(TARGET_I386)
+static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
+                                       const char *devaddr,
+                                       const char *opts_str)
+{
+    QemuOpts *opts;
+    PCIBus *bus;
+    int ret, devfn;
+
+    bus = pci_get_bus_devfn(&devfn, devaddr);
+    if (!bus) {
+        monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
+        return NULL;
+    }
+    if (!((BusState*)bus)->allow_hotplug) {
+        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
+        return NULL;
+    }
+
+    opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
+    if (!opts) {
+        return NULL;
+    }
+
+    qemu_opt_set(opts, "type", "nic");
+
+    ret = net_client_init(mon, opts, 0);
+    if (ret < 0)
+        return NULL;
+    if (nd_table[ret].devaddr) {
+        monitor_printf(mon, "Parameter addr not supported\n");
+        return NULL;
+    }
+    return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
+}
+
+static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
+                        DriveInfo *dinfo, int printinfo)
+{
+    SCSIBus *scsibus;
+    SCSIDevice *scsidev;
+
+    scsibus = DO_UPCAST(SCSIBus, qbus, QLIST_FIRST(&adapter->child_bus));
+    if (!scsibus || strcmp(scsibus->qbus.info->name, "SCSI") != 0) {
+        error_report("Device is not a SCSI adapter");
+        return -1;
+    }
+
+    /*
+     * drive_init() tries to find a default for dinfo->unit.  Doesn't
+     * work at all for hotplug though as we assign the device to a
+     * specific bus instead of the first bus with spare scsi ids.
+     *
+     * Ditch the calculated value and reload from option string (if
+     * specified).
+     */
+    dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
+    dinfo->bus = scsibus->busnr;
+    scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false);
+    if (!scsidev) {
+        return -1;
+    }
+    dinfo->unit = scsidev->id;
+
+    if (printinfo)
+        monitor_printf(mon, "OK bus %d, unit %d\n",
+                       scsibus->busnr, scsidev->id);
+    return 0;
+}
+
+void drive_hot_add(Monitor *mon, const QDict *qdict)
+{
+    int dom, pci_bus;
+    unsigned slot;
+    int type;
+    PCIDevice *dev;
+    DriveInfo *dinfo = NULL;
+    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
+    const char *opts = qdict_get_str(qdict, "opts");
+
+    dinfo = add_init_drive(opts);
+    if (!dinfo)
+        goto err;
+    if (dinfo->devaddr) {
+        monitor_printf(mon, "Parameter addr not supported\n");
+        goto err;
+    }
+    type = dinfo->type;
+
+    switch (type) {
+    case IF_SCSI:
+        if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
+            goto err;
+        }
+        dev = pci_find_device(pci_find_root_bus(dom), pci_bus,
+                              PCI_DEVFN(slot, 0));
+        if (!dev) {
+            monitor_printf(mon, "no pci device with address %s\n", pci_addr);
+            goto err;
+        }
+        if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) {
+            goto err;
+        }
+        break;
+    case IF_NONE:
+        monitor_printf(mon, "OK\n");
+        break;
+    default:
+        monitor_printf(mon, "Can't hot-add drive to type %d\n", type);
+        goto err;
+    }
+    return;
+
+err:
+    if (dinfo)
+        drive_put_ref(dinfo);
+    return;
+}
+
+static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
+                                           const char *devaddr,
+                                           const char *opts)
+{
+    PCIDevice *dev;
+    DriveInfo *dinfo = NULL;
+    int type = -1;
+    char buf[128];
+    PCIBus *bus;
+    int devfn;
+
+    if (get_param_value(buf, sizeof(buf), "if", opts)) {
+        if (!strcmp(buf, "scsi"))
+            type = IF_SCSI;
+        else if (!strcmp(buf, "virtio")) {
+            type = IF_VIRTIO;
+        } else {
+            monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf);
+            return NULL;
+        }
+    } else {
+        monitor_printf(mon, "no if= specified\n");
+        return NULL;
+    }
+
+    if (get_param_value(buf, sizeof(buf), "file", opts)) {
+        dinfo = add_init_drive(opts);
+        if (!dinfo)
+            return NULL;
+        if (dinfo->devaddr) {
+            monitor_printf(mon, "Parameter addr not supported\n");
+            return NULL;
+        }
+    } else {
+        dinfo = NULL;
+    }
+
+    bus = pci_get_bus_devfn(&devfn, devaddr);
+    if (!bus) {
+        monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
+        return NULL;
+    }
+    if (!((BusState*)bus)->allow_hotplug) {
+        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
+        return NULL;
+    }
+
+    switch (type) {
+    case IF_SCSI:
+        dev = pci_create(bus, devfn, "lsi53c895a");
+        if (qdev_init(&dev->qdev) < 0)
+            dev = NULL;
+        if (dev && dinfo) {
+            if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) {
+                qdev_unplug(&dev->qdev);
+                dev = NULL;
+            }
+        }
+        break;
+    case IF_VIRTIO:
+        if (!dinfo) {
+            monitor_printf(mon, "virtio requires a backing file/device.\n");
+            return NULL;
+        }
+        dev = pci_create(bus, devfn, "virtio-blk-pci");
+        if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
+            qdev_free(&dev->qdev);
+            dev = NULL;
+            break;
+        }
+        if (qdev_init(&dev->qdev) < 0)
+            dev = NULL;
+        break;
+    default:
+        dev = NULL;
+    }
+    return dev;
+}
+
+void pci_device_hot_add(Monitor *mon, const QDict *qdict)
+{
+    PCIDevice *dev = NULL;
+    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
+    const char *type = qdict_get_str(qdict, "type");
+    const char *opts = qdict_get_try_str(qdict, "opts");
+
+    /* strip legacy tag */
+    if (!strncmp(pci_addr, "pci_addr=", 9)) {
+        pci_addr += 9;
+    }
+
+    if (!opts) {
+        opts = "";
+    }
+
+    if (!strcmp(pci_addr, "auto"))
+        pci_addr = NULL;
+
+    if (strcmp(type, "nic") == 0) {
+        dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
+    } else if (strcmp(type, "storage") == 0) {
+        dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
+    } else {
+        monitor_printf(mon, "invalid type: %s\n", type);
+    }
+
+    if (dev) {
+        monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
+                       pci_find_domain(dev->bus),
+                       pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
+                       PCI_FUNC(dev->devfn));
+    } else
+        monitor_printf(mon, "failed to add %s\n", opts);
+}
+#endif
+
+static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
+{
+    PCIDevice *d;
+    int dom, bus;
+    unsigned slot;
+
+    if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
+        return -1;
+    }
+
+    d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0));
+    if (!d) {
+        monitor_printf(mon, "slot %d empty\n", slot);
+        return -1;
+    }
+    return qdev_unplug(&d->qdev);
+}
+
+void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict)
+{
+    pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
+}
diff --git a/qemu-0.15.x/hw/pci-stub.c b/qemu-0.15.x/hw/pci-stub.c
new file mode 100644
index 0000000..c5a0aa8
--- /dev/null
+++ b/qemu-0.15.x/hw/pci-stub.c
@@ -0,0 +1,50 @@
+/*
+ * PCI stubs for plathome that doesn't support pci bus.
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu.h"
+#include "monitor.h"
+#include "pci.h"
+
+static void pci_error_message(Monitor *mon)
+{
+    monitor_printf(mon, "PCI devices not supported\n");
+}
+
+void do_pci_info(Monitor *mon, QObject **ret_data)
+{
+    pci_error_message(mon);
+}
+
+void do_pci_info_print(Monitor *mon, const QObject *data)
+{
+    pci_error_message(mon);
+}
+
+int do_pcie_aer_inejct_error(Monitor *mon,
+                             const QDict *qdict, QObject **ret_data)
+{
+    pci_error_message(mon);
+    return -ENOSYS;
+}
+
+void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
+{
+    pci_error_message(mon);
+}
diff --git a/qemu-0.15.x/hw/pci.c b/qemu-0.15.x/hw/pci.c
new file mode 100644
index 0000000..b904a4e
--- /dev/null
+++ b/qemu-0.15.x/hw/pci.c
@@ -0,0 +1,2185 @@
+/*
+ * 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 "hw.h"
+#include "pci.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "monitor.h"
+#include "net.h"
+#include "sysemu.h"
+#include "loader.h"
+#include "qemu-objects.h"
+#include "range.h"
+
+//#define DEBUG_PCI
+#ifdef DEBUG_PCI
+# define PCI_DPRINTF(format, ...)       printf(format, ## __VA_ARGS__)
+#else
+# define PCI_DPRINTF(format, ...)       do { } while (0)
+#endif
+
+static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *pcibus_get_dev_path(DeviceState *dev);
+static char *pcibus_get_fw_dev_path(DeviceState *dev);
+static int pcibus_reset(BusState *qbus);
+
+struct BusInfo pci_bus_info = {
+    .name       = "PCI",
+    .size       = sizeof(PCIBus),
+    .print_dev  = pcibus_dev_print,
+    .get_dev_path = pcibus_get_dev_path,
+    .get_fw_dev_path = pcibus_get_fw_dev_path,
+    .reset      = pcibus_reset,
+    .props      = (Property[]) {
+        DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+        DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
+        DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
+        DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
+                        QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
+        DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
+                        QEMU_PCI_CAP_SERR_BITNR, true),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void pci_update_mappings(PCIDevice *d);
+static void pci_set_irq(void *opaque, int irq_num, int level);
+static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
+static void pci_del_option_rom(PCIDevice *pdev);
+
+static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
+static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
+
+struct PCIHostBus {
+    int domain;
+    struct PCIBus *bus;
+    QLIST_ENTRY(PCIHostBus) next;
+};
+static QLIST_HEAD(, PCIHostBus) host_buses;
+
+static const VMStateDescription vmstate_pcibus = {
+    .name = "PCIBUS",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(nirq, PCIBus),
+        VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pci_bar(PCIDevice *d, int reg)
+{
+    uint8_t type;
+
+    if (reg != PCI_ROM_SLOT)
+        return PCI_BASE_ADDRESS_0 + reg * 4;
+
+    type = d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
+}
+
+static inline int pci_irq_state(PCIDevice *d, int irq_num)
+{
+	return (d->irq_state >> irq_num) & 0x1;
+}
+
+static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
+{
+	d->irq_state &= ~(0x1 << irq_num);
+	d->irq_state |= level << irq_num;
+}
+
+static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
+{
+    PCIBus *bus;
+    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);
+}
+
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
+{
+    assert(irq_num >= 0);
+    assert(irq_num < bus->nirq);
+    return !!bus->irq_count[irq_num];
+}
+
+/* Update interrupt status bit in config space on interrupt
+ * state change. */
+static void pci_update_irq_status(PCIDevice *dev)
+{
+    if (dev->irq_state) {
+        dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
+    } else {
+        dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
+    }
+}
+
+void pci_device_deassert_intx(PCIDevice *dev)
+{
+    int i;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_set_irq(dev->irq[i], 0);
+    }
+}
+
+/*
+ * This function is called on #RST and FLR.
+ * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
+ */
+void pci_device_reset(PCIDevice *dev)
+{
+    int r;
+    /* TODO: call the below unconditionally once all pci devices
+     * are qdevified */
+    if (dev->qdev.info) {
+        qdev_reset_all(&dev->qdev);
+    }
+
+    dev->irq_state = 0;
+    pci_update_irq_status(dev);
+    pci_device_deassert_intx(dev);
+    /* Clear all writable bits */
+    pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
+                                 pci_get_word(dev->wmask + PCI_COMMAND) |
+                                 pci_get_word(dev->w1cmask + PCI_COMMAND));
+    pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
+                                 pci_get_word(dev->wmask + PCI_STATUS) |
+                                 pci_get_word(dev->w1cmask + PCI_STATUS));
+    dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
+    dev->config[PCI_INTERRUPT_LINE] = 0x0;
+    for (r = 0; r < PCI_NUM_REGIONS; ++r) {
+        PCIIORegion *region = &dev->io_regions[r];
+        if (!region->size) {
+            continue;
+        }
+
+        if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
+            region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+            pci_set_quad(dev->config + pci_bar(dev, r), region->type);
+        } else {
+            pci_set_long(dev->config + pci_bar(dev, r), region->type);
+        }
+    }
+    pci_update_mappings(dev);
+}
+
+/*
+ * Trigger pci bus reset under a given bus.
+ * To be called on RST# assert.
+ */
+void pci_bus_reset(PCIBus *bus)
+{
+    int i;
+
+    for (i = 0; i < bus->nirq; i++) {
+        bus->irq_count[i] = 0;
+    }
+    for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
+        if (bus->devices[i]) {
+            pci_device_reset(bus->devices[i]);
+        }
+    }
+}
+
+static int pcibus_reset(BusState *qbus)
+{
+    pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
+
+    /* topology traverse is done by pci_bus_reset().
+       Tell qbus/qdev walker not to traverse the tree */
+    return 1;
+}
+
+static void pci_host_bus_register(int domain, PCIBus *bus)
+{
+    struct PCIHostBus *host;
+    host = qemu_mallocz(sizeof(*host));
+    host->domain = domain;
+    host->bus = bus;
+    QLIST_INSERT_HEAD(&host_buses, host, next);
+}
+
+PCIBus *pci_find_root_bus(int domain)
+{
+    struct PCIHostBus *host;
+
+    QLIST_FOREACH(host, &host_buses, next) {
+        if (host->domain == domain) {
+            return host->bus;
+        }
+    }
+
+    return NULL;
+}
+
+int pci_find_domain(const PCIBus *bus)
+{
+    PCIDevice *d;
+    struct PCIHostBus *host;
+
+    /* obtain root bus */
+    while ((d = bus->parent_dev) != NULL) {
+        bus = d->bus;
+    }
+
+    QLIST_FOREACH(host, &host_buses, next) {
+        if (host->bus == bus) {
+            return host->domain;
+        }
+    }
+
+    abort();    /* should not be reached */
+    return -1;
+}
+
+void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
+                         const char *name, uint8_t devfn_min)
+{
+    qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
+    assert(PCI_FUNC(devfn_min) == 0);
+    bus->devfn_min = devfn_min;
+
+    /* host bridge */
+    QLIST_INIT(&bus->child);
+    pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */
+
+    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
+}
+
+PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min)
+{
+    PCIBus *bus;
+
+    bus = qemu_mallocz(sizeof(*bus));
+    bus->qbus.qdev_allocated = 1;
+    pci_bus_new_inplace(bus, parent, name, devfn_min);
+    return bus;
+}
+
+void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                  void *irq_opaque, int nirq)
+{
+    bus->set_irq = set_irq;
+    bus->map_irq = map_irq;
+    bus->irq_opaque = irq_opaque;
+    bus->nirq = nirq;
+    bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
+}
+
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
+{
+    bus->qbus.allow_hotplug = 1;
+    bus->hotplug = hotplug;
+    bus->hotplug_qdev = qdev;
+}
+
+void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
+{
+    bus->mem_base = base;
+}
+
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                         void *irq_opaque, uint8_t devfn_min, int nirq)
+{
+    PCIBus *bus;
+
+    bus = pci_bus_new(parent, name, devfn_min);
+    pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
+    return bus;
+}
+
+int pci_bus_num(PCIBus *s)
+{
+    if (!s->parent_dev)
+        return 0;       /* pci host bridge */
+    return s->parent_dev->config[PCI_SECONDARY_BUS];
+}
+
+static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
+{
+    PCIDevice *s = container_of(pv, PCIDevice, config);
+    uint8_t *config;
+    int i;
+
+    assert(size == pci_config_size(s));
+    config = qemu_malloc(size);
+
+    qemu_get_buffer(f, config, size);
+    for (i = 0; i < size; ++i) {
+        if ((config[i] ^ s->config[i]) &
+            s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
+            qemu_free(config);
+            return -EINVAL;
+        }
+    }
+    memcpy(s->config, config, size);
+
+    pci_update_mappings(s);
+
+    qemu_free(config);
+    return 0;
+}
+
+/* just put buffer */
+static void put_pci_config_device(QEMUFile *f, void *pv, size_t size)
+{
+    const uint8_t **v = pv;
+    assert(size == pci_config_size(container_of(pv, PCIDevice, config)));
+    qemu_put_buffer(f, *v, size);
+}
+
+static VMStateInfo vmstate_info_pci_config = {
+    .name = "pci config",
+    .get  = get_pci_config_device,
+    .put  = put_pci_config_device,
+};
+
+static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
+{
+    PCIDevice *s = container_of(pv, PCIDevice, irq_state);
+    uint32_t irq_state[PCI_NUM_PINS];
+    int i;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        irq_state[i] = qemu_get_be32(f);
+        if (irq_state[i] != 0x1 && irq_state[i] != 0) {
+            fprintf(stderr, "irq state %d: must be 0 or 1.\n",
+                    irq_state[i]);
+            return -EINVAL;
+        }
+    }
+
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        pci_set_irq_state(s, i, irq_state[i]);
+    }
+
+    return 0;
+}
+
+static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
+{
+    int i;
+    PCIDevice *s = container_of(pv, PCIDevice, irq_state);
+
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_put_be32(f, pci_irq_state(s, i));
+    }
+}
+
+static VMStateInfo vmstate_info_pci_irq_state = {
+    .name = "pci irq state",
+    .get  = get_pci_irq_state,
+    .put  = put_pci_irq_state,
+};
+
+const VMStateDescription vmstate_pci_device = {
+    .name = "PCIDevice",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_LE(version_id, PCIDevice),
+        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
+                                   vmstate_info_pci_config,
+                                   PCI_CONFIG_SPACE_SIZE),
+        VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
+				   vmstate_info_pci_irq_state,
+				   PCI_NUM_PINS * sizeof(int32_t)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_pcie_device = {
+    .name = "PCIDevice",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_LE(version_id, PCIDevice),
+        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
+                                   vmstate_info_pci_config,
+                                   PCIE_CONFIG_SPACE_SIZE),
+        VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
+				   vmstate_info_pci_irq_state,
+				   PCI_NUM_PINS * sizeof(int32_t)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s)
+{
+    return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device;
+}
+
+void pci_device_save(PCIDevice *s, QEMUFile *f)
+{
+    /* Clear interrupt status bit: it is implicit
+     * in irq_state which we are saving.
+     * This makes us compatible with old devices
+     * which never set or clear this bit. */
+    s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
+    vmstate_save_state(f, pci_get_vmstate(s), s);
+    /* Restore the interrupt status bit. */
+    pci_update_irq_status(s);
+}
+
+int pci_device_load(PCIDevice *s, QEMUFile *f)
+{
+    int ret;
+    ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
+    /* Restore the interrupt status bit. */
+    pci_update_irq_status(s);
+    return ret;
+}
+
+static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
+{
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+                 pci_default_sub_vendor_id);
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+                 pci_default_sub_device_id);
+}
+
+/*
+ * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
+ *       [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
+ */
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+                      unsigned int *slotp, unsigned int *funcp)
+{
+    const char *p;
+    char *e;
+    unsigned long val;
+    unsigned long dom = 0, bus = 0;
+    unsigned int slot = 0;
+    unsigned int func = 0;
+
+    p = addr;
+    val = strtoul(p, &e, 16);
+    if (e == p)
+	return -1;
+    if (*e == ':') {
+	bus = val;
+	p = e + 1;
+	val = strtoul(p, &e, 16);
+	if (e == p)
+	    return -1;
+	if (*e == ':') {
+	    dom = bus;
+	    bus = val;
+	    p = e + 1;
+	    val = strtoul(p, &e, 16);
+	    if (e == p)
+		return -1;
+	}
+    }
+
+    slot = val;
+
+    if (funcp != NULL) {
+        if (*e != '.')
+            return -1;
+
+        p = e + 1;
+        val = strtoul(p, &e, 16);
+        if (e == p)
+            return -1;
+
+        func = val;
+    }
+
+    /* if funcp == NULL func is 0 */
+    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
+	return -1;
+
+    if (*e)
+	return -1;
+
+    /* Note: QEMU doesn't implement domains other than 0 */
+    if (!pci_find_bus(pci_find_root_bus(dom), bus))
+	return -1;
+
+    *domp = dom;
+    *busp = bus;
+    *slotp = slot;
+    if (funcp != NULL)
+        *funcp = func;
+    return 0;
+}
+
+int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
+                     unsigned *slotp)
+{
+    /* strip legacy tag */
+    if (!strncmp(addr, "pci_addr=", 9)) {
+        addr += 9;
+    }
+    if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
+        monitor_printf(mon, "Invalid pci address\n");
+        return -1;
+    }
+    return 0;
+}
+
+PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
+{
+    int dom, bus;
+    unsigned slot;
+
+    if (!devaddr) {
+        *devfnp = -1;
+        return pci_find_bus(pci_find_root_bus(0), 0);
+    }
+
+    if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
+        return NULL;
+    }
+
+    *devfnp = PCI_DEVFN(slot, 0);
+    return pci_find_bus(pci_find_root_bus(dom), bus);
+}
+
+static void pci_init_cmask(PCIDevice *dev)
+{
+    pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff);
+    pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff);
+    dev->cmask[PCI_STATUS] = PCI_STATUS_CAP_LIST;
+    dev->cmask[PCI_REVISION_ID] = 0xff;
+    dev->cmask[PCI_CLASS_PROG] = 0xff;
+    pci_set_word(dev->cmask + PCI_CLASS_DEVICE, 0xffff);
+    dev->cmask[PCI_HEADER_TYPE] = 0xff;
+    dev->cmask[PCI_CAPABILITY_LIST] = 0xff;
+}
+
+static void pci_init_wmask(PCIDevice *dev)
+{
+    int config_size = pci_config_size(dev);
+
+    dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
+    dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
+    pci_set_word(dev->wmask + PCI_COMMAND,
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+                 PCI_COMMAND_INTX_DISABLE);
+    if (dev->cap_present & QEMU_PCI_CAP_SERR) {
+        pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
+    }
+
+    memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
+           config_size - PCI_CONFIG_HEADER_SIZE);
+}
+
+static void pci_init_w1cmask(PCIDevice *dev)
+{
+    /*
+     * Note: It's okay to set w1cmask even for readonly bits as
+     * long as their value is hardwired to 0.
+     */
+    pci_set_word(dev->w1cmask + PCI_STATUS,
+                 PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
+                 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
+                 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
+}
+
+static void pci_init_wmask_bridge(PCIDevice *d)
+{
+    /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
+       PCI_SEC_LETENCY_TIMER */
+    memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4);
+
+    /* base and limit */
+    d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff;
+    d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff;
+    pci_set_word(d->wmask + PCI_MEMORY_BASE,
+                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_set_word(d->wmask + PCI_MEMORY_LIMIT,
+                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE,
+                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT,
+                 PCI_PREF_RANGE_MASK & 0xffff);
+
+    /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
+    memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
+
+/* TODO: add this define to pci_regs.h in linux and then in qemu. */
+#define  PCI_BRIDGE_CTL_VGA_16BIT	0x10	/* VGA 16-bit decode */
+#define  PCI_BRIDGE_CTL_DISCARD		0x100	/* Primary discard timer */
+#define  PCI_BRIDGE_CTL_SEC_DISCARD	0x200	/* Secondary discard timer */
+#define  PCI_BRIDGE_CTL_DISCARD_STATUS	0x400	/* Discard timer status */
+#define  PCI_BRIDGE_CTL_DISCARD_SERR	0x800	/* Discard timer SERR# enable */
+    pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
+                 PCI_BRIDGE_CTL_PARITY |
+                 PCI_BRIDGE_CTL_SERR |
+                 PCI_BRIDGE_CTL_ISA |
+                 PCI_BRIDGE_CTL_VGA |
+                 PCI_BRIDGE_CTL_VGA_16BIT |
+                 PCI_BRIDGE_CTL_MASTER_ABORT |
+                 PCI_BRIDGE_CTL_BUS_RESET |
+                 PCI_BRIDGE_CTL_FAST_BACK |
+                 PCI_BRIDGE_CTL_DISCARD |
+                 PCI_BRIDGE_CTL_SEC_DISCARD |
+                 PCI_BRIDGE_CTL_DISCARD_SERR);
+    /* Below does not do anything as we never set this bit, put here for
+     * completeness. */
+    pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
+                 PCI_BRIDGE_CTL_DISCARD_STATUS);
+}
+
+static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
+{
+    uint8_t slot = PCI_SLOT(dev->devfn);
+    uint8_t func;
+
+    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+        dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+    }
+
+    /*
+     * multifunction bit is interpreted in two ways as follows.
+     *   - all functions must set the bit to 1.
+     *     Example: Intel X53
+     *   - function 0 must set the bit, but the rest function (> 0)
+     *     is allowed to leave the bit to 0.
+     *     Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
+     *
+     * So OS (at least Linux) checks the bit of only function 0,
+     * and doesn't see the bit of function > 0.
+     *
+     * The below check allows both interpretation.
+     */
+    if (PCI_FUNC(dev->devfn)) {
+        PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
+        if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
+            /* function 0 should set multifunction bit */
+            error_report("PCI: single function device can't be populated "
+                         "in function %x.%x", slot, PCI_FUNC(dev->devfn));
+            return -1;
+        }
+        return 0;
+    }
+
+    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+        return 0;
+    }
+    /* function 0 indicates single function, so function > 0 must be NULL */
+    for (func = 1; func < PCI_FUNC_MAX; ++func) {
+        if (bus->devices[PCI_DEVFN(slot, func)]) {
+            error_report("PCI: %x.0 indicates single function, "
+                         "but %x.%x is already populated.",
+                         slot, slot, func);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void pci_config_alloc(PCIDevice *pci_dev)
+{
+    int config_size = pci_config_size(pci_dev);
+
+    pci_dev->config = qemu_mallocz(config_size);
+    pci_dev->cmask = qemu_mallocz(config_size);
+    pci_dev->wmask = qemu_mallocz(config_size);
+    pci_dev->w1cmask = qemu_mallocz(config_size);
+    pci_dev->used = qemu_mallocz(config_size);
+}
+
+static void pci_config_free(PCIDevice *pci_dev)
+{
+    qemu_free(pci_dev->config);
+    qemu_free(pci_dev->cmask);
+    qemu_free(pci_dev->wmask);
+    qemu_free(pci_dev->w1cmask);
+    qemu_free(pci_dev->used);
+}
+
+/* -1 for devfn means auto assign */
+static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
+                                         const char *name, int devfn,
+                                         const PCIDeviceInfo *info)
+{
+    PCIConfigReadFunc *config_read = info->config_read;
+    PCIConfigWriteFunc *config_write = info->config_write;
+
+    if (devfn < 0) {
+        for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
+            devfn += PCI_FUNC_MAX) {
+            if (!bus->devices[devfn])
+                goto found;
+        }
+        error_report("PCI: no slot/function available for %s, all in use", name);
+        return NULL;
+    found: ;
+    } else if (bus->devices[devfn]) {
+        error_report("PCI: slot %d function %d not available for %s, in use by %s",
+                     PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name);
+        return NULL;
+    }
+    pci_dev->bus = bus;
+    pci_dev->devfn = devfn;
+    pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
+    pci_dev->irq_state = 0;
+    pci_config_alloc(pci_dev);
+
+    pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
+    pci_config_set_device_id(pci_dev->config, info->device_id);
+    pci_config_set_revision(pci_dev->config, info->revision);
+    pci_config_set_class(pci_dev->config, info->class_id);
+
+    if (!info->is_bridge) {
+        if (info->subsystem_vendor_id || info->subsystem_id) {
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+                         info->subsystem_vendor_id);
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+                         info->subsystem_id);
+        } else {
+            pci_set_default_subsystem_id(pci_dev);
+        }
+    } else {
+        /* subsystem_vendor_id/subsystem_id are only for header type 0 */
+        assert(!info->subsystem_vendor_id);
+        assert(!info->subsystem_id);
+    }
+    pci_init_cmask(pci_dev);
+    pci_init_wmask(pci_dev);
+    pci_init_w1cmask(pci_dev);
+    if (info->is_bridge) {
+        pci_init_wmask_bridge(pci_dev);
+    }
+    if (pci_init_multifunction(bus, pci_dev)) {
+        pci_config_free(pci_dev);
+        return NULL;
+    }
+
+    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;
+    bus->devices[devfn] = pci_dev;
+    pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
+    pci_dev->version_id = 2; /* Current pci device vmstate version */
+    return pci_dev;
+}
+
+static void do_pci_unregister_device(PCIDevice *pci_dev)
+{
+    qemu_free_irqs(pci_dev->irq);
+    pci_dev->bus->devices[pci_dev->devfn] = NULL;
+    pci_config_free(pci_dev);
+}
+
+/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write)
+{
+    PCIDevice *pci_dev;
+    PCIDeviceInfo info = {
+        .config_read = config_read,
+        .config_write = config_write,
+    };
+
+    pci_dev = qemu_mallocz(instance_size);
+    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
+    if (pci_dev == NULL) {
+        hw_error("PCI: can't register device\n");
+    }
+    return pci_dev;
+}
+
+static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
+                                          target_phys_addr_t addr)
+{
+    return addr + bus->mem_base;
+}
+
+static void pci_unregister_io_regions(PCIDevice *pci_dev)
+{
+    PCIIORegion *r;
+    int i;
+
+    for(i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &pci_dev->io_regions[i];
+        if (!r->size || r->addr == PCI_BAR_UNMAPPED)
+            continue;
+        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
+            isa_unassign_ioport(r->addr, r->filtered_size);
+        } else {
+            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
+                                                         r->addr),
+                                         r->filtered_size,
+                                         IO_MEM_UNASSIGNED);
+        }
+    }
+}
+
+static int pci_unregister_device(DeviceState *dev)
+{
+    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
+    PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info);
+    int ret = 0;
+
+    if (info->exit)
+        ret = info->exit(pci_dev);
+    if (ret)
+        return ret;
+
+    pci_unregister_io_regions(pci_dev);
+    pci_del_option_rom(pci_dev);
+    qemu_free(pci_dev->romfile);
+    do_pci_unregister_device(pci_dev);
+    return 0;
+}
+
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+                            pcibus_t size, uint8_t type,
+                            PCIMapIORegionFunc *map_func)
+{
+    PCIIORegion *r;
+    uint32_t addr;
+    uint64_t wmask;
+
+    assert(region_num >= 0);
+    assert(region_num < PCI_NUM_REGIONS);
+    if (size & (size-1)) {
+        fprintf(stderr, "ERROR: PCI region size must be pow2 "
+                    "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
+        exit(1);
+    }
+
+    r = &pci_dev->io_regions[region_num];
+    r->addr = PCI_BAR_UNMAPPED;
+    r->size = size;
+    r->filtered_size = size;
+    r->type = type;
+    r->map_func = map_func;
+    r->ram_addr = IO_MEM_UNASSIGNED;
+
+    wmask = ~(size - 1);
+    addr = pci_bar(pci_dev, region_num);
+    if (region_num == PCI_ROM_SLOT) {
+        /* ROM enable bit is writable */
+        wmask |= PCI_ROM_ADDRESS_ENABLE;
+    }
+    pci_set_long(pci_dev->config + addr, type);
+    if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
+        r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        pci_set_quad(pci_dev->wmask + addr, wmask);
+        pci_set_quad(pci_dev->cmask + addr, ~0ULL);
+    } else {
+        pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
+        pci_set_long(pci_dev->cmask + addr, 0xffffffff);
+    }
+}
+
+static void pci_simple_bar_mapfunc(PCIDevice *pci_dev, int region_num,
+                                   pcibus_t addr, pcibus_t size, int type)
+{
+    cpu_register_physical_memory(addr, size,
+                                 pci_dev->io_regions[region_num].ram_addr);
+}
+
+void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
+                             pcibus_t size,  uint8_t attr, ram_addr_t ram_addr)
+{
+    pci_register_bar(pci_dev, region_num, size,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY | attr,
+                     pci_simple_bar_mapfunc);
+    pci_dev->io_regions[region_num].ram_addr = ram_addr;
+}
+
+static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
+                              uint8_t type)
+{
+    pcibus_t base = *addr;
+    pcibus_t limit = *addr + *size - 1;
+    PCIDevice *br;
+
+    for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) {
+        uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
+
+        if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+            if (!(cmd & PCI_COMMAND_IO)) {
+                goto no_map;
+            }
+        } else {
+            if (!(cmd & PCI_COMMAND_MEMORY)) {
+                goto no_map;
+            }
+        }
+
+        base = MAX(base, pci_bridge_get_base(br, type));
+        limit = MIN(limit, pci_bridge_get_limit(br, type));
+    }
+
+    if (base > limit) {
+        goto no_map;
+    }
+    *addr = base;
+    *size = limit - base + 1;
+    return;
+no_map:
+    *addr = PCI_BAR_UNMAPPED;
+    *size = 0;
+}
+
+static pcibus_t pci_bar_address(PCIDevice *d,
+				int reg, uint8_t type, pcibus_t size)
+{
+    pcibus_t new_addr, last_addr;
+    int bar = pci_bar(d, reg);
+    uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
+
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        if (!(cmd & PCI_COMMAND_IO)) {
+            return PCI_BAR_UNMAPPED;
+        }
+        new_addr = pci_get_long(d->config + bar) & ~(size - 1);
+        last_addr = new_addr + size - 1;
+        /* NOTE: we have only 64K ioports on PC */
+        if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) {
+            return PCI_BAR_UNMAPPED;
+        }
+        return new_addr;
+    }
+
+    if (!(cmd & PCI_COMMAND_MEMORY)) {
+        return PCI_BAR_UNMAPPED;
+    }
+    if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        new_addr = pci_get_quad(d->config + bar);
+    } else {
+        new_addr = pci_get_long(d->config + bar);
+    }
+    /* the ROM slot has a specific enable bit */
+    if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) {
+        return PCI_BAR_UNMAPPED;
+    }
+    new_addr &= ~(size - 1);
+    last_addr = new_addr + 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 == PCI_BAR_UNMAPPED) {
+        return PCI_BAR_UNMAPPED;
+    }
+
+    /* Now pcibus_t is 64bit.
+     * Check if 32 bit BAR wraps around explicitly.
+     * Without this, PC ide doesn't work well.
+     * TODO: remove this work around.
+     */
+    if  (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) {
+        return PCI_BAR_UNMAPPED;
+    }
+
+    /*
+     * OS is allowed to set BAR beyond its addressable
+     * bits. For example, 32 bit OS can set 64bit bar
+     * to >4G. Check it. TODO: we might need to support
+     * it in the future for e.g. PAE.
+     */
+    if (last_addr >= TARGET_PHYS_ADDR_MAX) {
+        return PCI_BAR_UNMAPPED;
+    }
+
+    return new_addr;
+}
+
+static void pci_update_mappings(PCIDevice *d)
+{
+    PCIIORegion *r;
+    int i;
+    pcibus_t new_addr, filtered_size;
+
+    for(i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+
+        /* this region isn't registered */
+        if (!r->size)
+            continue;
+
+        new_addr = pci_bar_address(d, i, r->type, r->size);
+
+        /* bridge filtering */
+        filtered_size = r->size;
+        if (new_addr != PCI_BAR_UNMAPPED) {
+            pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
+        }
+
+        /* This bar isn't changed */
+        if (new_addr == r->addr && filtered_size == r->filtered_size)
+            continue;
+
+        /* now do the real mapping */
+        if (r->addr != PCI_BAR_UNMAPPED) {
+            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                int class;
+                /* NOTE: specific hack for IDE in PC case:
+                   only one byte must be mapped. */
+                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+                if (class == 0x0101 && r->size == 4) {
+                    isa_unassign_ioport(r->addr + 2, 1);
+                } else {
+                    isa_unassign_ioport(r->addr, r->filtered_size);
+                }
+            } else {
+                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
+                                             r->filtered_size,
+                                             IO_MEM_UNASSIGNED);
+                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
+            }
+        }
+        r->addr = new_addr;
+        r->filtered_size = filtered_size;
+        if (r->addr != PCI_BAR_UNMAPPED) {
+            /*
+             * TODO: currently almost all the map funcions assumes
+             * filtered_size == size and addr & ~(size - 1) == addr.
+             * However with bridge filtering, they aren't always true.
+             * Teach them such cases, such that filtered_size < size and
+             * addr & (size - 1) != 0.
+             */
+            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                r->map_func(d, i, r->addr, r->filtered_size, r->type);
+            } else {
+                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
+                            r->filtered_size, r->type);
+            }
+        }
+    }
+}
+
+static inline int pci_irq_disabled(PCIDevice *d)
+{
+    return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
+}
+
+/* Called after interrupt disabled field update in config space,
+ * assert/deassert interrupts if necessary.
+ * Gets original interrupt disable bit value (before update). */
+static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
+{
+    int i, disabled = pci_irq_disabled(d);
+    if (disabled == was_irq_disabled)
+        return;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        int state = pci_irq_state(d, i);
+        pci_change_irq_level(d, i, disabled ? -state : state);
+    }
+}
+
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len)
+{
+    uint32_t val = 0;
+    assert(len == 1 || len == 2 || len == 4);
+    len = MIN(len, pci_config_size(d) - address);
+    memcpy(&val, d->config + address, len);
+    return le32_to_cpu(val);
+}
+
+void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
+{
+    int i, was_irq_disabled = pci_irq_disabled(d);
+    uint32_t config_size = pci_config_size(d);
+
+    for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
+        uint8_t wmask = d->wmask[addr + i];
+        uint8_t w1cmask = d->w1cmask[addr + i];
+        assert(!(wmask & w1cmask));
+        d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
+        d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
+    }
+    if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
+        ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
+        ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
+        range_covers_byte(addr, l, PCI_COMMAND))
+        pci_update_mappings(d);
+
+    if (range_covers_byte(addr, l, PCI_COMMAND))
+        pci_update_irq_disabled(d, was_irq_disabled);
+}
+
+/***********************************************************/
+/* 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 = opaque;
+    int change;
+
+    change = level - pci_irq_state(pci_dev, irq_num);
+    if (!change)
+        return;
+
+    pci_set_irq_state(pci_dev, irq_num, level);
+    pci_update_irq_status(pci_dev);
+    if (pci_irq_disabled(pci_dev))
+        return;
+    pci_change_irq_level(pci_dev, irq_num, change);
+}
+
+/***********************************************************/
+/* monitor info on PCI */
+
+typedef struct {
+    uint16_t class;
+    const char *desc;
+    const char *fw_name;
+    uint16_t fw_ign_bits;
+} pci_class_desc;
+
+static const pci_class_desc pci_class_descriptions[] =
+{
+    { 0x0001, "VGA controller", "display"},
+    { 0x0100, "SCSI controller", "scsi"},
+    { 0x0101, "IDE controller", "ide"},
+    { 0x0102, "Floppy controller", "fdc"},
+    { 0x0103, "IPI controller", "ipi"},
+    { 0x0104, "RAID controller", "raid"},
+    { 0x0106, "SATA controller"},
+    { 0x0107, "SAS controller"},
+    { 0x0180, "Storage controller"},
+    { 0x0200, "Ethernet controller", "ethernet"},
+    { 0x0201, "Token Ring controller", "token-ring"},
+    { 0x0202, "FDDI controller", "fddi"},
+    { 0x0203, "ATM controller", "atm"},
+    { 0x0280, "Network controller"},
+    { 0x0300, "VGA controller", "display", 0x00ff},
+    { 0x0301, "XGA controller"},
+    { 0x0302, "3D controller"},
+    { 0x0380, "Display controller"},
+    { 0x0400, "Video controller", "video"},
+    { 0x0401, "Audio controller", "sound"},
+    { 0x0402, "Phone"},
+    { 0x0403, "Audio controller", "sound"},
+    { 0x0480, "Multimedia controller"},
+    { 0x0500, "RAM controller", "memory"},
+    { 0x0501, "Flash controller", "flash"},
+    { 0x0580, "Memory controller"},
+    { 0x0600, "Host bridge", "host"},
+    { 0x0601, "ISA bridge", "isa"},
+    { 0x0602, "EISA bridge", "eisa"},
+    { 0x0603, "MC bridge", "mca"},
+    { 0x0604, "PCI bridge", "pci"},
+    { 0x0605, "PCMCIA bridge", "pcmcia"},
+    { 0x0606, "NUBUS bridge", "nubus"},
+    { 0x0607, "CARDBUS bridge", "cardbus"},
+    { 0x0608, "RACEWAY bridge"},
+    { 0x0680, "Bridge"},
+    { 0x0700, "Serial port", "serial"},
+    { 0x0701, "Parallel port", "parallel"},
+    { 0x0800, "Interrupt controller", "interrupt-controller"},
+    { 0x0801, "DMA controller", "dma-controller"},
+    { 0x0802, "Timer", "timer"},
+    { 0x0803, "RTC", "rtc"},
+    { 0x0900, "Keyboard", "keyboard"},
+    { 0x0901, "Pen", "pen"},
+    { 0x0902, "Mouse", "mouse"},
+    { 0x0A00, "Dock station", "dock", 0x00ff},
+    { 0x0B00, "i386 cpu", "cpu", 0x00ff},
+    { 0x0c00, "Fireware contorller", "fireware"},
+    { 0x0c01, "Access bus controller", "access-bus"},
+    { 0x0c02, "SSA controller", "ssa"},
+    { 0x0c03, "USB controller", "usb"},
+    { 0x0c04, "Fibre channel controller", "fibre-channel"},
+    { 0, NULL}
+};
+
+static void pci_for_each_device_under_bus(PCIBus *bus,
+                                          void (*fn)(PCIBus *b, PCIDevice *d))
+{
+    PCIDevice *d;
+    int devfn;
+
+    for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+        d = bus->devices[devfn];
+        if (d) {
+            fn(bus, d);
+        }
+    }
+}
+
+void pci_for_each_device(PCIBus *bus, int bus_num,
+                         void (*fn)(PCIBus *b, PCIDevice *d))
+{
+    bus = pci_find_bus(bus, bus_num);
+
+    if (bus) {
+        pci_for_each_device_under_bus(bus, fn);
+    }
+}
+
+static void pci_device_print(Monitor *mon, QDict *device)
+{
+    QDict *qdict;
+    QListEntry *entry;
+    uint64_t addr, size;
+
+    monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
+    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+                        qdict_get_int(device, "slot"),
+                        qdict_get_int(device, "function"));
+    monitor_printf(mon, "    ");
+
+    qdict = qdict_get_qdict(device, "class_info");
+    if (qdict_haskey(qdict, "desc")) {
+        monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
+    } else {
+        monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
+    }
+
+    qdict = qdict_get_qdict(device, "id");
+    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+                        qdict_get_int(qdict, "device"),
+                        qdict_get_int(qdict, "vendor"));
+
+    if (qdict_haskey(device, "irq")) {
+        monitor_printf(mon, "      IRQ %" PRId64 ".\n",
+                            qdict_get_int(device, "irq"));
+    }
+
+    if (qdict_haskey(device, "pci_bridge")) {
+        QDict *info;
+
+        qdict = qdict_get_qdict(device, "pci_bridge");
+
+        info = qdict_get_qdict(qdict, "bus");
+        monitor_printf(mon, "      BUS %" PRId64 ".\n",
+                            qdict_get_int(info, "number"));
+        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
+                            qdict_get_int(info, "secondary"));
+        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
+                            qdict_get_int(info, "subordinate"));
+
+        info = qdict_get_qdict(qdict, "io_range");
+        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
+                       qdict_get_int(info, "base"),
+                       qdict_get_int(info, "limit"));
+
+        info = qdict_get_qdict(qdict, "memory_range");
+        monitor_printf(mon,
+                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       qdict_get_int(info, "base"),
+                       qdict_get_int(info, "limit"));
+
+        info = qdict_get_qdict(qdict, "prefetchable_range");
+        monitor_printf(mon, "      prefetchable memory range "
+                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       qdict_get_int(info, "base"),
+        qdict_get_int(info, "limit"));
+    }
+
+    QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
+        qdict = qobject_to_qdict(qlist_entry_obj(entry));
+        monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+
+        addr = qdict_get_int(qdict, "address");
+        size = qdict_get_int(qdict, "size");
+
+        if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
+            monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
+                                " [0x%04"FMT_PCIBUS"].\n",
+                                addr, addr + size - 1);
+        } else {
+            monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
+                               " [0x%08"FMT_PCIBUS"].\n",
+                                qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
+                                qdict_get_bool(qdict, "prefetch") ?
+                                " prefetchable" : "", addr, addr + size - 1);
+        }
+    }
+
+    monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+
+    if (qdict_haskey(device, "pci_bridge")) {
+        qdict = qdict_get_qdict(device, "pci_bridge");
+        if (qdict_haskey(qdict, "devices")) {
+            QListEntry *dev;
+            QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
+                pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
+            }
+        }
+    }
+}
+
+void do_pci_info_print(Monitor *mon, const QObject *data)
+{
+    QListEntry *bus, *dev;
+
+    QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
+        QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
+        QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
+            pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
+        }
+    }
+}
+
+static QObject *pci_get_dev_class(const PCIDevice *dev)
+{
+    int class;
+    const pci_class_desc *desc;
+
+    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class)
+        desc++;
+
+    if (desc->desc) {
+        return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
+                                  desc->desc, class);
+    } else {
+        return qobject_from_jsonf("{ 'class': %d }", class);
+    }
+}
+
+static QObject *pci_get_dev_id(const PCIDevice *dev)
+{
+    return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
+                              pci_get_word(dev->config + PCI_VENDOR_ID),
+                              pci_get_word(dev->config + PCI_DEVICE_ID));
+}
+
+static QObject *pci_get_regions_list(const PCIDevice *dev)
+{
+    int i;
+    QList *regions_list;
+
+    regions_list = qlist_new();
+
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        QObject *obj;
+        const PCIIORegion *r = &dev->io_regions[i];
+
+        if (!r->size) {
+            continue;
+        }
+
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
+                                     "'address': %" PRId64 ", "
+                                     "'size': %" PRId64 " }",
+                                     i, r->addr, r->size);
+        } else {
+            int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
+                                     "'mem_type_64': %i, 'prefetch': %i, "
+                                     "'address': %" PRId64 ", "
+                                     "'size': %" PRId64 " }",
+                                     i, mem_type_64,
+                                     r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
+                                     r->addr, r->size);
+        }
+
+        qlist_append_obj(regions_list, obj);
+    }
+
+    return QOBJECT(regions_list);
+}
+
+static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
+
+static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
+{
+    uint8_t type;
+    QObject *obj;
+
+    obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"
+                              " 'qdev_id': %s }",
+                              bus_num,
+                              PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+                              pci_get_dev_class(dev), pci_get_dev_id(dev),
+                              pci_get_regions_list(dev),
+                              dev->qdev.id ? dev->qdev.id : "");
+
+    if (dev->config[PCI_INTERRUPT_PIN] != 0) {
+        QDict *qdict = qobject_to_qdict(obj);
+        qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+    }
+
+    type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    if (type == PCI_HEADER_TYPE_BRIDGE) {
+        QDict *qdict;
+        QObject *pci_bridge;
+
+        pci_bridge = qobject_from_jsonf("{ 'bus': "
+        "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
+        "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+        "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+        "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
+        dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
+        dev->config[PCI_SUBORDINATE_BUS],
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                               PCI_BASE_ADDRESS_MEM_PREFETCH),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                                PCI_BASE_ADDRESS_MEM_PREFETCH));
+
+        if (dev->config[PCI_SECONDARY_BUS] != 0) {
+            PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+
+            if (child_bus) {
+                qdict = qobject_to_qdict(pci_bridge);
+                qdict_put_obj(qdict, "devices",
+                              pci_get_devices_list(child_bus,
+                                                   dev->config[PCI_SECONDARY_BUS]));
+            }
+        }
+        qdict = qobject_to_qdict(obj);
+        qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+    }
+
+    return obj;
+}
+
+static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
+{
+    int devfn;
+    PCIDevice *dev;
+    QList *dev_list;
+
+    dev_list = qlist_new();
+
+    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+        dev = bus->devices[devfn];
+        if (dev) {
+            qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
+        }
+    }
+
+    return QOBJECT(dev_list);
+}
+
+static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
+{
+    bus = pci_find_bus(bus, bus_num);
+    if (bus) {
+        return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
+                                  bus_num, pci_get_devices_list(bus, bus_num));
+    }
+
+    return NULL;
+}
+
+void do_pci_info(Monitor *mon, QObject **ret_data)
+{
+    QList *bus_list;
+    struct PCIHostBus *host;
+
+    bus_list = qlist_new();
+
+    QLIST_FOREACH(host, &host_buses, next) {
+        QObject *obj = pci_get_bus_dict(host->bus, 0);
+        if (obj) {
+            qlist_append_obj(bus_list, obj);
+        }
+    }
+
+    *ret_data = QOBJECT(bus_list);
+}
+
+static const char * const pci_nic_models[] = {
+    "ne2k_pci",
+    "i82551",
+    "i82557b",
+    "i82559er",
+    "rtl8139",
+    "e1000",
+    "pcnet",
+    "virtio",
+    NULL
+};
+
+static const char * const pci_nic_names[] = {
+    "ne2k_pci",
+    "i82551",
+    "i82557b",
+    "i82559er",
+    "rtl8139",
+    "e1000",
+    "pcnet",
+    "virtio-net-pci",
+    NULL
+};
+
+/* Initialize a PCI NIC.  */
+/* FIXME callers should check for failure, but don't */
+PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
+                        const char *default_devaddr)
+{
+    const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
+    PCIBus *bus;
+    int devfn;
+    PCIDevice *pci_dev;
+    DeviceState *dev;
+    int i;
+
+    i = qemu_find_nic_model(nd, pci_nic_models, default_model);
+    if (i < 0)
+        return NULL;
+
+    bus = pci_get_bus_devfn(&devfn, devaddr);
+    if (!bus) {
+        error_report("Invalid PCI device address %s for device %s",
+                     devaddr, pci_nic_names[i]);
+        return NULL;
+    }
+
+    pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
+    dev = &pci_dev->qdev;
+    qdev_set_nic_properties(dev, nd);
+    if (qdev_init(dev) < 0)
+        return NULL;
+    return pci_dev;
+}
+
+PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
+                               const char *default_devaddr)
+{
+    PCIDevice *res;
+
+    if (qemu_show_nic_models(nd->model, pci_nic_models))
+        exit(0);
+
+    res = pci_nic_init(nd, default_model, default_devaddr);
+    if (!res)
+        exit(1);
+    return res;
+}
+
+static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
+{
+    pci_update_mappings(d);
+}
+
+void pci_bridge_update_mappings(PCIBus *b)
+{
+    PCIBus *child;
+
+    pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn);
+
+    QLIST_FOREACH(child, &b->child, sibling) {
+        pci_bridge_update_mappings(child);
+    }
+}
+
+/* Whether a given bus number is in range of the secondary
+ * bus of the given bridge device. */
+static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
+{
+    return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
+             PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ &&
+        dev->config[PCI_SECONDARY_BUS] < bus_num &&
+        bus_num <= dev->config[PCI_SUBORDINATE_BUS];
+}
+
+PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
+{
+    PCIBus *sec;
+
+    if (!bus) {
+        return NULL;
+    }
+
+    if (pci_bus_num(bus) == bus_num) {
+        return bus;
+    }
+
+    /* Consider all bus numbers in range for the host pci bridge. */
+    if (bus->parent_dev &&
+        !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
+        return NULL;
+    }
+
+    /* try child bus */
+    for (; bus; bus = sec) {
+        QLIST_FOREACH(sec, &bus->child, sibling) {
+            assert(sec->parent_dev);
+            if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
+                return sec;
+            }
+            if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
+                break;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
+{
+    bus = pci_find_bus(bus, bus_num);
+
+    if (!bus)
+        return NULL;
+
+    return bus->devices[devfn];
+}
+
+static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    PCIDevice *pci_dev = (PCIDevice *)qdev;
+    PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+    PCIBus *bus;
+    int rc;
+    bool is_default_rom;
+
+    /* initialize cap_present for pci_is_express() and pci_config_size() */
+    if (info->is_express) {
+        pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+    }
+
+    bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
+    pci_dev = do_pci_register_device(pci_dev, bus, base->name,
+                                     pci_dev->devfn, info);
+    if (pci_dev == NULL)
+        return -1;
+    if (qdev->hotplugged && info->no_hotplug) {
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+        do_pci_unregister_device(pci_dev);
+        return -1;
+    }
+    if (info->init) {
+        rc = info->init(pci_dev);
+        if (rc != 0) {
+            do_pci_unregister_device(pci_dev);
+            return rc;
+        }
+    }
+
+    /* rom loading */
+    is_default_rom = false;
+    if (pci_dev->romfile == NULL && info->romfile != NULL) {
+        pci_dev->romfile = qemu_strdup(info->romfile);
+        is_default_rom = true;
+    }
+    pci_add_option_rom(pci_dev, is_default_rom);
+
+    if (bus->hotplug) {
+        /* Let buses differentiate between hotplug and when device is
+         * enabled during qemu machine creation. */
+        rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
+                          qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
+                          PCI_COLDPLUG_ENABLED);
+        if (rc != 0) {
+            int r = pci_unregister_device(&pci_dev->qdev);
+            assert(!r);
+            return rc;
+        }
+    }
+    return 0;
+}
+
+static int pci_unplug_device(DeviceState *qdev)
+{
+    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+    PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+
+    if (info->no_hotplug) {
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+        return -1;
+    }
+    return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
+                             PCI_HOTPLUG_DISABLED);
+}
+
+void pci_qdev_register(PCIDeviceInfo *info)
+{
+    info->qdev.init = pci_qdev_init;
+    info->qdev.unplug = pci_unplug_device;
+    info->qdev.exit = pci_unregister_device;
+    info->qdev.bus_info = &pci_bus_info;
+    qdev_register(&info->qdev);
+}
+
+void pci_qdev_register_many(PCIDeviceInfo *info)
+{
+    while (info->qdev.name) {
+        pci_qdev_register(info);
+        info++;
+    }
+}
+
+PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
+                                    const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->qbus, name);
+    qdev_prop_set_uint32(dev, "addr", devfn);
+    qdev_prop_set_bit(dev, "multifunction", multifunction);
+    return DO_UPCAST(PCIDevice, qdev, dev);
+}
+
+PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
+                                        bool multifunction,
+                                        const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_try_create(&bus->qbus, name);
+    if (!dev) {
+        return NULL;
+    }
+    qdev_prop_set_uint32(dev, "addr", devfn);
+    qdev_prop_set_bit(dev, "multifunction", multifunction);
+    return DO_UPCAST(PCIDevice, qdev, dev);
+}
+
+PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
+                                           bool multifunction,
+                                           const char *name)
+{
+    PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+}
+
+PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_create_multifunction(bus, devfn, false, name);
+}
+
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_create_simple_multifunction(bus, devfn, false, name);
+}
+
+PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_try_create_multifunction(bus, devfn, false, name);
+}
+
+static int pci_find_space(PCIDevice *pdev, uint8_t size)
+{
+    int config_size = pci_config_size(pdev);
+    int offset = PCI_CONFIG_HEADER_SIZE;
+    int i;
+    for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
+        if (pdev->used[i])
+            offset = i + 1;
+        else if (i - offset + 1 == size)
+            return offset;
+    return 0;
+}
+
+static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
+                                        uint8_t *prev_p)
+{
+    uint8_t next, prev;
+
+    if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
+        return 0;
+
+    for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
+         prev = next + PCI_CAP_LIST_NEXT)
+        if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
+            break;
+
+    if (prev_p)
+        *prev_p = prev;
+    return next;
+}
+
+static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
+{
+    cpu_register_physical_memory(addr, size, pdev->rom_offset);
+}
+
+/* Patch the PCI vendor and device ids in a PCI rom image if necessary.
+   This is needed for an option rom which is used for more than one device. */
+static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
+{
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t rom_vendor_id;
+    uint16_t rom_device_id;
+    uint16_t rom_magic;
+    uint16_t pcir_offset;
+    uint8_t checksum;
+
+    /* Words in rom data are little endian (like in PCI configuration),
+       so they can be read / written with pci_get_word / pci_set_word. */
+
+    /* Only a valid rom will be patched. */
+    rom_magic = pci_get_word(ptr);
+    if (rom_magic != 0xaa55) {
+        PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
+        return;
+    }
+    pcir_offset = pci_get_word(ptr + 0x18);
+    if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
+        PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
+        return;
+    }
+
+    vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
+    device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
+    rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
+    rom_device_id = pci_get_word(ptr + pcir_offset + 6);
+
+    PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
+                vendor_id, device_id, rom_vendor_id, rom_device_id);
+
+    checksum = ptr[6];
+
+    if (vendor_id != rom_vendor_id) {
+        /* Patch vendor id and checksum (at offset 6 for etherboot roms). */
+        checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
+        checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
+        PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
+        ptr[6] = checksum;
+        pci_set_word(ptr + pcir_offset + 4, vendor_id);
+    }
+
+    if (device_id != rom_device_id) {
+        /* Patch device id and checksum (at offset 6 for etherboot roms). */
+        checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
+        checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
+        PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
+        ptr[6] = checksum;
+        pci_set_word(ptr + pcir_offset + 6, device_id);
+    }
+}
+
+/* Add an option rom for the device */
+static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
+{
+    int size;
+    char *path;
+    void *ptr;
+    char name[32];
+
+    if (!pdev->romfile)
+        return 0;
+    if (strlen(pdev->romfile) == 0)
+        return 0;
+
+    if (!pdev->rom_bar) {
+        /*
+         * Load rom via fw_cfg instead of creating a rom bar,
+         * for 0.11 compatibility.
+         */
+        int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
+        if (class == 0x0300) {
+            rom_add_vga(pdev->romfile);
+        } else {
+            rom_add_option(pdev->romfile, -1);
+        }
+        return 0;
+    }
+
+    path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
+    if (path == NULL) {
+        path = qemu_strdup(pdev->romfile);
+    }
+
+    size = get_image_size(path);
+    if (size < 0) {
+        error_report("%s: failed to find romfile \"%s\"",
+                     __FUNCTION__, pdev->romfile);
+        qemu_free(path);
+        return -1;
+    }
+    if (size & (size - 1)) {
+        size = 1 << qemu_fls(size);
+    }
+
+    if (pdev->qdev.info->vmsd)
+        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
+    else
+        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+    pdev->rom_offset = qemu_ram_alloc(&pdev->qdev, name, size);
+
+    ptr = qemu_get_ram_ptr(pdev->rom_offset);
+    load_image(path, ptr);
+    qemu_free(path);
+
+    if (is_default_rom) {
+        /* Only the default rom images will be patched (if needed). */
+        pci_patch_ids(pdev, ptr, size);
+    }
+
+    qemu_put_ram_ptr(ptr);
+
+    pci_register_bar(pdev, PCI_ROM_SLOT, size,
+                     0, pci_map_option_rom);
+
+    return 0;
+}
+
+static void pci_del_option_rom(PCIDevice *pdev)
+{
+    if (!pdev->rom_offset)
+        return;
+
+    qemu_ram_free(pdev->rom_offset);
+    pdev->rom_offset = 0;
+}
+
+/*
+ * if !offset
+ * Reserve space and add capability to the linked list in pci config space
+ *
+ * if offset = 0,
+ * Find and reserve space and add capability to the linked list
+ * in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size)
+{
+    uint8_t *config;
+    if (!offset) {
+        offset = pci_find_space(pdev, size);
+        if (!offset) {
+            return -ENOSPC;
+        }
+    }
+
+    config = pdev->config + offset;
+    config[PCI_CAP_LIST_ID] = cap_id;
+    config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
+    pdev->config[PCI_CAPABILITY_LIST] = offset;
+    pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
+    memset(pdev->used + offset, 0xFF, size);
+    /* Make capability read-only by default */
+    memset(pdev->wmask + offset, 0, size);
+    /* Check capability by default */
+    memset(pdev->cmask + offset, 0xFF, size);
+    return offset;
+}
+
+/* Unlink capability from the pci config space. */
+void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+{
+    uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
+    if (!offset)
+        return;
+    pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
+    /* Make capability writable again */
+    memset(pdev->wmask + offset, 0xff, size);
+    memset(pdev->w1cmask + offset, 0, size);
+    /* Clear cmask as device-specific registers can't be checked */
+    memset(pdev->cmask + offset, 0, size);
+    memset(pdev->used + offset, 0, size);
+
+    if (!pdev->config[PCI_CAPABILITY_LIST])
+        pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
+}
+
+/* Reserve space for capability at a known offset (to call after load). */
+void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
+{
+    memset(pdev->used + offset, 0xff, size);
+}
+
+uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
+{
+    return pci_find_capability_list(pdev, cap_id, NULL);
+}
+
+static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    const pci_class_desc *desc;
+    char ctxt[64];
+    PCIIORegion *r;
+    int i, class;
+
+    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class)
+        desc++;
+    if (desc->desc) {
+        snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
+    } else {
+        snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
+    }
+
+    monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
+                   "pci id %04x:%04x (sub %04x:%04x)\n",
+                   indent, "", ctxt, pci_bus_num(d->bus),
+                   PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
+                   pci_get_word(d->config + PCI_VENDOR_ID),
+                   pci_get_word(d->config + PCI_DEVICE_ID),
+                   pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
+                   pci_get_word(d->config + PCI_SUBSYSTEM_ID));
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        if (!r->size)
+            continue;
+        monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
+                       " [0x%"FMT_PCIBUS"]\n",
+                       indent, "",
+                       i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem",
+                       r->addr, r->addr + r->size - 1);
+    }
+}
+
+static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    const char *name = NULL;
+    const pci_class_desc *desc =  pci_class_descriptions;
+    int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+
+    while (desc->desc &&
+          (class & ~desc->fw_ign_bits) !=
+          (desc->class & ~desc->fw_ign_bits)) {
+        desc++;
+    }
+
+    if (desc->desc) {
+        name = desc->fw_name;
+    }
+
+    if (name) {
+        pstrcpy(buf, len, name);
+    } else {
+        snprintf(buf, len, "pci%04x,%04x",
+                 pci_get_word(d->config + PCI_VENDOR_ID),
+                 pci_get_word(d->config + PCI_DEVICE_ID));
+    }
+
+    return buf;
+}
+
+static char *pcibus_get_fw_dev_path(DeviceState *dev)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    char path[50], name[33];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s@%x",
+                   pci_dev_fw_name(dev, name, sizeof name),
+                   PCI_SLOT(d->devfn));
+    if (PCI_FUNC(d->devfn))
+        snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
+    return strdup(path);
+}
+
+static char *pcibus_get_dev_path(DeviceState *dev)
+{
+    PCIDevice *d = container_of(dev, PCIDevice, qdev);
+    PCIDevice *t;
+    int slot_depth;
+    /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
+     * 00 is added here to make this format compatible with
+     * domain:Bus:Slot.Func for systems without nested PCI bridges.
+     * Slot.Function list specifies the slot and function numbers for all
+     * devices on the path from root to the specific device. */
+    char domain[] = "DDDD:00";
+    char slot[] = ":SS.F";
+    int domain_len = sizeof domain - 1 /* For '\0' */;
+    int slot_len = sizeof slot - 1 /* For '\0' */;
+    int path_len;
+    char *path, *p;
+    int s;
+
+    /* Calculate # of slots on path between device and root. */;
+    slot_depth = 0;
+    for (t = d; t; t = t->bus->parent_dev) {
+        ++slot_depth;
+    }
+
+    path_len = domain_len + slot_len * slot_depth;
+
+    /* Allocate memory, fill in the terminating null byte. */
+    path = qemu_malloc(path_len + 1 /* For '\0' */);
+    path[path_len] = '\0';
+
+    /* First field is the domain. */
+    s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
+    assert(s == domain_len);
+    memcpy(path, domain, domain_len);
+
+    /* Fill in slot numbers. We walk up from device to root, so need to print
+     * them in the reverse order, last to first. */
+    p = path + path_len;
+    for (t = d; t; t = t->bus->parent_dev) {
+        p -= slot_len;
+        s = snprintf(slot, sizeof slot, ":%02x.%x",
+                     PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
+        assert(s == slot_len);
+        memcpy(p, slot, slot_len);
+    }
+
+    return path;
+}
+
+static int pci_qdev_find_recursive(PCIBus *bus,
+                                   const char *id, PCIDevice **pdev)
+{
+    DeviceState *qdev = qdev_find_recursive(&bus->qbus, id);
+    if (!qdev) {
+        return -ENODEV;
+    }
+
+    /* roughly check if given qdev is pci device */
+    if (qdev->info->init == &pci_qdev_init &&
+        qdev->parent_bus->info == &pci_bus_info) {
+        *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+        return 0;
+    }
+    return -EINVAL;
+}
+
+int pci_qdev_find_device(const char *id, PCIDevice **pdev)
+{
+    struct PCIHostBus *host;
+    int rc = -ENODEV;
+
+    QLIST_FOREACH(host, &host_buses, next) {
+        int tmp = pci_qdev_find_recursive(host->bus, id, pdev);
+        if (!tmp) {
+            rc = 0;
+            break;
+        }
+        if (tmp != -ENODEV) {
+            rc = tmp;
+        }
+    }
+
+    return rc;
+}
diff --git a/qemu-0.15.x/hw/pci.h b/qemu-0.15.x/hw/pci.h
new file mode 100644
index 0000000..c220745
--- /dev/null
+++ b/qemu-0.15.x/hw/pci.h
@@ -0,0 +1,485 @@
+#ifndef QEMU_PCI_H
+#define QEMU_PCI_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+
+#include "qdev.h"
+
+/* PCI includes legacy ISA access.  */
+#include "isa.h"
+
+#include "pcie.h"
+
+/* PCI bus */
+
+#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)         ((devfn) & 0x07)
+#define PCI_SLOT_MAX            32
+#define PCI_FUNC_MAX            8
+
+/* Class, Vendor and Device IDs from Linux's pci_ids.h */
+#include "pci_ids.h"
+
+/* QEMU-specific Vendor and Device ID definitions */
+
+/* IBM (0x1014) */
+#define PCI_DEVICE_ID_IBM_440GX          0x027f
+#define PCI_DEVICE_ID_IBM_OPENPIC2       0xffff
+
+/* Hitachi (0x1054) */
+#define PCI_VENDOR_ID_HITACHI            0x1054
+#define PCI_DEVICE_ID_HITACHI_SH7751R    0x350e
+
+/* Apple (0x106b) */
+#define PCI_DEVICE_ID_APPLE_343S1201     0x0010
+#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI  0x001e
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI    0x001f
+#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL   0x0022
+#define PCI_DEVICE_ID_APPLE_IPID_USB     0x003f
+
+/* Realtek (0x10ec) */
+#define PCI_DEVICE_ID_REALTEK_8029       0x8029
+
+/* Xilinx (0x10ee) */
+#define PCI_DEVICE_ID_XILINX_XC2VP30     0x0300
+
+/* Marvell (0x11ab) */
+#define PCI_DEVICE_ID_MARVELL_GT6412X    0x4620
+
+/* QEMU/Bochs VGA (0x1234) */
+#define PCI_VENDOR_ID_QEMU               0x1234
+#define PCI_DEVICE_ID_QEMU_VGA           0x1111
+
+/* VMWare (0x15ad) */
+#define PCI_VENDOR_ID_VMWARE             0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2       0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA        0x0710
+#define PCI_DEVICE_ID_VMWARE_NET         0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI        0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE         0x1729
+
+/* Intel (0x8086) */
+#define PCI_DEVICE_ID_INTEL_82551IT      0x1209
+#define PCI_DEVICE_ID_INTEL_82557        0x1229
+#define PCI_DEVICE_ID_INTEL_82801IR      0x2922
+
+/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
+#define PCI_VENDOR_ID_REDHAT_QUMRANET    0x1af4
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_SUBDEVICE_ID_QEMU            0x1100
+
+#define PCI_DEVICE_ID_VIRTIO_NET         0x1000
+#define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
+#define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+
+#define FMT_PCIBUS                      PRIx64
+
+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,
+                                pcibus_t addr, pcibus_t size, int type);
+typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
+
+typedef struct PCIIORegion {
+    pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
+#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
+    pcibus_t size;
+    pcibus_t filtered_size;
+    uint8_t type;
+    PCIMapIORegionFunc *map_func;
+    ram_addr_t ram_addr;
+} PCIIORegion;
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+#include "pci_regs.h"
+
+/* PCI HEADER_TYPE */
+#define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+
+/* Size of the standard PCI config header */
+#define PCI_CONFIG_HEADER_SIZE 0x40
+/* Size of the standard PCI config space */
+#define PCI_CONFIG_SPACE_SIZE 0x100
+/* Size of the standart PCIe config space: 4KB */
+#define PCIE_CONFIG_SPACE_SIZE  0x1000
+
+#define PCI_NUM_PINS 4 /* A-D */
+
+/* Bits in cap_present field. */
+enum {
+    QEMU_PCI_CAP_MSI = 0x1,
+    QEMU_PCI_CAP_MSIX = 0x2,
+    QEMU_PCI_CAP_EXPRESS = 0x4,
+
+    /* multifunction capable device */
+#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        3
+    QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
+
+    /* command register SERR bit enabled */
+#define QEMU_PCI_CAP_SERR_BITNR 4
+    QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
+};
+
+struct PCIDevice {
+    DeviceState qdev;
+    /* PCI config space */
+    uint8_t *config;
+
+    /* Used to enable config checks on load. Note that writable bits are
+     * never checked even if set in cmask. */
+    uint8_t *cmask;
+
+    /* Used to implement R/W bytes */
+    uint8_t *wmask;
+
+    /* Used to implement RW1C(Write 1 to Clear) bytes */
+    uint8_t *w1cmask;
+
+    /* Used to allocate config space for capabilities. */
+    uint8_t *used;
+
+    /* the following fields are read only */
+    PCIBus *bus;
+    uint32_t devfn;
+    char name[64];
+    PCIIORegion io_regions[PCI_NUM_REGIONS];
+
+    /* do not access the following fields */
+    PCIConfigReadFunc *config_read;
+    PCIConfigWriteFunc *config_write;
+
+    /* IRQ objects for the INTA-INTD pins.  */
+    qemu_irq *irq;
+
+    /* Current IRQ levels.  Used internally by the generic PCI code.  */
+    uint8_t irq_state;
+
+    /* Capability bits */
+    uint32_t cap_present;
+
+    /* Offset of MSI-X capability in config space */
+    uint8_t msix_cap;
+
+    /* MSI-X entries */
+    int msix_entries_nr;
+
+    /* Space to store MSIX table */
+    uint8_t *msix_table_page;
+    /* MMIO index used to map MSIX table and pending bit entries. */
+    int msix_mmio_index;
+    /* Reference-count for entries actually in use by driver. */
+    unsigned *msix_entry_used;
+    /* Region including the MSI-X table */
+    uint32_t msix_bar_size;
+    /* Version id needed for VMState */
+    int32_t version_id;
+
+    /* Offset of MSI capability in config space */
+    uint8_t msi_cap;
+
+    /* PCI Express */
+    PCIExpressDevice exp;
+
+    /* Location of option rom */
+    char *romfile;
+    ram_addr_t rom_offset;
+    uint32_t rom_bar;
+};
+
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write);
+
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+                            pcibus_t size, uint8_t type,
+                            PCIMapIORegionFunc *map_func);
+void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
+                             pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
+
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size);
+
+void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
+
+uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
+
+
+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);
+void pci_device_save(PCIDevice *s, QEMUFile *f);
+int pci_device_load(PCIDevice *s, QEMUFile *f);
+
+typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
+typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
+
+typedef enum {
+    PCI_HOTPLUG_DISABLED,
+    PCI_HOTPLUG_ENABLED,
+    PCI_COLDPLUG_ENABLED,
+} PCIHotplugState;
+
+typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
+                              PCIHotplugState state);
+void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
+                         const char *name, uint8_t devfn_min);
+PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min);
+void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                  void *irq_opaque, int nirq);
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                         void *irq_opaque, uint8_t devfn_min, int nirq);
+void pci_device_reset(PCIDevice *dev);
+void pci_bus_reset(PCIBus *bus);
+
+void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base);
+
+PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
+                        const char *default_devaddr);
+PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
+                               const char *default_devaddr);
+int pci_bus_num(PCIBus *s);
+void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d));
+PCIBus *pci_find_root_bus(int domain);
+int pci_find_domain(const PCIBus *bus);
+PCIBus *pci_find_bus(PCIBus *bus, int bus_num);
+PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
+int pci_qdev_find_device(const char *id, PCIDevice **pdev);
+PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
+
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+                      unsigned int *slotp, unsigned int *funcp);
+int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
+                     unsigned *slotp);
+
+void do_pci_info_print(Monitor *mon, const QObject *data);
+void do_pci_info(Monitor *mon, QObject **ret_data);
+void pci_bridge_update_mappings(PCIBus *b);
+
+void pci_device_deassert_intx(PCIDevice *dev);
+
+static inline void
+pci_set_byte(uint8_t *config, uint8_t val)
+{
+    *config = val;
+}
+
+static inline uint8_t
+pci_get_byte(const uint8_t *config)
+{
+    return *config;
+}
+
+static inline void
+pci_set_word(uint8_t *config, uint16_t val)
+{
+    cpu_to_le16wu((uint16_t *)config, val);
+}
+
+static inline uint16_t
+pci_get_word(const uint8_t *config)
+{
+    return le16_to_cpupu((const uint16_t *)config);
+}
+
+static inline void
+pci_set_long(uint8_t *config, uint32_t val)
+{
+    cpu_to_le32wu((uint32_t *)config, val);
+}
+
+static inline uint32_t
+pci_get_long(const uint8_t *config)
+{
+    return le32_to_cpupu((const uint32_t *)config);
+}
+
+static inline void
+pci_set_quad(uint8_t *config, uint64_t val)
+{
+    cpu_to_le64w((uint64_t *)config, val);
+}
+
+static inline uint64_t
+pci_get_quad(const uint8_t *config)
+{
+    return le64_to_cpup((const uint64_t *)config);
+}
+
+static inline void
+pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_VENDOR_ID], val);
+}
+
+static inline void
+pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_DEVICE_ID], val);
+}
+
+static inline void
+pci_config_set_revision(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_REVISION_ID], val);
+}
+
+static inline void
+pci_config_set_class(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_CLASS_DEVICE], val);
+}
+
+static inline void
+pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_CLASS_PROG], val);
+}
+
+static inline void
+pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
+}
+
+/*
+ * helper functions to do bit mask operation on configuration space.
+ * Just to set bit, use test-and-set and discard returned value.
+ * Just to clear bit, use test-and-clear and discard returned value.
+ * NOTE: They aren't atomic.
+ */
+static inline uint8_t
+pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint8_t
+pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val | mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val | mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val | mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val | mask);
+    return val & mask;
+}
+
+typedef int (*pci_qdev_initfn)(PCIDevice *dev);
+typedef struct {
+    DeviceInfo qdev;
+    pci_qdev_initfn init;
+    PCIUnregisterFunc *exit;
+    PCIConfigReadFunc *config_read;
+    PCIConfigWriteFunc *config_write;
+
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t class_id;
+    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
+    uint16_t subsystem_id;              /* only for header type = 0 */
+
+    /*
+     * pci-to-pci bridge or normal device.
+     * This doesn't mean pci host switch.
+     * When card bus bridge is supported, this would be enhanced.
+     */
+    int is_bridge;
+
+    /* pcie stuff */
+    int is_express;   /* is this device pci express? */
+
+    /* device isn't hot-pluggable */
+    int no_hotplug;
+
+    /* rom bar */
+    const char *romfile;
+} PCIDeviceInfo;
+
+void pci_qdev_register(PCIDeviceInfo *info);
+void pci_qdev_register_many(PCIDeviceInfo *info);
+
+PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
+                                    const char *name);
+PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
+                                           bool multifunction,
+                                           const char *name);
+PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
+                                        bool multifunction,
+                                        const char *name);
+PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
+PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name);
+
+static inline int pci_is_express(const PCIDevice *d)
+{
+    return d->cap_present & QEMU_PCI_CAP_EXPRESS;
+}
+
+static inline uint32_t pci_config_size(const PCIDevice *d)
+{
+    return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
+}
+
+#endif
diff --git a/qemu-0.15.x/hw/pci_bridge.c b/qemu-0.15.x/hw/pci_bridge.c
new file mode 100644
index 0000000..464d897
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_bridge.c
@@ -0,0 +1,275 @@
+/*
+ * 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 dea
+
+ * 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.
+ */
+/*
+ * split out from pci.c
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ */
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "range.h"
+
+/* PCI bridge subsystem vendor ID helper functions */
+#define PCI_SSVID_SIZEOF        8
+#define PCI_SSVID_SVID          4
+#define PCI_SSVID_SSID          6
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                          uint16_t svid, uint16_t ssid)
+{
+    int pos;
+    pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
+    if (pos < 0) {
+        return pos;
+    }
+
+    pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
+    pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
+    return pos;
+}
+
+/* Accessor function to get parent bridge device from pci bus. */
+PCIDevice *pci_bridge_get_device(PCIBus *bus)
+{
+    return bus->parent_dev;
+}
+
+/* Accessor function to get secondary bus from pci-to-pci bridge device */
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
+{
+    return &br->sec_bus;
+}
+
+static uint32_t pci_config_get_io_base(const PCIDevice *d,
+                                       uint32_t base, uint32_t base_upper16)
+{
+    uint32_t val;
+
+    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
+    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
+        val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
+    }
+    return val;
+}
+
+static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
+{
+    return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
+        << 16;
+}
+
+static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
+                                         uint32_t base, uint32_t upper)
+{
+    pcibus_t tmp;
+    pcibus_t val;
+
+    tmp = (pcibus_t)pci_get_word(d->config + base);
+    val = (tmp & PCI_PREF_RANGE_MASK) << 16;
+    if (tmp & PCI_PREF_RANGE_TYPE_64) {
+        val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
+    }
+    return val;
+}
+
+/* accessor function to get bridge filtering base address */
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
+{
+    pcibus_t base;
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        base = pci_config_get_io_base(bridge,
+                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
+    } else {
+        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+            base = pci_config_get_pref_base(
+                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
+        } else {
+            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
+        }
+    }
+
+    return base;
+}
+
+/* accessor funciton to get bridge filtering limit */
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
+{
+    pcibus_t limit;
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        limit = pci_config_get_io_base(bridge,
+                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
+        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
+    } else {
+        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+            limit = pci_config_get_pref_base(
+                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
+        } else {
+            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
+        }
+        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
+    }
+    return limit;
+}
+
+/* default write_config function for PCI-to-PCI bridge */
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len)
+{
+    PCIBridge *s = container_of(d, PCIBridge, dev);
+    uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
+    uint16_t newctl;
+
+    pci_default_write_config(d, address, val, len);
+
+    if (/* io base/limit */
+        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
+
+        /* memory base/limit, prefetchable base/limit and
+           io base/limit upper 16 */
+        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
+        pci_bridge_update_mappings(&s->sec_bus);
+    }
+
+    newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
+    if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
+        /* Trigger hot reset on 0->1 transition. */
+        pci_bus_reset(&s->sec_bus);
+    }
+}
+
+void pci_bridge_disable_base_limit(PCIDevice *dev)
+{
+    uint8_t *conf = dev->config;
+
+    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
+                               PCI_IO_RANGE_MASK & 0xff);
+    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
+                               PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+    pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+}
+
+/* reset bridge specific configuration registers */
+void pci_bridge_reset_reg(PCIDevice *dev)
+{
+    uint8_t *conf = dev->config;
+
+    conf[PCI_PRIMARY_BUS] = 0;
+    conf[PCI_SECONDARY_BUS] = 0;
+    conf[PCI_SUBORDINATE_BUS] = 0;
+    conf[PCI_SEC_LATENCY_TIMER] = 0;
+
+    /*
+     * the default values for base/limit registers aren't specified
+     * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
+     * Each implementation can override it.
+     * typical implementation does
+     * zero base/limit registers or
+     * disable forwarding: pci_bridge_disable_base_limit()
+     * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
+     * after this function.
+     */
+    pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+    pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+
+    pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
+}
+
+/* default reset function for PCI-to-PCI bridge */
+void pci_bridge_reset(DeviceState *qdev)
+{
+    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+    pci_bridge_reset_reg(dev);
+}
+
+/* default qdev initialization function for PCI-to-PCI bridge */
+int pci_bridge_initfn(PCIDevice *dev)
+{
+    PCIBus *parent = dev->bus;
+    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+    PCIBus *sec_bus = &br->sec_bus;
+
+    pci_set_word(dev->config + PCI_STATUS,
+                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
+    dev->config[PCI_HEADER_TYPE] =
+        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
+        PCI_HEADER_TYPE_BRIDGE;
+    pci_set_word(dev->config + PCI_SEC_STATUS,
+                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+
+    qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
+                        br->bus_name);
+    sec_bus->parent_dev = dev;
+    sec_bus->map_irq = br->map_irq;
+
+    QLIST_INIT(&sec_bus->child);
+    QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
+    return 0;
+}
+
+/* default qdev clean up function for PCI-to-PCI bridge */
+int pci_bridge_exitfn(PCIDevice *pci_dev)
+{
+    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
+    assert(QLIST_EMPTY(&s->sec_bus.child));
+    QLIST_REMOVE(&s->sec_bus, sibling);
+    /* qbus_free() is called automatically by qdev_free() */
+    return 0;
+}
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+                        pci_map_irq_fn map_irq)
+{
+    br->map_irq = map_irq;
+    br->bus_name = bus_name;
+}
diff --git a/qemu-0.15.x/hw/pci_bridge.h b/qemu-0.15.x/hw/pci_bridge.h
new file mode 100644
index 0000000..84411a6
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_bridge.h
@@ -0,0 +1,66 @@
+/*
+ * QEMU PCI bridge
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ */
+
+#ifndef QEMU_PCI_BRIDGE_H
+#define QEMU_PCI_BRIDGE_H
+
+#include "pci.h"
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                          uint16_t svid, uint16_t ssid);
+
+PCIDevice *pci_bridge_get_device(PCIBus *bus);
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
+
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
+
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len);
+void pci_bridge_disable_base_limit(PCIDevice *dev);
+void pci_bridge_reset_reg(PCIDevice *dev);
+void pci_bridge_reset(DeviceState *qdev);
+
+int pci_bridge_initfn(PCIDevice *pci_dev);
+int pci_bridge_exitfn(PCIDevice *pci_dev);
+
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+                        pci_map_irq_fn map_irq);
+
+#endif  /* QEMU_PCI_BRIDGE_H */
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/qemu-0.15.x/hw/pci_host.c b/qemu-0.15.x/hw/pci_host.c
new file mode 100644
index 0000000..728e2d4
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_host.c
@@ -0,0 +1,159 @@
+/*
+ * pci_host.c
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci.h"
+#include "pci_host.h"
+
+/* debug PCI */
+//#define DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCI_DPRINTF(fmt, ...) \
+do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define PCI_DPRINTF(fmt, ...)
+#endif
+
+/*
+ * PCI address
+ * bit 16 - 24: bus number
+ * bit  8 - 15: devfun number
+ * bit  0 -  7: offset in configuration space of a given pci device
+ */
+
+/* the helper functio to get a PCIDeice* for a given pci address */
+static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
+{
+    uint8_t bus_num = addr >> 16;
+    uint8_t devfn = addr >> 8;
+
+    return pci_find_device(bus, bus_num, devfn);
+}
+
+void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
+{
+    PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
+    uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
+
+    if (!pci_dev)
+        return;
+
+    PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
+                __func__, pci_dev->name, config_addr, val, len);
+    pci_dev->config_write(pci_dev, config_addr, val, len);
+}
+
+uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
+{
+    PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
+    uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
+    uint32_t val;
+
+    assert(len == 1 || len == 2 || len == 4);
+    if (!pci_dev) {
+        return ~0x0;
+    }
+
+    val = pci_dev->config_read(pci_dev, config_addr, len);
+    PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
+                __func__, pci_dev->name, config_addr, val, len);
+
+    return val;
+}
+
+static void pci_host_config_write(ReadWriteHandler *handler,
+                                  pcibus_t addr, uint32_t val, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+                __func__, addr, len, val);
+    s->config_reg = val;
+}
+
+static uint32_t pci_host_config_read(ReadWriteHandler *handler,
+                                     pcibus_t addr, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+    uint32_t val = s->config_reg;
+
+    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+                __func__, addr, len, val);
+    return val;
+}
+
+static void pci_host_data_write(ReadWriteHandler *handler,
+                                pcibus_t addr, uint32_t val, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
+                addr, len, val);
+    if (s->config_reg & (1u << 31))
+        pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static uint32_t pci_host_data_read(ReadWriteHandler *handler,
+                                   pcibus_t addr, int len)
+{
+    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+    uint32_t val;
+    if (!(s->config_reg & (1 << 31)))
+        return 0xffffffff;
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
+                addr, len, val);
+    return val;
+}
+
+static void pci_host_init(PCIHostState *s)
+{
+    s->conf_handler.write = pci_host_config_write;
+    s->conf_handler.read = pci_host_config_read;
+    s->data_handler.write = pci_host_data_write;
+    s->data_handler.read = pci_host_data_read;
+}
+
+int pci_host_conf_register_mmio(PCIHostState *s, int endian)
+{
+    pci_host_init(s);
+    return cpu_register_io_memory_simple(&s->conf_handler, endian);
+}
+
+void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
+{
+    pci_host_init(s);
+    register_ioport_simple(&s->conf_handler, ioport, 4, 4);
+    sysbus_init_ioports(&s->busdev, ioport, 4);
+}
+
+int pci_host_data_register_mmio(PCIHostState *s, int endian)
+{
+    pci_host_init(s);
+    return cpu_register_io_memory_simple(&s->data_handler, endian);
+}
+
+void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
+{
+    pci_host_init(s);
+    register_ioport_simple(&s->data_handler, ioport, 4, 1);
+    register_ioport_simple(&s->data_handler, ioport, 4, 2);
+    register_ioport_simple(&s->data_handler, ioport, 4, 4);
+    sysbus_init_ioports(&s->busdev, ioport, 4);
+}
diff --git a/qemu-0.15.x/hw/pci_host.h b/qemu-0.15.x/hw/pci_host.h
new file mode 100644
index 0000000..0a58595
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_host.h
@@ -0,0 +1,53 @@
+/*
+ * 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.  */
+
+#ifndef PCI_HOST_H
+#define PCI_HOST_H
+
+#include "sysbus.h"
+#include "rwhandler.h"
+
+struct PCIHostState {
+    SysBusDevice busdev;
+    ReadWriteHandler conf_handler;
+    ReadWriteHandler data_handler;
+    uint32_t config_reg;
+    PCIBus *bus;
+};
+
+void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
+uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
+
+/* for mmio */
+int pci_host_conf_register_mmio(PCIHostState *s, int endian);
+int pci_host_data_register_mmio(PCIHostState *s, int endian);
+
+/* for ioio */
+void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s);
+void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s);
+
+#endif /* PCI_HOST_H */
diff --git a/qemu-0.15.x/hw/pci_ids.h b/qemu-0.15.x/hw/pci_ids.h
new file mode 100644
index 0000000..83f3893
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_ids.h
@@ -0,0 +1,122 @@
+/*
+ *      PCI Class, Vendor and Device IDs
+ *
+ *      Please keep sorted.
+ *
+ *      Abbreviated version of linux/pci_ids.h
+ *
+ *      QEMU-specific definitions belong in pci.h
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_BASE_CLASS_STORAGE           0x01
+#define PCI_BASE_CLASS_NETWORK           0x02
+
+#define PCI_CLASS_STORAGE_SCSI           0x0100
+#define PCI_CLASS_STORAGE_IDE            0x0101
+#define PCI_CLASS_STORAGE_SATA           0x0106
+#define PCI_CLASS_STORAGE_OTHER          0x0180
+
+#define PCI_CLASS_NETWORK_ETHERNET       0x0200
+
+#define PCI_CLASS_DISPLAY_VGA            0x0300
+#define PCI_CLASS_DISPLAY_OTHER          0x0380
+
+#define PCI_CLASS_MULTIMEDIA_AUDIO       0x0401
+
+#define PCI_CLASS_MEMORY_RAM             0x0500
+
+#define PCI_CLASS_SYSTEM_OTHER           0x0880
+
+#define PCI_CLASS_SERIAL_USB             0x0c03
+
+#define PCI_CLASS_BRIDGE_HOST            0x0600
+#define PCI_CLASS_BRIDGE_ISA             0x0601
+#define PCI_CLASS_BRIDGE_PCI             0x0604
+#define PCI_CLASS_BRIDGE_OTHER           0x0680
+
+#define PCI_CLASS_COMMUNICATION_OTHER    0x0780
+
+#define PCI_CLASS_PROCESSOR_CO           0x0b40
+#define PCI_CLASS_PROCESSOR_POWERPC      0x0b20
+
+#define PCI_CLASS_OTHERS                 0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_LSI_LOGIC          0x1000
+#define PCI_DEVICE_ID_LSI_53C895A        0x0012
+
+#define PCI_VENDOR_ID_DEC                0x1011
+#define PCI_DEVICE_ID_DEC_21154          0x0026
+
+#define PCI_VENDOR_ID_CIRRUS             0x1013
+
+#define PCI_VENDOR_ID_IBM                0x1014
+
+#define PCI_VENDOR_ID_AMD                0x1022
+#define PCI_DEVICE_ID_AMD_LANCE          0x2000
+
+#define PCI_VENDOR_ID_TI                 0x104c
+
+#define PCI_VENDOR_ID_MOTOROLA           0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC106    0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN     0x4801
+
+#define PCI_VENDOR_ID_APPLE              0x106b
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
+#define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
+
+#define PCI_VENDOR_ID_SUN                0x108e
+#define PCI_DEVICE_ID_SUN_EBUS           0x1000
+#define PCI_DEVICE_ID_SUN_SIMBA          0x5000
+#define PCI_DEVICE_ID_SUN_SABRE          0xa000
+
+#define PCI_VENDOR_ID_CMD                0x1095
+#define PCI_DEVICE_ID_CMD_646            0x0646
+
+#define PCI_VENDOR_ID_REALTEK            0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139       0x8139
+
+#define PCI_VENDOR_ID_XILINX             0x10ee
+
+#define PCI_VENDOR_ID_VIA                0x1106
+#define PCI_DEVICE_ID_VIA_ISA_BRIDGE     0x0686
+#define PCI_DEVICE_ID_VIA_IDE            0x0571
+#define PCI_DEVICE_ID_VIA_UHCI           0x3038
+#define PCI_DEVICE_ID_VIA_ACPI           0x3057
+#define PCI_DEVICE_ID_VIA_AC97           0x3058
+#define PCI_DEVICE_ID_VIA_MC97           0x3068
+
+#define PCI_VENDOR_ID_MARVELL            0x11ab
+
+#define PCI_VENDOR_ID_ENSONIQ            0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1370     0x5000
+
+#define PCI_VENDOR_ID_FREESCALE          0x1957
+#define PCI_DEVICE_ID_MPC8533E           0x0030
+
+#define PCI_VENDOR_ID_INTEL              0x8086
+#define PCI_DEVICE_ID_INTEL_82441        0x1237
+#define PCI_DEVICE_ID_INTEL_82801AA_5    0x2415
+#define PCI_DEVICE_ID_INTEL_82801D       0x24CD
+#define PCI_DEVICE_ID_INTEL_ESB_9        0x25ab
+#define PCI_DEVICE_ID_INTEL_82371SB_0    0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1    0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2    0x7020
+#define PCI_DEVICE_ID_INTEL_82371AB_0    0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
+
+#define PCI_VENDOR_ID_XEN               0x5853
+#define PCI_DEVICE_ID_XEN_PLATFORM      0x0001
diff --git a/qemu-0.15.x/hw/pci_internals.h b/qemu-0.15.x/hw/pci_internals.h
new file mode 100644
index 0000000..fbe1866
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_internals.h
@@ -0,0 +1,47 @@
+#ifndef QEMU_PCI_INTERNALS_H
+#define QEMU_PCI_INTERNALS_H
+
+/*
+ * This header files is private to pci.c and pci_bridge.c
+ * So following structures are opaque to others and shouldn't be
+ * accessed.
+ *
+ * For pci-to-pci bridge needs to include this header file to embed
+ * PCIBridge in its structure or to get sizeof(PCIBridge),
+ * However, they shouldn't access those following members directly.
+ * Use accessor function in pci.h, pci_bridge.h
+ */
+
+extern struct BusInfo pci_bus_info;
+
+struct PCIBus {
+    BusState qbus;
+    uint8_t devfn_min;
+    pci_set_irq_fn set_irq;
+    pci_map_irq_fn map_irq;
+    pci_hotplug_fn hotplug;
+    DeviceState *hotplug_qdev;
+    void *irq_opaque;
+    PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
+    PCIDevice *parent_dev;
+    target_phys_addr_t mem_base;
+
+    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
+    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
+
+    /* The bus IRQ state is the logical OR of the connected devices.
+       Keep a count of the number of devices with raised IRQs.  */
+    int nirq;
+    int *irq_count;
+};
+
+struct PCIBridge {
+    PCIDevice dev;
+
+    /* private member */
+    PCIBus sec_bus;
+    pci_map_irq_fn map_irq;
+    const char *bus_name;
+};
+
+#endif /* QEMU_PCI_INTERNALS_H */
diff --git a/qemu-0.15.x/hw/pci_regs.h b/qemu-0.15.x/hw/pci_regs.h
new file mode 100644
index 0000000..e884096
--- /dev/null
+++ b/qemu-0.15.x/hw/pci_regs.h
@@ -0,0 +1,715 @@
+/*
+ *	pci_regs.h
+ *
+ *	PCI standard defines
+ *	Copyright 1994, Drew Eckhardt
+ *	Copyright 1997--1999 Martin Mares <mj at ucw.cz>
+ *
+ *	For more information, please consult the following manuals (look at
+ *	http://www.pcisig.com/ for how to get them):
+ *
+ *	PCI BIOS Specification
+ *	PCI Local Bus Specification
+ *	PCI to PCI Bridge Specification
+ *	PCI System Design Guide
+ *
+ * 	For hypertransport information, please consult the following manuals
+ * 	from http://www.hypertransport.org
+ *
+ *	The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#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_COMMAND_MASTER	0x4	/* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL	0x8	/* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE	0x10	/* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20	/* Enable palette snooping */
+#define  PCI_COMMAND_PARITY	0x40	/* Enable parity checking */
+#define  PCI_COMMAND_WAIT 	0x80	/* Enable address/data stepping */
+#define  PCI_COMMAND_SERR	0x100	/* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK	0x200	/* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS		0x06	/* 16 bits */
+#define  PCI_STATUS_INTERRUPT	0x08	/* Interrupt status */
+#define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */
+#define  PCI_STATUS_66MHZ	0x20	/* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK	0x80	/* Accept fast-back to back */
+#define  PCI_STATUS_PARITY	0x100	/* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK	0x600	/* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST		0x000
+#define  PCI_STATUS_DEVSEL_MEDIUM	0x200
+#define  PCI_STATUS_DEVSEL_SLOW		0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT	0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT	0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT	0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR	0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY	0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION	0x08	/* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID		0x08	/* Revision ID */
+#define PCI_CLASS_PROG		0x09	/* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE	0x0a	/* Device class */
+
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
+#define PCI_HEADER_TYPE		0x0e	/* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL		0
+#define  PCI_HEADER_TYPE_BRIDGE		1
+#define  PCI_HEADER_TYPE_CARDBUS	2
+
+#define PCI_BIST		0x0f	/* 8 bits */
+#define  PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define  PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back.  Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#define PCI_BASE_ADDRESS_1	0x14	/* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2	0x18	/* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3	0x1c	/* 32 bits */
+#define PCI_BASE_ADDRESS_4	0x20	/* 32 bits */
+#define PCI_BASE_ADDRESS_5	0x24	/* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE		0x01	/* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO	0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY	0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK	0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH	0x08	/* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK	(~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK	(~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS		0x28
+#define PCI_SUBSYSTEM_VENDOR_ID	0x2c
+#define PCI_SUBSYSTEM_ID	0x2e
+#define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE	0x01
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#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 */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS		0x18	/* Primary bus number */
+#define PCI_SECONDARY_BUS	0x19	/* Secondary bus number */
+#define PCI_SUBORDINATE_BUS	0x1a	/* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER	0x1b	/* Latency timer for secondary interface */
+#define PCI_IO_BASE		0x1c	/* I/O range behind the bridge */
+#define PCI_IO_LIMIT		0x1d
+#define  PCI_IO_RANGE_TYPE_MASK	0x0fUL	/* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16	0x00
+#define  PCI_IO_RANGE_TYPE_32	0x01
+#define  PCI_IO_RANGE_MASK	(~0x0fUL)
+#define PCI_SEC_STATUS		0x1e	/* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE		0x20	/* Memory range behind */
+#define PCI_MEMORY_LIMIT	0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_MEMORY_RANGE_MASK	(~0x0fUL)
+#define PCI_PREF_MEMORY_BASE	0x24	/* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT	0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_PREF_RANGE_TYPE_32	0x00
+#define  PCI_PREF_RANGE_TYPE_64	0x01
+#define  PCI_PREF_RANGE_MASK	(~0x0fUL)
+#define PCI_PREF_BASE_UPPER32	0x28	/* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32	0x2c
+#define PCI_IO_BASE_UPPER16	0x30	/* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16	0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1	0x38	/* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL	0x3e
+#define  PCI_BRIDGE_CTL_PARITY	0x01	/* Enable parity detection on secondary interface */
+#define  PCI_BRIDGE_CTL_SERR	0x02	/* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_ISA	0x04	/* Enable ISA mode */
+#define  PCI_BRIDGE_CTL_VGA	0x08	/* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT	0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET	0x40	/* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK	0x80	/* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST	0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS	0x16	/* Secondary status */
+#define PCI_CB_PRIMARY_BUS	0x18	/* PCI bus number */
+#define PCI_CB_CARD_BUS		0x19	/* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS	0x1a	/* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER	0x1b	/* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0	0x1c
+#define PCI_CB_MEMORY_LIMIT_0	0x20
+#define PCI_CB_MEMORY_BASE_1	0x24
+#define PCI_CB_MEMORY_LIMIT_1	0x28
+#define PCI_CB_IO_BASE_0	0x2c
+#define PCI_CB_IO_BASE_0_HI	0x2e
+#define PCI_CB_IO_LIMIT_0	0x30
+#define PCI_CB_IO_LIMIT_0_HI	0x32
+#define PCI_CB_IO_BASE_1	0x34
+#define PCI_CB_IO_BASE_1_HI	0x36
+#define PCI_CB_IO_LIMIT_1	0x38
+#define PCI_CB_IO_LIMIT_1_HI	0x3a
+#define  PCI_CB_IO_RANGE_MASK	(~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL	0x3e
+#define  PCI_CB_BRIDGE_CTL_PARITY	0x01	/* Similar to standard bridge control register */
+#define  PCI_CB_BRIDGE_CTL_SERR		0x02
+#define  PCI_CB_BRIDGE_CTL_ISA		0x04
+#define  PCI_CB_BRIDGE_CTL_VGA		0x08
+#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT	0x20
+#define  PCI_CB_BRIDGE_CTL_CB_RESET	0x40	/* CardBus reset */
+#define  PCI_CB_BRIDGE_CTL_16BIT_INT	0x80	/* Enable interrupt for 16-bit cards */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100	/* Prefetch enable for both memory regions */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define  PCI_CB_BRIDGE_CTL_POST_WRITES	0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID	0x40
+#define PCI_CB_SUBSYSTEM_ID		0x42
+#define PCI_CB_LEGACY_MODE_BASE		0x44	/* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID		0	/* Capability ID */
+#define  PCI_CAP_ID_PM		0x01	/* Power Management */
+#define  PCI_CAP_ID_AGP		0x02	/* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD		0x03	/* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
+#define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
+#define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_HT		0x08	/* HyperTransport */
+#define  PCI_CAP_ID_VNDR	0x09	/* Vendor specific */
+#define  PCI_CAP_ID_DBG		0x0A	/* Debug port */
+#define  PCI_CAP_ID_CCRC	0x0B	/* CompactPCI Central Resource Control */
+#define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
+#define  PCI_CAP_ID_SSVID	0x0D	/* Bridge subsystem vendor/device ID */
+#define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
+#define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
+#define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
+#define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
+#define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF		4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC		2	/* PM Capabilities Register */
+#define  PCI_PM_CAP_VER_MASK	0x0007	/* Version */
+#define  PCI_PM_CAP_PME_CLOCK	0x0008	/* PME clock required */
+#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
+#define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization */
+#define  PCI_PM_CAP_AUX_POWER	0x01C0	/* Auxiliary power support mask */
+#define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
+#define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
+#define  PCI_PM_CAP_PME		0x0800	/* PME pin supported */
+#define  PCI_PM_CAP_PME_MASK	0xF800	/* PME Mask of all supported states */
+#define  PCI_PM_CAP_PME_D0	0x0800	/* PME# from D0 */
+#define  PCI_PM_CAP_PME_D1	0x1000	/* PME# from D1 */
+#define  PCI_PM_CAP_PME_D2	0x2000	/* PME# from D2 */
+#define  PCI_PM_CAP_PME_D3	0x4000	/* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3cold	0x8000	/* PME# from D3 (cold) */
+#define  PCI_PM_CAP_PME_SHIFT	11	/* Start of the PME Mask in PMC */
+#define PCI_PM_CTRL		4	/* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_NO_SOFT_RESET	0x0008	/* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS	0x8000	/* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS	6	/* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3	0x40	/* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE	0x80	/* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER	7	/* (??) */
+#define PCI_PM_SIZEOF		8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION		2	/* BCD version number */
+#define PCI_AGP_RFU		3	/* Rest of capability flags */
+#define PCI_AGP_STATUS		4	/* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK	0xff000000	/* Maximum number of requests - 1 */
+#define  PCI_AGP_STATUS_SBA	0x0200	/* Sideband addressing supported */
+#define  PCI_AGP_STATUS_64BIT	0x0020	/* 64-bit addressing supported */
+#define  PCI_AGP_STATUS_FW	0x0010	/* FW transfers supported */
+#define  PCI_AGP_STATUS_RATE4	0x0004	/* 4x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE2	0x0002	/* 2x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE1	0x0001	/* 1x transfer rate supported */
+#define PCI_AGP_COMMAND		8	/* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
+#define  PCI_AGP_COMMAND_SBA	0x0200	/* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP	0x0100	/* Allow processing of AGP transactions */
+#define  PCI_AGP_COMMAND_64BIT	0x0020 	/* Allow processing of 64-bit addresses */
+#define  PCI_AGP_COMMAND_FW	0x0010 	/* Force FW transfers */
+#define  PCI_AGP_COMMAND_RATE4	0x0004	/* Use 4x rate */
+#define  PCI_AGP_COMMAND_RATE2	0x0002	/* Use 2x rate */
+#define  PCI_AGP_COMMAND_RATE1	0x0001	/* Use 1x rate */
+#define PCI_AGP_SIZEOF		12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR		2	/* Address to access (15 bits!) */
+#define  PCI_VPD_ADDR_MASK	0x7fff	/* Address mask */
+#define  PCI_VPD_ADDR_F		0x8000	/* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA		4	/* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR		2	/* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS	0x1f	/* Number of expansion slots available */
+#define  PCI_SID_ESR_FIC	0x20	/* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR	3	/* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS		2	/* Various flags */
+#define  PCI_MSI_FLAGS_64BIT	0x80	/* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE	0x70	/* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK	0x0e	/* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE	0x01	/* MSI feature enabled */
+#define  PCI_MSI_FLAGS_MASKBIT	0x100	/* 64-bit mask bits allowed */
+#define PCI_MSI_RFU		3	/* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO	4	/* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI	8	/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
+#define PCI_MSI_MASK_32		12	/* Mask bits register for 32-bit devices */
+#define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
+#define PCI_MSI_MASK_64		16	/* Mask bits register for 64-bit devices */
+
+/* MSI-X registers */
+#define PCI_MSIX_FLAGS		2
+#define  PCI_MSIX_FLAGS_QSIZE	0x7FF
+#define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
+#define  PCI_MSIX_FLAGS_MASKALL	(1 << 14)
+#define PCI_MSIX_TABLE		4
+#define PCI_MSIX_PBA		8
+#define  PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
+
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE		16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR	0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR	4
+#define  PCI_MSIX_ENTRY_DATA		8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL	12
+#define   PCI_MSIX_ENTRY_CTRL_MASKBIT	1
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR		2	/* Control and Status Register */
+#define  PCI_CHSWP_DHA		0x01	/* Device Hiding Arm */
+#define  PCI_CHSWP_EIM		0x02	/* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE		0x04	/* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO		0x08	/* LED On / Off */
+#define  PCI_CHSWP_PI		0x30	/* Programming Interface */
+#define  PCI_CHSWP_EXT		0x40	/* ENUM# status - extraction */
+#define  PCI_CHSWP_INS		0x80	/* ENUM# status - insertion */
+
+/* PCI Advanced Feature registers */
+
+#define PCI_AF_LENGTH		2
+#define PCI_AF_CAP		3
+#define  PCI_AF_CAP_TP		0x01
+#define  PCI_AF_CAP_FLR		0x02
+#define PCI_AF_CTRL		4
+#define  PCI_AF_CTRL_FLR	0x01
+#define PCI_AF_STATUS		5
+#define  PCI_AF_STATUS_TP	0x01
+
+/* PCI-X registers */
+
+#define PCI_X_CMD		2	/* Modes & Features */
+#define  PCI_X_CMD_DPERR_E	0x0001	/* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
+#define  PCI_X_CMD_READ_512	0x0000	/* 512 byte maximum read byte count */
+#define  PCI_X_CMD_READ_1K	0x0004	/* 1Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_2K	0x0008	/* 2Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_4K	0x000c	/* 4Kbyte maximum read byte count */
+#define  PCI_X_CMD_MAX_READ	0x000c	/* Max Memory Read Byte Count */
+				/* Max # of outstanding split transactions */
+#define  PCI_X_CMD_SPLIT_1	0x0000	/* Max 1 */
+#define  PCI_X_CMD_SPLIT_2	0x0010	/* Max 2 */
+#define  PCI_X_CMD_SPLIT_3	0x0020	/* Max 3 */
+#define  PCI_X_CMD_SPLIT_4	0x0030	/* Max 4 */
+#define  PCI_X_CMD_SPLIT_8	0x0040	/* Max 8 */
+#define  PCI_X_CMD_SPLIT_12	0x0050	/* Max 12 */
+#define  PCI_X_CMD_SPLIT_16	0x0060	/* Max 16 */
+#define  PCI_X_CMD_SPLIT_32	0x0070	/* Max 32 */
+#define  PCI_X_CMD_MAX_SPLIT	0x0070	/* Max Outstanding Split Transactions */
+#define  PCI_X_CMD_VERSION(x) 	(((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS		4	/* PCI-X capabilities */
+#define  PCI_X_STATUS_DEVFN	0x000000ff	/* A copy of devfn */
+#define  PCI_X_STATUS_BUS	0x0000ff00	/* A copy of bus nr */
+#define  PCI_X_STATUS_64BIT	0x00010000	/* 64-bit device */
+#define  PCI_X_STATUS_133MHZ	0x00020000	/* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC	0x00040000	/* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL	0x00080000	/* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX	0x00100000	/* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ	0x00600000	/* Designed Max Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT	0x03800000	/* Designed Max Outstanding Split Transactions */
+#define  PCI_X_STATUS_MAX_CUM	0x1c000000	/* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR	0x20000000	/* Rcvd Split Completion Error Msg */
+#define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
+#define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
+
+/* PCI Bridge Subsystem ID registers */
+
+#define PCI_SSVID_VENDOR_ID     4	/* PCI-Bridge subsystem vendor id register */
+#define PCI_SSVID_DEVICE_ID     6	/* PCI-Bridge subsystem device id register */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS		2	/* Capabilities register */
+#define PCI_EXP_FLAGS_VERS	0x000f	/* Capability version */
+#define PCI_EXP_FLAGS_TYPE	0x00f0	/* Device/Port type */
+#define  PCI_EXP_TYPE_ENDPOINT	0x0	/* Express Endpoint */
+#define  PCI_EXP_TYPE_LEG_END	0x1	/* Legacy Endpoint */
+#define  PCI_EXP_TYPE_ROOT_PORT 0x4	/* Root Port */
+#define  PCI_EXP_TYPE_UPSTREAM	0x5	/* Upstream Port */
+#define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
+#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_RC_END	0x9	/* Root Complex Integrated Endpoint */
+#define  PCI_EXP_TYPE_RC_EC	0x10	/* Root Complex Event Collector */
+#define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ	0x3e00	/* Interrupt message number */
+#define PCI_EXP_DEVCAP		4	/* Device capabilities */
+#define  PCI_EXP_DEVCAP_PAYLOAD	0x07	/* Max_Payload_Size */
+#define  PCI_EXP_DEVCAP_PHANTOM	0x18	/* Phantom functions */
+#define  PCI_EXP_DEVCAP_EXT_TAG	0x20	/* Extended tags */
+#define  PCI_EXP_DEVCAP_L0S	0x1c0	/* L0s Acceptable Latency */
+#define  PCI_EXP_DEVCAP_L1	0xe00	/* L1 Acceptable Latency */
+#define  PCI_EXP_DEVCAP_ATN_BUT	0x1000	/* Attention Button Present */
+#define  PCI_EXP_DEVCAP_ATN_IND	0x2000	/* Attention Indicator Present */
+#define  PCI_EXP_DEVCAP_PWR_IND	0x4000	/* Power Indicator Present */
+#define  PCI_EXP_DEVCAP_RBER	0x8000	/* Role-Based Error Reporting */
+#define  PCI_EXP_DEVCAP_PWR_VAL	0x3fc0000 /* Slot Power Limit Value */
+#define  PCI_EXP_DEVCAP_PWR_SCL	0xc000000 /* Slot Power Limit Scale */
+#define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL		8	/* Device Control */
+#define  PCI_EXP_DEVCTL_CERE	0x0001	/* Correctable Error Reporting En. */
+#define  PCI_EXP_DEVCTL_NFERE	0x0002	/* Non-Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_FERE	0x0004	/* Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_URRE	0x0008	/* Unsupported Request Reporting En. */
+#define  PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define  PCI_EXP_DEVCTL_PAYLOAD	0x00e0	/* Max_Payload_Size */
+#define  PCI_EXP_DEVCTL_EXT_TAG	0x0100	/* Extended Tag Field Enable */
+#define  PCI_EXP_DEVCTL_PHANTOM	0x0200	/* Phantom Functions Enable */
+#define  PCI_EXP_DEVCTL_AUX_PME	0x0400	/* Auxiliary Power PM Enable */
+#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+#define  PCI_EXP_DEVCTL_READRQ	0x7000	/* Max_Read_Request_Size */
+#define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
+#define PCI_EXP_DEVSTA		10	/* Device Status */
+#define  PCI_EXP_DEVSTA_CED	0x01	/* Correctable Error Detected */
+#define  PCI_EXP_DEVSTA_NFED	0x02	/* Non-Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_FED	0x04	/* Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_URD	0x08	/* Unsupported Request Detected */
+#define  PCI_EXP_DEVSTA_AUXPD	0x10	/* AUX Power Detected */
+#define  PCI_EXP_DEVSTA_TRPND	0x20	/* Transactions Pending */
+#define PCI_EXP_LNKCAP		12	/* Link Capabilities */
+#define  PCI_EXP_LNKCAP_SLS	0x0000000f /* Supported Link Speeds */
+#define  PCI_EXP_LNKCAP_MLW	0x000003f0 /* Maximum Link Width */
+#define  PCI_EXP_LNKCAP_ASPMS	0x00000c00 /* ASPM Support */
+#define  PCI_EXP_LNKCAP_L0SEL	0x00007000 /* L0s Exit Latency */
+#define  PCI_EXP_LNKCAP_L1EL	0x00038000 /* L1 Exit Latency */
+#define  PCI_EXP_LNKCAP_CLKPM	0x00040000 /* L1 Clock Power Management */
+#define  PCI_EXP_LNKCAP_SDERC	0x00080000 /* Surprise Down Error Reporting Capable */
+#define  PCI_EXP_LNKCAP_DLLLARC	0x00100000 /* Data Link Layer Link Active Reporting Capable */
+#define  PCI_EXP_LNKCAP_LBNC	0x00200000 /* Link Bandwidth Notification Capability */
+#define  PCI_EXP_LNKCAP_PN	0xff000000 /* Port Number */
+#define PCI_EXP_LNKCTL		16	/* Link Control */
+#define  PCI_EXP_LNKCTL_ASPMC	0x0003	/* ASPM Control */
+#define  PCI_EXP_LNKCTL_RCB	0x0008	/* Read Completion Boundary */
+#define  PCI_EXP_LNKCTL_LD	0x0010	/* Link Disable */
+#define  PCI_EXP_LNKCTL_RL	0x0020	/* Retrain Link */
+#define  PCI_EXP_LNKCTL_CCC	0x0040	/* Common Clock Configuration */
+#define  PCI_EXP_LNKCTL_ES	0x0080	/* Extended Synch */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100	/* Enable clkreq */
+#define  PCI_EXP_LNKCTL_HAWD	0x0200	/* Hardware Autonomous Width Disable */
+#define  PCI_EXP_LNKCTL_LBMIE	0x0400	/* Link Bandwidth Management Interrupt Enable */
+#define  PCI_EXP_LNKCTL_LABIE	0x0800	/* Lnk Autonomous Bandwidth Interrupt Enable */
+#define PCI_EXP_LNKSTA		18	/* Link Status */
+#define  PCI_EXP_LNKSTA_CLS	0x000f	/* Current Link Speed */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01	/* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02	/* Current Link Speed 5.0GT/s */
+#define  PCI_EXP_LNKSTA_NLW	0x03f0	/* Nogotiated Link Width */
+#define  PCI_EXP_LNKSTA_NLW_SHIFT 4	/* start of NLW mask in link status */
+#define  PCI_EXP_LNKSTA_LT	0x0800	/* Link Training */
+#define  PCI_EXP_LNKSTA_SLC	0x1000	/* Slot Clock Configuration */
+#define  PCI_EXP_LNKSTA_DLLLA	0x2000	/* Data Link Layer Link Active */
+#define  PCI_EXP_LNKSTA_LBMS	0x4000	/* Link Bandwidth Management Status */
+#define  PCI_EXP_LNKSTA_LABS	0x8000	/* Link Autonomous Bandwidth Status */
+#define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
+#define  PCI_EXP_SLTCAP_ABP	0x00000001 /* Attention Button Present */
+#define  PCI_EXP_SLTCAP_PCP	0x00000002 /* Power Controller Present */
+#define  PCI_EXP_SLTCAP_MRLSP	0x00000004 /* MRL Sensor Present */
+#define  PCI_EXP_SLTCAP_AIP	0x00000008 /* Attention Indicator Present */
+#define  PCI_EXP_SLTCAP_PIP	0x00000010 /* Power Indicator Present */
+#define  PCI_EXP_SLTCAP_HPS	0x00000020 /* Hot-Plug Surprise */
+#define  PCI_EXP_SLTCAP_HPC	0x00000040 /* Hot-Plug Capable */
+#define  PCI_EXP_SLTCAP_SPLV	0x00007f80 /* Slot Power Limit Value */
+#define  PCI_EXP_SLTCAP_SPLS	0x00018000 /* Slot Power Limit Scale */
+#define  PCI_EXP_SLTCAP_EIP	0x00020000 /* Electromechanical Interlock Present */
+#define  PCI_EXP_SLTCAP_NCCS	0x00040000 /* No Command Completed Support */
+#define  PCI_EXP_SLTCAP_PSN	0xfff80000 /* Physical Slot Number */
+#define PCI_EXP_SLTCTL		24	/* Slot Control */
+#define  PCI_EXP_SLTCTL_ABPE	0x0001	/* Attention Button Pressed Enable */
+#define  PCI_EXP_SLTCTL_PFDE	0x0002	/* Power Fault Detected Enable */
+#define  PCI_EXP_SLTCTL_MRLSCE	0x0004	/* MRL Sensor Changed Enable */
+#define  PCI_EXP_SLTCTL_PDCE	0x0008	/* Presence Detect Changed Enable */
+#define  PCI_EXP_SLTCTL_CCIE	0x0010	/* Command Completed Interrupt Enable */
+#define  PCI_EXP_SLTCTL_HPIE	0x0020	/* Hot-Plug Interrupt Enable */
+#define  PCI_EXP_SLTCTL_AIC	0x00c0	/* Attention Indicator Control */
+#define  PCI_EXP_SLTCTL_PIC	0x0300	/* Power Indicator Control */
+#define  PCI_EXP_SLTCTL_PCC	0x0400	/* Power Controller Control */
+#define  PCI_EXP_SLTCTL_EIC	0x0800	/* Electromechanical Interlock Control */
+#define  PCI_EXP_SLTCTL_DLLSCE	0x1000	/* Data Link Layer State Changed Enable */
+#define PCI_EXP_SLTSTA		26	/* Slot Status */
+#define  PCI_EXP_SLTSTA_ABP	0x0001	/* Attention Button Pressed */
+#define  PCI_EXP_SLTSTA_PFD	0x0002	/* Power Fault Detected */
+#define  PCI_EXP_SLTSTA_MRLSC	0x0004	/* MRL Sensor Changed */
+#define  PCI_EXP_SLTSTA_PDC	0x0008	/* Presence Detect Changed */
+#define  PCI_EXP_SLTSTA_CC	0x0010	/* Command Completed */
+#define  PCI_EXP_SLTSTA_MRLSS	0x0020	/* MRL Sensor State */
+#define  PCI_EXP_SLTSTA_PDS	0x0040	/* Presence Detect State */
+#define  PCI_EXP_SLTSTA_EIS	0x0080	/* Electromechanical Interlock Status */
+#define  PCI_EXP_SLTSTA_DLLSC	0x0100	/* Data Link Layer State Changed */
+#define PCI_EXP_RTCTL		28	/* Root Control */
+#define  PCI_EXP_RTCTL_SECEE	0x01	/* System Error on Correctable Error */
+#define  PCI_EXP_RTCTL_SENFEE	0x02	/* System Error on Non-Fatal Error */
+#define  PCI_EXP_RTCTL_SEFEE	0x04	/* System Error on Fatal Error */
+#define  PCI_EXP_RTCTL_PMEIE	0x08	/* PME Interrupt Enable */
+#define  PCI_EXP_RTCTL_CRSSVE	0x10	/* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP		30	/* Root Capabilities */
+#define PCI_EXP_RTSTA		32	/* Root Status */
+#define PCI_EXP_RTSTA_PME	0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING	0x20000 /* PME pending */
+#define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
+#define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
+#define  PCI_EXP_DEVCAP2_LTR	0x800	/* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MASK	0xc0000 /* OBFF support mechanism */
+#define  PCI_EXP_OBFF_MSG	0x40000 /* New message signaling */
+#define  PCI_EXP_OBFF_WAKE	0x80000 /* Re-use WAKE# for OBFF */
+#define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
+#define  PCI_EXP_DEVCTL2_ARI	0x20	/* Alternative Routing-ID */
+#define  PCI_EXP_IDO_REQ_EN	0x100	/* ID-based ordering request enable */
+#define  PCI_EXP_IDO_CMP_EN	0x200	/* ID-based ordering completion enable */
+#define  PCI_EXP_LTR_EN		0x400	/* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MSGA_EN	0x2000	/* OBFF enable with Message type A */
+#define  PCI_EXP_OBFF_MSGB_EN	0x4000	/* OBFF enable with Message type B */
+#define  PCI_EXP_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
+#define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
+#define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header)		((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR	1
+#define PCI_EXT_CAP_ID_VC	2
+#define PCI_EXT_CAP_ID_DSN	3
+#define PCI_EXT_CAP_ID_PWR	4
+#define PCI_EXT_CAP_ID_VNDR	11
+#define PCI_EXT_CAP_ID_ACS	13
+#define PCI_EXT_CAP_ID_ARI	14
+#define PCI_EXT_CAP_ID_ATS	15
+#define PCI_EXT_CAP_ID_SRIOV	16
+#define PCI_EXT_CAP_ID_LTR	24
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
+#define  PCI_ERR_UNC_TRAIN	0x00000001	/* Training */
+#define  PCI_ERR_UNC_DLP	0x00000010	/* Data Link Protocol */
+#define  PCI_ERR_UNC_POISON_TLP	0x00001000	/* Poisoned TLP */
+#define  PCI_ERR_UNC_FCP	0x00002000	/* Flow Control Protocol */
+#define  PCI_ERR_UNC_COMP_TIME	0x00004000	/* Completion Timeout */
+#define  PCI_ERR_UNC_COMP_ABORT	0x00008000	/* Completer Abort */
+#define  PCI_ERR_UNC_UNX_COMP	0x00010000	/* Unexpected Completion */
+#define  PCI_ERR_UNC_RX_OVER	0x00020000	/* Receiver Overflow */
+#define  PCI_ERR_UNC_MALF_TLP	0x00040000	/* Malformed TLP */
+#define  PCI_ERR_UNC_ECRC	0x00080000	/* ECRC Error Status */
+#define  PCI_ERR_UNC_UNSUP	0x00100000	/* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK	8	/* Uncorrectable Error Mask */
+	/* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER	12	/* Uncorrectable Error Severity */
+	/* Same bits as above */
+#define PCI_ERR_COR_STATUS	16	/* Correctable Error Status */
+#define  PCI_ERR_COR_RCVR	0x00000001	/* Receiver Error Status */
+#define  PCI_ERR_COR_BAD_TLP	0x00000040	/* Bad TLP Status */
+#define  PCI_ERR_COR_BAD_DLLP	0x00000080	/* Bad DLLP Status */
+#define  PCI_ERR_COR_REP_ROLL	0x00000100	/* REPLAY_NUM Rollover */
+#define  PCI_ERR_COR_REP_TIMER	0x00001000	/* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK	20	/* Correctable Error Mask */
+	/* Same bits as above */
+#define PCI_ERR_CAP		24	/* Advanced Error Capabilities */
+#define  PCI_ERR_CAP_FEP(x)	((x) & 31)	/* First Error Pointer */
+#define  PCI_ERR_CAP_ECRC_GENC	0x00000020	/* ECRC Generation Capable */
+#define  PCI_ERR_CAP_ECRC_GENE	0x00000040	/* ECRC Generation Enable */
+#define  PCI_ERR_CAP_ECRC_CHKC	0x00000080	/* ECRC Check Capable */
+#define  PCI_ERR_CAP_ECRC_CHKE	0x00000100	/* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG	28	/* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND	44	/* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN		0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN	0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN	0x00000004
+#define PCI_ERR_ROOT_STATUS	48
+#define PCI_ERR_ROOT_COR_RCV		0x00000001	/* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV	0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV		0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV	0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL	0x00000010	/* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV	0x00000020	/* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV		0x00000040	/* Fatal Received */
+#define PCI_ERR_ROOT_ERR_SRC	52	/* Error Source Identification */
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1	4
+#define PCI_VC_PORT_REG2	8
+#define PCI_VC_PORT_CTRL	12
+#define PCI_VC_PORT_STATUS	14
+#define PCI_VC_RES_CAP		16
+#define PCI_VC_RES_CTRL		20
+#define PCI_VC_RES_STATUS	26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR		4	/* Data Select Register */
+#define PCI_PWR_DATA		8	/* Data Register */
+#define  PCI_PWR_DATA_BASE(x)	((x) & 0xff)	    /* Base Power */
+#define  PCI_PWR_DATA_SCALE(x)	(((x) >> 8) & 3)    /* Data Scale */
+#define  PCI_PWR_DATA_PM_SUB(x)	(((x) >> 10) & 7)   /* PM Sub State */
+#define  PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define  PCI_PWR_DATA_TYPE(x)	(((x) >> 15) & 7)   /* Type */
+#define  PCI_PWR_DATA_RAIL(x)	(((x) >> 18) & 7)   /* Power Rail */
+#define PCI_PWR_CAP		12	/* Capability */
+#define  PCI_PWR_CAP_BUDGET(x)	((x) & 1)	/* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK	0xE0
+#define HT_CAPTYPE_SLAVE	0x00	/* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST		0x20	/* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK	0xF8
+#define HT_CAPTYPE_IRQ		0x80	/* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40	0xA0	/* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2	/* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP	0x90	/* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF	0x98	/* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING	0xA8	/* MSI Mapping Capability */
+#define  HT_MSI_FLAGS		0x02		/* Offset to flags */
+#define  HT_MSI_FLAGS_ENABLE	0x1		/* Mapping enable */
+#define  HT_MSI_FLAGS_FIXED	0x2		/* Fixed mapping only */
+#define  HT_MSI_FIXED_ADDR	0x00000000FEE00000ULL	/* Fixed addr */
+#define  HT_MSI_ADDR_LO		0x04		/* Offset to low addr bits */
+#define  HT_MSI_ADDR_LO_MASK	0xFFF00000	/* Low address bit mask */
+#define  HT_MSI_ADDR_HI		0x08		/* Offset to high addr bits */
+#define HT_CAPTYPE_DIRECT_ROUTE	0xB0	/* Direct routing configuration */
+#define HT_CAPTYPE_VCSET	0xB8	/* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY	0xC0	/* Retry on error configuration */
+#define HT_CAPTYPE_GEN3		0xD0	/* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM		0xE0	/* Hypertransport powermanagement configuration */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP		0x04	/* ARI Capability Register */
+#define  PCI_ARI_CAP_MFVC	0x0001	/* MFVC Function Groups Capability */
+#define  PCI_ARI_CAP_ACS	0x0002	/* ACS Function Groups Capability */
+#define  PCI_ARI_CAP_NFN(x)	(((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL		0x06	/* ARI Control Register */
+#define  PCI_ARI_CTRL_MFVC	0x0001	/* MFVC Function Groups Enable */
+#define  PCI_ARI_CTRL_ACS	0x0002	/* ACS Function Groups Enable */
+#define  PCI_ARI_CTRL_FG(x)	(((x) >> 4) & 7) /* Function Group */
+
+/* Address Translation Service */
+#define PCI_ATS_CAP		0x04	/* ATS Capability Register */
+#define  PCI_ATS_CAP_QDEP(x)	((x) & 0x1f)	/* Invalidate Queue Depth */
+#define  PCI_ATS_MAX_QDEP	32	/* Max Invalidate Queue Depth */
+#define PCI_ATS_CTRL		0x06	/* ATS Control Register */
+#define  PCI_ATS_CTRL_ENABLE	0x8000	/* ATS Enable */
+#define  PCI_ATS_CTRL_STU(x)	((x) & 0x1f)	/* Smallest Translation Unit */
+#define  PCI_ATS_MIN_STU	12	/* shift of minimum STU block */
+
+/* Single Root I/O Virtualization */
+#define PCI_SRIOV_CAP		0x04	/* SR-IOV Capabilities */
+#define  PCI_SRIOV_CAP_VFM	0x01	/* VF Migration Capable */
+#define  PCI_SRIOV_CAP_INTR(x)	((x) >> 21) /* Interrupt Message Number */
+#define PCI_SRIOV_CTRL		0x08	/* SR-IOV Control */
+#define  PCI_SRIOV_CTRL_VFE	0x01	/* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM	0x02	/* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR	0x04	/* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE	0x08	/* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI	0x10	/* ARI Capable Hierarchy */
+#define PCI_SRIOV_STATUS	0x0a	/* SR-IOV Status */
+#define  PCI_SRIOV_STATUS_VFM	0x01	/* VF Migration Status */
+#define PCI_SRIOV_INITIAL_VF	0x0c	/* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF	0x0e	/* Total VFs */
+#define PCI_SRIOV_NUM_VF	0x10	/* Number of VFs */
+#define PCI_SRIOV_FUNC_LINK	0x12	/* Function Dependency Link */
+#define PCI_SRIOV_VF_OFFSET	0x14	/* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE	0x16	/* Following VF Stride */
+#define PCI_SRIOV_VF_DID	0x1a	/* VF Device ID */
+#define PCI_SRIOV_SUP_PGSIZE	0x1c	/* Supported Page Sizes */
+#define PCI_SRIOV_SYS_PGSIZE	0x20	/* System Page Size */
+#define PCI_SRIOV_BAR		0x24	/* VF BAR0 */
+#define  PCI_SRIOV_NUM_BARS	6	/* Number of VF BARs */
+#define PCI_SRIOV_VFM		0x3c	/* VF Migration State Array Offset*/
+#define  PCI_SRIOV_VFM_BIR(x)	((x) & 7)	/* State BIR */
+#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)	/* State Offset */
+#define  PCI_SRIOV_VFM_UA	0x0	/* Inactive.Unavailable */
+#define  PCI_SRIOV_VFM_MI	0x1	/* Dormant.MigrateIn */
+#define  PCI_SRIOV_VFM_MO	0x2	/* Active.MigrateOut */
+#define  PCI_SRIOV_VFM_AV	0x3	/* Active.Available */
+
+#define PCI_LTR_MAX_SNOOP_LAT	0x4
+#define PCI_LTR_MAX_NOSNOOP_LAT	0x6
+#define  PCI_LTR_VALUE_MASK	0x000003ff
+#define  PCI_LTR_SCALE_MASK	0x00001c00
+#define  PCI_LTR_SCALE_SHIFT	10
+
+/* Access Control Service */
+#define PCI_ACS_CAP		0x04	/* ACS Capability Register */
+#define  PCI_ACS_SV		0x01	/* Source Validation */
+#define  PCI_ACS_TB		0x02	/* Translation Blocking */
+#define  PCI_ACS_RR		0x04	/* P2P Request Redirect */
+#define  PCI_ACS_CR		0x08	/* P2P Completion Redirect */
+#define  PCI_ACS_UF		0x10	/* Upstream Forwarding */
+#define  PCI_ACS_EC		0x20	/* P2P Egress Control */
+#define  PCI_ACS_DT		0x40	/* Direct Translated P2P */
+#define PCI_ACS_CTRL		0x06	/* ACS Control Register */
+#define PCI_ACS_EGRESS_CTL_V	0x08	/* ACS Egress Control Vector */
+
+#endif /* LINUX_PCI_REGS_H */
diff --git a/qemu-0.15.x/hw/pcie.c b/qemu-0.15.x/hw/pcie.c
new file mode 100644
index 0000000..39607bf
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie.c
@@ -0,0 +1,543 @@
+/*
+ * pcie.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "pci_bridge.h"
+#include "pcie.h"
+#include "msix.h"
+#include "msi.h"
+#include "pci_internals.h"
+#include "pcie_regs.h"
+#include "range.h"
+
+//#define DEBUG_PCIE
+#ifdef DEBUG_PCIE
+# define PCIE_DPRINTF(fmt, ...)                                         \
+    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define PCIE_DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
+    PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+
+/***************************************************************************
+ * pci express capability helper functions
+ */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
+{
+    int pos;
+    uint8_t *exp_cap;
+
+    assert(pci_is_express(dev));
+
+    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
+                                 PCI_EXP_VER2_SIZEOF);
+    if (pos < 0) {
+        return pos;
+    }
+    dev->exp.exp_cap = pos;
+    exp_cap = dev->config + pos;
+
+    /* capability register
+       interrupt message number defaults to 0 */
+    pci_set_word(exp_cap + PCI_EXP_FLAGS,
+                 ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
+                 PCI_EXP_FLAGS_VER2);
+
+    /* device capability register
+     * table 7-12:
+     * roll based error reporting bit must be set by all
+     * Functions conforming to the ECN, PCI Express Base
+     * Specification, Revision 1.1., or subsequent PCI Express Base
+     * Specification revisions.
+     */
+    pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
+
+    pci_set_long(exp_cap + PCI_EXP_LNKCAP,
+                 (port << PCI_EXP_LNKCAP_PN_SHIFT) |
+                 PCI_EXP_LNKCAP_ASPMS_0S |
+                 PCI_EXP_LNK_MLW_1 |
+                 PCI_EXP_LNK_LS_25);
+
+    pci_set_word(exp_cap + PCI_EXP_LNKSTA,
+                 PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
+
+    pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
+                 PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
+
+    pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
+    return pos;
+}
+
+void pcie_cap_exit(PCIDevice *dev)
+{
+    pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
+}
+
+uint8_t pcie_cap_get_type(const PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    assert(pos > 0);
+    return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
+            PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
+}
+
+/* MSI/MSI-X */
+/* pci express interrupt message number */
+/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
+{
+    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+    assert(vector < 32);
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
+    pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
+                               vector << PCI_EXP_FLAGS_IRQ_SHIFT);
+}
+
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
+{
+    return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
+            PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
+}
+
+void pcie_cap_deverr_init(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
+                               PCI_EXP_DEVCAP_RBER);
+    pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
+                               PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+                               PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+    pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
+                               PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
+                               PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
+}
+
+void pcie_cap_deverr_reset(PCIDevice *dev)
+{
+    uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+    pci_long_test_and_clear_mask(devctl,
+                                 PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+                                 PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+}
+
+static void hotplug_event_update_event_status(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    uint8_t *exp_cap = dev->config + pos;
+    uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+        (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
+}
+
+static void hotplug_event_notify(PCIDevice *dev)
+{
+    bool prev = dev->exp.hpev_notified;
+
+    hotplug_event_update_event_status(dev);
+
+    if (prev == dev->exp.hpev_notified) {
+        return;
+    }
+
+    /* Note: the logic above does not take into account whether interrupts
+     * are masked. The result is that interrupt will be sent when it is
+     * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
+     * The Port may optionally send an MSI when there are hot-plug events that
+     * occur while interrupt generation is disabled, and interrupt generation is
+     * subsequently enabled. */
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_cap_flags_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_cap_flags_get_vector(dev));
+    } else {
+        qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
+    }
+}
+
+/*
+ * A PCI Express Hot-Plug Event has occurred, so update slot status register
+ * and notify OS of the event if necessary.
+ *
+ * 6.7.3 PCI Express Hot-Plug Events
+ * 6.7.3.4 Software Notification of Hot-Plug Events
+ */
+static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
+{
+    /* Minor optimization: if nothing changed - no event is needed. */
+    if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
+                                   PCI_EXP_SLTSTA, event)) {
+        return;
+    }
+    hotplug_event_notify(dev);
+}
+
+static int pcie_cap_slot_hotplug(DeviceState *qdev,
+                                 PCIDevice *pci_dev, PCIHotplugState state)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    uint8_t *exp_cap = d->config + d->exp.exp_cap;
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    /* Don't send event when device is enabled during qemu machine creation:
+     * it is present on boot, no hotplug event is necessary. We do send an
+     * event when the device is disabled later. */
+    if (state == PCI_COLDPLUG_ENABLED) {
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+                                   PCI_EXP_SLTSTA_PDS);
+        return 0;
+    }
+
+    PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
+    if (sltsta & PCI_EXP_SLTSTA_EIS) {
+        /* the slot is electromechanically locked.
+         * This error is propagated up to qdev and then to HMP/QMP.
+         */
+        return -EBUSY;
+    }
+
+    /* TODO: multifunction hot-plug.
+     * Right now, only a device of function = 0 is allowed to be
+     * hot plugged/unplugged.
+     */
+    assert(PCI_FUNC(pci_dev->devfn) == 0);
+
+    if (state == PCI_HOTPLUG_ENABLED) {
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+                                   PCI_EXP_SLTSTA_PDS);
+        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+    } else {
+        qdev_free(&pci_dev->qdev);
+        pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+                                     PCI_EXP_SLTSTA_PDS);
+        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+    }
+    return 0;
+}
+
+/* pci express slot for pci express root/downstream port
+   PCI express capability slot registers */
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
+{
+    uint32_t pos = dev->exp.exp_cap;
+
+    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
+                               PCI_EXP_FLAGS_SLOT);
+
+    pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
+                                 ~PCI_EXP_SLTCAP_PSN);
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
+                               (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
+                               PCI_EXP_SLTCAP_EIP |
+                               PCI_EXP_SLTCAP_HPS |
+                               PCI_EXP_SLTCAP_HPC |
+                               PCI_EXP_SLTCAP_PIP |
+                               PCI_EXP_SLTCAP_AIP |
+                               PCI_EXP_SLTCAP_ABP);
+
+    pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
+                                 PCI_EXP_SLTCTL_PIC |
+                                 PCI_EXP_SLTCTL_AIC);
+    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC_OFF |
+                               PCI_EXP_SLTCTL_AIC_OFF);
+    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC |
+                               PCI_EXP_SLTCTL_AIC |
+                               PCI_EXP_SLTCTL_HPIE |
+                               PCI_EXP_SLTCTL_CCIE |
+                               PCI_EXP_SLTCTL_PDCE |
+                               PCI_EXP_SLTCTL_ABPE);
+    /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
+     * make the bit writable here in order to detect 1b is written.
+     * pcie_cap_slot_write_config() test-and-clear the bit, so
+     * this bit always returns 0 to the guest.
+     */
+    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_EIC);
+
+    pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
+                               PCI_EXP_HP_EV_SUPPORTED);
+
+    dev->exp.hpev_notified = false;
+
+    pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
+                    pcie_cap_slot_hotplug, &dev->qdev);
+}
+
+void pcie_cap_slot_reset(PCIDevice *dev)
+{
+    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+    PCIE_DEV_PRINTF(dev, "reset\n");
+
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+                                 PCI_EXP_SLTCTL_EIC |
+                                 PCI_EXP_SLTCTL_PIC |
+                                 PCI_EXP_SLTCTL_AIC |
+                                 PCI_EXP_SLTCTL_HPIE |
+                                 PCI_EXP_SLTCTL_CCIE |
+                                 PCI_EXP_SLTCTL_PDCE |
+                                 PCI_EXP_SLTCTL_ABPE);
+    pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC_OFF |
+                               PCI_EXP_SLTCTL_AIC_OFF);
+
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+                                 PCI_EXP_SLTSTA_EIS |/* on reset,
+                                                        the lock is released */
+                                 PCI_EXP_SLTSTA_CC |
+                                 PCI_EXP_SLTSTA_PDC |
+                                 PCI_EXP_SLTSTA_ABP);
+
+    hotplug_event_update_event_status(dev);
+}
+
+void pcie_cap_slot_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    uint8_t *exp_cap = dev->config + pos;
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
+        return;
+    }
+
+    if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+                                     PCI_EXP_SLTCTL_EIC)) {
+        sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
+        pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
+        PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
+                        "sltsta -> 0x%02"PRIx16"\n",
+                        sltsta);
+    }
+
+    hotplug_event_notify(dev);
+
+    /* 
+     * 6.7.3.2 Command Completed Events
+     *
+     * Software issues a command to a hot-plug capable Downstream Port by
+     * issuing a write transaction that targets any portion of the Port’s Slot
+     * Control register. A single write to the Slot Control register is
+     * considered to be a single command, even if the write affects more than
+     * one field in the Slot Control register. In response to this transaction,
+     * the Port must carry out the requested actions and then set the
+     * associated status field for the command completed event. */
+
+    /* Real hardware might take a while to complete requested command because
+     * physical movement would be involved like locking the electromechanical
+     * lock.  However in our case, command is completed instantaneously above,
+     * so send a command completion event right now.
+     */
+    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
+}
+
+int pcie_cap_slot_post_load(void *opaque, int version_id)
+{
+    PCIDevice *dev = opaque;
+    hotplug_event_update_event_status(dev);
+    return 0;
+}
+
+void pcie_cap_slot_push_attention_button(PCIDevice *dev)
+{
+    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
+}
+
+/* root control/capabilities/status. PME isn't emulated for now */
+void pcie_cap_root_init(PCIDevice *dev)
+{
+    pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
+                 PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
+                 PCI_EXP_RTCTL_SEFEE);
+}
+
+void pcie_cap_root_reset(PCIDevice *dev)
+{
+    pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
+}
+
+/* function level reset(FLR) */
+void pcie_cap_flr_init(PCIDevice *dev)
+{
+    pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
+                               PCI_EXP_DEVCAP_FLR);
+
+    /* Although reading BCR_FLR returns always 0,
+     * the bit is made writable here in order to detect the 1b is written
+     * pcie_cap_flr_write_config() test-and-clear the bit, so
+     * this bit always returns 0 to the guest.
+     */
+    pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
+                               PCI_EXP_DEVCTL_BCR_FLR);
+}
+
+void pcie_cap_flr_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int len)
+{
+    uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+    if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
+        /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
+           so the handler can detect FLR by looking at this bit. */
+        pci_device_reset(dev);
+        pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
+    }
+}
+
+/* Alternative Routing-ID Interpretation (ARI) */
+/* ari forwarding support for down stream port */
+void pcie_cap_ari_init(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
+                               PCI_EXP_DEVCAP2_ARI);
+    pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
+                               PCI_EXP_DEVCTL2_ARI);
+}
+
+void pcie_cap_ari_reset(PCIDevice *dev)
+{
+    uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
+    pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
+}
+
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev)
+{
+    if (!pci_is_express(dev)) {
+        return false;
+    }
+    if (!dev->exp.exp_cap) {
+        return false;
+    }
+
+    return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
+        PCI_EXP_DEVCTL2_ARI;
+}
+
+/**************************************************************************
+ * pci express extended capability allocation functions
+ * uint16_t ext_cap_id (16 bit)
+ * uint8_t cap_ver (4 bit)
+ * uint16_t cap_offset (12 bit)
+ * uint16_t ext_cap_size
+ */
+
+static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
+                                          uint16_t *prev_p)
+{
+    uint16_t prev = 0;
+    uint16_t next;
+    uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
+
+    if (!header) {
+        /* no extended capability */
+        next = 0;
+        goto out;
+    }
+    for (next = PCI_CONFIG_SPACE_SIZE; next;
+         prev = next, next = PCI_EXT_CAP_NEXT(header)) {
+
+        assert(next >= PCI_CONFIG_SPACE_SIZE);
+        assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
+
+        header = pci_get_long(dev->config + next);
+        if (PCI_EXT_CAP_ID(header) == cap_id) {
+            break;
+        }
+    }
+
+out:
+    if (prev_p) {
+        *prev_p = prev;
+    }
+    return next;
+}
+
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
+{
+    return pcie_find_capability_list(dev, cap_id, NULL);
+}
+
+static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next)
+{
+    uint16_t header = pci_get_long(dev->config + pos);
+    assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
+    header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
+        ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
+    pci_set_long(dev->config + pos, header);
+}
+
+/*
+ * caller must supply valid (offset, size) * such that the range shouldn't
+ * overlap with other capability or other registers.
+ * This function doesn't check it.
+ */
+void pcie_add_capability(PCIDevice *dev,
+                         uint16_t cap_id, uint8_t cap_ver,
+                         uint16_t offset, uint16_t size)
+{
+    uint32_t header;
+    uint16_t next;
+
+    assert(offset >= PCI_CONFIG_SPACE_SIZE);
+    assert(offset < offset + size);
+    assert(offset + size < PCIE_CONFIG_SPACE_SIZE);
+    assert(size >= 8);
+    assert(pci_is_express(dev));
+
+    if (offset == PCI_CONFIG_SPACE_SIZE) {
+        header = pci_get_long(dev->config + offset);
+        next = PCI_EXT_CAP_NEXT(header);
+    } else {
+        uint16_t prev;
+
+        /* 0 is reserved cap id. use internally to find the last capability
+           in the linked list */
+        next = pcie_find_capability_list(dev, 0, &prev);
+
+        assert(prev >= PCI_CONFIG_SPACE_SIZE);
+        assert(next == 0);
+        pcie_ext_cap_set_next(dev, prev, offset);
+    }
+    pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
+
+    /* Make capability read-only by default */
+    memset(dev->wmask + offset, 0, size);
+    memset(dev->w1cmask + offset, 0, size);
+    /* Check capability by default */
+    memset(dev->cmask + offset, 0xFF, size);
+}
+
+/**************************************************************************
+ * pci express extended capability helper functions
+ */
+
+/* ARI */
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
+{
+    pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
+                        offset, PCI_ARI_SIZEOF);
+    pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn));
+}
diff --git a/qemu-0.15.x/hw/pcie.h b/qemu-0.15.x/hw/pcie.h
new file mode 100644
index 0000000..a213fba
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie.h
@@ -0,0 +1,132 @@
+/*
+ * pcie.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_H
+#define QEMU_PCIE_H
+
+#include "hw.h"
+#include "pci_regs.h"
+#include "pcie_regs.h"
+#include "pcie_aer.h"
+
+typedef enum {
+    /* for attention and power indicator */
+    PCI_EXP_HP_IND_RESERVED     = PCI_EXP_SLTCTL_IND_RESERVED,
+    PCI_EXP_HP_IND_ON           = PCI_EXP_SLTCTL_IND_ON,
+    PCI_EXP_HP_IND_BLINK        = PCI_EXP_SLTCTL_IND_BLINK,
+    PCI_EXP_HP_IND_OFF          = PCI_EXP_SLTCTL_IND_OFF,
+} PCIExpressIndicator;
+
+typedef enum {
+    /* these bits must match the bits in Slot Control/Status registers.
+     * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
+     *
+     * Not all the bits of slot control register match with the ones of
+     * slot status. Not some bits of slot status register is used to
+     * show status, not to report event occurrence.
+     * So such bits must be masked out when checking the software
+     * notification condition.
+     */
+    PCI_EXP_HP_EV_ABP           = PCI_EXP_SLTCTL_ABPE,
+                                        /* attention button pressed */
+    PCI_EXP_HP_EV_PDC           = PCI_EXP_SLTCTL_PDCE,
+                                        /* presence detect changed */
+    PCI_EXP_HP_EV_CCI           = PCI_EXP_SLTCTL_CCIE,
+                                        /* command completed */
+
+    PCI_EXP_HP_EV_SUPPORTED     = PCI_EXP_HP_EV_ABP |
+                                  PCI_EXP_HP_EV_PDC |
+                                  PCI_EXP_HP_EV_CCI,
+                                                /* supported event mask  */
+
+    /* events not listed aren't supported */
+} PCIExpressHotPlugEvent;
+
+struct PCIExpressDevice {
+    /* Offset of express capability in config space */
+    uint8_t exp_cap;
+
+    /* SLOT */
+    unsigned int hpev_intx;     /* INTx for hot plug event (0-3:INT[A-D]#)
+                                 * default is 0 = INTA#
+                                 * If the chip wants to use other interrupt
+                                 * line, initialize this member with the
+                                 * desired number.
+                                 * If the chip dynamically changes this member,
+                                 * also initialize it when loaded as
+                                 * appropreately.
+                                 */
+    bool hpev_notified; /* Logical AND of conditions for hot plug event.
+                         Following 6.7.3.4:
+                         Software Notification of Hot-Plug Events, an interrupt
+                         is sent whenever the logical and of these conditions
+                         transitions from false to true. */
+
+    /* AER */
+    uint16_t aer_cap;
+    PCIEAERLog aer_log;
+    unsigned int aer_intx;      /* INTx for error reporting
+                                 * default is 0 = INTA#
+                                 * If the chip wants to use other interrupt
+                                 * line, initialize this member with the
+                                 * desired number.
+                                 * If the chip dynamically changes this member,
+                                 * also initialize it when loaded as
+                                 * appropreately.
+                                 */
+};
+
+/* PCI express capability helper functions */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+void pcie_cap_exit(PCIDevice *dev);
+uint8_t pcie_cap_get_type(const PCIDevice *dev);
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
+
+void pcie_cap_deverr_init(PCIDevice *dev);
+void pcie_cap_deverr_reset(PCIDevice *dev);
+
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
+void pcie_cap_slot_reset(PCIDevice *dev);
+void pcie_cap_slot_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len);
+int pcie_cap_slot_post_load(void *opaque, int version_id);
+void pcie_cap_slot_push_attention_button(PCIDevice *dev);
+
+void pcie_cap_root_init(PCIDevice *dev);
+void pcie_cap_root_reset(PCIDevice *dev);
+
+void pcie_cap_flr_init(PCIDevice *dev);
+void pcie_cap_flr_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len);
+
+void pcie_cap_ari_init(PCIDevice *dev);
+void pcie_cap_ari_reset(PCIDevice *dev);
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
+
+/* PCI express extended capability helper functions */
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
+void pcie_add_capability(PCIDevice *dev,
+                         uint16_t cap_id, uint8_t cap_ver,
+                         uint16_t offset, uint16_t size);
+
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
+
+#endif /* QEMU_PCIE_H */
diff --git a/qemu-0.15.x/hw/pcie_aer.c b/qemu-0.15.x/hw/pcie_aer.c
new file mode 100644
index 0000000..be019c7
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_aer.c
@@ -0,0 +1,1026 @@
+/*
+ * pcie_aer.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu.h"
+#include "qemu-objects.h"
+#include "monitor.h"
+#include "pci_bridge.h"
+#include "pcie.h"
+#include "msix.h"
+#include "msi.h"
+#include "pci_internals.h"
+#include "pcie_regs.h"
+
+//#define DEBUG_PCIE
+#ifdef DEBUG_PCIE
+# define PCIE_DPRINTF(fmt, ...)                                         \
+    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define PCIE_DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
+    PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+#define PCI_ERR_SRC_COR_OFFS    0
+#define PCI_ERR_SRC_UNCOR_OFFS  2
+
+/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
+static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
+{
+    switch (status) {
+    case PCI_ERR_UNC_INTN:
+    case PCI_ERR_UNC_DLP:
+    case PCI_ERR_UNC_SDN:
+    case PCI_ERR_UNC_RX_OVER:
+    case PCI_ERR_UNC_FCP:
+    case PCI_ERR_UNC_MALF_TLP:
+        return PCI_ERR_ROOT_CMD_FATAL_EN;
+    case PCI_ERR_UNC_POISON_TLP:
+    case PCI_ERR_UNC_ECRC:
+    case PCI_ERR_UNC_UNSUP:
+    case PCI_ERR_UNC_COMP_TIME:
+    case PCI_ERR_UNC_COMP_ABORT:
+    case PCI_ERR_UNC_UNX_COMP:
+    case PCI_ERR_UNC_ACSV:
+    case PCI_ERR_UNC_MCBTLP:
+    case PCI_ERR_UNC_ATOP_EBLOCKED:
+    case PCI_ERR_UNC_TLP_PRF_BLOCKED:
+        return PCI_ERR_ROOT_CMD_NONFATAL_EN;
+    default:
+        abort();
+        break;
+    }
+    return PCI_ERR_ROOT_CMD_FATAL_EN;
+}
+
+static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err)
+{
+    if (aer_log->log_num == aer_log->log_max) {
+        return -1;
+    }
+    memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err);
+    aer_log->log_num++;
+    return 0;
+}
+
+static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err)
+{
+    assert(aer_log->log_num);
+    *err = aer_log->log[0];
+    aer_log->log_num--;
+    memmove(&aer_log->log[0], &aer_log->log[1],
+            aer_log->log_num * sizeof *err);
+}
+
+static void aer_log_clear_all_err(PCIEAERLog *aer_log)
+{
+    aer_log->log_num = 0;
+}
+
+int pcie_aer_init(PCIDevice *dev, uint16_t offset)
+{
+    PCIExpressDevice *exp;
+
+    pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
+                        offset, PCI_ERR_SIZEOF);
+    exp = &dev->exp;
+    exp->aer_cap = offset;
+
+    /* log_max is property */
+    if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
+        dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
+    }
+    /* clip down the value to avoid unreasobale memory usage */
+    if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
+        return -EINVAL;
+    }
+    dev->exp.aer_log.log = qemu_mallocz(sizeof dev->exp.aer_log.log[0] *
+                                        dev->exp.aer_log.log_max);
+
+    pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
+                 PCI_ERR_UNC_SUPPORTED);
+
+    pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
+                 PCI_ERR_UNC_SEVERITY_DEFAULT);
+    pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
+                 PCI_ERR_UNC_SUPPORTED);
+
+    pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
+                               PCI_ERR_COR_STATUS);
+
+    pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
+                 PCI_ERR_COR_MASK_DEFAULT);
+    pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
+                 PCI_ERR_COR_SUPPORTED);
+
+    /* capabilities and control. multiple header logging is supported */
+    if (dev->exp.aer_log.log_max > 0) {
+        pci_set_long(dev->config + offset + PCI_ERR_CAP,
+                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
+                     PCI_ERR_CAP_MHRC);
+        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
+                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
+                     PCI_ERR_CAP_MHRE);
+    } else {
+        pci_set_long(dev->config + offset + PCI_ERR_CAP,
+                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
+        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
+                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
+    }
+
+    switch (pcie_cap_get_type(dev)) {
+    case PCI_EXP_TYPE_ROOT_PORT:
+        /* this case will be set by pcie_aer_root_init() */
+        /* fallthrough */
+    case PCI_EXP_TYPE_DOWNSTREAM:
+    case PCI_EXP_TYPE_UPSTREAM:
+        pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
+                                   PCI_BRIDGE_CTL_SERR);
+        pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
+                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return 0;
+}
+
+void pcie_aer_exit(PCIDevice *dev)
+{
+    qemu_free(dev->exp.aer_log.log);
+}
+
+static void pcie_aer_update_uncor_status(PCIDevice *dev)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    PCIEAERLog *aer_log = &dev->exp.aer_log;
+
+    uint16_t i;
+    for (i = 0; i < aer_log->log_num; i++) {
+        pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS,
+                                   dev->exp.aer_log.log[i].status);
+    }
+}
+
+/*
+ * return value:
+ * true: error message needs to be sent up
+ * false: error message is masked
+ *
+ * 6.2.6 Error Message Control
+ * Figure 6-3
+ * all pci express devices part
+ */
+static bool
+pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
+{
+    if (!(pcie_aer_msg_is_uncor(msg) &&
+          (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
+        return false;
+    }
+
+    /* Signaled System Error
+     *
+     * 7.5.1.1 Command register
+     * Bit 8 SERR# Enable
+     *
+     * When Set, this bit enables reporting of Non-fatal and Fatal
+     * errors detected by the Function to the Root Complex. Note that
+     * errors are reported if enabled either through this bit or through
+     * the PCI Express specific bits in the Device Control register (see
+     * Section 7.8.4).
+     */
+    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
+                               PCI_STATUS_SIG_SYSTEM_ERROR);
+
+    if (!(msg->severity &
+          pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
+        return false;
+    }
+
+    /* send up error message */
+    return true;
+}
+
+/*
+ * return value:
+ * true: error message is sent up
+ * false: error message is masked
+ *
+ * 6.2.6 Error Message Control
+ * Figure 6-3
+ * virtual pci bridge part
+ */
+static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
+{
+    uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);
+
+    if (pcie_aer_msg_is_uncor(msg)) {
+        /* Received System Error */
+        pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
+                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
+    }
+
+    if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
+        return false;
+    }
+    return true;
+}
+
+void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    assert(vector < PCI_ERR_ROOT_IRQ_MAX);
+    pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS,
+                                 PCI_ERR_ROOT_IRQ);
+    pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS,
+                               vector << PCI_ERR_ROOT_IRQ_SHIFT);
+}
+
+static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+    return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
+}
+
+/* Given a status register, get corresponding bits in the command register */
+static uint32_t pcie_aer_status_to_cmd(uint32_t status)
+{
+    uint32_t cmd = 0;
+    if (status & PCI_ERR_ROOT_COR_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_COR_EN;
+    }
+    if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
+    }
+    if (status & PCI_ERR_ROOT_FATAL_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
+    }
+    return cmd;
+}
+
+static void pcie_aer_root_notify(PCIDevice *dev)
+{
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_aer_root_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_aer_root_get_vector(dev));
+    } else {
+        qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
+    }
+}
+
+/*
+ * 6.2.6 Error Message Control
+ * Figure 6-3
+ * root port part
+ */
+static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
+{
+    uint16_t cmd;
+    uint8_t *aer_cap;
+    uint32_t root_cmd;
+    uint32_t root_status, prev_status;
+
+    cmd = pci_get_word(dev->config + PCI_COMMAND);
+    aer_cap = dev->config + dev->exp.aer_cap;
+    root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
+    prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+
+    if (cmd & PCI_COMMAND_SERR) {
+        /* System Error.
+         *
+         * The way to report System Error is platform specific and
+         * it isn't implemented in qemu right now.
+         * So just discard the error for now.
+         * OS which cares of aer would receive errors via
+         * native aer mechanims, so this wouldn't matter.
+         */
+    }
+
+    /* Errro Message Received: Root Error Status register */
+    switch (msg->severity) {
+    case PCI_ERR_ROOT_CMD_COR_EN:
+        if (root_status & PCI_ERR_ROOT_COR_RCV) {
+            root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
+        } else {
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS,
+                         msg->source_id);
+        }
+        root_status |= PCI_ERR_ROOT_COR_RCV;
+        break;
+    case PCI_ERR_ROOT_CMD_NONFATAL_EN:
+        root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
+        break;
+    case PCI_ERR_ROOT_CMD_FATAL_EN:
+        if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
+            root_status |= PCI_ERR_ROOT_FIRST_FATAL;
+        }
+        root_status |= PCI_ERR_ROOT_FATAL_RCV;
+        break;
+    default:
+        abort();
+        break;
+    }
+    if (pcie_aer_msg_is_uncor(msg)) {
+        if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
+            root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
+        } else {
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
+                         PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
+        }
+        root_status |= PCI_ERR_ROOT_UNCOR_RCV;
+    }
+    pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
+
+    /* 6.2.4.1.2 Interrupt Generation */
+    /* All the above did was set some bits in the status register.
+     * Specifically these that match message severity.
+     * The below code relies on this fact. */
+    if (!(root_cmd & msg->severity) ||
+        (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
+        /* Condition is not being set or was already true so nothing to do. */
+        return;
+    }
+
+    pcie_aer_root_notify(dev);
+}
+
+/*
+ * 6.2.6 Error Message Control Figure 6-3
+ *
+ * Walk up the bus tree from the device, propagate the error message.
+ */
+static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
+{
+    uint8_t type;
+
+    while (dev) {
+        if (!pci_is_express(dev)) {
+            /* just ignore it */
+            /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
+             * Consider e.g. a PCI bridge above a PCI Express device. */
+            return;
+        }
+
+        type = pcie_cap_get_type(dev);
+        if ((type == PCI_EXP_TYPE_ROOT_PORT ||
+            type == PCI_EXP_TYPE_UPSTREAM ||
+            type == PCI_EXP_TYPE_DOWNSTREAM) &&
+            !pcie_aer_msg_vbridge(dev, msg)) {
+                return;
+        }
+        if (!pcie_aer_msg_alldev(dev, msg)) {
+            return;
+        }
+        if (type == PCI_EXP_TYPE_ROOT_PORT) {
+            pcie_aer_msg_root_port(dev, msg);
+            /* Root port can notify system itself,
+               or send the error message to root complex event collector. */
+            /*
+             * if root port is associated with an event collector,
+             * return the root complex event collector here.
+             * For now root complex event collector isn't supported.
+             */
+            return;
+        }
+        dev = pci_bridge_get_device(dev->bus);
+    }
+}
+
+static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint8_t first_bit = ffs(err->status) - 1;
+    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
+    int i;
+
+    assert(err->status);
+    assert(err->status & (err->status - 1));
+
+    errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
+    errcap |= PCI_ERR_CAP_FEP(first_bit);
+
+    if (err->flags & PCIE_AER_ERR_HEADER_VALID) {
+        for (i = 0; i < ARRAY_SIZE(err->header); ++i) {
+            /* 7.10.8 Header Log Register */
+            uint8_t *header_log =
+                aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0];
+            cpu_to_be32wu((uint32_t*)header_log, err->header[i]);
+        }
+    } else {
+        assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT));
+        memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
+    }
+
+    if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
+        (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
+         PCI_EXP_DEVCAP2_EETLPP)) {
+        for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
+            /* 7.10.12 tlp prefix log register */
+            uint8_t *prefix_log =
+                aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0];
+            cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]);
+        }
+        errcap |= PCI_ERR_CAP_TLP;
+    } else {
+        memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0,
+               PCI_ERR_TLP_PREFIX_LOG_SIZE);
+    }
+    pci_set_long(aer_cap + PCI_ERR_CAP, errcap);
+}
+
+static void pcie_aer_clear_log(PCIDevice *dev)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+
+    pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP,
+                                 PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
+
+    memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE);
+    memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE);
+}
+
+static void pcie_aer_clear_error(PCIDevice *dev)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
+    PCIEAERLog *aer_log = &dev->exp.aer_log;
+    PCIEAERErr err;
+
+    if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) {
+        pcie_aer_clear_log(dev);
+        return;
+    }
+
+    /*
+     * If more errors are queued, set corresponding bits in uncorrectable
+     * error status.
+     * We emulate uncorrectable error status register as W1CS.
+     * So set bit in uncorrectable error status here again for multiple
+     * error recording support.
+     *
+     * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability)
+     */
+    pcie_aer_update_uncor_status(dev);
+
+    aer_log_del_err(aer_log, &err);
+    pcie_aer_update_log(dev, &err);
+}
+
+static int pcie_aer_record_error(PCIDevice *dev,
+                                 const PCIEAERErr *err)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
+    int fep = PCI_ERR_CAP_FEP(errcap);
+
+    assert(err->status);
+    assert(err->status & (err->status - 1));
+
+    if (errcap & PCI_ERR_CAP_MHRE &&
+        (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
+        /*  Not first error. queue error */
+        if (aer_log_add_err(&dev->exp.aer_log, err) < 0) {
+            /* overflow */
+            return -1;
+        }
+        return 0;
+    }
+
+    pcie_aer_update_log(dev, err);
+    return 0;
+}
+
+typedef struct PCIEAERInject {
+    PCIDevice *dev;
+    uint8_t *aer_cap;
+    const PCIEAERErr *err;
+    uint16_t devctl;
+    uint16_t devsta;
+    uint32_t error_status;
+    bool unsupported_request;
+    bool log_overflow;
+    PCIEAERMsg msg;
+} PCIEAERInject;
+
+static bool pcie_aer_inject_cor_error(PCIEAERInject *inj,
+                                      uint32_t uncor_status,
+                                      bool is_advisory_nonfatal)
+{
+    PCIDevice *dev = inj->dev;
+
+    inj->devsta |= PCI_EXP_DEVSTA_CED;
+    if (inj->unsupported_request) {
+        inj->devsta |= PCI_EXP_DEVSTA_URD;
+    }
+    pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
+
+    if (inj->aer_cap) {
+        uint32_t mask;
+        pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS,
+                                   inj->error_status);
+        mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK);
+        if (mask & inj->error_status) {
+            return false;
+        }
+        if (is_advisory_nonfatal) {
+            uint32_t uncor_mask =
+                pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
+            if (!(uncor_mask & uncor_status)) {
+                inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
+            }
+            pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
+                                       uncor_status);
+        }
+    }
+
+    if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) {
+        return false;
+    }
+    if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) {
+        return false;
+    }
+
+    inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN;
+    return true;
+}
+
+static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
+{
+    PCIDevice *dev = inj->dev;
+    uint16_t cmd;
+
+    if (is_fatal) {
+        inj->devsta |= PCI_EXP_DEVSTA_FED;
+    } else {
+        inj->devsta |= PCI_EXP_DEVSTA_NFED;
+    }
+    if (inj->unsupported_request) {
+        inj->devsta |= PCI_EXP_DEVSTA_URD;
+    }
+    pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta);
+
+    if (inj->aer_cap) {
+        uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK);
+        if (mask & inj->error_status) {
+            pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
+                                       inj->error_status);
+            return false;
+        }
+
+        inj->log_overflow = !!pcie_aer_record_error(dev, inj->err);
+        pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS,
+                                   inj->error_status);
+    }
+
+    cmd = pci_get_word(dev->config + PCI_COMMAND);
+    if (inj->unsupported_request &&
+        !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) {
+        return false;
+    }
+    if (is_fatal) {
+        if (!((cmd & PCI_COMMAND_SERR) ||
+              (inj->devctl & PCI_EXP_DEVCTL_FERE))) {
+            return false;
+        }
+        inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN;
+    } else {
+        if (!((cmd & PCI_COMMAND_SERR) ||
+              (inj->devctl & PCI_EXP_DEVCTL_NFERE))) {
+            return false;
+        }
+        inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN;
+    }
+    return true;
+}
+
+/*
+ * non-Function specific error must be recorded in all functions.
+ * It is the responsibility of the caller of this function.
+ * It is also caller's responsibility to determine which function should
+ * report the rerror.
+ *
+ * 6.2.4 Error Logging
+ * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations
+ * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging
+ *            Operations
+ */
+int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
+{
+    uint8_t *aer_cap = NULL;
+    uint16_t devctl = 0;
+    uint16_t devsta = 0;
+    uint32_t error_status = err->status;
+    PCIEAERInject inj;
+
+    if (!pci_is_express(dev)) {
+        return -ENOSYS;
+    }
+
+    if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
+        error_status &= PCI_ERR_COR_SUPPORTED;
+    } else {
+        error_status &= PCI_ERR_UNC_SUPPORTED;
+    }
+
+    /* invalid status bit. one and only one bit must be set */
+    if (!error_status || (error_status & (error_status - 1))) {
+        return -EINVAL;
+    }
+
+    if (dev->exp.aer_cap) {
+        uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+        aer_cap = dev->config + dev->exp.aer_cap;
+        devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL);
+        devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA);
+    }
+
+    inj.dev = dev;
+    inj.aer_cap = aer_cap;
+    inj.err = err;
+    inj.devctl = devctl;
+    inj.devsta = devsta;
+    inj.error_status = error_status;
+    inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) &&
+        err->status == PCI_ERR_UNC_UNSUP;
+    inj.log_overflow = false;
+
+    if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) {
+        if (!pcie_aer_inject_cor_error(&inj, 0, false)) {
+            return 0;
+        }
+    } else {
+        bool is_fatal =
+            pcie_aer_uncor_default_severity(error_status) ==
+            PCI_ERR_ROOT_CMD_FATAL_EN;
+        if (aer_cap) {
+            is_fatal =
+                error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER);
+        }
+        if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) {
+            inj.error_status = PCI_ERR_COR_ADV_NONFATAL;
+            if (!pcie_aer_inject_cor_error(&inj, error_status, true)) {
+                return 0;
+            }
+        } else {
+            if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) {
+                return 0;
+            }
+        }
+    }
+
+    /* send up error message */
+    inj.msg.source_id = err->source_id;
+    pcie_aer_msg(dev, &inj.msg);
+
+    if (inj.log_overflow) {
+        PCIEAERErr header_log_overflow = {
+            .status = PCI_ERR_COR_HL_OVERFLOW,
+            .flags = PCIE_AER_ERR_IS_CORRECTABLE,
+        };
+        int ret = pcie_aer_inject_error(dev, &header_log_overflow);
+        assert(!ret);
+    }
+    return 0;
+}
+
+void pcie_aer_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP);
+    uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap);
+    uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS);
+
+    /* uncorrectable error */
+    if (!(uncorsta & first_error)) {
+        /* the bit that corresponds to the first error is cleared */
+        pcie_aer_clear_error(dev);
+    } else if (errcap & PCI_ERR_CAP_MHRE) {
+        /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared
+         * nothing should happen. So we have to revert the modification to
+         * the register.
+         */
+        pcie_aer_update_uncor_status(dev);
+    } else {
+        /* capability & control
+         * PCI_ERR_CAP_MHRE might be cleared, so clear of header log.
+         */
+        aer_log_clear_all_err(&dev->exp.aer_log);
+    }
+}
+
+void pcie_aer_root_init(PCIDevice *dev)
+{
+    uint16_t pos = dev->exp.aer_cap;
+
+    pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND,
+                 PCI_ERR_ROOT_CMD_EN_MASK);
+    pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
+                 PCI_ERR_ROOT_STATUS_REPORT_MASK);
+}
+
+void pcie_aer_root_reset(PCIDevice *dev)
+{
+    uint8_t* aer_cap = dev->config + dev->exp.aer_cap;
+
+    pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0);
+
+    /*
+     * Advanced Error Interrupt Message Number in Root Error Status Register
+     * must be updated by chip dependent code because it's chip dependent
+     * which number is used.
+     */
+}
+
+void pcie_aer_root_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len,
+                                uint32_t root_cmd_prev)
+{
+    uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
+    uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+    uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
+    uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
+    /* 6.2.4.1.2 Interrupt Generation */
+    if (!msix_enabled(dev) && !msi_enabled(dev)) {
+        qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd));
+        return;
+    }
+
+    if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
+        /* Send MSI on transition from false to true. */
+        return;
+    }
+
+    pcie_aer_root_notify(dev);
+}
+
+static const VMStateDescription vmstate_pcie_aer_err = {
+    .name = "PCIE_AER_ERROR",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields     = (VMStateField[]) {
+        VMSTATE_UINT32(status, PCIEAERErr),
+        VMSTATE_UINT16(source_id, PCIEAERErr),
+        VMSTATE_UINT16(flags, PCIEAERErr),
+        VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4),
+        VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_pcie_aer_log = {
+    .name = "PCIE_AER_ERROR_LOG",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields     = (VMStateField[]) {
+        VMSTATE_UINT16(log_num, PCIEAERLog),
+        VMSTATE_UINT16(log_max, PCIEAERLog),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
+                              vmstate_pcie_aer_err, PCIEAERErr),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+    int devfn;
+    assert(qobject_type(data) == QTYPE_QDICT);
+    qdict = qobject_to_qdict(data);
+
+    devfn = (int)qdict_get_int(qdict, "devfn");
+    monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n",
+                   qdict_get_str(qdict, "id"),
+                   (int) qdict_get_int(qdict, "domain"),
+                   (int) qdict_get_int(qdict, "bus"),
+                   PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
+
+typedef struct PCIEAERErrorName {
+    const char *name;
+    uint32_t val;
+    bool correctable;
+} PCIEAERErrorName;
+
+/*
+ * AER error name -> value convertion table
+ * This naming scheme is same to linux aer-injection tool.
+ */
+static const struct PCIEAERErrorName pcie_aer_error_list[] = {
+    {
+        .name = "TRAIN",
+        .val = PCI_ERR_UNC_TRAIN,
+        .correctable = false,
+    }, {
+        .name = "DLP",
+        .val = PCI_ERR_UNC_DLP,
+        .correctable = false,
+    }, {
+        .name = "SDN",
+        .val = PCI_ERR_UNC_SDN,
+        .correctable = false,
+    }, {
+        .name = "POISON_TLP",
+        .val = PCI_ERR_UNC_POISON_TLP,
+        .correctable = false,
+    }, {
+        .name = "FCP",
+        .val = PCI_ERR_UNC_FCP,
+        .correctable = false,
+    }, {
+        .name = "COMP_TIME",
+        .val = PCI_ERR_UNC_COMP_TIME,
+        .correctable = false,
+    }, {
+        .name = "COMP_ABORT",
+        .val = PCI_ERR_UNC_COMP_ABORT,
+        .correctable = false,
+    }, {
+        .name = "UNX_COMP",
+        .val = PCI_ERR_UNC_UNX_COMP,
+        .correctable = false,
+    }, {
+        .name = "RX_OVER",
+        .val = PCI_ERR_UNC_RX_OVER,
+        .correctable = false,
+    }, {
+        .name = "MALF_TLP",
+        .val = PCI_ERR_UNC_MALF_TLP,
+        .correctable = false,
+    }, {
+        .name = "ECRC",
+        .val = PCI_ERR_UNC_ECRC,
+        .correctable = false,
+    }, {
+        .name = "UNSUP",
+        .val = PCI_ERR_UNC_UNSUP,
+        .correctable = false,
+    }, {
+        .name = "ACSV",
+        .val = PCI_ERR_UNC_ACSV,
+        .correctable = false,
+    }, {
+        .name = "INTN",
+        .val = PCI_ERR_UNC_INTN,
+        .correctable = false,
+    }, {
+        .name = "MCBTLP",
+        .val = PCI_ERR_UNC_MCBTLP,
+        .correctable = false,
+    }, {
+        .name = "ATOP_EBLOCKED",
+        .val = PCI_ERR_UNC_ATOP_EBLOCKED,
+        .correctable = false,
+    }, {
+        .name = "TLP_PRF_BLOCKED",
+        .val = PCI_ERR_UNC_TLP_PRF_BLOCKED,
+        .correctable = false,
+    }, {
+        .name = "RCVR",
+        .val = PCI_ERR_COR_RCVR,
+        .correctable = true,
+    }, {
+        .name = "BAD_TLP",
+        .val = PCI_ERR_COR_BAD_TLP,
+        .correctable = true,
+    }, {
+        .name = "BAD_DLLP",
+        .val = PCI_ERR_COR_BAD_DLLP,
+        .correctable = true,
+    }, {
+        .name = "REP_ROLL",
+        .val = PCI_ERR_COR_REP_ROLL,
+        .correctable = true,
+    }, {
+        .name = "REP_TIMER",
+        .val = PCI_ERR_COR_REP_TIMER,
+        .correctable = true,
+    }, {
+        .name = "ADV_NONFATAL",
+        .val = PCI_ERR_COR_ADV_NONFATAL,
+        .correctable = true,
+    }, {
+        .name = "INTERNAL",
+        .val = PCI_ERR_COR_INTERNAL,
+        .correctable = true,
+    }, {
+        .name = "HL_OVERFLOW",
+        .val = PCI_ERR_COR_HL_OVERFLOW,
+        .correctable = true,
+    },
+};
+
+static int pcie_aer_parse_error_string(const char *error_name,
+                                       uint32_t *status, bool *correctable)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(pcie_aer_error_list); i++) {
+        const  PCIEAERErrorName *e = &pcie_aer_error_list[i];
+        if (strcmp(error_name, e->name)) {
+            continue;
+        }
+
+        *status = e->val;
+        *correctable = e->correctable;
+        return 0;
+    }
+    return -EINVAL;
+}
+
+int do_pcie_aer_inejct_error(Monitor *mon,
+                             const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    const char *error_name;
+    uint32_t error_status;
+    bool correctable;
+    PCIDevice *dev;
+    PCIEAERErr err;
+    int ret;
+
+    ret = pci_qdev_find_device(id, &dev);
+    if (ret < 0) {
+        monitor_printf(mon,
+                       "id or pci device path is invalid or device not "
+                       "found. %s\n", id);
+        return ret;
+    }
+    if (!pci_is_express(dev)) {
+        monitor_printf(mon, "the device doesn't support pci express. %s\n",
+                       id);
+        return -ENOSYS;
+    }
+
+    error_name = qdict_get_str(qdict, "error_status");
+    if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) {
+        char *e = NULL;
+        error_status = strtoul(error_name, &e, 0);
+        correctable = !!qdict_get_int(qdict, "correctable");
+        if (!e || *e != '\0') {
+            monitor_printf(mon, "invalid error status value. \"%s\"",
+                           error_name);
+            return -EINVAL;
+        }
+    }
+    err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
+
+    err.flags = 0;
+    if (correctable) {
+        err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
+    }
+    if (qdict_get_int(qdict, "advisory_non_fatal")) {
+        err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
+    }
+    if (qdict_haskey(qdict, "header0")) {
+        err.flags |= PCIE_AER_ERR_HEADER_VALID;
+    }
+    if (qdict_haskey(qdict, "prefix0")) {
+        err.flags |= PCIE_AER_ERR_TLP_PREFIX_PRESENT;
+    }
+
+    err.header[0] = qdict_get_try_int(qdict, "header0", 0);
+    err.header[1] = qdict_get_try_int(qdict, "header1", 0);
+    err.header[2] = qdict_get_try_int(qdict, "header2", 0);
+    err.header[3] = qdict_get_try_int(qdict, "header3", 0);
+
+    err.prefix[0] = qdict_get_try_int(qdict, "prefix0", 0);
+    err.prefix[1] = qdict_get_try_int(qdict, "prefix1", 0);
+    err.prefix[2] = qdict_get_try_int(qdict, "prefix2", 0);
+    err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
+
+    ret = pcie_aer_inject_error(dev, &err);
+    *ret_data = qobject_from_jsonf("{'id': %s, "
+                                   "'domain': %d, 'bus': %d, 'devfn': %d, "
+                                   "'ret': %d}",
+                                   id,
+                                   pci_find_domain(dev->bus),
+                                   pci_bus_num(dev->bus), dev->devfn,
+                                   ret);
+    assert(*ret_data);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/pcie_aer.h b/qemu-0.15.x/hw/pcie_aer.h
new file mode 100644
index 0000000..7539500
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_aer.h
@@ -0,0 +1,106 @@
+/*
+ * pcie_aer.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_AER_H
+#define QEMU_PCIE_AER_H
+
+#include "hw.h"
+
+/* definitions which PCIExpressDevice uses */
+
+/* AER log */
+struct PCIEAERLog {
+    /* This structure is saved/loaded.
+       So explicitly size them instead of unsigned int */
+
+    /* the number of currently recorded log in log member */
+    uint16_t log_num;
+
+    /*
+     * The maximum number of the log. Errors can be logged up to this.
+     *
+     * This is configurable property.
+     * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT
+     * to avoid unreasonable memory usage.
+     * I bet that 128 log size would be big enough, otherwise too many errors
+     * for system to function normaly. But could consecutive errors occur?
+     */
+#define PCIE_AER_LOG_MAX_DEFAULT        8
+#define PCIE_AER_LOG_MAX_LIMIT          128
+#define PCIE_AER_LOG_MAX_UNSET          0xffff
+    uint16_t log_max;
+
+    /* Error log. log_max-sized array */
+    PCIEAERErr *log;
+};
+
+/* aer error message: error signaling message has only error sevirity and
+   source id. See 2.2.8.3 error signaling messages */
+struct PCIEAERMsg {
+    /*
+     * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN
+     * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE}
+     */
+    uint32_t severity;
+
+    uint16_t source_id; /* bdf */
+};
+
+static inline bool
+pcie_aer_msg_is_uncor(const PCIEAERMsg *msg)
+{
+    return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN ||
+        msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN;
+}
+
+/* error */
+struct PCIEAERErr {
+    uint32_t status;    /* error status bits */
+    uint16_t source_id; /* bdf */
+
+#define PCIE_AER_ERR_IS_CORRECTABLE     0x1     /* correctable/uncorrectable */
+#define PCIE_AER_ERR_MAYBE_ADVISORY     0x2     /* maybe advisory non-fatal */
+#define PCIE_AER_ERR_HEADER_VALID       0x4     /* TLP header is logged */
+#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8     /* TLP Prefix is logged */
+    uint16_t flags;
+
+    uint32_t header[4]; /* TLP header */
+    uint32_t prefix[4]; /* TLP header prefix */
+};
+
+extern const VMStateDescription vmstate_pcie_aer_log;
+
+int pcie_aer_init(PCIDevice *dev, uint16_t offset);
+void pcie_aer_exit(PCIDevice *dev);
+void pcie_aer_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len);
+
+/* aer root port */
+void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector);
+void pcie_aer_root_init(PCIDevice *dev);
+void pcie_aer_root_reset(PCIDevice *dev);
+void pcie_aer_root_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len,
+                                uint32_t root_cmd_prev);
+
+/* error injection */
+int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
+
+#endif /* QEMU_PCIE_AER_H */
diff --git a/qemu-0.15.x/hw/pcie_host.c b/qemu-0.15.x/hw/pcie_host.c
new file mode 100644
index 0000000..b749865
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_host.c
@@ -0,0 +1,176 @@
+/*
+ * pcie_host.c
+ * utility functions for pci express host bridge.
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "pcie_host.h"
+
+/*
+ * PCI express mmcfig address
+ * bit 20 - 28: bus number
+ * bit 15 - 19: device number
+ * bit 12 - 14: function number
+ * bit  0 - 11: offset in configuration space of a given device
+ */
+#define PCIE_MMCFG_SIZE_MAX             (1ULL << 28)
+#define PCIE_MMCFG_SIZE_MIN             (1ULL << 20)
+#define PCIE_MMCFG_BUS_BIT              20
+#define PCIE_MMCFG_BUS_MASK             0x1ff
+#define PCIE_MMCFG_DEVFN_BIT            12
+#define PCIE_MMCFG_DEVFN_MASK           0xff
+#define PCIE_MMCFG_CONFOFFSET_MASK      0xfff
+#define PCIE_MMCFG_BUS(addr)            (((addr) >> PCIE_MMCFG_BUS_BIT) & \
+                                         PCIE_MMCFG_BUS_MASK)
+#define PCIE_MMCFG_DEVFN(addr)          (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \
+                                         PCIE_MMCFG_DEVFN_MASK)
+#define PCIE_MMCFG_CONFOFFSET(addr)     ((addr) & PCIE_MMCFG_CONFOFFSET_MASK)
+
+
+/* a helper function to get a PCIDevice for a given mmconfig address */
+static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
+                                                     uint32_t mmcfg_addr)
+{
+    return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
+                           PCIE_MMCFG_DEVFN(mmcfg_addr));
+}
+
+static void pcie_mmcfg_data_write(PCIBus *s,
+                                  uint32_t mmcfg_addr, uint32_t val, int len)
+{
+    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
+
+    if (!pci_dev)
+        return;
+
+    pci_dev->config_write(pci_dev,
+                          PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len);
+}
+
+static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len)
+{
+    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr);
+
+    assert(len == 1 || len == 2 || len == 4);
+    if (!pci_dev) {
+        return ~0x0;
+    }
+    return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len);
+}
+
+static void pcie_mmcfg_data_writeb(void *opaque,
+                                   target_phys_addr_t addr, uint32_t value)
+{
+    PCIExpressHost *e = opaque;
+    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1);
+}
+
+static void pcie_mmcfg_data_writew(void *opaque,
+                                   target_phys_addr_t addr, uint32_t value)
+{
+    PCIExpressHost *e = opaque;
+    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2);
+}
+
+static void pcie_mmcfg_data_writel(void *opaque,
+                                   target_phys_addr_t addr, uint32_t value)
+{
+    PCIExpressHost *e = opaque;
+    pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4);
+}
+
+static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCIExpressHost *e = opaque;
+    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1);
+}
+
+static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCIExpressHost *e = opaque;
+    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2);
+}
+
+static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIExpressHost *e = opaque;
+    return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4);
+}
+
+
+static CPUWriteMemoryFunc * const pcie_mmcfg_write[] =
+{
+    pcie_mmcfg_data_writeb,
+    pcie_mmcfg_data_writew,
+    pcie_mmcfg_data_writel,
+};
+
+static CPUReadMemoryFunc * const pcie_mmcfg_read[] =
+{
+    pcie_mmcfg_data_readb,
+    pcie_mmcfg_data_readw,
+    pcie_mmcfg_data_readl,
+};
+
+/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
+#define PCIE_BASE_ADDR_UNMAPPED  ((target_phys_addr_t)-1ULL)
+
+int pcie_host_init(PCIExpressHost *e)
+{
+    e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
+    e->mmio_index =
+        cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e,
+                               DEVICE_NATIVE_ENDIAN);
+    if (e->mmio_index < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void pcie_host_mmcfg_unmap(PCIExpressHost *e)
+{
+    if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
+        cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED);
+        e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
+    }
+}
+
+void pcie_host_mmcfg_map(PCIExpressHost *e,
+                         target_phys_addr_t addr, uint32_t size)
+{
+    assert(!(size & (size - 1)));       /* power of 2 */
+    assert(size >= PCIE_MMCFG_SIZE_MIN);
+    assert(size <= PCIE_MMCFG_SIZE_MAX);
+
+    e->base_addr = addr;
+    e->size = size;
+    cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index);
+}
+
+void pcie_host_mmcfg_update(PCIExpressHost *e,
+                            int enable,
+                            target_phys_addr_t addr, uint32_t size)
+{
+    pcie_host_mmcfg_unmap(e);
+    if (enable) {
+        pcie_host_mmcfg_map(e, addr, size);
+    }
+}
diff --git a/qemu-0.15.x/hw/pcie_host.h b/qemu-0.15.x/hw/pcie_host.h
new file mode 100644
index 0000000..a202661
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_host.h
@@ -0,0 +1,49 @@
+/*
+ * pcie_host.h
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PCIE_HOST_H
+#define PCIE_HOST_H
+
+#include "pci_host.h"
+
+struct PCIExpressHost {
+    PCIHostState pci;
+
+    /* express part */
+
+    /* base address where MMCONFIG area is mapped. */
+    target_phys_addr_t  base_addr;
+
+    /* the size of MMCONFIG area. It's host bridge dependent */
+    target_phys_addr_t  size;
+
+    /* result of cpu_register_io_memory() to map MMCONFIG area */
+    int mmio_index;
+};
+
+int pcie_host_init(PCIExpressHost *e);
+void pcie_host_mmcfg_unmap(PCIExpressHost *e);
+void pcie_host_mmcfg_map(PCIExpressHost *e,
+                         target_phys_addr_t addr, uint32_t size);
+void pcie_host_mmcfg_update(PCIExpressHost *e,
+                            int enable,
+                            target_phys_addr_t addr, uint32_t size);
+
+#endif /* PCIE_HOST_H */
diff --git a/qemu-0.15.x/hw/pcie_port.c b/qemu-0.15.x/hw/pcie_port.c
new file mode 100644
index 0000000..340dcdb
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_port.c
@@ -0,0 +1,124 @@
+/*
+ * pcie_port.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pcie_port.h"
+
+void pcie_port_init_reg(PCIDevice *d)
+{
+    /* Unlike pci bridge,
+       66MHz and fast back to back don't apply to pci express port. */
+    pci_set_word(d->config + PCI_STATUS, 0);
+    pci_set_word(d->config + PCI_SEC_STATUS, 0);
+
+    /* Unlike conventional pci bridge, some bits are hardwared to 0. */
+    pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
+                 PCI_BRIDGE_CTL_PARITY |
+                 PCI_BRIDGE_CTL_ISA |
+                 PCI_BRIDGE_CTL_VGA |
+                 PCI_BRIDGE_CTL_SERR |
+                 PCI_BRIDGE_CTL_BUS_RESET);
+
+    /* 7.5.3.5 Prefetchable Memory Base Limit
+     * The Prefetchable Memory Base and Prefetchable Memory Limit registers
+     * must indicate that 64-bit addresses are supported, as defined in
+     * PCI-to-PCI Bridge Architecture Specification, Revision 1.2.
+     */
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_TYPE_64);
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
+                               PCI_PREF_RANGE_TYPE_64);
+}
+
+/**************************************************************************
+ * (chassis number, pcie physical slot number) -> pcie slot conversion
+ */
+struct PCIEChassis {
+    uint8_t     number;
+
+    QLIST_HEAD(, PCIESlot) slots;
+    QLIST_ENTRY(PCIEChassis) next;
+};
+
+static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
+
+static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
+{
+    struct PCIEChassis *c;
+    QLIST_FOREACH(c, &chassis, next) {
+        if (c->number == chassis_number) {
+            break;
+        }
+    }
+    return c;
+}
+
+void pcie_chassis_create(uint8_t chassis_number)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(chassis_number);
+    if (c) {
+        return;
+    }
+    c = qemu_mallocz(sizeof(*c));
+    c->number = chassis_number;
+    QLIST_INIT(&c->slots);
+    QLIST_INSERT_HEAD(&chassis, c, next);
+}
+
+static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
+                                                     uint8_t slot)
+{
+    PCIESlot *s;
+    QLIST_FOREACH(s, &c->slots, next) {
+        if (s->slot == slot) {
+            break;
+        }
+    }
+    return s;
+}
+
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(chassis_number);
+    if (!c) {
+        return NULL;
+    }
+    return pcie_chassis_find_slot_with_chassis(c, slot);
+}
+
+int pcie_chassis_add_slot(struct PCIESlot *slot)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(slot->chassis);
+    if (!c) {
+        return -ENODEV;
+    }
+    if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
+        return -EBUSY;
+    }
+    QLIST_INSERT_HEAD(&c->slots, slot, next);
+    return 0;
+}
+
+void pcie_chassis_del_slot(PCIESlot *s)
+{
+    QLIST_REMOVE(s, next);
+}
diff --git a/qemu-0.15.x/hw/pcie_port.h b/qemu-0.15.x/hw/pcie_port.h
new file mode 100644
index 0000000..3709583
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_port.h
@@ -0,0 +1,51 @@
+/*
+ * pcie_port.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_PORT_H
+#define QEMU_PCIE_PORT_H
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+
+struct PCIEPort {
+    PCIBridge   br;
+
+    /* pci express switch port */
+    uint8_t     port;
+};
+
+void pcie_port_init_reg(PCIDevice *d);
+
+struct PCIESlot {
+    PCIEPort    port;
+
+    /* pci express switch port with slot */
+    uint8_t     chassis;
+    uint16_t    slot;
+    QLIST_ENTRY(PCIESlot) next;
+};
+
+void pcie_chassis_create(uint8_t chassis_number);
+void pcie_main_chassis_create(void);
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
+int pcie_chassis_add_slot(struct PCIESlot *slot);
+void pcie_chassis_del_slot(PCIESlot *s);
+
+#endif /* QEMU_PCIE_PORT_H */
diff --git a/qemu-0.15.x/hw/pcie_regs.h b/qemu-0.15.x/hw/pcie_regs.h
new file mode 100644
index 0000000..4d123d9
--- /dev/null
+++ b/qemu-0.15.x/hw/pcie_regs.h
@@ -0,0 +1,156 @@
+/*
+ * constants for pcie configurations space from pci express spec.
+ *
+ * TODO:
+ * Those constants and macros should go to Linux pci_regs.h
+ * Once they're merged, they will go away.
+ */
+#ifndef QEMU_PCIE_REGS_H
+#define QEMU_PCIE_REGS_H
+
+
+/* express capability */
+
+#define PCI_EXP_VER2_SIZEOF             0x3c /* express capability of ver. 2 */
+#define PCI_EXT_CAP_VER_SHIFT           16
+#define PCI_EXT_CAP_NEXT_SHIFT          20
+#define PCI_EXT_CAP_NEXT_MASK           (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
+
+#define PCI_EXT_CAP(id, ver, next)                                      \
+    ((id) |                                                             \
+     ((ver) << PCI_EXT_CAP_VER_SHIFT) |                                 \
+     ((next) << PCI_EXT_CAP_NEXT_SHIFT))
+
+#define PCI_EXT_CAP_ALIGN               4
+#define PCI_EXT_CAP_ALIGNUP(x)                                  \
+    (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
+
+/* PCI_EXP_FLAGS */
+#define PCI_EXP_FLAGS_VER2              2 /* for now, supports only ver. 2 */
+#define PCI_EXP_FLAGS_IRQ_SHIFT         (ffs(PCI_EXP_FLAGS_IRQ) - 1)
+#define PCI_EXP_FLAGS_TYPE_SHIFT        (ffs(PCI_EXP_FLAGS_TYPE) - 1)
+
+
+/* PCI_EXP_LINK{CAP, STA} */
+/* link speed */
+#define PCI_EXP_LNK_LS_25               1
+
+#define PCI_EXP_LNK_MLW_SHIFT           (ffs(PCI_EXP_LNKCAP_MLW) - 1)
+#define PCI_EXP_LNK_MLW_1               (1 << PCI_EXP_LNK_MLW_SHIFT)
+
+/* PCI_EXP_LINKCAP */
+#define PCI_EXP_LNKCAP_ASPMS_SHIFT      (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
+#define PCI_EXP_LNKCAP_ASPMS_0S         (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
+
+#define PCI_EXP_LNKCAP_PN_SHIFT         (ffs(PCI_EXP_LNKCAP_PN) - 1)
+
+#define PCI_EXP_SLTCAP_PSN_SHIFT        (ffs(PCI_EXP_SLTCAP_PSN) - 1)
+
+#define PCI_EXP_SLTCTL_IND_RESERVED     0x0
+#define PCI_EXP_SLTCTL_IND_ON           0x1
+#define PCI_EXP_SLTCTL_IND_BLINK        0x2
+#define PCI_EXP_SLTCTL_IND_OFF          0x3
+#define PCI_EXP_SLTCTL_AIC_SHIFT        (ffs(PCI_EXP_SLTCTL_AIC) - 1)
+#define PCI_EXP_SLTCTL_AIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_PIC_SHIFT        (ffs(PCI_EXP_SLTCTL_PIC) - 1)
+#define PCI_EXP_SLTCTL_PIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_SUPPORTED        \
+            (PCI_EXP_SLTCTL_ABPE |      \
+             PCI_EXP_SLTCTL_PDCE |      \
+             PCI_EXP_SLTCTL_CCIE |      \
+             PCI_EXP_SLTCTL_HPIE |      \
+             PCI_EXP_SLTCTL_AIC |       \
+             PCI_EXP_SLTCTL_PCC |       \
+             PCI_EXP_SLTCTL_EIC)
+
+#define PCI_EXP_DEVCAP2_EFF             0x100000
+#define PCI_EXP_DEVCAP2_EETLPP          0x200000
+
+#define PCI_EXP_DEVCTL2_EETLPPB         0x80
+
+/* ARI */
+#define PCI_ARI_VER                     1
+#define PCI_ARI_SIZEOF                  8
+
+/* AER */
+#define PCI_ERR_VER                     2
+#define PCI_ERR_SIZEOF                  0x48
+
+#define PCI_ERR_UNC_SDN                 0x00000020      /* surprise down */
+#define PCI_ERR_UNC_ACSV                0x00200000      /* ACS Violation */
+#define PCI_ERR_UNC_INTN                0x00400000      /* Internal Error */
+#define PCI_ERR_UNC_MCBTLP              0x00800000      /* MC Blcoked TLP */
+#define PCI_ERR_UNC_ATOP_EBLOCKED       0x01000000      /* atomic op egress blocked */
+#define PCI_ERR_UNC_TLP_PRF_BLOCKED     0x02000000      /* TLP Prefix Blocked */
+#define PCI_ERR_COR_ADV_NONFATAL        0x00002000      /* Advisory Non-Fatal */
+#define PCI_ERR_COR_INTERNAL            0x00004000      /* Corrected Internal */
+#define PCI_ERR_COR_HL_OVERFLOW         0x00008000      /* Header Long Overflow */
+#define PCI_ERR_CAP_FEP_MASK            0x0000001f
+#define PCI_ERR_CAP_MHRC                0x00000200
+#define PCI_ERR_CAP_MHRE                0x00000400
+#define PCI_ERR_CAP_TLP                 0x00000800
+
+#define PCI_ERR_HEADER_LOG_SIZE         16
+#define PCI_ERR_TLP_PREFIX_LOG          0x38
+#define PCI_ERR_TLP_PREFIX_LOG_SIZE     16
+
+#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR         0x4000
+
+/* aer root error command/status */
+#define PCI_ERR_ROOT_CMD_EN_MASK        (PCI_ERR_ROOT_CMD_COR_EN |      \
+                                         PCI_ERR_ROOT_CMD_NONFATAL_EN | \
+                                         PCI_ERR_ROOT_CMD_FATAL_EN)
+
+#define PCI_ERR_ROOT_IRQ_MAX            32
+#define PCI_ERR_ROOT_IRQ                0xf8000000
+#define PCI_ERR_ROOT_IRQ_SHIFT          (ffs(PCI_ERR_ROOT_IRQ) - 1)
+#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV |         \
+                                         PCI_ERR_ROOT_MULTI_COR_RCV |   \
+                                         PCI_ERR_ROOT_UNCOR_RCV |       \
+                                         PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
+                                         PCI_ERR_ROOT_FIRST_FATAL |     \
+                                         PCI_ERR_ROOT_NONFATAL_RCV |    \
+                                         PCI_ERR_ROOT_FATAL_RCV)
+
+#define PCI_ERR_UNC_SUPPORTED           (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_POISON_TLP |       \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_COMP_TIME |        \
+                                         PCI_ERR_UNC_COMP_ABORT |       \
+                                         PCI_ERR_UNC_UNX_COMP |         \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_ECRC |             \
+                                         PCI_ERR_UNC_UNSUP |            \
+                                         PCI_ERR_UNC_ACSV |             \
+                                         PCI_ERR_UNC_INTN |             \
+                                         PCI_ERR_UNC_MCBTLP |           \
+                                         PCI_ERR_UNC_ATOP_EBLOCKED |    \
+                                         PCI_ERR_UNC_TLP_PRF_BLOCKED)
+
+#define PCI_ERR_UNC_SEVERITY_DEFAULT    (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_INTN)
+
+#define PCI_ERR_COR_SUPPORTED           (PCI_ERR_COR_RCVR |             \
+                                         PCI_ERR_COR_BAD_TLP |          \
+                                         PCI_ERR_COR_BAD_DLLP |         \
+                                         PCI_ERR_COR_REP_ROLL |         \
+                                         PCI_ERR_COR_REP_TIMER |        \
+                                         PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#define PCI_ERR_COR_MASK_DEFAULT        (PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#endif /* QEMU_PCIE_REGS_H */
diff --git a/qemu-0.15.x/hw/pckbd.c b/qemu-0.15.x/hw/pckbd.c
new file mode 100644
index 0000000..ae65c04
--- /dev/null
+++ b/qemu-0.15.x/hw/pckbd.c
@@ -0,0 +1,499 @@
+/*
+ * QEMU PC keyboard emulation
+ *
+ * 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 "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "ps2.h"
+#include "sysemu.h"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+#ifdef DEBUG_KBD
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/*	Keyboard Controller Commands */
+#define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
+#define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
+#define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
+#define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
+#define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
+#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
+#define KBD_CCMD_READ_OUTPORT	0xD0    /* read output port */
+#define KBD_CCMD_WRITE_OUTPORT	0xD1    /* write output port */
+#define KBD_CCMD_WRITE_OBUF	0xD2
+#define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
+					   initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
+#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
+#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
+#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
+#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
+#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
+#define KBD_CMD_ECHO     	0xEE
+#define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
+#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
+#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
+#define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
+#define KBD_CMD_RESET		0xFF	/* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR		0xAA	/* Power on reset */
+#define KBD_REPLY_ACK		0xFA	/* Command ACK */
+#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
+
+/* Status Register Bits */
+#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
+#define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST	0x04	/* Self test successful */
+#define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
+#define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
+#define KBD_STAT_PERR 		0x80	/* Parity error */
+
+/* Controller Mode Register Bits */
+#define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 		0x04	/* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
+#define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
+#define KBD_MODE_RFU		0x80
+
+/* Output Port Bits */
+#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
+#define KBD_OUT_A20             0x02    /* x86 only */
+#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
+#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
+#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
+#define AUX_SET_RES		0xE8	/* Set resolution */
+#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
+#define AUX_SET_STREAM		0xEA	/* Set stream mode */
+#define AUX_POLL		0xEB	/* Poll */
+#define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
+#define AUX_SET_WRAP		0xEE	/* Set wrap mode */
+#define AUX_SET_REMOTE		0xF0	/* Set remote mode */
+#define AUX_GET_TYPE		0xF2	/* Get type */
+#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
+#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
+#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
+#define AUX_SET_DEFAULT		0xF6
+#define AUX_RESET		0xFF	/* Reset aux device */
+#define AUX_ACK			0xFA	/* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE     0x40
+#define MOUSE_STATUS_ENABLED    0x20
+#define MOUSE_STATUS_SCALE21    0x10
+
+#define KBD_PENDING_KBD         1
+#define KBD_PENDING_AUX         2
+
+typedef struct KBDState {
+    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
+    uint8_t status;
+    uint8_t mode;
+    uint8_t outport;
+    /* Bitmask of devices with data available.  */
+    uint8_t pending;
+    void *kbd;
+    void *mouse;
+
+    qemu_irq irq_kbd;
+    qemu_irq irq_mouse;
+    qemu_irq *a20_out;
+    target_phys_addr_t mask;
+} KBDState;
+
+/* update irq and KBD_STAT_[MOUSE_]OBF */
+/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
+   incorrect, but it avoids having to simulate exact delays */
+static void kbd_update_irq(KBDState *s)
+{
+    int irq_kbd_level, irq_mouse_level;
+
+    irq_kbd_level = 0;
+    irq_mouse_level = 0;
+    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
+    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
+    if (s->pending) {
+        s->status |= KBD_STAT_OBF;
+        s->outport |= KBD_OUT_OBF;
+        /* kbd data takes priority over aux data.  */
+        if (s->pending == KBD_PENDING_AUX) {
+            s->status |= KBD_STAT_MOUSE_OBF;
+            s->outport |= KBD_OUT_MOUSE_OBF;
+            if (s->mode & KBD_MODE_MOUSE_INT)
+                irq_mouse_level = 1;
+        } else {
+            if ((s->mode & KBD_MODE_KBD_INT) &&
+                !(s->mode & KBD_MODE_DISABLE_KBD))
+                irq_kbd_level = 1;
+        }
+    }
+    qemu_set_irq(s->irq_kbd, irq_kbd_level);
+    qemu_set_irq(s->irq_mouse, irq_mouse_level);
+}
+
+static void kbd_update_kbd_irq(void *opaque, int level)
+{
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_KBD;
+    else
+        s->pending &= ~KBD_PENDING_KBD;
+    kbd_update_irq(s);
+}
+
+static void kbd_update_aux_irq(void *opaque, int level)
+{
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_AUX;
+    else
+        s->pending &= ~KBD_PENDING_AUX;
+    kbd_update_irq(s);
+}
+
+static uint32_t kbd_read_status(void *opaque, uint32_t addr)
+{
+    KBDState *s = opaque;
+    int val;
+    val = s->status;
+    DPRINTF("kbd: read status=0x%02x\n", val);
+    return val;
+}
+
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+    if (aux)
+        ps2_queue(s->mouse, b);
+    else
+        ps2_queue(s->kbd, b);
+}
+
+static void outport_write(KBDState *s, uint32_t val)
+{
+    DPRINTF("kbd: write outport=0x%02x\n", val);
+    s->outport = val;
+    if (s->a20_out) {
+        qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    }
+    if (!(val & 1)) {
+        qemu_system_reset_request();
+    }
+}
+
+static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
+{
+    KBDState *s = opaque;
+
+    DPRINTF("kbd: write cmd=0x%02x\n", val);
+
+    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
+     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
+     * command specify the output port bits to be pulsed.
+     * 0: Bit should be pulsed. 1: Bit should not be modified.
+     * The only useful version of this command is pulsing bit 0,
+     * which does a CPU reset.
+     */
+    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
+        if(!(val & 1))
+            val = KBD_CCMD_RESET;
+        else
+            val = KBD_CCMD_NO_OP;
+    }
+
+    switch(val) {
+    case KBD_CCMD_READ_MODE:
+        kbd_queue(s, s->mode, 0);
+        break;
+    case KBD_CCMD_WRITE_MODE:
+    case KBD_CCMD_WRITE_OBUF:
+    case KBD_CCMD_WRITE_AUX_OBUF:
+    case KBD_CCMD_WRITE_MOUSE:
+    case KBD_CCMD_WRITE_OUTPORT:
+        s->write_cmd = val;
+        break;
+    case KBD_CCMD_MOUSE_DISABLE:
+        s->mode |= KBD_MODE_DISABLE_MOUSE;
+        break;
+    case KBD_CCMD_MOUSE_ENABLE:
+        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
+        break;
+    case KBD_CCMD_TEST_MOUSE:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_SELF_TEST:
+        s->status |= KBD_STAT_SELFTEST;
+        kbd_queue(s, 0x55, 0);
+        break;
+    case KBD_CCMD_KBD_TEST:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_KBD_DISABLE:
+        s->mode |= KBD_MODE_DISABLE_KBD;
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_KBD_ENABLE:
+        s->mode &= ~KBD_MODE_DISABLE_KBD;
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_READ_INPORT:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_READ_OUTPORT:
+        kbd_queue(s, s->outport, 0);
+        break;
+    case KBD_CCMD_ENABLE_A20:
+        if (s->a20_out) {
+            qemu_irq_raise(*s->a20_out);
+        }
+        s->outport |= KBD_OUT_A20;
+        break;
+    case KBD_CCMD_DISABLE_A20:
+        if (s->a20_out) {
+            qemu_irq_lower(*s->a20_out);
+        }
+        s->outport &= ~KBD_OUT_A20;
+        break;
+    case KBD_CCMD_RESET:
+        qemu_system_reset_request();
+        break;
+    case KBD_CCMD_NO_OP:
+        /* ignore that */
+        break;
+    default:
+        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
+        break;
+    }
+}
+
+static uint32_t kbd_read_data(void *opaque, uint32_t addr)
+{
+    KBDState *s = opaque;
+    uint32_t val;
+
+    if (s->pending == KBD_PENDING_AUX)
+        val = ps2_read_data(s->mouse);
+    else
+        val = ps2_read_data(s->kbd);
+
+    DPRINTF("kbd: read data=0x%02x\n", val);
+    return val;
+}
+
+static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
+{
+    KBDState *s = opaque;
+
+    DPRINTF("kbd: write data=0x%02x\n", val);
+
+    switch(s->write_cmd) {
+    case 0:
+        ps2_write_keyboard(s->kbd, val);
+        break;
+    case KBD_CCMD_WRITE_MODE:
+        s->mode = val;
+        ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
+        /* ??? */
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_WRITE_OBUF:
+        kbd_queue(s, val, 0);
+        break;
+    case KBD_CCMD_WRITE_AUX_OBUF:
+        kbd_queue(s, val, 1);
+        break;
+    case KBD_CCMD_WRITE_OUTPORT:
+        outport_write(s, val);
+        break;
+    case KBD_CCMD_WRITE_MOUSE:
+        ps2_write_mouse(s->mouse, val);
+        break;
+    default:
+        break;
+    }
+    s->write_cmd = 0;
+}
+
+static void kbd_reset(void *opaque)
+{
+    KBDState *s = opaque;
+
+    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
+    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
+    s->outport = KBD_OUT_RESET | KBD_OUT_A20;
+}
+
+static const VMStateDescription vmstate_kbd = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(write_cmd, KBDState),
+        VMSTATE_UINT8(status, KBDState),
+        VMSTATE_UINT8(mode, KBDState),
+        VMSTATE_UINT8(pending, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Memory mapped interface */
+static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        return kbd_read_status(s, 0) & 0xff;
+    else
+        return kbd_read_data(s, 0) & 0xff;
+}
+
+static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        kbd_write_command(s, 0, value & 0xff);
+    else
+        kbd_write_data(s, 0, value & 0xff);
+}
+
+static CPUReadMemoryFunc * const kbd_mm_read[] = {
+    &kbd_mm_readb,
+    &kbd_mm_readb,
+    &kbd_mm_readb,
+};
+
+static CPUWriteMemoryFunc * const kbd_mm_write[] = {
+    &kbd_mm_writeb,
+    &kbd_mm_writeb,
+    &kbd_mm_writeb,
+};
+
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   target_phys_addr_t base, ram_addr_t size,
+                   target_phys_addr_t mask)
+{
+    KBDState *s = qemu_mallocz(sizeof(KBDState));
+    int s_io_memory;
+
+    s->irq_kbd = kbd_irq;
+    s->irq_mouse = mouse_irq;
+    s->mask = mask;
+
+    vmstate_register(NULL, 0, &vmstate_kbd, s);
+    s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, size, s_io_memory);
+
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+    qemu_register_reset(kbd_reset, s);
+}
+
+typedef struct ISAKBDState {
+    ISADevice dev;
+    KBDState  kbd;
+} ISAKBDState;
+
+void i8042_isa_mouse_fake_event(void *opaque)
+{
+    ISADevice *dev = opaque;
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+
+    ps2_mouse_fake_event(s->mouse);
+}
+
+void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out)
+{
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_kbd_isa = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i8042_initfn(ISADevice *dev)
+{
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+
+    isa_init_irq(dev, &s->irq_kbd, 1);
+    isa_init_irq(dev, &s->irq_mouse, 12);
+
+    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
+    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
+    isa_init_ioport(dev, 0x60);
+    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
+    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
+    isa_init_ioport(dev, 0x64);
+
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+    qemu_register_reset(kbd_reset, s);
+    return 0;
+}
+
+static ISADeviceInfo i8042_info = {
+    .qdev.name     = "i8042",
+    .qdev.size     = sizeof(ISAKBDState),
+    .qdev.vmsd     = &vmstate_kbd_isa,
+    .qdev.no_user  = 1,
+    .init          = i8042_initfn,
+};
+
+static void i8042_register(void)
+{
+    isa_qdev_register(&i8042_info);
+}
+device_init(i8042_register)
diff --git a/qemu-0.15.x/hw/pcmcia.h b/qemu-0.15.x/hw/pcmcia.h
new file mode 100644
index 0000000..50648c9
--- /dev/null
+++ b/qemu-0.15.x/hw/pcmcia.h
@@ -0,0 +1,51 @@
+/* PCMCIA/Cardbus */
+
+#include "qemu-common.h"
+
+typedef struct {
+    qemu_irq irq;
+    int attached;
+    const char *slot_string;
+    const char *card_string;
+} PCMCIASocket;
+
+void pcmcia_socket_register(PCMCIASocket *socket);
+void pcmcia_socket_unregister(PCMCIASocket *socket);
+void pcmcia_info(Monitor *mon);
+
+struct PCMCIACardState {
+    void *state;
+    PCMCIASocket *slot;
+    int (*attach)(void *state);
+    int (*detach)(void *state);
+    const uint8_t *cis;
+    int cis_len;
+
+    /* Only valid if attached */
+    uint8_t (*attr_read)(void *state, uint32_t address);
+    void (*attr_write)(void *state, uint32_t address, uint8_t value);
+    uint16_t (*common_read)(void *state, uint32_t address);
+    void (*common_write)(void *state, uint32_t address, uint16_t value);
+    uint16_t (*io_read)(void *state, uint32_t address);
+    void (*io_write)(void *state, uint32_t address, uint16_t value);
+};
+
+#define CISTPL_DEVICE		0x01	/* 5V Device Information Tuple */
+#define CISTPL_NO_LINK		0x14	/* No Link Tuple */
+#define CISTPL_VERS_1		0x15	/* Level 1 Version Tuple */
+#define CISTPL_JEDEC_C		0x18	/* JEDEC ID Tuple */
+#define CISTPL_JEDEC_A		0x19	/* JEDEC ID Tuple */
+#define CISTPL_CONFIG		0x1a	/* Configuration Tuple */
+#define CISTPL_CFTABLE_ENTRY	0x1b	/* 16-bit PCCard Configuration */
+#define CISTPL_DEVICE_OC	0x1c	/* Additional Device Information */
+#define CISTPL_DEVICE_OA	0x1d	/* Additional Device Information */
+#define CISTPL_DEVICE_GEO	0x1e	/* Additional Device Information */
+#define CISTPL_DEVICE_GEO_A	0x1f	/* Additional Device Information */
+#define CISTPL_MANFID		0x20	/* Manufacture ID Tuple */
+#define CISTPL_FUNCID		0x21	/* Function ID Tuple */
+#define CISTPL_FUNCE		0x22	/* Function Extension Tuple */
+#define CISTPL_END		0xff	/* Tuple End */
+#define CISTPL_ENDMARK		0xff
+
+/* dscm1xxxx.c */
+PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv);
diff --git a/qemu-0.15.x/hw/pcnet-pci.c b/qemu-0.15.x/hw/pcnet-pci.c
new file mode 100644
index 0000000..216cf81
--- /dev/null
+++ b/qemu-0.15.x/hw/pcnet-pci.c
@@ -0,0 +1,332 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) PCI emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+#include "pci.h"
+#include "net.h"
+#include "loader.h"
+#include "qemu-timer.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+typedef struct {
+    PCIDevice pci_dev;
+    PCNetState state;
+} PCIPCNetState;
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    /* Check APROMWE bit to enable write access */
+    if (pcnet_bcr_readw(s,2) & 0x100)
+        s->prom[addr & 15] = val;
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = s->prom[addr & 15];
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
+                             pcibus_t addr, pcibus_t size, int type)
+{
+    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
+           addr, size);
+#endif
+
+    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
+    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+
+    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
+    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
+    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
+    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+}
+
+static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
+           val);
+#endif
+    if (!(addr & 0x10))
+        pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (!(addr & 0x10))
+        val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
+           val & 0xff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writew(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+    }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (addr & 0x10)
+        val = pcnet_ioport_readw(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
+           val & 0xffff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writel(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+    }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val;
+    if (addr & 0x10)
+        val = pcnet_ioport_readl(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+3);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+2);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
+           val);
+#endif
+    return val;
+}
+
+static const VMStateDescription vmstate_pci_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
+    &pcnet_mmio_writeb,
+    &pcnet_mmio_writew,
+    &pcnet_mmio_writel
+};
+
+static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
+    &pcnet_mmio_readb,
+    &pcnet_mmio_readw,
+    &pcnet_mmio_readl
+};
+
+static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
+                                      uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_write(addr, buf, len);
+}
+
+static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
+                                     uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_read(addr, buf, len);
+}
+
+static void pci_pcnet_cleanup(VLANClientState *nc)
+{
+    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+    cpu_unregister_io_memory(d->state.mmio_index);
+    qemu_del_timer(d->state.poll_timer);
+    qemu_free_timer(d->state.poll_timer);
+    qemu_del_vlan_client(&d->state.nic->nc);
+    return 0;
+}
+
+static NetClientInfo net_pci_pcnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .cleanup = pci_pcnet_cleanup,
+};
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+    PCNetState *s = &d->state;
+    uint8_t *pci_conf;
+
+#if 0
+    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+    pci_conf = pci_dev->config;
+
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_MIN_GNT] = 0x06;
+    pci_conf[PCI_MAX_LAT] = 0xff;
+
+    /* Handler for memory-mapped I/O */
+    s->mmio_index =
+      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state,
+                             DEVICE_NATIVE_ENDIAN);
+
+    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+
+    pci_register_bar_simple(pci_dev, 1, PCNET_PNPMMIO_SIZE, 0, s->mmio_index);
+
+    s->irq = pci_dev->irq[0];
+    s->phys_mem_read = pci_physical_memory_read;
+    s->phys_mem_write = pci_physical_memory_write;
+
+    if (!pci_dev->qdev.hotplugged) {
+        static int loaded = 0;
+        if (!loaded) {
+            rom_add_option("pxe-pcnet.rom", -1);
+            loaded = 1;
+        }
+    }
+
+    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+}
+
+static void pci_reset(DeviceState *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static PCIDeviceInfo pcnet_info = {
+    .qdev.name  = "pcnet",
+    .qdev.size  = sizeof(PCIPCNetState),
+    .qdev.reset = pci_reset,
+    .qdev.vmsd  = &vmstate_pci_pcnet,
+    .init       = pci_pcnet_init,
+    .exit       = pci_pcnet_uninit,
+    .vendor_id  = PCI_VENDOR_ID_AMD,
+    .device_id  = PCI_DEVICE_ID_AMD_LANCE,
+    .revision   = 0x10,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void pci_pcnet_register_devices(void)
+{
+    pci_qdev_register(&pcnet_info);
+}
+
+device_init(pci_pcnet_register_devices)
diff --git a/qemu-0.15.x/hw/pcnet.c b/qemu-0.15.x/hw/pcnet.c
new file mode 100644
index 0000000..cf16fd4
--- /dev/null
+++ b/qemu-0.15.x/hw/pcnet.c
@@ -0,0 +1,1765 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */
+
+#include "qdev.h"
+#include "net.h"
+#include "qemu-timer.h"
+#include "qemu_socket.h"
+#include "sysemu.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+struct qemu_ether_header {
+    uint8_t ether_dhost[6];
+    uint8_t ether_shost[6];
+    uint16_t ether_type;
+};
+
+/* BUS CONFIGURATION REGISTERS */
+#define BCR_MSRDA    0
+#define BCR_MSWRA    1
+#define BCR_MC       2
+#define BCR_LNKST    4
+#define BCR_LED1     5
+#define BCR_LED2     6
+#define BCR_LED3     7
+#define BCR_FDC      9
+#define BCR_BSBC     18
+#define BCR_EECAS    19
+#define BCR_SWS      20
+#define BCR_PLAT     22
+
+#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
+#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
+#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
+
+#define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
+#define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
+#define CSR_STOP(S)      !!(((S)->csr[0])&0x0004)
+#define CSR_TDMD(S)      !!(((S)->csr[0])&0x0008)
+#define CSR_TXON(S)      !!(((S)->csr[0])&0x0010)
+#define CSR_RXON(S)      !!(((S)->csr[0])&0x0020)
+#define CSR_INEA(S)      !!(((S)->csr[0])&0x0040)
+#define CSR_BSWP(S)      !!(((S)->csr[3])&0x0004)
+#define CSR_LAPPEN(S)    !!(((S)->csr[3])&0x0020)
+#define CSR_DXSUFLO(S)   !!(((S)->csr[3])&0x0040)
+#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
+#define CSR_DPOLL(S)     !!(((S)->csr[4])&0x1000)
+#define CSR_SPND(S)      !!(((S)->csr[5])&0x0001)
+#define CSR_LTINTEN(S)   !!(((S)->csr[5])&0x4000)
+#define CSR_TOKINTD(S)   !!(((S)->csr[5])&0x8000)
+#define CSR_DRX(S)       !!(((S)->csr[15])&0x0001)
+#define CSR_DTX(S)       !!(((S)->csr[15])&0x0002)
+#define CSR_LOOP(S)      !!(((S)->csr[15])&0x0004)
+#define CSR_DXMTFCS(S)   !!(((S)->csr[15])&0x0008)
+#define CSR_DRCVPA(S)    !!(((S)->csr[15])&0x2000)
+#define CSR_DRCVBC(S)    !!(((S)->csr[15])&0x4000)
+#define CSR_PROM(S)      !!(((S)->csr[15])&0x8000)
+
+#define CSR_CRBC(S)      ((S)->csr[40])
+#define CSR_CRST(S)      ((S)->csr[41])
+#define CSR_CXBC(S)      ((S)->csr[42])
+#define CSR_CXST(S)      ((S)->csr[43])
+#define CSR_NRBC(S)      ((S)->csr[44])
+#define CSR_NRST(S)      ((S)->csr[45])
+#define CSR_POLL(S)      ((S)->csr[46])
+#define CSR_PINT(S)      ((S)->csr[47])
+#define CSR_RCVRC(S)     ((S)->csr[72])
+#define CSR_XMTRC(S)     ((S)->csr[74])
+#define CSR_RCVRL(S)     ((S)->csr[76])
+#define CSR_XMTRL(S)     ((S)->csr[78])
+#define CSR_MISSC(S)     ((S)->csr[112])
+
+#define CSR_IADR(S)      ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
+#define CSR_CRBA(S)      ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
+#define CSR_CXBA(S)      ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
+#define CSR_NRBA(S)      ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
+#define CSR_BADR(S)      ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
+#define CSR_NRDA(S)      ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
+#define CSR_CRDA(S)      ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
+#define CSR_BADX(S)      ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
+#define CSR_NXDA(S)      ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
+#define CSR_CXDA(S)      ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
+#define CSR_NNRD(S)      ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
+#define CSR_NNXD(S)      ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
+#define CSR_PXDA(S)      ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
+#define CSR_NXBA(S)      ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
+
+#define PHYSADDR(S,A) \
+  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
+
+struct pcnet_initblk16 {
+    uint16_t mode;
+    uint16_t padr[3];
+    uint16_t ladrf[4];
+    uint32_t rdra;
+    uint32_t tdra;
+};
+
+struct pcnet_initblk32 {
+    uint16_t mode;
+    uint8_t rlen;
+    uint8_t tlen;
+    uint16_t padr[3];
+    uint16_t _res;
+    uint16_t ladrf[4];
+    uint32_t rdra;
+    uint32_t tdra;
+};
+
+struct pcnet_TMD {
+    uint32_t tbadr;
+    int16_t length;
+    int16_t status;
+    uint32_t misc;
+    uint32_t res;
+};
+
+#define TMDL_BCNT_MASK  0x0fff
+#define TMDL_BCNT_SH    0
+#define TMDL_ONES_MASK  0xf000
+#define TMDL_ONES_SH    12
+
+#define TMDS_BPE_MASK   0x0080
+#define TMDS_BPE_SH     7
+#define TMDS_ENP_MASK   0x0100
+#define TMDS_ENP_SH     8
+#define TMDS_STP_MASK   0x0200
+#define TMDS_STP_SH     9
+#define TMDS_DEF_MASK   0x0400
+#define TMDS_DEF_SH     10
+#define TMDS_ONE_MASK   0x0800
+#define TMDS_ONE_SH     11
+#define TMDS_LTINT_MASK 0x1000
+#define TMDS_LTINT_SH   12
+#define TMDS_NOFCS_MASK 0x2000
+#define TMDS_NOFCS_SH   13
+#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
+#define TMDS_ADDFCS_SH  TMDS_NOFCS_SH
+#define TMDS_ERR_MASK   0x4000
+#define TMDS_ERR_SH     14
+#define TMDS_OWN_MASK   0x8000
+#define TMDS_OWN_SH     15
+
+#define TMDM_TRC_MASK   0x0000000f
+#define TMDM_TRC_SH     0
+#define TMDM_TDR_MASK   0x03ff0000
+#define TMDM_TDR_SH     16
+#define TMDM_RTRY_MASK  0x04000000
+#define TMDM_RTRY_SH    26
+#define TMDM_LCAR_MASK  0x08000000
+#define TMDM_LCAR_SH    27
+#define TMDM_LCOL_MASK  0x10000000
+#define TMDM_LCOL_SH    28
+#define TMDM_EXDEF_MASK 0x20000000
+#define TMDM_EXDEF_SH   29
+#define TMDM_UFLO_MASK  0x40000000
+#define TMDM_UFLO_SH    30
+#define TMDM_BUFF_MASK  0x80000000
+#define TMDM_BUFF_SH    31
+
+struct pcnet_RMD {
+    uint32_t rbadr;
+    int16_t buf_length;
+    int16_t status;
+    uint32_t msg_length;
+    uint32_t res;
+};
+
+#define RMDL_BCNT_MASK  0x0fff
+#define RMDL_BCNT_SH    0
+#define RMDL_ONES_MASK  0xf000
+#define RMDL_ONES_SH    12
+
+#define RMDS_BAM_MASK   0x0010
+#define RMDS_BAM_SH     4
+#define RMDS_LFAM_MASK  0x0020
+#define RMDS_LFAM_SH    5
+#define RMDS_PAM_MASK   0x0040
+#define RMDS_PAM_SH     6
+#define RMDS_BPE_MASK   0x0080
+#define RMDS_BPE_SH     7
+#define RMDS_ENP_MASK   0x0100
+#define RMDS_ENP_SH     8
+#define RMDS_STP_MASK   0x0200
+#define RMDS_STP_SH     9
+#define RMDS_BUFF_MASK  0x0400
+#define RMDS_BUFF_SH    10
+#define RMDS_CRC_MASK   0x0800
+#define RMDS_CRC_SH     11
+#define RMDS_OFLO_MASK  0x1000
+#define RMDS_OFLO_SH    12
+#define RMDS_FRAM_MASK  0x2000
+#define RMDS_FRAM_SH    13
+#define RMDS_ERR_MASK   0x4000
+#define RMDS_ERR_SH     14
+#define RMDS_OWN_MASK   0x8000
+#define RMDS_OWN_SH     15
+
+#define RMDM_MCNT_MASK  0x00000fff
+#define RMDM_MCNT_SH    0
+#define RMDM_ZEROS_MASK 0x0000f000
+#define RMDM_ZEROS_SH   12
+#define RMDM_RPC_MASK   0x00ff0000
+#define RMDM_RPC_SH     16
+#define RMDM_RCC_MASK   0xff000000
+#define RMDM_RCC_SH     24
+
+#define SET_FIELD(regp, name, field, value)             \
+  (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
+             | ((value) << name ## _ ## field ## _SH))
+
+#define GET_FIELD(reg, name, field)                     \
+  (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
+
+#define PRINT_TMD(T) printf(                            \
+        "TMD0 : TBADR=0x%08x\n"                         \
+        "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, "       \
+        "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n"             \
+        "       BPE=%d, BCNT=%d\n"                      \
+        "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, "       \
+        "LCA=%d, RTR=%d,\n"                             \
+        "       TDR=%d, TRC=%d\n",                      \
+        (T)->tbadr,                                     \
+        GET_FIELD((T)->status, TMDS, OWN),              \
+        GET_FIELD((T)->status, TMDS, ERR),              \
+        GET_FIELD((T)->status, TMDS, NOFCS),            \
+        GET_FIELD((T)->status, TMDS, LTINT),            \
+        GET_FIELD((T)->status, TMDS, ONE),              \
+        GET_FIELD((T)->status, TMDS, DEF),              \
+        GET_FIELD((T)->status, TMDS, STP),              \
+        GET_FIELD((T)->status, TMDS, ENP),              \
+        GET_FIELD((T)->status, TMDS, BPE),              \
+        4096-GET_FIELD((T)->length, TMDL, BCNT),        \
+        GET_FIELD((T)->misc, TMDM, BUFF),               \
+        GET_FIELD((T)->misc, TMDM, UFLO),               \
+        GET_FIELD((T)->misc, TMDM, EXDEF),              \
+        GET_FIELD((T)->misc, TMDM, LCOL),               \
+        GET_FIELD((T)->misc, TMDM, LCAR),               \
+        GET_FIELD((T)->misc, TMDM, RTRY),               \
+        GET_FIELD((T)->misc, TMDM, TDR),                \
+        GET_FIELD((T)->misc, TMDM, TRC))
+
+#define PRINT_RMD(R) printf(                            \
+        "RMD0 : RBADR=0x%08x\n"                         \
+        "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, "     \
+        "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n       "     \
+        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
+        "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n",   \
+        (R)->rbadr,                                     \
+        GET_FIELD((R)->status, RMDS, OWN),              \
+        GET_FIELD((R)->status, RMDS, ERR),              \
+        GET_FIELD((R)->status, RMDS, FRAM),             \
+        GET_FIELD((R)->status, RMDS, OFLO),             \
+        GET_FIELD((R)->status, RMDS, CRC),              \
+        GET_FIELD((R)->status, RMDS, BUFF),             \
+        GET_FIELD((R)->status, RMDS, STP),              \
+        GET_FIELD((R)->status, RMDS, ENP),              \
+        GET_FIELD((R)->status, RMDS, BPE),              \
+        GET_FIELD((R)->status, RMDS, PAM),              \
+        GET_FIELD((R)->status, RMDS, LFAM),             \
+        GET_FIELD((R)->status, RMDS, BAM),              \
+        GET_FIELD((R)->buf_length, RMDL, ONES),         \
+        4096-GET_FIELD((R)->buf_length, RMDL, BCNT),    \
+        GET_FIELD((R)->msg_length, RMDM, RCC),          \
+        GET_FIELD((R)->msg_length, RMDM, RPC),          \
+        GET_FIELD((R)->msg_length, RMDM, MCNT),         \
+        GET_FIELD((R)->msg_length, RMDM, ZEROS))
+
+static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
+                                  target_phys_addr_t addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+	} xda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+        tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
+        tmd->length = le16_to_cpu(xda.length);
+        tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
+        tmd->misc = le16_to_cpu(xda.status) << 16;
+        tmd->res = 0;
+    } else {
+        s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
+        le32_to_cpus(&tmd->tbadr);
+        le16_to_cpus((uint16_t *)&tmd->length);
+        le16_to_cpus((uint16_t *)&tmd->status);
+        le32_to_cpus(&tmd->misc);
+        le32_to_cpus(&tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = tmd->tbadr;
+            tmd->tbadr = tmd->misc;
+            tmd->misc = tmp;
+        }
+    }
+}
+
+static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
+                                   target_phys_addr_t addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+        } xda;
+        xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
+                                ((tmd->status & 0xff00) << 16));
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->misc >> 16);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+    } else {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+            uint32_t misc;
+            uint32_t res;
+        } xda;
+        xda.tbadr = cpu_to_le32(tmd->tbadr);
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->status);
+        xda.misc = cpu_to_le32(tmd->misc);
+        xda.res = cpu_to_le32(tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = xda.tbadr;
+            xda.tbadr = xda.misc;
+            xda.misc = tmp;
+        }
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+    }
+}
+
+static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
+                                  target_phys_addr_t addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+	} rda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+        rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
+        rmd->buf_length = le16_to_cpu(rda.buf_length);
+        rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
+        rmd->msg_length = le16_to_cpu(rda.msg_length);
+        rmd->res = 0;
+    } else {
+        s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
+        le32_to_cpus(&rmd->rbadr);
+        le16_to_cpus((uint16_t *)&rmd->buf_length);
+        le16_to_cpus((uint16_t *)&rmd->status);
+        le32_to_cpus(&rmd->msg_length);
+        le32_to_cpus(&rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rmd->rbadr;
+            rmd->rbadr = rmd->msg_length;
+            rmd->msg_length = tmp;
+        }
+    }
+}
+
+static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
+                                   target_phys_addr_t addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+        } rda;
+        rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
+                                ((rmd->status & 0xff00) << 16));
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.msg_length = cpu_to_le16(rmd->msg_length);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+    } else {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t status;
+            uint32_t msg_length;
+            uint32_t res;
+        } rda;
+        rda.rbadr = cpu_to_le32(rmd->rbadr);
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.status = cpu_to_le16(rmd->status);
+        rda.msg_length = cpu_to_le32(rmd->msg_length);
+        rda.res = cpu_to_le32(rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rda.rbadr;
+            rda.rbadr = rda.msg_length;
+            rda.msg_length = tmp;
+        }
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+    }
+}
+
+
+#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
+
+#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
+
+#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
+
+#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
+
+#if 1
+
+#define CHECK_RMD(ADDR,RES) do {                \
+    struct pcnet_RMD rmd;                       \
+    RMDLOAD(&rmd,(ADDR));                       \
+    (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
+          || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do {                \
+    struct pcnet_TMD tmd;                       \
+    TMDLOAD(&tmd,(ADDR));                       \
+    (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
+} while (0)
+
+#else
+
+#define CHECK_RMD(ADDR,RES) do {                \
+    switch (BCR_SWSTYLE(s)) {                   \
+    case 0x00:                                  \
+        do {                                    \
+            uint16_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[2] & 0xf000)!=0xf000; \
+            (RES) |= (rda[3] & 0xf000)!=0x0000; \
+        } while (0);                            \
+        break;                                  \
+    case 0x01:                                  \
+    case 0x02:                                  \
+        do {                                    \
+            uint32_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+            (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
+        } while (0);                            \
+        break;                                  \
+    case 0x03:                                  \
+        do {                                    \
+            uint32_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
+            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+        } while (0);                            \
+        break;                                  \
+    }                                           \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do {                \
+    switch (BCR_SWSTYLE(s)) {                   \
+    case 0x00:                                  \
+        do {                                    \
+            uint16_t xda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
+            (RES) |= (xda[2] & 0xf000)!=0xf000; \
+        } while (0);                            \
+        break;                                  \
+    case 0x01:                                  \
+    case 0x02:                                  \
+    case 0x03:                                  \
+        do {                                    \
+            uint32_t xda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
+            (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
+        } while (0);                            \
+        break;                                  \
+    }                                           \
+} while (0)
+
+#endif
+
+#define PRINT_PKTHDR(BUF) do {                  \
+    struct qemu_ether_header *hdr = (void *)(BUF); \
+    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "type=0x%04x\n",                     \
+           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
+           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
+           hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
+           hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
+           be16_to_cpu(hdr->ether_type));       \
+} while (0)
+
+#define MULTICAST_FILTER_LEN 8
+
+static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
+{
+#define LNC_POLYNOMIAL          0xEDB88320UL
+    uint32_t crc = 0xFFFFFFFF;
+    int idx, bit;
+    uint8_t data;
+
+    for (idx = 0; idx < 6; idx++) {
+        for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
+            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
+            data >>= 1;
+        }
+    }
+    return crc;
+#undef LNC_POLYNOMIAL
+}
+
+#define CRC(crc, ch)	 (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
+
+/* generated using the AUTODIN II polynomial
+ *	x^32 + x^26 + x^23 + x^22 + x^16 +
+ *	x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+ */
+static const uint32_t crctab[256] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+    struct qemu_ether_header *hdr = (void *)buf;
+    uint8_t padr[6] = {
+        s->csr[12] & 0xff, s->csr[12] >> 8,
+        s->csr[13] & 0xff, s->csr[13] >> 8,
+        s->csr[14] & 0xff, s->csr[14] >> 8
+    };
+    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
+#ifdef PCNET_DEBUG_MATCH
+    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
+           "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
+           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
+           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
+           padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
+    printf("padr_match result=%d\n", result);
+#endif
+    return result;
+}
+
+static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
+{
+    static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    struct qemu_ether_header *hdr = (void *)buf;
+    int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
+#ifdef PCNET_DEBUG_MATCH
+    printf("padr_bcast result=%d\n", result);
+#endif
+    return result;
+}
+
+static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+    struct qemu_ether_header *hdr = (void *)buf;
+    if ((*(hdr->ether_dhost)&0x01) &&
+        ((uint64_t *)&s->csr[8])[0] != 0LL) {
+        uint8_t ladr[8] = {
+            s->csr[8] & 0xff, s->csr[8] >> 8,
+            s->csr[9] & 0xff, s->csr[9] >> 8,
+            s->csr[10] & 0xff, s->csr[10] >> 8,
+            s->csr[11] & 0xff, s->csr[11] >> 8
+        };
+        int index = lnc_mchash(hdr->ether_dhost) >> 26;
+        return !!(ladr[index >> 3] & (1 << (index & 7)));
+    }
+    return 0;
+}
+
+static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
+{
+    while (idx < 1) idx += CSR_RCVRL(s);
+    return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
+}
+
+static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
+{
+    int64_t next_time = current_time +
+        muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
+                 get_ticks_per_sec(), 33000000L);
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+static void pcnet_poll(PCNetState *s);
+static void pcnet_poll_timer(void *opaque);
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
+
+static void pcnet_s_reset(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_s_reset\n");
+#endif
+
+    s->lnkst = 0x40;
+    s->rdra = 0;
+    s->tdra = 0;
+    s->rap = 0;
+
+    s->bcr[BCR_BSBC] &= ~0x0080;
+
+    s->csr[0]   = 0x0004;
+    s->csr[3]   = 0x0000;
+    s->csr[4]   = 0x0115;
+    s->csr[5]   = 0x0000;
+    s->csr[6]   = 0x0000;
+    s->csr[8]   = 0;
+    s->csr[9]   = 0;
+    s->csr[10]  = 0;
+    s->csr[11]  = 0;
+    s->csr[12]  = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
+    s->csr[13]  = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
+    s->csr[14]  = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
+    s->csr[15] &= 0x21c4;
+    s->csr[72]  = 1;
+    s->csr[74]  = 1;
+    s->csr[76]  = 1;
+    s->csr[78]  = 1;
+    s->csr[80]  = 0x1410;
+    s->csr[88]  = 0x1003;
+    s->csr[89]  = 0x0262;
+    s->csr[94]  = 0x0000;
+    s->csr[100] = 0x0200;
+    s->csr[103] = 0x0105;
+    s->csr[103] = 0x0105;
+    s->csr[112] = 0x0000;
+    s->csr[114] = 0x0000;
+    s->csr[122] = 0x0000;
+    s->csr[124] = 0x0000;
+
+    s->tx_busy = 0;
+}
+
+static void pcnet_update_irq(PCNetState *s)
+{
+    int isr = 0;
+    s->csr[0] &= ~0x0080;
+
+#if 1
+    if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
+        (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
+        (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
+#else
+    if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
+        (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
+        (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
+        (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
+        (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
+        (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
+        (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
+        (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
+        (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
+        (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
+        (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
+        (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
+#endif
+    {
+
+        isr = CSR_INEA(s);
+        s->csr[0] |= 0x0080;
+    }
+
+    if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
+        s->csr[4] &= ~0x0080;
+        s->csr[4] |= 0x0040;
+        s->csr[0] |= 0x0080;
+        isr = 1;
+#ifdef PCNET_DEBUG
+        printf("pcnet user int\n");
+#endif
+    }
+
+#if 1
+    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
+#else
+    if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
+        (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
+#endif
+    {
+        isr = 1;
+        s->csr[0] |= 0x0080;
+    }
+
+    if (isr != s->isr) {
+#ifdef PCNET_DEBUG
+        printf("pcnet: INTA=%d\n", isr);
+#endif
+    }
+    qemu_set_irq(s->irq, isr);
+    s->isr = isr;
+}
+
+static void pcnet_init(PCNetState *s)
+{
+    int rlen, tlen;
+    uint16_t padr[3], ladrf[4], mode;
+    uint32_t rdra, tdra;
+
+#ifdef PCNET_DEBUG
+    printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
+#endif
+
+    if (BCR_SSIZE32(s)) {
+        struct pcnet_initblk32 initblk;
+        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
+                (uint8_t *)&initblk, sizeof(initblk), 0);
+        mode = le16_to_cpu(initblk.mode);
+        rlen = initblk.rlen >> 4;
+        tlen = initblk.tlen >> 4;
+	ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+	ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+	ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+	ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+	padr[0] = le16_to_cpu(initblk.padr[0]);
+	padr[1] = le16_to_cpu(initblk.padr[1]);
+	padr[2] = le16_to_cpu(initblk.padr[2]);
+        rdra = le32_to_cpu(initblk.rdra);
+        tdra = le32_to_cpu(initblk.tdra);
+    } else {
+        struct pcnet_initblk16 initblk;
+        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
+                (uint8_t *)&initblk, sizeof(initblk), 0);
+        mode = le16_to_cpu(initblk.mode);
+	ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+	ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+	ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+	ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+	padr[0] = le16_to_cpu(initblk.padr[0]);
+	padr[1] = le16_to_cpu(initblk.padr[1]);
+	padr[2] = le16_to_cpu(initblk.padr[2]);
+        rdra = le32_to_cpu(initblk.rdra);
+        tdra = le32_to_cpu(initblk.tdra);
+        rlen = rdra >> 29;
+        tlen = tdra >> 29;
+        rdra &= 0x00ffffff;
+        tdra &= 0x00ffffff;
+    }
+
+#if defined(PCNET_DEBUG)
+    printf("rlen=%d tlen=%d\n", rlen, tlen);
+#endif
+
+    CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
+    CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
+    s->csr[ 6] = (tlen << 12) | (rlen << 8);
+    s->csr[15] = mode;
+    s->csr[ 8] = ladrf[0];
+    s->csr[ 9] = ladrf[1];
+    s->csr[10] = ladrf[2];
+    s->csr[11] = ladrf[3];
+    s->csr[12] = padr[0];
+    s->csr[13] = padr[1];
+    s->csr[14] = padr[2];
+    s->rdra = PHYSADDR(s, rdra);
+    s->tdra = PHYSADDR(s, tdra);
+
+    CSR_RCVRC(s) = CSR_RCVRL(s);
+    CSR_XMTRC(s) = CSR_XMTRL(s);
+
+#ifdef PCNET_DEBUG
+    printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
+        BCR_SSIZE32(s),
+        s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
+#endif
+
+    s->csr[0] |= 0x0101;
+    s->csr[0] &= ~0x0004;       /* clear STOP bit */
+}
+
+static void pcnet_start(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_start\n");
+#endif
+
+    if (!CSR_DTX(s))
+        s->csr[0] |= 0x0010;    /* set TXON */
+
+    if (!CSR_DRX(s))
+        s->csr[0] |= 0x0020;    /* set RXON */
+
+    s->csr[0] &= ~0x0004;       /* clear STOP bit */
+    s->csr[0] |= 0x0002;
+    pcnet_poll_timer(s);
+}
+
+static void pcnet_stop(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_stop\n");
+#endif
+    s->csr[0] &= ~0x7feb;
+    s->csr[0] |= 0x0014;
+    s->csr[4] &= ~0x02c2;
+    s->csr[5] &= ~0x0011;
+    pcnet_poll_timer(s);
+}
+
+static void pcnet_rdte_poll(PCNetState *s)
+{
+    s->csr[28] = s->csr[29] = 0;
+    if (s->rdra) {
+        int bad = 0;
+#if 1
+        target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
+        target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
+        target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
+#else
+        target_phys_addr_t crda = s->rdra +
+            (CSR_RCVRL(s) - CSR_RCVRC(s)) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+        int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
+        target_phys_addr_t nrda = s->rdra +
+            (CSR_RCVRL(s) - nrdc) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+        int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
+        target_phys_addr_t nnrd = s->rdra +
+            (CSR_RCVRL(s) - nnrc) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+#endif
+
+        CHECK_RMD(crda, bad);
+        if (!bad) {
+            CHECK_RMD(nrda, bad);
+            if (bad || (nrda == crda)) nrda = 0;
+            CHECK_RMD(nnrd, bad);
+            if (bad || (nnrd == crda)) nnrd = 0;
+
+            s->csr[28] = crda & 0xffff;
+            s->csr[29] = crda >> 16;
+            s->csr[26] = nrda & 0xffff;
+            s->csr[27] = nrda >> 16;
+            s->csr[36] = nnrd & 0xffff;
+            s->csr[37] = nnrd >> 16;
+#ifdef PCNET_DEBUG
+            if (bad) {
+                printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
+                       crda);
+            }
+        } else {
+            printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
+                   crda);
+#endif
+        }
+    }
+
+    if (CSR_CRDA(s)) {
+        struct pcnet_RMD rmd;
+        RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
+        CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_CRST(s) = rmd.status;
+#ifdef PCNET_DEBUG_RMD_X
+        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
+                PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
+                rmd.buf_length, rmd.status, rmd.msg_length);
+        PRINT_RMD(&rmd);
+#endif
+    } else {
+        CSR_CRBC(s) = CSR_CRST(s) = 0;
+    }
+
+    if (CSR_NRDA(s)) {
+        struct pcnet_RMD rmd;
+        RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
+        CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_NRST(s) = rmd.status;
+    } else {
+        CSR_NRBC(s) = CSR_NRST(s) = 0;
+    }
+
+}
+
+static int pcnet_tdte_poll(PCNetState *s)
+{
+    s->csr[34] = s->csr[35] = 0;
+    if (s->tdra) {
+        target_phys_addr_t cxda = s->tdra +
+            (CSR_XMTRL(s) - CSR_XMTRC(s)) *
+            (BCR_SWSTYLE(s) ? 16 : 8);
+        int bad = 0;
+        CHECK_TMD(cxda, bad);
+        if (!bad) {
+            if (CSR_CXDA(s) != cxda) {
+                s->csr[60] = s->csr[34];
+                s->csr[61] = s->csr[35];
+                s->csr[62] = CSR_CXBC(s);
+                s->csr[63] = CSR_CXST(s);
+            }
+            s->csr[34] = cxda & 0xffff;
+            s->csr[35] = cxda >> 16;
+#ifdef PCNET_DEBUG_X
+            printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
+#endif
+        }
+    }
+
+    if (CSR_CXDA(s)) {
+        struct pcnet_TMD tmd;
+
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+        CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
+        CSR_CXST(s) = tmd.status;
+    } else {
+        CSR_CXBC(s) = CSR_CXST(s) = 0;
+    }
+
+    return !!(CSR_CXST(s) & 0x8000);
+}
+
+int pcnet_can_receive(VLANClientState *nc)
+{
+    PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    if (CSR_STOP(s) || CSR_SPND(s))
+        return 0;
+
+    return sizeof(s->buffer)-16;
+}
+
+#define MIN_BUF_SIZE 60
+
+ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
+{
+    PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int is_padr = 0, is_bcast = 0, is_ladr = 0;
+    uint8_t buf1[60];
+    int remaining;
+    int crc_err = 0;
+    int size = size_;
+
+    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
+        (CSR_LOOP(s) && !s->looptest)) {
+        return -1;
+    }
+#ifdef PCNET_DEBUG
+    printf("pcnet_receive size=%d\n", size);
+#endif
+
+    /* if too small buffer, then expand it */
+    if (size < MIN_BUF_SIZE) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        buf = buf1;
+        size = MIN_BUF_SIZE;
+    }
+
+    if (CSR_PROM(s)
+        || (is_padr=padr_match(s, buf, size))
+        || (is_bcast=padr_bcast(s, buf, size))
+        || (is_ladr=ladr_match(s, buf, size))) {
+
+        pcnet_rdte_poll(s);
+
+        if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
+            struct pcnet_RMD rmd;
+            int rcvrc = CSR_RCVRC(s)-1,i;
+            target_phys_addr_t nrda;
+            for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
+                if (rcvrc <= 1)
+                    rcvrc = CSR_RCVRL(s);
+                nrda = s->rdra +
+                    (CSR_RCVRL(s) - rcvrc) *
+                    (BCR_SWSTYLE(s) ? 16 : 8 );
+                RMDLOAD(&rmd, nrda);
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
+#ifdef PCNET_DEBUG_RMD
+                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
+                                rcvrc, CSR_RCVRC(s));
+#endif
+                    CSR_RCVRC(s) = rcvrc;
+                    pcnet_rdte_poll(s);
+                    break;
+                }
+            }
+        }
+
+        if (!(CSR_CRST(s) & 0x8000)) {
+#ifdef PCNET_DEBUG_RMD
+            printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
+#endif
+            s->csr[0] |= 0x1000; /* Set MISS flag */
+            CSR_MISSC(s)++;
+        } else {
+            uint8_t *src = s->buffer;
+            target_phys_addr_t crda = CSR_CRDA(s);
+            struct pcnet_RMD rmd;
+            int pktcount = 0;
+
+            if (!s->looptest) {
+                memcpy(src, buf, size);
+                /* no need to compute the CRC */
+                src[size] = 0;
+                src[size + 1] = 0;
+                src[size + 2] = 0;
+                src[size + 3] = 0;
+                size += 4;
+            } else if (s->looptest == PCNET_LOOPTEST_CRC ||
+                       !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
+                uint32_t fcs = ~0;
+                uint8_t *p = src;
+
+                while (p != &src[size])
+                    CRC(fcs, *p++);
+                *(uint32_t *)p = htonl(fcs);
+                size += 4;
+            } else {
+                uint32_t fcs = ~0;
+                uint8_t *p = src;
+
+                while (p != &src[size-4])
+                    CRC(fcs, *p++);
+                crc_err = (*(uint32_t *)p != htonl(fcs));
+            }
+
+#ifdef PCNET_DEBUG_MATCH
+            PRINT_PKTHDR(buf);
+#endif
+
+            RMDLOAD(&rmd, PHYSADDR(s,crda));
+            /*if (!CSR_LAPPEN(s))*/
+                SET_FIELD(&rmd.status, RMDS, STP, 1);
+
+#define PCNET_RECV_STORE() do {                                 \
+    int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
+    target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr);          \
+    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
+    src += count; remaining -= count;                           \
+    SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
+    RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
+    pktcount++;                                                 \
+} while (0)
+
+            remaining = size;
+            PCNET_RECV_STORE();
+            if ((remaining > 0) && CSR_NRDA(s)) {
+                target_phys_addr_t nrda = CSR_NRDA(s);
+#ifdef PCNET_DEBUG_RMD
+                PRINT_RMD(&rmd);
+#endif
+                RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
+                    crda = nrda;
+                    PCNET_RECV_STORE();
+#ifdef PCNET_DEBUG_RMD
+                    PRINT_RMD(&rmd);
+#endif
+                    if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
+                        RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                        if (GET_FIELD(rmd.status, RMDS, OWN)) {
+                            crda = nrda;
+                            PCNET_RECV_STORE();
+                        }
+                    }
+                }
+            }
+
+#undef PCNET_RECV_STORE
+
+            RMDLOAD(&rmd, PHYSADDR(s,crda));
+            if (remaining == 0) {
+                SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
+                SET_FIELD(&rmd.status, RMDS, ENP, 1);
+                SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
+                SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
+                SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
+                if (crc_err) {
+                    SET_FIELD(&rmd.status, RMDS, CRC, 1);
+                    SET_FIELD(&rmd.status, RMDS, ERR, 1);
+                }
+            } else {
+                SET_FIELD(&rmd.status, RMDS, OFLO, 1);
+                SET_FIELD(&rmd.status, RMDS, BUFF, 1);
+                SET_FIELD(&rmd.status, RMDS, ERR, 1);
+            }
+            RMDSTORE(&rmd, PHYSADDR(s,crda));
+            s->csr[0] |= 0x0400;
+
+#ifdef PCNET_DEBUG
+            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
+                CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
+#endif
+#ifdef PCNET_DEBUG_RMD
+            PRINT_RMD(&rmd);
+#endif
+
+            while (pktcount--) {
+                if (CSR_RCVRC(s) <= 1)
+                    CSR_RCVRC(s) = CSR_RCVRL(s);
+                else
+                    CSR_RCVRC(s)--;
+            }
+
+            pcnet_rdte_poll(s);
+
+        }
+    }
+
+    pcnet_poll(s);
+    pcnet_update_irq(s);
+
+    return size_;
+}
+
+static void pcnet_transmit(PCNetState *s)
+{
+    target_phys_addr_t xmit_cxda = 0;
+    int count = CSR_XMTRL(s)-1;
+    int add_crc = 0;
+
+    s->xmit_pos = -1;
+
+    if (!CSR_TXON(s)) {
+        s->csr[0] &= ~0x0008;
+        return;
+    }
+
+    s->tx_busy = 1;
+
+    txagain:
+    if (pcnet_tdte_poll(s)) {
+        struct pcnet_TMD tmd;
+
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+#ifdef PCNET_DEBUG_TMD
+        printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
+        PRINT_TMD(&tmd);
+#endif
+        if (GET_FIELD(tmd.status, TMDS, STP)) {
+            s->xmit_pos = 0;
+            xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
+            if (BCR_SWSTYLE(s) != 1)
+                add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
+        }
+        if (!GET_FIELD(tmd.status, TMDS, ENP)) {
+            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+            s->xmit_pos += bcnt;
+        } else if (s->xmit_pos >= 0) {
+            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+            s->xmit_pos += bcnt;
+#ifdef PCNET_DEBUG
+            printf("pcnet_transmit size=%d\n", s->xmit_pos);
+#endif
+            if (CSR_LOOP(s)) {
+                if (BCR_SWSTYLE(s) == 1)
+                    add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
+                s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
+                pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos);
+                s->looptest = 0;
+            } else
+                if (s->nic)
+                    qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos);
+
+            s->csr[0] &= ~0x0008;   /* clear TDMD */
+            s->csr[4] |= 0x0004;    /* set TXSTRT */
+            s->xmit_pos = -1;
+        }
+
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
+        TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
+            s->csr[0] |= 0x0200;    /* set TINT */
+
+        if (CSR_XMTRC(s)<=1)
+            CSR_XMTRC(s) = CSR_XMTRL(s);
+        else
+            CSR_XMTRC(s)--;
+        if (count--)
+            goto txagain;
+
+    } else
+    if (s->xmit_pos >= 0) {
+        struct pcnet_TMD tmd;
+        TMDLOAD(&tmd, xmit_cxda);
+        SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
+        SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
+        SET_FIELD(&tmd.status, TMDS, ERR, 1);
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
+        TMDSTORE(&tmd, xmit_cxda);
+        s->csr[0] |= 0x0200;    /* set TINT */
+        if (!CSR_DXSUFLO(s)) {
+            s->csr[0] &= ~0x0010;
+        } else
+        if (count--)
+          goto txagain;
+    }
+
+    s->tx_busy = 0;
+}
+
+static void pcnet_poll(PCNetState *s)
+{
+    if (CSR_RXON(s)) {
+        pcnet_rdte_poll(s);
+    }
+
+    if (CSR_TDMD(s) ||
+        (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
+    {
+        /* prevent recursion */
+        if (s->tx_busy)
+            return;
+
+        pcnet_transmit(s);
+    }
+}
+
+static void pcnet_poll_timer(void *opaque)
+{
+    PCNetState *s = opaque;
+
+    qemu_del_timer(s->poll_timer);
+
+    if (CSR_TDMD(s)) {
+        pcnet_transmit(s);
+    }
+
+    pcnet_update_irq(s);
+
+    if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
+        uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
+        if (!s->timer || !now)
+            s->timer = now;
+        else {
+            uint64_t t = now - s->timer + CSR_POLL(s);
+            if (t > 0xffffLL) {
+                pcnet_poll(s);
+                CSR_POLL(s) = CSR_PINT(s);
+            } else
+                CSR_POLL(s) = t;
+        }
+        qemu_mod_timer(s->poll_timer,
+            pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
+    }
+}
+
+
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
+{
+    uint16_t val = new_value;
+#ifdef PCNET_DEBUG_CSR
+    printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+    switch (rap) {
+    case 0:
+        s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
+
+        s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
+
+        val = (val & 0x007f) | (s->csr[0] & 0x7f00);
+
+        /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
+        if ((val&7) == 7)
+          val &= ~3;
+
+        if (!CSR_STOP(s) && (val & 4))
+            pcnet_stop(s);
+
+        if (!CSR_INIT(s) && (val & 1))
+            pcnet_init(s);
+
+        if (!CSR_STRT(s) && (val & 2))
+            pcnet_start(s);
+
+        if (CSR_TDMD(s))
+            pcnet_transmit(s);
+
+        return;
+    case 1:
+    case 2:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 18: /* CRBAL */
+    case 19: /* CRBAU */
+    case 20: /* CXBAL */
+    case 21: /* CXBAU */
+    case 22: /* NRBAU */
+    case 23: /* NRBAU */
+    case 24:
+    case 25:
+    case 26:
+    case 27:
+    case 28:
+    case 29:
+    case 30:
+    case 31:
+    case 32:
+    case 33:
+    case 34:
+    case 35:
+    case 36:
+    case 37:
+    case 38:
+    case 39:
+    case 40: /* CRBC */
+    case 41:
+    case 42: /* CXBC */
+    case 43:
+    case 44:
+    case 45:
+    case 46: /* POLL */
+    case 47: /* POLLINT */
+    case 72:
+    case 74:
+    case 76: /* RCVRL */
+    case 78: /* XMTRL */
+    case 112:
+       if (CSR_STOP(s) || CSR_SPND(s))
+           break;
+       return;
+    case 3:
+        break;
+    case 4:
+        s->csr[4] &= ~(val & 0x026a);
+        val &= ~0x026a; val |= s->csr[4] & 0x026a;
+        break;
+    case 5:
+        s->csr[5] &= ~(val & 0x0a90);
+        val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
+        break;
+    case 16:
+        pcnet_csr_writew(s,1,val);
+        return;
+    case 17:
+        pcnet_csr_writew(s,2,val);
+        return;
+    case 58:
+        pcnet_bcr_writew(s,BCR_SWS,val);
+        break;
+    default:
+        return;
+    }
+    s->csr[rap] = val;
+}
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
+{
+    uint32_t val;
+    switch (rap) {
+    case 0:
+        pcnet_update_irq(s);
+        val = s->csr[0];
+        val |= (val & 0x7800) ? 0x8000 : 0;
+        break;
+    case 16:
+        return pcnet_csr_readw(s,1);
+    case 17:
+        return pcnet_csr_readw(s,2);
+    case 58:
+        return pcnet_bcr_readw(s,BCR_SWS);
+    case 88:
+        val = s->csr[89];
+        val <<= 16;
+        val |= s->csr[88];
+        break;
+    default:
+        val = s->csr[rap];
+    }
+#ifdef PCNET_DEBUG_CSR
+    printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+    return val;
+}
+
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
+{
+    rap &= 127;
+#ifdef PCNET_DEBUG_BCR
+    printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+    switch (rap) {
+    case BCR_SWS:
+        if (!(CSR_STOP(s) || CSR_SPND(s)))
+            return;
+        val &= ~0x0300;
+        switch (val & 0x00ff) {
+        case 0:
+            val |= 0x0200;
+            break;
+        case 1:
+            val |= 0x0100;
+            break;
+        case 2:
+        case 3:
+            val |= 0x0300;
+            break;
+        default:
+            printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
+            val = 0x0200;
+            break;
+        }
+#ifdef PCNET_DEBUG
+       printf("BCR_SWS=0x%04x\n", val);
+#endif
+    case BCR_LNKST:
+    case BCR_LED1:
+    case BCR_LED2:
+    case BCR_LED3:
+    case BCR_MC:
+    case BCR_FDC:
+    case BCR_BSBC:
+    case BCR_EECAS:
+    case BCR_PLAT:
+        s->bcr[rap] = val;
+        break;
+    default:
+        break;
+    }
+}
+
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+{
+    uint32_t val;
+    rap &= 127;
+    switch (rap) {
+    case BCR_LNKST:
+    case BCR_LED1:
+    case BCR_LED2:
+    case BCR_LED3:
+        val = s->bcr[rap] & ~0x8000;
+        val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
+        break;
+    default:
+        val = rap < 32 ? s->bcr[rap] : 0;
+        break;
+    }
+#ifdef PCNET_DEBUG_BCR
+    printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+    return val;
+}
+
+void pcnet_h_reset(void *opaque)
+{
+    PCNetState *s = opaque;
+
+    s->bcr[BCR_MSRDA] = 0x0005;
+    s->bcr[BCR_MSWRA] = 0x0005;
+    s->bcr[BCR_MC   ] = 0x0002;
+    s->bcr[BCR_LNKST] = 0x00c0;
+    s->bcr[BCR_LED1 ] = 0x0084;
+    s->bcr[BCR_LED2 ] = 0x0088;
+    s->bcr[BCR_LED3 ] = 0x0090;
+    s->bcr[BCR_FDC  ] = 0x0000;
+    s->bcr[BCR_BSBC ] = 0x9001;
+    s->bcr[BCR_EECAS] = 0x0002;
+    s->bcr[BCR_SWS  ] = 0x0200;
+    s->bcr[BCR_PLAT ] = 0xff06;
+
+    pcnet_s_reset(s);
+    pcnet_update_irq(s);
+    pcnet_poll_timer(s);
+}
+
+void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+    pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
+#endif
+    if (!BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            pcnet_csr_writew(s, s->rap, val);
+            break;
+        case 0x02:
+            s->rap = val & 0x7f;
+            break;
+        case 0x06:
+            pcnet_bcr_writew(s, s->rap, val);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+}
+
+uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = -1;
+    pcnet_poll_timer(s);
+    if (!BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            val = pcnet_csr_readw(s, s->rap);
+            break;
+        case 0x02:
+            val = s->rap;
+            break;
+        case 0x04:
+            pcnet_s_reset(s);
+            val = 0;
+            break;
+        case 0x06:
+            val = pcnet_bcr_readw(s, s->rap);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
+#endif
+    return val;
+}
+
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+    pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+    if (BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            pcnet_csr_writew(s, s->rap, val & 0xffff);
+            break;
+        case 0x04:
+            s->rap = val & 0x7f;
+            break;
+        case 0x0c:
+            pcnet_bcr_writew(s, s->rap, val & 0xffff);
+            break;
+        }
+    } else
+    if ((addr & 0x0f) == 0) {
+        /* switch device to dword i/o mode */
+        pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
+#ifdef PCNET_DEBUG_IO
+        printf("device switched into dword i/o mode\n");
+#endif
+    }
+    pcnet_update_irq(s);
+}
+
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = -1;
+    pcnet_poll_timer(s);
+    if (BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            val = pcnet_csr_readw(s, s->rap);
+            break;
+        case 0x04:
+            val = s->rap;
+            break;
+        case 0x08:
+            pcnet_s_reset(s);
+            val = 0;
+            break;
+        case 0x0c:
+            val = pcnet_bcr_readw(s, s->rap);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+    return val;
+}
+
+static bool is_version_2(void *opaque, int version_id)
+{
+    return version_id == 2;
+}
+
+const VMStateDescription vmstate_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(rap, PCNetState),
+        VMSTATE_INT32(isr, PCNetState),
+        VMSTATE_INT32(lnkst, PCNetState),
+        VMSTATE_UINT32(rdra, PCNetState),
+        VMSTATE_UINT32(tdra, PCNetState),
+        VMSTATE_BUFFER(prom, PCNetState),
+        VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
+        VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
+        VMSTATE_UINT64(timer, PCNetState),
+        VMSTATE_INT32(xmit_pos, PCNetState),
+        VMSTATE_BUFFER(buffer, PCNetState),
+        VMSTATE_UNUSED_TEST(is_version_2, 4),
+        VMSTATE_INT32(tx_busy, PCNetState),
+        VMSTATE_TIMER(poll_timer, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pcnet_common_cleanup(PCNetState *d)
+{
+    d->nic = NULL;
+}
+
+int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
+{
+    int i;
+    uint16_t checksum;
+
+    s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy at 0");
+
+    /* Initialize the PROM */
+
+    /*
+      Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
+      page 95
+    */
+    memcpy(s->prom, s->conf.macaddr.a, 6);
+    /* Reserved Location: must be 00h */
+    s->prom[6] = s->prom[7] = 0x00;
+    /* Reserved Location: must be 00h */
+    s->prom[8] = 0x00;
+    /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
+    s->prom[9] = 0x11;
+    /* User programmable space, init with 0 */
+    s->prom[10] = s->prom[11] = 0x00;
+    /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
+       and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
+    s->prom[12] = s->prom[13] = 0x00;
+    /* Must be ASCII W (57h) if compatibility to AMD
+       driver software is desired */
+    s->prom[14] = s->prom[15] = 0x57;
+
+    for (i = 0, checksum = 0; i < 16; i++) {
+        checksum += s->prom[i];
+    }
+    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/pcnet.h b/qemu-0.15.x/hw/pcnet.h
new file mode 100644
index 0000000..534bdf9
--- /dev/null
+++ b/qemu-0.15.x/hw/pcnet.h
@@ -0,0 +1,42 @@
+#define PCNET_IOPORT_SIZE       0x20
+#define PCNET_PNPMMIO_SIZE      0x20
+
+#define PCNET_LOOPTEST_CRC	1
+#define PCNET_LOOPTEST_NOCRC	2
+
+
+typedef struct PCNetState_st PCNetState;
+
+struct PCNetState_st {
+    NICState *nic;
+    NICConf conf;
+    QEMUTimer *poll_timer;
+    int rap, isr, lnkst;
+    uint32_t rdra, tdra;
+    uint8_t prom[16];
+    uint16_t csr[128];
+    uint16_t bcr[32];
+    uint64_t timer;
+    int mmio_index, xmit_pos;
+    uint8_t buffer[4096];
+    int tx_busy;
+    qemu_irq irq;
+    void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
+                         uint8_t *buf, int len, int do_bswap);
+    void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
+                          uint8_t *buf, int len, int do_bswap);
+    void *dma_opaque;
+    int looptest;
+};
+
+void pcnet_h_reset(void *opaque);
+void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
+int pcnet_can_receive(VLANClientState *nc);
+ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
+void pcnet_common_cleanup(PCNetState *d);
+int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
+extern const VMStateDescription vmstate_pcnet;
diff --git a/qemu-0.15.x/hw/pcspk.c b/qemu-0.15.x/hw/pcspk.c
new file mode 100644
index 0000000..7fa2d36
--- /dev/null
+++ b/qemu-0.15.x/hw/pcspk.c
@@ -0,0 +1,147 @@
+/*
+ * QEMU PC speaker emulation
+ *
+ * Copyright (c) 2006 Joachim Henke
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "audio/audio.h"
+#include "qemu-timer.h"
+
+#define PCSPK_BUF_LEN 1792
+#define PCSPK_SAMPLE_RATE 32000
+#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
+#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
+
+typedef struct {
+    uint8_t sample_buf[PCSPK_BUF_LEN];
+    QEMUSoundCard card;
+    SWVoiceOut *voice;
+    ISADevice *pit;
+    unsigned int pit_count;
+    unsigned int samples;
+    unsigned int play_pos;
+    int data_on;
+    int dummy_refresh_clock;
+} PCSpkState;
+
+static const char *s_spk = "pcspk";
+static PCSpkState pcspk_state;
+
+static inline void generate_samples(PCSpkState *s)
+{
+    unsigned int i;
+
+    if (s->pit_count) {
+        const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
+        const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
+
+        /* multiple of wavelength for gapless looping */
+        s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
+        for (i = 0; i < s->samples; ++i)
+            s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
+    } else {
+        s->samples = PCSPK_BUF_LEN;
+        for (i = 0; i < PCSPK_BUF_LEN; ++i)
+            s->sample_buf[i] = 128; /* silence */
+    }
+}
+
+static void pcspk_callback(void *opaque, int free)
+{
+    PCSpkState *s = opaque;
+    unsigned int n;
+
+    if (pit_get_mode(s->pit, 2) != 3)
+        return;
+
+    n = pit_get_initial_count(s->pit, 2);
+    /* avoid frequencies that are not reproducible with sample rate */
+    if (n < PCSPK_MIN_COUNT)
+        n = 0;
+
+    if (s->pit_count != n) {
+        s->pit_count = n;
+        s->play_pos = 0;
+        generate_samples(s);
+    }
+
+    while (free > 0) {
+        n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
+        n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
+        if (!n)
+            break;
+        s->play_pos = (s->play_pos + n) % s->samples;
+        free -= n;
+    }
+}
+
+int pcspk_audio_init(qemu_irq *pic)
+{
+    PCSpkState *s = &pcspk_state;
+    struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
+
+    AUD_register_card(s_spk, &s->card);
+
+    s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
+    if (!s->voice) {
+        AUD_log(s_spk, "Could not open voice\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
+{
+    PCSpkState *s = opaque;
+    int out;
+
+    s->dummy_refresh_clock ^= (1 << 4);
+    out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5;
+
+    return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
+}
+
+static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCSpkState *s = opaque;
+    const int gate = val & 1;
+
+    s->data_on = (val >> 1) & 1;
+    pit_set_gate(s->pit, 2, gate);
+    if (s->voice) {
+        if (gate) /* restart */
+            s->play_pos = 0;
+        AUD_set_active_out(s->voice, gate & s->data_on);
+    }
+}
+
+void pcspk_init(ISADevice *pit)
+{
+    PCSpkState *s = &pcspk_state;
+
+    s->pit = pit;
+    register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s);
+    register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s);
+}
diff --git a/qemu-0.15.x/hw/petalogix_ml605_mmu.c b/qemu-0.15.x/hw/petalogix_ml605_mmu.c
new file mode 100644
index 0000000..8213902
--- /dev/null
+++ b/qemu-0.15.x/hw/petalogix_ml605_mmu.c
@@ -0,0 +1,266 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan ml605
+ * board.
+ *
+ * Copyright (c) 2011 Michal Simek <monstr at monstr.eu>
+ * Copyright (c) 2011 PetaLogix
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "xilinx.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "pc.h"
+
+#include "xilinx_axidma.h"
+
+#define LMB_BRAM_SIZE  (128 * 1024)
+#define FLASH_SIZE     (32 * 1024 * 1024)
+
+static struct
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+} boot_info;
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->regs[5] = boot_info.cmdline;
+    env->regs[7] = boot_info.fdt;
+    env->sregs[SR_PC] = boot_info.bootstrap_pc;
+    env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
+    /* setup pvr to match kernel setting */
+    env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK;
+    env->pvr.regs[0] |= PVR0_USE_FPU_MASK | PVR0_ENDI;
+    env->pvr.regs[0] = (env->pvr.regs[0] & ~PVR0_VERSION_MASK) | (0x14 << 8);
+    env->pvr.regs[2] ^= PVR2_USE_FPU2_MASK;
+    env->pvr.regs[4] = 0xc56b8000;
+    env->pvr.regs[5] = 0xc56be000;
+}
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb"
+static int petalogix_load_device_tree(target_phys_addr_t addr,
+                                      uint32_t ramsize,
+                                      target_phys_addr_t initrd_base,
+                                      target_phys_addr_t initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "mb.dtb" override.  */
+    fdt = load_device_tree("mb.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            qemu_free(path);
+        }
+        if (!fdt) {
+            return 0;
+        }
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0) {
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    }
+    cpu_physical_memory_write(addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+            qemu_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x30000000LL;
+}
+
+#define MEMORY_BASEADDR 0x50000000
+#define FLASH_BASEADDR 0x86000000
+#define INTC_BASEADDR 0x81800000
+#define TIMER_BASEADDR 0x83c00000
+#define UART16550_BASEADDR 0x83e00000
+#define AXIENET_BASEADDR 0x82780000
+#define AXIDMA_BASEADDR 0x84600000
+
+static void
+petalogix_ml605_init(ram_addr_t ram_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    DeviceState *dev;
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    int i;
+    target_phys_addr_t ddr_base = MEMORY_BASEADDR;
+    ram_addr_t phys_lmb_bram;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "microblaze";
+    }
+    env = cpu_init(cpu_model);
+
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* Attach emulated BRAM through the LMB.  */
+    phys_lmb_bram = qemu_ram_alloc(NULL, "petalogix_ml605.lmb_bram",
+                                   LMB_BRAM_SIZE);
+    cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE,
+                                 phys_lmb_bram | IO_MEM_RAM);
+
+    phys_ram = qemu_ram_alloc(NULL, "petalogix_ml605.ram", ram_size);
+    cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "petalogix_ml605.flash", FLASH_SIZE);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* 5th parameter 2 means bank-width
+     * 10th paremeter 0 means little-endian */
+    pflash_cfi01_register(FLASH_BASEADDR, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          2, 0x89, 0x18, 0x0000, 0x0, 0);
+
+
+    cpu_irq = microblaze_pic_init_cpu(env);
+    dev = xilinx_intc_create(INTC_BASEADDR, cpu_irq[0], 4);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(UART16550_BASEADDR + 0x1000, 2, irq[5], 115200,
+                   serial_hds[0], 1, 0);
+
+    /* 2 timers at irq 2 @ 100 Mhz.  */
+    xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
+
+    /* axi ethernet and dma initialization. TODO: Dynamically connect them.  */
+    {
+        static struct XilinxDMAConnection dmach;
+
+        xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
+                                  irq[3], 0x1000, 0x1000);
+        xilinx_axiethernetdma_create(&dmach, 0x84600000,
+                                     irq[1], irq[0], 100 * 1000000);
+    }
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        uint32_t base32;
+        int big_endian = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        big_endian = 1;
+#endif
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high,
+                               big_endian, ELF_MACHINE, 0);
+        base32 = entry;
+        if (base32 == 0xc0000000) {
+            kernel_size = load_elf(kernel_filename, translate_kernel_address,
+                                   NULL, &entry, NULL, NULL,
+                                   big_endian, ELF_MACHINE, 0);
+        }
+        /* Always boot into physical ram.  */
+        boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+        /* If it wasn't an ELF image, try an u-boot image.  */
+        if (kernel_size < 0) {
+            target_phys_addr_t uentry, loadaddr;
+
+            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+            boot_info.bootstrap_pc = uentry;
+            high = (loadaddr + kernel_size + 3) & ~3;
+        }
+
+        /* Not an ELF image nor an u-boot image, try a RAW image.  */
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ddr_base,
+                                              ram_size);
+            boot_info.bootstrap_pc = ddr_base;
+            high = (ddr_base + kernel_size + 3) & ~3;
+        }
+
+        boot_info.cmdline = high + 4096;
+        if (kernel_cmdline && strlen(kernel_cmdline)) {
+            pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
+        }
+        /* Provide a device-tree.  */
+        boot_info.fdt = boot_info.cmdline + 4096;
+        petalogix_load_device_tree(boot_info.fdt, ram_size,
+                                   0, 0,
+                                   kernel_cmdline);
+    }
+}
+
+static QEMUMachine petalogix_ml605_machine = {
+    .name = "petalogix-ml605",
+    .desc = "PetaLogix linux refdesign for xilinx ml605 little endian",
+    .init = petalogix_ml605_init,
+    .is_default = 0
+};
+
+static void petalogix_ml605_machine_init(void)
+{
+    qemu_register_machine(&petalogix_ml605_machine);
+}
+
+machine_init(petalogix_ml605_machine_init);
diff --git a/qemu-0.15.x/hw/petalogix_s3adsp1800_mmu.c b/qemu-0.15.x/hw/petalogix_s3adsp1800_mmu.c
new file mode 100644
index 0000000..4dcdfbd
--- /dev/null
+++ b/qemu-0.15.x/hw/petalogix_s3adsp1800_mmu.c
@@ -0,0 +1,230 @@
+/*
+ * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800
+ * boards.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "xilinx.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+
+#define LMB_BRAM_SIZE  (128 * 1024)
+#define FLASH_SIZE     (16 * 1024 * 1024)
+
+static struct
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+} boot_info;
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->regs[5] = boot_info.cmdline;
+    env->regs[7] = boot_info.fdt;
+    env->sregs[SR_PC] = boot_info.bootstrap_pc;
+}
+
+#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb"
+static int petalogix_load_device_tree(target_phys_addr_t addr,
+                                      uint32_t ramsize,
+                                      target_phys_addr_t initrd_base,
+                                      target_phys_addr_t initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "mb.dtb" override.  */
+    fdt = load_device_tree("mb.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            qemu_free(path);
+        }
+        if (!fdt)
+            return 0;
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+	    qemu_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0x30000000LL;
+}
+
+static void
+petalogix_s3adsp1800_init(ram_addr_t ram_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    DeviceState *dev;
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    int i;
+    target_phys_addr_t ddr_base = 0x90000000;
+    ram_addr_t phys_lmb_bram;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "microblaze";
+    }
+    env = cpu_init(cpu_model);
+
+    env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family.  */
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* Attach emulated BRAM through the LMB.  */
+    phys_lmb_bram = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.lmb_bram",
+                                   LMB_BRAM_SIZE);
+    cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE,
+                                 phys_lmb_bram | IO_MEM_RAM);
+
+    phys_ram = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.ram", ram_size);
+    cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(0xa0000000, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+    cpu_irq = microblaze_pic_init_cpu(env);
+    dev = xilinx_intc_create(0x81800000, cpu_irq[0], 2);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    sysbus_create_simple("xilinx,uartlite", 0x84000000, irq[3]);
+    /* 2 timers at irq 2 @ 62 Mhz.  */
+    xilinx_timer_create(0x83c00000, irq[0], 2, 62 * 1000000);
+    xilinx_ethlite_create(&nd_table[0], 0x81000000, irq[1], 0, 0);
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        uint32_t base32;
+        int big_endian = 0;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        big_endian = 1;
+#endif
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high,
+                               big_endian, ELF_MACHINE, 0);
+        base32 = entry;
+        if (base32 == 0xc0000000) {
+            kernel_size = load_elf(kernel_filename, translate_kernel_address,
+                                   NULL, &entry, NULL, NULL,
+                                   big_endian, ELF_MACHINE, 0);
+        }
+        /* Always boot into physical ram.  */
+        boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+        /* If it wasn't an ELF image, try an u-boot image.  */
+        if (kernel_size < 0) {
+            target_phys_addr_t uentry, loadaddr;
+
+            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+            boot_info.bootstrap_pc = uentry;
+            high = (loadaddr + kernel_size + 3) & ~3;
+        }
+
+        /* Not an ELF image nor an u-boot image, try a RAW image.  */
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ddr_base,
+                                              ram_size);
+            boot_info.bootstrap_pc = ddr_base;
+            high = (ddr_base + kernel_size + 3) & ~3;
+        }
+
+        boot_info.cmdline = high + 4096;
+        if (kernel_cmdline && strlen(kernel_cmdline)) {
+            pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
+        }
+        /* Provide a device-tree.  */
+        boot_info.fdt = boot_info.cmdline + 4096; 
+        petalogix_load_device_tree(boot_info.fdt, ram_size,
+                                   0, 0,
+                                   kernel_cmdline);
+    }
+}
+
+static QEMUMachine petalogix_s3adsp1800_machine = {
+    .name = "petalogix-s3adsp1800",
+    .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800",
+    .init = petalogix_s3adsp1800_init,
+    .is_default = 1
+};
+
+static void petalogix_s3adsp1800_machine_init(void)
+{
+    qemu_register_machine(&petalogix_s3adsp1800_machine);
+}
+
+machine_init(petalogix_s3adsp1800_machine_init);
diff --git a/qemu-0.15.x/hw/pflash_cfi01.c b/qemu-0.15.x/hw/pflash_cfi01.c
new file mode 100644
index 0000000..90fdc84
--- /dev/null
+++ b/qemu-0.15.x/hw/pflash_cfi01.c
@@ -0,0 +1,726 @@
+/*
+ *  CFI parallel flash with Intel command set emulation
+ *
+ *  Copyright (c) 2006 Thorsten Zitterell
+ *  Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
+ * Supported commands/modes are:
+ * - flash read
+ * - flash write
+ * - flash ID read
+ * - sector erase
+ * - CFI queries
+ *
+ * It does not support timings
+ * It does not support flash interleaving
+ * It does not implement software data protection as found in many real chips
+ * It does not implement erase suspend/resume commands
+ * It does not implement multiple sectors erase
+ *
+ * It does not implement much more ...
+ */
+
+#include "hw.h"
+#include "flash.h"
+#include "block.h"
+#include "qemu-timer.h"
+
+#define PFLASH_BUG(fmt, ...) \
+do { \
+    printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
+    exit(1); \
+} while(0)
+
+/* #define PFLASH_DEBUG */
+#ifdef PFLASH_DEBUG
+#define DPRINTF(fmt, ...)                          \
+do {                                               \
+    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+struct pflash_t {
+    BlockDriverState *bs;
+    target_phys_addr_t base;
+    target_phys_addr_t sector_len;
+    target_phys_addr_t total_len;
+    int width;
+    int wcycle; /* if 0, the flash is read normally */
+    int bypass;
+    int ro;
+    uint8_t cmd;
+    uint8_t status;
+    uint16_t ident[4];
+    uint8_t cfi_len;
+    uint8_t cfi_table[0x52];
+    target_phys_addr_t counter;
+    unsigned int writeblock_size;
+    QEMUTimer *timer;
+    ram_addr_t off;
+    int fl_mem;
+    void *storage;
+};
+
+static void pflash_timer (void *opaque)
+{
+    pflash_t *pfl = opaque;
+
+    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
+    /* Reset flash */
+    pfl->status ^= 0x80;
+    if (pfl->bypass) {
+        pfl->wcycle = 2;
+    } else {
+        cpu_register_physical_memory(pfl->base, pfl->total_len,
+                        pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+        pfl->wcycle = 0;
+    }
+    pfl->cmd = 0;
+}
+
+static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
+                             int width, int be)
+{
+    target_phys_addr_t boff;
+    uint32_t ret;
+    uint8_t *p;
+
+    ret = -1;
+    boff = offset & 0xFF; /* why this here ?? */
+
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+
+#if 0
+    DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
+            __func__, offset, pfl->cmd, width);
+#endif
+    switch (pfl->cmd) {
+    case 0x00:
+        /* Flash area read */
+        p = pfl->storage;
+        switch (width) {
+        case 1:
+            ret = p[offset];
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
+                    __func__, offset, ret);
+            break;
+        case 2:
+            if (be) {
+                ret = p[offset] << 8;
+                ret |= p[offset + 1];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+            }
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
+                    __func__, offset, ret);
+            break;
+        case 4:
+            if (be) {
+                ret = p[offset] << 24;
+                ret |= p[offset + 1] << 16;
+                ret |= p[offset + 2] << 8;
+                ret |= p[offset + 3];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+                ret |= p[offset + 1] << 8;
+                ret |= p[offset + 2] << 16;
+                ret |= p[offset + 3] << 24;
+            }
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
+                    __func__, offset, ret);
+            break;
+        default:
+            DPRINTF("BUG in %s\n", __func__);
+        }
+
+        break;
+    case 0x20: /* Block erase */
+    case 0x50: /* Clear status register */
+    case 0x60: /* Block /un)lock */
+    case 0x70: /* Status Register */
+    case 0xe8: /* Write block */
+        /* Status register read */
+        ret = pfl->status;
+        DPRINTF("%s: status %x\n", __func__, ret);
+        break;
+    case 0x90:
+        switch (boff) {
+        case 0:
+            ret = pfl->ident[0] << 8 | pfl->ident[1];
+            DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
+            break;
+        case 1:
+            ret = pfl->ident[2] << 8 | pfl->ident[3];
+            DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
+            break;
+        default:
+            DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff);
+            ret = 0;
+            break;
+        }
+        break;
+    case 0x98: /* Query mode */
+        if (boff > pfl->cfi_len)
+            ret = 0;
+        else
+            ret = pfl->cfi_table[boff];
+        break;
+    default:
+        /* This should never happen : reset state & treat it as a read */
+        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+        pfl->wcycle = 0;
+        pfl->cmd = 0;
+    }
+    return ret;
+}
+
+/* update flash content on disk */
+static void pflash_update(pflash_t *pfl, int offset,
+                          int size)
+{
+    int offset_end;
+    if (pfl->bs) {
+        offset_end = offset + size;
+        /* round to sectors */
+        offset = offset >> 9;
+        offset_end = (offset_end + 511) >> 9;
+        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
+                   offset_end - offset);
+    }
+}
+
+static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset,
+                                     uint32_t value, int width, int be)
+{
+    uint8_t *p = pfl->storage;
+
+    DPRINTF("%s: block write offset " TARGET_FMT_plx
+            " value %x counter " TARGET_FMT_plx "\n",
+            __func__, offset, value, pfl->counter);
+    switch (width) {
+    case 1:
+        p[offset] = value;
+        break;
+    case 2:
+        if (be) {
+            p[offset] = value >> 8;
+            p[offset + 1] = value;
+        } else {
+            p[offset] = value;
+            p[offset + 1] = value >> 8;
+        }
+        break;
+    case 4:
+        if (be) {
+            p[offset] = value >> 24;
+            p[offset + 1] = value >> 16;
+            p[offset + 2] = value >> 8;
+            p[offset + 3] = value;
+        } else {
+            p[offset] = value;
+            p[offset + 1] = value >> 8;
+            p[offset + 2] = value >> 16;
+            p[offset + 3] = value >> 24;
+        }
+        break;
+    }
+
+}
+
+static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
+                         uint32_t value, int width, int be)
+{
+    uint8_t *p;
+    uint8_t cmd;
+
+    cmd = value;
+
+    DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
+            __func__, offset, value, width, pfl->wcycle);
+
+    if (!pfl->wcycle) {
+        /* Set the device in I/O access mode */
+        cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+    }
+
+    switch (pfl->wcycle) {
+    case 0:
+        /* read mode */
+        switch (cmd) {
+        case 0x00: /* ??? */
+            goto reset_flash;
+        case 0x10: /* Single Byte Program */
+        case 0x40: /* Single Byte Program */
+            DPRINTF("%s: Single Byte Program\n", __func__);
+            break;
+        case 0x20: /* Block erase */
+            p = pfl->storage;
+            offset &= ~(pfl->sector_len - 1);
+
+            DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
+                    TARGET_FMT_plx "\n",
+                    __func__, offset, pfl->sector_len);
+
+            memset(p + offset, 0xff, pfl->sector_len);
+            pflash_update(pfl, offset, pfl->sector_len);
+            pfl->status |= 0x80; /* Ready! */
+            break;
+        case 0x50: /* Clear status bits */
+            DPRINTF("%s: Clear status bits\n", __func__);
+            pfl->status = 0x0;
+            goto reset_flash;
+        case 0x60: /* Block (un)lock */
+            DPRINTF("%s: Block unlock\n", __func__);
+            break;
+        case 0x70: /* Status Register */
+            DPRINTF("%s: Read status register\n", __func__);
+            pfl->cmd = cmd;
+            return;
+        case 0x90: /* Read Device ID */
+            DPRINTF("%s: Read Device information\n", __func__);
+            pfl->cmd = cmd;
+            return;
+        case 0x98: /* CFI query */
+            DPRINTF("%s: CFI query\n", __func__);
+            break;
+        case 0xe8: /* Write to buffer */
+            DPRINTF("%s: Write to buffer\n", __func__);
+            pfl->status |= 0x80; /* Ready! */
+            break;
+        case 0xff: /* Read array mode */
+            DPRINTF("%s: Read array mode\n", __func__);
+            goto reset_flash;
+        default:
+            goto error_flash;
+        }
+        pfl->wcycle++;
+        pfl->cmd = cmd;
+        return;
+    case 1:
+        switch (pfl->cmd) {
+        case 0x10: /* Single Byte Program */
+        case 0x40: /* Single Byte Program */
+            DPRINTF("%s: Single Byte Program\n", __func__);
+            pflash_data_write(pfl, offset, value, width, be);
+            pflash_update(pfl, offset, width);
+            pfl->status |= 0x80; /* Ready! */
+            pfl->wcycle = 0;
+        break;
+        case 0x20: /* Block erase */
+        case 0x28:
+            if (cmd == 0xd0) { /* confirm */
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0xff) { /* read array mode */
+                goto reset_flash;
+            } else
+                goto error_flash;
+
+            break;
+        case 0xe8:
+            DPRINTF("%s: block write of %x bytes\n", __func__, value);
+            pfl->counter = value;
+            pfl->wcycle++;
+            break;
+        case 0x60:
+            if (cmd == 0xd0) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0x01) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0xff) {
+                goto reset_flash;
+            } else {
+                DPRINTF("%s: Unknown (un)locking command\n", __func__);
+                goto reset_flash;
+            }
+            break;
+        case 0x98:
+            if (cmd == 0xff) {
+                goto reset_flash;
+            } else {
+                DPRINTF("%s: leaving query mode\n", __func__);
+            }
+            break;
+        default:
+            goto error_flash;
+        }
+        return;
+    case 2:
+        switch (pfl->cmd) {
+        case 0xe8: /* Block write */
+            pflash_data_write(pfl, offset, value, width, be);
+
+            pfl->status |= 0x80;
+
+            if (!pfl->counter) {
+                target_phys_addr_t mask = pfl->writeblock_size - 1;
+                mask = ~mask;
+
+                DPRINTF("%s: block write finished\n", __func__);
+                pfl->wcycle++;
+                /* Flush the entire write buffer onto backing storage.  */
+                pflash_update(pfl, offset & mask, pfl->writeblock_size);
+            }
+
+            pfl->counter--;
+            break;
+        default:
+            goto error_flash;
+        }
+        return;
+    case 3: /* Confirm mode */
+        switch (pfl->cmd) {
+        case 0xe8: /* Block write */
+            if (cmd == 0xd0) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else {
+                DPRINTF("%s: unknown command for \"write block\"\n", __func__);
+                PFLASH_BUG("Write block confirm");
+                goto reset_flash;
+            }
+            break;
+        default:
+            goto error_flash;
+        }
+        return;
+    default:
+        /* Should never happen */
+        DPRINTF("%s: invalid write state\n",  __func__);
+        goto reset_flash;
+    }
+    return;
+
+ error_flash:
+    printf("%s: Unimplemented flash cmd sequence "
+           "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
+           __func__, offset, pfl->wcycle, pfl->cmd, value);
+
+ reset_flash:
+    cpu_register_physical_memory(pfl->base, pfl->total_len,
+                    pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+
+    pfl->bypass = 0;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    return;
+}
+
+
+static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
+{
+    return pflash_read(opaque, addr, 1, 1);
+}
+
+static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
+{
+    return pflash_read(opaque, addr, 1, 0);
+}
+
+static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 1);
+}
+
+static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 0);
+}
+
+static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 1);
+}
+
+static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 0);
+}
+
+static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 1);
+}
+
+static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 0);
+}
+
+static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 1);
+}
+
+static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 0);
+}
+
+static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 1);
+}
+
+static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 0);
+}
+
+static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
+    &pflash_writeb_be,
+    &pflash_writew_be,
+    &pflash_writel_be,
+};
+
+static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
+    &pflash_readb_be,
+    &pflash_readw_be,
+    &pflash_readl_be,
+};
+
+static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
+    &pflash_writeb_le,
+    &pflash_writew_le,
+    &pflash_writel_le,
+};
+
+static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
+    &pflash_readb_le,
+    &pflash_readw_le,
+    &pflash_readl_le,
+};
+
+/* Count trailing zeroes of a 32 bits quantity */
+static int ctz32 (uint32_t n)
+{
+    int ret;
+
+    ret = 0;
+    if (!(n & 0xFFFF)) {
+        ret += 16;
+        n = n >> 16;
+    }
+    if (!(n & 0xFF)) {
+        ret += 8;
+        n = n >> 8;
+    }
+    if (!(n & 0xF)) {
+        ret += 4;
+        n = n >> 4;
+    }
+    if (!(n & 0x3)) {
+        ret += 2;
+        n = n >> 2;
+    }
+    if (!(n & 0x1)) {
+        ret++;
+#if 0 /* This is not necessary as n is never 0 */
+        n = n >> 1;
+#endif
+    }
+#if 0 /* This is not necessary as n is never 0 */
+    if (!n)
+        ret++;
+#endif
+
+    return ret;
+}
+
+pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3,
+                                int be)
+{
+    pflash_t *pfl;
+    target_phys_addr_t total_len;
+    int ret;
+
+    total_len = sector_len * nb_blocs;
+
+    /* XXX: to be fixed */
+#if 0
+    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
+        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
+        return NULL;
+#endif
+
+    pfl = qemu_mallocz(sizeof(pflash_t));
+
+    /* FIXME: Allocate ram ourselves.  */
+    pfl->storage = qemu_get_ram_ptr(off);
+    if (be) {
+        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
+                                             pflash_write_ops_be, pfl,
+                                             DEVICE_NATIVE_ENDIAN);
+    } else {
+        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
+                                             pflash_write_ops_le, pfl,
+                                             DEVICE_NATIVE_ENDIAN);
+    }
+    pfl->off = off;
+    cpu_register_physical_memory(base, total_len,
+                    off | pfl->fl_mem | IO_MEM_ROMD);
+
+    pfl->bs = bs;
+    if (pfl->bs) {
+        /* read the initial flash content */
+        ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
+        if (ret < 0) {
+            cpu_unregister_io_memory(pfl->fl_mem);
+            qemu_free(pfl);
+            return NULL;
+        }
+    }
+#if 0 /* XXX: there should be a bit to set up read-only,
+       *      the same way the hardware does (with WP pin).
+       */
+    pfl->ro = 1;
+#else
+    pfl->ro = 0;
+#endif
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
+    pfl->base = base;
+    pfl->sector_len = sector_len;
+    pfl->total_len = total_len;
+    pfl->width = width;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    pfl->status = 0;
+    pfl->ident[0] = id0;
+    pfl->ident[1] = id1;
+    pfl->ident[2] = id2;
+    pfl->ident[3] = id3;
+    /* Hardcoded CFI table */
+    pfl->cfi_len = 0x52;
+    /* Standard "QRY" string */
+    pfl->cfi_table[0x10] = 'Q';
+    pfl->cfi_table[0x11] = 'R';
+    pfl->cfi_table[0x12] = 'Y';
+    /* Command set (Intel) */
+    pfl->cfi_table[0x13] = 0x01;
+    pfl->cfi_table[0x14] = 0x00;
+    /* Primary extended table address (none) */
+    pfl->cfi_table[0x15] = 0x31;
+    pfl->cfi_table[0x16] = 0x00;
+    /* Alternate command set (none) */
+    pfl->cfi_table[0x17] = 0x00;
+    pfl->cfi_table[0x18] = 0x00;
+    /* Alternate extended table (none) */
+    pfl->cfi_table[0x19] = 0x00;
+    pfl->cfi_table[0x1A] = 0x00;
+    /* Vcc min */
+    pfl->cfi_table[0x1B] = 0x45;
+    /* Vcc max */
+    pfl->cfi_table[0x1C] = 0x55;
+    /* Vpp min (no Vpp pin) */
+    pfl->cfi_table[0x1D] = 0x00;
+    /* Vpp max (no Vpp pin) */
+    pfl->cfi_table[0x1E] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x1F] = 0x07;
+    /* Timeout for min size buffer write */
+    pfl->cfi_table[0x20] = 0x07;
+    /* Typical timeout for block erase */
+    pfl->cfi_table[0x21] = 0x0a;
+    /* Typical timeout for full chip erase (4096 ms) */
+    pfl->cfi_table[0x22] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x23] = 0x04;
+    /* Max timeout for buffer write */
+    pfl->cfi_table[0x24] = 0x04;
+    /* Max timeout for block erase */
+    pfl->cfi_table[0x25] = 0x04;
+    /* Max timeout for chip erase */
+    pfl->cfi_table[0x26] = 0x00;
+    /* Device size */
+    pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
+    /* Flash device interface (8 & 16 bits) */
+    pfl->cfi_table[0x28] = 0x02;
+    pfl->cfi_table[0x29] = 0x00;
+    /* Max number of bytes in multi-bytes write */
+    if (width == 1) {
+        pfl->cfi_table[0x2A] = 0x08;
+    } else {
+        pfl->cfi_table[0x2A] = 0x0B;
+    }
+    pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
+
+    pfl->cfi_table[0x2B] = 0x00;
+    /* Number of erase block regions (uniform) */
+    pfl->cfi_table[0x2C] = 0x01;
+    /* Erase block region 1 */
+    pfl->cfi_table[0x2D] = nb_blocs - 1;
+    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
+    pfl->cfi_table[0x2F] = sector_len >> 8;
+    pfl->cfi_table[0x30] = sector_len >> 16;
+
+    /* Extended */
+    pfl->cfi_table[0x31] = 'P';
+    pfl->cfi_table[0x32] = 'R';
+    pfl->cfi_table[0x33] = 'I';
+
+    pfl->cfi_table[0x34] = '1';
+    pfl->cfi_table[0x35] = '1';
+
+    pfl->cfi_table[0x36] = 0x00;
+    pfl->cfi_table[0x37] = 0x00;
+    pfl->cfi_table[0x38] = 0x00;
+    pfl->cfi_table[0x39] = 0x00;
+
+    pfl->cfi_table[0x3a] = 0x00;
+
+    pfl->cfi_table[0x3b] = 0x00;
+    pfl->cfi_table[0x3c] = 0x00;
+
+    return pfl;
+}
diff --git a/qemu-0.15.x/hw/pflash_cfi02.c b/qemu-0.15.x/hw/pflash_cfi02.c
new file mode 100644
index 0000000..725cd1e
--- /dev/null
+++ b/qemu-0.15.x/hw/pflash_cfi02.c
@@ -0,0 +1,745 @@
+/*
+ *  CFI parallel flash with AMD command set emulation
+ *
+ *  Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
+ * Supported commands/modes are:
+ * - flash read
+ * - flash write
+ * - flash ID read
+ * - sector erase
+ * - chip erase
+ * - unlock bypass command
+ * - CFI queries
+ *
+ * It does not support flash interleaving.
+ * It does not implement boot blocs with reduced size
+ * It does not implement software data protection as found in many real chips
+ * It does not implement erase suspend/resume commands
+ * It does not implement multiple sectors erase
+ */
+
+#include "hw.h"
+#include "flash.h"
+#include "qemu-timer.h"
+#include "block.h"
+
+//#define PFLASH_DEBUG
+#ifdef PFLASH_DEBUG
+#define DPRINTF(fmt, ...)                          \
+do {                                               \
+    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
+struct pflash_t {
+    BlockDriverState *bs;
+    target_phys_addr_t base;
+    uint32_t sector_len;
+    uint32_t chip_len;
+    int mappings;
+    int width;
+    int wcycle; /* if 0, the flash is read normally */
+    int bypass;
+    int ro;
+    uint8_t cmd;
+    uint8_t status;
+    uint16_t ident[4];
+    uint16_t unlock_addr[2];
+    uint8_t cfi_len;
+    uint8_t cfi_table[0x52];
+    QEMUTimer *timer;
+    ram_addr_t off;
+    int fl_mem;
+    int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
+    void *storage;
+};
+
+static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+{
+    unsigned long phys_offset = pfl->fl_mem;
+    int i;
+
+    if (rom_mode)
+        phys_offset |= pfl->off | IO_MEM_ROMD;
+    pfl->rom_mode = rom_mode;
+
+    for (i = 0; i < pfl->mappings; i++)
+        cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
+                                     pfl->chip_len, phys_offset);
+}
+
+static void pflash_timer (void *opaque)
+{
+    pflash_t *pfl = opaque;
+
+    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
+    /* Reset flash */
+    pfl->status ^= 0x80;
+    if (pfl->bypass) {
+        pfl->wcycle = 2;
+    } else {
+        pflash_register_memory(pfl, 1);
+        pfl->wcycle = 0;
+    }
+    pfl->cmd = 0;
+}
+
+static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
+                             int width, int be)
+{
+    target_phys_addr_t boff;
+    uint32_t ret;
+    uint8_t *p;
+
+    DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
+    ret = -1;
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
+    }
+    offset &= pfl->chip_len - 1;
+    boff = offset & 0xFF;
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+    switch (pfl->cmd) {
+    default:
+        /* This should never happen : reset state & treat it as a read*/
+        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+        pfl->wcycle = 0;
+        pfl->cmd = 0;
+    case 0x80:
+        /* We accept reads during second unlock sequence... */
+    case 0x00:
+    flash_read:
+        /* Flash area read */
+        p = pfl->storage;
+        switch (width) {
+        case 1:
+            ret = p[offset];
+//            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
+            break;
+        case 2:
+            if (be) {
+                ret = p[offset] << 8;
+                ret |= p[offset + 1];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+            }
+//            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
+            break;
+        case 4:
+            if (be) {
+                ret = p[offset] << 24;
+                ret |= p[offset + 1] << 16;
+                ret |= p[offset + 2] << 8;
+                ret |= p[offset + 3];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+                ret |= p[offset + 2] << 16;
+                ret |= p[offset + 3] << 24;
+            }
+//            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
+            break;
+        }
+        break;
+    case 0x90:
+        /* flash ID read */
+        switch (boff) {
+        case 0x00:
+        case 0x01:
+            ret = pfl->ident[boff & 0x01];
+            break;
+        case 0x02:
+            ret = 0x00; /* Pretend all sectors are unprotected */
+            break;
+        case 0x0E:
+        case 0x0F:
+            if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
+                goto flash_read;
+            ret = pfl->ident[2 + (boff & 0x01)];
+            break;
+        default:
+            goto flash_read;
+        }
+        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
+        break;
+    case 0xA0:
+    case 0x10:
+    case 0x30:
+        /* Status register read */
+        ret = pfl->status;
+        DPRINTF("%s: status %x\n", __func__, ret);
+        /* Toggle bit 6 */
+        pfl->status ^= 0x40;
+        break;
+    case 0x98:
+        /* CFI query mode */
+        if (boff > pfl->cfi_len)
+            ret = 0;
+        else
+            ret = pfl->cfi_table[boff];
+        break;
+    }
+
+    return ret;
+}
+
+/* update flash content on disk */
+static void pflash_update(pflash_t *pfl, int offset,
+                          int size)
+{
+    int offset_end;
+    if (pfl->bs) {
+        offset_end = offset + size;
+        /* round to sectors */
+        offset = offset >> 9;
+        offset_end = (offset_end + 511) >> 9;
+        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
+                   offset_end - offset);
+    }
+}
+
+static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
+                          uint32_t value, int width, int be)
+{
+    target_phys_addr_t boff;
+    uint8_t *p;
+    uint8_t cmd;
+
+    cmd = value;
+    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
+#if 0
+        DPRINTF("%s: flash reset asked (%02x %02x)\n",
+                __func__, pfl->cmd, cmd);
+#endif
+        goto reset_flash;
+    }
+    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
+            offset, value, width, pfl->wcycle);
+    offset &= pfl->chip_len - 1;
+
+    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
+            offset, value, width);
+    boff = offset & (pfl->sector_len - 1);
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+    switch (pfl->wcycle) {
+    case 0:
+        /* Set the device in I/O access mode if required */
+        if (pfl->rom_mode)
+            pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
+        /* We're in read mode */
+    check_unlock0:
+        if (boff == 0x55 && cmd == 0x98) {
+        enter_CFI_mode:
+            /* Enter CFI query mode */
+            pfl->wcycle = 7;
+            pfl->cmd = 0x98;
+            return;
+        }
+        if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
+            DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
+                    __func__, boff, cmd, pfl->unlock_addr[0]);
+            goto reset_flash;
+        }
+        DPRINTF("%s: unlock sequence started\n", __func__);
+        break;
+    case 1:
+        /* We started an unlock sequence */
+    check_unlock1:
+        if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
+            DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
+                    boff, cmd);
+            goto reset_flash;
+        }
+        DPRINTF("%s: unlock sequence done\n", __func__);
+        break;
+    case 2:
+        /* We finished an unlock sequence */
+        if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
+            DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
+                    boff, cmd);
+            goto reset_flash;
+        }
+        switch (cmd) {
+        case 0x20:
+            pfl->bypass = 1;
+            goto do_bypass;
+        case 0x80:
+        case 0x90:
+        case 0xA0:
+            pfl->cmd = cmd;
+            DPRINTF("%s: starting command %02x\n", __func__, cmd);
+            break;
+        default:
+            DPRINTF("%s: unknown command %02x\n", __func__, cmd);
+            goto reset_flash;
+        }
+        break;
+    case 3:
+        switch (pfl->cmd) {
+        case 0x80:
+            /* We need another unlock sequence */
+            goto check_unlock0;
+        case 0xA0:
+            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
+                    __func__, offset, value, width);
+            p = pfl->storage;
+            switch (width) {
+            case 1:
+                p[offset] &= value;
+                pflash_update(pfl, offset, 1);
+                break;
+            case 2:
+                if (be) {
+                    p[offset] &= value >> 8;
+                    p[offset + 1] &= value;
+                } else {
+                    p[offset] &= value;
+                    p[offset + 1] &= value >> 8;
+                }
+                pflash_update(pfl, offset, 2);
+                break;
+            case 4:
+                if (be) {
+                    p[offset] &= value >> 24;
+                    p[offset + 1] &= value >> 16;
+                    p[offset + 2] &= value >> 8;
+                    p[offset + 3] &= value;
+                } else {
+                    p[offset] &= value;
+                    p[offset + 1] &= value >> 8;
+                    p[offset + 2] &= value >> 16;
+                    p[offset + 3] &= value >> 24;
+                }
+                pflash_update(pfl, offset, 4);
+                break;
+            }
+            pfl->status = 0x00 | ~(value & 0x80);
+            /* Let's pretend write is immediate */
+            if (pfl->bypass)
+                goto do_bypass;
+            goto reset_flash;
+        case 0x90:
+            if (pfl->bypass && cmd == 0x00) {
+                /* Unlock bypass reset */
+                goto reset_flash;
+            }
+            /* We can enter CFI query mode from autoselect mode */
+            if (boff == 0x55 && cmd == 0x98)
+                goto enter_CFI_mode;
+            /* No break here */
+        default:
+            DPRINTF("%s: invalid write for command %02x\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+    case 4:
+        switch (pfl->cmd) {
+        case 0xA0:
+            /* Ignore writes while flash data write is occurring */
+            /* As we suppose write is immediate, this should never happen */
+            return;
+        case 0x80:
+            goto check_unlock1;
+        default:
+            /* Should never happen */
+            DPRINTF("%s: invalid command state %02x (wc 4)\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+        break;
+    case 5:
+        switch (cmd) {
+        case 0x10:
+            if (boff != pfl->unlock_addr[0]) {
+                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
+                        __func__, offset);
+                goto reset_flash;
+            }
+            /* Chip erase */
+            DPRINTF("%s: start chip erase\n", __func__);
+            memset(pfl->storage, 0xFF, pfl->chip_len);
+            pfl->status = 0x00;
+            pflash_update(pfl, 0, pfl->chip_len);
+            /* Let's wait 5 seconds before chip erase is done */
+            qemu_mod_timer(pfl->timer,
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
+            break;
+        case 0x30:
+            /* Sector erase */
+            p = pfl->storage;
+            offset &= ~(pfl->sector_len - 1);
+            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
+                    offset);
+            memset(p + offset, 0xFF, pfl->sector_len);
+            pflash_update(pfl, offset, pfl->sector_len);
+            pfl->status = 0x00;
+            /* Let's wait 1/2 second before sector erase is done */
+            qemu_mod_timer(pfl->timer,
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
+            break;
+        default:
+            DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
+            goto reset_flash;
+        }
+        pfl->cmd = cmd;
+        break;
+    case 6:
+        switch (pfl->cmd) {
+        case 0x10:
+            /* Ignore writes during chip erase */
+            return;
+        case 0x30:
+            /* Ignore writes during sector erase */
+            return;
+        default:
+            /* Should never happen */
+            DPRINTF("%s: invalid command state %02x (wc 6)\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+        break;
+    case 7: /* Special value for CFI queries */
+        DPRINTF("%s: invalid write in CFI query mode\n", __func__);
+        goto reset_flash;
+    default:
+        /* Should never happen */
+        DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
+        goto reset_flash;
+    }
+    pfl->wcycle++;
+
+    return;
+
+    /* Reset flash */
+ reset_flash:
+    pfl->bypass = 0;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    return;
+
+ do_bypass:
+    pfl->wcycle = 2;
+    pfl->cmd = 0;
+    return;
+}
+
+
+static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
+{
+    return pflash_read(opaque, addr, 1, 1);
+}
+
+static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
+{
+    return pflash_read(opaque, addr, 1, 0);
+}
+
+static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 1);
+}
+
+static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 0);
+}
+
+static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 1);
+}
+
+static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 0);
+}
+
+static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 1);
+}
+
+static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 0);
+}
+
+static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 1);
+}
+
+static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 0);
+}
+
+static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 1);
+}
+
+static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 0);
+}
+
+static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
+    &pflash_writeb_be,
+    &pflash_writew_be,
+    &pflash_writel_be,
+};
+
+static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
+    &pflash_readb_be,
+    &pflash_readw_be,
+    &pflash_readl_be,
+};
+
+static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
+    &pflash_writeb_le,
+    &pflash_writew_le,
+    &pflash_writel_le,
+};
+
+static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
+    &pflash_readb_le,
+    &pflash_readw_le,
+    &pflash_readl_le,
+};
+
+/* Count trailing zeroes of a 32 bits quantity */
+static int ctz32 (uint32_t n)
+{
+    int ret;
+
+    ret = 0;
+    if (!(n & 0xFFFF)) {
+        ret += 16;
+        n = n >> 16;
+    }
+    if (!(n & 0xFF)) {
+        ret += 8;
+        n = n >> 8;
+    }
+    if (!(n & 0xF)) {
+        ret += 4;
+        n = n >> 4;
+    }
+    if (!(n & 0x3)) {
+        ret += 2;
+        n = n >> 2;
+    }
+    if (!(n & 0x1)) {
+        ret++;
+#if 0 /* This is not necessary as n is never 0 */
+        n = n >> 1;
+#endif
+    }
+#if 0 /* This is not necessary as n is never 0 */
+    if (!n)
+        ret++;
+#endif
+
+    return ret;
+}
+
+pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int nb_mappings, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3,
+                                uint16_t unlock_addr0, uint16_t unlock_addr1,
+                                int be)
+{
+    pflash_t *pfl;
+    int32_t chip_len;
+    int ret;
+
+    chip_len = sector_len * nb_blocs;
+    /* XXX: to be fixed */
+#if 0
+    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
+        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
+        return NULL;
+#endif
+    pfl = qemu_mallocz(sizeof(pflash_t));
+    /* FIXME: Allocate ram ourselves.  */
+    pfl->storage = qemu_get_ram_ptr(off);
+    if (be) {
+        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
+                                             pflash_write_ops_be,
+                                             pfl, DEVICE_NATIVE_ENDIAN);
+    } else {
+        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
+                                             pflash_write_ops_le,
+                                             pfl, DEVICE_NATIVE_ENDIAN);
+    }
+    pfl->off = off;
+    pfl->base = base;
+    pfl->chip_len = chip_len;
+    pfl->mappings = nb_mappings;
+    pflash_register_memory(pfl, 1);
+    pfl->bs = bs;
+    if (pfl->bs) {
+        /* read the initial flash content */
+        ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
+        if (ret < 0) {
+            cpu_unregister_io_memory(pfl->fl_mem);
+            qemu_free(pfl);
+            return NULL;
+        }
+    }
+#if 0 /* XXX: there should be a bit to set up read-only,
+       *      the same way the hardware does (with WP pin).
+       */
+    pfl->ro = 1;
+#else
+    pfl->ro = 0;
+#endif
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
+    pfl->sector_len = sector_len;
+    pfl->width = width;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    pfl->status = 0;
+    pfl->ident[0] = id0;
+    pfl->ident[1] = id1;
+    pfl->ident[2] = id2;
+    pfl->ident[3] = id3;
+    pfl->unlock_addr[0] = unlock_addr0;
+    pfl->unlock_addr[1] = unlock_addr1;
+    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
+    pfl->cfi_len = 0x52;
+    /* Standard "QRY" string */
+    pfl->cfi_table[0x10] = 'Q';
+    pfl->cfi_table[0x11] = 'R';
+    pfl->cfi_table[0x12] = 'Y';
+    /* Command set (AMD/Fujitsu) */
+    pfl->cfi_table[0x13] = 0x02;
+    pfl->cfi_table[0x14] = 0x00;
+    /* Primary extended table address */
+    pfl->cfi_table[0x15] = 0x31;
+    pfl->cfi_table[0x16] = 0x00;
+    /* Alternate command set (none) */
+    pfl->cfi_table[0x17] = 0x00;
+    pfl->cfi_table[0x18] = 0x00;
+    /* Alternate extended table (none) */
+    pfl->cfi_table[0x19] = 0x00;
+    pfl->cfi_table[0x1A] = 0x00;
+    /* Vcc min */
+    pfl->cfi_table[0x1B] = 0x27;
+    /* Vcc max */
+    pfl->cfi_table[0x1C] = 0x36;
+    /* Vpp min (no Vpp pin) */
+    pfl->cfi_table[0x1D] = 0x00;
+    /* Vpp max (no Vpp pin) */
+    pfl->cfi_table[0x1E] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x1F] = 0x07;
+    /* Timeout for min size buffer write (NA) */
+    pfl->cfi_table[0x20] = 0x00;
+    /* Typical timeout for block erase (512 ms) */
+    pfl->cfi_table[0x21] = 0x09;
+    /* Typical timeout for full chip erase (4096 ms) */
+    pfl->cfi_table[0x22] = 0x0C;
+    /* Reserved */
+    pfl->cfi_table[0x23] = 0x01;
+    /* Max timeout for buffer write (NA) */
+    pfl->cfi_table[0x24] = 0x00;
+    /* Max timeout for block erase */
+    pfl->cfi_table[0x25] = 0x0A;
+    /* Max timeout for chip erase */
+    pfl->cfi_table[0x26] = 0x0D;
+    /* Device size */
+    pfl->cfi_table[0x27] = ctz32(chip_len);
+    /* Flash device interface (8 & 16 bits) */
+    pfl->cfi_table[0x28] = 0x02;
+    pfl->cfi_table[0x29] = 0x00;
+    /* Max number of bytes in multi-bytes write */
+    /* XXX: disable buffered write as it's not supported */
+    //    pfl->cfi_table[0x2A] = 0x05;
+    pfl->cfi_table[0x2A] = 0x00;
+    pfl->cfi_table[0x2B] = 0x00;
+    /* Number of erase block regions (uniform) */
+    pfl->cfi_table[0x2C] = 0x01;
+    /* Erase block region 1 */
+    pfl->cfi_table[0x2D] = nb_blocs - 1;
+    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
+    pfl->cfi_table[0x2F] = sector_len >> 8;
+    pfl->cfi_table[0x30] = sector_len >> 16;
+
+    /* Extended */
+    pfl->cfi_table[0x31] = 'P';
+    pfl->cfi_table[0x32] = 'R';
+    pfl->cfi_table[0x33] = 'I';
+
+    pfl->cfi_table[0x34] = '1';
+    pfl->cfi_table[0x35] = '0';
+
+    pfl->cfi_table[0x36] = 0x00;
+    pfl->cfi_table[0x37] = 0x00;
+    pfl->cfi_table[0x38] = 0x00;
+    pfl->cfi_table[0x39] = 0x00;
+
+    pfl->cfi_table[0x3a] = 0x00;
+
+    pfl->cfi_table[0x3b] = 0x00;
+    pfl->cfi_table[0x3c] = 0x00;
+
+    return pfl;
+}
diff --git a/qemu-0.15.x/hw/piix4.c b/qemu-0.15.x/hw/piix4.c
new file mode 100644
index 0000000..9590e7b
--- /dev/null
+++ b/qemu-0.15.x/hw/piix4.c
@@ -0,0 +1,125 @@
+/*
+ * QEMU PIIX4 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 "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "isa.h"
+#include "sysbus.h"
+
+PCIDevice *piix4_dev;
+
+typedef struct PIIX4State {
+    PCIDevice dev;
+} PIIX4State;
+
+static void piix4_reset(void *opaque)
+{
+    PIIX4State *d = opaque;
+    uint8_t *pci_conf = d->dev.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;
+}
+
+static const VMStateDescription vmstate_piix4 = {
+    .name = "PIIX4",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PIIX4State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int piix4_initfn(PCIDevice *dev)
+{
+    PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
+
+    isa_bus_new(&d->dev.qdev);
+    piix4_dev = &d->dev;
+    qemu_register_reset(piix4_reset, d);
+    return 0;
+}
+
+int piix4_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+
+    d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
+    return d->devfn;
+}
+
+static PCIDeviceInfo piix4_info[] = {
+    {
+        .qdev.name    = "PIIX4",
+        .qdev.desc    = "ISA bridge",
+        .qdev.size    = sizeof(PIIX4State),
+        .qdev.vmsd    = &vmstate_piix4,
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = piix4_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
+    },{
+        /* end of list */
+    }
+};
+
+static void piix4_register(void)
+{
+    pci_qdev_register_many(piix4_info);
+}
+device_init(piix4_register);
diff --git a/qemu-0.15.x/hw/piix_pci.c b/qemu-0.15.x/hw/piix_pci.c
new file mode 100644
index 0000000..d08b31a
--- /dev/null
+++ b/qemu-0.15.x/hw/piix_pci.c
@@ -0,0 +1,502 @@
+/*
+ * 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 "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "isa.h"
+#include "sysbus.h"
+#include "range.h"
+#include "xen.h"
+
+/*
+ * I440FX chipset data sheet.
+ * http://download.intel.com/design/chipsets/datashts/29054901.pdf
+ */
+
+typedef PCIHostState I440FXState;
+
+#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
+#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
+#define XEN_PIIX_NUM_PIRQS      128ULL
+#define PIIX_PIRQC              0x60
+
+typedef struct PIIX3State {
+    PCIDevice dev;
+
+    /*
+     * bitmap to track pic levels.
+     * The pic level is the logical OR of all the PCI irqs mapped to it
+     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+     *
+     * PIRQ is mapped to PIC pins, we track it by
+     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
+     * pic_irq * PIIX_NUM_PIRQS + pirq
+     */
+#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+    uint64_t pic_levels;
+
+    qemu_irq *pic;
+
+    /* This member isn't used. Just for save/load compatibility */
+    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
+} PIIX3State;
+
+struct PCII440FXState {
+    PCIDevice dev;
+    target_phys_addr_t isa_page_descs[384 / 4];
+    uint8_t smm_enabled;
+    PIIX3State *piix3;
+};
+
+
+#define I440FX_PAM      0x59
+#define I440FX_PAM_SIZE 7
+#define I440FX_SMRAM    0x72
+
+static void piix3_set_irq(void *opaque, int pirq, int level);
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len);
+
+/* 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 pci_intx)
+{
+    int slot_addend;
+    slot_addend = (pci_dev->devfn >> 3) - 1;
+    return (pci_intx + slot_addend) & 3;
+}
+
+static void update_pam(PCII440FXState *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,
+                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
+        }
+        break;
+    }
+}
+
+static void i440fx_update_memory_mappings(PCII440FXState *d)
+{
+    int i, r;
+    uint32_t smram, addr;
+
+    update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3);
+    for(i = 0; i < 12; i++) {
+        r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
+        update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
+    }
+    smram = d->dev.config[I440FX_SMRAM];
+    if ((d->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,
+                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
+        }
+    }
+}
+
+static void i440fx_set_smm(int val, void *arg)
+{
+    PCII440FXState *d = arg;
+
+    val = (val != 0);
+    if (d->smm_enabled != val) {
+        d->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(PCII440FXState *d)
+{
+    int i;
+    for(i = 0; i < 96; i++) {
+        d->isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
+    }
+}
+
+static void i440fx_write_config(PCIDevice *dev,
+                                uint32_t address, uint32_t val, int len)
+{
+    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
+
+    /* XXX: implement SMRAM.D_LOCK */
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
+        range_covers_byte(address, len, I440FX_SMRAM)) {
+        i440fx_update_memory_mappings(d);
+    }
+}
+
+static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
+{
+    PCII440FXState *d = opaque;
+    int ret, i;
+
+    ret = pci_device_load(&d->dev, f);
+    if (ret < 0)
+        return ret;
+    i440fx_update_memory_mappings(d);
+    qemu_get_8s(f, &d->smm_enabled);
+
+    if (version_id == 2) {
+        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+            qemu_get_be32(f); /* dummy load for compatibility */
+        }
+    }
+
+    return 0;
+}
+
+static int i440fx_post_load(void *opaque, int version_id)
+{
+    PCII440FXState *d = opaque;
+
+    i440fx_update_memory_mappings(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_i440fx = {
+    .name = "I440FX",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = i440fx_load_old,
+    .post_load = i440fx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
+        VMSTATE_UINT8(smm_enabled, PCII440FXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i440fx_pcihost_initfn(SysBusDevice *dev)
+{
+    I440FXState *s = FROM_SYSBUS(I440FXState, dev);
+
+    pci_host_conf_register_ioport(0xcf8, s);
+
+    pci_host_data_register_ioport(0xcfc, s);
+    return 0;
+}
+
+static int i440fx_initfn(PCIDevice *dev)
+{
+    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
+
+    d->dev.config[I440FX_SMRAM] = 0x02;
+
+    cpu_smm_register(&i440fx_set_smm, d);
+    return 0;
+}
+
+static PCIBus *i440fx_common_init(const char *device_name,
+                                  PCII440FXState **pi440fx_state,
+                                  int *piix3_devfn,
+                                  qemu_irq *pic, ram_addr_t ram_size)
+{
+    DeviceState *dev;
+    PCIBus *b;
+    PCIDevice *d;
+    I440FXState *s;
+    PIIX3State *piix3;
+
+    dev = qdev_create(NULL, "i440FX-pcihost");
+    s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
+    b = pci_bus_new(&s->busdev.qdev, NULL, 0);
+    s->bus = b;
+    qdev_init_nofail(dev);
+
+    d = pci_create_simple(b, 0, device_name);
+    *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
+
+    /* Xen supports additional interrupt routes from the PCI devices to
+     * the IOAPIC: the four pins of each PCI device on the bus are also
+     * connected to the IOAPIC directly.
+     * These additional routes can be discovered through ACPI. */
+    if (xen_enabled()) {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
+        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+                piix3, XEN_PIIX_NUM_PIRQS);
+    } else {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
+        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
+                PIIX_NUM_PIRQS);
+    }
+    piix3->pic = pic;
+
+    (*pi440fx_state)->piix3 = piix3;
+
+    *piix3_devfn = piix3->dev.devfn;
+
+    ram_size = ram_size / 8 / 1024 / 1024;
+    if (ram_size > 255)
+        ram_size = 255;
+    (*pi440fx_state)->dev.config[0x57]=ram_size;
+
+    return b;
+}
+
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
+                    qemu_irq *pic, ram_addr_t ram_size)
+{
+    PCIBus *b;
+
+    b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic, ram_size);
+    return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+    qemu_set_irq(piix3->pic[pic_irq],
+                 !!(piix3->pic_levels &
+                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
+                     (pic_irq * PIIX_NUM_PIRQS))));
+}
+
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+    int pic_irq;
+    uint64_t mask;
+
+    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+        return;
+    }
+
+    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+    piix3->pic_levels &= ~mask;
+    piix3->pic_levels |= mask * !!level;
+
+    piix3_set_irq_pic(piix3, pic_irq);
+}
+
+static void piix3_set_irq(void *opaque, int pirq, int level)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_set_irq_level(piix3, pirq, level);
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+    int pirq;
+
+    piix3->pic_levels = 0;
+    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+        piix3_set_irq_level(piix3, pirq,
+                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
+    }
+}
+
+static void piix3_write_config(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
+        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
+        int pic_irq;
+        piix3_update_irq_levels(piix3);
+        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+            piix3_set_irq_pic(piix3, pic_irq);
+        }
+    }
+}
+
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    xen_piix_pci_write_config_client(address, val, len);
+    piix3_write_config(dev, address, val, len);
+}
+
+static void piix3_reset(void *opaque)
+{
+    PIIX3State *d = opaque;
+    uint8_t *pci_conf = d->dev.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[0x61] = 0x80;
+    pci_conf[0x62] = 0x80;
+    pci_conf[0x63] = 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;
+
+    d->pic_levels = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_update_irq_levels(piix3);
+    return 0;
+}
+
+static void piix3_pre_save(void *opaque)
+{
+    int i;
+    PIIX3State *piix3 = opaque;
+
+    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+        piix3->pci_irq_levels_vmstate[i] =
+            pci_bus_get_irq_level(piix3->dev.bus, i);
+    }
+}
+
+static const VMStateDescription vmstate_piix3 = {
+    .name = "PIIX3",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = piix3_post_load,
+    .pre_save = piix3_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PIIX3State),
+        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+                              PIIX_NUM_PIRQS, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int piix3_initfn(PCIDevice *dev)
+{
+    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
+
+    isa_bus_new(&d->dev.qdev);
+    qemu_register_reset(piix3_reset, d);
+    return 0;
+}
+
+static PCIDeviceInfo i440fx_info[] = {
+    {
+        .qdev.name    = "i440FX",
+        .qdev.desc    = "Host bridge",
+        .qdev.size    = sizeof(PCII440FXState),
+        .qdev.vmsd    = &vmstate_i440fx,
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = i440fx_initfn,
+        .config_write = i440fx_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82441,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_BRIDGE_HOST,
+    },{
+        .qdev.name    = "PIIX3",
+        .qdev.desc    = "ISA bridge",
+        .qdev.size    = sizeof(PIIX3State),
+        .qdev.vmsd    = &vmstate_piix3,
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = piix3_initfn,
+        .config_write = piix3_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
+    },{
+        .qdev.name    = "PIIX3-xen",
+        .qdev.desc    = "ISA bridge",
+        .qdev.size    = sizeof(PIIX3State),
+        .qdev.vmsd    = &vmstate_piix3,
+        .qdev.no_user = 1,
+        .no_hotplug   = 1,
+        .init         = piix3_initfn,
+        .config_write = piix3_write_config_xen,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
+    },{
+        /* end of list */
+    }
+};
+
+static SysBusDeviceInfo i440fx_pcihost_info = {
+    .init         = i440fx_pcihost_initfn,
+    .qdev.name    = "i440FX-pcihost",
+    .qdev.fw_name = "pci",
+    .qdev.size    = sizeof(I440FXState),
+    .qdev.no_user = 1,
+};
+
+static void i440fx_register(void)
+{
+    sysbus_register_withprop(&i440fx_pcihost_info);
+    pci_qdev_register_many(i440fx_info);
+}
+device_init(i440fx_register);
diff --git a/qemu-0.15.x/hw/pixel_ops.h b/qemu-0.15.x/hw/pixel_ops.h
new file mode 100644
index 0000000..d390adf
--- /dev/null
+++ b/qemu-0.15.x/hw/pixel_ops.h
@@ -0,0 +1,53 @@
+static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g,
+                                         unsigned int b)
+{
+    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
+}
+
+static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+}
+
+static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3);
+}
+
+static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+}
+
+static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3);
+}
+
+static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return (b << 16) | (g << 8) | r;
+}
+
+static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return (b << 16) | (g << 8) | r;
+}
diff --git a/qemu-0.15.x/hw/pl011.c b/qemu-0.15.x/hw/pl011.c
new file mode 100644
index 0000000..997ce84
--- /dev/null
+++ b/qemu-0.15.x/hw/pl011.c
@@ -0,0 +1,306 @@
+/*
+ * Arm PrimeCell PL011 UART
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t readbuff;
+    uint32_t flags;
+    uint32_t lcr;
+    uint32_t cr;
+    uint32_t dmacr;
+    uint32_t int_enabled;
+    uint32_t int_level;
+    uint32_t read_fifo[16];
+    uint32_t ilpr;
+    uint32_t ibrd;
+    uint32_t fbrd;
+    uint32_t ifl;
+    int read_pos;
+    int read_count;
+    int read_trigger;
+    CharDriverState *chr;
+    qemu_irq irq;
+    const unsigned char *id;
+} pl011_state;
+
+#define PL011_INT_TX 0x20
+#define PL011_INT_RX 0x10
+
+#define PL011_FLAG_TXFE 0x80
+#define PL011_FLAG_RXFF 0x40
+#define PL011_FLAG_TXFF 0x20
+#define PL011_FLAG_RXFE 0x10
+
+static const unsigned char pl011_id_arm[8] =
+  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+static const unsigned char pl011_id_luminary[8] =
+  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl011_update(pl011_state *s)
+{
+    uint32_t flags;
+
+    flags = s->int_level & s->int_enabled;
+    qemu_set_irq(s->irq, flags != 0);
+}
+
+static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    uint32_t c;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return s->id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        s->flags &= ~PL011_FLAG_RXFF;
+        c = s->read_fifo[s->read_pos];
+        if (s->read_count > 0) {
+            s->read_count--;
+            if (++s->read_pos == 16)
+                s->read_pos = 0;
+        }
+        if (s->read_count == 0) {
+            s->flags |= PL011_FLAG_RXFE;
+        }
+        if (s->read_count == s->read_trigger - 1)
+            s->int_level &= ~ PL011_INT_RX;
+        pl011_update(s);
+        qemu_chr_accept_input(s->chr);
+        return c;
+    case 1: /* UARTCR */
+        return 0;
+    case 6: /* UARTFR */
+        return s->flags;
+    case 8: /* UARTILPR */
+        return s->ilpr;
+    case 9: /* UARTIBRD */
+        return s->ibrd;
+    case 10: /* UARTFBRD */
+        return s->fbrd;
+    case 11: /* UARTLCR_H */
+        return s->lcr;
+    case 12: /* UARTCR */
+        return s->cr;
+    case 13: /* UARTIFLS */
+        return s->ifl;
+    case 14: /* UARTIMSC */
+        return s->int_enabled;
+    case 15: /* UARTRIS */
+        return s->int_level;
+    case 16: /* UARTMIS */
+        return s->int_level & s->int_enabled;
+    case 18: /* UARTDMACR */
+        return s->dmacr;
+    default:
+        hw_error("pl011_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl011_set_read_trigger(pl011_state *s)
+{
+#if 0
+    /* The docs say the RX interrupt is triggered when the FIFO exceeds
+       the threshold.  However linux only reads the FIFO in response to an
+       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
+       to make things work.  */
+    if (s->lcr & 0x10)
+        s->read_trigger = (s->ifl >> 1) & 0x1c;
+    else
+#endif
+        s->read_trigger = 1;
+}
+
+static void pl011_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    unsigned char ch;
+
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        /* ??? Check if transmitter is enabled.  */
+        ch = value;
+        if (s->chr)
+            qemu_chr_write(s->chr, &ch, 1);
+        s->int_level |= PL011_INT_TX;
+        pl011_update(s);
+        break;
+    case 1: /* UARTCR */
+        s->cr = value;
+        break;
+    case 6: /* UARTFR */
+        /* Writes to Flag register are ignored.  */
+        break;
+    case 8: /* UARTUARTILPR */
+        s->ilpr = value;
+        break;
+    case 9: /* UARTIBRD */
+        s->ibrd = value;
+        break;
+    case 10: /* UARTFBRD */
+        s->fbrd = value;
+        break;
+    case 11: /* UARTLCR_H */
+        s->lcr = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 12: /* UARTCR */
+        /* ??? Need to implement the enable and loopback bits.  */
+        s->cr = value;
+        break;
+    case 13: /* UARTIFS */
+        s->ifl = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 14: /* UARTIMSC */
+        s->int_enabled = value;
+        pl011_update(s);
+        break;
+    case 17: /* UARTICR */
+        s->int_level &= ~value;
+        pl011_update(s);
+        break;
+    case 18: /* UARTDMACR */
+        s->dmacr = value;
+        if (value & 3)
+            hw_error("PL011: DMA not implemented\n");
+        break;
+    default:
+        hw_error("pl011_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static int pl011_can_receive(void *opaque)
+{
+    pl011_state *s = (pl011_state *)opaque;
+
+    if (s->lcr & 0x10)
+        return s->read_count < 16;
+    else
+        return s->read_count < 1;
+}
+
+static void pl011_put_fifo(void *opaque, uint32_t value)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    int slot;
+
+    slot = s->read_pos + s->read_count;
+    if (slot >= 16)
+        slot -= 16;
+    s->read_fifo[slot] = value;
+    s->read_count++;
+    s->flags &= ~PL011_FLAG_RXFE;
+    if (s->cr & 0x10 || s->read_count == 16) {
+        s->flags |= PL011_FLAG_RXFF;
+    }
+    if (s->read_count == s->read_trigger) {
+        s->int_level |= PL011_INT_RX;
+        pl011_update(s);
+    }
+}
+
+static void pl011_receive(void *opaque, const uint8_t *buf, int size)
+{
+    pl011_put_fifo(opaque, *buf);
+}
+
+static void pl011_event(void *opaque, int event)
+{
+    if (event == CHR_EVENT_BREAK)
+        pl011_put_fifo(opaque, 0x400);
+}
+
+static CPUReadMemoryFunc * const pl011_readfn[] = {
+   pl011_read,
+   pl011_read,
+   pl011_read
+};
+
+static CPUWriteMemoryFunc * const pl011_writefn[] = {
+   pl011_write,
+   pl011_write,
+   pl011_write
+};
+
+static const VMStateDescription vmstate_pl011 = {
+    .name = "pl011",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(readbuff, pl011_state),
+        VMSTATE_UINT32(flags, pl011_state),
+        VMSTATE_UINT32(lcr, pl011_state),
+        VMSTATE_UINT32(cr, pl011_state),
+        VMSTATE_UINT32(dmacr, pl011_state),
+        VMSTATE_UINT32(int_enabled, pl011_state),
+        VMSTATE_UINT32(int_level, pl011_state),
+        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
+        VMSTATE_UINT32(ilpr, pl011_state),
+        VMSTATE_UINT32(ibrd, pl011_state),
+        VMSTATE_UINT32(fbrd, pl011_state),
+        VMSTATE_UINT32(ifl, pl011_state),
+        VMSTATE_INT32(read_pos, pl011_state),
+        VMSTATE_INT32(read_count, pl011_state),
+        VMSTATE_INT32(read_trigger, pl011_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pl011_init(SysBusDevice *dev, const unsigned char *id)
+{
+    int iomemtype;
+    pl011_state *s = FROM_SYSBUS(pl011_state, dev);
+
+    iomemtype = cpu_register_io_memory(pl011_readfn,
+                                       pl011_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000,iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->id = id;
+    s->chr = qdev_init_chardev(&dev->qdev);
+
+    s->read_trigger = 1;
+    s->ifl = 0x12;
+    s->cr = 0x300;
+    s->flags = 0x90;
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+                              pl011_event, s);
+    }
+    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
+    return 0;
+}
+
+static int pl011_init_arm(SysBusDevice *dev)
+{
+    return pl011_init(dev, pl011_id_arm);
+}
+
+static int pl011_init_luminary(SysBusDevice *dev)
+{
+    return pl011_init(dev, pl011_id_luminary);
+}
+
+static void pl011_register_devices(void)
+{
+    sysbus_register_dev("pl011", sizeof(pl011_state),
+                        pl011_init_arm);
+    sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
+                        pl011_init_luminary);
+}
+
+device_init(pl011_register_devices)
diff --git a/qemu-0.15.x/hw/pl022.c b/qemu-0.15.x/hw/pl022.c
new file mode 100644
index 0000000..9a1cb71
--- /dev/null
+++ b/qemu-0.15.x/hw/pl022.c
@@ -0,0 +1,300 @@
+/*
+ * Arm PrimeCell PL022 Synchronous Serial Port
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "ssi.h"
+#include "primecell.h"
+
+//#define DEBUG_PL022 1
+
+#ifdef DEBUG_PL022
+#define DPRINTF(fmt, ...) \
+do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define PL022_CR1_LBM 0x01
+#define PL022_CR1_SSE 0x02
+#define PL022_CR1_MS  0x04
+#define PL022_CR1_SDO 0x08
+
+#define PL022_SR_TFE  0x01
+#define PL022_SR_TNF  0x02
+#define PL022_SR_RNE  0x04
+#define PL022_SR_RFF  0x08
+#define PL022_SR_BSY  0x10
+
+#define PL022_INT_ROR 0x01
+#define PL022_INT_RT  0x04
+#define PL022_INT_RX  0x04
+#define PL022_INT_TX  0x08
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t bitmask;
+    uint32_t sr;
+    uint32_t cpsr;
+    uint32_t is;
+    uint32_t im;
+    /* The FIFO head points to the next empty entry.  */
+    int tx_fifo_head;
+    int rx_fifo_head;
+    int tx_fifo_len;
+    int rx_fifo_len;
+    uint16_t tx_fifo[8];
+    uint16_t rx_fifo[8];
+    qemu_irq irq;
+    SSIBus *ssi;
+} pl022_state;
+
+static const unsigned char pl022_id[8] =
+  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl022_update(pl022_state *s)
+{
+    s->sr = 0;
+    if (s->tx_fifo_len == 0)
+        s->sr |= PL022_SR_TFE;
+    if (s->tx_fifo_len != 8)
+        s->sr |= PL022_SR_TNF;
+    if (s->rx_fifo_len != 0)
+        s->sr |= PL022_SR_RNE;
+    if (s->rx_fifo_len == 8)
+        s->sr |= PL022_SR_RFF;
+    if (s->tx_fifo_len)
+        s->sr |= PL022_SR_BSY;
+    s->is = 0;
+    if (s->rx_fifo_len >= 4)
+        s->is |= PL022_INT_RX;
+    if (s->tx_fifo_len <= 4)
+        s->is |= PL022_INT_TX;
+
+    qemu_set_irq(s->irq, (s->is & s->im) != 0);
+}
+
+static void pl022_xfer(pl022_state *s)
+{
+    int i;
+    int o;
+    int val;
+
+    if ((s->cr1 & PL022_CR1_SSE) == 0) {
+        pl022_update(s);
+        DPRINTF("Disabled\n");
+        return;
+    }
+
+    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
+    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
+    o = s->rx_fifo_head;
+    /* ??? We do not emulate the line speed.
+       This may break some applications.  The are two problematic cases:
+        (a) A driver feeds data into the TX FIFO until it is full,
+         and only then drains the RX FIFO.  On real hardware the CPU can
+         feed data fast enough that the RX fifo never gets chance to overflow.
+        (b) A driver transmits data, deliberately allowing the RX FIFO to
+         overflow because it ignores the RX data anyway.
+
+       We choose to support (a) by stalling the transmit engine if it would
+       cause the RX FIFO to overflow.  In practice much transmit-only code
+       falls into (a) because it flushes the RX FIFO to determine when
+       the transfer has completed.  */
+    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
+        DPRINTF("xfer\n");
+        val = s->tx_fifo[i];
+        if (s->cr1 & PL022_CR1_LBM) {
+            /* Loopback mode.  */
+        } else {
+            val = ssi_transfer(s->ssi, val);
+        }
+        s->rx_fifo[o] = val & s->bitmask;
+        i = (i + 1) & 7;
+        o = (o + 1) & 7;
+        s->tx_fifo_len--;
+        s->rx_fifo_len++;
+    }
+    s->rx_fifo_head = o;
+    pl022_update(s);
+}
+
+static uint32_t pl022_read(void *opaque, target_phys_addr_t offset)
+{
+    pl022_state *s = (pl022_state *)opaque;
+    int val;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl022_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset) {
+    case 0x00: /* CR0 */
+      return s->cr0;
+    case 0x04: /* CR1 */
+      return s->cr1;
+    case 0x08: /* DR */
+        if (s->rx_fifo_len) {
+            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
+            DPRINTF("RX %02x\n", val);
+            s->rx_fifo_len--;
+            pl022_xfer(s);
+        } else {
+            val = 0;
+        }
+        return val;
+    case 0x0c: /* SR */
+        return s->sr;
+    case 0x10: /* CPSR */
+        return s->cpsr;
+    case 0x14: /* IMSC */
+        return s->im;
+    case 0x18: /* RIS */
+        return s->is;
+    case 0x1c: /* MIS */
+        return s->im & s->is;
+    case 0x20: /* DMACR */
+        /* Not implemented.  */
+        return 0;
+    default:
+        hw_error("pl022_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl022_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    pl022_state *s = (pl022_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* CR0 */
+        s->cr0 = value;
+        /* Clock rate and format are ignored.  */
+        s->bitmask = (1 << ((value & 15) + 1)) - 1;
+        break;
+    case 0x04: /* CR1 */
+        s->cr1 = value;
+        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
+                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
+            BADF("SPI slave mode not implemented\n");
+        }
+        pl022_xfer(s);
+        break;
+    case 0x08: /* DR */
+        if (s->tx_fifo_len < 8) {
+            DPRINTF("TX %02x\n", value);
+            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
+            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
+            s->tx_fifo_len++;
+            pl022_xfer(s);
+        }
+        break;
+    case 0x10: /* CPSR */
+        /* Prescaler.  Ignored.  */
+        s->cpsr = value & 0xff;
+        break;
+    case 0x14: /* IMSC */
+        s->im = value;
+        pl022_update(s);
+        break;
+    case 0x20: /* DMACR */
+        if (value) {
+            hw_error("pl022: DMA not implemented\n");
+        }
+        break;
+    default:
+        hw_error("pl022_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static void pl022_reset(pl022_state *s)
+{
+    s->rx_fifo_len = 0;
+    s->tx_fifo_len = 0;
+    s->im = 0;
+    s->is = PL022_INT_TX;
+    s->sr = PL022_SR_TFE | PL022_SR_TNF;
+}
+
+static CPUReadMemoryFunc * const pl022_readfn[] = {
+   pl022_read,
+   pl022_read,
+   pl022_read
+};
+
+static CPUWriteMemoryFunc * const pl022_writefn[] = {
+   pl022_write,
+   pl022_write,
+   pl022_write
+};
+
+static const VMStateDescription vmstate_pl022 = {
+    .name = "pl022_ssp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr0, pl022_state),
+        VMSTATE_UINT32(cr1, pl022_state),
+        VMSTATE_UINT32(bitmask, pl022_state),
+        VMSTATE_UINT32(sr, pl022_state),
+        VMSTATE_UINT32(cpsr, pl022_state),
+        VMSTATE_UINT32(is, pl022_state),
+        VMSTATE_UINT32(im, pl022_state),
+        VMSTATE_INT32(tx_fifo_head, pl022_state),
+        VMSTATE_INT32(rx_fifo_head, pl022_state),
+        VMSTATE_INT32(tx_fifo_len, pl022_state),
+        VMSTATE_INT32(rx_fifo_len, pl022_state),
+        VMSTATE_UINT16(tx_fifo[0], pl022_state),
+        VMSTATE_UINT16(rx_fifo[0], pl022_state),
+        VMSTATE_UINT16(tx_fifo[1], pl022_state),
+        VMSTATE_UINT16(rx_fifo[1], pl022_state),
+        VMSTATE_UINT16(tx_fifo[2], pl022_state),
+        VMSTATE_UINT16(rx_fifo[2], pl022_state),
+        VMSTATE_UINT16(tx_fifo[3], pl022_state),
+        VMSTATE_UINT16(rx_fifo[3], pl022_state),
+        VMSTATE_UINT16(tx_fifo[4], pl022_state),
+        VMSTATE_UINT16(rx_fifo[4], pl022_state),
+        VMSTATE_UINT16(tx_fifo[5], pl022_state),
+        VMSTATE_UINT16(rx_fifo[5], pl022_state),
+        VMSTATE_UINT16(tx_fifo[6], pl022_state),
+        VMSTATE_UINT16(rx_fifo[6], pl022_state),
+        VMSTATE_UINT16(tx_fifo[7], pl022_state),
+        VMSTATE_UINT16(rx_fifo[7], pl022_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pl022_init(SysBusDevice *dev)
+{
+    pl022_state *s = FROM_SYSBUS(pl022_state, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(pl022_readfn,
+                                       pl022_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
+    pl022_reset(s);
+    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
+    return 0;
+}
+
+static void pl022_register_devices(void)
+{
+    sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init);
+}
+
+device_init(pl022_register_devices)
diff --git a/qemu-0.15.x/hw/pl031.c b/qemu-0.15.x/hw/pl031.c
new file mode 100644
index 0000000..017a313
--- /dev/null
+++ b/qemu-0.15.x/hw/pl031.c
@@ -0,0 +1,237 @@
+/*
+ * ARM AMBA PrimeCell PL031 RTC
+ *
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * This file 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.
+ *
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_PL031
+
+#ifdef DEBUG_PL031
+#define DPRINTF(fmt, ...) \
+do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define RTC_DR      0x00    /* Data read register */
+#define RTC_MR      0x04    /* Match register */
+#define RTC_LR      0x08    /* Data load register */
+#define RTC_CR      0x0c    /* Control register */
+#define RTC_IMSC    0x10    /* Interrupt mask and set register */
+#define RTC_RIS     0x14    /* Raw interrupt status register */
+#define RTC_MIS     0x18    /* Masked interrupt status register */
+#define RTC_ICR     0x1c    /* Interrupt clear register */
+
+typedef struct {
+    SysBusDevice busdev;
+    QEMUTimer *timer;
+    qemu_irq irq;
+
+    uint32_t tick_offset;
+
+    uint32_t mr;
+    uint32_t lr;
+    uint32_t cr;
+    uint32_t im;
+    uint32_t is;
+} pl031_state;
+
+static const VMStateDescription vmstate_pl031 = {
+    .name = "pl031",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(tick_offset, pl031_state),
+        VMSTATE_UINT32(mr, pl031_state),
+        VMSTATE_UINT32(lr, pl031_state),
+        VMSTATE_UINT32(cr, pl031_state),
+        VMSTATE_UINT32(im, pl031_state),
+        VMSTATE_UINT32(is, pl031_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const unsigned char pl031_id[] = {
+    0x31, 0x10, 0x14, 0x00,         /* Device ID        */
+    0x0d, 0xf0, 0x05, 0xb1          /* Cell ID      */
+};
+
+static void pl031_update(pl031_state *s)
+{
+    qemu_set_irq(s->irq, s->is & s->im);
+}
+
+static void pl031_interrupt(void * opaque)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    s->im = 1;
+    DPRINTF("Alarm raised\n");
+    pl031_update(s);
+}
+
+static uint32_t pl031_get_count(pl031_state *s)
+{
+    /* This assumes qemu_get_clock_ns returns the time since the machine was
+       created.  */
+    return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec();
+}
+
+static void pl031_set_alarm(pl031_state *s)
+{
+    int64_t now;
+    uint32_t ticks;
+
+    now = qemu_get_clock_ns(vm_clock);
+    ticks = s->tick_offset + now / get_ticks_per_sec();
+
+    /* The timer wraps around.  This subtraction also wraps in the same way,
+       and gives correct results when alarm < now_ticks.  */
+    ticks = s->mr - ticks;
+    DPRINTF("Alarm set in %ud ticks\n", ticks);
+    if (ticks == 0) {
+        qemu_del_timer(s->timer);
+        pl031_interrupt(s);
+    } else {
+        qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
+    }
+}
+
+static uint32_t pl031_read(void *opaque, target_phys_addr_t offset)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    if (offset >= 0xfe0  &&  offset < 0x1000)
+        return pl031_id[(offset - 0xfe0) >> 2];
+
+    switch (offset) {
+    case RTC_DR:
+        return pl031_get_count(s);
+    case RTC_MR:
+        return s->mr;
+    case RTC_IMSC:
+        return s->im;
+    case RTC_RIS:
+        return s->is;
+    case RTC_LR:
+        return s->lr;
+    case RTC_CR:
+        /* RTC is permanently enabled.  */
+        return 1;
+    case RTC_MIS:
+        return s->is & s->im;
+    case RTC_ICR:
+        fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n",
+                (int)offset);
+        break;
+    default:
+        hw_error("pl031_read: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+
+    return 0;
+}
+
+static void pl031_write(void * opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+
+    switch (offset) {
+    case RTC_LR:
+        s->tick_offset += value - pl031_get_count(s);
+        pl031_set_alarm(s);
+        break;
+    case RTC_MR:
+        s->mr = value;
+        pl031_set_alarm(s);
+        break;
+    case RTC_IMSC:
+        s->im = value & 1;
+        DPRINTF("Interrupt mask %d\n", s->im);
+        pl031_update(s);
+        break;
+    case RTC_ICR:
+        /* The PL031 documentation (DDI0224B) states that the interrupt is
+           cleared when bit 0 of the written value is set.  However the
+           arm926e documentation (DDI0287B) states that the interrupt is
+           cleared when any value is written.  */
+        DPRINTF("Interrupt cleared");
+        s->is = 0;
+        pl031_update(s);
+        break;
+    case RTC_CR:
+        /* Written value is ignored.  */
+        break;
+
+    case RTC_DR:
+    case RTC_MIS:
+    case RTC_RIS:
+        fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n",
+                (int)offset);
+        break;
+
+    default:
+        hw_error("pl031_write: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+}
+
+static CPUWriteMemoryFunc * const  pl031_writefn[] = {
+    pl031_write,
+    pl031_write,
+    pl031_write
+};
+
+static CPUReadMemoryFunc * const  pl031_readfn[] = {
+    pl031_read,
+    pl031_read,
+    pl031_read
+};
+
+static int pl031_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    pl031_state *s = FROM_SYSBUS(pl031_state, dev);
+    struct tm tm;
+
+    iomemtype = cpu_register_io_memory(pl031_readfn, pl031_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    if (iomemtype == -1) {
+        hw_error("pl031_init: Can't register I/O memory\n");
+    }
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    sysbus_init_irq(dev, &s->irq);
+    /* ??? We assume vm_clock is zero at this point.  */
+    qemu_get_timedate(&tm, 0);
+    s->tick_offset = mktimegm(&tm);
+
+    s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s);
+    return 0;
+}
+
+static SysBusDeviceInfo pl031_info = {
+    .init = pl031_init,
+    .qdev.name = "pl031",
+    .qdev.size = sizeof(pl031_state),
+    .qdev.vmsd = &vmstate_pl031,
+    .qdev.no_user = 1,
+};
+
+static void pl031_register_devices(void)
+{
+    sysbus_register_withprop(&pl031_info);
+}
+
+device_init(pl031_register_devices)
diff --git a/qemu-0.15.x/hw/pl050.c b/qemu-0.15.x/hw/pl050.c
new file mode 100644
index 0000000..f7fa2e2
--- /dev/null
+++ b/qemu-0.15.x/hw/pl050.c
@@ -0,0 +1,187 @@
+/*
+ * Arm PrimeCell PL050 Keyboard / Mouse Interface
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "ps2.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    void *dev;
+    uint32_t cr;
+    uint32_t clk;
+    uint32_t last;
+    int pending;
+    qemu_irq irq;
+    int is_mouse;
+} pl050_state;
+
+static const VMStateDescription vmstate_pl050 = {
+    .name = "pl050",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr, pl050_state),
+        VMSTATE_UINT32(clk, pl050_state),
+        VMSTATE_UINT32(last, pl050_state),
+        VMSTATE_INT32(pending, pl050_state),
+        VMSTATE_INT32(is_mouse, pl050_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define PL050_TXEMPTY         (1 << 6)
+#define PL050_TXBUSY          (1 << 5)
+#define PL050_RXFULL          (1 << 4)
+#define PL050_RXBUSY          (1 << 3)
+#define PL050_RXPARITY        (1 << 2)
+#define PL050_KMIC            (1 << 1)
+#define PL050_KMID            (1 << 0)
+
+static const unsigned char pl050_id[] =
+{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl050_update(void *opaque, int level)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    int raise;
+
+    s->pending = level;
+    raise = (s->pending && (s->cr & 0x10) != 0)
+            || (s->cr & 0x08) != 0;
+    qemu_set_irq(s->irq, raise);
+}
+
+static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    if (offset >= 0xfe0 && offset < 0x1000)
+        return pl050_id[(offset - 0xfe0) >> 2];
+
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        return s->cr;
+    case 1: /* KMISTAT */
+        {
+            uint8_t val;
+            uint32_t stat;
+
+            val = s->last;
+            val = val ^ (val >> 4);
+            val = val ^ (val >> 2);
+            val = (val ^ (val >> 1)) & 1;
+
+            stat = PL050_TXEMPTY;
+            if (val)
+                stat |= PL050_RXPARITY;
+            if (s->pending)
+                stat |= PL050_RXFULL;
+
+            return stat;
+        }
+    case 2: /* KMIDATA */
+        if (s->pending)
+            s->last = ps2_read_data(s->dev);
+        return s->last;
+    case 3: /* KMICLKDIV */
+        return s->clk;
+    case 4: /* KMIIR */
+        return s->pending | 2;
+    default:
+        hw_error("pl050_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl050_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        s->cr = value;
+        pl050_update(s, s->pending);
+        /* ??? Need to implement the enable/disable bit.  */
+        break;
+    case 2: /* KMIDATA */
+        /* ??? This should toggle the TX interrupt line.  */
+        /* ??? This means kbd/mouse can block each other.  */
+        if (s->is_mouse) {
+            ps2_write_mouse(s->dev, value);
+        } else {
+            ps2_write_keyboard(s->dev, value);
+        }
+        break;
+    case 3: /* KMICLKDIV */
+        s->clk = value;
+        return;
+    default:
+        hw_error("pl050_write: Bad offset %x\n", (int)offset);
+    }
+}
+static CPUReadMemoryFunc * const pl050_readfn[] = {
+   pl050_read,
+   pl050_read,
+   pl050_read
+};
+
+static CPUWriteMemoryFunc * const pl050_writefn[] = {
+   pl050_write,
+   pl050_write,
+   pl050_write
+};
+
+static int pl050_init(SysBusDevice *dev, int is_mouse)
+{
+    pl050_state *s = FROM_SYSBUS(pl050_state, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(pl050_readfn,
+                                       pl050_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->is_mouse = is_mouse;
+    if (s->is_mouse)
+        s->dev = ps2_mouse_init(pl050_update, s);
+    else
+        s->dev = ps2_kbd_init(pl050_update, s);
+    return 0;
+}
+
+static int pl050_init_keyboard(SysBusDevice *dev)
+{
+    return pl050_init(dev, 0);
+}
+
+static int pl050_init_mouse(SysBusDevice *dev)
+{
+    return pl050_init(dev, 1);
+}
+
+static SysBusDeviceInfo pl050_kbd_info = {
+    .init = pl050_init_keyboard,
+    .qdev.name  = "pl050_keyboard",
+    .qdev.size  = sizeof(pl050_state),
+    .qdev.vmsd = &vmstate_pl050,
+};
+
+static SysBusDeviceInfo pl050_mouse_info = {
+    .init = pl050_init_mouse,
+    .qdev.name  = "pl050_mouse",
+    .qdev.size  = sizeof(pl050_state),
+    .qdev.vmsd = &vmstate_pl050,
+};
+
+static void pl050_register_devices(void)
+{
+    sysbus_register_withprop(&pl050_kbd_info);
+    sysbus_register_withprop(&pl050_mouse_info);
+}
+
+device_init(pl050_register_devices)
diff --git a/qemu-0.15.x/hw/pl061.c b/qemu-0.15.x/hw/pl061.c
new file mode 100644
index 0000000..79e5c53
--- /dev/null
+++ b/qemu-0.15.x/hw/pl061.c
@@ -0,0 +1,332 @@
+/*
+ * Arm PrimeCell PL061 General Purpose IO with additional
+ * Luminary Micro Stellaris bits.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+
+//#define DEBUG_PL061 1
+
+#ifdef DEBUG_PL061
+#define DPRINTF(fmt, ...) \
+do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+static const uint8_t pl061_id[12] =
+  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+static const uint8_t pl061_id_luminary[12] =
+  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
+
+typedef struct {
+    SysBusDevice busdev;
+    int locked;
+    uint8_t data;
+    uint8_t old_data;
+    uint8_t dir;
+    uint8_t isense;
+    uint8_t ibe;
+    uint8_t iev;
+    uint8_t im;
+    uint8_t istate;
+    uint8_t afsel;
+    uint8_t dr2r;
+    uint8_t dr4r;
+    uint8_t dr8r;
+    uint8_t odr;
+    uint8_t pur;
+    uint8_t pdr;
+    uint8_t slr;
+    uint8_t den;
+    uint8_t cr;
+    uint8_t float_high;
+    qemu_irq irq;
+    qemu_irq out[8];
+    const unsigned char *id;
+} pl061_state;
+
+static void pl061_update(pl061_state *s)
+{
+    uint8_t changed;
+    uint8_t mask;
+    uint8_t out;
+    int i;
+
+    /* Outputs float high.  */
+    /* FIXME: This is board dependent.  */
+    out = (s->data & s->dir) | ~s->dir;
+    changed = s->old_data ^ out;
+    if (!changed)
+        return;
+
+    s->old_data = out;
+    for (i = 0; i < 8; i++) {
+        mask = 1 << i;
+        if ((changed & mask) && s->out) {
+            DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
+            qemu_set_irq(s->out[i], (out & mask) != 0);
+        }
+    }
+
+    /* FIXME: Implement input interrupts.  */
+}
+
+static uint32_t pl061_read(void *opaque, target_phys_addr_t offset)
+{
+    pl061_state *s = (pl061_state *)opaque;
+
+    if (offset >= 0xfd0 && offset < 0x1000) {
+        return s->id[(offset - 0xfd0) >> 2];
+    }
+    if (offset < 0x400) {
+        return s->data & (offset >> 2);
+    }
+    switch (offset) {
+    case 0x400: /* Direction */
+        return s->dir;
+    case 0x404: /* Interrupt sense */
+        return s->isense;
+    case 0x408: /* Interrupt both edges */
+        return s->ibe;
+    case 0x40c: /* Interrupt event */
+        return s->iev;
+    case 0x410: /* Interrupt mask */
+        return s->im;
+    case 0x414: /* Raw interrupt status */
+        return s->istate;
+    case 0x418: /* Masked interrupt status */
+        return s->istate | s->im;
+    case 0x420: /* Alternate function select */
+        return s->afsel;
+    case 0x500: /* 2mA drive */
+        return s->dr2r;
+    case 0x504: /* 4mA drive */
+        return s->dr4r;
+    case 0x508: /* 8mA drive */
+        return s->dr8r;
+    case 0x50c: /* Open drain */
+        return s->odr;
+    case 0x510: /* Pull-up */
+        return s->pur;
+    case 0x514: /* Pull-down */
+        return s->pdr;
+    case 0x518: /* Slew rate control */
+        return s->slr;
+    case 0x51c: /* Digital enable */
+        return s->den;
+    case 0x520: /* Lock */
+        return s->locked;
+    case 0x524: /* Commit */
+        return s->cr;
+    default:
+        hw_error("pl061_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl061_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    pl061_state *s = (pl061_state *)opaque;
+    uint8_t mask;
+
+    if (offset < 0x400) {
+        mask = (offset >> 2) & s->dir;
+        s->data = (s->data & ~mask) | (value & mask);
+        pl061_update(s);
+        return;
+    }
+    switch (offset) {
+    case 0x400: /* Direction */
+        s->dir = value;
+        break;
+    case 0x404: /* Interrupt sense */
+        s->isense = value;
+        break;
+    case 0x408: /* Interrupt both edges */
+        s->ibe = value;
+        break;
+    case 0x40c: /* Interrupt event */
+        s->iev = value;
+        break;
+    case 0x410: /* Interrupt mask */
+        s->im = value;
+        break;
+    case 0x41c: /* Interrupt clear */
+        s->istate &= ~value;
+        break;
+    case 0x420: /* Alternate function select */
+        mask = s->cr;
+        s->afsel = (s->afsel & ~mask) | (value & mask);
+        break;
+    case 0x500: /* 2mA drive */
+        s->dr2r = value;
+        break;
+    case 0x504: /* 4mA drive */
+        s->dr4r = value;
+        break;
+    case 0x508: /* 8mA drive */
+        s->dr8r = value;
+        break;
+    case 0x50c: /* Open drain */
+        s->odr = value;
+        break;
+    case 0x510: /* Pull-up */
+        s->pur = value;
+        break;
+    case 0x514: /* Pull-down */
+        s->pdr = value;
+        break;
+    case 0x518: /* Slew rate control */
+        s->slr = value;
+        break;
+    case 0x51c: /* Digital enable */
+        s->den = value;
+        break;
+    case 0x520: /* Lock */
+        s->locked = (value != 0xacce551);
+        break;
+    case 0x524: /* Commit */
+        if (!s->locked)
+            s->cr = value;
+        break;
+    default:
+        hw_error("pl061_write: Bad offset %x\n", (int)offset);
+    }
+    pl061_update(s);
+}
+
+static void pl061_reset(pl061_state *s)
+{
+  s->locked = 1;
+  s->cr = 0xff;
+}
+
+static void pl061_set_irq(void * opaque, int irq, int level)
+{
+    pl061_state *s = (pl061_state *)opaque;
+    uint8_t mask;
+
+    mask = 1 << irq;
+    if ((s->dir & mask) == 0) {
+        s->data &= ~mask;
+        if (level)
+            s->data |= mask;
+        pl061_update(s);
+    }
+}
+
+static CPUReadMemoryFunc * const pl061_readfn[] = {
+   pl061_read,
+   pl061_read,
+   pl061_read
+};
+
+static CPUWriteMemoryFunc * const pl061_writefn[] = {
+   pl061_write,
+   pl061_write,
+   pl061_write
+};
+
+static void pl061_save(QEMUFile *f, void *opaque)
+{
+    pl061_state *s = (pl061_state *)opaque;
+
+    qemu_put_be32(f, s->locked);
+    qemu_put_be32(f, s->data);
+    qemu_put_be32(f, s->old_data);
+    qemu_put_be32(f, s->dir);
+    qemu_put_be32(f, s->isense);
+    qemu_put_be32(f, s->ibe);
+    qemu_put_be32(f, s->iev);
+    qemu_put_be32(f, s->im);
+    qemu_put_be32(f, s->istate);
+    qemu_put_be32(f, s->afsel);
+    qemu_put_be32(f, s->dr2r);
+    qemu_put_be32(f, s->dr4r);
+    qemu_put_be32(f, s->dr8r);
+    qemu_put_be32(f, s->odr);
+    qemu_put_be32(f, s->pur);
+    qemu_put_be32(f, s->pdr);
+    qemu_put_be32(f, s->slr);
+    qemu_put_be32(f, s->den);
+    qemu_put_be32(f, s->cr);
+    qemu_put_be32(f, s->float_high);
+}
+
+static int pl061_load(QEMUFile *f, void *opaque, int version_id)
+{
+    pl061_state *s = (pl061_state *)opaque;
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->locked = qemu_get_be32(f);
+    s->data = qemu_get_be32(f);
+    s->old_data = qemu_get_be32(f);
+    s->dir = qemu_get_be32(f);
+    s->isense = qemu_get_be32(f);
+    s->ibe = qemu_get_be32(f);
+    s->iev = qemu_get_be32(f);
+    s->im = qemu_get_be32(f);
+    s->istate = qemu_get_be32(f);
+    s->afsel = qemu_get_be32(f);
+    s->dr2r = qemu_get_be32(f);
+    s->dr4r = qemu_get_be32(f);
+    s->dr8r = qemu_get_be32(f);
+    s->odr = qemu_get_be32(f);
+    s->pur = qemu_get_be32(f);
+    s->pdr = qemu_get_be32(f);
+    s->slr = qemu_get_be32(f);
+    s->den = qemu_get_be32(f);
+    s->cr = qemu_get_be32(f);
+    s->float_high = qemu_get_be32(f);
+
+    return 0;
+}
+
+static int pl061_init(SysBusDevice *dev, const unsigned char *id)
+{
+    int iomemtype;
+    pl061_state *s = FROM_SYSBUS(pl061_state, dev);
+    s->id = id;
+    iomemtype = cpu_register_io_memory(pl061_readfn,
+                                       pl061_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
+    qdev_init_gpio_out(&dev->qdev, s->out, 8);
+    pl061_reset(s);
+    register_savevm(&dev->qdev, "pl061_gpio", -1, 1, pl061_save, pl061_load, s);
+    return 0;
+}
+
+static int pl061_init_luminary(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id_luminary);
+}
+
+static int pl061_init_arm(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id);
+}
+
+static void pl061_register_devices(void)
+{
+    sysbus_register_dev("pl061", sizeof(pl061_state),
+                        pl061_init_arm);
+    sysbus_register_dev("pl061_luminary", sizeof(pl061_state),
+                        pl061_init_luminary);
+}
+
+device_init(pl061_register_devices)
diff --git a/qemu-0.15.x/hw/pl080.c b/qemu-0.15.x/hw/pl080.c
new file mode 100644
index 0000000..5ba3b08
--- /dev/null
+++ b/qemu-0.15.x/hw/pl080.c
@@ -0,0 +1,407 @@
+/*
+ * Arm PrimeCell PL080/PL081 DMA controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+
+#define PL080_MAX_CHANNELS 8
+#define PL080_CONF_E    0x1
+#define PL080_CONF_M1   0x2
+#define PL080_CONF_M2   0x4
+
+#define PL080_CCONF_H   0x40000
+#define PL080_CCONF_A   0x20000
+#define PL080_CCONF_L   0x10000
+#define PL080_CCONF_ITC 0x08000
+#define PL080_CCONF_IE  0x04000
+#define PL080_CCONF_E   0x00001
+
+#define PL080_CCTRL_I   0x80000000
+#define PL080_CCTRL_DI  0x08000000
+#define PL080_CCTRL_SI  0x04000000
+#define PL080_CCTRL_D   0x02000000
+#define PL080_CCTRL_S   0x01000000
+
+typedef struct {
+    uint32_t src;
+    uint32_t dest;
+    uint32_t lli;
+    uint32_t ctrl;
+    uint32_t conf;
+} pl080_channel;
+
+typedef struct {
+    SysBusDevice busdev;
+    uint8_t tc_int;
+    uint8_t tc_mask;
+    uint8_t err_int;
+    uint8_t err_mask;
+    uint32_t conf;
+    uint32_t sync;
+    uint32_t req_single;
+    uint32_t req_burst;
+    pl080_channel chan[PL080_MAX_CHANNELS];
+    int nchannels;
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+    qemu_irq irq;
+} pl080_state;
+
+static const VMStateDescription vmstate_pl080_channel = {
+    .name = "pl080_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(src, pl080_channel),
+        VMSTATE_UINT32(dest, pl080_channel),
+        VMSTATE_UINT32(lli, pl080_channel),
+        VMSTATE_UINT32(ctrl, pl080_channel),
+        VMSTATE_UINT32(conf, pl080_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl080 = {
+    .name = "pl080",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_mask, pl080_state),
+        VMSTATE_UINT8(err_int, pl080_state),
+        VMSTATE_UINT8(err_mask, pl080_state),
+        VMSTATE_UINT32(conf, pl080_state),
+        VMSTATE_UINT32(sync, pl080_state),
+        VMSTATE_UINT32(req_single, pl080_state),
+        VMSTATE_UINT32(req_burst, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS,
+                             1, vmstate_pl080_channel, pl080_channel),
+        VMSTATE_INT32(running, pl080_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const unsigned char pl080_id[] =
+{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static const unsigned char pl081_id[] =
+{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl080_update(pl080_state *s)
+{
+    if ((s->tc_int & s->tc_mask)
+            || (s->err_int & s->err_mask))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void pl080_run(pl080_state *s)
+{
+    int c;
+    int flow;
+    pl080_channel *ch;
+    int swidth;
+    int dwidth;
+    int xsize;
+    int n;
+    int src_id;
+    int dest_id;
+    int size;
+    uint8_t buff[4];
+    uint32_t req;
+
+    s->tc_mask = 0;
+    for (c = 0; c < s->nchannels; c++) {
+        if (s->chan[c].conf & PL080_CCONF_ITC)
+            s->tc_mask |= 1 << c;
+        if (s->chan[c].conf & PL080_CCONF_IE)
+            s->err_mask |= 1 << c;
+    }
+
+    if ((s->conf & PL080_CONF_E) == 0)
+        return;
+
+hw_error("DMA active\n");
+    /* If we are already in the middle of a DMA operation then indicate that
+       there may be new DMA requests and return immediately.  */
+    if (s->running) {
+        s->running++;
+        return;
+    }
+    s->running = 1;
+    while (s->running) {
+        for (c = 0; c < s->nchannels; c++) {
+            ch = &s->chan[c];
+again:
+            /* Test if thiws channel has any pending DMA requests.  */
+            if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
+                    != PL080_CCONF_E)
+                continue;
+            flow = (ch->conf >> 11) & 7;
+            if (flow >= 4) {
+                hw_error(
+                    "pl080_run: Peripheral flow control not implemented\n");
+            }
+            src_id = (ch->conf >> 1) & 0x1f;
+            dest_id = (ch->conf >> 6) & 0x1f;
+            size = ch->ctrl & 0xfff;
+            req = s->req_single | s->req_burst;
+            switch (flow) {
+            case 0:
+                break;
+            case 1:
+                if ((req & (1u << dest_id)) == 0)
+                    size = 0;
+                break;
+            case 2:
+                if ((req & (1u << src_id)) == 0)
+                    size = 0;
+                break;
+            case 3:
+                if ((req & (1u << src_id)) == 0
+                        || (req & (1u << dest_id)) == 0)
+                    size = 0;
+                break;
+            }
+            if (!size)
+                continue;
+
+            /* Transfer one element.  */
+            /* ??? Should transfer multiple elements for a burst request.  */
+            /* ??? Unclear what the proper behavior is when source and
+               destination widths are different.  */
+            swidth = 1 << ((ch->ctrl >> 18) & 7);
+            dwidth = 1 << ((ch->ctrl >> 21) & 7);
+            for (n = 0; n < dwidth; n+= swidth) {
+                cpu_physical_memory_read(ch->src, buff + n, swidth);
+                if (ch->ctrl & PL080_CCTRL_SI)
+                    ch->src += swidth;
+            }
+            xsize = (dwidth < swidth) ? swidth : dwidth;
+            /* ??? This may pad the value incorrectly for dwidth < 32.  */
+            for (n = 0; n < xsize; n += dwidth) {
+                cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
+                if (ch->ctrl & PL080_CCTRL_DI)
+                    ch->dest += swidth;
+            }
+
+            size--;
+            ch->ctrl = (ch->ctrl & 0xfffff000) | size;
+            if (size == 0) {
+                /* Transfer complete.  */
+                if (ch->lli) {
+                    ch->src = ldl_le_phys(ch->lli);
+                    ch->dest = ldl_le_phys(ch->lli + 4);
+                    ch->ctrl = ldl_le_phys(ch->lli + 12);
+                    ch->lli = ldl_le_phys(ch->lli + 8);
+                } else {
+                    ch->conf &= ~PL080_CCONF_E;
+                }
+                if (ch->ctrl & PL080_CCTRL_I) {
+                    s->tc_int |= 1 << c;
+                }
+            }
+            goto again;
+        }
+        if (--s->running)
+            s->running = 1;
+    }
+}
+
+static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
+{
+    pl080_state *s = (pl080_state *)opaque;
+    uint32_t i;
+    uint32_t mask;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        if (s->nchannels == 8) {
+            return pl080_id[(offset - 0xfe0) >> 2];
+        } else {
+            return pl081_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    if (offset >= 0x100 && offset < 0x200) {
+        i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
+        switch (offset >> 2) {
+        case 0: /* SrcAddr */
+            return s->chan[i].src;
+        case 1: /* DestAddr */
+            return s->chan[i].dest;
+        case 2: /* LLI */
+            return s->chan[i].lli;
+        case 3: /* Control */
+            return s->chan[i].ctrl;
+        case 4: /* Configuration */
+            return s->chan[i].conf;
+        default:
+            goto bad_offset;
+        }
+    }
+    switch (offset >> 2) {
+    case 0: /* IntStatus */
+        return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
+    case 1: /* IntTCStatus */
+        return (s->tc_int & s->tc_mask);
+    case 3: /* IntErrorStatus */
+        return (s->err_int & s->err_mask);
+    case 5: /* RawIntTCStatus */
+        return s->tc_int;
+    case 6: /* RawIntErrorStatus */
+        return s->err_int;
+    case 7: /* EnbldChns */
+        mask = 0;
+        for (i = 0; i < s->nchannels; i++) {
+            if (s->chan[i].conf & PL080_CCONF_E)
+                mask |= 1 << i;
+        }
+        return mask;
+    case 8: /* SoftBReq */
+    case 9: /* SoftSReq */
+    case 10: /* SoftLBReq */
+    case 11: /* SoftLSReq */
+        /* ??? Implement these. */
+        return 0;
+    case 12: /* Configuration */
+        return s->conf;
+    case 13: /* Sync */
+        return s->sync;
+    default:
+    bad_offset:
+        hw_error("pl080_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl080_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl080_state *s = (pl080_state *)opaque;
+    int i;
+
+    if (offset >= 0x100 && offset < 0x200) {
+        i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
+        switch (offset >> 2) {
+        case 0: /* SrcAddr */
+            s->chan[i].src = value;
+            break;
+        case 1: /* DestAddr */
+            s->chan[i].dest = value;
+            break;
+        case 2: /* LLI */
+            s->chan[i].lli = value;
+            break;
+        case 3: /* Control */
+            s->chan[i].ctrl = value;
+            break;
+        case 4: /* Configuration */
+            s->chan[i].conf = value;
+            pl080_run(s);
+            break;
+        }
+    }
+    switch (offset >> 2) {
+    case 2: /* IntTCClear */
+        s->tc_int &= ~value;
+        break;
+    case 4: /* IntErrorClear */
+        s->err_int &= ~value;
+        break;
+    case 8: /* SoftBReq */
+    case 9: /* SoftSReq */
+    case 10: /* SoftLBReq */
+    case 11: /* SoftLSReq */
+        /* ??? Implement these.  */
+        hw_error("pl080_write: Soft DMA not implemented\n");
+        break;
+    case 12: /* Configuration */
+        s->conf = value;
+        if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
+            hw_error("pl080_write: Big-endian DMA not implemented\n");
+        }
+        pl080_run(s);
+        break;
+    case 13: /* Sync */
+        s->sync = value;
+        break;
+    default:
+    bad_offset:
+        hw_error("pl080_write: Bad offset %x\n", (int)offset);
+    }
+    pl080_update(s);
+}
+
+static CPUReadMemoryFunc * const pl080_readfn[] = {
+   pl080_read,
+   pl080_read,
+   pl080_read
+};
+
+static CPUWriteMemoryFunc * const pl080_writefn[] = {
+   pl080_write,
+   pl080_write,
+   pl080_write
+};
+
+static int pl08x_init(SysBusDevice *dev, int nchannels)
+{
+    int iomemtype;
+    pl080_state *s = FROM_SYSBUS(pl080_state, dev);
+
+    iomemtype = cpu_register_io_memory(pl080_readfn,
+                                       pl080_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->nchannels = nchannels;
+    return 0;
+}
+
+static int pl080_init(SysBusDevice *dev)
+{
+    return pl08x_init(dev, 8);
+}
+
+static int pl081_init(SysBusDevice *dev)
+{
+    return pl08x_init(dev, 2);
+}
+
+static SysBusDeviceInfo pl080_info = {
+    .init = pl080_init,
+    .qdev.name = "pl080",
+    .qdev.size = sizeof(pl080_state),
+    .qdev.vmsd = &vmstate_pl080,
+    .qdev.no_user = 1,
+};
+
+static SysBusDeviceInfo pl081_info = {
+    .init = pl081_init,
+    .qdev.name = "pl081",
+    .qdev.size = sizeof(pl080_state),
+    .qdev.vmsd = &vmstate_pl080,
+    .qdev.no_user = 1,
+};
+
+/* The PL080 and PL081 are the same except for the number of channels
+   they implement (8 and 2 respectively).  */
+static void pl080_register_devices(void)
+{
+    sysbus_register_withprop(&pl080_info);
+    sysbus_register_withprop(&pl081_info);
+}
+
+device_init(pl080_register_devices)
diff --git a/qemu-0.15.x/hw/pl110.c b/qemu-0.15.x/hw/pl110.c
new file mode 100644
index 0000000..62aba17
--- /dev/null
+++ b/qemu-0.15.x/hw/pl110.c
@@ -0,0 +1,422 @@
+/*
+ * Arm PrimeCell PL110 Color LCD Controller
+ *
+ * Copyright (c) 2005-2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU LGPL
+ */
+
+#include "sysbus.h"
+#include "console.h"
+#include "framebuffer.h"
+
+#define PL110_CR_EN   0x001
+#define PL110_CR_BGR  0x100
+#define PL110_CR_BEBO 0x200
+#define PL110_CR_BEPO 0x400
+#define PL110_CR_PWR  0x800
+
+enum pl110_bppmode
+{
+    BPP_1,
+    BPP_2,
+    BPP_4,
+    BPP_8,
+    BPP_16,
+    BPP_32
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    DisplayState *ds;
+
+    /* The Versatile/PB uses a slightly modified PL110 controller.  */
+    int versatile;
+    uint32_t timing[4];
+    uint32_t cr;
+    uint32_t upbase;
+    uint32_t lpbase;
+    uint32_t int_status;
+    uint32_t int_mask;
+    int cols;
+    int rows;
+    enum pl110_bppmode bpp;
+    int invalidate;
+    uint32_t pallette[256];
+    uint32_t raw_pallette[128];
+    qemu_irq irq;
+} pl110_state;
+
+static const VMStateDescription vmstate_pl110 = {
+    .name = "pl110",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(versatile, pl110_state),
+        VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
+        VMSTATE_UINT32(cr, pl110_state),
+        VMSTATE_UINT32(upbase, pl110_state),
+        VMSTATE_UINT32(lpbase, pl110_state),
+        VMSTATE_UINT32(int_status, pl110_state),
+        VMSTATE_UINT32(int_mask, pl110_state),
+        VMSTATE_INT32(cols, pl110_state),
+        VMSTATE_INT32(rows, pl110_state),
+        VMSTATE_UINT32(bpp, pl110_state),
+        VMSTATE_INT32(invalidate, pl110_state),
+        VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256),
+        VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const unsigned char pl110_id[] =
+{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
+   has a different ID.  However Linux only looks for the normal ID.  */
+#if 0
+static const unsigned char pl110_versatile_id[] =
+{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+#else
+#define pl110_versatile_id pl110_id
+#endif
+
+#include "pixel_ops.h"
+
+#define BITS 8
+#include "pl110_template.h"
+#define BITS 15
+#include "pl110_template.h"
+#define BITS 16
+#include "pl110_template.h"
+#define BITS 24
+#include "pl110_template.h"
+#define BITS 32
+#include "pl110_template.h"
+
+static int pl110_enabled(pl110_state *s)
+{
+  return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
+}
+
+static void pl110_update_display(void *opaque)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    drawfn* fntable;
+    drawfn fn;
+    int dest_width;
+    int src_width;
+    int bpp_offset;
+    int first;
+    int last;
+
+    if (!pl110_enabled(s))
+        return;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 8:
+        fntable = pl110_draw_fn_8;
+        dest_width = 1;
+        break;
+    case 15:
+        fntable = pl110_draw_fn_15;
+        dest_width = 2;
+        break;
+    case 16:
+        fntable = pl110_draw_fn_16;
+        dest_width = 2;
+        break;
+    case 24:
+        fntable = pl110_draw_fn_24;
+        dest_width = 3;
+        break;
+    case 32:
+        fntable = pl110_draw_fn_32;
+        dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "pl110: Bad color depth\n");
+        exit(1);
+    }
+    if (s->cr & PL110_CR_BGR)
+        bpp_offset = 0;
+    else
+        bpp_offset = 18;
+
+    if (s->cr & PL110_CR_BEBO)
+        fn = fntable[s->bpp + 6 + bpp_offset];
+    else if (s->cr & PL110_CR_BEPO)
+        fn = fntable[s->bpp + 12 + bpp_offset];
+    else
+        fn = fntable[s->bpp + bpp_offset];
+
+    src_width = s->cols;
+    switch (s->bpp) {
+    case BPP_1:
+        src_width >>= 3;
+        break;
+    case BPP_2:
+        src_width >>= 2;
+        break;
+    case BPP_4:
+        src_width >>= 1;
+        break;
+    case BPP_8:
+        break;
+    case BPP_16:
+        src_width <<= 1;
+        break;
+    case BPP_32:
+        src_width <<= 2;
+        break;
+    }
+    dest_width *= s->cols;
+    first = 0;
+    framebuffer_update_display(s->ds,
+                               s->upbase, s->cols, s->rows,
+                               src_width, dest_width, 0,
+                               s->invalidate,
+                               fn, s->pallette,
+                               &first, &last);
+    if (first >= 0) {
+        dpy_update(s->ds, 0, first, s->cols, last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void pl110_invalidate_display(void * opaque)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    s->invalidate = 1;
+    if (pl110_enabled(s)) {
+        qemu_console_resize(s->ds, s->cols, s->rows);
+    }
+}
+
+static void pl110_update_pallette(pl110_state *s, int n)
+{
+    int i;
+    uint32_t raw;
+    unsigned int r, g, b;
+
+    raw = s->raw_pallette[n];
+    n <<= 1;
+    for (i = 0; i < 2; i++) {
+        r = (raw & 0x1f) << 3;
+        raw >>= 5;
+        g = (raw & 0x1f) << 3;
+        raw >>= 5;
+        b = (raw & 0x1f) << 3;
+        /* The I bit is ignored.  */
+        raw >>= 6;
+        switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            s->pallette[n] = rgb_to_pixel8(r, g, b);
+            break;
+        case 15:
+            s->pallette[n] = rgb_to_pixel15(r, g, b);
+            break;
+        case 16:
+            s->pallette[n] = rgb_to_pixel16(r, g, b);
+            break;
+        case 24:
+        case 32:
+            s->pallette[n] = rgb_to_pixel32(r, g, b);
+            break;
+        }
+        n++;
+    }
+}
+
+static void pl110_resize(pl110_state *s, int width, int height)
+{
+    if (width != s->cols || height != s->rows) {
+        if (pl110_enabled(s)) {
+            qemu_console_resize(s->ds, width, height);
+        }
+    }
+    s->cols = width;
+    s->rows = height;
+}
+
+/* Update interrupts.  */
+static void pl110_update(pl110_state *s)
+{
+  /* TODO: Implement interrupts.  */
+}
+
+static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
+{
+    pl110_state *s = (pl110_state *)opaque;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        if (s->versatile)
+            return pl110_versatile_id[(offset - 0xfe0) >> 2];
+        else
+            return pl110_id[(offset - 0xfe0) >> 2];
+    }
+    if (offset >= 0x200 && offset < 0x400) {
+        return s->raw_pallette[(offset - 0x200) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* LCDTiming0 */
+        return s->timing[0];
+    case 1: /* LCDTiming1 */
+        return s->timing[1];
+    case 2: /* LCDTiming2 */
+        return s->timing[2];
+    case 3: /* LCDTiming3 */
+        return s->timing[3];
+    case 4: /* LCDUPBASE */
+        return s->upbase;
+    case 5: /* LCDLPBASE */
+        return s->lpbase;
+    case 6: /* LCDIMSC */
+	if (s->versatile)
+	  return s->cr;
+        return s->int_mask;
+    case 7: /* LCDControl */
+	if (s->versatile)
+	  return s->int_mask;
+        return s->cr;
+    case 8: /* LCDRIS */
+        return s->int_status;
+    case 9: /* LCDMIS */
+        return s->int_status & s->int_mask;
+    case 11: /* LCDUPCURR */
+        /* TODO: Implement vertical refresh.  */
+        return s->upbase;
+    case 12: /* LCDLPCURR */
+        return s->lpbase;
+    default:
+        hw_error("pl110_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl110_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t val)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    int n;
+
+    /* For simplicity invalidate the display whenever a control register
+       is writen to.  */
+    s->invalidate = 1;
+    if (offset >= 0x200 && offset < 0x400) {
+        /* Pallette.  */
+        n = (offset - 0x200) >> 2;
+        s->raw_pallette[(offset - 0x200) >> 2] = val;
+        pl110_update_pallette(s, n);
+        return;
+    }
+    switch (offset >> 2) {
+    case 0: /* LCDTiming0 */
+        s->timing[0] = val;
+        n = ((val & 0xfc) + 4) * 4;
+        pl110_resize(s, n, s->rows);
+        break;
+    case 1: /* LCDTiming1 */
+        s->timing[1] = val;
+        n = (val & 0x3ff) + 1;
+        pl110_resize(s, s->cols, n);
+        break;
+    case 2: /* LCDTiming2 */
+        s->timing[2] = val;
+        break;
+    case 3: /* LCDTiming3 */
+        s->timing[3] = val;
+        break;
+    case 4: /* LCDUPBASE */
+        s->upbase = val;
+        break;
+    case 5: /* LCDLPBASE */
+        s->lpbase = val;
+        break;
+    case 6: /* LCDIMSC */
+        if (s->versatile)
+            goto control;
+    imsc:
+        s->int_mask = val;
+        pl110_update(s);
+        break;
+    case 7: /* LCDControl */
+        if (s->versatile)
+            goto imsc;
+    control:
+        s->cr = val;
+        s->bpp = (val >> 1) & 7;
+        if (pl110_enabled(s)) {
+            qemu_console_resize(s->ds, s->cols, s->rows);
+        }
+        break;
+    case 10: /* LCDICR */
+        s->int_status &= ~val;
+        pl110_update(s);
+        break;
+    default:
+        hw_error("pl110_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static CPUReadMemoryFunc * const pl110_readfn[] = {
+   pl110_read,
+   pl110_read,
+   pl110_read
+};
+
+static CPUWriteMemoryFunc * const pl110_writefn[] = {
+   pl110_write,
+   pl110_write,
+   pl110_write
+};
+
+static int pl110_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(pl110_readfn,
+                                       pl110_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->ds = graphic_console_init(pl110_update_display,
+                                 pl110_invalidate_display,
+                                 NULL, NULL, s);
+    return 0;
+}
+
+static int pl110_versatile_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+    s->versatile = 1;
+    return pl110_init(dev);
+}
+
+static SysBusDeviceInfo pl110_info = {
+    .init = pl110_init,
+    .qdev.name = "pl110",
+    .qdev.size = sizeof(pl110_state),
+    .qdev.vmsd = &vmstate_pl110,
+    .qdev.no_user = 1,
+};
+
+static SysBusDeviceInfo pl110_versatile_info = {
+    .init = pl110_versatile_init,
+    .qdev.name = "pl110_versatile",
+    .qdev.size = sizeof(pl110_state),
+    .qdev.vmsd = &vmstate_pl110,
+    .qdev.no_user = 1,
+};
+
+static void pl110_register_devices(void)
+{
+    sysbus_register_withprop(&pl110_info);
+    sysbus_register_withprop(&pl110_versatile_info);
+}
+
+device_init(pl110_register_devices)
diff --git a/qemu-0.15.x/hw/pl110_template.h b/qemu-0.15.x/hw/pl110_template.h
new file mode 100644
index 0000000..d303336
--- /dev/null
+++ b/qemu-0.15.x/hw/pl110_template.h
@@ -0,0 +1,307 @@
+/*
+ * Arm PrimeCell PL110 Color LCD Controller
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU LGPL
+ *
+ * Framebuffer format conversion routines.
+ */
+
+#ifndef ORDER
+
+#if BITS == 8
+#define COPY_PIXEL(to, from) *(to++) = from
+#elif BITS == 15 || BITS == 16
+#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2;
+#elif BITS == 24
+#define COPY_PIXEL(to, from) \
+  *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16
+#elif BITS == 32
+#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4;
+#else
+#error unknown bit depth
+#endif
+
+#undef RGB
+#define BORDER bgr
+#define ORDER 0
+#include "pl110_template.h"
+#define ORDER 1
+#include "pl110_template.h"
+#define ORDER 2
+#include "pl110_template.h"
+#undef BORDER
+#define RGB
+#define BORDER rgb
+#define ORDER 0
+#include "pl110_template.h"
+#define ORDER 1
+#include "pl110_template.h"
+#define ORDER 2
+#include "pl110_template.h"
+#undef BORDER
+
+static drawfn glue(pl110_draw_fn_,BITS)[36] =
+{
+    glue(pl110_draw_line1_lblp_bgr,BITS),
+    glue(pl110_draw_line2_lblp_bgr,BITS),
+    glue(pl110_draw_line4_lblp_bgr,BITS),
+    glue(pl110_draw_line8_lblp_bgr,BITS),
+    glue(pl110_draw_line16_lblp_bgr,BITS),
+    glue(pl110_draw_line32_lblp_bgr,BITS),
+
+    glue(pl110_draw_line1_bbbp_bgr,BITS),
+    glue(pl110_draw_line2_bbbp_bgr,BITS),
+    glue(pl110_draw_line4_bbbp_bgr,BITS),
+    glue(pl110_draw_line8_bbbp_bgr,BITS),
+    glue(pl110_draw_line16_bbbp_bgr,BITS),
+    glue(pl110_draw_line32_bbbp_bgr,BITS),
+
+    glue(pl110_draw_line1_lbbp_bgr,BITS),
+    glue(pl110_draw_line2_lbbp_bgr,BITS),
+    glue(pl110_draw_line4_lbbp_bgr,BITS),
+    glue(pl110_draw_line8_lbbp_bgr,BITS),
+    glue(pl110_draw_line16_lbbp_bgr,BITS),
+    glue(pl110_draw_line32_lbbp_bgr,BITS),
+
+    glue(pl110_draw_line1_lblp_rgb,BITS),
+    glue(pl110_draw_line2_lblp_rgb,BITS),
+    glue(pl110_draw_line4_lblp_rgb,BITS),
+    glue(pl110_draw_line8_lblp_rgb,BITS),
+    glue(pl110_draw_line16_lblp_rgb,BITS),
+    glue(pl110_draw_line32_lblp_rgb,BITS),
+
+    glue(pl110_draw_line1_bbbp_rgb,BITS),
+    glue(pl110_draw_line2_bbbp_rgb,BITS),
+    glue(pl110_draw_line4_bbbp_rgb,BITS),
+    glue(pl110_draw_line8_bbbp_rgb,BITS),
+    glue(pl110_draw_line16_bbbp_rgb,BITS),
+    glue(pl110_draw_line32_bbbp_rgb,BITS),
+
+    glue(pl110_draw_line1_lbbp_rgb,BITS),
+    glue(pl110_draw_line2_lbbp_rgb,BITS),
+    glue(pl110_draw_line4_lbbp_rgb,BITS),
+    glue(pl110_draw_line8_lbbp_rgb,BITS),
+    glue(pl110_draw_line16_lbbp_rgb,BITS),
+    glue(pl110_draw_line32_lbbp_rgb,BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+
+#else
+
+#if ORDER == 0
+#define NAME glue(glue(lblp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#elif ORDER == 1
+#define NAME glue(glue(bbbp_, BORDER), BITS)
+#ifndef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#else
+#define SWAP_PIXELS 1
+#define NAME glue(glue(lbbp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#endif
+
+#define FN_2(x, y) FN(x, y) FN(x+1, y)
+#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
+#define FN_8(y) FN_4(0, y) FN_4(4, y)
+
+static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *pallette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]);
+#else
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]);
+#endif
+#ifdef SWAP_WORDS
+        FN_8(24)
+        FN_8(16)
+        FN_8(8)
+        FN_8(0)
+#else
+        FN_8(0)
+        FN_8(8)
+        FN_8(16)
+        FN_8(24)
+#endif
+#undef FN
+        width -= 32;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *pallette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]);
+#else
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]);
+#endif
+#ifdef SWAP_WORDS
+        FN_4(0, 24)
+        FN_4(0, 16)
+        FN_4(0, 8)
+        FN_4(0, 0)
+#else
+        FN_4(0, 0)
+        FN_4(0, 8)
+        FN_4(0, 16)
+        FN_4(0, 24)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *pallette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]);
+#else
+#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]);
+#endif
+#ifdef SWAP_WORDS
+        FN_2(0, 24)
+        FN_2(0, 16)
+        FN_2(0, 8)
+        FN_2(0, 0)
+#else
+        FN_2(0, 0)
+        FN_2(0, 8)
+        FN_2(0, 16)
+        FN_2(0, 24)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *pallette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#if 0
+        LSB = data & 0x1f;
+        data >>= 5;
+        g = data & 0x3f;
+        data >>= 6;
+        MSB = data & 0x1f;
+        data >>= 5;
+#else
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+#endif
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#ifndef SWAP_WORDS
+        LSB = data & 0xff;
+        g = (data >> 8) & 0xff;
+        MSB = (data >> 16) & 0xff;
+#else
+        LSB = (data >> 24) & 0xff;
+        g = (data >> 16) & 0xff;
+        MSB = (data >> 8) & 0xff;
+#endif
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width--;
+        src += 4;
+    }
+}
+
+#undef SWAP_PIXELS
+#undef NAME
+#undef SWAP_WORDS
+#undef ORDER
+
+#endif
diff --git a/qemu-0.15.x/hw/pl181.c b/qemu-0.15.x/hw/pl181.c
new file mode 100644
index 0000000..0943c09
--- /dev/null
+++ b/qemu-0.15.x/hw/pl181.c
@@ -0,0 +1,479 @@
+/*
+ * Arm PrimeCell PL181 MultiMedia Card Interface
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "blockdev.h"
+#include "sysbus.h"
+#include "sd.h"
+
+//#define DEBUG_PL181 1
+
+#ifdef DEBUG_PL181
+#define DPRINTF(fmt, ...) \
+do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define PL181_FIFO_LEN 16
+
+typedef struct {
+    SysBusDevice busdev;
+    SDState *card;
+    uint32_t clock;
+    uint32_t power;
+    uint32_t cmdarg;
+    uint32_t cmd;
+    uint32_t datatimer;
+    uint32_t datalength;
+    uint32_t respcmd;
+    uint32_t response[4];
+    uint32_t datactrl;
+    uint32_t datacnt;
+    uint32_t status;
+    uint32_t mask[2];
+    int fifo_pos;
+    int fifo_len;
+    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
+       while it is reading the FIFO.  We hack around this be defering
+       subsequent transfers until after the driver polls the status word.
+       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
+     */
+    int linux_hack;
+    uint32_t fifo[PL181_FIFO_LEN];
+    qemu_irq irq[2];
+    /* GPIO outputs for 'card is readonly' and 'card inserted' */
+    qemu_irq cardstatus[2];
+} pl181_state;
+
+#define PL181_CMD_INDEX     0x3f
+#define PL181_CMD_RESPONSE  (1 << 6)
+#define PL181_CMD_LONGRESP  (1 << 7)
+#define PL181_CMD_INTERRUPT (1 << 8)
+#define PL181_CMD_PENDING   (1 << 9)
+#define PL181_CMD_ENABLE    (1 << 10)
+
+#define PL181_DATA_ENABLE             (1 << 0)
+#define PL181_DATA_DIRECTION          (1 << 1)
+#define PL181_DATA_MODE               (1 << 2)
+#define PL181_DATA_DMAENABLE          (1 << 3)
+
+#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
+#define PL181_STATUS_DATACRCFAIL      (1 << 1)
+#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
+#define PL181_STATUS_DATATIMEOUT      (1 << 3)
+#define PL181_STATUS_TXUNDERRUN       (1 << 4)
+#define PL181_STATUS_RXOVERRUN        (1 << 5)
+#define PL181_STATUS_CMDRESPEND       (1 << 6)
+#define PL181_STATUS_CMDSENT          (1 << 7)
+#define PL181_STATUS_DATAEND          (1 << 8)
+#define PL181_STATUS_DATABLOCKEND     (1 << 10)
+#define PL181_STATUS_CMDACTIVE        (1 << 11)
+#define PL181_STATUS_TXACTIVE         (1 << 12)
+#define PL181_STATUS_RXACTIVE         (1 << 13)
+#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
+#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
+#define PL181_STATUS_TXFIFOFULL       (1 << 16)
+#define PL181_STATUS_RXFIFOFULL       (1 << 17)
+#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
+#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
+#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
+#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
+
+#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
+                             |PL181_STATUS_TXFIFOHALFEMPTY \
+                             |PL181_STATUS_TXFIFOFULL \
+                             |PL181_STATUS_TXFIFOEMPTY \
+                             |PL181_STATUS_TXDATAAVLBL)
+#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
+                             |PL181_STATUS_RXFIFOHALFFULL \
+                             |PL181_STATUS_RXFIFOFULL \
+                             |PL181_STATUS_RXFIFOEMPTY \
+                             |PL181_STATUS_RXDATAAVLBL)
+
+static const unsigned char pl181_id[] =
+{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl181_update(pl181_state *s)
+{
+    int i;
+    for (i = 0; i < 2; i++) {
+        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
+    }
+}
+
+static void pl181_fifo_push(pl181_state *s, uint32_t value)
+{
+    int n;
+
+    if (s->fifo_len == PL181_FIFO_LEN) {
+        fprintf(stderr, "pl181: FIFO overflow\n");
+        return;
+    }
+    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
+    s->fifo_len++;
+    s->fifo[n] = value;
+    DPRINTF("FIFO push %08x\n", (int)value);
+}
+
+static uint32_t pl181_fifo_pop(pl181_state *s)
+{
+    uint32_t value;
+
+    if (s->fifo_len == 0) {
+        fprintf(stderr, "pl181: FIFO underflow\n");
+        return 0;
+    }
+    value = s->fifo[s->fifo_pos];
+    s->fifo_len--;
+    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
+    DPRINTF("FIFO pop %08x\n", (int)value);
+    return value;
+}
+
+static void pl181_send_command(pl181_state *s)
+{
+    SDRequest request;
+    uint8_t response[16];
+    int rlen;
+
+    request.cmd = s->cmd & PL181_CMD_INDEX;
+    request.arg = s->cmdarg;
+    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
+    rlen = sd_do_command(s->card, &request, response);
+    if (rlen < 0)
+        goto error;
+    if (s->cmd & PL181_CMD_RESPONSE) {
+#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
+                  | (response[n + 2] << 8) | response[n + 3])
+        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
+            goto error;
+        if (rlen != 4 && rlen != 16)
+            goto error;
+        s->response[0] = RWORD(0);
+        if (rlen == 4) {
+            s->response[1] = s->response[2] = s->response[3] = 0;
+        } else {
+            s->response[1] = RWORD(4);
+            s->response[2] = RWORD(8);
+            s->response[3] = RWORD(12) & ~1;
+        }
+        DPRINTF("Response received\n");
+        s->status |= PL181_STATUS_CMDRESPEND;
+#undef RWORD
+    } else {
+        DPRINTF("Command sent\n");
+        s->status |= PL181_STATUS_CMDSENT;
+    }
+    return;
+
+error:
+    DPRINTF("Timeout\n");
+    s->status |= PL181_STATUS_CMDTIMEOUT;
+}
+
+/* Transfer data between the card and the FIFO.  This is complicated by
+   the FIFO holding 32-bit words and the card taking data in single byte
+   chunks.  FIFO bytes are transferred in little-endian order.  */
+
+static void pl181_fifo_run(pl181_state *s)
+{
+    uint32_t bits;
+    uint32_t value = 0;
+    int n;
+    int is_read;
+
+    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
+    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
+            && !s->linux_hack) {
+        if (is_read) {
+            n = 0;
+            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
+                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+                s->datacnt--;
+                n++;
+                if (n == 4) {
+                    pl181_fifo_push(s, value);
+                    n = 0;
+                    value = 0;
+                }
+            }
+            if (n != 0) {
+                pl181_fifo_push(s, value);
+            }
+        } else { /* write */
+            n = 0;
+            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
+                if (n == 0) {
+                    value = pl181_fifo_pop(s);
+                    n = 4;
+                }
+                n--;
+                s->datacnt--;
+                sd_write_data(s->card, value & 0xff);
+                value >>= 8;
+            }
+        }
+    }
+    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
+    if (s->datacnt == 0) {
+        s->status |= PL181_STATUS_DATAEND;
+        /* HACK: */
+        s->status |= PL181_STATUS_DATABLOCKEND;
+        DPRINTF("Transfer Complete\n");
+    }
+    if (s->datacnt == 0 && s->fifo_len == 0) {
+        s->datactrl &= ~PL181_DATA_ENABLE;
+        DPRINTF("Data engine idle\n");
+    } else {
+        /* Update FIFO bits.  */
+        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
+        if (s->fifo_len == 0) {
+            bits |= PL181_STATUS_TXFIFOEMPTY;
+            bits |= PL181_STATUS_RXFIFOEMPTY;
+        } else {
+            bits |= PL181_STATUS_TXDATAAVLBL;
+            bits |= PL181_STATUS_RXDATAAVLBL;
+        }
+        if (s->fifo_len == 16) {
+            bits |= PL181_STATUS_TXFIFOFULL;
+            bits |= PL181_STATUS_RXFIFOFULL;
+        }
+        if (s->fifo_len <= 8) {
+            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
+        }
+        if (s->fifo_len >= 8) {
+            bits |= PL181_STATUS_RXFIFOHALFFULL;
+        }
+        if (s->datactrl & PL181_DATA_DIRECTION) {
+            bits &= PL181_STATUS_RX_FIFO;
+        } else {
+            bits &= PL181_STATUS_TX_FIFO;
+        }
+        s->status |= bits;
+    }
+}
+
+static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
+{
+    pl181_state *s = (pl181_state *)opaque;
+    uint32_t tmp;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl181_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset) {
+    case 0x00: /* Power */
+        return s->power;
+    case 0x04: /* Clock */
+        return s->clock;
+    case 0x08: /* Argument */
+        return s->cmdarg;
+    case 0x0c: /* Command */
+        return s->cmd;
+    case 0x10: /* RespCmd */
+        return s->respcmd;
+    case 0x14: /* Response0 */
+        return s->response[0];
+    case 0x18: /* Response1 */
+        return s->response[1];
+    case 0x1c: /* Response2 */
+        return s->response[2];
+    case 0x20: /* Response3 */
+        return s->response[3];
+    case 0x24: /* DataTimer */
+        return s->datatimer;
+    case 0x28: /* DataLength */
+        return s->datalength;
+    case 0x2c: /* DataCtrl */
+        return s->datactrl;
+    case 0x30: /* DataCnt */
+        return s->datacnt;
+    case 0x34: /* Status */
+        tmp = s->status;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x3c: /* Mask0 */
+        return s->mask[0];
+    case 0x40: /* Mask1 */
+        return s->mask[1];
+    case 0x48: /* FifoCnt */
+        /* The documentation is somewhat vague about exactly what FifoCnt
+           does.  On real hardware it appears to be when decrememnted
+           when a word is transfered between the FIFO and the serial
+           data engine.  DataCnt is decremented after each byte is
+           transfered between the serial engine and the card.
+           We don't emulate this level of detail, so both can be the same.  */
+        tmp = (s->datacnt + 3) >> 2;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->fifo_len == 0) {
+            fprintf(stderr, "pl181: Unexpected FIFO read\n");
+            return 0;
+        } else {
+            uint32_t value;
+            value = pl181_fifo_pop(s);
+            s->linux_hack = 1;
+            pl181_fifo_run(s);
+            pl181_update(s);
+            return value;
+        }
+    default:
+        hw_error("pl181_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl181_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl181_state *s = (pl181_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* Power */
+        s->power = value & 0xff;
+        break;
+    case 0x04: /* Clock */
+        s->clock = value & 0xff;
+        break;
+    case 0x08: /* Argument */
+        s->cmdarg = value;
+        break;
+    case 0x0c: /* Command */
+        s->cmd = value;
+        if (s->cmd & PL181_CMD_ENABLE) {
+            if (s->cmd & PL181_CMD_INTERRUPT) {
+                fprintf(stderr, "pl181: Interrupt mode not implemented\n");
+                abort();
+            } if (s->cmd & PL181_CMD_PENDING) {
+                fprintf(stderr, "pl181: Pending commands not implemented\n");
+                abort();
+            } else {
+                pl181_send_command(s);
+                pl181_fifo_run(s);
+            }
+            /* The command has completed one way or the other.  */
+            s->cmd &= ~PL181_CMD_ENABLE;
+        }
+        break;
+    case 0x24: /* DataTimer */
+        s->datatimer = value;
+        break;
+    case 0x28: /* DataLength */
+        s->datalength = value & 0xffff;
+        break;
+    case 0x2c: /* DataCtrl */
+        s->datactrl = value & 0xff;
+        if (value & PL181_DATA_ENABLE) {
+            s->datacnt = s->datalength;
+            pl181_fifo_run(s);
+        }
+        break;
+    case 0x38: /* Clear */
+        s->status &= ~(value & 0x7ff);
+        break;
+    case 0x3c: /* Mask0 */
+        s->mask[0] = value;
+        break;
+    case 0x40: /* Mask1 */
+        s->mask[1] = value;
+        break;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->datacnt == 0) {
+            fprintf(stderr, "pl181: Unexpected FIFO write\n");
+        } else {
+            pl181_fifo_push(s, value);
+            pl181_fifo_run(s);
+        }
+        break;
+    default:
+        hw_error("pl181_write: Bad offset %x\n", (int)offset);
+    }
+    pl181_update(s);
+}
+
+static CPUReadMemoryFunc * const pl181_readfn[] = {
+   pl181_read,
+   pl181_read,
+   pl181_read
+};
+
+static CPUWriteMemoryFunc * const pl181_writefn[] = {
+   pl181_write,
+   pl181_write,
+   pl181_write
+};
+
+static void pl181_reset(void *opaque)
+{
+    pl181_state *s = (pl181_state *)opaque;
+
+    s->power = 0;
+    s->cmdarg = 0;
+    s->cmd = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->respcmd = 0;
+    s->response[0] = 0;
+    s->response[1] = 0;
+    s->response[2] = 0;
+    s->response[3] = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->datactrl = 0;
+    s->datacnt = 0;
+    s->status = 0;
+    s->linux_hack = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+
+    /* We can assume our GPIO outputs have been wired up now */
+    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
+}
+
+static int pl181_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
+    DriveInfo *dinfo;
+
+    iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq[0]);
+    sysbus_init_irq(dev, &s->irq[1]);
+    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    qemu_register_reset(pl181_reset, s);
+    pl181_reset(s);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+static void pl181_register_devices(void)
+{
+    sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
+}
+
+device_init(pl181_register_devices)
diff --git a/qemu-0.15.x/hw/pl190.c b/qemu-0.15.x/hw/pl190.c
new file mode 100644
index 0000000..8dc7e42
--- /dev/null
+++ b/qemu-0.15.x/hw/pl190.c
@@ -0,0 +1,278 @@
+/*
+ * Arm PrimeCell PL190 Vector Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+
+/* The number of virtual priority levels.  16 user vectors plus the
+   unvectored IRQ.  Chained interrupts would require an additional level
+   if implemented.  */
+
+#define PL190_NUM_PRIO 17
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t level;
+    uint32_t soft_level;
+    uint32_t irq_enable;
+    uint32_t fiq_select;
+    uint8_t vect_control[16];
+    uint32_t vect_addr[PL190_NUM_PRIO];
+    /* Mask containing interrupts with higher priority than this one.  */
+    uint32_t prio_mask[PL190_NUM_PRIO + 1];
+    int protected;
+    /* Current priority level.  */
+    int priority;
+    int prev_prio[PL190_NUM_PRIO];
+    qemu_irq irq;
+    qemu_irq fiq;
+} pl190_state;
+
+static const unsigned char pl190_id[] =
+{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
+
+static inline uint32_t pl190_irq_level(pl190_state *s)
+{
+    return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
+}
+
+/* Update interrupts.  */
+static void pl190_update(pl190_state *s)
+{
+    uint32_t level = pl190_irq_level(s);
+    int set;
+
+    set = (level & s->prio_mask[s->priority]) != 0;
+    qemu_set_irq(s->irq, set);
+    set = ((s->level | s->soft_level) & s->fiq_select) != 0;
+    qemu_set_irq(s->fiq, set);
+}
+
+static void pl190_set_irq(void *opaque, int irq, int level)
+{
+    pl190_state *s = (pl190_state *)opaque;
+
+    if (level)
+        s->level |= 1u << irq;
+    else
+        s->level &= ~(1u << irq);
+    pl190_update(s);
+}
+
+static void pl190_update_vectors(pl190_state *s)
+{
+    uint32_t mask;
+    int i;
+    int n;
+
+    mask = 0;
+    for (i = 0; i < 16; i++)
+      {
+        s->prio_mask[i] = mask;
+        if (s->vect_control[i] & 0x20)
+          {
+            n = s->vect_control[i] & 0x1f;
+            mask |= 1 << n;
+          }
+      }
+    s->prio_mask[16] = mask;
+    pl190_update(s);
+}
+
+static uint32_t pl190_read(void *opaque, target_phys_addr_t offset)
+{
+    pl190_state *s = (pl190_state *)opaque;
+    int i;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl190_id[(offset - 0xfe0) >> 2];
+    }
+    if (offset >= 0x100 && offset < 0x140) {
+        return s->vect_addr[(offset - 0x100) >> 2];
+    }
+    if (offset >= 0x200 && offset < 0x240) {
+        return s->vect_control[(offset - 0x200) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* IRQSTATUS */
+        return pl190_irq_level(s);
+    case 1: /* FIQSATUS */
+        return (s->level | s->soft_level) & s->fiq_select;
+    case 2: /* RAWINTR */
+        return s->level | s->soft_level;
+    case 3: /* INTSELECT */
+        return s->fiq_select;
+    case 4: /* INTENABLE */
+        return s->irq_enable;
+    case 6: /* SOFTINT */
+        return s->soft_level;
+    case 8: /* PROTECTION */
+        return s->protected;
+    case 12: /* VECTADDR */
+        /* Read vector address at the start of an ISR.  Increases the
+           current priority level to that of the current interrupt.  */
+        for (i = 0; i < s->priority; i++)
+          {
+            if ((s->level | s->soft_level) & s->prio_mask[i])
+              break;
+          }
+        /* Reading this value with no pending interrupts is undefined.
+           We return the default address.  */
+        if (i == PL190_NUM_PRIO)
+          return s->vect_addr[16];
+        if (i < s->priority)
+          {
+            s->prev_prio[i] = s->priority;
+            s->priority = i;
+            pl190_update(s);
+          }
+        return s->vect_addr[s->priority];
+    case 13: /* DEFVECTADDR */
+        return s->vect_addr[16];
+    default:
+        hw_error("pl190_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val)
+{
+    pl190_state *s = (pl190_state *)opaque;
+
+    if (offset >= 0x100 && offset < 0x140) {
+        s->vect_addr[(offset - 0x100) >> 2] = val;
+        pl190_update_vectors(s);
+        return;
+    }
+    if (offset >= 0x200 && offset < 0x240) {
+        s->vect_control[(offset - 0x200) >> 2] = val;
+        pl190_update_vectors(s);
+        return;
+    }
+    switch (offset >> 2) {
+    case 0: /* SELECT */
+        /* This is a readonly register, but linux tries to write to it
+           anyway.  Ignore the write.  */
+        break;
+    case 3: /* INTSELECT */
+        s->fiq_select = val;
+        break;
+    case 4: /* INTENABLE */
+        s->irq_enable |= val;
+        break;
+    case 5: /* INTENCLEAR */
+        s->irq_enable &= ~val;
+        break;
+    case 6: /* SOFTINT */
+        s->soft_level |= val;
+        break;
+    case 7: /* SOFTINTCLEAR */
+        s->soft_level &= ~val;
+        break;
+    case 8: /* PROTECTION */
+        /* TODO: Protection (supervisor only access) is not implemented.  */
+        s->protected = val & 1;
+        break;
+    case 12: /* VECTADDR */
+        /* Restore the previous priority level.  The value written is
+           ignored.  */
+        if (s->priority < PL190_NUM_PRIO)
+            s->priority = s->prev_prio[s->priority];
+        break;
+    case 13: /* DEFVECTADDR */
+        s->vect_addr[16] = val;
+        break;
+    case 0xc0: /* ITCR */
+        if (val) {
+            hw_error("pl190: Test mode not implemented\n");
+        }
+        break;
+    default:
+        hw_error("pl190_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    pl190_update(s);
+}
+
+static CPUReadMemoryFunc * const pl190_readfn[] = {
+   pl190_read,
+   pl190_read,
+   pl190_read
+};
+
+static CPUWriteMemoryFunc * const pl190_writefn[] = {
+   pl190_write,
+   pl190_write,
+   pl190_write
+};
+
+static void pl190_reset(DeviceState *d)
+{
+  pl190_state *s = DO_UPCAST(pl190_state, busdev.qdev, d);
+  int i;
+
+  for (i = 0; i < 16; i++)
+    {
+      s->vect_addr[i] = 0;
+      s->vect_control[i] = 0;
+    }
+  s->vect_addr[16] = 0;
+  s->prio_mask[17] = 0xffffffff;
+  s->priority = PL190_NUM_PRIO;
+  pl190_update_vectors(s);
+}
+
+static int pl190_init(SysBusDevice *dev)
+{
+    pl190_state *s = FROM_SYSBUS(pl190_state, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(pl190_readfn,
+                                       pl190_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl190 = {
+    .name = "pl190",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, pl190_state),
+        VMSTATE_UINT32(soft_level, pl190_state),
+        VMSTATE_UINT32(irq_enable, pl190_state),
+        VMSTATE_UINT32(fiq_select, pl190_state),
+        VMSTATE_UINT8_ARRAY(vect_control, pl190_state, 16),
+        VMSTATE_UINT32_ARRAY(vect_addr, pl190_state, PL190_NUM_PRIO),
+        VMSTATE_UINT32_ARRAY(prio_mask, pl190_state, PL190_NUM_PRIO+1),
+        VMSTATE_INT32(protected, pl190_state),
+        VMSTATE_INT32(priority, pl190_state),
+        VMSTATE_INT32_ARRAY(prev_prio, pl190_state, PL190_NUM_PRIO),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo pl190_info = {
+    .init = pl190_init,
+    .qdev.name = "pl190",
+    .qdev.size = sizeof(pl190_state),
+    .qdev.vmsd = &vmstate_pl190,
+    .qdev.reset = pl190_reset,
+    .qdev.no_user = 1,
+};
+
+static void pl190_register_devices(void)
+{
+    sysbus_register_withprop(&pl190_info);
+}
+
+device_init(pl190_register_devices)
diff --git a/qemu-0.15.x/hw/pm_smbus.c b/qemu-0.15.x/hw/pm_smbus.c
new file mode 100644
index 0000000..5d6046d
--- /dev/null
+++ b/qemu-0.15.x/hw/pm_smbus.c
@@ -0,0 +1,176 @@
+/*
+ * PC SMBus implementation
+ * splitted from acpi.c
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pm_smbus.h"
+#include "smbus.h"
+
+/* no save/load? */
+
+#define SMBHSTSTS       0x00
+#define SMBHSTCNT       0x02
+#define SMBHSTCMD       0x03
+#define SMBHSTADD       0x04
+#define SMBHSTDAT0      0x05
+#define SMBHSTDAT1      0x06
+#define SMBBLKDAT       0x07
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define SMBUS_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
+#else
+# define SMBUS_DPRINTF(format, ...)     do { } while (0)
+#endif
+
+
+static void smb_transaction(PMSMBus *s)
+{
+    uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+    uint8_t read = s->smb_addr & 0x01;
+    uint8_t cmd = s->smb_cmd;
+    uint8_t addr = s->smb_addr >> 1;
+    i2c_bus *bus = s->smbus;
+
+    SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
+    switch(prot) {
+    case 0x0:
+        smbus_quick_command(bus, addr, read);
+        break;
+    case 0x1:
+        if (read) {
+            s->smb_data0 = smbus_receive_byte(bus, addr);
+        } else {
+            smbus_send_byte(bus, addr, cmd);
+        }
+        break;
+    case 0x2:
+        if (read) {
+            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+        } else {
+            smbus_write_byte(bus, addr, cmd, s->smb_data0);
+        }
+        break;
+    case 0x3:
+        if (read) {
+            uint16_t val;
+            val = smbus_read_word(bus, addr, cmd);
+            s->smb_data0 = val;
+            s->smb_data1 = val >> 8;
+        } else {
+            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+        }
+        break;
+    case 0x5:
+        if (read) {
+            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+        } else {
+            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
+        }
+        break;
+    default:
+        goto error;
+    }
+    return;
+
+  error:
+    s->smb_stat |= 0x04;
+}
+
+void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PMSMBus *s = opaque;
+    addr &= 0x3f;
+    SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
+    switch(addr) {
+    case SMBHSTSTS:
+        s->smb_stat = 0;
+        s->smb_index = 0;
+        break;
+    case SMBHSTCNT:
+        s->smb_ctl = val;
+        if (val & 0x40)
+            smb_transaction(s);
+        break;
+    case SMBHSTCMD:
+        s->smb_cmd = val;
+        break;
+    case SMBHSTADD:
+        s->smb_addr = val;
+        break;
+    case SMBHSTDAT0:
+        s->smb_data0 = val;
+        break;
+    case SMBHSTDAT1:
+        s->smb_data1 = val;
+        break;
+    case SMBBLKDAT:
+        s->smb_data[s->smb_index++] = val;
+        if (s->smb_index > 31)
+            s->smb_index = 0;
+        break;
+    default:
+        break;
+    }
+}
+
+uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
+{
+    PMSMBus *s = opaque;
+    uint32_t val;
+
+    addr &= 0x3f;
+    switch(addr) {
+    case SMBHSTSTS:
+        val = s->smb_stat;
+        break;
+    case SMBHSTCNT:
+        s->smb_index = 0;
+        val = s->smb_ctl & 0x1f;
+        break;
+    case SMBHSTCMD:
+        val = s->smb_cmd;
+        break;
+    case SMBHSTADD:
+        val = s->smb_addr;
+        break;
+    case SMBHSTDAT0:
+        val = s->smb_data0;
+        break;
+    case SMBHSTDAT1:
+        val = s->smb_data1;
+        break;
+    case SMBBLKDAT:
+        val = s->smb_data[s->smb_index++];
+        if (s->smb_index > 31)
+            s->smb_index = 0;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
+    return val;
+}
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
+{
+    smb->smbus = i2c_init_bus(parent, "i2c");
+}
diff --git a/qemu-0.15.x/hw/pm_smbus.h b/qemu-0.15.x/hw/pm_smbus.h
new file mode 100644
index 0000000..4750a40
--- /dev/null
+++ b/qemu-0.15.x/hw/pm_smbus.h
@@ -0,0 +1,21 @@
+#ifndef PM_SMBUS_H
+#define PM_SMBUS_H
+
+typedef struct PMSMBus {
+    i2c_bus *smbus;
+
+    uint8_t smb_stat;
+    uint8_t smb_ctl;
+    uint8_t smb_cmd;
+    uint8_t smb_addr;
+    uint8_t smb_data0;
+    uint8_t smb_data1;
+    uint8_t smb_data[32];
+    uint8_t smb_index;
+} PMSMBus;
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
+void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val);
+uint32_t smb_ioport_readb(void *opaque, uint32_t addr);
+
+#endif /* !PM_SMBUS_H */
diff --git a/qemu-0.15.x/hw/ppc-viosrp.h b/qemu-0.15.x/hw/ppc-viosrp.h
new file mode 100644
index 0000000..d8e365d
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc-viosrp.h
@@ -0,0 +1,216 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef PPC_VIOSRP_H
+#define PPC_VIOSRP_H
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN    256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+    struct srp_login_req login_req;
+    struct srp_login_rsp login_rsp;
+    struct srp_login_rej login_rej;
+    struct srp_i_logout i_logout;
+    struct srp_t_logout t_logout;
+    struct srp_tsk_mgmt tsk_mgmt;
+    struct srp_cmd cmd;
+    struct srp_rsp rsp;
+    uint8_t reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_formats {
+    VIOSRP_SRP_FORMAT = 0x01,
+    VIOSRP_MAD_FORMAT = 0x02,
+    VIOSRP_OS400_FORMAT = 0x03,
+    VIOSRP_AIX_FORMAT = 0x04,
+    VIOSRP_LINUX_FORMAT = 0x06,
+    VIOSRP_INLINE_FORMAT = 0x07
+};
+
+enum viosrp_crq_status {
+    VIOSRP_OK = 0x0,
+    VIOSRP_NONRECOVERABLE_ERR = 0x1,
+    VIOSRP_VIOLATES_MAX_XFER = 0x2,
+    VIOSRP_PARTNER_PANIC = 0x3,
+    VIOSRP_DEVICE_BUSY = 0x8,
+    VIOSRP_ADAPTER_FAIL = 0x10,
+    VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+    uint8_t valid;        /* used by RPA */
+    uint8_t format;        /* SCSI vs out-of-band */
+    uint8_t reserved;
+    uint8_t status;        /* non-scsi failure? (e.g. DMA failure) */
+    uint16_t timeout;        /* in seconds */
+    uint16_t IU_length;        /* in bytes */
+    uint64_t IU_data_ptr;    /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+    VIOSRP_EMPTY_IU_TYPE = 0x01,
+    VIOSRP_ERROR_LOG_TYPE = 0x02,
+    VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+    VIOSRP_HOST_CONFIG_TYPE = 0x04,
+    VIOSRP_CAPABILITIES_TYPE = 0x05,
+    VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+    VIOSRP_MAD_SUCCESS = 0x00,
+    VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+    VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+    MIGRATION_CAPABILITIES = 0x01,
+    RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+    SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+    SERVER_SUPPORTS_CAP = 0x01,
+    SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+    CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+    CLIENT_MIGRATED = 0x01,
+    CLIENT_RECONNECT = 0x02,
+    CAP_LIST_SUPPORTED = 0x04,
+    CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+    uint32_t type;
+    uint16_t status;
+    uint16_t length;
+    uint64_t tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+    struct mad_common common;
+    uint64_t buffer;
+    uint32_t port;
+};
+
+struct viosrp_error_log {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_adapter_info {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_host_config {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_fast_fail {
+    struct mad_common common;
+};
+
+struct viosrp_capabilities {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct mad_capability_common {
+    uint32_t cap_type;
+    uint16_t length;
+    uint16_t server_support;
+};
+
+struct mad_reserve_cap {
+    struct mad_capability_common common;
+    uint32_t type;
+};
+
+struct mad_migration_cap {
+    struct mad_capability_common common;
+    uint32_t ecl;
+};
+
+struct capabilities {
+    uint32_t flags;
+    char name[SRP_MAX_LOC_LEN];
+    char loc[SRP_MAX_LOC_LEN];
+    struct mad_migration_cap migration;
+    struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+    struct viosrp_empty_iu empty_iu;
+    struct viosrp_error_log error_log;
+    struct viosrp_adapter_info adapter_info;
+    struct viosrp_host_config host_config;
+    struct viosrp_fast_fail fast_fail;
+    struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+    union srp_iu srp;
+    union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+    char srp_version[8];
+    char partition_name[96];
+    uint32_t partition_number;
+    uint32_t mad_version;
+    uint32_t os_type;
+    uint32_t port_max_txu[8];    /* per-port maximum transfer */
+};
+
+#endif
diff --git a/qemu-0.15.x/hw/ppc.c b/qemu-0.15.x/hw/ppc.c
new file mode 100644
index 0000000..9157719
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc.c
@@ -0,0 +1,1335 @@
+/*
+ * QEMU generic PowerPC hardware System Emulator
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "nvram.h"
+#include "qemu-log.h"
+#include "loader.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+
+//#define PPC_DEBUG_IRQ
+//#define PPC_DEBUG_TB
+
+#ifdef PPC_DEBUG_IRQ
+#  define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#else
+#  define LOG_IRQ(...) do { } while (0)
+#endif
+
+
+#ifdef PPC_DEBUG_TB
+#  define LOG_TB(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_TB(...) do { } while (0)
+#endif
+
+static void cpu_ppc_tb_stop (CPUState *env);
+static void cpu_ppc_tb_start (CPUState *env);
+
+static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+{
+    unsigned int old_pending = env->pending_interrupts;
+
+    if (level) {
+        env->pending_interrupts |= 1 << n_IRQ;
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        env->pending_interrupts &= ~(1 << n_IRQ);
+        if (env->pending_interrupts == 0)
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+
+    if (old_pending != env->pending_interrupts) {
+#ifdef CONFIG_KVM
+        kvmppc_set_interrupt(env, n_IRQ, level);
+#endif
+    }
+
+    LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
+                "req %08x\n", __func__, env, n_IRQ, level,
+                env->pending_interrupts, env->interrupt_request);
+}
+
+/* PowerPC 6xx / 7xx internal IRQ controller */
+static void ppc6xx_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC6xx_INPUT_TBEN:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: %s the time base\n",
+                        __func__, level ? "start" : "stop");
+            if (level) {
+                cpu_ppc_tb_start(env);
+            } else {
+                cpu_ppc_tb_stop(env);
+            }
+        case PPC6xx_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC6xx_INPUT_SMI:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the SMI IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
+            break;
+        case PPC6xx_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+                LOG_IRQ("%s: raise machine check state\n",
+                            __func__);
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC6xx_INPUT_CKSTP_IN:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            /* XXX: Note that the only way to restart the CPU is to reset it */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            }
+            break;
+        case PPC6xx_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+                LOG_IRQ("%s: reset the CPU\n", __func__);
+                env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+                /* XXX: TOFIX */
+#if 0
+                cpu_reset(env);
+#else
+                qemu_system_reset_request();
+#endif
+            }
+            break;
+        case PPC6xx_INPUT_SRESET:
+            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc6xx_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env,
+                                                  PPC6xx_INPUT_NB);
+}
+
+#if defined(TARGET_PPC64)
+/* PowerPC 970 internal IRQ controller */
+static void ppc970_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC970_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC970_INPUT_THINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
+                        level);
+            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
+            break;
+        case PPC970_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+                LOG_IRQ("%s: raise machine check state\n",
+                            __func__);
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC970_INPUT_CKSTP:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            } else {
+                LOG_IRQ("%s: restart the CPU\n", __func__);
+                env->halted = 0;
+                qemu_cpu_kick(env);
+            }
+            break;
+        case PPC970_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+#if 0 // XXX: TOFIX
+                LOG_IRQ("%s: reset the CPU\n", __func__);
+                cpu_reset(env);
+#endif
+            }
+            break;
+        case PPC970_INPUT_SRESET:
+            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+            break;
+        case PPC970_INPUT_TBEN:
+            LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
+                        level);
+            /* XXX: TODO */
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc970_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
+                                                  PPC970_INPUT_NB);
+}
+
+/* POWER7 internal IRQ controller */
+static void power7_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+
+    switch (pin) {
+    case POWER7_INPUT_INT:
+        /* Level sensitive - active high */
+        LOG_IRQ("%s: set the external IRQ state to %d\n",
+                __func__, level);
+        ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+        break;
+    default:
+        /* Unknown pin - do nothing */
+        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+        return;
+    }
+    if (level) {
+        env->irq_input_state |= 1 << pin;
+    } else {
+        env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppcPOWER7_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
+                                                  POWER7_INPUT_NB);
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* PowerPC 40x internal IRQ controller */
+static void ppc40x_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC40x_INPUT_RESET_SYS:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC system\n",
+                            __func__);
+                ppc40x_system_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CHIP:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
+                ppc40x_chip_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CORE:
+            /* XXX: TODO: update DBSR[MRR] */
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
+                ppc40x_core_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_CINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the critical IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
+            break;
+        case PPC40x_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC40x_INPUT_HALT:
+            /* Level sensitive - active low */
+            if (level) {
+                LOG_IRQ("%s: stop the CPU\n", __func__);
+                env->halted = 1;
+            } else {
+                LOG_IRQ("%s: restart the CPU\n", __func__);
+                env->halted = 0;
+                qemu_cpu_kick(env);
+            }
+            break;
+        case PPC40x_INPUT_DEBUG:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the debug pin state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc40x_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
+                                                  env, PPC40x_INPUT_NB);
+}
+
+/* PowerPC E500 internal IRQ controller */
+static void ppce500_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPCE500_INPUT_MCK:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC system\n",
+                            __func__);
+                qemu_system_reset_request();
+            }
+            break;
+        case PPCE500_INPUT_RESET_CORE:
+            if (level) {
+                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, level);
+            }
+            break;
+        case PPCE500_INPUT_CINT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the critical IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
+            break;
+        case PPCE500_INPUT_INT:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the core IRQ state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPCE500_INPUT_DEBUG:
+            /* Level sensitive - active high */
+            LOG_IRQ("%s: set the debug pin state to %d\n",
+                        __func__, level);
+            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppce500_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
+                                        env, PPCE500_INPUT_NB);
+}
+/*****************************************************************************/
+/* PowerPC time base and decrementer emulation */
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation                    */
+    int64_t  atb_offset;   /* Compensation                    */
+    uint32_t tb_freq;      /* TB frequency                    */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt    */
+    uint32_t decr_freq;    /* decrementer frequency           */
+    struct QEMUTimer *decr_timer;
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+    void *opaque;
+};
+
+static inline uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk,
+                                      int64_t tb_offset)
+{
+    /* TB time in tb periods */
+    return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
+}
+
+uint64_t cpu_ppc_load_tbl (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBL];
+    }
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb;
+}
+
+static inline uint32_t _cpu_ppc_load_tbu(CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb >> 32;
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+    if (kvm_enabled()) {
+        return env->spr[SPR_TBU];
+    }
+
+    return _cpu_ppc_load_tbu(env);
+}
+
+static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
+                                    int64_t *tb_offsetp, uint64_t value)
+{
+    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec());
+    LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
+                __func__, value, *tb_offsetp);
+}
+
+void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->tb_offset, tb | (uint64_t)value);
+}
+
+static inline void _cpu_ppc_store_tbu(CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint64_t cpu_ppc_load_atbl (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb;
+}
+
+uint32_t cpu_ppc_load_atbu (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
+
+    return tb >> 32;
+}
+
+void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->atb_offset, tb | (uint64_t)value);
+}
+
+void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
+}
+
+static void cpu_ppc_tb_stop (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb, atb, vmclk;
+
+    /* If the time base is already frozen, do nothing */
+    if (tb_env->tb_freq != 0) {
+        vmclk = qemu_get_clock_ns(vm_clock);
+        /* Get the time base */
+        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
+        /* Get the alternate time base */
+        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
+        /* Store the time base value (ie compute the current offset) */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
+        /* Store the alternate time base value (compute the current offset) */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
+        /* Set the time base frequency to zero */
+        tb_env->tb_freq = 0;
+        /* Now, the time bases are frozen to tb_offset / atb_offset value */
+    }
+}
+
+static void cpu_ppc_tb_start (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb, atb, vmclk;
+
+    /* If the time base is not frozen, do nothing */
+    if (tb_env->tb_freq == 0) {
+        vmclk = qemu_get_clock_ns(vm_clock);
+        /* Get the time base from tb_offset */
+        tb = tb_env->tb_offset;
+        /* Get the alternate time base from atb_offset */
+        atb = tb_env->atb_offset;
+        /* Restore the tb frequency from the decrementer frequency */
+        tb_env->tb_freq = tb_env->decr_freq;
+        /* Store the time base value */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
+        /* Store the alternate time base value */
+        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
+    }
+}
+
+static inline uint32_t _cpu_ppc_load_decr(CPUState *env, uint64_t next)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint32_t decr;
+    int64_t diff;
+
+    diff = next - qemu_get_clock_ns(vm_clock);
+    if (diff >= 0)
+        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
+    else
+        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
+    LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
+
+    return decr;
+}
+
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    if (kvm_enabled()) {
+        return env->spr[SPR_DECR];
+    }
+
+    return _cpu_ppc_load_decr(env, tb_env->decr_next);
+}
+
+uint32_t cpu_ppc_load_hdecr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
+}
+
+uint64_t cpu_ppc_load_purr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t diff;
+
+    diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
+
+    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
+}
+
+/* When decrementer expires,
+ * all we need to do is generate or queue a CPU exception
+ */
+static inline void cpu_ppc_decr_excp(CPUState *env)
+{
+    /* Raise it */
+    LOG_TB("raise decrementer exception\n");
+    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
+}
+
+static inline void cpu_ppc_hdecr_excp(CPUState *env)
+{
+    /* Raise it */
+    LOG_TB("raise decrementer exception\n");
+    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
+}
+
+static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
+                                  struct QEMUTimer *timer,
+                                  void (*raise_excp)(CPUState *),
+                                  uint32_t decr, uint32_t value,
+                                  int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t now, next;
+
+    LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
+                decr, value);
+    now = qemu_get_clock_ns(vm_clock);
+    next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
+    if (is_excp)
+        next += *nextp - now;
+    if (next == now)
+        next++;
+    *nextp = next;
+    /* Adjust timer */
+    qemu_mod_timer(timer, next);
+    /* If we set a negative value and the decrementer was positive,
+     * raise an exception.
+     */
+    if ((value & 0x80000000) && !(decr & 0x80000000))
+        (*raise_excp)(env);
+}
+
+static inline void _cpu_ppc_store_decr(CPUState *env, uint32_t decr,
+                                       uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
+                         &cpu_ppc_decr_excp, decr, value, is_excp);
+}
+
+void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
+}
+
+static void cpu_ppc_decr_cb (void *opaque)
+{
+    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+static inline void _cpu_ppc_store_hdecr(CPUState *env, uint32_t hdecr,
+                                        uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    if (tb_env->hdecr_timer != NULL) {
+        __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
+                             &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
+    }
+}
+
+void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
+}
+
+static void cpu_ppc_hdecr_cb (void *opaque)
+{
+    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+void cpu_ppc_store_purr (CPUState *env, uint64_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    tb_env->purr_load = value;
+    tb_env->purr_start = qemu_get_clock_ns(vm_clock);
+}
+
+static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUState *env = opaque;
+    ppc_tb_t *tb_env = env->tb_env;
+
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    /* There is a bug in Linux 2.4 kernels:
+     * if a decrementer exception is pending when it enables msr_ee at startup,
+     * it's not ready to handle it...
+     */
+    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
+}
+
+/* Set up (once) timebase frequency (in Hz) */
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
+{
+    ppc_tb_t *tb_env;
+
+    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    env->tb_env = tb_env;
+    /* Create new timer */
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env);
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor decrementer
+         */
+        tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env);
+    } else {
+        tb_env->hdecr_timer = NULL;
+    }
+    cpu_ppc_set_tb_clk(env, freq);
+
+    return &cpu_ppc_set_tb_clk;
+}
+
+/* Specific helpers for POWER & PowerPC 601 RTC */
+#if 0
+static clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
+{
+    return cpu_ppc_tb_init(env, 7812500);
+}
+#endif
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+{
+    return _cpu_ppc_load_tbu(env);
+}
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
+{
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC timers */
+
+/* PIT, FIT & WDT */
+typedef struct ppcemb_timer_t ppcemb_timer_t;
+struct ppcemb_timer_t {
+    uint64_t pit_reload;  /* PIT auto-reload value        */
+    uint64_t fit_next;    /* Tick for next FIT interrupt  */
+    struct QEMUTimer *fit_timer;
+    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
+    struct QEMUTimer *wdt_timer;
+
+    /* 405 have the PIT, 440 have a DECR.  */
+    unsigned int decr_excp;
+};
+
+/* Fixed interval timer */
+static void cpu_4xx_fit_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
+    case 0:
+        next = 1 << 9;
+        break;
+    case 1:
+        next = 1 << 13;
+        break;
+    case 2:
+        next = 1 << 17;
+        break;
+    case 3:
+        next = 1 << 21;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
+    if (next == now)
+        next++;
+    qemu_mod_timer(ppcemb_timer->fit_timer, next);
+    env->spr[SPR_40x_TSR] |= 1 << 26;
+    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
+        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
+    LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
+           (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+}
+
+/* Programmable interval timer */
+static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
+{
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    ppcemb_timer = tb_env->opaque;
+    if (ppcemb_timer->pit_reload <= 1 ||
+        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
+        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
+        /* Stop PIT */
+        LOG_TB("%s: stop PIT\n", __func__);
+        qemu_del_timer(tb_env->decr_timer);
+    } else {
+        LOG_TB("%s: start PIT %016" PRIx64 "\n",
+                    __func__, ppcemb_timer->pit_reload);
+        now = qemu_get_clock_ns(vm_clock);
+        next = now + muldiv64(ppcemb_timer->pit_reload,
+                              get_ticks_per_sec(), tb_env->decr_freq);
+        if (is_excp)
+            next += tb_env->decr_next - now;
+        if (next == now)
+            next++;
+        qemu_mod_timer(tb_env->decr_timer, next);
+        tb_env->decr_next = next;
+    }
+}
+
+static void cpu_4xx_pit_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    env->spr[SPR_40x_TSR] |= 1 << 27;
+    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
+        ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
+    start_stop_pit(env, tb_env, 1);
+    LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
+           "%016" PRIx64 "\n", __func__,
+           (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
+           (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
+           ppcemb_timer->pit_reload);
+}
+
+/* Watchdog timer */
+static void cpu_4xx_wdt_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    now = qemu_get_clock_ns(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
+    case 0:
+        next = 1 << 17;
+        break;
+    case 1:
+        next = 1 << 21;
+        break;
+    case 2:
+        next = 1 << 25;
+        break;
+    case 3:
+        next = 1 << 29;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq);
+    if (next == now)
+        next++;
+    LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
+           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
+    case 0x0:
+    case 0x1:
+        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+        ppcemb_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 31;
+        break;
+    case 0x2:
+        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+        ppcemb_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 30;
+        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
+            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
+        break;
+    case 0x3:
+        env->spr[SPR_40x_TSR] &= ~0x30000000;
+        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
+        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
+        case 0x0:
+            /* No reset */
+            break;
+        case 0x1: /* Core reset */
+            ppc40x_core_reset(env);
+            break;
+        case 0x2: /* Chip reset */
+            ppc40x_chip_reset(env);
+            break;
+        case 0x3: /* System reset */
+            ppc40x_system_reset(env);
+            break;
+        }
+    }
+}
+
+void store_40x_pit (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
+    ppcemb_timer->pit_reload = val;
+    start_stop_pit(env, tb_env, 0);
+}
+
+target_ulong load_40x_pit (CPUState *env)
+{
+    return cpu_ppc_load_decr(env);
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    ppcemb_timer = tb_env->opaque;
+
+    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
+    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
+    if (val & 0x80000000)
+        ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env;
+
+    tb_env = env->tb_env;
+    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
+    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
+    start_stop_pit(env, tb_env, 1);
+    cpu_4xx_wdt_cb(env);
+}
+
+static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUState *env = opaque;
+    ppc_tb_t *tb_env = env->tb_env;
+
+    LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
+                freq);
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    /* XXX: we should also update all timers */
+}
+
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+                                  unsigned int decr_excp)
+{
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    env->tb_env = tb_env;
+    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+    tb_env->tb_freq = freq;
+    tb_env->decr_freq = freq;
+    tb_env->opaque = ppcemb_timer;
+    LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
+    if (ppcemb_timer != NULL) {
+        /* We use decr timer for PIT */
+        tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
+        ppcemb_timer->fit_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
+        ppcemb_timer->wdt_timer =
+            qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
+        ppcemb_timer->decr_excp = decr_excp;
+    }
+
+    return &ppc_emb_set_tb_clk;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC Device Control Registers */
+typedef struct ppc_dcrn_t ppc_dcrn_t;
+struct ppc_dcrn_t {
+    dcr_read_cb dcr_read;
+    dcr_write_cb dcr_write;
+    void *opaque;
+};
+
+/* XXX: on 460, DCR addresses are 32 bits wide,
+ *      using DCRIPR to get the 22 upper bits of the DCR address
+ */
+#define DCRN_NB 1024
+struct ppc_dcr_t {
+    ppc_dcrn_t dcrn[DCRN_NB];
+    int (*read_error)(int dcrn);
+    int (*write_error)(int dcrn);
+};
+
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_read == NULL)
+        goto error;
+    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
+
+    return 0;
+
+ error:
+    if (dcr_env->read_error != NULL)
+        return (*dcr_env->read_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_write == NULL)
+        goto error;
+    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
+
+    return 0;
+
+ error:
+    if (dcr_env->write_error != NULL)
+        return (*dcr_env->write_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
+{
+    ppc_dcr_t *dcr_env;
+    ppc_dcrn_t *dcr;
+
+    dcr_env = env->dcr_env;
+    if (dcr_env == NULL)
+        return -1;
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        return -1;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->opaque != NULL ||
+        dcr->dcr_read != NULL ||
+        dcr->dcr_write != NULL)
+        return -1;
+    dcr->opaque = opaque;
+    dcr->dcr_read = dcr_read;
+    dcr->dcr_write = dcr_write;
+
+    return 0;
+}
+
+int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
+                  int (*write_error)(int dcrn))
+{
+    ppc_dcr_t *dcr_env;
+
+    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
+    dcr_env->read_error = read_error;
+    dcr_env->write_error = write_error;
+    env->dcr_env = dcr_env;
+
+    return 0;
+}
+
+/*****************************************************************************/
+/* Debug port */
+void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 0xF;
+    switch (addr) {
+    case 0:
+        printf("%c", val);
+        break;
+    case 1:
+        printf("\n");
+        fflush(stdout);
+        break;
+    case 2:
+        printf("Set loglevel to %04" PRIx32 "\n", val);
+        cpu_set_log(val | 0x100);
+        break;
+    }
+}
+
+/*****************************************************************************/
+/* NVRAM helpers */
+static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
+{
+    return (*nvram->read_fn)(nvram->opaque, addr);;
+}
+
+static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
+{
+    (*nvram->write_fn)(nvram->opaque, addr, val);
+}
+
+void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
+{
+    nvram_write(nvram, addr, value);
+}
+
+uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
+{
+    return nvram_read(nvram, addr);
+}
+
+void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
+{
+    nvram_write(nvram, addr, value >> 8);
+    nvram_write(nvram, addr + 1, value & 0xFF);
+}
+
+uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
+{
+    uint16_t tmp;
+
+    tmp = nvram_read(nvram, addr) << 8;
+    tmp |= nvram_read(nvram, addr + 1);
+
+    return tmp;
+}
+
+void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
+{
+    nvram_write(nvram, addr, value >> 24);
+    nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
+    nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
+    nvram_write(nvram, addr + 3, value & 0xFF);
+}
+
+uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
+{
+    uint32_t tmp;
+
+    tmp = nvram_read(nvram, addr) << 24;
+    tmp |= nvram_read(nvram, addr + 1) << 16;
+    tmp |= nvram_read(nvram, addr + 2) << 8;
+    tmp |= nvram_read(nvram, addr + 3);
+
+    return tmp;
+}
+
+void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
+                       const char *str, uint32_t max)
+{
+    int i;
+
+    for (i = 0; i < max && str[i] != '\0'; i++) {
+        nvram_write(nvram, addr + i, str[i]);
+    }
+    nvram_write(nvram, addr + i, str[i]);
+    nvram_write(nvram, addr + max - 1, '\0');
+}
+
+int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
+{
+    int i;
+
+    memset(dst, 0, max);
+    for (i = 0; i < max; i++) {
+        dst[i] = NVRAM_get_byte(nvram, addr + i);
+        if (dst[i] == '\0')
+            break;
+    }
+
+    return i;
+}
+
+static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
+{
+    uint16_t tmp;
+    uint16_t pd, pd1, pd2;
+
+    tmp = prev >> 8;
+    pd = prev ^ value;
+    pd1 = pd & 0x000F;
+    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
+    tmp ^= (pd1 << 3) | (pd1 << 8);
+    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
+
+    return tmp;
+}
+
+static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
+{
+    uint32_t i;
+    uint16_t crc = 0xFFFF;
+    int odd;
+
+    odd = count & 1;
+    count &= ~1;
+    for (i = 0; i != count; i++) {
+        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+    }
+    if (odd) {
+        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+    }
+
+    return crc;
+}
+
+#define CMDLINE_ADDR 0x017ff000
+
+int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
+                          const char *arch,
+                          uint32_t RAM_size, int boot_device,
+                          uint32_t kernel_image, uint32_t kernel_size,
+                          const char *cmdline,
+                          uint32_t initrd_image, uint32_t initrd_size,
+                          uint32_t NVRAM_image,
+                          int width, int height, int depth)
+{
+    uint16_t crc;
+
+    /* Set parameters for Open Hack'Ware BIOS */
+    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
+    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
+    NVRAM_set_word(nvram,   0x14, NVRAM_size);
+    NVRAM_set_string(nvram, 0x20, arch, 16);
+    NVRAM_set_lword(nvram,  0x30, RAM_size);
+    NVRAM_set_byte(nvram,   0x34, boot_device);
+    NVRAM_set_lword(nvram,  0x38, kernel_image);
+    NVRAM_set_lword(nvram,  0x3C, kernel_size);
+    if (cmdline) {
+        /* XXX: put the cmdline in NVRAM too ? */
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
+        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
+        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
+    } else {
+        NVRAM_set_lword(nvram,  0x40, 0);
+        NVRAM_set_lword(nvram,  0x44, 0);
+    }
+    NVRAM_set_lword(nvram,  0x48, initrd_image);
+    NVRAM_set_lword(nvram,  0x4C, initrd_size);
+    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
+
+    NVRAM_set_word(nvram,   0x54, width);
+    NVRAM_set_word(nvram,   0x56, height);
+    NVRAM_set_word(nvram,   0x58, depth);
+    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
+    NVRAM_set_word(nvram,   0xFC, crc);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/ppc.h b/qemu-0.15.x/hw/ppc.h
new file mode 100644
index 0000000..3ccf134
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc.h
@@ -0,0 +1,57 @@
+/* PowerPC hardware exceptions management helpers */
+typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
+typedef struct clk_setup_t clk_setup_t;
+struct clk_setup_t {
+    clk_setup_cb cb;
+    void *opaque;
+};
+static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
+{
+    if (clk->cb != NULL)
+        (*clk->cb)(clk->opaque, freq);
+}
+
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val);
+int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
+                  int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb drc_read, dcr_write_cb dcr_write);
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+                                  unsigned int decr_excp);
+
+/* Embedded PowerPC reset */
+void ppc40x_core_reset (CPUState *env);
+void ppc40x_chip_reset (CPUState *env);
+void ppc40x_system_reset (CPUState *env);
+void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
+
+extern CPUWriteMemoryFunc * const PPC_io_write[];
+extern CPUReadMemoryFunc * const PPC_io_read[];
+void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
+
+void ppc40x_irq_init (CPUState *env);
+void ppce500_irq_init (CPUState *env);
+void ppc6xx_irq_init (CPUState *env);
+void ppc970_irq_init (CPUState *env);
+void ppcPOWER7_irq_init (CPUState *env);
+
+/* PPC machines for OpenBIOS */
+enum {
+    ARCH_PREP = 0,
+    ARCH_MAC99,
+    ARCH_HEATHROW,
+    ARCH_MAC99_U3,
+};
+
+#define FW_CFG_PPC_WIDTH	(FW_CFG_ARCH_LOCAL + 0x00)
+#define FW_CFG_PPC_HEIGHT	(FW_CFG_ARCH_LOCAL + 0x01)
+#define FW_CFG_PPC_DEPTH	(FW_CFG_ARCH_LOCAL + 0x02)
+#define FW_CFG_PPC_TBFREQ	(FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_IS_KVM       (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC       (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
+
+#define PPC_SERIAL_MM_BAUDBASE 399193
diff --git a/qemu-0.15.x/hw/ppc405.h b/qemu-0.15.x/hw/ppc405.h
new file mode 100644
index 0000000..e042a05
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc405.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU PowerPC 405 shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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(PPC_405_H)
+#define PPC_405_H
+
+#include "ppc4xx.h"
+
+/* Bootinfo as set-up by u-boot */
+typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
+struct ppc4xx_bd_info_t {
+    uint32_t bi_memstart;
+    uint32_t bi_memsize;
+    uint32_t bi_flashstart;
+    uint32_t bi_flashsize;
+    uint32_t bi_flashoffset; /* 0x10 */
+    uint32_t bi_sramstart;
+    uint32_t bi_sramsize;
+    uint32_t bi_bootflags;
+    uint32_t bi_ipaddr; /* 0x20 */
+    uint8_t  bi_enetaddr[6];
+    uint16_t bi_ethspeed;
+    uint32_t bi_intfreq;
+    uint32_t bi_busfreq; /* 0x30 */
+    uint32_t bi_baudrate;
+    uint8_t  bi_s_version[4];
+    uint8_t  bi_r_version[32];
+    uint32_t bi_procfreq;
+    uint32_t bi_plb_busfreq;
+    uint32_t bi_pci_busfreq;
+    uint8_t  bi_pci_enetaddr[6];
+    uint32_t bi_pci_enetaddr2[6];
+    uint32_t bi_opbfreq;
+    uint32_t bi_iic_fast[2];
+};
+
+/* PowerPC 405 core */
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags);
+
+CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
+                         target_phys_addr_t ram_sizes[4],
+                         uint32_t sysclk, qemu_irq **picp,
+                         int do_init);
+CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+                         target_phys_addr_t ram_sizes[2],
+                         uint32_t sysclk, qemu_irq **picp,
+                         int do_init);
+/* IBM STBxxx microcontrollers */
+CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2],
+                           target_phys_addr_t ram_sizes[2],
+                           uint32_t sysclk, qemu_irq **picp,
+                           ram_addr_t *offsetp);
+
+#endif /* !defined(PPC_405_H) */
diff --git a/qemu-0.15.x/hw/ppc405_boards.c b/qemu-0.15.x/hw/ppc405_boards.c
new file mode 100644
index 0000000..ad27181
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc405_boards.c
@@ -0,0 +1,654 @@
+/*
+ * QEMU PowerPC 405 evaluation boards emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "nvram.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "block.h"
+#include "boards.h"
+#include "qemu-log.h"
+#include "loader.h"
+#include "blockdev.h"
+
+#define BIOS_FILENAME "ppc405_rom.bin"
+#define BIOS_SIZE (2048 * 1024)
+
+#define KERNEL_LOAD_ADDR 0x00000000
+#define INITRD_LOAD_ADDR 0x01800000
+
+#define USE_FLASH_BIOS
+
+#define DEBUG_BOARD_INIT
+
+/*****************************************************************************/
+/* PPC405EP reference board (IBM) */
+/* Standalone board with:
+ * - PowerPC 405EP CPU
+ * - SDRAM (0x00000000)
+ * - Flash (0xFFF80000)
+ * - SRAM  (0xFFF00000)
+ * - NVRAM (0xF0000000)
+ * - FPGA  (0xF0300000)
+ */
+typedef struct ref405ep_fpga_t ref405ep_fpga_t;
+struct ref405ep_fpga_t {
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr)
+{
+    ref405ep_fpga_t *fpga;
+    uint32_t ret;
+
+    fpga = opaque;
+    switch (addr) {
+    case 0x0:
+        ret = fpga->reg0;
+        break;
+    case 0x1:
+        ret = fpga->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void ref405ep_fpga_writeb (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        fpga->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writew (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 24;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
+    ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writel (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc * const ref405ep_fpga_read[] = {
+    &ref405ep_fpga_readb,
+    &ref405ep_fpga_readw,
+    &ref405ep_fpga_readl,
+};
+
+static CPUWriteMemoryFunc * const ref405ep_fpga_write[] = {
+    &ref405ep_fpga_writeb,
+    &ref405ep_fpga_writew,
+    &ref405ep_fpga_writel,
+};
+
+static void ref405ep_fpga_reset (void *opaque)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    fpga->reg0 = 0x00;
+    fpga->reg1 = 0x0F;
+}
+
+static void ref405ep_fpga_init (uint32_t base)
+{
+    ref405ep_fpga_t *fpga;
+    int fpga_memory;
+
+    fpga = qemu_mallocz(sizeof(ref405ep_fpga_t));
+    fpga_memory = cpu_register_io_memory(ref405ep_fpga_read,
+                                         ref405ep_fpga_write, fpga,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00000100, fpga_memory);
+    qemu_register_reset(&ref405ep_fpga_reset, fpga);
+}
+
+static void ref405ep_init (ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    char *filename;
+    ppc4xx_bd_info_t bd;
+    CPUPPCState *env;
+    qemu_irq *pic;
+    ram_addr_t sram_offset, bios_offset, bdloc;
+    target_phys_addr_t ram_bases[2], ram_sizes[2];
+    target_ulong sram_size;
+    long bios_size;
+    //int phy_addr = 0;
+    //static int phy_addr = 1;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors, len;
+    DriveInfo *dinfo;
+
+    /* XXX: fix this */
+    ram_bases[0] = qemu_ram_alloc(NULL, "ef405ep.ram", 0x08000000);
+    ram_sizes[0] = 0x08000000;
+    ram_bases[1] = 0x00000000;
+    ram_sizes[1] = 0x00000000;
+    ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
+                        kernel_filename == NULL ? 0 : 1);
+    /* allocate SRAM */
+    sram_size = 512 * 1024;
+    sram_offset = qemu_ram_alloc(NULL, "ef405ep.sram", sram_size);
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+#endif
+    cpu_register_physical_memory(0xFFF00000, sram_size,
+                                 sram_offset | IO_MEM_RAM);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", bios_size);
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at offset %08lx addr %lx '%s' %d\n",
+               fl_idx, bios_size, bios_offset, -bios_size,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+#endif
+        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", BIOS_SIZE);
+        if (bios_name == NULL)
+            bios_name = BIOS_FILENAME;
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
+            qemu_free(filename);
+        } else {
+            bios_size = -1;
+        }
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
+                    bios_name);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        cpu_register_physical_memory((uint32_t)(-bios_size),
+                                     bios_size, bios_offset | IO_MEM_ROM);
+    }
+    /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register FPGA\n", __func__);
+#endif
+    ref405ep_fpga_init(0xF0300000);
+    /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register NVRAM\n", __func__);
+#endif
+    m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        memset(&bd, 0, sizeof(bd));
+        bd.bi_memstart = 0x00000000;
+        bd.bi_memsize = ram_size;
+        bd.bi_flashstart = -bios_size;
+        bd.bi_flashsize = -bios_size;
+        bd.bi_flashoffset = 0;
+        bd.bi_sramstart = 0xFFF00000;
+        bd.bi_sramsize = sram_size;
+        bd.bi_bootflags = 0;
+        bd.bi_intfreq = 133333333;
+        bd.bi_busfreq = 33333333;
+        bd.bi_baudrate = 115200;
+        bd.bi_s_version[0] = 'Q';
+        bd.bi_s_version[1] = 'M';
+        bd.bi_s_version[2] = 'U';
+        bd.bi_s_version[3] = '\0';
+        bd.bi_r_version[0] = 'Q';
+        bd.bi_r_version[1] = 'E';
+        bd.bi_r_version[2] = 'M';
+        bd.bi_r_version[3] = 'U';
+        bd.bi_r_version[4] = '\0';
+        bd.bi_procfreq = 133333333;
+        bd.bi_plb_busfreq = 33333333;
+        bd.bi_pci_busfreq = 33333333;
+        bd.bi_opbfreq = 33333333;
+        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
+        env->gpr[3] = bdloc;
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                          ram_size - kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        printf("Load kernel size %ld at " TARGET_FMT_lx,
+               kernel_size, kernel_base);
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        env->gpr[4] = initrd_base;
+        env->gpr[5] = initrd_size;
+        if (kernel_cmdline != NULL) {
+            len = strlen(kernel_cmdline);
+            bdloc -= ((len + 255) & ~255);
+            cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1);
+            env->gpr[6] = bdloc;
+            env->gpr[7] = bdloc + len;
+        } else {
+            env->gpr[6] = 0;
+            env->gpr[7] = 0;
+        }
+        env->nip = KERNEL_LOAD_ADDR;
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        bdloc = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+    printf("bdloc %016lx\n", (unsigned long)bdloc);
+}
+
+static QEMUMachine ref405ep_machine = {
+    .name = "ref405ep",
+    .desc = "ref405ep",
+    .init = ref405ep_init,
+};
+
+/*****************************************************************************/
+/* AMCC Taihu evaluation board */
+/* - PowerPC 405EP processor
+ * - SDRAM               128 MB at 0x00000000
+ * - Boot flash          2 MB   at 0xFFE00000
+ * - Application flash   32 MB  at 0xFC000000
+ * - 2 serial ports
+ * - 2 ethernet PHY
+ * - 1 USB 1.1 device    0x50000000
+ * - 1 LCD display       0x50100000
+ * - 1 CPLD              0x50100000
+ * - 1 I2C EEPROM
+ * - 1 I2C thermal sensor
+ * - a set of LEDs
+ * - bit-bang SPI port using GPIOs
+ * - 1 EBC interface connector 0 0x50200000
+ * - 1 cardbus controller + expansion slot.
+ * - 1 PCI expansion slot.
+ */
+typedef struct taihu_cpld_t taihu_cpld_t;
+struct taihu_cpld_t {
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr)
+{
+    taihu_cpld_t *cpld;
+    uint32_t ret;
+
+    cpld = opaque;
+    switch (addr) {
+    case 0x0:
+        ret = cpld->reg0;
+        break;
+    case 0x1:
+        ret = cpld->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void taihu_cpld_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        cpld->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void taihu_cpld_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 24;
+    ret |= taihu_cpld_readb(opaque, addr + 1) << 16;
+    ret |= taihu_cpld_readb(opaque, addr + 2) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void taihu_cpld_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc * const taihu_cpld_read[] = {
+    &taihu_cpld_readb,
+    &taihu_cpld_readw,
+    &taihu_cpld_readl,
+};
+
+static CPUWriteMemoryFunc * const taihu_cpld_write[] = {
+    &taihu_cpld_writeb,
+    &taihu_cpld_writew,
+    &taihu_cpld_writel,
+};
+
+static void taihu_cpld_reset (void *opaque)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    cpld->reg0 = 0x01;
+    cpld->reg1 = 0x80;
+}
+
+static void taihu_cpld_init (uint32_t base)
+{
+    taihu_cpld_t *cpld;
+    int cpld_memory;
+
+    cpld = qemu_mallocz(sizeof(taihu_cpld_t));
+    cpld_memory = cpu_register_io_memory(taihu_cpld_read,
+                                         taihu_cpld_write, cpld,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00000100, cpld_memory);
+    qemu_register_reset(&taihu_cpld_reset, cpld);
+}
+
+static void taihu_405ep_init(ram_addr_t ram_size,
+                             const char *boot_device,
+                             const char *kernel_filename,
+                             const char *kernel_cmdline,
+                             const char *initrd_filename,
+                             const char *cpu_model)
+{
+    char *filename;
+    qemu_irq *pic;
+    ram_addr_t bios_offset;
+    target_phys_addr_t ram_bases[2], ram_sizes[2];
+    long bios_size;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors;
+    DriveInfo *dinfo;
+
+    /* RAM is soldered to the board so the size cannot be changed */
+    ram_bases[0] = qemu_ram_alloc(NULL, "taihu_405ep.ram-0", 0x04000000);
+    ram_sizes[0] = 0x04000000;
+    ram_bases[1] = qemu_ram_alloc(NULL, "taihu_405ep.ram-1", 0x04000000);
+    ram_sizes[1] = 0x04000000;
+    ram_size = 0x08000000;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
+                  kernel_filename == NULL ? 0 : 1);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    fl_idx = 0;
+#if defined(USE_FLASH_BIOS)
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        /* XXX: should check that size is 2MB */
+        //        bios_size = 2 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", bios_size);
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at offset %08lx addr %lx '%s' %d\n",
+               fl_idx, bios_size, bios_offset, -bios_size,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+#endif
+        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        if (bios_name == NULL)
+            bios_name = BIOS_FILENAME;
+        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", BIOS_SIZE);
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
+            qemu_free(filename);
+        } else {
+            bios_size = -1;
+        }
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
+                    bios_name);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        cpu_register_physical_memory((uint32_t)(-bios_size),
+                                     bios_size, bios_offset | IO_MEM_ROM);
+    }
+    /* Register Linux flash */
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+    if (dinfo) {
+        bios_size = bdrv_getlength(dinfo->bdrv);
+        /* XXX: should check that size is 32MB */
+        bios_size = 32 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size %lx"
+               " at offset %08lx  addr " TARGET_FMT_lx " '%s'\n",
+               fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
+               bdrv_get_device_name(dinfo->bdrv));
+#endif
+        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.flash", bios_size);
+        pflash_cfi02_register(0xfc000000, bios_offset,
+                              dinfo->bdrv, 65536, fl_sectors, 1,
+                              4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
+                              1);
+        fl_idx++;
+    }
+    /* Register CLPD & LCD display */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register CPLD\n", __func__);
+#endif
+    taihu_cpld_init(0x50100000);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                          ram_size - kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr,
+                        "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+}
+
+static QEMUMachine taihu_machine = {
+    .name = "taihu",
+    .desc = "taihu",
+    .init = taihu_405ep_init,
+};
+
+static void ppc405_machine_init(void)
+{
+    qemu_register_machine(&ref405ep_machine);
+    qemu_register_machine(&taihu_machine);
+}
+
+machine_init(ppc405_machine_init);
diff --git a/qemu-0.15.x/hw/ppc405_uc.c b/qemu-0.15.x/hw/ppc405_uc.c
new file mode 100644
index 0000000..06a053b
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc405_uc.c
@@ -0,0 +1,2547 @@
+/*
+ * QEMU PowerPC 405 embedded processors emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "qemu-log.h"
+
+#define DEBUG_OPBA
+#define DEBUG_SDRAM
+#define DEBUG_GPIO
+#define DEBUG_SERIAL
+#define DEBUG_OCM
+//#define DEBUG_I2C
+#define DEBUG_GPT
+#define DEBUG_MAL
+#define DEBUG_CLOCKS
+//#define DEBUG_CLOCKS_LL
+
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags)
+{
+    ram_addr_t bdloc;
+    int i, n;
+
+    /* We put the bd structure at the top of memory */
+    if (bd->bi_memsize >= 0x01000000UL)
+        bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
+    else
+        bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
+    stl_be_phys(bdloc + 0x00, bd->bi_memstart);
+    stl_be_phys(bdloc + 0x04, bd->bi_memsize);
+    stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
+    stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
+    stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
+    stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
+    stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
+    stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
+    stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
+    for (i = 0; i < 6; i++) {
+        stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+    }
+    stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
+    stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
+    stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
+    stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
+    for (i = 0; i < 4; i++) {
+        stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
+    }
+    for (i = 0; i < 32; i++) {
+        stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
+    }
+    stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
+    stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
+    for (i = 0; i < 6; i++) {
+        stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+    }
+    n = 0x6A;
+    if (flags & 0x00000001) {
+        for (i = 0; i < 6; i++)
+            stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
+    }
+    stl_be_phys(bdloc + n, bd->bi_opbfreq);
+    n += 4;
+    for (i = 0; i < 2; i++) {
+        stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
+        n += 4;
+    }
+
+    return bdloc;
+}
+
+/*****************************************************************************/
+/* Shared peripherals */
+
+/*****************************************************************************/
+/* Peripheral local bus arbitrer */
+enum {
+    PLB0_BESR = 0x084,
+    PLB0_BEAR = 0x086,
+    PLB0_ACR  = 0x087,
+};
+
+typedef struct ppc4xx_plb_t ppc4xx_plb_t;
+struct ppc4xx_plb_t {
+    uint32_t acr;
+    uint32_t bear;
+    uint32_t besr;
+};
+
+static uint32_t dcr_read_plb (void *opaque, int dcrn)
+{
+    ppc4xx_plb_t *plb;
+    uint32_t ret;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        ret = plb->acr;
+        break;
+    case PLB0_BEAR:
+        ret = plb->bear;
+        break;
+    case PLB0_BESR:
+        ret = plb->besr;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_plb (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        /* We don't care about the actual parameters written as
+         * we don't manage any priorities on the bus
+         */
+        plb->acr = val & 0xF8000000;
+        break;
+    case PLB0_BEAR:
+        /* Read only */
+        break;
+    case PLB0_BESR:
+        /* Write-clear */
+        plb->besr &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_plb_reset (void *opaque)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    plb->acr = 0x00000000;
+    plb->bear = 0x00000000;
+    plb->besr = 0x00000000;
+}
+
+static void ppc4xx_plb_init(CPUState *env)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = qemu_mallocz(sizeof(ppc4xx_plb_t));
+    ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
+    ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
+    ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
+    qemu_register_reset(ppc4xx_plb_reset, plb);
+}
+
+/*****************************************************************************/
+/* PLB to OPB bridge */
+enum {
+    POB0_BESR0 = 0x0A0,
+    POB0_BESR1 = 0x0A2,
+    POB0_BEAR  = 0x0A4,
+};
+
+typedef struct ppc4xx_pob_t ppc4xx_pob_t;
+struct ppc4xx_pob_t {
+    uint32_t bear;
+    uint32_t besr[2];
+};
+
+static uint32_t dcr_read_pob (void *opaque, int dcrn)
+{
+    ppc4xx_pob_t *pob;
+    uint32_t ret;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        ret = pob->bear;
+        break;
+    case POB0_BESR0:
+    case POB0_BESR1:
+        ret = pob->besr[dcrn - POB0_BESR0];
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_pob (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        /* Read only */
+        break;
+    case POB0_BESR0:
+    case POB0_BESR1:
+        /* Write-clear */
+        pob->besr[dcrn - POB0_BESR0] &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_pob_reset (void *opaque)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    /* No error */
+    pob->bear = 0x00000000;
+    pob->besr[0] = 0x0000000;
+    pob->besr[1] = 0x0000000;
+}
+
+static void ppc4xx_pob_init(CPUState *env)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = qemu_mallocz(sizeof(ppc4xx_pob_t));
+    ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
+    ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
+    ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
+    qemu_register_reset(ppc4xx_pob_reset, pob);
+}
+
+/*****************************************************************************/
+/* OPB arbitrer */
+typedef struct ppc4xx_opba_t ppc4xx_opba_t;
+struct ppc4xx_opba_t {
+    uint8_t cr;
+    uint8_t pr;
+};
+
+static uint32_t opba_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_opba_t *opba;
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    opba = opaque;
+    switch (addr) {
+    case 0x00:
+        ret = opba->cr;
+        break;
+    case 0x01:
+        ret = opba->pr;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+
+    return ret;
+}
+
+static void opba_writeb (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_opba_t *opba;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba = opaque;
+    switch (addr) {
+    case 0x00:
+        opba->cr = value & 0xF8;
+        break;
+    case 0x01:
+        opba->pr = value & 0xFF;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t opba_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 8;
+    ret |= opba_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void opba_writew (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba_writeb(opaque, addr, value >> 8);
+    opba_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t opba_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 24;
+    ret |= opba_readb(opaque, addr + 1) << 16;
+
+    return ret;
+}
+
+static void opba_writel (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    opba_writeb(opaque, addr, value >> 24);
+    opba_writeb(opaque, addr + 1, value >> 16);
+}
+
+static CPUReadMemoryFunc * const opba_read[] = {
+    &opba_readb,
+    &opba_readw,
+    &opba_readl,
+};
+
+static CPUWriteMemoryFunc * const opba_write[] = {
+    &opba_writeb,
+    &opba_writew,
+    &opba_writel,
+};
+
+static void ppc4xx_opba_reset (void *opaque)
+{
+    ppc4xx_opba_t *opba;
+
+    opba = opaque;
+    opba->cr = 0x00; /* No dynamic priorities - park disabled */
+    opba->pr = 0x11;
+}
+
+static void ppc4xx_opba_init(target_phys_addr_t base)
+{
+    ppc4xx_opba_t *opba;
+    int io;
+
+    opba = qemu_mallocz(sizeof(ppc4xx_opba_t));
+#ifdef DEBUG_OPBA
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    io = cpu_register_io_memory(opba_read, opba_write, opba,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x002, io);
+    qemu_register_reset(ppc4xx_opba_reset, opba);
+}
+
+/*****************************************************************************/
+/* Code decompression controller */
+/* XXX: TODO */
+
+/*****************************************************************************/
+/* Peripheral controller */
+typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
+struct ppc4xx_ebc_t {
+    uint32_t addr;
+    uint32_t bcr[8];
+    uint32_t bap[8];
+    uint32_t bear;
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t cfg;
+};
+
+enum {
+    EBC0_CFGADDR = 0x012,
+    EBC0_CFGDATA = 0x013,
+};
+
+static uint32_t dcr_read_ebc (void *opaque, int dcrn)
+{
+    ppc4xx_ebc_t *ebc;
+    uint32_t ret;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ret = ebc->addr;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            ret = ebc->bcr[0];
+            break;
+        case 0x01: /* B1CR */
+            ret = ebc->bcr[1];
+            break;
+        case 0x02: /* B2CR */
+            ret = ebc->bcr[2];
+            break;
+        case 0x03: /* B3CR */
+            ret = ebc->bcr[3];
+            break;
+        case 0x04: /* B4CR */
+            ret = ebc->bcr[4];
+            break;
+        case 0x05: /* B5CR */
+            ret = ebc->bcr[5];
+            break;
+        case 0x06: /* B6CR */
+            ret = ebc->bcr[6];
+            break;
+        case 0x07: /* B7CR */
+            ret = ebc->bcr[7];
+            break;
+        case 0x10: /* B0AP */
+            ret = ebc->bap[0];
+            break;
+        case 0x11: /* B1AP */
+            ret = ebc->bap[1];
+            break;
+        case 0x12: /* B2AP */
+            ret = ebc->bap[2];
+            break;
+        case 0x13: /* B3AP */
+            ret = ebc->bap[3];
+            break;
+        case 0x14: /* B4AP */
+            ret = ebc->bap[4];
+            break;
+        case 0x15: /* B5AP */
+            ret = ebc->bap[5];
+            break;
+        case 0x16: /* B6AP */
+            ret = ebc->bap[6];
+            break;
+        case 0x17: /* B7AP */
+            ret = ebc->bap[7];
+            break;
+        case 0x20: /* BEAR */
+            ret = ebc->bear;
+            break;
+        case 0x21: /* BESR0 */
+            ret = ebc->besr0;
+            break;
+        case 0x22: /* BESR1 */
+            ret = ebc->besr1;
+            break;
+        case 0x23: /* CFG */
+            ret = ebc->cfg;
+            break;
+        default:
+            ret = 0x00000000;
+            break;
+        }
+        break;
+    default:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ebc->addr = val;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            break;
+        case 0x01: /* B1CR */
+            break;
+        case 0x02: /* B2CR */
+            break;
+        case 0x03: /* B3CR */
+            break;
+        case 0x04: /* B4CR */
+            break;
+        case 0x05: /* B5CR */
+            break;
+        case 0x06: /* B6CR */
+            break;
+        case 0x07: /* B7CR */
+            break;
+        case 0x10: /* B0AP */
+            break;
+        case 0x11: /* B1AP */
+            break;
+        case 0x12: /* B2AP */
+            break;
+        case 0x13: /* B3AP */
+            break;
+        case 0x14: /* B4AP */
+            break;
+        case 0x15: /* B5AP */
+            break;
+        case 0x16: /* B6AP */
+            break;
+        case 0x17: /* B7AP */
+            break;
+        case 0x20: /* BEAR */
+            break;
+        case 0x21: /* BESR0 */
+            break;
+        case 0x22: /* BESR1 */
+            break;
+        case 0x23: /* CFG */
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void ebc_reset (void *opaque)
+{
+    ppc4xx_ebc_t *ebc;
+    int i;
+
+    ebc = opaque;
+    ebc->addr = 0x00000000;
+    ebc->bap[0] = 0x7F8FFE80;
+    ebc->bcr[0] = 0xFFE28000;
+    for (i = 0; i < 8; i++) {
+        ebc->bap[i] = 0x00000000;
+        ebc->bcr[i] = 0x00000000;
+    }
+    ebc->besr0 = 0x00000000;
+    ebc->besr1 = 0x00000000;
+    ebc->cfg = 0x80400000;
+}
+
+static void ppc405_ebc_init(CPUState *env)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = qemu_mallocz(sizeof(ppc4xx_ebc_t));
+    qemu_register_reset(&ebc_reset, ebc);
+    ppc_dcr_register(env, EBC0_CFGADDR,
+                     ebc, &dcr_read_ebc, &dcr_write_ebc);
+    ppc_dcr_register(env, EBC0_CFGDATA,
+                     ebc, &dcr_read_ebc, &dcr_write_ebc);
+}
+
+/*****************************************************************************/
+/* DMA controller */
+enum {
+    DMA0_CR0 = 0x100,
+    DMA0_CT0 = 0x101,
+    DMA0_DA0 = 0x102,
+    DMA0_SA0 = 0x103,
+    DMA0_SG0 = 0x104,
+    DMA0_CR1 = 0x108,
+    DMA0_CT1 = 0x109,
+    DMA0_DA1 = 0x10A,
+    DMA0_SA1 = 0x10B,
+    DMA0_SG1 = 0x10C,
+    DMA0_CR2 = 0x110,
+    DMA0_CT2 = 0x111,
+    DMA0_DA2 = 0x112,
+    DMA0_SA2 = 0x113,
+    DMA0_SG2 = 0x114,
+    DMA0_CR3 = 0x118,
+    DMA0_CT3 = 0x119,
+    DMA0_DA3 = 0x11A,
+    DMA0_SA3 = 0x11B,
+    DMA0_SG3 = 0x11C,
+    DMA0_SR  = 0x120,
+    DMA0_SGC = 0x123,
+    DMA0_SLP = 0x125,
+    DMA0_POL = 0x126,
+};
+
+typedef struct ppc405_dma_t ppc405_dma_t;
+struct ppc405_dma_t {
+    qemu_irq irqs[4];
+    uint32_t cr[4];
+    uint32_t ct[4];
+    uint32_t da[4];
+    uint32_t sa[4];
+    uint32_t sg[4];
+    uint32_t sr;
+    uint32_t sgc;
+    uint32_t slp;
+    uint32_t pol;
+};
+
+static uint32_t dcr_read_dma (void *opaque, int dcrn)
+{
+    return 0;
+}
+
+static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
+{
+}
+
+static void ppc405_dma_reset (void *opaque)
+{
+    ppc405_dma_t *dma;
+    int i;
+
+    dma = opaque;
+    for (i = 0; i < 4; i++) {
+        dma->cr[i] = 0x00000000;
+        dma->ct[i] = 0x00000000;
+        dma->da[i] = 0x00000000;
+        dma->sa[i] = 0x00000000;
+        dma->sg[i] = 0x00000000;
+    }
+    dma->sr = 0x00000000;
+    dma->sgc = 0x00000000;
+    dma->slp = 0x7C000000;
+    dma->pol = 0x00000000;
+}
+
+static void ppc405_dma_init(CPUState *env, qemu_irq irqs[4])
+{
+    ppc405_dma_t *dma;
+
+    dma = qemu_mallocz(sizeof(ppc405_dma_t));
+    memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
+    qemu_register_reset(&ppc405_dma_reset, dma);
+    ppc_dcr_register(env, DMA0_CR0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG0,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG1,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG2,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CR3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_CT3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_DA3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SA3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SG3,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SR,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SGC,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_SLP,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+    ppc_dcr_register(env, DMA0_POL,
+                     dma, &dcr_read_dma, &dcr_write_dma);
+}
+
+/*****************************************************************************/
+/* GPIO */
+typedef struct ppc405_gpio_t ppc405_gpio_t;
+struct ppc405_gpio_t {
+    uint32_t or;
+    uint32_t tcr;
+    uint32_t osrh;
+    uint32_t osrl;
+    uint32_t tsrh;
+    uint32_t tsrl;
+    uint32_t odr;
+    uint32_t ir;
+    uint32_t rr1;
+    uint32_t isr1h;
+    uint32_t isr1l;
+};
+
+static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writeb (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writew (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writel (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_GPIO
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static CPUReadMemoryFunc * const ppc405_gpio_read[] = {
+    &ppc405_gpio_readb,
+    &ppc405_gpio_readw,
+    &ppc405_gpio_readl,
+};
+
+static CPUWriteMemoryFunc * const ppc405_gpio_write[] = {
+    &ppc405_gpio_writeb,
+    &ppc405_gpio_writew,
+    &ppc405_gpio_writel,
+};
+
+static void ppc405_gpio_reset (void *opaque)
+{
+}
+
+static void ppc405_gpio_init(target_phys_addr_t base)
+{
+    ppc405_gpio_t *gpio;
+    int io;
+
+    gpio = qemu_mallocz(sizeof(ppc405_gpio_t));
+#ifdef DEBUG_GPIO
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    io = cpu_register_io_memory(ppc405_gpio_read, ppc405_gpio_write, gpio,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x038, io);
+    qemu_register_reset(&ppc405_gpio_reset, gpio);
+}
+
+/*****************************************************************************/
+/* On Chip Memory */
+enum {
+    OCM0_ISARC   = 0x018,
+    OCM0_ISACNTL = 0x019,
+    OCM0_DSARC   = 0x01A,
+    OCM0_DSACNTL = 0x01B,
+};
+
+typedef struct ppc405_ocm_t ppc405_ocm_t;
+struct ppc405_ocm_t {
+    target_ulong offset;
+    uint32_t isarc;
+    uint32_t isacntl;
+    uint32_t dsarc;
+    uint32_t dsacntl;
+};
+
+static void ocm_update_mappings (ppc405_ocm_t *ocm,
+                                 uint32_t isarc, uint32_t isacntl,
+                                 uint32_t dsarc, uint32_t dsacntl)
+{
+#ifdef DEBUG_OCM
+    printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32
+           " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32
+           " (%08" PRIx32 " %08" PRIx32 ")\n",
+           isarc, isacntl, dsarc, dsacntl,
+           ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
+#endif
+    if (ocm->isarc != isarc ||
+        (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
+        if (ocm->isacntl & 0x80000000) {
+            /* Unmap previously assigned memory region */
+            printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc);
+            cpu_register_physical_memory(ocm->isarc, 0x04000000,
+                                         IO_MEM_UNASSIGNED);
+        }
+        if (isacntl & 0x80000000) {
+            /* Map new instruction memory region */
+#ifdef DEBUG_OCM
+            printf("OCM map ISA %08" PRIx32 "\n", isarc);
+#endif
+            cpu_register_physical_memory(isarc, 0x04000000,
+                                         ocm->offset | IO_MEM_RAM);
+        }
+    }
+    if (ocm->dsarc != dsarc ||
+        (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
+        if (ocm->dsacntl & 0x80000000) {
+            /* Beware not to unmap the region we just mapped */
+            if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
+                /* Unmap previously assigned memory region */
+#ifdef DEBUG_OCM
+                printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc);
+#endif
+                cpu_register_physical_memory(ocm->dsarc, 0x04000000,
+                                             IO_MEM_UNASSIGNED);
+            }
+        }
+        if (dsacntl & 0x80000000) {
+            /* Beware not to remap the region we just mapped */
+            if (!(isacntl & 0x80000000) || dsarc != isarc) {
+                /* Map new data memory region */
+#ifdef DEBUG_OCM
+                printf("OCM map DSA %08" PRIx32 "\n", dsarc);
+#endif
+                cpu_register_physical_memory(dsarc, 0x04000000,
+                                             ocm->offset | IO_MEM_RAM);
+            }
+        }
+    }
+}
+
+static uint32_t dcr_read_ocm (void *opaque, int dcrn)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t ret;
+
+    ocm = opaque;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        ret = ocm->isarc;
+        break;
+    case OCM0_ISACNTL:
+        ret = ocm->isacntl;
+        break;
+    case OCM0_DSARC:
+        ret = ocm->dsarc;
+        break;
+    case OCM0_DSACNTL:
+        ret = ocm->dsacntl;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = ocm->isarc;
+    dsarc = ocm->dsarc;
+    isacntl = ocm->isacntl;
+    dsacntl = ocm->dsacntl;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_ISACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    case OCM0_DSARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_DSACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    }
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+static void ocm_reset (void *opaque)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = 0x00000000;
+    isacntl = 0x00000000;
+    dsarc = 0x00000000;
+    dsacntl = 0x00000000;
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+static void ppc405_ocm_init(CPUState *env)
+{
+    ppc405_ocm_t *ocm;
+
+    ocm = qemu_mallocz(sizeof(ppc405_ocm_t));
+    ocm->offset = qemu_ram_alloc(NULL, "ppc405.ocm", 4096);
+    qemu_register_reset(&ocm_reset, ocm);
+    ppc_dcr_register(env, OCM0_ISARC,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_ISACNTL,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_DSARC,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+    ppc_dcr_register(env, OCM0_DSACNTL,
+                     ocm, &dcr_read_ocm, &dcr_write_ocm);
+}
+
+/*****************************************************************************/
+/* I2C controller */
+typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
+struct ppc4xx_i2c_t {
+    qemu_irq irq;
+    uint8_t mdata;
+    uint8_t lmadr;
+    uint8_t hmadr;
+    uint8_t cntl;
+    uint8_t mdcntl;
+    uint8_t sts;
+    uint8_t extsts;
+    uint8_t sdata;
+    uint8_t lsadr;
+    uint8_t hsadr;
+    uint8_t clkdiv;
+    uint8_t intrmsk;
+    uint8_t xfrcnt;
+    uint8_t xtcntlss;
+    uint8_t directcntl;
+};
+
+static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_i2c_t *i2c;
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    i2c = opaque;
+    switch (addr) {
+    case 0x00:
+        //        i2c_readbyte(&i2c->mdata);
+        ret = i2c->mdata;
+        break;
+    case 0x02:
+        ret = i2c->sdata;
+        break;
+    case 0x04:
+        ret = i2c->lmadr;
+        break;
+    case 0x05:
+        ret = i2c->hmadr;
+        break;
+    case 0x06:
+        ret = i2c->cntl;
+        break;
+    case 0x07:
+        ret = i2c->mdcntl;
+        break;
+    case 0x08:
+        ret = i2c->sts;
+        break;
+    case 0x09:
+        ret = i2c->extsts;
+        break;
+    case 0x0A:
+        ret = i2c->lsadr;
+        break;
+    case 0x0B:
+        ret = i2c->hsadr;
+        break;
+    case 0x0C:
+        ret = i2c->clkdiv;
+        break;
+    case 0x0D:
+        ret = i2c->intrmsk;
+        break;
+    case 0x0E:
+        ret = i2c->xfrcnt;
+        break;
+    case 0x0F:
+        ret = i2c->xtcntlss;
+        break;
+    case 0x10:
+        ret = i2c->directcntl;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret);
+#endif
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_i2c_t *i2c;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    i2c = opaque;
+    switch (addr) {
+    case 0x00:
+        i2c->mdata = value;
+        //        i2c_sendbyte(&i2c->mdata);
+        break;
+    case 0x02:
+        i2c->sdata = value;
+        break;
+    case 0x04:
+        i2c->lmadr = value;
+        break;
+    case 0x05:
+        i2c->hmadr = value;
+        break;
+    case 0x06:
+        i2c->cntl = value;
+        break;
+    case 0x07:
+        i2c->mdcntl = value & 0xDF;
+        break;
+    case 0x08:
+        i2c->sts &= ~(value & 0x0A);
+        break;
+    case 0x09:
+        i2c->extsts &= ~(value & 0x8F);
+        break;
+    case 0x0A:
+        i2c->lsadr = value;
+        break;
+    case 0x0B:
+        i2c->hsadr = value;
+        break;
+    case 0x0C:
+        i2c->clkdiv = value;
+        break;
+    case 0x0D:
+        i2c->intrmsk = value;
+        break;
+    case 0x0E:
+        i2c->xfrcnt = value & 0x77;
+        break;
+    case 0x0F:
+        i2c->xtcntlss = value;
+        break;
+    case 0x10:
+        i2c->directcntl = value & 0x7;
+        break;
+    }
+}
+
+static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
+    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 3, value);
+}
+
+static CPUReadMemoryFunc * const i2c_read[] = {
+    &ppc4xx_i2c_readb,
+    &ppc4xx_i2c_readw,
+    &ppc4xx_i2c_readl,
+};
+
+static CPUWriteMemoryFunc * const i2c_write[] = {
+    &ppc4xx_i2c_writeb,
+    &ppc4xx_i2c_writew,
+    &ppc4xx_i2c_writel,
+};
+
+static void ppc4xx_i2c_reset (void *opaque)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = opaque;
+    i2c->mdata = 0x00;
+    i2c->sdata = 0x00;
+    i2c->cntl = 0x00;
+    i2c->mdcntl = 0x00;
+    i2c->sts = 0x00;
+    i2c->extsts = 0x00;
+    i2c->clkdiv = 0x00;
+    i2c->xfrcnt = 0x00;
+    i2c->directcntl = 0x0F;
+}
+
+static void ppc405_i2c_init(target_phys_addr_t base, qemu_irq irq)
+{
+    ppc4xx_i2c_t *i2c;
+    int io;
+
+    i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
+    i2c->irq = irq;
+#ifdef DEBUG_I2C
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    io = cpu_register_io_memory(i2c_read, i2c_write, i2c,
+                                DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x011, io);
+    qemu_register_reset(ppc4xx_i2c_reset, i2c);
+}
+
+/*****************************************************************************/
+/* General purpose timers */
+typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
+struct ppc4xx_gpt_t {
+    int64_t tb_offset;
+    uint32_t tb_freq;
+    struct QEMUTimer *timer;
+    qemu_irq irqs[5];
+    uint32_t oe;
+    uint32_t ol;
+    uint32_t im;
+    uint32_t is;
+    uint32_t ie;
+    uint32_t comp[5];
+    uint32_t mask[5];
+};
+
+static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
+{
+    /* XXX: TODO */
+    return 0;
+}
+
+static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
+{
+    /* XXX: TODO */
+}
+
+static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x80000000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->oe & mask) {
+            /* Output is enabled */
+            if (ppc4xx_gpt_compare(gpt, i)) {
+                /* Comparison is OK */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
+            } else {
+                /* Comparison is KO */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
+            }
+        }
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x00008000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->is & gpt->im & mask)
+            qemu_irq_raise(gpt->irqs[i]);
+        else
+            qemu_irq_lower(gpt->irqs[i]);
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
+{
+    /* XXX: TODO */
+}
+
+static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_gpt_t *gpt;
+    uint32_t ret;
+    int idx;
+
+#ifdef DEBUG_GPT
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+    gpt = opaque;
+    switch (addr) {
+    case 0x00:
+        /* Time base counter */
+        ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset,
+                       gpt->tb_freq, get_ticks_per_sec());
+        break;
+    case 0x10:
+        /* Output enable */
+        ret = gpt->oe;
+        break;
+    case 0x14:
+        /* Output level */
+        ret = gpt->ol;
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        ret = gpt->im;
+        break;
+    case 0x1C:
+    case 0x20:
+        /* Interrupt status */
+        ret = gpt->is;
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        ret = gpt->ie;
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = (addr - 0x80) >> 2;
+        ret = gpt->comp[idx];
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = (addr - 0xC0) >> 2;
+        ret = gpt->mask[idx];
+        break;
+    default:
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+static void ppc4xx_gpt_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_gpt_t *gpt;
+    int idx;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+    gpt = opaque;
+    switch (addr) {
+    case 0x00:
+        /* Time base counter */
+        gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq)
+            - qemu_get_clock_ns(vm_clock);
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0x10:
+        /* Output enable */
+        gpt->oe = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x14:
+        /* Output level */
+        gpt->ol = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        gpt->im = value & 0x0000F800;
+        break;
+    case 0x1C:
+        /* Interrupt status set */
+        gpt->is |= value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x20:
+        /* Interrupt status clear */
+        gpt->is &= ~(value & 0x0000F800);
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        gpt->ie = value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = (addr - 0x80) >> 2;
+        gpt->comp[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = (addr - 0xC0) >> 2;
+        gpt->mask[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const gpt_read[] = {
+    &ppc4xx_gpt_readb,
+    &ppc4xx_gpt_readw,
+    &ppc4xx_gpt_readl,
+};
+
+static CPUWriteMemoryFunc * const gpt_write[] = {
+    &ppc4xx_gpt_writeb,
+    &ppc4xx_gpt_writew,
+    &ppc4xx_gpt_writel,
+};
+
+static void ppc4xx_gpt_cb (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+
+    gpt = opaque;
+    ppc4xx_gpt_set_irqs(gpt);
+    ppc4xx_gpt_set_outputs(gpt);
+    ppc4xx_gpt_compute_timer(gpt);
+}
+
+static void ppc4xx_gpt_reset (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+
+    gpt = opaque;
+    qemu_del_timer(gpt->timer);
+    gpt->oe = 0x00000000;
+    gpt->ol = 0x00000000;
+    gpt->im = 0x00000000;
+    gpt->is = 0x00000000;
+    gpt->ie = 0x00000000;
+    for (i = 0; i < 5; i++) {
+        gpt->comp[i] = 0x00000000;
+        gpt->mask[i] = 0x00000000;
+    }
+}
+
+static void ppc4xx_gpt_init(target_phys_addr_t base, qemu_irq irqs[5])
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+    int io;
+
+    gpt = qemu_mallocz(sizeof(ppc4xx_gpt_t));
+    for (i = 0; i < 5; i++) {
+        gpt->irqs[i] = irqs[i];
+    }
+    gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt);
+#ifdef DEBUG_GPT
+    printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
+#endif
+    io = cpu_register_io_memory(gpt_read, gpt_write, gpt, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x0d4, io);
+    qemu_register_reset(ppc4xx_gpt_reset, gpt);
+}
+
+/*****************************************************************************/
+/* MAL */
+enum {
+    MAL0_CFG      = 0x180,
+    MAL0_ESR      = 0x181,
+    MAL0_IER      = 0x182,
+    MAL0_TXCASR   = 0x184,
+    MAL0_TXCARR   = 0x185,
+    MAL0_TXEOBISR = 0x186,
+    MAL0_TXDEIR   = 0x187,
+    MAL0_RXCASR   = 0x190,
+    MAL0_RXCARR   = 0x191,
+    MAL0_RXEOBISR = 0x192,
+    MAL0_RXDEIR   = 0x193,
+    MAL0_TXCTP0R  = 0x1A0,
+    MAL0_TXCTP1R  = 0x1A1,
+    MAL0_TXCTP2R  = 0x1A2,
+    MAL0_TXCTP3R  = 0x1A3,
+    MAL0_RXCTP0R  = 0x1C0,
+    MAL0_RXCTP1R  = 0x1C1,
+    MAL0_RCBS0    = 0x1E0,
+    MAL0_RCBS1    = 0x1E1,
+};
+
+typedef struct ppc40x_mal_t ppc40x_mal_t;
+struct ppc40x_mal_t {
+    qemu_irq irqs[4];
+    uint32_t cfg;
+    uint32_t esr;
+    uint32_t ier;
+    uint32_t txcasr;
+    uint32_t txcarr;
+    uint32_t txeobisr;
+    uint32_t txdeir;
+    uint32_t rxcasr;
+    uint32_t rxcarr;
+    uint32_t rxeobisr;
+    uint32_t rxdeir;
+    uint32_t txctpr[4];
+    uint32_t rxctpr[2];
+    uint32_t rcbs[2];
+};
+
+static void ppc40x_mal_reset (void *opaque);
+
+static uint32_t dcr_read_mal (void *opaque, int dcrn)
+{
+    ppc40x_mal_t *mal;
+    uint32_t ret;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        ret = mal->cfg;
+        break;
+    case MAL0_ESR:
+        ret = mal->esr;
+        break;
+    case MAL0_IER:
+        ret = mal->ier;
+        break;
+    case MAL0_TXCASR:
+        ret = mal->txcasr;
+        break;
+    case MAL0_TXCARR:
+        ret = mal->txcarr;
+        break;
+    case MAL0_TXEOBISR:
+        ret = mal->txeobisr;
+        break;
+    case MAL0_TXDEIR:
+        ret = mal->txdeir;
+        break;
+    case MAL0_RXCASR:
+        ret = mal->rxcasr;
+        break;
+    case MAL0_RXCARR:
+        ret = mal->rxcarr;
+        break;
+    case MAL0_RXEOBISR:
+        ret = mal->rxeobisr;
+        break;
+    case MAL0_RXDEIR:
+        ret = mal->rxdeir;
+        break;
+    case MAL0_TXCTP0R:
+        ret = mal->txctpr[0];
+        break;
+    case MAL0_TXCTP1R:
+        ret = mal->txctpr[1];
+        break;
+    case MAL0_TXCTP2R:
+        ret = mal->txctpr[2];
+        break;
+    case MAL0_TXCTP3R:
+        ret = mal->txctpr[3];
+        break;
+    case MAL0_RXCTP0R:
+        ret = mal->rxctpr[0];
+        break;
+    case MAL0_RXCTP1R:
+        ret = mal->rxctpr[1];
+        break;
+    case MAL0_RCBS0:
+        ret = mal->rcbs[0];
+        break;
+    case MAL0_RCBS1:
+        ret = mal->rcbs[1];
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_mal (void *opaque, int dcrn, uint32_t val)
+{
+    ppc40x_mal_t *mal;
+    int idx;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        if (val & 0x80000000)
+            ppc40x_mal_reset(mal);
+        mal->cfg = val & 0x00FFC087;
+        break;
+    case MAL0_ESR:
+        /* Read/clear */
+        mal->esr &= ~val;
+        break;
+    case MAL0_IER:
+        mal->ier = val & 0x0000001F;
+        break;
+    case MAL0_TXCASR:
+        mal->txcasr = val & 0xF0000000;
+        break;
+    case MAL0_TXCARR:
+        mal->txcarr = val & 0xF0000000;
+        break;
+    case MAL0_TXEOBISR:
+        /* Read/clear */
+        mal->txeobisr &= ~val;
+        break;
+    case MAL0_TXDEIR:
+        /* Read/clear */
+        mal->txdeir &= ~val;
+        break;
+    case MAL0_RXCASR:
+        mal->rxcasr = val & 0xC0000000;
+        break;
+    case MAL0_RXCARR:
+        mal->rxcarr = val & 0xC0000000;
+        break;
+    case MAL0_RXEOBISR:
+        /* Read/clear */
+        mal->rxeobisr &= ~val;
+        break;
+    case MAL0_RXDEIR:
+        /* Read/clear */
+        mal->rxdeir &= ~val;
+        break;
+    case MAL0_TXCTP0R:
+        idx = 0;
+        goto update_tx_ptr;
+    case MAL0_TXCTP1R:
+        idx = 1;
+        goto update_tx_ptr;
+    case MAL0_TXCTP2R:
+        idx = 2;
+        goto update_tx_ptr;
+    case MAL0_TXCTP3R:
+        idx = 3;
+    update_tx_ptr:
+        mal->txctpr[idx] = val;
+        break;
+    case MAL0_RXCTP0R:
+        idx = 0;
+        goto update_rx_ptr;
+    case MAL0_RXCTP1R:
+        idx = 1;
+    update_rx_ptr:
+        mal->rxctpr[idx] = val;
+        break;
+    case MAL0_RCBS0:
+        idx = 0;
+        goto update_rx_size;
+    case MAL0_RCBS1:
+        idx = 1;
+    update_rx_size:
+        mal->rcbs[idx] = val & 0x000000FF;
+        break;
+    }
+}
+
+static void ppc40x_mal_reset (void *opaque)
+{
+    ppc40x_mal_t *mal;
+
+    mal = opaque;
+    mal->cfg = 0x0007C000;
+    mal->esr = 0x00000000;
+    mal->ier = 0x00000000;
+    mal->rxcasr = 0x00000000;
+    mal->rxdeir = 0x00000000;
+    mal->rxeobisr = 0x00000000;
+    mal->txcasr = 0x00000000;
+    mal->txdeir = 0x00000000;
+    mal->txeobisr = 0x00000000;
+}
+
+static void ppc405_mal_init(CPUState *env, qemu_irq irqs[4])
+{
+    ppc40x_mal_t *mal;
+    int i;
+
+    mal = qemu_mallocz(sizeof(ppc40x_mal_t));
+    for (i = 0; i < 4; i++)
+        mal->irqs[i] = irqs[i];
+    qemu_register_reset(&ppc40x_mal_reset, mal);
+    ppc_dcr_register(env, MAL0_CFG,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_ESR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_IER,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCASR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCARR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXEOBISR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXDEIR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCASR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCARR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXEOBISR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXDEIR,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP0R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP1R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP2R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_TXCTP3R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCTP0R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RXCTP1R,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RCBS0,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+    ppc_dcr_register(env, MAL0_RCBS1,
+                     mal, &dcr_read_mal, &dcr_write_mal);
+}
+
+/*****************************************************************************/
+/* SPR */
+void ppc40x_core_reset (CPUState *env)
+{
+    target_ulong dbsr;
+
+    printf("Reset PowerPC core\n");
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    /* XXX: TOFIX */
+#if 0
+    cpu_reset(env);
+#else
+    qemu_system_reset_request();
+#endif
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000100;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_chip_reset (CPUState *env)
+{
+    target_ulong dbsr;
+
+    printf("Reset PowerPC chip\n");
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    /* XXX: TOFIX */
+#if 0
+    cpu_reset(env);
+#else
+    qemu_system_reset_request();
+#endif
+    /* XXX: TODO reset all internal peripherals */
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000200;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_system_reset (CPUState *env)
+{
+    printf("Reset PowerPC system\n");
+    qemu_system_reset_request();
+}
+
+void store_40x_dbcr0 (CPUState *env, uint32_t val)
+{
+    switch ((val >> 28) & 0x3) {
+    case 0x0:
+        /* No action */
+        break;
+    case 0x1:
+        /* Core reset */
+        ppc40x_core_reset(env);
+        break;
+    case 0x2:
+        /* Chip reset */
+        ppc40x_chip_reset(env);
+        break;
+    case 0x3:
+        /* System reset */
+        ppc40x_system_reset(env);
+        break;
+    }
+}
+
+/*****************************************************************************/
+/* PowerPC 405CR */
+enum {
+    PPC405CR_CPC0_PLLMR  = 0x0B0,
+    PPC405CR_CPC0_CR0    = 0x0B1,
+    PPC405CR_CPC0_CR1    = 0x0B2,
+    PPC405CR_CPC0_PSR    = 0x0B4,
+    PPC405CR_CPC0_JTAGID = 0x0B5,
+    PPC405CR_CPC0_ER     = 0x0B9,
+    PPC405CR_CPC0_FR     = 0x0BA,
+    PPC405CR_CPC0_SR     = 0x0BB,
+};
+
+enum {
+    PPC405CR_CPU_CLK   = 0,
+    PPC405CR_TMR_CLK   = 1,
+    PPC405CR_PLB_CLK   = 2,
+    PPC405CR_SDRAM_CLK = 3,
+    PPC405CR_OPB_CLK   = 4,
+    PPC405CR_EXT_CLK   = 5,
+    PPC405CR_UART_CLK  = 6,
+    PPC405CR_CLK_NB    = 7,
+};
+
+typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
+struct ppc405cr_cpc_t {
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    uint32_t sysclk;
+    uint32_t psr;
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t jtagid;
+    uint32_t pllmr;
+    uint32_t er;
+    uint32_t fr;
+};
+
+static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
+{
+    uint64_t VCO_out, PLL_out;
+    uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
+    int M, D0, D1, D2;
+
+    D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
+    if (cpc->pllmr & 0x80000000) {
+        D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
+        D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
+        M = D0 * D1 * D2;
+        VCO_out = cpc->sysclk * M;
+        if (VCO_out < 400000000 || VCO_out > 800000000) {
+            /* PLL cannot lock */
+            cpc->pllmr &= ~0x80000000;
+            goto bypass_pll;
+        }
+        PLL_out = VCO_out / D2;
+    } else {
+        /* Bypass PLL */
+    bypass_pll:
+        M = D0;
+        PLL_out = cpc->sysclk * M;
+    }
+    CPU_clk = PLL_out;
+    if (cpc->cr1 & 0x00800000)
+        TMR_clk = cpc->sysclk; /* Should have a separate clock */
+    else
+        TMR_clk = CPU_clk;
+    PLB_clk = CPU_clk / D0;
+    SDRAM_clk = PLB_clk;
+    D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
+    OPB_clk = PLB_clk / D0;
+    D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
+    EXT_clk = PLB_clk / D0;
+    D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
+    UART_clk = CPU_clk / D0;
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
+    /* Setup time-base clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
+    /* Setup SDRAM clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
+    /* Setup UART clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
+}
+
+static uint32_t dcr_read_crcpc (void *opaque, int dcrn)
+{
+    ppc405cr_cpc_t *cpc;
+    uint32_t ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        ret = cpc->pllmr;
+        break;
+    case PPC405CR_CPC0_CR0:
+        ret = cpc->cr0;
+        break;
+    case PPC405CR_CPC0_CR1:
+        ret = cpc->cr1;
+        break;
+    case PPC405CR_CPC0_PSR:
+        ret = cpc->psr;
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405CR_CPC0_ER:
+        ret = cpc->er;
+        break;
+    case PPC405CR_CPC0_FR:
+        ret = cpc->fr;
+        break;
+    case PPC405CR_CPC0_SR:
+        ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        cpc->pllmr = val & 0xFFF77C3F;
+        break;
+    case PPC405CR_CPC0_CR0:
+        cpc->cr0 = val & 0x0FFFFFFE;
+        break;
+    case PPC405CR_CPC0_CR1:
+        cpc->cr1 = val & 0x00800000;
+        break;
+    case PPC405CR_CPC0_PSR:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_ER:
+        cpc->er = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_FR:
+        cpc->fr = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_SR:
+        /* Read-only */
+        break;
+    }
+}
+
+static void ppc405cr_cpc_reset (void *opaque)
+{
+    ppc405cr_cpc_t *cpc;
+    int D;
+
+    cpc = opaque;
+    /* Compute PLLMR value from PSR settings */
+    cpc->pllmr = 0x80000000;
+    /* PFWD */
+    switch ((cpc->psr >> 30) & 3) {
+    case 0:
+        /* Bypass */
+        cpc->pllmr &= ~0x80000000;
+        break;
+    case 1:
+        /* Divide by 3 */
+        cpc->pllmr |= 5 << 16;
+        break;
+    case 2:
+        /* Divide by 4 */
+        cpc->pllmr |= 4 << 16;
+        break;
+    case 3:
+        /* Divide by 6 */
+        cpc->pllmr |= 2 << 16;
+        break;
+    }
+    /* PFBD */
+    D = (cpc->psr >> 28) & 3;
+    cpc->pllmr |= (D + 1) << 20;
+    /* PT   */
+    D = (cpc->psr >> 25) & 7;
+    switch (D) {
+    case 0x2:
+        cpc->pllmr |= 0x13;
+        break;
+    case 0x4:
+        cpc->pllmr |= 0x15;
+        break;
+    case 0x5:
+        cpc->pllmr |= 0x16;
+        break;
+    default:
+        break;
+    }
+    /* PDC  */
+    D = (cpc->psr >> 23) & 3;
+    cpc->pllmr |= D << 26;
+    /* ODP  */
+    D = (cpc->psr >> 21) & 3;
+    cpc->pllmr |= D << 10;
+    /* EBPD */
+    D = (cpc->psr >> 17) & 3;
+    cpc->pllmr |= D << 24;
+    cpc->cr0 = 0x0000003C;
+    cpc->cr1 = 0x2B0D8800;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    ppc405cr_clk_setup(cpc);
+}
+
+static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
+{
+    int D;
+
+    /* XXX: this should be read from IO pins */
+    cpc->psr = 0x00000000; /* 8 bits ROM */
+    /* PFWD */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 30;
+    /* PFBD */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 28;
+    /* PDC */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 23;
+    /* PT */
+    D = 0x5; /* M = 16 */
+    cpc->psr |= D << 25;
+    /* ODP */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 21;
+    /* EBDP */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 17;
+}
+
+static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
+                               uint32_t sysclk)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t));
+    memcpy(cpc->clk_setup, clk_setup,
+           PPC405CR_CLK_NB * sizeof(clk_setup_t));
+    cpc->sysclk = sysclk;
+    cpc->jtagid = 0x42051049;
+    ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
+                     &dcr_read_crcpc, &dcr_write_crcpc);
+    ppc405cr_clk_init(cpc);
+    qemu_register_reset(ppc405cr_cpc_reset, cpc);
+}
+
+CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
+                         target_phys_addr_t ram_sizes[4],
+                         uint32_t sysclk, qemu_irq **picp,
+                         int do_init)
+{
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    qemu_irq dma_irqs[4];
+    CPUState *env;
+    qemu_irq *pic, *irqs;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
+                      &clk_setup[PPC405CR_TMR_CLK], sysclk);
+    /* Memory mapped devices registers */
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(0xef600600);
+    /* Universal interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+    ppc4xx_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[26];
+    dma_irqs[1] = pic[25];
+    dma_irqs[2] = pic[24];
+    dma_irqs[3] = pic[23];
+    ppc405_dma_init(env, dma_irqs);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[0], 1, 1);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[1], 1, 1);
+    }
+    /* IIC controller */
+    ppc405_i2c_init(0xef600500, pic[2]);
+    /* GPIO */
+    ppc405_gpio_init(0xef600700);
+    /* CPU control */
+    ppc405cr_cpc_init(env, clk_setup, sysclk);
+
+    return env;
+}
+
+/*****************************************************************************/
+/* PowerPC 405EP */
+/* CPU control */
+enum {
+    PPC405EP_CPC0_PLLMR0 = 0x0F0,
+    PPC405EP_CPC0_BOOT   = 0x0F1,
+    PPC405EP_CPC0_EPCTL  = 0x0F3,
+    PPC405EP_CPC0_PLLMR1 = 0x0F4,
+    PPC405EP_CPC0_UCR    = 0x0F5,
+    PPC405EP_CPC0_SRR    = 0x0F6,
+    PPC405EP_CPC0_JTAGID = 0x0F7,
+    PPC405EP_CPC0_PCI    = 0x0F9,
+#if 0
+    PPC405EP_CPC0_ER     = xxx,
+    PPC405EP_CPC0_FR     = xxx,
+    PPC405EP_CPC0_SR     = xxx,
+#endif
+};
+
+enum {
+    PPC405EP_CPU_CLK   = 0,
+    PPC405EP_PLB_CLK   = 1,
+    PPC405EP_OPB_CLK   = 2,
+    PPC405EP_EBC_CLK   = 3,
+    PPC405EP_MAL_CLK   = 4,
+    PPC405EP_PCI_CLK   = 5,
+    PPC405EP_UART0_CLK = 6,
+    PPC405EP_UART1_CLK = 7,
+    PPC405EP_CLK_NB    = 8,
+};
+
+typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
+struct ppc405ep_cpc_t {
+    uint32_t sysclk;
+    clk_setup_t clk_setup[PPC405EP_CLK_NB];
+    uint32_t boot;
+    uint32_t epctl;
+    uint32_t pllmr[2];
+    uint32_t ucr;
+    uint32_t srr;
+    uint32_t jtagid;
+    uint32_t pci;
+    /* Clock and power management */
+    uint32_t er;
+    uint32_t fr;
+    uint32_t sr;
+};
+
+static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
+{
+    uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
+    uint32_t UART0_clk, UART1_clk;
+    uint64_t VCO_out, PLL_out;
+    int M, D;
+
+    VCO_out = 0;
+    if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
+        M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
+#ifdef DEBUG_CLOCKS_LL
+        printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
+#endif
+        D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
+#ifdef DEBUG_CLOCKS_LL
+        printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
+#endif
+        VCO_out = cpc->sysclk * M * D;
+        if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
+            /* Error - unlock the PLL */
+            printf("VCO out of range %" PRIu64 "\n", VCO_out);
+#if 0
+            cpc->pllmr[1] &= ~0x80000000;
+            goto pll_bypass;
+#endif
+        }
+        PLL_out = VCO_out / D;
+        /* Pretend the PLL is locked */
+        cpc->boot |= 0x00000001;
+    } else {
+#if 0
+    pll_bypass:
+#endif
+        PLL_out = cpc->sysclk;
+        if (cpc->pllmr[1] & 0x40000000) {
+            /* Pretend the PLL is not locked */
+            cpc->boot &= ~0x00000001;
+        }
+    }
+    /* Now, compute all other clocks */
+    D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
+#endif
+    CPU_clk = PLL_out / D;
+    D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
+#endif
+    PLB_clk = CPU_clk / D;
+    D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
+#endif
+    OPB_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
+#endif
+    EBC_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
+#endif
+    MAL_clk = PLB_clk / D;
+    D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D);
+#endif
+    PCI_clk = PLB_clk / D;
+    D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D);
+#endif
+    UART0_clk = PLL_out / D;
+    D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
+#ifdef DEBUG_CLOCKS_LL
+    printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D);
+#endif
+    UART1_clk = PLL_out / D;
+#ifdef DEBUG_CLOCKS
+    printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64
+           " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
+    printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32
+           " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32
+           " UART1 %" PRIu32 "\n",
+           CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
+           UART0_clk, UART1_clk);
+#endif
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
+    /* Setup MAL clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
+    /* Setup PCI clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
+    /* Setup UART0 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
+    /* Setup UART1 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
+}
+
+static uint32_t dcr_read_epcpc (void *opaque, int dcrn)
+{
+    ppc405ep_cpc_t *cpc;
+    uint32_t ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        ret = cpc->boot;
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        ret = cpc->epctl;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        ret = cpc->pllmr[0];
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        ret = cpc->pllmr[1];
+        break;
+    case PPC405EP_CPC0_UCR:
+        ret = cpc->ucr;
+        break;
+    case PPC405EP_CPC0_SRR:
+        ret = cpc->srr;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405EP_CPC0_PCI:
+        ret = cpc->pci;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        /* Read-only register */
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        /* Don't care for now */
+        cpc->epctl = val & 0xC00000F3;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        cpc->pllmr[0] = val & 0x00633333;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        cpc->pllmr[1] = val & 0xC0F73FFF;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_UCR:
+        /* UART control - don't care for now */
+        cpc->ucr = val & 0x003F7F7F;
+        break;
+    case PPC405EP_CPC0_SRR:
+        cpc->srr = val;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405EP_CPC0_PCI:
+        cpc->pci = val;
+        break;
+    }
+}
+
+static void ppc405ep_cpc_reset (void *opaque)
+{
+    ppc405ep_cpc_t *cpc = opaque;
+
+    cpc->boot = 0x00000010;     /* Boot from PCI - IIC EEPROM disabled */
+    cpc->epctl = 0x00000000;
+    cpc->pllmr[0] = 0x00011010;
+    cpc->pllmr[1] = 0x40000000;
+    cpc->ucr = 0x00000000;
+    cpc->srr = 0x00040000;
+    cpc->pci = 0x00000000;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    cpc->sr = 0x00000000;
+    ppc405ep_compute_clocks(cpc);
+}
+
+/* XXX: sysclk should be between 25 and 100 MHz */
+static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
+                               uint32_t sysclk)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t));
+    memcpy(cpc->clk_setup, clk_setup,
+           PPC405EP_CLK_NB * sizeof(clk_setup_t));
+    cpc->jtagid = 0x20267049;
+    cpc->sysclk = sysclk;
+    qemu_register_reset(&ppc405ep_cpc_reset, cpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+#if 0
+    ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+    ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
+                     &dcr_read_epcpc, &dcr_write_epcpc);
+#endif
+}
+
+CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+                         target_phys_addr_t ram_sizes[2],
+                         uint32_t sysclk, qemu_irq **picp,
+                         int do_init)
+{
+    clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
+    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
+    CPUState *env;
+    qemu_irq *pic, *irqs;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    /* init CPUs */
+    env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+                      &tlb_clk_setup, sysclk);
+    clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
+    clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
+    /* Internal devices init */
+    /* Memory mapped devices registers */
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(0xef600600);
+    /* Universal interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+	/* XXX 405EP has no ECC interrupt */
+    ppc4xx_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init);
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[5];
+    dma_irqs[1] = pic[6];
+    dma_irqs[2] = pic[7];
+    dma_irqs[3] = pic[8];
+    ppc405_dma_init(env, dma_irqs);
+    /* IIC controller */
+    ppc405_i2c_init(0xef600500, pic[2]);
+    /* GPIO */
+    ppc405_gpio_init(0xef600700);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[0], 1, 1);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[1], 1, 1);
+    }
+    /* OCM */
+    ppc405_ocm_init(env);
+    /* GPT */
+    gpt_irqs[0] = pic[19];
+    gpt_irqs[1] = pic[20];
+    gpt_irqs[2] = pic[21];
+    gpt_irqs[3] = pic[22];
+    gpt_irqs[4] = pic[23];
+    ppc4xx_gpt_init(0xef600000, gpt_irqs);
+    /* PCI */
+    /* Uses pic[3], pic[16], pic[18] */
+    /* MAL */
+    mal_irqs[0] = pic[11];
+    mal_irqs[1] = pic[12];
+    mal_irqs[2] = pic[13];
+    mal_irqs[3] = pic[14];
+    ppc405_mal_init(env, mal_irqs);
+    /* Ethernet */
+    /* Uses pic[9], pic[15], pic[17] */
+    /* CPU control */
+    ppc405ep_cpc_init(env, clk_setup, sysclk);
+
+    return env;
+}
diff --git a/qemu-0.15.x/hw/ppc440.c b/qemu-0.15.x/hw/ppc440.c
new file mode 100644
index 0000000..90abc91
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc440.c
@@ -0,0 +1,101 @@
+/*
+ * Qemu PowerPC 440 chip emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ * 	Jerone Young <jyoung5 at us.ibm.com>
+ * 	Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ * 	Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "ppc440.h"
+#include "ppc405.h"
+#include "sysemu.h"
+#include "kvm.h"
+
+#define PPC440EP_PCI_CONFIG     0xeec00000
+#define PPC440EP_PCI_INTACK     0xeed00000
+#define PPC440EP_PCI_SPECIAL    0xeed00000
+#define PPC440EP_PCI_REGS       0xef400000
+#define PPC440EP_PCI_IO         0xe8000000
+#define PPC440EP_PCI_IOLEN      0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+    256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
+                        const unsigned int pci_irq_nrs[4], int do_init,
+                        const char *cpu_model)
+{
+    target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
+    target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+    CPUState *env;
+    qemu_irq *pic;
+    qemu_irq *irqs;
+    qemu_irq *pci_irqs;
+
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx"; // XXX: should be 440EP
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+
+    /* SDRAM controller */
+    memset(ram_bases, 0, sizeof(ram_bases));
+    memset(ram_sizes, 0, sizeof(ram_sizes));
+    *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
+                                    ram_bases, ram_sizes,
+                                    ppc440ep_sdram_bank_sizes);
+    /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_bases,
+                      ram_sizes, do_init);
+
+    /* PCI */
+    pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
+    pci_irqs[0] = pic[pci_irq_nrs[0]];
+    pci_irqs[1] = pic[pci_irq_nrs[1]];
+    pci_irqs[2] = pic[pci_irq_nrs[2]];
+    pci_irqs[3] = pic[pci_irq_nrs[3]];
+    *pcip = ppc4xx_pci_init(env, pci_irqs,
+                            PPC440EP_PCI_CONFIG,
+                            PPC440EP_PCI_INTACK,
+                            PPC440EP_PCI_SPECIAL,
+                            PPC440EP_PCI_REGS);
+    if (!*pcip)
+        printf("couldn't create PCI controller!\n");
+
+    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[0], 1, 1);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+                       serial_hds[1], 1, 1);
+    }
+
+    return env;
+}
diff --git a/qemu-0.15.x/hw/ppc440.h b/qemu-0.15.x/hw/ppc440.h
new file mode 100644
index 0000000..a40f917
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc440.h
@@ -0,0 +1,21 @@
+/*
+ * Qemu PowerPC 440 board emualtion
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors: Jerone Young <jyoung5 at us.ibm.com>
+ * 	    Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the GNU GPL licence version 2 or later
+ *
+ */
+
+#ifndef QEMU_PPC440_H
+#define QEMU_PPC440_H
+
+#include "hw.h"
+
+CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
+                        const unsigned int pci_irq_nrs[4], int do_init,
+                        const char *cpu_model);
+
+#endif
diff --git a/qemu-0.15.x/hw/ppc440_bamboo.c b/qemu-0.15.x/hw/ppc440_bamboo.c
new file mode 100644
index 0000000..20b8629
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc440_bamboo.c
@@ -0,0 +1,200 @@
+/*
+ * Qemu PowerPC 440 Bamboo board emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ * 	Jerone Young <jyoung5 at us.ibm.com>
+ * 	Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ * 	Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "net.h"
+#include "hw.h"
+#include "pci.h"
+#include "boards.h"
+#include "ppc440.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
+
+#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
+
+/* from u-boot */
+#define KERNEL_ADDR  0x1000000
+#define FDT_ADDR     0x1800000
+#define RAMDISK_ADDR 0x1900000
+
+static int bamboo_load_device_tree(target_phys_addr_t addr,
+                                     uint32_t ramsize,
+                                     target_phys_addr_t initrd_base,
+                                     target_phys_addr_t initrd_size,
+                                     const char *kernel_cmdline)
+{
+    int ret = -1;
+#ifdef CONFIG_FDT
+    uint32_t mem_reg_property[] = { 0, 0, ramsize };
+    char *filename;
+    int fdt_size;
+    void *fdt;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+    if (!filename) {
+        goto out;
+    }
+    fdt = load_device_tree(filename, &fdt_size);
+    qemu_free(filename);
+    if (fdt == NULL) {
+        goto out;
+    }
+
+    /* Manipulate device tree in memory. */
+
+    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+                               sizeof(mem_reg_property));
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /memory/reg\n");
+
+    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                    initrd_base);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+
+    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                    (initrd_base + initrd_size));
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+
+    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                      kernel_cmdline);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+
+    if (kvm_enabled())
+        kvmppc_fdt_update(fdt);
+
+    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+    qemu_free(fdt);
+
+out:
+#endif
+
+    return ret;
+}
+
+static void bamboo_init(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
+    PCIBus *pcibus;
+    CPUState *env;
+    uint64_t elf_entry;
+    uint64_t elf_lowaddr;
+    target_phys_addr_t entry = 0;
+    target_phys_addr_t loadaddr = 0;
+    target_long initrd_size = 0;
+    int success;
+    int i;
+
+    /* Setup CPU. */
+    env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1, cpu_model);
+
+    if (pcibus) {
+        /* Register network interfaces. */
+        for (i = 0; i < nb_nics; i++) {
+            /* There are no PCI NICs on the Bamboo board, but there are
+             * PCI slots, so we can pick whatever default model we want. */
+            pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
+        }
+    }
+
+    /* Load kernel. */
+    if (kernel_filename) {
+        success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+        if (success < 0) {
+            success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+            entry = elf_entry;
+            loadaddr = elf_lowaddr;
+        }
+        /* XXX try again as binary */
+        if (success < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* Load initrd. */
+    if (initrd_filename) {
+        initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
+                                          ram_size - RAMDISK_ADDR);
+
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
+                    initrd_filename, RAMDISK_ADDR);
+            exit(1);
+        }
+    }
+
+    /* If we're loading a kernel directly, we must load the device tree too. */
+    if (kernel_filename) {
+        if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
+                                    initrd_size, kernel_cmdline) < 0) {
+            fprintf(stderr, "couldn't load device tree\n");
+            exit(1);
+        }
+
+        /* Set initial guest state. */
+        env->gpr[1] = (16<<20) - 8;
+        env->gpr[3] = FDT_ADDR;
+        env->nip = entry;
+        /* XXX we currently depend on KVM to create some initial TLB entries. */
+    }
+
+    if (kvm_enabled())
+        kvmppc_init();
+}
+
+static QEMUMachine bamboo_machine = {
+    .name = "bamboo-0.13",
+    .alias = "bamboo",
+    .desc = "bamboo",
+    .init = bamboo_init,
+};
+
+static QEMUMachine bamboo_machine_v0_12 = {
+    .name = "bamboo-0.12",
+    .desc = "bamboo",
+    .init = bamboo_init,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-serial-pci",
+            .property = "max_ports",
+            .value    = stringify(1),
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },
+        { /* end of list */ }
+    },
+};
+
+static void bamboo_machine_init(void)
+{
+    qemu_register_machine(&bamboo_machine);
+    qemu_register_machine(&bamboo_machine_v0_12);
+}
+
+machine_init(bamboo_machine_init);
diff --git a/qemu-0.15.x/hw/ppc4xx.h b/qemu-0.15.x/hw/ppc4xx.h
new file mode 100644
index 0000000..bc4ee01
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc4xx.h
@@ -0,0 +1,60 @@
+/*
+ * QEMU PowerPC 4xx emulation shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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(PPC_4XX_H)
+#define PPC_4XX_H
+
+#include "pci.h"
+
+/* PowerPC 4xx core initialization */
+CPUState *ppc4xx_init (const char *cpu_model,
+                       clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                       uint32_t sysclk);
+
+/* PowerPC 4xx universal interrupt controller */
+enum {
+    PPCUIC_OUTPUT_INT = 0,
+    PPCUIC_OUTPUT_CINT = 1,
+    PPCUIC_OUTPUT_NB,
+};
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr);
+
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               target_phys_addr_t ram_bases[],
+                               target_phys_addr_t ram_sizes[],
+                               const unsigned int sdram_bank_sizes[]);
+
+void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        target_phys_addr_t *ram_bases,
+                        target_phys_addr_t *ram_sizes,
+                        int do_init);
+
+PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
+                        target_phys_addr_t config_space,
+                        target_phys_addr_t int_ack,
+                        target_phys_addr_t special_cycle,
+                        target_phys_addr_t registers);
+
+#endif /* !defined(PPC_4XX_H) */
diff --git a/qemu-0.15.x/hw/ppc4xx_devs.c b/qemu-0.15.x/hw/ppc4xx_devs.c
new file mode 100644
index 0000000..68bdfaa
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc4xx_devs.c
@@ -0,0 +1,690 @@
+/*
+ * QEMU PowerPC 4xx embedded processors shared devices emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "qemu-log.h"
+
+//#define DEBUG_MMIO
+//#define DEBUG_UNASSIGNED
+#define DEBUG_UIC
+
+
+#ifdef DEBUG_UIC
+#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#else
+#  define LOG_UIC(...) do { } while (0)
+#endif
+
+/*****************************************************************************/
+/* Generic PowerPC 4xx processor instantiation */
+CPUState *ppc4xx_init (const char *cpu_model,
+                       clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                       uint32_t sysclk)
+{
+    CPUState *env;
+
+    /* init CPUs */
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
+                cpu_model);
+        exit(1);
+    }
+    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+    cpu_clk->opaque = env;
+    /* Set time-base frequency to sysclk */
+    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
+    tb_clk->opaque = env;
+    ppc_dcr_init(env, NULL, NULL);
+    /* Register qemu callbacks */
+    qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+
+    return env;
+}
+
+/*****************************************************************************/
+/* "Universal" Interrupt controller */
+enum {
+    DCR_UICSR  = 0x000,
+    DCR_UICSRS = 0x001,
+    DCR_UICER  = 0x002,
+    DCR_UICCR  = 0x003,
+    DCR_UICPR  = 0x004,
+    DCR_UICTR  = 0x005,
+    DCR_UICMSR = 0x006,
+    DCR_UICVR  = 0x007,
+    DCR_UICVCR = 0x008,
+    DCR_UICMAX = 0x009,
+};
+
+#define UIC_MAX_IRQ 32
+typedef struct ppcuic_t ppcuic_t;
+struct ppcuic_t {
+    uint32_t dcr_base;
+    int use_vectors;
+    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
+    uint32_t uicsr;  /* Status register */
+    uint32_t uicer;  /* Enable register */
+    uint32_t uiccr;  /* Critical register */
+    uint32_t uicpr;  /* Polarity register */
+    uint32_t uictr;  /* Triggering register */
+    uint32_t uicvcr; /* Vector configuration register */
+    uint32_t uicvr;
+    qemu_irq *irqs;
+};
+
+static void ppcuic_trigger_irq (ppcuic_t *uic)
+{
+    uint32_t ir, cr;
+    int start, end, inc, i;
+
+    /* Trigger interrupt if any is pending */
+    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
+    cr = uic->uicsr & uic->uicer & uic->uiccr;
+    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
+                " uiccr %08" PRIx32 "\n"
+                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
+                __func__, uic->uicsr, uic->uicer, uic->uiccr,
+                uic->uicsr & uic->uicer, ir, cr);
+    if (ir != 0x0000000) {
+        LOG_UIC("Raise UIC interrupt\n");
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
+    } else {
+        LOG_UIC("Lower UIC interrupt\n");
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
+    }
+    /* Trigger critical interrupt if any is pending and update vector */
+    if (cr != 0x0000000) {
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        if (uic->use_vectors) {
+            /* Compute critical IRQ vector */
+            if (uic->uicvcr & 1) {
+                start = 31;
+                end = 0;
+                inc = -1;
+            } else {
+                start = 0;
+                end = 31;
+                inc = 1;
+            }
+            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
+            for (i = start; i <= end; i += inc) {
+                if (cr & (1 << i)) {
+                    uic->uicvr += (i - start) * 512 * inc;
+                    break;
+                }
+            }
+        }
+        LOG_UIC("Raise UIC critical interrupt - "
+                    "vector %08" PRIx32 "\n", uic->uicvr);
+    } else {
+        LOG_UIC("Lower UIC critical interrupt\n");
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        uic->uicvr = 0x00000000;
+    }
+}
+
+static void ppcuic_set_irq (void *opaque, int irq_num, int level)
+{
+    ppcuic_t *uic;
+    uint32_t mask, sr;
+
+    uic = opaque;
+    mask = 1 << (31-irq_num);
+    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
+                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
+                __func__, irq_num, level,
+                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
+    if (irq_num < 0 || irq_num > 31)
+        return;
+    sr = uic->uicsr;
+
+    /* Update status register */
+    if (uic->uictr & mask) {
+        /* Edge sensitive interrupt */
+        if (level == 1)
+            uic->uicsr |= mask;
+    } else {
+        /* Level sensitive interrupt */
+        if (level == 1) {
+            uic->uicsr |= mask;
+            uic->level |= mask;
+        } else {
+            uic->uicsr &= ~mask;
+            uic->level &= ~mask;
+        }
+    }
+    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
+                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
+    if (sr != uic->uicsr)
+        ppcuic_trigger_irq(uic);
+}
+
+static uint32_t dcr_read_uic (void *opaque, int dcrn)
+{
+    ppcuic_t *uic;
+    uint32_t ret;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    switch (dcrn) {
+    case DCR_UICSR:
+    case DCR_UICSRS:
+        ret = uic->uicsr;
+        break;
+    case DCR_UICER:
+        ret = uic->uicer;
+        break;
+    case DCR_UICCR:
+        ret = uic->uiccr;
+        break;
+    case DCR_UICPR:
+        ret = uic->uicpr;
+        break;
+    case DCR_UICTR:
+        ret = uic->uictr;
+        break;
+    case DCR_UICMSR:
+        ret = uic->uicsr & uic->uicer;
+        break;
+    case DCR_UICVR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvr;
+        break;
+    case DCR_UICVCR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvcr;
+        break;
+    default:
+    no_read:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
+    switch (dcrn) {
+    case DCR_UICSR:
+        uic->uicsr &= ~val;
+        uic->uicsr |= uic->level;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICSRS:
+        uic->uicsr |= val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICER:
+        uic->uicer = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICCR:
+        uic->uiccr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICPR:
+        uic->uicpr = val;
+        break;
+    case DCR_UICTR:
+        uic->uictr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICMSR:
+        break;
+    case DCR_UICVR:
+        break;
+    case DCR_UICVCR:
+        uic->uicvcr = val & 0xFFFFFFFD;
+        ppcuic_trigger_irq(uic);
+        break;
+    }
+}
+
+static void ppcuic_reset (void *opaque)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    uic->uiccr = 0x00000000;
+    uic->uicer = 0x00000000;
+    uic->uicpr = 0x00000000;
+    uic->uicsr = 0x00000000;
+    uic->uictr = 0x00000000;
+    if (uic->use_vectors) {
+        uic->uicvcr = 0x00000000;
+        uic->uicvr = 0x0000000;
+    }
+}
+
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr)
+{
+    ppcuic_t *uic;
+    int i;
+
+    uic = qemu_mallocz(sizeof(ppcuic_t));
+    uic->dcr_base = dcr_base;
+    uic->irqs = irqs;
+    if (has_vr)
+        uic->use_vectors = 1;
+    for (i = 0; i < DCR_UICMAX; i++) {
+        ppc_dcr_register(env, dcr_base + i, uic,
+                         &dcr_read_uic, &dcr_write_uic);
+    }
+    qemu_register_reset(ppcuic_reset, uic);
+
+    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
+}
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
+struct ppc4xx_sdram_t {
+    uint32_t addr;
+    int nbanks;
+    target_phys_addr_t ram_bases[4];
+    target_phys_addr_t ram_sizes[4];
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t bear;
+    uint32_t cfg;
+    uint32_t status;
+    uint32_t rtr;
+    uint32_t pmit;
+    uint32_t bcr[4];
+    uint32_t tr;
+    uint32_t ecccfg;
+    uint32_t eccesr;
+    qemu_irq irq;
+};
+
+enum {
+    SDRAM0_CFGADDR = 0x010,
+    SDRAM0_CFGDATA = 0x011,
+};
+
+/* XXX: TOFIX: some patches have made this code become inconsistent:
+ *      there are type inconsistencies, mixing target_phys_addr_t, target_ulong
+ *      and uint32_t
+ */
+static uint32_t sdram_bcr (target_phys_addr_t ram_base,
+                           target_phys_addr_t ram_size)
+{
+    uint32_t bcr;
+
+    switch (ram_size) {
+    case (4 * 1024 * 1024):
+        bcr = 0x00000000;
+        break;
+    case (8 * 1024 * 1024):
+        bcr = 0x00020000;
+        break;
+    case (16 * 1024 * 1024):
+        bcr = 0x00040000;
+        break;
+    case (32 * 1024 * 1024):
+        bcr = 0x00060000;
+        break;
+    case (64 * 1024 * 1024):
+        bcr = 0x00080000;
+        break;
+    case (128 * 1024 * 1024):
+        bcr = 0x000A0000;
+        break;
+    case (256 * 1024 * 1024):
+        bcr = 0x000C0000;
+        break;
+    default:
+        printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
+               ram_size);
+        return 0x00000000;
+    }
+    bcr |= ram_base & 0xFF800000;
+    bcr |= 1;
+
+    return bcr;
+}
+
+static inline target_phys_addr_t sdram_base(uint32_t bcr)
+{
+    return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size (uint32_t bcr)
+{
+    target_ulong size;
+    int sh;
+
+    sh = (bcr >> 17) & 0x7;
+    if (sh == 7)
+        size = -1;
+    else
+        size = (4 * 1024 * 1024) << sh;
+
+    return size;
+}
+
+static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+    if (*bcrp & 0x00000001) {
+        /* Unmap RAM */
+#ifdef DEBUG_SDRAM
+        printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+#endif
+        cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
+                                     IO_MEM_UNASSIGNED);
+    }
+    *bcrp = bcr & 0xFFDEE001;
+    if (enabled && (bcr & 0x00000001)) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(bcr), sdram_size(bcr));
+#endif
+        cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
+                                     sdram_base(bcr) | IO_MEM_RAM);
+    }
+}
+
+static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+        if (sdram->ram_sizes[i] != 0) {
+            sdram_set_bcr(&sdram->bcr[i],
+                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+                          1);
+        } else {
+            sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
+        }
+    }
+}
+
+static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
+#endif
+        cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
+                                     sdram_size(sdram->bcr[i]),
+                                     IO_MEM_UNASSIGNED);
+    }
+}
+
+static uint32_t dcr_read_sdram (void *opaque, int dcrn)
+{
+    ppc4xx_sdram_t *sdram;
+    uint32_t ret;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        ret = sdram->addr;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            ret = sdram->besr0;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            ret = sdram->besr1;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            ret = sdram->bear;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            ret = sdram->cfg;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            ret = sdram->status;
+            break;
+        case 0x30: /* SDRAM_RTR */
+            ret = sdram->rtr;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            ret = sdram->pmit;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            ret = sdram->bcr[0];
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            ret = sdram->bcr[1];
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            ret = sdram->bcr[2];
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            ret = sdram->bcr[3];
+            break;
+        case 0x80: /* SDRAM_TR */
+            ret = -1; /* ? */
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            ret = sdram->ecccfg;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            ret = sdram->eccesr;
+            break;
+        default: /* Error */
+            ret = -1;
+            break;
+        }
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        sdram->addr = val;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            sdram->besr0 &= ~val;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            sdram->besr1 &= ~val;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            sdram->bear = val;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            val &= 0xFFE00000;
+            if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: enable SDRAM controller\n", __func__);
+#endif
+                /* validate all RAM mappings */
+                sdram_map_bcr(sdram);
+                sdram->status &= ~0x80000000;
+            } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: disable SDRAM controller\n", __func__);
+#endif
+                /* invalidate all RAM mappings */
+                sdram_unmap_bcr(sdram);
+                sdram->status |= 0x80000000;
+            }
+            if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
+                sdram->status |= 0x40000000;
+            else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
+                sdram->status &= ~0x40000000;
+            sdram->cfg = val;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            /* Read-only register */
+            break;
+        case 0x30: /* SDRAM_RTR */
+            sdram->rtr = val & 0x3FF80000;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            sdram->pmit = (val & 0xF8000000) | 0x07C00000;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x80: /* SDRAM_TR */
+            sdram->tr = val & 0x018FC01F;
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            sdram->ecccfg = val & 0x00F00000;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            val &= 0xFFF0F000;
+            if (sdram->eccesr == 0 && val != 0)
+                qemu_irq_raise(sdram->irq);
+            else if (sdram->eccesr != 0 && val == 0)
+                qemu_irq_lower(sdram->irq);
+            sdram->eccesr = val;
+            break;
+        default: /* Error */
+            break;
+        }
+        break;
+    }
+}
+
+static void sdram_reset (void *opaque)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    sdram->addr = 0x00000000;
+    sdram->bear = 0x00000000;
+    sdram->besr0 = 0x00000000; /* No error */
+    sdram->besr1 = 0x00000000; /* No error */
+    sdram->cfg = 0x00000000;
+    sdram->ecccfg = 0x00000000; /* No ECC */
+    sdram->eccesr = 0x00000000; /* No error */
+    sdram->pmit = 0x07C00000;
+    sdram->rtr = 0x05F00000;
+    sdram->tr = 0x00854009;
+    /* We pre-initialize RAM banks */
+    sdram->status = 0x00000000;
+    sdram->cfg = 0x00800000;
+}
+
+void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        target_phys_addr_t *ram_bases,
+                        target_phys_addr_t *ram_sizes,
+                        int do_init)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
+    sdram->irq = irq;
+    sdram->nbanks = nbanks;
+    memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t));
+    memcpy(sdram->ram_bases, ram_bases,
+           nbanks * sizeof(target_phys_addr_t));
+    memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t));
+    memcpy(sdram->ram_sizes, ram_sizes,
+           nbanks * sizeof(target_phys_addr_t));
+    qemu_register_reset(&sdram_reset, sdram);
+    ppc_dcr_register(env, SDRAM0_CFGADDR,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM0_CFGDATA,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    if (do_init)
+        sdram_map_bcr(sdram);
+}
+
+/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory.
+ *
+ * sdram_bank_sizes[] must be 0-terminated.
+ *
+ * The 4xx SDRAM controller supports a small number of banks, and each bank
+ * must be one of a small set of sizes. The number of banks and the supported
+ * sizes varies by SoC. */
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               target_phys_addr_t ram_bases[],
+                               target_phys_addr_t ram_sizes[],
+                               const unsigned int sdram_bank_sizes[])
+{
+    ram_addr_t size_left = ram_size;
+    int i;
+    int j;
+
+    for (i = 0; i < nr_banks; i++) {
+        for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+            unsigned int bank_size = sdram_bank_sizes[j];
+
+            if (bank_size <= size_left) {
+                char name[32];
+                snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
+                ram_bases[i] = qemu_ram_alloc(NULL, name, bank_size);
+                ram_sizes[i] = bank_size;
+                size_left -= bank_size;
+                break;
+            }
+        }
+
+        if (!size_left) {
+            /* No need to use the remaining banks. */
+            break;
+        }
+    }
+
+    ram_size -= size_left;
+    if (size_left)
+        printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
+               (int)(ram_size >> 20));
+
+    return ram_size;
+}
diff --git a/qemu-0.15.x/hw/ppc4xx_pci.c b/qemu-0.15.x/hw/ppc4xx_pci.c
new file mode 100644
index 0000000..299473c
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc4xx_pci.c
@@ -0,0 +1,391 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
+ */
+
+/* This file implements emulation of the 32-bit PCI controller found in some
+ * 4xx SoCs, such as the 440EP. */
+
+#include "hw.h"
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "pci.h"
+#include "pci_host.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif /* DEBUG */
+
+struct PCIMasterMap {
+    uint32_t la;
+    uint32_t ma;
+    uint32_t pcila;
+    uint32_t pciha;
+};
+
+struct PCITargetMap {
+    uint32_t ms;
+    uint32_t la;
+};
+
+#define PPC4xx_PCI_NR_PMMS 3
+#define PPC4xx_PCI_NR_PTMS 2
+
+struct PPC4xxPCIState {
+    struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
+    struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
+
+    PCIHostState pci_state;
+    PCIDevice *pci_dev;
+};
+typedef struct PPC4xxPCIState PPC4xxPCIState;
+
+#define PCIC0_CFGADDR       0x0
+#define PCIC0_CFGDATA       0x4
+
+/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
+ * PCI accesses. */
+#define PCIL0_PMM0LA        0x0
+#define PCIL0_PMM0MA        0x4
+#define PCIL0_PMM0PCILA     0x8
+#define PCIL0_PMM0PCIHA     0xc
+#define PCIL0_PMM1LA        0x10
+#define PCIL0_PMM1MA        0x14
+#define PCIL0_PMM1PCILA     0x18
+#define PCIL0_PMM1PCIHA     0x1c
+#define PCIL0_PMM2LA        0x20
+#define PCIL0_PMM2MA        0x24
+#define PCIL0_PMM2PCILA     0x28
+#define PCIL0_PMM2PCIHA     0x2c
+
+/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
+ * PLB accesses. */
+#define PCIL0_PTM1MS        0x30
+#define PCIL0_PTM1LA        0x34
+#define PCIL0_PTM2MS        0x38
+#define PCIL0_PTM2LA        0x3c
+#define PCI_REG_SIZE        0x40
+
+
+static uint32_t pci4xx_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
+{
+    PPC4xxPCIState *ppc4xx_pci = opaque;
+
+    return ppc4xx_pci->pci_state.config_reg;
+}
+
+static CPUReadMemoryFunc * const pci4xx_cfgaddr_read[] = {
+    &pci4xx_cfgaddr_readl,
+    &pci4xx_cfgaddr_readl,
+    &pci4xx_cfgaddr_readl,
+};
+
+static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    PPC4xxPCIState *ppc4xx_pci = opaque;
+
+    ppc4xx_pci->pci_state.config_reg = value & ~0x3;
+}
+
+static CPUWriteMemoryFunc * const pci4xx_cfgaddr_write[] = {
+    &pci4xx_cfgaddr_writel,
+    &pci4xx_cfgaddr_writel,
+    &pci4xx_cfgaddr_writel,
+};
+
+static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
+                                  uint32_t value)
+{
+    struct PPC4xxPCIState *pci = opaque;
+
+    /* We ignore all target attempts at PCI configuration, effectively
+     * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
+
+    switch (offset) {
+    case PCIL0_PMM0LA:
+        pci->pmm[0].la = value;
+        break;
+    case PCIL0_PMM0MA:
+        pci->pmm[0].ma = value;
+        break;
+    case PCIL0_PMM0PCIHA:
+        pci->pmm[0].pciha = value;
+        break;
+    case PCIL0_PMM0PCILA:
+        pci->pmm[0].pcila = value;
+        break;
+
+    case PCIL0_PMM1LA:
+        pci->pmm[1].la = value;
+        break;
+    case PCIL0_PMM1MA:
+        pci->pmm[1].ma = value;
+        break;
+    case PCIL0_PMM1PCIHA:
+        pci->pmm[1].pciha = value;
+        break;
+    case PCIL0_PMM1PCILA:
+        pci->pmm[1].pcila = value;
+        break;
+
+    case PCIL0_PMM2LA:
+        pci->pmm[2].la = value;
+        break;
+    case PCIL0_PMM2MA:
+        pci->pmm[2].ma = value;
+        break;
+    case PCIL0_PMM2PCIHA:
+        pci->pmm[2].pciha = value;
+        break;
+    case PCIL0_PMM2PCILA:
+        pci->pmm[2].pcila = value;
+        break;
+
+    case PCIL0_PTM1MS:
+        pci->ptm[0].ms = value;
+        break;
+    case PCIL0_PTM1LA:
+        pci->ptm[0].la = value;
+        break;
+    case PCIL0_PTM2MS:
+        pci->ptm[1].ms = value;
+        break;
+    case PCIL0_PTM2LA:
+        pci->ptm[1].la = value;
+        break;
+
+    default:
+        printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
+               (unsigned long)offset);
+        break;
+    }
+}
+
+static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
+{
+    struct PPC4xxPCIState *pci = opaque;
+    uint32_t value;
+
+    switch (offset) {
+    case PCIL0_PMM0LA:
+        value = pci->pmm[0].la;
+        break;
+    case PCIL0_PMM0MA:
+        value = pci->pmm[0].ma;
+        break;
+    case PCIL0_PMM0PCIHA:
+        value = pci->pmm[0].pciha;
+        break;
+    case PCIL0_PMM0PCILA:
+        value = pci->pmm[0].pcila;
+        break;
+
+    case PCIL0_PMM1LA:
+        value = pci->pmm[1].la;
+        break;
+    case PCIL0_PMM1MA:
+        value = pci->pmm[1].ma;
+        break;
+    case PCIL0_PMM1PCIHA:
+        value = pci->pmm[1].pciha;
+        break;
+    case PCIL0_PMM1PCILA:
+        value = pci->pmm[1].pcila;
+        break;
+
+    case PCIL0_PMM2LA:
+        value = pci->pmm[2].la;
+        break;
+    case PCIL0_PMM2MA:
+        value = pci->pmm[2].ma;
+        break;
+    case PCIL0_PMM2PCIHA:
+        value = pci->pmm[2].pciha;
+        break;
+    case PCIL0_PMM2PCILA:
+        value = pci->pmm[2].pcila;
+        break;
+
+    case PCIL0_PTM1MS:
+        value = pci->ptm[0].ms;
+        break;
+    case PCIL0_PTM1LA:
+        value = pci->ptm[0].la;
+        break;
+    case PCIL0_PTM2MS:
+        value = pci->ptm[1].ms;
+        break;
+    case PCIL0_PTM2LA:
+        value = pci->ptm[1].la;
+        break;
+
+    default:
+        printf("%s: invalid PCI internal register 0x%lx\n", __func__,
+               (unsigned long)offset);
+        value = 0;
+    }
+
+    return value;
+}
+
+static CPUReadMemoryFunc * const pci_reg_read[] = {
+    &ppc4xx_pci_reg_read4,
+    &ppc4xx_pci_reg_read4,
+    &ppc4xx_pci_reg_read4,
+};
+
+static CPUWriteMemoryFunc * const pci_reg_write[] = {
+    &ppc4xx_pci_reg_write4,
+    &ppc4xx_pci_reg_write4,
+    &ppc4xx_pci_reg_write4,
+};
+
+static void ppc4xx_pci_reset(void *opaque)
+{
+    struct PPC4xxPCIState *pci = opaque;
+
+    memset(pci->pmm, 0, sizeof(pci->pmm));
+    memset(pci->ptm, 0, sizeof(pci->ptm));
+}
+
+/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
+ * may need further refactoring for other boards. */
+static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot = pci_dev->devfn >> 3;
+
+    DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
+            pci_dev->devfn, irq_num, slot);
+
+    return slot - 1;
+}
+
+static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pci_irqs = opaque;
+
+    DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
+    qemu_set_irq(pci_irqs[irq_num], level);
+}
+
+static const VMStateDescription vmstate_pci_master_map = {
+    .name = "pci_master_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(la, struct PCIMasterMap),
+        VMSTATE_UINT32(ma, struct PCIMasterMap),
+        VMSTATE_UINT32(pcila, struct PCIMasterMap),
+        VMSTATE_UINT32(pciha, struct PCIMasterMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_target_map = {
+    .name = "pci_target_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(ms, struct PCITargetMap),
+        VMSTATE_UINT32(la, struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ppc4xx_pci = {
+    .name = "ppc4xx_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState),
+        VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
+                             vmstate_pci_master_map,
+                             struct PCIMasterMap),
+        VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1,
+                             vmstate_pci_target_map,
+                             struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* XXX Interrupt acknowledge cycles not supported. */
+PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
+                        target_phys_addr_t config_space,
+                        target_phys_addr_t int_ack,
+                        target_phys_addr_t special_cycle,
+                        target_phys_addr_t registers)
+{
+    PPC4xxPCIState *controller;
+    int index;
+    static int ppc4xx_pci_id;
+    uint8_t *pci_conf;
+
+    controller = qemu_mallocz(sizeof(PPC4xxPCIState));
+
+    controller->pci_state.bus = pci_register_bus(NULL, "pci",
+                                                 ppc4xx_pci_set_irq,
+                                                 ppc4xx_pci_map_irq,
+                                                 pci_irqs, 0, 4);
+
+    controller->pci_dev = pci_register_device(controller->pci_state.bus,
+                                              "host bridge", sizeof(PCIDevice),
+                                              0, NULL, NULL);
+    pci_conf = controller->pci_dev->config;
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
+    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+
+    /* CFGADDR */
+    index = cpu_register_io_memory(pci4xx_cfgaddr_read,
+                                   pci4xx_cfgaddr_write, controller,
+                                   DEVICE_LITTLE_ENDIAN);
+    if (index < 0)
+        goto free;
+    cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
+
+    /* CFGDATA */
+    index = pci_host_data_register_mmio(&controller->pci_state, 1);
+    if (index < 0)
+        goto free;
+    cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
+
+    /* Internal registers */
+    index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
+                                   DEVICE_LITTLE_ENDIAN);
+    if (index < 0)
+        goto free;
+    cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
+
+    qemu_register_reset(ppc4xx_pci_reset, controller);
+
+    /* XXX load/save code not tested. */
+    vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++,
+                     &vmstate_ppc4xx_pci, controller);
+
+    return controller->pci_state.bus;
+
+free:
+    printf("%s error\n", __func__);
+    qemu_free(controller);
+    return NULL;
+}
diff --git a/qemu-0.15.x/hw/ppc_mac.h b/qemu-0.15.x/hw/ppc_mac.h
new file mode 100644
index 0000000..68dade7
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc_mac.h
@@ -0,0 +1,112 @@
+/*
+ * QEMU PowerMac emulation shared definitions and prototypes
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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(__PPC_MAC_H__)
+#define __PPC_MAC_H__
+
+/* SMP is not enabled, for now */
+#define MAX_CPUS 1
+
+#define BIOS_SIZE     (1024 * 1024)
+#define BIOS_FILENAME "ppc_rom.bin"
+#define NVRAM_SIZE        0x2000
+#define PROM_FILENAME    "openbios-ppc"
+#define PROM_ADDR         0xfff00000
+
+#define KERNEL_LOAD_ADDR 0x01000000
+#define KERNEL_GAP       0x00100000
+
+#define ESCC_CLOCK 3686400
+
+/* Cuda */
+void cuda_init (int *cuda_mem_index, qemu_irq irq);
+
+/* MacIO */
+void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
+                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
+                 int nb_ide, int *ide_mem_index, int escc_mem_index);
+
+/* Heathrow PIC */
+qemu_irq *heathrow_pic_init(int *pmem_index,
+                            int nb_cpus, qemu_irq **irqs);
+
+/* Grackle PCI */
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
+
+/* UniNorth PCI */
+PCIBus *pci_pmac_init(qemu_irq *pic);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic);
+
+/* Mac NVRAM */
+typedef struct MacIONVRAMState MacIONVRAMState;
+
+MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+                                   unsigned int it_shift);
+void macio_nvram_map (void *opaque, target_phys_addr_t mem_base);
+void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len);
+uint32_t macio_nvram_read (void *opaque, uint32_t addr);
+void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val);
+
+/* adb.c */
+
+#define MAX_ADB_DEVICES 16
+
+#define ADB_MAX_OUT_LEN 16
+
+typedef struct ADBDevice ADBDevice;
+
+/* buf = NULL means polling */
+typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
+                              const uint8_t *buf, int len);
+typedef int ADBDeviceReset(ADBDevice *d);
+
+struct ADBDevice {
+    struct ADBBusState *bus;
+    int devaddr;
+    int handler;
+    ADBDeviceRequest *devreq;
+    ADBDeviceReset *devreset;
+    void *opaque;
+};
+
+typedef struct ADBBusState {
+    ADBDevice devices[MAX_ADB_DEVICES];
+    int nb_devices;
+    int poll_index;
+} ADBBusState;
+
+int adb_request(ADBBusState *s, uint8_t *buf_out,
+                const uint8_t *buf, int len);
+int adb_poll(ADBBusState *s, uint8_t *buf_out);
+
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
+                               void *opaque);
+void adb_kbd_init(ADBBusState *bus);
+void adb_mouse_init(ADBBusState *bus);
+
+extern ADBBusState adb_bus;
+
+#endif /* !defined(__PPC_MAC_H__) */
diff --git a/qemu-0.15.x/hw/ppc_newworld.c b/qemu-0.15.x/hw/ppc_newworld.c
new file mode 100644
index 0000000..5bce709
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc_newworld.c
@@ -0,0 +1,429 @@
+/*
+ * QEMU PowerPC CHRP (currently NewWorld PowerMac) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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.
+ *
+ * PCI bus layout on a real G5 (U3 based):
+ *
+ * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b]
+ * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150]
+ * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a]
+ * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045]
+ * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046]
+ * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047]
+ * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048]
+ * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049]
+ * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20)
+ * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04)
+ * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043]
+ * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042]
+ * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c]
+ * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240]
+ *
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "ppc_mac.h"
+#include "mac_dbdma.h"
+#include "nvram.h"
+#include "pc.h"
+#include "pci.h"
+#include "usb-ohci.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "fw_cfg.h"
+#include "escc.h"
+#include "openpic.h"
+#include "ide.h"
+#include "loader.h"
+#include "elf.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "hw/usb.h"
+#include "blockdev.h"
+
+#define MAX_IDE_BUS 2
+#define CFG_ADDR 0xf0000510
+
+/* debug UniNorth */
+//#define DEBUG_UNIN
+
+#ifdef DEBUG_UNIN
+#define UNIN_DPRINTF(fmt, ...)                                  \
+    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define UNIN_DPRINTF(fmt, ...)
+#endif
+
+/* UniN device */
+static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    UNIN_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", addr, value);
+}
+
+static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t value;
+
+    value = 0;
+    UNIN_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", addr, value);
+
+    return value;
+}
+
+static CPUWriteMemoryFunc * const unin_write[] = {
+    &unin_writel,
+    &unin_writel,
+    &unin_writel,
+};
+
+static CPUReadMemoryFunc * const unin_read[] = {
+    &unin_readl,
+    &unin_readl,
+    &unin_readl,
+};
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
+/* PowerPC Mac99 hardware initialisation */
+static void ppc_core99_init (ram_addr_t ram_size,
+                             const char *boot_device,
+                             const char *kernel_filename,
+                             const char *kernel_cmdline,
+                             const char *initrd_filename,
+                             const char *cpu_model)
+{
+    CPUState *env = NULL;
+    char *filename;
+    qemu_irq *pic, **openpic_irqs;
+    int unin_memory;
+    int linux_boot, i;
+    ram_addr_t ram_offset, bios_offset;
+    target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0;
+    long kernel_size, initrd_size;
+    PCIBus *pci_bus;
+    MacIONVRAMState *nvr;
+    int nvram_mem_index;
+    int bios_size;
+    int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
+    int ide_mem_index[3];
+    int ppc_boot_device;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    void *fw_cfg;
+    void *dbdma;
+    int machine_arch;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* init CPUs */
+    if (cpu_model == NULL)
+#ifdef TARGET_PPC64
+        cpu_model = "970fx";
+#else
+        cpu_model = "G4";
+#endif
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        /* Set time-base frequency to 100 Mhz */
+        cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+    }
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_core99.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate and load BIOS */
+    bios_offset = qemu_ram_alloc(NULL, "ppc_core99.bios", BIOS_SIZE);
+    if (bios_name == NULL)
+        bios_name = PROM_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+    /* Load OpenBIOS (ELF) */
+    if (filename) {
+        bios_size = load_elf(filename, NULL, NULL, NULL,
+                             NULL, NULL, 1, ELF_MACHINE, 0);
+
+        qemu_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size < 0 || bios_size > BIOS_SIZE) {
+        hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name);
+        exit(1);
+    }
+
+    if (linux_boot) {
+        uint64_t lowaddr = 0;
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_base = KERNEL_LOAD_ADDR;
+
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0)
+            kernel_size = load_aout(kernel_filename, kernel_base,
+                                    ram_size - kernel_base, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        if (kernel_size < 0)
+            kernel_size = load_image_targphys(kernel_filename,
+                                              kernel_base,
+                                              ram_size - kernel_base);
+        if (kernel_size < 0) {
+            hw_error("qemu: could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                hw_error("qemu: could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+            cmdline_base = round_page(initrd_base + initrd_size);
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
+        }
+        ppc_boot_device = 'm';
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        ppc_boot_device = '\0';
+        /* We consider that NewWorld PowerMac never have any floppy drive
+         * For now, OHW cannot boot from the network.
+         */
+        for (i = 0; boot_device[i] != '\0'; i++) {
+            if (boot_device[i] >= 'c' && boot_device[i] <= 'f') {
+                ppc_boot_device = boot_device[i];
+                break;
+            }
+        }
+        if (ppc_boot_device == '\0') {
+            fprintf(stderr, "No valid boot device for Mac99 machine\n");
+            exit(1);
+        }
+    }
+
+    isa_mem_base = 0x80000000;
+
+    /* Register 8 MB of ISA IO space */
+    isa_mmio_init(0xf2000000, 0x00800000);
+
+    /* UniN init */
+    unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
+
+    openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+    openpic_irqs[0] =
+        qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+    for (i = 0; i < smp_cpus; i++) {
+        /* Mac99 IRQ connection between OpenPIC outputs pins
+         * and PowerPC input pins
+         */
+        switch (PPC_INPUT(env)) {
+        case PPC_FLAGS_INPUT_6xx:
+            openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+            openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
+            /* Not connected ? */
+            openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+            /* Check this */
+            openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
+            break;
+#if defined(TARGET_PPC64)
+        case PPC_FLAGS_INPUT_970:
+            openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+            openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+                ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+                ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+                ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
+            /* Not connected ? */
+            openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+            /* Check this */
+            openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+                ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
+            break;
+#endif /* defined(TARGET_PPC64) */
+        default:
+            hw_error("Bus model not supported on mac99 machine\n");
+            exit(1);
+        }
+    }
+    pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
+    if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
+        /* 970 gets a U3 bus */
+        pci_bus = pci_pmac_u3_init(pic);
+        machine_arch = ARCH_MAC99_U3;
+    } else {
+        pci_bus = pci_pmac_init(pic);
+        machine_arch = ARCH_MAC99;
+    }
+    /* init basic PC hardware */
+    pci_vga_init(pci_bus);
+
+    escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
+                               serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
+
+    for(i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    dbdma = DBDMA_init(&dbdma_mem_index);
+
+    /* We only emulate 2 out of 3 IDE controllers for now */
+    ide_mem_index[0] = -1;
+    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
+    ide_mem_index[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
+
+    /* cuda also initialize ADB */
+    if (machine_arch == ARCH_MAC99_U3) {
+        usb_enabled = 1;
+    }
+    cuda_init(&cuda_mem_index, pic[0x19]);
+
+    adb_kbd_init(&adb_bus);
+    adb_mouse_init(&adb_bus);
+
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
+               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
+               escc_mem_index);
+
+    if (usb_enabled) {
+        usb_ohci_init_pci(pci_bus, -1);
+    }
+
+    /* U3 needs to use USB for input because Linux doesn't support via-cuda
+       on PPC64 */
+    if (machine_arch == ARCH_MAC99_U3) {
+        usbdevice_create("keyboard");
+        usbdevice_create("mouse");
+    }
+
+    if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
+        graphic_depth = 15;
+
+    /* The NewWorld NVRAM is not located in the MacIO device */
+    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 1);
+    pmac_format_nvram_partition(nvr, 0x2000);
+    macio_nvram_map(nvr, 0xFFF04000);
+    /* No PCI init: the BIOS will do it */
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);
+
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
+#endif
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+    }
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+static QEMUMachine core99_machine = {
+    .name = "mac99",
+    .desc = "Mac99 based PowerMAC",
+    .init = ppc_core99_init,
+    .max_cpus = MAX_CPUS,
+#ifdef TARGET_PPC64
+    .is_default = 1,
+#endif
+};
+
+static void core99_machine_init(void)
+{
+    qemu_register_machine(&core99_machine);
+}
+
+machine_init(core99_machine_init);
diff --git a/qemu-0.15.x/hw/ppc_oldworld.c b/qemu-0.15.x/hw/ppc_oldworld.c
new file mode 100644
index 0000000..20cd8e1
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc_oldworld.c
@@ -0,0 +1,334 @@
+
+/*
+ * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "ppc.h"
+#include "ppc_mac.h"
+#include "mac_dbdma.h"
+#include "nvram.h"
+#include "pc.h"
+#include "sysemu.h"
+#include "net.h"
+#include "isa.h"
+#include "pci.h"
+#include "usb-ohci.h"
+#include "boards.h"
+#include "fw_cfg.h"
+#include "escc.h"
+#include "ide.h"
+#include "loader.h"
+#include "elf.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "blockdev.h"
+
+#define MAX_IDE_BUS 2
+#define CFG_ADDR 0xf0000510
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
+static void ppc_heathrow_init (ram_addr_t ram_size,
+                               const char *boot_device,
+                               const char *kernel_filename,
+                               const char *kernel_cmdline,
+                               const char *initrd_filename,
+                               const char *cpu_model)
+{
+    CPUState *env = NULL;
+    char *filename;
+    qemu_irq *pic, **heathrow_irqs;
+    int linux_boot, i;
+    ram_addr_t ram_offset, bios_offset;
+    uint32_t kernel_base, initrd_base, cmdline_base = 0;
+    int32_t kernel_size, initrd_size;
+    PCIBus *pci_bus;
+    MacIONVRAMState *nvr;
+    int bios_size;
+    int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
+    int escc_mem_index, ide_mem_index[2];
+    uint16_t ppc_boot_device;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    void *fw_cfg;
+    void *dbdma;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* init CPUs */
+    if (cpu_model == NULL)
+        cpu_model = "G3";
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        /* Set time-base frequency to 16.6 Mhz */
+        cpu_ppc_tb_init(env,  16600000UL);
+        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+    }
+
+    /* allocate RAM */
+    if (ram_size > (2047 << 20)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d MB, maximum 2047 MB\n",
+                ((unsigned int)ram_size / (1 << 20)));
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate and load BIOS */
+    bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);
+    if (bios_name == NULL)
+        bios_name = PROM_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+    /* Load OpenBIOS (ELF) */
+    if (filename) {
+        bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
+                             1, ELF_MACHINE, 0);
+        qemu_free(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size < 0 || bios_size > BIOS_SIZE) {
+        hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name);
+        exit(1);
+    }
+
+    if (linux_boot) {
+        uint64_t lowaddr = 0;
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_base = KERNEL_LOAD_ADDR;
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0)
+            kernel_size = load_aout(kernel_filename, kernel_base,
+                                    ram_size - kernel_base, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        if (kernel_size < 0)
+            kernel_size = load_image_targphys(kernel_filename,
+                                              kernel_base,
+                                              ram_size - kernel_base);
+        if (kernel_size < 0) {
+            hw_error("qemu: could not load kernel '%s'\n",
+                      kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                hw_error("qemu: could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+            cmdline_base = round_page(initrd_base + initrd_size);
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
+        }
+        ppc_boot_device = 'm';
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        ppc_boot_device = '\0';
+        for (i = 0; boot_device[i] != '\0'; i++) {
+            /* TOFIX: for now, the second IDE channel is not properly
+             *        used by OHW. The Mac floppy disk are not emulated.
+             *        For now, OHW cannot boot from the network.
+             */
+#if 0
+            if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {
+                ppc_boot_device = boot_device[i];
+                break;
+            }
+#else
+            if (boot_device[i] >= 'c' && boot_device[i] <= 'd') {
+                ppc_boot_device = boot_device[i];
+                break;
+            }
+#endif
+        }
+        if (ppc_boot_device == '\0') {
+            fprintf(stderr, "No valid boot device for G3 Beige machine\n");
+            exit(1);
+        }
+    }
+
+    isa_mem_base = 0x80000000;
+
+    /* Register 2 MB of ISA IO space */
+    isa_mmio_init(0xfe000000, 0x00200000);
+
+    /* XXX: we register only 1 output pin for heathrow PIC */
+    heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+    heathrow_irqs[0] =
+        qemu_mallocz(smp_cpus * sizeof(qemu_irq) * 1);
+    /* Connect the heathrow PIC outputs to the 6xx bus */
+    for (i = 0; i < smp_cpus; i++) {
+        switch (PPC_INPUT(env)) {
+        case PPC_FLAGS_INPUT_6xx:
+            heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);
+            heathrow_irqs[i][0] =
+                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+            break;
+        default:
+            hw_error("Bus model not supported on OldWorld Mac machine\n");
+        }
+    }
+
+    /* init basic PC hardware */
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        hw_error("Only 6xx bus is supported on heathrow machine\n");
+    }
+    pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
+    pci_bus = pci_grackle_init(0xfec00000, pic);
+    pci_vga_init(pci_bus);
+
+    escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
+                               serial_hds[1], ESCC_CLOCK, 4);
+
+    for(i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    /* First IDE channel is a MAC IDE on the MacIO bus */
+    dbdma = DBDMA_init(&dbdma_mem_index);
+    ide_mem_index[0] = -1;
+    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
+
+    /* Second IDE channel is a CMD646 on the PCI bus */
+    hd[0] = hd[MAX_IDE_DEVS];
+    hd[1] = hd[MAX_IDE_DEVS + 1];
+    hd[3] = hd[2] = NULL;
+    pci_cmd646_ide_init(pci_bus, hd, 0);
+
+    /* cuda also initialize ADB */
+    cuda_init(&cuda_mem_index, pic[0x12]);
+
+    adb_kbd_init(&adb_bus);
+    adb_mouse_init(&adb_bus);
+
+    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 4);
+    pmac_format_nvram_partition(nvr, 0x2000);
+
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
+               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
+               escc_mem_index);
+
+    if (usb_enabled) {
+        usb_ohci_init_pci(pci_bus, -1);
+    }
+
+    if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
+        graphic_depth = 15;
+
+    /* No PCI init: the BIOS will do it */
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);
+
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
+#endif
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+    }
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+static QEMUMachine heathrow_machine = {
+    .name = "g3beige",
+    .desc = "Heathrow based PowerMAC",
+    .init = ppc_heathrow_init,
+    .max_cpus = MAX_CPUS,
+#ifndef TARGET_PPC64
+    .is_default = 1,
+#endif
+};
+
+static void heathrow_machine_init(void)
+{
+    qemu_register_machine(&heathrow_machine);
+}
+
+machine_init(heathrow_machine_init);
diff --git a/qemu-0.15.x/hw/ppc_prep.c b/qemu-0.15.x/hw/ppc_prep.c
new file mode 100644
index 0000000..0e9cfc2
--- /dev/null
+++ b/qemu-0.15.x/hw/ppc_prep.c
@@ -0,0 +1,763 @@
+/*
+ * QEMU PPC PREP hardware System Emulator
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * 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 "hw.h"
+#include "nvram.h"
+#include "pc.h"
+#include "fdc.h"
+#include "net.h"
+#include "sysemu.h"
+#include "isa.h"
+#include "pci.h"
+#include "prep_pci.h"
+#include "usb-ohci.h"
+#include "ppc.h"
+#include "boards.h"
+#include "qemu-log.h"
+#include "ide.h"
+#include "loader.h"
+#include "mc146818rtc.h"
+#include "blockdev.h"
+
+//#define HARD_DEBUG_PPC_IO
+//#define DEBUG_PPC_IO
+
+/* SMP is not enabled, for now */
+#define MAX_CPUS 1
+
+#define MAX_IDE_BUS 2
+
+#define BIOS_SIZE (1024 * 1024)
+#define BIOS_FILENAME "ppc_rom.bin"
+#define KERNEL_LOAD_ADDR 0x01000000
+#define INITRD_LOAD_ADDR 0x01800000
+
+#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO)
+#define DEBUG_PPC_IO
+#endif
+
+#if defined (HARD_DEBUG_PPC_IO)
+#define PPC_IO_DPRINTF(fmt, ...)                         \
+do {                                                     \
+    if (qemu_loglevel_mask(CPU_LOG_IOPORT)) {            \
+        qemu_log("%s: " fmt, __func__ , ## __VA_ARGS__); \
+    } else {                                             \
+        printf("%s : " fmt, __func__ , ## __VA_ARGS__);  \
+    }                                                    \
+} while (0)
+#elif defined (DEBUG_PPC_IO)
+#define PPC_IO_DPRINTF(fmt, ...) \
+qemu_log_mask(CPU_LOG_IOPORT, fmt, ## __VA_ARGS__)
+#else
+#define PPC_IO_DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+/* Constants for devices init */
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 13, 13 };
+
+#define NE2000_NB_MAX 6
+
+static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
+static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
+
+//static ISADevice *pit;
+
+/* ISA IO ports bridge */
+#define PPC_IO_BASE 0x80000000
+
+#if 0
+/* Speaker port 0x61 */
+static int speaker_data_on;
+static int dummy_refresh_clock;
+#endif
+
+static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val)
+{
+#if 0
+    speaker_data_on = (val >> 1) & 1;
+    pit_set_gate(pit, 2, val & 1);
+#endif
+}
+
+static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
+{
+#if 0
+    int out;
+    out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock));
+    dummy_refresh_clock ^= 1;
+    return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
+        (dummy_refresh_clock << 4);
+#endif
+    return 0;
+}
+
+/* PCI intack register */
+/* Read-only register (?) */
+static void _PPC_intack_write (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#if 0
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+           value);
+#endif
+}
+
+static inline uint32_t _PPC_intack_read(target_phys_addr_t addr)
+{
+    uint32_t retval = 0;
+
+    if ((addr & 0xf) == 0)
+        retval = pic_intack_read(isa_pic);
+#if 0
+    printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
+           retval);
+#endif
+
+    return retval;
+}
+
+static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
+{
+    return _PPC_intack_read(addr);
+}
+
+static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
+{
+    return _PPC_intack_read(addr);
+}
+
+static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
+{
+    return _PPC_intack_read(addr);
+}
+
+static CPUWriteMemoryFunc * const PPC_intack_write[] = {
+    &_PPC_intack_write,
+    &_PPC_intack_write,
+    &_PPC_intack_write,
+};
+
+static CPUReadMemoryFunc * const PPC_intack_read[] = {
+    &PPC_intack_readb,
+    &PPC_intack_readw,
+    &PPC_intack_readl,
+};
+
+/* PowerPC control and status registers */
+#if 0 // Not used
+static struct {
+    /* IDs */
+    uint32_t veni_devi;
+    uint32_t revi;
+    /* Control and status */
+    uint32_t gcsr;
+    uint32_t xcfr;
+    uint32_t ct32;
+    uint32_t mcsr;
+    /* General purpose registers */
+    uint32_t gprg[6];
+    /* Exceptions */
+    uint32_t feen;
+    uint32_t fest;
+    uint32_t fema;
+    uint32_t fecl;
+    uint32_t eeen;
+    uint32_t eest;
+    uint32_t eecl;
+    uint32_t eeint;
+    uint32_t eemck0;
+    uint32_t eemck1;
+    /* Error diagnostic */
+} XCSR;
+
+static void PPC_XCSR_writeb (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+           value);
+}
+
+static void PPC_XCSR_writew (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+           value);
+}
+
+static void PPC_XCSR_writel (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
+           value);
+}
+
+static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t retval = 0;
+
+    printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
+           retval);
+
+    return retval;
+}
+
+static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t retval = 0;
+
+    printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
+           retval);
+
+    return retval;
+}
+
+static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t retval = 0;
+
+    printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
+           retval);
+
+    return retval;
+}
+
+static CPUWriteMemoryFunc * const PPC_XCSR_write[] = {
+    &PPC_XCSR_writeb,
+    &PPC_XCSR_writew,
+    &PPC_XCSR_writel,
+};
+
+static CPUReadMemoryFunc * const PPC_XCSR_read[] = {
+    &PPC_XCSR_readb,
+    &PPC_XCSR_readw,
+    &PPC_XCSR_readl,
+};
+#endif
+
+/* Fake super-io ports for PREP platform (Intel 82378ZB) */
+typedef struct sysctrl_t {
+    qemu_irq reset_irq;
+    M48t59State *nvram;
+    uint8_t state;
+    uint8_t syscontrol;
+    uint8_t fake_io[2];
+    int contiguous_map;
+    int endian;
+} sysctrl_t;
+
+enum {
+    STATE_HARDFILE = 0x01,
+};
+
+static sysctrl_t *sysctrl;
+
+static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE,
+                   val);
+    sysctrl->fake_io[addr - 0x0398] = val;
+}
+
+static uint32_t PREP_io_read (void *opaque, uint32_t addr)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE,
+                   sysctrl->fake_io[addr - 0x0398]);
+    return sysctrl->fake_io[addr - 0x0398];
+}
+
+static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n",
+                   addr - PPC_IO_BASE, val);
+    switch (addr) {
+    case 0x0092:
+        /* Special port 92 */
+        /* Check soft reset asked */
+        if (val & 0x01) {
+            qemu_irq_raise(sysctrl->reset_irq);
+        } else {
+            qemu_irq_lower(sysctrl->reset_irq);
+        }
+        /* Check LE mode */
+        if (val & 0x02) {
+            sysctrl->endian = 1;
+        } else {
+            sysctrl->endian = 0;
+        }
+        break;
+    case 0x0800:
+        /* Motorola CPU configuration register : read-only */
+        break;
+    case 0x0802:
+        /* Motorola base module feature register : read-only */
+        break;
+    case 0x0803:
+        /* Motorola base module status register : read-only */
+        break;
+    case 0x0808:
+        /* Hardfile light register */
+        if (val & 1)
+            sysctrl->state |= STATE_HARDFILE;
+        else
+            sysctrl->state &= ~STATE_HARDFILE;
+        break;
+    case 0x0810:
+        /* Password protect 1 register */
+        if (sysctrl->nvram != NULL)
+            m48t59_toggle_lock(sysctrl->nvram, 1);
+        break;
+    case 0x0812:
+        /* Password protect 2 register */
+        if (sysctrl->nvram != NULL)
+            m48t59_toggle_lock(sysctrl->nvram, 2);
+        break;
+    case 0x0814:
+        /* L2 invalidate register */
+        //        tlb_flush(first_cpu, 1);
+        break;
+    case 0x081C:
+        /* system control register */
+        sysctrl->syscontrol = val & 0x0F;
+        break;
+    case 0x0850:
+        /* I/O map type register */
+        sysctrl->contiguous_map = val & 0x01;
+        break;
+    default:
+        printf("ERROR: unaffected IO port write: %04" PRIx32
+               " => %02" PRIx32"\n", addr, val);
+        break;
+    }
+}
+
+static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
+{
+    sysctrl_t *sysctrl = opaque;
+    uint32_t retval = 0xFF;
+
+    switch (addr) {
+    case 0x0092:
+        /* Special port 92 */
+        retval = 0x00;
+        break;
+    case 0x0800:
+        /* Motorola CPU configuration register */
+        retval = 0xEF; /* MPC750 */
+        break;
+    case 0x0802:
+        /* Motorola Base module feature register */
+        retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
+        break;
+    case 0x0803:
+        /* Motorola base module status register */
+        retval = 0xE0; /* Standard MPC750 */
+        break;
+    case 0x080C:
+        /* Equipment present register:
+         *  no L2 cache
+         *  no upgrade processor
+         *  no cards in PCI slots
+         *  SCSI fuse is bad
+         */
+        retval = 0x3C;
+        break;
+    case 0x0810:
+        /* Motorola base module extended feature register */
+        retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
+        break;
+    case 0x0814:
+        /* L2 invalidate: don't care */
+        break;
+    case 0x0818:
+        /* Keylock */
+        retval = 0x00;
+        break;
+    case 0x081C:
+        /* system control register
+         * 7 - 6 / 1 - 0: L2 cache enable
+         */
+        retval = sysctrl->syscontrol;
+        break;
+    case 0x0823:
+        /* */
+        retval = 0x03; /* no L2 cache */
+        break;
+    case 0x0850:
+        /* I/O map type register */
+        retval = sysctrl->contiguous_map;
+        break;
+    default:
+        printf("ERROR: unaffected IO port: %04" PRIx32 " read\n", addr);
+        break;
+    }
+    PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n",
+                   addr - PPC_IO_BASE, retval);
+
+    return retval;
+}
+
+static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl,
+                                                 target_phys_addr_t addr)
+{
+    if (sysctrl->contiguous_map == 0) {
+        /* 64 KB contiguous space for IOs */
+        addr &= 0xFFFF;
+    } else {
+        /* 8 MB non-contiguous space for IOs */
+        addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
+    }
+
+    return addr;
+}
+
+static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    addr = prep_IO_address(sysctrl, addr);
+    cpu_outb(addr, value);
+}
+
+static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
+{
+    sysctrl_t *sysctrl = opaque;
+    uint32_t ret;
+
+    addr = prep_IO_address(sysctrl, addr);
+    ret = cpu_inb(addr);
+
+    return ret;
+}
+
+static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    addr = prep_IO_address(sysctrl, addr);
+    PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
+    cpu_outw(addr, value);
+}
+
+static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
+{
+    sysctrl_t *sysctrl = opaque;
+    uint32_t ret;
+
+    addr = prep_IO_address(sysctrl, addr);
+    ret = cpu_inw(addr);
+    PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
+
+    return ret;
+}
+
+static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    sysctrl_t *sysctrl = opaque;
+
+    addr = prep_IO_address(sysctrl, addr);
+    PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
+    cpu_outl(addr, value);
+}
+
+static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
+{
+    sysctrl_t *sysctrl = opaque;
+    uint32_t ret;
+
+    addr = prep_IO_address(sysctrl, addr);
+    ret = cpu_inl(addr);
+    PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
+
+    return ret;
+}
+
+static CPUWriteMemoryFunc * const PPC_prep_io_write[] = {
+    &PPC_prep_io_writeb,
+    &PPC_prep_io_writew,
+    &PPC_prep_io_writel,
+};
+
+static CPUReadMemoryFunc * const PPC_prep_io_read[] = {
+    &PPC_prep_io_readb,
+    &PPC_prep_io_readw,
+    &PPC_prep_io_readl,
+};
+
+#define NVRAM_SIZE        0x2000
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
+
+/* PowerPC PREP hardware initialisation */
+static void ppc_prep_init (ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    CPUState *env = NULL;
+    char *filename;
+    nvram_t nvram;
+    M48t59State *m48t59;
+    int PPC_io_memory;
+    int linux_boot, i, nb_nics1, bios_size;
+    ram_addr_t ram_offset, bios_offset;
+    uint32_t kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    PCIBus *pci_bus;
+    qemu_irq *i8259;
+    qemu_irq *cpu_exit_irq;
+    int ppc_boot_device;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *fd[MAX_FD];
+
+    sysctrl = qemu_mallocz(sizeof(sysctrl_t));
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* init CPUs */
+    if (cpu_model == NULL)
+        cpu_model = "602";
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        if (env->flags & POWERPC_FLAG_RTC_CLK) {
+            /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
+            cpu_ppc_tb_init(env, 7812500UL);
+        } else {
+            /* Set time-base frequency to 100 Mhz */
+            cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+        }
+        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+    }
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_prep.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate and load BIOS */
+    bios_offset = qemu_ram_alloc(NULL, "ppc_prep.bios", BIOS_SIZE);
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+        target_phys_addr_t bios_addr;
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        bios_addr = (uint32_t)(-bios_size);
+        cpu_register_physical_memory(bios_addr, bios_size,
+                                     bios_offset | IO_MEM_ROM);
+        bios_size = load_image_targphys(filename, bios_addr, bios_size);
+    }
+    if (bios_size < 0 || bios_size > BIOS_SIZE) {
+        hw_error("qemu: could not load PPC PREP bios '%s'\n", bios_name);
+    }
+    if (filename) {
+        qemu_free(filename);
+    }
+
+    if (linux_boot) {
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                          ram_size - kernel_base);
+        if (kernel_size < 0) {
+            hw_error("qemu: could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                hw_error("qemu: could not load initial ram disk '%s'\n",
+                          initrd_filename);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        ppc_boot_device = 'm';
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        ppc_boot_device = '\0';
+        /* For now, OHW cannot boot from the network. */
+        for (i = 0; boot_device[i] != '\0'; i++) {
+            if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {
+                ppc_boot_device = boot_device[i];
+                break;
+            }
+        }
+        if (ppc_boot_device == '\0') {
+            fprintf(stderr, "No valid boot device for Mac99 machine\n");
+            exit(1);
+        }
+    }
+
+    isa_mem_base = 0xc0000000;
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        hw_error("Only 6xx bus is supported on PREP machine\n");
+    }
+    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+    pci_bus = pci_prep_init(i8259);
+    /* Hmm, prep has no pci-isa bridge ??? */
+    isa_bus_new(NULL);
+    isa_bus_irqs(i8259);
+    //    pci_bus = i440fx_init();
+    /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
+    PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
+                                           PPC_prep_io_write, sysctrl,
+                                           DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
+
+    /* init basic PC hardware */
+    pci_vga_init(pci_bus);
+    //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
+    //    pit = pit_init(0x40, 0);
+    rtc_init(2000, NULL);
+
+    if (serial_hds[0])
+        serial_isa_init(0, serial_hds[0]);
+    nb_nics1 = nb_nics;
+    if (nb_nics1 > NE2000_NB_MAX)
+        nb_nics1 = NE2000_NB_MAX;
+    for(i = 0; i < nb_nics1; i++) {
+        if (nd_table[i].model == NULL) {
+	    nd_table[i].model = qemu_strdup("ne2k_isa");
+        }
+        if (strcmp(nd_table[i].model, "ne2k_isa") == 0) {
+            isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
+        } else {
+            pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+        }
+    }
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+    for(i = 0; i < MAX_IDE_BUS; i++) {
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                     hd[2 * i],
+		     hd[2 * i + 1]);
+    }
+    isa_create_simple("i8042");
+
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(1, cpu_exit_irq);
+
+    //    SB16_init();
+
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(fd);
+
+    /* Register speaker port */
+    register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
+    register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
+    /* Register fake IO ports for PREP */
+    sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
+    register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
+    register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
+    /* System control ports */
+    register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
+    register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
+    register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
+    register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
+    /* PCI intack location */
+    PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
+                                           PPC_intack_write, NULL,
+                                           DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
+    /* PowerPC control and status register group */
+#if 0
+    PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write,
+                                           NULL, DEVICE_LITTLE_ENDIAN);
+    cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
+#endif
+
+    if (usb_enabled) {
+        usb_ohci_init_pci(pci_bus, -1);
+    }
+
+    m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
+    if (m48t59 == NULL)
+        return;
+    sysctrl->nvram = m48t59;
+
+    /* Initialise NVRAM */
+    nvram.opaque = m48t59;
+    nvram.read_fn = &m48t59_read;
+    nvram.write_fn = &m48t59_write;
+    PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, ppc_boot_device,
+                         kernel_base, kernel_size,
+                         kernel_cmdline,
+                         initrd_base, initrd_size,
+                         /* XXX: need an option to load a NVRAM image */
+                         0,
+                         graphic_width, graphic_height, graphic_depth);
+
+    /* Special port to get debug messages from Open-Firmware */
+    register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
+}
+
+static QEMUMachine prep_machine = {
+    .name = "prep",
+    .desc = "PowerPC PREP platform",
+    .init = ppc_prep_init,
+    .max_cpus = MAX_CPUS,
+};
+
+static void prep_machine_init(void)
+{
+    qemu_register_machine(&prep_machine);
+}
+
+machine_init(prep_machine_init);
diff --git a/qemu-0.15.x/hw/ppce500_mpc8544ds.c b/qemu-0.15.x/hw/ppce500_mpc8544ds.c
new file mode 100644
index 0000000..b739ce2
--- /dev/null
+++ b/qemu-0.15.x/hw/ppce500_mpc8544ds.c
@@ -0,0 +1,374 @@
+/*
+ * Qemu PowerPC MPC8544DS board emualtion
+ *
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu,     <yu.liu at freescale.com>
+ *
+ * This file is derived from hw/ppc440_bamboo.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of  the GNU General  Public License as published by
+ * the Free Software Foundation;  either version 2 of the  License, or
+ * (at your option) any later version.
+ */
+
+#include <dirent.h>
+
+#include "config.h"
+#include "qemu-common.h"
+#include "net.h"
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "boards.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+#include "openpic.h"
+#include "ppc.h"
+#include "loader.h"
+#include "elf.h"
+#include "sysbus.h"
+
+#define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
+#define UIMAGE_LOAD_BASE           0
+#define DTC_LOAD_PAD               0x500000
+#define DTC_PAD_MASK               0xFFFFF
+#define INITRD_LOAD_PAD            0x2000000
+#define INITRD_PAD_MASK            0xFFFFFF
+
+#define RAM_SIZES_ALIGN            (64UL << 20)
+
+#define MPC8544_CCSRBAR_BASE       0xE0000000
+#define MPC8544_MPIC_REGS_BASE     (MPC8544_CCSRBAR_BASE + 0x40000)
+#define MPC8544_SERIAL0_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4500)
+#define MPC8544_SERIAL1_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4600)
+#define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + 0x8000)
+#define MPC8544_PCI_REGS_SIZE      0x1000
+#define MPC8544_PCI_IO             0xE1000000
+#define MPC8544_PCI_IOLEN          0x10000
+#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000)
+
+struct boot_info
+{
+    uint32_t dt_base;
+    uint32_t entry;
+};
+
+#ifdef CONFIG_FDT
+static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
+{
+    uint32_t cell;
+    int ret;
+
+    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
+    if (ret < 0) {
+        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
+        goto out;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
+                                prop, cell);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't set guest /cpus/PowerPC,8544 at 0/%s\n", prop);
+        goto out;
+    }
+
+out:
+    return ret;
+}
+#endif
+
+static int mpc8544_load_device_tree(CPUState *env,
+                                    target_phys_addr_t addr,
+                                    uint32_t ramsize,
+                                    target_phys_addr_t initrd_base,
+                                    target_phys_addr_t initrd_size,
+                                    const char *kernel_cmdline)
+{
+    int ret = -1;
+#ifdef CONFIG_FDT
+    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
+    char *filename;
+    int fdt_size;
+    void *fdt;
+    uint8_t hypercall[16];
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+    if (!filename) {
+        goto out;
+    }
+    fdt = load_device_tree(filename, &fdt_size);
+    qemu_free(filename);
+    if (fdt == NULL) {
+        goto out;
+    }
+
+    /* Manipulate device tree in memory. */
+    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+                               sizeof(mem_reg_property));
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /memory/reg\n");
+
+    if (initrd_size) {
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                        initrd_base);
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+        }
+
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                        (initrd_base + initrd_size));
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        }
+    }
+
+    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                      kernel_cmdline);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+
+    if (kvm_enabled()) {
+        struct dirent *dirp;
+        DIR *dp;
+        char buf[128];
+
+        if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) {
+            printf("Can't open directory /proc/device-tree/cpus/\n");
+            ret = -1;
+            goto out;
+        }
+
+        buf[0] = '\0';
+        while ((dirp = readdir(dp)) != NULL) {
+            if (strncmp(dirp->d_name, "PowerPC", 7) == 0) {
+                snprintf(buf, 128, "/cpus/%s", dirp->d_name);
+                break;
+            }
+        }
+        closedir(dp);
+        if (buf[0] == '\0') {
+            printf("Unknow host!\n");
+            ret = -1;
+            goto out;
+        }
+
+        mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
+        mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
+
+        /* indicate KVM hypercall interface */
+        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
+                                    "linux,kvm");
+        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
+        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
+                             hypercall, sizeof(hypercall));
+    } else {
+        const uint32_t freq = 400000000;
+
+        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
+                                  "clock-frequency", freq);
+        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
+                                  "timebase-frequency", freq);
+    }
+
+    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+    qemu_free(fdt);
+
+out:
+#endif
+
+    return ret;
+}
+
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return (ffs(size >> 10) - 1) >> 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
+    target_phys_addr_t size;
+
+    size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = va & TARGET_PAGE_MASK;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static void mpc8544ds_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(env);
+
+    /* Set initial guest state. */
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = bi->dt_base;
+    env->nip = bi->entry;
+    mmubooke_create_initial_mapping(env, 0, 0);
+}
+
+static void mpc8544ds_init(ram_addr_t ram_size,
+                         const char *boot_device,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename,
+                         const char *cpu_model)
+{
+    PCIBus *pci_bus;
+    CPUState *env;
+    uint64_t elf_entry;
+    uint64_t elf_lowaddr;
+    target_phys_addr_t entry=0;
+    target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
+    target_long kernel_size=0;
+    target_ulong dt_base = 0;
+    target_ulong initrd_base = 0;
+    target_long initrd_size=0;
+    int i=0;
+    unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
+    qemu_irq *irqs, *mpic;
+    DeviceState *dev;
+    struct boot_info *boot_info;
+
+    /* Setup CPU */
+    if (cpu_model == NULL) {
+        cpu_model = "e500v2_v30";
+    }
+
+    env = cpu_ppc_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    /* XXX register timer? */
+    ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* Register reset handler */
+    qemu_register_reset(mpc8544ds_cpu_reset, env);
+
+    /* Fixup Memory size on a alignment boundary */
+    ram_size &= ~(RAM_SIZES_ALIGN - 1);
+
+    /* Register Memory */
+    cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL,
+                                 "mpc8544ds.ram", ram_size));
+
+    /* MPIC */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+    irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
+    irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
+    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
+
+    /* Serial */
+    if (serial_hds[0]) {
+        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
+    }
+
+    if (serial_hds[1]) {
+        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
+    }
+
+    /* General Utility device */
+    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
+
+    /* PCI */
+    dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
+                                mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
+                                mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
+                                NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (!pci_bus)
+        printf("couldn't create PCI controller!\n");
+
+    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
+
+    if (pci_bus) {
+        /* Register network interfaces. */
+        for (i = 0; i < nb_nics; i++) {
+            pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
+        }
+    }
+
+    /* Load kernel. */
+    if (kernel_filename) {
+        kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+        if (kernel_size < 0) {
+            kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                                   &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+            entry = elf_entry;
+            loadaddr = elf_lowaddr;
+        }
+        /* XXX try again as binary */
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* Load initrd. */
+    if (initrd_filename) {
+        initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                          ram_size - initrd_base);
+
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    initrd_filename);
+            exit(1);
+        }
+    }
+
+    boot_info = qemu_mallocz(sizeof(struct boot_info));
+
+    /* If we're loading a kernel directly, we must load the device tree too. */
+    if (kernel_filename) {
+#ifndef CONFIG_FDT
+        cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
+#endif
+        dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+        if (mpc8544_load_device_tree(env, dt_base, ram_size,
+                    initrd_base, initrd_size, kernel_cmdline) < 0) {
+            fprintf(stderr, "couldn't load device tree\n");
+            exit(1);
+        }
+
+        boot_info->entry = entry;
+        boot_info->dt_base = dt_base;
+    }
+    env->load_info = boot_info;
+
+    if (kvm_enabled()) {
+        kvmppc_init();
+    }
+}
+
+static QEMUMachine mpc8544ds_machine = {
+    .name = "mpc8544ds",
+    .desc = "mpc8544ds",
+    .init = mpc8544ds_init,
+};
+
+static void mpc8544ds_machine_init(void)
+{
+    qemu_register_machine(&mpc8544ds_machine);
+}
+
+machine_init(mpc8544ds_machine_init);
diff --git a/qemu-0.15.x/hw/ppce500_pci.c b/qemu-0.15.x/hw/ppce500_pci.c
new file mode 100644
index 0000000..fc11af4
--- /dev/null
+++ b/qemu-0.15.x/hw/ppce500_pci.c
@@ -0,0 +1,328 @@
+/*
+ * QEMU PowerPC E500 embedded processors pci controller emulation
+ *
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu,     <yu.liu at freescale.com>
+ *
+ * This file is derived from hw/ppc4xx_pci.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of  the GNU General  Public License as published by
+ * the Free Software Foundation;  either version 2 of the  License, or
+ * (at your option) any later version.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "bswap.h"
+
+#ifdef DEBUG_PCI
+#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
+#else
+#define pci_debug(fmt, ...)
+#endif
+
+#define PCIE500_CFGADDR       0x0
+#define PCIE500_CFGDATA       0x4
+#define PCIE500_REG_BASE      0xC00
+#define PCIE500_ALL_SIZE      0x1000
+#define PCIE500_REG_SIZE      (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
+
+#define PPCE500_PCI_CONFIG_ADDR         0x0
+#define PPCE500_PCI_CONFIG_DATA         0x4
+#define PPCE500_PCI_INTACK              0x8
+
+#define PPCE500_PCI_OW1                 (0xC20 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW2                 (0xC40 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW3                 (0xC60 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW4                 (0xC80 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW3                 (0xDA0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW2                 (0xDC0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW1                 (0xDE0 - PCIE500_REG_BASE)
+
+#define PPCE500_PCI_GASKET_TIMR         (0xE20 - PCIE500_REG_BASE)
+
+#define PCI_POTAR               0x0
+#define PCI_POTEAR              0x4
+#define PCI_POWBAR              0x8
+#define PCI_POWAR               0x10
+
+#define PCI_PITAR               0x0
+#define PCI_PIWBAR              0x8
+#define PCI_PIWBEAR             0xC
+#define PCI_PIWAR               0x10
+
+#define PPCE500_PCI_NR_POBS     5
+#define PPCE500_PCI_NR_PIBS     3
+
+struct  pci_outbound {
+    uint32_t potar;
+    uint32_t potear;
+    uint32_t powbar;
+    uint32_t powar;
+};
+
+struct pci_inbound {
+    uint32_t pitar;
+    uint32_t piwbar;
+    uint32_t piwbear;
+    uint32_t piwar;
+};
+
+struct PPCE500PCIState {
+    PCIHostState pci_state;
+    struct pci_outbound pob[PPCE500_PCI_NR_POBS];
+    struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
+    uint32_t gasket_time;
+    qemu_irq irq[4];
+    /* mmio maps */
+    int cfgaddr;
+    int cfgdata;
+    int reg;
+};
+
+typedef struct PPCE500PCIState PPCE500PCIState;
+
+static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+    uint32_t value = 0;
+
+    win = addr & 0xfe0;
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+        switch (addr & 0xC) {
+        case PCI_POTAR: value = pci->pob[(addr >> 5) & 0x7].potar; break;
+        case PCI_POTEAR: value = pci->pob[(addr >> 5) & 0x7].potear; break;
+        case PCI_POWBAR: value = pci->pob[(addr >> 5) & 0x7].powbar; break;
+        case PCI_POWAR: value = pci->pob[(addr >> 5) & 0x7].powar; break;
+        default: break;
+        }
+        break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+        switch (addr & 0xC) {
+        case PCI_PITAR: value = pci->pib[(addr >> 5) & 0x3].pitar; break;
+        case PCI_PIWBAR: value = pci->pib[(addr >> 5) & 0x3].piwbar; break;
+        case PCI_PIWBEAR: value = pci->pib[(addr >> 5) & 0x3].piwbear; break;
+        case PCI_PIWAR: value = pci->pib[(addr >> 5) & 0x3].piwar; break;
+        default: break;
+        };
+        break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+        value = pci->gasket_time;
+        break;
+
+    default:
+        break;
+    }
+
+    pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__,
+              win, addr, value);
+    return value;
+}
+
+static CPUReadMemoryFunc * const e500_pci_reg_read[] = {
+    &pci_reg_read4,
+    &pci_reg_read4,
+    &pci_reg_read4,
+};
+
+static void pci_reg_write4(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+
+    win = addr & 0xfe0;
+
+    pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n",
+              __func__, value, win, addr);
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+        switch (addr & 0xC) {
+        case PCI_POTAR: pci->pob[(addr >> 5) & 0x7].potar = value; break;
+        case PCI_POTEAR: pci->pob[(addr >> 5) & 0x7].potear = value; break;
+        case PCI_POWBAR: pci->pob[(addr >> 5) & 0x7].powbar = value; break;
+        case PCI_POWAR: pci->pob[(addr >> 5) & 0x7].powar = value; break;
+        default: break;
+        };
+        break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+        switch (addr & 0xC) {
+        case PCI_PITAR: pci->pib[(addr >> 5) & 0x3].pitar = value; break;
+        case PCI_PIWBAR: pci->pib[(addr >> 5) & 0x3].piwbar = value; break;
+        case PCI_PIWBEAR: pci->pib[(addr >> 5) & 0x3].piwbear = value; break;
+        case PCI_PIWAR: pci->pib[(addr >> 5) & 0x3].piwar = value; break;
+        default: break;
+        };
+        break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+        pci->gasket_time = value;
+        break;
+
+    default:
+        break;
+    };
+}
+
+static CPUWriteMemoryFunc * const e500_pci_reg_write[] = {
+    &pci_reg_write4,
+    &pci_reg_write4,
+    &pci_reg_write4,
+};
+
+static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int devno = pci_dev->devfn >> 3, ret = 0;
+
+    switch (devno) {
+        /* Two PCI slot */
+        case 0x11:
+        case 0x12:
+            ret = (irq_num + devno - 0x10) % 4;
+            break;
+        default:
+            printf("Error:%s:unknown dev number\n", __func__);
+    }
+
+    pci_debug("%s: devfn %x irq %d -> %d  devno:%x\n", __func__,
+           pci_dev->devfn, irq_num, ret, devno);
+
+    return ret;
+}
+
+static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level);
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static const VMStateDescription vmstate_pci_outbound = {
+    .name = "pci_outbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(potar, struct pci_outbound),
+        VMSTATE_UINT32(potear, struct pci_outbound),
+        VMSTATE_UINT32(powbar, struct pci_outbound),
+        VMSTATE_UINT32(powar, struct pci_outbound),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_inbound = {
+    .name = "pci_inbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pitar, struct pci_inbound),
+        VMSTATE_UINT32(piwbar, struct pci_inbound),
+        VMSTATE_UINT32(piwbear, struct pci_inbound),
+        VMSTATE_UINT32(piwar, struct pci_inbound),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ppce500_pci = {
+    .name = "ppce500_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
+                             vmstate_pci_outbound, struct pci_outbound),
+        VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
+                             vmstate_pci_outbound, struct pci_inbound),
+        VMSTATE_UINT32(gasket_time, PPCE500PCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+
+    cpu_register_physical_memory(base + PCIE500_CFGADDR, 4, s->cfgaddr);
+    cpu_register_physical_memory(base + PCIE500_CFGDATA, 4, s->cfgdata);
+    cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
+                                 s->reg);
+}
+
+static int e500_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *h;
+    PPCE500PCIState *s;
+    PCIBus *b;
+    int i;
+
+    h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
+                         mpc85xx_pci_map_irq, s->irq, PCI_DEVFN(0x11, 0), 4);
+    s->pci_state.bus = b;
+
+    pci_create_simple(b, 0, "e500-host-bridge");
+
+    s->cfgaddr = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN);
+    s->cfgdata = pci_host_data_register_mmio(&s->pci_state,
+                                             DEVICE_LITTLE_ENDIAN);
+    s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s,
+                                    DEVICE_BIG_ENDIAN);
+    sysbus_init_mmio_cb(dev, PCIE500_ALL_SIZE, e500_pci_map);
+
+    return 0;
+}
+
+static PCIDeviceInfo e500_host_bridge_info = {
+    .qdev.name    = "e500-host-bridge",
+    .qdev.desc    = "Host bridge",
+    .qdev.size    = sizeof(PCIDevice),
+    .vendor_id    = PCI_VENDOR_ID_FREESCALE,
+    .device_id    = PCI_DEVICE_ID_MPC8533E,
+    .class_id     = PCI_CLASS_PROCESSOR_POWERPC,
+};
+
+static SysBusDeviceInfo e500_pcihost_info = {
+    .init         = e500_pcihost_initfn,
+    .qdev.name    = "e500-pcihost",
+    .qdev.size    = sizeof(PPCE500PCIState),
+    .qdev.vmsd    = &vmstate_ppce500_pci,
+};
+
+static void e500_pci_register(void)
+{
+    sysbus_register_withprop(&e500_pcihost_info);
+    pci_qdev_register(&e500_host_bridge_info);
+}
+device_init(e500_pci_register);
diff --git a/qemu-0.15.x/hw/prep_pci.c b/qemu-0.15.x/hw/prep_pci.c
new file mode 100644
index 0000000..f88b825
--- /dev/null
+++ b/qemu-0.15.x/hw/prep_pci.c
@@ -0,0 +1,144 @@
+/*
+ * QEMU PREP PCI host
+ *
+ * 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 "hw.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "prep_pci.h"
+
+typedef PCIHostState PREPPCIState;
+
+static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
+{
+    int i;
+
+    for(i = 0; i < 11; i++) {
+        if ((addr & (1 << (11 + i))) != 0)
+            break;
+    }
+    return (addr & 0x7ff) |  (i << 11);
+}
+
+static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PREPPCIState *s = opaque;
+    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+}
+
+static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PREPPCIState *s = opaque;
+    val = bswap16(val);
+    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
+}
+
+static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PREPPCIState *s = opaque;
+    val = bswap32(val);
+    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+}
+
+static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
+{
+    PREPPCIState *s = opaque;
+    uint32_t val;
+    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
+    return val;
+}
+
+static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
+{
+    PREPPCIState *s = opaque;
+    uint32_t val;
+    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
+    val = bswap16(val);
+    return val;
+}
+
+static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
+{
+    PREPPCIState *s = opaque;
+    uint32_t val;
+    val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
+    val = bswap32(val);
+    return val;
+}
+
+static CPUWriteMemoryFunc * const PPC_PCIIO_write[] = {
+    &PPC_PCIIO_writeb,
+    &PPC_PCIIO_writew,
+    &PPC_PCIIO_writel,
+};
+
+static CPUReadMemoryFunc * const PPC_PCIIO_read[] = {
+    &PPC_PCIIO_readb,
+    &PPC_PCIIO_readw,
+    &PPC_PCIIO_readl,
+};
+
+static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return (irq_num + (pci_dev->devfn >> 3)) & 1;
+}
+
+static void prep_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
+}
+
+PCIBus *pci_prep_init(qemu_irq *pic)
+{
+    PREPPCIState *s;
+    PCIDevice *d;
+    int PPC_io_memory;
+
+    s = qemu_mallocz(sizeof(PREPPCIState));
+    s->bus = pci_register_bus(NULL, "pci",
+                              prep_set_irq, prep_map_irq, pic, 0, 4);
+
+    pci_host_conf_register_ioport(0xcf8, s);
+
+    pci_host_data_register_ioport(0xcfc, s);
+
+    PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read,
+                                           PPC_PCIIO_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
+
+    /* PCI host bridge */
+    d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
+                            sizeof(PCIDevice), 0, NULL, NULL);
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
+    d->config[0x08] = 0x00; // revision
+    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+
+    return s->bus;
+}
diff --git a/qemu-0.15.x/hw/prep_pci.h b/qemu-0.15.x/hw/prep_pci.h
new file mode 100644
index 0000000..cd68512
--- /dev/null
+++ b/qemu-0.15.x/hw/prep_pci.h
@@ -0,0 +1,8 @@
+#ifndef QEMU_PREP_PCI_H
+#define QEMU_PREP_PCI_H
+
+#include "qemu-common.h"
+
+PCIBus *pci_prep_init(qemu_irq *pic);
+
+#endif
diff --git a/qemu-0.15.x/hw/primecell.h b/qemu-0.15.x/hw/primecell.h
new file mode 100644
index 0000000..de7d6f2
--- /dev/null
+++ b/qemu-0.15.x/hw/primecell.h
@@ -0,0 +1,18 @@
+#ifndef PRIMECELL_H
+#define PRIMECELL_H
+
+/* Declarations for ARM PrimeCell based periperals.  */
+/* Also includes some devices that are currently only used by the
+   ARM boards.  */
+
+/* pl080.c */
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
+
+/* arm_sysctl.c */
+void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id);
+
+/* arm_sysctl GPIO lines */
+#define ARM_SYSCTL_GPIO_MMC_WPROT 0
+#define ARM_SYSCTL_GPIO_MMC_CARDIN 1
+
+#endif
diff --git a/qemu-0.15.x/hw/ps2.c b/qemu-0.15.x/hw/ps2.c
new file mode 100644
index 0000000..91b73e0
--- /dev/null
+++ b/qemu-0.15.x/hw/ps2.c
@@ -0,0 +1,628 @@
+/*
+ * QEMU PS/2 keyboard/mouse emulation
+ *
+ * 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 "hw.h"
+#include "ps2.h"
+#include "console.h"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+
+/* debug PC keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
+#define KBD_CMD_ECHO     	0xEE
+#define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
+#define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
+#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
+#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
+#define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
+#define KBD_CMD_RESET		0xFF	/* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR		0xAA	/* Power on reset */
+#define KBD_REPLY_ID		0xAB	/* Keyboard ID */
+#define KBD_REPLY_ACK		0xFA	/* Command ACK */
+#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
+#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
+#define AUX_SET_RES		0xE8	/* Set resolution */
+#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
+#define AUX_SET_STREAM		0xEA	/* Set stream mode */
+#define AUX_POLL		0xEB	/* Poll */
+#define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
+#define AUX_SET_WRAP		0xEE	/* Set wrap mode */
+#define AUX_SET_REMOTE		0xF0	/* Set remote mode */
+#define AUX_GET_TYPE		0xF2	/* Get type */
+#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
+#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
+#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
+#define AUX_SET_DEFAULT		0xF6
+#define AUX_RESET		0xFF	/* Reset aux device */
+#define AUX_ACK			0xFA	/* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE     0x40
+#define MOUSE_STATUS_ENABLED    0x20
+#define MOUSE_STATUS_SCALE21    0x10
+
+#define PS2_QUEUE_SIZE 256
+
+typedef struct {
+    uint8_t data[PS2_QUEUE_SIZE];
+    int rptr, wptr, count;
+} PS2Queue;
+
+typedef struct {
+    PS2Queue queue;
+    int32_t write_cmd;
+    void (*update_irq)(void *, int);
+    void *update_arg;
+} PS2State;
+
+typedef struct {
+    PS2State common;
+    int scan_enabled;
+    /* Qemu uses translated PC scancodes internally.  To avoid multiple
+       conversions we do the translation (if any) in the PS/2 emulation
+       not the keyboard controller.  */
+    int translate;
+    int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
+} PS2KbdState;
+
+typedef struct {
+    PS2State common;
+    uint8_t mouse_status;
+    uint8_t mouse_resolution;
+    uint8_t mouse_sample_rate;
+    uint8_t mouse_wrap;
+    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
+    uint8_t mouse_detect_state;
+    int mouse_dx; /* current values, needed for 'poll' mode */
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons;
+} PS2MouseState;
+
+/* Table to convert from PC scancodes to raw scancodes.  */
+static const unsigned char ps2_raw_keycode[128] = {
+  0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
+ 11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
+114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+};
+static const unsigned char ps2_raw_keycode_set3[128] = {
+  0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
+ 47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
+114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+};
+
+void ps2_queue(void *opaque, int b)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q = &s->queue;
+
+    if (q->count >= PS2_QUEUE_SIZE)
+        return;
+    q->data[q->wptr] = b;
+    if (++q->wptr == PS2_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    s->update_irq(s->update_arg, 1);
+}
+
+/*
+   keycode is expressed as follow:
+   bit 7    - 0 key pressed, 1 = key released
+   bits 6-0 - translated scancode set 2
+ */
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+    PS2KbdState *s = opaque;
+
+    /* XXX: add support for scancode set 1 */
+    if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
+        if (keycode & 0x80) {
+            ps2_queue(&s->common, 0xf0);
+        }
+        if (s->scancode_set == 2) {
+            keycode = ps2_raw_keycode[keycode & 0x7f];
+        } else if (s->scancode_set == 3) {
+            keycode = ps2_raw_keycode_set3[keycode & 0x7f];
+        }
+      }
+    ps2_queue(&s->common, keycode);
+}
+
+uint32_t ps2_read_data(void *opaque)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q;
+    int val, index;
+
+    q = &s->queue;
+    if (q->count == 0) {
+        /* NOTE: if no data left, we return the last keyboard one
+           (needed for EMM386) */
+        /* XXX: need a timer to do things correctly */
+        index = q->rptr - 1;
+        if (index < 0)
+            index = PS2_QUEUE_SIZE - 1;
+        val = q->data[index];
+    } else {
+        val = q->data[q->rptr];
+        if (++q->rptr == PS2_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+        /* reading deasserts IRQ */
+        s->update_irq(s->update_arg, 0);
+        /* reassert IRQs if data left */
+        s->update_irq(s->update_arg, q->count != 0);
+    }
+    return val;
+}
+
+static void ps2_reset_keyboard(PS2KbdState *s)
+{
+    s->scan_enabled = 1;
+    s->scancode_set = 2;
+    kbd_put_ledstate(0);
+}
+
+void ps2_write_keyboard(void *opaque, int val)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        switch(val) {
+        case 0x00:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case 0x05:
+            ps2_queue(&s->common, KBD_REPLY_RESEND);
+            break;
+        case KBD_CMD_GET_ID:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            /* We emulate a MF2 AT keyboard here */
+            ps2_queue(&s->common, KBD_REPLY_ID);
+            if (s->translate)
+                ps2_queue(&s->common, 0x41);
+            else
+                ps2_queue(&s->common, 0x83);
+            break;
+        case KBD_CMD_ECHO:
+            ps2_queue(&s->common, KBD_CMD_ECHO);
+            break;
+        case KBD_CMD_ENABLE:
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_SCANCODE:
+        case KBD_CMD_SET_LEDS:
+        case KBD_CMD_SET_RATE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_DISABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 0;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_ENABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET:
+            ps2_reset_keyboard(s);
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_queue(&s->common, KBD_REPLY_POR);
+            break;
+        default:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        }
+        break;
+    case KBD_CMD_SCANCODE:
+        if (val == 0) {
+            if (s->scancode_set == 1)
+                ps2_put_keycode(s, 0x43);
+            else if (s->scancode_set == 2)
+                ps2_put_keycode(s, 0x41);
+            else if (s->scancode_set == 3)
+                ps2_put_keycode(s, 0x3f);
+        } else {
+            if (val >= 1 && val <= 3)
+                s->scancode_set = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+        }
+        s->common.write_cmd = -1;
+        break;
+    case KBD_CMD_SET_LEDS:
+        kbd_put_ledstate(val);
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case KBD_CMD_SET_RATE:
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+/* Set the scancode translation mode.
+   0 = raw scancodes.
+   1 = translated scancodes (used by qemu internally).  */
+
+void ps2_keyboard_set_translation(void *opaque, int mode)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+    s->translate = mode;
+}
+
+static void ps2_mouse_send_packet(PS2MouseState *s)
+{
+    unsigned int b;
+    int dx1, dy1, dz1;
+
+    dx1 = s->mouse_dx;
+    dy1 = s->mouse_dy;
+    dz1 = s->mouse_dz;
+    /* XXX: increase range to 8 bits ? */
+    if (dx1 > 127)
+        dx1 = 127;
+    else if (dx1 < -127)
+        dx1 = -127;
+    if (dy1 > 127)
+        dy1 = 127;
+    else if (dy1 < -127)
+        dy1 = -127;
+    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+    ps2_queue(&s->common, b);
+    ps2_queue(&s->common, dx1 & 0xff);
+    ps2_queue(&s->common, dy1 & 0xff);
+    /* extra byte for IMPS/2 or IMEX */
+    switch(s->mouse_type) {
+    default:
+        break;
+    case 3:
+        if (dz1 > 127)
+            dz1 = 127;
+        else if (dz1 < -127)
+                dz1 = -127;
+        ps2_queue(&s->common, dz1 & 0xff);
+        break;
+    case 4:
+        if (dz1 > 7)
+            dz1 = 7;
+        else if (dz1 < -7)
+            dz1 = -7;
+        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+        ps2_queue(&s->common, b);
+        break;
+    }
+
+    /* update deltas */
+    s->mouse_dx -= dx1;
+    s->mouse_dy -= dy1;
+    s->mouse_dz -= dz1;
+}
+
+static void ps2_mouse_event(void *opaque,
+                            int dx, int dy, int dz, int buttons_state)
+{
+    PS2MouseState *s = opaque;
+
+    /* check if deltas are recorded when disabled */
+    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
+        return;
+
+    s->mouse_dx += dx;
+    s->mouse_dy -= dy;
+    s->mouse_dz += dz;
+    /* XXX: SDL sometimes generates nul events: we delete them */
+    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+        s->mouse_buttons == buttons_state)
+	return;
+    s->mouse_buttons = buttons_state;
+
+    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
+        (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
+        for(;;) {
+            /* if not remote, send event. Multiple events are sent if
+               too big deltas */
+            ps2_mouse_send_packet(s);
+            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+                break;
+        }
+    }
+}
+
+void ps2_mouse_fake_event(void *opaque)
+{
+    ps2_mouse_event(opaque, 1, 0, 0, 0);
+}
+
+void ps2_write_mouse(void *opaque, int val)
+{
+    PS2MouseState *s = (PS2MouseState *)opaque;
+#ifdef DEBUG_MOUSE
+    printf("kbd: write mouse 0x%02x\n", val);
+#endif
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        /* mouse command */
+        if (s->mouse_wrap) {
+            if (val == AUX_RESET_WRAP) {
+                s->mouse_wrap = 0;
+                ps2_queue(&s->common, AUX_ACK);
+                return;
+            } else if (val != AUX_RESET) {
+                ps2_queue(&s->common, val);
+                return;
+            }
+        }
+        switch(val) {
+        case AUX_SET_SCALE11:
+            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_SCALE21:
+            s->mouse_status |= MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_STREAM:
+            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_WRAP:
+            s->mouse_wrap = 1;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_REMOTE:
+            s->mouse_status |= MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_TYPE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        case AUX_SET_RES:
+        case AUX_SET_SAMPLE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_SCALE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_status);
+            ps2_queue(&s->common, s->mouse_resolution);
+            ps2_queue(&s->common, s->mouse_sample_rate);
+            break;
+        case AUX_POLL:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_mouse_send_packet(s);
+            break;
+        case AUX_ENABLE_DEV:
+            s->mouse_status |= MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_DISABLE_DEV:
+            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_DEFAULT:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_RESET:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            s->mouse_type = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, 0xaa);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        default:
+            break;
+        }
+        break;
+    case AUX_SET_SAMPLE:
+        s->mouse_sample_rate = val;
+        /* detect IMPS/2 or IMEX */
+        switch(s->mouse_detect_state) {
+        default:
+        case 0:
+            if (val == 200)
+                s->mouse_detect_state = 1;
+            break;
+        case 1:
+            if (val == 100)
+                s->mouse_detect_state = 2;
+            else if (val == 200)
+                s->mouse_detect_state = 3;
+            else
+                s->mouse_detect_state = 0;
+            break;
+        case 2:
+            if (val == 80)
+                s->mouse_type = 3; /* IMPS/2 */
+            s->mouse_detect_state = 0;
+            break;
+        case 3:
+            if (val == 80)
+                s->mouse_type = 4; /* IMEX */
+            s->mouse_detect_state = 0;
+            break;
+        }
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case AUX_SET_RES:
+        s->mouse_resolution = val;
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_common_reset(PS2State *s)
+{
+    PS2Queue *q;
+    s->write_cmd = -1;
+    q = &s->queue;
+    q->rptr = 0;
+    q->wptr = 0;
+    q->count = 0;
+    s->update_irq(s->update_arg, 0);
+}
+
+static void ps2_kbd_reset(void *opaque)
+{
+    PS2KbdState *s = (PS2KbdState *) opaque;
+
+    ps2_common_reset(&s->common);
+    s->scan_enabled = 0;
+    s->translate = 0;
+    s->scancode_set = 0;
+}
+
+static void ps2_mouse_reset(void *opaque)
+{
+    PS2MouseState *s = (PS2MouseState *) opaque;
+
+    ps2_common_reset(&s->common);
+    s->mouse_status = 0;
+    s->mouse_resolution = 0;
+    s->mouse_sample_rate = 0;
+    s->mouse_wrap = 0;
+    s->mouse_type = 0;
+    s->mouse_detect_state = 0;
+    s->mouse_dx = 0;
+    s->mouse_dy = 0;
+    s->mouse_dz = 0;
+    s->mouse_buttons = 0;
+}
+
+static const VMStateDescription vmstate_ps2_common = {
+    .name = "PS2 Common State",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(write_cmd, PS2State),
+        VMSTATE_INT32(queue.rptr, PS2State),
+        VMSTATE_INT32(queue.wptr, PS2State),
+        VMSTATE_INT32(queue.count, PS2State),
+        VMSTATE_BUFFER(queue.data, PS2State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ps2_kbd_post_load(void* opaque, int version_id)
+{
+    PS2KbdState *s = (PS2KbdState*)opaque;
+
+    if (version_id == 2)
+        s->scancode_set=2;
+    return 0;
+}
+
+static const VMStateDescription vmstate_ps2_keyboard = {
+    .name = "ps2kbd",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = ps2_kbd_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
+        VMSTATE_INT32(scan_enabled, PS2KbdState),
+        VMSTATE_INT32(translate, PS2KbdState),
+        VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ps2_mouse = {
+    .name = "ps2mouse",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
+        VMSTATE_UINT8(mouse_status, PS2MouseState),
+        VMSTATE_UINT8(mouse_resolution, PS2MouseState),
+        VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
+        VMSTATE_UINT8(mouse_wrap, PS2MouseState),
+        VMSTATE_UINT8(mouse_type, PS2MouseState),
+        VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
+        VMSTATE_INT32(mouse_dx, PS2MouseState),
+        VMSTATE_INT32(mouse_dy, PS2MouseState),
+        VMSTATE_INT32(mouse_dz, PS2MouseState),
+        VMSTATE_UINT8(mouse_buttons, PS2MouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    s->scancode_set = 2;
+    vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
+    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+    qemu_register_reset(ps2_kbd_reset, s);
+    return s;
+}
+
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
+    qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
+    qemu_register_reset(ps2_mouse_reset, s);
+    return s;
+}
diff --git a/qemu-0.15.x/hw/ps2.h b/qemu-0.15.x/hw/ps2.h
new file mode 100644
index 0000000..32a4231
--- /dev/null
+++ b/qemu-0.15.x/hw/ps2.h
@@ -0,0 +1,9 @@
+/* ps2.c */
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
+void ps2_write_mouse(void *, int val);
+void ps2_write_keyboard(void *, int val);
+uint32_t ps2_read_data(void *);
+void ps2_queue(void *, int b);
+void ps2_keyboard_set_translation(void *opaque, int mode);
+void ps2_mouse_fake_event(void *opaque);
diff --git a/qemu-0.15.x/hw/ptimer.c b/qemu-0.15.x/hw/ptimer.c
new file mode 100644
index 0000000..6f13ce9
--- /dev/null
+++ b/qemu-0.15.x/hw/ptimer.c
@@ -0,0 +1,217 @@
+/*
+ * General purpose implementation of a simple periodic countdown timer.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GNU LGPL.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "host-utils.h"
+
+struct ptimer_state
+{
+    uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
+    uint64_t limit;
+    uint64_t delta;
+    uint32_t period_frac;
+    int64_t period;
+    int64_t last_event;
+    int64_t next_event;
+    QEMUBH *bh;
+    QEMUTimer *timer;
+};
+
+/* Use a bottom-half routine to avoid reentrancy issues.  */
+static void ptimer_trigger(ptimer_state *s)
+{
+    if (s->bh) {
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void ptimer_reload(ptimer_state *s)
+{
+    if (s->delta == 0) {
+        ptimer_trigger(s);
+        s->delta = s->limit;
+    }
+    if (s->delta == 0 || s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        s->enabled = 0;
+        return;
+    }
+
+    s->last_event = s->next_event;
+    s->next_event = s->last_event + s->delta * s->period;
+    if (s->period_frac) {
+        s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
+    }
+    qemu_mod_timer(s->timer, s->next_event);
+}
+
+static void ptimer_tick(void *opaque)
+{
+    ptimer_state *s = (ptimer_state *)opaque;
+    ptimer_trigger(s);
+    s->delta = 0;
+    if (s->enabled == 2) {
+        s->enabled = 0;
+    } else {
+        ptimer_reload(s);
+    }
+}
+
+uint64_t ptimer_get_count(ptimer_state *s)
+{
+    int64_t now;
+    uint64_t counter;
+
+    if (s->enabled) {
+        now = qemu_get_clock_ns(vm_clock);
+        /* Figure out the current counter value.  */
+        if (now - s->next_event > 0
+            || s->period == 0) {
+            /* Prevent timer underflowing if it should already have
+               triggered.  */
+            counter = 0;
+        } else {
+            uint64_t rem;
+            uint64_t div;
+            int clz1, clz2;
+            int shift;
+
+            /* We need to divide time by period, where time is stored in
+               rem (64-bit integer) and period is stored in period/period_frac
+               (64.32 fixed point).
+              
+               Doing full precision division is hard, so scale values and
+               do a 64-bit division.  The result should be rounded down,
+               so that the rounding error never causes the timer to go
+               backwards.
+            */
+
+            rem = s->next_event - now;
+            div = s->period;
+
+            clz1 = clz64(rem);
+            clz2 = clz64(div);
+            shift = clz1 < clz2 ? clz1 : clz2;
+
+            rem <<= shift;
+            div <<= shift;
+            if (shift >= 32) {
+                div |= ((uint64_t)s->period_frac << (shift - 32));
+            } else {
+                if (shift != 0)
+                    div |= (s->period_frac >> (32 - shift));
+                /* Look at remaining bits of period_frac and round div up if 
+                   necessary.  */
+                if ((uint32_t)(s->period_frac << shift))
+                    div += 1;
+            }
+            counter = rem / div;
+        }
+    } else {
+        counter = s->delta;
+    }
+    return counter;
+}
+
+void ptimer_set_count(ptimer_state *s, uint64_t count)
+{
+    s->delta = count;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+void ptimer_run(ptimer_state *s, int oneshot)
+{
+    if (s->enabled) {
+        return;
+    }
+    if (s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        return;
+    }
+    s->enabled = oneshot ? 2 : 1;
+    s->next_event = qemu_get_clock_ns(vm_clock);
+    ptimer_reload(s);
+}
+
+/* Pause a timer.  Note that this may cause it to "lose" time, even if it
+   is immediately restarted.  */
+void ptimer_stop(ptimer_state *s)
+{
+    if (!s->enabled)
+        return;
+
+    s->delta = ptimer_get_count(s);
+    qemu_del_timer(s->timer);
+    s->enabled = 0;
+}
+
+/* Set counter increment interval in nanoseconds.  */
+void ptimer_set_period(ptimer_state *s, int64_t period)
+{
+    s->period = period;
+    s->period_frac = 0;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set counter frequency in Hz.  */
+void ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+    s->period = 1000000000ll / freq;
+    s->period_frac = (1000000000ll << 32) / freq;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set the initial countdown value.  If reload is nonzero then also set
+   count = limit.  */
+void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
+{
+    s->limit = limit;
+    if (reload)
+        s->delta = limit;
+    if (s->enabled && reload) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+const VMStateDescription vmstate_ptimer = {
+    .name = "ptimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(enabled, ptimer_state),
+        VMSTATE_UINT64(limit, ptimer_state),
+        VMSTATE_UINT64(delta, ptimer_state),
+        VMSTATE_UINT32(period_frac, ptimer_state),
+        VMSTATE_INT64(period, ptimer_state),
+        VMSTATE_INT64(last_event, ptimer_state),
+        VMSTATE_INT64(next_event, ptimer_state),
+        VMSTATE_TIMER(timer, ptimer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+ptimer_state *ptimer_init(QEMUBH *bh)
+{
+    ptimer_state *s;
+
+    s = (ptimer_state *)qemu_mallocz(sizeof(ptimer_state));
+    s->bh = bh;
+    s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s);
+    return s;
+}
diff --git a/qemu-0.15.x/hw/pxa.h b/qemu-0.15.x/hw/pxa.h
new file mode 100644
index 0000000..859fc67
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa.h
@@ -0,0 +1,179 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#ifndef PXA_H
+# define PXA_H			"pxa.h"
+
+/* Interrupt numbers */
+# define PXA2XX_PIC_SSP3	0
+# define PXA2XX_PIC_USBH2	2
+# define PXA2XX_PIC_USBH1	3
+# define PXA2XX_PIC_KEYPAD	4
+# define PXA2XX_PIC_PWRI2C	6
+# define PXA25X_PIC_HWUART	7
+# define PXA27X_PIC_OST_4_11	7
+# define PXA2XX_PIC_GPIO_0	8
+# define PXA2XX_PIC_GPIO_1	9
+# define PXA2XX_PIC_GPIO_X	10
+# define PXA2XX_PIC_I2S 	13
+# define PXA26X_PIC_ASSP	15
+# define PXA25X_PIC_NSSP	16
+# define PXA27X_PIC_SSP2	16
+# define PXA2XX_PIC_LCD		17
+# define PXA2XX_PIC_I2C		18
+# define PXA2XX_PIC_ICP		19
+# define PXA2XX_PIC_STUART	20
+# define PXA2XX_PIC_BTUART	21
+# define PXA2XX_PIC_FFUART	22
+# define PXA2XX_PIC_MMC		23
+# define PXA2XX_PIC_SSP		24
+# define PXA2XX_PIC_DMA		25
+# define PXA2XX_PIC_OST_0	26
+# define PXA2XX_PIC_RTC1HZ	30
+# define PXA2XX_PIC_RTCALARM	31
+
+/* DMA requests */
+# define PXA2XX_RX_RQ_I2S	2
+# define PXA2XX_TX_RQ_I2S	3
+# define PXA2XX_RX_RQ_BTUART	4
+# define PXA2XX_TX_RQ_BTUART	5
+# define PXA2XX_RX_RQ_FFUART	6
+# define PXA2XX_TX_RQ_FFUART	7
+# define PXA2XX_RX_RQ_SSP1	13
+# define PXA2XX_TX_RQ_SSP1	14
+# define PXA2XX_RX_RQ_SSP2	15
+# define PXA2XX_TX_RQ_SSP2	16
+# define PXA2XX_RX_RQ_ICP	17
+# define PXA2XX_TX_RQ_ICP	18
+# define PXA2XX_RX_RQ_STUART	19
+# define PXA2XX_TX_RQ_STUART	20
+# define PXA2XX_RX_RQ_MMCI	21
+# define PXA2XX_TX_RQ_MMCI	22
+# define PXA2XX_USB_RQ(x)	((x) + 24)
+# define PXA2XX_RX_RQ_SSP3	66
+# define PXA2XX_TX_RQ_SSP3	67
+
+# define PXA2XX_SDRAM_BASE	0xa0000000
+# define PXA2XX_INTERNAL_BASE	0x5c000000
+# define PXA2XX_INTERNAL_SIZE	0x40000
+
+/* pxa2xx_pic.c */
+DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
+
+/* pxa2xx_gpio.c */
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, DeviceState *pic, int lines);
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
+
+/* pxa2xx_dma.c */
+DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq);
+DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq);
+
+/* pxa2xx_lcd.c */
+typedef struct PXA2xxLCDState PXA2xxLCDState;
+PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base,
+                qemu_irq irq);
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
+void pxa2xx_lcdc_oritentation(void *opaque, int angle);
+
+/* pxa2xx_mmci.c */
+typedef struct PXA2xxMMCIState PXA2xxMMCIState;
+PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma);
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
+                qemu_irq coverswitch);
+
+/* pxa2xx_pcmcia.c */
+typedef struct PXA2xxPCMCIAState PXA2xxPCMCIAState;
+PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base);
+int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
+int pxa2xx_pcmcia_dettach(void *opaque);
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
+
+/* pxa2xx_keypad.c */
+struct  keymap {
+    int column;
+    int row;
+};
+typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
+PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
+                qemu_irq irq);
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
+                int size);
+
+/* pxa2xx.c */
+typedef struct PXA2xxI2CState PXA2xxI2CState;
+PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, uint32_t page_size);
+i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
+
+typedef struct PXA2xxI2SState PXA2xxI2SState;
+typedef struct PXA2xxFIrState PXA2xxFIrState;
+
+typedef struct {
+    CPUState *env;
+    DeviceState *pic;
+    qemu_irq reset;
+    DeviceState *dma;
+    DeviceState *gpio;
+    PXA2xxLCDState *lcd;
+    SSIBus **ssp;
+    PXA2xxI2CState *i2c[2];
+    PXA2xxMMCIState *mmc;
+    PXA2xxPCMCIAState *pcmcia[2];
+    PXA2xxI2SState *i2s;
+    PXA2xxFIrState *fir;
+    PXA2xxKeyPadState *kp;
+
+    /* Power management */
+    target_phys_addr_t pm_base;
+    uint32_t pm_regs[0x40];
+
+    /* Clock management */
+    target_phys_addr_t cm_base;
+    uint32_t cm_regs[4];
+    uint32_t clkcfg;
+
+    /* Memory management */
+    target_phys_addr_t mm_base;
+    uint32_t mm_regs[0x1a];
+
+    /* Performance monitoring */
+    uint32_t pmnc;
+} PXA2xxState;
+
+struct PXA2xxI2SState {
+    qemu_irq irq;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
+    void (*data_req)(void *, int, int);
+
+    uint32_t control[2];
+    uint32_t status;
+    uint32_t mask;
+    uint32_t clk;
+
+    int enable;
+    int rx_len;
+    int tx_len;
+    void (*codec_out)(void *, uint32_t);
+    uint32_t (*codec_in)(void *);
+    void *opaque;
+
+    int fifo_len;
+    uint32_t fifo[16];
+};
+
+# define PA_FMT			"0x%08lx"
+# define REG_FMT		"0x" TARGET_FMT_plx
+
+PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
+PXA2xxState *pxa255_init(unsigned int sdram_size);
+
+#endif	/* PXA_H */
diff --git a/qemu-0.15.x/hw/pxa2xx.c b/qemu-0.15.x/hw/pxa2xx.c
new file mode 100644
index 0000000..cf93110
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx.c
@@ -0,0 +1,2344 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "pxa.h"
+#include "sysemu.h"
+#include "pc.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "qemu-char.h"
+#include "blockdev.h"
+
+static struct {
+    target_phys_addr_t io_base;
+    int irqn;
+} pxa255_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0x41600000, PXA25X_PIC_HWUART },
+    { 0, 0 }
+}, pxa270_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0, 0 }
+};
+
+typedef struct PXASSPDef {
+    target_phys_addr_t io_base;
+    int irqn;
+} PXASSPDef;
+
+#if 0
+static PXASSPDef pxa250_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0, 0 }
+};
+#endif
+
+static PXASSPDef pxa255_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0, 0 }
+};
+
+#if 0
+static PXASSPDef pxa26x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0x41500000, PXA26X_PIC_ASSP },
+    { 0, 0 }
+};
+#endif
+
+static PXASSPDef pxa27x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41700000, PXA27X_PIC_SSP2 },
+    { 0x41900000, PXA2XX_PIC_SSP3 },
+    { 0, 0 }
+};
+
+#define PMCR	0x00	/* Power Manager Control register */
+#define PSSR	0x04	/* Power Manager Sleep Status register */
+#define PSPR	0x08	/* Power Manager Scratch-Pad register */
+#define PWER	0x0c	/* Power Manager Wake-Up Enable register */
+#define PRER	0x10	/* Power Manager Rising-Edge Detect Enable register */
+#define PFER	0x14	/* Power Manager Falling-Edge Detect Enable register */
+#define PEDR	0x18	/* Power Manager Edge-Detect Status register */
+#define PCFR	0x1c	/* Power Manager General Configuration register */
+#define PGSR0	0x20	/* Power Manager GPIO Sleep-State register 0 */
+#define PGSR1	0x24	/* Power Manager GPIO Sleep-State register 1 */
+#define PGSR2	0x28	/* Power Manager GPIO Sleep-State register 2 */
+#define PGSR3	0x2c	/* Power Manager GPIO Sleep-State register 3 */
+#define RCSR	0x30	/* Reset Controller Status register */
+#define PSLR	0x34	/* Power Manager Sleep Configuration register */
+#define PTSR	0x38	/* Power Manager Standby Configuration register */
+#define PVCR	0x40	/* Power Manager Voltage Change Control register */
+#define PUCR	0x4c	/* Power Manager USIM Card Control/Status register */
+#define PKWR	0x50	/* Power Manager Keyboard Wake-Up Enable register */
+#define PKSR	0x54	/* Power Manager Keyboard Level-Detect Status */
+#define PCMD0	0x80	/* Power Manager I2C Command register File 0 */
+#define PCMD31	0xfc	/* Power Manager I2C Command register File 31 */
+
+static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case PMCR ... PCMD31:
+        if (addr & 3)
+            goto fail;
+
+        return s->pm_regs[addr >> 2];
+    default:
+    fail:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case PMCR:
+        s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+        s->pm_regs[addr >> 2] |= value & 0x15;
+        break;
+
+    case PSSR:	/* Read-clean registers */
+    case RCSR:
+    case PKSR:
+        s->pm_regs[addr >> 2] &= ~value;
+        break;
+
+    default:	/* Read-write registers */
+        if (!(addr & 3)) {
+            s->pm_regs[addr >> 2] = value;
+            break;
+        }
+
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_pm_readfn[] = {
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = {
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+};
+
+static const VMStateDescription vmstate_pxa2xx_pm = {
+    .name = "pxa2xx_pm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define CCCR	0x00	/* Core Clock Configuration register */
+#define CKEN	0x04	/* Clock Enable register */
+#define OSCC	0x08	/* Oscillator Configuration register */
+#define CCSR	0x0c	/* Core Clock Status register */
+
+static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+    case OSCC:
+        return s->cm_regs[addr >> 2];
+
+    case CCSR:
+        return s->cm_regs[CCCR >> 2] | (3 << 28);
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+        s->cm_regs[addr >> 2] = value;
+        break;
+
+    case OSCC:
+        s->cm_regs[addr >> 2] &= ~0x6c;
+        s->cm_regs[addr >> 2] |= value & 0x6e;
+        if ((value >> 1) & 1)			/* OON */
+            s->cm_regs[addr >> 2] |= 1 << 0;	/* Oscillator is now stable */
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_cm_readfn[] = {
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = {
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+};
+
+static const VMStateDescription vmstate_pxa2xx_cm = {
+    .name = "pxa2xx_cm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
+        VMSTATE_UINT32(clkcfg, PXA2xxState),
+        VMSTATE_UINT32(pmnc, PXA2xxState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (reg) {
+    case 6:	/* Clock Configuration register */
+        return s->clkcfg;
+
+    case 7:	/* Power Mode register */
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+    static const char *pwrmode[8] = {
+        "Normal", "Idle", "Deep-idle", "Standby",
+        "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
+    };
+
+    switch (reg) {
+    case 6:	/* Clock Configuration register */
+        s->clkcfg = value & 0xf;
+        if (value & 2)
+            printf("%s: CPU frequency change attempt\n", __FUNCTION__);
+        break;
+
+    case 7:	/* Power Mode register */
+        if (value & 8)
+            printf("%s: CPU voltage change attempt\n", __FUNCTION__);
+        switch (value & 7) {
+        case 0:
+            /* Do nothing */
+            break;
+
+        case 1:
+            /* Idle */
+            if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) {	/* CPDIS */
+                cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+                break;
+            }
+            /* Fall through.  */
+
+        case 2:
+            /* Deep-Idle */
+            cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+            s->pm_regs[RCSR >> 2] |= 0x8;	/* Set GPR */
+            goto message;
+
+        case 3:
+            s->env->uncached_cpsr =
+                    ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+            s->env->cp15.c1_sys = 0;
+            s->env->cp15.c1_coproc = 0;
+            s->env->cp15.c2_base0 = 0;
+            s->env->cp15.c3 = 0;
+            s->pm_regs[PSSR >> 2] |= 0x8;	/* Set STS */
+            s->pm_regs[RCSR >> 2] |= 0x8;	/* Set GPR */
+
+            /*
+             * The scratch-pad register is almost universally used
+             * for storing the return address on suspend.  For the
+             * lack of a resuming bootloader, perform a jump
+             * directly to that address.
+             */
+            memset(s->env->regs, 0, 4 * 15);
+            s->env->regs[15] = s->pm_regs[PSPR >> 2];
+
+#if 0
+            buffer = 0xe59ff000;	/* ldr     pc, [pc, #0] */
+            cpu_physical_memory_write(0, &buffer, 4);
+            buffer = s->pm_regs[PSPR >> 2];
+            cpu_physical_memory_write(8, &buffer, 4);
+#endif
+
+            /* Suspend */
+            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+
+            goto message;
+
+        default:
+        message:
+            printf("%s: machine entered %s mode\n", __FUNCTION__,
+                            pwrmode[value & 7]);
+        }
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+/* Performace Monitoring Registers */
+#define CPPMNC		0	/* Performance Monitor Control register */
+#define CPCCNT		1	/* Clock Counter register */
+#define CPINTEN		4	/* Interrupt Enable register */
+#define CPFLAG		5	/* Overflow Flag register */
+#define CPEVTSEL	8	/* Event Selection register */
+
+#define CPPMN0		0	/* Performance Count register 0 */
+#define CPPMN1		1	/* Performance Count register 1 */
+#define CPPMN2		2	/* Performance Count register 2 */
+#define CPPMN3		3	/* Performance Count register 3 */
+
+static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        return s->pmnc;
+    case CPCCNT:
+        if (s->pmnc & 1)
+            return qemu_get_clock_ns(vm_clock);
+        else
+            return 0;
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        s->pmnc = value;
+        break;
+
+    case CPCCNT:
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
+{
+    switch (crm) {
+    case 0:
+        return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
+    case 1:
+        return pxa2xx_perf_read(opaque, op2, reg, crm);
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return 0;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    switch (crm) {
+    case 0:
+        pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
+        break;
+    case 1:
+        pxa2xx_perf_write(opaque, op2, reg, crm, value);
+        break;
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+#define MDCNFG		0x00	/* SDRAM Configuration register */
+#define MDREFR		0x04	/* SDRAM Refresh Control register */
+#define MSC0		0x08	/* Static Memory Control register 0 */
+#define MSC1		0x0c	/* Static Memory Control register 1 */
+#define MSC2		0x10	/* Static Memory Control register 2 */
+#define MECR		0x14	/* Expansion Memory Bus Config register */
+#define SXCNFG		0x1c	/* Synchronous Static Memory Config register */
+#define MCMEM0		0x28	/* PC Card Memory Socket 0 Timing register */
+#define MCMEM1		0x2c	/* PC Card Memory Socket 1 Timing register */
+#define MCATT0		0x30	/* PC Card Attribute Socket 0 register */
+#define MCATT1		0x34	/* PC Card Attribute Socket 1 register */
+#define MCIO0		0x38	/* PC Card I/O Socket 0 Timing register */
+#define MCIO1		0x3c	/* PC Card I/O Socket 1 Timing register */
+#define MDMRS		0x40	/* SDRAM Mode Register Set Config register */
+#define BOOT_DEF	0x44	/* Boot-time Default Configuration register */
+#define ARB_CNTL	0x48	/* Arbiter Control register */
+#define BSCNTR0		0x4c	/* Memory Buffer Strength Control register 0 */
+#define BSCNTR1		0x50	/* Memory Buffer Strength Control register 1 */
+#define LCDBSCNTR	0x54	/* LCD Buffer Strength Control register */
+#define MDMRSLP		0x58	/* Low Power SDRAM Mode Set Config register */
+#define BSCNTR2		0x5c	/* Memory Buffer Strength Control register 2 */
+#define BSCNTR3		0x60	/* Memory Buffer Strength Control register 3 */
+#define SA1110		0x64	/* SA-1110 Memory Compatibility register */
+
+static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0)
+            return s->mm_regs[addr >> 2];
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0) {
+            s->mm_regs[addr >> 2] = value;
+            break;
+        }
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_mm_readfn[] = {
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = {
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+};
+
+static const VMStateDescription vmstate_pxa2xx_mm = {
+    .name = "pxa2xx_mm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Synchronous Serial Ports */
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    int enable;
+    SSIBus *bus;
+
+    uint32_t sscr[2];
+    uint32_t sspsp;
+    uint32_t ssto;
+    uint32_t ssitr;
+    uint32_t sssr;
+    uint8_t sstsa;
+    uint8_t ssrsa;
+    uint8_t ssacd;
+
+    uint32_t rx_fifo[16];
+    int rx_level;
+    int rx_start;
+} PXA2xxSSPState;
+
+#define SSCR0	0x00	/* SSP Control register 0 */
+#define SSCR1	0x04	/* SSP Control register 1 */
+#define SSSR	0x08	/* SSP Status register */
+#define SSITR	0x0c	/* SSP Interrupt Test register */
+#define SSDR	0x10	/* SSP Data register */
+#define SSTO	0x28	/* SSP Time-Out register */
+#define SSPSP	0x2c	/* SSP Programmable Serial Protocol register */
+#define SSTSA	0x30	/* SSP TX Time Slot Active register */
+#define SSRSA	0x34	/* SSP RX Time Slot Active register */
+#define SSTSS	0x38	/* SSP Time Slot Status register */
+#define SSACD	0x3c	/* SSP Audio Clock Divider register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)	(((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)	(((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x)	(((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)	(((x) & 0x30) == 0x30)
+#define SSCR0_SSE	(1 << 7)
+#define SSCR0_RIM	(1 << 22)
+#define SSCR0_TIM	(1 << 23)
+#define SSCR0_MOD	(1 << 31)
+#define SSCR0_DSS(x)	(((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
+#define SSCR1_RIE	(1 << 0)
+#define SSCR1_TIE	(1 << 1)
+#define SSCR1_LBM	(1 << 2)
+#define SSCR1_MWDS	(1 << 5)
+#define SSCR1_TFT(x)	((((x) >> 6) & 0xf) + 1)
+#define SSCR1_RFT(x)	((((x) >> 10) & 0xf) + 1)
+#define SSCR1_EFWR	(1 << 14)
+#define SSCR1_PINTE	(1 << 18)
+#define SSCR1_TINTE	(1 << 19)
+#define SSCR1_RSRE	(1 << 20)
+#define SSCR1_TSRE	(1 << 21)
+#define SSCR1_EBCEI	(1 << 29)
+#define SSITR_INT	(7 << 5)
+#define SSSR_TNF	(1 << 2)
+#define SSSR_RNE	(1 << 3)
+#define SSSR_TFS	(1 << 5)
+#define SSSR_RFS	(1 << 6)
+#define SSSR_ROR	(1 << 7)
+#define SSSR_PINT	(1 << 18)
+#define SSSR_TINT	(1 << 19)
+#define SSSR_EOC	(1 << 20)
+#define SSSR_TUR	(1 << 21)
+#define SSSR_BCE	(1 << 23)
+#define SSSR_RW		0x00bc0080
+
+static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
+{
+    int level = 0;
+
+    level |= s->ssitr & SSITR_INT;
+    level |= (s->sssr & SSSR_BCE)  &&  (s->sscr[1] & SSCR1_EBCEI);
+    level |= (s->sssr & SSSR_TUR)  && !(s->sscr[0] & SSCR0_TIM);
+    level |= (s->sssr & SSSR_EOC)  &&  (s->sssr & (SSSR_TINT | SSSR_PINT));
+    level |= (s->sssr & SSSR_TINT) &&  (s->sscr[1] & SSCR1_TINTE);
+    level |= (s->sssr & SSSR_PINT) &&  (s->sscr[1] & SSCR1_PINTE);
+    level |= (s->sssr & SSSR_ROR)  && !(s->sscr[0] & SSCR0_RIM);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, !!level);
+}
+
+static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
+{
+    s->sssr &= ~(0xf << 12);	/* Clear RFL */
+    s->sssr &= ~(0xf << 8);	/* Clear TFL */
+    s->sssr &= ~SSSR_TFS;
+    s->sssr &= ~SSSR_TNF;
+    if (s->enable) {
+        s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
+        if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
+            s->sssr |= SSSR_RFS;
+        else
+            s->sssr &= ~SSSR_RFS;
+        if (s->rx_level)
+            s->sssr |= SSSR_RNE;
+        else
+            s->sssr &= ~SSSR_RNE;
+        /* TX FIFO is never filled, so it is always in underrun
+           condition if SSP is enabled */
+        s->sssr |= SSSR_TFS;
+        s->sssr |= SSSR_TNF;
+    }
+
+    pxa2xx_ssp_int_update(s);
+}
+
+static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+    uint32_t retval;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSPSP:
+        return s->sspsp;
+    case SSTO:
+        return s->ssto;
+    case SSITR:
+        return s->ssitr;
+    case SSSR:
+        return s->sssr | s->ssitr;
+    case SSDR:
+        if (!s->enable)
+            return 0xffffffff;
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __FUNCTION__);
+            return 0xffffffff;
+        }
+        s->rx_level --;
+        retval = s->rx_fifo[s->rx_start ++];
+        s->rx_start &= 0xf;
+        pxa2xx_ssp_fifo_update(s);
+        return retval;
+    case SSTSA:
+        return s->sstsa;
+    case SSRSA:
+        return s->ssrsa;
+    case SSTSS:
+        return 0;
+    case SSACD:
+        return s->ssacd;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xc7ffffff;
+        s->enable = value & SSCR0_SSE;
+        if (value & SSCR0_MOD)
+            printf("%s: Attempt to use network mode\n", __FUNCTION__);
+        if (s->enable && SSCR0_DSS(value) < 4)
+            printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
+                            SSCR0_DSS(value));
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->ssitr = 0;
+            s->rx_level = 0;
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value;
+        if (value & (SSCR1_LBM | SSCR1_EFWR))
+            printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSPSP:
+        s->sspsp = value;
+        break;
+
+    case SSTO:
+        s->ssto = value;
+        break;
+
+    case SSITR:
+        s->ssitr = value & SSITR_INT;
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            if (s->sscr[1] & SSCR1_MWDS)
+                value &= 0xffff;
+            else
+                value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->enable) {
+            uint32_t readval;
+            readval = ssi_transfer(s->bus, value);
+            if (s->rx_level < 0x10) {
+                s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
+            } else {
+                s->sssr |= SSSR_ROR;
+            }
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSTSA:
+        s->sstsa = value;
+        break;
+
+    case SSRSA:
+        s->ssrsa = value;
+        break;
+
+    case SSACD:
+        s->ssacd = value;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_ssp_readfn[] = {
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_ssp_writefn[] = {
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+};
+
+static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
+{
+    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->enable);
+
+    qemu_put_be32s(f, &s->sscr[0]);
+    qemu_put_be32s(f, &s->sscr[1]);
+    qemu_put_be32s(f, &s->sspsp);
+    qemu_put_be32s(f, &s->ssto);
+    qemu_put_be32s(f, &s->ssitr);
+    qemu_put_be32s(f, &s->sssr);
+    qemu_put_8s(f, &s->sstsa);
+    qemu_put_8s(f, &s->ssrsa);
+    qemu_put_8s(f, &s->ssacd);
+
+    qemu_put_byte(f, s->rx_level);
+    for (i = 0; i < s->rx_level; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]);
+}
+
+static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
+    int i;
+
+    s->enable = qemu_get_be32(f);
+
+    qemu_get_be32s(f, &s->sscr[0]);
+    qemu_get_be32s(f, &s->sscr[1]);
+    qemu_get_be32s(f, &s->sspsp);
+    qemu_get_be32s(f, &s->ssto);
+    qemu_get_be32s(f, &s->ssitr);
+    qemu_get_be32s(f, &s->sssr);
+    qemu_get_8s(f, &s->sstsa);
+    qemu_get_8s(f, &s->ssrsa);
+    qemu_get_8s(f, &s->ssacd);
+
+    s->rx_level = qemu_get_byte(f);
+    s->rx_start = 0;
+    for (i = 0; i < s->rx_level; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+static int pxa2xx_ssp_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn,
+                                       pxa2xx_ssp_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0,
+                    pxa2xx_ssp_save, pxa2xx_ssp_load, s);
+
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
+    return 0;
+}
+
+/* Real-Time Clock */
+#define RCNR		0x00	/* RTC Counter register */
+#define RTAR		0x04	/* RTC Alarm register */
+#define RTSR		0x08	/* RTC Status register */
+#define RTTR		0x0c	/* RTC Timer Trim register */
+#define RDCR		0x10	/* RTC Day Counter register */
+#define RYCR		0x14	/* RTC Year Counter register */
+#define RDAR1		0x18	/* RTC Wristwatch Day Alarm register 1 */
+#define RYAR1		0x1c	/* RTC Wristwatch Year Alarm register 1 */
+#define RDAR2		0x20	/* RTC Wristwatch Day Alarm register 2 */
+#define RYAR2		0x24	/* RTC Wristwatch Year Alarm register 2 */
+#define SWCR		0x28	/* RTC Stopwatch Counter register */
+#define SWAR1		0x2c	/* RTC Stopwatch Alarm register 1 */
+#define SWAR2		0x30	/* RTC Stopwatch Alarm register 2 */
+#define RTCPICR		0x34	/* RTC Periodic Interrupt Counter register */
+#define PIAR		0x38	/* RTC Periodic Interrupt Alarm register */
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t rdar1;
+    uint32_t rdar2;
+    uint32_t ryar1;
+    uint32_t ryar2;
+    uint32_t swar1;
+    uint32_t swar2;
+    uint32_t piar;
+    uint32_t last_rcnr;
+    uint32_t last_rdcr;
+    uint32_t last_rycr;
+    uint32_t last_swcr;
+    uint32_t last_rtcpicr;
+    int64_t last_hz;
+    int64_t last_sw;
+    int64_t last_pi;
+    QEMUTimer *rtc_hz;
+    QEMUTimer *rtc_rdal1;
+    QEMUTimer *rtc_rdal2;
+    QEMUTimer *rtc_swal1;
+    QEMUTimer *rtc_swal2;
+    QEMUTimer *rtc_pi;
+    qemu_irq rtc_irq;
+} PXA2xxRTCState;
+
+static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
+{
+    qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
+}
+
+static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rt_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_rdcr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rt_clock);
+    if (s->rtsr & (1 << 12))
+        s->last_swcr += (rt - s->last_sw) / 10;
+    s->last_sw = rt;
+}
+
+static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rt_clock);
+    if (s->rtsr & (1 << 15))
+        s->last_swcr += rt - s->last_pi;
+    s->last_pi = rt;
+}
+
+static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
+                uint32_t rtsr)
+{
+    if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
+        qemu_mod_timer(s->rtc_hz, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    else
+        qemu_del_timer(s->rtc_hz);
+
+    if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
+        qemu_mod_timer(s->rtc_rdal1, s->last_hz +
+                (((s->rdar1 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal1);
+
+    if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
+        qemu_mod_timer(s->rtc_rdal2, s->last_hz +
+                (((s->rdar2 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal2);
+
+    if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
+        qemu_mod_timer(s->rtc_swal1, s->last_sw +
+                        (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal1);
+
+    if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
+        qemu_mod_timer(s->rtc_swal2, s->last_sw +
+                        (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal2);
+
+    if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
+        qemu_mod_timer(s->rtc_pi, s->last_pi +
+                        (s->piar & 0xffff) - s->last_rtcpicr);
+    else
+        qemu_del_timer(s->rtc_pi);
+}
+
+static inline void pxa2xx_rtc_hz_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 0);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 4);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 6);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal1_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 8);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal2_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 10);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_pi_tick(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+    s->rtsr |= (1 << 13);
+    pxa2xx_rtc_piupdate(s);
+    s->last_rtcpicr = 0;
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RDAR1:
+        return s->rdar1;
+    case RDAR2:
+        return s->rdar2;
+    case RYAR1:
+        return s->ryar1;
+    case RYAR2:
+        return s->ryar2;
+    case SWAR1:
+        return s->swar1;
+    case SWAR2:
+        return s->swar2;
+    case PIAR:
+        return s->piar;
+    case RCNR:
+        return s->last_rcnr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RDCR:
+        return s->last_rdcr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RYCR:
+        return s->last_rycr;
+    case SWCR:
+        if (s->rtsr & (1 << 12))
+            return s->last_swcr + (qemu_get_clock_ms(rt_clock) - s->last_sw) / 10;
+        else
+            return s->last_swcr;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+
+    switch (addr) {
+    case RTTR:
+        if (!(s->rttr & (1 << 31))) {
+            pxa2xx_rtc_hzupdate(s);
+            s->rttr = value;
+            pxa2xx_rtc_alarm_update(s, s->rtsr);
+        }
+        break;
+
+    case RTSR:
+        if ((s->rtsr ^ value) & (1 << 15))
+            pxa2xx_rtc_piupdate(s);
+
+        if ((s->rtsr ^ value) & (1 << 12))
+            pxa2xx_rtc_swupdate(s);
+
+        if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
+            pxa2xx_rtc_alarm_update(s, value);
+
+        s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
+        pxa2xx_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR1:
+        s->rdar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR2:
+        s->rdar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR1:
+        s->ryar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR2:
+        s->ryar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR1:
+        pxa2xx_rtc_swupdate(s);
+        s->swar1 = value;
+        s->last_swcr = 0;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR2:
+        s->swar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case PIAR:
+        s->piar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RCNR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDCR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rdcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYCR:
+        s->last_rycr = value;
+        break;
+
+    case SWCR:
+        pxa2xx_rtc_swupdate(s);
+        s->last_swcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RTCPICR:
+        pxa2xx_rtc_piupdate(s);
+        s->last_rtcpicr = value & 0xffff;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_rtc_readfn[] = {
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_rtc_writefn[] = {
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+};
+
+static int pxa2xx_rtc_init(SysBusDevice *dev)
+{
+    PXA2xxRTCState *s = FROM_SYSBUS(PXA2xxRTCState, dev);
+    struct tm tm;
+    int wom;
+    int iomemtype;
+
+    s->rttr = 0x7fff;
+    s->rtsr = 0;
+
+    qemu_get_timedate(&tm, 0);
+    wom = ((tm.tm_mday - 1) / 7) + 1;
+
+    s->last_rcnr = (uint32_t) mktimegm(&tm);
+    s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
+            (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
+    s->last_rycr = ((tm.tm_year + 1900) << 9) |
+            ((tm.tm_mon + 1) << 5) | tm.tm_mday;
+    s->last_swcr = (tm.tm_hour << 19) |
+            (tm.tm_min << 13) | (tm.tm_sec << 7);
+    s->last_rtcpicr = 0;
+    s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rt_clock);
+
+    s->rtc_hz    = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_hz_tick,    s);
+    s->rtc_rdal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal1_tick, s);
+    s->rtc_rdal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal2_tick, s);
+    s->rtc_swal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal1_tick, s);
+    s->rtc_swal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal2_tick, s);
+    s->rtc_pi    = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_pi_tick,    s);
+
+    sysbus_init_irq(dev, &s->rtc_irq);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
+                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x10000, iomemtype);
+
+    return 0;
+}
+
+static void pxa2xx_rtc_pre_save(void *opaque)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+
+    pxa2xx_rtc_hzupdate(s);
+    pxa2xx_rtc_piupdate(s);
+    pxa2xx_rtc_swupdate(s);
+}
+
+static int pxa2xx_rtc_post_load(void *opaque, int version_id)
+{
+    PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
+
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
+    .name = "pxa2xx_rtc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = pxa2xx_rtc_pre_save,
+    .post_load = pxa2xx_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(rttr, PXA2xxRTCState),
+        VMSTATE_UINT32(rtsr, PXA2xxRTCState),
+        VMSTATE_UINT32(rtar, PXA2xxRTCState),
+        VMSTATE_UINT32(rdar1, PXA2xxRTCState),
+        VMSTATE_UINT32(rdar2, PXA2xxRTCState),
+        VMSTATE_UINT32(ryar1, PXA2xxRTCState),
+        VMSTATE_UINT32(ryar2, PXA2xxRTCState),
+        VMSTATE_UINT32(swar1, PXA2xxRTCState),
+        VMSTATE_UINT32(swar2, PXA2xxRTCState),
+        VMSTATE_UINT32(piar, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
+        VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
+        VMSTATE_INT64(last_hz, PXA2xxRTCState),
+        VMSTATE_INT64(last_sw, PXA2xxRTCState),
+        VMSTATE_INT64(last_pi, PXA2xxRTCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
+    .init       = pxa2xx_rtc_init,
+    .qdev.name  = "pxa2xx_rtc",
+    .qdev.desc  = "PXA2xx RTC Controller",
+    .qdev.size  = sizeof(PXA2xxRTCState),
+    .qdev.vmsd  = &vmstate_pxa2xx_rtc_regs,
+};
+
+/* I2C Interface */
+typedef struct {
+    i2c_slave i2c;
+    PXA2xxI2CState *host;
+} PXA2xxI2CSlaveState;
+
+struct PXA2xxI2CState {
+    SysBusDevice busdev;
+    PXA2xxI2CSlaveState *slave;
+    i2c_bus *bus;
+    qemu_irq irq;
+    uint32_t offset;
+    uint32_t region_size;
+
+    uint16_t control;
+    uint16_t status;
+    uint8_t ibmr;
+    uint8_t data;
+};
+
+#define IBMR	0x80	/* I2C Bus Monitor register */
+#define IDBR	0x88	/* I2C Data Buffer register */
+#define ICR	0x90	/* I2C Control register */
+#define ISR	0x98	/* I2C Status register */
+#define ISAR	0xa0	/* I2C Slave Address register */
+
+static void pxa2xx_i2c_update(PXA2xxI2CState *s)
+{
+    uint16_t level = 0;
+    level |= s->status & s->control & (1 << 10);		/* BED */
+    level |= (s->status & (1 << 7)) && (s->control & (1 << 9));	/* IRF */
+    level |= (s->status & (1 << 6)) && (s->control & (1 << 8));	/* ITE */
+    level |= s->status & (1 << 9);				/* SAD */
+    qemu_set_irq(s->irq, !!level);
+}
+
+/* These are only stubs now.  */
+static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+    PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
+    PXA2xxI2CState *s = slave->host;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->status |= (1 << 9);				/* set SAD */
+        s->status &= ~(1 << 0);				/* clear RWM */
+        break;
+    case I2C_START_RECV:
+        s->status |= (1 << 9);				/* set SAD */
+        s->status |= 1 << 0;				/* set RWM */
+        break;
+    case I2C_FINISH:
+        s->status |= (1 << 4);				/* set SSD */
+        break;
+    case I2C_NACK:
+        s->status |= 1 << 1;				/* set ACKNAK */
+        break;
+    }
+    pxa2xx_i2c_update(s);
+}
+
+static int pxa2xx_i2c_rx(i2c_slave *i2c)
+{
+    PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
+    PXA2xxI2CState *s = slave->host;
+    if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+        return 0;
+
+    if (s->status & (1 << 0)) {			/* RWM */
+        s->status |= 1 << 6;			/* set ITE */
+    }
+    pxa2xx_i2c_update(s);
+
+    return s->data;
+}
+
+static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+    PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
+    PXA2xxI2CState *s = slave->host;
+    if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+        return 1;
+
+    if (!(s->status & (1 << 0))) {		/* RWM */
+        s->status |= 1 << 7;			/* set IRF */
+        s->data = data;
+    }
+    pxa2xx_i2c_update(s);
+
+    return 1;
+}
+
+static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
+
+    addr -= s->offset;
+    switch (addr) {
+    case ICR:
+        return s->control;
+    case ISR:
+        return s->status | (i2c_bus_busy(s->bus) << 2);
+    case ISAR:
+        return s->slave->i2c.address;
+    case IDBR:
+        return s->data;
+    case IBMR:
+        if (s->status & (1 << 2))
+            s->ibmr ^= 3;	/* Fake SCL and SDA pin changes */
+        else
+            s->ibmr = 0;
+        return s->ibmr;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
+    int ack;
+
+    addr -= s->offset;
+    switch (addr) {
+    case ICR:
+        s->control = value & 0xfff7;
+        if ((value & (1 << 3)) && (value & (1 << 6))) {	/* TB and IUE */
+            /* TODO: slave mode */
+            if (value & (1 << 0)) {			/* START condition */
+                if (s->data & 1)
+                    s->status |= 1 << 0;		/* set RWM */
+                else
+                    s->status &= ~(1 << 0);		/* clear RWM */
+                ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
+            } else {
+                if (s->status & (1 << 0)) {		/* RWM */
+                    s->data = i2c_recv(s->bus);
+                    if (value & (1 << 2))		/* ACKNAK */
+                        i2c_nack(s->bus);
+                    ack = 1;
+                } else
+                    ack = !i2c_send(s->bus, s->data);
+            }
+
+            if (value & (1 << 1))			/* STOP condition */
+                i2c_end_transfer(s->bus);
+
+            if (ack) {
+                if (value & (1 << 0))			/* START condition */
+                    s->status |= 1 << 6;		/* set ITE */
+                else
+                    if (s->status & (1 << 0))		/* RWM */
+                        s->status |= 1 << 7;		/* set IRF */
+                    else
+                        s->status |= 1 << 6;		/* set ITE */
+                s->status &= ~(1 << 1);			/* clear ACKNAK */
+            } else {
+                s->status |= 1 << 6;			/* set ITE */
+                s->status |= 1 << 10;			/* set BED */
+                s->status |= 1 << 1;			/* set ACKNAK */
+            }
+        }
+        if (!(value & (1 << 3)) && (value & (1 << 6)))	/* !TB and IUE */
+            if (value & (1 << 4))			/* MA */
+                i2c_end_transfer(s->bus);
+        pxa2xx_i2c_update(s);
+        break;
+
+    case ISR:
+        s->status &= ~(value & 0x07f0);
+        pxa2xx_i2c_update(s);
+        break;
+
+    case ISAR:
+        i2c_set_slave_address(&s->slave->i2c, value & 0x7f);
+        break;
+
+    case IDBR:
+        s->data = value & 0xff;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_i2c_readfn[] = {
+    pxa2xx_i2c_read,
+    pxa2xx_i2c_read,
+    pxa2xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_i2c_writefn[] = {
+    pxa2xx_i2c_write,
+    pxa2xx_i2c_write,
+    pxa2xx_i2c_write,
+};
+
+static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
+    .name = "pxa2xx_i2c_slave",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_I2C_SLAVE(i2c, PXA2xxI2CSlaveState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pxa2xx_i2c = {
+    .name = "pxa2xx_i2c",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(control, PXA2xxI2CState),
+        VMSTATE_UINT16(status, PXA2xxI2CState),
+        VMSTATE_UINT8(ibmr, PXA2xxI2CState),
+        VMSTATE_UINT8(data, PXA2xxI2CState),
+        VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
+                               vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pxa2xx_i2c_slave_init(i2c_slave *i2c)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+static I2CSlaveInfo pxa2xx_i2c_slave_info = {
+    .qdev.name = "pxa2xx-i2c-slave",
+    .qdev.size = sizeof(PXA2xxI2CSlaveState),
+    .init = pxa2xx_i2c_slave_init,
+    .event = pxa2xx_i2c_event,
+    .recv = pxa2xx_i2c_rx,
+    .send = pxa2xx_i2c_tx
+};
+
+PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, uint32_t region_size)
+{
+    DeviceState *dev;
+    SysBusDevice *i2c_dev;
+    PXA2xxI2CState *s;
+
+    i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c"));
+    qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1);
+    qdev_prop_set_uint32(&i2c_dev->qdev, "offset",
+            base - (base & (~region_size) & TARGET_PAGE_MASK));
+
+    qdev_init_nofail(&i2c_dev->qdev);
+
+    sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
+    sysbus_connect_irq(i2c_dev, 0, irq);
+
+    s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev);
+    /* FIXME: Should the slave device really be on a separate bus?  */
+    dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0);
+    s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev));
+    s->slave->host = s;
+
+    return s;
+}
+
+static int pxa2xx_i2c_initfn(SysBusDevice *dev)
+{
+    PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev);
+    int iomemtype;
+
+    s->bus = i2c_init_bus(&dev->qdev, "i2c");
+
+    iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn,
+                    pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, s->region_size, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
+{
+    return s->bus;
+}
+
+static SysBusDeviceInfo pxa2xx_i2c_info = {
+    .init       = pxa2xx_i2c_initfn,
+    .qdev.name  = "pxa2xx_i2c",
+    .qdev.desc  = "PXA2xx I2C Bus Controller",
+    .qdev.size  = sizeof(PXA2xxI2CState),
+    .qdev.vmsd  = &vmstate_pxa2xx_i2c,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
+        DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+/* PXA Inter-IC Sound Controller */
+static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
+{
+    i2s->rx_len = 0;
+    i2s->tx_len = 0;
+    i2s->fifo_len = 0;
+    i2s->clk = 0x1a;
+    i2s->control[0] = 0x00;
+    i2s->control[1] = 0x00;
+    i2s->status = 0x00;
+    i2s->mask = 0x00;
+}
+
+#define SACR_TFTH(val)	((val >> 8) & 0xf)
+#define SACR_RFTH(val)	((val >> 12) & 0xf)
+#define SACR_DREC(val)	(val & (1 << 3))
+#define SACR_DPRL(val)	(val & (1 << 4))
+
+static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
+{
+    int rfs, tfs;
+    rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
+            !SACR_DREC(i2s->control[1]);
+    tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
+            i2s->enable && !SACR_DPRL(i2s->control[1]);
+
+    qemu_set_irq(i2s->rx_dma, rfs);
+    qemu_set_irq(i2s->tx_dma, tfs);
+
+    i2s->status &= 0xe0;
+    if (i2s->fifo_len < 16 || !i2s->enable)
+        i2s->status |= 1 << 0;			/* TNF */
+    if (i2s->rx_len)
+        i2s->status |= 1 << 1;			/* RNE */
+    if (i2s->enable)
+        i2s->status |= 1 << 2;			/* BSY */
+    if (tfs)
+        i2s->status |= 1 << 3;			/* TFS */
+    if (rfs)
+        i2s->status |= 1 << 4;			/* RFS */
+    if (!(i2s->tx_len && i2s->enable))
+        i2s->status |= i2s->fifo_len << 8;	/* TFL */
+    i2s->status |= MAX(i2s->rx_len, 0xf) << 12;	/* RFL */
+
+    qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
+}
+
+#define SACR0	0x00	/* Serial Audio Global Control register */
+#define SACR1	0x04	/* Serial Audio I2S/MSB-Justified Control register */
+#define SASR0	0x0c	/* Serial Audio Interface and FIFO Status register */
+#define SAIMR	0x14	/* Serial Audio Interrupt Mask register */
+#define SAICR	0x18	/* Serial Audio Interrupt Clear register */
+#define SADIV	0x60	/* Serial Audio Clock Divider register */
+#define SADR	0x80	/* Serial Audio Data register */
+
+static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
+
+    switch (addr) {
+    case SACR0:
+        return s->control[0];
+    case SACR1:
+        return s->control[1];
+    case SASR0:
+        return s->status;
+    case SAIMR:
+        return s->mask;
+    case SAICR:
+        return 0;
+    case SADIV:
+        return s->clk;
+    case SADR:
+        if (s->rx_len > 0) {
+            s->rx_len --;
+            pxa2xx_i2s_update(s);
+            return s->codec_in(s->opaque);
+        }
+        return 0;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
+    uint32_t *sample;
+
+    switch (addr) {
+    case SACR0:
+        if (value & (1 << 3))				/* RST */
+            pxa2xx_i2s_reset(s);
+        s->control[0] = value & 0xff3d;
+        if (!s->enable && (value & 1) && s->tx_len) {	/* ENB */
+            for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
+                s->codec_out(s->opaque, *sample);
+            s->status &= ~(1 << 7);			/* I2SOFF */
+        }
+        if (value & (1 << 4))				/* EFWR */
+            printf("%s: Attempt to use special function\n", __FUNCTION__);
+        s->enable = (value & 9) == 1;			/* ENB && !RST*/
+        pxa2xx_i2s_update(s);
+        break;
+    case SACR1:
+        s->control[1] = value & 0x0039;
+        if (value & (1 << 5))				/* ENLBF */
+            printf("%s: Attempt to use loopback function\n", __FUNCTION__);
+        if (value & (1 << 4))				/* DPRL */
+            s->fifo_len = 0;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAIMR:
+        s->mask = value & 0x0078;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAICR:
+        s->status &= ~(value & (3 << 5));
+        pxa2xx_i2s_update(s);
+        break;
+    case SADIV:
+        s->clk = value & 0x007f;
+        break;
+    case SADR:
+        if (s->tx_len && s->enable) {
+            s->tx_len --;
+            pxa2xx_i2s_update(s);
+            s->codec_out(s->opaque, value);
+        } else if (s->fifo_len < 16) {
+            s->fifo[s->fifo_len ++] = value;
+            pxa2xx_i2s_update(s);
+        }
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_i2s_readfn[] = {
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = {
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+};
+
+static const VMStateDescription vmstate_pxa2xx_i2s = {
+    .name = "pxa2xx_i2s",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
+        VMSTATE_UINT32(status, PXA2xxI2SState),
+        VMSTATE_UINT32(mask, PXA2xxI2SState),
+        VMSTATE_UINT32(clk, PXA2xxI2SState),
+        VMSTATE_INT32(enable, PXA2xxI2SState),
+        VMSTATE_INT32(rx_len, PXA2xxI2SState),
+        VMSTATE_INT32(tx_len, PXA2xxI2SState),
+        VMSTATE_INT32(fifo_len, PXA2xxI2SState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
+{
+    PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
+    uint32_t *sample;
+
+    /* Signal FIFO errors */
+    if (s->enable && s->tx_len)
+        s->status |= 1 << 5;		/* TUR */
+    if (s->enable && s->rx_len)
+        s->status |= 1 << 6;		/* ROR */
+
+    /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
+     * handle the cases where it makes a difference.  */
+    s->tx_len = tx - s->fifo_len;
+    s->rx_len = rx;
+    /* Note that is s->codec_out wasn't set, we wouldn't get called.  */
+    if (s->enable)
+        for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
+            s->codec_out(s->opaque, *sample);
+    pxa2xx_i2s_update(s);
+}
+
+static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
+{
+    int iomemtype;
+    PXA2xxI2SState *s = (PXA2xxI2SState *)
+            qemu_mallocz(sizeof(PXA2xxI2SState));
+
+    s->irq = irq;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
+    s->data_req = pxa2xx_i2s_data_req;
+
+    pxa2xx_i2s_reset(s);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn,
+                    pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x100000, iomemtype);
+
+    vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
+
+    return s;
+}
+
+/* PXA Fast Infra-red Communications Port */
+struct PXA2xxFIrState {
+    qemu_irq irq;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
+    int enable;
+    CharDriverState *chr;
+
+    uint8_t control[3];
+    uint8_t status[2];
+
+    int rx_len;
+    int rx_start;
+    uint8_t rx_fifo[64];
+};
+
+static void pxa2xx_fir_reset(PXA2xxFIrState *s)
+{
+    s->control[0] = 0x00;
+    s->control[1] = 0x00;
+    s->control[2] = 0x00;
+    s->status[0] = 0x00;
+    s->status[1] = 0x00;
+    s->enable = 0;
+}
+
+static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
+{
+    static const int tresh[4] = { 8, 16, 32, 0 };
+    int intr = 0;
+    if ((s->control[0] & (1 << 4)) &&			/* RXE */
+                    s->rx_len >= tresh[s->control[2] & 3])	/* TRIG */
+        s->status[0] |= 1 << 4;				/* RFS */
+    else
+        s->status[0] &= ~(1 << 4);			/* RFS */
+    if (s->control[0] & (1 << 3))			/* TXE */
+        s->status[0] |= 1 << 3;				/* TFS */
+    else
+        s->status[0] &= ~(1 << 3);			/* TFS */
+    if (s->rx_len)
+        s->status[1] |= 1 << 2;				/* RNE */
+    else
+        s->status[1] &= ~(1 << 2);			/* RNE */
+    if (s->control[0] & (1 << 4))			/* RXE */
+        s->status[1] |= 1 << 0;				/* RSY */
+    else
+        s->status[1] &= ~(1 << 0);			/* RSY */
+
+    intr |= (s->control[0] & (1 << 5)) &&		/* RIE */
+            (s->status[0] & (1 << 4));			/* RFS */
+    intr |= (s->control[0] & (1 << 6)) &&		/* TIE */
+            (s->status[0] & (1 << 3));			/* TFS */
+    intr |= (s->control[2] & (1 << 4)) &&		/* TRAIL */
+            (s->status[0] & (1 << 6));			/* EOC */
+    intr |= (s->control[0] & (1 << 2)) &&		/* TUS */
+            (s->status[0] & (1 << 1));			/* TUR */
+    intr |= s->status[0] & 0x25;			/* FRE, RAB, EIF */
+
+    qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
+    qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
+
+    qemu_set_irq(s->irq, intr && s->enable);
+}
+
+#define ICCR0	0x00	/* FICP Control register 0 */
+#define ICCR1	0x04	/* FICP Control register 1 */
+#define ICCR2	0x08	/* FICP Control register 2 */
+#define ICDR	0x0c	/* FICP Data register */
+#define ICSR0	0x14	/* FICP Status register 0 */
+#define ICSR1	0x18	/* FICP Status register 1 */
+#define ICFOR	0x1c	/* FICP FIFO Occupancy Status register */
+
+static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    uint8_t ret;
+
+    switch (addr) {
+    case ICCR0:
+        return s->control[0];
+    case ICCR1:
+        return s->control[1];
+    case ICCR2:
+        return s->control[2];
+    case ICDR:
+        s->status[0] &= ~0x01;
+        s->status[1] &= ~0x72;
+        if (s->rx_len) {
+            s->rx_len --;
+            ret = s->rx_fifo[s->rx_start ++];
+            s->rx_start &= 63;
+            pxa2xx_fir_update(s);
+            return ret;
+        }
+        printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
+        break;
+    case ICSR0:
+        return s->status[0];
+    case ICSR1:
+        return s->status[1] | (1 << 3);			/* TNF */
+    case ICFOR:
+        return s->rx_len;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    uint8_t ch;
+
+    switch (addr) {
+    case ICCR0:
+        s->control[0] = value;
+        if (!(value & (1 << 4)))			/* RXE */
+            s->rx_len = s->rx_start = 0;
+        if (!(value & (1 << 3))) {                      /* TXE */
+            /* Nop */
+        }
+        s->enable = value & 1;				/* ITR */
+        if (!s->enable)
+            s->status[0] = 0;
+        pxa2xx_fir_update(s);
+        break;
+    case ICCR1:
+        s->control[1] = value;
+        break;
+    case ICCR2:
+        s->control[2] = value & 0x3f;
+        pxa2xx_fir_update(s);
+        break;
+    case ICDR:
+        if (s->control[2] & (1 << 2))			/* TXP */
+            ch = value;
+        else
+            ch = ~value;
+        if (s->chr && s->enable && (s->control[0] & (1 << 3)))	/* TXE */
+            qemu_chr_write(s->chr, &ch, 1);
+        break;
+    case ICSR0:
+        s->status[0] &= ~(value & 0x66);
+        pxa2xx_fir_update(s);
+        break;
+    case ICFOR:
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_fir_readfn[] = {
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_fir_writefn[] = {
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+};
+
+static int pxa2xx_fir_is_empty(void *opaque)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    return (s->rx_len < 64);
+}
+
+static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    if (!(s->control[0] & (1 << 4)))			/* RXE */
+        return;
+
+    while (size --) {
+        s->status[1] |= 1 << 4;				/* EOF */
+        if (s->rx_len >= 64) {
+            s->status[1] |= 1 << 6;			/* ROR */
+            break;
+        }
+
+        if (s->control[2] & (1 << 3))			/* RXP */
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
+        else
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
+    }
+
+    pxa2xx_fir_update(s);
+}
+
+static void pxa2xx_fir_event(void *opaque, int event)
+{
+}
+
+static void pxa2xx_fir_save(QEMUFile *f, void *opaque)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->enable);
+
+    qemu_put_8s(f, &s->control[0]);
+    qemu_put_8s(f, &s->control[1]);
+    qemu_put_8s(f, &s->control[2]);
+    qemu_put_8s(f, &s->status[0]);
+    qemu_put_8s(f, &s->status[1]);
+
+    qemu_put_byte(f, s->rx_len);
+    for (i = 0; i < s->rx_len; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]);
+}
+
+static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
+    int i;
+
+    s->enable = qemu_get_be32(f);
+
+    qemu_get_8s(f, &s->control[0]);
+    qemu_get_8s(f, &s->control[1]);
+    qemu_get_8s(f, &s->control[2]);
+    qemu_get_8s(f, &s->status[0]);
+    qemu_get_8s(f, &s->status[1]);
+
+    s->rx_len = qemu_get_byte(f);
+    s->rx_start = 0;
+    for (i = 0; i < s->rx_len; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
+                CharDriverState *chr)
+{
+    int iomemtype;
+    PXA2xxFIrState *s = (PXA2xxFIrState *)
+            qemu_mallocz(sizeof(PXA2xxFIrState));
+
+    s->irq = irq;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
+    s->chr = chr;
+
+    pxa2xx_fir_reset(s);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn,
+                    pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x1000, iomemtype);
+
+    if (chr)
+        qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
+                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+
+    register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
+                    pxa2xx_fir_load, s);
+
+    return s;
+}
+
+static void pxa2xx_reset(void *opaque, int line, int level)
+{
+    PXA2xxState *s = (PXA2xxState *) opaque;
+
+    if (level && (s->pm_regs[PCFR >> 2] & 0x10)) {	/* GPR_EN */
+        cpu_reset(s->env);
+        /* TODO: reset peripherals */
+    }
+}
+
+/* Initialise a PXA270 integrated chip (ARM based core).  */
+PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
+{
+    PXA2xxState *s;
+    int iomemtype, i;
+    DriveInfo *dinfo;
+    s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
+
+    if (revision && strncmp(revision, "pxa27", 5)) {
+        fprintf(stderr, "Machine requires a PXA27x processor.\n");
+        exit(1);
+    }
+    if (!revision)
+        revision = "pxa270";
+    
+    s->env = cpu_init(revision);
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
+
+    /* SDRAM & Internal Memory Storage */
+    cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
+                    sdram_size, qemu_ram_alloc(NULL, "pxa270.sdram",
+                                               sdram_size) | IO_MEM_RAM);
+    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
+                    0x40000, qemu_ram_alloc(NULL, "pxa270.internal",
+                                            0x40000) | IO_MEM_RAM);
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa27x_dma_init(0x40000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
+
+    sysbus_create_varargs("pxa27x-timer", 0x40a00000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
+                    qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
+                    NULL);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+
+    dinfo = drive_get(IF_SD, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
+
+    for (i = 0; pxa270_serial[i].io_base; i ++)
+        if (serial_hds[i])
+#ifdef TARGET_WORDS_BIGENDIAN
+            serial_mm_init(pxa270_serial[i].io_base, 2,
+                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
+                            14857000 / 16, serial_hds[i], 1, 1);
+#else
+            serial_mm_init(pxa270_serial[i].io_base, 2,
+                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
+                            14857000 / 16, serial_hds[i], 1, 0);
+#endif
+        else
+            break;
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
+                        serial_hds[i]);
+
+    s->lcd = pxa2xx_lcdc_init(0x44000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
+    s->clkcfg = 0x00000009;		/* Turbo mode active */
+    iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
+
+    for (i = 0; pxa27x_ssp[i].io_base; i ++);
+    s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
+    for (i = 0; pxa27x_ssp[i].io_base; i ++) {
+        DeviceState *dev;
+        dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
+                        qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
+        s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
+    }
+
+    if (usb_enabled) {
+        sysbus_create_simple("sysbus-ohci", 0x4c000000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
+    }
+
+    s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+    s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+    sysbus_create_simple("pxa2xx_rtc", 0x40900000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
+
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
+
+    s->kp = pxa27x_keypad_init(0x41500000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overridden by board-specific code */
+    qdev_connect_gpio_out(s->gpio, 1, s->reset);
+    return s;
+}
+
+/* Initialise a PXA255 integrated chip (ARM based core).  */
+PXA2xxState *pxa255_init(unsigned int sdram_size)
+{
+    PXA2xxState *s;
+    int iomemtype, i;
+    DriveInfo *dinfo;
+
+    s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
+
+    s->env = cpu_init("pxa255");
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
+
+    /* SDRAM & Internal Memory Storage */
+    cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size,
+                    qemu_ram_alloc(NULL, "pxa255.sdram",
+                                   sdram_size) | IO_MEM_RAM);
+    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE,
+                    qemu_ram_alloc(NULL, "pxa255.internal",
+                                   PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM);
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa255_dma_init(0x40000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
+
+    sysbus_create_varargs("pxa25x-timer", 0x40a00000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
+                    NULL);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
+
+    dinfo = drive_get(IF_SD, 0, 0);
+    if (!dinfo) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
+
+    for (i = 0; pxa255_serial[i].io_base; i ++)
+        if (serial_hds[i]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+            serial_mm_init(pxa255_serial[i].io_base, 2,
+                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
+                            14745600 / 16, serial_hds[i], 1, 1);
+#else
+            serial_mm_init(pxa255_serial[i].io_base, 2,
+                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
+                            14745600 / 16, serial_hds[i], 1, 0);
+#endif
+        } else {
+            break;
+        }
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
+                        qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
+                        serial_hds[i]);
+
+    s->lcd = pxa2xx_lcdc_init(0x44000000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
+    s->clkcfg = 0x00000009;		/* Turbo mode active */
+    iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
+
+    for (i = 0; pxa255_ssp[i].io_base; i ++);
+    s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
+    for (i = 0; pxa255_ssp[i].io_base; i ++) {
+        DeviceState *dev;
+        dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
+                        qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
+        s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
+    }
+
+    if (usb_enabled) {
+        sysbus_create_simple("sysbus-ohci", 0x4c000000,
+                        qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
+    }
+
+    s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+    s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+    sysbus_create_simple("pxa2xx_rtc", 0x40900000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
+
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000,
+                    qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
+                    qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overridden by board-specific code */
+    qdev_connect_gpio_out(s->gpio, 1, s->reset);
+    return s;
+}
+
+static void pxa2xx_register_devices(void)
+{
+    i2c_register_slave(&pxa2xx_i2c_slave_info);
+    sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
+    sysbus_register_withprop(&pxa2xx_i2c_info);
+    sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
+}
+
+device_init(pxa2xx_register_devices)
diff --git a/qemu-0.15.x/hw/pxa2xx_dma.c b/qemu-0.15.x/hw/pxa2xx_dma.c
new file mode 100644
index 0000000..599581e
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_dma.c
@@ -0,0 +1,568 @@
+/*
+ * Intel XScale PXA255/270 DMA controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "sysbus.h"
+
+#define PXA255_DMA_NUM_CHANNELS 16
+#define PXA27X_DMA_NUM_CHANNELS 32
+
+#define PXA2XX_DMA_NUM_REQUESTS 75
+
+typedef struct {
+    target_phys_addr_t descr;
+    target_phys_addr_t src;
+    target_phys_addr_t dest;
+    uint32_t cmd;
+    uint32_t state;
+    int request;
+} PXA2xxDMAChannel;
+
+typedef struct PXA2xxDMAState {
+    SysBusDevice busdev;
+    qemu_irq irq;
+
+    uint32_t stopintr;
+    uint32_t eorintr;
+    uint32_t rasintr;
+    uint32_t startintr;
+    uint32_t endintr;
+
+    uint32_t align;
+    uint32_t pio;
+
+    int channels;
+    PXA2xxDMAChannel *chan;
+
+    uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
+
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+} PXA2xxDMAState;
+
+#define DCSR0	0x0000	/* DMA Control / Status register for Channel 0 */
+#define DCSR31	0x007c	/* DMA Control / Status register for Channel 31 */
+#define DALGN	0x00a0	/* DMA Alignment register */
+#define DPCSR	0x00a4	/* DMA Programmed I/O Control Status register */
+#define DRQSR0	0x00e0	/* DMA DREQ<0> Status register */
+#define DRQSR1	0x00e4	/* DMA DREQ<1> Status register */
+#define DRQSR2	0x00e8	/* DMA DREQ<2> Status register */
+#define DINT	0x00f0	/* DMA Interrupt register */
+#define DRCMR0	0x0100	/* Request to Channel Map register 0 */
+#define DRCMR63	0x01fc	/* Request to Channel Map register 63 */
+#define D_CH0	0x0200	/* Channel 0 Descriptor start */
+#define DRCMR64	0x1100	/* Request to Channel Map register 64 */
+#define DRCMR74	0x1128	/* Request to Channel Map register 74 */
+
+/* Per-channel register */
+#define DDADR	0x00
+#define DSADR	0x01
+#define DTADR	0x02
+#define DCMD	0x03
+
+/* Bit-field masks */
+#define DRCMR_CHLNUM		0x1f
+#define DRCMR_MAPVLD		(1 << 7)
+#define DDADR_STOP		(1 << 0)
+#define DDADR_BREN		(1 << 1)
+#define DCMD_LEN		0x1fff
+#define DCMD_WIDTH(x)		(1 << ((((x) >> 14) & 3) - 1))
+#define DCMD_SIZE(x)		(4 << (((x) >> 16) & 3))
+#define DCMD_FLYBYT		(1 << 19)
+#define DCMD_FLYBYS		(1 << 20)
+#define DCMD_ENDIRQEN		(1 << 21)
+#define DCMD_STARTIRQEN		(1 << 22)
+#define DCMD_CMPEN		(1 << 25)
+#define DCMD_FLOWTRG		(1 << 28)
+#define DCMD_FLOWSRC		(1 << 29)
+#define DCMD_INCTRGADDR		(1 << 30)
+#define DCMD_INCSRCADDR		(1 << 31)
+#define DCSR_BUSERRINTR		(1 << 0)
+#define DCSR_STARTINTR		(1 << 1)
+#define DCSR_ENDINTR		(1 << 2)
+#define DCSR_STOPINTR		(1 << 3)
+#define DCSR_RASINTR		(1 << 4)
+#define DCSR_REQPEND		(1 << 8)
+#define DCSR_EORINT		(1 << 9)
+#define DCSR_CMPST		(1 << 10)
+#define DCSR_MASKRUN		(1 << 22)
+#define DCSR_RASIRQEN		(1 << 23)
+#define DCSR_CLRCMPST		(1 << 24)
+#define DCSR_SETCMPST		(1 << 25)
+#define DCSR_EORSTOPEN		(1 << 26)
+#define DCSR_EORJMPEN		(1 << 27)
+#define DCSR_EORIRQEN		(1 << 28)
+#define DCSR_STOPIRQEN		(1 << 29)
+#define DCSR_NODESCFETCH	(1 << 30)
+#define DCSR_RUN		(1 << 31)
+
+static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
+{
+    if (ch >= 0) {
+        if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
+                (s->chan[ch].state & DCSR_STOPINTR))
+            s->stopintr |= 1 << ch;
+        else
+            s->stopintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_EORIRQEN) &&
+                (s->chan[ch].state & DCSR_EORINT))
+            s->eorintr |= 1 << ch;
+        else
+            s->eorintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_RASIRQEN) &&
+                (s->chan[ch].state & DCSR_RASINTR))
+            s->rasintr |= 1 << ch;
+        else
+            s->rasintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_STARTINTR)
+            s->startintr |= 1 << ch;
+        else
+            s->startintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_ENDINTR)
+            s->endintr |= 1 << ch;
+        else
+            s->endintr &= ~(1 << ch);
+    }
+
+    if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static inline void pxa2xx_dma_descriptor_fetch(
+                PXA2xxDMAState *s, int ch)
+{
+    uint32_t desc[4];
+    target_phys_addr_t daddr = s->chan[ch].descr & ~0xf;
+    if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
+        daddr += 32;
+
+    cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
+    s->chan[ch].descr = desc[DDADR];
+    s->chan[ch].src = desc[DSADR];
+    s->chan[ch].dest = desc[DTADR];
+    s->chan[ch].cmd = desc[DCMD];
+
+    if (s->chan[ch].cmd & DCMD_FLOWSRC)
+        s->chan[ch].src &= ~3;
+    if (s->chan[ch].cmd & DCMD_FLOWTRG)
+        s->chan[ch].dest &= ~3;
+
+    if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
+        printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
+
+    if (s->chan[ch].cmd & DCMD_STARTIRQEN)
+        s->chan[ch].state |= DCSR_STARTINTR;
+}
+
+static void pxa2xx_dma_run(PXA2xxDMAState *s)
+{
+    int c, srcinc, destinc;
+    uint32_t n, size;
+    uint32_t width;
+    uint32_t length;
+    uint8_t buffer[32];
+    PXA2xxDMAChannel *ch;
+
+    if (s->running ++)
+        return;
+
+    while (s->running) {
+        s->running = 1;
+        for (c = 0; c < s->channels; c ++) {
+            ch = &s->chan[c];
+
+            while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
+                /* Test for pending requests */
+                if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
+                    break;
+
+                length = ch->cmd & DCMD_LEN;
+                size = DCMD_SIZE(ch->cmd);
+                width = DCMD_WIDTH(ch->cmd);
+
+                srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
+                destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
+
+                while (length) {
+                    size = MIN(length, size);
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_read(ch->src, buffer + n, width);
+                        ch->src += srcinc;
+                    }
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_write(ch->dest, buffer + n, width);
+                        ch->dest += destinc;
+                    }
+
+                    length -= size;
+
+                    if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
+                            !ch->request) {
+                        ch->state |= DCSR_EORINT;
+                        if (ch->state & DCSR_EORSTOPEN)
+                            ch->state |= DCSR_STOPINTR;
+                        if ((ch->state & DCSR_EORJMPEN) &&
+                                        !(ch->state & DCSR_NODESCFETCH))
+                            pxa2xx_dma_descriptor_fetch(s, c);
+                        break;
+		    }
+                }
+
+                ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
+
+                /* Is the transfer complete now? */
+                if (!length) {
+                    if (ch->cmd & DCMD_ENDIRQEN)
+                        ch->state |= DCSR_ENDINTR;
+
+                    if ((ch->state & DCSR_NODESCFETCH) ||
+                                (ch->descr & DDADR_STOP) ||
+                                (ch->state & DCSR_EORSTOPEN)) {
+                        ch->state |= DCSR_STOPINTR;
+                        ch->state &= ~DCSR_RUN;
+
+                        break;
+                    }
+
+                    ch->state |= DCSR_STOPINTR;
+                    break;
+                }
+            }
+        }
+
+        s->running --;
+    }
+}
+
+static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
+    unsigned int channel;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+        return s->req[channel];
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        return 0;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+	if (s->chan[channel].request)
+            return s->chan[channel].state | DCSR_REQPEND;
+        return s->chan[channel].state;
+
+    case DINT:
+        return s->stopintr | s->eorintr | s->rasintr |
+                s->startintr | s->endintr;
+
+    case DALGN:
+        return s->align;
+
+    case DPCSR:
+        return s->pio;
+    }
+
+    if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+        channel = (offset - D_CH0) >> 4;
+        switch ((offset & 0x0f) >> 2) {
+        case DDADR:
+            return s->chan[channel].descr;
+        case DSADR:
+            return s->chan[channel].src;
+        case DTADR:
+            return s->chan[channel].dest;
+        case DCMD:
+            return s->chan[channel].cmd;
+        }
+    }
+
+    hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __FUNCTION__, offset);
+    return 7;
+}
+
+static void pxa2xx_dma_write(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
+    unsigned int channel;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+
+        if (value & DRCMR_MAPVLD)
+            if ((value & DRCMR_CHLNUM) > s->channels)
+                hw_error("%s: Bad DMA channel %i\n",
+                         __FUNCTION__, value & DRCMR_CHLNUM);
+
+        s->req[channel] = value;
+        break;
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        /* Nothing to do */
+        break;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+        s->chan[channel].state &= 0x0000071f & ~(value &
+                        (DCSR_EORINT | DCSR_ENDINTR |
+                         DCSR_STARTINTR | DCSR_BUSERRINTR));
+        s->chan[channel].state |= value & 0xfc800000;
+
+        if (s->chan[channel].state & DCSR_STOPIRQEN)
+            s->chan[channel].state &= ~DCSR_STOPINTR;
+
+        if (value & DCSR_NODESCFETCH) {
+            /* No-descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_run(s);
+            }
+        } else {
+            /* Descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_descriptor_fetch(s, channel);
+                pxa2xx_dma_run(s);
+            }
+        }
+
+        /* Shouldn't matter as our DMA is synchronous.  */
+        if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
+            s->chan[channel].state |= DCSR_STOPINTR;
+
+        if (value & DCSR_CLRCMPST)
+            s->chan[channel].state &= ~DCSR_CMPST;
+        if (value & DCSR_SETCMPST)
+            s->chan[channel].state |= DCSR_CMPST;
+
+        pxa2xx_dma_update(s, channel);
+        break;
+
+    case DALGN:
+        s->align = value;
+        break;
+
+    case DPCSR:
+        s->pio = value & 0x80000001;
+        break;
+
+    default:
+        if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+            channel = (offset - D_CH0) >> 4;
+            switch ((offset & 0x0f) >> 2) {
+            case DDADR:
+                s->chan[channel].descr = value;
+                break;
+            case DSADR:
+                s->chan[channel].src = value;
+                break;
+            case DTADR:
+                s->chan[channel].dest = value;
+                break;
+            case DCMD:
+                s->chan[channel].cmd = value;
+                break;
+            default:
+                goto fail;
+            }
+
+            break;
+        }
+    fail:
+        hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset)
+{
+    hw_error("%s: Bad access width\n", __FUNCTION__);
+    return 5;
+}
+
+static void pxa2xx_dma_writebad(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    hw_error("%s: Bad access width\n", __FUNCTION__);
+}
+
+static CPUReadMemoryFunc * const pxa2xx_dma_readfn[] = {
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_read
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_dma_writefn[] = {
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_write
+};
+
+static void pxa2xx_dma_request(void *opaque, int req_num, int on)
+{
+    PXA2xxDMAState *s = opaque;
+    int ch;
+    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
+        hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
+
+    if (!(s->req[req_num] & DRCMR_MAPVLD))
+        return;
+    ch = s->req[req_num] & DRCMR_CHLNUM;
+
+    if (!s->chan[ch].request && on)
+        s->chan[ch].state |= DCSR_RASINTR;
+    else
+        s->chan[ch].state &= ~DCSR_RASINTR;
+    if (s->chan[ch].request && !on)
+        s->chan[ch].state |= DCSR_EORINT;
+
+    s->chan[ch].request = on;
+    if (on) {
+        pxa2xx_dma_run(s);
+        pxa2xx_dma_update(s, ch);
+    }
+}
+
+static int pxa2xx_dma_init(SysBusDevice *dev)
+{
+    int i, iomemtype;
+    PXA2xxDMAState *s;
+    s = FROM_SYSBUS(PXA2xxDMAState, dev);
+
+    if (s->channels <= 0) {
+        return -1;
+    }
+
+    s->chan = qemu_mallocz(sizeof(PXA2xxDMAChannel) * s->channels);
+
+    memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);
+    for (i = 0; i < s->channels; i ++)
+        s->chan[i].state = DCSR_STOPINTR;
+
+    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+
+    qdev_init_gpio_in(&dev->qdev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_dma_readfn,
+                    pxa2xx_dma_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x00010000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+static bool is_version_0(void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static VMStateDescription vmstate_pxa2xx_dma_chan = {
+    .name = "pxa2xx_dma_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINTTL(descr, PXA2xxDMAChannel),
+        VMSTATE_UINTTL(src, PXA2xxDMAChannel),
+        VMSTATE_UINTTL(dest, PXA2xxDMAChannel),
+        VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
+        VMSTATE_UINT32(state, PXA2xxDMAChannel),
+        VMSTATE_INT32(request, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static VMStateDescription vmstate_pxa2xx_dma = {
+    .name = "pxa2xx_dma",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UNUSED_TEST(is_version_0, 4),
+        VMSTATE_UINT32(stopintr, PXA2xxDMAState),
+        VMSTATE_UINT32(eorintr, PXA2xxDMAState),
+        VMSTATE_UINT32(rasintr, PXA2xxDMAState),
+        VMSTATE_UINT32(startintr, PXA2xxDMAState),
+        VMSTATE_UINT32(endintr, PXA2xxDMAState),
+        VMSTATE_UINT32(align, PXA2xxDMAState),
+        VMSTATE_UINT32(pio, PXA2xxDMAState),
+        VMSTATE_BUFFER(req, PXA2xxDMAState),
+        VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
+                vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa2xx_dma_info = {
+    .init       = pxa2xx_dma_init,
+    .qdev.name  = "pxa2xx-dma",
+    .qdev.desc  = "PXA2xx DMA controller",
+    .qdev.size  = sizeof(PXA2xxDMAState),
+    .qdev.vmsd  = &vmstate_pxa2xx_dma,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pxa2xx_dma_register(void)
+{
+    sysbus_register_withprop(&pxa2xx_dma_info);
+}
+device_init(pxa2xx_dma_register);
diff --git a/qemu-0.15.x/hw/pxa2xx_gpio.c b/qemu-0.15.x/hw/pxa2xx_gpio.c
new file mode 100644
index 0000000..200b0cf
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_gpio.c
@@ -0,0 +1,343 @@
+/*
+ * Intel XScale PXA255/270 GPIO controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "pxa.h"
+
+#define PXA2XX_GPIO_BANKS	4
+
+typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
+struct PXA2xxGPIOInfo {
+    SysBusDevice busdev;
+    qemu_irq irq0, irq1, irqX;
+    int lines;
+    int ncpu;
+    CPUState *cpu_env;
+
+    /* XXX: GNU C vectors are more suitable */
+    uint32_t ilevel[PXA2XX_GPIO_BANKS];
+    uint32_t olevel[PXA2XX_GPIO_BANKS];
+    uint32_t dir[PXA2XX_GPIO_BANKS];
+    uint32_t rising[PXA2XX_GPIO_BANKS];
+    uint32_t falling[PXA2XX_GPIO_BANKS];
+    uint32_t status[PXA2XX_GPIO_BANKS];
+    uint32_t gpsr[PXA2XX_GPIO_BANKS];
+    uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
+
+    uint32_t prev_level[PXA2XX_GPIO_BANKS];
+    qemu_irq handler[PXA2XX_GPIO_BANKS * 32];
+    qemu_irq read_notify;
+};
+
+static struct {
+    enum {
+        GPIO_NONE,
+        GPLR,
+        GPSR,
+        GPCR,
+        GPDR,
+        GRER,
+        GFER,
+        GEDR,
+        GAFR_L,
+        GAFR_U,
+    } reg;
+    int bank;
+} pxa2xx_gpio_regs[0x200] = {
+    [0 ... 0x1ff] = { GPIO_NONE, 0 },
+#define PXA2XX_REG(reg, a0, a1, a2, a3)	\
+    [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
+
+    PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
+    PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
+    PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
+    PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
+    PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
+    PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
+    PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
+    PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
+    PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
+};
+
+static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
+{
+    if (s->status[0] & (1 << 0))
+        qemu_irq_raise(s->irq0);
+    else
+        qemu_irq_lower(s->irq0);
+
+    if (s->status[0] & (1 << 1))
+        qemu_irq_raise(s->irq1);
+    else
+        qemu_irq_lower(s->irq1);
+
+    if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
+        qemu_irq_raise(s->irqX);
+    else
+        qemu_irq_lower(s->irqX);
+}
+
+/* Bitmap of pins used as standby and sleep wake-up sources.  */
+static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
+    0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
+};
+
+static void pxa2xx_gpio_set(void *opaque, int line, int level)
+{
+    PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
+    int bank;
+    uint32_t mask;
+
+    if (line >= s->lines) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    bank = line >> 5;
+    mask = 1 << (line & 31);
+
+    if (level) {
+        s->status[bank] |= s->rising[bank] & mask &
+                ~s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] |= mask;
+    } else {
+        s->status[bank] |= s->falling[bank] & mask &
+                s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] &= ~mask;
+    }
+
+    if (s->status[bank] & mask)
+        pxa2xx_gpio_irq_update(s);
+
+    /* Wake-up GPIOs */
+    if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+}
+
+static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
+    uint32_t level, diff;
+    int i, bit, line;
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        level = s->olevel[i] & s->dir[i];
+
+        for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
+            bit = ffs(diff) - 1;
+            line = bit + 32 * i;
+            qemu_set_irq(s->handler[line], (level >> bit) & 1);
+        }
+
+        s->prev_level[i] = level;
+    }
+}
+
+static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
+    uint32_t ret;
+    int bank;
+    if (offset >= 0x200)
+        return 0;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:		/* GPIO Pin-Direction registers */
+        return s->dir[bank];
+
+    case GPSR:		/* GPIO Pin-Output Set registers */
+        printf("%s: Read from a write-only register " REG_FMT "\n",
+                        __FUNCTION__, offset);
+        return s->gpsr[bank];	/* Return last written value.  */
+
+    case GPCR:		/* GPIO Pin-Output Clear registers */
+        printf("%s: Read from a write-only register " REG_FMT "\n",
+                        __FUNCTION__, offset);
+        return 31337;		/* Specified as unpredictable in the docs.  */
+
+    case GRER:		/* GPIO Rising-Edge Detect Enable registers */
+        return s->rising[bank];
+
+    case GFER:		/* GPIO Falling-Edge Detect Enable registers */
+        return s->falling[bank];
+
+    case GAFR_L:	/* GPIO Alternate Function registers */
+        return s->gafr[bank * 2];
+
+    case GAFR_U:	/* GPIO Alternate Function registers */
+        return s->gafr[bank * 2 + 1];
+
+    case GPLR:		/* GPIO Pin-Level registers */
+        ret = (s->olevel[bank] & s->dir[bank]) |
+                (s->ilevel[bank] & ~s->dir[bank]);
+        qemu_irq_raise(s->read_notify);
+        return ret;
+
+    case GEDR:		/* GPIO Edge Detect Status registers */
+        return s->status[bank];
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_gpio_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
+    int bank;
+    if (offset >= 0x200)
+        return;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:		/* GPIO Pin-Direction registers */
+        s->dir[bank] = value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GPSR:		/* GPIO Pin-Output Set registers */
+        s->olevel[bank] |= value;
+        pxa2xx_gpio_handler_update(s);
+        s->gpsr[bank] = value;
+        break;
+
+    case GPCR:		/* GPIO Pin-Output Clear registers */
+        s->olevel[bank] &= ~value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GRER:		/* GPIO Rising-Edge Detect Enable registers */
+        s->rising[bank] = value;
+        break;
+
+    case GFER:		/* GPIO Falling-Edge Detect Enable registers */
+        s->falling[bank] = value;
+        break;
+
+    case GAFR_L:	/* GPIO Alternate Function registers */
+        s->gafr[bank * 2] = value;
+        break;
+
+    case GAFR_U:	/* GPIO Alternate Function registers */
+        s->gafr[bank * 2 + 1] = value;
+        break;
+
+    case GEDR:		/* GPIO Edge Detect Status registers */
+        s->status[bank] &= ~value;
+        pxa2xx_gpio_irq_update(s);
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_gpio_readfn[] = {
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_gpio_writefn[] = {
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write
+};
+
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, DeviceState *pic, int lines)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-gpio");
+    qdev_prop_set_int32(dev, "lines", lines);
+    qdev_prop_set_int32(dev, "ncpu", env->cpu_index);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2,
+                    qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
+
+    return dev;
+}
+
+static int pxa2xx_gpio_initfn(SysBusDevice *dev)
+{
+    int iomemtype;
+    PXA2xxGPIOInfo *s;
+
+    s = FROM_SYSBUS(PXA2xxGPIOInfo, dev);
+
+    s->cpu_env = qemu_get_cpu(s->ncpu);
+
+    qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines);
+    qdev_init_gpio_out(&dev->qdev, s->handler, s->lines);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
+                    pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq0);
+    sysbus_init_irq(dev, &s->irq1);
+    sysbus_init_irq(dev, &s->irqX);
+
+    return 0;
+}
+
+/*
+ * Registers a callback to notify on GPLR reads.  This normally
+ * shouldn't be needed but it is used for the hack on Spitz machines.
+ */
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
+{
+    PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, sysbus_from_qdev(dev));
+    s->read_notify = handler;
+}
+
+static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
+    .name = "pxa2xx-gpio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32(lines, PXA2xxGPIOInfo),
+        VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+        VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa2xx_gpio_info = {
+    .init       = pxa2xx_gpio_initfn,
+    .qdev.name  = "pxa2xx-gpio",
+    .qdev.desc  = "PXA2xx GPIO controller",
+    .qdev.size  = sizeof(PXA2xxGPIOInfo),
+    .qdev.props = (Property []) {
+        DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+        DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void pxa2xx_gpio_register(void)
+{
+    sysbus_register_withprop(&pxa2xx_gpio_info);
+}
+device_init(pxa2xx_gpio_register);
diff --git a/qemu-0.15.x/hw/pxa2xx_keypad.c b/qemu-0.15.x/hw/pxa2xx_keypad.c
new file mode 100644
index 0000000..10ef154
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_keypad.c
@@ -0,0 +1,337 @@
+/*
+ * Intel PXA27X Keypad Controller emulation.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc
+ * Written by Armin Kuster <akuster at kama-aina.net>
+ *              or  <Akuster at mvista.com>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "console.h"
+
+/*
+ * Keypad
+ */
+#define KPC         0x00    /* Keypad Interface Control register */
+#define KPDK        0x08    /* Keypad Interface Direct Key register */
+#define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
+#define KPMK        0x18    /* Keypad Interface Matrix Key register */
+#define KPAS        0x20    /* Keypad Interface Automatic Scan register */
+#define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 0 */
+#define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 1 */
+#define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 2 */
+#define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 3 */
+#define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
+                                register */
+
+/* Keypad defines */
+#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
+#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
+#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
+#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
+#define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
+#define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
+#define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
+#define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
+#define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
+#define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
+#define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
+#define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
+#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
+#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
+#define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
+#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
+#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
+#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
+#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
+#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
+#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
+
+#define KPDK_DKP        (0x1 << 31)
+#define KPDK_DK7        (0x1 <<  7)
+#define KPDK_DK6        (0x1 <<  6)
+#define KPDK_DK5        (0x1 <<  5)
+#define KPDK_DK4        (0x1 <<  4)
+#define KPDK_DK3        (0x1 <<  3)
+#define KPDK_DK2        (0x1 <<  2)
+#define KPDK_DK1        (0x1 <<  1)
+#define KPDK_DK0        (0x1 <<  0)
+
+#define KPREC_OF1       (0x1 << 31)
+#define KPREC_UF1       (0x1 << 30)
+#define KPREC_OF0       (0x1 << 15)
+#define KPREC_UF0       (0x1 << 14)
+
+#define KPMK_MKP        (0x1 << 31)
+#define KPAS_SO         (0x1 << 31)
+#define KPASMKPx_SO     (0x1 << 31)
+
+
+#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
+
+#define PXAKBD_MAXROW   8
+#define PXAKBD_MAXCOL   8
+
+struct PXA2xxKeyPadState {
+    qemu_irq    irq;
+    struct  keymap *map;
+    int         pressed_cnt;
+    int         alt_code;
+
+    uint32_t    kpc;
+    uint32_t    kpdk;
+    uint32_t    kprec;
+    uint32_t    kpmk;
+    uint32_t    kpas;
+    uint32_t    kpasmkp[4];
+    uint32_t    kpkdi;
+};
+
+static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
+{
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        *col = i * 2;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << *row))
+                return;
+        }
+        *col = i * 2 + 1;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << (*row + 16)))
+                return;
+        }
+    }
+}
+
+static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
+{
+    int row, col, rel, assert_irq = 0;
+    uint32_t val;
+
+    if (keycode == 0xe0) {
+        kp->alt_code = 1;
+        return;
+    }
+
+    if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
+        return;
+
+    if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) {
+        if(kp->kpc & KPC_AS)
+            kp->kpc &= ~(KPC_AS);
+
+        rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
+        keycode &= ~(0x80); /* strip qemu key release bit */
+        if (kp->alt_code) {
+            keycode |= 0x80;
+            kp->alt_code = 0;
+        }
+
+        row = kp->map[keycode].row;
+        col = kp->map[keycode].column;
+        if(row == -1 || col == -1)
+            return;
+
+        val = KPASMKPx_MKC(row, col);
+        if (rel) {
+            if (kp->kpasmkp[col / 2] & val) {
+                kp->kpasmkp[col / 2] &= ~val;
+                kp->pressed_cnt--;
+                assert_irq = 1;
+            }
+        } else {
+            if (!(kp->kpasmkp[col / 2] & val)) {
+                kp->kpasmkp[col / 2] |= val;
+                kp->pressed_cnt++;
+                assert_irq = 1;
+            }
+        }
+        kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
+        if (kp->pressed_cnt == 1) {
+            kp->kpas &= ~((0xf << 4) | 0xf);
+            if (rel)
+                pxa27x_keypad_find_pressed_key(kp, &row, &col);
+            kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
+        }
+        goto out;
+    }
+    return;
+
+out:
+    if (assert_irq && (kp->kpc & KPC_MIE)) {
+        kp->kpc |= KPC_MI;
+        qemu_irq_raise(kp->irq);
+    }
+    return;
+}
+
+static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+    uint32_t tmp;
+
+    switch (offset) {
+    case KPC:
+        tmp = s->kpc;
+        if(tmp & KPC_MI)
+            s->kpc &= ~(KPC_MI);
+        if(tmp & KPC_DI)
+            s->kpc &= ~(KPC_DI);
+        qemu_irq_lower(s->irq);
+        return tmp;
+        break;
+    case KPDK:
+        return s->kpdk;
+        break;
+    case KPREC:
+        tmp = s->kprec;
+        if(tmp & KPREC_OF1)
+            s->kprec &= ~(KPREC_OF1);
+        if(tmp & KPREC_UF1)
+            s->kprec &= ~(KPREC_UF1);
+        if(tmp & KPREC_OF0)
+            s->kprec &= ~(KPREC_OF0);
+        if(tmp & KPREC_UF0)
+            s->kprec &= ~(KPREC_UF0);
+        return tmp;
+        break;
+    case KPMK:
+        tmp = s->kpmk;
+        if(tmp & KPMK_MKP)
+            s->kpmk &= ~(KPMK_MKP);
+        return tmp;
+        break;
+    case KPAS:
+        return s->kpas;
+        break;
+    case KPASMKP0:
+        return s->kpasmkp[0];
+        break;
+    case KPASMKP1:
+        return s->kpasmkp[1];
+        break;
+    case KPASMKP2:
+        return s->kpasmkp[2];
+        break;
+    case KPASMKP3:
+        return s->kpasmkp[3];
+        break;
+    case KPKDI:
+        return s->kpkdi;
+        break;
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_keypad_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+
+    switch (offset) {
+    case KPC:
+        s->kpc = value;
+        break;
+    case KPDK:
+        s->kpdk = value;
+        break;
+    case KPREC:
+        s->kprec = value;
+        break;
+    case KPMK:
+        s->kpmk = value;
+        break;
+    case KPAS:
+        s->kpas = value;
+        break;
+    case KPASMKP0:
+        s->kpasmkp[0] = value;
+        break;
+    case KPASMKP1:
+        s->kpasmkp[1] = value;
+        break;
+    case KPASMKP2:
+        s->kpasmkp[2] = value;
+        break;
+    case KPASMKP3:
+        s->kpasmkp[3] = value;
+        break;
+    case KPKDI:
+        s->kpkdi = value;
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_keypad_readfn[] = {
+    pxa2xx_keypad_read,
+    pxa2xx_keypad_read,
+    pxa2xx_keypad_read
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_keypad_writefn[] = {
+    pxa2xx_keypad_write,
+    pxa2xx_keypad_write,
+    pxa2xx_keypad_write
+};
+
+static const VMStateDescription vmstate_pxa2xx_keypad = {
+    .name = "pxa2xx_keypad",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
+        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
+        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
+        qemu_irq irq)
+{
+    int iomemtype;
+    PXA2xxKeyPadState *s;
+
+    s = (PXA2xxKeyPadState *) qemu_mallocz(sizeof(PXA2xxKeyPadState));
+    s->irq = irq;
+
+    iomemtype = cpu_register_io_memory(pxa2xx_keypad_readfn,
+                    pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
+
+    return s;
+}
+
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
+        int size)
+{
+    if(!map || size < 0x80) {
+        fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    kp->map = map;
+    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
+}
diff --git a/qemu-0.15.x/hw/pxa2xx_lcd.c b/qemu-0.15.x/hw/pxa2xx_lcd.c
new file mode 100644
index 0000000..a5f8c51
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_lcd.c
@@ -0,0 +1,1045 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "pxa.h"
+#include "pixel_ops.h"
+/* FIXME: For graphic_rotate. Should probably be done in common code.  */
+#include "sysemu.h"
+#include "framebuffer.h"
+
+struct DMAChannel {
+    target_phys_addr_t branch;
+    uint8_t up;
+    uint8_t palette[1024];
+    uint8_t pbuffer[1024];
+    void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr,
+                   int *miny, int *maxy);
+
+    target_phys_addr_t descriptor;
+    target_phys_addr_t source;
+    uint32_t id;
+    uint32_t command;
+};
+
+struct PXA2xxLCDState {
+    qemu_irq irq;
+    int irqlevel;
+
+    int invalidated;
+    DisplayState *ds;
+    drawfn *line_fn[2];
+    int dest_width;
+    int xres, yres;
+    int pal_for;
+    int transp;
+    enum {
+        pxa_lcdc_2bpp = 1,
+        pxa_lcdc_4bpp = 2,
+        pxa_lcdc_8bpp = 3,
+        pxa_lcdc_16bpp = 4,
+        pxa_lcdc_18bpp = 5,
+        pxa_lcdc_18pbpp = 6,
+        pxa_lcdc_19bpp = 7,
+        pxa_lcdc_19pbpp = 8,
+        pxa_lcdc_24bpp = 9,
+        pxa_lcdc_25bpp = 10,
+    } bpp;
+
+    uint32_t control[6];
+    uint32_t status[2];
+    uint32_t ovl1c[2];
+    uint32_t ovl2c[2];
+    uint32_t ccr;
+    uint32_t cmdcr;
+    uint32_t trgbr;
+    uint32_t tcr;
+    uint32_t liidr;
+    uint8_t bscntr;
+
+    struct DMAChannel dma_ch[7];
+
+    qemu_irq vsync_cb;
+    int orientation;
+};
+
+typedef struct __attribute__ ((__packed__)) {
+    uint32_t fdaddr;
+    uint32_t fsaddr;
+    uint32_t fidr;
+    uint32_t ldcmd;
+} PXAFrameDescriptor;
+
+#define LCCR0	0x000	/* LCD Controller Control register 0 */
+#define LCCR1	0x004	/* LCD Controller Control register 1 */
+#define LCCR2	0x008	/* LCD Controller Control register 2 */
+#define LCCR3	0x00c	/* LCD Controller Control register 3 */
+#define LCCR4	0x010	/* LCD Controller Control register 4 */
+#define LCCR5	0x014	/* LCD Controller Control register 5 */
+
+#define FBR0	0x020	/* DMA Channel 0 Frame Branch register */
+#define FBR1	0x024	/* DMA Channel 1 Frame Branch register */
+#define FBR2	0x028	/* DMA Channel 2 Frame Branch register */
+#define FBR3	0x02c	/* DMA Channel 3 Frame Branch register */
+#define FBR4	0x030	/* DMA Channel 4 Frame Branch register */
+#define FBR5	0x110	/* DMA Channel 5 Frame Branch register */
+#define FBR6	0x114	/* DMA Channel 6 Frame Branch register */
+
+#define LCSR1	0x034	/* LCD Controller Status register 1 */
+#define LCSR0	0x038	/* LCD Controller Status register 0 */
+#define LIIDR	0x03c	/* LCD Controller Interrupt ID register */
+
+#define TRGBR	0x040	/* TMED RGB Seed register */
+#define TCR	0x044	/* TMED Control register */
+
+#define OVL1C1	0x050	/* Overlay 1 Control register 1 */
+#define OVL1C2	0x060	/* Overlay 1 Control register 2 */
+#define OVL2C1	0x070	/* Overlay 2 Control register 1 */
+#define OVL2C2	0x080	/* Overlay 2 Control register 2 */
+#define CCR	0x090	/* Cursor Control register */
+
+#define CMDCR	0x100	/* Command Control register */
+#define PRSR	0x104	/* Panel Read Status register */
+
+#define PXA_LCDDMA_CHANS	7
+#define DMA_FDADR		0x00	/* Frame Descriptor Address register */
+#define DMA_FSADR		0x04	/* Frame Source Address register */
+#define DMA_FIDR		0x08	/* Frame ID register */
+#define DMA_LDCMD		0x0c	/* Command register */
+
+/* LCD Buffer Strength Control register */
+#define BSCNTR	0x04000054
+
+/* Bitfield masks */
+#define LCCR0_ENB	(1 << 0)
+#define LCCR0_CMS	(1 << 1)
+#define LCCR0_SDS	(1 << 2)
+#define LCCR0_LDM	(1 << 3)
+#define LCCR0_SOFM0	(1 << 4)
+#define LCCR0_IUM	(1 << 5)
+#define LCCR0_EOFM0	(1 << 6)
+#define LCCR0_PAS	(1 << 7)
+#define LCCR0_DPD	(1 << 9)
+#define LCCR0_DIS	(1 << 10)
+#define LCCR0_QDM	(1 << 11)
+#define LCCR0_PDD	(0xff << 12)
+#define LCCR0_BSM0	(1 << 20)
+#define LCCR0_OUM	(1 << 21)
+#define LCCR0_LCDT	(1 << 22)
+#define LCCR0_RDSTM	(1 << 23)
+#define LCCR0_CMDIM	(1 << 24)
+#define LCCR0_OUC	(1 << 25)
+#define LCCR0_LDDALT	(1 << 26)
+#define LCCR1_PPL(x)	((x) & 0x3ff)
+#define LCCR2_LPP(x)	((x) & 0x3ff)
+#define LCCR3_API	(15 << 16)
+#define LCCR3_BPP(x)	((((x) >> 24) & 7) | (((x) >> 26) & 8))
+#define LCCR3_PDFOR(x)	(((x) >> 30) & 3)
+#define LCCR4_K1(x)	(((x) >> 0) & 7)
+#define LCCR4_K2(x)	(((x) >> 3) & 7)
+#define LCCR4_K3(x)	(((x) >> 6) & 7)
+#define LCCR4_PALFOR(x)	(((x) >> 15) & 3)
+#define LCCR5_SOFM(ch)	(1 << (ch - 1))
+#define LCCR5_EOFM(ch)	(1 << (ch + 7))
+#define LCCR5_BSM(ch)	(1 << (ch + 15))
+#define LCCR5_IUM(ch)	(1 << (ch + 23))
+#define OVLC1_EN	(1 << 31)
+#define CCR_CEN		(1 << 31)
+#define FBR_BRA		(1 << 0)
+#define FBR_BINT	(1 << 1)
+#define FBR_SRCADDR	(0xfffffff << 4)
+#define LCSR0_LDD	(1 << 0)
+#define LCSR0_SOF0	(1 << 1)
+#define LCSR0_BER	(1 << 2)
+#define LCSR0_ABC	(1 << 3)
+#define LCSR0_IU0	(1 << 4)
+#define LCSR0_IU1	(1 << 5)
+#define LCSR0_OU	(1 << 6)
+#define LCSR0_QD	(1 << 7)
+#define LCSR0_EOF0	(1 << 8)
+#define LCSR0_BS0	(1 << 9)
+#define LCSR0_SINT	(1 << 10)
+#define LCSR0_RDST	(1 << 11)
+#define LCSR0_CMDINT	(1 << 12)
+#define LCSR0_BERCH(x)	(((x) & 7) << 28)
+#define LCSR1_SOF(ch)	(1 << (ch - 1))
+#define LCSR1_EOF(ch)	(1 << (ch + 7))
+#define LCSR1_BS(ch)	(1 << (ch + 15))
+#define LCSR1_IU(ch)	(1 << (ch + 23))
+#define LDCMD_LENGTH(x)	((x) & 0x001ffffc)
+#define LDCMD_EOFINT	(1 << 21)
+#define LDCMD_SOFINT	(1 << 22)
+#define LDCMD_PAL	(1 << 26)
+
+/* Route internal interrupt lines to the global IC */
+static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
+{
+    int level = 0;
+    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
+    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
+    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
+    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
+    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
+    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
+    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
+    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
+    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
+    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
+    level |= (s->status[1] & ~s->control[5]);
+
+    qemu_set_irq(s->irq, !!level);
+    s->irqlevel = level;
+}
+
+/* Set Branch Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (ch == 0) {
+        s->status[0] |= LCSR0_BS0;
+        unmasked = !(s->control[0] & LCCR0_BSM0);
+    } else {
+        s->status[1] |= LCSR1_BS(ch);
+        unmasked = !(s->control[5] & LCCR5_BSM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Start Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_SOF0;
+        unmasked = !(s->control[0] & LCCR0_SOFM0);
+    } else {
+        s->status[1] |= LCSR1_SOF(ch);
+        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set End Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_EOF0;
+        unmasked = !(s->control[0] & LCCR0_EOFM0);
+    } else {
+        s->status[1] |= LCSR1_EOF(ch);
+        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Bus Error Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
+{
+    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
+    if (s->irqlevel)
+        s->status[0] |= LCSR0_SINT;
+    else
+        s->liidr = s->dma_ch[ch].id;
+}
+
+/* Set Read Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
+{
+    s->status[0] |= LCSR0_RDST;
+    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
+        s->status[0] |= LCSR0_SINT;
+}
+
+/* Load new Frame Descriptors from DMA */
+static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
+{
+    PXAFrameDescriptor desc;
+    target_phys_addr_t descptr;
+    int i;
+
+    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
+        s->dma_ch[i].source = 0;
+
+        if (!s->dma_ch[i].up)
+            continue;
+
+        if (s->dma_ch[i].branch & FBR_BRA) {
+            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
+            if (s->dma_ch[i].branch & FBR_BINT)
+                pxa2xx_dma_bs_set(s, i);
+            s->dma_ch[i].branch &= ~FBR_BRA;
+        } else
+            descptr = s->dma_ch[i].descriptor;
+
+        if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
+                    sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size))
+            continue;
+
+        cpu_physical_memory_read(descptr, (void *)&desc, sizeof(desc));
+        s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
+        s->dma_ch[i].source = tswap32(desc.fsaddr);
+        s->dma_ch[i].id = tswap32(desc.fidr);
+        s->dma_ch[i].command = tswap32(desc.ldcmd);
+    }
+}
+
+static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        return s->control[0];
+    case LCCR1:
+        return s->control[1];
+    case LCCR2:
+        return s->control[2];
+    case LCCR3:
+        return s->control[3];
+    case LCCR4:
+        return s->control[4];
+    case LCCR5:
+        return s->control[5];
+
+    case OVL1C1:
+        return s->ovl1c[0];
+    case OVL1C2:
+        return s->ovl1c[1];
+    case OVL2C1:
+        return s->ovl2c[0];
+    case OVL2C2:
+        return s->ovl2c[1];
+
+    case CCR:
+        return s->ccr;
+
+    case CMDCR:
+        return s->cmdcr;
+
+    case TRGBR:
+        return s->trgbr;
+    case TCR:
+        return s->tcr;
+
+    case 0x200 ... 0x1000:	/* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            return s->dma_ch[ch].descriptor;
+        case DMA_FSADR:
+            return s->dma_ch[ch].source;
+        case DMA_FIDR:
+            return s->dma_ch[ch].id;
+        case DMA_LDCMD:
+            return s->dma_ch[ch].command;
+        default:
+            goto fail;
+        }
+
+    case FBR0:
+        return s->dma_ch[0].branch;
+    case FBR1:
+        return s->dma_ch[1].branch;
+    case FBR2:
+        return s->dma_ch[2].branch;
+    case FBR3:
+        return s->dma_ch[3].branch;
+    case FBR4:
+        return s->dma_ch[4].branch;
+    case FBR5:
+        return s->dma_ch[5].branch;
+    case FBR6:
+        return s->dma_ch[6].branch;
+
+    case BSCNTR:
+        return s->bscntr;
+
+    case PRSR:
+        return 0;
+
+    case LCSR0:
+        return s->status[0];
+    case LCSR1:
+        return s->status[1];
+    case LIIDR:
+        return s->liidr;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_lcdc_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        /* ACK Quick Disable done */
+        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
+            s->status[0] |= LCSR0_QD;
+
+        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
+            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
+
+        if ((s->control[3] & LCCR3_API) &&
+                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
+            s->status[0] |= LCSR0_ABC;
+
+        s->control[0] = value & 0x07ffffff;
+        pxa2xx_lcdc_int_update(s);
+
+        s->dma_ch[0].up = !!(value & LCCR0_ENB);
+        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
+        break;
+
+    case LCCR1:
+        s->control[1] = value;
+        break;
+
+    case LCCR2:
+        s->control[2] = value;
+        break;
+
+    case LCCR3:
+        s->control[3] = value & 0xefffffff;
+        s->bpp = LCCR3_BPP(value);
+        break;
+
+    case LCCR4:
+        s->control[4] = value & 0x83ff81ff;
+        break;
+
+    case LCCR5:
+        s->control[5] = value & 0x3f3f3f3f;
+        break;
+
+    case OVL1C1:
+        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
+
+        s->ovl1c[0] = value & 0x80ffffff;
+        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
+        break;
+
+    case OVL1C2:
+        s->ovl1c[1] = value & 0x000fffff;
+        break;
+
+    case OVL2C1:
+        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
+
+        s->ovl2c[0] = value & 0x80ffffff;
+        s->dma_ch[2].up = !!(value & OVLC1_EN);
+        s->dma_ch[3].up = !!(value & OVLC1_EN);
+        s->dma_ch[4].up = !!(value & OVLC1_EN);
+        break;
+
+    case OVL2C2:
+        s->ovl2c[1] = value & 0x007fffff;
+        break;
+
+    case CCR:
+        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
+            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
+
+        s->ccr = value & 0x81ffffe7;
+        s->dma_ch[5].up = !!(value & CCR_CEN);
+        break;
+
+    case CMDCR:
+        s->cmdcr = value & 0xff;
+        break;
+
+    case TRGBR:
+        s->trgbr = value & 0x00ffffff;
+        break;
+
+    case TCR:
+        s->tcr = value & 0x7fff;
+        break;
+
+    case 0x200 ... 0x1000:	/* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            s->dma_ch[ch].descriptor = value & 0xfffffff0;
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case FBR0:
+        s->dma_ch[0].branch = value & 0xfffffff3;
+        break;
+    case FBR1:
+        s->dma_ch[1].branch = value & 0xfffffff3;
+        break;
+    case FBR2:
+        s->dma_ch[2].branch = value & 0xfffffff3;
+        break;
+    case FBR3:
+        s->dma_ch[3].branch = value & 0xfffffff3;
+        break;
+    case FBR4:
+        s->dma_ch[4].branch = value & 0xfffffff3;
+        break;
+    case FBR5:
+        s->dma_ch[5].branch = value & 0xfffffff3;
+        break;
+    case FBR6:
+        s->dma_ch[6].branch = value & 0xfffffff3;
+        break;
+
+    case BSCNTR:
+        s->bscntr = value & 0xf;
+        break;
+
+    case PRSR:
+        break;
+
+    case LCSR0:
+        s->status[0] &= ~(value & 0xfff);
+        if (value & LCSR0_BER)
+            s->status[0] &= ~LCSR0_BERCH(7);
+        break;
+
+    case LCSR1:
+        s->status[1] &= ~(value & 0x3e3f3f);
+        break;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_lcdc_readfn[] = {
+    pxa2xx_lcdc_read,
+    pxa2xx_lcdc_read,
+    pxa2xx_lcdc_read
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_lcdc_writefn[] = {
+    pxa2xx_lcdc_write,
+    pxa2xx_lcdc_write,
+    pxa2xx_lcdc_write
+};
+
+/* Load new palette for a given DMA channel, convert to internal format */
+static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
+{
+    int i, n, format, r, g, b, alpha;
+    uint32_t *dest, *src;
+    s->pal_for = LCCR4_PALFOR(s->control[4]);
+    format = s->pal_for;
+
+    switch (bpp) {
+    case pxa_lcdc_2bpp:
+        n = 4;
+        break;
+    case pxa_lcdc_4bpp:
+        n = 16;
+        break;
+    case pxa_lcdc_8bpp:
+        n = 256;
+        break;
+    default:
+        format = 0;
+        return;
+    }
+
+    src = (uint32_t *) s->dma_ch[ch].pbuffer;
+    dest = (uint32_t *) s->dma_ch[ch].palette;
+    alpha = r = g = b = 0;
+
+    for (i = 0; i < n; i ++) {
+        switch (format) {
+        case 0: /* 16 bpp, no transparency */
+            alpha = 0;
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf800) >> 8;
+                g = (*src & 0x07e0) >> 3;
+                b = (*src & 0x001f) << 3;
+            }
+            break;
+        case 1: /* 16 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf800) >> 8;
+                g = (*src & 0x07e0) >> 3;
+                b = (*src & 0x001f) << 3;
+            }
+            break;
+        case 2: /* 18 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf80000) >> 16;
+                g = (*src & 0x00fc00) >> 8;
+                b = (*src & 0x0000f8);
+            }
+            break;
+        case 3: /* 24 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xff0000) >> 16;
+                g = (*src & 0x00ff00) >> 8;
+                b = (*src & 0x0000ff);
+            }
+            break;
+        }
+        switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            *dest = rgb_to_pixel8(r, g, b) | alpha;
+            break;
+        case 15:
+            *dest = rgb_to_pixel15(r, g, b) | alpha;
+            break;
+        case 16:
+            *dest = rgb_to_pixel16(r, g, b) | alpha;
+            break;
+        case 24:
+            *dest = rgb_to_pixel24(r, g, b) | alpha;
+            break;
+        case 32:
+            *dest = rgb_to_pixel32(r, g, b) | alpha;
+            break;
+        }
+        src ++;
+        dest ++;
+    }
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
+                target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, dest_width, s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
+               target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, s->dest_width, -dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
+                target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, -dest_width, -s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
+               target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds,
+                               addr, s->xres, s->yres,
+                               src_width, -s->dest_width, dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
+static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
+{
+    int width, height;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    width = LCCR1_PPL(s->control[1]) + 1;
+    height = LCCR2_LPP(s->control[2]) + 1;
+
+    if (width != s->xres || height != s->yres) {
+        if (s->orientation == 90 || s->orientation == 270) {
+            qemu_console_resize(s->ds, height, width);
+        } else {
+            qemu_console_resize(s->ds, width, height);
+        }
+        s->invalidated = 1;
+        s->xres = width;
+        s->yres = height;
+    }
+}
+
+static void pxa2xx_update_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    target_phys_addr_t fbptr;
+    int miny, maxy;
+    int ch;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    pxa2xx_descriptor_load(s);
+
+    pxa2xx_lcdc_resize(s);
+    miny = s->yres;
+    maxy = 0;
+    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
+    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
+    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
+        if (s->dma_ch[ch].up) {
+            if (!s->dma_ch[ch].source) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+            fbptr = s->dma_ch[ch].source;
+            if (!(fbptr >= PXA2XX_SDRAM_BASE &&
+                    fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+
+            if (s->dma_ch[ch].command & LDCMD_PAL) {
+                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
+                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+                        sizeof(s->dma_ch[ch].pbuffer)));
+                pxa2xx_palette_parse(s, ch, s->bpp);
+            } else {
+                /* Do we need to reparse palette */
+                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
+                    pxa2xx_palette_parse(s, ch, s->bpp);
+
+                /* ACK frame start */
+                pxa2xx_dma_sof_set(s, ch);
+
+                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
+                s->invalidated = 0;
+
+                /* ACK frame completed */
+                pxa2xx_dma_eof_set(s, ch);
+            }
+        }
+
+    if (s->control[0] & LCCR0_DIS) {
+        /* ACK last frame completed */
+        s->control[0] &= ~LCCR0_ENB;
+        s->status[0] |= LCSR0_LDD;
+    }
+
+    if (miny >= 0) {
+        switch (s->orientation) {
+        case 0:
+            dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
+            break;
+        case 90:
+            dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
+            break;
+        case 180:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
+            break;
+        case 270:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
+            break;
+        }
+    }
+    pxa2xx_lcdc_int_update(s);
+
+    qemu_irq_raise(s->vsync_cb);
+}
+
+static void pxa2xx_invalidate_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    s->invalidated = 1;
+}
+
+static void pxa2xx_screen_dump(void *opaque, const char *filename)
+{
+    /* TODO */
+}
+
+static void pxa2xx_lcdc_orientation(void *opaque, int angle)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+
+    switch (angle) {
+    case 0:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
+        break;
+    case 90:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
+        break;
+    case 180:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
+        break;
+    case 270:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
+        break;
+    }
+
+    s->orientation = angle;
+    s->xres = s->yres = -1;
+    pxa2xx_lcdc_resize(s);
+}
+
+static const VMStateDescription vmstate_dma_channel = {
+    .name = "dma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINTTL(branch, struct DMAChannel),
+        VMSTATE_UINT8(up, struct DMAChannel),
+        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
+        VMSTATE_UINTTL(descriptor, struct DMAChannel),
+        VMSTATE_UINTTL(source, struct DMAChannel),
+        VMSTATE_UINT32(id, struct DMAChannel),
+        VMSTATE_UINT32(command, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
+{
+    PXA2xxLCDState *s = opaque;
+
+    s->bpp = LCCR3_BPP(s->control[3]);
+    s->xres = s->yres = s->pal_for = -1;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_lcdc = {
+    .name = "pxa2xx_lcdc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_lcdc_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
+        VMSTATE_INT32(transp, PXA2xxLCDState),
+        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
+        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32(ccr, PXA2xxLCDState),
+        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
+        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
+        VMSTATE_UINT32(tcr, PXA2xxLCDState),
+        VMSTATE_UINT32(liidr, PXA2xxLCDState),
+        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
+        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
+                             vmstate_dma_channel, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define BITS 8
+#include "pxa2xx_template.h"
+#define BITS 15
+#include "pxa2xx_template.h"
+#define BITS 16
+#include "pxa2xx_template.h"
+#define BITS 24
+#include "pxa2xx_template.h"
+#define BITS 32
+#include "pxa2xx_template.h"
+
+PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq)
+{
+    int iomemtype;
+    PXA2xxLCDState *s;
+
+    s = (PXA2xxLCDState *) qemu_mallocz(sizeof(PXA2xxLCDState));
+    s->invalidated = 1;
+    s->irq = irq;
+
+    pxa2xx_lcdc_orientation(s, graphic_rotate);
+
+    iomemtype = cpu_register_io_memory(pxa2xx_lcdc_readfn,
+                    pxa2xx_lcdc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    s->ds = graphic_console_init(pxa2xx_update_display,
+                                 pxa2xx_invalidate_display,
+                                 pxa2xx_screen_dump, NULL, s);
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        s->dest_width = 0;
+        break;
+    case 8:
+        s->line_fn[0] = pxa2xx_draw_fn_8;
+        s->line_fn[1] = pxa2xx_draw_fn_8t;
+        s->dest_width = 1;
+        break;
+    case 15:
+        s->line_fn[0] = pxa2xx_draw_fn_15;
+        s->line_fn[1] = pxa2xx_draw_fn_15t;
+        s->dest_width = 2;
+        break;
+    case 16:
+        s->line_fn[0] = pxa2xx_draw_fn_16;
+        s->line_fn[1] = pxa2xx_draw_fn_16t;
+        s->dest_width = 2;
+        break;
+    case 24:
+        s->line_fn[0] = pxa2xx_draw_fn_24;
+        s->line_fn[1] = pxa2xx_draw_fn_24t;
+        s->dest_width = 3;
+        break;
+    case 32:
+        s->line_fn[0] = pxa2xx_draw_fn_32;
+        s->line_fn[1] = pxa2xx_draw_fn_32t;
+        s->dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
+
+    return s;
+}
+
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
+{
+    s->vsync_cb = handler;
+}
diff --git a/qemu-0.15.x/hw/pxa2xx_mmci.c b/qemu-0.15.x/hw/pxa2xx_mmci.c
new file mode 100644
index 0000000..d86f735
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_mmci.c
@@ -0,0 +1,549 @@
+/*
+ * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "sd.h"
+#include "qdev.h"
+
+struct PXA2xxMMCIState {
+    qemu_irq irq;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
+
+    SDState *card;
+
+    uint32_t status;
+    uint32_t clkrt;
+    uint32_t spi;
+    uint32_t cmdat;
+    uint32_t resp_tout;
+    uint32_t read_tout;
+    int blklen;
+    int numblk;
+    uint32_t intmask;
+    uint32_t intreq;
+    int cmd;
+    uint32_t arg;
+
+    int active;
+    int bytesleft;
+    uint8_t tx_fifo[64];
+    int tx_start;
+    int tx_len;
+    uint8_t rx_fifo[32];
+    int rx_start;
+    int rx_len;
+    uint16_t resp_fifo[9];
+    int resp_len;
+
+    int cmdreq;
+    int ac_width;
+};
+
+#define MMC_STRPCL	0x00	/* MMC Clock Start/Stop register */
+#define MMC_STAT	0x04	/* MMC Status register */
+#define MMC_CLKRT	0x08	/* MMC Clock Rate register */
+#define MMC_SPI		0x0c	/* MMC SPI Mode register */
+#define MMC_CMDAT	0x10	/* MMC Command/Data register */
+#define MMC_RESTO	0x14	/* MMC Response Time-Out register */
+#define MMC_RDTO	0x18	/* MMC Read Time-Out register */
+#define MMC_BLKLEN	0x1c	/* MMC Block Length register */
+#define MMC_NUMBLK	0x20	/* MMC Number of Blocks register */
+#define MMC_PRTBUF	0x24	/* MMC Buffer Partly Full register */
+#define MMC_I_MASK	0x28	/* MMC Interrupt Mask register */
+#define MMC_I_REG	0x2c	/* MMC Interrupt Request register */
+#define MMC_CMD		0x30	/* MMC Command register */
+#define MMC_ARGH	0x34	/* MMC Argument High register */
+#define MMC_ARGL	0x38	/* MMC Argument Low register */
+#define MMC_RES		0x3c	/* MMC Response FIFO */
+#define MMC_RXFIFO	0x40	/* MMC Receive FIFO */
+#define MMC_TXFIFO	0x44	/* MMC Transmit FIFO */
+#define MMC_RDWAIT	0x48	/* MMC RD_WAIT register */
+#define MMC_BLKS_REM	0x4c	/* MMC Blocks Remaining register */
+
+/* Bitfield masks */
+#define STRPCL_STOP_CLK	(1 << 0)
+#define STRPCL_STRT_CLK	(1 << 1)
+#define STAT_TOUT_RES	(1 << 1)
+#define STAT_CLK_EN	(1 << 8)
+#define STAT_DATA_DONE	(1 << 11)
+#define STAT_PRG_DONE	(1 << 12)
+#define STAT_END_CMDRES	(1 << 13)
+#define SPI_SPI_MODE	(1 << 0)
+#define CMDAT_RES_TYPE	(3 << 0)
+#define CMDAT_DATA_EN	(1 << 2)
+#define CMDAT_WR_RD	(1 << 3)
+#define CMDAT_DMA_EN	(1 << 7)
+#define CMDAT_STOP_TRAN	(1 << 10)
+#define INT_DATA_DONE	(1 << 0)
+#define INT_PRG_DONE	(1 << 1)
+#define INT_END_CMD	(1 << 2)
+#define INT_STOP_CMD	(1 << 3)
+#define INT_CLK_OFF	(1 << 4)
+#define INT_RXFIFO_REQ	(1 << 5)
+#define INT_TXFIFO_REQ	(1 << 6)
+#define INT_TINT	(1 << 7)
+#define INT_DAT_ERR	(1 << 8)
+#define INT_RES_ERR	(1 << 9)
+#define INT_RD_STALLED	(1 << 10)
+#define INT_SDIO_INT	(1 << 11)
+#define INT_SDIO_SACK	(1 << 12)
+#define PRTBUF_PRT_BUF	(1 << 0)
+
+/* Route internal interrupt lines to the global IC and DMA */
+static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
+{
+    uint32_t mask = s->intmask;
+    if (s->cmdat & CMDAT_DMA_EN) {
+        mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
+
+        qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
+        qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
+    }
+
+    qemu_set_irq(s->irq, !!(s->intreq & ~mask));
+}
+
+static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
+{
+    if (!s->active)
+        return;
+
+    if (s->cmdat & CMDAT_WR_RD) {
+        while (s->bytesleft && s->tx_len) {
+            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
+            s->tx_start &= 0x1f;
+            s->tx_len --;
+            s->bytesleft --;
+        }
+        if (s->bytesleft)
+            s->intreq |= INT_TXFIFO_REQ;
+    } else
+        while (s->bytesleft && s->rx_len < 32) {
+            s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
+                sd_read_data(s->card);
+            s->bytesleft --;
+            s->intreq |= INT_RXFIFO_REQ;
+        }
+
+    if (!s->bytesleft) {
+        s->active = 0;
+        s->intreq |= INT_DATA_DONE;
+        s->status |= STAT_DATA_DONE;
+
+        if (s->cmdat & CMDAT_WR_RD) {
+            s->intreq |= INT_PRG_DONE;
+            s->status |= STAT_PRG_DONE;
+        }
+    }
+
+    pxa2xx_mmci_int_update(s);
+}
+
+static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
+{
+    int rsplen, i;
+    SDRequest request;
+    uint8_t response[16];
+
+    s->active = 1;
+    s->rx_len = 0;
+    s->tx_len = 0;
+    s->cmdreq = 0;
+
+    request.cmd = s->cmd;
+    request.arg = s->arg;
+    request.crc = 0;	/* FIXME */
+
+    rsplen = sd_do_command(s->card, &request, response);
+    s->intreq |= INT_END_CMD;
+
+    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
+    switch (s->cmdat & CMDAT_RES_TYPE) {
+#define PXAMMCI_RESP(wd, value0, value1)	\
+        s->resp_fifo[(wd) + 0] |= (value0);	\
+        s->resp_fifo[(wd) + 1] |= (value1) << 8;
+    case 0:	/* No response */
+        goto complete;
+
+    case 1:	/* R1, R4, R5 or R6 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    case 2:	/* R2 */
+        if (rsplen < 16)
+            goto timeout;
+        goto complete;
+
+    case 3:	/* R3 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    complete:
+        for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
+            PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
+        }
+        s->status |= STAT_END_CMDRES;
+
+        if (!(s->cmdat & CMDAT_DATA_EN))
+            s->active = 0;
+        else
+            s->bytesleft = s->numblk * s->blklen;
+
+        s->resp_len = 0;
+        break;
+
+    timeout:
+        s->active = 0;
+        s->status |= STAT_TOUT_RES;
+        break;
+    }
+
+    pxa2xx_mmci_fifo_update(s);
+}
+
+static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    uint32_t ret;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        return 0;
+    case MMC_STAT:
+        return s->status;
+    case MMC_CLKRT:
+        return s->clkrt;
+    case MMC_SPI:
+        return s->spi;
+    case MMC_CMDAT:
+        return s->cmdat;
+    case MMC_RESTO:
+        return s->resp_tout;
+    case MMC_RDTO:
+        return s->read_tout;
+    case MMC_BLKLEN:
+        return s->blklen;
+    case MMC_NUMBLK:
+        return s->numblk;
+    case MMC_PRTBUF:
+        return 0;
+    case MMC_I_MASK:
+        return s->intmask;
+    case MMC_I_REG:
+        return s->intreq;
+    case MMC_CMD:
+        return s->cmd | 0x40;
+    case MMC_ARGH:
+        return s->arg >> 16;
+    case MMC_ARGL:
+        return s->arg & 0xffff;
+    case MMC_RES:
+        if (s->resp_len < 9)
+            return s->resp_fifo[s->resp_len ++];
+        return 0;
+    case MMC_RXFIFO:
+        ret = 0;
+        while (s->ac_width -- && s->rx_len) {
+            ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
+            s->rx_start &= 0x1f;
+            s->rx_len --;
+        }
+        s->intreq &= ~INT_RXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        return ret;
+    case MMC_RDWAIT:
+        return 0;
+    case MMC_BLKS_REM:
+        return s->numblk;
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_mmci_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        if (value & STRPCL_STRT_CLK) {
+            s->status |= STAT_CLK_EN;
+            s->intreq &= ~INT_CLK_OFF;
+
+            if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
+                s->status &= STAT_CLK_EN;
+                pxa2xx_mmci_wakequeues(s);
+            }
+        }
+
+        if (value & STRPCL_STOP_CLK) {
+            s->status &= ~STAT_CLK_EN;
+            s->intreq |= INT_CLK_OFF;
+            s->active = 0;
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CLKRT:
+        s->clkrt = value & 7;
+        break;
+
+    case MMC_SPI:
+        s->spi = value & 0xf;
+        if (value & SPI_SPI_MODE)
+            printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+        break;
+
+    case MMC_CMDAT:
+        s->cmdat = value & 0x3dff;
+        s->active = 0;
+        s->cmdreq = 1;
+        if (!(value & CMDAT_STOP_TRAN)) {
+            s->status &= STAT_CLK_EN;
+
+            if (s->status & STAT_CLK_EN)
+                pxa2xx_mmci_wakequeues(s);
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_RESTO:
+        s->resp_tout = value & 0x7f;
+        break;
+
+    case MMC_RDTO:
+        s->read_tout = value & 0xffff;
+        break;
+
+    case MMC_BLKLEN:
+        s->blklen = value & 0xfff;
+        break;
+
+    case MMC_NUMBLK:
+        s->numblk = value & 0xffff;
+        break;
+
+    case MMC_PRTBUF:
+        if (value & PRTBUF_PRT_BUF) {
+            s->tx_start ^= 32;
+            s->tx_len = 0;
+        }
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_I_MASK:
+        s->intmask = value & 0x1fff;
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CMD:
+        s->cmd = value & 0x3f;
+        break;
+
+    case MMC_ARGH:
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case MMC_ARGL:
+        s->arg &= 0xffff0000;
+        s->arg |= value & 0x0000ffff;
+        break;
+
+    case MMC_TXFIFO:
+        while (s->ac_width -- && s->tx_len < 0x20)
+            s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
+                    (value >> (s->ac_width << 3)) & 0xff;
+        s->intreq &= ~INT_TXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_RDWAIT:
+    case MMC_BLKS_REM:
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 1;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 2;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 4;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static CPUReadMemoryFunc * const pxa2xx_mmci_readfn[] = {
+    pxa2xx_mmci_readb,
+    pxa2xx_mmci_readh,
+    pxa2xx_mmci_readw
+};
+
+static void pxa2xx_mmci_writeb(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 1;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writeh(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 2;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writew(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 4;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static CPUWriteMemoryFunc * const pxa2xx_mmci_writefn[] = {
+    pxa2xx_mmci_writeb,
+    pxa2xx_mmci_writeh,
+    pxa2xx_mmci_writew
+};
+
+static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    int i;
+
+    qemu_put_be32s(f, &s->status);
+    qemu_put_be32s(f, &s->clkrt);
+    qemu_put_be32s(f, &s->spi);
+    qemu_put_be32s(f, &s->cmdat);
+    qemu_put_be32s(f, &s->resp_tout);
+    qemu_put_be32s(f, &s->read_tout);
+    qemu_put_be32(f, s->blklen);
+    qemu_put_be32(f, s->numblk);
+    qemu_put_be32s(f, &s->intmask);
+    qemu_put_be32s(f, &s->intreq);
+    qemu_put_be32(f, s->cmd);
+    qemu_put_be32s(f, &s->arg);
+    qemu_put_be32(f, s->cmdreq);
+    qemu_put_be32(f, s->active);
+    qemu_put_be32(f, s->bytesleft);
+
+    qemu_put_byte(f, s->tx_len);
+    for (i = 0; i < s->tx_len; i ++)
+        qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
+
+    qemu_put_byte(f, s->rx_len);
+    for (i = 0; i < s->rx_len; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
+
+    qemu_put_byte(f, s->resp_len);
+    for (i = s->resp_len; i < 9; i ++)
+        qemu_put_be16s(f, &s->resp_fifo[i]);
+}
+
+static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    int i;
+
+    qemu_get_be32s(f, &s->status);
+    qemu_get_be32s(f, &s->clkrt);
+    qemu_get_be32s(f, &s->spi);
+    qemu_get_be32s(f, &s->cmdat);
+    qemu_get_be32s(f, &s->resp_tout);
+    qemu_get_be32s(f, &s->read_tout);
+    s->blklen = qemu_get_be32(f);
+    s->numblk = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->intmask);
+    qemu_get_be32s(f, &s->intreq);
+    s->cmd = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->arg);
+    s->cmdreq = qemu_get_be32(f);
+    s->active = qemu_get_be32(f);
+    s->bytesleft = qemu_get_be32(f);
+
+    s->tx_len = qemu_get_byte(f);
+    s->tx_start = 0;
+    if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->tx_len; i ++)
+        s->tx_fifo[i] = qemu_get_byte(f);
+
+    s->rx_len = qemu_get_byte(f);
+    s->rx_start = 0;
+    if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->rx_len; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    s->resp_len = qemu_get_byte(f);
+    if (s->resp_len > 9 || s->resp_len < 0)
+        return -EINVAL;
+    for (i = s->resp_len; i < 9; i ++)
+         qemu_get_be16s(f, &s->resp_fifo[i]);
+
+    return 0;
+}
+
+PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma)
+{
+    int iomemtype;
+    PXA2xxMMCIState *s;
+
+    s = (PXA2xxMMCIState *) qemu_mallocz(sizeof(PXA2xxMMCIState));
+    s->irq = irq;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
+
+    iomemtype = cpu_register_io_memory(pxa2xx_mmci_readfn,
+                    pxa2xx_mmci_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    /* Instantiate the actual storage */
+    s->card = sd_init(bd, 0);
+
+    register_savevm(NULL, "pxa2xx_mmci", 0, 0,
+                    pxa2xx_mmci_save, pxa2xx_mmci_load, s);
+
+    return s;
+}
+
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
+                qemu_irq coverswitch)
+{
+    sd_set_cb(s->card, readonly, coverswitch);
+}
diff --git a/qemu-0.15.x/hw/pxa2xx_pcmcia.c b/qemu-0.15.x/hw/pxa2xx_pcmcia.c
new file mode 100644
index 0000000..50d4649
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_pcmcia.c
@@ -0,0 +1,215 @@
+/*
+ * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "hw.h"
+#include "pcmcia.h"
+#include "pxa.h"
+
+struct PXA2xxPCMCIAState {
+    PCMCIASocket slot;
+    PCMCIACardState *card;
+
+    qemu_irq irq;
+    qemu_irq cd_irq;
+};
+
+static uint32_t pxa2xx_pcmcia_common_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->common_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_common_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->common_write(s->card->state, offset, value);
+    }
+}
+
+static uint32_t pxa2xx_pcmcia_attr_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->attr_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_attr_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->attr_write(s->card->state, offset, value);
+    }
+}
+
+static uint32_t pxa2xx_pcmcia_io_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->io_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_io_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->io_write(s->card->state, offset, value);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_pcmcia_common_readfn[] = {
+    pxa2xx_pcmcia_common_read,
+    pxa2xx_pcmcia_common_read,
+    pxa2xx_pcmcia_common_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_pcmcia_common_writefn[] = {
+    pxa2xx_pcmcia_common_write,
+    pxa2xx_pcmcia_common_write,
+    pxa2xx_pcmcia_common_write,
+};
+
+static CPUReadMemoryFunc * const pxa2xx_pcmcia_attr_readfn[] = {
+    pxa2xx_pcmcia_attr_read,
+    pxa2xx_pcmcia_attr_read,
+    pxa2xx_pcmcia_attr_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_pcmcia_attr_writefn[] = {
+    pxa2xx_pcmcia_attr_write,
+    pxa2xx_pcmcia_attr_write,
+    pxa2xx_pcmcia_attr_write,
+};
+
+static CPUReadMemoryFunc * const pxa2xx_pcmcia_io_readfn[] = {
+    pxa2xx_pcmcia_io_read,
+    pxa2xx_pcmcia_io_read,
+    pxa2xx_pcmcia_io_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_pcmcia_io_writefn[] = {
+    pxa2xx_pcmcia_io_write,
+    pxa2xx_pcmcia_io_write,
+    pxa2xx_pcmcia_io_write,
+};
+
+static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (!s->irq)
+        return;
+
+    qemu_set_irq(s->irq, level);
+}
+
+PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base)
+{
+    int iomemtype;
+    PXA2xxPCMCIAState *s;
+
+    s = (PXA2xxPCMCIAState *)
+            qemu_mallocz(sizeof(PXA2xxPCMCIAState));
+
+    /* Socket I/O Memory Space */
+    iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_io_readfn,
+                    pxa2xx_pcmcia_io_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base | 0x00000000, 0x04000000, iomemtype);
+
+    /* Then next 64 MB is reserved */
+
+    /* Socket Attribute Memory Space */
+    iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_attr_readfn,
+                    pxa2xx_pcmcia_attr_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base | 0x08000000, 0x04000000, iomemtype);
+
+    /* Socket Common Memory Space */
+    iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_common_readfn,
+                    pxa2xx_pcmcia_common_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base | 0x0c000000, 0x04000000, iomemtype);
+
+    if (base == 0x30000000)
+        s->slot.slot_string = "PXA PC Card Socket 1";
+    else
+        s->slot.slot_string = "PXA PC Card Socket 0";
+    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
+    pcmcia_socket_register(&s->slot);
+
+    return s;
+}
+
+/* Insert a new card into a slot */
+int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (s->slot.attached)
+        return -EEXIST;
+
+    if (s->cd_irq) {
+        qemu_irq_raise(s->cd_irq);
+    }
+
+    s->card = card;
+
+    s->slot.attached = 1;
+    s->card->slot = &s->slot;
+    s->card->attach(s->card->state);
+
+    return 0;
+}
+
+/* Eject card from the slot */
+int pxa2xx_pcmcia_dettach(void *opaque)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (!s->slot.attached)
+        return -ENOENT;
+
+    s->card->detach(s->card->state);
+    s->card->slot = NULL;
+    s->card = NULL;
+
+    s->slot.attached = 0;
+
+    if (s->irq)
+        qemu_irq_lower(s->irq);
+    if (s->cd_irq)
+        qemu_irq_lower(s->cd_irq);
+
+    return 0;
+}
+
+/* Who to notify on card events */
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    s->irq = irq;
+    s->cd_irq = cd_irq;
+}
diff --git a/qemu-0.15.x/hw/pxa2xx_pic.c b/qemu-0.15.x/hw/pxa2xx_pic.c
new file mode 100644
index 0000000..bdd82e6
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_pic.c
@@ -0,0 +1,316 @@
+/*
+ * Intel XScale PXA Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "sysbus.h"
+
+#define ICIP	0x00	/* Interrupt Controller IRQ Pending register */
+#define ICMR	0x04	/* Interrupt Controller Mask register */
+#define ICLR	0x08	/* Interrupt Controller Level register */
+#define ICFP	0x0c	/* Interrupt Controller FIQ Pending register */
+#define ICPR	0x10	/* Interrupt Controller Pending register */
+#define ICCR	0x14	/* Interrupt Controller Control register */
+#define ICHP	0x18	/* Interrupt Controller Highest Priority register */
+#define IPR0	0x1c	/* Interrupt Controller Priority register 0 */
+#define IPR31	0x98	/* Interrupt Controller Priority register 31 */
+#define ICIP2	0x9c	/* Interrupt Controller IRQ Pending register 2 */
+#define ICMR2	0xa0	/* Interrupt Controller Mask register 2 */
+#define ICLR2	0xa4	/* Interrupt Controller Level register 2 */
+#define ICFP2	0xa8	/* Interrupt Controller FIQ Pending register 2 */
+#define ICPR2	0xac	/* Interrupt Controller Pending register 2 */
+#define IPR32	0xb0	/* Interrupt Controller Priority register 32 */
+#define IPR39	0xcc	/* Interrupt Controller Priority register 39 */
+
+#define PXA2XX_PIC_SRCS	40
+
+typedef struct {
+    SysBusDevice busdev;
+    CPUState *cpu_env;
+    uint32_t int_enabled[2];
+    uint32_t int_pending[2];
+    uint32_t is_fiq[2];
+    uint32_t int_idle;
+    uint32_t priority[PXA2XX_PIC_SRCS];
+} PXA2xxPICState;
+
+static void pxa2xx_pic_update(void *opaque)
+{
+    uint32_t mask[2];
+    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
+
+    if (s->cpu_env->halted) {
+        mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
+        mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
+        if (mask[0] || mask[1])
+            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+    }
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+
+    if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+}
+
+/* Note: Here level means state of the signal on a pin, not
+ * IRQ/FIQ distinction as in PXA Developer Manual.  */
+static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
+{
+    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
+    int int_set = (irq >= 32);
+    irq &= 31;
+
+    if (level)
+        s->int_pending[int_set] |= 1 << irq;
+    else
+        s->int_pending[int_set] &= ~(1 << irq);
+
+    pxa2xx_pic_update(opaque);
+}
+
+static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
+    int i, int_set, irq;
+    uint32_t bit, mask[2];
+    uint32_t ichp = 0x003f003f;	/* Both IDs invalid */
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
+        irq = s->priority[i] & 0x3f;
+        if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
+            /* Source peripheral ID is valid.  */
+            bit = 1 << (irq & 31);
+            int_set = (irq >= 32);
+
+            if (mask[int_set] & bit & s->is_fiq[int_set]) {
+                /* FIQ asserted */
+                ichp &= 0xffff0000;
+                ichp |= (1 << 15) | irq;
+            }
+
+            if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
+                /* IRQ asserted */
+                ichp &= 0x0000ffff;
+                ichp |= (1 << 31) | (irq << 16);
+            }
+        }
+    }
+
+    return ichp;
+}
+
+static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
+
+    switch (offset) {
+    case ICIP:	/* IRQ Pending register */
+        return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
+    case ICIP2:	/* IRQ Pending register 2 */
+        return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
+    case ICMR:	/* Mask register */
+        return s->int_enabled[0];
+    case ICMR2:	/* Mask register 2 */
+        return s->int_enabled[1];
+    case ICLR:	/* Level register */
+        return s->is_fiq[0];
+    case ICLR2:	/* Level register 2 */
+        return s->is_fiq[1];
+    case ICCR:	/* Idle mask */
+        return (s->int_idle == 0);
+    case ICFP:	/* FIQ Pending register */
+        return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
+    case ICFP2:	/* FIQ Pending register 2 */
+        return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
+    case ICPR:	/* Pending register */
+        return s->int_pending[0];
+    case ICPR2:	/* Pending register 2 */
+        return s->int_pending[1];
+    case IPR0  ... IPR31:
+        return s->priority[0  + ((offset - IPR0 ) >> 2)];
+    case IPR32 ... IPR39:
+        return s->priority[32 + ((offset - IPR32) >> 2)];
+    case ICHP:	/* Highest Priority register */
+        return pxa2xx_pic_highest(s);
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return 0;
+    }
+}
+
+static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    PXA2xxPICState *s = (PXA2xxPICState *) opaque;
+
+    switch (offset) {
+    case ICMR:	/* Mask register */
+        s->int_enabled[0] = value;
+        break;
+    case ICMR2:	/* Mask register 2 */
+        s->int_enabled[1] = value;
+        break;
+    case ICLR:	/* Level register */
+        s->is_fiq[0] = value;
+        break;
+    case ICLR2:	/* Level register 2 */
+        s->is_fiq[1] = value;
+        break;
+    case ICCR:	/* Idle mask */
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    case IPR0  ... IPR31:
+        s->priority[0  + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
+        break;
+    case IPR32 ... IPR39:
+        s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
+        break;
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return;
+    }
+    pxa2xx_pic_update(opaque);
+}
+
+/* Interrupt Controller Coprocessor Space Register Mapping */
+static const int pxa2xx_cp_reg_map[0x10] = {
+    [0x0 ... 0xf] = -1,
+    [0x0] = ICIP,
+    [0x1] = ICMR,
+    [0x2] = ICLR,
+    [0x3] = ICFP,
+    [0x4] = ICPR,
+    [0x5] = ICHP,
+    [0x6] = ICIP2,
+    [0x7] = ICMR2,
+    [0x8] = ICLR2,
+    [0x9] = ICFP2,
+    [0xa] = ICPR2,
+};
+
+static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm)
+{
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return 0;
+    }
+
+    offset = pxa2xx_cp_reg_map[reg];
+    return pxa2xx_pic_mem_read(opaque, offset);
+}
+
+static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return;
+    }
+
+    offset = pxa2xx_cp_reg_map[reg];
+    pxa2xx_pic_mem_write(opaque, offset, value);
+}
+
+static CPUReadMemoryFunc * const pxa2xx_pic_readfn[] = {
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_pic_writefn[] = {
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+};
+
+static int pxa2xx_pic_post_load(void *opaque, int version_id)
+{
+    pxa2xx_pic_update(opaque);
+    return 0;
+}
+
+DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
+{
+    DeviceState *dev = qdev_create(NULL, "pxa2xx_pic");
+    int iomemtype;
+    PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, sysbus_from_qdev(dev));
+
+    s->cpu_env = env;
+
+    s->int_pending[0] = 0;
+    s->int_pending[1] = 0;
+    s->int_enabled[0] = 0;
+    s->int_enabled[1] = 0;
+    s->is_fiq[0] = 0;
+    s->is_fiq[1] = 0;
+
+    qdev_init_nofail(dev);
+
+    qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
+
+    /* Enable IC memory-mapped registers access.  */
+    iomemtype = cpu_register_io_memory(pxa2xx_pic_readfn,
+                    pxa2xx_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(sysbus_from_qdev(dev), 0x00100000, iomemtype);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    /* Enable IC coprocessor access.  */
+    cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
+
+    return dev;
+}
+
+static VMStateDescription vmstate_pxa2xx_pic_regs = {
+    .name = "pxa2xx_pic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
+        VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
+        VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
+        VMSTATE_UINT32(int_idle, PXA2xxPICState),
+        VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static int pxa2xx_pic_initfn(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo pxa2xx_pic_info = {
+    .init       = pxa2xx_pic_initfn,
+    .qdev.name  = "pxa2xx_pic",
+    .qdev.desc  = "PXA2xx PIC",
+    .qdev.size  = sizeof(PXA2xxPICState),
+    .qdev.vmsd  = &vmstate_pxa2xx_pic_regs,
+};
+
+static void pxa2xx_pic_register(void)
+{
+    sysbus_register_withprop(&pxa2xx_pic_info);
+}
+device_init(pxa2xx_pic_register);
diff --git a/qemu-0.15.x/hw/pxa2xx_template.h b/qemu-0.15.x/hw/pxa2xx_template.h
new file mode 100644
index 0000000..1cbe36c
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_template.h
@@ -0,0 +1,435 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to)		to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from)	*(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24
+# define COPY_PIXEL(to, from)	\
+	*(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from)	*(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+# define SWAP_WORDS	1
+#endif
+
+#define FN_2(x)		FN(x + 1) FN(x)
+#define FN_4(x)		FN_2(x + 2) FN_2(x)
+
+static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+        FN_4(12)
+        FN_4(8)
+        FN_4(4)
+        FN_4(0)
+#else
+        FN_4(0)
+        FN_4(4)
+        FN_4(8)
+        FN_4(12)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+        FN_2(6)
+        FN_2(4)
+        FN_2(2)
+        FN_2(0)
+#else
+        FN_2(0)
+        FN_2(2)
+        FN_2(4)
+        FN_2(6)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data >>= 1;
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+#ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+#endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 8;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        data >>= 6;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+# ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+# endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        if (data[0] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[0] >>= 6;
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        if (data[1] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[1] >>= 6;
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 2;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[2] >>= 6;
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        data[2] >>= 6;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x7f) << 1;
+        data >>= 7;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* Overlay planes disabled, no transparency */
+static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
+{
+    [0 ... 0xf]       = NULL,
+    [pxa_lcdc_2bpp]   = glue(pxa2xx_draw_line2_, BITS),
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16_, BITS),
+    [pxa_lcdc_18bpp]  = glue(pxa2xx_draw_line18_, BITS),
+    [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24_, BITS),
+};
+
+/* Overlay planes enabled, transparency used */
+static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
+{
+    [0 ... 0xf]       = NULL,
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16t_, BITS),
+    [pxa_lcdc_19bpp]  = glue(pxa2xx_draw_line19_, BITS),
+    [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24t_, BITS),
+    [pxa_lcdc_25bpp]  = glue(pxa2xx_draw_line25_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
diff --git a/qemu-0.15.x/hw/pxa2xx_timer.c b/qemu-0.15.x/hw/pxa2xx_timer.c
new file mode 100644
index 0000000..4235e42
--- /dev/null
+++ b/qemu-0.15.x/hw/pxa2xx_timer.c
@@ -0,0 +1,518 @@
+/*
+ * Intel XScale PXA255/270 OS Timers.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "pxa.h"
+#include "sysbus.h"
+
+#define OSMR0	0x00
+#define OSMR1	0x04
+#define OSMR2	0x08
+#define OSMR3	0x0c
+#define OSMR4	0x80
+#define OSMR5	0x84
+#define OSMR6	0x88
+#define OSMR7	0x8c
+#define OSMR8	0x90
+#define OSMR9	0x94
+#define OSMR10	0x98
+#define OSMR11	0x9c
+#define OSCR	0x10	/* OS Timer Count */
+#define OSCR4	0x40
+#define OSCR5	0x44
+#define OSCR6	0x48
+#define OSCR7	0x4c
+#define OSCR8	0x50
+#define OSCR9	0x54
+#define OSCR10	0x58
+#define OSCR11	0x5c
+#define OSSR	0x14	/* Timer status register */
+#define OWER	0x18
+#define OIER	0x1c	/* Interrupt enable register  3-0 to E3-E0 */
+#define OMCR4	0xc0	/* OS Match Control registers */
+#define OMCR5	0xc4
+#define OMCR6	0xc8
+#define OMCR7	0xcc
+#define OMCR8	0xd0
+#define OMCR9	0xd4
+#define OMCR10	0xd8
+#define OMCR11	0xdc
+#define OSNR	0x20
+
+#define PXA25X_FREQ	3686400	/* 3.6864 MHz */
+#define PXA27X_FREQ	3250000	/* 3.25 MHz */
+
+static int pxa2xx_timer4_freq[8] = {
+    [0] = 0,
+    [1] = 32768,
+    [2] = 1000,
+    [3] = 1,
+    [4] = 1000000,
+    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
+    [5 ... 7] = 0,
+};
+
+typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
+
+typedef struct {
+    uint32_t value;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    int num;
+    PXA2xxTimerInfo *info;
+} PXA2xxTimer0;
+
+typedef struct {
+    PXA2xxTimer0 tm;
+    int32_t oldclock;
+    int32_t clock;
+    uint64_t lastload;
+    uint32_t freq;
+    uint32_t control;
+} PXA2xxTimer4;
+
+struct PXA2xxTimerInfo {
+    SysBusDevice busdev;
+    uint32_t flags;
+
+    int32_t clock;
+    int32_t oldclock;
+    uint64_t lastload;
+    uint32_t freq;
+    PXA2xxTimer0 timer[4];
+    uint32_t events;
+    uint32_t irq_enabled;
+    uint32_t reset3;
+    uint32_t snapshot;
+
+    qemu_irq irq4;
+    PXA2xxTimer4 tm4[8];
+};
+
+#define PXA2XX_TIMER_HAVE_TM4	0
+
+static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
+{
+    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
+}
+
+static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int i;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+
+    now_vm = s->clock +
+            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
+
+    for (i = 0; i < 4; i ++) {
+        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
+                        get_ticks_per_sec(), s->freq);
+        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
+    }
+}
+
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+    int counter;
+
+    if (s->tm4[n].control & (1 << 7))
+        counter = n;
+    else
+        counter = counters[n];
+
+    if (!s->tm4[counter].freq) {
+        qemu_del_timer(s->tm4[n].tm.qtimer);
+        return;
+    }
+
+    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+                    s->tm4[counter].lastload,
+                    s->tm4[counter].freq, get_ticks_per_sec());
+
+    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
+                    get_ticks_per_sec(), s->tm4[counter].freq);
+    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
+}
+
+static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int tm = 0;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+    case OSMR2:  tm ++;
+    case OSMR1:  tm ++;
+    case OSMR0:
+        return s->timer[tm].value;
+    case OSMR11: tm ++;
+    case OSMR10: tm ++;
+    case OSMR9:  tm ++;
+    case OSMR8:  tm ++;
+    case OSMR7:  tm ++;
+    case OSMR6:  tm ++;
+    case OSMR5:  tm ++;
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].tm.value;
+    case OSCR:
+        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->lastload, s->freq, get_ticks_per_sec());
+    case OSCR11: tm ++;
+    case OSCR10: tm ++;
+    case OSCR9:  tm ++;
+    case OSCR8:  tm ++;
+    case OSCR7:  tm ++;
+    case OSCR6:  tm ++;
+    case OSCR5:  tm ++;
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+
+        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+            if (s->tm4[tm - 1].freq)
+                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+                                qemu_get_clock_ns(vm_clock) -
+                                s->tm4[tm - 1].lastload,
+                                s->tm4[tm - 1].freq, get_ticks_per_sec());
+            else
+                s->snapshot = s->tm4[tm - 1].clock;
+        }
+
+        if (!s->tm4[tm].freq)
+            return s->tm4[tm].clock;
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
+    case OIER:
+        return s->irq_enabled;
+    case OSSR:	/* Status register */
+        return s->events;
+    case OWER:
+        return s->reset3;
+    case OMCR11: tm ++;
+    case OMCR10: tm ++;
+    case OMCR9:  tm ++;
+    case OMCR8:  tm ++;
+    case OMCR7:  tm ++;
+    case OMCR6:  tm ++;
+    case OMCR5:  tm ++;
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].control;
+    case OSNR:
+        return s->snapshot;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    int i, tm = 0;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+    case OSMR2:  tm ++;
+    case OSMR1:  tm ++;
+    case OSMR0:
+        s->timer[tm].value = value;
+        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
+        break;
+    case OSMR11: tm ++;
+    case OSMR10: tm ++;
+    case OSMR9:  tm ++;
+    case OSMR8:  tm ++;
+    case OSMR7:  tm ++;
+    case OSMR6:  tm ++;
+    case OSMR5:  tm ++;
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].tm.value = value;
+        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        break;
+    case OSCR:
+        s->oldclock = s->clock;
+        s->lastload = qemu_get_clock_ns(vm_clock);
+        s->clock = value;
+        pxa2xx_timer_update(s, s->lastload);
+        break;
+    case OSCR11: tm ++;
+    case OSCR10: tm ++;
+    case OSCR9:  tm ++;
+    case OSCR8:  tm ++;
+    case OSCR7:  tm ++;
+    case OSCR6:  tm ++;
+    case OSCR5:  tm ++;
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].oldclock = s->tm4[tm].clock;
+        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
+        s->tm4[tm].clock = value;
+        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+        break;
+    case OIER:
+        s->irq_enabled = value & 0xfff;
+        break;
+    case OSSR:	/* Status register */
+        value &= s->events;
+        s->events &= ~value;
+        for (i = 0; i < 4; i ++, value >>= 1)
+            if (value & 1)
+                qemu_irq_lower(s->timer[i].irq);
+        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
+            qemu_irq_lower(s->irq4);
+        break;
+    case OWER:	/* XXX: Reset on OSMR3 match? */
+        s->reset3 = value;
+        break;
+    case OMCR7:  tm ++;
+    case OMCR6:  tm ++;
+    case OMCR5:  tm ++;
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x0ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || tm == 0)
+            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    case OMCR11: tm ++;
+    case OMCR10: tm ++;
+    case OMCR9:  tm ++;
+    case OMCR8:  tm += 4;
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x3ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || !(tm & 1))
+            s->tm4[tm].freq =
+                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
+    }
+}
+
+static CPUReadMemoryFunc * const pxa2xx_timer_readfn[] = {
+    pxa2xx_timer_read,
+    pxa2xx_timer_read,
+    pxa2xx_timer_read,
+};
+
+static CPUWriteMemoryFunc * const pxa2xx_timer_writefn[] = {
+    pxa2xx_timer_write,
+    pxa2xx_timer_write,
+    pxa2xx_timer_write,
+};
+
+static void pxa2xx_timer_tick(void *opaque)
+{
+    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
+    PXA2xxTimerInfo *i = t->info;
+
+    if (i->irq_enabled & (1 << t->num)) {
+        i->events |= 1 << t->num;
+        qemu_irq_raise(t->irq);
+    }
+
+    if (t->num == 3)
+        if (i->reset3 & 1) {
+            i->reset3 = 0;
+            qemu_system_reset_request();
+        }
+}
+
+static void pxa2xx_timer_tick4(void *opaque)
+{
+    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
+    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
+
+    pxa2xx_timer_tick(&t->tm);
+    if (t->control & (1 << 3))
+        t->clock = 0;
+    if (t->control & (1 << 6))
+        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
+    if (i->events & 0xff0)
+        qemu_irq_raise(i->irq4);
+}
+
+static int pxa25x_timer_post_load(void *opaque, int version_id)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int64_t now;
+    int i;
+
+    now = qemu_get_clock_ns(vm_clock);
+    pxa2xx_timer_update(s, now);
+
+    if (pxa2xx_timer_has_tm4(s))
+        for (i = 0; i < 8; i ++)
+            pxa2xx_timer_update4(s, now, i);
+
+    return 0;
+}
+
+static int pxa2xx_timer_init(SysBusDevice *dev)
+{
+    int i;
+    int iomemtype;
+    PXA2xxTimerInfo *s;
+
+    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
+    s->irq_enabled = 0;
+    s->oldclock = 0;
+    s->clock = 0;
+    s->lastload = qemu_get_clock_ns(vm_clock);
+    s->reset3 = 0;
+
+    for (i = 0; i < 4; i ++) {
+        s->timer[i].value = 0;
+        sysbus_init_irq(dev, &s->timer[i].irq);
+        s->timer[i].info = s;
+        s->timer[i].num = i;
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick, &s->timer[i]);
+    }
+    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
+        sysbus_init_irq(dev, &s->irq4);
+
+        for (i = 0; i < 8; i ++) {
+            s->tm4[i].tm.value = 0;
+            s->tm4[i].tm.info = s;
+            s->tm4[i].tm.num = i + 4;
+            s->tm4[i].freq = 0;
+            s->tm4[i].control = 0x0;
+            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+        }
+    }
+
+    iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
+                    pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x00001000, iomemtype);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
+    .name = "pxa2xx_timer0",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(value, PXA2xxTimer0),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
+    .name = "pxa2xx_timer4",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_INT32(oldclock, PXA2xxTimer4),
+        VMSTATE_INT32(clock, PXA2xxTimer4),
+        VMSTATE_UINT64(lastload, PXA2xxTimer4),
+        VMSTATE_UINT32(freq, PXA2xxTimer4),
+        VMSTATE_UINT32(control, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
+{
+    return pxa2xx_timer_has_tm4(opaque);
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer_regs = {
+    .name = "pxa2xx_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pxa25x_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(clock, PXA2xxTimerInfo),
+        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
+        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_UINT32(events, PXA2xxTimerInfo),
+        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
+        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
+        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
+                        pxa2xx_timer_has_tm4_test, 0,
+                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static SysBusDeviceInfo pxa25x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa25x-timer",
+    .qdev.desc  = "PXA25x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa27x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa27x-timer",
+    .qdev.desc  = "PXA27x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, true),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pxa2xx_timer_register(void)
+{
+    sysbus_register_withprop(&pxa25x_timer_dev_info);
+    sysbus_register_withprop(&pxa27x_timer_dev_info);
+};
+device_init(pxa2xx_timer_register);
diff --git a/qemu-0.15.x/hw/qdev-addr.c b/qemu-0.15.x/hw/qdev-addr.c
new file mode 100644
index 0000000..305c2d3
--- /dev/null
+++ b/qemu-0.15.x/hw/qdev-addr.c
@@ -0,0 +1,32 @@
+#include "qdev.h"
+#include "qdev-addr.h"
+#include "targphys.h"
+
+/* --- target physical address --- */
+
+static int parse_taddr(DeviceState *dev, Property *prop, const char *str)
+{
+    target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    *ptr = strtoull(str, NULL, 16);
+    return 0;
+}
+
+static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
+}
+
+PropertyInfo qdev_prop_taddr = {
+    .name  = "taddr",
+    .type  = PROP_TYPE_TADDR,
+    .size  = sizeof(target_phys_addr_t),
+    .parse = parse_taddr,
+    .print = print_taddr,
+};
+
+void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_TADDR);
+}
diff --git a/qemu-0.15.x/hw/qdev-addr.h b/qemu-0.15.x/hw/qdev-addr.h
new file mode 100644
index 0000000..a0ddf38
--- /dev/null
+++ b/qemu-0.15.x/hw/qdev-addr.h
@@ -0,0 +1,5 @@
+#define DEFINE_PROP_TADDR(_n, _s, _f, _d)                               \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_taddr, target_phys_addr_t)
+
+extern PropertyInfo qdev_prop_taddr;
+void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value);
diff --git a/qemu-0.15.x/hw/qdev-properties.c b/qemu-0.15.x/hw/qdev-properties.c
new file mode 100644
index 0000000..eff2d24
--- /dev/null
+++ b/qemu-0.15.x/hw/qdev-properties.c
@@ -0,0 +1,782 @@
+#include "net.h"
+#include "qdev.h"
+#include "qerror.h"
+#include "blockdev.h"
+
+void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
+{
+    void *ptr = dev;
+    ptr += prop->offset;
+    return ptr;
+}
+
+static uint32_t qdev_get_prop_mask(Property *prop)
+{
+    assert(prop->info->type == PROP_TYPE_BIT);
+    return 0x1 << prop->bitnr;
+}
+
+static void bit_prop_set(DeviceState *dev, Property *props, bool val)
+{
+    uint32_t *p = qdev_get_prop_ptr(dev, props);
+    uint32_t mask = qdev_get_prop_mask(props);
+    if (val)
+        *p |= mask;
+    else
+        *p &= ~mask;
+}
+
+static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
+{
+    if (props->info->type == PROP_TYPE_BIT) {
+        bool *defval = src;
+        bit_prop_set(dev, props, *defval);
+    } else {
+        char *dst = qdev_get_prop_ptr(dev, props);
+        memcpy(dst, src, props->info->size);
+    }
+}
+
+/* Bit */
+static int parse_bit(DeviceState *dev, Property *prop, const char *str)
+{
+    if (!strncasecmp(str, "on", 2))
+        bit_prop_set(dev, prop, true);
+    else if (!strncasecmp(str, "off", 3))
+        bit_prop_set(dev, prop, false);
+    else
+        return -EINVAL;
+    return 0;
+}
+
+static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *p = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
+}
+
+PropertyInfo qdev_prop_bit = {
+    .name  = "on/off",
+    .type  = PROP_TYPE_BIT,
+    .size  = sizeof(uint32_t),
+    .parse = parse_bit,
+    .print = print_bit,
+};
+
+/* --- 8bit integer --- */
+
+static int parse_uint8(DeviceState *dev, Property *prop, const char *str)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    /* accept both hex and decimal */
+    *ptr = strtoul(str, &end, 0);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%" PRIu8, *ptr);
+}
+
+PropertyInfo qdev_prop_uint8 = {
+    .name  = "uint8",
+    .type  = PROP_TYPE_UINT8,
+    .size  = sizeof(uint8_t),
+    .parse = parse_uint8,
+    .print = print_uint8,
+};
+
+/* --- 16bit integer --- */
+
+static int parse_uint16(DeviceState *dev, Property *prop, const char *str)
+{
+    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    /* accept both hex and decimal */
+    *ptr = strtoul(str, &end, 0);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%" PRIu16, *ptr);
+}
+
+PropertyInfo qdev_prop_uint16 = {
+    .name  = "uint16",
+    .type  = PROP_TYPE_UINT16,
+    .size  = sizeof(uint16_t),
+    .parse = parse_uint16,
+    .print = print_uint16,
+};
+
+/* --- 32bit integer --- */
+
+static int parse_uint32(DeviceState *dev, Property *prop, const char *str)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    /* accept both hex and decimal */
+    *ptr = strtoul(str, &end, 0);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%" PRIu32, *ptr);
+}
+
+PropertyInfo qdev_prop_uint32 = {
+    .name  = "uint32",
+    .type  = PROP_TYPE_UINT32,
+    .size  = sizeof(uint32_t),
+    .parse = parse_uint32,
+    .print = print_uint32,
+};
+
+static int parse_int32(DeviceState *dev, Property *prop, const char *str)
+{
+    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    *ptr = strtol(str, &end, 10);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%" PRId32, *ptr);
+}
+
+PropertyInfo qdev_prop_int32 = {
+    .name  = "int32",
+    .type  = PROP_TYPE_INT32,
+    .size  = sizeof(int32_t),
+    .parse = parse_int32,
+    .print = print_int32,
+};
+
+/* --- 32bit hex value --- */
+
+static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    *ptr = strtoul(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx32, *ptr);
+}
+
+PropertyInfo qdev_prop_hex32 = {
+    .name  = "hex32",
+    .type  = PROP_TYPE_UINT32,
+    .size  = sizeof(uint32_t),
+    .parse = parse_hex32,
+    .print = print_hex32,
+};
+
+/* --- 64bit integer --- */
+
+static int parse_uint64(DeviceState *dev, Property *prop, const char *str)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    /* accept both hex and decimal */
+    *ptr = strtoull(str, &end, 0);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%" PRIu64, *ptr);
+}
+
+PropertyInfo qdev_prop_uint64 = {
+    .name  = "uint64",
+    .type  = PROP_TYPE_UINT64,
+    .size  = sizeof(uint64_t),
+    .parse = parse_uint64,
+    .print = print_uint64,
+};
+
+/* --- 64bit hex value --- */
+
+static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    *ptr = strtoull(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx64, *ptr);
+}
+
+PropertyInfo qdev_prop_hex64 = {
+    .name  = "hex64",
+    .type  = PROP_TYPE_UINT64,
+    .size  = sizeof(uint64_t),
+    .parse = parse_hex64,
+    .print = print_hex64,
+};
+
+/* --- string --- */
+
+static int parse_string(DeviceState *dev, Property *prop, const char *str)
+{
+    char **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr)
+        qemu_free(*ptr);
+    *ptr = qemu_strdup(str);
+    return 0;
+}
+
+static void free_string(DeviceState *dev, Property *prop)
+{
+    qemu_free(*(char **)qdev_get_prop_ptr(dev, prop));
+}
+
+static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    char **ptr = qdev_get_prop_ptr(dev, prop);
+    if (!*ptr)
+        return snprintf(dest, len, "<null>");
+    return snprintf(dest, len, "\"%s\"", *ptr);
+}
+
+PropertyInfo qdev_prop_string = {
+    .name  = "string",
+    .type  = PROP_TYPE_STRING,
+    .size  = sizeof(char*),
+    .parse = parse_string,
+    .print = print_string,
+    .free  = free_string,
+};
+
+/* --- drive --- */
+
+static int parse_drive(DeviceState *dev, Property *prop, const char *str)
+{
+    BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+    BlockDriverState *bs;
+
+    bs = bdrv_find(str);
+    if (bs == NULL)
+        return -ENOENT;
+    if (bdrv_attach(bs, dev) < 0)
+        return -EEXIST;
+    *ptr = bs;
+    return 0;
+}
+
+static void free_drive(DeviceState *dev, Property *prop)
+{
+    BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        bdrv_detach(*ptr, dev);
+        blockdev_auto_del(*ptr);
+    }
+}
+
+static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "%s",
+                    *ptr ? bdrv_get_device_name(*ptr) : "<null>");
+}
+
+PropertyInfo qdev_prop_drive = {
+    .name  = "drive",
+    .type  = PROP_TYPE_DRIVE,
+    .size  = sizeof(BlockDriverState *),
+    .parse = parse_drive,
+    .print = print_drive,
+    .free  = free_drive,
+};
+
+/* --- character device --- */
+
+static int parse_chr(DeviceState *dev, Property *prop, const char *str)
+{
+    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    *ptr = qemu_chr_find(str);
+    if (*ptr == NULL) {
+        return -ENOENT;
+    }
+    if ((*ptr)->avail_connections < 1) {
+        return -EEXIST;
+    }
+    --(*ptr)->avail_connections;
+    return 0;
+}
+
+static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr && (*ptr)->label) {
+        return snprintf(dest, len, "%s", (*ptr)->label);
+    } else {
+        return snprintf(dest, len, "<null>");
+    }
+}
+
+PropertyInfo qdev_prop_chr = {
+    .name  = "chr",
+    .type  = PROP_TYPE_CHR,
+    .size  = sizeof(CharDriverState*),
+    .parse = parse_chr,
+    .print = print_chr,
+};
+
+/* --- netdev device --- */
+
+static int parse_netdev(DeviceState *dev, Property *prop, const char *str)
+{
+    VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    *ptr = qemu_find_netdev(str);
+    if (*ptr == NULL)
+        return -ENOENT;
+    if ((*ptr)->peer) {
+        return -EEXIST;
+    }
+    return 0;
+}
+
+static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr && (*ptr)->name) {
+        return snprintf(dest, len, "%s", (*ptr)->name);
+    } else {
+        return snprintf(dest, len, "<null>");
+    }
+}
+
+PropertyInfo qdev_prop_netdev = {
+    .name  = "netdev",
+    .type  = PROP_TYPE_NETDEV,
+    .size  = sizeof(VLANClientState*),
+    .parse = parse_netdev,
+    .print = print_netdev,
+};
+
+/* --- vlan --- */
+
+static int parse_vlan(DeviceState *dev, Property *prop, const char *str)
+{
+    VLANState **ptr = qdev_get_prop_ptr(dev, prop);
+    int id;
+
+    if (sscanf(str, "%d", &id) != 1)
+        return -EINVAL;
+    *ptr = qemu_find_vlan(id, 1);
+    if (*ptr == NULL)
+        return -ENOENT;
+    return 0;
+}
+
+static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    VLANState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        return snprintf(dest, len, "%d", (*ptr)->id);
+    } else {
+        return snprintf(dest, len, "<null>");
+    }
+}
+
+PropertyInfo qdev_prop_vlan = {
+    .name  = "vlan",
+    .type  = PROP_TYPE_VLAN,
+    .size  = sizeof(VLANClientState*),
+    .parse = parse_vlan,
+    .print = print_vlan,
+};
+
+/* --- pointer --- */
+
+/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
+PropertyInfo qdev_prop_ptr = {
+    .name  = "ptr",
+    .type  = PROP_TYPE_PTR,
+    .size  = sizeof(void*),
+};
+
+/* --- mac address --- */
+
+/*
+ * accepted syntax versions:
+ *   01:02:03:04:05:06
+ *   01-02-03-04-05-06
+ */
+static int parse_mac(DeviceState *dev, Property *prop, const char *str)
+{
+    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
+    int i, pos;
+    char *p;
+
+    for (i = 0, pos = 0; i < 6; i++, pos += 3) {
+        if (!qemu_isxdigit(str[pos]))
+            return -EINVAL;
+        if (!qemu_isxdigit(str[pos+1]))
+            return -EINVAL;
+        if (i == 5) {
+            if (str[pos+2] != '\0')
+                return -EINVAL;
+        } else {
+            if (str[pos+2] != ':' && str[pos+2] != '-')
+                return -EINVAL;
+        }
+        mac->a[i] = strtol(str+pos, &p, 16);
+    }
+    return 0;
+}
+
+static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
+
+    return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
+                    mac->a[0], mac->a[1], mac->a[2],
+                    mac->a[3], mac->a[4], mac->a[5]);
+}
+
+PropertyInfo qdev_prop_macaddr = {
+    .name  = "macaddr",
+    .type  = PROP_TYPE_MACADDR,
+    .size  = sizeof(MACAddr),
+    .parse = parse_mac,
+    .print = print_mac,
+};
+
+/* --- pci address --- */
+
+/*
+ * bus-local address, i.e. "$slot" or "$slot.$fn"
+ */
+static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    unsigned int slot, fn, n;
+
+    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
+        fn = 0;
+        if (sscanf(str, "%x%n", &slot, &n) != 1) {
+            return -EINVAL;
+        }
+    }
+    if (str[n] != '\0')
+        return -EINVAL;
+    if (fn > 7)
+        return -EINVAL;
+    *ptr = slot << 3 | fn;
+    return 0;
+}
+
+static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr == -1) {
+        return snprintf(dest, len, "<unset>");
+    } else {
+        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
+    }
+}
+
+PropertyInfo qdev_prop_pci_devfn = {
+    .name  = "pci-devfn",
+    .type  = PROP_TYPE_UINT32,
+    .size  = sizeof(uint32_t),
+    .parse = parse_pci_devfn,
+    .print = print_pci_devfn,
+};
+
+/* --- public helpers --- */
+
+static Property *qdev_prop_walk(Property *props, const char *name)
+{
+    if (!props)
+        return NULL;
+    while (props->name) {
+        if (strcmp(props->name, name) == 0)
+            return props;
+        props++;
+    }
+    return NULL;
+}
+
+static Property *qdev_prop_find(DeviceState *dev, const char *name)
+{
+    Property *prop;
+
+    /* device properties */
+    prop = qdev_prop_walk(dev->info->props, name);
+    if (prop)
+        return prop;
+
+    /* bus properties */
+    prop = qdev_prop_walk(dev->parent_bus->info->props, name);
+    if (prop)
+        return prop;
+
+    return NULL;
+}
+
+int qdev_prop_exists(DeviceState *dev, const char *name)
+{
+    return qdev_prop_find(dev, name) ? true : false;
+}
+
+int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
+{
+    Property *prop;
+    int ret;
+
+    prop = qdev_prop_find(dev, name);
+    /*
+     * TODO Properties without a parse method are just for dirty
+     * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
+     * marked for removal.  The test !prop->info->parse should be
+     * removed along with it.
+     */
+    if (!prop || !prop->info->parse) {
+        qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name);
+        return -1;
+    }
+    ret = prop->info->parse(dev, prop, value);
+    if (ret < 0) {
+        switch (ret) {
+        case -EEXIST:
+            qerror_report(QERR_PROPERTY_VALUE_IN_USE,
+                          dev->info->name, name, value);
+            break;
+        default:
+        case -EINVAL:
+            qerror_report(QERR_PROPERTY_VALUE_BAD,
+                          dev->info->name, name, value);
+            break;
+        case -ENOENT:
+            qerror_report(QERR_PROPERTY_VALUE_NOT_FOUND,
+                          dev->info->name, name, value);
+            break;
+        }
+        return -1;
+    }
+    return 0;
+}
+
+void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
+{
+    Property *prop;
+
+    prop = qdev_prop_find(dev, name);
+    if (!prop) {
+        fprintf(stderr, "%s: property \"%s.%s\" not found\n",
+                __FUNCTION__, dev->info->name, name);
+        abort();
+    }
+    if (prop->info->type != type) {
+        fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
+                __FUNCTION__, dev->info->name, name);
+        abort();
+    }
+    qdev_prop_cpy(dev, prop, src);
+}
+
+void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_BIT);
+}
+
+void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8);
+}
+
+void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16);
+}
+
+void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32);
+}
+
+void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_INT32);
+}
+
+void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
+}
+
+void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
+}
+
+int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
+{
+    int res;
+
+    res = bdrv_attach(value, dev);
+    if (res < 0) {
+        error_report("Can't attach drive %s to %s.%s: %s",
+                     bdrv_get_device_name(value),
+                     dev->id ? dev->id : dev->info->name,
+                     name, strerror(-res));
+        return -1;
+    }
+    qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
+    return 0;
+}
+
+void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value)
+{
+    if (qdev_prop_set_drive(dev, name, value) < 0) {
+        exit(1);
+    }
+}
+void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_CHR);
+}
+
+void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV);
+}
+
+void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN);
+}
+
+void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
+{
+    qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
+}
+
+void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
+}
+
+void qdev_prop_set_defaults(DeviceState *dev, Property *props)
+{
+    if (!props)
+        return;
+    while (props->name) {
+        if (props->defval) {
+            qdev_prop_cpy(dev, props, props->defval);
+        }
+        props++;
+    }
+}
+
+static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props);
+
+static void qdev_prop_register_global(GlobalProperty *prop)
+{
+    QTAILQ_INSERT_TAIL(&global_props, prop, next);
+}
+
+void qdev_prop_register_global_list(GlobalProperty *props)
+{
+    int i;
+
+    for (i = 0; props[i].driver != NULL; i++) {
+        qdev_prop_register_global(props+i);
+    }
+}
+
+void qdev_prop_set_globals(DeviceState *dev)
+{
+    GlobalProperty *prop;
+
+    QTAILQ_FOREACH(prop, &global_props, next) {
+        if (strcmp(dev->info->name, prop->driver) != 0 &&
+            strcmp(dev->info->bus_info->name, prop->driver) != 0) {
+            continue;
+        }
+        if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
+            exit(1);
+        }
+    }
+}
+
+static int qdev_add_one_global(QemuOpts *opts, void *opaque)
+{
+    GlobalProperty *g;
+
+    g = qemu_mallocz(sizeof(*g));
+    g->driver   = qemu_opt_get(opts, "driver");
+    g->property = qemu_opt_get(opts, "property");
+    g->value    = qemu_opt_get(opts, "value");
+    qdev_prop_register_global(g);
+    return 0;
+}
+
+void qemu_add_globals(void)
+{
+    qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
+}
diff --git a/qemu-0.15.x/hw/qdev.c b/qemu-0.15.x/hw/qdev.c
new file mode 100644
index 0000000..a0fcd06
--- /dev/null
+++ b/qemu-0.15.x/hw/qdev.c
@@ -0,0 +1,940 @@
+/*
+ *  Dynamic device configuration and creation.
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The theory here is that it should be possible to create a machine without
+   knowledge of specific devices.  Historically board init routines have
+   passed a bunch of arguments to each device, requiring the board know
+   exactly which device it is dealing with.  This file provides an abstract
+   API for device configuration and initialization.  Devices will generally
+   inherit from a particular bus (e.g. PCI or I2C) rather than
+   this API directly.  */
+
+#include "net.h"
+#include "qdev.h"
+#include "sysemu.h"
+#include "monitor.h"
+
+static int qdev_hotplug = 0;
+static bool qdev_hot_added = false;
+static bool qdev_hot_removed = false;
+
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+static BusState *main_system_bus;
+
+DeviceInfo *device_info_list;
+
+static BusState *qbus_find_recursive(BusState *bus, const char *name,
+                                     const BusInfo *info);
+static BusState *qbus_find(const char *path);
+
+/* Register a new device type.  */
+void qdev_register(DeviceInfo *info)
+{
+    assert(info->size >= sizeof(DeviceState));
+    assert(!info->next);
+
+    info->next = device_info_list;
+    device_info_list = info;
+}
+
+static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+{
+    DeviceInfo *info;
+
+    /* first check device names */
+    for (info = device_info_list; info != NULL; info = info->next) {
+        if (bus_info && info->bus_info != bus_info)
+            continue;
+        if (strcmp(info->name, name) != 0)
+            continue;
+        return info;
+    }
+
+    /* failing that check the aliases */
+    for (info = device_info_list; info != NULL; info = info->next) {
+        if (bus_info && info->bus_info != bus_info)
+            continue;
+        if (!info->alias)
+            continue;
+        if (strcmp(info->alias, name) != 0)
+            continue;
+        return info;
+    }
+    return NULL;
+}
+
+static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+{
+    DeviceState *dev;
+
+    assert(bus->info == info->bus_info);
+    dev = qemu_mallocz(info->size);
+    dev->info = info;
+    dev->parent_bus = bus;
+    qdev_prop_set_defaults(dev, dev->info->props);
+    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+    qdev_prop_set_globals(dev);
+    QLIST_INSERT_HEAD(&bus->children, dev, sibling);
+    if (qdev_hotplug) {
+        assert(bus->allow_hotplug);
+        dev->hotplugged = 1;
+        qdev_hot_added = true;
+    }
+    dev->instance_id_alias = -1;
+    dev->state = DEV_STATE_CREATED;
+    return dev;
+}
+
+/* Create a new device.  This only initializes the device state structure
+   and allows properties to be set.  qdev_init should be called to
+   initialize the actual device emulation.  */
+DeviceState *qdev_create(BusState *bus, const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_try_create(bus, name);
+    if (!dev) {
+        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
+    }
+
+    return dev;
+}
+
+DeviceState *qdev_try_create(BusState *bus, const char *name)
+{
+    DeviceInfo *info;
+
+    if (!bus) {
+        bus = sysbus_get_default();
+    }
+
+    info = qdev_find_info(bus->info, name);
+    if (!info) {
+        return NULL;
+    }
+
+    return qdev_create_from_info(bus, info);
+}
+
+static void qdev_print_devinfo(DeviceInfo *info)
+{
+    error_printf("name \"%s\", bus %s",
+                 info->name, info->bus_info->name);
+    if (info->alias) {
+        error_printf(", alias \"%s\"", info->alias);
+    }
+    if (info->desc) {
+        error_printf(", desc \"%s\"", info->desc);
+    }
+    if (info->no_user) {
+        error_printf(", no-user");
+    }
+    error_printf("\n");
+}
+
+static int set_property(const char *name, const char *value, void *opaque)
+{
+    DeviceState *dev = opaque;
+
+    if (strcmp(name, "driver") == 0)
+        return 0;
+    if (strcmp(name, "bus") == 0)
+        return 0;
+
+    if (qdev_prop_parse(dev, name, value) == -1) {
+        return -1;
+    }
+    return 0;
+}
+
+int qdev_device_help(QemuOpts *opts)
+{
+    const char *driver;
+    DeviceInfo *info;
+    Property *prop;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (driver && !strcmp(driver, "?")) {
+        for (info = device_info_list; info != NULL; info = info->next) {
+            if (info->no_user) {
+                continue;       /* not available, don't show */
+            }
+            qdev_print_devinfo(info);
+        }
+        return 1;
+    }
+
+    if (!qemu_opt_get(opts, "?")) {
+        return 0;
+    }
+
+    info = qdev_find_info(NULL, driver);
+    if (!info) {
+        return 0;
+    }
+
+    for (prop = info->props; prop && prop->name; prop++) {
+        /*
+         * TODO Properties without a parser are just for dirty hacks.
+         * qdev_prop_ptr is the only such PropertyInfo.  It's marked
+         * for removal.  This conditional should be removed along with
+         * it.
+         */
+        if (!prop->info->parse) {
+            continue;           /* no way to set it, don't show */
+        }
+        error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
+    }
+    return 1;
+}
+
+DeviceState *qdev_device_add(QemuOpts *opts)
+{
+    const char *driver, *path, *id;
+    DeviceInfo *info;
+    DeviceState *qdev;
+    BusState *bus;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (!driver) {
+        qerror_report(QERR_MISSING_PARAMETER, "driver");
+        return NULL;
+    }
+
+    /* find driver */
+    info = qdev_find_info(NULL, driver);
+    if (!info || info->no_user) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
+        error_printf_unless_qmp("Try with argument '?' for a list.\n");
+        return NULL;
+    }
+
+    /* find bus */
+    path = qemu_opt_get(opts, "bus");
+    if (path != NULL) {
+        bus = qbus_find(path);
+        if (!bus) {
+            return NULL;
+        }
+        if (bus->info != info->bus_info) {
+            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
+                           driver, bus->info->name);
+            return NULL;
+        }
+    } else {
+        bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
+        if (!bus) {
+            qerror_report(QERR_NO_BUS_FOR_DEVICE,
+                           info->name, info->bus_info->name);
+            return NULL;
+        }
+    }
+    if (qdev_hotplug && !bus->allow_hotplug) {
+        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
+        return NULL;
+    }
+
+    /* create device, set properties */
+    qdev = qdev_create_from_info(bus, info);
+    id = qemu_opts_id(opts);
+    if (id) {
+        qdev->id = id;
+    }
+    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
+        qdev_free(qdev);
+        return NULL;
+    }
+    if (qdev_init(qdev) < 0) {
+        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+        return NULL;
+    }
+    qdev->opts = opts;
+    return qdev;
+}
+
+/* Initialize a device.  Device properties should be set before calling
+   this function.  IRQs and MMIO regions should be connected/mapped after
+   calling this function.
+   On failure, destroy the device and return negative value.
+   Return 0 on success.  */
+int qdev_init(DeviceState *dev)
+{
+    int rc;
+
+    assert(dev->state == DEV_STATE_CREATED);
+    rc = dev->info->init(dev, dev->info);
+    if (rc < 0) {
+        qdev_free(dev);
+        return rc;
+    }
+    if (dev->info->vmsd) {
+        vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
+                                       dev->instance_id_alias,
+                                       dev->alias_required_for_version);
+    }
+    dev->state = DEV_STATE_INITIALIZED;
+    return 0;
+}
+
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+                                 int required_for_version)
+{
+    assert(dev->state == DEV_STATE_CREATED);
+    dev->instance_id_alias = alias_id;
+    dev->alias_required_for_version = required_for_version;
+}
+
+int qdev_unplug(DeviceState *dev)
+{
+    if (!dev->parent_bus->allow_hotplug) {
+        qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
+        return -1;
+    }
+    assert(dev->info->unplug != NULL);
+
+    qdev_hot_removed = true;
+
+    return dev->info->unplug(dev);
+}
+
+static int qdev_reset_one(DeviceState *dev, void *opaque)
+{
+    if (dev->info->reset) {
+        dev->info->reset(dev);
+    }
+
+    return 0;
+}
+
+BusState *sysbus_get_default(void)
+{
+    if (!main_system_bus) {
+        main_system_bus = qbus_create(&system_bus_info, NULL,
+                                      "main-system-bus");
+    }
+    return main_system_bus;
+}
+
+static int qbus_reset_one(BusState *bus, void *opaque)
+{
+    if (bus->info->reset) {
+        return bus->info->reset(bus);
+    }
+    return 0;
+}
+
+void qdev_reset_all(DeviceState *dev)
+{
+    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
+}
+
+void qbus_reset_all_fn(void *opaque)
+{
+    BusState *bus = opaque;
+    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
+}
+
+/* can be used as ->unplug() callback for the simple cases */
+int qdev_simple_unplug_cb(DeviceState *dev)
+{
+    /* just zap it */
+    qdev_free(dev);
+    return 0;
+}
+
+
+/* Like qdev_init(), but terminate program via error_report() instead of
+   returning an error value.  This is okay during machine creation.
+   Don't use for hotplug, because there callers need to recover from
+   failure.  Exception: if you know the device's init() callback can't
+   fail, then qdev_init_nofail() can't fail either, and is therefore
+   usable even then.  But relying on the device implementation that
+   way is somewhat unclean, and best avoided.  */
+void qdev_init_nofail(DeviceState *dev)
+{
+    DeviceInfo *info = dev->info;
+
+    if (qdev_init(dev) < 0) {
+        error_report("Initialization of device %s failed", info->name);
+        exit(1);
+    }
+}
+
+/* Unlink device from bus and free the structure.  */
+void qdev_free(DeviceState *dev)
+{
+    BusState *bus;
+    Property *prop;
+
+    if (dev->state == DEV_STATE_INITIALIZED) {
+        while (dev->num_child_bus) {
+            bus = QLIST_FIRST(&dev->child_bus);
+            qbus_free(bus);
+        }
+        if (dev->info->vmsd)
+            vmstate_unregister(dev, dev->info->vmsd, dev);
+        if (dev->info->exit)
+            dev->info->exit(dev);
+        if (dev->opts)
+            qemu_opts_del(dev->opts);
+    }
+    QLIST_REMOVE(dev, sibling);
+    for (prop = dev->info->props; prop && prop->name; prop++) {
+        if (prop->info->free) {
+            prop->info->free(dev, prop);
+        }
+    }
+    qemu_free(dev);
+}
+
+void qdev_machine_creation_done(void)
+{
+    /*
+     * ok, initial machine setup is done, starting from now we can
+     * only create hotpluggable devices
+     */
+    qdev_hotplug = 1;
+}
+
+bool qdev_machine_modified(void)
+{
+    return qdev_hot_added || qdev_hot_removed;
+}
+
+/* Get a character (serial) device interface.  */
+CharDriverState *qdev_init_chardev(DeviceState *dev)
+{
+    static int next_serial;
+
+    /* FIXME: This function needs to go away: use chardev properties!  */
+    return serial_hds[next_serial++];
+}
+
+BusState *qdev_get_parent_bus(DeviceState *dev)
+{
+    return dev->parent_bus;
+}
+
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
+{
+    assert(dev->num_gpio_in == 0);
+    dev->num_gpio_in = n;
+    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
+}
+
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
+{
+    assert(dev->num_gpio_out == 0);
+    dev->num_gpio_out = n;
+    dev->gpio_out = pins;
+}
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
+{
+    assert(n >= 0 && n < dev->num_gpio_in);
+    return dev->gpio_in[n];
+}
+
+void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
+{
+    assert(n >= 0 && n < dev->num_gpio_out);
+    dev->gpio_out[n] = pin;
+}
+
+void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
+{
+    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
+    if (nd->vlan)
+        qdev_prop_set_vlan(dev, "vlan", nd->vlan);
+    if (nd->netdev)
+        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
+    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
+        qdev_prop_exists(dev, "vectors")) {
+        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
+    }
+    nd->instantiated = 1;
+}
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
+{
+    BusState *bus;
+
+    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+        if (strcmp(name, bus->name) == 0) {
+            return bus;
+        }
+    }
+    return NULL;
+}
+
+int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque)
+{
+    DeviceState *dev;
+    int err;
+
+    if (busfn) {
+        err = busfn(bus, opaque);
+        if (err) {
+            return err;
+        }
+    }
+
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        err = qdev_walk_children(dev, devfn, busfn, opaque);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque)
+{
+    BusState *bus;
+    int err;
+
+    if (devfn) {
+        err = devfn(dev, opaque);
+        if (err) {
+            return err;
+        }
+    }
+
+    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+        err = qbus_walk_children(bus, devfn, busfn, opaque);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+static BusState *qbus_find_recursive(BusState *bus, const char *name,
+                                     const BusInfo *info)
+{
+    DeviceState *dev;
+    BusState *child, *ret;
+    int match = 1;
+
+    if (name && (strcmp(bus->name, name) != 0)) {
+        match = 0;
+    }
+    if (info && (bus->info != info)) {
+        match = 0;
+    }
+    if (match) {
+        return bus;
+    }
+
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        QLIST_FOREACH(child, &dev->child_bus, sibling) {
+            ret = qbus_find_recursive(child, name, info);
+            if (ret) {
+                return ret;
+            }
+        }
+    }
+    return NULL;
+}
+
+DeviceState *qdev_find_recursive(BusState *bus, const char *id)
+{
+    DeviceState *dev, *ret;
+    BusState *child;
+
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        if (dev->id && strcmp(dev->id, id) == 0)
+            return dev;
+        QLIST_FOREACH(child, &dev->child_bus, sibling) {
+            ret = qdev_find_recursive(child, id);
+            if (ret) {
+                return ret;
+            }
+        }
+    }
+    return NULL;
+}
+
+static void qbus_list_bus(DeviceState *dev)
+{
+    BusState *child;
+    const char *sep = " ";
+
+    error_printf("child busses at \"%s\":",
+                 dev->id ? dev->id : dev->info->name);
+    QLIST_FOREACH(child, &dev->child_bus, sibling) {
+        error_printf("%s\"%s\"", sep, child->name);
+        sep = ", ";
+    }
+    error_printf("\n");
+}
+
+static void qbus_list_dev(BusState *bus)
+{
+    DeviceState *dev;
+    const char *sep = " ";
+
+    error_printf("devices at \"%s\":", bus->name);
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        error_printf("%s\"%s\"", sep, dev->info->name);
+        if (dev->id)
+            error_printf("/\"%s\"", dev->id);
+        sep = ", ";
+    }
+    error_printf("\n");
+}
+
+static BusState *qbus_find_bus(DeviceState *dev, char *elem)
+{
+    BusState *child;
+
+    QLIST_FOREACH(child, &dev->child_bus, sibling) {
+        if (strcmp(child->name, elem) == 0) {
+            return child;
+        }
+    }
+    return NULL;
+}
+
+static DeviceState *qbus_find_dev(BusState *bus, char *elem)
+{
+    DeviceState *dev;
+
+    /*
+     * try to match in order:
+     *   (1) instance id, if present
+     *   (2) driver name
+     *   (3) driver alias, if present
+     */
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
+            return dev;
+        }
+    }
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        if (strcmp(dev->info->name, elem) == 0) {
+            return dev;
+        }
+    }
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
+static BusState *qbus_find(const char *path)
+{
+    DeviceState *dev;
+    BusState *bus;
+    char elem[128];
+    int pos, len;
+
+    /* find start element */
+    if (path[0] == '/') {
+        bus = main_system_bus;
+        pos = 0;
+    } else {
+        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
+            assert(!path[0]);
+            elem[0] = len = 0;
+        }
+        bus = qbus_find_recursive(main_system_bus, elem, NULL);
+        if (!bus) {
+            qerror_report(QERR_BUS_NOT_FOUND, elem);
+            return NULL;
+        }
+        pos = len;
+    }
+
+    for (;;) {
+        assert(path[pos] == '/' || !path[pos]);
+        while (path[pos] == '/') {
+            pos++;
+        }
+        if (path[pos] == '\0') {
+            return bus;
+        }
+
+        /* find device */
+        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+            assert(0);
+            elem[0] = len = 0;
+        }
+        pos += len;
+        dev = qbus_find_dev(bus, elem);
+        if (!dev) {
+            qerror_report(QERR_DEVICE_NOT_FOUND, elem);
+            if (!monitor_cur_is_qmp()) {
+                qbus_list_dev(bus);
+            }
+            return NULL;
+        }
+
+        assert(path[pos] == '/' || !path[pos]);
+        while (path[pos] == '/') {
+            pos++;
+        }
+        if (path[pos] == '\0') {
+            /* last specified element is a device.  If it has exactly
+             * one child bus accept it nevertheless */
+            switch (dev->num_child_bus) {
+            case 0:
+                qerror_report(QERR_DEVICE_NO_BUS, elem);
+                return NULL;
+            case 1:
+                return QLIST_FIRST(&dev->child_bus);
+            default:
+                qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
+                if (!monitor_cur_is_qmp()) {
+                    qbus_list_bus(dev);
+                }
+                return NULL;
+            }
+        }
+
+        /* find bus */
+        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+            assert(0);
+            elem[0] = len = 0;
+        }
+        pos += len;
+        bus = qbus_find_bus(dev, elem);
+        if (!bus) {
+            qerror_report(QERR_BUS_NOT_FOUND, elem);
+            if (!monitor_cur_is_qmp()) {
+                qbus_list_bus(dev);
+            }
+            return NULL;
+        }
+    }
+}
+
+void qbus_create_inplace(BusState *bus, BusInfo *info,
+                         DeviceState *parent, const char *name)
+{
+    char *buf;
+    int i,len;
+
+    bus->info = info;
+    bus->parent = parent;
+
+    if (name) {
+        /* use supplied name */
+        bus->name = qemu_strdup(name);
+    } else if (parent && parent->id) {
+        /* parent device has id -> use it for bus name */
+        len = strlen(parent->id) + 16;
+        buf = qemu_malloc(len);
+        snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
+        bus->name = buf;
+    } else {
+        /* no id -> use lowercase bus type for bus name */
+        len = strlen(info->name) + 16;
+        buf = qemu_malloc(len);
+        len = snprintf(buf, len, "%s.%d", info->name,
+                       parent ? parent->num_child_bus : 0);
+        for (i = 0; i < len; i++)
+            buf[i] = qemu_tolower(buf[i]);
+        bus->name = buf;
+    }
+
+    QLIST_INIT(&bus->children);
+    if (parent) {
+        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
+        parent->num_child_bus++;
+    } else if (bus != main_system_bus) {
+        /* TODO: once all bus devices are qdevified,
+           only reset handler for main_system_bus should be registered here. */
+        qemu_register_reset(qbus_reset_all_fn, bus);
+    }
+}
+
+BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
+{
+    BusState *bus;
+
+    bus = qemu_mallocz(info->size);
+    bus->qdev_allocated = 1;
+    qbus_create_inplace(bus, info, parent, name);
+    return bus;
+}
+
+void qbus_free(BusState *bus)
+{
+    DeviceState *dev;
+
+    while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
+        qdev_free(dev);
+    }
+    if (bus->parent) {
+        QLIST_REMOVE(bus, sibling);
+        bus->parent->num_child_bus--;
+    } else {
+        assert(bus != main_system_bus); /* main_system_bus is never freed */
+        qemu_unregister_reset(qbus_reset_all_fn, bus);
+    }
+    qemu_free((void*)bus->name);
+    if (bus->qdev_allocated) {
+        qemu_free(bus);
+    }
+}
+
+#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
+static void qbus_print(Monitor *mon, BusState *bus, int indent);
+
+static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
+                             const char *prefix, int indent)
+{
+    char buf[64];
+
+    if (!props)
+        return;
+    while (props->name) {
+        /*
+         * TODO Properties without a print method are just for dirty
+         * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
+         * marked for removal.  The test props->info->print should be
+         * removed along with it.
+         */
+        if (props->info->print) {
+            props->info->print(dev, props, buf, sizeof(buf));
+            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
+        }
+        props++;
+    }
+}
+
+static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    BusState *child;
+    qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
+                dev->id ? dev->id : "");
+    indent += 2;
+    if (dev->num_gpio_in) {
+        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
+    }
+    if (dev->num_gpio_out) {
+        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
+    }
+    qdev_print_props(mon, dev, dev->info->props, "dev", indent);
+    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
+    if (dev->parent_bus->info->print_dev)
+        dev->parent_bus->info->print_dev(mon, dev, indent);
+    QLIST_FOREACH(child, &dev->child_bus, sibling) {
+        qbus_print(mon, child, indent);
+    }
+}
+
+static void qbus_print(Monitor *mon, BusState *bus, int indent)
+{
+    struct DeviceState *dev;
+
+    qdev_printf("bus: %s\n", bus->name);
+    indent += 2;
+    qdev_printf("type %s\n", bus->info->name);
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        qdev_print(mon, dev, indent);
+    }
+}
+#undef qdev_printf
+
+void do_info_qtree(Monitor *mon)
+{
+    if (main_system_bus)
+        qbus_print(mon, main_system_bus, 0);
+}
+
+void do_info_qdm(Monitor *mon)
+{
+    DeviceInfo *info;
+
+    for (info = device_info_list; info != NULL; info = info->next) {
+        qdev_print_devinfo(info);
+    }
+}
+
+int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    QemuOpts *opts;
+
+    opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
+    if (!opts) {
+        return -1;
+    }
+    if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
+        qemu_opts_del(opts);
+        return 0;
+    }
+    if (!qdev_device_add(opts)) {
+        qemu_opts_del(opts);
+        return -1;
+    }
+    return 0;
+}
+
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    DeviceState *dev;
+
+    dev = qdev_find_recursive(main_system_bus, id);
+    if (NULL == dev) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        return -1;
+    }
+    return qdev_unplug(dev);
+}
+
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+{
+    int l = 0;
+
+    if (dev && dev->parent_bus) {
+        char *d;
+        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
+        if (dev->parent_bus->info->get_fw_dev_path) {
+            d = dev->parent_bus->info->get_fw_dev_path(dev);
+            l += snprintf(p + l, size - l, "%s", d);
+            qemu_free(d);
+        } else {
+            l += snprintf(p + l, size - l, "%s", dev->info->name);
+        }
+    }
+    l += snprintf(p + l , size - l, "/");
+
+    return l;
+}
+
+char* qdev_get_fw_dev_path(DeviceState *dev)
+{
+    char path[128];
+    int l;
+
+    l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+    path[l-1] = '\0';
+
+    return strdup(path);
+}
diff --git a/qemu-0.15.x/hw/qdev.h b/qemu-0.15.x/hw/qdev.h
new file mode 100644
index 0000000..8a13ec9
--- /dev/null
+++ b/qemu-0.15.x/hw/qdev.h
@@ -0,0 +1,329 @@
+#ifndef QDEV_H
+#define QDEV_H
+
+#include "hw.h"
+#include "qemu-queue.h"
+#include "qemu-char.h"
+#include "qemu-option.h"
+
+typedef struct Property Property;
+
+typedef struct PropertyInfo PropertyInfo;
+
+typedef struct CompatProperty CompatProperty;
+
+typedef struct DeviceInfo DeviceInfo;
+
+typedef struct BusState BusState;
+
+typedef struct BusInfo BusInfo;
+
+enum DevState {
+    DEV_STATE_CREATED = 1,
+    DEV_STATE_INITIALIZED,
+};
+
+enum {
+    DEV_NVECTORS_UNSPECIFIED = -1,
+};
+
+/* This structure should not be accessed directly.  We declare it here
+   so that it can be embedded in individual device state structures.  */
+struct DeviceState {
+    const char *id;
+    enum DevState state;
+    QemuOpts *opts;
+    int hotplugged;
+    DeviceInfo *info;
+    BusState *parent_bus;
+    int num_gpio_out;
+    qemu_irq *gpio_out;
+    int num_gpio_in;
+    qemu_irq *gpio_in;
+    QLIST_HEAD(, BusState) child_bus;
+    int num_child_bus;
+    QLIST_ENTRY(DeviceState) sibling;
+    int instance_id_alias;
+    int alias_required_for_version;
+};
+
+typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
+typedef char *(*bus_get_dev_path)(DeviceState *dev);
+/*
+ * This callback is used to create Open Firmware device path in accordance with
+ * OF spec http://forthworks.com/standards/of1275.pdf. Indicidual bus bindings
+ * can be found here http://playground.sun.com/1275/bindings/.
+ */
+typedef char *(*bus_get_fw_dev_path)(DeviceState *dev);
+typedef int (qbus_resetfn)(BusState *bus);
+
+struct BusInfo {
+    const char *name;
+    size_t size;
+    bus_dev_printfn print_dev;
+    bus_get_dev_path get_dev_path;
+    bus_get_fw_dev_path get_fw_dev_path;
+    qbus_resetfn *reset;
+    Property *props;
+};
+
+struct BusState {
+    DeviceState *parent;
+    BusInfo *info;
+    const char *name;
+    int allow_hotplug;
+    int qdev_allocated;
+    QLIST_HEAD(, DeviceState) children;
+    QLIST_ENTRY(BusState) sibling;
+};
+
+struct Property {
+    const char   *name;
+    PropertyInfo *info;
+    int          offset;
+    int          bitnr;
+    void         *defval;
+};
+
+enum PropertyType {
+    PROP_TYPE_UNSPEC = 0,
+    PROP_TYPE_UINT8,
+    PROP_TYPE_UINT16,
+    PROP_TYPE_UINT32,
+    PROP_TYPE_INT32,
+    PROP_TYPE_UINT64,
+    PROP_TYPE_TADDR,
+    PROP_TYPE_MACADDR,
+    PROP_TYPE_DRIVE,
+    PROP_TYPE_CHR,
+    PROP_TYPE_STRING,
+    PROP_TYPE_NETDEV,
+    PROP_TYPE_VLAN,
+    PROP_TYPE_PTR,
+    PROP_TYPE_BIT,
+};
+
+struct PropertyInfo {
+    const char *name;
+    size_t size;
+    enum PropertyType type;
+    int (*parse)(DeviceState *dev, Property *prop, const char *str);
+    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
+    void (*free)(DeviceState *dev, Property *prop);
+};
+
+typedef struct GlobalProperty {
+    const char *driver;
+    const char *property;
+    const char *value;
+    QTAILQ_ENTRY(GlobalProperty) next;
+} GlobalProperty;
+
+/*** Board API.  This should go away once we have a machine config file.  ***/
+
+DeviceState *qdev_create(BusState *bus, const char *name);
+DeviceState *qdev_try_create(BusState *bus, const char *name);
+int qdev_device_help(QemuOpts *opts);
+DeviceState *qdev_device_add(QemuOpts *opts);
+int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
+void qdev_init_nofail(DeviceState *dev);
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+                                 int required_for_version);
+int qdev_unplug(DeviceState *dev);
+void qdev_free(DeviceState *dev);
+int qdev_simple_unplug_cb(DeviceState *dev);
+void qdev_machine_creation_done(void);
+bool qdev_machine_modified(void);
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
+void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
+
+/*** Device API.  ***/
+
+typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
+
+struct DeviceInfo {
+    const char *name;
+    const char *fw_name;
+    const char *alias;
+    const char *desc;
+    size_t size;
+    Property *props;
+    int no_user;
+
+    /* callbacks */
+    qdev_resetfn reset;
+
+    /* device state */
+    const VMStateDescription *vmsd;
+
+    /* Private to qdev / bus.  */
+    qdev_initfn init;
+    qdev_event unplug;
+    qdev_event exit;
+    BusInfo *bus_info;
+    struct DeviceInfo *next;
+};
+extern DeviceInfo *device_info_list;
+
+void qdev_register(DeviceInfo *info);
+
+/* Register device properties.  */
+/* GPIO inputs also double as IRQ sinks.  */
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
+
+CharDriverState *qdev_init_chardev(DeviceState *dev);
+
+BusState *qdev_get_parent_bus(DeviceState *dev);
+
+/*** BUS API. ***/
+
+DeviceState *qdev_find_recursive(BusState *bus, const char *id);
+
+/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
+typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
+typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
+
+void qbus_create_inplace(BusState *bus, BusInfo *info,
+                         DeviceState *parent, const char *name);
+BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name);
+/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
+ *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
+ *           0 otherwise. */
+int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque);
+int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque);
+void qdev_reset_all(DeviceState *dev);
+void qbus_reset_all_fn(void *opaque);
+
+void qbus_free(BusState *bus);
+
+#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
+
+/* This should go away once we get rid of the NULL bus hack */
+BusState *sysbus_get_default(void);
+
+/*** monitor commands ***/
+
+void do_info_qtree(Monitor *mon);
+void do_info_qdm(Monitor *mon);
+int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+/*** qdev-properties.c ***/
+
+extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_uint8;
+extern PropertyInfo qdev_prop_uint16;
+extern PropertyInfo qdev_prop_uint32;
+extern PropertyInfo qdev_prop_int32;
+extern PropertyInfo qdev_prop_uint64;
+extern PropertyInfo qdev_prop_hex32;
+extern PropertyInfo qdev_prop_hex64;
+extern PropertyInfo qdev_prop_string;
+extern PropertyInfo qdev_prop_chr;
+extern PropertyInfo qdev_prop_ptr;
+extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_drive;
+extern PropertyInfo qdev_prop_netdev;
+extern PropertyInfo qdev_prop_vlan;
+extern PropertyInfo qdev_prop_pci_devfn;
+
+#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
+        .name      = (_name),                                    \
+        .info      = &(_prop),                                   \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(_type,typeof_field(_state, _field)),    \
+        }
+#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
+        .name      = (_name),                                           \
+        .info      = &(_prop),                                          \
+        .offset    = offsetof(_state, _field)                           \
+            + type_check(_type,typeof_field(_state, _field)),           \
+        .defval    = (_type[]) { _defval },                             \
+        }
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
+        .name      = (_name),                                    \
+        .info      = &(qdev_prop_bit),                           \
+        .bitnr    = (_bit),                                      \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(uint32_t,typeof_field(_state, _field)), \
+        .defval    = (bool[]) { (_defval) },                     \
+        }
+
+#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
+#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
+#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
+#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
+#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
+#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
+#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
+#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, uint32_t)
+
+#define DEFINE_PROP_PTR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
+#define DEFINE_PROP_CHR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
+#define DEFINE_PROP_STRING(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
+#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
+#define DEFINE_PROP_VLAN(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
+#define DEFINE_PROP_DRIVE(_n, _s, _f) \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
+#define DEFINE_PROP_MACADDR(_n, _s, _f)         \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+
+#define DEFINE_PROP_END_OF_LIST()               \
+    {}
+
+/* Set properties between creation and init.  */
+void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
+int qdev_prop_exists(DeviceState *dev, const char *name);
+int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
+void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
+void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
+void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
+void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
+void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
+void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
+void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
+void qdev_prop_set_string(DeviceState *dev, const char *name, char *value);
+void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
+void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value);
+void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
+int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
+void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
+void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
+/* FIXME: Remove opaque pointer properties.  */
+void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
+void qdev_prop_set_defaults(DeviceState *dev, Property *props);
+
+void qdev_prop_register_global_list(GlobalProperty *props);
+void qdev_prop_set_globals(DeviceState *dev);
+
+static inline const char *qdev_fw_name(DeviceState *dev)
+{
+    return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
+}
+
+char *qdev_get_fw_dev_path(DeviceState *dev);
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+extern struct BusInfo system_bus_info;
+
+#endif
diff --git a/qemu-0.15.x/hw/qxl-logger.c b/qemu-0.15.x/hw/qxl-logger.c
new file mode 100644
index 0000000..74cadba
--- /dev/null
+++ b/qemu-0.15.x/hw/qxl-logger.c
@@ -0,0 +1,250 @@
+/*
+ * qxl command logging -- for debug purposes
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-timer.h"
+#include "qxl.h"
+
+static const char *qxl_type[] = {
+    [ QXL_CMD_NOP ]     = "nop",
+    [ QXL_CMD_DRAW ]    = "draw",
+    [ QXL_CMD_UPDATE ]  = "update",
+    [ QXL_CMD_CURSOR ]  = "cursor",
+    [ QXL_CMD_MESSAGE ] = "message",
+    [ QXL_CMD_SURFACE ] = "surface",
+};
+
+static const char *qxl_draw_type[] = {
+    [ QXL_DRAW_NOP         ] = "nop",
+    [ QXL_DRAW_FILL        ] = "fill",
+    [ QXL_DRAW_OPAQUE      ] = "opaque",
+    [ QXL_DRAW_COPY        ] = "copy",
+    [ QXL_COPY_BITS        ] = "copy-bits",
+    [ QXL_DRAW_BLEND       ] = "blend",
+    [ QXL_DRAW_BLACKNESS   ] = "blackness",
+    [ QXL_DRAW_WHITENESS   ] = "whitemess",
+    [ QXL_DRAW_INVERS      ] = "invers",
+    [ QXL_DRAW_ROP3        ] = "rop3",
+    [ QXL_DRAW_STROKE      ] = "stroke",
+    [ QXL_DRAW_TEXT        ] = "text",
+    [ QXL_DRAW_TRANSPARENT ] = "transparent",
+    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
+};
+
+static const char *qxl_draw_effect[] = {
+    [ QXL_EFFECT_BLEND            ] = "blend",
+    [ QXL_EFFECT_OPAQUE           ] = "opaque",
+    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
+    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
+    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
+    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
+    [ QXL_EFFECT_NOP              ] = "nop",
+    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
+};
+
+static const char *qxl_surface_cmd[] = {
+   [ QXL_SURFACE_CMD_CREATE  ] = "create",
+   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
+};
+
+static const char *spice_surface_fmt[] = {
+   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
+   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
+   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
+   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
+   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
+   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
+   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
+};
+
+static const char *qxl_cursor_cmd[] = {
+   [ QXL_CURSOR_SET   ] = "set",
+   [ QXL_CURSOR_MOVE  ] = "move",
+   [ QXL_CURSOR_HIDE  ] = "hide",
+   [ QXL_CURSOR_TRAIL ] = "trail",
+};
+
+static const char *spice_cursor_type[] = {
+   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
+   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
+   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
+   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
+   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
+   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
+   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
+};
+
+static const char *qxl_v2n(const char *n[], size_t l, int v)
+{
+    if (v >= l || !n[v]) {
+        return "???";
+    }
+    return n[v];
+}
+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
+
+static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
+{
+    QXLImage *image;
+    QXLImageDescriptor *desc;
+
+    image = qxl_phys2virt(qxl, addr, group_id);
+    desc = &image->descriptor;
+    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
+            desc->id, desc->type, desc->flags, desc->width, desc->height);
+    switch (desc->type) {
+    case SPICE_IMAGE_TYPE_BITMAP:
+        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
+                " palette %" PRIx64 " data %" PRIx64,
+                image->bitmap.format, image->bitmap.flags,
+                image->bitmap.x, image->bitmap.y,
+                image->bitmap.stride,
+                image->bitmap.palette, image->bitmap.data);
+        break;
+    }
+    fprintf(stderr, ")");
+}
+
+static void qxl_log_rect(QXLRect *rect)
+{
+    fprintf(stderr, " %dx%d+%d+%d",
+            rect->right - rect->left,
+            rect->bottom - rect->top,
+            rect->left, rect->top);
+}
+
+static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id)
+{
+    fprintf(stderr, " src %" PRIx64,
+            copy->src_bitmap);
+    qxl_log_image(qxl, copy->src_bitmap, group_id);
+    fprintf(stderr, " area");
+    qxl_log_rect(&copy->src_area);
+    fprintf(stderr, " rop %d", copy->rop_descriptor);
+}
+
+static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
+{
+    fprintf(stderr, ": surface_id %d type %s effect %s",
+            draw->surface_id,
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+}
+
+static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
+                                    int group_id)
+{
+    fprintf(stderr, ": type %s effect %s",
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    if (draw->bitmap_offset) {
+        fprintf(stderr, ": bitmap %d",
+                draw->bitmap_offset);
+        qxl_log_rect(&draw->bitmap_area);
+    }
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+}
+
+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
+{
+    fprintf(stderr, ": %s id %d",
+            qxl_name(qxl_surface_cmd, cmd->type),
+            cmd->surface_id);
+    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
+                cmd->u.surface_create.width,
+                cmd->u.surface_create.height,
+                cmd->u.surface_create.stride,
+                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
+                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
+    }
+    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
+    }
+}
+
+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
+{
+    QXLCursor *cursor;
+
+    fprintf(stderr, ": %s",
+            qxl_name(qxl_cursor_cmd, cmd->type));
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
+                cmd->u.set.position.x,
+                cmd->u.set.position.y,
+                cmd->u.set.visible ? "yes" : "no",
+                cmd->u.set.shape);
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
+        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
+                " unique 0x%" PRIx64 " data-size %d",
+                qxl_name(spice_cursor_type, cursor->header.type),
+                cursor->header.width, cursor->header.height,
+                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
+                cursor->header.unique, cursor->data_size);
+        break;
+    case QXL_CURSOR_MOVE:
+        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
+        break;
+    }
+}
+
+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
+{
+    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
+    void *data;
+
+    if (!qxl->cmdlog) {
+        return;
+    }
+    fprintf(stderr, "%ld qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+            qxl->id, ring);
+    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
+            qxl_name(qxl_type, ext->cmd.type),
+            compat ? "(compat)" : "");
+
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    switch (ext->cmd.type) {
+    case QXL_CMD_DRAW:
+        if (!compat) {
+            qxl_log_cmd_draw(qxl, data, ext->group_id);
+        } else {
+            qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
+        }
+        break;
+    case QXL_CMD_SURFACE:
+        qxl_log_cmd_surface(qxl, data);
+        break;
+    case QXL_CMD_CURSOR:
+        qxl_log_cmd_cursor(qxl, data, ext->group_id);
+        break;
+    }
+    fprintf(stderr, "\n");
+}
diff --git a/qemu-0.15.x/hw/qxl-render.c b/qemu-0.15.x/hw/qxl-render.c
new file mode 100644
index 0000000..1316066
--- /dev/null
+++ b/qemu-0.15.x/hw/qxl-render.c
@@ -0,0 +1,225 @@
+/*
+ * qxl local rendering (aka display on sdl/vnc)
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qxl.h"
+
+static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
+{
+    uint8_t *src = qxl->guest_primary.data;
+    uint8_t *dst = qxl->guest_primary.flipped;
+    int len, i;
+
+    src += (qxl->guest_primary.surface.height - rect->top - 1) *
+        qxl->guest_primary.stride;
+    dst += rect->top  * qxl->guest_primary.stride;
+    src += rect->left * qxl->guest_primary.bytes_pp;
+    dst += rect->left * qxl->guest_primary.bytes_pp;
+    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
+
+    for (i = rect->top; i < rect->bottom; i++) {
+        memcpy(dst, src, len);
+        dst += qxl->guest_primary.stride;
+        src -= qxl->guest_primary.stride;
+    }
+}
+
+void qxl_render_resize(PCIQXLDevice *qxl)
+{
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    qxl->guest_primary.stride = sc->stride;
+    qxl->guest_primary.resized++;
+    switch (sc->format) {
+    case SPICE_SURFACE_FMT_16_555:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 15;
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 16;
+        break;
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
+                qxl->guest_primary.surface.format);
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    }
+}
+
+void qxl_render_update(PCIQXLDevice *qxl)
+{
+    VGACommonState *vga = &qxl->vga;
+    QXLRect dirty[32], update;
+    void *ptr;
+    int i;
+
+    if (qxl->guest_primary.resized) {
+        qxl->guest_primary.resized = 0;
+
+        if (qxl->guest_primary.flipped) {
+            qemu_free(qxl->guest_primary.flipped);
+            qxl->guest_primary.flipped = NULL;
+        }
+        qemu_free_displaysurface(vga->ds);
+
+        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
+        if (qxl->guest_primary.stride < 0) {
+            /* spice surface is upside down -> need extra buffer to flip */
+            qxl->guest_primary.stride = -qxl->guest_primary.stride;
+            qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
+                                                     qxl->guest_primary.stride);
+            ptr = qxl->guest_primary.flipped;
+        } else {
+            ptr = qxl->guest_primary.data;
+        }
+        dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
+               __FUNCTION__,
+               qxl->guest_primary.surface.width,
+               qxl->guest_primary.surface.height,
+               qxl->guest_primary.stride,
+               qxl->guest_primary.bytes_pp,
+               qxl->guest_primary.bits_pp,
+               qxl->guest_primary.flipped ? "yes" : "no");
+        vga->ds->surface =
+            qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
+                                            qxl->guest_primary.surface.height,
+                                            qxl->guest_primary.bits_pp,
+                                            qxl->guest_primary.stride,
+                                            ptr);
+        dpy_resize(vga->ds);
+    }
+
+    if (!qxl->guest_primary.commands) {
+        return;
+    }
+    qxl->guest_primary.commands = 0;
+
+    update.left   = 0;
+    update.right  = qxl->guest_primary.surface.width;
+    update.top    = 0;
+    update.bottom = qxl->guest_primary.surface.height;
+
+    memset(dirty, 0, sizeof(dirty));
+    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
+                                 dirty, ARRAY_SIZE(dirty), 1);
+
+    for (i = 0; i < ARRAY_SIZE(dirty); i++) {
+        if (qemu_spice_rect_is_empty(dirty+i)) {
+            break;
+        }
+        if (qxl->guest_primary.flipped) {
+            qxl_flip(qxl, dirty+i);
+        }
+        dpy_update(vga->ds,
+                   dirty[i].left, dirty[i].top,
+                   dirty[i].right - dirty[i].left,
+                   dirty[i].bottom - dirty[i].top);
+    }
+}
+
+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
+{
+    QEMUCursor *c;
+    uint8_t *image, *mask;
+    int size;
+
+    c = cursor_alloc(cursor->header.width, cursor->header.height);
+    c->hot_x = cursor->header.hot_spot_x;
+    c->hot_y = cursor->header.hot_spot_y;
+    switch (cursor->header.type) {
+    case SPICE_CURSOR_TYPE_ALPHA:
+        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
+        memcpy(c->data, cursor->chunk.data, size);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/alpha");
+        }
+        break;
+    case SPICE_CURSOR_TYPE_MONO:
+        mask  = cursor->chunk.data;
+        image = mask + cursor_get_mono_bpl(c) * c->width;
+        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/mono");
+        }
+        break;
+    default:
+        fprintf(stderr, "%s: not implemented: type %d\n",
+                __FUNCTION__, cursor->header.type);
+        goto fail;
+    }
+    return c;
+
+fail:
+    cursor_put(c);
+    return NULL;
+}
+
+
+/* called from spice server thread context only */
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+{
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    QXLCursor *cursor;
+    QEMUCursor *c;
+
+    if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
+        return;
+    }
+
+    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
+        fprintf(stderr, "%s", __FUNCTION__);
+        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
+        fprintf(stderr, "\n");
+    }
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
+        if (cursor->chunk.data_size != cursor->data_size) {
+            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
+            return;
+        }
+        c = qxl_cursor(qxl, cursor);
+        if (c == NULL) {
+            c = cursor_builtin_left_ptr();
+        }
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.cursor) {
+            cursor_put(qxl->ssd.cursor);
+        }
+        qxl->ssd.cursor = c;
+        qxl->ssd.mouse_x = cmd->u.set.position.x;
+        qxl->ssd.mouse_y = cmd->u.set.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    case QXL_CURSOR_MOVE:
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qxl->ssd.mouse_x = cmd->u.position.x;
+        qxl->ssd.mouse_y = cmd->u.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    }
+}
diff --git a/qemu-0.15.x/hw/qxl.c b/qemu-0.15.x/hw/qxl.c
new file mode 100644
index 0000000..a6fb7f0
--- /dev/null
+++ b/qemu-0.15.x/hw/qxl.c
@@ -0,0 +1,1551 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+#include "sysemu.h"
+
+#include "qxl.h"
+
+#undef SPICE_RING_PROD_ITEM
+#define SPICE_RING_PROD_ITEM(r, ret) {                                  \
+        typeof(r) start = r;                                            \
+        typeof(r) end = r + 1;                                          \
+        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
+        typeof(&(r)->items[prod]) m_item = &(r)->items[prod];           \
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+            abort();                                                    \
+        }                                                               \
+        ret = &m_item->el;                                              \
+    }
+
+#undef SPICE_RING_CONS_ITEM
+#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
+        typeof(r) start = r;                                            \
+        typeof(r) end = r + 1;                                          \
+        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
+        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+            abort();                                                    \
+        }                                                               \
+        ret = &m_item->el;                                              \
+    }
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
+
+#define QXL_MODE(_x, _y, _b, _o)                  \
+    {   .x_res = _x,                              \
+        .y_res = _y,                              \
+        .bits  = _b,                              \
+        .stride = (_x) * (_b) / 8,                \
+        .x_mili = PIXEL_SIZE * (_x),              \
+        .y_mili = PIXEL_SIZE * (_y),              \
+        .orientation = _o,                        \
+    }
+
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
+    QXL_MODE(x_res, y_res, 16, orientation),      \
+    QXL_MODE(x_res, y_res, 32, orientation)
+
+#define QXL_MODE_EX(x_res, y_res)                 \
+    QXL_MODE_16_32(x_res, y_res, 0),              \
+    QXL_MODE_16_32(y_res, x_res, 1),              \
+    QXL_MODE_16_32(x_res, y_res, 2),              \
+    QXL_MODE_16_32(y_res, x_res, 3)
+
+static QXLMode qxl_modes[] = {
+    QXL_MODE_EX(640, 480),
+    QXL_MODE_EX(800, 480),
+    QXL_MODE_EX(800, 600),
+    QXL_MODE_EX(832, 624),
+    QXL_MODE_EX(960, 640),
+    QXL_MODE_EX(1024, 600),
+    QXL_MODE_EX(1024, 768),
+    QXL_MODE_EX(1152, 864),
+    QXL_MODE_EX(1152, 870),
+    QXL_MODE_EX(1280, 720),
+    QXL_MODE_EX(1280, 760),
+    QXL_MODE_EX(1280, 768),
+    QXL_MODE_EX(1280, 800),
+    QXL_MODE_EX(1280, 960),
+    QXL_MODE_EX(1280, 1024),
+    QXL_MODE_EX(1360, 768),
+    QXL_MODE_EX(1366, 768),
+    QXL_MODE_EX(1400, 1050),
+    QXL_MODE_EX(1440, 900),
+    QXL_MODE_EX(1600, 900),
+    QXL_MODE_EX(1600, 1200),
+    QXL_MODE_EX(1680, 1050),
+    QXL_MODE_EX(1920, 1080),
+#if VGA_RAM_SIZE >= (16 * 1024 * 1024)
+    /* these modes need more than 8 MB video memory */
+    QXL_MODE_EX(1920, 1200),
+    QXL_MODE_EX(1920, 1440),
+    QXL_MODE_EX(2048, 1536),
+    QXL_MODE_EX(2560, 1440),
+    QXL_MODE_EX(2560, 1600),
+#endif
+#if VGA_RAM_SIZE >= (32 * 1024 * 1024)
+    /* these modes need more than 16 MB video memory */
+    QXL_MODE_EX(2560, 2048),
+    QXL_MODE_EX(2800, 2100),
+    QXL_MODE_EX(3200, 2400),
+#endif
+};
+
+static PCIQXLDevice *qxl0;
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+static void qxl_destroy_primary(PCIQXLDevice *d);
+static void qxl_reset_memslots(PCIQXLDevice *d);
+static void qxl_reset_surfaces(PCIQXLDevice *d);
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+
+static inline uint32_t msb_mask(uint32_t val)
+{
+    uint32_t mask;
+
+    do {
+        mask = ~(val - 1) & val;
+        val &= ~mask;
+    } while (mask < val);
+
+    return mask;
+}
+
+static ram_addr_t qxl_rom_size(void)
+{
+    uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes);
+    rom_size = MAX(rom_size, TARGET_PAGE_SIZE);
+    rom_size = msb_mask(rom_size * 2 - 1);
+    return rom_size;
+}
+
+static void init_qxl_rom(PCIQXLDevice *d)
+{
+    QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
+    QXLModes *modes = (QXLModes *)(rom + 1);
+    uint32_t ram_header_size;
+    uint32_t surface0_area_size;
+    uint32_t num_pages;
+    uint32_t fb, maxfb = 0;
+    int i;
+
+    memset(rom, 0, d->rom_size);
+
+    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
+    rom->id            = cpu_to_le32(d->id);
+    rom->log_level     = cpu_to_le32(d->guestdebug);
+    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
+
+    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
+    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
+    rom->slots_start   = 1;
+    rom->slots_end     = NUM_MEMSLOTS - 1;
+    rom->n_surfaces    = cpu_to_le32(NUM_SURFACES);
+
+    modes->n_modes     = cpu_to_le32(ARRAY_SIZE(qxl_modes));
+    for (i = 0; i < modes->n_modes; i++) {
+        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
+        if (maxfb < fb) {
+            maxfb = fb;
+        }
+        modes->modes[i].id          = cpu_to_le32(i);
+        modes->modes[i].x_res       = cpu_to_le32(qxl_modes[i].x_res);
+        modes->modes[i].y_res       = cpu_to_le32(qxl_modes[i].y_res);
+        modes->modes[i].bits        = cpu_to_le32(qxl_modes[i].bits);
+        modes->modes[i].stride      = cpu_to_le32(qxl_modes[i].stride);
+        modes->modes[i].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
+        modes->modes[i].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
+        modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation);
+    }
+    if (maxfb < VGA_RAM_SIZE && d->id == 0)
+        maxfb = VGA_RAM_SIZE;
+
+    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
+    surface0_area_size = ALIGN(maxfb, 4096);
+    num_pages          = d->vga.vram_size;
+    num_pages         -= ram_header_size;
+    num_pages         -= surface0_area_size;
+    num_pages          = num_pages / TARGET_PAGE_SIZE;
+
+    rom->draw_area_offset   = cpu_to_le32(0);
+    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
+    rom->pages_offset       = cpu_to_le32(surface0_area_size);
+    rom->num_pages          = cpu_to_le32(num_pages);
+    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
+
+    d->shadow_rom = *rom;
+    d->rom        = rom;
+    d->modes      = modes;
+}
+
+static void init_qxl_ram(PCIQXLDevice *d)
+{
+    uint8_t *buf;
+    uint64_t *item;
+
+    buf = d->vga.vram_ptr;
+    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
+    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
+    d->ram->int_pending = cpu_to_le32(0);
+    d->ram->int_mask    = cpu_to_le32(0);
+    SPICE_RING_INIT(&d->ram->cmd_ring);
+    SPICE_RING_INIT(&d->ram->cursor_ring);
+    SPICE_RING_INIT(&d->ram->release_ring);
+    SPICE_RING_PROD_ITEM(&d->ram->release_ring, item);
+    *item = 0;
+    qxl_ring_set_dirty(d);
+}
+
+/* can be called from spice server thread context */
+static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
+{
+    while (addr < end) {
+        cpu_physical_memory_set_dirty(addr);
+        addr += TARGET_PAGE_SIZE;
+    }
+}
+
+static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
+{
+    ram_addr_t addr = qxl->rom_offset;
+    qxl_set_dirty(addr, addr + qxl->rom_size);
+}
+
+/* called from spice server thread context only */
+static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
+{
+    ram_addr_t addr = qxl->vga.vram_offset;
+    void *base = qxl->vga.vram_ptr;
+    intptr_t offset;
+
+    offset = ptr - base;
+    offset &= ~(TARGET_PAGE_SIZE-1);
+    assert(offset < qxl->vga.vram_size);
+    qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE);
+}
+
+/* can be called from spice server thread context */
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
+{
+    ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset;
+    ram_addr_t end  = qxl->vga.vram_offset + qxl->vga.vram_size;
+    qxl_set_dirty(addr, end);
+}
+
+/*
+ * keep track of some command state, for savevm/loadvm.
+ * called from spice server thread context only
+ */
+static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+{
+    switch (le32_to_cpu(ext->cmd.type)) {
+    case QXL_CMD_SURFACE:
+    {
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+        uint32_t id = le32_to_cpu(cmd->surface_id);
+        PANIC_ON(id >= NUM_SURFACES);
+        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+            qxl->guest_surfaces.count++;
+            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
+                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+            qxl->guest_surfaces.cmds[id] = 0;
+            qxl->guest_surfaces.count--;
+        }
+        break;
+    }
+    case QXL_CMD_CURSOR:
+    {
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+        if (cmd->type == QXL_CURSOR_SET) {
+            qxl->guest_cursor = ext->cmd.data;
+        }
+        break;
+    }
+    }
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s:\n", __FUNCTION__);
+    qxl->ssd.worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level);
+    qxl->shadow_rom.compression_level = cpu_to_le32(level);
+    qxl->rom->compression_level = cpu_to_le32(level);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
+    qxl->rom->mm_clock = cpu_to_le32(mm_time);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s:\n", __FUNCTION__);
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
+    info->n_surfaces = NUM_SURFACES;
+}
+
+static const char *qxl_mode_to_string(int mode)
+{
+    switch (mode) {
+    case QXL_MODE_COMPAT:
+        return "compat";
+    case QXL_MODE_NATIVE:
+        return "native";
+    case QXL_MODE_UNDEFINED:
+        return "undefined";
+    case QXL_MODE_VGA:
+        return "vga";
+    }
+    return "INVALID";
+}
+
+/* called from spice server thread context only */
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    SimpleSpiceUpdate *update;
+    QXLCommandRing *ring;
+    QXLCommand *cmd;
+    int notify, ret;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
+        ret = false;
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.update != NULL) {
+            update = qxl->ssd.update;
+            qxl->ssd.update = NULL;
+            *ext = update->ext;
+            ret = true;
+        }
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        if (ret) {
+            dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
+            qxl_log_command(qxl, "vga", ext);
+        }
+        return ret;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
+        ring = &qxl->ram->cmd_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
+        SPICE_RING_CONS_ITEM(ring, cmd);
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "cmd", ext);
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context only */
+static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
+{
+    QXLReleaseRing *ring = &d->ram->release_ring;
+    uint64_t *item;
+    int notify;
+
+#define QXL_FREE_BUNCH_SIZE 32
+
+    if (ring->prod - ring->cons + 1 == ring->num_items) {
+        /* ring full -- can't push */
+        return;
+    }
+    if (!flush && d->oom_running) {
+        /* collect everything from oom handler before pushing */
+        return;
+    }
+    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
+        /* collect a bit more before pushing */
+        return;
+    }
+
+    SPICE_RING_PUSH(ring, notify);
+    dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n",
+           d->num_free_res, notify ? "yes" : "no",
+           ring->prod - ring->cons, ring->num_items,
+           ring->prod, ring->cons);
+    if (notify) {
+        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+    }
+    SPICE_RING_PROD_ITEM(ring, item);
+    *item = 0;
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    qxl_ring_set_dirty(d);
+}
+
+/* called from spice server thread context only */
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLReleaseRing *ring;
+    uint64_t *item, id;
+
+    if (ext.group_id == MEMSLOT_GROUP_HOST) {
+        /* host group -> vga mode update request */
+        qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id);
+        return;
+    }
+
+    /*
+     * ext->info points into guest-visible memory
+     * pci bar 0, $command.release_info
+     */
+    ring = &qxl->ram->release_ring;
+    SPICE_RING_PROD_ITEM(ring, item);
+    if (*item == 0) {
+        /* stick head into the ring */
+        id = ext.info->id;
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+        *item = id;
+        qxl_ring_set_dirty(qxl);
+    } else {
+        /* append item to the list */
+        qxl->last_release->next = ext.info->id;
+        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+    }
+    qxl->last_release = ext.info;
+    qxl->num_free_res++;
+    dprint(qxl, 3, "%4d\r", qxl->num_free_res);
+    qxl_push_free_res(qxl, 0);
+}
+
+/* called from spice server thread context only */
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCursorRing *ring;
+    QXLCommand *cmd;
+    int notify;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cursor_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(ring, cmd);
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "csr", ext);
+        if (qxl->id == 0) {
+            qxl_render_cursor(qxl, ext);
+        }
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context */
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+}
+
+/* called from spice server thread context only */
+static int interface_flush_resources(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int ret;
+
+    dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res);
+    ret = qxl->num_free_res;
+    if (ret) {
+        qxl_push_free_res(qxl, 1);
+    }
+    return ret;
+}
+
+static const QXLInterface qxl_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qxl gpu",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+};
+
+static void qxl_enter_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_VGA) {
+        return;
+    }
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    qemu_spice_create_host_primary(&d->ssd);
+    d->mode = QXL_MODE_VGA;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode != QXL_MODE_VGA) {
+        return;
+    }
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    qxl_destroy_primary(d);
+}
+
+static void qxl_set_irq(PCIQXLDevice *d)
+{
+    uint32_t pending = le32_to_cpu(d->ram->int_pending);
+    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
+    int level = !!(pending & mask);
+    qemu_set_irq(d->pci.irq[0], level);
+    qxl_ring_set_dirty(d);
+}
+
+static void qxl_write_config(PCIDevice *d, uint32_t address,
+                             uint32_t val, int len)
+{
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d);
+    VGACommonState *vga = &qxl->vga;
+
+    vga_dirty_log_stop(vga);
+    pci_default_write_config(d, address, val, len);
+    if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) {
+        vga->map_addr = 0;
+    }
+    vga_dirty_log_start(vga);
+}
+
+static void qxl_check_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->ram;
+
+    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+}
+
+static void qxl_reset_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->ram;
+    QXLRom *rom = d->rom;
+
+    assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+    d->shadow_rom.update_id = cpu_to_le32(0);
+    *rom = d->shadow_rom;
+    qxl_rom_set_dirty(d);
+    init_qxl_ram(d);
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_soft_reset(PCIQXLDevice *d)
+{
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    qxl_check_state(d);
+
+    if (d->id == 0) {
+        qxl_enter_vga_mode(d);
+    } else {
+        d->mode = QXL_MODE_UNDEFINED;
+    }
+}
+
+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+{
+    dprint(d, 1, "%s: start%s\n", __FUNCTION__,
+           loadvm ? " (loadvm)" : "");
+
+    d->ssd.worker->reset_cursor(d->ssd.worker);
+    d->ssd.worker->reset_image_cache(d->ssd.worker);
+    qxl_reset_surfaces(d);
+    qxl_reset_memslots(d);
+
+    /* pre loadvm reset must not touch QXLRam.  This lives in
+     * device memory, is migrated together with RAM and thus
+     * already loaded at this point */
+    if (!loadvm) {
+        qxl_reset_state(d);
+    }
+    qemu_spice_create_host_memslot(&d->ssd);
+    qxl_soft_reset(d);
+
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+}
+
+static void qxl_reset_handler(DeviceState *dev)
+{
+    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
+    qxl_hard_reset(d, 0);
+}
+
+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *vga = opaque;
+    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
+
+    if (qxl->mode != QXL_MODE_VGA) {
+        dprint(qxl, 1, "%s\n", __FUNCTION__);
+        qxl_destroy_primary(qxl);
+        qxl_soft_reset(qxl);
+    }
+    vga_ioport_write(opaque, addr, val);
+}
+
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+{
+    static const int regions[] = {
+        QXL_RAM_RANGE_INDEX,
+        QXL_VRAM_RANGE_INDEX,
+    };
+    uint64_t guest_start;
+    uint64_t guest_end;
+    int pci_region;
+    pcibus_t pci_start;
+    pcibus_t pci_end;
+    intptr_t virt_start;
+    QXLDevMemSlot memslot;
+    int i;
+
+    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
+    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
+
+    dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+           __FUNCTION__, slot_id,
+           guest_start, guest_end);
+
+    PANIC_ON(slot_id >= NUM_MEMSLOTS);
+    PANIC_ON(guest_start > guest_end);
+
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
+        pci_region = regions[i];
+        pci_start = d->pci.io_regions[pci_region].addr;
+        pci_end = pci_start + d->pci.io_regions[pci_region].size;
+        /* mapped? */
+        if (pci_start == -1) {
+            continue;
+        }
+        /* start address in range ? */
+        if (guest_start < pci_start || guest_start > pci_end) {
+            continue;
+        }
+        /* end address in range ? */
+        if (guest_end > pci_end) {
+            continue;
+        }
+        /* passed */
+        break;
+    }
+    PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */
+
+    switch (pci_region) {
+    case QXL_RAM_RANGE_INDEX:
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
+        break;
+    case QXL_VRAM_RANGE_INDEX:
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
+        break;
+    default:
+        /* should not happen */
+        abort();
+    }
+
+    memslot.slot_id = slot_id;
+    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
+    memslot.virt_start = virt_start + (guest_start - pci_start);
+    memslot.virt_end   = virt_start + (guest_end   - pci_start);
+    memslot.addr_delta = memslot.virt_start - delta;
+    memslot.generation = d->rom->slot_generation = 0;
+    qxl_rom_set_dirty(d);
+
+    dprint(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+           __FUNCTION__, memslot.slot_id,
+           memslot.virt_start, memslot.virt_end);
+
+    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
+    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
+    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
+    d->guest_slots[slot_id].delta = delta;
+    d->guest_slots[slot_id].active = 1;
+}
+
+static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
+{
+    dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
+    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
+    d->guest_slots[slot_id].active = 0;
+}
+
+static void qxl_reset_memslots(PCIQXLDevice *d)
+{
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    d->ssd.worker->reset_memslots(d->ssd.worker);
+    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+}
+
+static void qxl_reset_surfaces(PCIQXLDevice *d)
+{
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    d->mode = QXL_MODE_UNDEFINED;
+    d->ssd.worker->destroy_surfaces(d->ssd.worker);
+    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+}
+
+/* called from spice server thread context only */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
+{
+    uint64_t phys   = le64_to_cpu(pqxl);
+    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
+    uint64_t offset = phys & 0xffffffffffff;
+
+    switch (group_id) {
+    case MEMSLOT_GROUP_HOST:
+        return (void*)offset;
+    case MEMSLOT_GROUP_GUEST:
+        PANIC_ON(slot > NUM_MEMSLOTS);
+        PANIC_ON(!qxl->guest_slots[slot].active);
+        PANIC_ON(offset < qxl->guest_slots[slot].delta);
+        offset -= qxl->guest_slots[slot].delta;
+        PANIC_ON(offset > qxl->guest_slots[slot].size)
+        return qxl->guest_slots[slot].ptr + offset;
+    default:
+        PANIC_ON(1);
+    }
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+{
+    QXLDevSurfaceCreate surface;
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    assert(qxl->mode != QXL_MODE_NATIVE);
+    qxl_exit_vga_mode(qxl);
+
+    dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__,
+           le32_to_cpu(sc->width), le32_to_cpu(sc->height));
+
+    surface.format     = le32_to_cpu(sc->format);
+    surface.height     = le32_to_cpu(sc->height);
+    surface.mem        = le64_to_cpu(sc->mem);
+    surface.position   = le32_to_cpu(sc->position);
+    surface.stride     = le32_to_cpu(sc->stride);
+    surface.width      = le32_to_cpu(sc->width);
+    surface.type       = le32_to_cpu(sc->type);
+    surface.flags      = le32_to_cpu(sc->flags);
+
+    surface.mouse_mode = true;
+    surface.group_id   = MEMSLOT_GROUP_GUEST;
+    if (loadvm) {
+        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
+
+    qxl->mode = QXL_MODE_NATIVE;
+    qxl->cmdflags = 0;
+    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
+
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_destroy_primary(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_UNDEFINED) {
+        return;
+    }
+
+    dprint(d, 1, "%s\n", __FUNCTION__);
+
+    d->mode = QXL_MODE_UNDEFINED;
+    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
+}
+
+static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+{
+    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
+    QXLMode *mode = d->modes->modes + modenr;
+    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    QXLMemSlot slot = {
+        .mem_start = start,
+        .mem_end = end
+    };
+    QXLSurfaceCreate surface = {
+        .width      = mode->x_res,
+        .height     = mode->y_res,
+        .stride     = -mode->x_res * 4,
+        .format     = SPICE_SURFACE_FMT_32_xRGB,
+        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
+        .mouse_mode = true,
+        .mem        = devmem + d->shadow_rom.draw_area_offset,
+    };
+
+    dprint(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__,
+           modenr, mode->x_res, mode->y_res, mode->bits, devmem);
+    if (!loadvm) {
+        qxl_hard_reset(d, 0);
+    }
+
+    d->guest_slots[0].slot = slot;
+    qxl_add_memslot(d, 0, devmem);
+
+    d->guest_primary.surface = surface;
+    qxl_create_guest_primary(d, 0);
+
+    d->mode = QXL_MODE_COMPAT;
+    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
+#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */
+    if (mode->bits == 16) {
+        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
+    }
+#endif
+    d->shadow_rom.mode = cpu_to_le32(modenr);
+    d->rom->mode = cpu_to_le32(modenr);
+    qxl_rom_set_dirty(d);
+}
+
+static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIQXLDevice *d = opaque;
+    uint32_t io_port = addr - d->io_base;
+
+    switch (io_port) {
+    case QXL_IO_RESET:
+    case QXL_IO_SET_MODE:
+    case QXL_IO_MEMSLOT_ADD:
+    case QXL_IO_MEMSLOT_DEL:
+    case QXL_IO_CREATE_PRIMARY:
+    case QXL_IO_UPDATE_IRQ:
+    case QXL_IO_LOG:
+        break;
+    default:
+        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
+            break;
+        dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+        return;
+    }
+
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA:
+    {
+        QXLRect update = d->ram->update_area;
+        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
+                                   &update, NULL, 0, 0);
+        break;
+    }
+    case QXL_IO_NOTIFY_CMD:
+        d->ssd.worker->wakeup(d->ssd.worker);
+        break;
+    case QXL_IO_NOTIFY_CURSOR:
+        d->ssd.worker->wakeup(d->ssd.worker);
+        break;
+    case QXL_IO_UPDATE_IRQ:
+        qxl_set_irq(d);
+        break;
+    case QXL_IO_NOTIFY_OOM:
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        pthread_yield();
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        d->oom_running = 1;
+        d->ssd.worker->oom(d->ssd.worker);
+        d->oom_running = 0;
+        break;
+    case QXL_IO_SET_MODE:
+        dprint(d, 1, "QXL_SET_MODE %d\n", val);
+        qxl_set_mode(d, val, 0);
+        break;
+    case QXL_IO_LOG:
+        if (d->guestdebug) {
+            fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id,
+                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
+        }
+        break;
+    case QXL_IO_RESET:
+        dprint(d, 1, "QXL_IO_RESET\n");
+        qxl_hard_reset(d, 0);
+        break;
+    case QXL_IO_MEMSLOT_ADD:
+        PANIC_ON(val >= NUM_MEMSLOTS);
+        PANIC_ON(d->guest_slots[val].active);
+        d->guest_slots[val].slot = d->ram->mem_slot;
+        qxl_add_memslot(d, val, 0);
+        break;
+    case QXL_IO_MEMSLOT_DEL:
+        qxl_del_memslot(d, val);
+        break;
+    case QXL_IO_CREATE_PRIMARY:
+        PANIC_ON(val != 0);
+        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
+        d->guest_primary.surface = d->ram->create_surface;
+        qxl_create_guest_primary(d, 0);
+        break;
+    case QXL_IO_DESTROY_PRIMARY:
+        PANIC_ON(val != 0);
+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
+        qxl_destroy_primary(d);
+        break;
+    case QXL_IO_DESTROY_SURFACE_WAIT:
+        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES:
+        d->ssd.worker->destroy_surfaces(d->ssd.worker);
+        break;
+    default:
+        fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+        abort();
+    }
+}
+
+static uint32_t ioport_read(void *opaque, uint32_t addr)
+{
+    PCIQXLDevice *d = opaque;
+
+    dprint(d, 1, "%s: unexpected\n", __FUNCTION__);
+    return 0xff;
+}
+
+static void qxl_map(PCIDevice *pci, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    static const char *names[] = {
+        [ QXL_IO_RANGE_INDEX ]   = "ioports",
+        [ QXL_RAM_RANGE_INDEX ]  = "devram",
+        [ QXL_ROM_RANGE_INDEX ]  = "rom",
+        [ QXL_VRAM_RANGE_INDEX ] = "vram",
+    };
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci);
+
+    dprint(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__,
+            region_num, names[region_num], addr, size);
+
+    switch (region_num) {
+    case QXL_IO_RANGE_INDEX:
+        register_ioport_write(addr, size, 1, ioport_write, pci);
+        register_ioport_read(addr, size, 1, ioport_read, pci);
+        qxl->io_base = addr;
+        break;
+    case QXL_RAM_RANGE_INDEX:
+        cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM);
+        qxl->vga.map_addr = addr;
+        qxl->vga.map_end = addr + size;
+        if (qxl->id == 0) {
+            vga_dirty_log_start(&qxl->vga);
+        }
+        break;
+    case QXL_ROM_RANGE_INDEX:
+        cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM);
+        break;
+    case QXL_VRAM_RANGE_INDEX:
+        cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM);
+        break;
+    }
+}
+
+static void pipe_read(void *opaque)
+{
+    PCIQXLDevice *d = opaque;
+    char dummy;
+    int len;
+
+    do {
+        len = read(d->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qxl_set_irq(d);
+}
+
+/* called from spice server thread context only */
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+{
+    uint32_t old_pending;
+    uint32_t le_events = cpu_to_le32(events);
+
+    assert(d->ssd.running);
+    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
+    if ((old_pending & le_events) == le_events) {
+        return;
+    }
+    if (pthread_self() == d->main) {
+        qxl_set_irq(d);
+    } else {
+        if (write(d->pipe[1], d, 1) != 1) {
+            dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
+        }
+    }
+}
+
+static void init_pipe_signaling(PCIQXLDevice *d)
+{
+   if (pipe(d->pipe) < 0) {
+       dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
+       return;
+   }
+#ifdef CONFIG_IOTHREAD
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
+#else
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
+#endif
+   fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
+   fcntl(d->pipe[0], F_SETOWN, getpid());
+
+   d->main = pthread_self();
+   qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
+}
+
+/* graphics console */
+
+static void qxl_hw_update(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        vga->update(vga);
+        break;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_invalidate(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    vga->invalidate(vga);
+}
+
+static void qxl_hw_screen_dump(void *opaque, const char *filename)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        ppm_save(filename, qxl->ssd.ds->surface);
+        break;
+    case QXL_MODE_VGA:
+        vga->screen_dump(vga, filename);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        vga->text_update(vga, chardata);
+        return;
+    }
+}
+
+static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    PCIQXLDevice *qxl = opaque;
+    qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
+
+    if (!running && qxl->mode == QXL_MODE_NATIVE) {
+        /* dirty all vram (which holds surfaces) and devram (primary surface)
+         * to make sure they are saved */
+        /* FIXME #1: should go out during "live" stage */
+        /* FIXME #2: we only need to save the areas which are actually used */
+        ram_addr_t vram_addr = qxl->vram_offset;
+        ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
+        qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
+        qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
+    }
+}
+
+/* display change listener */
+
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_update(&qxl0->ssd, x, y, w, h);
+    }
+}
+
+static void display_resize(struct DisplayState *ds)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_resize(&qxl0->ssd);
+    }
+}
+
+static void display_refresh(struct DisplayState *ds)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_refresh(&qxl0->ssd);
+    }
+}
+
+static DisplayChangeListener display_listener = {
+    .dpy_update  = display_update,
+    .dpy_resize  = display_resize,
+    .dpy_refresh = display_refresh,
+};
+
+static int qxl_init_common(PCIQXLDevice *qxl)
+{
+    uint8_t* config = qxl->pci.config;
+    uint32_t pci_device_rev;
+    uint32_t io_size;
+
+    qxl->mode = QXL_MODE_UNDEFINED;
+    qxl->generation = 1;
+    qxl->num_memslots = NUM_MEMSLOTS;
+    qxl->num_surfaces = NUM_SURFACES;
+
+    switch (qxl->revision) {
+    case 1: /* spice 0.4 -- qxl-1 */
+        pci_device_rev = QXL_REVISION_STABLE_V04;
+        break;
+    case 2: /* spice 0.6 -- qxl-2 */
+    default:
+        pci_device_rev = QXL_REVISION_STABLE_V06;
+        break;
+    }
+
+    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
+    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+
+    qxl->rom_size = qxl_rom_size();
+    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
+    init_qxl_rom(qxl);
+    init_qxl_ram(qxl);
+
+    if (qxl->vram_size < 16 * 1024 * 1024) {
+        qxl->vram_size = 16 * 1024 * 1024;
+    }
+    if (qxl->revision == 1) {
+        qxl->vram_size = 4096;
+    }
+    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
+    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
+
+    io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
+    if (qxl->revision == 1) {
+        io_size = 8;
+    }
+
+    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
+                     io_size, PCI_BASE_ADDRESS_SPACE_IO, qxl_map);
+
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                     qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     qxl_map);
+
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                     qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     qxl_map);
+
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
+
+    qxl->ssd.qxl.base.sif = &qxl_interface.base;
+    qxl->ssd.qxl.id = qxl->id;
+    qemu_spice_add_interface(&qxl->ssd.qxl.base);
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+
+    init_pipe_signaling(qxl);
+    qxl_reset_state(qxl);
+
+    return 0;
+}
+
+static int qxl_init_primary(PCIDevice *dev)
+{
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    VGACommonState *vga = &qxl->vga;
+    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+
+    qxl->id = 0;
+
+    if (ram_size < 32 * 1024 * 1024) {
+        ram_size = 32 * 1024 * 1024;
+    }
+    vga_common_init(vga, ram_size);
+    vga_init(vga);
+    register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3b4,  2, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3d4,  2, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3ba,  1, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3da,  1, 1, qxl_vga_ioport_write, vga);
+
+    vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
+                                   qxl_hw_screen_dump, qxl_hw_text_update, qxl);
+    qxl->ssd.ds = vga->ds;
+    qemu_mutex_init(&qxl->ssd.lock);
+    qxl->ssd.mouse_x = -1;
+    qxl->ssd.mouse_y = -1;
+    qxl->ssd.bufsize = (16 * 1024 * 1024);
+    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
+
+    qxl0 = qxl;
+    register_displaychangelistener(vga->ds, &display_listener);
+
+    return qxl_init_common(qxl);
+}
+
+static int qxl_init_secondary(PCIDevice *dev)
+{
+    static int device_id = 1;
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+
+    qxl->id = device_id++;
+
+    if (ram_size < 16 * 1024 * 1024) {
+        ram_size = 16 * 1024 * 1024;
+    }
+    qxl->vga.vram_size = ram_size;
+    qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
+                                          qxl->vga.vram_size);
+    qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
+
+    return qxl_init_common(qxl);
+}
+
+static void qxl_pre_save(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    if (d->last_release == NULL) {
+        d->last_release_offset = 0;
+    } else {
+        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
+    }
+    assert(d->last_release_offset < d->vga.vram_size);
+}
+
+static int qxl_pre_load(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+
+    dprint(d, 1, "%s: start\n", __FUNCTION__);
+    qxl_hard_reset(d, 1);
+    qxl_exit_vga_mode(d);
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+    return 0;
+}
+
+static int qxl_post_load(void *opaque, int version)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+    QXLCommandExt *cmds;
+    int in, out, i, newmode;
+
+    dprint(d, 1, "%s: start\n", __FUNCTION__);
+
+    assert(d->last_release_offset < d->vga.vram_size);
+    if (d->last_release_offset == 0) {
+        d->last_release = NULL;
+    } else {
+        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
+    }
+
+    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
+
+    dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__,
+        qxl_mode_to_string(d->mode));
+    newmode = d->mode;
+    d->mode = QXL_MODE_UNDEFINED;
+    switch (newmode) {
+    case QXL_MODE_UNDEFINED:
+        break;
+    case QXL_MODE_VGA:
+        qxl_enter_vga_mode(d);
+        break;
+    case QXL_MODE_NATIVE:
+        for (i = 0; i < NUM_MEMSLOTS; i++) {
+            if (!d->guest_slots[i].active) {
+                continue;
+            }
+            qxl_add_memslot(d, i, 0);
+        }
+        qxl_create_guest_primary(d, 1);
+
+        /* replay surface-create and cursor-set commands */
+        cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
+        for (in = 0, out = 0; in < NUM_SURFACES; in++) {
+            if (d->guest_surfaces.cmds[in] == 0) {
+                continue;
+            }
+            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
+            cmds[out].cmd.type = QXL_CMD_SURFACE;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        cmds[out].cmd.data = d->guest_cursor;
+        cmds[out].cmd.type = QXL_CMD_CURSOR;
+        cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+        out++;
+        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
+        qemu_free(cmds);
+
+        break;
+    case QXL_MODE_COMPAT:
+        qxl_set_mode(d, d->shadow_rom.mode, 1);
+        break;
+    }
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+
+    return 0;
+}
+
+#define QXL_SAVE_VERSION 21
+
+static VMStateDescription qxl_memslot = {
+    .name               = "qxl-memslot",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
+        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
+        VMSTATE_UINT32(active,         struct guest_slots),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_surface = {
+    .name               = "qxl-surface",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(width,      QXLSurfaceCreate),
+        VMSTATE_UINT32(height,     QXLSurfaceCreate),
+        VMSTATE_INT32(stride,      QXLSurfaceCreate),
+        VMSTATE_UINT32(format,     QXLSurfaceCreate),
+        VMSTATE_UINT32(position,   QXLSurfaceCreate),
+        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
+        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
+        VMSTATE_UINT32(type,       QXLSurfaceCreate),
+        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_vmstate = {
+    .name               = "qxl",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .pre_save           = qxl_pre_save,
+    .pre_load           = qxl_pre_load,
+    .post_load          = qxl_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
+        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
+        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
+        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
+        VMSTATE_UINT32(mode, PCIQXLDevice),
+        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+                             qxl_memslot, struct guest_slots),
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+                       qxl_surface, QXLSurfaceCreate),
+        VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
+        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
+                      vmstate_info_uint64, uint64_t),
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static PCIDeviceInfo qxl_info_primary = {
+    .qdev.name    = "qxl-vga",
+    .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
+    .qdev.size    = sizeof(PCIQXLDevice),
+    .qdev.reset   = qxl_reset_handler,
+    .qdev.vmsd    = &qxl_vmstate,
+    .no_hotplug   = 1,
+    .init         = qxl_init_primary,
+    .config_write = qxl_write_config,
+    .romfile      = "vgabios-qxl.bin",
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .device_id    = QXL_DEVICE_ID_STABLE,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static PCIDeviceInfo qxl_info_secondary = {
+    .qdev.name    = "qxl",
+    .qdev.desc    = "Spice QXL GPU (secondary)",
+    .qdev.size    = sizeof(PCIQXLDevice),
+    .qdev.reset   = qxl_reset_handler,
+    .qdev.vmsd    = &qxl_vmstate,
+    .init         = qxl_init_secondary,
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .device_id    = QXL_DEVICE_ID_STABLE,
+    .class_id     = PCI_CLASS_DISPLAY_OTHER,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void qxl_register(void)
+{
+    pci_qdev_register(&qxl_info_primary);
+    pci_qdev_register(&qxl_info_secondary);
+}
+
+device_init(qxl_register);
diff --git a/qemu-0.15.x/hw/qxl.h b/qemu-0.15.x/hw/qxl.h
new file mode 100644
index 0000000..f6c450d
--- /dev/null
+++ b/qemu-0.15.x/hw/qxl.h
@@ -0,0 +1,108 @@
+#include "qemu-common.h"
+
+#include "console.h"
+#include "hw.h"
+#include "pci.h"
+#include "vga_int.h"
+
+#include "ui/qemu-spice.h"
+#include "ui/spice-display.h"
+
+enum qxl_mode {
+    QXL_MODE_UNDEFINED,
+    QXL_MODE_VGA,
+    QXL_MODE_COMPAT, /* spice 0.4.x */
+    QXL_MODE_NATIVE,
+};
+
+typedef struct PCIQXLDevice {
+    PCIDevice          pci;
+    SimpleSpiceDisplay ssd;
+    int                id;
+    uint32_t           debug;
+    uint32_t           guestdebug;
+    uint32_t           cmdlog;
+    enum qxl_mode      mode;
+    uint32_t           cmdflags;
+    int                generation;
+    uint32_t           revision;
+
+    int32_t            num_memslots;
+    int32_t            num_surfaces;
+
+    struct guest_slots {
+        QXLMemSlot     slot;
+        void           *ptr;
+        uint64_t       size;
+        uint64_t       delta;
+        uint32_t       active;
+    } guest_slots[NUM_MEMSLOTS];
+
+    struct guest_primary {
+        QXLSurfaceCreate surface;
+        uint32_t       commands;
+        uint32_t       resized;
+        int32_t        stride;
+        uint32_t       bits_pp;
+        uint32_t       bytes_pp;
+        uint8_t        *data, *flipped;
+    } guest_primary;
+
+    struct surfaces {
+        QXLPHYSICAL    cmds[NUM_SURFACES];
+        uint32_t       count;
+        uint32_t       max;
+    } guest_surfaces;
+    QXLPHYSICAL        guest_cursor;
+
+    /* thread signaling */
+    pthread_t          main;
+    int                pipe[2];
+
+    /* ram pci bar */
+    QXLRam             *ram;
+    VGACommonState     vga;
+    uint32_t           num_free_res;
+    QXLReleaseInfo     *last_release;
+    uint32_t           last_release_offset;
+    uint32_t           oom_running;
+
+    /* rom pci bar */
+    QXLRom             shadow_rom;
+    QXLRom             *rom;
+    QXLModes           *modes;
+    uint32_t           rom_size;
+    uint64_t           rom_offset;
+
+    /* vram pci bar */
+    uint32_t           vram_size;
+    uint64_t           vram_offset;
+
+    /* io bar */
+    uint32_t           io_base;
+} PCIQXLDevice;
+
+#define PANIC_ON(x) if ((x)) {                         \
+    printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
+    exit(-1);                                          \
+}
+
+#define dprint(_qxl, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_qxl->debug >= _level) {                                    \
+            fprintf(stderr, "qxl-%d: ", _qxl->id);                      \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+/* qxl.c */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+
+/* qxl-logger.c */
+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
+
+/* qxl-render.c */
+void qxl_render_resize(PCIQXLDevice *qxl);
+void qxl_render_update(PCIQXLDevice *qxl);
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
diff --git a/qemu-0.15.x/hw/r2d.c b/qemu-0.15.x/hw/r2d.c
new file mode 100644
index 0000000..a0f8c1f
--- /dev/null
+++ b/qemu-0.15.x/hw/r2d.c
@@ -0,0 +1,341 @@
+/*
+ * Renesas SH7751R R2D-PLUS emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Copyright (c) 2008 Paul Mundt
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "sh.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "pci.h"
+#include "net.h"
+#include "sh7750_regs.h"
+#include "ide.h"
+#include "loader.h"
+#include "usb.h"
+#include "flash.h"
+#include "blockdev.h"
+
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x02000000
+
+#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
+#define SDRAM_SIZE 0x04000000
+
+#define SM501_VRAM_SIZE 0x800000
+
+#define BOOT_PARAMS_OFFSET 0x0010000
+/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
+#define LINUX_LOAD_OFFSET  0x0800000
+#define INITRD_LOAD_OFFSET 0x1800000
+
+#define PA_IRLMSK	0x00
+#define PA_POWOFF	0x30
+#define PA_VERREG	0x32
+#define PA_OUTPORT	0x36
+
+typedef struct {
+    uint16_t bcr;
+    uint16_t irlmsk;
+    uint16_t irlmon;
+    uint16_t cfctl;
+    uint16_t cfpow;
+    uint16_t dispctl;
+    uint16_t sdmpow;
+    uint16_t rtcce;
+    uint16_t pcicd;
+    uint16_t voyagerrts;
+    uint16_t cfrst;
+    uint16_t admrts;
+    uint16_t extrst;
+    uint16_t cfcdintclr;
+    uint16_t keyctlclr;
+    uint16_t pad0;
+    uint16_t pad1;
+    uint16_t verreg;
+    uint16_t inport;
+    uint16_t outport;
+    uint16_t bverreg;
+
+/* output pin */
+    qemu_irq irl;
+} r2d_fpga_t;
+
+enum r2d_fpga_irq {
+    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
+    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
+    NR_IRQS
+};
+
+static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
+    [CF_IDE]	= {  1, 1<<9 },
+    [CF_CD]	= {  2, 1<<8 },
+    [PCI_INTA]	= {  9, 1<<14 },
+    [PCI_INTB]	= { 10, 1<<13 },
+    [PCI_INTC]	= {  3, 1<<12 },
+    [PCI_INTD]	= {  0, 1<<11 },
+    [SM501]	= {  4, 1<<10 },
+    [KEY]	= {  5, 1<<6 },
+    [RTC_A]	= {  6, 1<<5 },
+    [RTC_T]	= {  7, 1<<4 },
+    [SDCARD]	= {  8, 1<<7 },
+    [EXT]	= { 11, 1<<0 },
+    [TP]	= { 12, 1<<15 },
+};
+
+static void update_irl(r2d_fpga_t *fpga)
+{
+    int i, irl = 15;
+    for (i = 0; i < NR_IRQS; i++)
+        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
+            if (irqtab[i].irl < irl)
+                irl = irqtab[i].irl;
+    qemu_set_irq(fpga->irl, irl ^ 15);
+}
+
+static void r2d_fpga_irq_set(void *opaque, int n, int level)
+{
+    r2d_fpga_t *fpga = opaque;
+    if (level)
+        fpga->irlmon |= irqtab[n].msk;
+    else
+        fpga->irlmon &= ~irqtab[n].msk;
+    update_irl(fpga);
+}
+
+static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr)
+{
+    r2d_fpga_t *s = opaque;
+
+    switch (addr) {
+    case PA_IRLMSK:
+        return s->irlmsk;
+    case PA_OUTPORT:
+	return s->outport;
+    case PA_POWOFF:
+	return 0x00;
+    case PA_VERREG:
+	return 0x10;
+    }
+
+    return 0;
+}
+
+static void
+r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    r2d_fpga_t *s = opaque;
+
+    switch (addr) {
+    case PA_IRLMSK:
+        s->irlmsk = value;
+        update_irl(s);
+	break;
+    case PA_OUTPORT:
+	s->outport = value;
+	break;
+    case PA_POWOFF:
+        if (value & 1) {
+            qemu_system_shutdown_request();
+        }
+        break;
+    case PA_VERREG:
+	/* Discard writes */
+	break;
+    }
+}
+
+static CPUReadMemoryFunc * const r2d_fpga_readfn[] = {
+    r2d_fpga_read,
+    r2d_fpga_read,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const r2d_fpga_writefn[] = {
+    r2d_fpga_write,
+    r2d_fpga_write,
+    NULL,
+};
+
+static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
+{
+    int iomemtype;
+    r2d_fpga_t *s;
+
+    s = qemu_mallocz(sizeof(r2d_fpga_t));
+
+    s->irl = irl;
+
+    iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
+				       r2d_fpga_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x40, iomemtype);
+    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
+}
+
+typedef struct ResetData {
+    CPUState *env;
+    uint32_t vector;
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUState *env = s->env;
+
+    cpu_reset(env);
+    env->pc = s->vector;
+}
+
+static struct __attribute__((__packed__))
+{
+    int mount_root_rdonly;
+    int ramdisk_flags;
+    int orig_root_dev;
+    int loader_type;
+    int initrd_start;
+    int initrd_size;
+
+    char pad[232];
+
+    char kernel_cmdline[256];
+} boot_params;
+
+static void r2d_init(ram_addr_t ram_size,
+              const char *boot_device,
+	      const char *kernel_filename, const char *kernel_cmdline,
+	      const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    ResetData *reset_info;
+    struct SH7750State *s;
+    ram_addr_t sdram_addr;
+    qemu_irq *irq;
+    DriveInfo *dinfo;
+    int i;
+
+    if (!cpu_model)
+        cpu_model = "SH7751R";
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info->env = env;
+    reset_info->vector = env->pc;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate memory space */
+    sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE);
+    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
+    /* Register peripherals */
+    s = sh7750_init(env);
+    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
+    sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
+                          irq[PCI_INTC], irq[PCI_INTD], NULL);
+
+    sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
+
+    /* onboard CF (True IDE mode, Master only). */
+    dinfo = drive_get(IF_IDE, 0, 0);
+    mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1,
+                  dinfo, NULL);
+
+    /* onboard flash memory */
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi02_register(0x0, qemu_ram_alloc(NULL, "r2d.flash", FLASH_SIZE),
+                          dinfo ? dinfo->bdrv : NULL, (16 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
+                          0x555, 0x2aa, 0);
+
+    /* NIC: rtl8139 on-board, and 2 slots. */
+    for (i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
+
+    /* USB keyboard */
+    usbdevice_create("keyboard");
+
+    /* Todo: register on board registers */
+    memset(&boot_params, 0, sizeof(boot_params));
+
+    if (kernel_filename) {
+        int kernel_size;
+
+        kernel_size = load_image_targphys(kernel_filename,
+                                          SDRAM_BASE + LINUX_LOAD_OFFSET,
+                                          INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
+        if (kernel_size < 0) {
+          fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+          exit(1);
+        }
+
+        /* initialization which should be done by firmware */
+        stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
+        stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
+        reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
+    }
+
+    if (initrd_filename) {
+        int initrd_size;
+
+        initrd_size = load_image_targphys(initrd_filename,
+                                          SDRAM_BASE + INITRD_LOAD_OFFSET,
+                                          SDRAM_SIZE - INITRD_LOAD_OFFSET);
+
+        if (initrd_size < 0) {
+          fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
+          exit(1);
+        }
+
+        /* initialization which should be done by firmware */
+        boot_params.loader_type = 1;
+        boot_params.initrd_start = INITRD_LOAD_OFFSET;
+        boot_params.initrd_size = initrd_size;
+    }
+
+    if (kernel_cmdline) {
+        strncpy(boot_params.kernel_cmdline, kernel_cmdline,
+                sizeof(boot_params.kernel_cmdline));
+    }
+
+    rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
+                       SDRAM_BASE + BOOT_PARAMS_OFFSET);
+}
+
+static QEMUMachine r2d_machine = {
+    .name = "r2d",
+    .desc = "r2d-plus board",
+    .init = r2d_init,
+};
+
+static void r2d_machine_init(void)
+{
+    qemu_register_machine(&r2d_machine);
+}
+
+machine_init(r2d_machine_init);
diff --git a/qemu-0.15.x/hw/rc4030.c b/qemu-0.15.x/hw/rc4030.c
new file mode 100644
index 0000000..6563336
--- /dev/null
+++ b/qemu-0.15.x/hw/rc4030.c
@@ -0,0 +1,830 @@
+/*
+ * QEMU JAZZ RC4030 chipset
+ *
+ * Copyright (c) 2007-2009 Herve Poussineau
+ *
+ * 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 "hw.h"
+#include "mips.h"
+#include "qemu-timer.h"
+
+/********************************************************/
+/* debug rc4030 */
+
+//#define DEBUG_RC4030
+//#define DEBUG_RC4030_DMA
+
+#ifdef DEBUG_RC4030
+#define DPRINTF(fmt, ...) \
+do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0)
+static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
+            "network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define RC4030_ERROR(fmt, ...) \
+do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+/********************************************************/
+/* rc4030 emulation                                     */
+
+typedef struct dma_pagetable_entry {
+    int32_t frame;
+    int32_t owner;
+} __attribute__((packed)) dma_pagetable_entry;
+
+#define DMA_PAGESIZE    4096
+#define DMA_REG_ENABLE  1
+#define DMA_REG_COUNT   2
+#define DMA_REG_ADDRESS 3
+
+#define DMA_FLAG_ENABLE     0x0001
+#define DMA_FLAG_MEM_TO_DEV 0x0002
+#define DMA_FLAG_TC_INTR    0x0100
+#define DMA_FLAG_MEM_INTR   0x0200
+#define DMA_FLAG_ADDR_INTR  0x0400
+
+typedef struct rc4030State
+{
+    uint32_t config; /* 0x0000: RC4030 config register */
+    uint32_t revision; /* 0x0008: RC4030 Revision register */
+    uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
+
+    /* DMA */
+    uint32_t dma_regs[8][4];
+    uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
+    uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
+
+    /* cache */
+    uint32_t cache_maint; /* 0x0030: Cache Maintenance */
+    uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
+    uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
+    uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
+    uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
+    uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
+
+    uint32_t nmi_interrupt; /* 0x0200: interrupt source */
+    uint32_t offset210;
+    uint32_t nvram_protect; /* 0x0220: NV ram protect register */
+    uint32_t rem_speed[16];
+    uint32_t imr_jazz; /* Local bus int enable mask */
+    uint32_t isr_jazz; /* Local bus int source */
+
+    /* timer */
+    QEMUTimer *periodic_timer;
+    uint32_t itr; /* Interval timer reload */
+
+    qemu_irq timer_irq;
+    qemu_irq jazz_bus_irq;
+} rc4030State;
+
+static void set_next_tick(rc4030State *s)
+{
+    qemu_irq_lower(s->timer_irq);
+    uint32_t tm_hz;
+
+    tm_hz = 1000 / (s->itr + 1);
+
+    qemu_mod_timer(s->periodic_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() / tm_hz);
+}
+
+/* called for accesses to rc4030 */
+static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr)
+{
+    rc4030State *s = opaque;
+    uint32_t val;
+
+    addr &= 0x3fff;
+    switch (addr & ~0x3) {
+    /* Global config register */
+    case 0x0000:
+        val = s->config;
+        break;
+    /* Revision register */
+    case 0x0008:
+        val = s->revision;
+        break;
+    /* Invalid Address register */
+    case 0x0010:
+        val = s->invalid_address_register;
+        break;
+    /* DMA transl. table base */
+    case 0x0018:
+        val = s->dma_tl_base;
+        break;
+    /* DMA transl. table limit */
+    case 0x0020:
+        val = s->dma_tl_limit;
+        break;
+    /* Remote Failed Address */
+    case 0x0038:
+        val = s->remote_failed_address;
+        break;
+    /* Memory Failed Address */
+    case 0x0040:
+        val = s->memory_failed_address;
+        break;
+    /* I/O Cache Byte Mask */
+    case 0x0058:
+        val = s->cache_bmask;
+        /* HACK */
+        if (s->cache_bmask == (uint32_t)-1)
+            s->cache_bmask = 0;
+        break;
+    /* Remote Speed Registers */
+    case 0x0070:
+    case 0x0078:
+    case 0x0080:
+    case 0x0088:
+    case 0x0090:
+    case 0x0098:
+    case 0x00a0:
+    case 0x00a8:
+    case 0x00b0:
+    case 0x00b8:
+    case 0x00c0:
+    case 0x00c8:
+    case 0x00d0:
+    case 0x00d8:
+    case 0x00e0:
+    case 0x00e8:
+        val = s->rem_speed[(addr - 0x0070) >> 3];
+        break;
+    /* DMA channel base address */
+    case 0x0100:
+    case 0x0108:
+    case 0x0110:
+    case 0x0118:
+    case 0x0120:
+    case 0x0128:
+    case 0x0130:
+    case 0x0138:
+    case 0x0140:
+    case 0x0148:
+    case 0x0150:
+    case 0x0158:
+    case 0x0160:
+    case 0x0168:
+    case 0x0170:
+    case 0x0178:
+    case 0x0180:
+    case 0x0188:
+    case 0x0190:
+    case 0x0198:
+    case 0x01a0:
+    case 0x01a8:
+    case 0x01b0:
+    case 0x01b8:
+    case 0x01c0:
+    case 0x01c8:
+    case 0x01d0:
+    case 0x01d8:
+    case 0x01e0:
+    case 0x01e8:
+    case 0x01f0:
+    case 0x01f8:
+        {
+            int entry = (addr - 0x0100) >> 5;
+            int idx = (addr & 0x1f) >> 3;
+            val = s->dma_regs[entry][idx];
+        }
+        break;
+    /* Interrupt source */
+    case 0x0200:
+        val = s->nmi_interrupt;
+        break;
+    /* Error type */
+    case 0x0208:
+        val = 0;
+        break;
+    /* Offset 0x0210 */
+    case 0x0210:
+        val = s->offset210;
+        break;
+    /* NV ram protect register */
+    case 0x0220:
+        val = s->nvram_protect;
+        break;
+    /* Interval timer count */
+    case 0x0230:
+        val = 0;
+        qemu_irq_lower(s->timer_irq);
+        break;
+    /* EISA interrupt */
+    case 0x0238:
+        val = 7; /* FIXME: should be read from EISA controller */
+        break;
+    default:
+        RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
+        val = 0;
+        break;
+    }
+
+    if ((addr & ~3) != 0x230) {
+        DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr);
+    }
+
+    return val;
+}
+
+static uint32_t rc4030_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
+    if (addr & 0x2)
+        return v >> 16;
+    else
+        return v & 0xffff;
+}
+
+static uint32_t rc4030_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
+    return (v >> (8 * (addr & 0x3))) & 0xff;
+}
+
+static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    rc4030State *s = opaque;
+    addr &= 0x3fff;
+
+    DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr);
+
+    switch (addr & ~0x3) {
+    /* Global config register */
+    case 0x0000:
+        s->config = val;
+        break;
+    /* DMA transl. table base */
+    case 0x0018:
+        s->dma_tl_base = val;
+        break;
+    /* DMA transl. table limit */
+    case 0x0020:
+        s->dma_tl_limit = val;
+        break;
+    /* DMA transl. table invalidated */
+    case 0x0028:
+        break;
+    /* Cache Maintenance */
+    case 0x0030:
+        s->cache_maint = val;
+        break;
+    /* I/O Cache Physical Tag */
+    case 0x0048:
+        s->cache_ptag = val;
+        break;
+    /* I/O Cache Logical Tag */
+    case 0x0050:
+        s->cache_ltag = val;
+        break;
+    /* I/O Cache Byte Mask */
+    case 0x0058:
+        s->cache_bmask |= val; /* HACK */
+        break;
+    /* I/O Cache Buffer Window */
+    case 0x0060:
+        /* HACK */
+        if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
+            target_phys_addr_t dest = s->cache_ptag & ~0x1;
+            dest += (s->cache_maint & 0x3) << 3;
+            cpu_physical_memory_write(dest, &val, 4);
+        }
+        break;
+    /* Remote Speed Registers */
+    case 0x0070:
+    case 0x0078:
+    case 0x0080:
+    case 0x0088:
+    case 0x0090:
+    case 0x0098:
+    case 0x00a0:
+    case 0x00a8:
+    case 0x00b0:
+    case 0x00b8:
+    case 0x00c0:
+    case 0x00c8:
+    case 0x00d0:
+    case 0x00d8:
+    case 0x00e0:
+    case 0x00e8:
+        s->rem_speed[(addr - 0x0070) >> 3] = val;
+        break;
+    /* DMA channel base address */
+    case 0x0100:
+    case 0x0108:
+    case 0x0110:
+    case 0x0118:
+    case 0x0120:
+    case 0x0128:
+    case 0x0130:
+    case 0x0138:
+    case 0x0140:
+    case 0x0148:
+    case 0x0150:
+    case 0x0158:
+    case 0x0160:
+    case 0x0168:
+    case 0x0170:
+    case 0x0178:
+    case 0x0180:
+    case 0x0188:
+    case 0x0190:
+    case 0x0198:
+    case 0x01a0:
+    case 0x01a8:
+    case 0x01b0:
+    case 0x01b8:
+    case 0x01c0:
+    case 0x01c8:
+    case 0x01d0:
+    case 0x01d8:
+    case 0x01e0:
+    case 0x01e8:
+    case 0x01f0:
+    case 0x01f8:
+        {
+            int entry = (addr - 0x0100) >> 5;
+            int idx = (addr & 0x1f) >> 3;
+            s->dma_regs[entry][idx] = val;
+        }
+        break;
+    /* Offset 0x0210 */
+    case 0x0210:
+        s->offset210 = val;
+        break;
+    /* Interval timer reload */
+    case 0x0228:
+        s->itr = val;
+        qemu_irq_lower(s->timer_irq);
+        set_next_tick(s);
+        break;
+    /* EISA interrupt */
+    case 0x0238:
+        break;
+    default:
+        RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
+        break;
+    }
+}
+
+static void rc4030_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
+
+    if (addr & 0x2)
+        val = (val << 16) | (old_val & 0x0000ffff);
+    else
+        val = val | (old_val & 0xffff0000);
+    rc4030_writel(opaque, addr & ~0x3, val);
+}
+
+static void rc4030_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
+
+    switch (addr & 3) {
+    case 0:
+        val = val | (old_val & 0xffffff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0xffff00ff);
+        break;
+    case 2:
+        val = (val << 16) | (old_val & 0xff00ffff);
+        break;
+    case 3:
+        val = (val << 24) | (old_val & 0x00ffffff);
+        break;
+    }
+    rc4030_writel(opaque, addr & ~0x3, val);
+}
+
+static CPUReadMemoryFunc * const rc4030_read[3] = {
+    rc4030_readb,
+    rc4030_readw,
+    rc4030_readl,
+};
+
+static CPUWriteMemoryFunc * const rc4030_write[3] = {
+    rc4030_writeb,
+    rc4030_writew,
+    rc4030_writel,
+};
+
+static void update_jazz_irq(rc4030State *s)
+{
+    uint16_t pending;
+
+    pending = s->isr_jazz & s->imr_jazz;
+
+#ifdef DEBUG_RC4030
+    if (s->isr_jazz != 0) {
+        uint32_t irq = 0;
+        DPRINTF("pending irqs:");
+        for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
+            if (s->isr_jazz & (1 << irq)) {
+                printf(" %s", irq_names[irq]);
+                if (!(s->imr_jazz & (1 << irq))) {
+                    printf("(ignored)");
+                }
+            }
+        }
+        printf("\n");
+    }
+#endif
+
+    if (pending != 0)
+        qemu_irq_raise(s->jazz_bus_irq);
+    else
+        qemu_irq_lower(s->jazz_bus_irq);
+}
+
+static void rc4030_irq_jazz_request(void *opaque, int irq, int level)
+{
+    rc4030State *s = opaque;
+
+    if (level) {
+        s->isr_jazz |= 1 << irq;
+    } else {
+        s->isr_jazz &= ~(1 << irq);
+    }
+
+    update_jazz_irq(s);
+}
+
+static void rc4030_periodic_timer(void *opaque)
+{
+    rc4030State *s = opaque;
+
+    set_next_tick(s);
+    qemu_irq_raise(s->timer_irq);
+}
+
+static uint32_t jazzio_readw(void *opaque, target_phys_addr_t addr)
+{
+    rc4030State *s = opaque;
+    uint32_t val;
+    uint32_t irq;
+    addr &= 0xfff;
+
+    switch (addr) {
+    /* Local bus int source */
+    case 0x00: {
+        uint32_t pending = s->isr_jazz & s->imr_jazz;
+        val = 0;
+        irq = 0;
+        while (pending) {
+            if (pending & 1) {
+                DPRINTF("returning irq %s\n", irq_names[irq]);
+                val = (irq + 1) << 2;
+                break;
+            }
+            irq++;
+            pending >>= 1;
+        }
+        break;
+    }
+    /* Local bus int enable mask */
+    case 0x02:
+        val = s->imr_jazz;
+        break;
+    default:
+        RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr);
+        val = 0;
+    }
+
+    DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr);
+
+    return val;
+}
+
+static uint32_t jazzio_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = jazzio_readw(opaque, addr & ~0x1);
+    return (v >> (8 * (addr & 0x1))) & 0xff;
+}
+
+static uint32_t jazzio_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = jazzio_readw(opaque, addr);
+    v |= jazzio_readw(opaque, addr + 2) << 16;
+    return v;
+}
+
+static void jazzio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    rc4030State *s = opaque;
+    addr &= 0xfff;
+
+    DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr);
+
+    switch (addr) {
+    /* Local bus int enable mask */
+    case 0x02:
+        s->imr_jazz = val;
+        update_jazz_irq(s);
+        break;
+    default:
+        RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr);
+        break;
+    }
+}
+
+static void jazzio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
+
+    switch (addr & 1) {
+    case 0:
+        val = val | (old_val & 0xff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0x00ff);
+        break;
+    }
+    jazzio_writew(opaque, addr & ~0x1, val);
+}
+
+static void jazzio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    jazzio_writew(opaque, addr, val & 0xffff);
+    jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
+}
+
+static CPUReadMemoryFunc * const jazzio_read[3] = {
+    jazzio_readb,
+    jazzio_readw,
+    jazzio_readl,
+};
+
+static CPUWriteMemoryFunc * const jazzio_write[3] = {
+    jazzio_writeb,
+    jazzio_writew,
+    jazzio_writel,
+};
+
+static void rc4030_reset(void *opaque)
+{
+    rc4030State *s = opaque;
+    int i;
+
+    s->config = 0x410; /* some boards seem to accept 0x104 too */
+    s->revision = 1;
+    s->invalid_address_register = 0;
+
+    memset(s->dma_regs, 0, sizeof(s->dma_regs));
+    s->dma_tl_base = s->dma_tl_limit = 0;
+
+    s->remote_failed_address = s->memory_failed_address = 0;
+    s->cache_maint = 0;
+    s->cache_ptag = s->cache_ltag = 0;
+    s->cache_bmask = 0;
+
+    s->offset210 = 0x18186;
+    s->nvram_protect = 7;
+    for (i = 0; i < 15; i++)
+        s->rem_speed[i] = 7;
+    s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
+    s->isr_jazz = 0;
+
+    s->itr = 0;
+
+    qemu_irq_lower(s->timer_irq);
+    qemu_irq_lower(s->jazz_bus_irq);
+}
+
+static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
+{
+    rc4030State* s = opaque;
+    int i, j;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    s->config = qemu_get_be32(f);
+    s->invalid_address_register = qemu_get_be32(f);
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 4; j++)
+            s->dma_regs[i][j] = qemu_get_be32(f);
+    s->dma_tl_base = qemu_get_be32(f);
+    s->dma_tl_limit = qemu_get_be32(f);
+    s->cache_maint = qemu_get_be32(f);
+    s->remote_failed_address = qemu_get_be32(f);
+    s->memory_failed_address = qemu_get_be32(f);
+    s->cache_ptag = qemu_get_be32(f);
+    s->cache_ltag = qemu_get_be32(f);
+    s->cache_bmask = qemu_get_be32(f);
+    s->offset210 = qemu_get_be32(f);
+    s->nvram_protect = qemu_get_be32(f);
+    for (i = 0; i < 15; i++)
+        s->rem_speed[i] = qemu_get_be32(f);
+    s->imr_jazz = qemu_get_be32(f);
+    s->isr_jazz = qemu_get_be32(f);
+    s->itr = qemu_get_be32(f);
+
+    set_next_tick(s);
+    update_jazz_irq(s);
+
+    return 0;
+}
+
+static void rc4030_save(QEMUFile *f, void *opaque)
+{
+    rc4030State* s = opaque;
+    int i, j;
+
+    qemu_put_be32(f, s->config);
+    qemu_put_be32(f, s->invalid_address_register);
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 4; j++)
+            qemu_put_be32(f, s->dma_regs[i][j]);
+    qemu_put_be32(f, s->dma_tl_base);
+    qemu_put_be32(f, s->dma_tl_limit);
+    qemu_put_be32(f, s->cache_maint);
+    qemu_put_be32(f, s->remote_failed_address);
+    qemu_put_be32(f, s->memory_failed_address);
+    qemu_put_be32(f, s->cache_ptag);
+    qemu_put_be32(f, s->cache_ltag);
+    qemu_put_be32(f, s->cache_bmask);
+    qemu_put_be32(f, s->offset210);
+    qemu_put_be32(f, s->nvram_protect);
+    for (i = 0; i < 15; i++)
+        qemu_put_be32(f, s->rem_speed[i]);
+    qemu_put_be32(f, s->imr_jazz);
+    qemu_put_be32(f, s->isr_jazz);
+    qemu_put_be32(f, s->itr);
+}
+
+void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)
+{
+    rc4030State *s = opaque;
+    target_phys_addr_t entry_addr;
+    target_phys_addr_t phys_addr;
+    dma_pagetable_entry entry;
+    int index;
+    int ncpy, i;
+
+    i = 0;
+    for (;;) {
+        if (i == len) {
+            break;
+        }
+
+        ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
+        if (ncpy > len - i)
+            ncpy = len - i;
+
+        /* Get DMA translation table entry */
+        index = addr / DMA_PAGESIZE;
+        if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
+            break;
+        }
+        entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
+        /* XXX: not sure. should we really use only lowest bits? */
+        entry_addr &= 0x7fffffff;
+        cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
+
+        /* Read/write data at right place */
+        phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
+        cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
+
+        i += ncpy;
+        addr += ncpy;
+    }
+}
+
+static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
+{
+    rc4030State *s = opaque;
+    target_phys_addr_t dma_addr;
+    int dev_to_mem;
+
+    s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
+
+    /* Check DMA channel consistency */
+    dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
+    if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
+        (is_write != dev_to_mem)) {
+        s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+        s->nmi_interrupt |= 1 << n;
+        return;
+    }
+
+    /* Get start address and len */
+    if (len > s->dma_regs[n][DMA_REG_COUNT])
+        len = s->dma_regs[n][DMA_REG_COUNT];
+    dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
+
+    /* Read/write data at right place */
+    rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
+
+    s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
+    s->dma_regs[n][DMA_REG_COUNT] -= len;
+
+#ifdef DEBUG_RC4030_DMA
+    {
+        int i, j;
+        printf("rc4030 dma: Copying %d bytes %s host %p\n",
+            len, is_write ? "from" : "to", buf);
+        for (i = 0; i < len; i += 16) {
+            int n = 16;
+            if (n > len - i) {
+                n = len - i;
+            }
+            for (j = 0; j < n; j++)
+                printf("%02x ", buf[i + j]);
+            while (j++ < 16)
+                printf("   ");
+            printf("| ");
+            for (j = 0; j < n; j++)
+                printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
+            printf("\n");
+        }
+    }
+#endif
+}
+
+struct rc4030DMAState {
+    void *opaque;
+    int n;
+};
+
+void rc4030_dma_read(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 0);
+}
+
+void rc4030_dma_write(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 1);
+}
+
+static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
+{
+    rc4030_dma *s;
+    struct rc4030DMAState *p;
+    int i;
+
+    s = (rc4030_dma *)qemu_mallocz(sizeof(rc4030_dma) * n);
+    p = (struct rc4030DMAState *)qemu_mallocz(sizeof(struct rc4030DMAState) * n);
+    for (i = 0; i < n; i++) {
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+                  qemu_irq **irqs, rc4030_dma **dmas)
+{
+    rc4030State *s;
+    int s_chipset, s_jazzio;
+
+    s = qemu_mallocz(sizeof(rc4030State));
+
+    *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
+    *dmas = rc4030_allocate_dmas(s, 4);
+
+    s->periodic_timer = qemu_new_timer_ns(vm_clock, rc4030_periodic_timer, s);
+    s->timer_irq = timer;
+    s->jazz_bus_irq = jazz_bus;
+
+    qemu_register_reset(rc4030_reset, s);
+    register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
+    rc4030_reset(s);
+
+    s_chipset = cpu_register_io_memory(rc4030_read, rc4030_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0x80000000, 0x300, s_chipset);
+    s_jazzio = cpu_register_io_memory(jazzio_read, jazzio_write, s,
+                                      DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/realview.c b/qemu-0.15.x/hw/realview.c
new file mode 100644
index 0000000..94ab900
--- /dev/null
+++ b/qemu-0.15.x/hw/realview.c
@@ -0,0 +1,467 @@
+/*
+ * ARM RealView Baseboard System emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "pci.h"
+#include "usb-ohci.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "bitbang_i2c.h"
+#include "blockdev.h"
+
+#define SMP_BOOT_ADDR 0xe0000000
+
+typedef struct {
+    SysBusDevice busdev;
+    bitbang_i2c_interface *bitbang;
+    int out;
+    int in;
+} RealViewI2CState;
+
+static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset)
+{
+    RealViewI2CState *s = (RealViewI2CState *)opaque;
+
+    if (offset == 0) {
+        return (s->out & 1) | (s->in << 1);
+    } else {
+        hw_error("realview_i2c_read: Bad offset 0x%x\n", (int)offset);
+        return -1;
+    }
+}
+
+static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    RealViewI2CState *s = (RealViewI2CState *)opaque;
+
+    switch (offset) {
+    case 0:
+        s->out |= value & 3;
+        break;
+    case 4:
+        s->out &= ~value;
+        break;
+    default:
+        hw_error("realview_i2c_write: Bad offset 0x%x\n", (int)offset);
+    }
+    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static CPUReadMemoryFunc * const realview_i2c_readfn[] = {
+   realview_i2c_read,
+   realview_i2c_read,
+   realview_i2c_read
+};
+
+static CPUWriteMemoryFunc * const realview_i2c_writefn[] = {
+   realview_i2c_write,
+   realview_i2c_write,
+   realview_i2c_write
+};
+
+static int realview_i2c_init(SysBusDevice *dev)
+{
+    RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
+    i2c_bus *bus;
+    int iomemtype;
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+    iomemtype = cpu_register_io_memory(realview_i2c_readfn,
+                                       realview_i2c_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    return 0;
+}
+
+static SysBusDeviceInfo realview_i2c_info = {
+    .init = realview_i2c_init,
+    .qdev.name  = "realview_i2c",
+    .qdev.size  = sizeof(RealViewI2CState),
+};
+
+static void realview_register_devices(void)
+{
+    sysbus_register_withprop(&realview_i2c_info);
+}
+
+/* Board init.  */
+
+static struct arm_boot_info realview_binfo = {
+    .smp_loader_start = SMP_BOOT_ADDR,
+};
+
+/* The following two lists must be consistent.  */
+enum realview_board_type {
+    BOARD_EB,
+    BOARD_EB_MPCORE,
+    BOARD_PB_A8,
+    BOARD_PBX_A9,
+};
+
+static const int realview_board_id[] = {
+    0x33b,
+    0x33b,
+    0x769,
+    0x76d
+};
+
+static void realview_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model,
+                     enum realview_board_type board_type)
+{
+    CPUState *env = NULL;
+    ram_addr_t ram_offset;
+    DeviceState *dev, *sysctl, *gpio2;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    qemu_irq mmc_irq[2];
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    i2c_bus *i2c;
+    int n;
+    int done_nic = 0;
+    qemu_irq cpu_irq[4];
+    int is_mpcore = 0;
+    int is_pb = 0;
+    uint32_t proc_id = 0;
+    uint32_t sys_id;
+    ram_addr_t low_ram_size;
+
+    switch (board_type) {
+    case BOARD_EB:
+        break;
+    case BOARD_EB_MPCORE:
+        is_mpcore = 1;
+        break;
+    case BOARD_PB_A8:
+        is_pb = 1;
+        break;
+    case BOARD_PBX_A9:
+        is_mpcore = 1;
+        is_pb = 1;
+        break;
+    }
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(env);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        if (is_mpcore) {
+            proc_id = 0x0c000000;
+        } else {
+            proc_id = 0x0e000000;
+        }
+    } else if (arm_feature(env, ARM_FEATURE_V6K)) {
+        proc_id = 0x06000000;
+    } else if (arm_feature(env, ARM_FEATURE_V6)) {
+        proc_id = 0x04000000;
+    } else {
+        proc_id = 0x02000000;
+    }
+
+    if (is_pb && ram_size > 0x20000000) {
+        /* Core tile RAM.  */
+        low_ram_size = ram_size - 0x20000000;
+        ram_size = 0x20000000;
+        ram_offset = qemu_ram_alloc(NULL, "realview.lowmem", low_ram_size);
+        cpu_register_physical_memory(0x20000000, low_ram_size,
+                                     ram_offset | IO_MEM_RAM);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "realview.highmem", ram_size);
+    low_ram_size = ram_size;
+    if (low_ram_size > 0x10000000)
+      low_ram_size = 0x10000000;
+    /* SDRAM at address zero.  */
+    cpu_register_physical_memory(0, low_ram_size, ram_offset | IO_MEM_RAM);
+    if (is_pb) {
+        /* And again at a high address.  */
+        cpu_register_physical_memory(0x70000000, ram_size,
+                                     ram_offset | IO_MEM_RAM);
+    } else {
+        ram_size = low_ram_size;
+    }
+
+    sys_id = is_pb ? 0x01780500 : 0xc1400400;
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_init_nofail(sysctl);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+
+    if (is_mpcore) {
+        dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
+        qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+        qdev_init_nofail(dev);
+        busdev = sysbus_from_qdev(dev);
+        if (is_pb) {
+            realview_binfo.smp_priv_base = 0x1f000000;
+        } else {
+            realview_binfo.smp_priv_base = 0x10100000;
+        }
+        sysbus_mmio_map(busdev, 0, realview_binfo.smp_priv_base);
+        for (n = 0; n < smp_cpus; n++) {
+            sysbus_connect_irq(busdev, n, cpu_irq[n]);
+        }
+    } else {
+        uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
+        /* For now just create the nIRQ GIC, and ignore the others.  */
+        dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]);
+    }
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
+
+    sysbus_create_simple("pl011", 0x10009000, pic[12]);
+    sysbus_create_simple("pl011", 0x1000a000, pic[13]);
+    sysbus_create_simple("pl011", 0x1000b000, pic[14]);
+    sysbus_create_simple("pl011", 0x1000c000, pic[15]);
+
+    /* DMA controller is optional, apparently.  */
+    sysbus_create_simple("pl081", 0x10030000, pic[24]);
+
+    sysbus_create_simple("sp804", 0x10011000, pic[4]);
+    sysbus_create_simple("sp804", 0x10012000, pic[5]);
+
+    sysbus_create_simple("pl061", 0x10013000, pic[6]);
+    sysbus_create_simple("pl061", 0x10014000, pic[7]);
+    gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]);
+
+    sysbus_create_simple("pl110_versatile", 0x10020000, pic[23]);
+
+    dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL);
+    /* Wire up MMC card detect and read-only signals. These have
+     * to go to both the PL061 GPIO and the sysctl register.
+     * Note that the PL181 orders these lines (readonly,inserted)
+     * and the PL061 has them the other way about. Also the card
+     * detect line is inverted.
+     */
+    mmc_irq[0] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT),
+        qdev_get_gpio_in(gpio2, 1));
+    mmc_irq[1] = qemu_irq_split(
+        qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN),
+        qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
+    qdev_connect_gpio_out(dev, 0, mmc_irq[0]);
+    qdev_connect_gpio_out(dev, 1, mmc_irq[1]);
+
+    sysbus_create_simple("pl031", 0x10017000, pic[10]);
+
+    if (!is_pb) {
+        dev = sysbus_create_varargs("realview_pci", 0x60000000,
+                                    pic[48], pic[49], pic[50], pic[51], NULL);
+        pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+        if (usb_enabled) {
+            usb_ohci_init_pci(pci_bus, -1);
+        }
+        n = drive_get_max_bus(IF_SCSI);
+        while (n >= 0) {
+            pci_create_simple(pci_bus, -1, "lsi53c895a");
+            n--;
+        }
+    }
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+
+        if (!done_nic && (!nd->model ||
+                    strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) {
+            if (is_pb) {
+                lan9118_init(nd, 0x4e000000, pic[28]);
+            } else {
+                smc91c111_init(nd, 0x4e000000, pic[28]);
+            }
+            done_nic = 1;
+        } else {
+            pci_nic_init_nofail(nd, "rtl8139", NULL);
+        }
+    }
+
+    dev = sysbus_create_simple("realview_i2c", 0x10002000, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+    i2c_create_slave(i2c, "ds1338", 0x68);
+
+    /* Memory map for RealView Emulation Baseboard:  */
+    /* 0x10000000 System registers.  */
+    /*  0x10001000 System controller.  */
+    /* 0x10002000 Two-Wire Serial Bus.  */
+    /* 0x10003000 Reserved.  */
+    /*  0x10004000 AACI.  */
+    /*  0x10005000 MCI.  */
+    /* 0x10006000 KMI0.  */
+    /* 0x10007000 KMI1.  */
+    /*  0x10008000 Character LCD. (EB) */
+    /* 0x10009000 UART0.  */
+    /* 0x1000a000 UART1.  */
+    /* 0x1000b000 UART2.  */
+    /* 0x1000c000 UART3.  */
+    /*  0x1000d000 SSPI.  */
+    /*  0x1000e000 SCI.  */
+    /* 0x1000f000 Reserved.  */
+    /*  0x10010000 Watchdog.  */
+    /* 0x10011000 Timer 0+1.  */
+    /* 0x10012000 Timer 2+3.  */
+    /*  0x10013000 GPIO 0.  */
+    /*  0x10014000 GPIO 1.  */
+    /*  0x10015000 GPIO 2.  */
+    /*  0x10002000 Two-Wire Serial Bus - DVI. (PB) */
+    /* 0x10017000 RTC.  */
+    /*  0x10018000 DMC.  */
+    /*  0x10019000 PCI controller config.  */
+    /*  0x10020000 CLCD.  */
+    /* 0x10030000 DMA Controller.  */
+    /* 0x10040000 GIC1. (EB) */
+    /*  0x10050000 GIC2. (EB) */
+    /*  0x10060000 GIC3. (EB) */
+    /*  0x10070000 GIC4. (EB) */
+    /*  0x10080000 SMC.  */
+    /* 0x1e000000 GIC1. (PB) */
+    /*  0x1e001000 GIC2. (PB) */
+    /*  0x1e002000 GIC3. (PB) */
+    /*  0x1e003000 GIC4. (PB) */
+    /*  0x40000000 NOR flash.  */
+    /*  0x44000000 DoC flash.  */
+    /*  0x48000000 SRAM.  */
+    /*  0x4c000000 Configuration flash.  */
+    /* 0x4e000000 Ethernet.  */
+    /*  0x4f000000 USB.  */
+    /*  0x50000000 PISMO.  */
+    /*  0x54000000 PISMO.  */
+    /*  0x58000000 PISMO.  */
+    /*  0x5c000000 PISMO.  */
+    /* 0x60000000 PCI.  */
+    /* 0x61000000 PCI Self Config.  */
+    /* 0x62000000 PCI Config.  */
+    /* 0x63000000 PCI IO.  */
+    /* 0x64000000 PCI mem 0.  */
+    /* 0x68000000 PCI mem 1.  */
+    /* 0x6c000000 PCI mem 2.  */
+
+    /* ??? Hack to map an additional page of ram for the secondary CPU
+       startup code.  I guess this works on real hardware because the
+       BootROM happens to be in ROM/flash or in memory that isn't clobbered
+       until after Linux boots the secondary CPUs.  */
+    ram_offset = qemu_ram_alloc(NULL, "realview.hack", 0x1000);
+    cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
+                                 ram_offset | IO_MEM_RAM);
+
+    realview_binfo.ram_size = ram_size;
+    realview_binfo.kernel_filename = kernel_filename;
+    realview_binfo.kernel_cmdline = kernel_cmdline;
+    realview_binfo.initrd_filename = initrd_filename;
+    realview_binfo.nb_cpus = smp_cpus;
+    realview_binfo.board_id = realview_board_id[board_type];
+    realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
+    arm_load_kernel(first_cpu, &realview_binfo);
+}
+
+static void realview_eb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_EB);
+}
+
+static void realview_eb_mpcore_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "arm11mpcore";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_EB_MPCORE);
+}
+
+static void realview_pb_a8_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "cortex-a8";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_PB_A8);
+}
+
+static void realview_pbx_a9_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_PBX_A9);
+}
+
+static QEMUMachine realview_eb_machine = {
+    .name = "realview-eb",
+    .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
+    .init = realview_eb_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine realview_eb_mpcore_machine = {
+    .name = "realview-eb-mpcore",
+    .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)",
+    .init = realview_eb_mpcore_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static QEMUMachine realview_pb_a8_machine = {
+    .name = "realview-pb-a8",
+    .desc = "ARM RealView Platform Baseboard for Cortex-A8",
+    .init = realview_pb_a8_init,
+};
+
+static QEMUMachine realview_pbx_a9_machine = {
+    .name = "realview-pbx-a9",
+    .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9",
+    .init = realview_pbx_a9_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static void realview_machine_init(void)
+{
+    qemu_register_machine(&realview_eb_machine);
+    qemu_register_machine(&realview_eb_mpcore_machine);
+    qemu_register_machine(&realview_pb_a8_machine);
+    qemu_register_machine(&realview_pbx_a9_machine);
+}
+
+machine_init(realview_machine_init);
+device_init(realview_register_devices)
diff --git a/qemu-0.15.x/hw/realview_gic.c b/qemu-0.15.x/hw/realview_gic.c
new file mode 100644
index 0000000..43a2a0d
--- /dev/null
+++ b/qemu-0.15.x/hw/realview_gic.c
@@ -0,0 +1,79 @@
+/*
+ * ARM RealView Emulation Baseboard Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+
+#define GIC_NIRQ 96
+#define NCPU 1
+
+/* Only a single "CPU" interface is present.  */
+static inline int
+gic_get_current_cpu(void)
+{
+  return 0;
+}
+
+#include "arm_gic.c"
+
+typedef struct {
+    gic_state gic;
+    int iomemtype;
+} RealViewGICState;
+
+static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset)
+{
+    gic_state *s = (gic_state *)opaque;
+    return gic_cpu_read(s, gic_get_current_cpu(), offset);
+}
+
+static void realview_gic_cpu_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+    gic_cpu_write(s, gic_get_current_cpu(), offset, value);
+}
+
+static CPUReadMemoryFunc * const realview_gic_cpu_readfn[] = {
+   realview_gic_cpu_read,
+   realview_gic_cpu_read,
+   realview_gic_cpu_read
+};
+
+static CPUWriteMemoryFunc * const realview_gic_cpu_writefn[] = {
+   realview_gic_cpu_write,
+   realview_gic_cpu_write,
+   realview_gic_cpu_write
+};
+
+static void realview_gic_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
+    cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+    cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+}
+
+static int realview_gic_init(SysBusDevice *dev)
+{
+    RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
+
+    gic_init(&s->gic);
+    s->iomemtype = cpu_register_io_memory(realview_gic_cpu_readfn,
+                                          realview_gic_cpu_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map);
+    return 0;
+}
+
+static void realview_gic_register_devices(void)
+{
+    sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
+                        realview_gic_init);
+}
+
+device_init(realview_gic_register_devices)
diff --git a/qemu-0.15.x/hw/rtl8139.c b/qemu-0.15.x/hw/rtl8139.c
new file mode 100644
index 0000000..5214b8c
--- /dev/null
+++ b/qemu-0.15.x/hw/rtl8139.c
@@ -0,0 +1,3528 @@
+/**
+ * QEMU RTL8139 emulation
+ *
+ * Copyright (c) 2006 Igor Kovalenko
+ *
+ * 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.
+
+ * Modifications:
+ *  2006-Jan-28  Mark Malakanov :   TSAD and CSCR implementation (for Windows driver)
+ *
+ *  2006-Apr-28  Juergen Lock   :   EEPROM emulation changes for FreeBSD driver
+ *                                  HW revision ID changes for FreeBSD driver
+ *
+ *  2006-Jul-01  Igor Kovalenko :   Implemented loopback mode for FreeBSD driver
+ *                                  Corrected packet transfer reassembly routine for 8139C+ mode
+ *                                  Rearranged debugging print statements
+ *                                  Implemented PCI timer interrupt (disabled by default)
+ *                                  Implemented Tally Counters, increased VM load/save version
+ *                                  Implemented IP/TCP/UDP checksum task offloading
+ *
+ *  2006-Jul-04  Igor Kovalenko :   Implemented TCP segmentation offloading
+ *                                  Fixed MTU=1500 for produced ethernet frames
+ *
+ *  2006-Jul-09  Igor Kovalenko :   Fixed TCP header length calculation while processing
+ *                                  segmentation offloading
+ *                                  Removed slirp.h dependency
+ *                                  Added rx/tx buffer reset when enabling rx/tx operation
+ *
+ *  2010-Feb-04  Frediano Ziglio:   Rewrote timer support using QEMU timer only
+ *                                  when strictly needed (required for for
+ *                                  Darwin)
+ *  2011-Mar-22  Benjamin Poirier:  Implemented VLAN offloading
+ */
+
+/* For crc32 */
+#include <zlib.h>
+
+#include "hw.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "net.h"
+#include "loader.h"
+#include "sysemu.h"
+#include "iov.h"
+
+/* debug RTL8139 card */
+//#define DEBUG_RTL8139 1
+
+#define PCI_FREQUENCY 33000000L
+
+/* debug RTL8139 card C+ mode only */
+//#define DEBUG_RTL8139CP 1
+
+#define SET_MASKED(input, mask, curr) \
+    ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
+
+/* arg % size for size which is a power of 2 */
+#define MOD2(input, size) \
+    ( ( input ) & ( size - 1 )  )
+
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETH_P_IP    0x0800      /* Internet Protocol packet */
+#define ETH_P_8021Q 0x8100      /* 802.1Q VLAN Extended Header  */
+#define ETH_MTU     1500
+
+#define VLAN_TCI_LEN 2
+#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
+#if defined (DEBUG_RTL8139)
+#  define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
+#else
+static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
+{
+    return 0;
+}
+#endif
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+    MAC0 = 0,        /* Ethernet hardware address. */
+    MAR0 = 8,        /* Multicast filter. */
+    TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
+                     /* Dump Tally Conter control register(64bit). C+ mode only */
+    TxAddr0 = 0x20,  /* Tx descriptors (also four 32bit). */
+    RxBuf = 0x30,
+    ChipCmd = 0x37,
+    RxBufPtr = 0x38,
+    RxBufAddr = 0x3A,
+    IntrMask = 0x3C,
+    IntrStatus = 0x3E,
+    TxConfig = 0x40,
+    RxConfig = 0x44,
+    Timer = 0x48,        /* A general-purpose counter. */
+    RxMissed = 0x4C,    /* 24 bits valid, write clears. */
+    Cfg9346 = 0x50,
+    Config0 = 0x51,
+    Config1 = 0x52,
+    FlashReg = 0x54,
+    MediaStatus = 0x58,
+    Config3 = 0x59,
+    Config4 = 0x5A,        /* absent on RTL-8139A */
+    HltClk = 0x5B,
+    MultiIntr = 0x5C,
+    PCIRevisionID = 0x5E,
+    TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
+    BasicModeCtrl = 0x62,
+    BasicModeStatus = 0x64,
+    NWayAdvert = 0x66,
+    NWayLPAR = 0x68,
+    NWayExpansion = 0x6A,
+    /* Undocumented registers, but required for proper operation. */
+    FIFOTMS = 0x70,        /* FIFO Control and test. */
+    CSCR = 0x74,        /* Chip Status and Configuration Register. */
+    PARA78 = 0x78,
+    PARA7c = 0x7c,        /* Magic transceiver parameter register. */
+    Config5 = 0xD8,        /* absent on RTL-8139A */
+    /* C+ mode */
+    TxPoll        = 0xD9,    /* Tell chip to check Tx descriptors for work */
+    RxMaxSize    = 0xDA, /* Max size of an Rx packet (8169 only) */
+    CpCmd        = 0xE0, /* C+ Command register (C+ mode only) */
+    IntrMitigate    = 0xE2,    /* rx/tx interrupt mitigation control */
+    RxRingAddrLO    = 0xE4, /* 64-bit start addr of Rx ring */
+    RxRingAddrHI    = 0xE8, /* 64-bit start addr of Rx ring */
+    TxThresh    = 0xEC, /* Early Tx threshold */
+};
+
+enum ClearBitMasks {
+    MultiIntrClear = 0xF000,
+    ChipCmdClear = 0xE2,
+    Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+};
+
+enum ChipCmdBits {
+    CmdReset = 0x10,
+    CmdRxEnb = 0x08,
+    CmdTxEnb = 0x04,
+    RxBufEmpty = 0x01,
+};
+
+/* C+ mode */
+enum CplusCmdBits {
+    CPlusRxVLAN   = 0x0040, /* enable receive VLAN detagging */
+    CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
+    CPlusRxEnb    = 0x0002,
+    CPlusTxEnb    = 0x0001,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+    PCIErr = 0x8000,
+    PCSTimeout = 0x4000,
+    RxFIFOOver = 0x40,
+    RxUnderrun = 0x20,
+    RxOverflow = 0x10,
+    TxErr = 0x08,
+    TxOK = 0x04,
+    RxErr = 0x02,
+    RxOK = 0x01,
+
+    RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+};
+
+enum TxStatusBits {
+    TxHostOwns = 0x2000,
+    TxUnderrun = 0x4000,
+    TxStatOK = 0x8000,
+    TxOutOfWindow = 0x20000000,
+    TxAborted = 0x40000000,
+    TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+    RxMulticast = 0x8000,
+    RxPhysical = 0x4000,
+    RxBroadcast = 0x2000,
+    RxBadSymbol = 0x0020,
+    RxRunt = 0x0010,
+    RxTooLong = 0x0008,
+    RxCRCErr = 0x0004,
+    RxBadAlign = 0x0002,
+    RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+    AcceptErr = 0x20,
+    AcceptRunt = 0x10,
+    AcceptBroadcast = 0x08,
+    AcceptMulticast = 0x04,
+    AcceptMyPhys = 0x02,
+    AcceptAllPhys = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits {
+
+        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+        TxIFGShift = 24,
+        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TxCRC = (1 << 16),    /* DISABLE appending CRC to end of Tx packets */
+    TxClearAbt = (1 << 0),    /* Clear abort (WO) */
+    TxDMAShift = 8,        /* DMA burst value (0-7) is shifted this many bits */
+    TxRetryShift = 4,    /* TXRR value (0-15) is shifted this many bits */
+
+    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+
+/* Transmit Status of All Descriptors (TSAD) Register */
+enum TSAD_bits {
+ TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
+ TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
+ TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
+ TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
+ TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
+ TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
+ TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
+ TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
+ TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
+ TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
+ TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
+ TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
+ TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
+ TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
+ TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
+ TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
+};
+
+
+/* Bits in Config1 */
+enum Config1Bits {
+    Cfg1_PM_Enable = 0x01,
+    Cfg1_VPD_Enable = 0x02,
+    Cfg1_PIO = 0x04,
+    Cfg1_MMIO = 0x08,
+    LWAKE = 0x10,        /* not on 8139, 8139A */
+    Cfg1_Driver_Load = 0x20,
+    Cfg1_LED0 = 0x40,
+    Cfg1_LED1 = 0x80,
+    SLEEP = (1 << 1),    /* only on 8139, 8139A */
+    PWRDN = (1 << 0),    /* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum Config3Bits {
+    Cfg3_FBtBEn    = (1 << 0), /* 1 = Fast Back to Back */
+    Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+    Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+    Cfg3_CardB_En  = (1 << 3), /* 1 = enable CardBus registers */
+    Cfg3_LinkUp    = (1 << 4), /* 1 = wake up on link up */
+    Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+    Cfg3_PARM_En   = (1 << 6), /* 0 = software can set twister parameters */
+    Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum Config4Bits {
+    LWPTN = (1 << 2),    /* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum Config5Bits {
+    Cfg5_PME_STS     = (1 << 0), /* 1 = PCI reset resets PME_Status */
+    Cfg5_LANWake     = (1 << 1), /* 1 = enable LANWake signal */
+    Cfg5_LDPS        = (1 << 2), /* 0 = save power when link is down */
+    Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
+    Cfg5_UWF         = (1 << 4), /* 1 = accept unicast wakeup frame */
+    Cfg5_MWF         = (1 << 5), /* 1 = accept multicast wakeup frame */
+    Cfg5_BWF         = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum RxConfigBits {
+    /* rx fifo threshold */
+    RxCfgFIFOShift = 13,
+    RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+    /* Max DMA burst */
+    RxCfgDMAShift = 8,
+    RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+    /* rx ring buffer length */
+    RxCfgRcv8K = 0,
+    RxCfgRcv16K = (1 << 11),
+    RxCfgRcv32K = (1 << 12),
+    RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+    /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+    RxNoWrap = (1 << 7),
+};
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links on some boards. */
+/*
+enum CSCRBits {
+    CSCR_LinkOKBit = 0x0400,
+    CSCR_LinkChangeBit = 0x0800,
+    CSCR_LinkStatusBits = 0x0f000,
+    CSCR_LinkDownOffCmd = 0x003c0,
+    CSCR_LinkDownCmd = 0x0f3c0,
+*/
+enum CSCRBits {
+    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
+    CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
+    CSCR_HEART_BIT = 1<<8,  /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
+    CSCR_JBEN = 1<<7,  /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
+    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
+    CSCR_F_Connect  = 1<<5,  /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
+    CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
+    CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
+    CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
+};
+
+enum Cfg9346Bits {
+    Cfg9346_Lock = 0x00,
+    Cfg9346_Unlock = 0xC0,
+};
+
+typedef enum {
+    CH_8139 = 0,
+    CH_8139_K,
+    CH_8139A,
+    CH_8139A_G,
+    CH_8139B,
+    CH_8130,
+    CH_8139C,
+    CH_8100,
+    CH_8100B_8139D,
+    CH_8101,
+} chip_t;
+
+enum chip_flags {
+    HasHltClk = (1 << 0),
+    HasLWake = (1 << 1),
+};
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+    (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+#define HW_REVID_MASK    HW_REVID(1, 1, 1, 1, 1, 1, 1)
+
+#define RTL8139_PCI_REVID_8139      0x10
+#define RTL8139_PCI_REVID_8139CPLUS 0x20
+
+#define RTL8139_PCI_REVID           RTL8139_PCI_REVID_8139CPLUS
+
+/* Size is 64 * 16bit words */
+#define EEPROM_9346_ADDR_BITS 6
+#define EEPROM_9346_SIZE  (1 << EEPROM_9346_ADDR_BITS)
+#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
+
+enum Chip9346Operation
+{
+    Chip9346_op_mask = 0xc0,          /* 10 zzzzzz */
+    Chip9346_op_read = 0x80,          /* 10 AAAAAA */
+    Chip9346_op_write = 0x40,         /* 01 AAAAAA D(15)..D(0) */
+    Chip9346_op_ext_mask = 0xf0,      /* 11 zzzzzz */
+    Chip9346_op_write_enable = 0x30,  /* 00 11zzzz */
+    Chip9346_op_write_all = 0x10,     /* 00 01zzzz */
+    Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
+};
+
+enum Chip9346Mode
+{
+    Chip9346_none = 0,
+    Chip9346_enter_command_mode,
+    Chip9346_read_command,
+    Chip9346_data_read,      /* from output register */
+    Chip9346_data_write,     /* to input register, then to contents at specified address */
+    Chip9346_data_write_all, /* to input register, then filling contents */
+};
+
+typedef struct EEprom9346
+{
+    uint16_t contents[EEPROM_9346_SIZE];
+    int      mode;
+    uint32_t tick;
+    uint8_t  address;
+    uint16_t input;
+    uint16_t output;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedi;
+    uint8_t eedo;
+} EEprom9346;
+
+typedef struct RTL8139TallyCounters
+{
+    /* Tally counters */
+    uint64_t   TxOk;
+    uint64_t   RxOk;
+    uint64_t   TxERR;
+    uint32_t   RxERR;
+    uint16_t   MissPkt;
+    uint16_t   FAE;
+    uint32_t   Tx1Col;
+    uint32_t   TxMCol;
+    uint64_t   RxOkPhy;
+    uint64_t   RxOkBrd;
+    uint32_t   RxOkMul;
+    uint16_t   TxAbt;
+    uint16_t   TxUndrn;
+} RTL8139TallyCounters;
+
+/* Clears all tally counters */
+static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
+
+/* Writes tally counters to specified physical memory address */
+static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters);
+
+typedef struct RTL8139State {
+    PCIDevice dev;
+    uint8_t phys[8]; /* mac address */
+    uint8_t mult[8]; /* multicast mask array */
+
+    uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
+    uint32_t TxAddr[4];   /* TxAddr0 */
+    uint32_t RxBuf;       /* Receive buffer */
+    uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
+    uint32_t RxBufPtr;
+    uint32_t RxBufAddr;
+
+    uint16_t IntrStatus;
+    uint16_t IntrMask;
+
+    uint32_t TxConfig;
+    uint32_t RxConfig;
+    uint32_t RxMissed;
+
+    uint16_t CSCR;
+
+    uint8_t  Cfg9346;
+    uint8_t  Config0;
+    uint8_t  Config1;
+    uint8_t  Config3;
+    uint8_t  Config4;
+    uint8_t  Config5;
+
+    uint8_t  clock_enabled;
+    uint8_t  bChipCmdState;
+
+    uint16_t MultiIntr;
+
+    uint16_t BasicModeCtrl;
+    uint16_t BasicModeStatus;
+    uint16_t NWayAdvert;
+    uint16_t NWayLPAR;
+    uint16_t NWayExpansion;
+
+    uint16_t CpCmd;
+    uint8_t  TxThresh;
+
+    NICState *nic;
+    NICConf conf;
+    int rtl8139_mmio_io_addr;
+
+    /* C ring mode */
+    uint32_t   currTxDesc;
+
+    /* C+ mode */
+    uint32_t   cplus_enabled;
+
+    uint32_t   currCPlusRxDesc;
+    uint32_t   currCPlusTxDesc;
+
+    uint32_t   RxRingAddrLO;
+    uint32_t   RxRingAddrHI;
+
+    EEprom9346 eeprom;
+
+    uint32_t   TCTR;
+    uint32_t   TimerInt;
+    int64_t    TCTR_base;
+
+    /* Tally counters */
+    RTL8139TallyCounters tally_counters;
+
+    /* Non-persistent data */
+    uint8_t   *cplus_txbuffer;
+    int        cplus_txbuffer_len;
+    int        cplus_txbuffer_offset;
+
+    /* PCI interrupt timer */
+    QEMUTimer *timer;
+    int64_t TimerExpire;
+
+    /* Support migration to/from old versions */
+    int rtl8139_mmio_io_addr_dummy;
+} RTL8139State;
+
+static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
+
+static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
+{
+    DPRINTF("eeprom command 0x%02x\n", command);
+
+    switch (command & Chip9346_op_mask)
+    {
+        case Chip9346_op_read:
+        {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->output = eeprom->contents[eeprom->address];
+            eeprom->eedo = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_data_read;
+            DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
+                eeprom->address, eeprom->output);
+        }
+        break;
+
+        case Chip9346_op_write:
+        {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->input = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_none; /* Chip9346_data_write */
+            DPRINTF("eeprom begin write to address 0x%02x\n",
+                eeprom->address);
+        }
+        break;
+        default:
+            eeprom->mode = Chip9346_none;
+            switch (command & Chip9346_op_ext_mask)
+            {
+                case Chip9346_op_write_enable:
+                    DPRINTF("eeprom write enabled\n");
+                    break;
+                case Chip9346_op_write_all:
+                    DPRINTF("eeprom begin write all\n");
+                    break;
+                case Chip9346_op_write_disable:
+                    DPRINTF("eeprom write disabled\n");
+                    break;
+            }
+            break;
+    }
+}
+
+static void prom9346_shift_clock(EEprom9346 *eeprom)
+{
+    int bit = eeprom->eedi?1:0;
+
+    ++ eeprom->tick;
+
+    DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
+        eeprom->eedo);
+
+    switch (eeprom->mode)
+    {
+        case Chip9346_enter_command_mode:
+            if (bit)
+            {
+                eeprom->mode = Chip9346_read_command;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+                DPRINTF("eeprom: +++ synchronized, begin command read\n");
+            }
+            break;
+
+        case Chip9346_read_command:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 8)
+            {
+                prom9346_decode_command(eeprom, eeprom->input & 0xff);
+            }
+            break;
+
+        case Chip9346_data_read:
+            eeprom->eedo = (eeprom->output & 0x8000)?1:0;
+            eeprom->output <<= 1;
+            if (eeprom->tick == 16)
+            {
+#if 1
+        // the FreeBSD drivers (rl and re) don't explicitly toggle
+        // CS between reads (or does setting Cfg9346 to 0 count too?),
+        // so we need to enter wait-for-command state here
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->input = 0;
+                eeprom->tick = 0;
+
+                DPRINTF("eeprom: +++ end of read, awaiting next command\n");
+#else
+        // original behaviour
+                ++eeprom->address;
+                eeprom->address &= EEPROM_9346_ADDR_MASK;
+                eeprom->output = eeprom->contents[eeprom->address];
+                eeprom->tick = 0;
+
+                DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->output);
+#endif
+            }
+            break;
+
+        case Chip9346_data_write:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16)
+            {
+                DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->input);
+
+                eeprom->contents[eeprom->address] = eeprom->input;
+                eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        case Chip9346_data_write_all:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16)
+            {
+                int i;
+                for (i = 0; i < EEPROM_9346_SIZE; i++)
+                {
+                    eeprom->contents[i] = eeprom->input;
+                }
+                DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
+
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static int prom9346_get_wire(RTL8139State *s)
+{
+    EEprom9346 *eeprom = &s->eeprom;
+    if (!eeprom->eecs)
+        return 0;
+
+    return eeprom->eedo;
+}
+
+/* FIXME: This should be merged into/replaced by eeprom93xx.c.  */
+static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
+{
+    EEprom9346 *eeprom = &s->eeprom;
+    uint8_t old_eecs = eeprom->eecs;
+    uint8_t old_eesk = eeprom->eesk;
+
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedi = eedi;
+
+    DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
+        eeprom->eesk, eeprom->eedi, eeprom->eedo);
+
+    if (!old_eecs && eecs)
+    {
+        /* Synchronize start */
+        eeprom->tick = 0;
+        eeprom->input = 0;
+        eeprom->output = 0;
+        eeprom->mode = Chip9346_enter_command_mode;
+
+        DPRINTF("=== eeprom: begin access, enter command mode\n");
+    }
+
+    if (!eecs)
+    {
+        DPRINTF("=== eeprom: end access\n");
+        return;
+    }
+
+    if (!old_eesk && eesk)
+    {
+        /* SK front rules */
+        prom9346_shift_clock(eeprom);
+    }
+}
+
+static void rtl8139_update_irq(RTL8139State *s)
+{
+    int isr;
+    isr = (s->IntrStatus & s->IntrMask) & 0xffff;
+
+    DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
+        s->IntrMask);
+
+    qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static int compute_mcast_idx(const uint8_t *ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ POLYNOMIAL) | carry);
+        }
+    }
+    return (crc >> 26);
+}
+
+static int rtl8139_RxWrap(RTL8139State *s)
+{
+    /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
+    return (s->RxConfig & (1 << 7));
+}
+
+static int rtl8139_receiver_enabled(RTL8139State *s)
+{
+    return s->bChipCmdState & CmdRxEnb;
+}
+
+static int rtl8139_transmitter_enabled(RTL8139State *s)
+{
+    return s->bChipCmdState & CmdTxEnb;
+}
+
+static int rtl8139_cp_receiver_enabled(RTL8139State *s)
+{
+    return s->CpCmd & CPlusRxEnb;
+}
+
+static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
+{
+    return s->CpCmd & CPlusTxEnb;
+}
+
+static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
+{
+    if (s->RxBufAddr + size > s->RxBufferSize)
+    {
+        int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
+
+        /* write packet data */
+        if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
+        {
+            DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
+
+            if (size > wrapped)
+            {
+                cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
+                                           buf, size-wrapped );
+            }
+
+            /* reset buffer pointer */
+            s->RxBufAddr = 0;
+
+            cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
+                                       buf + (size-wrapped), wrapped );
+
+            s->RxBufAddr = wrapped;
+
+            return;
+        }
+    }
+
+    /* non-wrapping path or overwrapping enabled */
+    cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size );
+
+    s->RxBufAddr += size;
+}
+
+#define MIN_BUF_SIZE 60
+static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+    return low | ((target_phys_addr_t)high << 32);
+#else
+    return low;
+#endif
+}
+
+static int rtl8139_can_receive(VLANClientState *nc)
+{
+    RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int avail;
+
+    /* Receive (drop) packets if card is disabled.  */
+    if (!s->clock_enabled)
+      return 1;
+    if (!rtl8139_receiver_enabled(s))
+      return 1;
+
+    if (rtl8139_cp_receiver_enabled(s)) {
+        /* ??? Flow control not implemented in c+ mode.
+           This is a hack to work around slirp deficiencies anyway.  */
+        return 1;
+    } else {
+        avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
+                     s->RxBufferSize);
+        return (avail == 0 || avail >= 1514);
+    }
+}
+
+static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
+{
+    RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    /* size is the length of the buffer passed to the driver */
+    int size = size_;
+    const uint8_t *dot1q_buf = NULL;
+
+    uint32_t packet_header = 0;
+
+    uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+    DPRINTF(">>> received len=%d\n", size);
+
+    /* test if board clock is stopped */
+    if (!s->clock_enabled)
+    {
+        DPRINTF("stopped ==========================\n");
+        return -1;
+    }
+
+    /* first check if receiver is enabled */
+
+    if (!rtl8139_receiver_enabled(s))
+    {
+        DPRINTF("receiver disabled ================\n");
+        return -1;
+    }
+
+    /* XXX: check this */
+    if (s->RxConfig & AcceptAllPhys) {
+        /* promiscuous: receive all */
+        DPRINTF(">>> packet received in promiscuous mode\n");
+
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->RxConfig & AcceptBroadcast))
+            {
+                DPRINTF(">>> broadcast packet rejected\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxBroadcast;
+
+            DPRINTF(">>> broadcast packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkBrd;
+
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->RxConfig & AcceptMulticast))
+            {
+                DPRINTF(">>> multicast packet rejected\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            int mcast_idx = compute_mcast_idx(buf);
+
+            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+            {
+                DPRINTF(">>> multicast address mismatch\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxMulticast;
+
+            DPRINTF(">>> multicast packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkMul;
+
+        } else if (s->phys[0] == buf[0] &&
+                   s->phys[1] == buf[1] &&
+                   s->phys[2] == buf[2] &&
+                   s->phys[3] == buf[3] &&
+                   s->phys[4] == buf[4] &&
+                   s->phys[5] == buf[5]) {
+            /* match */
+            if (!(s->RxConfig & AcceptMyPhys))
+            {
+                DPRINTF(">>> rejecting physical address matching packet\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxPhysical;
+
+            DPRINTF(">>> physical address matching packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkPhy;
+
+        } else {
+
+            DPRINTF(">>> unknown packet\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+
+            return size;
+        }
+    }
+
+    /* if too small buffer, then expand it
+     * Include some tailroom in case a vlan tag is later removed. */
+    if (size < MIN_BUF_SIZE + VLAN_HLEN) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
+        buf = buf1;
+        if (size < MIN_BUF_SIZE) {
+            size = MIN_BUF_SIZE;
+        }
+    }
+
+    if (rtl8139_cp_receiver_enabled(s))
+    {
+        DPRINTF("in C+ Rx mode ================\n");
+
+        /* begin C+ receiver mode */
+
+/* w0 ownership flag */
+#define CP_RX_OWN (1<<31)
+/* w0 end of ring flag */
+#define CP_RX_EOR (1<<30)
+/* w0 bits 0...12 : buffer size */
+#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
+/* w1 tag available flag */
+#define CP_RX_TAVA (1<<16)
+/* w1 bits 0...15 : VLAN tag */
+#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
+/* w2 low  32bit of Rx buffer ptr */
+/* w3 high 32bit of Rx buffer ptr */
+
+        int descriptor = s->currCPlusRxDesc;
+        target_phys_addr_t cplus_rx_ring_desc;
+
+        cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
+        cplus_rx_ring_desc += 16 * descriptor;
+
+        DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
+            "%08x %08x = "TARGET_FMT_plx"\n", descriptor, s->RxRingAddrHI,
+            s->RxRingAddrLO, cplus_rx_ring_desc);
+
+        uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
+
+        cpu_physical_memory_read(cplus_rx_ring_desc,    (uint8_t *)&val, 4);
+        rxdw0 = le32_to_cpu(val);
+        cpu_physical_memory_read(cplus_rx_ring_desc+4,  (uint8_t *)&val, 4);
+        rxdw1 = le32_to_cpu(val);
+        cpu_physical_memory_read(cplus_rx_ring_desc+8,  (uint8_t *)&val, 4);
+        rxbufLO = le32_to_cpu(val);
+        cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
+        rxbufHI = le32_to_cpu(val);
+
+        DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
+            descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
+
+        if (!(rxdw0 & CP_RX_OWN))
+        {
+            DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
+                descriptor);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+            ++s->tally_counters.MissPkt;
+
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
+
+        /* write VLAN info to descriptor variables. */
+        if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
+                &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
+            dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
+            size -= VLAN_HLEN;
+            /* if too small buffer, use the tailroom added duing expansion */
+            if (size < MIN_BUF_SIZE) {
+                size = MIN_BUF_SIZE;
+            }
+
+            rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
+            /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+            rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+                &dot1q_buf[ETHER_TYPE_LEN]);
+
+            DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
+                be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN]));
+        } else {
+            /* reset VLAN tag flag */
+            rxdw1 &= ~CP_RX_TAVA;
+        }
+
+        /* TODO: scatter the packet over available receive ring descriptors space */
+
+        if (size+4 > rx_space)
+        {
+            DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
+                descriptor, rx_space, size);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+            ++s->tally_counters.MissPkt;
+
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
+
+        /* receive/copy to target memory */
+        if (dot1q_buf) {
+            cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
+            cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN,
+                buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
+                size - 2 * ETHER_ADDR_LEN);
+        } else {
+            cpu_physical_memory_write(rx_addr, buf, size);
+        }
+
+        if (s->CpCmd & CPlusRxChkSum)
+        {
+            /* do some packet checksumming */
+        }
+
+        /* write checksum */
+        val = cpu_to_le32(crc32(0, buf, size_));
+        cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4);
+
+/* first segment of received packet flag */
+#define CP_RX_STATUS_FS (1<<29)
+/* last segment of received packet flag */
+#define CP_RX_STATUS_LS (1<<28)
+/* multicast packet flag */
+#define CP_RX_STATUS_MAR (1<<26)
+/* physical-matching packet flag */
+#define CP_RX_STATUS_PAM (1<<25)
+/* broadcast packet flag */
+#define CP_RX_STATUS_BAR (1<<24)
+/* runt packet flag */
+#define CP_RX_STATUS_RUNT (1<<19)
+/* crc error flag */
+#define CP_RX_STATUS_CRC (1<<18)
+/* IP checksum error flag */
+#define CP_RX_STATUS_IPF (1<<15)
+/* UDP checksum error flag */
+#define CP_RX_STATUS_UDPF (1<<14)
+/* TCP checksum error flag */
+#define CP_RX_STATUS_TCPF (1<<13)
+
+        /* transfer ownership to target */
+        rxdw0 &= ~CP_RX_OWN;
+
+        /* set first segment bit */
+        rxdw0 |= CP_RX_STATUS_FS;
+
+        /* set last segment bit */
+        rxdw0 |= CP_RX_STATUS_LS;
+
+        /* set received packet type flags */
+        if (packet_header & RxBroadcast)
+            rxdw0 |= CP_RX_STATUS_BAR;
+        if (packet_header & RxMulticast)
+            rxdw0 |= CP_RX_STATUS_MAR;
+        if (packet_header & RxPhysical)
+            rxdw0 |= CP_RX_STATUS_PAM;
+
+        /* set received size */
+        rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
+        rxdw0 |= (size+4);
+
+        /* update ring data */
+        val = cpu_to_le32(rxdw0);
+        cpu_physical_memory_write(cplus_rx_ring_desc,    (uint8_t *)&val, 4);
+        val = cpu_to_le32(rxdw1);
+        cpu_physical_memory_write(cplus_rx_ring_desc+4,  (uint8_t *)&val, 4);
+
+        /* update tally counter */
+        ++s->tally_counters.RxOk;
+
+        /* seek to next Rx descriptor */
+        if (rxdw0 & CP_RX_EOR)
+        {
+            s->currCPlusRxDesc = 0;
+        }
+        else
+        {
+            ++s->currCPlusRxDesc;
+        }
+
+        DPRINTF("done C+ Rx mode ----------------\n");
+
+    }
+    else
+    {
+        DPRINTF("in ring Rx mode ================\n");
+
+        /* begin ring receiver mode */
+        int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
+
+        /* if receiver buffer is empty then avail == 0 */
+
+        if (avail != 0 && size + 8 >= avail)
+        {
+            DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
+                "read 0x%04x === available 0x%04x need 0x%04x\n",
+                s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        packet_header |= RxStatusOK;
+
+        packet_header |= (((size+4) << 16) & 0xffff0000);
+
+        /* write header */
+        uint32_t val = cpu_to_le32(packet_header);
+
+        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
+
+        rtl8139_write_buffer(s, buf, size);
+
+        /* write checksum */
+        val = cpu_to_le32(crc32(0, buf, size));
+        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
+
+        /* correct buffer write pointer */
+        s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
+
+        /* now we can signal we have received something */
+
+        DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
+            s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
+    }
+
+    s->IntrStatus |= RxOK;
+
+    if (do_interrupt)
+    {
+        rtl8139_update_irq(s);
+    }
+
+    return size_;
+}
+
+static ssize_t rtl8139_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    return rtl8139_do_receive(nc, buf, size, 1);
+}
+
+static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
+{
+    s->RxBufferSize = bufferSize;
+    s->RxBufPtr  = 0;
+    s->RxBufAddr = 0;
+}
+
+static void rtl8139_reset(DeviceState *d)
+{
+    RTL8139State *s = container_of(d, RTL8139State, dev.qdev);
+    int i;
+
+    /* restore MAC address */
+    memcpy(s->phys, s->conf.macaddr.a, 6);
+
+    /* reset interrupt mask */
+    s->IntrStatus = 0;
+    s->IntrMask = 0;
+
+    rtl8139_update_irq(s);
+
+    /* mark all status registers as owned by host */
+    for (i = 0; i < 4; ++i)
+    {
+        s->TxStatus[i] = TxHostOwns;
+    }
+
+    s->currTxDesc = 0;
+    s->currCPlusRxDesc = 0;
+    s->currCPlusTxDesc = 0;
+
+    s->RxRingAddrLO = 0;
+    s->RxRingAddrHI = 0;
+
+    s->RxBuf = 0;
+
+    rtl8139_reset_rxring(s, 8192);
+
+    /* ACK the reset */
+    s->TxConfig = 0;
+
+#if 0
+//    s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139  HasHltClk
+    s->clock_enabled = 0;
+#else
+    s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
+    s->clock_enabled = 1;
+#endif
+
+    s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
+
+    /* set initial state data */
+    s->Config0 = 0x0; /* No boot ROM */
+    s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
+    s->Config3 = 0x1; /* fast back-to-back compatible */
+    s->Config5 = 0x0;
+
+    s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+
+    s->CpCmd   = 0x0; /* reset C+ mode */
+    s->cplus_enabled = 0;
+
+
+//    s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
+//    s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
+    s->BasicModeCtrl = 0x1000; // autonegotiation
+
+    s->BasicModeStatus  = 0x7809;
+    //s->BasicModeStatus |= 0x0040; /* UTP medium */
+    s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
+    s->BasicModeStatus |= 0x0004; /* link is up */
+
+    s->NWayAdvert    = 0x05e1; /* all modes, full duplex */
+    s->NWayLPAR      = 0x05e1; /* all modes, full duplex */
+    s->NWayExpansion = 0x0001; /* autonegotiation supported */
+
+    /* also reset timer and disable timer interrupt */
+    s->TCTR = 0;
+    s->TimerInt = 0;
+    s->TCTR_base = 0;
+
+    /* reset tally counters */
+    RTL8139TallyCounters_clear(&s->tally_counters);
+}
+
+static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
+{
+    counters->TxOk = 0;
+    counters->RxOk = 0;
+    counters->TxERR = 0;
+    counters->RxERR = 0;
+    counters->MissPkt = 0;
+    counters->FAE = 0;
+    counters->Tx1Col = 0;
+    counters->TxMCol = 0;
+    counters->RxOkPhy = 0;
+    counters->RxOkBrd = 0;
+    counters->RxOkMul = 0;
+    counters->TxAbt = 0;
+    counters->TxUndrn = 0;
+}
+
+static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters)
+{
+    uint16_t val16;
+    uint32_t val32;
+    uint64_t val64;
+
+    val64 = cpu_to_le64(tally_counters->TxOk);
+    cpu_physical_memory_write(tc_addr + 0,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOk);
+    cpu_physical_memory_write(tc_addr + 8,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->TxERR);
+    cpu_physical_memory_write(tc_addr + 16,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxERR);
+    cpu_physical_memory_write(tc_addr + 24,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->MissPkt);
+    cpu_physical_memory_write(tc_addr + 28,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->FAE);
+    cpu_physical_memory_write(tc_addr + 30,    (uint8_t *)&val16, 2);
+
+    val32 = cpu_to_le32(tally_counters->Tx1Col);
+    cpu_physical_memory_write(tc_addr + 32,    (uint8_t *)&val32, 4);
+
+    val32 = cpu_to_le32(tally_counters->TxMCol);
+    cpu_physical_memory_write(tc_addr + 36,    (uint8_t *)&val32, 4);
+
+    val64 = cpu_to_le64(tally_counters->RxOkPhy);
+    cpu_physical_memory_write(tc_addr + 40,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOkBrd);
+    cpu_physical_memory_write(tc_addr + 48,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxOkMul);
+    cpu_physical_memory_write(tc_addr + 56,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->TxAbt);
+    cpu_physical_memory_write(tc_addr + 60,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->TxUndrn);
+    cpu_physical_memory_write(tc_addr + 62,    (uint8_t *)&val16, 2);
+}
+
+/* Loads values of tally counters from VM state file */
+
+static const VMStateDescription vmstate_tally_counters = {
+    .name = "tally_counters",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(TxOk, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOk, RTL8139TallyCounters),
+        VMSTATE_UINT64(TxERR, RTL8139TallyCounters),
+        VMSTATE_UINT32(RxERR, RTL8139TallyCounters),
+        VMSTATE_UINT16(MissPkt, RTL8139TallyCounters),
+        VMSTATE_UINT16(FAE, RTL8139TallyCounters),
+        VMSTATE_UINT32(Tx1Col, RTL8139TallyCounters),
+        VMSTATE_UINT32(TxMCol, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOkPhy, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOkBrd, RTL8139TallyCounters),
+        VMSTATE_UINT16(TxAbt, RTL8139TallyCounters),
+        VMSTATE_UINT16(TxUndrn, RTL8139TallyCounters),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("ChipCmd write val=0x%08x\n", val);
+
+    if (val & CmdReset)
+    {
+        DPRINTF("ChipCmd reset\n");
+        rtl8139_reset(&s->dev.qdev);
+    }
+    if (val & CmdRxEnb)
+    {
+        DPRINTF("ChipCmd enable receiver\n");
+
+        s->currCPlusRxDesc = 0;
+    }
+    if (val & CmdTxEnb)
+    {
+        DPRINTF("ChipCmd enable transmitter\n");
+
+        s->currCPlusTxDesc = 0;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xe3, s->bChipCmdState);
+
+    /* Deassert reset pin before next read */
+    val &= ~CmdReset;
+
+    s->bChipCmdState = val;
+}
+
+static int rtl8139_RxBufferEmpty(RTL8139State *s)
+{
+    int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
+
+    if (unread != 0)
+    {
+        DPRINTF("receiver buffer data available 0x%04x\n", unread);
+        return 0;
+    }
+
+    DPRINTF("receiver buffer is empty\n");
+
+    return 1;
+}
+
+static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
+{
+    uint32_t ret = s->bChipCmdState;
+
+    if (rtl8139_RxBufferEmpty(s))
+        ret |= RxBufEmpty;
+
+    DPRINTF("ChipCmd read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("C+ command register write(w) val=0x%04x\n", val);
+
+    s->cplus_enabled = 1;
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xff84, s->CpCmd);
+
+    s->CpCmd = val;
+}
+
+static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
+{
+    uint32_t ret = s->CpCmd;
+
+    DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
+}
+
+static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
+{
+    uint32_t ret = 0;
+
+    DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static int rtl8139_config_writable(RTL8139State *s)
+{
+    if (s->Cfg9346 & Cfg9346_Unlock)
+    {
+        return 1;
+    }
+
+    DPRINTF("Configuration registers are write-protected\n");
+
+    return 0;
+}
+
+static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    uint32_t mask = 0x4cff;
+
+    if (1 || !rtl8139_config_writable(s))
+    {
+        /* Speed setting and autonegotiation enable bits are read-only */
+        mask |= 0x3000;
+        /* Duplex mode setting is read-only */
+        mask |= 0x0100;
+    }
+
+    val = SET_MASKED(val, mask, s->BasicModeCtrl);
+
+    s->BasicModeCtrl = val;
+}
+
+static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
+{
+    uint32_t ret = s->BasicModeCtrl;
+
+    DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
+
+    s->BasicModeStatus = val;
+}
+
+static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
+{
+    uint32_t ret = s->BasicModeStatus;
+
+    DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Cfg9346 write val=0x%02x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x31, s->Cfg9346);
+
+    uint32_t opmode = val & 0xc0;
+    uint32_t eeprom_val = val & 0xf;
+
+    if (opmode == 0x80) {
+        /* eeprom access */
+        int eecs = (eeprom_val & 0x08)?1:0;
+        int eesk = (eeprom_val & 0x04)?1:0;
+        int eedi = (eeprom_val & 0x02)?1:0;
+        prom9346_set_wire(s, eecs, eesk, eedi);
+    } else if (opmode == 0x40) {
+        /* Reset.  */
+        val = 0;
+        rtl8139_reset(&s->dev.qdev);
+    }
+
+    s->Cfg9346 = val;
+}
+
+static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
+{
+    uint32_t ret = s->Cfg9346;
+
+    uint32_t opmode = ret & 0xc0;
+
+    if (opmode == 0x80)
+    {
+        /* eeprom access */
+        int eedo = prom9346_get_wire(s);
+        if (eedo)
+        {
+            ret |=  0x01;
+        }
+        else
+        {
+            ret &= ~0x01;
+        }
+    }
+
+    DPRINTF("Cfg9346 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config0 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf8, s->Config0);
+
+    s->Config0 = val;
+}
+
+static uint32_t rtl8139_Config0_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config0;
+
+    DPRINTF("Config0 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config1 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xC, s->Config1);
+
+    s->Config1 = val;
+}
+
+static uint32_t rtl8139_Config1_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config1;
+
+    DPRINTF("Config1 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config3 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x8F, s->Config3);
+
+    s->Config3 = val;
+}
+
+static uint32_t rtl8139_Config3_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config3;
+
+    DPRINTF("Config3 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config4 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x0a, s->Config4);
+
+    s->Config4 = val;
+}
+
+static uint32_t rtl8139_Config4_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config4;
+
+    DPRINTF("Config4 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config5 write val=0x%02x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x80, s->Config5);
+
+    s->Config5 = val;
+}
+
+static uint32_t rtl8139_Config5_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config5;
+
+    DPRINTF("Config5 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
+        return;
+    }
+
+    DPRINTF("TxConfig write val=0x%08x\n", val);
+
+    val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
+
+    s->TxConfig = val;
+}
+
+static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
+
+    uint32_t tc = s->TxConfig;
+    tc &= 0xFFFFFF00;
+    tc |= (val & 0x000000FF);
+    rtl8139_TxConfig_write(s, tc);
+}
+
+static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
+{
+    uint32_t ret = s->TxConfig;
+
+    DPRINTF("TxConfig read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxConfig write val=0x%08x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
+
+    s->RxConfig = val;
+
+    /* reset buffer size and read/write pointers */
+    rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
+
+    DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
+}
+
+static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
+{
+    uint32_t ret = s->RxConfig;
+
+    DPRINTF("RxConfig read val=0x%08x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
+    int do_interrupt, const uint8_t *dot1q_buf)
+{
+    struct iovec *iov = NULL;
+
+    if (!size)
+    {
+        DPRINTF("+++ empty ethernet frame\n");
+        return;
+    }
+
+    if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
+        iov = (struct iovec[3]) {
+            { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+            { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
+            { .iov_base = buf + ETHER_ADDR_LEN * 2,
+                .iov_len = size - ETHER_ADDR_LEN * 2 },
+        };
+    }
+
+    if (TxLoopBack == (s->TxConfig & TxLoopBack))
+    {
+        size_t buf2_size;
+        uint8_t *buf2;
+
+        if (iov) {
+            buf2_size = iov_size(iov, 3);
+            buf2 = qemu_malloc(buf2_size);
+            iov_to_buf(iov, 3, buf2, 0, buf2_size);
+            buf = buf2;
+        }
+
+        DPRINTF("+++ transmit loopback mode\n");
+        rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt);
+
+        if (iov) {
+            qemu_free(buf2);
+        }
+    }
+    else
+    {
+        if (iov) {
+            qemu_sendv_packet(&s->nic->nc, iov, 3);
+        } else {
+            qemu_send_packet(&s->nic->nc, buf, size);
+        }
+    }
+}
+
+static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
+            "disabled\n", descriptor);
+        return 0;
+    }
+
+    if (s->TxStatus[descriptor] & TxHostOwns)
+    {
+        DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
+            "(%08x)\n", descriptor, s->TxStatus[descriptor]);
+        return 0;
+    }
+
+    DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
+
+    int txsize = s->TxStatus[descriptor] & 0x1fff;
+    uint8_t txbuffer[0x2000];
+
+    DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
+        txsize, s->TxAddr[descriptor]);
+
+    cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
+
+    /* Mark descriptor as transferred */
+    s->TxStatus[descriptor] |= TxHostOwns;
+    s->TxStatus[descriptor] |= TxStatOK;
+
+    rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
+
+    DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
+        descriptor);
+
+    /* update interrupt */
+    s->IntrStatus |= TxOK;
+    rtl8139_update_irq(s);
+
+    return 1;
+}
+
+/* structures and macros for task offloading */
+typedef struct ip_header
+{
+    uint8_t  ip_ver_len;    /* version and header length */
+    uint8_t  ip_tos;        /* type of service */
+    uint16_t ip_len;        /* total length */
+    uint16_t ip_id;         /* identification */
+    uint16_t ip_off;        /* fragment offset field */
+    uint8_t  ip_ttl;        /* time to live */
+    uint8_t  ip_p;          /* protocol */
+    uint16_t ip_sum;        /* checksum */
+    uint32_t ip_src,ip_dst; /* source and dest address */
+} ip_header;
+
+#define IP_HEADER_VERSION_4 4
+#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
+#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
+
+typedef struct tcp_header
+{
+    uint16_t th_sport;		/* source port */
+    uint16_t th_dport;		/* destination port */
+    uint32_t th_seq;			/* sequence number */
+    uint32_t th_ack;			/* acknowledgement number */
+    uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
+    uint16_t th_win;			/* window */
+    uint16_t th_sum;			/* checksum */
+    uint16_t th_urp;			/* urgent pointer */
+} tcp_header;
+
+typedef struct udp_header
+{
+    uint16_t uh_sport; /* source port */
+    uint16_t uh_dport; /* destination port */
+    uint16_t uh_ulen;  /* udp length */
+    uint16_t uh_sum;   /* udp checksum */
+} udp_header;
+
+typedef struct ip_pseudo_header
+{
+    uint32_t ip_src;
+    uint32_t ip_dst;
+    uint8_t  zeros;
+    uint8_t  ip_proto;
+    uint16_t ip_payload;
+} ip_pseudo_header;
+
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
+#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
+#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
+
+#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
+
+#define TCP_FLAG_FIN  0x01
+#define TCP_FLAG_PUSH 0x08
+
+/* produces ones' complement sum of data */
+static uint16_t ones_complement_sum(uint8_t *data, size_t len)
+{
+    uint32_t result = 0;
+
+    for (; len > 1; data+=2, len-=2)
+    {
+        result += *(uint16_t*)data;
+    }
+
+    /* add the remainder byte */
+    if (len)
+    {
+        uint8_t odd[2] = {*data, 0};
+        result += *(uint16_t*)odd;
+    }
+
+    while (result>>16)
+        result = (result & 0xffff) + (result >> 16);
+
+    return result;
+}
+
+static uint16_t ip_checksum(void *data, size_t len)
+{
+    return ~ones_complement_sum((uint8_t*)data, len);
+}
+
+static int rtl8139_cplus_transmit_one(RTL8139State *s)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("+++ C+ mode: transmitter disabled\n");
+        return 0;
+    }
+
+    if (!rtl8139_cp_transmitter_enabled(s))
+    {
+        DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
+        return 0 ;
+    }
+
+    int descriptor = s->currCPlusTxDesc;
+
+    target_phys_addr_t cplus_tx_ring_desc =
+        rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
+
+    /* Normal priority ring */
+    cplus_tx_ring_desc += 16 * descriptor;
+
+    DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
+        "%08x0x%08x = 0x"TARGET_FMT_plx"\n", descriptor, s->TxAddr[1],
+        s->TxAddr[0], cplus_tx_ring_desc);
+
+    uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
+
+    cpu_physical_memory_read(cplus_tx_ring_desc,    (uint8_t *)&val, 4);
+    txdw0 = le32_to_cpu(val);
+    cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)&val, 4);
+    txdw1 = le32_to_cpu(val);
+    cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)&val, 4);
+    txbufLO = le32_to_cpu(val);
+    cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
+    txbufHI = le32_to_cpu(val);
+
+    DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
+        txdw0, txdw1, txbufLO, txbufHI);
+
+/* w0 ownership flag */
+#define CP_TX_OWN (1<<31)
+/* w0 end of ring flag */
+#define CP_TX_EOR (1<<30)
+/* first segment of received packet flag */
+#define CP_TX_FS (1<<29)
+/* last segment of received packet flag */
+#define CP_TX_LS (1<<28)
+/* large send packet flag */
+#define CP_TX_LGSEN (1<<27)
+/* large send MSS mask, bits 16...25 */
+#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
+
+/* IP checksum offload flag */
+#define CP_TX_IPCS (1<<18)
+/* UDP checksum offload flag */
+#define CP_TX_UDPCS (1<<17)
+/* TCP checksum offload flag */
+#define CP_TX_TCPCS (1<<16)
+
+/* w0 bits 0...15 : buffer size */
+#define CP_TX_BUFFER_SIZE (1<<16)
+#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
+/* w1 add tag flag */
+#define CP_TX_TAGC (1<<17)
+/* w1 bits 0...15 : VLAN tag (big endian) */
+#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
+/* w2 low  32bit of Rx buffer ptr */
+/* w3 high 32bit of Rx buffer ptr */
+
+/* set after transmission */
+/* FIFO underrun flag */
+#define CP_TX_STATUS_UNF (1<<25)
+/* transmit error summary flag, valid if set any of three below */
+#define CP_TX_STATUS_TES (1<<23)
+/* out-of-window collision flag */
+#define CP_TX_STATUS_OWC (1<<22)
+/* link failure flag */
+#define CP_TX_STATUS_LNKF (1<<21)
+/* excessive collisions flag */
+#define CP_TX_STATUS_EXC (1<<20)
+
+    if (!(txdw0 & CP_TX_OWN))
+    {
+        DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
+        return 0 ;
+    }
+
+    DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
+
+    if (txdw0 & CP_TX_FS)
+    {
+        DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
+            "descriptor\n", descriptor);
+
+        /* reset internal buffer offset */
+        s->cplus_txbuffer_offset = 0;
+    }
+
+    int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
+    target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
+
+    /* make sure we have enough space to assemble the packet */
+    if (!s->cplus_txbuffer)
+    {
+        s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
+        s->cplus_txbuffer = qemu_malloc(s->cplus_txbuffer_len);
+        s->cplus_txbuffer_offset = 0;
+
+        DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
+            s->cplus_txbuffer_len);
+    }
+
+    while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+    {
+        s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
+        s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+
+        DPRINTF("+++ C+ mode transmission buffer space changed to %d\n",
+            s->cplus_txbuffer_len);
+    }
+
+    if (!s->cplus_txbuffer)
+    {
+        /* out of memory */
+
+        DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n",
+            s->cplus_txbuffer_len);
+
+        /* update tally counter */
+        ++s->tally_counters.TxERR;
+        ++s->tally_counters.TxAbt;
+
+        return 0;
+    }
+
+    /* append more data to the packet */
+
+    DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
+        TARGET_FMT_plx" to offset %d\n", txsize, tx_addr,
+        s->cplus_txbuffer_offset);
+
+    cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
+    s->cplus_txbuffer_offset += txsize;
+
+    /* seek to next Rx descriptor */
+    if (txdw0 & CP_TX_EOR)
+    {
+        s->currCPlusTxDesc = 0;
+    }
+    else
+    {
+        ++s->currCPlusTxDesc;
+        if (s->currCPlusTxDesc >= 64)
+            s->currCPlusTxDesc = 0;
+    }
+
+    /* transfer ownership to target */
+    txdw0 &= ~CP_RX_OWN;
+
+    /* reset error indicator bits */
+    txdw0 &= ~CP_TX_STATUS_UNF;
+    txdw0 &= ~CP_TX_STATUS_TES;
+    txdw0 &= ~CP_TX_STATUS_OWC;
+    txdw0 &= ~CP_TX_STATUS_LNKF;
+    txdw0 &= ~CP_TX_STATUS_EXC;
+
+    /* update ring data */
+    val = cpu_to_le32(txdw0);
+    cpu_physical_memory_write(cplus_tx_ring_desc,    (uint8_t *)&val, 4);
+
+    /* Now decide if descriptor being processed is holding the last segment of packet */
+    if (txdw0 & CP_TX_LS)
+    {
+        uint8_t dot1q_buffer_space[VLAN_HLEN];
+        uint16_t *dot1q_buffer;
+
+        DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
+            descriptor);
+
+        /* can transfer fully assembled packet */
+
+        uint8_t *saved_buffer  = s->cplus_txbuffer;
+        int      saved_size    = s->cplus_txbuffer_offset;
+        int      saved_buffer_len = s->cplus_txbuffer_len;
+
+        /* create vlan tag */
+        if (txdw1 & CP_TX_TAGC) {
+            /* the vlan tag is in BE byte order in the descriptor
+             * BE + le_to_cpu() + ~swap()~ = cpu */
+            DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
+                bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
+
+            dot1q_buffer = (uint16_t *) dot1q_buffer_space;
+            dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
+            /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
+            dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
+        } else {
+            dot1q_buffer = NULL;
+        }
+
+        /* reset the card space to protect from recursive call */
+        s->cplus_txbuffer = NULL;
+        s->cplus_txbuffer_offset = 0;
+        s->cplus_txbuffer_len = 0;
+
+        if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
+        {
+            DPRINTF("+++ C+ mode offloaded task checksum\n");
+
+            /* ip packet header */
+            ip_header *ip = NULL;
+            int hlen = 0;
+            uint8_t  ip_protocol = 0;
+            uint16_t ip_data_len = 0;
+
+            uint8_t *eth_payload_data = NULL;
+            size_t   eth_payload_len  = 0;
+
+            int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
+            if (proto == ETH_P_IP)
+            {
+                DPRINTF("+++ C+ mode has IP packet\n");
+
+                /* not aligned */
+                eth_payload_data = saved_buffer + ETH_HLEN;
+                eth_payload_len  = saved_size   - ETH_HLEN;
+
+                ip = (ip_header*)eth_payload_data;
+
+                if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
+                    DPRINTF("+++ C+ mode packet has bad IP version %d "
+                        "expected %d\n", IP_HEADER_VERSION(ip),
+                        IP_HEADER_VERSION_4);
+                    ip = NULL;
+                } else {
+                    hlen = IP_HEADER_LENGTH(ip);
+                    ip_protocol = ip->ip_p;
+                    ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
+                }
+            }
+
+            if (ip)
+            {
+                if (txdw0 & CP_TX_IPCS)
+                {
+                    DPRINTF("+++ C+ mode need IP checksum\n");
+
+                    if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
+                        /* bad packet header len */
+                        /* or packet too short */
+                    }
+                    else
+                    {
+                        ip->ip_sum = 0;
+                        ip->ip_sum = ip_checksum(ip, hlen);
+                        DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
+                            hlen, ip->ip_sum);
+                    }
+                }
+
+                if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
+                {
+                    int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
+
+                    DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
+                        "frame data %d specified MSS=%d\n", ETH_MTU,
+                        ip_data_len, saved_size - ETH_HLEN, large_send_mss);
+
+                    int tcp_send_offset = 0;
+                    int send_count = 0;
+
+                    /* maximum IP header length is 60 bytes */
+                    uint8_t saved_ip_header[60];
+
+                    /* save IP header template; data area is used in tcp checksum calculation */
+                    memcpy(saved_ip_header, eth_payload_data, hlen);
+
+                    /* a placeholder for checksum calculation routine in tcp case */
+                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
+                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
+
+                    /* pointer to TCP header */
+                    tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
+
+                    int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
+
+                    /* ETH_MTU = ip header len + tcp header len + payload */
+                    int tcp_data_len = ip_data_len - tcp_hlen;
+                    int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
+
+                    DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
+                        "data len %d TCP chunk size %d\n", ip_data_len,
+                        tcp_hlen, tcp_data_len, tcp_chunk_size);
+
+                    /* note the cycle below overwrites IP header data,
+                       but restores it from saved_ip_header before sending packet */
+
+                    int is_last_frame = 0;
+
+                    for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
+                    {
+                        uint16_t chunk_size = tcp_chunk_size;
+
+                        /* check if this is the last frame */
+                        if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
+                        {
+                            is_last_frame = 1;
+                            chunk_size = tcp_data_len - tcp_send_offset;
+                        }
+
+                        DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
+                            be32_to_cpu(p_tcp_hdr->th_seq));
+
+                        /* add 4 TCP pseudoheader fields */
+                        /* copy IP source and destination fields */
+                        memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+                        DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
+                            "packet with %d bytes data\n", tcp_hlen +
+                            chunk_size);
+
+                        if (tcp_send_offset)
+                        {
+                            memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
+                        }
+
+                        /* keep PUSH and FIN flags only for the last frame */
+                        if (!is_last_frame)
+                        {
+                            TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
+                        }
+
+                        /* recalculate TCP checksum */
+                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_tcpip_hdr->zeros      = 0;
+                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
+                        p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
+
+                        p_tcp_hdr->th_sum = 0;
+
+                        int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
+                        DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
+                            tcp_checksum);
+
+                        p_tcp_hdr->th_sum = tcp_checksum;
+
+                        /* restore IP header */
+                        memcpy(eth_payload_data, saved_ip_header, hlen);
+
+                        /* set IP data length and recalculate IP checksum */
+                        ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
+
+                        /* increment IP id for subsequent frames */
+                        ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
+
+                        ip->ip_sum = 0;
+                        ip->ip_sum = ip_checksum(eth_payload_data, hlen);
+                        DPRINTF("+++ C+ mode TSO IP header len=%d "
+                            "checksum=%04x\n", hlen, ip->ip_sum);
+
+                        int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
+                        DPRINTF("+++ C+ mode TSO transferring packet size "
+                            "%d\n", tso_send_size);
+                        rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
+                            0, (uint8_t *) dot1q_buffer);
+
+                        /* add transferred count to TCP sequence number */
+                        p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
+                        ++send_count;
+                    }
+
+                    /* Stop sending this frame */
+                    saved_size = 0;
+                }
+                else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
+                {
+                    DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
+
+                    /* maximum IP header length is 60 bytes */
+                    uint8_t saved_ip_header[60];
+                    memcpy(saved_ip_header, eth_payload_data, hlen);
+
+                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
+                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
+
+                    /* add 4 TCP pseudoheader fields */
+                    /* copy IP source and destination fields */
+                    memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+                    if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
+                    {
+                        DPRINTF("+++ C+ mode calculating TCP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
+
+                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_tcpip_hdr->zeros      = 0;
+                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
+                        p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+                        tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
+
+                        p_tcp_hdr->th_sum = 0;
+
+                        int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+                        DPRINTF("+++ C+ mode TCP checksum %04x\n",
+                            tcp_checksum);
+
+                        p_tcp_hdr->th_sum = tcp_checksum;
+                    }
+                    else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
+                    {
+                        DPRINTF("+++ C+ mode calculating UDP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
+
+                        ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_udpip_hdr->zeros      = 0;
+                        p_udpip_hdr->ip_proto   = IP_PROTO_UDP;
+                        p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+                        udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
+
+                        p_udp_hdr->uh_sum = 0;
+
+                        int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+                        DPRINTF("+++ C+ mode UDP checksum %04x\n",
+                            udp_checksum);
+
+                        p_udp_hdr->uh_sum = udp_checksum;
+                    }
+
+                    /* restore IP header */
+                    memcpy(eth_payload_data, saved_ip_header, hlen);
+                }
+            }
+        }
+
+        /* update tally counter */
+        ++s->tally_counters.TxOk;
+
+        DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
+
+        rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
+            (uint8_t *) dot1q_buffer);
+
+        /* restore card space if there was no recursion and reset offset */
+        if (!s->cplus_txbuffer)
+        {
+            s->cplus_txbuffer        = saved_buffer;
+            s->cplus_txbuffer_len    = saved_buffer_len;
+            s->cplus_txbuffer_offset = 0;
+        }
+        else
+        {
+            qemu_free(saved_buffer);
+        }
+    }
+    else
+    {
+        DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
+    }
+
+    return 1;
+}
+
+static void rtl8139_cplus_transmit(RTL8139State *s)
+{
+    int txcount = 0;
+
+    while (rtl8139_cplus_transmit_one(s))
+    {
+        ++txcount;
+    }
+
+    /* Mark transfer completed */
+    if (!txcount)
+    {
+        DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
+            s->currCPlusTxDesc);
+    }
+    else
+    {
+        /* update interrupt status */
+        s->IntrStatus |= TxOK;
+        rtl8139_update_irq(s);
+    }
+}
+
+static void rtl8139_transmit(RTL8139State *s)
+{
+    int descriptor = s->currTxDesc, txcount = 0;
+
+    /*while*/
+    if (rtl8139_transmit_one(s, descriptor))
+    {
+        ++s->currTxDesc;
+        s->currTxDesc %= 4;
+        ++txcount;
+    }
+
+    /* Mark transfer completed */
+    if (!txcount)
+    {
+        DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
+            s->currTxDesc);
+    }
+}
+
+static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
+{
+
+    int descriptor = txRegOffset/4;
+
+    /* handle C+ transmit mode register configuration */
+
+    if (s->cplus_enabled)
+    {
+        DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
+            "descriptor=%d\n", txRegOffset, val, descriptor);
+
+        /* handle Dump Tally Counters command */
+        s->TxStatus[descriptor] = val;
+
+        if (descriptor == 0 && (val & 0x8))
+        {
+            target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
+
+            /* dump tally counters to specified memory location */
+            RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters);
+
+            /* mark dump completed */
+            s->TxStatus[0] &= ~0x8;
+        }
+
+        return;
+    }
+
+    DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
+        txRegOffset, val, descriptor);
+
+    /* mask only reserved bits */
+    val &= ~0xff00c000; /* these bits are reset on write */
+    val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
+
+    s->TxStatus[descriptor] = val;
+
+    /* attempt to start transmission */
+    rtl8139_transmit(s);
+}
+
+static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset)
+{
+    uint32_t ret = s->TxStatus[txRegOffset/4];
+
+    DPRINTF("TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret);
+
+    return ret;
+}
+
+static uint16_t rtl8139_TSAD_read(RTL8139State *s)
+{
+    uint16_t ret = 0;
+
+    /* Simulate TSAD, it is read only anyway */
+
+    ret = ((s->TxStatus[3] & TxStatOK  )?TSAD_TOK3:0)
+         |((s->TxStatus[2] & TxStatOK  )?TSAD_TOK2:0)
+         |((s->TxStatus[1] & TxStatOK  )?TSAD_TOK1:0)
+         |((s->TxStatus[0] & TxStatOK  )?TSAD_TOK0:0)
+
+         |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
+         |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
+         |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
+         |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
+
+         |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
+         |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
+         |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
+         |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
+
+         |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
+         |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
+         |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
+         |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
+
+
+    DPRINTF("TSAD read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static uint16_t rtl8139_CSCR_read(RTL8139State *s)
+{
+    uint16_t ret = s->CSCR;
+
+    DPRINTF("CSCR read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
+{
+    DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
+
+    s->TxAddr[txAddrOffset/4] = val;
+}
+
+static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
+{
+    uint32_t ret = s->TxAddr[txAddrOffset/4];
+
+    DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
+
+    return ret;
+}
+
+static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxBufPtr write val=0x%04x\n", val);
+
+    /* this value is off by 16 */
+    s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
+
+    DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+        s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
+}
+
+static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
+{
+    /* this value is off by 16 */
+    uint32_t ret = s->RxBufPtr - 0x10;
+
+    DPRINTF("RxBufPtr read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
+{
+    /* this value is NOT off by 16 */
+    uint32_t ret = s->RxBufAddr;
+
+    DPRINTF("RxBufAddr read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxBuf write val=0x%08x\n", val);
+
+    s->RxBuf = val;
+
+    /* may need to reset rxring here */
+}
+
+static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
+{
+    uint32_t ret = s->RxBuf;
+
+    DPRINTF("RxBuf read val=0x%08x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("IntrMask write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x1e00, s->IntrMask);
+
+    s->IntrMask = val;
+
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    rtl8139_update_irq(s);
+
+}
+
+static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
+{
+    uint32_t ret = s->IntrMask;
+
+    DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
+
+#if 0
+
+    /* writing to ISR has no effect */
+
+    return;
+
+#else
+    uint16_t newStatus = s->IntrStatus & ~val;
+
+    /* mask unwritable bits */
+    newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
+
+    /* writing 1 to interrupt status register bit clears it */
+    s->IntrStatus = 0;
+    rtl8139_update_irq(s);
+
+    s->IntrStatus = newStatus;
+    /*
+     * Computing if we miss an interrupt here is not that correct but
+     * considered that we should have had already an interrupt
+     * and probably emulated is slower is better to assume this resetting was
+     * done before testing on previous rtl8139_update_irq lead to IRQ loosing
+     */
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    rtl8139_update_irq(s);
+
+#endif
+}
+
+static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
+{
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+
+    uint32_t ret = s->IntrStatus;
+
+    DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
+
+#if 0
+
+    /* reading ISR clears all interrupts */
+    s->IntrStatus = 0;
+
+    rtl8139_update_irq(s);
+
+#endif
+
+    return ret;
+}
+
+static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf000, s->MultiIntr);
+
+    s->MultiIntr = val;
+}
+
+static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
+{
+    uint32_t ret = s->MultiIntr;
+
+    DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    addr &= 0xff;
+
+    switch (addr)
+    {
+        case MAC0 ... MAC0+5:
+            s->phys[addr - MAC0] = val;
+            break;
+        case MAC0+6 ... MAC0+7:
+            /* reserved */
+            break;
+        case MAR0 ... MAR0+7:
+            s->mult[addr - MAR0] = val;
+            break;
+        case ChipCmd:
+            rtl8139_ChipCmd_write(s, val);
+            break;
+        case Cfg9346:
+            rtl8139_Cfg9346_write(s, val);
+            break;
+        case TxConfig: /* windows driver sometimes writes using byte-lenth call */
+            rtl8139_TxConfig_writeb(s, val);
+            break;
+        case Config0:
+            rtl8139_Config0_write(s, val);
+            break;
+        case Config1:
+            rtl8139_Config1_write(s, val);
+            break;
+        case Config3:
+            rtl8139_Config3_write(s, val);
+            break;
+        case Config4:
+            rtl8139_Config4_write(s, val);
+            break;
+        case Config5:
+            rtl8139_Config5_write(s, val);
+            break;
+        case MediaStatus:
+            /* ignore */
+            DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
+                val);
+            break;
+
+        case HltClk:
+            DPRINTF("HltClk write val=0x%08x\n", val);
+            if (val == 'R')
+            {
+                s->clock_enabled = 1;
+            }
+            else if (val == 'H')
+            {
+                s->clock_enabled = 0;
+            }
+            break;
+
+        case TxThresh:
+            DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
+            s->TxThresh = val;
+            break;
+
+        case TxPoll:
+            DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
+            if (val & (1 << 7))
+            {
+                DPRINTF("C+ TxPoll high priority transmission (not "
+                    "implemented)\n");
+                //rtl8139_cplus_transmit(s);
+            }
+            if (val & (1 << 6))
+            {
+                DPRINTF("C+ TxPoll normal priority transmission\n");
+                rtl8139_cplus_transmit(s);
+            }
+
+            break;
+
+        default:
+            DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
+                val);
+            break;
+    }
+}
+
+static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    addr &= 0xfe;
+
+    switch (addr)
+    {
+        case IntrMask:
+            rtl8139_IntrMask_write(s, val);
+            break;
+
+        case IntrStatus:
+            rtl8139_IntrStatus_write(s, val);
+            break;
+
+        case MultiIntr:
+            rtl8139_MultiIntr_write(s, val);
+            break;
+
+        case RxBufPtr:
+            rtl8139_RxBufPtr_write(s, val);
+            break;
+
+        case BasicModeCtrl:
+            rtl8139_BasicModeCtrl_write(s, val);
+            break;
+        case BasicModeStatus:
+            rtl8139_BasicModeStatus_write(s, val);
+            break;
+        case NWayAdvert:
+            DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
+            s->NWayAdvert = val;
+            break;
+        case NWayLPAR:
+            DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
+            break;
+        case NWayExpansion:
+            DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
+            s->NWayExpansion = val;
+            break;
+
+        case CpCmd:
+            rtl8139_CpCmd_write(s, val);
+            break;
+
+        case IntrMitigate:
+            rtl8139_IntrMitigate_write(s, val);
+            break;
+
+        default:
+            DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
+                addr, val);
+
+            rtl8139_io_writeb(opaque, addr, val & 0xff);
+            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+            break;
+    }
+}
+
+static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time)
+{
+    int64_t pci_time, next_time;
+    uint32_t low_pci;
+
+    DPRINTF("entered rtl8139_set_next_tctr_time\n");
+
+    if (s->TimerExpire && current_time >= s->TimerExpire) {
+        s->IntrStatus |= PCSTimeout;
+        rtl8139_update_irq(s);
+    }
+
+    /* Set QEMU timer only if needed that is
+     * - TimerInt <> 0 (we have a timer)
+     * - mask = 1 (we want an interrupt timer)
+     * - irq = 0  (irq is not already active)
+     * If any of above change we need to compute timer again
+     * Also we must check if timer is passed without QEMU timer
+     */
+    s->TimerExpire = 0;
+    if (!s->TimerInt) {
+        return;
+    }
+
+    pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
+                                get_ticks_per_sec());
+    low_pci = pci_time & 0xffffffff;
+    pci_time = pci_time - low_pci + s->TimerInt;
+    if (low_pci >= s->TimerInt) {
+        pci_time += 0x100000000LL;
+    }
+    next_time = s->TCTR_base + muldiv64(pci_time, get_ticks_per_sec(),
+                                                PCI_FREQUENCY);
+    s->TimerExpire = next_time;
+
+    if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) {
+        qemu_mod_timer(s->timer, next_time);
+    }
+}
+
+static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    addr &= 0xfc;
+
+    switch (addr)
+    {
+        case RxMissed:
+            DPRINTF("RxMissed clearing on write\n");
+            s->RxMissed = 0;
+            break;
+
+        case TxConfig:
+            rtl8139_TxConfig_write(s, val);
+            break;
+
+        case RxConfig:
+            rtl8139_RxConfig_write(s, val);
+            break;
+
+        case TxStatus0 ... TxStatus0+4*4-1:
+            rtl8139_TxStatus_write(s, addr-TxStatus0, val);
+            break;
+
+        case TxAddr0 ... TxAddr0+4*4-1:
+            rtl8139_TxAddr_write(s, addr-TxAddr0, val);
+            break;
+
+        case RxBuf:
+            rtl8139_RxBuf_write(s, val);
+            break;
+
+        case RxRingAddrLO:
+            DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
+            s->RxRingAddrLO = val;
+            break;
+
+        case RxRingAddrHI:
+            DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
+            s->RxRingAddrHI = val;
+            break;
+
+        case Timer:
+            DPRINTF("TCTR Timer reset on write\n");
+            s->TCTR_base = qemu_get_clock_ns(vm_clock);
+            rtl8139_set_next_tctr_time(s, s->TCTR_base);
+            break;
+
+        case FlashReg:
+            DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
+            if (s->TimerInt != val) {
+                s->TimerInt = val;
+                rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+            }
+            break;
+
+        default:
+            DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
+                addr, val);
+            rtl8139_io_writeb(opaque, addr, val & 0xff);
+            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+            rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+            rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+            break;
+    }
+}
+
+static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    int ret;
+
+    addr &= 0xff;
+
+    switch (addr)
+    {
+        case MAC0 ... MAC0+5:
+            ret = s->phys[addr - MAC0];
+            break;
+        case MAC0+6 ... MAC0+7:
+            ret = 0;
+            break;
+        case MAR0 ... MAR0+7:
+            ret = s->mult[addr - MAR0];
+            break;
+        case ChipCmd:
+            ret = rtl8139_ChipCmd_read(s);
+            break;
+        case Cfg9346:
+            ret = rtl8139_Cfg9346_read(s);
+            break;
+        case Config0:
+            ret = rtl8139_Config0_read(s);
+            break;
+        case Config1:
+            ret = rtl8139_Config1_read(s);
+            break;
+        case Config3:
+            ret = rtl8139_Config3_read(s);
+            break;
+        case Config4:
+            ret = rtl8139_Config4_read(s);
+            break;
+        case Config5:
+            ret = rtl8139_Config5_read(s);
+            break;
+
+        case MediaStatus:
+            ret = 0xd0;
+            DPRINTF("MediaStatus read 0x%x\n", ret);
+            break;
+
+        case HltClk:
+            ret = s->clock_enabled;
+            DPRINTF("HltClk read 0x%x\n", ret);
+            break;
+
+        case PCIRevisionID:
+            ret = RTL8139_PCI_REVID;
+            DPRINTF("PCI Revision ID read 0x%x\n", ret);
+            break;
+
+        case TxThresh:
+            ret = s->TxThresh;
+            DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
+            break;
+
+        case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
+            ret = s->TxConfig >> 24;
+            DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
+            break;
+
+        default:
+            DPRINTF("not implemented read(b) addr=0x%x\n", addr);
+            ret = 0;
+            break;
+    }
+
+    return ret;
+}
+
+static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    uint32_t ret;
+
+    addr &= 0xfe; /* mask lower bit */
+
+    switch (addr)
+    {
+        case IntrMask:
+            ret = rtl8139_IntrMask_read(s);
+            break;
+
+        case IntrStatus:
+            ret = rtl8139_IntrStatus_read(s);
+            break;
+
+        case MultiIntr:
+            ret = rtl8139_MultiIntr_read(s);
+            break;
+
+        case RxBufPtr:
+            ret = rtl8139_RxBufPtr_read(s);
+            break;
+
+        case RxBufAddr:
+            ret = rtl8139_RxBufAddr_read(s);
+            break;
+
+        case BasicModeCtrl:
+            ret = rtl8139_BasicModeCtrl_read(s);
+            break;
+        case BasicModeStatus:
+            ret = rtl8139_BasicModeStatus_read(s);
+            break;
+        case NWayAdvert:
+            ret = s->NWayAdvert;
+            DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
+            break;
+        case NWayLPAR:
+            ret = s->NWayLPAR;
+            DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
+            break;
+        case NWayExpansion:
+            ret = s->NWayExpansion;
+            DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
+            break;
+
+        case CpCmd:
+            ret = rtl8139_CpCmd_read(s);
+            break;
+
+        case IntrMitigate:
+            ret = rtl8139_IntrMitigate_read(s);
+            break;
+
+        case TxSummary:
+            ret = rtl8139_TSAD_read(s);
+            break;
+
+        case CSCR:
+            ret = rtl8139_CSCR_read(s);
+            break;
+
+        default:
+            DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
+
+            ret  = rtl8139_io_readb(opaque, addr);
+            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
+
+            DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
+            break;
+    }
+
+    return ret;
+}
+
+static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    uint32_t ret;
+
+    addr &= 0xfc; /* also mask low 2 bits */
+
+    switch (addr)
+    {
+        case RxMissed:
+            ret = s->RxMissed;
+
+            DPRINTF("RxMissed read val=0x%08x\n", ret);
+            break;
+
+        case TxConfig:
+            ret = rtl8139_TxConfig_read(s);
+            break;
+
+        case RxConfig:
+            ret = rtl8139_RxConfig_read(s);
+            break;
+
+        case TxStatus0 ... TxStatus0+4*4-1:
+            ret = rtl8139_TxStatus_read(s, addr-TxStatus0);
+            break;
+
+        case TxAddr0 ... TxAddr0+4*4-1:
+            ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
+            break;
+
+        case RxBuf:
+            ret = rtl8139_RxBuf_read(s);
+            break;
+
+        case RxRingAddrLO:
+            ret = s->RxRingAddrLO;
+            DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
+            break;
+
+        case RxRingAddrHI:
+            ret = s->RxRingAddrHI;
+            DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
+            break;
+
+        case Timer:
+            ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base,
+                           PCI_FREQUENCY, get_ticks_per_sec());
+            DPRINTF("TCTR Timer read val=0x%08x\n", ret);
+            break;
+
+        case FlashReg:
+            ret = s->TimerInt;
+            DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
+            break;
+
+        default:
+            DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
+
+            ret  = rtl8139_io_readb(opaque, addr);
+            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
+            ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
+            ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
+
+            DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
+            break;
+    }
+
+    return ret;
+}
+
+/* */
+
+static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    rtl8139_io_writeb(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    rtl8139_io_writew(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    rtl8139_io_writel(opaque, addr & 0xFF, val);
+}
+
+static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr)
+{
+    return rtl8139_io_readb(opaque, addr & 0xFF);
+}
+
+static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr)
+{
+    return rtl8139_io_readw(opaque, addr & 0xFF);
+}
+
+static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr)
+{
+    return rtl8139_io_readl(opaque, addr & 0xFF);
+}
+
+/* */
+
+static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    rtl8139_io_writeb(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    rtl8139_io_writew(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    rtl8139_io_writel(opaque, addr & 0xFF, val);
+}
+
+static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    return rtl8139_io_readb(opaque, addr & 0xFF);
+}
+
+static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
+    return val;
+}
+
+static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
+    return val;
+}
+
+static int rtl8139_post_load(void *opaque, int version_id)
+{
+    RTL8139State* s = opaque;
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    if (version_id < 4) {
+        s->cplus_enabled = s->CpCmd != 0;
+    }
+
+    return 0;
+}
+
+static bool rtl8139_hotplug_ready_needed(void *opaque)
+{
+    return qdev_machine_modified();
+}
+
+static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
+    .name = "rtl8139/hotplug_ready",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtl8139_pre_save(void *opaque)
+{
+    RTL8139State* s = opaque;
+    int64_t current_time = qemu_get_clock_ns(vm_clock);
+
+    /* set IntrStatus correctly */
+    rtl8139_set_next_tctr_time(s, current_time);
+    s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
+                       get_ticks_per_sec());
+    s->rtl8139_mmio_io_addr_dummy = s->rtl8139_mmio_io_addr;
+}
+
+static const VMStateDescription vmstate_rtl8139 = {
+    .name = "rtl8139",
+    .version_id = 4,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .post_load = rtl8139_post_load,
+    .pre_save  = rtl8139_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, RTL8139State),
+        VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
+        VMSTATE_BUFFER(mult, RTL8139State),
+        VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
+        VMSTATE_UINT32_ARRAY(TxAddr, RTL8139State, 4),
+
+        VMSTATE_UINT32(RxBuf, RTL8139State),
+        VMSTATE_UINT32(RxBufferSize, RTL8139State),
+        VMSTATE_UINT32(RxBufPtr, RTL8139State),
+        VMSTATE_UINT32(RxBufAddr, RTL8139State),
+
+        VMSTATE_UINT16(IntrStatus, RTL8139State),
+        VMSTATE_UINT16(IntrMask, RTL8139State),
+
+        VMSTATE_UINT32(TxConfig, RTL8139State),
+        VMSTATE_UINT32(RxConfig, RTL8139State),
+        VMSTATE_UINT32(RxMissed, RTL8139State),
+        VMSTATE_UINT16(CSCR, RTL8139State),
+
+        VMSTATE_UINT8(Cfg9346, RTL8139State),
+        VMSTATE_UINT8(Config0, RTL8139State),
+        VMSTATE_UINT8(Config1, RTL8139State),
+        VMSTATE_UINT8(Config3, RTL8139State),
+        VMSTATE_UINT8(Config4, RTL8139State),
+        VMSTATE_UINT8(Config5, RTL8139State),
+
+        VMSTATE_UINT8(clock_enabled, RTL8139State),
+        VMSTATE_UINT8(bChipCmdState, RTL8139State),
+
+        VMSTATE_UINT16(MultiIntr, RTL8139State),
+
+        VMSTATE_UINT16(BasicModeCtrl, RTL8139State),
+        VMSTATE_UINT16(BasicModeStatus, RTL8139State),
+        VMSTATE_UINT16(NWayAdvert, RTL8139State),
+        VMSTATE_UINT16(NWayLPAR, RTL8139State),
+        VMSTATE_UINT16(NWayExpansion, RTL8139State),
+
+        VMSTATE_UINT16(CpCmd, RTL8139State),
+        VMSTATE_UINT8(TxThresh, RTL8139State),
+
+        VMSTATE_UNUSED(4),
+        VMSTATE_MACADDR(conf.macaddr, RTL8139State),
+        VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
+
+        VMSTATE_UINT32(currTxDesc, RTL8139State),
+        VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
+        VMSTATE_UINT32(currCPlusTxDesc, RTL8139State),
+        VMSTATE_UINT32(RxRingAddrLO, RTL8139State),
+        VMSTATE_UINT32(RxRingAddrHI, RTL8139State),
+
+        VMSTATE_UINT16_ARRAY(eeprom.contents, RTL8139State, EEPROM_9346_SIZE),
+        VMSTATE_INT32(eeprom.mode, RTL8139State),
+        VMSTATE_UINT32(eeprom.tick, RTL8139State),
+        VMSTATE_UINT8(eeprom.address, RTL8139State),
+        VMSTATE_UINT16(eeprom.input, RTL8139State),
+        VMSTATE_UINT16(eeprom.output, RTL8139State),
+
+        VMSTATE_UINT8(eeprom.eecs, RTL8139State),
+        VMSTATE_UINT8(eeprom.eesk, RTL8139State),
+        VMSTATE_UINT8(eeprom.eedi, RTL8139State),
+        VMSTATE_UINT8(eeprom.eedo, RTL8139State),
+
+        VMSTATE_UINT32(TCTR, RTL8139State),
+        VMSTATE_UINT32(TimerInt, RTL8139State),
+        VMSTATE_INT64(TCTR_base, RTL8139State),
+
+        VMSTATE_STRUCT(tally_counters, RTL8139State, 0,
+                       vmstate_tally_counters, RTL8139TallyCounters),
+
+        VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_rtl8139_hotplug_ready,
+            .needed = rtl8139_hotplug_ready_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+/***********************************************************/
+/* PCI RTL8139 definitions */
+
+static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
+
+    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
+    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
+
+    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
+    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
+
+    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
+    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
+}
+
+static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
+    rtl8139_mmio_readb,
+    rtl8139_mmio_readw,
+    rtl8139_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const rtl8139_mmio_write[3] = {
+    rtl8139_mmio_writeb,
+    rtl8139_mmio_writew,
+    rtl8139_mmio_writel,
+};
+
+static void rtl8139_timer(void *opaque)
+{
+    RTL8139State *s = opaque;
+
+    if (!s->clock_enabled)
+    {
+        DPRINTF(">>> timer: clock is not running\n");
+        return;
+    }
+
+    s->IntrStatus |= PCSTimeout;
+    rtl8139_update_irq(s);
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+}
+
+static void rtl8139_cleanup(VLANClientState *nc)
+{
+    RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static int pci_rtl8139_uninit(PCIDevice *dev)
+{
+    RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
+
+    cpu_unregister_io_memory(s->rtl8139_mmio_io_addr);
+    if (s->cplus_txbuffer) {
+        qemu_free(s->cplus_txbuffer);
+        s->cplus_txbuffer = NULL;
+    }
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_del_vlan_client(&s->nic->nc);
+    return 0;
+}
+
+static NetClientInfo net_rtl8139_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = rtl8139_can_receive,
+    .receive = rtl8139_receive,
+    .cleanup = rtl8139_cleanup,
+};
+
+static int pci_rtl8139_init(PCIDevice *dev)
+{
+    RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin 0 */
+    /* TODO: start of capability list, but no capability
+     * list bit in status register, and offset 0xdc seems unused. */
+    pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
+
+    /* I/O handler for memory-mapped I/O */
+    s->rtl8139_mmio_io_addr =
+        cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s,
+                               DEVICE_LITTLE_ENDIAN);
+
+    pci_register_bar(&s->dev, 0, 0x100,
+                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
+
+    pci_register_bar_simple(&s->dev, 1, 0x100, 0, s->rtl8139_mmio_io_addr);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    /* prepare eeprom */
+    s->eeprom.contents[0] = 0x8129;
+#if 1
+    /* PCI vendor and device ID should be mirrored here */
+    s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
+    s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
+#endif
+    s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
+    s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
+    s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
+
+    s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    s->cplus_txbuffer = NULL;
+    s->cplus_txbuffer_len = 0;
+    s->cplus_txbuffer_offset = 0;
+
+    s->TimerExpire = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s);
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy at 0");
+
+    return 0;
+}
+
+static PCIDeviceInfo rtl8139_info = {
+    .qdev.name  = "rtl8139",
+    .qdev.size  = sizeof(RTL8139State),
+    .qdev.reset = rtl8139_reset,
+    .qdev.vmsd  = &vmstate_rtl8139,
+    .init       = pci_rtl8139_init,
+    .exit       = pci_rtl8139_uninit,
+    .romfile    = "pxe-rtl8139.rom",
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8139,
+    .revision   = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void rtl8139_register_devices(void)
+{
+    pci_qdev_register(&rtl8139_info);
+}
+
+device_init(rtl8139_register_devices)
diff --git a/qemu-0.15.x/hw/s390-virtio-bus.c b/qemu-0.15.x/hw/s390-virtio-bus.c
new file mode 100644
index 0000000..e2f3e32
--- /dev/null
+++ b/qemu-0.15.x/hw/s390-virtio-bus.c
@@ -0,0 +1,423 @@
+/*
+ * QEMU S390 virtio target
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "block.h"
+#include "sysemu.h"
+#include "net.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/virtio.h"
+#include "hw/virtio-serial.h"
+#include "hw/virtio-net.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+
+#include "hw/s390-virtio-bus.h"
+
+/* #define DEBUG_S390 */
+
+#ifdef DEBUG_S390
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define VIRTIO_EXT_CODE   0x2603
+
+struct BusInfo s390_virtio_bus_info = {
+    .name       = "s390-virtio",
+    .size       = sizeof(VirtIOS390Bus),
+};
+
+typedef struct {
+    DeviceInfo qdev;
+    int (*init)(VirtIOS390Device *dev);
+} VirtIOS390DeviceInfo;
+
+
+static const VirtIOBindings virtio_s390_bindings;
+
+static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
+
+/* length of VirtIO device pages */
+const target_phys_addr_t virtio_size = S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
+
+VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
+{
+    VirtIOS390Bus *bus;
+    BusState *_bus;
+    DeviceState *dev;
+
+    /* Create bridge device */
+    dev = qdev_create(NULL, "s390-virtio-bridge");
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+
+    _bus = qbus_create(&s390_virtio_bus_info, dev, "s390-virtio");
+    bus = DO_UPCAST(VirtIOS390Bus, bus, _bus);
+
+    bus->dev_page = *ram_size;
+    bus->dev_offs = bus->dev_page;
+    bus->next_ring = bus->dev_page + TARGET_PAGE_SIZE;
+
+    /* Allocate RAM for VirtIO device pages (descriptors, queues, rings) */
+    *ram_size += S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
+
+    return bus;
+}
+
+static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
+{
+    VirtIOS390Bus *bus;
+    int dev_len;
+
+    bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
+    dev->vdev = vdev;
+    dev->dev_offs = bus->dev_offs;
+    dev->feat_len = sizeof(uint32_t); /* always keep 32 bits features */
+
+    dev_len = VIRTIO_DEV_OFFS_CONFIG;
+    dev_len += s390_virtio_device_num_vq(dev) * VIRTIO_VQCONFIG_LEN;
+    dev_len += dev->feat_len * 2;
+    dev_len += vdev->config_len;
+
+    bus->dev_offs += dev_len;
+
+    virtio_bind_device(vdev, &virtio_s390_bindings, dev);
+    dev->host_features = vdev->get_features(vdev, dev->host_features);
+    s390_virtio_device_sync(dev);
+
+    return 0;
+}
+
+static int s390_virtio_net_init(VirtIOS390Device *dev)
+{
+    VirtIODevice *vdev;
+
+    vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net);
+    if (!vdev) {
+        return -1;
+    }
+
+    return s390_virtio_device_init(dev, vdev);
+}
+
+static int s390_virtio_blk_init(VirtIOS390Device *dev)
+{
+    VirtIODevice *vdev;
+
+    vdev = virtio_blk_init((DeviceState *)dev, &dev->block,
+                           &dev->block_serial);
+    if (!vdev) {
+        return -1;
+    }
+
+    return s390_virtio_device_init(dev, vdev);
+}
+
+static int s390_virtio_serial_init(VirtIOS390Device *dev)
+{
+    VirtIOS390Bus *bus;
+    VirtIODevice *vdev;
+    int r;
+
+    bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
+
+    vdev = virtio_serial_init((DeviceState *)dev, &dev->serial);
+    if (!vdev) {
+        return -1;
+    }
+
+    r = s390_virtio_device_init(dev, vdev);
+    if (!r) {
+        bus->console = dev;
+    }
+
+    return r;
+}
+
+static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
+{
+    ram_addr_t token_off;
+
+    token_off = (dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG) +
+                (vq * VIRTIO_VQCONFIG_LEN) +
+                VIRTIO_VQCONFIG_OFFS_TOKEN;
+
+    return ldq_be_phys(token_off);
+}
+
+static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
+{
+    VirtIODevice *vdev = dev->vdev;
+    int num_vq;
+
+    for (num_vq = 0; num_vq < VIRTIO_PCI_QUEUE_MAX; num_vq++) {
+        if (!virtio_queue_get_num(vdev, num_vq)) {
+            break;
+        }
+    }
+
+    return num_vq;
+}
+
+static ram_addr_t s390_virtio_next_ring(VirtIOS390Bus *bus)
+{
+    ram_addr_t r = bus->next_ring;
+
+    bus->next_ring += VIRTIO_RING_LEN;
+    return r;
+}
+
+void s390_virtio_device_sync(VirtIOS390Device *dev)
+{
+    VirtIOS390Bus *bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
+    ram_addr_t cur_offs;
+    uint8_t num_vq;
+    int i;
+
+    virtio_reset(dev->vdev);
+
+    /* Sync dev space */
+    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_TYPE, dev->vdev->device_id);
+
+    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_NUM_VQ, s390_virtio_device_num_vq(dev));
+    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_FEATURE_LEN, dev->feat_len);
+
+    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG_LEN, dev->vdev->config_len);
+
+    num_vq = s390_virtio_device_num_vq(dev);
+    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_NUM_VQ, num_vq);
+
+    /* Sync virtqueues */
+    for (i = 0; i < num_vq; i++) {
+        ram_addr_t vq = (dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG) +
+                        (i * VIRTIO_VQCONFIG_LEN);
+        ram_addr_t vring;
+
+        vring = s390_virtio_next_ring(bus);
+        virtio_queue_set_addr(dev->vdev, i, vring);
+        virtio_queue_set_vector(dev->vdev, i, i);
+        stq_be_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring);
+        stw_be_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i));
+    }
+
+    cur_offs = dev->dev_offs;
+    cur_offs += VIRTIO_DEV_OFFS_CONFIG;
+    cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
+
+    /* Sync feature bitmap */
+    stl_le_phys(cur_offs, dev->host_features);
+
+    dev->feat_offs = cur_offs + dev->feat_len;
+    cur_offs += dev->feat_len * 2;
+
+    /* Sync config space */
+    if (dev->vdev->get_config) {
+        dev->vdev->get_config(dev->vdev, dev->vdev->config);
+    }
+
+    cpu_physical_memory_write(cur_offs,
+                              dev->vdev->config, dev->vdev->config_len);
+    cur_offs += dev->vdev->config_len;
+}
+
+void s390_virtio_device_update_status(VirtIOS390Device *dev)
+{
+    VirtIODevice *vdev = dev->vdev;
+    uint32_t features;
+
+    virtio_set_status(vdev, ldub_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS));
+
+    /* Update guest supported feature bitmap */
+
+    features = bswap32(ldl_be_phys(dev->feat_offs));
+    if (vdev->set_features) {
+        vdev->set_features(vdev, features);
+    }
+    vdev->guest_features = features;
+}
+
+VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
+{
+    return bus->console;
+}
+
+/* Find a device by vring address */
+VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
+                                             ram_addr_t mem,
+                                             int *vq_num)
+{
+    VirtIOS390Device *_dev;
+    DeviceState *dev;
+    int i;
+
+    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+        _dev = (VirtIOS390Device *)dev;
+        for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+            if (!virtio_queue_get_addr(_dev->vdev, i))
+                break;
+            if (virtio_queue_get_addr(_dev->vdev, i) == mem) {
+                if (vq_num) {
+                    *vq_num = i;
+                }
+                return _dev;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/* Find a device by device descriptor location */
+VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
+{
+    VirtIOS390Device *_dev;
+    DeviceState *dev;
+
+    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+        _dev = (VirtIOS390Device *)dev;
+        if (_dev->dev_offs == mem) {
+            return _dev;
+        }
+    }
+
+    return NULL;
+}
+
+static void virtio_s390_notify(void *opaque, uint16_t vector)
+{
+    VirtIOS390Device *dev = (VirtIOS390Device*)opaque;
+    uint64_t token = s390_virtio_device_vq_token(dev, vector);
+    CPUState *env = s390_cpu_addr2state(0);
+
+    if (kvm_enabled()) {
+        kvm_s390_virtio_irq(env, 0, token);
+    } else {
+        cpu_inject_ext(env, VIRTIO_EXT_CODE, 0, token);
+    }
+}
+
+static unsigned virtio_s390_get_features(void *opaque)
+{
+    VirtIOS390Device *dev = (VirtIOS390Device*)opaque;
+    return dev->host_features;
+}
+
+/**************** S390 Virtio Bus Device Descriptions *******************/
+
+static const VirtIOBindings virtio_s390_bindings = {
+    .notify = virtio_s390_notify,
+    .get_features = virtio_s390_get_features,
+};
+
+static VirtIOS390DeviceInfo s390_virtio_net = {
+    .init = s390_virtio_net_init,
+    .qdev.name = "virtio-net-s390",
+    .qdev.alias = "virtio-net",
+    .qdev.size = sizeof(VirtIOS390Device),
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+        DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+                           net.txtimer, TX_TIMER_INTERVAL),
+        DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+                          net.txburst, TX_BURST),
+        DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static VirtIOS390DeviceInfo s390_virtio_blk = {
+    .init = s390_virtio_blk_init,
+    .qdev.name = "virtio-blk-s390",
+    .qdev.alias = "virtio-blk",
+    .qdev.size = sizeof(VirtIOS390Device),
+    .qdev.props = (Property[]) {
+        DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
+        DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static VirtIOS390DeviceInfo s390_virtio_serial = {
+    .init = s390_virtio_serial_init,
+    .qdev.name = "virtio-serial-s390",
+    .qdev.alias = "virtio-serial",
+    .qdev.size = sizeof(VirtIOS390Device),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
+                           serial.max_virtserial_ports, 31),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
+{
+    VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info;
+    VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
+
+    return _info->init(_dev);
+}
+
+static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
+{
+    info->qdev.init = s390_virtio_busdev_init;
+    info->qdev.bus_info = &s390_virtio_bus_info;
+
+    assert(info->qdev.size >= sizeof(VirtIOS390Device));
+    qdev_register(&info->qdev);
+}
+
+static void s390_virtio_register(void)
+{
+    s390_virtio_bus_register_withprop(&s390_virtio_serial);
+    s390_virtio_bus_register_withprop(&s390_virtio_blk);
+    s390_virtio_bus_register_withprop(&s390_virtio_net);
+}
+device_init(s390_virtio_register);
+
+
+/***************** S390 Virtio Bus Bridge Device *******************/
+/* Only required to have the virtio bus as child in the system bus */
+
+static int s390_virtio_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static SysBusDeviceInfo s390_virtio_bridge_info = {
+    .init = s390_virtio_bridge_init,
+    .qdev.name  = "s390-virtio-bridge",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.no_user = 1,
+};
+
+static void s390_virtio_register_devices(void)
+{
+    sysbus_register_withprop(&s390_virtio_bridge_info);
+}
+
+device_init(s390_virtio_register_devices)
diff --git a/qemu-0.15.x/hw/s390-virtio-bus.h b/qemu-0.15.x/hw/s390-virtio-bus.h
new file mode 100644
index 0000000..f1bece7
--- /dev/null
+++ b/qemu-0.15.x/hw/s390-virtio-bus.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU S390x VirtIO BUS definitions
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "virtio-net.h"
+#include "virtio-serial.h"
+
+#define VIRTIO_DEV_OFFS_TYPE		0	/* 8 bits */
+#define VIRTIO_DEV_OFFS_NUM_VQ		1	/* 8 bits */
+#define VIRTIO_DEV_OFFS_FEATURE_LEN	2	/* 8 bits */
+#define VIRTIO_DEV_OFFS_CONFIG_LEN	3	/* 8 bits */
+#define VIRTIO_DEV_OFFS_STATUS		4	/* 8 bits */
+#define VIRTIO_DEV_OFFS_CONFIG		5	/* dynamic */
+
+#define VIRTIO_VQCONFIG_OFFS_TOKEN	0	/* 64 bits */
+#define VIRTIO_VQCONFIG_OFFS_ADDRESS	8	/* 64 bits */
+#define VIRTIO_VQCONFIG_OFFS_NUM	16	/* 16 bits */
+#define VIRTIO_VQCONFIG_LEN		24
+
+#define VIRTIO_RING_LEN			(TARGET_PAGE_SIZE * 3)
+#define S390_DEVICE_PAGES		512
+
+typedef struct VirtIOS390Device {
+    DeviceState qdev;
+    ram_addr_t dev_offs;
+    ram_addr_t feat_offs;
+    uint8_t feat_len;
+    VirtIODevice *vdev;
+    BlockConf block;
+    char *block_serial;
+    NICConf nic;
+    uint32_t host_features;
+    virtio_serial_conf serial;
+    virtio_net_conf net;
+} VirtIOS390Device;
+
+typedef struct VirtIOS390Bus {
+    BusState bus;
+
+    VirtIOS390Device *console;
+    ram_addr_t dev_page;
+    ram_addr_t dev_offs;
+    ram_addr_t next_ring;
+} VirtIOS390Bus;
+
+
+void s390_virtio_device_update_status(VirtIOS390Device *dev);
+
+VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus);
+VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size);
+
+VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
+                                             ram_addr_t mem, int *vq_num);
+VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem);
+void s390_virtio_device_sync(VirtIOS390Device *dev);
diff --git a/qemu-0.15.x/hw/s390-virtio.c b/qemu-0.15.x/hw/s390-virtio.c
new file mode 100644
index 0000000..abe954d
--- /dev/null
+++ b/qemu-0.15.x/hw/s390-virtio.c
@@ -0,0 +1,297 @@
+/*
+ * QEMU S390 virtio target
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "block.h"
+#include "blockdev.h"
+#include "sysemu.h"
+#include "net.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/virtio.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+
+#include "hw/s390-virtio-bus.h"
+
+//#define DEBUG_S390
+
+#ifdef DEBUG_S390
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define KVM_S390_VIRTIO_NOTIFY          0
+#define KVM_S390_VIRTIO_RESET           1
+#define KVM_S390_VIRTIO_SET_STATUS      2
+
+#define KERN_IMAGE_START                0x010000UL
+#define KERN_PARM_AREA                  0x010480UL
+#define INITRD_START                    0x800000UL
+#define INITRD_PARM_START               0x010408UL
+#define INITRD_PARM_SIZE                0x010410UL
+#define PARMFILE_START                  0x001000UL
+
+#define ZIPL_START			0x009000UL
+#define ZIPL_LOAD_ADDR			0x009000UL
+#define ZIPL_FILENAME			"s390-zipl.rom"
+
+#define MAX_BLK_DEVS                    10
+
+static VirtIOS390Bus *s390_bus;
+static CPUState **ipi_states;
+
+void irq_info(Monitor *mon);
+void pic_info(Monitor *mon);
+
+void irq_info(Monitor *mon)
+{
+}
+
+void pic_info(Monitor *mon)
+{
+}
+
+CPUState *s390_cpu_addr2state(uint16_t cpu_addr)
+{
+    if (cpu_addr >= smp_cpus) {
+        return NULL;
+    }
+
+    return ipi_states[cpu_addr];
+}
+
+int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall)
+{
+    int r = 0, i;
+
+    dprintf("KVM hypercall: %ld\n", hypercall);
+    switch (hypercall) {
+    case KVM_S390_VIRTIO_NOTIFY:
+        if (mem > ram_size) {
+            VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus,
+                                                               mem, &i);
+            if (dev) {
+                virtio_queue_notify(dev->vdev, i);
+            } else {
+                r = -EINVAL;
+            }
+        } else {
+            /* Early printk */
+        }
+        break;
+    case KVM_S390_VIRTIO_RESET:
+    {
+        VirtIOS390Device *dev;
+
+        dev = s390_virtio_bus_find_mem(s390_bus, mem);
+        virtio_reset(dev->vdev);
+        s390_virtio_device_sync(dev);
+        break;
+    }
+    case KVM_S390_VIRTIO_SET_STATUS:
+    {
+        VirtIOS390Device *dev;
+
+        dev = s390_virtio_bus_find_mem(s390_bus, mem);
+        if (dev) {
+            s390_virtio_device_update_status(dev);
+        } else {
+            r = -EINVAL;
+        }
+        break;
+    }
+    default:
+        r = -EINVAL;
+        break;
+    }
+
+    return r;
+}
+
+/* PC hardware initialisation */
+static void s390_init(ram_addr_t my_ram_size,
+                      const char *boot_device,
+                      const char *kernel_filename,
+                      const char *kernel_cmdline,
+                      const char *initrd_filename,
+                      const char *cpu_model)
+{
+    CPUState *env = NULL;
+    ram_addr_t ram_addr;
+    ram_addr_t kernel_size = 0;
+    ram_addr_t initrd_offset;
+    ram_addr_t initrd_size = 0;
+    int shift = 0;
+    uint8_t *storage_keys;
+    int i;
+
+    /* s390x ram size detection needs a 16bit multiplier + an increment. So
+       guests > 64GB can be specified in 2MB steps etc. */
+    while ((my_ram_size >> (20 + shift)) > 65535) {
+        shift++;
+    }
+    my_ram_size = my_ram_size >> (20 + shift) << (20 + shift);
+
+    /* lets propagate the changed ram size into the global variable. */
+    ram_size = my_ram_size;
+
+    /* get a BUS */
+    s390_bus = s390_virtio_bus_init(&my_ram_size);
+
+    /* allocate RAM */
+    ram_addr = qemu_ram_alloc(NULL, "s390.ram", my_ram_size);
+    cpu_register_physical_memory(0, my_ram_size, ram_addr);
+
+    /* allocate storage keys */
+    storage_keys = qemu_mallocz(my_ram_size / TARGET_PAGE_SIZE);
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "host";
+    }
+
+    ipi_states = qemu_malloc(sizeof(CPUState *) * smp_cpus);
+
+    for (i = 0; i < smp_cpus; i++) {
+        CPUState *tmp_env;
+
+        tmp_env = cpu_init(cpu_model);
+        if (!env) {
+            env = tmp_env;
+        }
+        ipi_states[i] = tmp_env;
+        tmp_env->halted = 1;
+        tmp_env->exception_index = EXCP_HLT;
+        tmp_env->storage_keys = storage_keys;
+    }
+
+    env->halted = 0;
+    env->exception_index = 0;
+
+    if (kernel_filename) {
+        kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
+
+        if (lduw_be_phys(KERN_IMAGE_START) != 0x0dd0) {
+            fprintf(stderr, "Specified image is not an s390 boot image\n");
+            exit(1);
+        }
+
+        env->psw.addr = KERN_IMAGE_START;
+        env->psw.mask = 0x0000000180000000ULL;
+    } else {
+        ram_addr_t bios_size = 0;
+        char *bios_filename;
+
+        /* Load zipl bootloader */
+        if (bios_name == NULL) {
+            bios_name = ZIPL_FILENAME;
+        }
+
+        bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        bios_size = load_image(bios_filename, qemu_get_ram_ptr(ZIPL_LOAD_ADDR));
+        qemu_free(bios_filename);
+
+        if ((long)bios_size < 0) {
+            hw_error("could not load bootloader '%s'\n", bios_name);
+        }
+
+        if (bios_size > 4096) {
+            hw_error("stage1 bootloader is > 4k\n");
+        }
+
+        env->psw.addr = ZIPL_START;
+        env->psw.mask = 0x0000000180000000ULL;
+    }
+
+    if (initrd_filename) {
+        initrd_offset = INITRD_START;
+        while (kernel_size + 0x100000 > initrd_offset) {
+            initrd_offset += 0x100000;
+        }
+        initrd_size = load_image(initrd_filename, qemu_get_ram_ptr(initrd_offset));
+
+        stq_be_phys(INITRD_PARM_START, initrd_offset);
+        stq_be_phys(INITRD_PARM_SIZE, initrd_size);
+    }
+
+    if (kernel_cmdline) {
+        cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline,
+                                  strlen(kernel_cmdline));
+    }
+
+    /* Create VirtIO network adapters */
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        DeviceState *dev;
+
+        if (!nd->model) {
+            nd->model = qemu_strdup("virtio");
+        }
+
+        if (strcmp(nd->model, "virtio")) {
+            fprintf(stderr, "S390 only supports VirtIO nics\n");
+            exit(1);
+        }
+
+        dev = qdev_create((BusState *)s390_bus, "virtio-net-s390");
+        qdev_set_nic_properties(dev, nd);
+        qdev_init_nofail(dev);
+    }
+
+    /* Create VirtIO disk drives */
+    for(i = 0; i < MAX_BLK_DEVS; i++) {
+        DriveInfo *dinfo;
+        DeviceState *dev;
+
+        dinfo = drive_get(IF_IDE, 0, i);
+        if (!dinfo) {
+            continue;
+        }
+
+        dev = qdev_create((BusState *)s390_bus, "virtio-blk-s390");
+        qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
+        qdev_init_nofail(dev);
+    }
+}
+
+static QEMUMachine s390_machine = {
+    .name = "s390-virtio",
+    .alias = "s390",
+    .desc = "VirtIO based S390 machine",
+    .init = s390_init,
+    .no_serial = 1,
+    .no_parallel = 1,
+    .use_virtcon = 1,
+    .no_vga = 1,
+    .max_cpus = 255,
+    .is_default = 1,
+};
+
+static void s390_machine_init(void)
+{
+    qemu_register_machine(&s390_machine);
+}
+
+machine_init(s390_machine_init);
diff --git a/qemu-0.15.x/hw/sb16.c b/qemu-0.15.x/hw/sb16.c
new file mode 100644
index 0000000..a76df1b
--- /dev/null
+++ b/qemu-0.15.x/hw/sb16.c
@@ -0,0 +1,1420 @@
+/*
+ * QEMU Soundblaster 16 emulation
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "isa.h"
+#include "qdev.h"
+#include "qemu-timer.h"
+#include "host-utils.h"
+
+#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
+
+/* #define DEBUG */
+/* #define DEBUG_SB16_MOST */
+
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#define IO_READ_PROTO(name)                             \
+    uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name)                                    \
+    void name (void *opaque, uint32_t nport, uint32_t val)
+
+static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
+
+typedef struct SB16State {
+    ISADevice dev;
+    QEMUSoundCard card;
+    qemu_irq pic;
+    uint32_t irq;
+    uint32_t dma;
+    uint32_t hdma;
+    uint32_t port;
+    uint32_t ver;
+
+    int in_index;
+    int out_data_len;
+    int fmt_stereo;
+    int fmt_signed;
+    int fmt_bits;
+    audfmt_e fmt;
+    int dma_auto;
+    int block_size;
+    int fifo;
+    int freq;
+    int time_const;
+    int speaker;
+    int needed_bytes;
+    int cmd;
+    int use_hdma;
+    int highspeed;
+    int can_write;
+
+    int v2x6;
+
+    uint8_t csp_param;
+    uint8_t csp_value;
+    uint8_t csp_mode;
+    uint8_t csp_regs[256];
+    uint8_t csp_index;
+    uint8_t csp_reg83[4];
+    int csp_reg83r;
+    int csp_reg83w;
+
+    uint8_t in2_data[10];
+    uint8_t out_data[50];
+    uint8_t test_reg;
+    uint8_t last_read_byte;
+    int nzero;
+
+    int left_till_irq;
+
+    int dma_running;
+    int bytes_per_second;
+    int align;
+    int audio_free;
+    SWVoiceOut *voice;
+
+    QEMUTimer *aux_ts;
+    /* mixer state */
+    int mixer_nreg;
+    uint8_t mixer_regs[256];
+} SB16State;
+
+static void SB_audio_callback (void *opaque, int free);
+
+static int magic_of_irq (int irq)
+{
+    switch (irq) {
+    case 5:
+        return 2;
+    case 7:
+        return 4;
+    case 9:
+        return 1;
+    case 10:
+        return 8;
+    default:
+        dolog ("bad irq %d\n", irq);
+        return 2;
+    }
+}
+
+static int irq_of_magic (int magic)
+{
+    switch (magic) {
+    case 1:
+        return 9;
+    case 2:
+        return 5;
+    case 4:
+        return 7;
+    case 8:
+        return 10;
+    default:
+        dolog ("bad irq magic %d\n", magic);
+        return -1;
+    }
+}
+
+#if 0
+static void log_dsp (SB16State *dsp)
+{
+    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
+            dsp->fmt_stereo ? "Stereo" : "Mono",
+            dsp->fmt_signed ? "Signed" : "Unsigned",
+            dsp->fmt_bits,
+            dsp->dma_auto ? "Auto" : "Single",
+            dsp->block_size,
+            dsp->freq,
+            dsp->time_const,
+            dsp->speaker);
+}
+#endif
+
+static void speaker (SB16State *s, int on)
+{
+    s->speaker = on;
+    /* AUD_enable (s->voice, on); */
+}
+
+static void control (SB16State *s, int hold)
+{
+    int dma = s->use_hdma ? s->hdma : s->dma;
+    s->dma_running = hold;
+
+    ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
+
+    if (hold) {
+        DMA_hold_DREQ (dma);
+        AUD_set_active_out (s->voice, 1);
+    }
+    else {
+        DMA_release_DREQ (dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+}
+
+static void aux_timer (void *opaque)
+{
+    SB16State *s = opaque;
+    s->can_write = 1;
+    qemu_irq_raise (s->pic);
+}
+
+#define DMA8_AUTO 1
+#define DMA8_HIGH 2
+
+static void continue_dma8 (SB16State *s)
+{
+    if (s->freq > 0) {
+        struct audsettings as;
+
+        s->audio_free = 0;
+
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as
+            );
+    }
+
+    control (s, 1);
+}
+
+static void dma_cmd8 (SB16State *s, int mask, int dma_len)
+{
+    s->fmt = AUD_FMT_U8;
+    s->use_hdma = 0;
+    s->fmt_bits = 8;
+    s->fmt_signed = 0;
+    s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
+    if (-1 == s->time_const) {
+        if (s->freq <= 0)
+            s->freq = 11025;
+    }
+    else {
+        int tmp = (256 - s->time_const);
+        s->freq = (1000000 + (tmp / 2)) / tmp;
+    }
+
+    if (dma_len != -1) {
+        s->block_size = dma_len << s->fmt_stereo;
+    }
+    else {
+        /* This is apparently the only way to make both Act1/PL
+           and SecondReality/FC work
+
+           Act1 sets block size via command 0x48 and it's an odd number
+           SR does the same with even number
+           Both use stereo, and Creatives own documentation states that
+           0x48 sets block size in bytes less one.. go figure */
+        s->block_size &= ~s->fmt_stereo;
+    }
+
+    s->freq >>= s->fmt_stereo;
+    s->left_till_irq = s->block_size;
+    s->bytes_per_second = (s->freq << s->fmt_stereo);
+    /* s->highspeed = (mask & DMA8_HIGH) != 0; */
+    s->dma_auto = (mask & DMA8_AUTO) != 0;
+    s->align = (1 << s->fmt_stereo) - 1;
+
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
+
+    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
+            "dma %d, auto %d, fifo %d, high %d\n",
+            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
+            s->block_size, s->dma_auto, s->fifo, s->highspeed);
+
+    continue_dma8 (s);
+    speaker (s, 1);
+}
+
+static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
+{
+    s->use_hdma = cmd < 0xc0;
+    s->fifo = (cmd >> 1) & 1;
+    s->dma_auto = (cmd >> 2) & 1;
+    s->fmt_signed = (d0 >> 4) & 1;
+    s->fmt_stereo = (d0 >> 5) & 1;
+
+    switch (cmd >> 4) {
+    case 11:
+        s->fmt_bits = 16;
+        break;
+
+    case 12:
+        s->fmt_bits = 8;
+        break;
+    }
+
+    if (-1 != s->time_const) {
+#if 1
+        int tmp = 256 - s->time_const;
+        s->freq = (1000000 + (tmp / 2)) / tmp;
+#else
+        /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
+        s->freq = 1000000 / ((255 - s->time_const));
+#endif
+        s->time_const = -1;
+    }
+
+    s->block_size = dma_len + 1;
+    s->block_size <<= (s->fmt_bits == 16);
+    if (!s->dma_auto) {
+        /* It is clear that for DOOM and auto-init this value
+           shouldn't take stereo into account, while Miles Sound Systems
+           setsound.exe with single transfer mode wouldn't work without it
+           wonders of SB16 yet again */
+        s->block_size <<= s->fmt_stereo;
+    }
+
+    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
+            "dma %d, auto %d, fifo %d, high %d\n",
+            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
+            s->block_size, s->dma_auto, s->fifo, s->highspeed);
+
+    if (16 == s->fmt_bits) {
+        if (s->fmt_signed) {
+            s->fmt = AUD_FMT_S16;
+        }
+        else {
+            s->fmt = AUD_FMT_U16;
+        }
+    }
+    else {
+        if (s->fmt_signed) {
+            s->fmt = AUD_FMT_S8;
+        }
+        else {
+            s->fmt = AUD_FMT_U8;
+        }
+    }
+
+    s->left_till_irq = s->block_size;
+
+    s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
+    s->highspeed = 0;
+    s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
+
+    if (s->freq) {
+        struct audsettings as;
+
+        s->audio_free = 0;
+
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as
+            );
+    }
+
+    control (s, 1);
+    speaker (s, 1);
+}
+
+static inline void dsp_out_data (SB16State *s, uint8_t val)
+{
+    ldebug ("outdata %#x\n", val);
+    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
+        s->out_data[s->out_data_len++] = val;
+    }
+}
+
+static inline uint8_t dsp_get_data (SB16State *s)
+{
+    if (s->in_index) {
+        return s->in2_data[--s->in_index];
+    }
+    else {
+        dolog ("buffer underflow\n");
+        return 0;
+    }
+}
+
+static void command (SB16State *s, uint8_t cmd)
+{
+    ldebug ("command %#x\n", cmd);
+
+    if (cmd > 0xaf && cmd < 0xd0) {
+        if (cmd & 8) {
+            dolog ("ADC not yet supported (command %#x)\n", cmd);
+        }
+
+        switch (cmd >> 4) {
+        case 11:
+        case 12:
+            break;
+        default:
+            dolog ("%#x wrong bits\n", cmd);
+        }
+        s->needed_bytes = 3;
+    }
+    else {
+        s->needed_bytes = 0;
+
+        switch (cmd) {
+        case 0x03:
+            dsp_out_data (s, 0x10); /* s->csp_param); */
+            goto warn;
+
+        case 0x04:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x05:
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x08:
+            /* __asm__ ("int3"); */
+            goto warn;
+
+        case 0x0e:
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x09:
+            dsp_out_data (s, 0xf8);
+            goto warn;
+
+        case 0x0f:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x10:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x14:
+            s->needed_bytes = 2;
+            s->block_size = 0;
+            break;
+
+        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
+            dma_cmd8 (s, DMA8_AUTO, -1);
+            break;
+
+        case 0x20:              /* Direct ADC, Juice/PL */
+            dsp_out_data (s, 0xff);
+            goto warn;
+
+        case 0x35:
+            dolog ("0x35 - MIDI command not implemented\n");
+            break;
+
+        case 0x40:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 1;
+            break;
+
+        case 0x41:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 2;
+            break;
+
+        case 0x42:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x45:
+            dsp_out_data (s, 0xaa);
+            goto warn;
+
+        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
+            break;
+
+        case 0x48:
+            s->needed_bytes = 2;
+            break;
+
+        case 0x74:
+            s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
+            dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
+            break;
+
+        case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
+            break;
+
+        case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x7d:
+            dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
+            dolog ("not implemented\n");
+            break;
+
+        case 0x7f:
+            dolog (
+                "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
+                );
+            dolog ("not implemented\n");
+            break;
+
+        case 0x80:
+            s->needed_bytes = 2;
+            break;
+
+        case 0x90:
+        case 0x91:
+            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
+            break;
+
+        case 0xd0:              /* halt DMA operation. 8bit */
+            control (s, 0);
+            break;
+
+        case 0xd1:              /* speaker on */
+            speaker (s, 1);
+            break;
+
+        case 0xd3:              /* speaker off */
+            speaker (s, 0);
+            break;
+
+        case 0xd4:              /* continue DMA operation. 8bit */
+            /* KQ6 (or maybe Sierras audblst.drv in general) resets
+               the frequency between halt/continue */
+            continue_dma8 (s);
+            break;
+
+        case 0xd5:              /* halt DMA operation. 16bit */
+            control (s, 0);
+            break;
+
+        case 0xd6:              /* continue DMA operation. 16bit */
+            control (s, 1);
+            break;
+
+        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
+            s->dma_auto = 0;
+            break;
+
+        case 0xda:              /* exit auto-init DMA after this block. 8bit */
+            s->dma_auto = 0;
+            break;
+
+        case 0xe0:              /* DSP identification */
+            s->needed_bytes = 1;
+            break;
+
+        case 0xe1:
+            dsp_out_data (s, s->ver & 0xff);
+            dsp_out_data (s, s->ver >> 8);
+            break;
+
+        case 0xe2:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0xe3:
+            {
+                int i;
+                for (i = sizeof (e3) - 1; i >= 0; --i)
+                    dsp_out_data (s, e3[i]);
+            }
+            break;
+
+        case 0xe4:              /* write test reg */
+            s->needed_bytes = 1;
+            break;
+
+        case 0xe7:
+            dolog ("Attempt to probe for ESS (0xe7)?\n");
+            break;
+
+        case 0xe8:              /* read test reg */
+            dsp_out_data (s, s->test_reg);
+            break;
+
+        case 0xf2:
+        case 0xf3:
+            dsp_out_data (s, 0xaa);
+            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
+            qemu_irq_raise (s->pic);
+            break;
+
+        case 0xf9:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0xfa:
+            dsp_out_data (s, 0);
+            goto warn;
+
+        case 0xfc:              /* FIXME */
+            dsp_out_data (s, 0);
+            goto warn;
+
+        default:
+            dolog ("Unrecognized command %#x\n", cmd);
+            break;
+        }
+    }
+
+    if (!s->needed_bytes) {
+        ldebug ("\n");
+    }
+
+ exit:
+    if (!s->needed_bytes) {
+        s->cmd = -1;
+    }
+    else {
+        s->cmd = cmd;
+    }
+    return;
+
+ warn:
+    dolog ("warning: command %#x,%d is not truly understood yet\n",
+           cmd, s->needed_bytes);
+    goto exit;
+
+}
+
+static uint16_t dsp_get_lohi (SB16State *s)
+{
+    uint8_t hi = dsp_get_data (s);
+    uint8_t lo = dsp_get_data (s);
+    return (hi << 8) | lo;
+}
+
+static uint16_t dsp_get_hilo (SB16State *s)
+{
+    uint8_t lo = dsp_get_data (s);
+    uint8_t hi = dsp_get_data (s);
+    return (hi << 8) | lo;
+}
+
+static void complete (SB16State *s)
+{
+    int d0, d1, d2;
+    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
+            s->cmd, s->in_index, s->needed_bytes);
+
+    if (s->cmd > 0xaf && s->cmd < 0xd0) {
+        d2 = dsp_get_data (s);
+        d1 = dsp_get_data (s);
+        d0 = dsp_get_data (s);
+
+        if (s->cmd & 8) {
+            dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
+                   s->cmd, d0, d1, d2);
+        }
+        else {
+            ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
+                    s->cmd, d0, d1, d2);
+            dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
+        }
+    }
+    else {
+        switch (s->cmd) {
+        case 0x04:
+            s->csp_mode = dsp_get_data (s);
+            s->csp_reg83r = 0;
+            s->csp_reg83w = 0;
+            ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
+            break;
+
+        case 0x05:
+            s->csp_param = dsp_get_data (s);
+            s->csp_value = dsp_get_data (s);
+            ldebug ("CSP command 0x05: param=%#x value=%#x\n",
+                    s->csp_param,
+                    s->csp_value);
+            break;
+
+        case 0x0e:
+            d0 = dsp_get_data (s);
+            d1 = dsp_get_data (s);
+            ldebug ("write CSP register %d <- %#x\n", d1, d0);
+            if (d1 == 0x83) {
+                ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
+                s->csp_reg83[s->csp_reg83r % 4] = d0;
+                s->csp_reg83r += 1;
+            }
+            else {
+                s->csp_regs[d1] = d0;
+            }
+            break;
+
+        case 0x0f:
+            d0 = dsp_get_data (s);
+            ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
+                    d0, s->csp_regs[d0], s->csp_mode);
+            if (d0 == 0x83) {
+                ldebug ("0x83[%d] -> %#x\n",
+                        s->csp_reg83w,
+                        s->csp_reg83[s->csp_reg83w % 4]);
+                dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
+                s->csp_reg83w += 1;
+            }
+            else {
+                dsp_out_data (s, s->csp_regs[d0]);
+            }
+            break;
+
+        case 0x10:
+            d0 = dsp_get_data (s);
+            dolog ("cmd 0x10 d0=%#x\n", d0);
+            break;
+
+        case 0x14:
+            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
+            break;
+
+        case 0x40:
+            s->time_const = dsp_get_data (s);
+            ldebug ("set time const %d\n", s->time_const);
+            break;
+
+        case 0x42:              /* FT2 sets output freq with this, go figure */
+#if 0
+            dolog ("cmd 0x42 might not do what it think it should\n");
+#endif
+        case 0x41:
+            s->freq = dsp_get_hilo (s);
+            ldebug ("set freq %d\n", s->freq);
+            break;
+
+        case 0x48:
+            s->block_size = dsp_get_lohi (s) + 1;
+            ldebug ("set dma block len %d\n", s->block_size);
+            break;
+
+        case 0x74:
+        case 0x75:
+        case 0x76:
+        case 0x77:
+            /* ADPCM stuff, ignore */
+            break;
+
+        case 0x80:
+            {
+                int freq, samples, bytes;
+                int64_t ticks;
+
+                freq = s->freq > 0 ? s->freq : 11025;
+                samples = dsp_get_lohi (s) + 1;
+                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
+                ticks = muldiv64 (bytes, get_ticks_per_sec (), freq);
+                if (ticks < get_ticks_per_sec () / 1024) {
+                    qemu_irq_raise (s->pic);
+                }
+                else {
+                    if (s->aux_ts) {
+                        qemu_mod_timer (
+                            s->aux_ts,
+                            qemu_get_clock_ns (vm_clock) + ticks
+                            );
+                    }
+                }
+                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
+            }
+            break;
+
+        case 0xe0:
+            d0 = dsp_get_data (s);
+            s->out_data_len = 0;
+            ldebug ("E0 data = %#x\n", d0);
+            dsp_out_data (s, ~d0);
+            break;
+
+        case 0xe2:
+#ifdef DEBUG
+            d0 = dsp_get_data (s);
+            dolog ("E2 = %#x\n", d0);
+#endif
+            break;
+
+        case 0xe4:
+            s->test_reg = dsp_get_data (s);
+            break;
+
+        case 0xf9:
+            d0 = dsp_get_data (s);
+            ldebug ("command 0xf9 with %#x\n", d0);
+            switch (d0) {
+            case 0x0e:
+                dsp_out_data (s, 0xff);
+                break;
+
+            case 0x0f:
+                dsp_out_data (s, 0x07);
+                break;
+
+            case 0x37:
+                dsp_out_data (s, 0x38);
+                break;
+
+            default:
+                dsp_out_data (s, 0x00);
+                break;
+            }
+            break;
+
+        default:
+            dolog ("complete: unrecognized command %#x\n", s->cmd);
+            return;
+        }
+    }
+
+    ldebug ("\n");
+    s->cmd = -1;
+    return;
+}
+
+static void legacy_reset (SB16State *s)
+{
+    struct audsettings as;
+
+    s->freq = 11025;
+    s->fmt_signed = 0;
+    s->fmt_bits = 8;
+    s->fmt_stereo = 0;
+
+    as.freq = s->freq;
+    as.nchannels = 1;
+    as.fmt = AUD_FMT_U8;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "sb16",
+        s,
+        SB_audio_callback,
+        &as
+        );
+
+    /* Not sure about that... */
+    /* AUD_set_active_out (s->voice, 1); */
+}
+
+static void reset (SB16State *s)
+{
+    qemu_irq_lower (s->pic);
+    if (s->dma_auto) {
+        qemu_irq_raise (s->pic);
+        qemu_irq_lower (s->pic);
+    }
+
+    s->mixer_regs[0x82] = 0;
+    s->dma_auto = 0;
+    s->in_index = 0;
+    s->out_data_len = 0;
+    s->left_till_irq = 0;
+    s->needed_bytes = 0;
+    s->block_size = -1;
+    s->nzero = 0;
+    s->highspeed = 0;
+    s->v2x6 = 0;
+    s->cmd = -1;
+
+    dsp_out_data (s, 0xaa);
+    speaker (s, 0);
+    control (s, 0);
+    legacy_reset (s);
+}
+
+static IO_WRITE_PROTO (dsp_write)
+{
+    SB16State *s = opaque;
+    int iport;
+
+    iport = nport - s->port;
+
+    ldebug ("write %#x <- %#x\n", nport, val);
+    switch (iport) {
+    case 0x06:
+        switch (val) {
+        case 0x00:
+            if (s->v2x6 == 1) {
+                reset (s);
+            }
+            s->v2x6 = 0;
+            break;
+
+        case 0x01:
+        case 0x03:              /* FreeBSD kludge */
+            s->v2x6 = 1;
+            break;
+
+        case 0xc6:
+            s->v2x6 = 0;        /* Prince of Persia, csp.sys, diagnose.exe */
+            break;
+
+        case 0xb8:              /* Panic */
+            reset (s);
+            break;
+
+        case 0x39:
+            dsp_out_data (s, 0x38);
+            reset (s);
+            s->v2x6 = 0x39;
+            break;
+
+        default:
+            s->v2x6 = val;
+            break;
+        }
+        break;
+
+    case 0x0c:                  /* write data or command | write status */
+/*         if (s->highspeed) */
+/*             break; */
+
+        if (0 == s->needed_bytes) {
+            command (s, val);
+#if 0
+            if (0 == s->needed_bytes) {
+                log_dsp (s);
+            }
+#endif
+        }
+        else {
+            if (s->in_index == sizeof (s->in2_data)) {
+                dolog ("in data overrun\n");
+            }
+            else {
+                s->in2_data[s->in_index++] = val;
+                if (s->in_index == s->needed_bytes) {
+                    s->needed_bytes = 0;
+                    complete (s);
+#if 0
+                    log_dsp (s);
+#endif
+                }
+            }
+        }
+        break;
+
+    default:
+        ldebug ("(nport=%#x, val=%#x)\n", nport, val);
+        break;
+    }
+}
+
+static IO_READ_PROTO (dsp_read)
+{
+    SB16State *s = opaque;
+    int iport, retval, ack = 0;
+
+    iport = nport - s->port;
+
+    switch (iport) {
+    case 0x06:                  /* reset */
+        retval = 0xff;
+        break;
+
+    case 0x0a:                  /* read data */
+        if (s->out_data_len) {
+            retval = s->out_data[--s->out_data_len];
+            s->last_read_byte = retval;
+        }
+        else {
+            if (s->cmd != -1) {
+                dolog ("empty output buffer for command %#x\n",
+                       s->cmd);
+            }
+            retval = s->last_read_byte;
+            /* goto error; */
+        }
+        break;
+
+    case 0x0c:                  /* 0 can write */
+        retval = s->can_write ? 0 : 0x80;
+        break;
+
+    case 0x0d:                  /* timer interrupt clear */
+        /* dolog ("timer interrupt clear\n"); */
+        retval = 0;
+        break;
+
+    case 0x0e:                  /* data available status | irq 8 ack */
+        retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
+        if (s->mixer_regs[0x82] & 1) {
+            ack = 1;
+            s->mixer_regs[0x82] &= 1;
+            qemu_irq_lower (s->pic);
+        }
+        break;
+
+    case 0x0f:                  /* irq 16 ack */
+        retval = 0xff;
+        if (s->mixer_regs[0x82] & 2) {
+            ack = 1;
+            s->mixer_regs[0x82] &= 2;
+            qemu_irq_lower (s->pic);
+        }
+        break;
+
+    default:
+        goto error;
+    }
+
+    if (!ack) {
+        ldebug ("read %#x -> %#x\n", nport, retval);
+    }
+
+    return retval;
+
+ error:
+    dolog ("warning: dsp_read %#x error\n", nport);
+    return 0xff;
+}
+
+static void reset_mixer (SB16State *s)
+{
+    int i;
+
+    memset (s->mixer_regs, 0xff, 0x7f);
+    memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
+
+    s->mixer_regs[0x02] = 4;    /* master volume 3bits */
+    s->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
+    s->mixer_regs[0x08] = 0;    /* CD volume 3bits */
+    s->mixer_regs[0x0a] = 0;    /* voice volume 2bits */
+
+    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
+    s->mixer_regs[0x0c] = 0;
+
+    /* d5=output filt, d1=stereo switch */
+    s->mixer_regs[0x0e] = 0;
+
+    /* voice volume L d5,d7, R d1,d3 */
+    s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
+    /* master ... */
+    s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
+    /* MIDI ... */
+    s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
+
+    for (i = 0x30; i < 0x48; i++) {
+        s->mixer_regs[i] = 0x20;
+    }
+}
+
+static IO_WRITE_PROTO (mixer_write_indexb)
+{
+    SB16State *s = opaque;
+    (void) nport;
+    s->mixer_nreg = val;
+}
+
+static IO_WRITE_PROTO (mixer_write_datab)
+{
+    SB16State *s = opaque;
+
+    (void) nport;
+    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
+
+    switch (s->mixer_nreg) {
+    case 0x00:
+        reset_mixer (s);
+        break;
+
+    case 0x80:
+        {
+            int irq = irq_of_magic (val);
+            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
+            if (irq > 0) {
+                s->irq = irq;
+            }
+        }
+        break;
+
+    case 0x81:
+        {
+            int dma, hdma;
+
+            dma = ctz32 (val & 0xf);
+            hdma = ctz32 (val & 0xf0);
+            if (dma != s->dma || hdma != s->hdma) {
+                dolog (
+                    "attempt to change DMA "
+                    "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
+                    dma, s->dma, hdma, s->hdma, val);
+            }
+#if 0
+            s->dma = dma;
+            s->hdma = hdma;
+#endif
+        }
+        break;
+
+    case 0x82:
+        dolog ("attempt to write into IRQ status register (val=%#x)\n",
+               val);
+        return;
+
+    default:
+        if (s->mixer_nreg >= 0x80) {
+            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
+        }
+        break;
+    }
+
+    s->mixer_regs[s->mixer_nreg] = val;
+}
+
+static IO_WRITE_PROTO (mixer_write_indexw)
+{
+    mixer_write_indexb (opaque, nport, val & 0xff);
+    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
+}
+
+static IO_READ_PROTO (mixer_read)
+{
+    SB16State *s = opaque;
+
+    (void) nport;
+#ifndef DEBUG_SB16_MOST
+    if (s->mixer_nreg != 0x82) {
+        ldebug ("mixer_read[%#x] -> %#x\n",
+                s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+    }
+#else
+    ldebug ("mixer_read[%#x] -> %#x\n",
+            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+#endif
+    return s->mixer_regs[s->mixer_nreg];
+}
+
+static int write_audio (SB16State *s, int nchan, int dma_pos,
+                        int dma_len, int len)
+{
+    int temp, net;
+    uint8_t tmpbuf[4096];
+
+    temp = len;
+    net = 0;
+
+    while (temp) {
+        int left = dma_len - dma_pos;
+        int copied;
+        size_t to_copy;
+
+        to_copy = audio_MIN (temp, left);
+        if (to_copy > sizeof (tmpbuf)) {
+            to_copy = sizeof (tmpbuf);
+        }
+
+        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
+        copied = AUD_write (s->voice, tmpbuf, copied);
+
+        temp -= copied;
+        dma_pos = (dma_pos + copied) % dma_len;
+        net += copied;
+
+        if (!copied) {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    SB16State *s = opaque;
+    int till, copy, written, free;
+
+    if (s->block_size <= 0) {
+        dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
+               s->block_size, nchan, dma_pos, dma_len);
+        return dma_pos;
+    }
+
+    if (s->left_till_irq < 0) {
+        s->left_till_irq = s->block_size;
+    }
+
+    if (s->voice) {
+        free = s->audio_free & ~s->align;
+        if ((free <= 0) || !dma_len) {
+            return dma_pos;
+        }
+    }
+    else {
+        free = dma_len;
+    }
+
+    copy = free;
+    till = s->left_till_irq;
+
+#ifdef DEBUG_SB16_MOST
+    dolog ("pos:%06d %d till:%d len:%d\n",
+           dma_pos, free, till, dma_len);
+#endif
+
+    if (till <= copy) {
+        if (0 == s->dma_auto) {
+            copy = till;
+        }
+    }
+
+    written = write_audio (s, nchan, dma_pos, dma_len, copy);
+    dma_pos = (dma_pos + written) % dma_len;
+    s->left_till_irq -= written;
+
+    if (s->left_till_irq <= 0) {
+        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
+        qemu_irq_raise (s->pic);
+        if (0 == s->dma_auto) {
+            control (s, 0);
+            speaker (s, 0);
+        }
+    }
+
+#ifdef DEBUG_SB16_MOST
+    ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
+            dma_pos, free, dma_len, s->left_till_irq, copy, written,
+            s->block_size);
+#endif
+
+    while (s->left_till_irq <= 0) {
+        s->left_till_irq = s->block_size + s->left_till_irq;
+    }
+
+    return dma_pos;
+}
+
+static void SB_audio_callback (void *opaque, int free)
+{
+    SB16State *s = opaque;
+    s->audio_free = free;
+}
+
+static int sb16_post_load (void *opaque, int version_id)
+{
+    SB16State *s = opaque;
+
+    if (s->voice) {
+        AUD_close_out (&s->card, s->voice);
+        s->voice = NULL;
+    }
+
+    if (s->dma_running) {
+        if (s->freq) {
+            struct audsettings as;
+
+            s->audio_free = 0;
+
+            as.freq = s->freq;
+            as.nchannels = 1 << s->fmt_stereo;
+            as.fmt = s->fmt;
+            as.endianness = 0;
+
+            s->voice = AUD_open_out (
+                &s->card,
+                s->voice,
+                "sb16",
+                s,
+                SB_audio_callback,
+                &as
+                );
+        }
+
+        control (s, 1);
+        speaker (s, s->speaker);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_sb16 = {
+    .name = "sb16",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = sb16_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(irq, SB16State),
+        VMSTATE_UINT32(dma, SB16State),
+        VMSTATE_UINT32(hdma, SB16State),
+        VMSTATE_UINT32(port, SB16State),
+        VMSTATE_UINT32(ver, SB16State),
+        VMSTATE_INT32(in_index, SB16State),
+        VMSTATE_INT32(out_data_len, SB16State),
+        VMSTATE_INT32(fmt_stereo, SB16State),
+        VMSTATE_INT32(fmt_signed, SB16State),
+        VMSTATE_INT32(fmt_bits, SB16State),
+        VMSTATE_UINT32(fmt, SB16State),
+        VMSTATE_INT32(dma_auto, SB16State),
+        VMSTATE_INT32(block_size, SB16State),
+        VMSTATE_INT32(fifo, SB16State),
+        VMSTATE_INT32(freq, SB16State),
+        VMSTATE_INT32(time_const, SB16State),
+        VMSTATE_INT32(speaker, SB16State),
+        VMSTATE_INT32(needed_bytes, SB16State),
+        VMSTATE_INT32(cmd, SB16State),
+        VMSTATE_INT32(use_hdma, SB16State),
+        VMSTATE_INT32(highspeed, SB16State),
+        VMSTATE_INT32(can_write, SB16State),
+        VMSTATE_INT32(v2x6, SB16State),
+
+        VMSTATE_UINT8(csp_param, SB16State),
+        VMSTATE_UINT8(csp_value, SB16State),
+        VMSTATE_UINT8(csp_mode, SB16State),
+        VMSTATE_UINT8(csp_param, SB16State),
+        VMSTATE_BUFFER(csp_regs, SB16State),
+        VMSTATE_UINT8(csp_index, SB16State),
+        VMSTATE_BUFFER(csp_reg83, SB16State),
+        VMSTATE_INT32(csp_reg83r, SB16State),
+        VMSTATE_INT32(csp_reg83w, SB16State),
+
+        VMSTATE_BUFFER(in2_data, SB16State),
+        VMSTATE_BUFFER(out_data, SB16State),
+        VMSTATE_UINT8(test_reg, SB16State),
+        VMSTATE_UINT8(last_read_byte, SB16State),
+
+        VMSTATE_INT32(nzero, SB16State),
+        VMSTATE_INT32(left_till_irq, SB16State),
+        VMSTATE_INT32(dma_running, SB16State),
+        VMSTATE_INT32(bytes_per_second, SB16State),
+        VMSTATE_INT32(align, SB16State),
+
+        VMSTATE_INT32(mixer_nreg, SB16State),
+        VMSTATE_BUFFER(mixer_regs, SB16State),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int sb16_initfn (ISADevice *dev)
+{
+    static const uint8_t dsp_write_ports[] = {0x6, 0xc};
+    static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
+    SB16State *s;
+    int i;
+
+    s = DO_UPCAST (SB16State, dev, dev);
+
+    s->cmd = -1;
+    isa_init_irq (dev, &s->pic, s->irq);
+
+    s->mixer_regs[0x80] = magic_of_irq (s->irq);
+    s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
+    s->mixer_regs[0x82] = 2 << 5;
+
+    s->csp_regs[5] = 1;
+    s->csp_regs[9] = 0xf8;
+
+    reset_mixer (s);
+    s->aux_ts = qemu_new_timer_ns (vm_clock, aux_timer, s);
+    if (!s->aux_ts) {
+        dolog ("warning: Could not create auxiliary timer\n");
+    }
+
+    for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
+        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
+        isa_init_ioport(dev, s->port + dsp_write_ports[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
+        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
+        isa_init_ioport(dev, s->port + dsp_read_ports[i]);
+    }
+
+    register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
+    register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
+    isa_init_ioport(dev, s->port + 0x4);
+    register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
+    register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
+    isa_init_ioport(dev, s->port + 0x5);
+
+    DMA_register_channel (s->hdma, SB_read_DMA, s);
+    DMA_register_channel (s->dma, SB_read_DMA, s);
+    s->can_write = 1;
+
+    AUD_register_card ("sb16", &s->card);
+    return 0;
+}
+
+int SB16_init (qemu_irq *pic)
+{
+    isa_create_simple ("sb16");
+    return 0;
+}
+
+static ISADeviceInfo sb16_info = {
+    .qdev.name     = "sb16",
+    .qdev.desc     = "Creative Sound Blaster 16",
+    .qdev.size     = sizeof (SB16State),
+    .qdev.vmsd     = &vmstate_sb16,
+    .init          = sb16_initfn,
+    .qdev.props    = (Property[]) {
+        DEFINE_PROP_HEX32  ("version", SB16State, ver,  0x0405), /* 4.5 */
+        DEFINE_PROP_HEX32  ("iobase",  SB16State, port, 0x220),
+        DEFINE_PROP_UINT32 ("irq",     SB16State, irq,  5),
+        DEFINE_PROP_UINT32 ("dma",     SB16State, dma,  1),
+        DEFINE_PROP_UINT32 ("dma16",   SB16State, hdma, 5),
+        DEFINE_PROP_END_OF_LIST (),
+    },
+};
+
+static void sb16_register (void)
+{
+    isa_qdev_register (&sb16_info);
+}
+device_init (sb16_register)
diff --git a/qemu-0.15.x/hw/sbi.c b/qemu-0.15.x/hw/sbi.c
new file mode 100644
index 0000000..53f66f2
--- /dev/null
+++ b/qemu-0.15.x/hw/sbi.c
@@ -0,0 +1,148 @@
+/*
+ * QEMU Sparc SBI interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 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 "sysbus.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define MAX_CPUS 16
+
+#define SBI_NREGS 16
+
+typedef struct SBIState {
+    SysBusDevice busdev;
+    uint32_t regs[SBI_NREGS];
+    uint32_t intreg_pending[MAX_CPUS];
+    qemu_irq cpu_irqs[MAX_CPUS];
+    uint32_t pil_out[MAX_CPUS];
+} SBIState;
+
+#define SBI_SIZE (SBI_NREGS * 4)
+
+static void sbi_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static uint32_t sbi_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SBIState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sbi_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SBIState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
+    switch (saddr) {
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sbi_mem_read[3] = {
+    NULL,
+    NULL,
+    sbi_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const sbi_mem_write[3] = {
+    NULL,
+    NULL,
+    sbi_mem_writel,
+};
+
+static const VMStateDescription vmstate_sbi = {
+    .name ="sbi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(intreg_pending, SBIState, MAX_CPUS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sbi_reset(DeviceState *d)
+{
+    SBIState *s = container_of(d, SBIState, busdev.qdev);
+    unsigned int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->intreg_pending[i] = 0;
+    }
+}
+
+static int sbi_init1(SysBusDevice *dev)
+{
+    SBIState *s = FROM_SYSBUS(SBIState, dev);
+    int sbi_io_memory;
+    unsigned int i;
+
+    qdev_init_gpio_in(&dev->qdev, sbi_set_irq, 32 + MAX_CPUS);
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    sbi_io_memory = cpu_register_io_memory(sbi_mem_read, sbi_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, SBI_SIZE, sbi_io_memory);
+
+    return 0;
+}
+
+static SysBusDeviceInfo sbi_info = {
+    .init = sbi_init1,
+    .qdev.name  = "sbi",
+    .qdev.size  = sizeof(SBIState),
+    .qdev.vmsd  = &vmstate_sbi,
+    .qdev.reset = sbi_reset,
+};
+
+static void sbi_register_devices(void)
+{
+    sysbus_register_withprop(&sbi_info);
+}
+
+device_init(sbi_register_devices)
diff --git a/qemu-0.15.x/hw/scsi-bus.c b/qemu-0.15.x/hw/scsi-bus.c
new file mode 100644
index 0000000..8b1a412
--- /dev/null
+++ b/qemu-0.15.x/hw/scsi-bus.c
@@ -0,0 +1,734 @@
+#include "hw.h"
+#include "qemu-error.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "qdev.h"
+#include "blockdev.h"
+#include "trace.h"
+
+static char *scsibus_get_fw_dev_path(DeviceState *dev);
+
+static struct BusInfo scsi_bus_info = {
+    .name  = "SCSI",
+    .size  = sizeof(SCSIBus),
+    .get_fw_dev_path = scsibus_get_fw_dev_path,
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+static int next_scsi_bus;
+
+/* Create a scsi bus, and attach devices to it.  */
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
+                  const SCSIBusOps *ops)
+{
+    qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
+    bus->busnr = next_scsi_bus++;
+    bus->tcq = tcq;
+    bus->ndev = ndev;
+    bus->ops = ops;
+    bus->qbus.allow_hotplug = 1;
+}
+
+static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+    SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+    int rc = -1;
+
+    if (dev->id == -1) {
+        for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
+            if (bus->devs[dev->id] == NULL)
+                break;
+        }
+    }
+    if (dev->id >= bus->ndev) {
+        error_report("bad scsi device id: %d", dev->id);
+        goto err;
+    }
+
+    if (bus->devs[dev->id]) {
+        qdev_free(&bus->devs[dev->id]->qdev);
+    }
+    bus->devs[dev->id] = dev;
+
+    dev->info = info;
+    QTAILQ_INIT(&dev->requests);
+    rc = dev->info->init(dev);
+    if (rc != 0) {
+        bus->devs[dev->id] = NULL;
+    }
+
+err:
+    return rc;
+}
+
+static int scsi_qdev_exit(DeviceState *qdev)
+{
+    SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+
+    assert(bus->devs[dev->id] != NULL);
+    if (bus->devs[dev->id]->info->destroy) {
+        bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
+    }
+    bus->devs[dev->id] = NULL;
+    return 0;
+}
+
+void scsi_qdev_register(SCSIDeviceInfo *info)
+{
+    info->qdev.bus_info = &scsi_bus_info;
+    info->qdev.init     = scsi_qdev_init;
+    info->qdev.unplug   = qdev_simple_unplug_cb;
+    info->qdev.exit     = scsi_qdev_exit;
+    qdev_register(&info->qdev);
+}
+
+/* handle legacy '-drive if=scsi,...' cmd line args */
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+                                      int unit, bool removable)
+{
+    const char *driver;
+    DeviceState *dev;
+
+    driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
+    dev = qdev_create(&bus->qbus, driver);
+    qdev_prop_set_uint32(dev, "scsi-id", unit);
+    if (qdev_prop_exists(dev, "removable")) {
+        qdev_prop_set_bit(dev, "removable", removable);
+    }
+    if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
+        qdev_free(dev);
+        return NULL;
+    }
+    if (qdev_init(dev) < 0)
+        return NULL;
+    return DO_UPCAST(SCSIDevice, qdev, dev);
+}
+
+int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
+{
+    Location loc;
+    DriveInfo *dinfo;
+    int res = 0, unit;
+
+    loc_push_none(&loc);
+    for (unit = 0; unit < bus->ndev; unit++) {
+        dinfo = drive_get(IF_SCSI, bus->busnr, unit);
+        if (dinfo == NULL) {
+            continue;
+        }
+        qemu_opts_loc_restore(dinfo->opts);
+        if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) {
+            res = -1;
+            break;
+        }
+    }
+    loc_pop(&loc);
+    return res;
+}
+
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+                            uint32_t lun, void *hba_private)
+{
+    SCSIRequest *req;
+
+    req = qemu_mallocz(size);
+    req->refcount = 1;
+    req->bus = scsi_bus_from_device(d);
+    req->dev = d;
+    req->tag = tag;
+    req->lun = lun;
+    req->hba_private = hba_private;
+    req->status = -1;
+    trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
+    return req;
+}
+
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          void *hba_private)
+{
+    return d->info->alloc_req(d, tag, lun, hba_private);
+}
+
+uint8_t *scsi_req_get_buf(SCSIRequest *req)
+{
+    return req->dev->info->get_buf(req);
+}
+
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
+{
+    if (req->dev->info->get_sense) {
+        return req->dev->info->get_sense(req, buf, len);
+    } else {
+        return 0;
+    }
+}
+
+int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf)
+{
+    int32_t rc;
+
+    assert(!req->enqueued);
+    scsi_req_ref(req);
+    req->enqueued = true;
+    QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+
+    scsi_req_ref(req);
+    rc = req->dev->info->send_command(req, buf);
+    scsi_req_unref(req);
+    return rc;
+}
+
+static void scsi_req_dequeue(SCSIRequest *req)
+{
+    trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
+    if (req->enqueued) {
+        QTAILQ_REMOVE(&req->dev->requests, req, next);
+        req->enqueued = false;
+        scsi_req_unref(req);
+    }
+}
+
+static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
+{
+    switch (cmd[0] >> 5) {
+    case 0:
+        req->cmd.xfer = cmd[4];
+        req->cmd.len = 6;
+        /* length 0 means 256 blocks */
+        if (req->cmd.xfer == 0)
+            req->cmd.xfer = 256;
+        break;
+    case 1:
+    case 2:
+        req->cmd.xfer = cmd[8] | (cmd[7] << 8);
+        req->cmd.len = 10;
+        break;
+    case 4:
+        req->cmd.xfer = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24);
+        req->cmd.len = 16;
+        break;
+    case 5:
+        req->cmd.xfer = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24);
+        req->cmd.len = 12;
+        break;
+    default:
+        trace_scsi_req_parse_bad(req->dev->id, req->lun, req->tag, cmd[0]);
+        return -1;
+    }
+
+    switch(cmd[0]) {
+    case TEST_UNIT_READY:
+    case REZERO_UNIT:
+    case START_STOP:
+    case SEEK_6:
+    case WRITE_FILEMARKS:
+    case SPACE:
+    case RESERVE:
+    case RELEASE:
+    case ERASE:
+    case ALLOW_MEDIUM_REMOVAL:
+    case VERIFY:
+    case SEEK_10:
+    case SYNCHRONIZE_CACHE:
+    case LOCK_UNLOCK_CACHE:
+    case LOAD_UNLOAD:
+    case SET_CD_SPEED:
+    case SET_LIMITS:
+    case WRITE_LONG:
+    case MOVE_MEDIUM:
+    case UPDATE_BLOCK:
+        req->cmd.xfer = 0;
+        break;
+    case MODE_SENSE:
+        break;
+    case WRITE_SAME:
+        req->cmd.xfer = 1;
+        break;
+    case READ_CAPACITY:
+        req->cmd.xfer = 8;
+        break;
+    case READ_BLOCK_LIMITS:
+        req->cmd.xfer = 6;
+        break;
+    case READ_POSITION:
+        req->cmd.xfer = 20;
+        break;
+    case SEND_VOLUME_TAG:
+        req->cmd.xfer *= 40;
+        break;
+    case MEDIUM_SCAN:
+        req->cmd.xfer *= 8;
+        break;
+    case WRITE_10:
+    case WRITE_VERIFY:
+    case WRITE_6:
+    case WRITE_12:
+    case WRITE_VERIFY_12:
+    case WRITE_16:
+    case WRITE_VERIFY_16:
+        req->cmd.xfer *= req->dev->blocksize;
+        break;
+    case READ_10:
+    case READ_6:
+    case READ_REVERSE:
+    case RECOVER_BUFFERED_DATA:
+    case READ_12:
+    case READ_16:
+        req->cmd.xfer *= req->dev->blocksize;
+        break;
+    case INQUIRY:
+        req->cmd.xfer = cmd[4] | (cmd[3] << 8);
+        break;
+    case MAINTENANCE_OUT:
+    case MAINTENANCE_IN:
+        if (req->dev->type == TYPE_ROM) {
+            /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
+            req->cmd.xfer = cmd[9] | (cmd[8] << 8);
+        }
+        break;
+    }
+    return 0;
+}
+
+static int scsi_req_stream_length(SCSIRequest *req, uint8_t *cmd)
+{
+    switch(cmd[0]) {
+    /* stream commands */
+    case READ_6:
+    case READ_REVERSE:
+    case RECOVER_BUFFERED_DATA:
+    case WRITE_6:
+        req->cmd.len = 6;
+        req->cmd.xfer = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16);
+        if (cmd[1] & 0x01) /* fixed */
+            req->cmd.xfer *= req->dev->blocksize;
+        break;
+    case REWIND:
+    case START_STOP:
+        req->cmd.len = 6;
+        req->cmd.xfer = 0;
+        break;
+    /* generic commands */
+    default:
+        return scsi_req_length(req, cmd);
+    }
+    return 0;
+}
+
+static void scsi_req_xfer_mode(SCSIRequest *req)
+{
+    switch (req->cmd.buf[0]) {
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_VERIFY:
+    case WRITE_12:
+    case WRITE_VERIFY_12:
+    case WRITE_16:
+    case WRITE_VERIFY_16:
+    case COPY:
+    case COPY_VERIFY:
+    case COMPARE:
+    case CHANGE_DEFINITION:
+    case LOG_SELECT:
+    case MODE_SELECT:
+    case MODE_SELECT_10:
+    case SEND_DIAGNOSTIC:
+    case WRITE_BUFFER:
+    case FORMAT_UNIT:
+    case REASSIGN_BLOCKS:
+    case SEARCH_EQUAL:
+    case SEARCH_HIGH:
+    case SEARCH_LOW:
+    case UPDATE_BLOCK:
+    case WRITE_LONG:
+    case WRITE_SAME:
+    case SEARCH_HIGH_12:
+    case SEARCH_EQUAL_12:
+    case SEARCH_LOW_12:
+    case SET_WINDOW:
+    case MEDIUM_SCAN:
+    case SEND_VOLUME_TAG:
+    case WRITE_LONG_2:
+    case PERSISTENT_RESERVE_OUT:
+    case MAINTENANCE_OUT:
+        req->cmd.mode = SCSI_XFER_TO_DEV;
+        break;
+    default:
+        if (req->cmd.xfer)
+            req->cmd.mode = SCSI_XFER_FROM_DEV;
+        else {
+            req->cmd.mode = SCSI_XFER_NONE;
+        }
+        break;
+    }
+}
+
+static uint64_t scsi_req_lba(SCSIRequest *req)
+{
+    uint8_t *buf = req->cmd.buf;
+    uint64_t lba;
+
+    switch (buf[0] >> 5) {
+    case 0:
+        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
+              (((uint64_t) buf[1] & 0x1f) << 16);
+        break;
+    case 1:
+    case 2:
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+        break;
+    case 4:
+        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
+              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
+              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
+              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
+        break;
+    case 5:
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+        break;
+    default:
+        lba = -1;
+
+    }
+    return lba;
+}
+
+int scsi_req_parse(SCSIRequest *req, uint8_t *buf)
+{
+    int rc;
+
+    if (req->dev->type == TYPE_TAPE) {
+        rc = scsi_req_stream_length(req, buf);
+    } else {
+        rc = scsi_req_length(req, buf);
+    }
+    if (rc != 0)
+        return rc;
+
+    memcpy(req->cmd.buf, buf, req->cmd.len);
+    scsi_req_xfer_mode(req);
+    req->cmd.lba = scsi_req_lba(req);
+    trace_scsi_req_parsed(req->dev->id, req->lun, req->tag, buf[0],
+                          req->cmd.mode, req->cmd.xfer);
+    if (req->cmd.lba != -1) {
+        trace_scsi_req_parsed_lba(req->dev->id, req->lun, req->tag, buf[0],
+                              req->cmd.lba);
+    }
+    return 0;
+}
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+const struct SCSISense sense_code_NO_SENSE = {
+    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
+};
+
+/* LUN not ready, Manual intervention required */
+const struct SCSISense sense_code_LUN_NOT_READY = {
+    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
+};
+
+/* LUN not ready, Medium not present */
+const struct SCSISense sense_code_NO_MEDIUM = {
+    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
+};
+
+/* Hardware error, internal target failure */
+const struct SCSISense sense_code_TARGET_FAILURE = {
+    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
+};
+
+/* Illegal request, invalid command operation code */
+const struct SCSISense sense_code_INVALID_OPCODE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
+};
+
+/* Illegal request, LBA out of range */
+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in CDB */
+const struct SCSISense sense_code_INVALID_FIELD = {
+    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
+};
+
+/* Illegal request, LUN not supported */
+const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
+};
+
+/* Command aborted, I/O process terminated */
+const struct SCSISense sense_code_IO_ERROR = {
+    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
+};
+
+/* Command aborted, I_T Nexus loss occurred */
+const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
+    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
+};
+
+/* Command aborted, Logical Unit failure */
+const struct SCSISense sense_code_LUN_FAILURE = {
+    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
+};
+
+/*
+ * scsi_build_sense
+ *
+ * Build a sense buffer
+ */
+int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed)
+{
+    if (!fixed && len < 8) {
+        return 0;
+    }
+
+    memset(buf, 0, len);
+    if (fixed) {
+        /* Return fixed format sense buffer */
+        buf[0] = 0xf0;
+        buf[2] = sense.key;
+        buf[7] = 7;
+        buf[12] = sense.asc;
+        buf[13] = sense.ascq;
+        return MIN(len, 18);
+    } else {
+        /* Return descriptor format sense buffer */
+        buf[0] = 0x72;
+        buf[1] = sense.key;
+        buf[2] = sense.asc;
+        buf[3] = sense.ascq;
+        return 8;
+    }
+}
+
+static const char *scsi_command_name(uint8_t cmd)
+{
+    static const char *names[] = {
+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
+        [ REZERO_UNIT              ] = "REZERO_UNIT",
+        /* REWIND and REZERO_UNIT use the same operation code */
+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS",
+        [ READ_6                   ] = "READ_6",
+        [ WRITE_6                  ] = "WRITE_6",
+        [ SEEK_6                   ] = "SEEK_6",
+        [ READ_REVERSE             ] = "READ_REVERSE",
+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
+        [ SPACE                    ] = "SPACE",
+        [ INQUIRY                  ] = "INQUIRY",
+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
+        [ MODE_SELECT              ] = "MODE_SELECT",
+        [ RESERVE                  ] = "RESERVE",
+        [ RELEASE                  ] = "RELEASE",
+        [ COPY                     ] = "COPY",
+        [ ERASE                    ] = "ERASE",
+        [ MODE_SENSE               ] = "MODE_SENSE",
+        [ START_STOP               ] = "START_STOP",
+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
+
+        [ SET_WINDOW               ] = "SET_WINDOW",
+        [ READ_CAPACITY            ] = "READ_CAPACITY",
+        [ READ_10                  ] = "READ_10",
+        [ WRITE_10                 ] = "WRITE_10",
+        [ SEEK_10                  ] = "SEEK_10",
+        [ WRITE_VERIFY             ] = "WRITE_VERIFY",
+        [ VERIFY                   ] = "VERIFY",
+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
+        [ SEARCH_LOW               ] = "SEARCH_LOW",
+        [ SET_LIMITS               ] = "SET_LIMITS",
+        [ PRE_FETCH                ] = "PRE_FETCH",
+        /* READ_POSITION and PRE_FETCH use the same operation code */
+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA",
+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
+        [ COMPARE                  ] = "COMPARE",
+        [ COPY_VERIFY              ] = "COPY_VERIFY",
+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
+        [ READ_BUFFER              ] = "READ_BUFFER",
+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
+        [ READ_LONG                ] = "READ_LONG",
+        [ WRITE_LONG               ] = "WRITE_LONG",
+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
+        [ WRITE_SAME               ] = "WRITE_SAME",
+        [ READ_TOC                 ] = "READ_TOC",
+        [ LOG_SELECT               ] = "LOG_SELECT",
+        [ LOG_SENSE                ] = "LOG_SENSE",
+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
+        [ RESERVE_10               ] = "RESERVE_10",
+        [ RELEASE_10               ] = "RELEASE_10",
+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+        [ READ_12                  ] = "READ_12",
+        [ WRITE_12                 ] = "WRITE_12",
+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG",
+        [ WRITE_LONG_2             ] = "WRITE_LONG_2",
+
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
+        [ READ_16                  ] = "READ_16",
+        [ WRITE_16                 ] = "WRITE_16",
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+        [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN",
+        [ REPORT_LUNS              ] = "REPORT_LUNS",
+        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
+        [ BLANK                    ] = "BLANK",
+    };
+
+    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
+        return "*UNKNOWN*";
+    return names[cmd];
+}
+
+SCSIRequest *scsi_req_ref(SCSIRequest *req)
+{
+    req->refcount++;
+    return req;
+}
+
+void scsi_req_unref(SCSIRequest *req)
+{
+    if (--req->refcount == 0) {
+        if (req->dev->info->free_req) {
+            req->dev->info->free_req(req);
+        }
+        qemu_free(req);
+    }
+}
+
+/* Tell the device that we finished processing this chunk of I/O.  It
+   will start the next chunk or complete the command.  */
+void scsi_req_continue(SCSIRequest *req)
+{
+    trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
+    if (req->cmd.mode == SCSI_XFER_TO_DEV) {
+        req->dev->info->write_data(req);
+    } else {
+        req->dev->info->read_data(req);
+    }
+}
+
+/* Called by the devices when data is ready for the HBA.  The HBA should
+   start a DMA operation to read or fill the device's data buffer.
+   Once it completes, calling scsi_req_continue will restart I/O.  */
+void scsi_req_data(SCSIRequest *req, int len)
+{
+    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+    req->bus->ops->transfer_data(req, len);
+}
+
+void scsi_req_print(SCSIRequest *req)
+{
+    FILE *fp = stderr;
+    int i;
+
+    fprintf(fp, "[%s id=%d] %s",
+            req->dev->qdev.parent_bus->name,
+            req->dev->id,
+            scsi_command_name(req->cmd.buf[0]));
+    for (i = 1; i < req->cmd.len; i++) {
+        fprintf(fp, " 0x%02x", req->cmd.buf[i]);
+    }
+    switch (req->cmd.mode) {
+    case SCSI_XFER_NONE:
+        fprintf(fp, " - none\n");
+        break;
+    case SCSI_XFER_FROM_DEV:
+        fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
+        break;
+    case SCSI_XFER_TO_DEV:
+        fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
+        break;
+    default:
+        fprintf(fp, " - Oops\n");
+        break;
+    }
+}
+
+void scsi_req_complete(SCSIRequest *req)
+{
+    assert(req->status != -1);
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->bus->ops->complete(req, req->status);
+    scsi_req_unref(req);
+}
+
+void scsi_req_cancel(SCSIRequest *req)
+{
+    if (req->dev && req->dev->info->cancel_io) {
+        req->dev->info->cancel_io(req);
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    if (req->bus->ops->cancel) {
+        req->bus->ops->cancel(req);
+    }
+    scsi_req_unref(req);
+}
+
+void scsi_req_abort(SCSIRequest *req, int status)
+{
+    req->status = status;
+    if (req->dev && req->dev->info->cancel_io) {
+        req->dev->info->cancel_io(req);
+    }
+    scsi_req_complete(req);
+}
+
+void scsi_device_purge_requests(SCSIDevice *sdev)
+{
+    SCSIRequest *req;
+
+    while (!QTAILQ_EMPTY(&sdev->requests)) {
+        req = QTAILQ_FIRST(&sdev->requests);
+        scsi_req_cancel(req);
+    }
+}
+
+static char *scsibus_get_fw_dev_path(DeviceState *dev)
+{
+    SCSIDevice *d = (SCSIDevice*)dev;
+    SCSIBus *bus = scsi_bus_from_device(d);
+    char path[100];
+    int i;
+
+    for (i = 0; i < bus->ndev; i++) {
+        if (bus->devs[i] == d) {
+            break;
+        }
+    }
+
+    assert(i != bus->ndev);
+
+    snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
+
+    return strdup(path);
+}
diff --git a/qemu-0.15.x/hw/scsi-defs.h b/qemu-0.15.x/hw/scsi-defs.h
new file mode 100644
index 0000000..413cce0
--- /dev/null
+++ b/qemu-0.15.x/hw/scsi-defs.h
@@ -0,0 +1,166 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This header file contains public constants and structures used by
+ * the scsi code for linux.
+ */
+
+/*
+ *      SCSI opcodes
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define READ_TOC              0x43
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define RESERVE_10            0x56
+#define RELEASE_10            0x57
+#define MODE_SENSE_10         0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define WRITE_SAME_16         0x93
+#define MAINTENANCE_IN        0xa3
+#define MAINTENANCE_OUT       0xa4
+#define MOVE_MEDIUM           0xa5
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define READ_ELEMENT_STATUS   0xb8
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
+
+/* from hw/scsi-generic.c */
+#define REWIND 0x01
+#define REPORT_DENSITY_SUPPORT 0x44
+#define GET_CONFIGURATION 0x46
+#define READ_16 0x88
+#define WRITE_16 0x8a
+#define WRITE_VERIFY_16 0x8e
+#define SERVICE_ACTION_IN 0x9e
+#define REPORT_LUNS 0xa0
+#define LOAD_UNLOAD 0xa6
+#define SET_CD_SPEED 0xbb
+#define BLANK 0xa1
+
+/*
+ *  SAM Status codes
+ */
+
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x02
+#define CONDITION_GOOD       0x04
+#define BUSY                 0x08
+#define INTERMEDIATE_GOOD    0x10
+#define INTERMEDIATE_C_GOOD  0x14
+#define RESERVATION_CONFLICT 0x18
+#define COMMAND_TERMINATED   0x22
+#define TASK_SET_FULL        0x28
+#define ACA_ACTIVE           0x30
+#define TASK_ABORTED         0x40
+
+#define STATUS_MASK          0x3e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/*
+ *  DEVICE TYPES
+ */
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk -
+				     * - treated as TYPE_DISK */
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_ENCLOSURE	    0x0d    /* Enclosure Services Device */
+#define TYPE_NO_LUN         0x7f
+
diff --git a/qemu-0.15.x/hw/scsi-disk.c b/qemu-0.15.x/hw/scsi-disk.c
new file mode 100644
index 0000000..f42a5d1
--- /dev/null
+++ b/qemu-0.15.x/hw/scsi-disk.c
@@ -0,0 +1,1346 @@
+/*
+ * SCSI Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Paul Brook
+ * Modifications:
+ *  2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
+ *                                 when the allocation length of CDB is smaller
+ *                                 than 36.
+ *  2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
+ *                                 MODE SENSE response.
+ *
+ * This code is licensed under the LGPL.
+ *
+ * Note that this file only handles the SCSI architecture model and device
+ * commands.  Emulation of interface/link layer protocols is handled by
+ * the host adapter emulator.
+ */
+
+//#define DEBUG_SCSI
+
+#ifdef DEBUG_SCSI
+#define DPRINTF(fmt, ...) \
+do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "sysemu.h"
+#include "blockdev.h"
+
+#define SCSI_DMA_BUF_SIZE    131072
+#define SCSI_MAX_INQUIRY_LEN 256
+
+#define SCSI_REQ_STATUS_RETRY           0x01
+#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
+#define SCSI_REQ_STATUS_RETRY_READ      0x00
+#define SCSI_REQ_STATUS_RETRY_WRITE     0x02
+#define SCSI_REQ_STATUS_RETRY_FLUSH     0x04
+
+typedef struct SCSIDiskState SCSIDiskState;
+
+typedef struct SCSIDiskReq {
+    SCSIRequest req;
+    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
+    uint64_t sector;
+    uint32_t sector_count;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    uint32_t status;
+} SCSIDiskReq;
+
+typedef enum { SCSI_HD, SCSI_CD } SCSIDriveKind;
+
+struct SCSIDiskState
+{
+    SCSIDevice qdev;
+    BlockDriverState *bs;
+    /* The qemu block layer uses a fixed 512 byte sector size.
+       This is the number of 512 byte blocks in a single scsi sector.  */
+    int cluster_size;
+    uint32_t removable;
+    uint64_t max_lba;
+    QEMUBH *bh;
+    char *version;
+    char *serial;
+    SCSISense sense;
+    SCSIDriveKind drive_kind;
+};
+
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
+                                     uint32_t lun, void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+    SCSIRequest *req;
+    SCSIDiskReq *r;
+
+    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
+    r = DO_UPCAST(SCSIDiskReq, req, req);
+    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+    return req;
+}
+
+static void scsi_free_request(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    qemu_vfree(r->iov.iov_base);
+}
+
+static void scsi_disk_clear_sense(SCSIDiskState *s)
+{
+    memset(&s->sense, 0, sizeof(s->sense));
+}
+
+static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    r->req.status = status;
+    s->sense = sense;
+}
+
+/* Helper function for command completion.  */
+static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
+{
+    DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
+            r->req.tag, status, sense.key, sense.asc, sense.ascq);
+    scsi_req_set_status(r, status, sense);
+    scsi_req_complete(&r->req);
+}
+
+/* Cancel a pending data transfer.  */
+static void scsi_cancel_io(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
+    }
+    r->req.aiocb = NULL;
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    int n;
+
+    r->req.aiocb = NULL;
+
+    if (ret) {
+        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
+            return;
+        }
+    }
+
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+
+    n = r->iov.iov_len / 512;
+    r->sector += n;
+    r->sector_count -= n;
+    scsi_req_data(&r->req, r->iov.iov_len);
+}
+
+
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    if (r->sector_count == (uint32_t)-1) {
+        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
+        r->sector_count = 0;
+        scsi_req_data(&r->req, r->iov.iov_len);
+        return;
+    }
+    DPRINTF("Read sector_count=%d\n", r->sector_count);
+    if (r->sector_count == 0) {
+        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+        return;
+    }
+
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_read_complete(r, -EINVAL);
+        return;
+    }
+
+    n = r->sector_count;
+    if (n > SCSI_DMA_BUF_SIZE / 512)
+        n = SCSI_DMA_BUF_SIZE / 512;
+
+    r->iov.iov_len = n * 512;
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
+                              scsi_read_complete, r);
+    if (r->req.aiocb == NULL) {
+        scsi_read_complete(r, -EIO);
+    }
+}
+
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+{
+    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+
+    if (action == BLOCK_ERR_IGNORE) {
+        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+        return 0;
+    }
+
+    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+            || action == BLOCK_ERR_STOP_ANY) {
+
+        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
+        r->status |= SCSI_REQ_STATUS_RETRY | type;
+
+        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+        vm_stop(VMSTOP_DISKFULL);
+    } else {
+        if (type == SCSI_REQ_STATUS_RETRY_READ) {
+            scsi_req_data(&r->req, 0);
+        }
+        switch (error) {
+        case ENOMEM:
+            scsi_command_complete(r, CHECK_CONDITION,
+                                  SENSE_CODE(TARGET_FAILURE));
+            break;
+        case EINVAL:
+            scsi_command_complete(r, CHECK_CONDITION,
+                                  SENSE_CODE(INVALID_FIELD));
+            break;
+        default:
+            scsi_command_complete(r, CHECK_CONDITION,
+                                  SENSE_CODE(IO_ERROR));
+            break;
+        }
+        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+    }
+    return 1;
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    uint32_t len;
+    uint32_t n;
+
+    r->req.aiocb = NULL;
+
+    if (ret) {
+        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
+            return;
+        }
+    }
+
+    n = r->iov.iov_len / 512;
+    r->sector += n;
+    r->sector_count -= n;
+    if (r->sector_count == 0) {
+        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+    } else {
+        len = r->sector_count * 512;
+        if (len > SCSI_DMA_BUF_SIZE) {
+            len = SCSI_DMA_BUF_SIZE;
+        }
+        r->iov.iov_len = len;
+        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
+        scsi_req_data(&r->req, len);
+    }
+}
+
+static void scsi_write_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
+    if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_write_complete(r, -EINVAL);
+        return;
+    }
+
+    n = r->iov.iov_len / 512;
+    if (n) {
+        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+        r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
+                                   scsi_write_complete, r);
+        if (r->req.aiocb == NULL) {
+            scsi_write_complete(r, -ENOMEM);
+        }
+    } else {
+        /* Invoke completion routine to fetch data from host.  */
+        scsi_write_complete(r, 0);
+    }
+}
+
+static void scsi_dma_restart_bh(void *opaque)
+{
+    SCSIDiskState *s = opaque;
+    SCSIRequest *req;
+    SCSIDiskReq *r;
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
+        r = DO_UPCAST(SCSIDiskReq, req, req);
+        if (r->status & SCSI_REQ_STATUS_RETRY) {
+            int status = r->status;
+            int ret;
+
+            r->status &=
+                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
+
+            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
+            case SCSI_REQ_STATUS_RETRY_READ:
+                scsi_read_data(&r->req);
+                break;
+            case SCSI_REQ_STATUS_RETRY_WRITE:
+                scsi_write_data(&r->req);
+                break;
+            case SCSI_REQ_STATUS_RETRY_FLUSH:
+                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+                if (ret == 0) {
+                    scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+                }
+            }
+        }
+    }
+}
+
+static void scsi_dma_restart_cb(void *opaque, int running, int reason)
+{
+    SCSIDiskState *s = opaque;
+
+    if (!running)
+        return;
+
+    if (!s->bh) {
+        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+/* Return a pointer to the data buffer.  */
+static uint8_t *scsi_get_buf(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    return (uint8_t *)r->iov.iov_base;
+}
+
+/* Copy sense information into the provided buffer */
+static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+
+    return scsi_build_sense(s->sense, outbuf, len, len > 14);
+}
+
+static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int buflen = 0;
+
+    if (req->cmd.buf[1] & 0x2) {
+        /* Command support data - optional, not implemented */
+        BADF("optional INQUIRY command support request not implemented\n");
+        return -1;
+    }
+
+    if (req->cmd.buf[1] & 0x1) {
+        /* Vital product data */
+        uint8_t page_code = req->cmd.buf[2];
+        if (req->cmd.xfer < 4) {
+            BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is "
+                 "less than 4\n", page_code, req->cmd.xfer);
+            return -1;
+        }
+
+        if (s->drive_kind == SCSI_CD) {
+            outbuf[buflen++] = 5;
+        } else {
+            outbuf[buflen++] = 0;
+        }
+        outbuf[buflen++] = page_code ; // this page
+        outbuf[buflen++] = 0x00;
+
+        switch (page_code) {
+        case 0x00: /* Supported page codes, mandatory */
+        {
+            int pages;
+            DPRINTF("Inquiry EVPD[Supported pages] "
+                    "buffer size %zd\n", req->cmd.xfer);
+            pages = buflen++;
+            outbuf[buflen++] = 0x00; // list of supported pages (this page)
+            if (s->serial)
+                outbuf[buflen++] = 0x80; // unit serial number
+            outbuf[buflen++] = 0x83; // device identification
+            if (s->drive_kind == SCSI_HD) {
+                outbuf[buflen++] = 0xb0; // block limits
+                outbuf[buflen++] = 0xb2; // thin provisioning
+            }
+            outbuf[pages] = buflen - pages - 1; // number of pages
+            break;
+        }
+        case 0x80: /* Device serial number, optional */
+        {
+            int l;
+
+            if (!s->serial) {
+                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
+                return -1;
+            }
+
+            l = strlen(s->serial);
+            if (l > req->cmd.xfer)
+                l = req->cmd.xfer;
+            if (l > 20)
+                l = 20;
+
+            DPRINTF("Inquiry EVPD[Serial number] "
+                    "buffer size %zd\n", req->cmd.xfer);
+            outbuf[buflen++] = l;
+            memcpy(outbuf+buflen, s->serial, l);
+            buflen += l;
+            break;
+        }
+
+        case 0x83: /* Device identification page, mandatory */
+        {
+            int max_len = 255 - 8;
+            int id_len = strlen(bdrv_get_device_name(s->bs));
+
+            if (id_len > max_len)
+                id_len = max_len;
+            DPRINTF("Inquiry EVPD[Device identification] "
+                    "buffer size %zd\n", req->cmd.xfer);
+
+            outbuf[buflen++] = 4 + id_len;
+            outbuf[buflen++] = 0x2; // ASCII
+            outbuf[buflen++] = 0;   // not officially assigned
+            outbuf[buflen++] = 0;   // reserved
+            outbuf[buflen++] = id_len; // length of data following
+
+            memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
+            buflen += id_len;
+            break;
+        }
+        case 0xb0: /* block limits */
+        {
+            unsigned int unmap_sectors =
+                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
+            unsigned int min_io_size =
+                    s->qdev.conf.min_io_size / s->qdev.blocksize;
+            unsigned int opt_io_size =
+                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
+
+            if (s->drive_kind == SCSI_CD) {
+                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
+                        page_code);
+                return -1;
+            }
+            /* required VPD size with unmap support */
+            outbuf[3] = buflen = 0x3c;
+
+            memset(outbuf + 4, 0, buflen - 4);
+
+            /* optimal transfer length granularity */
+            outbuf[6] = (min_io_size >> 8) & 0xff;
+            outbuf[7] = min_io_size & 0xff;
+
+            /* optimal transfer length */
+            outbuf[12] = (opt_io_size >> 24) & 0xff;
+            outbuf[13] = (opt_io_size >> 16) & 0xff;
+            outbuf[14] = (opt_io_size >> 8) & 0xff;
+            outbuf[15] = opt_io_size & 0xff;
+
+            /* optimal unmap granularity */
+            outbuf[28] = (unmap_sectors >> 24) & 0xff;
+            outbuf[29] = (unmap_sectors >> 16) & 0xff;
+            outbuf[30] = (unmap_sectors >> 8) & 0xff;
+            outbuf[31] = unmap_sectors & 0xff;
+            break;
+        }
+        case 0xb2: /* thin provisioning */
+        {
+            outbuf[3] = buflen = 8;
+            outbuf[4] = 0;
+            outbuf[5] = 0x40; /* write same with unmap supported */
+            outbuf[6] = 0;
+            outbuf[7] = 0;
+            break;
+        }
+        default:
+            BADF("Error: unsupported Inquiry (EVPD[%02X]) "
+                 "buffer size %zd\n", page_code, req->cmd.xfer);
+            return -1;
+        }
+        /* done with EVPD */
+        return buflen;
+    }
+
+    /* Standard INQUIRY data */
+    if (req->cmd.buf[2] != 0) {
+        BADF("Error: Inquiry (STANDARD) page or code "
+             "is non-zero [%02X]\n", req->cmd.buf[2]);
+        return -1;
+    }
+
+    /* PAGE CODE == 0 */
+    if (req->cmd.xfer < 5) {
+        BADF("Error: Inquiry (STANDARD) buffer size %zd "
+             "is less than 5\n", req->cmd.xfer);
+        return -1;
+    }
+
+    buflen = req->cmd.xfer;
+    if (buflen > SCSI_MAX_INQUIRY_LEN)
+        buflen = SCSI_MAX_INQUIRY_LEN;
+
+    memset(outbuf, 0, buflen);
+
+    if (req->lun) {
+        outbuf[0] = 0x7f;	/* LUN not supported */
+        return buflen;
+    }
+
+    if (s->drive_kind == SCSI_CD) {
+        outbuf[0] = 5;
+        outbuf[1] = 0x80;
+        memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
+    } else {
+        outbuf[0] = 0;
+        outbuf[1] = s->removable ? 0x80 : 0;
+        memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
+    }
+    memcpy(&outbuf[8], "QEMU    ", 8);
+    memset(&outbuf[32], 0, 4);
+    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
+    /*
+     * We claim conformance to SPC-3, which is required for guests
+     * to ask for modern features like READ CAPACITY(16) or the
+     * block characteristics VPD page by default.  Not all of SPC-3
+     * is actually implemented, but we're good enough.
+     */
+    outbuf[2] = 5;
+    outbuf[3] = 2; /* Format 2 */
+
+    if (buflen > 36) {
+        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
+    } else {
+        /* If the allocation length of CDB is too small,
+               the additional length is not adjusted */
+        outbuf[4] = 36 - 5;
+    }
+
+    /* Sync data transfer and TCQ.  */
+    outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
+    return buflen;
+}
+
+static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+                           int page_control)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    BlockDriverState *bdrv = s->bs;
+    int cylinders, heads, secs;
+
+    /*
+     * If Changeable Values are requested, a mask denoting those mode parameters
+     * that are changeable shall be returned. As we currently don't support
+     * parameter changes via MODE_SELECT all bits are returned set to zero.
+     * The buffer was already menset to zero by the caller of this function.
+     */
+    switch (page) {
+    case 4: /* Rigid disk device geometry page. */
+        p[0] = 4;
+        p[1] = 0x16;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
+        /* if a geometry hint is available, use it */
+        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
+        p[2] = (cylinders >> 16) & 0xff;
+        p[3] = (cylinders >> 8) & 0xff;
+        p[4] = cylinders & 0xff;
+        p[5] = heads & 0xff;
+        /* Write precomp start cylinder, disabled */
+        p[6] = (cylinders >> 16) & 0xff;
+        p[7] = (cylinders >> 8) & 0xff;
+        p[8] = cylinders & 0xff;
+        /* Reduced current start cylinder, disabled */
+        p[9] = (cylinders >> 16) & 0xff;
+        p[10] = (cylinders >> 8) & 0xff;
+        p[11] = cylinders & 0xff;
+        /* Device step rate [ns], 200ns */
+        p[12] = 0;
+        p[13] = 200;
+        /* Landing zone cylinder */
+        p[14] = 0xff;
+        p[15] =  0xff;
+        p[16] = 0xff;
+        /* Medium rotation rate [rpm], 5400 rpm */
+        p[20] = (5400 >> 8) & 0xff;
+        p[21] = 5400 & 0xff;
+        return p[1] + 2;
+
+    case 5: /* Flexible disk device geometry page. */
+        p[0] = 5;
+        p[1] = 0x1e;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
+        /* Transfer rate [kbit/s], 5Mbit/s */
+        p[2] = 5000 >> 8;
+        p[3] = 5000 & 0xff;
+        /* if a geometry hint is available, use it */
+        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
+        p[4] = heads & 0xff;
+        p[5] = secs & 0xff;
+        p[6] = s->cluster_size * 2;
+        p[8] = (cylinders >> 8) & 0xff;
+        p[9] = cylinders & 0xff;
+        /* Write precomp start cylinder, disabled */
+        p[10] = (cylinders >> 8) & 0xff;
+        p[11] = cylinders & 0xff;
+        /* Reduced current start cylinder, disabled */
+        p[12] = (cylinders >> 8) & 0xff;
+        p[13] = cylinders & 0xff;
+        /* Device step rate [100us], 100us */
+        p[14] = 0;
+        p[15] = 1;
+        /* Device step pulse width [us], 1us */
+        p[16] = 1;
+        /* Device head settle delay [100us], 100us */
+        p[17] = 0;
+        p[18] = 1;
+        /* Motor on delay [0.1s], 0.1s */
+        p[19] = 1;
+        /* Motor off delay [0.1s], 0.1s */
+        p[20] = 1;
+        /* Medium rotation rate [rpm], 5400 rpm */
+        p[28] = (5400 >> 8) & 0xff;
+        p[29] = 5400 & 0xff;
+        return p[1] + 2;
+
+    case 8: /* Caching page.  */
+        p[0] = 8;
+        p[1] = 0x12;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
+        if (bdrv_enable_write_cache(s->bs)) {
+            p[2] = 4; /* WCE */
+        }
+        return p[1] + 2;
+
+    case 0x2a: /* CD Capabilities and Mechanical Status page. */
+        if (s->drive_kind != SCSI_CD)
+            return 0;
+        p[0] = 0x2a;
+        p[1] = 0x14;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
+        p[2] = 3; // CD-R & CD-RW read
+        p[3] = 0; // Writing not supported
+        p[4] = 0x7f; /* Audio, composite, digital out,
+                        mode 2 form 1&2, multi session */
+        p[5] = 0xff; /* CD DA, DA accurate, RW supported,
+                        RW corrected, C2 errors, ISRC,
+                        UPC, Bar code */
+        p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0);
+        /* Locking supported, jumper present, eject, tray */
+        p[7] = 0; /* no volume & mute control, no
+                     changer */
+        p[8] = (50 * 176) >> 8; // 50x read speed
+        p[9] = (50 * 176) & 0xff;
+        p[10] = 0 >> 8; // No volume
+        p[11] = 0 & 0xff;
+        p[12] = 2048 >> 8; // 2M buffer
+        p[13] = 2048 & 0xff;
+        p[14] = (16 * 176) >> 8; // 16x read speed current
+        p[15] = (16 * 176) & 0xff;
+        p[18] = (16 * 176) >> 8; // 16x write speed
+        p[19] = (16 * 176) & 0xff;
+        p[20] = (16 * 176) >> 8; // 16x write speed current
+        p[21] = (16 * 176) & 0xff;
+        return p[1] + 2;
+
+    default:
+        return 0;
+    }
+}
+
+static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint64_t nb_sectors;
+    int page, dbd, buflen, page_control;
+    uint8_t *p;
+    uint8_t dev_specific_param;
+
+    dbd = req->cmd.buf[1]  & 0x8;
+    page = req->cmd.buf[2] & 0x3f;
+    page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+    DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
+        (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
+    memset(outbuf, 0, req->cmd.xfer);
+    p = outbuf;
+
+    if (bdrv_is_read_only(s->bs)) {
+        dev_specific_param = 0x80; /* Readonly.  */
+    } else {
+        dev_specific_param = 0x00;
+    }
+
+    if (req->cmd.buf[0] == MODE_SENSE) {
+        p[1] = 0; /* Default media type.  */
+        p[2] = dev_specific_param;
+        p[3] = 0; /* Block descriptor length.  */
+        p += 4;
+    } else { /* MODE_SENSE_10 */
+        p[2] = 0; /* Default media type.  */
+        p[3] = dev_specific_param;
+        p[6] = p[7] = 0; /* Block descriptor length.  */
+        p += 8;
+    }
+
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    if (!dbd && nb_sectors) {
+        if (req->cmd.buf[0] == MODE_SENSE) {
+            outbuf[3] = 8; /* Block descriptor length  */
+        } else { /* MODE_SENSE_10 */
+            outbuf[7] = 8; /* Block descriptor length  */
+        }
+        nb_sectors /= s->cluster_size;
+        if (nb_sectors > 0xffffff)
+            nb_sectors = 0;
+        p[0] = 0; /* media density code */
+        p[1] = (nb_sectors >> 16) & 0xff;
+        p[2] = (nb_sectors >> 8) & 0xff;
+        p[3] = nb_sectors & 0xff;
+        p[4] = 0; /* reserved */
+        p[5] = 0; /* bytes 5-7 are the sector size in bytes */
+        p[6] = s->cluster_size * 2;
+        p[7] = 0;
+        p += 8;
+    }
+
+    if (page_control == 3) { /* Saved Values */
+        return -1; /* ILLEGAL_REQUEST */
+    }
+
+    switch (page) {
+    case 0x04:
+    case 0x05:
+    case 0x08:
+    case 0x2a:
+        p += mode_sense_page(req, page, p, page_control);
+        break;
+    case 0x3f:
+        p += mode_sense_page(req, 0x08, p, page_control);
+        p += mode_sense_page(req, 0x2a, p, page_control);
+        break;
+    default:
+        return -1; /* ILLEGAL_REQUEST */
+    }
+
+    buflen = p - outbuf;
+    /*
+     * The mode data length field specifies the length in bytes of the
+     * following data that is available to be transferred. The mode data
+     * length does not include itself.
+     */
+    if (req->cmd.buf[0] == MODE_SENSE) {
+        outbuf[0] = buflen - 1;
+    } else { /* MODE_SENSE_10 */
+        outbuf[0] = ((buflen - 2) >> 8) & 0xff;
+        outbuf[1] = (buflen - 2) & 0xff;
+    }
+    if (buflen > req->cmd.xfer)
+        buflen = req->cmd.xfer;
+    return buflen;
+}
+
+static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int start_track, format, msf, toclen;
+    uint64_t nb_sectors;
+
+    msf = req->cmd.buf[1] & 2;
+    format = req->cmd.buf[2] & 0xf;
+    start_track = req->cmd.buf[6];
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
+    nb_sectors /= s->cluster_size;
+    switch (format) {
+    case 0:
+        toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
+        break;
+    case 1:
+        /* multi session : only a single session defined */
+        toclen = 12;
+        memset(outbuf, 0, 12);
+        outbuf[1] = 0x0a;
+        outbuf[2] = 0x01;
+        outbuf[3] = 0x01;
+        break;
+    case 2:
+        toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
+        break;
+    default:
+        return -1;
+    }
+    if (toclen > req->cmd.xfer)
+        toclen = req->cmd.xfer;
+    return toclen;
+}
+
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint64_t nb_sectors;
+    int buflen = 0;
+    int ret;
+
+    switch (req->cmd.buf[0]) {
+    case TEST_UNIT_READY:
+        if (!bdrv_is_inserted(s->bs))
+            goto not_ready;
+	break;
+    case REQUEST_SENSE:
+        if (req->cmd.xfer < 4)
+            goto illegal_request;
+        buflen = scsi_build_sense(s->sense, outbuf, req->cmd.xfer,
+                                  req->cmd.xfer > 13);
+        scsi_disk_clear_sense(s);
+        break;
+    case INQUIRY:
+        buflen = scsi_disk_emulate_inquiry(req, outbuf);
+        if (buflen < 0)
+            goto illegal_request;
+	break;
+    case MODE_SENSE:
+    case MODE_SENSE_10:
+        buflen = scsi_disk_emulate_mode_sense(req, outbuf);
+        if (buflen < 0)
+            goto illegal_request;
+        break;
+    case READ_TOC:
+        buflen = scsi_disk_emulate_read_toc(req, outbuf);
+        if (buflen < 0)
+            goto illegal_request;
+        break;
+    case RESERVE:
+        if (req->cmd.buf[1] & 1)
+            goto illegal_request;
+        break;
+    case RESERVE_10:
+        if (req->cmd.buf[1] & 3)
+            goto illegal_request;
+        break;
+    case RELEASE:
+        if (req->cmd.buf[1] & 1)
+            goto illegal_request;
+        break;
+    case RELEASE_10:
+        if (req->cmd.buf[1] & 3)
+            goto illegal_request;
+        break;
+    case START_STOP:
+        if (s->drive_kind == SCSI_CD && (req->cmd.buf[4] & 2)) {
+            /* load/eject medium */
+            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
+        }
+	break;
+    case ALLOW_MEDIUM_REMOVAL:
+        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
+	break;
+    case READ_CAPACITY:
+        /* The normal LEN field for this command is zero.  */
+	memset(outbuf, 0, 8);
+	bdrv_get_geometry(s->bs, &nb_sectors);
+        if (!nb_sectors)
+            goto not_ready;
+        nb_sectors /= s->cluster_size;
+        /* Returned value is the address of the last sector.  */
+        nb_sectors--;
+        /* Remember the new size for read/write sanity checking. */
+        s->max_lba = nb_sectors;
+        /* Clip to 2TB, instead of returning capacity modulo 2TB. */
+        if (nb_sectors > UINT32_MAX)
+            nb_sectors = UINT32_MAX;
+        outbuf[0] = (nb_sectors >> 24) & 0xff;
+        outbuf[1] = (nb_sectors >> 16) & 0xff;
+        outbuf[2] = (nb_sectors >> 8) & 0xff;
+        outbuf[3] = nb_sectors & 0xff;
+        outbuf[4] = 0;
+        outbuf[5] = 0;
+        outbuf[6] = s->cluster_size * 2;
+        outbuf[7] = 0;
+        buflen = 8;
+	break;
+    case SYNCHRONIZE_CACHE:
+        ret = bdrv_flush(s->bs);
+        if (ret < 0) {
+            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+                return -1;
+            }
+        }
+        break;
+    case GET_CONFIGURATION:
+        memset(outbuf, 0, 8);
+        /* ??? This should probably return much more information.  For now
+           just return the basic header indicating the CD-ROM profile.  */
+        outbuf[7] = 8; // CD-ROM
+        buflen = 8;
+        break;
+    case SERVICE_ACTION_IN:
+        /* Service Action In subcommands. */
+        if ((req->cmd.buf[1] & 31) == 0x10) {
+            DPRINTF("SAI READ CAPACITY(16)\n");
+            memset(outbuf, 0, req->cmd.xfer);
+            bdrv_get_geometry(s->bs, &nb_sectors);
+            if (!nb_sectors)
+                goto not_ready;
+            nb_sectors /= s->cluster_size;
+            /* Returned value is the address of the last sector.  */
+            nb_sectors--;
+            /* Remember the new size for read/write sanity checking. */
+            s->max_lba = nb_sectors;
+            outbuf[0] = (nb_sectors >> 56) & 0xff;
+            outbuf[1] = (nb_sectors >> 48) & 0xff;
+            outbuf[2] = (nb_sectors >> 40) & 0xff;
+            outbuf[3] = (nb_sectors >> 32) & 0xff;
+            outbuf[4] = (nb_sectors >> 24) & 0xff;
+            outbuf[5] = (nb_sectors >> 16) & 0xff;
+            outbuf[6] = (nb_sectors >> 8) & 0xff;
+            outbuf[7] = nb_sectors & 0xff;
+            outbuf[8] = 0;
+            outbuf[9] = 0;
+            outbuf[10] = s->cluster_size * 2;
+            outbuf[11] = 0;
+            outbuf[12] = 0;
+            outbuf[13] = get_physical_block_exp(&s->qdev.conf);
+
+            /* set TPE bit if the format supports discard */
+            if (s->qdev.conf.discard_granularity) {
+                outbuf[14] = 0x80;
+            }
+
+            /* Protection, exponent and lowest lba field left blank. */
+            buflen = req->cmd.xfer;
+            break;
+        }
+        DPRINTF("Unsupported Service Action In\n");
+        goto illegal_request;
+    case REPORT_LUNS:
+        if (req->cmd.xfer < 16)
+            goto illegal_request;
+        memset(outbuf, 0, 16);
+        outbuf[3] = 8;
+        buflen = 16;
+        break;
+    case VERIFY:
+        break;
+    case REZERO_UNIT:
+        DPRINTF("Rezero Unit\n");
+        if (!bdrv_is_inserted(s->bs)) {
+            goto not_ready;
+        }
+        break;
+    default:
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
+        return -1;
+    }
+    scsi_req_set_status(r, GOOD, SENSE_CODE(NO_SENSE));
+    return buflen;
+
+not_ready:
+    if (!bdrv_is_inserted(s->bs)) {
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM));
+    } else {
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY));
+    }
+    return -1;
+
+illegal_request:
+    scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
+    return -1;
+}
+
+/* Execute a scsi command.  Returns the length of the data expected by the
+   command.  This will be Positive for data transfers from the device
+   (eg. disk reads), negative for transfers to the device (eg. disk writes),
+   and zero if the command does not transfer any data.  */
+
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int32_t len;
+    uint8_t command;
+    uint8_t *outbuf;
+    int rc;
+
+    command = buf[0];
+    outbuf = (uint8_t *)r->iov.iov_base;
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
+
+    if (scsi_req_parse(&r->req, buf) != 0) {
+        BADF("Unsupported command length, command %x\n", command);
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
+        return 0;
+    }
+#ifdef DEBUG_SCSI
+    {
+        int i;
+        for (i = 1; i < r->req.cmd.len; i++) {
+            printf(" 0x%02x", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+
+    if (req->lun) {
+        /* Only LUN 0 supported.  */
+        DPRINTF("Unimplemented LUN %d\n", req->lun);
+        if (command != REQUEST_SENSE && command != INQUIRY) {
+            scsi_command_complete(r, CHECK_CONDITION,
+                                  SENSE_CODE(LUN_NOT_SUPPORTED));
+            return 0;
+        }
+    }
+    switch (command) {
+    case TEST_UNIT_READY:
+    case REQUEST_SENSE:
+    case INQUIRY:
+    case MODE_SENSE:
+    case MODE_SENSE_10:
+    case RESERVE:
+    case RESERVE_10:
+    case RELEASE:
+    case RELEASE_10:
+    case START_STOP:
+    case ALLOW_MEDIUM_REMOVAL:
+    case READ_CAPACITY:
+    case SYNCHRONIZE_CACHE:
+    case READ_TOC:
+    case GET_CONFIGURATION:
+    case SERVICE_ACTION_IN:
+    case REPORT_LUNS:
+    case VERIFY:
+    case REZERO_UNIT:
+        rc = scsi_disk_emulate_command(r, outbuf);
+        if (rc < 0) {
+            return 0;
+        }
+
+        r->iov.iov_len = rc;
+        break;
+    case READ_6:
+    case READ_10:
+    case READ_12:
+    case READ_16:
+        len = r->req.cmd.xfer / s->qdev.blocksize;
+        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
+        if (r->req.cmd.lba > s->max_lba)
+            goto illegal_lba;
+        r->sector = r->req.cmd.lba * s->cluster_size;
+        r->sector_count = len * s->cluster_size;
+        break;
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+    case WRITE_VERIFY:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        len = r->req.cmd.xfer / s->qdev.blocksize;
+        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+                (command & 0xe) == 0xe ? "And Verify " : "",
+                r->req.cmd.lba, len);
+        if (r->req.cmd.lba > s->max_lba)
+            goto illegal_lba;
+        r->sector = r->req.cmd.lba * s->cluster_size;
+        r->sector_count = len * s->cluster_size;
+        break;
+    case MODE_SELECT:
+        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (r->req.cmd.xfer > 12) {
+            goto fail;
+        }
+        break;
+    case MODE_SELECT_10:
+        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (r->req.cmd.xfer > 16) {
+            goto fail;
+        }
+        break;
+    case SEEK_6:
+    case SEEK_10:
+        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
+                r->req.cmd.lba);
+        if (r->req.cmd.lba > s->max_lba) {
+            goto illegal_lba;
+        }
+        break;
+    case WRITE_SAME_16:
+        len = r->req.cmd.xfer / s->qdev.blocksize;
+
+        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
+                r->req.cmd.lba, len);
+
+        if (r->req.cmd.lba > s->max_lba) {
+            goto illegal_lba;
+        }
+
+        /*
+         * We only support WRITE SAME with the unmap bit set for now.
+         */
+        if (!(buf[1] & 0x8)) {
+            goto fail;
+        }
+
+        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
+                          len * s->cluster_size);
+        if (rc < 0) {
+            /* XXX: better error code ?*/
+            goto fail;
+        }
+
+        break;
+    default:
+        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
+        return 0;
+    fail:
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
+        return 0;
+    illegal_lba:
+        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
+        return 0;
+    }
+    if (r->sector_count == 0 && r->iov.iov_len == 0) {
+        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+    }
+    len = r->sector_count * 512 + r->iov.iov_len;
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        return -len;
+    } else {
+        if (!r->sector_count)
+            r->sector_count = -1;
+        return len;
+    }
+}
+
+static void scsi_disk_reset(DeviceState *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+    uint64_t nb_sectors;
+
+    scsi_device_purge_requests(&s->qdev);
+
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    nb_sectors /= s->cluster_size;
+    if (nb_sectors) {
+        nb_sectors--;
+    }
+    s->max_lba = nb_sectors;
+}
+
+static void scsi_destroy(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+
+    scsi_device_purge_requests(&s->qdev);
+    blockdev_mark_auto_del(s->qdev.conf.bs);
+}
+
+static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    DriveInfo *dinfo;
+
+    if (!s->qdev.conf.bs) {
+        error_report("scsi-disk: drive property not set");
+        return -1;
+    }
+    s->bs = s->qdev.conf.bs;
+    s->drive_kind = kind;
+
+    if (kind == SCSI_HD && !bdrv_is_inserted(s->bs)) {
+        error_report("Device needs media, but drive is empty");
+        return -1;
+    }
+
+    if (!s->serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(s->bs);
+        if (*dinfo->serial) {
+            s->serial = qemu_strdup(dinfo->serial);
+        }
+    }
+
+    if (!s->version) {
+        s->version = qemu_strdup(QEMU_VERSION);
+    }
+
+    if (bdrv_is_sg(s->bs)) {
+        error_report("scsi-disk: unwanted /dev/sg*");
+        return -1;
+    }
+
+    if (kind == SCSI_CD) {
+        s->qdev.blocksize = 2048;
+    } else {
+        s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    }
+    s->cluster_size = s->qdev.blocksize / 512;
+    s->bs->buffer_alignment = s->qdev.blocksize;
+
+    s->qdev.type = TYPE_DISK;
+    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
+    bdrv_set_removable(s->bs, kind == SCSI_CD);
+    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
+    return 0;
+}
+
+static int scsi_hd_initfn(SCSIDevice *dev)
+{
+    return scsi_initfn(dev, SCSI_HD);
+}
+
+static int scsi_cd_initfn(SCSIDevice *dev)
+{
+    return scsi_initfn(dev, SCSI_CD);
+}
+
+static int scsi_disk_initfn(SCSIDevice *dev)
+{
+    SCSIDriveKind kind;
+    DriveInfo *dinfo;
+
+    if (!dev->conf.bs) {
+        kind = SCSI_HD;         /* will die in scsi_initfn() */
+    } else {
+        dinfo = drive_get_by_blockdev(dev->conf.bs);
+        kind = dinfo->media_cd ? SCSI_CD : SCSI_HD;
+    }
+
+    return scsi_initfn(dev, kind);
+}
+
+#define DEFINE_SCSI_DISK_PROPERTIES()                           \
+    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),          \
+    DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
+    DEFINE_PROP_STRING("serial",  SCSIDiskState, serial)
+
+static SCSIDeviceInfo scsi_disk_info[] = {
+    {
+        .qdev.name    = "scsi-hd",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI disk",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_hd_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .free_req     = scsi_free_request,
+        .send_command = scsi_send_command,
+        .read_data    = scsi_read_data,
+        .write_data   = scsi_write_data,
+        .cancel_io    = scsi_cancel_io,
+        .get_buf      = scsi_get_buf,
+        .get_sense    = scsi_get_sense,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    },{
+        .qdev.name    = "scsi-cd",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI CD-ROM",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_cd_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .free_req     = scsi_free_request,
+        .send_command = scsi_send_command,
+        .read_data    = scsi_read_data,
+        .write_data   = scsi_write_data,
+        .cancel_io    = scsi_cancel_io,
+        .get_buf      = scsi_get_buf,
+        .get_sense    = scsi_get_sense,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+    },{
+        .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "virtual SCSI disk or CD-ROM (legacy)",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_disk_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_new_request,
+        .free_req     = scsi_free_request,
+        .send_command = scsi_send_command,
+        .read_data    = scsi_read_data,
+        .write_data   = scsi_write_data,
+        .cancel_io    = scsi_cancel_io,
+        .get_buf      = scsi_get_buf,
+        .get_sense    = scsi_get_sense,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+            DEFINE_PROP_END_OF_LIST(),
+        }
+    }
+};
+
+static void scsi_disk_register_devices(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
+        scsi_qdev_register(&scsi_disk_info[i]);
+    }
+}
+device_init(scsi_disk_register_devices)
diff --git a/qemu-0.15.x/hw/scsi-generic.c b/qemu-0.15.x/hw/scsi-generic.c
new file mode 100644
index 0000000..63361b3
--- /dev/null
+++ b/qemu-0.15.x/hw/scsi-generic.c
@@ -0,0 +1,568 @@
+/*
+ * Generic SCSI Device support
+ *
+ * Copyright (c) 2007 Bull S.A.S.
+ * Based on code by Paul Brook
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "scsi.h"
+#include "blockdev.h"
+
+#ifdef __linux__
+
+//#define DEBUG_SCSI
+
+#ifdef DEBUG_SCSI
+#define DPRINTF(fmt, ...) \
+do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <scsi/sg.h>
+#include "scsi-defs.h"
+
+#define SCSI_SENSE_BUF_SIZE 96
+
+#define SG_ERR_DRIVER_TIMEOUT 0x06
+#define SG_ERR_DRIVER_SENSE 0x08
+
+#ifndef MAX_UINT
+#define MAX_UINT ((unsigned int)-1)
+#endif
+
+typedef struct SCSIGenericState SCSIGenericState;
+
+typedef struct SCSIGenericReq {
+    SCSIRequest req;
+    uint8_t *buf;
+    int buflen;
+    int len;
+    sg_io_hdr_t io_header;
+} SCSIGenericReq;
+
+struct SCSIGenericState
+{
+    SCSIDevice qdev;
+    BlockDriverState *bs;
+    int lun;
+    int driver_status;
+    uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
+    uint8_t senselen;
+};
+
+static void scsi_set_sense(SCSIGenericState *s, SCSISense sense)
+{
+    s->senselen = scsi_build_sense(sense, s->sensebuf, SCSI_SENSE_BUF_SIZE, 0);
+    s->driver_status = SG_ERR_DRIVER_SENSE;
+}
+
+static void scsi_clear_sense(SCSIGenericState *s)
+{
+    memset(s->sensebuf, 0, SCSI_SENSE_BUF_SIZE);
+    s->senselen = 0;
+    s->driver_status = 0;
+}
+
+static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
+    int size = SCSI_SENSE_BUF_SIZE;
+
+    if (!(s->driver_status & SG_ERR_DRIVER_SENSE)) {
+        size = scsi_build_sense(SENSE_CODE(NO_SENSE), s->sensebuf,
+                                SCSI_SENSE_BUF_SIZE, 0);
+    }
+    if (size > len) {
+        size = len;
+    }
+    memcpy(outbuf, s->sensebuf, size);
+
+    return size;
+}
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     void *hba_private)
+{
+    SCSIRequest *req;
+
+    req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun, hba_private);
+    return req;
+}
+
+static void scsi_free_request(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    qemu_free(r->buf);
+}
+
+/* Helper function for command completion.  */
+static void scsi_command_complete(void *opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+
+    r->req.aiocb = NULL;
+    s->driver_status = r->io_header.driver_status;
+    if (s->driver_status & SG_ERR_DRIVER_SENSE)
+        s->senselen = r->io_header.sb_len_wr;
+
+    if (ret != 0) {
+        switch (ret) {
+        case -EDOM:
+            r->req.status = TASK_SET_FULL;
+            break;
+        case -EINVAL:
+            r->req.status = CHECK_CONDITION;
+            scsi_set_sense(s, SENSE_CODE(INVALID_FIELD));
+            break;
+        case -ENOMEM:
+            r->req.status = CHECK_CONDITION;
+            scsi_set_sense(s, SENSE_CODE(TARGET_FAILURE));
+            break;
+        default:
+            r->req.status = CHECK_CONDITION;
+            scsi_set_sense(s, SENSE_CODE(IO_ERROR));
+            break;
+        }
+    } else {
+        if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+            r->req.status = BUSY;
+            BADF("Driver Timeout\n");
+        } else if (r->io_header.status)
+            r->req.status = r->io_header.status;
+        else if (s->driver_status & SG_ERR_DRIVER_SENSE)
+            r->req.status = CHECK_CONDITION;
+        else
+            r->req.status = GOOD;
+    }
+    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
+            r, r->req.tag, r->req.status);
+
+    scsi_req_complete(&r->req);
+}
+
+/* Cancel a pending data transfer.  */
+static void scsi_cancel_io(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
+    }
+    r->req.aiocb = NULL;
+}
+
+static int execute_command(BlockDriverState *bdrv,
+                           SCSIGenericReq *r, int direction,
+			   BlockDriverCompletionFunc *complete)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+
+    r->io_header.interface_id = 'S';
+    r->io_header.dxfer_direction = direction;
+    r->io_header.dxferp = r->buf;
+    r->io_header.dxfer_len = r->buflen;
+    r->io_header.cmdp = r->req.cmd.buf;
+    r->io_header.cmd_len = r->req.cmd.len;
+    r->io_header.mx_sb_len = sizeof(s->sensebuf);
+    r->io_header.sbp = s->sensebuf;
+    r->io_header.timeout = MAX_UINT;
+    r->io_header.usr_ptr = r;
+    r->io_header.flags |= SG_FLAG_DIRECT_IO;
+
+    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
+    if (r->req.aiocb == NULL) {
+        BADF("execute_command: read failed !\n");
+        return -ENOMEM;
+    }
+
+    return 0;
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    int len;
+
+    r->req.aiocb = NULL;
+    if (ret) {
+        DPRINTF("IO error ret %d\n", ret);
+        scsi_command_complete(r, ret);
+        return;
+    }
+    len = r->io_header.dxfer_len - r->io_header.resid;
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
+
+    r->len = -1;
+    if (len == 0) {
+        scsi_command_complete(r, 0);
+    } else {
+        scsi_req_data(&r->req, len);
+    }
+}
+
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+    int ret;
+
+    DPRINTF("scsi_read_data 0x%x\n", req->tag);
+    if (r->len == -1) {
+        scsi_command_complete(r, 0);
+        return;
+    }
+
+    if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
+    {
+        s->senselen = MIN(r->len, s->senselen);
+        memcpy(r->buf, s->sensebuf, s->senselen);
+        r->io_header.driver_status = 0;
+        r->io_header.status = 0;
+        r->io_header.dxfer_len  = s->senselen;
+        r->len = -1;
+        DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
+        DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
+                r->buf[0], r->buf[1], r->buf[2], r->buf[3],
+                r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
+        scsi_req_data(&r->req, s->senselen);
+        /* Clear sensebuf after REQUEST_SENSE */
+        scsi_clear_sense(s);
+        return;
+    }
+
+    ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
+        return;
+    }
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+
+    DPRINTF("scsi_write_complete() ret = %d\n", ret);
+    r->req.aiocb = NULL;
+    if (ret) {
+        DPRINTF("IO error\n");
+        scsi_command_complete(r, ret);
+        return;
+    }
+
+    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
+        s->qdev.type == TYPE_TAPE) {
+        s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+        DPRINTF("block size %d\n", s->qdev.blocksize);
+    }
+
+    scsi_command_complete(r, ret);
+}
+
+/* Write data to a scsi device.  Returns nonzero on failure.
+   The transfer may complete asynchronously.  */
+static void scsi_write_data(SCSIRequest *req)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    int ret;
+
+    DPRINTF("scsi_write_data 0x%x\n", req->tag);
+    if (r->len == 0) {
+        r->len = r->buflen;
+        scsi_req_data(&r->req, r->len);
+        return;
+    }
+
+    ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
+    }
+}
+
+/* Return a pointer to the data buffer.  */
+static uint8_t *scsi_get_buf(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    return r->buf;
+}
+
+static void scsi_req_fixup(SCSIRequest *req)
+{
+    switch(req->cmd.buf[0]) {
+    case WRITE_10:
+        req->cmd.buf[1] &= ~0x08;	/* disable FUA */
+        break;
+    case READ_10:
+        req->cmd.buf[1] &= ~0x08;	/* disable FUA */
+        break;
+    case REWIND:
+    case START_STOP:
+        if (req->dev->type == TYPE_TAPE) {
+            /* force IMMED, otherwise qemu waits end of command */
+            req->cmd.buf[1] = 0x01;
+        }
+        break;
+    }
+}
+
+/* Execute a scsi command.  Returns the length of the data expected by the
+   command.  This will be Positive for data transfers from the device
+   (eg. disk reads), negative for transfers to the device (eg. disk writes),
+   and zero if the command does not transfer any data.  */
+
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    int ret;
+
+    if (cmd[0] != REQUEST_SENSE && req->lun != s->lun) {
+        DPRINTF("Unimplemented LUN %d\n", req->lun);
+        scsi_set_sense(s, SENSE_CODE(LUN_NOT_SUPPORTED));
+        r->req.status = CHECK_CONDITION;
+        scsi_req_complete(&r->req);
+        return 0;
+    }
+
+    if (-1 == scsi_req_parse(&r->req, cmd)) {
+        BADF("Unsupported command length, command %x\n", cmd[0]);
+        scsi_command_complete(r, -EINVAL);
+        return 0;
+    }
+    scsi_req_fixup(&r->req);
+
+    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
+            r->req.cmd.xfer, cmd[0]);
+
+#ifdef DEBUG_SCSI
+    {
+        int i;
+        for (i = 1; i < r->req.cmd.len; i++) {
+            printf(" 0x%02x", cmd[i]);
+        }
+        printf("\n");
+    }
+#endif
+
+    if (r->req.cmd.xfer == 0) {
+        if (r->buf != NULL)
+            qemu_free(r->buf);
+        r->buflen = 0;
+        r->buf = NULL;
+        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
+        if (ret < 0) {
+            scsi_command_complete(r, ret);
+            return 0;
+        }
+        return 0;
+    }
+
+    if (r->buflen != r->req.cmd.xfer) {
+        if (r->buf != NULL)
+            qemu_free(r->buf);
+        r->buf = qemu_malloc(r->req.cmd.xfer);
+        r->buflen = r->req.cmd.xfer;
+    }
+
+    memset(r->buf, 0, r->buflen);
+    r->len = r->req.cmd.xfer;
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        r->len = 0;
+        return -r->req.cmd.xfer;
+    } else {
+        return r->req.cmd.xfer;
+    }
+}
+
+static int get_blocksize(BlockDriverState *bdrv)
+{
+    uint8_t cmd[10];
+    uint8_t buf[8];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = READ_CAPACITY;
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0)
+        return -1;
+
+    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+}
+
+static int get_stream_blocksize(BlockDriverState *bdrv)
+{
+    uint8_t cmd[6];
+    uint8_t buf[12];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = MODE_SENSE;
+    cmd[4] = sizeof(buf);
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0)
+        return -1;
+
+    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
+}
+
+static void scsi_generic_reset(DeviceState *dev)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+
+    scsi_device_purge_requests(&s->qdev);
+}
+
+static void scsi_destroy(SCSIDevice *d)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
+
+    scsi_device_purge_requests(&s->qdev);
+    blockdev_mark_auto_del(s->qdev.conf.bs);
+}
+
+static int scsi_generic_initfn(SCSIDevice *dev)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
+    int sg_version;
+    struct sg_scsi_id scsiid;
+
+    if (!s->qdev.conf.bs) {
+        error_report("scsi-generic: drive property not set");
+        return -1;
+    }
+    s->bs = s->qdev.conf.bs;
+
+    /* check we are really using a /dev/sg* file */
+    if (!bdrv_is_sg(s->bs)) {
+        error_report("scsi-generic: not /dev/sg*");
+        return -1;
+    }
+
+    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+        error_report("Device doesn't support drive option werror");
+        return -1;
+    }
+    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
+        error_report("Device doesn't support drive option rerror");
+        return -1;
+    }
+
+    /* check we are using a driver managing SG_IO (version 3 and after */
+    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+        sg_version < 30000) {
+        error_report("scsi-generic: scsi generic interface too old");
+        return -1;
+    }
+
+    /* get LUN of the /dev/sg? */
+    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
+        error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
+        return -1;
+    }
+
+    /* define device state */
+    s->lun = scsiid.lun;
+    DPRINTF("LUN %d\n", s->lun);
+    s->qdev.type = scsiid.scsi_type;
+    DPRINTF("device type %d\n", s->qdev.type);
+    if (s->qdev.type == TYPE_TAPE) {
+        s->qdev.blocksize = get_stream_blocksize(s->bs);
+        if (s->qdev.blocksize == -1)
+            s->qdev.blocksize = 0;
+    } else {
+        s->qdev.blocksize = get_blocksize(s->bs);
+        /* removable media returns 0 if not present */
+        if (s->qdev.blocksize <= 0) {
+            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
+                s->qdev.blocksize = 2048;
+            else
+                s->qdev.blocksize = 512;
+        }
+    }
+    DPRINTF("block size %d\n", s->qdev.blocksize);
+    s->driver_status = 0;
+    memset(s->sensebuf, 0, sizeof(s->sensebuf));
+    bdrv_set_removable(s->bs, 0);
+    return 0;
+}
+
+static SCSIDeviceInfo scsi_generic_info = {
+    .qdev.name    = "scsi-generic",
+    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
+    .qdev.size    = sizeof(SCSIGenericState),
+    .qdev.reset   = scsi_generic_reset,
+    .init         = scsi_generic_initfn,
+    .destroy      = scsi_destroy,
+    .alloc_req    = scsi_new_request,
+    .free_req     = scsi_free_request,
+    .send_command = scsi_send_command,
+    .read_data    = scsi_read_data,
+    .write_data   = scsi_write_data,
+    .cancel_io    = scsi_cancel_io,
+    .get_buf      = scsi_get_buf,
+    .get_sense    = scsi_get_sense,
+    .qdev.props   = (Property[]) {
+        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void scsi_generic_register_devices(void)
+{
+    scsi_qdev_register(&scsi_generic_info);
+}
+device_init(scsi_generic_register_devices)
+
+#endif /* __linux__ */
diff --git a/qemu-0.15.x/hw/scsi.h b/qemu-0.15.x/hw/scsi.h
new file mode 100644
index 0000000..6b15bbc
--- /dev/null
+++ b/qemu-0.15.x/hw/scsi.h
@@ -0,0 +1,163 @@
+#ifndef QEMU_HW_SCSI_H
+#define QEMU_HW_SCSI_H
+
+#include "qdev.h"
+#include "block.h"
+#include "block_int.h"
+
+#define MAX_SCSI_DEVS	255
+
+#define SCSI_CMD_BUF_SIZE     16
+
+typedef struct SCSIBus SCSIBus;
+typedef struct SCSIBusOps SCSIBusOps;
+typedef struct SCSIDevice SCSIDevice;
+typedef struct SCSIDeviceInfo SCSIDeviceInfo;
+typedef struct SCSIRequest SCSIRequest;
+
+enum SCSIXferMode {
+    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
+    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
+    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
+};
+
+typedef struct SCSISense {
+    uint8_t key;
+    uint8_t asc;
+    uint8_t ascq;
+} SCSISense;
+
+struct SCSIRequest {
+    SCSIBus           *bus;
+    SCSIDevice        *dev;
+    uint32_t          refcount;
+    uint32_t          tag;
+    uint32_t          lun;
+    uint32_t          status;
+    struct {
+        uint8_t buf[SCSI_CMD_BUF_SIZE];
+        int len;
+        size_t xfer;
+        uint64_t lba;
+        enum SCSIXferMode mode;
+    } cmd;
+    BlockDriverAIOCB  *aiocb;
+    bool enqueued;
+    void *hba_private;
+    QTAILQ_ENTRY(SCSIRequest) next;
+};
+
+struct SCSIDevice
+{
+    DeviceState qdev;
+    uint32_t id;
+    BlockConf conf;
+    SCSIDeviceInfo *info;
+    QTAILQ_HEAD(, SCSIRequest) requests;
+    int blocksize;
+    int type;
+};
+
+/* 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);
+
+/* scsi-bus.c */
+typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
+struct SCSIDeviceInfo {
+    DeviceInfo qdev;
+    scsi_qdev_initfn init;
+    void (*destroy)(SCSIDevice *s);
+    SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+                              void *hba_private);
+    void (*free_req)(SCSIRequest *req);
+    int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
+    void (*read_data)(SCSIRequest *req);
+    void (*write_data)(SCSIRequest *req);
+    void (*cancel_io)(SCSIRequest *req);
+    uint8_t *(*get_buf)(SCSIRequest *req);
+    int (*get_sense)(SCSIRequest *req, uint8_t *buf, int len);
+};
+
+struct SCSIBusOps {
+    void (*transfer_data)(SCSIRequest *req, uint32_t arg);
+    void (*complete)(SCSIRequest *req, uint32_t arg);
+    void (*cancel)(SCSIRequest *req);
+};
+
+struct SCSIBus {
+    BusState qbus;
+    int busnr;
+
+    int tcq, ndev;
+    const SCSIBusOps *ops;
+
+    SCSIDevice *devs[MAX_SCSI_DEVS];
+};
+
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
+                  const SCSIBusOps *ops);
+void scsi_qdev_register(SCSIDeviceInfo *info);
+
+static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
+{
+    return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
+}
+
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+                                      int unit, bool removable);
+int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+extern const struct SCSISense sense_code_NO_SENSE;
+/* LUN not ready, Manual intervention required */
+extern const struct SCSISense sense_code_LUN_NOT_READY;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_NO_MEDIUM;
+/* Hardware error, internal target failure */
+extern const struct SCSISense sense_code_TARGET_FAILURE;
+/* Illegal request, invalid command operation code */
+extern const struct SCSISense sense_code_INVALID_OPCODE;
+/* Illegal request, LBA out of range */
+extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
+/* Illegal request, Invalid field in CDB */
+extern const struct SCSISense sense_code_INVALID_FIELD;
+/* Illegal request, LUN not supported */
+extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
+/* Command aborted, I/O process terminated */
+extern const struct SCSISense sense_code_IO_ERROR;
+/* Command aborted, I_T Nexus loss occurred */
+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+/* Command aborted, Logical Unit failure */
+extern const struct SCSISense sense_code_LUN_FAILURE;
+
+#define SENSE_CODE(x) sense_code_ ## x
+
+int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
+int scsi_sense_valid(SCSISense sense);
+
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+                            uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          void *hba_private);
+int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf);
+void scsi_req_free(SCSIRequest *req);
+SCSIRequest *scsi_req_ref(SCSIRequest *req);
+void scsi_req_unref(SCSIRequest *req);
+
+int scsi_req_parse(SCSIRequest *req, uint8_t *buf);
+void scsi_req_print(SCSIRequest *req);
+void scsi_req_continue(SCSIRequest *req);
+void scsi_req_data(SCSIRequest *req, int len);
+void scsi_req_complete(SCSIRequest *req);
+uint8_t *scsi_req_get_buf(SCSIRequest *req);
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
+void scsi_req_abort(SCSIRequest *req, int status);
+void scsi_req_cancel(SCSIRequest *req);
+void scsi_device_purge_requests(SCSIDevice *sdev);
+
+#endif
diff --git a/qemu-0.15.x/hw/sd.c b/qemu-0.15.x/hw/sd.c
new file mode 100644
index 0000000..cedfb20
--- /dev/null
+++ b/qemu-0.15.x/hw/sd.c
@@ -0,0 +1,1671 @@
+/*
+ * SD Memory Card emulation as defined in the "SD Memory Card Physical
+ * layer specification, Version 1.10."
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * 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.
+ */
+
+#include "hw.h"
+#include "block.h"
+#include "block_int.h"
+#include "sd.h"
+
+//#define DEBUG_SD 1
+
+#ifdef DEBUG_SD
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+typedef enum {
+    sd_r0 = 0,    /* no response */
+    sd_r1,        /* normal response command */
+    sd_r2_i,      /* CID register */
+    sd_r2_s,      /* CSD register */
+    sd_r3,        /* OCR register */
+    sd_r6 = 6,    /* Published RCA response */
+    sd_r7,        /* Operating voltage */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+struct SDState {
+    enum {
+        sd_inactive,
+        sd_card_identification_mode,
+        sd_data_transfer_mode,
+    } mode;
+    enum {
+        sd_inactive_state = -1,
+        sd_idle_state = 0,
+        sd_ready_state,
+        sd_identification_state,
+        sd_standby_state,
+        sd_transfer_state,
+        sd_sendingdata_state,
+        sd_receivingdata_state,
+        sd_programming_state,
+        sd_disconnect_state,
+    } state;
+    uint32_t ocr;
+    uint8_t scr[8];
+    uint8_t cid[16];
+    uint8_t csd[16];
+    uint16_t rca;
+    uint32_t card_status;
+    uint8_t sd_status[64];
+    uint32_t vhs;
+    int wp_switch;
+    int *wp_groups;
+    uint64_t size;
+    int blk_len;
+    uint32_t erase_start;
+    uint32_t erase_end;
+    uint8_t pwd[16];
+    int pwd_len;
+    int function_group[6];
+
+    int spi;
+    int current_cmd;
+    int blk_written;
+    uint64_t data_start;
+    uint32_t data_offset;
+    uint8_t data[512];
+    qemu_irq readonly_cb;
+    qemu_irq inserted_cb;
+    BlockDriverState *bdrv;
+    uint8_t *buf;
+
+    int enable;
+};
+
+static void sd_set_status(SDState *sd)
+{
+    switch (sd->state) {
+    case sd_inactive_state:
+        sd->mode = sd_inactive;
+        break;
+
+    case sd_idle_state:
+    case sd_ready_state:
+    case sd_identification_state:
+        sd->mode = sd_card_identification_mode;
+        break;
+
+    case sd_standby_state:
+    case sd_transfer_state:
+    case sd_sendingdata_state:
+    case sd_receivingdata_state:
+    case sd_programming_state:
+    case sd_disconnect_state:
+        sd->mode = sd_data_transfer_mode;
+        break;
+    }
+
+    sd->card_status &= ~CURRENT_STATE;
+    sd->card_status |= sd->state << 9;
+}
+
+static const sd_cmd_type_t sd_cmd_type[64] = {
+    sd_bc,   sd_none, sd_bcr,  sd_bcr,  sd_none, sd_none, sd_none, sd_ac,
+    sd_bcr,  sd_ac,   sd_ac,   sd_adtc, sd_ac,   sd_ac,   sd_none, sd_ac,
+    sd_ac,   sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac,   sd_ac,   sd_adtc, sd_none,
+    sd_ac,   sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_bc,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
+    sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const sd_cmd_type_t sd_acmd_type[64] = {
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_bcr,  sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const int sd_cmd_class[64] = {
+    0,  0,  0,  0,  0,  9, 10,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    2,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  6,  6,  6,  6,
+    5,  5, 10, 10, 10, 10,  5,  9,  9,  9,  7,  7,  7,  7,  7,  7,
+    7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
+};
+
+static uint8_t sd_crc7(void *message, size_t width)
+{
+    int i, bit;
+    uint8_t shift_reg = 0x00;
+    uint8_t *msg = (uint8_t *) message;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 7; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x89;
+        }
+
+    return shift_reg;
+}
+
+static uint16_t sd_crc16(void *message, size_t width)
+{
+    int i, bit;
+    uint16_t shift_reg = 0x0000;
+    uint16_t *msg = (uint16_t *) message;
+    width <<= 1;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 15; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x1011;
+        }
+
+    return shift_reg;
+}
+
+static void sd_set_ocr(SDState *sd)
+{
+    /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */
+    sd->ocr = 0x80ffff00;
+}
+
+static void sd_set_scr(SDState *sd)
+{
+    sd->scr[0] = 0x00;		/* SCR Structure */
+    sd->scr[1] = 0x2f;		/* SD Security Support */
+    sd->scr[2] = 0x00;
+    sd->scr[3] = 0x00;
+    sd->scr[4] = 0x00;
+    sd->scr[5] = 0x00;
+    sd->scr[6] = 0x00;
+    sd->scr[7] = 0x00;
+}
+
+#define MID	0xaa
+#define OID	"XY"
+#define PNM	"QEMU!"
+#define PRV	0x01
+#define MDT_YR	2006
+#define MDT_MON	2
+
+static void sd_set_cid(SDState *sd)
+{
+    sd->cid[0] = MID;		/* Fake card manufacturer ID (MID) */
+    sd->cid[1] = OID[0];	/* OEM/Application ID (OID) */
+    sd->cid[2] = OID[1];
+    sd->cid[3] = PNM[0];	/* Fake product name (PNM) */
+    sd->cid[4] = PNM[1];
+    sd->cid[5] = PNM[2];
+    sd->cid[6] = PNM[3];
+    sd->cid[7] = PNM[4];
+    sd->cid[8] = PRV;		/* Fake product revision (PRV) */
+    sd->cid[9] = 0xde;		/* Fake serial number (PSN) */
+    sd->cid[10] = 0xad;
+    sd->cid[11] = 0xbe;
+    sd->cid[12] = 0xef;
+    sd->cid[13] = 0x00 |	/* Manufacture date (MDT) */
+        ((MDT_YR - 2000) / 10);
+    sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+    sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
+}
+
+#define HWBLOCK_SHIFT	9			/* 512 bytes */
+#define SECTOR_SHIFT	5			/* 16 kilobytes */
+#define WPGROUP_SHIFT	7			/* 2 megs */
+#define CMULT_SHIFT	9			/* 512 times HWBLOCK_SIZE */
+#define WPGROUP_SIZE	(1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
+
+static const uint8_t sd_csd_rw_mask[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
+};
+
+static void sd_set_csd(SDState *sd, uint64_t size)
+{
+    uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
+    uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
+    uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
+
+    if (size <= 0x40000000) {	/* Standard Capacity SD */
+        sd->csd[0] = 0x00;	/* CSD structure */
+        sd->csd[1] = 0x26;	/* Data read access-time-1 */
+        sd->csd[2] = 0x00;	/* Data read access-time-2 */
+        sd->csd[3] = 0x5a;	/* Max. data transfer rate */
+        sd->csd[4] = 0x5f;	/* Card Command Classes */
+        sd->csd[5] = 0x50 |	/* Max. read data block length */
+            HWBLOCK_SHIFT;
+        sd->csd[6] = 0xe0 |	/* Partial block for read allowed */
+            ((csize >> 10) & 0x03);
+        sd->csd[7] = 0x00 |	/* Device size */
+            ((csize >> 2) & 0xff);
+        sd->csd[8] = 0x3f |	/* Max. read current */
+            ((csize << 6) & 0xc0);
+        sd->csd[9] = 0xfc |	/* Max. write current */
+            ((CMULT_SHIFT - 2) >> 1);
+        sd->csd[10] = 0x40 |	/* Erase sector size */
+            (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
+        sd->csd[11] = 0x00 |	/* Write protect group size */
+            ((sectsize << 7) & 0x80) | wpsize;
+        sd->csd[12] = 0x90 |	/* Write speed factor */
+            (HWBLOCK_SHIFT >> 2);
+        sd->csd[13] = 0x20 |	/* Max. write data block length */
+            ((HWBLOCK_SHIFT << 6) & 0xc0);
+        sd->csd[14] = 0x00;	/* File format group */
+        sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
+    } else {			/* SDHC */
+        size /= 512 * 1024;
+        size -= 1;
+        sd->csd[0] = 0x40;
+        sd->csd[1] = 0x0e;
+        sd->csd[2] = 0x00;
+        sd->csd[3] = 0x32;
+        sd->csd[4] = 0x5b;
+        sd->csd[5] = 0x59;
+        sd->csd[6] = 0x00;
+        sd->csd[7] = (size >> 16) & 0xff;
+        sd->csd[8] = (size >> 8) & 0xff;
+        sd->csd[9] = (size & 0xff);
+        sd->csd[10] = 0x7f;
+        sd->csd[11] = 0x80;
+        sd->csd[12] = 0x0a;
+        sd->csd[13] = 0x40;
+        sd->csd[14] = 0x00;
+        sd->csd[15] = 0x00;
+        sd->ocr |= 1 << 30;	/* High Capacity SD Memort Card */
+    }
+}
+
+static void sd_set_rca(SDState *sd)
+{
+    sd->rca += 0x4567;
+}
+
+#define CARD_STATUS_A	0x02004100
+#define CARD_STATUS_B	0x00c01e00
+#define CARD_STATUS_C	0xfd39a028
+
+static void sd_set_cardstatus(SDState *sd)
+{
+    sd->card_status = 0x00000100;
+}
+
+static void sd_set_sdstatus(SDState *sd)
+{
+    memset(sd->sd_status, 0, 64);
+}
+
+static int sd_req_crc_validate(SDRequest *req)
+{
+    uint8_t buffer[5];
+    buffer[0] = 0x40 | req->cmd;
+    buffer[1] = (req->arg >> 24) & 0xff;
+    buffer[2] = (req->arg >> 16) & 0xff;
+    buffer[3] = (req->arg >> 8) & 0xff;
+    buffer[4] = (req->arg >> 0) & 0xff;
+    return 0;
+    return sd_crc7(buffer, 5) != req->crc;	/* TODO */
+}
+
+static void sd_response_r1_make(SDState *sd,
+                                uint8_t *response, uint32_t last_status)
+{
+    uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
+    uint32_t status;
+
+    status = (sd->card_status & ~mask) | (last_status & mask);
+    sd->card_status &= ~CARD_STATUS_C | APP_CMD;
+
+    response[0] = (status >> 24) & 0xff;
+    response[1] = (status >> 16) & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = (status >> 0) & 0xff;
+}
+
+static void sd_response_r3_make(SDState *sd, uint8_t *response)
+{
+    response[0] = (sd->ocr >> 24) & 0xff;
+    response[1] = (sd->ocr >> 16) & 0xff;
+    response[2] = (sd->ocr >> 8) & 0xff;
+    response[3] = (sd->ocr >> 0) & 0xff;
+}
+
+static void sd_response_r6_make(SDState *sd, uint8_t *response)
+{
+    uint16_t arg;
+    uint16_t status;
+
+    arg = sd->rca;
+    status = ((sd->card_status >> 8) & 0xc000) |
+             ((sd->card_status >> 6) & 0x2000) |
+              (sd->card_status & 0x1fff);
+
+    response[0] = (arg >> 8) & 0xff;
+    response[1] = arg & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = status & 0xff;
+}
+
+static void sd_response_r7_make(SDState *sd, uint8_t *response)
+{
+    response[0] = (sd->vhs >> 24) & 0xff;
+    response[1] = (sd->vhs >> 16) & 0xff;
+    response[2] = (sd->vhs >>  8) & 0xff;
+    response[3] = (sd->vhs >>  0) & 0xff;
+}
+
+static void sd_reset(SDState *sd, BlockDriverState *bdrv)
+{
+    uint64_t size;
+    uint64_t sect;
+
+    if (bdrv) {
+        bdrv_get_geometry(bdrv, &sect);
+    } else {
+        sect = 0;
+    }
+    sect <<= 9;
+
+    size = sect + 1;
+
+    sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+
+    sd->state = sd_idle_state;
+    sd->rca = 0x0000;
+    sd_set_ocr(sd);
+    sd_set_scr(sd);
+    sd_set_cid(sd);
+    sd_set_csd(sd, size);
+    sd_set_cardstatus(sd);
+    sd_set_sdstatus(sd);
+
+    sd->bdrv = bdrv;
+
+    if (sd->wp_groups)
+        qemu_free(sd->wp_groups);
+    sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
+    sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
+    memset(sd->function_group, 0, sizeof(int) * 6);
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->size = size;
+    sd->blk_len = 0x200;
+    sd->pwd_len = 0;
+}
+
+static void sd_cardchange(void *opaque, int reason)
+{
+    SDState *sd = opaque;
+
+    if (!(reason & CHANGE_MEDIA)) {
+        return;
+    }
+
+    qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
+    if (bdrv_is_inserted(sd->bdrv)) {
+        sd_reset(sd, sd->bdrv);
+        qemu_set_irq(sd->readonly_cb, sd->wp_switch);
+    }
+}
+
+/* We do not model the chip select pin, so allow the board to select
+   whether card should be in SSI or MMC/SD mode.  It is also up to the
+   board to ensure that ssi transfers only occur when the chip select
+   is asserted.  */
+SDState *sd_init(BlockDriverState *bs, int is_spi)
+{
+    SDState *sd;
+
+    sd = (SDState *) qemu_mallocz(sizeof(SDState));
+    sd->buf = qemu_blockalign(bs, 512);
+    sd->spi = is_spi;
+    sd->enable = 1;
+    sd_reset(sd, bs);
+    if (sd->bdrv) {
+        bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+    }
+    return sd;
+}
+
+void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
+{
+    sd->readonly_cb = readonly;
+    sd->inserted_cb = insert;
+    qemu_set_irq(readonly, sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0);
+    qemu_set_irq(insert, sd->bdrv ? bdrv_is_inserted(sd->bdrv) : 0);
+}
+
+static void sd_erase(SDState *sd)
+{
+    int i, start, end;
+    if (!sd->erase_start || !sd->erase_end) {
+        sd->card_status |= ERASE_SEQ_ERROR;
+        return;
+    }
+
+    start = sd->erase_start >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    end = sd->erase_end >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->csd[14] |= 0x40;
+
+    for (i = start; i <= end; i ++)
+        if (sd->wp_groups[i])
+            sd->card_status |= WP_ERASE_SKIP;
+}
+
+static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
+{
+    uint32_t i, wpnum;
+    uint32_t ret = 0;
+
+    wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+
+    for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
+        if (addr < sd->size && sd->wp_groups[wpnum])
+            ret |= (1 << i);
+
+    return ret;
+}
+
+static void sd_function_switch(SDState *sd, uint32_t arg)
+{
+    int i, mode, new_func, crc;
+    mode = !!(arg & 0x80000000);
+
+    sd->data[0] = 0x00;		/* Maximum current consumption */
+    sd->data[1] = 0x01;
+    sd->data[2] = 0x80;		/* Supported group 6 functions */
+    sd->data[3] = 0x01;
+    sd->data[4] = 0x80;		/* Supported group 5 functions */
+    sd->data[5] = 0x01;
+    sd->data[6] = 0x80;		/* Supported group 4 functions */
+    sd->data[7] = 0x01;
+    sd->data[8] = 0x80;		/* Supported group 3 functions */
+    sd->data[9] = 0x01;
+    sd->data[10] = 0x80;	/* Supported group 2 functions */
+    sd->data[11] = 0x43;
+    sd->data[12] = 0x80;	/* Supported group 1 functions */
+    sd->data[13] = 0x03;
+    for (i = 0; i < 6; i ++) {
+        new_func = (arg >> (i * 4)) & 0x0f;
+        if (mode && new_func != 0x0f)
+            sd->function_group[i] = new_func;
+        sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
+    }
+    memset(&sd->data[17], 0, 47);
+    crc = sd_crc16(sd->data, 64);
+    sd->data[65] = crc >> 8;
+    sd->data[66] = crc & 0xff;
+}
+
+static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+{
+    return sd->wp_groups[addr >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+}
+
+static void sd_lock_command(SDState *sd)
+{
+    int erase, lock, clr_pwd, set_pwd, pwd_len;
+    erase = !!(sd->data[0] & 0x08);
+    lock = sd->data[0] & 0x04;
+    clr_pwd = sd->data[0] & 0x02;
+    set_pwd = sd->data[0] & 0x01;
+
+    if (sd->blk_len > 1)
+        pwd_len = sd->data[1];
+    else
+        pwd_len = 0;
+
+    if (erase) {
+        if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
+                        set_pwd || clr_pwd || lock || sd->wp_switch ||
+                        (sd->csd[14] & 0x20)) {
+            sd->card_status |= LOCK_UNLOCK_FAILED;
+            return;
+        }
+        memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
+                        (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+        sd->csd[14] &= ~0x10;
+        sd->card_status &= ~CARD_IS_LOCKED;
+        sd->pwd_len = 0;
+        /* Erasing the entire card here! */
+        fprintf(stderr, "SD: Card force-erased by CMD42\n");
+        return;
+    }
+
+    if (sd->blk_len < 2 + pwd_len ||
+                    pwd_len <= sd->pwd_len ||
+                    pwd_len > sd->pwd_len + 16) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    pwd_len -= sd->pwd_len;
+    if ((pwd_len && !set_pwd) ||
+                    (clr_pwd && (set_pwd || lock)) ||
+                    (lock && !sd->pwd_len && !set_pwd) ||
+                    (!set_pwd && !clr_pwd &&
+                     (((sd->card_status & CARD_IS_LOCKED) && lock) ||
+                      (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (set_pwd) {
+        memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
+        sd->pwd_len = pwd_len;
+    }
+
+    if (clr_pwd) {
+        sd->pwd_len = 0;
+    }
+
+    if (lock)
+        sd->card_status |= CARD_IS_LOCKED;
+    else
+        sd->card_status &= ~CARD_IS_LOCKED;
+}
+
+static sd_rsp_type_t sd_normal_command(SDState *sd,
+                                       SDRequest req)
+{
+    uint32_t rca = 0x0000;
+    uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg;
+
+    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+        rca = req.arg >> 16;
+
+    DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
+    switch (req.cmd) {
+    /* Basic commands (Class 0 and Class 1) */
+    case 0:	/* CMD0:   GO_IDLE_STATE */
+        switch (sd->state) {
+        case sd_inactive_state:
+            return sd->spi ? sd_r1 : sd_r0;
+
+        default:
+            sd->state = sd_idle_state;
+            sd_reset(sd, sd->bdrv);
+            return sd->spi ? sd_r1 : sd_r0;
+        }
+        break;
+
+    case 1:	/* CMD1:   SEND_OP_CMD */
+        if (!sd->spi)
+            goto bad_cmd;
+
+        sd->state = sd_transfer_state;
+        return sd_r1;
+
+    case 2:	/* CMD2:   ALL_SEND_CID */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_ready_state:
+            sd->state = sd_identification_state;
+            return sd_r2_i;
+
+        default:
+            break;
+        }
+        break;
+
+    case 3:	/* CMD3:   SEND_RELATIVE_ADDR */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_identification_state:
+        case sd_standby_state:
+            sd->state = sd_standby_state;
+            sd_set_rca(sd);
+            return sd_r6;
+
+        default:
+            break;
+        }
+        break;
+
+    case 4:	/* CMD4:   SEND_DSR */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_standby_state:
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case 5: /* CMD5: reserved for SDIO cards */
+        sd->card_status |= ILLEGAL_COMMAND;
+        return sd_r0;
+
+    case 6:	/* CMD6:   SWITCH_FUNCTION */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            sd_function_switch(sd, req.arg);
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 7:	/* CMD7:   SELECT/DESELECT_CARD */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_transfer_state:
+        case sd_sendingdata_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_standby_state;
+            return sd_r1b;
+
+        case sd_disconnect_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_programming_state;
+            return sd_r1b;
+
+        case sd_programming_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_disconnect_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 8:	/* CMD8:   SEND_IF_COND */
+        /* Physical Layer Specification Version 2.00 command */
+        switch (sd->state) {
+        case sd_idle_state:
+            sd->vhs = 0;
+
+            /* No response if not exactly one VHS bit is set.  */
+            if (!(req.arg >> 8) || (req.arg >> ffs(req.arg & ~0xff)))
+                return sd->spi ? sd_r7 : sd_r0;
+
+            /* Accept.  */
+            sd->vhs = req.arg;
+            return sd_r7;
+
+        default:
+            break;
+        }
+        break;
+
+    case 9:	/* CMD9:   SEND_CSD */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_s;
+
+        case sd_transfer_state:
+            if (!sd->spi)
+                break;
+            sd->state = sd_sendingdata_state;
+            memcpy(sd->data, sd->csd, 16);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 10:	/* CMD10:  SEND_CID */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_i;
+
+        case sd_transfer_state:
+            if (!sd->spi)
+                break;
+            sd->state = sd_sendingdata_state;
+            memcpy(sd->data, sd->cid, 16);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 11:	/* CMD11:  READ_DAT_UNTIL_STOP */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    case 12:	/* CMD12:  STOP_TRANSMISSION */
+        switch (sd->state) {
+        case sd_sendingdata_state:
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_receivingdata_state:
+            sd->state = sd_programming_state;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:	/* CMD13:  SEND_STATUS */
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 15:	/* CMD15:  GO_INACTIVE_STATE */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_inactive_state;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block read commands (Classs 2) */
+    case 16:	/* CMD16:  SET_BLOCKLEN */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (req.arg > (1 << HWBLOCK_SHIFT))
+                sd->card_status |= BLOCK_LEN_ERROR;
+            else
+                sd->blk_len = req.arg;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 17:	/* CMD17:  READ_SINGLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 18:	/* CMD18:  READ_MULTIPLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block write commands (Class 4) */
+    case 24:	/* CMD24:  WRITE_SINGLE_BLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Writing in SPI mode not implemented.  */
+            if (sd->spi)
+                break;
+            sd->state = sd_receivingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 25:	/* CMD25:  WRITE_MULTIPLE_BLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Writing in SPI mode not implemented.  */
+            if (sd->spi)
+                break;
+            sd->state = sd_receivingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 26:	/* CMD26:  PROGRAM_CID */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 27:	/* CMD27:  PROGRAM_CSD */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Write protection (Class 6) */
+    case 28:	/* CMD28:  SET_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (addr >= sd->size) {
+                sd->card_status = ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd->wp_groups[addr >> (HWBLOCK_SHIFT +
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 29:	/* CMD29:  CLR_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (addr >= sd->size) {
+                sd->card_status = ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd->wp_groups[addr >> (HWBLOCK_SHIFT +
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 30:	/* CMD30:  SEND_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Erase commands (Class 5) */
+    case 32:	/* CMD32:  ERASE_WR_BLK_START */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_start = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 33:	/* CMD33:  ERASE_WR_BLK_END */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_end = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 38:	/* CMD38:  ERASE */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (sd->csd[14] & 0x30) {
+                sd->card_status |= WP_VIOLATION;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd_erase(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Lock card commands (Class 7) */
+    case 42:	/* CMD42:  LOCK_UNLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 52:
+    case 53:
+        /* CMD52, CMD53: reserved for SDIO cards
+         * (see the SDIO Simplified Specification V2.0)
+         * Handle as illegal command but do not complain
+         * on stderr, as some OSes may use these in their
+         * probing for presence of an SDIO card.
+         */
+        sd->card_status |= ILLEGAL_COMMAND;
+        return sd_r0;
+
+    /* Application specific commands (Class 8) */
+    case 55:	/* CMD55:  APP_CMD */
+        if (sd->rca != rca)
+            return sd_r0;
+
+        sd->card_status |= APP_CMD;
+        return sd_r1;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg);
+
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->data_offset = 0;
+            if (req.arg & 1)
+                sd->state = sd_sendingdata_state;
+            else
+                sd->state = sd_receivingdata_state;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+    bad_cmd:
+        sd->card_status |= ILLEGAL_COMMAND;
+
+        fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
+        return sd_r0;
+
+    unimplemented_cmd:
+        /* Commands that are recognised but not yet implemented in SPI mode.  */
+        sd->card_status |= ILLEGAL_COMMAND;
+        fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
+        return sd_r0;
+    }
+
+    sd->card_status |= ILLEGAL_COMMAND;
+    fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
+    return sd_r0;
+}
+
+static sd_rsp_type_t sd_app_command(SDState *sd,
+                                    SDRequest req)
+{
+    DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
+    switch (req.cmd) {
+    case 6:	/* ACMD6:  SET_BUS_WIDTH */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->sd_status[0] &= 0x3f;
+            sd->sd_status[0] |= (req.arg & 0x03) << 6;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:	/* ACMD13: SD_STATUS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 22:	/* ACMD22: SEND_NUM_WR_BLOCKS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            *(uint32_t *) sd->data = sd->blk_written;
+
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 23:	/* ACMD23: SET_WR_BLK_ERASE_COUNT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 41:	/* ACMD41: SD_APP_OP_COND */
+        if (sd->spi) {
+            /* SEND_OP_CMD */
+            sd->state = sd_transfer_state;
+            return sd_r1;
+        }
+        switch (sd->state) {
+        case sd_idle_state:
+            /* We accept any voltage.  10000 V is nothing.  */
+            if (req.arg)
+                sd->state = sd_ready_state;
+
+            return sd_r3;
+
+        default:
+            break;
+        }
+        break;
+
+    case 42:	/* ACMD42: SET_CLR_CARD_DETECT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Bringing in the 50KOhm pull-up resistor... Done.  */
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 51:	/* ACMD51: SEND_SCR */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+        /* Fall back to standard commands.  */
+        sd->card_status &= ~APP_CMD;
+        return sd_normal_command(sd, req);
+    }
+
+    fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
+    return sd_r0;
+}
+
+int sd_do_command(SDState *sd, SDRequest *req,
+                  uint8_t *response) {
+    uint32_t last_status = sd->card_status;
+    sd_rsp_type_t rtype;
+    int rsplen;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) {
+        return 0;
+    }
+
+    if (sd_req_crc_validate(req)) {
+        sd->card_status &= ~COM_CRC_ERROR;
+        return 0;
+    }
+
+    sd->card_status &= ~CARD_STATUS_B;
+    sd_set_status(sd);
+
+    if (last_status & CARD_IS_LOCKED)
+        if (((last_status & APP_CMD) &&
+                                 req->cmd == 41) ||
+                        (!(last_status & APP_CMD) &&
+                         (sd_cmd_class[req->cmd] == 0 ||
+                          sd_cmd_class[req->cmd] == 7 ||
+                          req->cmd == 16 || req->cmd == 55))) {
+            sd->card_status |= ILLEGAL_COMMAND;
+            fprintf(stderr, "SD: Card is locked\n");
+            return 0;
+        }
+
+    if (last_status & APP_CMD) {
+        rtype = sd_app_command(sd, *req);
+        sd->card_status &= ~APP_CMD;
+    } else
+        rtype = sd_normal_command(sd, *req);
+
+    sd->current_cmd = req->cmd;
+
+    switch (rtype) {
+    case sd_r1:
+    case sd_r1b:
+        sd_response_r1_make(sd, response, last_status);
+        rsplen = 4;
+        break;
+
+    case sd_r2_i:
+        memcpy(response, sd->cid, sizeof(sd->cid));
+        rsplen = 16;
+        break;
+
+    case sd_r2_s:
+        memcpy(response, sd->csd, sizeof(sd->csd));
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        sd_response_r3_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r6:
+        sd_response_r6_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r7:
+        sd_response_r7_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r0:
+    default:
+        rsplen = 0;
+        break;
+    }
+
+    if (sd->card_status & ILLEGAL_COMMAND)
+        rsplen = 0;
+
+#ifdef DEBUG_SD
+    if (rsplen) {
+        int i;
+        DPRINTF("Response:");
+        for (i = 0; i < rsplen; i++)
+            printf(" %02x", response[i]);
+        printf(" state %d\n", sd->state);
+    } else {
+        DPRINTF("No response %d\n", sd->state);
+    }
+#endif
+
+    return rsplen;
+}
+
+static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
+{
+    uint64_t end = addr + len;
+
+    DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
+            (unsigned long long) addr, len);
+    if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
+        fprintf(stderr, "sd_blk_read: read error on host side\n");
+        return;
+    }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
+
+        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
+            fprintf(stderr, "sd_blk_read: read error on host side\n");
+            return;
+        }
+        memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
+    } else
+        memcpy(sd->data, sd->buf + (addr & 511), len);
+}
+
+static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
+{
+    uint64_t end = addr + len;
+
+    if ((addr & 511) || len < 512)
+        if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
+            return;
+        }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
+        if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+            return;
+        }
+
+        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
+            return;
+        }
+        memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
+        if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1)
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+    } else {
+        memcpy(sd->buf + (addr & 511), sd->data, len);
+        if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1)
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+    }
+}
+
+#define BLK_READ_BLOCK(a, len)	sd_blk_read(sd, a, len)
+#define BLK_WRITE_BLOCK(a, len)	sd_blk_write(sd, a, len)
+#define APP_READ_BLOCK(a, len)	memset(sd->data, 0xec, len)
+#define APP_WRITE_BLOCK(a, len)
+
+void sd_write_data(SDState *sd, uint8_t value)
+{
+    int i;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
+        return;
+
+    if (sd->state != sd_receivingdata_state) {
+        fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
+        return;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return;
+
+    switch (sd->current_cmd) {
+    case 24:	/* CMD24:  WRITE_SINGLE_BLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written ++;
+            sd->csd[14] |= 0x40;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 25:	/* CMD25:  WRITE_MULTIPLE_BLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written ++;
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
+            if (sd->data_start + sd->blk_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+            if (sd_wp_addr(sd, sd->data_start)) {
+                sd->card_status |= WP_VIOLATION;
+                break;
+            }
+            sd->csd[14] |= 0x40;
+
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_receivingdata_state;
+        }
+        break;
+
+    case 26:	/* CMD26:  PROGRAM_CID */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->cid)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->cid); i ++)
+                if ((sd->cid[i] | 0x00) != sd->data[i])
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->cid); i ++) {
+                    sd->cid[i] |= 0x00;
+                    sd->cid[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 27:	/* CMD27:  PROGRAM_CSD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->csd)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->csd); i ++)
+                if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
+                    (sd->data[i] | sd_csd_rw_mask[i]))
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            /* Copy flag (OTP) & Permanent write protect */
+            if (sd->csd[14] & ~sd->data[14] & 0x60)
+                sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->csd); i ++) {
+                    sd->csd[i] |= sd_csd_rw_mask[i];
+                    sd->csd[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 42:	/* CMD42:  LOCK_UNLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            sd_lock_command(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    default:
+        fprintf(stderr, "sd_write_data: unknown command\n");
+        break;
+    }
+}
+
+uint8_t sd_read_data(SDState *sd)
+{
+    /* TODO: Append CRCs */
+    uint8_t ret;
+    int io_len;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
+        return 0x00;
+
+    if (sd->state != sd_sendingdata_state) {
+        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
+        return 0x00;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return 0x00;
+
+    io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len;
+
+    switch (sd->current_cmd) {
+    case 6:	/* CMD6:   SWITCH_FUNCTION */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 64)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 9:	/* CMD9:   SEND_CSD */
+    case 10:	/* CMD10:  SEND_CID */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 16)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 11:	/* CMD11:  READ_DAT_UNTIL_STOP */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len) {
+            sd->data_start += io_len;
+            sd->data_offset = 0;
+            if (sd->data_start + io_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 13:	/* ACMD13: SD_STATUS */
+        ret = sd->sd_status[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->sd_status))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 17:	/* CMD17:  READ_SINGLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 18:	/* CMD18:  READ_MULTIPLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len) {
+            sd->data_start += io_len;
+            sd->data_offset = 0;
+            if (sd->data_start + io_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 22:	/* ACMD22: SEND_NUM_WR_BLOCKS */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 30:	/* CMD30:  SEND_WRITE_PROT */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 51:	/* ACMD51: SEND_SCR */
+        ret = sd->scr[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->scr))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        if (sd->data_offset == 0)
+            APP_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    default:
+        fprintf(stderr, "sd_read_data: unknown command\n");
+        return 0x00;
+    }
+
+    return ret;
+}
+
+int sd_data_ready(SDState *sd)
+{
+    return sd->state == sd_sendingdata_state;
+}
+
+void sd_enable(SDState *sd, int enable)
+{
+    sd->enable = enable;
+}
diff --git a/qemu-0.15.x/hw/sd.h b/qemu-0.15.x/hw/sd.h
new file mode 100644
index 0000000..ac4b7c4
--- /dev/null
+++ b/qemu-0.15.x/hw/sd.h
@@ -0,0 +1,79 @@
+/*
+ * SD Memory Card emulation.  Mostly correct for MMC too.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * 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 __hw_sd_h
+#define __hw_sd_h		1
+
+#define OUT_OF_RANGE		(1 << 31)
+#define ADDRESS_ERROR		(1 << 30)
+#define BLOCK_LEN_ERROR		(1 << 29)
+#define ERASE_SEQ_ERROR		(1 << 28)
+#define ERASE_PARAM		(1 << 27)
+#define WP_VIOLATION		(1 << 26)
+#define CARD_IS_LOCKED		(1 << 25)
+#define LOCK_UNLOCK_FAILED	(1 << 24)
+#define COM_CRC_ERROR		(1 << 23)
+#define ILLEGAL_COMMAND		(1 << 22)
+#define CARD_ECC_FAILED		(1 << 21)
+#define CC_ERROR		(1 << 20)
+#define SD_ERROR		(1 << 19)
+#define CID_CSD_OVERWRITE	(1 << 16)
+#define WP_ERASE_SKIP		(1 << 15)
+#define CARD_ECC_DISABLED	(1 << 14)
+#define ERASE_RESET		(1 << 13)
+#define CURRENT_STATE		(7 << 9)
+#define READY_FOR_DATA		(1 << 8)
+#define APP_CMD			(1 << 5)
+#define AKE_SEQ_ERROR		(1 << 3)
+
+typedef enum {
+    sd_none = -1,
+    sd_bc = 0,	/* broadcast -- no response */
+    sd_bcr,	/* broadcast with response */
+    sd_ac,	/* addressed -- no data transfer */
+    sd_adtc,	/* addressed with data transfer */
+} sd_cmd_type_t;
+
+typedef struct {
+    uint8_t cmd;
+    uint32_t arg;
+    uint8_t crc;
+} SDRequest;
+
+typedef struct SDState SDState;
+
+SDState *sd_init(BlockDriverState *bs, int is_spi);
+int sd_do_command(SDState *sd, SDRequest *req,
+                  uint8_t *response);
+void sd_write_data(SDState *sd, uint8_t value);
+uint8_t sd_read_data(SDState *sd);
+void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
+int sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, int enable);
+
+#endif	/* __hw_sd_h */
diff --git a/qemu-0.15.x/hw/serial.c b/qemu-0.15.x/hw/serial.c
new file mode 100644
index 0000000..0ee61dd
--- /dev/null
+++ b/qemu-0.15.x/hw/serial.c
@@ -0,0 +1,979 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * 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 "hw.h"
+#include "qemu-char.h"
+#include "isa.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "sysemu.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 */
+#define UART_IIR_CTI    0x0C    /* Character Timeout Indication */
+
+#define UART_IIR_FENF   0x80    /* Fifo enabled, but not functionning */
+#define UART_IIR_FE     0xC0    /* Fifo enabled */
+
+/*
+ * 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 */
+#define UART_LSR_INT_ANY 0x1E	/* Any of the lsr-interrupt-triggering status bits */
+
+/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
+
+#define UART_FCR_ITL_1      0x00 /* 1 byte ITL */
+#define UART_FCR_ITL_2      0x40 /* 4 bytes ITL */
+#define UART_FCR_ITL_3      0x80 /* 8 bytes ITL */
+#define UART_FCR_ITL_4      0xC0 /* 14 bytes ITL */
+
+#define UART_FCR_DMS        0x08    /* DMA Mode Select */
+#define UART_FCR_XFR        0x04    /* XMIT Fifo Reset */
+#define UART_FCR_RFR        0x02    /* RCVR Fifo Reset */
+#define UART_FCR_FE         0x01    /* FIFO Enable */
+
+#define UART_FIFO_LENGTH    16      /* 16550A Fifo Length */
+
+#define XMIT_FIFO           0
+#define RECV_FIFO           1
+#define MAX_XMIT_RETRY      4
+
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+typedef struct SerialFIFO {
+    uint8_t data[UART_FIFO_LENGTH];
+    uint8_t count;
+    uint8_t itl;                        /* Interrupt Trigger Level */
+    uint8_t tail;
+    uint8_t head;
+} SerialFIFO;
+
+struct SerialState {
+    uint16_t divider;
+    uint8_t rbr; /* receive register */
+    uint8_t thr; /* transmit holding register */
+    uint8_t tsr; /* transmit shift 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;
+    uint8_t fcr;
+    uint8_t fcr_vmstate; /* we can't write directly this value
+                            it has side effects */
+    /* 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;
+    int it_shift;
+    int baudbase;
+    int tsr_retry;
+
+    uint64_t last_xmit_ts;              /* Time when the last byte was successfully sent out of the tsr */
+    SerialFIFO recv_fifo;
+    SerialFIFO xmit_fifo;
+
+    struct QEMUTimer *fifo_timeout_timer;
+    int timeout_ipending;                   /* timeout interrupt pending state */
+    struct QEMUTimer *transmit_timer;
+
+
+    uint64_t char_transmit_time;               /* time to transmit a char in ticks*/
+    int poll_msl;
+
+    struct QEMUTimer *modem_status_poll;
+};
+
+typedef struct ISASerialState {
+    ISADevice dev;
+    uint32_t index;
+    uint32_t iobase;
+    uint32_t isairq;
+    SerialState state;
+} ISASerialState;
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size);
+
+static void fifo_clear(SerialState *s, int fifo)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+    memset(f->data, 0, UART_FIFO_LENGTH);
+    f->count = 0;
+    f->head = 0;
+    f->tail = 0;
+}
+
+static int fifo_put(SerialState *s, int fifo, uint8_t chr)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+
+    /* Receive overruns do not overwrite FIFO contents. */
+    if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
+
+        f->data[f->head++] = chr;
+
+        if (f->head == UART_FIFO_LENGTH)
+            f->head = 0;
+    }
+
+    if (f->count < UART_FIFO_LENGTH)
+        f->count++;
+    else if (fifo == RECV_FIFO)
+        s->lsr |= UART_LSR_OE;
+
+    return 1;
+}
+
+static uint8_t fifo_get(SerialState *s, int fifo)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+    uint8_t c;
+
+    if(f->count == 0)
+        return 0;
+
+    c = f->data[f->tail++];
+    if (f->tail == UART_FIFO_LENGTH)
+        f->tail = 0;
+    f->count--;
+
+    return c;
+}
+
+static void serial_update_irq(SerialState *s)
+{
+    uint8_t tmp_iir = UART_IIR_NO_INT;
+
+    if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
+        tmp_iir = UART_IIR_RLSI;
+    } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
+        /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
+         * this is not in the specification but is observed on existing
+         * hardware.  */
+        tmp_iir = UART_IIR_CTI;
+    } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) &&
+               (!(s->fcr & UART_FCR_FE) ||
+                s->recv_fifo.count >= s->recv_fifo.itl)) {
+        tmp_iir = UART_IIR_RDI;
+    } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) {
+        tmp_iir = UART_IIR_THRI;
+    } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) {
+        tmp_iir = UART_IIR_MSI;
+    }
+
+    s->iir = tmp_iir | (s->iir & 0xF0);
+
+    if (tmp_iir != UART_IIR_NO_INT) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void serial_update_parameters(SerialState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+
+    if (s->divider == 0)
+        return;
+
+    /* Start bit. */
+    frame_size = 1;
+    if (s->lcr & 0x08) {
+        /* Parity bit. */
+        frame_size++;
+        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;
+    frame_size += data_bits + stop_bits;
+    speed = s->baudbase / s->divider;
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
+    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+    DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+}
+
+static void serial_update_msl(SerialState *s)
+{
+    uint8_t omsr;
+    int flags;
+
+    qemu_del_timer(s->modem_status_poll);
+
+    if (qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
+        s->poll_msl = -1;
+        return;
+    }
+
+    omsr = s->msr;
+
+    s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS;
+    s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR;
+    s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD;
+    s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI;
+
+    if (s->msr != omsr) {
+         /* Set delta bits */
+         s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4));
+         /* UART_MSR_TERI only if change was from 1 -> 0 */
+         if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
+             s->msr &= ~UART_MSR_TERI;
+         serial_update_irq(s);
+    }
+
+    /* The real 16550A apparently has a 250ns response latency to line status changes.
+       We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
+
+    if (s->poll_msl)
+        qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
+}
+
+static void serial_xmit(void *opaque)
+{
+    SerialState *s = opaque;
+    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    if (s->tsr_retry <= 0) {
+        if (s->fcr & UART_FCR_FE) {
+            s->tsr = fifo_get(s,XMIT_FIFO);
+            if (!s->xmit_fifo.count)
+                s->lsr |= UART_LSR_THRE;
+        } else {
+            s->tsr = s->thr;
+            s->lsr |= UART_LSR_THRE;
+        }
+    }
+
+    if (s->mcr & UART_MCR_LOOP) {
+        /* in loopback mode, say that we just received a char */
+        serial_receive1(s, &s->tsr, 1);
+    } else if (qemu_chr_write(s->chr, &s->tsr, 1) != 1) {
+        if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
+            s->tsr_retry++;
+            qemu_mod_timer(s->transmit_timer,  new_xmit_ts + s->char_transmit_time);
+            return;
+        } else if (s->poll_msl < 0) {
+            /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
+            drop any further failed writes instantly, until we get one that goes through.
+            This is to prevent guests that log to unconnected pipes or pty's from stalling. */
+            s->tsr_retry = -1;
+        }
+    }
+    else {
+        s->tsr_retry = 0;
+    }
+
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
+    if (!(s->lsr & UART_LSR_THRE))
+        qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time);
+
+    if (s->lsr & UART_LSR_THRE) {
+        s->lsr |= UART_LSR_TEMT;
+        s->thr_ipending = 1;
+        serial_update_irq(s);
+    }
+}
+
+
+static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    SerialState *s = opaque;
+
+    addr &= 7;
+    DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
+    switch(addr) {
+    default:
+    case 0:
+        if (s->lcr & UART_LCR_DLAB) {
+            s->divider = (s->divider & 0xff00) | val;
+            serial_update_parameters(s);
+        } else {
+            s->thr = (uint8_t) val;
+            if(s->fcr & UART_FCR_FE) {
+                fifo_put(s, XMIT_FIFO, s->thr);
+                s->thr_ipending = 0;
+                s->lsr &= ~UART_LSR_TEMT;
+                s->lsr &= ~UART_LSR_THRE;
+                serial_update_irq(s);
+            } else {
+                s->thr_ipending = 0;
+                s->lsr &= ~UART_LSR_THRE;
+                serial_update_irq(s);
+            }
+            serial_xmit(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 the backend device is a real serial port, turn polling of the modem
+               status lines on physical port on or off depending on UART_IER_MSI state */
+            if (s->poll_msl >= 0) {
+                if (s->ier & UART_IER_MSI) {
+                     s->poll_msl = 1;
+                     serial_update_msl(s);
+                } else {
+                     qemu_del_timer(s->modem_status_poll);
+                     s->poll_msl = 0;
+                }
+            }
+            if (s->lsr & UART_LSR_THRE) {
+                s->thr_ipending = 1;
+                serial_update_irq(s);
+            }
+        }
+        break;
+    case 2:
+        val = val & 0xFF;
+
+        if (s->fcr == val)
+            break;
+
+        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
+        if ((val ^ s->fcr) & UART_FCR_FE)
+            val |= UART_FCR_XFR | UART_FCR_RFR;
+
+        /* FIFO clear */
+
+        if (val & UART_FCR_RFR) {
+            qemu_del_timer(s->fifo_timeout_timer);
+            s->timeout_ipending=0;
+            fifo_clear(s,RECV_FIFO);
+        }
+
+        if (val & UART_FCR_XFR) {
+            fifo_clear(s,XMIT_FIFO);
+        }
+
+        if (val & UART_FCR_FE) {
+            s->iir |= UART_IIR_FE;
+            /* Set RECV_FIFO trigger Level */
+            switch (val & 0xC0) {
+            case UART_FCR_ITL_1:
+                s->recv_fifo.itl = 1;
+                break;
+            case UART_FCR_ITL_2:
+                s->recv_fifo.itl = 4;
+                break;
+            case UART_FCR_ITL_3:
+                s->recv_fifo.itl = 8;
+                break;
+            case UART_FCR_ITL_4:
+                s->recv_fifo.itl = 14;
+                break;
+            }
+        } else
+            s->iir &= ~UART_IIR_FE;
+
+        /* Set fcr - or at least the bits in it that are supposed to "stick" */
+        s->fcr = val & 0xC9;
+        serial_update_irq(s);
+        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:
+        {
+            int flags;
+            int old_mcr = s->mcr;
+            s->mcr = val & 0x1f;
+            if (val & UART_MCR_LOOP)
+                break;
+
+            if (s->poll_msl >= 0 && old_mcr != s->mcr) {
+
+                qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+
+                flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
+
+                if (val & UART_MCR_RTS)
+                    flags |= CHR_TIOCM_RTS;
+                if (val & UART_MCR_DTR)
+                    flags |= CHR_TIOCM_DTR;
+
+                qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+                /* Update the modem status after a one-character-send wait-time, since there may be a response
+                   from the device/computer at the other end of the serial line */
+                qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time);
+            }
+        }
+        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 {
+            if(s->fcr & UART_FCR_FE) {
+                ret = fifo_get(s,RECV_FIFO);
+                if (s->recv_fifo.count == 0)
+                    s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
+                else
+                    qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
+                s->timeout_ipending = 0;
+            } else {
+                ret = s->rbr;
+                s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
+            }
+            serial_update_irq(s);
+            if (!(s->mcr & UART_MCR_LOOP)) {
+                /* in loopback mode, don't receive any data */
+                qemu_chr_accept_input(s->chr);
+            }
+        }
+        break;
+    case 1:
+        if (s->lcr & UART_LCR_DLAB) {
+            ret = (s->divider >> 8) & 0xff;
+        } else {
+            ret = s->ier;
+        }
+        break;
+    case 2:
+        ret = s->iir;
+        if ((ret & UART_IIR_ID) == 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;
+        /* Clear break and overrun interrupts */
+        if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
+            s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
+            serial_update_irq(s);
+        }
+        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 {
+            if (s->poll_msl >= 0)
+                serial_update_msl(s);
+            ret = s->msr;
+            /* Clear delta bits & msr int after read, if they were set */
+            if (s->msr & UART_MSR_ANY_DELTA) {
+                s->msr &= 0xF0;
+                serial_update_irq(s);
+            }
+        }
+        break;
+    case 7:
+        ret = s->scr;
+        break;
+    }
+    DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
+    return ret;
+}
+
+static int serial_can_receive(SerialState *s)
+{
+    if(s->fcr & UART_FCR_FE) {
+        if(s->recv_fifo.count < UART_FIFO_LENGTH)
+        /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
+        advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
+        effectively overriding the ITL that the guest has set. */
+             return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1;
+        else
+             return 0;
+    } else {
+    return !(s->lsr & UART_LSR_DR);
+    }
+}
+
+static void serial_receive_break(SerialState *s)
+{
+    s->rbr = 0;
+    /* When the LSR_DR is set a null byte is pushed into the fifo */
+    fifo_put(s, RECV_FIFO, '\0');
+    s->lsr |= UART_LSR_BI | UART_LSR_DR;
+    serial_update_irq(s);
+}
+
+/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
+static void fifo_timeout_int (void *opaque) {
+    SerialState *s = opaque;
+    if (s->recv_fifo.count) {
+        s->timeout_ipending = 1;
+        serial_update_irq(s);
+    }
+}
+
+static int serial_can_receive1(void *opaque)
+{
+    SerialState *s = opaque;
+    return serial_can_receive(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    SerialState *s = opaque;
+    if(s->fcr & UART_FCR_FE) {
+        int i;
+        for (i = 0; i < size; i++) {
+            fifo_put(s, RECV_FIFO, buf[i]);
+        }
+        s->lsr |= UART_LSR_DR;
+        /* call the timeout receive callback in 4 char transmit time */
+        qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
+    } else {
+        if (s->lsr & UART_LSR_DR)
+            s->lsr |= UART_LSR_OE;
+        s->rbr = buf[0];
+        s->lsr |= UART_LSR_DR;
+    }
+    serial_update_irq(s);
+}
+
+static void serial_event(void *opaque, int event)
+{
+    SerialState *s = opaque;
+    DPRINTF("event %x\n", event);
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+static void serial_pre_save(void *opaque)
+{
+    SerialState *s = opaque;
+    s->fcr_vmstate = s->fcr;
+}
+
+static int serial_post_load(void *opaque, int version_id)
+{
+    SerialState *s = opaque;
+
+    if (version_id < 3) {
+        s->fcr_vmstate = 0;
+    }
+    /* Initialize fcr via setter to perform essential side-effects */
+    serial_ioport_write(s, 0x02, s->fcr_vmstate);
+    serial_update_parameters(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_serial = {
+    .name = "serial",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .pre_save = serial_pre_save,
+    .post_load = serial_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16_V(divider, SerialState, 2),
+        VMSTATE_UINT8(rbr, SerialState),
+        VMSTATE_UINT8(ier, SerialState),
+        VMSTATE_UINT8(iir, SerialState),
+        VMSTATE_UINT8(lcr, SerialState),
+        VMSTATE_UINT8(mcr, SerialState),
+        VMSTATE_UINT8(lsr, SerialState),
+        VMSTATE_UINT8(msr, SerialState),
+        VMSTATE_UINT8(scr, SerialState),
+        VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void serial_reset(void *opaque)
+{
+    SerialState *s = opaque;
+
+    s->rbr = 0;
+    s->ier = 0;
+    s->iir = UART_IIR_NO_INT;
+    s->lcr = 0;
+    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
+    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+    /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
+    s->divider = 0x0C;
+    s->mcr = UART_MCR_OUT2;
+    s->scr = 0;
+    s->tsr_retry = 0;
+    s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
+    s->poll_msl = 0;
+
+    fifo_clear(s,RECV_FIFO);
+    fifo_clear(s,XMIT_FIFO);
+
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    s->thr_ipending = 0;
+    s->last_break_enable = 0;
+    qemu_irq_lower(s->irq);
+}
+
+static void serial_init_core(SerialState *s)
+{
+    if (!s->chr) {
+        fprintf(stderr, "Can't create serial device, empty char device\n");
+	exit(1);
+    }
+
+    s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
+
+    s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
+    s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s);
+
+    qemu_register_reset(serial_reset, s);
+
+    qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+                          serial_event, s);
+}
+
+/* Change the main reference oscillator frequency. */
+void serial_set_frequency(SerialState *s, uint32_t frequency)
+{
+    s->baudbase = frequency;
+    serial_update_parameters(s);
+}
+
+static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
+
+static int serial_isa_initfn(ISADevice *dev)
+{
+    static int index;
+    ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev);
+    SerialState *s = &isa->state;
+
+    if (isa->index == -1)
+        isa->index = index;
+    if (isa->index >= MAX_SERIAL_PORTS)
+        return -1;
+    if (isa->iobase == -1)
+        isa->iobase = isa_serial_io[isa->index];
+    if (isa->isairq == -1)
+        isa->isairq = isa_serial_irq[isa->index];
+    index++;
+
+    s->baudbase = 115200;
+    isa_init_irq(dev, &s->irq, isa->isairq);
+    serial_init_core(s);
+    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
+
+    register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
+    register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
+    isa_init_ioport_range(dev, isa->iobase, 8);
+    return 0;
+}
+
+static const VMStateDescription vmstate_isa_serial = {
+    .name = "serial",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+SerialState *serial_init(int base, qemu_irq irq, int baudbase,
+                         CharDriverState *chr)
+{
+    SerialState *s;
+
+    s = qemu_mallocz(sizeof(SerialState));
+
+    s->irq = irq;
+    s->baudbase = baudbase;
+    s->chr = chr;
+    serial_init_core(s);
+
+    vmstate_register(NULL, base, &vmstate_serial, s);
+
+    register_ioport_write(base, 8, 1, serial_ioport_write, s);
+    register_ioport_read(base, 8, 1, serial_ioport_read, s);
+    return s;
+}
+
+/* Memory mapped interface */
+static uint32_t serial_mm_readb(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+
+    return serial_ioport_read(s, addr >> s->it_shift) & 0xFF;
+}
+
+static void serial_mm_writeb(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    SerialState *s = opaque;
+
+    serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
+}
+
+static uint32_t serial_mm_readw_be(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
+    val = bswap16(val);
+    return val;
+}
+
+static uint32_t serial_mm_readw_le(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
+    return val;
+}
+
+static void serial_mm_writew_be(void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    SerialState *s = opaque;
+
+    value = bswap16(value);
+    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
+}
+
+static void serial_mm_writew_le(void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    SerialState *s = opaque;
+
+    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
+}
+
+static uint32_t serial_mm_readl_be(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, addr >> s->it_shift);
+    val = bswap32(val);
+    return val;
+}
+
+static uint32_t serial_mm_readl_le(void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, addr >> s->it_shift);
+    return val;
+}
+
+static void serial_mm_writel_be(void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    SerialState *s = opaque;
+
+    value = bswap32(value);
+    serial_ioport_write(s, addr >> s->it_shift, value);
+}
+
+static void serial_mm_writel_le(void *opaque, target_phys_addr_t addr,
+                                uint32_t value)
+{
+    SerialState *s = opaque;
+
+    serial_ioport_write(s, addr >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc * const serial_mm_read_be[] = {
+    &serial_mm_readb,
+    &serial_mm_readw_be,
+    &serial_mm_readl_be,
+};
+
+static CPUWriteMemoryFunc * const serial_mm_write_be[] = {
+    &serial_mm_writeb,
+    &serial_mm_writew_be,
+    &serial_mm_writel_be,
+};
+
+static CPUReadMemoryFunc * const serial_mm_read_le[] = {
+    &serial_mm_readb,
+    &serial_mm_readw_le,
+    &serial_mm_readl_le,
+};
+
+static CPUWriteMemoryFunc * const serial_mm_write_le[] = {
+    &serial_mm_writeb,
+    &serial_mm_writew_le,
+    &serial_mm_writel_le,
+};
+
+SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
+                             qemu_irq irq, int baudbase,
+                             CharDriverState *chr, int ioregister,
+                             int be)
+{
+    SerialState *s;
+    int s_io_memory;
+
+    s = qemu_mallocz(sizeof(SerialState));
+
+    s->it_shift = it_shift;
+    s->irq = irq;
+    s->baudbase = baudbase;
+    s->chr = chr;
+
+    serial_init_core(s);
+    vmstate_register(NULL, base, &vmstate_serial, s);
+
+    if (ioregister) {
+        if (be) {
+            s_io_memory = cpu_register_io_memory(serial_mm_read_be,
+                                                 serial_mm_write_be, s,
+                                                 DEVICE_NATIVE_ENDIAN);
+        } else {
+            s_io_memory = cpu_register_io_memory(serial_mm_read_le,
+                                                 serial_mm_write_le, s,
+                                                 DEVICE_NATIVE_ENDIAN);
+        }
+        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+    }
+    serial_update_msl(s);
+    return s;
+}
+
+static ISADeviceInfo serial_isa_info = {
+    .qdev.name  = "isa-serial",
+    .qdev.size  = sizeof(ISASerialState),
+    .qdev.vmsd  = &vmstate_isa_serial,
+    .init       = serial_isa_initfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("index", ISASerialState, index,   -1),
+        DEFINE_PROP_HEX32("iobase", ISASerialState, iobase,  -1),
+        DEFINE_PROP_UINT32("irq",   ISASerialState, isairq,  -1),
+        DEFINE_PROP_CHR("chardev",  ISASerialState, state.chr),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void serial_register_devices(void)
+{
+    isa_qdev_register(&serial_isa_info);
+}
+
+device_init(serial_register_devices)
diff --git a/qemu-0.15.x/hw/sga.c b/qemu-0.15.x/hw/sga.c
new file mode 100644
index 0000000..7ef750a
--- /dev/null
+++ b/qemu-0.15.x/hw/sga.c
@@ -0,0 +1,56 @@
+/*
+ * QEMU dummy ISA device for loading sgabios option rom.
+ *
+ * Copyright (c) 2011 Glauber Costa, Red Hat Inc.
+ *
+ * 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.
+ *
+ * sgabios code originally available at code.google.com/p/sgabios
+ *
+ */
+#include "pci.h"
+#include "pc.h"
+#include "loader.h"
+#include "sysemu.h"
+
+#define SGABIOS_FILENAME "sgabios.bin"
+
+typedef struct ISAGAState {
+    ISADevice dev;
+} ISASGAState;
+
+static int isa_cirrus_vga_initfn(ISADevice *dev)
+{
+    rom_add_vga(SGABIOS_FILENAME);
+    return 0;
+}
+
+static ISADeviceInfo sga_info = {
+    .qdev.name    = "sga",
+    .qdev.desc    = "Serial Graphics Adapter",
+    .qdev.size    = sizeof(ISASGAState),
+    .init         = isa_cirrus_vga_initfn,
+};
+
+static void sga_register(void)
+{
+      isa_qdev_register(&sga_info);
+}
+
+device_init(sga_register);
diff --git a/qemu-0.15.x/hw/sh.h b/qemu-0.15.x/hw/sh.h
new file mode 100644
index 0000000..d30e9f5
--- /dev/null
+++ b/qemu-0.15.x/hw/sh.h
@@ -0,0 +1,54 @@
+#ifndef QEMU_SH_H
+#define QEMU_SH_H
+/* Definitions for SH board emulation.  */
+
+#include "sh_intc.h"
+
+#define A7ADDR(x) ((x) & 0x1fffffff)
+#define P4ADDR(x) ((x) | 0xe0000000)
+
+/* sh7750.c */
+struct SH7750State;
+
+struct SH7750State *sh7750_init(CPUState * cpu);
+
+typedef struct {
+    /* The callback will be triggered if any of the designated lines change */
+    uint16_t portamask_trigger;
+    uint16_t portbmask_trigger;
+    /* Return 0 if no action was taken */
+    int (*port_change_cb) (uint16_t porta, uint16_t portb,
+			   uint16_t * periph_pdtra,
+			   uint16_t * periph_portdira,
+			   uint16_t * periph_pdtrb,
+			   uint16_t * periph_portdirb);
+} sh7750_io_device;
+
+int sh7750_register_io_device(struct SH7750State *s,
+			      sh7750_io_device * device);
+/* sh_timer.c */
+#define TMU012_FEAT_TOCR   (1 << 0)
+#define TMU012_FEAT_3CHAN  (1 << 1)
+#define TMU012_FEAT_EXTCLK (1 << 2)
+void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq,
+		 qemu_irq ch0_irq, qemu_irq ch1_irq,
+		 qemu_irq ch2_irq0, qemu_irq ch2_irq1);
+
+
+/* sh_serial.c */
+#define SH_SERIAL_FEAT_SCIF (1 << 0)
+void sh_serial_init (target_phys_addr_t base, int feat,
+		     uint32_t freq, CharDriverState *chr,
+		     qemu_irq eri_source,
+		     qemu_irq rxi_source,
+		     qemu_irq txi_source,
+		     qemu_irq tei_source,
+		     qemu_irq bri_source);
+
+/* sh7750.c */
+qemu_irq sh7750_irl(struct SH7750State *s);
+
+/* tc58128.c */
+int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2);
+
+#endif
diff --git a/qemu-0.15.x/hw/sh7750.c b/qemu-0.15.x/hw/sh7750.c
new file mode 100644
index 0000000..4f279e7
--- /dev/null
+++ b/qemu-0.15.x/hw/sh7750.c
@@ -0,0 +1,817 @@
+/*
+ * SH7750 device
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Copyright (c) 2005 Samuel Tardieu
+ *
+ * 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 <stdio.h>
+#include "hw.h"
+#include "sh.h"
+#include "sysemu.h"
+#include "sh7750_regs.h"
+#include "sh7750_regnames.h"
+#include "sh_intc.h"
+#include "cpu.h"
+
+#define NB_DEVICES 4
+
+typedef struct SH7750State {
+    /* CPU */
+    CPUSH4State *cpu;
+    /* Peripheral frequency in Hz */
+    uint32_t periph_freq;
+    /* SDRAM controller */
+    uint32_t bcr1;
+    uint16_t bcr2;
+    uint16_t bcr3;
+    uint32_t bcr4;
+    uint16_t rfcr;
+    /* PCMCIA controller */
+    uint16_t pcr;
+    /* IO ports */
+    uint16_t gpioic;
+    uint32_t pctra;
+    uint32_t pctrb;
+    uint16_t portdira;		/* Cached */
+    uint16_t portpullupa;	/* Cached */
+    uint16_t portdirb;		/* Cached */
+    uint16_t portpullupb;	/* Cached */
+    uint16_t pdtra;
+    uint16_t pdtrb;
+    uint16_t periph_pdtra;	/* Imposed by the peripherals */
+    uint16_t periph_portdira;	/* Direction seen from the peripherals */
+    uint16_t periph_pdtrb;	/* Imposed by the peripherals */
+    uint16_t periph_portdirb;	/* Direction seen from the peripherals */
+    sh7750_io_device *devices[NB_DEVICES];	/* External peripherals */
+
+    /* Cache */
+    uint32_t ccr;
+
+    struct intc_desc intc;
+} SH7750State;
+
+static inline int has_bcr3_and_bcr4(SH7750State * s)
+{
+	return (s->cpu->features & SH_FEATURE_BCR3_AND_BCR4);
+}
+/**********************************************************************
+ I/O ports
+**********************************************************************/
+
+int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device)
+{
+    int i;
+
+    for (i = 0; i < NB_DEVICES; i++) {
+	if (s->devices[i] == NULL) {
+	    s->devices[i] = device;
+	    return 0;
+	}
+    }
+    return -1;
+}
+
+static uint16_t portdir(uint32_t v)
+{
+#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n))
+    return
+	EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) |
+	EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) |
+	EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) |
+	EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) |
+	EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) |
+	EVENPORTMASK(0);
+}
+
+static uint16_t portpullup(uint32_t v)
+{
+#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n))
+    return
+	ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) |
+	ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) |
+	ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) |
+	ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) |
+	ODDPORTMASK(1) | ODDPORTMASK(0);
+}
+
+static uint16_t porta_lines(SH7750State * s)
+{
+    return (s->portdira & s->pdtra) |	/* CPU */
+	(s->periph_portdira & s->periph_pdtra) |	/* Peripherals */
+	(~(s->portdira | s->periph_portdira) & s->portpullupa);	/* Pullups */
+}
+
+static uint16_t portb_lines(SH7750State * s)
+{
+    return (s->portdirb & s->pdtrb) |	/* CPU */
+	(s->periph_portdirb & s->periph_pdtrb) |	/* Peripherals */
+	(~(s->portdirb | s->periph_portdirb) & s->portpullupb);	/* Pullups */
+}
+
+static void gen_port_interrupts(SH7750State * s)
+{
+    /* XXXXX interrupts not generated */
+}
+
+static void porta_changed(SH7750State * s, uint16_t prev)
+{
+    uint16_t currenta, changes;
+    int i, r = 0;
+
+#if 0
+    fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n",
+	    prev, porta_lines(s));
+    fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra);
+#endif
+    currenta = porta_lines(s);
+    if (currenta == prev)
+	return;
+    changes = currenta ^ prev;
+
+    for (i = 0; i < NB_DEVICES; i++) {
+	if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
+	    r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
+					       &s->periph_pdtra,
+					       &s->periph_portdira,
+					       &s->periph_pdtrb,
+					       &s->periph_portdirb);
+	}
+    }
+
+    if (r)
+	gen_port_interrupts(s);
+}
+
+static void portb_changed(SH7750State * s, uint16_t prev)
+{
+    uint16_t currentb, changes;
+    int i, r = 0;
+
+    currentb = portb_lines(s);
+    if (currentb == prev)
+	return;
+    changes = currentb ^ prev;
+
+    for (i = 0; i < NB_DEVICES; i++) {
+	if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
+	    r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
+					       &s->periph_pdtra,
+					       &s->periph_portdira,
+					       &s->periph_pdtrb,
+					       &s->periph_portdirb);
+	}
+    }
+
+    if (r)
+	gen_port_interrupts(s);
+}
+
+/**********************************************************************
+ Memory
+**********************************************************************/
+
+static void error_access(const char *kind, target_phys_addr_t addr)
+{
+    fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n",
+	    kind, regname(addr), addr);
+}
+
+static void ignore_access(const char *kind, target_phys_addr_t addr)
+{
+    fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n",
+	    kind, regname(addr), addr);
+}
+
+static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    switch (addr) {
+    default:
+	error_access("byte read", addr);
+        abort();
+    }
+}
+
+static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    SH7750State *s = opaque;
+
+    switch (addr) {
+    case SH7750_BCR2_A7:
+	return s->bcr2;
+    case SH7750_BCR3_A7:
+	if(!has_bcr3_and_bcr4(s))
+	    error_access("word read", addr);
+	return s->bcr3;
+    case SH7750_FRQCR_A7:
+	return 0;
+    case SH7750_PCR_A7:
+	return s->pcr;
+    case SH7750_RFCR_A7:
+	fprintf(stderr,
+		"Read access to refresh count register, incrementing\n");
+	return s->rfcr++;
+    case SH7750_PDTRA_A7:
+	return porta_lines(s);
+    case SH7750_PDTRB_A7:
+	return portb_lines(s);
+    case SH7750_RTCOR_A7:
+    case SH7750_RTCNT_A7:
+    case SH7750_RTCSR_A7:
+	ignore_access("word read", addr);
+	return 0;
+    default:
+	error_access("word read", addr);
+        abort();
+    }
+}
+
+static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SH7750State *s = opaque;
+
+    switch (addr) {
+    case SH7750_BCR1_A7:
+	return s->bcr1;
+    case SH7750_BCR4_A7:
+	if(!has_bcr3_and_bcr4(s))
+	    error_access("long read", addr);
+	return s->bcr4;
+    case SH7750_WCR1_A7:
+    case SH7750_WCR2_A7:
+    case SH7750_WCR3_A7:
+    case SH7750_MCR_A7:
+        ignore_access("long read", addr);
+        return 0;
+    case SH7750_MMUCR_A7:
+	return s->cpu->mmucr;
+    case SH7750_PTEH_A7:
+	return s->cpu->pteh;
+    case SH7750_PTEL_A7:
+	return s->cpu->ptel;
+    case SH7750_TTB_A7:
+	return s->cpu->ttb;
+    case SH7750_TEA_A7:
+	return s->cpu->tea;
+    case SH7750_TRA_A7:
+	return s->cpu->tra;
+    case SH7750_EXPEVT_A7:
+	return s->cpu->expevt;
+    case SH7750_INTEVT_A7:
+	return s->cpu->intevt;
+    case SH7750_CCR_A7:
+	return s->ccr;
+    case 0x1f000030:		/* Processor version */
+	return s->cpu->pvr;
+    case 0x1f000040:		/* Cache version */
+	return s->cpu->cvr;
+    case 0x1f000044:		/* Processor revision */
+	return s->cpu->prr;
+    default:
+	error_access("long read", addr);
+        abort();
+    }
+}
+
+#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \
+			&& a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB))
+static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
+			      uint32_t mem_value)
+{
+
+    if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) {
+	ignore_access("byte write", addr);
+	return;
+    }
+
+    error_access("byte write", addr);
+    abort();
+}
+
+static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr,
+			      uint32_t mem_value)
+{
+    SH7750State *s = opaque;
+    uint16_t temp;
+
+    switch (addr) {
+	/* SDRAM controller */
+    case SH7750_BCR2_A7:
+        s->bcr2 = mem_value;
+        return;
+    case SH7750_BCR3_A7:
+	if(!has_bcr3_and_bcr4(s))
+	    error_access("word write", addr);
+	s->bcr3 = mem_value;
+	return;
+    case SH7750_PCR_A7:
+	s->pcr = mem_value;
+	return;
+    case SH7750_RTCNT_A7:
+    case SH7750_RTCOR_A7:
+    case SH7750_RTCSR_A7:
+	ignore_access("word write", addr);
+	return;
+	/* IO ports */
+    case SH7750_PDTRA_A7:
+	temp = porta_lines(s);
+	s->pdtra = mem_value;
+	porta_changed(s, temp);
+	return;
+    case SH7750_PDTRB_A7:
+	temp = portb_lines(s);
+	s->pdtrb = mem_value;
+	portb_changed(s, temp);
+	return;
+    case SH7750_RFCR_A7:
+	fprintf(stderr, "Write access to refresh count register\n");
+	s->rfcr = mem_value;
+	return;
+    case SH7750_GPIOIC_A7:
+	s->gpioic = mem_value;
+	if (mem_value != 0) {
+	    fprintf(stderr, "I/O interrupts not implemented\n");
+            abort();
+	}
+	return;
+    default:
+	error_access("word write", addr);
+        abort();
+    }
+}
+
+static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
+			      uint32_t mem_value)
+{
+    SH7750State *s = opaque;
+    uint16_t temp;
+
+    switch (addr) {
+	/* SDRAM controller */
+    case SH7750_BCR1_A7:
+        s->bcr1 = mem_value;
+        return;
+    case SH7750_BCR4_A7:
+	if(!has_bcr3_and_bcr4(s))
+	    error_access("long write", addr);
+	s->bcr4 = mem_value;
+	return;
+    case SH7750_WCR1_A7:
+    case SH7750_WCR2_A7:
+    case SH7750_WCR3_A7:
+    case SH7750_MCR_A7:
+	ignore_access("long write", addr);
+	return;
+	/* IO ports */
+    case SH7750_PCTRA_A7:
+	temp = porta_lines(s);
+	s->pctra = mem_value;
+	s->portdira = portdir(mem_value);
+	s->portpullupa = portpullup(mem_value);
+	porta_changed(s, temp);
+	return;
+    case SH7750_PCTRB_A7:
+	temp = portb_lines(s);
+	s->pctrb = mem_value;
+	s->portdirb = portdir(mem_value);
+	s->portpullupb = portpullup(mem_value);
+	portb_changed(s, temp);
+	return;
+    case SH7750_MMUCR_A7:
+        if (mem_value & MMUCR_TI) {
+            cpu_sh4_invalidate_tlb(s->cpu);
+        }
+        s->cpu->mmucr = mem_value & ~MMUCR_TI;
+        return;
+    case SH7750_PTEH_A7:
+        /* If asid changes, clear all registered tlb entries. */
+	if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))
+	    tlb_flush(s->cpu, 1);
+	s->cpu->pteh = mem_value;
+	return;
+    case SH7750_PTEL_A7:
+	s->cpu->ptel = mem_value;
+	return;
+    case SH7750_PTEA_A7:
+	s->cpu->ptea = mem_value & 0x0000000f;
+	return;
+    case SH7750_TTB_A7:
+	s->cpu->ttb = mem_value;
+	return;
+    case SH7750_TEA_A7:
+	s->cpu->tea = mem_value;
+	return;
+    case SH7750_TRA_A7:
+	s->cpu->tra = mem_value & 0x000007ff;
+	return;
+    case SH7750_EXPEVT_A7:
+	s->cpu->expevt = mem_value & 0x000007ff;
+	return;
+    case SH7750_INTEVT_A7:
+	s->cpu->intevt = mem_value & 0x000007ff;
+	return;
+    case SH7750_CCR_A7:
+	s->ccr = mem_value;
+	return;
+    default:
+	error_access("long write", addr);
+        abort();
+    }
+}
+
+static CPUReadMemoryFunc * const sh7750_mem_read[] = {
+    sh7750_mem_readb,
+    sh7750_mem_readw,
+    sh7750_mem_readl
+};
+
+static CPUWriteMemoryFunc * const sh7750_mem_write[] = {
+    sh7750_mem_writeb,
+    sh7750_mem_writew,
+    sh7750_mem_writel
+};
+
+/* sh775x interrupt controller tables for sh_intc.c
+ * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+ */
+
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+	IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7,
+	IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E,
+	IRL0, IRL1, IRL2, IRL3,
+	HUDI, GPIOI,
+	DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+	DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+	DMAC_DMAE,
+	PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+	PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
+	TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+	RTC_ATI, RTC_PRI, RTC_CUI,
+	SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
+	SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
+	WDT,
+	REF_RCMI, REF_ROVI,
+
+	/* interrupt groups */
+	DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
+	/* irl bundle */
+	IRL,
+
+	NR_SOURCES,
+};
+
+static struct intc_vect vectors[] = {
+	INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+	INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+	INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+	INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+	INTC_VECT(RTC_CUI, 0x4c0),
+	INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
+	INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
+	INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
+	INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+	INTC_VECT(WDT, 0x560),
+	INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
+};
+
+static struct intc_group groups[] = {
+	INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+	INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
+	INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
+	INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
+
+static struct intc_prio_reg prio_registers[] = {
+	{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+	{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+	{ 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+	{ 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+	{ 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+						 TMU4, TMU3,
+						 PCIC1, PCIC0_PCISERR } },
+};
+
+/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+
+static struct intc_vect vectors_dma4[] = {
+	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+	INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma4[] = {
+	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+		   DMAC_DMTE3, DMAC_DMAE),
+};
+
+/* SH7750R and SH7751R both have 8-channel DMA controllers */
+
+static struct intc_vect vectors_dma8[] = {
+	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+	INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+	INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+	INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma8[] = {
+	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+		   DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+		   DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+};
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+
+static struct intc_vect vectors_tmu34[] = {
+	INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+	{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, TMU4, TMU3,
+	    PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+	    PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
+	    PCIC1_PCIDMA3, PCIC0_PCISERR } },
+};
+
+/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
+
+static struct intc_vect vectors_irlm[] = {
+	INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+	INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+/* SH7751 and SH7751R both have PCI */
+
+static struct intc_vect vectors_pci[] = {
+	INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
+	INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
+	INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
+	INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
+};
+
+static struct intc_group groups_pci[] = {
+	INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+		   PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
+};
+
+static struct intc_vect vectors_irl[] = {
+	INTC_VECT(IRL_0, 0x200),
+	INTC_VECT(IRL_1, 0x220),
+	INTC_VECT(IRL_2, 0x240),
+	INTC_VECT(IRL_3, 0x260),
+	INTC_VECT(IRL_4, 0x280),
+	INTC_VECT(IRL_5, 0x2a0),
+	INTC_VECT(IRL_6, 0x2c0),
+	INTC_VECT(IRL_7, 0x2e0),
+	INTC_VECT(IRL_8, 0x300),
+	INTC_VECT(IRL_9, 0x320),
+	INTC_VECT(IRL_A, 0x340),
+	INTC_VECT(IRL_B, 0x360),
+	INTC_VECT(IRL_C, 0x380),
+	INTC_VECT(IRL_D, 0x3a0),
+	INTC_VECT(IRL_E, 0x3c0),
+};
+
+static struct intc_group groups_irl[] = {
+	INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6,
+		IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E),
+};
+
+/**********************************************************************
+ Memory mapped cache and TLB
+**********************************************************************/
+
+#define MM_REGION_MASK   0x07000000
+#define MM_ICACHE_ADDR   (0)
+#define MM_ICACHE_DATA   (1)
+#define MM_ITLB_ADDR     (2)
+#define MM_ITLB_DATA     (3)
+#define MM_OCACHE_ADDR   (4)
+#define MM_OCACHE_DATA   (5)
+#define MM_UTLB_ADDR     (6)
+#define MM_UTLB_DATA     (7)
+#define MM_REGION_TYPE(addr)  ((addr & MM_REGION_MASK) >> 24)
+
+static uint32_t invalid_read(void *opaque, target_phys_addr_t addr)
+{
+    abort();
+
+    return 0;
+}
+
+static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
+{
+    SH7750State *s = opaque;
+    uint32_t ret = 0;
+
+    switch (MM_REGION_TYPE(addr)) {
+    case MM_ICACHE_ADDR:
+    case MM_ICACHE_DATA:
+        /* do nothing */
+	break;
+    case MM_ITLB_ADDR:
+        ret = cpu_sh4_read_mmaped_itlb_addr(s->cpu, addr);
+        break;
+    case MM_ITLB_DATA:
+        ret = cpu_sh4_read_mmaped_itlb_data(s->cpu, addr);
+        break;
+    case MM_OCACHE_ADDR:
+    case MM_OCACHE_DATA:
+        /* do nothing */
+	break;
+    case MM_UTLB_ADDR:
+        ret = cpu_sh4_read_mmaped_utlb_addr(s->cpu, addr);
+        break;
+    case MM_UTLB_DATA:
+        ret = cpu_sh4_read_mmaped_utlb_data(s->cpu, addr);
+        break;
+    default:
+        abort();
+    }
+
+    return ret;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr,
+			  uint32_t mem_value)
+{
+    abort();
+}
+
+static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
+				uint32_t mem_value)
+{
+    SH7750State *s = opaque;
+
+    switch (MM_REGION_TYPE(addr)) {
+    case MM_ICACHE_ADDR:
+    case MM_ICACHE_DATA:
+        /* do nothing */
+	break;
+    case MM_ITLB_ADDR:
+        cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value);
+        break;
+    case MM_ITLB_DATA:
+        cpu_sh4_write_mmaped_itlb_data(s->cpu, addr, mem_value);
+        abort();
+	break;
+    case MM_OCACHE_ADDR:
+    case MM_OCACHE_DATA:
+        /* do nothing */
+	break;
+    case MM_UTLB_ADDR:
+        cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value);
+	break;
+    case MM_UTLB_DATA:
+        cpu_sh4_write_mmaped_utlb_data(s->cpu, addr, mem_value);
+	break;
+    default:
+        abort();
+	break;
+    }
+}
+
+static CPUReadMemoryFunc * const sh7750_mmct_read[] = {
+    invalid_read,
+    invalid_read,
+    sh7750_mmct_readl
+};
+
+static CPUWriteMemoryFunc * const sh7750_mmct_write[] = {
+    invalid_write,
+    invalid_write,
+    sh7750_mmct_writel
+};
+
+SH7750State *sh7750_init(CPUSH4State * cpu)
+{
+    SH7750State *s;
+    int sh7750_io_memory;
+    int sh7750_mm_cache_and_tlb; /* memory mapped cache and tlb */
+
+    s = qemu_mallocz(sizeof(SH7750State));
+    s->cpu = cpu;
+    s->periph_freq = 60000000;	/* 60MHz */
+    sh7750_io_memory = cpu_register_io_memory(sh7750_mem_read,
+					      sh7750_mem_write, s,
+                                              DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory_offset(0x1f000000, 0x1000,
+                                        sh7750_io_memory, 0x1f000000);
+    cpu_register_physical_memory_offset(0xff000000, 0x1000,
+                                        sh7750_io_memory, 0x1f000000);
+    cpu_register_physical_memory_offset(0x1f800000, 0x1000,
+                                        sh7750_io_memory, 0x1f800000);
+    cpu_register_physical_memory_offset(0xff800000, 0x1000,
+                                        sh7750_io_memory, 0x1f800000);
+    cpu_register_physical_memory_offset(0x1fc00000, 0x1000,
+                                        sh7750_io_memory, 0x1fc00000);
+    cpu_register_physical_memory_offset(0xffc00000, 0x1000,
+                                        sh7750_io_memory, 0x1fc00000);
+
+    sh7750_mm_cache_and_tlb = cpu_register_io_memory(sh7750_mmct_read,
+						     sh7750_mmct_write, s,
+                                                     DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(0xf0000000, 0x08000000,
+				 sh7750_mm_cache_and_tlb);
+
+    sh_intc_init(&s->intc, NR_SOURCES,
+		 _INTC_ARRAY(mask_registers),
+		 _INTC_ARRAY(prio_registers));
+
+    sh_intc_register_sources(&s->intc,
+			     _INTC_ARRAY(vectors),
+			     _INTC_ARRAY(groups));
+
+    cpu->intc_handle = &s->intc;
+
+    sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0],
+		   s->intc.irqs[SCI1_ERI],
+		   s->intc.irqs[SCI1_RXI],
+		   s->intc.irqs[SCI1_TXI],
+		   s->intc.irqs[SCI1_TEI],
+		   NULL);
+    sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF,
+		   s->periph_freq, serial_hds[1],
+		   s->intc.irqs[SCIF_ERI],
+		   s->intc.irqs[SCIF_RXI],
+		   s->intc.irqs[SCIF_TXI],
+		   NULL,
+		   s->intc.irqs[SCIF_BRI]);
+
+    tmu012_init(0x1fd80000,
+		TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
+		s->periph_freq,
+		s->intc.irqs[TMU0],
+		s->intc.irqs[TMU1],
+		s->intc.irqs[TMU2_TUNI],
+		s->intc.irqs[TMU2_TICPI]);
+
+    if (cpu->id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) {
+        sh_intc_register_sources(&s->intc,
+				 _INTC_ARRAY(vectors_dma4),
+				 _INTC_ARRAY(groups_dma4));
+    }
+
+    if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) {
+        sh_intc_register_sources(&s->intc,
+				 _INTC_ARRAY(vectors_dma8),
+				 _INTC_ARRAY(groups_dma8));
+    }
+
+    if (cpu->id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) {
+        sh_intc_register_sources(&s->intc,
+				 _INTC_ARRAY(vectors_tmu34),
+				 NULL, 0);
+        tmu012_init(0x1e100000, 0, s->periph_freq,
+		    s->intc.irqs[TMU3],
+		    s->intc.irqs[TMU4],
+		    NULL, NULL);
+    }
+
+    if (cpu->id & (SH_CPU_SH7751_ALL)) {
+        sh_intc_register_sources(&s->intc,
+				 _INTC_ARRAY(vectors_pci),
+				 _INTC_ARRAY(groups_pci));
+    }
+
+    if (cpu->id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) {
+        sh_intc_register_sources(&s->intc,
+				 _INTC_ARRAY(vectors_irlm),
+				 NULL, 0);
+    }
+
+    sh_intc_register_sources(&s->intc,
+				_INTC_ARRAY(vectors_irl),
+				_INTC_ARRAY(groups_irl));
+    return s;
+}
+
+qemu_irq sh7750_irl(SH7750State *s)
+{
+    sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */
+    return qemu_allocate_irqs(sh_intc_set_irl, sh_intc_source(&s->intc, IRL),
+                               1)[0];
+}
diff --git a/qemu-0.15.x/hw/sh7750_regnames.c b/qemu-0.15.x/hw/sh7750_regnames.c
new file mode 100644
index 0000000..5a5a2d8
--- /dev/null
+++ b/qemu-0.15.x/hw/sh7750_regnames.c
@@ -0,0 +1,97 @@
+#include "hw.h"
+#include "sh.h"
+#include "sh7750_regs.h"
+#include "sh7750_regnames.h"
+
+#define REGNAME(r) {r, #r},
+
+typedef struct {
+    uint32_t regaddr;
+    const char *regname;
+} regname_t;
+
+static regname_t regnames[] = {
+    REGNAME(SH7750_PTEH_A7)
+	REGNAME(SH7750_PTEL_A7)
+	REGNAME(SH7750_PTEA_A7)
+	REGNAME(SH7750_TTB_A7)
+	REGNAME(SH7750_TEA_A7)
+	REGNAME(SH7750_MMUCR_A7)
+	REGNAME(SH7750_CCR_A7)
+	REGNAME(SH7750_QACR0_A7)
+	REGNAME(SH7750_QACR1_A7)
+	REGNAME(SH7750_TRA_A7)
+	REGNAME(SH7750_EXPEVT_A7)
+	REGNAME(SH7750_INTEVT_A7)
+	REGNAME(SH7750_STBCR_A7)
+	REGNAME(SH7750_STBCR2_A7)
+	REGNAME(SH7750_FRQCR_A7)
+	REGNAME(SH7750_WTCNT_A7)
+	REGNAME(SH7750_WTCSR_A7)
+	REGNAME(SH7750_R64CNT_A7)
+	REGNAME(SH7750_RSECCNT_A7)
+	REGNAME(SH7750_RMINCNT_A7)
+	REGNAME(SH7750_RHRCNT_A7)
+	REGNAME(SH7750_RWKCNT_A7)
+	REGNAME(SH7750_RDAYCNT_A7)
+	REGNAME(SH7750_RMONCNT_A7)
+	REGNAME(SH7750_RYRCNT_A7)
+	REGNAME(SH7750_RSECAR_A7)
+	REGNAME(SH7750_RMINAR_A7)
+	REGNAME(SH7750_RHRAR_A7)
+	REGNAME(SH7750_RWKAR_A7)
+	REGNAME(SH7750_RDAYAR_A7)
+	REGNAME(SH7750_RMONAR_A7)
+	REGNAME(SH7750_RCR1_A7)
+	REGNAME(SH7750_RCR2_A7)
+	REGNAME(SH7750_BCR1_A7)
+	REGNAME(SH7750_BCR2_A7)
+	REGNAME(SH7750_WCR1_A7)
+	REGNAME(SH7750_WCR2_A7)
+	REGNAME(SH7750_WCR3_A7)
+	REGNAME(SH7750_MCR_A7)
+	REGNAME(SH7750_PCR_A7)
+	REGNAME(SH7750_RTCSR_A7)
+	REGNAME(SH7750_RTCNT_A7)
+	REGNAME(SH7750_RTCOR_A7)
+	REGNAME(SH7750_RFCR_A7)
+	REGNAME(SH7750_SAR0_A7)
+	REGNAME(SH7750_SAR1_A7)
+	REGNAME(SH7750_SAR2_A7)
+	REGNAME(SH7750_SAR3_A7)
+	REGNAME(SH7750_DAR0_A7)
+	REGNAME(SH7750_DAR1_A7)
+	REGNAME(SH7750_DAR2_A7)
+	REGNAME(SH7750_DAR3_A7)
+	REGNAME(SH7750_DMATCR0_A7)
+	REGNAME(SH7750_DMATCR1_A7)
+	REGNAME(SH7750_DMATCR2_A7)
+	REGNAME(SH7750_DMATCR3_A7)
+	REGNAME(SH7750_CHCR0_A7)
+	REGNAME(SH7750_CHCR1_A7)
+	REGNAME(SH7750_CHCR2_A7)
+	REGNAME(SH7750_CHCR3_A7)
+	REGNAME(SH7750_DMAOR_A7)
+	REGNAME(SH7750_PCTRA_A7)
+	REGNAME(SH7750_PDTRA_A7)
+	REGNAME(SH7750_PCTRB_A7)
+	REGNAME(SH7750_PDTRB_A7)
+	REGNAME(SH7750_GPIOIC_A7)
+	REGNAME(SH7750_ICR_A7)
+	REGNAME(SH7750_BCR3_A7)
+	REGNAME(SH7750_BCR4_A7)
+	REGNAME(SH7750_SDMR2_A7)
+	REGNAME(SH7750_SDMR3_A7) {(uint32_t) - 1, NULL}
+};
+
+const char *regname(uint32_t addr)
+{
+    unsigned int i;
+
+    for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) {
+	if (regnames[i].regaddr == addr)
+	    return regnames[i].regname;
+    }
+
+    return "<unknown reg>";
+}
diff --git a/qemu-0.15.x/hw/sh7750_regnames.h b/qemu-0.15.x/hw/sh7750_regnames.h
new file mode 100644
index 0000000..7463709
--- /dev/null
+++ b/qemu-0.15.x/hw/sh7750_regnames.h
@@ -0,0 +1,6 @@
+#ifndef _SH7750_REGNAMES_H
+#define _SH7750_REGNAMES_H
+
+const char *regname(uint32_t addr);
+
+#endif				/* _SH7750_REGNAMES_H */
diff --git a/qemu-0.15.x/hw/sh7750_regs.h b/qemu-0.15.x/hw/sh7750_regs.h
new file mode 100644
index 0000000..6ec13ab
--- /dev/null
+++ b/qemu-0.15.x/hw/sh7750_regs.h
@@ -0,0 +1,1277 @@
+/*
+ * SH-7750 memory-mapped registers
+ * This file based on information provided in the following document:
+ * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S)
+ *  Hardware Manual"
+ *  Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Alexandra Kossovsky <sasha at oktet.ru>
+ *         Victor V. Vengerov <vvv at oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ *
+ * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
+ */
+
+#ifndef __SH7750_REGS_H__
+#define __SH7750_REGS_H__
+
+/*
+ * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and
+ * in 0x1f000000 - 0x1fffffff (area 7 address)
+ */
+#define SH7750_P4_BASE       0xff000000	/* Accessible only in
+					   privileged mode */
+#define SH7750_A7_BASE       0x1f000000	/* Accessible only using TLB */
+
+#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
+#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
+
+/*
+ * MMU Registers
+ */
+
+/* Page Table Entry High register - PTEH */
+#define SH7750_PTEH_REGOFS    0x000000	/* offset */
+#define SH7750_PTEH           SH7750_P4_REG32(SH7750_PTEH_REGOFS)
+#define SH7750_PTEH_A7        SH7750_A7_REG32(SH7750_PTEH_REGOFS)
+#define SH7750_PTEH_VPN       0xfffffd00	/* Virtual page number */
+#define SH7750_PTEH_VPN_S     10
+#define SH7750_PTEH_ASID      0x000000ff	/* Address space identifier */
+#define SH7750_PTEH_ASID_S    0
+
+/* Page Table Entry Low register - PTEL */
+#define SH7750_PTEL_REGOFS    0x000004	/* offset */
+#define SH7750_PTEL           SH7750_P4_REG32(SH7750_PTEL_REGOFS)
+#define SH7750_PTEL_A7        SH7750_A7_REG32(SH7750_PTEL_REGOFS)
+#define SH7750_PTEL_PPN       0x1ffffc00	/* Physical page number */
+#define SH7750_PTEL_PPN_S     10
+#define SH7750_PTEL_V         0x00000100	/* Validity (0-entry is invalid) */
+#define SH7750_PTEL_SZ1       0x00000080	/* Page size bit 1 */
+#define SH7750_PTEL_SZ0       0x00000010	/* Page size bit 0 */
+#define SH7750_PTEL_SZ_1KB    0x00000000	/*   1-kbyte page */
+#define SH7750_PTEL_SZ_4KB    0x00000010	/*   4-kbyte page */
+#define SH7750_PTEL_SZ_64KB   0x00000080	/*   64-kbyte page */
+#define SH7750_PTEL_SZ_1MB    0x00000090	/*   1-Mbyte page */
+#define SH7750_PTEL_PR        0x00000060	/* Protection Key Data */
+#define SH7750_PTEL_PR_ROPO   0x00000000	/*   read-only in priv mode */
+#define SH7750_PTEL_PR_RWPO   0x00000020	/*   read-write in priv mode */
+#define SH7750_PTEL_PR_ROPU   0x00000040	/*   read-only in priv or user mode */
+#define SH7750_PTEL_PR_RWPU   0x00000060	/*   read-write in priv or user mode */
+#define SH7750_PTEL_C         0x00000008	/* Cacheability
+						   (0 - page not cacheable) */
+#define SH7750_PTEL_D         0x00000004	/* Dirty bit (1 - write has been
+						   performed to a page) */
+#define SH7750_PTEL_SH        0x00000002	/* Share Status bit (1 - page are
+						   shared by processes) */
+#define SH7750_PTEL_WT        0x00000001	/* Write-through bit, specifies the
+						   cache write mode:
+						   0 - Copy-back mode
+						   1 - Write-through mode */
+
+/* Page Table Entry Assistance register - PTEA */
+#define SH7750_PTEA_REGOFS    0x000034	/* offset */
+#define SH7750_PTEA           SH7750_P4_REG32(SH7750_PTEA_REGOFS)
+#define SH7750_PTEA_A7        SH7750_A7_REG32(SH7750_PTEA_REGOFS)
+#define SH7750_PTEA_TC        0x00000008	/* Timing Control bit
+						   0 - use area 5 wait states
+						   1 - use area 6 wait states */
+#define SH7750_PTEA_SA        0x00000007	/* Space Attribute bits: */
+#define SH7750_PTEA_SA_UNDEF  0x00000000	/*    0 - undefined */
+#define SH7750_PTEA_SA_IOVAR  0x00000001	/*    1 - variable-size I/O space */
+#define SH7750_PTEA_SA_IO8    0x00000002	/*    2 - 8-bit I/O space */
+#define SH7750_PTEA_SA_IO16   0x00000003	/*    3 - 16-bit I/O space */
+#define SH7750_PTEA_SA_CMEM8  0x00000004	/*    4 - 8-bit common memory space */
+#define SH7750_PTEA_SA_CMEM16 0x00000005	/*    5 - 16-bit common memory space */
+#define SH7750_PTEA_SA_AMEM8  0x00000006	/*    6 - 8-bit attr memory space */
+#define SH7750_PTEA_SA_AMEM16 0x00000007	/*    7 - 16-bit attr memory space */
+
+
+/* Translation table base register */
+#define SH7750_TTB_REGOFS     0x000008	/* offset */
+#define SH7750_TTB            SH7750_P4_REG32(SH7750_TTB_REGOFS)
+#define SH7750_TTB_A7         SH7750_A7_REG32(SH7750_TTB_REGOFS)
+
+/* TLB exeption address register - TEA */
+#define SH7750_TEA_REGOFS     0x00000c	/* offset */
+#define SH7750_TEA            SH7750_P4_REG32(SH7750_TEA_REGOFS)
+#define SH7750_TEA_A7         SH7750_A7_REG32(SH7750_TEA_REGOFS)
+
+/* MMU control register - MMUCR */
+#define SH7750_MMUCR_REGOFS   0x000010	/* offset */
+#define SH7750_MMUCR          SH7750_P4_REG32(SH7750_MMUCR_REGOFS)
+#define SH7750_MMUCR_A7       SH7750_A7_REG32(SH7750_MMUCR_REGOFS)
+#define SH7750_MMUCR_AT       0x00000001	/* Address translation bit */
+#define SH7750_MMUCR_TI       0x00000004	/* TLB invalidate */
+#define SH7750_MMUCR_SV       0x00000100	/* Single Virtual Mode bit */
+#define SH7750_MMUCR_SQMD     0x00000200	/* Store Queue Mode bit */
+#define SH7750_MMUCR_URC      0x0000FC00	/* UTLB Replace Counter */
+#define SH7750_MMUCR_URC_S    10
+#define SH7750_MMUCR_URB      0x00FC0000	/* UTLB Replace Boundary */
+#define SH7750_MMUCR_URB_S    18
+#define SH7750_MMUCR_LRUI     0xFC000000	/* Least Recently Used ITLB */
+#define SH7750_MMUCR_LRUI_S   26
+
+
+
+
+/*
+ * Cache registers
+ *   IC -- instructions cache
+ *   OC -- operand cache
+ */
+
+/* Cache Control Register - CCR */
+#define SH7750_CCR_REGOFS     0x00001c	/* offset */
+#define SH7750_CCR            SH7750_P4_REG32(SH7750_CCR_REGOFS)
+#define SH7750_CCR_A7         SH7750_A7_REG32(SH7750_CCR_REGOFS)
+
+#define SH7750_CCR_IIX      0x00008000	/* IC index enable bit */
+#define SH7750_CCR_ICI      0x00000800	/* IC invalidation bit:
+					   set it to clear IC */
+#define SH7750_CCR_ICE      0x00000100	/* IC enable bit */
+#define SH7750_CCR_OIX      0x00000080	/* OC index enable bit */
+#define SH7750_CCR_ORA      0x00000020	/* OC RAM enable bit
+					   if you set OCE = 0,
+					   you should set ORA = 0 */
+#define SH7750_CCR_OCI      0x00000008	/* OC invalidation bit */
+#define SH7750_CCR_CB       0x00000004	/* Copy-back bit for P1 area */
+#define SH7750_CCR_WT       0x00000002	/* Write-through bit for P0,U0,P3 area */
+#define SH7750_CCR_OCE      0x00000001	/* OC enable bit */
+
+/* Queue address control register 0 - QACR0 */
+#define SH7750_QACR0_REGOFS   0x000038	/* offset */
+#define SH7750_QACR0          SH7750_P4_REG32(SH7750_QACR0_REGOFS)
+#define SH7750_QACR0_A7       SH7750_A7_REG32(SH7750_QACR0_REGOFS)
+
+/* Queue address control register 1 - QACR1 */
+#define SH7750_QACR1_REGOFS   0x00003c	/* offset */
+#define SH7750_QACR1          SH7750_P4_REG32(SH7750_QACR1_REGOFS)
+#define SH7750_QACR1_A7       SH7750_A7_REG32(SH7750_QACR1_REGOFS)
+
+
+/*
+ * Exeption-related registers
+ */
+
+/* Immediate data for TRAPA instuction - TRA */
+#define SH7750_TRA_REGOFS     0x000020	/* offset */
+#define SH7750_TRA            SH7750_P4_REG32(SH7750_TRA_REGOFS)
+#define SH7750_TRA_A7         SH7750_A7_REG32(SH7750_TRA_REGOFS)
+
+#define SH7750_TRA_IMM      0x000003fd	/* Immediate data operand */
+#define SH7750_TRA_IMM_S    2
+
+/* Exeption event register - EXPEVT */
+#define SH7750_EXPEVT_REGOFS  0x000024
+#define SH7750_EXPEVT         SH7750_P4_REG32(SH7750_EXPEVT_REGOFS)
+#define SH7750_EXPEVT_A7      SH7750_A7_REG32(SH7750_EXPEVT_REGOFS)
+
+#define SH7750_EXPEVT_EX      0x00000fff	/* Exeption code */
+#define SH7750_EXPEVT_EX_S    0
+
+/* Interrupt event register */
+#define SH7750_INTEVT_REGOFS  0x000028
+#define SH7750_INTEVT         SH7750_P4_REG32(SH7750_INTEVT_REGOFS)
+#define SH7750_INTEVT_A7      SH7750_A7_REG32(SH7750_INTEVT_REGOFS)
+#define SH7750_INTEVT_EX    0x00000fff	/* Exeption code */
+#define SH7750_INTEVT_EX_S  0
+
+/*
+ * Exception/interrupt codes
+ */
+#define SH7750_EVT_TO_NUM(evt)  ((evt) >> 5)
+
+/* Reset exception category */
+#define SH7750_EVT_POWER_ON_RST        0x000	/* Power-on reset */
+#define SH7750_EVT_MANUAL_RST          0x020	/* Manual reset */
+#define SH7750_EVT_TLB_MULT_HIT        0x140	/* TLB multiple-hit exception */
+
+/* General exception category */
+#define SH7750_EVT_USER_BREAK          0x1E0	/* User break */
+#define SH7750_EVT_IADDR_ERR           0x0E0	/* Instruction address error */
+#define SH7750_EVT_TLB_READ_MISS       0x040	/* ITLB miss exception /
+						   DTLB miss exception (read) */
+#define SH7750_EVT_TLB_READ_PROTV      0x0A0	/* ITLB protection violation /
+						   DTLB protection violation (read) */
+#define SH7750_EVT_ILLEGAL_INSTR       0x180	/* General Illegal Instruction
+						   exception */
+#define SH7750_EVT_SLOT_ILLEGAL_INSTR  0x1A0	/* Slot Illegal Instruction
+						   exception */
+#define SH7750_EVT_FPU_DISABLE         0x800	/* General FPU disable exception */
+#define SH7750_EVT_SLOT_FPU_DISABLE    0x820	/* Slot FPU disable exception */
+#define SH7750_EVT_DATA_READ_ERR       0x0E0	/* Data address error (read) */
+#define SH7750_EVT_DATA_WRITE_ERR      0x100	/* Data address error (write) */
+#define SH7750_EVT_DTLB_WRITE_MISS     0x060	/* DTLB miss exception (write) */
+#define SH7750_EVT_DTLB_WRITE_PROTV    0x0C0	/* DTLB protection violation
+						   exception (write) */
+#define SH7750_EVT_FPU_EXCEPTION       0x120	/* FPU exception */
+#define SH7750_EVT_INITIAL_PGWRITE     0x080	/* Initial Page Write exception */
+#define SH7750_EVT_TRAPA               0x160	/* Unconditional trap (TRAPA) */
+
+/* Interrupt exception category */
+#define SH7750_EVT_NMI                 0x1C0	/* Non-maskable interrupt */
+#define SH7750_EVT_IRQ0                0x200	/* External Interrupt 0 */
+#define SH7750_EVT_IRQ1                0x220	/* External Interrupt 1 */
+#define SH7750_EVT_IRQ2                0x240	/* External Interrupt 2 */
+#define SH7750_EVT_IRQ3                0x260	/* External Interrupt 3 */
+#define SH7750_EVT_IRQ4                0x280	/* External Interrupt 4 */
+#define SH7750_EVT_IRQ5                0x2A0	/* External Interrupt 5 */
+#define SH7750_EVT_IRQ6                0x2C0	/* External Interrupt 6 */
+#define SH7750_EVT_IRQ7                0x2E0	/* External Interrupt 7 */
+#define SH7750_EVT_IRQ8                0x300	/* External Interrupt 8 */
+#define SH7750_EVT_IRQ9                0x320	/* External Interrupt 9 */
+#define SH7750_EVT_IRQA                0x340	/* External Interrupt A */
+#define SH7750_EVT_IRQB                0x360	/* External Interrupt B */
+#define SH7750_EVT_IRQC                0x380	/* External Interrupt C */
+#define SH7750_EVT_IRQD                0x3A0	/* External Interrupt D */
+#define SH7750_EVT_IRQE                0x3C0	/* External Interrupt E */
+
+/* Peripheral Module Interrupts - Timer Unit (TMU) */
+#define SH7750_EVT_TUNI0               0x400	/* TMU Underflow Interrupt 0 */
+#define SH7750_EVT_TUNI1               0x420	/* TMU Underflow Interrupt 1 */
+#define SH7750_EVT_TUNI2               0x440	/* TMU Underflow Interrupt 2 */
+#define SH7750_EVT_TICPI2              0x460	/* TMU Input Capture Interrupt 2 */
+
+/* Peripheral Module Interrupts - Real-Time Clock (RTC) */
+#define SH7750_EVT_RTC_ATI             0x480	/* Alarm Interrupt Request */
+#define SH7750_EVT_RTC_PRI             0x4A0	/* Periodic Interrupt Request */
+#define SH7750_EVT_RTC_CUI             0x4C0	/* Carry Interrupt Request */
+
+/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */
+#define SH7750_EVT_SCI_ERI             0x4E0	/* Receive Error */
+#define SH7750_EVT_SCI_RXI             0x500	/* Receive Data Register Full */
+#define SH7750_EVT_SCI_TXI             0x520	/* Transmit Data Register Empty */
+#define SH7750_EVT_SCI_TEI             0x540	/* Transmit End */
+
+/* Peripheral Module Interrupts - Watchdog Timer (WDT) */
+#define SH7750_EVT_WDT_ITI             0x560	/* Interval Timer Interrupt
+						   (used when WDT operates in
+						   interval timer mode) */
+
+/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
+#define SH7750_EVT_REF_RCMI            0x580	/* Compare-match Interrupt */
+#define SH7750_EVT_REF_ROVI            0x5A0	/* Refresh Counter Overflow
+						   interrupt */
+
+/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
+#define SH7750_EVT_HUDI                0x600	/* UDI interrupt */
+
+/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */
+#define SH7750_EVT_GPIO                0x620	/* GPIO Interrupt */
+
+/* Peripheral Module Interrupts - DMA Controller (DMAC) */
+#define SH7750_EVT_DMAC_DMTE0          0x640	/* DMAC 0 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE1          0x660	/* DMAC 1 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE2          0x680	/* DMAC 2 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE3          0x6A0	/* DMAC 3 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMAE           0x6C0	/* DMAC Address Error Interrupt */
+
+/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */
+/*                                                                  (SCIF) */
+#define SH7750_EVT_SCIF_ERI            0x700	/* Receive Error */
+#define SH7750_EVT_SCIF_RXI            0x720	/* Receive FIFO Data Full or
+						   Receive Data ready interrupt */
+#define SH7750_EVT_SCIF_BRI            0x740	/* Break or overrun error */
+#define SH7750_EVT_SCIF_TXI            0x760	/* Transmit FIFO Data Empty */
+
+/*
+ * Power Management
+ */
+#define SH7750_STBCR_REGOFS   0xC00004	/* offset */
+#define SH7750_STBCR          SH7750_P4_REG32(SH7750_STBCR_REGOFS)
+#define SH7750_STBCR_A7       SH7750_A7_REG32(SH7750_STBCR_REGOFS)
+
+#define SH7750_STBCR_STBY     0x80	/* Specifies a transition to standby mode:
+					   0 - Transition to SLEEP mode on SLEEP
+					   1 - Transition to STANDBY mode on SLEEP */
+#define SH7750_STBCR_PHZ      0x40	/* State of peripheral module pins in
+					   standby mode:
+					   0 - normal state
+					   1 - high-impendance state */
+
+#define SH7750_STBCR_PPU      0x20	/* Peripheral module pins pull-up controls */
+#define SH7750_STBCR_MSTP4    0x10	/* Stopping the clock supply to DMAC */
+#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4
+#define SH7750_STBCR_MSTP3    0x08	/* Stopping the clock supply to SCIF */
+#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3
+#define SH7750_STBCR_MSTP2    0x04	/* Stopping the clock supply to TMU */
+#define SH7750_STBCR_TMU_STP  SH7750_STBCR_MSTP2
+#define SH7750_STBCR_MSTP1    0x02	/* Stopping the clock supply to RTC */
+#define SH7750_STBCR_RTC_STP  SH7750_STBCR_MSTP1
+#define SH7750_STBCR_MSPT0    0x01	/* Stopping the clock supply to SCI */
+#define SH7750_STBCR_SCI_STP  SH7750_STBCR_MSTP0
+
+#define SH7750_STBCR_STBY     0x80
+
+
+#define SH7750_STBCR2_REGOFS  0xC00010	/* offset */
+#define SH7750_STBCR2         SH7750_P4_REG32(SH7750_STBCR2_REGOFS)
+#define SH7750_STBCR2_A7      SH7750_A7_REG32(SH7750_STBCR2_REGOFS)
+
+#define SH7750_STBCR2_DSLP    0x80	/* Specifies transition to deep sleep mode:
+					   0 - transition to sleep or standby mode
+					   as it is specified in STBY bit
+					   1 - transition to deep sleep mode on
+					   execution of SLEEP instruction */
+#define SH7750_STBCR2_MSTP6   0x02	/* Stopping the clock supply to Store Queue
+					   in the cache controller */
+#define SH7750_STBCR2_SQ_STP  SH7750_STBCR2_MSTP6
+#define SH7750_STBCR2_MSTP5   0x01	/* Stopping the clock supply to the User
+					   Break Controller (UBC) */
+#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5
+
+/*
+ * Clock Pulse Generator (CPG)
+ */
+#define SH7750_FRQCR_REGOFS   0xC00000	/* offset */
+#define SH7750_FRQCR          SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
+#define SH7750_FRQCR_A7       SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
+
+#define SH7750_FRQCR_CKOEN    0x0800	/* Clock Output Enable
+					   0 - CKIO pin goes to HiZ/pullup
+					   1 - Clock is output from CKIO */
+#define SH7750_FRQCR_PLL1EN   0x0400	/* PLL circuit 1 enable */
+#define SH7750_FRQCR_PLL2EN   0x0200	/* PLL circuit 2 enable */
+
+#define SH7750_FRQCR_IFC      0x01C0	/* CPU clock frequency division ratio: */
+#define SH7750_FRQCR_IFCDIV1  0x0000	/*    0 - * 1 */
+#define SH7750_FRQCR_IFCDIV2  0x0040	/*    1 - * 1/2 */
+#define SH7750_FRQCR_IFCDIV3  0x0080	/*    2 - * 1/3 */
+#define SH7750_FRQCR_IFCDIV4  0x00C0	/*    3 - * 1/4 */
+#define SH7750_FRQCR_IFCDIV6  0x0100	/*    4 - * 1/6 */
+#define SH7750_FRQCR_IFCDIV8  0x0140	/*    5 - * 1/8 */
+
+#define SH7750_FRQCR_BFC      0x0038	/* Bus clock frequency division ratio: */
+#define SH7750_FRQCR_BFCDIV1  0x0000	/*    0 - * 1 */
+#define SH7750_FRQCR_BFCDIV2  0x0008	/*    1 - * 1/2 */
+#define SH7750_FRQCR_BFCDIV3  0x0010	/*    2 - * 1/3 */
+#define SH7750_FRQCR_BFCDIV4  0x0018	/*    3 - * 1/4 */
+#define SH7750_FRQCR_BFCDIV6  0x0020	/*    4 - * 1/6 */
+#define SH7750_FRQCR_BFCDIV8  0x0028	/*    5 - * 1/8 */
+
+#define SH7750_FRQCR_PFC      0x0007	/* Peripheral module clock frequency
+					   division ratio: */
+#define SH7750_FRQCR_PFCDIV2  0x0000	/*    0 - * 1/2 */
+#define SH7750_FRQCR_PFCDIV3  0x0001	/*    1 - * 1/3 */
+#define SH7750_FRQCR_PFCDIV4  0x0002	/*    2 - * 1/4 */
+#define SH7750_FRQCR_PFCDIV6  0x0003	/*    3 - * 1/6 */
+#define SH7750_FRQCR_PFCDIV8  0x0004	/*    4 - * 1/8 */
+
+/*
+ * Watchdog Timer (WDT)
+ */
+
+/* Watchdog Timer Counter register - WTCNT */
+#define SH7750_WTCNT_REGOFS   0xC00008	/* offset */
+#define SH7750_WTCNT          SH7750_P4_REG32(SH7750_WTCNT_REGOFS)
+#define SH7750_WTCNT_A7       SH7750_A7_REG32(SH7750_WTCNT_REGOFS)
+#define SH7750_WTCNT_KEY      0x5A00	/* When WTCNT byte register written,
+					   you have to set the upper byte to
+					   0x5A */
+
+/* Watchdog Timer Control/Status register - WTCSR */
+#define SH7750_WTCSR_REGOFS   0xC0000C	/* offset */
+#define SH7750_WTCSR          SH7750_P4_REG32(SH7750_WTCSR_REGOFS)
+#define SH7750_WTCSR_A7       SH7750_A7_REG32(SH7750_WTCSR_REGOFS)
+#define SH7750_WTCSR_KEY      0xA500	/* When WTCSR byte register written,
+					   you have to set the upper byte to
+					   0xA5 */
+#define SH7750_WTCSR_TME      0x80	/* Timer enable (1-upcount start) */
+#define SH7750_WTCSR_MODE     0x40	/* Timer Mode Select: */
+#define SH7750_WTCSR_MODE_WT  0x40	/*    Watchdog Timer Mode */
+#define SH7750_WTCSR_MODE_IT  0x00	/*    Interval Timer Mode */
+#define SH7750_WTCSR_RSTS     0x20	/* Reset Select: */
+#define SH7750_WTCSR_RST_MAN  0x20	/*    Manual Reset */
+#define SH7750_WTCSR_RST_PWR  0x00	/*    Power-on Reset */
+#define SH7750_WTCSR_WOVF     0x10	/* Watchdog Timer Overflow Flag */
+#define SH7750_WTCSR_IOVF     0x08	/* Interval Timer Overflow Flag */
+#define SH7750_WTCSR_CKS      0x07	/* Clock Select: */
+#define SH7750_WTCSR_CKS_DIV32   0x00	/*   1/32 of frequency divider 2 input */
+#define SH7750_WTCSR_CKS_DIV64   0x01	/*   1/64 */
+#define SH7750_WTCSR_CKS_DIV128  0x02	/*   1/128 */
+#define SH7750_WTCSR_CKS_DIV256  0x03	/*   1/256 */
+#define SH7750_WTCSR_CKS_DIV512  0x04	/*   1/512 */
+#define SH7750_WTCSR_CKS_DIV1024 0x05	/*   1/1024 */
+#define SH7750_WTCSR_CKS_DIV2048 0x06	/*   1/2048 */
+#define SH7750_WTCSR_CKS_DIV4096 0x07	/*   1/4096 */
+
+/*
+ * Real-Time Clock (RTC)
+ */
+/* 64-Hz Counter Register (byte, read-only) - R64CNT */
+#define SH7750_R64CNT_REGOFS  0xC80000	/* offset */
+#define SH7750_R64CNT         SH7750_P4_REG32(SH7750_R64CNT_REGOFS)
+#define SH7750_R64CNT_A7      SH7750_A7_REG32(SH7750_R64CNT_REGOFS)
+
+/* Second Counter Register (byte, BCD-coded) - RSECCNT */
+#define SH7750_RSECCNT_REGOFS 0xC80004	/* offset */
+#define SH7750_RSECCNT        SH7750_P4_REG32(SH7750_RSECCNT_REGOFS)
+#define SH7750_RSECCNT_A7     SH7750_A7_REG32(SH7750_RSECCNT_REGOFS)
+
+/* Minute Counter Register (byte, BCD-coded) - RMINCNT */
+#define SH7750_RMINCNT_REGOFS 0xC80008	/* offset */
+#define SH7750_RMINCNT        SH7750_P4_REG32(SH7750_RMINCNT_REGOFS)
+#define SH7750_RMINCNT_A7     SH7750_A7_REG32(SH7750_RMINCNT_REGOFS)
+
+/* Hour Counter Register (byte, BCD-coded) - RHRCNT */
+#define SH7750_RHRCNT_REGOFS  0xC8000C	/* offset */
+#define SH7750_RHRCNT         SH7750_P4_REG32(SH7750_RHRCNT_REGOFS)
+#define SH7750_RHRCNT_A7      SH7750_A7_REG32(SH7750_RHRCNT_REGOFS)
+
+/* Day-of-Week Counter Register (byte) - RWKCNT */
+#define SH7750_RWKCNT_REGOFS  0xC80010	/* offset */
+#define SH7750_RWKCNT         SH7750_P4_REG32(SH7750_RWKCNT_REGOFS)
+#define SH7750_RWKCNT_A7      SH7750_A7_REG32(SH7750_RWKCNT_REGOFS)
+
+#define SH7750_RWKCNT_SUN     0	/* Sunday */
+#define SH7750_RWKCNT_MON     1	/* Monday */
+#define SH7750_RWKCNT_TUE     2	/* Tuesday */
+#define SH7750_RWKCNT_WED     3	/* Wednesday */
+#define SH7750_RWKCNT_THU     4	/* Thursday */
+#define SH7750_RWKCNT_FRI     5	/* Friday */
+#define SH7750_RWKCNT_SAT     6	/* Saturday */
+
+/* Day Counter Register (byte, BCD-coded) - RDAYCNT */
+#define SH7750_RDAYCNT_REGOFS 0xC80014	/* offset */
+#define SH7750_RDAYCNT        SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS)
+#define SH7750_RDAYCNT_A7     SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS)
+
+/* Month Counter Register (byte, BCD-coded) - RMONCNT */
+#define SH7750_RMONCNT_REGOFS 0xC80018	/* offset */
+#define SH7750_RMONCNT        SH7750_P4_REG32(SH7750_RMONCNT_REGOFS)
+#define SH7750_RMONCNT_A7     SH7750_A7_REG32(SH7750_RMONCNT_REGOFS)
+
+/* Year Counter Register (half, BCD-coded) - RYRCNT */
+#define SH7750_RYRCNT_REGOFS  0xC8001C	/* offset */
+#define SH7750_RYRCNT         SH7750_P4_REG32(SH7750_RYRCNT_REGOFS)
+#define SH7750_RYRCNT_A7      SH7750_A7_REG32(SH7750_RYRCNT_REGOFS)
+
+/* Second Alarm Register (byte, BCD-coded) - RSECAR */
+#define SH7750_RSECAR_REGOFS  0xC80020	/* offset */
+#define SH7750_RSECAR         SH7750_P4_REG32(SH7750_RSECAR_REGOFS)
+#define SH7750_RSECAR_A7      SH7750_A7_REG32(SH7750_RSECAR_REGOFS)
+#define SH7750_RSECAR_ENB     0x80	/* Second Alarm Enable */
+
+/* Minute Alarm Register (byte, BCD-coded) - RMINAR */
+#define SH7750_RMINAR_REGOFS  0xC80024	/* offset */
+#define SH7750_RMINAR         SH7750_P4_REG32(SH7750_RMINAR_REGOFS)
+#define SH7750_RMINAR_A7      SH7750_A7_REG32(SH7750_RMINAR_REGOFS)
+#define SH7750_RMINAR_ENB     0x80	/* Minute Alarm Enable */
+
+/* Hour Alarm Register (byte, BCD-coded) - RHRAR */
+#define SH7750_RHRAR_REGOFS   0xC80028	/* offset */
+#define SH7750_RHRAR          SH7750_P4_REG32(SH7750_RHRAR_REGOFS)
+#define SH7750_RHRAR_A7       SH7750_A7_REG32(SH7750_RHRAR_REGOFS)
+#define SH7750_RHRAR_ENB      0x80	/* Hour Alarm Enable */
+
+/* Day-of-Week Alarm Register (byte) - RWKAR */
+#define SH7750_RWKAR_REGOFS   0xC8002C	/* offset */
+#define SH7750_RWKAR          SH7750_P4_REG32(SH7750_RWKAR_REGOFS)
+#define SH7750_RWKAR_A7       SH7750_A7_REG32(SH7750_RWKAR_REGOFS)
+#define SH7750_RWKAR_ENB      0x80	/* Day-of-week Alarm Enable */
+
+#define SH7750_RWKAR_SUN      0	/* Sunday */
+#define SH7750_RWKAR_MON      1	/* Monday */
+#define SH7750_RWKAR_TUE      2	/* Tuesday */
+#define SH7750_RWKAR_WED      3	/* Wednesday */
+#define SH7750_RWKAR_THU      4	/* Thursday */
+#define SH7750_RWKAR_FRI      5	/* Friday */
+#define SH7750_RWKAR_SAT      6	/* Saturday */
+
+/* Day Alarm Register (byte, BCD-coded) - RDAYAR */
+#define SH7750_RDAYAR_REGOFS  0xC80030	/* offset */
+#define SH7750_RDAYAR         SH7750_P4_REG32(SH7750_RDAYAR_REGOFS)
+#define SH7750_RDAYAR_A7      SH7750_A7_REG32(SH7750_RDAYAR_REGOFS)
+#define SH7750_RDAYAR_ENB     0x80	/* Day Alarm Enable */
+
+/* Month Counter Register (byte, BCD-coded) - RMONAR */
+#define SH7750_RMONAR_REGOFS  0xC80034	/* offset */
+#define SH7750_RMONAR         SH7750_P4_REG32(SH7750_RMONAR_REGOFS)
+#define SH7750_RMONAR_A7      SH7750_A7_REG32(SH7750_RMONAR_REGOFS)
+#define SH7750_RMONAR_ENB     0x80	/* Month Alarm Enable */
+
+/* RTC Control Register 1 (byte) - RCR1 */
+#define SH7750_RCR1_REGOFS    0xC80038	/* offset */
+#define SH7750_RCR1           SH7750_P4_REG32(SH7750_RCR1_REGOFS)
+#define SH7750_RCR1_A7        SH7750_A7_REG32(SH7750_RCR1_REGOFS)
+#define SH7750_RCR1_CF        0x80	/* Carry Flag */
+#define SH7750_RCR1_CIE       0x10	/* Carry Interrupt Enable */
+#define SH7750_RCR1_AIE       0x08	/* Alarm Interrupt Enable */
+#define SH7750_RCR1_AF        0x01	/* Alarm Flag */
+
+/* RTC Control Register 2 (byte) - RCR2 */
+#define SH7750_RCR2_REGOFS    0xC8003C	/* offset */
+#define SH7750_RCR2           SH7750_P4_REG32(SH7750_RCR2_REGOFS)
+#define SH7750_RCR2_A7        SH7750_A7_REG32(SH7750_RCR2_REGOFS)
+#define SH7750_RCR2_PEF        0x80	/* Periodic Interrupt Flag */
+#define SH7750_RCR2_PES        0x70	/* Periodic Interrupt Enable: */
+#define SH7750_RCR2_PES_DIS    0x00	/*   Periodic Interrupt Disabled */
+#define SH7750_RCR2_PES_DIV256 0x10	/*   Generated at 1/256 sec interval */
+#define SH7750_RCR2_PES_DIV64  0x20	/*   Generated at 1/64 sec interval */
+#define SH7750_RCR2_PES_DIV16  0x30	/*   Generated at 1/16 sec interval */
+#define SH7750_RCR2_PES_DIV4   0x40	/*   Generated at 1/4 sec interval */
+#define SH7750_RCR2_PES_DIV2   0x50	/*   Generated at 1/2 sec interval */
+#define SH7750_RCR2_PES_x1     0x60	/*   Generated at 1 sec interval */
+#define SH7750_RCR2_PES_x2     0x70	/*   Generated at 2 sec interval */
+#define SH7750_RCR2_RTCEN      0x08	/* RTC Crystal Oscillator is Operated */
+#define SH7750_RCR2_ADJ        0x04	/* 30-Second Adjastment */
+#define SH7750_RCR2_RESET      0x02	/* Frequency divider circuits are reset */
+#define SH7750_RCR2_START      0x01	/* 0 - sec, min, hr, day-of-week, month,
+					   year counters are stopped
+					   1 - sec, min, hr, day-of-week, month,
+					   year counters operate normally */
+/*
+ * Bus State Controller - BSC
+ */
+/* Bus Control Register 1 - BCR1 */
+#define SH7750_BCR1_REGOFS    0x800000	/* offset */
+#define SH7750_BCR1           SH7750_P4_REG32(SH7750_BCR1_REGOFS)
+#define SH7750_BCR1_A7        SH7750_A7_REG32(SH7750_BCR1_REGOFS)
+#define SH7750_BCR1_ENDIAN    0x80000000	/* Endianness (1 - little endian) */
+#define SH7750_BCR1_MASTER    0x40000000	/* Master/Slave mode (1-master) */
+#define SH7750_BCR1_A0MPX     0x20000000	/* Area 0 Memory Type (0-SRAM,1-MPX) */
+#define SH7750_BCR1_IPUP      0x02000000	/* Input Pin Pull-up Control:
+						   0 - pull-up resistor is on for
+						   control input pins
+						   1 - pull-up resistor is off */
+#define SH7750_BCR1_OPUP      0x01000000	/* Output Pin Pull-up Control:
+						   0 - pull-up resistor is on for
+						   control output pins
+						   1 - pull-up resistor is off */
+#define SH7750_BCR1_A1MBC     0x00200000	/* Area 1 SRAM Byte Control Mode:
+						   0 - Area 1 SRAM is set to
+						   normal mode
+						   1 - Area 1 SRAM is set to byte
+						   control mode */
+#define SH7750_BCR1_A4MBC     0x00100000	/* Area 4 SRAM Byte Control Mode:
+						   0 - Area 4 SRAM is set to
+						   normal mode
+						   1 - Area 4 SRAM is set to byte
+						   control mode */
+#define SH7750_BCR1_BREQEN    0x00080000	/* BREQ Enable:
+						   0 - External requests are  not
+						   accepted
+						   1 - External requests are
+						   accepted */
+#define SH7750_BCR1_PSHR      0x00040000	/* Partial Sharing Bit:
+						   0 - Master Mode
+						   1 - Partial-sharing Mode */
+#define SH7750_BCR1_MEMMPX    0x00020000	/* Area 1 to 6 MPX Interface:
+						   0 - SRAM/burst ROM interface
+						   1 - MPX interface */
+#define SH7750_BCR1_HIZMEM    0x00008000	/* High Impendance Control. Specifies
+						   the state of A[25:0], BS\, CSn\,
+						   RD/WR\, CE2A\, CE2B\ in standby
+						   mode and when bus is released:
+						   0 - signals go to High-Z mode
+						   1 - signals driven */
+#define SH7750_BCR1_HIZCNT    0x00004000	/* High Impendance Control. Specifies
+						   the state of the RAS\, RAS2\, WEn\,
+						   CASn\, DQMn, RD\, CASS\, FRAME\,
+						   RD2\ signals in standby mode and
+						   when bus is released:
+						   0 - signals go to High-Z mode
+						   1 - signals driven */
+#define SH7750_BCR1_A0BST     0x00003800	/* Area 0 Burst ROM Control */
+#define SH7750_BCR1_A0BST_SRAM    0x0000	/*   Area 0 accessed as SRAM i/f */
+#define SH7750_BCR1_A0BST_ROM4    0x0800	/*   Area 0 accessed as burst ROM
+						   interface, 4 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM8    0x1000	/*   Area 0 accessed as burst ROM
+						   interface, 8 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM16   0x1800	/*   Area 0 accessed as burst ROM
+						   interface, 16 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM32   0x2000	/*   Area 0 accessed as burst ROM
+						   interface, 32 cosequtive access */
+
+#define SH7750_BCR1_A5BST     0x00000700	/* Area 5 Burst ROM Control */
+#define SH7750_BCR1_A5BST_SRAM    0x0000	/*   Area 5 accessed as SRAM i/f */
+#define SH7750_BCR1_A5BST_ROM4    0x0100	/*   Area 5 accessed as burst ROM
+						   interface, 4 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM8    0x0200	/*   Area 5 accessed as burst ROM
+						   interface, 8 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM16   0x0300	/*   Area 5 accessed as burst ROM
+						   interface, 16 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM32   0x0400	/*   Area 5 accessed as burst ROM
+						   interface, 32 cosequtive access */
+
+#define SH7750_BCR1_A6BST     0x000000E0	/* Area 6 Burst ROM Control */
+#define SH7750_BCR1_A6BST_SRAM    0x0000	/*   Area 6 accessed as SRAM i/f */
+#define SH7750_BCR1_A6BST_ROM4    0x0020	/*   Area 6 accessed as burst ROM
+						   interface, 4 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM8    0x0040	/*   Area 6 accessed as burst ROM
+						   interface, 8 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM16   0x0060	/*   Area 6 accessed as burst ROM
+						   interface, 16 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM32   0x0080	/*   Area 6 accessed as burst ROM
+						   interface, 32 cosequtive access */
+
+#define SH7750_BCR1_DRAMTP        0x001C	/* Area 2 and 3 Memory Type */
+#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM   0x0000	/* Area 2 and 3 are SRAM or MPX
+						   interface. */
+#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM  0x0008	/* Area 2 - SRAM/MPX, Area 3 -
+						   synchronous DRAM */
+#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C	/* Area 2 and 3 are synchronous
+						   DRAM interface */
+#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM   0x0010	/* Area 2 - SRAM/MPX, Area 3 -
+						   DRAM interface */
+#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM   0x0014	/* Area 2 and 3 are DRAM
+						   interface */
+
+#define SH7750_BCR1_A56PCM    0x00000001	/* Area 5 and 6 Bus Type:
+						   0 - SRAM interface
+						   1 - PCMCIA interface */
+
+/* Bus Control Register 2 (half) - BCR2 */
+#define SH7750_BCR2_REGOFS    0x800004	/* offset */
+#define SH7750_BCR2           SH7750_P4_REG32(SH7750_BCR2_REGOFS)
+#define SH7750_BCR2_A7        SH7750_A7_REG32(SH7750_BCR2_REGOFS)
+
+#define SH7750_BCR2_A0SZ      0xC000	/* Area 0 Bus Width */
+#define SH7750_BCR2_A0SZ_S    14
+#define SH7750_BCR2_A6SZ      0x3000	/* Area 6 Bus Width */
+#define SH7750_BCR2_A6SZ_S    12
+#define SH7750_BCR2_A5SZ      0x0C00	/* Area 5 Bus Width */
+#define SH7750_BCR2_A5SZ_S    10
+#define SH7750_BCR2_A4SZ      0x0300	/* Area 4 Bus Width */
+#define SH7750_BCR2_A4SZ_S    8
+#define SH7750_BCR2_A3SZ      0x00C0	/* Area 3 Bus Width */
+#define SH7750_BCR2_A3SZ_S    6
+#define SH7750_BCR2_A2SZ      0x0030	/* Area 2 Bus Width */
+#define SH7750_BCR2_A2SZ_S    4
+#define SH7750_BCR2_A1SZ      0x000C	/* Area 1 Bus Width */
+#define SH7750_BCR2_A1SZ_S    2
+#define SH7750_BCR2_SZ_64     0	/* 64 bits */
+#define SH7750_BCR2_SZ_8      1	/* 8 bits */
+#define SH7750_BCR2_SZ_16     2	/* 16 bits */
+#define SH7750_BCR2_SZ_32     3	/* 32 bits */
+#define SH7750_BCR2_PORTEN    0x0001	/* Port Function Enable :
+					   0 - D51-D32 are not used as a port
+					   1 - D51-D32 are used as a port */
+
+/* Wait Control Register 1 - WCR1 */
+#define SH7750_WCR1_REGOFS    0x800008	/* offset */
+#define SH7750_WCR1           SH7750_P4_REG32(SH7750_WCR1_REGOFS)
+#define SH7750_WCR1_A7        SH7750_A7_REG32(SH7750_WCR1_REGOFS)
+#define SH7750_WCR1_DMAIW     0x70000000	/* DACK Device Inter-Cycle Idle
+						   specification */
+#define SH7750_WCR1_DMAIW_S   28
+#define SH7750_WCR1_A6IW      0x07000000	/* Area 6 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A6IW_S    24
+#define SH7750_WCR1_A5IW      0x00700000	/* Area 5 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A5IW_S    20
+#define SH7750_WCR1_A4IW      0x00070000	/* Area 4 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A4IW_S    16
+#define SH7750_WCR1_A3IW      0x00007000	/* Area 3 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A3IW_S    12
+#define SH7750_WCR1_A2IW      0x00000700	/* Area 2 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A2IW_S    8
+#define SH7750_WCR1_A1IW      0x00000070	/* Area 1 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A1IW_S    4
+#define SH7750_WCR1_A0IW      0x00000007	/* Area 0 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A0IW_S    0
+
+/* Wait Control Register 2 - WCR2 */
+#define SH7750_WCR2_REGOFS    0x80000C	/* offset */
+#define SH7750_WCR2           SH7750_P4_REG32(SH7750_WCR2_REGOFS)
+#define SH7750_WCR2_A7        SH7750_A7_REG32(SH7750_WCR2_REGOFS)
+
+#define SH7750_WCR2_A6W       0xE0000000	/* Area 6 Wait Control */
+#define SH7750_WCR2_A6W_S     29
+#define SH7750_WCR2_A6B       0x1C000000	/* Area 6 Burst Pitch */
+#define SH7750_WCR2_A6B_S     26
+#define SH7750_WCR2_A5W       0x03800000	/* Area 5 Wait Control */
+#define SH7750_WCR2_A5W_S     23
+#define SH7750_WCR2_A5B       0x00700000	/* Area 5 Burst Pitch */
+#define SH7750_WCR2_A5B_S     20
+#define SH7750_WCR2_A4W       0x000E0000	/* Area 4 Wait Control */
+#define SH7750_WCR2_A4W_S     17
+#define SH7750_WCR2_A3W       0x0000E000	/* Area 3 Wait Control */
+#define SH7750_WCR2_A3W_S     13
+#define SH7750_WCR2_A2W       0x00000E00	/* Area 2 Wait Control */
+#define SH7750_WCR2_A2W_S     9
+#define SH7750_WCR2_A1W       0x000001C0	/* Area 1 Wait Control */
+#define SH7750_WCR2_A1W_S     6
+#define SH7750_WCR2_A0W       0x00000038	/* Area 0 Wait Control */
+#define SH7750_WCR2_A0W_S     3
+#define SH7750_WCR2_A0B       0x00000007	/* Area 0 Burst Pitch */
+#define SH7750_WCR2_A0B_S     0
+
+#define SH7750_WCR2_WS0       0	/* 0 wait states inserted */
+#define SH7750_WCR2_WS1       1	/* 1 wait states inserted */
+#define SH7750_WCR2_WS2       2	/* 2 wait states inserted */
+#define SH7750_WCR2_WS3       3	/* 3 wait states inserted */
+#define SH7750_WCR2_WS6       4	/* 6 wait states inserted */
+#define SH7750_WCR2_WS9       5	/* 9 wait states inserted */
+#define SH7750_WCR2_WS12      6	/* 12 wait states inserted */
+#define SH7750_WCR2_WS15      7	/* 15 wait states inserted */
+
+#define SH7750_WCR2_BPWS0     0	/* 0 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS1     1	/* 1 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS2     2	/* 2 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS3     3	/* 3 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS4     4	/* 4 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS5     5	/* 5 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS6     6	/* 6 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS7     7	/* 7 wait states inserted from 2nd access */
+
+/* DRAM CAS\ Assertion Delay (area 3,2) */
+#define SH7750_WCR2_DRAM_CAS_ASW1   0	/* 1 cycle */
+#define SH7750_WCR2_DRAM_CAS_ASW2   1	/* 2 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW3   2	/* 3 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW4   3	/* 4 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW7   4	/* 7 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW10  5	/* 10 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW13  6	/* 13 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW16  7	/* 16 cycles */
+
+/* SDRAM CAS\ Latency Cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT1  1	/* 1 cycle */
+#define SH7750_WCR2_SDRAM_CAS_LAT2  2	/* 2 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT3  3	/* 3 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT4  4	/* 4 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT5  5	/* 5 cycles */
+
+/* Wait Control Register 3 - WCR3 */
+#define SH7750_WCR3_REGOFS    0x800010	/* offset */
+#define SH7750_WCR3           SH7750_P4_REG32(SH7750_WCR3_REGOFS)
+#define SH7750_WCR3_A7        SH7750_A7_REG32(SH7750_WCR3_REGOFS)
+
+#define SH7750_WCR3_A6S       0x04000000	/* Area 6 Write Strobe Setup time */
+#define SH7750_WCR3_A6H       0x03000000	/* Area 6 Data Hold Time */
+#define SH7750_WCR3_A6H_S     24
+#define SH7750_WCR3_A5S       0x00400000	/* Area 5 Write Strobe Setup time */
+#define SH7750_WCR3_A5H       0x00300000	/* Area 5 Data Hold Time */
+#define SH7750_WCR3_A5H_S     20
+#define SH7750_WCR3_A4S       0x00040000	/* Area 4 Write Strobe Setup time */
+#define SH7750_WCR3_A4H       0x00030000	/* Area 4 Data Hold Time */
+#define SH7750_WCR3_A4H_S     16
+#define SH7750_WCR3_A3S       0x00004000	/* Area 3 Write Strobe Setup time */
+#define SH7750_WCR3_A3H       0x00003000	/* Area 3 Data Hold Time */
+#define SH7750_WCR3_A3H_S     12
+#define SH7750_WCR3_A2S       0x00000400	/* Area 2 Write Strobe Setup time */
+#define SH7750_WCR3_A2H       0x00000300	/* Area 2 Data Hold Time */
+#define SH7750_WCR3_A2H_S     8
+#define SH7750_WCR3_A1S       0x00000040	/* Area 1 Write Strobe Setup time */
+#define SH7750_WCR3_A1H       0x00000030	/* Area 1 Data Hold Time */
+#define SH7750_WCR3_A1H_S     4
+#define SH7750_WCR3_A0S       0x00000004	/* Area 0 Write Strobe Setup time */
+#define SH7750_WCR3_A0H       0x00000003	/* Area 0 Data Hold Time */
+#define SH7750_WCR3_A0H_S     0
+
+#define SH7750_WCR3_DHWS_0    0	/* 0 wait states data hold time */
+#define SH7750_WCR3_DHWS_1    1	/* 1 wait states data hold time */
+#define SH7750_WCR3_DHWS_2    2	/* 2 wait states data hold time */
+#define SH7750_WCR3_DHWS_3    3	/* 3 wait states data hold time */
+
+#define SH7750_MCR_REGOFS     0x800014	/* offset */
+#define SH7750_MCR            SH7750_P4_REG32(SH7750_MCR_REGOFS)
+#define SH7750_MCR_A7         SH7750_A7_REG32(SH7750_MCR_REGOFS)
+
+#define SH7750_MCR_RASD       0x80000000	/* RAS Down mode */
+#define SH7750_MCR_MRSET      0x40000000	/* SDRAM Mode Register Set */
+#define SH7750_MCR_PALL       0x00000000	/* SDRAM Precharge All cmd. Mode */
+#define SH7750_MCR_TRC        0x38000000	/* RAS Precharge Time at End of
+						   Refresh: */
+#define SH7750_MCR_TRC_0      0x00000000	/*    0 */
+#define SH7750_MCR_TRC_3      0x08000000	/*    3 */
+#define SH7750_MCR_TRC_6      0x10000000	/*    6 */
+#define SH7750_MCR_TRC_9      0x18000000	/*    9 */
+#define SH7750_MCR_TRC_12     0x20000000	/*    12 */
+#define SH7750_MCR_TRC_15     0x28000000	/*    15 */
+#define SH7750_MCR_TRC_18     0x30000000	/*    18 */
+#define SH7750_MCR_TRC_21     0x38000000	/*    21 */
+
+#define SH7750_MCR_TCAS       0x00800000	/* CAS Negation Period */
+#define SH7750_MCR_TCAS_1     0x00000000	/*    1 */
+#define SH7750_MCR_TCAS_2     0x00800000	/*    2 */
+
+#define SH7750_MCR_TPC        0x00380000	/* DRAM: RAS Precharge Period
+						   SDRAM: minimum number of cycles
+						   until the next bank active cmd
+						   is output after precharging */
+#define SH7750_MCR_TPC_S      19
+#define SH7750_MCR_TPC_SDRAM_1 0x00000000	/* 1 cycle */
+#define SH7750_MCR_TPC_SDRAM_2 0x00080000	/* 2 cycles */
+#define SH7750_MCR_TPC_SDRAM_3 0x00100000	/* 3 cycles */
+#define SH7750_MCR_TPC_SDRAM_4 0x00180000	/* 4 cycles */
+#define SH7750_MCR_TPC_SDRAM_5 0x00200000	/* 5 cycles */
+#define SH7750_MCR_TPC_SDRAM_6 0x00280000	/* 6 cycles */
+#define SH7750_MCR_TPC_SDRAM_7 0x00300000	/* 7 cycles */
+#define SH7750_MCR_TPC_SDRAM_8 0x00380000	/* 8 cycles */
+
+#define SH7750_MCR_RCD        0x00030000	/* DRAM: RAS-CAS Assertion Delay time
+						   SDRAM: bank active-read/write cmd
+						   delay time */
+#define SH7750_MCR_RCD_DRAM_2  0x00000000	/* DRAM delay 2 clocks */
+#define SH7750_MCR_RCD_DRAM_3  0x00010000	/* DRAM delay 3 clocks */
+#define SH7750_MCR_RCD_DRAM_4  0x00020000	/* DRAM delay 4 clocks */
+#define SH7750_MCR_RCD_DRAM_5  0x00030000	/* DRAM delay 5 clocks */
+#define SH7750_MCR_RCD_SDRAM_2 0x00010000	/* DRAM delay 2 clocks */
+#define SH7750_MCR_RCD_SDRAM_3 0x00020000	/* DRAM delay 3 clocks */
+#define SH7750_MCR_RCD_SDRAM_4 0x00030000	/* DRAM delay 4 clocks */
+
+#define SH7750_MCR_TRWL       0x0000E000	/* SDRAM Write Precharge Delay */
+#define SH7750_MCR_TRWL_1     0x00000000	/*    1 */
+#define SH7750_MCR_TRWL_2     0x00002000	/*    2 */
+#define SH7750_MCR_TRWL_3     0x00004000	/*    3 */
+#define SH7750_MCR_TRWL_4     0x00006000	/*    4 */
+#define SH7750_MCR_TRWL_5     0x00008000	/*    5 */
+
+#define SH7750_MCR_TRAS       0x00001C00	/* DRAM: CAS-Before-RAS Refresh RAS
+						   asserting period
+						   SDRAM: Command interval after
+						   synchronous DRAM refresh */
+#define SH7750_MCR_TRAS_DRAM_2         0x00000000	/* 2 */
+#define SH7750_MCR_TRAS_DRAM_3         0x00000400	/* 3 */
+#define SH7750_MCR_TRAS_DRAM_4         0x00000800	/* 4 */
+#define SH7750_MCR_TRAS_DRAM_5         0x00000C00	/* 5 */
+#define SH7750_MCR_TRAS_DRAM_6         0x00001000	/* 6 */
+#define SH7750_MCR_TRAS_DRAM_7         0x00001400	/* 7 */
+#define SH7750_MCR_TRAS_DRAM_8         0x00001800	/* 8 */
+#define SH7750_MCR_TRAS_DRAM_9         0x00001C00	/* 9 */
+
+#define SH7750_MCR_TRAS_SDRAM_TRC_4    0x00000000	/* 4 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_5    0x00000400	/* 5 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_6    0x00000800	/* 6 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_7    0x00000C00	/* 7 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_8    0x00001000	/* 8 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_9    0x00001400	/* 9 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_10   0x00001800	/* 10 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_11   0x00001C00	/* 11 + TRC */
+
+#define SH7750_MCR_BE         0x00000200	/* Burst Enable */
+#define SH7750_MCR_SZ         0x00000180	/* Memory Data Size */
+#define SH7750_MCR_SZ_64      0x00000000	/*    64 bits */
+#define SH7750_MCR_SZ_16      0x00000100	/*    16 bits */
+#define SH7750_MCR_SZ_32      0x00000180	/*    32 bits */
+
+#define SH7750_MCR_AMX        0x00000078	/* Address Multiplexing */
+#define SH7750_MCR_AMX_S      3
+#define SH7750_MCR_AMX_DRAM_8BIT_COL    0x00000000	/* 8-bit column addr */
+#define SH7750_MCR_AMX_DRAM_9BIT_COL    0x00000008	/* 9-bit column addr */
+#define SH7750_MCR_AMX_DRAM_10BIT_COL   0x00000010	/* 10-bit column addr */
+#define SH7750_MCR_AMX_DRAM_11BIT_COL   0x00000018	/* 11-bit column addr */
+#define SH7750_MCR_AMX_DRAM_12BIT_COL   0x00000020	/* 12-bit column addr */
+/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */
+
+#define SH7750_MCR_RFSH       0x00000004	/* Refresh Control */
+#define SH7750_MCR_RMODE      0x00000002	/* Refresh Mode: */
+#define SH7750_MCR_RMODE_NORMAL 0x00000000	/* Normal Refresh Mode */
+#define SH7750_MCR_RMODE_SELF   0x00000002	/* Self-Refresh Mode */
+#define SH7750_MCR_RMODE_EDO    0x00000001	/* EDO Mode */
+
+/* SDRAM Mode Set address */
+#define SH7750_SDRAM_MODE_A2_BASE  0xFF900000
+#define SH7750_SDRAM_MODE_A3_BASE  0xFF940000
+#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2))
+#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2))
+#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3))
+#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3))
+
+
+/* PCMCIA Control Register (half) - PCR */
+#define SH7750_PCR_REGOFS     0x800018	/* offset */
+#define SH7750_PCR            SH7750_P4_REG32(SH7750_PCR_REGOFS)
+#define SH7750_PCR_A7         SH7750_A7_REG32(SH7750_PCR_REGOFS)
+
+#define SH7750_PCR_A5PCW      0xC000	/* Area 5 PCMCIA Wait - Number of wait
+					   states to be added to the number of
+					   waits specified by WCR2 in a low-speed
+					   PCMCIA wait cycle */
+#define SH7750_PCR_A5PCW_0    0x0000	/*    0 waits inserted */
+#define SH7750_PCR_A5PCW_15   0x4000	/*    15 waits inserted */
+#define SH7750_PCR_A5PCW_30   0x8000	/*    30 waits inserted */
+#define SH7750_PCR_A5PCW_50   0xC000	/*    50 waits inserted */
+
+#define SH7750_PCR_A6PCW      0x3000	/* Area 6 PCMCIA Wait - Number of wait
+					   states to be added to the number of
+					   waits specified by WCR2 in a low-speed
+					   PCMCIA wait cycle */
+#define SH7750_PCR_A6PCW_0    0x0000	/*    0 waits inserted */
+#define SH7750_PCR_A6PCW_15   0x1000	/*    15 waits inserted */
+#define SH7750_PCR_A6PCW_30   0x2000	/*    30 waits inserted */
+#define SH7750_PCR_A6PCW_50   0x3000	/*    50 waits inserted */
+
+#define SH7750_PCR_A5TED      0x0E00	/* Area 5 Address-OE\/WE\ Assertion Delay,
+					   delay time from address output to
+					   OE\/WE\ assertion on the connected
+					   PCMCIA interface */
+#define SH7750_PCR_A5TED_S    9
+#define SH7750_PCR_A6TED      0x01C0	/* Area 6 Address-OE\/WE\ Assertion Delay */
+#define SH7750_PCR_A6TED_S    6
+
+#define SH7750_PCR_TED_0WS    0	/* 0 Waits inserted */
+#define SH7750_PCR_TED_1WS    1	/* 1 Waits inserted */
+#define SH7750_PCR_TED_2WS    2	/* 2 Waits inserted */
+#define SH7750_PCR_TED_3WS    3	/* 3 Waits inserted */
+#define SH7750_PCR_TED_6WS    4	/* 6 Waits inserted */
+#define SH7750_PCR_TED_9WS    5	/* 9 Waits inserted */
+#define SH7750_PCR_TED_12WS   6	/* 12 Waits inserted */
+#define SH7750_PCR_TED_15WS   7	/* 15 Waits inserted */
+
+#define SH7750_PCR_A5TEH      0x0038	/* Area 5 OE\/WE\ Negation Address delay,
+					   address hold delay time from OE\/WE\
+					   negation in a write on the connected
+					   PCMCIA interface */
+#define SH7750_PCR_A5TEH_S    3
+
+#define SH7750_PCR_A6TEH      0x0007	/* Area 6 OE\/WE\ Negation Address delay */
+#define SH7750_PCR_A6TEH_S    0
+
+#define SH7750_PCR_TEH_0WS    0	/* 0 Waits inserted */
+#define SH7750_PCR_TEH_1WS    1	/* 1 Waits inserted */
+#define SH7750_PCR_TEH_2WS    2	/* 2 Waits inserted */
+#define SH7750_PCR_TEH_3WS    3	/* 3 Waits inserted */
+#define SH7750_PCR_TEH_6WS    4	/* 6 Waits inserted */
+#define SH7750_PCR_TEH_9WS    5	/* 9 Waits inserted */
+#define SH7750_PCR_TEH_12WS   6	/* 12 Waits inserted */
+#define SH7750_PCR_TEH_15WS   7	/* 15 Waits inserted */
+
+/* Refresh Timer Control/Status Register (half) - RTSCR */
+#define SH7750_RTCSR_REGOFS   0x80001C	/* offset */
+#define SH7750_RTCSR          SH7750_P4_REG32(SH7750_RTCSR_REGOFS)
+#define SH7750_RTCSR_A7       SH7750_A7_REG32(SH7750_RTCSR_REGOFS)
+
+#define SH7750_RTCSR_KEY      0xA500	/* RTCSR write key */
+#define SH7750_RTCSR_CMF      0x0080	/* Compare-Match Flag (indicates a
+					   match between the refresh timer
+					   counter and refresh time constant) */
+#define SH7750_RTCSR_CMIE     0x0040	/* Compare-Match Interrupt Enable */
+#define SH7750_RTCSR_CKS      0x0038	/* Refresh Counter Clock Selects */
+#define SH7750_RTCSR_CKS_DIS          0x0000	/* Clock Input Disabled */
+#define SH7750_RTCSR_CKS_CKIO_DIV4    0x0008	/* Bus Clock / 4 */
+#define SH7750_RTCSR_CKS_CKIO_DIV16   0x0010	/* Bus Clock / 16 */
+#define SH7750_RTCSR_CKS_CKIO_DIV64   0x0018	/* Bus Clock / 64 */
+#define SH7750_RTCSR_CKS_CKIO_DIV256  0x0020	/* Bus Clock / 256 */
+#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028	/* Bus Clock / 1024 */
+#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030	/* Bus Clock / 2048 */
+#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038	/* Bus Clock / 4096 */
+
+#define SH7750_RTCSR_OVF      0x0004	/* Refresh Count Overflow Flag */
+#define SH7750_RTCSR_OVIE     0x0002	/* Refresh Count Overflow Interrupt
+					   Enable */
+#define SH7750_RTCSR_LMTS     0x0001	/* Refresh Count Overflow Limit Select */
+#define SH7750_RTCSR_LMTS_1024 0x0000	/* Count Limit is 1024 */
+#define SH7750_RTCSR_LMTS_512  0x0001	/* Count Limit is 512 */
+
+/* Refresh Timer Counter (half) - RTCNT */
+#define SH7750_RTCNT_REGOFS   0x800020	/* offset */
+#define SH7750_RTCNT          SH7750_P4_REG32(SH7750_RTCNT_REGOFS)
+#define SH7750_RTCNT_A7       SH7750_A7_REG32(SH7750_RTCNT_REGOFS)
+
+#define SH7750_RTCNT_KEY      0xA500	/* RTCNT write key */
+
+/* Refresh Time Constant Register (half) - RTCOR */
+#define SH7750_RTCOR_REGOFS   0x800024	/* offset */
+#define SH7750_RTCOR          SH7750_P4_REG32(SH7750_RTCOR_REGOFS)
+#define SH7750_RTCOR_A7       SH7750_A7_REG32(SH7750_RTCOR_REGOFS)
+
+#define SH7750_RTCOR_KEY      0xA500	/* RTCOR write key */
+
+/* Refresh Count Register (half) - RFCR */
+#define SH7750_RFCR_REGOFS    0x800028	/* offset */
+#define SH7750_RFCR           SH7750_P4_REG32(SH7750_RFCR_REGOFS)
+#define SH7750_RFCR_A7        SH7750_A7_REG32(SH7750_RFCR_REGOFS)
+
+#define SH7750_RFCR_KEY       0xA400	/* RFCR write key */
+
+/* Synchronous DRAM mode registers - SDMR */
+#define SH7750_SDMR2_REGOFS   0x900000	/* base offset */
+#define SH7750_SDMR2_REGNB    0x0FFC	/* nb of register */
+#define SH7750_SDMR2          SH7750_P4_REG32(SH7750_SDMR2_REGOFS)
+#define SH7750_SDMR2_A7       SH7750_A7_REG32(SH7750_SDMR2_REGOFS)
+
+#define SH7750_SDMR3_REGOFS   0x940000	/* offset */
+#define SH7750_SDMR3_REGNB    0x0FFC	/* nb of register */
+#define SH7750_SDMR3          SH7750_P4_REG32(SH7750_SDMR3_REGOFS)
+#define SH7750_SDMR3_A7       SH7750_A7_REG32(SH7750_SDMR3_REGOFS)
+
+/*
+ * Direct Memory Access Controller (DMAC)
+ */
+
+/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */
+#define SH7750_SAR_REGOFS(n)  (0xA00000 + ((n)*16))	/* offset */
+#define SH7750_SAR(n)         SH7750_P4_REG32(SH7750_SAR_REGOFS(n))
+#define SH7750_SAR_A7(n)      SH7750_A7_REG32(SH7750_SAR_REGOFS(n))
+#define SH7750_SAR0           SH7750_SAR(0)
+#define SH7750_SAR1           SH7750_SAR(1)
+#define SH7750_SAR2           SH7750_SAR(2)
+#define SH7750_SAR3           SH7750_SAR(3)
+#define SH7750_SAR0_A7        SH7750_SAR_A7(0)
+#define SH7750_SAR1_A7        SH7750_SAR_A7(1)
+#define SH7750_SAR2_A7        SH7750_SAR_A7(2)
+#define SH7750_SAR3_A7        SH7750_SAR_A7(3)
+
+/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */
+#define SH7750_DAR_REGOFS(n)  (0xA00004 + ((n)*16))	/* offset */
+#define SH7750_DAR(n)         SH7750_P4_REG32(SH7750_DAR_REGOFS(n))
+#define SH7750_DAR_A7(n)      SH7750_A7_REG32(SH7750_DAR_REGOFS(n))
+#define SH7750_DAR0           SH7750_DAR(0)
+#define SH7750_DAR1           SH7750_DAR(1)
+#define SH7750_DAR2           SH7750_DAR(2)
+#define SH7750_DAR3           SH7750_DAR(3)
+#define SH7750_DAR0_A7        SH7750_DAR_A7(0)
+#define SH7750_DAR1_A7        SH7750_DAR_A7(1)
+#define SH7750_DAR2_A7        SH7750_DAR_A7(2)
+#define SH7750_DAR3_A7        SH7750_DAR_A7(3)
+
+/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */
+#define SH7750_DMATCR_REGOFS(n)  (0xA00008 + ((n)*16))	/* offset */
+#define SH7750_DMATCR(n)      SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n))
+#define SH7750_DMATCR_A7(n)   SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n))
+#define SH7750_DMATCR0_P4     SH7750_DMATCR(0)
+#define SH7750_DMATCR1_P4     SH7750_DMATCR(1)
+#define SH7750_DMATCR2_P4     SH7750_DMATCR(2)
+#define SH7750_DMATCR3_P4     SH7750_DMATCR(3)
+#define SH7750_DMATCR0_A7     SH7750_DMATCR_A7(0)
+#define SH7750_DMATCR1_A7     SH7750_DMATCR_A7(1)
+#define SH7750_DMATCR2_A7     SH7750_DMATCR_A7(2)
+#define SH7750_DMATCR3_A7     SH7750_DMATCR_A7(3)
+
+/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */
+#define SH7750_CHCR_REGOFS(n)  (0xA0000C + ((n)*16))	/* offset */
+#define SH7750_CHCR(n)        SH7750_P4_REG32(SH7750_CHCR_REGOFS(n))
+#define SH7750_CHCR_A7(n)     SH7750_A7_REG32(SH7750_CHCR_REGOFS(n))
+#define SH7750_CHCR0          SH7750_CHCR(0)
+#define SH7750_CHCR1          SH7750_CHCR(1)
+#define SH7750_CHCR2          SH7750_CHCR(2)
+#define SH7750_CHCR3          SH7750_CHCR(3)
+#define SH7750_CHCR0_A7       SH7750_CHCR_A7(0)
+#define SH7750_CHCR1_A7       SH7750_CHCR_A7(1)
+#define SH7750_CHCR2_A7       SH7750_CHCR_A7(2)
+#define SH7750_CHCR3_A7       SH7750_CHCR_A7(3)
+
+#define SH7750_CHCR_SSA       0xE0000000	/* Source Address Space Attribute */
+#define SH7750_CHCR_SSA_PCMCIA  0x00000000	/* Reserved in PCMCIA access */
+#define SH7750_CHCR_SSA_DYNBSZ  0x20000000	/* Dynamic Bus Sizing I/O space */
+#define SH7750_CHCR_SSA_IO8     0x40000000	/* 8-bit I/O space */
+#define SH7750_CHCR_SSA_IO16    0x60000000	/* 16-bit I/O space */
+#define SH7750_CHCR_SSA_CMEM8   0x80000000	/* 8-bit common memory space */
+#define SH7750_CHCR_SSA_CMEM16  0xA0000000	/* 16-bit common memory space */
+#define SH7750_CHCR_SSA_AMEM8   0xC0000000	/* 8-bit attribute memory space */
+#define SH7750_CHCR_SSA_AMEM16  0xE0000000	/* 16-bit attribute memory space */
+
+#define SH7750_CHCR_STC       0x10000000	/* Source Address Wait Control Select,
+						   specifies CS5 or CS6 space wait
+						   control for PCMCIA access */
+
+#define SH7750_CHCR_DSA       0x0E000000	/* Source Address Space Attribute */
+#define SH7750_CHCR_DSA_PCMCIA  0x00000000	/* Reserved in PCMCIA access */
+#define SH7750_CHCR_DSA_DYNBSZ  0x02000000	/* Dynamic Bus Sizing I/O space */
+#define SH7750_CHCR_DSA_IO8     0x04000000	/* 8-bit I/O space */
+#define SH7750_CHCR_DSA_IO16    0x06000000	/* 16-bit I/O space */
+#define SH7750_CHCR_DSA_CMEM8   0x08000000	/* 8-bit common memory space */
+#define SH7750_CHCR_DSA_CMEM16  0x0A000000	/* 16-bit common memory space */
+#define SH7750_CHCR_DSA_AMEM8   0x0C000000	/* 8-bit attribute memory space */
+#define SH7750_CHCR_DSA_AMEM16  0x0E000000	/* 16-bit attribute memory space */
+
+#define SH7750_CHCR_DTC       0x01000000	/* Destination Address Wait Control
+						   Select, specifies CS5 or CS6
+						   space wait control for PCMCIA
+						   access */
+
+#define SH7750_CHCR_DS        0x00080000	/* DREQ\ Select : */
+#define SH7750_CHCR_DS_LOWLVL 0x00000000	/*     Low Level Detection */
+#define SH7750_CHCR_DS_FALL   0x00080000	/*     Falling Edge Detection */
+
+#define SH7750_CHCR_RL        0x00040000	/* Request Check Level: */
+#define SH7750_CHCR_RL_ACTH   0x00000000	/*     DRAK is an active high out */
+#define SH7750_CHCR_RL_ACTL   0x00040000	/*     DRAK is an active low out */
+
+#define SH7750_CHCR_AM        0x00020000	/* Acknowledge Mode: */
+#define SH7750_CHCR_AM_RD     0x00000000	/*     DACK is output in read cycle */
+#define SH7750_CHCR_AM_WR     0x00020000	/*     DACK is output in write cycle */
+
+#define SH7750_CHCR_AL        0x00010000	/* Acknowledge Level: */
+#define SH7750_CHCR_AL_ACTH   0x00000000	/*     DACK is an active high out */
+#define SH7750_CHCR_AL_ACTL   0x00010000	/*     DACK is an active low out */
+
+#define SH7750_CHCR_DM        0x0000C000	/* Destination Address Mode: */
+#define SH7750_CHCR_DM_FIX    0x00000000	/*     Destination Addr Fixed */
+#define SH7750_CHCR_DM_INC    0x00004000	/*     Destination Addr Incremented */
+#define SH7750_CHCR_DM_DEC    0x00008000	/*     Destination Addr Decremented */
+
+#define SH7750_CHCR_SM        0x00003000	/* Source Address Mode: */
+#define SH7750_CHCR_SM_FIX    0x00000000	/*     Source Addr Fixed */
+#define SH7750_CHCR_SM_INC    0x00001000	/*     Source Addr Incremented */
+#define SH7750_CHCR_SM_DEC    0x00002000	/*     Source Addr Decremented */
+
+#define SH7750_CHCR_RS        0x00000F00	/* Request Source Select: */
+#define SH7750_CHCR_RS_ER_DA_EA_TO_EA   0x000	/* External Request, Dual Address
+						   Mode (External Addr Space->
+						   External Addr Space) */
+#define SH7750_CHCR_RS_ER_SA_EA_TO_ED   0x200	/* External Request, Single
+						   Address Mode (External Addr
+						   Space -> External Device) */
+#define SH7750_CHCR_RS_ER_SA_ED_TO_EA   0x300	/* External Request, Single
+						   Address Mode, (External
+						   Device -> External Addr
+						   Space) */
+#define SH7750_CHCR_RS_AR_EA_TO_EA      0x400	/* Auto-Request (External Addr
+						   Space -> External Addr Space) */
+
+#define SH7750_CHCR_RS_AR_EA_TO_OCP     0x500	/* Auto-Request (External Addr
+						   Space -> On-chip Peripheral
+						   Module) */
+#define SH7750_CHCR_RS_AR_OCP_TO_EA     0x600	/* Auto-Request (On-chip
+						   Peripheral Module ->
+						   External Addr Space */
+#define SH7750_CHCR_RS_SCITX_EA_TO_SC   0x800	/* SCI Transmit-Data-Empty intr
+						   transfer request (external
+						   address space -> SCTDR1) */
+#define SH7750_CHCR_RS_SCIRX_SC_TO_EA   0x900	/* SCI Receive-Data-Full intr
+						   transfer request (SCRDR1 ->
+						   External Addr Space) */
+#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC  0xA00	/* SCIF Transmit-Data-Empty intr
+						   transfer request (external
+						   address space -> SCFTDR1) */
+#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA  0xB00	/* SCIF Receive-Data-Full intr
+						   transfer request (SCFRDR2 ->
+						   External Addr Space) */
+#define SH7750_CHCR_RS_TMU2_EA_TO_EA    0xC00	/* TMU Channel 2 (input capture
+						   interrupt), (external address
+						   space -> external address
+						   space) */
+#define SH7750_CHCR_RS_TMU2_EA_TO_OCP   0xD00	/* TMU Channel 2 (input capture
+						   interrupt), (external address
+						   space -> on-chip peripheral
+						   module) */
+#define SH7750_CHCR_RS_TMU2_OCP_TO_EA   0xE00	/* TMU Channel 2 (input capture
+						   interrupt), (on-chip
+						   peripheral module -> external
+						   address space) */
+
+#define SH7750_CHCR_TM        0x00000080	/* Transmit mode: */
+#define SH7750_CHCR_TM_CSTEAL 0x00000000	/*     Cycle Steal Mode */
+#define SH7750_CHCR_TM_BURST  0x00000080	/*     Burst Mode */
+
+#define SH7750_CHCR_TS        0x00000070	/* Transmit Size: */
+#define SH7750_CHCR_TS_QUAD   0x00000000	/*     Quadword Size (64 bits) */
+#define SH7750_CHCR_TS_BYTE   0x00000010	/*     Byte Size (8 bit) */
+#define SH7750_CHCR_TS_WORD   0x00000020	/*     Word Size (16 bit) */
+#define SH7750_CHCR_TS_LONG   0x00000030	/*     Longword Size (32 bit) */
+#define SH7750_CHCR_TS_BLOCK  0x00000040	/*     32-byte block transfer */
+
+#define SH7750_CHCR_IE        0x00000004	/* Interrupt Enable */
+#define SH7750_CHCR_TE        0x00000002	/* Transfer End */
+#define SH7750_CHCR_DE        0x00000001	/* DMAC Enable */
+
+/* DMA Operation Register - DMAOR */
+#define SH7750_DMAOR_REGOFS   0xA00040	/* offset */
+#define SH7750_DMAOR          SH7750_P4_REG32(SH7750_DMAOR_REGOFS)
+#define SH7750_DMAOR_A7       SH7750_A7_REG32(SH7750_DMAOR_REGOFS)
+
+#define SH7750_DMAOR_DDT      0x00008000	/* On-Demand Data Transfer Mode */
+
+#define SH7750_DMAOR_PR       0x00000300	/* Priority Mode: */
+#define SH7750_DMAOR_PR_0123  0x00000000	/*     CH0 > CH1 > CH2 > CH3 */
+#define SH7750_DMAOR_PR_0231  0x00000100	/*     CH0 > CH2 > CH3 > CH1 */
+#define SH7750_DMAOR_PR_2013  0x00000200	/*     CH2 > CH0 > CH1 > CH3 */
+#define SH7750_DMAOR_PR_RR    0x00000300	/*     Round-robin mode */
+
+#define SH7750_DMAOR_COD      0x00000010	/* Check Overrun for DREQ\ */
+#define SH7750_DMAOR_AE       0x00000004	/* Address Error flag */
+#define SH7750_DMAOR_NMIF     0x00000002	/* NMI Flag */
+#define SH7750_DMAOR_DME      0x00000001	/* DMAC Master Enable */
+
+/*
+ * I/O Ports
+ */
+/* Port Control Register A - PCTRA */
+#define SH7750_PCTRA_REGOFS   0x80002C	/* offset */
+#define SH7750_PCTRA          SH7750_P4_REG32(SH7750_PCTRA_REGOFS)
+#define SH7750_PCTRA_A7       SH7750_A7_REG32(SH7750_PCTRA_REGOFS)
+
+#define SH7750_PCTRA_PBPUP(n) 0	/* Bit n is pulled up */
+#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1))	/* Bit n is not pulled up */
+#define SH7750_PCTRA_PBINP(n) 0	/* Bit n is an input */
+#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2))	/* Bit n is an output */
+
+/* Port Data Register A - PDTRA(half) */
+#define SH7750_PDTRA_REGOFS   0x800030	/* offset */
+#define SH7750_PDTRA          SH7750_P4_REG32(SH7750_PDTRA_REGOFS)
+#define SH7750_PDTRA_A7       SH7750_A7_REG32(SH7750_PDTRA_REGOFS)
+
+#define SH7750_PDTRA_BIT(n) (1 << (n))
+
+/* Port Control Register B - PCTRB */
+#define SH7750_PCTRB_REGOFS   0x800040	/* offset */
+#define SH7750_PCTRB          SH7750_P4_REG32(SH7750_PCTRB_REGOFS)
+#define SH7750_PCTRB_A7       SH7750_A7_REG32(SH7750_PCTRB_REGOFS)
+
+#define SH7750_PCTRB_PBPUP(n) 0	/* Bit n is pulled up */
+#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1))	/* Bit n is not pulled up */
+#define SH7750_PCTRB_PBINP(n) 0	/* Bit n is an input */
+#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2))	/* Bit n is an output */
+
+/* Port Data Register B - PDTRB(half) */
+#define SH7750_PDTRB_REGOFS   0x800044	/* offset */
+#define SH7750_PDTRB          SH7750_P4_REG32(SH7750_PDTRB_REGOFS)
+#define SH7750_PDTRB_A7       SH7750_A7_REG32(SH7750_PDTRB_REGOFS)
+
+#define SH7750_PDTRB_BIT(n) (1 << ((n)-16))
+
+/* GPIO Interrupt Control Register - GPIOIC(half) */
+#define SH7750_GPIOIC_REGOFS  0x800048	/* offset */
+#define SH7750_GPIOIC         SH7750_P4_REG32(SH7750_GPIOIC_REGOFS)
+#define SH7750_GPIOIC_A7      SH7750_A7_REG32(SH7750_GPIOIC_REGOFS)
+
+#define SH7750_GPIOIC_PTIREN(n) (1 << (n))	/* Port n is used as a GPIO int */
+
+/*
+ * Interrupt Controller - INTC
+ */
+/* Interrupt Control Register - ICR (half) */
+#define SH7750_ICR_REGOFS     0xD00000	/* offset */
+#define SH7750_ICR            SH7750_P4_REG32(SH7750_ICR_REGOFS)
+#define SH7750_ICR_A7         SH7750_A7_REG32(SH7750_ICR_REGOFS)
+
+#define SH7750_ICR_NMIL       0x8000	/* NMI Input Level */
+#define SH7750_ICR_MAI        0x4000	/* NMI Interrupt Mask */
+
+#define SH7750_ICR_NMIB       0x0200	/* NMI Block Mode: */
+#define SH7750_ICR_NMIB_BLK   0x0000	/*   NMI requests held pending while
+					   SR.BL bit is set to 1 */
+#define SH7750_ICR_NMIB_NBLK  0x0200	/*   NMI requests detected when SR.BL bit
+					   set to 1 */
+
+#define SH7750_ICR_NMIE       0x0100	/* NMI Edge Select: */
+#define SH7750_ICR_NMIE_FALL  0x0000	/*   Interrupt request detected on falling
+					   edge of NMI input */
+#define SH7750_ICR_NMIE_RISE  0x0100	/*   Interrupt request detected on rising
+					   edge of NMI input */
+
+#define SH7750_ICR_IRLM       0x0080	/* IRL Pin Mode: */
+#define SH7750_ICR_IRLM_ENC   0x0000	/*   IRL\ pins used as a level-encoded
+					   interrupt requests */
+#define SH7750_ICR_IRLM_RAW   0x0080	/*   IRL\ pins used as a four independent
+					   interrupt requests */
+
+/*
+ * User Break Controller registers
+ */
+#define SH7750_BARA           0x200000	/* Break address regiser A */
+#define SH7750_BAMRA          0x200004	/* Break address mask regiser A */
+#define SH7750_BBRA           0x200008	/* Break bus cycle regiser A */
+#define SH7750_BARB           0x20000c	/* Break address regiser B */
+#define SH7750_BAMRB          0x200010	/* Break address mask regiser B */
+#define SH7750_BBRB           0x200014	/* Break bus cycle regiser B */
+#define SH7750_BASRB          0x000018	/* Break ASID regiser B */
+#define SH7750_BDRB           0x200018	/* Break data regiser B */
+#define SH7750_BDMRB          0x20001c	/* Break data mask regiser B */
+#define SH7750_BRCR           0x200020	/* Break control register */
+
+#define SH7750_BRCR_UDBE        0x0001	/* User break debug enable bit */
+
+/*
+ * Missing in RTEMS, added for QEMU
+ */
+#define SH7750_BCR3_A7       0x1f800050
+#define SH7750_BCR4_A7       0x1e0a00f0
+
+#endif
diff --git a/qemu-0.15.x/hw/sh_intc.c b/qemu-0.15.x/hw/sh_intc.c
new file mode 100644
index 0000000..c43b99f
--- /dev/null
+++ b/qemu-0.15.x/hw/sh_intc.c
@@ -0,0 +1,481 @@
+/*
+ * SuperH interrupt controller module
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on sh_timer.c and arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sh_intc.h"
+#include "hw.h"
+#include "sh.h"
+
+//#define DEBUG_INTC
+//#define DEBUG_INTC_SOURCES
+
+#define INTC_A7(x) ((x) & 0x1fffffff)
+
+void sh_intc_toggle_source(struct intc_source *source,
+			   int enable_adj, int assert_adj)
+{
+    int enable_changed = 0;
+    int pending_changed = 0;
+    int old_pending;
+
+    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
+        enable_changed = -1;
+
+    source->enable_count += enable_adj;
+
+    if (source->enable_count == source->enable_max)
+        enable_changed = 1;
+
+    source->asserted += assert_adj;
+
+    old_pending = source->pending;
+    source->pending = source->asserted &&
+      (source->enable_count == source->enable_max);
+
+    if (old_pending != source->pending)
+        pending_changed = 1;
+
+    if (pending_changed) {
+        if (source->pending) {
+            source->parent->pending++;
+	    if (source->parent->pending == 1)
+                cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
+	}
+	else {
+            source->parent->pending--;
+	    if (source->parent->pending == 0)
+                cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
+	}
+    }
+
+  if (enable_changed || assert_adj || pending_changed) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
+		   source->parent->pending,
+		   source->asserted,
+		   source->enable_count,
+		   source->enable_max,
+		   source->vect,
+		   source->asserted ? "asserted " :
+		   assert_adj ? "deasserted" : "",
+		   enable_changed == 1 ? "enabled " :
+		   enable_changed == -1 ? "disabled " : "",
+		   source->pending ? "pending" : "");
+#endif
+  }
+}
+
+static void sh_intc_set_irq (void *opaque, int n, int level)
+{
+  struct intc_desc *desc = opaque;
+  struct intc_source *source = &(desc->sources[n]);
+
+  if (level && !source->asserted)
+    sh_intc_toggle_source(source, 0, 1);
+  else if (!level && source->asserted)
+    sh_intc_toggle_source(source, 0, -1);
+}
+
+int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
+{
+    unsigned int i;
+
+    /* slow: use a linked lists of pending sources instead */
+    /* wrong: take interrupt priority into account (one list per priority) */
+
+    if (imask == 0x0f) {
+        return -1; /* FIXME, update code to include priority per source */
+    }
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+	if (source->pending) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
+		   desc->pending, source->vect);
+#endif
+            return source->vect;
+	}
+    }
+
+    abort();
+}
+
+#define INTC_MODE_NONE       0
+#define INTC_MODE_DUAL_SET   1
+#define INTC_MODE_DUAL_CLR   2
+#define INTC_MODE_ENABLE_REG 3
+#define INTC_MODE_MASK_REG   4
+#define INTC_MODE_IS_PRIO    8
+
+static unsigned int sh_intc_mode(unsigned long address,
+				 unsigned long set_reg, unsigned long clr_reg)
+{
+    if ((address != INTC_A7(set_reg)) &&
+	(address != INTC_A7(clr_reg)))
+        return INTC_MODE_NONE;
+
+    if (set_reg && clr_reg) {
+        if (address == INTC_A7(set_reg))
+            return INTC_MODE_DUAL_SET;
+	else
+            return INTC_MODE_DUAL_CLR;
+    }
+
+    if (set_reg)
+        return INTC_MODE_ENABLE_REG;
+    else
+        return INTC_MODE_MASK_REG;
+}
+
+static void sh_intc_locate(struct intc_desc *desc,
+			   unsigned long address,
+			   unsigned long **datap,
+			   intc_enum **enums,
+			   unsigned int *first,
+			   unsigned int *width,
+			   unsigned int *modep)
+{
+    unsigned int i, mode;
+
+    /* this is slow but works for now */
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+	    struct intc_mask_reg *mr = desc->mask_regs + i;
+
+	    mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
+	    if (mode == INTC_MODE_NONE)
+                continue;
+
+	    *modep = mode;
+	    *datap = &mr->value;
+	    *enums = mr->enum_ids;
+	    *first = mr->reg_width - 1;
+	    *width = 1;
+	    return;
+	}
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+	    struct intc_prio_reg *pr = desc->prio_regs + i;
+
+	    mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
+	    if (mode == INTC_MODE_NONE)
+                continue;
+
+	    *modep = mode | INTC_MODE_IS_PRIO;
+	    *datap = &pr->value;
+	    *enums = pr->enum_ids;
+	    *first = (pr->reg_width / pr->field_width) - 1;
+	    *width = pr->field_width;
+	    return;
+	}
+    }
+
+    abort();
+}
+
+static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
+				int enable, int is_group)
+{
+    struct intc_source *source = desc->sources + id;
+
+    if (!id)
+	return;
+
+    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
+#ifdef DEBUG_INTC_SOURCES
+        printf("sh_intc: reserved interrupt source %d modified\n", id);
+#endif
+	return;
+    }
+
+    if (source->vect)
+        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
+
+#ifdef DEBUG_INTC
+    else {
+        printf("setting interrupt group %d to %d\n", id, !!enable);
+    }
+#endif
+
+    if ((is_group || !source->vect) && source->next_enum_id) {
+        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
+    }
+
+#ifdef DEBUG_INTC
+    if (!source->vect) {
+        printf("setting interrupt group %d to %d - done\n", id, !!enable);
+    }
+#endif
+}
+
+static uint32_t sh_intc_read(void *opaque, target_phys_addr_t offset)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned long *valuep;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+		   &enum_ids, &first, &width, &mode);
+    return *valuep;
+}
+
+static void sh_intc_write(void *opaque, target_phys_addr_t offset,
+			  uint32_t value)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned int k;
+    unsigned long *valuep;
+    unsigned long mask;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+		   &enum_ids, &first, &width, &mode);
+
+    switch (mode) {
+    case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
+    case INTC_MODE_DUAL_SET: value |= *valuep; break;
+    case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
+    default: abort();
+    }
+
+    for (k = 0; k <= first; k++) {
+        mask = ((1 << width) - 1) << ((first - k) * width);
+
+	if ((*valuep & mask) == (value & mask))
+            continue;
+#if 0
+	printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
+	       k, first, enum_ids[k], (unsigned int)mask);
+#endif
+        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
+    }
+
+    *valuep = value;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
+#endif
+}
+
+static CPUReadMemoryFunc * const sh_intc_readfn[] = {
+    sh_intc_read,
+    sh_intc_read,
+    sh_intc_read
+};
+
+static CPUWriteMemoryFunc * const sh_intc_writefn[] = {
+    sh_intc_write,
+    sh_intc_write,
+    sh_intc_write
+};
+
+struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
+{
+    if (id)
+        return desc->sources + id;
+
+    return NULL;
+}
+
+static void sh_intc_register(struct intc_desc *desc, 
+			     unsigned long address)
+{
+    if (address) {
+        cpu_register_physical_memory_offset(P4ADDR(address), 4,
+                                            desc->iomemtype, INTC_A7(address));
+        cpu_register_physical_memory_offset(A7ADDR(address), 4,
+                                            desc->iomemtype, INTC_A7(address));
+    }
+}
+
+static void sh_intc_register_source(struct intc_desc *desc,
+				    intc_enum source,
+				    struct intc_group *groups,
+				    int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+	    struct intc_mask_reg *mr = desc->mask_regs + i;
+
+	    for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
+                if (mr->enum_ids[k] != source)
+                    continue;
+
+		s = sh_intc_source(desc, mr->enum_ids[k]);
+		if (s)
+                    s->enable_max++;
+	    }
+	}
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+	    struct intc_prio_reg *pr = desc->prio_regs + i;
+
+	    for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
+                if (pr->enum_ids[k] != source)
+                    continue;
+
+		s = sh_intc_source(desc, pr->enum_ids[k]);
+		if (s)
+                    s->enable_max++;
+	    }
+	}
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+	    struct intc_group *gr = groups + i;
+
+	    for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (gr->enum_ids[k] != source)
+                    continue;
+
+		s = sh_intc_source(desc, gr->enum_ids[k]);
+		if (s)
+                    s->enable_max++;
+	    }
+	}
+    }
+
+}
+
+void sh_intc_register_sources(struct intc_desc *desc,
+			      struct intc_vect *vectors,
+			      int nr_vectors,
+			      struct intc_group *groups,
+			      int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    for (i = 0; i < nr_vectors; i++) {
+	struct intc_vect *vect = vectors + i;
+
+	sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
+	s = sh_intc_source(desc, vect->enum_id);
+	if (s)
+	    s->vect = vect->vect;
+
+#ifdef DEBUG_INTC_SOURCES
+	printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
+	       vect->enum_id, s->vect, s->enable_count, s->enable_max);
+#endif
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+	    struct intc_group *gr = groups + i;
+
+	    s = sh_intc_source(desc, gr->enum_id);
+	    s->next_enum_id = gr->enum_ids[0];
+
+	    for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (!gr->enum_ids[k])
+                    continue;
+
+		s = sh_intc_source(desc, gr->enum_ids[k - 1]);
+		s->next_enum_id = gr->enum_ids[k];
+	    }
+
+#ifdef DEBUG_INTC_SOURCES
+	    printf("sh_intc: registered group %d (%d/%d)\n",
+		   gr->enum_id, s->enable_count, s->enable_max);
+#endif
+	}
+    }
+}
+
+int sh_intc_init(struct intc_desc *desc,
+		 int nr_sources,
+		 struct intc_mask_reg *mask_regs,
+		 int nr_mask_regs,
+		 struct intc_prio_reg *prio_regs,
+		 int nr_prio_regs)
+{
+    unsigned int i;
+
+    desc->pending = 0;
+    desc->nr_sources = nr_sources;
+    desc->mask_regs = mask_regs;
+    desc->nr_mask_regs = nr_mask_regs;
+    desc->prio_regs = prio_regs;
+    desc->nr_prio_regs = nr_prio_regs;
+
+    i = sizeof(struct intc_source) * nr_sources;
+    desc->sources = qemu_mallocz(i);
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+        source->parent = desc;
+    }
+
+    desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
+ 
+    desc->iomemtype = cpu_register_io_memory(sh_intc_readfn,
+					     sh_intc_writefn, desc,
+                                             DEVICE_NATIVE_ENDIAN);
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+	    struct intc_mask_reg *mr = desc->mask_regs + i;
+
+	    sh_intc_register(desc, mr->set_reg);
+	    sh_intc_register(desc, mr->clr_reg);
+	}
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+	    struct intc_prio_reg *pr = desc->prio_regs + i;
+
+	    sh_intc_register(desc, pr->set_reg);
+	    sh_intc_register(desc, pr->clr_reg);
+	}
+    }
+
+    return 0;
+}
+
+/* Assert level <n> IRL interrupt. 
+   0:deassert. 1:lowest priority,... 15:highest priority. */
+void sh_intc_set_irl(void *opaque, int n, int level)
+{
+    struct intc_source *s = opaque;
+    int i, irl = level ^ 15;
+    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
+	if (i == irl)
+	    sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
+	else
+	    if (s->asserted)
+	        sh_intc_toggle_source(s, 0, -1);
+    }
+}
diff --git a/qemu-0.15.x/hw/sh_intc.h b/qemu-0.15.x/hw/sh_intc.h
new file mode 100644
index 0000000..c117d6f
--- /dev/null
+++ b/qemu-0.15.x/hw/sh_intc.h
@@ -0,0 +1,80 @@
+#ifndef __SH_INTC_H__
+#define __SH_INTC_H__
+
+#include "qemu-common.h"
+#include "irq.h"
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+    intc_enum enum_id;
+    unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_group {
+    intc_enum enum_id;
+    intc_enum enum_ids[32];
+};
+
+#define INTC_GROUP(enum_id, ...) { enum_id, {  __VA_ARGS__ } }
+
+struct intc_mask_reg {
+    unsigned long set_reg, clr_reg, reg_width;
+    intc_enum enum_ids[32];
+    unsigned long value;
+};
+
+struct intc_prio_reg {
+    unsigned long set_reg, clr_reg, reg_width, field_width;
+    intc_enum enum_ids[16];
+    unsigned long value;
+};
+
+#define _INTC_ARRAY(a) a, ARRAY_SIZE(a)
+
+struct intc_source {
+    unsigned short vect;
+    intc_enum next_enum_id;
+
+    int asserted; /* emulates the interrupt signal line from device to intc */
+    int enable_count;
+    int enable_max;
+    int pending; /* emulates the result of signal and masking */
+    struct intc_desc *parent;
+};
+
+struct intc_desc {
+    qemu_irq *irqs;
+    struct intc_source *sources;
+    int nr_sources;
+    struct intc_mask_reg *mask_regs;
+    int nr_mask_regs;
+    struct intc_prio_reg *prio_regs;
+    int nr_prio_regs;
+    int iomemtype;
+    int pending; /* number of interrupt sources that has pending set */
+};
+
+int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
+struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
+void sh_intc_toggle_source(struct intc_source *source,
+			   int enable_adj, int assert_adj);
+
+void sh_intc_register_sources(struct intc_desc *desc,
+			      struct intc_vect *vectors,
+			      int nr_vectors,
+			      struct intc_group *groups,
+			      int nr_groups);
+
+int sh_intc_init(struct intc_desc *desc,
+		 int nr_sources,
+		 struct intc_mask_reg *mask_regs,
+		 int nr_mask_regs,
+		 struct intc_prio_reg *prio_regs,
+		 int nr_prio_regs);
+
+void sh_intc_set_irl(void *opaque, int n, int level);
+
+#endif /* __SH_INTC_H__ */
diff --git a/qemu-0.15.x/hw/sh_pci.c b/qemu-0.15.x/hw/sh_pci.c
new file mode 100644
index 0000000..a076cf2
--- /dev/null
+++ b/qemu-0.15.x/hw/sh_pci.c
@@ -0,0 +1,161 @@
+/*
+ * SuperH on-chip PCIC emulation.
+ *
+ * Copyright (c) 2008 Takashi YOSHII
+ *
+ * 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 "sysbus.h"
+#include "sh.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "bswap.h"
+
+typedef struct SHPCIState {
+    SysBusDevice busdev;
+    PCIBus *bus;
+    PCIDevice *dev;
+    qemu_irq irq[4];
+    int memconfig;
+    uint32_t par;
+    uint32_t mbr;
+    uint32_t iobr;
+} SHPCIState;
+
+static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    SHPCIState *pcic = p;
+    switch(addr) {
+    case 0 ... 0xfc:
+        cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
+        break;
+    case 0x1c0:
+        pcic->par = val;
+        break;
+    case 0x1c4:
+        pcic->mbr = val & 0xff000001;
+        break;
+    case 0x1c8:
+        if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
+            cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
+                                         IO_MEM_UNASSIGNED);
+            pcic->iobr = val & 0xfffc0001;
+            isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
+        }
+        break;
+    case 0x220:
+        pci_data_write(pcic->bus, pcic->par, val, 4);
+        break;
+    }
+}
+
+static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
+{
+    SHPCIState *pcic = p;
+    switch(addr) {
+    case 0 ... 0xfc:
+        return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
+    case 0x1c0:
+        return pcic->par;
+    case 0x1c4:
+        return pcic->mbr;
+    case 0x1c8:
+        return pcic->iobr;
+    case 0x220:
+        return pci_data_read(pcic->bus, pcic->par, 4);
+    }
+    return 0;
+}
+
+typedef struct {
+    CPUReadMemoryFunc * const r[3];
+    CPUWriteMemoryFunc * const w[3];
+} MemOp;
+
+static MemOp sh_pci_reg = {
+    { NULL, NULL, sh_pci_reg_read },
+    { NULL, NULL, sh_pci_reg_write },
+};
+
+static int sh_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    return (d->devfn >> 3);
+}
+
+static void sh_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static void sh_pci_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    SHPCIState *s = FROM_SYSBUS(SHPCIState, dev);
+
+    cpu_register_physical_memory(P4ADDR(base), 0x224, s->memconfig);
+    cpu_register_physical_memory(A7ADDR(base), 0x224, s->memconfig);
+
+    s->iobr = 0xfe240000;
+    isa_mmio_init(s->iobr, 0x40000);
+}
+
+static int sh_pci_init_device(SysBusDevice *dev)
+{
+    SHPCIState *s;
+    int i;
+
+    s = FROM_SYSBUS(SHPCIState, dev);
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+    s->bus = pci_register_bus(&s->busdev.qdev, "pci",
+                              sh_pci_set_irq, sh_pci_map_irq,
+                              s->irq, PCI_DEVFN(0, 0), 4);
+    s->memconfig = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w,
+                                          s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio_cb(dev, 0x224, sh_pci_map);
+    s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
+    return 0;
+}
+
+static int sh_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
+    pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+static PCIDeviceInfo sh_pci_host_info = {
+    .qdev.name = "sh_pci_host",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = sh_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_HITACHI,
+    .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
+};
+
+static void sh_pci_register_devices(void)
+{
+    sysbus_register_dev("sh_pci", sizeof(SHPCIState),
+                        sh_pci_init_device);
+    pci_qdev_register(&sh_pci_host_info);
+}
+
+device_init(sh_pci_register_devices)
diff --git a/qemu-0.15.x/hw/sh_serial.c b/qemu-0.15.x/hw/sh_serial.c
new file mode 100644
index 0000000..191f4a6
--- /dev/null
+++ b/qemu-0.15.x/hw/sh_serial.c
@@ -0,0 +1,401 @@
+/*
+ * QEMU SCI/SCIF serial port emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ *
+ * Based on serial.c - 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 "hw.h"
+#include "sh.h"
+#include "qemu-char.h"
+
+//#define DEBUG_SERIAL
+
+#define SH_SERIAL_FLAG_TEND (1 << 0)
+#define SH_SERIAL_FLAG_TDE  (1 << 1)
+#define SH_SERIAL_FLAG_RDF  (1 << 2)
+#define SH_SERIAL_FLAG_BRK  (1 << 3)
+#define SH_SERIAL_FLAG_DR   (1 << 4)
+
+#define SH_RX_FIFO_LENGTH (16)
+
+typedef struct {
+    uint8_t smr;
+    uint8_t brr;
+    uint8_t scr;
+    uint8_t dr; /* ftdr / tdr */
+    uint8_t sr; /* fsr / ssr */
+    uint16_t fcr;
+    uint8_t sptr;
+
+    uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
+    uint8_t rx_cnt;
+    uint8_t rx_tail;
+    uint8_t rx_head;
+
+    int freq;
+    int feat;
+    int flags;
+    int rtrg;
+
+    CharDriverState *chr;
+
+    qemu_irq eri;
+    qemu_irq rxi;
+    qemu_irq txi;
+    qemu_irq tei;
+    qemu_irq bri;
+} sh_serial_state;
+
+static void sh_serial_clear_fifo(sh_serial_state * s)
+{
+    memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
+    s->rx_cnt = 0;
+    s->rx_head = 0;
+    s->rx_tail = 0;
+}
+
+static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
+{
+    sh_serial_state *s = opaque;
+    unsigned char ch;
+
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: write offs=0x%02x val=0x%02x\n",
+	   offs, val);
+#endif
+    switch(offs) {
+    case 0x00: /* SMR */
+        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
+        return;
+    case 0x04: /* BRR */
+        s->brr = val;
+	return;
+    case 0x08: /* SCR */
+        /* TODO : For SH7751, SCIF mask should be 0xfb. */
+        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
+        if (!(val & (1 << 5)))
+            s->flags |= SH_SERIAL_FLAG_TEND;
+        if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
+	    qemu_set_irq(s->txi, val & (1 << 7));
+        }
+        if (!(val & (1 << 6))) {
+	    qemu_set_irq(s->rxi, 0);
+        }
+        return;
+    case 0x0c: /* FTDR / TDR */
+        if (s->chr) {
+            ch = val;
+            qemu_chr_write(s->chr, &ch, 1);
+	}
+	s->dr = val;
+	s->flags &= ~SH_SERIAL_FLAG_TDE;
+        return;
+#if 0
+    case 0x14: /* FRDR / RDR */
+        ret = 0;
+        break;
+#endif
+    }
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x10: /* FSR */
+            if (!(val & (1 << 6)))
+                s->flags &= ~SH_SERIAL_FLAG_TEND;
+            if (!(val & (1 << 5)))
+                s->flags &= ~SH_SERIAL_FLAG_TDE;
+            if (!(val & (1 << 4)))
+                s->flags &= ~SH_SERIAL_FLAG_BRK;
+            if (!(val & (1 << 1)))
+                s->flags &= ~SH_SERIAL_FLAG_RDF;
+            if (!(val & (1 << 0)))
+                s->flags &= ~SH_SERIAL_FLAG_DR;
+
+            if (!(val & (1 << 1)) || !(val & (1 << 0))) {
+                if (s->rxi) {
+                    qemu_set_irq(s->rxi, 0);
+                }
+            }
+            return;
+        case 0x18: /* FCR */
+            s->fcr = val;
+            switch ((val >> 6) & 3) {
+            case 0:
+                s->rtrg = 1;
+                break;
+            case 1:
+                s->rtrg = 4;
+                break;
+            case 2:
+                s->rtrg = 8;
+                break;
+            case 3:
+                s->rtrg = 14;
+                break;
+            }
+            if (val & (1 << 1)) {
+                sh_serial_clear_fifo(s);
+                s->sr &= ~(1 << 1);
+            }
+
+            return;
+        case 0x20: /* SPTR */
+            s->sptr = val & 0xf3;
+            return;
+        case 0x24: /* LSR */
+            return;
+        }
+    }
+    else {
+        switch(offs) {
+#if 0
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+#endif
+        case 0x1c:
+            s->sptr = val & 0x8f;
+            return;
+        }
+    }
+
+    fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
+    abort();
+}
+
+static uint32_t sh_serial_read(void *opaque, uint32_t offs)
+{
+    sh_serial_state *s = opaque;
+    uint32_t ret = ~0;
+
+#if 0
+    switch(offs) {
+    case 0x00:
+        ret = s->smr;
+        break;
+    case 0x04:
+        ret = s->brr;
+	break;
+    case 0x08:
+        ret = s->scr;
+        break;
+    case 0x14:
+        ret = 0;
+        break;
+    }
+#endif
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x00: /* SMR */
+            ret = s->smr;
+            break;
+        case 0x08: /* SCR */
+            ret = s->scr;
+            break;
+        case 0x10: /* FSR */
+            ret = 0;
+            if (s->flags & SH_SERIAL_FLAG_TEND)
+                ret |= (1 << 6);
+            if (s->flags & SH_SERIAL_FLAG_TDE)
+                ret |= (1 << 5);
+            if (s->flags & SH_SERIAL_FLAG_BRK)
+                ret |= (1 << 4);
+            if (s->flags & SH_SERIAL_FLAG_RDF)
+                ret |= (1 << 1);
+            if (s->flags & SH_SERIAL_FLAG_DR)
+                ret |= (1 << 0);
+
+            if (s->scr & (1 << 5))
+                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
+
+            break;
+        case 0x14:
+            if (s->rx_cnt > 0) {
+                ret = s->rx_fifo[s->rx_tail++];
+                s->rx_cnt--;
+                if (s->rx_tail == SH_RX_FIFO_LENGTH)
+                    s->rx_tail = 0;
+                if (s->rx_cnt < s->rtrg)
+                    s->flags &= ~SH_SERIAL_FLAG_RDF;
+            }
+            break;
+#if 0
+        case 0x18:
+            ret = s->fcr;
+            break;
+#endif
+        case 0x1c:
+            ret = s->rx_cnt;
+            break;
+        case 0x20:
+            ret = s->sptr;
+            break;
+        case 0x24:
+            ret = 0;
+            break;
+        }
+    }
+    else {
+        switch(offs) {
+#if 0
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+        case 0x14:
+            ret = s->rx_fifo[0];
+            break;
+#endif
+        case 0x1c:
+            ret = s->sptr;
+            break;
+        }
+    }
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: read offs=0x%02x val=0x%x\n",
+	   offs, ret);
+#endif
+
+    if (ret & ~((1 << 16) - 1)) {
+        fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
+        abort();
+    }
+
+    return ret;
+}
+
+static int sh_serial_can_receive(sh_serial_state *s)
+{
+    return s->scr & (1 << 4);
+}
+
+static void sh_serial_receive_break(sh_serial_state *s)
+{
+    if (s->feat & SH_SERIAL_FEAT_SCIF)
+        s->sr |= (1 << 4);
+}
+
+static int sh_serial_can_receive1(void *opaque)
+{
+    sh_serial_state *s = opaque;
+    return sh_serial_can_receive(s);
+}
+
+static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    sh_serial_state *s = opaque;
+
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        int i;
+        for (i = 0; i < size; i++) {
+            if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
+                s->rx_fifo[s->rx_head++] = buf[i];
+                if (s->rx_head == SH_RX_FIFO_LENGTH) {
+                    s->rx_head = 0;
+                }
+                s->rx_cnt++;
+                if (s->rx_cnt >= s->rtrg) {
+                    s->flags |= SH_SERIAL_FLAG_RDF;
+                    if (s->scr & (1 << 6) && s->rxi) {
+                        qemu_set_irq(s->rxi, 1);
+                    }
+                }
+            }
+        }
+    } else {
+        s->rx_fifo[0] = buf[0];
+    }
+}
+
+static void sh_serial_event(void *opaque, int event)
+{
+    sh_serial_state *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        sh_serial_receive_break(s);
+}
+
+static CPUReadMemoryFunc * const sh_serial_readfn[] = {
+    &sh_serial_read,
+    &sh_serial_read,
+    &sh_serial_read,
+};
+
+static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
+    &sh_serial_write,
+    &sh_serial_write,
+    &sh_serial_write,
+};
+
+void sh_serial_init (target_phys_addr_t base, int feat,
+		     uint32_t freq, CharDriverState *chr,
+		     qemu_irq eri_source,
+		     qemu_irq rxi_source,
+		     qemu_irq txi_source,
+		     qemu_irq tei_source,
+		     qemu_irq bri_source)
+{
+    sh_serial_state *s;
+    int s_io_memory;
+
+    s = qemu_mallocz(sizeof(sh_serial_state));
+
+    s->feat = feat;
+    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
+    s->rtrg = 1;
+
+    s->smr = 0;
+    s->brr = 0xff;
+    s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
+    s->sptr = 0;
+
+    if (feat & SH_SERIAL_FEAT_SCIF) {
+        s->fcr = 0;
+    }
+    else {
+        s->dr = 0xff;
+    }
+
+    sh_serial_clear_fifo(s);
+
+    s_io_memory = cpu_register_io_memory(sh_serial_readfn,
+					 sh_serial_writefn, s,
+                                         DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
+    cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
+
+    s->chr = chr;
+
+    if (chr)
+        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
+			      sh_serial_event, s);
+
+    s->eri = eri_source;
+    s->rxi = rxi_source;
+    s->txi = txi_source;
+    s->tei = tei_source;
+    s->bri = bri_source;
+}
diff --git a/qemu-0.15.x/hw/sh_timer.c b/qemu-0.15.x/hw/sh_timer.c
new file mode 100644
index 0000000..5df7fb6
--- /dev/null
+++ b/qemu-0.15.x/hw/sh_timer.c
@@ -0,0 +1,327 @@
+/*
+ * SuperH Timer modules.
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "sh.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_TIMER
+
+#define TIMER_TCR_TPSC          (7 << 0)
+#define TIMER_TCR_CKEG          (3 << 3)
+#define TIMER_TCR_UNIE          (1 << 5)
+#define TIMER_TCR_ICPE          (3 << 6)
+#define TIMER_TCR_UNF           (1 << 8)
+#define TIMER_TCR_ICPF          (1 << 9)
+#define TIMER_TCR_RESERVED      (0x3f << 10)
+
+#define TIMER_FEAT_CAPT   (1 << 0)
+#define TIMER_FEAT_EXTCLK (1 << 1)
+
+#define OFFSET_TCOR   0
+#define OFFSET_TCNT   1
+#define OFFSET_TCR    2
+#define OFFSET_TCPR   3
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t tcnt;
+    uint32_t tcor;
+    uint32_t tcr;
+    uint32_t tcpr;
+    int freq;
+    int int_level;
+    int old_level;
+    int feat;
+    int enabled;
+    qemu_irq irq;
+} sh_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt. */
+
+static void sh_timer_update(sh_timer_state *s)
+{
+    int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
+
+    if (new_level != s->old_level)
+      qemu_set_irq (s->irq, new_level);
+
+    s->old_level = s->int_level;
+    s->int_level = new_level;
+}
+
+static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        return s->tcor;
+    case OFFSET_TCNT:
+        return ptimer_get_count(s->timer);
+    case OFFSET_TCR:
+        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT)
+            return s->tcpr;
+    default:
+        hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void sh_timer_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        s->tcor = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        break;
+    case OFFSET_TCNT:
+        s->tcnt = value;
+        ptimer_set_count(s->timer, s->tcnt);
+        break;
+    case OFFSET_TCR:
+        if (s->enabled) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch (value & TIMER_TCR_TPSC) {
+        case 0: freq >>= 2; break;
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 6; break;
+        case 3: freq >>= 8; break;
+        case 4: freq >>= 10; break;
+	case 6:
+	case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
+	default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
+        }
+        switch ((value & TIMER_TCR_CKEG) >> 3) {
+	case 0: break;
+        case 1:
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
+	default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
+        }
+        switch ((value & TIMER_TCR_ICPE) >> 6) {
+	case 0: break;
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
+	default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
+        }
+	if ((value & TIMER_TCR_UNF) == 0)
+            s->int_level = 0;
+
+	value &= ~TIMER_TCR_UNF;
+
+	if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
+            hw_error("sh_timer_write: Reserved ICPF value\n");
+
+	value &= ~TIMER_TCR_ICPF; /* capture not supported */
+
+	if (value & TIMER_TCR_RESERVED)
+            hw_error("sh_timer_write: Reserved TCR bits set\n");
+        s->tcr = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        ptimer_set_freq(s->timer, freq);
+        if (s->enabled) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, 0);
+        }
+        break;
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT) {
+            s->tcpr = value;
+	    break;
+	}
+    default:
+        hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
+    }
+    sh_timer_update(s);
+}
+
+static void sh_timer_start_stop(void *opaque, int enable)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
+#endif
+
+    if (s->enabled && !enable) {
+        ptimer_stop(s->timer);
+    }
+    if (!s->enabled && enable) {
+        ptimer_run(s->timer, 0);
+    }
+    s->enabled = !!enable;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop done %d\n", s->enabled);
+#endif
+}
+
+static void sh_timer_tick(void *opaque)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    s->int_level = s->enabled;
+    sh_timer_update(s);
+}
+
+static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
+{
+    sh_timer_state *s;
+    QEMUBH *bh;
+
+    s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state));
+    s->freq = freq;
+    s->feat = feat;
+    s->tcor = 0xffffffff;
+    s->tcnt = 0xffffffff;
+    s->tcpr = 0xdeadbeef;
+    s->tcr = 0;
+    s->enabled = 0;
+    s->irq = irq;
+
+    bh = qemu_bh_new(sh_timer_tick, s);
+    s->timer = ptimer_init(bh);
+
+    sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
+    sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
+    sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
+    sh_timer_write(s, OFFSET_TCR  >> 2, s->tcpr);
+    /* ??? Save/restore.  */
+    return s;
+}
+
+typedef struct {
+    void *timer[3];
+    int level[3];
+    uint32_t tocr;
+    uint32_t tstr;
+    int feat;
+} tmu012_state;
+
+static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+	    hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        return sh_timer_read(s->timer[2], offset - 0x20);
+    }
+
+    if (offset >= 0x14)
+        return sh_timer_read(s->timer[1], offset - 0x14);
+
+    if (offset >= 0x08)
+        return sh_timer_read(s->timer[0], offset - 0x08);
+
+    if (offset == 4)
+        return s->tstr;
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
+        return s->tocr;
+
+    hw_error("tmu012_write: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static void tmu012_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+	    hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        sh_timer_write(s->timer[2], offset - 0x20, value);
+	return;
+    }
+
+    if (offset >= 0x14) {
+        sh_timer_write(s->timer[1], offset - 0x14, value);
+	return;
+    }
+
+    if (offset >= 0x08) {
+        sh_timer_write(s->timer[0], offset - 0x08, value);
+	return;
+    }
+
+    if (offset == 4) {
+        sh_timer_start_stop(s->timer[0], value & (1 << 0));
+        sh_timer_start_stop(s->timer[1], value & (1 << 1));
+        if (s->feat & TMU012_FEAT_3CHAN)
+            sh_timer_start_stop(s->timer[2], value & (1 << 2));
+	else
+            if (value & (1 << 2))
+                hw_error("tmu012_write: Bad channel\n");
+
+	s->tstr = value;
+	return;
+    }
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
+        s->tocr = value & (1 << 0);
+    }
+}
+
+static CPUReadMemoryFunc * const tmu012_readfn[] = {
+    tmu012_read,
+    tmu012_read,
+    tmu012_read
+};
+
+static CPUWriteMemoryFunc * const tmu012_writefn[] = {
+    tmu012_write,
+    tmu012_write,
+    tmu012_write
+};
+
+void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq,
+		 qemu_irq ch0_irq, qemu_irq ch1_irq,
+		 qemu_irq ch2_irq0, qemu_irq ch2_irq1)
+{
+    int iomemtype;
+    tmu012_state *s;
+    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
+
+    s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state));
+    s->feat = feat;
+    s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
+    s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
+    if (feat & TMU012_FEAT_3CHAN)
+        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
+				    ch2_irq0); /* ch2_irq1 not supported */
+    iomemtype = cpu_register_io_memory(tmu012_readfn,
+                                       tmu012_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(P4ADDR(base), 0x00001000, iomemtype);
+    cpu_register_physical_memory(A7ADDR(base), 0x00001000, iomemtype);
+    /* ??? Save/restore.  */
+}
diff --git a/qemu-0.15.x/hw/sharpsl.h b/qemu-0.15.x/hw/sharpsl.h
new file mode 100644
index 0000000..0b3a774
--- /dev/null
+++ b/qemu-0.15.x/hw/sharpsl.h
@@ -0,0 +1,17 @@
+/*
+ * Common declarations for the Zaurii.
+ *
+ * This file is licensed under the GNU GPL.
+ */
+#ifndef QEMU_SHARPSL_H
+#define QEMU_SHARPSL_H
+
+#define zaurus_printf(format, ...)	\
+    fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
+
+/* zaurus.c */
+
+#define SL_PXA_PARAM_BASE	0xa0000a00
+void sl_bootparam_write(target_phys_addr_t ptr);
+
+#endif
diff --git a/qemu-0.15.x/hw/shix.c b/qemu-0.15.x/hw/shix.c
new file mode 100644
index 0000000..638bf16
--- /dev/null
+++ b/qemu-0.15.x/hw/shix.c
@@ -0,0 +1,104 @@
+/*
+ * SHIX 2.0 board description
+ *
+ * Copyright (c) 2005 Samuel Tardieu
+ *
+ * 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.
+ */
+/*
+   Shix 2.0 board by Alexis Polti, described at
+   http://perso.enst.fr/~polti/realisations/shix20/
+
+   More information in target-sh4/README.sh4
+*/
+#include "hw.h"
+#include "pc.h"
+#include "sh.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+
+#define BIOS_FILENAME "shix_bios.bin"
+#define BIOS_ADDRESS 0xA0000000
+
+void irq_info(Monitor *mon)
+{
+    /* XXXXX */
+}
+
+void pic_info(Monitor *mon)
+{
+    /* XXXXX */
+}
+
+static void shix_init(ram_addr_t ram_size,
+               const char *boot_device,
+	       const char *kernel_filename, const char *kernel_cmdline,
+	       const char *initrd_filename, const char *cpu_model)
+{
+    int ret;
+    CPUState *env;
+    struct SH7750State *s;
+    
+    if (!cpu_model)
+        cpu_model = "any";
+
+    printf("Initializing CPU\n");
+    env = cpu_init(cpu_model);
+
+    /* Allocate memory space */
+    printf("Allocating ROM\n");
+    cpu_register_physical_memory(0x00000000, 0x00004000, IO_MEM_ROM);
+    printf("Allocating SDRAM 1\n");
+    cpu_register_physical_memory(0x08000000, 0x01000000, 0x00004000);
+    printf("Allocating SDRAM 2\n");
+    cpu_register_physical_memory(0x0c000000, 0x01000000, 0x01004000);
+
+    /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    printf("%s: load BIOS '%s'\n", __func__, bios_name);
+    ret = load_image_targphys(bios_name, 0, 0x4000);
+    if (ret < 0) {		/* Check bios size */
+	fprintf(stderr, "ret=%d\n", ret);
+	fprintf(stderr, "qemu: could not load SHIX bios '%s'\n",
+		bios_name);
+	exit(1);
+    }
+
+    /* Register peripherals */
+    s = sh7750_init(env);
+    /* XXXXX Check success */
+    tc58128_init(s, "shix_linux_nand.bin", NULL);
+    fprintf(stderr, "initialization terminated\n");
+}
+
+static QEMUMachine shix_machine = {
+    .name = "shix",
+    .desc = "shix card",
+    .init = shix_init,
+    .is_default = 1,
+};
+
+static void shix_machine_init(void)
+{
+    qemu_register_machine(&shix_machine);
+}
+
+machine_init(shix_machine_init);
diff --git a/qemu-0.15.x/hw/slavio_intctl.c b/qemu-0.15.x/hw/slavio_intctl.c
new file mode 100644
index 0000000..a83e5b8
--- /dev/null
+++ b/qemu-0.15.x/hw/slavio_intctl.c
@@ -0,0 +1,463 @@
+/*
+ * QEMU Sparc SLAVIO interrupt controller emulation
+ *
+ * Copyright (c) 2003-2005 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 "sun4m.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "trace.h"
+
+//#define DEBUG_IRQ_COUNT
+
+/*
+ * Registers of interrupt controller in sun4m.
+ *
+ * This is the interrupt controller part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * There is a system master controller and one for each cpu.
+ *
+ */
+
+#define MAX_CPUS 16
+#define MAX_PILS 16
+
+struct SLAVIO_INTCTLState;
+
+typedef struct SLAVIO_CPUINTCTLState {
+    uint32_t intreg_pending;
+    struct SLAVIO_INTCTLState *master;
+    uint32_t cpu;
+    uint32_t irl_out;
+} SLAVIO_CPUINTCTLState;
+
+typedef struct SLAVIO_INTCTLState {
+    SysBusDevice busdev;
+    uint32_t intregm_pending;
+    uint32_t intregm_disabled;
+    uint32_t target_cpu;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count[32];
+#endif
+    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
+    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
+} SLAVIO_INTCTLState;
+
+#define INTCTL_MAXADDR 0xf
+#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
+#define INTCTLM_SIZE 0x14
+#define MASTER_IRQ_MASK ~0x0fa2007f
+#define MASTER_DISABLE 0x80000000
+#define CPU_SOFTIRQ_MASK 0xfffe0000
+#define CPU_IRQ_INT15_IN (1 << 15)
+#define CPU_IRQ_TIMER_IN (1 << 14)
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
+
+// per-cpu interrupt controller
+static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intreg_pending;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
+                                     uint32_t val)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
+    switch (saddr) {
+    case 1: // clear pending softints
+        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
+        s->intreg_pending &= ~val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
+        break;
+    case 2: // set softint
+        val &= CPU_SOFTIRQ_MASK;
+        s->intreg_pending |= val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
+        break;
+    default:
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const slavio_intctl_mem_read[3] = {
+    NULL,
+    NULL,
+    slavio_intctl_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const slavio_intctl_mem_write[3] = {
+    NULL,
+    NULL,
+    slavio_intctl_mem_writel,
+};
+
+// master system interrupt controller
+static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intregm_pending & ~MASTER_DISABLE;
+        break;
+    case 1:
+        ret = s->intregm_disabled & MASTER_IRQ_MASK;
+        break;
+    case 4:
+        ret = s->target_cpu;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctlm_mem_readl(addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
+                                      uint32_t val)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctlm_mem_writel(addr, val);
+    switch (saddr) {
+    case 2: // clear (enable)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled &= ~val;
+        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
+        slavio_check_interrupts(s, 1);
+        break;
+    case 3: // set (disable; doesn't affect pending)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled |= val;
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
+        break;
+    case 4:
+        s->target_cpu = val & (MAX_CPUS - 1);
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
+        break;
+    default:
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const slavio_intctlm_mem_read[3] = {
+    NULL,
+    NULL,
+    slavio_intctlm_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const slavio_intctlm_mem_write[3] = {
+    NULL,
+    NULL,
+    slavio_intctlm_mem_writel,
+};
+
+void slavio_pic_info(Monitor *mon, DeviceState *dev)
+{
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+
+    sd = sysbus_from_qdev(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    for (i = 0; i < MAX_CPUS; i++) {
+        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
+                       s->slaves[i].intreg_pending);
+    }
+    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
+                   s->intregm_pending, s->intregm_disabled);
+}
+
+void slavio_irq_info(Monitor *mon, DeviceState *dev)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+    int64_t count;
+
+    sd = sysbus_from_qdev(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = s->irq_count[i];
+        if (count > 0)
+            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+    }
+#endif
+}
+
+static const uint32_t intbit_to_level[] = {
+    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
+    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
+};
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
+{
+    uint32_t pending = s->intregm_pending, pil_pending;
+    unsigned int i, j;
+
+    pending &= ~s->intregm_disabled;
+
+    trace_slavio_check_interrupts(pending, s->intregm_disabled);
+    for (i = 0; i < MAX_CPUS; i++) {
+        pil_pending = 0;
+
+        /* If we are the current interrupt target, get hard interrupts */
+        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
+            (i == s->target_cpu)) {
+            for (j = 0; j < 32; j++) {
+                if ((pending & (1 << j)) && intbit_to_level[j]) {
+                    pil_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Calculate current pending hard interrupts for display */
+        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
+            CPU_IRQ_TIMER_IN;
+        if (i == s->target_cpu) {
+            for (j = 0; j < 32; j++) {
+                if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
+                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Level 15 and CPU timer interrupts are only masked when
+           the MASTER_DISABLE bit is set */
+        if (!(s->intregm_disabled & MASTER_DISABLE)) {
+            pil_pending |= s->slaves[i].intreg_pending &
+                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
+        }
+
+        /* Add soft interrupts */
+        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
+
+        if (set_irqs) {
+            /* Since there is not really an interrupt 0 (and pil_pending
+             * and irl_out bit zero are thus always zero) there is no need
+             * to do anything with cpu_irqs[i][0] and it is OK not to do
+             * the j=0 iteration of this loop.
+             */
+            for (j = MAX_PILS-1; j > 0; j--) {
+                if (pil_pending & (1 << j)) {
+                    if (!(s->slaves[i].irl_out & (1 << j))) {
+                        qemu_irq_raise(s->cpu_irqs[i][j]);
+                    }
+                } else {
+                    if (s->slaves[i].irl_out & (1 << j)) {
+                        qemu_irq_lower(s->cpu_irqs[i][j]);
+                    }
+                }
+            }
+        }
+        s->slaves[i].irl_out = pil_pending;
+    }
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register to
+ * separate serial and keyboard interrupts sharing a level.
+ */
+static void slavio_set_irq(void *opaque, int irq, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+    unsigned int i;
+
+    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count[pil]++;
+#endif
+            s->intregm_pending |= mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending |= 1 << pil;
+                }
+            }
+        } else {
+            s->intregm_pending &= ~mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending &= ~(1 << pil);
+                }
+            }
+        }
+        slavio_check_interrupts(s, 1);
+    }
+}
+
+static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    trace_slavio_set_timer_irq_cpu(cpu, level);
+
+    if (level) {
+        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
+    } else {
+        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
+    }
+
+    slavio_check_interrupts(s, 1);
+}
+
+static void slavio_set_irq_all(void *opaque, int irq, int level)
+{
+    if (irq < 32) {
+        slavio_set_irq(opaque, irq, level);
+    } else {
+        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
+    }
+}
+
+static int vmstate_intctl_post_load(void *opaque, int version_id)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    slavio_check_interrupts(s, 0);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intctl_cpu = {
+    .name ="slavio_intctl_cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intctl = {
+    .name ="slavio_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_intctl_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
+                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
+        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_intctl_reset(DeviceState *d)
+{
+    SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->slaves[i].intreg_pending = 0;
+        s->slaves[i].irl_out = 0;
+    }
+    s->intregm_disabled = ~MASTER_IRQ_MASK;
+    s->intregm_pending = 0;
+    s->target_cpu = 0;
+    slavio_check_interrupts(s, 0);
+}
+
+static int slavio_intctl_init1(SysBusDevice *dev)
+{
+    SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
+    int io_memory;
+    unsigned int i, j;
+
+    qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
+    io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
+                                       slavio_intctlm_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        for (j = 0; j < MAX_PILS; j++) {
+            sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
+        }
+        io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
+                                           slavio_intctl_mem_write,
+                                           &s->slaves[i],
+                                           DEVICE_NATIVE_ENDIAN);
+        sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
+        s->slaves[i].cpu = i;
+        s->slaves[i].master = s;
+    }
+
+    return 0;
+}
+
+static SysBusDeviceInfo slavio_intctl_info = {
+    .init = slavio_intctl_init1,
+    .qdev.name  = "slavio_intctl",
+    .qdev.size  = sizeof(SLAVIO_INTCTLState),
+    .qdev.vmsd  = &vmstate_intctl,
+    .qdev.reset = slavio_intctl_reset,
+};
+
+static void slavio_intctl_register_devices(void)
+{
+    sysbus_register_withprop(&slavio_intctl_info);
+}
+
+device_init(slavio_intctl_register_devices)
diff --git a/qemu-0.15.x/hw/slavio_misc.c b/qemu-0.15.x/hw/slavio_misc.c
new file mode 100644
index 0000000..198360d
--- /dev/null
+++ b/qemu-0.15.x/hw/slavio_misc.c
@@ -0,0 +1,499 @@
+/*
+ * QEMU Sparc SLAVIO aux io port emulation
+ *
+ * Copyright (c) 2005 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 "sysemu.h"
+#include "sysbus.h"
+#include "trace.h"
+
+/*
+ * This is the auxio port, chip control and system control part of
+ * chip STP2001 (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * This also includes the PMC CPU idle controller.
+ */
+
+typedef struct MiscState {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t dummy;
+    uint8_t config;
+    uint8_t aux1, aux2;
+    uint8_t diag, mctrl;
+    uint8_t sysctrl;
+    uint16_t leds;
+    qemu_irq fdc_tc;
+} MiscState;
+
+typedef struct APCState {
+    SysBusDevice busdev;
+    qemu_irq cpu_halt;
+} APCState;
+
+#define MISC_SIZE 1
+#define SYSCTRL_SIZE 4
+
+#define AUX1_TC        0x02
+
+#define AUX2_PWROFF    0x01
+#define AUX2_PWRINTCLR 0x02
+#define AUX2_PWRFAIL   0x20
+
+#define CFG_PWRINTEN   0x08
+
+#define SYS_RESET      0x01
+#define SYS_RESETSTAT  0x02
+
+static void slavio_misc_update_irq(void *opaque)
+{
+    MiscState *s = opaque;
+
+    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
+        trace_slavio_misc_update_irq_raise();
+        qemu_irq_raise(s->irq);
+    } else {
+        trace_slavio_misc_update_irq_lower();
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void slavio_misc_reset(DeviceState *d)
+{
+    MiscState *s = container_of(d, MiscState, busdev.qdev);
+
+    // Diagnostic and system control registers not cleared in reset
+    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
+}
+
+static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_set_power_fail(power_failing, s->config);
+    if (power_failing && (s->config & CFG_PWRINTEN)) {
+        s->aux2 |= AUX2_PWRFAIL;
+    } else {
+        s->aux2 &= ~AUX2_PWRFAIL;
+    }
+    slavio_misc_update_irq(s);
+}
+
+static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_cfg_mem_writeb(val & 0xff);
+    s->config = val & 0xff;
+    slavio_misc_update_irq(s);
+}
+
+static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->config;
+    trace_slavio_cfg_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const slavio_cfg_mem_read[3] = {
+    slavio_cfg_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_cfg_mem_write[3] = {
+    slavio_cfg_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_diag_mem_writeb(val & 0xff);
+    s->diag = val & 0xff;
+}
+
+static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->diag;
+    trace_slavio_diag_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
+    slavio_diag_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
+    slavio_diag_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_mdm_mem_writeb(val & 0xff);
+    s->mctrl = val & 0xff;
+}
+
+static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->mctrl;
+    trace_slavio_mdm_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
+    slavio_mdm_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
+    slavio_mdm_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_aux1_mem_writeb(val & 0xff);
+    if (val & AUX1_TC) {
+        // Send a pulse to floppy terminal count line
+        if (s->fdc_tc) {
+            qemu_irq_raise(s->fdc_tc);
+            qemu_irq_lower(s->fdc_tc);
+        }
+        val &= ~AUX1_TC;
+    }
+    s->aux1 = val & 0xff;
+}
+
+static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->aux1;
+    trace_slavio_aux1_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
+    slavio_aux1_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
+    slavio_aux1_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    MiscState *s = opaque;
+
+    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
+    trace_slavio_aux2_mem_writeb(val & 0xff);
+    val |= s->aux2 & AUX2_PWRFAIL;
+    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
+        val &= AUX2_PWROFF;
+    s->aux2 = val;
+    if (val & AUX2_PWROFF)
+        qemu_system_shutdown_request();
+    slavio_misc_update_irq(s);
+}
+
+static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->aux2;
+    trace_slavio_aux2_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
+    slavio_aux2_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
+    slavio_aux2_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    APCState *s = opaque;
+
+    trace_apc_mem_writeb(val & 0xff);
+    qemu_irq_raise(s->cpu_halt);
+}
+
+static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret = 0;
+
+    trace_apc_mem_readb(ret);
+    return ret;
+}
+
+static CPUReadMemoryFunc * const apc_mem_read[3] = {
+    apc_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const apc_mem_write[3] = {
+    apc_mem_writeb,
+    NULL,
+    NULL,
+};
+
+static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case 0:
+        ret = s->sysctrl;
+        break;
+    default:
+        break;
+    }
+    trace_slavio_sysctrl_mem_readl(ret);
+    return ret;
+}
+
+static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
+                                      uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_sysctrl_mem_writel(val);
+    switch (addr) {
+    case 0:
+        if (val & SYS_RESET) {
+            s->sysctrl = SYS_RESETSTAT;
+            qemu_system_reset_request();
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
+    NULL,
+    NULL,
+    slavio_sysctrl_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
+    NULL,
+    NULL,
+    slavio_sysctrl_mem_writel,
+};
+
+static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case 0:
+        ret = s->leds;
+        break;
+    default:
+        break;
+    }
+    trace_slavio_led_mem_readw(ret);
+    return ret;
+}
+
+static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_led_mem_readw(val & 0xffff);
+    switch (addr) {
+    case 0:
+        s->leds = val;
+        break;
+    default:
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
+    NULL,
+    slavio_led_mem_readw,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
+    NULL,
+    slavio_led_mem_writew,
+    NULL,
+};
+
+static const VMStateDescription vmstate_misc = {
+    .name ="slavio_misc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(dummy, MiscState),
+        VMSTATE_UINT8(config, MiscState),
+        VMSTATE_UINT8(aux1, MiscState),
+        VMSTATE_UINT8(aux2, MiscState),
+        VMSTATE_UINT8(diag, MiscState),
+        VMSTATE_UINT8(mctrl, MiscState),
+        VMSTATE_UINT8(sysctrl, MiscState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int apc_init1(SysBusDevice *dev)
+{
+    APCState *s = FROM_SYSBUS(APCState, dev);
+    int io;
+
+    sysbus_init_irq(dev, &s->cpu_halt);
+
+    /* Power management (APC) XXX: not a Slavio device */
+    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+    return 0;
+}
+
+static int slavio_misc_init1(SysBusDevice *dev)
+{
+    MiscState *s = FROM_SYSBUS(MiscState, dev);
+    int io;
+
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fdc_tc);
+
+    /* 8 bit registers */
+    /* Slavio control */
+    io = cpu_register_io_memory(slavio_cfg_mem_read,
+                                slavio_cfg_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    /* Diagnostics */
+    io = cpu_register_io_memory(slavio_diag_mem_read,
+                                slavio_diag_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    /* Modem control */
+    io = cpu_register_io_memory(slavio_mdm_mem_read,
+                                slavio_mdm_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    /* 16 bit registers */
+    /* ss600mp diag LEDs */
+    io = cpu_register_io_memory(slavio_led_mem_read,
+                                slavio_led_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    /* 32 bit registers */
+    /* System control */
+    io = cpu_register_io_memory(slavio_sysctrl_mem_read,
+                                slavio_sysctrl_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
+
+    /* AUX 1 (Misc System Functions) */
+    io = cpu_register_io_memory(slavio_aux1_mem_read,
+                                slavio_aux1_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    /* AUX 2 (Software Powerdown Control) */
+    io = cpu_register_io_memory(slavio_aux2_mem_read,
+                                slavio_aux2_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MISC_SIZE, io);
+
+    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
+
+    return 0;
+}
+
+static SysBusDeviceInfo slavio_misc_info = {
+    .init = slavio_misc_init1,
+    .qdev.name  = "slavio_misc",
+    .qdev.size  = sizeof(MiscState),
+    .qdev.vmsd  = &vmstate_misc,
+    .qdev.reset  = slavio_misc_reset,
+};
+
+static SysBusDeviceInfo apc_info = {
+    .init = apc_init1,
+    .qdev.name  = "apc",
+    .qdev.size  = sizeof(MiscState),
+};
+
+static void slavio_misc_register_devices(void)
+{
+    sysbus_register_withprop(&slavio_misc_info);
+    sysbus_register_withprop(&apc_info);
+}
+
+device_init(slavio_misc_register_devices)
diff --git a/qemu-0.15.x/hw/slavio_timer.c b/qemu-0.15.x/hw/slavio_timer.c
new file mode 100644
index 0000000..5511313
--- /dev/null
+++ b/qemu-0.15.x/hw/slavio_timer.c
@@ -0,0 +1,424 @@
+/*
+ * QEMU Sparc SLAVIO timer controller emulation
+ *
+ * Copyright (c) 2003-2005 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 "sun4m.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+#include "trace.h"
+
+/*
+ * Registers of hardware timer in sun4m.
+ *
+ * This is the timer/counter part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
+ * are zero. Bit 31 is 1 when count has been reached.
+ *
+ * Per-CPU timers interrupt local CPU, system timer uses normal
+ * interrupt routing.
+ *
+ */
+
+#define MAX_CPUS 16
+
+typedef struct CPUTimerState {
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint32_t count, counthigh, reached;
+    uint64_t limit;
+    // processor only
+    uint32_t running;
+} CPUTimerState;
+
+typedef struct SLAVIO_TIMERState {
+    SysBusDevice busdev;
+    uint32_t num_cpus;
+    CPUTimerState cputimer[MAX_CPUS + 1];
+    uint32_t cputimer_mode;
+} SLAVIO_TIMERState;
+
+typedef struct TimerContext {
+    SLAVIO_TIMERState *s;
+    unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
+} TimerContext;
+
+#define SYS_TIMER_SIZE 0x14
+#define CPU_TIMER_SIZE 0x10
+
+#define TIMER_LIMIT         0
+#define TIMER_COUNTER       1
+#define TIMER_COUNTER_NORST 2
+#define TIMER_STATUS        3
+#define TIMER_MODE          4
+
+#define TIMER_COUNT_MASK32 0xfffffe00
+#define TIMER_LIMIT_MASK32 0x7fffffff
+#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
+#define TIMER_MAX_COUNT32  0x7ffffe00ULL
+#define TIMER_REACHED      0x80000000
+#define TIMER_PERIOD       500ULL // 500ns
+#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
+#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
+
+static int slavio_timer_is_user(TimerContext *tc)
+{
+    SLAVIO_TIMERState *s = tc->s;
+    unsigned int timer_index = tc->timer_index;
+
+    return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
+}
+
+// Update count, set irq, update expire_time
+// Convert from ptimer countdown units
+static void slavio_timer_get_out(CPUTimerState *t)
+{
+    uint64_t count, limit;
+
+    if (t->limit == 0) { /* free-run system or processor counter */
+        limit = TIMER_MAX_COUNT32;
+    } else {
+        limit = t->limit;
+    }
+    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
+
+    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
+    t->count = count & TIMER_COUNT_MASK32;
+    t->counthigh = count >> 32;
+}
+
+// timer callback
+static void slavio_timer_irq(void *opaque)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    CPUTimerState *t = &s->cputimer[tc->timer_index];
+
+    slavio_timer_get_out(t);
+    trace_slavio_timer_irq(t->counthigh, t->count);
+    /* if limit is 0 (free-run), there will be no match */
+    if (t->limit != 0) {
+        t->reached = TIMER_REACHED;
+    }
+    /* there is no interrupt if user timer or free-run */
+    if (!slavio_timer_is_user(tc) && t->limit != 0) {
+        qemu_irq_raise(t->irq);
+    }
+}
+
+static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr, ret;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        // read limit (system counter mode) or read most signifying
+        // part of counter (user mode)
+        if (slavio_timer_is_user(tc)) {
+            // read user timer MSW
+            slavio_timer_get_out(t);
+            ret = t->counthigh | t->reached;
+        } else {
+            // read limit
+            // clear irq
+            qemu_irq_lower(t->irq);
+            t->reached = 0;
+            ret = t->limit & TIMER_LIMIT_MASK32;
+        }
+        break;
+    case TIMER_COUNTER:
+        // read counter and reached bit (system mode) or read lsbits
+        // of counter (user mode)
+        slavio_timer_get_out(t);
+        if (slavio_timer_is_user(tc)) { // read user timer LSW
+            ret = t->count & TIMER_MAX_COUNT64;
+        } else { // read limit
+            ret = (t->count & TIMER_MAX_COUNT32) |
+                t->reached;
+        }
+        break;
+    case TIMER_STATUS:
+        // only available in processor counter/timer
+        // read start/stop status
+        if (timer_index > 0) {
+            ret = t->running;
+        } else {
+            ret = 0;
+        }
+        break;
+    case TIMER_MODE:
+        // only available in system counter
+        // read user/system mode
+        ret = s->cputimer_mode;
+        break;
+    default:
+        trace_slavio_timer_mem_readl_invalid(addr);
+        ret = 0;
+        break;
+    }
+    trace_slavio_timer_mem_readl(addr, ret);
+    return ret;
+}
+
+static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
+                                    uint32_t val)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    trace_slavio_timer_mem_writel(addr, val);
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter MSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh << 32) | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            // set limit, reset counter
+            qemu_irq_lower(t->irq);
+            t->limit = val & TIMER_MAX_COUNT32;
+            if (t->timer) {
+                if (t->limit == 0) { /* free-run */
+                    ptimer_set_limit(t->timer,
+                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+                } else {
+                    ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
+                }
+            }
+        }
+        break;
+    case TIMER_COUNTER:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter LSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->count = val & TIMER_MAX_COUNT64;
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh) << 32 | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            trace_slavio_timer_mem_writel_counter_invalid();
+        }
+        break;
+    case TIMER_COUNTER_NORST:
+        // set limit without resetting counter
+        t->limit = val & TIMER_MAX_COUNT32;
+        if (t->limit == 0) { /* free-run */
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
+        } else {
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
+        }
+        break;
+    case TIMER_STATUS:
+        if (slavio_timer_is_user(tc)) {
+            // start/stop user counter
+            if ((val & 1) && !t->running) {
+                trace_slavio_timer_mem_writel_status_start(timer_index);
+                ptimer_run(t->timer, 0);
+                t->running = 1;
+            } else if (!(val & 1) && t->running) {
+                trace_slavio_timer_mem_writel_status_stop(timer_index);
+                ptimer_stop(t->timer);
+                t->running = 0;
+            }
+        }
+        break;
+    case TIMER_MODE:
+        if (timer_index == 0) {
+            unsigned int i;
+
+            for (i = 0; i < s->num_cpus; i++) {
+                unsigned int processor = 1 << i;
+                CPUTimerState *curr_timer = &s->cputimer[i + 1];
+
+                // check for a change in timer mode for this processor
+                if ((val & processor) != (s->cputimer_mode & processor)) {
+                    if (val & processor) { // counter -> user timer
+                        qemu_irq_lower(curr_timer->irq);
+                        // counters are always running
+                        ptimer_stop(curr_timer->timer);
+                        curr_timer->running = 0;
+                        // user timer limit is always the same
+                        curr_timer->limit = TIMER_MAX_COUNT64;
+                        ptimer_set_limit(curr_timer->timer,
+                                         LIMIT_TO_PERIODS(curr_timer->limit),
+                                         1);
+                        // set this processors user timer bit in config
+                        // register
+                        s->cputimer_mode |= processor;
+                        trace_slavio_timer_mem_writel_mode_user(timer_index);
+                    } else { // user timer -> counter
+                        // stop the user timer if it is running
+                        if (curr_timer->running) {
+                            ptimer_stop(curr_timer->timer);
+                        }
+                        // start the counter
+                        ptimer_run(curr_timer->timer, 0);
+                        curr_timer->running = 1;
+                        // clear this processors user timer bit in config
+                        // register
+                        s->cputimer_mode &= ~processor;
+                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
+                    }
+                }
+            }
+        } else {
+            trace_slavio_timer_mem_writel_mode_invalid();
+        }
+        break;
+    default:
+        trace_slavio_timer_mem_writel_invalid(addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const slavio_timer_mem_read[3] = {
+    NULL,
+    NULL,
+    slavio_timer_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const slavio_timer_mem_write[3] = {
+    NULL,
+    NULL,
+    slavio_timer_mem_writel,
+};
+
+static const VMStateDescription vmstate_timer = {
+    .name ="timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(limit, CPUTimerState),
+        VMSTATE_UINT32(count, CPUTimerState),
+        VMSTATE_UINT32(counthigh, CPUTimerState),
+        VMSTATE_UINT32(reached, CPUTimerState),
+        VMSTATE_UINT32(running, CPUTimerState),
+        VMSTATE_PTIMER(timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slavio_timer = {
+    .name ="slavio_timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
+                             vmstate_timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_timer_reset(DeviceState *d)
+{
+    SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
+    unsigned int i;
+    CPUTimerState *curr_timer;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        curr_timer = &s->cputimer[i];
+        curr_timer->limit = 0;
+        curr_timer->count = 0;
+        curr_timer->reached = 0;
+        if (i <= s->num_cpus) {
+            ptimer_set_limit(curr_timer->timer,
+                             LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+            ptimer_run(curr_timer->timer, 0);
+            curr_timer->running = 1;
+        }
+    }
+    s->cputimer_mode = 0;
+}
+
+static int slavio_timer_init1(SysBusDevice *dev)
+{
+    int io;
+    SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
+    QEMUBH *bh;
+    unsigned int i;
+    TimerContext *tc;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        tc = qemu_mallocz(sizeof(TimerContext));
+        tc->s = s;
+        tc->timer_index = i;
+
+        bh = qemu_bh_new(slavio_timer_irq, tc);
+        s->cputimer[i].timer = ptimer_init(bh);
+        ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
+
+        io = cpu_register_io_memory(slavio_timer_mem_read,
+                                    slavio_timer_mem_write, tc,
+                                    DEVICE_NATIVE_ENDIAN);
+        if (i == 0) {
+            sysbus_init_mmio(dev, SYS_TIMER_SIZE, io);
+        } else {
+            sysbus_init_mmio(dev, CPU_TIMER_SIZE, io);
+        }
+
+        sysbus_init_irq(dev, &s->cputimer[i].irq);
+    }
+
+    return 0;
+}
+
+static SysBusDeviceInfo slavio_timer_info = {
+    .init = slavio_timer_init1,
+    .qdev.name  = "slavio_timer",
+    .qdev.size  = sizeof(SLAVIO_TIMERState),
+    .qdev.vmsd  = &vmstate_slavio_timer,
+    .qdev.reset = slavio_timer_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void slavio_timer_register_devices(void)
+{
+    sysbus_register_withprop(&slavio_timer_info);
+}
+
+device_init(slavio_timer_register_devices)
diff --git a/qemu-0.15.x/hw/sm501.c b/qemu-0.15.x/hw/sm501.c
new file mode 100644
index 0000000..0f0bf96
--- /dev/null
+++ b/qemu-0.15.x/hw/sm501.c
@@ -0,0 +1,1457 @@
+/*
+ * QEMU SM501 Device
+ *
+ * Copyright (c) 2008 Shin-ichiro KAWASAKI
+ *
+ * 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 <stdio.h>
+#include "hw.h"
+#include "pc.h"
+#include "console.h"
+#include "devices.h"
+#include "sysbus.h"
+#include "qdev-addr.h"
+#include "range.h"
+
+/*
+ * Status: 2010/05/07
+ *   - Minimum implementation for Linux console : mmio regs and CRT layer.
+ *   - 2D grapihcs acceleration partially supported : only fill rectangle.
+ *
+ * TODO:
+ *   - Panel support
+ *   - Touch panel support
+ *   - USB support
+ *   - UART support
+ *   - More 2D graphics engine support
+ *   - Performance tuning
+ */
+
+//#define DEBUG_SM501
+//#define DEBUG_BITBLT
+
+#ifdef DEBUG_SM501
+#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define SM501_DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+
+#define MMIO_BASE_OFFSET 0x3e00000
+
+/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
+
+/* System Configuration area */
+/* System config base */
+#define SM501_SYS_CONFIG		(0x000000)
+
+/* config 1 */
+#define SM501_SYSTEM_CONTROL 		(0x000000)
+
+#define SM501_SYSCTRL_PANEL_TRISTATE	(1<<0)
+#define SM501_SYSCTRL_MEM_TRISTATE	(1<<1)
+#define SM501_SYSCTRL_CRT_TRISTATE	(1<<2)
+
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_1	(0<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_2	(1<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_4	(2<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_8	(3<<4)
+
+#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN	(1<<6)
+#define SM501_SYSCTRL_PCI_RETRY_DISABLE	(1<<7)
+#define SM501_SYSCTRL_PCI_SUBSYS_LOCK	(1<<11)
+#define SM501_SYSCTRL_PCI_BURST_READ_EN	(1<<15)
+
+/* miscellaneous control */
+
+#define SM501_MISC_CONTROL		(0x000004)
+
+#define SM501_MISC_BUS_SH		(0x0)
+#define SM501_MISC_BUS_PCI		(0x1)
+#define SM501_MISC_BUS_XSCALE		(0x2)
+#define SM501_MISC_BUS_NEC		(0x6)
+#define SM501_MISC_BUS_MASK		(0x7)
+
+#define SM501_MISC_VR_62MB		(1<<3)
+#define SM501_MISC_CDR_RESET		(1<<7)
+#define SM501_MISC_USB_LB		(1<<8)
+#define SM501_MISC_USB_SLAVE		(1<<9)
+#define SM501_MISC_BL_1			(1<<10)
+#define SM501_MISC_MC			(1<<11)
+#define SM501_MISC_DAC_POWER		(1<<12)
+#define SM501_MISC_IRQ_INVERT		(1<<16)
+#define SM501_MISC_SH			(1<<17)
+
+#define SM501_MISC_HOLD_EMPTY		(0<<18)
+#define SM501_MISC_HOLD_8		(1<<18)
+#define SM501_MISC_HOLD_16		(2<<18)
+#define SM501_MISC_HOLD_24		(3<<18)
+#define SM501_MISC_HOLD_32		(4<<18)
+#define SM501_MISC_HOLD_MASK		(7<<18)
+
+#define SM501_MISC_FREQ_12		(1<<24)
+#define SM501_MISC_PNL_24BIT		(1<<25)
+#define SM501_MISC_8051_LE		(1<<26)
+
+
+
+#define SM501_GPIO31_0_CONTROL		(0x000008)
+#define SM501_GPIO63_32_CONTROL		(0x00000C)
+#define SM501_DRAM_CONTROL		(0x000010)
+
+/* command list */
+#define SM501_ARBTRTN_CONTROL		(0x000014)
+
+/* command list */
+#define SM501_COMMAND_LIST_STATUS	(0x000024)
+
+/* interrupt debug */
+#define SM501_RAW_IRQ_STATUS		(0x000028)
+#define SM501_RAW_IRQ_CLEAR		(0x000028)
+#define SM501_IRQ_STATUS		(0x00002C)
+#define SM501_IRQ_MASK			(0x000030)
+#define SM501_DEBUG_CONTROL		(0x000034)
+
+/* power management */
+#define SM501_POWERMODE_P2X_SRC		(1<<29)
+#define SM501_POWERMODE_V2X_SRC		(1<<20)
+#define SM501_POWERMODE_M_SRC		(1<<12)
+#define SM501_POWERMODE_M1_SRC		(1<<4)
+
+#define SM501_CURRENT_GATE		(0x000038)
+#define SM501_CURRENT_CLOCK		(0x00003C)
+#define SM501_POWER_MODE_0_GATE		(0x000040)
+#define SM501_POWER_MODE_0_CLOCK	(0x000044)
+#define SM501_POWER_MODE_1_GATE		(0x000048)
+#define SM501_POWER_MODE_1_CLOCK	(0x00004C)
+#define SM501_SLEEP_MODE_GATE		(0x000050)
+#define SM501_POWER_MODE_CONTROL	(0x000054)
+
+/* power gates for units within the 501 */
+#define SM501_GATE_HOST			(0)
+#define SM501_GATE_MEMORY		(1)
+#define SM501_GATE_DISPLAY		(2)
+#define SM501_GATE_2D_ENGINE		(3)
+#define SM501_GATE_CSC			(4)
+#define SM501_GATE_ZVPORT		(5)
+#define SM501_GATE_GPIO			(6)
+#define SM501_GATE_UART0		(7)
+#define SM501_GATE_UART1		(8)
+#define SM501_GATE_SSP			(10)
+#define SM501_GATE_USB_HOST		(11)
+#define SM501_GATE_USB_GADGET		(12)
+#define SM501_GATE_UCONTROLLER		(17)
+#define SM501_GATE_AC97			(18)
+
+/* panel clock */
+#define SM501_CLOCK_P2XCLK		(24)
+/* crt clock */
+#define SM501_CLOCK_V2XCLK		(16)
+/* main clock */
+#define SM501_CLOCK_MCLK		(8)
+/* SDRAM controller clock */
+#define SM501_CLOCK_M1XCLK		(0)
+
+/* config 2 */
+#define SM501_PCI_MASTER_BASE		(0x000058)
+#define SM501_ENDIAN_CONTROL		(0x00005C)
+#define SM501_DEVICEID			(0x000060)
+/* 0x050100A0 */
+
+#define SM501_DEVICEID_SM501		(0x05010000)
+#define SM501_DEVICEID_IDMASK		(0xffff0000)
+#define SM501_DEVICEID_REVMASK		(0x000000ff)
+
+#define SM501_PLLCLOCK_COUNT		(0x000064)
+#define SM501_MISC_TIMING		(0x000068)
+#define SM501_CURRENT_SDRAM_CLOCK	(0x00006C)
+
+#define SM501_PROGRAMMABLE_PLL_CONTROL	(0x000074)
+
+/* GPIO base */
+#define SM501_GPIO			(0x010000)
+#define SM501_GPIO_DATA_LOW		(0x00)
+#define SM501_GPIO_DATA_HIGH		(0x04)
+#define SM501_GPIO_DDR_LOW		(0x08)
+#define SM501_GPIO_DDR_HIGH		(0x0C)
+#define SM501_GPIO_IRQ_SETUP		(0x10)
+#define SM501_GPIO_IRQ_STATUS		(0x14)
+#define SM501_GPIO_IRQ_RESET		(0x14)
+
+/* I2C controller base */
+#define SM501_I2C			(0x010040)
+#define SM501_I2C_BYTE_COUNT		(0x00)
+#define SM501_I2C_CONTROL		(0x01)
+#define SM501_I2C_STATUS		(0x02)
+#define SM501_I2C_RESET			(0x02)
+#define SM501_I2C_SLAVE_ADDRESS		(0x03)
+#define SM501_I2C_DATA			(0x04)
+
+/* SSP base */
+#define SM501_SSP			(0x020000)
+
+/* Uart 0 base */
+#define SM501_UART0			(0x030000)
+
+/* Uart 1 base */
+#define SM501_UART1			(0x030020)
+
+/* USB host port base */
+#define SM501_USB_HOST			(0x040000)
+
+/* USB slave/gadget base */
+#define SM501_USB_GADGET		(0x060000)
+
+/* USB slave/gadget data port base */
+#define SM501_USB_GADGET_DATA		(0x070000)
+
+/* Display controller/video engine base */
+#define SM501_DC			(0x080000)
+
+/* common defines for the SM501 address registers */
+#define SM501_ADDR_FLIP			(1<<31)
+#define SM501_ADDR_EXT			(1<<27)
+#define SM501_ADDR_CS1			(1<<26)
+#define SM501_ADDR_MASK			(0x3f << 26)
+
+#define SM501_FIFO_MASK			(0x3 << 16)
+#define SM501_FIFO_1			(0x0 << 16)
+#define SM501_FIFO_3			(0x1 << 16)
+#define SM501_FIFO_7			(0x2 << 16)
+#define SM501_FIFO_11			(0x3 << 16)
+
+/* common registers for panel and the crt */
+#define SM501_OFF_DC_H_TOT		(0x000)
+#define SM501_OFF_DC_V_TOT		(0x008)
+#define SM501_OFF_DC_H_SYNC		(0x004)
+#define SM501_OFF_DC_V_SYNC		(0x00C)
+
+#define SM501_DC_PANEL_CONTROL		(0x000)
+
+#define SM501_DC_PANEL_CONTROL_FPEN	(1<<27)
+#define SM501_DC_PANEL_CONTROL_BIAS	(1<<26)
+#define SM501_DC_PANEL_CONTROL_DATA	(1<<25)
+#define SM501_DC_PANEL_CONTROL_VDD	(1<<24)
+#define SM501_DC_PANEL_CONTROL_DP	(1<<23)
+
+#define SM501_DC_PANEL_CONTROL_TFT_888	(0<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_333	(1<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_444	(2<<21)
+
+#define SM501_DC_PANEL_CONTROL_DE	(1<<20)
+
+#define SM501_DC_PANEL_CONTROL_LCD_TFT	(0<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN8	(1<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
+
+#define SM501_DC_PANEL_CONTROL_CP	(1<<14)
+#define SM501_DC_PANEL_CONTROL_VSP	(1<<13)
+#define SM501_DC_PANEL_CONTROL_HSP	(1<<12)
+#define SM501_DC_PANEL_CONTROL_CK	(1<<9)
+#define SM501_DC_PANEL_CONTROL_TE	(1<<8)
+#define SM501_DC_PANEL_CONTROL_VPD	(1<<7)
+#define SM501_DC_PANEL_CONTROL_VP	(1<<6)
+#define SM501_DC_PANEL_CONTROL_HPD	(1<<5)
+#define SM501_DC_PANEL_CONTROL_HP	(1<<4)
+#define SM501_DC_PANEL_CONTROL_GAMMA	(1<<3)
+#define SM501_DC_PANEL_CONTROL_EN	(1<<2)
+
+#define SM501_DC_PANEL_CONTROL_8BPP	(0<<0)
+#define SM501_DC_PANEL_CONTROL_16BPP	(1<<0)
+#define SM501_DC_PANEL_CONTROL_32BPP	(2<<0)
+
+
+#define SM501_DC_PANEL_PANNING_CONTROL	(0x004)
+#define SM501_DC_PANEL_COLOR_KEY	(0x008)
+#define SM501_DC_PANEL_FB_ADDR		(0x00C)
+#define SM501_DC_PANEL_FB_OFFSET	(0x010)
+#define SM501_DC_PANEL_FB_WIDTH		(0x014)
+#define SM501_DC_PANEL_FB_HEIGHT	(0x018)
+#define SM501_DC_PANEL_TL_LOC		(0x01C)
+#define SM501_DC_PANEL_BR_LOC		(0x020)
+#define SM501_DC_PANEL_H_TOT		(0x024)
+#define SM501_DC_PANEL_H_SYNC		(0x028)
+#define SM501_DC_PANEL_V_TOT		(0x02C)
+#define SM501_DC_PANEL_V_SYNC		(0x030)
+#define SM501_DC_PANEL_CUR_LINE		(0x034)
+
+#define SM501_DC_VIDEO_CONTROL		(0x040)
+#define SM501_DC_VIDEO_FB0_ADDR		(0x044)
+#define SM501_DC_VIDEO_FB_WIDTH		(0x048)
+#define SM501_DC_VIDEO_FB0_LAST_ADDR	(0x04C)
+#define SM501_DC_VIDEO_TL_LOC		(0x050)
+#define SM501_DC_VIDEO_BR_LOC		(0x054)
+#define SM501_DC_VIDEO_SCALE		(0x058)
+#define SM501_DC_VIDEO_INIT_SCALE	(0x05C)
+#define SM501_DC_VIDEO_YUV_CONSTANTS	(0x060)
+#define SM501_DC_VIDEO_FB1_ADDR		(0x064)
+#define SM501_DC_VIDEO_FB1_LAST_ADDR	(0x068)
+
+#define SM501_DC_VIDEO_ALPHA_CONTROL	(0x080)
+#define SM501_DC_VIDEO_ALPHA_FB_ADDR	(0x084)
+#define SM501_DC_VIDEO_ALPHA_FB_OFFSET	(0x088)
+#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR	(0x08C)
+#define SM501_DC_VIDEO_ALPHA_TL_LOC	(0x090)
+#define SM501_DC_VIDEO_ALPHA_BR_LOC	(0x094)
+#define SM501_DC_VIDEO_ALPHA_SCALE	(0x098)
+#define SM501_DC_VIDEO_ALPHA_INIT_SCALE	(0x09C)
+#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY	(0x0A0)
+#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP	(0x0A4)
+
+#define SM501_DC_PANEL_HWC_BASE		(0x0F0)
+#define SM501_DC_PANEL_HWC_ADDR		(0x0F0)
+#define SM501_DC_PANEL_HWC_LOC		(0x0F4)
+#define SM501_DC_PANEL_HWC_COLOR_1_2	(0x0F8)
+#define SM501_DC_PANEL_HWC_COLOR_3	(0x0FC)
+
+#define SM501_HWC_EN			(1<<31)
+
+#define SM501_OFF_HWC_ADDR		(0x00)
+#define SM501_OFF_HWC_LOC		(0x04)
+#define SM501_OFF_HWC_COLOR_1_2		(0x08)
+#define SM501_OFF_HWC_COLOR_3		(0x0C)
+
+#define SM501_DC_ALPHA_CONTROL		(0x100)
+#define SM501_DC_ALPHA_FB_ADDR		(0x104)
+#define SM501_DC_ALPHA_FB_OFFSET	(0x108)
+#define SM501_DC_ALPHA_TL_LOC		(0x10C)
+#define SM501_DC_ALPHA_BR_LOC		(0x110)
+#define SM501_DC_ALPHA_CHROMA_KEY	(0x114)
+#define SM501_DC_ALPHA_COLOR_LOOKUP	(0x118)
+
+#define SM501_DC_CRT_CONTROL		(0x200)
+
+#define SM501_DC_CRT_CONTROL_TVP	(1<<15)
+#define SM501_DC_CRT_CONTROL_CP		(1<<14)
+#define SM501_DC_CRT_CONTROL_VSP	(1<<13)
+#define SM501_DC_CRT_CONTROL_HSP	(1<<12)
+#define SM501_DC_CRT_CONTROL_VS		(1<<11)
+#define SM501_DC_CRT_CONTROL_BLANK	(1<<10)
+#define SM501_DC_CRT_CONTROL_SEL	(1<<9)
+#define SM501_DC_CRT_CONTROL_TE		(1<<8)
+#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
+#define SM501_DC_CRT_CONTROL_GAMMA	(1<<3)
+#define SM501_DC_CRT_CONTROL_ENABLE	(1<<2)
+
+#define SM501_DC_CRT_CONTROL_8BPP	(0<<0)
+#define SM501_DC_CRT_CONTROL_16BPP	(1<<0)
+#define SM501_DC_CRT_CONTROL_32BPP	(2<<0)
+
+#define SM501_DC_CRT_FB_ADDR		(0x204)
+#define SM501_DC_CRT_FB_OFFSET		(0x208)
+#define SM501_DC_CRT_H_TOT		(0x20C)
+#define SM501_DC_CRT_H_SYNC		(0x210)
+#define SM501_DC_CRT_V_TOT		(0x214)
+#define SM501_DC_CRT_V_SYNC		(0x218)
+#define SM501_DC_CRT_SIGNATURE_ANALYZER	(0x21C)
+#define SM501_DC_CRT_CUR_LINE		(0x220)
+#define SM501_DC_CRT_MONITOR_DETECT	(0x224)
+
+#define SM501_DC_CRT_HWC_BASE		(0x230)
+#define SM501_DC_CRT_HWC_ADDR		(0x230)
+#define SM501_DC_CRT_HWC_LOC		(0x234)
+#define SM501_DC_CRT_HWC_COLOR_1_2	(0x238)
+#define SM501_DC_CRT_HWC_COLOR_3	(0x23C)
+
+#define SM501_DC_PANEL_PALETTE		(0x400)
+
+#define SM501_DC_VIDEO_PALETTE		(0x800)
+
+#define SM501_DC_CRT_PALETTE		(0xC00)
+
+/* Zoom Video port base */
+#define SM501_ZVPORT			(0x090000)
+
+/* AC97/I2S base */
+#define SM501_AC97			(0x0A0000)
+
+/* 8051 micro controller base */
+#define SM501_UCONTROLLER		(0x0B0000)
+
+/* 8051 micro controller SRAM base */
+#define SM501_UCONTROLLER_SRAM		(0x0C0000)
+
+/* DMA base */
+#define SM501_DMA			(0x0D0000)
+
+/* 2d engine base */
+#define SM501_2D_ENGINE			(0x100000)
+#define SM501_2D_SOURCE			(0x00)
+#define SM501_2D_DESTINATION		(0x04)
+#define SM501_2D_DIMENSION		(0x08)
+#define SM501_2D_CONTROL		(0x0C)
+#define SM501_2D_PITCH			(0x10)
+#define SM501_2D_FOREGROUND		(0x14)
+#define SM501_2D_BACKGROUND		(0x18)
+#define SM501_2D_STRETCH		(0x1C)
+#define SM501_2D_COLOR_COMPARE		(0x20)
+#define SM501_2D_COLOR_COMPARE_MASK 	(0x24)
+#define SM501_2D_MASK			(0x28)
+#define SM501_2D_CLIP_TL		(0x2C)
+#define SM501_2D_CLIP_BR		(0x30)
+#define SM501_2D_MONO_PATTERN_LOW	(0x34)
+#define SM501_2D_MONO_PATTERN_HIGH	(0x38)
+#define SM501_2D_WINDOW_WIDTH		(0x3C)
+#define SM501_2D_SOURCE_BASE		(0x40)
+#define SM501_2D_DESTINATION_BASE	(0x44)
+#define SM501_2D_ALPHA			(0x48)
+#define SM501_2D_WRAP			(0x4C)
+#define SM501_2D_STATUS			(0x50)
+
+#define SM501_CSC_Y_SOURCE_BASE		(0xC8)
+#define SM501_CSC_CONSTANTS		(0xCC)
+#define SM501_CSC_Y_SOURCE_X		(0xD0)
+#define SM501_CSC_Y_SOURCE_Y		(0xD4)
+#define SM501_CSC_U_SOURCE_BASE		(0xD8)
+#define SM501_CSC_V_SOURCE_BASE		(0xDC)
+#define SM501_CSC_SOURCE_DIMENSION	(0xE0)
+#define SM501_CSC_SOURCE_PITCH		(0xE4)
+#define SM501_CSC_DESTINATION		(0xE8)
+#define SM501_CSC_DESTINATION_DIMENSION	(0xEC)
+#define SM501_CSC_DESTINATION_PITCH	(0xF0)
+#define SM501_CSC_SCALE_FACTOR		(0xF4)
+#define SM501_CSC_DESTINATION_BASE	(0xF8)
+#define SM501_CSC_CONTROL		(0xFC)
+
+/* 2d engine data port base */
+#define SM501_2D_ENGINE_DATA		(0x110000)
+
+/* end of register definitions */
+
+#define SM501_HWC_WIDTH                       (64)
+#define SM501_HWC_HEIGHT                      (64)
+
+/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
+static const uint32_t sm501_mem_local_size[] = {
+	[0]	= 4*1024*1024,
+	[1]	= 8*1024*1024,
+	[2]	= 16*1024*1024,
+	[3]	= 32*1024*1024,
+	[4]	= 64*1024*1024,
+	[5]	= 2*1024*1024,
+};
+#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
+
+typedef struct SM501State {
+    /* graphic console status */
+    DisplayState *ds;
+
+    /* status & internal resources */
+    target_phys_addr_t base;
+    uint32_t local_mem_size_index;
+    uint8_t * local_mem;
+    ram_addr_t local_mem_offset;
+    uint32_t last_width;
+    uint32_t last_height;
+
+    /* mmio registers */
+    uint32_t system_control;
+    uint32_t misc_control;
+    uint32_t gpio_31_0_control;
+    uint32_t gpio_63_32_control;
+    uint32_t dram_control;
+    uint32_t irq_mask;
+    uint32_t misc_timing;
+    uint32_t power_mode_control;
+
+    uint32_t uart0_ier;
+    uint32_t uart0_lcr;
+    uint32_t uart0_mcr;
+    uint32_t uart0_scr;
+
+    uint8_t dc_palette[0x400 * 3];
+
+    uint32_t dc_panel_control;
+    uint32_t dc_panel_panning_control;
+    uint32_t dc_panel_fb_addr;
+    uint32_t dc_panel_fb_offset;
+    uint32_t dc_panel_fb_width;
+    uint32_t dc_panel_fb_height;
+    uint32_t dc_panel_tl_location;
+    uint32_t dc_panel_br_location;
+    uint32_t dc_panel_h_total;
+    uint32_t dc_panel_h_sync;
+    uint32_t dc_panel_v_total;
+    uint32_t dc_panel_v_sync;
+
+    uint32_t dc_panel_hwc_addr;
+    uint32_t dc_panel_hwc_location;
+    uint32_t dc_panel_hwc_color_1_2;
+    uint32_t dc_panel_hwc_color_3;
+
+    uint32_t dc_crt_control;
+    uint32_t dc_crt_fb_addr;
+    uint32_t dc_crt_fb_offset;
+    uint32_t dc_crt_h_total;
+    uint32_t dc_crt_h_sync;
+    uint32_t dc_crt_v_total;
+    uint32_t dc_crt_v_sync;
+
+    uint32_t dc_crt_hwc_addr;
+    uint32_t dc_crt_hwc_location;
+    uint32_t dc_crt_hwc_color_1_2;
+    uint32_t dc_crt_hwc_color_3;
+
+    uint32_t twoD_source;
+    uint32_t twoD_destination;
+    uint32_t twoD_dimension;
+    uint32_t twoD_control;
+    uint32_t twoD_pitch;
+    uint32_t twoD_foreground;
+    uint32_t twoD_stretch;
+    uint32_t twoD_color_compare_mask;
+    uint32_t twoD_mask;
+    uint32_t twoD_window_width;
+    uint32_t twoD_source_base;
+    uint32_t twoD_destination_base;
+
+} SM501State;
+
+static uint32_t get_local_mem_size_index(uint32_t size)
+{
+    uint32_t norm_size = 0;
+    int i, index = 0;
+
+    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
+	uint32_t new_size = sm501_mem_local_size[i];
+	if (new_size >= size) {
+	    if (norm_size == 0 || norm_size > new_size) {
+		norm_size = new_size;
+		index = i;
+	    }
+	}
+    }
+
+    return index;
+}
+
+/**
+ * Check the availability of hardware cursor.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline int is_hwc_enabled(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return addr & 0x80000000;
+}
+
+/**
+ * Get the address which holds cursor pattern data.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_address(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return (addr & 0x03FFFFF0)/* >> 4*/;
+}
+
+/**
+ * Get the cursor position in y coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_y(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return (location & 0x07FF0000) >> 16;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_x(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return location & 0x000007FF;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
+ */
+static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
+{
+    uint16_t color_reg = 0;
+    uint16_t color_565 = 0;
+
+    if (index == 0) {
+        return 0;
+    }
+
+    switch (index) {
+    case 1:
+    case 2:
+        color_reg = crt ? state->dc_crt_hwc_color_1_2
+                        : state->dc_panel_hwc_color_1_2;
+        break;
+    case 3:
+        color_reg = crt ? state->dc_crt_hwc_color_3
+                        : state->dc_panel_hwc_color_3;
+        break;
+    default:
+        printf("invalid hw cursor color.\n");
+        abort();
+    }
+
+    switch (index) {
+    case 1:
+    case 3:
+        color_565 = (uint16_t)(color_reg & 0xFFFF);
+        break;
+    case 2:
+        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
+        break;
+    }
+    return color_565;
+}
+
+static int within_hwc_y_range(SM501State *state, int y, int crt)
+{
+    int hwc_y = get_hwc_y(state, crt);
+    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
+}
+
+static void sm501_2d_operation(SM501State * s)
+{
+    /* obtain operation parameters */
+    int operation = (s->twoD_control >> 16) & 0x1f;
+    int rtl = s->twoD_control & 0x8000000;
+    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+    int src_y = s->twoD_source & 0xFFFF;
+    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+    int dst_y = s->twoD_destination & 0xFFFF;
+    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
+    int operation_height = s->twoD_dimension & 0xFFFF;
+    uint32_t color = s->twoD_foreground;
+    int format_flags = (s->twoD_stretch >> 20) & 0x3;
+    int addressing = (s->twoD_stretch >> 16) & 0xF;
+
+    /* get frame buffer info */
+    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
+    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+
+    if (addressing != 0x0) {
+        printf("%s: only XY addressing is supported.\n", __func__);
+        abort();
+    }
+
+    if ((s->twoD_source_base & 0x08000000) ||
+        (s->twoD_destination_base & 0x08000000)) {
+        printf("%s: only local memory is supported.\n", __func__);
+        abort();
+    }
+
+    switch (operation) {
+    case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
+        int y, x, index_d, index_s;                                         \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                if (rtl) {                                                  \
+                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+                } else {                                                    \
+                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+                }                                                           \
+                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+            }                                                               \
+        }                                                                   \
+    }
+        switch (format_flags) {
+        case 0:
+            COPY_AREA(1, uint8_t, rtl);
+            break;
+        case 1:
+            COPY_AREA(2, uint16_t, rtl);
+            break;
+        case 2:
+            COPY_AREA(4, uint32_t, rtl);
+            break;
+        }
+        break;
+
+    case 0x01: /* fill rectangle */
+#define FILL_RECT(_bpp, _pixel_type) {                                      \
+        int y, x;                                                           \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
+            }                                                               \
+        }                                                                   \
+    }
+
+        switch (format_flags) {
+        case 0:
+            FILL_RECT(1, uint8_t);
+            break;
+        case 1:
+            FILL_RECT(2, uint16_t);
+            break;
+        case 2:
+            FILL_RECT(4, uint32_t);
+            break;
+        }
+        break;
+
+    default:
+        printf("non-implemented SM501 2D operation. %d\n", operation);
+        abort();
+        break;
+    }
+}
+
+static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+	ret = s->system_control;
+	break;
+    case SM501_MISC_CONTROL:
+	ret = s->misc_control;
+	break;
+    case SM501_GPIO31_0_CONTROL:
+	ret = s->gpio_31_0_control;
+	break;
+    case SM501_GPIO63_32_CONTROL:
+	ret = s->gpio_63_32_control;
+	break;
+    case SM501_DEVICEID:
+	ret = 0x050100A0;
+	break;
+    case SM501_DRAM_CONTROL:
+	ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
+	break;
+    case SM501_IRQ_MASK:
+	ret = s->irq_mask;
+	break;
+    case SM501_MISC_TIMING:
+	/* TODO : simulate gate control */
+	ret = s->misc_timing;
+	break;
+    case SM501_CURRENT_GATE:
+	/* TODO : simulate gate control */
+	ret = 0x00021807;
+	break;
+    case SM501_CURRENT_CLOCK:
+	ret = 0x2A1A0A09;
+	break;
+    case SM501_POWER_MODE_CONTROL:
+	ret = s->power_mode_control;
+	break;
+
+    default:
+	printf("sm501 system config : not implemented register read."
+	       " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_system_config_write(void *opaque,
+				      target_phys_addr_t addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
+		  addr, value);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+	s->system_control = value & 0xE300B8F7;
+	break;
+    case SM501_MISC_CONTROL:
+	s->misc_control = value & 0xFF7FFF20;
+	break;
+    case SM501_GPIO31_0_CONTROL:
+	s->gpio_31_0_control = value;
+	break;
+    case SM501_GPIO63_32_CONTROL:
+	s->gpio_63_32_control = value;
+	break;
+    case SM501_DRAM_CONTROL:
+	s->local_mem_size_index = (value >> 13) & 0x7;
+	/* rODO : check validity of size change */
+	s->dram_control |=  value & 0x7FFFFFC3;
+	break;
+    case SM501_IRQ_MASK:
+	s->irq_mask = value;
+	break;
+    case SM501_MISC_TIMING:
+	s->misc_timing = value & 0xF31F1FFF;
+	break;
+    case SM501_POWER_MODE_0_GATE:
+    case SM501_POWER_MODE_1_GATE:
+    case SM501_POWER_MODE_0_CLOCK:
+    case SM501_POWER_MODE_1_CLOCK:
+	/* TODO : simulate gate & clock control */
+	break;
+    case SM501_POWER_MODE_CONTROL:
+	s->power_mode_control = value & 0x00000003;
+	break;
+
+    default:
+	printf("sm501 system config : not implemented register write."
+	       " addr=%x, val=%x\n", (int)addr, value);
+        abort();
+    }
+}
+
+static CPUReadMemoryFunc * const sm501_system_config_readfn[] = {
+    NULL,
+    NULL,
+    &sm501_system_config_read,
+};
+
+static CPUWriteMemoryFunc * const sm501_system_config_writefn[] = {
+    NULL,
+    NULL,
+    &sm501_system_config_write,
+};
+
+static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    return *(uint32_t*)&s->dc_palette[addr];
+}
+
+static void sm501_palette_write(void *opaque,
+				target_phys_addr_t addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
+		  (int)addr, value);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    *(uint32_t*)&s->dc_palette[addr] = value;
+}
+
+static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+
+    case SM501_DC_PANEL_CONTROL:
+	ret = s->dc_panel_control;
+	break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+	ret = s->dc_panel_panning_control;
+	break;
+    case SM501_DC_PANEL_FB_ADDR:
+	ret = s->dc_panel_fb_addr;
+	break;
+    case SM501_DC_PANEL_FB_OFFSET:
+	ret = s->dc_panel_fb_offset;
+	break;
+    case SM501_DC_PANEL_FB_WIDTH:
+	ret = s->dc_panel_fb_width;
+	break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+	ret = s->dc_panel_fb_height;
+	break;
+    case SM501_DC_PANEL_TL_LOC:
+	ret = s->dc_panel_tl_location;
+	break;
+    case SM501_DC_PANEL_BR_LOC:
+	ret = s->dc_panel_br_location;
+	break;
+
+    case SM501_DC_PANEL_H_TOT:
+	ret = s->dc_panel_h_total;
+	break;
+    case SM501_DC_PANEL_H_SYNC:
+	ret = s->dc_panel_h_sync;
+	break;
+    case SM501_DC_PANEL_V_TOT:
+	ret = s->dc_panel_v_total;
+	break;
+    case SM501_DC_PANEL_V_SYNC:
+	ret = s->dc_panel_v_sync;
+	break;
+
+    case SM501_DC_CRT_CONTROL:
+	ret = s->dc_crt_control;
+	break;
+    case SM501_DC_CRT_FB_ADDR:
+	ret = s->dc_crt_fb_addr;
+	break;
+    case SM501_DC_CRT_FB_OFFSET:
+	ret = s->dc_crt_fb_offset;
+	break;
+    case SM501_DC_CRT_H_TOT:
+	ret = s->dc_crt_h_total;
+	break;
+    case SM501_DC_CRT_H_SYNC:
+	ret = s->dc_crt_h_sync;
+	break;
+    case SM501_DC_CRT_V_TOT:
+	ret = s->dc_crt_v_total;
+	break;
+    case SM501_DC_CRT_V_SYNC:
+	ret = s->dc_crt_v_sync;
+	break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+	ret = s->dc_crt_hwc_addr;
+	break;
+    case SM501_DC_CRT_HWC_LOC:
+	ret = s->dc_crt_hwc_location;
+	break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+	ret = s->dc_crt_hwc_color_1_2;
+	break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+	ret = s->dc_crt_hwc_color_3;
+	break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
+        break;
+
+    default:
+	printf("sm501 disp ctrl : not implemented register read."
+	       " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_disp_ctrl_write(void *opaque,
+					   target_phys_addr_t addr,
+					   uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
+		  addr, value);
+
+    switch(addr) {
+    case SM501_DC_PANEL_CONTROL:
+	s->dc_panel_control = value & 0x0FFF73FF;
+	break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+	s->dc_panel_panning_control = value & 0xFF3FFF3F;
+	break;
+    case SM501_DC_PANEL_FB_ADDR:
+	s->dc_panel_fb_addr = value & 0x8FFFFFF0;
+	break;
+    case SM501_DC_PANEL_FB_OFFSET:
+	s->dc_panel_fb_offset = value & 0x3FF03FF0;
+	break;
+    case SM501_DC_PANEL_FB_WIDTH:
+	s->dc_panel_fb_width = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+	s->dc_panel_fb_height = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_PANEL_TL_LOC:
+	s->dc_panel_tl_location = value & 0x07FF07FF;
+	break;
+    case SM501_DC_PANEL_BR_LOC:
+	s->dc_panel_br_location = value & 0x07FF07FF;
+	break;
+
+    case SM501_DC_PANEL_H_TOT:
+	s->dc_panel_h_total = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_PANEL_H_SYNC:
+	s->dc_panel_h_sync = value & 0x00FF0FFF;
+	break;
+    case SM501_DC_PANEL_V_TOT:
+	s->dc_panel_v_total = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_PANEL_V_SYNC:
+	s->dc_panel_v_sync = value & 0x003F0FFF;
+	break;
+
+    case SM501_DC_PANEL_HWC_ADDR:
+	s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
+	break;
+    case SM501_DC_PANEL_HWC_LOC:
+	s->dc_panel_hwc_location = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_PANEL_HWC_COLOR_1_2:
+	s->dc_panel_hwc_color_1_2 = value;
+	break;
+    case SM501_DC_PANEL_HWC_COLOR_3:
+	s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
+	break;
+
+    case SM501_DC_CRT_CONTROL:
+	s->dc_crt_control = value & 0x0003FFFF;
+	break;
+    case SM501_DC_CRT_FB_ADDR:
+	s->dc_crt_fb_addr = value & 0x8FFFFFF0;
+	break;
+    case SM501_DC_CRT_FB_OFFSET:
+	s->dc_crt_fb_offset = value & 0x3FF03FF0;
+	break;
+    case SM501_DC_CRT_H_TOT:
+	s->dc_crt_h_total = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_CRT_H_SYNC:
+	s->dc_crt_h_sync = value & 0x00FF0FFF;
+	break;
+    case SM501_DC_CRT_V_TOT:
+	s->dc_crt_v_total = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_CRT_V_SYNC:
+	s->dc_crt_v_sync = value & 0x003F0FFF;
+	break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+	s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
+	break;
+    case SM501_DC_CRT_HWC_LOC:
+	s->dc_crt_hwc_location = value & 0x0FFF0FFF;
+	break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+	s->dc_crt_hwc_color_1_2 = value;
+	break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+	s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
+	break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
+        break;
+
+    default:
+	printf("sm501 disp ctrl : not implemented register write."
+	       " addr=%x, val=%x\n", (int)addr, value);
+        abort();
+    }
+}
+
+static CPUReadMemoryFunc * const sm501_disp_ctrl_readfn[] = {
+    NULL,
+    NULL,
+    &sm501_disp_ctrl_read,
+};
+
+static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = {
+    NULL,
+    NULL,
+    &sm501_disp_ctrl_write,
+};
+
+static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_2D_SOURCE_BASE:
+        ret = s->twoD_source_base;
+        break;
+    default:
+        printf("sm501 disp ctrl : not implemented register read."
+               " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_2d_engine_write(void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
+                  addr, value);
+
+    switch(addr) {
+    case SM501_2D_SOURCE:
+        s->twoD_source = value;
+        break;
+    case SM501_2D_DESTINATION:
+        s->twoD_destination = value;
+        break;
+    case SM501_2D_DIMENSION:
+        s->twoD_dimension = value;
+        break;
+    case SM501_2D_CONTROL:
+        s->twoD_control = value;
+
+        /* do 2d operation if start flag is set. */
+        if (value & 0x80000000) {
+            sm501_2d_operation(s);
+            s->twoD_control &= ~0x80000000; /* start flag down */
+        }
+
+        break;
+    case SM501_2D_PITCH:
+        s->twoD_pitch = value;
+        break;
+    case SM501_2D_FOREGROUND:
+        s->twoD_foreground = value;
+        break;
+    case SM501_2D_STRETCH:
+        s->twoD_stretch = value;
+        break;
+    case SM501_2D_COLOR_COMPARE_MASK:
+        s->twoD_color_compare_mask = value;
+        break;
+    case SM501_2D_MASK:
+        s->twoD_mask = value;
+        break;
+    case SM501_2D_WINDOW_WIDTH:
+        s->twoD_window_width = value;
+        break;
+    case SM501_2D_SOURCE_BASE:
+        s->twoD_source_base = value;
+        break;
+    case SM501_2D_DESTINATION_BASE:
+        s->twoD_destination_base = value;
+        break;
+    default:
+        printf("sm501 2d engine : not implemented register write."
+               " addr=%x, val=%x\n", (int)addr, value);
+        abort();
+    }
+}
+
+static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = {
+    NULL,
+    NULL,
+    &sm501_2d_engine_read,
+};
+
+static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = {
+    NULL,
+    NULL,
+    &sm501_2d_engine_write,
+};
+
+/* draw line functions for all console modes */
+
+#include "pixel_ops.h"
+
+typedef void draw_line_func(uint8_t *d, const uint8_t *s,
+			    int width, const uint32_t *pal);
+
+typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
+                                int c_y, uint8_t *d, int width);
+
+#define DEPTH 8
+#include "sm501_template.h"
+
+#define DEPTH 15
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "sm501_template.h"
+
+#define DEPTH 16
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "sm501_template.h"
+
+#define DEPTH 32
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "sm501_template.h"
+
+static draw_line_func * draw_line8_funcs[] = {
+    draw_line8_8,
+    draw_line8_15,
+    draw_line8_16,
+    draw_line8_32,
+    draw_line8_32bgr,
+    draw_line8_15bgr,
+    draw_line8_16bgr,
+};
+
+static draw_line_func * draw_line16_funcs[] = {
+    draw_line16_8,
+    draw_line16_15,
+    draw_line16_16,
+    draw_line16_32,
+    draw_line16_32bgr,
+    draw_line16_15bgr,
+    draw_line16_16bgr,
+};
+
+static draw_line_func * draw_line32_funcs[] = {
+    draw_line32_8,
+    draw_line32_15,
+    draw_line32_16,
+    draw_line32_32,
+    draw_line32_32bgr,
+    draw_line32_15bgr,
+    draw_line32_16bgr,
+};
+
+static draw_hwc_line_func * draw_hwc_line_funcs[] = {
+    draw_hwc_line_8,
+    draw_hwc_line_15,
+    draw_hwc_line_16,
+    draw_hwc_line_32,
+    draw_hwc_line_32bgr,
+    draw_hwc_line_15bgr,
+    draw_hwc_line_16bgr,
+};
+
+static inline int get_depth_index(DisplayState *s)
+{
+    switch(ds_get_bits_per_pixel(s)) {
+    default:
+    case 8:
+	return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+	if (is_surface_bgr(s->surface))
+	    return 4;
+	else
+	    return 3;
+    }
+}
+
+static void sm501_draw_crt(SM501State * s)
+{
+    int y;
+    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
+
+    uint8_t  * src = s->local_mem;
+    int src_bpp = 0;
+    int dst_bpp = ds_get_bytes_per_pixel(s->ds) + (ds_get_bits_per_pixel(s->ds) % 8 ? 1 : 0);
+    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
+						    - SM501_DC_PANEL_PALETTE];
+    uint8_t hwc_palette[3 * 3];
+    int ds_depth_index = get_depth_index(s->ds);
+    draw_line_func * draw_line = NULL;
+    draw_hwc_line_func * draw_hwc_line = NULL;
+    int full_update = 0;
+    int y_start = -1;
+    ram_addr_t page_min = ~0l;
+    ram_addr_t page_max = 0l;
+    ram_addr_t offset = s->local_mem_offset;
+
+    /* choose draw_line function */
+    switch (s->dc_crt_control & 3) {
+    case SM501_DC_CRT_CONTROL_8BPP:
+	src_bpp = 1;
+	draw_line = draw_line8_funcs[ds_depth_index];
+	break;
+    case SM501_DC_CRT_CONTROL_16BPP:
+	src_bpp = 2;
+	draw_line = draw_line16_funcs[ds_depth_index];
+	break;
+    case SM501_DC_CRT_CONTROL_32BPP:
+	src_bpp = 4;
+	draw_line = draw_line32_funcs[ds_depth_index];
+	break;
+    default:
+	printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
+	       s->dc_crt_control);
+        abort();
+	break;
+    }
+
+    /* set up to draw hardware cursor */
+    if (is_hwc_enabled(s, 1)) {
+        int i;
+
+        /* get cursor palette */
+        for (i = 0; i < 3; i++) {
+            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
+            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
+            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
+            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
+        }
+
+        /* choose cursor draw line function */
+        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
+    }
+
+    /* adjust console size */
+    if (s->last_width != width || s->last_height != height) {
+	qemu_console_resize(s->ds, width, height);
+	s->last_width = width;
+	s->last_height = height;
+	full_update = 1;
+    }
+
+    /* draw each line according to conditions */
+    for (y = 0; y < height; y++) {
+	int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
+	int update = full_update || update_hwc;
+	ram_addr_t page0 = offset & TARGET_PAGE_MASK;
+	ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
+	ram_addr_t page;
+
+	/* check dirty flags for each line */
+	for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
+	    if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG))
+		update = 1;
+
+	/* draw line and change status */
+	if (update) {
+            uint8_t * d = &(ds_get_data(s->ds)[y * width * dst_bpp]);
+
+            /* draw graphics layer */
+            draw_line(d, src, width, palette);
+
+            /* draw haredware cursor */
+            if (update_hwc) {
+                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
+            }
+
+	    if (y_start < 0)
+		y_start = y;
+	    if (page0 < page_min)
+		page_min = page0;
+	    if (page1 > page_max)
+		page_max = page1;
+	} else {
+	    if (y_start >= 0) {
+		/* flush to display */
+		dpy_update(s->ds, 0, y_start, width, y - y_start);
+		y_start = -1;
+	    }
+	}
+
+	src += width * src_bpp;
+	offset += width * src_bpp;
+    }
+
+    /* complete flush to display */
+    if (y_start >= 0)
+	dpy_update(s->ds, 0, y_start, width, y - y_start);
+
+    /* clear dirty flags */
+    if (page_min != ~0l) {
+	cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+					VGA_DIRTY_FLAG);
+    }
+}
+
+static void sm501_update_display(void *opaque)
+{
+    SM501State * s = (SM501State *)opaque;
+
+    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
+	sm501_draw_crt(s);
+}
+
+void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+                CharDriverState *chr)
+{
+    SM501State * s;
+    DeviceState *dev;
+    int sm501_system_config_index;
+    int sm501_disp_ctrl_index;
+    int sm501_2d_engine_index;
+
+    /* allocate management data region */
+    s = (SM501State *)qemu_mallocz(sizeof(SM501State));
+    s->base = base;
+    s->local_mem_size_index
+	= get_local_mem_size_index(local_mem_bytes);
+    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
+		  s->local_mem_size_index);
+    s->system_control = 0x00100000;
+    s->misc_control = 0x00001000; /* assumes SH, active=low */
+    s->dc_panel_control = 0x00010000;
+    s->dc_crt_control = 0x00010000;
+
+    /* allocate local memory */
+    s->local_mem_offset = qemu_ram_alloc(NULL, "sm501.local", local_mem_bytes);
+    s->local_mem = qemu_get_ram_ptr(s->local_mem_offset);
+    cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset);
+
+    /* map mmio */
+    sm501_system_config_index
+	= cpu_register_io_memory(sm501_system_config_readfn,
+				 sm501_system_config_writefn, s,
+                                 DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base + MMIO_BASE_OFFSET,
+				 0x6c, sm501_system_config_index);
+    sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn,
+						   sm501_disp_ctrl_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
+                                 0x1000, sm501_disp_ctrl_index);
+    sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
+                                                   sm501_2d_engine_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                 0x54, sm501_2d_engine_index);
+
+    /* bridge to usb host emulation module */
+    dev = qdev_create(NULL, "sysbus-ohci");
+    qdev_prop_set_uint32(dev, "num-ports", 2);
+    qdev_prop_set_taddr(dev, "dma-offset", base);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0,
+                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    /* bridge to serial emulation module */
+    if (chr) {
+#ifdef TARGET_WORDS_BIGENDIAN
+        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+                       NULL, /* TODO : chain irq to IRL */
+                       115200, chr, 1, 1);
+#else
+        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+                       NULL, /* TODO : chain irq to IRL */
+                       115200, chr, 1, 0);
+#endif
+    }
+
+    /* create qemu graphic console */
+    s->ds = graphic_console_init(sm501_update_display, NULL,
+				 NULL, NULL, s);
+}
diff --git a/qemu-0.15.x/hw/sm501_template.h b/qemu-0.15.x/hw/sm501_template.h
new file mode 100644
index 0000000..2d4a3d8
--- /dev/null
+++ b/qemu-0.15.x/hw/sm501_template.h
@@ -0,0 +1,145 @@
+/*
+ * Pixel drawing function templates for QEMU SM501 Device
+ *
+ * Copyright (c) 2008 Shin-ichiro KAWASAKI
+ *
+ * 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 DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+
+static void glue(draw_line8_, PIXEL_NAME)(
+                 uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint8_t v, r, g, b;
+    do {
+      	v = ldub_raw(s);
+	r = (pal[v] >> 16) & 0xff;
+	g = (pal[v] >>  8) & 0xff;
+	b = (pal[v] >>  0) & 0xff;
+	((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+	s ++;
+	d += BPP;
+    } while (-- width != 0);
+}
+
+static void glue(draw_line16_, PIXEL_NAME)(
+		 uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    do {
+	rgb565 = lduw_raw(s);
+	r = ((rgb565 >> 11) & 0x1f) << 3;
+	g = ((rgb565 >>  5) & 0x3f) << 2;
+	b = ((rgb565 >>  0) & 0x1f) << 3;
+	((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+	s += 2;
+	d += BPP;
+    } while (-- width != 0);
+}
+
+static void glue(draw_line32_, PIXEL_NAME)(
+		 uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint8_t r, g, b;
+
+    do {
+	ldub_raw(s);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+	((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+	s += 4;
+	d += BPP;
+    } while (-- width != 0);
+}
+
+/**
+ * Draw hardware cursor image on the given line.
+ */
+static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
+                         uint8_t * palette, int c_y, uint8_t *d, int width)
+{
+    int x, i;
+    uint8_t bitset = 0;
+
+    /* get hardware cursor pattern */
+    uint32_t cursor_addr = get_hwc_address(s, crt);
+    assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
+    cursor_addr += 64 * c_y / 4;  /* 4 pixels per byte */
+    cursor_addr += s->base;
+
+    /* get cursor position */
+    x = get_hwc_x(s, crt);
+    d += x * BPP;
+
+    for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) {
+        uint8_t v;
+
+        /* get pixel value */
+        if (i % 4 == 0) {
+            bitset = ldub_phys(cursor_addr);
+            cursor_addr++;
+        }
+        v = bitset & 3;
+        bitset >>= 2;
+
+        /* write pixel */
+        if (v) {
+            v--;
+            uint8_t r = palette[v * 3 + 0];
+            uint8_t g = palette[v * 3 + 1];
+            uint8_t b = palette[v * 3 + 2];
+            ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        }
+        d += BPP;
+    }
+}
+
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/qemu-0.15.x/hw/smbios.c b/qemu-0.15.x/hw/smbios.c
new file mode 100644
index 0000000..a3ae1de
--- /dev/null
+++ b/qemu-0.15.x/hw/smbios.c
@@ -0,0 +1,239 @@
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson at hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu.h"
+#include "smbios.h"
+#include "loader.h"
+
+/*
+ * Structures shared with the BIOS
+ */
+struct smbios_header {
+    uint16_t length;
+    uint8_t type;
+} __attribute__((__packed__));
+
+struct smbios_field {
+    struct smbios_header header;
+    uint8_t type;
+    uint16_t offset;
+    uint8_t data[];
+} __attribute__((__packed__));
+
+struct smbios_table {
+    struct smbios_header header;
+    uint8_t data[];
+} __attribute__((__packed__));
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+
+static uint8_t *smbios_entries;
+static size_t smbios_entries_len;
+static int smbios_type4_count = 0;
+
+static void smbios_validate_table(void)
+{
+    if (smbios_type4_count && smbios_type4_count != smp_cpus) {
+         fprintf(stderr,
+                 "Number of SMBIOS Type 4 tables must match cpu count.\n");
+        exit(1);
+    }
+}
+
+uint8_t *smbios_get_table(size_t *length)
+{
+    smbios_validate_table();
+    *length = smbios_entries_len;
+    return smbios_entries;
+}
+
+/*
+ * To avoid unresolvable overlaps in data, don't allow both
+ * tables and fields for the same smbios type.
+ */
+static void smbios_check_collision(int type, int entry)
+{
+    uint16_t *num_entries = (uint16_t *)smbios_entries;
+    struct smbios_header *header;
+    char *p;
+    int i;
+
+    if (!num_entries)
+        return;
+
+    p = (char *)(num_entries + 1);
+
+    for (i = 0; i < *num_entries; i++) {
+        header = (struct smbios_header *)p;
+        if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
+            struct smbios_field *field = (void *)header;
+            if (type == field->type) {
+                fprintf(stderr, "SMBIOS type %d field already defined, "
+                                "cannot add table\n", type);
+                exit(1);
+            }
+        } else if (entry == SMBIOS_FIELD_ENTRY &&
+                   header->type == SMBIOS_TABLE_ENTRY) {
+            struct smbios_structure_header *table = (void *)(header + 1);
+            if (type == table->type) {
+                fprintf(stderr, "SMBIOS type %d table already defined, "
+                                "cannot add field\n", type);
+                exit(1);
+            }
+        }
+        p += le16_to_cpu(header->length);
+    }
+}
+
+void smbios_add_field(int type, int offset, int len, void *data)
+{
+    struct smbios_field *field;
+
+    smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
+
+    if (!smbios_entries) {
+        smbios_entries_len = sizeof(uint16_t);
+        smbios_entries = qemu_mallocz(smbios_entries_len);
+    }
+    smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+                                                  sizeof(*field) + len);
+    field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
+    field->header.type = SMBIOS_FIELD_ENTRY;
+    field->header.length = cpu_to_le16(sizeof(*field) + len);
+
+    field->type = type;
+    field->offset = cpu_to_le16(offset);
+    memcpy(field->data, data, len);
+
+    smbios_entries_len += sizeof(*field) + len;
+    (*(uint16_t *)smbios_entries) =
+            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+}
+
+static void smbios_build_type_0_fields(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "vendor", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "version", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "date", t))
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     bios_release_date_str),
+                                     strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "release", t)) {
+        int major, minor;
+        sscanf(buf, "%d.%d", &major, &minor);
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_major_release), 1, &major);
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_minor_release), 1, &minor);
+    }
+}
+
+static void smbios_build_type_1_fields(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "manufacturer", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "product", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "version", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "serial", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "uuid", t)) {
+        if (qemu_uuid_parse(buf, qemu_uuid) != 0) {
+            fprintf(stderr, "Invalid SMBIOS UUID string\n");
+            exit(1);
+        }
+    }
+    if (get_param_value(buf, sizeof(buf), "sku", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
+                         strlen(buf) + 1, buf);
+    if (get_param_value(buf, sizeof(buf), "family", t))
+        smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
+                         strlen(buf) + 1, buf);
+}
+
+int smbios_entry_add(const char *t)
+{
+    char buf[1024];
+
+    if (get_param_value(buf, sizeof(buf), "file", t)) {
+        struct smbios_structure_header *header;
+        struct smbios_table *table;
+        int size = get_image_size(buf);
+
+        if (size == -1 || size < sizeof(struct smbios_structure_header)) {
+            fprintf(stderr, "Cannot read smbios file %s\n", buf);
+            exit(1);
+        }
+
+        if (!smbios_entries) {
+            smbios_entries_len = sizeof(uint16_t);
+            smbios_entries = qemu_mallocz(smbios_entries_len);
+        }
+
+        smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+                                                      sizeof(*table) + size);
+        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
+        table->header.type = SMBIOS_TABLE_ENTRY;
+        table->header.length = cpu_to_le16(sizeof(*table) + size);
+
+        if (load_image(buf, table->data) != size) {
+            fprintf(stderr, "Failed to load smbios file %s", buf);
+            exit(1);
+        }
+
+        header = (struct smbios_structure_header *)(table->data);
+        smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
+        if (header->type == 4) {
+            smbios_type4_count++;
+        }
+
+        smbios_entries_len += sizeof(*table) + size;
+        (*(uint16_t *)smbios_entries) =
+                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+        return 0;
+    }
+
+    if (get_param_value(buf, sizeof(buf), "type", t)) {
+        unsigned long type = strtoul(buf, NULL, 0);
+        switch (type) {
+        case 0:
+            smbios_build_type_0_fields(t);
+            return 0;
+        case 1:
+            smbios_build_type_1_fields(t);
+            return 0;
+        default:
+            fprintf(stderr, "Don't know how to build fields for SMBIOS type "
+                    "%ld\n", type);
+            exit(1);
+        }
+    }
+
+    fprintf(stderr, "smbios: must specify type= or file=\n");
+    return -1;
+}
diff --git a/qemu-0.15.x/hw/smbios.h b/qemu-0.15.x/hw/smbios.h
new file mode 100644
index 0000000..3a5169d
--- /dev/null
+++ b/qemu-0.15.x/hw/smbios.h
@@ -0,0 +1,162 @@
+#ifndef QEMU_SMBIOS_H
+#define QEMU_SMBIOS_H
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson at hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+int smbios_entry_add(const char *t);
+void smbios_add_field(int type, int offset, int len, void *data);
+uint8_t *smbios_get_table(size_t *length);
+
+/*
+ * SMBIOS spec defined tables
+ */
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+    struct smbios_structure_header header;
+    uint8_t vendor_str;
+    uint8_t bios_version_str;
+    uint16_t bios_starting_address_segment;
+    uint8_t bios_release_date_str;
+    uint8_t bios_rom_size;
+    uint8_t bios_characteristics[8];
+    uint8_t bios_characteristics_extension_bytes[2];
+    uint8_t system_bios_major_release;
+    uint8_t system_bios_minor_release;
+    uint8_t embedded_controller_major_release;
+    uint8_t embedded_controller_minor_release;
+} __attribute__((__packed__));
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_name_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t uuid[16];
+    uint8_t wake_up_type;
+    uint8_t sku_number_str;
+    uint8_t family_str;
+} __attribute__((__packed__));
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t type;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t boot_up_state;
+    uint8_t power_supply_state;
+    uint8_t thermal_state;
+    uint8_t security_status;
+    uint32_t oem_defined;
+    uint8_t height;
+    uint8_t number_of_power_cords;
+    uint8_t contained_element_count;
+    // contained elements follow
+} __attribute__((__packed__));
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+    struct smbios_structure_header header;
+    uint8_t socket_designation_str;
+    uint8_t processor_type;
+    uint8_t processor_family;
+    uint8_t processor_manufacturer_str;
+    uint32_t processor_id[2];
+    uint8_t processor_version_str;
+    uint8_t voltage;
+    uint16_t external_clock;
+    uint16_t max_speed;
+    uint16_t current_speed;
+    uint8_t status;
+    uint8_t processor_upgrade;
+    uint16_t l1_cache_handle;
+    uint16_t l2_cache_handle;
+    uint16_t l3_cache_handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 16 - Physical Memory Array
+ *   Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+    struct smbios_structure_header header;
+    uint8_t location;
+    uint8_t use;
+    uint8_t error_correction;
+    uint32_t maximum_capacity;
+    uint16_t memory_error_information_handle;
+    uint16_t number_of_memory_devices;
+} __attribute__((__packed__));
+/* SMBIOS type 17 - Memory Device
+ *   Associated with one type 19
+ */
+struct smbios_type_17 {
+    struct smbios_structure_header header;
+    uint16_t physical_memory_array_handle;
+    uint16_t memory_error_information_handle;
+    uint16_t total_width;
+    uint16_t data_width;
+    uint16_t size;
+    uint8_t form_factor;
+    uint8_t device_set;
+    uint8_t device_locator_str;
+    uint8_t bank_locator_str;
+    uint8_t memory_type;
+    uint16_t type_detail;
+} __attribute__((__packed__));
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_array_handle;
+    uint8_t partition_width;
+} __attribute__((__packed__));
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_device_handle;
+    uint16_t memory_array_mapped_address_handle;
+    uint8_t partition_row_position;
+    uint8_t interleave_position;
+    uint8_t interleaved_data_depth;
+} __attribute__((__packed__));
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+    struct smbios_structure_header header;
+    uint8_t reserved[6];
+    uint8_t boot_status;
+} __attribute__((__packed__));
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+    struct smbios_structure_header header;
+} __attribute__((__packed__));
+
+#endif /*QEMU_SMBIOS_H */
diff --git a/qemu-0.15.x/hw/smbus.c b/qemu-0.15.x/hw/smbus.c
new file mode 100644
index 0000000..ff027c8
--- /dev/null
+++ b/qemu-0.15.x/hw/smbus.c
@@ -0,0 +1,318 @@
+/*
+ * QEMU SMBus device emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+/* TODO: Implement PEC.  */
+
+#include "hw.h"
+#include "i2c.h"
+#include "smbus.h"
+
+//#define DEBUG_SMBUS 1
+
+#ifdef DEBUG_SMBUS
+#define DPRINTF(fmt, ...) \
+do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    SMBUS_IDLE,
+    SMBUS_WRITE_DATA,
+    SMBUS_RECV_BYTE,
+    SMBUS_READ_DATA,
+    SMBUS_DONE,
+    SMBUS_CONFUSED = -1
+};
+
+static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
+{
+    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+
+    DPRINTF("Quick Command %d\n", recv);
+    if (t->quick_cmd)
+        t->quick_cmd(dev, recv);
+}
+
+static void smbus_do_write(SMBusDevice *dev)
+{
+    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+
+    if (dev->data_len == 0) {
+        smbus_do_quick_cmd(dev, 0);
+    } else if (dev->data_len == 1) {
+        DPRINTF("Send Byte\n");
+        if (t->send_byte) {
+            t->send_byte(dev, dev->data_buf[0]);
+        }
+    } else {
+        dev->command = dev->data_buf[0];
+        DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
+        if (t->write_data) {
+            t->write_data(dev, dev->command, dev->data_buf + 1,
+                          dev->data_len - 1);
+        }
+    }
+}
+
+static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+{
+    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+
+    switch (event) {
+    case I2C_START_SEND:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Incoming data\n");
+            dev->mode = SMBUS_WRITE_DATA;
+            break;
+        default:
+            BADF("Unexpected send start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_START_RECV:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Read mode\n");
+            dev->mode = SMBUS_RECV_BYTE;
+            break;
+        case SMBUS_WRITE_DATA:
+            if (dev->data_len == 0) {
+                BADF("Read after write with no data\n");
+                dev->mode = SMBUS_CONFUSED;
+            } else {
+                if (dev->data_len > 1) {
+                    smbus_do_write(dev);
+                } else {
+                    dev->command = dev->data_buf[0];
+                    DPRINTF("%02x: Command %d\n", dev->i2c.address,
+                            dev->command);
+                }
+                DPRINTF("Read mode\n");
+                dev->data_len = 0;
+                dev->mode = SMBUS_READ_DATA;
+            }
+            break;
+        default:
+            BADF("Unexpected recv start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_FINISH:
+        switch (dev->mode) {
+        case SMBUS_WRITE_DATA:
+            smbus_do_write(dev);
+            break;
+        case SMBUS_RECV_BYTE:
+            smbus_do_quick_cmd(dev, 1);
+            break;
+        case SMBUS_READ_DATA:
+            BADF("Unexpected stop during receive\n");
+            break;
+        default:
+            /* Nothing to do.  */
+            break;
+        }
+        dev->mode = SMBUS_IDLE;
+        dev->data_len = 0;
+        break;
+
+    case I2C_NACK:
+        switch (dev->mode) {
+        case SMBUS_DONE:
+            /* Nothing to do.  */
+            break;
+        case SMBUS_READ_DATA:
+            dev->mode = SMBUS_DONE;
+            break;
+        default:
+            BADF("Unexpected NACK in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+    }
+}
+
+static int smbus_i2c_recv(i2c_slave *s)
+{
+    SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
+    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+    int ret;
+
+    switch (dev->mode) {
+    case SMBUS_RECV_BYTE:
+        if (t->receive_byte) {
+            ret = t->receive_byte(dev);
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Receive Byte %02x\n", ret);
+        dev->mode = SMBUS_DONE;
+        break;
+    case SMBUS_READ_DATA:
+        if (t->read_data) {
+            ret = t->read_data(dev, dev->command, dev->data_len);
+            dev->data_len++;
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Read data %02x\n", ret);
+        break;
+    default:
+        BADF("Unexpected read in state %d\n", dev->mode);
+        dev->mode = SMBUS_CONFUSED;
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+{
+    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+
+    switch (dev->mode) {
+    case SMBUS_WRITE_DATA:
+        DPRINTF("Write data %02x\n", data);
+        dev->data_buf[dev->data_len++] = data;
+        break;
+    default:
+        BADF("Unexpected write in state %d\n", dev->mode);
+        break;
+    }
+    return 0;
+}
+
+static int smbus_device_init(i2c_slave *i2c)
+{
+    SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
+    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
+
+    return t->init(dev);
+}
+
+void smbus_register_device(SMBusDeviceInfo *info)
+{
+    assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
+    info->i2c.init = smbus_device_init;
+    info->i2c.event = smbus_i2c_event;
+    info->i2c.recv = smbus_i2c_recv;
+    info->i2c.send = smbus_i2c_send;
+    i2c_register_slave(&info->i2c);
+}
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
+{
+    i2c_start_transfer(bus, addr, read);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
+{
+    uint8_t data;
+
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
+{
+    uint8_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
+{
+    uint16_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    data |= i2c_recv(bus) << 8;
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data & 0xff);
+    i2c_send(bus, data >> 8);
+    i2c_end_transfer(bus);
+}
+
+int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
+{
+    int len;
+    int i;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    len = i2c_recv(bus);
+    if (len > 32)
+        len = 0;
+    for (i = 0; i < len; i++)
+        data[i] = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return len;
+}
+
+void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                       int len)
+{
+    int i;
+
+    if (len > 32)
+        len = 32;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, len);
+    for (i = 0; i < len; i++)
+        i2c_send(bus, data[i]);
+    i2c_end_transfer(bus);
+}
diff --git a/qemu-0.15.x/hw/smbus.h b/qemu-0.15.x/hw/smbus.h
new file mode 100644
index 0000000..a398715
--- /dev/null
+++ b/qemu-0.15.x/hw/smbus.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU SMBus API
+ *
+ * Copyright (c) 2007 Arastra, Inc.
+ *
+ * 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 "i2c.h"
+
+struct SMBusDevice {
+    /* The SMBus protocol is implemented on top of I2C.  */
+    i2c_slave i2c;
+
+    /* Remaining fields for internal use only.  */
+    int mode;
+    int data_len;
+    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
+    uint8_t command;
+};
+
+typedef struct {
+    I2CSlaveInfo i2c;
+    int (*init)(SMBusDevice *dev);
+    void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
+    void (*send_byte)(SMBusDevice *dev, uint8_t val);
+    uint8_t (*receive_byte)(SMBusDevice *dev);
+    /* We can't distinguish between a word write and a block write with
+       length 1, so pass the whole data block including the length byte
+       (if present).  The device is responsible figuring out what type of
+       command  this is.  */
+    void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
+    /* Likewise we can't distinguish between different reads, or even know
+       the length of the read until the read is complete, so read data a
+       byte at a time.  The device is responsible for adding the length
+       byte on block reads.  */
+    uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
+} SMBusDeviceInfo;
+
+void smbus_register_device(SMBusDeviceInfo *info);
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
+uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr);
+void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data);
+uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command);
+void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data);
+uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command);
+void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data);
+int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data);
+void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                       int len);
+
+void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
+                       const uint8_t *eeprom_spd, int size);
diff --git a/qemu-0.15.x/hw/smbus_eeprom.c b/qemu-0.15.x/hw/smbus_eeprom.c
new file mode 100644
index 0000000..3634754
--- /dev/null
+++ b/qemu-0.15.x/hw/smbus_eeprom.c
@@ -0,0 +1,145 @@
+/*
+ * QEMU SMBus EEPROM device
+ *
+ * Copyright (c) 2007 Arastra, Inc.
+ *
+ * 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 "hw.h"
+#include "i2c.h"
+#include "smbus.h"
+
+//#define DEBUG
+
+typedef struct SMBusEEPROMDevice {
+    SMBusDevice smbusdev;
+    void *data;
+    uint8_t offset;
+} SMBusEEPROMDevice;
+
+static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
+{
+#ifdef DEBUG
+    printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
+#endif
+}
+
+static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+#ifdef DEBUG
+    printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
+           dev->i2c.address, val);
+#endif
+    eeprom->offset = val;
+}
+
+static uint8_t eeprom_receive_byte(SMBusDevice *dev)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    uint8_t *data = eeprom->data;
+    uint8_t val = data[eeprom->offset++];
+#ifdef DEBUG
+    printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
+           dev->i2c.address, val);
+#endif
+    return val;
+}
+
+static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    int n;
+#ifdef DEBUG
+    printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
+           dev->i2c.address, cmd, buf[0]);
+#endif
+    /* An page write operation is not a valid SMBus command.
+       It is a block write without a length byte.  Fortunately we
+       get the full block anyway.  */
+    /* TODO: Should this set the current location?  */
+    if (cmd + len > 256)
+        n = 256 - cmd;
+    else
+        n = len;
+    memcpy(eeprom->data + cmd, buf, n);
+    len -= n;
+    if (len)
+        memcpy(eeprom->data, buf + n, len);
+}
+
+static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    /* If this is the first byte then set the current position.  */
+    if (n == 0)
+        eeprom->offset = cmd;
+    /* As with writes, we implement block reads without the
+       SMBus length byte.  */
+    return eeprom_receive_byte(dev);
+}
+
+static int smbus_eeprom_initfn(SMBusDevice *dev)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
+
+    eeprom->offset = 0;
+    return 0;
+}
+
+static SMBusDeviceInfo smbus_eeprom_info = {
+    .i2c.qdev.name = "smbus-eeprom",
+    .i2c.qdev.size = sizeof(SMBusEEPROMDevice),
+    .i2c.qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init = smbus_eeprom_initfn,
+    .quick_cmd = eeprom_quick_cmd,
+    .send_byte = eeprom_send_byte,
+    .receive_byte = eeprom_receive_byte,
+    .write_data = eeprom_write_data,
+    .read_data = eeprom_read_data
+};
+
+static void smbus_eeprom_register_devices(void)
+{
+    smbus_register_device(&smbus_eeprom_info);
+}
+
+device_init(smbus_eeprom_register_devices)
+
+void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
+                       const uint8_t *eeprom_spd, int eeprom_spd_size)
+{
+    int i;
+    uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+    if (eeprom_spd_size > 0) {
+        memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
+    }
+
+    for (i = 0; i < nb_eeprom; i++) {
+        DeviceState *eeprom;
+        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
+        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
+        qdev_init_nofail(eeprom);
+    }
+}
diff --git a/qemu-0.15.x/hw/smc91c111.c b/qemu-0.15.x/hw/smc91c111.c
new file mode 100644
index 0000000..3a8a85c
--- /dev/null
+++ b/qemu-0.15.x/hw/smc91c111.c
@@ -0,0 +1,797 @@
+/*
+ * SMSC 91C111 Ethernet interface emulation
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "sysbus.h"
+#include "net.h"
+#include "devices.h"
+/* For crc32 */
+#include <zlib.h>
+
+/* Number of 2k memory pages available.  */
+#define NUM_PACKETS 4
+
+typedef struct {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    uint16_t tcr;
+    uint16_t rcr;
+    uint16_t cr;
+    uint16_t ctr;
+    uint16_t gpr;
+    uint16_t ptr;
+    uint16_t ercv;
+    qemu_irq irq;
+    int bank;
+    int packet_num;
+    int tx_alloc;
+    /* Bitmask of allocated packets.  */
+    int allocated;
+    int tx_fifo_len;
+    int tx_fifo[NUM_PACKETS];
+    int rx_fifo_len;
+    int rx_fifo[NUM_PACKETS];
+    int tx_fifo_done_len;
+    int tx_fifo_done[NUM_PACKETS];
+    /* Packet buffer memory.  */
+    uint8_t data[NUM_PACKETS][2048];
+    uint8_t int_level;
+    uint8_t int_mask;
+    int mmio_index;
+} smc91c111_state;
+
+static const VMStateDescription vmstate_smc91c111 = {
+    .name = "smc91c111",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(tcr, smc91c111_state),
+        VMSTATE_UINT16(rcr, smc91c111_state),
+        VMSTATE_UINT16(cr, smc91c111_state),
+        VMSTATE_UINT16(ctr, smc91c111_state),
+        VMSTATE_UINT16(gpr, smc91c111_state),
+        VMSTATE_UINT16(ptr, smc91c111_state),
+        VMSTATE_UINT16(ercv, smc91c111_state),
+        VMSTATE_INT32(bank, smc91c111_state),
+        VMSTATE_INT32(packet_num, smc91c111_state),
+        VMSTATE_INT32(tx_alloc, smc91c111_state),
+        VMSTATE_INT32(allocated, smc91c111_state),
+        VMSTATE_INT32(tx_fifo_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
+        VMSTATE_INT32(rx_fifo_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
+        VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
+        VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
+        VMSTATE_UINT8(int_level, smc91c111_state),
+        VMSTATE_UINT8(int_mask, smc91c111_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define RCR_SOFT_RST  0x8000
+#define RCR_STRIP_CRC 0x0200
+#define RCR_RXEN      0x0100
+
+#define TCR_EPH_LOOP  0x2000
+#define TCR_NOCRC     0x0100
+#define TCR_PAD_EN    0x0080
+#define TCR_FORCOL    0x0004
+#define TCR_LOOP      0x0002
+#define TCR_TXEN      0x0001
+
+#define INT_MD        0x80
+#define INT_ERCV      0x40
+#define INT_EPH       0x20
+#define INT_RX_OVRN   0x10
+#define INT_ALLOC     0x08
+#define INT_TX_EMPTY  0x04
+#define INT_TX        0x02
+#define INT_RCV       0x01
+
+#define CTR_AUTO_RELEASE  0x0800
+#define CTR_RELOAD        0x0002
+#define CTR_STORE         0x0001
+
+#define RS_ALGNERR      0x8000
+#define RS_BRODCAST     0x4000
+#define RS_BADCRC       0x2000
+#define RS_ODDFRAME     0x1000
+#define RS_TOOLONG      0x0800
+#define RS_TOOSHORT     0x0400
+#define RS_MULTICAST    0x0001
+
+/* Update interrupt status.  */
+static void smc91c111_update(smc91c111_state *s)
+{
+    int level;
+
+    if (s->tx_fifo_len == 0)
+        s->int_level |= INT_TX_EMPTY;
+    if (s->tx_fifo_done_len != 0)
+        s->int_level |= INT_TX;
+    level = (s->int_level & s->int_mask) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+/* Try to allocate a packet.  Returns 0x80 on failure.  */
+static int smc91c111_allocate_packet(smc91c111_state *s)
+{
+    int i;
+    if (s->allocated == (1 << NUM_PACKETS) - 1) {
+        return 0x80;
+    }
+
+    for (i = 0; i < NUM_PACKETS; i++) {
+        if ((s->allocated & (1 << i)) == 0)
+            break;
+    }
+    s->allocated |= 1 << i;
+    return i;
+}
+
+
+/* Process a pending TX allocate.  */
+static void smc91c111_tx_alloc(smc91c111_state *s)
+{
+    s->tx_alloc = smc91c111_allocate_packet(s);
+    if (s->tx_alloc == 0x80)
+        return;
+    s->int_level |= INT_ALLOC;
+    smc91c111_update(s);
+}
+
+/* Remove and item from the RX FIFO.  */
+static void smc91c111_pop_rx_fifo(smc91c111_state *s)
+{
+    int i;
+
+    s->rx_fifo_len--;
+    if (s->rx_fifo_len) {
+        for (i = 0; i < s->rx_fifo_len; i++)
+            s->rx_fifo[i] = s->rx_fifo[i + 1];
+        s->int_level |= INT_RCV;
+    } else {
+        s->int_level &= ~INT_RCV;
+    }
+    smc91c111_update(s);
+}
+
+/* Remove an item from the TX completion FIFO.  */
+static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
+{
+    int i;
+
+    if (s->tx_fifo_done_len == 0)
+        return;
+    s->tx_fifo_done_len--;
+    for (i = 0; i < s->tx_fifo_done_len; i++)
+        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
+}
+
+/* Release the memory allocated to a packet.  */
+static void smc91c111_release_packet(smc91c111_state *s, int packet)
+{
+    s->allocated &= ~(1 << packet);
+    if (s->tx_alloc == 0x80)
+        smc91c111_tx_alloc(s);
+}
+
+/* Flush the TX FIFO.  */
+static void smc91c111_do_tx(smc91c111_state *s)
+{
+    int i;
+    int len;
+    int control;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->tcr & TCR_TXEN) == 0)
+        return;
+    if (s->tx_fifo_len == 0)
+        return;
+    for (i = 0; i < s->tx_fifo_len; i++) {
+        packetnum = s->tx_fifo[i];
+        p = &s->data[packetnum][0];
+        /* Set status word.  */
+        *(p++) = 0x01;
+        *(p++) = 0x40;
+        len = *(p++);
+        len |= ((int)*(p++)) << 8;
+        len -= 6;
+        control = p[len + 1];
+        if (control & 0x20)
+            len++;
+        /* ??? This overwrites the data following the buffer.
+           Don't know what real hardware does.  */
+        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
+            memset(p + len, 0, 64 - len);
+            len = 64;
+        }
+#if 0
+        {
+            int add_crc;
+
+            /* The card is supposed to append the CRC to the frame.
+               However none of the other network traffic has the CRC
+               appended.  Suspect this is low level ethernet detail we
+               don't need to worry about.  */
+            add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
+            if (add_crc) {
+                uint32_t crc;
+
+                crc = crc32(~0, p, len);
+                memcpy(p + len, &crc, 4);
+                len += 4;
+            }
+        }
+#endif
+        if (s->ctr & CTR_AUTO_RELEASE)
+            /* Race?  */
+            smc91c111_release_packet(s, packetnum);
+        else if (s->tx_fifo_done_len < NUM_PACKETS)
+            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
+        qemu_send_packet(&s->nic->nc, p, len);
+    }
+    s->tx_fifo_len = 0;
+    smc91c111_update(s);
+}
+
+/* Add a packet to the TX FIFO.  */
+static void smc91c111_queue_tx(smc91c111_state *s, int packet)
+{
+    if (s->tx_fifo_len == NUM_PACKETS)
+        return;
+    s->tx_fifo[s->tx_fifo_len++] = packet;
+    smc91c111_do_tx(s);
+}
+
+static void smc91c111_reset(DeviceState *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, sysbus_from_qdev(dev));
+    s->bank = 0;
+    s->tx_fifo_len = 0;
+    s->tx_fifo_done_len = 0;
+    s->rx_fifo_len = 0;
+    s->allocated = 0;
+    s->packet_num = 0;
+    s->tx_alloc = 0;
+    s->tcr = 0;
+    s->rcr = 0;
+    s->cr = 0xa0b1;
+    s->ctr = 0x1210;
+    s->ptr = 0;
+    s->ercv = 0x1f;
+    s->int_level = INT_TX_EMPTY;
+    s->int_mask = 0;
+    smc91c111_update(s);
+}
+
+#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
+#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
+
+static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset = offset & 0xf;
+    if (offset == 14) {
+        s->bank = value;
+        return;
+    }
+    if (offset == 15)
+        return;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            SET_LOW(tcr, value);
+            return;
+        case 1:
+            SET_HIGH(tcr, value);
+            return;
+        case 4: /* RCR */
+            SET_LOW(rcr, value);
+            return;
+        case 5:
+            SET_HIGH(rcr, value);
+            if (s->rcr & RCR_SOFT_RST)
+                smc91c111_reset(&s->busdev.qdev);
+            return;
+        case 10: case 11: /* RPCR */
+            /* Ignored */
+            return;
+        case 12: case 13: /* Reserved */
+            return;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            SET_LOW(cr, value);
+            return;
+        case 1:
+            SET_HIGH(cr,value);
+            return;
+        case 2: case 3: /* BASE */
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            /* Not implemented.  */
+            return;
+        case 10: /* Genral Purpose */
+            SET_LOW(gpr, value);
+            return;
+        case 11:
+            SET_HIGH(gpr, value);
+            return;
+        case 12: /* Control */
+            if (value & 1)
+                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
+            if (value & 2)
+                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
+            value &= ~3;
+            SET_LOW(ctr, value);
+            return;
+        case 13:
+            SET_HIGH(ctr, value);
+            return;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: /* MMU Command */
+            switch (value >> 5) {
+            case 0: /* no-op */
+                break;
+            case 1: /* Allocate for TX.  */
+                s->tx_alloc = 0x80;
+                s->int_level &= ~INT_ALLOC;
+                smc91c111_update(s);
+                smc91c111_tx_alloc(s);
+                break;
+            case 2: /* Reset MMU.  */
+                s->allocated = 0;
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                s->rx_fifo_len = 0;
+                s->tx_alloc = 0;
+                break;
+            case 3: /* Remove from RX FIFO.  */
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 4: /* Remove from RX FIFO and release.  */
+                if (s->rx_fifo_len > 0) {
+                    smc91c111_release_packet(s, s->rx_fifo[0]);
+                }
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 5: /* Release.  */
+                smc91c111_release_packet(s, s->packet_num);
+                break;
+            case 6: /* Add to TX FIFO.  */
+                smc91c111_queue_tx(s, s->packet_num);
+                break;
+            case 7: /* Reset TX FIFO.  */
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                break;
+            }
+            return;
+        case 1:
+            /* Ignore.  */
+            return;
+        case 2: /* Packet Number Register */
+            s->packet_num = value;
+            return;
+        case 3: case 4: case 5:
+            /* Should be readonly, but linux writes to them anyway. Ignore.  */
+            return;
+        case 6: /* Pointer */
+            SET_LOW(ptr, value);
+            return;
+        case 7:
+            SET_HIGH(ptr, value);
+            return;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
+                } else {
+                    p += (offset & 3);
+                }
+                s->data[n][p] = value;
+            }
+            return;
+        case 12: /* Interrupt ACK.  */
+            s->int_level &= ~(value & 0xd6);
+            if (value & INT_TX)
+                smc91c111_pop_tx_fifo_done(s);
+            smc91c111_update(s);
+            return;
+        case 13: /* Interrupt mask.  */
+            s->int_mask = value;
+            smc91c111_update(s);
+            return;
+        }
+        break;;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return;
+        case 8: case 9: /* Management Interface.  */
+            /* Not implemented.  */
+            return;
+        case 12: /* Early receive.  */
+            s->ercv = value & 0x1f;
+        case 13:
+            /* Ignore.  */
+            return;
+        }
+        break;
+    }
+    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
+}
+
+static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset = offset & 0xf;
+    if (offset == 14) {
+        return s->bank;
+    }
+    if (offset == 15)
+        return 0x33;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            return s->tcr & 0xff;
+        case 1:
+            return s->tcr >> 8;
+        case 2: /* EPH Status */
+            return 0;
+        case 3:
+            return 0x40;
+        case 4: /* RCR */
+            return s->rcr & 0xff;
+        case 5:
+            return s->rcr >> 8;
+        case 6: /* Counter */
+        case 7:
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Memory size.  */
+            return NUM_PACKETS;
+        case 9: /* Free memory available.  */
+            {
+                int i;
+                int n;
+                n = 0;
+                for (i = 0; i < NUM_PACKETS; i++) {
+                    if (s->allocated & (1 << i))
+                        n++;
+                }
+                return n;
+            }
+        case 10: case 11: /* RPCR */
+            /* Not implemented.  */
+            return 0;
+        case 12: case 13: /* Reserved */
+            return 0;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            return s->cr & 0xff;
+        case 1:
+            return s->cr >> 8;
+        case 2: case 3: /* BASE */
+            /* Not implemented.  */
+            return 0;
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            return s->conf.macaddr.a[offset - 4];
+        case 10: /* General Purpose */
+            return s->gpr & 0xff;
+        case 11:
+            return s->gpr >> 8;
+        case 12: /* Control */
+            return s->ctr & 0xff;
+        case 13:
+            return s->ctr >> 8;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: case 1: /* MMUCR Busy bit.  */
+            return 0;
+        case 2: /* Packet Number.  */
+            return s->packet_num;
+        case 3: /* Allocation Result.  */
+            return s->tx_alloc;
+        case 4: /* TX FIFO */
+            if (s->tx_fifo_done_len == 0)
+                return 0x80;
+            else
+                return s->tx_fifo_done[0];
+        case 5: /* RX FIFO */
+            if (s->rx_fifo_len == 0)
+                return 0x80;
+            else
+                return s->rx_fifo[0];
+        case 6: /* Pointer */
+            return s->ptr & 0xff;
+        case 7:
+            return (s->ptr >> 8) & 0xf7;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
+                } else {
+                    p += (offset & 3);
+                }
+                return s->data[n][p];
+            }
+        case 12: /* Interrupt status.  */
+            return s->int_level;
+        case 13: /* Interrupt mask.  */
+            return s->int_mask;
+        }
+        break;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Management Interface.  */
+            /* Not implemented.  */
+            return 0x30;
+        case 9:
+            return 0x33;
+        case 10: /* Revision.  */
+            return 0x91;
+        case 11:
+            return 0x33;
+        case 12:
+            return s->ercv;
+        case 13:
+            return 0;
+        }
+        break;
+    }
+    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
+    return 0;
+}
+
+static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    smc91c111_writeb(opaque, offset, value & 0xff);
+    smc91c111_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    /* 32-bit writes to offset 0xc only actually write to the bank select
+       register (offset 0xe)  */
+    if (offset != 0xc)
+        smc91c111_writew(opaque, offset, value & 0xffff);
+    smc91c111_writew(opaque, offset + 2, value >> 16);
+}
+
+static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = smc91c111_readb(opaque, offset);
+    val |= smc91c111_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = smc91c111_readw(opaque, offset);
+    val |= smc91c111_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static int smc91c111_can_receive(VLANClientState *nc)
+{
+    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return 1;
+    if (s->allocated == (1 << NUM_PACKETS) - 1)
+        return 0;
+    return 1;
+}
+
+static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int status;
+    int packetsize;
+    uint32_t crc;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return -1;
+    /* Short packets are padded with zeros.  Receiving a packet
+       < 64 bytes long is considered an error condition.  */
+    if (size < 64)
+        packetsize = 64;
+    else
+        packetsize = (size & ~1);
+    packetsize += 6;
+    crc = (s->rcr & RCR_STRIP_CRC) == 0;
+    if (crc)
+        packetsize += 4;
+    /* TODO: Flag overrun and receive errors.  */
+    if (packetsize > 2048)
+        return -1;
+    packetnum = smc91c111_allocate_packet(s);
+    if (packetnum == 0x80)
+        return -1;
+    s->rx_fifo[s->rx_fifo_len++] = packetnum;
+
+    p = &s->data[packetnum][0];
+    /* ??? Multicast packets?  */
+    status = 0;
+    if (size > 1518)
+        status |= RS_TOOLONG;
+    if (size & 1)
+        status |= RS_ODDFRAME;
+    *(p++) = status & 0xff;
+    *(p++) = status >> 8;
+    *(p++) = packetsize & 0xff;
+    *(p++) = packetsize >> 8;
+    memcpy(p, buf, size & ~1);
+    p += (size & ~1);
+    /* Pad short packets.  */
+    if (size < 64) {
+        int pad;
+
+        if (size & 1)
+            *(p++) = buf[size - 1];
+        pad = 64 - size;
+        memset(p, 0, pad);
+        p += pad;
+        size = 64;
+    }
+    /* It's not clear if the CRC should go before or after the last byte in
+       odd sized packets.  Linux disables the CRC, so that's no help.
+       The pictures in the documentation show the CRC aligned on a 16-bit
+       boundary before the last odd byte, so that's what we do.  */
+    if (crc) {
+        crc = crc32(~0, buf, size);
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff;
+    }
+    if (size & 1) {
+        *(p++) = buf[size - 1];
+        *p = 0x60;
+    } else {
+        *(p++) = 0;
+        *p = 0x40;
+    }
+    /* TODO: Raise early RX interrupt?  */
+    s->int_level |= INT_RCV;
+    smc91c111_update(s);
+
+    return size;
+}
+
+static CPUReadMemoryFunc * const smc91c111_readfn[] = {
+    smc91c111_readb,
+    smc91c111_readw,
+    smc91c111_readl
+};
+
+static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
+    smc91c111_writeb,
+    smc91c111_writew,
+    smc91c111_writel
+};
+
+static void smc91c111_cleanup(VLANClientState *nc)
+{
+    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_smc91c111_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = smc91c111_can_receive,
+    .receive = smc91c111_receive,
+    .cleanup = smc91c111_cleanup,
+};
+
+static int smc91c111_init1(SysBusDevice *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
+
+    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
+                                           smc91c111_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 16, s->mmio_index);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+static SysBusDeviceInfo smc91c111_info = {
+    .init = smc91c111_init1,
+    .qdev.name  = "smc91c111",
+    .qdev.size  = sizeof(smc91c111_state),
+    .qdev.vmsd = &vmstate_smc91c111,
+    .qdev.reset = smc91c111_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void smc91c111_register_devices(void)
+{
+    sysbus_register_withprop(&smc91c111_info);
+}
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "smc91c111");
+    dev = qdev_create(NULL, "smc91c111");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+device_init(smc91c111_register_devices)
diff --git a/qemu-0.15.x/hw/soc_dma.c b/qemu-0.15.x/hw/soc_dma.c
new file mode 100644
index 0000000..3f0f414
--- /dev/null
+++ b/qemu-0.15.x/hw/soc_dma.c
@@ -0,0 +1,366 @@
+/*
+ * On-chip DMA controller framework.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "soc_dma.h"
+
+static void transfer_mem2mem(struct soc_dma_ch_s *ch)
+{
+    memcpy(ch->paddr[0], ch->paddr[1], ch->bytes);
+    ch->paddr[0] += ch->bytes;
+    ch->paddr[1] += ch->bytes;
+}
+
+static void transfer_mem2fifo(struct soc_dma_ch_s *ch)
+{
+    ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes);
+    ch->paddr[0] += ch->bytes;
+}
+
+static void transfer_fifo2mem(struct soc_dma_ch_s *ch)
+{
+    ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes);
+    ch->paddr[1] += ch->bytes;
+}
+
+/* This is further optimisable but isn't very important because often
+ * DMA peripherals forbid this kind of transfers and even when they don't,
+ * oprating systems may not need to use them.  */
+static void *fifo_buf;
+static int fifo_size;
+static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
+{
+    if (ch->bytes > fifo_size)
+        fifo_buf = qemu_realloc(fifo_buf, fifo_size = ch->bytes);
+
+    /* Implement as transfer_fifo2linear + transfer_linear2fifo.  */
+    ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
+    ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes);
+}
+
+struct dma_s {
+    struct soc_dma_s soc;
+    int chnum;
+    uint64_t ch_enable_mask;
+    int64_t channel_freq;
+    int enabled_count;
+
+    struct memmap_entry_s {
+        enum soc_dma_port_type type;
+        target_phys_addr_t addr;
+        union {
+           struct {
+               void *opaque;
+               soc_dma_io_t fn;
+               int out;
+           } fifo;
+           struct {
+               void *base;
+               size_t size;
+           } mem;
+        } u;
+    } *memmap;
+    int memmap_size;
+
+    struct soc_dma_ch_s ch[0];
+};
+
+static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
+{
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+
+    qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq);
+}
+
+static void soc_dma_ch_run(void *opaque)
+{
+    struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque;
+
+    ch->running = 1;
+    ch->dma->setup_fn(ch);
+    ch->transfer_fn(ch);
+    ch->running = 0;
+
+    if (ch->enable)
+        soc_dma_ch_schedule(ch, ch->bytes);
+    ch->bytes = 0;
+}
+
+static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma,
+                target_phys_addr_t addr)
+{
+    struct memmap_entry_s *lo;
+    int hi;
+
+    lo = dma->memmap;
+    hi = dma->memmap_size;
+
+    while (hi > 1) {
+        hi /= 2;
+        if (lo[hi].addr <= addr)
+            lo += hi;
+    }
+
+    return lo;
+}
+
+static inline enum soc_dma_port_type soc_dma_ch_update_type(
+                struct soc_dma_ch_s *ch, int port)
+{
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+    struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]);
+
+    if (entry->type == soc_dma_port_fifo) {
+        while (entry < dma->memmap + dma->memmap_size &&
+                        entry->u.fifo.out != port)
+            entry ++;
+        if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port)
+            return soc_dma_port_other;
+
+        if (ch->type[port] != soc_dma_access_const)
+            return soc_dma_port_other;
+
+        ch->io_fn[port] = entry->u.fifo.fn;
+        ch->io_opaque[port] = entry->u.fifo.opaque;
+        return soc_dma_port_fifo;
+    } else if (entry->type == soc_dma_port_mem) {
+        if (entry->addr > ch->vaddr[port] ||
+                        entry->addr + entry->u.mem.size <= ch->vaddr[port])
+            return soc_dma_port_other;
+
+        /* TODO: support constant memory address for source port as used for
+         * drawing solid rectangles by PalmOS(R).  */
+        if (ch->type[port] != soc_dma_access_const)
+            return soc_dma_port_other;
+
+        ch->paddr[port] = (uint8_t *) entry->u.mem.base +
+                (ch->vaddr[port] - entry->addr);
+        /* TODO: save bytes left to the end of the mapping somewhere so we
+         * can check we're not reading beyond it.  */
+        return soc_dma_port_mem;
+    } else
+        return soc_dma_port_other;
+}
+
+void soc_dma_ch_update(struct soc_dma_ch_s *ch)
+{
+    enum soc_dma_port_type src, dst;
+
+    src = soc_dma_ch_update_type(ch, 0);
+    if (src == soc_dma_port_other) {
+        ch->update = 0;
+        ch->transfer_fn = ch->dma->transfer_fn;
+        return;
+    }
+    dst = soc_dma_ch_update_type(ch, 1);
+
+    /* TODO: use src and dst as array indices.  */
+    if (src == soc_dma_port_mem && dst == soc_dma_port_mem)
+        ch->transfer_fn = transfer_mem2mem;
+    else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo)
+        ch->transfer_fn = transfer_mem2fifo;
+    else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem)
+        ch->transfer_fn = transfer_fifo2mem;
+    else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo)
+        ch->transfer_fn = transfer_fifo2fifo;
+    else
+        ch->transfer_fn = ch->dma->transfer_fn;
+
+    ch->update = (dst != soc_dma_port_other);
+}
+
+static void soc_dma_ch_freq_update(struct dma_s *s)
+{
+    if (s->enabled_count)
+        /* We completely ignore channel priorities and stuff */
+        s->channel_freq = s->soc.freq / s->enabled_count;
+    else {
+        /* TODO: Signal that we want to disable the functional clock and let
+         * the platform code decide what to do with it, i.e. check that
+         * auto-idle is enabled in the clock controller and if we are stopping
+         * the clock, do the same with any parent clocks that had only one
+         * user keeping them on and auto-idle enabled.  */
+    }
+}
+
+void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
+{
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+
+    dma->enabled_count += level - ch->enable;
+
+    if (level)
+        dma->ch_enable_mask |= 1 << ch->num;
+    else
+        dma->ch_enable_mask &= ~(1 << ch->num);
+
+    if (level != ch->enable) {
+        soc_dma_ch_freq_update(dma);
+        ch->enable = level;
+
+        if (!ch->enable)
+            qemu_del_timer(ch->timer);
+        else if (!ch->running)
+            soc_dma_ch_run(ch);
+        else
+            soc_dma_ch_schedule(ch, 1);
+    }
+}
+
+void soc_dma_reset(struct soc_dma_s *soc)
+{
+    struct dma_s *s = (struct dma_s *) soc;
+
+    s->soc.drqbmp = 0;
+    s->ch_enable_mask = 0;
+    s->enabled_count = 0;
+    soc_dma_ch_freq_update(s);
+}
+
+/* TODO: take a functional-clock argument */
+struct soc_dma_s *soc_dma_init(int n)
+{
+    int i;
+    struct dma_s *s = qemu_mallocz(sizeof(*s) + n * sizeof(*s->ch));
+
+    s->chnum = n;
+    s->soc.ch = s->ch;
+    for (i = 0; i < n; i ++) {
+        s->ch[i].dma = &s->soc;
+        s->ch[i].num = i;
+        s->ch[i].timer = qemu_new_timer_ns(vm_clock, soc_dma_ch_run, &s->ch[i]);
+    }
+
+    soc_dma_reset(&s->soc);
+    fifo_size = 0;
+
+    return &s->soc;
+}
+
+void soc_dma_port_add_fifo(struct soc_dma_s *soc, target_phys_addr_t virt_base,
+                soc_dma_io_t fn, void *opaque, int out)
+{
+    struct memmap_entry_s *entry;
+    struct dma_s *dma = (struct dma_s *) soc;
+
+    dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) *
+                    (dma->memmap_size + 1));
+    entry = soc_dma_lookup(dma, virt_base);
+
+    if (dma->memmap_size) {
+        if (entry->type == soc_dma_port_mem) {
+            if (entry->addr <= virt_base &&
+                            entry->addr + entry->u.mem.size > virt_base) {
+                fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
+                                " collides with RAM region at " TARGET_FMT_lx
+                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) entry->addr, (target_ulong)
+                                (entry->addr + entry->u.mem.size));
+                exit(-1);
+            }
+
+            if (entry->addr <= virt_base)
+                entry ++;
+        } else
+            while (entry < dma->memmap + dma->memmap_size &&
+                            entry->addr <= virt_base) {
+                if (entry->addr == virt_base && entry->u.fifo.out == out) {
+                    fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
+                                    " collides FIFO at " TARGET_FMT_lx "\n",
+                                    __FUNCTION__, (target_ulong) virt_base,
+                                    (target_ulong) entry->addr);
+                    exit(-1);
+                }
+
+                entry ++;
+            }
+
+        memmove(entry + 1, entry,
+                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
+                        (uint8_t *) entry);
+    } else
+        dma->memmap_size ++;
+
+    entry->addr          = virt_base;
+    entry->type          = soc_dma_port_fifo;
+    entry->u.fifo.fn     = fn;
+    entry->u.fifo.opaque = opaque;
+    entry->u.fifo.out    = out;
+}
+
+void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
+                target_phys_addr_t virt_base, size_t size)
+{
+    struct memmap_entry_s *entry;
+    struct dma_s *dma = (struct dma_s *) soc;
+
+    dma->memmap = qemu_realloc(dma->memmap, sizeof(*entry) *
+                    (dma->memmap_size + 1));
+    entry = soc_dma_lookup(dma, virt_base);
+
+    if (dma->memmap_size) {
+        if (entry->type == soc_dma_port_mem) {
+            if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
+                            (entry->addr <= virt_base &&
+                             entry->addr + entry->u.mem.size > virt_base)) {
+                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
+                                " collides with RAM region at " TARGET_FMT_lx
+                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) (virt_base + size),
+                                (target_ulong) entry->addr, (target_ulong)
+                                (entry->addr + entry->u.mem.size));
+                exit(-1);
+            }
+
+            if (entry->addr <= virt_base)
+                entry ++;
+        } else {
+            if (entry->addr >= virt_base &&
+                            entry->addr < virt_base + size) {
+                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
+                                " collides with FIFO at " TARGET_FMT_lx
+                                "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) (virt_base + size),
+                                (target_ulong) entry->addr);
+                exit(-1);
+            }
+
+            while (entry < dma->memmap + dma->memmap_size &&
+                            entry->addr <= virt_base)
+                entry ++;
+	}
+
+        memmove(entry + 1, entry,
+                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
+                        (uint8_t *) entry);
+    } else
+        dma->memmap_size ++;
+
+    entry->addr          = virt_base;
+    entry->type          = soc_dma_port_mem;
+    entry->u.mem.base    = phys_base;
+    entry->u.mem.size    = size;
+}
+
+/* TODO: port removal for ports like PCMCIA memory */
diff --git a/qemu-0.15.x/hw/soc_dma.h b/qemu-0.15.x/hw/soc_dma.h
new file mode 100644
index 0000000..c0ebb8d
--- /dev/null
+++ b/qemu-0.15.x/hw/soc_dma.h
@@ -0,0 +1,113 @@
+/*
+ * On-chip DMA controller framework.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct soc_dma_s;
+struct soc_dma_ch_s;
+typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
+typedef void (*soc_dma_transfer_t)(struct soc_dma_ch_s *ch);
+
+enum soc_dma_port_type {
+    soc_dma_port_mem,
+    soc_dma_port_fifo,
+    soc_dma_port_other,
+};
+
+enum soc_dma_access_type {
+    soc_dma_access_const,
+    soc_dma_access_linear,
+    soc_dma_access_other,
+};
+
+struct soc_dma_ch_s {
+    /* Private */
+    struct soc_dma_s *dma;
+    int num;
+    QEMUTimer *timer;
+
+    /* Set by soc_dma.c */
+    int enable;
+    int update;
+
+    /* This should be set by dma->setup_fn().  */
+    int bytes;
+    /* Initialised by the DMA module, call soc_dma_ch_update after writing.  */
+    enum soc_dma_access_type type[2];
+    target_phys_addr_t vaddr[2];	/* Updated by .transfer_fn().  */
+    /* Private */
+    void *paddr[2];
+    soc_dma_io_t io_fn[2];
+    void *io_opaque[2];
+
+    int running;
+    soc_dma_transfer_t transfer_fn;
+
+    /* Set and used by the DMA module.  */
+    void *opaque;
+};
+
+struct soc_dma_s {
+    /* Following fields are set by the SoC DMA module and can be used
+     * by anybody.  */
+    uint64_t drqbmp;	/* Is zeroed by soc_dma_reset() */
+    qemu_irq *drq;
+    void *opaque;
+    int64_t freq;
+    soc_dma_transfer_t transfer_fn;
+    soc_dma_transfer_t setup_fn;
+    /* Set by soc_dma_init() for use by the DMA module.  */
+    struct soc_dma_ch_s *ch;
+};
+
+/* Call to activate or stop a DMA channel.  */
+void soc_dma_set_request(struct soc_dma_ch_s *ch, int level);
+/* Call after every write to one of the following fields and before
+ * calling soc_dma_set_request(ch, 1):
+ *   ch->type[0...1],
+ *   ch->vaddr[0...1],
+ *   ch->paddr[0...1],
+ * or after a soc_dma_port_add_fifo() or soc_dma_port_add_mem().  */
+void soc_dma_ch_update(struct soc_dma_ch_s *ch);
+
+/* The SoC should call this when the DMA module is being reset.  */
+void soc_dma_reset(struct soc_dma_s *s);
+struct soc_dma_s *soc_dma_init(int n);
+
+void soc_dma_port_add_fifo(struct soc_dma_s *dma, target_phys_addr_t virt_base,
+                soc_dma_io_t fn, void *opaque, int out);
+void soc_dma_port_add_mem(struct soc_dma_s *dma, uint8_t *phys_base,
+                target_phys_addr_t virt_base, size_t size);
+
+static inline void soc_dma_port_add_fifo_in(struct soc_dma_s *dma,
+                target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque)
+{
+    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 0);
+}
+
+static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
+                target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque)
+{
+    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1);
+}
+
+static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma,
+                ram_addr_t offset, target_phys_addr_t virt_base, size_t size)
+{
+    return soc_dma_port_add_mem(dma, qemu_get_ram_ptr(offset), virt_base, size);
+}
diff --git a/qemu-0.15.x/hw/spapr.c b/qemu-0.15.x/hw/spapr.c
new file mode 100644
index 0000000..109b774
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr.c
@@ -0,0 +1,476 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * 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 "sysemu.h"
+#include "hw.h"
+#include "elf.h"
+#include "net.h"
+#include "blockdev.h"
+
+#include "hw/boards.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/xics.h"
+
+#include <libfdt.h>
+
+#define KERNEL_LOAD_ADDR        0x00000000
+#define INITRD_LOAD_ADDR        0x02800000
+#define FDT_MAX_SIZE            0x10000
+#define RTAS_MAX_SIZE           0x10000
+#define FW_MAX_SIZE             0x400000
+#define FW_FILE_NAME            "slof.bin"
+
+#define MIN_RAM_SLOF		512UL
+
+#define TIMEBASE_FREQ           512000000ULL
+
+#define MAX_CPUS                256
+#define XICS_IRQS		1024
+
+sPAPREnvironment *spapr;
+
+static void *spapr_create_fdt_skel(const char *cpu_model,
+                                   target_phys_addr_t initrd_base,
+                                   target_phys_addr_t initrd_size,
+                                   const char *boot_device,
+                                   const char *kernel_cmdline,
+                                   long hash_shift)
+{
+    void *fdt;
+    CPUState *env;
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) };
+    uint32_t start_prop = cpu_to_be32(initrd_base);
+    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
+    uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+        "\0hcall-tce\0hcall-vio\0hcall-splpar";
+    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+    int i;
+    char *modelname;
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+                    #exp, fdt_strerror(ret));                      \
+            exit(1);                                               \
+        }                                                          \
+    } while (0)
+
+    fdt = qemu_mallocz(FDT_MAX_SIZE);
+    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+
+    _FDT((fdt_finish_reservemap(fdt)));
+
+    /* Root node */
+    _FDT((fdt_begin_node(fdt, "")));
+    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
+    _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
+
+    /* /chosen */
+    _FDT((fdt_begin_node(fdt, "chosen")));
+
+    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
+    _FDT((fdt_property(fdt, "linux,initrd-start",
+                       &start_prop, sizeof(start_prop))));
+    _FDT((fdt_property(fdt, "linux,initrd-end",
+                       &end_prop, sizeof(end_prop))));
+    _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* memory node */
+    _FDT((fdt_begin_node(fdt, "memory at 0")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "memory")));
+    _FDT((fdt_property(fdt, "reg",
+                       mem_reg_property, sizeof(mem_reg_property))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* cpus */
+    _FDT((fdt_begin_node(fdt, "cpus")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+
+    modelname = qemu_strdup(cpu_model);
+
+    for (i = 0; i < strlen(modelname); i++) {
+        modelname[i] = toupper(modelname[i]);
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        int index = env->cpu_index;
+        uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */
+        char *nodename;
+        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                           0xffffffff, 0xffffffff};
+
+        if (asprintf(&nodename, "%s@%x", modelname, index) < 0) {
+            fprintf(stderr, "Allocation failure\n");
+            exit(1);
+        }
+
+        _FDT((fdt_begin_node(fdt, nodename)));
+
+        free(nodename);
+
+        _FDT((fdt_property_cell(fdt, "reg", index)));
+        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
+
+        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
+        _FDT((fdt_property_cell(fdt, "dcache-block-size",
+                                env->dcache_line_size)));
+        _FDT((fdt_property_cell(fdt, "icache-block-size",
+                                env->icache_line_size)));
+        _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
+        /* Hardcode CPU frequency for now.  It's kind of arbitrary on
+         * full emu, for kvm we should copy it from the host */
+        _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
+        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
+        _FDT((fdt_property(fdt, "ibm,pft-size",
+                           pft_size_prop, sizeof(pft_size_prop))));
+        _FDT((fdt_property_string(fdt, "status", "okay")));
+        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+        _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index)));
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+                           gserver_prop, sizeof(gserver_prop))));
+
+        if (env->mmu_model & POWERPC_MMU_1TSEG) {
+            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
+                               segs, sizeof(segs))));
+        }
+
+        _FDT((fdt_end_node(fdt)));
+    }
+
+    qemu_free(modelname);
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* RTAS */
+    _FDT((fdt_begin_node(fdt, "rtas")));
+
+    _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
+                       sizeof(hypertas_prop))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* interrupt controller */
+    _FDT((fdt_begin_node(fdt, "interrupt-controller at 0")));
+
+    _FDT((fdt_property_string(fdt, "device_type",
+                              "PowerPC-External-Interrupt-Presentation")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+    _FDT((fdt_property_cell(fdt, "reg", 0)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+    _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
+                       interrupt_server_ranges_prop,
+                       sizeof(interrupt_server_ranges_prop))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* vdevice */
+    _FDT((fdt_begin_node(fdt, "vdevice")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    _FDT((fdt_end_node(fdt))); /* close root node */
+    _FDT((fdt_finish(fdt)));
+
+    return fdt;
+}
+
+static void spapr_finalize_fdt(sPAPREnvironment *spapr,
+                               target_phys_addr_t fdt_addr,
+                               target_phys_addr_t rtas_addr,
+                               target_phys_addr_t rtas_size)
+{
+    int ret;
+    void *fdt;
+
+    fdt = qemu_malloc(FDT_MAX_SIZE);
+
+    /* open out the base tree into a temp buffer for the final tweaks */
+    _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
+
+    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup vio devices in fdt\n");
+        exit(1);
+    }
+
+    /* RTAS */
+    ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
+    }
+
+    _FDT((fdt_pack(fdt)));
+
+    cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
+
+    qemu_free(fdt);
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static void emulate_spapr_hypercall(CPUState *env)
+{
+    env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
+}
+
+static void spapr_reset(void *opaque)
+{
+    sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
+
+    fprintf(stderr, "sPAPR reset\n");
+
+    /* flush out the hash table */
+    memset(spapr->htab, 0, spapr->htab_size);
+
+    /* Load the fdt */
+    spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
+                       spapr->rtas_size);
+
+    /* Set up the entry state */
+    first_cpu->gpr[3] = spapr->fdt_addr;
+    first_cpu->gpr[5] = 0;
+    first_cpu->halted = 0;
+    first_cpu->nip = spapr->entry_point;
+
+}
+
+/* pSeries LPAR / sPAPR hardware init */
+static void ppc_spapr_init(ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    CPUState *env;
+    int i;
+    ram_addr_t ram_offset;
+    uint32_t initrd_base;
+    long kernel_size, initrd_size, fw_size;
+    long pteg_shift = 17;
+    char *filename;
+    int irq = 16;
+
+    spapr = qemu_malloc(sizeof(*spapr));
+    cpu_ppc_hypercall = emulate_spapr_hypercall;
+
+    /* We place the device tree just below either the top of RAM, or
+     * 2GB, so that it can be processed with 32-bit code if
+     * necessary */
+    spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
+    spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "POWER7";
+    }
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        /* Set time-base frequency to 512 MHz */
+        cpu_ppc_tb_init(env, TIMEBASE_FREQ);
+        qemu_register_reset((QEMUResetHandler *)&cpu_reset, env);
+
+        env->hreset_vector = 0x60;
+        env->hreset_excp_prefix = 0;
+        env->gpr[3] = env->cpu_index;
+    }
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate hash page table.  For now we always make this 16mb,
+     * later we should probably make it scale to the size of guest
+     * RAM */
+    spapr->htab_size = 1ULL << (pteg_shift + 7);
+    spapr->htab = qemu_malloc(spapr->htab_size);
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->external_htab = spapr->htab;
+        env->htab_base = -1;
+        env->htab_mask = spapr->htab_size - 1;
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
+    spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
+                                           ram_size - spapr->rtas_addr);
+    if (spapr->rtas_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    qemu_free(filename);
+
+    /* Set up Interrupt Controller */
+    spapr->icp = xics_system_init(XICS_IRQS);
+
+    /* Set up VIO bus */
+    spapr->vio_bus = spapr_vio_bus_init();
+
+    for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
+        if (serial_hds[i]) {
+            spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i,
+                             serial_hds[i], xics_find_qirq(spapr->icp, irq),
+                             irq);
+        }
+    }
+
+    for (i = 0; i < nb_nics; i++, irq++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = qemu_strdup("ibmveth");
+        }
+
+        if (strcmp(nd->model, "ibmveth") == 0) {
+            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd,
+                              xics_find_qirq(spapr->icp, irq), irq);
+        } else {
+            fprintf(stderr, "pSeries (sPAPR) platform does not support "
+                    "NIC model '%s' (only ibmveth is supported)\n",
+                    nd->model);
+            exit(1);
+        }
+    }
+
+    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
+        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i,
+                           xics_find_qirq(spapr->icp, irq), irq);
+        irq++;
+    }
+
+    if (kernel_filename) {
+        uint64_t lowaddr = 0;
+
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+
+        spapr->entry_point = KERNEL_LOAD_ADDR;
+    } else {
+        if (ram_size < (MIN_RAM_SLOF << 20)) {
+            fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+                    "%ldM guest RAM\n", MIN_RAM_SLOF);
+            exit(1);
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin");
+        fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+        if (fw_size < 0) {
+            hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+            exit(1);
+        }
+        qemu_free(filename);
+        spapr->entry_point = 0x100;
+        initrd_base = 0;
+        initrd_size = 0;
+
+        /* SLOF will startup the secondary CPUs using RTAS,
+           rather than expecting a kexec() style entry */
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            env->halted = 1;
+        }
+    }
+
+    /* Prepare the device tree */
+    spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
+                                            initrd_base, initrd_size,
+                                            boot_device, kernel_cmdline,
+                                            pteg_shift + 7);
+    assert(spapr->fdt_skel != NULL);
+
+    qemu_register_reset(spapr_reset, spapr);
+}
+
+static QEMUMachine spapr_machine = {
+    .name = "pseries",
+    .desc = "pSeries Logical Partition (PAPR compliant)",
+    .init = ppc_spapr_init,
+    .max_cpus = MAX_CPUS,
+    .no_vga = 1,
+    .no_parallel = 1,
+    .use_scsi = 1,
+};
+
+static void spapr_machine_init(void)
+{
+    qemu_register_machine(&spapr_machine);
+}
+
+machine_init(spapr_machine_init);
diff --git a/qemu-0.15.x/hw/spapr.h b/qemu-0.15.x/hw/spapr.h
new file mode 100644
index 0000000..263691b
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr.h
@@ -0,0 +1,301 @@
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+struct VIOsPAPRBus;
+struct icp_state;
+
+typedef struct sPAPREnvironment {
+    struct VIOsPAPRBus *vio_bus;
+    struct icp_state *icp;
+
+    void *htab;
+    long htab_size;
+    target_phys_addr_t fdt_addr, rtas_addr;
+    long rtas_size;
+    void *fdt_skel;
+    target_ulong entry_point;
+} sPAPREnvironment;
+
+#define H_SUCCESS         0
+#define H_BUSY            1        /* Hardware busy -- retry later */
+#define H_CLOSED          2        /* Resource closed */
+#define H_NOT_AVAILABLE   3
+#define H_CONSTRAINED     4        /* Resource request constrained to max allowed */
+#define H_PARTIAL         5
+#define H_IN_PROGRESS     14       /* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE   16
+#define H_PENDING         17       /* returned from H_POLL_PENDING */
+#define H_CONTINUE        18       /* Returned from H_Join on success */
+#define H_LONG_BUSY_START_RANGE         9900  /* Start of long busy range */
+#define H_LONG_BUSY_ORDER_1_MSEC        9900  /* Long busy, hint that 1msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_MSEC       9901  /* Long busy, hint that 10msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_MSEC      9902  /* Long busy, hint that 100msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_1_SEC         9903  /* Long busy, hint that 1sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_SEC        9904  /* Long busy, hint that 10sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_SEC       9905  /* Long busy, hint that 100sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_END_RANGE           9905  /* End of long busy range */
+#define H_HARDWARE        -1       /* Hardware error */
+#define H_FUNCTION        -2       /* Function not supported */
+#define H_PRIVILEGE       -3       /* Caller not privileged */
+#define H_PARAMETER       -4       /* Parameter invalid, out-of-range or conflicting */
+#define H_BAD_MODE        -5       /* Illegal msr value */
+#define H_PTEG_FULL       -6       /* PTEG is full */
+#define H_NOT_FOUND       -7       /* PTE was not found" */
+#define H_RESERVED_DABR   -8       /* DABR address is reserved by the hypervisor on this processor" */
+#define H_NO_MEM          -9
+#define H_AUTHORITY       -10
+#define H_PERMISSION      -11
+#define H_DROPPED         -12
+#define H_SOURCE_PARM     -13
+#define H_DEST_PARM       -14
+#define H_REMOTE_PARM     -15
+#define H_RESOURCE        -16
+#define H_ADAPTER_PARM    -17
+#define H_RH_PARM         -18
+#define H_RCQ_PARM        -19
+#define H_SCQ_PARM        -20
+#define H_EQ_PARM         -21
+#define H_RT_PARM         -22
+#define H_ST_PARM         -23
+#define H_SIGT_PARM       -24
+#define H_TOKEN_PARM      -25
+#define H_MLENGTH_PARM    -27
+#define H_MEM_PARM        -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM       -30
+#define H_PORT_PARM       -31
+#define H_MCG_PARM        -32
+#define H_VL_PARM         -33
+#define H_TSIZE_PARM      -34
+#define H_TRACE_PARM      -35
+
+#define H_MASK_PARM       -37
+#define H_MCG_FULL        -38
+#define H_ALIAS_EXIST     -39
+#define H_P_COUNTER       -40
+#define H_TABLE_FULL      -41
+#define H_ALT_TABLE       -42
+#define H_MR_CONDITION    -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE         -45
+#define H_RESCINDEND      -46
+#define H_MULTI_THREADS_ACTIVE -9005
+
+
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later.  This prevents calls blocking in the
+ * firmware for long periods of time.  Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying.  If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_IS_LONG_BUSY(x)  ((x >= H_LONG_BUSY_START_RANGE) \
+                            && (x <= H_LONG_BUSY_END_RANGE))
+
+/* Flags */
+#define H_LARGE_PAGE      (1ULL<<(63-16))
+#define H_EXACT           (1ULL<<(63-24))       /* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE         (1ULL<<(63-25))       /* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4          (1ULL<<(63-26))       /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
+#define H_PAGE_UNUSED     ((1ULL<<(63-29)) | (1ULL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
+#define H_AVPN            (1ULL<<(63-32))       /* An avpn is provided as a sanity test */
+#define H_ANDCOND         (1ULL<<(63-33))
+#define H_ICACHE_INVALIDATE (1ULL<<(63-40))     /* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41))    /* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE       (1ULL<<(63-48))       /* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE       (1ULL<<(63-49))
+#define H_N               (1ULL<<(63-61))
+#define H_PP1             (1ULL<<(63-62))
+#define H_PP2             (1ULL<<(63-63))
+
+/* VASI States */
+#define H_VASI_INVALID    0
+#define H_VASI_ENABLED    1
+#define H_VASI_ABORTED    2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED  4
+#define H_VASI_RESUMED    5
+#define H_VASI_COMPLETED  6
+
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
+#define H_DABRX_KERNEL     (1ULL<<(63-62))
+#define H_DABRX_USER       (1ULL<<(63-63))
+
+/* Each control block has to be on a 4K bondary */
+#define H_CB_ALIGNMENT     4096
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE                0x04
+#define H_ENTER                 0x08
+#define H_READ                  0x0c
+#define H_CLEAR_MOD             0x10
+#define H_CLEAR_REF             0x14
+#define H_PROTECT               0x18
+#define H_GET_TCE               0x1c
+#define H_PUT_TCE               0x20
+#define H_SET_SPRG0             0x24
+#define H_SET_DABR              0x28
+#define H_PAGE_INIT             0x2c
+#define H_SET_ASR               0x30
+#define H_ASR_ON                0x34
+#define H_ASR_OFF               0x38
+#define H_LOGICAL_CI_LOAD       0x3c
+#define H_LOGICAL_CI_STORE      0x40
+#define H_LOGICAL_CACHE_LOAD    0x44
+#define H_LOGICAL_CACHE_STORE   0x48
+#define H_LOGICAL_ICBI          0x4c
+#define H_LOGICAL_DCBF          0x50
+#define H_GET_TERM_CHAR         0x54
+#define H_PUT_TERM_CHAR         0x58
+#define H_REAL_TO_LOGICAL       0x5c
+#define H_HYPERVISOR_DATA       0x60
+#define H_EOI                   0x64
+#define H_CPPR                  0x68
+#define H_IPI                   0x6c
+#define H_IPOLL                 0x70
+#define H_XIRR                  0x74
+#define H_PERFMON               0x7c
+#define H_MIGRATE_DMA           0x78
+#define H_REGISTER_VPA          0xDC
+#define H_CEDE                  0xE0
+#define H_CONFER                0xE4
+#define H_PROD                  0xE8
+#define H_GET_PPP               0xEC
+#define H_SET_PPP               0xF0
+#define H_PURR                  0xF4
+#define H_PIC                   0xF8
+#define H_REG_CRQ               0xFC
+#define H_FREE_CRQ              0x100
+#define H_VIO_SIGNAL            0x104
+#define H_SEND_CRQ              0x108
+#define H_COPY_RDMA             0x110
+#define H_REGISTER_LOGICAL_LAN  0x114
+#define H_FREE_LOGICAL_LAN      0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN      0x120
+#define H_BULK_REMOVE           0x124
+#define H_MULTICAST_CTRL        0x130
+#define H_SET_XDABR             0x134
+#define H_STUFF_TCE             0x138
+#define H_PUT_TCE_INDIRECT      0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+#define H_VTERM_PARTNER_INFO    0x150
+#define H_REGISTER_VTERM        0x154
+#define H_FREE_VTERM            0x158
+#define H_RESET_EVENTS          0x15C
+#define H_ALLOC_RESOURCE        0x160
+#define H_FREE_RESOURCE         0x164
+#define H_MODIFY_QP             0x168
+#define H_QUERY_QP              0x16C
+#define H_REREGISTER_PMR        0x170
+#define H_REGISTER_SMR          0x174
+#define H_QUERY_MR              0x178
+#define H_QUERY_MW              0x17C
+#define H_QUERY_HCA             0x180
+#define H_QUERY_PORT            0x184
+#define H_MODIFY_PORT           0x188
+#define H_DEFINE_AQP1           0x18C
+#define H_GET_TRACE_BUFFER      0x190
+#define H_DEFINE_AQP0           0x194
+#define H_RESIZE_MR             0x198
+#define H_ATTACH_MCQP           0x19C
+#define H_DETACH_MCQP           0x1A0
+#define H_CREATE_RPT            0x1A4
+#define H_REMOVE_RPT            0x1A8
+#define H_REGISTER_RPAGES       0x1AC
+#define H_DISABLE_AND_GETC      0x1B0
+#define H_ERROR_DATA            0x1B4
+#define H_GET_HCA_INFO          0x1B8
+#define H_GET_PERF_COUNT        0x1BC
+#define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+#define H_QUERY_INT_STATE       0x1E4
+#define H_POLL_PENDING          0x1D8
+#define H_ILLAN_ATTRIBUTES      0x244
+#define H_MODIFY_HEA_QP         0x250
+#define H_QUERY_HEA_QP          0x254
+#define H_QUERY_HEA             0x258
+#define H_QUERY_HEA_PORT        0x25C
+#define H_MODIFY_HEA_PORT       0x260
+#define H_REG_BCMC              0x264
+#define H_DEREG_BCMC            0x268
+#define H_REGISTER_HEA_RPAGES   0x26C
+#define H_DISABLE_AND_GET_HEA   0x270
+#define H_GET_HEA_INFO          0x274
+#define H_ALLOC_HEA_RESOURCE    0x278
+#define H_ADD_CONN              0x284
+#define H_DEL_CONN              0x288
+#define H_JOIN                  0x298
+#define H_VASI_STATE            0x2A4
+#define H_ENABLE_CRQ            0x2B0
+#define H_GET_EM_PARMS          0x2B8
+#define H_SET_MPP               0x2D0
+#define H_GET_MPP               0x2D4
+#define MAX_HCALL_OPCODE        H_GET_MPP
+
+/* The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * So far we just need one for H_RTAS, but in future we'll need more
+ * for extensions like virtio.  We put those into the 0xf000-0xfffc
+ * range which is reserved by PAPR for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_HCALL_MAX        KVMPPC_H_RTAS
+
+extern sPAPREnvironment *spapr;
+
+/*#define DEBUG_SPAPR_HCALLS*/
+
+#ifdef DEBUG_SPAPR_HCALLS
+#define hcall_dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define hcall_dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef target_ulong (*spapr_hcall_fn)(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode,
+                                       target_ulong *args);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
+                             target_ulong *args);
+
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+    return ldl_be_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+    stl_be_phys(phys + 4*n, val);
+}
+
+typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size);
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/qemu-0.15.x/hw/spapr_hcall.c b/qemu-0.15.x/hw/spapr_hcall.c
new file mode 100644
index 0000000..5cd8d8f
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_hcall.c
@@ -0,0 +1,519 @@
+#include "sysemu.h"
+#include "cpu.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "exec.h"
+#include "helper_regs.h"
+#include "hw/spapr.h"
+
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_SSIZE_SHIFT      62
+#define HPTE_V_AVPN_SHIFT       7
+#define HPTE_V_AVPN             0x3fffffffffffff80ULL
+#define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x, y)    (!(((x) ^ (y)) & 0xffffffffffffff80UL))
+#define HPTE_V_BOLTED           0x0000000000000010ULL
+#define HPTE_V_LOCK             0x0000000000000008ULL
+#define HPTE_V_LARGE            0x0000000000000004ULL
+#define HPTE_V_SECONDARY        0x0000000000000002ULL
+#define HPTE_V_VALID            0x0000000000000001ULL
+
+#define HPTE_R_PP0              0x8000000000000000ULL
+#define HPTE_R_TS               0x4000000000000000ULL
+#define HPTE_R_KEY_HI           0x3000000000000000ULL
+#define HPTE_R_RPN_SHIFT        12
+#define HPTE_R_RPN              0x3ffffffffffff000ULL
+#define HPTE_R_FLAGS            0x00000000000003ffULL
+#define HPTE_R_PP               0x0000000000000003ULL
+#define HPTE_R_N                0x0000000000000004ULL
+#define HPTE_R_G                0x0000000000000008ULL
+#define HPTE_R_M                0x0000000000000010ULL
+#define HPTE_R_I                0x0000000000000020ULL
+#define HPTE_R_W                0x0000000000000040ULL
+#define HPTE_R_WIMG             0x0000000000000078ULL
+#define HPTE_R_C                0x0000000000000080ULL
+#define HPTE_R_R                0x0000000000000100ULL
+#define HPTE_R_KEY_LO           0x0000000000000e00ULL
+
+#define HPTE_V_1TB_SEG          0x4000000000000000ULL
+#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
+
+#define HPTE_V_HVLOCK           0x40ULL
+
+static inline int lock_hpte(void *hpte, target_ulong bits)
+{
+    uint64_t pteh;
+
+    pteh = ldq_p(hpte);
+
+    /* We're protected by qemu's global lock here */
+    if (pteh & bits) {
+        return 0;
+    }
+    stq_p(hpte, pteh | HPTE_V_HVLOCK);
+    return 1;
+}
+
+static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
+                                     target_ulong pte_index)
+{
+    target_ulong rb, va_low;
+
+    rb = (v & ~0x7fULL) << 16; /* AVA field */
+    va_low = pte_index >> 3;
+    if (v & HPTE_V_SECONDARY) {
+        va_low = ~va_low;
+    }
+    /* xor vsid from AVA */
+    if (!(v & HPTE_V_1TB_SEG)) {
+        va_low ^= v >> 12;
+    } else {
+        va_low ^= v >> 24;
+    }
+    va_low &= 0x7ff;
+    if (v & HPTE_V_LARGE) {
+        rb |= 1;                         /* L field */
+#if 0 /* Disable that P7 specific bit for now */
+        if (r & 0xff000) {
+            /* non-16MB large page, must be 64k */
+            /* (masks depend on page size) */
+            rb |= 0x1000;                /* page encoding in LP field */
+            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
+            rb |= (va_low & 0xfe);       /* AVAL field */
+        }
+#endif
+    } else {
+        /* 4kB page */
+        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
+    }
+    rb |= (v >> 54) & 0x300;            /* B field */
+    return rb;
+}
+
+static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
+                            target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong pteh = args[2];
+    target_ulong ptel = args[3];
+    target_ulong i;
+    uint8_t *hpte;
+
+    /* only handle 4k and 16M pages for now */
+    if (pteh & HPTE_V_LARGE) {
+#if 0 /* We don't support 64k pages yet */
+        if ((ptel & 0xf000) == 0x1000) {
+            /* 64k page */
+        } else
+#endif
+        if ((ptel & 0xff000) == 0) {
+            /* 16M page */
+            /* lowest AVA bit must be 0 for 16M pages */
+            if (pteh & 0x80) {
+                return H_PARAMETER;
+            }
+        } else {
+            return H_PARAMETER;
+        }
+    }
+
+    /* FIXME: bounds check the pa? */
+
+    /* Check WIMG */
+    if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
+        return H_PARAMETER;
+    }
+    pteh &= ~0x60ULL;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+    if (likely((flags & H_EXACT) == 0)) {
+        pte_index &= ~7ULL;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        for (i = 0; ; ++i) {
+            if (i == 8) {
+                return H_PTEG_FULL;
+            }
+            if (((ldq_p(hpte) & HPTE_V_VALID) == 0) &&
+                lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+                break;
+            }
+            hpte += HASH_PTE_SIZE_64;
+        }
+    } else {
+        i = 0;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+            return H_PTEG_FULL;
+        }
+    }
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
+    /* eieio();  FIXME: need some sort of barrier for smp? */
+    stq_p(hpte, pteh);
+
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    args[0] = pte_index + i;
+    return H_SUCCESS;
+}
+
+static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
+        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+    args[0] = v & ~HPTE_V_HVLOCK;
+    args[1] = r;
+    stq_p(hpte, 0);
+    rb = compute_tlbie_rb(v, r, pte_index);
+    ppc_tlb_invalidate_one(env, rb);
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
+static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+
+    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
+           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
+    r |= (flags << 55) & HPTE_R_PP0;
+    r |= (flags << 48) & HPTE_R_KEY_HI;
+    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+    rb = compute_tlbie_rb(v, r, pte_index);
+    stq_p(hpte, v & ~HPTE_V_VALID);
+    ppc_tlb_invalidate_one(env, rb);
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
+    /* Don't need a memory barrier, due to qemu's global lock */
+    stq_p(hpte, v & ~HPTE_V_HVLOCK);
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
+static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    /* FIXME: actually implement this */
+    return H_HARDWARE;
+}
+
+#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
+#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
+#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
+#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
+#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
+#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
+
+#define VPA_MIN_SIZE           640
+#define VPA_SIZE_OFFSET        0x4
+#define VPA_SHARED_PROC_OFFSET 0x9
+#define VPA_SHARED_PROC_VAL    0x2
+
+static target_ulong register_vpa(CPUState *env, target_ulong vpa)
+{
+    uint16_t size;
+    uint8_t tmp;
+
+    if (vpa == 0) {
+        hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    if (vpa % env->dcache_line_size) {
+        return H_PARAMETER;
+    }
+    /* FIXME: bounds check the address */
+
+    size = lduw_be_phys(vpa + 0x4);
+
+    if (size < VPA_MIN_SIZE) {
+        return H_PARAMETER;
+    }
+
+    /* VPA is not allowed to cross a page boundary */
+    if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    env->vpa = vpa;
+
+    tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET);
+    tmp |= VPA_SHARED_PROC_VAL;
+    stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp);
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_vpa(CPUState *env, target_ulong vpa)
+{
+    if (env->slb_shadow) {
+        return H_RESOURCE;
+    }
+
+    if (env->dispatch_trace_log) {
+        return H_RESOURCE;
+    }
+
+    env->vpa = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_be_phys(addr + 0x4);
+    if (size < 0x8) {
+        return H_PARAMETER;
+    }
+
+    if ((addr / 4096) != ((addr + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->slb_shadow = addr;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr)
+{
+    env->slb_shadow = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_dtl(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        hcall_dprintf("Can't cope with DTL at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_be_phys(addr + 0x4);
+
+    if (size < 48) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->dispatch_trace_log = addr;
+    env->dtl_size = size;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_dtl(CPUState *emv, target_ulong addr)
+{
+    env->dispatch_trace_log = 0;
+    env->dtl_size = 0;
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong procno = args[1];
+    target_ulong vpa = args[2];
+    target_ulong ret = H_PARAMETER;
+    CPUState *tenv;
+
+    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
+        if (tenv->cpu_index == procno) {
+            break;
+        }
+    }
+
+    if (!tenv) {
+        return H_PARAMETER;
+    }
+
+    switch (flags) {
+    case FLAGS_REGISTER_VPA:
+        ret = register_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_VPA:
+        ret = deregister_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_SLBSHADOW:
+        ret = register_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_SLBSHADOW:
+        ret = deregister_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_DTL:
+        ret = register_dtl(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_DTL:
+        ret = deregister_dtl(tenv, vpa);
+        break;
+    }
+
+    return ret;
+}
+
+static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    env->msr |= (1ULL << MSR_EE);
+    hreg_compute_hflags(env);
+    if (!cpu_has_work(env)) {
+        env->halted = 1;
+    }
+    return H_SUCCESS;
+}
+
+static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong rtas_r3 = args[0];
+    uint32_t token = ldl_be_phys(rtas_r3);
+    uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
+    uint32_t nret = ldl_be_phys(rtas_r3 + 8);
+
+    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+                           nret, rtas_r3 + 12 + 4*nargs);
+}
+
+static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
+{
+    spapr_hcall_fn *slot;
+
+    if (opcode <= MAX_HCALL_OPCODE) {
+        assert((opcode & 0x3) == 0);
+
+        slot = &papr_hypercall_table[opcode / 4];
+    } else {
+        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
+
+
+        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+    }
+
+    assert(!(*slot) || (fn == *slot));
+    *slot = fn;
+}
+
+target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
+                             target_ulong *args)
+{
+    if (msr_pr) {
+        hcall_dprintf("Hypercall made with MSR[PR]=1\n");
+        return H_PRIVILEGE;
+    }
+
+    if ((opcode <= MAX_HCALL_OPCODE)
+        && ((opcode & 0x3) == 0)) {
+        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
+
+        if (fn) {
+            return fn(env, spapr, opcode, args);
+        }
+    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
+               (opcode <= KVMPPC_HCALL_MAX)) {
+        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+
+        if (fn) {
+            return fn(env, spapr, opcode, args);
+        }
+    }
+
+    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
+    return H_FUNCTION;
+}
+
+static void hypercall_init(void)
+{
+    /* hcall-pft */
+    spapr_register_hypercall(H_ENTER, h_enter);
+    spapr_register_hypercall(H_REMOVE, h_remove);
+    spapr_register_hypercall(H_PROTECT, h_protect);
+
+    /* hcall-dabr */
+    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+
+    /* hcall-splpar */
+    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
+    spapr_register_hypercall(H_CEDE, h_cede);
+
+    /* qemu/KVM-PPC specific hcalls */
+    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+}
+device_init(hypercall_init);
diff --git a/qemu-0.15.x/hw/spapr_llan.c b/qemu-0.15.x/hw/spapr_llan.c
new file mode 100644
index 0000000..c18efc7
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_llan.c
@@ -0,0 +1,515 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Inter-VM Logical Lan, aka ibmveth
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw.h"
+#include "net.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define ETH_ALEN        6
+#define MAX_PACKET_SIZE 65536
+
+/*#define DEBUG*/
+
+#ifdef DEBUG
+#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
+#else
+#define dprintf(fmt...)
+#endif
+
+/*
+ * Virtual LAN device
+ */
+
+typedef uint64_t vlan_bd_t;
+
+#define VLAN_BD_VALID        0x8000000000000000ULL
+#define VLAN_BD_TOGGLE       0x4000000000000000ULL
+#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
+#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
+#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
+#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
+#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
+#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
+
+#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
+                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
+                                  (addr & VLAN_BD_ADDR_MASK))
+
+#define VLAN_RXQC_TOGGLE     0x80
+#define VLAN_RXQC_VALID      0x40
+#define VLAN_RXQC_NO_CSUM    0x02
+#define VLAN_RXQC_CSUM_GOOD  0x01
+
+#define VLAN_RQ_ALIGNMENT    16
+#define VLAN_RXQ_BD_OFF      0
+#define VLAN_FILTER_BD_OFF   8
+#define VLAN_RX_BDS_OFF      16
+#define VLAN_MAX_BUFS        ((SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
+
+typedef struct VIOsPAPRVLANDevice {
+    VIOsPAPRDevice sdev;
+    NICConf nicconf;
+    NICState *nic;
+    int isopen;
+    target_ulong buf_list;
+    int add_buf_ptr, use_buf_ptr, rx_bufs;
+    target_ulong rxq_ptr;
+} VIOsPAPRVLANDevice;
+
+static int spapr_vlan_can_receive(VLANClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    return (dev->isopen && dev->rx_bufs > 0);
+}
+
+static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque;
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t rxq_bd = ldq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
+    vlan_bd_t bd;
+    int buf_ptr = dev->use_buf_ptr;
+    uint64_t handle;
+    uint8_t control;
+
+    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
+            dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return -1;
+    }
+
+    if (!dev->rx_bufs) {
+        return -1;
+    }
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + buf_ptr);
+        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
+             && (buf_ptr != dev->use_buf_ptr));
+
+    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
+        /* Failed to find a suitable buffer */
+        return -1;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->rx_bufs--;
+    dev->use_buf_ptr = buf_ptr;
+    stq_tce(sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    /* Transfer the packet data */
+    if (spapr_tce_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
+        return -1;
+    }
+
+    dprintf("spapr_vlan_receive: DMA write completed\n");
+
+    /* Update the receive queue */
+    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
+    if (rxq_bd & VLAN_BD_TOGGLE) {
+        control ^= VLAN_RXQC_TOGGLE;
+    }
+
+    handle = ldq_tce(sdev, VLAN_BD_ADDR(bd));
+    stq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
+    stw_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
+    sth_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
+    stb_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
+
+    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
+            (unsigned long long)dev->rxq_ptr,
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr),
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr + 8));
+
+    dev->rxq_ptr += 16;
+    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
+        dev->rxq_ptr = 0;
+        stq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
+    }
+
+    if (sdev->signal_state & 1) {
+        qemu_irq_pulse(sdev->qirq);
+    }
+
+    return size;
+}
+
+static NetClientInfo net_spapr_vlan_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = spapr_vlan_can_receive,
+    .receive = spapr_vlan_receive,
+};
+
+static int spapr_vlan_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
+
+    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
+                            sdev->qdev.info->name, sdev->qdev.id, dev);
+    qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
+
+    return 0;
+}
+
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
+    uint8_t padded_mac[8] = {0, 0};
+    int ret;
+
+    /* Some old phyp versions give the mac address in an 8-byte
+     * property.  The kernel driver has an insane workaround for this;
+     * rather than doing the obvious thing and checking the property
+     * length, it checks whether the first byte has 0b10 in the low
+     * bits.  If a correct 6-byte property has a different first byte
+     * the kernel will get the wrong mac address, overrunning its
+     * buffer in the process (read only, thank goodness).
+     *
+     * Here we workaround the kernel workaround by always supplying an
+     * 8-byte property, with the mac address in the last six bytes */
+    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
+    ret = fdt_setprop(fdt, node_off, "local-mac-address",
+                      padded_mac, sizeof(padded_mac));
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
+                    target_ulong alignment)
+{
+    if ((VLAN_BD_ADDR(bd) % alignment)
+        || (VLAN_BD_LEN(bd) % alignment)) {
+        return -1;
+    }
+
+    if (spapr_vio_check_tces(&dev->sdev, VLAN_BD_ADDR(bd),
+                             VLAN_BD_LEN(bd), SPAPR_TCE_RW) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static target_ulong h_register_logical_lan(CPUState *env,
+                                           sPAPREnvironment *spapr,
+                                           target_ulong opcode,
+                                           target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf_list = args[1];
+    target_ulong rec_queue = args[2];
+    target_ulong filter_list = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t filter_list_bd;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (dev->isopen) {
+        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
+                      "H_FREE_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
+                 SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
+                      "H_REGISTER_LOGICAL_LAN\n", buf_list);
+        return H_PARAMETER;
+    }
+
+    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
+    if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
+                      "H_REGISTER_LOGICAL_LAN\n", filter_list);
+        return H_PARAMETER;
+    }
+
+    if (!(rec_queue & VLAN_BD_VALID)
+        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
+        hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
+        return H_PARAMETER;
+    }
+
+    dev->buf_list = buf_list;
+    sdev->signal_state = 0;
+
+    rec_queue &= ~VLAN_BD_TOGGLE;
+
+    /* Initialize the buffer list */
+    stq_tce(sdev, buf_list, rec_queue);
+    stq_tce(sdev, buf_list + 8, filter_list_bd);
+    spapr_tce_dma_zero(sdev, buf_list + VLAN_RX_BDS_OFF,
+                       SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
+    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->rx_bufs = 0;
+    dev->rxq_ptr = 0;
+
+    /* Initialize the receive queue */
+    spapr_tce_dma_zero(sdev, VLAN_BD_ADDR(rec_queue), VLAN_BD_LEN(rec_queue));
+
+    dev->isopen = 1;
+    return H_SUCCESS;
+}
+
+
+static target_ulong h_free_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen) {
+        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
+                      "H_REGISTER_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    dev->buf_list = 0;
+    dev->rx_bufs = 0;
+    dev->isopen = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong h_add_logical_lan_buffer(CPUState *env,
+                                             sPAPREnvironment *spapr,
+                                             target_ulong opcode,
+                                             target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf = args[1];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t bd;
+
+    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
+            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
+
+    if (!sdev) {
+        hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
+        return H_PARAMETER;
+    }
+
+    if ((check_bd(dev, buf, 4) < 0)
+        || (VLAN_BD_LEN(buf) < 16)) {
+        hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n");
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    stq_tce(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    dev->rx_bufs++;
+
+    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
+            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
+            (unsigned long long)buf);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *bufs = args + 1;
+    target_ulong continue_token = args[7];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    unsigned total_len;
+    uint8_t *lbuf, *p;
+    int i, nbufs;
+    int ret;
+
+    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
+            TARGET_FMT_lx ")\n", reg, continue_token);
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    dprintf("rxbufs = %d\n", dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return H_DROPPED;
+    }
+
+    if (continue_token) {
+        return H_HARDWARE; /* FIXME actually handle this */
+    }
+
+    total_len = 0;
+    for (i = 0; i < 6; i++) {
+        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
+        if (!(bufs[i] & VLAN_BD_VALID)) {
+            break;
+        }
+        total_len += VLAN_BD_LEN(bufs[i]);
+    }
+
+    nbufs = i;
+    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
+            nbufs, total_len);
+
+    if (total_len == 0) {
+        return H_SUCCESS;
+    }
+
+    if (total_len > MAX_PACKET_SIZE) {
+        /* Don't let the guest force too large an allocation */
+        return H_RESOURCE;
+    }
+
+    lbuf = alloca(total_len);
+    p = lbuf;
+    for (i = 0; i < nbufs; i++) {
+        ret = spapr_tce_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
+                                 p, VLAN_BD_LEN(bufs[i]));
+        if (ret < 0) {
+            return ret;
+        }
+
+        p += VLAN_BD_LEN(bufs[i]);
+    }
+
+    qemu_send_packet(&dev->nic->nc, lbuf, total_len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
+                                     target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    return H_SUCCESS;
+}
+
+static void vlan_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
+    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
+    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
+    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
+                             h_add_logical_lan_buffer);
+    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+}
+
+static VIOsPAPRDeviceInfo spapr_vlan = {
+    .init = spapr_vlan_init,
+    .devnode = spapr_vlan_devnode,
+    .dt_name = "l-lan",
+    .dt_type = "network",
+    .dt_compatible = "IBM,l-lan",
+    .signal_mask = 0x1,
+    .hcalls = vlan_hcalls,
+    .qdev.name = "spapr-vlan",
+    .qdev.size = sizeof(VIOsPAPRVLANDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size,
+                           0x10000000),
+        DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vlan_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vlan);
+}
+device_init(spapr_vlan_register);
diff --git a/qemu-0.15.x/hw/spapr_rtas.c b/qemu-0.15.x/hw/spapr_rtas.c
new file mode 100644
index 0000000..00c8ce5
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_rtas.c
@@ -0,0 +1,279 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Hypercall based emulated RTAS
+ *
+ * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
+ *
+ * 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 "cpu.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "hw/qdev.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define TOKEN_BASE      0x2000
+#define TOKEN_MAX       0x100
+
+static void rtas_display_character(sPAPREnvironment *spapr,
+                                   uint32_t token, uint32_t nargs,
+                                   target_ulong args,
+                                   uint32_t nret, target_ulong rets)
+{
+    uint8_t c = rtas_ld(args, 0);
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
+                                                 SPAPR_VTY_BASE_ADDRESS);
+
+    if (!sdev) {
+        rtas_st(rets, 0, -1);
+    } else {
+        vty_putchars(sdev, &c, sizeof(c));
+        rtas_st(rets, 0, 0);
+    }
+}
+
+static void rtas_get_time_of_day(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    struct tm tm;
+
+    if (nret != 8) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    qemu_get_timedate(&tm, 0);
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, tm.tm_year + 1900);
+    rtas_st(rets, 2, tm.tm_mon + 1);
+    rtas_st(rets, 3, tm.tm_mday);
+    rtas_st(rets, 4, tm.tm_hour);
+    rtas_st(rets, 5, tm.tm_min);
+    rtas_st(rets, 6, tm.tm_sec);
+    rtas_st(rets, 7, 0); /* we don't do nanoseconds */
+}
+
+static void rtas_power_off(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs, target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    if (nargs != 2 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    qemu_system_shutdown_request();
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
+                                         uint32_t token, uint32_t nargs,
+                                         target_ulong args,
+                                         uint32_t nret, target_ulong rets)
+{
+    target_ulong id;
+    CPUState *env;
+
+    if (nargs != 1 || nret != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (env->halted) {
+            rtas_st(rets, 1, 0);
+        } else {
+            rtas_st(rets, 1, 2);
+        }
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
+static void rtas_start_cpu(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs,
+                           target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    target_ulong id, start, r3;
+    CPUState *env;
+
+    if (nargs != 3 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    start = rtas_ld(args, 1);
+    r3 = rtas_ld(args, 2);
+
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (!env->halted) {
+            rtas_st(rets, 0, -1);
+            return;
+        }
+
+        env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+        env->nip = start;
+        env->gpr[3] = r3;
+        env->halted = 0;
+
+        qemu_cpu_kick(env);
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
+static struct rtas_call {
+    const char *name;
+    spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+    if ((token >= TOKEN_BASE)
+        && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+        struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+        if (call->fn) {
+            call->fn(spapr, token, nargs, args, nret, rets);
+            return H_SUCCESS;
+        }
+    }
+
+    /* HACK: Some Linux early debug code uses RTAS display-character,
+     * but assumes the token value is 0xa (which it is on some real
+     * machines) without looking it up in the device tree.  This
+     * special case makes this work */
+    if (token == 0xa) {
+        rtas_display_character(spapr, 0xa, nargs, args, nret, rets);
+        return H_SUCCESS;
+    }
+
+    hcall_dprintf("Unknown RTAS token 0x%x\n", token);
+    rtas_st(rets, 0, -3);
+    return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+    assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+    rtas_next->name = name;
+    rtas_next->fn = fn;
+
+    rtas_next++;
+}
+
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size)
+{
+    int ret;
+    int i;
+
+    ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size",
+                                    rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add rtas-size property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    for (i = 0; i < TOKEN_MAX; i++) {
+        struct rtas_call *call = &rtas_table[i];
+
+        if (!call->fn) {
+            continue;
+        }
+
+        ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name,
+                                        i + TOKEN_BASE);
+        if (ret < 0) {
+            fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
+                    call->name, fdt_strerror(ret));
+            return ret;
+        }
+
+    }
+    return 0;
+}
+
+static void register_core_rtas(void)
+{
+    spapr_rtas_register("display-character", rtas_display_character);
+    spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+    spapr_rtas_register("power-off", rtas_power_off);
+    spapr_rtas_register("query-cpu-stopped-state",
+                        rtas_query_cpu_stopped_state);
+    spapr_rtas_register("start-cpu", rtas_start_cpu);
+}
+device_init(register_core_rtas);
diff --git a/qemu-0.15.x/hw/spapr_vio.c b/qemu-0.15.x/hw/spapr_vio.c
new file mode 100644
index 0000000..481a804
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_vio.c
@@ -0,0 +1,731 @@
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg at au1.ibm.com>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "device_tree.h"
+#include "kvm_ppc.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#ifdef CONFIG_FDT
+#include <libfdt.h>
+#endif /* CONFIG_FDT */
+
+/* #define DEBUG_SPAPR */
+/* #define DEBUG_TCE */
+
+#ifdef DEBUG_SPAPR
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static struct BusInfo spapr_vio_bus_info = {
+    .name       = "spapr-vio",
+    .size       = sizeof(VIOsPAPRBus),
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        if (dev->reg == reg) {
+            break;
+        }
+    }
+
+    return dev;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+                            void *fdt)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    int vdevice_off, node_off;
+    int ret;
+
+    vdevice_off = fdt_path_offset(fdt, "/vdevice");
+    if (vdevice_off < 0) {
+        return vdevice_off;
+    }
+
+    node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
+    if (node_off < 0) {
+        return node_off;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (info->dt_type) {
+        ret = fdt_setprop_string(fdt, node_off, "device_type",
+                                 info->dt_type);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->dt_compatible) {
+        ret = fdt_setprop_string(fdt, node_off, "compatible",
+                                 info->dt_compatible);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (dev->qirq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+
+        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+                          sizeof(ints_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (dev->rtce_window_size) {
+        uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
+                               0, 0,
+                               0, cpu_to_be32(dev->rtce_window_size)};
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
+                          sizeof(dma_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->devnode) {
+        ret = (info->devnode)(dev, fdt, node_off);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return node_off;
+}
+#endif /* CONFIG_FDT */
+
+/*
+ * RTCE handling
+ */
+
+static void rtce_init(VIOsPAPRDevice *dev)
+{
+    size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+        * sizeof(VIOsPAPR_RTCE);
+
+    if (size) {
+        dev->rtce_table = qemu_mallocz(size);
+    }
+}
+
+static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong liobn = args[0];
+    target_ulong ioba = args[1];
+    target_ulong tce = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
+    VIOsPAPR_RTCE *rtce;
+
+    if (!dev) {
+        hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
+                      TARGET_FMT_lx "\n", liobn);
+        return H_PARAMETER;
+    }
+
+    ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_vio_put_tce on %s  ioba 0x" TARGET_FMT_lx
+            "  TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
+#endif
+
+    if (ioba >= dev->rtce_window_size) {
+        hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
+                      TARGET_FMT_lx "\n", ioba);
+        return H_PARAMETER;
+    }
+
+    rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
+    rtce->tce = tce;
+
+    return H_SUCCESS;
+}
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len, enum VIOsPAPR_TCEAccess access)
+{
+    int start, end, i;
+
+    start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
+    end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
+
+    for (i = start; i <= end; i++) {
+        if ((dev->rtce_table[i].tce & access) != access) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "FAIL on %d\n", i);
+#endif
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
+                        uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_write(taddr, buf, size);
+        return 0;
+    }
+
+    while (size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
+#endif
+            return H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 2)) {
+            return H_DEST_PARM;
+        }
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
+            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+
+        /* Do it */
+        cpu_physical_memory_write(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return 0;
+}
+
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
+{
+    /* FIXME: allocating a temp buffer is nasty, but just stepping
+     * through writing zeroes is awkward.  This will do for now. */
+    uint8_t zeroes[size];
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    memset(zeroes, 0, size);
+    return spapr_tce_dma_write(dev, taddr, zeroes, size);
+}
+
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
+{
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
+{
+    val = tswap16(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
+{
+    val = tswap32(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
+{
+    val = tswap64(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
+                       uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_read(taddr, buf, size);
+        return 0;
+    }
+
+    while (size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
+#endif
+            return H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 1)) {
+            return H_DEST_PARM;
+        }
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
+            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+        /* Do it */
+        cpu_physical_memory_read(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return H_SUCCESS;
+}
+
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
+{
+    uint64_t val;
+
+    spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
+    return tswap64(val);
+}
+
+/*
+ * CRQ handling
+ */
+static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong queue_addr = args[1];
+    target_ulong queue_len = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("h_reg_crq on non-existent unit 0x"
+                      TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    /* We can't grok a queue size bigger than 256M for now */
+    if (queue_len < 0x1000 || queue_len > 0x10000000) {
+        hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
+                      (unsigned long long)queue_len);
+        return H_PARAMETER;
+    }
+
+    /* Check queue alignment */
+    if (queue_addr & 0xfff) {
+        hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
+                      (unsigned long long)queue_addr);
+        return H_PARAMETER;
+    }
+
+    /* Check if device supports CRQs */
+    if (!dev->crq.SendFunc) {
+        return H_NOT_FOUND;
+    }
+
+
+    /* Already a queue ? */
+    if (dev->crq.qsize) {
+        return H_RESOURCE;
+    }
+    dev->crq.qladdr = queue_addr;
+    dev->crq.qsize = queue_len;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
+            TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
+            reg, queue_addr, queue_len);
+    return H_SUCCESS;
+}
+
+static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("h_free_crq on non-existent unit 0x"
+                      TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong msg_hi = args[1];
+    target_ulong msg_lo = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint64_t crq_mangle[2];
+
+    if (!dev) {
+        hcall_dprintf("h_send_crq on non-existent unit 0x"
+                      TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+    crq_mangle[0] = cpu_to_be64(msg_hi);
+    crq_mangle[1] = cpu_to_be64(msg_lo);
+
+    if (dev->crq.SendFunc) {
+        return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
+    }
+
+    return H_HARDWARE;
+}
+
+static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("h_enable_crq on non-existent unit 0x"
+                      TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    return 0;
+}
+
+/* Returns negative error, 0 success, or positive: queue full */
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
+{
+    int rc;
+    uint8_t byte;
+
+    if (!dev->crq.qsize) {
+        fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
+        return -1;
+    }
+
+    /* Maybe do a fast path for KVM just writing to the pages */
+    rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
+    if (rc) {
+        return rc;
+    }
+    if (byte != 0) {
+        return 1;
+    }
+
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
+                             &crq[8], 8);
+    if (rc) {
+        return rc;
+    }
+
+    kvmppc_eieio();
+
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
+    if (rc) {
+        return rc;
+    }
+
+    dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
+
+    if (dev->signal_state & 1) {
+        qemu_irq_pulse(dev->qirq);
+    }
+
+    return 0;
+}
+
+/* "quiesce" handling */
+
+static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+{
+    dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+
+    if (dev->rtce_table) {
+        size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+            * sizeof(VIOsPAPR_RTCE);
+        memset(dev->rtce_table, 0, size);
+    }
+
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+}
+
+static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
+                                uint32_t nargs, target_ulong args,
+                                uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    VIOsPAPRDevice *dev;
+    uint32_t unit, enable;
+
+    if (nargs != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    unit = rtas_ld(args, 0);
+    enable = rtas_ld(args, 1);
+    dev = spapr_vio_find_by_reg(bus, unit);
+    if (!dev) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    if (enable) {
+        dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS;
+    } else {
+        dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    if (nargs != 0) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        spapr_vio_quiesce_one(dev);
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
+    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+    char *id;
+
+    if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
+        return -1;
+    }
+
+    dev->qdev.id = id;
+
+    rtce_init(dev);
+
+    return info->init(dev);
+}
+
+void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
+{
+    info->qdev.init = spapr_vio_busdev_init;
+    info->qdev.bus_info = &spapr_vio_bus_info;
+
+    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
+    qdev_register(&info->qdev);
+}
+
+static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode,
+                                 target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong mode = args[1];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRDeviceInfo *info;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+
+    if (mode & ~info->signal_mask) {
+        return H_PARAMETER;
+    }
+
+    dev->signal_state = mode;
+
+    return H_SUCCESS;
+}
+
+VIOsPAPRBus *spapr_vio_bus_init(void)
+{
+    VIOsPAPRBus *bus;
+    BusState *qbus;
+    DeviceState *dev;
+    DeviceInfo *qinfo;
+
+    /* Create bridge device */
+    dev = qdev_create(NULL, "spapr-vio-bridge");
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+
+    qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
+    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
+
+    /* hcall-vio */
+    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
+    /* hcall-tce */
+    spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+
+    /* hcall-crq */
+    spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
+    spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
+    spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
+    spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
+
+    /* RTAS calls */
+    spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
+    spapr_rtas_register("quiesce", rtas_quiesce);
+
+    for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
+        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
+
+        if (qinfo->bus_info != &spapr_vio_bus_info) {
+            continue;
+        }
+
+        if (info->hcalls) {
+            info->hcalls(bus);
+        }
+    }
+
+    return bus;
+}
+
+/* Represents sPAPR hcall VIO devices */
+
+static int spapr_vio_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static SysBusDeviceInfo spapr_vio_bridge_info = {
+    .init = spapr_vio_bridge_init,
+    .qdev.name  = "spapr-vio-bridge",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.no_user = 1,
+};
+
+static void spapr_vio_register_devices(void)
+{
+    sysbus_register_withprop(&spapr_vio_bridge_info);
+}
+
+device_init(spapr_vio_register_devices)
+
+#ifdef CONFIG_FDT
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+    DeviceState *qdev;
+    int ret = 0;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+
+        ret = vio_make_devnode(dev, fdt);
+
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return 0;
+}
+#endif /* CONFIG_FDT */
diff --git a/qemu-0.15.x/hw/spapr_vio.h b/qemu-0.15.x/hw/spapr_vio.h
new file mode 100644
index 0000000..603a8c4
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_vio.h
@@ -0,0 +1,114 @@
+#ifndef _HW_SPAPR_VIO_H
+#define _HW_SPAPR_VIO_H
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david at gibson.dropbear.id.au>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define SPAPR_VIO_TCE_PAGE_SHIFT   12
+#define SPAPR_VIO_TCE_PAGE_SIZE    (1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
+#define SPAPR_VIO_TCE_PAGE_MASK    (SPAPR_VIO_TCE_PAGE_SIZE - 1)
+
+enum VIOsPAPR_TCEAccess {
+    SPAPR_TCE_FAULT = 0,
+    SPAPR_TCE_RO = 1,
+    SPAPR_TCE_WO = 2,
+    SPAPR_TCE_RW = 3,
+};
+
+#define SPAPR_VTY_BASE_ADDRESS     0x30000000
+
+struct VIOsPAPRDevice;
+
+typedef struct VIOsPAPR_RTCE {
+    uint64_t tce;
+} VIOsPAPR_RTCE;
+
+typedef struct VIOsPAPR_CRQ {
+    uint64_t qladdr;
+    uint32_t qsize;
+    uint32_t qnext;
+    int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
+} VIOsPAPR_CRQ;
+
+typedef struct VIOsPAPRDevice {
+    DeviceState qdev;
+    uint32_t reg;
+    uint32_t flags;
+#define VIO_PAPR_FLAG_DMA_BYPASS        0x1
+    qemu_irq qirq;
+    uint32_t vio_irq_num;
+    target_ulong signal_state;
+    uint32_t rtce_window_size;
+    VIOsPAPR_RTCE *rtce_table;
+    VIOsPAPR_CRQ crq;
+} VIOsPAPRDevice;
+
+typedef struct VIOsPAPRBus {
+    BusState bus;
+} VIOsPAPRBus;
+
+typedef struct {
+    DeviceInfo qdev;
+    const char *dt_name, *dt_type, *dt_compatible;
+    target_ulong signal_mask;
+    int (*init)(VIOsPAPRDevice *dev);
+    void (*hcalls)(VIOsPAPRBus *bus);
+    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceInfo;
+
+extern VIOsPAPRBus *spapr_vio_bus_init(void);
+extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
+extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
+extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
+
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len,
+                         enum VIOsPAPR_TCEAccess access);
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+                       void *buf, uint32_t size);
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+                        const void *buf, uint32_t size);
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size);
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val);
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val);
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val);
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val);
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
+
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num);
+
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num);
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num);
+
+int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
+void spapr_vio_quiesce(void);
+
+#endif /* _HW_SPAPR_VIO_H */
diff --git a/qemu-0.15.x/hw/spapr_vscsi.c b/qemu-0.15.x/hw/spapr_vscsi.c
new file mode 100644
index 0000000..646b1e3
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_vscsi.c
@@ -0,0 +1,999 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual SCSI, aka ibmvscsi
+ *
+ * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ *  - Cleanups :-)
+ *  - Sort out better how to assign devices to VSCSI instances
+ *  - Fix residual counts
+ *  - Add indirect descriptors support
+ *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
+ */
+#include "hw.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "net.h" /* Remove that when we can */
+#include "srp.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/ppc-viosrp.h"
+
+#include <libfdt.h>
+
+/*#define DEBUG_VSCSI*/
+
+#ifdef DEBUG_VSCSI
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+/*
+ * Virtual SCSI device
+ */
+
+/* Random numbers */
+#define VSCSI_MAX_SECTORS       4096
+#define VSCSI_REQ_LIMIT         24
+
+#define SCSI_SENSE_BUF_SIZE     96
+#define SRP_RSP_SENSE_DATA_LEN  18
+
+typedef union vscsi_crq {
+    struct viosrp_crq s;
+    uint8_t raw[16];
+} vscsi_crq;
+
+typedef struct vscsi_req {
+    vscsi_crq               crq;
+    union viosrp_iu         iu;
+
+    /* SCSI request tracking */
+    SCSIRequest             *sreq;
+    uint32_t                qtag; /* qemu tag != srp tag */
+    int                     lun;
+    int                     active;
+    long                    data_len;
+    int                     writing;
+    int                     sensing;
+    int                     senselen;
+    uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
+
+    /* RDMA related bits */
+    uint8_t                 dma_fmt;
+    struct srp_direct_buf   ext_desc;
+    struct srp_direct_buf   *cur_desc;
+    struct srp_indirect_buf *ind_desc;
+    int                     local_desc;
+    int                     total_desc;
+} vscsi_req;
+
+
+typedef struct {
+    VIOsPAPRDevice vdev;
+    SCSIBus bus;
+    vscsi_req reqs[VSCSI_REQ_LIMIT];
+} VSCSIState;
+
+/* XXX Debug only */
+static VSCSIState *dbg_vscsi_state;
+
+
+static struct vscsi_req *vscsi_get_req(VSCSIState *s)
+{
+    vscsi_req *req;
+    int i;
+
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        req = &s->reqs[i];
+        if (!req->active) {
+            memset(req, 0, sizeof(*req));
+            req->qtag = i;
+            req->active = 1;
+            return req;
+        }
+    }
+    return NULL;
+}
+
+static void vscsi_put_req(vscsi_req *req)
+{
+    if (req->sreq != NULL) {
+        scsi_req_unref(req->sreq);
+    }
+    req->sreq = NULL;
+    req->active = 0;
+}
+
+static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
+{
+    /* XXX Figure that one out properly ! This is crackpot */
+    *id = (srp_lun >> 56) & 0x7f;
+    *lun = (srp_lun >> 48) & 0xff;
+}
+
+static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
+                         uint64_t length, uint8_t format)
+{
+    long rc, rc1;
+
+    /* First copy the SRP */
+    rc = spapr_tce_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
+                             &req->iu, length);
+    if (rc) {
+        fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
+    }
+
+    req->crq.s.valid = 0x80;
+    req->crq.s.format = format;
+    req->crq.s.reserved = 0x00;
+    req->crq.s.timeout = cpu_to_be16(0x0000);
+    req->crq.s.IU_length = cpu_to_be16(length);
+    req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+
+    if (rc == 0) {
+        req->crq.s.status = 0x99; /* Just needs to be non-zero */
+    } else {
+        req->crq.s.status = 0x00;
+    }
+
+    rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
+    if (rc1) {
+        fprintf(stderr, "vscsi_send_iu: Error sending response\n");
+        return rc1;
+    }
+
+    return rc;
+}
+
+static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
+                               uint8_t key, uint8_t asc, uint8_t ascq)
+{
+    req->senselen = SRP_RSP_SENSE_DATA_LEN;
+
+    /* Valid bit and 'current errors' */
+    req->sense[0] = (0x1 << 7 | 0x70);
+    /* Sense key */
+    req->sense[2] = key;
+    /* Additional sense length */
+    req->sense[7] = 0xa; /* 10 bytes */
+    /* Additional sense code */
+    req->sense[12] = asc;
+    req->sense[13] = ascq;
+}
+
+static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
+                          uint8_t status, int32_t res_in, int32_t res_out)
+{
+    union viosrp_iu *iu = &req->iu;
+    uint64_t tag = iu->srp.rsp.tag;
+    int total_len = sizeof(iu->srp.rsp);
+
+    dprintf("VSCSI: Sending resp status: 0x%x, "
+            "res_in: %d, res_out: %d\n", status, res_in, res_out);
+
+    memset(iu, 0, sizeof(struct srp_rsp));
+    iu->srp.rsp.opcode = SRP_RSP;
+    iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
+    iu->srp.rsp.tag = tag;
+
+    /* Handle residuals */
+    if (res_in < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
+        res_in = -res_in;
+    } else if (res_in) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+    }
+    if (res_out < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
+        res_out = -res_out;
+    } else if (res_out) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
+    }
+    iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
+    iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
+
+    /* We don't do response data */
+    /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
+    iu->srp.rsp.resp_data_len = cpu_to_be32(0);
+
+    /* Handle success vs. failure */
+    iu->srp.rsp.status = status;
+    if (status) {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2;
+        if (req->senselen) {
+            req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+            req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
+            memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
+            total_len += req->senselen;
+        }
+    } else {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1;
+    }
+
+    vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
+    return 0;
+}
+
+static inline void vscsi_swap_desc(struct srp_direct_buf *desc)
+{
+    desc->va = be64_to_cpu(desc->va);
+    desc->len = be32_to_cpu(desc->len);
+}
+
+static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
+                                 uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *md = req->cur_desc;
+    uint32_t llen;
+    int rc = 0;
+
+    dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n",
+            len, (unsigned long long)md->va, md->len);
+
+    llen = MIN(len, md->len);
+    if (llen) {
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+    }
+    md->len -= llen;
+    md->va += llen;
+
+    if (rc) {
+        return -1;
+    }
+    return llen;
+}
+
+static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
+                                   uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *td = &req->ind_desc->table_desc;
+    struct srp_direct_buf *md = req->cur_desc;
+    int rc = 0;
+    uint32_t llen, total = 0;
+
+    dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n",
+            len, (unsigned long long)td->va, td->len);
+
+    /* While we have data ... */
+    while (len) {
+        /* If we have a descriptor but it's empty, go fetch a new one */
+        if (md && md->len == 0) {
+            /* More local available, use one */
+            if (req->local_desc) {
+                md = ++req->cur_desc;
+                --req->local_desc;
+                --req->total_desc;
+                td->va += sizeof(struct srp_direct_buf);
+            } else {
+                md = req->cur_desc = NULL;
+            }
+        }
+        /* No descriptor at hand, fetch one */
+        if (!md) {
+            if (!req->total_desc) {
+                dprintf("VSCSI:   Out of descriptors !\n");
+                break;
+            }
+            md = req->cur_desc = &req->ext_desc;
+            dprintf("VSCSI:   Reading desc from 0x%llx\n",
+                    (unsigned long long)td->va);
+            rc = spapr_tce_dma_read(&s->vdev, td->va, md,
+                                    sizeof(struct srp_direct_buf));
+            if (rc) {
+                dprintf("VSCSI: tce_dma_read -> %d reading ext_desc\n", rc);
+                break;
+            }
+            vscsi_swap_desc(md);
+            td->va += sizeof(struct srp_direct_buf);
+            --req->total_desc;
+        }
+        dprintf("VSCSI:   [desc va=0x%llx,len=0x%x] remaining=0x%x\n",
+                (unsigned long long)md->va, md->len, len);
+
+        /* Perform transfer */
+        llen = MIN(len, md->len);
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+        if (rc) {
+            dprintf("VSCSI: tce_dma_r/w(%d) -> %d\n", req->writing, rc);
+            break;
+        }
+        dprintf("VSCSI:     data: %02x %02x %02x %02x...\n",
+                buf[0], buf[1], buf[2], buf[3]);
+
+        len -= llen;
+        buf += llen;
+        total += llen;
+        md->va += llen;
+        md->len -= llen;
+    }
+    return rc ? -1 : total;
+}
+
+static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
+                                   int writing, uint8_t *buf, uint32_t len)
+{
+    int err = 0;
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        err = vscsi_srp_direct_data(s, req, buf, len);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        err = vscsi_srp_indirect_data(s, req, buf, len);
+        break;
+    }
+    return err;
+}
+
+/* Bits from linux srp */
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+    int size = 0;
+    uint8_t fmt = cmd->buf_fmt >> 4;
+
+    switch (fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        size = sizeof(struct srp_direct_buf);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        size = sizeof(struct srp_indirect_buf) +
+            sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
+        break;
+    default:
+        break;
+    }
+    return size;
+}
+
+static int vscsi_preprocess_desc(vscsi_req *req)
+{
+    struct srp_cmd *cmd = &req->iu.srp.cmd;
+    int offset, i;
+
+    offset = cmd->add_cdb_len & ~3;
+
+    if (req->writing) {
+        req->dma_fmt = cmd->buf_fmt >> 4;
+    } else {
+        offset += data_out_desc_size(cmd);
+        req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
+    }
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset);
+        req->total_desc = req->local_desc = 1;
+        vscsi_swap_desc(req->cur_desc);
+        dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n",
+                req->writing ? "write" : "read",
+                req->cur_desc->len, (unsigned long long)req->cur_desc->va);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset);
+        vscsi_swap_desc(&req->ind_desc->table_desc);
+        req->total_desc = req->ind_desc->table_desc.len /
+            sizeof(struct srp_direct_buf);
+        req->local_desc = req->writing ? cmd->data_out_desc_cnt :
+            cmd->data_in_desc_cnt;
+        for (i = 0; i < req->local_desc; i++) {
+            vscsi_swap_desc(&req->ind_desc->desc_list[i]);
+        }
+        req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL;
+        dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs "
+                "(%d local) VA: 0x%llx\n",
+                req->writing ? "read" : "write",
+                be32_to_cpu(req->ind_desc->len),
+                req->total_desc, req->local_desc,
+                (unsigned long long)req->ind_desc->table_desc.va);
+        break;
+    default:
+        fprintf(stderr,
+                "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
+{
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    int n;
+
+    n = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense));
+    if (n) {
+        req->senselen = n;
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        vscsi_put_req(req);
+        return;
+    }
+
+    dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n");
+    cdb[0] = 3;
+    cdb[1] = 0;
+    cdb[2] = 0;
+    cdb[3] = 0;
+    cdb[4] = 96;
+    cdb[5] = 0;
+    req->sensing = 1;
+    n = scsi_req_enqueue(req->sreq, cdb);
+    dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag);
+    if (n < 0) {
+        fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n");
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        scsi_req_abort(req->sreq, CHECK_CONDITION);
+        return;
+    } else if (n == 0) {
+        return;
+    }
+    scsi_req_continue(req->sreq);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    uint8_t *buf;
+    int rc = 0;
+
+    dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n",
+            sreq->tag, len, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (req->sensing) {
+        uint8_t *buf = scsi_req_get_buf(sreq);
+
+        len = MIN(len, SCSI_SENSE_BUF_SIZE);
+        dprintf("VSCSI: Sense data, %d bytes:\n", len);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                buf[0], buf[1], buf[2], buf[3],
+                buf[4], buf[5], buf[6], buf[7]);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                buf[8], buf[9], buf[10], buf[11],
+                buf[12], buf[13], buf[14], buf[15]);
+        memcpy(req->sense, buf, len);
+        req->senselen = len;
+        scsi_req_continue(req->sreq);
+        return;
+    }
+
+    if (len) {
+        buf = scsi_req_get_buf(sreq);
+        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        scsi_req_abort(req->sreq, CHECK_CONDITION);
+        return;
+    }
+
+    /* Start next chunk */
+    req->data_len -= rc;
+    scsi_req_continue(sreq);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    int32_t res_in = 0, res_out = 0;
+
+    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
+            reason, sreq->tag, status, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (!req->sensing && status == CHECK_CONDITION) {
+        vscsi_send_request_sense(s, req);
+        return;
+    }
+
+    if (req->sensing) {
+        dprintf("VSCSI: Sense done !\n");
+        status = CHECK_CONDITION;
+    } else {
+        dprintf("VSCSI: Command complete err=%d\n", status);
+        if (status == 0) {
+            /* We handle overflows, not underflows for normal commands,
+             * but hopefully nobody cares
+             */
+            if (req->writing) {
+                res_out = req->data_len;
+            } else {
+                res_in = req->data_len;
+            }
+        }
+    }
+    vscsi_send_rsp(s, req, 0, res_in, res_out);
+    vscsi_put_req(req);
+}
+
+static void vscsi_request_cancelled(SCSIRequest *sreq)
+{
+    vscsi_req *req = sreq->hba_private;
+
+    vscsi_put_req(req);
+}
+
+static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+    uint64_t tag = iu->srp.rsp.tag;
+
+    dprintf("VSCSI: Got login, sendin response !\n");
+
+    /* TODO handle case that requested size is wrong and
+     * buffer format is wrong
+     */
+    memset(iu, 0, sizeof(struct srp_login_rsp));
+    rsp->opcode = SRP_LOGIN_RSP;
+    /* Don't advertise quite as many request as we support to
+     * keep room for management stuff etc...
+     */
+    rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
+    rsp->tag = tag;
+    rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    /* direct and indirect */
+    rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
+
+    vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
+{
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    uint8_t resp_data[36];
+    int rc, len, alen;
+
+    /* We dont do EVPD. Also check that page_code is 0 */
+    if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
+        /* Send INVALID FIELD IN CDB */
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        return;
+    }
+    alen = cdb[3];
+    alen = (alen << 8) | cdb[4];
+    len = MIN(alen, 36);
+
+    /* Fake up inquiry using PQ=3 */
+    memset(resp_data, 0, 36);
+    resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
+    resp_data[2] = 0x06;   /* SPS-4 */
+    resp_data[3] = 0x02;   /* Resp data format */
+    resp_data[4] = 36 - 5; /* Additional length */
+    resp_data[7] = 0x10;   /* Sync transfers */
+    memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
+    memcpy(&resp_data[8], "QEMU    ", 8);
+
+    req->writing = 0;
+    vscsi_preprocess_desc(req);
+    rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+    if (rc < 0) {
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    } else {
+        vscsi_send_rsp(s, req, 0, 36 - rc, 0);
+    }
+}
+
+static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    SCSIDevice *sdev;
+    int n, id, lun;
+
+    vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
+
+    /* Qemu vs. linux issue with LUNs to be sorted out ... */
+    sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
+    if (!sdev) {
+        dprintf("VSCSI: Command for id %d with no drive\n", id);
+        if (srp->cmd.cdb[0] == INQUIRY) {
+            vscsi_inquiry_no_target(s, req);
+        } else {
+            vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        } return 1;
+    }
+
+    req->lun = lun;
+    req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
+    n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
+
+    dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
+            req->qtag, srp->cmd.cdb[0], id, lun, n);
+
+    if (n) {
+        /* Transfer direction must be set before preprocessing the
+         * descriptors
+         */
+        req->writing = (n < 1);
+
+        /* Preprocess RDMA descriptors */
+        vscsi_preprocess_desc(req);
+
+        /* Get transfer direction and initiate transfer */
+        if (n > 0) {
+            req->data_len = n;
+        } else if (n < 0) {
+            req->data_len = -n;
+        }
+        scsi_req_continue(req->sreq);
+    }
+    /* Don't touch req here, it may have been recycled already */
+
+    return 0;
+}
+
+static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    int fn;
+
+    fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
+            iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+    switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+#if 0 /* We really don't deal with these for now */
+    case SRP_TSK_ABORT_TASK:
+        fn = ABORT_TASK;
+        break;
+    case SRP_TSK_ABORT_TASK_SET:
+        fn = ABORT_TASK_SET;
+        break;
+    case SRP_TSK_CLEAR_TASK_SET:
+        fn = CLEAR_TASK_SET;
+        break;
+    case SRP_TSK_LUN_RESET:
+        fn = LOGICAL_UNIT_RESET;
+        break;
+    case SRP_TSK_CLEAR_ACA:
+        fn = CLEAR_ACA;
+        break;
+#endif
+    default:
+        fn = 0;
+    }
+    if (fn) {
+        /* XXX Send/Handle target task management */
+        ;
+    } else {
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    }
+    return !fn;
+}
+
+static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    int done = 1;
+    uint8_t opcode = srp->rsp.opcode;
+
+    switch (opcode) {
+    case SRP_LOGIN_REQ:
+        vscsi_process_login(s, req);
+        break;
+    case SRP_TSK_MGMT:
+        done = vscsi_process_tsk_mgmt(s, req);
+        break;
+    case SRP_CMD:
+        done = vscsi_queue_cmd(s, req);
+        break;
+    case SRP_LOGIN_RSP:
+    case SRP_I_LOGOUT:
+    case SRP_T_LOGOUT:
+    case SRP_RSP:
+    case SRP_CRED_REQ:
+    case SRP_CRED_RSP:
+    case SRP_AER_REQ:
+    case SRP_AER_RSP:
+        fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
+    }
+
+    return done;
+}
+
+static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
+{
+    struct viosrp_adapter_info *sinfo;
+    struct mad_adapter_info_data info;
+    int rc;
+
+    sinfo = &req->iu.mad.adapter_info;
+
+#if 0 /* What for ? */
+    rc = spapr_tce_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
+                            &info, be16_to_cpu(sinfo->common.length));
+    if (rc) {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
+    }
+#endif
+    memset(&info, 0, sizeof(info));
+    strcpy(info.srp_version, SRP_VERSION);
+    strncpy(info.partition_name, "qemu", sizeof("qemu"));
+    info.partition_number = cpu_to_be32(0);
+    info.mad_version = cpu_to_be32(1);
+    info.os_type = cpu_to_be32(2);
+    info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
+
+    rc = spapr_tce_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
+                             &info, be16_to_cpu(sinfo->common.length));
+    if (rc)  {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
+    }
+
+    sinfo->common.status = rc ? cpu_to_be32(1) : 0;
+
+    return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
+}
+
+static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
+{
+    union mad_iu *mad = &req->iu.mad;
+
+    switch (be32_to_cpu(mad->empty_iu.common.type)) {
+    case VIOSRP_EMPTY_IU_TYPE:
+        fprintf(stderr, "Unsupported EMPTY MAD IU\n");
+        break;
+    case VIOSRP_ERROR_LOG_TYPE:
+        fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
+        mad->error_log.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT);
+        break;
+    case VIOSRP_ADAPTER_INFO_TYPE:
+        vscsi_send_adapter_info(s, req);
+        break;
+    case VIOSRP_HOST_CONFIG_TYPE:
+        mad->host_config.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
+                be32_to_cpu(mad->empty_iu.common.type));
+    }
+
+    return 1;
+}
+
+static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
+{
+    vscsi_req *req;
+    int done;
+
+    req = vscsi_get_req(s);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Failed to get a request !\n");
+        return;
+    }
+
+    /* We only support a limited number of descriptors, we know
+     * the ibmvscsi driver uses up to 10 max, so it should fit
+     * in our 256 bytes IUs. If not we'll have to increase the size
+     * of the structure.
+     */
+    if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+        fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
+                crq->s.IU_length);
+        return;
+    }
+
+    /* XXX Handle failure differently ? */
+    if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+                           crq->s.IU_length)) {
+        fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
+        qemu_free(req);
+    }
+    memcpy(&req->crq, crq, sizeof(vscsi_crq));
+
+    if (crq->s.format == VIOSRP_MAD_FORMAT) {
+        done = vscsi_handle_mad_req(s, req);
+    } else {
+        done = vscsi_handle_srp_req(s, req);
+    }
+
+    if (done) {
+        vscsi_put_req(req);
+    }
+}
+
+
+static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    vscsi_crq crq;
+
+    memcpy(crq.raw, crq_data, 16);
+    crq.s.timeout = be16_to_cpu(crq.s.timeout);
+    crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
+    crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
+
+    dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
+
+    switch (crq.s.valid) {
+    case 0xc0: /* Init command/response */
+
+        /* Respond to initialization request */
+        if (crq.s.format == 0x01) {
+            memset(crq.raw, 0, 16);
+            crq.s.valid = 0xc0;
+            crq.s.format = 0x02;
+            spapr_vio_send_crq(dev, crq.raw);
+        }
+
+        /* Note that in hotplug cases, we might get a 0x02
+         * as a result of us emitting the init request
+         */
+
+        break;
+    case 0xff: /* Link event */
+
+        /* Not handled for now */
+
+        break;
+    case 0x80: /* Payloads */
+        switch (crq.s.format) {
+        case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
+        case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
+            vscsi_got_payload(s, &crq);
+            break;
+        case VIOSRP_OS400_FORMAT:
+        case VIOSRP_AIX_FORMAT:
+        case VIOSRP_LINUX_FORMAT:
+        case VIOSRP_INLINE_FORMAT:
+            fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
+                    crq.s.format);
+            break;
+        default:
+            fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
+                    crq.s.format);
+        }
+        break;
+    default:
+        fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
+                crq.raw[0], crq.raw[1]);
+    };
+
+    return 0;
+}
+
+static const struct SCSIBusOps vscsi_scsi_ops = {
+    .transfer_data = vscsi_transfer_data,
+    .complete = vscsi_command_complete,
+    .cancel = vscsi_request_cancelled
+};
+
+static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    int i;
+
+    dbg_vscsi_state = s;
+
+    /* Initialize qemu request tags */
+    memset(s->reqs, 0, sizeof(s->reqs));
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        s->reqs[i].qtag = i;
+    }
+
+    dev->crq.SendFunc = vscsi_do_crq;
+
+    scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
+                 &vscsi_scsi_ops);
+    if (!dev->qdev.hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    return 0;
+}
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vscsi");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_init_nofail(dev);
+
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    int ret;
+
+    ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static VIOsPAPRDeviceInfo spapr_vscsi = {
+    .init = spapr_vscsi_init,
+    .devnode = spapr_vscsi_devnode,
+    .dt_name = "v-scsi",
+    .dt_type = "vscsi",
+    .dt_compatible = "IBM,v-scsi",
+    .signal_mask = 0x00000001,
+    .qdev.name = "spapr-vscsi",
+    .qdev.size = sizeof(VSCSIState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice,
+                           rtce_window_size, 0x10000000),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vscsi_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vscsi);
+}
+device_init(spapr_vscsi_register);
diff --git a/qemu-0.15.x/hw/spapr_vty.c b/qemu-0.15.x/hw/spapr_vty.c
new file mode 100644
index 0000000..6fc0105
--- /dev/null
+++ b/qemu-0.15.x/hw/spapr_vty.c
@@ -0,0 +1,159 @@
+#include "qdev.h"
+#include "qemu-char.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#define VTERM_BUFSIZE   16
+
+typedef struct VIOsPAPRVTYDevice {
+    VIOsPAPRDevice sdev;
+    CharDriverState *chardev;
+    uint32_t in, out;
+    uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+    return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+    int i;
+
+    if ((dev->in == dev->out) && size) {
+        /* toggle line to simulate edge interrupt */
+        qemu_irq_pulse(dev->sdev.qirq);
+    }
+    for (i = 0; i < size; i++) {
+        assert((dev->in - dev->out) < VTERM_BUFSIZE);
+        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+    }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+    int n = 0;
+
+    while ((n < max) && (dev->out != dev->in)) {
+        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+    }
+
+    return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    /* FIXME: should check the qemu_chr_write() return value */
+    qemu_chr_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+                          vty_receive, NULL, dev);
+
+    return 0;
+}
+
+static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong len = args[1];
+    target_ulong char0_7 = args[2];
+    target_ulong char8_15 = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    if (len > 16) {
+        return H_PARAMETER;
+    }
+
+    *((uint64_t *)buf) = cpu_to_be64(char0_7);
+    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+    vty_putchars(sdev, buf, len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *len = args + 0;
+    target_ulong *char0_7 = args + 1;
+    target_ulong *char8_15 = args + 2;
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    *len = vty_getchars(sdev, buf, sizeof(buf));
+    if (*len < 16) {
+        memset(buf + *len, 0, 16 - *len);
+    }
+
+    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+    return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vty");
+    qdev_prop_set_uint32(dev, "reg", reg);
+    qdev_prop_set_chr(dev, "chardev", chardev);
+    qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static void vty_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+}
+
+static VIOsPAPRDeviceInfo spapr_vty = {
+    .init = spapr_vty_init,
+    .dt_name = "vty",
+    .dt_type = "serial",
+    .dt_compatible = "hvterm1",
+    .hcalls = vty_hcalls,
+    .qdev.name = "spapr-vty",
+    .qdev.size = sizeof(VIOsPAPRVTYDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
+        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vty_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vty);
+}
+device_init(spapr_vty_register);
diff --git a/qemu-0.15.x/hw/sparc32_dma.c b/qemu-0.15.x/hw/sparc32_dma.c
new file mode 100644
index 0000000..e75694b
--- /dev/null
+++ b/qemu-0.15.x/hw/sparc32_dma.c
@@ -0,0 +1,305 @@
+/*
+ * QEMU Sparc32 DMA controller emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Modifications:
+ *  2010-Feb-14 Artyom Tarasenko : reworked irq generation
+ *
+ * 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 "hw.h"
+#include "sparc32_dma.h"
+#include "sun4m.h"
+#include "sysbus.h"
+#include "trace.h"
+
+/*
+ * This is the DMA controller part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
+ */
+
+#define DMA_REGS 4
+#define DMA_SIZE (4 * sizeof(uint32_t))
+/* We need the mask, because one instance of the device is not page
+   aligned (ledma, start address 0x0010) */
+#define DMA_MASK (DMA_SIZE - 1)
+/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
+#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
+#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
+
+#define DMA_VER 0xa0000000
+#define DMA_INTR 1
+#define DMA_INTREN 0x10
+#define DMA_WRITE_MEM 0x100
+#define DMA_EN 0x200
+#define DMA_LOADED 0x04000000
+#define DMA_DRAIN_FIFO 0x40
+#define DMA_RESET 0x80
+
+/* XXX SCSI and ethernet should have different read-only bit masks */
+#define DMA_CSR_RO_MASK 0xfe000007
+
+typedef struct DMAState DMAState;
+
+struct DMAState {
+    SysBusDevice busdev;
+    uint32_t dmaregs[DMA_REGS];
+    qemu_irq irq;
+    void *iommu;
+    qemu_irq gpio[2];
+    uint32_t is_ledma;
+};
+
+enum {
+    GPIO_RESET = 0,
+    GPIO_DMA,
+};
+
+/* Note: on sparc, the lance 16 bit bus is swapped */
+void ledma_memory_read(void *opaque, target_phys_addr_t addr,
+                       uint8_t *buf, int len, int do_bswap)
+{
+    DMAState *s = opaque;
+    int i;
+
+    addr |= s->dmaregs[3];
+    trace_ledma_memory_read(addr);
+    if (do_bswap) {
+        sparc_iommu_memory_read(s->iommu, addr, buf, len);
+    } else {
+        addr &= ~1;
+        len &= ~1;
+        sparc_iommu_memory_read(s->iommu, addr, buf, len);
+        for(i = 0; i < len; i += 2) {
+            bswap16s((uint16_t *)(buf + i));
+        }
+    }
+}
+
+void ledma_memory_write(void *opaque, target_phys_addr_t addr,
+                        uint8_t *buf, int len, int do_bswap)
+{
+    DMAState *s = opaque;
+    int l, i;
+    uint16_t tmp_buf[32];
+
+    addr |= s->dmaregs[3];
+    trace_ledma_memory_write(addr);
+    if (do_bswap) {
+        sparc_iommu_memory_write(s->iommu, addr, buf, len);
+    } else {
+        addr &= ~1;
+        len &= ~1;
+        while (len > 0) {
+            l = len;
+            if (l > sizeof(tmp_buf))
+                l = sizeof(tmp_buf);
+            for(i = 0; i < l; i += 2) {
+                tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
+            }
+            sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
+            len -= l;
+            buf += l;
+            addr += l;
+        }
+    }
+}
+
+static void dma_set_irq(void *opaque, int irq, int level)
+{
+    DMAState *s = opaque;
+    if (level) {
+        s->dmaregs[0] |= DMA_INTR;
+        if (s->dmaregs[0] & DMA_INTREN) {
+            trace_sparc32_dma_set_irq_raise();
+            qemu_irq_raise(s->irq);
+        }
+    } else {
+        if (s->dmaregs[0] & DMA_INTR) {
+            s->dmaregs[0] &= ~DMA_INTR;
+            if (s->dmaregs[0] & DMA_INTREN) {
+                trace_sparc32_dma_set_irq_lower();
+                qemu_irq_lower(s->irq);
+            }
+        }
+    }
+}
+
+void espdma_memory_read(void *opaque, uint8_t *buf, int len)
+{
+    DMAState *s = opaque;
+
+    trace_espdma_memory_read(s->dmaregs[1]);
+    sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
+    s->dmaregs[1] += len;
+}
+
+void espdma_memory_write(void *opaque, uint8_t *buf, int len)
+{
+    DMAState *s = opaque;
+
+    trace_espdma_memory_write(s->dmaregs[1]);
+    sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
+    s->dmaregs[1] += len;
+}
+
+static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        /* aliased to espdma, but we can't get there from here */
+        /* buggy driver if using undocumented behavior, just return 0 */
+        trace_sparc32_dma_mem_readl(addr, 0);
+        return 0;
+    }
+    saddr = (addr & DMA_MASK) >> 2;
+    trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
+    return s->dmaregs[saddr];
+}
+
+static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        /* aliased to espdma, but we can't get there from here */
+        trace_sparc32_dma_mem_writel(addr, 0, val);
+        return;
+    }
+    saddr = (addr & DMA_MASK) >> 2;
+    trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
+    switch (saddr) {
+    case 0:
+        if (val & DMA_INTREN) {
+            if (s->dmaregs[0] & DMA_INTR) {
+                trace_sparc32_dma_set_irq_raise();
+                qemu_irq_raise(s->irq);
+            }
+        } else {
+            if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) {
+                trace_sparc32_dma_set_irq_lower();
+                qemu_irq_lower(s->irq);
+            }
+        }
+        if (val & DMA_RESET) {
+            qemu_irq_raise(s->gpio[GPIO_RESET]);
+            qemu_irq_lower(s->gpio[GPIO_RESET]);
+        } else if (val & DMA_DRAIN_FIFO) {
+            val &= ~DMA_DRAIN_FIFO;
+        } else if (val == 0)
+            val = DMA_DRAIN_FIFO;
+
+        if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
+            trace_sparc32_dma_enable_raise();
+            qemu_irq_raise(s->gpio[GPIO_DMA]);
+        } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
+            trace_sparc32_dma_enable_lower();
+            qemu_irq_lower(s->gpio[GPIO_DMA]);
+        }
+
+        val &= ~DMA_CSR_RO_MASK;
+        val |= DMA_VER;
+        s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
+        break;
+    case 1:
+        s->dmaregs[0] |= DMA_LOADED;
+        /* fall through */
+    default:
+        s->dmaregs[saddr] = val;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const dma_mem_read[3] = {
+    NULL,
+    NULL,
+    dma_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const dma_mem_write[3] = {
+    NULL,
+    NULL,
+    dma_mem_writel,
+};
+
+static void dma_reset(DeviceState *d)
+{
+    DMAState *s = container_of(d, DMAState, busdev.qdev);
+
+    memset(s->dmaregs, 0, DMA_SIZE);
+    s->dmaregs[0] = DMA_VER;
+}
+
+static const VMStateDescription vmstate_dma = {
+    .name ="sparc32_dma",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int sparc32_dma_init1(SysBusDevice *dev)
+{
+    DMAState *s = FROM_SYSBUS(DMAState, dev);
+    int dma_io_memory;
+    int reg_size;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE;
+    sysbus_init_mmio(dev, reg_size, dma_io_memory);
+
+    qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
+    qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
+
+    return 0;
+}
+
+static SysBusDeviceInfo sparc32_dma_info = {
+    .init = sparc32_dma_init1,
+    .qdev.name  = "sparc32_dma",
+    .qdev.size  = sizeof(DMAState),
+    .qdev.vmsd  = &vmstate_dma,
+    .qdev.reset = dma_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+        DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void sparc32_dma_register_devices(void)
+{
+    sysbus_register_withprop(&sparc32_dma_info);
+}
+
+device_init(sparc32_dma_register_devices)
diff --git a/qemu-0.15.x/hw/sparc32_dma.h b/qemu-0.15.x/hw/sparc32_dma.h
new file mode 100644
index 0000000..8b72c37
--- /dev/null
+++ b/qemu-0.15.x/hw/sparc32_dma.h
@@ -0,0 +1,12 @@
+#ifndef SPARC32_DMA_H
+#define SPARC32_DMA_H
+
+/* sparc32_dma.c */
+void ledma_memory_read(void *opaque, target_phys_addr_t addr,
+                       uint8_t *buf, int len, int do_bswap);
+void ledma_memory_write(void *opaque, target_phys_addr_t addr,
+                        uint8_t *buf, int len, int do_bswap);
+void espdma_memory_read(void *opaque, uint8_t *buf, int len);
+void espdma_memory_write(void *opaque, uint8_t *buf, int len);
+
+#endif
diff --git a/qemu-0.15.x/hw/spitz.c b/qemu-0.15.x/hw/spitz.c
new file mode 100644
index 0000000..006f7a9
--- /dev/null
+++ b/qemu-0.15.x/hw/spitz.c
@@ -0,0 +1,1117 @@
+/*
+ * PXA270-based Clamshell PDA platforms.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "arm-misc.h"
+#include "sysemu.h"
+#include "pcmcia.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "flash.h"
+#include "qemu-timer.h"
+#include "devices.h"
+#include "sharpsl.h"
+#include "console.h"
+#include "block.h"
+#include "audio/audio.h"
+#include "boards.h"
+#include "blockdev.h"
+#include "sysbus.h"
+
+#undef REG_FMT
+#define REG_FMT			"0x%02lx"
+
+/* Spitz Flash */
+#define FLASH_BASE		0x0c000000
+#define FLASH_ECCLPLB		0x00	/* Line parity 7 - 0 bit */
+#define FLASH_ECCLPUB		0x04	/* Line parity 15 - 8 bit */
+#define FLASH_ECCCP		0x08	/* Column parity 5 - 0 bit */
+#define FLASH_ECCCNTR		0x0c	/* ECC byte counter */
+#define FLASH_ECCCLRR		0x10	/* Clear ECC */
+#define FLASH_FLASHIO		0x14	/* Flash I/O */
+#define FLASH_FLASHCTL		0x18	/* Flash Control */
+
+#define FLASHCTL_CE0		(1 << 0)
+#define FLASHCTL_CLE		(1 << 1)
+#define FLASHCTL_ALE		(1 << 2)
+#define FLASHCTL_WP		(1 << 3)
+#define FLASHCTL_CE1		(1 << 4)
+#define FLASHCTL_RYBY		(1 << 5)
+#define FLASHCTL_NCE		(FLASHCTL_CE0 | FLASHCTL_CE1)
+
+typedef struct {
+    SysBusDevice busdev;
+    NANDFlashState *nand;
+    uint8_t ctl;
+    uint8_t manf_id;
+    uint8_t chip_id;
+    ECCState ecc;
+} SLNANDState;
+
+static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
+{
+    SLNANDState *s = (SLNANDState *) opaque;
+    int ryby;
+
+    switch (addr) {
+#define BSHR(byte, from, to)	((s->ecc.lp[byte] >> (from - to)) & (1 << to))
+    case FLASH_ECCLPLB:
+        return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
+                BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
+
+#define BSHL(byte, from, to)	((s->ecc.lp[byte] << (to - from)) & (1 << to))
+    case FLASH_ECCLPUB:
+        return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
+                BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
+
+    case FLASH_ECCCP:
+        return s->ecc.cp;
+
+    case FLASH_ECCCNTR:
+        return s->ecc.count & 0xff;
+
+    case FLASH_FLASHCTL:
+        nand_getpins(s->nand, &ryby);
+        if (ryby)
+            return s->ctl | FLASHCTL_RYBY;
+        else
+            return s->ctl;
+
+    case FLASH_FLASHIO:
+        return ecc_digest(&s->ecc, nand_getio(s->nand));
+
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+    return 0;
+}
+
+static uint32_t sl_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLNANDState *s = (SLNANDState *) opaque;
+
+    if (addr == FLASH_FLASHIO)
+        return ecc_digest(&s->ecc, nand_getio(s->nand)) |
+                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
+
+    return sl_readb(opaque, addr);
+}
+
+static void sl_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    SLNANDState *s = (SLNANDState *) opaque;
+
+    switch (addr) {
+    case FLASH_ECCCLRR:
+        /* Value is ignored.  */
+        ecc_reset(&s->ecc);
+        break;
+
+    case FLASH_FLASHCTL:
+        s->ctl = value & 0xff & ~FLASHCTL_RYBY;
+        nand_setpins(s->nand,
+                        s->ctl & FLASHCTL_CLE,
+                        s->ctl & FLASHCTL_ALE,
+                        s->ctl & FLASHCTL_NCE,
+                        s->ctl & FLASHCTL_WP,
+                        0);
+        break;
+
+    case FLASH_FLASHIO:
+        nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
+        break;
+
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+}
+
+enum {
+    FLASH_128M,
+    FLASH_1024M,
+};
+
+static CPUReadMemoryFunc * const sl_readfn[] = {
+    sl_readb,
+    sl_readb,
+    sl_readl,
+};
+static CPUWriteMemoryFunc * const sl_writefn[] = {
+    sl_writeb,
+    sl_writeb,
+    sl_writeb,
+};
+
+static void sl_flash_register(PXA2xxState *cpu, int size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "sl-nand");
+
+    qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
+    if (size == FLASH_128M)
+        qdev_prop_set_uint8(dev, "chip_id", 0x73);
+    else if (size == FLASH_1024M)
+        qdev_prop_set_uint8(dev, "chip_id", 0xf1);
+
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, FLASH_BASE);
+}
+
+static int sl_nand_init(SysBusDevice *dev) {
+    int iomemtype;
+    SLNANDState *s;
+
+    s = FROM_SYSBUS(SLNANDState, dev);
+
+    s->ctl = 0;
+    s->nand = nand_init(s->manf_id, s->chip_id);
+
+    iomemtype = cpu_register_io_memory(sl_readfn,
+                    sl_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x40, iomemtype);
+
+    return 0;
+}
+
+/* Spitz Keyboard */
+
+#define SPITZ_KEY_STROBE_NUM	11
+#define SPITZ_KEY_SENSE_NUM	7
+
+static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
+    12, 17, 91, 34, 36, 38, 39
+};
+
+static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
+    88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
+};
+
+/* Eighth additional row maps the special keys */
+static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
+    { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
+    {  -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
+    { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25,  -1 ,  -1 ,  -1  },
+    { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26,  -1 , 0x36,  -1  },
+    { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34,  -1 , 0x1c, 0x2a,  -1  },
+    { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33,  -1 , 0x48,  -1 ,  -1 , 0x38 },
+    { 0x37, 0x3d,  -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d,  -1 ,  -1  },
+    { 0x52, 0x43, 0x01, 0x47, 0x49,  -1 ,  -1 ,  -1 ,  -1 ,  -1 ,  -1  },
+};
+
+#define SPITZ_GPIO_AK_INT	13	/* Remote control */
+#define SPITZ_GPIO_SYNC		16	/* Sync button */
+#define SPITZ_GPIO_ON_KEY	95	/* Power button */
+#define SPITZ_GPIO_SWA		97	/* Lid */
+#define SPITZ_GPIO_SWB		96	/* Tablet mode */
+
+/* The special buttons are mapped to unused keys */
+static const int spitz_gpiomap[5] = {
+    SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
+    SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq sense[SPITZ_KEY_SENSE_NUM];
+    qemu_irq gpiomap[5];
+    int keymap[0x80];
+    uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
+    uint16_t strobe_state;
+    uint16_t sense_state;
+
+    uint16_t pre_map[0x100];
+    uint16_t modifiers;
+    uint16_t imodifiers;
+    uint8_t fifo[16];
+    int fifopos, fifolen;
+    QEMUTimer *kbdtimer;
+} SpitzKeyboardState;
+
+static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
+{
+    int i;
+    uint16_t strobe, sense = 0;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
+        strobe = s->keyrow[i] & s->strobe_state;
+        if (strobe) {
+            sense |= 1 << i;
+            if (!(s->sense_state & (1 << i)))
+                qemu_irq_raise(s->sense[i]);
+        } else if (s->sense_state & (1 << i))
+            qemu_irq_lower(s->sense[i]);
+    }
+
+    s->sense_state = sense;
+}
+
+static void spitz_keyboard_strobe(void *opaque, int line, int level)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    if (level)
+        s->strobe_state |= 1 << line;
+    else
+        s->strobe_state &= ~(1 << line);
+    spitz_keyboard_sense_update(s);
+}
+
+static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
+{
+    int spitz_keycode = s->keymap[keycode & 0x7f];
+    if (spitz_keycode == -1)
+        return;
+
+    /* Handle the additional keys */
+    if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
+        qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
+        return;
+    }
+
+    if (keycode & 0x80)
+        s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
+    else
+        s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
+
+    spitz_keyboard_sense_update(s);
+}
+
+#define SHIFT	(1 << 7)
+#define CTRL	(1 << 8)
+#define FN	(1 << 9)
+
+#define QUEUE_KEY(c)	s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
+
+static void spitz_keyboard_handler(void *opaque, int keycode)
+{
+    SpitzKeyboardState *s = opaque;
+    uint16_t code;
+    int mapcode;
+    switch (keycode) {
+    case 0x2a:	/* Left Shift */
+        s->modifiers |= 1;
+        break;
+    case 0xaa:
+        s->modifiers &= ~1;
+        break;
+    case 0x36:	/* Right Shift */
+        s->modifiers |= 2;
+        break;
+    case 0xb6:
+        s->modifiers &= ~2;
+        break;
+    case 0x1d:	/* Control */
+        s->modifiers |= 4;
+        break;
+    case 0x9d:
+        s->modifiers &= ~4;
+        break;
+    case 0x38:	/* Alt */
+        s->modifiers |= 8;
+        break;
+    case 0xb8:
+        s->modifiers &= ~8;
+        break;
+    }
+
+    code = s->pre_map[mapcode = ((s->modifiers & 3) ?
+            (keycode | SHIFT) :
+            (keycode & ~SHIFT))];
+
+    if (code != mapcode) {
+#if 0
+        if ((code & SHIFT) && !(s->modifiers & 1))
+            QUEUE_KEY(0x2a | (keycode & 0x80));
+        if ((code & CTRL ) && !(s->modifiers & 4))
+            QUEUE_KEY(0x1d | (keycode & 0x80));
+        if ((code & FN   ) && !(s->modifiers & 8))
+            QUEUE_KEY(0x38 | (keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 1))
+            QUEUE_KEY(0x2a | (~keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 2))
+            QUEUE_KEY(0x36 | (~keycode & 0x80));
+#else
+        if (keycode & 0x80) {
+            if ((s->imodifiers & 1   ) && !(s->modifiers & 1))
+                QUEUE_KEY(0x2a | 0x80);
+            if ((s->imodifiers & 4   ) && !(s->modifiers & 4))
+                QUEUE_KEY(0x1d | 0x80);
+            if ((s->imodifiers & 8   ) && !(s->modifiers & 8))
+                QUEUE_KEY(0x38 | 0x80);
+            if ((s->imodifiers & 0x10) && (s->modifiers & 1))
+                QUEUE_KEY(0x2a);
+            if ((s->imodifiers & 0x20) && (s->modifiers & 2))
+                QUEUE_KEY(0x36);
+            s->imodifiers = 0;
+        } else {
+            if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) {
+                QUEUE_KEY(0x2a);
+                s->imodifiers |= 1;
+            }
+            if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) {
+                QUEUE_KEY(0x1d);
+                s->imodifiers |= 4;
+            }
+            if ((code & FN   ) && !((s->modifiers | s->imodifiers) & 8)) {
+                QUEUE_KEY(0x38);
+                s->imodifiers |= 8;
+            }
+            if ((code & FN   ) && (s->modifiers & 1) &&
+                            !(s->imodifiers & 0x10)) {
+                QUEUE_KEY(0x2a | 0x80);
+                s->imodifiers |= 0x10;
+            }
+            if ((code & FN   ) && (s->modifiers & 2) &&
+                            !(s->imodifiers & 0x20)) {
+                QUEUE_KEY(0x36 | 0x80);
+                s->imodifiers |= 0x20;
+            }
+        }
+#endif
+    }
+
+    QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
+}
+
+static void spitz_keyboard_tick(void *opaque)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    if (s->fifolen) {
+        spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
+        s->fifolen --;
+        if (s->fifopos >= 16)
+            s->fifopos = 0;
+    }
+
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() / 32);
+}
+
+static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
+{
+    int i;
+    for (i = 0; i < 0x100; i ++)
+        s->pre_map[i] = i;
+    s->pre_map[0x02 | SHIFT	] = 0x02 | SHIFT;	/* exclam */
+    s->pre_map[0x28 | SHIFT	] = 0x03 | SHIFT;	/* quotedbl */
+    s->pre_map[0x04 | SHIFT	] = 0x04 | SHIFT;	/* numbersign */
+    s->pre_map[0x05 | SHIFT	] = 0x05 | SHIFT;	/* dollar */
+    s->pre_map[0x06 | SHIFT	] = 0x06 | SHIFT;	/* percent */
+    s->pre_map[0x08 | SHIFT	] = 0x07 | SHIFT;	/* ampersand */
+    s->pre_map[0x28		] = 0x08 | SHIFT;	/* apostrophe */
+    s->pre_map[0x0a | SHIFT	] = 0x09 | SHIFT;	/* parenleft */
+    s->pre_map[0x0b | SHIFT	] = 0x0a | SHIFT;	/* parenright */
+    s->pre_map[0x29 | SHIFT	] = 0x0b | SHIFT;	/* asciitilde */
+    s->pre_map[0x03 | SHIFT	] = 0x0c | SHIFT;	/* at */
+    s->pre_map[0xd3		] = 0x0e | FN;		/* Delete */
+    s->pre_map[0x3a		] = 0x0f | FN;		/* Caps_Lock */
+    s->pre_map[0x07 | SHIFT	] = 0x11 | FN;		/* asciicircum */
+    s->pre_map[0x0d		] = 0x12 | FN;		/* equal */
+    s->pre_map[0x0d | SHIFT	] = 0x13 | FN;		/* plus */
+    s->pre_map[0x1a		] = 0x14 | FN;		/* bracketleft */
+    s->pre_map[0x1b		] = 0x15 | FN;		/* bracketright */
+    s->pre_map[0x1a | SHIFT	] = 0x16 | FN;		/* braceleft */
+    s->pre_map[0x1b | SHIFT	] = 0x17 | FN;		/* braceright */
+    s->pre_map[0x27		] = 0x22 | FN;		/* semicolon */
+    s->pre_map[0x27 | SHIFT	] = 0x23 | FN;		/* colon */
+    s->pre_map[0x09 | SHIFT	] = 0x24 | FN;		/* asterisk */
+    s->pre_map[0x2b		] = 0x25 | FN;		/* backslash */
+    s->pre_map[0x2b | SHIFT	] = 0x26 | FN;		/* bar */
+    s->pre_map[0x0c | SHIFT	] = 0x30 | FN;		/* underscore */
+    s->pre_map[0x33 | SHIFT	] = 0x33 | FN;		/* less */
+    s->pre_map[0x35		] = 0x33 | SHIFT;	/* slash */
+    s->pre_map[0x34 | SHIFT	] = 0x34 | FN;		/* greater */
+    s->pre_map[0x35 | SHIFT	] = 0x34 | SHIFT;	/* question */
+    s->pre_map[0x49		] = 0x48 | FN;		/* Page_Up */
+    s->pre_map[0x51		] = 0x50 | FN;		/* Page_Down */
+
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+}
+
+#undef SHIFT
+#undef CTRL
+#undef FN
+
+static int spitz_keyboard_post_load(void *opaque, int version_id)
+{
+    SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
+
+    /* Release all pressed keys */
+    memset(s->keyrow, 0, sizeof(s->keyrow));
+    spitz_keyboard_sense_update(s);
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+
+    return 0;
+}
+
+static void spitz_keyboard_register(PXA2xxState *cpu)
+{
+    int i;
+    DeviceState *dev;
+    SpitzKeyboardState *s;
+
+    dev = sysbus_create_simple("spitz-keyboard", -1, NULL);
+    s = FROM_SYSBUS(SpitzKeyboardState, sysbus_from_qdev(dev));
+
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
+
+    for (i = 0; i < 5; i ++)
+        s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
+
+    if (!graphic_rotate)
+        s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
+
+    for (i = 0; i < 5; i++)
+        qemu_set_irq(s->gpiomap[i], 0);
+
+    for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+        qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
+                qdev_get_gpio_in(dev, i));
+
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock_ns(vm_clock));
+
+    qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
+}
+
+static int spitz_keyboard_init(SysBusDevice *dev)
+{
+    SpitzKeyboardState *s;
+    int i, j;
+
+    s = FROM_SYSBUS(SpitzKeyboardState, dev);
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
+        for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
+            if (spitz_keymap[i][j] != -1)
+                s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
+
+    spitz_keyboard_pre_map(s);
+
+    s->kbdtimer = qemu_new_timer_ns(vm_clock, spitz_keyboard_tick, s);
+    qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
+    qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
+
+    return 0;
+}
+
+/* LCD backlight controller */
+
+#define LCDTG_RESCTL	0x00
+#define LCDTG_PHACTRL	0x01
+#define LCDTG_DUTYCTRL	0x02
+#define LCDTG_POWERREG0	0x03
+#define LCDTG_POWERREG1	0x04
+#define LCDTG_GPOR3	0x05
+#define LCDTG_PICTRL	0x06
+#define LCDTG_POLCTRL	0x07
+
+typedef struct {
+    SSISlave ssidev;
+    uint32_t bl_intensity;
+    uint32_t bl_power;
+} SpitzLCDTG;
+
+static void spitz_bl_update(SpitzLCDTG *s)
+{
+    if (s->bl_power && s->bl_intensity)
+        zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity);
+    else
+        zaurus_printf("LCD Backlight now off\n");
+}
+
+/* FIXME: Implement GPIO properly and remove this hack.  */
+static SpitzLCDTG *spitz_lcdtg;
+
+static inline void spitz_bl_bit5(void *opaque, int line, int level)
+{
+    SpitzLCDTG *s = spitz_lcdtg;
+    int prev = s->bl_intensity;
+
+    if (level)
+        s->bl_intensity &= ~0x20;
+    else
+        s->bl_intensity |= 0x20;
+
+    if (s->bl_power && prev != s->bl_intensity)
+        spitz_bl_update(s);
+}
+
+static inline void spitz_bl_power(void *opaque, int line, int level)
+{
+    SpitzLCDTG *s = spitz_lcdtg;
+    s->bl_power = !!level;
+    spitz_bl_update(s);
+}
+
+static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
+{
+    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+    int addr;
+    addr = value >> 5;
+    value &= 0x1f;
+
+    switch (addr) {
+    case LCDTG_RESCTL:
+        if (value)
+            zaurus_printf("LCD in QVGA mode\n");
+        else
+            zaurus_printf("LCD in VGA mode\n");
+        break;
+
+    case LCDTG_DUTYCTRL:
+        s->bl_intensity &= ~0x1f;
+        s->bl_intensity |= value;
+        if (s->bl_power)
+            spitz_bl_update(s);
+        break;
+
+    case LCDTG_POWERREG0:
+        /* Set common voltage to M62332FP */
+        break;
+    }
+    return 0;
+}
+
+static int spitz_lcdtg_init(SSISlave *dev)
+{
+    SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+
+    spitz_lcdtg = s;
+    s->bl_power = 0;
+    s->bl_intensity = 0x20;
+
+    return 0;
+}
+
+/* SSP devices */
+
+#define CORGI_SSP_PORT		2
+
+#define SPITZ_GPIO_LCDCON_CS	53
+#define SPITZ_GPIO_ADS7846_CS	14
+#define SPITZ_GPIO_MAX1111_CS	20
+#define SPITZ_GPIO_TP_INT	11
+
+static DeviceState *max1111;
+
+/* "Demux" the signal based on current chipselect */
+typedef struct {
+    SSISlave ssidev;
+    SSIBus *bus[3];
+    uint32_t enable[3];
+} CorgiSSPState;
+
+static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
+{
+    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        if (s->enable[i]) {
+            return ssi_transfer(s->bus[i], value);
+        }
+    }
+    return 0;
+}
+
+static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
+{
+    CorgiSSPState *s = (CorgiSSPState *)opaque;
+    assert(line >= 0 && line < 3);
+    s->enable[line] = !level;
+}
+
+#define MAX1111_BATT_VOLT	1
+#define MAX1111_BATT_TEMP	2
+#define MAX1111_ACIN_VOLT	3
+
+#define SPITZ_BATTERY_TEMP	0xe0	/* About 2.9V */
+#define SPITZ_BATTERY_VOLT	0xd0	/* About 4.0V */
+#define SPITZ_CHARGEON_ACIN	0x80	/* About 5.0V */
+
+static void spitz_adc_temp_on(void *opaque, int line, int level)
+{
+    if (!max1111)
+        return;
+
+    if (level)
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
+    else
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+}
+
+static int corgi_ssp_init(SSISlave *dev)
+{
+    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+
+    qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
+    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
+    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
+    s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
+
+    return 0;
+}
+
+static void spitz_ssp_attach(PXA2xxState *cpu)
+{
+    DeviceState *mux;
+    DeviceState *dev;
+    void *bus;
+
+    mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
+
+    bus = qdev_get_child_bus(mux, "ssi0");
+    ssi_create_slave(bus, "spitz-lcdtg");
+
+    bus = qdev_get_child_bus(mux, "ssi1");
+    dev = ssi_create_slave(bus, "ads7846");
+    qdev_connect_gpio_out(dev, 0,
+                          qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
+
+    bus = qdev_get_child_bus(mux, "ssi2");
+    max1111 = ssi_create_slave(bus, "max1111");
+    max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
+    max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+    max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
+
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
+                        qdev_get_gpio_in(mux, 0));
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
+                        qdev_get_gpio_in(mux, 1));
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
+                        qdev_get_gpio_in(mux, 2));
+}
+
+/* CF Microdrive */
+
+static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
+{
+    PCMCIACardState *md;
+    BlockDriverState *bs;
+    DriveInfo *dinfo;
+
+    dinfo = drive_get(IF_IDE, 0, 0);
+    if (!dinfo)
+        return;
+    bs = dinfo->bdrv;
+    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
+        md = dscm1xxxx_init(dinfo);
+        pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
+    }
+}
+
+/* Wm8750 and Max7310 on I2C */
+
+#define AKITA_MAX_ADDR	0x18
+#define SPITZ_WM_ADDRL	0x1b
+#define SPITZ_WM_ADDRH	0x1a
+
+#define SPITZ_GPIO_WM	5
+
+static void spitz_wm8750_addr(void *opaque, int line, int level)
+{
+    i2c_slave *wm = (i2c_slave *) opaque;
+    if (level)
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
+    else
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
+}
+
+static void spitz_i2c_setup(PXA2xxState *cpu)
+{
+    /* Attach the CPU on one end of our I2C bus.  */
+    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+
+    DeviceState *wm;
+
+    /* Attach a WM8750 to the bus */
+    wm = i2c_create_slave(bus, "wm8750", 0);
+
+    spitz_wm8750_addr(wm, 0, 0);
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
+                    qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]);
+    /* .. and to the sound interface.  */
+    cpu->i2s->opaque = wm;
+    cpu->i2s->codec_out = wm8750_dac_dat;
+    cpu->i2s->codec_in = wm8750_adc_dat;
+    wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
+}
+
+static void spitz_akita_i2c_setup(PXA2xxState *cpu)
+{
+    /* Attach a Max7310 to Akita I2C bus.  */
+    i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
+                     AKITA_MAX_ADDR);
+}
+
+/* Other peripherals */
+
+static void spitz_out_switch(void *opaque, int line, int level)
+{
+    switch (line) {
+    case 0:
+        zaurus_printf("Charging %s.\n", level ? "off" : "on");
+        break;
+    case 1:
+        zaurus_printf("Discharging %s.\n", level ? "on" : "off");
+        break;
+    case 2:
+        zaurus_printf("Green LED %s.\n", level ? "on" : "off");
+        break;
+    case 3:
+        zaurus_printf("Orange LED %s.\n", level ? "on" : "off");
+        break;
+    case 4:
+        spitz_bl_bit5(opaque, line, level);
+        break;
+    case 5:
+        spitz_bl_power(opaque, line, level);
+        break;
+    case 6:
+        spitz_adc_temp_on(opaque, line, level);
+        break;
+    }
+}
+
+#define SPITZ_SCP_LED_GREEN		1
+#define SPITZ_SCP_JK_B			2
+#define SPITZ_SCP_CHRG_ON		3
+#define SPITZ_SCP_MUTE_L		4
+#define SPITZ_SCP_MUTE_R		5
+#define SPITZ_SCP_CF_POWER		6
+#define SPITZ_SCP_LED_ORANGE		7
+#define SPITZ_SCP_JK_A			8
+#define SPITZ_SCP_ADC_TEMP_ON		9
+#define SPITZ_SCP2_IR_ON		1
+#define SPITZ_SCP2_AKIN_PULLUP		2
+#define SPITZ_SCP2_BACKLIGHT_CONT	7
+#define SPITZ_SCP2_BACKLIGHT_ON		8
+#define SPITZ_SCP2_MIC_BIAS		9
+
+static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
+                DeviceState *scp0, DeviceState *scp1)
+{
+    qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
+
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
+
+    if (scp1) {
+        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
+        qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
+    }
+
+    qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
+}
+
+#define SPITZ_GPIO_HSYNC		22
+#define SPITZ_GPIO_SD_DETECT		9
+#define SPITZ_GPIO_SD_WP		81
+#define SPITZ_GPIO_ON_RESET		89
+#define SPITZ_GPIO_BAT_COVER		90
+#define SPITZ_GPIO_CF1_IRQ		105
+#define SPITZ_GPIO_CF1_CD		94
+#define SPITZ_GPIO_CF2_IRQ		106
+#define SPITZ_GPIO_CF2_CD		93
+
+static int spitz_hsync;
+
+static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
+{
+    PXA2xxState *cpu = (PXA2xxState *) opaque;
+    qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
+    spitz_hsync ^= 1;
+}
+
+static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
+{
+    qemu_irq lcd_hsync;
+    /*
+     * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
+     * read to satisfy broken guests that poll-wait for hsync.
+     * Simulating a real hsync event would be less practical and
+     * wouldn't guarantee that a guest ever exits the loop.
+     */
+    spitz_hsync = 0;
+    lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0];
+    pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
+    pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc,
+                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
+                    qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
+
+    /* Battery lock always closed */
+    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
+
+    /* Handle reset */
+    qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
+
+    /* PCMCIA signals: card's IRQ and Card-Detect */
+    if (slots >= 1)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
+    if (slots >= 2)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
+}
+
+/* Board init.  */
+enum spitz_model_e { spitz, akita, borzoi, terrier };
+
+#define SPITZ_RAM	0x04000000
+#define SPITZ_ROM	0x00800000
+
+static struct arm_boot_info spitz_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void spitz_common_init(ram_addr_t ram_size,
+                const char *kernel_filename,
+                const char *kernel_cmdline, const char *initrd_filename,
+                const char *cpu_model, enum spitz_model_e model, int arm_id)
+{
+    PXA2xxState *cpu;
+    DeviceState *scp0, *scp1 = NULL;
+
+    if (!cpu_model)
+        cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
+
+    /* Setup CPU & memory */
+    cpu = pxa270_init(spitz_binfo.ram_size, cpu_model);
+
+    sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
+
+    cpu_register_physical_memory(0, SPITZ_ROM,
+                    qemu_ram_alloc(NULL, "spitz.rom", SPITZ_ROM) | IO_MEM_ROM);
+
+    /* Setup peripherals */
+    spitz_keyboard_register(cpu);
+
+    spitz_ssp_attach(cpu);
+
+    scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
+    if (model != akita) {
+        scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
+    }
+
+    spitz_scoop_gpio_setup(cpu, scp0, scp1);
+
+    spitz_gpio_setup(cpu, (model == akita) ? 1 : 2);
+
+    spitz_i2c_setup(cpu);
+
+    if (model == akita)
+        spitz_akita_i2c_setup(cpu);
+
+    if (model == terrier)
+        /* A 6.0 GB microdrive is permanently sitting in CF slot 1.  */
+        spitz_microdrive_attach(cpu, 1);
+    else if (model != akita)
+        /* A 4.0 GB microdrive is permanently sitting in CF slot 0.  */
+        spitz_microdrive_attach(cpu, 0);
+
+    spitz_binfo.kernel_filename = kernel_filename;
+    spitz_binfo.kernel_cmdline = kernel_cmdline;
+    spitz_binfo.initrd_filename = initrd_filename;
+    spitz_binfo.board_id = arm_id;
+    arm_load_kernel(cpu->env, &spitz_binfo);
+    sl_bootparam_write(SL_PXA_PARAM_BASE);
+}
+
+static void spitz_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    spitz_common_init(ram_size, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9);
+}
+
+static void borzoi_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    spitz_common_init(ram_size, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f);
+}
+
+static void akita_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    spitz_common_init(ram_size, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8);
+}
+
+static void terrier_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    spitz_common_init(ram_size, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f);
+}
+
+static QEMUMachine akitapda_machine = {
+    .name = "akita",
+    .desc = "Akita PDA (PXA270)",
+    .init = akita_init,
+};
+
+static QEMUMachine spitzpda_machine = {
+    .name = "spitz",
+    .desc = "Spitz PDA (PXA270)",
+    .init = spitz_init,
+};
+
+static QEMUMachine borzoipda_machine = {
+    .name = "borzoi",
+    .desc = "Borzoi PDA (PXA270)",
+    .init = borzoi_init,
+};
+
+static QEMUMachine terrierpda_machine = {
+    .name = "terrier",
+    .desc = "Terrier PDA (PXA270)",
+    .init = terrier_init,
+};
+
+static void spitz_machine_init(void)
+{
+    qemu_register_machine(&akitapda_machine);
+    qemu_register_machine(&spitzpda_machine);
+    qemu_register_machine(&borzoipda_machine);
+    qemu_register_machine(&terrierpda_machine);
+}
+
+machine_init(spitz_machine_init);
+
+static bool is_version_0(void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static VMStateDescription vmstate_sl_nand_info = {
+    .name = "sl-nand",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(ctl, SLNANDState),
+        VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo sl_nand_info = {
+    .init = sl_nand_init,
+    .qdev.name = "sl-nand",
+    .qdev.size = sizeof(SLNANDState),
+    .qdev.vmsd = &vmstate_sl_nand_info,
+    .qdev.props = (Property []) {
+        DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+        DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static VMStateDescription vmstate_spitz_kbd = {
+    .name = "spitz-keyboard",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = spitz_keyboard_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT16(sense_state, SpitzKeyboardState),
+        VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
+        VMSTATE_UNUSED_TEST(is_version_0, 5),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo spitz_keyboard_info = {
+    .init = spitz_keyboard_init,
+    .qdev.name = "spitz-keyboard",
+    .qdev.size = sizeof(SpitzKeyboardState),
+    .qdev.vmsd = &vmstate_spitz_kbd,
+    .qdev.props = (Property []) {
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_corgi_ssp_regs = {
+    .name = "corgi-ssp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static SSISlaveInfo corgi_ssp_info = {
+    .qdev.name = "corgi-ssp",
+    .qdev.size = sizeof(CorgiSSPState),
+    .qdev.vmsd = &vmstate_corgi_ssp_regs,
+    .init = corgi_ssp_init,
+    .transfer = corgi_ssp_transfer
+};
+
+static const VMStateDescription vmstate_spitz_lcdtg_regs = {
+    .name = "spitz-lcdtg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
+        VMSTATE_UINT32(bl_power, SpitzLCDTG),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static SSISlaveInfo spitz_lcdtg_info = {
+    .qdev.name = "spitz-lcdtg",
+    .qdev.size = sizeof(SpitzLCDTG),
+    .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
+    .init = spitz_lcdtg_init,
+    .transfer = spitz_lcdtg_transfer
+};
+
+static void spitz_register_devices(void)
+{
+    ssi_register_slave(&corgi_ssp_info);
+    ssi_register_slave(&spitz_lcdtg_info);
+    sysbus_register_withprop(&spitz_keyboard_info);
+    sysbus_register_withprop(&sl_nand_info);
+}
+
+device_init(spitz_register_devices)
diff --git a/qemu-0.15.x/hw/srp.h b/qemu-0.15.x/hw/srp.h
new file mode 100644
index 0000000..afcd135
--- /dev/null
+++ b/qemu-0.15.x/hw/srp.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * 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 SCSI_SRP_H
+#define SCSI_SRP_H
+
+/*
+ * Structures and constants for the SCSI RDMA Protocol (SRP) as
+ * defined by the INCITS T10 committee.  This file was written using
+ * draft Revision 16a of the SRP standard.
+ */
+
+enum {
+
+    SRP_LOGIN_REQ = 0x00,
+    SRP_TSK_MGMT  = 0x01,
+    SRP_CMD       = 0x02,
+    SRP_I_LOGOUT  = 0x03,
+    SRP_LOGIN_RSP = 0xc0,
+    SRP_RSP       = 0xc1,
+    SRP_LOGIN_REJ = 0xc2,
+    SRP_T_LOGOUT  = 0x80,
+    SRP_CRED_REQ  = 0x81,
+    SRP_AER_REQ   = 0x82,
+    SRP_CRED_RSP  = 0x41,
+    SRP_AER_RSP   = 0x42
+};
+
+enum {
+    SRP_BUF_FORMAT_DIRECT   = 1 << 1,
+    SRP_BUF_FORMAT_INDIRECT = 1 << 2
+};
+
+enum {
+    SRP_NO_DATA_DESC       = 0,
+    SRP_DATA_DESC_DIRECT   = 1,
+    SRP_DATA_DESC_INDIRECT = 2
+};
+
+enum {
+    SRP_TSK_ABORT_TASK     = 0x01,
+    SRP_TSK_ABORT_TASK_SET = 0x02,
+    SRP_TSK_CLEAR_TASK_SET = 0x04,
+    SRP_TSK_LUN_RESET      = 0x08,
+    SRP_TSK_CLEAR_ACA      = 0x40
+};
+
+enum srp_login_rej_reason {
+    SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL   = 0x00010000,
+    SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES     = 0x00010001,
+    SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
+    SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL   = 0x00010003,
+    SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
+    SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED  = 0x00010005,
+    SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED      = 0x00010006
+};
+
+enum {
+    SRP_REV10_IB_IO_CLASS  = 0xff00,
+    SRP_REV16A_IB_IO_CLASS = 0x0100
+};
+
+struct srp_direct_buf {
+    uint64_t    va;
+    uint32_t    key;
+    uint32_t    len;
+};
+
+/*
+ * We need the packed attribute because the SRP spec puts the list of
+ * descriptors at an offset of 20, which is not aligned to the size of
+ * struct srp_direct_buf.  The whole structure must be packed to avoid
+ * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
+ */
+struct srp_indirect_buf {
+    struct srp_direct_buf    table_desc;
+    uint32_t                 len;
+    struct srp_direct_buf    desc_list[0];
+} __attribute__((packed));
+
+enum {
+    SRP_MULTICHAN_SINGLE = 0,
+    SRP_MULTICHAN_MULTI  = 1
+};
+
+struct srp_login_req {
+    uint8_t    opcode;
+    uint8_t    reserved1[7];
+    uint64_t   tag;
+    uint32_t   req_it_iu_len;
+    uint8_t    reserved2[4];
+    uint16_t   req_buf_fmt;
+    uint8_t    req_flags;
+    uint8_t    reserved3[5];
+    uint8_t    initiator_port_id[16];
+    uint8_t    target_port_id[16];
+};
+
+/*
+ * The SRP spec defines the size of the LOGIN_RSP structure to be 52
+ * bytes, so it needs to be packed to avoid having it padded to 56
+ * bytes on 64-bit architectures.
+ */
+struct srp_login_rsp {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint32_t   max_it_iu_len;
+    uint32_t   max_ti_iu_len;
+    uint16_t   buf_fmt;
+    uint8_t    rsp_flags;
+    uint8_t    reserved2[25];
+} __attribute__((packed));
+
+struct srp_login_rej {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   reason;
+    uint64_t   tag;
+    uint8_t    reserved2[8];
+    uint16_t   buf_fmt;
+    uint8_t    reserved3[6];
+};
+
+struct srp_i_logout {
+    uint8_t    opcode;
+    uint8_t    reserved[7];
+    uint64_t   tag;
+};
+
+struct srp_t_logout {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved[2];
+    uint32_t   reason;
+    uint64_t   tag;
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_tsk_mgmt {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[6];
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3[2];
+    uint8_t    tsk_mgmt_func;
+    uint8_t    reserved4;
+    uint64_t   task_tag;
+    uint8_t    reserved5[8];
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_cmd {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[3];
+    uint8_t    buf_fmt;
+    uint8_t    data_out_desc_cnt;
+    uint8_t    data_in_desc_cnt;
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3;
+    uint8_t    task_attr;
+    uint8_t    reserved4;
+    uint8_t    add_cdb_len;
+    uint8_t    cdb[16];
+    uint8_t    add_data[0];
+};
+
+enum {
+    SRP_RSP_FLAG_RSPVALID = 1 << 0,
+    SRP_RSP_FLAG_SNSVALID = 1 << 1,
+    SRP_RSP_FLAG_DOOVER   = 1 << 2,
+    SRP_RSP_FLAG_DOUNDER  = 1 << 3,
+    SRP_RSP_FLAG_DIOVER   = 1 << 4,
+    SRP_RSP_FLAG_DIUNDER  = 1 << 5
+};
+
+/*
+ * The SRP spec defines the size of the RSP structure to be 36 bytes,
+ * so it needs to be packed to avoid having it padded to 40 bytes on
+ * 64-bit architectures.
+ */
+struct srp_rsp {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[2];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint8_t    reserved2[2];
+    uint8_t    flags;
+    uint8_t    status;
+    uint32_t   data_out_res_cnt;
+    uint32_t   data_in_res_cnt;
+    uint32_t   sense_data_len;
+    uint32_t   resp_data_len;
+    uint8_t    data[0];
+} __attribute__((packed));
+
+#endif /* SCSI_SRP_H */
diff --git a/qemu-0.15.x/hw/ssd0303.c b/qemu-0.15.x/hw/ssd0303.c
new file mode 100644
index 0000000..401fdf5
--- /dev/null
+++ b/qemu-0.15.x/hw/ssd0303.c
@@ -0,0 +1,312 @@
+/*
+ * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* The controller can support a variety of different displays, but we only
+   implement one.  Most of the commends relating to brightness and geometry
+   setup are ignored. */
+#include "i2c.h"
+#include "console.h"
+
+//#define DEBUG_SSD0303 1
+
+#ifdef DEBUG_SSD0303
+#define DPRINTF(fmt, ...) \
+do { printf("ssd0303: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+/* Scaling factor for pixels.  */
+#define MAGNIFY 4
+
+enum ssd0303_mode
+{
+    SSD0303_IDLE,
+    SSD0303_DATA,
+    SSD0303_CMD
+};
+
+enum ssd0303_cmd {
+    SSD0303_CMD_NONE,
+    SSD0303_CMD_SKIP1
+};
+
+typedef struct {
+    i2c_slave i2c;
+    DisplayState *ds;
+    int row;
+    int col;
+    int start_line;
+    int mirror;
+    int flash;
+    int enabled;
+    int inverse;
+    int redraw;
+    enum ssd0303_mode mode;
+    enum ssd0303_cmd cmd_state;
+    uint8_t framebuffer[132*8];
+} ssd0303_state;
+
+static int ssd0303_recv(i2c_slave *i2c)
+{
+    BADF("Reads not implemented\n");
+    return -1;
+}
+
+static int ssd0303_send(i2c_slave *i2c, uint8_t data)
+{
+    ssd0303_state *s = (ssd0303_state *)i2c;
+    enum ssd0303_cmd old_cmd_state;
+    switch (s->mode) {
+    case SSD0303_IDLE:
+        DPRINTF("byte 0x%02x\n", data);
+        if (data == 0x80)
+            s->mode = SSD0303_CMD;
+        else if (data == 0x40)
+            s->mode = SSD0303_DATA;
+        else
+            BADF("Unexpected byte 0x%x\n", data);
+        break;
+    case SSD0303_DATA:
+        DPRINTF("data 0x%02x\n", data);
+        if (s->col < 132) {
+            s->framebuffer[s->col + s->row * 132] = data;
+            s->col++;
+            s->redraw = 1;
+        }
+        break;
+    case SSD0303_CMD:
+        old_cmd_state = s->cmd_state;
+        s->cmd_state = SSD0303_CMD_NONE;
+        switch (old_cmd_state) {
+        case SSD0303_CMD_NONE:
+            DPRINTF("cmd 0x%02x\n", data);
+            s->mode = SSD0303_IDLE;
+            switch (data) {
+            case 0x00 ... 0x0f: /* Set lower column address.  */
+                s->col = (s->col & 0xf0) | (data & 0xf);
+                break;
+            case 0x10 ... 0x20: /* Set higher column address.  */
+                s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
+                break;
+            case 0x40 ... 0x7f: /* Set start line.  */
+                s->start_line = 0;
+                break;
+            case 0x81: /* Set contrast (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xa0: /* Mirror off.  */
+                s->mirror = 0;
+                break;
+            case 0xa1: /* Mirror off.  */
+                s->mirror = 1;
+                break;
+            case 0xa4: /* Entire display off.  */
+                s->flash = 0;
+                break;
+            case 0xa5: /* Entire display on.  */
+                s->flash = 1;
+                break;
+            case 0xa6: /* Inverse off.  */
+                s->inverse = 0;
+                break;
+            case 0xa7: /* Inverse on.  */
+                s->inverse = 1;
+                break;
+            case 0xa8: /* Set multipled ratio (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xad: /* DC-DC power control.  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xae: /* Display off.  */
+                s->enabled = 0;
+                break;
+            case 0xaf: /* Display on.  */
+                s->enabled = 1;
+                break;
+            case 0xb0 ... 0xbf: /* Set Page address.  */
+                s->row = data & 7;
+                break;
+            case 0xc0 ... 0xc8: /* Set COM output direction (Ignored).  */
+                break;
+            case 0xd3: /* Set display offset (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd5: /* Set display clock (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd8: /* Set color and power mode (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd9: /* Set pre-charge period (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xda: /* Set COM pin configuration (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xdb: /* Set VCOM dselect level (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xe3: /* no-op.  */
+                break;
+            default:
+                BADF("Unknown command: 0x%x\n", data);
+            }
+            break;
+        case SSD0303_CMD_SKIP1:
+            DPRINTF("skip 0x%02x\n", data);
+            break;
+        }
+        break;
+    }
+    return 0;
+}
+
+static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
+{
+    ssd0303_state *s = (ssd0303_state *)i2c;
+    switch (event) {
+    case I2C_FINISH:
+        s->mode = SSD0303_IDLE;
+        break;
+    case I2C_START_RECV:
+    case I2C_START_SEND:
+    case I2C_NACK:
+        /* Nothing to do.  */
+        break;
+    }
+}
+
+static void ssd0303_update_display(void *opaque)
+{
+    ssd0303_state *s = (ssd0303_state *)opaque;
+    uint8_t *dest;
+    uint8_t *src;
+    int x;
+    int y;
+    int line;
+    char *colors[2];
+    char colortab[MAGNIFY * 8];
+    int dest_width;
+    uint8_t mask;
+
+    if (!s->redraw)
+        return;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 15:
+        dest_width = 2;
+        break;
+    case 16:
+        dest_width = 2;
+        break;
+    case 24:
+        dest_width = 3;
+        break;
+    case 32:
+        dest_width = 4;
+        break;
+    default:
+        BADF("Bad color depth\n");
+        return;
+    }
+    dest_width *= MAGNIFY;
+    memset(colortab, 0xff, dest_width);
+    memset(colortab + dest_width, 0, dest_width);
+    if (s->flash) {
+        colors[0] = colortab;
+        colors[1] = colortab;
+    } else if (s->inverse) {
+        colors[0] = colortab;
+        colors[1] = colortab + dest_width;
+    } else {
+        colors[0] = colortab + dest_width;
+        colors[1] = colortab;
+    }
+    dest = ds_get_data(s->ds);
+    for (y = 0; y < 16; y++) {
+        line = (y + s->start_line) & 63;
+        src = s->framebuffer + 132 * (line >> 3) + 36;
+        mask = 1 << (line & 7);
+        for (x = 0; x < 96; x++) {
+            memcpy(dest, colors[(*src & mask) != 0], dest_width);
+            dest += dest_width;
+            src++;
+        }
+        for (x = 1; x < MAGNIFY; x++) {
+            memcpy(dest, dest - dest_width * 96, dest_width * 96);
+            dest += dest_width * 96;
+        }
+    }
+    s->redraw = 0;
+    dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
+}
+
+static void ssd0303_invalidate_display(void * opaque)
+{
+    ssd0303_state *s = (ssd0303_state *)opaque;
+    s->redraw = 1;
+}
+
+static const VMStateDescription vmstate_ssd0303 = {
+    .name = "ssd0303_oled",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(row, ssd0303_state),
+        VMSTATE_INT32(col, ssd0303_state),
+        VMSTATE_INT32(start_line, ssd0303_state),
+        VMSTATE_INT32(mirror, ssd0303_state),
+        VMSTATE_INT32(flash, ssd0303_state),
+        VMSTATE_INT32(enabled, ssd0303_state),
+        VMSTATE_INT32(inverse, ssd0303_state),
+        VMSTATE_INT32(redraw, ssd0303_state),
+        VMSTATE_UINT32(mode, ssd0303_state),
+        VMSTATE_UINT32(cmd_state, ssd0303_state),
+        VMSTATE_BUFFER(framebuffer, ssd0303_state),
+        VMSTATE_I2C_SLAVE(i2c, ssd0303_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ssd0303_init(i2c_slave *i2c)
+{
+    ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
+
+    s->ds = graphic_console_init(ssd0303_update_display,
+                                 ssd0303_invalidate_display,
+                                 NULL, NULL, s);
+    qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
+    return 0;
+}
+
+static I2CSlaveInfo ssd0303_info = {
+    .qdev.name = "ssd0303",
+    .qdev.size = sizeof(ssd0303_state),
+    .qdev.vmsd = &vmstate_ssd0303,
+    .init = ssd0303_init,
+    .event = ssd0303_event,
+    .recv = ssd0303_recv,
+    .send = ssd0303_send
+};
+
+static void ssd0303_register_devices(void)
+{
+    i2c_register_slave(&ssd0303_info);
+}
+
+device_init(ssd0303_register_devices)
diff --git a/qemu-0.15.x/hw/ssd0323.c b/qemu-0.15.x/hw/ssd0323.c
new file mode 100644
index 0000000..1eb3823
--- /dev/null
+++ b/qemu-0.15.x/hw/ssd0323.c
@@ -0,0 +1,355 @@
+/*
+ * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* The controller can support a variety of different displays, but we only
+   implement one.  Most of the commends relating to brightness and geometry
+   setup are ignored. */
+#include "ssi.h"
+#include "console.h"
+
+//#define DEBUG_SSD0323 1
+
+#ifdef DEBUG_SSD0323
+#define DPRINTF(fmt, ...) \
+do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+/* Scaling factor for pixels.  */
+#define MAGNIFY 4
+
+#define REMAP_SWAP_COLUMN 0x01
+#define REMAP_SWAP_NYBBLE 0x02
+#define REMAP_VERTICAL    0x04
+#define REMAP_SWAP_COM    0x10
+#define REMAP_SPLIT_COM   0x40
+
+enum ssd0323_mode
+{
+    SSD0323_CMD,
+    SSD0323_DATA
+};
+
+typedef struct {
+    SSISlave ssidev;
+    DisplayState *ds;
+
+    int cmd_len;
+    int cmd;
+    int cmd_data[8];
+    int row;
+    int row_start;
+    int row_end;
+    int col;
+    int col_start;
+    int col_end;
+    int redraw;
+    int remap;
+    enum ssd0323_mode mode;
+    uint8_t framebuffer[128 * 80 / 2];
+} ssd0323_state;
+
+static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
+{
+    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+
+    switch (s->mode) {
+    case SSD0323_DATA:
+        DPRINTF("data 0x%02x\n", data);
+        s->framebuffer[s->col + s->row * 64] = data;
+        if (s->remap & REMAP_VERTICAL) {
+            s->row++;
+            if (s->row > s->row_end) {
+                s->row = s->row_start;
+                s->col++;
+            }
+            if (s->col > s->col_end) {
+                s->col = s->col_start;
+            }
+        } else {
+            s->col++;
+            if (s->col > s->col_end) {
+                s->row++;
+                s->col = s->col_start;
+            }
+            if (s->row > s->row_end) {
+                s->row = s->row_start;
+            }
+        }
+        s->redraw = 1;
+        break;
+    case SSD0323_CMD:
+        DPRINTF("cmd 0x%02x\n", data);
+        if (s->cmd_len == 0) {
+            s->cmd = data;
+        } else {
+            s->cmd_data[s->cmd_len - 1] = data;
+        }
+        s->cmd_len++;
+        switch (s->cmd) {
+#define DATA(x) if (s->cmd_len <= (x)) return 0
+        case 0x15: /* Set column.  */
+            DATA(2);
+            s->col = s->col_start = s->cmd_data[0] % 64;
+            s->col_end = s->cmd_data[1] % 64;
+            break;
+        case 0x75: /* Set row.  */
+            DATA(2);
+            s->row = s->row_start = s->cmd_data[0] % 80;
+            s->row_end = s->cmd_data[1] % 80;
+            break;
+        case 0x81: /* Set contrast */
+            DATA(1);
+            break;
+        case 0x84: case 0x85: case 0x86: /* Max current.  */
+            DATA(0);
+            break;
+        case 0xa0: /* Set remapping.  */
+            /* FIXME: Implement this.  */
+            DATA(1);
+            s->remap = s->cmd_data[0];
+            break;
+        case 0xa1: /* Set display start line.  */
+        case 0xa2: /* Set display offset.  */
+            /* FIXME: Implement these.  */
+            DATA(1);
+            break;
+        case 0xa4: /* Normal mode.  */
+        case 0xa5: /* All on.  */
+        case 0xa6: /* All off.  */
+        case 0xa7: /* Inverse.  */
+            /* FIXME: Implement these.  */
+            DATA(0);
+            break;
+        case 0xa8: /* Set multiplex ratio.  */
+        case 0xad: /* Set DC-DC converter.  */
+            DATA(1);
+            /* Ignored.  Don't care.  */
+            break;
+        case 0xae: /* Display off.  */
+        case 0xaf: /* Display on.  */
+            DATA(0);
+            /* TODO: Implement power control.  */
+            break;
+        case 0xb1: /* Set phase length.  */
+        case 0xb2: /* Set row period.  */
+        case 0xb3: /* Set clock rate.  */
+        case 0xbc: /* Set precharge.  */
+        case 0xbe: /* Set VCOMH.  */
+        case 0xbf: /* Set segment low.  */
+            DATA(1);
+            /* Ignored.  Don't care.  */
+            break;
+        case 0xb8: /* Set grey scale table.  */
+            /* FIXME: Implement this.  */
+            DATA(8);
+            break;
+        case 0xe3: /* NOP.  */
+            DATA(0);
+            break;
+        case 0xff: /* Nasty hack because we don't handle chip selects
+                      properly.  */
+            break;
+        default:
+            BADF("Unknown command: 0x%x\n", data);
+        }
+        s->cmd_len = 0;
+        return 0;
+    }
+    return 0;
+}
+
+static void ssd0323_update_display(void *opaque)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    uint8_t *dest;
+    uint8_t *src;
+    int x;
+    int y;
+    int i;
+    int line;
+    char *colors[16];
+    char colortab[MAGNIFY * 64];
+    char *p;
+    int dest_width;
+
+    if (!s->redraw)
+        return;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 15:
+        dest_width = 2;
+        break;
+    case 16:
+        dest_width = 2;
+        break;
+    case 24:
+        dest_width = 3;
+        break;
+    case 32:
+        dest_width = 4;
+        break;
+    default:
+        BADF("Bad color depth\n");
+        return;
+    }
+    p = colortab;
+    for (i = 0; i < 16; i++) {
+        int n;
+        colors[i] = p;
+        switch (ds_get_bits_per_pixel(s->ds)) {
+        case 15:
+            n = i * 2 + (i >> 3);
+            p[0] = n | (n << 5);
+            p[1] = (n << 2) | (n >> 3);
+            break;
+        case 16:
+            n = i * 2 + (i >> 3);
+            p[0] = n | (n << 6) | ((n << 1) & 0x20);
+            p[1] = (n << 3) | (n >> 2);
+            break;
+        case 24:
+        case 32:
+            n = (i << 4) | i;
+            p[0] = p[1] = p[2] = n;
+            break;
+        default:
+            BADF("Bad color depth\n");
+            return;
+        }
+        p += dest_width;
+    }
+    /* TODO: Implement row/column remapping.  */
+    dest = ds_get_data(s->ds);
+    for (y = 0; y < 64; y++) {
+        line = y;
+        src = s->framebuffer + 64 * line;
+        for (x = 0; x < 64; x++) {
+            int val;
+            val = *src >> 4;
+            for (i = 0; i < MAGNIFY; i++) {
+                memcpy(dest, colors[val], dest_width);
+                dest += dest_width;
+            }
+            val = *src & 0xf;
+            for (i = 0; i < MAGNIFY; i++) {
+                memcpy(dest, colors[val], dest_width);
+                dest += dest_width;
+            }
+            src++;
+        }
+        for (i = 1; i < MAGNIFY; i++) {
+            memcpy(dest, dest - dest_width * MAGNIFY * 128,
+                   dest_width * 128 * MAGNIFY);
+            dest += dest_width * 128 * MAGNIFY;
+        }
+    }
+    s->redraw = 0;
+    dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
+}
+
+static void ssd0323_invalidate_display(void * opaque)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    s->redraw = 1;
+}
+
+/* Command/data input.  */
+static void ssd0323_cd(void *opaque, int n, int level)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    DPRINTF("%s mode\n", level ? "Data" : "Command");
+    s->mode = level ? SSD0323_DATA : SSD0323_CMD;
+}
+
+static void ssd0323_save(QEMUFile *f, void *opaque)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->cmd_len);
+    qemu_put_be32(f, s->cmd);
+    for (i = 0; i < 8; i++)
+        qemu_put_be32(f, s->cmd_data[i]);
+    qemu_put_be32(f, s->row);
+    qemu_put_be32(f, s->row_start);
+    qemu_put_be32(f, s->row_end);
+    qemu_put_be32(f, s->col);
+    qemu_put_be32(f, s->col_start);
+    qemu_put_be32(f, s->col_end);
+    qemu_put_be32(f, s->redraw);
+    qemu_put_be32(f, s->remap);
+    qemu_put_be32(f, s->mode);
+    qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+}
+
+static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->cmd_len = qemu_get_be32(f);
+    s->cmd = qemu_get_be32(f);
+    for (i = 0; i < 8; i++)
+        s->cmd_data[i] = qemu_get_be32(f);
+    s->row = qemu_get_be32(f);
+    s->row_start = qemu_get_be32(f);
+    s->row_end = qemu_get_be32(f);
+    s->col = qemu_get_be32(f);
+    s->col_start = qemu_get_be32(f);
+    s->col_end = qemu_get_be32(f);
+    s->redraw = qemu_get_be32(f);
+    s->remap = qemu_get_be32(f);
+    s->mode = qemu_get_be32(f);
+    qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+    return 0;
+}
+
+static int ssd0323_init(SSISlave *dev)
+{
+    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+
+    s->col_end = 63;
+    s->row_end = 79;
+    s->ds = graphic_console_init(ssd0323_update_display,
+                                 ssd0323_invalidate_display,
+                                 NULL, NULL, s);
+    qemu_console_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
+
+    qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
+
+    register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
+                    ssd0323_save, ssd0323_load, s);
+    return 0;
+}
+
+static SSISlaveInfo ssd0323_info = {
+    .qdev.name = "ssd0323",
+    .qdev.size = sizeof(ssd0323_state),
+    .init = ssd0323_init,
+    .transfer = ssd0323_transfer
+};
+
+static void ssd03232_register_devices(void)
+{
+    ssi_register_slave(&ssd0323_info);
+}
+
+device_init(ssd03232_register_devices)
diff --git a/qemu-0.15.x/hw/ssi-sd.c b/qemu-0.15.x/hw/ssi-sd.c
new file mode 100644
index 0000000..18dabd6
--- /dev/null
+++ b/qemu-0.15.x/hw/ssi-sd.c
@@ -0,0 +1,256 @@
+/*
+ * SSI to SD card adapter.
+ *
+ * Copyright (c) 2007-2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "blockdev.h"
+#include "ssi.h"
+#include "sd.h"
+
+//#define DEBUG_SSI_SD 1
+
+#ifdef DEBUG_SSI_SD
+#define DPRINTF(fmt, ...) \
+do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+typedef enum {
+    SSI_SD_CMD,
+    SSI_SD_CMDARG,
+    SSI_SD_RESPONSE,
+    SSI_SD_DATA_START,
+    SSI_SD_DATA_READ,
+} ssi_sd_mode;
+
+typedef struct {
+    SSISlave ssidev;
+    ssi_sd_mode mode;
+    int cmd;
+    uint8_t cmdarg[4];
+    uint8_t response[5];
+    int arglen;
+    int response_pos;
+    int stopping;
+    SDState *sd;
+} ssi_sd_state;
+
+/* State word bits.  */
+#define SSI_SDR_LOCKED          0x0001
+#define SSI_SDR_WP_ERASE        0x0002
+#define SSI_SDR_ERROR           0x0004
+#define SSI_SDR_CC_ERROR        0x0008
+#define SSI_SDR_ECC_FAILED      0x0010
+#define SSI_SDR_WP_VIOLATION    0x0020
+#define SSI_SDR_ERASE_PARAM     0x0040
+#define SSI_SDR_OUT_OF_RANGE    0x0080
+#define SSI_SDR_IDLE            0x0100
+#define SSI_SDR_ERASE_RESET     0x0200
+#define SSI_SDR_ILLEGAL_COMMAND 0x0400
+#define SSI_SDR_COM_CRC_ERROR   0x0800
+#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
+#define SSI_SDR_ADDRESS_ERROR   0x2000
+#define SSI_SDR_PARAMETER_ERROR 0x4000
+
+static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
+{
+    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+
+    /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
+    if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
+        s->mode = SSI_SD_CMD;
+        /* There must be at least one byte delay before the card responds.  */
+        s->stopping = 1;
+    }
+
+    switch (s->mode) {
+    case SSI_SD_CMD:
+        if (val == 0xff) {
+            DPRINTF("NULL command\n");
+            return 0xff;
+        }
+        s->cmd = val & 0x3f;
+        s->mode = SSI_SD_CMDARG;
+        s->arglen = 0;
+        return 0xff;
+    case SSI_SD_CMDARG:
+        if (s->arglen == 4) {
+            SDRequest request;
+            uint8_t longresp[16];
+            /* FIXME: Check CRC.  */
+            request.cmd = s->cmd;
+            request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
+                           | (s->cmdarg[2] << 8) | s->cmdarg[3];
+            DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
+            s->arglen = sd_do_command(s->sd, &request, longresp);
+            if (s->arglen <= 0) {
+                s->arglen = 1;
+                s->response[0] = 4;
+                DPRINTF("SD command failed\n");
+            } else if (s->cmd == 58) {
+                /* CMD58 returns R3 response (OCR)  */
+                DPRINTF("Returned OCR\n");
+                s->arglen = 5;
+                s->response[0] = 1;
+                memcpy(&s->response[1], longresp, 4);
+            } else if (s->arglen != 4) {
+                BADF("Unexpected response to cmd %d\n", s->cmd);
+                /* Illegal command is about as near as we can get.  */
+                s->arglen = 1;
+                s->response[0] = 4;
+            } else {
+                /* All other commands return status.  */
+                uint32_t cardstatus;
+                uint16_t status;
+                /* CMD13 returns a 2-byte statuse work. Other commands
+                   only return the first byte.  */
+                s->arglen = (s->cmd == 13) ? 2 : 1;
+                cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
+                             | (longresp[2] << 8) | longresp[3];
+                status = 0;
+                if (((cardstatus >> 9) & 0xf) < 4)
+                    status |= SSI_SDR_IDLE;
+                if (cardstatus & ERASE_RESET)
+                    status |= SSI_SDR_ERASE_RESET;
+                if (cardstatus & ILLEGAL_COMMAND)
+                    status |= SSI_SDR_ILLEGAL_COMMAND;
+                if (cardstatus & COM_CRC_ERROR)
+                    status |= SSI_SDR_COM_CRC_ERROR;
+                if (cardstatus & ERASE_SEQ_ERROR)
+                    status |= SSI_SDR_ERASE_SEQ_ERROR;
+                if (cardstatus & ADDRESS_ERROR)
+                    status |= SSI_SDR_ADDRESS_ERROR;
+                if (cardstatus & CARD_IS_LOCKED)
+                    status |= SSI_SDR_LOCKED;
+                if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
+                    status |= SSI_SDR_WP_ERASE;
+                if (cardstatus & SD_ERROR)
+                    status |= SSI_SDR_ERROR;
+                if (cardstatus & CC_ERROR)
+                    status |= SSI_SDR_CC_ERROR;
+                if (cardstatus & CARD_ECC_FAILED)
+                    status |= SSI_SDR_ECC_FAILED;
+                if (cardstatus & WP_VIOLATION)
+                    status |= SSI_SDR_WP_VIOLATION;
+                if (cardstatus & ERASE_PARAM)
+                    status |= SSI_SDR_ERASE_PARAM;
+                if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
+                    status |= SSI_SDR_OUT_OF_RANGE;
+                /* ??? Don't know what Parameter Error really means, so
+                   assume it's set if the second byte is nonzero.  */
+                if (status & 0xff)
+                    status |= SSI_SDR_PARAMETER_ERROR;
+                s->response[0] = status >> 8;
+                s->response[1] = status;
+                DPRINTF("Card status 0x%02x\n", status);
+            }
+            s->mode = SSI_SD_RESPONSE;
+            s->response_pos = 0;
+        } else {
+            s->cmdarg[s->arglen++] = val;
+        }
+        return 0xff;
+    case SSI_SD_RESPONSE:
+        if (s->stopping) {
+            s->stopping = 0;
+            return 0xff;
+        }
+        if (s->response_pos < s->arglen) {
+            DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
+            return s->response[s->response_pos++];
+        }
+        if (sd_data_ready(s->sd)) {
+            DPRINTF("Data read\n");
+            s->mode = SSI_SD_DATA_START;
+        } else {
+            DPRINTF("End of command\n");
+            s->mode = SSI_SD_CMD;
+        }
+        return 0xff;
+    case SSI_SD_DATA_START:
+        DPRINTF("Start read block\n");
+        s->mode = SSI_SD_DATA_READ;
+        return 0xfe;
+    case SSI_SD_DATA_READ:
+        val = sd_read_data(s->sd);
+        if (!sd_data_ready(s->sd)) {
+            DPRINTF("Data read end\n");
+            s->mode = SSI_SD_CMD;
+        }
+        return val;
+    }
+    /* Should never happen.  */
+    return 0xff;
+}
+
+static void ssi_sd_save(QEMUFile *f, void *opaque)
+{
+    ssi_sd_state *s = (ssi_sd_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->mode);
+    qemu_put_be32(f, s->cmd);
+    for (i = 0; i < 4; i++)
+        qemu_put_be32(f, s->cmdarg[i]);
+    for (i = 0; i < 5; i++)
+        qemu_put_be32(f, s->response[i]);
+    qemu_put_be32(f, s->arglen);
+    qemu_put_be32(f, s->response_pos);
+    qemu_put_be32(f, s->stopping);
+}
+
+static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ssi_sd_state *s = (ssi_sd_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->mode = qemu_get_be32(f);
+    s->cmd = qemu_get_be32(f);
+    for (i = 0; i < 4; i++)
+        s->cmdarg[i] = qemu_get_be32(f);
+    for (i = 0; i < 5; i++)
+        s->response[i] = qemu_get_be32(f);
+    s->arglen = qemu_get_be32(f);
+    s->response_pos = qemu_get_be32(f);
+    s->stopping = qemu_get_be32(f);
+
+    return 0;
+}
+
+static int ssi_sd_init(SSISlave *dev)
+{
+    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+    DriveInfo *dinfo;
+
+    s->mode = SSI_SD_CMD;
+    dinfo = drive_get_next(IF_SD);
+    s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
+    register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
+    return 0;
+}
+
+static SSISlaveInfo ssi_sd_info = {
+    .qdev.name = "ssi-sd",
+    .qdev.size = sizeof(ssi_sd_state),
+    .init = ssi_sd_init,
+    .transfer = ssi_sd_transfer
+};
+
+static void ssi_sd_register_devices(void)
+{
+    ssi_register_slave(&ssi_sd_info);
+}
+
+device_init(ssi_sd_register_devices)
diff --git a/qemu-0.15.x/hw/ssi.c b/qemu-0.15.x/hw/ssi.c
new file mode 100644
index 0000000..3f4c5f9
--- /dev/null
+++ b/qemu-0.15.x/hw/ssi.c
@@ -0,0 +1,70 @@
+/*
+ * QEMU Synchronous Serial Interface support
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "ssi.h"
+
+struct SSIBus {
+    BusState qbus;
+};
+
+static struct BusInfo ssi_bus_info = {
+    .name = "SSI",
+    .size = sizeof(SSIBus),
+};
+
+static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
+{
+    SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev);
+    SSISlave *s = SSI_SLAVE_FROM_QDEV(dev);
+    SSIBus *bus;
+
+    bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
+    if (QLIST_FIRST(&bus->qbus.children) != dev
+        || QLIST_NEXT(dev, sibling) != NULL) {
+        hw_error("Too many devices on SSI bus");
+    }
+
+    s->info = info;
+    return info->init(s);
+}
+
+void ssi_register_slave(SSISlaveInfo *info)
+{
+    assert(info->qdev.size >= sizeof(SSISlave));
+    info->qdev.init = ssi_slave_init;
+    info->qdev.bus_info = &ssi_bus_info;
+    qdev_register(&info->qdev);
+}
+
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
+{
+    DeviceState *dev;
+    dev = qdev_create(&bus->qbus, name);
+    qdev_init_nofail(dev);
+    return dev;
+}
+
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
+{
+    BusState *bus;
+    bus = qbus_create(&ssi_bus_info, parent, name);
+    return FROM_QBUS(SSIBus, bus);
+}
+
+uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
+{
+    DeviceState *dev;
+    SSISlave *slave;
+    dev = QLIST_FIRST(&bus->qbus.children);
+    if (!dev) {
+        return 0;
+    }
+    slave = SSI_SLAVE_FROM_QDEV(dev);
+    return slave->info->transfer(slave, val);
+}
diff --git a/qemu-0.15.x/hw/ssi.h b/qemu-0.15.x/hw/ssi.h
new file mode 100644
index 0000000..24610a8
--- /dev/null
+++ b/qemu-0.15.x/hw/ssi.h
@@ -0,0 +1,45 @@
+/* QEMU Synchronous Serial Interface support.  */
+
+/* In principle SSI is a point-point interface.  As such the qemu
+   implementation has a single slave device on a "bus".
+   However it is fairly common for boards to have multiple slaves
+   connected to a single master, and select devices with an external
+   chip select.  This is implemented in qemu by having an explicit mux device.
+   It is assumed that master and slave are both using the same transfer width.
+   */
+
+#ifndef QEMU_SSI_H
+#define QEMU_SSI_H
+
+#include "qdev.h"
+
+typedef struct SSISlave SSISlave;
+
+/* Slave devices.  */
+typedef struct {
+    DeviceInfo qdev;
+    int (*init)(SSISlave *dev);
+    uint32_t (*transfer)(SSISlave *dev, uint32_t val);
+} SSISlaveInfo;
+
+struct SSISlave {
+    DeviceState qdev;
+    SSISlaveInfo *info;
+};
+
+#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
+#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
+
+void ssi_register_slave(SSISlaveInfo *info);
+
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
+
+/* Master interface.  */
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
+
+uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
+
+/* max111x.c */
+void max111x_set_input(DeviceState *dev, int line, uint8_t value);
+
+#endif
diff --git a/qemu-0.15.x/hw/stellaris.c b/qemu-0.15.x/hw/stellaris.c
new file mode 100644
index 0000000..a280930
--- /dev/null
+++ b/qemu-0.15.x/hw/stellaris.c
@@ -0,0 +1,1370 @@
+/*
+ * Luminary Micro Stellaris peripherals
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "ssi.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "net.h"
+#include "boards.h"
+
+#define GPIO_A 0
+#define GPIO_B 1
+#define GPIO_C 2
+#define GPIO_D 3
+#define GPIO_E 4
+#define GPIO_F 5
+#define GPIO_G 6
+
+#define BP_OLED_I2C  0x01
+#define BP_OLED_SSI  0x02
+#define BP_GAMEPAD   0x04
+
+typedef const struct {
+    const char *name;
+    uint32_t did0;
+    uint32_t did1;
+    uint32_t dc0;
+    uint32_t dc1;
+    uint32_t dc2;
+    uint32_t dc3;
+    uint32_t dc4;
+    uint32_t peripherals;
+} stellaris_board_info;
+
+/* General purpose timer module.  */
+
+typedef struct gptm_state {
+    SysBusDevice busdev;
+    uint32_t config;
+    uint32_t mode[2];
+    uint32_t control;
+    uint32_t state;
+    uint32_t mask;
+    uint32_t load[2];
+    uint32_t match[2];
+    uint32_t prescale[2];
+    uint32_t match_prescale[2];
+    uint32_t rtc;
+    int64_t tick[2];
+    struct gptm_state *opaque[2];
+    QEMUTimer *timer[2];
+    /* The timers have an alternate output used to trigger the ADC.  */
+    qemu_irq trigger;
+    qemu_irq irq;
+} gptm_state;
+
+static void gptm_update_irq(gptm_state *s)
+{
+    int level;
+    level = (s->state & s->mask) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+static void gptm_stop(gptm_state *s, int n)
+{
+    qemu_del_timer(s->timer[n]);
+}
+
+static void gptm_reload(gptm_state *s, int n, int reset)
+{
+    int64_t tick;
+    if (reset)
+        tick = qemu_get_clock_ns(vm_clock);
+    else
+        tick = s->tick[n];
+
+    if (s->config == 0) {
+        /* 32-bit CountDown.  */
+        uint32_t count;
+        count = s->load[0] | (s->load[1] << 16);
+        tick += (int64_t)count * system_clock_scale;
+    } else if (s->config == 1) {
+        /* 32-bit RTC.  1Hz tick.  */
+        tick += get_ticks_per_sec();
+    } else if (s->mode[n] == 0xa) {
+        /* PWM mode.  Not implemented.  */
+    } else {
+        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+    }
+    s->tick[n] = tick;
+    qemu_mod_timer(s->timer[n], tick);
+}
+
+static void gptm_tick(void *opaque)
+{
+    gptm_state **p = (gptm_state **)opaque;
+    gptm_state *s;
+    int n;
+
+    s = *p;
+    n = p - s->opaque;
+    if (s->config == 0) {
+        s->state |= 1;
+        if ((s->control & 0x20)) {
+            /* Output trigger.  */
+	    qemu_irq_pulse(s->trigger);
+        }
+        if (s->mode[0] & 1) {
+            /* One-shot.  */
+            s->control &= ~1;
+        } else {
+            /* Periodic.  */
+            gptm_reload(s, 0, 0);
+        }
+    } else if (s->config == 1) {
+        /* RTC.  */
+        uint32_t match;
+        s->rtc++;
+        match = s->match[0] | (s->match[1] << 16);
+        if (s->rtc > match)
+            s->rtc = 0;
+        if (s->rtc == 0) {
+            s->state |= 8;
+        }
+        gptm_reload(s, 0, 0);
+    } else if (s->mode[n] == 0xa) {
+        /* PWM mode.  Not implemented.  */
+    } else {
+        hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
+    }
+    gptm_update_irq(s);
+}
+
+static uint32_t gptm_read(void *opaque, target_phys_addr_t offset)
+{
+    gptm_state *s = (gptm_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* CFG */
+        return s->config;
+    case 0x04: /* TAMR */
+        return s->mode[0];
+    case 0x08: /* TBMR */
+        return s->mode[1];
+    case 0x0c: /* CTL */
+        return s->control;
+    case 0x18: /* IMR */
+        return s->mask;
+    case 0x1c: /* RIS */
+        return s->state;
+    case 0x20: /* MIS */
+        return s->state & s->mask;
+    case 0x24: /* CR */
+        return 0;
+    case 0x28: /* TAILR */
+        return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
+    case 0x2c: /* TBILR */
+        return s->load[1];
+    case 0x30: /* TAMARCHR */
+        return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
+    case 0x34: /* TBMATCHR */
+        return s->match[1];
+    case 0x38: /* TAPR */
+        return s->prescale[0];
+    case 0x3c: /* TBPR */
+        return s->prescale[1];
+    case 0x40: /* TAPMR */
+        return s->match_prescale[0];
+    case 0x44: /* TBPMR */
+        return s->match_prescale[1];
+    case 0x48: /* TAR */
+        if (s->control == 1)
+            return s->rtc;
+    case 0x4c: /* TBR */
+        hw_error("TODO: Timer value read\n");
+    default:
+        hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+    gptm_state *s = (gptm_state *)opaque;
+    uint32_t oldval;
+
+    /* The timers should be disabled before changing the configuration.
+       We take advantage of this and defer everything until the timer
+       is enabled.  */
+    switch (offset) {
+    case 0x00: /* CFG */
+        s->config = value;
+        break;
+    case 0x04: /* TAMR */
+        s->mode[0] = value;
+        break;
+    case 0x08: /* TBMR */
+        s->mode[1] = value;
+        break;
+    case 0x0c: /* CTL */
+        oldval = s->control;
+        s->control = value;
+        /* TODO: Implement pause.  */
+        if ((oldval ^ value) & 1) {
+            if (value & 1) {
+                gptm_reload(s, 0, 1);
+            } else {
+                gptm_stop(s, 0);
+            }
+        }
+        if (((oldval ^ value) & 0x100) && s->config >= 4) {
+            if (value & 0x100) {
+                gptm_reload(s, 1, 1);
+            } else {
+                gptm_stop(s, 1);
+            }
+        }
+        break;
+    case 0x18: /* IMR */
+        s->mask = value & 0x77;
+        gptm_update_irq(s);
+        break;
+    case 0x24: /* CR */
+        s->state &= ~value;
+        break;
+    case 0x28: /* TAILR */
+        s->load[0] = value & 0xffff;
+        if (s->config < 4) {
+            s->load[1] = value >> 16;
+        }
+        break;
+    case 0x2c: /* TBILR */
+        s->load[1] = value & 0xffff;
+        break;
+    case 0x30: /* TAMARCHR */
+        s->match[0] = value & 0xffff;
+        if (s->config < 4) {
+            s->match[1] = value >> 16;
+        }
+        break;
+    case 0x34: /* TBMATCHR */
+        s->match[1] = value >> 16;
+        break;
+    case 0x38: /* TAPR */
+        s->prescale[0] = value;
+        break;
+    case 0x3c: /* TBPR */
+        s->prescale[1] = value;
+        break;
+    case 0x40: /* TAPMR */
+        s->match_prescale[0] = value;
+        break;
+    case 0x44: /* TBPMR */
+        s->match_prescale[0] = value;
+        break;
+    default:
+        hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
+    }
+    gptm_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const gptm_readfn[] = {
+   gptm_read,
+   gptm_read,
+   gptm_read
+};
+
+static CPUWriteMemoryFunc * const gptm_writefn[] = {
+   gptm_write,
+   gptm_write,
+   gptm_write
+};
+
+static const VMStateDescription vmstate_stellaris_gptm = {
+    .name = "stellaris_gptm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(config, gptm_state),
+        VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
+        VMSTATE_UINT32(control, gptm_state),
+        VMSTATE_UINT32(state, gptm_state),
+        VMSTATE_UINT32(mask, gptm_state),
+        VMSTATE_UNUSED(8),
+        VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
+        VMSTATE_UINT32(rtc, gptm_state),
+        VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
+        VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_gptm_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    gptm_state *s = FROM_SYSBUS(gptm_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
+
+    iomemtype = cpu_register_io_memory(gptm_readfn,
+                                       gptm_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    s->opaque[0] = s->opaque[1] = s;
+    s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
+    s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
+    return 0;
+}
+
+
+/* System controller.  */
+
+typedef struct {
+    uint32_t pborctl;
+    uint32_t ldopctl;
+    uint32_t int_status;
+    uint32_t int_mask;
+    uint32_t resc;
+    uint32_t rcc;
+    uint32_t rcgc[3];
+    uint32_t scgc[3];
+    uint32_t dcgc[3];
+    uint32_t clkvclr;
+    uint32_t ldoarst;
+    uint32_t user0;
+    uint32_t user1;
+    qemu_irq irq;
+    stellaris_board_info *board;
+} ssys_state;
+
+static void ssys_update(ssys_state *s)
+{
+  qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
+}
+
+static uint32_t pllcfg_sandstorm[16] = {
+    0x31c0, /* 1 Mhz */
+    0x1ae0, /* 1.8432 Mhz */
+    0x18c0, /* 2 Mhz */
+    0xd573, /* 2.4576 Mhz */
+    0x37a6, /* 3.57954 Mhz */
+    0x1ae2, /* 3.6864 Mhz */
+    0x0c40, /* 4 Mhz */
+    0x98bc, /* 4.906 Mhz */
+    0x935b, /* 4.9152 Mhz */
+    0x09c0, /* 5 Mhz */
+    0x4dee, /* 5.12 Mhz */
+    0x0c41, /* 6 Mhz */
+    0x75db, /* 6.144 Mhz */
+    0x1ae6, /* 7.3728 Mhz */
+    0x0600, /* 8 Mhz */
+    0x585b /* 8.192 Mhz */
+};
+
+static uint32_t pllcfg_fury[16] = {
+    0x3200, /* 1 Mhz */
+    0x1b20, /* 1.8432 Mhz */
+    0x1900, /* 2 Mhz */
+    0xf42b, /* 2.4576 Mhz */
+    0x37e3, /* 3.57954 Mhz */
+    0x1b21, /* 3.6864 Mhz */
+    0x0c80, /* 4 Mhz */
+    0x98ee, /* 4.906 Mhz */
+    0xd5b4, /* 4.9152 Mhz */
+    0x0a00, /* 5 Mhz */
+    0x4e27, /* 5.12 Mhz */
+    0x1902, /* 6 Mhz */
+    0xec1c, /* 6.144 Mhz */
+    0x1b23, /* 7.3728 Mhz */
+    0x0640, /* 8 Mhz */
+    0xb11c /* 8.192 Mhz */
+};
+
+static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    switch (offset) {
+    case 0x000: /* DID0 */
+        return s->board->did0;
+    case 0x004: /* DID1 */
+        return s->board->did1;
+    case 0x008: /* DC0 */
+        return s->board->dc0;
+    case 0x010: /* DC1 */
+        return s->board->dc1;
+    case 0x014: /* DC2 */
+        return s->board->dc2;
+    case 0x018: /* DC3 */
+        return s->board->dc3;
+    case 0x01c: /* DC4 */
+        return s->board->dc4;
+    case 0x030: /* PBORCTL */
+        return s->pborctl;
+    case 0x034: /* LDOPCTL */
+        return s->ldopctl;
+    case 0x040: /* SRCR0 */
+        return 0;
+    case 0x044: /* SRCR1 */
+        return 0;
+    case 0x048: /* SRCR2 */
+        return 0;
+    case 0x050: /* RIS */
+        return s->int_status;
+    case 0x054: /* IMC */
+        return s->int_mask;
+    case 0x058: /* MISC */
+        return s->int_status & s->int_mask;
+    case 0x05c: /* RESC */
+        return s->resc;
+    case 0x060: /* RCC */
+        return s->rcc;
+    case 0x064: /* PLLCFG */
+        {
+            int xtal;
+            xtal = (s->rcc >> 6) & 0xf;
+            if (s->board->did0 & (1 << 16)) {
+                return pllcfg_fury[xtal];
+            } else {
+                return pllcfg_sandstorm[xtal];
+            }
+        }
+    case 0x100: /* RCGC0 */
+        return s->rcgc[0];
+    case 0x104: /* RCGC1 */
+        return s->rcgc[1];
+    case 0x108: /* RCGC2 */
+        return s->rcgc[2];
+    case 0x110: /* SCGC0 */
+        return s->scgc[0];
+    case 0x114: /* SCGC1 */
+        return s->scgc[1];
+    case 0x118: /* SCGC2 */
+        return s->scgc[2];
+    case 0x120: /* DCGC0 */
+        return s->dcgc[0];
+    case 0x124: /* DCGC1 */
+        return s->dcgc[1];
+    case 0x128: /* DCGC2 */
+        return s->dcgc[2];
+    case 0x150: /* CLKVCLR */
+        return s->clkvclr;
+    case 0x160: /* LDOARST */
+        return s->ldoarst;
+    case 0x1e0: /* USER0 */
+        return s->user0;
+    case 0x1e4: /* USER1 */
+        return s->user1;
+    default:
+        hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void ssys_calculate_system_clock(ssys_state *s)
+{
+    system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+}
+
+static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    switch (offset) {
+    case 0x030: /* PBORCTL */
+        s->pborctl = value & 0xffff;
+        break;
+    case 0x034: /* LDOPCTL */
+        s->ldopctl = value & 0x1f;
+        break;
+    case 0x040: /* SRCR0 */
+    case 0x044: /* SRCR1 */
+    case 0x048: /* SRCR2 */
+        fprintf(stderr, "Peripheral reset not implemented\n");
+        break;
+    case 0x054: /* IMC */
+        s->int_mask = value & 0x7f;
+        break;
+    case 0x058: /* MISC */
+        s->int_status &= ~value;
+        break;
+    case 0x05c: /* RESC */
+        s->resc = value & 0x3f;
+        break;
+    case 0x060: /* RCC */
+        if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
+            /* PLL enable.  */
+            s->int_status |= (1 << 6);
+        }
+        s->rcc = value;
+        ssys_calculate_system_clock(s);
+        break;
+    case 0x100: /* RCGC0 */
+        s->rcgc[0] = value;
+        break;
+    case 0x104: /* RCGC1 */
+        s->rcgc[1] = value;
+        break;
+    case 0x108: /* RCGC2 */
+        s->rcgc[2] = value;
+        break;
+    case 0x110: /* SCGC0 */
+        s->scgc[0] = value;
+        break;
+    case 0x114: /* SCGC1 */
+        s->scgc[1] = value;
+        break;
+    case 0x118: /* SCGC2 */
+        s->scgc[2] = value;
+        break;
+    case 0x120: /* DCGC0 */
+        s->dcgc[0] = value;
+        break;
+    case 0x124: /* DCGC1 */
+        s->dcgc[1] = value;
+        break;
+    case 0x128: /* DCGC2 */
+        s->dcgc[2] = value;
+        break;
+    case 0x150: /* CLKVCLR */
+        s->clkvclr = value;
+        break;
+    case 0x160: /* LDOARST */
+        s->ldoarst = value;
+        break;
+    default:
+        hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
+    }
+    ssys_update(s);
+}
+
+static CPUReadMemoryFunc * const ssys_readfn[] = {
+   ssys_read,
+   ssys_read,
+   ssys_read
+};
+
+static CPUWriteMemoryFunc * const ssys_writefn[] = {
+   ssys_write,
+   ssys_write,
+   ssys_write
+};
+
+static void ssys_reset(void *opaque)
+{
+    ssys_state *s = (ssys_state *)opaque;
+
+    s->pborctl = 0x7ffd;
+    s->rcc = 0x078e3ac0;
+    s->rcgc[0] = 1;
+    s->scgc[0] = 1;
+    s->dcgc[0] = 1;
+}
+
+static int stellaris_sys_post_load(void *opaque, int version_id)
+{
+    ssys_state *s = opaque;
+
+    ssys_calculate_system_clock(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_stellaris_sys = {
+    .name = "stellaris_sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = stellaris_sys_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pborctl, ssys_state),
+        VMSTATE_UINT32(ldopctl, ssys_state),
+        VMSTATE_UINT32(int_mask, ssys_state),
+        VMSTATE_UINT32(int_status, ssys_state),
+        VMSTATE_UINT32(resc, ssys_state),
+        VMSTATE_UINT32(rcc, ssys_state),
+        VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
+        VMSTATE_UINT32(clkvclr, ssys_state),
+        VMSTATE_UINT32(ldoarst, ssys_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_sys_init(uint32_t base, qemu_irq irq,
+                              stellaris_board_info * board,
+                              uint8_t *macaddr)
+{
+    int iomemtype;
+    ssys_state *s;
+
+    s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
+    s->irq = irq;
+    s->board = board;
+    /* Most devices come preprogrammed with a MAC address in the user data. */
+    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
+    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
+
+    iomemtype = cpu_register_io_memory(ssys_readfn,
+                                       ssys_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    ssys_reset(s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
+    return 0;
+}
+
+
+/* I2C controller.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    i2c_bus *bus;
+    qemu_irq irq;
+    uint32_t msa;
+    uint32_t mcs;
+    uint32_t mdr;
+    uint32_t mtpr;
+    uint32_t mimr;
+    uint32_t mris;
+    uint32_t mcr;
+} stellaris_i2c_state;
+
+#define STELLARIS_I2C_MCS_BUSY    0x01
+#define STELLARIS_I2C_MCS_ERROR   0x02
+#define STELLARIS_I2C_MCS_ADRACK  0x04
+#define STELLARIS_I2C_MCS_DATACK  0x08
+#define STELLARIS_I2C_MCS_ARBLST  0x10
+#define STELLARIS_I2C_MCS_IDLE    0x20
+#define STELLARIS_I2C_MCS_BUSBSY  0x40
+
+static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
+{
+    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* MSA */
+        return s->msa;
+    case 0x04: /* MCS */
+        /* We don't emulate timing, so the controller is never busy.  */
+        return s->mcs | STELLARIS_I2C_MCS_IDLE;
+    case 0x08: /* MDR */
+        return s->mdr;
+    case 0x0c: /* MTPR */
+        return s->mtpr;
+    case 0x10: /* MIMR */
+        return s->mimr;
+    case 0x14: /* MRIS */
+        return s->mris;
+    case 0x18: /* MMIS */
+        return s->mris & s->mimr;
+    case 0x20: /* MCR */
+        return s->mcr;
+    default:
+        hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_i2c_update(stellaris_i2c_state *s)
+{
+    int level;
+
+    level = (s->mris & s->mimr) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* MSA */
+        s->msa = value & 0xff;
+        break;
+    case 0x04: /* MCS */
+        if ((s->mcr & 0x10) == 0) {
+            /* Disabled.  Do nothing.  */
+            break;
+        }
+        /* Grab the bus if this is starting a transfer.  */
+        if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
+            if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
+                s->mcs |= STELLARIS_I2C_MCS_ARBLST;
+            } else {
+                s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
+                s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
+            }
+        }
+        /* If we don't have the bus then indicate an error.  */
+        if (!i2c_bus_busy(s->bus)
+                || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
+            s->mcs |= STELLARIS_I2C_MCS_ERROR;
+            break;
+        }
+        s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
+        if (value & 1) {
+            /* Transfer a byte.  */
+            /* TODO: Handle errors.  */
+            if (s->msa & 1) {
+                /* Recv */
+                s->mdr = i2c_recv(s->bus) & 0xff;
+            } else {
+                /* Send */
+                i2c_send(s->bus, s->mdr);
+            }
+            /* Raise an interrupt.  */
+            s->mris |= 1;
+        }
+        if (value & 4) {
+            /* Finish transfer.  */
+            i2c_end_transfer(s->bus);
+            s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
+        }
+        break;
+    case 0x08: /* MDR */
+        s->mdr = value & 0xff;
+        break;
+    case 0x0c: /* MTPR */
+        s->mtpr = value & 0xff;
+        break;
+    case 0x10: /* MIMR */
+        s->mimr = 1;
+        break;
+    case 0x1c: /* MICR */
+        s->mris &= ~value;
+        break;
+    case 0x20: /* MCR */
+        if (value & 1)
+            hw_error(
+                      "stellaris_i2c_write: Loopback not implemented\n");
+        if (value & 0x20)
+            hw_error(
+                      "stellaris_i2c_write: Slave mode not implemented\n");
+        s->mcr = value & 0x31;
+        break;
+    default:
+        hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
+                  (int)offset);
+    }
+    stellaris_i2c_update(s);
+}
+
+static void stellaris_i2c_reset(stellaris_i2c_state *s)
+{
+    if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
+        i2c_end_transfer(s->bus);
+
+    s->msa = 0;
+    s->mcs = 0;
+    s->mdr = 0;
+    s->mtpr = 1;
+    s->mimr = 0;
+    s->mris = 0;
+    s->mcr = 0;
+    stellaris_i2c_update(s);
+}
+
+static CPUReadMemoryFunc * const stellaris_i2c_readfn[] = {
+   stellaris_i2c_read,
+   stellaris_i2c_read,
+   stellaris_i2c_read
+};
+
+static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
+   stellaris_i2c_write,
+   stellaris_i2c_write,
+   stellaris_i2c_write
+};
+
+static const VMStateDescription vmstate_stellaris_i2c = {
+    .name = "stellaris_i2c",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(msa, stellaris_i2c_state),
+        VMSTATE_UINT32(mcs, stellaris_i2c_state),
+        VMSTATE_UINT32(mdr, stellaris_i2c_state),
+        VMSTATE_UINT32(mtpr, stellaris_i2c_state),
+        VMSTATE_UINT32(mimr, stellaris_i2c_state),
+        VMSTATE_UINT32(mris, stellaris_i2c_state),
+        VMSTATE_UINT32(mcr, stellaris_i2c_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_i2c_init(SysBusDevice * dev)
+{
+    stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
+    i2c_bus *bus;
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bus = bus;
+
+    iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
+                                       stellaris_i2c_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    /* ??? For now we only implement the master interface.  */
+    stellaris_i2c_reset(s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
+    return 0;
+}
+
+/* Analogue to Digital Converter.  This is only partially implemented,
+   enough for applications that use a combined ADC and timer tick.  */
+
+#define STELLARIS_ADC_EM_CONTROLLER 0
+#define STELLARIS_ADC_EM_COMP       1
+#define STELLARIS_ADC_EM_EXTERNAL   4
+#define STELLARIS_ADC_EM_TIMER      5
+#define STELLARIS_ADC_EM_PWM0       6
+#define STELLARIS_ADC_EM_PWM1       7
+#define STELLARIS_ADC_EM_PWM2       8
+
+#define STELLARIS_ADC_FIFO_EMPTY    0x0100
+#define STELLARIS_ADC_FIFO_FULL     0x1000
+
+typedef struct
+{
+    SysBusDevice busdev;
+    uint32_t actss;
+    uint32_t ris;
+    uint32_t im;
+    uint32_t emux;
+    uint32_t ostat;
+    uint32_t ustat;
+    uint32_t sspri;
+    uint32_t sac;
+    struct {
+        uint32_t state;
+        uint32_t data[16];
+    } fifo[4];
+    uint32_t ssmux[4];
+    uint32_t ssctl[4];
+    uint32_t noise;
+    qemu_irq irq[4];
+} stellaris_adc_state;
+
+static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
+{
+    int tail;
+
+    tail = s->fifo[n].state & 0xf;
+    if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
+        s->ustat |= 1 << n;
+    } else {
+        s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
+        s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
+        if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
+            s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
+    }
+    return s->fifo[n].data[tail];
+}
+
+static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
+                                     uint32_t value)
+{
+    int head;
+
+    /* TODO: Real hardware has limited size FIFOs.  We have a full 16 entry 
+       FIFO fir each sequencer.  */
+    head = (s->fifo[n].state >> 4) & 0xf;
+    if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
+        s->ostat |= 1 << n;
+        return;
+    }
+    s->fifo[n].data[head] = value;
+    head = (head + 1) & 0xf;
+    s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
+    s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
+    if ((s->fifo[n].state & 0xf) == head)
+        s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
+}
+
+static void stellaris_adc_update(stellaris_adc_state *s)
+{
+    int level;
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        level = (s->ris & s->im & (1 << n)) != 0;
+        qemu_set_irq(s->irq[n], level);
+    }
+}
+
+static void stellaris_adc_trigger(void *opaque, int irq, int level)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        if ((s->actss & (1 << n)) == 0) {
+            continue;
+        }
+
+        if (((s->emux >> (n * 4)) & 0xff) != 5) {
+            continue;
+        }
+
+        /* Some applications use the ADC as a random number source, so introduce
+           some variation into the signal.  */
+        s->noise = s->noise * 314159 + 1;
+        /* ??? actual inputs not implemented.  Return an arbitrary value.  */
+        stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
+        s->ris |= (1 << n);
+        stellaris_adc_update(s);
+    }
+}
+
+static void stellaris_adc_reset(stellaris_adc_state *s)
+{
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        s->ssmux[n] = 0;
+        s->ssctl[n] = 0;
+        s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
+    }
+}
+
+static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+
+    /* TODO: Implement this.  */
+    if (offset >= 0x40 && offset < 0xc0) {
+        int n;
+        n = (offset - 0x40) >> 5;
+        switch (offset & 0x1f) {
+        case 0x00: /* SSMUX */
+            return s->ssmux[n];
+        case 0x04: /* SSCTL */
+            return s->ssctl[n];
+        case 0x08: /* SSFIFO */
+            return stellaris_adc_fifo_read(s, n);
+        case 0x0c: /* SSFSTAT */
+            return s->fifo[n].state;
+        default:
+            break;
+        }
+    }
+    switch (offset) {
+    case 0x00: /* ACTSS */
+        return s->actss;
+    case 0x04: /* RIS */
+        return s->ris;
+    case 0x08: /* IM */
+        return s->im;
+    case 0x0c: /* ISC */
+        return s->ris & s->im;
+    case 0x10: /* OSTAT */
+        return s->ostat;
+    case 0x14: /* EMUX */
+        return s->emux;
+    case 0x18: /* USTAT */
+        return s->ustat;
+    case 0x20: /* SSPRI */
+        return s->sspri;
+    case 0x30: /* SAC */
+        return s->sac;
+    default:
+        hw_error("strllaris_adc_read: Bad offset 0x%x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+
+    /* TODO: Implement this.  */
+    if (offset >= 0x40 && offset < 0xc0) {
+        int n;
+        n = (offset - 0x40) >> 5;
+        switch (offset & 0x1f) {
+        case 0x00: /* SSMUX */
+            s->ssmux[n] = value & 0x33333333;
+            return;
+        case 0x04: /* SSCTL */
+            if (value != 6) {
+                hw_error("ADC: Unimplemented sequence %x\n",
+                          value);
+            }
+            s->ssctl[n] = value;
+            return;
+        default:
+            break;
+        }
+    }
+    switch (offset) {
+    case 0x00: /* ACTSS */
+        s->actss = value & 0xf;
+        break;
+    case 0x08: /* IM */
+        s->im = value;
+        break;
+    case 0x0c: /* ISC */
+        s->ris &= ~value;
+        break;
+    case 0x10: /* OSTAT */
+        s->ostat &= ~value;
+        break;
+    case 0x14: /* EMUX */
+        s->emux = value;
+        break;
+    case 0x18: /* USTAT */
+        s->ustat &= ~value;
+        break;
+    case 0x20: /* SSPRI */
+        s->sspri = value;
+        break;
+    case 0x28: /* PSSI */
+        hw_error("Not implemented:  ADC sample initiate\n");
+        break;
+    case 0x30: /* SAC */
+        s->sac = value;
+        break;
+    default:
+        hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
+    }
+    stellaris_adc_update(s);
+}
+
+static CPUReadMemoryFunc * const stellaris_adc_readfn[] = {
+   stellaris_adc_read,
+   stellaris_adc_read,
+   stellaris_adc_read
+};
+
+static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
+   stellaris_adc_write,
+   stellaris_adc_write,
+   stellaris_adc_write
+};
+
+static const VMStateDescription vmstate_stellaris_adc = {
+    .name = "stellaris_adc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(actss, stellaris_adc_state),
+        VMSTATE_UINT32(ris, stellaris_adc_state),
+        VMSTATE_UINT32(im, stellaris_adc_state),
+        VMSTATE_UINT32(emux, stellaris_adc_state),
+        VMSTATE_UINT32(ostat, stellaris_adc_state),
+        VMSTATE_UINT32(ustat, stellaris_adc_state),
+        VMSTATE_UINT32(sspri, stellaris_adc_state),
+        VMSTATE_UINT32(sac, stellaris_adc_state),
+        VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
+        VMSTATE_UINT32(noise, stellaris_adc_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_adc_init(SysBusDevice *dev)
+{
+    stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
+    int iomemtype;
+    int n;
+
+    for (n = 0; n < 4; n++) {
+        sysbus_init_irq(dev, &s->irq[n]);
+    }
+
+    iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
+                                       stellaris_adc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    stellaris_adc_reset(s);
+    qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
+    return 0;
+}
+
+/* Some boards have both an OLED controller and SD card connected to
+   the same SSI port, with the SD card chip select connected to a
+   GPIO pin.  Technically the OLED chip select is connected to the SSI
+   Fss pin.  We do not bother emulating that as both devices should
+   never be selected simultaneously, and our OLED controller ignores stray
+   0xff commands that occur when deselecting the SD card.  */
+
+typedef struct {
+    SSISlave ssidev;
+    qemu_irq irq;
+    int current_dev;
+    SSIBus *bus[2];
+} stellaris_ssi_bus_state;
+
+static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
+{
+    stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
+
+    s->current_dev = level;
+}
+
+static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
+{
+    stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
+
+    return ssi_transfer(s->bus[s->current_dev], val);
+}
+
+static const VMStateDescription vmstate_stellaris_ssi_bus = {
+    .name = "stellaris_ssi_bus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int stellaris_ssi_bus_init(SSISlave *dev)
+{
+    stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
+
+    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
+    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
+    qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
+
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
+    return 0;
+}
+
+/* Board init.  */
+static stellaris_board_info stellaris_boards[] = {
+  { "LM3S811EVB",
+    0,
+    0x0032000e,
+    0x001f001f, /* dc0 */
+    0x001132bf,
+    0x01071013,
+    0x3f0f01ff,
+    0x0000001f,
+    BP_OLED_I2C
+  },
+  { "LM3S6965EVB",
+    0x10010002,
+    0x1073402e,
+    0x00ff007f, /* dc0 */
+    0x001133ff,
+    0x030f5317,
+    0x0f0f87ff,
+    0x5000007f,
+    BP_OLED_SSI | BP_GAMEPAD
+  }
+};
+
+static void stellaris_init(const char *kernel_filename, const char *cpu_model,
+                           stellaris_board_info *board)
+{
+    static const int uart_irq[] = {5, 6, 33, 34};
+    static const int timer_irq[] = {19, 21, 23, 35};
+    static const uint32_t gpio_addr[7] =
+      { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
+        0x40024000, 0x40025000, 0x40026000};
+    static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
+
+    qemu_irq *pic;
+    DeviceState *gpio_dev[7];
+    qemu_irq gpio_in[7][8];
+    qemu_irq gpio_out[7][8];
+    qemu_irq adc;
+    int sram_size;
+    int flash_size;
+    i2c_bus *i2c;
+    DeviceState *dev;
+    int i;
+    int j;
+
+    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
+    sram_size = (board->dc0 >> 18) + 1;
+    pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
+
+    if (board->dc1 & (1 << 16)) {
+        dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
+                                    pic[14], pic[15], pic[16], pic[17], NULL);
+        adc = qdev_get_gpio_in(dev, 0);
+    } else {
+        adc = NULL;
+    }
+    for (i = 0; i < 4; i++) {
+        if (board->dc2 & (0x10000 << i)) {
+            dev = sysbus_create_simple("stellaris-gptm",
+                                       0x40030000 + i * 0x1000,
+                                       pic[timer_irq[i]]);
+            /* TODO: This is incorrect, but we get away with it because
+               the ADC output is only ever pulsed.  */
+            qdev_connect_gpio_out(dev, 0, adc);
+        }
+    }
+
+    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
+
+    for (i = 0; i < 7; i++) {
+        if (board->dc4 & (1 << i)) {
+            gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
+                                               pic[gpio_irq[i]]);
+            for (j = 0; j < 8; j++) {
+                gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
+                gpio_out[i][j] = NULL;
+            }
+        }
+    }
+
+    if (board->dc2 & (1 << 12)) {
+        dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
+        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+        if (board->peripherals & BP_OLED_I2C) {
+            i2c_create_slave(i2c, "ssd0303", 0x3d);
+        }
+    }
+
+    for (i = 0; i < 4; i++) {
+        if (board->dc2 & (1 << i)) {
+            sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
+                                 pic[uart_irq[i]]);
+        }
+    }
+    if (board->dc2 & (1 << 4)) {
+        dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
+        if (board->peripherals & BP_OLED_SSI) {
+            DeviceState *mux;
+            void *bus;
+
+            bus = qdev_get_child_bus(dev, "ssi");
+            mux = ssi_create_slave(bus, "evb6965-ssi");
+            gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
+
+            bus = qdev_get_child_bus(mux, "ssi0");
+            ssi_create_slave(bus, "ssi-sd");
+
+            bus = qdev_get_child_bus(mux, "ssi1");
+            dev = ssi_create_slave(bus, "ssd0323");
+            gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
+
+            /* Make sure the select pin is high.  */
+            qemu_irq_raise(gpio_out[GPIO_D][0]);
+        }
+    }
+    if (board->dc4 & (1 << 28)) {
+        DeviceState *enet;
+
+        qemu_check_nic_model(&nd_table[0], "stellaris");
+
+        enet = qdev_create(NULL, "stellaris_enet");
+        qdev_set_nic_properties(enet, &nd_table[0]);
+        qdev_init_nofail(enet);
+        sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
+        sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
+    }
+    if (board->peripherals & BP_GAMEPAD) {
+        qemu_irq gpad_irq[5];
+        static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
+
+        gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
+        gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
+        gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
+        gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
+        gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
+
+        stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
+    }
+    for (i = 0; i < 7; i++) {
+        if (board->dc4 & (1 << i)) {
+            for (j = 0; j < 8; j++) {
+                if (gpio_out[i][j]) {
+                    qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
+                }
+            }
+        }
+    }
+}
+
+/* FIXME: Figure out how to generate these from stellaris_boards.  */
+static void lm3s811evb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
+}
+
+static void lm3s6965evb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
+}
+
+static QEMUMachine lm3s811evb_machine = {
+    .name = "lm3s811evb",
+    .desc = "Stellaris LM3S811EVB",
+    .init = lm3s811evb_init,
+};
+
+static QEMUMachine lm3s6965evb_machine = {
+    .name = "lm3s6965evb",
+    .desc = "Stellaris LM3S6965EVB",
+    .init = lm3s6965evb_init,
+};
+
+static void stellaris_machine_init(void)
+{
+    qemu_register_machine(&lm3s811evb_machine);
+    qemu_register_machine(&lm3s6965evb_machine);
+}
+
+machine_init(stellaris_machine_init);
+
+static SSISlaveInfo stellaris_ssi_bus_info = {
+    .qdev.name = "evb6965-ssi",
+    .qdev.size = sizeof(stellaris_ssi_bus_state),
+    .init = stellaris_ssi_bus_init,
+    .transfer = stellaris_ssi_bus_transfer
+};
+
+static void stellaris_register_devices(void)
+{
+    sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
+                        stellaris_i2c_init);
+    sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
+                        stellaris_gptm_init);
+    sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
+                        stellaris_adc_init);
+    ssi_register_slave(&stellaris_ssi_bus_info);
+}
+
+device_init(stellaris_register_devices)
diff --git a/qemu-0.15.x/hw/stellaris_enet.c b/qemu-0.15.x/hw/stellaris_enet.c
new file mode 100644
index 0000000..1291931
--- /dev/null
+++ b/qemu-0.15.x/hw/stellaris_enet.c
@@ -0,0 +1,443 @@
+/*
+ * Luminary Micro Stellaris Ethernet Controller
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+#include "sysbus.h"
+#include "net.h"
+#include <zlib.h>
+
+//#define DEBUG_STELLARIS_ENET 1
+
+#ifdef DEBUG_STELLARIS_ENET
+#define DPRINTF(fmt, ...) \
+do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define SE_INT_RX       0x01
+#define SE_INT_TXER     0x02
+#define SE_INT_TXEMP    0x04
+#define SE_INT_FOV      0x08
+#define SE_INT_RXER     0x10
+#define SE_INT_MD       0x20
+#define SE_INT_PHY      0x40
+
+#define SE_RCTL_RXEN    0x01
+#define SE_RCTL_AMUL    0x02
+#define SE_RCTL_PRMS    0x04
+#define SE_RCTL_BADCRC  0x08
+#define SE_RCTL_RSTFIFO 0x10
+
+#define SE_TCTL_TXEN    0x01
+#define SE_TCTL_PADEN   0x02
+#define SE_TCTL_CRC     0x04
+#define SE_TCTL_DUPLEX  0x08
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t ris;
+    uint32_t im;
+    uint32_t rctl;
+    uint32_t tctl;
+    uint32_t thr;
+    uint32_t mctl;
+    uint32_t mdv;
+    uint32_t mtxd;
+    uint32_t mrxd;
+    uint32_t np;
+    int tx_frame_len;
+    int tx_fifo_len;
+    uint8_t tx_fifo[2048];
+    /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
+       We implement a full 31 packet fifo.  */
+    struct {
+        uint8_t data[2048];
+        int len;
+    } rx[31];
+    uint8_t *rx_fifo;
+    int rx_fifo_len;
+    int next_packet;
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+    int mmio_index;
+} stellaris_enet_state;
+
+static void stellaris_enet_update(stellaris_enet_state *s)
+{
+    qemu_set_irq(s->irq, (s->ris & s->im) != 0);
+}
+
+/* TODO: Implement MAC address filtering.  */
+static ssize_t stellaris_enet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int n;
+    uint8_t *p;
+    uint32_t crc;
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return -1;
+    if (s->np >= 31) {
+        DPRINTF("Packet dropped\n");
+        return -1;
+    }
+
+    DPRINTF("Received packet len=%d\n", size);
+    n = s->next_packet + s->np;
+    if (n >= 31)
+        n -= 31;
+    s->np++;
+
+    s->rx[n].len = size + 6;
+    p = s->rx[n].data;
+    *(p++) = (size + 6);
+    *(p++) = (size + 6) >> 8;
+    memcpy (p, buf, size);
+    p += size;
+    crc = crc32(~0, buf, size);
+    *(p++) = crc;
+    *(p++) = crc >> 8;
+    *(p++) = crc >> 16;
+    *(p++) = crc >> 24;
+    /* Clear the remaining bytes in the last word.  */
+    if ((size & 3) != 2) {
+        memset(p, 0, (6 - size) & 3);
+    }
+
+    s->ris |= SE_INT_RX;
+    stellaris_enet_update(s);
+
+    return size;
+}
+
+static int stellaris_enet_can_receive(VLANClientState *nc)
+{
+    stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return 1;
+
+    return (s->np < 31);
+}
+
+static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    uint32_t val;
+
+    switch (offset) {
+    case 0x00: /* RIS */
+        DPRINTF("IRQ status %02x\n", s->ris);
+        return s->ris;
+    case 0x04: /* IM */
+        return s->im;
+    case 0x08: /* RCTL */
+        return s->rctl;
+    case 0x0c: /* TCTL */
+        return s->tctl;
+    case 0x10: /* DATA */
+        if (s->rx_fifo_len == 0) {
+            if (s->np == 0) {
+                BADF("RX underflow\n");
+                return 0;
+            }
+            s->rx_fifo_len = s->rx[s->next_packet].len;
+            s->rx_fifo = s->rx[s->next_packet].data;
+            DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len);
+        }
+        val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16)
+              | (s->rx_fifo[3] << 24);
+        s->rx_fifo += 4;
+        s->rx_fifo_len -= 4;
+        if (s->rx_fifo_len <= 0) {
+            s->rx_fifo_len = 0;
+            s->next_packet++;
+            if (s->next_packet >= 31)
+                s->next_packet = 0;
+            s->np--;
+            DPRINTF("RX done np=%d\n", s->np);
+        }
+        return val;
+    case 0x14: /* IA0 */
+        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+    case 0x18: /* IA1 */
+        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+    case 0x1c: /* THR */
+        return s->thr;
+    case 0x20: /* MCTL */
+        return s->mctl;
+    case 0x24: /* MDV */
+        return s->mdv;
+    case 0x28: /* MADD */
+        return 0;
+    case 0x2c: /* MTXD */
+        return s->mtxd;
+    case 0x30: /* MRXD */
+        return s->mrxd;
+    case 0x34: /* NP */
+        return s->np;
+    case 0x38: /* TR */
+        return 0;
+    case 0x3c: /* Undocuented: Timestamp? */
+        return 0;
+    default:
+        hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_enet_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* IACK */
+        s->ris &= ~value;
+        DPRINTF("IRQ ack %02x/%02x\n", value, s->ris);
+        stellaris_enet_update(s);
+        /* Clearing TXER also resets the TX fifo.  */
+        if (value & SE_INT_TXER)
+            s->tx_frame_len = -1;
+        break;
+    case 0x04: /* IM */
+        DPRINTF("IRQ mask %02x/%02x\n", value, s->ris);
+        s->im = value;
+        stellaris_enet_update(s);
+        break;
+    case 0x08: /* RCTL */
+        s->rctl = value;
+        if (value & SE_RCTL_RSTFIFO) {
+            s->rx_fifo_len = 0;
+            s->np = 0;
+            stellaris_enet_update(s);
+        }
+        break;
+    case 0x0c: /* TCTL */
+        s->tctl = value;
+        break;
+    case 0x10: /* DATA */
+        if (s->tx_frame_len == -1) {
+            s->tx_frame_len = value & 0xffff;
+            if (s->tx_frame_len > 2032) {
+                DPRINTF("TX frame too long (%d)\n", s->tx_frame_len);
+                s->tx_frame_len = 0;
+                s->ris |= SE_INT_TXER;
+                stellaris_enet_update(s);
+            } else {
+                DPRINTF("Start TX frame len=%d\n", s->tx_frame_len);
+                /* The value written does not include the ethernet header.  */
+                s->tx_frame_len += 14;
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len += 4;
+                s->tx_fifo_len = 0;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            }
+        } else {
+            s->tx_fifo[s->tx_fifo_len++] = value;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 8;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            if (s->tx_fifo_len >= s->tx_frame_len) {
+                /* We don't implement explicit CRC, so just chop it off.  */
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len -= 4;
+                if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) {
+                    memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len);
+                    s->tx_fifo_len = 60;
+                }
+                qemu_send_packet(&s->nic->nc, s->tx_fifo, s->tx_frame_len);
+                s->tx_frame_len = -1;
+                s->ris |= SE_INT_TXEMP;
+                stellaris_enet_update(s);
+                DPRINTF("Done TX\n");
+            }
+        }
+        break;
+    case 0x14: /* IA0 */
+        s->conf.macaddr.a[0] = value;
+        s->conf.macaddr.a[1] = value >> 8;
+        s->conf.macaddr.a[2] = value >> 16;
+        s->conf.macaddr.a[3] = value >> 24;
+        break;
+    case 0x18: /* IA1 */
+        s->conf.macaddr.a[4] = value;
+        s->conf.macaddr.a[5] = value >> 8;
+        break;
+    case 0x1c: /* THR */
+        s->thr = value;
+        break;
+    case 0x20: /* MCTL */
+        s->mctl = value;
+        break;
+    case 0x24: /* MDV */
+        s->mdv = value;
+        break;
+    case 0x28: /* MADD */
+        /* ignored.  */
+        break;
+    case 0x2c: /* MTXD */
+        s->mtxd = value & 0xff;
+        break;
+    case 0x30: /* MRXD */
+    case 0x34: /* NP */
+    case 0x38: /* TR */
+        /* Ignored.  */
+    case 0x3c: /* Undocuented: Timestamp? */
+        /* Ignored.  */
+        break;
+    default:
+        hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static CPUReadMemoryFunc * const stellaris_enet_readfn[] = {
+   stellaris_enet_read,
+   stellaris_enet_read,
+   stellaris_enet_read
+};
+
+static CPUWriteMemoryFunc * const stellaris_enet_writefn[] = {
+   stellaris_enet_write,
+   stellaris_enet_write,
+   stellaris_enet_write
+};
+static void stellaris_enet_reset(stellaris_enet_state *s)
+{
+    s->mdv = 0x80;
+    s->rctl = SE_RCTL_BADCRC;
+    s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
+            | SE_INT_TXER | SE_INT_RX;
+    s->thr = 0x3f;
+    s->tx_frame_len = -1;
+}
+
+static void stellaris_enet_save(QEMUFile *f, void *opaque)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->ris);
+    qemu_put_be32(f, s->im);
+    qemu_put_be32(f, s->rctl);
+    qemu_put_be32(f, s->tctl);
+    qemu_put_be32(f, s->thr);
+    qemu_put_be32(f, s->mctl);
+    qemu_put_be32(f, s->mdv);
+    qemu_put_be32(f, s->mtxd);
+    qemu_put_be32(f, s->mrxd);
+    qemu_put_be32(f, s->np);
+    qemu_put_be32(f, s->tx_frame_len);
+    qemu_put_be32(f, s->tx_fifo_len);
+    qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        qemu_put_be32(f, s->rx[i].len);
+        qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    qemu_put_be32(f, s->next_packet);
+    qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
+    qemu_put_be32(f, s->rx_fifo_len);
+}
+
+static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->ris = qemu_get_be32(f);
+    s->im = qemu_get_be32(f);
+    s->rctl = qemu_get_be32(f);
+    s->tctl = qemu_get_be32(f);
+    s->thr = qemu_get_be32(f);
+    s->mctl = qemu_get_be32(f);
+    s->mdv = qemu_get_be32(f);
+    s->mtxd = qemu_get_be32(f);
+    s->mrxd = qemu_get_be32(f);
+    s->np = qemu_get_be32(f);
+    s->tx_frame_len = qemu_get_be32(f);
+    s->tx_fifo_len = qemu_get_be32(f);
+    qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        s->rx[i].len = qemu_get_be32(f);
+        qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    s->next_packet = qemu_get_be32(f);
+    s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
+    s->rx_fifo_len = qemu_get_be32(f);
+
+    return 0;
+}
+
+static void stellaris_enet_cleanup(VLANClientState *nc)
+{
+    stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
+
+    cpu_unregister_io_memory(s->mmio_index);
+
+    qemu_free(s);
+}
+
+static NetClientInfo net_stellaris_enet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = stellaris_enet_can_receive,
+    .receive = stellaris_enet_receive,
+    .cleanup = stellaris_enet_cleanup,
+};
+
+static int stellaris_enet_init(SysBusDevice *dev)
+{
+    stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
+
+    s->mmio_index = cpu_register_io_memory(stellaris_enet_readfn,
+                                           stellaris_enet_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, s->mmio_index);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    stellaris_enet_reset(s);
+    register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1,
+                    stellaris_enet_save, stellaris_enet_load, s);
+    return 0;
+}
+
+static SysBusDeviceInfo stellaris_enet_info = {
+    .init = stellaris_enet_init,
+    .qdev.name  = "stellaris_enet",
+    .qdev.size  = sizeof(stellaris_enet_state),
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void stellaris_enet_register_devices(void)
+{
+    sysbus_register_withprop(&stellaris_enet_info);
+}
+
+device_init(stellaris_enet_register_devices)
diff --git a/qemu-0.15.x/hw/stellaris_input.c b/qemu-0.15.x/hw/stellaris_input.c
new file mode 100644
index 0000000..95604ec
--- /dev/null
+++ b/qemu-0.15.x/hw/stellaris_input.c
@@ -0,0 +1,89 @@
+/*
+ * Gamepad style buttons connected to IRQ/GPIO lines
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+#include "hw.h"
+#include "devices.h"
+#include "console.h"
+
+typedef struct {
+    qemu_irq irq;
+    int keycode;
+    uint8_t pressed;
+} gamepad_button;
+
+typedef struct {
+    gamepad_button *buttons;
+    int num_buttons;
+    int extension;
+} gamepad_state;
+
+static void stellaris_gamepad_put_key(void * opaque, int keycode)
+{
+    gamepad_state *s = (gamepad_state *)opaque;
+    int i;
+    int down;
+
+    if (keycode == 0xe0 && !s->extension) {
+        s->extension = 0x80;
+        return;
+    }
+
+    down = (keycode & 0x80) == 0;
+    keycode = (keycode & 0x7f) | s->extension;
+
+    for (i = 0; i < s->num_buttons; i++) {
+        if (s->buttons[i].keycode == keycode
+                && s->buttons[i].pressed != down) {
+            s->buttons[i].pressed = down;
+            qemu_set_irq(s->buttons[i].irq, down);
+        }
+    }
+
+    s->extension = 0;
+}
+
+static const VMStateDescription vmstate_stellaris_button = {
+    .name = "stellaris_button",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(pressed, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_stellaris_gamepad = {
+    .name = "stellaris_gamepad",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(extension, gamepad_state),
+        VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
+                              vmstate_stellaris_button, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Returns an array 5 ouput slots.  */
+void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
+{
+    gamepad_state *s;
+    int i;
+
+    s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state));
+    s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button));
+    for (i = 0; i < n; i++) {
+        s->buttons[i].irq = irq[i];
+        s->buttons[i].keycode = keycode[i];
+    }
+    s->num_buttons = n;
+    qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
+}
diff --git a/qemu-0.15.x/hw/strongarm.c b/qemu-0.15.x/hw/strongarm.c
new file mode 100644
index 0000000..0e03d61
--- /dev/null
+++ b/qemu-0.15.x/hw/strongarm.c
@@ -0,0 +1,1598 @@
+/*
+ * StrongARM SA-1100/SA-1110 emulation
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * Largely based on StrongARM emulation:
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * UART code based on QEMU 16550A UART emulation
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "sysbus.h"
+#include "strongarm.h"
+#include "qemu-error.h"
+#include "arm-misc.h"
+#include "sysemu.h"
+#include "ssi.h"
+
+//#define DEBUG
+
+/*
+ TODO
+ - Implement cp15, c14 ?
+ - Implement cp15, c15 !!! (idle used in L)
+ - Implement idle mode handling/DIM
+ - Implement sleep mode/Wake sources
+ - Implement reset control
+ - Implement memory control regs
+ - PCMCIA handling
+ - Maybe support MBGNT/MBREQ
+ - DMA channels
+ - GPCLK
+ - IrDA
+ - MCP
+ - Enhance UART with modem signals
+ */
+
+#ifdef DEBUG
+# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
+#else
+# define DPRINTF(format, ...) do { } while (0)
+#endif
+
+static struct {
+    target_phys_addr_t io_base;
+    int irq;
+} sa_serial[] = {
+    { 0x80010000, SA_PIC_UART1 },
+    { 0x80030000, SA_PIC_UART2 },
+    { 0x80050000, SA_PIC_UART3 },
+    { 0, 0 }
+};
+
+/* Interrupt Controller */
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq    irq;
+    qemu_irq    fiq;
+
+    uint32_t pending;
+    uint32_t enabled;
+    uint32_t is_fiq;
+    uint32_t int_idle;
+} StrongARMPICState;
+
+#define ICIP    0x00
+#define ICMR    0x04
+#define ICLR    0x08
+#define ICFP    0x10
+#define ICPR    0x20
+#define ICCR    0x0c
+
+#define SA_PIC_SRCS     32
+
+
+static void strongarm_pic_update(void *opaque)
+{
+    StrongARMPICState *s = opaque;
+
+    /* FIXME: reflect DIM */
+    qemu_set_irq(s->fiq, s->pending & s->enabled &  s->is_fiq);
+    qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
+}
+
+static void strongarm_pic_set_irq(void *opaque, int irq, int level)
+{
+    StrongARMPICState *s = opaque;
+
+    if (level) {
+        s->pending |= 1 << irq;
+    } else {
+        s->pending &= ~(1 << irq);
+    }
+
+    strongarm_pic_update(s);
+}
+
+static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICIP:
+        return s->pending & ~s->is_fiq & s->enabled;
+    case ICMR:
+        return s->enabled;
+    case ICLR:
+        return s->is_fiq;
+    case ICCR:
+        return s->int_idle == 0;
+    case ICFP:
+        return s->pending & s->is_fiq & s->enabled;
+    case ICPR:
+        return s->pending;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 0;
+    }
+}
+
+static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICMR:
+        s->enabled = value;
+        break;
+    case ICLR:
+        s->is_fiq = value;
+        break;
+    case ICCR:
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        break;
+    }
+    strongarm_pic_update(s);
+}
+
+static CPUReadMemoryFunc * const strongarm_pic_readfn[] = {
+    strongarm_pic_mem_read,
+    strongarm_pic_mem_read,
+    strongarm_pic_mem_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = {
+    strongarm_pic_mem_write,
+    strongarm_pic_mem_write,
+    strongarm_pic_mem_write,
+};
+
+static int strongarm_pic_initfn(SysBusDevice *dev)
+{
+    StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
+    int iomemtype;
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
+    iomemtype = cpu_register_io_memory(strongarm_pic_readfn,
+                    strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+
+    return 0;
+}
+
+static int strongarm_pic_post_load(void *opaque, int version_id)
+{
+    strongarm_pic_update(opaque);
+    return 0;
+}
+
+static VMStateDescription vmstate_strongarm_pic_regs = {
+    .name = "strongarm_pic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(pending, StrongARMPICState),
+        VMSTATE_UINT32(enabled, StrongARMPICState),
+        VMSTATE_UINT32(is_fiq, StrongARMPICState),
+        VMSTATE_UINT32(int_idle, StrongARMPICState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_pic_info = {
+    .init       = strongarm_pic_initfn,
+    .qdev.name  = "strongarm_pic",
+    .qdev.desc  = "StrongARM PIC",
+    .qdev.size  = sizeof(StrongARMPICState),
+    .qdev.vmsd  = &vmstate_strongarm_pic_regs,
+};
+
+/* Real-Time Clock */
+#define RTAR 0x00 /* RTC Alarm register */
+#define RCNR 0x04 /* RTC Counter register */
+#define RTTR 0x08 /* RTC Timer Trim register */
+#define RTSR 0x10 /* RTC Status register */
+
+#define RTSR_AL (1 << 0) /* RTC Alarm detected */
+#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
+#define RTSR_ALE (1 << 2) /* RTC Alarm enable */
+#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
+
+/* 16 LSB of RTTR are clockdiv for internal trim logic,
+ * trim delete isn't emulated, so
+ * f = 32 768 / (RTTR_trim + 1) */
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t last_rcnr;
+    int64_t last_hz;
+    QEMUTimer *rtc_alarm;
+    QEMUTimer *rtc_hz;
+    qemu_irq rtc_irq;
+    qemu_irq rtc_hz_irq;
+} StrongARMRTCState;
+
+static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
+{
+    qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
+    qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
+}
+
+static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rt_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
+{
+    if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
+        qemu_mod_timer(s->rtc_hz, s->last_hz + 1000);
+    } else {
+        qemu_del_timer(s->rtc_hz);
+    }
+
+    if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
+        qemu_mod_timer(s->rtc_alarm, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    } else {
+        qemu_del_timer(s->rtc_alarm);
+    }
+}
+
+static inline void strongarm_rtc_alarm_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_AL;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static inline void strongarm_rtc_hz_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_HZ;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMRTCState *s = opaque;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RCNR:
+        return s->last_rcnr +
+                ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMRTCState *s = opaque;
+    uint32_t old_rtsr;
+
+    switch (addr) {
+    case RTTR:
+        strongarm_rtc_hzupdate(s);
+        s->rttr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RTSR:
+        old_rtsr = s->rtsr;
+        s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
+                  (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
+
+        if (s->rtsr != old_rtsr) {
+            strongarm_rtc_timer_update(s);
+        }
+
+        strongarm_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RCNR:
+        strongarm_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = {
+    strongarm_rtc_read,
+    strongarm_rtc_read,
+    strongarm_rtc_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = {
+    strongarm_rtc_write,
+    strongarm_rtc_write,
+    strongarm_rtc_write,
+};
+
+static int strongarm_rtc_init(SysBusDevice *dev)
+{
+    StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
+    struct tm tm;
+    int iomemtype;
+
+    s->rttr = 0x0;
+    s->rtsr = 0;
+
+    qemu_get_timedate(&tm, 0);
+
+    s->last_rcnr = (uint32_t) mktimegm(&tm);
+    s->last_hz = qemu_get_clock_ms(rt_clock);
+
+    s->rtc_alarm = qemu_new_timer_ms(rt_clock, strongarm_rtc_alarm_tick, s);
+    s->rtc_hz = qemu_new_timer_ms(rt_clock, strongarm_rtc_hz_tick, s);
+
+    sysbus_init_irq(dev, &s->rtc_irq);
+    sysbus_init_irq(dev, &s->rtc_hz_irq);
+
+    iomemtype = cpu_register_io_memory(strongarm_rtc_readfn,
+                    strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x10000, iomemtype);
+
+    return 0;
+}
+
+static void strongarm_rtc_pre_save(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_hzupdate(s);
+}
+
+static int strongarm_rtc_post_load(void *opaque, int version_id)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_rtc_regs = {
+    .name = "strongarm-rtc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = strongarm_rtc_pre_save,
+    .post_load = strongarm_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(rttr, StrongARMRTCState),
+        VMSTATE_UINT32(rtsr, StrongARMRTCState),
+        VMSTATE_UINT32(rtar, StrongARMRTCState),
+        VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
+        VMSTATE_INT64(last_hz, StrongARMRTCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_rtc_sysbus_info = {
+    .init       = strongarm_rtc_init,
+    .qdev.name  = "strongarm-rtc",
+    .qdev.desc  = "StrongARM RTC Controller",
+    .qdev.size  = sizeof(StrongARMRTCState),
+    .qdev.vmsd  = &vmstate_strongarm_rtc_regs,
+};
+
+/* GPIO */
+#define GPLR 0x00
+#define GPDR 0x04
+#define GPSR 0x08
+#define GPCR 0x0c
+#define GRER 0x10
+#define GFER 0x14
+#define GEDR 0x18
+#define GAFR 0x1c
+
+typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
+struct StrongARMGPIOInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[28];
+    qemu_irq irqs[11];
+    qemu_irq irqX;
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t rising;
+    uint32_t falling;
+    uint32_t status;
+    uint32_t gpsr;
+    uint32_t gafr;
+
+    uint32_t prev_level;
+};
+
+
+static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
+{
+    int i;
+    for (i = 0; i < 11; i++) {
+        qemu_set_irq(s->irqs[i], s->status & (1 << i));
+    }
+
+    qemu_set_irq(s->irqX, (s->status & ~0x7ff));
+}
+
+static void strongarm_gpio_set(void *opaque, int line, int level)
+{
+    StrongARMGPIOInfo *s = opaque;
+    uint32_t mask;
+
+    mask = 1 << line;
+
+    if (level) {
+        s->status |= s->rising & mask &
+                ~s->ilevel & ~s->dir;
+        s->ilevel |= mask;
+    } else {
+        s->status |= s->falling & mask &
+                s->ilevel & ~s->dir;
+        s->ilevel &= ~mask;
+    }
+
+    if (s->status & mask) {
+        strongarm_gpio_irq_update(s);
+    }
+}
+
+static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        return s->dir;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return s->gpsr;    /* Return last written value.  */
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 31337;        /* Specified as unpredictable in the docs.  */
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        return s->rising;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        return s->falling;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        return s->gafr;
+
+    case GPLR:        /* GPIO Pin-Level registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir);
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        return s->status;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_gpio_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        s->dir = value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        s->olevel |= value;
+        strongarm_gpio_handler_update(s);
+        s->gpsr = value;
+        break;
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        s->olevel &= ~value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        s->rising = value;
+        break;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        s->falling = value;
+        break;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        s->gafr = value;
+        break;
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        s->status &= ~value;
+        strongarm_gpio_irq_update(s);
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = {
+    strongarm_gpio_read,
+    strongarm_gpio_read,
+    strongarm_gpio_read
+};
+
+static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = {
+    strongarm_gpio_write,
+    strongarm_gpio_write,
+    strongarm_gpio_write
+};
+
+static DeviceState *strongarm_gpio_init(target_phys_addr_t base,
+                DeviceState *pic)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "strongarm-gpio");
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    for (i = 0; i < 12; i++)
+        sysbus_connect_irq(sysbus_from_qdev(dev), i,
+                    qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
+
+    return dev;
+}
+
+static int strongarm_gpio_initfn(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMGPIOInfo *s;
+    int i;
+
+    s = FROM_SYSBUS(StrongARMGPIOInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 28);
+
+    iomemtype = cpu_register_io_memory(strongarm_gpio_readfn,
+                    strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    for (i = 0; i < 11; i++) {
+        sysbus_init_irq(dev, &s->irqs[i]);
+    }
+    sysbus_init_irq(dev, &s->irqX);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_gpio_regs = {
+    .name = "strongarm-gpio",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(dir, StrongARMGPIOInfo),
+        VMSTATE_UINT32(rising, StrongARMGPIOInfo),
+        VMSTATE_UINT32(falling, StrongARMGPIOInfo),
+        VMSTATE_UINT32(status, StrongARMGPIOInfo),
+        VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_gpio_info = {
+    .init       = strongarm_gpio_initfn,
+    .qdev.name  = "strongarm-gpio",
+    .qdev.desc  = "StrongARM GPIO controller",
+    .qdev.size  = sizeof(StrongARMGPIOInfo),
+};
+
+/* Peripheral Pin Controller */
+#define PPDR 0x00
+#define PPSR 0x04
+#define PPAR 0x08
+#define PSDR 0x0c
+#define PPFR 0x10
+
+typedef struct StrongARMPPCInfo StrongARMPPCInfo;
+struct StrongARMPPCInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[28];
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t ppar;
+    uint32_t psdr;
+    uint32_t ppfr;
+
+    uint32_t prev_level;
+};
+
+static void strongarm_ppc_set(void *opaque, int line, int level)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    if (level) {
+        s->ilevel |= 1 << line;
+    } else {
+        s->ilevel &= ~(1 << line);
+    }
+}
+
+static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        return s->dir | ~0x3fffff;
+
+    case PPSR:        /* PPC Pin State registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir) |
+               ~0x3fffff;
+
+    case PPAR:
+        return s->ppar | ~0x41000;
+
+    case PSDR:
+        return s->psdr;
+
+    case PPFR:
+        return s->ppfr | ~0x7f001;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_ppc_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        s->dir = value & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPSR:        /* PPC Pin State registers */
+        s->olevel = value & s->dir & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPAR:
+        s->ppar = value & 0x41000;
+        break;
+
+    case PSDR:
+        s->psdr = value & 0x3fffff;
+        break;
+
+    case PPFR:
+        s->ppfr = value & 0x7f001;
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = {
+    strongarm_ppc_read,
+    strongarm_ppc_read,
+    strongarm_ppc_read
+};
+
+static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = {
+    strongarm_ppc_write,
+    strongarm_ppc_write,
+    strongarm_ppc_write
+};
+
+static int strongarm_ppc_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMPPCInfo *s;
+
+    s = FROM_SYSBUS(StrongARMPPCInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 22);
+
+    iomemtype = cpu_register_io_memory(strongarm_ppc_readfn,
+                    strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ppc_regs = {
+    .name = "strongarm-ppc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(olevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(dir, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppar, StrongARMPPCInfo),
+        VMSTATE_UINT32(psdr, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_ppc_info = {
+    .init       = strongarm_ppc_init,
+    .qdev.name  = "strongarm-ppc",
+    .qdev.desc  = "StrongARM PPC controller",
+    .qdev.size  = sizeof(StrongARMPPCInfo),
+};
+
+/* UART Ports */
+#define UTCR0 0x00
+#define UTCR1 0x04
+#define UTCR2 0x08
+#define UTCR3 0x0c
+#define UTDR  0x14
+#define UTSR0 0x1c
+#define UTSR1 0x20
+
+#define UTCR0_PE  (1 << 0) /* Parity enable */
+#define UTCR0_OES (1 << 1) /* Even parity */
+#define UTCR0_SBS (1 << 2) /* 2 stop bits */
+#define UTCR0_DSS (1 << 3) /* 8-bit data */
+
+#define UTCR3_RXE (1 << 0) /* Rx enable */
+#define UTCR3_TXE (1 << 1) /* Tx enable */
+#define UTCR3_BRK (1 << 2) /* Force Break */
+#define UTCR3_RIE (1 << 3) /* Rx int enable */
+#define UTCR3_TIE (1 << 4) /* Tx int enable */
+#define UTCR3_LBM (1 << 5) /* Loopback */
+
+#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
+#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
+#define UTSR0_RID (1 << 2) /* Receiver Idle */
+#define UTSR0_RBB (1 << 3) /* Receiver begin break */
+#define UTSR0_REB (1 << 4) /* Receiver end break */
+#define UTSR0_EIF (1 << 5) /* Error in FIFO */
+
+#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
+#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
+#define UTSR1_PRE (1 << 3) /* Parity error */
+#define UTSR1_FRE (1 << 4) /* Frame error */
+#define UTSR1_ROR (1 << 5) /* Receive Over Run */
+
+#define RX_FIFO_PRE (1 << 8)
+#define RX_FIFO_FRE (1 << 9)
+#define RX_FIFO_ROR (1 << 10)
+
+typedef struct {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint8_t utcr0;
+    uint16_t brd;
+    uint8_t utcr3;
+    uint8_t utsr0;
+    uint8_t utsr1;
+
+    uint8_t tx_fifo[8];
+    uint8_t tx_start;
+    uint8_t tx_len;
+    uint16_t rx_fifo[12]; /* value + error flags in high bits */
+    uint8_t rx_start;
+    uint8_t rx_len;
+
+    uint64_t char_transmit_time; /* time to transmit a char in ticks*/
+    bool wait_break_end;
+    QEMUTimer *rx_timeout_timer;
+    QEMUTimer *tx_timer;
+} StrongARMUARTState;
+
+static void strongarm_uart_update_status(StrongARMUARTState *s)
+{
+    uint16_t utsr1 = 0;
+
+    if (s->tx_len != 8) {
+        utsr1 |= UTSR1_TNF;
+    }
+
+    if (s->rx_len != 0) {
+        uint16_t ent = s->rx_fifo[s->rx_start];
+
+        utsr1 |= UTSR1_RNE;
+        if (ent & RX_FIFO_PRE) {
+            s->utsr1 |= UTSR1_PRE;
+        }
+        if (ent & RX_FIFO_FRE) {
+            s->utsr1 |= UTSR1_FRE;
+        }
+        if (ent & RX_FIFO_ROR) {
+            s->utsr1 |= UTSR1_ROR;
+        }
+    }
+
+    s->utsr1 = utsr1;
+}
+
+static void strongarm_uart_update_int_status(StrongARMUARTState *s)
+{
+    uint16_t utsr0 = s->utsr0 &
+            (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
+    int i;
+
+    if ((s->utcr3 & UTCR3_TXE) &&
+                (s->utcr3 & UTCR3_TIE) &&
+                s->tx_len <= 4) {
+        utsr0 |= UTSR0_TFS;
+    }
+
+    if ((s->utcr3 & UTCR3_RXE) &&
+                (s->utcr3 & UTCR3_RIE) &&
+                s->rx_len > 4) {
+        utsr0 |= UTSR0_RFS;
+    }
+
+    for (i = 0; i < s->rx_len && i < 4; i++)
+        if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
+            utsr0 |= UTSR0_EIF;
+            break;
+        }
+
+    s->utsr0 = utsr0;
+    qemu_set_irq(s->irq, utsr0);
+}
+
+static void strongarm_uart_update_parameters(StrongARMUARTState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+
+    /* Start bit. */
+    frame_size = 1;
+    if (s->utcr0 & UTCR0_PE) {
+        /* Parity bit. */
+        frame_size++;
+        if (s->utcr0 & UTCR0_OES) {
+            parity = 'E';
+        } else {
+            parity = 'O';
+        }
+    } else {
+            parity = 'N';
+    }
+    if (s->utcr0 & UTCR0_SBS) {
+        stop_bits = 2;
+    } else {
+        stop_bits = 1;
+    }
+
+    data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
+    frame_size += data_bits + stop_bits;
+    speed = 3686400 / 16 / (s->brd + 1);
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
+    if (s->chr) {
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    }
+
+    DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
+            speed, parity, data_bits, stop_bits);
+}
+
+static void strongarm_uart_rx_to(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len) {
+        s->utsr0 |= UTSR0_RID;
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
+{
+    if ((s->utcr3 & UTCR3_RXE) == 0) {
+        /* rx disabled */
+        return;
+    }
+
+    if (s->wait_break_end) {
+        s->utsr0 |= UTSR0_REB;
+        s->wait_break_end = false;
+    }
+
+    if (s->rx_len < 12) {
+        s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
+        s->rx_len++;
+    } else
+        s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
+}
+
+static int strongarm_uart_can_receive(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len == 12) {
+        return 0;
+    }
+    /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
+    if (s->rx_len < 8) {
+        return 8 - s->rx_len;
+    }
+    return 1;
+}
+
+static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    StrongARMUARTState *s = opaque;
+    int i;
+
+    for (i = 0; i < size; i++) {
+        strongarm_uart_rx_push(s, buf[i]);
+    }
+
+    /* call the timeout receive callback in 3 char transmit time */
+    qemu_mod_timer(s->rx_timeout_timer,
+                    qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static void strongarm_uart_event(void *opaque, int event)
+{
+    StrongARMUARTState *s = opaque;
+    if (event == CHR_EVENT_BREAK) {
+        s->utsr0 |= UTSR0_RBB;
+        strongarm_uart_rx_push(s, RX_FIFO_FRE);
+        s->wait_break_end = true;
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_tx(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    if (s->utcr3 & UTCR3_LBM) /* loopback */ {
+        strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
+    } else if (s->chr) {
+        qemu_chr_write(s->chr, &s->tx_fifo[s->tx_start], 1);
+    }
+
+    s->tx_start = (s->tx_start + 1) % 8;
+    s->tx_len--;
+    if (s->tx_len) {
+        qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time);
+    }
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMUARTState *s = opaque;
+    uint16_t ret;
+
+    switch (addr) {
+    case UTCR0:
+        return s->utcr0;
+
+    case UTCR1:
+        return s->brd >> 8;
+
+    case UTCR2:
+        return s->brd & 0xff;
+
+    case UTCR3:
+        return s->utcr3;
+
+    case UTDR:
+        if (s->rx_len != 0) {
+            ret = s->rx_fifo[s->rx_start];
+            s->rx_start = (s->rx_start + 1) % 12;
+            s->rx_len--;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            return ret;
+        }
+        return 0;
+
+    case UTSR0:
+        return s->utsr0;
+
+    case UTSR1:
+        return s->utsr1;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_uart_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMUARTState *s = opaque;
+
+    switch (addr) {
+    case UTCR0:
+        s->utcr0 = value & 0x7f;
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR1:
+        s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR2:
+        s->brd = (s->brd & 0xf00) | (value & 0xff);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR3:
+        s->utcr3 = value & 0x3f;
+        if ((s->utcr3 & UTCR3_RXE) == 0) {
+            s->rx_len = 0;
+        }
+        if ((s->utcr3 & UTCR3_TXE) == 0) {
+            s->tx_len = 0;
+        }
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+        break;
+
+    case UTDR:
+        if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
+            s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
+            s->tx_len++;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            if (s->tx_len == 1) {
+                strongarm_uart_tx(s);
+            }
+        }
+        break;
+
+    case UTSR0:
+        s->utsr0 = s->utsr0 & ~(value &
+                (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
+        strongarm_uart_update_int_status(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_uart_readfn[] = {
+    strongarm_uart_read,
+    strongarm_uart_read,
+    strongarm_uart_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = {
+    strongarm_uart_write,
+    strongarm_uart_write,
+    strongarm_uart_write,
+};
+
+static int strongarm_uart_init(SysBusDevice *dev)
+{
+    StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(strongarm_uart_readfn,
+                    strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x10000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s);
+    s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s);
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr,
+                        strongarm_uart_can_receive,
+                        strongarm_uart_receive,
+                        strongarm_uart_event,
+                        s);
+    }
+
+    return 0;
+}
+
+static void strongarm_uart_reset(DeviceState *dev)
+{
+    StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev);
+
+    s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
+    s->brd = 23;    /* 9600 */
+    /* enable send & recv - this actually violates spec */
+    s->utcr3 = UTCR3_TXE | UTCR3_RXE;
+
+    s->rx_len = s->tx_len = 0;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static int strongarm_uart_post_load(void *opaque, int version_id)
+{
+    StrongARMUARTState *s = opaque;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+
+    /* tx and restart timer */
+    if (s->tx_len) {
+        strongarm_uart_tx(s);
+    }
+
+    /* restart rx timeout timer */
+    if (s->rx_len) {
+        qemu_mod_timer(s->rx_timeout_timer,
+                qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_uart_regs = {
+    .name = "strongarm-uart",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(utcr0, StrongARMUARTState),
+        VMSTATE_UINT16(brd, StrongARMUARTState),
+        VMSTATE_UINT8(utcr3, StrongARMUARTState),
+        VMSTATE_UINT8(utsr0, StrongARMUARTState),
+        VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
+        VMSTATE_UINT8(tx_start, StrongARMUARTState),
+        VMSTATE_UINT8(tx_len, StrongARMUARTState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
+        VMSTATE_UINT8(rx_start, StrongARMUARTState),
+        VMSTATE_UINT8(rx_len, StrongARMUARTState),
+        VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_uart_info = {
+    .init       = strongarm_uart_init,
+    .qdev.name  = "strongarm-uart",
+    .qdev.desc  = "StrongARM UART controller",
+    .qdev.size  = sizeof(StrongARMUARTState),
+    .qdev.reset = strongarm_uart_reset,
+    .qdev.vmsd  = &vmstate_strongarm_uart_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+/* Synchronous Serial Ports */
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    SSIBus *bus;
+
+    uint16_t sscr[2];
+    uint16_t sssr;
+
+    uint16_t rx_fifo[8];
+    uint8_t rx_level;
+    uint8_t rx_start;
+} StrongARMSSPState;
+
+#define SSCR0 0x60 /* SSP Control register 0 */
+#define SSCR1 0x64 /* SSP Control register 1 */
+#define SSDR  0x6c /* SSP Data register */
+#define SSSR  0x74 /* SSP Status register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)    (((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)    (((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x)  (((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)    (((x) & 0x30) == 0x30)
+#define SSCR0_SSE       (1 << 7)
+#define SSCR0_DSS(x)    (((x) & 0xf) + 1)
+#define SSCR1_RIE       (1 << 0)
+#define SSCR1_TIE       (1 << 1)
+#define SSCR1_LBM       (1 << 2)
+#define SSSR_TNF        (1 << 2)
+#define SSSR_RNE        (1 << 3)
+#define SSSR_TFS        (1 << 5)
+#define SSSR_RFS        (1 << 6)
+#define SSSR_ROR        (1 << 7)
+#define SSSR_RW         0x0080
+
+static void strongarm_ssp_int_update(StrongARMSSPState *s)
+{
+    int level = 0;
+
+    level |= (s->sssr & SSSR_ROR);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, level);
+}
+
+static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
+{
+    s->sssr &= ~SSSR_TFS;
+    s->sssr &= ~SSSR_TNF;
+    if (s->sscr[0] & SSCR0_SSE) {
+        if (s->rx_level >= 4) {
+            s->sssr |= SSSR_RFS;
+        } else {
+            s->sssr &= ~SSSR_RFS;
+        }
+        if (s->rx_level) {
+            s->sssr |= SSSR_RNE;
+        } else {
+            s->sssr &= ~SSSR_RNE;
+        }
+        /* TX FIFO is never filled, so it is always in underrun
+           condition if SSP is enabled */
+        s->sssr |= SSSR_TFS;
+        s->sssr |= SSSR_TNF;
+    }
+
+    strongarm_ssp_int_update(s);
+}
+
+static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMSSPState *s = opaque;
+    uint32_t retval;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSSR:
+        return s->sssr;
+    case SSDR:
+        if (~s->sscr[0] & SSCR0_SSE) {
+            return 0xffffffff;
+        }
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __func__);
+            return 0xffffffff;
+        }
+        s->rx_level--;
+        retval = s->rx_fifo[s->rx_start++];
+        s->rx_start &= 0x7;
+        strongarm_ssp_fifo_update(s);
+        return retval;
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMSSPState *s = opaque;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xffbf;
+        if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
+            printf("%s: Wrong data size: %i bits\n", __func__,
+                            SSCR0_DSS(value));
+        }
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->rx_level = 0;
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value & 0x2f;
+        if (value & SSCR1_LBM) {
+            printf("%s: Attempt to use SSP LBM mode\n", __func__);
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        strongarm_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->sscr[0] & SSCR0_SSE) {
+            uint32_t readval;
+            if (s->sscr[1] & SSCR1_LBM) {
+                readval = value;
+            } else {
+                readval = ssi_transfer(s->bus, value);
+            }
+
+            if (s->rx_level < 0x08) {
+                s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
+            } else {
+                s->sssr |= SSSR_ROR;
+            }
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = {
+    strongarm_ssp_read,
+    strongarm_ssp_read,
+    strongarm_ssp_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = {
+    strongarm_ssp_write,
+    strongarm_ssp_write,
+    strongarm_ssp_write,
+};
+
+static int strongarm_ssp_post_load(void *opaque, int version_id)
+{
+    StrongARMSSPState *s = opaque;
+
+    strongarm_ssp_fifo_update(s);
+
+    return 0;
+}
+
+static int strongarm_ssp_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    iomemtype = cpu_register_io_memory(strongarm_ssp_readfn,
+                                       strongarm_ssp_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
+    return 0;
+}
+
+static void strongarm_ssp_reset(DeviceState *dev)
+{
+    StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev);
+    s->sssr = 0x03; /* 3 bit data, SPI, disabled */
+    s->rx_start = 0;
+    s->rx_level = 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ssp_regs = {
+    .name = "strongarm-ssp",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_ssp_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
+        VMSTATE_UINT16(sssr, StrongARMSSPState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
+        VMSTATE_UINT8(rx_start, StrongARMSSPState),
+        VMSTATE_UINT8(rx_level, StrongARMSSPState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_ssp_info = {
+    .init       = strongarm_ssp_init,
+    .qdev.name  = "strongarm-ssp",
+    .qdev.desc  = "StrongARM SSP controller",
+    .qdev.size  = sizeof(StrongARMSSPState),
+    .qdev.reset = strongarm_ssp_reset,
+    .qdev.vmsd  = &vmstate_strongarm_ssp_regs,
+};
+
+/* Main CPU functions */
+StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev)
+{
+    StrongARMState *s;
+    qemu_irq *pic;
+    int i;
+
+    s = qemu_mallocz(sizeof(StrongARMState));
+
+    if (!rev) {
+        rev = "sa1110-b5";
+    }
+
+    if (strncmp(rev, "sa1110", 6)) {
+        error_report("Machine requires a SA1110 processor.");
+        exit(1);
+    }
+
+    s->env = cpu_init(rev);
+
+    if (!s->env) {
+        error_report("Unable to find CPU definition");
+        exit(1);
+    }
+
+    cpu_register_physical_memory(SA_SDCS0,
+                    sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram",
+                                                sdram_size) | IO_MEM_RAM);
+
+    pic = arm_pic_init_cpu(s->env);
+    s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
+                    pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL);
+
+    sysbus_create_varargs("pxa25x-timer", 0x90000000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
+                    NULL);
+
+    sysbus_create_simple("strongarm-rtc", 0x90010000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
+
+    s->gpio = strongarm_gpio_init(0x90040000, s->pic);
+
+    s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL);
+
+    for (i = 0; sa_serial[i].io_base; i++) {
+        DeviceState *dev = qdev_create(NULL, "strongarm-uart");
+        qdev_prop_set_chr(dev, "chardev", serial_hds[i]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0,
+                sa_serial[i].io_base);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 0,
+                qdev_get_gpio_in(s->pic, sa_serial[i].irq));
+    }
+
+    s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000,
+                qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
+    s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
+
+    return s;
+}
+
+static void strongarm_register_devices(void)
+{
+    sysbus_register_withprop(&strongarm_pic_info);
+    sysbus_register_withprop(&strongarm_rtc_sysbus_info);
+    sysbus_register_withprop(&strongarm_gpio_info);
+    sysbus_register_withprop(&strongarm_ppc_info);
+    sysbus_register_withprop(&strongarm_uart_info);
+    sysbus_register_withprop(&strongarm_ssp_info);
+}
+device_init(strongarm_register_devices)
diff --git a/qemu-0.15.x/hw/strongarm.h b/qemu-0.15.x/hw/strongarm.h
new file mode 100644
index 0000000..a81b110
--- /dev/null
+++ b/qemu-0.15.x/hw/strongarm.h
@@ -0,0 +1,64 @@
+#ifndef _STRONGARM_H
+#define _STRONGARM_H
+
+#define SA_CS0          0x00000000
+#define SA_CS1          0x08000000
+#define SA_CS2          0x10000000
+#define SA_CS3          0x18000000
+#define SA_PCMCIA_CS0   0x20000000
+#define SA_PCMCIA_CS1   0x30000000
+#define SA_CS4          0x40000000
+#define SA_CS5          0x48000000
+/* system registers here */
+#define SA_SDCS0        0xc0000000
+#define SA_SDCS1        0xc8000000
+#define SA_SDCS2        0xd0000000
+#define SA_SDCS3        0xd8000000
+
+enum {
+    SA_PIC_GPIO0_EDGE = 0,
+    SA_PIC_GPIO1_EDGE,
+    SA_PIC_GPIO2_EDGE,
+    SA_PIC_GPIO3_EDGE,
+    SA_PIC_GPIO4_EDGE,
+    SA_PIC_GPIO5_EDGE,
+    SA_PIC_GPIO6_EDGE,
+    SA_PIC_GPIO7_EDGE,
+    SA_PIC_GPIO8_EDGE,
+    SA_PIC_GPIO9_EDGE,
+    SA_PIC_GPIO10_EDGE,
+    SA_PIC_GPIOX_EDGE,
+    SA_PIC_LCD,
+    SA_PIC_UDC,
+    SA_PIC_RSVD1,
+    SA_PIC_UART1,
+    SA_PIC_UART2,
+    SA_PIC_UART3,
+    SA_PIC_MCP,
+    SA_PIC_SSP,
+    SA_PIC_DMA_CH0,
+    SA_PIC_DMA_CH1,
+    SA_PIC_DMA_CH2,
+    SA_PIC_DMA_CH3,
+    SA_PIC_DMA_CH4,
+    SA_PIC_DMA_CH5,
+    SA_PIC_OSTC0,
+    SA_PIC_OSTC1,
+    SA_PIC_OSTC2,
+    SA_PIC_OSTC3,
+    SA_PIC_RTC_HZ,
+    SA_PIC_RTC_ALARM,
+};
+
+typedef struct {
+    CPUState *env;
+    DeviceState *pic;
+    DeviceState *gpio;
+    DeviceState *ppc;
+    DeviceState *ssp;
+    SSIBus *ssp_bus;
+} StrongARMState;
+
+StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev);
+
+#endif
diff --git a/qemu-0.15.x/hw/sun4c_intctl.c b/qemu-0.15.x/hw/sun4c_intctl.c
new file mode 100644
index 0000000..5c7fdef
--- /dev/null
+++ b/qemu-0.15.x/hw/sun4c_intctl.c
@@ -0,0 +1,224 @@
+/*
+ * QEMU Sparc Sun4c interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 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 "hw.h"
+#include "sun4m.h"
+#include "monitor.h"
+#include "sysbus.h"
+
+//#define DEBUG_IRQ_COUNT
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/*
+ * Registers of interrupt controller in sun4c.
+ *
+ */
+
+#define MAX_PILS 16
+
+typedef struct Sun4c_INTCTLState {
+    SysBusDevice busdev;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count;
+#endif
+    qemu_irq cpu_irqs[MAX_PILS];
+    const uint32_t *intbit_to_level;
+    uint32_t pil_out;
+    uint8_t reg;
+    uint8_t pending;
+} Sun4c_INTCTLState;
+
+#define INTCTL_SIZE 1
+
+static void sun4c_check_interrupts(void *opaque);
+
+static uint32_t sun4c_intctl_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t ret;
+
+    ret = s->reg;
+    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                    uint32_t val)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
+    val &= 0xbf;
+    s->reg = val;
+    sun4c_check_interrupts(s);
+}
+
+static CPUReadMemoryFunc * const sun4c_intctl_mem_read[3] = {
+    sun4c_intctl_mem_readb,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const sun4c_intctl_mem_write[3] = {
+    sun4c_intctl_mem_writeb,
+    NULL,
+    NULL,
+};
+
+void sun4c_pic_info(Monitor *mon, void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    monitor_printf(mon, "master: pending 0x%2.2x, enabled 0x%2.2x\n",
+                   s->pending, s->reg);
+}
+
+void sun4c_irq_info(Monitor *mon, void *opaque)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    Sun4c_INTCTLState *s = opaque;
+    int64_t count;
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    count = s->irq_count;
+    if (count > 0)
+        monitor_printf(mon, " %" PRId64 "\n", count);
+#endif
+}
+
+static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
+
+static void sun4c_check_interrupts(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t pil_pending;
+    unsigned int i;
+
+    pil_pending = 0;
+    if (s->pending && !(s->reg & 0x80000000)) {
+        for (i = 0; i < 8; i++) {
+            if (s->pending & (1 << i))
+                pil_pending |= 1 << intbit_to_level[i];
+        }
+    }
+
+    for (i = 0; i < MAX_PILS; i++) {
+        if (pil_pending & (1 << i)) {
+            if (!(s->pil_out & (1 << i)))
+                qemu_irq_raise(s->cpu_irqs[i]);
+        } else {
+            if (s->pil_out & (1 << i))
+                qemu_irq_lower(s->cpu_irqs[i]);
+        }
+    }
+    s->pil_out = pil_pending;
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register
+ */
+static void sun4c_set_irq(void *opaque, int irq, int level)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+
+    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
+            level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count++;
+#endif
+            s->pending |= mask;
+        } else {
+            s->pending &= ~mask;
+        }
+        sun4c_check_interrupts(s);
+    }
+}
+
+static const VMStateDescription vmstate_sun4c_intctl = {
+    .name ="sun4c_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(reg, Sun4c_INTCTLState),
+        VMSTATE_UINT8(pending, Sun4c_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sun4c_intctl_reset(DeviceState *d)
+{
+    Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev);
+
+    s->reg = 1;
+    s->pending = 0;
+}
+
+static int sun4c_intctl_init1(SysBusDevice *dev)
+{
+    Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev);
+    int io_memory;
+    unsigned int i;
+
+    io_memory = cpu_register_io_memory(sun4c_intctl_mem_read,
+                                       sun4c_intctl_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
+    qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
+
+    for (i = 0; i < MAX_PILS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    return 0;
+}
+
+static SysBusDeviceInfo sun4c_intctl_info = {
+    .init = sun4c_intctl_init1,
+    .qdev.name  = "sun4c_intctl",
+    .qdev.size  = sizeof(Sun4c_INTCTLState),
+    .qdev.vmsd  = &vmstate_sun4c_intctl,
+    .qdev.reset = sun4c_intctl_reset,
+};
+
+static void sun4c_intctl_register_devices(void)
+{
+    sysbus_register_withprop(&sun4c_intctl_info);
+}
+
+device_init(sun4c_intctl_register_devices)
diff --git a/qemu-0.15.x/hw/sun4m.c b/qemu-0.15.x/hw/sun4m.c
new file mode 100644
index 0000000..df3aa32
--- /dev/null
+++ b/qemu-0.15.x/hw/sun4m.c
@@ -0,0 +1,1827 @@
+/*
+ * QEMU Sun4m & Sun4d & Sun4c System Emulator
+ *
+ * Copyright (c) 2003-2005 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 "sysbus.h"
+#include "qemu-timer.h"
+#include "sun4m.h"
+#include "nvram.h"
+#include "sparc32_dma.h"
+#include "fdc.h"
+#include "sysemu.h"
+#include "net.h"
+#include "boards.h"
+#include "firmware_abi.h"
+#include "esp.h"
+#include "pc.h"
+#include "isa.h"
+#include "fw_cfg.h"
+#include "escc.h"
+#include "empty_slot.h"
+#include "qdev-addr.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "trace.h"
+
+/*
+ * Sun4m architecture was used in the following machines:
+ *
+ * SPARCserver 6xxMP/xx
+ * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15),
+ * SPARCclassic X (4/10)
+ * SPARCstation LX/ZX (4/30)
+ * SPARCstation Voyager
+ * SPARCstation 10/xx, SPARCserver 10/xx
+ * SPARCstation 5, SPARCserver 5
+ * SPARCstation 20/xx, SPARCserver 20
+ * SPARCstation 4
+ *
+ * Sun4d architecture was used in the following machines:
+ *
+ * SPARCcenter 2000
+ * SPARCserver 1000
+ *
+ * Sun4c architecture was used in the following machines:
+ * SPARCstation 1/1+, SPARCserver 1/1+
+ * SPARCstation SLC
+ * SPARCstation IPC
+ * SPARCstation ELC
+ * SPARCstation IPX
+ *
+ * See for example: http://www.sunhelp.org/faq/sunref1.html
+ */
+
+#define KERNEL_LOAD_ADDR     0x00004000
+#define CMDLINE_ADDR         0x007ff000
+#define INITRD_LOAD_ADDR     0x00800000
+#define PROM_SIZE_MAX        (1024 * 1024)
+#define PROM_VADDR           0xffd00000
+#define PROM_FILENAME        "openbios-sparc32"
+#define CFG_ADDR             0xd00000510ULL
+#define FW_CFG_SUN4M_DEPTH   (FW_CFG_ARCH_LOCAL + 0x00)
+
+#define MAX_CPUS 16
+#define MAX_PILS 16
+#define MAX_VSIMMS 4
+
+#define ESCC_CLOCK 4915200
+
+struct sun4m_hwdef {
+    target_phys_addr_t iommu_base, iommu_pad_base, iommu_pad_len, slavio_base;
+    target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base;
+    target_phys_addr_t serial_base, fd_base;
+    target_phys_addr_t afx_base, idreg_base, dma_base, esp_base, le_base;
+    target_phys_addr_t tcx_base, cs_base, apc_base, aux1_base, aux2_base;
+    target_phys_addr_t bpp_base, dbri_base, sx_base;
+    struct {
+        target_phys_addr_t reg_base, vram_base;
+    } vsimm[MAX_VSIMMS];
+    target_phys_addr_t ecc_base;
+    uint32_t ecc_version;
+    uint8_t nvram_machine_id;
+    uint16_t machine_id;
+    uint32_t iommu_version;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+};
+
+#define MAX_IOUNITS 5
+
+struct sun4d_hwdef {
+    target_phys_addr_t iounit_bases[MAX_IOUNITS], slavio_base;
+    target_phys_addr_t counter_base, nvram_base, ms_kb_base;
+    target_phys_addr_t serial_base;
+    target_phys_addr_t espdma_base, esp_base;
+    target_phys_addr_t ledma_base, le_base;
+    target_phys_addr_t tcx_base;
+    target_phys_addr_t sbi_base;
+    uint8_t nvram_machine_id;
+    uint16_t machine_id;
+    uint32_t iounit_version;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+};
+
+struct sun4c_hwdef {
+    target_phys_addr_t iommu_base, slavio_base;
+    target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base;
+    target_phys_addr_t serial_base, fd_base;
+    target_phys_addr_t idreg_base, dma_base, esp_base, le_base;
+    target_phys_addr_t tcx_base, aux1_base;
+    uint8_t nvram_machine_id;
+    uint16_t machine_id;
+    uint32_t iommu_version;
+    uint64_t max_mem;
+    const char * const default_cpu_model;
+};
+
+int DMA_get_channel_mode (int nchan)
+{
+    return 0;
+}
+int DMA_read_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+int DMA_write_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+void DMA_hold_DREQ (int nchan) {}
+void DMA_release_DREQ (int nchan) {}
+void DMA_schedule(int nchan) {}
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+}
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
+                       const char *cmdline, const char *boot_devices,
+                       ram_addr_t RAM_size, uint32_t kernel_size,
+                       int width, int height, int depth,
+                       int nvram_machine_id, const char *arch)
+{
+    unsigned int i;
+    uint32_t start, end;
+    uint8_t image[0x1ff0];
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    memset(image, '\0', sizeof(image));
+
+    start = 0;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(image, end, prom_envs[i]);
+
+    // End marker
+    image[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = 0x1fd0;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr,
+                    nvram_machine_id);
+
+    for (i = 0; i < sizeof(image); i++)
+        m48t59_write(nvram, i, image[i]);
+}
+
+static DeviceState *slavio_intctl;
+
+void pic_info(Monitor *mon)
+{
+    if (slavio_intctl)
+        slavio_pic_info(mon, slavio_intctl);
+}
+
+void irq_info(Monitor *mon)
+{
+    if (slavio_intctl)
+        slavio_irq_info(mon, slavio_intctl);
+}
+
+void cpu_check_irqs(CPUState *env)
+{
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index) {
+                    trace_sun4m_cpu_interrupt(i);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void cpu_kick_irq(CPUState *env)
+{
+    env->halted = 0;
+    cpu_check_irqs(env);
+    qemu_cpu_kick(env);
+}
+
+static void cpu_set_irq(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        trace_sun4m_cpu_set_irq_raise(irq);
+        env->pil_in |= 1 << irq;
+        cpu_kick_irq(env);
+    } else {
+        trace_sun4m_cpu_set_irq_lower(irq);
+        env->pil_in &= ~(1 << irq);
+        cpu_check_irqs(env);
+    }
+}
+
+static void dummy_cpu_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->halted = 0;
+}
+
+static void secondary_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->halted = 1;
+}
+
+static void cpu_halt_signal(void *opaque, int irq, int level)
+{
+    if (level && cpu_single_env)
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return addr - 0xf0000000ULL;
+}
+
+static unsigned long sun4m_load_kernel(const char *kernel_filename,
+                                       const char *initrd_filename,
+                                       ram_addr_t RAM_size)
+{
+    int linux_boot;
+    unsigned int i;
+    long initrd_size, kernel_size;
+    uint8_t *ptr;
+
+    linux_boot = (kernel_filename != NULL);
+
+    kernel_size = 0;
+    if (linux_boot) {
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0)
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        if (kernel_size < 0)
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              RAM_size - KERNEL_LOAD_ADDR);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        initrd_size = 0;
+        if (initrd_filename) {
+            initrd_size = load_image_targphys(initrd_filename,
+                                              INITRD_LOAD_ADDR,
+                                              RAM_size - INITRD_LOAD_ADDR);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        }
+        if (initrd_size > 0) {
+            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
+                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
+                if (ldl_p(ptr) == 0x48647253) { // HdrS
+                    stl_p(ptr + 16, INITRD_LOAD_ADDR);
+                    stl_p(ptr + 20, initrd_size);
+                    break;
+                }
+            }
+        }
+    }
+    return kernel_size;
+}
+
+static void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "iommu");
+    qdev_prop_set_uint32(dev, "version", version);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, addr);
+
+    return s;
+}
+
+static void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq,
+                              void *iommu, qemu_irq *dev_irq, int is_ledma)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "sparc32_dma");
+    qdev_prop_set_ptr(dev, "iommu_opaque", iommu);
+    qdev_prop_set_uint32(dev, "is_ledma", is_ledma);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, parent_irq);
+    *dev_irq = qdev_get_gpio_in(dev, 0);
+    sysbus_mmio_map(s, 0, daddr);
+
+    return s;
+}
+
+static void lance_init(NICInfo *nd, target_phys_addr_t leaddr,
+                       void *dma_opaque, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    qemu_irq reset;
+
+    qemu_check_nic_model(&nd_table[0], "lance");
+
+    dev = qdev_create(NULL, "lance");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_ptr(dev, "dma", dma_opaque);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, leaddr);
+    sysbus_connect_irq(s, 0, irq);
+    reset = qdev_get_gpio_in(dev, 0);
+    qdev_connect_gpio_out(dma_opaque, 0, reset);
+}
+
+static DeviceState *slavio_intctl_init(target_phys_addr_t addr,
+                                       target_phys_addr_t addrg,
+                                       qemu_irq **parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i, j;
+
+    dev = qdev_create(NULL, "slavio_intctl");
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        for (j = 0; j < MAX_PILS; j++) {
+            sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
+        }
+    }
+    sysbus_mmio_map(s, 0, addrg);
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE);
+    }
+
+    return dev;
+}
+
+#define SYS_TIMER_OFFSET      0x10000ULL
+#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
+
+static void slavio_timer_init_all(target_phys_addr_t addr, qemu_irq master_irq,
+                                  qemu_irq *cpu_irqs, unsigned int num_cpus)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "slavio_timer");
+    qdev_prop_set_uint32(dev, "num_cpus", num_cpus);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, master_irq);
+    sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_mmio_map(s, i + 1, addr + (target_phys_addr_t)CPU_TIMER_OFFSET(i));
+        sysbus_connect_irq(s, i + 1, cpu_irqs[i]);
+    }
+}
+
+#define MISC_LEDS 0x01600000
+#define MISC_CFG  0x01800000
+#define MISC_DIAG 0x01a00000
+#define MISC_MDM  0x01b00000
+#define MISC_SYS  0x01f00000
+
+static void slavio_misc_init(target_phys_addr_t base,
+                             target_phys_addr_t aux1_base,
+                             target_phys_addr_t aux2_base, qemu_irq irq,
+                             qemu_irq fdc_tc)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "slavio_misc");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    if (base) {
+        /* 8 bit registers */
+        /* Slavio control */
+        sysbus_mmio_map(s, 0, base + MISC_CFG);
+        /* Diagnostics */
+        sysbus_mmio_map(s, 1, base + MISC_DIAG);
+        /* Modem control */
+        sysbus_mmio_map(s, 2, base + MISC_MDM);
+        /* 16 bit registers */
+        /* ss600mp diag LEDs */
+        sysbus_mmio_map(s, 3, base + MISC_LEDS);
+        /* 32 bit registers */
+        /* System control */
+        sysbus_mmio_map(s, 4, base + MISC_SYS);
+    }
+    if (aux1_base) {
+        /* AUX 1 (Misc System Functions) */
+        sysbus_mmio_map(s, 5, aux1_base);
+    }
+    if (aux2_base) {
+        /* AUX 2 (Software Powerdown Control) */
+        sysbus_mmio_map(s, 6, aux2_base);
+    }
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_connect_irq(s, 1, fdc_tc);
+    qemu_system_powerdown = qdev_get_gpio_in(dev, 0);
+}
+
+static void ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "eccmemctl");
+    qdev_prop_set_uint32(dev, "version", version);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, base);
+    if (version == 0) { // SS-600MP only
+        sysbus_mmio_map(s, 1, base + 0x1000);
+    }
+}
+
+static void apc_init(target_phys_addr_t power_base, qemu_irq cpu_halt)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "apc");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    /* Power management (APC) XXX: not a Slavio device */
+    sysbus_mmio_map(s, 0, power_base);
+    sysbus_connect_irq(s, 0, cpu_halt);
+}
+
+static void tcx_init(target_phys_addr_t addr, int vram_size, int width,
+                     int height, int depth)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "SUNW,tcx");
+    qdev_prop_set_taddr(dev, "addr", addr);
+    qdev_prop_set_uint32(dev, "vram_size", vram_size);
+    qdev_prop_set_uint16(dev, "width", width);
+    qdev_prop_set_uint16(dev, "height", height);
+    qdev_prop_set_uint16(dev, "depth", depth);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    /* 8-bit plane */
+    sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
+    /* DAC */
+    sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
+    /* TEC (dummy) */
+    sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
+    /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
+    sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
+    if (depth == 24) {
+        /* 24-bit plane */
+        sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
+        /* Control plane */
+        sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
+    } else {
+        /* THC 8 bit (dummy) */
+        sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
+    }
+}
+
+/* NCR89C100/MACIO Internal ID register */
+static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 };
+
+static void idreg_init(target_phys_addr_t addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "macio_idreg");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+    cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data));
+}
+
+static int idreg_init1(SysBusDevice *dev)
+{
+    ram_addr_t idreg_offset;
+
+    idreg_offset = qemu_ram_alloc(NULL, "sun4m.idreg", sizeof(idreg_data));
+    sysbus_init_mmio(dev, sizeof(idreg_data), idreg_offset | IO_MEM_ROM);
+    return 0;
+}
+
+static SysBusDeviceInfo idreg_info = {
+    .init = idreg_init1,
+    .qdev.name  = "macio_idreg",
+    .qdev.size  = sizeof(SysBusDevice),
+};
+
+static void idreg_register_devices(void)
+{
+    sysbus_register_withprop(&idreg_info);
+}
+
+device_init(idreg_register_devices);
+
+/* SS-5 TCX AFX register */
+static void afx_init(target_phys_addr_t addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "tcx_afx");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static int afx_init1(SysBusDevice *dev)
+{
+    ram_addr_t afx_offset;
+
+    afx_offset = qemu_ram_alloc(NULL, "sun4m.afx", 4);
+    sysbus_init_mmio(dev, 4, afx_offset | IO_MEM_RAM);
+    return 0;
+}
+
+static SysBusDeviceInfo afx_info = {
+    .init = afx_init1,
+    .qdev.name  = "tcx_afx",
+    .qdev.size  = sizeof(SysBusDevice),
+};
+
+static void afx_register_devices(void)
+{
+    sysbus_register_withprop(&afx_info);
+}
+
+device_init(afx_register_devices);
+
+/* Boot PROM (OpenBIOS) */
+static uint64_t translate_prom_address(void *opaque, uint64_t addr)
+{
+    target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque;
+    return addr + *base_addr - PROM_VADDR;
+}
+
+static void prom_init(target_phys_addr_t addr, const char *bios_name)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    char *filename;
+    int ret;
+
+    dev = qdev_create(NULL, "openprom");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+
+    /* load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        ret = load_elf(filename, translate_prom_address, &addr, NULL,
+                       NULL, NULL, 1, ELF_MACHINE, 0);
+        if (ret < 0 || ret > PROM_SIZE_MAX) {
+            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
+        }
+        qemu_free(filename);
+    } else {
+        ret = -1;
+    }
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
+        exit(1);
+    }
+}
+
+static int prom_init1(SysBusDevice *dev)
+{
+    ram_addr_t prom_offset;
+
+    prom_offset = qemu_ram_alloc(NULL, "sun4m.prom", PROM_SIZE_MAX);
+    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    return 0;
+}
+
+static SysBusDeviceInfo prom_info = {
+    .init = prom_init1,
+    .qdev.name  = "openprom",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.props = (Property[]) {
+        {/* end of property list */}
+    }
+};
+
+static void prom_register_devices(void)
+{
+    sysbus_register_withprop(&prom_info);
+}
+
+device_init(prom_register_devices);
+
+typedef struct RamDevice
+{
+    SysBusDevice busdev;
+    uint64_t size;
+} RamDevice;
+
+/* System RAM */
+static int ram_init1(SysBusDevice *dev)
+{
+    ram_addr_t RAM_size, ram_offset;
+    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
+
+    RAM_size = d->size;
+
+    ram_offset = qemu_ram_alloc(NULL, "sun4m.ram", RAM_size);
+    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    return 0;
+}
+
+static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size,
+                     uint64_t max_mem)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    RamDevice *d;
+
+    /* allocate RAM */
+    if ((uint64_t)RAM_size > max_mem) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum %d\n",
+                (unsigned int)(RAM_size / (1024 * 1024)),
+                (unsigned int)(max_mem / (1024 * 1024)));
+        exit(1);
+    }
+    dev = qdev_create(NULL, "memory");
+    s = sysbus_from_qdev(dev);
+
+    d = FROM_SYSBUS(RamDevice, s);
+    d->size = RAM_size;
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static SysBusDeviceInfo ram_info = {
+    .init = ram_init1,
+    .qdev.name  = "memory",
+    .qdev.size  = sizeof(RamDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ram_register_devices(void)
+{
+    sysbus_register_withprop(&ram_info);
+}
+
+device_init(ram_register_devices);
+
+static void cpu_devinit(const char *cpu_model, unsigned int id,
+                        uint64_t prom_addr, qemu_irq **cpu_irqs)
+{
+    CPUState *env;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    cpu_sparc_set_id(env, id);
+    if (id == 0) {
+        qemu_register_reset(main_cpu_reset, env);
+    } else {
+        qemu_register_reset(secondary_cpu_reset, env);
+        env->halted = 1;
+    }
+    *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
+    env->prom_addr = prom_addr;
+}
+
+static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    unsigned int i;
+    void *iommu, *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
+        espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq fdc_tc;
+    qemu_irq *cpu_halt;
+    unsigned long kernel_size;
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+    unsigned int num_vsimms;
+
+    /* init CPUs */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    for(i = 0; i < smp_cpus; i++) {
+        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
+    }
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+    /* models without ECC don't trap when missing ram is accessed */
+    if (!hwdef->ecc_base) {
+        empty_slot_init(RAM_size, hwdef->max_mem - RAM_size);
+    }
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
+                                       hwdef->intctl_base + 0x10000ULL,
+                                       cpu_irqs);
+
+    for (i = 0; i < 32; i++) {
+        slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);
+    }
+    for (i = 0; i < MAX_CPUS; i++) {
+        slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i);
+    }
+
+    if (hwdef->idreg_base) {
+        idreg_init(hwdef->idreg_base);
+    }
+
+    if (hwdef->afx_base) {
+        afx_init(hwdef->afx_base);
+    }
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[30]);
+
+    if (hwdef->iommu_pad_base) {
+        /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased.
+           Software shouldn't use aliased addresses, neither should it crash
+           when does. Using empty_slot instead of aliasing can help with
+           debugging such accesses */
+        empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len);
+    }
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18],
+                              iommu, &espdma_irq, 0);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[16], iommu, &ledma_irq, 1);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    num_vsimms = 0;
+    if (num_vsimms == 0) {
+        tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+                 graphic_depth);
+    }
+
+    for (i = num_vsimms; i < MAX_VSIMMS; i++) {
+        /* vsimm registers probed by OBP */
+        if (hwdef->vsimm[i].reg_base) {
+            empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
+        }
+    }
+
+    if (hwdef->sx_base) {
+        empty_slot_init(hwdef->sx_base, 0x2000);
+    }
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
+
+    slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
+    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+    escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
+              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
+
+    cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
+    slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
+                     slavio_irq[30], fdc_tc);
+
+    if (hwdef->apc_base) {
+        apc_init(hwdef->apc_base, cpu_halt[0]);
+    }
+
+    if (hwdef->fd_base) {
+        /* there is zero or one floppy drive */
+        memset(fd, 0, sizeof(fd));
+        fd[0] = drive_get(IF_FLOPPY, 0, 0);
+        sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
+                          &fdc_tc);
+    }
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    if (hwdef->cs_base) {
+        sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
+                             slavio_irq[5]);
+    }
+
+    if (hwdef->dbri_base) {
+        /* ISDN chip with attached CS4215 audio codec */
+        /* prom space */
+        empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
+        /* reg space */
+        empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
+    }
+
+    if (hwdef->bpp_base) {
+        /* parallel port */
+        empty_slot_init(hwdef->bpp_base, 0x20);
+    }
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4m");
+
+    if (hwdef->ecc_base)
+        ecc_init(hwdef->ecc_base, slavio_irq[28],
+                 hwdef->ecc_version);
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
+                         (uint8_t*)strdup(kernel_cmdline),
+                         strlen(kernel_cmdline) + 1);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(kernel_cmdline) + 1);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+enum {
+    ss2_id = 0,
+    ss5_id = 32,
+    vger_id,
+    lx_id,
+    ss4_id,
+    scls_id,
+    sbook_id,
+    ss10_id = 64,
+    ss20_id,
+    ss600mp_id,
+    ss1000_id = 96,
+    ss2000_id,
+};
+
+static const struct sun4m_hwdef sun4m_hwdefs[] = {
+    /* SS-5 */
+    {
+        .iommu_base   = 0x10000000,
+        .iommu_pad_base = 0x10004000,
+        .iommu_pad_len  = 0x0fffb000,
+        .tcx_base     = 0x50000000,
+        .cs_base      = 0x6c000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .afx_base     = 0x6e000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss5_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* SS-10 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_base      = 0xff1700000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL,
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x10000000, // version 0, implementation 1
+        .nvram_machine_id = 0x72,
+        .machine_id = ss10_id,
+        .iommu_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-600MP */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .dma_base     = 0xef0081000ULL,
+        .esp_base     = 0xef0080000ULL,
+        .le_base      = 0xef0060000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL, // XXX should not exist
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x00000000, // version 0, implementation 0
+        .nvram_machine_id = 0x71,
+        .machine_id = ss600mp_id,
+        .iommu_version = 0x01000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-20 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_base      = 0xff1700000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .idreg_base   = 0xef0000000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .bpp_base     = 0xef4800000ULL,
+        .apc_base     = 0xefa000000ULL, // XXX should not exist
+        .aux1_base    = 0xff1800000ULL,
+        .aux2_base    = 0xff1a01000ULL,
+        .dbri_base    = 0xee0000000ULL,
+        .sx_base      = 0xf80000000ULL,
+        .vsimm        = {
+            {
+                .reg_base  = 0x9c000000ULL,
+                .vram_base = 0xfc000000ULL
+            }, {
+                .reg_base  = 0x90000000ULL,
+                .vram_base = 0xf0000000ULL
+            }, {
+                .reg_base  = 0x94000000ULL
+            }, {
+                .reg_base  = 0x98000000ULL
+            }
+        },
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x20000000, // version 0, implementation 2
+        .nvram_machine_id = 0x72,
+        .machine_id = ss20_id,
+        .iommu_version = 0x13000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* Voyager */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x71300000, // pmc
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = vger_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* LX */
+    {
+        .iommu_base   = 0x10000000,
+        .iommu_pad_base = 0x10004000,
+        .iommu_pad_len  = 0x0fffb000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = lx_id,
+        .iommu_version = 0x04000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+    /* SS-4 */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .cs_base      = 0x6c000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss4_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Fujitsu MB86904",
+    },
+    /* SPARCClassic */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = scls_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+    /* SPARCbook */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000, // XXX
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .idreg_base   = 0x78000000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .apc_base     = 0x6a000000,
+        .aux1_base    = 0x71900000,
+        .aux2_base    = 0x71910000,
+        .nvram_machine_id = 0x80,
+        .machine_id = sbook_id,
+        .iommu_version = 0x05000000,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "TI MicroSparc I",
+    },
+};
+
+/* SPARCstation 5 hardware initialisation */
+static void ss5_init(ram_addr_t RAM_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 10 hardware initialisation */
+static void ss10_init(ram_addr_t RAM_size,
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCserver 600MP hardware initialisation */
+static void ss600mp_init(ram_addr_t RAM_size,
+                         const char *boot_device,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 20 hardware initialisation */
+static void ss20_init(ram_addr_t RAM_size,
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation Voyager hardware initialisation */
+static void vger_init(ram_addr_t RAM_size,
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation LX hardware initialisation */
+static void ss_lx_init(ram_addr_t RAM_size,
+                       const char *boot_device,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCstation 4 hardware initialisation */
+static void ss4_init(ram_addr_t RAM_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCClassic hardware initialisation */
+static void scls_init(ram_addr_t RAM_size,
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCbook hardware initialisation */
+static void sbook_init(ram_addr_t RAM_size,
+                       const char *boot_device,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss5_machine = {
+    .name = "SS-5",
+    .desc = "Sun4m platform, SPARCstation 5",
+    .init = ss5_init,
+    .use_scsi = 1,
+    .is_default = 1,
+};
+
+static QEMUMachine ss10_machine = {
+    .name = "SS-10",
+    .desc = "Sun4m platform, SPARCstation 10",
+    .init = ss10_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static QEMUMachine ss600mp_machine = {
+    .name = "SS-600MP",
+    .desc = "Sun4m platform, SPARCserver 600MP",
+    .init = ss600mp_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static QEMUMachine ss20_machine = {
+    .name = "SS-20",
+    .desc = "Sun4m platform, SPARCstation 20",
+    .init = ss20_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static QEMUMachine voyager_machine = {
+    .name = "Voyager",
+    .desc = "Sun4m platform, SPARCstation Voyager",
+    .init = vger_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine ss_lx_machine = {
+    .name = "LX",
+    .desc = "Sun4m platform, SPARCstation LX",
+    .init = ss_lx_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine ss4_machine = {
+    .name = "SS-4",
+    .desc = "Sun4m platform, SPARCstation 4",
+    .init = ss4_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine scls_machine = {
+    .name = "SPARCClassic",
+    .desc = "Sun4m platform, SPARCClassic",
+    .init = scls_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine sbook_machine = {
+    .name = "SPARCbook",
+    .desc = "Sun4m platform, SPARCbook",
+    .init = sbook_init,
+    .use_scsi = 1,
+};
+
+static const struct sun4d_hwdef sun4d_hwdefs[] = {
+    /* SS-1000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            -1,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss1000_id,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+    /* SS-2000 */
+    {
+        .iounit_bases   = {
+            0xfe0200000ULL,
+            0xfe1200000ULL,
+            0xfe2200000ULL,
+            0xfe3200000ULL,
+            0xfe4200000ULL,
+        },
+        .tcx_base     = 0x820000000ULL,
+        .slavio_base  = 0xf00000000ULL,
+        .ms_kb_base   = 0xf00240000ULL,
+        .serial_base  = 0xf00200000ULL,
+        .nvram_base   = 0xf00280000ULL,
+        .counter_base = 0xf00300000ULL,
+        .espdma_base  = 0x800081000ULL,
+        .esp_base     = 0x800080000ULL,
+        .ledma_base   = 0x800040000ULL,
+        .le_base      = 0x800060000ULL,
+        .sbi_base     = 0xf02800000ULL,
+        .nvram_machine_id = 0x80,
+        .machine_id = ss2000_id,
+        .iounit_version = 0x03000000,
+        .max_mem = 0xf00000000ULL,
+        .default_cpu_model = "TI SuperSparc II",
+    },
+};
+
+static DeviceState *sbi_init(target_phys_addr_t addr, qemu_irq **parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "sbi");
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_connect_irq(s, i, *parent_irq[i]);
+    }
+
+    sysbus_mmio_map(s, 0, addr);
+
+    return dev;
+}
+
+static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    unsigned int i;
+    void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
+        espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    unsigned long kernel_size;
+    void *fw_cfg;
+    DeviceState *dev;
+
+    /* init CPUs */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    for(i = 0; i < smp_cpus; i++) {
+        cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]);
+    }
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    dev = sbi_init(hwdef->sbi_base, cpu_irqs);
+
+    for (i = 0; i < 32; i++) {
+        sbi_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+    for (i = 0; i < MAX_CPUS; i++) {
+        sbi_cpu_irq[i] = qdev_get_gpio_in(dev, 32 + i);
+    }
+
+    for (i = 0; i < MAX_IOUNITS; i++)
+        if (hwdef->iounit_bases[i] != (target_phys_addr_t)-1)
+            iounits[i] = iommu_init(hwdef->iounit_bases[i],
+                                    hwdef->iounit_version,
+                                    sbi_irq[0]);
+
+    espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3],
+                              iounits[0], &espdma_irq, 0);
+
+    /* should be lebuffer instead */
+    ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4],
+                             iounits[0], &ledma_irq, 0);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+             graphic_depth);
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
+
+    slavio_timer_init_all(hwdef->counter_base, sbi_irq[10], sbi_cpu_irq, smp_cpus);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
+    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+    escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12],
+              serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4d");
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
+                         (uint8_t*)strdup(kernel_cmdline),
+                         strlen(kernel_cmdline) + 1);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+/* SPARCserver 1000 hardware initialisation */
+static void ss1000_init(ram_addr_t RAM_size,
+                        const char *boot_device,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+/* SPARCcenter 2000 hardware initialisation */
+static void ss2000_init(ram_addr_t RAM_size,
+                        const char *boot_device,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss1000_machine = {
+    .name = "SS-1000",
+    .desc = "Sun4d platform, SPARCserver 1000",
+    .init = ss1000_init,
+    .use_scsi = 1,
+    .max_cpus = 8,
+};
+
+static QEMUMachine ss2000_machine = {
+    .name = "SS-2000",
+    .desc = "Sun4d platform, SPARCcenter 2000",
+    .init = ss2000_init,
+    .use_scsi = 1,
+    .max_cpus = 20,
+};
+
+static const struct sun4c_hwdef sun4c_hwdefs[] = {
+    /* SS-2 */
+    {
+        .iommu_base   = 0xf8000000,
+        .tcx_base     = 0xfe000000,
+        .slavio_base  = 0xf6000000,
+        .intctl_base  = 0xf5000000,
+        .counter_base = 0xf3000000,
+        .ms_kb_base   = 0xf0000000,
+        .serial_base  = 0xf1000000,
+        .nvram_base   = 0xf2000000,
+        .fd_base      = 0xf7200000,
+        .dma_base     = 0xf8400000,
+        .esp_base     = 0xf8800000,
+        .le_base      = 0xf8c00000,
+        .aux1_base    = 0xf7400003,
+        .nvram_machine_id = 0x55,
+        .machine_id = ss2_id,
+        .max_mem = 0x10000000,
+        .default_cpu_model = "Cypress CY7C601",
+    },
+};
+
+static DeviceState *sun4c_intctl_init(target_phys_addr_t addr,
+                                      qemu_irq *parent_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    unsigned int i;
+
+    dev = qdev_create(NULL, "sun4c_intctl");
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+
+    for (i = 0; i < MAX_PILS; i++) {
+        sysbus_connect_irq(s, i, parent_irq[i]);
+    }
+    sysbus_mmio_map(s, 0, addr);
+
+    return dev;
+}
+
+static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    void *iommu, *espdma, *ledma, *nvram;
+    qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
+    qemu_irq esp_reset, dma_enable;
+    qemu_irq fdc_tc;
+    unsigned long kernel_size;
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+    DeviceState *dev;
+    unsigned int i;
+
+    /* init CPU */
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+
+    cpu_devinit(cpu_model, 0, hwdef->slavio_base, &cpu_irqs);
+
+    /* set up devices */
+    ram_init(0, RAM_size, hwdef->max_mem);
+
+    prom_init(hwdef->slavio_base, bios_name);
+
+    dev = sun4c_intctl_init(hwdef->intctl_base, cpu_irqs);
+
+    for (i = 0; i < 8; i++) {
+        slavio_irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
+                       slavio_irq[1]);
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2],
+                              iommu, &espdma_irq, 0);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[3], iommu, &ledma_irq, 1);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+             graphic_depth);
+
+    lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x800, 2);
+
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1],
+                              display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
+    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+    escc_init(hwdef->serial_base, slavio_irq[1],
+              slavio_irq[1], serial_hds[0], serial_hds[1],
+              ESCC_CLOCK, 1);
+
+    slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
+
+    if (hwdef->fd_base != (target_phys_addr_t)-1) {
+        /* there is zero or one floppy drive */
+        memset(fd, 0, sizeof(fd));
+        fd[0] = drive_get(IF_FLOPPY, 0, 0);
+        sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
+                          &fdc_tc);
+    }
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    esp_init(hwdef->esp_base, 2,
+             espdma_memory_read, espdma_memory_write,
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
+
+    kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
+                                    RAM_size);
+
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, hwdef->nvram_machine_id,
+               "Sun4c");
+
+    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
+                         (uint8_t*)strdup(kernel_cmdline),
+                         strlen(kernel_cmdline) + 1);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+/* SPARCstation 2 hardware initialisation */
+static void ss2_init(ram_addr_t RAM_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename,
+                  kernel_cmdline, initrd_filename, cpu_model);
+}
+
+static QEMUMachine ss2_machine = {
+    .name = "SS-2",
+    .desc = "Sun4c platform, SPARCstation 2",
+    .init = ss2_init,
+    .use_scsi = 1,
+};
+
+static void ss2_machine_init(void)
+{
+    qemu_register_machine(&ss5_machine);
+    qemu_register_machine(&ss10_machine);
+    qemu_register_machine(&ss600mp_machine);
+    qemu_register_machine(&ss20_machine);
+    qemu_register_machine(&voyager_machine);
+    qemu_register_machine(&ss_lx_machine);
+    qemu_register_machine(&ss4_machine);
+    qemu_register_machine(&scls_machine);
+    qemu_register_machine(&sbook_machine);
+    qemu_register_machine(&ss1000_machine);
+    qemu_register_machine(&ss2000_machine);
+    qemu_register_machine(&ss2_machine);
+}
+
+machine_init(ss2_machine_init);
diff --git a/qemu-0.15.x/hw/sun4m.h b/qemu-0.15.x/hw/sun4m.h
new file mode 100644
index 0000000..ce97ee5
--- /dev/null
+++ b/qemu-0.15.x/hw/sun4m.h
@@ -0,0 +1,36 @@
+#ifndef SUN4M_H
+#define SUN4M_H
+
+#include "qemu-common.h"
+
+/* Devices used by sparc32 system.  */
+
+/* iommu.c */
+void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
+                                 uint8_t *buf, int len, int is_write);
+static inline void sparc_iommu_memory_read(void *opaque,
+                                           target_phys_addr_t addr,
+                                           uint8_t *buf, int len)
+{
+    sparc_iommu_memory_rw(opaque, addr, buf, len, 0);
+}
+
+static inline void sparc_iommu_memory_write(void *opaque,
+                                            target_phys_addr_t addr,
+                                            uint8_t *buf, int len)
+{
+    sparc_iommu_memory_rw(opaque, addr, buf, len, 1);
+}
+
+/* slavio_intctl.c */
+void slavio_pic_info(Monitor *mon, DeviceState *dev);
+void slavio_irq_info(Monitor *mon, DeviceState *dev);
+
+/* sun4c_intctl.c */
+void sun4c_pic_info(Monitor *mon, void *opaque);
+void sun4c_irq_info(Monitor *mon, void *opaque);
+
+/* sparc32_dma.c */
+#include "sparc32_dma.h"
+
+#endif
diff --git a/qemu-0.15.x/hw/sun4m_iommu.c b/qemu-0.15.x/hw/sun4m_iommu.c
new file mode 100644
index 0000000..7f5dad5
--- /dev/null
+++ b/qemu-0.15.x/hw/sun4m_iommu.c
@@ -0,0 +1,378 @@
+/*
+ * QEMU Sun4m iommu emulation
+ *
+ * Copyright (c) 2003-2005 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 "sun4m.h"
+#include "sysbus.h"
+#include "trace.h"
+
+/*
+ * I/O MMU used by Sun4m systems
+ *
+ * Chipset docs:
+ * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
+ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
+ */
+
+#define IOMMU_NREGS         (4*4096/4)
+#define IOMMU_CTRL          (0x0000 >> 2)
+#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
+#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
+#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
+#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
+#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
+#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
+#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
+#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
+#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
+#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
+#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+#define IOMMU_CTRL_MASK     0x0000001d
+
+#define IOMMU_BASE          (0x0004 >> 2)
+#define IOMMU_BASE_MASK     0x07fffc00
+
+#define IOMMU_TLBFLUSH      (0x0014 >> 2)
+#define IOMMU_TLBFLUSH_MASK 0xffffffff
+
+#define IOMMU_PGFLUSH       (0x0018 >> 2)
+#define IOMMU_PGFLUSH_MASK  0xffffffff
+
+#define IOMMU_AFSR          (0x1000 >> 2)
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after
+                                          transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than
+                                          12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error
+                                          acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00800000 /* Reserved, forced to 0x8 by
+                                          hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+#define IOMMU_AFSR_MASK     0xff0fffff
+
+#define IOMMU_AFAR          (0x1004 >> 2)
+
+#define IOMMU_AER           (0x1008 >> 2) /* Arbiter Enable Register */
+#define IOMMU_AER_EN_P0_ARB 0x00000001    /* MBus master 0x8 (Always 1) */
+#define IOMMU_AER_EN_P1_ARB 0x00000002    /* MBus master 0x9 */
+#define IOMMU_AER_EN_P2_ARB 0x00000004    /* MBus master 0xa */
+#define IOMMU_AER_EN_P3_ARB 0x00000008    /* MBus master 0xb */
+#define IOMMU_AER_EN_0      0x00010000    /* SBus slot 0 */
+#define IOMMU_AER_EN_1      0x00020000    /* SBus slot 1 */
+#define IOMMU_AER_EN_2      0x00040000    /* SBus slot 2 */
+#define IOMMU_AER_EN_3      0x00080000    /* SBus slot 3 */
+#define IOMMU_AER_EN_F      0x00100000    /* SBus on-board */
+#define IOMMU_AER_SBW       0x80000000    /* S-to-M asynchronous writes */
+#define IOMMU_AER_MASK      0x801f000f
+
+#define IOMMU_SBCFG0        (0x1010 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG1        (0x1014 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG2        (0x1018 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG3        (0x101c >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when
+                                          bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+                                          produced by this device as pure
+                                          physical. */
+#define IOMMU_SBCFG_MASK    0x00010003
+
+#define IOMMU_ARBEN         (0x2000 >> 2) /* SBUS arbitration enable */
+#define IOMMU_ARBEN_MASK    0x001f0000
+#define IOMMU_MID           0x00000008
+
+#define IOMMU_MASK_ID       (0x3018 >> 2) /* Mask ID */
+#define IOMMU_MASK_ID_MASK  0x00ffffff
+
+#define IOMMU_MSII_MASK     0x26000000 /* microSPARC II mask number */
+#define IOMMU_TS_MASK       0x23000000 /* turboSPARC mask number */
+
+/* The format of an iopte in the page tables */
+#define IOPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
+#define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or
+                                          Viking/MXCC) */
+#define IOPTE_WRITE         0x00000004 /* Writable */
+#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
+#define IOPTE_WAZ           0x00000001 /* Write as zeros */
+
+#define IOMMU_PAGE_SHIFT    12
+#define IOMMU_PAGE_SIZE     (1 << IOMMU_PAGE_SHIFT)
+#define IOMMU_PAGE_MASK     ~(IOMMU_PAGE_SIZE - 1)
+
+typedef struct IOMMUState {
+    SysBusDevice busdev;
+    uint32_t regs[IOMMU_NREGS];
+    target_phys_addr_t iostart;
+    uint32_t version;
+    qemu_irq irq;
+} IOMMUState;
+
+static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    IOMMUState *s = opaque;
+    target_phys_addr_t saddr;
+    uint32_t ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    case IOMMU_AFAR:
+    case IOMMU_AFSR:
+        ret = s->regs[saddr];
+        qemu_irq_lower(s->irq);
+        break;
+    }
+    trace_sun4m_iommu_mem_readl(saddr, ret);
+    return ret;
+}
+
+static void iommu_mem_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    IOMMUState *s = opaque;
+    target_phys_addr_t saddr;
+
+    saddr = addr >> 2;
+    trace_sun4m_iommu_mem_writel(saddr, val);
+    switch (saddr) {
+    case IOMMU_CTRL:
+        switch (val & IOMMU_CTRL_RNGE) {
+        case IOMMU_RNGE_16MB:
+            s->iostart = 0xffffffffff000000ULL;
+            break;
+        case IOMMU_RNGE_32MB:
+            s->iostart = 0xfffffffffe000000ULL;
+            break;
+        case IOMMU_RNGE_64MB:
+            s->iostart = 0xfffffffffc000000ULL;
+            break;
+        case IOMMU_RNGE_128MB:
+            s->iostart = 0xfffffffff8000000ULL;
+            break;
+        case IOMMU_RNGE_256MB:
+            s->iostart = 0xfffffffff0000000ULL;
+            break;
+        case IOMMU_RNGE_512MB:
+            s->iostart = 0xffffffffe0000000ULL;
+            break;
+        case IOMMU_RNGE_1GB:
+            s->iostart = 0xffffffffc0000000ULL;
+            break;
+        default:
+        case IOMMU_RNGE_2GB:
+            s->iostart = 0xffffffff80000000ULL;
+            break;
+        }
+        trace_sun4m_iommu_mem_writel_ctrl(s->iostart);
+        s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version);
+        break;
+    case IOMMU_BASE:
+        s->regs[saddr] = val & IOMMU_BASE_MASK;
+        break;
+    case IOMMU_TLBFLUSH:
+        trace_sun4m_iommu_mem_writel_tlbflush(val);
+        s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
+        break;
+    case IOMMU_PGFLUSH:
+        trace_sun4m_iommu_mem_writel_pgflush(val);
+        s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
+        break;
+    case IOMMU_AFAR:
+        s->regs[saddr] = val;
+        qemu_irq_lower(s->irq);
+        break;
+    case IOMMU_AER:
+        s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB;
+        break;
+    case IOMMU_AFSR:
+        s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
+        qemu_irq_lower(s->irq);
+        break;
+    case IOMMU_SBCFG0:
+    case IOMMU_SBCFG1:
+    case IOMMU_SBCFG2:
+    case IOMMU_SBCFG3:
+        s->regs[saddr] = val & IOMMU_SBCFG_MASK;
+        break;
+    case IOMMU_ARBEN:
+        // XXX implement SBus probing: fault when reading unmapped
+        // addresses, fault cause and address stored to MMU/IOMMU
+        s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
+        break;
+    case IOMMU_MASK_ID:
+        s->regs[saddr] |= val & IOMMU_MASK_ID_MASK;
+        break;
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const iommu_mem_read[3] = {
+    NULL,
+    NULL,
+    iommu_mem_readl,
+};
+
+static CPUWriteMemoryFunc * const iommu_mem_write[3] = {
+    NULL,
+    NULL,
+    iommu_mem_writel,
+};
+
+static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr)
+{
+    uint32_t ret;
+    target_phys_addr_t iopte;
+    target_phys_addr_t pa = addr;
+
+    iopte = s->regs[IOMMU_BASE] << 4;
+    addr &= ~s->iostart;
+    iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
+    cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4);
+    tswap32s(&ret);
+    trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
+    return ret;
+}
+
+static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr,
+                                             uint32_t pte)
+{
+    target_phys_addr_t pa;
+
+    pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK);
+    trace_sun4m_iommu_translate_pa(addr, pa, pte);
+    return pa;
+}
+
+static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr,
+                           int is_write)
+{
+    trace_sun4m_iommu_bad_addr(addr);
+    s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
+        IOMMU_AFSR_FAV;
+    if (!is_write)
+        s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
+    s->regs[IOMMU_AFAR] = addr;
+    qemu_irq_raise(s->irq);
+}
+
+void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int l;
+    uint32_t flags;
+    target_phys_addr_t page, phys_addr;
+
+    while (len > 0) {
+        page = addr & IOMMU_PAGE_MASK;
+        l = (page + IOMMU_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        flags = iommu_page_get_flags(opaque, page);
+        if (!(flags & IOPTE_VALID)) {
+            iommu_bad_addr(opaque, page, is_write);
+            return;
+        }
+        phys_addr = iommu_translate_pa(addr, flags);
+        if (is_write) {
+            if (!(flags & IOPTE_WRITE)) {
+                iommu_bad_addr(opaque, page, is_write);
+                return;
+            }
+            cpu_physical_memory_write(phys_addr, buf, l);
+        } else {
+            cpu_physical_memory_read(phys_addr, buf, l);
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+}
+
+static const VMStateDescription vmstate_iommu = {
+    .name ="iommu",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
+        VMSTATE_UINT64(iostart, IOMMUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void iommu_reset(DeviceState *d)
+{
+    IOMMUState *s = container_of(d, IOMMUState, busdev.qdev);
+
+    memset(s->regs, 0, IOMMU_NREGS * 4);
+    s->iostart = 0;
+    s->regs[IOMMU_CTRL] = s->version;
+    s->regs[IOMMU_ARBEN] = IOMMU_MID;
+    s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
+    s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
+    s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
+}
+
+static int iommu_init1(SysBusDevice *dev)
+{
+    IOMMUState *s = FROM_SYSBUS(IOMMUState, dev);
+    int io;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    io = cpu_register_io_memory(iommu_mem_read, iommu_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, IOMMU_NREGS * sizeof(uint32_t), io);
+
+    return 0;
+}
+
+static SysBusDeviceInfo iommu_info = {
+    .init = iommu_init1,
+    .qdev.name  = "iommu",
+    .qdev.size  = sizeof(IOMMUState),
+    .qdev.vmsd  = &vmstate_iommu,
+    .qdev.reset = iommu_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void iommu_register_devices(void)
+{
+    sysbus_register_withprop(&iommu_info);
+}
+
+device_init(iommu_register_devices)
diff --git a/qemu-0.15.x/hw/sun4u.c b/qemu-0.15.x/hw/sun4u.c
new file mode 100644
index 0000000..d7dcaf0
--- /dev/null
+++ b/qemu-0.15.x/hw/sun4u.c
@@ -0,0 +1,935 @@
+/*
+ * QEMU Sun4u/Sun4v System Emulator
+ *
+ * Copyright (c) 2005 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 "hw.h"
+#include "pci.h"
+#include "apb_pci.h"
+#include "pc.h"
+#include "nvram.h"
+#include "fdc.h"
+#include "net.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "firmware_abi.h"
+#include "fw_cfg.h"
+#include "sysbus.h"
+#include "ide.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+
+//#define DEBUG_IRQ
+//#define DEBUG_EBUS
+//#define DEBUG_TIMER
+
+#ifdef DEBUG_IRQ
+#define CPUIRQ_DPRINTF(fmt, ...)                                \
+    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define CPUIRQ_DPRINTF(fmt, ...)
+#endif
+
+#ifdef DEBUG_EBUS
+#define EBUS_DPRINTF(fmt, ...)                                  \
+    do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define EBUS_DPRINTF(fmt, ...)
+#endif
+
+#ifdef DEBUG_TIMER
+#define TIMER_DPRINTF(fmt, ...)                                  \
+    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define TIMER_DPRINTF(fmt, ...)
+#endif
+
+#define KERNEL_LOAD_ADDR     0x00404000
+#define CMDLINE_ADDR         0x003ff000
+#define INITRD_LOAD_ADDR     0x00300000
+#define PROM_SIZE_MAX        (4 * 1024 * 1024)
+#define PROM_VADDR           0x000ffd00000ULL
+#define APB_SPECIAL_BASE     0x1fe00000000ULL
+#define APB_MEM_BASE         0x1ff00000000ULL
+#define APB_PCI_IO_BASE      (APB_SPECIAL_BASE + 0x02000000ULL)
+#define PROM_FILENAME        "openbios-sparc64"
+#define NVRAM_SIZE           0x2000
+#define MAX_IDE_BUS          2
+#define BIOS_CFG_IOPORT      0x510
+#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
+#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
+#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
+
+#define MAX_PILS 16
+
+#define TICK_MAX             0x7fffffffffffffffULL
+
+struct hwdef {
+    const char * const default_cpu_model;
+    uint16_t machine_id;
+    uint64_t prom_addr;
+    uint64_t console_serial_base;
+};
+
+int DMA_get_channel_mode (int nchan)
+{
+    return 0;
+}
+int DMA_read_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+int DMA_write_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+void DMA_hold_DREQ (int nchan) {}
+void DMA_release_DREQ (int nchan) {}
+void DMA_schedule(int nchan) {}
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+}
+
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+{
+    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+    return 0;
+}
+
+static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
+                                  const char *arch, ram_addr_t RAM_size,
+                                  const char *boot_devices,
+                                  uint32_t kernel_image, uint32_t kernel_size,
+                                  const char *cmdline,
+                                  uint32_t initrd_image, uint32_t initrd_size,
+                                  uint32_t NVRAM_image,
+                                  int width, int height, int depth,
+                                  const uint8_t *macaddr)
+{
+    unsigned int i;
+    uint32_t start, end;
+    uint8_t image[0x1ff0];
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    memset(image, '\0', sizeof(image));
+
+    start = 0;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(image, end, prom_envs[i]);
+
+    // End marker
+    image[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = 0x1fd0;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
+
+    for (i = 0; i < sizeof(image); i++)
+        m48t59_write(nvram, i, image[i]);
+
+    return 0;
+}
+static unsigned long sun4u_load_kernel(const char *kernel_filename,
+                                       const char *initrd_filename,
+                                       ram_addr_t RAM_size, long *initrd_size)
+{
+    int linux_boot;
+    unsigned int i;
+    long kernel_size;
+    uint8_t *ptr;
+
+    linux_boot = (kernel_filename != NULL);
+
+    kernel_size = 0;
+    if (linux_boot) {
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
+                               NULL, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0)
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
+        if (kernel_size < 0)
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              RAM_size - KERNEL_LOAD_ADDR);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        *initrd_size = 0;
+        if (initrd_filename) {
+            *initrd_size = load_image_targphys(initrd_filename,
+                                               INITRD_LOAD_ADDR,
+                                               RAM_size - INITRD_LOAD_ADDR);
+            if (*initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        }
+        if (*initrd_size > 0) {
+            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
+                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
+                if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
+                    stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000);
+                    stl_p(ptr + 28, *initrd_size);
+                    break;
+                }
+            }
+        }
+    }
+    return kernel_size;
+}
+
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
+
+void cpu_check_irqs(CPUState *env)
+{
+    uint32_t pil = env->pil_in |
+                  (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
+
+    /* check if TM or SM in SOFTINT are set
+       setting these also causes interrupt 14 */
+    if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
+        pil |= 1 << 14;
+    }
+
+    if (!pil) {
+        if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+            CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
+                           env->interrupt_index);
+            env->interrupt_index = 0;
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+        return;
+    }
+
+    if (cpu_interrupts_enabled(env)) {
+
+        unsigned int i;
+
+        for (i = 15; i > env->psrpil; i--) {
+            if (pil & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+                int new_interrupt = TT_EXTINT | i;
+
+                if (env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt) {
+                    CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
+                                   "current %x >= pending %x\n",
+                                   env->tl, cpu_tsptr(env)->tt, new_interrupt);
+                } else if (old_interrupt != new_interrupt) {
+                    env->interrupt_index = new_interrupt;
+                    CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
+                                   old_interrupt, new_interrupt);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else {
+        CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
+                       "current interrupt %x\n",
+                       pil, env->pil_in, env->softint, env->interrupt_index);
+    }
+}
+
+static void cpu_kick_irq(CPUState *env)
+{
+    env->halted = 0;
+    cpu_check_irqs(env);
+    qemu_cpu_kick(env);
+}
+
+static void cpu_set_irq(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
+        env->pil_in |= 1 << irq;
+        cpu_kick_irq(env);
+    } else {
+        CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
+        env->pil_in &= ~(1 << irq);
+        cpu_check_irqs(env);
+    }
+}
+
+typedef struct ResetData {
+    CPUState *env;
+    uint64_t prom_addr;
+} ResetData;
+
+void cpu_put_timer(QEMUFile *f, CPUTimer *s)
+{
+    qemu_put_be32s(f, &s->frequency);
+    qemu_put_be32s(f, &s->disabled);
+    qemu_put_be64s(f, &s->disabled_mask);
+    qemu_put_sbe64s(f, &s->clock_offset);
+
+    qemu_put_timer(f, s->qtimer);
+}
+
+void cpu_get_timer(QEMUFile *f, CPUTimer *s)
+{
+    qemu_get_be32s(f, &s->frequency);
+    qemu_get_be32s(f, &s->disabled);
+    qemu_get_be64s(f, &s->disabled_mask);
+    qemu_get_sbe64s(f, &s->clock_offset);
+
+    qemu_get_timer(f, s->qtimer);
+}
+
+static CPUTimer* cpu_timer_create(const char* name, CPUState *env,
+                                  QEMUBHFunc *cb, uint32_t frequency,
+                                  uint64_t disabled_mask)
+{
+    CPUTimer *timer = qemu_mallocz(sizeof (CPUTimer));
+
+    timer->name = name;
+    timer->frequency = frequency;
+    timer->disabled_mask = disabled_mask;
+
+    timer->disabled = 1;
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
+
+    timer->qtimer = qemu_new_timer_ns(vm_clock, cb, env);
+
+    return timer;
+}
+
+static void cpu_timer_reset(CPUTimer *timer)
+{
+    timer->disabled = 1;
+    timer->clock_offset = qemu_get_clock_ns(vm_clock);
+
+    qemu_del_timer(timer->qtimer);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    CPUState *env = s->env;
+    static unsigned int nr_resets;
+
+    cpu_reset(env);
+
+    cpu_timer_reset(env->tick);
+    cpu_timer_reset(env->stick);
+    cpu_timer_reset(env->hstick);
+
+    env->gregs[1] = 0; // Memory start
+    env->gregs[2] = ram_size; // Memory size
+    env->gregs[3] = 0; // Machine description XXX
+    if (nr_resets++ == 0) {
+        /* Power on reset */
+        env->pc = s->prom_addr + 0x20ULL;
+    } else {
+        env->pc = s->prom_addr + 0x40ULL;
+    }
+    env->npc = env->pc + 4;
+}
+
+static void tick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    CPUTimer* timer = env->tick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("tick: fire\n");
+    }
+
+    env->softint |= SOFTINT_TIMER;
+    cpu_kick_irq(env);
+}
+
+static void stick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    CPUTimer* timer = env->stick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("stick: fire\n");
+    }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(env);
+}
+
+static void hstick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    CPUTimer* timer = env->hstick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("hstick: fire\n");
+    }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(env);
+}
+
+static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
+{
+    return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency);
+}
+
+static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
+{
+    return muldiv64(timer_ticks, frequency, get_ticks_per_sec());
+}
+
+void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
+{
+    uint64_t real_count = count & ~timer->disabled_mask;
+    uint64_t disabled_bit = count & timer->disabled_mask;
+
+    int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) -
+                    cpu_to_timer_ticks(real_count, timer->frequency);
+
+    TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
+                  timer->name, real_count,
+                  timer->disabled?"disabled":"enabled", timer);
+
+    timer->disabled = disabled_bit ? 1 : 0;
+    timer->clock_offset = vm_clock_offset;
+}
+
+uint64_t cpu_tick_get_count(CPUTimer *timer)
+{
+    uint64_t real_count = timer_to_cpu_ticks(
+                    qemu_get_clock_ns(vm_clock) - timer->clock_offset,
+                    timer->frequency);
+
+    TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
+           timer->name, real_count,
+           timer->disabled?"disabled":"enabled", timer);
+
+    if (timer->disabled)
+        real_count |= timer->disabled_mask;
+
+    return real_count;
+}
+
+void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
+{
+    int64_t now = qemu_get_clock_ns(vm_clock);
+
+    uint64_t real_limit = limit & ~timer->disabled_mask;
+    timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
+
+    int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
+                    timer->clock_offset;
+
+    if (expires < now) {
+        expires = now + 1;
+    }
+
+    TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
+                  "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
+                  timer->name, real_limit,
+                  timer->disabled?"disabled":"enabled",
+                  timer, limit,
+                  timer_to_cpu_ticks(now - timer->clock_offset,
+                                     timer->frequency),
+                  timer_to_cpu_ticks(expires - now, timer->frequency));
+
+    if (!real_limit) {
+        TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
+                timer->name);
+        qemu_del_timer(timer->qtimer);
+    } else if (timer->disabled) {
+        qemu_del_timer(timer->qtimer);
+    } else {
+        qemu_mod_timer(timer->qtimer, expires);
+    }
+}
+
+static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
+                              pcibus_t addr, pcibus_t size, int type)
+{
+    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
+                 region_num, addr);
+    switch (region_num) {
+    case 0:
+        isa_mmio_init(addr, 0x1000000);
+        break;
+    case 1:
+        isa_mmio_init(addr, 0x800000);
+        break;
+    }
+}
+
+static void dummy_isa_irq_handler(void *opaque, int n, int level)
+{
+}
+
+/* EBUS (Eight bit bus) bridge */
+static void
+pci_ebus_init(PCIBus *bus, int devfn)
+{
+    qemu_irq *isa_irq;
+
+    pci_create_simple(bus, devfn, "ebus");
+    isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
+    isa_bus_irqs(isa_irq);
+}
+
+static int
+pci_ebus_init1(PCIDevice *s)
+{
+    isa_bus_new(&s->qdev);
+
+    s->config[0x04] = 0x06; // command = bus master, pci mem
+    s->config[0x05] = 0x00;
+    s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+    s->config[0x07] = 0x03; // status = medium devsel
+    s->config[0x09] = 0x00; // programming i/f
+    s->config[0x0D] = 0x0a; // latency_timer
+
+    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                           ebus_mmio_mapfunc);
+    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
+                           ebus_mmio_mapfunc);
+    return 0;
+}
+
+static PCIDeviceInfo ebus_info = {
+    .qdev.name = "ebus",
+    .qdev.size = sizeof(PCIDevice),
+    .init = pci_ebus_init1,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_EBUS,
+    .revision = 0x01,
+    .class_id = PCI_CLASS_BRIDGE_OTHER,
+};
+
+static void pci_ebus_register(void)
+{
+    pci_qdev_register(&ebus_info);
+}
+
+device_init(pci_ebus_register);
+
+static uint64_t translate_prom_address(void *opaque, uint64_t addr)
+{
+    target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque;
+    return addr + *base_addr - PROM_VADDR;
+}
+
+/* Boot PROM (OpenBIOS) */
+static void prom_init(target_phys_addr_t addr, const char *bios_name)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    char *filename;
+    int ret;
+
+    dev = qdev_create(NULL, "openprom");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+
+    /* load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        ret = load_elf(filename, translate_prom_address, &addr,
+                       NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+        if (ret < 0 || ret > PROM_SIZE_MAX) {
+            ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
+        }
+        qemu_free(filename);
+    } else {
+        ret = -1;
+    }
+    if (ret < 0 || ret > PROM_SIZE_MAX) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
+        exit(1);
+    }
+}
+
+static int prom_init1(SysBusDevice *dev)
+{
+    ram_addr_t prom_offset;
+
+    prom_offset = qemu_ram_alloc(NULL, "sun4u.prom", PROM_SIZE_MAX);
+    sysbus_init_mmio(dev, PROM_SIZE_MAX, prom_offset | IO_MEM_ROM);
+    return 0;
+}
+
+static SysBusDeviceInfo prom_info = {
+    .init = prom_init1,
+    .qdev.name  = "openprom",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.props = (Property[]) {
+        {/* end of property list */}
+    }
+};
+
+static void prom_register_devices(void)
+{
+    sysbus_register_withprop(&prom_info);
+}
+
+device_init(prom_register_devices);
+
+
+typedef struct RamDevice
+{
+    SysBusDevice busdev;
+    uint64_t size;
+} RamDevice;
+
+/* System RAM */
+static int ram_init1(SysBusDevice *dev)
+{
+    ram_addr_t RAM_size, ram_offset;
+    RamDevice *d = FROM_SYSBUS(RamDevice, dev);
+
+    RAM_size = d->size;
+
+    ram_offset = qemu_ram_alloc(NULL, "sun4u.ram", RAM_size);
+    sysbus_init_mmio(dev, RAM_size, ram_offset);
+    return 0;
+}
+
+static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    RamDevice *d;
+
+    /* allocate RAM */
+    dev = qdev_create(NULL, "memory");
+    s = sysbus_from_qdev(dev);
+
+    d = FROM_SYSBUS(RamDevice, s);
+    d->size = RAM_size;
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(s, 0, addr);
+}
+
+static SysBusDeviceInfo ram_info = {
+    .init = ram_init1,
+    .qdev.name  = "memory",
+    .qdev.size  = sizeof(RamDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ram_register_devices(void)
+{
+    sysbus_register_withprop(&ram_info);
+}
+
+device_init(ram_register_devices);
+
+static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
+{
+    CPUState *env;
+    ResetData *reset_info;
+
+    uint32_t   tick_frequency = 100*1000000;
+    uint32_t  stick_frequency = 100*1000000;
+    uint32_t hstick_frequency = 100*1000000;
+
+    if (!cpu_model)
+        cpu_model = hwdef->default_cpu_model;
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    env->tick = cpu_timer_create("tick", env, tick_irq,
+                                  tick_frequency, TICK_NPT_MASK);
+
+    env->stick = cpu_timer_create("stick", env, stick_irq,
+                                   stick_frequency, TICK_INT_DIS);
+
+    env->hstick = cpu_timer_create("hstick", env, hstick_irq,
+                                    hstick_frequency, TICK_INT_DIS);
+
+    reset_info = qemu_mallocz(sizeof(ResetData));
+    reset_info->env = env;
+    reset_info->prom_addr = hwdef->prom_addr;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    return env;
+}
+
+static void sun4uv_init(ram_addr_t RAM_size,
+                        const char *boot_devices,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model,
+                        const struct hwdef *hwdef)
+{
+    CPUState *env;
+    M48t59State *nvram;
+    unsigned int i;
+    long initrd_size, kernel_size;
+    PCIBus *pci_bus, *pci_bus2, *pci_bus3;
+    qemu_irq *irq;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    DriveInfo *fd[MAX_FD];
+    void *fw_cfg;
+
+    /* init CPUs */
+    env = cpu_devinit(cpu_model, hwdef);
+
+    /* set up devices */
+    ram_init(0, RAM_size);
+
+    prom_init(hwdef->prom_addr, bios_name);
+
+
+    irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
+    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
+                           &pci_bus3);
+    isa_mem_base = APB_PCI_IO_BASE;
+    pci_vga_init(pci_bus);
+
+    // XXX Should be pci_bus3
+    pci_ebus_init(pci_bus, -1);
+
+    i = 0;
+    if (hwdef->console_serial_base) {
+        serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
+                       serial_hds[i], 1, 1);
+        i++;
+    }
+    for(; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(i, parallel_hds[i]);
+        }
+    }
+
+    for(i = 0; i < nb_nics; i++)
+        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+
+    ide_drive_get(hd, MAX_IDE_BUS);
+
+    pci_cmd646_ide_init(pci_bus, hd, 1);
+
+    isa_create_simple("i8042");
+    for(i = 0; i < MAX_FD; i++) {
+        fd[i] = drive_get(IF_FLOPPY, 0, i);
+    }
+    fdctrl_init_isa(fd);
+    nvram = m48t59_init_isa(0x0074, NVRAM_SIZE, 59);
+
+    initrd_size = 0;
+    kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
+                                    ram_size, &initrd_size);
+
+    sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
+                           KERNEL_LOAD_ADDR, kernel_size,
+                           kernel_cmdline,
+                           INITRD_LOAD_ADDR, initrd_size,
+                           /* XXX: need an option to load a NVRAM image */
+                           0,
+                           graphic_width, graphic_height, graphic_depth,
+                           (uint8_t *)&nd_table[0].macaddr);
+
+    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+    if (kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(kernel_cmdline) + 1);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
+                         (uint8_t*)strdup(kernel_cmdline),
+                         strlen(kernel_cmdline) + 1);
+    } else {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
+    }
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
+
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth);
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+enum {
+    sun4u_id = 0,
+    sun4v_id = 64,
+    niagara_id,
+};
+
+static const struct hwdef hwdefs[] = {
+    /* Sun4u generic PC-like machine */
+    {
+        .default_cpu_model = "TI UltraSparc IIi",
+        .machine_id = sun4u_id,
+        .prom_addr = 0x1fff0000000ULL,
+        .console_serial_base = 0,
+    },
+    /* Sun4v generic PC-like machine */
+    {
+        .default_cpu_model = "Sun UltraSparc T1",
+        .machine_id = sun4v_id,
+        .prom_addr = 0x1fff0000000ULL,
+        .console_serial_base = 0,
+    },
+    /* Sun4v generic Niagara machine */
+    {
+        .default_cpu_model = "Sun UltraSparc T1",
+        .machine_id = niagara_id,
+        .prom_addr = 0xfff0000000ULL,
+        .console_serial_base = 0xfff0c2c000ULL,
+    },
+};
+
+/* Sun4u hardware initialisation */
+static void sun4u_init(ram_addr_t RAM_size,
+                       const char *boot_devices,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
+}
+
+/* Sun4v hardware initialisation */
+static void sun4v_init(ram_addr_t RAM_size,
+                       const char *boot_devices,
+                       const char *kernel_filename, const char *kernel_cmdline,
+                       const char *initrd_filename, const char *cpu_model)
+{
+    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
+}
+
+/* Niagara hardware initialisation */
+static void niagara_init(ram_addr_t RAM_size,
+                         const char *boot_devices,
+                         const char *kernel_filename, const char *kernel_cmdline,
+                         const char *initrd_filename, const char *cpu_model)
+{
+    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
+}
+
+static QEMUMachine sun4u_machine = {
+    .name = "sun4u",
+    .desc = "Sun4u platform",
+    .init = sun4u_init,
+    .max_cpus = 1, // XXX for now
+    .is_default = 1,
+};
+
+static QEMUMachine sun4v_machine = {
+    .name = "sun4v",
+    .desc = "Sun4v platform",
+    .init = sun4v_init,
+    .max_cpus = 1, // XXX for now
+};
+
+static QEMUMachine niagara_machine = {
+    .name = "Niagara",
+    .desc = "Sun4v platform, Niagara",
+    .init = niagara_init,
+    .max_cpus = 1, // XXX for now
+};
+
+static void sun4u_machine_init(void)
+{
+    qemu_register_machine(&sun4u_machine);
+    qemu_register_machine(&sun4v_machine);
+    qemu_register_machine(&niagara_machine);
+}
+
+machine_init(sun4u_machine_init);
diff --git a/qemu-0.15.x/hw/syborg.c b/qemu-0.15.x/hw/syborg.c
new file mode 100644
index 0000000..bc200e4
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg.c
@@ -0,0 +1,111 @@
+/*
+ * Syborg (Symbian Virtual Platform) reference board
+ *
+ * Copyright (c) 2009 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 "sysbus.h"
+#include "boards.h"
+#include "arm-misc.h"
+#include "net.h"
+
+static struct arm_boot_info syborg_binfo;
+
+static void syborg_init(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    qemu_irq *cpu_pic;
+    qemu_irq pic[64];
+    ram_addr_t ram_addr;
+    DeviceState *dev;
+    int i;
+
+    if (!cpu_model)
+        cpu_model = "cortex-a8";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    /* RAM at address zero. */
+    ram_addr = qemu_ram_alloc(NULL, "syborg.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM);
+
+    cpu_pic = arm_pic_init_cpu(env);
+    dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
+                               cpu_pic[ARM_PIC_CPU_IRQ]);
+    for (i = 0; i < 64; i++) {
+        pic[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    sysbus_create_simple("syborg,rtc", 0xC0001000, NULL);
+
+    dev = qdev_create(NULL, "syborg,timer");
+    qdev_prop_set_uint32(dev, "frequency", 1000000);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xC0002000);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[1]);
+
+    sysbus_create_simple("syborg,keyboard", 0xC0003000, pic[2]);
+    sysbus_create_simple("syborg,pointer", 0xC0004000, pic[3]);
+    sysbus_create_simple("syborg,framebuffer", 0xC0005000, pic[4]);
+    sysbus_create_simple("syborg,serial", 0xC0006000, pic[5]);
+    sysbus_create_simple("syborg,serial", 0xC0007000, pic[6]);
+    sysbus_create_simple("syborg,serial", 0xC0008000, pic[7]);
+    sysbus_create_simple("syborg,serial", 0xC0009000, pic[8]);
+
+    if (nd_table[0].vlan || nd_table[0].netdev) {
+        DeviceState *dev;
+        SysBusDevice *s;
+
+        qemu_check_nic_model(&nd_table[0], "virtio");
+        dev = qdev_create(NULL, "syborg,virtio-net");
+        qdev_set_nic_properties(dev, &nd_table[0]);
+        qdev_init_nofail(dev);
+        s = sysbus_from_qdev(dev);
+        sysbus_mmio_map(s, 0, 0xc000c000);
+        sysbus_connect_irq(s, 0, pic[9]);
+    }
+
+    syborg_binfo.ram_size = ram_size;
+    syborg_binfo.kernel_filename = kernel_filename;
+    syborg_binfo.kernel_cmdline = kernel_cmdline;
+    syborg_binfo.initrd_filename = initrd_filename;
+    syborg_binfo.board_id = 0;
+    arm_load_kernel(env, &syborg_binfo);
+}
+
+static QEMUMachine syborg_machine = {
+    .name = "syborg",
+    .desc = "Syborg (Symbian Virtual Platform)",
+    .init = syborg_init,
+};
+
+static void syborg_machine_init(void)
+{
+    qemu_register_machine(&syborg_machine);
+}
+
+machine_init(syborg_machine_init);
diff --git a/qemu-0.15.x/hw/syborg.h b/qemu-0.15.x/hw/syborg.h
new file mode 100644
index 0000000..b82ce4a
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg.h
@@ -0,0 +1,18 @@
+#ifndef _SYBORG_H
+#define _SYBORG_H
+
+#define SYBORG_ID_PLATFORM    0xc51d1000
+#define SYBORG_ID_INT         0xc51d0000
+#define SYBORG_ID_SERIAL      0xc51d0001
+#define SYBORG_ID_KEYBOARD    0xc51d0002
+#define SYBORG_ID_TIMER       0xc51d0003
+#define SYBORG_ID_RTC         0xc51d0004
+#define SYBORG_ID_MOUSE       0xc51d0005
+#define SYBORG_ID_TOUCHSCREEN 0xc51d0006
+#define SYBORG_ID_FRAMEBUFFER 0xc51d0007
+#define SYBORG_ID_HOSTFS      0xc51d0008
+#define SYBORG_ID_SNAPSHOT    0xc51d0009
+#define SYBORG_ID_VIRTIO      0xc51d000a
+#define SYBORG_ID_NAND        0xc51d000b
+
+#endif
diff --git a/qemu-0.15.x/hw/syborg_fb.c b/qemu-0.15.x/hw/syborg_fb.c
new file mode 100644
index 0000000..7e37364
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_fb.c
@@ -0,0 +1,551 @@
+/*
+ * Syborg Framebuffer
+ *
+ * Copyright (c) 2009 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 "sysbus.h"
+#include "console.h"
+#include "syborg.h"
+#include "framebuffer.h"
+
+//#define DEBUG_SYBORG_FB
+
+#ifdef DEBUG_SYBORG_FB
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    FB_ID               = 0,
+    FB_BASE             = 1,
+    FB_HEIGHT           = 2,
+    FB_WIDTH            = 3,
+    FB_ORIENTATION      = 4,
+    FB_BLANK            = 5,
+    FB_INT_MASK         = 6,
+    FB_INTERRUPT_CAUSE  = 7,
+    FB_BPP              = 8,
+    FB_COLOR_ORDER      = 9,
+    FB_BYTE_ORDER       = 10,
+    FB_PIXEL_ORDER      = 11,
+    FB_ROW_PITCH        = 12,
+    FB_ENABLED          = 13,
+    FB_PALETTE_START    = 0x400 >> 2,
+    FB_PALETTE_END   = FB_PALETTE_START+256-1,
+};
+
+#define FB_INT_VSYNC            (1U << 0)
+#define FB_INT_BASE_UPDATE_DONE (1U << 1)
+
+typedef struct {
+    SysBusDevice busdev;
+    DisplayState *ds;
+    /*QEMUConsole *console;*/
+    uint32_t need_update : 1;
+    uint32_t need_int : 1;
+    uint32_t enabled : 1;
+    uint32_t int_status;
+    uint32_t int_enable;
+    qemu_irq irq;
+
+    uint32_t base;
+    uint32_t pitch;
+    uint32_t rows;
+    uint32_t cols;
+    int blank;
+    int bpp;
+    int rgb; /* 0 = BGR, 1 = RGB */
+    int endian; /* 0 = Little, 1 = Big */
+    uint32_t raw_palette[256];
+    uint32_t palette[256];
+} SyborgFBState;
+
+enum {
+    BPP_SRC_1,
+    BPP_SRC_2,
+    BPP_SRC_4,
+    BPP_SRC_8,
+    BPP_SRC_16,
+    BPP_SRC_32,
+    /* TODO: Implement these.  */
+    BPP_SRC_15 = -1,
+    BPP_SRC_24 = -2
+};
+
+#include "pixel_ops.h"
+
+#define BITS 8
+#include "pl110_template.h"
+#define BITS 15
+#include "pl110_template.h"
+#define BITS 16
+#include "pl110_template.h"
+#define BITS 24
+#include "pl110_template.h"
+#define BITS 32
+#include "pl110_template.h"
+
+/* Update interrupts.  */
+static void syborg_fb_update(SyborgFBState *s)
+{
+    if ((s->int_status & s->int_enable) != 0) {
+        DPRINTF("Raise IRQ\n");
+        qemu_irq_raise(s->irq);
+    } else {
+        DPRINTF("Lower IRQ\n");
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static int syborg_fb_enabled(const SyborgFBState *s)
+{
+    return s->enabled;
+}
+
+static void syborg_fb_update_palette(SyborgFBState *s)
+{
+    int n, i;
+    uint32_t raw;
+    unsigned int r, g, b;
+
+    switch (s->bpp) {
+    case BPP_SRC_1: n = 2; break;
+    case BPP_SRC_2: n = 4; break;
+    case BPP_SRC_4: n = 16; break;
+    case BPP_SRC_8: n = 256; break;
+    default: return;
+    }
+
+    for (i = 0; i < n; i++) {
+        raw = s->raw_palette[i];
+        r = (raw >> 16) & 0xff;
+        g = (raw >> 8) & 0xff;
+        b = raw & 0xff;
+        switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            s->palette[i] = rgb_to_pixel8(r, g, b);
+            break;
+        case 15:
+            s->palette[i] = rgb_to_pixel15(r, g, b);
+            break;
+        case 16:
+            s->palette[i] = rgb_to_pixel16(r, g, b);
+            break;
+        case 24:
+        case 32:
+            s->palette[i] = rgb_to_pixel32(r, g, b);
+            break;
+        default:
+            abort();
+        }
+    }
+
+}
+
+static void syborg_fb_update_display(void *opaque)
+{
+    SyborgFBState *s = (SyborgFBState *)opaque;
+    drawfn* fntable;
+    drawfn fn;
+    int dest_width;
+    int src_width;
+    int bpp_offset;
+    int first;
+    int last;
+
+    if (!syborg_fb_enabled(s))
+        return;
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 8:
+        fntable = pl110_draw_fn_8;
+        dest_width = 1;
+        break;
+    case 15:
+        fntable = pl110_draw_fn_15;
+        dest_width = 2;
+        break;
+    case 16:
+        fntable = pl110_draw_fn_16;
+        dest_width = 2;
+        break;
+    case 24:
+        fntable = pl110_draw_fn_24;
+        dest_width = 3;
+        break;
+    case 32:
+        fntable = pl110_draw_fn_32;
+        dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "syborg_fb: Bad color depth\n");
+        exit(1);
+    }
+
+    if (s->need_int) {
+        s->int_status |= FB_INT_BASE_UPDATE_DONE;
+        syborg_fb_update(s);
+        s->need_int = 0;
+    }
+
+    if (s->rgb) {
+        bpp_offset = 18;
+    } else {
+        bpp_offset = 0;
+    }
+    if (s->endian) {
+        bpp_offset += 6;
+    }
+
+    fn = fntable[s->bpp + bpp_offset];
+
+    if (s->pitch) {
+        src_width = s->pitch;
+    } else {
+        src_width = s->cols;
+        switch (s->bpp) {
+        case BPP_SRC_1:
+            src_width >>= 3;
+            break;
+        case BPP_SRC_2:
+            src_width >>= 2;
+            break;
+        case BPP_SRC_4:
+            src_width >>= 1;
+            break;
+        case BPP_SRC_8:
+            break;
+        case BPP_SRC_15:
+        case BPP_SRC_16:
+            src_width <<= 1;
+            break;
+        case BPP_SRC_24:
+            src_width *= 3;
+            break;
+        case BPP_SRC_32:
+            src_width <<= 2;
+            break;
+        }
+    }
+    dest_width *= s->cols;
+    first = 0;
+    /* TODO: Implement blanking.  */
+    if (!s->blank) {
+        if (s->need_update && s->bpp <= BPP_SRC_8) {
+            syborg_fb_update_palette(s);
+        }
+        framebuffer_update_display(s->ds,
+                                   s->base, s->cols, s->rows,
+                                   src_width, dest_width, 0,
+                                   s->need_update,
+                                   fn, s->palette,
+                                   &first, &last);
+        if (first >= 0) {
+            dpy_update(s->ds, 0, first, s->cols, last - first + 1);
+        }
+
+        s->int_status |= FB_INT_VSYNC;
+        syborg_fb_update(s);
+    }
+
+    s->need_update = 0;
+}
+
+static void syborg_fb_invalidate_display(void * opaque)
+{
+    SyborgFBState *s = (SyborgFBState *)opaque;
+    s->need_update = 1;
+}
+
+static uint32_t syborg_fb_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgFBState *s = opaque;
+
+    DPRINTF("read reg %d\n", (int)offset);
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case FB_ID:
+        return SYBORG_ID_FRAMEBUFFER;
+
+    case FB_BASE:
+        return s->base;
+
+    case FB_HEIGHT:
+        return s->rows;
+
+    case FB_WIDTH:
+        return s->cols;
+
+    case FB_ORIENTATION:
+        return 0;
+
+    case FB_BLANK:
+        return s->blank;
+
+    case FB_INT_MASK:
+        return s->int_enable;
+
+    case FB_INTERRUPT_CAUSE:
+        return s->int_status;
+
+    case FB_BPP:
+        switch (s->bpp) {
+        case BPP_SRC_1: return 1;
+        case BPP_SRC_2: return 2;
+        case BPP_SRC_4: return 4;
+        case BPP_SRC_8: return 8;
+        case BPP_SRC_15: return 15;
+        case BPP_SRC_16: return 16;
+        case BPP_SRC_24: return 24;
+        case BPP_SRC_32: return 32;
+        default: return 0;
+        }
+
+    case FB_COLOR_ORDER:
+        return s->rgb;
+
+    case FB_BYTE_ORDER:
+        return s->endian;
+
+    case FB_PIXEL_ORDER:
+        return 0;
+
+    case FB_ROW_PITCH:
+        return s->pitch;
+
+    case FB_ENABLED:
+        return s->enabled;
+
+    default:
+        if ((offset >> 2) >= FB_PALETTE_START
+            && (offset >> 2) <= FB_PALETTE_END) {
+            return s->raw_palette[(offset >> 2) - FB_PALETTE_START];
+        } else {
+            cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
+                         (int)offset);
+        }
+        return 0;
+    }
+}
+
+static void syborg_fb_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t val)
+{
+    SyborgFBState *s = opaque;
+
+    DPRINTF("write reg %d = %d\n", (int)offset, val);
+    s->need_update = 1;
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case FB_BASE:
+        s->base = val;
+        s->need_int = 1;
+        s->need_update = 1;
+        syborg_fb_update(s);
+        break;
+
+    case FB_HEIGHT:
+        s->rows = val;
+        break;
+
+    case FB_WIDTH:
+        s->cols = val;
+        break;
+
+    case FB_ORIENTATION:
+        /* TODO: Implement rotation.  */
+        break;
+
+    case FB_BLANK:
+        s->blank = val & 1;
+        break;
+
+    case FB_INT_MASK:
+        s->int_enable = val;
+        syborg_fb_update(s);
+        break;
+
+    case FB_INTERRUPT_CAUSE:
+        s->int_status &= ~val;
+        syborg_fb_update(s);
+        break;
+
+    case FB_BPP:
+        switch (val) {
+        case 1: val = BPP_SRC_1; break;
+        case 2: val = BPP_SRC_2; break;
+        case 4: val = BPP_SRC_4; break;
+        case 8: val = BPP_SRC_8; break;
+        /* case 15: val = BPP_SRC_15; break; */
+        case 16: val = BPP_SRC_16; break;
+        /* case 24: val = BPP_SRC_24; break; */
+        case 32: val = BPP_SRC_32; break;
+        default: val = s->bpp; break;
+        }
+        s->bpp = val;
+        break;
+
+    case FB_COLOR_ORDER:
+        s->rgb = (val != 0);
+        break;
+
+    case FB_BYTE_ORDER:
+        s->endian = (val != 0);
+        break;
+
+    case FB_PIXEL_ORDER:
+        /* TODO: Implement this.  */
+        break;
+
+    case FB_ROW_PITCH:
+        s->pitch = val;
+        break;
+
+    case FB_ENABLED:
+        s->enabled = val;
+        break;
+
+    default:
+        if ((offset >> 2) >= FB_PALETTE_START
+            && (offset >> 2) <= FB_PALETTE_END) {
+            s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
+        } else {
+            cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
+                      (int)offset);
+        }
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const syborg_fb_readfn[] = {
+    syborg_fb_read,
+    syborg_fb_read,
+    syborg_fb_read
+};
+
+static CPUWriteMemoryFunc * const syborg_fb_writefn[] = {
+    syborg_fb_write,
+    syborg_fb_write,
+    syborg_fb_write
+};
+
+static void syborg_fb_save(QEMUFile *f, void *opaque)
+{
+    SyborgFBState *s = opaque;
+    int i;
+
+    qemu_put_be32(f, s->need_int);
+    qemu_put_be32(f, s->int_status);
+    qemu_put_be32(f, s->int_enable);
+    qemu_put_be32(f, s->enabled);
+    qemu_put_be32(f, s->base);
+    qemu_put_be32(f, s->pitch);
+    qemu_put_be32(f, s->rows);
+    qemu_put_be32(f, s->cols);
+    qemu_put_be32(f, s->bpp);
+    qemu_put_be32(f, s->rgb);
+    for (i = 0; i < 256; i++) {
+        qemu_put_be32(f, s->raw_palette[i]);
+    }
+}
+
+static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SyborgFBState *s = opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->need_int = qemu_get_be32(f);
+    s->int_status = qemu_get_be32(f);
+    s->int_enable = qemu_get_be32(f);
+    s->enabled = qemu_get_be32(f);
+    s->base = qemu_get_be32(f);
+    s->pitch = qemu_get_be32(f);
+    s->rows = qemu_get_be32(f);
+    s->cols = qemu_get_be32(f);
+    s->bpp = qemu_get_be32(f);
+    s->rgb = qemu_get_be32(f);
+    for (i = 0; i < 256; i++) {
+        s->raw_palette[i] = qemu_get_be32(f);
+    }
+    s->need_update = 1;
+
+    return 0;
+}
+
+static int syborg_fb_init(SysBusDevice *dev)
+{
+    SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+    iomemtype = cpu_register_io_memory(syborg_fb_readfn,
+                                       syborg_fb_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    s->ds = graphic_console_init(syborg_fb_update_display,
+                                 syborg_fb_invalidate_display,
+                                 NULL, NULL, s);
+
+    if (s->cols != 0 && s->rows != 0) {
+        qemu_console_resize(s->ds, s->cols, s->rows);
+    }
+
+    if (!s->cols)
+        s->cols = ds_get_width(s->ds);
+    if (!s->rows)
+        s->rows = ds_get_height(s->ds);
+
+    register_savevm(&dev->qdev, "syborg_framebuffer", -1, 1,
+                    syborg_fb_save, syborg_fb_load, s);
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_fb_info = {
+    .init = syborg_fb_init,
+    .qdev.name  = "syborg,framebuffer",
+    .qdev.size  = sizeof(SyborgFBState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("width",  SyborgFBState, cols, 0),
+        DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_fb_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_fb_info);
+}
+
+device_init(syborg_fb_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_interrupt.c b/qemu-0.15.x/hw/syborg_interrupt.c
new file mode 100644
index 0000000..5217983
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_interrupt.c
@@ -0,0 +1,238 @@
+/*
+ * Syborg interrupt controller.
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "syborg.h"
+
+//#define DEBUG_SYBORG_INT
+
+#ifdef DEBUG_SYBORG_INT
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+enum {
+    INT_ID            = 0,
+    INT_STATUS        = 1, /* number of pending interrupts */
+    INT_CURRENT       = 2, /* next interrupt to be serviced */
+    INT_DISABLE_ALL   = 3,
+    INT_DISABLE       = 4,
+    INT_ENABLE        = 5,
+    INT_TOTAL         = 6
+};
+
+typedef struct {
+    unsigned level:1;
+    unsigned enabled:1;
+} syborg_int_flags;
+
+typedef struct {
+    SysBusDevice busdev;
+    int pending_count;
+    uint32_t num_irqs;
+    syborg_int_flags *flags;
+    qemu_irq parent_irq;
+} SyborgIntState;
+
+static void syborg_int_update(SyborgIntState *s)
+{
+    DPRINTF("pending %d\n", s->pending_count);
+    qemu_set_irq(s->parent_irq, s->pending_count > 0);
+}
+
+static void syborg_int_set_irq(void *opaque, int irq, int level)
+{
+    SyborgIntState *s = (SyborgIntState *)opaque;
+
+    if (s->flags[irq].level == level)
+        return;
+
+    s->flags[irq].level = level;
+    if (s->flags[irq].enabled) {
+        if (level)
+            s->pending_count++;
+        else
+            s->pending_count--;
+        syborg_int_update(s);
+    }
+}
+
+static uint32_t syborg_int_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgIntState *s = (SyborgIntState *)opaque;
+    int i;
+
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case INT_ID:
+        return SYBORG_ID_INT;
+    case INT_STATUS:
+        DPRINTF("read status=%d\n", s->pending_count);
+        return s->pending_count;
+
+    case INT_CURRENT:
+        for (i = 0; i < s->num_irqs; i++) {
+            if (s->flags[i].level & s->flags[i].enabled) {
+                DPRINTF("read current=%d\n", i);
+                return i;
+            }
+        }
+        DPRINTF("read current=none\n");
+        return 0xffffffffu;
+
+    default:
+        cpu_abort(cpu_single_env, "syborg_int_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_int_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+    SyborgIntState *s = (SyborgIntState *)opaque;
+    int i;
+    offset &= 0xfff;
+
+    DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value);
+    switch (offset >> 2) {
+    case INT_DISABLE_ALL:
+        s->pending_count = 0;
+        for (i = 0; i < s->num_irqs; i++)
+            s->flags[i].enabled = 0;
+        break;
+
+    case INT_DISABLE:
+        if (value >= s->num_irqs)
+            break;
+        if (s->flags[value].enabled) {
+            if (s->flags[value].enabled)
+                s->pending_count--;
+            s->flags[value].enabled = 0;
+        }
+        break;
+
+    case INT_ENABLE:
+      if (value >= s->num_irqs)
+          break;
+      if (!(s->flags[value].enabled)) {
+          if(s->flags[value].level)
+              s->pending_count++;
+          s->flags[value].enabled = 1;
+      }
+      break;
+
+    default:
+        cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n",
+                  (int)offset);
+        return;
+    }
+    syborg_int_update(s);
+}
+
+static CPUReadMemoryFunc * const syborg_int_readfn[] = {
+    syborg_int_read,
+    syborg_int_read,
+    syborg_int_read
+};
+
+static CPUWriteMemoryFunc * const syborg_int_writefn[] = {
+    syborg_int_write,
+    syborg_int_write,
+    syborg_int_write
+};
+
+static void syborg_int_save(QEMUFile *f, void *opaque)
+{
+    SyborgIntState *s = (SyborgIntState *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->num_irqs);
+    qemu_put_be32(f, s->pending_count);
+    for (i = 0; i < s->num_irqs; i++) {
+        qemu_put_be32(f, s->flags[i].enabled
+                         | ((unsigned)s->flags[i].level << 1));
+    }
+}
+
+static int syborg_int_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SyborgIntState *s = (SyborgIntState *)opaque;
+    uint32_t val;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    val = qemu_get_be32(f);
+    if (val != s->num_irqs)
+        return -EINVAL;
+    s->pending_count = qemu_get_be32(f);
+    for (i = 0; i < s->num_irqs; i++) {
+        val = qemu_get_be32(f);
+        s->flags[i].enabled = val & 1;
+        s->flags[i].level = (val >> 1) & 1;
+    }
+    return 0;
+}
+
+static int syborg_int_init(SysBusDevice *dev)
+{
+    SyborgIntState *s = FROM_SYSBUS(SyborgIntState, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->parent_irq);
+    qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
+    iomemtype = cpu_register_io_memory(syborg_int_readfn,
+                                       syborg_int_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags));
+
+    register_savevm(&dev->qdev, "syborg_int", -1, 1, syborg_int_save,
+                    syborg_int_load, s);
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_int_info = {
+    .init = syborg_int_init,
+    .qdev.name  = "syborg,interrupt",
+    .qdev.size  = sizeof(SyborgIntState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-interrupts", SyborgIntState, num_irqs, 64),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_interrupt_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_int_info);
+}
+
+device_init(syborg_interrupt_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_keyboard.c b/qemu-0.15.x/hw/syborg_keyboard.c
new file mode 100644
index 0000000..706a039
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_keyboard.c
@@ -0,0 +1,221 @@
+/*
+ * Syborg keyboard controller.
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "console.h"
+#include "syborg.h"
+
+//#define DEBUG_SYBORG_KEYBOARD
+
+#ifdef DEBUG_SYBORG_KEYBOARD
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_keyboard: " fmt , ##args); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
+} while (0)
+#endif
+
+enum {
+    KBD_ID          = 0,
+    KBD_DATA        = 1,
+    KBD_FIFO_COUNT  = 2,
+    KBD_INT_ENABLE  = 3,
+    KBD_FIFO_SIZE   = 4
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t int_enabled;
+    int extension_bit;
+    uint32_t fifo_size;
+    uint32_t *key_fifo;
+    uint32_t read_pos, read_count;
+    qemu_irq irq;
+} SyborgKeyboardState;
+
+static void syborg_keyboard_update(SyborgKeyboardState *s)
+{
+    int level = s->read_count && s->int_enabled;
+    DPRINTF("Update IRQ %d\n", level);
+    qemu_set_irq(s->irq, level);
+}
+
+static uint32_t syborg_keyboard_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
+    int c;
+
+    DPRINTF("reg read %d\n", (int)offset);
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case KBD_ID:
+        return SYBORG_ID_KEYBOARD;
+    case KBD_FIFO_COUNT:
+        return s->read_count;
+    case KBD_DATA:
+        if (s->read_count == 0) {
+            c = -1;
+            DPRINTF("FIFO underflow\n");
+        } else {
+            c = s->key_fifo[s->read_pos];
+            DPRINTF("FIFO read 0x%x\n", c);
+            s->read_count--;
+            s->read_pos++;
+            if (s->read_pos == s->fifo_size)
+                s->read_pos = 0;
+        }
+        syborg_keyboard_update(s);
+        return c;
+    case KBD_INT_ENABLE:
+        return s->int_enabled;
+    case KBD_FIFO_SIZE:
+        return s->fifo_size;
+    default:
+        cpu_abort(cpu_single_env, "syborg_keyboard_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset,
+                                  uint32_t value)
+{
+    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
+
+    DPRINTF("reg write %d\n", (int)offset);
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case KBD_INT_ENABLE:
+        s->int_enabled = value;
+        syborg_keyboard_update(s);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n",
+                  (int)offset);
+    }
+}
+
+static CPUReadMemoryFunc * const syborg_keyboard_readfn[] = {
+     syborg_keyboard_read,
+     syborg_keyboard_read,
+     syborg_keyboard_read
+};
+
+static CPUWriteMemoryFunc * const syborg_keyboard_writefn[] = {
+     syborg_keyboard_write,
+     syborg_keyboard_write,
+     syborg_keyboard_write
+};
+
+static void syborg_keyboard_event(void *opaque, int keycode)
+{
+    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
+    int slot;
+    uint32_t val;
+
+    /* Strip off 0xe0 prefixes and reconstruct the full scancode.  */
+    if (keycode == 0xe0 && !s->extension_bit) {
+        DPRINTF("Extension bit\n");
+        s->extension_bit = 0x80;
+        return;
+    }
+    val = (keycode & 0x7f) | s->extension_bit;
+    if (keycode & 0x80)
+        val |= 0x80000000u;
+    s->extension_bit = 0;
+
+    DPRINTF("FIFO push 0x%x\n", val);
+    slot = s->read_pos + s->read_count;
+    if (slot >= s->fifo_size)
+        slot -= s->fifo_size;
+
+    if (s->read_count < s->fifo_size) {
+        s->read_count++;
+        s->key_fifo[slot] = val;
+    } else {
+        fprintf(stderr, "syborg_keyboard error! FIFO overflow\n");
+    }
+
+    syborg_keyboard_update(s);
+}
+
+static const VMStateDescription vmstate_syborg_keyboard = {
+    .name = "syborg_keyboard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState),
+        VMSTATE_UINT32(int_enabled, SyborgKeyboardState),
+        VMSTATE_UINT32(read_pos, SyborgKeyboardState),
+        VMSTATE_UINT32(read_count, SyborgKeyboardState),
+        VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1,
+                              vmstate_info_uint32, uint32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int syborg_keyboard_init(SysBusDevice *dev)
+{
+    SyborgKeyboardState *s = FROM_SYSBUS(SyborgKeyboardState, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+    iomemtype = cpu_register_io_memory(syborg_keyboard_readfn,
+                                       syborg_keyboard_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    if (s->fifo_size <= 0) {
+        fprintf(stderr, "syborg_keyboard: fifo too small\n");
+        s->fifo_size = 16;
+    }
+    s->key_fifo = qemu_mallocz(s->fifo_size * sizeof(s->key_fifo[0]));
+
+    qemu_add_kbd_event_handler(syborg_keyboard_event, s);
+
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s);
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_keyboard_info = {
+    .init = syborg_keyboard_init,
+    .qdev.name  = "syborg,keyboard",
+    .qdev.size  = sizeof(SyborgKeyboardState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fifo-size", SyborgKeyboardState, fifo_size, 16),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_keyboard_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_keyboard_info);
+}
+
+device_init(syborg_keyboard_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_pointer.c b/qemu-0.15.x/hw/syborg_pointer.c
new file mode 100644
index 0000000..2f99707
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_pointer.c
@@ -0,0 +1,226 @@
+/*
+ * Syborg pointing device (mouse/touchscreen)
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "console.h"
+#include "syborg.h"
+
+enum {
+    POINTER_ID          = 0,
+    POINTER_LATCH       = 1,
+    POINTER_FIFO_COUNT  = 2,
+    POINTER_X           = 3,
+    POINTER_Y           = 4,
+    POINTER_Z           = 5,
+    POINTER_BUTTONS     = 6,
+    POINTER_INT_ENABLE  = 7,
+    POINTER_FIFO_SIZE   = 8
+};
+
+typedef struct {
+    int x, y, z, pointer_buttons;
+} event_data;
+
+typedef struct {
+    SysBusDevice busdev;
+    int int_enabled;
+    uint32_t fifo_size;
+    event_data *event_fifo;
+    int read_pos, read_count;
+    qemu_irq irq;
+    uint32_t absolute;
+} SyborgPointerState;
+
+static void syborg_pointer_update(SyborgPointerState *s)
+{
+    qemu_set_irq(s->irq, s->read_count && s->int_enabled);
+}
+
+static uint32_t syborg_pointer_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgPointerState *s = (SyborgPointerState *)opaque;
+
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case POINTER_ID:
+        return s->absolute ? SYBORG_ID_TOUCHSCREEN : SYBORG_ID_MOUSE;
+    case POINTER_FIFO_COUNT:
+        return s->read_count;
+    case POINTER_X:
+        return s->event_fifo[s->read_pos].x;
+    case POINTER_Y:
+        return s->event_fifo[s->read_pos].y;
+    case POINTER_Z:
+        return s->event_fifo[s->read_pos].z;
+    case POINTER_BUTTONS:
+        return s->event_fifo[s->read_pos].pointer_buttons;
+    case POINTER_INT_ENABLE:
+        return s->int_enabled;
+    case POINTER_FIFO_SIZE:
+        return s->fifo_size;
+    default:
+        cpu_abort(cpu_single_env, "syborg_pointer_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_pointer_write(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+    SyborgPointerState *s = (SyborgPointerState *)opaque;
+
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case POINTER_LATCH:
+        if (s->read_count > 0) {
+            s->read_count--;
+            if (++s->read_pos == s->fifo_size)
+                s->read_pos = 0;
+        }
+        break;
+    case POINTER_INT_ENABLE:
+        s->int_enabled = value;
+        break;
+    default:
+        cpu_abort(cpu_single_env, "syborg_pointer_write: Bad offset %x\n",
+                  (int)offset);
+    }
+    syborg_pointer_update(s);
+}
+
+static CPUReadMemoryFunc * const syborg_pointer_readfn[] = {
+   syborg_pointer_read,
+   syborg_pointer_read,
+   syborg_pointer_read
+};
+
+static CPUWriteMemoryFunc * const syborg_pointer_writefn[] = {
+   syborg_pointer_write,
+   syborg_pointer_write,
+   syborg_pointer_write
+};
+
+static void syborg_pointer_event(void *opaque, int dx, int dy, int dz,
+                                 int buttons_state)
+{
+    SyborgPointerState *s = (SyborgPointerState *)opaque;
+    int slot = s->read_pos + s->read_count;
+
+    /* This first FIFO entry is used to store current register state.  */
+    if (s->read_count < s->fifo_size - 1) {
+        s->read_count++;
+        slot++;
+    }
+
+    if (slot >= s->fifo_size)
+          slot -= s->fifo_size;
+
+    if (s->read_count == s->fifo_size && !s->absolute) {
+        /* Merge existing entries.  */
+        s->event_fifo[slot].x += dx;
+        s->event_fifo[slot].y += dy;
+        s->event_fifo[slot].z += dz;
+    } else {
+        s->event_fifo[slot].x = dx;
+        s->event_fifo[slot].y = dy;
+        s->event_fifo[slot].z = dz;
+    }
+    s->event_fifo[slot].pointer_buttons = buttons_state;
+
+    syborg_pointer_update(s);
+}
+
+static const VMStateDescription vmstate_event_data = {
+    .name = "dbma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(x, event_data),
+        VMSTATE_INT32(y, event_data),
+        VMSTATE_INT32(z, event_data),
+        VMSTATE_INT32(pointer_buttons, event_data),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_syborg_pointer = {
+    .name = "syborg_pointer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState),
+        VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState),
+        VMSTATE_INT32(int_enabled, SyborgPointerState),
+        VMSTATE_INT32(read_pos, SyborgPointerState),
+        VMSTATE_INT32(read_count, SyborgPointerState),
+        VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size,
+                                     1, vmstate_event_data, event_data),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int syborg_pointer_init(SysBusDevice *dev)
+{
+    SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+    iomemtype = cpu_register_io_memory(syborg_pointer_readfn,
+				       syborg_pointer_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    if (s->fifo_size <= 0) {
+        fprintf(stderr, "syborg_pointer: fifo too small\n");
+        s->fifo_size = 16;
+    }
+    s->event_fifo = qemu_mallocz(s->fifo_size * sizeof(s->event_fifo[0]));
+
+    qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
+                                 "Syborg Pointer");
+
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s);
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_pointer_info = {
+    .init = syborg_pointer_init,
+    .qdev.name  = "syborg,pointer",
+    .qdev.size  = sizeof(SyborgPointerState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fifo-size", SyborgPointerState, fifo_size, 16),
+        DEFINE_PROP_UINT32("absolute",  SyborgPointerState, absolute,   1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_pointer_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_pointer_info);
+}
+
+device_init(syborg_pointer_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_rtc.c b/qemu-0.15.x/hw/syborg_rtc.c
new file mode 100644
index 0000000..69f6ccf
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_rtc.c
@@ -0,0 +1,140 @@
+/*
+ * Syborg RTC
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "qemu-timer.h"
+#include "syborg.h"
+
+enum {
+    RTC_ID        = 0,
+    RTC_LATCH     = 1,
+    RTC_DATA_LOW  = 2,
+    RTC_DATA_HIGH = 3
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    int64_t offset;
+    int64_t data;
+    qemu_irq irq;
+} SyborgRTCState;
+
+static uint32_t syborg_rtc_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgRTCState *s = (SyborgRTCState *)opaque;
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case RTC_ID:
+        return SYBORG_ID_RTC;
+    case RTC_DATA_LOW:
+        return (uint32_t)s->data;
+    case RTC_DATA_HIGH:
+        return (uint32_t)(s->data >> 32);
+    default:
+        cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+    SyborgRTCState *s = (SyborgRTCState *)opaque;
+    uint64_t now;
+
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case RTC_LATCH:
+        now = qemu_get_clock_ns(vm_clock);
+        if (value >= 4) {
+            s->offset = s->data - now;
+        } else {
+            s->data = now + s->offset;
+            while (value) {
+                s->data /= 1000;
+                value--;
+            }
+        }
+        break;
+    case RTC_DATA_LOW:
+        s->data = (s->data & ~(uint64_t)0xffffffffu) | value;
+        break;
+    case RTC_DATA_HIGH:
+        s->data = (s->data & 0xffffffffu) | ((uint64_t)value << 32);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "syborg_rtc_write: Bad offset %x\n",
+                  (int)offset);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const syborg_rtc_readfn[] = {
+    syborg_rtc_read,
+    syborg_rtc_read,
+    syborg_rtc_read
+};
+
+static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = {
+    syborg_rtc_write,
+    syborg_rtc_write,
+    syborg_rtc_write
+};
+
+static const VMStateDescription vmstate_syborg_rtc = {
+    .name = "syborg_keyboard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT64(offset, SyborgRTCState),
+        VMSTATE_INT64(data, SyborgRTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int syborg_rtc_init(SysBusDevice *dev)
+{
+    SyborgRTCState *s = FROM_SYSBUS(SyborgRTCState, dev);
+    struct tm tm;
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(syborg_rtc_readfn,
+                                       syborg_rtc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    qemu_get_timedate(&tm, 0);
+    s->offset = (uint64_t)mktime(&tm) * 1000000000;
+
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s);
+    return 0;
+}
+
+static void syborg_rtc_register_devices(void)
+{
+    sysbus_register_dev("syborg,rtc", sizeof(SyborgRTCState), syborg_rtc_init);
+}
+
+device_init(syborg_rtc_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_serial.c b/qemu-0.15.x/hw/syborg_serial.c
new file mode 100644
index 0000000..2ef7175
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_serial.c
@@ -0,0 +1,335 @@
+/*
+ * Syborg serial port
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "qemu-char.h"
+#include "syborg.h"
+
+//#define DEBUG_SYBORG_SERIAL
+
+#ifdef DEBUG_SYBORG_SERIAL
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_serial: " fmt , ##args); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_serial: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_serial: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    SERIAL_ID           = 0,
+    SERIAL_DATA         = 1,
+    SERIAL_FIFO_COUNT   = 2,
+    SERIAL_INT_ENABLE   = 3,
+    SERIAL_DMA_TX_ADDR  = 4,
+    SERIAL_DMA_TX_COUNT = 5, /* triggers dma */
+    SERIAL_DMA_RX_ADDR  = 6,
+    SERIAL_DMA_RX_COUNT = 7, /* triggers dma */
+    SERIAL_FIFO_SIZE    = 8
+};
+
+#define SERIAL_INT_FIFO   (1u << 0)
+#define SERIAL_INT_DMA_TX (1u << 1)
+#define SERIAL_INT_DMA_RX (1u << 2)
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t int_enable;
+    uint32_t fifo_size;
+    uint32_t *read_fifo;
+    int read_pos;
+    int read_count;
+    CharDriverState *chr;
+    qemu_irq irq;
+    uint32_t dma_tx_ptr;
+    uint32_t dma_rx_ptr;
+    uint32_t dma_rx_size;
+} SyborgSerialState;
+
+static void syborg_serial_update(SyborgSerialState *s)
+{
+    int level;
+    level = 0;
+    if ((s->int_enable & SERIAL_INT_FIFO) && s->read_count)
+        level = 1;
+    if (s->int_enable & SERIAL_INT_DMA_TX)
+        level = 1;
+    if ((s->int_enable & SERIAL_INT_DMA_RX) && s->dma_rx_size == 0)
+        level = 1;
+
+    qemu_set_irq(s->irq, level);
+}
+
+static uint32_t fifo_pop(SyborgSerialState *s)
+{
+    const uint32_t c = s->read_fifo[s->read_pos];
+    s->read_count--;
+    s->read_pos++;
+    if (s->read_pos == s->fifo_size)
+        s->read_pos = 0;
+
+    DPRINTF("FIFO pop %x (%d)\n", c, s->read_count);
+    return c;
+}
+
+static void fifo_push(SyborgSerialState *s, uint32_t new_value)
+{
+    int slot;
+
+    DPRINTF("FIFO push %x (%d)\n", new_value, s->read_count);
+    slot = s->read_pos + s->read_count;
+    if (slot >= s->fifo_size)
+          slot -= s->fifo_size;
+    s->read_fifo[slot] = new_value;
+    s->read_count++;
+}
+
+static void do_dma_tx(SyborgSerialState *s, uint32_t count)
+{
+    unsigned char ch;
+
+    if (count == 0)
+        return;
+
+    if (s->chr != NULL) {
+        /* optimize later. Now, 1 byte per iteration */
+        while (count--) {
+            cpu_physical_memory_read(s->dma_tx_ptr, &ch, 1);
+            qemu_chr_write(s->chr, &ch, 1);
+            s->dma_tx_ptr++;
+        }
+    } else {
+        s->dma_tx_ptr += count;
+    }
+    /* QEMU char backends do not have a nonblocking mode, so we transmit all
+       the data immediately and the interrupt status will be unchanged.  */
+}
+
+/* Initiate RX DMA, and transfer data from the FIFO.  */
+static void dma_rx_start(SyborgSerialState *s, uint32_t len)
+{
+    uint32_t dest;
+    unsigned char ch;
+
+    dest = s->dma_rx_ptr;
+    if (s->read_count < len) {
+        s->dma_rx_size = len - s->read_count;
+        len = s->read_count;
+    } else {
+        s->dma_rx_size = 0;
+    }
+
+    while (len--) {
+        ch = fifo_pop(s);
+        cpu_physical_memory_write(dest, &ch, 1);
+        dest++;
+    }
+    s->dma_rx_ptr = dest;
+    syborg_serial_update(s);
+}
+
+static uint32_t syborg_serial_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgSerialState *s = (SyborgSerialState *)opaque;
+    uint32_t c;
+
+    offset &= 0xfff;
+    DPRINTF("read 0x%x\n", (int)offset);
+    switch(offset >> 2) {
+    case SERIAL_ID:
+        return SYBORG_ID_SERIAL;
+    case SERIAL_DATA:
+        if (s->read_count > 0)
+            c = fifo_pop(s);
+        else
+            c = -1;
+        syborg_serial_update(s);
+        return c;
+    case SERIAL_FIFO_COUNT:
+        return s->read_count;
+    case SERIAL_INT_ENABLE:
+        return s->int_enable;
+    case SERIAL_DMA_TX_ADDR:
+        return s->dma_tx_ptr;
+    case SERIAL_DMA_TX_COUNT:
+        return 0;
+    case SERIAL_DMA_RX_ADDR:
+        return s->dma_rx_ptr;
+    case SERIAL_DMA_RX_COUNT:
+        return s->dma_rx_size;
+    case SERIAL_FIFO_SIZE:
+        return s->fifo_size;
+
+    default:
+        cpu_abort(cpu_single_env, "syborg_serial_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_serial_write(void *opaque, target_phys_addr_t offset,
+                                uint32_t value)
+{
+    SyborgSerialState *s = (SyborgSerialState *)opaque;
+    unsigned char ch;
+
+    offset &= 0xfff;
+    DPRINTF("Write 0x%x=0x%x\n", (int)offset, value);
+    switch (offset >> 2) {
+    case SERIAL_DATA:
+        ch = value;
+        if (s->chr)
+            qemu_chr_write(s->chr, &ch, 1);
+        break;
+    case SERIAL_INT_ENABLE:
+        s->int_enable = value;
+        syborg_serial_update(s);
+        break;
+    case SERIAL_DMA_TX_ADDR:
+        s->dma_tx_ptr = value;
+        break;
+    case SERIAL_DMA_TX_COUNT:
+        do_dma_tx(s, value);
+        break;
+    case SERIAL_DMA_RX_ADDR:
+        /* For safety, writes to this register cancel any pending DMA.  */
+        s->dma_rx_size = 0;
+        s->dma_rx_ptr = value;
+        break;
+    case SERIAL_DMA_RX_COUNT:
+        dma_rx_start(s, value);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "syborg_serial_write: Bad offset %x\n",
+                  (int)offset);
+        break;
+    }
+}
+
+static int syborg_serial_can_receive(void *opaque)
+{
+    SyborgSerialState *s = (SyborgSerialState *)opaque;
+
+    if (s->dma_rx_size)
+        return s->dma_rx_size;
+    return s->fifo_size - s->read_count;
+}
+
+static void syborg_serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+    SyborgSerialState *s = (SyborgSerialState *)opaque;
+
+    if (s->dma_rx_size) {
+        /* Place it in the DMA buffer.  */
+        cpu_physical_memory_write(s->dma_rx_ptr, buf, size);
+        s->dma_rx_size -= size;
+        s->dma_rx_ptr += size;
+    } else {
+        while (size--)
+            fifo_push(s, *buf);
+    }
+
+    syborg_serial_update(s);
+}
+
+static void syborg_serial_event(void *opaque, int event)
+{
+    /* TODO: Report BREAK events?  */
+}
+
+static CPUReadMemoryFunc * const syborg_serial_readfn[] = {
+     syborg_serial_read,
+     syborg_serial_read,
+     syborg_serial_read
+};
+
+static CPUWriteMemoryFunc * const syborg_serial_writefn[] = {
+     syborg_serial_write,
+     syborg_serial_write,
+     syborg_serial_write
+};
+
+static const VMStateDescription vmstate_syborg_serial = {
+    .name = "syborg_serial",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgSerialState),
+        VMSTATE_UINT32(int_enable, SyborgSerialState),
+        VMSTATE_INT32(read_pos, SyborgSerialState),
+        VMSTATE_INT32(read_count, SyborgSerialState),
+        VMSTATE_UINT32(dma_tx_ptr, SyborgSerialState),
+        VMSTATE_UINT32(dma_rx_ptr, SyborgSerialState),
+        VMSTATE_UINT32(dma_rx_size, SyborgSerialState),
+        VMSTATE_VARRAY_UINT32(read_fifo, SyborgSerialState, fifo_size, 1,
+                              vmstate_info_uint32, uint32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int syborg_serial_init(SysBusDevice *dev)
+{
+    SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev);
+    int iomemtype;
+
+    sysbus_init_irq(dev, &s->irq);
+    iomemtype = cpu_register_io_memory(syborg_serial_readfn,
+                                       syborg_serial_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, syborg_serial_can_receive,
+                              syborg_serial_receive, syborg_serial_event, s);
+    }
+    if (s->fifo_size <= 0) {
+        fprintf(stderr, "syborg_serial: fifo too small\n");
+        s->fifo_size = 16;
+    }
+    s->read_fifo = qemu_mallocz(s->fifo_size * sizeof(s->read_fifo[0]));
+
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_serial_info = {
+    .init = syborg_serial_init,
+    .qdev.name  = "syborg,serial",
+    .qdev.size  = sizeof(SyborgSerialState),
+    .qdev.vmsd  = &vmstate_syborg_serial,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fifo-size", SyborgSerialState, fifo_size, 16),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_serial_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_serial_info);
+}
+
+device_init(syborg_serial_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_timer.c b/qemu-0.15.x/hw/syborg_timer.c
new file mode 100644
index 0000000..50c813e
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_timer.c
@@ -0,0 +1,231 @@
+/*
+ * Syborg Interval Timer.
+ *
+ * Copyright (c) 2008 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 "sysbus.h"
+#include "qemu-timer.h"
+#include "syborg.h"
+
+//#define DEBUG_SYBORG_TIMER
+
+#ifdef DEBUG_SYBORG_TIMER
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_timer: " fmt , ##args); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    TIMER_ID          = 0,
+    TIMER_RUNNING     = 1,
+    TIMER_ONESHOT     = 2,
+    TIMER_LIMIT       = 3,
+    TIMER_VALUE       = 4,
+    TIMER_INT_ENABLE  = 5,
+    TIMER_INT_STATUS  = 6,
+    TIMER_FREQ        = 7
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    ptimer_state *timer;
+    int running;
+    int oneshot;
+    uint32_t limit;
+    uint32_t freq;
+    uint32_t int_level;
+    uint32_t int_enabled;
+    qemu_irq irq;
+} SyborgTimerState;
+
+static void syborg_timer_update(SyborgTimerState *s)
+{
+    /* Update interrupt.  */
+    if (s->int_level && s->int_enabled) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void syborg_timer_tick(void *opaque)
+{
+    SyborgTimerState *s = (SyborgTimerState *)opaque;
+    //DPRINTF("Timer Tick\n");
+    s->int_level = 1;
+    if (s->oneshot)
+        s->running = 0;
+    syborg_timer_update(s);
+}
+
+static uint32_t syborg_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    SyborgTimerState *s = (SyborgTimerState *)opaque;
+
+    DPRINTF("Reg read %d\n", (int)offset);
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case TIMER_ID:
+        return SYBORG_ID_TIMER;
+    case TIMER_RUNNING:
+        return s->running;
+    case TIMER_ONESHOT:
+        return s->oneshot;
+    case TIMER_LIMIT:
+        return s->limit;
+    case TIMER_VALUE:
+        return ptimer_get_count(s->timer);
+    case TIMER_INT_ENABLE:
+        return s->int_enabled;
+    case TIMER_INT_STATUS:
+        return s->int_level;
+    case TIMER_FREQ:
+        return s->freq;
+    default:
+        cpu_abort(cpu_single_env, "syborg_timer_read: Bad offset %x\n",
+                  (int)offset);
+        return 0;
+    }
+}
+
+static void syborg_timer_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    SyborgTimerState *s = (SyborgTimerState *)opaque;
+
+    DPRINTF("Reg write %d\n", (int)offset);
+    offset &= 0xfff;
+    switch (offset >> 2) {
+    case TIMER_RUNNING:
+        if (value == s->running)
+            break;
+        s->running = value;
+        if (value) {
+            ptimer_run(s->timer, s->oneshot);
+        } else {
+            ptimer_stop(s->timer);
+        }
+        break;
+    case TIMER_ONESHOT:
+        if (s->running) {
+            ptimer_stop(s->timer);
+        }
+        s->oneshot = value;
+        if (s->running) {
+            ptimer_run(s->timer, s->oneshot);
+        }
+        break;
+    case TIMER_LIMIT:
+        s->limit = value;
+        ptimer_set_limit(s->timer, value, 1);
+        break;
+    case TIMER_VALUE:
+        ptimer_set_count(s->timer, value);
+        break;
+    case TIMER_INT_ENABLE:
+        s->int_enabled = value;
+        syborg_timer_update(s);
+        break;
+    case TIMER_INT_STATUS:
+        s->int_level &= ~value;
+        syborg_timer_update(s);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "syborg_timer_write: Bad offset %x\n",
+                  (int)offset);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const syborg_timer_readfn[] = {
+    syborg_timer_read,
+    syborg_timer_read,
+    syborg_timer_read
+};
+
+static CPUWriteMemoryFunc * const syborg_timer_writefn[] = {
+    syborg_timer_write,
+    syborg_timer_write,
+    syborg_timer_write
+};
+
+static const VMStateDescription vmstate_syborg_timer = {
+    .name = "syborg_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(running, SyborgTimerState),
+        VMSTATE_INT32(oneshot, SyborgTimerState),
+        VMSTATE_UINT32(limit, SyborgTimerState),
+        VMSTATE_UINT32(int_level, SyborgTimerState),
+        VMSTATE_UINT32(int_enabled, SyborgTimerState),
+        VMSTATE_PTIMER(timer, SyborgTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int syborg_timer_init(SysBusDevice *dev)
+{
+    SyborgTimerState *s = FROM_SYSBUS(SyborgTimerState, dev);
+    QEMUBH *bh;
+    int iomemtype;
+
+    if (s->freq == 0) {
+        fprintf(stderr, "syborg_timer: Zero/unset frequency\n");
+        exit(1);
+    }
+    sysbus_init_irq(dev, &s->irq);
+    iomemtype = cpu_register_io_memory(syborg_timer_readfn,
+                                       syborg_timer_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    bh = qemu_bh_new(syborg_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    ptimer_set_freq(s->timer, s->freq);
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_timer, s);
+    return 0;
+}
+
+static SysBusDeviceInfo syborg_timer_info = {
+    .init = syborg_timer_init,
+    .qdev.name  = "syborg,timer",
+    .qdev.size  = sizeof(SyborgTimerState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency",SyborgTimerState, freq, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_timer_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_timer_info);
+}
+
+device_init(syborg_timer_register_devices)
diff --git a/qemu-0.15.x/hw/syborg_virtio.c b/qemu-0.15.x/hw/syborg_virtio.c
new file mode 100644
index 0000000..00c7be8
--- /dev/null
+++ b/qemu-0.15.x/hw/syborg_virtio.c
@@ -0,0 +1,315 @@
+/*
+ * Virtio Syborg bindings
+ *
+ * Copyright (c) 2009 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 "syborg.h"
+#include "sysbus.h"
+#include "virtio.h"
+#include "virtio-net.h"
+
+//#define DEBUG_SYBORG_VIRTIO
+
+#ifdef DEBUG_SYBORG_VIRTIO
+#define DPRINTF(fmt, ...) \
+do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
+    exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    SYBORG_VIRTIO_ID             = 0,
+    SYBORG_VIRTIO_DEVTYPE        = 1,
+    SYBORG_VIRTIO_HOST_FEATURES  = 2,
+    SYBORG_VIRTIO_GUEST_FEATURES = 3,
+    SYBORG_VIRTIO_QUEUE_BASE     = 4,
+    SYBORG_VIRTIO_QUEUE_NUM      = 5,
+    SYBORG_VIRTIO_QUEUE_SEL      = 6,
+    SYBORG_VIRTIO_QUEUE_NOTIFY   = 7,
+    SYBORG_VIRTIO_STATUS         = 8,
+    SYBORG_VIRTIO_INT_ENABLE     = 9,
+    SYBORG_VIRTIO_INT_STATUS     = 10
+};
+
+#define SYBORG_VIRTIO_CONFIG 0x100
+
+/* Device independent interface.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    VirtIODevice *vdev;
+    qemu_irq irq;
+    uint32_t int_enable;
+    uint32_t id;
+    NICConf nic;
+    uint32_t host_features;
+    virtio_net_conf net;
+} SyborgVirtIOProxy;
+
+static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+    uint32_t ret;
+
+    DPRINTF("readl 0x%x\n", (int)offset);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
+    }
+    switch(offset >> 2) {
+    case SYBORG_VIRTIO_ID:
+        ret = SYBORG_ID_VIRTIO;
+        break;
+    case SYBORG_VIRTIO_DEVTYPE:
+        ret = s->id;
+        break;
+    case SYBORG_VIRTIO_HOST_FEATURES:
+        ret = s->host_features;
+        break;
+    case SYBORG_VIRTIO_GUEST_FEATURES:
+        ret = vdev->guest_features;
+        break;
+    case SYBORG_VIRTIO_QUEUE_BASE:
+        ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
+        break;
+    case SYBORG_VIRTIO_QUEUE_NUM:
+        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
+        break;
+    case SYBORG_VIRTIO_QUEUE_SEL:
+        ret = vdev->queue_sel;
+        break;
+    case SYBORG_VIRTIO_STATUS:
+        ret = vdev->status;
+        break;
+    case SYBORG_VIRTIO_INT_ENABLE:
+        ret = s->int_enable;
+        break;
+    case SYBORG_VIRTIO_INT_STATUS:
+        ret = vdev->isr;
+        break;
+    default:
+        BADF("Bad read offset 0x%x\n", (int)offset);
+        return 0;
+    }
+    return ret;
+}
+
+static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+
+    DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
+                                    value);
+    }
+    switch (offset >> 2) {
+    case SYBORG_VIRTIO_GUEST_FEATURES:
+        if (vdev->set_features)
+            vdev->set_features(vdev, value);
+        vdev->guest_features = value;
+        break;
+    case SYBORG_VIRTIO_QUEUE_BASE:
+        if (value == 0)
+            virtio_reset(vdev);
+        else
+            virtio_queue_set_addr(vdev, vdev->queue_sel, value);
+        break;
+    case SYBORG_VIRTIO_QUEUE_SEL:
+        if (value < VIRTIO_PCI_QUEUE_MAX)
+            vdev->queue_sel = value;
+        break;
+    case SYBORG_VIRTIO_QUEUE_NOTIFY:
+        if (value < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, value);
+        }
+        break;
+    case SYBORG_VIRTIO_STATUS:
+        virtio_set_status(vdev, value & 0xFF);
+        if (vdev->status == 0)
+            virtio_reset(vdev);
+        break;
+    case SYBORG_VIRTIO_INT_ENABLE:
+        s->int_enable = value;
+        virtio_update_irq(vdev);
+        break;
+    case SYBORG_VIRTIO_INT_STATUS:
+        vdev->isr &= ~value;
+        virtio_update_irq(vdev);
+        break;
+    default:
+        BADF("Bad write offset 0x%x\n", (int)offset);
+        break;
+    }
+}
+
+static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+
+    DPRINTF("readw 0x%x\n", (int)offset);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
+    }
+    BADF("Bad halfword read offset 0x%x\n", (int)offset);
+    return -1;
+}
+
+static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+
+    DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
+                                    value);
+    }
+    BADF("Bad halfword write offset 0x%x\n", (int)offset);
+}
+
+static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+
+    DPRINTF("readb 0x%x\n", (int)offset);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
+    }
+    BADF("Bad byte read offset 0x%x\n", (int)offset);
+    return -1;
+}
+
+static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
+                                 uint32_t value)
+{
+    SyborgVirtIOProxy *s = opaque;
+    VirtIODevice *vdev = s->vdev;
+
+    DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
+    if (offset >= SYBORG_VIRTIO_CONFIG) {
+        return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
+                                    value);
+    }
+    BADF("Bad byte write offset 0x%x\n", (int)offset);
+}
+
+static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
+     syborg_virtio_readb,
+     syborg_virtio_readw,
+     syborg_virtio_readl
+};
+
+static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
+     syborg_virtio_writeb,
+     syborg_virtio_writew,
+     syborg_virtio_writel
+};
+
+static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
+{
+    SyborgVirtIOProxy *proxy = opaque;
+    int level;
+
+    level = proxy->int_enable & proxy->vdev->isr;
+    DPRINTF("IRQ %d\n", level);
+    qemu_set_irq(proxy->irq, level != 0);
+}
+
+static unsigned syborg_virtio_get_features(void *opaque)
+{
+    SyborgVirtIOProxy *proxy = opaque;
+    return proxy->host_features;
+}
+
+static VirtIOBindings syborg_virtio_bindings = {
+    .notify = syborg_virtio_update_irq,
+    .get_features = syborg_virtio_get_features,
+};
+
+static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
+{
+    int iomemtype;
+
+    proxy->vdev = vdev;
+
+    /* Don't support multiple vectors */
+    proxy->vdev->nvectors = 0;
+    sysbus_init_irq(&proxy->busdev, &proxy->irq);
+    iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
+                                       syborg_virtio_writefn, proxy,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
+
+    proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
+
+    qemu_register_reset(virtio_reset, vdev);
+
+    virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
+    proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
+    return 0;
+}
+
+/* Device specific bindings.  */
+
+static int syborg_virtio_net_init(SysBusDevice *dev)
+{
+    VirtIODevice *vdev;
+    SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
+
+    vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
+    return syborg_virtio_init(proxy, vdev);
+}
+
+static SysBusDeviceInfo syborg_virtio_net_info = {
+    .init = syborg_virtio_net_init,
+    .qdev.name  = "syborg,virtio-net",
+    .qdev.size  = sizeof(SyborgVirtIOProxy),
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
+        DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
+        DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
+                           net.txtimer, TX_TIMER_INTERVAL),
+        DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
+                          net.txburst, TX_BURST),
+        DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void syborg_virtio_register_devices(void)
+{
+    sysbus_register_withprop(&syborg_virtio_net_info);
+}
+
+device_init(syborg_virtio_register_devices)
diff --git a/qemu-0.15.x/hw/sysbus.c b/qemu-0.15.x/hw/sysbus.c
new file mode 100644
index 0000000..2e22be7
--- /dev/null
+++ b/qemu-0.15.x/hw/sysbus.c
@@ -0,0 +1,234 @@
+/*
+ *  System (CPU) Bus device support code
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "monitor.h"
+
+static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *sysbus_get_fw_dev_path(DeviceState *dev);
+
+struct BusInfo system_bus_info = {
+    .name       = "System",
+    .size       = sizeof(BusState),
+    .print_dev  = sysbus_dev_print,
+    .get_fw_dev_path = sysbus_get_fw_dev_path,
+};
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
+{
+    assert(n >= 0 && n < dev->num_irq);
+    dev->irqs[n] = NULL;
+    if (dev->irqp[n]) {
+        *dev->irqp[n] = irq;
+    }
+}
+
+void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == addr) {
+        /* ??? region already mapped here.  */
+        return;
+    }
+    if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
+        /* Unregister previous mapping.  */
+        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+                                     IO_MEM_UNASSIGNED);
+    }
+    dev->mmio[n].addr = addr;
+    if (dev->mmio[n].cb) {
+        dev->mmio[n].cb(dev, addr);
+    } else {
+        cpu_register_physical_memory(addr, dev->mmio[n].size,
+                                     dev->mmio[n].iofunc);
+    }
+}
+
+
+/* Request an IRQ source.  The actual IRQ object may be populated later.  */
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
+{
+    int n;
+
+    assert(dev->num_irq < QDEV_MAX_IRQ);
+    n = dev->num_irq++;
+    dev->irqp[n] = p;
+}
+
+/* Pass IRQs from a target device.  */
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
+{
+    int i;
+    assert(dev->num_irq == 0);
+    dev->num_irq = target->num_irq;
+    for (i = 0; i < dev->num_irq; i++) {
+        dev->irqp[i] = target->irqp[i];
+    }
+}
+
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+                      ram_addr_t iofunc)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].size = size;
+    dev->mmio[n].iofunc = iofunc;
+}
+
+void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
+                         mmio_mapfunc cb)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].size = size;
+    dev->mmio[n].cb = cb;
+}
+
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
+{
+    pio_addr_t i;
+
+    for (i = 0; i < size; i++) {
+        assert(dev->num_pio < QDEV_MAX_PIO);
+        dev->pio[dev->num_pio++] = ioport++;
+    }
+}
+
+static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
+{
+    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+
+    return info->init(sysbus_from_qdev(dev));
+}
+
+void sysbus_register_withprop(SysBusDeviceInfo *info)
+{
+    info->qdev.init = sysbus_device_init;
+    info->qdev.bus_info = &system_bus_info;
+
+    assert(info->qdev.size >= sizeof(SysBusDevice));
+    qdev_register(&info->qdev);
+}
+
+void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
+{
+    SysBusDeviceInfo *info;
+
+    info = qemu_mallocz(sizeof(*info));
+    info->qdev.name = qemu_strdup(name);
+    info->qdev.size = size;
+    info->init = init;
+    sysbus_register_withprop(info);
+}
+
+DeviceState *sysbus_create_varargs(const char *name,
+                                   target_phys_addr_t addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_create(NULL, name);
+    s = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    if (addr != (target_phys_addr_t)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    return dev;
+}
+
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       target_phys_addr_t addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_try_create(NULL, name);
+    if (!dev) {
+        return NULL;
+    }
+    s = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    if (addr != (target_phys_addr_t)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    return dev;
+}
+
+static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    SysBusDevice *s = sysbus_from_qdev(dev);
+    int i;
+
+    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
+    for (i = 0; i < s->num_mmio; i++) {
+        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
+                       indent, "", s->mmio[i].addr, s->mmio[i].size);
+    }
+}
+
+static char *sysbus_get_fw_dev_path(DeviceState *dev)
+{
+    SysBusDevice *s = sysbus_from_qdev(dev);
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+
+    if (s->num_mmio) {
+        snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
+                 s->mmio[0].addr);
+    } else if (s->num_pio) {
+        snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
+    }
+
+    return strdup(path);
+}
diff --git a/qemu-0.15.x/hw/sysbus.h b/qemu-0.15.x/hw/sysbus.h
new file mode 100644
index 0000000..4e8cb16
--- /dev/null
+++ b/qemu-0.15.x/hw/sysbus.h
@@ -0,0 +1,76 @@
+#ifndef HW_SYSBUS_H
+#define HW_SYSBUS_H 1
+
+/* Devices attached directly to the main system bus.  */
+
+#include "qdev.h"
+
+#define QDEV_MAX_MMIO 32
+#define QDEV_MAX_PIO 32
+#define QDEV_MAX_IRQ 256
+
+typedef struct SysBusDevice SysBusDevice;
+typedef void (*mmio_mapfunc)(SysBusDevice *dev, target_phys_addr_t addr);
+
+struct SysBusDevice {
+    DeviceState qdev;
+    int num_irq;
+    qemu_irq irqs[QDEV_MAX_IRQ];
+    qemu_irq *irqp[QDEV_MAX_IRQ];
+    int num_mmio;
+    struct {
+        target_phys_addr_t addr;
+        target_phys_addr_t size;
+        mmio_mapfunc cb;
+        ram_addr_t iofunc;
+    } mmio[QDEV_MAX_MMIO];
+    int num_pio;
+    pio_addr_t pio[QDEV_MAX_PIO];
+};
+
+typedef int (*sysbus_initfn)(SysBusDevice *dev);
+
+/* Macros to compensate for lack of type inheritance in C.  */
+#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
+#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
+
+typedef struct {
+    DeviceInfo qdev;
+    sysbus_initfn init;
+} SysBusDeviceInfo;
+
+void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
+void sysbus_register_withprop(SysBusDeviceInfo *info);
+void *sysbus_new(void);
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+                      ram_addr_t iofunc);
+void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
+                            mmio_mapfunc cb);
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
+
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
+void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+
+/* Legacy helper function for creating devices.  */
+DeviceState *sysbus_create_varargs(const char *name,
+                                 target_phys_addr_t addr, ...);
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       target_phys_addr_t addr, ...);
+static inline DeviceState *sysbus_create_simple(const char *name,
+                                              target_phys_addr_t addr,
+                                              qemu_irq irq)
+{
+    return sysbus_create_varargs(name, addr, irq, NULL);
+}
+
+static inline DeviceState *sysbus_try_create_simple(const char *name,
+                                                    target_phys_addr_t addr,
+                                                    qemu_irq irq)
+{
+    return sysbus_try_create_varargs(name, addr, irq, NULL);
+}
+
+#endif /* !HW_SYSBUS_H */
diff --git a/qemu-0.15.x/hw/tc58128.c b/qemu-0.15.x/hw/tc58128.c
new file mode 100644
index 0000000..61b99dd
--- /dev/null
+++ b/qemu-0.15.x/hw/tc58128.c
@@ -0,0 +1,182 @@
+#include "hw.h"
+#include "sh.h"
+#include "loader.h"
+
+#define CE1  0x0100
+#define CE2  0x0200
+#define RE   0x0400
+#define WE   0x0800
+#define ALE  0x1000
+#define CLE  0x2000
+#define RDY1 0x4000
+#define RDY2 0x8000
+#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
+
+typedef enum { WAIT, READ1, READ2, READ3 } state_t;
+
+typedef struct {
+    uint8_t *flash_contents;
+    state_t state;
+    uint32_t address;
+    uint8_t address_cycle;
+} tc58128_dev;
+
+static tc58128_dev tc58128_devs[2];
+
+#define FLASH_SIZE (16*1024*1024)
+
+static void init_dev(tc58128_dev * dev, const char *filename)
+{
+    int ret, blocks;
+
+    dev->state = WAIT;
+    dev->flash_contents = qemu_mallocz(FLASH_SIZE);
+    memset(dev->flash_contents, 0xff, FLASH_SIZE);
+    if (!dev->flash_contents) {
+	fprintf(stderr, "could not alloc memory for flash\n");
+	exit(1);
+    }
+    if (filename) {
+	/* Load flash image skipping the first block */
+	ret = load_image(filename, dev->flash_contents + 528 * 32);
+	if (ret < 0) {
+	    fprintf(stderr, "ret=%d\n", ret);
+	    fprintf(stderr, "qemu: could not load flash image %s\n",
+		    filename);
+	    exit(1);
+	} else {
+	    /* Build first block with number of blocks */
+	    blocks = (ret + 528 * 32 - 1) / (528 * 32);
+	    dev->flash_contents[0] = blocks & 0xff;
+	    dev->flash_contents[1] = (blocks >> 8) & 0xff;
+	    dev->flash_contents[2] = (blocks >> 16) & 0xff;
+	    dev->flash_contents[3] = (blocks >> 24) & 0xff;
+	    fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
+		    filename);
+	}
+    }
+}
+
+static void handle_command(tc58128_dev * dev, uint8_t command)
+{
+    switch (command) {
+    case 0xff:
+	fprintf(stderr, "reset flash device\n");
+	dev->state = WAIT;
+	break;
+    case 0x00:
+	fprintf(stderr, "read mode 1\n");
+	dev->state = READ1;
+	dev->address_cycle = 0;
+	break;
+    case 0x01:
+	fprintf(stderr, "read mode 2\n");
+	dev->state = READ2;
+	dev->address_cycle = 0;
+	break;
+    case 0x50:
+	fprintf(stderr, "read mode 3\n");
+	dev->state = READ3;
+	dev->address_cycle = 0;
+	break;
+    default:
+	fprintf(stderr, "unknown flash command 0x%02x\n", command);
+        abort();
+    }
+}
+
+static void handle_address(tc58128_dev * dev, uint8_t data)
+{
+    switch (dev->state) {
+    case READ1:
+    case READ2:
+    case READ3:
+	switch (dev->address_cycle) {
+	case 0:
+	    dev->address = data;
+	    if (dev->state == READ2)
+		dev->address |= 0x100;
+	    else if (dev->state == READ3)
+		dev->address |= 0x200;
+	    break;
+	case 1:
+	    dev->address += data * 528 * 0x100;
+	    break;
+	case 2:
+	    dev->address += data * 528;
+	    fprintf(stderr, "address pointer in flash: 0x%08x\n",
+		    dev->address);
+	    break;
+	default:
+	    /* Invalid data */
+            abort();
+	}
+	dev->address_cycle++;
+	break;
+    default:
+        abort();
+    }
+}
+
+static uint8_t handle_read(tc58128_dev * dev)
+{
+#if 0
+    if (dev->address % 0x100000 == 0)
+	fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
+#endif
+    return dev->flash_contents[dev->address++];
+}
+
+/* We never mark the device as busy, so interrupts cannot be triggered
+   XXXXX */
+
+static int tc58128_cb(uint16_t porta, uint16_t portb,
+                      uint16_t * periph_pdtra, uint16_t * periph_portadir,
+                      uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
+{
+    int dev;
+
+    if ((porta & CE1) == 0)
+	dev = 0;
+    else if ((porta & CE2) == 0)
+	dev = 1;
+    else
+	return 0;		/* No device selected */
+
+    if ((porta & RE) && (porta & WE)) {
+	/* Nothing to do, assert ready and return to input state */
+	*periph_portadir &= 0xff00;
+	*periph_portadir |= RDY(dev);
+	*periph_pdtra |= RDY(dev);
+	return 1;
+    }
+
+    if (porta & CLE) {
+	/* Command */
+	assert((porta & WE) == 0);
+	handle_command(&tc58128_devs[dev], porta & 0x00ff);
+    } else if (porta & ALE) {
+	assert((porta & WE) == 0);
+	handle_address(&tc58128_devs[dev], porta & 0x00ff);
+    } else if ((porta & RE) == 0) {
+	*periph_portadir |= 0x00ff;
+	*periph_pdtra &= 0xff00;
+	*periph_pdtra |= handle_read(&tc58128_devs[dev]);
+    } else {
+        abort();
+    }
+    return 1;
+}
+
+static sh7750_io_device tc58128 = {
+    RE | WE,			/* Port A triggers */
+    0,				/* Port B triggers */
+    tc58128_cb			/* Callback */
+};
+
+int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
+{
+    init_dev(&tc58128_devs[0], zone1);
+    init_dev(&tc58128_devs[1], zone2);
+    return sh7750_register_io_device(s, &tc58128);
+}
diff --git a/qemu-0.15.x/hw/tc6393xb.c b/qemu-0.15.x/hw/tc6393xb.c
new file mode 100644
index 0000000..ed49e94
--- /dev/null
+++ b/qemu-0.15.x/hw/tc6393xb.c
@@ -0,0 +1,607 @@
+/*
+ * Toshiba TC6393XB I/O Controller.
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
+ * Toshiba e-Series PDAs.
+ *
+ * Most features are currently unsupported!!!
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "devices.h"
+#include "flash.h"
+#include "console.h"
+#include "pixel_ops.h"
+
+#define IRQ_TC6393_NAND		0
+#define IRQ_TC6393_MMC		1
+#define IRQ_TC6393_OHCI		2
+#define IRQ_TC6393_SERIAL	3
+#define IRQ_TC6393_FB		4
+
+#define	TC6393XB_NR_IRQS	8
+
+#define TC6393XB_GPIOS  16
+
+#define SCR_REVID	0x08		/* b Revision ID	*/
+#define SCR_ISR		0x50		/* b Interrupt Status	*/
+#define SCR_IMR		0x52		/* b Interrupt Mask	*/
+#define SCR_IRR		0x54		/* b Interrupt Routing	*/
+#define SCR_GPER	0x60		/* w GP Enable		*/
+#define SCR_GPI_SR(i)	(0x64 + (i))	/* b3 GPI Status	*/
+#define SCR_GPI_IMR(i)	(0x68 + (i))	/* b3 GPI INT Mask	*/
+#define SCR_GPI_EDER(i)	(0x6c + (i))	/* b3 GPI Edge Detect Enable */
+#define SCR_GPI_LIR(i)	(0x70 + (i))	/* b3 GPI Level Invert	*/
+#define SCR_GPO_DSR(i)	(0x78 + (i))	/* b3 GPO Data Set	*/
+#define SCR_GPO_DOECR(i) (0x7c + (i))	/* b3 GPO Data OE Control */
+#define SCR_GP_IARCR(i)	(0x80 + (i))	/* b3 GP Internal Active Register Control */
+#define SCR_GP_IARLCR(i) (0x84 + (i))	/* b3 GP INTERNAL Active Register Level Control */
+#define SCR_GPI_BCR(i)	(0x88 + (i))	/* b3 GPI Buffer Control */
+#define SCR_GPA_IARCR	0x8c		/* w GPa Internal Active Register Control */
+#define SCR_GPA_IARLCR	0x90		/* w GPa Internal Active Register Level Control */
+#define SCR_GPA_BCR	0x94		/* w GPa Buffer Control */
+#define SCR_CCR		0x98		/* w Clock Control	*/
+#define SCR_PLL2CR	0x9a		/* w PLL2 Control	*/
+#define SCR_PLL1CR	0x9c		/* l PLL1 Control	*/
+#define SCR_DIARCR	0xa0		/* b Device Internal Active Register Control */
+#define SCR_DBOCR	0xa1		/* b Device Buffer Off Control */
+#define SCR_FER		0xe0		/* b Function Enable	*/
+#define SCR_MCR		0xe4		/* w Mode Control	*/
+#define SCR_CONFIG	0xfc		/* b Configuration Control */
+#define SCR_DEBUG	0xff		/* b Debug		*/
+
+#define NAND_CFG_COMMAND    0x04    /* w Command        */
+#define NAND_CFG_BASE       0x10    /* l Control Base Address */
+#define NAND_CFG_INTP       0x3d    /* b Interrupt Pin  */
+#define NAND_CFG_INTE       0x48    /* b Int Enable     */
+#define NAND_CFG_EC         0x4a    /* b Event Control  */
+#define NAND_CFG_ICC        0x4c    /* b Internal Clock Control */
+#define NAND_CFG_ECCC       0x5b    /* b ECC Control    */
+#define NAND_CFG_NFTC       0x60    /* b NAND Flash Transaction Control */
+#define NAND_CFG_NFM        0x61    /* b NAND Flash Monitor */
+#define NAND_CFG_NFPSC      0x62    /* b NAND Flash Power Supply Control */
+#define NAND_CFG_NFDC       0x63    /* b NAND Flash Detect Control */
+
+#define NAND_DATA   0x00        /* l Data       */
+#define NAND_MODE   0x04        /* b Mode       */
+#define NAND_STATUS 0x05        /* b Status     */
+#define NAND_ISR    0x06        /* b Interrupt Status */
+#define NAND_IMR    0x07        /* b Interrupt Mask */
+
+#define NAND_MODE_WP        0x80
+#define NAND_MODE_CE        0x10
+#define NAND_MODE_ALE       0x02
+#define NAND_MODE_CLE       0x01
+#define NAND_MODE_ECC_MASK  0x60
+#define NAND_MODE_ECC_EN    0x20
+#define NAND_MODE_ECC_READ  0x40
+#define NAND_MODE_ECC_RST   0x60
+
+struct TC6393xbState {
+    qemu_irq irq;
+    qemu_irq *sub_irqs;
+    struct {
+        uint8_t ISR;
+        uint8_t IMR;
+        uint8_t IRR;
+        uint16_t GPER;
+        uint8_t GPI_SR[3];
+        uint8_t GPI_IMR[3];
+        uint8_t GPI_EDER[3];
+        uint8_t GPI_LIR[3];
+        uint8_t GP_IARCR[3];
+        uint8_t GP_IARLCR[3];
+        uint8_t GPI_BCR[3];
+        uint16_t GPA_IARCR;
+        uint16_t GPA_IARLCR;
+        uint16_t CCR;
+        uint16_t PLL2CR;
+        uint32_t PLL1CR;
+        uint8_t DIARCR;
+        uint8_t DBOCR;
+        uint8_t FER;
+        uint16_t MCR;
+        uint8_t CONFIG;
+        uint8_t DEBUG;
+    } scr;
+    uint32_t gpio_dir;
+    uint32_t gpio_level;
+    uint32_t prev_level;
+    qemu_irq handler[TC6393XB_GPIOS];
+    qemu_irq *gpio_in;
+
+    struct {
+        uint8_t mode;
+        uint8_t isr;
+        uint8_t imr;
+    } nand;
+    int nand_enable;
+    uint32_t nand_phys;
+    NANDFlashState *flash;
+    ECCState ecc;
+
+    DisplayState *ds;
+    ram_addr_t vram_addr;
+    uint16_t *vram_ptr;
+    uint32_t scr_width, scr_height; /* in pixels */
+    qemu_irq l3v;
+    unsigned blank : 1,
+             blanked : 1;
+};
+
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
+{
+    return s->gpio_in;
+}
+
+static void tc6393xb_gpio_set(void *opaque, int line, int level)
+{
+//    TC6393xbState *s = opaque;
+
+    if (line > TC6393XB_GPIOS) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    // FIXME: how does the chip reflect the GPIO input level change?
+}
+
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
+                    qemu_irq handler)
+{
+    if (line >= TC6393XB_GPIOS) {
+        fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
+        return;
+    }
+
+    s->handler[line] = handler;
+}
+
+static void tc6393xb_gpio_handler_update(TC6393xbState *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
+{
+    return s->l3v;
+}
+
+static void tc6393xb_l3v(void *opaque, int line, int level)
+{
+    TC6393xbState *s = opaque;
+    s->blank = !level;
+    fprintf(stderr, "L3V: %d\n", level);
+}
+
+static void tc6393xb_sub_irq(void *opaque, int line, int level) {
+    TC6393xbState *s = opaque;
+    uint8_t isr = s->scr.ISR;
+    if (level)
+        isr |= 1 << line;
+    else
+        isr &= ~(1 << line);
+    s->scr.ISR = isr;
+    qemu_set_irq(s->irq, isr & s->scr.IMR);
+}
+
+#define SCR_REG_B(N)                            \
+    case SCR_ ##N: return s->scr.N
+#define SCR_REG_W(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;
+#define SCR_REG_L(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;    \
+    case SCR_ ##N + 2: return s->scr.N >> 16;   \
+    case SCR_ ##N + 3: return s->scr.N >> 24;
+#define SCR_REG_A(N)                            \
+    case SCR_ ##N(0): return s->scr.N[0];       \
+    case SCR_ ##N(1): return s->scr.N[1];       \
+    case SCR_ ##N(2): return s->scr.N[2]
+
+static uint32_t tc6393xb_scr_readb(TC6393xbState *s, target_phys_addr_t addr)
+{
+    switch (addr) {
+        case SCR_REVID:
+            return 3;
+        case SCR_REVID+1:
+            return 0;
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+#define SCR_REG_B(N)                                \
+    case SCR_ ##N: s->scr.N = value; return;
+#define SCR_REG_W(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
+#define SCR_REG_L(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return;   \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return;     \
+    case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return;   \
+    case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
+#define SCR_REG_A(N)                                \
+    case SCR_ ##N(0): s->scr.N[0] = value; return;   \
+    case SCR_ ##N(1): s->scr.N[1] = value; return;   \
+    case SCR_ ##N(2): s->scr.N[2] = value; return
+
+static void tc6393xb_scr_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value)
+{
+    switch (addr) {
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
+					(uint32_t) addr, value & 0xff);
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+static void tc6393xb_nand_irq(TC6393xbState *s) {
+    qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
+            (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
+}
+
+static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, target_phys_addr_t addr) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            return s->nand_enable ? 2 : 0;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            return s->nand_phys >> (addr - NAND_CFG_BASE);
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            s->nand_enable = (value & 0x2);
+            return;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
+            s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
+					(uint32_t) addr, value & 0xff);
+}
+
+static uint32_t tc6393xb_nand_readb(TC6393xbState *s, target_phys_addr_t addr) {
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            return nand_getio(s->flash);
+        case NAND_MODE:
+            return s->nand.mode;
+        case NAND_STATUS:
+            return 0x14;
+        case NAND_ISR:
+            return s->nand.isr;
+        case NAND_IMR:
+            return s->nand.imr;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value) {
+//    fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
+//					(uint32_t) addr, value & 0xff);
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            nand_setio(s->flash, value);
+            s->nand.isr |= 1;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_MODE:
+            s->nand.mode = value;
+            nand_setpins(s->flash,
+                    value & NAND_MODE_CLE,
+                    value & NAND_MODE_ALE,
+                    !(value & NAND_MODE_CE),
+                    value & NAND_MODE_WP,
+                    0); // FIXME: gnd
+            switch (value & NAND_MODE_ECC_MASK) {
+                case NAND_MODE_ECC_RST:
+                    ecc_reset(&s->ecc);
+                    break;
+                case NAND_MODE_ECC_READ:
+                    // FIXME
+                    break;
+                case NAND_MODE_ECC_EN:
+                    ecc_reset(&s->ecc);
+            }
+            return;
+        case NAND_ISR:
+            s->nand.isr = value;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_IMR:
+            s->nand.imr = value;
+            tc6393xb_nand_irq(s);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
+					(uint32_t) addr, value & 0xff);
+}
+
+#define BITS 8
+#include "tc6393xb_template.h"
+#define BITS 15
+#include "tc6393xb_template.h"
+#define BITS 16
+#include "tc6393xb_template.h"
+#define BITS 24
+#include "tc6393xb_template.h"
+#define BITS 32
+#include "tc6393xb_template.h"
+
+static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
+{
+    switch (ds_get_bits_per_pixel(s->ds)) {
+        case 8:
+            tc6393xb_draw_graphic8(s);
+            break;
+        case 15:
+            tc6393xb_draw_graphic15(s);
+            break;
+        case 16:
+            tc6393xb_draw_graphic16(s);
+            break;
+        case 24:
+            tc6393xb_draw_graphic24(s);
+            break;
+        case 32:
+            tc6393xb_draw_graphic32(s);
+            break;
+        default:
+            printf("tc6393xb: unknown depth %d\n", ds_get_bits_per_pixel(s->ds));
+            return;
+    }
+
+    dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
+{
+    int i, w;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+
+    w = s->scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+    d = ds_get_data(s->ds);
+    for(i = 0; i < s->scr_height; i++) {
+        memset(d, 0, w);
+        d += ds_get_linesize(s->ds);
+    }
+
+    dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_update_display(void *opaque)
+{
+    TC6393xbState *s = opaque;
+    int full_update;
+
+    if (s->scr_width == 0 || s->scr_height == 0)
+        return;
+
+    full_update = 0;
+    if (s->blanked != s->blank) {
+        s->blanked = s->blank;
+        full_update = 1;
+    }
+    if (s->scr_width != ds_get_width(s->ds) || s->scr_height != ds_get_height(s->ds)) {
+        qemu_console_resize(s->ds, s->scr_width, s->scr_height);
+        full_update = 1;
+    }
+    if (s->blanked)
+        tc6393xb_draw_blank(s, full_update);
+    else
+        tc6393xb_draw_graphic(s, full_update);
+}
+
+
+static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) {
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            return tc6393xb_scr_readb(s, addr & 0xff);
+        case 1:
+            return tc6393xb_nand_cfg_readb(s, addr & 0xff);
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
+//        return tc6393xb_nand_readb(s, addr & 0xff);
+        uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
+//        fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
+        return d;
+    }
+
+//    fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+
+static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) {
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            tc6393xb_scr_writeb(s, addr & 0xff, value);
+            return;
+        case 1:
+            tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
+            return;
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable)
+        tc6393xb_nand_writeb(s, addr & 0xff, value);
+    else
+        fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
+					(uint32_t) addr, value & 0xff);
+}
+
+static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr)
+{
+    return (tc6393xb_readb(opaque, addr) & 0xff) |
+        (tc6393xb_readb(opaque, addr + 1) << 8);
+}
+
+static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr)
+{
+    return (tc6393xb_readb(opaque, addr) & 0xff) |
+        ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) |
+        ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) |
+        ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24);
+}
+
+static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    tc6393xb_writeb(opaque, addr, value);
+    tc6393xb_writeb(opaque, addr + 1, value >> 8);
+}
+
+static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    tc6393xb_writeb(opaque, addr, value);
+    tc6393xb_writeb(opaque, addr + 1, value >> 8);
+    tc6393xb_writeb(opaque, addr + 2, value >> 16);
+    tc6393xb_writeb(opaque, addr + 3, value >> 24);
+}
+
+TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
+{
+    int iomemtype;
+    TC6393xbState *s;
+    CPUReadMemoryFunc * const tc6393xb_readfn[] = {
+        tc6393xb_readb,
+        tc6393xb_readw,
+        tc6393xb_readl,
+    };
+    CPUWriteMemoryFunc * const tc6393xb_writefn[] = {
+        tc6393xb_writeb,
+        tc6393xb_writew,
+        tc6393xb_writel,
+    };
+
+    s = (TC6393xbState *) qemu_mallocz(sizeof(TC6393xbState));
+    s->irq = irq;
+    s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
+
+    s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
+    s->blanked = 1;
+
+    s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
+
+    s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+
+    iomemtype = cpu_register_io_memory(tc6393xb_readfn,
+                    tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
+    cpu_register_physical_memory(base, 0x10000, iomemtype);
+
+    s->vram_addr = qemu_ram_alloc(NULL, "tc6393xb.vram", 0x100000);
+    s->vram_ptr = qemu_get_ram_ptr(s->vram_addr);
+    cpu_register_physical_memory(base + 0x100000, 0x100000, s->vram_addr);
+    s->scr_width = 480;
+    s->scr_height = 640;
+    s->ds = graphic_console_init(tc6393xb_update_display,
+            NULL, /* invalidate */
+            NULL, /* screen_dump */
+            NULL, /* text_update */
+            s);
+
+    return s;
+}
diff --git a/qemu-0.15.x/hw/tc6393xb_template.h b/qemu-0.15.x/hw/tc6393xb_template.h
new file mode 100644
index 0000000..1ccf6e8
--- /dev/null
+++ b/qemu-0.15.x/hw/tc6393xb_template.h
@@ -0,0 +1,67 @@
+/*
+ * Toshiba TC6393XB I/O Controller.
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
+ * Toshiba e-Series PDAs.
+ *
+ * FB support code. Based on G364 fb emulator
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if BITS == 8
+# define SET_PIXEL(addr, color)	*(uint8_t*)addr = color;
+#elif BITS == 15 || BITS == 16
+# define SET_PIXEL(addr, color)	*(uint16_t*)addr = color;
+#elif BITS == 24
+# define SET_PIXEL(addr, color)	\
+    addr[0] = color; addr[1] = (color) >> 8; addr[2] = (color) >> 16;
+#elif BITS == 32
+# define SET_PIXEL(addr, color)	*(uint32_t*)addr = color;
+#else
+# error unknown bit depth
+#endif
+
+
+static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
+{
+    int i;
+    uint16_t *data_buffer;
+    uint8_t *data_display;
+
+    data_buffer = s->vram_ptr;
+    data_display = ds_get_data(s->ds);
+    for(i = 0; i < s->scr_height; i++) {
+#if (BITS == 16)
+        memcpy(data_display, data_buffer, s->scr_width * 2);
+        data_buffer += s->scr_width;
+        data_display += ds_get_linesize(s->ds);
+#else
+        int j;
+        for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) {
+            uint16_t color = *data_buffer;
+            uint32_t dest_color = glue(rgb_to_pixel, BITS)(
+                           ((color & 0xf800) * 0x108) >> 11,
+                           ((color & 0x7e0) * 0x41) >> 9,
+                           ((color & 0x1f) * 0x21) >> 2
+                           );
+            SET_PIXEL(data_display, dest_color);
+        }
+#endif
+    }
+}
+
+#undef BITS
+#undef SET_PIXEL
diff --git a/qemu-0.15.x/hw/tcx.c b/qemu-0.15.x/hw/tcx.c
new file mode 100644
index 0000000..0e32830
--- /dev/null
+++ b/qemu-0.15.x/hw/tcx.c
@@ -0,0 +1,651 @@
+/*
+ * QEMU TCX Frame buffer
+ *
+ * Copyright (c) 2003-2005 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 "console.h"
+#include "pixel_ops.h"
+#include "sysbus.h"
+#include "qdev-addr.h"
+
+#define MAXX 1024
+#define MAXY 768
+#define TCX_DAC_NREGS 16
+#define TCX_THC_NREGS_8  0x081c
+#define TCX_THC_NREGS_24 0x1000
+#define TCX_TEC_NREGS    0x1000
+
+typedef struct TCXState {
+    SysBusDevice busdev;
+    target_phys_addr_t addr;
+    DisplayState *ds;
+    uint8_t *vram;
+    uint32_t *vram24, *cplane;
+    ram_addr_t vram_offset, vram24_offset, cplane_offset;
+    uint32_t vram_size;
+    uint16_t width, height, depth;
+    uint8_t r[256], g[256], b[256];
+    uint32_t palette[256];
+    uint8_t dac_index, dac_state;
+} TCXState;
+
+static void tcx_screen_dump(void *opaque, const char *filename);
+static void tcx24_screen_dump(void *opaque, const char *filename);
+
+static void tcx_set_dirty(TCXState *s)
+{
+    unsigned int i;
+
+    for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram_offset + i);
+    }
+}
+
+static void tcx24_set_dirty(TCXState *s)
+{
+    unsigned int i;
+
+    for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram24_offset + i);
+        cpu_physical_memory_set_dirty(s->cplane_offset + i);
+    }
+}
+
+static void update_palette_entries(TCXState *s, int start, int end)
+{
+    int i;
+    for(i = start; i < end; i++) {
+        switch(ds_get_bits_per_pixel(s->ds)) {
+        default:
+        case 8:
+            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 15:
+            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 16:
+            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 32:
+            if (is_surface_bgr(s->ds->surface))
+                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+            else
+                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
+            break;
+        }
+    }
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+}
+
+static void tcx_draw_line32(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint32_t *p = (uint32_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line16(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint16_t *p = (uint16_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line8(TCXState *s1, uint8_t *d,
+                           const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *d++ = s1->palette[val];
+    }
+}
+
+/*
+  XXX Could be much more optimal:
+  * detect if line/page/whole screen is in 24 bit mode
+  * if destination is also BGR, use memcpy
+  */
+static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
+                                     const uint8_t *s, int width,
+                                     const uint32_t *cplane,
+                                     const uint32_t *s24)
+{
+    int x, bgr, r, g, b;
+    uint8_t val, *p8;
+    uint32_t *p = (uint32_t *)d;
+    uint32_t dval;
+
+    bgr = is_surface_bgr(s1->ds->surface);
+    for(x = 0; x < width; x++, s++, s24++) {
+        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
+            // 24-bit direct, BGR order
+            p8 = (uint8_t *)s24;
+            p8++;
+            b = *p8++;
+            g = *p8++;
+            r = *p8;
+            if (bgr)
+                dval = rgb_to_pixel32bgr(r, g, b);
+            else
+                dval = rgb_to_pixel32(r, g, b);
+        } else {
+            val = *s;
+            dval = s1->palette[val];
+        }
+        *p++ = dval;
+    }
+}
+
+static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    int ret;
+    unsigned int off;
+
+    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
+        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
+        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+    }
+    return ret;
+}
+
+static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
+                               ram_addr_t page_max, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+    page_min -= ts->vram_offset;
+    page_max -= ts->vram_offset;
+    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
+                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
+                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+}
+
+/* Fixed line length 1024 allows us to do nice tricks not possible on
+   VGA... */
+static void tcx_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    ram_addr_t page, page_min, page_max;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
+
+    if (ds_get_bits_per_pixel(ts->ds) == 0)
+        return;
+    page = ts->vram_offset;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = ds_get_data(ts->ds);
+    s = ts->vram;
+    dd = ds_get_linesize(ts->ds);
+    ds = 1024;
+
+    switch (ds_get_bits_per_pixel(ts->ds)) {
+    case 32:
+        f = tcx_draw_line32;
+        break;
+    case 15:
+    case 16:
+        f = tcx_draw_line16;
+        break;
+    default:
+    case 8:
+        f = tcx_draw_line8;
+        break;
+    case 0:
+        return;
+    }
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
+        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(ts->ds, 0, y_start,
+                           ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(ts->ds, 0, y_start,
+                   ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+                                        VGA_DIRTY_FLAG);
+    }
+}
+
+static void tcx24_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    ram_addr_t page, page_min, page_max, cpage, page24;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    uint32_t *cptr, *s24;
+
+    if (ds_get_bits_per_pixel(ts->ds) != 32)
+            return;
+    page = ts->vram_offset;
+    page24 = ts->vram24_offset;
+    cpage = ts->cplane_offset;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = ds_get_data(ts->ds);
+    s = ts->vram;
+    s24 = ts->vram24;
+    cptr = ts->cplane;
+    dd = ds_get_linesize(ts->ds);
+    ds = 1024;
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
+            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
+        if (check_dirty(page, page24, cpage)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(ts->ds, 0, y_start,
+                           ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+            cptr += ds * 4;
+            s24 += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(ts->ds, 0, y_start,
+                   ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        reset_dirty(ts, page_min, page_max, page24, cpage);
+    }
+}
+
+static void tcx_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    qemu_console_resize(s->ds, s->width, s->height);
+}
+
+static void tcx24_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    tcx24_set_dirty(s);
+    qemu_console_resize(s->ds, s->width, s->height);
+}
+
+static int vmstate_tcx_post_load(void *opaque, int version_id)
+{
+    TCXState *s = opaque;
+
+    update_palette_entries(s, 0, 256);
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tcx = {
+    .name ="tcx",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = vmstate_tcx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(height, TCXState),
+        VMSTATE_UINT16(width, TCXState),
+        VMSTATE_UINT16(depth, TCXState),
+        VMSTATE_BUFFER(r, TCXState),
+        VMSTATE_BUFFER(g, TCXState),
+        VMSTATE_BUFFER(b, TCXState),
+        VMSTATE_UINT8(dac_index, TCXState),
+        VMSTATE_UINT8(dac_state, TCXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tcx_reset(DeviceState *d)
+{
+    TCXState *s = container_of(d, TCXState, busdev.qdev);
+
+    /* Initialize palette */
+    memset(s->r, 0, 256);
+    memset(s->g, 0, 256);
+    memset(s->b, 0, 256);
+    s->r[255] = s->g[255] = s->b[255] = 255;
+    update_palette_entries(s, 0, 256);
+    memset(s->vram, 0, MAXX*MAXY);
+    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
+                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
+    s->dac_index = 0;
+    s->dac_state = 0;
+}
+
+static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    TCXState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        s->dac_index = val >> 24;
+        s->dac_state = 0;
+        break;
+    case 4:
+        switch (s->dac_state) {
+        case 0:
+            s->r[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 1:
+            s->g[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 2:
+            s->b[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
+        default:
+            s->dac_state = 0;
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+    return;
+}
+
+static CPUReadMemoryFunc * const tcx_dac_read[3] = {
+    NULL,
+    NULL,
+    tcx_dac_readl,
+};
+
+static CPUWriteMemoryFunc * const tcx_dac_write[3] = {
+    NULL,
+    NULL,
+    tcx_dac_writel,
+};
+
+static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+}
+
+static CPUReadMemoryFunc * const tcx_dummy_read[3] = {
+    NULL,
+    NULL,
+    tcx_dummy_readl,
+};
+
+static CPUWriteMemoryFunc * const tcx_dummy_write[3] = {
+    NULL,
+    NULL,
+    tcx_dummy_writel,
+};
+
+static int tcx_init1(SysBusDevice *dev)
+{
+    TCXState *s = FROM_SYSBUS(TCXState, dev);
+    int io_memory, dummy_memory;
+    ram_addr_t vram_offset;
+    int size;
+    uint8_t *vram_base;
+
+    vram_offset = qemu_ram_alloc(NULL, "tcx.vram", s->vram_size * (1 + 4 + 4));
+    vram_base = qemu_get_ram_ptr(vram_offset);
+    s->vram_offset = vram_offset;
+
+    /* 8-bit plane */
+    s->vram = vram_base;
+    size = s->vram_size;
+    sysbus_init_mmio(dev, size, s->vram_offset);
+    vram_offset += size;
+    vram_base += size;
+
+    /* DAC */
+    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
+
+    /* TEC (dummy) */
+    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
+                                          s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
+    /* THC: NetBSD writes here even with 8-bit display: dummy */
+    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
+
+    if (s->depth == 24) {
+        /* 24-bit plane */
+        size = s->vram_size * 4;
+        s->vram24 = (uint32_t *)vram_base;
+        s->vram24_offset = vram_offset;
+        sysbus_init_mmio(dev, size, vram_offset);
+        vram_offset += size;
+        vram_base += size;
+
+        /* Control plane */
+        size = s->vram_size * 4;
+        s->cplane = (uint32_t *)vram_base;
+        s->cplane_offset = vram_offset;
+        sysbus_init_mmio(dev, size, vram_offset);
+
+        s->ds = graphic_console_init(tcx24_update_display,
+                                     tcx24_invalidate_display,
+                                     tcx24_screen_dump, NULL, s);
+    } else {
+        /* THC 8 bit (dummy) */
+        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
+
+        s->ds = graphic_console_init(tcx_update_display,
+                                     tcx_invalidate_display,
+                                     tcx_screen_dump, NULL, s);
+    }
+
+    qemu_console_resize(s->ds, s->width, s->height);
+    return 0;
+}
+
+static void tcx_screen_dump(void *opaque, const char *filename)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    int y, x;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return;
+    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    d1 = s->vram;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++) {
+            v = *d;
+            fputc(s->r[v], f);
+            fputc(s->g[v], f);
+            fputc(s->b[v], f);
+            d++;
+        }
+        d1 += MAXX;
+    }
+    fclose(f);
+    return;
+}
+
+static void tcx24_screen_dump(void *opaque, const char *filename)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    uint32_t *s24, *cptr, dval;
+    int y, x;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return;
+    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    d1 = s->vram;
+    s24 = s->vram24;
+    cptr = s->cplane;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++, d++, s24++) {
+            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
+                dval = *s24 & 0x00ffffff;
+                fputc((dval >> 16) & 0xff, f);
+                fputc((dval >> 8) & 0xff, f);
+                fputc(dval & 0xff, f);
+            } else {
+                v = *d;
+                fputc(s->r[v], f);
+                fputc(s->g[v], f);
+                fputc(s->b[v], f);
+            }
+        }
+        d1 += MAXX;
+    }
+    fclose(f);
+    return;
+}
+
+static SysBusDeviceInfo tcx_info = {
+    .init = tcx_init1,
+    .qdev.name  = "SUNW,tcx",
+    .qdev.size  = sizeof(TCXState),
+    .qdev.reset = tcx_reset,
+    .qdev.vmsd  = &vmstate_tcx,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
+        DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+        DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
+        DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
+        DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void tcx_register_devices(void)
+{
+    sysbus_register_withprop(&tcx_info);
+}
+
+device_init(tcx_register_devices)
diff --git a/qemu-0.15.x/hw/tmp105.c b/qemu-0.15.x/hw/tmp105.c
new file mode 100644
index 0000000..f7e6f2b
--- /dev/null
+++ b/qemu-0.15.x/hw/tmp105.c
@@ -0,0 +1,244 @@
+/*
+ * Texas Instruments TMP105 temperature sensor.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "i2c.h"
+
+typedef struct {
+    i2c_slave i2c;
+    uint8_t len;
+    uint8_t buf[2];
+    qemu_irq pin;
+
+    uint8_t pointer;
+    uint8_t config;
+    int16_t temperature;
+    int16_t limit[2];
+    int faults;
+    uint8_t alarm;
+} TMP105State;
+
+static void tmp105_interrupt_update(TMP105State *s)
+{
+    qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1));	/* POL */
+}
+
+static void tmp105_alarm_update(TMP105State *s)
+{
+    if ((s->config >> 0) & 1) {					/* SD */
+        if ((s->config >> 7) & 1)				/* OS */
+            s->config &= ~(1 << 7);				/* OS */
+        else
+            return;
+    }
+
+    if ((s->config >> 1) & 1) {					/* TM */
+        if (s->temperature >= s->limit[1])
+            s->alarm = 1;
+        else if (s->temperature < s->limit[0])
+            s->alarm = 1;
+    } else {
+        if (s->temperature >= s->limit[1])
+            s->alarm = 1;
+        else if (s->temperature < s->limit[0])
+            s->alarm = 0;
+    }
+
+    tmp105_interrupt_update(s);
+}
+
+/* Units are 0.001 centigrades relative to 0 C.  */
+void tmp105_set(i2c_slave *i2c, int temp)
+{
+    TMP105State *s = (TMP105State *) i2c;
+
+    if (temp >= 128000 || temp < -128000) {
+        fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
+                        __FUNCTION__, temp / 1000, temp % 1000);
+        exit(-1);
+    }
+
+    s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
+
+    tmp105_alarm_update(s);
+}
+
+static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
+
+static void tmp105_read(TMP105State *s)
+{
+    s->len = 0;
+
+    if ((s->config >> 1) & 1) {					/* TM */
+        s->alarm = 0;
+        tmp105_interrupt_update(s);
+    }
+
+    switch (s->pointer & 3) {
+    case 0:	/* Temperature */
+        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
+        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
+                (0xf0 << ((~s->config >> 5) & 3));		/* R */
+        break;
+
+    case 1:	/* Configuration */
+        s->buf[s->len ++] = s->config;
+        break;
+
+    case 2:	/* T_LOW */
+        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
+        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
+        break;
+
+    case 3:	/* T_HIGH */
+        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
+        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
+        break;
+    }
+}
+
+static void tmp105_write(TMP105State *s)
+{
+    switch (s->pointer & 3) {
+    case 0:	/* Temperature */
+        break;
+
+    case 1:	/* Configuration */
+        if (s->buf[0] & ~s->config & (1 << 0))			/* SD */
+            printf("%s: TMP105 shutdown\n", __FUNCTION__);
+        s->config = s->buf[0];
+        s->faults = tmp105_faultq[(s->config >> 3) & 3];	/* F */
+        tmp105_alarm_update(s);
+        break;
+
+    case 2:	/* T_LOW */
+    case 3:	/* T_HIGH */
+        if (s->len >= 3)
+            s->limit[s->pointer & 1] = (int16_t)
+                    ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
+        tmp105_alarm_update(s);
+        break;
+    }
+}
+
+static int tmp105_rx(i2c_slave *i2c)
+{
+    TMP105State *s = (TMP105State *) i2c;
+
+    if (s->len < 2)
+        return s->buf[s->len ++];
+    else
+        return 0xff;
+}
+
+static int tmp105_tx(i2c_slave *i2c, uint8_t data)
+{
+    TMP105State *s = (TMP105State *) i2c;
+
+    if (!s->len ++)
+        s->pointer = data;
+    else {
+        if (s->len <= 2)
+            s->buf[s->len - 1] = data;
+        tmp105_write(s);
+    }
+
+    return 0;
+}
+
+static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
+{
+    TMP105State *s = (TMP105State *) i2c;
+
+    if (event == I2C_START_RECV)
+        tmp105_read(s);
+
+    s->len = 0;
+}
+
+static int tmp105_post_load(void *opaque, int version_id)
+{
+    TMP105State *s = opaque;
+
+    s->faults = tmp105_faultq[(s->config >> 3) & 3];		/* F */
+
+    tmp105_interrupt_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_tmp105 = {
+    .name = "TMP105",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = tmp105_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(len, TMP105State),
+        VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
+        VMSTATE_UINT8(pointer, TMP105State),
+        VMSTATE_UINT8(config, TMP105State),
+        VMSTATE_INT16(temperature, TMP105State),
+        VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
+        VMSTATE_UINT8(alarm, TMP105State),
+        VMSTATE_I2C_SLAVE(i2c, TMP105State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tmp105_reset(i2c_slave *i2c)
+{
+    TMP105State *s = (TMP105State *) i2c;
+
+    s->temperature = 0;
+    s->pointer = 0;
+    s->config = 0;
+    s->faults = tmp105_faultq[(s->config >> 3) & 3];
+    s->alarm = 0;
+
+    tmp105_interrupt_update(s);
+}
+
+static int tmp105_init(i2c_slave *i2c)
+{
+    TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
+
+    qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
+
+    tmp105_reset(&s->i2c);
+
+    return 0;
+}
+
+static I2CSlaveInfo tmp105_info = {
+    .qdev.name = "tmp105",
+    .qdev.size = sizeof(TMP105State),
+    .qdev.vmsd = &vmstate_tmp105,
+    .init = tmp105_init,
+    .event = tmp105_event,
+    .recv = tmp105_rx,
+    .send = tmp105_tx
+};
+
+static void tmp105_register_devices(void)
+{
+    i2c_register_slave(&tmp105_info);
+}
+
+device_init(tmp105_register_devices)
diff --git a/qemu-0.15.x/hw/tosa.c b/qemu-0.15.x/hw/tosa.c
new file mode 100644
index 0000000..a7967a2
--- /dev/null
+++ b/qemu-0.15.x/hw/tosa.c
@@ -0,0 +1,280 @@
+/* vim:set shiftwidth=4 ts=4 et: */
+/*
+ * PXA255 Sharp Zaurus SL-6000 PDA platform
+ *
+ * Copyright (c) 2008 Dmitry Baryshkov
+ *
+ * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "sharpsl.h"
+#include "pcmcia.h"
+#include "block.h"
+#include "boards.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "blockdev.h"
+#include "sysbus.h"
+
+#define TOSA_RAM    0x04000000
+#define TOSA_ROM	0x00800000
+
+#define TOSA_GPIO_USB_IN		(5)
+#define TOSA_GPIO_nSD_DETECT	(9)
+#define TOSA_GPIO_ON_RESET		(19)
+#define TOSA_GPIO_CF_IRQ		(21)	/* CF slot0 Ready */
+#define TOSA_GPIO_CF_CD			(13)
+#define TOSA_GPIO_TC6393XB_INT  (15)
+#define TOSA_GPIO_JC_CF_IRQ		(36)	/* CF slot1 Ready */
+
+#define TOSA_SCOOP_GPIO_BASE	1
+#define TOSA_GPIO_IR_POWERDWN	(TOSA_SCOOP_GPIO_BASE + 2)
+#define TOSA_GPIO_SD_WP			(TOSA_SCOOP_GPIO_BASE + 3)
+#define TOSA_GPIO_PWR_ON		(TOSA_SCOOP_GPIO_BASE + 4)
+
+#define TOSA_SCOOP_JC_GPIO_BASE		1
+#define TOSA_GPIO_BT_LED		(TOSA_SCOOP_JC_GPIO_BASE + 0)
+#define TOSA_GPIO_NOTE_LED		(TOSA_SCOOP_JC_GPIO_BASE + 1)
+#define TOSA_GPIO_CHRG_ERR_LED		(TOSA_SCOOP_JC_GPIO_BASE + 2)
+#define TOSA_GPIO_TC6393XB_L3V_ON	(TOSA_SCOOP_JC_GPIO_BASE + 5)
+#define TOSA_GPIO_WLAN_LED		(TOSA_SCOOP_JC_GPIO_BASE + 7)
+
+#define	DAC_BASE	0x4e
+#define DAC_CH1		0
+#define DAC_CH2		1
+
+static void tosa_microdrive_attach(PXA2xxState *cpu)
+{
+    PCMCIACardState *md;
+    BlockDriverState *bs;
+    DriveInfo *dinfo;
+
+    dinfo = drive_get(IF_IDE, 0, 0);
+    if (!dinfo)
+        return;
+    bs = dinfo->bdrv;
+    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
+        md = dscm1xxxx_init(dinfo);
+        pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
+    }
+}
+
+static void tosa_out_switch(void *opaque, int line, int level)
+{
+    switch (line) {
+        case 0:
+            fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
+            break;
+        case 1:
+            fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
+            break;
+        case 2:
+            fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
+            break;
+        case 3:
+            fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
+            break;
+        default:
+            fprintf(stderr, "Uhandled out event: %d = %d\n", line, level);
+            break;
+    }
+}
+
+
+static void tosa_gpio_setup(PXA2xxState *cpu,
+                DeviceState *scp0,
+                DeviceState *scp1,
+                TC6393xbState *tmio)
+{
+    qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc,
+                    qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
+                    qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
+
+    /* Handle reset */
+    qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
+
+    /* PCMCIA signals: card's IRQ and Card-Detect */
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
+
+    pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
+                        qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
+                        NULL);
+
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
+
+    qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
+
+    /* UDC Vbus */
+    qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
+}
+
+static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
+{
+    fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f);
+    return 0;
+}
+
+static int tosa_ssp_init(SSISlave *dev)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+typedef struct {
+    i2c_slave i2c;
+    int len;
+    char buf[3];
+} TosaDACState;
+
+static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
+{
+    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
+    s->buf[s->len] = data;
+    if (s->len ++ > 2) {
+#ifdef VERBOSE
+        fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        return 1;
+    }
+
+    if (s->len == 2) {
+        fprintf(stderr, "dac: channel %d value 0x%02x\n",
+                s->buf[0], s->buf[1]);
+    }
+
+    return 0;
+}
+
+static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
+{
+    TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
+    s->len = 0;
+    switch (event) {
+    case I2C_START_SEND:
+        break;
+    case I2C_START_RECV:
+        printf("%s: recv not supported!!!\n", __FUNCTION__);
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->len < 2)
+            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+        if (s->len > 2)
+            printf("%s: message too long\n", __FUNCTION__);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+static int tosa_dac_recv(i2c_slave *s)
+{
+    printf("%s: recv not supported!!!\n", __FUNCTION__);
+    return -1;
+}
+
+static int tosa_dac_init(i2c_slave *i2c)
+{
+    /* Nothing to do.  */
+    return 0;
+}
+
+static void tosa_tg_init(PXA2xxState *cpu)
+{
+    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+    i2c_create_slave(bus, "tosa_dac", DAC_BASE);
+    ssi_create_slave(cpu->ssp[1], "tosa-ssp");
+}
+
+
+static struct arm_boot_info tosa_binfo = {
+    .loader_start = PXA2XX_SDRAM_BASE,
+    .ram_size = 0x04000000,
+};
+
+static void tosa_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    PXA2xxState *cpu;
+    TC6393xbState *tmio;
+    DeviceState *scp0, *scp1;
+
+    if (!cpu_model)
+        cpu_model = "pxa255";
+
+    cpu = pxa255_init(tosa_binfo.ram_size);
+
+    cpu_register_physical_memory(0, TOSA_ROM,
+                    qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
+
+    tmio = tc6393xb_init(0x10000000,
+            qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT));
+
+    scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
+    scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
+
+    tosa_gpio_setup(cpu, scp0, scp1, tmio);
+
+    tosa_microdrive_attach(cpu);
+
+    tosa_tg_init(cpu);
+
+    tosa_binfo.kernel_filename = kernel_filename;
+    tosa_binfo.kernel_cmdline = kernel_cmdline;
+    tosa_binfo.initrd_filename = initrd_filename;
+    tosa_binfo.board_id = 0x208;
+    arm_load_kernel(cpu->env, &tosa_binfo);
+    sl_bootparam_write(SL_PXA_PARAM_BASE);
+}
+
+static QEMUMachine tosapda_machine = {
+    .name = "tosa",
+    .desc = "Tosa PDA (PXA255)",
+    .init = tosa_init,
+};
+
+static void tosapda_machine_init(void)
+{
+    qemu_register_machine(&tosapda_machine);
+}
+
+machine_init(tosapda_machine_init);
+
+static I2CSlaveInfo tosa_dac_info = {
+    .qdev.name = "tosa_dac",
+    .qdev.size = sizeof(TosaDACState),
+    .init = tosa_dac_init,
+    .event = tosa_dac_event,
+    .recv = tosa_dac_recv,
+    .send = tosa_dac_send
+};
+
+static SSISlaveInfo tosa_ssp_info = {
+    .qdev.name = "tosa-ssp",
+    .qdev.size = sizeof(SSISlave),
+    .init = tosa_ssp_init,
+    .transfer = tosa_ssp_tansfer
+};
+
+static void tosa_register_devices(void)
+{
+    i2c_register_slave(&tosa_dac_info);
+    ssi_register_slave(&tosa_ssp_info);
+}
+
+device_init(tosa_register_devices)
diff --git a/qemu-0.15.x/hw/tsc2005.c b/qemu-0.15.x/hw/tsc2005.c
new file mode 100644
index 0000000..c95dcf0
--- /dev/null
+++ b/qemu-0.15.x/hw/tsc2005.c
@@ -0,0 +1,593 @@
+/*
+ * TI TSC2005 emulator.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "devices.h"
+
+#define TSC_CUT_RESOLUTION(value, p)	((value) >> (16 - (p ? 12 : 10)))
+
+typedef struct {
+    qemu_irq pint;	/* Combination of the nPENIRQ and DAV signals */
+    QEMUTimer *timer;
+    uint16_t model;
+
+    int x, y;
+    int pressure;
+
+    int state, reg, irq, command;
+    uint16_t data, dav;
+
+    int busy;
+    int enabled;
+    int host_mode;
+    int function;
+    int nextfunction;
+    int precision;
+    int nextprecision;
+    int filter;
+    int pin_func;
+    int timing[2];
+    int noise;
+    int reset;
+    int pdst;
+    int pnd0;
+    uint16_t temp_thr[2];
+    uint16_t aux_thr[2];
+
+    int tr[8];
+} TSC2005State;
+
+enum {
+    TSC_MODE_XYZ_SCAN	= 0x0,
+    TSC_MODE_XY_SCAN,
+    TSC_MODE_X,
+    TSC_MODE_Y,
+    TSC_MODE_Z,
+    TSC_MODE_AUX,
+    TSC_MODE_TEMP1,
+    TSC_MODE_TEMP2,
+    TSC_MODE_AUX_SCAN,
+    TSC_MODE_X_TEST,
+    TSC_MODE_Y_TEST,
+    TSC_MODE_TS_TEST,
+    TSC_MODE_RESERVED,
+    TSC_MODE_XX_DRV,
+    TSC_MODE_YY_DRV,
+    TSC_MODE_YX_DRV,
+};
+
+static const uint16_t mode_regs[16] = {
+    0xf000,	/* X, Y, Z scan */
+    0xc000,	/* X, Y scan */
+    0x8000,	/* X */
+    0x4000,	/* Y */
+    0x3000,	/* Z */
+    0x0800,	/* AUX */
+    0x0400,	/* TEMP1 */
+    0x0200,	/* TEMP2 */
+    0x0800,	/* AUX scan */
+    0x0040,	/* X test */
+    0x0020,	/* Y test */
+    0x0080,	/* Short-circuit test */
+    0x0000,	/* Reserved */
+    0x0000,	/* X+, X- drivers */
+    0x0000,	/* Y+, Y- drivers */
+    0x0000,	/* Y+, X- drivers */
+};
+
+#define X_TRANSFORM(s)			\
+    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
+#define Y_TRANSFORM(s)			\
+    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+#define Z1_TRANSFORM(s)			\
+    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+#define Z2_TRANSFORM(s)			\
+    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+
+#define AUX_VAL				(700 << 4)	/* +/- 3 at 12-bit */
+#define TEMP1_VAL			(1264 << 4)	/* +/- 5 at 12-bit */
+#define TEMP2_VAL			(1531 << 4)	/* +/- 5 at 12-bit */
+
+static uint16_t tsc2005_read(TSC2005State *s, int reg)
+{
+    uint16_t ret;
+
+    switch (reg) {
+    case 0x0:	/* X */
+        s->dav &= ~mode_regs[TSC_MODE_X];
+        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+                (s->noise & 3);
+    case 0x1:	/* Y */
+        s->dav &= ~mode_regs[TSC_MODE_Y];
+        s->noise ++;
+        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+                (s->noise & 3);
+    case 0x2:	/* Z1 */
+        s->dav &= 0xdfff;
+        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+                (s->noise & 3);
+    case 0x3:	/* Z2 */
+        s->dav &= 0xefff;
+        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+                (s->noise & 3);
+
+    case 0x4:	/* AUX */
+        s->dav &= ~mode_regs[TSC_MODE_AUX];
+        return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
+
+    case 0x5:	/* TEMP1 */
+        s->dav &= ~mode_regs[TSC_MODE_TEMP1];
+        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+                (s->noise & 5);
+    case 0x6:	/* TEMP2 */
+        s->dav &= 0xdfff;
+        s->dav &= ~mode_regs[TSC_MODE_TEMP2];
+        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+                (s->noise & 3);
+
+    case 0x7:	/* Status */
+        ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
+        s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
+                        mode_regs[TSC_MODE_TS_TEST]);
+        s->reset = 1;
+        return ret;
+
+    case 0x8:	/* AUX high treshold */
+        return s->aux_thr[1];
+    case 0x9:	/* AUX low treshold */
+        return s->aux_thr[0];
+
+    case 0xa:	/* TEMP high treshold */
+        return s->temp_thr[1];
+    case 0xb:	/* TEMP low treshold */
+        return s->temp_thr[0];
+
+    case 0xc:	/* CFR0 */
+        return (s->pressure << 15) | ((!s->busy) << 14) |
+                (s->nextprecision << 13) | s->timing[0]; 
+    case 0xd:	/* CFR1 */
+        return s->timing[1];
+    case 0xe:	/* CFR2 */
+        return (s->pin_func << 14) | s->filter;
+
+    case 0xf:	/* Function select status */
+        return s->function >= 0 ? 1 << s->function : 0;
+    }
+
+    /* Never gets here */
+    return 0xffff;
+}
+
+static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
+{
+    switch (reg) {
+    case 0x8:	/* AUX high treshold */
+        s->aux_thr[1] = data;
+        break;
+    case 0x9:	/* AUX low treshold */
+        s->aux_thr[0] = data;
+        break;
+
+    case 0xa:	/* TEMP high treshold */
+        s->temp_thr[1] = data;
+        break;
+    case 0xb:	/* TEMP low treshold */
+        s->temp_thr[0] = data;
+        break;
+
+    case 0xc:	/* CFR0 */
+        s->host_mode = data >> 15;
+        if (s->enabled != !(data & 0x4000)) {
+            s->enabled = !(data & 0x4000);
+            fprintf(stderr, "%s: touchscreen sense %sabled\n",
+                            __FUNCTION__, s->enabled ? "en" : "dis");
+            if (s->busy && !s->enabled)
+                qemu_del_timer(s->timer);
+            s->busy &= s->enabled;
+        }
+        s->nextprecision = (data >> 13) & 1;
+        s->timing[0] = data & 0x1fff;
+        if ((s->timing[0] >> 11) == 3)
+            fprintf(stderr, "%s: illegal conversion clock setting\n",
+                            __FUNCTION__);
+        break;
+    case 0xd:	/* CFR1 */
+        s->timing[1] = data & 0xf07;
+        break;
+    case 0xe:	/* CFR2 */
+        s->pin_func = (data >> 14) & 3;
+        s->filter = data & 0x3fff;
+        break;
+
+    default:
+        fprintf(stderr, "%s: write into read-only register %x\n",
+                        __FUNCTION__, reg);
+    }
+}
+
+/* This handles most of the chip's logic.  */
+static void tsc2005_pin_update(TSC2005State *s)
+{
+    int64_t expires;
+    int pin_state;
+
+    switch (s->pin_func) {
+    case 0:
+        pin_state = !s->pressure && !!s->dav;
+        break;
+    case 1:
+    case 3:
+    default:
+        pin_state = !s->dav;
+        break;
+    case 2:
+        pin_state = !s->pressure;
+    }
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, s->irq);
+    }
+
+    switch (s->nextfunction) {
+    case TSC_MODE_XYZ_SCAN:
+    case TSC_MODE_XY_SCAN:
+        if (!s->host_mode && s->dav)
+            s->enabled = 0;
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_AUX_SCAN:
+        break;
+
+    case TSC_MODE_X:
+    case TSC_MODE_Y:
+    case TSC_MODE_Z:
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_AUX:
+    case TSC_MODE_TEMP1:
+    case TSC_MODE_TEMP2:
+    case TSC_MODE_X_TEST:
+    case TSC_MODE_Y_TEST:
+    case TSC_MODE_TS_TEST:
+        if (s->dav)
+            s->enabled = 0;
+        break;
+
+    case TSC_MODE_RESERVED:
+    case TSC_MODE_XX_DRV:
+    case TSC_MODE_YY_DRV:
+    case TSC_MODE_YX_DRV:
+    default:
+        return;
+    }
+
+    if (!s->enabled || s->busy)
+        return;
+
+    s->busy = 1;
+    s->precision = s->nextprecision;
+    s->function = s->nextfunction;
+    s->pdst = !s->pnd0;	/* Synchronised on internal clock */
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 7);
+    qemu_mod_timer(s->timer, expires);
+}
+
+static void tsc2005_reset(TSC2005State *s)
+{
+    s->state = 0;
+    s->pin_func = 0;
+    s->enabled = 0;
+    s->busy = 0;
+    s->nextprecision = 0;
+    s->nextfunction = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->irq = 0;
+    s->dav = 0;
+    s->reset = 0;
+    s->pdst = 1;
+    s->pnd0 = 0;
+    s->function = -1;
+    s->temp_thr[0] = 0x000;
+    s->temp_thr[1] = 0xfff;
+    s->aux_thr[0] = 0x000;
+    s->aux_thr[1] = 0xfff;
+
+    tsc2005_pin_update(s);
+}
+
+static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
+{
+    TSC2005State *s = opaque;
+    uint32_t ret = 0;
+
+    switch (s->state ++) {
+    case 0:
+        if (value & 0x80) {
+            /* Command */
+            if (value & (1 << 1))
+                tsc2005_reset(s);
+            else {
+                s->nextfunction = (value >> 3) & 0xf;
+                s->nextprecision = (value >> 2) & 1;
+                if (s->enabled != !(value & 1)) {
+                    s->enabled = !(value & 1);
+                    fprintf(stderr, "%s: touchscreen sense %sabled\n",
+                                    __FUNCTION__, s->enabled ? "en" : "dis");
+                    if (s->busy && !s->enabled)
+                        qemu_del_timer(s->timer);
+                    s->busy &= s->enabled;
+                }
+                tsc2005_pin_update(s);
+            }
+
+            s->state = 0;
+        } else if (value) {
+            /* Data transfer */
+            s->reg = (value >> 3) & 0xf;
+            s->pnd0 = (value >> 1) & 1;
+            s->command = value & 1;
+
+            if (s->command) {
+                /* Read */
+                s->data = tsc2005_read(s, s->reg);
+                tsc2005_pin_update(s);
+            } else
+                s->data = 0;
+        } else
+            s->state = 0;
+        break;
+
+    case 1:
+        if (s->command)
+            ret = (s->data >> 8) & 0xff;
+        else
+            s->data |= value << 8;
+        break;
+
+    case 2:
+        if (s->command)
+            ret = s->data & 0xff;
+        else {
+            s->data |= value;
+            tsc2005_write(s, s->reg, s->data);
+            tsc2005_pin_update(s);
+        }
+
+        s->state = 0;
+        break;
+    }
+
+    return ret;
+}
+
+uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
+{
+    uint32_t ret = 0;
+
+    len &= ~7;
+    while (len > 0) {
+        len -= 8;
+        ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
+    }
+
+    return ret;
+}
+
+static void tsc2005_timer_tick(void *opaque)
+{
+    TSC2005State *s = opaque;
+
+    /* Timer ticked -- a set of conversions has been finished.  */
+
+    if (!s->busy)
+        return;
+
+    s->busy = 0;
+    s->dav |= mode_regs[s->function];
+    s->function = -1;
+    tsc2005_pin_update(s);
+}
+
+static void tsc2005_touchscreen_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    TSC2005State *s = opaque;
+    int p = s->pressure;
+
+    if (buttons_state) {
+        s->x = x;
+        s->y = y;
+    }
+    s->pressure = !!buttons_state;
+
+    /*
+     * Note: We would get better responsiveness in the guest by
+     * signaling TS events immediately, but for now we simulate
+     * the first conversion delay for sake of correctness.
+     */
+    if (p != s->pressure)
+        tsc2005_pin_update(s);
+}
+
+static void tsc2005_save(QEMUFile *f, void *opaque)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+    int i;
+
+    qemu_put_be16(f, s->x);
+    qemu_put_be16(f, s->y);
+    qemu_put_byte(f, s->pressure);
+
+    qemu_put_byte(f, s->state);
+    qemu_put_byte(f, s->reg);
+    qemu_put_byte(f, s->command);
+
+    qemu_put_byte(f, s->irq);
+    qemu_put_be16s(f, &s->dav);
+    qemu_put_be16s(f, &s->data);
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_byte(f, s->enabled);
+    qemu_put_byte(f, s->host_mode);
+    qemu_put_byte(f, s->function);
+    qemu_put_byte(f, s->nextfunction);
+    qemu_put_byte(f, s->precision);
+    qemu_put_byte(f, s->nextprecision);
+    qemu_put_be16(f, s->filter);
+    qemu_put_byte(f, s->pin_func);
+    qemu_put_be16(f, s->timing[0]);
+    qemu_put_be16(f, s->timing[1]);
+    qemu_put_be16s(f, &s->temp_thr[0]);
+    qemu_put_be16s(f, &s->temp_thr[1]);
+    qemu_put_be16s(f, &s->aux_thr[0]);
+    qemu_put_be16s(f, &s->aux_thr[1]);
+    qemu_put_be32(f, s->noise);
+    qemu_put_byte(f, s->reset);
+    qemu_put_byte(f, s->pdst);
+    qemu_put_byte(f, s->pnd0);
+
+    for (i = 0; i < 8; i ++)
+        qemu_put_be32(f, s->tr[i]);
+}
+
+static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+    int i;
+
+    s->x = qemu_get_be16(f);
+    s->y = qemu_get_be16(f);
+    s->pressure = qemu_get_byte(f);
+
+    s->state = qemu_get_byte(f);
+    s->reg = qemu_get_byte(f);
+    s->command = qemu_get_byte(f);
+
+    s->irq = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dav);
+    qemu_get_be16s(f, &s->data);
+
+    qemu_get_timer(f, s->timer);
+    s->enabled = qemu_get_byte(f);
+    s->host_mode = qemu_get_byte(f);
+    s->function = qemu_get_byte(f);
+    s->nextfunction = qemu_get_byte(f);
+    s->precision = qemu_get_byte(f);
+    s->nextprecision = qemu_get_byte(f);
+    s->filter = qemu_get_be16(f);
+    s->pin_func = qemu_get_byte(f);
+    s->timing[0] = qemu_get_be16(f);
+    s->timing[1] = qemu_get_be16(f);
+    qemu_get_be16s(f, &s->temp_thr[0]);
+    qemu_get_be16s(f, &s->temp_thr[1]);
+    qemu_get_be16s(f, &s->aux_thr[0]);
+    qemu_get_be16s(f, &s->aux_thr[1]);
+    s->noise = qemu_get_be32(f);
+    s->reset = qemu_get_byte(f);
+    s->pdst = qemu_get_byte(f);
+    s->pnd0 = qemu_get_byte(f);
+
+    for (i = 0; i < 8; i ++)
+        s->tr[i] = qemu_get_be32(f);
+
+    s->busy = qemu_timer_pending(s->timer);
+    tsc2005_pin_update(s);
+
+    return 0;
+}
+
+void *tsc2005_init(qemu_irq pintdav)
+{
+    TSC2005State *s;
+
+    s = (TSC2005State *)
+            qemu_mallocz(sizeof(TSC2005State));
+    s->x = 400;
+    s->y = 240;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc2005_timer_tick, s);
+    s->pint = pintdav;
+    s->model = 0x2005;
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    tsc2005_reset(s);
+
+    qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
+                    "QEMU TSC2005-driven Touchscreen");
+
+    qemu_register_reset((void *) tsc2005_reset, s);
+    register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
+
+    return s;
+}
+
+/*
+ * Use tslib generated calibration data to generate ADC input values
+ * from the touchscreen.  Assuming 12-bit precision was used during
+ * tslib calibration.
+ */
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+
+    /* This version assumes touchscreen X & Y axis are parallel or
+     * perpendicular to LCD's  X & Y axis in some way.  */
+    if (abs(info->a[0]) > abs(info->a[1])) {
+        s->tr[0] = 0;
+        s->tr[1] = -info->a[6] * info->x;
+        s->tr[2] = info->a[0];
+        s->tr[3] = -info->a[2] / info->a[0];
+        s->tr[4] = info->a[6] * info->y;
+        s->tr[5] = 0;
+        s->tr[6] = info->a[4];
+        s->tr[7] = -info->a[5] / info->a[4];
+    } else {
+        s->tr[0] = info->a[6] * info->y;
+        s->tr[1] = 0;
+        s->tr[2] = info->a[1];
+        s->tr[3] = -info->a[2] / info->a[1];
+        s->tr[4] = 0;
+        s->tr[5] = -info->a[6] * info->x;
+        s->tr[6] = info->a[3];
+        s->tr[7] = -info->a[5] / info->a[3];
+    }
+
+    s->tr[0] >>= 11;
+    s->tr[1] >>= 11;
+    s->tr[3] <<= 4;
+    s->tr[4] >>= 11;
+    s->tr[5] >>= 11;
+    s->tr[7] <<= 4;
+}
diff --git a/qemu-0.15.x/hw/tsc210x.c b/qemu-0.15.x/hw/tsc210x.c
new file mode 100644
index 0000000..96446dd
--- /dev/null
+++ b/qemu-0.15.x/hw/tsc210x.c
@@ -0,0 +1,1293 @@
+/*
+ * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
+ * TI TSC2301 (touchscreen/sensors/keypad).
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog at zabor.org>
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "omap.h"	/* For I2SCodec and uWireSlave */
+#include "devices.h"
+
+#define TSC_DATA_REGISTERS_PAGE		0x0
+#define TSC_CONTROL_REGISTERS_PAGE	0x1
+#define TSC_AUDIO_REGISTERS_PAGE	0x2
+
+#define TSC_VERBOSE
+
+#define TSC_CUT_RESOLUTION(value, p)	((value) >> (16 - resolution[p]))
+
+typedef struct {
+    qemu_irq pint;
+    qemu_irq kbint;
+    qemu_irq davint;
+    QEMUTimer *timer;
+    QEMUSoundCard card;
+    uWireSlave chip;
+    I2SCodec codec;
+    uint8_t in_fifo[16384];
+    uint8_t out_fifo[16384];
+    uint16_t model;
+
+    int x, y;
+    int pressure;
+
+    int state, page, offset, irq;
+    uint16_t command, dav;
+
+    int busy;
+    int enabled;
+    int host_mode;
+    int function;
+    int nextfunction;
+    int precision;
+    int nextprecision;
+    int filter;
+    int pin_func;
+    int ref;
+    int timing;
+    int noise;
+
+    uint16_t audio_ctrl1;
+    uint16_t audio_ctrl2;
+    uint16_t audio_ctrl3;
+    uint16_t pll[3];
+    uint16_t volume;
+    int64_t volume_change;
+    int softstep;
+    uint16_t dac_power;
+    int64_t powerdown;
+    uint16_t filter_data[0x14];
+
+    const char *name;
+    SWVoiceIn *adc_voice[1];
+    SWVoiceOut *dac_voice[1];
+    int i2s_rx_rate;
+    int i2s_tx_rate;
+
+    int tr[8];
+
+    struct {
+        uint16_t down;
+        uint16_t mask;
+        int scan;
+        int debounce;
+        int mode;
+        int intr;
+    } kb;
+} TSC210xState;
+
+static const int resolution[4] = { 12, 8, 10, 12 };
+
+#define TSC_MODE_NO_SCAN	0x0
+#define TSC_MODE_XY_SCAN	0x1
+#define TSC_MODE_XYZ_SCAN	0x2
+#define TSC_MODE_X		0x3
+#define TSC_MODE_Y		0x4
+#define TSC_MODE_Z		0x5
+#define TSC_MODE_BAT1		0x6
+#define TSC_MODE_BAT2		0x7
+#define TSC_MODE_AUX		0x8
+#define TSC_MODE_AUX_SCAN	0x9
+#define TSC_MODE_TEMP1		0xa
+#define TSC_MODE_PORT_SCAN	0xb
+#define TSC_MODE_TEMP2		0xc
+#define TSC_MODE_XX_DRV		0xd
+#define TSC_MODE_YY_DRV		0xe
+#define TSC_MODE_YX_DRV		0xf
+
+static const uint16_t mode_regs[16] = {
+    0x0000,	/* No scan */
+    0x0600,	/* X, Y scan */
+    0x0780,	/* X, Y, Z scan */
+    0x0400,	/* X */
+    0x0200,	/* Y */
+    0x0180,	/* Z */
+    0x0040,	/* BAT1 */
+    0x0030,	/* BAT2 */
+    0x0010,	/* AUX */
+    0x0010,	/* AUX scan */
+    0x0004,	/* TEMP1 */
+    0x0070,	/* Port scan */
+    0x0002,	/* TEMP2 */
+    0x0000,	/* X+, X- drivers */
+    0x0000,	/* Y+, Y- drivers */
+    0x0000,	/* Y+, X- drivers */
+};
+
+#define X_TRANSFORM(s)			\
+    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
+#define Y_TRANSFORM(s)			\
+    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+#define Z1_TRANSFORM(s)			\
+    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+#define Z2_TRANSFORM(s)			\
+    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+
+#define BAT1_VAL			0x8660
+#define BAT2_VAL			0x0000
+#define AUX1_VAL			0x35c0
+#define AUX2_VAL			0xffff
+#define TEMP1_VAL			0x8c70
+#define TEMP2_VAL			0xa5b0
+
+#define TSC_POWEROFF_DELAY		50
+#define TSC_SOFTSTEP_DELAY		50
+
+static void tsc210x_reset(TSC210xState *s)
+{
+    s->state = 0;
+    s->pin_func = 2;
+    s->enabled = 0;
+    s->busy = 0;
+    s->nextfunction = 0;
+    s->ref = 0;
+    s->timing = 0;
+    s->irq = 0;
+    s->dav = 0;
+
+    s->audio_ctrl1 = 0x0000;
+    s->audio_ctrl2 = 0x4410;
+    s->audio_ctrl3 = 0x0000;
+    s->pll[0] = 0x1004;
+    s->pll[1] = 0x0000;
+    s->pll[2] = 0x1fff;
+    s->volume = 0xffff;
+    s->dac_power = 0x8540;
+    s->softstep = 1;
+    s->volume_change = 0;
+    s->powerdown = 0;
+    s->filter_data[0x00] = 0x6be3;
+    s->filter_data[0x01] = 0x9666;
+    s->filter_data[0x02] = 0x675d;
+    s->filter_data[0x03] = 0x6be3;
+    s->filter_data[0x04] = 0x9666;
+    s->filter_data[0x05] = 0x675d;
+    s->filter_data[0x06] = 0x7d83;
+    s->filter_data[0x07] = 0x84ee;
+    s->filter_data[0x08] = 0x7d83;
+    s->filter_data[0x09] = 0x84ee;
+    s->filter_data[0x0a] = 0x6be3;
+    s->filter_data[0x0b] = 0x9666;
+    s->filter_data[0x0c] = 0x675d;
+    s->filter_data[0x0d] = 0x6be3;
+    s->filter_data[0x0e] = 0x9666;
+    s->filter_data[0x0f] = 0x675d;
+    s->filter_data[0x10] = 0x7d83;
+    s->filter_data[0x11] = 0x84ee;
+    s->filter_data[0x12] = 0x7d83;
+    s->filter_data[0x13] = 0x84ee;
+
+    s->i2s_tx_rate = 0;
+    s->i2s_rx_rate = 0;
+
+    s->kb.scan = 1;
+    s->kb.debounce = 0;
+    s->kb.mask = 0x0000;
+    s->kb.mode = 3;
+    s->kb.intr = 0;
+
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+    qemu_irq_raise(s->kbint);
+}
+
+typedef struct {
+    int rate;
+    int dsor;
+    int fsref;
+} TSC210xRateInfo;
+
+/*  { rate,  dsor,  fsref } */
+static const TSC210xRateInfo tsc2101_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,	7,	1 },
+    { 8000,	7,	0 },
+    /* Fsref / 5.5 */
+    { 8018,	6,	1 },
+    { 8727,	6,	0 },
+    /* Fsref / 5.0 */
+    { 8820,	5,	1 },
+    { 9600,	5,	0 },
+    /* Fsref / 4.0 */
+    { 11025,	4,	1 },
+    { 12000,	4,	0 },
+    /* Fsref / 3.0 */
+    { 14700,	3,	1 },
+    { 16000,	3,	0 },
+    /* Fsref / 2.0 */
+    { 22050,	2,	1 },
+    { 24000,	2,	0 },
+    /* Fsref / 1.5 */
+    { 29400,	1,	1 },
+    { 32000,	1,	0 },
+    /* Fsref */
+    { 44100,	0,	1 },
+    { 48000,	0,	0 },
+
+    { 0,	0, 	0 },
+};
+
+/*  { rate,   dsor, fsref }	*/
+static const TSC210xRateInfo tsc2102_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,	63,	1 },
+    { 8000,	63,	0 },
+    /* Fsref / 6.0 */
+    { 7350,	54,	1 },
+    { 8000,	54,	0 },
+    /* Fsref / 5.0 */
+    { 8820,	45,	1 },
+    { 9600,	45,	0 },
+    /* Fsref / 4.0 */
+    { 11025,	36,	1 },
+    { 12000,	36,	0 },
+    /* Fsref / 3.0 */
+    { 14700,	27,	1 },
+    { 16000,	27,	0 },
+    /* Fsref / 2.0 */
+    { 22050,	18,	1 },
+    { 24000,	18,	0 },
+    /* Fsref / 1.5 */
+    { 29400,	9,	1 },
+    { 32000,	9,	0 },
+    /* Fsref */
+    { 44100,	0,	1 },
+    { 48000,	0,	0 },
+
+    { 0,	0, 	0 },
+};
+
+static inline void tsc210x_out_flush(TSC210xState *s, int len)
+{
+    uint8_t *data = s->codec.out.fifo + s->codec.out.start;
+    uint8_t *end = data + len;
+
+    while (data < end)
+        data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
+
+    s->codec.out.len -= len;
+    if (s->codec.out.len)
+        memmove(s->codec.out.fifo, end, s->codec.out.len);
+    s->codec.out.start = 0;
+}
+
+static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
+{
+    if (s->codec.out.len >= free_b) {
+        tsc210x_out_flush(s, free_b);
+        return;
+    }
+
+    s->codec.out.size = MIN(free_b, 16384);
+    qemu_irq_raise(s->codec.tx_start);
+}
+
+static void tsc2102_audio_rate_update(TSC210xState *s)
+{
+    const TSC210xRateInfo *rate;
+
+    s->codec.tx_rate = 0;
+    s->codec.rx_rate = 0;
+    if (s->dac_power & (1 << 15))				/* PWDNC */
+        return;
+
+    for (rate = tsc2102_rates; rate->rate; rate ++)
+        if (rate->dsor == (s->audio_ctrl1 & 0x3f) &&		/* DACFS */
+                        rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
+            break;
+    if (!rate->rate) {
+        printf("%s: unknown sampling rate configured\n", __FUNCTION__);
+        return;
+    }
+
+    s->codec.tx_rate = rate->rate;
+}
+
+static void tsc2102_audio_output_update(TSC210xState *s)
+{
+    int enable;
+    struct audsettings fmt;
+
+    if (s->dac_voice[0]) {
+        tsc210x_out_flush(s, s->codec.out.len);
+        s->codec.out.size = 0;
+        AUD_set_active_out(s->dac_voice[0], 0);
+        AUD_close_out(&s->card, s->dac_voice[0]);
+        s->dac_voice[0] = NULL;
+    }
+    s->codec.cts = 0;
+
+    enable =
+            (~s->dac_power & (1 << 15)) &&			/* PWDNC */
+            (~s->dac_power & (1 << 10));			/* DAPWDN */
+    if (!enable || !s->codec.tx_rate)
+        return;
+
+    /* Force our own sampling rate even in slave DAC mode */
+    fmt.endianness = 0;
+    fmt.nchannels = 2;
+    fmt.freq = s->codec.tx_rate;
+    fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
+    if (s->dac_voice[0]) {
+        s->codec.cts = 1;
+        AUD_set_active_out(s->dac_voice[0], 1);
+    }
+}
+
+static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00:	/* X */
+        s->dav &= 0xfbff;
+        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+                (s->noise & 3);
+
+    case 0x01:	/* Y */
+        s->noise ++;
+        s->dav &= 0xfdff;
+        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+                (s->noise & 3);
+
+    case 0x02:	/* Z1 */
+        s->dav &= 0xfeff;
+        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+                (s->noise & 3);
+
+    case 0x03:	/* Z2 */
+        s->dav &= 0xff7f;
+        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+                (s->noise & 3);
+
+    case 0x04:	/* KPData */
+        if ((s->model & 0xff00) == 0x2300) {
+            if (s->kb.intr && (s->kb.mode & 2)) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+            return s->kb.down;
+        }
+
+        return 0xffff;
+
+    case 0x05:	/* BAT1 */
+        s->dav &= 0xffbf;
+        return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
+                (s->noise & 6);
+
+    case 0x06:	/* BAT2 */
+        s->dav &= 0xffdf;
+        return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
+
+    case 0x07:	/* AUX1 */
+        s->dav &= 0xffef;
+        return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
+
+    case 0x08:	/* AUX2 */
+        s->dav &= 0xfff7;
+        return 0xffff;
+
+    case 0x09:	/* TEMP1 */
+        s->dav &= 0xfffb;
+        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+                (s->noise & 5);
+
+    case 0x0a:	/* TEMP2 */
+        s->dav &= 0xfffd;
+        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+                (s->noise & 3);
+
+    case 0x0b:	/* DAC */
+        s->dav &= 0xfffe;
+        return 0xffff;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_control_register_read(
+                TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00:	/* TSC ADC */
+        return (s->pressure << 15) | ((!s->busy) << 14) |
+                (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; 
+
+    case 0x01:	/* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            return (s->pin_func << 14) | ((!s->enabled) << 13) |
+                    (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
+        else
+            return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
+                    (s->kb.debounce << 11);
+
+    case 0x02:	/* DAC Control */
+        if ((s->model & 0xff00) == 0x2300)
+            return s->dac_power & 0x8000;
+        else
+            goto bad_reg;
+
+    case 0x03:	/* Reference */
+        return s->ref;
+
+    case 0x04:	/* Reset */
+        return 0xffff;
+
+    case 0x05:	/* Configuration */
+        return s->timing;
+
+    case 0x06:	/* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
+
+    case 0x10:	/* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return s->kb.mask;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
+{
+    int l_ch, r_ch;
+    uint16_t val;
+
+    switch (reg) {
+    case 0x00:	/* Audio Control 1 */
+        return s->audio_ctrl1;
+
+    case 0x01:
+        return 0xff00;
+
+    case 0x02:	/* DAC Volume Control */
+        return s->volume;
+
+    case 0x03:
+        return 0x8b00;
+
+    case 0x04:	/* Audio Control 2 */
+        l_ch = 1;
+        r_ch = 1;
+        if (s->softstep && !(s->dac_power & (1 << 10))) {
+            l_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+            r_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+        }
+
+        return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
+
+    case 0x05:	/* Stereo DAC Power Control */
+        return 0x2aa0 | s->dac_power |
+                (((s->dac_power & (1 << 10)) &&
+                  (qemu_get_clock_ns(vm_clock) >
+                   s->powerdown + TSC_POWEROFF_DELAY)) << 6);
+
+    case 0x06:	/* Audio Control 3 */
+        val = s->audio_ctrl3 | 0x0001;
+        s->audio_ctrl3 &= 0xff3f;
+        return val;
+
+    case 0x07:	/* LCH_BASS_BOOST_N0 */
+    case 0x08:	/* LCH_BASS_BOOST_N1 */
+    case 0x09:	/* LCH_BASS_BOOST_N2 */
+    case 0x0a:	/* LCH_BASS_BOOST_N3 */
+    case 0x0b:	/* LCH_BASS_BOOST_N4 */
+    case 0x0c:	/* LCH_BASS_BOOST_N5 */
+    case 0x0d:	/* LCH_BASS_BOOST_D1 */
+    case 0x0e:	/* LCH_BASS_BOOST_D2 */
+    case 0x0f:	/* LCH_BASS_BOOST_D4 */
+    case 0x10:	/* LCH_BASS_BOOST_D5 */
+    case 0x11:	/* RCH_BASS_BOOST_N0 */
+    case 0x12:	/* RCH_BASS_BOOST_N1 */
+    case 0x13:	/* RCH_BASS_BOOST_N2 */
+    case 0x14:	/* RCH_BASS_BOOST_N3 */
+    case 0x15:	/* RCH_BASS_BOOST_N4 */
+    case 0x16:	/* RCH_BASS_BOOST_N5 */
+    case 0x17:	/* RCH_BASS_BOOST_D1 */
+    case 0x18:	/* RCH_BASS_BOOST_D2 */
+    case 0x19:	/* RCH_BASS_BOOST_D4 */
+    case 0x1a:	/* RCH_BASS_BOOST_D5 */
+        return s->filter_data[reg - 0x07];
+
+    case 0x1b:	/* PLL Programmability 1 */
+        return s->pll[0];
+
+    case 0x1c:	/* PLL Programmability 2 */
+        return s->pll[1];
+
+    case 0x1d:	/* Audio Control 4 */
+        return (!s->softstep) << 14;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static void tsc2102_data_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00:	/* X */
+    case 0x01:	/* Y */
+    case 0x02:	/* Z1 */
+    case 0x03:	/* Z2 */
+    case 0x05:	/* BAT1 */
+    case 0x06:	/* BAT2 */
+    case 0x07:	/* AUX1 */
+    case 0x08:	/* AUX2 */
+    case 0x09:	/* TEMP1 */
+    case 0x0a:	/* TEMP2 */
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_control_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00:	/* TSC ADC */
+        s->host_mode = value >> 15;
+        s->enabled = !(value & 0x4000);
+        if (s->busy && !s->enabled)
+            qemu_del_timer(s->timer);
+        s->busy &= s->enabled;
+        s->nextfunction = (value >> 10) & 0xf;
+        s->nextprecision = (value >> 8) & 3;
+        s->filter = value & 0xff;
+        return;
+
+    case 0x01:	/* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            s->pin_func = value >> 14;
+	else {
+            s->kb.scan = (value >> 14) & 1;
+            s->kb.debounce = (value >> 11) & 7;
+            if (s->kb.intr && s->kb.scan) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+        }
+        return;
+
+    case 0x02:	/* DAC Control */
+        if ((s->model & 0xff00) == 0x2300) {
+            s->dac_power &= 0x7fff;
+            s->dac_power |= 0x8000 & value;
+        } else
+            goto bad_reg;
+        break;
+
+    case 0x03:	/* Reference */
+        s->ref = value & 0x1f;
+        return;
+
+    case 0x04:	/* Reset */
+        if (value == 0xbb00) {
+            if (s->busy)
+                qemu_del_timer(s->timer);
+            tsc210x_reset(s);
+#ifdef TSC_VERBOSE
+        } else {
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into RESET\n");
+#endif
+        }
+        return;
+
+    case 0x05:	/* Configuration */
+        s->timing = value & 0x3f;
+#ifdef TSC_VERBOSE
+        if (value & ~0x3f)
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into CONFIG\n");
+#endif
+        return;
+
+    case 0x06:	/* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mode = value >> 14;
+        s->pll[2] = value & 0x3ffff;
+        return;
+
+    case 0x10:	/* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mask = value;
+        return;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_audio_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00:	/* Audio Control 1 */
+        s->audio_ctrl1 = value & 0x0f3f;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 1\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x01:
+#ifdef TSC_VERBOSE
+        if (value != 0xff00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x01\n");
+#endif
+        return;
+
+    case 0x02:	/* DAC Volume Control */
+        s->volume = value;
+        s->volume_change = qemu_get_clock_ns(vm_clock);
+        return;
+
+    case 0x03:
+#ifdef TSC_VERBOSE
+        if (value != 0x8b00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x03\n");
+#endif
+        return;
+
+    case 0x04:	/* Audio Control 2 */
+        s->audio_ctrl2 = value & 0xf7f2;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf7fd)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 2\n");
+#endif
+        return;
+
+    case 0x05:	/* Stereo DAC Power Control */
+        if ((value & ~s->dac_power) & (1 << 10))
+            s->powerdown = qemu_get_clock_ns(vm_clock);
+
+        s->dac_power = value & 0x9543;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x9543) != 0x2aa0)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Power\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x06:	/* Audio Control 3 */
+        s->audio_ctrl3 &= 0x00c0;
+        s->audio_ctrl3 |= value & 0xf800;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf8c7)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 3\n");
+#endif
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x07:	/* LCH_BASS_BOOST_N0 */
+    case 0x08:	/* LCH_BASS_BOOST_N1 */
+    case 0x09:	/* LCH_BASS_BOOST_N2 */
+    case 0x0a:	/* LCH_BASS_BOOST_N3 */
+    case 0x0b:	/* LCH_BASS_BOOST_N4 */
+    case 0x0c:	/* LCH_BASS_BOOST_N5 */
+    case 0x0d:	/* LCH_BASS_BOOST_D1 */
+    case 0x0e:	/* LCH_BASS_BOOST_D2 */
+    case 0x0f:	/* LCH_BASS_BOOST_D4 */
+    case 0x10:	/* LCH_BASS_BOOST_D5 */
+    case 0x11:	/* RCH_BASS_BOOST_N0 */
+    case 0x12:	/* RCH_BASS_BOOST_N1 */
+    case 0x13:	/* RCH_BASS_BOOST_N2 */
+    case 0x14:	/* RCH_BASS_BOOST_N3 */
+    case 0x15:	/* RCH_BASS_BOOST_N4 */
+    case 0x16:	/* RCH_BASS_BOOST_N5 */
+    case 0x17:	/* RCH_BASS_BOOST_D1 */
+    case 0x18:	/* RCH_BASS_BOOST_D2 */
+    case 0x19:	/* RCH_BASS_BOOST_D4 */
+    case 0x1a:	/* RCH_BASS_BOOST_D5 */
+        s->filter_data[reg - 0x07] = value;
+        return;
+
+    case 0x1b:	/* PLL Programmability 1 */
+        s->pll[0] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 1\n");
+#endif
+        return;
+
+    case 0x1c:	/* PLL Programmability 2 */
+        s->pll[1] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 2\n");
+#endif
+        return;
+
+    case 0x1d:	/* Audio Control 4 */
+        s->softstep = !(value & 0x4000);
+#ifdef TSC_VERBOSE
+        if (value & ~0x4000)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 4\n");
+#endif
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+/* This handles most of the chip logic.  */
+static void tsc210x_pin_update(TSC210xState *s)
+{
+    int64_t expires;
+    int pin_state;
+
+    switch (s->pin_func) {
+    case 0:
+        pin_state = s->pressure;
+        break;
+    case 1:
+        pin_state = !!s->dav;
+        break;
+    case 2:
+    default:
+        pin_state = s->pressure && !s->dav;
+    }
+
+    if (!s->enabled)
+        pin_state = 0;
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, !s->irq);
+    }
+
+    switch (s->nextfunction) {
+    case TSC_MODE_XY_SCAN:
+    case TSC_MODE_XYZ_SCAN:
+        if (!s->pressure)
+            return;
+        break;
+
+    case TSC_MODE_X:
+    case TSC_MODE_Y:
+    case TSC_MODE_Z:
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_BAT1:
+    case TSC_MODE_BAT2:
+    case TSC_MODE_AUX:
+    case TSC_MODE_TEMP1:
+    case TSC_MODE_TEMP2:
+        if (s->dav)
+            s->enabled = 0;
+        break;
+
+    case TSC_MODE_AUX_SCAN:
+    case TSC_MODE_PORT_SCAN:
+        break;
+
+    case TSC_MODE_NO_SCAN:
+    case TSC_MODE_XX_DRV:
+    case TSC_MODE_YY_DRV:
+    case TSC_MODE_YX_DRV:
+    default:
+        return;
+    }
+
+    if (!s->enabled || s->busy || s->dav)
+        return;
+
+    s->busy = 1;
+    s->precision = s->nextprecision;
+    s->function = s->nextfunction;
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
+    qemu_mod_timer(s->timer, expires);
+}
+
+static uint16_t tsc210x_read(TSC210xState *s)
+{
+    uint16_t ret = 0x0000;
+
+    if (!s->command)
+        fprintf(stderr, "tsc210x_read: SPI underrun!\n");
+
+    switch (s->page) {
+    case TSC_DATA_REGISTERS_PAGE:
+        ret = tsc2102_data_register_read(s, s->offset);
+        if (!s->dav)
+            qemu_irq_raise(s->davint);
+        break;
+    case TSC_CONTROL_REGISTERS_PAGE:
+        ret = tsc2102_control_register_read(s, s->offset);
+        break;
+    case TSC_AUDIO_REGISTERS_PAGE:
+        ret = tsc2102_audio_register_read(s, s->offset);
+        break;
+    default:
+        hw_error("tsc210x_read: wrong memory page\n");
+    }
+
+    tsc210x_pin_update(s);
+
+    /* Allow sequential reads.  */
+    s->offset ++;
+    s->state = 0;
+    return ret;
+}
+
+static void tsc210x_write(TSC210xState *s, uint16_t value)
+{
+    /*
+     * This is a two-state state machine for reading
+     * command and data every second time.
+     */
+    if (!s->state) {
+        s->command = value >> 15;
+        s->page = (value >> 11) & 0x0f;
+        s->offset = (value >> 5) & 0x3f;
+        s->state = 1;
+    } else {
+        if (s->command)
+            fprintf(stderr, "tsc210x_write: SPI overrun!\n");
+        else
+            switch (s->page) {
+            case TSC_DATA_REGISTERS_PAGE:
+                tsc2102_data_register_write(s, s->offset, value);
+                break;
+            case TSC_CONTROL_REGISTERS_PAGE:
+                tsc2102_control_register_write(s, s->offset, value);
+                break;
+            case TSC_AUDIO_REGISTERS_PAGE:
+                tsc2102_audio_register_write(s, s->offset, value);
+                break;
+            default:
+                hw_error("tsc210x_write: wrong memory page\n");
+            }
+
+        tsc210x_pin_update(s);
+        s->state = 0;
+    }
+}
+
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
+{
+    TSC210xState *s = opaque;
+    uint32_t ret = 0;
+
+    if (len != 16)
+        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
+
+    /* TODO: sequential reads etc - how do we make sure the host doesn't
+     * unintentionally read out a conversion result from a register while
+     * transmitting the command word of the next command?  */
+    if (!value || (s->state && s->command))
+        ret = tsc210x_read(s);
+    if (value || (s->state && !s->command))
+        tsc210x_write(s, value);
+
+    return ret;
+}
+
+static void tsc210x_timer_tick(void *opaque)
+{
+    TSC210xState *s = opaque;
+
+    /* Timer ticked -- a set of conversions has been finished.  */
+
+    if (!s->busy)
+        return;
+
+    s->busy = 0;
+    s->dav |= mode_regs[s->function];
+    tsc210x_pin_update(s);
+    qemu_irq_lower(s->davint);
+}
+
+static void tsc210x_touchscreen_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    TSC210xState *s = opaque;
+    int p = s->pressure;
+
+    if (buttons_state) {
+        s->x = x;
+        s->y = y;
+    }
+    s->pressure = !!buttons_state;
+
+    /*
+     * Note: We would get better responsiveness in the guest by
+     * signaling TS events immediately, but for now we simulate
+     * the first conversion delay for sake of correctness.
+     */
+    if (p != s->pressure)
+        tsc210x_pin_update(s);
+}
+
+static void tsc210x_i2s_swallow(TSC210xState *s)
+{
+    if (s->dac_voice[0])
+        tsc210x_out_flush(s, s->codec.out.len);
+    else
+        s->codec.out.len = 0;
+}
+
+static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
+{
+    s->i2s_tx_rate = out;
+    s->i2s_rx_rate = in;
+}
+
+static void tsc210x_save(QEMUFile *f, void *opaque)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    qemu_put_be16(f, s->x);
+    qemu_put_be16(f, s->y);
+    qemu_put_byte(f, s->pressure);
+
+    qemu_put_byte(f, s->state);
+    qemu_put_byte(f, s->page);
+    qemu_put_byte(f, s->offset);
+    qemu_put_byte(f, s->command);
+
+    qemu_put_byte(f, s->irq);
+    qemu_put_be16s(f, &s->dav);
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_byte(f, s->enabled);
+    qemu_put_byte(f, s->host_mode);
+    qemu_put_byte(f, s->function);
+    qemu_put_byte(f, s->nextfunction);
+    qemu_put_byte(f, s->precision);
+    qemu_put_byte(f, s->nextprecision);
+    qemu_put_byte(f, s->filter);
+    qemu_put_byte(f, s->pin_func);
+    qemu_put_byte(f, s->ref);
+    qemu_put_byte(f, s->timing);
+    qemu_put_be32(f, s->noise);
+
+    qemu_put_be16s(f, &s->audio_ctrl1);
+    qemu_put_be16s(f, &s->audio_ctrl2);
+    qemu_put_be16s(f, &s->audio_ctrl3);
+    qemu_put_be16s(f, &s->pll[0]);
+    qemu_put_be16s(f, &s->pll[1]);
+    qemu_put_be16s(f, &s->volume);
+    qemu_put_sbe64(f, (s->volume_change - now));
+    qemu_put_sbe64(f, (s->powerdown - now));
+    qemu_put_byte(f, s->softstep);
+    qemu_put_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_put_be16s(f, &s->filter_data[i]);
+}
+
+static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    s->x = qemu_get_be16(f);
+    s->y = qemu_get_be16(f);
+    s->pressure = qemu_get_byte(f);
+
+    s->state = qemu_get_byte(f);
+    s->page = qemu_get_byte(f);
+    s->offset = qemu_get_byte(f);
+    s->command = qemu_get_byte(f);
+
+    s->irq = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dav);
+
+    qemu_get_timer(f, s->timer);
+    s->enabled = qemu_get_byte(f);
+    s->host_mode = qemu_get_byte(f);
+    s->function = qemu_get_byte(f);
+    s->nextfunction = qemu_get_byte(f);
+    s->precision = qemu_get_byte(f);
+    s->nextprecision = qemu_get_byte(f);
+    s->filter = qemu_get_byte(f);
+    s->pin_func = qemu_get_byte(f);
+    s->ref = qemu_get_byte(f);
+    s->timing = qemu_get_byte(f);
+    s->noise = qemu_get_be32(f);
+
+    qemu_get_be16s(f, &s->audio_ctrl1);
+    qemu_get_be16s(f, &s->audio_ctrl2);
+    qemu_get_be16s(f, &s->audio_ctrl3);
+    qemu_get_be16s(f, &s->pll[0]);
+    qemu_get_be16s(f, &s->pll[1]);
+    qemu_get_be16s(f, &s->volume);
+    s->volume_change = qemu_get_sbe64(f) + now;
+    s->powerdown = qemu_get_sbe64(f) + now;
+    s->softstep = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_get_be16s(f, &s->filter_data[i]);
+
+    s->busy = qemu_timer_pending(s->timer);
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+
+    return 0;
+}
+
+uWireSlave *tsc2102_init(qemu_irq pint)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            qemu_mallocz(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 160;
+    s->y = 160;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = pint;
+    s->model = 0x2102;
+    s->name = "tsc2102";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2102-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0,
+                    tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            qemu_mallocz(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 400;
+    s->y = 240;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = penirq;
+    s->kbint = kbirq;
+    s->davint = dav;
+    s->model = 0x2301;
+    s->name = "tsc2301";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2301-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+I2SCodec *tsc210x_codec(uWireSlave *chip)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    return &s->codec;
+}
+
+/*
+ * Use tslib generated calibration data to generate ADC input values
+ * from the touchscreen.  Assuming 12-bit precision was used during
+ * tslib calibration.
+ */
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+#if 0
+    int64_t ltr[8];
+
+    ltr[0] = (int64_t) info->a[1] * info->y;
+    ltr[1] = (int64_t) info->a[4] * info->x;
+    ltr[2] = (int64_t) info->a[1] * info->a[3] -
+            (int64_t) info->a[4] * info->a[0];
+    ltr[3] = (int64_t) info->a[2] * info->a[4] -
+            (int64_t) info->a[5] * info->a[1];
+    ltr[4] = (int64_t) info->a[0] * info->y;
+    ltr[5] = (int64_t) info->a[3] * info->x;
+    ltr[6] = (int64_t) info->a[4] * info->a[0] -
+            (int64_t) info->a[1] * info->a[3];
+    ltr[7] = (int64_t) info->a[2] * info->a[3] -
+            (int64_t) info->a[5] * info->a[0];
+
+    /* Avoid integer overflow */
+    s->tr[0] = ltr[0] >> 11;
+    s->tr[1] = ltr[1] >> 11;
+    s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
+    s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
+    s->tr[4] = ltr[4] >> 11;
+    s->tr[5] = ltr[5] >> 11;
+    s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
+    s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
+#else
+
+    /* This version assumes touchscreen X & Y axis are parallel or
+     * perpendicular to LCD's  X & Y axis in some way.  */
+    if (abs(info->a[0]) > abs(info->a[1])) {
+        s->tr[0] = 0;
+        s->tr[1] = -info->a[6] * info->x;
+        s->tr[2] = info->a[0];
+        s->tr[3] = -info->a[2] / info->a[0];
+        s->tr[4] = info->a[6] * info->y;
+        s->tr[5] = 0;
+        s->tr[6] = info->a[4];
+        s->tr[7] = -info->a[5] / info->a[4];
+    } else {
+        s->tr[0] = info->a[6] * info->y;
+        s->tr[1] = 0;
+        s->tr[2] = info->a[1];
+        s->tr[3] = -info->a[2] / info->a[1];
+        s->tr[4] = 0;
+        s->tr[5] = -info->a[6] * info->x;
+        s->tr[6] = info->a[3];
+        s->tr[7] = -info->a[5] / info->a[3];
+    }
+
+    s->tr[0] >>= 11;
+    s->tr[1] >>= 11;
+    s->tr[3] <<= 4;
+    s->tr[4] >>= 11;
+    s->tr[5] >>= 11;
+    s->tr[7] <<= 4;
+#endif
+}
+
+void tsc210x_key_event(uWireSlave *chip, int key, int down)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    if (down)
+        s->kb.down |= 1 << key;
+    else
+        s->kb.down &= ~(1 << key);
+
+    if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
+        s->kb.intr = 1;
+        qemu_irq_lower(s->kbint);
+    } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
+                    !(s->kb.mode & 1)) {
+        s->kb.intr = 0;
+        qemu_irq_raise(s->kbint);
+    }
+}
diff --git a/qemu-0.15.x/hw/tusb6010.c b/qemu-0.15.x/hw/tusb6010.c
new file mode 100644
index 0000000..ccd01ad
--- /dev/null
+++ b/qemu-0.15.x/hw/tusb6010.c
@@ -0,0 +1,766 @@
+/*
+ * Texas Instruments TUSB6010 emulation.
+ * Based on reverse-engineering of a linux driver.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "omap.h"
+#include "irq.h"
+#include "devices.h"
+
+struct TUSBState {
+    int iomemtype[2];
+    qemu_irq irq;
+    MUSBState *musb;
+    QEMUTimer *otg_timer;
+    QEMUTimer *pwr_timer;
+
+    int power;
+    uint32_t scratch;
+    uint16_t test_reset;
+    uint32_t prcm_config;
+    uint32_t prcm_mngmt;
+    uint16_t otg_status;
+    uint32_t dev_config;
+    int host_mode;
+    uint32_t intr;
+    uint32_t intr_ok;
+    uint32_t mask;
+    uint32_t usbip_intr;
+    uint32_t usbip_mask;
+    uint32_t gpio_intr;
+    uint32_t gpio_mask;
+    uint32_t gpio_config;
+    uint32_t dma_intr;
+    uint32_t dma_mask;
+    uint32_t dma_map;
+    uint32_t dma_config;
+    uint32_t ep0_config;
+    uint32_t rx_config[15];
+    uint32_t tx_config[15];
+    uint32_t wkup_mask;
+    uint32_t pullup[2];
+    uint32_t control_config;
+    uint32_t otg_timer_val;
+};
+
+#define TUSB_DEVCLOCK			60000000	/* 60 MHz */
+
+#define TUSB_VLYNQ_CTRL			0x004
+
+/* Mentor Graphics OTG core registers.  */
+#define TUSB_BASE_OFFSET		0x400
+
+/* FIFO registers, 32-bit.  */
+#define TUSB_FIFO_BASE			0x600
+
+/* Device System & Control registers, 32-bit.  */
+#define TUSB_SYS_REG_BASE		0x800
+
+#define TUSB_DEV_CONF			(TUSB_SYS_REG_BASE + 0x000)
+#define	TUSB_DEV_CONF_USB_HOST_MODE	(1 << 16)
+#define	TUSB_DEV_CONF_PROD_TEST_MODE	(1 << 15)
+#define	TUSB_DEV_CONF_SOFT_ID		(1 << 1)
+#define	TUSB_DEV_CONF_ID_SEL		(1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE	(TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL		(TUSB_SYS_REG_BASE + 0x008)
+#define	TUSB_PHY_OTG_CTRL_WRPROTECT	(0xa5 << 24)
+#define	TUSB_PHY_OTG_CTRL_O_ID_PULLUP	(1 << 23)
+#define	TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN	(1 << 19)
+#define	TUSB_PHY_OTG_CTRL_O_SESS_END_EN	(1 << 18)
+#define	TUSB_PHY_OTG_CTRL_TESTM2	(1 << 17)
+#define	TUSB_PHY_OTG_CTRL_TESTM1	(1 << 16)
+#define	TUSB_PHY_OTG_CTRL_TESTM0	(1 << 15)
+#define	TUSB_PHY_OTG_CTRL_TX_DATA2	(1 << 14)
+#define	TUSB_PHY_OTG_CTRL_TX_GZ2	(1 << 13)
+#define	TUSB_PHY_OTG_CTRL_TX_ENABLE2	(1 << 12)
+#define	TUSB_PHY_OTG_CTRL_DM_PULLDOWN	(1 << 11)
+#define	TUSB_PHY_OTG_CTRL_DP_PULLDOWN	(1 << 10)
+#define	TUSB_PHY_OTG_CTRL_OSC_EN	(1 << 9)
+#define	TUSB_PHY_OTG_CTRL_PHYREF_CLK(v)	(((v) & 3) << 7)
+#define	TUSB_PHY_OTG_CTRL_PD		(1 << 6)
+#define	TUSB_PHY_OTG_CTRL_PLL_ON	(1 << 5)
+#define	TUSB_PHY_OTG_CTRL_EXT_RPU	(1 << 4)
+#define	TUSB_PHY_OTG_CTRL_PWR_GOOD	(1 << 3)
+#define	TUSB_PHY_OTG_CTRL_RESET		(1 << 2)
+#define	TUSB_PHY_OTG_CTRL_SUSPENDM	(1 << 1)
+#define	TUSB_PHY_OTG_CTRL_CLK_MODE	(1 << 0)
+
+/* OTG status register */
+#define TUSB_DEV_OTG_STAT		(TUSB_SYS_REG_BASE + 0x00c)
+#define	TUSB_DEV_OTG_STAT_PWR_CLK_GOOD	(1 << 8)
+#define	TUSB_DEV_OTG_STAT_SESS_END	(1 << 7)
+#define	TUSB_DEV_OTG_STAT_SESS_VALID	(1 << 6)
+#define	TUSB_DEV_OTG_STAT_VBUS_VALID	(1 << 5)
+#define	TUSB_DEV_OTG_STAT_VBUS_SENSE	(1 << 4)
+#define	TUSB_DEV_OTG_STAT_ID_STATUS	(1 << 3)
+#define	TUSB_DEV_OTG_STAT_HOST_DISCON	(1 << 2)
+#define	TUSB_DEV_OTG_STAT_LINE_STATE	(3 << 0)
+#define	TUSB_DEV_OTG_STAT_DP_ENABLE	(1 << 1)
+#define	TUSB_DEV_OTG_STAT_DM_ENABLE	(1 << 0)
+
+#define TUSB_DEV_OTG_TIMER		(TUSB_SYS_REG_BASE + 0x010)
+#define TUSB_DEV_OTG_TIMER_ENABLE	(1 << 31)
+#define TUSB_DEV_OTG_TIMER_VAL(v)	((v) & 0x07ffffff)
+#define TUSB_PRCM_REV			(TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF			(TUSB_SYS_REG_BASE + 0x018)
+#define	TUSB_PRCM_CONF_SFW_CPEN		(1 << 24)
+#define	TUSB_PRCM_CONF_SYS_CLKSEL(v)	(((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT			(TUSB_SYS_REG_BASE + 0x01c)
+#define	TUSB_PRCM_MNGMT_SRP_FIX_TMR(v)	(((v) & 0xf) << 25)
+#define	TUSB_PRCM_MNGMT_SRP_FIX_EN	(1 << 24)
+#define	TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v)	(((v) & 0xf) << 20)
+#define	TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN	(1 << 19)
+#define	TUSB_PRCM_MNGMT_DFT_CLK_DIS	(1 << 18)
+#define	TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS	(1 << 17)
+#define	TUSB_PRCM_MNGMT_OTG_SESS_END_EN	(1 << 10)
+#define	TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN	(1 << 9)
+#define	TUSB_PRCM_MNGMT_OTG_ID_PULLUP	(1 << 8)
+#define	TUSB_PRCM_MNGMT_15_SW_EN	(1 << 4)
+#define	TUSB_PRCM_MNGMT_33_SW_EN	(1 << 3)
+#define	TUSB_PRCM_MNGMT_5V_CPEN		(1 << 2)
+#define	TUSB_PRCM_MNGMT_PM_IDLE		(1 << 1)
+#define	TUSB_PRCM_MNGMT_DEV_IDLE	(1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE		(TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR		(TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK		(TUSB_SYS_REG_BASE + 0x02c)
+#define	TUSB_PRCM_WAKEUP_RESERVED_BITS	(0xffffe << 13)
+#define	TUSB_PRCM_WGPIO_7		(1 << 12)
+#define	TUSB_PRCM_WGPIO_6		(1 << 11)
+#define	TUSB_PRCM_WGPIO_5		(1 << 10)
+#define	TUSB_PRCM_WGPIO_4		(1 << 9)
+#define	TUSB_PRCM_WGPIO_3		(1 << 8)
+#define	TUSB_PRCM_WGPIO_2		(1 << 7)
+#define	TUSB_PRCM_WGPIO_1		(1 << 6)
+#define	TUSB_PRCM_WGPIO_0		(1 << 5)
+#define	TUSB_PRCM_WHOSTDISCON		(1 << 4)	/* Host disconnect */
+#define	TUSB_PRCM_WBUS			(1 << 3)	/* USB bus resume */
+#define	TUSB_PRCM_WNORCS		(1 << 2)	/* NOR chip select */
+#define	TUSB_PRCM_WVBUS			(1 << 1)	/* OTG PHY VBUS */
+#define	TUSB_PRCM_WID			(1 << 0)	/* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL		(TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL		(TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV		(TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF		(TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC		(TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET		(TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK		(TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC		(TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET		(TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK		(TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC		(TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET		(TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK		(TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC			(TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET		(TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR		(TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK			(TUSB_SYS_REG_BASE + 0x07c)
+#define	TUSB_INT_SRC_TXRX_DMA_DONE	(1 << 24)
+#define	TUSB_INT_SRC_USB_IP_CORE	(1 << 17)
+#define	TUSB_INT_SRC_OTG_TIMEOUT	(1 << 16)
+#define	TUSB_INT_SRC_VBUS_SENSE_CHNG	(1 << 15)
+#define	TUSB_INT_SRC_ID_STATUS_CHNG	(1 << 14)
+#define	TUSB_INT_SRC_DEV_WAKEUP		(1 << 13)
+#define	TUSB_INT_SRC_DEV_READY		(1 << 12)
+#define	TUSB_INT_SRC_USB_IP_TX		(1 << 9)
+#define	TUSB_INT_SRC_USB_IP_RX		(1 << 8)
+#define	TUSB_INT_SRC_USB_IP_VBUS_ERR	(1 << 7)
+#define	TUSB_INT_SRC_USB_IP_VBUS_REQ	(1 << 6)
+#define	TUSB_INT_SRC_USB_IP_DISCON	(1 << 5)
+#define	TUSB_INT_SRC_USB_IP_CONN	(1 << 4)
+#define	TUSB_INT_SRC_USB_IP_SOF		(1 << 3)
+#define	TUSB_INT_SRC_USB_IP_RST_BABBLE	(1 << 2)
+#define	TUSB_INT_SRC_USB_IP_RESUME	(1 << 1)
+#define	TUSB_INT_SRC_USB_IP_SUSPEND	(1 << 0)
+
+#define TUSB_GPIO_REV			(TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF			(TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV		(TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF		(TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF			(TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_EP_IN_SIZE			(TUSB_SYS_REG_BASE + 0x10c)
+#define TUSB_DMA_EP_MAP			(TUSB_SYS_REG_BASE + 0x148)
+#define TUSB_EP_OUT_SIZE		(TUSB_SYS_REG_BASE + 0x14c)
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET	(TUSB_SYS_REG_BASE + 0x188)
+#define TUSB_SCRATCH_PAD		(TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_WAIT_COUNT			(TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_PROD_TEST_RESET		(TUSB_SYS_REG_BASE + 0x1d8)
+
+#define TUSB_DIDR1_LO			(TUSB_SYS_REG_BASE + 0x1f8)
+#define TUSB_DIDR1_HI			(TUSB_SYS_REG_BASE + 0x1fc)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RLCYC(v)	(((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY	(1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE	(1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v)	(((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)	(((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v)	(((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v)	(((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN		(1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX		(1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v)	((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN		(1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v)	((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL	0xa596
+
+int tusb6010_sync_io(TUSBState *s)
+{
+    return s->iomemtype[0];
+}
+
+int tusb6010_async_io(TUSBState *s)
+{
+    return s->iomemtype[1];
+}
+
+static void tusb_intr_update(TUSBState *s)
+{
+    if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
+        qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
+    else
+        qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
+}
+
+static void tusb_usbip_intr_update(TUSBState *s)
+{
+    /* TX interrupt in the MUSB */
+    if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_TX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
+
+    /* RX interrupt in the MUSB */
+    if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_RX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
+
+    /* XXX: What about TUSB_INT_SRC_USB_IP_CORE?  */
+
+    tusb_intr_update(s);
+}
+
+static void tusb_dma_intr_update(TUSBState *s)
+{
+    if (s->dma_intr & ~s->dma_mask)
+        s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
+    else
+        s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
+
+    tusb_intr_update(s);
+}
+
+static void tusb_gpio_intr_update(TUSBState *s)
+{
+    /* TODO: How is this signalled?  */
+}
+
+extern CPUReadMemoryFunc * const musb_read[];
+extern CPUWriteMemoryFunc * const musb_write[];
+
+static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[0](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[1](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+    uint32_t ret;
+
+    switch (offset) {
+    case TUSB_DEV_CONF:
+        return s->dev_config;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[2](s->musb, offset & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return 0x00;	/* TODO */
+
+    case TUSB_DEV_OTG_STAT:
+        ret = s->otg_status;
+#if 0
+        if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
+            ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+#endif
+        return ret;
+    case TUSB_DEV_OTG_TIMER:
+        return s->otg_timer_val;
+
+    case TUSB_PRCM_REV:
+        return 0x20;
+    case TUSB_PRCM_CONF:
+        return s->prcm_config;
+    case TUSB_PRCM_MNGMT:
+        return s->prcm_mngmt;
+    case TUSB_PRCM_WAKEUP_SOURCE:
+    case TUSB_PRCM_WAKEUP_CLEAR:	/* TODO: What does this one return?  */
+        return 0x00000000;
+    case TUSB_PRCM_WAKEUP_MASK:
+        return s->wkup_mask;
+
+    case TUSB_PULLUP_1_CTRL:
+        return s->pullup[0];
+    case TUSB_PULLUP_2_CTRL:
+        return s->pullup[1];
+
+    case TUSB_INT_CTRL_REV:
+        return 0x20;
+    case TUSB_INT_CTRL_CONF:
+        return s->control_config;
+
+    case TUSB_USBIP_INT_SRC:
+    case TUSB_USBIP_INT_SET:	/* TODO: What do these two return?  */
+    case TUSB_USBIP_INT_CLEAR:
+        return s->usbip_intr;
+    case TUSB_USBIP_INT_MASK:
+        return s->usbip_mask;
+
+    case TUSB_DMA_INT_SRC:
+    case TUSB_DMA_INT_SET:	/* TODO: What do these two return?  */
+    case TUSB_DMA_INT_CLEAR:
+        return s->dma_intr;
+    case TUSB_DMA_INT_MASK:
+        return s->dma_mask;
+
+    case TUSB_GPIO_INT_SRC:	/* TODO: What do these two return?  */
+    case TUSB_GPIO_INT_SET:
+    case TUSB_GPIO_INT_CLEAR:
+        return s->gpio_intr;
+    case TUSB_GPIO_INT_MASK:
+        return s->gpio_mask;
+
+    case TUSB_INT_SRC:
+    case TUSB_INT_SRC_SET:	/* TODO: What do these two return?  */
+    case TUSB_INT_SRC_CLEAR:
+        return s->intr;
+    case TUSB_INT_MASK:
+        return s->mask;
+
+    case TUSB_GPIO_REV:
+        return 0x30;
+    case TUSB_GPIO_CONF:
+        return s->gpio_config;
+
+    case TUSB_DMA_CTRL_REV:
+        return 0x30;
+    case TUSB_DMA_REQ_CONF:
+        return s->dma_config;
+    case TUSB_EP0_CONF:
+        return s->ep0_config;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        return s->tx_config[epnum];
+    case TUSB_DMA_EP_MAP:
+        return s->dma_map;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        return s->rx_config[epnum];
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return 0x00000000;	/* TODO */
+    case TUSB_WAIT_COUNT:
+        return 0x00;		/* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        return s->scratch;
+
+    case TUSB_PROD_TEST_RESET:
+        return s->test_reset;
+
+    /* DIE IDs */
+    case TUSB_DIDR1_LO:
+        return 0xa9453c59;
+    case TUSB_DIDR1_HI:
+        return 0x54059adf;
+    }
+
+    printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+    return 0;
+}
+
+static void tusb_async_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[0](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writeh(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[1](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writew(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+
+    switch (offset) {
+    case TUSB_VLYNQ_CTRL:
+        break;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[2](s->musb, offset & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    case TUSB_DEV_CONF:
+        s->dev_config = value;
+        s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
+        if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
+            hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
+        break;
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return;		/* TODO */
+    case TUSB_DEV_OTG_TIMER:
+        s->otg_timer_val = value;
+        if (value & TUSB_DEV_OTG_TIMER_ENABLE)
+            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
+                            muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
+                                     get_ticks_per_sec(), TUSB_DEVCLOCK));
+        else
+            qemu_del_timer(s->otg_timer);
+        break;
+
+    case TUSB_PRCM_CONF:
+        s->prcm_config = value;
+        break;
+    case TUSB_PRCM_MNGMT:
+        s->prcm_mngmt = value;
+        break;
+    case TUSB_PRCM_WAKEUP_CLEAR:
+        break;
+    case TUSB_PRCM_WAKEUP_MASK:
+        s->wkup_mask = value;
+        break;
+
+    case TUSB_PULLUP_1_CTRL:
+        s->pullup[0] = value;
+        break;
+    case TUSB_PULLUP_2_CTRL:
+        s->pullup[1] = value;
+        break;
+    case TUSB_INT_CTRL_CONF:
+        s->control_config = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_USBIP_INT_SET:
+        s->usbip_intr |= value;
+        tusb_usbip_intr_update(s);
+        break;
+    case TUSB_USBIP_INT_CLEAR:
+        s->usbip_intr &= ~value;
+        tusb_usbip_intr_update(s);
+        musb_core_intr_clear(s->musb, ~value);
+        break;
+    case TUSB_USBIP_INT_MASK:
+        s->usbip_mask = value;
+        tusb_usbip_intr_update(s);
+        break;
+
+    case TUSB_DMA_INT_SET:
+        s->dma_intr |= value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_CLEAR:
+        s->dma_intr &= ~value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_MASK:
+        s->dma_mask = value;
+        tusb_dma_intr_update(s);
+        break;
+
+    case TUSB_GPIO_INT_SET:
+        s->gpio_intr |= value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_CLEAR:
+        s->gpio_intr &= ~value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_MASK:
+        s->gpio_mask = value;
+        tusb_gpio_intr_update(s);
+        break;
+
+    case TUSB_INT_SRC_SET:
+        s->intr |= value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_SRC_CLEAR:
+        s->intr &= ~value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_MASK:
+        s->mask = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_GPIO_CONF:
+        s->gpio_config = value;
+        break;
+    case TUSB_DMA_REQ_CONF:
+        s->dma_config = value;
+        break;
+    case TUSB_EP0_CONF:
+        s->ep0_config = value & 0x1ff;
+        musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
+                        value & TUSB_EP0_CONFIG_DIR_TX);
+        break;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        s->tx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
+        break;
+    case TUSB_DMA_EP_MAP:
+        s->dma_map = value;
+        break;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        s->rx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
+        break;
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return;		/* TODO */
+    case TUSB_WAIT_COUNT:
+        return;		/* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        s->scratch = value;
+        break;
+
+    case TUSB_PROD_TEST_RESET:
+        s->test_reset = value;
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc * const tusb_async_readfn[] = {
+    tusb_async_readb,
+    tusb_async_readh,
+    tusb_async_readw,
+};
+
+static CPUWriteMemoryFunc * const tusb_async_writefn[] = {
+    tusb_async_writeb,
+    tusb_async_writeh,
+    tusb_async_writew,
+};
+
+static void tusb_otg_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    s->otg_timer_val = 0;
+    s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
+    tusb_intr_update(s);
+}
+
+static void tusb_power_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    if (s->power) {
+        s->intr_ok = ~0;
+        tusb_intr_update(s);
+    }
+}
+
+static void tusb_musb_core_intr(void *opaque, int source, int level)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    uint16_t otg_status = s->otg_status;
+
+    switch (source) {
+    case musb_set_vbus:
+        if (level)
+            otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
+        else
+            otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set?  */
+        if (s->otg_status != otg_status) {
+            s->otg_status = otg_status;
+            s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
+            tusb_intr_update(s);
+        }
+        break;
+
+    case musb_set_session:
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
+        if (level) {
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
+        } else {
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
+        }
+
+        /* XXX: some IRQ or anything?  */
+        break;
+
+    case musb_irq_tx:
+    case musb_irq_rx:
+        s->usbip_intr = musb_core_intr_get(s->musb);
+        /* Fall through.  */
+    default:
+        if (level)
+            s->intr |= 1 << source;
+        else
+            s->intr &= ~(1 << source);
+        tusb_intr_update(s);
+        break;
+    }
+}
+
+TUSBState *tusb6010_init(qemu_irq intr)
+{
+    TUSBState *s = qemu_mallocz(sizeof(*s));
+
+    s->test_reset = TUSB_PROD_TEST_RESET_VAL;
+    s->host_mode = 0;
+    s->dev_config = 0;
+    s->otg_status = 0;	/* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
+    s->power = 0;
+    s->mask = 0xffffffff;
+    s->intr = 0x00000000;
+    s->otg_timer_val = 0;
+    s->iomemtype[1] = cpu_register_io_memory(tusb_async_readfn,
+                    tusb_async_writefn, s, DEVICE_NATIVE_ENDIAN);
+    s->irq = intr;
+    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
+    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
+    s->musb = musb_init(qemu_allocate_irqs(tusb_musb_core_intr, s,
+                            __musb_irq_max));
+
+    return s;
+}
+
+void tusb6010_power(TUSBState *s, int on)
+{
+    if (!on)
+        s->power = 0;
+    else if (!s->power && on) {
+        s->power = 1;
+
+        /* Pull the interrupt down after TUSB6010 comes up.  */
+        s->intr_ok = 0;
+        tusb_intr_update(s);
+        qemu_mod_timer(s->pwr_timer,
+                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
+    }
+}
diff --git a/qemu-0.15.x/hw/twl92230.c b/qemu-0.15.x/hw/twl92230.c
new file mode 100644
index 0000000..a75448f
--- /dev/null
+++ b/qemu-0.15.x/hw/twl92230.c
@@ -0,0 +1,875 @@
+/*
+ * TI TWL92230C energy-management companion device for the OMAP24xx.
+ * Aka. Menelaus (N4200 MENELAUS1_V2.2)
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "console.h"
+
+#define VERBOSE 1
+
+typedef struct {
+    i2c_slave i2c;
+
+    int firstbyte;
+    uint8_t reg;
+
+    uint8_t vcore[5];
+    uint8_t dcdc[3];
+    uint8_t ldo[8];
+    uint8_t sleep[2];
+    uint8_t osc;
+    uint8_t detect;
+    uint16_t mask;
+    uint16_t status;
+    uint8_t dir;
+    uint8_t inputs;
+    uint8_t outputs;
+    uint8_t bbsms;
+    uint8_t pull[4];
+    uint8_t mmc_ctrl[3];
+    uint8_t mmc_debounce;
+    struct {
+        uint8_t ctrl;
+        uint16_t comp;
+        QEMUTimer *hz_tm;
+        int64_t next;
+        struct tm tm;
+        struct tm new;
+        struct tm alm;
+        int sec_offset;
+        int alm_sec;
+        int next_comp;
+    } rtc;
+    uint16_t rtc_next_vmstate;
+    qemu_irq out[4];
+    qemu_irq *in;
+    uint8_t pwrbtn_state;
+    qemu_irq pwrbtn;
+} MenelausState;
+
+static inline void menelaus_update(MenelausState *s)
+{
+    qemu_set_irq(s->out[3], s->status & ~s->mask);
+}
+
+static inline void menelaus_rtc_start(MenelausState *s)
+{
+    s->rtc.next += qemu_get_clock_ms(rt_clock);
+    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
+}
+
+static inline void menelaus_rtc_stop(MenelausState *s)
+{
+    qemu_del_timer(s->rtc.hz_tm);
+    s->rtc.next -= qemu_get_clock_ms(rt_clock);
+    if (s->rtc.next < 1)
+        s->rtc.next = 1;
+}
+
+static void menelaus_rtc_update(MenelausState *s)
+{
+    qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
+}
+
+static void menelaus_alm_update(MenelausState *s)
+{
+    if ((s->rtc.ctrl & 3) == 3)
+        s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
+}
+
+static void menelaus_rtc_hz(void *opaque)
+{
+    MenelausState *s = (MenelausState *) opaque;
+
+    s->rtc.next_comp --;
+    s->rtc.alm_sec --;
+    s->rtc.next += 1000;
+    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
+    if ((s->rtc.ctrl >> 3) & 3) {				/* EVERY */
+        menelaus_rtc_update(s);
+        if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
+            s->status |= 1 << 8;				/* RTCTMR */
+        else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
+            s->status |= 1 << 8;				/* RTCTMR */
+        else if (!s->rtc.tm.tm_hour)
+            s->status |= 1 << 8;				/* RTCTMR */
+    } else
+        s->status |= 1 << 8;					/* RTCTMR */
+    if ((s->rtc.ctrl >> 1) & 1) {				/* RTC_AL_EN */
+        if (s->rtc.alm_sec == 0)
+            s->status |= 1 << 9;				/* RTCALM */
+        /* TODO: wake-up */
+    }
+    if (s->rtc.next_comp <= 0) {
+        s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
+        s->rtc.next_comp = 3600;
+    }
+    menelaus_update(s);
+}
+
+static void menelaus_reset(i2c_slave *i2c)
+{
+    MenelausState *s = (MenelausState *) i2c;
+    s->reg = 0x00;
+
+    s->vcore[0] = 0x0c;	/* XXX: X-loader needs 0x8c? check!  */
+    s->vcore[1] = 0x05;
+    s->vcore[2] = 0x02;
+    s->vcore[3] = 0x0c;
+    s->vcore[4] = 0x03;
+    s->dcdc[0] = 0x33;	/* Depends on wiring */
+    s->dcdc[1] = 0x03;
+    s->dcdc[2] = 0x00;
+    s->ldo[0] = 0x95;
+    s->ldo[1] = 0x7e;
+    s->ldo[2] = 0x00;
+    s->ldo[3] = 0x00;	/* Depends on wiring */
+    s->ldo[4] = 0x03;	/* Depends on wiring */
+    s->ldo[5] = 0x00;
+    s->ldo[6] = 0x00;
+    s->ldo[7] = 0x00;
+    s->sleep[0] = 0x00;
+    s->sleep[1] = 0x00;
+    s->osc = 0x01;
+    s->detect = 0x09;
+    s->mask = 0x0fff;
+    s->status = 0;
+    s->dir = 0x07;
+    s->outputs = 0x00;
+    s->bbsms = 0x00;
+    s->pull[0] = 0x00;
+    s->pull[1] = 0x00;
+    s->pull[2] = 0x00;
+    s->pull[3] = 0x00;
+    s->mmc_ctrl[0] = 0x03;
+    s->mmc_ctrl[1] = 0xc0;
+    s->mmc_ctrl[2] = 0x00;
+    s->mmc_debounce = 0x05;
+
+    if (s->rtc.ctrl & 1)
+        menelaus_rtc_stop(s);
+    s->rtc.ctrl = 0x00;
+    s->rtc.comp = 0x0000;
+    s->rtc.next = 1000;
+    s->rtc.sec_offset = 0;
+    s->rtc.next_comp = 1800;
+    s->rtc.alm_sec = 1800;
+    s->rtc.alm.tm_sec = 0x00;
+    s->rtc.alm.tm_min = 0x00;
+    s->rtc.alm.tm_hour = 0x00;
+    s->rtc.alm.tm_mday = 0x01;
+    s->rtc.alm.tm_mon = 0x00;
+    s->rtc.alm.tm_year = 2004;
+    menelaus_update(s);
+}
+
+static void menelaus_gpio_set(void *opaque, int line, int level)
+{
+    MenelausState *s = (MenelausState *) opaque;
+
+    /* No interrupt generated */
+    s->inputs &= ~(1 << line);
+    s->inputs |= level << line;
+}
+
+static void menelaus_pwrbtn_set(void *opaque, int line, int level)
+{
+    MenelausState *s = (MenelausState *) opaque;
+
+    if (!s->pwrbtn_state && level) {
+        s->status |= 1 << 11;					/* PSHBTN */
+        menelaus_update(s);
+    }
+    s->pwrbtn_state = level;
+}
+
+#define MENELAUS_REV		0x01
+#define MENELAUS_VCORE_CTRL1	0x02
+#define MENELAUS_VCORE_CTRL2	0x03
+#define MENELAUS_VCORE_CTRL3	0x04
+#define MENELAUS_VCORE_CTRL4	0x05
+#define MENELAUS_VCORE_CTRL5	0x06
+#define MENELAUS_DCDC_CTRL1	0x07
+#define MENELAUS_DCDC_CTRL2	0x08
+#define MENELAUS_DCDC_CTRL3	0x09
+#define MENELAUS_LDO_CTRL1	0x0a
+#define MENELAUS_LDO_CTRL2	0x0b
+#define MENELAUS_LDO_CTRL3	0x0c
+#define MENELAUS_LDO_CTRL4	0x0d
+#define MENELAUS_LDO_CTRL5	0x0e
+#define MENELAUS_LDO_CTRL6	0x0f
+#define MENELAUS_LDO_CTRL7	0x10
+#define MENELAUS_LDO_CTRL8	0x11
+#define MENELAUS_SLEEP_CTRL1	0x12
+#define MENELAUS_SLEEP_CTRL2	0x13
+#define MENELAUS_DEVICE_OFF	0x14
+#define MENELAUS_OSC_CTRL	0x15
+#define MENELAUS_DETECT_CTRL	0x16
+#define MENELAUS_INT_MASK1	0x17
+#define MENELAUS_INT_MASK2	0x18
+#define MENELAUS_INT_STATUS1	0x19
+#define MENELAUS_INT_STATUS2	0x1a
+#define MENELAUS_INT_ACK1	0x1b
+#define MENELAUS_INT_ACK2	0x1c
+#define MENELAUS_GPIO_CTRL	0x1d
+#define MENELAUS_GPIO_IN	0x1e
+#define MENELAUS_GPIO_OUT	0x1f
+#define MENELAUS_BBSMS		0x20
+#define MENELAUS_RTC_CTRL	0x21
+#define MENELAUS_RTC_UPDATE	0x22
+#define MENELAUS_RTC_SEC	0x23
+#define MENELAUS_RTC_MIN	0x24
+#define MENELAUS_RTC_HR		0x25
+#define MENELAUS_RTC_DAY	0x26
+#define MENELAUS_RTC_MON	0x27
+#define MENELAUS_RTC_YR		0x28
+#define MENELAUS_RTC_WKDAY	0x29
+#define MENELAUS_RTC_AL_SEC	0x2a
+#define MENELAUS_RTC_AL_MIN	0x2b
+#define MENELAUS_RTC_AL_HR	0x2c
+#define MENELAUS_RTC_AL_DAY	0x2d
+#define MENELAUS_RTC_AL_MON	0x2e
+#define MENELAUS_RTC_AL_YR	0x2f
+#define MENELAUS_RTC_COMP_MSB	0x30
+#define MENELAUS_RTC_COMP_LSB	0x31
+#define MENELAUS_S1_PULL_EN	0x32
+#define MENELAUS_S1_PULL_DIR	0x33
+#define MENELAUS_S2_PULL_EN	0x34
+#define MENELAUS_S2_PULL_DIR	0x35
+#define MENELAUS_MCT_CTRL1	0x36
+#define MENELAUS_MCT_CTRL2	0x37
+#define MENELAUS_MCT_CTRL3	0x38
+#define MENELAUS_MCT_PIN_ST	0x39
+#define MENELAUS_DEBOUNCE1	0x3a
+
+static uint8_t menelaus_read(void *opaque, uint8_t addr)
+{
+    MenelausState *s = (MenelausState *) opaque;
+    int reg = 0;
+
+    switch (addr) {
+    case MENELAUS_REV:
+        return 0x22;
+
+    case MENELAUS_VCORE_CTRL5: reg ++;
+    case MENELAUS_VCORE_CTRL4: reg ++;
+    case MENELAUS_VCORE_CTRL3: reg ++;
+    case MENELAUS_VCORE_CTRL2: reg ++;
+    case MENELAUS_VCORE_CTRL1:
+        return s->vcore[reg];
+
+    case MENELAUS_DCDC_CTRL3: reg ++;
+    case MENELAUS_DCDC_CTRL2: reg ++;
+    case MENELAUS_DCDC_CTRL1:
+        return s->dcdc[reg];
+
+    case MENELAUS_LDO_CTRL8: reg ++;
+    case MENELAUS_LDO_CTRL7: reg ++;
+    case MENELAUS_LDO_CTRL6: reg ++;
+    case MENELAUS_LDO_CTRL5: reg ++;
+    case MENELAUS_LDO_CTRL4: reg ++;
+    case MENELAUS_LDO_CTRL3: reg ++;
+    case MENELAUS_LDO_CTRL2: reg ++;
+    case MENELAUS_LDO_CTRL1:
+        return s->ldo[reg];
+
+    case MENELAUS_SLEEP_CTRL2: reg ++;
+    case MENELAUS_SLEEP_CTRL1:
+        return s->sleep[reg];
+
+    case MENELAUS_DEVICE_OFF:
+        return 0;
+
+    case MENELAUS_OSC_CTRL:
+        return s->osc | (1 << 7);			/* CLK32K_GOOD */
+
+    case MENELAUS_DETECT_CTRL:
+        return s->detect;
+
+    case MENELAUS_INT_MASK1:
+        return (s->mask >> 0) & 0xff;
+    case MENELAUS_INT_MASK2:
+        return (s->mask >> 8) & 0xff;
+
+    case MENELAUS_INT_STATUS1:
+        return (s->status >> 0) & 0xff;
+    case MENELAUS_INT_STATUS2:
+        return (s->status >> 8) & 0xff;
+
+    case MENELAUS_INT_ACK1:
+    case MENELAUS_INT_ACK2:
+        return 0;
+
+    case MENELAUS_GPIO_CTRL:
+        return s->dir;
+    case MENELAUS_GPIO_IN:
+        return s->inputs | (~s->dir & s->outputs);
+    case MENELAUS_GPIO_OUT:
+        return s->outputs;
+
+    case MENELAUS_BBSMS:
+        return s->bbsms;
+
+    case MENELAUS_RTC_CTRL:
+        return s->rtc.ctrl;
+    case MENELAUS_RTC_UPDATE:
+        return 0x00;
+    case MENELAUS_RTC_SEC:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_sec);
+    case MENELAUS_RTC_MIN:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_min);
+    case MENELAUS_RTC_HR:
+        menelaus_rtc_update(s);
+        if ((s->rtc.ctrl >> 2) & 1)			/* MODE12_n24 */
+            return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
+                    (!!(s->rtc.tm.tm_hour >= 12) << 7);	/* PM_nAM */
+        else
+            return to_bcd(s->rtc.tm.tm_hour);
+    case MENELAUS_RTC_DAY:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_mday);
+    case MENELAUS_RTC_MON:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_mon + 1);
+    case MENELAUS_RTC_YR:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_year - 2000);
+    case MENELAUS_RTC_WKDAY:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_wday);
+    case MENELAUS_RTC_AL_SEC:
+        return to_bcd(s->rtc.alm.tm_sec);
+    case MENELAUS_RTC_AL_MIN:
+        return to_bcd(s->rtc.alm.tm_min);
+    case MENELAUS_RTC_AL_HR:
+        if ((s->rtc.ctrl >> 2) & 1)			/* MODE12_n24 */
+            return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
+                    (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
+        else
+            return to_bcd(s->rtc.alm.tm_hour);
+    case MENELAUS_RTC_AL_DAY:
+        return to_bcd(s->rtc.alm.tm_mday);
+    case MENELAUS_RTC_AL_MON:
+        return to_bcd(s->rtc.alm.tm_mon + 1);
+    case MENELAUS_RTC_AL_YR:
+        return to_bcd(s->rtc.alm.tm_year - 2000);
+    case MENELAUS_RTC_COMP_MSB:
+        return (s->rtc.comp >> 8) & 0xff;
+    case MENELAUS_RTC_COMP_LSB:
+        return (s->rtc.comp >> 0) & 0xff;
+
+    case MENELAUS_S1_PULL_EN:
+        return s->pull[0];
+    case MENELAUS_S1_PULL_DIR:
+        return s->pull[1];
+    case MENELAUS_S2_PULL_EN:
+        return s->pull[2];
+    case MENELAUS_S2_PULL_DIR:
+        return s->pull[3];
+
+    case MENELAUS_MCT_CTRL3: reg ++;
+    case MENELAUS_MCT_CTRL2: reg ++;
+    case MENELAUS_MCT_CTRL1:
+        return s->mmc_ctrl[reg];
+    case MENELAUS_MCT_PIN_ST:
+        /* TODO: return the real Card Detect */
+        return 0;
+    case MENELAUS_DEBOUNCE1:
+        return s->mmc_debounce;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
+#endif
+        break;
+    }
+    return 0;
+}
+
+static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    MenelausState *s = (MenelausState *) opaque;
+    int line;
+    int reg = 0;
+    struct tm tm;
+
+    switch (addr) {
+    case MENELAUS_VCORE_CTRL1:
+        s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL2:
+        s->vcore[1] = value;
+        break;
+    case MENELAUS_VCORE_CTRL3:
+        s->vcore[2] = MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL4:
+        s->vcore[3] = MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL5:
+        s->vcore[4] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+
+    case MENELAUS_DCDC_CTRL1:
+        s->dcdc[0] = value & 0x3f;
+        break;
+    case MENELAUS_DCDC_CTRL2:
+        s->dcdc[1] = value & 0x07;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_DCDC_CTRL3:
+        s->dcdc[2] = value & 0x07;
+        break;
+
+    case MENELAUS_LDO_CTRL1:
+        s->ldo[0] = value;
+        break;
+    case MENELAUS_LDO_CTRL2:
+        s->ldo[1] = value & 0x7f;
+        /* XXX
+         * auto set to 0x7e on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL3:
+        s->ldo[2] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL4:
+        s->ldo[3] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL5:
+        s->ldo[4] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL6:
+        s->ldo[5] = value & 3;
+        break;
+    case MENELAUS_LDO_CTRL7:
+        s->ldo[6] = value & 3;
+        break;
+    case MENELAUS_LDO_CTRL8:
+        s->ldo[7] = value & 3;
+        break;
+
+    case MENELAUS_SLEEP_CTRL2: reg ++;
+    case MENELAUS_SLEEP_CTRL1:
+        s->sleep[reg] = value;
+        break;
+
+    case MENELAUS_DEVICE_OFF:
+        if (value & 1)
+            menelaus_reset(&s->i2c);
+        break;
+
+    case MENELAUS_OSC_CTRL:
+        s->osc = value & 7;
+        break;
+
+    case MENELAUS_DETECT_CTRL:
+        s->detect = value & 0x7f;
+        break;
+
+    case MENELAUS_INT_MASK1:
+        s->mask &= 0xf00;
+        s->mask |= value << 0;
+        menelaus_update(s);
+        break;
+    case MENELAUS_INT_MASK2:
+        s->mask &= 0x0ff;
+        s->mask |= value << 8;
+        menelaus_update(s);
+        break;
+
+    case MENELAUS_INT_ACK1:
+        s->status &= ~(((uint16_t) value) << 0);
+        menelaus_update(s);
+        break;
+    case MENELAUS_INT_ACK2:
+        s->status &= ~(((uint16_t) value) << 8);
+        menelaus_update(s);
+        break;
+
+    case MENELAUS_GPIO_CTRL:
+        for (line = 0; line < 3; line ++) {
+            if (((s->dir ^ value) >> line) & 1) {
+                qemu_set_irq(s->out[line],
+                             ((s->outputs & ~s->dir) >> line) & 1);
+            }
+        }
+        s->dir = value & 0x67;
+        break;
+    case MENELAUS_GPIO_OUT:
+        for (line = 0; line < 3; line ++) {
+            if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
+                qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
+            }
+        }
+        s->outputs = value & 0x07;
+        break;
+
+    case MENELAUS_BBSMS:
+        s->bbsms = 0x0d;
+        break;
+
+    case MENELAUS_RTC_CTRL:
+        if ((s->rtc.ctrl ^ value) & 1) {			/* RTC_EN */
+            if (value & 1)
+                menelaus_rtc_start(s);
+            else
+                menelaus_rtc_stop(s);
+        }
+        s->rtc.ctrl = value & 0x1f;
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_UPDATE:
+        menelaus_rtc_update(s);
+        memcpy(&tm, &s->rtc.tm, sizeof(tm));
+        switch (value & 0xf) {
+        case 0:
+            break;
+        case 1:
+            tm.tm_sec = s->rtc.new.tm_sec;
+            break;
+        case 2:
+            tm.tm_min = s->rtc.new.tm_min;
+            break;
+        case 3:
+            if (s->rtc.new.tm_hour > 23)
+                goto rtc_badness;
+            tm.tm_hour = s->rtc.new.tm_hour;
+            break;
+        case 4:
+            if (s->rtc.new.tm_mday < 1)
+                goto rtc_badness;
+            /* TODO check range */
+            tm.tm_mday = s->rtc.new.tm_mday;
+            break;
+        case 5:
+            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
+                goto rtc_badness;
+            tm.tm_mon = s->rtc.new.tm_mon;
+            break;
+        case 6:
+            tm.tm_year = s->rtc.new.tm_year;
+            break;
+        case 7:
+            /* TODO set .tm_mday instead */
+            tm.tm_wday = s->rtc.new.tm_wday;
+            break;
+        case 8:
+            if (s->rtc.new.tm_hour > 23)
+                goto rtc_badness;
+            if (s->rtc.new.tm_mday < 1)
+                goto rtc_badness;
+            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
+                goto rtc_badness;
+            tm.tm_sec = s->rtc.new.tm_sec;
+            tm.tm_min = s->rtc.new.tm_min;
+            tm.tm_hour = s->rtc.new.tm_hour;
+            tm.tm_mday = s->rtc.new.tm_mday;
+            tm.tm_mon = s->rtc.new.tm_mon;
+            tm.tm_year = s->rtc.new.tm_year;
+            break;
+        rtc_badness:
+        default:
+            fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
+                            __FUNCTION__, value);
+            s->status |= 1 << 10;				/* RTCERR */
+            menelaus_update(s);
+        }
+        s->rtc.sec_offset = qemu_timedate_diff(&tm);
+        break;
+    case MENELAUS_RTC_SEC:
+        s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
+        break;
+    case MENELAUS_RTC_MIN:
+        s->rtc.tm.tm_min = from_bcd(value & 0x7f);
+        break;
+    case MENELAUS_RTC_HR:
+        s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?	/* MODE12_n24 */
+                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
+                from_bcd(value & 0x3f);
+        break;
+    case MENELAUS_RTC_DAY:
+        s->rtc.tm.tm_mday = from_bcd(value);
+        break;
+    case MENELAUS_RTC_MON:
+        s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
+        break;
+    case MENELAUS_RTC_YR:
+        s->rtc.tm.tm_year = 2000 + from_bcd(value);
+        break;
+    case MENELAUS_RTC_WKDAY:
+        s->rtc.tm.tm_mday = from_bcd(value);
+        break;
+    case MENELAUS_RTC_AL_SEC:
+        s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_MIN:
+        s->rtc.alm.tm_min = from_bcd(value & 0x7f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_HR:
+        s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?	/* MODE12_n24 */
+                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
+                from_bcd(value & 0x3f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_DAY:
+        s->rtc.alm.tm_mday = from_bcd(value);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_MON:
+        s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_YR:
+        s->rtc.alm.tm_year = 2000 + from_bcd(value);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_COMP_MSB:
+        s->rtc.comp &= 0xff;
+        s->rtc.comp |= value << 8;
+        break;
+    case MENELAUS_RTC_COMP_LSB:
+        s->rtc.comp &= 0xff << 8;
+        s->rtc.comp |= value;
+        break;
+
+    case MENELAUS_S1_PULL_EN:
+        s->pull[0] = value;
+        break;
+    case MENELAUS_S1_PULL_DIR:
+        s->pull[1] = value & 0x1f;
+        break;
+    case MENELAUS_S2_PULL_EN:
+        s->pull[2] = value;
+        break;
+    case MENELAUS_S2_PULL_DIR:
+        s->pull[3] = value & 0x1f;
+        break;
+
+    case MENELAUS_MCT_CTRL1:
+        s->mmc_ctrl[0] = value & 0x7f;
+        break;
+    case MENELAUS_MCT_CTRL2:
+        s->mmc_ctrl[1] = value;
+        /* TODO update Card Detect interrupts */
+        break;
+    case MENELAUS_MCT_CTRL3:
+        s->mmc_ctrl[2] = value & 0xf;
+        break;
+    case MENELAUS_DEBOUNCE1:
+        s->mmc_debounce = value & 0x3f;
+        break;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
+#endif
+    }
+}
+
+static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
+{
+    MenelausState *s = (MenelausState *) i2c;
+
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static int menelaus_tx(i2c_slave *i2c, uint8_t data)
+{
+    MenelausState *s = (MenelausState *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        menelaus_write(s, s->reg ++, data);
+
+    return 0;
+}
+
+static int menelaus_rx(i2c_slave *i2c)
+{
+    MenelausState *s = (MenelausState *) i2c;
+
+    return menelaus_read(s, s->reg ++);
+}
+
+/* Save restore 32 bit int as uint16_t
+   This is a Big hack, but it is how the old state did it.
+   Or we broke compatibility in the state, or we can't use struct tm
+ */
+
+static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    int *v = pv;
+    *v = qemu_get_be16(f);
+    return 0;
+}
+
+static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    int *v = pv;
+    qemu_put_be16(f, *v);
+}
+
+static const VMStateInfo vmstate_hack_int32_as_uint16 = {
+    .name = "int32_as_uint16",
+    .get  = get_int32_as_uint16,
+    .put  = put_int32_as_uint16,
+};
+
+#define VMSTATE_UINT16_HACK(_f, _s)                                  \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
+
+
+static const VMStateDescription vmstate_menelaus_tm = {
+    .name = "menelaus_tm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16_HACK(tm_sec, struct tm),
+        VMSTATE_UINT16_HACK(tm_min, struct tm),
+        VMSTATE_UINT16_HACK(tm_hour, struct tm),
+        VMSTATE_UINT16_HACK(tm_mday, struct tm),
+        VMSTATE_UINT16_HACK(tm_min, struct tm),
+        VMSTATE_UINT16_HACK(tm_year, struct tm),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void menelaus_pre_save(void *opaque)
+{
+    MenelausState *s = opaque;
+    /* Should be <= 1000 */
+    s->rtc_next_vmstate =  s->rtc.next - qemu_get_clock_ms(rt_clock);
+}
+
+static int menelaus_post_load(void *opaque, int version_id)
+{
+    MenelausState *s = opaque;
+
+    if (s->rtc.ctrl & 1)					/* RTC_EN */
+        menelaus_rtc_stop(s);
+
+    s->rtc.next = s->rtc_next_vmstate;
+
+    menelaus_alm_update(s);
+    menelaus_update(s);
+    if (s->rtc.ctrl & 1)					/* RTC_EN */
+        menelaus_rtc_start(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_menelaus = {
+    .name = "menelaus",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = menelaus_pre_save,
+    .post_load = menelaus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(firstbyte, MenelausState),
+        VMSTATE_UINT8(reg, MenelausState),
+        VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
+        VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
+        VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
+        VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
+        VMSTATE_UINT8(osc, MenelausState),
+        VMSTATE_UINT8(detect, MenelausState),
+        VMSTATE_UINT16(mask, MenelausState),
+        VMSTATE_UINT16(status, MenelausState),
+        VMSTATE_UINT8(dir, MenelausState),
+        VMSTATE_UINT8(inputs, MenelausState),
+        VMSTATE_UINT8(outputs, MenelausState),
+        VMSTATE_UINT8(bbsms, MenelausState),
+        VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
+        VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
+        VMSTATE_UINT8(mmc_debounce, MenelausState),
+        VMSTATE_UINT8(rtc.ctrl, MenelausState),
+        VMSTATE_UINT16(rtc.comp, MenelausState),
+        VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
+        VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
+                       struct tm),
+        VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
+                       struct tm),
+        VMSTATE_UINT8(pwrbtn_state, MenelausState),
+        VMSTATE_I2C_SLAVE(i2c, MenelausState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int twl92230_init(i2c_slave *i2c)
+{
+    MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
+
+    s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s);
+    /* Three output pins plus one interrupt pin.  */
+    qdev_init_gpio_out(&i2c->qdev, s->out, 4);
+    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 3);
+    s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0];
+
+    menelaus_reset(&s->i2c);
+
+    return 0;
+}
+
+static I2CSlaveInfo twl92230_info = {
+    .qdev.name ="twl92230",
+    .qdev.size = sizeof(MenelausState),
+    .qdev.vmsd = &vmstate_menelaus,
+    .init = twl92230_init,
+    .event = menelaus_event,
+    .recv = menelaus_rx,
+    .send = menelaus_tx
+};
+
+static void twl92230_register_devices(void)
+{
+    i2c_register_slave(&twl92230_info);
+}
+
+device_init(twl92230_register_devices)
diff --git a/qemu-0.15.x/hw/unin_pci.c b/qemu-0.15.x/hw/unin_pci.c
new file mode 100644
index 0000000..d364daa
--- /dev/null
+++ b/qemu-0.15.x/hw/unin_pci.c
@@ -0,0 +1,369 @@
+/*
+ * QEMU Uninorth PCI host (for all Mac99 and newer machines)
+ *
+ * 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 "hw.h"
+#include "ppc_mac.h"
+#include "pci.h"
+#include "pci_host.h"
+
+/* debug UniNorth */
+//#define DEBUG_UNIN
+
+#ifdef DEBUG_UNIN
+#define UNIN_DPRINTF(fmt, ...)                                  \
+    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define UNIN_DPRINTF(fmt, ...)
+#endif
+
+static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+
+typedef struct UNINState {
+    SysBusDevice busdev;
+    PCIHostState host_state;
+    ReadWriteHandler data_handler;
+} UNINState;
+
+static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int retval;
+    int devfn = pci_dev->devfn & 0x00FFFFFF;
+
+    retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
+
+    return retval;
+}
+
+static void pci_unin_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
+                 unin_irq_line[irq_num], level);
+    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
+}
+
+static void pci_unin_reset(void *opaque)
+{
+}
+
+static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
+{
+    uint32_t retval;
+
+    if (reg & (1u << 31)) {
+        /* XXX OpenBIOS compatibility hack */
+        retval = reg | (addr & 3);
+    } else if (reg & 1) {
+        /* CFA1 style */
+        retval = (reg & ~7u) | (addr & 7);
+    } else {
+        uint32_t slot, func;
+
+        /* Grab CFA0 style values */
+        slot = ffs(reg & 0xfffff800) - 1;
+        func = (reg >> 8) & 7;
+
+        /* ... and then convert them to x86 format */
+        /* config pointer */
+        retval = (reg & (0xff - 7)) | (addr & 7);
+        /* slot */
+        retval |= slot << 11;
+        /* fn */
+        retval |= func << 8;
+    }
+
+
+    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
+                 reg, addr, retval);
+
+    return retval;
+}
+
+static void unin_data_write(ReadWriteHandler *handler,
+                            pcibus_t addr, uint32_t val, int len)
+{
+    UNINState *s = container_of(handler, UNINState, data_handler);
+    UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    pci_data_write(s->host_state.bus,
+                   unin_get_config_reg(s->host_state.config_reg, addr),
+                   val, len);
+}
+
+static uint32_t unin_data_read(ReadWriteHandler *handler,
+                               pcibus_t addr, int len)
+{
+    UNINState *s = container_of(handler, UNINState, data_handler);
+    uint32_t val;
+
+    val = pci_data_read(s->host_state.bus,
+                        unin_get_config_reg(s->host_state.config_reg, addr),
+                        len);
+    UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    return val;
+}
+
+static int pci_unin_main_init_device(SysBusDevice *dev)
+{
+    UNINState *s;
+    int pci_mem_config, pci_mem_data;
+
+    /* Use values found on a real PowerMac */
+    /* Uninorth main bus */
+    s = FROM_SYSBUS(UNINState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    s->data_handler.read = unin_data_read;
+    s->data_handler.write = unin_data_write;
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
+                                                 DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+
+    qemu_register_reset(pci_unin_reset, &s->host_state);
+    return 0;
+}
+
+static int pci_u3_agp_init_device(SysBusDevice *dev)
+{
+    UNINState *s;
+    int pci_mem_config, pci_mem_data;
+
+    /* Uninorth U3 AGP bus */
+    s = FROM_SYSBUS(UNINState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    s->data_handler.read = unin_data_read;
+    s->data_handler.write = unin_data_write;
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
+                                                 DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+
+    qemu_register_reset(pci_unin_reset, &s->host_state);
+
+    return 0;
+}
+
+static int pci_unin_agp_init_device(SysBusDevice *dev)
+{
+    UNINState *s;
+    int pci_mem_config, pci_mem_data;
+
+    /* Uninorth AGP bus */
+    s = FROM_SYSBUS(UNINState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    return 0;
+}
+
+static int pci_unin_internal_init_device(SysBusDevice *dev)
+{
+    UNINState *s;
+    int pci_mem_config, pci_mem_data;
+
+    /* Uninorth internal bus */
+    s = FROM_SYSBUS(UNINState, dev);
+
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    return 0;
+}
+
+PCIBus *pci_pmac_init(qemu_irq *pic)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    UNINState *d;
+
+    /* Use values found on a real PowerMac */
+    /* Uninorth main bus */
+    dev = qdev_create(NULL, "uni-north");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(UNINState, s);
+    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                         pci_unin_set_irq, pci_unin_map_irq,
+                                         pic, PCI_DEVFN(11, 0), 4);
+
+#if 0
+    pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
+#endif
+
+    sysbus_mmio_map(s, 0, 0xf2800000);
+    sysbus_mmio_map(s, 1, 0xf2c00000);
+
+    /* DEC 21154 bridge */
+#if 0
+    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
+    pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154");
+#endif
+
+    /* Uninorth AGP bus */
+    pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
+    dev = qdev_create(NULL, "uni-north-agp");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, 0xf0800000);
+    sysbus_mmio_map(s, 1, 0xf0c00000);
+
+    /* Uninorth internal bus */
+#if 0
+    /* XXX: not needed for now */
+    pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
+    dev = qdev_create(NULL, "uni-north-pci");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, 0xf4800000);
+    sysbus_mmio_map(s, 1, 0xf4c00000);
+#endif
+
+    return d->host_state.bus;
+}
+
+PCIBus *pci_pmac_u3_init(qemu_irq *pic)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    UNINState *d;
+
+    /* Uninorth AGP bus */
+
+    dev = qdev_create(NULL, "u3-agp");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(UNINState, s);
+
+    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                         pci_unin_set_irq, pci_unin_map_irq,
+                                         pic, PCI_DEVFN(11, 0), 4);
+
+    sysbus_mmio_map(s, 0, 0xf0800000);
+    sysbus_mmio_map(s, 1, 0xf0c00000);
+
+    pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
+
+    return d->host_state.bus;
+}
+
+static int unin_main_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+    return 0;
+}
+
+static int unin_agp_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    //    d->config[0x34] = 0x80; // capabilities_pointer
+    return 0;
+}
+
+static int u3_agp_pci_host_init(PCIDevice *d)
+{
+    /* cache line size */
+    d->config[0x0C] = 0x08;
+    /* latency timer */
+    d->config[0x0D] = 0x10;
+    return 0;
+}
+
+static int unin_internal_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+    return 0;
+}
+
+static PCIDeviceInfo unin_main_pci_host_info = {
+    .qdev.name = "uni-north",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = unin_main_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static PCIDeviceInfo u3_agp_pci_host_info = {
+    .qdev.name = "u3-agp",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = u3_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static PCIDeviceInfo unin_agp_pci_host_info = {
+    .qdev.name = "uni-north-agp",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = unin_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static PCIDeviceInfo unin_internal_pci_host_info = {
+    .qdev.name = "uni-north-pci",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = unin_internal_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
+
+static void unin_register_devices(void)
+{
+    sysbus_register_dev("uni-north", sizeof(UNINState),
+                        pci_unin_main_init_device);
+    pci_qdev_register(&unin_main_pci_host_info);
+    sysbus_register_dev("u3-agp", sizeof(UNINState),
+                        pci_u3_agp_init_device);
+    pci_qdev_register(&u3_agp_pci_host_info);
+    sysbus_register_dev("uni-north-agp", sizeof(UNINState),
+                        pci_unin_agp_init_device);
+    pci_qdev_register(&unin_agp_pci_host_info);
+    sysbus_register_dev("uni-north-pci", sizeof(UNINState),
+                        pci_unin_internal_init_device);
+    pci_qdev_register(&unin_internal_pci_host_info);
+}
+
+device_init(unin_register_devices)
diff --git a/qemu-0.15.x/hw/usb-bt.c b/qemu-0.15.x/hw/usb-bt.c
new file mode 100644
index 0000000..e364513
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-bt.c
@@ -0,0 +1,568 @@
+/*
+ * QEMU Bluetooth HCI USB Transport Layer v1.0
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "net.h"
+#include "bt.h"
+
+struct USBBtState {
+    USBDevice dev;
+    struct HCIInfo *hci;
+
+    int altsetting;
+    int config;
+
+#define CFIFO_LEN_MASK	255
+#define DFIFO_LEN_MASK	4095
+    struct usb_hci_in_fifo_s {
+        uint8_t data[(DFIFO_LEN_MASK + 1) * 2];
+        struct {
+            uint8_t *data;
+            int len;
+        } fifo[CFIFO_LEN_MASK + 1];
+        int dstart, dlen, dsize, start, len;
+    } evt, acl, sco;
+
+    struct usb_hci_out_fifo_s {
+        uint8_t data[4096];
+	int len;
+    } outcmd, outacl, outsco;
+};
+
+#define USB_EVT_EP	1
+#define USB_ACL_EP	2
+#define USB_SCO_EP	3
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_SERIALNUMBER]     = "1",
+};
+
+static const USBDescIface desc_iface_bluetooth[] = {
+    {
+        .bInterfaceNumber              = 0,
+        .bNumEndpoints                 = 3,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_EVT_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .wMaxPacketSize        = 0x10,
+                .bInterval             = 0x02,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_ACL_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+                .bInterval             = 0x0a,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_ACL_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+                .bInterval             = 0x0a,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 0,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0,
+                .bInterval             = 0x01,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 1,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x09,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x09,
+                .bInterval             = 0x01,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 2,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x11,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x11,
+                .bInterval             = 0x01,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 3,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x19,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x19,
+                .bInterval             = 0x01,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 4,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x21,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x21,
+                .bInterval             = 0x01,
+            },
+        },
+    },{
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 5,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = 0xe0, /* Wireless */
+        .bInterfaceSubClass            = 0x01, /* Radio Frequency */
+        .bInterfaceProtocol            = 0x01, /* Bluetooth */
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_OUT | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x31,
+                .bInterval             = 0x01,
+            },
+            {
+                .bEndpointAddress      = USB_DIR_IN | USB_SCO_EP,
+                .bmAttributes          = USB_ENDPOINT_XFER_ISOC,
+                .wMaxPacketSize        = 0x31,
+                .bInterval             = 0x01,
+            },
+        },
+    }
+};
+
+static const USBDescDevice desc_device_bluetooth = {
+    .bcdUSB                        = 0x0110,
+    .bDeviceClass                  = 0xe0, /* Wireless */
+    .bDeviceSubClass               = 0x01, /* Radio Frequency */
+    .bDeviceProtocol               = 0x01, /* Bluetooth */
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 2,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0xc0,
+            .bMaxPower             = 0,
+            .nif = ARRAY_SIZE(desc_iface_bluetooth),
+            .ifs = desc_iface_bluetooth,
+        },
+    },
+};
+
+static const USBDesc desc_bluetooth = {
+    .id = {
+        .idVendor          = 0x0a12,
+        .idProduct         = 0x0001,
+        .bcdDevice         = 0x1958,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = 0,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_bluetooth,
+    .str  = desc_strings,
+};
+
+static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
+{
+    fifo->dstart = 0;
+    fifo->dlen = 0;
+    fifo->dsize = DFIFO_LEN_MASK + 1;
+    fifo->start = 0;
+    fifo->len = 0;
+}
+
+static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
+                const uint8_t *data, int len)
+{
+    int off = fifo->dstart + fifo->dlen;
+    uint8_t *buf;
+
+    fifo->dlen += len;
+    if (off <= DFIFO_LEN_MASK) {
+        if (off + len > DFIFO_LEN_MASK + 1 &&
+                        (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) {
+            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+            exit(-1);
+        }
+        buf = fifo->data + off;
+    } else {
+        if (fifo->dlen > fifo->dsize) {
+            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+            exit(-1);
+        }
+        buf = fifo->data + off - fifo->dsize;
+    }
+
+    off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK;
+    fifo->fifo[off].data = memcpy(buf, data, len);
+    fifo->fifo[off].len = len;
+}
+
+static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
+                USBPacket *p)
+{
+    int len;
+
+    if (likely(!fifo->len))
+        return USB_RET_STALL;
+
+    len = MIN(p->len, fifo->fifo[fifo->start].len);
+    memcpy(p->data, fifo->fifo[fifo->start].data, len);
+    if (len == p->len) {
+        fifo->fifo[fifo->start].len -= len;
+        fifo->fifo[fifo->start].data += len;
+    } else {
+        fifo->start ++;
+        fifo->start &= CFIFO_LEN_MASK;
+        fifo->len --;
+    }
+
+    fifo->dstart += len;
+    fifo->dlen -= len;
+    if (fifo->dstart >= fifo->dsize) {
+        fifo->dstart = 0;
+        fifo->dsize = DFIFO_LEN_MASK + 1;
+    }
+
+    return len;
+}
+
+static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
+                struct usb_hci_out_fifo_s *fifo,
+                void (*send)(struct HCIInfo *, const uint8_t *, int),
+                int (*complete)(const uint8_t *, int),
+                const uint8_t *data, int len)
+{
+    if (fifo->len) {
+        memcpy(fifo->data + fifo->len, data, len);
+        fifo->len += len;
+        if (complete(fifo->data, fifo->len)) {
+            send(s->hci, fifo->data, fifo->len);
+            fifo->len = 0;
+        }
+    } else if (complete(data, len))
+        send(s->hci, data, len);
+    else {
+        memcpy(fifo->data, data, len);
+        fifo->len = len;
+    }
+
+    /* TODO: do we need to loop? */
+}
+
+static int usb_bt_hci_cmd_complete(const uint8_t *data, int len)
+{
+    len -= HCI_COMMAND_HDR_SIZE;
+    return len >= 0 &&
+            len >= ((struct hci_command_hdr *) data)->plen;
+}
+
+static int usb_bt_hci_acl_complete(const uint8_t *data, int len)
+{
+    len -= HCI_ACL_HDR_SIZE;
+    return len >= 0 &&
+            len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen);
+}
+
+static int usb_bt_hci_sco_complete(const uint8_t *data, int len)
+{
+    len -= HCI_SCO_HDR_SIZE;
+    return len >= 0 &&
+            len >= ((struct hci_sco_hdr *) data)->dlen;
+}
+
+static void usb_bt_handle_reset(USBDevice *dev)
+{
+    struct USBBtState *s = (struct USBBtState *) dev->opaque;
+
+    usb_bt_fifo_reset(&s->evt);
+    usb_bt_fifo_reset(&s->acl);
+    usb_bt_fifo_reset(&s->sco);
+    s->outcmd.len = 0;
+    s->outacl.len = 0;
+    s->outsco.len = 0;
+    s->altsetting = 0;
+}
+
+static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    struct USBBtState *s = (struct USBBtState *) dev->opaque;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        switch (request) {
+        case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+            s->config = 0;
+            break;
+        case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+            s->config = 1;
+            usb_bt_fifo_reset(&s->evt);
+            usb_bt_fifo_reset(&s->acl);
+            usb_bt_fifo_reset(&s->sco);
+            break;
+        }
+        return ret;
+    }
+
+    ret = 0;
+    switch (request) {
+    case InterfaceRequest | USB_REQ_GET_STATUS:
+    case EndpointRequest | USB_REQ_GET_STATUS:
+        data[0] = 0x00;
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        goto fail;
+    case InterfaceOutRequest | USB_REQ_SET_FEATURE:
+    case EndpointOutRequest | USB_REQ_SET_FEATURE:
+        goto fail;
+        break;
+    case InterfaceRequest | USB_REQ_GET_INTERFACE:
+        if (value != 0 || (index & ~1) || length != 1)
+            goto fail;
+        if (index == 1)
+            data[0] = s->altsetting;
+        else
+            data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        if ((index & ~1) || length != 0 ||
+                        (index == 1 && (value < 0 || value > 4)) ||
+                        (index == 0 && value != 0)) {
+            printf("%s: Wrong SET_INTERFACE request (%i, %i)\n",
+                            __FUNCTION__, index, value);
+            goto fail;
+        }
+        s->altsetting = value;
+        ret = 0;
+        break;
+    case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
+        if (s->config)
+            usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
+                            usb_bt_hci_cmd_complete, data, length);
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
+{
+    struct USBBtState *s = (struct USBBtState *) dev->opaque;
+    int ret = 0;
+
+    if (!s->config)
+        goto fail;
+
+    switch (p->pid) {
+    case USB_TOKEN_IN:
+        switch (p->devep & 0xf) {
+        case USB_EVT_EP:
+            ret = usb_bt_fifo_dequeue(&s->evt, p);
+            break;
+
+        case USB_ACL_EP:
+            ret = usb_bt_fifo_dequeue(&s->acl, p);
+            break;
+
+        case USB_SCO_EP:
+            ret = usb_bt_fifo_dequeue(&s->sco, p);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case USB_TOKEN_OUT:
+        switch (p->devep & 0xf) {
+        case USB_ACL_EP:
+            usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
+                            usb_bt_hci_acl_complete, p->data, p->len);
+            break;
+
+        case USB_SCO_EP:
+            usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
+                            usb_bt_hci_sco_complete, p->data, p->len);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void usb_bt_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct USBBtState *s = (struct USBBtState *) opaque;
+
+    usb_bt_fifo_enqueue(&s->evt, data, len);
+}
+
+static void usb_bt_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct USBBtState *s = (struct USBBtState *) opaque;
+
+    usb_bt_fifo_enqueue(&s->acl, data, len);
+}
+
+static void usb_bt_handle_destroy(USBDevice *dev)
+{
+    struct USBBtState *s = (struct USBBtState *) dev->opaque;
+
+    s->hci->opaque = NULL;
+    s->hci->evt_recv = NULL;
+    s->hci->acl_recv = NULL;
+}
+
+static int usb_bt_initfn(USBDevice *dev)
+{
+    usb_desc_init(dev);
+    return 0;
+}
+
+USBDevice *usb_bt_init(HCIInfo *hci)
+{
+    USBDevice *dev;
+    struct USBBtState *s;
+
+    if (!hci)
+        return NULL;
+    dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle");
+    s = DO_UPCAST(struct USBBtState, dev, dev);
+    s->dev.opaque = s;
+
+    s->hci = hci;
+    s->hci->opaque = s;
+    s->hci->evt_recv = usb_bt_out_hci_packet_event;
+    s->hci->acl_recv = usb_bt_out_hci_packet_acl;
+
+    usb_bt_handle_reset(&s->dev);
+
+    return dev;
+}
+
+static struct USBDeviceInfo bt_info = {
+    .product_desc   = "QEMU BT dongle",
+    .qdev.name      = "usb-bt-dongle",
+    .qdev.size      = sizeof(struct USBBtState),
+    .usb_desc       = &desc_bluetooth,
+    .init           = usb_bt_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_bt_handle_reset,
+    .handle_control = usb_bt_handle_control,
+    .handle_data    = usb_bt_handle_data,
+    .handle_destroy = usb_bt_handle_destroy,
+};
+
+static void usb_bt_register_devices(void)
+{
+    usb_qdev_register(&bt_info);
+}
+device_init(usb_bt_register_devices)
diff --git a/qemu-0.15.x/hw/usb-bus.c b/qemu-0.15.x/hw/usb-bus.c
new file mode 100644
index 0000000..f1dd55e
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-bus.c
@@ -0,0 +1,445 @@
+#include "hw.h"
+#include "usb.h"
+#include "qdev.h"
+#include "sysemu.h"
+#include "monitor.h"
+
+static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
+
+static char *usb_get_dev_path(DeviceState *dev);
+static char *usb_get_fw_dev_path(DeviceState *qdev);
+
+static struct BusInfo usb_bus_info = {
+    .name      = "USB",
+    .size      = sizeof(USBBus),
+    .print_dev = usb_bus_dev_print,
+    .get_dev_path = usb_get_dev_path,
+    .get_fw_dev_path = usb_get_fw_dev_path,
+    .props      = (Property[]) {
+        DEFINE_PROP_STRING("port", USBDevice, port_path),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+static int next_usb_bus = 0;
+static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
+
+const VMStateDescription vmstate_usb_device = {
+    .name = "USBDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(addr, USBDevice),
+        VMSTATE_INT32(state, USBDevice),
+        VMSTATE_INT32(remote_wakeup, USBDevice),
+        VMSTATE_INT32(setup_state, USBDevice),
+        VMSTATE_INT32(setup_len, USBDevice),
+        VMSTATE_INT32(setup_index, USBDevice),
+        VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
+{
+    qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
+    bus->ops = ops;
+    bus->busnr = next_usb_bus++;
+    bus->qbus.allow_hotplug = 1; /* Yes, we can */
+    QTAILQ_INIT(&bus->free);
+    QTAILQ_INIT(&bus->used);
+    QTAILQ_INSERT_TAIL(&busses, bus, next);
+}
+
+USBBus *usb_bus_find(int busnr)
+{
+    USBBus *bus;
+
+    if (-1 == busnr)
+        return QTAILQ_FIRST(&busses);
+    QTAILQ_FOREACH(bus, &busses, next) {
+        if (bus->busnr == busnr)
+            return bus;
+    }
+    return NULL;
+}
+
+static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+    int rc;
+
+    pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
+    dev->info = info;
+    dev->auto_attach = 1;
+    QLIST_INIT(&dev->strings);
+    rc = dev->info->init(dev);
+    if (rc == 0 && dev->auto_attach)
+        rc = usb_device_attach(dev);
+    return rc;
+}
+
+static int usb_qdev_exit(DeviceState *qdev)
+{
+    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+
+    if (dev->attached) {
+        usb_device_detach(dev);
+    }
+    if (dev->info->handle_destroy) {
+        dev->info->handle_destroy(dev);
+    }
+    return 0;
+}
+
+void usb_qdev_register(USBDeviceInfo *info)
+{
+    info->qdev.bus_info = &usb_bus_info;
+    info->qdev.init     = usb_qdev_init;
+    info->qdev.unplug   = qdev_simple_unplug_cb;
+    info->qdev.exit     = usb_qdev_exit;
+    qdev_register(&info->qdev);
+}
+
+void usb_qdev_register_many(USBDeviceInfo *info)
+{
+    while (info->qdev.name) {
+        usb_qdev_register(info);
+        info++;
+    }
+}
+
+USBDevice *usb_create(USBBus *bus, const char *name)
+{
+    DeviceState *dev;
+
+#if 1
+    /* temporary stopgap until all usb is properly qdev-ified */
+    if (!bus) {
+        bus = usb_bus_find(-1);
+        if (!bus)
+            return NULL;
+        error_report("%s: no bus specified, using \"%s\" for \"%s\"\n",
+                __FUNCTION__, bus->qbus.name, name);
+    }
+#endif
+
+    dev = qdev_create(&bus->qbus, name);
+    return DO_UPCAST(USBDevice, qdev, dev);
+}
+
+USBDevice *usb_create_simple(USBBus *bus, const char *name)
+{
+    USBDevice *dev = usb_create(bus, name);
+    if (!dev) {
+        hw_error("Failed to create USB device '%s'\n", name);
+    }
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+}
+
+static void usb_fill_port(USBPort *port, void *opaque, int index,
+                          USBPortOps *ops, int speedmask)
+{
+    port->opaque = opaque;
+    port->index = index;
+    port->ops = ops;
+    port->speedmask = speedmask;
+    usb_port_location(port, NULL, index + 1);
+}
+
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+                       USBPortOps *ops, int speedmask)
+{
+    usb_fill_port(port, opaque, index, ops, speedmask);
+    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+    bus->nfree++;
+}
+
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+                           uint32_t portcount, uint32_t firstport,
+                           void *opaque, USBPortOps *ops, int speedmask)
+{
+    USBBus *bus;
+    int i;
+
+    QTAILQ_FOREACH(bus, &busses, next) {
+        if (strcmp(bus->qbus.name, masterbus) == 0) {
+            break;
+        }
+    }
+
+    if (!bus || !bus->ops->register_companion) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+                      "an USB masterbus");
+        if (bus) {
+            error_printf_unless_qmp(
+                "USB bus '%s' does not allow companion controllers\n",
+                masterbus);
+        }
+        return -1;
+    }
+
+    for (i = 0; i < portcount; i++) {
+        usb_fill_port(ports[i], opaque, i, ops, speedmask);
+    }
+
+    return bus->ops->register_companion(bus, ports, portcount, firstport);
+}
+
+void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
+{
+    if (upstream) {
+        snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
+                 upstream->path, portnr);
+    } else {
+        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
+    }
+}
+
+void usb_unregister_port(USBBus *bus, USBPort *port)
+{
+    if (port->dev)
+        qdev_free(&port->dev->qdev);
+    QTAILQ_REMOVE(&bus->free, port, next);
+    bus->nfree--;
+}
+
+static int do_attach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port;
+
+    if (dev->attached) {
+        error_report("Error: tried to attach usb device %s twice\n",
+                dev->product_desc);
+        return -1;
+    }
+    if (bus->nfree == 0) {
+        error_report("Error: tried to attach usb device %s to a bus with no free ports\n",
+                dev->product_desc);
+        return -1;
+    }
+    if (dev->port_path) {
+        QTAILQ_FOREACH(port, &bus->free, next) {
+            if (strcmp(port->path, dev->port_path) == 0) {
+                break;
+            }
+        }
+        if (port == NULL) {
+            error_report("Error: usb port %s (bus %s) not found\n",
+                    dev->port_path, bus->qbus.name);
+            return -1;
+        }
+    } else {
+        port = QTAILQ_FIRST(&bus->free);
+    }
+    if (!(port->speedmask & dev->speedmask)) {
+        error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
+                dev->product_desc, bus->qbus.name);
+        return -1;
+    }
+
+    dev->attached++;
+    QTAILQ_REMOVE(&bus->free, port, next);
+    bus->nfree--;
+
+    usb_attach(port, dev);
+
+    QTAILQ_INSERT_TAIL(&bus->used, port, next);
+    bus->nused++;
+
+    return 0;
+}
+
+int usb_device_attach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+
+    if (bus->nfree == 1 && dev->port_path == NULL) {
+        /* Create a new hub and chain it on
+           (unless a physical port location is specified). */
+        usb_create_simple(bus, "usb-hub");
+    }
+    return do_attach(dev);
+}
+
+int usb_device_detach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port;
+
+    if (!dev->attached) {
+        error_report("Error: tried to detach unattached usb device %s\n",
+                dev->product_desc);
+        return -1;
+    }
+    dev->attached--;
+
+    QTAILQ_FOREACH(port, &bus->used, next) {
+        if (port->dev == dev)
+            break;
+    }
+    assert(port != NULL);
+
+    QTAILQ_REMOVE(&bus->used, port, next);
+    bus->nused--;
+
+    usb_attach(port, NULL);
+
+    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+    bus->nfree++;
+    return 0;
+}
+
+int usb_device_delete_addr(int busnr, int addr)
+{
+    USBBus *bus;
+    USBPort *port;
+    USBDevice *dev;
+
+    bus = usb_bus_find(busnr);
+    if (!bus)
+        return -1;
+
+    QTAILQ_FOREACH(port, &bus->used, next) {
+        if (port->dev->addr == addr)
+            break;
+    }
+    if (!port)
+        return -1;
+    dev = port->dev;
+
+    qdev_free(&dev->qdev);
+    return 0;
+}
+
+static const char *usb_speed(unsigned int speed)
+{
+    static const char *txt[] = {
+        [ USB_SPEED_LOW  ] = "1.5",
+        [ USB_SPEED_FULL ] = "12",
+        [ USB_SPEED_HIGH ] = "480",
+        [ USB_SPEED_SUPER ] = "5000",
+    };
+    if (speed >= ARRAY_SIZE(txt))
+        return "?";
+    return txt[speed];
+}
+
+static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    USBBus *bus = usb_bus_from_device(dev);
+
+    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
+                   indent, "", bus->busnr, dev->addr,
+                   dev->port ? dev->port->path : "-",
+                   usb_speed(dev->speed), dev->product_desc,
+                   dev->attached ? ", attached" : "");
+}
+
+static char *usb_get_dev_path(DeviceState *qdev)
+{
+    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    return qemu_strdup(dev->port->path);
+}
+
+static char *usb_get_fw_dev_path(DeviceState *qdev)
+{
+    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+    char *fw_path, *in;
+    ssize_t pos = 0, fw_len;
+    long nr;
+
+    fw_len = 32 + strlen(dev->port->path) * 6;
+    fw_path = qemu_malloc(fw_len);
+    in = dev->port->path;
+    while (fw_len - pos > 0) {
+        nr = strtol(in, &in, 10);
+        if (in[0] == '.') {
+            /* some hub between root port and device */
+            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
+            in++;
+        } else {
+            /* the device itself */
+            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
+                            qdev_fw_name(qdev), nr);
+            break;
+        }
+    }
+    return fw_path;
+}
+
+void usb_info(Monitor *mon)
+{
+    USBBus *bus;
+    USBDevice *dev;
+    USBPort *port;
+
+    if (QTAILQ_EMPTY(&busses)) {
+        monitor_printf(mon, "USB support not enabled\n");
+        return;
+    }
+
+    QTAILQ_FOREACH(bus, &busses, next) {
+        QTAILQ_FOREACH(port, &bus->used, next) {
+            dev = port->dev;
+            if (!dev)
+                continue;
+            monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
+                           bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
+                           dev->product_desc);
+        }
+    }
+}
+
+/* handle legacy -usbdevice cmd line option */
+USBDevice *usbdevice_create(const char *cmdline)
+{
+    USBBus *bus = usb_bus_find(-1 /* any */);
+    DeviceInfo *info;
+    USBDeviceInfo *usb;
+    char driver[32];
+    const char *params;
+    int len;
+
+    params = strchr(cmdline,':');
+    if (params) {
+        params++;
+        len = params - cmdline;
+        if (len > sizeof(driver))
+            len = sizeof(driver);
+        pstrcpy(driver, len, cmdline);
+    } else {
+        params = "";
+        pstrcpy(driver, sizeof(driver), cmdline);
+    }
+
+    for (info = device_info_list; info != NULL; info = info->next) {
+        if (info->bus_info != &usb_bus_info)
+            continue;
+        usb = DO_UPCAST(USBDeviceInfo, qdev, info);
+        if (usb->usbdevice_name == NULL)
+            continue;
+        if (strcmp(usb->usbdevice_name, driver) != 0)
+            continue;
+        break;
+    }
+    if (info == NULL) {
+#if 0
+        /* no error because some drivers are not converted (yet) */
+        error_report("usbdevice %s not found", driver);
+#endif
+        return NULL;
+    }
+
+    if (!usb->usbdevice_init) {
+        if (*params) {
+            error_report("usbdevice %s accepts no params", driver);
+            return NULL;
+        }
+        return usb_create_simple(bus, usb->qdev.name);
+    }
+    return usb->usbdevice_init(params);
+}
diff --git a/qemu-0.15.x/hw/usb-ccid.c b/qemu-0.15.x/hw/usb-ccid.c
new file mode 100644
index 0000000..4dda2c4
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-ccid.c
@@ -0,0 +1,1397 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * CCID Device emulation
+ *
+ * Written by Alon Levy, with contributions from Robert Relyea.
+ *
+ * Based on usb-serial.c, see it's copyright and attributions below.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ * ------- (original copyright & attribution for usb-serial.c below) --------
+ * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2008 Samuel Thibault <samuel.thibault at ens-lyon.org>
+ * Written by Paul Brook, reused for FTDI by Samuel Thibault,
+ */
+
+/*
+ * References:
+ *
+ * CCID Specification Revision 1.1 April 22nd 2005
+ *  "Universal Serial Bus, Device Class: Smart Card"
+ *  Specification for Integrated Circuit(s) Cards Interface Devices
+ *
+ * Endianness note: from the spec (1.3)
+ *  "Fields that are larger than a byte are stored in little endian"
+ *
+ * KNOWN BUGS
+ * 1. remove/insert can sometimes result in removed state instead of inserted.
+ * This is a result of the following:
+ *  symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen
+ *  when a short packet is sent, as seen in uhci-usb.c, resulting from a urb
+ *  from the guest requesting SPD and us returning a smaller packet.
+ *  Not sure which messages trigger this.
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "usb.h"
+#include "monitor.h"
+
+#include "hw/ccid.h"
+
+#define DPRINTF(s, lvl, fmt, ...) \
+do { \
+    if (lvl <= s->debug) { \
+        printf("usb-ccid: " fmt , ## __VA_ARGS__); \
+    } \
+} while (0)
+
+#define D_WARN 1
+#define D_INFO 2
+#define D_MORE_INFO 3
+#define D_VERBOSE 4
+
+#define CCID_DEV_NAME "usb-ccid"
+
+/*
+ * The two options for variable sized buffers:
+ * make them constant size, for large enough constant,
+ * or handle the migration complexity - VMState doesn't handle this case.
+ * sizes are expected never to be exceeded, unless guest misbehaves.
+ */
+#define BULK_OUT_DATA_SIZE 65536
+#define PENDING_ANSWERS_NUM 128
+
+#define BULK_IN_BUF_SIZE 384
+#define BULK_IN_PENDING_NUM 8
+
+#define InterfaceOutClass \
+    ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
+
+#define InterfaceInClass  \
+    ((USB_DIR_IN  | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
+
+#define CCID_MAX_PACKET_SIZE                64
+
+#define CCID_CONTROL_ABORT                  0x1
+#define CCID_CONTROL_GET_CLOCK_FREQUENCIES  0x2
+#define CCID_CONTROL_GET_DATA_RATES         0x3
+
+#define CCID_PRODUCT_DESCRIPTION        "QEMU USB CCID"
+#define CCID_VENDOR_DESCRIPTION         "QEMU " QEMU_VERSION
+#define CCID_INTERFACE_NAME             "CCID Interface"
+#define CCID_SERIAL_NUMBER_STRING       "1"
+/*
+ * Using Gemplus Vendor and Product id
+ * Effect on various drivers:
+ *  usbccid.sys (winxp, others untested) is a class driver so it doesn't care.
+ *  linux has a number of class drivers, but openct filters based on
+ *   vendor/product (/etc/openct.conf under fedora), hence Gemplus.
+ */
+#define CCID_VENDOR_ID                  0x08e6
+#define CCID_PRODUCT_ID                 0x4433
+#define CCID_DEVICE_VERSION             0x0000
+
+/*
+ * BULK_OUT messages from PC to Reader
+ * Defined in CCID Rev 1.1 6.1 (page 26)
+ */
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn              0x62
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff             0x63
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus           0x65
+#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                0x6f
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters           0x6c
+#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters         0x6d
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters           0x61
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                  0x6b
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                0x6e
+#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                  0x6a
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                  0x69
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical              0x71
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                   0x72
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
+
+/*
+ * BULK_IN messages from Reader to PC
+ * Defined in CCID Rev 1.1 6.2 (page 48)
+ */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock               0x80
+#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus              0x81
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters              0x82
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                  0x83
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
+
+/*
+ * INTERRUPT_IN messages from Reader to PC
+ * Defined in CCID Rev 1.1 6.3 (page 56)
+ */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange        0x50
+#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError           0x51
+
+/*
+ * Endpoints for CCID - addresses are up to us to decide.
+ * To support slot insertion and removal we must have an interrupt in ep
+ * in addition we need a bulk in and bulk out ep
+ * 5.2, page 20
+ */
+#define CCID_INT_IN_EP       1
+#define CCID_BULK_IN_EP      2
+#define CCID_BULK_OUT_EP     3
+
+/* bmSlotICCState masks */
+#define SLOT_0_STATE_MASK    1
+#define SLOT_0_CHANGED_MASK  2
+
+/* Status codes that go in bStatus (see 6.2.6) */
+enum {
+    ICC_STATUS_PRESENT_ACTIVE = 0,
+    ICC_STATUS_PRESENT_INACTIVE,
+    ICC_STATUS_NOT_PRESENT
+};
+
+enum {
+    COMMAND_STATUS_NO_ERROR = 0,
+    COMMAND_STATUS_FAILED,
+    COMMAND_STATUS_TIME_EXTENSION_REQUIRED
+};
+
+/* Error codes that go in bError (see 6.2.6) */
+enum {
+    ERROR_CMD_NOT_SUPPORTED = 0,
+    ERROR_CMD_ABORTED       = -1,
+    ERROR_ICC_MUTE          = -2,
+    ERROR_XFR_PARITY_ERROR  = -3,
+    ERROR_XFR_OVERRUN       = -4,
+    ERROR_HW_ERROR          = -5,
+};
+
+/* 6.2.6 RDR_to_PC_SlotStatus definitions */
+enum {
+    CLOCK_STATUS_RUNNING = 0,
+    /*
+     * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
+     * 3 - unknown state. rest are RFU
+     */
+};
+
+typedef struct __attribute__ ((__packed__)) CCID_Header {
+    uint8_t     bMessageType;
+    uint32_t    dwLength;
+    uint8_t     bSlot;
+    uint8_t     bSeq;
+} CCID_Header;
+
+typedef struct __attribute__ ((__packed__)) CCID_BULK_IN {
+    CCID_Header hdr;
+    uint8_t     bStatus;        /* Only used in BULK_IN */
+    uint8_t     bError;         /* Only used in BULK_IN */
+} CCID_BULK_IN;
+
+typedef struct __attribute__ ((__packed__)) CCID_SlotStatus {
+    CCID_BULK_IN b;
+    uint8_t     bClockStatus;
+} CCID_SlotStatus;
+
+typedef struct __attribute__ ((__packed__)) CCID_Parameter {
+    CCID_BULK_IN b;
+    uint8_t     bProtocolNum;
+    uint8_t     abProtocolDataStructure[0];
+} CCID_Parameter;
+
+typedef struct __attribute__ ((__packed__)) CCID_DataBlock {
+    CCID_BULK_IN b;
+    uint8_t      bChainParameter;
+    uint8_t      abData[0];
+} CCID_DataBlock;
+
+/* 6.1.4 PC_to_RDR_XfrBlock */
+typedef struct __attribute__ ((__packed__)) CCID_XferBlock {
+    CCID_Header  hdr;
+    uint8_t      bBWI; /* Block Waiting Timeout */
+    uint16_t     wLevelParameter; /* XXX currently unused */
+    uint8_t      abData[0];
+} CCID_XferBlock;
+
+typedef struct __attribute__ ((__packed__)) CCID_IccPowerOn {
+    CCID_Header hdr;
+    uint8_t     bPowerSelect;
+    uint16_t    abRFU;
+} CCID_IccPowerOn;
+
+typedef struct __attribute__ ((__packed__)) CCID_IccPowerOff {
+    CCID_Header hdr;
+    uint16_t    abRFU;
+} CCID_IccPowerOff;
+
+typedef struct __attribute__ ((__packed__)) CCID_SetParameters {
+    CCID_Header hdr;
+    uint8_t     bProtocolNum;
+    uint16_t   abRFU;
+    uint8_t    abProtocolDataStructure[0];
+} CCID_SetParameters;
+
+typedef struct CCID_Notify_Slot_Change {
+    uint8_t     bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */
+    uint8_t     bmSlotICCState;
+} CCID_Notify_Slot_Change;
+
+/* used for DataBlock response to XferBlock */
+typedef struct Answer {
+    uint8_t slot;
+    uint8_t seq;
+} Answer;
+
+/* pending BULK_IN messages */
+typedef struct BulkIn {
+    uint8_t  data[BULK_IN_BUF_SIZE];
+    uint32_t len;
+    uint32_t pos;
+} BulkIn;
+
+enum {
+    MIGRATION_NONE,
+    MIGRATION_MIGRATED,
+};
+
+typedef struct CCIDBus {
+    BusState qbus;
+} CCIDBus;
+
+#define MAX_PROTOCOL_SIZE   7
+
+/*
+ * powered - defaults to true, changed by PowerOn/PowerOff messages
+ */
+typedef struct USBCCIDState {
+    USBDevice dev;
+    CCIDBus bus;
+    CCIDCardState *card;
+    CCIDCardInfo *cardinfo; /* caching the info pointer */
+    BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
+    uint32_t bulk_in_pending_start;
+    uint32_t bulk_in_pending_end; /* first free */
+    uint32_t bulk_in_pending_num;
+    BulkIn *current_bulk_in;
+    uint8_t  bulk_out_data[BULK_OUT_DATA_SIZE];
+    uint32_t bulk_out_pos;
+    uint64_t last_answer_error;
+    Answer pending_answers[PENDING_ANSWERS_NUM];
+    uint32_t pending_answers_start;
+    uint32_t pending_answers_end;
+    uint32_t pending_answers_num;
+    uint8_t  bError;
+    uint8_t  bmCommandStatus;
+    uint8_t  bProtocolNum;
+    uint8_t  abProtocolDataStructure[MAX_PROTOCOL_SIZE];
+    uint32_t ulProtocolDataStructureSize;
+    uint32_t state_vmstate;
+    uint32_t migration_target_ip;
+    uint16_t migration_target_port;
+    uint8_t  migration_state;
+    uint8_t  bmSlotICCState;
+    uint8_t  powered;
+    uint8_t  notify_slot_change;
+    uint8_t  debug;
+} USBCCIDState;
+
+/*
+ * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
+ * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
+ * Specification.
+ *
+ * This device implemented based on the spec and with an Athena Smart Card
+ * Reader as reference:
+ *   0dc3:1004 Athena Smartcard Solutions, Inc.
+ */
+
+static const uint8_t qemu_ccid_dev_descriptor[] = {
+        0x12,       /*  u8 bLength; */
+        USB_DT_DEVICE, /*  u8 bDescriptorType; Device */
+        0x10, 0x01, /*  u16 bcdUSB; v1.1 */
+
+        0x00,       /*  u8  bDeviceClass; */
+        0x00,       /*  u8  bDeviceSubClass; */
+        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+        0x40,       /*  u8  bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */
+
+        /* Vendor and product id are arbitrary.  */
+                    /*  u16 idVendor  */
+        CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8,
+                    /*  u16 idProduct */
+        CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8,
+                    /*  u16 bcdDevice */
+        CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8,
+        0x01,       /*  u8  iManufacturer; */
+        0x02,       /*  u8  iProduct; */
+        0x03,       /*  u8  iSerialNumber; */
+        0x01,       /*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_ccid_config_descriptor[] = {
+
+        /* one configuration */
+        0x09,       /* u8  bLength; */
+        USB_DT_CONFIG, /* u8  bDescriptorType; Configuration */
+        0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */
+        0x01,       /* u8  bNumInterfaces; (1) */
+        0x01,       /* u8  bConfigurationValue; */
+        0x00,       /* u8  iConfiguration; */
+        0xe0,       /* u8  bmAttributes;
+                                 Bit 7: must be set,
+                                     6: Self-powered,
+                                     5: Remote wakeup,
+                                     4..0: resvd */
+        100/2,      /* u8  MaxPower; 50 == 100mA */
+
+        /* one interface */
+        0x09,       /* u8  if_bLength; */
+        USB_DT_INTERFACE, /* u8  if_bDescriptorType; Interface */
+        0x00,       /* u8  if_bInterfaceNumber; */
+        0x00,       /* u8  if_bAlternateSetting; */
+        0x03,       /* u8  if_bNumEndpoints; */
+        0x0b,       /* u8  if_bInterfaceClass; Smart Card Device Class */
+        0x00,       /* u8  if_bInterfaceSubClass; Subclass code */
+        0x00,       /* u8  if_bInterfaceProtocol; Protocol code */
+        0x04,       /* u8  if_iInterface; Index of string descriptor */
+
+        /* Smart Card Device Class Descriptor */
+        0x36,       /* u8  bLength; */
+        0x21,       /* u8  bDescriptorType; Functional */
+        0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */
+        0x00,       /*
+                     * u8  bMaxSlotIndex; The index of the highest available
+                     * slot on this device. All slots are consecutive starting
+                     * at 00h.
+                     */
+        0x07,       /* u8  bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */
+
+        0x03, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
+        0x00, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */
+                    /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */
+        0xa0, 0x0f, 0x00, 0x00,
+                    /* u32 dwMaximumClock; */
+        0x00, 0x00, 0x01, 0x00,
+        0x00,       /* u8 bNumClockSupported;                 *
+                     *    0 means just the default and max.   */
+                    /* u32 dwDataRate ;bps. 9600 == 00002580h */
+        0x80, 0x25, 0x00, 0x00,
+                    /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */
+        0x00, 0xC2, 0x01, 0x00,
+        0x00,       /* u8  bNumDataRatesSupported; 00 means all rates between
+                     *     default and max */
+                    /* u32 dwMaxIFSD;                                  *
+                     *     maximum IFSD supported by CCID for protocol *
+                     *     T=1 (Maximum seen from various cards)       */
+        0xfe, 0x00, 0x00, 0x00,
+                    /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */
+        0x00, 0x00, 0x00, 0x00,
+                    /* u32 dwMechanical;  0 - no special characteristics. */
+        0x00, 0x00, 0x00, 0x00,
+                    /*
+                     * u32 dwFeatures;
+                     * 0 - No special characteristics
+                     * + 2 Automatic parameter configuration based on ATR data
+                     * + 4 Automatic activation of ICC on inserting
+                     * + 8 Automatic ICC voltage selection
+                     * + 10 Automatic ICC clock frequency change
+                     * + 20 Automatic baud rate change
+                     * + 40 Automatic parameters negotiation made by the CCID
+                     * + 80 automatic PPS made by the CCID
+                     * 100 CCID can set ICC in clock stop mode
+                     * 200 NAD value other then 00 accepted (T=1 protocol)
+                     * + 400 Automatic IFSD exchange as first exchange (T=1)
+                     * One of the following only:
+                     * + 10000 TPDU level exchanges with CCID
+                     * 20000 Short APDU level exchange with CCID
+                     * 40000 Short and Extended APDU level exchange with CCID
+                     *
+                     * + 100000 USB Wake up signaling supported on card
+                     * insertion and removal. Must set bit 5 in bmAttributes
+                     * in Configuration descriptor if 100000 is set.
+                     */
+        0xfe, 0x04, 0x11, 0x00,
+                    /*
+                     * u32 dwMaxCCIDMessageLength; For extended APDU in
+                     * [261 + 10 , 65544 + 10]. Otherwise the minimum is
+                     * wMaxPacketSize of the Bulk-OUT endpoint
+                     */
+        0x12, 0x00, 0x01, 0x00,
+        0xFF,       /*
+                     * u8  bClassGetResponse; Significant only for CCID that
+                     * offers an APDU level for exchanges. Indicates the
+                     * default class value used by the CCID when it sends a
+                     * Get Response command to perform the transportation of
+                     * an APDU by T=0 protocol
+                     * FFh indicates that the CCID echos the class of the APDU.
+                     */
+        0xFF,       /*
+                     * u8  bClassEnvelope; EAPDU only. Envelope command for
+                     * T=0
+                     */
+        0x00, 0x00, /*
+                     * u16 wLcdLayout; XXYY Number of lines (XX) and chars per
+                     * line for LCD display used for PIN entry. 0000 - no LCD
+                     */
+        0x01,       /*
+                     * u8  bPINSupport; 01h PIN Verification,
+                     *                  02h PIN Modification
+                     */
+        0x01,       /* u8  bMaxCCIDBusySlots; */
+
+        /* Interrupt-IN endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x80 | CCID_INT_IN_EP,
+        0x03,       /* u8  ep_bmAttributes; Interrupt */
+                    /* u16 ep_wMaxPacketSize; */
+        CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8),
+        0xff,       /* u8  ep_bInterval; */
+
+        /* Bulk-In endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; IN Endpoint 2 */
+        0x80 | CCID_BULK_IN_EP,
+        0x02,       /* u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+        0x00,       /* u8  ep_bInterval; */
+
+        /* Bulk-Out endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; OUT Endpoint 3 */
+        CCID_BULK_OUT_EP,
+        0x02,       /* u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+        0x00,       /* u8  ep_bInterval; */
+
+};
+
+static bool ccid_has_pending_answers(USBCCIDState *s)
+{
+    return s->pending_answers_num > 0;
+}
+
+static void ccid_clear_pending_answers(USBCCIDState *s)
+{
+    s->pending_answers_num = 0;
+    s->pending_answers_start = 0;
+    s->pending_answers_end = 0;
+}
+
+static void ccid_print_pending_answers(USBCCIDState *s)
+{
+    Answer *answer;
+    int i, count;
+
+    DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:");
+    if (!ccid_has_pending_answers(s)) {
+        DPRINTF(s, D_VERBOSE, " empty\n");
+        return;
+    }
+    for (i = s->pending_answers_start, count = s->pending_answers_num ;
+         count > 0; count--, i++) {
+        answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
+        if (count == 1) {
+            DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq);
+        } else {
+            DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq);
+        }
+    }
+}
+
+static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
+{
+    Answer *answer;
+
+    assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
+    s->pending_answers_num++;
+    answer =
+        &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
+    answer->slot = hdr->bSlot;
+    answer->seq = hdr->bSeq;
+    ccid_print_pending_answers(s);
+}
+
+static void ccid_remove_pending_answer(USBCCIDState *s,
+    uint8_t *slot, uint8_t *seq)
+{
+    Answer *answer;
+
+    assert(s->pending_answers_num > 0);
+    s->pending_answers_num--;
+    answer =
+        &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
+    *slot = answer->slot;
+    *seq = answer->seq;
+    ccid_print_pending_answers(s);
+}
+
+static void ccid_bulk_in_clear(USBCCIDState *s)
+{
+    s->bulk_in_pending_start = 0;
+    s->bulk_in_pending_end = 0;
+    s->bulk_in_pending_num = 0;
+}
+
+static void ccid_bulk_in_release(USBCCIDState *s)
+{
+    assert(s->current_bulk_in != NULL);
+    s->current_bulk_in->pos = 0;
+    s->current_bulk_in = NULL;
+}
+
+static void ccid_bulk_in_get(USBCCIDState *s)
+{
+    if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) {
+        return;
+    }
+    assert(s->bulk_in_pending_num > 0);
+    s->bulk_in_pending_num--;
+    s->current_bulk_in =
+        &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM];
+}
+
+static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
+{
+    BulkIn *bulk_in;
+
+    DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len);
+
+    /* look for an existing element */
+    if (len > BULK_IN_BUF_SIZE) {
+        DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). "
+                           "discarding message.\n",
+                           __func__, len, BULK_IN_BUF_SIZE);
+        return NULL;
+    }
+    if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
+        DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
+                           "discarding message.\n", __func__);
+        return NULL;
+    }
+    bulk_in =
+        &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
+    s->bulk_in_pending_num++;
+    bulk_in->len = len;
+    return bulk_in->data;
+}
+
+static void ccid_reset(USBCCIDState *s)
+{
+    ccid_bulk_in_clear(s);
+    ccid_clear_pending_answers(s);
+}
+
+static void ccid_detach(USBCCIDState *s)
+{
+    ccid_reset(s);
+}
+
+static void ccid_handle_reset(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    DPRINTF(s, 1, "Reset\n");
+
+    ccid_reset(s);
+}
+
+static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
+                               int value, int index, int length, uint8_t *data)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+    int ret = 0;
+
+    DPRINTF(s, 1, "got control %x, value %x\n", request, value);
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
+            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch (value >> 8) {
+        case USB_DT_DEVICE:
+            memcpy(data, qemu_ccid_dev_descriptor,
+                   sizeof(qemu_ccid_dev_descriptor));
+            ret = sizeof(qemu_ccid_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+            memcpy(data, qemu_ccid_config_descriptor,
+                   sizeof(qemu_ccid_config_descriptor));
+            ret = sizeof(qemu_ccid_config_descriptor);
+            break;
+        case USB_DT_STRING:
+            switch (value & 0xff) {
+            case 0:
+                /* language ids */
+                data[0] = 4;
+                data[1] = 3;
+                data[2] = 0x09;
+                data[3] = 0x04;
+                ret = 4;
+                break;
+            case 1:
+                /* vendor description */
+                ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION);
+                break;
+            case 2:
+                /* product description */
+                ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION);
+                break;
+            case 3:
+                /* serial number */
+                ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING);
+                break;
+            case 4:
+                /* interface name */
+                ret = set_usb_string(data, CCID_INTERFACE_NAME);
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = 1;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        /* Only one configuration - we just ignore the request */
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+
+        /* Class specific requests.  */
+    case InterfaceOutClass | CCID_CONTROL_ABORT:
+        DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
+        DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES:
+        DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    default:
+fail:
+        DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
+                request, value);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static bool ccid_card_inserted(USBCCIDState *s)
+{
+    return s->bmSlotICCState & SLOT_0_STATE_MASK;
+}
+
+static uint8_t ccid_card_status(USBCCIDState *s)
+{
+    return ccid_card_inserted(s)
+            ? (s->powered ?
+                ICC_STATUS_PRESENT_ACTIVE
+              : ICC_STATUS_PRESENT_INACTIVE
+              )
+            : ICC_STATUS_NOT_PRESENT;
+}
+
+static uint8_t ccid_calc_status(USBCCIDState *s)
+{
+    /*
+     * page 55, 6.2.6, calculation of bStatus from bmICCStatus and
+     * bmCommandStatus
+     */
+    uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6);
+    DPRINTF(s, D_VERBOSE, "status = %d\n", ret);
+    return ret;
+}
+
+static void ccid_reset_error_status(USBCCIDState *s)
+{
+    s->bError = ERROR_CMD_NOT_SUPPORTED;
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+}
+
+static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus));
+    if (h == NULL) {
+        return;
+    }
+    h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus;
+    h->b.hdr.dwLength = 0;
+    h->b.hdr.bSlot = recv->bSlot;
+    h->b.hdr.bSeq = recv->bSeq;
+    h->b.bStatus = ccid_calc_status(s);
+    h->b.bError = s->bError;
+    h->bClockStatus = CLOCK_STATUS_RUNNING;
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_Parameter *h;
+    uint32_t len = s->ulProtocolDataStructureSize;
+
+    h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len);
+    if (h == NULL) {
+        return;
+    }
+    h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
+    h->b.hdr.dwLength = 0;
+    h->b.hdr.bSlot = recv->bSlot;
+    h->b.hdr.bSeq = recv->bSeq;
+    h->b.bStatus = ccid_calc_status(s);
+    h->b.bError = s->bError;
+    h->bProtocolNum = s->bProtocolNum;
+    memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len);
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq,
+                                  const uint8_t *data, uint32_t len)
+{
+    CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len);
+
+    if (p == NULL) {
+        return;
+    }
+    p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock;
+    p->b.hdr.dwLength = cpu_to_le32(len);
+    p->b.hdr.bSlot = slot;
+    p->b.hdr.bSeq = seq;
+    p->b.bStatus = ccid_calc_status(s);
+    p->b.bError = s->bError;
+    if (p->b.bError) {
+        DPRINTF(s, D_VERBOSE, "error %d", p->b.bError);
+    }
+    memcpy(p->abData, data, len);
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_data_block_answer(USBCCIDState *s,
+    const uint8_t *data, uint32_t len)
+{
+    uint8_t seq;
+    uint8_t slot;
+
+    if (!ccid_has_pending_answers(s)) {
+        abort();
+    }
+    ccid_remove_pending_answer(s, &slot, &seq);
+    ccid_write_data_block(s, slot, seq, data, len);
+}
+
+static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
+{
+    const uint8_t *atr = NULL;
+    uint32_t len = 0;
+
+    if (s->card) {
+        atr = s->cardinfo->get_atr(s->card, &len);
+    }
+    ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
+}
+
+static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_SetParameters *ph = (CCID_SetParameters *) recv;
+    uint32_t len = 0;
+    if ((ph->bProtocolNum & 3) == 0) {
+        len = 5;
+    }
+    if ((ph->bProtocolNum & 3) == 1) {
+        len = 7;
+    }
+    if (len == 0) {
+        s->bmCommandStatus = COMMAND_STATUS_FAILED;
+        s->bError = 7; /* Protocol invalid or not supported */
+        return;
+    }
+    s->bProtocolNum = ph->bProtocolNum;
+    memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len);
+    s->ulProtocolDataStructureSize = len;
+    DPRINTF(s, 1, "%s: using len %d\n", __func__, len);
+}
+
+/*
+ * must be 5 bytes for T=0, 7 bytes for T=1
+ * See page 52
+ */
+static const uint8_t abDefaultProtocolDataStructure[7] = {
+    0x77, 0x00, 0x00, 0x00, 0x00, 0xfe /*IFSC*/, 0x00 /*NAD*/ };
+
+static void ccid_reset_parameters(USBCCIDState *s)
+{
+   uint32_t len = sizeof(abDefaultProtocolDataStructure);
+
+   s->bProtocolNum = 1; /* T=1 */
+   s->ulProtocolDataStructureSize = len;
+   memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len);
+}
+
+static void ccid_report_error_failed(USBCCIDState *s, uint8_t error)
+{
+    s->bmCommandStatus = COMMAND_STATUS_FAILED;
+    s->bError = error;
+}
+
+/* NOTE: only a single slot is supported (SLOT_0) */
+static void ccid_on_slot_change(USBCCIDState *s, bool full)
+{
+    /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */
+    uint8_t current = s->bmSlotICCState;
+    if (full) {
+        s->bmSlotICCState |= SLOT_0_STATE_MASK;
+    } else {
+        s->bmSlotICCState &= ~SLOT_0_STATE_MASK;
+    }
+    if (current != s->bmSlotICCState) {
+        s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
+    }
+    s->notify_slot_change = true;
+}
+
+static void ccid_write_data_block_error(
+    USBCCIDState *s, uint8_t slot, uint8_t seq)
+{
+    ccid_write_data_block(s, slot, seq, NULL, 0);
+}
+
+static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
+{
+    uint32_t len;
+
+    if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) {
+        DPRINTF(s, 1,
+                "usb-ccid: not sending apdu to client, no card connected\n");
+        ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
+        return;
+    }
+    len = le32_to_cpu(recv->hdr.dwLength);
+    DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__,
+                recv->hdr.bSeq, len);
+    ccid_add_pending_answer(s, (CCID_Header *)recv);
+    if (s->card) {
+        s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+    } else {
+        DPRINTF(s, D_WARN, "warning: discarded apdu\n");
+    }
+}
+
+/*
+ * Handle a single USB_TOKEN_OUT, return value returned to guest.
+ * Return value:
+ *  0             - all ok
+ *  USB_RET_STALL - failed to handle packet
+ */
+static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
+{
+    CCID_Header *ccid_header;
+
+    if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+        return USB_RET_STALL;
+    }
+    ccid_header = (CCID_Header *)s->bulk_out_data;
+    memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len);
+    s->bulk_out_pos += p->len;
+    if (p->len == CCID_MAX_PACKET_SIZE) {
+        DPRINTF(s, D_VERBOSE,
+            "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
+            p->len, ccid_header->dwLength);
+        return 0;
+    }
+    if (s->bulk_out_pos < 10) {
+        DPRINTF(s, 1,
+                "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
+                __func__);
+    } else {
+        DPRINTF(s, D_MORE_INFO, "%s %x\n", __func__, ccid_header->bMessageType);
+        switch (ccid_header->bMessageType) {
+        case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
+            DPRINTF(s, 1, "PowerOn: %d\n",
+                ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
+            s->powered = true;
+            if (!ccid_card_inserted(s)) {
+                ccid_report_error_failed(s, ERROR_ICC_MUTE);
+            }
+            /* atr is written regardless of error. */
+            ccid_write_data_block_atr(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
+            DPRINTF(s, 1, "PowerOff\n");
+            ccid_reset_error_status(s);
+            s->powered = false;
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
+            ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
+            ccid_reset_error_status(s);
+            ccid_set_parameters(s, ccid_header);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
+            ccid_reset_error_status(s);
+            ccid_reset_parameters(s);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
+            ccid_reset_error_status(s);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        default:
+            DPRINTF(s, 1,
+                "handle_data: ERROR: unhandled message type %Xh\n",
+                ccid_header->bMessageType);
+            /*
+             * The caller is expecting the device to respond, tell it we
+             * don't support the operation.
+             */
+            ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        }
+    }
+    s->bulk_out_pos = 0;
+    return 0;
+}
+
+static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
+{
+    int ret = 0;
+
+    assert(len > 0);
+    ccid_bulk_in_get(s);
+    if (s->current_bulk_in != NULL) {
+        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len);
+        memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret);
+        s->current_bulk_in->pos += ret;
+        if (s->current_bulk_in->pos == s->current_bulk_in->len) {
+            ccid_bulk_in_release(s);
+        }
+    } else {
+        /* return when device has no data - usb 2.0 spec Table 8-4 */
+        ret = USB_RET_NAK;
+    }
+    if (ret > 0) {
+        DPRINTF(s, D_MORE_INFO,
+                "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret);
+    }
+    if (ret != USB_RET_NAK && ret < len) {
+        DPRINTF(s, 1,
+            "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len);
+    }
+    return ret;
+}
+
+static int ccid_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+    int ret = 0;
+    uint8_t *data = p->data;
+    int len = p->len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        ret = ccid_handle_bulk_out(s, p);
+        break;
+
+    case USB_TOKEN_IN:
+        switch (p->devep & 0xf) {
+        case CCID_BULK_IN_EP:
+            if (!len) {
+                ret = USB_RET_NAK;
+            } else {
+                ret = ccid_bulk_in_copy_to_guest(s, data, len);
+            }
+            break;
+        case CCID_INT_IN_EP:
+            if (s->notify_slot_change) {
+                /* page 56, RDR_to_PC_NotifySlotChange */
+                data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+                data[1] = s->bmSlotICCState;
+                ret = 2;
+                s->notify_slot_change = false;
+                s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
+                DPRINTF(s, D_INFO,
+                        "handle_data: int_in: notify_slot_change %X, "
+                        "requested len %d\n",
+                        s->bmSlotICCState, len);
+            }
+            break;
+        default:
+            DPRINTF(s, 1, "Bad endpoint\n");
+            break;
+        }
+        break;
+    default:
+        DPRINTF(s, 1, "Bad token\n");
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void ccid_handle_destroy(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    ccid_bulk_in_clear(s);
+}
+
+static void ccid_flush_pending_answers(USBCCIDState *s)
+{
+    while (ccid_has_pending_answers(s)) {
+        ccid_write_data_block_answer(s, NULL, 0);
+    }
+}
+
+static Answer *ccid_peek_next_answer(USBCCIDState *s)
+{
+    return s->pending_answers_num == 0
+        ? NULL
+        : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
+}
+
+static struct BusInfo ccid_bus_info = {
+    .name = "ccid-bus",
+    .size = sizeof(CCIDBus),
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+void ccid_card_send_apdu_to_guest(CCIDCardState *card,
+                                  uint8_t *apdu, uint32_t len)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev,
+                                card->qdev.parent_bus->parent);
+    Answer *answer;
+
+    if (!ccid_has_pending_answers(s)) {
+        DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n");
+        return;
+    }
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+    answer = ccid_peek_next_answer(s);
+    if (answer == NULL) {
+        abort();
+    }
+    DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n",
+        len, answer->seq, answer->slot);
+    ccid_write_data_block_answer(s, apdu, len);
+}
+
+void ccid_card_card_removed(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    ccid_on_slot_change(s, false);
+    ccid_flush_pending_answers(s);
+    ccid_reset(s);
+}
+
+int ccid_card_ccid_attach(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    DPRINTF(s, 1, "CCID Attach\n");
+    if (s->migration_state == MIGRATION_MIGRATED) {
+        s->migration_state = MIGRATION_NONE;
+    }
+    return 0;
+}
+
+void ccid_card_ccid_detach(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    DPRINTF(s, 1, "CCID Detach\n");
+    if (ccid_card_inserted(s)) {
+        ccid_on_slot_change(s, false);
+    }
+    ccid_detach(s);
+}
+
+void ccid_card_card_error(CCIDCardState *card, uint64_t error)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    s->bmCommandStatus = COMMAND_STATUS_FAILED;
+    s->last_answer_error = error;
+    DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error);
+    /* TODO: these errors should be more verbose and propagated to the guest.*/
+    /*
+     * We flush all pending answers on CardRemove message in ccid-card-passthru,
+     * so check that first to not trigger abort
+     */
+    if (ccid_has_pending_answers(s)) {
+        ccid_write_data_block_answer(s, NULL, 0);
+    }
+}
+
+void ccid_card_card_inserted(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+    ccid_flush_pending_answers(s);
+    ccid_on_slot_change(s, true);
+}
+
+static int ccid_card_exit(DeviceState *qdev)
+{
+    int ret = 0;
+    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    if (ccid_card_inserted(s)) {
+        ccid_card_card_removed(card);
+    }
+    if (info->exitfn) {
+        ret = info->exitfn(card);
+    }
+    s->card = NULL;
+    s->cardinfo = NULL;
+    return ret;
+}
+
+static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+{
+    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+    int ret = 0;
+
+    if (card->slot != 0) {
+        error_report("Warning: usb-ccid supports one slot, can't add %d",
+                card->slot);
+        return -1;
+    }
+    if (s->card != NULL) {
+        error_report("Warning: usb-ccid card already full, not adding");
+        return -1;
+    }
+    ret = info->initfn ? info->initfn(card) : ret;
+    if (ret == 0) {
+        s->card = card;
+        s->cardinfo = info;
+    }
+    return ret;
+}
+
+void ccid_card_qdev_register(CCIDCardInfo *card)
+{
+    card->qdev.bus_info = &ccid_bus_info;
+    card->qdev.init = ccid_card_init;
+    card->qdev.exit = ccid_card_exit;
+    qdev_register(&card->qdev);
+}
+
+static int ccid_initfn(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+    s->bus.qbus.allow_hotplug = 1;
+    s->card = NULL;
+    s->cardinfo = NULL;
+    s->migration_state = MIGRATION_NONE;
+    s->migration_target_ip = 0;
+    s->migration_target_port = 0;
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.speedmask = USB_SPEED_MASK_FULL;
+    s->notify_slot_change = false;
+    s->powered = true;
+    s->pending_answers_num = 0;
+    s->last_answer_error = 0;
+    s->bulk_in_pending_start = 0;
+    s->bulk_in_pending_end = 0;
+    s->current_bulk_in = NULL;
+    ccid_reset_error_status(s);
+    s->bulk_out_pos = 0;
+    ccid_reset_parameters(s);
+    ccid_reset(s);
+    return 0;
+}
+
+static int ccid_post_load(void *opaque, int version_id)
+{
+    USBCCIDState *s = opaque;
+
+    /*
+     * This must be done after usb_device_attach, which sets state to ATTACHED,
+     * while it must be DEFAULT in order to accept packets (like it is after
+     * reset, but reset will reset our addr and call our reset handler which
+     * may change state, and we don't want to do that when migrating).
+     */
+    s->dev.state = s->state_vmstate;
+    return 0;
+}
+
+static void ccid_pre_save(void *opaque)
+{
+    USBCCIDState *s = opaque;
+
+    s->state_vmstate = s->dev.state;
+    if (s->dev.attached) {
+        /*
+         * Migrating an open device, ignore reconnection CHR_EVENT to avoid an
+         * erroneous detach.
+         */
+        s->migration_state = MIGRATION_MIGRATED;
+    }
+}
+
+static VMStateDescription bulk_in_vmstate = {
+    .name = "CCID BulkIn state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(data, BulkIn),
+        VMSTATE_UINT32(len, BulkIn),
+        VMSTATE_UINT32(pos, BulkIn),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription answer_vmstate = {
+    .name = "CCID Answer state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(slot, Answer),
+        VMSTATE_UINT8(seq, Answer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription usb_device_vmstate = {
+    .name = "usb_device",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(addr, USBDevice),
+        VMSTATE_BUFFER(setup_buf, USBDevice),
+        VMSTATE_BUFFER(data_buf, USBDevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription ccid_vmstate = {
+    .name = CCID_DEV_NAME,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = ccid_post_load,
+    .pre_save = ccid_pre_save,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice),
+        VMSTATE_UINT8(debug, USBCCIDState),
+        VMSTATE_BUFFER(bulk_out_data, USBCCIDState),
+        VMSTATE_UINT32(bulk_out_pos, USBCCIDState),
+        VMSTATE_UINT8(bmSlotICCState, USBCCIDState),
+        VMSTATE_UINT8(powered, USBCCIDState),
+        VMSTATE_UINT8(notify_slot_change, USBCCIDState),
+        VMSTATE_UINT64(last_answer_error, USBCCIDState),
+        VMSTATE_UINT8(bError, USBCCIDState),
+        VMSTATE_UINT8(bmCommandStatus, USBCCIDState),
+        VMSTATE_UINT8(bProtocolNum, USBCCIDState),
+        VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState),
+        VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState),
+        VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState,
+                       BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn),
+        VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState),
+        VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
+        VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
+                        PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
+        VMSTATE_UINT32(pending_answers_num, USBCCIDState),
+        VMSTATE_UINT8(migration_state, USBCCIDState),
+        VMSTATE_UINT32(state_vmstate, USBCCIDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static struct USBDeviceInfo ccid_info = {
+    .product_desc   = "QEMU USB CCID",
+    .qdev.name      = CCID_DEV_NAME,
+    .qdev.desc      = "CCID Rev 1.1 smartcard reader",
+    .qdev.size      = sizeof(USBCCIDState),
+    .init           = ccid_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = ccid_handle_reset,
+    .handle_control = ccid_handle_control,
+    .handle_data    = ccid_handle_data,
+    .handle_destroy = ccid_handle_destroy,
+    .usbdevice_name = "ccid",
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .qdev.vmsd      = &ccid_vmstate,
+};
+
+static void ccid_register_devices(void)
+{
+    usb_qdev_register(&ccid_info);
+}
+device_init(ccid_register_devices)
diff --git a/qemu-0.15.x/hw/usb-desc.c b/qemu-0.15.x/hw/usb-desc.c
new file mode 100644
index 0000000..bc6858f
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-desc.c
@@ -0,0 +1,466 @@
+#include "usb.h"
+#include "usb-desc.h"
+#include "trace.h"
+
+/* ------------------------------------------------------------------ */
+
+static uint8_t usb_lo(uint16_t val)
+{
+    return val & 0xff;
+}
+
+static uint8_t usb_hi(uint16_t val)
+{
+    return (val >> 8) & 0xff;
+}
+
+int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
+                    uint8_t *dest, size_t len)
+{
+    uint8_t bLength = 0x12;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_DEVICE;
+
+    dest[0x02] = usb_lo(dev->bcdUSB);
+    dest[0x03] = usb_hi(dev->bcdUSB);
+    dest[0x04] = dev->bDeviceClass;
+    dest[0x05] = dev->bDeviceSubClass;
+    dest[0x06] = dev->bDeviceProtocol;
+    dest[0x07] = dev->bMaxPacketSize0;
+
+    dest[0x08] = usb_lo(id->idVendor);
+    dest[0x09] = usb_hi(id->idVendor);
+    dest[0x0a] = usb_lo(id->idProduct);
+    dest[0x0b] = usb_hi(id->idProduct);
+    dest[0x0c] = usb_lo(id->bcdDevice);
+    dest[0x0d] = usb_hi(id->bcdDevice);
+    dest[0x0e] = id->iManufacturer;
+    dest[0x0f] = id->iProduct;
+    dest[0x10] = id->iSerialNumber;
+
+    dest[0x11] = dev->bNumConfigurations;
+
+    return bLength;
+}
+
+int usb_desc_device_qualifier(const USBDescDevice *dev,
+                              uint8_t *dest, size_t len)
+{
+    uint8_t bLength = 0x0a;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_DEVICE_QUALIFIER;
+
+    dest[0x02] = usb_lo(dev->bcdUSB);
+    dest[0x03] = usb_hi(dev->bcdUSB);
+    dest[0x04] = dev->bDeviceClass;
+    dest[0x05] = dev->bDeviceSubClass;
+    dest[0x06] = dev->bDeviceProtocol;
+    dest[0x07] = dev->bMaxPacketSize0;
+    dest[0x08] = dev->bNumConfigurations;
+    dest[0x09] = 0; /* reserved */
+
+    return bLength;
+}
+
+int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
+{
+    uint8_t  bLength = 0x09;
+    uint16_t wTotalLength = 0;
+    int i, rc;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_CONFIG;
+    dest[0x04] = conf->bNumInterfaces;
+    dest[0x05] = conf->bConfigurationValue;
+    dest[0x06] = conf->iConfiguration;
+    dest[0x07] = conf->bmAttributes;
+    dest[0x08] = conf->bMaxPower;
+    wTotalLength += bLength;
+
+    /* handle grouped interfaces if any*/
+    for (i = 0; i < conf->nif_groups; i++) {
+        rc = usb_desc_iface_group(&(conf->if_groups[i]),
+                                  dest + wTotalLength,
+                                  len - wTotalLength);
+        if (rc < 0) {
+            return rc;
+        }
+        wTotalLength += rc;
+    }
+
+    /* handle normal (ungrouped / no IAD) interfaces if any */
+    for (i = 0; i < conf->nif; i++) {
+        rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
+        if (rc < 0) {
+            return rc;
+        }
+        wTotalLength += rc;
+    }
+
+    dest[0x02] = usb_lo(wTotalLength);
+    dest[0x03] = usb_hi(wTotalLength);
+    return wTotalLength;
+}
+
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
+                         size_t len)
+{
+    int pos = 0;
+    int i = 0;
+
+    /* handle interface association descriptor */
+    uint8_t bLength = 0x08;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_INTERFACE_ASSOC;
+    dest[0x02] = iad->bFirstInterface;
+    dest[0x03] = iad->bInterfaceCount;
+    dest[0x04] = iad->bFunctionClass;
+    dest[0x05] = iad->bFunctionSubClass;
+    dest[0x06] = iad->bFunctionProtocol;
+    dest[0x07] = iad->iFunction;
+    pos += bLength;
+
+    /* handle associated interfaces in this group */
+    for (i = 0; i < iad->nif; i++) {
+        int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
+        if (rc < 0) {
+            return rc;
+        }
+        pos += rc;
+    }
+
+    return pos;
+}
+
+int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
+{
+    uint8_t bLength = 0x09;
+    int i, rc, pos = 0;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_INTERFACE;
+    dest[0x02] = iface->bInterfaceNumber;
+    dest[0x03] = iface->bAlternateSetting;
+    dest[0x04] = iface->bNumEndpoints;
+    dest[0x05] = iface->bInterfaceClass;
+    dest[0x06] = iface->bInterfaceSubClass;
+    dest[0x07] = iface->bInterfaceProtocol;
+    dest[0x08] = iface->iInterface;
+    pos += bLength;
+
+    for (i = 0; i < iface->ndesc; i++) {
+        rc = usb_desc_other(iface->descs + i, dest + pos, len - pos);
+        if (rc < 0) {
+            return rc;
+        }
+        pos += rc;
+    }
+
+    for (i = 0; i < iface->bNumEndpoints; i++) {
+        rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos);
+        if (rc < 0) {
+            return rc;
+        }
+        pos += rc;
+    }
+
+    return pos;
+}
+
+int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
+{
+    uint8_t bLength = 0x07;
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    dest[0x00] = bLength;
+    dest[0x01] = USB_DT_ENDPOINT;
+    dest[0x02] = ep->bEndpointAddress;
+    dest[0x03] = ep->bmAttributes;
+    dest[0x04] = usb_lo(ep->wMaxPacketSize);
+    dest[0x05] = usb_hi(ep->wMaxPacketSize);
+    dest[0x06] = ep->bInterval;
+
+    return bLength;
+}
+
+int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
+{
+    int bLength = desc->length ? desc->length : desc->data[0];
+
+    if (len < bLength) {
+        return -1;
+    }
+
+    memcpy(dest, desc->data, bLength);
+    return bLength;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void usb_desc_setdefaults(USBDevice *dev)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+
+    assert(desc != NULL);
+    switch (dev->speed) {
+    case USB_SPEED_LOW:
+    case USB_SPEED_FULL:
+        dev->device = desc->full;
+        break;
+    case USB_SPEED_HIGH:
+        dev->device = desc->high;
+        break;
+    }
+    dev->config = dev->device->confs;
+}
+
+void usb_desc_init(USBDevice *dev)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+
+    assert(desc != NULL);
+    dev->speed = USB_SPEED_FULL;
+    dev->speedmask = 0;
+    if (desc->full) {
+        dev->speedmask |= USB_SPEED_MASK_FULL;
+    }
+    if (desc->high) {
+        dev->speedmask |= USB_SPEED_MASK_HIGH;
+    }
+    usb_desc_setdefaults(dev);
+}
+
+void usb_desc_attach(USBDevice *dev)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+
+    assert(desc != NULL);
+    if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
+        dev->speed = USB_SPEED_HIGH;
+    } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
+        dev->speed = USB_SPEED_FULL;
+    } else {
+        fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
+                dev->info->product_desc);
+        return;
+    }
+    usb_desc_setdefaults(dev);
+}
+
+void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
+{
+    USBDescString *s;
+
+    QLIST_FOREACH(s, &dev->strings, next) {
+        if (s->index == index) {
+            break;
+        }
+    }
+    if (s == NULL) {
+        s = qemu_mallocz(sizeof(*s));
+        s->index = index;
+        QLIST_INSERT_HEAD(&dev->strings, s, next);
+    }
+    qemu_free(s->str);
+    s->str = qemu_strdup(str);
+}
+
+const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
+{
+    USBDescString *s;
+
+    QLIST_FOREACH(s, &dev->strings, next) {
+        if (s->index == index) {
+            return s->str;
+        }
+    }
+    return NULL;
+}
+
+int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
+{
+    uint8_t bLength, pos, i;
+    const char *str;
+
+    if (len < 4) {
+        return -1;
+    }
+
+    if (index == 0) {
+        /* language ids */
+        dest[0] = 4;
+        dest[1] = USB_DT_STRING;
+        dest[2] = 0x09;
+        dest[3] = 0x04;
+        return 4;
+    }
+
+    str = usb_desc_get_string(dev, index);
+    if (str == NULL) {
+        str = dev->info->usb_desc->str[index];
+        if (str == NULL) {
+            return 0;
+        }
+    }
+
+    bLength = strlen(str) * 2 + 2;
+    dest[0] = bLength;
+    dest[1] = USB_DT_STRING;
+    i = 0; pos = 2;
+    while (pos+1 < bLength && pos+1 < len) {
+        dest[pos++] = str[i++];
+        dest[pos++] = 0;
+    }
+    return pos;
+}
+
+int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+    const USBDescDevice *other_dev;
+    uint8_t buf[256];
+    uint8_t type = value >> 8;
+    uint8_t index = value & 0xff;
+    int ret = -1;
+
+    if (dev->speed == USB_SPEED_HIGH) {
+        other_dev = dev->info->usb_desc->full;
+    } else {
+        other_dev = dev->info->usb_desc->high;
+    }
+
+    switch(type) {
+    case USB_DT_DEVICE:
+        ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
+        trace_usb_desc_device(dev->addr, len, ret);
+        break;
+    case USB_DT_CONFIG:
+        if (index < dev->device->bNumConfigurations) {
+            ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
+        }
+        trace_usb_desc_config(dev->addr, index, len, ret);
+        break;
+    case USB_DT_STRING:
+        ret = usb_desc_string(dev, index, buf, sizeof(buf));
+        trace_usb_desc_string(dev->addr, index, len, ret);
+        break;
+
+    case USB_DT_DEVICE_QUALIFIER:
+        if (other_dev != NULL) {
+            ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
+        }
+        trace_usb_desc_device_qualifier(dev->addr, len, ret);
+        break;
+    case USB_DT_OTHER_SPEED_CONFIG:
+        if (other_dev != NULL && index < other_dev->bNumConfigurations) {
+            ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf));
+            buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
+        }
+        trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
+        break;
+
+    case USB_DT_DEBUG:
+        /* ignore silently */
+        break;
+
+    default:
+        fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
+                dev->addr, type, len);
+        break;
+    }
+
+    if (ret > 0) {
+        if (ret > len) {
+            ret = len;
+        }
+        memcpy(dest, buf, ret);
+    }
+    return ret;
+}
+
+int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+    int i, ret = -1;
+
+    assert(desc != NULL);
+    switch(request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        trace_usb_set_addr(dev->addr);
+        ret = 0;
+        break;
+
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        ret = usb_desc_get_descriptor(dev, value, data, length);
+        break;
+
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = dev->config->bConfigurationValue;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        for (i = 0; i < dev->device->bNumConfigurations; i++) {
+            if (dev->device->confs[i].bConfigurationValue == value) {
+                dev->config = dev->device->confs + i;
+                ret = 0;
+            }
+        }
+        trace_usb_set_config(dev->addr, value, ret);
+        break;
+
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = 0;
+        if (dev->config->bmAttributes & 0x40) {
+            data[0] |= 1 << USB_DEVICE_SELF_POWERED;
+        }
+        if (dev->remote_wakeup) {
+            data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+        }
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+            ret = 0;
+        }
+        trace_usb_clear_device_feature(dev->addr, value, ret);
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+            ret = 0;
+        }
+        trace_usb_set_device_feature(dev->addr, value, ret);
+        break;
+    }
+    return ret;
+}
diff --git a/qemu-0.15.x/hw/usb-desc.h b/qemu-0.15.x/hw/usb-desc.h
new file mode 100644
index 0000000..9d7ed59
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-desc.h
@@ -0,0 +1,112 @@
+#ifndef QEMU_HW_USB_DESC_H
+#define QEMU_HW_USB_DESC_H
+
+#include <inttypes.h>
+
+struct USBDescID {
+    uint16_t                  idVendor;
+    uint16_t                  idProduct;
+    uint16_t                  bcdDevice;
+    uint8_t                   iManufacturer;
+    uint8_t                   iProduct;
+    uint8_t                   iSerialNumber;
+};
+
+struct USBDescDevice {
+    uint16_t                  bcdUSB;
+    uint8_t                   bDeviceClass;
+    uint8_t                   bDeviceSubClass;
+    uint8_t                   bDeviceProtocol;
+    uint8_t                   bMaxPacketSize0;
+    uint8_t                   bNumConfigurations;
+
+    const USBDescConfig       *confs;
+};
+
+struct USBDescConfig {
+    uint8_t                   bNumInterfaces;
+    uint8_t                   bConfigurationValue;
+    uint8_t                   iConfiguration;
+    uint8_t                   bmAttributes;
+    uint8_t                   bMaxPower;
+
+    /* grouped interfaces */
+    uint8_t                   nif_groups;
+    const USBDescIfaceAssoc   *if_groups;
+
+    /* "normal" interfaces */
+    uint8_t                   nif;
+    const USBDescIface        *ifs;
+};
+
+/* conceptually an Interface Association Descriptor, and releated interfaces */
+struct USBDescIfaceAssoc {
+    uint8_t                   bFirstInterface;
+    uint8_t                   bInterfaceCount;
+    uint8_t                   bFunctionClass;
+    uint8_t                   bFunctionSubClass;
+    uint8_t                   bFunctionProtocol;
+    uint8_t                   iFunction;
+
+    uint8_t                   nif;
+    const USBDescIface        *ifs;
+};
+
+struct USBDescIface {
+    uint8_t                   bInterfaceNumber;
+    uint8_t                   bAlternateSetting;
+    uint8_t                   bNumEndpoints;
+    uint8_t                   bInterfaceClass;
+    uint8_t                   bInterfaceSubClass;
+    uint8_t                   bInterfaceProtocol;
+    uint8_t                   iInterface;
+
+    uint8_t                   ndesc;
+    USBDescOther              *descs;
+    USBDescEndpoint           *eps;
+};
+
+struct USBDescEndpoint {
+    uint8_t                   bEndpointAddress;
+    uint8_t                   bmAttributes;
+    uint16_t                  wMaxPacketSize;
+    uint8_t                   bInterval;
+};
+
+struct USBDescOther {
+    uint8_t                   length;
+    uint8_t                   *data;
+};
+
+typedef const char *USBDescStrings[256];
+
+struct USBDesc {
+    USBDescID                 id;
+    const USBDescDevice       *full;
+    const USBDescDevice       *high;
+    const char* const         *str;
+};
+
+/* generate usb packages from structs */
+int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
+                    uint8_t *dest, size_t len);
+int usb_desc_device_qualifier(const USBDescDevice *dev,
+                              uint8_t *dest, size_t len);
+int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
+                         size_t len);
+int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
+int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
+int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
+
+/* control message emulation helpers */
+void usb_desc_init(USBDevice *dev);
+void usb_desc_attach(USBDevice *dev);
+void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
+const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
+int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
+int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
+int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data);
+
+#endif /* QEMU_HW_USB_DESC_H */
diff --git a/qemu-0.15.x/hw/usb-ehci.c b/qemu-0.15.x/hw/usb-ehci.c
new file mode 100644
index 0000000..a4758f9
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-ehci.c
@@ -0,0 +1,2359 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * Copyright(c) 2008  Emutex Ltd. (address at hidden)
+ *
+ * EHCI project was started by Mark Burkley, with contributions by
+ * Niels de Vos.  David S. Ahern continued working on it.  Kevin Wolf,
+ * Jan Kiszka and Vincent Palatin contributed bugfixes.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "monitor.h"
+#include "trace.h"
+
+#define EHCI_DEBUG   0
+
+#if EHCI_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+/* internal processing - reset HC to try and recover */
+#define USB_RET_PROCERR   (-99)
+
+#define MMIO_SIZE        0x1000
+
+/* Capability Registers Base Address - section 2.2 */
+#define CAPREGBASE       0x0000
+#define CAPLENGTH        CAPREGBASE + 0x0000  // 1-byte, 0x0001 reserved
+#define HCIVERSION       CAPREGBASE + 0x0002  // 2-bytes, i/f version #
+#define HCSPARAMS        CAPREGBASE + 0x0004  // 4-bytes, structural params
+#define HCCPARAMS        CAPREGBASE + 0x0008  // 4-bytes, capability params
+#define EECP             HCCPARAMS + 1
+#define HCSPPORTROUTE1   CAPREGBASE + 0x000c
+#define HCSPPORTROUTE2   CAPREGBASE + 0x0010
+
+#define OPREGBASE        0x0020        // Operational Registers Base Address
+
+#define USBCMD           OPREGBASE + 0x0000
+#define USBCMD_RUNSTOP   (1 << 0)      // run / Stop
+#define USBCMD_HCRESET   (1 << 1)      // HC Reset
+#define USBCMD_FLS       (3 << 2)      // Frame List Size
+#define USBCMD_FLS_SH    2             // Frame List Size Shift
+#define USBCMD_PSE       (1 << 4)      // Periodic Schedule Enable
+#define USBCMD_ASE       (1 << 5)      // Asynch Schedule Enable
+#define USBCMD_IAAD      (1 << 6)      // Int Asynch Advance Doorbell
+#define USBCMD_LHCR      (1 << 7)      // Light Host Controller Reset
+#define USBCMD_ASPMC     (3 << 8)      // Async Sched Park Mode Count
+#define USBCMD_ASPME     (1 << 11)     // Async Sched Park Mode Enable
+#define USBCMD_ITC       (0x7f << 16)  // Int Threshold Control
+#define USBCMD_ITC_SH    16            // Int Threshold Control Shift
+
+#define USBSTS           OPREGBASE + 0x0004
+#define USBSTS_RO_MASK   0x0000003f
+#define USBSTS_INT       (1 << 0)      // USB Interrupt
+#define USBSTS_ERRINT    (1 << 1)      // Error Interrupt
+#define USBSTS_PCD       (1 << 2)      // Port Change Detect
+#define USBSTS_FLR       (1 << 3)      // Frame List Rollover
+#define USBSTS_HSE       (1 << 4)      // Host System Error
+#define USBSTS_IAA       (1 << 5)      // Interrupt on Async Advance
+#define USBSTS_HALT      (1 << 12)     // HC Halted
+#define USBSTS_REC       (1 << 13)     // Reclamation
+#define USBSTS_PSS       (1 << 14)     // Periodic Schedule Status
+#define USBSTS_ASS       (1 << 15)     // Asynchronous Schedule Status
+
+/*
+ *  Interrupt enable bits correspond to the interrupt active bits in USBSTS
+ *  so no need to redefine here.
+ */
+#define USBINTR              OPREGBASE + 0x0008
+#define USBINTR_MASK         0x0000003f
+
+#define FRINDEX              OPREGBASE + 0x000c
+#define CTRLDSSEGMENT        OPREGBASE + 0x0010
+#define PERIODICLISTBASE     OPREGBASE + 0x0014
+#define ASYNCLISTADDR        OPREGBASE + 0x0018
+#define ASYNCLISTADDR_MASK   0xffffffe0
+
+#define CONFIGFLAG           OPREGBASE + 0x0040
+
+#define PORTSC               (OPREGBASE + 0x0044)
+#define PORTSC_BEGIN         PORTSC
+#define PORTSC_END           (PORTSC + 4 * NB_PORTS)
+/*
+ * Bits that are reserved or are read-only are masked out of values
+ * written to us by software
+ */
+#define PORTSC_RO_MASK       0x007001c0
+#define PORTSC_RWC_MASK      0x0000002a
+#define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
+#define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
+#define PORTSC_WKCN_E        (1 << 20)    // Wake on Connect Enable
+#define PORTSC_PTC           (15 << 16)   // Port Test Control
+#define PORTSC_PTC_SH        16           // Port Test Control shift
+#define PORTSC_PIC           (3 << 14)    // Port Indicator Control
+#define PORTSC_PIC_SH        14           // Port Indicator Control Shift
+#define PORTSC_POWNER        (1 << 13)    // Port Owner
+#define PORTSC_PPOWER        (1 << 12)    // Port Power
+#define PORTSC_LINESTAT      (3 << 10)    // Port Line Status
+#define PORTSC_LINESTAT_SH   10           // Port Line Status Shift
+#define PORTSC_PRESET        (1 << 8)     // Port Reset
+#define PORTSC_SUSPEND       (1 << 7)     // Port Suspend
+#define PORTSC_FPRES         (1 << 6)     // Force Port Resume
+#define PORTSC_OCC           (1 << 5)     // Over Current Change
+#define PORTSC_OCA           (1 << 4)     // Over Current Active
+#define PORTSC_PEDC          (1 << 3)     // Port Enable/Disable Change
+#define PORTSC_PED           (1 << 2)     // Port Enable/Disable
+#define PORTSC_CSC           (1 << 1)     // Connect Status Change
+#define PORTSC_CONNECT       (1 << 0)     // Current Connect Status
+
+#define FRAME_TIMER_FREQ 1000
+#define FRAME_TIMER_NS   (1000000000 / FRAME_TIMER_FREQ)
+
+#define NB_MAXINTRATE    8        // Max rate at which controller issues ints
+#define NB_PORTS         6        // Number of downstream ports
+#define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
+#define MAX_ITERATIONS   20       // Max number of QH before we break the loop
+#define MAX_QH           100      // Max allowable queue heads in a chain
+
+/*  Internal periodic / asynchronous schedule state machine states
+ */
+typedef enum {
+    EST_INACTIVE = 1000,
+    EST_ACTIVE,
+    EST_EXECUTING,
+    EST_SLEEPING,
+    /*  The following states are internal to the state machine function
+    */
+    EST_WAITLISTHEAD,
+    EST_FETCHENTRY,
+    EST_FETCHQH,
+    EST_FETCHITD,
+    EST_ADVANCEQUEUE,
+    EST_FETCHQTD,
+    EST_EXECUTE,
+    EST_WRITEBACK,
+    EST_HORIZONTALQH
+} EHCI_STATES;
+
+/* macros for accessing fields within next link pointer entry */
+#define NLPTR_GET(x)             ((x) & 0xffffffe0)
+#define NLPTR_TYPE_GET(x)        (((x) >> 1) & 3)
+#define NLPTR_TBIT(x)            ((x) & 1)  // 1=invalid, 0=valid
+
+/* link pointer types */
+#define NLPTR_TYPE_ITD           0     // isoc xfer descriptor
+#define NLPTR_TYPE_QH            1     // queue head
+#define NLPTR_TYPE_STITD         2     // split xaction, isoc xfer descriptor
+#define NLPTR_TYPE_FSTN          3     // frame span traversal node
+
+
+/*  EHCI spec version 1.0 Section 3.3
+ */
+typedef struct EHCIitd {
+    uint32_t next;
+
+    uint32_t transact[8];
+#define ITD_XACT_ACTIVE          (1 << 31)
+#define ITD_XACT_DBERROR         (1 << 30)
+#define ITD_XACT_BABBLE          (1 << 29)
+#define ITD_XACT_XACTERR         (1 << 28)
+#define ITD_XACT_LENGTH_MASK     0x0fff0000
+#define ITD_XACT_LENGTH_SH       16
+#define ITD_XACT_IOC             (1 << 15)
+#define ITD_XACT_PGSEL_MASK      0x00007000
+#define ITD_XACT_PGSEL_SH        12
+#define ITD_XACT_OFFSET_MASK     0x00000fff
+
+    uint32_t bufptr[7];
+#define ITD_BUFPTR_MASK          0xfffff000
+#define ITD_BUFPTR_SH            12
+#define ITD_BUFPTR_EP_MASK       0x00000f00
+#define ITD_BUFPTR_EP_SH         8
+#define ITD_BUFPTR_DEVADDR_MASK  0x0000007f
+#define ITD_BUFPTR_DEVADDR_SH    0
+#define ITD_BUFPTR_DIRECTION     (1 << 11)
+#define ITD_BUFPTR_MAXPKT_MASK   0x000007ff
+#define ITD_BUFPTR_MAXPKT_SH     0
+#define ITD_BUFPTR_MULT_MASK     0x00000003
+#define ITD_BUFPTR_MULT_SH       0
+} EHCIitd;
+
+/*  EHCI spec version 1.0 Section 3.4
+ */
+typedef struct EHCIsitd {
+    uint32_t next;                  // Standard next link pointer
+    uint32_t epchar;
+#define SITD_EPCHAR_IO              (1 << 31)
+#define SITD_EPCHAR_PORTNUM_MASK    0x7f000000
+#define SITD_EPCHAR_PORTNUM_SH      24
+#define SITD_EPCHAR_HUBADD_MASK     0x007f0000
+#define SITD_EPCHAR_HUBADDR_SH      16
+#define SITD_EPCHAR_EPNUM_MASK      0x00000f00
+#define SITD_EPCHAR_EPNUM_SH        8
+#define SITD_EPCHAR_DEVADDR_MASK    0x0000007f
+
+    uint32_t uframe;
+#define SITD_UFRAME_CMASK_MASK      0x0000ff00
+#define SITD_UFRAME_CMASK_SH        8
+#define SITD_UFRAME_SMASK_MASK      0x000000ff
+
+    uint32_t results;
+#define SITD_RESULTS_IOC              (1 << 31)
+#define SITD_RESULTS_PGSEL            (1 << 30)
+#define SITD_RESULTS_TBYTES_MASK      0x03ff0000
+#define SITD_RESULTS_TYBYTES_SH       16
+#define SITD_RESULTS_CPROGMASK_MASK   0x0000ff00
+#define SITD_RESULTS_CPROGMASK_SH     8
+#define SITD_RESULTS_ACTIVE           (1 << 7)
+#define SITD_RESULTS_ERR              (1 << 6)
+#define SITD_RESULTS_DBERR            (1 << 5)
+#define SITD_RESULTS_BABBLE           (1 << 4)
+#define SITD_RESULTS_XACTERR          (1 << 3)
+#define SITD_RESULTS_MISSEDUF         (1 << 2)
+#define SITD_RESULTS_SPLITXSTATE      (1 << 1)
+
+    uint32_t bufptr[2];
+#define SITD_BUFPTR_MASK              0xfffff000
+#define SITD_BUFPTR_CURROFF_MASK      0x00000fff
+#define SITD_BUFPTR_TPOS_MASK         0x00000018
+#define SITD_BUFPTR_TPOS_SH           3
+#define SITD_BUFPTR_TCNT_MASK         0x00000007
+
+    uint32_t backptr;                 // Standard next link pointer
+} EHCIsitd;
+
+/*  EHCI spec version 1.0 Section 3.5
+ */
+typedef struct EHCIqtd {
+    uint32_t next;                    // Standard next link pointer
+    uint32_t altnext;                 // Standard next link pointer
+    uint32_t token;
+#define QTD_TOKEN_DTOGGLE             (1 << 31)
+#define QTD_TOKEN_TBYTES_MASK         0x7fff0000
+#define QTD_TOKEN_TBYTES_SH           16
+#define QTD_TOKEN_IOC                 (1 << 15)
+#define QTD_TOKEN_CPAGE_MASK          0x00007000
+#define QTD_TOKEN_CPAGE_SH            12
+#define QTD_TOKEN_CERR_MASK           0x00000c00
+#define QTD_TOKEN_CERR_SH             10
+#define QTD_TOKEN_PID_MASK            0x00000300
+#define QTD_TOKEN_PID_SH              8
+#define QTD_TOKEN_ACTIVE              (1 << 7)
+#define QTD_TOKEN_HALT                (1 << 6)
+#define QTD_TOKEN_DBERR               (1 << 5)
+#define QTD_TOKEN_BABBLE              (1 << 4)
+#define QTD_TOKEN_XACTERR             (1 << 3)
+#define QTD_TOKEN_MISSEDUF            (1 << 2)
+#define QTD_TOKEN_SPLITXSTATE         (1 << 1)
+#define QTD_TOKEN_PING                (1 << 0)
+
+    uint32_t bufptr[5];               // Standard buffer pointer
+#define QTD_BUFPTR_MASK               0xfffff000
+} EHCIqtd;
+
+/*  EHCI spec version 1.0 Section 3.6
+ */
+typedef struct EHCIqh {
+    uint32_t next;                    // Standard next link pointer
+
+    /* endpoint characteristics */
+    uint32_t epchar;
+#define QH_EPCHAR_RL_MASK             0xf0000000
+#define QH_EPCHAR_RL_SH               28
+#define QH_EPCHAR_C                   (1 << 27)
+#define QH_EPCHAR_MPLEN_MASK          0x07FF0000
+#define QH_EPCHAR_MPLEN_SH            16
+#define QH_EPCHAR_H                   (1 << 15)
+#define QH_EPCHAR_DTC                 (1 << 14)
+#define QH_EPCHAR_EPS_MASK            0x00003000
+#define QH_EPCHAR_EPS_SH              12
+#define EHCI_QH_EPS_FULL              0
+#define EHCI_QH_EPS_LOW               1
+#define EHCI_QH_EPS_HIGH              2
+#define EHCI_QH_EPS_RESERVED          3
+
+#define QH_EPCHAR_EP_MASK             0x00000f00
+#define QH_EPCHAR_EP_SH               8
+#define QH_EPCHAR_I                   (1 << 7)
+#define QH_EPCHAR_DEVADDR_MASK        0x0000007f
+#define QH_EPCHAR_DEVADDR_SH          0
+
+    /* endpoint capabilities */
+    uint32_t epcap;
+#define QH_EPCAP_MULT_MASK            0xc0000000
+#define QH_EPCAP_MULT_SH              30
+#define QH_EPCAP_PORTNUM_MASK         0x3f800000
+#define QH_EPCAP_PORTNUM_SH           23
+#define QH_EPCAP_HUBADDR_MASK         0x007f0000
+#define QH_EPCAP_HUBADDR_SH           16
+#define QH_EPCAP_CMASK_MASK           0x0000ff00
+#define QH_EPCAP_CMASK_SH             8
+#define QH_EPCAP_SMASK_MASK           0x000000ff
+#define QH_EPCAP_SMASK_SH             0
+
+    uint32_t current_qtd;             // Standard next link pointer
+    uint32_t next_qtd;                // Standard next link pointer
+    uint32_t altnext_qtd;
+#define QH_ALTNEXT_NAKCNT_MASK        0x0000001e
+#define QH_ALTNEXT_NAKCNT_SH          1
+
+    uint32_t token;                   // Same as QTD token
+    uint32_t bufptr[5];               // Standard buffer pointer
+#define BUFPTR_CPROGMASK_MASK         0x000000ff
+#define BUFPTR_FRAMETAG_MASK          0x0000001f
+#define BUFPTR_SBYTES_MASK            0x00000fe0
+#define BUFPTR_SBYTES_SH              5
+} EHCIqh;
+
+/*  EHCI spec version 1.0 Section 3.7
+ */
+typedef struct EHCIfstn {
+    uint32_t next;                    // Standard next link pointer
+    uint32_t backptr;                 // Standard next link pointer
+} EHCIfstn;
+
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+enum async_state {
+    EHCI_ASYNC_NONE = 0,
+    EHCI_ASYNC_INFLIGHT,
+    EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIQueue {
+    EHCIState *ehci;
+    QTAILQ_ENTRY(EHCIQueue) next;
+    bool async_schedule;
+    uint32_t seen;
+    uint64_t ts;
+
+    /* cached data from guest - needs to be flushed
+     * when guest removes an entry (doorbell, handshake sequence)
+     */
+    EHCIqh qh;             // copy of current QH (being worked on)
+    uint32_t qhaddr;       // address QH read from
+    EHCIqtd qtd;           // copy of current QTD (being worked on)
+    uint32_t qtdaddr;      // address QTD read from
+
+    USBPacket packet;
+    uint8_t buffer[BUFF_SIZE];
+    int pid;
+    uint32_t tbytes;
+    enum async_state async;
+    int usb_status;
+};
+
+struct EHCIState {
+    PCIDevice dev;
+    USBBus bus;
+    qemu_irq irq;
+    target_phys_addr_t mem_base;
+    int mem;
+    int companion_count;
+
+    /* properties */
+    uint32_t freq;
+    uint32_t maxframes;
+
+    /*
+     *  EHCI spec version 1.0 Section 2.3
+     *  Host Controller Operational Registers
+     */
+    union {
+        uint8_t mmio[MMIO_SIZE];
+        struct {
+            uint8_t cap[OPREGBASE];
+            uint32_t usbcmd;
+            uint32_t usbsts;
+            uint32_t usbintr;
+            uint32_t frindex;
+            uint32_t ctrldssegment;
+            uint32_t periodiclistbase;
+            uint32_t asynclistaddr;
+            uint32_t notused[9];
+            uint32_t configflag;
+            uint32_t portsc[NB_PORTS];
+        };
+    };
+
+    /*
+     *  Internal states, shadow registers, etc
+     */
+    uint32_t sofv;
+    QEMUTimer *frame_timer;
+    int attach_poll_counter;
+    int astate;                        // Current state in asynchronous schedule
+    int pstate;                        // Current state in periodic schedule
+    USBPort ports[NB_PORTS];
+    USBPort *companion_ports[NB_PORTS];
+    uint32_t usbsts_pending;
+    QTAILQ_HEAD(, EHCIQueue) queues;
+
+    uint32_t a_fetch_addr;   // which address to look at next
+    uint32_t p_fetch_addr;   // which address to look at next
+
+    USBPacket ipacket;
+    uint8_t ibuffer[BUFF_SIZE];
+    int isoch_pause;
+
+    uint64_t last_run_ns;
+};
+
+#define SET_LAST_RUN_CLOCK(s) \
+    (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
+
+/* nifty macros from Arnon's EHCI version  */
+#define get_field(data, field) \
+    (((data) & field##_MASK) >> field##_SH)
+
+#define set_field(data, newval, field) do { \
+    uint32_t val = *data; \
+    val &= ~ field##_MASK; \
+    val |= ((newval) << field##_SH) & field##_MASK; \
+    *data = val; \
+    } while(0)
+
+static const char *ehci_state_names[] = {
+    [ EST_INACTIVE ]     = "INACTIVE",
+    [ EST_ACTIVE ]       = "ACTIVE",
+    [ EST_EXECUTING ]    = "EXECUTING",
+    [ EST_SLEEPING ]     = "SLEEPING",
+    [ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
+    [ EST_FETCHENTRY ]   = "FETCH ENTRY",
+    [ EST_FETCHQH ]      = "FETCH QH",
+    [ EST_FETCHITD ]     = "FETCH ITD",
+    [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
+    [ EST_FETCHQTD ]     = "FETCH QTD",
+    [ EST_EXECUTE ]      = "EXECUTE",
+    [ EST_WRITEBACK ]    = "WRITEBACK",
+    [ EST_HORIZONTALQH ] = "HORIZONTALQH",
+};
+
+static const char *ehci_mmio_names[] = {
+    [ CAPLENGTH ]        = "CAPLENGTH",
+    [ HCIVERSION ]       = "HCIVERSION",
+    [ HCSPARAMS ]        = "HCSPARAMS",
+    [ HCCPARAMS ]        = "HCCPARAMS",
+    [ USBCMD ]           = "USBCMD",
+    [ USBSTS ]           = "USBSTS",
+    [ USBINTR ]          = "USBINTR",
+    [ FRINDEX ]          = "FRINDEX",
+    [ PERIODICLISTBASE ] = "P-LIST BASE",
+    [ ASYNCLISTADDR ]    = "A-LIST ADDR",
+    [ PORTSC_BEGIN ]     = "PORTSC #0",
+    [ PORTSC_BEGIN + 4]  = "PORTSC #1",
+    [ PORTSC_BEGIN + 8]  = "PORTSC #2",
+    [ PORTSC_BEGIN + 12] = "PORTSC #3",
+    [ CONFIGFLAG ]       = "CONFIGFLAG",
+};
+
+static const char *nr2str(const char **n, size_t len, uint32_t nr)
+{
+    if (nr < len && n[nr] != NULL) {
+        return n[nr];
+    } else {
+        return "unknown";
+    }
+}
+
+static const char *state2str(uint32_t state)
+{
+    return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
+}
+
+static const char *addr2str(target_phys_addr_t addr)
+{
+    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+}
+
+static void ehci_trace_usbsts(uint32_t mask, int state)
+{
+    /* interrupts */
+    if (mask & USBSTS_INT) {
+        trace_usb_ehci_usbsts("INT", state);
+    }
+    if (mask & USBSTS_ERRINT) {
+        trace_usb_ehci_usbsts("ERRINT", state);
+    }
+    if (mask & USBSTS_PCD) {
+        trace_usb_ehci_usbsts("PCD", state);
+    }
+    if (mask & USBSTS_FLR) {
+        trace_usb_ehci_usbsts("FLR", state);
+    }
+    if (mask & USBSTS_HSE) {
+        trace_usb_ehci_usbsts("HSE", state);
+    }
+    if (mask & USBSTS_IAA) {
+        trace_usb_ehci_usbsts("IAA", state);
+    }
+
+    /* status */
+    if (mask & USBSTS_HALT) {
+        trace_usb_ehci_usbsts("HALT", state);
+    }
+    if (mask & USBSTS_REC) {
+        trace_usb_ehci_usbsts("REC", state);
+    }
+    if (mask & USBSTS_PSS) {
+        trace_usb_ehci_usbsts("PSS", state);
+    }
+    if (mask & USBSTS_ASS) {
+        trace_usb_ehci_usbsts("ASS", state);
+    }
+}
+
+static inline void ehci_set_usbsts(EHCIState *s, int mask)
+{
+    if ((s->usbsts & mask) == mask) {
+        return;
+    }
+    ehci_trace_usbsts(mask, 1);
+    s->usbsts |= mask;
+}
+
+static inline void ehci_clear_usbsts(EHCIState *s, int mask)
+{
+    if ((s->usbsts & mask) == 0) {
+        return;
+    }
+    ehci_trace_usbsts(mask, 0);
+    s->usbsts &= ~mask;
+}
+
+static inline void ehci_set_interrupt(EHCIState *s, int intr)
+{
+    int level = 0;
+
+    // TODO honour interrupt threshold requests
+
+    ehci_set_usbsts(s, intr);
+
+    if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
+        level = 1;
+    }
+
+    qemu_set_irq(s->irq, level);
+}
+
+static inline void ehci_record_interrupt(EHCIState *s, int intr)
+{
+    s->usbsts_pending |= intr;
+}
+
+static inline void ehci_commit_interrupt(EHCIState *s)
+{
+    if (!s->usbsts_pending) {
+        return;
+    }
+    ehci_set_interrupt(s, s->usbsts_pending);
+    s->usbsts_pending = 0;
+}
+
+static void ehci_set_state(EHCIState *s, int async, int state)
+{
+    if (async) {
+        trace_usb_ehci_state("async", state2str(state));
+        s->astate = state;
+    } else {
+        trace_usb_ehci_state("periodic", state2str(state));
+        s->pstate = state;
+    }
+}
+
+static int ehci_get_state(EHCIState *s, int async)
+{
+    return async ? s->astate : s->pstate;
+}
+
+static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
+{
+    if (async) {
+        s->a_fetch_addr = addr;
+    } else {
+        s->p_fetch_addr = addr;
+    }
+}
+
+static int ehci_get_fetch_addr(EHCIState *s, int async)
+{
+    return async ? s->a_fetch_addr : s->p_fetch_addr;
+}
+
+static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh)
+{
+    /* need three here due to argument count limits */
+    trace_usb_ehci_qh_ptrs(q, addr, qh->next,
+                           qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
+    trace_usb_ehci_qh_fields(addr,
+                             get_field(qh->epchar, QH_EPCHAR_RL),
+                             get_field(qh->epchar, QH_EPCHAR_MPLEN),
+                             get_field(qh->epchar, QH_EPCHAR_EPS),
+                             get_field(qh->epchar, QH_EPCHAR_EP),
+                             get_field(qh->epchar, QH_EPCHAR_DEVADDR));
+    trace_usb_ehci_qh_bits(addr,
+                           (bool)(qh->epchar & QH_EPCHAR_C),
+                           (bool)(qh->epchar & QH_EPCHAR_H),
+                           (bool)(qh->epchar & QH_EPCHAR_DTC),
+                           (bool)(qh->epchar & QH_EPCHAR_I));
+}
+
+static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
+{
+    /* need three here due to argument count limits */
+    trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
+    trace_usb_ehci_qtd_fields(addr,
+                              get_field(qtd->token, QTD_TOKEN_TBYTES),
+                              get_field(qtd->token, QTD_TOKEN_CPAGE),
+                              get_field(qtd->token, QTD_TOKEN_CERR),
+                              get_field(qtd->token, QTD_TOKEN_PID));
+    trace_usb_ehci_qtd_bits(addr,
+                            (bool)(qtd->token & QTD_TOKEN_IOC),
+                            (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+                            (bool)(qtd->token & QTD_TOKEN_HALT),
+                            (bool)(qtd->token & QTD_TOKEN_BABBLE),
+                            (bool)(qtd->token & QTD_TOKEN_XACTERR));
+}
+
+static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+{
+    trace_usb_ehci_itd(addr, itd->next,
+                       get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
+                       get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
+                       get_field(itd->bufptr[0], ITD_BUFPTR_EP),
+                       get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
+}
+
+/* queue management */
+
+static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+{
+    EHCIQueue *q;
+
+    q = qemu_mallocz(sizeof(*q));
+    q->ehci = ehci;
+    q->async_schedule = async;
+    QTAILQ_INSERT_HEAD(&ehci->queues, q, next);
+    trace_usb_ehci_queue_action(q, "alloc");
+    return q;
+}
+
+static void ehci_free_queue(EHCIQueue *q)
+{
+    trace_usb_ehci_queue_action(q, "free");
+    if (q->async == EHCI_ASYNC_INFLIGHT) {
+        usb_cancel_packet(&q->packet);
+    }
+    QTAILQ_REMOVE(&q->ehci->queues, q, next);
+    qemu_free(q);
+}
+
+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
+{
+    EHCIQueue *q;
+
+    QTAILQ_FOREACH(q, &ehci->queues, next) {
+        if (addr == q->qhaddr) {
+            return q;
+        }
+    }
+    return NULL;
+}
+
+static void ehci_queues_rip_unused(EHCIState *ehci)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        if (q->seen) {
+            q->seen = 0;
+            q->ts = ehci->last_run_ns;
+            continue;
+        }
+        if (ehci->last_run_ns < q->ts + 250000000) {
+            /* allow 0.25 sec idle */
+            continue;
+        }
+        ehci_free_queue(q);
+    }
+}
+
+static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        if (q->packet.owner != dev) {
+            continue;
+        }
+        ehci_free_queue(q);
+    }
+}
+
+static void ehci_queues_rip_all(EHCIState *ehci)
+{
+    EHCIQueue *q, *tmp;
+
+    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+        ehci_free_queue(q);
+    }
+}
+
+/* Attach or detach a device on root hub */
+
+static void ehci_attach(USBPort *port)
+{
+    EHCIState *s = port->opaque;
+    uint32_t *portsc = &s->portsc[port->index];
+
+    trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
+
+    if (*portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->dev = port->dev;
+        companion->ops->attach(companion);
+        return;
+    }
+
+    *portsc |= PORTSC_CONNECT;
+    *portsc |= PORTSC_CSC;
+
+    ehci_set_interrupt(s, USBSTS_PCD);
+}
+
+static void ehci_detach(USBPort *port)
+{
+    EHCIState *s = port->opaque;
+    uint32_t *portsc = &s->portsc[port->index];
+
+    trace_usb_ehci_port_detach(port->index);
+
+    if (*portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->detach(companion);
+        companion->dev = NULL;
+        return;
+    }
+
+    ehci_queues_rip_device(s, port->dev);
+
+    *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
+    *portsc |= PORTSC_CSC;
+
+    ehci_set_interrupt(s, USBSTS_PCD);
+}
+
+static void ehci_child_detach(USBPort *port, USBDevice *child)
+{
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
+
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->child_detach(companion, child);
+        companion->dev = NULL;
+        return;
+    }
+
+    ehci_queues_rip_device(s, child);
+}
+
+static void ehci_wakeup(USBPort *port)
+{
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
+
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        if (companion->ops->wakeup) {
+            companion->ops->wakeup(companion);
+        }
+    }
+}
+
+static int ehci_register_companion(USBBus *bus, USBPort *ports[],
+                                   uint32_t portcount, uint32_t firstport)
+{
+    EHCIState *s = container_of(bus, EHCIState, bus);
+    uint32_t i;
+
+    if (firstport + portcount > NB_PORTS) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
+                      "firstport on masterbus");
+        error_printf_unless_qmp(
+            "firstport value of %u makes companion take ports %u - %u, which "
+            "is outside of the valid range of 0 - %u\n", firstport, firstport,
+            firstport + portcount - 1, NB_PORTS - 1);
+        return -1;
+    }
+
+    for (i = 0; i < portcount; i++) {
+        if (s->companion_ports[firstport + i]) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+                          "an USB masterbus");
+            error_printf_unless_qmp(
+                "port %u on masterbus %s already has a companion assigned\n",
+                firstport + i, bus->qbus.name);
+            return -1;
+        }
+    }
+
+    for (i = 0; i < portcount; i++) {
+        s->companion_ports[firstport + i] = ports[i];
+        s->ports[firstport + i].speedmask |=
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
+        /* Ensure devs attached before the initial reset go to the companion */
+        s->portsc[firstport + i] = PORTSC_POWNER;
+    }
+
+    s->companion_count++;
+    s->mmio[0x05] = (s->companion_count << 4) | portcount;
+
+    return 0;
+}
+
+/* 4.1 host controller initialization */
+static void ehci_reset(void *opaque)
+{
+    EHCIState *s = opaque;
+    int i;
+    USBDevice *devs[NB_PORTS];
+
+    trace_usb_ehci_reset();
+
+    /*
+     * Do the detach before touching portsc, so that it correctly gets send to
+     * us or to our companion based on PORTSC_POWNER before the reset.
+     */
+    for(i = 0; i < NB_PORTS; i++) {
+        devs[i] = s->ports[i].dev;
+        if (devs[i]) {
+            usb_attach(&s->ports[i], NULL);
+        }
+    }
+
+    memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
+
+    s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
+    s->usbsts = USBSTS_HALT;
+
+    s->astate = EST_INACTIVE;
+    s->pstate = EST_INACTIVE;
+    s->isoch_pause = -1;
+    s->attach_poll_counter = 0;
+
+    for(i = 0; i < NB_PORTS; i++) {
+        if (s->companion_ports[i]) {
+            s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
+        } else {
+            s->portsc[i] = PORTSC_PPOWER;
+        }
+        if (devs[i]) {
+            usb_attach(&s->ports[i], devs[i]);
+        }
+    }
+    ehci_queues_rip_all(s);
+}
+
+static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
+{
+    EHCIState *s = ptr;
+    uint32_t val;
+
+    val = s->mmio[addr];
+
+    return val;
+}
+
+static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
+{
+    EHCIState *s = ptr;
+    uint32_t val;
+
+    val = s->mmio[addr] | (s->mmio[addr+1] << 8);
+
+    return val;
+}
+
+static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
+{
+    EHCIState *s = ptr;
+    uint32_t val;
+
+    val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
+          (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
+
+    trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
+    return val;
+}
+
+static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
+    exit(1);
+}
+
+static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
+    exit(1);
+}
+
+static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
+{
+    USBDevice *dev = s->ports[port].dev;
+    uint32_t *portsc = &s->portsc[port];
+    uint32_t orig;
+
+    if (s->companion_ports[port] == NULL)
+        return;
+
+    owner = owner & PORTSC_POWNER;
+    orig  = *portsc & PORTSC_POWNER;
+
+    if (!(owner ^ orig)) {
+        return;
+    }
+
+    if (dev) {
+        usb_attach(&s->ports[port], NULL);
+    }
+
+    *portsc &= ~PORTSC_POWNER;
+    *portsc |= owner;
+
+    if (dev) {
+        usb_attach(&s->ports[port], dev);
+    }
+}
+
+static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+{
+    uint32_t *portsc = &s->portsc[port];
+    USBDevice *dev = s->ports[port].dev;
+
+    /* Clear rwc bits */
+    *portsc &= ~(val & PORTSC_RWC_MASK);
+    /* The guest may clear, but not set the PED bit */
+    *portsc &= val | ~PORTSC_PED;
+    /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
+    handle_port_owner_write(s, port, val);
+    /* And finally apply RO_MASK */
+    val &= PORTSC_RO_MASK;
+
+    if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
+        trace_usb_ehci_port_reset(port, 1);
+    }
+
+    if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
+        trace_usb_ehci_port_reset(port, 0);
+        if (dev) {
+            usb_attach(&s->ports[port], dev);
+            usb_send_msg(dev, USB_MSG_RESET);
+            *portsc &= ~PORTSC_CSC;
+        }
+
+        /*
+         *  Table 2.16 Set the enable bit(and enable bit change) to indicate
+         *  to SW that this port has a high speed device attached
+         */
+        if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+            val |= PORTSC_PED;
+        }
+    }
+
+    *portsc &= ~PORTSC_RO_MASK;
+    *portsc |= val;
+}
+
+static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    EHCIState *s = ptr;
+    uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
+    uint32_t old = *mmio;
+    int i;
+
+    trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
+
+    /* Only aligned reads are allowed on OHCI */
+    if (addr & 3) {
+        fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
+                TARGET_FMT_plx "\n", addr);
+        return;
+    }
+
+    if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
+        handle_port_status_write(s, (addr-PORTSC)/4, val);
+        trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
+        return;
+    }
+
+    if (addr < OPREGBASE) {
+        fprintf(stderr, "usb-ehci: write attempt to read-only register"
+                TARGET_FMT_plx "\n", addr);
+        return;
+    }
+
+
+    /* Do any register specific pre-write processing here.  */
+    switch(addr) {
+    case USBCMD:
+        if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
+            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
+            SET_LAST_RUN_CLOCK(s);
+            ehci_clear_usbsts(s, USBSTS_HALT);
+        }
+
+        if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
+            qemu_del_timer(s->frame_timer);
+            // TODO - should finish out some stuff before setting halt
+            ehci_set_usbsts(s, USBSTS_HALT);
+        }
+
+        if (val & USBCMD_HCRESET) {
+            ehci_reset(s);
+            val &= ~USBCMD_HCRESET;
+        }
+
+        /* not supporting dynamic frame list size at the moment */
+        if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
+            fprintf(stderr, "attempt to set frame list size -- value %d\n",
+                    val & USBCMD_FLS);
+            val &= ~USBCMD_FLS;
+        }
+        break;
+
+    case USBSTS:
+        val &= USBSTS_RO_MASK;              // bits 6 thru 31 are RO
+        ehci_clear_usbsts(s, val);          // bits 0 thru 5 are R/WC
+        val = s->usbsts;
+        ehci_set_interrupt(s, 0);
+        break;
+
+    case USBINTR:
+        val &= USBINTR_MASK;
+        break;
+
+    case FRINDEX:
+        s->sofv = val >> 3;
+        break;
+
+    case CONFIGFLAG:
+        val &= 0x1;
+        if (val) {
+            for(i = 0; i < NB_PORTS; i++)
+                handle_port_owner_write(s, i, 0);
+        }
+        break;
+
+    case PERIODICLISTBASE:
+        if ((s->usbcmd & USBCMD_PSE) && (s->usbcmd & USBCMD_RUNSTOP)) {
+            fprintf(stderr,
+              "ehci: PERIODIC list base register set while periodic schedule\n"
+              "      is enabled and HC is enabled\n");
+        }
+        break;
+
+    case ASYNCLISTADDR:
+        if ((s->usbcmd & USBCMD_ASE) && (s->usbcmd & USBCMD_RUNSTOP)) {
+            fprintf(stderr,
+              "ehci: ASYNC list address register set while async schedule\n"
+              "      is enabled and HC is enabled\n");
+        }
+        break;
+    }
+
+    *mmio = val;
+    trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
+}
+
+
+// TODO : Put in common header file, duplication from usb-ohci.c
+
+/* Get an array of dwords from main memory */
+static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+    int i;
+
+    for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        cpu_physical_memory_rw(addr,(uint8_t *)buf, sizeof(*buf), 0);
+        *buf = le32_to_cpu(*buf);
+    }
+
+    return 1;
+}
+
+/* Put an array of dwords in to main memory */
+static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+    int i;
+
+    for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        uint32_t tmp = cpu_to_le32(*buf);
+        cpu_physical_memory_rw(addr,(uint8_t *)&tmp, sizeof(tmp), 1);
+    }
+
+    return 1;
+}
+
+// 4.10.2
+
+static int ehci_qh_do_overlay(EHCIQueue *q)
+{
+    int i;
+    int dtoggle;
+    int ping;
+    int eps;
+    int reload;
+
+    // remember values in fields to preserve in qh after overlay
+
+    dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
+    ping    = q->qh.token & QTD_TOKEN_PING;
+
+    q->qh.current_qtd = q->qtdaddr;
+    q->qh.next_qtd    = q->qtd.next;
+    q->qh.altnext_qtd = q->qtd.altnext;
+    q->qh.token       = q->qtd.token;
+
+
+    eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
+    if (eps == EHCI_QH_EPS_HIGH) {
+        q->qh.token &= ~QTD_TOKEN_PING;
+        q->qh.token |= ping;
+    }
+
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+    set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+
+    for (i = 0; i < 5; i++) {
+        q->qh.bufptr[i] = q->qtd.bufptr[i];
+    }
+
+    if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
+        // preserve QH DT bit
+        q->qh.token &= ~QTD_TOKEN_DTOGGLE;
+        q->qh.token |= dtoggle;
+    }
+
+    q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
+    q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
+
+    put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+
+    return 0;
+}
+
+static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
+{
+    int bufpos = 0;
+    int cpage, offset;
+    uint32_t head;
+    uint32_t tail;
+
+
+    if (!bytes) {
+        return 0;
+    }
+
+    cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+    if (cpage > 4) {
+        fprintf(stderr, "cpage out of range (%d)\n", cpage);
+        return USB_RET_PROCERR;
+    }
+
+    offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+
+    do {
+        /* start and end of this page */
+        head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
+        tail = head + ~QTD_BUFPTR_MASK + 1;
+        /* add offset into page */
+        head |= offset;
+
+        if (bytes <= (tail - head)) {
+            tail = head + bytes;
+        }
+
+        trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
+        cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
+
+        bufpos += (tail - head);
+        offset += (tail - head);
+        bytes -= (tail - head);
+
+        if (bytes > 0) {
+            cpage++;
+            offset = 0;
+        }
+    } while (bytes > 0);
+
+    /* save cpage */
+    set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+
+    /* save offset into cpage */
+    q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+    q->qh.bufptr[0] |= offset;
+
+    return 0;
+}
+
+static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
+{
+    EHCIQueue *q;
+    EHCIState *s = port->opaque;
+    uint32_t portsc = s->portsc[port->index];
+
+    if (portsc & PORTSC_POWNER) {
+        USBPort *companion = s->companion_ports[port->index];
+        companion->ops->complete(companion, packet);
+        return;
+    }
+
+    q = container_of(packet, EHCIQueue, packet);
+    trace_usb_ehci_queue_action(q, "wakeup");
+    assert(q->async == EHCI_ASYNC_INFLIGHT);
+    q->async = EHCI_ASYNC_FINISHED;
+    q->usb_status = packet->len;
+}
+
+static void ehci_execute_complete(EHCIQueue *q)
+{
+    int c_err, reload;
+
+    assert(q->async != EHCI_ASYNC_INFLIGHT);
+    q->async = EHCI_ASYNC_NONE;
+
+    DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
+            q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
+
+    if (q->usb_status < 0) {
+err:
+        /* TO-DO: put this is in a function that can be invoked below as well */
+        c_err = get_field(q->qh.token, QTD_TOKEN_CERR);
+        c_err--;
+        set_field(&q->qh.token, c_err, QTD_TOKEN_CERR);
+
+        switch(q->usb_status) {
+        case USB_RET_NODEV:
+            q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+            break;
+        case USB_RET_STALL:
+            q->qh.token |= QTD_TOKEN_HALT;
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+            break;
+        case USB_RET_NAK:
+            /* 4.10.3 */
+            reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+            if ((q->pid == USB_TOKEN_IN) && reload) {
+                int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+                nakcnt--;
+                set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+            } else if (!reload) {
+                return;
+            }
+            break;
+        case USB_RET_BABBLE:
+            q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
+            ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+            break;
+        default:
+            /* should not be triggerable */
+            fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status);
+            assert(0);
+            break;
+        }
+    } else {
+        // DPRINTF("Short packet condition\n");
+        // TODO check 4.12 for splits
+
+        if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
+            q->usb_status = USB_RET_BABBLE;
+            goto err;
+        }
+
+        if (q->tbytes && q->pid == USB_TOKEN_IN) {
+            if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
+                q->usb_status = USB_RET_PROCERR;
+                return;
+            }
+            q->tbytes -= q->usb_status;
+        } else {
+            q->tbytes = 0;
+        }
+
+        DPRINTF("updating tbytes to %d\n", q->tbytes);
+        set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
+    }
+
+    q->qh.token ^= QTD_TOKEN_DTOGGLE;
+    q->qh.token &= ~QTD_TOKEN_ACTIVE;
+
+    if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) {
+        ehci_record_interrupt(q->ehci, USBSTS_INT);
+    }
+}
+
+// 4.10.3
+
+static int ehci_execute(EHCIQueue *q)
+{
+    USBPort *port;
+    USBDevice *dev;
+    int ret;
+    int i;
+    int endp;
+    int devadr;
+
+    if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) {
+        fprintf(stderr, "Attempting to execute inactive QH\n");
+        return USB_RET_PROCERR;
+    }
+
+    q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+    if (q->tbytes > BUFF_SIZE) {
+        fprintf(stderr, "Request for more bytes than allowed\n");
+        return USB_RET_PROCERR;
+    }
+
+    q->pid = (q->qh.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+    switch(q->pid) {
+        case 0: q->pid = USB_TOKEN_OUT; break;
+        case 1: q->pid = USB_TOKEN_IN; break;
+        case 2: q->pid = USB_TOKEN_SETUP; break;
+        default: fprintf(stderr, "bad token\n"); break;
+    }
+
+    if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
+        (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
+        return USB_RET_PROCERR;
+    }
+
+    endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
+    devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
+
+    ret = USB_RET_NODEV;
+
+    // TO-DO: associating device with ehci port
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &q->ehci->ports[i];
+        dev = port->dev;
+
+        if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
+            DPRINTF("Port %d, no exec, not connected(%08X)\n",
+                    i, q->ehci->portsc[i]);
+            continue;
+        }
+
+        q->packet.pid = q->pid;
+        q->packet.devaddr = devadr;
+        q->packet.devep = endp;
+        q->packet.data = q->buffer;
+        q->packet.len = q->tbytes;
+
+        ret = usb_handle_packet(dev, &q->packet);
+
+        DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+                q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+                q->packet.len, q->tbytes, endp, ret);
+
+        if (ret != USB_RET_NODEV) {
+            break;
+        }
+    }
+
+    if (ret > BUFF_SIZE) {
+        fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
+        return USB_RET_PROCERR;
+    }
+
+    return ret;
+}
+
+/*  4.7.2
+ */
+
+static int ehci_process_itd(EHCIState *ehci,
+                            EHCIitd *itd)
+{
+    USBPort *port;
+    USBDevice *dev;
+    int ret;
+    uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+    uint32_t pg, off, ptr1, ptr2, max, mult;
+
+    dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
+    devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+    endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
+    max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+    mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
+
+    for(i = 0; i < 8; i++) {
+        if (itd->transact[i] & ITD_XACT_ACTIVE) {
+            pg   = get_field(itd->transact[i], ITD_XACT_PGSEL);
+            off  = itd->transact[i] & ITD_XACT_OFFSET_MASK;
+            ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
+            ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
+            len  = get_field(itd->transact[i], ITD_XACT_LENGTH);
+
+            if (len > max * mult) {
+                len = max * mult;
+            }
+
+            if (len > BUFF_SIZE) {
+                return USB_RET_PROCERR;
+            }
+
+            if (off + len > 4096) {
+                /* transfer crosses page border */
+                len2 = off + len - 4096;
+                len1 = len - len2;
+            } else {
+                len1 = len;
+                len2 = 0;
+            }
+
+            if (!dir) {
+                pid = USB_TOKEN_OUT;
+                trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
+                cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
+                if (len2) {
+                    trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
+                    cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
+                }
+            } else {
+                pid = USB_TOKEN_IN;
+            }
+
+            ret = USB_RET_NODEV;
+
+            for (j = 0; j < NB_PORTS; j++) {
+                port = &ehci->ports[j];
+                dev = port->dev;
+
+                if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
+                    continue;
+                }
+
+                ehci->ipacket.pid = pid;
+                ehci->ipacket.devaddr = devaddr;
+                ehci->ipacket.devep = endp;
+                ehci->ipacket.data = ehci->ibuffer;
+                ehci->ipacket.len = len;
+
+                ret = usb_handle_packet(dev, &ehci->ipacket);
+
+                if (ret != USB_RET_NODEV) {
+                    break;
+                }
+            }
+
+#if 0
+            /*  In isoch, there is no facility to indicate a NAK so let's
+             *  instead just complete a zero-byte transaction.  Setting
+             *  DBERR seems too draconian.
+             */
+
+            if (ret == USB_RET_NAK) {
+                if (ehci->isoch_pause > 0) {
+                    DPRINTF("ISOCH: received a NAK but paused so returning\n");
+                    ehci->isoch_pause--;
+                    return 0;
+                } else if (ehci->isoch_pause == -1) {
+                    DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
+                    // Pause frindex for up to 50 msec waiting for data from
+                    // remote
+                    ehci->isoch_pause = 50;
+                    return 0;
+                } else {
+                    DPRINTF("ISOCH: isoch pause timeout! return 0\n");
+                    ret = 0;
+                }
+            } else {
+                DPRINTF("ISOCH: received ACK, clearing pause\n");
+                ehci->isoch_pause = -1;
+            }
+#else
+            if (ret == USB_RET_NAK) {
+                ret = 0;
+            }
+#endif
+
+            if (ret >= 0) {
+                if (!dir) {
+                    /* OUT */
+                    set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
+                } else {
+                    /* IN */
+                    if (len1 > ret) {
+                        len1 = ret;
+                    }
+                    if (len2 > ret - len1) {
+                        len2 = ret - len1;
+                    }
+                    if (len1) {
+                        trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
+                        cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
+                    }
+                    if (len2) {
+                        trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
+                        cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
+                    }
+                    set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+                }
+
+                if (itd->transact[i] & ITD_XACT_IOC) {
+                    ehci_record_interrupt(ehci, USBSTS_INT);
+                }
+            }
+            itd->transact[i] &= ~ITD_XACT_ACTIVE;
+        }
+    }
+    return 0;
+}
+
+/*  This state is the entry point for asynchronous schedule
+ *  processing.  Entry here consitutes a EHCI start event state (4.8.5)
+ */
+static int ehci_state_waitlisthead(EHCIState *ehci,  int async)
+{
+    EHCIqh qh;
+    int i = 0;
+    int again = 0;
+    uint32_t entry = ehci->asynclistaddr;
+
+    /* set reclamation flag at start event (4.8.6) */
+    if (async) {
+        ehci_set_usbsts(ehci, USBSTS_REC);
+    }
+
+    ehci_queues_rip_unused(ehci);
+
+    /*  Find the head of the list (4.9.1.1) */
+    for(i = 0; i < MAX_QH; i++) {
+        get_dwords(NLPTR_GET(entry), (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
+        ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
+
+        if (qh.epchar & QH_EPCHAR_H) {
+            if (async) {
+                entry |= (NLPTR_TYPE_QH << 1);
+            }
+
+            ehci_set_fetch_addr(ehci, async, entry);
+            ehci_set_state(ehci, async, EST_FETCHENTRY);
+            again = 1;
+            goto out;
+        }
+
+        entry = qh.next;
+        if (entry == ehci->asynclistaddr) {
+            break;
+        }
+    }
+
+    /* no head found for list. */
+
+    ehci_set_state(ehci, async, EST_ACTIVE);
+
+out:
+    return again;
+}
+
+
+/*  This state is the entry point for periodic schedule processing as
+ *  well as being a continuation state for async processing.
+ */
+static int ehci_state_fetchentry(EHCIState *ehci, int async)
+{
+    int again = 0;
+    uint32_t entry = ehci_get_fetch_addr(ehci, async);
+
+    if (entry < 0x1000) {
+        DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
+        ehci_set_state(ehci, async, EST_ACTIVE);
+        goto out;
+    }
+
+    /* section 4.8, only QH in async schedule */
+    if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
+        fprintf(stderr, "non queue head request in async schedule\n");
+        return -1;
+    }
+
+    switch (NLPTR_TYPE_GET(entry)) {
+    case NLPTR_TYPE_QH:
+        ehci_set_state(ehci, async, EST_FETCHQH);
+        again = 1;
+        break;
+
+    case NLPTR_TYPE_ITD:
+        ehci_set_state(ehci, async, EST_FETCHITD);
+        again = 1;
+        break;
+
+    default:
+        // TODO: handle siTD and FSTN types
+        fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
+                "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
+        return -1;
+    }
+
+out:
+    return again;
+}
+
+static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
+{
+    uint32_t entry;
+    EHCIQueue *q;
+    int reload;
+
+    entry = ehci_get_fetch_addr(ehci, async);
+    q = ehci_find_queue_by_qh(ehci, entry);
+    if (NULL == q) {
+        q = ehci_alloc_queue(ehci, async);
+    }
+    q->qhaddr = entry;
+    q->seen++;
+
+    if (q->seen > 1) {
+        /* we are going in circles -- stop processing */
+        ehci_set_state(ehci, async, EST_ACTIVE);
+        q = NULL;
+        goto out;
+    }
+
+    get_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+    ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
+
+    if (q->async == EHCI_ASYNC_INFLIGHT) {
+        /* I/O still in progress -- skip queue */
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
+        goto out;
+    }
+    if (q->async == EHCI_ASYNC_FINISHED) {
+        /* I/O finished -- continue processing queue */
+        trace_usb_ehci_queue_action(q, "resume");
+        ehci_set_state(ehci, async, EST_EXECUTING);
+        goto out;
+    }
+
+    if (async && (q->qh.epchar & QH_EPCHAR_H)) {
+
+        /*  EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
+        if (ehci->usbsts & USBSTS_REC) {
+            ehci_clear_usbsts(ehci, USBSTS_REC);
+        } else {
+            DPRINTF("FETCHQH:  QH 0x%08x. H-bit set, reclamation status reset"
+                       " - done processing\n", q->qhaddr);
+            ehci_set_state(ehci, async, EST_ACTIVE);
+            q = NULL;
+            goto out;
+        }
+    }
+
+#if EHCI_DEBUG
+    if (q->qhaddr != q->qh.next) {
+    DPRINTF("FETCHQH:  QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
+               q->qhaddr,
+               q->qh.epchar & QH_EPCHAR_H,
+               q->qh.token & QTD_TOKEN_HALT,
+               q->qh.token & QTD_TOKEN_ACTIVE,
+               q->qh.next);
+    }
+#endif
+
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+    if (reload) {
+        set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+    }
+
+    if (q->qh.token & QTD_TOKEN_HALT) {
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
+
+    } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) {
+        q->qtdaddr = q->qh.current_qtd;
+        ehci_set_state(ehci, async, EST_FETCHQTD);
+
+    } else {
+        /*  EHCI spec version 1.0 Section 4.10.2 */
+        ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
+    }
+
+out:
+    return q;
+}
+
+static int ehci_state_fetchitd(EHCIState *ehci, int async)
+{
+    uint32_t entry;
+    EHCIitd itd;
+
+    assert(!async);
+    entry = ehci_get_fetch_addr(ehci, async);
+
+    get_dwords(NLPTR_GET(entry),(uint32_t *) &itd,
+               sizeof(EHCIitd) >> 2);
+    ehci_trace_itd(ehci, entry, &itd);
+
+    if (ehci_process_itd(ehci, &itd) != 0) {
+        return -1;
+    }
+
+    put_dwords(NLPTR_GET(entry), (uint32_t *) &itd,
+                sizeof(EHCIitd) >> 2);
+    ehci_set_fetch_addr(ehci, async, itd.next);
+    ehci_set_state(ehci, async, EST_FETCHENTRY);
+
+    return 1;
+}
+
+/* Section 4.10.2 - paragraph 3 */
+static int ehci_state_advqueue(EHCIQueue *q, int async)
+{
+#if 0
+    /* TO-DO: 4.10.2 - paragraph 2
+     * if I-bit is set to 1 and QH is not active
+     * go to horizontal QH
+     */
+    if (I-bit set) {
+        ehci_set_state(ehci, async, EST_HORIZONTALQH);
+        goto out;
+    }
+#endif
+
+    /*
+     * want data and alt-next qTD is valid
+     */
+    if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+        (q->qh.altnext_qtd > 0x1000) &&
+        (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
+        q->qtdaddr = q->qh.altnext_qtd;
+        ehci_set_state(q->ehci, async, EST_FETCHQTD);
+
+    /*
+     *  next qTD is valid
+     */
+    } else if ((q->qh.next_qtd > 0x1000) &&
+               (NLPTR_TBIT(q->qh.next_qtd) == 0)) {
+        q->qtdaddr = q->qh.next_qtd;
+        ehci_set_state(q->ehci, async, EST_FETCHQTD);
+
+    /*
+     *  no valid qTD, try next QH
+     */
+    } else {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+    }
+
+    return 1;
+}
+
+/* Section 4.10.2 - paragraph 4 */
+static int ehci_state_fetchqtd(EHCIQueue *q, int async)
+{
+    int again = 0;
+
+    get_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qtd, sizeof(EHCIqtd) >> 2);
+    ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd);
+
+    if (q->qtd.token & QTD_TOKEN_ACTIVE) {
+        ehci_set_state(q->ehci, async, EST_EXECUTE);
+        again = 1;
+    } else {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+        again = 1;
+    }
+
+    return again;
+}
+
+static int ehci_state_horizqh(EHCIQueue *q, int async)
+{
+    int again = 0;
+
+    if (ehci_get_fetch_addr(q->ehci, async) != q->qh.next) {
+        ehci_set_fetch_addr(q->ehci, async, q->qh.next);
+        ehci_set_state(q->ehci, async, EST_FETCHENTRY);
+        again = 1;
+    } else {
+        ehci_set_state(q->ehci, async, EST_ACTIVE);
+    }
+
+    return again;
+}
+
+/*
+ *  Write the qh back to guest physical memory.  This step isn't
+ *  in the EHCI spec but we need to do it since we don't share
+ *  physical memory with our guest VM.
+ *
+ *  The first three dwords are read-only for the EHCI, so skip them
+ *  when writing back the qh.
+ */
+static void ehci_flush_qh(EHCIQueue *q)
+{
+    uint32_t *qh = (uint32_t *) &q->qh;
+    uint32_t dwords = sizeof(EHCIqh) >> 2;
+    uint32_t addr = NLPTR_GET(q->qhaddr);
+
+    put_dwords(addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
+}
+
+static int ehci_state_execute(EHCIQueue *q, int async)
+{
+    int again = 0;
+    int reload, nakcnt;
+    int smask;
+
+    if (ehci_qh_do_overlay(q) != 0) {
+        return -1;
+    }
+
+    smask = get_field(q->qh.epcap, QH_EPCAP_SMASK);
+
+    if (!smask) {
+        reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+        if (reload && !nakcnt) {
+            ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+            again = 1;
+            goto out;
+        }
+    }
+
+    // TODO verify enough time remains in the uframe as in 4.4.1.1
+    // TODO write back ptr to async list when done or out of time
+    // TODO Windows does not seem to ever set the MULT field
+
+    if (!async) {
+        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
+        if (!transactCtr) {
+            ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+            again = 1;
+            goto out;
+        }
+    }
+
+    if (async) {
+        ehci_set_usbsts(q->ehci, USBSTS_REC);
+    }
+
+    q->usb_status = ehci_execute(q);
+    if (q->usb_status == USB_RET_PROCERR) {
+        again = -1;
+        goto out;
+    }
+    if (q->usb_status == USB_RET_ASYNC) {
+        ehci_flush_qh(q);
+        trace_usb_ehci_queue_action(q, "suspend");
+        q->async = EHCI_ASYNC_INFLIGHT;
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+        again = 1;
+        goto out;
+    }
+
+    ehci_set_state(q->ehci, async, EST_EXECUTING);
+    again = 1;
+
+out:
+    return again;
+}
+
+static int ehci_state_executing(EHCIQueue *q, int async)
+{
+    int again = 0;
+    int reload, nakcnt;
+
+    ehci_execute_complete(q);
+    if (q->usb_status == USB_RET_ASYNC) {
+        goto out;
+    }
+    if (q->usb_status == USB_RET_PROCERR) {
+        again = -1;
+        goto out;
+    }
+
+    // 4.10.3
+    if (!async) {
+        int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
+        transactCtr--;
+        set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
+        // 4.10.3, bottom of page 82, should exit this state when transaction
+        // counter decrements to 0
+    }
+
+    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+    if (reload) {
+        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+        if (q->usb_status == USB_RET_NAK) {
+            if (nakcnt) {
+                nakcnt--;
+            }
+        } else {
+            nakcnt = reload;
+        }
+        set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+    }
+
+    /* 4.10.5 */
+    if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+    } else {
+        ehci_set_state(q->ehci, async, EST_WRITEBACK);
+    }
+
+    again = 1;
+
+out:
+    ehci_flush_qh(q);
+    return again;
+}
+
+
+static int ehci_state_writeback(EHCIQueue *q, int async)
+{
+    int again = 0;
+
+    /*  Write back the QTD from the QH area */
+    ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
+    put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
+                sizeof(EHCIqtd) >> 2);
+
+    /*
+     * EHCI specs say go horizontal here.
+     *
+     * We can also advance the queue here for performance reasons.  We
+     * need to take care to only take that shortcut in case we've
+     * processed the qtd just written back without errors, i.e. halt
+     * bit is clear.
+     */
+    if (q->qh.token & QTD_TOKEN_HALT) {
+        ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+        again = 1;
+    } else {
+        ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
+        again = 1;
+    }
+    return again;
+}
+
+/*
+ * This is the state machine that is common to both async and periodic
+ */
+
+static void ehci_advance_state(EHCIState *ehci,
+                               int async)
+{
+    EHCIQueue *q = NULL;
+    int again;
+    int iter = 0;
+
+    do {
+        if (ehci_get_state(ehci, async) == EST_FETCHQH) {
+            iter++;
+            /* if we are roaming a lot of QH without executing a qTD
+             * something is wrong with the linked list. TO-DO: why is
+             * this hack needed?
+             */
+            assert(iter < MAX_ITERATIONS);
+#if 0
+            if (iter > MAX_ITERATIONS) {
+                DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
+                ehci_set_state(ehci, async, EST_ACTIVE);
+                break;
+            }
+#endif
+        }
+        switch(ehci_get_state(ehci, async)) {
+        case EST_WAITLISTHEAD:
+            again = ehci_state_waitlisthead(ehci, async);
+            break;
+
+        case EST_FETCHENTRY:
+            again = ehci_state_fetchentry(ehci, async);
+            break;
+
+        case EST_FETCHQH:
+            q = ehci_state_fetchqh(ehci, async);
+            again = q ? 1 : 0;
+            break;
+
+        case EST_FETCHITD:
+            again = ehci_state_fetchitd(ehci, async);
+            break;
+
+        case EST_ADVANCEQUEUE:
+            again = ehci_state_advqueue(q, async);
+            break;
+
+        case EST_FETCHQTD:
+            again = ehci_state_fetchqtd(q, async);
+            break;
+
+        case EST_HORIZONTALQH:
+            again = ehci_state_horizqh(q, async);
+            break;
+
+        case EST_EXECUTE:
+            iter = 0;
+            again = ehci_state_execute(q, async);
+            break;
+
+        case EST_EXECUTING:
+            assert(q != NULL);
+            again = ehci_state_executing(q, async);
+            break;
+
+        case EST_WRITEBACK:
+            again = ehci_state_writeback(q, async);
+            break;
+
+        default:
+            fprintf(stderr, "Bad state!\n");
+            again = -1;
+            assert(0);
+            break;
+        }
+
+        if (again < 0) {
+            fprintf(stderr, "processing error - resetting ehci HC\n");
+            ehci_reset(ehci);
+            again = 0;
+            assert(0);
+        }
+    }
+    while (again);
+
+    ehci_commit_interrupt(ehci);
+}
+
+static void ehci_advance_async_state(EHCIState *ehci)
+{
+    int async = 1;
+
+    switch(ehci_get_state(ehci, async)) {
+    case EST_INACTIVE:
+        if (!(ehci->usbcmd & USBCMD_ASE)) {
+            break;
+        }
+        ehci_set_usbsts(ehci, USBSTS_ASS);
+        ehci_set_state(ehci, async, EST_ACTIVE);
+        // No break, fall through to ACTIVE
+
+    case EST_ACTIVE:
+        if ( !(ehci->usbcmd & USBCMD_ASE)) {
+            ehci_clear_usbsts(ehci, USBSTS_ASS);
+            ehci_set_state(ehci, async, EST_INACTIVE);
+            break;
+        }
+
+        /* If the doorbell is set, the guest wants to make a change to the
+         * schedule. The host controller needs to release cached data.
+         * (section 4.8.2)
+         */
+        if (ehci->usbcmd & USBCMD_IAAD) {
+            DPRINTF("ASYNC: doorbell request acknowledged\n");
+            ehci->usbcmd &= ~USBCMD_IAAD;
+            ehci_set_interrupt(ehci, USBSTS_IAA);
+            break;
+        }
+
+        /* make sure guest has acknowledged */
+        /* TO-DO: is this really needed? */
+        if (ehci->usbsts & USBSTS_IAA) {
+            DPRINTF("IAA status bit still set.\n");
+            break;
+        }
+
+        /* check that address register has been set */
+        if (ehci->asynclistaddr == 0) {
+            break;
+        }
+
+        ehci_set_state(ehci, async, EST_WAITLISTHEAD);
+        ehci_advance_state(ehci, async);
+        break;
+
+    default:
+        /* this should only be due to a developer mistake */
+        fprintf(stderr, "ehci: Bad asynchronous state %d. "
+                "Resetting to active\n", ehci->astate);
+        assert(0);
+    }
+}
+
+static void ehci_advance_periodic_state(EHCIState *ehci)
+{
+    uint32_t entry;
+    uint32_t list;
+    int async = 0;
+
+    // 4.6
+
+    switch(ehci_get_state(ehci, async)) {
+    case EST_INACTIVE:
+        if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
+            ehci_set_usbsts(ehci, USBSTS_PSS);
+            ehci_set_state(ehci, async, EST_ACTIVE);
+            // No break, fall through to ACTIVE
+        } else
+            break;
+
+    case EST_ACTIVE:
+        if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
+            ehci_clear_usbsts(ehci, USBSTS_PSS);
+            ehci_set_state(ehci, async, EST_INACTIVE);
+            break;
+        }
+
+        list = ehci->periodiclistbase & 0xfffff000;
+        /* check that register has been set */
+        if (list == 0) {
+            break;
+        }
+        list |= ((ehci->frindex & 0x1ff8) >> 1);
+
+        cpu_physical_memory_rw(list, (uint8_t *) &entry, sizeof entry, 0);
+        entry = le32_to_cpu(entry);
+
+        DPRINTF("PERIODIC state adv fr=%d.  [%08X] -> %08X\n",
+                ehci->frindex / 8, list, entry);
+        ehci_set_fetch_addr(ehci, async,entry);
+        ehci_set_state(ehci, async, EST_FETCHENTRY);
+        ehci_advance_state(ehci, async);
+        break;
+
+    default:
+        /* this should only be due to a developer mistake */
+        fprintf(stderr, "ehci: Bad periodic state %d. "
+                "Resetting to active\n", ehci->pstate);
+        assert(0);
+    }
+}
+
+static void ehci_frame_timer(void *opaque)
+{
+    EHCIState *ehci = opaque;
+    int64_t expire_time, t_now;
+    uint64_t ns_elapsed;
+    int frames;
+    int i;
+    int skipped_frames = 0;
+
+    t_now = qemu_get_clock_ns(vm_clock);
+    expire_time = t_now + (get_ticks_per_sec() / ehci->freq);
+
+    ns_elapsed = t_now - ehci->last_run_ns;
+    frames = ns_elapsed / FRAME_TIMER_NS;
+
+    for (i = 0; i < frames; i++) {
+        if ( !(ehci->usbsts & USBSTS_HALT)) {
+            if (ehci->isoch_pause <= 0) {
+                ehci->frindex += 8;
+            }
+
+            if (ehci->frindex > 0x00001fff) {
+                ehci->frindex = 0;
+                ehci_set_interrupt(ehci, USBSTS_FLR);
+            }
+
+            ehci->sofv = (ehci->frindex - 1) >> 3;
+            ehci->sofv &= 0x000003ff;
+        }
+
+        if (frames - i > ehci->maxframes) {
+            skipped_frames++;
+        } else {
+            ehci_advance_periodic_state(ehci);
+        }
+
+        ehci->last_run_ns += FRAME_TIMER_NS;
+    }
+
+#if 0
+    if (skipped_frames) {
+        DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames);
+    }
+#endif
+
+    /*  Async is not inside loop since it executes everything it can once
+     *  called
+     */
+    ehci_advance_async_state(ehci);
+
+    qemu_mod_timer(ehci->frame_timer, expire_time);
+}
+
+static CPUReadMemoryFunc *ehci_readfn[3]={
+    ehci_mem_readb,
+    ehci_mem_readw,
+    ehci_mem_readl
+};
+
+static CPUWriteMemoryFunc *ehci_writefn[3]={
+    ehci_mem_writeb,
+    ehci_mem_writew,
+    ehci_mem_writel
+};
+
+static void ehci_map(PCIDevice *pci_dev, int region_num,
+                     pcibus_t addr, pcibus_t size, int type)
+{
+    EHCIState *s =(EHCIState *)pci_dev;
+
+    DPRINTF("ehci_map: region %d, addr %08" PRIx64 ", size %" PRId64 ", s->mem %08X\n",
+            region_num, addr, size, s->mem);
+    s->mem_base = addr;
+    cpu_register_physical_memory(addr, size, s->mem);
+}
+
+static int usb_ehci_initfn(PCIDevice *dev);
+
+static USBPortOps ehci_port_ops = {
+    .attach = ehci_attach,
+    .detach = ehci_detach,
+    .child_detach = ehci_child_detach,
+    .wakeup = ehci_wakeup,
+    .complete = ehci_async_complete_packet,
+};
+
+static USBBusOps ehci_bus_ops = {
+    .register_companion = ehci_register_companion,
+};
+
+static Property ehci_properties[] = {
+    DEFINE_PROP_UINT32("freq",      EHCIState, freq, FRAME_TIMER_FREQ),
+    DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static PCIDeviceInfo ehci_info[] = {
+    {
+        .qdev.name    = "usb-ehci",
+        .qdev.size    = sizeof(EHCIState),
+        .init         = usb_ehci_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
+        .revision     = 0x10,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = ehci_properties,
+    },{
+        .qdev.name    = "ich9-usb-ehci1",
+        .qdev.size    = sizeof(EHCIState),
+        .init         = usb_ehci_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = ehci_properties,
+    },{
+        /* end of list */
+    }
+};
+
+static int usb_ehci_initfn(PCIDevice *dev)
+{
+    EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+    int i;
+
+    pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+    /* capabilities pointer */
+    pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+    //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
+
+    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3
+    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+    // pci_conf[0x50] = 0x01; // power management caps
+
+    pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
+    pci_set_byte(&pci_conf[0x61], 0x20);  // frame length adjustment (2.1.5)
+    pci_set_word(&pci_conf[0x62], 0x00);  // port wake up capability (2.1.6)
+
+    pci_conf[0x64] = 0x00;
+    pci_conf[0x65] = 0x00;
+    pci_conf[0x66] = 0x00;
+    pci_conf[0x67] = 0x00;
+    pci_conf[0x68] = 0x01;
+    pci_conf[0x69] = 0x00;
+    pci_conf[0x6a] = 0x00;
+    pci_conf[0x6b] = 0x00;  // USBLEGSUP
+    pci_conf[0x6c] = 0x00;
+    pci_conf[0x6d] = 0x00;
+    pci_conf[0x6e] = 0x00;
+    pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS
+
+    // 2.2 host controller interface version
+    s->mmio[0x00] = (uint8_t) OPREGBASE;
+    s->mmio[0x01] = 0x00;
+    s->mmio[0x02] = 0x00;
+    s->mmio[0x03] = 0x01;        // HC version
+    s->mmio[0x04] = NB_PORTS;    // Number of downstream ports
+    s->mmio[0x05] = 0x00;        // No companion ports at present
+    s->mmio[0x06] = 0x00;
+    s->mmio[0x07] = 0x00;
+    s->mmio[0x08] = 0x80;        // We can cache whole frame, not 64-bit capable
+    s->mmio[0x09] = 0x68;        // EECP
+    s->mmio[0x0a] = 0x00;
+    s->mmio[0x0b] = 0x00;
+
+    s->irq = s->dev.irq[3];
+
+    usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
+    for(i = 0; i < NB_PORTS; i++) {
+        usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
+                          USB_SPEED_MASK_HIGH);
+        s->ports[i].dev = 0;
+    }
+
+    s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
+    QTAILQ_INIT(&s->queues);
+
+    qemu_register_reset(ehci_reset, s);
+
+    s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s,
+                                    DEVICE_LITTLE_ENDIAN);
+
+    pci_register_bar(&s->dev, 0, MMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                                                            ehci_map);
+
+    fprintf(stderr, "*** EHCI support is under development ***\n");
+
+    return 0;
+}
+
+static void ehci_register(void)
+{
+    pci_qdev_register_many(ehci_info);
+}
+device_init(ehci_register);
+
+/*
+ * vim: expandtab ts=4
+ */
diff --git a/qemu-0.15.x/hw/usb-hid.c b/qemu-0.15.x/hw/usb-hid.c
new file mode 100644
index 0000000..b812da2
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-hid.c
@@ -0,0 +1,1007 @@
+/*
+ * QEMU USB HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew at openedhand.com)
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "qemu-timer.h"
+
+/* HID interface requests */
+#define GET_REPORT   0xa101
+#define GET_IDLE     0xa102
+#define GET_PROTOCOL 0xa103
+#define SET_REPORT   0x2109
+#define SET_IDLE     0x210a
+#define SET_PROTOCOL 0x210b
+
+/* HID descriptor types */
+#define USB_DT_HID    0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHY    0x23
+
+#define USB_MOUSE     1
+#define USB_TABLET    2
+#define USB_KEYBOARD  3
+
+typedef struct USBPointerEvent {
+    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+    int32_t dz, buttons_state;
+} USBPointerEvent;
+
+#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_MASK      (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
+
+typedef struct USBMouseState {
+    USBPointerEvent queue[QUEUE_LENGTH];
+    int mouse_grabbed;
+    QEMUPutMouseEntry *eh_entry;
+} USBMouseState;
+
+typedef struct USBKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int32_t keys;
+} USBKeyboardState;
+
+typedef struct USBHIDState {
+    USBDevice dev;
+    union {
+        USBMouseState ptr;
+        USBKeyboardState kbd;
+    };
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
+    int kind;
+    int32_t protocol;
+    uint8_t idle;
+    int64_t next_idle_clock;
+    int changed;
+    void *datain_opaque;
+    void (*datain)(void *);
+} USBHIDState;
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT_MOUSE,
+    STR_PRODUCT_TABLET,
+    STR_PRODUCT_KEYBOARD,
+    STR_SERIALNUMBER,
+    STR_CONFIG_MOUSE,
+    STR_CONFIG_TABLET,
+    STR_CONFIG_KEYBOARD,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse",
+    [STR_PRODUCT_TABLET]   = "QEMU USB Tablet",
+    [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
+    [STR_SERIALNUMBER]     = "42", /* == remote wakeup works */
+    [STR_CONFIG_MOUSE]     = "HID Mouse",
+    [STR_CONFIG_TABLET]    = "HID Tablet",
+    [STR_CONFIG_KEYBOARD]  = "HID Keyboard",
+};
+
+static const USBDescIface desc_iface_mouse = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HID,
+    .bInterfaceSubClass            = 0x01, /* boot */
+    .bInterfaceProtocol            = 0x02,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* HID descriptor */
+            .data = (uint8_t[]) {
+                0x09,          /*  u8  bLength */
+                USB_DT_HID,    /*  u8  bDescriptorType */
+                0x01, 0x00,    /*  u16 HID_class */
+                0x00,          /*  u8  country_code */
+                0x01,          /*  u8  num_descriptors */
+                USB_DT_REPORT, /*  u8  type: Report */
+                52, 0,         /*  u16 len */
+            },
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 4,
+            .bInterval             = 0x0a,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_tablet = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HID,
+    .bInterfaceProtocol            = 0x02,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* HID descriptor */
+            .data = (uint8_t[]) {
+                0x09,          /*  u8  bLength */
+                USB_DT_HID,    /*  u8  bDescriptorType */
+                0x01, 0x00,    /*  u16 HID_class */
+                0x00,          /*  u8  country_code */
+                0x01,          /*  u8  num_descriptors */
+                USB_DT_REPORT, /*  u8  type: Report */
+                74, 0,         /*  u16 len */
+            },
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_keyboard = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HID,
+    .bInterfaceSubClass            = 0x01, /* boot */
+    .bInterfaceProtocol            = 0x01, /* keyboard */
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* HID descriptor */
+            .data = (uint8_t[]) {
+                0x09,          /*  u8  bLength */
+                USB_DT_HID,    /*  u8  bDescriptorType */
+                0x11, 0x01,    /*  u16 HID_class */
+                0x00,          /*  u8  country_code */
+                0x01,          /*  u8  num_descriptors */
+                USB_DT_REPORT, /*  u8  type: Report */
+                0x3f, 0,       /*  u16 len */
+            },
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_mouse = {
+    .bcdUSB                        = 0x0100,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_MOUSE,
+            .bmAttributes          = 0xa0,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface_mouse,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_tablet = {
+    .bcdUSB                        = 0x0100,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_TABLET,
+            .bmAttributes          = 0xa0,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface_tablet,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_keyboard = {
+    .bcdUSB                        = 0x0100,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_KEYBOARD,
+            .bmAttributes          = 0xa0,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface_keyboard,
+        },
+    },
+};
+
+static const USBDesc desc_mouse = {
+    .id = {
+        .idVendor          = 0x0627,
+        .idProduct         = 0x0001,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_MOUSE,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_mouse,
+    .str  = desc_strings,
+};
+
+static const USBDesc desc_tablet = {
+    .id = {
+        .idVendor          = 0x0627,
+        .idProduct         = 0x0001,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_TABLET,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_tablet,
+    .str  = desc_strings,
+};
+
+static const USBDesc desc_keyboard = {
+    .id = {
+        .idVendor          = 0x0627,
+        .idProduct         = 0x0001,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_KEYBOARD,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_keyboard,
+    .str  = desc_strings,
+};
+
+static const uint8_t qemu_mouse_hid_report_descriptor[] = {
+    0x05, 0x01,		/* Usage Page (Generic Desktop) */
+    0x09, 0x02,		/* Usage (Mouse) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x09, 0x01,		/*   Usage (Pointer) */
+    0xa1, 0x00,		/*   Collection (Physical) */
+    0x05, 0x09,		/*     Usage Page (Button) */
+    0x19, 0x01,		/*     Usage Minimum (1) */
+    0x29, 0x03,		/*     Usage Maximum (3) */
+    0x15, 0x00,		/*     Logical Minimum (0) */
+    0x25, 0x01,		/*     Logical Maximum (1) */
+    0x95, 0x03,		/*     Report Count (3) */
+    0x75, 0x01,		/*     Report Size (1) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0x95, 0x01,		/*     Report Count (1) */
+    0x75, 0x05,		/*     Report Size (5) */
+    0x81, 0x01,		/*     Input (Constant) */
+    0x05, 0x01,		/*     Usage Page (Generic Desktop) */
+    0x09, 0x30,		/*     Usage (X) */
+    0x09, 0x31,		/*     Usage (Y) */
+    0x09, 0x38,		/*     Usage (Wheel) */
+    0x15, 0x81,		/*     Logical Minimum (-0x7f) */
+    0x25, 0x7f,		/*     Logical Maximum (0x7f) */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x03,		/*     Report Count (3) */
+    0x81, 0x06,		/*     Input (Data, Variable, Relative) */
+    0xc0,		/*   End Collection */
+    0xc0,		/* End Collection */
+};
+
+static const uint8_t qemu_tablet_hid_report_descriptor[] = {
+    0x05, 0x01,		/* Usage Page (Generic Desktop) */
+    0x09, 0x01,		/* Usage (Pointer) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x09, 0x01,		/*   Usage (Pointer) */
+    0xa1, 0x00,		/*   Collection (Physical) */
+    0x05, 0x09,		/*     Usage Page (Button) */
+    0x19, 0x01,		/*     Usage Minimum (1) */
+    0x29, 0x03,		/*     Usage Maximum (3) */
+    0x15, 0x00,		/*     Logical Minimum (0) */
+    0x25, 0x01,		/*     Logical Maximum (1) */
+    0x95, 0x03,		/*     Report Count (3) */
+    0x75, 0x01,		/*     Report Size (1) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0x95, 0x01,		/*     Report Count (1) */
+    0x75, 0x05,		/*     Report Size (5) */
+    0x81, 0x01,		/*     Input (Constant) */
+    0x05, 0x01,		/*     Usage Page (Generic Desktop) */
+    0x09, 0x30,		/*     Usage (X) */
+    0x09, 0x31,		/*     Usage (Y) */
+    0x15, 0x00,		/*     Logical Minimum (0) */
+    0x26, 0xff, 0x7f,	/*     Logical Maximum (0x7fff) */
+    0x35, 0x00,		/*     Physical Minimum (0) */
+    0x46, 0xff, 0x7f,	/*     Physical Maximum (0x7fff) */
+    0x75, 0x10,		/*     Report Size (16) */
+    0x95, 0x02,		/*     Report Count (2) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0x05, 0x01,		/*     Usage Page (Generic Desktop) */
+    0x09, 0x38,		/*     Usage (Wheel) */
+    0x15, 0x81,		/*     Logical Minimum (-0x7f) */
+    0x25, 0x7f,		/*     Logical Maximum (0x7f) */
+    0x35, 0x00,		/*     Physical Minimum (same as logical) */
+    0x45, 0x00,		/*     Physical Maximum (same as logical) */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x01,		/*     Report Count (1) */
+    0x81, 0x06,		/*     Input (Data, Variable, Relative) */
+    0xc0,		/*   End Collection */
+    0xc0,		/* End Collection */
+};
+
+static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
+    0x05, 0x01,		/* Usage Page (Generic Desktop) */
+    0x09, 0x06,		/* Usage (Keyboard) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x75, 0x01,		/*   Report Size (1) */
+    0x95, 0x08,		/*   Report Count (8) */
+    0x05, 0x07,		/*   Usage Page (Key Codes) */
+    0x19, 0xe0,		/*   Usage Minimum (224) */
+    0x29, 0xe7,		/*   Usage Maximum (231) */
+    0x15, 0x00,		/*   Logical Minimum (0) */
+    0x25, 0x01,		/*   Logical Maximum (1) */
+    0x81, 0x02,		/*   Input (Data, Variable, Absolute) */
+    0x95, 0x01,		/*   Report Count (1) */
+    0x75, 0x08,		/*   Report Size (8) */
+    0x81, 0x01,		/*   Input (Constant) */
+    0x95, 0x05,		/*   Report Count (5) */
+    0x75, 0x01,		/*   Report Size (1) */
+    0x05, 0x08,		/*   Usage Page (LEDs) */
+    0x19, 0x01,		/*   Usage Minimum (1) */
+    0x29, 0x05,		/*   Usage Maximum (5) */
+    0x91, 0x02,		/*   Output (Data, Variable, Absolute) */
+    0x95, 0x01,		/*   Report Count (1) */
+    0x75, 0x03,		/*   Report Size (3) */
+    0x91, 0x01,		/*   Output (Constant) */
+    0x95, 0x06,		/*   Report Count (6) */
+    0x75, 0x08,		/*   Report Size (8) */
+    0x15, 0x00,		/*   Logical Minimum (0) */
+    0x25, 0xff,		/*   Logical Maximum (255) */
+    0x05, 0x07,		/*   Usage Page (Key Codes) */
+    0x19, 0x00,		/*   Usage Minimum (0) */
+    0x29, 0xff,		/*   Usage Maximum (255) */
+    0x81, 0x00,		/*   Input (Data, Array) */
+    0xc0,		/* End Collection */
+};
+
+#define USB_HID_USAGE_ERROR_ROLLOVER	0x01
+#define USB_HID_USAGE_POSTFAIL		0x02
+#define USB_HID_USAGE_ERROR_UNDEFINED	0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t usb_hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static void usb_hid_changed(USBHIDState *hs)
+{
+    hs->changed = 1;
+
+    if (hs->datain)
+        hs->datain(hs->datain_opaque);
+
+    usb_wakeup(&hs->dev);
+}
+
+static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
+    e->xdx = e->ydy = e->dz = 0;
+    e->buttons_state = buttons;
+}
+
+static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
+                                      int x1, int y1, int z1) {
+    if (xyrel) {
+        e->xdx += x1;
+        e->ydy += y1;
+    } else {
+        e->xdx = x1;
+        e->ydy = y1;
+    }
+    e->dz += z1;
+}
+
+static void usb_pointer_event(void *opaque,
+                              int x1, int y1, int z1, int buttons_state)
+{
+    USBHIDState *hs = opaque;
+    USBMouseState *s = &hs->ptr;
+    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+    /* We combine events where feasible to keep the queue small.  We shouldn't
+     * combine anything with the first event of a particular button state, as
+     * that would change the location of the button state change.  When the
+     * queue is empty, a second event is needed because we don't know if
+     * the first event changed the button state.  */
+    if (hs->n == QUEUE_LENGTH) {
+        /* Queue full.  Discard old button state, combine motion normally.  */
+        s->queue[use_slot].buttons_state = buttons_state;
+    } else if (hs->n < 2 ||
+               s->queue[use_slot].buttons_state != buttons_state ||
+               s->queue[previous_slot].buttons_state != s->queue[use_slot].buttons_state) {
+        /* Cannot or should not combine, so add an empty item to the queue.  */
+        QUEUE_INCR(use_slot);
+        hs->n++;
+        usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+    }
+    usb_pointer_event_combine(&s->queue[use_slot],
+                              hs->kind == USB_MOUSE,
+                              x1, y1, z1);
+    usb_hid_changed(hs);
+}
+
+static void usb_keyboard_event(void *opaque, int keycode)
+{
+    USBHIDState *hs = opaque;
+    USBKeyboardState *s = &hs->kbd;
+    int slot;
+
+    if (hs->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+    s->keycodes[slot] = keycode;
+    usb_hid_changed(hs);
+}
+
+static void usb_keyboard_process_keycode(USBHIDState *hs)
+{
+    USBKeyboardState *s = &hs->kbd;
+    uint8_t hid_code, key;
+    int i, keycode, slot;
+
+    if (hs->n == 0) {
+        return;
+    }
+    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+    keycode = s->keycodes[slot];
+
+    key = keycode & 0x7f;
+    hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
+    s->modifiers &= ~(1 << 8);
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (s->modifiers & (1 << 9)) {
+            s->modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            s->modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        s->modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = s->keys - 1; i >= 0; i --)
+            if (s->key[i] == hid_code) {
+                s->key[i] = s->key[-- s->keys];
+                s->key[s->keys] = 0x00;
+                break;
+            }
+        if (i < 0)
+            return;
+    } else {
+        for (i = s->keys - 1; i >= 0; i --)
+            if (s->key[i] == hid_code)
+                break;
+        if (i < 0) {
+            if (s->keys < sizeof(s->key))
+                s->key[s->keys ++] = hid_code;
+        } else
+            return;
+    }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin)
+        return vmin;
+    else if (val > vmax)
+        return vmax;
+    else
+        return val;
+}
+
+static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+    int index;
+    USBMouseState *s = &hs->ptr;
+    USBPointerEvent *e;
+
+    if (!s->mouse_grabbed) {
+        qemu_activate_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 1;
+    }
+
+    /* When the buffer is empty, return the last event.  Relative
+       movements will all be zero.  */
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &s->queue[index & QUEUE_MASK];
+
+    if (hs->kind == USB_MOUSE) {
+        dx = int_clamp(e->xdx, -127, 127);
+        dy = int_clamp(e->ydy, -127, 127);
+        e->xdx -= dx;
+        e->ydy -= dy;
+    } else {
+        dx = e->xdx;
+        dy = e->ydy;
+    }
+    dz = int_clamp(e->dz, -127, 127);
+    e->dz -= dz;
+
+    b = 0;
+    if (e->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (e->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (e->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    if (hs->n &&
+        !e->dz &&
+        (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
+        /* that deals with this event */
+        QUEUE_INCR(hs->head);
+        hs->n--;
+    }
+
+    /* Appears we have to invert the wheel direction */
+    dz = 0 - dz;
+    l = 0;
+    switch (hs->kind) {
+    case USB_MOUSE:
+        if (len > l)
+            buf[l++] = b;
+        if (len > l)
+            buf[l++] = dx;
+        if (len > l)
+            buf[l++] = dy;
+        if (len > l)
+            buf[l++] = dz;
+        break;
+
+    case USB_TABLET:
+        if (len > l)
+            buf[l++] = b;
+        if (len > l)
+            buf[l++] = dx & 0xff;
+        if (len > l)
+            buf[l++] = dx >> 8;
+        if (len > l)
+            buf[l++] = dy & 0xff;
+        if (len > l)
+            buf[l++] = dy >> 8;
+        if (len > l)
+            buf[l++] = dz;
+        break;
+
+    default:
+        abort();
+    }
+
+    return l;
+}
+
+static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
+{
+    USBKeyboardState *s = &hs->kbd;
+    if (len < 2)
+        return 0;
+
+    usb_keyboard_process_keycode(hs);
+
+    buf[0] = s->modifiers & 0xff;
+    buf[1] = 0;
+    if (s->keys > 6)
+        memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    else
+        memcpy(buf + 2, s->key, MIN(8, len) - 2);
+
+    return MIN(8, len);
+}
+
+static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        int ledstate = 0;
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        s->leds = buf[0];
+        if (s->leds & 0x04)
+            ledstate |= QEMU_SCROLL_LOCK_LED;
+        if (s->leds & 0x01)
+            ledstate |= QEMU_NUM_LOCK_LED;
+        if (s->leds & 0x02)
+            ledstate |= QEMU_CAPS_LOCK_LED;
+        kbd_put_ledstate(ledstate);
+    }
+    return 0;
+}
+
+static void usb_mouse_handle_reset(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
+    s->head = 0;
+    s->n = 0;
+    s->protocol = 1;
+}
+
+static void usb_keyboard_handle_reset(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    qemu_add_kbd_event_handler(usb_keyboard_event, s);
+    memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
+    s->head = 0;
+    s->n = 0;
+    memset(s->kbd.key, 0, sizeof (s->kbd.key));
+    s->kbd.keys = 0;
+    s->protocol = 1;
+}
+
+static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
+{
+    s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
+}
+
+static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ret = 0;
+    switch(request) {
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+        /* hid specific requests */
+    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch(value >> 8) {
+        case 0x22:
+	    if (s->kind == USB_MOUSE) {
+		memcpy(data, qemu_mouse_hid_report_descriptor,
+		       sizeof(qemu_mouse_hid_report_descriptor));
+		ret = sizeof(qemu_mouse_hid_report_descriptor);
+	    } else if (s->kind == USB_TABLET) {
+		memcpy(data, qemu_tablet_hid_report_descriptor,
+		       sizeof(qemu_tablet_hid_report_descriptor));
+		ret = sizeof(qemu_tablet_hid_report_descriptor);
+            } else if (s->kind == USB_KEYBOARD) {
+                memcpy(data, qemu_keyboard_hid_report_descriptor,
+                       sizeof(qemu_keyboard_hid_report_descriptor));
+                ret = sizeof(qemu_keyboard_hid_report_descriptor);
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case GET_REPORT:
+        if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
+            ret = usb_pointer_poll(s, data, length);
+        } else if (s->kind == USB_KEYBOARD) {
+            ret = usb_keyboard_poll(s, data, length);
+        }
+        s->changed = s->n > 0;
+        break;
+    case SET_REPORT:
+        if (s->kind == USB_KEYBOARD)
+            ret = usb_keyboard_write(&s->kbd, data, length);
+        else
+            goto fail;
+        break;
+    case GET_PROTOCOL:
+        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+            goto fail;
+        ret = 1;
+        data[0] = s->protocol;
+        break;
+    case SET_PROTOCOL:
+        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+            goto fail;
+        ret = 0;
+        s->protocol = value;
+        break;
+    case GET_IDLE:
+        ret = 1;
+        data[0] = s->idle;
+        break;
+    case SET_IDLE:
+        s->idle = (uint8_t) (value >> 8);
+        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+        ret = 0;
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+    int ret = 0;
+
+    switch(p->pid) {
+    case USB_TOKEN_IN:
+        if (p->devep == 1) {
+            int64_t curtime = qemu_get_clock_ns(vm_clock);
+            if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
+                return USB_RET_NAK;
+            usb_hid_set_next_idle(s, curtime);
+            if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
+                ret = usb_pointer_poll(s, p->data, p->len);
+            }
+            else if (s->kind == USB_KEYBOARD) {
+                ret = usb_keyboard_poll(s, p->data, p->len);
+            }
+            s->changed = s->n > 0;
+        } else {
+            goto fail;
+        }
+        break;
+    case USB_TOKEN_OUT:
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_hid_handle_destroy(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    switch(s->kind) {
+    case USB_KEYBOARD:
+        qemu_remove_kbd_event_handler();
+        break;
+    default:
+        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+    }
+}
+
+static int usb_hid_initfn(USBDevice *dev, int kind)
+{
+    USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
+
+    usb_desc_init(dev);
+    s->kind = kind;
+
+    if (s->kind == USB_MOUSE) {
+        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
+                                                       0, "QEMU USB Mouse");
+    } else if (s->kind == USB_TABLET) {
+        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
+                                                       1, "QEMU USB Tablet");
+    }
+
+    /* Force poll routine to be run and grab input the first time.  */
+    s->changed = 1;
+    return 0;
+}
+
+static int usb_tablet_initfn(USBDevice *dev)
+{
+    return usb_hid_initfn(dev, USB_TABLET);
+}
+
+static int usb_mouse_initfn(USBDevice *dev)
+{
+    return usb_hid_initfn(dev, USB_MOUSE);
+}
+
+static int usb_keyboard_initfn(USBDevice *dev)
+{
+    return usb_hid_initfn(dev, USB_KEYBOARD);
+}
+
+void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    s->datain_opaque = opaque;
+    s->datain = datain;
+}
+
+static int usb_hid_post_load(void *opaque, int version_id)
+{
+    USBHIDState *s = opaque;
+
+    if (s->idle) {
+        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_usb_ptr_queue = {
+    .name = "usb-ptr-queue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32(xdx, USBPointerEvent),
+        VMSTATE_INT32(ydy, USBPointerEvent),
+        VMSTATE_INT32(dz, USBPointerEvent),
+        VMSTATE_INT32(buttons_state, USBPointerEvent),
+        VMSTATE_END_OF_LIST()
+    }
+};
+static const VMStateDescription vmstate_usb_ptr = {
+    .name = "usb-ptr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = usb_hid_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_USB_DEVICE(dev, USBHIDState),
+        VMSTATE_STRUCT_ARRAY(ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
+                             vmstate_usb_ptr_queue, USBPointerEvent),
+        VMSTATE_UINT32(head, USBHIDState),
+        VMSTATE_UINT32(n, USBHIDState),
+        VMSTATE_INT32(protocol, USBHIDState),
+        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_usb_kbd = {
+    .name = "usb-kbd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = usb_hid_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_USB_DEVICE(dev, USBHIDState),
+        VMSTATE_UINT32_ARRAY(kbd.keycodes, USBHIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(head, USBHIDState),
+        VMSTATE_UINT32(n, USBHIDState),
+        VMSTATE_UINT16(kbd.modifiers, USBHIDState),
+        VMSTATE_UINT8(kbd.leds, USBHIDState),
+        VMSTATE_UINT8_ARRAY(kbd.key, USBHIDState, 16),
+        VMSTATE_INT32(kbd.keys, USBHIDState),
+        VMSTATE_INT32(protocol, USBHIDState),
+        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static struct USBDeviceInfo hid_info[] = {
+    {
+        .product_desc   = "QEMU USB Tablet",
+        .qdev.name      = "usb-tablet",
+        .usbdevice_name = "tablet",
+        .qdev.size      = sizeof(USBHIDState),
+        .qdev.vmsd      = &vmstate_usb_ptr,
+        .usb_desc       = &desc_tablet,
+        .init           = usb_tablet_initfn,
+        .handle_packet  = usb_generic_handle_packet,
+        .handle_reset   = usb_mouse_handle_reset,
+        .handle_control = usb_hid_handle_control,
+        .handle_data    = usb_hid_handle_data,
+        .handle_destroy = usb_hid_handle_destroy,
+    },{
+        .product_desc   = "QEMU USB Mouse",
+        .qdev.name      = "usb-mouse",
+        .usbdevice_name = "mouse",
+        .qdev.size      = sizeof(USBHIDState),
+        .qdev.vmsd      = &vmstate_usb_ptr,
+        .usb_desc       = &desc_mouse,
+        .init           = usb_mouse_initfn,
+        .handle_packet  = usb_generic_handle_packet,
+        .handle_reset   = usb_mouse_handle_reset,
+        .handle_control = usb_hid_handle_control,
+        .handle_data    = usb_hid_handle_data,
+        .handle_destroy = usb_hid_handle_destroy,
+    },{
+        .product_desc   = "QEMU USB Keyboard",
+        .qdev.name      = "usb-kbd",
+        .usbdevice_name = "keyboard",
+        .qdev.size      = sizeof(USBHIDState),
+        .qdev.vmsd      = &vmstate_usb_kbd,
+        .usb_desc       = &desc_keyboard,
+        .init           = usb_keyboard_initfn,
+        .handle_packet  = usb_generic_handle_packet,
+        .handle_reset   = usb_keyboard_handle_reset,
+        .handle_control = usb_hid_handle_control,
+        .handle_data    = usb_hid_handle_data,
+        .handle_destroy = usb_hid_handle_destroy,
+    },{
+        /* end of list */
+    }
+};
+
+static void usb_hid_register_devices(void)
+{
+    usb_qdev_register_many(hid_info);
+}
+device_init(usb_hid_register_devices)
diff --git a/qemu-0.15.x/hw/usb-hub.c b/qemu-0.15.x/hw/usb-hub.c
new file mode 100644
index 0000000..b49a2fe
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-hub.c
@@ -0,0 +1,549 @@
+/*
+ * QEMU USB HUB emulation
+ *
+ * Copyright (c) 2005 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 "qemu-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+
+//#define DEBUG
+
+#define NUM_PORTS 8
+
+typedef struct USBHubPort {
+    USBPort port;
+    uint16_t wPortStatus;
+    uint16_t wPortChange;
+} USBHubPort;
+
+typedef struct USBHubState {
+    USBDevice dev;
+    USBHubPort ports[NUM_PORTS];
+} USBHubState;
+
+#define ClearHubFeature		(0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature	(0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor	(0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus		(0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus		(0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature		(0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature		(0x2300 | USB_REQ_SET_FEATURE)
+
+#define PORT_STAT_CONNECTION	0x0001
+#define PORT_STAT_ENABLE	0x0002
+#define PORT_STAT_SUSPEND	0x0004
+#define PORT_STAT_OVERCURRENT	0x0008
+#define PORT_STAT_RESET		0x0010
+#define PORT_STAT_POWER		0x0100
+#define PORT_STAT_LOW_SPEED	0x0200
+#define PORT_STAT_HIGH_SPEED    0x0400
+#define PORT_STAT_TEST          0x0800
+#define PORT_STAT_INDICATOR     0x1000
+
+#define PORT_STAT_C_CONNECTION	0x0001
+#define PORT_STAT_C_ENABLE	0x0002
+#define PORT_STAT_C_SUSPEND	0x0004
+#define PORT_STAT_C_OVERCURRENT	0x0008
+#define PORT_STAT_C_RESET	0x0010
+
+#define PORT_CONNECTION	        0
+#define PORT_ENABLE		1
+#define PORT_SUSPEND		2
+#define PORT_OVERCURRENT	3
+#define PORT_RESET		4
+#define PORT_POWER		8
+#define PORT_LOWSPEED		9
+#define PORT_HIGHSPEED		10
+#define PORT_C_CONNECTION	16
+#define PORT_C_ENABLE		17
+#define PORT_C_SUSPEND		18
+#define PORT_C_OVERCURRENT	19
+#define PORT_C_RESET		20
+#define PORT_TEST               21
+#define PORT_INDICATOR          22
+
+/* same as Linux kernel root hubs */
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]      = "QEMU USB Hub",
+    [STR_SERIALNUMBER] = "314159",
+};
+
+static const USBDescIface desc_iface_hub = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HUB,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 1 + (NUM_PORTS + 7) / 8,
+            .bInterval             = 0xff,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_hub = {
+    .bcdUSB                        = 0x0110,
+    .bDeviceClass                  = USB_CLASS_HUB,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0xe0,
+            .nif = 1,
+            .ifs = &desc_iface_hub,
+        },
+    },
+};
+
+static const USBDesc desc_hub = {
+    .id = {
+        .idVendor          = 0,
+        .idProduct         = 0,
+        .bcdDevice         = 0x0101,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_hub,
+    .str  = desc_strings,
+};
+
+static const uint8_t qemu_hub_hub_descriptor[] =
+{
+	0x00,			/*  u8  bLength; patched in later */
+	0x29,			/*  u8  bDescriptorType; Hub-descriptor */
+	0x00,			/*  u8  bNbrPorts; (patched later) */
+	0x0a,			/* u16  wHubCharacteristics; */
+	0x00,			/*   (per-port OC, no power switching) */
+	0x01,			/*  u8  bPwrOn2pwrGood; 2ms */
+	0x00			/*  u8  bHubContrCurrent; 0 mA */
+
+        /* DeviceRemovable and PortPwrCtrlMask patched in later */
+};
+
+static void usb_hub_attach(USBPort *port1)
+{
+    USBHubState *s = port1->opaque;
+    USBHubPort *port = &s->ports[port1->index];
+
+    port->wPortStatus |= PORT_STAT_CONNECTION;
+    port->wPortChange |= PORT_STAT_C_CONNECTION;
+    if (port->port.dev->speed == USB_SPEED_LOW) {
+        port->wPortStatus |= PORT_STAT_LOW_SPEED;
+    } else {
+        port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
+    }
+}
+
+static void usb_hub_detach(USBPort *port1)
+{
+    USBHubState *s = port1->opaque;
+    USBHubPort *port = &s->ports[port1->index];
+
+    /* Let upstream know the device on this port is gone */
+    s->dev.port->ops->child_detach(s->dev.port, port1->dev);
+
+    port->wPortStatus &= ~PORT_STAT_CONNECTION;
+    port->wPortChange |= PORT_STAT_C_CONNECTION;
+    if (port->wPortStatus & PORT_STAT_ENABLE) {
+        port->wPortStatus &= ~PORT_STAT_ENABLE;
+        port->wPortChange |= PORT_STAT_C_ENABLE;
+    }
+}
+
+static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
+{
+    USBHubState *s = port1->opaque;
+
+    /* Pass along upstream */
+    s->dev.port->ops->child_detach(s->dev.port, child);
+}
+
+static void usb_hub_wakeup(USBPort *port1)
+{
+    USBHubState *s = port1->opaque;
+    USBHubPort *port = &s->ports[port1->index];
+
+    if (port->wPortStatus & PORT_STAT_SUSPEND) {
+        port->wPortChange |= PORT_STAT_C_SUSPEND;
+        usb_wakeup(&s->dev);
+    }
+}
+
+static void usb_hub_complete(USBPort *port, USBPacket *packet)
+{
+    USBHubState *s = port->opaque;
+
+    /*
+     * Just pass it along upstream for now.
+     *
+     * If we ever inplement usb 2.0 split transactions this will
+     * become a little more complicated ...
+     */
+    usb_packet_complete(&s->dev, packet);
+}
+
+static void usb_hub_handle_attach(USBDevice *dev)
+{
+    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+    int i;
+
+    for (i = 0; i < NUM_PORTS; i++) {
+        usb_port_location(&s->ports[i].port, dev->port, i+1);
+    }
+}
+
+static void usb_hub_handle_reset(USBDevice *dev)
+{
+    /* XXX: do it */
+}
+
+static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBHubState *s = (USBHubState *)dev;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    switch(request) {
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == 0 && index != 0x81) { /* clear ep halt */
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+        /* usb specific requests */
+    case GetHubStatus:
+        data[0] = 0;
+        data[1] = 0;
+        data[2] = 0;
+        data[3] = 0;
+        ret = 4;
+        break;
+    case GetPortStatus:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+            if (n >= NUM_PORTS) {
+                goto fail;
+            }
+            port = &s->ports[n];
+            data[0] = port->wPortStatus;
+            data[1] = port->wPortStatus >> 8;
+            data[2] = port->wPortChange;
+            data[3] = port->wPortChange >> 8;
+            ret = 4;
+        }
+        break;
+    case SetHubFeature:
+    case ClearHubFeature:
+        if (value == 0 || value == 1) {
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case SetPortFeature:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+            USBDevice *dev;
+            if (n >= NUM_PORTS) {
+                goto fail;
+            }
+            port = &s->ports[n];
+            dev = port->port.dev;
+            switch(value) {
+            case PORT_SUSPEND:
+                port->wPortStatus |= PORT_STAT_SUSPEND;
+                break;
+            case PORT_RESET:
+                if (dev) {
+                    usb_send_msg(dev, USB_MSG_RESET);
+                    port->wPortChange |= PORT_STAT_C_RESET;
+                    /* set enable bit */
+                    port->wPortStatus |= PORT_STAT_ENABLE;
+                }
+                break;
+            case PORT_POWER:
+                break;
+            default:
+                goto fail;
+            }
+            ret = 0;
+        }
+        break;
+    case ClearPortFeature:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+
+            if (n >= NUM_PORTS) {
+                goto fail;
+            }
+            port = &s->ports[n];
+            switch(value) {
+            case PORT_ENABLE:
+                port->wPortStatus &= ~PORT_STAT_ENABLE;
+                break;
+            case PORT_C_ENABLE:
+                port->wPortChange &= ~PORT_STAT_C_ENABLE;
+                break;
+            case PORT_SUSPEND:
+                port->wPortStatus &= ~PORT_STAT_SUSPEND;
+                break;
+            case PORT_C_SUSPEND:
+                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
+                break;
+            case PORT_C_CONNECTION:
+                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
+                break;
+            case PORT_C_OVERCURRENT:
+                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
+                break;
+            case PORT_C_RESET:
+                port->wPortChange &= ~PORT_STAT_C_RESET;
+                break;
+            default:
+                goto fail;
+            }
+            ret = 0;
+        }
+        break;
+    case GetHubDescriptor:
+        {
+            unsigned int n, limit, var_hub_size = 0;
+            memcpy(data, qemu_hub_hub_descriptor,
+                   sizeof(qemu_hub_hub_descriptor));
+            data[2] = NUM_PORTS;
+
+            /* fill DeviceRemovable bits */
+            limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
+            for (n = 7; n < limit; n++) {
+                data[n] = 0x00;
+                var_hub_size++;
+            }
+
+            /* fill PortPwrCtrlMask bits */
+            limit = limit + ((NUM_PORTS + 7) / 8);
+            for (;n < limit; n++) {
+                data[n] = 0xff;
+                var_hub_size++;
+            }
+
+            ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
+            data[0] = ret;
+            break;
+        }
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBHubState *s = (USBHubState *)dev;
+    int ret;
+
+    switch(p->pid) {
+    case USB_TOKEN_IN:
+        if (p->devep == 1) {
+            USBHubPort *port;
+            unsigned int status;
+            int i, n;
+            n = (NUM_PORTS + 1 + 7) / 8;
+            if (p->len == 1) { /* FreeBSD workaround */
+                n = 1;
+            } else if (n > p->len) {
+                return USB_RET_BABBLE;
+            }
+            status = 0;
+            for(i = 0; i < NUM_PORTS; i++) {
+                port = &s->ports[i];
+                if (port->wPortChange)
+                    status |= (1 << (i + 1));
+            }
+            if (status != 0) {
+                for(i = 0; i < n; i++) {
+                    p->data[i] = status >> (8 * i);
+                }
+                ret = n;
+            } else {
+                ret = USB_RET_NAK; /* usb11 11.13.1 */
+            }
+        } else {
+            goto fail;
+        }
+        break;
+    case USB_TOKEN_OUT:
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
+{
+    USBHubPort *port;
+    USBDevice *dev;
+    int i, ret;
+
+    for(i = 0; i < NUM_PORTS; i++) {
+        port = &s->ports[i];
+        dev = port->port.dev;
+        if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
+            ret = usb_handle_packet(dev, p);
+            if (ret != USB_RET_NODEV) {
+                return ret;
+            }
+        }
+    }
+    return USB_RET_NODEV;
+}
+
+static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
+{
+    USBHubState *s = (USBHubState *)dev;
+
+#if defined(DEBUG) && 0
+    printf("usb_hub: pid=0x%x\n", pid);
+#endif
+    if (dev->state == USB_STATE_DEFAULT &&
+        dev->addr != 0 &&
+        p->devaddr != dev->addr &&
+        (p->pid == USB_TOKEN_SETUP ||
+         p->pid == USB_TOKEN_OUT ||
+         p->pid == USB_TOKEN_IN)) {
+        /* broadcast the packet to the devices */
+        return usb_hub_broadcast_packet(s, p);
+    }
+    return usb_generic_handle_packet(dev, p);
+}
+
+static void usb_hub_handle_destroy(USBDevice *dev)
+{
+    USBHubState *s = (USBHubState *)dev;
+    int i;
+
+    for (i = 0; i < NUM_PORTS; i++) {
+        usb_unregister_port(usb_bus_from_device(dev),
+                            &s->ports[i].port);
+    }
+}
+
+static USBPortOps usb_hub_port_ops = {
+    .attach = usb_hub_attach,
+    .detach = usb_hub_detach,
+    .child_detach = usb_hub_child_detach,
+    .wakeup = usb_hub_wakeup,
+    .complete = usb_hub_complete,
+};
+
+static int usb_hub_initfn(USBDevice *dev)
+{
+    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+    USBHubPort *port;
+    int i;
+
+    usb_desc_init(dev);
+    for (i = 0; i < NUM_PORTS; i++) {
+        port = &s->ports[i];
+        usb_register_port(usb_bus_from_device(dev),
+                          &port->port, s, i, &usb_hub_port_ops,
+                          USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        port->wPortStatus = PORT_STAT_POWER;
+        port->wPortChange = 0;
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_usb_hub_port = {
+    .name = "usb-hub-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT16(wPortStatus, USBHubPort),
+        VMSTATE_UINT16(wPortChange, USBHubPort),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_usb_hub = {
+    .name = "usb-hub",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_USB_DEVICE(dev, USBHubState),
+        VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
+                             vmstate_usb_hub_port, USBHubPort),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static struct USBDeviceInfo hub_info = {
+    .product_desc   = "QEMU USB Hub",
+    .qdev.name      = "usb-hub",
+    .qdev.fw_name    = "hub",
+    .qdev.size      = sizeof(USBHubState),
+    .qdev.vmsd      = &vmstate_usb_hub,
+    .usb_desc       = &desc_hub,
+    .init           = usb_hub_initfn,
+    .handle_packet  = usb_hub_handle_packet,
+    .handle_attach  = usb_hub_handle_attach,
+    .handle_reset   = usb_hub_handle_reset,
+    .handle_control = usb_hub_handle_control,
+    .handle_data    = usb_hub_handle_data,
+    .handle_destroy = usb_hub_handle_destroy,
+};
+
+static void usb_hub_register_devices(void)
+{
+    usb_qdev_register(&hub_info);
+}
+device_init(usb_hub_register_devices)
diff --git a/qemu-0.15.x/hw/usb-msd.c b/qemu-0.15.x/hw/usb-msd.c
new file mode 100644
index 0000000..6391dad
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-msd.c
@@ -0,0 +1,646 @@
+/*
+ * USB Mass Storage Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "scsi.h"
+#include "console.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "blockdev.h"
+
+//#define DEBUG_MSD
+
+#ifdef DEBUG_MSD
+#define DPRINTF(fmt, ...) \
+do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+/* USB requests.  */
+#define MassStorageReset  0xff
+#define GetMaxLun         0xfe
+
+enum USBMSDMode {
+    USB_MSDM_CBW, /* Command Block.  */
+    USB_MSDM_DATAOUT, /* Transfer data to device.  */
+    USB_MSDM_DATAIN, /* Transfer data from device.  */
+    USB_MSDM_CSW /* Command Status.  */
+};
+
+typedef struct {
+    USBDevice dev;
+    enum USBMSDMode mode;
+    uint32_t scsi_len;
+    uint8_t *scsi_buf;
+    uint32_t usb_len;
+    uint8_t *usb_buf;
+    uint32_t data_len;
+    uint32_t residue;
+    uint32_t tag;
+    SCSIRequest *req;
+    SCSIBus bus;
+    BlockConf conf;
+    char *serial;
+    SCSIDevice *scsi_dev;
+    uint32_t removable;
+    int result;
+    /* For async completion.  */
+    USBPacket *packet;
+} MSDState;
+
+struct usb_msd_cbw {
+    uint32_t sig;
+    uint32_t tag;
+    uint32_t data_len;
+    uint8_t flags;
+    uint8_t lun;
+    uint8_t cmd_len;
+    uint8_t cmd[16];
+};
+
+struct usb_msd_csw {
+    uint32_t sig;
+    uint32_t tag;
+    uint32_t residue;
+    uint8_t status;
+};
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_CONFIG_FULL,
+    STR_CONFIG_HIGH,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
+    [STR_SERIALNUMBER] = "1",
+    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
+    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+};
+
+static const USBDescIface desc_iface_full = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 2,
+    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
+    .bInterfaceSubClass            = 0x06, /* SCSI */
+    .bInterfaceProtocol            = 0x50, /* Bulk */
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | 0x02,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_full = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_FULL,
+            .bmAttributes          = 0xc0,
+            .nif = 1,
+            .ifs = &desc_iface_full,
+        },
+    },
+};
+
+static const USBDescIface desc_iface_high = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 2,
+    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
+    .bInterfaceSubClass            = 0x06, /* SCSI */
+    .bInterfaceProtocol            = 0x50, /* Bulk */
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | 0x02,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 512,
+        },
+    }
+};
+
+static const USBDescDevice desc_device_high = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_HIGH,
+            .bmAttributes          = 0xc0,
+            .nif = 1,
+            .ifs = &desc_iface_high,
+        },
+    },
+};
+
+static const USBDesc desc = {
+    .id = {
+        .idVendor          = 0,
+        .idProduct         = 0,
+        .bcdDevice         = 0,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_full,
+    .high = &desc_device_high,
+    .str  = desc_strings,
+};
+
+static void usb_msd_copy_data(MSDState *s)
+{
+    uint32_t len;
+    len = s->usb_len;
+    if (len > s->scsi_len)
+        len = s->scsi_len;
+    if (s->mode == USB_MSDM_DATAIN) {
+        memcpy(s->usb_buf, s->scsi_buf, len);
+    } else {
+        memcpy(s->scsi_buf, s->usb_buf, len);
+    }
+    s->usb_len -= len;
+    s->scsi_len -= len;
+    s->usb_buf += len;
+    s->scsi_buf += len;
+    s->data_len -= len;
+    if (s->scsi_len == 0 || s->data_len == 0) {
+        scsi_req_continue(s->req);
+    }
+}
+
+static void usb_msd_send_status(MSDState *s, USBPacket *p)
+{
+    struct usb_msd_csw csw;
+    int len;
+
+    csw.sig = cpu_to_le32(0x53425355);
+    csw.tag = cpu_to_le32(s->tag);
+    csw.residue = s->residue;
+    csw.status = s->result;
+
+    len = MIN(sizeof(csw), p->len);
+    memcpy(p->data, &csw, len);
+}
+
+static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+    USBPacket *p = s->packet;
+
+    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
+    s->scsi_len = len;
+    s->scsi_buf = scsi_req_get_buf(req);
+    if (p) {
+        usb_msd_copy_data(s);
+        if (s->packet && s->usb_len == 0) {
+            /* Set s->packet to NULL before calling usb_packet_complete
+               because another request may be issued before
+               usb_packet_complete returns.  */
+            DPRINTF("Packet complete %p\n", p);
+            s->packet = NULL;
+            usb_packet_complete(&s->dev, p);
+        }
+    }
+}
+
+static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+    USBPacket *p = s->packet;
+
+    DPRINTF("Command complete %d\n", status);
+    s->residue = s->data_len;
+    s->result = status != 0;
+    if (s->packet) {
+        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
+            /* A deferred packet with no write data remaining must be
+               the status read packet.  */
+            usb_msd_send_status(s, p);
+            s->mode = USB_MSDM_CBW;
+        } else {
+            if (s->data_len) {
+                s->data_len -= s->usb_len;
+                if (s->mode == USB_MSDM_DATAIN) {
+                    memset(s->usb_buf, 0, s->usb_len);
+                }
+                s->usb_len = 0;
+            }
+            if (s->data_len == 0) {
+                s->mode = USB_MSDM_CSW;
+            }
+        }
+        s->packet = NULL;
+        usb_packet_complete(&s->dev, p);
+    } else if (s->data_len == 0) {
+        s->mode = USB_MSDM_CSW;
+    }
+    scsi_req_unref(req);
+    s->req = NULL;
+}
+
+static void usb_msd_request_cancelled(SCSIRequest *req)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+
+    if (req == s->req) {
+        scsi_req_unref(s->req);
+        s->req = NULL;
+        s->packet = NULL;
+        s->scsi_len = 0;
+    }
+}
+
+static void usb_msd_handle_reset(USBDevice *dev)
+{
+    MSDState *s = (MSDState *)dev;
+
+    DPRINTF("Reset\n");
+    s->mode = USB_MSDM_CBW;
+}
+
+static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    MSDState *s = (MSDState *)dev;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ret = 0;
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+        /* Class specific requests.  */
+    case ClassInterfaceOutRequest | MassStorageReset:
+        /* Reset state ready for the next CBW.  */
+        s->mode = USB_MSDM_CBW;
+        ret = 0;
+        break;
+    case ClassInterfaceRequest | GetMaxLun:
+        data[0] = 0;
+        ret = 1;
+        break;
+    default:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev, dev);
+    scsi_req_cancel(s->req);
+}
+
+static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
+{
+    MSDState *s = (MSDState *)dev;
+    int ret = 0;
+    struct usb_msd_cbw cbw;
+    uint8_t devep = p->devep;
+    uint8_t *data = p->data;
+    int len = p->len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        if (devep != 2)
+            goto fail;
+
+        switch (s->mode) {
+        case USB_MSDM_CBW:
+            if (len != 31) {
+                fprintf(stderr, "usb-msd: Bad CBW size");
+                goto fail;
+            }
+            memcpy(&cbw, data, 31);
+            if (le32_to_cpu(cbw.sig) != 0x43425355) {
+                fprintf(stderr, "usb-msd: Bad signature %08x\n",
+                        le32_to_cpu(cbw.sig));
+                goto fail;
+            }
+            DPRINTF("Command on LUN %d\n", cbw.lun);
+            if (cbw.lun != 0) {
+                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
+                goto fail;
+            }
+            s->tag = le32_to_cpu(cbw.tag);
+            s->data_len = le32_to_cpu(cbw.data_len);
+            if (s->data_len == 0) {
+                s->mode = USB_MSDM_CSW;
+            } else if (cbw.flags & 0x80) {
+                s->mode = USB_MSDM_DATAIN;
+            } else {
+                s->mode = USB_MSDM_DATAOUT;
+            }
+            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
+                    s->tag, cbw.flags, cbw.cmd_len, s->data_len);
+            s->residue = 0;
+            s->scsi_len = 0;
+            s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
+            scsi_req_enqueue(s->req, cbw.cmd);
+            /* ??? Should check that USB and SCSI data transfer
+               directions match.  */
+            if (s->mode != USB_MSDM_CSW && s->residue == 0) {
+                scsi_req_continue(s->req);
+            }
+            ret = len;
+            break;
+
+        case USB_MSDM_DATAOUT:
+            DPRINTF("Data out %d/%d\n", len, s->data_len);
+            if (len > s->data_len)
+                goto fail;
+
+            s->usb_buf = data;
+            s->usb_len = len;
+            if (s->scsi_len) {
+                usb_msd_copy_data(s);
+            }
+            if (s->residue && s->usb_len) {
+                s->data_len -= s->usb_len;
+                if (s->data_len == 0)
+                    s->mode = USB_MSDM_CSW;
+                s->usb_len = 0;
+            }
+            if (s->usb_len) {
+                DPRINTF("Deferring packet %p\n", p);
+                s->packet = p;
+                ret = USB_RET_ASYNC;
+            } else {
+                ret = len;
+            }
+            break;
+
+        default:
+            DPRINTF("Unexpected write (len %d)\n", len);
+            goto fail;
+        }
+        break;
+
+    case USB_TOKEN_IN:
+        if (devep != 1)
+            goto fail;
+
+        switch (s->mode) {
+        case USB_MSDM_DATAOUT:
+            if (s->data_len != 0 || len < 13)
+                goto fail;
+            /* Waiting for SCSI write to complete.  */
+            s->packet = p;
+            ret = USB_RET_ASYNC;
+            break;
+
+        case USB_MSDM_CSW:
+            DPRINTF("Command status %d tag 0x%x, len %d\n",
+                    s->result, s->tag, len);
+            if (len < 13)
+                goto fail;
+
+            usb_msd_send_status(s, p);
+            s->mode = USB_MSDM_CBW;
+            ret = 13;
+            break;
+
+        case USB_MSDM_DATAIN:
+            DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
+            if (len > s->data_len)
+                len = s->data_len;
+            s->usb_buf = data;
+            s->usb_len = len;
+            if (s->scsi_len) {
+                usb_msd_copy_data(s);
+            }
+            if (s->residue && s->usb_len) {
+                s->data_len -= s->usb_len;
+                memset(s->usb_buf, 0, s->usb_len);
+                if (s->data_len == 0)
+                    s->mode = USB_MSDM_CSW;
+                s->usb_len = 0;
+            }
+            if (s->usb_len) {
+                DPRINTF("Deferring packet %p\n", p);
+                s->packet = p;
+                ret = USB_RET_ASYNC;
+            } else {
+                ret = len;
+            }
+            break;
+
+        default:
+            DPRINTF("Unexpected read (len %d)\n", len);
+            goto fail;
+        }
+        break;
+
+    default:
+        DPRINTF("Bad token\n");
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void usb_msd_password_cb(void *opaque, int err)
+{
+    MSDState *s = opaque;
+
+    if (!err)
+        err = usb_device_attach(&s->dev);
+
+    if (err)
+        qdev_unplug(&s->dev.qdev);
+}
+
+static const struct SCSIBusOps usb_msd_scsi_ops = {
+    .transfer_data = usb_msd_transfer_data,
+    .complete = usb_msd_command_complete,
+    .cancel = usb_msd_request_cancelled
+};
+
+static int usb_msd_initfn(USBDevice *dev)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev, dev);
+    BlockDriverState *bs = s->conf.bs;
+    DriveInfo *dinfo;
+
+    if (!bs) {
+        error_report("usb-msd: drive property not set");
+        return -1;
+    }
+
+    /*
+     * Hack alert: this pretends to be a block device, but it's really
+     * a SCSI bus that can serve only a single device, which it
+     * creates automatically.  But first it needs to detach from its
+     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
+     * attaches again.
+     *
+     * The hack is probably a bad idea.
+     */
+    bdrv_detach(bs, &s->dev.qdev);
+    s->conf.bs = NULL;
+
+    if (!s->serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(bs);
+        if (*dinfo->serial) {
+            s->serial = strdup(dinfo->serial);
+        }
+    }
+    if (s->serial) {
+        usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
+    }
+
+    usb_desc_init(dev);
+    scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
+    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
+    if (!s->scsi_dev) {
+        return -1;
+    }
+    s->bus.qbus.allow_hotplug = 0;
+    usb_msd_handle_reset(dev);
+
+    if (bdrv_key_required(bs)) {
+        if (cur_mon) {
+            monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
+            s->dev.auto_attach = 0;
+        } else {
+            autostart = 0;
+        }
+    }
+
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk at 0,0");
+    return 0;
+}
+
+static USBDevice *usb_msd_init(const char *filename)
+{
+    static int nr=0;
+    char id[8];
+    QemuOpts *opts;
+    DriveInfo *dinfo;
+    USBDevice *dev;
+    const char *p1;
+    char fmt[32];
+
+    /* parse -usbdevice disk: syntax into drive opts */
+    snprintf(id, sizeof(id), "usb%d", nr++);
+    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
+
+    p1 = strchr(filename, ':');
+    if (p1++) {
+        const char *p2;
+
+        if (strstart(filename, "format=", &p2)) {
+            int len = MIN(p1 - p2, sizeof(fmt));
+            pstrcpy(fmt, len, p2);
+            qemu_opt_set(opts, "format", fmt);
+        } else if (*filename != ':') {
+            printf("unrecognized USB mass-storage option %s\n", filename);
+            return NULL;
+        }
+        filename = p1;
+    }
+    if (!*filename) {
+        printf("block device specification needed\n");
+        return NULL;
+    }
+    qemu_opt_set(opts, "file", filename);
+    qemu_opt_set(opts, "if", "none");
+
+    /* create host drive */
+    dinfo = drive_init(opts, 0);
+    if (!dinfo) {
+        qemu_opts_del(opts);
+        return NULL;
+    }
+
+    /* create guest device */
+    dev = usb_create(NULL /* FIXME */, "usb-storage");
+    if (!dev) {
+        return NULL;
+    }
+    if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
+        qdev_free(&dev->qdev);
+        return NULL;
+    }
+    if (qdev_init(&dev->qdev) < 0)
+        return NULL;
+
+    return dev;
+}
+
+static struct USBDeviceInfo msd_info = {
+    .product_desc   = "QEMU USB MSD",
+    .qdev.name      = "usb-storage",
+    .qdev.fw_name      = "storage",
+    .qdev.size      = sizeof(MSDState),
+    .usb_desc       = &desc,
+    .init           = usb_msd_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usb_msd_cancel_io,
+    .handle_attach  = usb_desc_attach,
+    .handle_reset   = usb_msd_handle_reset,
+    .handle_control = usb_msd_handle_control,
+    .handle_data    = usb_msd_handle_data,
+    .usbdevice_name = "disk",
+    .usbdevice_init = usb_msd_init,
+    .qdev.props     = (Property[]) {
+        DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+        DEFINE_PROP_STRING("serial", MSDState, serial),
+        DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void usb_msd_register_devices(void)
+{
+    usb_qdev_register(&msd_info);
+}
+device_init(usb_msd_register_devices)
diff --git a/qemu-0.15.x/hw/usb-musb.c b/qemu-0.15.x/hw/usb-musb.c
new file mode 100644
index 0000000..035dda8
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-musb.c
@@ -0,0 +1,1529 @@
+/*
+ * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
+ * USB2.0 OTG compliant core used in various chips.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Only host-mode and non-DMA accesses are currently supported.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "irq.h"
+#include "hw.h"
+
+/* Common USB registers */
+#define MUSB_HDRC_FADDR		0x00	/* 8-bit */
+#define MUSB_HDRC_POWER		0x01	/* 8-bit */
+
+#define MUSB_HDRC_INTRTX	0x02	/* 16-bit */
+#define MUSB_HDRC_INTRRX	0x04
+#define MUSB_HDRC_INTRTXE	0x06  
+#define MUSB_HDRC_INTRRXE	0x08  
+#define MUSB_HDRC_INTRUSB	0x0a	/* 8 bit */
+#define MUSB_HDRC_INTRUSBE	0x0b	/* 8 bit */
+#define MUSB_HDRC_FRAME		0x0c	/* 16-bit */
+#define MUSB_HDRC_INDEX		0x0e	/* 8 bit */
+#define MUSB_HDRC_TESTMODE	0x0f	/* 8 bit */
+
+/* Per-EP registers in indexed mode */
+#define MUSB_HDRC_EP_IDX	0x10	/* 8-bit */
+
+/* EP FIFOs */
+#define MUSB_HDRC_FIFO		0x20
+
+/* Additional Control Registers */
+#define	MUSB_HDRC_DEVCTL	0x60	/* 8 bit */
+
+/* These are indexed */
+#define MUSB_HDRC_TXFIFOSZ	0x62	/* 8 bit (see masks) */
+#define MUSB_HDRC_RXFIFOSZ	0x63	/* 8 bit (see masks) */
+#define MUSB_HDRC_TXFIFOADDR	0x64	/* 16 bit offset shifted right 3 */
+#define MUSB_HDRC_RXFIFOADDR	0x66	/* 16 bit offset shifted right 3 */
+
+/* Some more registers */
+#define MUSB_HDRC_VCTRL		0x68	/* 8 bit */
+#define MUSB_HDRC_HWVERS	0x6c	/* 8 bit */
+
+/* Added in HDRC 1.9(?) & MHDRC 1.4 */
+/* ULPI pass-through */
+#define MUSB_HDRC_ULPI_VBUSCTL	0x70
+#define MUSB_HDRC_ULPI_REGDATA	0x74
+#define MUSB_HDRC_ULPI_REGADDR	0x75
+#define MUSB_HDRC_ULPI_REGCTL	0x76
+
+/* Extended config & PHY control */
+#define MUSB_HDRC_ENDCOUNT	0x78	/* 8 bit */
+#define MUSB_HDRC_DMARAMCFG	0x79	/* 8 bit */
+#define MUSB_HDRC_PHYWAIT	0x7a	/* 8 bit */
+#define MUSB_HDRC_PHYVPLEN	0x7b	/* 8 bit */
+#define MUSB_HDRC_HS_EOF1	0x7c	/* 8 bit, units of 546.1 us */
+#define MUSB_HDRC_FS_EOF1	0x7d	/* 8 bit, units of 533.3 ns */
+#define MUSB_HDRC_LS_EOF1	0x7e	/* 8 bit, units of 1.067 us */
+
+/* Per-EP BUSCTL registers */
+#define MUSB_HDRC_BUSCTL	0x80
+
+/* Per-EP registers in flat mode */
+#define MUSB_HDRC_EP		0x100
+
+/* offsets to registers in flat model */
+#define MUSB_HDRC_TXMAXP	0x00	/* 16 bit apparently */
+#define MUSB_HDRC_TXCSR		0x02	/* 16 bit apparently */
+#define MUSB_HDRC_CSR0		MUSB_HDRC_TXCSR		/* re-used for EP0 */
+#define MUSB_HDRC_RXMAXP	0x04	/* 16 bit apparently */
+#define MUSB_HDRC_RXCSR		0x06	/* 16 bit apparently */
+#define MUSB_HDRC_RXCOUNT	0x08	/* 16 bit apparently */
+#define MUSB_HDRC_COUNT0	MUSB_HDRC_RXCOUNT	/* re-used for EP0 */
+#define MUSB_HDRC_TXTYPE	0x0a	/* 8 bit apparently */
+#define MUSB_HDRC_TYPE0		MUSB_HDRC_TXTYPE	/* re-used for EP0 */
+#define MUSB_HDRC_TXINTERVAL	0x0b	/* 8 bit apparently */
+#define MUSB_HDRC_NAKLIMIT0	MUSB_HDRC_TXINTERVAL	/* re-used for EP0 */
+#define MUSB_HDRC_RXTYPE	0x0c	/* 8 bit apparently */
+#define MUSB_HDRC_RXINTERVAL	0x0d	/* 8 bit apparently */
+#define MUSB_HDRC_FIFOSIZE	0x0f	/* 8 bit apparently */
+#define MUSB_HDRC_CONFIGDATA	MGC_O_HDRC_FIFOSIZE	/* re-used for EP0 */
+
+/* "Bus control" registers */
+#define MUSB_HDRC_TXFUNCADDR	0x00
+#define MUSB_HDRC_TXHUBADDR	0x02
+#define MUSB_HDRC_TXHUBPORT	0x03
+
+#define MUSB_HDRC_RXFUNCADDR	0x04
+#define MUSB_HDRC_RXHUBADDR	0x06
+#define MUSB_HDRC_RXHUBPORT	0x07
+
+/*
+ * MUSBHDRC Register bit masks
+ */
+
+/* POWER */
+#define MGC_M_POWER_ISOUPDATE		0x80 
+#define	MGC_M_POWER_SOFTCONN		0x40
+#define	MGC_M_POWER_HSENAB		0x20
+#define	MGC_M_POWER_HSMODE		0x10
+#define MGC_M_POWER_RESET		0x08
+#define MGC_M_POWER_RESUME		0x04
+#define MGC_M_POWER_SUSPENDM		0x02
+#define MGC_M_POWER_ENSUSPEND		0x01
+
+/* INTRUSB */
+#define MGC_M_INTR_SUSPEND		0x01
+#define MGC_M_INTR_RESUME		0x02
+#define MGC_M_INTR_RESET		0x04
+#define MGC_M_INTR_BABBLE		0x04
+#define MGC_M_INTR_SOF			0x08 
+#define MGC_M_INTR_CONNECT		0x10
+#define MGC_M_INTR_DISCONNECT		0x20
+#define MGC_M_INTR_SESSREQ		0x40
+#define MGC_M_INTR_VBUSERROR		0x80	/* FOR SESSION END */
+#define MGC_M_INTR_EP0			0x01	/* FOR EP0 INTERRUPT */
+
+/* DEVCTL */
+#define MGC_M_DEVCTL_BDEVICE		0x80   
+#define MGC_M_DEVCTL_FSDEV		0x40
+#define MGC_M_DEVCTL_LSDEV		0x20
+#define MGC_M_DEVCTL_VBUS		0x18
+#define MGC_S_DEVCTL_VBUS		3
+#define MGC_M_DEVCTL_HM			0x04
+#define MGC_M_DEVCTL_HR			0x02
+#define MGC_M_DEVCTL_SESSION		0x01
+
+/* TESTMODE */
+#define MGC_M_TEST_FORCE_HOST		0x80
+#define MGC_M_TEST_FIFO_ACCESS		0x40
+#define MGC_M_TEST_FORCE_FS		0x20
+#define MGC_M_TEST_FORCE_HS		0x10
+#define MGC_M_TEST_PACKET		0x08
+#define MGC_M_TEST_K			0x04
+#define MGC_M_TEST_J			0x02
+#define MGC_M_TEST_SE0_NAK		0x01
+
+/* CSR0 */
+#define	MGC_M_CSR0_FLUSHFIFO		0x0100
+#define MGC_M_CSR0_TXPKTRDY		0x0002
+#define MGC_M_CSR0_RXPKTRDY		0x0001
+
+/* CSR0 in Peripheral mode */
+#define MGC_M_CSR0_P_SVDSETUPEND	0x0080
+#define MGC_M_CSR0_P_SVDRXPKTRDY	0x0040
+#define MGC_M_CSR0_P_SENDSTALL		0x0020
+#define MGC_M_CSR0_P_SETUPEND		0x0010
+#define MGC_M_CSR0_P_DATAEND		0x0008
+#define MGC_M_CSR0_P_SENTSTALL		0x0004
+
+/* CSR0 in Host mode */
+#define MGC_M_CSR0_H_NO_PING		0x0800
+#define MGC_M_CSR0_H_WR_DATATOGGLE	0x0400	/* set to allow setting: */
+#define MGC_M_CSR0_H_DATATOGGLE		0x0200	/* data toggle control */
+#define	MGC_M_CSR0_H_NAKTIMEOUT		0x0080
+#define MGC_M_CSR0_H_STATUSPKT		0x0040
+#define MGC_M_CSR0_H_REQPKT		0x0020
+#define MGC_M_CSR0_H_ERROR		0x0010
+#define MGC_M_CSR0_H_SETUPPKT		0x0008
+#define MGC_M_CSR0_H_RXSTALL		0x0004
+
+/* CONFIGDATA */
+#define MGC_M_CONFIGDATA_MPRXE		0x80	/* auto bulk pkt combining */
+#define MGC_M_CONFIGDATA_MPTXE		0x40	/* auto bulk pkt splitting */
+#define MGC_M_CONFIGDATA_BIGENDIAN	0x20
+#define MGC_M_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */
+#define MGC_M_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */
+#define MGC_M_CONFIGDATA_DYNFIFO	0x04	/* dynamic FIFO sizing */
+#define MGC_M_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */
+#define MGC_M_CONFIGDATA_UTMIDW		0x01	/* Width, 0 => 8b, 1 => 16b */
+
+/* TXCSR in Peripheral and Host mode */
+#define MGC_M_TXCSR_AUTOSET		0x8000
+#define MGC_M_TXCSR_ISO			0x4000
+#define MGC_M_TXCSR_MODE		0x2000
+#define MGC_M_TXCSR_DMAENAB		0x1000
+#define MGC_M_TXCSR_FRCDATATOG		0x0800
+#define MGC_M_TXCSR_DMAMODE		0x0400
+#define MGC_M_TXCSR_CLRDATATOG		0x0040
+#define MGC_M_TXCSR_FLUSHFIFO		0x0008
+#define MGC_M_TXCSR_FIFONOTEMPTY	0x0002
+#define MGC_M_TXCSR_TXPKTRDY		0x0001
+
+/* TXCSR in Peripheral mode */
+#define MGC_M_TXCSR_P_INCOMPTX		0x0080
+#define MGC_M_TXCSR_P_SENTSTALL		0x0020
+#define MGC_M_TXCSR_P_SENDSTALL		0x0010
+#define MGC_M_TXCSR_P_UNDERRUN		0x0004
+
+/* TXCSR in Host mode */
+#define MGC_M_TXCSR_H_WR_DATATOGGLE	0x0200
+#define MGC_M_TXCSR_H_DATATOGGLE	0x0100
+#define MGC_M_TXCSR_H_NAKTIMEOUT	0x0080
+#define MGC_M_TXCSR_H_RXSTALL		0x0020
+#define MGC_M_TXCSR_H_ERROR		0x0004
+
+/* RXCSR in Peripheral and Host mode */
+#define MGC_M_RXCSR_AUTOCLEAR		0x8000
+#define MGC_M_RXCSR_DMAENAB		0x2000
+#define MGC_M_RXCSR_DISNYET		0x1000
+#define MGC_M_RXCSR_DMAMODE		0x0800
+#define MGC_M_RXCSR_INCOMPRX		0x0100
+#define MGC_M_RXCSR_CLRDATATOG		0x0080
+#define MGC_M_RXCSR_FLUSHFIFO		0x0010
+#define MGC_M_RXCSR_DATAERROR		0x0008
+#define MGC_M_RXCSR_FIFOFULL		0x0002
+#define MGC_M_RXCSR_RXPKTRDY		0x0001
+
+/* RXCSR in Peripheral mode */
+#define MGC_M_RXCSR_P_ISO		0x4000
+#define MGC_M_RXCSR_P_SENTSTALL		0x0040
+#define MGC_M_RXCSR_P_SENDSTALL		0x0020
+#define MGC_M_RXCSR_P_OVERRUN		0x0004
+
+/* RXCSR in Host mode */
+#define MGC_M_RXCSR_H_AUTOREQ		0x4000
+#define MGC_M_RXCSR_H_WR_DATATOGGLE	0x0400
+#define MGC_M_RXCSR_H_DATATOGGLE	0x0200
+#define MGC_M_RXCSR_H_RXSTALL		0x0040
+#define MGC_M_RXCSR_H_REQPKT		0x0020
+#define MGC_M_RXCSR_H_ERROR		0x0004
+
+/* HUBADDR */
+#define MGC_M_HUBADDR_MULTI_TT		0x80
+
+/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
+#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND	0x02
+#define MGC_M_ULPI_VBCTL_USEEXTVBUS	0x01
+#define MGC_M_ULPI_REGCTL_INT_ENABLE	0x08
+#define MGC_M_ULPI_REGCTL_READNOTWRITE	0x04
+#define MGC_M_ULPI_REGCTL_COMPLETE	0x02
+#define MGC_M_ULPI_REGCTL_REG		0x01
+
+/* #define MUSB_DEBUG */
+
+#ifdef MUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
+                               __LINE__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+
+static void musb_attach(USBPort *port);
+static void musb_detach(USBPort *port);
+static void musb_child_detach(USBPort *port, USBDevice *child);
+static void musb_schedule_cb(USBPort *port, USBPacket *p);
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
+
+static USBPortOps musb_port_ops = {
+    .attach = musb_attach,
+    .detach = musb_detach,
+    .child_detach = musb_child_detach,
+    .complete = musb_schedule_cb,
+};
+
+static USBBusOps musb_bus_ops = {
+};
+
+typedef struct MUSBPacket MUSBPacket;
+typedef struct MUSBEndPoint MUSBEndPoint;
+
+struct MUSBPacket {
+    USBPacket p;
+    MUSBEndPoint *ep;
+    int dir;
+};
+
+struct MUSBEndPoint {
+    uint16_t faddr[2];
+    uint8_t haddr[2];
+    uint8_t hport[2];
+    uint16_t csr[2];
+    uint16_t maxp[2];
+    uint16_t rxcount;
+    uint8_t type[2];
+    uint8_t interval[2];
+    uint8_t config;
+    uint8_t fifosize;
+    int timeout[2];	/* Always in microframes */
+
+    uint8_t *buf[2];
+    int fifolen[2];
+    int fifostart[2];
+    int fifoaddr[2];
+    MUSBPacket packey[2];
+    int status[2];
+    int ext_size[2];
+
+    /* For callbacks' use */
+    int epnum;
+    int interrupt[2];
+    MUSBState *musb;
+    USBCallback *delayed_cb[2];
+    QEMUTimer *intv_timer[2];
+};
+
+struct MUSBState {
+    qemu_irq *irqs;
+    USBBus bus;
+    USBPort port;
+
+    int idx;
+    uint8_t devctl;
+    uint8_t power;
+    uint8_t faddr;
+
+    uint8_t intr;
+    uint8_t mask;
+    uint16_t tx_intr;
+    uint16_t tx_mask;
+    uint16_t rx_intr;
+    uint16_t rx_mask;
+
+    int setup_len;
+    int session;
+
+    uint8_t buf[0x8000];
+
+        /* Duplicating the world since 2008!...  probably we should have 32
+         * logical, single endpoints instead.  */
+    MUSBEndPoint ep[16];
+};
+
+struct MUSBState *musb_init(qemu_irq *irqs)
+{
+    MUSBState *s = qemu_mallocz(sizeof(*s));
+    int i;
+
+    s->irqs = irqs;
+
+    s->faddr = 0x00;
+    s->power = MGC_M_POWER_HSENAB;
+    s->tx_intr = 0x0000;
+    s->rx_intr = 0x0000;
+    s->tx_mask = 0xffff;
+    s->rx_mask = 0xffff;
+    s->intr = 0x00;
+    s->mask = 0x06;
+    s->idx = 0;
+
+    /* TODO: _DW */
+    s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
+    for (i = 0; i < 16; i ++) {
+        s->ep[i].fifosize = 64;
+        s->ep[i].maxp[0] = 0x40;
+        s->ep[i].maxp[1] = 0x40;
+        s->ep[i].musb = s;
+        s->ep[i].epnum = i;
+    }
+
+    usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
+    usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
+                      USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+
+    return s;
+}
+
+static void musb_vbus_set(MUSBState *s, int level)
+{
+    if (level)
+        s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
+    else
+        s->devctl &= ~MGC_M_DEVCTL_VBUS;
+
+    qemu_set_irq(s->irqs[musb_set_vbus], level);
+}
+
+static void musb_intr_set(MUSBState *s, int line, int level)
+{
+    if (!level) {
+        s->intr &= ~(1 << line);
+        qemu_irq_lower(s->irqs[line]);
+    } else if (s->mask & (1 << line)) {
+        s->intr |= 1 << line;
+        qemu_irq_raise(s->irqs[line]);
+    }
+}
+
+static void musb_tx_intr_set(MUSBState *s, int line, int level)
+{
+    if (!level) {
+        s->tx_intr &= ~(1 << line);
+        if (!s->tx_intr)
+            qemu_irq_lower(s->irqs[musb_irq_tx]);
+    } else if (s->tx_mask & (1 << line)) {
+        s->tx_intr |= 1 << line;
+        qemu_irq_raise(s->irqs[musb_irq_tx]);
+    }
+}
+
+static void musb_rx_intr_set(MUSBState *s, int line, int level)
+{
+    if (line) {
+        if (!level) {
+            s->rx_intr &= ~(1 << line);
+            if (!s->rx_intr)
+                qemu_irq_lower(s->irqs[musb_irq_rx]);
+        } else if (s->rx_mask & (1 << line)) {
+            s->rx_intr |= 1 << line;
+            qemu_irq_raise(s->irqs[musb_irq_rx]);
+        }
+    } else
+        musb_tx_intr_set(s, line, level);
+}
+
+uint32_t musb_core_intr_get(MUSBState *s)
+{
+    return (s->rx_intr << 15) | s->tx_intr;
+}
+
+void musb_core_intr_clear(MUSBState *s, uint32_t mask)
+{
+    if (s->rx_intr) {
+        s->rx_intr &= mask >> 15;
+        if (!s->rx_intr)
+            qemu_irq_lower(s->irqs[musb_irq_rx]);
+    }
+
+    if (s->tx_intr) {
+        s->tx_intr &= mask & 0xffff;
+        if (!s->tx_intr)
+            qemu_irq_lower(s->irqs[musb_irq_tx]);
+    }
+}
+
+void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
+{
+    s->ep[epnum].ext_size[!is_tx] = size;
+    s->ep[epnum].fifostart[0] = 0;
+    s->ep[epnum].fifostart[1] = 0;
+    s->ep[epnum].fifolen[0] = 0;
+    s->ep[epnum].fifolen[1] = 0;
+}
+
+static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
+{
+    int detect_prev = prev_dev && prev_sess;
+    int detect = !!s->port.dev && s->session;
+
+    if (detect && !detect_prev) {
+        /* Let's skip the ID pin sense and VBUS sense formalities and
+         * and signal a successful SRP directly.  This should work at least
+         * for the Linux driver stack.  */
+        musb_intr_set(s, musb_irq_connect, 1);
+
+        if (s->port.dev->speed == USB_SPEED_LOW) {
+            s->devctl &= ~MGC_M_DEVCTL_FSDEV;
+            s->devctl |= MGC_M_DEVCTL_LSDEV;
+        } else {
+            s->devctl |= MGC_M_DEVCTL_FSDEV;
+            s->devctl &= ~MGC_M_DEVCTL_LSDEV;
+        }
+
+        /* A-mode?  */
+        s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
+
+        /* Host-mode bit?  */
+        s->devctl |= MGC_M_DEVCTL_HM;
+#if 1
+        musb_vbus_set(s, 1);
+#endif
+    } else if (!detect && detect_prev) {
+#if 1
+        musb_vbus_set(s, 0);
+#endif
+    }
+}
+
+/* Attach or detach a device on our only port.  */
+static void musb_attach(USBPort *port)
+{
+    MUSBState *s = (MUSBState *) port->opaque;
+
+    musb_intr_set(s, musb_irq_vbus_request, 1);
+    musb_session_update(s, 0, s->session);
+}
+
+static void musb_detach(USBPort *port)
+{
+    MUSBState *s = (MUSBState *) port->opaque;
+
+    musb_async_cancel_device(s, port->dev);
+
+    musb_intr_set(s, musb_irq_disconnect, 1);
+    musb_session_update(s, 1, s->session);
+}
+
+static void musb_child_detach(USBPort *port, USBDevice *child)
+{
+    MUSBState *s = (MUSBState *) port->opaque;
+
+    musb_async_cancel_device(s, child);
+}
+
+static void musb_cb_tick0(void *opaque)
+{
+    MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+
+    ep->delayed_cb[0](&ep->packey[0].p, opaque);
+}
+
+static void musb_cb_tick1(void *opaque)
+{
+    MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+
+    ep->delayed_cb[1](&ep->packey[1].p, opaque);
+}
+
+#define musb_cb_tick	(dir ? musb_cb_tick1 : musb_cb_tick0)
+
+static void musb_schedule_cb(USBPort *port, USBPacket *packey)
+{
+    MUSBPacket *p = container_of(packey, MUSBPacket, p);
+    MUSBEndPoint *ep = p->ep;
+    int dir = p->dir;
+    int timeout = 0;
+
+    if (ep->status[dir] == USB_RET_NAK)
+        timeout = ep->timeout[dir];
+    else if (ep->interrupt[dir])
+        timeout = 8;
+    else
+        return musb_cb_tick(ep);
+
+    if (!ep->intv_timer[dir])
+        ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep);
+
+    qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) +
+                   muldiv64(timeout, get_ticks_per_sec(), 8000));
+}
+
+static int musb_timeout(int ttype, int speed, int val)
+{
+#if 1
+    return val << 3;
+#endif
+
+    switch (ttype) {
+    case USB_ENDPOINT_XFER_CONTROL:
+        if (val < 2)
+            return 0;
+        else if (speed == USB_SPEED_HIGH)
+            return 1 << (val - 1);
+        else
+            return 8 << (val - 1);
+
+    case USB_ENDPOINT_XFER_INT:
+        if (speed == USB_SPEED_HIGH)
+            if (val < 2)
+                return 0;
+            else
+                return 1 << (val - 1);
+        else
+            return val << 3;
+
+    case USB_ENDPOINT_XFER_BULK:
+    case USB_ENDPOINT_XFER_ISOC:
+        if (val < 2)
+            return 0;
+        else if (speed == USB_SPEED_HIGH)
+            return 1 << (val - 1);
+        else
+            return 8 << (val - 1);
+        /* TODO: what with low-speed Bulk and Isochronous?  */
+    }
+
+    hw_error("bad interval\n");
+}
+
+static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
+                int epnum, int pid, int len, USBCallback cb, int dir)
+{
+    int ret;
+    int idx = epnum && dir;
+    int ttype;
+
+    /* ep->type[0,1] contains:
+     * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
+     * in bits 5:4 the transfer type (BULK / INT)
+     * in bits 3:0 the EP num
+     */
+    ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
+
+    ep->timeout[dir] = musb_timeout(ttype,
+                    ep->type[idx] >> 6, ep->interval[idx]);
+    ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
+    ep->delayed_cb[dir] = cb;
+
+    ep->packey[dir].p.pid = pid;
+    /* A wild guess on the FADDR semantics... */
+    ep->packey[dir].p.devaddr = ep->faddr[idx];
+    ep->packey[dir].p.devep = ep->type[idx] & 0xf;
+    ep->packey[dir].p.data = (void *) ep->buf[idx];
+    ep->packey[dir].p.len = len;
+    ep->packey[dir].ep = ep;
+    ep->packey[dir].dir = dir;
+
+    if (s->port.dev)
+        ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
+    else
+        ret = USB_RET_NODEV;
+
+    if (ret == USB_RET_ASYNC) {
+        ep->status[dir] = len;
+        return;
+    }
+
+    ep->status[dir] = ret;
+    musb_schedule_cb(&s->port, &ep->packey[dir].p);
+}
+
+static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
+{
+    /* Unfortunately we can't use packey->devep because that's the remote
+     * endpoint number and may be different than our local.  */
+    MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+    int epnum = ep->epnum;
+    MUSBState *s = ep->musb;
+
+    ep->fifostart[0] = 0;
+    ep->fifolen[0] = 0;
+#ifdef CLEAR_NAK
+    if (ep->status[0] != USB_RET_NAK) {
+#endif
+        if (epnum)
+            ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
+        else
+            ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
+#ifdef CLEAR_NAK
+    }
+#endif
+
+    /* Clear all of the error bits first */
+    if (epnum)
+        ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
+                        MGC_M_TXCSR_H_NAKTIMEOUT);
+    else
+        ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
+                        MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
+
+    if (ep->status[0] == USB_RET_STALL) {
+        /* Command not supported by target! */
+        ep->status[0] = 0;
+
+        if (epnum)
+            ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
+        else
+            ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
+    }
+
+    if (ep->status[0] == USB_RET_NAK) {
+        ep->status[0] = 0;
+
+        /* NAK timeouts are only generated in Bulk transfers and
+         * Data-errors in Isochronous.  */
+        if (ep->interrupt[0]) {
+            return;
+        }
+
+        if (epnum)
+            ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
+        else
+            ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
+    }
+
+    if (ep->status[0] < 0) {
+        if (ep->status[0] == USB_RET_BABBLE)
+            musb_intr_set(s, musb_irq_rst_babble, 1);
+
+        /* Pretend we've tried three times already and failed (in
+         * case of USB_TOKEN_SETUP).  */
+        if (epnum)
+            ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
+        else
+            ep->csr[0] |= MGC_M_CSR0_H_ERROR;
+
+        musb_tx_intr_set(s, epnum, 1);
+        return;
+    }
+    /* TODO: check len for over/underruns of an OUT packet?  */
+
+#ifdef SETUPLEN_HACK
+    if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
+        s->setup_len = ep->packey[0].data[6];
+#endif
+
+    /* In DMA mode: if no error, assert DMA request for this EP,
+     * and skip the interrupt.  */
+    musb_tx_intr_set(s, epnum, 1);
+}
+
+static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
+{
+    /* Unfortunately we can't use packey->devep because that's the remote
+     * endpoint number and may be different than our local.  */
+    MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
+    int epnum = ep->epnum;
+    MUSBState *s = ep->musb;
+
+    ep->fifostart[1] = 0;
+    ep->fifolen[1] = 0;
+
+#ifdef CLEAR_NAK
+    if (ep->status[1] != USB_RET_NAK) {
+#endif
+        ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
+        if (!epnum)
+            ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
+#ifdef CLEAR_NAK
+    }
+#endif
+
+    /* Clear all of the imaginable error bits first */
+    ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
+                    MGC_M_RXCSR_DATAERROR);
+    if (!epnum)
+        ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
+                        MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
+
+    if (ep->status[1] == USB_RET_STALL) {
+        ep->status[1] = 0;
+        packey->len = 0;
+
+        ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
+        if (!epnum)
+            ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
+    }
+
+    if (ep->status[1] == USB_RET_NAK) {
+        ep->status[1] = 0;
+
+        /* NAK timeouts are only generated in Bulk transfers and
+         * Data-errors in Isochronous.  */
+        if (ep->interrupt[1])
+            return musb_packet(s, ep, epnum, USB_TOKEN_IN,
+                            packey->len, musb_rx_packet_complete, 1);
+
+        ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
+        if (!epnum)
+            ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
+    }
+
+    if (ep->status[1] < 0) {
+        if (ep->status[1] == USB_RET_BABBLE) {
+            musb_intr_set(s, musb_irq_rst_babble, 1);
+            return;
+        }
+
+        /* Pretend we've tried three times already and failed (in
+         * case of a control transfer).  */
+        ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
+        if (!epnum)
+            ep->csr[0] |= MGC_M_CSR0_H_ERROR;
+
+        musb_rx_intr_set(s, epnum, 1);
+        return;
+    }
+    /* TODO: check len for over/underruns of an OUT packet?  */
+    /* TODO: perhaps make use of e->ext_size[1] here.  */
+
+    packey->len = ep->status[1];
+
+    if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
+        ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
+        if (!epnum)
+            ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
+
+        ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+        /* In DMA mode: assert DMA request for this EP */
+    }
+
+    /* Only if DMA has not been asserted */
+    musb_rx_intr_set(s, epnum, 1);
+}
+
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
+{
+    int ep, dir;
+
+    for (ep = 0; ep < 16; ep++) {
+        for (dir = 0; dir < 2; dir++) {
+            if (s->ep[ep].packey[dir].p.owner != dev) {
+                continue;
+            }
+            usb_cancel_packet(&s->ep[ep].packey[dir].p);
+            /* status updates needed here? */
+        }
+    }
+}
+
+static void musb_tx_rdy(MUSBState *s, int epnum)
+{
+    MUSBEndPoint *ep = s->ep + epnum;
+    int pid;
+    int total, valid = 0;
+    TRACE("start %d, len %d",  ep->fifostart[0], ep->fifolen[0] );
+    ep->fifostart[0] += ep->fifolen[0];
+    ep->fifolen[0] = 0;
+
+    /* XXX: how's the total size of the packet retrieved exactly in
+     * the generic case?  */
+    total = ep->maxp[0] & 0x3ff;
+
+    if (ep->ext_size[0]) {
+        total = ep->ext_size[0];
+        ep->ext_size[0] = 0;
+        valid = 1;
+    }
+
+    /* If the packet is not fully ready yet, wait for a next segment.  */
+    if (epnum && (ep->fifostart[0]) < total)
+        return;
+
+    if (!valid)
+        total = ep->fifostart[0];
+
+    pid = USB_TOKEN_OUT;
+    if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
+        pid = USB_TOKEN_SETUP;
+        if (total != 8) {
+            TRACE("illegal SETUPPKT length of %i bytes", total);
+        }
+        /* Controller should retry SETUP packets three times on errors
+         * but it doesn't make sense for us to do that.  */
+    }
+
+    return musb_packet(s, ep, epnum, pid,
+                    total, musb_tx_packet_complete, 0);
+}
+
+static void musb_rx_req(MUSBState *s, int epnum)
+{
+    MUSBEndPoint *ep = s->ep + epnum;
+    int total;
+
+    /* If we already have a packet, which didn't fit into the
+     * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
+    if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
+                    (ep->fifostart[1]) + ep->rxcount <
+                    ep->packey[1].p.len) {
+        TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
+        ep->fifostart[1] += ep->rxcount;
+        ep->fifolen[1] = 0;
+
+        ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
+                        ep->maxp[1]);
+
+        ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
+        if (!epnum)
+            ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
+
+        /* Clear all of the error bits first */
+        ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
+                        MGC_M_RXCSR_DATAERROR);
+        if (!epnum)
+            ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
+                            MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
+
+        ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
+        if (!epnum)
+            ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
+        musb_rx_intr_set(s, epnum, 1);
+        return;
+    }
+
+    /* The driver sets maxp[1] to 64 or less because it knows the hardware
+     * FIFO is this deep.  Bigger packets get split in
+     * usb_generic_handle_packet but we can also do the splitting locally
+     * for performance.  It turns out we can also have a bigger FIFO and
+     * ignore the limit set in ep->maxp[1].  The Linux MUSB driver deals
+     * OK with single packets of even 32KB and we avoid splitting, however
+     * usb_msd.c sometimes sends a packet bigger than what Linux expects
+     * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN.  Splitting
+     * hides this overrun from Linux.  Up to 4096 everything is fine
+     * though.  Currently this is disabled.
+     *
+     * XXX: mind ep->fifosize.  */
+    total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
+
+#ifdef SETUPLEN_HACK
+    /* Why should *we* do that instead of Linux?  */
+    if (!epnum) {
+        if (ep->packey[0].p.devaddr == 2) {
+            total = MIN(s->setup_len, 8);
+        } else {
+            total = MIN(s->setup_len, 64);
+        }
+        s->setup_len -= total;
+    }
+#endif
+
+    return musb_packet(s, ep, epnum, USB_TOKEN_IN,
+                    total, musb_rx_packet_complete, 1);
+}
+
+static uint8_t musb_read_fifo(MUSBEndPoint *ep)
+{
+    uint8_t value;
+    if (ep->fifolen[1] >= 64) {
+        /* We have a FIFO underrun */
+        TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
+        return 0x00000000;
+    }
+    /* In DMA mode clear RXPKTRDY and set REQPKT automatically
+     * (if AUTOREQ is set) */
+
+    ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
+    value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
+    TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
+    return value;
+}
+
+static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
+{
+    TRACE("EP%d = %02x", ep->epnum, value);
+    if (ep->fifolen[0] >= 64) {
+        /* We have a FIFO overrun */
+        TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
+        return;
+     }
+
+     ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
+     ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
+}
+
+static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
+{
+    if (ep->intv_timer[dir])
+        qemu_del_timer(ep->intv_timer[dir]);
+}
+
+/* Bus control */
+static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    /* For USB2.0 HS hubs only */
+    case MUSB_HDRC_TXHUBADDR:
+        return s->ep[ep].haddr[0];
+    case MUSB_HDRC_TXHUBPORT:
+        return s->ep[ep].hport[0];
+    case MUSB_HDRC_RXHUBADDR:
+        return s->ep[ep].haddr[1];
+    case MUSB_HDRC_RXHUBPORT:
+        return s->ep[ep].hport[1];
+
+    default:
+        TRACE("unknown register 0x%02x", addr);
+        return 0x00;
+    };
+}
+
+static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXFUNCADDR:
+        s->ep[ep].faddr[0] = value;
+        break;
+    case MUSB_HDRC_RXFUNCADDR:
+        s->ep[ep].faddr[1] = value;
+        break;
+    case MUSB_HDRC_TXHUBADDR:
+        s->ep[ep].haddr[0] = value;
+        break;
+    case MUSB_HDRC_TXHUBPORT:
+        s->ep[ep].hport[0] = value;
+        break;
+    case MUSB_HDRC_RXHUBADDR:
+        s->ep[ep].haddr[1] = value;
+        break;
+    case MUSB_HDRC_RXHUBPORT:
+        s->ep[ep].hport[1] = value;
+        break;
+
+    default:
+        TRACE("unknown register 0x%02x", addr);
+        break;
+    };
+}
+
+static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXFUNCADDR:
+        return s->ep[ep].faddr[0];
+    case MUSB_HDRC_RXFUNCADDR:
+        return s->ep[ep].faddr[1];
+
+    default:
+        return musb_busctl_readb(s, ep, addr) |
+                (musb_busctl_readb(s, ep, addr | 1) << 8);
+    };
+}
+
+static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXFUNCADDR:
+        s->ep[ep].faddr[0] = value;
+        break;
+    case MUSB_HDRC_RXFUNCADDR:
+        s->ep[ep].faddr[1] = value;
+        break;
+
+    default:
+        musb_busctl_writeb(s, ep, addr, value & 0xff);
+        musb_busctl_writeb(s, ep, addr | 1, value >> 8);
+    };
+}
+
+/* Endpoint control */
+static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXTYPE:
+        return s->ep[ep].type[0];
+    case MUSB_HDRC_TXINTERVAL:
+        return s->ep[ep].interval[0];
+    case MUSB_HDRC_RXTYPE:
+        return s->ep[ep].type[1];
+    case MUSB_HDRC_RXINTERVAL:
+        return s->ep[ep].interval[1];
+    case (MUSB_HDRC_FIFOSIZE & ~1):
+        return 0x00;
+    case MUSB_HDRC_FIFOSIZE:
+        return ep ? s->ep[ep].fifosize : s->ep[ep].config;
+    case MUSB_HDRC_RXCOUNT:
+        return s->ep[ep].rxcount;
+
+    default:
+        TRACE("unknown register 0x%02x", addr);
+        return 0x00;
+    };
+}
+
+static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXTYPE:
+        s->ep[ep].type[0] = value;
+        break;
+    case MUSB_HDRC_TXINTERVAL:
+        s->ep[ep].interval[0] = value;
+        musb_ep_frame_cancel(&s->ep[ep], 0);
+        break;
+    case MUSB_HDRC_RXTYPE:
+        s->ep[ep].type[1] = value;
+        break;
+    case MUSB_HDRC_RXINTERVAL:
+        s->ep[ep].interval[1] = value;
+        musb_ep_frame_cancel(&s->ep[ep], 1);
+        break;
+    case (MUSB_HDRC_FIFOSIZE & ~1):
+        break;
+    case MUSB_HDRC_FIFOSIZE:
+        TRACE("somebody messes with fifosize (now %i bytes)", value);
+        s->ep[ep].fifosize = value;
+        break;
+    default:
+        TRACE("unknown register 0x%02x", addr);
+        break;
+    };
+}
+
+static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    uint16_t ret;
+
+    switch (addr) {
+    case MUSB_HDRC_TXMAXP:
+        return s->ep[ep].maxp[0];
+    case MUSB_HDRC_TXCSR:
+        return s->ep[ep].csr[0];
+    case MUSB_HDRC_RXMAXP:
+        return s->ep[ep].maxp[1];
+    case MUSB_HDRC_RXCSR:
+        ret = s->ep[ep].csr[1];
+
+        /* TODO: This and other bits probably depend on
+         * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR.  */
+        if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
+            s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
+
+        return ret;
+    case MUSB_HDRC_RXCOUNT:
+        return s->ep[ep].rxcount;
+
+    default:
+        return musb_ep_readb(s, ep, addr) |
+                (musb_ep_readb(s, ep, addr | 1) << 8);
+    };
+}
+
+static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+
+    switch (addr) {
+    case MUSB_HDRC_TXMAXP:
+        s->ep[ep].maxp[0] = value;
+        break;
+    case MUSB_HDRC_TXCSR:
+        if (ep) {
+            s->ep[ep].csr[0] &= value & 0xa6;
+            s->ep[ep].csr[0] |= value & 0xff59;
+        } else {
+            s->ep[ep].csr[0] &= value & 0x85;
+            s->ep[ep].csr[0] |= value & 0xf7a;
+        }
+
+        musb_ep_frame_cancel(&s->ep[ep], 0);
+
+        if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
+                        (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
+            s->ep[ep].fifolen[0] = 0;
+            s->ep[ep].fifostart[0] = 0;
+            if (ep)
+                s->ep[ep].csr[0] &=
+                        ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
+            else
+                s->ep[ep].csr[0] &=
+                        ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
+        }
+        if (
+                        (ep &&
+#ifdef CLEAR_NAK
+                         (value & MGC_M_TXCSR_TXPKTRDY) &&
+                         !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
+#else
+                         (value & MGC_M_TXCSR_TXPKTRDY)) ||
+#endif
+                        (!ep &&
+#ifdef CLEAR_NAK
+                         (value & MGC_M_CSR0_TXPKTRDY) &&
+                         !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
+#else
+                         (value & MGC_M_CSR0_TXPKTRDY)))
+#endif
+            musb_tx_rdy(s, ep);
+        if (!ep &&
+                        (value & MGC_M_CSR0_H_REQPKT) &&
+#ifdef CLEAR_NAK
+                        !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
+                                        MGC_M_CSR0_RXPKTRDY)))
+#else
+                        !(value & MGC_M_CSR0_RXPKTRDY))
+#endif
+            musb_rx_req(s, ep);
+        break;
+
+    case MUSB_HDRC_RXMAXP:
+        s->ep[ep].maxp[1] = value;
+        break;
+    case MUSB_HDRC_RXCSR:
+        /* (DMA mode only) */
+        if (
+                (value & MGC_M_RXCSR_H_AUTOREQ) &&
+                !(value & MGC_M_RXCSR_RXPKTRDY) &&
+                (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
+            value |= MGC_M_RXCSR_H_REQPKT;
+
+        s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
+        s->ep[ep].csr[1] |= value & 0xfeb0;
+
+        musb_ep_frame_cancel(&s->ep[ep], 1);
+
+        if (value & MGC_M_RXCSR_FLUSHFIFO) {
+            s->ep[ep].fifolen[1] = 0;
+            s->ep[ep].fifostart[1] = 0;
+            s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
+            /* If double buffering and we have two packets ready, flush
+             * only the first one and set up the fifo at the second packet.  */
+        }
+#ifdef CLEAR_NAK
+        if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
+#else
+        if (value & MGC_M_RXCSR_H_REQPKT)
+#endif
+            musb_rx_req(s, ep);
+        break;
+    case MUSB_HDRC_RXCOUNT:
+        s->ep[ep].rxcount = value;
+        break;
+
+    default:
+        musb_ep_writeb(s, ep, addr, value & 0xff);
+        musb_ep_writeb(s, ep, addr | 1, value >> 8);
+    };
+}
+
+/* Generic control */
+static uint32_t musb_readb(void *opaque, target_phys_addr_t addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep, i;
+    uint8_t ret;
+
+    switch (addr) {
+    case MUSB_HDRC_FADDR:
+        return s->faddr;
+    case MUSB_HDRC_POWER:
+        return s->power;
+    case MUSB_HDRC_INTRUSB:
+        ret = s->intr;
+        for (i = 0; i < sizeof(ret) * 8; i ++)
+            if (ret & (1 << i))
+                musb_intr_set(s, i, 0);
+        return ret;
+    case MUSB_HDRC_INTRUSBE:
+        return s->mask;
+    case MUSB_HDRC_INDEX:
+        return s->idx;
+    case MUSB_HDRC_TESTMODE:
+        return 0x00;
+
+    case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
+        return musb_ep_readb(s, s->idx, addr & 0xf);
+
+    case MUSB_HDRC_DEVCTL:
+        return s->devctl;
+
+    case MUSB_HDRC_TXFIFOSZ:
+    case MUSB_HDRC_RXFIFOSZ:
+    case MUSB_HDRC_VCTRL:
+        /* TODO */
+        return 0x00;
+
+    case MUSB_HDRC_HWVERS:
+        return (1 << 10) | 400;
+
+    case (MUSB_HDRC_VCTRL | 1):
+    case (MUSB_HDRC_HWVERS | 1):
+    case (MUSB_HDRC_DEVCTL | 1):
+        return 0x00;
+
+    case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
+        ep = (addr >> 3) & 0xf;
+        return musb_busctl_readb(s, ep, addr & 0x7);
+
+    case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
+        ep = (addr >> 4) & 0xf;
+        return musb_ep_readb(s, ep, addr & 0xf);
+
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return musb_read_fifo(s->ep + ep);
+
+    default:
+        TRACE("unknown register 0x%02x", (int) addr);
+        return 0x00;
+    };
+}
+
+static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep;
+
+    switch (addr) {
+    case MUSB_HDRC_FADDR:
+        s->faddr = value & 0x7f;
+        break;
+    case MUSB_HDRC_POWER:
+        s->power = (value & 0xef) | (s->power & 0x10);
+        /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
+        if ((value & MGC_M_POWER_RESET) && s->port.dev) {
+            usb_send_msg(s->port.dev, USB_MSG_RESET);
+            /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set.  */
+            if ((value & MGC_M_POWER_HSENAB) &&
+                            s->port.dev->speed == USB_SPEED_HIGH)
+                s->power |= MGC_M_POWER_HSMODE;	/* Success */
+            /* Restart frame counting.  */
+        }
+        if (value & MGC_M_POWER_SUSPENDM) {
+            /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
+             * is set, also go into low power mode.  Frame counting stops.  */
+            /* XXX: Cleared when the interrupt register is read */
+        }
+        if (value & MGC_M_POWER_RESUME) {
+            /* Wait 20ms and signal resuming on the bus.  Frame counting
+             * restarts.  */
+        }
+        break;
+    case MUSB_HDRC_INTRUSB:
+        break;
+    case MUSB_HDRC_INTRUSBE:
+        s->mask = value & 0xff;
+        break;
+    case MUSB_HDRC_INDEX:
+        s->idx = value & 0xf;
+        break;
+    case MUSB_HDRC_TESTMODE:
+        break;
+
+    case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
+        musb_ep_writeb(s, s->idx, addr & 0xf, value);
+        break;
+
+    case MUSB_HDRC_DEVCTL:
+        s->session = !!(value & MGC_M_DEVCTL_SESSION);
+        musb_session_update(s,
+                        !!s->port.dev,
+                        !!(s->devctl & MGC_M_DEVCTL_SESSION));
+
+        /* It seems this is the only R/W bit in this register?  */
+        s->devctl &= ~MGC_M_DEVCTL_SESSION;
+        s->devctl |= value & MGC_M_DEVCTL_SESSION;
+        break;
+
+    case MUSB_HDRC_TXFIFOSZ:
+    case MUSB_HDRC_RXFIFOSZ:
+    case MUSB_HDRC_VCTRL:
+        /* TODO */
+        break;
+
+    case (MUSB_HDRC_VCTRL | 1):
+    case (MUSB_HDRC_DEVCTL | 1):
+        break;
+
+    case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
+        ep = (addr >> 3) & 0xf;
+        musb_busctl_writeb(s, ep, addr & 0x7, value);
+        break;
+
+    case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
+        ep = (addr >> 4) & 0xf;
+        musb_ep_writeb(s, ep, addr & 0xf, value);
+        break;
+
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        break;
+
+    default:
+        TRACE("unknown register 0x%02x", (int) addr);
+        break;
+    };
+}
+
+static uint32_t musb_readh(void *opaque, target_phys_addr_t addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep, i;
+    uint16_t ret;
+
+    switch (addr) {
+    case MUSB_HDRC_INTRTX:
+        ret = s->tx_intr;
+        /* Auto clear */
+        for (i = 0; i < sizeof(ret) * 8; i ++)
+            if (ret & (1 << i))
+                musb_tx_intr_set(s, i, 0);
+        return ret;
+    case MUSB_HDRC_INTRRX:
+        ret = s->rx_intr;
+        /* Auto clear */
+        for (i = 0; i < sizeof(ret) * 8; i ++)
+            if (ret & (1 << i))
+                musb_rx_intr_set(s, i, 0);
+        return ret;
+    case MUSB_HDRC_INTRTXE:
+        return s->tx_mask;
+    case MUSB_HDRC_INTRRXE:
+        return s->rx_mask;
+
+    case MUSB_HDRC_FRAME:
+        /* TODO */
+        return 0x0000;
+    case MUSB_HDRC_TXFIFOADDR:
+        return s->ep[s->idx].fifoaddr[0];
+    case MUSB_HDRC_RXFIFOADDR:
+        return s->ep[s->idx].fifoaddr[1];
+
+    case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
+        return musb_ep_readh(s, s->idx, addr & 0xf);
+
+    case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
+        ep = (addr >> 3) & 0xf;
+        return musb_busctl_readh(s, ep, addr & 0x7);
+
+    case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
+        ep = (addr >> 4) & 0xf;
+        return musb_ep_readh(s, ep, addr & 0xf);
+
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
+
+    default:
+        return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
+    };
+}
+
+static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep;
+
+    switch (addr) {
+    case MUSB_HDRC_INTRTXE:
+        s->tx_mask = value;
+        /* XXX: the masks seem to apply on the raising edge like with
+         * edge-triggered interrupts, thus no need to update.  I may be
+         * wrong though.  */
+        break;
+    case MUSB_HDRC_INTRRXE:
+        s->rx_mask = value;
+        break;
+
+    case MUSB_HDRC_FRAME:
+        /* TODO */
+        break;
+    case MUSB_HDRC_TXFIFOADDR:
+        s->ep[s->idx].fifoaddr[0] = value;
+        s->ep[s->idx].buf[0] =
+                s->buf + ((value << 3) & 0x7ff );
+        break;
+    case MUSB_HDRC_RXFIFOADDR:
+        s->ep[s->idx].fifoaddr[1] = value;
+        s->ep[s->idx].buf[1] =
+                s->buf + ((value << 3) & 0x7ff);
+        break;
+
+    case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
+        musb_ep_writeh(s, s->idx, addr & 0xf, value);
+        break;
+
+    case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
+        ep = (addr >> 3) & 0xf;
+        musb_busctl_writeh(s, ep, addr & 0x7, value);
+        break;
+
+    case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
+        ep = (addr >> 4) & 0xf;
+        musb_ep_writeh(s, ep, addr & 0xf, value);
+        break;
+
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
+        break;
+
+    default:
+        musb_writeb(s, addr, value & 0xff);
+        musb_writeb(s, addr | 1, value >> 8);
+    };
+}
+
+static uint32_t musb_readw(void *opaque, target_phys_addr_t addr)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep;
+
+    switch (addr) {
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return ( musb_read_fifo(s->ep + ep)       |
+                 musb_read_fifo(s->ep + ep) << 8  |
+                 musb_read_fifo(s->ep + ep) << 16 |
+                 musb_read_fifo(s->ep + ep) << 24 );
+    default:
+        TRACE("unknown register 0x%02x", (int) addr);
+        return 0x00000000;
+    };
+}
+
+static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MUSBState *s = (MUSBState *) opaque;
+    int ep;
+
+    switch (addr) {
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
+            break;
+    default:
+        TRACE("unknown register 0x%02x", (int) addr);
+        break;
+    };
+}
+
+CPUReadMemoryFunc * const musb_read[] = {
+    musb_readb,
+    musb_readh,
+    musb_readw,
+};
+
+CPUWriteMemoryFunc * const musb_write[] = {
+    musb_writeb,
+    musb_writeh,
+    musb_writew,
+};
diff --git a/qemu-0.15.x/hw/usb-net.c b/qemu-0.15.x/hw/usb-net.c
new file mode 100644
index 0000000..9be709f
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-net.c
@@ -0,0 +1,1441 @@
+/*
+ * QEMU USB Net devices
+ *
+ * Copyright (c) 2006 Thomas Sailer
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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 "qemu-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "net.h"
+#include "qemu-queue.h"
+#include "sysemu.h"
+
+/*#define TRAFFIC_DEBUG*/
+/* Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM          0x0525  /* NetChip */
+#define CDC_PRODUCT_NUM         0xa4a1  /* Linux-USB Ethernet Gadget */
+/* For hardware that can talk RNDIS and either of the above protocols,
+ * use this ID ... the windows INF files will know it.
+ */
+#define RNDIS_VENDOR_NUM        0x0525  /* NetChip */
+#define RNDIS_PRODUCT_NUM       0xa4a2  /* Ethernet/RNDIS Gadget */
+
+enum usbstring_idx {
+    STRING_MANUFACTURER		= 1,
+    STRING_PRODUCT,
+    STRING_ETHADDR,
+    STRING_DATA,
+    STRING_CONTROL,
+    STRING_RNDIS_CONTROL,
+    STRING_CDC,
+    STRING_SUBSET,
+    STRING_RNDIS,
+    STRING_SERIALNUMBER,
+};
+
+#define DEV_CONFIG_VALUE		1	/* CDC or a subset */
+#define DEV_RNDIS_CONFIG_VALUE		2	/* RNDIS; optional */
+
+#define USB_CDC_SUBCLASS_ACM		0x02
+#define USB_CDC_SUBCLASS_ETHERNET	0x06
+
+#define USB_CDC_PROTO_NONE		0
+#define USB_CDC_ACM_PROTO_VENDOR	0xff
+
+#define USB_CDC_HEADER_TYPE		0x00	/* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE	0x01	/* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE		0x02	/* acm_descriptor */
+#define USB_CDC_UNION_TYPE		0x06	/* union_desc */
+#define USB_CDC_ETHERNET_TYPE		0x0f	/* ether_desc */
+
+#define USB_DT_CS_INTERFACE		0x24
+#define USB_DT_CS_ENDPOINT		0x25
+
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
+#define USB_CDC_REQ_SET_LINE_CODING		0x20
+#define USB_CDC_REQ_GET_LINE_CODING		0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
+#define USB_CDC_REQ_SEND_BREAK			0x23
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS	0x40
+#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER	0x41
+#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER	0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER	0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC		0x44
+
+#define LOG2_STATUS_INTERVAL_MSEC	5    /* 1 << 5 == 32 msec */
+#define STATUS_BYTECOUNT		16   /* 8 byte header + data */
+
+#define ETH_FRAME_LEN			1514 /* Max. octets in frame sans FCS */
+
+static const USBDescStrings usb_net_stringtable = {
+    [STRING_MANUFACTURER]       = "QEMU",
+    [STRING_PRODUCT]            = "RNDIS/QEMU USB Network Device",
+    [STRING_ETHADDR]            = "400102030405",
+    [STRING_DATA]               = "QEMU USB Net Data Interface",
+    [STRING_CONTROL]            = "QEMU USB Net Control Interface",
+    [STRING_RNDIS_CONTROL]      = "QEMU USB Net RNDIS Control Interface",
+    [STRING_CDC]                = "QEMU USB Net CDC",
+    [STRING_SUBSET]             = "QEMU USB Net Subset",
+    [STRING_RNDIS]              = "QEMU USB Net RNDIS",
+    [STRING_SERIALNUMBER]       = "1",
+};
+
+static const USBDescIface desc_iface_rndis[] = {
+    {
+        /* RNDIS Control Interface */
+        .bInterfaceNumber              = 0,
+        .bNumEndpoints                 = 1,
+        .bInterfaceClass               = USB_CLASS_COMM,
+        .bInterfaceSubClass            = USB_CDC_SUBCLASS_ACM,
+        .bInterfaceProtocol            = USB_CDC_ACM_PROTO_VENDOR,
+        .iInterface                    = STRING_RNDIS_CONTROL,
+        .ndesc                         = 4,
+        .descs = (USBDescOther[]) {
+            {
+                /* Header Descriptor */
+                .data = (uint8_t[]) {
+                    0x05,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_HEADER_TYPE,        /*  u8    bDescriptorSubType */
+                    0x10, 0x01,                 /*  le16  bcdCDC */
+                },
+            },{
+                /* Call Management Descriptor */
+                .data = (uint8_t[]) {
+                    0x05,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_CALL_MANAGEMENT_TYPE, /*  u8    bDescriptorSubType */
+                    0x00,                       /*  u8    bmCapabilities */
+                    0x01,                       /*  u8    bDataInterface */
+                },
+            },{
+                /* ACM Descriptor */
+                .data = (uint8_t[]) {
+                    0x04,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_ACM_TYPE,           /*  u8    bDescriptorSubType */
+                    0x00,                       /*  u8    bmCapabilities */
+                },
+            },{
+                /* Union Descriptor */
+                .data = (uint8_t[]) {
+                    0x05,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_UNION_TYPE,         /*  u8    bDescriptorSubType */
+                    0x00,                       /*  u8    bMasterInterface0 */
+                    0x01,                       /*  u8    bSlaveInterface0 */
+                },
+            },
+        },
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_IN | 0x01,
+                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .wMaxPacketSize        = STATUS_BYTECOUNT,
+                .bInterval             = 1 << LOG2_STATUS_INTERVAL_MSEC,
+            },
+        }
+    },{
+        /* RNDIS Data Interface */
+        .bInterfaceNumber              = 1,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = USB_CLASS_CDC_DATA,
+        .iInterface                    = STRING_DATA,
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_IN | 0x02,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+            },{
+                .bEndpointAddress      = USB_DIR_OUT | 0x02,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+            }
+        }
+    }
+};
+
+static const USBDescIface desc_iface_cdc[] = {
+    {
+        /* CDC Control Interface */
+        .bInterfaceNumber              = 0,
+        .bNumEndpoints                 = 1,
+        .bInterfaceClass               = USB_CLASS_COMM,
+        .bInterfaceSubClass            = USB_CDC_SUBCLASS_ETHERNET,
+        .bInterfaceProtocol            = USB_CDC_PROTO_NONE,
+        .iInterface                    = STRING_CONTROL,
+        .ndesc                         = 3,
+        .descs = (USBDescOther[]) {
+            {
+                /* Header Descriptor */
+                .data = (uint8_t[]) {
+                    0x05,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_HEADER_TYPE,        /*  u8    bDescriptorSubType */
+                    0x10, 0x01,                 /*  le16  bcdCDC */
+                },
+            },{
+                /* Union Descriptor */
+                .data = (uint8_t[]) {
+                    0x05,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_UNION_TYPE,         /*  u8    bDescriptorSubType */
+                    0x00,                       /*  u8    bMasterInterface0 */
+                    0x01,                       /*  u8    bSlaveInterface0 */
+                },
+            },{
+                /* Ethernet Descriptor */
+                .data = (uint8_t[]) {
+                    0x0d,                       /*  u8    bLength */
+                    USB_DT_CS_INTERFACE,        /*  u8    bDescriptorType */
+                    USB_CDC_ETHERNET_TYPE,      /*  u8    bDescriptorSubType */
+                    STRING_ETHADDR,             /*  u8    iMACAddress */
+                    0x00, 0x00, 0x00, 0x00,     /*  le32  bmEthernetStatistics */
+                    ETH_FRAME_LEN & 0xff,
+                    ETH_FRAME_LEN >> 8,         /*  le16  wMaxSegmentSize */
+                    0x00, 0x00,                 /*  le16  wNumberMCFilters */
+                    0x00,                       /*  u8    bNumberPowerFilters */
+                },
+            },
+        },
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_IN | 0x01,
+                .bmAttributes          = USB_ENDPOINT_XFER_INT,
+                .wMaxPacketSize        = STATUS_BYTECOUNT,
+                .bInterval             = 1 << LOG2_STATUS_INTERVAL_MSEC,
+            },
+        }
+    },{
+        /* CDC Data Interface (off) */
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 0,
+        .bNumEndpoints                 = 0,
+        .bInterfaceClass               = USB_CLASS_CDC_DATA,
+    },{
+        /* CDC Data Interface */
+        .bInterfaceNumber              = 1,
+        .bAlternateSetting             = 1,
+        .bNumEndpoints                 = 2,
+        .bInterfaceClass               = USB_CLASS_CDC_DATA,
+        .iInterface                    = STRING_DATA,
+        .eps = (USBDescEndpoint[]) {
+            {
+                .bEndpointAddress      = USB_DIR_IN | 0x02,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+            },{
+                .bEndpointAddress      = USB_DIR_OUT | 0x02,
+                .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+                .wMaxPacketSize        = 0x40,
+            }
+        }
+    }
+};
+
+static const USBDescDevice desc_device_net = {
+    .bcdUSB                        = 0x0200,
+    .bDeviceClass                  = USB_CLASS_COMM,
+    .bMaxPacketSize0               = 0x40,
+    .bNumConfigurations            = 2,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 2,
+            .bConfigurationValue   = DEV_RNDIS_CONFIG_VALUE,
+            .iConfiguration        = STRING_RNDIS,
+            .bmAttributes          = 0xc0,
+            .bMaxPower             = 0x32,
+            .nif = ARRAY_SIZE(desc_iface_rndis),
+            .ifs = desc_iface_rndis,
+        },{
+            .bNumInterfaces        = 2,
+            .bConfigurationValue   = DEV_CONFIG_VALUE,
+            .iConfiguration        = STRING_CDC,
+            .bmAttributes          = 0xc0,
+            .bMaxPower             = 0x32,
+            .nif = ARRAY_SIZE(desc_iface_cdc),
+            .ifs = desc_iface_cdc,
+        }
+    },
+};
+
+static const USBDesc desc_net = {
+    .id = {
+        .idVendor          = RNDIS_VENDOR_NUM,
+        .idProduct         = RNDIS_PRODUCT_NUM,
+        .bcdDevice         = 0,
+        .iManufacturer     = STRING_MANUFACTURER,
+        .iProduct          = STRING_PRODUCT,
+        .iSerialNumber     = STRING_SERIALNUMBER,
+    },
+    .full = &desc_device_net,
+    .str  = usb_net_stringtable,
+};
+
+/*
+ * RNDIS Definitions - in theory not specific to USB.
+ */
+#define RNDIS_MAXIMUM_FRAME_SIZE	1518
+#define RNDIS_MAX_TOTAL_SIZE		1558
+
+/* Remote NDIS Versions */
+#define RNDIS_MAJOR_VERSION		1
+#define RNDIS_MINOR_VERSION		0
+
+/* Status Values */
+#define RNDIS_STATUS_SUCCESS		0x00000000U /* Success */
+#define RNDIS_STATUS_FAILURE		0xc0000001U /* Unspecified error */
+#define RNDIS_STATUS_INVALID_DATA	0xc0010015U /* Invalid data */
+#define RNDIS_STATUS_NOT_SUPPORTED	0xc00000bbU /* Unsupported request */
+#define RNDIS_STATUS_MEDIA_CONNECT	0x4001000bU /* Device connected */
+#define RNDIS_STATUS_MEDIA_DISCONNECT	0x4001000cU /* Device disconnected */
+
+/* Message Set for Connectionless (802.3) Devices */
+enum {
+    RNDIS_PACKET_MSG		= 1,
+    RNDIS_INITIALIZE_MSG	= 2,	/* Initialize device */
+    RNDIS_HALT_MSG		= 3,
+    RNDIS_QUERY_MSG		= 4,
+    RNDIS_SET_MSG		= 5,
+    RNDIS_RESET_MSG		= 6,
+    RNDIS_INDICATE_STATUS_MSG	= 7,
+    RNDIS_KEEPALIVE_MSG		= 8,
+};
+
+/* Message completion */
+enum {
+    RNDIS_INITIALIZE_CMPLT	= 0x80000002U,
+    RNDIS_QUERY_CMPLT		= 0x80000004U,
+    RNDIS_SET_CMPLT		= 0x80000005U,
+    RNDIS_RESET_CMPLT		= 0x80000006U,
+    RNDIS_KEEPALIVE_CMPLT	= 0x80000008U,
+};
+
+/* Device Flags */
+enum {
+    RNDIS_DF_CONNECTIONLESS	= 1,
+    RNDIS_DF_CONNECTIONORIENTED	= 2,
+};
+
+#define RNDIS_MEDIUM_802_3		0x00000000U
+
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES		0xfd010100
+#define OID_PNP_SET_POWER		0xfd010101
+#define OID_PNP_QUERY_POWER		0xfd010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN	0xfd010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN	0xfd010104
+#define OID_PNP_ENABLE_WAKE_UP		0xfd010106
+
+typedef uint32_t le32;
+
+typedef struct rndis_init_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 MajorVersion;
+    le32 MinorVersion;
+    le32 MaxTransferSize;
+} rndis_init_msg_type;
+
+typedef struct rndis_init_cmplt_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 Status;
+    le32 MajorVersion;
+    le32 MinorVersion;
+    le32 DeviceFlags;
+    le32 Medium;
+    le32 MaxPacketsPerTransfer;
+    le32 MaxTransferSize;
+    le32 PacketAlignmentFactor;
+    le32 AFListOffset;
+    le32 AFListSize;
+} rndis_init_cmplt_type;
+
+typedef struct rndis_halt_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+} rndis_halt_msg_type;
+
+typedef struct rndis_query_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 OID;
+    le32 InformationBufferLength;
+    le32 InformationBufferOffset;
+    le32 DeviceVcHandle;
+} rndis_query_msg_type;
+
+typedef struct rndis_query_cmplt_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 Status;
+    le32 InformationBufferLength;
+    le32 InformationBufferOffset;
+} rndis_query_cmplt_type;
+
+typedef struct rndis_set_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 OID;
+    le32 InformationBufferLength;
+    le32 InformationBufferOffset;
+    le32 DeviceVcHandle;
+} rndis_set_msg_type;
+
+typedef struct rndis_set_cmplt_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 Status;
+} rndis_set_cmplt_type;
+
+typedef struct rndis_reset_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 Reserved;
+} rndis_reset_msg_type;
+
+typedef struct rndis_reset_cmplt_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 Status;
+    le32 AddressingReset;
+} rndis_reset_cmplt_type;
+
+typedef struct rndis_indicate_status_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 Status;
+    le32 StatusBufferLength;
+    le32 StatusBufferOffset;
+} rndis_indicate_status_msg_type;
+
+typedef struct rndis_keepalive_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+} rndis_keepalive_msg_type;
+
+typedef struct rndis_keepalive_cmplt_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 RequestID;
+    le32 Status;
+} rndis_keepalive_cmplt_type;
+
+struct rndis_packet_msg_type {
+    le32 MessageType;
+    le32 MessageLength;
+    le32 DataOffset;
+    le32 DataLength;
+    le32 OOBDataOffset;
+    le32 OOBDataLength;
+    le32 NumOOBDataElements;
+    le32 PerPacketInfoOffset;
+    le32 PerPacketInfoLength;
+    le32 VcHandle;
+    le32 Reserved;
+};
+
+struct rndis_config_parameter {
+    le32 ParameterNameOffset;
+    le32 ParameterNameLength;
+    le32 ParameterType;
+    le32 ParameterValueOffset;
+    le32 ParameterValueLength;
+};
+
+/* implementation specific */
+enum rndis_state
+{
+    RNDIS_UNINITIALIZED,
+    RNDIS_INITIALIZED,
+    RNDIS_DATA_INITIALIZED,
+};
+
+/* from ndis.h */
+enum ndis_oid {
+    /* Required Object IDs (OIDs) */
+    OID_GEN_SUPPORTED_LIST		= 0x00010101,
+    OID_GEN_HARDWARE_STATUS		= 0x00010102,
+    OID_GEN_MEDIA_SUPPORTED		= 0x00010103,
+    OID_GEN_MEDIA_IN_USE		= 0x00010104,
+    OID_GEN_MAXIMUM_LOOKAHEAD		= 0x00010105,
+    OID_GEN_MAXIMUM_FRAME_SIZE		= 0x00010106,
+    OID_GEN_LINK_SPEED			= 0x00010107,
+    OID_GEN_TRANSMIT_BUFFER_SPACE	= 0x00010108,
+    OID_GEN_RECEIVE_BUFFER_SPACE	= 0x00010109,
+    OID_GEN_TRANSMIT_BLOCK_SIZE		= 0x0001010a,
+    OID_GEN_RECEIVE_BLOCK_SIZE		= 0x0001010b,
+    OID_GEN_VENDOR_ID			= 0x0001010c,
+    OID_GEN_VENDOR_DESCRIPTION		= 0x0001010d,
+    OID_GEN_CURRENT_PACKET_FILTER	= 0x0001010e,
+    OID_GEN_CURRENT_LOOKAHEAD		= 0x0001010f,
+    OID_GEN_DRIVER_VERSION		= 0x00010110,
+    OID_GEN_MAXIMUM_TOTAL_SIZE		= 0x00010111,
+    OID_GEN_PROTOCOL_OPTIONS		= 0x00010112,
+    OID_GEN_MAC_OPTIONS			= 0x00010113,
+    OID_GEN_MEDIA_CONNECT_STATUS	= 0x00010114,
+    OID_GEN_MAXIMUM_SEND_PACKETS	= 0x00010115,
+    OID_GEN_VENDOR_DRIVER_VERSION	= 0x00010116,
+    OID_GEN_SUPPORTED_GUIDS		= 0x00010117,
+    OID_GEN_NETWORK_LAYER_ADDRESSES	= 0x00010118,
+    OID_GEN_TRANSPORT_HEADER_OFFSET	= 0x00010119,
+    OID_GEN_MACHINE_NAME		= 0x0001021a,
+    OID_GEN_RNDIS_CONFIG_PARAMETER	= 0x0001021b,
+    OID_GEN_VLAN_ID			= 0x0001021c,
+
+    /* Optional OIDs */
+    OID_GEN_MEDIA_CAPABILITIES		= 0x00010201,
+    OID_GEN_PHYSICAL_MEDIUM		= 0x00010202,
+
+    /* Required statistics OIDs */
+    OID_GEN_XMIT_OK			= 0x00020101,
+    OID_GEN_RCV_OK			= 0x00020102,
+    OID_GEN_XMIT_ERROR			= 0x00020103,
+    OID_GEN_RCV_ERROR			= 0x00020104,
+    OID_GEN_RCV_NO_BUFFER		= 0x00020105,
+
+    /* Optional statistics OIDs */
+    OID_GEN_DIRECTED_BYTES_XMIT		= 0x00020201,
+    OID_GEN_DIRECTED_FRAMES_XMIT	= 0x00020202,
+    OID_GEN_MULTICAST_BYTES_XMIT	= 0x00020203,
+    OID_GEN_MULTICAST_FRAMES_XMIT	= 0x00020204,
+    OID_GEN_BROADCAST_BYTES_XMIT	= 0x00020205,
+    OID_GEN_BROADCAST_FRAMES_XMIT	= 0x00020206,
+    OID_GEN_DIRECTED_BYTES_RCV		= 0x00020207,
+    OID_GEN_DIRECTED_FRAMES_RCV		= 0x00020208,
+    OID_GEN_MULTICAST_BYTES_RCV		= 0x00020209,
+    OID_GEN_MULTICAST_FRAMES_RCV	= 0x0002020a,
+    OID_GEN_BROADCAST_BYTES_RCV		= 0x0002020b,
+    OID_GEN_BROADCAST_FRAMES_RCV	= 0x0002020c,
+    OID_GEN_RCV_CRC_ERROR		= 0x0002020d,
+    OID_GEN_TRANSMIT_QUEUE_LENGTH	= 0x0002020e,
+    OID_GEN_GET_TIME_CAPS		= 0x0002020f,
+    OID_GEN_GET_NETCARD_TIME		= 0x00020210,
+    OID_GEN_NETCARD_LOAD		= 0x00020211,
+    OID_GEN_DEVICE_PROFILE		= 0x00020212,
+    OID_GEN_INIT_TIME_MS		= 0x00020213,
+    OID_GEN_RESET_COUNTS		= 0x00020214,
+    OID_GEN_MEDIA_SENSE_COUNTS		= 0x00020215,
+    OID_GEN_FRIENDLY_NAME		= 0x00020216,
+    OID_GEN_MINIPORT_INFO		= 0x00020217,
+    OID_GEN_RESET_VERIFY_PARAMETERS	= 0x00020218,
+
+    /* IEEE 802.3 (Ethernet) OIDs */
+    OID_802_3_PERMANENT_ADDRESS		= 0x01010101,
+    OID_802_3_CURRENT_ADDRESS		= 0x01010102,
+    OID_802_3_MULTICAST_LIST		= 0x01010103,
+    OID_802_3_MAXIMUM_LIST_SIZE		= 0x01010104,
+    OID_802_3_MAC_OPTIONS		= 0x01010105,
+    OID_802_3_RCV_ERROR_ALIGNMENT	= 0x01020101,
+    OID_802_3_XMIT_ONE_COLLISION	= 0x01020102,
+    OID_802_3_XMIT_MORE_COLLISIONS	= 0x01020103,
+    OID_802_3_XMIT_DEFERRED		= 0x01020201,
+    OID_802_3_XMIT_MAX_COLLISIONS	= 0x01020202,
+    OID_802_3_RCV_OVERRUN		= 0x01020203,
+    OID_802_3_XMIT_UNDERRUN		= 0x01020204,
+    OID_802_3_XMIT_HEARTBEAT_FAILURE	= 0x01020205,
+    OID_802_3_XMIT_TIMES_CRS_LOST	= 0x01020206,
+    OID_802_3_XMIT_LATE_COLLISIONS	= 0x01020207,
+};
+
+static const uint32_t oid_supported_list[] =
+{
+    /* the general stuff */
+    OID_GEN_SUPPORTED_LIST,
+    OID_GEN_HARDWARE_STATUS,
+    OID_GEN_MEDIA_SUPPORTED,
+    OID_GEN_MEDIA_IN_USE,
+    OID_GEN_MAXIMUM_FRAME_SIZE,
+    OID_GEN_LINK_SPEED,
+    OID_GEN_TRANSMIT_BLOCK_SIZE,
+    OID_GEN_RECEIVE_BLOCK_SIZE,
+    OID_GEN_VENDOR_ID,
+    OID_GEN_VENDOR_DESCRIPTION,
+    OID_GEN_VENDOR_DRIVER_VERSION,
+    OID_GEN_CURRENT_PACKET_FILTER,
+    OID_GEN_MAXIMUM_TOTAL_SIZE,
+    OID_GEN_MEDIA_CONNECT_STATUS,
+    OID_GEN_PHYSICAL_MEDIUM,
+
+    /* the statistical stuff */
+    OID_GEN_XMIT_OK,
+    OID_GEN_RCV_OK,
+    OID_GEN_XMIT_ERROR,
+    OID_GEN_RCV_ERROR,
+    OID_GEN_RCV_NO_BUFFER,
+
+    /* IEEE 802.3 */
+    /* the general stuff */
+    OID_802_3_PERMANENT_ADDRESS,
+    OID_802_3_CURRENT_ADDRESS,
+    OID_802_3_MULTICAST_LIST,
+    OID_802_3_MAC_OPTIONS,
+    OID_802_3_MAXIMUM_LIST_SIZE,
+
+    /* the statistical stuff */
+    OID_802_3_RCV_ERROR_ALIGNMENT,
+    OID_802_3_XMIT_ONE_COLLISION,
+    OID_802_3_XMIT_MORE_COLLISIONS,
+};
+
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA	(1 << 0)
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED	(1 << 1)
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND	(1 << 2)
+#define NDIS_MAC_OPTION_NO_LOOPBACK		(1 << 3)
+#define NDIS_MAC_OPTION_FULL_DUPLEX		(1 << 4)
+#define NDIS_MAC_OPTION_EOTX_INDICATION		(1 << 5)
+#define NDIS_MAC_OPTION_8021P_PRIORITY		(1 << 6)
+
+struct rndis_response {
+    QTAILQ_ENTRY(rndis_response) entries;
+    uint32_t length;
+    uint8_t buf[0];
+};
+
+typedef struct USBNetState {
+    USBDevice dev;
+
+    enum rndis_state rndis_state;
+    uint32_t medium;
+    uint32_t speed;
+    uint32_t media_state;
+    uint16_t filter;
+    uint32_t vendorid;
+
+    unsigned int out_ptr;
+    uint8_t out_buf[2048];
+
+    USBPacket *inpkt;
+    unsigned int in_ptr, in_len;
+    uint8_t in_buf[2048];
+
+    char usbstring_mac[13];
+    NICState *nic;
+    NICConf conf;
+    QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
+} USBNetState;
+
+static int is_rndis(USBNetState *s)
+{
+    return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
+}
+
+static int ndis_query(USBNetState *s, uint32_t oid,
+                      uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
+                      size_t outlen)
+{
+    unsigned int i;
+
+    switch (oid) {
+    /* general oids (table 4-1) */
+    /* mandatory */
+    case OID_GEN_SUPPORTED_LIST:
+        for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
+            ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
+        return sizeof(oid_supported_list);
+
+    /* mandatory */
+    case OID_GEN_HARDWARE_STATUS:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_MEDIA_SUPPORTED:
+        *((le32 *) outbuf) = cpu_to_le32(s->medium);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_MEDIA_IN_USE:
+        *((le32 *) outbuf) = cpu_to_le32(s->medium);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_MAXIMUM_FRAME_SIZE:
+        *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_LINK_SPEED:
+        *((le32 *) outbuf) = cpu_to_le32(s->speed);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_TRANSMIT_BLOCK_SIZE:
+        *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_RECEIVE_BLOCK_SIZE:
+        *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_VENDOR_ID:
+        *((le32 *) outbuf) = cpu_to_le32(s->vendorid);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_VENDOR_DESCRIPTION:
+        pstrcpy((char *)outbuf, outlen, "QEMU USB RNDIS Net");
+        return strlen((char *)outbuf) + 1;
+
+    case OID_GEN_VENDOR_DRIVER_VERSION:
+        *((le32 *) outbuf) = cpu_to_le32(1);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_CURRENT_PACKET_FILTER:
+        *((le32 *) outbuf) = cpu_to_le32(s->filter);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_MAXIMUM_TOTAL_SIZE:
+        *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_MEDIA_CONNECT_STATUS:
+        *((le32 *) outbuf) = cpu_to_le32(s->media_state);
+        return sizeof(le32);
+
+    case OID_GEN_PHYSICAL_MEDIUM:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    case OID_GEN_MAC_OPTIONS:
+        *((le32 *) outbuf) = cpu_to_le32(
+                        NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+                        NDIS_MAC_OPTION_FULL_DUPLEX);
+        return sizeof(le32);
+
+    /* statistics OIDs (table 4-2) */
+    /* mandatory */
+    case OID_GEN_XMIT_OK:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_RCV_OK:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_XMIT_ERROR:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_RCV_ERROR:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_GEN_RCV_NO_BUFFER:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* ieee802.3 OIDs (table 4-3) */
+    /* mandatory */
+    case OID_802_3_PERMANENT_ADDRESS:
+        memcpy(outbuf, s->conf.macaddr.a, 6);
+        return 6;
+
+    /* mandatory */
+    case OID_802_3_CURRENT_ADDRESS:
+        memcpy(outbuf, s->conf.macaddr.a, 6);
+        return 6;
+
+    /* mandatory */
+    case OID_802_3_MULTICAST_LIST:
+        *((le32 *) outbuf) = cpu_to_le32(0xe0000000);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_802_3_MAXIMUM_LIST_SIZE:
+        *((le32 *) outbuf) = cpu_to_le32(1);
+        return sizeof(le32);
+
+    case OID_802_3_MAC_OPTIONS:
+        return 0;
+
+    /* ieee802.3 statistics OIDs (table 4-4) */
+    /* mandatory */
+    case OID_802_3_RCV_ERROR_ALIGNMENT:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_802_3_XMIT_ONE_COLLISION:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    /* mandatory */
+    case OID_802_3_XMIT_MORE_COLLISIONS:
+        *((le32 *) outbuf) = cpu_to_le32(0);
+        return sizeof(le32);
+
+    default:
+        fprintf(stderr, "usbnet: unknown OID 0x%08x\n", oid);
+        return 0;
+    }
+    return -1;
+}
+
+static int ndis_set(USBNetState *s, uint32_t oid,
+                uint8_t *inbuf, unsigned int inlen)
+{
+    switch (oid) {
+    case OID_GEN_CURRENT_PACKET_FILTER:
+        s->filter = le32_to_cpup((le32 *) inbuf);
+        if (s->filter) {
+            s->rndis_state = RNDIS_DATA_INITIALIZED;
+        } else {
+            s->rndis_state = RNDIS_INITIALIZED;
+        }
+        return 0;
+
+    case OID_802_3_MULTICAST_LIST:
+        return 0;
+    }
+    return -1;
+}
+
+static int rndis_get_response(USBNetState *s, uint8_t *buf)
+{
+    int ret = 0;
+    struct rndis_response *r = s->rndis_resp.tqh_first;
+
+    if (!r)
+        return ret;
+
+    QTAILQ_REMOVE(&s->rndis_resp, r, entries);
+    ret = r->length;
+    memcpy(buf, r->buf, r->length);
+    qemu_free(r);
+
+    return ret;
+}
+
+static void *rndis_queue_response(USBNetState *s, unsigned int length)
+{
+    struct rndis_response *r =
+            qemu_mallocz(sizeof(struct rndis_response) + length);
+
+    QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
+    r->length = length;
+
+    return &r->buf[0];
+}
+
+static void rndis_clear_responsequeue(USBNetState *s)
+{
+    struct rndis_response *r;
+
+    while ((r = s->rndis_resp.tqh_first)) {
+        QTAILQ_REMOVE(&s->rndis_resp, r, entries);
+        qemu_free(r);
+    }
+}
+
+static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf)
+{
+    rndis_init_cmplt_type *resp =
+            rndis_queue_response(s, sizeof(rndis_init_cmplt_type));
+
+    if (!resp)
+        return USB_RET_STALL;
+
+    resp->MessageType = cpu_to_le32(RNDIS_INITIALIZE_CMPLT);
+    resp->MessageLength = cpu_to_le32(sizeof(rndis_init_cmplt_type));
+    resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+    resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+    resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
+    resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
+    resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
+    resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
+    resp->MaxPacketsPerTransfer = cpu_to_le32(1);
+    resp->MaxTransferSize = cpu_to_le32(ETH_FRAME_LEN +
+                    sizeof(struct rndis_packet_msg_type) + 22);
+    resp->PacketAlignmentFactor = cpu_to_le32(0);
+    resp->AFListOffset = cpu_to_le32(0);
+    resp->AFListSize = cpu_to_le32(0);
+    return 0;
+}
+
+static int rndis_query_response(USBNetState *s,
+                rndis_query_msg_type *buf, unsigned int length)
+{
+    rndis_query_cmplt_type *resp;
+    /* oid_supported_list is the largest data reply */
+    uint8_t infobuf[sizeof(oid_supported_list)];
+    uint32_t bufoffs, buflen;
+    int infobuflen;
+    unsigned int resplen;
+
+    bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
+    buflen = le32_to_cpu(buf->InformationBufferLength);
+    if (bufoffs + buflen > length)
+        return USB_RET_STALL;
+
+    infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
+                            bufoffs + (uint8_t *) buf, buflen, infobuf,
+                            sizeof(infobuf));
+    resplen = sizeof(rndis_query_cmplt_type) +
+            ((infobuflen < 0) ? 0 : infobuflen);
+    resp = rndis_queue_response(s, resplen);
+    if (!resp)
+        return USB_RET_STALL;
+
+    resp->MessageType = cpu_to_le32(RNDIS_QUERY_CMPLT);
+    resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+    resp->MessageLength = cpu_to_le32(resplen);
+
+    if (infobuflen < 0) {
+        /* OID not supported */
+        resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+        resp->InformationBufferLength = cpu_to_le32(0);
+        resp->InformationBufferOffset = cpu_to_le32(0);
+        return 0;
+    }
+
+    resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+    resp->InformationBufferOffset =
+            cpu_to_le32(infobuflen ? sizeof(rndis_query_cmplt_type) - 8 : 0);
+    resp->InformationBufferLength = cpu_to_le32(infobuflen);
+    memcpy(resp + 1, infobuf, infobuflen);
+
+    return 0;
+}
+
+static int rndis_set_response(USBNetState *s,
+                rndis_set_msg_type *buf, unsigned int length)
+{
+    rndis_set_cmplt_type *resp =
+            rndis_queue_response(s, sizeof(rndis_set_cmplt_type));
+    uint32_t bufoffs, buflen;
+    int ret;
+
+    if (!resp)
+        return USB_RET_STALL;
+
+    bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
+    buflen = le32_to_cpu(buf->InformationBufferLength);
+    if (bufoffs + buflen > length)
+        return USB_RET_STALL;
+
+    ret = ndis_set(s, le32_to_cpu(buf->OID),
+                    bufoffs + (uint8_t *) buf, buflen);
+    resp->MessageType = cpu_to_le32(RNDIS_SET_CMPLT);
+    resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+    resp->MessageLength = cpu_to_le32(sizeof(rndis_set_cmplt_type));
+    if (ret < 0) {
+        /* OID not supported */
+        resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+        return 0;
+    }
+    resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+    return 0;
+}
+
+static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
+{
+    rndis_reset_cmplt_type *resp =
+            rndis_queue_response(s, sizeof(rndis_reset_cmplt_type));
+
+    if (!resp)
+        return USB_RET_STALL;
+
+    resp->MessageType = cpu_to_le32(RNDIS_RESET_CMPLT);
+    resp->MessageLength = cpu_to_le32(sizeof(rndis_reset_cmplt_type));
+    resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+    resp->AddressingReset = cpu_to_le32(1); /* reset information */
+
+    return 0;
+}
+
+static int rndis_keepalive_response(USBNetState *s,
+                rndis_keepalive_msg_type *buf)
+{
+    rndis_keepalive_cmplt_type *resp =
+            rndis_queue_response(s, sizeof(rndis_keepalive_cmplt_type));
+
+    if (!resp)
+        return USB_RET_STALL;
+
+    resp->MessageType = cpu_to_le32(RNDIS_KEEPALIVE_CMPLT);
+    resp->MessageLength = cpu_to_le32(sizeof(rndis_keepalive_cmplt_type));
+    resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+    resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+    return 0;
+}
+
+static int rndis_parse(USBNetState *s, uint8_t *data, int length)
+{
+    uint32_t msg_type;
+    le32 *tmp = (le32 *) data;
+
+    msg_type = le32_to_cpup(tmp);
+
+    switch (msg_type) {
+    case RNDIS_INITIALIZE_MSG:
+        s->rndis_state = RNDIS_INITIALIZED;
+        return rndis_init_response(s, (rndis_init_msg_type *) data);
+
+    case RNDIS_HALT_MSG:
+        s->rndis_state = RNDIS_UNINITIALIZED;
+        return 0;
+
+    case RNDIS_QUERY_MSG:
+        return rndis_query_response(s, (rndis_query_msg_type *) data, length);
+
+    case RNDIS_SET_MSG:
+        return rndis_set_response(s, (rndis_set_msg_type *) data, length);
+
+    case RNDIS_RESET_MSG:
+        rndis_clear_responsequeue(s);
+        s->out_ptr = s->in_ptr = s->in_len = 0;
+        return rndis_reset_response(s, (rndis_reset_msg_type *) data);
+
+    case RNDIS_KEEPALIVE_MSG:
+        /* For USB: host does this every 5 seconds */
+        return rndis_keepalive_response(s, (rndis_keepalive_msg_type *) data);
+    }
+
+    return USB_RET_STALL;
+}
+
+static void usb_net_handle_reset(USBDevice *dev)
+{
+}
+
+static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBNetState *s = (USBNetState *) dev;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ret = 0;
+    switch(request) {
+    case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
+        if (!is_rndis(s) || value || index != 0) {
+            goto fail;
+        }
+#ifdef TRAFFIC_DEBUG
+        {
+            unsigned int i;
+            fprintf(stderr, "SEND_ENCAPSULATED_COMMAND:");
+            for (i = 0; i < length; i++) {
+                if (!(i & 15))
+                    fprintf(stderr, "\n%04x:", i);
+                fprintf(stderr, " %02x", data[i]);
+            }
+            fprintf(stderr, "\n\n");
+        }
+#endif
+        ret = rndis_parse(s, data, length);
+        break;
+
+    case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
+        if (!is_rndis(s) || value || index != 0) {
+            goto fail;
+        }
+        ret = rndis_get_response(s, data);
+        if (!ret) {
+            data[0] = 0;
+            ret = 1;
+        }
+#ifdef TRAFFIC_DEBUG
+        {
+            unsigned int i;
+            fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
+            for (i = 0; i < ret; i++) {
+                if (!(i & 15))
+                    fprintf(stderr, "\n%04x:", i);
+                fprintf(stderr, " %02x", data[i]);
+            }
+            fprintf(stderr, "\n\n");
+        }
+#endif
+        break;
+
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+    case InterfaceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+
+    default:
+    fail:
+        fprintf(stderr, "usbnet: failed control transaction: "
+                        "request 0x%x value 0x%x index 0x%x length 0x%x\n",
+                        request, value, index, length);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
+{
+    int ret = 8;
+
+    if (p->len < 8)
+        return USB_RET_STALL;
+
+    ((le32 *) p->data)[0] = cpu_to_le32(1);
+    ((le32 *) p->data)[1] = cpu_to_le32(0);
+    if (!s->rndis_resp.tqh_first)
+        ret = USB_RET_NAK;
+
+#ifdef TRAFFIC_DEBUG
+    fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret);
+    {
+        int i;
+        fprintf(stderr, ":");
+        for (i = 0; i < ret; i++) {
+            if (!(i & 15))
+                fprintf(stderr, "\n%04x:", i);
+            fprintf(stderr, " %02x", p->data[i]);
+        }
+        fprintf(stderr, "\n\n");
+    }
+#endif
+
+    return ret;
+}
+
+static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
+{
+    int ret = USB_RET_NAK;
+
+    if (s->in_ptr > s->in_len) {
+        s->in_ptr = s->in_len = 0;
+        ret = USB_RET_NAK;
+        return ret;
+    }
+    if (!s->in_len) {
+        ret = USB_RET_NAK;
+        return ret;
+    }
+    ret = s->in_len - s->in_ptr;
+    if (ret > p->len)
+        ret = p->len;
+    memcpy(p->data, &s->in_buf[s->in_ptr], ret);
+    s->in_ptr += ret;
+    if (s->in_ptr >= s->in_len &&
+                    (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
+        /* no short packet necessary */
+        s->in_ptr = s->in_len = 0;
+    }
+
+#ifdef TRAFFIC_DEBUG
+    fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret);
+    {
+        int i;
+        fprintf(stderr, ":");
+        for (i = 0; i < ret; i++) {
+            if (!(i & 15))
+                fprintf(stderr, "\n%04x:", i);
+            fprintf(stderr, " %02x", p->data[i]);
+        }
+        fprintf(stderr, "\n\n");
+    }
+#endif
+
+    return ret;
+}
+
+static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
+{
+    int ret = p->len;
+    int sz = sizeof(s->out_buf) - s->out_ptr;
+    struct rndis_packet_msg_type *msg =
+            (struct rndis_packet_msg_type *) s->out_buf;
+    uint32_t len;
+
+#ifdef TRAFFIC_DEBUG
+    fprintf(stderr, "usbnet: data out len %u\n", p->len);
+    {
+        int i;
+        fprintf(stderr, ":");
+        for (i = 0; i < p->len; i++) {
+            if (!(i & 15))
+                fprintf(stderr, "\n%04x:", i);
+            fprintf(stderr, " %02x", p->data[i]);
+        }
+        fprintf(stderr, "\n\n");
+    }
+#endif
+
+    if (sz > ret)
+        sz = ret;
+    memcpy(&s->out_buf[s->out_ptr], p->data, sz);
+    s->out_ptr += sz;
+
+    if (!is_rndis(s)) {
+        if (ret < 64) {
+            qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
+            s->out_ptr = 0;
+        }
+        return ret;
+    }
+    len = le32_to_cpu(msg->MessageLength);
+    if (s->out_ptr < 8 || s->out_ptr < len)
+        return ret;
+    if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
+        uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
+        uint32_t size = le32_to_cpu(msg->DataLength);
+        if (offs + size <= len)
+            qemu_send_packet(&s->nic->nc, s->out_buf + offs, size);
+    }
+    s->out_ptr -= len;
+    memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
+
+    return ret;
+}
+
+static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBNetState *s = (USBNetState *) dev;
+    int ret = 0;
+
+    switch(p->pid) {
+    case USB_TOKEN_IN:
+        switch (p->devep) {
+        case 1:
+            ret = usb_net_handle_statusin(s, p);
+            break;
+
+        case 2:
+            ret = usb_net_handle_datain(s, p);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case USB_TOKEN_OUT:
+        switch (p->devep) {
+        case 2:
+            ret = usb_net_handle_dataout(s, p);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    if (ret == USB_RET_STALL)
+        fprintf(stderr, "usbnet: failed data transaction: "
+                        "pid 0x%x ep 0x%x len 0x%x\n",
+                        p->pid, p->devep, p->len);
+    return ret;
+}
+
+static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    struct rndis_packet_msg_type *msg;
+
+    if (is_rndis(s)) {
+        msg = (struct rndis_packet_msg_type *) s->in_buf;
+        if (!s->rndis_state == RNDIS_DATA_INITIALIZED)
+            return -1;
+        if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
+            return -1;
+
+        memset(msg, 0, sizeof(struct rndis_packet_msg_type));
+        msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
+        msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type));
+        msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8);
+        msg->DataLength = cpu_to_le32(size);
+        /* msg->OOBDataOffset;
+         * msg->OOBDataLength;
+         * msg->NumOOBDataElements;
+         * msg->PerPacketInfoOffset;
+         * msg->PerPacketInfoLength;
+         * msg->VcHandle;
+         * msg->Reserved;
+         */
+        memcpy(msg + 1, buf, size);
+        s->in_len = size + sizeof(struct rndis_packet_msg_type);
+    } else {
+        if (size > sizeof(s->in_buf))
+            return -1;
+        memcpy(s->in_buf, buf, size);
+        s->in_len = size;
+    }
+    s->in_ptr = 0;
+    return size;
+}
+
+static int usbnet_can_receive(VLANClientState *nc)
+{
+    USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) {
+        return 1;
+    }
+
+    return !s->in_len;
+}
+
+static void usbnet_cleanup(VLANClientState *nc)
+{
+    USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static void usb_net_handle_destroy(USBDevice *dev)
+{
+    USBNetState *s = (USBNetState *) dev;
+
+    /* TODO: remove the nd_table[] entry */
+    rndis_clear_responsequeue(s);
+    qemu_del_vlan_client(&s->nic->nc);
+}
+
+static NetClientInfo net_usbnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = usbnet_can_receive,
+    .receive = usbnet_receive,
+    .cleanup = usbnet_cleanup,
+};
+
+static int usb_net_initfn(USBDevice *dev)
+{
+    USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
+
+    usb_desc_init(dev);
+
+    s->rndis_state = RNDIS_UNINITIALIZED;
+    QTAILQ_INIT(&s->rndis_resp);
+
+    s->medium = 0;	/* NDIS_MEDIUM_802_3 */
+    s->speed = 1000000; /* 100MBps, in 100Bps units */
+    s->media_state = 0;	/* NDIS_MEDIA_STATE_CONNECTED */;
+    s->filter = 0;
+    s->vendorid = 0x1234;
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
+                          s->dev.qdev.info->name, s->dev.qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
+             "%02x%02x%02x%02x%02x%02x",
+             0x40,
+             s->conf.macaddr.a[1],
+             s->conf.macaddr.a[2],
+             s->conf.macaddr.a[3],
+             s->conf.macaddr.a[4],
+             s->conf.macaddr.a[5]);
+    usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac);
+
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet at 0");
+    return 0;
+}
+
+static USBDevice *usb_net_init(const char *cmdline)
+{
+    USBDevice *dev;
+    QemuOpts *opts;
+    int idx;
+
+    opts = qemu_opts_parse(qemu_find_opts("net"), cmdline, 0);
+    if (!opts) {
+        return NULL;
+    }
+    qemu_opt_set(opts, "type", "nic");
+    qemu_opt_set(opts, "model", "usb");
+
+    idx = net_client_init(NULL, opts, 0);
+    if (idx == -1) {
+        return NULL;
+    }
+
+    dev = usb_create(NULL /* FIXME */, "usb-net");
+    if (!dev) {
+        return NULL;
+    }
+    qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+}
+
+static struct USBDeviceInfo net_info = {
+    .product_desc   = "QEMU USB Network Interface",
+    .qdev.name      = "usb-net",
+    .qdev.fw_name    = "network",
+    .qdev.size      = sizeof(USBNetState),
+    .usb_desc       = &desc_net,
+    .init           = usb_net_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_net_handle_reset,
+    .handle_control = usb_net_handle_control,
+    .handle_data    = usb_net_handle_data,
+    .handle_destroy = usb_net_handle_destroy,
+    .usbdevice_name = "net",
+    .usbdevice_init = usb_net_init,
+    .qdev.props     = (Property[]) {
+        DEFINE_NIC_PROPERTIES(USBNetState, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void usb_net_register_devices(void)
+{
+    usb_qdev_register(&net_info);
+}
+device_init(usb_net_register_devices)
diff --git a/qemu-0.15.x/hw/usb-ohci.c b/qemu-0.15.x/hw/usb-ohci.c
new file mode 100644
index 0000000..8491d59
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-ohci.c
@@ -0,0 +1,1863 @@
+/*
+ * QEMU USB OHCI Emulation
+ * Copyright (c) 2004 Gianni Tedesco
+ * Copyright (c) 2006 CodeSourcery
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * TODO:
+ *  o Isochronous transfers
+ *  o Allocate bandwidth in frames properly
+ *  o Disable timers when nothing needs to be done, or remove timer usage
+ *    all together.
+ *  o Handle unrecoverable errors properly
+ *  o BIOS work to boot from USB storage
+*/
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "usb-ohci.h"
+#include "sysbus.h"
+#include "qdev-addr.h"
+
+//#define DEBUG_OHCI
+/* Dump packet contents.  */
+//#define DEBUG_PACKET
+//#define DEBUG_ISOCH
+/* This causes frames to occur 1000x slower */
+//#define OHCI_TIME_WARP 1
+
+#ifdef DEBUG_OHCI
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+/* Number of Downstream Ports on the root hub.  */
+
+#define OHCI_MAX_PORTS 15
+
+static int64_t usb_frame_time;
+static int64_t usb_bit_time;
+
+typedef struct OHCIPort {
+    USBPort port;
+    uint32_t ctrl;
+} OHCIPort;
+
+typedef struct {
+    USBBus bus;
+    qemu_irq irq;
+    int mem;
+    int num_ports;
+    const char *name;
+
+    QEMUTimer *eof_timer;
+    int64_t sof_time;
+
+    /* OHCI state */
+    /* Control partition */
+    uint32_t ctl, status;
+    uint32_t intr_status;
+    uint32_t intr;
+
+    /* memory pointer partition */
+    uint32_t hcca;
+    uint32_t ctrl_head, ctrl_cur;
+    uint32_t bulk_head, bulk_cur;
+    uint32_t per_cur;
+    uint32_t done;
+    int done_count;
+
+    /* Frame counter partition */
+    uint32_t fsmps:15;
+    uint32_t fit:1;
+    uint32_t fi:14;
+    uint32_t frt:1;
+    uint16_t frame_number;
+    uint16_t padding;
+    uint32_t pstart;
+    uint32_t lst;
+
+    /* Root Hub partition */
+    uint32_t rhdesc_a, rhdesc_b;
+    uint32_t rhstatus;
+    OHCIPort rhport[OHCI_MAX_PORTS];
+
+    /* PXA27x Non-OHCI events */
+    uint32_t hstatus;
+    uint32_t hmask;
+    uint32_t hreset;
+    uint32_t htest;
+
+    /* SM501 local memory offset */
+    target_phys_addr_t localmem_base;
+
+    /* Active packets.  */
+    uint32_t old_ctl;
+    USBPacket usb_packet;
+    uint8_t usb_buf[8192];
+    uint32_t async_td;
+    int async_complete;
+
+} OHCIState;
+
+/* Host Controller Communications Area */
+struct ohci_hcca {
+    uint32_t intr[32];
+    uint16_t frame, pad;
+    uint32_t done;
+};
+
+static void ohci_bus_stop(OHCIState *ohci);
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
+
+/* Bitfields for the first word of an Endpoint Desciptor.  */
+#define OHCI_ED_FA_SHIFT  0
+#define OHCI_ED_FA_MASK   (0x7f<<OHCI_ED_FA_SHIFT)
+#define OHCI_ED_EN_SHIFT  7
+#define OHCI_ED_EN_MASK   (0xf<<OHCI_ED_EN_SHIFT)
+#define OHCI_ED_D_SHIFT   11
+#define OHCI_ED_D_MASK    (3<<OHCI_ED_D_SHIFT)
+#define OHCI_ED_S         (1<<13)
+#define OHCI_ED_K         (1<<14)
+#define OHCI_ED_F         (1<<15)
+#define OHCI_ED_MPS_SHIFT 16
+#define OHCI_ED_MPS_MASK  (0x7ff<<OHCI_ED_MPS_SHIFT)
+
+/* Flags in the head field of an Endpoint Desciptor.  */
+#define OHCI_ED_H         1
+#define OHCI_ED_C         2
+
+/* Bitfields for the first word of a Transfer Desciptor.  */
+#define OHCI_TD_R         (1<<18)
+#define OHCI_TD_DP_SHIFT  19
+#define OHCI_TD_DP_MASK   (3<<OHCI_TD_DP_SHIFT)
+#define OHCI_TD_DI_SHIFT  21
+#define OHCI_TD_DI_MASK   (7<<OHCI_TD_DI_SHIFT)
+#define OHCI_TD_T0        (1<<24)
+#define OHCI_TD_T1        (1<<24)
+#define OHCI_TD_EC_SHIFT  26
+#define OHCI_TD_EC_MASK   (3<<OHCI_TD_EC_SHIFT)
+#define OHCI_TD_CC_SHIFT  28
+#define OHCI_TD_CC_MASK   (0xf<<OHCI_TD_CC_SHIFT)
+
+/* Bitfields for the first word of an Isochronous Transfer Desciptor.  */
+/* CC & DI - same as in the General Transfer Desciptor */
+#define OHCI_TD_SF_SHIFT  0
+#define OHCI_TD_SF_MASK   (0xffff<<OHCI_TD_SF_SHIFT)
+#define OHCI_TD_FC_SHIFT  24
+#define OHCI_TD_FC_MASK   (7<<OHCI_TD_FC_SHIFT)
+
+/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
+#define OHCI_TD_PSW_CC_SHIFT 12
+#define OHCI_TD_PSW_CC_MASK  (0xf<<OHCI_TD_PSW_CC_SHIFT)
+#define OHCI_TD_PSW_SIZE_SHIFT 0
+#define OHCI_TD_PSW_SIZE_MASK  (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
+
+#define OHCI_PAGE_MASK    0xfffff000
+#define OHCI_OFFSET_MASK  0xfff
+
+#define OHCI_DPTR_MASK    0xfffffff0
+
+#define OHCI_BM(val, field) \
+  (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
+
+#define OHCI_SET_BM(val, field, newval) do { \
+    val &= ~OHCI_##field##_MASK; \
+    val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
+    } while(0)
+
+/* endpoint descriptor */
+struct ohci_ed {
+    uint32_t flags;
+    uint32_t tail;
+    uint32_t head;
+    uint32_t next;
+};
+
+/* General transfer descriptor */
+struct ohci_td {
+    uint32_t flags;
+    uint32_t cbp;
+    uint32_t next;
+    uint32_t be;
+};
+
+/* Isochronous transfer descriptor */
+struct ohci_iso_td {
+    uint32_t flags;
+    uint32_t bp;
+    uint32_t next;
+    uint32_t be;
+    uint16_t offset[8];
+};
+
+#define USB_HZ                      12000000
+
+/* OHCI Local stuff */
+#define OHCI_CTL_CBSR         ((1<<0)|(1<<1))
+#define OHCI_CTL_PLE          (1<<2)
+#define OHCI_CTL_IE           (1<<3)
+#define OHCI_CTL_CLE          (1<<4)
+#define OHCI_CTL_BLE          (1<<5)
+#define OHCI_CTL_HCFS         ((1<<6)|(1<<7))
+#define  OHCI_USB_RESET       0x00
+#define  OHCI_USB_RESUME      0x40
+#define  OHCI_USB_OPERATIONAL 0x80
+#define  OHCI_USB_SUSPEND     0xc0
+#define OHCI_CTL_IR           (1<<8)
+#define OHCI_CTL_RWC          (1<<9)
+#define OHCI_CTL_RWE          (1<<10)
+
+#define OHCI_STATUS_HCR       (1<<0)
+#define OHCI_STATUS_CLF       (1<<1)
+#define OHCI_STATUS_BLF       (1<<2)
+#define OHCI_STATUS_OCR       (1<<3)
+#define OHCI_STATUS_SOC       ((1<<6)|(1<<7))
+
+#define OHCI_INTR_SO          (1<<0) /* Scheduling overrun */
+#define OHCI_INTR_WD          (1<<1) /* HcDoneHead writeback */
+#define OHCI_INTR_SF          (1<<2) /* Start of frame */
+#define OHCI_INTR_RD          (1<<3) /* Resume detect */
+#define OHCI_INTR_UE          (1<<4) /* Unrecoverable error */
+#define OHCI_INTR_FNO         (1<<5) /* Frame number overflow */
+#define OHCI_INTR_RHSC        (1<<6) /* Root hub status change */
+#define OHCI_INTR_OC          (1<<30) /* Ownership change */
+#define OHCI_INTR_MIE         (1<<31) /* Master Interrupt Enable */
+
+#define OHCI_HCCA_SIZE        0x100
+#define OHCI_HCCA_MASK        0xffffff00
+
+#define OHCI_EDPTR_MASK       0xfffffff0
+
+#define OHCI_FMI_FI           0x00003fff
+#define OHCI_FMI_FSMPS        0xffff0000
+#define OHCI_FMI_FIT          0x80000000
+
+#define OHCI_FR_RT            (1<<31)
+
+#define OHCI_LS_THRESH        0x628
+
+#define OHCI_RHA_RW_MASK      0x00000000 /* Mask of supported features.  */
+#define OHCI_RHA_PSM          (1<<8)
+#define OHCI_RHA_NPS          (1<<9)
+#define OHCI_RHA_DT           (1<<10)
+#define OHCI_RHA_OCPM         (1<<11)
+#define OHCI_RHA_NOCP         (1<<12)
+#define OHCI_RHA_POTPGT_MASK  0xff000000
+
+#define OHCI_RHS_LPS          (1<<0)
+#define OHCI_RHS_OCI          (1<<1)
+#define OHCI_RHS_DRWE         (1<<15)
+#define OHCI_RHS_LPSC         (1<<16)
+#define OHCI_RHS_OCIC         (1<<17)
+#define OHCI_RHS_CRWE         (1<<31)
+
+#define OHCI_PORT_CCS         (1<<0)
+#define OHCI_PORT_PES         (1<<1)
+#define OHCI_PORT_PSS         (1<<2)
+#define OHCI_PORT_POCI        (1<<3)
+#define OHCI_PORT_PRS         (1<<4)
+#define OHCI_PORT_PPS         (1<<8)
+#define OHCI_PORT_LSDA        (1<<9)
+#define OHCI_PORT_CSC         (1<<16)
+#define OHCI_PORT_PESC        (1<<17)
+#define OHCI_PORT_PSSC        (1<<18)
+#define OHCI_PORT_OCIC        (1<<19)
+#define OHCI_PORT_PRSC        (1<<20)
+#define OHCI_PORT_WTC         (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
+                               |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
+
+#define OHCI_TD_DIR_SETUP     0x0
+#define OHCI_TD_DIR_OUT       0x1
+#define OHCI_TD_DIR_IN        0x2
+#define OHCI_TD_DIR_RESERVED  0x3
+
+#define OHCI_CC_NOERROR             0x0
+#define OHCI_CC_CRC                 0x1
+#define OHCI_CC_BITSTUFFING         0x2
+#define OHCI_CC_DATATOGGLEMISMATCH  0x3
+#define OHCI_CC_STALL               0x4
+#define OHCI_CC_DEVICENOTRESPONDING 0x5
+#define OHCI_CC_PIDCHECKFAILURE     0x6
+#define OHCI_CC_UNDEXPETEDPID       0x7
+#define OHCI_CC_DATAOVERRUN         0x8
+#define OHCI_CC_DATAUNDERRUN        0x9
+#define OHCI_CC_BUFFEROVERRUN       0xc
+#define OHCI_CC_BUFFERUNDERRUN      0xd
+
+#define OHCI_HRESET_FSBIR       (1 << 0)
+
+/* Update IRQ levels */
+static inline void ohci_intr_update(OHCIState *ohci)
+{
+    int level = 0;
+
+    if ((ohci->intr & OHCI_INTR_MIE) &&
+        (ohci->intr_status & ohci->intr))
+        level = 1;
+
+    qemu_set_irq(ohci->irq, level);
+}
+
+/* Set an interrupt */
+static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
+{
+    ohci->intr_status |= intr;
+    ohci_intr_update(ohci);
+}
+
+/* Attach or detach a device on a root hub port.  */
+static void ohci_attach(USBPort *port1)
+{
+    OHCIState *s = port1->opaque;
+    OHCIPort *port = &s->rhport[port1->index];
+    uint32_t old_state = port->ctrl;
+
+    /* set connect status */
+    port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
+
+    /* update speed */
+    if (port->port.dev->speed == USB_SPEED_LOW) {
+        port->ctrl |= OHCI_PORT_LSDA;
+    } else {
+        port->ctrl &= ~OHCI_PORT_LSDA;
+    }
+
+    /* notify of remote-wakeup */
+    if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+        ohci_set_interrupt(s, OHCI_INTR_RD);
+    }
+
+    DPRINTF("usb-ohci: Attached port %d\n", port1->index);
+
+    if (old_state != port->ctrl) {
+        ohci_set_interrupt(s, OHCI_INTR_RHSC);
+    }
+}
+
+static void ohci_detach(USBPort *port1)
+{
+    OHCIState *s = port1->opaque;
+    OHCIPort *port = &s->rhport[port1->index];
+    uint32_t old_state = port->ctrl;
+
+    ohci_async_cancel_device(s, port1->dev);
+
+    /* set connect status */
+    if (port->ctrl & OHCI_PORT_CCS) {
+        port->ctrl &= ~OHCI_PORT_CCS;
+        port->ctrl |= OHCI_PORT_CSC;
+    }
+    /* disable port */
+    if (port->ctrl & OHCI_PORT_PES) {
+        port->ctrl &= ~OHCI_PORT_PES;
+        port->ctrl |= OHCI_PORT_PESC;
+    }
+    DPRINTF("usb-ohci: Detached port %d\n", port1->index);
+
+    if (old_state != port->ctrl) {
+        ohci_set_interrupt(s, OHCI_INTR_RHSC);
+    }
+}
+
+static void ohci_wakeup(USBPort *port1)
+{
+    OHCIState *s = port1->opaque;
+    OHCIPort *port = &s->rhport[port1->index];
+    uint32_t intr = 0;
+    if (port->ctrl & OHCI_PORT_PSS) {
+        DPRINTF("usb-ohci: port %d: wakeup\n", port1->index);
+        port->ctrl |= OHCI_PORT_PSSC;
+        port->ctrl &= ~OHCI_PORT_PSS;
+        intr = OHCI_INTR_RHSC;
+    }
+    /* Note that the controller can be suspended even if this port is not */
+    if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+        DPRINTF("usb-ohci: remote-wakeup: SUSPEND->RESUME\n");
+        /* This is the one state transition the controller can do by itself */
+        s->ctl &= ~OHCI_CTL_HCFS;
+        s->ctl |= OHCI_USB_RESUME;
+        /* In suspend mode only ResumeDetected is possible, not RHSC:
+         * see the OHCI spec 5.1.2.3.
+         */
+        intr = OHCI_INTR_RD;
+    }
+    ohci_set_interrupt(s, intr);
+}
+
+static void ohci_child_detach(USBPort *port1, USBDevice *child)
+{
+    OHCIState *s = port1->opaque;
+
+    ohci_async_cancel_device(s, child);
+}
+
+/* Reset the controller */
+static void ohci_reset(void *opaque)
+{
+    OHCIState *ohci = opaque;
+    OHCIPort *port;
+    int i;
+
+    ohci_bus_stop(ohci);
+    ohci->ctl = 0;
+    ohci->old_ctl = 0;
+    ohci->status = 0;
+    ohci->intr_status = 0;
+    ohci->intr = OHCI_INTR_MIE;
+
+    ohci->hcca = 0;
+    ohci->ctrl_head = ohci->ctrl_cur = 0;
+    ohci->bulk_head = ohci->bulk_cur = 0;
+    ohci->per_cur = 0;
+    ohci->done = 0;
+    ohci->done_count = 7;
+
+    /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
+     * I took the value linux sets ...
+     */
+    ohci->fsmps = 0x2778;
+    ohci->fi = 0x2edf;
+    ohci->fit = 0;
+    ohci->frt = 0;
+    ohci->frame_number = 0;
+    ohci->pstart = 0;
+    ohci->lst = OHCI_LS_THRESH;
+
+    ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
+    ohci->rhdesc_b = 0x0; /* Impl. specific */
+    ohci->rhstatus = 0;
+
+    for (i = 0; i < ohci->num_ports; i++)
+      {
+        port = &ohci->rhport[i];
+        port->ctrl = 0;
+        if (port->port.dev) {
+            usb_attach(&port->port, port->port.dev);
+        }
+      }
+    if (ohci->async_td) {
+        usb_cancel_packet(&ohci->usb_packet);
+        ohci->async_td = 0;
+    }
+    DPRINTF("usb-ohci: Reset %s\n", ohci->name);
+}
+
+/* Get an array of dwords from main memory */
+static inline int get_dwords(OHCIState *ohci,
+                             uint32_t addr, uint32_t *buf, int num)
+{
+    int i;
+
+    addr += ohci->localmem_base;
+
+    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        cpu_physical_memory_read(addr, buf, sizeof(*buf));
+        *buf = le32_to_cpu(*buf);
+    }
+
+    return 1;
+}
+
+/* Put an array of dwords in to main memory */
+static inline int put_dwords(OHCIState *ohci,
+                             uint32_t addr, uint32_t *buf, int num)
+{
+    int i;
+
+    addr += ohci->localmem_base;
+
+    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        uint32_t tmp = cpu_to_le32(*buf);
+        cpu_physical_memory_write(addr, &tmp, sizeof(tmp));
+    }
+
+    return 1;
+}
+
+/* Get an array of words from main memory */
+static inline int get_words(OHCIState *ohci,
+                            uint32_t addr, uint16_t *buf, int num)
+{
+    int i;
+
+    addr += ohci->localmem_base;
+
+    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        cpu_physical_memory_read(addr, buf, sizeof(*buf));
+        *buf = le16_to_cpu(*buf);
+    }
+
+    return 1;
+}
+
+/* Put an array of words in to main memory */
+static inline int put_words(OHCIState *ohci,
+                            uint32_t addr, uint16_t *buf, int num)
+{
+    int i;
+
+    addr += ohci->localmem_base;
+
+    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+        uint16_t tmp = cpu_to_le16(*buf);
+        cpu_physical_memory_write(addr, &tmp, sizeof(tmp));
+    }
+
+    return 1;
+}
+
+static inline int ohci_read_ed(OHCIState *ohci,
+                               uint32_t addr, struct ohci_ed *ed)
+{
+    return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+}
+
+static inline int ohci_read_td(OHCIState *ohci,
+                               uint32_t addr, struct ohci_td *td)
+{
+    return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_read_iso_td(OHCIState *ohci,
+                                   uint32_t addr, struct ohci_iso_td *td)
+{
+    return (get_dwords(ohci, addr, (uint32_t *)td, 4) &&
+            get_words(ohci, addr + 16, td->offset, 8));
+}
+
+static inline int ohci_read_hcca(OHCIState *ohci,
+                                 uint32_t addr, struct ohci_hcca *hcca)
+{
+    cpu_physical_memory_read(addr + ohci->localmem_base, hcca, sizeof(*hcca));
+    return 1;
+}
+
+static inline int ohci_put_ed(OHCIState *ohci,
+                              uint32_t addr, struct ohci_ed *ed)
+{
+    return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+}
+
+static inline int ohci_put_td(OHCIState *ohci,
+                              uint32_t addr, struct ohci_td *td)
+{
+    return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_put_iso_td(OHCIState *ohci,
+                                  uint32_t addr, struct ohci_iso_td *td)
+{
+    return (put_dwords(ohci, addr, (uint32_t *)td, 4) &&
+            put_words(ohci, addr + 16, td->offset, 8));
+}
+
+static inline int ohci_put_hcca(OHCIState *ohci,
+                                uint32_t addr, struct ohci_hcca *hcca)
+{
+    cpu_physical_memory_write(addr + ohci->localmem_base, hcca, sizeof(*hcca));
+    return 1;
+}
+
+/* Read/Write the contents of a TD from/to main memory.  */
+static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
+                         uint8_t *buf, int len, int write)
+{
+    uint32_t ptr;
+    uint32_t n;
+
+    ptr = td->cbp;
+    n = 0x1000 - (ptr & 0xfff);
+    if (n > len)
+        n = len;
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
+    if (n == len)
+        return;
+    ptr = td->be & ~0xfffu;
+    buf += n;
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
+}
+
+/* Read/Write the contents of an ISO TD from/to main memory.  */
+static void ohci_copy_iso_td(OHCIState *ohci,
+                             uint32_t start_addr, uint32_t end_addr,
+                             uint8_t *buf, int len, int write)
+{
+    uint32_t ptr;
+    uint32_t n;
+
+    ptr = start_addr;
+    n = 0x1000 - (ptr & 0xfff);
+    if (n > len)
+        n = len;
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
+    if (n == len)
+        return;
+    ptr = end_addr & ~0xfffu;
+    buf += n;
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
+}
+
+static void ohci_process_lists(OHCIState *ohci, int completion);
+
+static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
+{
+    OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
+#ifdef DEBUG_PACKET
+    DPRINTF("Async packet complete\n");
+#endif
+    ohci->async_complete = 1;
+    ohci_process_lists(ohci, 1);
+}
+
+#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
+
+static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
+                               int completion)
+{
+    int dir;
+    size_t len = 0;
+#ifdef DEBUG_ISOCH
+    const char *str = NULL;
+#endif
+    int pid;
+    int ret;
+    int i;
+    USBDevice *dev;
+    struct ohci_iso_td iso_td;
+    uint32_t addr;
+    uint16_t starting_frame;
+    int16_t relative_frame_number;
+    int frame_count;
+    uint32_t start_offset, next_offset, end_offset = 0;
+    uint32_t start_addr, end_addr;
+
+    addr = ed->head & OHCI_DPTR_MASK;
+
+    if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
+        printf("usb-ohci: ISO_TD read error at %x\n", addr);
+        return 0;
+    }
+
+    starting_frame = OHCI_BM(iso_td.flags, TD_SF);
+    frame_count = OHCI_BM(iso_td.flags, TD_FC);
+    relative_frame_number = USUB(ohci->frame_number, starting_frame); 
+
+#ifdef DEBUG_ISOCH
+    printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
+           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
+           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
+           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
+           "frame_number 0x%.8x starting_frame 0x%.8x\n"
+           "frame_count  0x%.8x relative %d\n"
+           "di 0x%.8x cc 0x%.8x\n",
+           ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
+           iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
+           iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],
+           iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],
+           ohci->frame_number, starting_frame, 
+           frame_count, relative_frame_number,         
+           OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));
+#endif
+
+    if (relative_frame_number < 0) {
+        DPRINTF("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number);
+        return 1;
+    } else if (relative_frame_number > frame_count) {
+        /* ISO TD expired - retire the TD to the Done Queue and continue with
+           the next ISO TD of the same ED */
+        DPRINTF("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number, 
+               frame_count);
+        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
+        ed->head &= ~OHCI_DPTR_MASK;
+        ed->head |= (iso_td.next & OHCI_DPTR_MASK);
+        iso_td.next = ohci->done;
+        ohci->done = addr;
+        i = OHCI_BM(iso_td.flags, TD_DI);
+        if (i < ohci->done_count)
+            ohci->done_count = i;
+        ohci_put_iso_td(ohci, addr, &iso_td);
+        return 0;
+    }
+
+    dir = OHCI_BM(ed->flags, ED_D);
+    switch (dir) {
+    case OHCI_TD_DIR_IN:
+#ifdef DEBUG_ISOCH
+        str = "in";
+#endif
+        pid = USB_TOKEN_IN;
+        break;
+    case OHCI_TD_DIR_OUT:
+#ifdef DEBUG_ISOCH
+        str = "out";
+#endif
+        pid = USB_TOKEN_OUT;
+        break;
+    case OHCI_TD_DIR_SETUP:
+#ifdef DEBUG_ISOCH
+        str = "setup";
+#endif
+        pid = USB_TOKEN_SETUP;
+        break;
+    default:
+        printf("usb-ohci: Bad direction %d\n", dir);
+        return 1;
+    }
+
+    if (!iso_td.bp || !iso_td.be) {
+        printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be);
+        return 1;
+    }
+
+    start_offset = iso_td.offset[relative_frame_number];
+    next_offset = iso_td.offset[relative_frame_number + 1];
+
+    if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 
+        ((relative_frame_number < frame_count) && 
+         !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
+        printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",
+               start_offset, next_offset);
+        return 1;
+    }
+
+    if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
+        printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",
+                start_offset, next_offset);
+        return 1;
+    }
+
+    if ((start_offset & 0x1000) == 0) {
+        start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
+            (start_offset & OHCI_OFFSET_MASK);
+    } else {
+        start_addr = (iso_td.be & OHCI_PAGE_MASK) |
+            (start_offset & OHCI_OFFSET_MASK);
+    }
+
+    if (relative_frame_number < frame_count) {
+        end_offset = next_offset - 1;
+        if ((end_offset & 0x1000) == 0) {
+            end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
+                (end_offset & OHCI_OFFSET_MASK);
+        } else {
+            end_addr = (iso_td.be & OHCI_PAGE_MASK) |
+                (end_offset & OHCI_OFFSET_MASK);
+        }
+    } else {
+        /* Last packet in the ISO TD */
+        end_addr = iso_td.be;
+    }
+
+    if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
+        len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
+            - (start_addr & OHCI_OFFSET_MASK);
+    } else {
+        len = end_addr - start_addr + 1;
+    }
+
+    if (len && dir != OHCI_TD_DIR_IN) {
+        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);
+    }
+
+    if (completion) {
+        ret = ohci->usb_packet.len;
+    } else {
+        ret = USB_RET_NODEV;
+        for (i = 0; i < ohci->num_ports; i++) {
+            dev = ohci->rhport[i].port.dev;
+            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
+                continue;
+            ohci->usb_packet.pid = pid;
+            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
+            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
+            ohci->usb_packet.data = ohci->usb_buf;
+            ohci->usb_packet.len = len;
+            ret = usb_handle_packet(dev, &ohci->usb_packet);
+            if (ret != USB_RET_NODEV)
+                break;
+        }
+    
+        if (ret == USB_RET_ASYNC) {
+            return 1;
+        }
+    }
+
+#ifdef DEBUG_ISOCH
+    printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
+           start_offset, end_offset, start_addr, end_addr, str, len, ret);
+#endif
+
+    /* Writeback */
+    if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
+        /* IN transfer succeeded */
+        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);
+        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                    OHCI_CC_NOERROR);
+        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
+    } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
+        /* OUT transfer succeeded */
+        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                    OHCI_CC_NOERROR);
+        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
+    } else {
+        if (ret > (ssize_t) len) {
+            printf("usb-ohci: DataOverrun %d > %zu\n", ret, len);
+            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                        OHCI_CC_DATAOVERRUN);
+            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
+                        len);
+        } else if (ret >= 0) {
+            printf("usb-ohci: DataUnderrun %d\n", ret);
+            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                        OHCI_CC_DATAUNDERRUN);
+        } else {
+            switch (ret) {
+            case USB_RET_NODEV:
+                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                            OHCI_CC_DEVICENOTRESPONDING);
+                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
+                            0);
+                break;
+            case USB_RET_NAK:
+            case USB_RET_STALL:
+                printf("usb-ohci: got NAK/STALL %d\n", ret);
+                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                            OHCI_CC_STALL);
+                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
+                            0);
+                break;
+            default:
+                printf("usb-ohci: Bad device response %d\n", ret);
+                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                            OHCI_CC_UNDEXPETEDPID);
+                break;
+            }
+        }
+    }
+
+    if (relative_frame_number == frame_count) {
+        /* Last data packet of ISO TD - retire the TD to the Done Queue */
+        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
+        ed->head &= ~OHCI_DPTR_MASK;
+        ed->head |= (iso_td.next & OHCI_DPTR_MASK);
+        iso_td.next = ohci->done;
+        ohci->done = addr;
+        i = OHCI_BM(iso_td.flags, TD_DI);
+        if (i < ohci->done_count)
+            ohci->done_count = i;
+    }
+    ohci_put_iso_td(ohci, addr, &iso_td);
+    return 1;
+}
+
+/* Service a transport descriptor.
+   Returns nonzero to terminate processing of this endpoint.  */
+
+static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
+{
+    int dir;
+    size_t len = 0;
+#ifdef DEBUG_PACKET
+    const char *str = NULL;
+#endif
+    int pid;
+    int ret;
+    int i;
+    USBDevice *dev;
+    struct ohci_td td;
+    uint32_t addr;
+    int flag_r;
+    int completion;
+
+    addr = ed->head & OHCI_DPTR_MASK;
+    /* See if this TD has already been submitted to the device.  */
+    completion = (addr == ohci->async_td);
+    if (completion && !ohci->async_complete) {
+#ifdef DEBUG_PACKET
+        DPRINTF("Skipping async TD\n");
+#endif
+        return 1;
+    }
+    if (!ohci_read_td(ohci, addr, &td)) {
+        fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
+        return 0;
+    }
+
+    dir = OHCI_BM(ed->flags, ED_D);
+    switch (dir) {
+    case OHCI_TD_DIR_OUT:
+    case OHCI_TD_DIR_IN:
+        /* Same value.  */
+        break;
+    default:
+        dir = OHCI_BM(td.flags, TD_DP);
+        break;
+    }
+
+    switch (dir) {
+    case OHCI_TD_DIR_IN:
+#ifdef DEBUG_PACKET
+        str = "in";
+#endif
+        pid = USB_TOKEN_IN;
+        break;
+    case OHCI_TD_DIR_OUT:
+#ifdef DEBUG_PACKET
+        str = "out";
+#endif
+        pid = USB_TOKEN_OUT;
+        break;
+    case OHCI_TD_DIR_SETUP:
+#ifdef DEBUG_PACKET
+        str = "setup";
+#endif
+        pid = USB_TOKEN_SETUP;
+        break;
+    default:
+        fprintf(stderr, "usb-ohci: Bad direction\n");
+        return 1;
+    }
+    if (td.cbp && td.be) {
+        if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
+            len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
+        } else {
+            len = (td.be - td.cbp) + 1;
+        }
+
+        if (len && dir != OHCI_TD_DIR_IN && !completion) {
+            ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
+        }
+    }
+
+    flag_r = (td.flags & OHCI_TD_R) != 0;
+#ifdef DEBUG_PACKET
+    DPRINTF(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
+            addr, (int64_t)len, str, flag_r, td.cbp, td.be);
+
+    if (len > 0 && dir != OHCI_TD_DIR_IN) {
+        DPRINTF("  data:");
+        for (i = 0; i < len; i++)
+            printf(" %.2x", ohci->usb_buf[i]);
+        DPRINTF("\n");
+    }
+#endif
+    if (completion) {
+        ret = ohci->usb_packet.len;
+        ohci->async_td = 0;
+        ohci->async_complete = 0;
+    } else {
+        ret = USB_RET_NODEV;
+        for (i = 0; i < ohci->num_ports; i++) {
+            dev = ohci->rhport[i].port.dev;
+            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
+                continue;
+
+            if (ohci->async_td) {
+                /* ??? The hardware should allow one active packet per
+                   endpoint.  We only allow one active packet per controller.
+                   This should be sufficient as long as devices respond in a
+                   timely manner.
+                 */
+#ifdef DEBUG_PACKET
+                DPRINTF("Too many pending packets\n");
+#endif
+                return 1;
+            }
+            ohci->usb_packet.pid = pid;
+            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
+            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
+            ohci->usb_packet.data = ohci->usb_buf;
+            ohci->usb_packet.len = len;
+            ret = usb_handle_packet(dev, &ohci->usb_packet);
+            if (ret != USB_RET_NODEV)
+                break;
+        }
+#ifdef DEBUG_PACKET
+        DPRINTF("ret=%d\n", ret);
+#endif
+        if (ret == USB_RET_ASYNC) {
+            ohci->async_td = addr;
+            return 1;
+        }
+    }
+    if (ret >= 0) {
+        if (dir == OHCI_TD_DIR_IN) {
+            ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1);
+#ifdef DEBUG_PACKET
+            DPRINTF("  data:");
+            for (i = 0; i < ret; i++)
+                printf(" %.2x", ohci->usb_buf[i]);
+            DPRINTF("\n");
+#endif
+        } else {
+            ret = len;
+        }
+    }
+
+    /* Writeback */
+    if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
+        /* Transmission succeeded.  */
+        if (ret == len) {
+            td.cbp = 0;
+        } else {
+            td.cbp += ret;
+            if ((td.cbp & 0xfff) + ret > 0xfff) {
+                td.cbp &= 0xfff;
+                td.cbp |= td.be & ~0xfff;
+            }
+        }
+        td.flags |= OHCI_TD_T1;
+        td.flags ^= OHCI_TD_T0;
+        OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
+        OHCI_SET_BM(td.flags, TD_EC, 0);
+
+        ed->head &= ~OHCI_ED_C;
+        if (td.flags & OHCI_TD_T0)
+            ed->head |= OHCI_ED_C;
+    } else {
+        if (ret >= 0) {
+            DPRINTF("usb-ohci: Underrun\n");
+            OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
+        } else {
+            switch (ret) {
+            case USB_RET_NODEV:
+                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
+            case USB_RET_NAK:
+                DPRINTF("usb-ohci: got NAK\n");
+                return 1;
+            case USB_RET_STALL:
+                DPRINTF("usb-ohci: got STALL\n");
+                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
+                break;
+            case USB_RET_BABBLE:
+                DPRINTF("usb-ohci: got BABBLE\n");
+                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
+                break;
+            default:
+                fprintf(stderr, "usb-ohci: Bad device response %d\n", ret);
+                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
+                OHCI_SET_BM(td.flags, TD_EC, 3);
+                break;
+            }
+        }
+        ed->head |= OHCI_ED_H;
+    }
+
+    /* Retire this TD */
+    ed->head &= ~OHCI_DPTR_MASK;
+    ed->head |= td.next & OHCI_DPTR_MASK;
+    td.next = ohci->done;
+    ohci->done = addr;
+    i = OHCI_BM(td.flags, TD_DI);
+    if (i < ohci->done_count)
+        ohci->done_count = i;
+    ohci_put_td(ohci, addr, &td);
+    return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
+}
+
+/* Service an endpoint list.  Returns nonzero if active TD were found.  */
+static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
+{
+    struct ohci_ed ed;
+    uint32_t next_ed;
+    uint32_t cur;
+    int active;
+
+    active = 0;
+
+    if (head == 0)
+        return 0;
+
+    for (cur = head; cur; cur = next_ed) {
+        if (!ohci_read_ed(ohci, cur, &ed)) {
+            fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
+            return 0;
+        }
+
+        next_ed = ed.next & OHCI_DPTR_MASK;
+
+        if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
+            uint32_t addr;
+            /* Cancel pending packets for ED that have been paused.  */
+            addr = ed.head & OHCI_DPTR_MASK;
+            if (ohci->async_td && addr == ohci->async_td) {
+                usb_cancel_packet(&ohci->usb_packet);
+                ohci->async_td = 0;
+            }
+            continue;
+        }
+
+        while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
+#ifdef DEBUG_PACKET
+            DPRINTF("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
+                    "h=%u c=%u\n  head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur,
+                    OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
+                    OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
+                    (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
+                    OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0,
+                    (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
+                    ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
+#endif
+            active = 1;
+
+            if ((ed.flags & OHCI_ED_F) == 0) {
+                if (ohci_service_td(ohci, &ed))
+                    break;
+            } else {
+                /* Handle isochronous endpoints */
+                if (ohci_service_iso_td(ohci, &ed, completion))
+                    break;
+            }
+        }
+
+        ohci_put_ed(ohci, cur, &ed);
+    }
+
+    return active;
+}
+
+/* Generate a SOF event, and set a timer for EOF */
+static void ohci_sof(OHCIState *ohci)
+{
+    ohci->sof_time = qemu_get_clock_ns(vm_clock);
+    qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time);
+    ohci_set_interrupt(ohci, OHCI_INTR_SF);
+}
+
+/* Process Control and Bulk lists.  */
+static void ohci_process_lists(OHCIState *ohci, int completion)
+{
+    if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
+        if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
+            DPRINTF("usb-ohci: head %x, cur %x\n",
+                    ohci->ctrl_head, ohci->ctrl_cur);
+        }
+        if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
+            ohci->ctrl_cur = 0;
+            ohci->status &= ~OHCI_STATUS_CLF;
+        }
+    }
+
+    if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
+        if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
+            ohci->bulk_cur = 0;
+            ohci->status &= ~OHCI_STATUS_BLF;
+        }
+    }
+}
+
+/* Do frame processing on frame boundary */
+static void ohci_frame_boundary(void *opaque)
+{
+    OHCIState *ohci = opaque;
+    struct ohci_hcca hcca;
+
+    ohci_read_hcca(ohci, ohci->hcca, &hcca);
+
+    /* Process all the lists at the end of the frame */
+    if (ohci->ctl & OHCI_CTL_PLE) {
+        int n;
+
+        n = ohci->frame_number & 0x1f;
+        ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
+    }
+
+    /* Cancel all pending packets if either of the lists has been disabled.  */
+    if (ohci->async_td &&
+        ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
+        usb_cancel_packet(&ohci->usb_packet);
+        ohci->async_td = 0;
+    }
+    ohci->old_ctl = ohci->ctl;
+    ohci_process_lists(ohci, 0);
+
+    /* Frame boundary, so do EOF stuf here */
+    ohci->frt = ohci->fit;
+
+    /* Increment frame number and take care of endianness. */
+    ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
+    hcca.frame = cpu_to_le16(ohci->frame_number);
+
+    if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
+        if (!ohci->done)
+            abort();
+        if (ohci->intr & ohci->intr_status)
+            ohci->done |= 1;
+        hcca.done = cpu_to_le32(ohci->done);
+        ohci->done = 0;
+        ohci->done_count = 7;
+        ohci_set_interrupt(ohci, OHCI_INTR_WD);
+    }
+
+    if (ohci->done_count != 7 && ohci->done_count != 0)
+        ohci->done_count--;
+
+    /* Do SOF stuff here */
+    ohci_sof(ohci);
+
+    /* Writeback HCCA */
+    ohci_put_hcca(ohci, ohci->hcca, &hcca);
+}
+
+/* Start sending SOF tokens across the USB bus, lists are processed in
+ * next frame
+ */
+static int ohci_bus_start(OHCIState *ohci)
+{
+    ohci->eof_timer = qemu_new_timer_ns(vm_clock,
+                    ohci_frame_boundary,
+                    ohci);
+
+    if (ohci->eof_timer == NULL) {
+        fprintf(stderr, "usb-ohci: %s: qemu_new_timer_ns failed\n", ohci->name);
+        /* TODO: Signal unrecoverable error */
+        return 0;
+    }
+
+    DPRINTF("usb-ohci: %s: USB Operational\n", ohci->name);
+
+    ohci_sof(ohci);
+
+    return 1;
+}
+
+/* Stop sending SOF tokens on the bus */
+static void ohci_bus_stop(OHCIState *ohci)
+{
+    if (ohci->eof_timer)
+        qemu_del_timer(ohci->eof_timer);
+    ohci->eof_timer = NULL;
+}
+
+/* Sets a flag in a port status register but only set it if the port is
+ * connected, if not set ConnectStatusChange flag. If flag is enabled
+ * return 1.
+ */
+static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
+{
+    int ret = 1;
+
+    /* writing a 0 has no effect */
+    if (val == 0)
+        return 0;
+
+    /* If CurrentConnectStatus is cleared we set
+     * ConnectStatusChange
+     */
+    if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
+        ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
+        if (ohci->rhstatus & OHCI_RHS_DRWE) {
+            /* TODO: CSC is a wakeup event */
+        }
+        return 0;
+    }
+
+    if (ohci->rhport[i].ctrl & val)
+        ret = 0;
+
+    /* set the bit */
+    ohci->rhport[i].ctrl |= val;
+
+    return ret;
+}
+
+/* Set the frame interval - frame interval toggle is manipulated by the hcd only */
+static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
+{
+    val &= OHCI_FMI_FI;
+
+    if (val != ohci->fi) {
+        DPRINTF("usb-ohci: %s: FrameInterval = 0x%x (%u)\n",
+            ohci->name, ohci->fi, ohci->fi);
+    }
+
+    ohci->fi = val;
+}
+
+static void ohci_port_power(OHCIState *ohci, int i, int p)
+{
+    if (p) {
+        ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
+    } else {
+        ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
+                    OHCI_PORT_CCS|
+                    OHCI_PORT_PSS|
+                    OHCI_PORT_PRS);
+    }
+}
+
+/* Set HcControlRegister */
+static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
+{
+    uint32_t old_state;
+    uint32_t new_state;
+
+    old_state = ohci->ctl & OHCI_CTL_HCFS;
+    ohci->ctl = val;
+    new_state = ohci->ctl & OHCI_CTL_HCFS;
+
+    /* no state change */
+    if (old_state == new_state)
+        return;
+
+    switch (new_state) {
+    case OHCI_USB_OPERATIONAL:
+        ohci_bus_start(ohci);
+        break;
+    case OHCI_USB_SUSPEND:
+        ohci_bus_stop(ohci);
+        DPRINTF("usb-ohci: %s: USB Suspended\n", ohci->name);
+        break;
+    case OHCI_USB_RESUME:
+        DPRINTF("usb-ohci: %s: USB Resume\n", ohci->name);
+        break;
+    case OHCI_USB_RESET:
+        ohci_reset(ohci);
+        DPRINTF("usb-ohci: %s: USB Reset\n", ohci->name);
+        break;
+    }
+}
+
+static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
+{
+    uint16_t fr;
+    int64_t tks;
+
+    if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
+        return (ohci->frt << 31);
+
+    /* Being in USB operational state guarnatees sof_time was
+     * set already.
+     */
+    tks = qemu_get_clock_ns(vm_clock) - ohci->sof_time;
+
+    /* avoid muldiv if possible */
+    if (tks >= usb_frame_time)
+        return (ohci->frt << 31);
+
+    tks = muldiv64(1, tks, usb_bit_time);
+    fr = (uint16_t)(ohci->fi - tks);
+
+    return (ohci->frt << 31) | fr;
+}
+
+
+/* Set root hub status */
+static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
+{
+    uint32_t old_state;
+
+    old_state = ohci->rhstatus;
+
+    /* write 1 to clear OCIC */
+    if (val & OHCI_RHS_OCIC)
+        ohci->rhstatus &= ~OHCI_RHS_OCIC;
+
+    if (val & OHCI_RHS_LPS) {
+        int i;
+
+        for (i = 0; i < ohci->num_ports; i++)
+            ohci_port_power(ohci, i, 0);
+        DPRINTF("usb-ohci: powered down all ports\n");
+    }
+
+    if (val & OHCI_RHS_LPSC) {
+        int i;
+
+        for (i = 0; i < ohci->num_ports; i++)
+            ohci_port_power(ohci, i, 1);
+        DPRINTF("usb-ohci: powered up all ports\n");
+    }
+
+    if (val & OHCI_RHS_DRWE)
+        ohci->rhstatus |= OHCI_RHS_DRWE;
+
+    if (val & OHCI_RHS_CRWE)
+        ohci->rhstatus &= ~OHCI_RHS_DRWE;
+
+    if (old_state != ohci->rhstatus)
+        ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
+}
+
+/* Set root hub port status */
+static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
+{
+    uint32_t old_state;
+    OHCIPort *port;
+
+    port = &ohci->rhport[portnum];
+    old_state = port->ctrl;
+
+    /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
+    if (val & OHCI_PORT_WTC)
+        port->ctrl &= ~(val & OHCI_PORT_WTC);
+
+    if (val & OHCI_PORT_CCS)
+        port->ctrl &= ~OHCI_PORT_PES;
+
+    ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
+
+    if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
+        DPRINTF("usb-ohci: port %d: SUSPEND\n", portnum);
+    }
+
+    if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
+        DPRINTF("usb-ohci: port %d: RESET\n", portnum);
+        usb_send_msg(port->port.dev, USB_MSG_RESET);
+        port->ctrl &= ~OHCI_PORT_PRS;
+        /* ??? Should this also set OHCI_PORT_PESC.  */
+        port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
+    }
+
+    /* Invert order here to ensure in ambiguous case, device is
+     * powered up...
+     */
+    if (val & OHCI_PORT_LSDA)
+        ohci_port_power(ohci, portnum, 0);
+    if (val & OHCI_PORT_PPS)
+        ohci_port_power(ohci, portnum, 1);
+
+    if (old_state != port->ctrl)
+        ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
+
+    return;
+}
+
+static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
+{
+    OHCIState *ohci = ptr;
+    uint32_t retval;
+
+    addr &= 0xff;
+
+    /* Only aligned reads are allowed on OHCI */
+    if (addr & 3) {
+        fprintf(stderr, "usb-ohci: Mis-aligned read\n");
+        return 0xffffffff;
+    } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
+        /* HcRhPortStatus */
+        retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
+    } else {
+        switch (addr >> 2) {
+        case 0: /* HcRevision */
+            retval = 0x10;
+            break;
+
+        case 1: /* HcControl */
+            retval = ohci->ctl;
+            break;
+
+        case 2: /* HcCommandStatus */
+            retval = ohci->status;
+            break;
+
+        case 3: /* HcInterruptStatus */
+            retval = ohci->intr_status;
+            break;
+
+        case 4: /* HcInterruptEnable */
+        case 5: /* HcInterruptDisable */
+            retval = ohci->intr;
+            break;
+
+        case 6: /* HcHCCA */
+            retval = ohci->hcca;
+            break;
+
+        case 7: /* HcPeriodCurrentED */
+            retval = ohci->per_cur;
+            break;
+
+        case 8: /* HcControlHeadED */
+            retval = ohci->ctrl_head;
+            break;
+
+        case 9: /* HcControlCurrentED */
+            retval = ohci->ctrl_cur;
+            break;
+
+        case 10: /* HcBulkHeadED */
+            retval = ohci->bulk_head;
+            break;
+
+        case 11: /* HcBulkCurrentED */
+            retval = ohci->bulk_cur;
+            break;
+
+        case 12: /* HcDoneHead */
+            retval = ohci->done;
+            break;
+
+        case 13: /* HcFmInterretval */
+            retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
+            break;
+
+        case 14: /* HcFmRemaining */
+            retval = ohci_get_frame_remaining(ohci);
+            break;
+
+        case 15: /* HcFmNumber */
+            retval = ohci->frame_number;
+            break;
+
+        case 16: /* HcPeriodicStart */
+            retval = ohci->pstart;
+            break;
+
+        case 17: /* HcLSThreshold */
+            retval = ohci->lst;
+            break;
+
+        case 18: /* HcRhDescriptorA */
+            retval = ohci->rhdesc_a;
+            break;
+
+        case 19: /* HcRhDescriptorB */
+            retval = ohci->rhdesc_b;
+            break;
+
+        case 20: /* HcRhStatus */
+            retval = ohci->rhstatus;
+            break;
+
+        /* PXA27x specific registers */
+        case 24: /* HcStatus */
+            retval = ohci->hstatus & ohci->hmask;
+            break;
+
+        case 25: /* HcHReset */
+            retval = ohci->hreset;
+            break;
+
+        case 26: /* HcHInterruptEnable */
+            retval = ohci->hmask;
+            break;
+
+        case 27: /* HcHInterruptTest */
+            retval = ohci->htest;
+            break;
+
+        default:
+            fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
+            retval = 0xffffffff;
+        }
+    }
+
+    return retval;
+}
+
+static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    OHCIState *ohci = ptr;
+
+    addr &= 0xff;
+
+    /* Only aligned reads are allowed on OHCI */
+    if (addr & 3) {
+        fprintf(stderr, "usb-ohci: Mis-aligned write\n");
+        return;
+    }
+
+    if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
+        /* HcRhPortStatus */
+        ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
+        return;
+    }
+
+    switch (addr >> 2) {
+    case 1: /* HcControl */
+        ohci_set_ctl(ohci, val);
+        break;
+
+    case 2: /* HcCommandStatus */
+        /* SOC is read-only */
+        val = (val & ~OHCI_STATUS_SOC);
+
+        /* Bits written as '0' remain unchanged in the register */
+        ohci->status |= val;
+
+        if (ohci->status & OHCI_STATUS_HCR)
+            ohci_reset(ohci);
+        break;
+
+    case 3: /* HcInterruptStatus */
+        ohci->intr_status &= ~val;
+        ohci_intr_update(ohci);
+        break;
+
+    case 4: /* HcInterruptEnable */
+        ohci->intr |= val;
+        ohci_intr_update(ohci);
+        break;
+
+    case 5: /* HcInterruptDisable */
+        ohci->intr &= ~val;
+        ohci_intr_update(ohci);
+        break;
+
+    case 6: /* HcHCCA */
+        ohci->hcca = val & OHCI_HCCA_MASK;
+        break;
+
+    case 7: /* HcPeriodCurrentED */
+        /* Ignore writes to this read-only register, Linux does them */
+        break;
+
+    case 8: /* HcControlHeadED */
+        ohci->ctrl_head = val & OHCI_EDPTR_MASK;
+        break;
+
+    case 9: /* HcControlCurrentED */
+        ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
+        break;
+
+    case 10: /* HcBulkHeadED */
+        ohci->bulk_head = val & OHCI_EDPTR_MASK;
+        break;
+
+    case 11: /* HcBulkCurrentED */
+        ohci->bulk_cur = val & OHCI_EDPTR_MASK;
+        break;
+
+    case 13: /* HcFmInterval */
+        ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
+        ohci->fit = (val & OHCI_FMI_FIT) >> 31;
+        ohci_set_frame_interval(ohci, val);
+        break;
+
+    case 15: /* HcFmNumber */
+        break;
+
+    case 16: /* HcPeriodicStart */
+        ohci->pstart = val & 0xffff;
+        break;
+
+    case 17: /* HcLSThreshold */
+        ohci->lst = val & 0xffff;
+        break;
+
+    case 18: /* HcRhDescriptorA */
+        ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
+        ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
+        break;
+
+    case 19: /* HcRhDescriptorB */
+        break;
+
+    case 20: /* HcRhStatus */
+        ohci_set_hub_status(ohci, val);
+        break;
+
+    /* PXA27x specific registers */
+    case 24: /* HcStatus */
+        ohci->hstatus &= ~(val & ohci->hmask);
+
+    case 25: /* HcHReset */
+        ohci->hreset = val & ~OHCI_HRESET_FSBIR;
+        if (val & OHCI_HRESET_FSBIR)
+            ohci_reset(ohci);
+        break;
+
+    case 26: /* HcHInterruptEnable */
+        ohci->hmask = val;
+        break;
+
+    case 27: /* HcHInterruptTest */
+        ohci->htest = val;
+        break;
+
+    default:
+        fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr);
+        break;
+    }
+}
+
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
+{
+    if (ohci->async_td && ohci->usb_packet.owner == dev) {
+        usb_cancel_packet(&ohci->usb_packet);
+        ohci->async_td = 0;
+    }
+}
+
+/* Only dword reads are defined on OHCI register space */
+static CPUReadMemoryFunc * const ohci_readfn[3]={
+    ohci_mem_read,
+    ohci_mem_read,
+    ohci_mem_read
+};
+
+/* Only dword writes are defined on OHCI register space */
+static CPUWriteMemoryFunc * const ohci_writefn[3]={
+    ohci_mem_write,
+    ohci_mem_write,
+    ohci_mem_write
+};
+
+static USBPortOps ohci_port_ops = {
+    .attach = ohci_attach,
+    .detach = ohci_detach,
+    .child_detach = ohci_child_detach,
+    .wakeup = ohci_wakeup,
+    .complete = ohci_async_complete_packet,
+};
+
+static USBBusOps ohci_bus_ops = {
+};
+
+static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
+                         int num_ports, uint32_t localmem_base,
+                         char *masterbus, uint32_t firstport)
+{
+    int i;
+
+    if (usb_frame_time == 0) {
+#ifdef OHCI_TIME_WARP
+        usb_frame_time = get_ticks_per_sec();
+        usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ/1000);
+#else
+        usb_frame_time = muldiv64(1, get_ticks_per_sec(), 1000);
+        if (get_ticks_per_sec() >= USB_HZ) {
+            usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ);
+        } else {
+            usb_bit_time = 1;
+        }
+#endif
+        DPRINTF("usb-ohci: usb_bit_time=%" PRId64 " usb_frame_time=%" PRId64 "\n",
+                usb_frame_time, usb_bit_time);
+    }
+
+    ohci->num_ports = num_ports;
+    if (masterbus) {
+        USBPort *ports[OHCI_MAX_PORTS];
+        for(i = 0; i < num_ports; i++) {
+            ports[i] = &ohci->rhport[i].port;
+        }
+        if (usb_register_companion(masterbus, ports, num_ports,
+                firstport, ohci, &ohci_port_ops,
+                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+            return -1;
+        }
+    } else {
+        usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
+        for (i = 0; i < num_ports; i++) {
+            usb_register_port(&ohci->bus, &ohci->rhport[i].port,
+                              ohci, i, &ohci_port_ops,
+                              USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        }
+    }
+
+    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
+                                       DEVICE_LITTLE_ENDIAN);
+    ohci->localmem_base = localmem_base;
+
+    ohci->name = dev->info->name;
+
+    ohci->async_td = 0;
+    qemu_register_reset(ohci_reset, ohci);
+
+    return 0;
+}
+
+typedef struct {
+    PCIDevice pci_dev;
+    OHCIState state;
+    char *masterbus;
+    uint32_t num_ports;
+    uint32_t firstport;
+} OHCIPCIState;
+
+static int usb_ohci_initfn_pci(struct PCIDevice *dev)
+{
+    OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
+
+    ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
+    /* TODO: RST# value should be 0. */
+    ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+
+    if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
+                      ohci->masterbus, ohci->firstport) != 0) {
+        return -1;
+    }
+    ohci->state.irq = ohci->pci_dev.irq[0];
+
+    /* TODO: avoid cast below by using dev */
+    pci_register_bar_simple(&ohci->pci_dev, 0, 256, 0, ohci->state.mem);
+    return 0;
+}
+
+void usb_ohci_init_pci(struct PCIBus *bus, int devfn)
+{
+    pci_create_simple(bus, devfn, "pci-ohci");
+}
+
+typedef struct {
+    SysBusDevice busdev;
+    OHCIState ohci;
+    uint32_t num_ports;
+    target_phys_addr_t dma_offset;
+} OHCISysBusState;
+
+static int ohci_init_pxa(SysBusDevice *dev)
+{
+    OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev);
+
+    /* Cannot fail as we pass NULL for masterbus */
+    usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0);
+    sysbus_init_irq(dev, &s->ohci.irq);
+    sysbus_init_mmio(dev, 0x1000, s->ohci.mem);
+
+    return 0;
+}
+
+static PCIDeviceInfo ohci_pci_info = {
+    .qdev.name    = "pci-ohci",
+    .qdev.desc    = "Apple USB Controller",
+    .qdev.size    = sizeof(OHCIPCIState),
+    .init         = usb_ohci_initfn_pci,
+    .vendor_id    = PCI_VENDOR_ID_APPLE,
+    .device_id    = PCI_DEVICE_ID_APPLE_IPID_USB,
+    .class_id     = PCI_CLASS_SERIAL_USB,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+        DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+        DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo ohci_sysbus_info = {
+    .init         = ohci_init_pxa,
+    .qdev.name    = "sysbus-ohci",
+    .qdev.desc    = "OHCI USB Controller",
+    .qdev.size    = sizeof(OHCISysBusState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
+        DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ohci_register(void)
+{
+    pci_qdev_register(&ohci_pci_info);
+    sysbus_register_withprop(&ohci_sysbus_info);
+}
+device_init(ohci_register);
diff --git a/qemu-0.15.x/hw/usb-ohci.h b/qemu-0.15.x/hw/usb-ohci.h
new file mode 100644
index 0000000..eefcef3
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-ohci.h
@@ -0,0 +1,9 @@
+#ifndef QEMU_USB_OHCI_H
+#define QEMU_USB_OHCI_H
+
+#include "qemu-common.h"
+
+void usb_ohci_init_pci(struct PCIBus *bus, int devfn);
+
+#endif
+
diff --git a/qemu-0.15.x/hw/usb-serial.c b/qemu-0.15.x/hw/usb-serial.c
new file mode 100644
index 0000000..c69c437
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-serial.c
@@ -0,0 +1,612 @@
+/*
+ * FTDI FT232BM Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2008 Samuel Thibault <samuel.thibault at ens-lyon.org>
+ * Written by Paul Brook, reused for FTDI by Samuel Thibault
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "qemu-char.h"
+
+//#define DEBUG_Serial
+
+#ifdef DEBUG_Serial
+#define DPRINTF(fmt, ...) \
+do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define RECV_BUF 384
+
+/* Commands */
+#define FTDI_RESET		0
+#define FTDI_SET_MDM_CTRL	1
+#define FTDI_SET_FLOW_CTRL	2
+#define FTDI_SET_BAUD		3
+#define FTDI_SET_DATA		4
+#define FTDI_GET_MDM_ST		5
+#define FTDI_SET_EVENT_CHR	6
+#define FTDI_SET_ERROR_CHR	7
+#define FTDI_SET_LATENCY	9
+#define FTDI_GET_LATENCY	10
+
+#define DeviceOutVendor	((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+#define DeviceInVendor	((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+
+/* RESET */
+
+#define FTDI_RESET_SIO	0
+#define FTDI_RESET_RX	1
+#define FTDI_RESET_TX	2
+
+/* SET_MDM_CTRL */
+
+#define FTDI_DTR	1
+#define FTDI_SET_DTR	(FTDI_DTR << 8)
+#define FTDI_RTS	2
+#define FTDI_SET_RTS	(FTDI_RTS << 8)
+
+/* SET_FLOW_CTRL */
+
+#define FTDI_RTS_CTS_HS		1
+#define FTDI_DTR_DSR_HS		2
+#define FTDI_XON_XOFF_HS	4
+
+/* SET_DATA */
+
+#define FTDI_PARITY	(0x7 << 8)
+#define FTDI_ODD	(0x1 << 8)
+#define FTDI_EVEN	(0x2 << 8)
+#define FTDI_MARK	(0x3 << 8)
+#define FTDI_SPACE	(0x4 << 8)
+
+#define FTDI_STOP	(0x3 << 11)
+#define FTDI_STOP1	(0x0 << 11)
+#define FTDI_STOP15	(0x1 << 11)
+#define FTDI_STOP2	(0x2 << 11)
+
+/* GET_MDM_ST */
+/* TODO: should be sent every 40ms */
+#define FTDI_CTS  (1<<4)        // CTS line status
+#define FTDI_DSR  (1<<5)        // DSR line status
+#define FTDI_RI   (1<<6)        // RI line status
+#define FTDI_RLSD (1<<7)        // Receive Line Signal Detect
+
+/* Status */
+
+#define FTDI_DR   (1<<0)        // Data Ready
+#define FTDI_OE   (1<<1)        // Overrun Err
+#define FTDI_PE   (1<<2)        // Parity Err
+#define FTDI_FE   (1<<3)        // Framing Err
+#define FTDI_BI   (1<<4)        // Break Interrupt
+#define FTDI_THRE (1<<5)        // Transmitter Holding Register
+#define FTDI_TEMT (1<<6)        // Transmitter Empty
+#define FTDI_FIFO (1<<7)        // Error in FIFO
+
+typedef struct {
+    USBDevice dev;
+    uint8_t recv_buf[RECV_BUF];
+    uint16_t recv_ptr;
+    uint16_t recv_used;
+    uint8_t event_chr;
+    uint8_t error_chr;
+    uint8_t event_trigger;
+    QEMUSerialSetParams params;
+    int latency;        /* ms */
+    CharDriverState *cs;
+} USBSerialState;
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT_SERIAL,
+    STR_PRODUCT_BRAILLE,
+    STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]    = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
+    [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
+    [STR_SERIALNUMBER]    = "1",
+};
+
+static const USBDescIface desc_iface0 = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 2,
+    .bInterfaceClass               = 0xff,
+    .bInterfaceSubClass            = 0xff,
+    .bInterfaceProtocol            = 0xff,
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | 0x02,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
+};
+
+static const USBDescDevice desc_device = {
+    .bcdUSB                        = 0x0200,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0x80,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0,
+        },
+    },
+};
+
+static const USBDesc desc_serial = {
+    .id = {
+        .idVendor          = 0x0403,
+        .idProduct         = 0x6001,
+        .bcdDevice         = 0x0400,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_SERIAL,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
+};
+
+static const USBDesc desc_braille = {
+    .id = {
+        .idVendor          = 0x0403,
+        .idProduct         = 0xfe72,
+        .bcdDevice         = 0x0400,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT_BRAILLE,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
+};
+
+static void usb_serial_reset(USBSerialState *s)
+{
+    /* TODO: Set flow control to none */
+    s->event_chr = 0x0d;
+    s->event_trigger = 0;
+    s->recv_ptr = 0;
+    s->recv_used = 0;
+    /* TODO: purge in char driver */
+}
+
+static void usb_serial_handle_reset(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    DPRINTF("Reset\n");
+
+    usb_serial_reset(s);
+    /* TODO: Reset char device, send BREAK? */
+}
+
+static uint8_t usb_get_modem_lines(USBSerialState *s)
+{
+    int flags;
+    uint8_t ret;
+
+    if (qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
+        return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
+
+    ret = 0;
+    if (flags & CHR_TIOCM_CTS)
+        ret |= FTDI_CTS;
+    if (flags & CHR_TIOCM_DSR)
+        ret |= FTDI_DSR;
+    if (flags & CHR_TIOCM_RI)
+        ret |= FTDI_RI;
+    if (flags & CHR_TIOCM_CAR)
+        ret |= FTDI_RLSD;
+
+    return ret;
+}
+
+static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret;
+
+    DPRINTF("got control %x, value %x\n",request, value);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ret = 0;
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+
+        /* Class specific requests.  */
+    case DeviceOutVendor | FTDI_RESET:
+        switch (value) {
+        case FTDI_RESET_SIO:
+            usb_serial_reset(s);
+            break;
+        case FTDI_RESET_RX:
+            s->recv_ptr = 0;
+            s->recv_used = 0;
+            /* TODO: purge from char device */
+            break;
+        case FTDI_RESET_TX:
+            /* TODO: purge from char device */
+            break;
+        }
+        break;
+    case DeviceOutVendor | FTDI_SET_MDM_CTRL:
+    {
+        static int flags;
+        qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+        if (value & FTDI_SET_RTS) {
+            if (value & FTDI_RTS)
+                flags |= CHR_TIOCM_RTS;
+            else
+                flags &= ~CHR_TIOCM_RTS;
+        }
+        if (value & FTDI_SET_DTR) {
+            if (value & FTDI_DTR)
+                flags |= CHR_TIOCM_DTR;
+            else
+                flags &= ~CHR_TIOCM_DTR;
+        }
+        qemu_chr_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+        break;
+    }
+    case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
+        /* TODO: ioctl */
+        break;
+    case DeviceOutVendor | FTDI_SET_BAUD: {
+        static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
+        int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
+                                     | ((index & 1) << 2)];
+        int divisor = value & 0x3fff;
+
+        /* chip special cases */
+        if (divisor == 1 && subdivisor8 == 0)
+            subdivisor8 = 4;
+        if (divisor == 0 && subdivisor8 == 0)
+            divisor = 1;
+
+        s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        break;
+    }
+    case DeviceOutVendor | FTDI_SET_DATA:
+        switch (value & FTDI_PARITY) {
+            case 0:
+                s->params.parity = 'N';
+                break;
+            case FTDI_ODD:
+                s->params.parity = 'O';
+                break;
+            case FTDI_EVEN:
+                s->params.parity = 'E';
+                break;
+            default:
+                DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
+                goto fail;
+        }
+        switch (value & FTDI_STOP) {
+            case FTDI_STOP1:
+                s->params.stop_bits = 1;
+                break;
+            case FTDI_STOP2:
+                s->params.stop_bits = 2;
+                break;
+            default:
+                DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
+                goto fail;
+        }
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        /* TODO: TX ON/OFF */
+        break;
+    case DeviceInVendor | FTDI_GET_MDM_ST:
+        data[0] = usb_get_modem_lines(s) | 1;
+        data[1] = 0;
+        ret = 2;
+        break;
+    case DeviceOutVendor | FTDI_SET_EVENT_CHR:
+        /* TODO: handle it */
+        s->event_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_ERROR_CHR:
+        /* TODO: handle it */
+        s->error_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_LATENCY:
+        s->latency = value;
+        break;
+    case DeviceInVendor | FTDI_GET_LATENCY:
+        data[0] = s->latency;
+        ret = 1;
+        break;
+    default:
+    fail:
+        DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret = 0;
+    uint8_t devep = p->devep;
+    uint8_t *data = p->data;
+    int len = p->len;
+    int first_len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        if (devep != 2)
+            goto fail;
+        qemu_chr_write(s->cs, data, len);
+        break;
+
+    case USB_TOKEN_IN:
+        if (devep != 1)
+            goto fail;
+        first_len = RECV_BUF - s->recv_ptr;
+        if (len <= 2) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        *data++ = usb_get_modem_lines(s) | 1;
+        /* We do not have the uart details */
+        /* handle serial break */
+        if (s->event_trigger && s->event_trigger & FTDI_BI) {
+            s->event_trigger &= ~FTDI_BI;
+            *data = FTDI_BI;
+            ret = 2;
+            break;
+        } else {
+            *data++ = 0;
+        }
+        len -= 2;
+        if (len > s->recv_used)
+            len = s->recv_used;
+        if (!len) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        if (first_len > len)
+            first_len = len;
+        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        if (len > first_len)
+            memcpy(data + first_len, s->recv_buf, len - first_len);
+        s->recv_used -= len;
+        s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
+        ret = len + 2;
+        break;
+
+    default:
+        DPRINTF("Bad token\n");
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void usb_serial_handle_destroy(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    qemu_chr_close(s->cs);
+}
+
+static int usb_serial_can_read(void *opaque)
+{
+    USBSerialState *s = opaque;
+    return RECV_BUF - s->recv_used;
+}
+
+static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
+{
+    USBSerialState *s = opaque;
+    int first_size, start;
+
+    /* room in the buffer? */
+    if (size > (RECV_BUF - s->recv_used))
+        size = RECV_BUF - s->recv_used;
+
+    start = s->recv_ptr + s->recv_used;
+    if (start < RECV_BUF) {
+        /* copy data to end of buffer */
+        first_size = RECV_BUF - start;
+        if (first_size > size)
+            first_size = size;
+
+        memcpy(s->recv_buf + start, buf, first_size);
+
+        /* wrap around to front if needed */
+        if (size > first_size)
+            memcpy(s->recv_buf, buf + first_size, size - first_size);
+    } else {
+        start -= RECV_BUF;
+        memcpy(s->recv_buf + start, buf, size);
+    }
+    s->recv_used += size;
+}
+
+static void usb_serial_event(void *opaque, int event)
+{
+    USBSerialState *s = opaque;
+
+    switch (event) {
+        case CHR_EVENT_BREAK:
+            s->event_trigger |= FTDI_BI;
+            break;
+        case CHR_EVENT_FOCUS:
+            break;
+        case CHR_EVENT_OPENED:
+            usb_serial_reset(s);
+            /* TODO: Reset USB port */
+            break;
+    }
+}
+
+static int usb_serial_initfn(USBDevice *dev)
+{
+    USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
+
+    usb_desc_init(dev);
+
+    if (!s->cs) {
+        error_report("Property chardev is required");
+        return -1;
+    }
+
+    qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
+                          usb_serial_event, s);
+    usb_serial_handle_reset(dev);
+    return 0;
+}
+
+static USBDevice *usb_serial_init(const char *filename)
+{
+    USBDevice *dev;
+    CharDriverState *cdrv;
+    uint32_t vendorid = 0, productid = 0;
+    char label[32];
+    static int index;
+
+    while (*filename && *filename != ':') {
+        const char *p;
+        char *e;
+        if (strstart(filename, "vendorid=", &p)) {
+            vendorid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                error_report("bogus vendor ID %s", p);
+                return NULL;
+            }
+            filename = e;
+        } else if (strstart(filename, "productid=", &p)) {
+            productid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                error_report("bogus product ID %s", p);
+                return NULL;
+            }
+            filename = e;
+        } else {
+            error_report("unrecognized serial USB option %s", filename);
+            return NULL;
+        }
+        while(*filename == ',')
+            filename++;
+    }
+    if (!*filename) {
+        error_report("character device specification needed");
+        return NULL;
+    }
+    filename++;
+
+    snprintf(label, sizeof(label), "usbserial%d", index++);
+    cdrv = qemu_chr_open(label, filename, NULL);
+    if (!cdrv)
+        return NULL;
+
+    dev = usb_create(NULL /* FIXME */, "usb-serial");
+    if (!dev) {
+        return NULL;
+    }
+    qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
+    if (vendorid)
+        qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
+    if (productid)
+        qdev_prop_set_uint16(&dev->qdev, "productid", productid);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+static USBDevice *usb_braille_init(const char *unused)
+{
+    USBDevice *dev;
+    CharDriverState *cdrv;
+
+    cdrv = qemu_chr_open("braille", "braille", NULL);
+    if (!cdrv)
+        return NULL;
+
+    dev = usb_create(NULL /* FIXME */, "usb-braille");
+    qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+static struct USBDeviceInfo serial_info = {
+    .product_desc   = "QEMU USB Serial",
+    .qdev.name      = "usb-serial",
+    .qdev.size      = sizeof(USBSerialState),
+    .usb_desc       = &desc_serial,
+    .init           = usb_serial_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_serial_handle_reset,
+    .handle_control = usb_serial_handle_control,
+    .handle_data    = usb_serial_handle_data,
+    .handle_destroy = usb_serial_handle_destroy,
+    .usbdevice_name = "serial",
+    .usbdevice_init = usb_serial_init,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static struct USBDeviceInfo braille_info = {
+    .product_desc   = "QEMU USB Braille",
+    .qdev.name      = "usb-braille",
+    .qdev.size      = sizeof(USBSerialState),
+    .usb_desc       = &desc_braille,
+    .init           = usb_serial_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_serial_handle_reset,
+    .handle_control = usb_serial_handle_control,
+    .handle_data    = usb_serial_handle_data,
+    .handle_destroy = usb_serial_handle_destroy,
+    .usbdevice_name = "braille",
+    .usbdevice_init = usb_braille_init,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void usb_serial_register_devices(void)
+{
+    usb_qdev_register(&serial_info);
+    usb_qdev_register(&braille_info);
+}
+device_init(usb_serial_register_devices)
diff --git a/qemu-0.15.x/hw/usb-uhci.c b/qemu-0.15.x/hw/usb-uhci.c
new file mode 100644
index 0000000..da74c57
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-uhci.c
@@ -0,0 +1,1276 @@
+/*
+ * USB UHCI controller emulation
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ *     Magor rewrite of the UHCI data structures parser and frame processor
+ *     Support for fully async operation and multiple outstanding transactions
+ *
+ * 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 "hw.h"
+#include "usb.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "usb-uhci.h"
+
+//#define DEBUG
+//#define DEBUG_DUMP_DATA
+
+#define UHCI_CMD_FGR      (1 << 4)
+#define UHCI_CMD_EGSM     (1 << 3)
+#define UHCI_CMD_GRESET   (1 << 2)
+#define UHCI_CMD_HCRESET  (1 << 1)
+#define UHCI_CMD_RS       (1 << 0)
+
+#define UHCI_STS_HCHALTED (1 << 5)
+#define UHCI_STS_HCPERR   (1 << 4)
+#define UHCI_STS_HSERR    (1 << 3)
+#define UHCI_STS_RD       (1 << 2)
+#define UHCI_STS_USBERR   (1 << 1)
+#define UHCI_STS_USBINT   (1 << 0)
+
+#define TD_CTRL_SPD     (1 << 29)
+#define TD_CTRL_ERROR_SHIFT  27
+#define TD_CTRL_IOS     (1 << 25)
+#define TD_CTRL_IOC     (1 << 24)
+#define TD_CTRL_ACTIVE  (1 << 23)
+#define TD_CTRL_STALL   (1 << 22)
+#define TD_CTRL_BABBLE  (1 << 20)
+#define TD_CTRL_NAK     (1 << 19)
+#define TD_CTRL_TIMEOUT (1 << 18)
+
+#define UHCI_PORT_SUSPEND (1 << 12)
+#define UHCI_PORT_RESET (1 << 9)
+#define UHCI_PORT_LSDA  (1 << 8)
+#define UHCI_PORT_RD    (1 << 6)
+#define UHCI_PORT_ENC   (1 << 3)
+#define UHCI_PORT_EN    (1 << 2)
+#define UHCI_PORT_CSC   (1 << 1)
+#define UHCI_PORT_CCS   (1 << 0)
+
+#define UHCI_PORT_READ_ONLY    (0x1bb)
+#define UHCI_PORT_WRITE_CLEAR  (UHCI_PORT_CSC | UHCI_PORT_ENC)
+
+#define FRAME_TIMER_FREQ 1000
+
+#define FRAME_MAX_LOOPS  100
+
+#define NB_PORTS 2
+
+#ifdef DEBUG
+#define DPRINTF printf
+
+static const char *pid2str(int pid)
+{
+    switch (pid) {
+    case USB_TOKEN_SETUP: return "SETUP";
+    case USB_TOKEN_IN:    return "IN";
+    case USB_TOKEN_OUT:   return "OUT";
+    }
+    return "?";
+}
+
+#else
+#define DPRINTF(...)
+#endif
+
+#ifdef DEBUG_DUMP_DATA
+static void dump_data(const uint8_t *data, int len)
+{
+    int i;
+
+    printf("uhci: data: ");
+    for(i = 0; i < len; i++)
+        printf(" %02x", data[i]);
+    printf("\n");
+}
+#else
+static void dump_data(const uint8_t *data, int len) {}
+#endif
+
+typedef struct UHCIState UHCIState;
+
+/* 
+ * Pending async transaction.
+ * 'packet' must be the first field because completion
+ * handler does "(UHCIAsync *) pkt" cast.
+ */
+typedef struct UHCIAsync {
+    USBPacket packet;
+    UHCIState *uhci;
+    QTAILQ_ENTRY(UHCIAsync) next;
+    uint32_t  td;
+    uint32_t  token;
+    int8_t    valid;
+    uint8_t   isoc;
+    uint8_t   done;
+    uint8_t   buffer[2048];
+} UHCIAsync;
+
+typedef struct UHCIPort {
+    USBPort port;
+    uint16_t ctrl;
+} UHCIPort;
+
+struct UHCIState {
+    PCIDevice dev;
+    USBBus bus; /* Note unused when we're a companion controller */
+    uint16_t cmd; /* cmd register */
+    uint16_t status;
+    uint16_t intr; /* interrupt enable register */
+    uint16_t frnum; /* frame number */
+    uint32_t fl_base_addr; /* frame list base address */
+    uint8_t sof_timing;
+    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
+    int64_t expire_time;
+    QEMUTimer *frame_timer;
+    UHCIPort ports[NB_PORTS];
+
+    /* Interrupts that should be raised at the end of the current frame.  */
+    uint32_t pending_int_mask;
+
+    /* Active packets */
+    QTAILQ_HEAD(,UHCIAsync) async_pending;
+    uint8_t num_ports_vmstate;
+
+    /* Properties */
+    char *masterbus;
+    uint32_t firstport;
+};
+
+typedef struct UHCI_TD {
+    uint32_t link;
+    uint32_t ctrl; /* see TD_CTRL_xxx */
+    uint32_t token;
+    uint32_t buffer;
+} UHCI_TD;
+
+typedef struct UHCI_QH {
+    uint32_t link;
+    uint32_t el_link;
+} UHCI_QH;
+
+static UHCIAsync *uhci_async_alloc(UHCIState *s)
+{
+    UHCIAsync *async = qemu_malloc(sizeof(UHCIAsync));
+
+    memset(&async->packet, 0, sizeof(async->packet));
+    async->uhci  = s;
+    async->valid = 0;
+    async->td    = 0;
+    async->token = 0;
+    async->done  = 0;
+    async->isoc  = 0;
+
+    return async;
+}
+
+static void uhci_async_free(UHCIState *s, UHCIAsync *async)
+{
+    qemu_free(async);
+}
+
+static void uhci_async_link(UHCIState *s, UHCIAsync *async)
+{
+    QTAILQ_INSERT_HEAD(&s->async_pending, async, next);
+}
+
+static void uhci_async_unlink(UHCIState *s, UHCIAsync *async)
+{
+    QTAILQ_REMOVE(&s->async_pending, async, next);
+}
+
+static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
+{
+    DPRINTF("uhci: cancel td 0x%x token 0x%x done %u\n",
+           async->td, async->token, async->done);
+
+    if (!async->done)
+        usb_cancel_packet(&async->packet);
+    uhci_async_free(s, async);
+}
+
+/*
+ * Mark all outstanding async packets as invalid.
+ * This is used for canceling them when TDs are removed by the HCD.
+ */
+static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
+{
+    UHCIAsync *async;
+
+    QTAILQ_FOREACH(async, &s->async_pending, next) {
+        async->valid--;
+    }
+    return NULL;
+}
+
+/*
+ * Cancel async packets that are no longer valid
+ */
+static void uhci_async_validate_end(UHCIState *s)
+{
+    UHCIAsync *curr, *n;
+
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+        if (curr->valid > 0) {
+            continue;
+        }
+        uhci_async_unlink(s, curr);
+        uhci_async_cancel(s, curr);
+    }
+}
+
+static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
+{
+    UHCIAsync *curr, *n;
+
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+        if (curr->packet.owner != dev) {
+            continue;
+        }
+        uhci_async_unlink(s, curr);
+        uhci_async_cancel(s, curr);
+    }
+}
+
+static void uhci_async_cancel_all(UHCIState *s)
+{
+    UHCIAsync *curr, *n;
+
+    QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+        uhci_async_unlink(s, curr);
+        uhci_async_cancel(s, curr);
+    }
+}
+
+static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token)
+{
+    UHCIAsync *async;
+    UHCIAsync *match = NULL;
+    int count = 0;
+
+    /*
+     * We're looking for the best match here. ie both td addr and token.
+     * Otherwise we return last good match. ie just token.
+     * It's ok to match just token because it identifies the transaction
+     * rather well, token includes: device addr, endpoint, size, etc.
+     *
+     * Also since we queue async transactions in reverse order by returning
+     * last good match we restores the order.
+     *
+     * It's expected that we wont have a ton of outstanding transactions.
+     * If we ever do we'd want to optimize this algorithm.
+     */
+
+    QTAILQ_FOREACH(async, &s->async_pending, next) {
+        if (async->token == token) {
+            /* Good match */
+            match = async;
+
+            if (async->td == addr) {
+                /* Best match */
+                break;
+            }
+        }
+        count++;
+    }
+
+    if (count > 64)
+	fprintf(stderr, "uhci: warning lots of async transactions\n");
+
+    return match;
+}
+
+static void uhci_update_irq(UHCIState *s)
+{
+    int level;
+    if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
+        ((s->status2 & 2) && (s->intr & (1 << 3))) ||
+        ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
+        ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
+        (s->status & UHCI_STS_HSERR) ||
+        (s->status & UHCI_STS_HCPERR)) {
+        level = 1;
+    } else {
+        level = 0;
+    }
+    qemu_set_irq(s->dev.irq[3], level);
+}
+
+static void uhci_reset(void *opaque)
+{
+    UHCIState *s = opaque;
+    uint8_t *pci_conf;
+    int i;
+    UHCIPort *port;
+
+    DPRINTF("uhci: full reset\n");
+
+    pci_conf = s->dev.config;
+
+    pci_conf[0x6a] = 0x01; /* usb clock */
+    pci_conf[0x6b] = 0x00;
+    s->cmd = 0;
+    s->status = 0;
+    s->status2 = 0;
+    s->intr = 0;
+    s->fl_base_addr = 0;
+    s->sof_timing = 64;
+
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &s->ports[i];
+        port->ctrl = 0x0080;
+        if (port->port.dev) {
+            usb_attach(&port->port, port->port.dev);
+        }
+    }
+
+    uhci_async_cancel_all(s);
+}
+
+static void uhci_pre_save(void *opaque)
+{
+    UHCIState *s = opaque;
+
+    uhci_async_cancel_all(s);
+}
+
+static const VMStateDescription vmstate_uhci_port = {
+    .name = "uhci port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(ctrl, UHCIPort),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_uhci = {
+    .name = "uhci",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = uhci_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, UHCIState),
+        VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
+        VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1,
+                             vmstate_uhci_port, UHCIPort),
+        VMSTATE_UINT16(cmd, UHCIState),
+        VMSTATE_UINT16(status, UHCIState),
+        VMSTATE_UINT16(intr, UHCIState),
+        VMSTATE_UINT16(frnum, UHCIState),
+        VMSTATE_UINT32(fl_base_addr, UHCIState),
+        VMSTATE_UINT8(sof_timing, UHCIState),
+        VMSTATE_UINT8(status2, UHCIState),
+        VMSTATE_TIMER(frame_timer, UHCIState),
+        VMSTATE_INT64_V(expire_time, UHCIState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    UHCIState *s = opaque;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x0c:
+        s->sof_timing = val;
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x0c:
+        val = s->sof_timing;
+        break;
+    default:
+        val = 0xff;
+        break;
+    }
+    return val;
+}
+
+static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    UHCIState *s = opaque;
+
+    addr &= 0x1f;
+    DPRINTF("uhci: writew port=0x%04x val=0x%04x\n", addr, val);
+
+    switch(addr) {
+    case 0x00:
+        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
+            /* start frame processing */
+            s->expire_time = qemu_get_clock_ns(vm_clock) +
+                (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+            qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
+            s->status &= ~UHCI_STS_HCHALTED;
+        } else if (!(val & UHCI_CMD_RS)) {
+            s->status |= UHCI_STS_HCHALTED;
+        }
+        if (val & UHCI_CMD_GRESET) {
+            UHCIPort *port;
+            USBDevice *dev;
+            int i;
+
+            /* send reset on the USB bus */
+            for(i = 0; i < NB_PORTS; i++) {
+                port = &s->ports[i];
+                dev = port->port.dev;
+                if (dev) {
+                    usb_send_msg(dev, USB_MSG_RESET);
+                }
+            }
+            uhci_reset(s);
+            return;
+        }
+        if (val & UHCI_CMD_HCRESET) {
+            uhci_reset(s);
+            return;
+        }
+        s->cmd = val;
+        break;
+    case 0x02:
+        s->status &= ~val;
+        /* XXX: the chip spec is not coherent, so we add a hidden
+           register to distinguish between IOC and SPD */
+        if (val & UHCI_STS_USBINT)
+            s->status2 = 0;
+        uhci_update_irq(s);
+        break;
+    case 0x04:
+        s->intr = val;
+        uhci_update_irq(s);
+        break;
+    case 0x06:
+        if (s->status & UHCI_STS_HCHALTED)
+            s->frnum = val & 0x7ff;
+        break;
+    case 0x10 ... 0x1f:
+        {
+            UHCIPort *port;
+            USBDevice *dev;
+            int n;
+
+            n = (addr >> 1) & 7;
+            if (n >= NB_PORTS)
+                return;
+            port = &s->ports[n];
+            dev = port->port.dev;
+            if (dev) {
+                /* port reset */
+                if ( (val & UHCI_PORT_RESET) &&
+                     !(port->ctrl & UHCI_PORT_RESET) ) {
+                    usb_send_msg(dev, USB_MSG_RESET);
+                }
+            }
+            port->ctrl &= UHCI_PORT_READ_ONLY;
+            port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
+            /* some bits are reset when a '1' is written to them */
+            port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
+        }
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x00:
+        val = s->cmd;
+        break;
+    case 0x02:
+        val = s->status;
+        break;
+    case 0x04:
+        val = s->intr;
+        break;
+    case 0x06:
+        val = s->frnum;
+        break;
+    case 0x10 ... 0x1f:
+        {
+            UHCIPort *port;
+            int n;
+            n = (addr >> 1) & 7;
+            if (n >= NB_PORTS)
+                goto read_default;
+            port = &s->ports[n];
+            val = port->ctrl;
+        }
+        break;
+    default:
+    read_default:
+        val = 0xff7f; /* disabled port */
+        break;
+    }
+
+    DPRINTF("uhci: readw port=0x%04x val=0x%04x\n", addr, val);
+
+    return val;
+}
+
+static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    UHCIState *s = opaque;
+
+    addr &= 0x1f;
+    DPRINTF("uhci: writel port=0x%04x val=0x%08x\n", addr, val);
+
+    switch(addr) {
+    case 0x08:
+        s->fl_base_addr = val & ~0xfff;
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x08:
+        val = s->fl_base_addr;
+        break;
+    default:
+        val = 0xffffffff;
+        break;
+    }
+    return val;
+}
+
+/* signal resume if controller suspended */
+static void uhci_resume (void *opaque)
+{
+    UHCIState *s = (UHCIState *)opaque;
+
+    if (!s)
+        return;
+
+    if (s->cmd & UHCI_CMD_EGSM) {
+        s->cmd |= UHCI_CMD_FGR;
+        s->status |= UHCI_STS_RD;
+        uhci_update_irq(s);
+    }
+}
+
+static void uhci_attach(USBPort *port1)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
+
+    /* set connect status */
+    port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+
+    /* update speed */
+    if (port->port.dev->speed == USB_SPEED_LOW) {
+        port->ctrl |= UHCI_PORT_LSDA;
+    } else {
+        port->ctrl &= ~UHCI_PORT_LSDA;
+    }
+
+    uhci_resume(s);
+}
+
+static void uhci_detach(USBPort *port1)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
+
+    uhci_async_cancel_device(s, port1->dev);
+
+    /* set connect status */
+    if (port->ctrl & UHCI_PORT_CCS) {
+        port->ctrl &= ~UHCI_PORT_CCS;
+        port->ctrl |= UHCI_PORT_CSC;
+    }
+    /* disable port */
+    if (port->ctrl & UHCI_PORT_EN) {
+        port->ctrl &= ~UHCI_PORT_EN;
+        port->ctrl |= UHCI_PORT_ENC;
+    }
+
+    uhci_resume(s);
+}
+
+static void uhci_child_detach(USBPort *port1, USBDevice *child)
+{
+    UHCIState *s = port1->opaque;
+
+    uhci_async_cancel_device(s, child);
+}
+
+static void uhci_wakeup(USBPort *port1)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
+
+    if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
+        port->ctrl |= UHCI_PORT_RD;
+        uhci_resume(s);
+    }
+}
+
+static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
+{
+    int i, ret;
+
+    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n",
+           pid2str(p->pid), p->devaddr, p->devep, p->len);
+    if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
+        dump_data(p->data, p->len);
+
+    ret = USB_RET_NODEV;
+    for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
+        UHCIPort *port = &s->ports[i];
+        USBDevice *dev = port->port.dev;
+
+        if (dev && (port->ctrl & UHCI_PORT_EN))
+            ret = usb_handle_packet(dev, p);
+    }
+
+    DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+    if (p->pid == USB_TOKEN_IN && ret > 0)
+        dump_data(p->data, ret);
+
+    return ret;
+}
+
+static void uhci_async_complete(USBPort *port, USBPacket *packet);
+static void uhci_process_frame(UHCIState *s);
+
+/* return -1 if fatal error (frame must be stopped)
+          0 if TD successful
+          1 if TD unsuccessful or inactive
+*/
+static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
+{
+    int len = 0, max_len, err, ret;
+    uint8_t pid;
+
+    max_len = ((td->token >> 21) + 1) & 0x7ff;
+    pid = td->token & 0xff;
+
+    ret = async->packet.len;
+
+    if (td->ctrl & TD_CTRL_IOS)
+        td->ctrl &= ~TD_CTRL_ACTIVE;
+
+    if (ret < 0)
+        goto out;
+
+    len = async->packet.len;
+    td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
+
+    /* The NAK bit may have been set by a previous frame, so clear it
+       here.  The docs are somewhat unclear, but win2k relies on this
+       behavior.  */
+    td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
+    if (td->ctrl & TD_CTRL_IOC)
+        *int_mask |= 0x01;
+
+    if (pid == USB_TOKEN_IN) {
+        if (len > max_len) {
+            ret = USB_RET_BABBLE;
+            goto out;
+        }
+
+        if (len > 0) {
+            /* write the data back */
+            cpu_physical_memory_write(td->buffer, async->buffer, len);
+        }
+
+        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
+            *int_mask |= 0x02;
+            /* short packet: do not update QH */
+            DPRINTF("uhci: short packet. td 0x%x token 0x%x\n", async->td, async->token);
+            return 1;
+        }
+    }
+
+    /* success */
+    return 0;
+
+out:
+    switch(ret) {
+    case USB_RET_STALL:
+        td->ctrl |= TD_CTRL_STALL;
+        td->ctrl &= ~TD_CTRL_ACTIVE;
+        s->status |= UHCI_STS_USBERR;
+        if (td->ctrl & TD_CTRL_IOC) {
+            *int_mask |= 0x01;
+        }
+        uhci_update_irq(s);
+        return 1;
+
+    case USB_RET_BABBLE:
+        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
+        td->ctrl &= ~TD_CTRL_ACTIVE;
+        s->status |= UHCI_STS_USBERR;
+        if (td->ctrl & TD_CTRL_IOC) {
+            *int_mask |= 0x01;
+        }
+        uhci_update_irq(s);
+        /* frame interrupted */
+        return -1;
+
+    case USB_RET_NAK:
+        td->ctrl |= TD_CTRL_NAK;
+        if (pid == USB_TOKEN_SETUP)
+            break;
+	return 1;
+
+    case USB_RET_NODEV:
+    default:
+	break;
+    }
+
+    /* Retry the TD if error count is not zero */
+
+    td->ctrl |= TD_CTRL_TIMEOUT;
+    err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
+    if (err != 0) {
+        err--;
+        if (err == 0) {
+            td->ctrl &= ~TD_CTRL_ACTIVE;
+            s->status |= UHCI_STS_USBERR;
+            if (td->ctrl & TD_CTRL_IOC)
+                *int_mask |= 0x01;
+            uhci_update_irq(s);
+        }
+    }
+    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
+        (err << TD_CTRL_ERROR_SHIFT);
+    return 1;
+}
+
+static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
+{
+    UHCIAsync *async;
+    int len = 0, max_len;
+    uint8_t pid, isoc;
+    uint32_t token;
+
+    /* Is active ? */
+    if (!(td->ctrl & TD_CTRL_ACTIVE))
+        return 1;
+
+    /* token field is not unique for isochronous requests,
+     * so use the destination buffer 
+     */
+    if (td->ctrl & TD_CTRL_IOS) {
+        token = td->buffer;
+        isoc = 1;
+    } else {
+        token = td->token;
+        isoc = 0;
+    }
+
+    async = uhci_async_find_td(s, addr, token);
+    if (async) {
+        /* Already submitted */
+        async->valid = 32;
+
+        if (!async->done)
+            return 1;
+
+        uhci_async_unlink(s, async);
+        goto done;
+    }
+
+    /* Allocate new packet */
+    async = uhci_async_alloc(s);
+    if (!async)
+        return 1;
+
+    /* valid needs to be large enough to handle 10 frame delay
+     * for initial isochronous requests
+     */
+    async->valid = 32;
+    async->td    = addr;
+    async->token = token;
+    async->isoc  = isoc;
+
+    max_len = ((td->token >> 21) + 1) & 0x7ff;
+    pid = td->token & 0xff;
+
+    async->packet.pid     = pid;
+    async->packet.devaddr = (td->token >> 8) & 0x7f;
+    async->packet.devep   = (td->token >> 15) & 0xf;
+    async->packet.data    = async->buffer;
+    async->packet.len     = max_len;
+
+    switch(pid) {
+    case USB_TOKEN_OUT:
+    case USB_TOKEN_SETUP:
+        cpu_physical_memory_read(td->buffer, async->buffer, max_len);
+        len = uhci_broadcast_packet(s, &async->packet);
+        if (len >= 0)
+            len = max_len;
+        break;
+
+    case USB_TOKEN_IN:
+        len = uhci_broadcast_packet(s, &async->packet);
+        break;
+
+    default:
+        /* invalid pid : frame interrupted */
+        uhci_async_free(s, async);
+        s->status |= UHCI_STS_HCPERR;
+        uhci_update_irq(s);
+        return -1;
+    }
+ 
+    if (len == USB_RET_ASYNC) {
+        uhci_async_link(s, async);
+        return 2;
+    }
+
+    async->packet.len = len;
+
+done:
+    len = uhci_complete_td(s, td, async, int_mask);
+    uhci_async_free(s, async);
+    return len;
+}
+
+static void uhci_async_complete(USBPort *port, USBPacket *packet)
+{
+    UHCIAsync *async = container_of(packet, UHCIAsync, packet);
+    UHCIState *s = async->uhci;
+
+    DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
+
+    if (async->isoc) {
+        UHCI_TD td;
+        uint32_t link = async->td;
+        uint32_t int_mask = 0, val;
+
+        cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td));
+        le32_to_cpus(&td.link);
+        le32_to_cpus(&td.ctrl);
+        le32_to_cpus(&td.token);
+        le32_to_cpus(&td.buffer);
+
+        uhci_async_unlink(s, async);
+        uhci_complete_td(s, &td, async, &int_mask);
+        s->pending_int_mask |= int_mask;
+
+        /* update the status bits of the TD */
+        val = cpu_to_le32(td.ctrl);
+        cpu_physical_memory_write((link & ~0xf) + 4,
+                                  (const uint8_t *)&val, sizeof(val));
+        uhci_async_free(s, async);
+    } else {
+        async->done = 1;
+        uhci_process_frame(s);
+    }
+}
+
+static int is_valid(uint32_t link)
+{
+    return (link & 1) == 0;
+}
+
+static int is_qh(uint32_t link)
+{
+    return (link & 2) != 0;
+}
+
+static int depth_first(uint32_t link)
+{
+    return (link & 4) != 0;
+}
+
+/* QH DB used for detecting QH loops */
+#define UHCI_MAX_QUEUES 128
+typedef struct {
+    uint32_t addr[UHCI_MAX_QUEUES];
+    int      count;
+} QhDb;
+
+static void qhdb_reset(QhDb *db)
+{
+    db->count = 0;
+}
+
+/* Add QH to DB. Returns 1 if already present or DB is full. */
+static int qhdb_insert(QhDb *db, uint32_t addr)
+{
+    int i;
+    for (i = 0; i < db->count; i++)
+        if (db->addr[i] == addr)
+            return 1;
+
+    if (db->count >= UHCI_MAX_QUEUES)
+        return 1;
+
+    db->addr[db->count++] = addr;
+    return 0;
+}
+
+static void uhci_process_frame(UHCIState *s)
+{
+    uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
+    uint32_t curr_qh;
+    int cnt, ret;
+    UHCI_TD td;
+    UHCI_QH qh;
+    QhDb qhdb;
+
+    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
+
+    DPRINTF("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr);
+
+    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
+    le32_to_cpus(&link);
+
+    int_mask = 0;
+    curr_qh  = 0;
+
+    qhdb_reset(&qhdb);
+
+    for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
+        if (is_qh(link)) {
+            /* QH */
+
+            if (qhdb_insert(&qhdb, link)) {
+                /*
+                 * We're going in circles. Which is not a bug because
+                 * HCD is allowed to do that as part of the BW management. 
+                 * In our case though it makes no sense to spin here. Sync transations 
+                 * are already done, and async completion handler will re-process 
+                 * the frame when something is ready.
+                 */
+                DPRINTF("uhci: detected loop. qh 0x%x\n", link);
+                break;
+            }
+
+            cpu_physical_memory_read(link & ~0xf, (uint8_t *) &qh, sizeof(qh));
+            le32_to_cpus(&qh.link);
+            le32_to_cpus(&qh.el_link);
+
+            DPRINTF("uhci: QH 0x%x load. link 0x%x elink 0x%x\n",
+                    link, qh.link, qh.el_link);
+
+            if (!is_valid(qh.el_link)) {
+                /* QH w/o elements */
+                curr_qh = 0;
+                link = qh.link;
+            } else {
+                /* QH with elements */
+            	curr_qh = link;
+            	link = qh.el_link;
+            }
+            continue;
+        }
+
+        /* TD */
+        cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td));
+        le32_to_cpus(&td.link);
+        le32_to_cpus(&td.ctrl);
+        le32_to_cpus(&td.token);
+        le32_to_cpus(&td.buffer);
+
+        DPRINTF("uhci: TD 0x%x load. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", 
+                link, td.link, td.ctrl, td.token, curr_qh);
+
+        old_td_ctrl = td.ctrl;
+        ret = uhci_handle_td(s, link, &td, &int_mask);
+        if (old_td_ctrl != td.ctrl) {
+            /* update the status bits of the TD */
+            val = cpu_to_le32(td.ctrl);
+            cpu_physical_memory_write((link & ~0xf) + 4,
+                                      (const uint8_t *)&val, sizeof(val));
+        }
+
+        if (ret < 0) {
+            /* interrupted frame */
+            break;
+        }
+
+        if (ret == 2 || ret == 1) {
+            DPRINTF("uhci: TD 0x%x %s. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n",
+                    link, ret == 2 ? "pend" : "skip",
+                    td.link, td.ctrl, td.token, curr_qh);
+
+            link = curr_qh ? qh.link : td.link;
+            continue;
+        }
+
+        /* completed TD */
+
+        DPRINTF("uhci: TD 0x%x done. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", 
+                link, td.link, td.ctrl, td.token, curr_qh);
+
+        link = td.link;
+
+        if (curr_qh) {
+	    /* update QH element link */
+            qh.el_link = link;
+            val = cpu_to_le32(qh.el_link);
+            cpu_physical_memory_write((curr_qh & ~0xf) + 4,
+                                          (const uint8_t *)&val, sizeof(val));
+
+            if (!depth_first(link)) {
+               /* done with this QH */
+
+               DPRINTF("uhci: QH 0x%x done. link 0x%x elink 0x%x\n",
+                       curr_qh, qh.link, qh.el_link);
+
+               curr_qh = 0;
+               link    = qh.link;
+            }
+        }
+
+        /* go to the next entry */
+    }
+
+    s->pending_int_mask |= int_mask;
+}
+
+static void uhci_frame_timer(void *opaque)
+{
+    UHCIState *s = opaque;
+
+    /* prepare the timer for the next frame */
+    s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+
+    if (!(s->cmd & UHCI_CMD_RS)) {
+        /* Full stop */
+        qemu_del_timer(s->frame_timer);
+        /* set hchalted bit in status - UHCI11D 2.1.2 */
+        s->status |= UHCI_STS_HCHALTED;
+
+        DPRINTF("uhci: halted\n");
+        return;
+    }
+
+    /* Complete the previous frame */
+    if (s->pending_int_mask) {
+        s->status2 |= s->pending_int_mask;
+        s->status  |= UHCI_STS_USBINT;
+        uhci_update_irq(s);
+    }
+    s->pending_int_mask = 0;
+
+    /* Start new frame */
+    s->frnum = (s->frnum + 1) & 0x7ff;
+
+    DPRINTF("uhci: new frame #%u\n" , s->frnum);
+
+    uhci_async_validate_begin(s);
+
+    uhci_process_frame(s);
+
+    uhci_async_validate_end(s);
+
+    qemu_mod_timer(s->frame_timer, s->expire_time);
+}
+
+static void uhci_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    UHCIState *s = (UHCIState *)pci_dev;
+
+    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
+    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
+    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
+    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
+    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
+    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
+}
+
+static USBPortOps uhci_port_ops = {
+    .attach = uhci_attach,
+    .detach = uhci_detach,
+    .child_detach = uhci_child_detach,
+    .wakeup = uhci_wakeup,
+    .complete = uhci_async_complete,
+};
+
+static USBBusOps uhci_bus_ops = {
+};
+
+static int usb_uhci_common_initfn(PCIDevice *dev)
+{
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+    int i;
+
+    pci_conf[PCI_CLASS_PROG] = 0x00;
+    /* TODO: reset value should be 0. */
+    pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
+    pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
+
+    if (s->masterbus) {
+        USBPort *ports[NB_PORTS];
+        for(i = 0; i < NB_PORTS; i++) {
+            ports[i] = &s->ports[i].port;
+        }
+        if (usb_register_companion(s->masterbus, ports, NB_PORTS,
+                s->firstport, s, &uhci_port_ops,
+                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+            return -1;
+        }
+    } else {
+        usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
+        for (i = 0; i < NB_PORTS; i++) {
+            usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
+                              USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        }
+    }
+    s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
+    s->num_ports_vmstate = NB_PORTS;
+    QTAILQ_INIT(&s->async_pending);
+
+    qemu_register_reset(uhci_reset, s);
+
+    /* Use region 4 for consistency with real hardware.  BSD guests seem
+       to rely on this.  */
+    pci_register_bar(&s->dev, 4, 0x20,
+                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
+
+    return 0;
+}
+
+static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
+{
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    /* USB misc control 1/2 */
+    pci_set_long(pci_conf + 0x40,0x00001000);
+    /* PM capability */
+    pci_set_long(pci_conf + 0x80,0x00020001);
+    /* USB legacy support  */
+    pci_set_long(pci_conf + 0xc0,0x00002000);
+
+    return usb_uhci_common_initfn(dev);
+}
+
+static Property uhci_properties[] = {
+    DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
+    DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static PCIDeviceInfo uhci_info[] = {
+    {
+        .qdev.name    = "piix3-usb-uhci",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "piix4-usb-uhci",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "vt82c686b-usb-uhci",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_vt82c686b_initfn,
+        .vendor_id    = PCI_VENDOR_ID_VIA,
+        .device_id    = PCI_DEVICE_ID_VIA_UHCI,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci1",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci2",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        .qdev.name    = "ich9-usb-uhci3",
+        .qdev.size    = sizeof(UHCIState),
+        .qdev.vmsd    = &vmstate_uhci,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
+        .revision     = 0x03,
+        .class_id     = PCI_CLASS_SERIAL_USB,
+        .qdev.props   = uhci_properties,
+    },{
+        /* end of list */
+    }
+};
+
+static void uhci_register(void)
+{
+    pci_qdev_register_many(uhci_info);
+}
+device_init(uhci_register);
+
+void usb_uhci_piix3_init(PCIBus *bus, int devfn)
+{
+    pci_create_simple(bus, devfn, "piix3-usb-uhci");
+}
+
+void usb_uhci_piix4_init(PCIBus *bus, int devfn)
+{
+    pci_create_simple(bus, devfn, "piix4-usb-uhci");
+}
+
+void usb_uhci_vt82c686b_init(PCIBus *bus, int devfn)
+{
+    pci_create_simple(bus, devfn, "vt82c686b-usb-uhci");
+}
diff --git a/qemu-0.15.x/hw/usb-uhci.h b/qemu-0.15.x/hw/usb-uhci.h
new file mode 100644
index 0000000..3e4d377
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-uhci.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_USB_UHCI_H
+#define QEMU_USB_UHCI_H
+
+#include "qemu-common.h"
+
+void usb_uhci_piix3_init(PCIBus *bus, int devfn);
+void usb_uhci_piix4_init(PCIBus *bus, int devfn);
+void usb_uhci_vt82c686b_init(PCIBus *bus, int devfn);
+
+#endif
diff --git a/qemu-0.15.x/hw/usb-wacom.c b/qemu-0.15.x/hw/usb-wacom.c
new file mode 100644
index 0000000..9d348e1
--- /dev/null
+++ b/qemu-0.15.x/hw/usb-wacom.c
@@ -0,0 +1,371 @@
+/*
+ * Wacom PenPartner USB tablet emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Author: Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * Based on hw/usb-hid.c:
+ * Copyright (c) 2005 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 "hw.h"
+#include "console.h"
+#include "usb.h"
+#include "usb-desc.h"
+
+/* Interface requests */
+#define WACOM_GET_REPORT	0x2101
+#define WACOM_SET_REPORT	0x2109
+
+/* HID interface requests */
+#define HID_GET_REPORT		0xa101
+#define HID_GET_IDLE		0xa102
+#define HID_GET_PROTOCOL	0xa103
+#define HID_SET_IDLE		0x210a
+#define HID_SET_PROTOCOL	0x210b
+
+typedef struct USBWacomState {
+    USBDevice dev;
+    QEMUPutMouseEntry *eh_entry;
+    int dx, dy, dz, buttons_state;
+    int x, y;
+    int mouse_grabbed;
+    enum {
+        WACOM_MODE_HID = 1,
+        WACOM_MODE_WACOM = 2,
+    } mode;
+    uint8_t idle;
+    int changed;
+} USBWacomState;
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]          = "Wacom PenPartner",
+    [STR_SERIALNUMBER]     = "1",
+};
+
+static const USBDescIface desc_iface_wacom = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 1,
+    .bInterfaceClass               = USB_CLASS_HID,
+    .bInterfaceSubClass            = 0x01, /* boot */
+    .bInterfaceProtocol            = 0x02,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* HID descriptor */
+            .data = (uint8_t[]) {
+                0x09,          /*  u8  bLength */
+                0x21,          /*  u8  bDescriptorType */
+                0x01, 0x10,    /*  u16 HID_class */
+                0x00,          /*  u8  country_code */
+                0x01,          /*  u8  num_descriptors */
+                0x22,          /*  u8  type: Report */
+                0x6e, 0,       /*  u16 len */
+            },
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | 0x01,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .wMaxPacketSize        = 8,
+            .bInterval             = 0x0a,
+        },
+    },
+};
+
+static const USBDescDevice desc_device_wacom = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = 8,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0x80,
+            .bMaxPower             = 40,
+            .nif = 1,
+            .ifs = &desc_iface_wacom,
+        },
+    },
+};
+
+static const USBDesc desc_wacom = {
+    .id = {
+        .idVendor          = 0x056a,
+        .idProduct         = 0x0000,
+        .bcdDevice         = 0x4210,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device_wacom,
+    .str  = desc_strings,
+};
+
+static void usb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    s->buttons_state = buttons_state;
+    s->changed = 1;
+}
+
+static void usb_wacom_event(void *opaque,
+                            int x, int y, int dz, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    /* scale to Penpartner resolution */
+    s->x = (x * 5040 / 0x7FFF);
+    s->y = (y * 3780 / 0x7FFF);
+    s->dz += dz;
+    s->buttons_state = buttons_state;
+    s->changed = 1;
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin)
+        return vmin;
+    else if (val > vmax)
+        return vmax;
+    else
+        return val;
+}
+
+static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+
+    if (!s->mouse_grabbed) {
+        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
+                        "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 1;
+    }
+
+    dx = int_clamp(s->dx, -128, 127);
+    dy = int_clamp(s->dy, -128, 127);
+    dz = int_clamp(s->dz, -128, 127);
+
+    s->dx -= dx;
+    s->dy -= dy;
+    s->dz -= dz;
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    buf[0] = b;
+    buf[1] = dx;
+    buf[2] = dy;
+    l = 3;
+    if (len >= 4) {
+        buf[3] = dz;
+        l = 4;
+    }
+    return l;
+}
+
+static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int b;
+
+    if (!s->mouse_grabbed) {
+        s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
+                        "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 1;
+    }
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x40;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x20; /* eraser */
+
+    if (len < 7)
+        return 0;
+
+    buf[0] = s->mode;
+    buf[5] = 0x00 | (b & 0xf0);
+    buf[1] = s->x & 0xff;
+    buf[2] = s->x >> 8;
+    buf[3] = s->y & 0xff;
+    buf[4] = s->y >> 8;
+    if (b & 0x3f) {
+        buf[6] = 0;
+    } else {
+        buf[6] = (unsigned char) -127;
+    }
+
+    return 7;
+}
+
+static void usb_wacom_handle_reset(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    s->dx = 0;
+    s->dy = 0;
+    s->dz = 0;
+    s->x = 0;
+    s->y = 0;
+    s->buttons_state = 0;
+    s->mode = WACOM_MODE_HID;
+}
+
+static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret;
+
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
+    ret = 0;
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case WACOM_SET_REPORT:
+        if (s->mouse_grabbed) {
+            qemu_remove_mouse_event_handler(s->eh_entry);
+            s->mouse_grabbed = 0;
+        }
+        s->mode = data[0];
+        ret = 0;
+        break;
+    case WACOM_GET_REPORT:
+        data[0] = 0;
+        data[1] = s->mode;
+        ret = 2;
+        break;
+    /* USB HID requests */
+    case HID_GET_REPORT:
+        if (s->mode == WACOM_MODE_HID)
+            ret = usb_mouse_poll(s, data, length);
+        else if (s->mode == WACOM_MODE_WACOM)
+            ret = usb_wacom_poll(s, data, length);
+        break;
+    case HID_GET_IDLE:
+        ret = 1;
+        data[0] = s->idle;
+        break;
+    case HID_SET_IDLE:
+        s->idle = (uint8_t) (value >> 8);
+        ret = 0;
+        break;
+    default:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret = 0;
+
+    switch (p->pid) {
+    case USB_TOKEN_IN:
+        if (p->devep == 1) {
+            if (!(s->changed || s->idle))
+                return USB_RET_NAK;
+            s->changed = 0;
+            if (s->mode == WACOM_MODE_HID)
+                ret = usb_mouse_poll(s, p->data, p->len);
+            else if (s->mode == WACOM_MODE_WACOM)
+                ret = usb_wacom_poll(s, p->data, p->len);
+            break;
+        }
+        /* Fall through.  */
+    case USB_TOKEN_OUT:
+    default:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_wacom_handle_destroy(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    if (s->mouse_grabbed) {
+        qemu_remove_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 0;
+    }
+}
+
+static int usb_wacom_initfn(USBDevice *dev)
+{
+    USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
+    usb_desc_init(dev);
+    s->changed = 1;
+    return 0;
+}
+
+static struct USBDeviceInfo wacom_info = {
+    .product_desc   = "QEMU PenPartner Tablet",
+    .qdev.name      = "usb-wacom-tablet",
+    .qdev.desc      = "QEMU PenPartner Tablet",
+    .usbdevice_name = "wacom-tablet",
+    .usb_desc       = &desc_wacom,
+    .qdev.size      = sizeof(USBWacomState),
+    .init           = usb_wacom_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_wacom_handle_reset,
+    .handle_control = usb_wacom_handle_control,
+    .handle_data    = usb_wacom_handle_data,
+    .handle_destroy = usb_wacom_handle_destroy,
+};
+
+static void usb_wacom_register_devices(void)
+{
+    usb_qdev_register(&wacom_info);
+}
+device_init(usb_wacom_register_devices)
diff --git a/qemu-0.15.x/hw/usb.c b/qemu-0.15.x/hw/usb.c
new file mode 100644
index 0000000..27a983c
--- /dev/null
+++ b/qemu-0.15.x/hw/usb.c
@@ -0,0 +1,349 @@
+/*
+ * QEMU USB emulation
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * 2008 Generic packet handler rewrite by Max Krasnyansky
+ *
+ * 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 "qemu-common.h"
+#include "usb.h"
+
+void usb_attach(USBPort *port, USBDevice *dev)
+{
+    if (dev != NULL) {
+        /* attach */
+        if (port->dev) {
+            usb_attach(port, NULL);
+        }
+        dev->port = port;
+        port->dev = dev;
+        port->ops->attach(port);
+        usb_send_msg(dev, USB_MSG_ATTACH);
+    } else {
+        /* detach */
+        dev = port->dev;
+        assert(dev);
+        port->ops->detach(port);
+        usb_send_msg(dev, USB_MSG_DETACH);
+        dev->port = NULL;
+        port->dev = NULL;
+    }
+}
+
+void usb_wakeup(USBDevice *dev)
+{
+    if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
+        dev->port->ops->wakeup(dev->port);
+    }
+}
+
+/**********************/
+
+/* generic USB device helpers (you are not forced to use them when
+   writing your USB device driver, but they help handling the
+   protocol)
+*/
+
+#define SETUP_STATE_IDLE  0
+#define SETUP_STATE_SETUP 1
+#define SETUP_STATE_DATA  2
+#define SETUP_STATE_ACK   3
+
+static int do_token_setup(USBDevice *s, USBPacket *p)
+{
+    int request, value, index;
+    int ret = 0;
+
+    if (p->len != 8)
+        return USB_RET_STALL;
+ 
+    memcpy(s->setup_buf, p->data, 8);
+    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
+    s->setup_index = 0;
+
+    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
+    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
+    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
+
+    if (s->setup_buf[0] & USB_DIR_IN) {
+        ret = s->info->handle_control(s, p, request, value, index,
+                                      s->setup_len, s->data_buf);
+        if (ret == USB_RET_ASYNC) {
+             s->setup_state = SETUP_STATE_SETUP;
+             return USB_RET_ASYNC;
+        }
+        if (ret < 0)
+            return ret;
+
+        if (ret < s->setup_len)
+            s->setup_len = ret;
+        s->setup_state = SETUP_STATE_DATA;
+    } else {
+        if (s->setup_len > sizeof(s->data_buf)) {
+            fprintf(stderr,
+                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
+                s->setup_len, sizeof(s->data_buf));
+            return USB_RET_STALL;
+        }
+        if (s->setup_len == 0)
+            s->setup_state = SETUP_STATE_ACK;
+        else
+            s->setup_state = SETUP_STATE_DATA;
+    }
+
+    return ret;
+}
+
+static int do_token_in(USBDevice *s, USBPacket *p)
+{
+    int request, value, index;
+    int ret = 0;
+
+    if (p->devep != 0)
+        return s->info->handle_data(s, p);
+
+    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
+    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
+    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
+ 
+    switch(s->setup_state) {
+    case SETUP_STATE_ACK:
+        if (!(s->setup_buf[0] & USB_DIR_IN)) {
+            ret = s->info->handle_control(s, p, request, value, index,
+                                          s->setup_len, s->data_buf);
+            if (ret == USB_RET_ASYNC) {
+                return USB_RET_ASYNC;
+            }
+            s->setup_state = SETUP_STATE_IDLE;
+            if (ret > 0)
+                return 0;
+            return ret;
+        }
+
+        /* return 0 byte */
+        return 0;
+
+    case SETUP_STATE_DATA:
+        if (s->setup_buf[0] & USB_DIR_IN) {
+            int len = s->setup_len - s->setup_index;
+            if (len > p->len)
+                len = p->len;
+            memcpy(p->data, s->data_buf + s->setup_index, len);
+            s->setup_index += len;
+            if (s->setup_index >= s->setup_len)
+                s->setup_state = SETUP_STATE_ACK;
+            return len;
+        }
+
+        s->setup_state = SETUP_STATE_IDLE;
+        return USB_RET_STALL;
+
+    default:
+        return USB_RET_STALL;
+    }
+}
+
+static int do_token_out(USBDevice *s, USBPacket *p)
+{
+    if (p->devep != 0)
+        return s->info->handle_data(s, p);
+
+    switch(s->setup_state) {
+    case SETUP_STATE_ACK:
+        if (s->setup_buf[0] & USB_DIR_IN) {
+            s->setup_state = SETUP_STATE_IDLE;
+            /* transfer OK */
+        } else {
+            /* ignore additional output */
+        }
+        return 0;
+
+    case SETUP_STATE_DATA:
+        if (!(s->setup_buf[0] & USB_DIR_IN)) {
+            int len = s->setup_len - s->setup_index;
+            if (len > p->len)
+                len = p->len;
+            memcpy(s->data_buf + s->setup_index, p->data, len);
+            s->setup_index += len;
+            if (s->setup_index >= s->setup_len)
+                s->setup_state = SETUP_STATE_ACK;
+            return len;
+        }
+
+        s->setup_state = SETUP_STATE_IDLE;
+        return USB_RET_STALL;
+
+    default:
+        return USB_RET_STALL;
+    }
+}
+
+/*
+ * Generic packet handler.
+ * Called by the HC (host controller).
+ *
+ * Returns length of the transaction or one of the USB_RET_XXX codes.
+ */
+int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
+{
+    switch(p->pid) {
+    case USB_MSG_ATTACH:
+        s->state = USB_STATE_ATTACHED;
+        if (s->info->handle_attach) {
+            s->info->handle_attach(s);
+        }
+        return 0;
+
+    case USB_MSG_DETACH:
+        s->state = USB_STATE_NOTATTACHED;
+        return 0;
+
+    case USB_MSG_RESET:
+        s->remote_wakeup = 0;
+        s->addr = 0;
+        s->state = USB_STATE_DEFAULT;
+        if (s->info->handle_reset) {
+            s->info->handle_reset(s);
+        }
+        return 0;
+    }
+
+    /* Rest of the PIDs must match our address */
+    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
+        return USB_RET_NODEV;
+
+    switch (p->pid) {
+    case USB_TOKEN_SETUP:
+        return do_token_setup(s, p);
+
+    case USB_TOKEN_IN:
+        return do_token_in(s, p);
+
+    case USB_TOKEN_OUT:
+        return do_token_out(s, p);
+ 
+    default:
+        return USB_RET_STALL;
+    }
+}
+
+/* ctrl complete function for devices which use usb_generic_handle_packet and
+   may return USB_RET_ASYNC from their handle_control callback. Device code
+   which does this *must* call this function instead of the normal
+   usb_packet_complete to complete their async control packets. */
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
+{
+    if (p->len < 0) {
+        s->setup_state = SETUP_STATE_IDLE;
+    }
+
+    switch (s->setup_state) {
+    case SETUP_STATE_SETUP:
+        if (p->len < s->setup_len) {
+            s->setup_len = p->len;
+        }
+        s->setup_state = SETUP_STATE_DATA;
+        p->len = 8;
+        break;
+
+    case SETUP_STATE_ACK:
+        s->setup_state = SETUP_STATE_IDLE;
+        p->len = 0;
+        break;
+
+    default:
+        break;
+    }
+    usb_packet_complete(s, p);
+}
+
+/* XXX: fix overflow */
+int set_usb_string(uint8_t *buf, const char *str)
+{
+    int len, i;
+    uint8_t *q;
+
+    q = buf;
+    len = strlen(str);
+    *q++ = 2 * len + 2;
+    *q++ = 3;
+    for(i = 0; i < len; i++) {
+        *q++ = str[i];
+        *q++ = 0;
+    }
+    return q - buf;
+}
+
+/* Send an internal message to a USB device.  */
+void usb_send_msg(USBDevice *dev, int msg)
+{
+    USBPacket p;
+    int ret;
+
+    memset(&p, 0, sizeof(p));
+    p.pid = msg;
+    ret = usb_handle_packet(dev, &p);
+    /* This _must_ be synchronous */
+    assert(ret != USB_RET_ASYNC);
+}
+
+/* Hand over a packet to a device for processing.  Return value
+   USB_RET_ASYNC indicates the processing isn't finished yet, the
+   driver will call usb_packet_complete() when done processing it. */
+int usb_handle_packet(USBDevice *dev, USBPacket *p)
+{
+    int ret;
+
+    assert(p->owner == NULL);
+    ret = dev->info->handle_packet(dev, p);
+    if (ret == USB_RET_ASYNC) {
+        if (p->owner == NULL) {
+            p->owner = dev;
+        } else {
+            /* We'll end up here when usb_handle_packet is called
+             * recursively due to a hub being in the chain.  Nothing
+             * to do.  Leave p->owner pointing to the device, not the
+             * hub. */;
+        }
+    }
+    return ret;
+}
+
+/* Notify the controller that an async packet is complete.  This should only
+   be called for packets previously deferred by returning USB_RET_ASYNC from
+   handle_packet. */
+void usb_packet_complete(USBDevice *dev, USBPacket *p)
+{
+    /* Note: p->owner != dev is possible in case dev is a hub */
+    assert(p->owner != NULL);
+    dev->port->ops->complete(dev->port, p);
+    p->owner = NULL;
+}
+
+/* Cancel an active packet.  The packed must have been deferred by
+   returning USB_RET_ASYNC from handle_packet, and not yet
+   completed.  */
+void usb_cancel_packet(USBPacket * p)
+{
+    assert(p->owner != NULL);
+    p->owner->info->cancel_packet(p->owner, p);
+    p->owner = NULL;
+}
diff --git a/qemu-0.15.x/hw/usb.h b/qemu-0.15.x/hw/usb.h
new file mode 100644
index 0000000..ded2de2
--- /dev/null
+++ b/qemu-0.15.x/hw/usb.h
@@ -0,0 +1,382 @@
+/*
+ * QEMU USB API
+ *
+ * Copyright (c) 2005 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 "block.h"
+#include "qdev.h"
+#include "qemu-queue.h"
+
+/* Constants related to the USB / PCI interaction */
+#define USB_SBRN    0x60 /* Serial Bus Release Number Register */
+#define USB_RELEASE_1  0x10 /* USB 1.0 */
+#define USB_RELEASE_2  0x20 /* USB 2.0 */
+#define USB_RELEASE_3  0x30 /* USB 3.0 */
+
+#define USB_TOKEN_SETUP 0x2d
+#define USB_TOKEN_IN    0x69 /* device -> host */
+#define USB_TOKEN_OUT   0xe1 /* host -> device */
+
+/* specific usb messages, also sent in the 'pid' parameter */
+#define USB_MSG_ATTACH   0x100
+#define USB_MSG_DETACH   0x101
+#define USB_MSG_RESET    0x102
+
+#define USB_RET_NODEV  (-1)
+#define USB_RET_NAK    (-2)
+#define USB_RET_STALL  (-3)
+#define USB_RET_BABBLE (-4)
+#define USB_RET_ASYNC  (-5)
+
+#define USB_SPEED_LOW   0
+#define USB_SPEED_FULL  1
+#define USB_SPEED_HIGH  2
+#define USB_SPEED_SUPER 3
+
+#define USB_SPEED_MASK_LOW   (1 << USB_SPEED_LOW)
+#define USB_SPEED_MASK_FULL  (1 << USB_SPEED_FULL)
+#define USB_SPEED_MASK_HIGH  (1 << USB_SPEED_HIGH)
+#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER)
+
+#define USB_STATE_NOTATTACHED 0
+#define USB_STATE_ATTACHED    1
+//#define USB_STATE_POWERED     2
+#define USB_STATE_DEFAULT     3
+//#define USB_STATE_ADDRESS     4
+//#define	USB_STATE_CONFIGURED  5
+#define USB_STATE_SUSPENDED   6
+
+#define USB_CLASS_AUDIO			1
+#define USB_CLASS_COMM			2
+#define USB_CLASS_HID			3
+#define USB_CLASS_PHYSICAL		5
+#define USB_CLASS_STILL_IMAGE		6
+#define USB_CLASS_PRINTER		7
+#define USB_CLASS_MASS_STORAGE		8
+#define USB_CLASS_HUB			9
+#define USB_CLASS_CDC_DATA		0x0a
+#define USB_CLASS_CSCID			0x0b
+#define USB_CLASS_CONTENT_SEC		0x0d
+#define USB_CLASS_APP_SPEC		0xfe
+#define USB_CLASS_VENDOR_SPEC		0xff
+
+#define USB_DIR_OUT			0
+#define USB_DIR_IN			0x80
+
+#define USB_TYPE_MASK			(0x03 << 5)
+#define USB_TYPE_STANDARD		(0x00 << 5)
+#define USB_TYPE_CLASS			(0x01 << 5)
+#define USB_TYPE_VENDOR			(0x02 << 5)
+#define USB_TYPE_RESERVED		(0x03 << 5)
+
+#define USB_RECIP_MASK			0x1f
+#define USB_RECIP_DEVICE		0x00
+#define USB_RECIP_INTERFACE		0x01
+#define USB_RECIP_ENDPOINT		0x02
+#define USB_RECIP_OTHER			0x03
+
+#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define InterfaceRequest \
+        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define InterfaceOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+#define EndpointOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+#define ClassInterfaceRequest \
+        ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
+#define ClassInterfaceOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
+
+#define USB_REQ_GET_STATUS		0x00
+#define USB_REQ_CLEAR_FEATURE		0x01
+#define USB_REQ_SET_FEATURE		0x03
+#define USB_REQ_SET_ADDRESS		0x05
+#define USB_REQ_GET_DESCRIPTOR		0x06
+#define USB_REQ_SET_DESCRIPTOR		0x07
+#define USB_REQ_GET_CONFIGURATION	0x08
+#define USB_REQ_SET_CONFIGURATION	0x09
+#define USB_REQ_GET_INTERFACE		0x0A
+#define USB_REQ_SET_INTERFACE		0x0B
+#define USB_REQ_SYNCH_FRAME		0x0C
+
+#define USB_DEVICE_SELF_POWERED		0
+#define USB_DEVICE_REMOTE_WAKEUP	1
+
+#define USB_DT_DEVICE			0x01
+#define USB_DT_CONFIG			0x02
+#define USB_DT_STRING			0x03
+#define USB_DT_INTERFACE		0x04
+#define USB_DT_ENDPOINT			0x05
+#define USB_DT_DEVICE_QUALIFIER         0x06
+#define USB_DT_OTHER_SPEED_CONFIG       0x07
+#define USB_DT_DEBUG                    0x0A
+#define USB_DT_INTERFACE_ASSOC          0x0B
+
+#define USB_ENDPOINT_XFER_CONTROL	0
+#define USB_ENDPOINT_XFER_ISOC		1
+#define USB_ENDPOINT_XFER_BULK		2
+#define USB_ENDPOINT_XFER_INT		3
+
+typedef struct USBBus USBBus;
+typedef struct USBBusOps USBBusOps;
+typedef struct USBPort USBPort;
+typedef struct USBDevice USBDevice;
+typedef struct USBDeviceInfo USBDeviceInfo;
+typedef struct USBPacket USBPacket;
+
+typedef struct USBDesc USBDesc;
+typedef struct USBDescID USBDescID;
+typedef struct USBDescDevice USBDescDevice;
+typedef struct USBDescConfig USBDescConfig;
+typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
+typedef struct USBDescIface USBDescIface;
+typedef struct USBDescEndpoint USBDescEndpoint;
+typedef struct USBDescOther USBDescOther;
+typedef struct USBDescString USBDescString;
+
+struct USBDescString {
+    uint8_t index;
+    char *str;
+    QLIST_ENTRY(USBDescString) next;
+};
+
+/* definition of a USB device */
+struct USBDevice {
+    DeviceState qdev;
+    USBDeviceInfo *info;
+    USBPort *port;
+    char *port_path;
+    void *opaque;
+
+    /* Actual connected speed */
+    int speed;
+    /* Supported speeds, not in info because it may be variable (hostdevs) */
+    int speedmask;
+    uint8_t addr;
+    char product_desc[32];
+    int auto_attach;
+    int attached;
+
+    int32_t state;
+    uint8_t setup_buf[8];
+    uint8_t data_buf[4096];
+    int32_t remote_wakeup;
+    int32_t setup_state;
+    int32_t setup_len;
+    int32_t setup_index;
+
+    QLIST_HEAD(, USBDescString) strings;
+    const USBDescDevice *device;
+    const USBDescConfig *config;
+};
+
+struct USBDeviceInfo {
+    DeviceInfo qdev;
+    int (*init)(USBDevice *dev);
+
+    /*
+     * Process USB packet.
+     * Called by the HC (Host Controller).
+     *
+     * Returns length of the transaction
+     * or one of the USB_RET_XXX codes.
+     */
+    int (*handle_packet)(USBDevice *dev, USBPacket *p);
+
+    /*
+     * Called when a packet is canceled.
+     */
+    void (*cancel_packet)(USBDevice *dev, USBPacket *p);
+
+    /*
+     * Called when device is destroyed.
+     */
+    void (*handle_destroy)(USBDevice *dev);
+
+    /*
+     * Attach the device
+     */
+    void (*handle_attach)(USBDevice *dev);
+
+    /*
+     * Reset the device
+     */
+    void (*handle_reset)(USBDevice *dev);
+
+    /*
+     * Process control request.
+     * Called from handle_packet().
+     *
+     * Returns length or one of the USB_RET_ codes.
+     */
+    int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
+                          int index, int length, uint8_t *data);
+
+    /*
+     * Process data transfers (both BULK and ISOC).
+     * Called from handle_packet().
+     *
+     * Returns length or one of the USB_RET_ codes.
+     */
+    int (*handle_data)(USBDevice *dev, USBPacket *p);
+
+    const char *product_desc;
+    const USBDesc *usb_desc;
+
+    /* handle legacy -usbdevice command line options */
+    const char *usbdevice_name;
+    USBDevice *(*usbdevice_init)(const char *params);
+};
+
+typedef struct USBPortOps {
+    void (*attach)(USBPort *port);
+    void (*detach)(USBPort *port);
+    /*
+     * This gets called when a device downstream from the device attached to
+     * the port (iow attached through a hub) gets detached.
+     */
+    void (*child_detach)(USBPort *port, USBDevice *child);
+    void (*wakeup)(USBPort *port);
+    /*
+     * Note that port->dev will be different then the device from which
+     * the packet originated when a hub is involved, if you want the orginating
+     * device use p->owner
+     */
+    void (*complete)(USBPort *port, USBPacket *p);
+} USBPortOps;
+
+/* USB port on which a device can be connected */
+struct USBPort {
+    USBDevice *dev;
+    int speedmask;
+    char path[16];
+    USBPortOps *ops;
+    void *opaque;
+    int index; /* internal port index, may be used with the opaque */
+    QTAILQ_ENTRY(USBPort) next;
+};
+
+typedef void USBCallback(USBPacket * packet, void *opaque);
+
+/* Structure used to hold information about an active USB packet.  */
+struct USBPacket {
+    /* Data fields for use by the driver.  */
+    int pid;
+    uint8_t devaddr;
+    uint8_t devep;
+    uint8_t *data;
+    int len;
+    /* Internal use by the USB layer.  */
+    USBDevice *owner;
+};
+
+int usb_handle_packet(USBDevice *dev, USBPacket *p);
+void usb_packet_complete(USBDevice *dev, USBPacket *p);
+void usb_cancel_packet(USBPacket * p);
+
+void usb_attach(USBPort *port, USBDevice *dev);
+void usb_wakeup(USBDevice *dev);
+int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
+int set_usb_string(uint8_t *buf, const char *str);
+void usb_send_msg(USBDevice *dev, int msg);
+
+/* usb-linux.c */
+USBDevice *usb_host_device_open(const char *devname);
+int usb_host_device_close(const char *devname);
+void usb_host_info(Monitor *mon);
+
+/* usb-hid.c */
+void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
+
+/* usb-bt.c */
+USBDevice *usb_bt_init(HCIInfo *hci);
+
+/* usb ports of the VM */
+
+#define VM_USB_HUB_SIZE 8
+
+/* usb-musb.c */
+enum musb_irq_source_e {
+    musb_irq_suspend = 0,
+    musb_irq_resume,
+    musb_irq_rst_babble,
+    musb_irq_sof,
+    musb_irq_connect,
+    musb_irq_disconnect,
+    musb_irq_vbus_request,
+    musb_irq_vbus_error,
+    musb_irq_rx,
+    musb_irq_tx,
+    musb_set_vbus,
+    musb_set_session,
+    __musb_irq_max,
+};
+
+typedef struct MUSBState MUSBState;
+MUSBState *musb_init(qemu_irq *irqs);
+uint32_t musb_core_intr_get(MUSBState *s);
+void musb_core_intr_clear(MUSBState *s, uint32_t mask);
+void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
+
+/* usb-bus.c */
+
+struct USBBus {
+    BusState qbus;
+    USBBusOps *ops;
+    int busnr;
+    int nfree;
+    int nused;
+    QTAILQ_HEAD(, USBPort) free;
+    QTAILQ_HEAD(, USBPort) used;
+    QTAILQ_ENTRY(USBBus) next;
+};
+
+struct USBBusOps {
+    int (*register_companion)(USBBus *bus, USBPort *ports[],
+                              uint32_t portcount, uint32_t firstport);
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
+USBBus *usb_bus_find(int busnr);
+void usb_qdev_register(USBDeviceInfo *info);
+void usb_qdev_register_many(USBDeviceInfo *info);
+USBDevice *usb_create(USBBus *bus, const char *name);
+USBDevice *usb_create_simple(USBBus *bus, const char *name);
+USBDevice *usbdevice_create(const char *cmdline);
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+                       USBPortOps *ops, int speedmask);
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+                           uint32_t portcount, uint32_t firstport,
+                           void *opaque, USBPortOps *ops, int speedmask);
+void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
+void usb_unregister_port(USBBus *bus, USBPort *port);
+int usb_device_attach(USBDevice *dev);
+int usb_device_detach(USBDevice *dev);
+int usb_device_delete_addr(int busnr, int addr);
+
+static inline USBBus *usb_bus_from_device(USBDevice *d)
+{
+    return DO_UPCAST(USBBus, qbus, d->qdev.parent_bus);
+}
diff --git a/qemu-0.15.x/hw/versatile_pci.c b/qemu-0.15.x/hw/versatile_pci.c
new file mode 100644
index 0000000..290a900
--- /dev/null
+++ b/qemu-0.15.x/hw/versatile_pci.c
@@ -0,0 +1,160 @@
+/*
+ * ARM Versatile/PB PCI host controller
+ *
+ * Copyright (c) 2006-2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "sysbus.h"
+#include "pci.h"
+#include "pci_host.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq irq[4];
+    int realview;
+    int mem_config;
+} PCIVPBState;
+
+static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
+{
+    return addr & 0xffffff;
+}
+
+static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
+}
+
+static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
+}
+
+static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
+                                   uint32_t val)
+{
+    pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
+}
+
+static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
+    return val;
+}
+
+static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
+    return val;
+}
+
+static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
+    return val;
+}
+
+static CPUWriteMemoryFunc * const pci_vpb_config_write[] = {
+    &pci_vpb_config_writeb,
+    &pci_vpb_config_writew,
+    &pci_vpb_config_writel,
+};
+
+static CPUReadMemoryFunc * const pci_vpb_config_read[] = {
+    &pci_vpb_config_readb,
+    &pci_vpb_config_readw,
+    &pci_vpb_config_readl,
+};
+
+static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
+{
+    return irq_num;
+}
+
+static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static void pci_vpb_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+    PCIVPBState *s = (PCIVPBState *)dev;
+    /* Selfconfig area.  */
+    cpu_register_physical_memory(base + 0x01000000, 0x1000000, s->mem_config);
+    /* Normal config area.  */
+    cpu_register_physical_memory(base + 0x02000000, 0x1000000, s->mem_config);
+
+    if (s->realview) {
+        /* IO memory area.  */
+        isa_mmio_init(base + 0x03000000, 0x00100000);
+    }
+}
+
+static int pci_vpb_init(SysBusDevice *dev)
+{
+    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
+    PCIBus *bus;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+    bus = pci_register_bus(&dev->qdev, "pci",
+                           pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
+                           PCI_DEVFN(11, 0), 4);
+
+    /* ??? Register memory space.  */
+
+    s->mem_config = cpu_register_io_memory(pci_vpb_config_read,
+                                           pci_vpb_config_write, bus,
+                                           DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio_cb(dev, 0x04000000, pci_vpb_map);
+
+    pci_create_simple(bus, -1, "versatile_pci_host");
+    return 0;
+}
+
+static int pci_realview_init(SysBusDevice *dev)
+{
+    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
+    s->realview = 1;
+    return pci_vpb_init(dev);
+}
+
+static int versatile_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_STATUS,
+		 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
+    return 0;
+}
+
+static PCIDeviceInfo versatile_pci_host_info = {
+    .qdev.name = "versatile_pci_host",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = versatile_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_XILINX,
+    /* Both boards have the same device ID.  Oh well.  */
+    .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
+    .class_id  = PCI_CLASS_PROCESSOR_CO,
+};
+
+static void versatile_pci_register_devices(void)
+{
+    sysbus_register_dev("versatile_pci", sizeof(PCIVPBState), pci_vpb_init);
+    sysbus_register_dev("realview_pci", sizeof(PCIVPBState),
+                        pci_realview_init);
+    pci_qdev_register(&versatile_pci_host_info);
+}
+
+device_init(versatile_pci_register_devices)
diff --git a/qemu-0.15.x/hw/versatilepb.c b/qemu-0.15.x/hw/versatilepb.c
new file mode 100644
index 0000000..147fe29
--- /dev/null
+++ b/qemu-0.15.x/hw/versatilepb.c
@@ -0,0 +1,362 @@
+/*
+ * ARM Versatile Platform/Application Baseboard System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "net.h"
+#include "sysemu.h"
+#include "pci.h"
+#include "usb-ohci.h"
+#include "boards.h"
+#include "blockdev.h"
+
+/* Primary interrupt controller.  */
+
+typedef struct vpb_sic_state
+{
+  SysBusDevice busdev;
+  uint32_t level;
+  uint32_t mask;
+  uint32_t pic_enable;
+  qemu_irq parent[32];
+  int irq;
+} vpb_sic_state;
+
+static const VMStateDescription vmstate_vpb_sic = {
+    .name = "versatilepb_sic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, vpb_sic_state),
+        VMSTATE_UINT32(mask, vpb_sic_state),
+        VMSTATE_UINT32(pic_enable, vpb_sic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vpb_sic_update(vpb_sic_state *s)
+{
+    uint32_t flags;
+
+    flags = s->level & s->mask;
+    qemu_set_irq(s->parent[s->irq], flags != 0);
+}
+
+static void vpb_sic_update_pic(vpb_sic_state *s)
+{
+    int i;
+    uint32_t mask;
+
+    for (i = 21; i <= 30; i++) {
+        mask = 1u << i;
+        if (!(s->pic_enable & mask))
+            continue;
+        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
+    }
+}
+
+static void vpb_sic_set_irq(void *opaque, int irq, int level)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+    if (level)
+        s->level |= 1u << irq;
+    else
+        s->level &= ~(1u << irq);
+    if (s->pic_enable & (1u << irq))
+        qemu_set_irq(s->parent[irq], level);
+    vpb_sic_update(s);
+}
+
+static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* STATUS */
+        return s->level & s->mask;
+    case 1: /* RAWSTAT */
+        return s->level;
+    case 2: /* ENABLE */
+        return s->mask;
+    case 4: /* SOFTINT */
+        return s->level & 1;
+    case 8: /* PICENABLE */
+        return s->pic_enable;
+    default:
+        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    vpb_sic_state *s = (vpb_sic_state *)opaque;
+
+    switch (offset >> 2) {
+    case 2: /* ENSET */
+        s->mask |= value;
+        break;
+    case 3: /* ENCLR */
+        s->mask &= ~value;
+        break;
+    case 4: /* SOFTINTSET */
+        if (value)
+            s->mask |= 1;
+        break;
+    case 5: /* SOFTINTCLR */
+        if (value)
+            s->mask &= ~1u;
+        break;
+    case 8: /* PICENSET */
+        s->pic_enable |= (value & 0x7fe00000);
+        vpb_sic_update_pic(s);
+        break;
+    case 9: /* PICENCLR */
+        s->pic_enable &= ~value;
+        vpb_sic_update_pic(s);
+        break;
+    default:
+        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+    vpb_sic_update(s);
+}
+
+static CPUReadMemoryFunc * const vpb_sic_readfn[] = {
+   vpb_sic_read,
+   vpb_sic_read,
+   vpb_sic_read
+};
+
+static CPUWriteMemoryFunc * const vpb_sic_writefn[] = {
+   vpb_sic_write,
+   vpb_sic_write,
+   vpb_sic_write
+};
+
+static int vpb_sic_init(SysBusDevice *dev)
+{
+    vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
+    int iomemtype;
+    int i;
+
+    qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
+    for (i = 0; i < 32; i++) {
+        sysbus_init_irq(dev, &s->parent[i]);
+    }
+    s->irq = 31;
+    iomemtype = cpu_register_io_memory(vpb_sic_readfn,
+                                       vpb_sic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    return 0;
+}
+
+/* Board init.  */
+
+/* The AB and PB boards both use the same core, just with different
+   peripherans and expansion busses.  For now we emulate a subset of the
+   PB peripherals and just change the board ID.  */
+
+static struct arm_boot_info versatile_binfo;
+
+static void versatile_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model,
+                     int board_id)
+{
+    CPUState *env;
+    ram_addr_t ram_offset;
+    qemu_irq *cpu_pic;
+    qemu_irq pic[32];
+    qemu_irq sic[32];
+    DeviceState *dev;
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    int n;
+    int done_smc = 0;
+
+    if (!cpu_model)
+        cpu_model = "arm926";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    ram_offset = qemu_ram_alloc(NULL, "versatile.ram", ram_size);
+    /* ??? RAM should repeat to fill physical memory space.  */
+    /* SDRAM at address zero.  */
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+    arm_sysctl_init(0x10000000, 0x41007004, 0x02000000);
+    cpu_pic = arm_pic_init_cpu(env);
+    dev = sysbus_create_varargs("pl190", 0x10140000,
+                                cpu_pic[0], cpu_pic[1], NULL);
+    for (n = 0; n < 32; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+    dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
+    for (n = 0; n < 32; n++) {
+        sysbus_connect_irq(sysbus_from_qdev(dev), n, pic[n]);
+        sic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
+
+    dev = sysbus_create_varargs("versatile_pci", 0x40000000,
+                                sic[27], sic[28], sic[29], sic[30], NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+
+    /* The Versatile PCI bridge does not provide access to PCI IO space,
+       so many of the qemu PCI devices are not useable.  */
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+
+        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
+            smc91c111_init(nd, 0x10010000, sic[25]);
+            done_smc = 1;
+        } else {
+            pci_nic_init_nofail(nd, "rtl8139", NULL);
+        }
+    }
+    if (usb_enabled) {
+        usb_ohci_init_pci(pci_bus, -1);
+    }
+    n = drive_get_max_bus(IF_SCSI);
+    while (n >= 0) {
+        pci_create_simple(pci_bus, -1, "lsi53c895a");
+        n--;
+    }
+
+    sysbus_create_simple("pl011", 0x101f1000, pic[12]);
+    sysbus_create_simple("pl011", 0x101f2000, pic[13]);
+    sysbus_create_simple("pl011", 0x101f3000, pic[14]);
+    sysbus_create_simple("pl011", 0x10009000, sic[6]);
+
+    sysbus_create_simple("pl080", 0x10130000, pic[17]);
+    sysbus_create_simple("sp804", 0x101e2000, pic[4]);
+    sysbus_create_simple("sp804", 0x101e3000, pic[5]);
+
+    /* The versatile/PB actually has a modified Color LCD controller
+       that includes hardware cursor support from the PL111.  */
+    sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
+
+    sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
+    sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
+
+    /* Add PL031 Real Time Clock. */
+    sysbus_create_simple("pl031", 0x101e8000, pic[10]);
+
+    /* Memory map for Versatile/PB:  */
+    /* 0x10000000 System registers.  */
+    /* 0x10001000 PCI controller config registers.  */
+    /* 0x10002000 Serial bus interface.  */
+    /*  0x10003000 Secondary interrupt controller.  */
+    /* 0x10004000 AACI (audio).  */
+    /*  0x10005000 MMCI0.  */
+    /*  0x10006000 KMI0 (keyboard).  */
+    /*  0x10007000 KMI1 (mouse).  */
+    /* 0x10008000 Character LCD Interface.  */
+    /*  0x10009000 UART3.  */
+    /* 0x1000a000 Smart card 1.  */
+    /*  0x1000b000 MMCI1.  */
+    /*  0x10010000 Ethernet.  */
+    /* 0x10020000 USB.  */
+    /* 0x10100000 SSMC.  */
+    /* 0x10110000 MPMC.  */
+    /*  0x10120000 CLCD Controller.  */
+    /*  0x10130000 DMA Controller.  */
+    /*  0x10140000 Vectored interrupt controller.  */
+    /* 0x101d0000 AHB Monitor Interface.  */
+    /* 0x101e0000 System Controller.  */
+    /* 0x101e1000 Watchdog Interface.  */
+    /* 0x101e2000 Timer 0/1.  */
+    /* 0x101e3000 Timer 2/3.  */
+    /* 0x101e4000 GPIO port 0.  */
+    /* 0x101e5000 GPIO port 1.  */
+    /* 0x101e6000 GPIO port 2.  */
+    /* 0x101e7000 GPIO port 3.  */
+    /* 0x101e8000 RTC.  */
+    /* 0x101f0000 Smart card 0.  */
+    /*  0x101f1000 UART0.  */
+    /*  0x101f2000 UART1.  */
+    /*  0x101f3000 UART2.  */
+    /* 0x101f4000 SSPI.  */
+
+    versatile_binfo.ram_size = ram_size;
+    versatile_binfo.kernel_filename = kernel_filename;
+    versatile_binfo.kernel_cmdline = kernel_cmdline;
+    versatile_binfo.initrd_filename = initrd_filename;
+    versatile_binfo.board_id = board_id;
+    arm_load_kernel(env, &versatile_binfo);
+}
+
+static void vpb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    versatile_init(ram_size,
+                   boot_device,
+                   kernel_filename, kernel_cmdline,
+                   initrd_filename, cpu_model, 0x183);
+}
+
+static void vab_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    versatile_init(ram_size,
+                   boot_device,
+                   kernel_filename, kernel_cmdline,
+                   initrd_filename, cpu_model, 0x25e);
+}
+
+static QEMUMachine versatilepb_machine = {
+    .name = "versatilepb",
+    .desc = "ARM Versatile/PB (ARM926EJ-S)",
+    .init = vpb_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine versatileab_machine = {
+    .name = "versatileab",
+    .desc = "ARM Versatile/AB (ARM926EJ-S)",
+    .init = vab_init,
+    .use_scsi = 1,
+};
+
+static void versatile_machine_init(void)
+{
+    qemu_register_machine(&versatilepb_machine);
+    qemu_register_machine(&versatileab_machine);
+}
+
+machine_init(versatile_machine_init);
+
+static SysBusDeviceInfo vpb_sic_info = {
+    .init = vpb_sic_init,
+    .qdev.name = "versatilepb_sic",
+    .qdev.size = sizeof(vpb_sic_state),
+    .qdev.vmsd = &vmstate_vpb_sic,
+    .qdev.no_user = 1,
+};
+
+static void versatilepb_register_devices(void)
+{
+    sysbus_register_withprop(&vpb_sic_info);
+}
+
+device_init(versatilepb_register_devices)
diff --git a/qemu-0.15.x/hw/vexpress.c b/qemu-0.15.x/hw/vexpress.c
new file mode 100644
index 0000000..9ffd332
--- /dev/null
+++ b/qemu-0.15.x/hw/vexpress.c
@@ -0,0 +1,224 @@
+/*
+ * ARM Versatile Express emulation.
+ *
+ * Copyright (c) 2010 - 2011 B Labs Ltd.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Bahadir Balban, Amit Mahajan, Peter Maydell
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+
+#define SMP_BOOT_ADDR 0xe0000000
+
+#define VEXPRESS_BOARD_ID 0x8e0
+
+static struct arm_boot_info vexpress_binfo = {
+    .smp_loader_start = SMP_BOOT_ADDR,
+};
+
+static void vexpress_a9_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    ram_addr_t ram_offset, vram_offset, sram_offset;
+    DeviceState *dev, *sysctl;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    int n;
+    qemu_irq cpu_irq[4];
+    uint32_t proc_id;
+    uint32_t sys_id;
+    ram_addr_t low_ram_size, vram_size, sram_size;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(env);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    if (ram_size > 0x40000000) {
+        /* 1GB is the maximum the address space permits */
+        fprintf(stderr, "vexpress: cannot model more than 1GB RAM\n");
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "vexpress.highmem", ram_size);
+    low_ram_size = ram_size;
+    if (low_ram_size > 0x4000000) {
+        low_ram_size = 0x4000000;
+    }
+    /* RAM is from 0x60000000 upwards. The bottom 64MB of the
+     * address space should in theory be remappable to various
+     * things including ROM or RAM; we always map the RAM there.
+     */
+    cpu_register_physical_memory(0x0, low_ram_size, ram_offset | IO_MEM_RAM);
+    cpu_register_physical_memory(0x60000000, ram_size,
+                                 ram_offset | IO_MEM_RAM);
+
+    /* 0x1e000000 A9MPCore (SCU) private memory region */
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    vexpress_binfo.smp_priv_base = 0x1e000000;
+    sysbus_mmio_map(busdev, 0, vexpress_binfo.smp_priv_base);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+    /* Interrupts [42:0] are from the motherboard;
+     * [47:43] are reserved; [63:48] are daughterboard
+     * peripherals. Note that some documentation numbers
+     * external interrupts starting from 32 (because the
+     * A9MP has internal interrupts 0..31).
+     */
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Motherboard peripherals CS7 : 0x10000000 .. 0x10020000 */
+    sys_id = 0x1190f500;
+    proc_id = 0x0c000191;
+
+    /* 0x10000000 System registers */
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_init_nofail(sysctl);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+
+    /* 0x10001000 SP810 system control */
+    /* 0x10002000 serial bus PCI */
+    /* 0x10004000 PL041 audio */
+
+    dev = sysbus_create_varargs("pl181", 0x10005000, pic[9], pic[10], NULL);
+    /* Wire up MMC card detect and read-only signals */
+    qdev_connect_gpio_out(dev, 0,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
+    qdev_connect_gpio_out(dev, 1,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[12]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, pic[13]);
+
+    sysbus_create_simple("pl011", 0x10009000, pic[5]);
+    sysbus_create_simple("pl011", 0x1000a000, pic[6]);
+    sysbus_create_simple("pl011", 0x1000b000, pic[7]);
+    sysbus_create_simple("pl011", 0x1000c000, pic[8]);
+
+    /* 0x1000f000 SP805 WDT */
+
+    sysbus_create_simple("sp804", 0x10011000, pic[2]);
+    sysbus_create_simple("sp804", 0x10012000, pic[3]);
+
+    /* 0x10016000 Serial Bus DVI */
+
+    sysbus_create_simple("pl031", 0x10017000, pic[4]); /* RTC */
+
+    /* 0x1001a000 Compact Flash */
+
+    /* 0x1001f000 PL111 CLCD (motherboard) */
+
+    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
+
+    /* 0x10020000 PL111 CLCD (daughterboard) */
+    sysbus_create_simple("pl110", 0x10020000, pic[44]);
+
+    /* 0x10060000 AXI RAM */
+    /* 0x100e0000 PL341 Dynamic Memory Controller */
+    /* 0x100e1000 PL354 Static Memory Controller */
+    /* 0x100e2000 System Configuration Controller */
+
+    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
+    /* 0x100e5000 SP805 Watchdog module */
+    /* 0x100e6000 BP147 TrustZone Protection Controller */
+    /* 0x100e9000 PL301 'Fast' AXI matrix */
+    /* 0x100ea000 PL301 'Slow' AXI matrix */
+    /* 0x100ec000 TrustZone Address Space Controller */
+    /* 0x10200000 CoreSight debug APB */
+    /* 0x1e00a000 PL310 L2 Cache Controller */
+
+    /* CS0: NOR0 flash          : 0x40000000 .. 0x44000000 */
+    /* CS4: NOR1 flash          : 0x44000000 .. 0x48000000 */
+    /* CS2: SRAM                : 0x48000000 .. 0x4a000000 */
+    sram_size = 0x2000000;
+    sram_offset = qemu_ram_alloc(NULL, "vexpress.sram", sram_size);
+    cpu_register_physical_memory(0x48000000, sram_size,
+                                 sram_offset | IO_MEM_RAM);
+
+    /* CS3: USB, ethernet, VRAM : 0x4c000000 .. 0x50000000 */
+
+    /* 0x4c000000 Video RAM */
+    vram_size = 0x800000;
+    vram_offset = qemu_ram_alloc(NULL, "vexpress.vram", vram_size);
+    cpu_register_physical_memory(0x4c000000, vram_size,
+                                 vram_offset | IO_MEM_RAM);
+
+    /* 0x4e000000 LAN9118 Ethernet */
+    if (nd_table[0].vlan) {
+        lan9118_init(&nd_table[0], 0x4e000000, pic[15]);
+    }
+
+    /* 0x4f000000 ISP1761 USB */
+
+    /* ??? Hack to map an additional page of ram for the secondary CPU
+       startup code.  I guess this works on real hardware because the
+       BootROM happens to be in ROM/flash or in memory that isn't clobbered
+       until after Linux boots the secondary CPUs.  */
+    ram_offset = qemu_ram_alloc(NULL, "vexpress.hack", 0x1000);
+    cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
+                                 ram_offset | IO_MEM_RAM);
+
+    vexpress_binfo.ram_size = ram_size;
+    vexpress_binfo.kernel_filename = kernel_filename;
+    vexpress_binfo.kernel_cmdline = kernel_cmdline;
+    vexpress_binfo.initrd_filename = initrd_filename;
+    vexpress_binfo.nb_cpus = smp_cpus;
+    vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
+    vexpress_binfo.loader_start = 0x60000000;
+    arm_load_kernel(first_cpu, &vexpress_binfo);
+}
+
+
+static QEMUMachine vexpress_a9_machine = {
+    .name = "vexpress-a9",
+    .desc = "ARM Versatile Express for Cortex-A9",
+    .init = vexpress_a9_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static void vexpress_machine_init(void)
+{
+    qemu_register_machine(&vexpress_a9_machine);
+}
+
+machine_init(vexpress_machine_init);
diff --git a/qemu-0.15.x/hw/vga-isa-mm.c b/qemu-0.15.x/hw/vga-isa-mm.c
new file mode 100644
index 0000000..4954bb1
--- /dev/null
+++ b/qemu-0.15.x/hw/vga-isa-mm.c
@@ -0,0 +1,128 @@
+/*
+ * QEMU ISA MM VGA Emulator.
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "pc.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+#include "qemu-timer.h"
+
+typedef struct ISAVGAMMState {
+    VGACommonState vga;
+    int it_shift;
+} ISAVGAMMState;
+
+/* Memory mapped interface */
+static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xff;
+}
+
+static void vga_mm_writeb (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xff);
+}
+
+static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xffff;
+}
+
+static void vga_mm_writew (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xffff);
+}
+
+static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift);
+}
+
+static void vga_mm_writel (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
+    &vga_mm_readb,
+    &vga_mm_readw,
+    &vga_mm_readl,
+};
+
+static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
+    &vga_mm_writeb,
+    &vga_mm_writew,
+    &vga_mm_writel,
+};
+
+static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base,
+                        target_phys_addr_t ctrl_base, int it_shift)
+{
+    int s_ioport_ctrl, vga_io_memory;
+
+    s->it_shift = it_shift;
+    s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s,
+                                           DEVICE_NATIVE_ENDIAN);
+    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
+
+    vmstate_register(NULL, 0, &vmstate_vga_common, s);
+
+    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
+    s->vga.bank_offset = 0;
+    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
+    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
+}
+
+int isa_vga_mm_init(target_phys_addr_t vram_base,
+                    target_phys_addr_t ctrl_base, int it_shift)
+{
+    ISAVGAMMState *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    vga_common_init(&s->vga, VGA_RAM_SIZE);
+    vga_mm_init(s, vram_base, ctrl_base, it_shift);
+
+    s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
+                                     s->vga.screen_dump, s->vga.text_update, s);
+
+    vga_init_vbe(&s->vga);
+    return 0;
+}
diff --git a/qemu-0.15.x/hw/vga-isa.c b/qemu-0.15.x/hw/vga-isa.c
new file mode 100644
index 0000000..245841f
--- /dev/null
+++ b/qemu-0.15.x/hw/vga-isa.c
@@ -0,0 +1,87 @@
+/*
+ * QEMU ISA VGA Emulator.
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "pc.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+#include "qemu-timer.h"
+#include "loader.h"
+
+typedef struct ISAVGAState {
+    ISADevice dev;
+    struct VGACommonState state;
+} ISAVGAState;
+
+static void vga_reset_isa(DeviceState *dev)
+{
+    ISAVGAState *d = container_of(dev, ISAVGAState, dev.qdev);
+    VGACommonState *s = &d->state;
+
+    vga_common_reset(s);
+}
+
+static int vga_initfn(ISADevice *dev)
+{
+    ISAVGAState *d = DO_UPCAST(ISAVGAState, dev, dev);
+    VGACommonState *s = &d->state;
+    int vga_io_memory;
+
+    vga_common_init(s, VGA_RAM_SIZE);
+    vga_io_memory = vga_init_io(s);
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
+                                 vga_io_memory);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    isa_init_ioport(dev, 0x3c0);
+    isa_init_ioport(dev, 0x3b4);
+    isa_init_ioport(dev, 0x3ba);
+    isa_init_ioport(dev, 0x3da);
+    isa_init_ioport(dev, 0x3c0);
+#ifdef CONFIG_BOCHS_VBE
+    isa_init_ioport(dev, 0x1ce);
+    isa_init_ioport(dev, 0x1cf);
+    isa_init_ioport(dev, 0x1d0);
+#endif /* CONFIG_BOCHS_VBE */
+    s->ds = graphic_console_init(s->update, s->invalidate,
+                                 s->screen_dump, s->text_update, s);
+
+    vga_init_vbe(s);
+    /* ROM BIOS */
+    rom_add_vga(VGABIOS_FILENAME);
+    return 0;
+}
+
+static ISADeviceInfo vga_info = {
+    .qdev.name     = "isa-vga",
+    .qdev.size     = sizeof(ISAVGAState),
+    .qdev.vmsd     = &vmstate_vga_common,
+    .qdev.reset     = vga_reset_isa,
+    .init          = vga_initfn,
+};
+
+static void vga_register(void)
+{
+    isa_qdev_register(&vga_info);
+}
+device_init(vga_register)
diff --git a/qemu-0.15.x/hw/vga-pci.c b/qemu-0.15.x/hw/vga-pci.c
new file mode 100644
index 0000000..481f448
--- /dev/null
+++ b/qemu-0.15.x/hw/vga-pci.c
@@ -0,0 +1,122 @@
+/*
+ * QEMU PCI VGA Emulator.
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "pc.h"
+#include "pci.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+#include "qemu-timer.h"
+#include "loader.h"
+
+typedef struct PCIVGAState {
+    PCIDevice dev;
+    VGACommonState vga;
+} PCIVGAState;
+
+static const VMStateDescription vmstate_vga_pci = {
+    .name = "vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIVGAState),
+        VMSTATE_STRUCT(vga, PCIVGAState, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vga_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    PCIVGAState *d = (PCIVGAState *)pci_dev;
+    VGACommonState *s = &d->vga;
+
+    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
+    s->map_addr = addr;
+    s->map_end = addr + s->vram_size;
+    vga_dirty_log_start(s);
+}
+
+static void pci_vga_write_config(PCIDevice *d,
+                                 uint32_t address, uint32_t val, int len)
+{
+    PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
+    VGACommonState *s = &pvs->vga;
+
+    pci_default_write_config(d, address, val, len);
+    if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
+        s->map_addr = 0;
+}
+
+static int pci_vga_initfn(PCIDevice *dev)
+{
+     PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
+     VGACommonState *s = &d->vga;
+
+     // vga + console init
+     vga_common_init(s, VGA_RAM_SIZE);
+     vga_init(s);
+
+     s->ds = graphic_console_init(s->update, s->invalidate,
+                                  s->screen_dump, s->text_update, s);
+
+     /* XXX: VGA_RAM_SIZE must be a power of two */
+     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
+                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+
+     if (!dev->rom_bar) {
+         /* compatibility with pc-0.13 and older */
+         vga_init_vbe(s);
+     }
+
+     return 0;
+}
+
+int pci_vga_init(PCIBus *bus)
+{
+    pci_create_simple(bus, -1, "VGA");
+    return 0;
+}
+
+static PCIDeviceInfo vga_info = {
+    .qdev.name    = "VGA",
+    .qdev.size    = sizeof(PCIVGAState),
+    .qdev.vmsd    = &vmstate_vga_pci,
+    .no_hotplug   = 1,
+    .init         = pci_vga_initfn,
+    .config_write = pci_vga_write_config,
+    .romfile      = "vgabios-stdvga.bin",
+
+    /* dummy VGA (same as Bochs ID) */
+    .vendor_id    = PCI_VENDOR_ID_QEMU,
+    .device_id    = PCI_DEVICE_ID_QEMU_VGA,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+};
+
+static void vga_register(void)
+{
+    pci_qdev_register(&vga_info);
+}
+device_init(vga_register);
diff --git a/qemu-0.15.x/hw/vga.c b/qemu-0.15.x/hw/vga.c
new file mode 100644
index 0000000..0f54734
--- /dev/null
+++ b/qemu-0.15.x/hw/vga.c
@@ -0,0 +1,2412 @@
+/*
+ * QEMU VGA Emulator.
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "pc.h"
+#include "pci.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_VGA
+//#define DEBUG_VGA_MEM
+//#define DEBUG_VGA_REG
+
+//#define DEBUG_BOCHS_VBE
+
+/* force some bits to zero */
+const uint8_t sr_mask[8] = {
+    0x03,
+    0x3d,
+    0x0f,
+    0x3f,
+    0x0e,
+    0x00,
+    0x00,
+    0xff,
+};
+
+const uint8_t gr_mask[16] = {
+    0x0f, /* 0x00 */
+    0x0f, /* 0x01 */
+    0x0f, /* 0x02 */
+    0x1f, /* 0x03 */
+    0x03, /* 0x04 */
+    0x7b, /* 0x05 */
+    0x0f, /* 0x06 */
+    0x0f, /* 0x07 */
+    0xff, /* 0x08 */
+    0x00, /* 0x09 */
+    0x00, /* 0x0a */
+    0x00, /* 0x0b */
+    0x00, /* 0x0c */
+    0x00, /* 0x0d */
+    0x00, /* 0x0e */
+    0x00, /* 0x0f */
+};
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) (x)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define BIG 1
+#else
+#define BIG 0
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
+#else
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+#endif
+
+static const uint32_t mask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+static uint32_t expand4[256];
+static uint16_t expand2[256];
+static uint8_t expand4to8[16];
+
+static void vga_screen_dump(void *opaque, const char *filename);
+static char *screen_dump_filename;
+static DisplayChangeListener *screen_dump_dcl;
+
+static void vga_dumb_update_retrace_info(VGACommonState *s)
+{
+    (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+    int htotal_chars;
+    int hretr_start_char;
+    int hretr_skew_chars;
+    int hretr_end_char;
+
+    int vtotal_lines;
+    int vretr_start_line;
+    int vretr_end_line;
+
+    int dots;
+#if 0
+    int div2, sldiv2;
+#endif
+    int clocking_mode;
+    int clock_sel;
+    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+    int64_t chars_per_sec;
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+    htotal_chars = s->cr[0x00] + 5;
+    hretr_start_char = s->cr[0x04];
+    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
+    hretr_end_char = s->cr[0x05] & 0x1f;
+
+    vtotal_lines = (s->cr[0x06]
+                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
+        ;
+    vretr_start_line = s->cr[0x10]
+        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
+        ;
+    vretr_end_line = s->cr[0x11] & 0xf;
+
+
+
+    clocking_mode = (s->sr[0x01] >> 3) & 1;
+    clock_sel = (s->msr >> 2) & 3;
+    dots = (s->msr & 1) ? 8 : 9;
+
+    chars_per_sec = clk_hz[clock_sel] / dots;
+
+    htotal_chars <<= clocking_mode;
+
+    r->total_chars = vtotal_lines * htotal_chars;
+    if (r->freq) {
+        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+    } else {
+        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+    }
+
+    r->vstart = vretr_start_line;
+    r->vend = r->vstart + vretr_end_line + 1;
+
+    r->hstart = hretr_start_char + hretr_skew_chars;
+    r->hend = r->hstart + hretr_end_char + 1;
+    r->htotal = htotal_chars;
+
+#if 0
+    div2 = (s->cr[0x17] >> 2) & 1;
+    sldiv2 = (s->cr[0x17] >> 3) & 1;
+    printf (
+        "hz=%f\n"
+        "htotal = %d\n"
+        "hretr_start = %d\n"
+        "hretr_skew = %d\n"
+        "hretr_end = %d\n"
+        "vtotal = %d\n"
+        "vretr_start = %d\n"
+        "vretr_end = %d\n"
+        "div2 = %d sldiv2 = %d\n"
+        "clocking_mode = %d\n"
+        "clock_sel = %d %d\n"
+        "dots = %d\n"
+        "ticks/char = %" PRId64 "\n"
+        "\n",
+        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+        htotal_chars,
+        hretr_start_char,
+        hretr_skew_chars,
+        hretr_end_char,
+        vtotal_lines,
+        vretr_start_line,
+        vretr_end_line,
+        div2, sldiv2,
+        clocking_mode,
+        clock_sel,
+        clk_hz[clock_sel],
+        dots,
+        r->ticks_per_char
+        );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGACommonState *s)
+{
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+    if (r->total_chars) {
+        int cur_line, cur_line_char, cur_char;
+        int64_t cur_tick;
+
+        cur_tick = qemu_get_clock_ns(vm_clock);
+
+        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+        cur_line = cur_char / r->htotal;
+
+        if (cur_line >= r->vstart && cur_line <= r->vend) {
+            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+        } else {
+            cur_line_char = cur_char % r->htotal;
+            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+                val |= ST01_DISP_ENABLE;
+            }
+        }
+
+        return val;
+    } else {
+        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+    }
+}
+
+static uint8_t vga_dumb_retrace(VGACommonState *s)
+{
+    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
+int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
+{
+    if (s->msr & MSR_COLOR_EMULATION) {
+        /* Color */
+        return (addr >= 0x3b0 && addr <= 0x3bf);
+    } else {
+        /* Monochrome */
+        return (addr >= 0x3d0 && addr <= 0x3df);
+    }
+}
+
+uint32_t vga_ioport_read(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    int val, index;
+
+    if (vga_ioport_invalid(s, addr)) {
+        val = 0xff;
+    } else {
+        switch(addr) {
+        case 0x3c0:
+            if (s->ar_flip_flop == 0) {
+                val = s->ar_index;
+            } else {
+                val = 0;
+            }
+            break;
+        case 0x3c1:
+            index = s->ar_index & 0x1f;
+            if (index < 21)
+                val = s->ar[index];
+            else
+                val = 0;
+            break;
+        case 0x3c2:
+            val = s->st00;
+            break;
+        case 0x3c4:
+            val = s->sr_index;
+            break;
+        case 0x3c5:
+            val = s->sr[s->sr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+            break;
+        case 0x3c7:
+            val = s->dac_state;
+            break;
+        case 0x3c8:
+            val = s->dac_write_index;
+            break;
+        case 0x3c9:
+            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
+            if (++s->dac_sub_index == 3) {
+                s->dac_sub_index = 0;
+                s->dac_read_index++;
+            }
+            break;
+        case 0x3ca:
+            val = s->fcr;
+            break;
+        case 0x3cc:
+            val = s->msr;
+            break;
+        case 0x3ce:
+            val = s->gr_index;
+            break;
+        case 0x3cf:
+            val = s->gr[s->gr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+            break;
+        case 0x3b4:
+        case 0x3d4:
+            val = s->cr_index;
+            break;
+        case 0x3b5:
+        case 0x3d5:
+            val = s->cr[s->cr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+            break;
+        case 0x3ba:
+        case 0x3da:
+            /* just toggle to fool polling */
+            val = s->st01 = s->retrace(s);
+            s->ar_flip_flop = 0;
+            break;
+        default:
+            val = 0x00;
+            break;
+        }
+    }
+#if defined(DEBUG_VGA)
+    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    int index;
+
+    /* check port range access depending on color/monochrome mode */
+    if (vga_ioport_invalid(s, addr)) {
+        return;
+    }
+#ifdef DEBUG_VGA
+    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+
+    switch(addr) {
+    case 0x3c0:
+        if (s->ar_flip_flop == 0) {
+            val &= 0x3f;
+            s->ar_index = val;
+        } else {
+            index = s->ar_index & 0x1f;
+            switch(index) {
+            case 0x00 ... 0x0f:
+                s->ar[index] = val & 0x3f;
+                break;
+            case 0x10:
+                s->ar[index] = val & ~0x10;
+                break;
+            case 0x11:
+                s->ar[index] = val;
+                break;
+            case 0x12:
+                s->ar[index] = val & ~0xc0;
+                break;
+            case 0x13:
+                s->ar[index] = val & ~0xf0;
+                break;
+            case 0x14:
+                s->ar[index] = val & ~0xf0;
+                break;
+            default:
+                break;
+            }
+        }
+        s->ar_flip_flop ^= 1;
+        break;
+    case 0x3c2:
+        s->msr = val & ~0x10;
+        s->update_retrace_info(s);
+        break;
+    case 0x3c4:
+        s->sr_index = val & 7;
+        break;
+    case 0x3c5:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+        if (s->sr_index == 1) s->update_retrace_info(s);
+        break;
+    case 0x3c7:
+        s->dac_read_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 3;
+        break;
+    case 0x3c8:
+        s->dac_write_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 0;
+        break;
+    case 0x3c9:
+        s->dac_cache[s->dac_sub_index] = val;
+        if (++s->dac_sub_index == 3) {
+            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
+            s->dac_sub_index = 0;
+            s->dac_write_index++;
+        }
+        break;
+    case 0x3ce:
+        s->gr_index = val & 0x0f;
+        break;
+    case 0x3cf:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+        break;
+    case 0x3b4:
+    case 0x3d4:
+        s->cr_index = val;
+        break;
+    case 0x3b5:
+    case 0x3d5:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+        /* handle CR0-7 protection */
+        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
+            /* can always write bit 4 of CR7 */
+            if (s->cr_index == 7)
+                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+            return;
+        }
+        s->cr[s->cr_index] = val;
+
+        switch(s->cr_index) {
+        case 0x00:
+        case 0x04:
+        case 0x05:
+        case 0x06:
+        case 0x07:
+        case 0x11:
+        case 0x17:
+            s->update_retrace_info(s);
+            break;
+        }
+        break;
+    case 0x3ba:
+    case 0x3da:
+        s->fcr = val & 0x10;
+        break;
+    }
+}
+
+#ifdef CONFIG_BOCHS_VBE
+static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+    val = s->vbe_index;
+    return val;
+}
+
+static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+
+    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
+        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
+            switch(s->vbe_index) {
+                /* XXX: do not hardcode ? */
+            case VBE_DISPI_INDEX_XRES:
+                val = VBE_DISPI_MAX_XRES;
+                break;
+            case VBE_DISPI_INDEX_YRES:
+                val = VBE_DISPI_MAX_YRES;
+                break;
+            case VBE_DISPI_INDEX_BPP:
+                val = VBE_DISPI_MAX_BPP;
+                break;
+            default:
+                val = s->vbe_regs[s->vbe_index];
+                break;
+            }
+        } else {
+            val = s->vbe_regs[s->vbe_index];
+        }
+    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
+        val = s->vram_size / (64 * 1024);
+    } else {
+        val = 0;
+    }
+#ifdef DEBUG_BOCHS_VBE
+    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+    return val;
+}
+
+static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    s->vbe_index = val;
+}
+
+static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+
+    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
+#ifdef DEBUG_BOCHS_VBE
+        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+        switch(s->vbe_index) {
+        case VBE_DISPI_INDEX_ID:
+            if (val == VBE_DISPI_ID0 ||
+                val == VBE_DISPI_ID1 ||
+                val == VBE_DISPI_ID2 ||
+                val == VBE_DISPI_ID3 ||
+                val == VBE_DISPI_ID4) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_XRES:
+            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_YRES:
+            if (val <= VBE_DISPI_MAX_YRES) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BPP:
+            if (val == 0)
+                val = 8;
+            if (val == 4 || val == 8 || val == 15 ||
+                val == 16 || val == 24 || val == 32) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BANK:
+            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+              val &= (s->vbe_bank_mask >> 2);
+            } else {
+              val &= s->vbe_bank_mask;
+            }
+            s->vbe_regs[s->vbe_index] = val;
+            s->bank_offset = (val << 16);
+            break;
+        case VBE_DISPI_INDEX_ENABLE:
+            if ((val & VBE_DISPI_ENABLED) &&
+                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+                int h, shift_control;
+
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
+                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
+                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
+                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
+                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
+
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
+                else
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
+                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr = 0;
+
+                /* clear the screen (should be done in BIOS) */
+                if (!(val & VBE_DISPI_NOCLEARMEM)) {
+                    memset(s->vram_ptr, 0,
+                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
+                }
+
+                /* we initialize the VGA graphic mode (should be done
+                   in BIOS) */
+                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
+                s->cr[0x17] |= 3; /* no CGA modes */
+                s->cr[0x13] = s->vbe_line_offset >> 3;
+                /* width */
+                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+                /* height (only meaningful if < 1024) */
+                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+                s->cr[0x12] = h;
+                s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+                /* line compare to 1023 */
+                s->cr[0x18] = 0xff;
+                s->cr[0x07] |= 0x10;
+                s->cr[0x09] |= 0x40;
+
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+                    shift_control = 0;
+                    s->sr[0x01] &= ~8; /* no double line */
+                } else {
+                    shift_control = 2;
+                    s->sr[4] |= 0x08; /* set chain 4 mode */
+                    s->sr[2] |= 0x0f; /* activate all planes */
+                }
+                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
+                s->cr[0x09] &= ~0x9f; /* no double scan */
+            } else {
+                /* XXX: the bios should do that */
+                s->bank_offset = 0;
+            }
+            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
+            s->vbe_regs[s->vbe_index] = val;
+            break;
+        case VBE_DISPI_INDEX_VIRT_WIDTH:
+            {
+                int w, h, line_offset;
+
+                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
+                    return;
+                w = val;
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    line_offset = w >> 1;
+                else
+                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                h = s->vram_size / line_offset;
+                /* XXX: support weird bochs semantics ? */
+                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
+                    return;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
+                s->vbe_line_offset = line_offset;
+            }
+            break;
+        case VBE_DISPI_INDEX_X_OFFSET:
+        case VBE_DISPI_INDEX_Y_OFFSET:
+            {
+                int x;
+                s->vbe_regs[s->vbe_index] = val;
+                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
+                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_start_addr += x >> 1;
+                else
+                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr >>= 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+#endif
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    VGACommonState *s = opaque;
+    int memory_map_mode, plane;
+    uint32_t ret;
+
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return 0xff;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    }
+
+    if (s->sr[4] & 0x08) {
+        /* chain 4 mode : simplest access */
+        ret = s->vram_ptr[addr];
+    } else if (s->gr[5] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (s->gr[4] & 2) | (addr & 1);
+        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+    } else {
+        /* standard VGA latched access */
+        s->latch = ((uint32_t *)s->vram_ptr)[addr];
+
+        if (!(s->gr[5] & 0x08)) {
+            /* read mode 0 */
+            plane = s->gr[4];
+            ret = GET_PLANE(s->latch, plane);
+        } else {
+            /* read mode 1 */
+            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
+            ret |= ret >> 16;
+            ret |= ret >> 8;
+            ret = (~ret) & 0xff;
+        }
+    }
+    return ret;
+}
+
+static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = vga_mem_readb(opaque, addr);
+    v |= vga_mem_readb(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = vga_mem_readb(opaque, addr);
+    v |= vga_mem_readb(opaque, addr + 1) << 8;
+    v |= vga_mem_readb(opaque, addr + 2) << 16;
+    v |= vga_mem_readb(opaque, addr + 3) << 24;
+    return v;
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    int memory_map_mode, plane, write_mode, b, func_select, mask;
+    uint32_t write_mask, bit_mask, set_mask;
+
+#ifdef DEBUG_VGA_MEM
+    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
+#endif
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    }
+
+    if (s->sr[4] & 0x08) {
+        /* chain 4 mode : simplest access */
+        plane = addr & 3;
+        mask = (1 << plane);
+        if (s->sr[2] & mask) {
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+        }
+    } else if (s->gr[5] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (s->gr[4] & 2) | (addr & 1);
+        mask = (1 << plane);
+        if (s->sr[2] & mask) {
+            addr = ((addr & ~1) << 1) | plane;
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+        }
+    } else {
+        /* standard VGA latched access */
+        write_mode = s->gr[5] & 3;
+        switch(write_mode) {
+        default:
+        case 0:
+            /* rotate */
+            b = s->gr[3] & 7;
+            val = ((val >> b) | (val << (8 - b))) & 0xff;
+            val |= val << 8;
+            val |= val << 16;
+
+            /* apply set/reset mask */
+            set_mask = mask16[s->gr[1]];
+            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
+            bit_mask = s->gr[8];
+            break;
+        case 1:
+            val = s->latch;
+            goto do_write;
+        case 2:
+            val = mask16[val & 0x0f];
+            bit_mask = s->gr[8];
+            break;
+        case 3:
+            /* rotate */
+            b = s->gr[3] & 7;
+            val = (val >> b) | (val << (8 - b));
+
+            bit_mask = s->gr[8] & val;
+            val = mask16[s->gr[0]];
+            break;
+        }
+
+        /* apply logical operation */
+        func_select = s->gr[3] >> 3;
+        switch(func_select) {
+        case 0:
+        default:
+            /* nothing to do */
+            break;
+        case 1:
+            /* and */
+            val &= s->latch;
+            break;
+        case 2:
+            /* or */
+            val |= s->latch;
+            break;
+        case 3:
+            /* xor */
+            val ^= s->latch;
+            break;
+        }
+
+        /* apply bit mask */
+        bit_mask |= bit_mask << 8;
+        bit_mask |= bit_mask << 16;
+        val = (val & bit_mask) | (s->latch & ~bit_mask);
+
+    do_write:
+        /* mask data according to sr[2] */
+        mask = s->sr[2];
+        s->plane_updated |= mask; /* only used to detect font change */
+        write_mask = mask16[mask];
+        ((uint32_t *)s->vram_ptr)[addr] =
+            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
+            (val & write_mask);
+#ifdef DEBUG_VGA_MEM
+        printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
+               addr * 4, write_mask, val);
+#endif
+        cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
+    }
+}
+
+static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    vga_mem_writeb(opaque, addr, val & 0xff);
+    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+}
+
+static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    vga_mem_writeb(opaque, addr, val & 0xff);
+    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+}
+
+typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
+                                  const uint8_t *font_ptr, int h,
+                                  uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+                                const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "vga_template.h"
+
+#define DEPTH 15
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "vga_template.h"
+
+#define DEPTH 16
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "vga_template.h"
+
+#define DEPTH 32
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel8(r, g, b);
+    col |= col << 8;
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32(r, g, b);
+    return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32bgr(r, g, b);
+    return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    for(i = 0; i < 16; i++) {
+        v = s->ar[i];
+        if (s->ar[0x10] & 0x80)
+            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
+        else
+            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
+        v = v * 3;
+        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                              c6_to_8(s->palette[v + 1]),
+                              c6_to_8(s->palette[v + 2]));
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+    }
+    return full_update;
+}
+
+/* return true if the palette was modified */
+static int update_palette256(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    v = 0;
+    for(i = 0; i < 256; i++) {
+        if (s->dac_8bit) {
+          col = s->rgb_to_pixel(s->palette[v],
+                                s->palette[v + 1],
+                                s->palette[v + 2]);
+        } else {
+          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                                c6_to_8(s->palette[v + 1]),
+                                c6_to_8(s->palette[v + 2]));
+        }
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+        v += 3;
+    }
+    return full_update;
+}
+
+static void vga_get_offsets(VGACommonState *s,
+                            uint32_t *pline_offset,
+                            uint32_t *pstart_addr,
+                            uint32_t *pline_compare)
+{
+    uint32_t start_addr, line_offset, line_compare;
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        line_offset = s->vbe_line_offset;
+        start_addr = s->vbe_start_addr;
+        line_compare = 65535;
+    } else
+#endif
+    {
+        /* compute line_offset in bytes */
+        line_offset = s->cr[0x13];
+        line_offset <<= 3;
+
+        /* starting address */
+        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
+
+        /* line compare */
+        line_compare = s->cr[0x18] |
+            ((s->cr[0x07] & 0x10) << 4) |
+            ((s->cr[0x09] & 0x40) << 3);
+    }
+    *pline_offset = line_offset;
+    *pstart_addr = start_addr;
+    *pline_compare = line_compare;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGACommonState *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
+
+    full_update = 0;
+
+    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+    if (line_offset != s->line_offset ||
+        start_addr != s->start_addr ||
+        line_compare != s->line_compare) {
+        s->line_offset = line_offset;
+        s->start_addr = start_addr;
+        s->line_compare = line_compare;
+        full_update = 1;
+    }
+    return full_update;
+}
+
+#define NB_DEPTHS 7
+
+static inline int get_depth_index(DisplayState *s)
+{
+    switch(ds_get_bits_per_pixel(s)) {
+    default:
+    case 8:
+        return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(s->surface))
+            return 4;
+        else
+            return 3;
+    }
+}
+
+static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
+    vga_draw_glyph8_8,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+};
+
+static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
+    vga_draw_glyph16_8,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+};
+
+static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
+    vga_draw_glyph9_8,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+                                    int *pcwidth, int *pcheight)
+{
+    int width, cwidth, height, cheight;
+
+    /* total width & height */
+    cheight = (s->cr[9] & 0x1f) + 1;
+    cwidth = 8;
+    if (!(s->sr[1] & 0x01))
+        cwidth = 9;
+    if (s->sr[1] & 0x08)
+        cwidth = 16; /* NOTE: no 18 pixel wide */
+    width = (s->cr[0x01] + 1);
+    if (s->cr[0x06] == 100) {
+        /* ugly hack for CGA 160x100x16 - explain me the logic */
+        height = 100;
+    } else {
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
+            ((s->cr[0x07] & 0x40) << 3);
+        height = (height + 1) / cheight;
+    }
+
+    *pwidth = width;
+    *pheight = height;
+    *pcwidth = cwidth;
+    *pcheight = cheight;
+}
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
+    rgb_to_pixel8_dup,
+    rgb_to_pixel15_dup,
+    rgb_to_pixel16_dup,
+    rgb_to_pixel32_dup,
+    rgb_to_pixel32bgr_dup,
+    rgb_to_pixel15bgr_dup,
+    rgb_to_pixel16bgr_dup,
+};
+
+/*
+ * Text mode update
+ * Missing:
+ * - double scan
+ * - double width
+ * - underline
+ * - flashing
+ */
+static void vga_draw_text(VGACommonState *s, int full_update)
+{
+    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+    int cx_min, cx_max, linesize, x_incr, line, line1;
+    uint32_t offset, fgcol, bgcol, v, cursor_offset;
+    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
+    const uint8_t *font_ptr, *font_base[2];
+    int dup9, line_offset, depth_index;
+    uint32_t *palette;
+    uint32_t *ch_attr_ptr;
+    vga_draw_glyph8_func *vga_draw_glyph8;
+    vga_draw_glyph9_func *vga_draw_glyph9;
+
+    /* compute font data address (in plane 2) */
+    v = s->sr[3];
+    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+    if (offset != s->font_offsets[0]) {
+        s->font_offsets[0] = offset;
+        full_update = 1;
+    }
+    font_base[0] = s->vram_ptr + offset;
+
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    font_base[1] = s->vram_ptr + offset;
+    if (offset != s->font_offsets[1]) {
+        s->font_offsets[1] = offset;
+        full_update = 1;
+    }
+    if (s->plane_updated & (1 << 2)) {
+        /* if the plane 2 was modified since the last display, it
+           indicates the font may have been modified */
+        s->plane_updated = 0;
+        full_update = 1;
+    }
+    full_update |= update_basic_params(s);
+
+    line_offset = s->line_offset;
+
+    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
+    if (width != s->last_width || height != s->last_height ||
+        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+        s->last_scr_width = width * cw;
+        s->last_scr_height = height * cheight;
+        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
+        s->last_depth = 0;
+        s->last_width = width;
+        s->last_height = height;
+        s->last_ch = cheight;
+        s->last_cw = cw;
+        full_update = 1;
+    }
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+    full_update |= update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+
+    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+    if (cursor_offset != s->cursor_offset ||
+        s->cr[0xa] != s->cursor_start ||
+        s->cr[0xb] != s->cursor_end) {
+      /* if the cursor position changed, we update the old and new
+         chars */
+        if (s->cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[s->cursor_offset] = -1;
+        if (cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[cursor_offset] = -1;
+        s->cursor_offset = cursor_offset;
+        s->cursor_start = s->cr[0xa];
+        s->cursor_end = s->cr[0xb];
+    }
+    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
+
+    depth_index = get_depth_index(s->ds);
+    if (cw == 16)
+        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
+    else
+        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
+    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
+
+    dest = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
+    ch_attr_ptr = s->last_ch_attr;
+    line = 0;
+    offset = s->start_addr * 4;
+    for(cy = 0; cy < height; cy++) {
+        d1 = dest;
+        src = s->vram_ptr + offset;
+        cx_min = width;
+        cx_max = -1;
+        for(cx = 0; cx < width; cx++) {
+            ch_attr = *(uint16_t *)src;
+            if (full_update || ch_attr != *ch_attr_ptr) {
+                if (cx < cx_min)
+                    cx_min = cx;
+                if (cx > cx_max)
+                    cx_max = cx;
+                *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+                ch = ch_attr >> 8;
+                cattr = ch_attr & 0xff;
+#else
+                ch = ch_attr & 0xff;
+                cattr = ch_attr >> 8;
+#endif
+                font_ptr = font_base[(cattr >> 3) & 1];
+                font_ptr += 32 * 4 * ch;
+                bgcol = palette[cattr >> 4];
+                fgcol = palette[cattr & 0x0f];
+                if (cw != 9) {
+                    vga_draw_glyph8(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol);
+                } else {
+                    dup9 = 0;
+                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+                        dup9 = 1;
+                    vga_draw_glyph9(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol, dup9);
+                }
+                if (src == cursor_ptr &&
+                    !(s->cr[0x0a] & 0x20)) {
+                    int line_start, line_last, h;
+                    /* draw the cursor */
+                    line_start = s->cr[0x0a] & 0x1f;
+                    line_last = s->cr[0x0b] & 0x1f;
+                    /* XXX: check that */
+                    if (line_last > cheight - 1)
+                        line_last = cheight - 1;
+                    if (line_last >= line_start && line_start < cheight) {
+                        h = line_last - line_start + 1;
+                        d = d1 + linesize * line_start;
+                        if (cw != 9) {
+                            vga_draw_glyph8(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol);
+                        } else {
+                            vga_draw_glyph9(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol, 1);
+                        }
+                    }
+                }
+            }
+            d1 += x_incr;
+            src += 4;
+            ch_attr_ptr++;
+        }
+        if (cx_max != -1) {
+            dpy_update(s->ds, cx_min * cw, cy * cheight,
+                       (cx_max - cx_min + 1) * cw, cheight);
+        }
+        dest += linesize * cheight;
+        line1 = line + cheight;
+        offset += line_offset;
+        if (line < s->line_compare && line1 >= s->line_compare) {
+            offset = 0;
+        }
+        line = line1;
+    }
+}
+
+enum {
+    VGA_DRAW_LINE2,
+    VGA_DRAW_LINE2D2,
+    VGA_DRAW_LINE4,
+    VGA_DRAW_LINE4D2,
+    VGA_DRAW_LINE8D2,
+    VGA_DRAW_LINE8,
+    VGA_DRAW_LINE15,
+    VGA_DRAW_LINE16,
+    VGA_DRAW_LINE24,
+    VGA_DRAW_LINE32,
+    VGA_DRAW_LINE_NB,
+};
+
+static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
+    vga_draw_line2_8,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+    vga_draw_line2_32,
+    vga_draw_line2_32,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+
+    vga_draw_line2d2_8,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+
+    vga_draw_line4_8,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+    vga_draw_line4_32,
+    vga_draw_line4_32,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+
+    vga_draw_line4d2_8,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+
+    vga_draw_line8d2_8,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+
+    vga_draw_line8_8,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+    vga_draw_line8_32,
+    vga_draw_line8_32,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+
+    vga_draw_line15_8,
+    vga_draw_line15_15,
+    vga_draw_line15_16,
+    vga_draw_line15_32,
+    vga_draw_line15_32bgr,
+    vga_draw_line15_15bgr,
+    vga_draw_line15_16bgr,
+
+    vga_draw_line16_8,
+    vga_draw_line16_15,
+    vga_draw_line16_16,
+    vga_draw_line16_32,
+    vga_draw_line16_32bgr,
+    vga_draw_line16_15bgr,
+    vga_draw_line16_16bgr,
+
+    vga_draw_line24_8,
+    vga_draw_line24_15,
+    vga_draw_line24_16,
+    vga_draw_line24_32,
+    vga_draw_line24_32bgr,
+    vga_draw_line24_15bgr,
+    vga_draw_line24_16bgr,
+
+    vga_draw_line32_8,
+    vga_draw_line32_15,
+    vga_draw_line32_16,
+    vga_draw_line32_32,
+    vga_draw_line32_32bgr,
+    vga_draw_line32_15bgr,
+    vga_draw_line32_16bgr,
+};
+
+static int vga_get_bpp(VGACommonState *s)
+{
+    int ret;
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+    } else
+#endif
+    {
+        ret = 0;
+    }
+    return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+    } else
+#endif
+    {
+        width = (s->cr[0x01] + 1) * 8;
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
+            ((s->cr[0x07] & 0x40) << 3);
+        height = (height + 1);
+    }
+    *pwidth = width;
+    *pheight = height;
+}
+
+void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
+{
+    int y;
+    if (y1 >= VGA_MAX_HEIGHT)
+        return;
+    if (y2 >= VGA_MAX_HEIGHT)
+        y2 = VGA_MAX_HEIGHT;
+    for(y = y1; y < y2; y++) {
+        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
+    }
+}
+
+static void vga_sync_dirty_bitmap(VGACommonState *s)
+{
+    if (s->map_addr)
+        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
+
+    if (s->lfb_vram_mapped) {
+        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
+        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
+    }
+
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_mapped) {
+        cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                       VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
+    }
+#endif
+
+}
+
+void vga_dirty_log_start(VGACommonState *s)
+{
+    if (s->map_addr) {
+        cpu_physical_log_start(s->map_addr, s->map_end - s->map_addr);
+    }
+
+    if (s->lfb_vram_mapped) {
+        cpu_physical_log_start(isa_mem_base + 0xa0000, 0x8000);
+        cpu_physical_log_start(isa_mem_base + 0xa8000, 0x8000);
+    }
+
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_mapped) {
+        cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
+    }
+#endif
+}
+
+void vga_dirty_log_stop(VGACommonState *s)
+{
+    if (s->map_addr) {
+        cpu_physical_log_stop(s->map_addr, s->map_end - s->map_addr);
+    }
+
+    if (s->lfb_vram_mapped) {
+        cpu_physical_log_stop(isa_mem_base + 0xa0000, 0x8000);
+        cpu_physical_log_stop(isa_mem_base + 0xa8000, 0x8000);
+    }
+
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_mapped) {
+        cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
+    }
+#endif
+}
+
+void vga_dirty_log_restart(VGACommonState *s)
+{
+    vga_dirty_log_stop(s);
+    vga_dirty_log_start(s);
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+    int y1, y, update, linesize, y_start, double_scan, mask, depth;
+    int width, height, shift_control, line_offset, bwidth, bits;
+    ram_addr_t page0, page1, page_min, page_max;
+    int disp_width, multi_scan, multi_run;
+    uint8_t *d;
+    uint32_t v, addr1, addr;
+    vga_draw_line_func *vga_draw_line;
+
+    full_update |= update_basic_params(s);
+
+    if (!full_update)
+        vga_sync_dirty_bitmap(s);
+
+    s->get_resolution(s, &width, &height);
+    disp_width = width;
+
+    shift_control = (s->gr[0x05] >> 5) & 3;
+    double_scan = (s->cr[0x09] >> 7);
+    if (shift_control != 1) {
+        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+    } else {
+        /* in CGA modes, multi_scan is ignored */
+        /* XXX: is it correct ? */
+        multi_scan = double_scan;
+    }
+    multi_run = multi_scan;
+    if (shift_control != s->shift_control ||
+        double_scan != s->double_scan) {
+        full_update = 1;
+        s->shift_control = shift_control;
+        s->double_scan = double_scan;
+    }
+
+    if (shift_control == 0) {
+        if (s->sr[0x01] & 8) {
+            disp_width <<= 1;
+        }
+    } else if (shift_control == 1) {
+        if (s->sr[0x01] & 8) {
+            disp_width <<= 1;
+        }
+    }
+
+    depth = s->get_bpp(s);
+    if (s->line_offset != s->last_line_offset ||
+        disp_width != s->last_width ||
+        height != s->last_height ||
+        s->last_depth != depth) {
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+        if (depth == 16 || depth == 32) {
+#else
+        if (depth == 32) {
+#endif
+            qemu_free_displaysurface(s->ds);
+            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
+                    s->line_offset,
+                    s->vram_ptr + (s->start_addr * 4));
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
+#endif
+            dpy_resize(s->ds);
+        } else {
+            qemu_console_resize(s->ds, disp_width, height);
+        }
+        s->last_scr_width = disp_width;
+        s->last_scr_height = height;
+        s->last_width = disp_width;
+        s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
+        full_update = 1;
+    } else if (is_buffer_shared(s->ds->surface) &&
+               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
+        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
+        dpy_setdata(s->ds);
+    }
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+
+    if (shift_control == 0) {
+        full_update |= update_palette16(s);
+        if (s->sr[0x01] & 8) {
+            v = VGA_DRAW_LINE4D2;
+        } else {
+            v = VGA_DRAW_LINE4;
+        }
+        bits = 4;
+    } else if (shift_control == 1) {
+        full_update |= update_palette16(s);
+        if (s->sr[0x01] & 8) {
+            v = VGA_DRAW_LINE2D2;
+        } else {
+            v = VGA_DRAW_LINE2;
+        }
+        bits = 4;
+    } else {
+        switch(s->get_bpp(s)) {
+        default:
+        case 0:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8D2;
+            bits = 4;
+            break;
+        case 8:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8;
+            bits = 8;
+            break;
+        case 15:
+            v = VGA_DRAW_LINE15;
+            bits = 16;
+            break;
+        case 16:
+            v = VGA_DRAW_LINE16;
+            bits = 16;
+            break;
+        case 24:
+            v = VGA_DRAW_LINE24;
+            bits = 24;
+            break;
+        case 32:
+            v = VGA_DRAW_LINE32;
+            bits = 32;
+            break;
+        }
+    }
+    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
+
+    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
+        s->cursor_invalidate(s);
+
+    line_offset = s->line_offset;
+#if 0
+    printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
+           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
+#endif
+    addr1 = (s->start_addr * 4);
+    bwidth = (width * bits + 7) / 8;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
+    y1 = 0;
+    for(y = 0; y < height; y++) {
+        addr = addr1;
+        if (!(s->cr[0x17] & 1)) {
+            int shift;
+            /* CGA compatibility handling */
+            shift = 14 + ((s->cr[0x17] >> 6) & 1);
+            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+        }
+        if (!(s->cr[0x17] & 2)) {
+            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
+        }
+        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
+        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
+        update = full_update |
+            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
+            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+        if ((page1 - page0) > TARGET_PAGE_SIZE) {
+            /* if wide line, can use another page */
+            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
+                                                    VGA_DIRTY_FLAG);
+        }
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+        if (update) {
+            if (y_start < 0)
+                y_start = y;
+            if (page0 < page_min)
+                page_min = page0;
+            if (page1 > page_max)
+                page_max = page1;
+            if (!(is_buffer_shared(s->ds->surface))) {
+                vga_draw_line(s, d, s->vram_ptr + addr, width);
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
+            }
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(s->ds, 0, y_start,
+                           disp_width, y - y_start);
+                y_start = -1;
+            }
+        }
+        if (!multi_run) {
+            mask = (s->cr[0x17] & 3) ^ 3;
+            if ((y1 & mask) == mask)
+                addr1 += line_offset;
+            y1++;
+            multi_run = multi_scan;
+        } else {
+            multi_run--;
+        }
+        /* line compare acts on the displayed lines */
+        if (y == s->line_compare)
+            addr1 = 0;
+        d += linesize;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(s->ds, 0, y_start,
+                   disp_width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+                                        VGA_DIRTY_FLAG);
+    }
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGACommonState *s, int full_update)
+{
+    int i, w, val;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+    if (ds_get_bits_per_pixel(s->ds) == 8)
+        val = s->rgb_to_pixel(0, 0, 0);
+    else
+        val = 0;
+    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+    d = ds_get_data(s->ds);
+    for(i = 0; i < s->last_scr_height; i++) {
+        memset(d, val, w);
+        d += ds_get_linesize(s->ds);
+    }
+    dpy_update(s->ds, 0, 0,
+               s->last_scr_width, s->last_scr_height);
+}
+
+#define GMODE_TEXT     0
+#define GMODE_GRAPH    1
+#define GMODE_BLANK 2
+
+static void vga_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    int full_update, graphic_mode;
+
+    if (ds_get_bits_per_pixel(s->ds) == 0) {
+        /* nothing to do */
+    } else {
+        full_update = 0;
+        if (!(s->ar_index & 0x20)) {
+            graphic_mode = GMODE_BLANK;
+        } else {
+            graphic_mode = s->gr[6] & 1;
+        }
+        if (graphic_mode != s->graphic_mode) {
+            s->graphic_mode = graphic_mode;
+            full_update = 1;
+        }
+        switch(graphic_mode) {
+        case GMODE_TEXT:
+            vga_draw_text(s, full_update);
+            break;
+        case GMODE_GRAPH:
+            vga_draw_graphic(s, full_update);
+            break;
+        case GMODE_BLANK:
+        default:
+            vga_draw_blank(s, full_update);
+            break;
+        }
+    }
+}
+
+/* force a full display refresh */
+static void vga_invalidate_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+
+    s->last_width = -1;
+    s->last_height = -1;
+}
+
+void vga_common_reset(VGACommonState *s)
+{
+    s->lfb_addr = 0;
+    s->lfb_end = 0;
+    s->map_addr = 0;
+    s->map_end = 0;
+    s->lfb_vram_mapped = 0;
+    s->sr_index = 0;
+    memset(s->sr, '\0', sizeof(s->sr));
+    s->gr_index = 0;
+    memset(s->gr, '\0', sizeof(s->gr));
+    s->ar_index = 0;
+    memset(s->ar, '\0', sizeof(s->ar));
+    s->ar_flip_flop = 0;
+    s->cr_index = 0;
+    memset(s->cr, '\0', sizeof(s->cr));
+    s->msr = 0;
+    s->fcr = 0;
+    s->st00 = 0;
+    s->st01 = 0;
+    s->dac_state = 0;
+    s->dac_sub_index = 0;
+    s->dac_read_index = 0;
+    s->dac_write_index = 0;
+    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
+    s->dac_8bit = 0;
+    memset(s->palette, '\0', sizeof(s->palette));
+    s->bank_offset = 0;
+#ifdef CONFIG_BOCHS_VBE
+    s->vbe_index = 0;
+    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
+    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
+    s->vbe_start_addr = 0;
+    s->vbe_line_offset = 0;
+    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
+#endif
+    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
+    s->graphic_mode = -1; /* force full update */
+    s->shift_control = 0;
+    s->double_scan = 0;
+    s->line_offset = 0;
+    s->line_compare = 0;
+    s->start_addr = 0;
+    s->plane_updated = 0;
+    s->last_cw = 0;
+    s->last_ch = 0;
+    s->last_width = 0;
+    s->last_height = 0;
+    s->last_scr_width = 0;
+    s->last_scr_height = 0;
+    s->cursor_start = 0;
+    s->cursor_end = 0;
+    s->cursor_offset = 0;
+    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
+    memset(s->last_palette, '\0', sizeof(s->last_palette));
+    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        break;
+    case VGA_RETRACE_PRECISE:
+        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
+        break;
+    }
+}
+
+static void vga_reset(void *opaque)
+{
+    VGACommonState *s =  opaque;
+    vga_common_reset(s);
+}
+
+#define TEXTMODE_X(x)	((x) % width)
+#define TEXTMODE_Y(x)	((x) / width)
+#define VMEM2CHTYPE(v)	((v & 0xff0007ff) | \
+        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+    VGACommonState *s =  opaque;
+    int graphic_mode, i, cursor_offset, cursor_visible;
+    int cw, cheight, width, height, size, c_min, c_max;
+    uint32_t *src;
+    console_ch_t *dst, val;
+    char msg_buffer[80];
+    int full_update = 0;
+
+    if (!(s->ar_index & 0x20)) {
+        graphic_mode = GMODE_BLANK;
+    } else {
+        graphic_mode = s->gr[6] & 1;
+    }
+    if (graphic_mode != s->graphic_mode) {
+        s->graphic_mode = graphic_mode;
+        full_update = 1;
+    }
+    if (s->last_width == -1) {
+        s->last_width = 0;
+        full_update = 1;
+    }
+
+    switch (graphic_mode) {
+    case GMODE_TEXT:
+        /* TODO: update palette */
+        full_update |= update_basic_params(s);
+
+        /* total width & height */
+        cheight = (s->cr[9] & 0x1f) + 1;
+        cw = 8;
+        if (!(s->sr[1] & 0x01))
+            cw = 9;
+        if (s->sr[1] & 0x08)
+            cw = 16; /* NOTE: no 18 pixel wide */
+        width = (s->cr[0x01] + 1);
+        if (s->cr[0x06] == 100) {
+            /* ugly hack for CGA 160x100x16 - explain me the logic */
+            height = 100;
+        } else {
+            height = s->cr[0x12] | 
+                ((s->cr[0x07] & 0x02) << 7) | 
+                ((s->cr[0x07] & 0x40) << 3);
+            height = (height + 1) / cheight;
+        }
+
+        size = (height * width);
+        if (size > CH_ATTR_SIZE) {
+            if (!full_update)
+                return;
+
+            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
+                     width, height);
+            break;
+        }
+
+        if (width != s->last_width || height != s->last_height ||
+            cw != s->last_cw || cheight != s->last_ch) {
+            s->last_scr_width = width * cw;
+            s->last_scr_height = height * cheight;
+            s->ds->surface->width = width;
+            s->ds->surface->height = height;
+            dpy_resize(s->ds);
+            s->last_width = width;
+            s->last_height = height;
+            s->last_ch = cheight;
+            s->last_cw = cw;
+            full_update = 1;
+        }
+
+        /* Update "hardware" cursor */
+        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+        if (cursor_offset != s->cursor_offset ||
+            s->cr[0xa] != s->cursor_start ||
+            s->cr[0xb] != s->cursor_end || full_update) {
+            cursor_visible = !(s->cr[0xa] & 0x20);
+            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
+                dpy_cursor(s->ds,
+                           TEXTMODE_X(cursor_offset),
+                           TEXTMODE_Y(cursor_offset));
+            else
+                dpy_cursor(s->ds, -1, -1);
+            s->cursor_offset = cursor_offset;
+            s->cursor_start = s->cr[0xa];
+            s->cursor_end = s->cr[0xb];
+        }
+
+        src = (uint32_t *) s->vram_ptr + s->start_addr;
+        dst = chardata;
+
+        if (full_update) {
+            for (i = 0; i < size; src ++, dst ++, i ++)
+                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+
+            dpy_update(s->ds, 0, 0, width, height);
+        } else {
+            c_max = 0;
+
+            for (i = 0; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                    break;
+                }
+            }
+            c_min = i;
+            for (; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                }
+            }
+
+            if (c_min <= c_max) {
+                i = TEXTMODE_Y(c_min);
+                dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+            }
+        }
+
+        return;
+    case GMODE_GRAPH:
+        if (!full_update)
+            return;
+
+        s->get_resolution(s, &width, &height);
+        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
+                 width, height);
+        break;
+    case GMODE_BLANK:
+    default:
+        if (!full_update)
+            return;
+
+        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
+        break;
+    }
+
+    /* Display a message */
+    s->last_width = 60;
+    s->last_height = height = 3;
+    dpy_cursor(s->ds, -1, -1);
+    s->ds->surface->width = s->last_width;
+    s->ds->surface->height = height;
+    dpy_resize(s->ds);
+
+    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
+        console_write_ch(dst ++, ' ');
+
+    size = strlen(msg_buffer);
+    width = (s->last_width - size) / 2;
+    dst = chardata + s->last_width + width;
+    for (i = 0; i < size; i ++)
+        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+
+    dpy_update(s->ds, 0, 0, s->last_width, height);
+}
+
+CPUReadMemoryFunc * const vga_mem_read[3] = {
+    vga_mem_readb,
+    vga_mem_readw,
+    vga_mem_readl,
+};
+
+CPUWriteMemoryFunc * const vga_mem_write[3] = {
+    vga_mem_writeb,
+    vga_mem_writew,
+    vga_mem_writel,
+};
+
+static int vga_common_post_load(void *opaque, int version_id)
+{
+    VGACommonState *s = opaque;
+
+    /* force refresh */
+    s->graphic_mode = -1;
+    return 0;
+}
+
+const VMStateDescription vmstate_vga_common = {
+    .name = "vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = vga_common_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(latch, VGACommonState),
+        VMSTATE_UINT8(sr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
+        VMSTATE_UINT8(gr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
+        VMSTATE_UINT8(ar_index, VGACommonState),
+        VMSTATE_BUFFER(ar, VGACommonState),
+        VMSTATE_INT32(ar_flip_flop, VGACommonState),
+        VMSTATE_UINT8(cr_index, VGACommonState),
+        VMSTATE_BUFFER(cr, VGACommonState),
+        VMSTATE_UINT8(msr, VGACommonState),
+        VMSTATE_UINT8(fcr, VGACommonState),
+        VMSTATE_UINT8(st00, VGACommonState),
+        VMSTATE_UINT8(st01, VGACommonState),
+
+        VMSTATE_UINT8(dac_state, VGACommonState),
+        VMSTATE_UINT8(dac_sub_index, VGACommonState),
+        VMSTATE_UINT8(dac_read_index, VGACommonState),
+        VMSTATE_UINT8(dac_write_index, VGACommonState),
+        VMSTATE_BUFFER(dac_cache, VGACommonState),
+        VMSTATE_BUFFER(palette, VGACommonState),
+
+        VMSTATE_INT32(bank_offset, VGACommonState),
+        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
+#ifdef CONFIG_BOCHS_VBE
+        VMSTATE_UINT16(vbe_index, VGACommonState),
+        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
+        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
+        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
+        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
+#endif
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void vga_common_init(VGACommonState *s, int vga_ram_size)
+{
+    int i, j, v, b;
+
+    for(i = 0;i < 256; i++) {
+        v = 0;
+        for(j = 0; j < 8; j++) {
+            v |= ((i >> j) & 1) << (j * 4);
+        }
+        expand4[i] = v;
+
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            v |= ((i >> (2 * j)) & 3) << (j * 4);
+        }
+        expand2[i] = v;
+    }
+    for(i = 0; i < 16; i++) {
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            b = ((i >> j) & 1);
+            v |= b << (2 * j);
+            v |= b << (2 * j + 1);
+        }
+        expand4to8[i] = v;
+    }
+
+#ifdef CONFIG_BOCHS_VBE
+    s->is_vbe_vmstate = 1;
+#else
+    s->is_vbe_vmstate = 0;
+#endif
+    s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
+    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
+    s->vram_size = vga_ram_size;
+    s->get_bpp = vga_get_bpp;
+    s->get_offsets = vga_get_offsets;
+    s->get_resolution = vga_get_resolution;
+    s->update = vga_update_display;
+    s->invalidate = vga_invalidate_display;
+    s->screen_dump = vga_screen_dump;
+    s->text_update = vga_update_text;
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        s->retrace = vga_dumb_retrace;
+        s->update_retrace_info = vga_dumb_update_retrace_info;
+        break;
+
+    case VGA_RETRACE_PRECISE:
+        s->retrace = vga_precise_retrace;
+        s->update_retrace_info = vga_precise_update_retrace_info;
+        break;
+    }
+}
+
+/* used by both ISA and PCI */
+int vga_init_io(VGACommonState *s)
+{
+    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
+
+    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
+    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
+    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
+    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
+
+    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
+
+    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
+    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
+    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
+    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
+
+#ifdef CONFIG_BOCHS_VBE
+#if defined (TARGET_I386)
+    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
+    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
+
+    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
+    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
+#else
+    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
+    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
+
+    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
+    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
+#endif
+#endif /* CONFIG_BOCHS_VBE */
+
+    return cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
+                                  DEVICE_LITTLE_ENDIAN);
+}
+
+void vga_init(VGACommonState *s)
+{
+    int vga_io_memory;
+
+    qemu_register_reset(vga_reset, s);
+
+    s->bank_offset = 0;
+
+    vga_io_memory = vga_init_io(s);
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
+                                 vga_io_memory);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+}
+
+void vga_init_vbe(VGACommonState *s)
+{
+#ifdef CONFIG_BOCHS_VBE
+    /* XXX: use optimized standard vga accesses */
+    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                 VGA_RAM_SIZE, s->vram_offset);
+    s->vbe_mapped = 1;
+#endif 
+}
+/********************************************************/
+/* vga screen dump */
+
+static void vga_save_dpy_update(DisplayState *ds,
+                                int x, int y, int w, int h)
+{
+    if (screen_dump_filename) {
+        ppm_save(screen_dump_filename, ds->surface);
+        screen_dump_filename = NULL;
+    }
+}
+
+static void vga_save_dpy_resize(DisplayState *s)
+{
+}
+
+static void vga_save_dpy_refresh(DisplayState *s)
+{
+}
+
+int ppm_save(const char *filename, struct DisplaySurface *ds)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    uint32_t v;
+    int y, x;
+    uint8_t r, g, b;
+    int ret;
+    char *linebuf, *pbuf;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return -1;
+    fprintf(f, "P6\n%d %d\n%d\n",
+            ds->width, ds->height, 255);
+    linebuf = qemu_malloc(ds->width * 3);
+    d1 = ds->data;
+    for(y = 0; y < ds->height; y++) {
+        d = d1;
+        pbuf = linebuf;
+        for(x = 0; x < ds->width; x++) {
+            if (ds->pf.bits_per_pixel == 32)
+                v = *(uint32_t *)d;
+            else
+                v = (uint32_t) (*(uint16_t *)d);
+            r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
+                (ds->pf.rmax + 1);
+            g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
+                (ds->pf.gmax + 1);
+            b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
+                (ds->pf.bmax + 1);
+            *pbuf++ = r;
+            *pbuf++ = g;
+            *pbuf++ = b;
+            d += ds->pf.bytes_per_pixel;
+        }
+        d1 += ds->linesize;
+        ret = fwrite(linebuf, 1, pbuf - linebuf, f);
+        (void)ret;
+    }
+    qemu_free(linebuf);
+    fclose(f);
+    return 0;
+}
+
+static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
+{
+    DisplayChangeListener *dcl;
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = vga_save_dpy_update;
+    dcl->dpy_resize = vga_save_dpy_resize;
+    dcl->dpy_refresh = vga_save_dpy_refresh;
+    register_displaychangelistener(ds, dcl);
+    return dcl;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vga_screen_dump(void *opaque, const char *filename)
+{
+    VGACommonState *s = opaque;
+
+    if (!screen_dump_dcl)
+        screen_dump_dcl = vga_screen_dump_init(s->ds);
+
+    screen_dump_filename = (char *)filename;
+    vga_invalidate_display(s);
+    vga_hw_update();
+}
+
diff --git a/qemu-0.15.x/hw/vga_int.h b/qemu-0.15.x/hw/vga_int.h
new file mode 100644
index 0000000..eee91a8
--- /dev/null
+++ b/qemu-0.15.x/hw/vga_int.h
@@ -0,0 +1,233 @@
+/*
+ * QEMU internal VGA defines.
+ *
+ * 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 <hw/hw.h>
+
+#define MSR_COLOR_EMULATION 0x01
+#define MSR_PAGE_SELECT     0x20
+
+#define ST01_V_RETRACE      0x08
+#define ST01_DISP_ENABLE    0x01
+
+/* bochs VBE support */
+#define CONFIG_BOCHS_VBE
+
+#define VBE_DISPI_MAX_XRES              1600
+#define VBE_DISPI_MAX_YRES              1200
+#define VBE_DISPI_MAX_BPP               32
+
+#define VBE_DISPI_INDEX_ID              0x0
+#define VBE_DISPI_INDEX_XRES            0x1
+#define VBE_DISPI_INDEX_YRES            0x2
+#define VBE_DISPI_INDEX_BPP             0x3
+#define VBE_DISPI_INDEX_ENABLE          0x4
+#define VBE_DISPI_INDEX_BANK            0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+#define VBE_DISPI_INDEX_X_OFFSET        0x8
+#define VBE_DISPI_INDEX_Y_OFFSET        0x9
+#define VBE_DISPI_INDEX_NB              0xa /* size of vbe_regs[] */
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
+
+#define VBE_DISPI_ID0                   0xB0C0
+#define VBE_DISPI_ID1                   0xB0C1
+#define VBE_DISPI_ID2                   0xB0C2
+#define VBE_DISPI_ID3                   0xB0C3
+#define VBE_DISPI_ID4                   0xB0C4
+#define VBE_DISPI_ID5                   0xB0C5
+
+#define VBE_DISPI_DISABLED              0x00
+#define VBE_DISPI_ENABLED               0x01
+#define VBE_DISPI_GETCAPS               0x02
+#define VBE_DISPI_8BIT_DAC              0x20
+#define VBE_DISPI_LFB_ENABLED           0x40
+#define VBE_DISPI_NOCLEARMEM            0x80
+
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+#ifdef CONFIG_BOCHS_VBE
+
+#define VGA_STATE_COMMON_BOCHS_VBE              \
+    uint16_t vbe_index;                         \
+    uint16_t vbe_regs[VBE_DISPI_INDEX_NB];      \
+    uint32_t vbe_start_addr;                    \
+    uint32_t vbe_line_offset;                   \
+    uint32_t vbe_bank_mask;			\
+    int vbe_mapped;
+#else
+
+#define VGA_STATE_COMMON_BOCHS_VBE
+
+#endif /* !CONFIG_BOCHS_VBE */
+
+#define CH_ATTR_SIZE (160 * 100)
+#define VGA_MAX_HEIGHT 2048
+
+struct vga_precise_retrace {
+    int64_t ticks_per_char;
+    int64_t total_chars;
+    int htotal;
+    int hstart;
+    int hend;
+    int vstart;
+    int vend;
+    int freq;
+};
+
+union vga_retrace {
+    struct vga_precise_retrace precise;
+};
+
+struct VGACommonState;
+typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
+typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
+
+typedef struct VGACommonState {
+    uint8_t *vram_ptr;
+    ram_addr_t vram_offset;
+    target_phys_addr_t lfb_addr;
+    target_phys_addr_t lfb_end;
+    target_phys_addr_t map_addr;
+    target_phys_addr_t map_end;
+    uint32_t vram_size;
+    uint32_t latch;
+    uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
+    uint8_t sr_index;
+    uint8_t sr[256];
+    uint8_t gr_index;
+    uint8_t gr[256];
+    uint8_t ar_index;
+    uint8_t ar[21];
+    int ar_flip_flop;
+    uint8_t cr_index;
+    uint8_t cr[256]; /* CRT registers */
+    uint8_t msr; /* Misc Output Register */
+    uint8_t fcr; /* Feature Control Register */
+    uint8_t st00; /* status 0 */
+    uint8_t st01; /* status 1 */
+    uint8_t dac_state;
+    uint8_t dac_sub_index;
+    uint8_t dac_read_index;
+    uint8_t dac_write_index;
+    uint8_t dac_cache[3]; /* used when writing */
+    int dac_8bit;
+    uint8_t palette[768];
+    int32_t bank_offset;
+    int vga_io_memory;
+    int (*get_bpp)(struct VGACommonState *s);
+    void (*get_offsets)(struct VGACommonState *s,
+                        uint32_t *pline_offset,
+                        uint32_t *pstart_addr,
+                        uint32_t *pline_compare);
+    void (*get_resolution)(struct VGACommonState *s,
+                        int *pwidth,
+                        int *pheight);
+    VGA_STATE_COMMON_BOCHS_VBE
+    /* display refresh support */
+    DisplayState *ds;
+    uint32_t font_offsets[2];
+    int graphic_mode;
+    uint8_t shift_control;
+    uint8_t double_scan;
+    uint32_t line_offset;
+    uint32_t line_compare;
+    uint32_t start_addr;
+    uint32_t plane_updated;
+    uint32_t last_line_offset;
+    uint8_t last_cw, last_ch;
+    uint32_t last_width, last_height; /* in chars or pixels */
+    uint32_t last_scr_width, last_scr_height; /* in pixels */
+    uint32_t last_depth; /* in bits */
+    uint8_t cursor_start, cursor_end;
+    uint32_t cursor_offset;
+    unsigned int (*rgb_to_pixel)(unsigned int r,
+                                 unsigned int g, unsigned b);
+    vga_hw_update_ptr update;
+    vga_hw_invalidate_ptr invalidate;
+    vga_hw_screen_dump_ptr screen_dump;
+    vga_hw_text_update_ptr text_update;
+    /* hardware mouse cursor support */
+    uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
+    void (*cursor_invalidate)(struct VGACommonState *s);
+    void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
+    /* tell for each page if it has been updated since the last time */
+    uint32_t last_palette[256];
+    uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
+    /* retrace */
+    vga_retrace_fn retrace;
+    vga_update_retrace_info_fn update_retrace_info;
+    union vga_retrace retrace_info;
+    uint8_t is_vbe_vmstate;
+} VGACommonState;
+
+static inline int c6_to_8(int v)
+{
+    int b;
+    v &= 0x3f;
+    b = v & 1;
+    return (v << 2) | (b << 1) | b;
+}
+
+void vga_common_init(VGACommonState *s, int vga_ram_size);
+void vga_init(VGACommonState *s);
+int vga_init_io(VGACommonState *s);
+void vga_common_reset(VGACommonState *s);
+
+void vga_dirty_log_start(VGACommonState *s);
+void vga_dirty_log_stop(VGACommonState *s);
+void vga_dirty_log_restart(VGACommonState *s);
+
+extern const VMStateDescription vmstate_vga_common;
+uint32_t vga_ioport_read(void *opaque, uint32_t addr);
+void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
+void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
+void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
+int ppm_save(const char *filename, struct DisplaySurface *ds);
+
+void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
+                            int poffset, int w,
+                            unsigned int color0, unsigned int color1,
+                            unsigned int color_xor);
+void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
+                             unsigned int color0, unsigned int color1,
+                             unsigned int color_xor);
+void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
+                             unsigned int color0, unsigned int color1,
+                             unsigned int color_xor);
+
+int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
+void vga_init_vbe(VGACommonState *s);
+
+extern const uint8_t sr_mask[8];
+extern const uint8_t gr_mask[16];
+
+#define VGA_RAM_SIZE (8192 * 1024)
+#define VGABIOS_FILENAME "vgabios.bin"
+#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+
+extern CPUReadMemoryFunc * const vga_mem_read[3];
+extern CPUWriteMemoryFunc * const vga_mem_write[3];
diff --git a/qemu-0.15.x/hw/vga_template.h b/qemu-0.15.x/hw/vga_template.h
new file mode 100644
index 0000000..681425f
--- /dev/null
+++ b/qemu-0.15.x/hw/vga_template.h
@@ -0,0 +1,525 @@
+/*
+ * QEMU VGA Emulator templates
+ *
+ * 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.
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+                                                     uint32_t font_data,
+                                                     uint32_t xorcol,
+                                                     uint32_t bgcol)
+{
+#if BPP == 1
+        ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+        ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(vga_draw_glyph_line_, DEPTH)(d,
+                                          expand4to8[font_data >> 4],
+                                          xorcol, bgcol);
+        glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+                                          expand4to8[font_data & 0x0f],
+                                          xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+    uint32_t font_data, xorcol, v;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+#if BPP == 1
+        cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+        v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+1, v);
+        if (dup9)
+            ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+        else
+            ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
+        cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+        v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+3, v);
+        if (dup9)
+            ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+        else
+            ((uint16_t *)d)[8] = bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = v;
+        if (dup9)
+            ((uint32_t *)d)[8] = v;
+        else
+            ((uint32_t *)d)[8] = bgcol;
+#endif
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        PUT_PIXEL2(d, 0, palette[v >> 12]);
+        PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        PUT_PIXEL2(d, 4, palette[v >> 12]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+        ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[0x12] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        PUT_PIXEL2(d, 0, palette[v >> 28]);
+        PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+        PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        PUT_PIXEL2(d, 0, palette[s[0]]);
+        PUT_PIXEL2(d, 1, palette[s[1]]);
+        PUT_PIXEL2(d, 2, palette[s[2]]);
+        PUT_PIXEL2(d, 3, palette[s[3]]);
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+        ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+        ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+        ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+        ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+        ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+        ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+        ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+        d += BPP * 8;
+        s += 8;
+    }
+}
+
+void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+                                        const uint8_t *src1,
+                                        int poffset, int w,
+                                        unsigned int color0,
+                                        unsigned int color1,
+                                        unsigned int color_xor)
+{
+    const uint8_t *plane0, *plane1;
+    int x, b0, b1;
+    uint8_t *d;
+
+    d = d1;
+    plane0 = src1;
+    plane1 = src1 + poffset;
+    for(x = 0; x < w; x++) {
+        b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+        b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            d[0] ^= color_xor;
+            break;
+        case 2:
+            d[0] = color0;
+            break;
+        case 3:
+            d[0] = color1;
+            break;
+        }
+#elif DEPTH == 16
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint16_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint16_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint16_t *)d)[0] = color1;
+            break;
+        }
+#elif DEPTH == 32
+        switch(b0 | (b1 << 1)) {
+        case 0:
+            break;
+        case 1:
+            ((uint32_t *)d)[0] ^= color_xor;
+            break;
+        case 2:
+            ((uint32_t *)d)[0] = color0;
+            break;
+        case 3:
+            ((uint32_t *)d)[0] = color1;
+            break;
+        }
+#else
+#error unsupported depth
+#endif
+        d += BPP;
+    }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 7) & 0xf8;
+        g = (v >> 2) & 0xf8;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[0];
+        g = s[1];
+        b = s[2];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 3;
+        d += BPP;
+    } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
+    memcpy(d, s, width * 4);
+#else
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 4;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/qemu-0.15.x/hw/vhost.c b/qemu-0.15.x/hw/vhost.c
new file mode 100644
index 0000000..c3d8821
--- /dev/null
+++ b/qemu-0.15.x/hw/vhost.c
@@ -0,0 +1,789 @@
+/*
+ * vhost support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <sys/ioctl.h>
+#include "vhost.h"
+#include "hw/hw.h"
+#include "range.h"
+#include <linux/vhost.h>
+
+static void vhost_dev_sync_region(struct vhost_dev *dev,
+                                  uint64_t mfirst, uint64_t mlast,
+                                  uint64_t rfirst, uint64_t rlast)
+{
+    uint64_t start = MAX(mfirst, rfirst);
+    uint64_t end = MIN(mlast, rlast);
+    vhost_log_chunk_t *from = dev->log + start / VHOST_LOG_CHUNK;
+    vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
+    uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
+
+    assert(end / VHOST_LOG_CHUNK < dev->log_size);
+    assert(start / VHOST_LOG_CHUNK < dev->log_size);
+    if (end < start) {
+        return;
+    }
+    for (;from < to; ++from) {
+        vhost_log_chunk_t log;
+        int bit;
+        /* We first check with non-atomic: much cheaper,
+         * and we expect non-dirty to be the common case. */
+        if (!*from) {
+            addr += VHOST_LOG_CHUNK;
+            continue;
+        }
+        /* Data must be read atomically. We don't really
+         * need the barrier semantics of __sync
+         * builtins, but it's easier to use them than
+         * roll our own. */
+        log = __sync_fetch_and_and(from, 0);
+        while ((bit = sizeof(log) > sizeof(int) ?
+                ffsll(log) : ffs(log))) {
+            ram_addr_t ram_addr;
+            bit -= 1;
+            ram_addr = cpu_get_physical_page_desc(addr + bit * VHOST_LOG_PAGE);
+            cpu_physical_memory_set_dirty(ram_addr);
+            log &= ~(0x1ull << bit);
+        }
+        addr += VHOST_LOG_CHUNK;
+    }
+}
+
+static int vhost_client_sync_dirty_bitmap(CPUPhysMemoryClient *client,
+                                          target_phys_addr_t start_addr,
+                                          target_phys_addr_t end_addr)
+{
+    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
+    int i;
+    if (!dev->log_enabled || !dev->started) {
+        return 0;
+    }
+    for (i = 0; i < dev->mem->nregions; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        vhost_dev_sync_region(dev, start_addr, end_addr,
+                              reg->guest_phys_addr,
+                              range_get_last(reg->guest_phys_addr,
+                                             reg->memory_size));
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        vhost_dev_sync_region(dev, start_addr, end_addr, vq->used_phys,
+                              range_get_last(vq->used_phys, vq->used_size));
+    }
+    return 0;
+}
+
+/* Assign/unassign. Keep an unsorted array of non-overlapping
+ * memory regions in dev->mem. */
+static void vhost_dev_unassign_memory(struct vhost_dev *dev,
+                                      uint64_t start_addr,
+                                      uint64_t size)
+{
+    int from, to, n = dev->mem->nregions;
+    /* Track overlapping/split regions for sanity checking. */
+    int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
+
+    for (from = 0, to = 0; from < n; ++from, ++to) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        uint64_t reglast;
+        uint64_t memlast;
+        uint64_t change;
+
+        /* clone old region */
+        if (to != from) {
+            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+        }
+
+        /* No overlap is simple */
+        if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+                            start_addr, size)) {
+            continue;
+        }
+
+        /* Split only happens if supplied region
+         * is in the middle of an existing one. Thus it can not
+         * overlap with any other existing region. */
+        assert(!split);
+
+        reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+        memlast = range_get_last(start_addr, size);
+
+        /* Remove whole region */
+        if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
+            --dev->mem->nregions;
+            --to;
+            assert(to >= 0);
+            ++overlap_middle;
+            continue;
+        }
+
+        /* Shrink region */
+        if (memlast >= reglast) {
+            reg->memory_size = start_addr - reg->guest_phys_addr;
+            assert(reg->memory_size);
+            assert(!overlap_end);
+            ++overlap_end;
+            continue;
+        }
+
+        /* Shift region */
+        if (start_addr <= reg->guest_phys_addr) {
+            change = memlast + 1 - reg->guest_phys_addr;
+            reg->memory_size -= change;
+            reg->guest_phys_addr += change;
+            reg->userspace_addr += change;
+            assert(reg->memory_size);
+            assert(!overlap_start);
+            ++overlap_start;
+            continue;
+        }
+
+        /* This only happens if supplied region
+         * is in the middle of an existing one. Thus it can not
+         * overlap with any other existing region. */
+        assert(!overlap_start);
+        assert(!overlap_end);
+        assert(!overlap_middle);
+        /* Split region: shrink first part, shift second part. */
+        memcpy(dev->mem->regions + n, reg, sizeof *reg);
+        reg->memory_size = start_addr - reg->guest_phys_addr;
+        assert(reg->memory_size);
+        change = memlast + 1 - reg->guest_phys_addr;
+        reg = dev->mem->regions + n;
+        reg->memory_size -= change;
+        assert(reg->memory_size);
+        reg->guest_phys_addr += change;
+        reg->userspace_addr += change;
+        /* Never add more than 1 region */
+        assert(dev->mem->nregions == n);
+        ++dev->mem->nregions;
+        ++split;
+    }
+}
+
+/* Called after unassign, so no regions overlap the given range. */
+static void vhost_dev_assign_memory(struct vhost_dev *dev,
+                                    uint64_t start_addr,
+                                    uint64_t size,
+                                    uint64_t uaddr)
+{
+    int from, to;
+    struct vhost_memory_region *merged = NULL;
+    for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        uint64_t prlast, urlast;
+        uint64_t pmlast, umlast;
+        uint64_t s, e, u;
+
+        /* clone old region */
+        if (to != from) {
+            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+        }
+        prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+        pmlast = range_get_last(start_addr, size);
+        urlast = range_get_last(reg->userspace_addr, reg->memory_size);
+        umlast = range_get_last(uaddr, size);
+
+        /* check for overlapping regions: should never happen. */
+        assert(prlast < start_addr || pmlast < reg->guest_phys_addr);
+        /* Not an adjacent or overlapping region - do not merge. */
+        if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
+            (pmlast + 1 != reg->guest_phys_addr ||
+             umlast + 1 != reg->userspace_addr)) {
+            continue;
+        }
+
+        if (merged) {
+            --to;
+            assert(to >= 0);
+        } else {
+            merged = reg;
+        }
+        u = MIN(uaddr, reg->userspace_addr);
+        s = MIN(start_addr, reg->guest_phys_addr);
+        e = MAX(pmlast, prlast);
+        uaddr = merged->userspace_addr = u;
+        start_addr = merged->guest_phys_addr = s;
+        size = merged->memory_size = e - s + 1;
+        assert(merged->memory_size);
+    }
+
+    if (!merged) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        memset(reg, 0, sizeof *reg);
+        reg->memory_size = size;
+        assert(reg->memory_size);
+        reg->guest_phys_addr = start_addr;
+        reg->userspace_addr = uaddr;
+        ++to;
+    }
+    assert(to <= dev->mem->nregions + 1);
+    dev->mem->nregions = to;
+}
+
+static uint64_t vhost_get_log_size(struct vhost_dev *dev)
+{
+    uint64_t log_size = 0;
+    int i;
+    for (i = 0; i < dev->mem->nregions; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        uint64_t last = range_get_last(reg->guest_phys_addr,
+                                       reg->memory_size);
+        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        uint64_t last = vq->used_phys + vq->used_size - 1;
+        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
+    }
+    return log_size;
+}
+
+static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
+{
+    vhost_log_chunk_t *log;
+    uint64_t log_base;
+    int r;
+    if (size) {
+        log = qemu_mallocz(size * sizeof *log);
+    } else {
+        log = NULL;
+    }
+    log_base = (uint64_t)(unsigned long)log;
+    r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
+    assert(r >= 0);
+    vhost_client_sync_dirty_bitmap(&dev->client, 0,
+                                   (target_phys_addr_t)~0x0ull);
+    if (dev->log) {
+        qemu_free(dev->log);
+    }
+    dev->log = log;
+    dev->log_size = size;
+}
+
+static int vhost_verify_ring_mappings(struct vhost_dev *dev,
+                                      uint64_t start_addr,
+                                      uint64_t size)
+{
+    int i;
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        target_phys_addr_t l;
+        void *p;
+
+        if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) {
+            continue;
+        }
+        l = vq->ring_size;
+        p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
+        if (!p || l != vq->ring_size) {
+            fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
+            return -ENOMEM;
+        }
+        if (p != vq->ring) {
+            fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
+            return -EBUSY;
+        }
+        cpu_physical_memory_unmap(p, l, 0, 0);
+    }
+    return 0;
+}
+
+static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
+						      uint64_t start_addr,
+						      uint64_t size)
+{
+    int i, n = dev->mem->nregions;
+    for (i = 0; i < n; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+                           start_addr, size)) {
+            return reg;
+        }
+    }
+    return NULL;
+}
+
+static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
+                                 uint64_t start_addr,
+                                 uint64_t size,
+                                 uint64_t uaddr)
+{
+    struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
+    uint64_t reglast;
+    uint64_t memlast;
+
+    if (!reg) {
+        return true;
+    }
+
+    reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+    memlast = range_get_last(start_addr, size);
+
+    /* Need to extend region? */
+    if (start_addr < reg->guest_phys_addr || memlast > reglast) {
+        return true;
+    }
+    /* userspace_addr changed? */
+    return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
+}
+
+static void vhost_client_set_memory(CPUPhysMemoryClient *client,
+                                    target_phys_addr_t start_addr,
+                                    ram_addr_t size,
+                                    ram_addr_t phys_offset,
+                                    bool log_dirty)
+{
+    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    int s = offsetof(struct vhost_memory, regions) +
+        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
+    uint64_t log_size;
+    int r;
+
+    dev->mem = qemu_realloc(dev->mem, s);
+
+    if (log_dirty) {
+        flags = IO_MEM_UNASSIGNED;
+    }
+
+    assert(size);
+
+    /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
+    if (flags == IO_MEM_RAM) {
+        if (!vhost_dev_cmp_memory(dev, start_addr, size,
+                                  (uintptr_t)qemu_get_ram_ptr(phys_offset))) {
+            /* Region exists with same address. Nothing to do. */
+            return;
+        }
+    } else {
+        if (!vhost_dev_find_reg(dev, start_addr, size)) {
+            /* Removing region that we don't access. Nothing to do. */
+            return;
+        }
+    }
+
+    vhost_dev_unassign_memory(dev, start_addr, size);
+    if (flags == IO_MEM_RAM) {
+        /* Add given mapping, merging adjacent regions if any */
+        vhost_dev_assign_memory(dev, start_addr, size,
+                                (uintptr_t)qemu_get_ram_ptr(phys_offset));
+    } else {
+        /* Remove old mapping for this memory, if any. */
+        vhost_dev_unassign_memory(dev, start_addr, size);
+    }
+
+    if (!dev->started) {
+        return;
+    }
+
+    if (dev->started) {
+        r = vhost_verify_ring_mappings(dev, start_addr, size);
+        assert(r >= 0);
+    }
+
+    if (!dev->log_enabled) {
+        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
+        assert(r >= 0);
+        return;
+    }
+    log_size = vhost_get_log_size(dev);
+    /* We allocate an extra 4K bytes to log,
+     * to reduce the * number of reallocations. */
+#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
+    /* To log more, must increase log size before table update. */
+    if (dev->log_size < log_size) {
+        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
+    }
+    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
+    assert(r >= 0);
+    /* To log less, can only decrease log size after table update. */
+    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
+        vhost_dev_log_resize(dev, log_size);
+    }
+}
+
+static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
+                                    struct vhost_virtqueue *vq,
+                                    unsigned idx, bool enable_log)
+{
+    struct vhost_vring_addr addr = {
+        .index = idx,
+        .desc_user_addr = (uint64_t)(unsigned long)vq->desc,
+        .avail_user_addr = (uint64_t)(unsigned long)vq->avail,
+        .used_user_addr = (uint64_t)(unsigned long)vq->used,
+        .log_guest_addr = vq->used_phys,
+        .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
+    };
+    int r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
+    if (r < 0) {
+        return -errno;
+    }
+    return 0;
+}
+
+static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
+{
+    uint64_t features = dev->acked_features;
+    int r;
+    if (enable_log) {
+        features |= 0x1 << VHOST_F_LOG_ALL;
+    }
+    r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
+    return r < 0 ? -errno : 0;
+}
+
+static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
+{
+    int r, t, i;
+    r = vhost_dev_set_features(dev, enable_log);
+    if (r < 0) {
+        goto err_features;
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        r = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
+                                     enable_log);
+        if (r < 0) {
+            goto err_vq;
+        }
+    }
+    return 0;
+err_vq:
+    for (; i >= 0; --i) {
+        t = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
+                                     dev->log_enabled);
+        assert(t >= 0);
+    }
+    t = vhost_dev_set_features(dev, dev->log_enabled);
+    assert(t >= 0);
+err_features:
+    return r;
+}
+
+static int vhost_client_migration_log(CPUPhysMemoryClient *client,
+                                      int enable)
+{
+    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
+    int r;
+    if (!!enable == dev->log_enabled) {
+        return 0;
+    }
+    if (!dev->started) {
+        dev->log_enabled = enable;
+        return 0;
+    }
+    if (!enable) {
+        r = vhost_dev_set_log(dev, false);
+        if (r < 0) {
+            return r;
+        }
+        if (dev->log) {
+            qemu_free(dev->log);
+        }
+        dev->log = NULL;
+        dev->log_size = 0;
+    } else {
+        vhost_dev_log_resize(dev, vhost_get_log_size(dev));
+        r = vhost_dev_set_log(dev, true);
+        if (r < 0) {
+            return r;
+        }
+    }
+    dev->log_enabled = enable;
+    return 0;
+}
+
+static int vhost_virtqueue_init(struct vhost_dev *dev,
+                                struct VirtIODevice *vdev,
+                                struct vhost_virtqueue *vq,
+                                unsigned idx)
+{
+    target_phys_addr_t s, l, a;
+    int r;
+    struct vhost_vring_file file = {
+        .index = idx,
+    };
+    struct vhost_vring_state state = {
+        .index = idx,
+    };
+    struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
+
+    if (!vdev->binding->set_host_notifier) {
+        fprintf(stderr, "binding does not support host notifiers\n");
+        return -ENOSYS;
+    }
+
+    vq->num = state.num = virtio_queue_get_num(vdev, idx);
+    r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
+    if (r) {
+        return -errno;
+    }
+
+    state.num = virtio_queue_get_last_avail_idx(vdev, idx);
+    r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
+    if (r) {
+        return -errno;
+    }
+
+    s = l = virtio_queue_get_desc_size(vdev, idx);
+    a = virtio_queue_get_desc_addr(vdev, idx);
+    vq->desc = cpu_physical_memory_map(a, &l, 0);
+    if (!vq->desc || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_desc;
+    }
+    s = l = virtio_queue_get_avail_size(vdev, idx);
+    a = virtio_queue_get_avail_addr(vdev, idx);
+    vq->avail = cpu_physical_memory_map(a, &l, 0);
+    if (!vq->avail || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_avail;
+    }
+    vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
+    vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
+    vq->used = cpu_physical_memory_map(a, &l, 1);
+    if (!vq->used || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_used;
+    }
+
+    vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
+    vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
+    vq->ring = cpu_physical_memory_map(a, &l, 1);
+    if (!vq->ring || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_ring;
+    }
+
+    r = vhost_virtqueue_set_addr(dev, vq, idx, dev->log_enabled);
+    if (r < 0) {
+        r = -errno;
+        goto fail_alloc;
+    }
+    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
+    if (r < 0) {
+        fprintf(stderr, "Error binding host notifier: %d\n", -r);
+        goto fail_host_notifier;
+    }
+
+    file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
+    r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
+    if (r) {
+        r = -errno;
+        goto fail_kick;
+    }
+
+    file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
+    r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
+    if (r) {
+        r = -errno;
+        goto fail_call;
+    }
+
+    return 0;
+
+fail_call:
+fail_kick:
+    vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
+fail_host_notifier:
+fail_alloc:
+    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
+                              0, 0);
+fail_alloc_ring:
+    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
+                              0, 0);
+fail_alloc_used:
+    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
+                              0, 0);
+fail_alloc_avail:
+    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
+                              0, 0);
+fail_alloc_desc:
+    return r;
+}
+
+static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
+                                    struct VirtIODevice *vdev,
+                                    struct vhost_virtqueue *vq,
+                                    unsigned idx)
+{
+    struct vhost_vring_state state = {
+        .index = idx,
+    };
+    int r;
+    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
+    if (r < 0) {
+        fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
+        fflush(stderr);
+    }
+    assert (r >= 0);
+    r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
+    if (r < 0) {
+        fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
+        fflush(stderr);
+    }
+    virtio_queue_set_last_avail_idx(vdev, idx, state.num);
+    assert (r >= 0);
+    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
+                              0, virtio_queue_get_ring_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
+                              1, virtio_queue_get_used_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
+                              0, virtio_queue_get_avail_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
+                              0, virtio_queue_get_desc_size(vdev, idx));
+}
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
+{
+    uint64_t features;
+    int r;
+    if (devfd >= 0) {
+        hdev->control = devfd;
+    } else {
+        hdev->control = open("/dev/vhost-net", O_RDWR);
+        if (hdev->control < 0) {
+            return -errno;
+        }
+    }
+    r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
+    if (r < 0) {
+        goto fail;
+    }
+
+    r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
+    if (r < 0) {
+        goto fail;
+    }
+    hdev->features = features;
+
+    hdev->client.set_memory = vhost_client_set_memory;
+    hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap;
+    hdev->client.migration_log = vhost_client_migration_log;
+    hdev->client.log_start = NULL;
+    hdev->client.log_stop = NULL;
+    hdev->mem = qemu_mallocz(offsetof(struct vhost_memory, regions));
+    hdev->log = NULL;
+    hdev->log_size = 0;
+    hdev->log_enabled = false;
+    hdev->started = false;
+    cpu_register_phys_memory_client(&hdev->client);
+    hdev->force = force;
+    return 0;
+fail:
+    r = -errno;
+    close(hdev->control);
+    return r;
+}
+
+void vhost_dev_cleanup(struct vhost_dev *hdev)
+{
+    cpu_unregister_phys_memory_client(&hdev->client);
+    qemu_free(hdev->mem);
+    close(hdev->control);
+}
+
+bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    return !vdev->binding->query_guest_notifiers ||
+        vdev->binding->query_guest_notifiers(vdev->binding_opaque) ||
+        hdev->force;
+}
+
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+    if (!vdev->binding->set_guest_notifiers) {
+        fprintf(stderr, "binding does not support guest notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true);
+    if (r < 0) {
+        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
+        goto fail_notifiers;
+    }
+
+    r = vhost_dev_set_features(hdev, hdev->log_enabled);
+    if (r < 0) {
+        goto fail_features;
+    }
+    r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
+    if (r < 0) {
+        r = -errno;
+        goto fail_mem;
+    }
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vhost_virtqueue_init(hdev,
+                                 vdev,
+                                 hdev->vqs + i,
+                                 i);
+        if (r < 0) {
+            goto fail_vq;
+        }
+    }
+
+    if (hdev->log_enabled) {
+        hdev->log_size = vhost_get_log_size(hdev);
+        hdev->log = hdev->log_size ?
+            qemu_mallocz(hdev->log_size * sizeof *hdev->log) : NULL;
+        r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
+                  (uint64_t)(unsigned long)hdev->log);
+        if (r < 0) {
+            r = -errno;
+            goto fail_log;
+        }
+    }
+
+    hdev->started = true;
+
+    return 0;
+fail_log:
+fail_vq:
+    while (--i >= 0) {
+        vhost_virtqueue_cleanup(hdev,
+                                vdev,
+                                hdev->vqs + i,
+                                i);
+    }
+fail_mem:
+fail_features:
+    vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+fail_notifiers:
+fail:
+    return r;
+}
+
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        vhost_virtqueue_cleanup(hdev,
+                                vdev,
+                                hdev->vqs + i,
+                                i);
+    }
+    vhost_client_sync_dirty_bitmap(&hdev->client, 0,
+                                   (target_phys_addr_t)~0x0ull);
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+    if (r < 0) {
+        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+        fflush(stderr);
+    }
+    assert (r >= 0);
+
+    hdev->started = false;
+    qemu_free(hdev->log);
+    hdev->log = NULL;
+    hdev->log_size = 0;
+}
diff --git a/qemu-0.15.x/hw/vhost.h b/qemu-0.15.x/hw/vhost.h
new file mode 100644
index 0000000..c8c595a
--- /dev/null
+++ b/qemu-0.15.x/hw/vhost.h
@@ -0,0 +1,50 @@
+#ifndef VHOST_H
+#define VHOST_H
+
+#include "hw/hw.h"
+#include "hw/virtio.h"
+
+/* Generic structures common for any vhost based device. */
+struct vhost_virtqueue {
+    int kick;
+    int call;
+    void *desc;
+    void *avail;
+    void *used;
+    int num;
+    unsigned long long used_phys;
+    unsigned used_size;
+    void *ring;
+    unsigned long long ring_phys;
+    unsigned ring_size;
+};
+
+typedef unsigned long vhost_log_chunk_t;
+#define VHOST_LOG_PAGE 0x1000
+#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
+#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
+
+struct vhost_memory;
+struct vhost_dev {
+    CPUPhysMemoryClient client;
+    int control;
+    struct vhost_memory *mem;
+    struct vhost_virtqueue *vqs;
+    int nvqs;
+    unsigned long long features;
+    unsigned long long acked_features;
+    unsigned long long backend_features;
+    bool started;
+    bool log_enabled;
+    vhost_log_chunk_t *log;
+    unsigned long long log_size;
+    bool force;
+};
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force);
+void vhost_dev_cleanup(struct vhost_dev *hdev);
+bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
+
+#endif
diff --git a/qemu-0.15.x/hw/vhost_net.c b/qemu-0.15.x/hw/vhost_net.c
new file mode 100644
index 0000000..b6dc592
--- /dev/null
+++ b/qemu-0.15.x/hw/vhost_net.c
@@ -0,0 +1,237 @@
+/*
+ * vhost-net support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "net.h"
+#include "net/tap.h"
+
+#include "virtio-net.h"
+#include "vhost_net.h"
+#include "qemu-error.h"
+
+#include "config.h"
+
+#ifdef CONFIG_VHOST_NET
+#include <linux/vhost.h>
+#include <sys/socket.h>
+#include <linux/kvm.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/virtio_ring.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "vhost.h"
+
+struct vhost_net {
+    struct vhost_dev dev;
+    struct vhost_virtqueue vqs[2];
+    int backend;
+    VLANClientState *vc;
+};
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+    /* Clear features not supported by host kernel. */
+    if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
+        features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
+        features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
+        features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+    return features;
+}
+
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+    net->dev.acked_features = net->dev.backend_features;
+    if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
+        net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    }
+    if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
+    }
+    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
+    }
+    if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+}
+
+static int vhost_net_get_fd(VLANClientState *backend)
+{
+    switch (backend->info->type) {
+    case NET_CLIENT_TYPE_TAP:
+        return tap_get_fd(backend);
+    default:
+        fprintf(stderr, "vhost-net requires tap backend\n");
+        return -EBADFD;
+    }
+}
+
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
+                                 bool force)
+{
+    int r;
+    struct vhost_net *net = qemu_malloc(sizeof *net);
+    if (!backend) {
+        fprintf(stderr, "vhost-net requires backend to be setup\n");
+        goto fail;
+    }
+    r = vhost_net_get_fd(backend);
+    if (r < 0) {
+        goto fail;
+    }
+    net->vc = backend;
+    net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
+        (1 << VHOST_NET_F_VIRTIO_NET_HDR);
+    net->backend = r;
+
+    r = vhost_dev_init(&net->dev, devfd, force);
+    if (r < 0) {
+        goto fail;
+    }
+    if (!tap_has_vnet_hdr_len(backend,
+                              sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
+        net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+    if (~net->dev.features & net->dev.backend_features) {
+        fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
+                (uint64_t)(~net->dev.features & net->dev.backend_features));
+        vhost_dev_cleanup(&net->dev);
+        goto fail;
+    }
+
+    /* Set sane init value. Override when guest acks. */
+    vhost_net_ack_features(net, 0);
+    return net;
+fail:
+    qemu_free(net);
+    return NULL;
+}
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
+{
+    return vhost_dev_query(&net->dev, dev);
+}
+
+int vhost_net_start(struct vhost_net *net,
+                    VirtIODevice *dev)
+{
+    struct vhost_vring_file file = { };
+    int r;
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc,
+                             sizeof(struct virtio_net_hdr_mrg_rxbuf));
+    }
+
+    net->dev.nvqs = 2;
+    net->dev.vqs = net->vqs;
+    r = vhost_dev_start(&net->dev, dev);
+    if (r < 0) {
+        return r;
+    }
+
+    net->vc->info->poll(net->vc, false);
+    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
+    file.fd = net->backend;
+    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+        r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        if (r < 0) {
+            r = -errno;
+            goto fail;
+        }
+    }
+    return 0;
+fail:
+    file.fd = -1;
+    while (file.index-- > 0) {
+        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        assert(r >= 0);
+    }
+    net->vc->info->poll(net->vc, true);
+    vhost_dev_stop(&net->dev, dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
+    return r;
+}
+
+void vhost_net_stop(struct vhost_net *net,
+                    VirtIODevice *dev)
+{
+    struct vhost_vring_file file = { .fd = -1 };
+
+    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        assert(r >= 0);
+    }
+    net->vc->info->poll(net->vc, true);
+    vhost_dev_stop(&net->dev, dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+    vhost_dev_cleanup(&net->dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
+    qemu_free(net);
+}
+#else
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
+                                 bool force)
+{
+    error_report("vhost-net support is not compiled in");
+    return NULL;
+}
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
+{
+    return false;
+}
+
+int vhost_net_start(struct vhost_net *net,
+		    VirtIODevice *dev)
+{
+    return -ENOSYS;
+}
+void vhost_net_stop(struct vhost_net *net,
+		    VirtIODevice *dev)
+{
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+}
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+    return features;
+}
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+}
+#endif
diff --git a/qemu-0.15.x/hw/vhost_net.h b/qemu-0.15.x/hw/vhost_net.h
new file mode 100644
index 0000000..91e40b1
--- /dev/null
+++ b/qemu-0.15.x/hw/vhost_net.h
@@ -0,0 +1,20 @@
+#ifndef VHOST_NET_H
+#define VHOST_NET_H
+
+#include "net.h"
+
+struct vhost_net;
+typedef struct vhost_net VHostNetState;
+
+VHostNetState *vhost_net_init(VLANClientState *backend, int devfd, bool force);
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev);
+int vhost_net_start(VHostNetState *net, VirtIODevice *dev);
+void vhost_net_stop(VHostNetState *net, VirtIODevice *dev);
+
+void vhost_net_cleanup(VHostNetState *net);
+
+unsigned vhost_net_get_features(VHostNetState *net, unsigned features);
+void vhost_net_ack_features(VHostNetState *net, unsigned features);
+
+#endif
diff --git a/qemu-0.15.x/hw/virtex_ml507.c b/qemu-0.15.x/hw/virtex_ml507.c
new file mode 100644
index 0000000..7bde8c7
--- /dev/null
+++ b/qemu-0.15.x/hw/virtex_ml507.c
@@ -0,0 +1,276 @@
+/*
+ * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "pc.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
+#include "qemu-log.h"
+
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "ppc440.h"
+#include "ppc405.h"
+
+#include "blockdev.h"
+#include "xilinx.h"
+
+#define EPAPR_MAGIC    (0x45504150)
+#define FLASH_SIZE     (16 * 1024 * 1024)
+
+static struct boot_info
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+    uint32_t ima_size;
+    void *vfdt;
+} boot_info;
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+
+    tlb = &env->tlb.tlbe[1];
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0xffffffff  */
+    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
+                                    int do_init,
+                                    const char *cpu_model,
+                                    clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                                    uint32_t sysclk)
+{
+    CPUState *env;
+    qemu_irq *irqs;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+    cpu_clk->opaque = env;
+    /* Set time-base frequency to sysclk */
+    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
+    tb_clk->opaque = env;
+
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    return env;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(env);
+    /* Linux Kernel Parameters (passing device tree):
+       *   r3: pointer to the fdt
+       *   r4: 0
+       *   r5: 0
+       *   r6: epapr magic
+       *   r7: size of IMA in bytes
+       *   r8: 0
+       *   r9: 0
+    */
+    env->gpr[1] = (16<<20) - 8;
+    /* Provide a device-tree.  */
+    env->gpr[3] = bi->fdt;
+    env->nip = bi->bootstrap_pc;
+
+    /* Create a mapping for the kernel.  */
+    mmubooke_create_initial_mapping(env, 0, 0);
+    env->gpr[6] = tswap32(EPAPR_MAGIC);
+    env->gpr[7] = bi->ima_size;
+}
+
+#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
+static int xilinx_load_device_tree(target_phys_addr_t addr,
+                                      uint32_t ramsize,
+                                      target_phys_addr_t initrd_base,
+                                      target_phys_addr_t initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "ppc.dtb" override.  */
+    fdt = load_device_tree("ppc.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            qemu_free(path);
+        }
+        if (!fdt) {
+            return 0;
+        }
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+            qemu_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static void virtex_init(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    DeviceState *dev;
+    CPUState *env;
+    target_phys_addr_t ram_base = 0;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+    clk_setup_t clk_setup[7];
+    int kernel_size;
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx";
+    }
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
+                             &clk_setup[1], 400000000);
+    qemu_register_reset(main_cpu_reset, env);
+
+    phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(0xfc000000, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+    cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
+    dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+
+    /* 2 timers at irq 2 @ 62 Mhz.  */
+    xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        target_phys_addr_t boot_offset;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high, 1, ELF_MACHINE, 0);
+        boot_info.bootstrap_pc = entry & 0x00ffffff;
+
+        if (kernel_size < 0) {
+            boot_offset = 0x1200000;
+            /* If we failed loading ELF's try a raw image.  */
+            kernel_size = load_image_targphys(kernel_filename,
+                                              boot_offset,
+                                              ram_size);
+            boot_info.bootstrap_pc = boot_offset;
+            high = boot_info.bootstrap_pc + kernel_size + 8192;
+        }
+
+        boot_info.ima_size = kernel_size;
+
+        /* Provide a device-tree.  */
+        boot_info.fdt = high + (8192 * 2);
+        boot_info.fdt &= ~8191;
+        xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+    }
+    env->load_info = &boot_info;
+}
+
+static QEMUMachine virtex_machine = {
+    .name = "virtex-ml507",
+    .desc = "Xilinx Virtex ML507 reference design",
+    .init = virtex_init,
+};
+
+static void virtex_machine_init(void)
+{
+    qemu_register_machine(&virtex_machine);
+}
+
+machine_init(virtex_machine_init);
diff --git a/qemu-0.15.x/hw/virtio-balloon.c b/qemu-0.15.x/hw/virtio-balloon.c
new file mode 100644
index 0000000..072a88a
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-balloon.c
@@ -0,0 +1,308 @@
+/*
+ * Virtio Balloon Device
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah at redhat.com>
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "iov.h"
+#include "qemu-common.h"
+#include "virtio.h"
+#include "pc.h"
+#include "cpu.h"
+#include "monitor.h"
+#include "balloon.h"
+#include "virtio-balloon.h"
+#include "kvm.h"
+#include "qlist.h"
+#include "qint.h"
+#include "qstring.h"
+
+#if defined(__linux__)
+#include <sys/mman.h>
+#endif
+
+/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
+#define ENABLE_GUEST_STATS   0
+
+
+typedef struct VirtIOBalloon
+{
+    VirtIODevice vdev;
+    VirtQueue *ivq, *dvq, *svq;
+    uint32_t num_pages;
+    uint32_t actual;
+    uint64_t stats[VIRTIO_BALLOON_S_NR];
+    VirtQueueElement stats_vq_elem;
+    size_t stats_vq_offset;
+    MonitorCompletion *stats_callback;
+    void *stats_opaque_callback_data;
+    DeviceState *qdev;
+} VirtIOBalloon;
+
+static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
+{
+    return (VirtIOBalloon *)vdev;
+}
+
+static void balloon_page(void *addr, int deflate)
+{
+#if defined(__linux__)
+    if (!kvm_enabled() || kvm_has_sync_mmu())
+        qemu_madvise(addr, TARGET_PAGE_SIZE,
+                deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
+#endif
+}
+
+/*
+ * reset_stats - Mark all items in the stats array as unset
+ *
+ * This function needs to be called at device intialization and before
+ * before updating to a set of newly-generated stats.  This will ensure that no
+ * stale values stick around in case the guest reports a subset of the supported
+ * statistics.
+ */
+static inline void reset_stats(VirtIOBalloon *dev)
+{
+    int i;
+    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
+}
+
+static void stat_put(QDict *dict, const char *label, uint64_t val)
+{
+    if (val != -1)
+        qdict_put(dict, label, qint_from_int(val));
+}
+
+static QObject *get_stats_qobject(VirtIOBalloon *dev)
+{
+    QDict *dict = qdict_new();
+    uint64_t actual = ram_size - ((uint64_t) dev->actual <<
+                                  VIRTIO_BALLOON_PFN_SHIFT);
+
+    stat_put(dict, "actual", actual);
+#if ENABLE_GUEST_STATS
+    stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
+    stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
+    stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
+    stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
+    stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
+    stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
+#endif
+
+    return QOBJECT(dict);
+}
+
+static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBalloon *s = to_virtio_balloon(vdev);
+    VirtQueueElement elem;
+
+    while (virtqueue_pop(vq, &elem)) {
+        size_t offset = 0;
+        uint32_t pfn;
+
+        while (iov_to_buf(elem.out_sg, elem.out_num, &pfn, offset, 4) == 4) {
+            ram_addr_t pa;
+            ram_addr_t addr;
+
+            pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
+            offset += 4;
+
+            addr = cpu_get_physical_page_desc(pa);
+            if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
+                continue;
+
+            /* Using qemu_get_ram_ptr is bending the rules a bit, but
+               should be OK because we only want a single page.  */
+            balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq));
+        }
+
+        virtqueue_push(vq, &elem, offset);
+        virtio_notify(vdev, vq);
+    }
+}
+
+static void complete_stats_request(VirtIOBalloon *vb)
+{
+    QObject *stats;
+
+    if (!vb->stats_opaque_callback_data)
+        return;
+
+    stats = get_stats_qobject(vb);
+    vb->stats_callback(vb->stats_opaque_callback_data, stats);
+    qobject_decref(stats);
+    vb->stats_opaque_callback_data = NULL;
+    vb->stats_callback = NULL;
+}
+
+static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+    VirtQueueElement *elem = &s->stats_vq_elem;
+    VirtIOBalloonStat stat;
+    size_t offset = 0;
+
+    if (!virtqueue_pop(vq, elem)) {
+        return;
+    }
+
+    /* Initialize the stats to get rid of any stale values.  This is only
+     * needed to handle the case where a guest supports fewer stats than it
+     * used to (ie. it has booted into an old kernel).
+     */
+    reset_stats(s);
+
+    while (iov_to_buf(elem->out_sg, elem->out_num, &stat, offset, sizeof(stat))
+           == sizeof(stat)) {
+        uint16_t tag = tswap16(stat.tag);
+        uint64_t val = tswap64(stat.val);
+
+        offset += sizeof(stat);
+        if (tag < VIRTIO_BALLOON_S_NR)
+            s->stats[tag] = val;
+    }
+    s->stats_vq_offset = offset;
+
+    complete_stats_request(s);
+}
+
+static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOBalloon *dev = to_virtio_balloon(vdev);
+    struct virtio_balloon_config config;
+
+    config.num_pages = cpu_to_le32(dev->num_pages);
+    config.actual = cpu_to_le32(dev->actual);
+
+    memcpy(config_data, &config, 8);
+}
+
+static void virtio_balloon_set_config(VirtIODevice *vdev,
+                                      const uint8_t *config_data)
+{
+    VirtIOBalloon *dev = to_virtio_balloon(vdev);
+    struct virtio_balloon_config config;
+    memcpy(&config, config_data, 8);
+    dev->actual = le32_to_cpu(config.actual);
+}
+
+static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
+{
+    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
+    return f;
+}
+
+static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
+                                void *cb_data)
+{
+    VirtIOBalloon *dev = opaque;
+
+    /* For now, only allow one request at a time.  This restriction can be
+     * removed later by queueing callback and data pairs.
+     */
+    if (dev->stats_callback != NULL) {
+        return;
+    }
+    dev->stats_callback = cb;
+    dev->stats_opaque_callback_data = cb_data;
+
+    if (ENABLE_GUEST_STATS
+        && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
+        virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
+        virtio_notify(&dev->vdev, dev->svq);
+        return;
+    }
+
+    /* Stats are not supported.  Clear out any stale values that might
+     * have been set by a more featureful guest kernel.
+     */
+    reset_stats(dev);
+    complete_stats_request(dev);
+}
+
+static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
+{
+    VirtIOBalloon *dev = opaque;
+
+    if (target > ram_size) {
+        target = ram_size;
+    }
+    if (target) {
+        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
+        virtio_notify_config(&dev->vdev);
+    }
+}
+
+static void virtio_balloon_save(QEMUFile *f, void *opaque)
+{
+    VirtIOBalloon *s = opaque;
+
+    virtio_save(&s->vdev, f);
+
+    qemu_put_be32(f, s->num_pages);
+    qemu_put_be32(f, s->actual);
+}
+
+static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOBalloon *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    virtio_load(&s->vdev, f);
+
+    s->num_pages = qemu_get_be32(f);
+    s->actual = qemu_get_be32(f);
+    return 0;
+}
+
+VirtIODevice *virtio_balloon_init(DeviceState *dev)
+{
+    VirtIOBalloon *s;
+    int ret;
+
+    s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
+                                            VIRTIO_ID_BALLOON,
+                                            8, sizeof(VirtIOBalloon));
+
+    s->vdev.get_config = virtio_balloon_get_config;
+    s->vdev.set_config = virtio_balloon_set_config;
+    s->vdev.get_features = virtio_balloon_get_features;
+
+    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
+                                   virtio_balloon_stat, s);
+    if (ret < 0) {
+        virtio_cleanup(&s->vdev);
+        return NULL;
+    }
+
+    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
+    s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
+    s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
+
+    reset_stats(s);
+
+    s->qdev = dev;
+    register_savevm(dev, "virtio-balloon", -1, 1,
+                    virtio_balloon_save, virtio_balloon_load, s);
+
+    return &s->vdev;
+}
+
+void virtio_balloon_exit(VirtIODevice *vdev)
+{
+    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+    unregister_savevm(s->qdev, "virtio-balloon", s);
+    virtio_cleanup(vdev);
+}
diff --git a/qemu-0.15.x/hw/virtio-balloon.h b/qemu-0.15.x/hw/virtio-balloon.h
new file mode 100644
index 0000000..e20cf6b
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-balloon.h
@@ -0,0 +1,55 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007-2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Rusty Russell     <rusty at rustcorp.com.au>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_BALLOON_H
+#define _QEMU_VIRTIO_BALLOON_H
+
+#include "virtio.h"
+#include "pci.h"
+
+/* from Linux's linux/virtio_balloon.h */
+
+/* The ID for virtio_balloon */
+#define VIRTIO_ID_BALLOON 5
+
+/* The feature bitmap for virtio balloon */
+#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
+#define VIRTIO_BALLOON_F_STATS_VQ 1       /* Memory stats virtqueue */
+
+/* Size of a PFN in the balloon interface. */
+#define VIRTIO_BALLOON_PFN_SHIFT 12
+
+struct virtio_balloon_config
+{
+    /* Number of pages host wants Guest to give up. */
+    uint32_t num_pages;
+    /* Number of pages we've actually got in balloon. */
+    uint32_t actual;
+};
+
+/* Memory Statistics */
+#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
+#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
+#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
+#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
+#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
+#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
+#define VIRTIO_BALLOON_S_NR       6
+
+typedef struct VirtIOBalloonStat {
+    uint16_t tag;
+    uint64_t val;
+} __attribute__((packed)) VirtIOBalloonStat;
+
+#endif
diff --git a/qemu-0.15.x/hw/virtio-blk.c b/qemu-0.15.x/hw/virtio-blk.c
new file mode 100644
index 0000000..6471ac8
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-blk.c
@@ -0,0 +1,597 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <qemu-common.h>
+#include "qemu-error.h"
+#include "trace.h"
+#include "blockdev.h"
+#include "virtio-blk.h"
+#ifdef __linux__
+# include <scsi/sg.h>
+#endif
+
+typedef struct VirtIOBlock
+{
+    VirtIODevice vdev;
+    BlockDriverState *bs;
+    VirtQueue *vq;
+    void *rq;
+    QEMUBH *bh;
+    BlockConf *conf;
+    char *serial;
+    unsigned short sector_mask;
+    DeviceState *qdev;
+} VirtIOBlock;
+
+static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
+{
+    return (VirtIOBlock *)vdev;
+}
+
+typedef struct VirtIOBlockReq
+{
+    VirtIOBlock *dev;
+    VirtQueueElement elem;
+    struct virtio_blk_inhdr *in;
+    struct virtio_blk_outhdr *out;
+    struct virtio_scsi_inhdr *scsi;
+    QEMUIOVector qiov;
+    struct VirtIOBlockReq *next;
+} VirtIOBlockReq;
+
+static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
+{
+    VirtIOBlock *s = req->dev;
+
+    trace_virtio_blk_req_complete(req, status);
+
+    stb_p(&req->in->status, status);
+    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
+    virtio_notify(&s->vdev, s->vq);
+
+    qemu_free(req);
+}
+
+static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
+    int is_read)
+{
+    BlockErrorAction action = bdrv_get_on_error(req->dev->bs, is_read);
+    VirtIOBlock *s = req->dev;
+
+    if (action == BLOCK_ERR_IGNORE) {
+        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+        return 0;
+    }
+
+    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+            || action == BLOCK_ERR_STOP_ANY) {
+        req->next = s->rq;
+        s->rq = req;
+        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+        vm_stop(VMSTOP_DISKFULL);
+    } else {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+    }
+
+    return 1;
+}
+
+static void virtio_blk_rw_complete(void *opaque, int ret)
+{
+    VirtIOBlockReq *req = opaque;
+
+    trace_virtio_blk_rw_complete(req, ret);
+
+    if (ret) {
+        int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
+        if (virtio_blk_handle_rw_error(req, -ret, is_read))
+            return;
+    }
+
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+}
+
+static void virtio_blk_flush_complete(void *opaque, int ret)
+{
+    VirtIOBlockReq *req = opaque;
+
+    if (ret) {
+        if (virtio_blk_handle_rw_error(req, -ret, 0)) {
+            return;
+        }
+    }
+
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+}
+
+static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
+{
+    VirtIOBlockReq *req = qemu_malloc(sizeof(*req));
+    req->dev = s;
+    req->qiov.size = 0;
+    req->next = NULL;
+    return req;
+}
+
+static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
+{
+    VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+
+    if (req != NULL) {
+        if (!virtqueue_pop(s->vq, &req->elem)) {
+            qemu_free(req);
+            return NULL;
+        }
+    }
+
+    return req;
+}
+
+#ifdef __linux__
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+    struct sg_io_hdr hdr;
+    int ret;
+    int status;
+    int i;
+
+    /*
+     * We require at least one output segment each for the virtio_blk_outhdr
+     * and the SCSI command block.
+     *
+     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
+     * and the sense buffer pointer in the input segments.
+     */
+    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        return;
+    }
+
+    /*
+     * No support for bidirection commands yet.
+     */
+    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+        return;
+    }
+
+    /*
+     * The scsi inhdr is placed in the second-to-last input segment, just
+     * before the regular inhdr.
+     */
+    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
+
+    memset(&hdr, 0, sizeof(struct sg_io_hdr));
+    hdr.interface_id = 'S';
+    hdr.cmd_len = req->elem.out_sg[1].iov_len;
+    hdr.cmdp = req->elem.out_sg[1].iov_base;
+    hdr.dxfer_len = 0;
+
+    if (req->elem.out_num > 2) {
+        /*
+         * If there are more than the minimally required 2 output segments
+         * there is write payload starting from the third iovec.
+         */
+        hdr.dxfer_direction = SG_DXFER_TO_DEV;
+        hdr.iovec_count = req->elem.out_num - 2;
+
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
+
+        hdr.dxferp = req->elem.out_sg + 2;
+
+    } else if (req->elem.in_num > 3) {
+        /*
+         * If we have more than 3 input segments the guest wants to actually
+         * read data.
+         */
+        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+        hdr.iovec_count = req->elem.in_num - 3;
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.in_sg[i].iov_len;
+
+        hdr.dxferp = req->elem.in_sg;
+    } else {
+        /*
+         * Some SCSI commands don't actually transfer any data.
+         */
+        hdr.dxfer_direction = SG_DXFER_NONE;
+    }
+
+    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
+    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
+
+    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
+    if (ret) {
+        status = VIRTIO_BLK_S_UNSUPP;
+        hdr.status = ret;
+        hdr.resid = hdr.dxfer_len;
+    } else if (hdr.status) {
+        status = VIRTIO_BLK_S_IOERR;
+    } else {
+        status = VIRTIO_BLK_S_OK;
+    }
+
+    stl_p(&req->scsi->errors, hdr.status);
+    stl_p(&req->scsi->residual, hdr.resid);
+    stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
+    stl_p(&req->scsi->data_len, hdr.dxfer_len);
+
+    virtio_blk_req_complete(req, status);
+}
+#else
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+}
+#endif /* __linux__ */
+
+typedef struct MultiReqBuffer {
+    BlockRequest        blkreq[32];
+    unsigned int        num_writes;
+} MultiReqBuffer;
+
+static void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
+{
+    int i, ret;
+
+    if (!mrb->num_writes) {
+        return;
+    }
+
+    ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
+    if (ret != 0) {
+        for (i = 0; i < mrb->num_writes; i++) {
+            if (mrb->blkreq[i].error) {
+                virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
+            }
+        }
+    }
+
+    mrb->num_writes = 0;
+}
+
+static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
+{
+    BlockDriverAIOCB *acb;
+
+    /*
+     * Make sure all outstanding writes are posted to the backing device.
+     */
+    virtio_submit_multiwrite(req->dev->bs, mrb);
+
+    acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
+    if (!acb) {
+        virtio_blk_flush_complete(req, -EIO);
+    }
+}
+
+static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
+{
+    BlockRequest *blkreq;
+    uint64_t sector;
+
+    sector = ldq_p(&req->out->sector);
+
+    trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
+
+    if (sector & req->dev->sector_mask) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+
+    if (mrb->num_writes == 32) {
+        virtio_submit_multiwrite(req->dev->bs, mrb);
+    }
+
+    blkreq = &mrb->blkreq[mrb->num_writes];
+    blkreq->sector = sector;
+    blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
+    blkreq->qiov = &req->qiov;
+    blkreq->cb = virtio_blk_rw_complete;
+    blkreq->opaque = req;
+    blkreq->error = 0;
+
+    mrb->num_writes++;
+}
+
+static void virtio_blk_handle_read(VirtIOBlockReq *req)
+{
+    BlockDriverAIOCB *acb;
+    uint64_t sector;
+
+    sector = ldq_p(&req->out->sector);
+
+    if (sector & req->dev->sector_mask) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+
+    acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
+                         req->qiov.size / BDRV_SECTOR_SIZE,
+                         virtio_blk_rw_complete, req);
+    if (!acb) {
+        virtio_blk_rw_complete(req, -EIO);
+    }
+}
+
+static void virtio_blk_handle_request(VirtIOBlockReq *req,
+    MultiReqBuffer *mrb)
+{
+    uint32_t type;
+
+    if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+        error_report("virtio-blk missing headers");
+        exit(1);
+    }
+
+    if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
+        req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
+        error_report("virtio-blk header not in correct element");
+        exit(1);
+    }
+
+    req->out = (void *)req->elem.out_sg[0].iov_base;
+    req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
+
+    type = ldl_p(&req->out->type);
+
+    if (type & VIRTIO_BLK_T_FLUSH) {
+        virtio_blk_handle_flush(req, mrb);
+    } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
+        virtio_blk_handle_scsi(req);
+    } else if (type & VIRTIO_BLK_T_GET_ID) {
+        VirtIOBlock *s = req->dev;
+
+        /*
+         * NB: per existing s/n string convention the string is
+         * terminated by '\0' only when shorter than buffer.
+         */
+        strncpy(req->elem.in_sg[0].iov_base,
+                s->serial ? s->serial : "",
+                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+    } else if (type & VIRTIO_BLK_T_OUT) {
+        qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
+                                 req->elem.out_num - 1);
+        virtio_blk_handle_write(req, mrb);
+    } else {
+        qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
+                                 req->elem.in_num - 1);
+        virtio_blk_handle_read(req);
+    }
+}
+
+static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    VirtIOBlockReq *req;
+    MultiReqBuffer mrb = {
+        .num_writes = 0,
+    };
+
+    while ((req = virtio_blk_get_request(s))) {
+        virtio_blk_handle_request(req, &mrb);
+    }
+
+    virtio_submit_multiwrite(s->bs, &mrb);
+
+    /*
+     * FIXME: Want to check for completions before returning to guest mode,
+     * so cached reads and writes are reported as quickly as possible. But
+     * that should be done in the generic block layer.
+     */
+}
+
+static void virtio_blk_dma_restart_bh(void *opaque)
+{
+    VirtIOBlock *s = opaque;
+    VirtIOBlockReq *req = s->rq;
+    MultiReqBuffer mrb = {
+        .num_writes = 0,
+    };
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    s->rq = NULL;
+
+    while (req) {
+        virtio_blk_handle_request(req, &mrb);
+        req = req->next;
+    }
+
+    virtio_submit_multiwrite(s->bs, &mrb);
+}
+
+static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
+{
+    VirtIOBlock *s = opaque;
+
+    if (!running)
+        return;
+
+    if (!s->bh) {
+        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void virtio_blk_reset(VirtIODevice *vdev)
+{
+    /*
+     * This should cancel pending requests, but can't do nicely until there
+     * are per-device request lists.
+     */
+    qemu_aio_flush();
+}
+
+/* coalesce internal state, copy to pci i/o region 0
+ */
+static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    struct virtio_blk_config blkcfg;
+    uint64_t capacity;
+    int cylinders, heads, secs;
+
+    bdrv_get_geometry(s->bs, &capacity);
+    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
+    memset(&blkcfg, 0, sizeof(blkcfg));
+    stq_raw(&blkcfg.capacity, capacity);
+    stl_raw(&blkcfg.seg_max, 128 - 2);
+    stw_raw(&blkcfg.cylinders, cylinders);
+    blkcfg.heads = heads;
+    blkcfg.sectors = secs & ~s->sector_mask;
+    blkcfg.blk_size = s->conf->logical_block_size;
+    blkcfg.size_max = 0;
+    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
+    blkcfg.alignment_offset = 0;
+    blkcfg.min_io_size = s->conf->min_io_size / blkcfg.blk_size;
+    blkcfg.opt_io_size = s->conf->opt_io_size / blkcfg.blk_size;
+    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
+}
+
+static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+
+    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
+    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
+    features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
+    features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
+
+    if (bdrv_enable_write_cache(s->bs))
+        features |= (1 << VIRTIO_BLK_F_WCACHE);
+    
+    if (bdrv_is_read_only(s->bs))
+        features |= 1 << VIRTIO_BLK_F_RO;
+
+    return features;
+}
+
+static void virtio_blk_save(QEMUFile *f, void *opaque)
+{
+    VirtIOBlock *s = opaque;
+    VirtIOBlockReq *req = s->rq;
+
+    virtio_save(&s->vdev, f);
+    
+    while (req) {
+        qemu_put_sbyte(f, 1);
+        qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+        req = req->next;
+    }
+    qemu_put_sbyte(f, 0);
+}
+
+static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOBlock *s = opaque;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    virtio_load(&s->vdev, f);
+    while (qemu_get_sbyte(f)) {
+        VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+        qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+        req->next = s->rq;
+        s->rq = req;
+
+        virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
+            req->elem.in_num, 1);
+        virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
+            req->elem.out_num, 0);
+    }
+
+    return 0;
+}
+
+static void virtio_blk_change_cb(void *opaque, int reason)
+{
+    VirtIOBlock *s = opaque;
+
+    if (reason & CHANGE_SIZE) {
+        virtio_notify_config(&s->vdev);
+    }
+}
+
+VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
+                              char **serial)
+{
+    VirtIOBlock *s;
+    int cylinders, heads, secs;
+    static int virtio_blk_id;
+    DriveInfo *dinfo;
+
+    if (!conf->bs) {
+        error_report("virtio-blk-pci: drive property not set");
+        return NULL;
+    }
+    if (!bdrv_is_inserted(conf->bs)) {
+        error_report("Device needs media, but drive is empty");
+        return NULL;
+    }
+
+    if (!*serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(conf->bs);
+        if (*dinfo->serial) {
+            *serial = strdup(dinfo->serial);
+        }
+    }
+
+    s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
+                                          sizeof(struct virtio_blk_config),
+                                          sizeof(VirtIOBlock));
+
+    s->vdev.get_config = virtio_blk_update_config;
+    s->vdev.get_features = virtio_blk_get_features;
+    s->vdev.reset = virtio_blk_reset;
+    s->bs = conf->bs;
+    s->conf = conf;
+    s->serial = *serial;
+    s->rq = NULL;
+    s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
+    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
+
+    s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
+
+    qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
+    s->qdev = dev;
+    register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
+                    virtio_blk_save, virtio_blk_load, s);
+    bdrv_set_removable(s->bs, 0);
+    bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
+    s->bs->buffer_alignment = conf->logical_block_size;
+
+    add_boot_device_path(conf->bootindex, dev, "/disk at 0,0");
+
+    return &s->vdev;
+}
+
+void virtio_blk_exit(VirtIODevice *vdev)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    unregister_savevm(s->qdev, "virtio-blk", s);
+}
diff --git a/qemu-0.15.x/hw/virtio-blk.h b/qemu-0.15.x/hw/virtio-blk.h
new file mode 100644
index 0000000..5645d2b
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-blk.h
@@ -0,0 +1,108 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_BLK_H
+#define _QEMU_VIRTIO_BLK_H
+
+#include "virtio.h"
+#include "block.h"
+
+/* from Linux's linux/virtio_blk.h */
+
+/* The ID for virtio_block */
+#define VIRTIO_ID_BLOCK 2
+
+/* Feature bits */
+#define VIRTIO_BLK_F_BARRIER    0       /* Does host support barriers? */
+#define VIRTIO_BLK_F_SIZE_MAX   1       /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX    2       /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY   4       /* Indicates support of legacy geometry */
+#define VIRTIO_BLK_F_RO         5       /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE   6       /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru */
+/* #define VIRTIO_BLK_F_IDENTIFY   8       ATA IDENTIFY supported, DEPRECATED */
+#define VIRTIO_BLK_F_WCACHE     9       /* write cache enabled */
+#define VIRTIO_BLK_F_TOPOLOGY   10      /* Topology information is available */
+
+#define VIRTIO_BLK_ID_BYTES     20      /* ID string length */
+
+struct virtio_blk_config
+{
+    uint64_t capacity;
+    uint32_t size_max;
+    uint32_t seg_max;
+    uint16_t cylinders;
+    uint8_t heads;
+    uint8_t sectors;
+    uint32_t blk_size;
+    uint8_t physical_block_exp;
+    uint8_t alignment_offset;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+} __attribute__((packed));
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN         0
+#define VIRTIO_BLK_T_OUT        1
+
+/* This bit says it's a scsi command, not an actual read or write. */
+#define VIRTIO_BLK_T_SCSI_CMD   2
+
+/* Flush the volatile write cache */
+#define VIRTIO_BLK_T_FLUSH      4
+
+/* return the device ID string */
+#define VIRTIO_BLK_T_GET_ID     8
+
+/* Barrier before this op. */
+#define VIRTIO_BLK_T_BARRIER    0x80000000
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr
+{
+    /* VIRTIO_BLK_T* */
+    uint32_t type;
+    /* io priority. */
+    uint32_t ioprio;
+    /* Sector (ie. 512 byte offset) */
+    uint64_t sector;
+};
+
+#define VIRTIO_BLK_S_OK         0
+#define VIRTIO_BLK_S_IOERR      1
+#define VIRTIO_BLK_S_UNSUPP     2
+
+/* This is the last element of the write scatter-gather list */
+struct virtio_blk_inhdr
+{
+    unsigned char status;
+};
+
+/* SCSI pass-through header */
+struct virtio_scsi_inhdr
+{
+    uint32_t errors;
+    uint32_t data_len;
+    uint32_t sense_len;
+    uint32_t residual;
+};
+
+#ifdef __linux__
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+        DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true)
+#else
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
+#endif
+#endif
diff --git a/qemu-0.15.x/hw/virtio-console.c b/qemu-0.15.x/hw/virtio-console.c
new file mode 100644
index 0000000..fe5e188
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-console.c
@@ -0,0 +1,168 @@
+/*
+ * Virtio Console and Generic Serial Port Devices
+ *
+ * Copyright Red Hat, Inc. 2009, 2010
+ *
+ * Authors:
+ *  Amit Shah <amit.shah at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu-char.h"
+#include "qemu-error.h"
+#include "trace.h"
+#include "virtio-serial.h"
+
+typedef struct VirtConsole {
+    VirtIOSerialPort port;
+    CharDriverState *chr;
+} VirtConsole;
+
+
+/* Callback function that's called when the guest sends us data */
+static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    ssize_t ret;
+
+    ret = qemu_chr_write(vcon->chr, buf, len);
+    trace_virtio_console_flush_buf(port->id, len, ret);
+
+    if (ret < 0) {
+        /*
+         * Ideally we'd get a better error code than just -1, but
+         * that's what the chardev interface gives us right now.  If
+         * we had a finer-grained message, like -EPIPE, we could close
+         * this connection.  Absent such error messages, the most we
+         * can do is to return 0 here.
+         *
+         * This will prevent stray -1 values to go to
+         * virtio-serial-bus.c and cause abort()s in
+         * do_flush_queued_data().
+         */
+        ret = 0;
+    }
+    return ret;
+}
+
+/* Callback function that's called when the guest opens the port */
+static void guest_open(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    qemu_chr_guest_open(vcon->chr);
+}
+
+/* Callback function that's called when the guest closes the port */
+static void guest_close(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    qemu_chr_guest_close(vcon->chr);
+}
+
+/* Readiness of the guest to accept data on a port */
+static int chr_can_read(void *opaque)
+{
+    VirtConsole *vcon = opaque;
+
+    return virtio_serial_guest_ready(&vcon->port);
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    VirtConsole *vcon = opaque;
+
+    trace_virtio_console_chr_read(vcon->port.id, size);
+    virtio_serial_write(&vcon->port, buf, size);
+}
+
+static void chr_event(void *opaque, int event)
+{
+    VirtConsole *vcon = opaque;
+
+    trace_virtio_console_chr_event(vcon->port.id, event);
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        virtio_serial_open(&vcon->port);
+        break;
+    case CHR_EVENT_CLOSED:
+        virtio_serial_close(&vcon->port);
+        break;
+    }
+}
+
+static int virtconsole_initfn(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
+                                           vcon->port.dev.info);
+
+    if (port->id == 0 && !info->is_console) {
+        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
+        return -1;
+    }
+
+    if (vcon->chr) {
+        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
+                              vcon);
+        info->have_data = flush_buf;
+        info->guest_open = guest_open;
+        info->guest_close = guest_close;
+    }
+
+    return 0;
+}
+
+static int virtconsole_exitfn(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    if (vcon->chr) {
+	/*
+	 * Instead of closing the chardev, free it so it can be used
+	 * for other purposes.
+	 */
+	qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL);
+    }
+
+    return 0;
+}
+
+static VirtIOSerialPortInfo virtconsole_info = {
+    .qdev.name     = "virtconsole",
+    .qdev.size     = sizeof(VirtConsole),
+    .is_console    = true,
+    .init          = virtconsole_initfn,
+    .exit          = virtconsole_exitfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void virtconsole_register(void)
+{
+    virtio_serial_port_qdev_register(&virtconsole_info);
+}
+device_init(virtconsole_register)
+
+static VirtIOSerialPortInfo virtserialport_info = {
+    .qdev.name     = "virtserialport",
+    .qdev.size     = sizeof(VirtConsole),
+    .init          = virtconsole_initfn,
+    .exit          = virtconsole_exitfn,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void virtserialport_register(void)
+{
+    virtio_serial_port_qdev_register(&virtserialport_info);
+}
+device_init(virtserialport_register)
diff --git a/qemu-0.15.x/hw/virtio-net.c b/qemu-0.15.x/hw/virtio-net.c
new file mode 100644
index 0000000..a32cc01
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-net.c
@@ -0,0 +1,1078 @@
+/*
+ * Virtio Network Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "iov.h"
+#include "virtio.h"
+#include "net.h"
+#include "net/checksum.h"
+#include "net/tap.h"
+#include "qemu-error.h"
+#include "qemu-timer.h"
+#include "virtio-net.h"
+#include "vhost_net.h"
+
+#define VIRTIO_NET_VM_VERSION    11
+
+#define MAC_TABLE_ENTRIES    64
+#define MAX_VLAN    (1 << 12)   /* Per 802.1Q definition */
+
+typedef struct VirtIONet
+{
+    VirtIODevice vdev;
+    uint8_t mac[ETH_ALEN];
+    uint16_t status;
+    VirtQueue *rx_vq;
+    VirtQueue *tx_vq;
+    VirtQueue *ctrl_vq;
+    NICState *nic;
+    QEMUTimer *tx_timer;
+    QEMUBH *tx_bh;
+    uint32_t tx_timeout;
+    int32_t tx_burst;
+    int tx_waiting;
+    uint32_t has_vnet_hdr;
+    uint8_t has_ufo;
+    struct {
+        VirtQueueElement elem;
+        ssize_t len;
+    } async_tx;
+    int mergeable_rx_bufs;
+    uint8_t promisc;
+    uint8_t allmulti;
+    uint8_t alluni;
+    uint8_t nomulti;
+    uint8_t nouni;
+    uint8_t nobcast;
+    uint8_t vhost_started;
+    struct {
+        int in_use;
+        int first_multi;
+        uint8_t multi_overflow;
+        uint8_t uni_overflow;
+        uint8_t *macs;
+    } mac_table;
+    uint32_t *vlans;
+    DeviceState *qdev;
+} VirtIONet;
+
+/* TODO
+ * - we could suppress RX interrupt if we were so inclined.
+ */
+
+static VirtIONet *to_virtio_net(VirtIODevice *vdev)
+{
+    return (VirtIONet *)vdev;
+}
+
+static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_config netcfg;
+
+    stw_p(&netcfg.status, n->status);
+    memcpy(netcfg.mac, n->mac, ETH_ALEN);
+    memcpy(config, &netcfg, sizeof(netcfg));
+}
+
+static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_config netcfg;
+
+    memcpy(&netcfg, config, sizeof(netcfg));
+
+    if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
+        memcpy(n->mac, netcfg.mac, ETH_ALEN);
+        qemu_format_nic_info_str(&n->nic->nc, n->mac);
+    }
+}
+
+static bool virtio_net_started(VirtIONet *n, uint8_t status)
+{
+    return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+        (n->status & VIRTIO_NET_S_LINK_UP) && n->vdev.vm_running;
+}
+
+static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
+{
+    if (!n->nic->nc.peer) {
+        return;
+    }
+    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+        return;
+    }
+
+    if (!tap_get_vhost_net(n->nic->nc.peer)) {
+        return;
+    }
+    if (!!n->vhost_started == virtio_net_started(n, status) &&
+                              !n->nic->nc.peer->link_down) {
+        return;
+    }
+    if (!n->vhost_started) {
+        int r;
+        if (!vhost_net_query(tap_get_vhost_net(n->nic->nc.peer), &n->vdev)) {
+            return;
+        }
+        r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        if (r < 0) {
+            error_report("unable to start vhost net: %d: "
+                         "falling back on userspace virtio", -r);
+        } else {
+            n->vhost_started = 1;
+        }
+    } else {
+        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        n->vhost_started = 0;
+    }
+}
+
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    virtio_net_vhost_status(n, status);
+
+    if (!n->tx_waiting) {
+        return;
+    }
+
+    if (virtio_net_started(n, status) && !n->vhost_started) {
+        if (n->tx_timer) {
+            qemu_mod_timer(n->tx_timer,
+                           qemu_get_clock_ns(vm_clock) + n->tx_timeout);
+        } else {
+            qemu_bh_schedule(n->tx_bh);
+        }
+    } else {
+        if (n->tx_timer) {
+            qemu_del_timer(n->tx_timer);
+        } else {
+            qemu_bh_cancel(n->tx_bh);
+        }
+    }
+}
+
+static void virtio_net_set_link_status(VLANClientState *nc)
+{
+    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+    uint16_t old_status = n->status;
+
+    if (nc->link_down)
+        n->status &= ~VIRTIO_NET_S_LINK_UP;
+    else
+        n->status |= VIRTIO_NET_S_LINK_UP;
+
+    if (n->status != old_status)
+        virtio_notify_config(&n->vdev);
+
+    virtio_net_set_status(&n->vdev, n->vdev.status);
+}
+
+static void virtio_net_reset(VirtIODevice *vdev)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    /* Reset back to compatibility mode */
+    n->promisc = 1;
+    n->allmulti = 0;
+    n->alluni = 0;
+    n->nomulti = 0;
+    n->nouni = 0;
+    n->nobcast = 0;
+
+    /* Flush any MAC and VLAN filter table state */
+    n->mac_table.in_use = 0;
+    n->mac_table.first_multi = 0;
+    n->mac_table.multi_overflow = 0;
+    n->mac_table.uni_overflow = 0;
+    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+    memset(n->vlans, 0, MAX_VLAN >> 3);
+}
+
+static int peer_has_vnet_hdr(VirtIONet *n)
+{
+    if (!n->nic->nc.peer)
+        return 0;
+
+    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP)
+        return 0;
+
+    n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer);
+
+    return n->has_vnet_hdr;
+}
+
+static int peer_has_ufo(VirtIONet *n)
+{
+    if (!peer_has_vnet_hdr(n))
+        return 0;
+
+    n->has_ufo = tap_has_ufo(n->nic->nc.peer);
+
+    return n->has_ufo;
+}
+
+static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    features |= (1 << VIRTIO_NET_F_MAC);
+
+    if (peer_has_vnet_hdr(n)) {
+        tap_using_vnet_hdr(n->nic->nc.peer, 1);
+    } else {
+        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
+
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
+    }
+
+    if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
+    }
+
+    if (!n->nic->nc.peer ||
+        n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+        return features;
+    }
+    if (!tap_get_vhost_net(n->nic->nc.peer)) {
+        return features;
+    }
+    return vhost_net_get_features(tap_get_vhost_net(n->nic->nc.peer), features);
+}
+
+static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
+{
+    uint32_t features = 0;
+
+    /* Linux kernel 2.6.25.  It understood MAC (as everyone must),
+     * but also these: */
+    features |= (1 << VIRTIO_NET_F_MAC);
+    features |= (1 << VIRTIO_NET_F_CSUM);
+    features |= (1 << VIRTIO_NET_F_HOST_TSO4);
+    features |= (1 << VIRTIO_NET_F_HOST_TSO6);
+    features |= (1 << VIRTIO_NET_F_HOST_ECN);
+
+    return features;
+}
+
+static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
+
+    if (n->has_vnet_hdr) {
+        tap_set_offload(n->nic->nc.peer,
+                        (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                        (features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
+    }
+    if (!n->nic->nc.peer ||
+        n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+        return;
+    }
+    if (!tap_get_vhost_net(n->nic->nc.peer)) {
+        return;
+    }
+    vhost_net_ack_features(tap_get_vhost_net(n->nic->nc.peer), features);
+}
+
+static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
+                                     VirtQueueElement *elem)
+{
+    uint8_t on;
+
+    if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
+        error_report("virtio-net ctrl invalid rx mode command");
+        exit(1);
+    }
+
+    on = ldub_p(elem->out_sg[1].iov_base);
+
+    if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC)
+        n->promisc = on;
+    else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI)
+        n->allmulti = on;
+    else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI)
+        n->alluni = on;
+    else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI)
+        n->nomulti = on;
+    else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI)
+        n->nouni = on;
+    else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST)
+        n->nobcast = on;
+    else
+        return VIRTIO_NET_ERR;
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
+                                 VirtQueueElement *elem)
+{
+    struct virtio_net_ctrl_mac mac_data;
+
+    if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||
+        elem->out_sg[1].iov_len < sizeof(mac_data) ||
+        elem->out_sg[2].iov_len < sizeof(mac_data))
+        return VIRTIO_NET_ERR;
+
+    n->mac_table.in_use = 0;
+    n->mac_table.first_multi = 0;
+    n->mac_table.uni_overflow = 0;
+    n->mac_table.multi_overflow = 0;
+    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+
+    mac_data.entries = ldl_p(elem->out_sg[1].iov_base);
+
+    if (sizeof(mac_data.entries) +
+        (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
+        return VIRTIO_NET_ERR;
+
+    if (mac_data.entries <= MAC_TABLE_ENTRIES) {
+        memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),
+               mac_data.entries * ETH_ALEN);
+        n->mac_table.in_use += mac_data.entries;
+    } else {
+        n->mac_table.uni_overflow = 1;
+    }
+
+    n->mac_table.first_multi = n->mac_table.in_use;
+
+    mac_data.entries = ldl_p(elem->out_sg[2].iov_base);
+
+    if (sizeof(mac_data.entries) +
+        (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
+        return VIRTIO_NET_ERR;
+
+    if (mac_data.entries) {
+        if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
+            memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
+                   elem->out_sg[2].iov_base + sizeof(mac_data),
+                   mac_data.entries * ETH_ALEN);
+            n->mac_table.in_use += mac_data.entries;
+        } else {
+            n->mac_table.multi_overflow = 1;
+        }
+    }
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
+                                        VirtQueueElement *elem)
+{
+    uint16_t vid;
+
+    if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) {
+        error_report("virtio-net ctrl invalid vlan command");
+        return VIRTIO_NET_ERR;
+    }
+
+    vid = lduw_p(elem->out_sg[1].iov_base);
+
+    if (vid >= MAX_VLAN)
+        return VIRTIO_NET_ERR;
+
+    if (cmd == VIRTIO_NET_CTRL_VLAN_ADD)
+        n->vlans[vid >> 5] |= (1U << (vid & 0x1f));
+    else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL)
+        n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f));
+    else
+        return VIRTIO_NET_ERR;
+
+    return VIRTIO_NET_OK;
+}
+
+static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_ctrl_hdr ctrl;
+    virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
+    VirtQueueElement elem;
+
+    while (virtqueue_pop(vq, &elem)) {
+        if ((elem.in_num < 1) || (elem.out_num < 1)) {
+            error_report("virtio-net ctrl missing headers");
+            exit(1);
+        }
+
+        if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
+            elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) {
+            error_report("virtio-net ctrl header not in correct element");
+            exit(1);
+        }
+
+        ctrl.class = ldub_p(elem.out_sg[0].iov_base);
+        ctrl.cmd = ldub_p(elem.out_sg[0].iov_base + sizeof(ctrl.class));
+
+        if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE)
+            status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem);
+        else if (ctrl.class == VIRTIO_NET_CTRL_MAC)
+            status = virtio_net_handle_mac(n, ctrl.cmd, &elem);
+        else if (ctrl.class == VIRTIO_NET_CTRL_VLAN)
+            status = virtio_net_handle_vlan_table(n, ctrl.cmd, &elem);
+
+        stb_p(elem.in_sg[elem.in_num - 1].iov_base, status);
+
+        virtqueue_push(vq, &elem, sizeof(status));
+        virtio_notify(vdev, vq);
+    }
+}
+
+/* RX */
+
+static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    qemu_flush_queued_packets(&n->nic->nc);
+
+    /* We now have RX buffers, signal to the IO thread to break out of the
+     * select to re-poll the tap file descriptor */
+    qemu_notify_event();
+}
+
+static int virtio_net_can_receive(VLANClientState *nc)
+{
+    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+    if (!n->vdev.vm_running) {
+        return 0;
+    }
+
+    if (!virtio_queue_ready(n->rx_vq) ||
+        !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
+        return 0;
+
+    return 1;
+}
+
+static int virtio_net_has_buffers(VirtIONet *n, int bufsize)
+{
+    if (virtio_queue_empty(n->rx_vq) ||
+        (n->mergeable_rx_bufs &&
+         !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
+        virtio_queue_set_notification(n->rx_vq, 1);
+
+        /* To avoid a race condition where the guest has made some buffers
+         * available after the above check but before notification was
+         * enabled, check for available buffers again.
+         */
+        if (virtio_queue_empty(n->rx_vq) ||
+            (n->mergeable_rx_bufs &&
+             !virtqueue_avail_bytes(n->rx_vq, bufsize, 0)))
+            return 0;
+    }
+
+    virtio_queue_set_notification(n->rx_vq, 0);
+    return 1;
+}
+
+/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
+ * it never finds out that the packets don't have valid checksums.  This
+ * causes dhclient to get upset.  Fedora's carried a patch for ages to
+ * fix this with Xen but it hasn't appeared in an upstream release of
+ * dhclient yet.
+ *
+ * To avoid breaking existing guests, we catch udp packets and add
+ * checksums.  This is terrible but it's better than hacking the guest
+ * kernels.
+ *
+ * N.B. if we introduce a zero-copy API, this operation is no longer free so
+ * we should provide a mechanism to disable it to avoid polluting the host
+ * cache.
+ */
+static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
+                                        const uint8_t *buf, size_t size)
+{
+    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
+        (size > 27 && size < 1500) && /* normal sized MTU */
+        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
+        (buf[23] == 17) && /* ip.protocol == UDP */
+        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
+        /* FIXME this cast is evil */
+        net_checksum_calculate((uint8_t *)buf, size);
+        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
+    }
+}
+
+static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
+                          const void *buf, size_t size, size_t hdr_len)
+{
+    struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
+    int offset = 0;
+
+    hdr->flags = 0;
+    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+    if (n->has_vnet_hdr) {
+        memcpy(hdr, buf, sizeof(*hdr));
+        offset = sizeof(*hdr);
+        work_around_broken_dhclient(hdr, buf + offset, size - offset);
+    }
+
+    /* We only ever receive a struct virtio_net_hdr from the tapfd,
+     * but we may be passing along a larger header to the guest.
+     */
+    iov[0].iov_base += hdr_len;
+    iov[0].iov_len  -= hdr_len;
+
+    return offset;
+}
+
+static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    static const uint8_t vlan[] = {0x81, 0x00};
+    uint8_t *ptr = (uint8_t *)buf;
+    int i;
+
+    if (n->promisc)
+        return 1;
+
+    if (n->has_vnet_hdr) {
+        ptr += sizeof(struct virtio_net_hdr);
+    }
+
+    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
+        int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
+        if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
+            return 0;
+    }
+
+    if (ptr[0] & 1) { // multicast
+        if (!memcmp(ptr, bcast, sizeof(bcast))) {
+            return !n->nobcast;
+        } else if (n->nomulti) {
+            return 0;
+        } else if (n->allmulti || n->mac_table.multi_overflow) {
+            return 1;
+        }
+
+        for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
+            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
+                return 1;
+            }
+        }
+    } else { // unicast
+        if (n->nouni) {
+            return 0;
+        } else if (n->alluni || n->mac_table.uni_overflow) {
+            return 1;
+        } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
+            return 1;
+        }
+
+        for (i = 0; i < n->mac_table.first_multi; i++) {
+            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+    struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
+    size_t guest_hdr_len, offset, i, host_hdr_len;
+
+    if (!virtio_net_can_receive(&n->nic->nc))
+        return -1;
+
+    /* hdr_len refers to the header we supply to the guest */
+    guest_hdr_len = n->mergeable_rx_bufs ?
+        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
+
+
+    host_hdr_len = n->has_vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
+    if (!virtio_net_has_buffers(n, size + guest_hdr_len - host_hdr_len))
+        return 0;
+
+    if (!receive_filter(n, buf, size))
+        return size;
+
+    offset = i = 0;
+
+    while (offset < size) {
+        VirtQueueElement elem;
+        int len, total;
+        struct iovec sg[VIRTQUEUE_MAX_SIZE];
+
+        total = 0;
+
+        if (virtqueue_pop(n->rx_vq, &elem) == 0) {
+            if (i == 0)
+                return -1;
+            error_report("virtio-net unexpected empty queue: "
+                    "i %zd mergeable %d offset %zd, size %zd, "
+                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
+                    i, n->mergeable_rx_bufs, offset, size,
+                    guest_hdr_len, host_hdr_len, n->vdev.guest_features);
+            exit(1);
+        }
+
+        if (elem.in_num < 1) {
+            error_report("virtio-net receive queue contains no in buffers");
+            exit(1);
+        }
+
+        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
+            error_report("virtio-net header not in first element");
+            exit(1);
+        }
+
+        memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);
+
+        if (i == 0) {
+            if (n->mergeable_rx_bufs)
+                mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
+
+            offset += receive_header(n, sg, elem.in_num,
+                                     buf + offset, size - offset, guest_hdr_len);
+            total += guest_hdr_len;
+        }
+
+        /* copy in packet.  ugh */
+        len = iov_from_buf(sg, elem.in_num,
+                           buf + offset, 0, size - offset);
+        total += len;
+        offset += len;
+        /* If buffers can't be merged, at this point we
+         * must have consumed the complete packet.
+         * Otherwise, drop it. */
+        if (!n->mergeable_rx_bufs && offset < size) {
+#if 0
+            error_report("virtio-net truncated non-mergeable packet: "
+                         "i %zd mergeable %d offset %zd, size %zd, "
+                         "guest hdr len %zd, host hdr len %zd",
+                         i, n->mergeable_rx_bufs,
+                         offset, size, guest_hdr_len, host_hdr_len);
+#endif
+            return size;
+        }
+
+        /* signal other side */
+        virtqueue_fill(n->rx_vq, &elem, total, i++);
+    }
+
+    if (mhdr) {
+        stw_p(&mhdr->num_buffers, i);
+    }
+
+    virtqueue_flush(n->rx_vq, i);
+    virtio_notify(&n->vdev, n->rx_vq);
+
+    return size;
+}
+
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
+
+static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len)
+{
+    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    virtqueue_push(n->tx_vq, &n->async_tx.elem, n->async_tx.len);
+    virtio_notify(&n->vdev, n->tx_vq);
+
+    n->async_tx.elem.out_num = n->async_tx.len = 0;
+
+    virtio_queue_set_notification(n->tx_vq, 1);
+    virtio_net_flush_tx(n, n->tx_vq);
+}
+
+/* TX */
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
+{
+    VirtQueueElement elem;
+    int32_t num_packets = 0;
+    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return num_packets;
+    }
+
+    assert(n->vdev.vm_running);
+
+    if (n->async_tx.elem.out_num) {
+        virtio_queue_set_notification(n->tx_vq, 0);
+        return num_packets;
+    }
+
+    while (virtqueue_pop(vq, &elem)) {
+        ssize_t ret, len = 0;
+        unsigned int out_num = elem.out_num;
+        struct iovec *out_sg = &elem.out_sg[0];
+        unsigned hdr_len;
+
+        /* hdr_len refers to the header received from the guest */
+        hdr_len = n->mergeable_rx_bufs ?
+            sizeof(struct virtio_net_hdr_mrg_rxbuf) :
+            sizeof(struct virtio_net_hdr);
+
+        if (out_num < 1 || out_sg->iov_len != hdr_len) {
+            error_report("virtio-net header not in first element");
+            exit(1);
+        }
+
+        /* ignore the header if GSO is not supported */
+        if (!n->has_vnet_hdr) {
+            out_num--;
+            out_sg++;
+            len += hdr_len;
+        } else if (n->mergeable_rx_bufs) {
+            /* tapfd expects a struct virtio_net_hdr */
+            hdr_len -= sizeof(struct virtio_net_hdr);
+            out_sg->iov_len -= hdr_len;
+            len += hdr_len;
+        }
+
+        ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num,
+                                      virtio_net_tx_complete);
+        if (ret == 0) {
+            virtio_queue_set_notification(n->tx_vq, 0);
+            n->async_tx.elem = elem;
+            n->async_tx.len  = len;
+            return -EBUSY;
+        }
+
+        len += ret;
+
+        virtqueue_push(vq, &elem, len);
+        virtio_notify(&n->vdev, vq);
+
+        if (++num_packets >= n->tx_burst) {
+            break;
+        }
+    }
+    return num_packets;
+}
+
+static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vdev.vm_running) {
+        n->tx_waiting = 1;
+        return;
+    }
+
+    if (n->tx_waiting) {
+        virtio_queue_set_notification(vq, 1);
+        qemu_del_timer(n->tx_timer);
+        n->tx_waiting = 0;
+        virtio_net_flush_tx(n, vq);
+    } else {
+        qemu_mod_timer(n->tx_timer,
+                       qemu_get_clock_ns(vm_clock) + n->tx_timeout);
+        n->tx_waiting = 1;
+        virtio_queue_set_notification(vq, 0);
+    }
+}
+
+static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    if (unlikely(n->tx_waiting)) {
+        return;
+    }
+    n->tx_waiting = 1;
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vdev.vm_running) {
+        return;
+    }
+    virtio_queue_set_notification(vq, 0);
+    qemu_bh_schedule(n->tx_bh);
+}
+
+static void virtio_net_tx_timer(void *opaque)
+{
+    VirtIONet *n = opaque;
+    assert(n->vdev.vm_running);
+
+    n->tx_waiting = 0;
+
+    /* Just in case the driver is not ready on more */
+    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
+        return;
+
+    virtio_queue_set_notification(n->tx_vq, 1);
+    virtio_net_flush_tx(n, n->tx_vq);
+}
+
+static void virtio_net_tx_bh(void *opaque)
+{
+    VirtIONet *n = opaque;
+    int32_t ret;
+
+    assert(n->vdev.vm_running);
+
+    n->tx_waiting = 0;
+
+    /* Just in case the driver is not ready on more */
+    if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)))
+        return;
+
+    ret = virtio_net_flush_tx(n, n->tx_vq);
+    if (ret == -EBUSY) {
+        return; /* Notification re-enable handled by tx_complete */
+    }
+
+    /* If we flush a full burst of packets, assume there are
+     * more coming and immediately reschedule */
+    if (ret >= n->tx_burst) {
+        qemu_bh_schedule(n->tx_bh);
+        n->tx_waiting = 1;
+        return;
+    }
+
+    /* If less than a full burst, re-enable notification and flush
+     * anything that may have come in while we weren't looking.  If
+     * we find something, assume the guest is still active and reschedule */
+    virtio_queue_set_notification(n->tx_vq, 1);
+    if (virtio_net_flush_tx(n, n->tx_vq) > 0) {
+        virtio_queue_set_notification(n->tx_vq, 0);
+        qemu_bh_schedule(n->tx_bh);
+        n->tx_waiting = 1;
+    }
+}
+
+static void virtio_net_save(QEMUFile *f, void *opaque)
+{
+    VirtIONet *n = opaque;
+
+    /* At this point, backend must be stopped, otherwise
+     * it might keep writing to memory. */
+    assert(!n->vhost_started);
+    virtio_save(&n->vdev, f);
+
+    qemu_put_buffer(f, n->mac, ETH_ALEN);
+    qemu_put_be32(f, n->tx_waiting);
+    qemu_put_be32(f, n->mergeable_rx_bufs);
+    qemu_put_be16(f, n->status);
+    qemu_put_byte(f, n->promisc);
+    qemu_put_byte(f, n->allmulti);
+    qemu_put_be32(f, n->mac_table.in_use);
+    qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
+    qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
+    qemu_put_be32(f, n->has_vnet_hdr);
+    qemu_put_byte(f, n->mac_table.multi_overflow);
+    qemu_put_byte(f, n->mac_table.uni_overflow);
+    qemu_put_byte(f, n->alluni);
+    qemu_put_byte(f, n->nomulti);
+    qemu_put_byte(f, n->nouni);
+    qemu_put_byte(f, n->nobcast);
+    qemu_put_byte(f, n->has_ufo);
+}
+
+static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIONet *n = opaque;
+    int i;
+
+    if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
+        return -EINVAL;
+
+    virtio_load(&n->vdev, f);
+
+    qemu_get_buffer(f, n->mac, ETH_ALEN);
+    n->tx_waiting = qemu_get_be32(f);
+    n->mergeable_rx_bufs = qemu_get_be32(f);
+
+    if (version_id >= 3)
+        n->status = qemu_get_be16(f);
+
+    if (version_id >= 4) {
+        if (version_id < 8) {
+            n->promisc = qemu_get_be32(f);
+            n->allmulti = qemu_get_be32(f);
+        } else {
+            n->promisc = qemu_get_byte(f);
+            n->allmulti = qemu_get_byte(f);
+        }
+    }
+
+    if (version_id >= 5) {
+        n->mac_table.in_use = qemu_get_be32(f);
+        /* MAC_TABLE_ENTRIES may be different from the saved image */
+        if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
+            qemu_get_buffer(f, n->mac_table.macs,
+                            n->mac_table.in_use * ETH_ALEN);
+        } else if (n->mac_table.in_use) {
+            qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
+            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
+            n->mac_table.in_use = 0;
+        }
+    }
+ 
+    if (version_id >= 6)
+        qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
+
+    if (version_id >= 7) {
+        if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
+            error_report("virtio-net: saved image requires vnet_hdr=on");
+            return -1;
+        }
+
+        if (n->has_vnet_hdr) {
+            tap_using_vnet_hdr(n->nic->nc.peer, 1);
+            tap_set_offload(n->nic->nc.peer,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
+        }
+    }
+
+    if (version_id >= 9) {
+        n->mac_table.multi_overflow = qemu_get_byte(f);
+        n->mac_table.uni_overflow = qemu_get_byte(f);
+    }
+
+    if (version_id >= 10) {
+        n->alluni = qemu_get_byte(f);
+        n->nomulti = qemu_get_byte(f);
+        n->nouni = qemu_get_byte(f);
+        n->nobcast = qemu_get_byte(f);
+    }
+
+    if (version_id >= 11) {
+        if (qemu_get_byte(f) && !peer_has_ufo(n)) {
+            error_report("virtio-net: saved image requires TUN_F_UFO support");
+            return -1;
+        }
+    }
+
+    /* Find the first multicast entry in the saved MAC filter */
+    for (i = 0; i < n->mac_table.in_use; i++) {
+        if (n->mac_table.macs[i * ETH_ALEN] & 1) {
+            break;
+        }
+    }
+    n->mac_table.first_multi = i;
+    return 0;
+}
+
+static void virtio_net_cleanup(VLANClientState *nc)
+{
+    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    n->nic = NULL;
+}
+
+static NetClientInfo net_virtio_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = virtio_net_can_receive,
+    .receive = virtio_net_receive,
+        .cleanup = virtio_net_cleanup,
+    .link_status_changed = virtio_net_set_link_status,
+};
+
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              virtio_net_conf *net)
+{
+    VirtIONet *n;
+
+    n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
+                                        sizeof(struct virtio_net_config),
+                                        sizeof(VirtIONet));
+
+    n->vdev.get_config = virtio_net_get_config;
+    n->vdev.set_config = virtio_net_set_config;
+    n->vdev.get_features = virtio_net_get_features;
+    n->vdev.set_features = virtio_net_set_features;
+    n->vdev.bad_features = virtio_net_bad_features;
+    n->vdev.reset = virtio_net_reset;
+    n->vdev.set_status = virtio_net_set_status;
+    n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
+
+    if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
+        error_report("virtio-net: "
+                     "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
+                     net->tx);
+        error_report("Defaulting to \"bh\"");
+    }
+
+    if (net->tx && !strcmp(net->tx, "timer")) {
+        n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_timer);
+        n->tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, n);
+        n->tx_timeout = net->txtimer;
+    } else {
+        n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh);
+        n->tx_bh = qemu_bh_new(virtio_net_tx_bh, n);
+    }
+    n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
+    qemu_macaddr_default_if_unset(&conf->macaddr);
+    memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
+    n->status = VIRTIO_NET_S_LINK_UP;
+
+    n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n);
+
+    qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
+
+    n->tx_waiting = 0;
+    n->tx_burst = net->txburst;
+    n->mergeable_rx_bufs = 0;
+    n->promisc = 1; /* for compatibility */
+
+    n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
+
+    n->vlans = qemu_mallocz(MAX_VLAN >> 3);
+
+    n->qdev = dev;
+    register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
+                    virtio_net_save, virtio_net_load, n);
+
+    add_boot_device_path(conf->bootindex, dev, "/ethernet-phy at 0");
+
+    return &n->vdev;
+}
+
+void virtio_net_exit(VirtIODevice *vdev)
+{
+    VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
+
+    /* This will stop vhost backend if appropriate. */
+    virtio_net_set_status(vdev, 0);
+
+    qemu_purge_queued_packets(&n->nic->nc);
+
+    unregister_savevm(n->qdev, "virtio-net", n);
+
+    qemu_free(n->mac_table.macs);
+    qemu_free(n->vlans);
+
+    if (n->tx_timer) {
+        qemu_del_timer(n->tx_timer);
+        qemu_free_timer(n->tx_timer);
+    } else {
+        qemu_bh_delete(n->tx_bh);
+    }
+
+    virtio_cleanup(&n->vdev);
+    qemu_del_vlan_client(&n->nic->nc);
+}
diff --git a/qemu-0.15.x/hw/virtio-net.h b/qemu-0.15.x/hw/virtio-net.h
new file mode 100644
index 0000000..8af9a1c
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-net.h
@@ -0,0 +1,189 @@
+/*
+ * Virtio Network Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_NET_H
+#define _QEMU_VIRTIO_NET_H
+
+#include "virtio.h"
+#include "net.h"
+#include "pci.h"
+
+#define ETH_ALEN    6
+
+/* from Linux's virtio_net.h */
+
+/* The ID for virtio_net */
+#define VIRTIO_ID_NET   1
+
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
+#define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
+#define VIRTIO_NET_F_STATUS     16      /* virtio_net_config.status available */
+#define VIRTIO_NET_F_CTRL_VQ    17      /* Control channel available */
+#define VIRTIO_NET_F_CTRL_RX    18      /* Control channel RX mode support */
+#define VIRTIO_NET_F_CTRL_VLAN  19      /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 20   /* Extra RX mode control support */
+
+#define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
+
+#define TX_TIMER_INTERVAL 150000 /* 150 us */
+
+/* Limit the number of packets that can be sent via a single flush
+ * of the TX queue.  This gives us a guaranteed exit condition and
+ * ensures fairness in the io path.  256 conveniently matches the
+ * length of the TX queue and shows a good balance of performance
+ * and latency. */
+#define TX_BURST 256
+
+typedef struct virtio_net_conf
+{
+    uint32_t txtimer;
+    int32_t txburst;
+    char *tx;
+} virtio_net_conf;
+
+/* Maximum packet size we can receive from tap device: header + 64k */
+#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
+
+struct virtio_net_config
+{
+    /* The config defining mac address ($ETH_ALEN bytes) */
+    uint8_t mac[ETH_ALEN];
+    /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
+    uint16_t status;
+} __attribute__((packed));
+
+/* This is the first element of the scatter-gather list.  If you don't
+ * specify GSO or CSUM features, you can simply ignore the header. */
+struct virtio_net_hdr
+{
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM     1       // Use csum_start, csum_offset
+    uint8_t flags;
+#define VIRTIO_NET_HDR_GSO_NONE         0       // Not a GSO frame
+#define VIRTIO_NET_HDR_GSO_TCPV4        1       // GSO frame, IPv4 TCP (TSO)
+#define VIRTIO_NET_HDR_GSO_UDP          3       // GSO frame, IPv4 UDP (UFO)
+#define VIRTIO_NET_HDR_GSO_TCPV6        4       // GSO frame, IPv6 TCP
+#define VIRTIO_NET_HDR_GSO_ECN          0x80    // TCP has ECN set
+    uint8_t gso_type;
+    uint16_t hdr_len;
+    uint16_t gso_size;
+    uint16_t csum_start;
+    uint16_t csum_offset;
+};
+
+/* This is the version of the header to use when the MRG_RXBUF
+ * feature has been negotiated. */
+struct virtio_net_hdr_mrg_rxbuf
+{
+    struct virtio_net_hdr hdr;
+    uint16_t num_buffers;   /* Number of merged rx buffers */
+};
+
+/*
+ * Control virtqueue data structures
+ *
+ * The control virtqueue expects a header in the first sg entry
+ * and an ack/status response in the last entry.  Data for the
+ * command goes in between.
+ */
+struct virtio_net_ctrl_hdr {
+    uint8_t class;
+    uint8_t cmd;
+};
+
+typedef uint8_t virtio_net_ctrl_ack;
+
+#define VIRTIO_NET_OK     0
+#define VIRTIO_NET_ERR    1
+
+/*
+ * Control the RX mode, ie. promisucous, allmulti, etc...
+ * All commands require an "out" sg entry containing a 1 byte
+ * state value, zero = disable, non-zero = enable.  Commands
+ * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
+ */
+#define VIRTIO_NET_CTRL_RX_MODE    0
+ #define VIRTIO_NET_CTRL_RX_MODE_PROMISC      0
+ #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI     1
+ #define VIRTIO_NET_CTRL_RX_MODE_ALLUNI       2
+ #define VIRTIO_NET_CTRL_RX_MODE_NOMULTI      3
+ #define VIRTIO_NET_CTRL_RX_MODE_NOUNI        4
+ #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST      5
+
+/*
+ * Control the MAC filter table.
+ *
+ * The MAC filter table is managed by the hypervisor, the guest should
+ * assume the size is infinite.  Filtering should be considered
+ * non-perfect, ie. based on hypervisor resources, the guest may
+ * received packets from sources not specified in the filter list.
+ *
+ * In addition to the class/cmd header, the TABLE_SET command requires
+ * two out scatterlists.  Each contains a 4 byte count of entries followed
+ * by a concatenated byte stream of the ETH_ALEN MAC addresses.  The
+ * first sg list contains unicast addresses, the second is for multicast.
+ * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
+ * is available.
+ */
+struct virtio_net_ctrl_mac {
+    uint32_t entries;
+    uint8_t macs[][ETH_ALEN];
+};
+#define VIRTIO_NET_CTRL_MAC    1
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+
+/*
+ * Control VLAN filtering
+ *
+ * The VLAN filter table is controlled via a simple ADD/DEL interface.
+ * VLAN IDs not added may be filterd by the hypervisor.  Del is the
+ * opposite of add.  Both commands expect an out entry containing a 2
+ * byte VLAN ID.  VLAN filterting is available with the
+ * VIRTIO_NET_F_CTRL_VLAN feature bit.
+ */
+#define VIRTIO_NET_CTRL_VLAN       2
+ #define VIRTIO_NET_CTRL_VLAN_ADD             0
+ #define VIRTIO_NET_CTRL_VLAN_DEL             1
+
+#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+        DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
+        DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
+        DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
+        DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
+        DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
+        DEFINE_PROP_BIT("guest_ecn", _state, _field, VIRTIO_NET_F_GUEST_ECN, true), \
+        DEFINE_PROP_BIT("guest_ufo", _state, _field, VIRTIO_NET_F_GUEST_UFO, true), \
+        DEFINE_PROP_BIT("host_tso4", _state, _field, VIRTIO_NET_F_HOST_TSO4, true), \
+        DEFINE_PROP_BIT("host_tso6", _state, _field, VIRTIO_NET_F_HOST_TSO6, true), \
+        DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN, true), \
+        DEFINE_PROP_BIT("host_ufo", _state, _field, VIRTIO_NET_F_HOST_UFO, true), \
+        DEFINE_PROP_BIT("mrg_rxbuf", _state, _field, VIRTIO_NET_F_MRG_RXBUF, true), \
+        DEFINE_PROP_BIT("status", _state, _field, VIRTIO_NET_F_STATUS, true), \
+        DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
+        DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
+        DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
+        DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true)
+#endif
diff --git a/qemu-0.15.x/hw/virtio-pci.c b/qemu-0.15.x/hw/virtio-pci.c
new file mode 100644
index 0000000..316bf92
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-pci.c
@@ -0,0 +1,901 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Paul Brook        <paul at codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <inttypes.h>
+
+#include "virtio.h"
+#include "virtio-blk.h"
+#include "virtio-net.h"
+#include "virtio-serial.h"
+#include "pci.h"
+#include "qemu-error.h"
+#include "msix.h"
+#include "net.h"
+#include "loader.h"
+#include "kvm.h"
+#include "blockdev.h"
+#include "virtio-pci.h"
+
+/* from Linux's linux/virtio_pci.h */
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES        0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES       4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN            8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM            12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL            14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY         16
+
+/* An 8-bit device status register.  */
+#define VIRTIO_PCI_STATUS               18
+
+/* An 8-bit r/o interrupt status register.  Reading the value will return the
+ * current contents of the ISR and will also clear it.  This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR                  19
+
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR        20
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR         22
+
+/* Config space size */
+#define VIRTIO_PCI_CONFIG_NOMSI         20
+#define VIRTIO_PCI_CONFIG_MSI           24
+#define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
+
+/* How many bits to shift physical queue address written to QUEUE_PFN.
+ * 12 is historical, and due to x86 page size. */
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
+
+/* Flags track per-device state like workarounds for quirks in older guests. */
+#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
+
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
+
+/* QEMU doesn't strictly need write barriers since everything runs in
+ * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
+ * KVM or if kqemu gets SMP support.
+ */
+#define wmb() do { } while (0)
+
+/* virtio device */
+
+static void virtio_pci_notify(void *opaque, uint16_t vector)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    if (msix_enabled(&proxy->pci_dev))
+        msix_notify(&proxy->pci_dev, vector);
+    else
+        qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
+}
+
+static void virtio_pci_save_config(void * opaque, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    pci_device_save(&proxy->pci_dev, f);
+    msix_save(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, proxy->vdev->config_vector);
+}
+
+static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
+}
+
+static int virtio_pci_load_config(void * opaque, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    int ret;
+    ret = pci_device_load(&proxy->pci_dev, f);
+    if (ret) {
+        return ret;
+    }
+    msix_load(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &proxy->vdev->config_vector);
+    } else {
+        proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
+    }
+    if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
+    }
+    return 0;
+}
+
+static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint16_t vector;
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &vector);
+    } else {
+        vector = VIRTIO_NO_VECTOR;
+    }
+    virtio_queue_set_vector(proxy->vdev, n, vector);
+    if (vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, vector);
+    }
+    return 0;
+}
+
+static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
+                                                 int n, bool assign)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+    int r;
+    if (assign) {
+        r = event_notifier_init(notifier, 1);
+        if (r < 0) {
+            error_report("%s: unable to init event notifier: %d",
+                         __func__, r);
+            return r;
+        }
+        r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
+                                       proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
+                                       n, assign);
+        if (r < 0) {
+            error_report("%s: unable to map ioeventfd: %d",
+                         __func__, r);
+            event_notifier_cleanup(notifier);
+        }
+    } else {
+        r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
+                                       proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
+                                       n, assign);
+        if (r < 0) {
+            error_report("%s: unable to unmap ioeventfd: %d",
+                         __func__, r);
+            return r;
+        }
+
+        /* Handle the race condition where the guest kicked and we deassigned
+         * before we got around to handling the kick.
+         */
+        if (event_notifier_test_and_clear(notifier)) {
+            virtio_queue_notify_vq(vq);
+        }
+
+        event_notifier_cleanup(notifier);
+    }
+    return r;
+}
+
+static void virtio_pci_host_notifier_read(void *opaque)
+{
+    VirtQueue *vq = opaque;
+    EventNotifier *n = virtio_queue_get_host_notifier(vq);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_queue_notify_vq(vq);
+    }
+}
+
+static void virtio_pci_set_host_notifier_fd_handler(VirtIOPCIProxy *proxy,
+                                                    int n, bool assign)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+    if (assign) {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            virtio_pci_host_notifier_read, NULL, vq);
+    } else {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            NULL, NULL, NULL);
+    }
+}
+
+static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
+{
+    int n, r;
+
+    if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
+        proxy->ioeventfd_disabled ||
+        proxy->ioeventfd_started) {
+        return;
+    }
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        r = virtio_pci_set_host_notifier_internal(proxy, n, true);
+        if (r < 0) {
+            goto assign_error;
+        }
+
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, true);
+    }
+    proxy->ioeventfd_started = true;
+    return;
+
+assign_error:
+    while (--n >= 0) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
+    error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+}
+
+static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
+{
+    int r;
+    int n;
+
+    if (!proxy->ioeventfd_started) {
+        return;
+    }
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
+}
+
+static void virtio_pci_reset(DeviceState *d)
+{
+    VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_reset(proxy->vdev);
+    msix_reset(&proxy->pci_dev);
+    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+}
+
+static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    target_phys_addr_t pa;
+
+    switch (addr) {
+    case VIRTIO_PCI_GUEST_FEATURES:
+	/* Guest does not negotiate properly?  We have to assume nothing. */
+	if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
+	    if (vdev->bad_features)
+		val = proxy->host_features & vdev->bad_features(vdev);
+	    else
+		val = 0;
+	}
+        if (vdev->set_features)
+            vdev->set_features(vdev, val);
+        vdev->guest_features = val;
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        if (pa == 0) {
+            virtio_pci_stop_ioeventfd(proxy);
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+        else
+            virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        if (val < VIRTIO_PCI_QUEUE_MAX)
+            vdev->queue_sel = val;
+        break;
+    case VIRTIO_PCI_QUEUE_NOTIFY:
+        if (val < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, val);
+        }
+        break;
+    case VIRTIO_PCI_STATUS:
+        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+            virtio_pci_stop_ioeventfd(proxy);
+        }
+
+        virtio_set_status(vdev, val & 0xFF);
+
+        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
+            virtio_pci_start_ioeventfd(proxy);
+        }
+
+        if (vdev->status == 0) {
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+
+        /* Linux before 2.6.34 sets the device as OK without enabling
+           the PCI device bus master bit. In this case we need to disable
+           some safety checks. */
+        if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        vdev->config_vector = val;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev,
+                          virtio_queue_vector(vdev, vdev->queue_sel));
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        virtio_queue_set_vector(vdev, vdev->queue_sel, val);
+        break;
+    default:
+        error_report("%s: unexpected address 0x%x value 0x%x",
+                     __func__, addr, val);
+        break;
+    }
+}
+
+static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
+{
+    VirtIODevice *vdev = proxy->vdev;
+    uint32_t ret = 0xFFFFFFFF;
+
+    switch (addr) {
+    case VIRTIO_PCI_HOST_FEATURES:
+        ret = proxy->host_features;
+        break;
+    case VIRTIO_PCI_GUEST_FEATURES:
+        ret = vdev->guest_features;
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
+              >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        break;
+    case VIRTIO_PCI_QUEUE_NUM:
+        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        ret = vdev->queue_sel;
+        break;
+    case VIRTIO_PCI_STATUS:
+        ret = vdev->status;
+        break;
+    case VIRTIO_PCI_ISR:
+        /* reading from the ISR also clears it. */
+        ret = vdev->isr;
+        vdev->isr = 0;
+        qemu_set_irq(proxy->pci_dev.irq[0], 0);
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        ret = vdev->config_vector;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        ret = virtio_queue_vector(vdev, vdev->queue_sel);
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readb(proxy->vdev, addr);
+}
+
+static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readw(proxy->vdev, addr);
+}
+
+static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config)
+        return virtio_ioport_read(proxy, addr);
+    addr -= config;
+    return virtio_config_readl(proxy->vdev, addr);
+}
+
+static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writeb(proxy->vdev, addr, val);
+}
+
+static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writew(proxy->vdev, addr, val);
+}
+
+static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    addr -= proxy->addr;
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    virtio_config_writel(proxy->vdev, addr, val);
+}
+
+static void virtio_map(PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
+
+    proxy->addr = addr;
+
+    register_ioport_write(addr, config_len, 1, virtio_pci_config_writeb, proxy);
+    register_ioport_write(addr, config_len, 2, virtio_pci_config_writew, proxy);
+    register_ioport_write(addr, config_len, 4, virtio_pci_config_writel, proxy);
+    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
+    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
+    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
+
+    if (vdev->config_len)
+        vdev->get_config(vdev, vdev->config);
+}
+
+static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
+                                uint32_t val, int len)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    if (PCI_COMMAND == address) {
+        if (!(val & PCI_COMMAND_MASTER)) {
+            if (!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
+                virtio_pci_stop_ioeventfd(proxy);
+                virtio_set_status(proxy->vdev,
+                                  proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
+            }
+        }
+    }
+
+    pci_default_write_config(pci_dev, address, val, len);
+    msix_write_config(pci_dev, address, val, len);
+}
+
+static unsigned virtio_pci_get_features(void *opaque)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    return proxy->host_features;
+}
+
+static void virtio_pci_guest_notifier_read(void *opaque)
+{
+    VirtQueue *vq = opaque;
+    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_irq(vq);
+    }
+}
+
+static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+
+    if (assign) {
+        int r = event_notifier_init(notifier, 0);
+        if (r < 0) {
+            return r;
+        }
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            virtio_pci_guest_notifier_read, NULL, vq);
+    } else {
+        qemu_set_fd_handler(event_notifier_get_fd(notifier),
+                            NULL, NULL, NULL);
+        event_notifier_cleanup(notifier);
+    }
+
+    return 0;
+}
+
+static bool virtio_pci_query_guest_notifiers(void *opaque)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    return msix_enabled(&proxy->pci_dev);
+}
+
+static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    int r, n;
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(vdev, n)) {
+            break;
+        }
+
+        r = virtio_pci_set_guest_notifier(opaque, n, assign);
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
+
+    return 0;
+
+assign_error:
+    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+    while (--n >= 0) {
+        virtio_pci_set_guest_notifier(opaque, n, !assign);
+    }
+    return r;
+}
+
+static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
+{
+    VirtIOPCIProxy *proxy = opaque;
+
+    /* Stop using ioeventfd for virtqueue kick if the device starts using host
+     * notifiers.  This makes it easy to avoid stepping on each others' toes.
+     */
+    proxy->ioeventfd_disabled = assign;
+    if (assign) {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
+    /* We don't need to start here: it's not needed because backend
+     * currently only stops on status change away from ok,
+     * reset, vmstop and such. If we do add code to start here,
+     * need to check vmstate, device state etc. */
+    return virtio_pci_set_host_notifier_internal(proxy, n, assign);
+}
+
+static void virtio_pci_vmstate_change(void *opaque, bool running)
+{
+    VirtIOPCIProxy *proxy = opaque;
+
+    if (running) {
+        /* Try to find out if the guest has bus master disabled, but is
+           in ready state. Then we have a buggy guest OS. */
+        if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        virtio_pci_start_ioeventfd(proxy);
+    } else {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
+}
+
+static const VirtIOBindings virtio_pci_bindings = {
+    .notify = virtio_pci_notify,
+    .save_config = virtio_pci_save_config,
+    .load_config = virtio_pci_load_config,
+    .save_queue = virtio_pci_save_queue,
+    .load_queue = virtio_pci_load_queue,
+    .get_features = virtio_pci_get_features,
+    .query_guest_notifiers = virtio_pci_query_guest_notifiers,
+    .set_host_notifier = virtio_pci_set_host_notifier,
+    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
+    .vmstate_change = virtio_pci_vmstate_change,
+};
+
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
+{
+    uint8_t *config;
+    uint32_t size;
+
+    proxy->vdev = vdev;
+
+    config = proxy->pci_dev.config;
+
+    if (proxy->class_code) {
+        pci_config_set_class(config, proxy->class_code);
+    }
+    pci_set_word(config + 0x2c, pci_get_word(config + PCI_VENDOR_ID));
+    pci_set_word(config + 0x2e, vdev->device_id);
+    config[0x3d] = 1;
+
+    if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
+        pci_register_bar(&proxy->pci_dev, 1,
+                         msix_bar_size(&proxy->pci_dev),
+                         PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         msix_mmio_map);
+    } else
+        vdev->nvectors = 0;
+
+    proxy->pci_dev.config_write = virtio_write_config;
+
+    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
+    if (size & (size-1))
+        size = 1 << qemu_fls(size);
+
+    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
+                           virtio_map);
+
+    if (!kvm_has_many_ioeventfds()) {
+        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
+    }
+
+    virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
+    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
+    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
+}
+
+static int virtio_blk_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    if (proxy->class_code != PCI_CLASS_STORAGE_SCSI &&
+        proxy->class_code != PCI_CLASS_STORAGE_OTHER)
+        proxy->class_code = PCI_CLASS_STORAGE_SCSI;
+
+    vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block,
+                           &proxy->block_serial);
+    if (!vdev) {
+        return -1;
+    }
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static int virtio_exit_pci(PCIDevice *pci_dev)
+{
+    return msix_uninit(pci_dev);
+}
+
+static int virtio_blk_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_blk_exit(proxy->vdev);
+    blockdev_mark_auto_del(proxy->block.bs);
+    return virtio_exit_pci(pci_dev);
+}
+
+static int virtio_serial_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
+        proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
+        proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
+        proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
+
+    vdev = virtio_serial_init(&pci_dev->qdev, &proxy->serial);
+    if (!vdev) {
+        return -1;
+    }
+    vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
+                                        ? proxy->serial.max_virtserial_ports + 1
+                                        : proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static int virtio_serial_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_serial_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
+static int virtio_net_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
+
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static int virtio_net_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_net_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
+static int virtio_balloon_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_balloon_init(&pci_dev->qdev);
+    if (!vdev) {
+        return -1;
+    }
+    virtio_init_pci(proxy, vdev);
+    return 0;
+}
+
+static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_balloon_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
+static PCIDeviceInfo virtio_info[] = {
+    {
+        .qdev.name = "virtio-blk-pci",
+        .qdev.alias = "virtio-blk",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_blk_init_pci,
+        .exit      = virtio_blk_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_STORAGE_SCSI,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+            DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+            DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+            DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+        .qdev.name  = "virtio-net-pci",
+        .qdev.alias = "virtio-net",
+        .qdev.size  = sizeof(VirtIOPCIProxy),
+        .init       = virtio_net_init_pci,
+        .exit       = virtio_net_exit_pci,
+        .romfile    = "pxe-virtio.rom",
+        .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id  = PCI_DEVICE_ID_VIRTIO_NET,
+        .revision   = VIRTIO_PCI_ABI_VERSION,
+        .class_id   = PCI_CLASS_NETWORK_ETHERNET,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+            DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+            DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
+                               net.txtimer, TX_TIMER_INTERVAL),
+            DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
+                              net.txburst, TX_BURST),
+            DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+        .qdev.name = "virtio-serial-pci",
+        .qdev.alias = "virtio-serial",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_serial_init_pci,
+        .exit      = virtio_serial_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_COMMUNICATION_OTHER,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                            VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                               DEV_NVECTORS_UNSPECIFIED),
+            DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy,
+                               serial.max_virtserial_ports, 31),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+        .qdev.name = "virtio-balloon-pci",
+        .qdev.alias = "virtio-balloon",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_balloon_init_pci,
+        .exit      = virtio_balloon_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_MEMORY_RAM,
+        .qdev.props = (Property[]) {
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+        .qdev.reset = virtio_pci_reset,
+    },{
+        /* end of list */
+    }
+};
+
+static void virtio_pci_register_devices(void)
+{
+    pci_qdev_register_many(virtio_info);
+}
+
+device_init(virtio_pci_register_devices)
diff --git a/qemu-0.15.x/hw/virtio-pci.h b/qemu-0.15.x/hw/virtio-pci.h
new file mode 100644
index 0000000..1f0de56
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-pci.h
@@ -0,0 +1,46 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Paul Brook        <paul at codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_VIRTIO_PCI_H
+#define QEMU_VIRTIO_PCI_H
+
+#include "virtio-net.h"
+#include "virtio-serial.h"
+
+typedef struct {
+    PCIDevice pci_dev;
+    VirtIODevice *vdev;
+    uint32_t flags;
+    uint32_t addr;
+    uint32_t class_code;
+    uint32_t nvectors;
+    BlockConf block;
+    char *block_serial;
+    NICConf nic;
+    uint32_t host_features;
+#ifdef CONFIG_LINUX
+    V9fsConf fsconf;
+#endif
+    virtio_serial_conf serial;
+    virtio_net_conf net;
+    bool ioeventfd_disabled;
+    bool ioeventfd_started;
+} VirtIOPCIProxy;
+
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
+
+/* Virtio ABI version, if we increment this, we break the guest driver. */
+#define VIRTIO_PCI_ABI_VERSION          0
+
+#endif
diff --git a/qemu-0.15.x/hw/virtio-serial-bus.c b/qemu-0.15.x/hw/virtio-serial-bus.c
new file mode 100644
index 0000000..c5eb931
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-serial-bus.c
@@ -0,0 +1,927 @@
+/*
+ * A bus for connecting virtio serial and console ports
+ *
+ * Copyright (C) 2009, 2010 Red Hat, Inc.
+ *
+ * Author(s):
+ *  Amit Shah <amit.shah at redhat.com>
+ *
+ * Some earlier parts are:
+ *  Copyright IBM, Corp. 2008
+ * authored by
+ *  Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "iov.h"
+#include "monitor.h"
+#include "qemu-queue.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "virtio-serial.h"
+
+/* The virtio-serial bus on top of which the ports will ride as devices */
+struct VirtIOSerialBus {
+    BusState qbus;
+
+    /* This is the parent device that provides the bus for ports. */
+    VirtIOSerial *vser;
+
+    /* The maximum number of ports that can ride on top of this bus */
+    uint32_t max_nr_ports;
+};
+
+struct VirtIOSerial {
+    VirtIODevice vdev;
+
+    VirtQueue *c_ivq, *c_ovq;
+    /* Arrays of ivqs and ovqs: one per port */
+    VirtQueue **ivqs, **ovqs;
+
+    VirtIOSerialBus bus;
+
+    DeviceState *qdev;
+
+    QTAILQ_HEAD(, VirtIOSerialPort) ports;
+
+    /* bitmap for identifying active ports */
+    uint32_t *ports_map;
+
+    struct virtio_console_config config;
+};
+
+static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
+{
+    VirtIOSerialPort *port;
+
+    if (id == VIRTIO_CONSOLE_BAD_ID) {
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(port, &vser->ports, next) {
+        if (port->id == id)
+            return port;
+    }
+    return NULL;
+}
+
+static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
+{
+    VirtIOSerialPort *port;
+
+    QTAILQ_FOREACH(port, &vser->ports, next) {
+        if (port->ivq == vq || port->ovq == vq)
+            return port;
+    }
+    return NULL;
+}
+
+static bool use_multiport(VirtIOSerial *vser)
+{
+    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
+
+static size_t write_to_port(VirtIOSerialPort *port,
+                            const uint8_t *buf, size_t size)
+{
+    VirtQueueElement elem;
+    VirtQueue *vq;
+    size_t offset;
+
+    vq = port->ivq;
+    if (!virtio_queue_ready(vq)) {
+        return 0;
+    }
+
+    offset = 0;
+    while (offset < size) {
+        size_t len;
+
+        if (!virtqueue_pop(vq, &elem)) {
+            break;
+        }
+
+        len = iov_from_buf(elem.in_sg, elem.in_num,
+                           buf + offset, 0, size - offset);
+        offset += len;
+
+        virtqueue_push(vq, &elem, len);
+    }
+
+    virtio_notify(&port->vser->vdev, vq);
+    return offset;
+}
+
+static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
+{
+    VirtQueueElement elem;
+
+    if (!virtio_queue_ready(vq)) {
+        return;
+    }
+    while (virtqueue_pop(vq, &elem)) {
+        virtqueue_push(vq, &elem, 0);
+    }
+    virtio_notify(vdev, vq);
+}
+
+static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
+                                 VirtIODevice *vdev)
+{
+    VirtIOSerialPortInfo *info;
+
+    assert(port);
+    assert(virtio_queue_ready(vq));
+
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+
+    while (!port->throttled) {
+        unsigned int i;
+
+        /* Pop an elem only if we haven't left off a previous one mid-way */
+        if (!port->elem.out_num) {
+            if (!virtqueue_pop(vq, &port->elem)) {
+                break;
+            }
+            port->iov_idx = 0;
+            port->iov_offset = 0;
+        }
+
+        for (i = port->iov_idx; i < port->elem.out_num; i++) {
+            size_t buf_size;
+            ssize_t ret;
+
+            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
+            ret = info->have_data(port,
+                                  port->elem.out_sg[i].iov_base
+                                  + port->iov_offset,
+                                  buf_size);
+            if (ret < 0 && ret != -EAGAIN) {
+                /* We don't handle any other type of errors here */
+                abort();
+            }
+            if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
+                virtio_serial_throttle_port(port, true);
+                port->iov_idx = i;
+                if (ret > 0) {
+                    port->iov_offset += ret;
+                }
+                break;
+            }
+            port->iov_offset = 0;
+        }
+        if (port->throttled) {
+            break;
+        }
+        virtqueue_push(vq, &port->elem, 0);
+        port->elem.out_num = 0;
+    }
+    virtio_notify(vdev, vq);
+}
+
+static void flush_queued_data(VirtIOSerialPort *port)
+{
+    assert(port);
+
+    if (!virtio_queue_ready(port->ovq)) {
+        return;
+    }
+    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
+}
+
+static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
+{
+    VirtQueueElement elem;
+    VirtQueue *vq;
+    struct virtio_console_control *cpkt;
+
+    vq = port->vser->c_ivq;
+    if (!virtio_queue_ready(vq)) {
+        return 0;
+    }
+    if (!virtqueue_pop(vq, &elem)) {
+        return 0;
+    }
+
+    cpkt = (struct virtio_console_control *)buf;
+    stl_p(&cpkt->id, port->id);
+    memcpy(elem.in_sg[0].iov_base, buf, len);
+
+    virtqueue_push(vq, &elem, len);
+    virtio_notify(&port->vser->vdev, vq);
+    return len;
+}
+
+static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
+                                 uint16_t value)
+{
+    struct virtio_console_control cpkt;
+
+    stw_p(&cpkt.event, event);
+    stw_p(&cpkt.value, value);
+
+    trace_virtio_serial_send_control_event(port->id, event, value);
+    return send_control_msg(port, &cpkt, sizeof(cpkt));
+}
+
+/* Functions for use inside qemu to open and read from/write to ports */
+int virtio_serial_open(VirtIOSerialPort *port)
+{
+    /* Don't allow opening an already-open port */
+    if (port->host_connected) {
+        return 0;
+    }
+    /* Send port open notification to the guest */
+    port->host_connected = true;
+    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+    return 0;
+}
+
+int virtio_serial_close(VirtIOSerialPort *port)
+{
+    port->host_connected = false;
+    /*
+     * If there's any data the guest sent which the app didn't
+     * consume, reset the throttling flag and discard the data.
+     */
+    port->throttled = false;
+    discard_vq_data(port->ovq, &port->vser->vdev);
+
+    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+    return 0;
+}
+
+/* Individual ports/apps call this function to write to the guest. */
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+                            size_t size)
+{
+    if (!port || !port->host_connected || !port->guest_connected) {
+        return 0;
+    }
+    return write_to_port(port, buf, size);
+}
+
+/*
+ * Readiness of the guest to accept data on a port.
+ * Returns max. data the guest can receive
+ */
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
+{
+    VirtQueue *vq = port->ivq;
+
+    if (!virtio_queue_ready(vq) ||
+        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
+        virtio_queue_empty(vq)) {
+        return 0;
+    }
+    if (use_multiport(port->vser) && !port->guest_connected) {
+        return 0;
+    }
+
+    if (virtqueue_avail_bytes(vq, 4096, 0)) {
+        return 4096;
+    }
+    if (virtqueue_avail_bytes(vq, 1, 0)) {
+        return 1;
+    }
+    return 0;
+}
+
+static void flush_queued_data_bh(void *opaque)
+{
+    VirtIOSerialPort *port = opaque;
+
+    flush_queued_data(port);
+}
+
+void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
+{
+    if (!port) {
+        return;
+    }
+
+    trace_virtio_serial_throttle_port(port->id, throttle);
+    port->throttled = throttle;
+    if (throttle) {
+        return;
+    }
+    qemu_bh_schedule(port->bh);
+}
+
+/* Guest wants to notify us of some event */
+static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
+{
+    struct VirtIOSerialPort *port;
+    struct VirtIOSerialPortInfo *info;
+    struct virtio_console_control cpkt, *gcpkt;
+    uint8_t *buffer;
+    size_t buffer_len;
+
+    gcpkt = buf;
+
+    if (len < sizeof(cpkt)) {
+        /* The guest sent an invalid control packet */
+        return;
+    }
+
+    cpkt.event = lduw_p(&gcpkt->event);
+    cpkt.value = lduw_p(&gcpkt->value);
+
+    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
+
+    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
+        if (!cpkt.value) {
+            error_report("virtio-serial-bus: Guest failure in adding device %s",
+                         vser->bus.qbus.name);
+            return;
+        }
+        /*
+         * The device is up, we can now tell the device about all the
+         * ports we have here.
+         */
+        QTAILQ_FOREACH(port, &vser->ports, next) {
+            send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
+        }
+        return;
+    }
+
+    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+    if (!port) {
+        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
+                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
+        return;
+    }
+
+    trace_virtio_serial_handle_control_message_port(port->id);
+
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+
+    switch(cpkt.event) {
+    case VIRTIO_CONSOLE_PORT_READY:
+        if (!cpkt.value) {
+            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
+                         port->id, vser->bus.qbus.name);
+            break;
+        }
+        /*
+         * Now that we know the guest asked for the port name, we're
+         * sure the guest has initialised whatever state is necessary
+         * for this port. Now's a good time to let the guest know if
+         * this port is a console port so that the guest can hook it
+         * up to hvc.
+         */
+        if (info->is_console) {
+            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
+        }
+
+        if (port->name) {
+            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
+            stw_p(&cpkt.value, 1);
+
+            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
+            buffer = qemu_malloc(buffer_len);
+
+            memcpy(buffer, &cpkt, sizeof(cpkt));
+            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
+            buffer[buffer_len - 1] = 0;
+
+            send_control_msg(port, buffer, buffer_len);
+            qemu_free(buffer);
+        }
+
+        if (port->host_connected) {
+            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+        }
+
+        /*
+         * When the guest has asked us for this information it means
+         * the guest is all setup and has its virtqueues
+         * initialised. If some app is interested in knowing about
+         * this event, let it know.
+         */
+        if (info->guest_ready) {
+            info->guest_ready(port);
+        }
+        break;
+
+    case VIRTIO_CONSOLE_PORT_OPEN:
+        port->guest_connected = cpkt.value;
+        if (cpkt.value && info->guest_open) {
+            /* Send the guest opened notification if an app is interested */
+            info->guest_open(port);
+        }
+
+        if (!cpkt.value && info->guest_close) {
+            /* Send the guest closed notification if an app is interested */
+            info->guest_close(port);
+        }
+        break;
+    }
+}
+
+static void control_in(VirtIODevice *vdev, VirtQueue *vq)
+{
+}
+
+static void control_out(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtQueueElement elem;
+    VirtIOSerial *vser;
+    uint8_t *buf;
+    size_t len;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    len = 0;
+    buf = NULL;
+    while (virtqueue_pop(vq, &elem)) {
+        size_t cur_len, copied;
+
+        cur_len = iov_size(elem.out_sg, elem.out_num);
+        /*
+         * Allocate a new buf only if we didn't have one previously or
+         * if the size of the buf differs
+         */
+        if (cur_len > len) {
+            qemu_free(buf);
+
+            buf = qemu_malloc(cur_len);
+            len = cur_len;
+        }
+        copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
+
+        handle_control_message(vser, buf, copied);
+        virtqueue_push(vq, &elem, 0);
+    }
+    qemu_free(buf);
+    virtio_notify(vdev, vq);
+}
+
+/* Guest wrote something to some port. */
+static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOSerial *vser;
+    VirtIOSerialPort *port;
+    VirtIOSerialPortInfo *info;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    port = find_port_by_vq(vser, vq);
+    info = port ? DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info) : NULL;
+
+    if (!port || !port->host_connected || !info->have_data) {
+        discard_vq_data(vq, vdev);
+        return;
+    }
+
+    if (!port->throttled) {
+        do_flush_queued_data(port, vq, vdev);
+        return;
+    }
+}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+}
+
+static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIOSerial *vser;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    if (vser->bus.max_nr_ports > 1) {
+        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+    }
+    return features;
+}
+
+/* Guest requested config info */
+static void get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOSerial *vser;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
+}
+
+static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
+{
+    struct virtio_console_config config;
+
+    memcpy(&config, config_data, sizeof(config));
+}
+
+static void virtio_serial_save(QEMUFile *f, void *opaque)
+{
+    VirtIOSerial *s = opaque;
+    VirtIOSerialPort *port;
+    uint32_t nr_active_ports;
+    unsigned int i, max_nr_ports;
+
+    /* The virtio device */
+    virtio_save(&s->vdev, f);
+
+    /* The config space */
+    qemu_put_be16s(f, &s->config.cols);
+    qemu_put_be16s(f, &s->config.rows);
+
+    qemu_put_be32s(f, &s->config.max_nr_ports);
+
+    /* The ports map */
+    max_nr_ports = tswap32(s->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        qemu_put_be32s(f, &s->ports_map[i]);
+    }
+
+    /* Ports */
+
+    nr_active_ports = 0;
+    QTAILQ_FOREACH(port, &s->ports, next) {
+        nr_active_ports++;
+    }
+
+    qemu_put_be32s(f, &nr_active_ports);
+
+    /*
+     * Items in struct VirtIOSerialPort.
+     */
+    QTAILQ_FOREACH(port, &s->ports, next) {
+        uint32_t elem_popped;
+
+        qemu_put_be32s(f, &port->id);
+        qemu_put_byte(f, port->guest_connected);
+        qemu_put_byte(f, port->host_connected);
+
+	elem_popped = 0;
+        if (port->elem.out_num) {
+            elem_popped = 1;
+        }
+        qemu_put_be32s(f, &elem_popped);
+        if (elem_popped) {
+            qemu_put_be32s(f, &port->iov_idx);
+            qemu_put_be64s(f, &port->iov_offset);
+
+            qemu_put_buffer(f, (unsigned char *)&port->elem,
+                            sizeof(port->elem));
+        }
+    }
+}
+
+static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOSerial *s = opaque;
+    VirtIOSerialPort *port;
+    uint32_t max_nr_ports, nr_active_ports, ports_map;
+    unsigned int i;
+
+    if (version_id > 3) {
+        return -EINVAL;
+    }
+
+    /* The virtio device */
+    virtio_load(&s->vdev, f);
+
+    if (version_id < 2) {
+        return 0;
+    }
+
+    /* The config space */
+    qemu_get_be16s(f, &s->config.cols);
+    qemu_get_be16s(f, &s->config.rows);
+
+    qemu_get_be32s(f, &max_nr_ports);
+    tswap32s(&max_nr_ports);
+    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
+        /* Source could have had more ports than us. Fail migration. */
+        return -EINVAL;
+    }
+
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        qemu_get_be32s(f, &ports_map);
+
+        if (ports_map != s->ports_map[i]) {
+            /*
+             * Ports active on source and destination don't
+             * match. Fail migration.
+             */
+            return -EINVAL;
+        }
+    }
+
+    qemu_get_be32s(f, &nr_active_ports);
+
+    /* Items in struct VirtIOSerialPort */
+    for (i = 0; i < nr_active_ports; i++) {
+        uint32_t id;
+        bool host_connected;
+
+        id = qemu_get_be32(f);
+        port = find_port_by_id(s, id);
+        if (!port) {
+            return -EINVAL;
+        }
+
+        port->guest_connected = qemu_get_byte(f);
+        host_connected = qemu_get_byte(f);
+        if (host_connected != port->host_connected) {
+            /*
+             * We have to let the guest know of the host connection
+             * status change
+             */
+            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
+                               port->host_connected);
+        }
+
+        if (version_id > 2) {
+            uint32_t elem_popped;
+
+            qemu_get_be32s(f, &elem_popped);
+            if (elem_popped) {
+                qemu_get_be32s(f, &port->iov_idx);
+                qemu_get_be64s(f, &port->iov_offset);
+
+                qemu_get_buffer(f, (unsigned char *)&port->elem,
+                                sizeof(port->elem));
+                virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
+                                 port->elem.in_num, 1);
+                virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
+                                 port->elem.out_num, 1);
+
+                /*
+                 *  Port was throttled on source machine.  Let's
+                 *  unthrottle it here so data starts flowing again.
+                 */
+                virtio_serial_throttle_port(port, false);
+            }
+        }
+    }
+    return 0;
+}
+
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
+
+static struct BusInfo virtser_bus_info = {
+    .name      = "virtio-serial-bus",
+    .size      = sizeof(VirtIOSerialBus),
+    .print_dev = virtser_bus_dev_print,
+    .props      = (Property[]) {
+        DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
+        DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+
+    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
+                   indent, "", port->id,
+                   port->guest_connected ? "on" : "off",
+                   port->host_connected ? "on" : "off",
+                   port->throttled ? "on" : "off");
+}
+
+/* This function is only used if a port id is not provided by the user */
+static uint32_t find_free_port_id(VirtIOSerial *vser)
+{
+    unsigned int i, max_nr_ports;
+
+    max_nr_ports = tswap32(vser->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        uint32_t map, bit;
+
+        map = vser->ports_map[i];
+        bit = ffs(~map);
+        if (bit) {
+            return (bit - 1) + i * 32;
+        }
+    }
+    return VIRTIO_CONSOLE_BAD_ID;
+}
+
+static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
+{
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] |= 1U << (port_id % 32);
+}
+
+static void add_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    mark_port_added(vser, port_id);
+
+    send_control_event(find_port_by_id(vser, port_id),
+                       VIRTIO_CONSOLE_PORT_ADD, 1);
+}
+
+static void remove_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    VirtIOSerialPort *port;
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] &= ~(1U << (port_id % 32));
+
+    port = find_port_by_id(vser, port_id);
+    /* Flush out any unconsumed buffers first */
+    discard_vq_data(port->ovq, &port->vser->vdev);
+
+    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
+}
+
+static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
+    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
+    int ret, max_nr_ports;
+    bool plugging_port0;
+
+    port->vser = bus->vser;
+    port->bh = qemu_bh_new(flush_queued_data_bh, port);
+
+    /*
+     * Is the first console port we're seeing? If so, put it up at
+     * location 0. This is done for backward compatibility (old
+     * kernel, new qemu).
+     */
+    plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
+
+    if (find_port_by_id(port->vser, port->id)) {
+        error_report("virtio-serial-bus: A port already exists at id %u",
+                     port->id);
+        return -1;
+    }
+
+    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+        if (plugging_port0) {
+            port->id = 0;
+        } else {
+            port->id = find_free_port_id(port->vser);
+            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+                error_report("virtio-serial-bus: Maximum port limit for this device reached");
+                return -1;
+            }
+        }
+    }
+
+    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
+    if (port->id >= max_nr_ports) {
+        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
+                     max_nr_ports - 1);
+        return -1;
+    }
+
+    ret = info->init(port);
+    if (ret) {
+        return ret;
+    }
+
+    if (!use_multiport(port->vser)) {
+        /*
+         * Allow writes to guest in this case; we have no way of
+         * knowing if a guest port is connected.
+         */
+        port->guest_connected = true;
+    }
+
+    port->elem.out_num = 0;
+
+    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
+    port->ivq = port->vser->ivqs[port->id];
+    port->ovq = port->vser->ovqs[port->id];
+
+    add_port(port->vser, port->id);
+
+    /* Send an update to the guest about this new port added */
+    virtio_notify_config(&port->vser->vdev);
+
+    return ret;
+}
+
+static int virtser_port_qdev_exit(DeviceState *qdev)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
+                                           port->dev.info);
+    VirtIOSerial *vser = port->vser;
+
+    qemu_bh_delete(port->bh);
+    remove_port(port->vser, port->id);
+
+    QTAILQ_REMOVE(&vser->ports, port, next);
+
+    if (info->exit) {
+        info->exit(port);
+    }
+    return 0;
+}
+
+void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
+{
+    info->qdev.init = virtser_port_qdev_init;
+    info->qdev.bus_info = &virtser_bus_info;
+    info->qdev.exit = virtser_port_qdev_exit;
+    info->qdev.unplug = qdev_simple_unplug_cb;
+    qdev_register(&info->qdev);
+}
+
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
+{
+    VirtIOSerial *vser;
+    VirtIODevice *vdev;
+    uint32_t i, max_supported_ports;
+
+    if (!conf->max_virtserial_ports)
+        return NULL;
+
+    /* Each port takes 2 queues, and one pair is for the control queue */
+    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
+
+    if (conf->max_virtserial_ports > max_supported_ports) {
+        error_report("maximum ports supported: %u", max_supported_ports);
+        return NULL;
+    }
+
+    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
+                              sizeof(struct virtio_console_config),
+                              sizeof(VirtIOSerial));
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
+    qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
+    vser->bus.qbus.allow_hotplug = 1;
+    vser->bus.vser = vser;
+    QTAILQ_INIT(&vser->ports);
+
+    vser->bus.max_nr_ports = conf->max_virtserial_ports;
+    vser->ivqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
+    vser->ovqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
+
+    /* Add a queue for host to guest transfers for port 0 (backward compat) */
+    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
+    /* Add a queue for guest to host transfers for port 0 (backward compat) */
+    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
+
+    /* TODO: host to guest notifications can get dropped
+     * if the queue fills up. Implement queueing in host,
+     * this might also make it possible to reduce the control
+     * queue size: as guest preposts buffers there,
+     * this will save 4Kbyte of guest memory per entry. */
+
+    /* control queue: host to guest */
+    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
+    /* control queue: guest to host */
+    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
+
+    for (i = 1; i < vser->bus.max_nr_ports; i++) {
+        /* Add a per-port queue for host to guest transfers */
+        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
+        /* Add a per-per queue for guest to host transfers */
+        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
+    }
+
+    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
+    vser->ports_map = qemu_mallocz(((conf->max_virtserial_ports + 31) / 32)
+        * sizeof(vser->ports_map[0]));
+    /*
+     * Reserve location 0 for a console port for backward compat
+     * (old kernel, new qemu)
+     */
+    mark_port_added(vser, 0);
+
+    vser->vdev.get_features = get_features;
+    vser->vdev.get_config = get_config;
+    vser->vdev.set_config = set_config;
+
+    vser->qdev = dev;
+
+    /*
+     * Register for the savevm section with the virtio-console name
+     * to preserve backward compat
+     */
+    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
+                    virtio_serial_load, vser);
+
+    return vdev;
+}
+
+void virtio_serial_exit(VirtIODevice *vdev)
+{
+    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    unregister_savevm(vser->qdev, "virtio-console", vser);
+
+    qemu_free(vser->ivqs);
+    qemu_free(vser->ovqs);
+    qemu_free(vser->ports_map);
+
+    virtio_cleanup(vdev);
+}
diff --git a/qemu-0.15.x/hw/virtio-serial.h b/qemu-0.15.x/hw/virtio-serial.h
new file mode 100644
index 0000000..36e9d22
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio-serial.h
@@ -0,0 +1,207 @@
+/*
+ * Virtio Serial / Console Support
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Red Hat, Inc. 2009, 2010
+ *
+ * Authors:
+ *  Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ *  Amit Shah <amit.shah at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_SERIAL_H
+#define _QEMU_VIRTIO_SERIAL_H
+
+#include "qdev.h"
+#include "virtio.h"
+
+/* == Interface shared between the guest kernel and qemu == */
+
+/* The Virtio ID for virtio console / serial ports */
+#define VIRTIO_ID_CONSOLE		3
+
+/* Features supported */
+#define VIRTIO_CONSOLE_F_MULTIPORT	1
+
+#define VIRTIO_CONSOLE_BAD_ID           (~(uint32_t)0)
+
+struct virtio_console_config {
+    /*
+     * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
+     * isn't implemented here yet
+     */
+    uint16_t cols;
+    uint16_t rows;
+
+    uint32_t max_nr_ports;
+} __attribute__((packed));
+
+struct virtio_console_control {
+    uint32_t id;		/* Port number */
+    uint16_t event;		/* The kind of control event (see below) */
+    uint16_t value;		/* Extra information for the key */
+};
+
+struct virtio_serial_conf {
+    /* Max. number of ports we can have for a virtio-serial device */
+    uint32_t max_virtserial_ports;
+};
+
+/* Some events for the internal messages (control packets) */
+#define VIRTIO_CONSOLE_DEVICE_READY	0
+#define VIRTIO_CONSOLE_PORT_ADD		1
+#define VIRTIO_CONSOLE_PORT_REMOVE	2
+#define VIRTIO_CONSOLE_PORT_READY	3
+#define VIRTIO_CONSOLE_CONSOLE_PORT	4
+#define VIRTIO_CONSOLE_RESIZE		5
+#define VIRTIO_CONSOLE_PORT_OPEN	6
+#define VIRTIO_CONSOLE_PORT_NAME	7
+
+/* == In-qemu interface == */
+
+typedef struct VirtIOSerial VirtIOSerial;
+typedef struct VirtIOSerialBus VirtIOSerialBus;
+typedef struct VirtIOSerialPort VirtIOSerialPort;
+typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
+
+/*
+ * This is the state that's shared between all the ports.  Some of the
+ * state is configurable via command-line options. Some of it can be
+ * set by individual devices in their initfn routines. Some of the
+ * state is set by the generic qdev device init routine.
+ */
+struct VirtIOSerialPort {
+    DeviceState dev;
+
+    QTAILQ_ENTRY(VirtIOSerialPort) next;
+
+    /*
+     * This field gives us the virtio device as well as the qdev bus
+     * that we are associated with
+     */
+    VirtIOSerial *vser;
+
+    VirtQueue *ivq, *ovq;
+
+    /*
+     * This name is sent to the guest and exported via sysfs.
+     * The guest could create symlinks based on this information.
+     * The name is in the reverse fqdn format, like org.qemu.console.0
+     */
+    char *name;
+
+    /*
+     * This id helps identify ports between the guest and the host.
+     * The guest sends a "header" with this id with each data packet
+     * that it sends and the host can then find out which associated
+     * device to send out this data to
+     */
+    uint32_t id;
+
+    /*
+     * This is the elem that we pop from the virtqueue.  A slow
+     * backend that consumes guest data (e.g. the file backend for
+     * qemu chardevs) can cause the guest to block till all the output
+     * is flushed.  This isn't desired, so we keep a note of the last
+     * element popped and continue consuming it once the backend
+     * becomes writable again.
+     */
+    VirtQueueElement elem;
+
+    /*
+     * The index and the offset into the iov buffer that was popped in
+     * elem above.
+     */
+    uint32_t iov_idx;
+    uint64_t iov_offset;
+
+    /*
+     * When unthrottling we use a bottom-half to call flush_queued_data.
+     */
+    QEMUBH *bh;
+
+    /* Is the corresponding guest device open? */
+    bool guest_connected;
+    /* Is this device open for IO on the host? */
+    bool host_connected;
+    /* Do apps not want to receive data? */
+    bool throttled;
+};
+
+struct VirtIOSerialPortInfo {
+    DeviceInfo qdev;
+
+    /* Is this a device that binds with hvc in the guest? */
+    bool is_console;
+
+    /*
+     * The per-port (or per-app) init function that's called when a
+     * new device is found on the bus.
+     */
+    int (*init)(VirtIOSerialPort *port);
+    /*
+     * Per-port exit function that's called when a port gets
+     * hot-unplugged or removed.
+     */
+    int (*exit)(VirtIOSerialPort *port);
+
+    /* Callbacks for guest events */
+        /* Guest opened device. */
+    void (*guest_open)(VirtIOSerialPort *port);
+        /* Guest closed device. */
+    void (*guest_close)(VirtIOSerialPort *port);
+
+        /* Guest is now ready to accept data (virtqueues set up). */
+    void (*guest_ready)(VirtIOSerialPort *port);
+
+    /*
+     * Guest wrote some data to the port. This data is handed over to
+     * the app via this callback.  The app can return a size less than
+     * 'len'.  In this case, throttling will be enabled for this port.
+     */
+    ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
+                         size_t len);
+};
+
+/* Interface to the virtio-serial bus */
+
+/*
+ * Individual ports/apps should call this function to register the port
+ * with the virtio-serial bus
+ */
+void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
+
+/*
+ * Open a connection to the port
+ *   Returns 0 on success (always).
+ */
+int virtio_serial_open(VirtIOSerialPort *port);
+
+/*
+ * Close the connection to the port
+ *   Returns 0 on success (always).
+ */
+int virtio_serial_close(VirtIOSerialPort *port);
+
+/*
+ * Send data to Guest
+ */
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+                            size_t size);
+
+/*
+ * Query whether a guest is ready to receive data.
+ */
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
+
+/*
+ * Flow control: Ports can signal to the virtio-serial core to stop
+ * sending data or re-start sending data, depending on the 'throttle'
+ * value here.
+ */
+void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
+
+#endif
diff --git a/qemu-0.15.x/hw/virtio.c b/qemu-0.15.x/hw/virtio.c
new file mode 100644
index 0000000..a8f4940
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio.c
@@ -0,0 +1,962 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <inttypes.h>
+
+#include "trace.h"
+#include "qemu-error.h"
+#include "virtio.h"
+
+/* The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize again. */
+#define VIRTIO_PCI_VRING_ALIGN         4096
+
+/* QEMU doesn't strictly need write barriers since everything runs in
+ * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
+ * KVM or if kqemu gets SMP support.
+ * In any case, we must prevent the compiler from reordering the code.
+ * TODO: we likely need some rmb()/mb() as well.
+ */
+
+#define wmb() __asm__ __volatile__("": : :"memory")
+
+typedef struct VRingDesc
+{
+    uint64_t addr;
+    uint32_t len;
+    uint16_t flags;
+    uint16_t next;
+} VRingDesc;
+
+typedef struct VRingAvail
+{
+    uint16_t flags;
+    uint16_t idx;
+    uint16_t ring[0];
+} VRingAvail;
+
+typedef struct VRingUsedElem
+{
+    uint32_t id;
+    uint32_t len;
+} VRingUsedElem;
+
+typedef struct VRingUsed
+{
+    uint16_t flags;
+    uint16_t idx;
+    VRingUsedElem ring[0];
+} VRingUsed;
+
+typedef struct VRing
+{
+    unsigned int num;
+    target_phys_addr_t desc;
+    target_phys_addr_t avail;
+    target_phys_addr_t used;
+} VRing;
+
+struct VirtQueue
+{
+    VRing vring;
+    target_phys_addr_t pa;
+    uint16_t last_avail_idx;
+    /* Last used index value we have signalled on */
+    uint16_t signalled_used;
+
+    /* Last used index value we have signalled on */
+    bool signalled_used_valid;
+
+    /* Notification enabled? */
+    bool notification;
+
+    int inuse;
+
+    uint16_t vector;
+    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
+    VirtIODevice *vdev;
+    EventNotifier guest_notifier;
+    EventNotifier host_notifier;
+};
+
+/* virt queue functions */
+static void virtqueue_init(VirtQueue *vq)
+{
+    target_phys_addr_t pa = vq->pa;
+
+    vq->vring.desc = pa;
+    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
+    vq->vring.used = vring_align(vq->vring.avail +
+                                 offsetof(VRingAvail, ring[vq->vring.num]),
+                                 VIRTIO_PCI_VRING_ALIGN);
+}
+
+static inline uint64_t vring_desc_addr(target_phys_addr_t desc_pa, int i)
+{
+    target_phys_addr_t pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
+    return ldq_phys(pa);
+}
+
+static inline uint32_t vring_desc_len(target_phys_addr_t desc_pa, int i)
+{
+    target_phys_addr_t pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
+    return ldl_phys(pa);
+}
+
+static inline uint16_t vring_desc_flags(target_phys_addr_t desc_pa, int i)
+{
+    target_phys_addr_t pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_desc_next(target_phys_addr_t desc_pa, int i)
+{
+    target_phys_addr_t pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_flags(VirtQueue *vq)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, flags);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_idx(VirtQueue *vq)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, idx);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_used_event(VirtQueue *vq)
+{
+    return vring_avail_ring(vq, vq->vring.num);
+}
+
+static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
+    stl_phys(pa, val);
+}
+
+static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
+    stl_phys(pa, val);
+}
+
+static uint16_t vring_used_idx(VirtQueue *vq)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, idx);
+    return lduw_phys(pa);
+}
+
+static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, idx);
+    stw_phys(pa, val);
+}
+
+static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, flags);
+    stw_phys(pa, lduw_phys(pa) | mask);
+}
+
+static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
+{
+    target_phys_addr_t pa;
+    pa = vq->vring.used + offsetof(VRingUsed, flags);
+    stw_phys(pa, lduw_phys(pa) & ~mask);
+}
+
+static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
+{
+    target_phys_addr_t pa;
+    if (!vq->notification) {
+        return;
+    }
+    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
+    stw_phys(pa, val);
+}
+
+void virtio_queue_set_notification(VirtQueue *vq, int enable)
+{
+    vq->notification = enable;
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    } else if (enable) {
+        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
+    } else {
+        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
+    }
+}
+
+int virtio_queue_ready(VirtQueue *vq)
+{
+    return vq->vring.avail != 0;
+}
+
+int virtio_queue_empty(VirtQueue *vq)
+{
+    return vring_avail_idx(vq) == vq->last_avail_idx;
+}
+
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len, unsigned int idx)
+{
+    unsigned int offset;
+    int i;
+
+    trace_virtqueue_fill(vq, elem, len, idx);
+
+    offset = 0;
+    for (i = 0; i < elem->in_num; i++) {
+        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
+
+        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
+                                  elem->in_sg[i].iov_len,
+                                  1, size);
+
+        offset += elem->in_sg[i].iov_len;
+    }
+
+    for (i = 0; i < elem->out_num; i++)
+        cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
+                                  elem->out_sg[i].iov_len,
+                                  0, elem->out_sg[i].iov_len);
+
+    idx = (idx + vring_used_idx(vq)) % vq->vring.num;
+
+    /* Get a pointer to the next entry in the used ring. */
+    vring_used_ring_id(vq, idx, elem->index);
+    vring_used_ring_len(vq, idx, len);
+}
+
+void virtqueue_flush(VirtQueue *vq, unsigned int count)
+{
+    uint16_t old, new;
+    /* Make sure buffer is written before we update index. */
+    wmb();
+    trace_virtqueue_flush(vq, count);
+    old = vring_used_idx(vq);
+    new = old + count;
+    vring_used_idx_set(vq, new);
+    vq->inuse -= count;
+    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
+        vq->signalled_used_valid = false;
+}
+
+void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len)
+{
+    virtqueue_fill(vq, elem, len, 0);
+    virtqueue_flush(vq, 1);
+}
+
+static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
+{
+    uint16_t num_heads = vring_avail_idx(vq) - idx;
+
+    /* Check it isn't doing very strange things with descriptor numbers. */
+    if (num_heads > vq->vring.num) {
+        error_report("Guest moved used index from %u to %u",
+                     idx, vring_avail_idx(vq));
+        exit(1);
+    }
+
+    return num_heads;
+}
+
+static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
+{
+    unsigned int head;
+
+    /* Grab the next descriptor number they're advertising, and increment
+     * the index we've seen. */
+    head = vring_avail_ring(vq, idx % vq->vring.num);
+
+    /* If their number is silly, that's a fatal mistake. */
+    if (head >= vq->vring.num) {
+        error_report("Guest says index %u is available", head);
+        exit(1);
+    }
+
+    return head;
+}
+
+static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
+                                    unsigned int i, unsigned int max)
+{
+    unsigned int next;
+
+    /* If this descriptor says it doesn't chain, we're done. */
+    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
+        return max;
+
+    /* Check they're not leading us off end of descriptors. */
+    next = vring_desc_next(desc_pa, i);
+    /* Make sure compiler knows to grab that: we don't want it changing! */
+    wmb();
+
+    if (next >= max) {
+        error_report("Desc next is %u", next);
+        exit(1);
+    }
+
+    return next;
+}
+
+int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
+{
+    unsigned int idx;
+    int total_bufs, in_total, out_total;
+
+    idx = vq->last_avail_idx;
+
+    total_bufs = in_total = out_total = 0;
+    while (virtqueue_num_heads(vq, idx)) {
+        unsigned int max, num_bufs, indirect = 0;
+        target_phys_addr_t desc_pa;
+        int i;
+
+        max = vq->vring.num;
+        num_bufs = total_bufs;
+        i = virtqueue_get_head(vq, idx++);
+        desc_pa = vq->vring.desc;
+
+        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
+            if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+                error_report("Invalid size for indirect buffer table");
+                exit(1);
+            }
+
+            /* If we've got too many, that implies a descriptor loop. */
+            if (num_bufs >= max) {
+                error_report("Looped descriptor");
+                exit(1);
+            }
+
+            /* loop over the indirect descriptor table */
+            indirect = 1;
+            max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
+            num_bufs = i = 0;
+            desc_pa = vring_desc_addr(desc_pa, i);
+        }
+
+        do {
+            /* If we've got too many, that implies a descriptor loop. */
+            if (++num_bufs > max) {
+                error_report("Looped descriptor");
+                exit(1);
+            }
+
+            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+                if (in_bytes > 0 &&
+                    (in_total += vring_desc_len(desc_pa, i)) >= in_bytes)
+                    return 1;
+            } else {
+                if (out_bytes > 0 &&
+                    (out_total += vring_desc_len(desc_pa, i)) >= out_bytes)
+                    return 1;
+            }
+        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+
+        if (!indirect)
+            total_bufs = num_bufs;
+        else
+            total_bufs++;
+    }
+
+    return 0;
+}
+
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+    size_t num_sg, int is_write)
+{
+    unsigned int i;
+    target_phys_addr_t len;
+
+    for (i = 0; i < num_sg; i++) {
+        len = sg[i].iov_len;
+        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
+        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
+            error_report("virtio: trying to map MMIO memory");
+            exit(1);
+        }
+    }
+}
+
+int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
+{
+    unsigned int i, head, max;
+    target_phys_addr_t desc_pa = vq->vring.desc;
+
+    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
+        return 0;
+
+    /* When we start there are none of either input nor output. */
+    elem->out_num = elem->in_num = 0;
+
+    max = vq->vring.num;
+
+    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    }
+
+    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
+        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+            error_report("Invalid size for indirect buffer table");
+            exit(1);
+        }
+
+        /* loop over the indirect descriptor table */
+        max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
+        desc_pa = vring_desc_addr(desc_pa, i);
+        i = 0;
+    }
+
+    /* Collect all the descriptors */
+    do {
+        struct iovec *sg;
+
+        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
+                error_report("Too many write descriptors in indirect table");
+                exit(1);
+            }
+            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
+            sg = &elem->in_sg[elem->in_num++];
+        } else {
+            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
+                error_report("Too many read descriptors in indirect table");
+                exit(1);
+            }
+            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
+            sg = &elem->out_sg[elem->out_num++];
+        }
+
+        sg->iov_len = vring_desc_len(desc_pa, i);
+
+        /* If we've got too many, that implies a descriptor loop. */
+        if ((elem->in_num + elem->out_num) > max) {
+            error_report("Looped descriptor");
+            exit(1);
+        }
+    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+
+    /* Now map what we have collected */
+    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
+    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
+
+    elem->index = head;
+
+    vq->inuse++;
+
+    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
+    return elem->in_num + elem->out_num;
+}
+
+/* virtio device */
+static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
+{
+    if (vdev->binding->notify) {
+        vdev->binding->notify(vdev->binding_opaque, vector);
+    }
+}
+
+void virtio_update_irq(VirtIODevice *vdev)
+{
+    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+}
+
+void virtio_reset(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+    int i;
+
+    virtio_set_status(vdev, 0);
+
+    if (vdev->reset)
+        vdev->reset(vdev);
+
+    vdev->guest_features = 0;
+    vdev->queue_sel = 0;
+    vdev->status = 0;
+    vdev->isr = 0;
+    vdev->config_vector = VIRTIO_NO_VECTOR;
+    virtio_notify_vector(vdev, vdev->config_vector);
+
+    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        vdev->vq[i].vring.desc = 0;
+        vdev->vq[i].vring.avail = 0;
+        vdev->vq[i].vring.used = 0;
+        vdev->vq[i].last_avail_idx = 0;
+        vdev->vq[i].pa = 0;
+        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].signalled_used = 0;
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
+    }
+}
+
+uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
+{
+    uint8_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    memcpy(&val, vdev->config + addr, sizeof(val));
+    return val;
+}
+
+uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
+{
+    uint16_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    memcpy(&val, vdev->config + addr, sizeof(val));
+    return val;
+}
+
+uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
+{
+    uint32_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    memcpy(&val, vdev->config + addr, sizeof(val));
+    return val;
+}
+
+void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint8_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint16_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint32_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    memcpy(vdev->config + addr, &val, sizeof(val));
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr)
+{
+    vdev->vq[n].pa = addr;
+    virtqueue_init(&vdev->vq[n]);
+}
+
+target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].pa;
+}
+
+int virtio_queue_get_num(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.num;
+}
+
+void virtio_queue_notify_vq(VirtQueue *vq)
+{
+    if (vq->vring.desc) {
+        VirtIODevice *vdev = vq->vdev;
+        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
+        vq->handle_output(vdev, vq);
+    }
+}
+
+void virtio_queue_notify(VirtIODevice *vdev, int n)
+{
+    virtio_queue_notify_vq(&vdev->vq[n]);
+}
+
+uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
+{
+    return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
+        VIRTIO_NO_VECTOR;
+}
+
+void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
+{
+    if (n < VIRTIO_PCI_QUEUE_MAX)
+        vdev->vq[n].vector = vector;
+}
+
+VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
+                            void (*handle_output)(VirtIODevice *, VirtQueue *))
+{
+    int i;
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+    }
+
+    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
+        abort();
+
+    vdev->vq[i].vring.num = queue_size;
+    vdev->vq[i].handle_output = handle_output;
+
+    return &vdev->vq[i];
+}
+
+void virtio_irq(VirtQueue *vq)
+{
+    trace_virtio_irq(vq);
+    vq->vdev->isr |= 0x01;
+    virtio_notify_vector(vq->vdev, vq->vector);
+}
+
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
+{
+	/* Note: Xen has similar logic for notification hold-off
+	 * in include/xen/interface/io/ring.h with req_event and req_prod
+	 * corresponding to event_idx + 1 and new respectively.
+	 * Note also that req_event and req_prod in Xen start at 1,
+	 * event indexes in virtio start at 0. */
+	return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
+}
+
+static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    uint16_t old, new;
+    bool v;
+    /* Always notify when queue is empty (when feature acknowledge) */
+    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
+         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
+        return true;
+    }
+
+    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
+    }
+
+    v = vq->signalled_used_valid;
+    vq->signalled_used_valid = true;
+    old = vq->signalled_used;
+    new = vq->signalled_used = vring_used_idx(vq);
+    return !v || vring_need_event(vring_used_event(vq), new, old);
+}
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    if (!vring_notify(vdev, vq)) {
+        return;
+    }
+
+    trace_virtio_notify(vdev, vq);
+    vdev->isr |= 0x01;
+    virtio_notify_vector(vdev, vq->vector);
+}
+
+void virtio_notify_config(VirtIODevice *vdev)
+{
+    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
+        return;
+
+    vdev->isr |= 0x03;
+    virtio_notify_vector(vdev, vdev->config_vector);
+}
+
+void virtio_save(VirtIODevice *vdev, QEMUFile *f)
+{
+    int i;
+
+    if (vdev->binding->save_config)
+        vdev->binding->save_config(vdev->binding_opaque, f);
+
+    qemu_put_8s(f, &vdev->status);
+    qemu_put_8s(f, &vdev->isr);
+    qemu_put_be16s(f, &vdev->queue_sel);
+    qemu_put_be32s(f, &vdev->guest_features);
+    qemu_put_be32(f, vdev->config_len);
+    qemu_put_buffer(f, vdev->config, vdev->config_len);
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+    }
+
+    qemu_put_be32(f, i);
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+
+        qemu_put_be32(f, vdev->vq[i].vring.num);
+        qemu_put_be64(f, vdev->vq[i].pa);
+        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
+        if (vdev->binding->save_queue)
+            vdev->binding->save_queue(vdev->binding_opaque, i, f);
+    }
+}
+
+int virtio_load(VirtIODevice *vdev, QEMUFile *f)
+{
+    int num, i, ret;
+    uint32_t features;
+    uint32_t supported_features =
+        vdev->binding->get_features(vdev->binding_opaque);
+
+    if (vdev->binding->load_config) {
+        ret = vdev->binding->load_config(vdev->binding_opaque, f);
+        if (ret)
+            return ret;
+    }
+
+    qemu_get_8s(f, &vdev->status);
+    qemu_get_8s(f, &vdev->isr);
+    qemu_get_be16s(f, &vdev->queue_sel);
+    qemu_get_be32s(f, &features);
+    if (features & ~supported_features) {
+        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
+                     features, supported_features);
+        return -1;
+    }
+    if (vdev->set_features)
+        vdev->set_features(vdev, features);
+    vdev->guest_features = features;
+    vdev->config_len = qemu_get_be32(f);
+    qemu_get_buffer(f, vdev->config, vdev->config_len);
+
+    num = qemu_get_be32(f);
+
+    for (i = 0; i < num; i++) {
+        vdev->vq[i].vring.num = qemu_get_be32(f);
+        vdev->vq[i].pa = qemu_get_be64(f);
+        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
+
+        if (vdev->vq[i].pa) {
+            uint16_t nheads;
+            virtqueue_init(&vdev->vq[i]);
+            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+            /* Check it isn't doing very strange things with descriptor numbers. */
+            if (nheads > vdev->vq[i].vring.num) {
+                error_report("VQ %d size 0x%x Guest index 0x%x "
+                             "inconsistent with Host index 0x%x: delta 0x%x",
+                             i, vdev->vq[i].vring.num,
+                             vring_avail_idx(&vdev->vq[i]),
+                             vdev->vq[i].last_avail_idx, nheads);
+                return -1;
+            }
+        } else if (vdev->vq[i].last_avail_idx) {
+            error_report("VQ %d address 0x0 "
+                         "inconsistent with Host index 0x%x",
+                         i, vdev->vq[i].last_avail_idx);
+                return -1;
+	}
+        if (vdev->binding->load_queue) {
+            ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
+            if (ret)
+                return ret;
+        }
+    }
+
+    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+    return 0;
+}
+
+void virtio_cleanup(VirtIODevice *vdev)
+{
+    qemu_del_vm_change_state_handler(vdev->vmstate);
+    if (vdev->config)
+        qemu_free(vdev->config);
+    qemu_free(vdev->vq);
+}
+
+static void virtio_vmstate_change(void *opaque, int running, int reason)
+{
+    VirtIODevice *vdev = opaque;
+    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
+    vdev->vm_running = running;
+
+    if (backend_run) {
+        virtio_set_status(vdev, vdev->status);
+    }
+
+    if (vdev->binding->vmstate_change) {
+        vdev->binding->vmstate_change(vdev->binding_opaque, backend_run);
+    }
+
+    if (!backend_run) {
+        virtio_set_status(vdev, vdev->status);
+    }
+}
+
+VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
+                                 size_t config_size, size_t struct_size)
+{
+    VirtIODevice *vdev;
+    int i;
+
+    vdev = qemu_mallocz(struct_size);
+
+    vdev->device_id = device_id;
+    vdev->status = 0;
+    vdev->isr = 0;
+    vdev->queue_sel = 0;
+    vdev->config_vector = VIRTIO_NO_VECTOR;
+    vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+    vdev->vm_running = vm_running;
+    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].vdev = vdev;
+    }
+
+    vdev->name = name;
+    vdev->config_len = config_size;
+    if (vdev->config_len)
+        vdev->config = qemu_mallocz(config_size);
+    else
+        vdev->config = NULL;
+
+    vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev);
+
+    return vdev;
+}
+
+void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
+                        void *opaque)
+{
+    vdev->binding = binding;
+    vdev->binding_opaque = opaque;
+}
+
+target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.avail;
+}
+
+target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used;
+}
+
+target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
+{
+    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingAvail, ring) +
+        sizeof(uint64_t) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingUsed, ring) +
+        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
+	    virtio_queue_get_used_size(vdev, n);
+}
+
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].last_avail_idx;
+}
+
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
+{
+    vdev->vq[n].last_avail_idx = idx;
+}
+
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
+{
+    return vdev->vq + n;
+}
+
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
+{
+    return &vq->guest_notifier;
+}
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
+{
+    return &vq->host_notifier;
+}
diff --git a/qemu-0.15.x/hw/virtio.h b/qemu-0.15.x/hw/virtio.h
new file mode 100644
index 0000000..c129264
--- /dev/null
+++ b/qemu-0.15.x/hw/virtio.h
@@ -0,0 +1,239 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_H
+#define _QEMU_VIRTIO_H
+
+#include "hw.h"
+#include "net.h"
+#include "qdev.h"
+#include "sysemu.h"
+#include "block_int.h"
+#include "event_notifier.h"
+#ifdef CONFIG_LINUX
+#include "9p.h"
+#endif
+
+/* from Linux's linux/virtio_config.h */
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER          2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK       4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED          0x80
+
+/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
+ * transport being used (eg. virtio_ring), the rest are per-device feature bits. */
+#define VIRTIO_TRANSPORT_F_START        28
+#define VIRTIO_TRANSPORT_F_END          32
+
+/* We notify when the ring is completely used, even if the guest is suppressing
+ * callbacks */
+#define VIRTIO_F_NOTIFY_ON_EMPTY        24
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC     28
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX         29
+/* A guest should never accept this.  It implies negotiation is broken. */
+#define VIRTIO_F_BAD_FEATURE		30
+
+/* from Linux's linux/virtio_ring.h */
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT       1
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE      2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT  4
+
+/* This means don't notify other side when buffer added. */
+#define VRING_USED_F_NO_NOTIFY  1
+/* This means don't interrupt guest when buffer consumed. */
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+struct VirtQueue;
+
+static inline target_phys_addr_t vring_align(target_phys_addr_t addr,
+                                             unsigned long align)
+{
+    return (addr + align - 1) & ~(align - 1);
+}
+
+typedef struct VirtQueue VirtQueue;
+
+#define VIRTQUEUE_MAX_SIZE 1024
+
+typedef struct VirtQueueElement
+{
+    unsigned int index;
+    unsigned int out_num;
+    unsigned int in_num;
+    target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE];
+    target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE];
+    struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
+    struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
+} VirtQueueElement;
+
+typedef struct {
+    void (*notify)(void * opaque, uint16_t vector);
+    void (*save_config)(void * opaque, QEMUFile *f);
+    void (*save_queue)(void * opaque, int n, QEMUFile *f);
+    int (*load_config)(void * opaque, QEMUFile *f);
+    int (*load_queue)(void * opaque, int n, QEMUFile *f);
+    int (*load_done)(void * opaque, QEMUFile *f);
+    unsigned (*get_features)(void * opaque);
+    bool (*query_guest_notifiers)(void * opaque);
+    int (*set_guest_notifiers)(void * opaque, bool assigned);
+    int (*set_host_notifier)(void * opaque, int n, bool assigned);
+    void (*vmstate_change)(void * opaque, bool running);
+} VirtIOBindings;
+
+#define VIRTIO_PCI_QUEUE_MAX 64
+
+#define VIRTIO_NO_VECTOR 0xffff
+
+struct VirtIODevice
+{
+    const char *name;
+    uint8_t status;
+    uint8_t isr;
+    uint16_t queue_sel;
+    uint32_t guest_features;
+    size_t config_len;
+    void *config;
+    uint16_t config_vector;
+    int nvectors;
+    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
+    uint32_t (*bad_features)(VirtIODevice *vdev);
+    void (*set_features)(VirtIODevice *vdev, uint32_t val);
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
+    void (*reset)(VirtIODevice *vdev);
+    void (*set_status)(VirtIODevice *vdev, uint8_t val);
+    VirtQueue *vq;
+    const VirtIOBindings *binding;
+    void *binding_opaque;
+    uint16_t device_id;
+    bool vm_running;
+    VMChangeStateEntry *vmstate;
+};
+
+static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    if (vdev->set_status) {
+        vdev->set_status(vdev, val);
+    }
+    vdev->status = val;
+}
+
+VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
+                            void (*handle_output)(VirtIODevice *,
+                                                  VirtQueue *));
+
+void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len);
+void virtqueue_flush(VirtQueue *vq, unsigned int count);
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len, unsigned int idx);
+
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+    size_t num_sg, int is_write);
+int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
+int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
+
+void virtio_save(VirtIODevice *vdev, QEMUFile *f);
+
+int virtio_load(VirtIODevice *vdev, QEMUFile *f);
+
+void virtio_cleanup(VirtIODevice *vdev);
+
+void virtio_notify_config(VirtIODevice *vdev);
+
+void virtio_queue_set_notification(VirtQueue *vq, int enable);
+
+int virtio_queue_ready(VirtQueue *vq);
+
+int virtio_queue_empty(VirtQueue *vq);
+
+/* Host binding interface.  */
+
+VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
+                                 size_t config_size, size_t struct_size);
+uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
+uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr);
+uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr);
+void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr);
+target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n);
+int virtio_queue_get_num(VirtIODevice *vdev, int n);
+void virtio_queue_notify(VirtIODevice *vdev, int n);
+uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
+void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
+void virtio_reset(void *opaque);
+void virtio_update_irq(VirtIODevice *vdev);
+
+void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
+                        void *opaque);
+
+/* Base devices.  */
+VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
+                              char **serial);
+struct virtio_net_conf;
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              struct virtio_net_conf *net);
+typedef struct virtio_serial_conf virtio_serial_conf;
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
+VirtIODevice *virtio_balloon_init(DeviceState *dev);
+#ifdef CONFIG_LINUX
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
+#endif
+
+
+void virtio_net_exit(VirtIODevice *vdev);
+void virtio_blk_exit(VirtIODevice *vdev);
+void virtio_serial_exit(VirtIODevice *vdev);
+void virtio_balloon_exit(VirtIODevice *vdev);
+
+#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
+	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
+			VIRTIO_RING_F_INDIRECT_DESC, true), \
+	DEFINE_PROP_BIT("event_idx", _state, _field, \
+			VIRTIO_RING_F_EVENT_IDX, true)
+
+target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
+void virtio_queue_notify_vq(VirtQueue *vq);
+void virtio_irq(VirtQueue *vq);
+#endif
diff --git a/qemu-0.15.x/hw/vmmouse.c b/qemu-0.15.x/hw/vmmouse.c
new file mode 100644
index 0000000..1113f33
--- /dev/null
+++ b/qemu-0.15.x/hw/vmmouse.c
@@ -0,0 +1,289 @@
+/*
+ * QEMU VMMouse emulation
+ *
+ * Copyright (C) 2007 Anthony Liguori <anthony at codemonkey.ws>
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "ps2.h"
+#include "pc.h"
+#include "qdev.h"
+
+/* debug only vmmouse */
+//#define DEBUG_VMMOUSE
+
+/* VMMouse Commands */
+#define VMMOUSE_GETVERSION	10
+#define VMMOUSE_DATA		39
+#define VMMOUSE_STATUS		40
+#define VMMOUSE_COMMAND		41
+
+#define VMMOUSE_READ_ID			0x45414552
+#define VMMOUSE_DISABLE			0x000000f5
+#define VMMOUSE_REQUEST_RELATIVE	0x4c455252
+#define VMMOUSE_REQUEST_ABSOLUTE	0x53424152
+
+#define VMMOUSE_QUEUE_SIZE	1024
+
+#define VMMOUSE_VERSION		0x3442554a
+
+#ifdef DEBUG_VMMOUSE
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct _VMMouseState
+{
+    ISADevice dev;
+    uint32_t queue[VMMOUSE_QUEUE_SIZE];
+    int32_t queue_size;
+    uint16_t nb_queue;
+    uint16_t status;
+    uint8_t absolute;
+    QEMUPutMouseEntry *entry;
+    void *ps2_mouse;
+} VMMouseState;
+
+static uint32_t vmmouse_get_status(VMMouseState *s)
+{
+    DPRINTF("vmmouse_get_status()\n");
+    return (s->status << 16) | s->nb_queue;
+}
+
+static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
+{
+    VMMouseState *s = opaque;
+    int buttons = 0;
+
+    if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
+        return;
+
+    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
+            x, y, dz, buttons_state);
+
+    if ((buttons_state & MOUSE_EVENT_LBUTTON))
+        buttons |= 0x20;
+    if ((buttons_state & MOUSE_EVENT_RBUTTON))
+        buttons |= 0x10;
+    if ((buttons_state & MOUSE_EVENT_MBUTTON))
+        buttons |= 0x08;
+
+    if (s->absolute) {
+        x <<= 1;
+        y <<= 1;
+    }
+
+    s->queue[s->nb_queue++] = buttons;
+    s->queue[s->nb_queue++] = x;
+    s->queue[s->nb_queue++] = y;
+    s->queue[s->nb_queue++] = dz;
+
+    /* need to still generate PS2 events to notify driver to
+       read from queue */
+    i8042_isa_mouse_fake_event(s->ps2_mouse);
+}
+
+static void vmmouse_remove_handler(VMMouseState *s)
+{
+    if (s->entry) {
+        qemu_remove_mouse_event_handler(s->entry);
+        s->entry = NULL;
+    }
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+    if (s->status != 0) {
+        return;
+    }
+    if (s->absolute != absolute) {
+        s->absolute = absolute;
+        vmmouse_remove_handler(s);
+    }
+    if (s->entry == NULL) {
+        s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
+                                                s, s->absolute,
+                                                "vmmouse");
+        qemu_activate_mouse_event_handler(s->entry);
+    }
+}
+
+static void vmmouse_read_id(VMMouseState *s)
+{
+    DPRINTF("vmmouse_read_id()\n");
+
+    if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
+        return;
+
+    s->queue[s->nb_queue++] = VMMOUSE_VERSION;
+    s->status = 0;
+}
+
+static void vmmouse_request_relative(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_relative()\n");
+    vmmouse_update_handler(s, 0);
+}
+
+static void vmmouse_request_absolute(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_absolute()\n");
+    vmmouse_update_handler(s, 1);
+}
+
+static void vmmouse_disable(VMMouseState *s)
+{
+    DPRINTF("vmmouse_disable()\n");
+    s->status = 0xffff;
+    vmmouse_remove_handler(s);
+}
+
+static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
+{
+    int i;
+
+    DPRINTF("vmmouse_data(%d)\n", size);
+
+    if (size == 0 || size > 6 || size > s->nb_queue) {
+        printf("vmmouse: driver requested too much data %d\n", size);
+        s->status = 0xffff;
+        vmmouse_remove_handler(s);
+        return;
+    }
+
+    for (i = 0; i < size; i++)
+        data[i] = s->queue[i];
+
+    s->nb_queue -= size;
+    if (s->nb_queue)
+        memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
+}
+
+static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
+{
+    VMMouseState *s = opaque;
+    uint32_t data[6];
+    uint16_t command;
+
+    vmmouse_get_data(data);
+
+    command = data[2] & 0xFFFF;
+
+    switch (command) {
+    case VMMOUSE_STATUS:
+        data[0] = vmmouse_get_status(s);
+        break;
+    case VMMOUSE_COMMAND:
+        switch (data[1]) {
+        case VMMOUSE_DISABLE:
+            vmmouse_disable(s);
+            break;
+        case VMMOUSE_READ_ID:
+            vmmouse_read_id(s);
+            break;
+        case VMMOUSE_REQUEST_RELATIVE:
+            vmmouse_request_relative(s);
+            break;
+        case VMMOUSE_REQUEST_ABSOLUTE:
+            vmmouse_request_absolute(s);
+            break;
+        default:
+            printf("vmmouse: unknown command %x\n", data[1]);
+            break;
+        }
+        break;
+    case VMMOUSE_DATA:
+        vmmouse_data(s, data, data[1]);
+        break;
+    default:
+        printf("vmmouse: unknown command %x\n", command);
+        break;
+    }
+
+    vmmouse_set_data(data);
+    return data[0];
+}
+
+static int vmmouse_post_load(void *opaque, int version_id)
+{
+    VMMouseState *s = opaque;
+
+    vmmouse_remove_handler(s);
+    vmmouse_update_handler(s, s->absolute);
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmmouse = {
+    .name = "vmmouse",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = vmmouse_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
+        VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
+        VMSTATE_UINT16(nb_queue, VMMouseState),
+        VMSTATE_UINT16(status, VMMouseState),
+        VMSTATE_UINT8(absolute, VMMouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vmmouse_reset(DeviceState *d)
+{
+    VMMouseState *s = container_of(d, VMMouseState, dev.qdev);
+
+    s->status = 0xffff;
+    s->queue_size = VMMOUSE_QUEUE_SIZE;
+}
+
+static int vmmouse_initfn(ISADevice *dev)
+{
+    VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev);
+
+    DPRINTF("vmmouse_init\n");
+
+    vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
+
+    return 0;
+}
+
+static ISADeviceInfo vmmouse_info = {
+    .init          = vmmouse_initfn,
+    .qdev.name     = "vmmouse",
+    .qdev.size     = sizeof(VMMouseState),
+    .qdev.vmsd     = &vmstate_vmmouse,
+    .qdev.no_user  = 1,
+    .qdev.reset    = vmmouse_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void vmmouse_dev_register(void)
+{
+    isa_qdev_register(&vmmouse_info);
+}
+device_init(vmmouse_dev_register)
diff --git a/qemu-0.15.x/hw/vmport.c b/qemu-0.15.x/hw/vmport.c
new file mode 100644
index 0000000..c8aefaa
--- /dev/null
+++ b/qemu-0.15.x/hw/vmport.c
@@ -0,0 +1,148 @@
+/*
+ * QEMU VMPort emulation
+ *
+ * Copyright (C) 2007 Hervé Poussineau
+ *
+ * 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 "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "kvm.h"
+#include "qdev.h"
+
+//#define VMPORT_DEBUG
+
+#define VMPORT_CMD_GETVERSION 0x0a
+#define VMPORT_CMD_GETRAMSIZE 0x14
+
+#define VMPORT_ENTRIES 0x2c
+#define VMPORT_MAGIC   0x564D5868
+
+typedef struct _VMPortState
+{
+    ISADevice dev;
+    IOPortReadFunc *func[VMPORT_ENTRIES];
+    void *opaque[VMPORT_ENTRIES];
+} VMPortState;
+
+static VMPortState *port_state;
+
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque)
+{
+    if (command >= VMPORT_ENTRIES)
+        return;
+
+    port_state->func[command] = func;
+    port_state->opaque[command] = opaque;
+}
+
+static uint32_t vmport_ioport_read(void *opaque, uint32_t addr)
+{
+    VMPortState *s = opaque;
+    CPUState *env = cpu_single_env;
+    unsigned char command;
+    uint32_t eax;
+
+    cpu_synchronize_state(env);
+
+    eax = env->regs[R_EAX];
+    if (eax != VMPORT_MAGIC)
+        return eax;
+
+    command = env->regs[R_ECX];
+    if (command >= VMPORT_ENTRIES)
+        return eax;
+    if (!s->func[command])
+    {
+#ifdef VMPORT_DEBUG
+        fprintf(stderr, "vmport: unknown command %x\n", command);
+#endif
+        return eax;
+    }
+
+    return s->func[command](s->opaque[command], addr);
+}
+
+static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    CPUState *env = cpu_single_env;
+
+    env->regs[R_EAX] = vmport_ioport_read(opaque, addr);
+}
+
+static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
+{
+    CPUState *env = cpu_single_env;
+    env->regs[R_EBX] = VMPORT_MAGIC;
+    return 6;
+}
+
+static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
+{
+    CPUState *env = cpu_single_env;
+    env->regs[R_EBX] = 0x1177;
+    return ram_size;
+}
+
+/* vmmouse helpers */
+void vmmouse_get_data(uint32_t *data)
+{
+    CPUState *env = cpu_single_env;
+
+    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+}
+
+void vmmouse_set_data(const uint32_t *data)
+{
+    CPUState *env = cpu_single_env;
+
+    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
+static int vmport_initfn(ISADevice *dev)
+{
+    VMPortState *s = DO_UPCAST(VMPortState, dev, dev);
+
+    register_ioport_read(0x5658, 1, 4, vmport_ioport_read, s);
+    register_ioport_write(0x5658, 1, 4, vmport_ioport_write, s);
+    isa_init_ioport(dev, 0x5658);
+    port_state = s;
+    /* Register some generic port commands */
+    vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
+    vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
+    return 0;
+}
+
+static ISADeviceInfo vmport_info = {
+    .qdev.name     = "vmport",
+    .qdev.size     = sizeof(VMPortState),
+    .qdev.no_user  = 1,
+    .init          = vmport_initfn,
+};
+
+static void vmport_dev_register(void)
+{
+    isa_qdev_register(&vmport_info);
+}
+device_init(vmport_dev_register)
diff --git a/qemu-0.15.x/hw/vmware_vga.c b/qemu-0.15.x/hw/vmware_vga.c
new file mode 100644
index 0000000..354c221
--- /dev/null
+++ b/qemu-0.15.x/hw/vmware_vga.c
@@ -0,0 +1,1324 @@
+/*
+ * QEMU VMware-SVGA "chipset".
+ *
+ * Copyright (c) 2007 Andrzej Zaborowski  <balrog at zabor.org>
+ *
+ * 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 "hw.h"
+#include "loader.h"
+#include "console.h"
+#include "pci.h"
+#include "vmware_vga.h"
+
+#define VERBOSE
+#undef DIRECT_VRAM
+#define HW_RECT_ACCEL
+#define HW_FILL_ACCEL
+#define HW_MOUSE_ACCEL
+
+# include "vga_int.h"
+
+struct vmsvga_state_s {
+    VGACommonState vga;
+
+    int width;
+    int height;
+    int invalidated;
+    int depth;
+    int bypp;
+    int enable;
+    int config;
+    struct {
+        int id;
+        int x;
+        int y;
+        int on;
+    } cursor;
+
+    target_phys_addr_t vram_base;
+
+    int index;
+    int scratch_size;
+    uint32_t *scratch;
+    int new_width;
+    int new_height;
+    uint32_t guest;
+    uint32_t svgaid;
+    uint32_t wred;
+    uint32_t wgreen;
+    uint32_t wblue;
+    int syncing;
+    int fb_size;
+
+    ram_addr_t fifo_offset;
+    uint8_t *fifo_ptr;
+    unsigned int fifo_size;
+    target_phys_addr_t fifo_base;
+
+    union {
+        uint32_t *fifo;
+        struct __attribute__((__packed__)) {
+            uint32_t min;
+            uint32_t max;
+            uint32_t next_cmd;
+            uint32_t stop;
+            /* Add registers here when adding capabilities.  */
+            uint32_t fifo[0];
+        } *cmd;
+    };
+
+#define REDRAW_FIFO_LEN	512
+    struct vmsvga_rect_s {
+        int x, y, w, h;
+    } redraw_fifo[REDRAW_FIFO_LEN];
+    int redraw_fifo_first, redraw_fifo_last;
+};
+
+struct pci_vmsvga_state_s {
+    PCIDevice card;
+    struct vmsvga_state_s chip;
+};
+
+#define SVGA_MAGIC		0x900000UL
+#define SVGA_MAKE_ID(ver)	(SVGA_MAGIC << 8 | (ver))
+#define SVGA_ID_0		SVGA_MAKE_ID(0)
+#define SVGA_ID_1		SVGA_MAKE_ID(1)
+#define SVGA_ID_2		SVGA_MAKE_ID(2)
+
+#define SVGA_LEGACY_BASE_PORT	0x4560
+#define SVGA_INDEX_PORT		0x0
+#define SVGA_VALUE_PORT		0x1
+#define SVGA_BIOS_PORT		0x2
+
+#define SVGA_VERSION_2
+
+#ifdef SVGA_VERSION_2
+# define SVGA_ID		SVGA_ID_2
+# define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL		1
+# define SVGA_FIFO_SIZE		0x10000
+# define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA2
+#else
+# define SVGA_ID		SVGA_ID_1
+# define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL		4
+# define SVGA_FIFO_SIZE		0x10000
+# define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA
+#endif
+
+enum {
+    /* ID 0, 1 and 2 registers */
+    SVGA_REG_ID = 0,
+    SVGA_REG_ENABLE = 1,
+    SVGA_REG_WIDTH = 2,
+    SVGA_REG_HEIGHT = 3,
+    SVGA_REG_MAX_WIDTH = 4,
+    SVGA_REG_MAX_HEIGHT = 5,
+    SVGA_REG_DEPTH = 6,
+    SVGA_REG_BITS_PER_PIXEL = 7,	/* Current bpp in the guest */
+    SVGA_REG_PSEUDOCOLOR = 8,
+    SVGA_REG_RED_MASK = 9,
+    SVGA_REG_GREEN_MASK = 10,
+    SVGA_REG_BLUE_MASK = 11,
+    SVGA_REG_BYTES_PER_LINE = 12,
+    SVGA_REG_FB_START = 13,
+    SVGA_REG_FB_OFFSET = 14,
+    SVGA_REG_VRAM_SIZE = 15,
+    SVGA_REG_FB_SIZE = 16,
+
+    /* ID 1 and 2 registers */
+    SVGA_REG_CAPABILITIES = 17,
+    SVGA_REG_MEM_START = 18,		/* Memory for command FIFO */
+    SVGA_REG_MEM_SIZE = 19,
+    SVGA_REG_CONFIG_DONE = 20,		/* Set when memory area configured */
+    SVGA_REG_SYNC = 21,			/* Write to force synchronization */
+    SVGA_REG_BUSY = 22,			/* Read to check if sync is done */
+    SVGA_REG_GUEST_ID = 23,		/* Set guest OS identifier */
+    SVGA_REG_CURSOR_ID = 24,		/* ID of cursor */
+    SVGA_REG_CURSOR_X = 25,		/* Set cursor X position */
+    SVGA_REG_CURSOR_Y = 26,		/* Set cursor Y position */
+    SVGA_REG_CURSOR_ON = 27,		/* Turn cursor on/off */
+    SVGA_REG_HOST_BITS_PER_PIXEL = 28,	/* Current bpp in the host */
+    SVGA_REG_SCRATCH_SIZE = 29,		/* Number of scratch registers */
+    SVGA_REG_MEM_REGS = 30,		/* Number of FIFO registers */
+    SVGA_REG_NUM_DISPLAYS = 31,		/* Number of guest displays */
+    SVGA_REG_PITCHLOCK = 32,		/* Fixed pitch for all modes */
+
+    SVGA_PALETTE_BASE = 1024,		/* Base of SVGA color map */
+    SVGA_PALETTE_END  = SVGA_PALETTE_BASE + 767,
+    SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
+};
+
+#define SVGA_CAP_NONE			0
+#define SVGA_CAP_RECT_FILL		(1 << 0)
+#define SVGA_CAP_RECT_COPY		(1 << 1)
+#define SVGA_CAP_RECT_PAT_FILL		(1 << 2)
+#define SVGA_CAP_LEGACY_OFFSCREEN	(1 << 3)
+#define SVGA_CAP_RASTER_OP		(1 << 4)
+#define SVGA_CAP_CURSOR			(1 << 5)
+#define SVGA_CAP_CURSOR_BYPASS		(1 << 6)
+#define SVGA_CAP_CURSOR_BYPASS_2	(1 << 7)
+#define SVGA_CAP_8BIT_EMULATION		(1 << 8)
+#define SVGA_CAP_ALPHA_CURSOR		(1 << 9)
+#define SVGA_CAP_GLYPH			(1 << 10)
+#define SVGA_CAP_GLYPH_CLIPPING		(1 << 11)
+#define SVGA_CAP_OFFSCREEN_1		(1 << 12)
+#define SVGA_CAP_ALPHA_BLEND		(1 << 13)
+#define SVGA_CAP_3D			(1 << 14)
+#define SVGA_CAP_EXTENDED_FIFO		(1 << 15)
+#define SVGA_CAP_MULTIMON		(1 << 16)
+#define SVGA_CAP_PITCHLOCK		(1 << 17)
+
+/*
+ * FIFO offsets (seen as an array of 32-bit words)
+ */
+enum {
+    /*
+     * The original defined FIFO offsets
+     */
+    SVGA_FIFO_MIN = 0,
+    SVGA_FIFO_MAX,	/* The distance from MIN to MAX must be at least 10K */
+    SVGA_FIFO_NEXT_CMD,
+    SVGA_FIFO_STOP,
+
+    /*
+     * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
+     */
+    SVGA_FIFO_CAPABILITIES = 4,
+    SVGA_FIFO_FLAGS,
+    SVGA_FIFO_FENCE,
+    SVGA_FIFO_3D_HWVERSION,
+    SVGA_FIFO_PITCHLOCK,
+};
+
+#define SVGA_FIFO_CAP_NONE		0
+#define SVGA_FIFO_CAP_FENCE		(1 << 0)
+#define SVGA_FIFO_CAP_ACCELFRONT	(1 << 1)
+#define SVGA_FIFO_CAP_PITCHLOCK		(1 << 2)
+
+#define SVGA_FIFO_FLAG_NONE		0
+#define SVGA_FIFO_FLAG_ACCELFRONT	(1 << 0)
+
+/* These values can probably be changed arbitrarily.  */
+#define SVGA_SCRATCH_SIZE		0x8000
+#define SVGA_MAX_WIDTH			2360
+#define SVGA_MAX_HEIGHT			1770
+
+#ifdef VERBOSE
+# define GUEST_OS_BASE		0x5001
+static const char *vmsvga_guest_id[] = {
+    [0x00] = "Dos",
+    [0x01] = "Windows 3.1",
+    [0x02] = "Windows 95",
+    [0x03] = "Windows 98",
+    [0x04] = "Windows ME",
+    [0x05] = "Windows NT",
+    [0x06] = "Windows 2000",
+    [0x07] = "Linux",
+    [0x08] = "OS/2",
+    [0x09] = "an unknown OS",
+    [0x0a] = "BSD",
+    [0x0b] = "Whistler",
+    [0x0c] = "an unknown OS",
+    [0x0d] = "an unknown OS",
+    [0x0e] = "an unknown OS",
+    [0x0f] = "an unknown OS",
+    [0x10] = "an unknown OS",
+    [0x11] = "an unknown OS",
+    [0x12] = "an unknown OS",
+    [0x13] = "an unknown OS",
+    [0x14] = "an unknown OS",
+    [0x15] = "Windows 2003",
+};
+#endif
+
+enum {
+    SVGA_CMD_INVALID_CMD = 0,
+    SVGA_CMD_UPDATE = 1,
+    SVGA_CMD_RECT_FILL = 2,
+    SVGA_CMD_RECT_COPY = 3,
+    SVGA_CMD_DEFINE_BITMAP = 4,
+    SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
+    SVGA_CMD_DEFINE_PIXMAP = 6,
+    SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
+    SVGA_CMD_RECT_BITMAP_FILL = 8,
+    SVGA_CMD_RECT_PIXMAP_FILL = 9,
+    SVGA_CMD_RECT_BITMAP_COPY = 10,
+    SVGA_CMD_RECT_PIXMAP_COPY = 11,
+    SVGA_CMD_FREE_OBJECT = 12,
+    SVGA_CMD_RECT_ROP_FILL = 13,
+    SVGA_CMD_RECT_ROP_COPY = 14,
+    SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
+    SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
+    SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
+    SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
+    SVGA_CMD_DEFINE_CURSOR = 19,
+    SVGA_CMD_DISPLAY_CURSOR = 20,
+    SVGA_CMD_MOVE_CURSOR = 21,
+    SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+    SVGA_CMD_DRAW_GLYPH = 23,
+    SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
+    SVGA_CMD_UPDATE_VERBOSE = 25,
+    SVGA_CMD_SURFACE_FILL = 26,
+    SVGA_CMD_SURFACE_COPY = 27,
+    SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
+    SVGA_CMD_FRONT_ROP_FILL = 29,
+    SVGA_CMD_FENCE = 30,
+};
+
+/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
+enum {
+    SVGA_CURSOR_ON_HIDE = 0,
+    SVGA_CURSOR_ON_SHOW = 1,
+    SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
+    SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
+};
+
+static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+#ifndef DIRECT_VRAM
+    int line;
+    int bypl;
+    int width;
+    int start;
+    uint8_t *src;
+    uint8_t *dst;
+
+    if (x + w > s->width) {
+        fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
+                        __FUNCTION__, x, w);
+        x = MIN(x, s->width);
+        w = s->width - x;
+    }
+
+    if (y + h > s->height) {
+        fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
+                        __FUNCTION__, y, h);
+        y = MIN(y, s->height);
+        h = s->height - y;
+    }
+
+    line = h;
+    bypl = s->bypp * s->width;
+    width = s->bypp * w;
+    start = s->bypp * x + bypl * y;
+    src = s->vga.vram_ptr + start;
+    dst = ds_get_data(s->vga.ds) + start;
+
+    for (; line > 0; line --, src += bypl, dst += bypl)
+        memcpy(dst, src, width);
+#endif
+
+    dpy_update(s->vga.ds, x, y, w, h);
+}
+
+static inline void vmsvga_update_screen(struct vmsvga_state_s *s)
+{
+#ifndef DIRECT_VRAM
+    memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, s->bypp * s->width * s->height);
+#endif
+
+    dpy_update(s->vga.ds, 0, 0, s->width, s->height);
+}
+
+#ifdef DIRECT_VRAM
+# define vmsvga_update_rect_delayed	vmsvga_update_rect
+#else
+static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+    struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last ++];
+    s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
+    rect->x = x;
+    rect->y = y;
+    rect->w = w;
+    rect->h = h;
+}
+#endif
+
+static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
+{
+    struct vmsvga_rect_s *rect;
+    if (s->invalidated) {
+        s->redraw_fifo_first = s->redraw_fifo_last;
+        return;
+    }
+    /* Overlapping region updates can be optimised out here - if someone
+     * knows a smart algorithm to do that, please share.  */
+    while (s->redraw_fifo_first != s->redraw_fifo_last) {
+        rect = &s->redraw_fifo[s->redraw_fifo_first ++];
+        s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
+        vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
+    }
+}
+
+#ifdef HW_RECT_ACCEL
+static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+                int x0, int y0, int x1, int y1, int w, int h)
+{
+# ifdef DIRECT_VRAM
+    uint8_t *vram = ds_get_data(s->ds);
+# else
+    uint8_t *vram = s->vga.vram_ptr;
+# endif
+    int bypl = s->bypp * s->width;
+    int width = s->bypp * w;
+    int line = h;
+    uint8_t *ptr[2];
+
+# ifdef DIRECT_VRAM
+    if (s->ds->dpy_copy)
+        qemu_console_copy(s->ds, x0, y0, x1, y1, w, h);
+    else
+# endif
+    {
+        if (y1 > y0) {
+            ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1);
+            ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1);
+            for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl)
+                memmove(ptr[1], ptr[0], width);
+        } else {
+            ptr[0] = vram + s->bypp * x0 + bypl * y0;
+            ptr[1] = vram + s->bypp * x1 + bypl * y1;
+            for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl)
+                memmove(ptr[1], ptr[0], width);
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x1, y1, w, h);
+}
+#endif
+
+#ifdef HW_FILL_ACCEL
+static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+                uint32_t c, int x, int y, int w, int h)
+{
+# ifdef DIRECT_VRAM
+    uint8_t *vram = ds_get_data(s->ds);
+# else
+    uint8_t *vram = s->vga.vram_ptr;
+# endif
+    int bypp = s->bypp;
+    int bypl = bypp * s->width;
+    int width = bypp * w;
+    int line = h;
+    int column;
+    uint8_t *fst = vram + bypp * x + bypl * y;
+    uint8_t *dst;
+    uint8_t *src;
+    uint8_t col[4];
+
+# ifdef DIRECT_VRAM
+    if (s->ds->dpy_fill)
+        s->ds->dpy_fill(s->ds, x, y, w, h, c);
+    else
+# endif
+    {
+        col[0] = c;
+        col[1] = c >> 8;
+        col[2] = c >> 16;
+        col[3] = c >> 24;
+
+        if (line --) {
+            dst = fst;
+            src = col;
+            for (column = width; column > 0; column --) {
+                *(dst ++) = *(src ++);
+                if (src - col == bypp)
+                    src = col;
+            }
+            dst = fst;
+            for (; line > 0; line --) {
+                dst += bypl;
+                memcpy(dst, fst, width);
+            }
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x, y, w, h);
+}
+#endif
+
+struct vmsvga_cursor_definition_s {
+    int width;
+    int height;
+    int id;
+    int bpp;
+    int hot_x;
+    int hot_y;
+    uint32_t mask[1024];
+    uint32_t image[4096];
+};
+
+#define SVGA_BITMAP_SIZE(w, h)		((((w) + 31) >> 5) * (h))
+#define SVGA_PIXMAP_SIZE(w, h, bpp)	(((((w) * (bpp)) + 31) >> 5) * (h))
+
+#ifdef HW_MOUSE_ACCEL
+static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
+                struct vmsvga_cursor_definition_s *c)
+{
+    QEMUCursor *qc;
+    int i, pixels;
+
+    qc = cursor_alloc(c->width, c->height);
+    qc->hot_x = c->hot_x;
+    qc->hot_y = c->hot_y;
+    switch (c->bpp) {
+    case 1:
+        cursor_set_mono(qc, 0xffffff, 0x000000, (void*)c->image,
+                        1, (void*)c->mask);
+#ifdef DEBUG
+        cursor_print_ascii_art(qc, "vmware/mono");
+#endif
+        break;
+    case 32:
+        /* fill alpha channel from mask, set color to zero */
+        cursor_set_mono(qc, 0x000000, 0x000000, (void*)c->mask,
+                        1, (void*)c->mask);
+        /* add in rgb values */
+        pixels = c->width * c->height;
+        for (i = 0; i < pixels; i++) {
+            qc->data[i] |= c->image[i] & 0xffffff;
+        }
+#ifdef DEBUG
+        cursor_print_ascii_art(qc, "vmware/32bit");
+#endif
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n",
+                __FUNCTION__, c->bpp);
+        cursor_put(qc);
+        qc = cursor_builtin_left_ptr();
+    }
+
+    if (s->vga.ds->cursor_define)
+        s->vga.ds->cursor_define(qc);
+    cursor_put(qc);
+}
+#endif
+
+#define CMD(f)	le32_to_cpu(s->cmd->f)
+
+static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
+{
+    int num;
+    if (!s->config || !s->enable)
+        return 0;
+    num = CMD(next_cmd) - CMD(stop);
+    if (num < 0)
+        num += CMD(max) - CMD(min);
+    return num >> 2;
+}
+
+static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
+{
+    uint32_t cmd = s->fifo[CMD(stop) >> 2];
+    s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
+    if (CMD(stop) >= CMD(max))
+        s->cmd->stop = s->cmd->min;
+    return cmd;
+}
+
+static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
+{
+    return le32_to_cpu(vmsvga_fifo_read_raw(s));
+}
+
+static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+{
+    uint32_t cmd, colour;
+    int args, len;
+    int x, y, dx, dy, width, height;
+    struct vmsvga_cursor_definition_s cursor;
+    uint32_t cmd_start;
+
+    len = vmsvga_fifo_length(s);
+    while (len > 0) {
+        /* May need to go back to the start of the command if incomplete */
+        cmd_start = s->cmd->stop;
+
+        switch (cmd = vmsvga_fifo_read(s)) {
+        case SVGA_CMD_UPDATE:
+        case SVGA_CMD_UPDATE_VERBOSE:
+            len -= 5;
+            if (len < 0)
+                goto rewind;
+
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+            vmsvga_update_rect_delayed(s, x, y, width, height);
+            break;
+
+        case SVGA_CMD_RECT_FILL:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
+            colour = vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_FILL_ACCEL
+            vmsvga_fill_rect(s, colour, x, y, width, height);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_RECT_COPY:
+            len -= 7;
+            if (len < 0)
+                goto rewind;
+
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            dx = vmsvga_fifo_read(s);
+            dy = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_RECT_ACCEL
+            vmsvga_copy_rect(s, x, y, dx, dy, width, height);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_DEFINE_CURSOR:
+            len -= 8;
+            if (len < 0)
+                goto rewind;
+
+            cursor.id = vmsvga_fifo_read(s);
+            cursor.hot_x = vmsvga_fifo_read(s);
+            cursor.hot_y = vmsvga_fifo_read(s);
+            cursor.width = x = vmsvga_fifo_read(s);
+            cursor.height = y = vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            cursor.bpp = vmsvga_fifo_read(s);
+
+            args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
+            if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
+                SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image)
+                    goto badcmd;
+
+            len -= args;
+            if (len < 0)
+                goto rewind;
+
+            for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
+                cursor.mask[args] = vmsvga_fifo_read_raw(s);
+            for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++)
+                cursor.image[args] = vmsvga_fifo_read_raw(s);
+#ifdef HW_MOUSE_ACCEL
+            vmsvga_cursor_define(s, &cursor);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        /*
+         * Other commands that we at least know the number of arguments
+         * for so we can avoid FIFO desync if driver uses them illegally.
+         */
+        case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            args = x * y;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_FILL:
+            args = 6;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_COPY:
+            args = 7;
+            goto badcmd;
+        case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+            len -= 4;
+            if (len < 0)
+                goto rewind;
+
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            args = 7 + (vmsvga_fifo_read(s) >> 2);
+            goto badcmd;
+        case SVGA_CMD_SURFACE_ALPHA_BLEND:
+            args = 12;
+            goto badcmd;
+
+        /*
+         * Other commands that are not listed as depending on any
+         * CAPABILITIES bits, but are not described in the README either.
+         */
+        case SVGA_CMD_SURFACE_FILL:
+        case SVGA_CMD_SURFACE_COPY:
+        case SVGA_CMD_FRONT_ROP_FILL:
+        case SVGA_CMD_FENCE:
+        case SVGA_CMD_INVALID_CMD:
+            break; /* Nop */
+
+        default:
+            args = 0;
+        badcmd:
+            len -= args;
+            if (len < 0)
+                goto rewind;
+            while (args --)
+                vmsvga_fifo_read(s);
+            printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
+                            __FUNCTION__, cmd);
+            break;
+
+        rewind:
+            s->cmd->stop = cmd_start;
+            break;
+        }
+    }
+
+    s->syncing = 0;
+}
+
+static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
+{
+    struct vmsvga_state_s *s = opaque;
+    return s->index;
+}
+
+static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
+{
+    struct vmsvga_state_s *s = opaque;
+    s->index = index;
+}
+
+static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
+{
+    uint32_t caps;
+    struct vmsvga_state_s *s = opaque;
+    switch (s->index) {
+    case SVGA_REG_ID:
+        return s->svgaid;
+
+    case SVGA_REG_ENABLE:
+        return s->enable;
+
+    case SVGA_REG_WIDTH:
+        return s->width;
+
+    case SVGA_REG_HEIGHT:
+        return s->height;
+
+    case SVGA_REG_MAX_WIDTH:
+        return SVGA_MAX_WIDTH;
+
+    case SVGA_REG_MAX_HEIGHT:
+        return SVGA_MAX_HEIGHT;
+
+    case SVGA_REG_DEPTH:
+        return s->depth;
+
+    case SVGA_REG_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_PSEUDOCOLOR:
+        return 0x0;
+
+    case SVGA_REG_RED_MASK:
+        return s->wred;
+    case SVGA_REG_GREEN_MASK:
+        return s->wgreen;
+    case SVGA_REG_BLUE_MASK:
+        return s->wblue;
+
+    case SVGA_REG_BYTES_PER_LINE:
+        return ((s->depth + 7) >> 3) * s->new_width;
+
+    case SVGA_REG_FB_START:
+        return s->vram_base;
+
+    case SVGA_REG_FB_OFFSET:
+        return 0x0;
+
+    case SVGA_REG_VRAM_SIZE:
+        return s->vga.vram_size;
+
+    case SVGA_REG_FB_SIZE:
+        return s->fb_size;
+
+    case SVGA_REG_CAPABILITIES:
+        caps = SVGA_CAP_NONE;
+#ifdef HW_RECT_ACCEL
+        caps |= SVGA_CAP_RECT_COPY;
+#endif
+#ifdef HW_FILL_ACCEL
+        caps |= SVGA_CAP_RECT_FILL;
+#endif
+#ifdef HW_MOUSE_ACCEL
+        if (s->vga.ds->mouse_set)
+            caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
+                    SVGA_CAP_CURSOR_BYPASS;
+#endif
+        return caps;
+
+    case SVGA_REG_MEM_START:
+        return s->fifo_base;
+
+    case SVGA_REG_MEM_SIZE:
+        return s->fifo_size;
+
+    case SVGA_REG_CONFIG_DONE:
+        return s->config;
+
+    case SVGA_REG_SYNC:
+    case SVGA_REG_BUSY:
+        return s->syncing;
+
+    case SVGA_REG_GUEST_ID:
+        return s->guest;
+
+    case SVGA_REG_CURSOR_ID:
+        return s->cursor.id;
+
+    case SVGA_REG_CURSOR_X:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_Y:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_ON:
+        return s->cursor.on;
+
+    case SVGA_REG_HOST_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_SCRATCH_SIZE:
+        return s->scratch_size;
+
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        return 0;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+                s->index < SVGA_SCRATCH_BASE + s->scratch_size)
+            return s->scratch[s->index - SVGA_SCRATCH_BASE];
+        printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+    }
+
+    return 0;
+}
+
+static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
+{
+    struct vmsvga_state_s *s = opaque;
+    switch (s->index) {
+    case SVGA_REG_ID:
+        if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0)
+            s->svgaid = value;
+        break;
+
+    case SVGA_REG_ENABLE:
+        s->enable = value;
+        s->config &= !!value;
+        s->width = -1;
+        s->height = -1;
+        s->invalidated = 1;
+        s->vga.invalidate(&s->vga);
+        if (s->enable) {
+            s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
+            vga_dirty_log_stop(&s->vga);
+        } else {
+            vga_dirty_log_start(&s->vga);
+        }
+        break;
+
+    case SVGA_REG_WIDTH:
+        s->new_width = value;
+        s->invalidated = 1;
+        break;
+
+    case SVGA_REG_HEIGHT:
+        s->new_height = value;
+        s->invalidated = 1;
+        break;
+
+    case SVGA_REG_DEPTH:
+    case SVGA_REG_BITS_PER_PIXEL:
+        if (value != s->depth) {
+            printf("%s: Bad colour depth: %i bits\n", __FUNCTION__, value);
+            s->config = 0;
+        }
+        break;
+
+    case SVGA_REG_CONFIG_DONE:
+        if (value) {
+            s->fifo = (uint32_t *) s->fifo_ptr;
+            /* Check range and alignment.  */
+            if ((CMD(min) | CMD(max) |
+                        CMD(next_cmd) | CMD(stop)) & 3)
+                break;
+            if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo)
+                break;
+            if (CMD(max) > SVGA_FIFO_SIZE)
+                break;
+            if (CMD(max) < CMD(min) + 10 * 1024)
+                break;
+        }
+        s->config = !!value;
+        break;
+
+    case SVGA_REG_SYNC:
+        s->syncing = 1;
+        vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
+        break;
+
+    case SVGA_REG_GUEST_ID:
+        s->guest = value;
+#ifdef VERBOSE
+        if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
+                ARRAY_SIZE(vmsvga_guest_id))
+            printf("%s: guest runs %s.\n", __FUNCTION__,
+                            vmsvga_guest_id[value - GUEST_OS_BASE]);
+#endif
+        break;
+
+    case SVGA_REG_CURSOR_ID:
+        s->cursor.id = value;
+        break;
+
+    case SVGA_REG_CURSOR_X:
+        s->cursor.x = value;
+        break;
+
+    case SVGA_REG_CURSOR_Y:
+        s->cursor.y = value;
+        break;
+
+    case SVGA_REG_CURSOR_ON:
+        s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
+        s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
+#ifdef HW_MOUSE_ACCEL
+        if (s->vga.ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW)
+            s->vga.ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on);
+#endif
+        break;
+
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        break;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+                s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
+            s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
+            break;
+        }
+        printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+    }
+}
+
+static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
+{
+    printf("%s: what are we supposed to return?\n", __FUNCTION__);
+    return 0xcafe;
+}
+
+static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
+{
+    printf("%s: what are we supposed to do with (%08x)?\n",
+                    __FUNCTION__, data);
+}
+
+static inline void vmsvga_size(struct vmsvga_state_s *s)
+{
+    if (s->new_width != s->width || s->new_height != s->height) {
+        s->width = s->new_width;
+        s->height = s->new_height;
+        qemu_console_resize(s->vga.ds, s->width, s->height);
+        s->invalidated = 1;
+    }
+}
+
+static void vmsvga_update_display(void *opaque)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (!s->enable) {
+        s->vga.update(&s->vga);
+        return;
+    }
+
+    vmsvga_size(s);
+
+    vmsvga_fifo_run(s);
+    vmsvga_update_rect_flush(s);
+
+    /*
+     * Is it more efficient to look at vram VGA-dirty bits or wait
+     * for the driver to issue SVGA_CMD_UPDATE?
+     */
+    if (s->invalidated) {
+        s->invalidated = 0;
+        vmsvga_update_screen(s);
+    }
+}
+
+static void vmsvga_reset(struct vmsvga_state_s *s)
+{
+    s->index = 0;
+    s->enable = 0;
+    s->config = 0;
+    s->width = -1;
+    s->height = -1;
+    s->svgaid = SVGA_ID;
+    s->depth = ds_get_bits_per_pixel(s->vga.ds);
+    s->bypp = ds_get_bytes_per_pixel(s->vga.ds);
+    s->cursor.on = 0;
+    s->redraw_fifo_first = 0;
+    s->redraw_fifo_last = 0;
+    switch (s->depth) {
+    case 8:
+        s->wred   = 0x00000007;
+        s->wgreen = 0x00000038;
+        s->wblue  = 0x000000c0;
+        break;
+    case 15:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000003e0;
+        s->wblue  = 0x00007c00;
+        break;
+    case 16:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000007e0;
+        s->wblue  = 0x0000f800;
+        break;
+    case 24:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    case 32:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    }
+    s->syncing = 0;
+
+    vga_dirty_log_start(&s->vga);
+}
+
+static void vmsvga_invalidate_display(void *opaque)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (!s->enable) {
+        s->vga.invalidate(&s->vga);
+        return;
+    }
+
+    s->invalidated = 1;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vmsvga_screen_dump(void *opaque, const char *filename)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (!s->enable) {
+        s->vga.screen_dump(&s->vga, filename);
+        return;
+    }
+
+    if (s->depth == 32) {
+        DisplaySurface *ds = qemu_create_displaysurface_from(s->width,
+                s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr);
+        ppm_save(filename, ds);
+        qemu_free(ds);
+    }
+}
+
+static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    if (s->vga.text_update)
+        s->vga.text_update(&s->vga, chardata);
+}
+
+#ifdef DIRECT_VRAM
+static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        return *(uint8_t *) (ds_get_data(s->ds) + addr);
+    else
+        return *(uint8_t *) (s->vram_ptr + addr);
+}
+
+static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        return *(uint16_t *) (ds_get_data(s->ds) + addr);
+    else
+        return *(uint16_t *) (s->vram_ptr + addr);
+}
+
+static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        return *(uint32_t *) (ds_get_data(s->ds) + addr);
+    else
+        return *(uint32_t *) (s->vram_ptr + addr);
+}
+
+static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        *(uint8_t *) (ds_get_data(s->ds) + addr) = value;
+    else
+        *(uint8_t *) (s->vram_ptr + addr) = value;
+}
+
+static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        *(uint16_t *) (ds_get_data(s->ds) + addr) = value;
+    else
+        *(uint16_t *) (s->vram_ptr + addr) = value;
+}
+
+static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (addr < s->fb_size)
+        *(uint32_t *) (ds_get_data(s->ds) + addr) = value;
+    else
+        *(uint32_t *) (s->vram_ptr + addr) = value;
+}
+
+static CPUReadMemoryFunc * const vmsvga_vram_read[] = {
+    vmsvga_vram_readb,
+    vmsvga_vram_readw,
+    vmsvga_vram_readl,
+};
+
+static CPUWriteMemoryFunc * const vmsvga_vram_write[] = {
+    vmsvga_vram_writeb,
+    vmsvga_vram_writew,
+    vmsvga_vram_writel,
+};
+#endif
+
+static int vmsvga_post_load(void *opaque, int version_id)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    s->invalidated = 1;
+    if (s->config)
+        s->fifo = (uint32_t *) s->fifo_ptr;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmware_vga_internal = {
+    .name = "vmware_vga_internal",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = vmsvga_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(depth, struct vmsvga_state_s),
+        VMSTATE_INT32(enable, struct vmsvga_state_s),
+        VMSTATE_INT32(config, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.id, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.x, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.y, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.on, struct vmsvga_state_s),
+        VMSTATE_INT32(index, struct vmsvga_state_s),
+        VMSTATE_VARRAY_INT32(scratch, struct vmsvga_state_s,
+                             scratch_size, 0, vmstate_info_uint32, uint32_t),
+        VMSTATE_INT32(new_width, struct vmsvga_state_s),
+        VMSTATE_INT32(new_height, struct vmsvga_state_s),
+        VMSTATE_UINT32(guest, struct vmsvga_state_s),
+        VMSTATE_UINT32(svgaid, struct vmsvga_state_s),
+        VMSTATE_INT32(syncing, struct vmsvga_state_s),
+        VMSTATE_INT32(fb_size, struct vmsvga_state_s),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_vmware_vga = {
+    .name = "vmware_vga",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(card, struct pci_vmsvga_state_s),
+        VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0,
+                       vmstate_vmware_vga_internal, struct vmsvga_state_s),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
+{
+    s->scratch_size = SVGA_SCRATCH_SIZE;
+    s->scratch = qemu_malloc(s->scratch_size * 4);
+
+    s->vga.ds = graphic_console_init(vmsvga_update_display,
+                                     vmsvga_invalidate_display,
+                                     vmsvga_screen_dump,
+                                     vmsvga_text_update, s);
+
+
+    s->fifo_size = SVGA_FIFO_SIZE;
+    s->fifo_offset = qemu_ram_alloc(NULL, "vmsvga.fifo", s->fifo_size);
+    s->fifo_ptr = qemu_get_ram_ptr(s->fifo_offset);
+
+    vga_common_init(&s->vga, vga_ram_size);
+    vga_init(&s->vga);
+    vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
+
+    vmsvga_reset(s);
+}
+
+static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
+                pcibus_t addr, pcibus_t size, int type)
+{
+    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
+    struct vmsvga_state_s *s = &d->chip;
+
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_write, s);
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_write, s);
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_write, s);
+}
+
+static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
+                pcibus_t addr, pcibus_t size, int type)
+{
+    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
+    struct vmsvga_state_s *s = &d->chip;
+    ram_addr_t iomemtype;
+
+    s->vram_base = addr;
+#ifdef DIRECT_VRAM
+    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
+                    vmsvga_vram_write, s, DEVICE_NATIVE_ENDIAN);
+#else
+    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
+#endif
+    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
+                    iomemtype);
+
+    s->vga.map_addr = addr;
+    s->vga.map_end = addr + s->vga.vram_size;
+    vga_dirty_log_restart(&s->vga);
+}
+
+static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
+                pcibus_t addr, pcibus_t size, int type)
+{
+    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
+    struct vmsvga_state_s *s = &d->chip;
+    ram_addr_t iomemtype;
+
+    s->fifo_base = addr;
+    iomemtype = s->fifo_offset | IO_MEM_RAM;
+    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
+                    iomemtype);
+}
+
+static int pci_vmsvga_initfn(PCIDevice *dev)
+{
+    struct pci_vmsvga_state_s *s =
+        DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+
+    s->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;		/* Cache line size */
+    s->card.config[PCI_LATENCY_TIMER] = 0x40;		/* Latency timer */
+    s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
+
+    pci_register_bar(&s->card, 0, 0x10,
+                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
+    pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
+                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
+
+    pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
+                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
+
+    vmsvga_init(&s->chip, VGA_RAM_SIZE);
+
+    if (!dev->rom_bar) {
+        /* compatibility with pc-0.13 and older */
+        vga_init_vbe(&s->chip.vga);
+    }
+
+    return 0;
+}
+
+static PCIDeviceInfo vmsvga_info = {
+    .qdev.name    = "vmware-svga",
+    .qdev.size    = sizeof(struct pci_vmsvga_state_s),
+    .qdev.vmsd    = &vmstate_vmware_vga,
+    .no_hotplug   = 1,
+    .init         = pci_vmsvga_initfn,
+    .romfile      = "vgabios-vmware.bin",
+
+    .vendor_id    =  PCI_VENDOR_ID_VMWARE,
+    .device_id    = SVGA_PCI_DEVICE_ID,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+    .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
+    .subsystem_id = SVGA_PCI_DEVICE_ID,
+};
+
+static void vmsvga_register(void)
+{
+    pci_qdev_register(&vmsvga_info);
+}
+device_init(vmsvga_register);
diff --git a/qemu-0.15.x/hw/vmware_vga.h b/qemu-0.15.x/hw/vmware_vga.h
new file mode 100644
index 0000000..5132573
--- /dev/null
+++ b/qemu-0.15.x/hw/vmware_vga.h
@@ -0,0 +1,19 @@
+#ifndef QEMU_VMWARE_VGA_H
+#define QEMU_VMWARE_VGA_H
+
+#include "qemu-common.h"
+
+/* vmware_vga.c */
+static inline bool pci_vmsvga_init(PCIBus *bus)
+{
+    PCIDevice *dev;
+
+    dev = pci_try_create(bus, -1, "vmware-svga");
+    if (!dev || qdev_init(&dev->qdev) < 0) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+#endif
diff --git a/qemu-0.15.x/hw/vt82c686.c b/qemu-0.15.x/hw/vt82c686.c
new file mode 100644
index 0000000..5c973ed
--- /dev/null
+++ b/qemu-0.15.x/hw/vt82c686.c
@@ -0,0 +1,537 @@
+/*
+ * VT82C686B south bridge support
+ *
+ * Copyright (c) 2008 yajin (yajin at vm-kernel.org)
+ * Copyright (c) 2009 chenming (chenming at rdc.faw.com.cn)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "vt82c686.h"
+#include "i2c.h"
+#include "smbus.h"
+#include "pci.h"
+#include "isa.h"
+#include "sysbus.h"
+#include "mips.h"
+#include "apm.h"
+#include "acpi.h"
+#include "pm_smbus.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+//#define DEBUG_VT82C686B
+
+#ifdef DEBUG_VT82C686B
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+typedef struct SuperIOConfig
+{
+    uint8_t config[0xff];
+    uint8_t index;
+    uint8_t data;
+} SuperIOConfig;
+
+typedef struct VT82C686BState {
+    PCIDevice dev;
+    SuperIOConfig superio_conf;
+} VT82C686BState;
+
+static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
+{
+    int can_write;
+    SuperIOConfig *superio_conf = opaque;
+
+    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x  \n", addr, data);
+    if (addr == 0x3f0) {
+        superio_conf->index = data & 0xff;
+    } else {
+        /* 0x3f1 */
+        switch (superio_conf->index) {
+        case 0x00 ... 0xdf:
+        case 0xe4:
+        case 0xe5:
+        case 0xe9 ... 0xed:
+        case 0xf3:
+        case 0xf5:
+        case 0xf7:
+        case 0xf9 ... 0xfb:
+        case 0xfd ... 0xff:
+            can_write = 0;
+            break;
+        default:
+            can_write = 1;
+
+            if (can_write) {
+                switch (superio_conf->index) {
+                case 0xe7:
+                    if ((data & 0xff) != 0xfe) {
+                        DPRINTF("chage uart 1 base. unsupported yet \n");
+                    }
+                    break;
+                case 0xe8:
+                    if ((data & 0xff) != 0xbe) {
+                        DPRINTF("chage uart 2 base. unsupported yet \n");
+                    }
+                    break;
+
+                default:
+                    superio_conf->config[superio_conf->index] = data & 0xff;
+                }
+            }
+        }
+        superio_conf->config[superio_conf->index] = data & 0xff;
+    }
+}
+
+static uint32_t superio_ioport_readb(void *opaque, uint32_t addr)
+{
+    SuperIOConfig *superio_conf = opaque;
+
+    DPRINTF("superio_ioport_readb  address 0x%x   \n", addr);
+    return (superio_conf->config[superio_conf->index]);
+}
+
+static void vt82c686b_reset(void * opaque)
+{
+    PCIDevice *d = opaque;
+    uint8_t *pci_conf = d->config;
+    VT82C686BState *vt82c = DO_UPCAST(VT82C686BState, dev, d);
+
+    pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                 PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_conf[0x48] = 0x01; /* Miscellaneous Control 3 */
+    pci_conf[0x4a] = 0x04; /* IDE interrupt Routing */
+    pci_conf[0x4f] = 0x03; /* DMA/Master Mem Access Control 3 */
+    pci_conf[0x50] = 0x2d; /* PnP DMA Request Control */
+    pci_conf[0x59] = 0x04;
+    pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/
+    pci_conf[0x5f] = 0x04;
+    pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
+
+    vt82c->superio_conf.config[0xe0] = 0x3c;
+    vt82c->superio_conf.config[0xe2] = 0x03;
+    vt82c->superio_conf.config[0xe3] = 0xfc;
+    vt82c->superio_conf.config[0xe6] = 0xde;
+    vt82c->superio_conf.config[0xe7] = 0xfe;
+    vt82c->superio_conf.config[0xe8] = 0xbe;
+}
+
+/* write config pci function0 registers. PCI-ISA bridge */
+static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
+                                   uint32_t val, int len)
+{
+    VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d);
+
+    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x \n",
+           address, val, len);
+
+    pci_default_write_config(d, address, val, len);
+    if (address == 0x85) {  /* enable or disable super IO configure */
+        if (val & 0x2) {
+            /* floppy also uses 0x3f0 and 0x3f1.
+             * But we do not emulate flopy,so just set it here. */
+            isa_unassign_ioport(0x3f0, 2);
+            register_ioport_read(0x3f0, 2, 1, superio_ioport_readb,
+                                 &vt686->superio_conf);
+            register_ioport_write(0x3f0, 2, 1, superio_ioport_writeb,
+                                  &vt686->superio_conf);
+        } else {
+            isa_unassign_ioport(0x3f0, 2);
+        }
+    }
+}
+
+#define ACPI_DBG_IO_ADDR  0xb044
+
+typedef struct VT686PMState {
+    PCIDevice dev;
+    ACPIPM1EVT pm1a;
+    ACPIPM1CNT pm1_cnt;
+    APMState apm;
+    ACPIPMTimer tmr;
+    PMSMBus smb;
+    uint32_t smb_io_base;
+} VT686PMState;
+
+typedef struct VT686AC97State {
+    PCIDevice dev;
+} VT686AC97State;
+
+typedef struct VT686MC97State {
+    PCIDevice dev;
+} VT686MC97State;
+
+static void pm_update_sci(VT686PMState *s)
+{
+    int sci_level, pmsts;
+
+    pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+    sci_level = (((pmsts & s->pm1a.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
+    qemu_set_irq(s->dev.irq[0], sci_level);
+    /* schedule a timer interruption if needed */
+    acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
+}
+
+static void pm_tmr_timer(ACPIPMTimer *tmr)
+{
+    VT686PMState *s = container_of(tmr, VT686PMState, tmr);
+    pm_update_sci(s);
+}
+
+static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    VT686PMState *s = opaque;
+
+    addr &= 0x0f;
+    switch (addr) {
+    case 0x00:
+        acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+        pm_update_sci(s);
+        break;
+    case 0x02:
+        s->pm1a.en = val;
+        pm_update_sci(s);
+        break;
+    case 0x04:
+        acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
+        break;
+    default:
+        break;
+    }
+    DPRINTF("PM writew port=0x%04x val=0x%02x\n", addr, val);
+}
+
+static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
+{
+    VT686PMState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x0f;
+    switch (addr) {
+    case 0x00:
+        val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+        break;
+    case 0x02:
+        val = s->pm1a.en;
+        break;
+    case 0x04:
+        val = s->pm1_cnt.cnt;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    DPRINTF("PM readw port=0x%04x val=0x%02x\n", addr, val);
+    return val;
+}
+
+static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 0x0f;
+    DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr, val);
+}
+
+static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
+{
+    VT686PMState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x0f;
+    switch (addr) {
+    case 0x08:
+        val = acpi_pm_tmr_get(&s->tmr);
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val);
+    return val;
+}
+
+static void pm_io_space_update(VT686PMState *s)
+{
+    uint32_t pm_io_base;
+
+    if (s->dev.config[0x80] & 1) {
+        pm_io_base = pci_get_long(s->dev.config + 0x40);
+        pm_io_base &= 0xffc0;
+
+        /* XXX: need to improve memory and ioport allocation */
+        DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
+        register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
+        register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
+        register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
+        register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
+    }
+}
+
+static void pm_write_config(PCIDevice *d,
+                            uint32_t address, uint32_t val, int len)
+{
+    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x \n",
+           address, val, len);
+    pci_default_write_config(d, address, val, len);
+}
+
+static int vmstate_acpi_post_load(void *opaque, int version_id)
+{
+    VT686PMState *s = opaque;
+
+    pm_io_space_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_acpi = {
+    .name = "vt82c686b_pm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_acpi_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, VT686PMState),
+        VMSTATE_UINT16(pm1a.sts, VT686PMState),
+        VMSTATE_UINT16(pm1a.en, VT686PMState),
+        VMSTATE_UINT16(pm1_cnt.cnt, VT686PMState),
+        VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
+        VMSTATE_TIMER(tmr.timer, VT686PMState),
+        VMSTATE_INT64(tmr.overflow_time, VT686PMState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * TODO: vt82c686b_ac97_init() and vt82c686b_mc97_init()
+ * just register a PCI device now, functionalities will be implemented later.
+ */
+
+static int vt82c686b_ac97_initfn(PCIDevice *dev)
+{
+    VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
+                 PCI_COMMAND_PARITY);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
+
+    return 0;
+}
+
+void vt82c686b_ac97_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, devfn, "VT82C686B_AC97");
+    qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo via_ac97_info = {
+    .qdev.name          = "VT82C686B_AC97",
+    .qdev.desc          = "AC97",
+    .qdev.size          = sizeof(VT686AC97State),
+    .init               = vt82c686b_ac97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_AC97,
+    .revision           = 0x50,
+    .class_id           = PCI_CLASS_MULTIMEDIA_AUDIO,
+};
+
+static void vt82c686b_ac97_register(void)
+{
+    pci_qdev_register(&via_ac97_info);
+}
+
+device_init(vt82c686b_ac97_register);
+
+static int vt82c686b_mc97_initfn(PCIDevice *dev)
+{
+    VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
+                 PCI_COMMAND_VGA_PALETTE);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
+
+    return 0;
+}
+
+void vt82c686b_mc97_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, devfn, "VT82C686B_MC97");
+    qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo via_mc97_info = {
+    .qdev.name          = "VT82C686B_MC97",
+    .qdev.desc          = "MC97",
+    .qdev.size          = sizeof(VT686MC97State),
+    .init               = vt82c686b_mc97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_MC97,
+    .class_id           = PCI_CLASS_COMMUNICATION_OTHER,
+    .revision           = 0x30,
+};
+
+static void vt82c686b_mc97_register(void)
+{
+    pci_qdev_register(&via_mc97_info);
+}
+
+device_init(vt82c686b_mc97_register);
+
+/* vt82c686 pm init */
+static int vt82c686b_pm_initfn(PCIDevice *dev)
+{
+    VT686PMState *s = DO_UPCAST(VT686PMState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_set_word(pci_conf + PCI_COMMAND, 0);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+
+    /* 0x48-0x4B is Power Management I/O Base */
+    pci_set_long(pci_conf + 0x48, 0x00000001);
+
+    /* SMB ports:0xeee0~0xeeef */
+    s->smb_io_base =((s->smb_io_base & 0xfff0) + 0x0);
+    pci_conf[0x90] = s->smb_io_base | 1;
+    pci_conf[0x91] = s->smb_io_base >> 8;
+    pci_conf[0xd2] = 0x90;
+    register_ioport_write(s->smb_io_base, 0xf, 1, smb_ioport_writeb, &s->smb);
+    register_ioport_read(s->smb_io_base, 0xf, 1, smb_ioport_readb, &s->smb);
+
+    apm_init(&s->apm, NULL, s);
+
+    acpi_pm_tmr_init(&s->tmr, pm_tmr_timer);
+    acpi_pm1_cnt_init(&s->pm1_cnt, NULL);
+
+    pm_smbus_init(&s->dev.qdev, &s->smb);
+
+    return 0;
+}
+
+i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq)
+{
+    PCIDevice *dev;
+    VT686PMState *s;
+
+    dev = pci_create(bus, devfn, "VT82C686B_PM");
+    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+
+    s = DO_UPCAST(VT686PMState, dev, dev);
+
+    qdev_init_nofail(&dev->qdev);
+
+    return s->smb.smbus;
+}
+
+static PCIDeviceInfo via_pm_info = {
+    .qdev.name          = "VT82C686B_PM",
+    .qdev.desc          = "PM",
+    .qdev.size          = sizeof(VT686PMState),
+    .qdev.vmsd          = &vmstate_acpi,
+    .init               = vt82c686b_pm_initfn,
+    .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_ACPI,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
+    .revision           = 0x40,
+    .qdev.props         = (Property[]) {
+        DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void vt82c686b_pm_register(void)
+{
+    pci_qdev_register(&via_pm_info);
+}
+
+device_init(vt82c686b_pm_register);
+
+static const VMStateDescription vmstate_via = {
+    .name = "vt82c686b",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, VT82C686BState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* init the PCI-to-ISA bridge */
+static int vt82c686b_initfn(PCIDevice *d)
+{
+    uint8_t *pci_conf;
+    uint8_t *wmask;
+    int i;
+
+    isa_bus_new(&d->qdev);
+
+    pci_conf = d->config;
+    pci_config_set_prog_interface(pci_conf, 0x0);
+
+    wmask = d->wmask;
+    for (i = 0x00; i < 0xff; i++) {
+       if (i<=0x03 || (i>=0x08 && i<=0x3f)) {
+           wmask[i] = 0x00;
+       }
+    }
+
+    qemu_register_reset(vt82c686b_reset, d);
+
+    return 0;
+}
+
+int vt82c686b_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+
+    d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B");
+
+    return d->devfn;
+}
+
+static PCIDeviceInfo via_info = {
+    .qdev.name    = "VT82C686B",
+    .qdev.desc    = "ISA bridge",
+    .qdev.size    = sizeof(VT82C686BState),
+    .qdev.vmsd    = &vmstate_via,
+    .qdev.no_user = 1,
+    .init         = vt82c686b_initfn,
+    .config_write = vt82c686b_write_config,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
+    .class_id     = PCI_CLASS_BRIDGE_ISA,
+    .revision     = 0x40,
+};
+
+static void vt82c686b_register(void)
+{
+    pci_qdev_register(&via_info);
+}
+device_init(vt82c686b_register);
diff --git a/qemu-0.15.x/hw/vt82c686.h b/qemu-0.15.x/hw/vt82c686.h
new file mode 100644
index 0000000..e3270ca
--- /dev/null
+++ b/qemu-0.15.x/hw/vt82c686.h
@@ -0,0 +1,11 @@
+#ifndef HW_VT82C686_H
+#define HW_VT82C686_H
+
+/* vt82c686.c */
+int vt82c686b_init(PCIBus * bus, int devfn);
+void vt82c686b_ac97_init(PCIBus *bus, int devfn);
+void vt82c686b_mc97_init(PCIBus *bus, int devfn);
+i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+            qemu_irq sci_irq);
+
+#endif
diff --git a/qemu-0.15.x/hw/watchdog.c b/qemu-0.15.x/hw/watchdog.c
new file mode 100644
index 0000000..1c900a1
--- /dev/null
+++ b/qemu-0.15.x/hw/watchdog.c
@@ -0,0 +1,147 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * By Richard W.M. Jones (rjones at redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "qemu-queue.h"
+#include "qemu-objects.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "hw/watchdog.h"
+
+/* Possible values for action parameter. */
+#define WDT_RESET        1	/* Hard reset. */
+#define WDT_SHUTDOWN     2	/* Shutdown. */
+#define WDT_POWEROFF     3	/* Quit. */
+#define WDT_PAUSE        4	/* Pause. */
+#define WDT_DEBUG        5	/* Prints a message and continues running. */
+#define WDT_NONE         6	/* Do nothing. */
+
+static int watchdog_action = WDT_RESET;
+static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
+
+void watchdog_add_model(WatchdogTimerModel *model)
+{
+    QLIST_INSERT_HEAD(&watchdog_list, model, entry);
+}
+
+/* Returns:
+ *   0 = continue
+ *   1 = exit program with error
+ *   2 = exit program without error
+ */
+int select_watchdog(const char *p)
+{
+    WatchdogTimerModel *model;
+    QemuOpts *opts;
+
+    /* -watchdog ? lists available devices and exits cleanly. */
+    if (strcmp(p, "?") == 0) {
+        QLIST_FOREACH(model, &watchdog_list, entry) {
+            fprintf(stderr, "\t%s\t%s\n",
+                     model->wdt_name, model->wdt_description);
+        }
+        return 2;
+    }
+
+    QLIST_FOREACH(model, &watchdog_list, entry) {
+        if (strcasecmp(model->wdt_name, p) == 0) {
+            /* add the device */
+            opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+            qemu_opt_set(opts, "driver", p);
+            return 0;
+        }
+    }
+
+    fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
+    QLIST_FOREACH(model, &watchdog_list, entry) {
+        fprintf(stderr, "\t%s\t%s\n",
+                 model->wdt_name, model->wdt_description);
+    }
+    return 1;
+}
+
+int select_watchdog_action(const char *p)
+{
+    if (strcasecmp(p, "reset") == 0)
+        watchdog_action = WDT_RESET;
+    else if (strcasecmp(p, "shutdown") == 0)
+        watchdog_action = WDT_SHUTDOWN;
+    else if (strcasecmp(p, "poweroff") == 0)
+        watchdog_action = WDT_POWEROFF;
+    else if (strcasecmp(p, "pause") == 0)
+        watchdog_action = WDT_PAUSE;
+    else if (strcasecmp(p, "debug") == 0)
+        watchdog_action = WDT_DEBUG;
+    else if (strcasecmp(p, "none") == 0)
+        watchdog_action = WDT_NONE;
+    else
+        return -1;
+
+    return 0;
+}
+
+static void watchdog_mon_event(const char *action)
+{
+    QObject *data;
+
+    data = qobject_from_jsonf("{ 'action': %s }", action);
+    monitor_protocol_event(QEVENT_WATCHDOG, data);
+    qobject_decref(data);
+}
+
+/* This actually performs the "action" once a watchdog has expired,
+ * ie. reboot, shutdown, exit, etc.
+ */
+void watchdog_perform_action(void)
+{
+    switch(watchdog_action) {
+    case WDT_RESET:             /* same as 'system_reset' in monitor */
+        watchdog_mon_event("reset");
+        qemu_system_reset_request();
+        break;
+
+    case WDT_SHUTDOWN:          /* same as 'system_powerdown' in monitor */
+        watchdog_mon_event("shutdown");
+        qemu_system_powerdown_request();
+        break;
+
+    case WDT_POWEROFF:          /* same as 'quit' command in monitor */
+        watchdog_mon_event("poweroff");
+        exit(0);
+        break;
+
+    case WDT_PAUSE:             /* same as 'stop' command in monitor */
+        watchdog_mon_event("pause");
+        vm_stop(VMSTOP_WATCHDOG);
+        break;
+
+    case WDT_DEBUG:
+        watchdog_mon_event("debug");
+        fprintf(stderr, "watchdog: timer fired\n");
+        break;
+
+    case WDT_NONE:
+        watchdog_mon_event("none");
+        break;
+    }
+}
diff --git a/qemu-0.15.x/hw/watchdog.h b/qemu-0.15.x/hw/watchdog.h
new file mode 100644
index 0000000..c12a293
--- /dev/null
+++ b/qemu-0.15.x/hw/watchdog.h
@@ -0,0 +1,43 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * By Richard W.M. Jones (rjones at redhat.com).
+ */
+
+#ifndef QEMU_WATCHDOG_H
+#define QEMU_WATCHDOG_H
+
+#include "qemu-queue.h"
+
+struct WatchdogTimerModel {
+    QLIST_ENTRY(WatchdogTimerModel) entry;
+
+    /* Short name of the device - used to select it on the command line. */
+    const char *wdt_name;
+    /* Longer description (eg. manufacturer and full model number). */
+    const char *wdt_description;
+};
+typedef struct WatchdogTimerModel WatchdogTimerModel;
+
+/* in hw/watchdog.c */
+int select_watchdog(const char *p);
+int select_watchdog_action(const char *action);
+void watchdog_add_model(WatchdogTimerModel *model);
+void watchdog_perform_action(void);
+
+#endif /* QEMU_WATCHDOG_H */
diff --git a/qemu-0.15.x/hw/wdt_i6300esb.c b/qemu-0.15.x/hw/wdt_i6300esb.c
new file mode 100644
index 0000000..53786ce
--- /dev/null
+++ b/qemu-0.15.x/hw/wdt_i6300esb.c
@@ -0,0 +1,433 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * By Richard W.M. Jones (rjones at redhat.com).
+ */
+
+#include <inttypes.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "hw.h"
+#include "pci.h"
+
+/*#define I6300ESB_DEBUG 1*/
+
+#ifdef I6300ESB_DEBUG
+#define i6300esb_debug(fs,...) \
+    fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define i6300esb_debug(fs,...)
+#endif
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG  0x60            /* Config register                   */
+#define ESB_LOCK_REG    0x68            /* WDT lock register                 */
+
+/* Memory mapped registers (offset from base address) */
+#define ESB_TIMER1_REG  0x00            /* Timer1 value after each reset     */
+#define ESB_TIMER2_REG  0x04            /* Timer2 value after each reset     */
+#define ESB_GINTSR_REG  0x08            /* General Interrupt Status Register */
+#define ESB_RELOAD_REG  0x0c            /* Reload register                   */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC    (0x01 << 2)   /* Watchdog functionality            */
+#define ESB_WDT_ENABLE  (0x01 << 1)   /* Enable WDT                        */
+#define ESB_WDT_LOCK    (0x01 << 0)   /* Lock (nowayout)                   */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT  (0x01 << 5)   /* Enable reboot on timeout          */
+#define ESB_WDT_FREQ    (0x01 << 2)   /* Decrement frequency               */
+#define ESB_WDT_INTTYPE (0x11 << 0)   /* Interrupt type on timer1 timeout  */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD  (0x01 << 8)    /* prevent timeout                   */
+
+/* Magic constants */
+#define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
+#define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
+
+/* Device state. */
+struct I6300State {
+    PCIDevice dev;
+
+    int reboot_enabled;         /* "Reboot" on timer expiry.  The real action
+                                 * performed depends on the -watchdog-action
+                                 * param passed on QEMU command line.
+                                 */
+    int clock_scale;            /* Clock scale. */
+#define CLOCK_SCALE_1KHZ 0
+#define CLOCK_SCALE_1MHZ 1
+
+    int int_type;               /* Interrupt type generated. */
+#define INT_TYPE_IRQ 0          /* APIC 1, INT 10 */
+#define INT_TYPE_SMI 2
+#define INT_TYPE_DISABLED 3
+
+    int free_run;               /* If true, reload timer on expiry. */
+    int locked;                 /* If true, enabled field cannot be changed. */
+    int enabled;                /* If true, watchdog is enabled. */
+
+    QEMUTimer *timer;           /* The actual watchdog timer. */
+
+    uint32_t timer1_preload;    /* Values preloaded into timer1, timer2. */
+    uint32_t timer2_preload;
+    int stage;                  /* Stage (1 or 2). */
+
+    int unlock_state;           /* Guest writes 0x80, 0x86 to unlock the
+                                 * registers, and we transition through
+                                 * states 0 -> 1 -> 2 when this happens.
+                                 */
+
+    int previous_reboot_flag;   /* If the watchdog caused the previous
+                                 * reboot, this flag will be set.
+                                 */
+};
+
+typedef struct I6300State I6300State;
+
+/* This function is called when the watchdog has either been enabled
+ * (hence it starts counting down) or has been keep-alived.
+ */
+static void i6300esb_restart_timer(I6300State *d, int stage)
+{
+    int64_t timeout;
+
+    if (!d->enabled)
+        return;
+
+    d->stage = stage;
+
+    if (d->stage <= 1)
+        timeout = d->timer1_preload;
+    else
+        timeout = d->timer2_preload;
+
+    if (d->clock_scale == CLOCK_SCALE_1KHZ)
+        timeout <<= 15;
+    else
+        timeout <<= 5;
+
+    /* Get the timeout in units of ticks_per_sec. */
+    timeout = get_ticks_per_sec() * timeout / 33000000;
+
+    i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
+
+    qemu_mod_timer(d->timer, qemu_get_clock_ns(vm_clock) + timeout);
+}
+
+/* This is called when the guest disables the watchdog. */
+static void i6300esb_disable_timer(I6300State *d)
+{
+    i6300esb_debug("timer disabled\n");
+
+    qemu_del_timer(d->timer);
+}
+
+static void i6300esb_reset(DeviceState *dev)
+{
+    PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+    I6300State *d = DO_UPCAST(I6300State, dev, pdev);
+
+    i6300esb_debug("I6300State = %p\n", d);
+
+    i6300esb_disable_timer(d);
+
+    /* NB: Don't change d->previous_reboot_flag in this function. */
+
+    d->reboot_enabled = 1;
+    d->clock_scale = CLOCK_SCALE_1KHZ;
+    d->int_type = INT_TYPE_IRQ;
+    d->free_run = 0;
+    d->locked = 0;
+    d->enabled = 0;
+    d->timer1_preload = 0xfffff;
+    d->timer2_preload = 0xfffff;
+    d->stage = 1;
+    d->unlock_state = 0;
+}
+
+/* This function is called when the watchdog expires.  Note that
+ * the hardware has two timers, and so expiry happens in two stages.
+ * If d->stage == 1 then we perform the first stage action (usually,
+ * sending an interrupt) and then restart the timer again for the
+ * second stage.  If the second stage expires then the watchdog
+ * really has run out.
+ */
+static void i6300esb_timer_expired(void *vp)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("stage %d\n", d->stage);
+
+    if (d->stage == 1) {
+        /* What to do at the end of stage 1? */
+        switch (d->int_type) {
+        case INT_TYPE_IRQ:
+            fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
+            break;
+        case INT_TYPE_SMI:
+            fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
+            break;
+        }
+
+        /* Start the second stage. */
+        i6300esb_restart_timer(d, 2);
+    } else {
+        /* Second stage expired, reboot for real. */
+        if (d->reboot_enabled) {
+            d->previous_reboot_flag = 1;
+            watchdog_perform_action(); /* This reboots, exits, etc */
+            i6300esb_reset(&d->dev.qdev);
+        }
+
+        /* In "free running mode" we start stage 1 again. */
+        if (d->free_run)
+            i6300esb_restart_timer(d, 1);
+    }
+}
+
+static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
+                                  uint32_t data, int len)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+    int old;
+
+    i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
+
+    if (addr == ESB_CONFIG_REG && len == 2) {
+        d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
+        d->clock_scale =
+            (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
+        d->int_type = (data & ESB_WDT_INTTYPE);
+    } else if (addr == ESB_LOCK_REG && len == 1) {
+        if (!d->locked) {
+            d->locked = (data & ESB_WDT_LOCK) != 0;
+            d->free_run = (data & ESB_WDT_FUNC) != 0;
+            old = d->enabled;
+            d->enabled = (data & ESB_WDT_ENABLE) != 0;
+            if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
+                i6300esb_restart_timer(d, 1);
+            else if (!d->enabled)
+                i6300esb_disable_timer(d);
+        }
+    } else {
+        pci_default_write_config(dev, addr, data, len);
+    }
+}
+
+static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+    uint32_t data;
+
+    i6300esb_debug ("addr = %x, len = %d\n", addr, len);
+
+    if (addr == ESB_CONFIG_REG && len == 2) {
+        data =
+            (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
+            (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
+            d->int_type;
+        return data;
+    } else if (addr == ESB_LOCK_REG && len == 1) {
+        data =
+            (d->free_run ? ESB_WDT_FUNC : 0) |
+            (d->locked ? ESB_WDT_LOCK : 0) |
+            (d->enabled ? ESB_WDT_ENABLE : 0);
+        return data;
+    } else {
+        return pci_default_read_config(dev, addr, len);
+    }
+}
+
+static uint32_t i6300esb_mem_readb(void *vp, target_phys_addr_t addr)
+{
+    i6300esb_debug ("addr = %x\n", (int) addr);
+
+    return 0;
+}
+
+static uint32_t i6300esb_mem_readw(void *vp, target_phys_addr_t addr)
+{
+    uint32_t data = 0;
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x\n", (int) addr);
+
+    if (addr == 0xc) {
+        /* The previous reboot flag is really bit 9, but there is
+         * a bug in the Linux driver where it thinks it's bit 12.
+         * Set both.
+         */
+        data = d->previous_reboot_flag ? 0x1200 : 0;
+    }
+
+    return data;
+}
+
+static uint32_t i6300esb_mem_readl(void *vp, target_phys_addr_t addr)
+{
+    i6300esb_debug("addr = %x\n", (int) addr);
+
+    return 0;
+}
+
+static void i6300esb_mem_writeb(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+}
+
+static void i6300esb_mem_writew(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+    else {
+        if (d->unlock_state == 2) {
+            if (addr == 0xc) {
+                if ((val & 0x100) != 0)
+                    /* This is the "ping" from the userspace watchdog in
+                     * the guest ...
+                     */
+                    i6300esb_restart_timer(d, 1);
+
+                /* Setting bit 9 resets the previous reboot flag.
+                 * There's a bug in the Linux driver where it sets
+                 * bit 12 instead.
+                 */
+                if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
+                    d->previous_reboot_flag = 0;
+                }
+            }
+
+            d->unlock_state = 0;
+        }
+    }
+}
+
+static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+    else {
+        if (d->unlock_state == 2) {
+            if (addr == 0)
+                d->timer1_preload = val & 0xfffff;
+            else if (addr == 4)
+                d->timer2_preload = val & 0xfffff;
+
+            d->unlock_state = 0;
+        }
+    }
+}
+
+static const VMStateDescription vmstate_i6300esb = {
+    .name = "i6300esb_wdt",
+    .version_id = sizeof(I6300State),
+    .minimum_version_id = sizeof(I6300State),
+    .minimum_version_id_old = sizeof(I6300State),
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, I6300State),
+        VMSTATE_INT32(reboot_enabled, I6300State),
+        VMSTATE_INT32(clock_scale, I6300State),
+        VMSTATE_INT32(int_type, I6300State),
+        VMSTATE_INT32(free_run, I6300State),
+        VMSTATE_INT32(locked, I6300State),
+        VMSTATE_INT32(enabled, I6300State),
+        VMSTATE_TIMER(timer, I6300State),
+        VMSTATE_UINT32(timer1_preload, I6300State),
+        VMSTATE_UINT32(timer2_preload, I6300State),
+        VMSTATE_INT32(stage, I6300State),
+        VMSTATE_INT32(unlock_state, I6300State),
+        VMSTATE_INT32(previous_reboot_flag, I6300State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i6300esb_init(PCIDevice *dev)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+    int io_mem;
+    static CPUReadMemoryFunc * const mem_read[3] = {
+        i6300esb_mem_readb,
+        i6300esb_mem_readw,
+        i6300esb_mem_readl,
+    };
+    static CPUWriteMemoryFunc * const mem_write[3] = {
+        i6300esb_mem_writeb,
+        i6300esb_mem_writew,
+        i6300esb_mem_writel,
+    };
+
+    i6300esb_debug("I6300State = %p\n", d);
+
+    d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
+    d->previous_reboot_flag = 0;
+
+    io_mem = cpu_register_io_memory(mem_read, mem_write, d,
+                                    DEVICE_NATIVE_ENDIAN);
+    pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
+    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
+
+    return 0;
+}
+
+static WatchdogTimerModel model = {
+    .wdt_name = "i6300esb",
+    .wdt_description = "Intel 6300ESB",
+};
+
+static PCIDeviceInfo i6300esb_info = {
+    .qdev.name    = "i6300esb",
+    .qdev.size    = sizeof(I6300State),
+    .qdev.vmsd    = &vmstate_i6300esb,
+    .qdev.reset   = i6300esb_reset,
+    .config_read  = i6300esb_config_read,
+    .config_write = i6300esb_config_write,
+    .init         = i6300esb_init,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_ESB_9,
+    .class_id     = PCI_CLASS_SYSTEM_OTHER,
+};
+
+static void i6300esb_register_devices(void)
+{
+    watchdog_add_model(&model);
+    pci_qdev_register(&i6300esb_info);
+}
+
+device_init(i6300esb_register_devices);
diff --git a/qemu-0.15.x/hw/wdt_ib700.c b/qemu-0.15.x/hw/wdt_ib700.c
new file mode 100644
index 0000000..81f22d0
--- /dev/null
+++ b/qemu-0.15.x/hw/wdt_ib700.c
@@ -0,0 +1,137 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * By Richard W.M. Jones (rjones at redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+
+/*#define IB700_DEBUG 1*/
+
+#ifdef IB700_DEBUG
+#define ib700_debug(fs,...)					\
+    fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define ib700_debug(fs,...)
+#endif
+
+typedef struct IB700state {
+    ISADevice dev;
+    QEMUTimer *timer;
+} IB700State;
+
+/* This is the timer.  We use a global here because the watchdog
+ * code ensures there is only one watchdog (it is located at a fixed,
+ * unchangable IO port, so there could only ever be one anyway).
+ */
+
+/* A write to this register enables the timer. */
+static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+    IB700State *s = vp;
+    static int time_map[] = {
+        30, 28, 26, 24, 22, 20, 18, 16,
+        14, 12, 10,  8,  6,  4,  2,  0
+    };
+    int64_t timeout;
+
+    ib700_debug("addr = %x, data = %x\n", addr, data);
+
+    timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec();
+    qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout);
+}
+
+/* A write (of any value) to this register disables the timer. */
+static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+    IB700State *s = vp;
+
+    ib700_debug("addr = %x, data = %x\n", addr, data);
+
+    qemu_del_timer(s->timer);
+}
+
+/* This is called when the watchdog expires. */
+static void ib700_timer_expired(void *vp)
+{
+    IB700State *s = vp;
+
+    ib700_debug("watchdog expired\n");
+
+    watchdog_perform_action();
+    qemu_del_timer(s->timer);
+}
+
+static const VMStateDescription vmstate_ib700 = {
+    .name = "ib700_wdt",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_TIMER(timer, IB700State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int wdt_ib700_init(ISADevice *dev)
+{
+    IB700State *s = DO_UPCAST(IB700State, dev, dev);
+
+    ib700_debug("watchdog init\n");
+
+    s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s);
+    register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s);
+    register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s);
+
+    return 0;
+}
+
+static void wdt_ib700_reset(DeviceState *dev)
+{
+    IB700State *s = DO_UPCAST(IB700State, dev.qdev, dev);
+
+    ib700_debug("watchdog reset\n");
+
+    qemu_del_timer(s->timer);
+}
+
+static WatchdogTimerModel model = {
+    .wdt_name = "ib700",
+    .wdt_description = "iBASE 700",
+};
+
+static ISADeviceInfo wdt_ib700_info = {
+    .qdev.name  = "ib700",
+    .qdev.size  = sizeof(IB700State),
+    .qdev.vmsd  = &vmstate_ib700,
+    .qdev.reset = wdt_ib700_reset,
+    .init       = wdt_ib700_init,
+};
+
+static void wdt_ib700_register_devices(void)
+{
+    watchdog_add_model(&model);
+    isa_qdev_register(&wdt_ib700_info);
+}
+
+device_init(wdt_ib700_register_devices);
diff --git a/qemu-0.15.x/hw/wm8750.c b/qemu-0.15.x/hw/wm8750.c
new file mode 100644
index 0000000..c9c6744
--- /dev/null
+++ b/qemu-0.15.x/hw/wm8750.c
@@ -0,0 +1,707 @@
+/*
+ * WM8750 audio CODEC.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "hw.h"
+#include "i2c.h"
+#include "audio/audio.h"
+
+#define IN_PORT_N	3
+#define OUT_PORT_N	3
+
+#define CODEC		"wm8750"
+
+typedef struct {
+    int adc;
+    int adc_hz;
+    int dac;
+    int dac_hz;
+} WMRate;
+
+typedef struct {
+    i2c_slave i2c;
+    uint8_t i2c_data[2];
+    int i2c_len;
+    QEMUSoundCard card;
+    SWVoiceIn *adc_voice[IN_PORT_N];
+    SWVoiceOut *dac_voice[OUT_PORT_N];
+    int enable;
+    void (*data_req)(void *, int, int);
+    void *opaque;
+    uint8_t data_in[4096];
+    uint8_t data_out[4096];
+    int idx_in, req_in;
+    int idx_out, req_out;
+
+    SWVoiceOut **out[2];
+    uint8_t outvol[7], outmute[2];
+    SWVoiceIn **in[2];
+    uint8_t invol[4], inmute[2];
+
+    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
+    uint8_t path[4], mpath[2], power, format;
+    const WMRate *rate;
+    uint8_t rate_vmstate;
+    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
+} WM8750State;
+
+/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
+static const uint8_t wm8750_vol_db_table[] = {
+    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
+    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
+    4, 4, 3, 3, 3, 2, 2
+};
+
+#define WM8750_OUTVOL_TRANSFORM(x)	wm8750_vol_db_table[(0x7f - x) / 3]
+#define WM8750_INVOL_TRANSFORM(x)	(x << 2)
+
+static inline void wm8750_in_load(WM8750State *s)
+{
+    if (s->idx_in + s->req_in <= sizeof(s->data_in))
+        return;
+    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
+    AUD_read(*s->in[0], s->data_in + s->idx_in,
+             sizeof(s->data_in) - s->idx_in);
+}
+
+static inline void wm8750_out_flush(WM8750State *s)
+{
+    int sent = 0;
+    while (sent < s->idx_out)
+        sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
+                ?: s->idx_out;
+    s->idx_out = 0;
+}
+
+static void wm8750_audio_in_cb(void *opaque, int avail_b)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    s->req_in = avail_b;
+    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
+}
+
+static void wm8750_audio_out_cb(void *opaque, int free_b)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    if (s->idx_out >= free_b) {
+        s->idx_out = free_b;
+        s->req_out = 0;
+        wm8750_out_flush(s);
+    } else
+        s->req_out = free_b - s->idx_out;
+ 
+    s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
+}
+
+static const WMRate wm_rate_table[] = {
+    {  256, 48000,  256, 48000 },	/* SR: 00000 */
+    {  384, 48000,  384, 48000 },	/* SR: 00001 */
+    {  256, 48000, 1536,  8000 },	/* SR: 00010 */
+    {  384, 48000, 2304,  8000 },	/* SR: 00011 */
+    { 1536,  8000,  256, 48000 },	/* SR: 00100 */
+    { 2304,  8000,  384, 48000 },	/* SR: 00101 */
+    { 1536,  8000, 1536,  8000 },	/* SR: 00110 */
+    { 2304,  8000, 2304,  8000 },	/* SR: 00111 */
+    { 1024, 12000, 1024, 12000 },	/* SR: 01000 */
+    { 1526, 12000, 1536, 12000 },	/* SR: 01001 */
+    {  768, 16000,  768, 16000 },	/* SR: 01010 */
+    { 1152, 16000, 1152, 16000 },	/* SR: 01011 */
+    {  384, 32000,  384, 32000 },	/* SR: 01100 */
+    {  576, 32000,  576, 32000 },	/* SR: 01101 */
+    {  128, 96000,  128, 96000 },	/* SR: 01110 */
+    {  192, 96000,  192, 96000 },	/* SR: 01111 */
+    {  256, 44100,  256, 44100 },	/* SR: 10000 */
+    {  384, 44100,  384, 44100 },	/* SR: 10001 */
+    {  256, 44100, 1408,  8018 },	/* SR: 10010 */
+    {  384, 44100, 2112,  8018 },	/* SR: 10011 */
+    { 1408,  8018,  256, 44100 },	/* SR: 10100 */
+    { 2112,  8018,  384, 44100 },	/* SR: 10101 */
+    { 1408,  8018, 1408,  8018 },	/* SR: 10110 */
+    { 2112,  8018, 2112,  8018 },	/* SR: 10111 */
+    { 1024, 11025, 1024, 11025 },	/* SR: 11000 */
+    { 1536, 11025, 1536, 11025 },	/* SR: 11001 */
+    {  512, 22050,  512, 22050 },	/* SR: 11010 */
+    {  768, 22050,  768, 22050 },	/* SR: 11011 */
+    {  512, 24000,  512, 24000 },	/* SR: 11100 */
+    {  768, 24000,  768, 24000 },	/* SR: 11101 */
+    {  128, 88200,  128, 88200 },	/* SR: 11110 */
+    {  192, 88200,  192, 88200 },	/* SR: 11111 */
+};
+
+static void wm8750_vol_update(WM8750State *s)
+{
+    /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
+
+    AUD_set_volume_in(s->adc_voice[0], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+    AUD_set_volume_in(s->adc_voice[1], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+    AUD_set_volume_in(s->adc_voice[2], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+
+    /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
+
+    /* Speaker: LOUT2VOL ROUT2VOL */
+    AUD_set_volume_out(s->dac_voice[0], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
+
+    /* Headphone: LOUT1VOL ROUT1VOL */
+    AUD_set_volume_out(s->dac_voice[1], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
+
+    /* MONOOUT: MONOVOL MONOVOL */
+    AUD_set_volume_out(s->dac_voice[2], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
+}
+
+static void wm8750_set_format(WM8750State *s)
+{
+    int i;
+    struct audsettings in_fmt;
+    struct audsettings out_fmt;
+
+    wm8750_out_flush(s);
+
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 0);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 0);
+
+    for (i = 0; i < IN_PORT_N; i ++)
+        if (s->adc_voice[i]) {
+            AUD_close_in(&s->card, s->adc_voice[i]);
+            s->adc_voice[i] = NULL;
+        }
+    for (i = 0; i < OUT_PORT_N; i ++)
+        if (s->dac_voice[i]) {
+            AUD_close_out(&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = NULL;
+        }
+
+    if (!s->enable)
+        return;
+
+    /* Setup input */
+    in_fmt.endianness = 0;
+    in_fmt.nchannels = 2;
+    in_fmt.freq = s->adc_hz;
+    in_fmt.fmt = AUD_FMT_S16;
+
+    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
+                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
+                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
+                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
+
+    /* Setup output */
+    out_fmt.endianness = 0;
+    out_fmt.nchannels = 2;
+    out_fmt.freq = s->dac_hz;
+    out_fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
+    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
+                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
+    /* MONOMIX is also in stereo for simplicity */
+    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
+                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
+    /* no sense emulating OUT3 which is a mix of other outputs */
+
+    wm8750_vol_update(s);
+
+    /* We should connect the left and right channels to their
+     * respective inputs/outputs but we have completely no need
+     * for mixing or combining paths to different ports, so we
+     * connect both channels to where the left channel is routed.  */
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 1);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 1);
+}
+
+static void wm8750_clk_update(WM8750State *s, int ext)
+{
+    if (s->master || !s->ext_dac_hz)
+        s->dac_hz = s->rate->dac_hz;
+    else
+        s->dac_hz = s->ext_dac_hz;
+
+    if (s->master || !s->ext_adc_hz)
+        s->adc_hz = s->rate->adc_hz;
+    else
+        s->adc_hz = s->ext_adc_hz;
+
+    if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
+        if (!ext)
+            wm8750_set_format(s);
+    } else {
+        if (ext)
+            wm8750_set_format(s);
+    }
+}
+
+static void wm8750_reset(i2c_slave *i2c)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    s->rate = &wm_rate_table[0];
+    s->enable = 0;
+    wm8750_clk_update(s, 1);
+    s->diff[0] = 0;
+    s->diff[1] = 0;
+    s->ds = 0;
+    s->alc = 0;
+    s->in[0] = &s->adc_voice[0];
+    s->invol[0] = 0x17;
+    s->invol[1] = 0x17;
+    s->invol[2] = 0xc3;
+    s->invol[3] = 0xc3;
+    s->out[0] = &s->dac_voice[0];
+    s->outvol[0] = 0xff;
+    s->outvol[1] = 0xff;
+    s->outvol[2] = 0x79;
+    s->outvol[3] = 0x79;
+    s->outvol[4] = 0x79;
+    s->outvol[5] = 0x79;
+    s->outvol[6] = 0x79;
+    s->inmute[0] = 0;
+    s->inmute[1] = 0;
+    s->outmute[0] = 0;
+    s->outmute[1] = 0;
+    s->mute = 1;
+    s->path[0] = 0;
+    s->path[1] = 0;
+    s->path[2] = 0;
+    s->path[3] = 0;
+    s->mpath[0] = 0;
+    s->mpath[1] = 0;
+    s->format = 0x0a;
+    s->idx_in = sizeof(s->data_in);
+    s->req_in = 0;
+    s->idx_out = 0;
+    s->req_out = 0;
+    wm8750_vol_update(s);
+    s->i2c_len = 0;
+}
+
+static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+{
+    WM8750State *s = (WM8750State *) i2c;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_len = 0;
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->i2c_len < 2)
+            printf("%s: message too short (%i bytes)\n",
+                            __FUNCTION__, s->i2c_len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+#define WM8750_LINVOL	0x00
+#define WM8750_RINVOL	0x01
+#define WM8750_LOUT1V	0x02
+#define WM8750_ROUT1V	0x03
+#define WM8750_ADCDAC	0x05
+#define WM8750_IFACE	0x07
+#define WM8750_SRATE	0x08
+#define WM8750_LDAC	0x0a
+#define WM8750_RDAC	0x0b
+#define WM8750_BASS	0x0c
+#define WM8750_TREBLE	0x0d
+#define WM8750_RESET	0x0f
+#define WM8750_3D	0x10
+#define WM8750_ALC1	0x11
+#define WM8750_ALC2	0x12
+#define WM8750_ALC3	0x13
+#define WM8750_NGATE	0x14
+#define WM8750_LADC	0x15
+#define WM8750_RADC	0x16
+#define WM8750_ADCTL1	0x17
+#define WM8750_ADCTL2	0x18
+#define WM8750_PWR1	0x19
+#define WM8750_PWR2	0x1a
+#define WM8750_ADCTL3	0x1b
+#define WM8750_ADCIN	0x1f
+#define WM8750_LADCIN	0x20
+#define WM8750_RADCIN	0x21
+#define WM8750_LOUTM1	0x22
+#define WM8750_LOUTM2	0x23
+#define WM8750_ROUTM1	0x24
+#define WM8750_ROUTM2	0x25
+#define WM8750_MOUTM1	0x26
+#define WM8750_MOUTM2	0x27
+#define WM8750_LOUT2V	0x28
+#define WM8750_ROUT2V	0x29
+#define WM8750_MOUTV	0x2a
+
+static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    uint8_t cmd;
+    uint16_t value;
+
+    if (s->i2c_len >= 2) {
+        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
+#ifdef VERBOSE
+        return 1;
+#endif
+    }
+    s->i2c_data[s->i2c_len ++] = data;
+    if (s->i2c_len != 2)
+        return 0;
+
+    cmd = s->i2c_data[0] >> 1;
+    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
+
+    switch (cmd) {
+    case WM8750_LADCIN:	/* ADC Signal Path Control (Left) */
+        s->diff[0] = (((value >> 6) & 3) == 3);	/* LINSEL */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_RADCIN:	/* ADC Signal Path Control (Right) */
+        s->diff[1] = (((value >> 6) & 3) == 3);	/* RINSEL */
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_ADCIN:	/* ADC Input Mode */
+        s->ds = (value >> 8) & 1;	/* DS */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        s->monomix[0] = (value >> 6) & 3;	/* MONOMIX */
+        break;
+
+    case WM8750_ADCTL1:	/* Additional Control (1) */
+        s->monomix[1] = (value >> 1) & 1;	/* DMONOMIX */
+        break;
+
+    case WM8750_PWR1:	/* Power Management (1) */
+        s->enable = ((value >> 6) & 7) == 3;	/* VMIDSEL, VREF */
+        wm8750_set_format(s);
+        break;
+
+    case WM8750_LINVOL:	/* Left Channel PGA */
+        s->invol[0] = value & 0x3f;		/* LINVOL */
+        s->inmute[0] = (value >> 7) & 1;	/* LINMUTE */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RINVOL:	/* Right Channel PGA */
+        s->invol[1] = value & 0x3f;		/* RINVOL */
+        s->inmute[1] = (value >> 7) & 1;	/* RINMUTE */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCDAC:	/* ADC and DAC Control */
+        s->pol = (value >> 5) & 3;		/* ADCPOL */
+        s->mute = (value >> 3) & 1;		/* DACMU */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCTL3:	/* Additional Control (3) */
+        break;
+
+    case WM8750_LADC:	/* Left ADC Digital Volume */
+        s->invol[2] = value & 0xff;		/* LADCVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RADC:	/* Right ADC Digital Volume */
+        s->invol[3] = value & 0xff;		/* RADCVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ALC1:	/* ALC Control (1) */
+        s->alc = (value >> 7) & 3;		/* ALCSEL */
+        break;
+
+    case WM8750_NGATE:	/* Noise Gate Control */
+    case WM8750_3D:	/* 3D enhance */
+        break;
+
+    case WM8750_LDAC:	/* Left Channel Digital Volume */
+        s->outvol[0] = value & 0xff;		/* LDACVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RDAC:	/* Right Channel Digital Volume */
+        s->outvol[1] = value & 0xff;		/* RDACVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_BASS:	/* Bass Control */
+        break;
+
+    case WM8750_LOUTM1:	/* Left Mixer Control (1) */
+        s->path[0] = (value >> 8) & 1;		/* LD2LO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUTM2:	/* Left Mixer Control (2) */
+        s->path[1] = (value >> 8) & 1;		/* RD2LO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUTM1:	/* Right Mixer Control (1) */
+        s->path[2] = (value >> 8) & 1;		/* LD2RO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUTM2:	/* Right Mixer Control (2) */
+        s->path[3] = (value >> 8) & 1;		/* RD2RO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTM1:	/* Mono Mixer Control (1) */
+        s->mpath[0] = (value >> 8) & 1;		/* LD2MO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTM2:	/* Mono Mixer Control (2) */
+        s->mpath[1] = (value >> 8) & 1;		/* RD2MO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUT1V:	/* LOUT1 Volume */
+        s->outvol[2] = value & 0x7f;		/* LOUT1VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUT2V:	/* LOUT2 Volume */
+        s->outvol[4] = value & 0x7f;		/* LOUT2VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUT1V:	/* ROUT1 Volume */
+        s->outvol[3] = value & 0x7f;		/* ROUT1VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUT2V:	/* ROUT2 Volume */
+        s->outvol[5] = value & 0x7f;		/* ROUT2VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTV:	/* MONOOUT Volume */
+        s->outvol[6] = value & 0x7f;		/* MONOOUTVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCTL2:	/* Additional Control (2) */
+        break;
+
+    case WM8750_PWR2:	/* Power Management (2) */
+        s->power = value & 0x7e;
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_IFACE:	/* Digital Audio Interface Format */
+        s->format = value;
+        s->master = (value >> 6) & 1;			/* MS */
+        wm8750_clk_update(s, s->master);
+        break;
+
+    case WM8750_SRATE:	/* Clocking and Sample Rate Control */
+        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
+        wm8750_clk_update(s, 0);
+        break;
+
+    case WM8750_RESET:	/* Reset */
+        wm8750_reset(&s->i2c);
+        break;
+
+#ifdef VERBOSE
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
+#endif
+    }
+
+    return 0;
+}
+
+static int wm8750_rx(i2c_slave *i2c)
+{
+    return 0x00;
+}
+
+static void wm8750_pre_save(void *opaque)
+{
+    WM8750State *s = opaque;
+
+    s->rate_vmstate = (s->rate - wm_rate_table) / sizeof(*s->rate);
+}
+
+static int wm8750_post_load(void *opaque, int version_id)
+{
+    WM8750State *s = opaque;
+
+    s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
+    return 0;
+}
+
+static const VMStateDescription vmstate_wm8750 = {
+    .name = CODEC,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = wm8750_pre_save,
+    .post_load = wm8750_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
+        VMSTATE_INT32(i2c_len, WM8750State),
+        VMSTATE_INT32(enable, WM8750State),
+        VMSTATE_INT32(idx_in, WM8750State),
+        VMSTATE_INT32(req_in, WM8750State),
+        VMSTATE_INT32(idx_out, WM8750State),
+        VMSTATE_INT32(req_out, WM8750State),
+        VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
+        VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
+        VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
+        VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
+        VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
+        VMSTATE_UINT8(pol, WM8750State),
+        VMSTATE_UINT8(ds, WM8750State),
+        VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
+        VMSTATE_UINT8(alc, WM8750State),
+        VMSTATE_UINT8(mute, WM8750State),
+        VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
+        VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
+        VMSTATE_UINT8(format, WM8750State),
+        VMSTATE_UINT8(power, WM8750State),
+        VMSTATE_UINT8(rate_vmstate, WM8750State),
+        VMSTATE_I2C_SLAVE(i2c, WM8750State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int wm8750_init(i2c_slave *i2c)
+{
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
+
+    AUD_register_card(CODEC, &s->card);
+    wm8750_reset(&s->i2c);
+
+    return 0;
+}
+
+#if 0
+static void wm8750_fini(i2c_slave *i2c)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    wm8750_reset(&s->i2c);
+    AUD_remove_card(&s->card);
+    qemu_free(s);
+}
+#endif
+
+void wm8750_data_req_set(DeviceState *dev,
+                void (*data_req)(void *, int, int), void *opaque)
+{
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE_FROM_QDEV(dev));
+    s->data_req = data_req;
+    s->opaque = opaque;
+}
+
+void wm8750_dac_dat(void *opaque, uint32_t sample)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    *(uint32_t *) &s->data_out[s->idx_out] = sample;
+    s->req_out -= 4;
+    s->idx_out += 4;
+    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
+        wm8750_out_flush(s);
+}
+
+void *wm8750_dac_buffer(void *opaque, int samples)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    /* XXX: Should check if there are <i>samples</i> free samples available */
+    void *ret = s->data_out + s->idx_out;
+
+    s->idx_out += samples << 2;
+    s->req_out -= samples << 2;
+    return ret;
+}
+
+void wm8750_dac_commit(void *opaque)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    wm8750_out_flush(s);
+}
+
+uint32_t wm8750_adc_dat(void *opaque)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    uint32_t *data;
+
+    if (s->idx_in >= sizeof(s->data_in))
+        wm8750_in_load(s);
+
+    data = (uint32_t *) &s->data_in[s->idx_in];
+    s->req_in -= 4;
+    s->idx_in += 4;
+    return *data;
+}
+
+void wm8750_set_bclk_in(void *opaque, int new_hz)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    s->ext_adc_hz = new_hz;
+    s->ext_dac_hz = new_hz;
+    wm8750_clk_update(s, 1);
+}
+
+static I2CSlaveInfo wm8750_info = {
+    .qdev.name = "wm8750",
+    .qdev.size = sizeof(WM8750State),
+    .qdev.vmsd = &vmstate_wm8750,
+    .init = wm8750_init,
+    .event = wm8750_event,
+    .recv = wm8750_rx,
+    .send = wm8750_tx
+};
+
+static void wm8750_register_devices(void)
+{
+    i2c_register_slave(&wm8750_info);
+}
+
+device_init(wm8750_register_devices)
diff --git a/qemu-0.15.x/hw/xen.h b/qemu-0.15.x/hw/xen.h
new file mode 100644
index 0000000..e432705
--- /dev/null
+++ b/qemu-0.15.x/hw/xen.h
@@ -0,0 +1,54 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+#include <inttypes.h>
+
+#include "qemu-common.h"
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+extern int xen_allowed;
+
+static inline int xen_enabled(void)
+{
+#ifdef CONFIG_XEN
+    return xen_allowed;
+#else
+    return 0;
+#endif
+}
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
+void xen_piix3_set_irq(void *opaque, int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
+
+qemu_irq *xen_interrupt_controller_init(void);
+
+int xen_init(void);
+int xen_hvm_init(void);
+void xen_vcpu_init(void);
+void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
+
+#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size);
+#endif
+
+#if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+#  define HVM_MAX_VCPUS 32
+#endif
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/qemu-0.15.x/hw/xen_backend.c b/qemu-0.15.x/hw/xen_backend.c
new file mode 100644
index 0000000..d881fa2
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_backend.c
@@ -0,0 +1,757 @@
+/*
+ *  xen backend driver infrastructure
+ *  (c) 2008 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * TODO: add some xenbus / xenstore concepts overview here.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/grant_table.h>
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+/* public */
+XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
+XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE;
+struct xs_handle *xenstore = NULL;
+const char *xen_protocol;
+
+/* private */
+static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_BUFSIZE];
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
+        return -1;
+    }
+    return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+    char abspath[XEN_BUFSIZE];
+    unsigned int len;
+    char *str, *ret = NULL;
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    str = xs_read(xenstore, 0, abspath, &len);
+    if (str != NULL) {
+        /* move to qemu-allocated memory to make sure
+         * callers can savely qemu_free() stuff. */
+        ret = qemu_strdup(str);
+        free(str);
+    }
+    return ret;
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+    char val[32];
+
+    snprintf(val, sizeof(val), "%d", ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%d", ival)) {
+        rc = 0;
+    }
+    qemu_free(val);
+    return rc;
+}
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+{
+    return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+{
+    return xenstore_write_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->fe, node, ival);
+}
+
+/* ------------------------------------------------------------- */
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+    static const char *const name[] = {
+        [ XenbusStateUnknown      ] = "Unknown",
+        [ XenbusStateInitialising ] = "Initialising",
+        [ XenbusStateInitWait     ] = "InitWait",
+        [ XenbusStateInitialised  ] = "Initialised",
+        [ XenbusStateConnected    ] = "Connected",
+        [ XenbusStateClosing      ] = "Closing",
+        [ XenbusStateClosed       ] = "Closed",
+    };
+    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
+{
+    int rc;
+
+    rc = xenstore_write_be_int(xendev, "state", state);
+    if (rc < 0) {
+        return rc;
+    }
+    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
+                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
+    xendev->be_state = state;
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    QTAILQ_FOREACH(xendev, &xendevs, next) {
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev) {
+            continue;
+        }
+        if (strcmp(xendev->type, type) != 0) {
+            continue;
+        }
+        return xendev;
+    }
+    return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                           struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char *dom0;
+
+    xendev = xen_be_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = qemu_mallocz(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
+             dom0, xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+    free(dom0);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        qemu_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            qemu_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct XenDevice *xen_be_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_next;
+
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev && dev != -1) {
+            continue;
+        }
+
+        if (xendev->ops->free) {
+            xendev->ops->free(xendev);
+        }
+
+        if (xendev->fe) {
+            char token[XEN_BUFSIZE];
+            snprintf(token, sizeof(token), "fe:%p", xendev);
+            xs_unwatch(xenstore, xendev->fe, token);
+            qemu_free(xendev->fe);
+        }
+
+        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
+            xc_evtchn_close(xendev->evtchndev);
+        }
+        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
+            xc_gnttab_close(xendev->gnttabdev);
+        }
+
+        QTAILQ_REMOVE(&xendevs, xendev, next);
+        qemu_free(xendev);
+    }
+    return NULL;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field.  node = NULL means
+ * update all fields (used for initialization).
+ */
+static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    if (node == NULL  ||  strcmp(node, "online") == 0) {
+        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
+            xendev->online = 0;
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "backend update: %s\n", node);
+        if (xendev->ops->backend_changed) {
+            xendev->ops->backend_changed(xendev, node);
+        }
+    }
+}
+
+static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    int fe_state;
+
+    if (node == NULL  ||  strcmp(node, "state") == 0) {
+        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+            fe_state = XenbusStateUnknown;
+        }
+        if (xendev->fe_state != fe_state) {
+            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+                          xenbus_strstate(xendev->fe_state),
+                          xenbus_strstate(fe_state));
+        }
+        xendev->fe_state = fe_state;
+    }
+    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
+        qemu_free(xendev->protocol);
+        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+        if (xendev->protocol) {
+            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+        if (xendev->ops->frontend_changed) {
+            xendev->ops->frontend_changed(xendev, node);
+        }
+    }
+}
+
+/* ------------------------------------------------------------- */
+/* Check for possible state transitions and perform them.        */
+
+/*
+ * Initial xendev setup.  Read frontend path, register watch for it.
+ * Should succeed once xend finished setting up the backend device.
+ *
+ * Also sets initial state (-> Initializing) when done.  Which
+ * only affects the xendev->be_state variable as xenbus should
+ * already be put into that state by xend.
+ */
+static int xen_be_try_setup(struct XenDevice *xendev)
+{
+    char token[XEN_BUFSIZE];
+    int be_state;
+
+    if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
+        xen_be_printf(xendev, 0, "reading backend state failed\n");
+        return -1;
+    }
+
+    if (be_state != XenbusStateInitialising) {
+        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
+                      xenbus_strstate(be_state));
+        return -1;
+    }
+
+    xendev->fe = xenstore_read_be_str(xendev, "frontend");
+    if (xendev->fe == NULL) {
+        xen_be_printf(xendev, 0, "reading frontend path failed\n");
+        return -1;
+    }
+
+    /* setup frontend watch */
+    snprintf(token, sizeof(token), "fe:%p", xendev);
+    if (!xs_watch(xenstore, xendev->fe, token)) {
+        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
+                      xendev->fe);
+        return -1;
+    }
+    xen_be_set_state(xendev, XenbusStateInitialising);
+
+    xen_be_backend_changed(xendev, NULL);
+    xen_be_frontend_changed(xendev, NULL);
+    return 0;
+}
+
+/*
+ * Try initialize xendev.  Prepare everything the backend can do
+ * without synchronizing with the frontend.  Fakes hotplug-status.  No
+ * hotplug involved here because this is about userspace drivers, thus
+ * there are kernel backend devices which could invoke hotplug.
+ *
+ * Goes to InitWait on success.
+ */
+static int xen_be_try_init(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    if (!xendev->online) {
+        xen_be_printf(xendev, 1, "not online\n");
+        return -1;
+    }
+
+    if (xendev->ops->init) {
+        rc = xendev->ops->init(xendev);
+    }
+    if (rc != 0) {
+        xen_be_printf(xendev, 1, "init() failed\n");
+        return rc;
+    }
+
+    xenstore_write_be_str(xendev, "hotplug-status", "connected");
+    xen_be_set_state(xendev, XenbusStateInitWait);
+    return 0;
+}
+
+/*
+ * Try to connect xendev.  Depends on the frontend being ready
+ * for it (shared ring and evtchn info in xenstore, state being
+ * Initialised or Connected).
+ *
+ * Goes to Connected on success.
+ */
+static int xen_be_try_connect(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    if (xendev->fe_state != XenbusStateInitialised  &&
+        xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return -1;
+        }
+    }
+
+    if (xendev->ops->connect) {
+        rc = xendev->ops->connect(xendev);
+    }
+    if (rc != 0) {
+        xen_be_printf(xendev, 0, "connect() failed\n");
+        return rc;
+    }
+
+    xen_be_set_state(xendev, XenbusStateConnected);
+    return 0;
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+{
+    if (xendev->be_state != XenbusStateClosing &&
+        xendev->be_state != XenbusStateClosed  &&
+        xendev->ops->disconnect) {
+        xendev->ops->disconnect(xendev);
+    }
+    if (xendev->be_state != state) {
+        xen_be_set_state(xendev, state);
+    }
+}
+
+/*
+ * Try to reset xendev, for reconnection by another frontend instance.
+ */
+static int xen_be_try_reset(struct XenDevice *xendev)
+{
+    if (xendev->fe_state != XenbusStateInitialising) {
+        return -1;
+    }
+
+    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
+    xen_be_set_state(xendev, XenbusStateInitialising);
+    return 0;
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    /* frontend may request shutdown from almost anywhere */
+    if (xendev->fe_state == XenbusStateClosing ||
+        xendev->fe_state == XenbusStateClosed) {
+        xen_be_disconnect(xendev, xendev->fe_state);
+        return;
+    }
+
+    /* check for possible backend state transitions */
+    for (;;) {
+        switch (xendev->be_state) {
+        case XenbusStateUnknown:
+            rc = xen_be_try_setup(xendev);
+            break;
+        case XenbusStateInitialising:
+            rc = xen_be_try_init(xendev);
+            break;
+        case XenbusStateInitWait:
+            rc = xen_be_try_connect(xendev);
+            break;
+        case XenbusStateClosed:
+            rc = xen_be_try_reset(xendev);
+            break;
+        default:
+            rc = -1;
+        }
+        if (rc != 0) {
+            break;
+        }
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    char **dev = NULL, *dom0;
+    unsigned int cdev, j;
+
+    /* setup watch */
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    if (!xs_watch(xenstore, path, token)) {
+        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
+        return -1;
+    }
+
+    /* look for backends */
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    if (!dev) {
+        return 0;
+    }
+    for (j = 0; j < cdev; j++) {
+        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
+        if (xendev == NULL) {
+            continue;
+        }
+        xen_be_check_state(xendev);
+    }
+    free(dev);
+    return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+                               struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *dom0;
+    unsigned int len, dev;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    if (strncmp(path, watch, len) != 0) {
+        return;
+    }
+    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+        strcpy(path, "");
+        if (sscanf(watch+len, "/%u", &dev) != 1) {
+            dev = -1;
+        }
+    }
+    if (dev == -1) {
+        return;
+    }
+
+    if (0) {
+        /* FIXME: detect devices being deleted from xenstore ... */
+        xen_be_del_xendev(dom, dev);
+    }
+
+    xendev = xen_be_get_xendev(type, dom, dev, ops);
+    if (xendev != NULL) {
+        xen_be_backend_changed(xendev, path);
+        xen_be_check_state(xendev);
+    }
+}
+
+static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+{
+    char *node;
+    unsigned int len;
+
+    len = strlen(xendev->fe);
+    if (strncmp(xendev->fe, watch, len) != 0) {
+        return;
+    }
+    if (watch[len] != '/') {
+        return;
+    }
+    node = watch + len + 1;
+
+    xen_be_frontend_changed(xendev, node);
+    xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+    char **vec = NULL;
+    intptr_t type, ops, ptr;
+    unsigned int dom, count;
+
+    vec = xs_read_watch(xenstore, &count);
+    if (vec == NULL) {
+        goto cleanup;
+    }
+
+    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+               &type, &dom, &ops) == 3) {
+        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
+    }
+    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
+        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+    }
+
+cleanup:
+    free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+    struct XenDevice *xendev = opaque;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xendev->evtchndev);
+    if (port != xendev->local_port) {
+        xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
+                      port, xendev->local_port);
+        return;
+    }
+    xc_evtchn_unmask(xendev->evtchndev, port);
+
+    if (xendev->ops->event) {
+        xendev->ops->event(xendev);
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+int xen_be_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
+        goto err;
+    }
+
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+        /* Check if xen_init() have been called */
+        goto err;
+    }
+    return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
+
+int xen_be_register(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct XenDevice *xendev)
+{
+    if (xendev->local_port != -1) {
+        return 0;
+    }
+    xendev->local_port = xc_evtchn_bind_interdomain
+        (xendev->evtchndev, xendev->dom, xendev->remote_port);
+    if (xendev->local_port == -1) {
+        xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+        return -1;
+    }
+    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+                        xen_be_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+void xen_be_unbind_evtchn(struct XenDevice *xendev)
+{
+    if (xendev->local_port == -1) {
+        return;
+    }
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
+    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
+    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
+    xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct XenDevice *xendev)
+{
+    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
+}
+
+/*
+ * msg_level:
+ *  0 == errors (stderr + logfile).
+ *  1 == informative debug messages (logfile only).
+ *  2 == noisy debug messages (logfile only).
+ *  3 == will flood your log (logfile only).
+ */
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+{
+    va_list args;
+
+    if (xendev) {
+        if (msg_level > xendev->debug) {
+            return;
+        }
+        qemu_log("xen be: %s: ", xendev->name);
+        if (msg_level == 0) {
+            fprintf(stderr, "xen be: %s: ", xendev->name);
+        }
+    } else {
+        if (msg_level > debug) {
+            return;
+        }
+        qemu_log("xen be core: ");
+        if (msg_level == 0) {
+            fprintf(stderr, "xen be core: ");
+        }
+    }
+    va_start(args, fmt);
+    qemu_log_vprintf(fmt, args);
+    va_end(args);
+    if (msg_level == 0) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+    qemu_log_flush();
+}
diff --git a/qemu-0.15.x/hw/xen_backend.h b/qemu-0.15.x/hw/xen_backend.h
new file mode 100644
index 0000000..6401c85
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_backend.h
@@ -0,0 +1,106 @@
+#ifndef QEMU_HW_XEN_BACKEND_H
+#define QEMU_HW_XEN_BACKEND_H 1
+
+#include "xen_common.h"
+#include "sysemu.h"
+#include "net.h"
+
+/* ------------------------------------------------------------- */
+
+#define XEN_BUFSIZE 1024
+
+struct XenDevice;
+
+/* driver uses grant tables  ->  open gntdev device (xendev->gnttabdev) */
+#define DEVOPS_FLAG_NEED_GNTDEV   1
+/* don't expect frontend doing correct state transitions (aka console quirk) */
+#define DEVOPS_FLAG_IGNORE_STATE  2
+
+struct XenDevOps {
+    size_t    size;
+    uint32_t  flags;
+    void      (*alloc)(struct XenDevice *xendev);
+    int       (*init)(struct XenDevice *xendev);
+    int       (*connect)(struct XenDevice *xendev);
+    void      (*event)(struct XenDevice *xendev);
+    void      (*disconnect)(struct XenDevice *xendev);
+    int       (*free)(struct XenDevice *xendev);
+    void      (*backend_changed)(struct XenDevice *xendev, const char *node);
+    void      (*frontend_changed)(struct XenDevice *xendev, const char *node);
+};
+
+struct XenDevice {
+    const char         *type;
+    int                dom;
+    int                dev;
+    char               name[64];
+    int                debug;
+
+    enum xenbus_state  be_state;
+    enum xenbus_state  fe_state;
+    int                online;
+    char               be[XEN_BUFSIZE];
+    char               *fe;
+    char               *protocol;
+    int                remote_port;
+    int                local_port;
+
+    XenEvtchn          evtchndev;
+    XenGnttab          gnttabdev;
+
+    struct XenDevOps   *ops;
+    QTAILQ_ENTRY(XenDevice) next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+extern XenXC xen_xc;
+extern struct xs_handle *xenstore;
+extern const char *xen_protocol;
+
+/* xenstore helper functions */
+int xenstore_write_str(const char *base, const char *node, const char *val);
+int xenstore_write_int(const char *base, const char *node, int ival);
+char *xenstore_read_str(const char *base, const char *node);
+int xenstore_read_int(const char *base, const char *node, int *ival);
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+void xen_be_check_state(struct XenDevice *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(const char *type, struct XenDevOps *ops);
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_unbind_evtchn(struct XenDevice *xendev);
+int xen_be_send_notify(struct XenDevice *xendev);
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
+extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
+extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
+
+void xen_init_display(int domid);
+
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
+
+#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/qemu-0.15.x/hw/xen_blkif.h b/qemu-0.15.x/hw/xen_blkif.h
new file mode 100644
index 0000000..c0f4136
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_blkif.h
@@ -0,0 +1,103 @@
+#ifndef __XEN_BLKIF_H__
+#define __XEN_BLKIF_H__
+
+#include <xen/io/ring.h>
+#include <xen/io/blkif.h>
+#include <xen/io/protocols.h>
+
+/* Not a real protocol.  Used to generate ring structs which contain
+ * the elements common to all protocols only.  This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places.  */
+struct blkif_common_request {
+	char dummy;
+};
+struct blkif_common_response {
+	char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+	uint8_t        operation;    /* BLKIF_OP_???                         */
+	uint8_t        nr_segments;  /* number of segments                   */
+	blkif_vdev_t   handle;       /* only for read/write requests         */
+	uint64_t       id;           /* private guest value, echoed in resp  */
+	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+	uint64_t        id;              /* copied from request */
+	uint8_t         operation;       /* copied from request */
+	int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+typedef struct blkif_x86_32_response blkif_x86_32_response_t;
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+	uint8_t        operation;    /* BLKIF_OP_???                         */
+	uint8_t        nr_segments;  /* number of segments                   */
+	blkif_vdev_t   handle;       /* only for read/write requests         */
+	uint64_t       __attribute__((__aligned__(8))) id;
+	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+	uint64_t       __attribute__((__aligned__(8))) id;
+	uint8_t         operation;       /* copied from request */
+	int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+typedef struct blkif_x86_64_response blkif_x86_64_response_t;
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
+
+union blkif_back_rings {
+	blkif_back_ring_t        native;
+	blkif_common_back_ring_t common;
+        blkif_x86_32_back_ring_t x86_32_part;
+        blkif_x86_64_back_ring_t x86_64_part;
+};
+typedef union blkif_back_rings blkif_back_rings_t;
+
+enum blkif_protocol {
+	BLKIF_PROTOCOL_NATIVE = 1,
+	BLKIF_PROTOCOL_X86_32 = 2,
+	BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+{
+	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	if (n > src->nr_segments)
+		n = src->nr_segments;
+	for (i = 0; i < n; i++)
+		dst->seg[i] = src->seg[i];
+}
+
+static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+{
+	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	if (n > src->nr_segments)
+		n = src->nr_segments;
+	for (i = 0; i < n; i++)
+		dst->seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF_H__ */
diff --git a/qemu-0.15.x/hw/xen_common.h b/qemu-0.15.x/hw/xen_common.h
new file mode 100644
index 0000000..0409ac7
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_common.h
@@ -0,0 +1,138 @@
+#ifndef QEMU_HW_XEN_COMMON_H
+#define QEMU_HW_XEN_COMMON_H 1
+
+#include "config-host.h"
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xs.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "xen.h"
+#include "qemu-queue.h"
+
+/*
+ * We don't support Xen prior to 3.3.0.
+ */
+
+/* Xen before 4.0 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+static inline void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
+                                        xen_pfn_t *arr, int *err,
+                                        unsigned int num)
+{
+    return xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
+}
+#endif
+
+
+/* Xen before 4.1 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 410
+
+typedef int XenXC;
+typedef int XenEvtchn;
+typedef int XenGnttab;
+
+#  define XC_INTERFACE_FMT "%i"
+#  define XC_HANDLER_INITIAL_VALUE    -1
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open();
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open();
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open();
+}
+
+static inline int xc_fd(int xen_xc)
+{
+    return xen_xc;
+}
+
+
+static inline int xc_domain_populate_physmap_exact
+    (XenXC xc_handle, uint32_t domid, unsigned long nr_extents,
+     unsigned int extent_order, unsigned int mem_flags, xen_pfn_t *extent_start)
+{
+    return xc_domain_memory_populate_physmap
+        (xc_handle, domid, nr_extents, extent_order, mem_flags, extent_start);
+}
+
+static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
+                                           unsigned int space, unsigned long idx,
+                                           xen_pfn_t gpfn)
+{
+    struct xen_add_to_physmap xatp = {
+        .domid = domid,
+        .space = space,
+        .idx = idx,
+        .gpfn = gpfn,
+    };
+
+    return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
+}
+
+static inline struct xs_handle *xs_open(unsigned long flags)
+{
+    return xs_daemon_open();
+}
+
+static inline void xs_close(struct xs_handle *xsh)
+{
+    if (xsh != NULL) {
+        xs_daemon_close(xsh);
+    }
+}
+
+
+/* Xen 4.1 */
+#else
+
+typedef xc_interface *XenXC;
+typedef xc_evtchn *XenEvtchn;
+typedef xc_gnttab *XenGnttab;
+
+#  define XC_INTERFACE_FMT "%p"
+#  define XC_HANDLER_INITIAL_VALUE    NULL
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open(logger, open_flags);
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open(logger, open_flags);
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open(logger, dombuild_logger, open_flags);
+}
+
+/* FIXME There is now way to have the xen fd */
+static inline int xc_fd(xc_interface *xen_xc)
+{
+    return -1;
+}
+#endif
+
+void destroy_hvm_domain(void);
+
+#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/qemu-0.15.x/hw/xen_console.c b/qemu-0.15.x/hw/xen_console.c
new file mode 100644
index 0000000..8ef104c
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_console.c
@@ -0,0 +1,279 @@
+/*
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori at us.ibm.com>
+ *
+ *  Copyright (C) Red Hat 2007
+ *
+ *  Xen Console
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <xs.h>
+#include <xen/io/console.h>
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+struct buffer {
+    uint8_t *data;
+    size_t consumed;
+    size_t size;
+    size_t capacity;
+    size_t max_capacity;
+};
+
+struct XenConsole {
+    struct XenDevice  xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[XEN_BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct XenConsole *con)
+{
+    struct buffer *buffer = &con->buffer;
+    XENCONS_RING_IDX cons, prod, size;
+    struct xencons_interface *intf = con->sring;
+
+    cons = intf->out_cons;
+    prod = intf->out_prod;
+    xen_mb();
+
+    size = prod - cons;
+    if ((size == 0) || (size > sizeof(intf->out)))
+	return;
+
+    if ((buffer->capacity - buffer->size) < size) {
+	buffer->capacity += (size + 1024);
+	buffer->data = qemu_realloc(buffer->data, buffer->capacity);
+    }
+
+    while (cons != prod)
+	buffer->data[buffer->size++] = intf->out[
+	    MASK_XENCONS_IDX(cons++, intf->out)];
+
+    xen_mb();
+    intf->out_cons = cons;
+    xen_be_send_notify(&con->xendev);
+
+    if (buffer->max_capacity &&
+	buffer->size > buffer->max_capacity) {
+	/* Discard the middle of the data. */
+
+	size_t over = buffer->size - buffer->max_capacity;
+	uint8_t *maxpos = buffer->data + buffer->max_capacity;
+
+	memmove(maxpos - over, maxpos, over);
+	buffer->data = qemu_realloc(buffer->data, buffer->max_capacity);
+	buffer->size = buffer->capacity = buffer->max_capacity;
+
+	if (buffer->consumed > buffer->max_capacity - over)
+	    buffer->consumed = buffer->max_capacity - over;
+    }
+}
+
+static void buffer_advance(struct buffer *buffer, size_t len)
+{
+    buffer->consumed += len;
+    if (buffer->consumed == buffer->size) {
+	buffer->consumed = 0;
+	buffer->size = 0;
+    }
+}
+
+static int ring_free_bytes(struct XenConsole *con)
+{
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX cons, prod, space;
+
+    cons = intf->in_cons;
+    prod = intf->in_prod;
+    xen_mb();
+
+    space = prod - cons;
+    if (space > sizeof(intf->in))
+	return 0; /* ring is screwed: ignore it */
+
+    return (sizeof(intf->in) - space);
+}
+
+static int xencons_can_receive(void *opaque)
+{
+    struct XenConsole *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct XenConsole *con = opaque;
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX prod;
+    int i, max;
+
+    max = ring_free_bytes(con);
+    /* The can_receive() func limits this, but check again anyway */
+    if (max < len)
+	len = max;
+
+    prod = intf->in_prod;
+    for (i = 0; i < len; i++) {
+	intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+	    buf[i];
+    }
+    xen_wmb();
+    intf->in_prod = prod;
+    xen_be_send_notify(&con->xendev);
+}
+
+static void xencons_send(struct XenConsole *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    if (con->chr)
+        len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+                             size);
+    else
+        len = size;
+    if (len < 1) {
+	if (!con->backlog) {
+	    con->backlog = 1;
+	    xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
+	}
+    } else {
+	buffer_advance(&con->buffer, len);
+	if (con->backlog && len == size) {
+	    con->backlog = 0;
+	    xen_be_printf(&con->xendev, 1, "backlog is gone\n");
+	}
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int con_init(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    char *type, *dom, label[32];
+    int ret = 0;
+    const char *output;
+
+    /* setup */
+    dom = xs_get_domain_path(xenstore, con->xendev.dom);
+    snprintf(con->console, sizeof(con->console), "%s/console", dom);
+    free(dom);
+
+    type = xenstore_read_str(con->console, "type");
+    if (!type || strcmp(type, "ioemu") != 0) {
+	xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
+        ret = -1;
+        goto out;
+    }
+
+    output = xenstore_read_str(con->console, "output");
+
+    /* no Xen override, use qemu output device */
+    if (output == NULL) {
+        con->chr = serial_hds[con->xendev.dev];
+    } else {
+        snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
+        con->chr = qemu_chr_open(label, output, NULL);
+    }
+
+    xenstore_store_pv_console_info(con->xendev.dev, con->chr);
+
+out:
+    qemu_free(type);
+    return ret;
+}
+
+static int con_connect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    int limit;
+
+    if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
+	return -1;
+    if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
+	return -1;
+    if (xenstore_read_int(con->console, "limit", &limit) == 0)
+	con->buffer.max_capacity = limit;
+
+    con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
+				      XC_PAGE_SIZE,
+				      PROT_READ|PROT_WRITE,
+				      con->ring_ref);
+    if (!con->sring)
+	return -1;
+
+    xen_be_bind_evtchn(&con->xendev);
+    if (con->chr)
+        qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
+                              NULL, con);
+
+    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
+		  con->ring_ref,
+		  con->xendev.remote_port,
+		  con->xendev.local_port,
+		  con->buffer.max_capacity);
+    return 0;
+}
+
+static void con_disconnect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    if (con->chr)
+        qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+    xen_be_unbind_evtchn(&con->xendev);
+
+    if (con->sring) {
+	munmap(con->sring, XC_PAGE_SIZE);
+	con->sring = NULL;
+    }
+}
+
+static void con_event(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+	xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+    .size       = sizeof(struct XenConsole),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/qemu-0.15.x/hw/xen_devconfig.c b/qemu-0.15.x/hw/xen_devconfig.c
new file mode 100644
index 0000000..6926c54
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_devconfig.c
@@ -0,0 +1,173 @@
+#include "xen_backend.h"
+#include "blockdev.h"
+#include "block_int.h" /* XXX */
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+    char *xs_dir;
+    QTAILQ_ENTRY(xs_dirs) list;
+};
+static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
+
+static void xen_config_cleanup_dir(char *dir)
+{
+    struct xs_dirs *d;
+
+    d = qemu_malloc(sizeof(*d));
+    d->xs_dir = dir;
+    QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+    struct xs_dirs *d;
+
+    QTAILQ_FOREACH(d, &xs_cleanup, list) {
+	xs_rm(xenstore, 0, d->xs_dir);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+    struct xs_permissions perms[2] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = p,
+        }};
+
+    if (!xs_mkdir(xenstore, 0, dev)) {
+	xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
+	return -1;
+    }
+    xen_config_cleanup_dir(qemu_strdup(dev));
+
+    if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
+	xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
+	return -1;
+    }
+    return 0;
+}
+
+static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
+			       char *fe, char *be, int len)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
+    free(dom);
+
+    dom = xs_get_domain_path(xenstore, 0);
+    snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
+    free(dom);
+
+    xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
+    xen_config_dev_mkdir(be, XS_PERM_READ);
+    return 0;
+}
+
+static int xen_config_dev_all(char *fe, char *be)
+{
+    /* frontend */
+    if (xen_protocol)
+        xenstore_write_str(fe, "protocol", xen_protocol);
+
+    xenstore_write_int(fe, "state",           XenbusStateInitialising);
+    xenstore_write_int(fe, "backend-id",      0);
+    xenstore_write_str(fe, "backend",         be);
+
+    /* backend */
+    xenstore_write_str(be, "domain",          qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(be, "online",          1);
+    xenstore_write_int(be, "state",           XenbusStateInitialising);
+    xenstore_write_int(be, "frontend-id",     xen_domid);
+    xenstore_write_str(be, "frontend",        fe);
+
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_config_dev_blk(DriveInfo *disk)
+{
+    char fe[256], be[256];
+    int vdev = 202 * 256 + 16 * disk->unit;
+    int cdrom = disk->media_cd;
+    const char *devtype = cdrom ? "cdrom" : "disk";
+    const char *mode    = cdrom ? "r"     : "w";
+
+    snprintf(disk->bdrv->device_name, sizeof(disk->bdrv->device_name),
+	     "xvd%c", 'a' + disk->unit);
+    xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
+                  disk->unit, disk->bdrv->device_name, disk->bdrv->filename);
+    xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "virtual-device",  vdev);
+    xenstore_write_str(fe, "device-type",     devtype);
+
+    /* backend */
+    xenstore_write_str(be, "dev",             disk->bdrv->device_name);
+    xenstore_write_str(be, "type",            "file");
+    xenstore_write_str(be, "params",          disk->bdrv->filename);
+    xenstore_write_str(be, "mode",            mode);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_nic(NICInfo *nic)
+{
+    char fe[256], be[256];
+    char mac[20];
+
+    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+             nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
+             nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
+    xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", nic->vlan->id, mac);
+    xen_config_dev_dirs("vif", "qnic", nic->vlan->id, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "handle",     nic->vlan->id);
+    xenstore_write_str(fe, "mac",        mac);
+
+    /* backend */
+    xenstore_write_int(be, "handle",     nic->vlan->id);
+    xenstore_write_str(be, "mac",        mac);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+    /* backend */
+    xenstore_write_str(be, "type",  type);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
diff --git a/qemu-0.15.x/hw/xen_disk.c b/qemu-0.15.x/hw/xen_disk.c
new file mode 100644
index 0000000..add815f
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_disk.c
@@ -0,0 +1,853 @@
+/*
+ *  xen paravirt block device backend
+ *
+ *  (c) Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "block_int.h"
+#include "qemu-char.h"
+#include "xen_blkif.h"
+#include "xen_backend.h"
+#include "blockdev.h"
+
+/* ------------------------------------------------------------- */
+
+static int syncwrite    = 0;
+static int batch_maps   = 0;
+
+static int max_requests = 32;
+static int use_aio      = 1;
+
+/* ------------------------------------------------------------- */
+
+#define BLOCK_SIZE  512
+#define IOCB_COUNT  (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
+
+struct ioreq {
+    blkif_request_t     req;
+    int16_t             status;
+
+    /* parsed request */
+    off_t               start;
+    QEMUIOVector        v;
+    int                 presync;
+    int                 postsync;
+
+    /* grant mapping */
+    uint32_t            domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t            refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int                 prot;
+    void                *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    void                *pages;
+
+    /* aio status */
+    int                 aio_inflight;
+    int                 aio_errors;
+
+    struct XenBlkDev    *blkdev;
+    QLIST_ENTRY(ioreq)   list;
+};
+
+struct XenBlkDev {
+    struct XenDevice    xendev;  /* must be first */
+    char                *params;
+    char                *mode;
+    char                *type;
+    char                *dev;
+    char                *devtype;
+    const char          *fileproto;
+    const char          *filename;
+    int                 ring_ref;
+    void                *sring;
+    int64_t             file_blk;
+    int64_t             file_size;
+    int                 protocol;
+    blkif_back_rings_t  rings;
+    int                 more_work;
+    int                 cnt_map;
+
+    /* request lists */
+    QLIST_HEAD(inflight_head, ioreq) inflight;
+    QLIST_HEAD(finished_head, ioreq) finished;
+    QLIST_HEAD(freelist_head, ioreq) freelist;
+    int                 requests_total;
+    int                 requests_inflight;
+    int                 requests_finished;
+
+    /* qemu block driver */
+    DriveInfo           *dinfo;
+    BlockDriverState    *bs;
+    QEMUBH              *bh;
+};
+
+/* ------------------------------------------------------------- */
+
+static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq = NULL;
+
+    if (QLIST_EMPTY(&blkdev->freelist)) {
+        if (blkdev->requests_total >= max_requests) {
+            goto out;
+        }
+        /* allocate new struct */
+        ioreq = qemu_mallocz(sizeof(*ioreq));
+        ioreq->blkdev = blkdev;
+        blkdev->requests_total++;
+        qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+    } else {
+        /* get one from freelist */
+        ioreq = QLIST_FIRST(&blkdev->freelist);
+        QLIST_REMOVE(ioreq, list);
+        qemu_iovec_reset(&ioreq->v);
+    }
+    QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
+    blkdev->requests_inflight++;
+
+out:
+    return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    QLIST_REMOVE(ioreq, list);
+    QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
+    blkdev->requests_inflight--;
+    blkdev->requests_finished++;
+}
+
+static void ioreq_release(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    QLIST_REMOVE(ioreq, list);
+    memset(ioreq, 0, sizeof(*ioreq));
+    ioreq->blkdev = blkdev;
+    QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
+    blkdev->requests_finished--;
+}
+
+/*
+ * translate request into iovec + start offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+    uintptr_t mem;
+    size_t len;
+    int i;
+
+    xen_be_printf(&blkdev->xendev, 3,
+                  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
+                  ioreq->req.operation, ioreq->req.nr_segments,
+                  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+        ioreq->prot = PROT_WRITE; /* to memory */
+        break;
+    case BLKIF_OP_WRITE_BARRIER:
+        if (!ioreq->req.nr_segments) {
+            ioreq->presync = 1;
+            return 0;
+        }
+        if (!syncwrite) {
+            ioreq->presync = ioreq->postsync = 1;
+        }
+        /* fall through */
+    case BLKIF_OP_WRITE:
+        ioreq->prot = PROT_READ; /* from memory */
+        if (syncwrite) {
+            ioreq->postsync = 1;
+        }
+        break;
+    default:
+        xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+                      ioreq->req.operation);
+        goto err;
+    };
+
+    if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
+        xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
+        goto err;
+    }
+
+    ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
+    for (i = 0; i < ioreq->req.nr_segments; i++) {
+        if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+            xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+            xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+            xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
+            goto err;
+        }
+
+        ioreq->domids[i] = blkdev->xendev.dom;
+        ioreq->refs[i]   = ioreq->req.seg[i].gref;
+
+        mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
+        len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+        qemu_iovec_add(&ioreq->v, (void*)mem, len);
+    }
+    if (ioreq->start + ioreq->v.size > blkdev->file_size) {
+        xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+        goto err;
+    }
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void ioreq_unmap(struct ioreq *ioreq)
+{
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
+    int i;
+
+    if (ioreq->v.niov == 0) {
+        return;
+    }
+    if (batch_maps) {
+        if (!ioreq->pages) {
+            return;
+        }
+        if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                          strerror(errno));
+        }
+        ioreq->blkdev->cnt_map -= ioreq->v.niov;
+        ioreq->pages = NULL;
+    } else {
+        for (i = 0; i < ioreq->v.niov; i++) {
+            if (!ioreq->page[i]) {
+                continue;
+            }
+            if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                              strerror(errno));
+            }
+            ioreq->blkdev->cnt_map--;
+            ioreq->page[i] = NULL;
+        }
+    }
+}
+
+static int ioreq_map(struct ioreq *ioreq)
+{
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
+    int i;
+
+    if (ioreq->v.niov == 0) {
+        return 0;
+    }
+    if (batch_maps) {
+        ioreq->pages = xc_gnttab_map_grant_refs
+            (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+        if (ioreq->pages == NULL) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0,
+                          "can't map %d grant refs (%s, %d maps)\n",
+                          ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map);
+            return -1;
+        }
+        for (i = 0; i < ioreq->v.niov; i++) {
+            ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE +
+                (uintptr_t)ioreq->v.iov[i].iov_base;
+        }
+        ioreq->blkdev->cnt_map += ioreq->v.niov;
+    } else  {
+        for (i = 0; i < ioreq->v.niov; i++) {
+            ioreq->page[i] = xc_gnttab_map_grant_ref
+                (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+            if (ioreq->page[i] == NULL) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0,
+                              "can't map grant ref %d (%s, %d maps)\n",
+                              ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+                ioreq_unmap(ioreq);
+                return -1;
+            }
+            ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base;
+            ioreq->blkdev->cnt_map++;
+        }
+    }
+    return 0;
+}
+
+static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+    int i, rc;
+    off_t pos;
+
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+        goto err_no_map;
+    }
+    if (ioreq->presync) {
+        bdrv_flush(blkdev->bs);
+    }
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+        pos = ioreq->start;
+        for (i = 0; i < ioreq->v.niov; i++) {
+            rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE,
+                           ioreq->v.iov[i].iov_base,
+                           ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+            if (rc != 0) {
+                xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n",
+                              ioreq->v.iov[i].iov_base,
+                              ioreq->v.iov[i].iov_len);
+                goto err;
+            }
+            pos += ioreq->v.iov[i].iov_len;
+        }
+        break;
+    case BLKIF_OP_WRITE:
+    case BLKIF_OP_WRITE_BARRIER:
+        if (!ioreq->req.nr_segments) {
+            break;
+        }
+        pos = ioreq->start;
+        for (i = 0; i < ioreq->v.niov; i++) {
+            rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
+                            ioreq->v.iov[i].iov_base,
+                            ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+            if (rc != 0) {
+                xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n",
+                              ioreq->v.iov[i].iov_base,
+                              ioreq->v.iov[i].iov_len);
+                goto err;
+            }
+            pos += ioreq->v.iov[i].iov_len;
+        }
+        break;
+    default:
+        /* unknown operation (shouldn't happen -- parse catches this) */
+        goto err;
+    }
+
+    if (ioreq->postsync) {
+        bdrv_flush(blkdev->bs);
+    }
+    ioreq->status = BLKIF_RSP_OKAY;
+
+    ioreq_unmap(ioreq);
+    ioreq_finish(ioreq);
+    return 0;
+
+err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void qemu_aio_complete(void *opaque, int ret)
+{
+    struct ioreq *ioreq = opaque;
+
+    if (ret != 0) {
+        xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+        ioreq->aio_errors++;
+    }
+
+    ioreq->aio_inflight--;
+    if (ioreq->aio_inflight > 0) {
+        return;
+    }
+
+    ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+    ioreq_unmap(ioreq);
+    ioreq_finish(ioreq);
+    qemu_bh_schedule(ioreq->blkdev->bh);
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+        goto err_no_map;
+    }
+
+    ioreq->aio_inflight++;
+    if (ioreq->presync) {
+        bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    }
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+        ioreq->aio_inflight++;
+        bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
+                       &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+                       qemu_aio_complete, ioreq);
+        break;
+    case BLKIF_OP_WRITE:
+    case BLKIF_OP_WRITE_BARRIER:
+        if (!ioreq->req.nr_segments) {
+            break;
+        }
+        ioreq->aio_inflight++;
+        bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
+                        &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+                        qemu_aio_complete, ioreq);
+        break;
+    default:
+        /* unknown operation (shouldn't happen -- parse catches this) */
+        goto err;
+    }
+
+    if (ioreq->postsync) {
+        bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+    }
+    qemu_aio_complete(ioreq, 0);
+
+    return 0;
+
+err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+    struct XenBlkDev  *blkdev = ioreq->blkdev;
+    int               send_notify   = 0;
+    int               have_requests = 0;
+    blkif_response_t  resp;
+    void              *dst;
+
+    resp.id        = ioreq->req.id;
+    resp.operation = ioreq->req.operation;
+    resp.status    = ioreq->status;
+
+    /* Place on the response ring for the relevant domain. */
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+        dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
+        break;
+    case BLKIF_PROTOCOL_X86_32:
+        dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
+                                blkdev->rings.x86_32_part.rsp_prod_pvt);
+        break;
+    case BLKIF_PROTOCOL_X86_64:
+        dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
+                                blkdev->rings.x86_64_part.rsp_prod_pvt);
+        break;
+    default:
+        dst = NULL;
+    }
+    memcpy(dst, &resp, sizeof(resp));
+    blkdev->rings.common.rsp_prod_pvt++;
+
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
+    if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
+        /*
+         * Tail check for pending requests. Allows frontend to avoid
+         * notifications if requests are already in flight (lower
+         * overheads and promotes batching).
+         */
+        RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
+    } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
+        have_requests = 1;
+    }
+
+    if (have_requests) {
+        blkdev->more_work++;
+    }
+    return send_notify;
+}
+
+/* walk finished list, send outstanding responses, free requests */
+static void blk_send_response_all(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq;
+    int send_notify = 0;
+
+    while (!QLIST_EMPTY(&blkdev->finished)) {
+        ioreq = QLIST_FIRST(&blkdev->finished);
+        send_notify += blk_send_response_one(ioreq);
+        ioreq_release(ioreq);
+    }
+    if (send_notify) {
+        xen_be_send_notify(&blkdev->xendev);
+    }
+}
+
+static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
+{
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+        memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
+               sizeof(ioreq->req));
+        break;
+    case BLKIF_PROTOCOL_X86_32:
+        blkif_get_x86_32_req(&ioreq->req,
+                             RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
+        break;
+    case BLKIF_PROTOCOL_X86_64:
+        blkif_get_x86_64_req(&ioreq->req,
+                             RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
+        break;
+    }
+    return 0;
+}
+
+static void blk_handle_requests(struct XenBlkDev *blkdev)
+{
+    RING_IDX rc, rp;
+    struct ioreq *ioreq;
+
+    blkdev->more_work = 0;
+
+    rc = blkdev->rings.common.req_cons;
+    rp = blkdev->rings.common.sring->req_prod;
+    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+    if (use_aio) {
+        blk_send_response_all(blkdev);
+    }
+    while (rc != rp) {
+        /* pull request from ring */
+        if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
+            break;
+        }
+        ioreq = ioreq_start(blkdev);
+        if (ioreq == NULL) {
+            blkdev->more_work++;
+            break;
+        }
+        blk_get_request(blkdev, ioreq, rc);
+        blkdev->rings.common.req_cons = ++rc;
+
+        /* parse them */
+        if (ioreq_parse(ioreq) != 0) {
+            if (blk_send_response_one(ioreq)) {
+                xen_be_send_notify(&blkdev->xendev);
+            }
+            ioreq_release(ioreq);
+            continue;
+        }
+
+        if (use_aio) {
+            /* run i/o in aio mode */
+            ioreq_runio_qemu_aio(ioreq);
+        } else {
+            /* run i/o in sync mode */
+            ioreq_runio_qemu_sync(ioreq);
+        }
+    }
+    if (!use_aio) {
+        blk_send_response_all(blkdev);
+    }
+
+    if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
+        qemu_bh_schedule(blkdev->bh);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_bh(void *opaque)
+{
+    struct XenBlkDev *blkdev = opaque;
+    blk_handle_requests(blkdev);
+}
+
+static void blk_alloc(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    QLIST_INIT(&blkdev->inflight);
+    QLIST_INIT(&blkdev->finished);
+    QLIST_INIT(&blkdev->freelist);
+    blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+    if (xen_mode != XEN_EMULATE) {
+        batch_maps = 1;
+    }
+}
+
+static int blk_init(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int index, qflags, have_barriers, info = 0;
+
+    /* read xenstore entries */
+    if (blkdev->params == NULL) {
+        char *h = NULL;
+        blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+        if (blkdev->params != NULL) {
+            h = strchr(blkdev->params, ':');
+        }
+        if (h != NULL) {
+            blkdev->fileproto = blkdev->params;
+            blkdev->filename  = h+1;
+            *h = 0;
+        } else {
+            blkdev->fileproto = "<unset>";
+            blkdev->filename  = blkdev->params;
+        }
+    }
+    if (!strcmp("aio", blkdev->fileproto)) {
+        blkdev->fileproto = "raw";
+    }
+    if (blkdev->mode == NULL) {
+        blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+    }
+    if (blkdev->type == NULL) {
+        blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+    }
+    if (blkdev->dev == NULL) {
+        blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
+    }
+    if (blkdev->devtype == NULL) {
+        blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+    }
+
+    /* do we have all we need? */
+    if (blkdev->params == NULL ||
+        blkdev->mode == NULL   ||
+        blkdev->type == NULL   ||
+        blkdev->dev == NULL) {
+        goto out_error;
+    }
+
+    /* read-only ? */
+    if (strcmp(blkdev->mode, "w") == 0) {
+        qflags = BDRV_O_RDWR;
+    } else {
+        qflags = 0;
+        info  |= VDISK_READONLY;
+    }
+
+    /* cdrom ? */
+    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
+        info  |= VDISK_CDROM;
+    }
+
+    /* init qemu block driver */
+    index = (blkdev->xendev.dev - 202 * 256) / 16;
+    blkdev->dinfo = drive_get(IF_XEN, 0, index);
+    if (!blkdev->dinfo) {
+        /* setup via xenbus -> create new block driver instance */
+        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+        blkdev->bs = bdrv_new(blkdev->dev);
+        if (blkdev->bs) {
+            if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
+                        bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
+                bdrv_delete(blkdev->bs);
+                blkdev->bs = NULL;
+            }
+        }
+        if (!blkdev->bs) {
+            goto out_error;
+        }
+    } else {
+        /* setup via qemu cmdline -> already setup for us */
+        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
+        blkdev->bs = blkdev->dinfo->bdrv;
+    }
+    blkdev->file_blk  = BLOCK_SIZE;
+    blkdev->file_size = bdrv_getlength(blkdev->bs);
+    if (blkdev->file_size < 0) {
+        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
+                      (int)blkdev->file_size, strerror(-blkdev->file_size),
+                      blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
+        blkdev->file_size = 0;
+    }
+    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
+
+    xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
+                  " size %" PRId64 " (%" PRId64 " MB)\n",
+                  blkdev->type, blkdev->fileproto, blkdev->filename,
+                  blkdev->file_size, blkdev->file_size >> 20);
+
+    /* fill info */
+    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+    xenstore_write_be_int(&blkdev->xendev, "info",            info);
+    xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
+    xenstore_write_be_int(&blkdev->xendev, "sectors",
+                          blkdev->file_size / blkdev->file_blk);
+    return 0;
+
+out_error:
+    qemu_free(blkdev->params);
+    blkdev->params = NULL;
+    qemu_free(blkdev->mode);
+    blkdev->mode = NULL;
+    qemu_free(blkdev->type);
+    blkdev->type = NULL;
+    qemu_free(blkdev->dev);
+    blkdev->dev = NULL;
+    qemu_free(blkdev->devtype);
+    blkdev->devtype = NULL;
+    return -1;
+}
+
+static int blk_connect(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
+        return -1;
+    }
+    if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
+                             &blkdev->xendev.remote_port) == -1) {
+        return -1;
+    }
+
+    blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
+    if (blkdev->xendev.protocol) {
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+            blkdev->protocol = BLKIF_PROTOCOL_X86_32;
+        }
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+            blkdev->protocol = BLKIF_PROTOCOL_X86_64;
+        }
+    }
+
+    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+                                            blkdev->xendev.dom,
+                                            blkdev->ring_ref,
+                                            PROT_READ | PROT_WRITE);
+    if (!blkdev->sring) {
+        return -1;
+    }
+    blkdev->cnt_map++;
+
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+    {
+        blkif_sring_t *sring_native = blkdev->sring;
+        BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
+        break;
+    }
+    case BLKIF_PROTOCOL_X86_32:
+    {
+        blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+
+        BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
+        break;
+    }
+    case BLKIF_PROTOCOL_X86_64:
+    {
+        blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+
+        BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
+        break;
+    }
+    }
+
+    xen_be_bind_evtchn(&blkdev->xendev);
+
+    xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
+                  "remote port %d, local port %d\n",
+                  blkdev->xendev.protocol, blkdev->ring_ref,
+                  blkdev->xendev.remote_port, blkdev->xendev.local_port);
+    return 0;
+}
+
+static void blk_disconnect(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    if (blkdev->bs) {
+        if (!blkdev->dinfo) {
+            /* close/delete only if we created it ourself */
+            bdrv_close(blkdev->bs);
+            bdrv_delete(blkdev->bs);
+        }
+        blkdev->bs = NULL;
+    }
+    xen_be_unbind_evtchn(&blkdev->xendev);
+
+    if (blkdev->sring) {
+        xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+        blkdev->cnt_map--;
+        blkdev->sring = NULL;
+    }
+}
+
+static int blk_free(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    struct ioreq *ioreq;
+
+    while (!QLIST_EMPTY(&blkdev->freelist)) {
+        ioreq = QLIST_FIRST(&blkdev->freelist);
+        QLIST_REMOVE(ioreq, list);
+        qemu_iovec_destroy(&ioreq->v);
+        qemu_free(ioreq);
+    }
+
+    qemu_free(blkdev->params);
+    qemu_free(blkdev->mode);
+    qemu_free(blkdev->type);
+    qemu_free(blkdev->dev);
+    qemu_free(blkdev->devtype);
+    qemu_bh_delete(blkdev->bh);
+    return 0;
+}
+
+static void blk_event(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    qemu_bh_schedule(blkdev->bh);
+}
+
+struct XenDevOps xen_blkdev_ops = {
+    .size       = sizeof(struct XenBlkDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .alloc      = blk_alloc,
+    .init       = blk_init,
+    .connect    = blk_connect,
+    .disconnect = blk_disconnect,
+    .event      = blk_event,
+    .free       = blk_free,
+};
diff --git a/qemu-0.15.x/hw/xen_domainbuild.c b/qemu-0.15.x/hw/xen_domainbuild.c
new file mode 100644
index 0000000..a6a12e5
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_domainbuild.c
@@ -0,0 +1,300 @@
+#include <signal.h>
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "qemu-timer.h"
+#include "qemu-log.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+    struct xs_permissions perms_ro[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ,
+        }};
+    struct xs_permissions perms_rw[] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = XS_PERM_READ | XS_PERM_WRITE,
+        }};
+    const char *writable[] = { "device", "control", "error", NULL };
+    char subpath[256];
+    int i;
+
+    if (!xs_mkdir(xenstore, 0, path)) {
+        fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+	return -1;
+    }
+    if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+        fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+	return -1;
+    }
+
+    for (i = 0; writable[i]; i++) {
+        snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+        if (!xs_mkdir(xenstore, 0, subpath)) {
+            fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
+            return -1;
+        }
+        if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+            fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline)
+{
+    char *dom, uuid_string[42], vm[256], path[256];
+    int i;
+
+    snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+             qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+             qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+             qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+             qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(vm,  sizeof(vm),  "/vm/%s", uuid_string);
+
+    xenstore_domain_mkdir(dom);
+
+    xenstore_write_str(vm, "image/ostype",  "linux");
+    if (kernel)
+        xenstore_write_str(vm, "image/kernel",  kernel);
+    if (ramdisk)
+        xenstore_write_str(vm, "image/ramdisk", ramdisk);
+    if (cmdline)
+        xenstore_write_str(vm, "image/cmdline", cmdline);
+
+    /* name + id */
+    xenstore_write_str(vm,  "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_str(vm,  "uuid",   uuid_string);
+    xenstore_write_str(dom, "name",   qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(dom, "domid",  xen_domid);
+    xenstore_write_str(dom, "vm",     vm);
+
+    /* memory */
+    xenstore_write_int(dom, "memory/target", ram_size >> 10);  // kB
+    xenstore_write_int(vm, "memory",         ram_size >> 20);  // MB
+    xenstore_write_int(vm, "maxmem",         ram_size >> 20);  // MB
+
+    /* cpus */
+    for (i = 0; i < smp_cpus; i++) {
+	snprintf(path, sizeof(path), "cpu/%d/availability",i);
+	xenstore_write_str(dom, path, "online");
+    }
+    xenstore_write_int(vm, "vcpu_avail",  smp_cpus);
+    xenstore_write_int(vm, "vcpus",       smp_cpus);
+
+    /* vnc password */
+    xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+    free(dom);
+    return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+
+    /* signal new domain */
+    xs_introduce_domain(xenstore,
+                        xen_domid,
+                        xenstore_mfn,
+                        xenstore_port);
+
+    /* xenstore */
+    xenstore_write_int(dom, "store/ring-ref",   xenstore_mfn);
+    xenstore_write_int(dom, "store/port",       xenstore_port);
+
+    /* console */
+    xenstore_write_str(dom, "console/type",     "ioemu");
+    xenstore_write_int(dom, "console/limit",    128 * 1024);
+    xenstore_write_int(dom, "console/ring-ref", console_mfn);
+    xenstore_write_int(dom, "console/port",     console_port);
+    xen_config_dev_console(0);
+
+    free(dom);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+    struct xc_dominfo info;
+    int rc;
+
+    rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+    if ((rc != 1) || (info.domid != xen_domid)) {
+        qemu_log("xen: domain %d is gone\n", xen_domid);
+        goto quit;
+    }
+    if (info.dying) {
+        qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
+                 info.crashed  ? "crashed"  : "",
+                 info.shutdown ? "shutdown" : "");
+        goto quit;
+    }
+
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+    return;
+
+quit:
+    qemu_system_shutdown_request();
+    return;
+}
+
+static int xen_domain_watcher(void)
+{
+    int qemu_running = 1;
+    int fd[2], i, n, rc;
+    char byte;
+
+    if (pipe(fd) != 0) {
+        qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno));
+        return -1;
+    }
+    if (fork() != 0)
+        return 0; /* not child */
+
+    /* close all file handles, except stdio/out/err,
+     * our watch pipe and the xen interface handle */
+    n = getdtablesize();
+    for (i = 3; i < n; i++) {
+        if (i == fd[0])
+            continue;
+        if (i == xc_fd(xen_xc)) {
+            continue;
+        }
+        close(i);
+    }
+
+    /* ignore term signals */
+    signal(SIGINT,  SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+
+    /* wait for qemu exiting */
+    while (qemu_running) {
+        rc = read(fd[0], &byte, 1);
+        switch (rc) {
+        case -1:
+            if (errno == EINTR)
+                continue;
+            qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
+            qemu_running = 0;
+            break;
+        case 0:
+            /* EOF -> qemu exited */
+            qemu_running = 0;
+            break;
+        default:
+            qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+            break;
+        }
+    }
+
+    /* cleanup */
+    qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+    xc_domain_destroy(xen_xc, xen_domid);
+    _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    if (dom) {
+        xs_rm(xenstore, 0, dom);
+        free(dom);
+    }
+    xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline)
+{
+    uint32_t ssidref = 0;
+    uint32_t flags = 0;
+    xen_domain_handle_t uuid;
+    unsigned int xenstore_port = 0, console_port = 0;
+    unsigned long xenstore_mfn = 0, console_mfn = 0;
+    int rc;
+
+    memcpy(uuid, qemu_uuid, sizeof(uuid));
+    rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_create() failed\n");
+        goto err;
+    }
+    qemu_log("xen: created domain %d\n", xen_domid);
+    atexit(xen_domain_cleanup);
+    if (xen_domain_watcher() == -1) {
+        goto err;
+    }
+
+    xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+    rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+        goto err;
+    }
+
+#if 0
+    rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+        goto err;
+    }
+#endif
+
+    rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+        goto err;
+    }
+
+    xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+    console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+    rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+                        kernel, ramdisk, cmdline,
+                        0, flags,
+                        xenstore_port, &xenstore_mfn,
+                        console_port, &console_mfn);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_linux_build() failed\n");
+        goto err;
+    }
+
+    xenstore_domain_init2(xenstore_port, xenstore_mfn,
+                          console_port, console_mfn);
+
+    qemu_log("xen: unpausing domain %d\n", xen_domid);
+    rc = xc_domain_unpause(xen_xc, xen_domid);
+    if (rc < 0) {
+        fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+        goto err;
+    }
+
+    xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL);
+    qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+    return 0;
+
+err:
+    return -1;
+}
diff --git a/qemu-0.15.x/hw/xen_domainbuild.h b/qemu-0.15.x/hw/xen_domainbuild.h
new file mode 100644
index 0000000..dea0121
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_domainbuild.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/qemu-0.15.x/hw/xen_machine_pv.c b/qemu-0.15.x/hw/xen_machine_pv.c
new file mode 100644
index 0000000..7985d11
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_machine_pv.c
@@ -0,0 +1,124 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 Red Hat
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "boards.h"
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "blockdev.h"
+
+static void xen_init_pv(ram_addr_t ram_size,
+			const char *boot_device,
+			const char *kernel_filename,
+			const char *kernel_cmdline,
+			const char *initrd_filename,
+			const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    int i;
+
+    /* Initialize a dummy CPU */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    env->halted = 1;
+
+    /* Initialize backend core & drivers */
+    if (xen_be_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+
+    switch (xen_mode) {
+    case XEN_ATTACH:
+        /* nothing to do, xend handles everything */
+        break;
+    case XEN_CREATE:
+        if (xen_domain_build_pv(kernel_filename, initrd_filename,
+                                kernel_cmdline) < 0) {
+            fprintf(stderr, "xen pv domain creation failed\n");
+            exit(1);
+        }
+        break;
+    case XEN_EMULATE:
+        fprintf(stderr, "xen emulation not implemented (yet)\n");
+        exit(1);
+        break;
+    }
+
+    xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("vfb", &xen_framebuffer_ops);
+    xen_be_register("qdisk", &xen_blkdev_ops);
+    xen_be_register("qnic", &xen_netdev_ops);
+
+    /* configure framebuffer */
+    if (xenfb_enabled) {
+        xen_config_dev_vfb(0, "vnc");
+        xen_config_dev_vkbd(0);
+    }
+
+    /* configure disks */
+    for (i = 0; i < 16; i++) {
+        dinfo = drive_get(IF_XEN, 0, i);
+        if (!dinfo)
+            continue;
+        xen_config_dev_blk(dinfo);
+    }
+
+    /* configure nics */
+    for (i = 0; i < nb_nics; i++) {
+        if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
+            continue;
+        xen_config_dev_nic(nd_table + i);
+    }
+
+    /* config cleanup hook */
+    atexit(xen_config_cleanup);
+
+    /* setup framebuffer */
+    xen_init_display(xen_domid);
+}
+
+static QEMUMachine xenpv_machine = {
+    .name = "xenpv",
+    .desc = "Xen Para-virtualized PC",
+    .init = xen_init_pv,
+    .max_cpus = 1,
+    .default_machine_opts = "accel=xen",
+};
+
+static void xenpv_machine_init(void)
+{
+    qemu_register_machine(&xenpv_machine);
+}
+
+machine_init(xenpv_machine_init);
diff --git a/qemu-0.15.x/hw/xen_nic.c b/qemu-0.15.x/hw/xen_nic.c
new file mode 100644
index 0000000..ff86491
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_nic.c
@@ -0,0 +1,440 @@
+/*
+ *  xen paravirt network card backend
+ *
+ *  (c) Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/netif.h>
+
+#include "hw.h"
+#include "net.h"
+#include "net/checksum.h"
+#include "net/util.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct XenNetDev {
+    struct XenDevice      xendev;  /* must be first */
+    char                  *mac;
+    int                   tx_work;
+    int                   tx_ring_ref;
+    int                   rx_ring_ref;
+    struct netif_tx_sring *txs;
+    struct netif_rx_sring *rxs;
+    netif_tx_back_ring_t  tx_ring;
+    netif_rx_back_ring_t  rx_ring;
+    NICConf               conf;
+    NICState              *nic;
+};
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
+{
+    RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
+    netif_tx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
+    resp->id     = txp->id;
+    resp->status = st;
+
+#if 0
+    if (txp->flags & NETTXF_extra_info) {
+        RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+    }
+#endif
+
+    netdev->tx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
+
+    if (i == netdev->tx_ring.req_cons) {
+        int more_to_do;
+        RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
+        if (more_to_do) {
+            netdev->tx_work++;
+        }
+    }
+}
+
+static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end)
+{
+#if 0
+    /*
+     * Hmm, why netback fails everything in the ring?
+     * Should we do that even when not supporting SG and TSO?
+     */
+    RING_IDX cons = netdev->tx_ring.req_cons;
+
+    do {
+        make_tx_response(netif, txp, NETIF_RSP_ERROR);
+        if (cons >= end) {
+            break;
+        }
+        txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
+    } while (1);
+    netdev->tx_ring.req_cons = cons;
+    netif_schedule_work(netif);
+    netif_put(netif);
+#else
+    net_tx_response(netdev, txp, NETIF_RSP_ERROR);
+#endif
+}
+
+static void net_tx_packets(struct XenNetDev *netdev)
+{
+    netif_tx_request_t txreq;
+    RING_IDX rc, rp;
+    void *page;
+    void *tmpbuf = NULL;
+
+    for (;;) {
+        rc = netdev->tx_ring.req_cons;
+        rp = netdev->tx_ring.sring->req_prod;
+        xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+        while ((rc != rp)) {
+            if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) {
+                break;
+            }
+            memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
+            netdev->tx_ring.req_cons = ++rc;
+
+#if 1
+            /* should not happen in theory, we don't announce the *
+             * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
+            if (txreq.flags & NETTXF_extra_info) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_more_data) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+#endif
+
+            if (txreq.size < 14) {
+                xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
+                xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
+                          txreq.gref, txreq.offset, txreq.size, txreq.flags,
+                          (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
+                          (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+                          (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
+                          (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
+
+            page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                           netdev->xendev.dom,
+                                           txreq.gref, PROT_READ);
+            if (page == NULL) {
+                xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
+                              txreq.gref);
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_csum_blank) {
+                /* have read-only mapping -> can't fill checksum in-place */
+                if (!tmpbuf) {
+                    tmpbuf = qemu_malloc(XC_PAGE_SIZE);
+                }
+                memcpy(tmpbuf, page + txreq.offset, txreq.size);
+                net_checksum_calculate(tmpbuf, txreq.size);
+                qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size);
+            } else {
+                qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size);
+            }
+            xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+            net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
+        }
+        if (!netdev->tx_work) {
+            break;
+        }
+        netdev->tx_work = 0;
+    }
+    qemu_free(tmpbuf);
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct XenNetDev *netdev,
+                            netif_rx_request_t *req, int8_t st,
+                            uint16_t offset, uint16_t size,
+                            uint16_t flags)
+{
+    RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
+    netif_rx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
+    resp->offset     = offset;
+    resp->flags      = flags;
+    resp->id         = req->id;
+    resp->status     = (int16_t)size;
+    if (st < 0) {
+        resp->status = (int16_t)st;
+    }
+
+    xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
+                  i, resp->status, resp->flags);
+
+    netdev->rx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
+}
+
+#define NET_IP_ALIGN 2
+
+static int net_rx_ok(VLANClientState *nc)
+{
+    struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque;
+    RING_IDX rc, rp;
+
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return 0;
+    }
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb();
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+        xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
+                      __FUNCTION__, rc, rp);
+        return 0;
+    }
+    return 1;
+}
+
+static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque;
+    netif_rx_request_t rxreq;
+    RING_IDX rc, rp;
+    void *page;
+
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return -1;
+    }
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+        xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
+        return -1;
+    }
+    if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
+        xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
+                      (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
+        return -1;
+    }
+
+    memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
+    netdev->rx_ring.req_cons = ++rc;
+
+    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                   netdev->xendev.dom,
+                                   rxreq.gref, PROT_WRITE);
+    if (page == NULL) {
+        xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
+                      rxreq.gref);
+        net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
+        return -1;
+    }
+    memcpy(page + NET_IP_ALIGN, buf, size);
+    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+    net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
+
+    return size;
+}
+
+/* ------------------------------------------------------------- */
+
+static NetClientInfo net_xen_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = net_rx_ok,
+    .receive = net_rx_packet,
+};
+
+static int net_init(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    /* read xenstore entries */
+    if (netdev->mac == NULL) {
+        netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+    }
+
+    /* do we have all we need? */
+    if (netdev->mac == NULL) {
+        return -1;
+    }
+
+    if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
+        return -1;
+    }
+
+    netdev->conf.vlan = qemu_find_vlan(netdev->xendev.dev, 1);
+    netdev->conf.peer = NULL;
+
+    netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
+                               "xen", NULL, netdev);
+
+    snprintf(netdev->nic->nc.info_str, sizeof(netdev->nic->nc.info_str),
+             "nic: xenbus vif macaddr=%s", netdev->mac);
+
+    /* fill info */
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
+
+    return 0;
+}
+
+static int net_connect(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    int rx_copy;
+
+    if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
+                             &netdev->tx_ring_ref) == -1) {
+        return -1;
+    }
+    if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
+                             &netdev->rx_ring_ref) == -1) {
+        return 1;
+    }
+    if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
+                             &netdev->xendev.remote_port) == -1) {
+        return -1;
+    }
+
+    if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
+        rx_copy = 0;
+    }
+    if (rx_copy == 0) {
+        xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
+        return -1;
+    }
+
+    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                          netdev->xendev.dom,
+                                          netdev->tx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
+    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                          netdev->xendev.dom,
+                                          netdev->rx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
+    if (!netdev->txs || !netdev->rxs) {
+        return -1;
+    }
+    BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
+    BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
+
+    xen_be_bind_evtchn(&netdev->xendev);
+
+    xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
+                  "remote port %d, local port %d\n",
+                  netdev->tx_ring_ref, netdev->rx_ring_ref,
+                  netdev->xendev.remote_port, netdev->xendev.local_port);
+
+    net_tx_packets(netdev);
+    return 0;
+}
+
+static void net_disconnect(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    xen_be_unbind_evtchn(&netdev->xendev);
+
+    if (netdev->txs) {
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+        netdev->txs = NULL;
+    }
+    if (netdev->rxs) {
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+        netdev->rxs = NULL;
+    }
+    if (netdev->nic) {
+        qemu_del_vlan_client(&netdev->nic->nc);
+        netdev->nic = NULL;
+    }
+}
+
+static void net_event(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    net_tx_packets(netdev);
+}
+
+static int net_free(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    qemu_free(netdev->mac);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevOps xen_netdev_ops = {
+    .size       = sizeof(struct XenNetDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = net_init,
+    .connect    = net_connect,
+    .event      = net_event,
+    .disconnect = net_disconnect,
+    .free       = net_free,
+};
diff --git a/qemu-0.15.x/hw/xen_platform.c b/qemu-0.15.x/hw/xen_platform.c
new file mode 100644
index 0000000..f43e175
--- /dev/null
+++ b/qemu-0.15.x/hw/xen_platform.c
@@ -0,0 +1,339 @@
+/*
+ * XEN platform pci device, formerly known as the event channel device
+ *
+ * Copyright (c) 2003-2004 Intel Corp.
+ * Copyright (c) 2006 XenSource
+ *
+ * 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 <assert.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "irq.h"
+#include "xen_common.h"
+#include "net.h"
+#include "xen_backend.h"
+#include "rwhandler.h"
+#include "trace.h"
+
+#include <xenguest.h>
+
+//#define DEBUG_PLATFORM
+
+#ifdef DEBUG_PLATFORM
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState {
+    PCIDevice  pci_dev;
+    uint8_t flags; /* used only for version_id == 2 */
+    int drivers_blacklisted;
+    uint16_t driver_product_version;
+
+    /* Log from guest drivers */
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* Send bytes to syslog */
+static void log_writeb(PCIXenPlatformState *s, char val)
+{
+    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+        /* Flush buffer */
+        s->log_buffer[s->log_buffer_off] = 0;
+        trace_xen_platform_log(s->log_buffer);
+        s->log_buffer_off = 0;
+    } else {
+        s->log_buffer[s->log_buffer_off++] = val;
+    }
+}
+
+/* Xen Platform, Fixed IOPort */
+
+static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* TODO: */
+        /* Unplug devices.  Value is a bitmask of which devices to
+           unplug, with bit 0 the IDE devices, bit 1 the network
+           devices, and bit 2 the non-primary-master IDE devices. */
+        break;
+    case 2:
+        switch (val) {
+        case 1:
+            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            DPRINTF("Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            DPRINTF("Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        s->driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0: /* Platform flags */ {
+        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
+            HVMMEM_ram_ro : HVMMEM_ram_rw;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
+            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
+        } else {
+            s->flags = val & PFFLAG_ROM_LOCK;
+            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
+                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
+        }
+        break;
+    }
+    case 2:
+        log_writeb(s, val);
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        if (s->drivers_blacklisted) {
+            /* The drivers will recognise this magic number and refuse
+             * to do anything. */
+            return 0xd249;
+        } else {
+            /* Magic value so that you can identify the interface. */
+            return 0x49d2;
+        }
+    default:
+        return 0xffff;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* Platform flags */
+        return s->flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_reset(void *opaque)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, 0);
+}
+
+static void platform_fixed_ioport_init(PCIXenPlatformState* s)
+{
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 4, platform_fixed_ioport_writel, s);
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_writew, s);
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_writeb, s);
+    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_readw, s);
+    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_readb, s);
+}
+
+/* Xen Platform PCI Device */
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+    addr &= 0xff;
+
+    if (addr == 0) {
+        return platform_fixed_ioport_readb(opaque, XEN_PLATFORM_IOPORT);
+    } else {
+        return ~0u;
+    }
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    addr &= 0xff;
+    val  &= 0xff;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_writeb(opaque, XEN_PLATFORM_IOPORT, val);
+        break;
+    case 8:
+        log_writeb(s, val);
+        break;
+    default:
+        break;
+    }
+}
+
+static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);
+
+    register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
+    register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
+}
+
+static uint32_t platform_mmio_read(ReadWriteHandler *handler, pcibus_t addr, int len)
+{
+    DPRINTF("Warning: attempted read from physical address "
+            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+
+    return 0;
+}
+
+static void platform_mmio_write(ReadWriteHandler *handler, pcibus_t addr,
+                                uint32_t val, int len)
+{
+    DPRINTF("Warning: attempted write of 0x%x to physical "
+            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+            val, addr);
+}
+
+static ReadWriteHandler platform_mmio_handler = {
+    .read = &platform_mmio_read,
+    .write = &platform_mmio_write,
+};
+
+static void platform_mmio_map(PCIDevice *d, int region_num,
+                              pcibus_t addr, pcibus_t size, int type)
+{
+    int mmio_io_addr;
+
+    mmio_io_addr = cpu_register_io_memory_simple(&platform_mmio_handler,
+                                                 DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(addr, size, mmio_io_addr);
+}
+
+static int xen_platform_post_load(void *opaque, int version_id)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, s->flags);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xen_platform = {
+    .name = "platform",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = xen_platform_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+        VMSTATE_UINT8(flags, PCIXenPlatformState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int xen_platform_initfn(PCIDevice *dev)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = d->pci_dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    pci_config_set_prog_interface(pci_conf, 0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    pci_register_bar(&d->pci_dev, 0, 0x100,
+            PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+
+    /* reserve 16MB mmio address for share memory*/
+    pci_register_bar(&d->pci_dev, 1, 0x1000000,
+            PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+
+    platform_fixed_ioport_init(d);
+
+    return 0;
+}
+
+static void platform_reset(DeviceState *dev)
+{
+    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+
+    platform_fixed_ioport_reset(s);
+}
+
+static PCIDeviceInfo xen_platform_info = {
+    .init = xen_platform_initfn,
+    .qdev.name = "xen-platform",
+    .qdev.desc = "XEN platform pci device",
+    .qdev.size = sizeof(PCIXenPlatformState),
+    .qdev.vmsd = &vmstate_xen_platform,
+    .qdev.reset = platform_reset,
+
+    .vendor_id    =  PCI_VENDOR_ID_XEN,
+    .device_id    = PCI_DEVICE_ID_XEN_PLATFORM,
+    .class_id     = PCI_CLASS_OTHERS << 8 | 0x80,
+    .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
+    .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
+    .revision = 1,
+};
+
+static void xen_platform_register(void)
+{
+    pci_qdev_register(&xen_platform_info);
+}
+
+device_init(xen_platform_register);
diff --git a/qemu-0.15.x/hw/xenfb.c b/qemu-0.15.x/hw/xenfb.c
new file mode 100644
index 0000000..0a01ae3
--- /dev/null
+++ b/qemu-0.15.x/hw/xenfb.c
@@ -0,0 +1,1017 @@
+/*
+ *  xen paravirt framebuffer backend
+ *
+ *  Copyright IBM, Corp. 2005-2006
+ *  Copyright Red Hat, Inc. 2006-2008
+ *
+ *  Authors:
+ *       Anthony Liguori <aliguori at us.ibm.com>,
+ *       Markus Armbruster <armbru at redhat.com>,
+ *       Daniel P. Berrange <berrange at redhat.com>,
+ *       Pat Campbell <plc at novell.com>,
+ *       Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/event_channel.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/fbif.h>
+#include <xen/io/kbdif.h>
+#include <xen/io/protocols.h>
+
+#include "hw.h"
+#include "console.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+#ifndef BTN_LEFT
+#define BTN_LEFT 0x110 /* from <linux/input.h> */
+#endif
+
+/* -------------------------------------------------------------------- */
+
+struct common {
+    struct XenDevice  xendev;  /* must be first */
+    void              *page;
+    DisplayState      *ds;
+};
+
+struct XenInput {
+    struct common c;
+    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
+    int button_state;       /* Last seen pointer button state */
+    int extended;
+    QEMUPutMouseEntry *qmouse;
+};
+
+#define UP_QUEUE 8
+
+struct XenFB {
+    struct common     c;
+    size_t            fb_len;
+    int               row_stride;
+    int               depth;
+    int               width;
+    int               height;
+    int               offset;
+    void              *pixels;
+    int               fbpages;
+    int               feature_update;
+    int               refresh_period;
+    int               bug_trigger;
+    int               have_console;
+    int               do_resize;
+
+    struct {
+	int x,y,w,h;
+    } up_rects[UP_QUEUE];
+    int               up_count;
+    int               up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct common *c)
+{
+    int mfn;
+
+    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
+	return -1;
+    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
+	return -1;
+
+    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
+				   XC_PAGE_SIZE,
+				   PROT_READ | PROT_WRITE, mfn);
+    if (c->page == NULL)
+	return -1;
+
+    xen_be_bind_evtchn(&c->xendev);
+    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
+		  mfn, c->xendev.remote_port, c->xendev.local_port);
+
+    return 0;
+}
+
+static void common_unbind(struct common *c)
+{
+    xen_be_unbind_evtchn(&c->xendev);
+    if (c->page) {
+	munmap(c->page, XC_PAGE_SIZE);
+	c->page = NULL;
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+#if 0
+/*
+ * These two tables are not needed any more, but left in here
+ * intentionally as documentation, to show how scancode2linux[]
+ * was generated.
+ *
+ * Tables to map from scancode to Linux input layer keycode.
+ * Scancodes are hardware-specific.  These maps assumes a
+ * standard AT or PS/2 keyboard which is what QEMU feeds us.
+ */
+const unsigned char atkbd_set2_keycode[512] = {
+
+     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
+     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
+     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
+     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
+     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
+     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
+     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
+    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
+    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
+    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
+    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
+    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
+    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
+
+};
+
+const unsigned char atkbd_unxlate_table[128] = {
+
+      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
+     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
+    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
+     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+
+};
+#endif
+
+/*
+ * for (i = 0; i < 128; i++) {
+ *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+ *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+ * }
+ */
+static const unsigned char scancode2linux[512] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
+    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
+    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
+    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
+      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct XenInput *xenfb,
+			   union xenkbd_in_event *event)
+{
+    struct xenkbd_page *page = xenfb->c.page;
+    uint32_t prod;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+	return 0;
+    if (!page)
+        return 0;
+
+    prod = page->in_prod;
+    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+	errno = EAGAIN;
+	return -1;
+    }
+
+    xen_mb();		/* ensure ring space available */
+    XENKBD_IN_RING_REF(page, prod) = *event;
+    xen_wmb();		/* ensure ring contents visible */
+    page->in_prod = prod + 1;
+    return xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* Send a keyboard (or mouse button) event */
+static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_KEY;
+    event.key.pressed = down ? 1 : 0;
+    event.key.keycode = keycode;
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send a relative mouse movement event */
+static int xenfb_send_motion(struct XenInput *xenfb,
+			     int rel_x, int rel_y, int rel_z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_MOTION;
+    event.motion.rel_x = rel_x;
+    event.motion.rel_y = rel_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
+    event.motion.rel_z = rel_z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send an absolute mouse movement event */
+static int xenfb_send_position(struct XenInput *xenfb,
+			       int abs_x, int abs_y, int z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_POS;
+    event.pos.abs_x = abs_x;
+    event.pos.abs_y = abs_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
+    event.pos.abs_z = z;
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
+    event.pos.rel_z = z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/*
+ * Send a key event from the client to the guest OS
+ * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * We have to turn this into a Linux Input layer keycode.
+ *
+ * Extra complexity from the fact that with extended scancodes
+ * (like those produced by arrow keys) this method gets called
+ * twice, but we only want to send a single event. So we have to
+ * track the '0xe0' scancode state & collapse the extended keys
+ * as needed.
+ *
+ * Wish we could just send scancodes straight to the guest which
+ * already has code for dealing with this...
+ */
+static void xenfb_key_event(void *opaque, int scancode)
+{
+    struct XenInput *xenfb = opaque;
+    int down = 1;
+
+    if (scancode == 0xe0) {
+	xenfb->extended = 1;
+	return;
+    } else if (scancode & 0x80) {
+	scancode &= 0x7f;
+	down = 0;
+    }
+    if (xenfb->extended) {
+	scancode |= 0x80;
+	xenfb->extended = 0;
+    }
+    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
+}
+
+/*
+ * Send a mouse event from the client to the guest OS
+ *
+ * The QEMU mouse can be in either relative, or absolute mode.
+ * Movement is sent separately from button state, which has to
+ * be encoded as virtual key events. We also don't actually get
+ * given any button up/down events, so have to track changes in
+ * the button state.
+ */
+static void xenfb_mouse_event(void *opaque,
+			      int dx, int dy, int dz, int button_state)
+{
+    struct XenInput *xenfb = opaque;
+    int dw = ds_get_width(xenfb->c.ds);
+    int dh = ds_get_height(xenfb->c.ds);
+    int i;
+
+    if (xenfb->abs_pointer_wanted)
+	xenfb_send_position(xenfb,
+			    dx * (dw - 1) / 0x7fff,
+			    dy * (dh - 1) / 0x7fff,
+			    dz);
+    else
+	xenfb_send_motion(xenfb, dx, dy, dz);
+
+    for (i = 0 ; i < 8 ; i++) {
+	int lastDown = xenfb->button_state & (1 << i);
+	int down = button_state & (1 << i);
+	if (down == lastDown)
+	    continue;
+
+	if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
+	    return;
+    }
+    xenfb->button_state = button_state;
+}
+
+static int input_init(struct XenDevice *xendev)
+{
+    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
+    return 0;
+}
+
+static int input_connect(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+    int rc;
+
+    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+                             &in->abs_pointer_wanted) == -1)
+	in->abs_pointer_wanted = 0;
+
+    if (!in->c.ds) {
+        char *vfb = xenstore_read_str(NULL, "device/vfb");
+        if (vfb == NULL) {
+            /* there is no vfb, run vkbd on its own */
+            in->c.ds = get_displaystate();
+        } else {
+            qemu_free(vfb);
+            xen_be_printf(xendev, 1, "ds not set (yet)\n");
+            return -1;
+        }
+    }
+
+    rc = common_bind(&in->c);
+    if (rc != 0)
+	return rc;
+
+    qemu_add_kbd_event_handler(xenfb_key_event, in);
+    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
+					      in->abs_pointer_wanted,
+					      "Xen PVFB Mouse");
+    return 0;
+}
+
+static void input_disconnect(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (in->qmouse) {
+	qemu_remove_mouse_event_handler(in->qmouse);
+	in->qmouse = NULL;
+    }
+    qemu_add_kbd_event_handler(NULL, NULL);
+    common_unbind(&in->c);
+}
+
+static void input_event(struct XenDevice *xendev)
+{
+    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
+    struct xenkbd_page *page = xenfb->c.page;
+
+    /* We don't understand any keyboard events, so just ignore them. */
+    if (page->out_prod == page->out_cons)
+	return;
+    page->out_cons = page->out_prod;
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
+{
+    uint32_t *src32 = src;
+    uint64_t *src64 = src;
+    int i;
+
+    for (i = 0; i < count; i++)
+	dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static int xenfb_map_fb(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    char *protocol = xenfb->c.xendev.protocol;
+    int n_fbdirs;
+    unsigned long *pgmfns = NULL;
+    unsigned long *fbmfns = NULL;
+    void *map, *pd;
+    int mode, ret = -1;
+
+    /* default to native */
+    pd = page->pd;
+    mode = sizeof(unsigned long) * 8;
+
+    if (!protocol) {
+	/*
+	 * Undefined protocol, some guesswork needed.
+	 *
+	 * Old frontends which don't set the protocol use
+	 * one page directory only, thus pd[1] must be zero.
+	 * pd[1] of the 32bit struct layout and the lower
+	 * 32 bits of pd[0] of the 64bit struct layout have
+	 * the same location, so we can check that ...
+	 */
+	uint32_t *ptr32 = NULL;
+	uint32_t *ptr64 = NULL;
+#if defined(__i386__)
+	ptr32 = (void*)page->pd;
+	ptr64 = ((void*)page->pd) + 4;
+#elif defined(__x86_64__)
+	ptr32 = ((void*)page->pd) - 4;
+	ptr64 = (void*)page->pd;
+#endif
+	if (ptr32) {
+	    if (ptr32[1] == 0) {
+		mode = 32;
+		pd   = ptr32;
+	    } else {
+		mode = 64;
+		pd   = ptr64;
+	    }
+	}
+#if defined(__x86_64__)
+    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+	/* 64bit dom0, 32bit domU */
+	mode = 32;
+	pd   = ((void*)page->pd) - 4;
+#elif defined(__i386__)
+    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+	/* 32bit dom0, 64bit domU */
+	mode = 64;
+	pd   = ((void*)page->pd) + 4;
+#endif
+    }
+
+    if (xenfb->pixels) {
+        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
+        xenfb->pixels = NULL;
+    }
+
+    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+    n_fbdirs = xenfb->fbpages * mode / 8;
+    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+
+    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
+    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+			       PROT_READ, pgmfns, n_fbdirs);
+    if (map == NULL)
+	goto out;
+    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
+    munmap(map, n_fbdirs * XC_PAGE_SIZE);
+
+    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+					 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
+    if (xenfb->pixels == NULL)
+	goto out;
+
+    ret = 0; /* all is fine */
+
+out:
+    qemu_free(pgmfns);
+    qemu_free(fbmfns);
+    return ret;
+}
+
+static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
+			      int width, int height, int depth,
+			      size_t fb_len, int offset, int row_stride)
+{
+    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
+    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
+    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
+    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
+    int max_width, max_height;
+
+    if (fb_len_lim > fb_len_max) {
+	xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
+		      fb_len_lim, fb_len_max);
+	fb_len_lim = fb_len_max;
+    }
+    if (fb_len_lim && fb_len > fb_len_lim) {
+	xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
+		      fb_len, fb_len_lim);
+	fb_len = fb_len_lim;
+    }
+    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
+	xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
+		      depth);
+	return -1;
+    }
+    if (row_stride <= 0 || row_stride > fb_len) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
+	return -1;
+    }
+    max_width = row_stride / (depth / 8);
+    if (width < 0 || width > max_width) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
+		      width, max_width);
+	width = max_width;
+    }
+    if (offset < 0 || offset >= fb_len) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
+		      offset, fb_len - 1);
+	return -1;
+    }
+    max_height = (fb_len - offset) / row_stride;
+    if (height < 0 || height > max_height) {
+	xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
+		      height, max_height);
+	height = max_height;
+    }
+    xenfb->fb_len = fb_len;
+    xenfb->row_stride = row_stride;
+    xenfb->depth = depth;
+    xenfb->width = width;
+    xenfb->height = height;
+    xenfb->offset = offset;
+    xenfb->up_fullscreen = 1;
+    xenfb->do_resize = 1;
+    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
+		  width, height, depth, offset, row_stride);
+    return 0;
+}
+
+/* A convenient function for munging pixels between different depths */
+#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
+    for (line = y ; line < (y+h) ; line++) {				\
+	SRC_T *src = (SRC_T *)(xenfb->pixels				\
+			       + xenfb->offset				\
+			       + (line * xenfb->row_stride)		\
+			       + (x * xenfb->depth / 8));		\
+	DST_T *dst = (DST_T *)(data					\
+			       + (line * linesize)			\
+			       + (x * bpp / 8));			\
+	int col;							\
+	const int RSS = 32 - (RSB + GSB + BSB);				\
+	const int GSS = 32 - (GSB + BSB);				\
+	const int BSS = 32 - (BSB);					\
+	const uint32_t RSM = (~0U) << (32 - RSB);			\
+	const uint32_t GSM = (~0U) << (32 - GSB);			\
+	const uint32_t BSM = (~0U) << (32 - BSB);			\
+	const int RDS = 32 - (RDB + GDB + BDB);				\
+	const int GDS = 32 - (GDB + BDB);				\
+	const int BDS = 32 - (BDB);					\
+	const uint32_t RDM = (~0U) << (32 - RDB);			\
+	const uint32_t GDM = (~0U) << (32 - GDB);			\
+	const uint32_t BDM = (~0U) << (32 - BDB);			\
+	for (col = x ; col < (x+w) ; col++) {				\
+	    uint32_t spix = *src;					\
+	    *dst = (((spix << RSS) & RSM & RDM) >> RDS) |		\
+		(((spix << GSS) & GSM & GDM) >> GDS) |			\
+		(((spix << BSS) & BSM & BDM) >> BDS);			\
+	    src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);	\
+	    dst = (DST_T *) ((unsigned long) dst + bpp / 8);		\
+	}								\
+    }
+
+
+/*
+ * This copies data from the guest framebuffer region, into QEMU's
+ * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
+ * uses something else we must convert and copy, otherwise we can
+ * supply the buffer directly and no thing here.
+ */
+static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
+{
+    int line, oops = 0;
+    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
+    int linesize = ds_get_linesize(xenfb->c.ds);
+    uint8_t *data = ds_get_data(xenfb->c.ds);
+
+    if (!is_buffer_shared(xenfb->c.ds->surface)) {
+        switch (xenfb->depth) {
+        case 8:
+            if (bpp == 16) {
+                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        case 24:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        default:
+            oops = 1;
+	}
+    }
+    if (oops) /* should not happen */
+        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
+                      __FUNCTION__, xenfb->depth, bpp);
+
+    dpy_update(xenfb->c.ds, x, y, w, h);
+}
+
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+static int xenfb_queue_full(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    uint32_t cons, prod;
+
+    if (!page)
+        return 1;
+
+    prod = page->in_prod;
+    cons = page->in_cons;
+    return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
+{
+    uint32_t prod;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->in_prod;
+    /* caller ensures !xenfb_queue_full() */
+    xen_mb();                   /* ensure ring space available */
+    XENFB_IN_RING_REF(page, prod) = *event;
+    xen_wmb();                  /* ensure ring contents visible */
+    page->in_prod = prod + 1;
+
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
+{
+    union xenfb_in_event event;
+
+    memset(&event, 0, sizeof(event));
+    event.type = XENFB_TYPE_REFRESH_PERIOD;
+    event.refresh_period.period = period;
+    xenfb_send_event(xenfb, &event);
+}
+#endif
+
+/*
+ * Periodic update of display.
+ * Also transmit the refresh interval to the frontend.
+ *
+ * Never ever do any qemu display operations
+ * (resize, screen update) outside this function.
+ * Our screen might be inactive.  When asked for
+ * an update we know it is active.
+ */
+static void xenfb_update(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    int i;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+        return;
+
+    if (xenfb->feature_update) {
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+        struct DisplayChangeListener *l;
+        int period = 99999999;
+        int idle = 1;
+
+	if (xenfb_queue_full(xenfb))
+	    return;
+
+        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
+            if (l->idle)
+                continue;
+            idle = 0;
+            if (!l->gui_timer_interval) {
+                if (period > GUI_REFRESH_INTERVAL)
+                    period = GUI_REFRESH_INTERVAL;
+            } else {
+                if (period > l->gui_timer_interval)
+                    period = l->gui_timer_interval;
+            }
+        }
+        if (idle)
+	    period = XENFB_NO_REFRESH;
+
+	if (xenfb->refresh_period != period) {
+	    xenfb_send_refresh_period(xenfb, period);
+	    xenfb->refresh_period = period;
+            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
+	}
+#else
+	; /* nothing */
+#endif
+    } else {
+	/* we don't get update notifications, thus use the
+	 * sledge hammer approach ... */
+	xenfb->up_fullscreen = 1;
+    }
+
+    /* resize if needed */
+    if (xenfb->do_resize) {
+        xenfb->do_resize = 0;
+        switch (xenfb->depth) {
+        case 16:
+        case 32:
+            /* console.c supported depth -> buffer can be used directly */
+            qemu_free_displaysurface(xenfb->c.ds);
+            xenfb->c.ds->surface = qemu_create_displaysurface_from
+                (xenfb->width, xenfb->height, xenfb->depth,
+                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
+            break;
+        default:
+            /* we must convert stuff */
+            qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
+            break;
+        }
+        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
+                      xenfb->width, xenfb->height, xenfb->depth,
+                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
+        dpy_resize(xenfb->c.ds);
+        xenfb->up_fullscreen = 1;
+    }
+
+    /* run queued updates */
+    if (xenfb->up_fullscreen) {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
+	xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
+    } else if (xenfb->up_count) {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
+	for (i = 0; i < xenfb->up_count; i++)
+	    xenfb_guest_copy(xenfb,
+			     xenfb->up_rects[i].x,
+			     xenfb->up_rects[i].y,
+			     xenfb->up_rects[i].w,
+			     xenfb->up_rects[i].h);
+    } else {
+	xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
+    }
+    xenfb->up_count = 0;
+    xenfb->up_fullscreen = 0;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    xenfb->up_fullscreen = 1;
+}
+
+static void xenfb_handle_events(struct XenFB *xenfb)
+{
+    uint32_t prod, cons;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->out_prod;
+    if (prod == page->out_cons)
+	return;
+    xen_rmb();		/* ensure we see ring contents up to prod */
+    for (cons = page->out_cons; cons != prod; cons++) {
+	union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+	int x, y, w, h;
+
+	switch (event->type) {
+	case XENFB_TYPE_UPDATE:
+	    if (xenfb->up_count == UP_QUEUE)
+		xenfb->up_fullscreen = 1;
+	    if (xenfb->up_fullscreen)
+		break;
+	    x = MAX(event->update.x, 0);
+	    y = MAX(event->update.y, 0);
+	    w = MIN(event->update.width, xenfb->width - x);
+	    h = MIN(event->update.height, xenfb->height - y);
+	    if (w < 0 || h < 0) {
+                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
+		break;
+	    }
+	    if (x != event->update.x ||
+                y != event->update.y ||
+		w != event->update.width ||
+		h != event->update.height) {
+                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
+	    }
+	    if (w == xenfb->width && h > xenfb->height / 2) {
+		/* scroll detector: updated more than 50% of the lines,
+		 * don't bother keeping track of the rectangles then */
+		xenfb->up_fullscreen = 1;
+	    } else {
+		xenfb->up_rects[xenfb->up_count].x = x;
+		xenfb->up_rects[xenfb->up_count].y = y;
+		xenfb->up_rects[xenfb->up_count].w = w;
+		xenfb->up_rects[xenfb->up_count].h = h;
+		xenfb->up_count++;
+	    }
+	    break;
+#ifdef XENFB_TYPE_RESIZE
+	case XENFB_TYPE_RESIZE:
+	    if (xenfb_configure_fb(xenfb, xenfb->fb_len,
+				   event->resize.width,
+				   event->resize.height,
+				   event->resize.depth,
+				   xenfb->fb_len,
+				   event->resize.offset,
+				   event->resize.stride) < 0)
+		break;
+	    xenfb_invalidate(xenfb);
+	    break;
+#endif
+	}
+    }
+    xen_mb();		/* ensure we're done with ring contents */
+    page->out_cons = cons;
+}
+
+static int fb_init(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+    xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+    return 0;
+}
+
+static int fb_connect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+    struct xenfb_page *fb_page;
+    int videoram;
+    int rc;
+
+    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
+	videoram = 0;
+
+    rc = common_bind(&fb->c);
+    if (rc != 0)
+	return rc;
+
+    fb_page = fb->c.page;
+    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
+			    fb_page->width, fb_page->height, fb_page->depth,
+			    fb_page->mem_length, 0, fb_page->line_length);
+    if (rc != 0)
+	return rc;
+
+    rc = xenfb_map_fb(fb);
+    if (rc != 0)
+	return rc;
+
+#if 0  /* handled in xen_init_display() for now */
+    if (!fb->have_console) {
+        fb->c.ds = graphic_console_init(xenfb_update,
+                                        xenfb_invalidate,
+                                        NULL,
+                                        NULL,
+                                        fb);
+        fb->have_console = 1;
+    }
+#endif
+
+    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
+	fb->feature_update = 0;
+    if (fb->feature_update)
+	xenstore_write_be_int(xendev, "request-update", 1);
+
+    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+		  fb->feature_update, videoram);
+    return 0;
+}
+
+static void fb_disconnect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * FIXME: qemu can't un-init gfx display (yet?).
+     *   Replacing the framebuffer with anonymous shared memory
+     *   instead.  This releases the guest pages and keeps qemu happy.
+     */
+    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
+                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
+                      -1, 0);
+    common_unbind(&fb->c);
+    fb->feature_update = 0;
+    fb->bug_trigger    = 0;
+}
+
+static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * Set state to Connected *again* once the frontend switched
+     * to connected.  We must trigger the watch a second time to
+     * workaround a frontend bug.
+     */
+    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
+        xendev->fe_state == XenbusStateConnected &&
+        xendev->be_state == XenbusStateConnected) {
+        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
+        xen_be_set_state(xendev, XenbusStateConnected);
+        fb->bug_trigger = 1; /* only once */
+    }
+}
+
+static void fb_event(struct XenDevice *xendev)
+{
+    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
+
+    xenfb_handle_events(xenfb);
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_kbdmouse_ops = {
+    .size       = sizeof(struct XenInput),
+    .init       = input_init,
+    .connect    = input_connect,
+    .disconnect = input_disconnect,
+    .event      = input_event,
+};
+
+struct XenDevOps xen_framebuffer_ops = {
+    .size       = sizeof(struct XenFB),
+    .init       = fb_init,
+    .connect    = fb_connect,
+    .disconnect = fb_disconnect,
+    .event      = fb_event,
+    .frontend_changed = fb_frontend_changed,
+};
+
+/*
+ * FIXME/TODO: Kill this.
+ * Temporary needed while DisplayState reorganization is in flight.
+ */
+void xen_init_display(int domid)
+{
+    struct XenDevice *xfb, *xin;
+    struct XenFB *fb;
+    struct XenInput *in;
+    int i = 0;
+
+wait_more:
+    i++;
+    main_loop_wait(true);
+    xfb = xen_be_find_xendev("vfb", domid, 0);
+    xin = xen_be_find_xendev("vkbd", domid, 0);
+    if (!xfb || !xin) {
+        if (i < 256) {
+            usleep(10000);
+            goto wait_more;
+        }
+        xen_be_printf(NULL, 1, "displaystate setup failed\n");
+        return;
+    }
+
+    /* vfb */
+    fb = container_of(xfb, struct XenFB, c.xendev);
+    fb->c.ds = graphic_console_init(xenfb_update,
+                                    xenfb_invalidate,
+                                    NULL,
+                                    NULL,
+                                    fb);
+    fb->have_console = 1;
+
+    /* vkbd */
+    in = container_of(xin, struct XenInput, c.xendev);
+    in->c.ds = fb->c.ds;
+
+    /* retry ->init() */
+    xen_be_check_state(xin);
+    xen_be_check_state(xfb);
+}
diff --git a/qemu-0.15.x/hw/xics.c b/qemu-0.15.x/hw/xics.c
new file mode 100644
index 0000000..13a1d25
--- /dev/null
+++ b/qemu-0.15.x/hw/xics.c
@@ -0,0 +1,496 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw.h"
+#include "hw/spapr.h"
+#include "hw/xics.h"
+
+#include <pthread.h>
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+    uint32_t xirr;
+    uint8_t pending_priority;
+    uint8_t mfrr;
+    qemu_irq output;
+};
+
+#define XISR_MASK  0x00ffffff
+#define CPPR_MASK  0xff000000
+
+#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
+#define CPPR(ss)   (((ss)->xirr) >> 24)
+
+struct ics_state;
+
+struct icp_state {
+    long nr_servers;
+    struct icp_server_state *ss;
+    struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+        return;
+    }
+
+    if (XISR(ss)) {
+        ics_reject(icp->ics, XISR(ss));
+    }
+
+    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
+    ss->pending_priority = ss->mfrr;
+    qemu_irq_raise(ss->output);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (ss->mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, server);
+    }
+    ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+    uint8_t old_cppr;
+    uint32_t old_xisr;
+
+    old_cppr = CPPR(ss);
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+
+    if (cppr < old_cppr) {
+        if (XISR(ss) && (cppr <= ss->pending_priority)) {
+            old_xisr = XISR(ss);
+            ss->xirr &= ~XISR_MASK; /* Clear XISR */
+            qemu_irq_lower(ss->output);
+            ics_reject(icp->ics, old_xisr);
+        }
+    } else {
+        if (!XISR(ss)) {
+            icp_resend(icp, server);
+        }
+    }
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
+{
+    struct icp_server_state *ss = icp->ss + nr;
+
+    ss->mfrr = mfrr;
+    if (mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, nr);
+    }
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+    uint32_t xirr;
+
+    qemu_irq_lower(ss->output);
+    xirr = ss->xirr;
+    ss->xirr = ss->pending_priority << 24;
+    return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    ics_eoi(icp->ics, xirr & XISR_MASK);
+    /* Send EOI -> ICS */
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+    if (!XISR(ss)) {
+        icp_resend(icp, server);
+    }
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if ((priority >= CPPR(ss))
+        || (XISR(ss) && (ss->pending_priority <= priority))) {
+        ics_reject(icp->ics, nr);
+    } else {
+        if (XISR(ss)) {
+            ics_reject(icp->ics, XISR(ss));
+        }
+        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+        ss->pending_priority = priority;
+        qemu_irq_raise(ss->output);
+    }
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+    int server;
+    uint8_t priority;
+    uint8_t saved_priority;
+    /* int pending:1; */
+    /* int presented:1; */
+    int rejected:1;
+    int masked_pending:1;
+};
+
+struct ics_state {
+    int nr_irqs;
+    int offset;
+    qemu_irq *qirqs;
+    struct ics_irq_state *irqs;
+    struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+    return (nr >= ics->offset)
+        && (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void ics_set_irq_msi(void *opaque, int nr, int val)
+{
+    struct ics_state *ics = (struct ics_state *)opaque;
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    if (val) {
+        if (irq->priority == 0xff) {
+            irq->masked_pending = 1;
+            /* masked pending */ ;
+        } else  {
+            icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority);
+        }
+    }
+}
+
+static void ics_reject_msi(struct ics_state *ics, int nr)
+{
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+    irq->rejected = 1;
+}
+
+static void ics_resend_msi(struct ics_state *ics)
+{
+    int i;
+
+    for (i = 0; i < ics->nr_irqs; i++) {
+        struct ics_irq_state *irq = ics->irqs + i;
+
+        /* FIXME: filter by server#? */
+        if (irq->rejected) {
+            irq->rejected = 0;
+            if (irq->priority != 0xff) {
+                icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
+            }
+        }
+    }
+}
+
+static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
+                               uint8_t priority)
+{
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    irq->server = server;
+    irq->priority = priority;
+
+    if (!irq->masked_pending || (priority == 0xff)) {
+        return;
+    }
+
+    irq->masked_pending = 0;
+    icp_irq(ics->icp, server, nr + ics->offset, priority);
+}
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+    ics_reject_msi(ics, nr);
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+    ics_resend_msi(ics);
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+}
+
+/*
+ * Exported functions
+ */
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
+{
+    if ((irq < icp->ics->offset)
+        || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
+        return NULL;
+    }
+
+    return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong cppr = args[0];
+
+    icp_set_cppr(spapr->icp, env->cpu_index, cppr);
+    return H_SUCCESS;
+}
+
+static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong server = args[0];
+    target_ulong mfrr = args[1];
+
+    if (server >= spapr->icp->nr_servers) {
+        return H_PARAMETER;
+    }
+
+    icp_set_mfrr(spapr->icp, server, mfrr);
+    return H_SUCCESS;
+
+}
+
+static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index);
+
+    args[0] = xirr;
+    return H_SUCCESS;
+}
+
+static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong xirr = args[0];
+
+    icp_eoi(spapr->icp, env->cpu_index, xirr);
+    return H_SUCCESS;
+}
+
+static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr, server, priority;
+
+    if ((nargs != 3) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+    server = rtas_ld(args, 1);
+    priority = rtas_ld(args, 2);
+
+    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+        || (priority > 0xff)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive_msi(ics, nr - ics->offset, server, priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 3)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
+    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    irq->saved_priority = irq->priority;
+    ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
+                        uint32_t nargs, target_ulong args,
+                        uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    ics_write_xive_msi(xics, nr - xics->offset,
+                       irq->server, irq->saved_priority);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+struct icp_state *xics_system_init(int nr_irqs)
+{
+    CPUState *env;
+    int max_server_num;
+    int i;
+    struct icp_state *icp;
+    struct ics_state *ics;
+
+    max_server_num = -1;
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index > max_server_num) {
+            max_server_num = env->cpu_index;
+        }
+    }
+
+    icp = qemu_mallocz(sizeof(*icp));
+    icp->nr_servers = max_server_num + 1;
+    icp->ss = qemu_mallocz(icp->nr_servers*sizeof(struct icp_server_state));
+
+    for (i = 0; i < icp->nr_servers; i++) {
+        icp->ss[i].mfrr = 0xff;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        struct icp_server_state *ss = &icp->ss[env->cpu_index];
+
+        switch (PPC_INPUT(env)) {
+        case PPC_FLAGS_INPUT_POWER7:
+            ss->output = env->irq_inputs[POWER7_INPUT_INT];
+            break;
+
+        case PPC_FLAGS_INPUT_970:
+            ss->output = env->irq_inputs[PPC970_INPUT_INT];
+            break;
+
+        default:
+            hw_error("XICS interrupt model does not support this CPU bus "
+                     "model\n");
+            exit(1);
+        }
+    }
+
+    ics = qemu_mallocz(sizeof(*ics));
+    ics->nr_irqs = nr_irqs;
+    ics->offset = 16;
+    ics->irqs = qemu_mallocz(nr_irqs * sizeof(struct ics_irq_state));
+
+    icp->ics = ics;
+    ics->icp = icp;
+
+    for (i = 0; i < nr_irqs; i++) {
+        ics->irqs[i].priority = 0xff;
+        ics->irqs[i].saved_priority = 0xff;
+    }
+
+    ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
+
+    spapr_register_hypercall(H_CPPR, h_cppr);
+    spapr_register_hypercall(H_IPI, h_ipi);
+    spapr_register_hypercall(H_XIRR, h_xirr);
+    spapr_register_hypercall(H_EOI, h_eoi);
+
+    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+    spapr_rtas_register("ibm,int-off", rtas_int_off);
+    spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+    return icp;
+}
diff --git a/qemu-0.15.x/hw/xics.h b/qemu-0.15.x/hw/xics.h
new file mode 100644
index 0000000..83c1182
--- /dev/null
+++ b/qemu-0.15.x/hw/xics.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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(__XICS_H__)
+#define __XICS_H__
+
+#define XICS_IPI        0x2
+
+struct icp_state;
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq);
+
+struct icp_state *xics_system_init(int nr_irqs);
+
+#endif /* __XICS_H__ */
diff --git a/qemu-0.15.x/hw/xilinx.h b/qemu-0.15.x/hw/xilinx.h
new file mode 100644
index 0000000..090e6f7
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx.h
@@ -0,0 +1,89 @@
+
+/* OPB Interrupt Controller.  */
+qemu_irq *microblaze_pic_init_cpu(CPUState *env);
+
+static inline DeviceState *
+xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "xilinx,intc");
+    qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+/* OPB Timer/Counter.  */
+static inline DeviceState *
+xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int nr, int freq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "xilinx,timer");
+    qdev_prop_set_uint32(dev, "nr-timers", nr);
+    qdev_prop_set_uint32(dev, "frequency", freq);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+/* XPS Ethernet Lite MAC.  */
+static inline DeviceState *
+xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+                      int txpingpong, int rxpingpong)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(nd, "xilinx-ethlite");
+
+    dev = qdev_create(NULL, "xilinx,ethlite");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "txpingpong", txpingpong);
+    qdev_prop_set_uint32(dev, "rxpingpong", rxpingpong);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+static inline DeviceState *
+xilinx_axiethernet_create(void *dmach,
+                          NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+                          int txmem, int rxmem)
+{
+    DeviceState *dev;
+    qemu_check_nic_model(nd, "xilinx-axienet");
+
+    dev = qdev_create(NULL, "xilinx,axienet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "c_rxmem", rxmem);
+    qdev_prop_set_uint32(dev, "c_txmem", txmem);
+    qdev_prop_set_ptr(dev, "dmach", dmach);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+static inline DeviceState *
+xilinx_axiethernetdma_create(void *dmach,
+                             target_phys_addr_t base, qemu_irq irq,
+                             qemu_irq irq2, int freqhz)
+{
+    DeviceState *dev = NULL;
+
+    dev = qdev_create(NULL, "xilinx,axidma");
+    qdev_prop_set_uint32(dev, "freqhz", freqhz);
+    qdev_prop_set_ptr(dev, "dmach", dmach);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq2);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq);
+
+    return dev;
+}
diff --git a/qemu-0.15.x/hw/xilinx_axidma.c b/qemu-0.15.x/hw/xilinx_axidma.c
new file mode 100644
index 0000000..571a5b0
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_axidma.c
@@ -0,0 +1,509 @@
+/*
+ * QEMU model of Xilinx AXI-DMA block.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+#include "qemu-log.h"
+#include "qdev-addr.h"
+
+#include "xilinx_axidma.h"
+
+#define D(x)
+
+#define R_DMACR             (0x00 / 4)
+#define R_DMASR             (0x04 / 4)
+#define R_CURDESC           (0x08 / 4)
+#define R_TAILDESC          (0x10 / 4)
+#define R_MAX               (0x30 / 4)
+
+enum {
+    DMACR_RUNSTOP = 1,
+    DMACR_TAILPTR_MODE = 2,
+    DMACR_RESET = 4
+};
+
+enum {
+    DMASR_HALTED = 1,
+    DMASR_IDLE  = 2,
+    DMASR_IOC_IRQ  = 1 << 12,
+    DMASR_DLY_IRQ  = 1 << 13,
+
+    DMASR_IRQ_MASK = 7 << 12
+};
+
+struct SDesc {
+    uint64_t nxtdesc;
+    uint64_t buffer_address;
+    uint64_t reserved;
+    uint32_t control;
+    uint32_t status;
+    uint32_t app[6];
+};
+
+enum {
+    SDESC_CTRL_EOF = (1 << 26),
+    SDESC_CTRL_SOF = (1 << 27),
+
+    SDESC_CTRL_LEN_MASK = (1 << 23) - 1
+};
+
+enum {
+    SDESC_STATUS_EOF = (1 << 26),
+    SDESC_STATUS_SOF_BIT = 27,
+    SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
+    SDESC_STATUS_COMPLETE = (1 << 31)
+};
+
+struct AXIStream {
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+    qemu_irq irq;
+
+    int nr;
+
+    struct SDesc desc;
+    int pos;
+    unsigned int complete_cnt;
+    uint32_t regs[R_MAX];
+};
+
+struct XilinxAXIDMA {
+    SysBusDevice busdev;
+    uint32_t freqhz;
+    void *dmach;
+
+    struct AXIStream streams[2];
+};
+
+/*
+ * Helper calls to extract info from desriptors and other trivial
+ * state from regs.
+ */
+static inline int stream_desc_sof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_SOF;
+}
+
+static inline int stream_desc_eof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_EOF;
+}
+
+static inline int stream_resetting(struct AXIStream *s)
+{
+    return !!(s->regs[R_DMACR] & DMACR_RESET);
+}
+
+static inline int stream_running(struct AXIStream *s)
+{
+    return s->regs[R_DMACR] & DMACR_RUNSTOP;
+}
+
+static inline int stream_halted(struct AXIStream *s)
+{
+    return s->regs[R_DMASR] & DMASR_HALTED;
+}
+
+static inline int stream_idle(struct AXIStream *s)
+{
+    return !!(s->regs[R_DMASR] & DMASR_IDLE);
+}
+
+static void stream_reset(struct AXIStream *s)
+{
+    s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
+    s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
+}
+
+/* Map an offset addr into a channel index.  */
+static inline int streamid_from_addr(target_phys_addr_t addr)
+{
+    int sid;
+
+    sid = addr / (0x30);
+    sid &= 1;
+    return sid;
+}
+
+#ifdef DEBUG_ENET
+static void stream_desc_show(struct SDesc *d)
+{
+    qemu_log("buffer_addr  = " PRIx64 "\n", d->buffer_address);
+    qemu_log("nxtdesc      = " PRIx64 "\n", d->nxtdesc);
+    qemu_log("control      = %x\n", d->control);
+    qemu_log("status       = %x\n", d->status);
+}
+#endif
+
+static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    cpu_physical_memory_read(addr, (void *) d, sizeof *d);
+
+    /* Convert from LE into host endianness.  */
+    d->buffer_address = le64_to_cpu(d->buffer_address);
+    d->nxtdesc = le64_to_cpu(d->nxtdesc);
+    d->control = le32_to_cpu(d->control);
+    d->status = le32_to_cpu(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = le32_to_cpu(d->app[i]);
+    }
+}
+
+static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    /* Convert from host endianness into LE.  */
+    d->buffer_address = cpu_to_le64(d->buffer_address);
+    d->nxtdesc = cpu_to_le64(d->nxtdesc);
+    d->control = cpu_to_le32(d->control);
+    d->status = cpu_to_le32(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = cpu_to_le32(d->app[i]);
+    }
+    cpu_physical_memory_write(addr, (void *) d, sizeof *d);
+}
+
+static void stream_update_irq(struct AXIStream *s)
+{
+    unsigned int pending, mask, irq;
+
+    pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
+    mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
+
+    irq = pending & mask;
+
+    qemu_set_irq(s->irq, !!irq);
+}
+
+static void stream_reload_complete_cnt(struct AXIStream *s)
+{
+    unsigned int comp_th;
+    comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
+    s->complete_cnt = comp_th;
+}
+
+static void timer_hit(void *opaque)
+{
+    struct AXIStream *s = opaque;
+
+    stream_reload_complete_cnt(s);
+    s->regs[R_DMASR] |= DMASR_DLY_IRQ;
+    stream_update_irq(s);
+}
+
+static void stream_complete(struct AXIStream *s)
+{
+    unsigned int comp_delay;
+
+    /* Start the delayed timer.  */
+    comp_delay = s->regs[R_DMACR] >> 24;
+    if (comp_delay) {
+        ptimer_stop(s->ptimer);
+        ptimer_set_count(s->ptimer, comp_delay);
+        ptimer_run(s->ptimer, 1);
+    }
+
+    s->complete_cnt--;
+    if (s->complete_cnt == 0) {
+        /* Raise the IOC irq.  */
+        s->regs[R_DMASR] |= DMASR_IOC_IRQ;
+        stream_reload_complete_cnt(s);
+    }
+}
+
+static void stream_process_mem2s(struct AXIStream *s,
+                                 struct XilinxDMAConnection *dmach)
+{
+    uint32_t prev_d;
+    unsigned char txbuf[16 * 1024];
+    unsigned int txlen;
+    uint32_t app[6];
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (1) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        if (stream_desc_sof(&s->desc)) {
+            s->pos = 0;
+            memcpy(app, s->desc.app, sizeof app);
+        }
+
+        txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if ((txlen + s->pos) > sizeof txbuf) {
+            hw_error("%s: too small internal txbuf! %d\n", __func__,
+                     txlen + s->pos);
+        }
+
+        cpu_physical_memory_read(s->desc.buffer_address,
+                                 txbuf + s->pos, txlen);
+        s->pos += txlen;
+
+        if (stream_desc_eof(&s->desc)) {
+            xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+            s->pos = 0;
+            stream_complete(s);
+        }
+
+        /* Update the descriptor.  */
+        s->desc.status = txlen | SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static void stream_process_s2mem(struct AXIStream *s,
+                                 unsigned char *buf, size_t len, uint32_t *app)
+{
+    uint32_t prev_d;
+    unsigned int rxlen;
+    int pos = 0;
+    int sof = 1;
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (len) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if (rxlen > len) {
+            /* It fits.  */
+            rxlen = len;
+        }
+
+        cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
+        len -= rxlen;
+        pos += rxlen;
+
+        /* Update the descriptor.  */
+        if (!len) {
+            int i;
+
+            stream_complete(s);
+            for (i = 0; i < 5; i++) {
+                s->desc.app[i] = app[i];
+            }
+            s->desc.status |= SDESC_STATUS_EOF;
+        }
+
+        s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
+        s->desc.status |= SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+        sof = 0;
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static
+void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s = &d->streams[1];
+
+    if (!app) {
+        hw_error("No stream app data!\n");
+    }
+    stream_process_s2mem(s, buf, len, app);
+    stream_update_irq(s);
+}
+
+static uint32_t axidma_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s;
+    uint32_t r = 0;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Simulate one cycles reset delay.  */
+            s->regs[addr] &= ~DMACR_RESET;
+            r = s->regs[addr];
+            break;
+        case R_DMASR:
+            s->regs[addr] &= 0xffff;
+            s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
+            s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
+            r = s->regs[addr];
+            break;
+        default:
+            r = s->regs[addr];
+            D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, sid, addr * 4, r));
+            break;
+    }
+    return r;
+
+}
+
+static void
+axidma_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct AXIStream *s;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Tailptr mode is always on.  */
+            value |= DMACR_TAILPTR_MODE;
+            /* Remember our previous reset state.  */
+            value |= (s->regs[addr] & DMACR_RESET);
+            s->regs[addr] = value;
+
+            if (value & DMACR_RESET) {
+                stream_reset(s);
+            }
+
+            if ((value & 1) && !stream_resetting(s)) {
+                /* Start processing.  */
+                s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
+            }
+            stream_reload_complete_cnt(s);
+            break;
+
+        case R_DMASR:
+            /* Mask away write to clear irq lines.  */
+            value &= ~(value & DMASR_IRQ_MASK);
+            s->regs[addr] = value;
+            break;
+
+        case R_TAILDESC:
+            s->regs[addr] = value;
+            s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
+            if (!sid) {
+                stream_process_mem2s(s, d->dmach);
+            }
+            break;
+        default:
+            D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                  __func__, sid, addr * 4, value));
+            s->regs[addr] = value;
+            break;
+    }
+    stream_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const axidma_read[] = {
+    &axidma_readl,
+    &axidma_readl,
+    &axidma_readl,
+};
+
+static CPUWriteMemoryFunc * const axidma_write[] = {
+    &axidma_writel,
+    &axidma_writel,
+    &axidma_writel,
+};
+
+static int xilinx_axidma_init(SysBusDevice *dev)
+{
+    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev);
+    int axidma_regs;
+    int i;
+
+    sysbus_init_irq(dev, &s->streams[1].irq);
+    sysbus_init_irq(dev, &s->streams[0].irq);
+
+    if (!s->dmach) {
+        hw_error("Unconnected DMA channel.\n");
+    }
+
+    xlx_dma_connect_dma(s->dmach, s, axidma_push);
+
+    axidma_regs = cpu_register_io_memory(axidma_read, axidma_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4 * 2, axidma_regs);
+
+    for (i = 0; i < 2; i++) {
+        stream_reset(&s->streams[i]);
+        s->streams[i].nr = i;
+        s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
+        s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
+        ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
+    }
+    return 0;
+}
+
+static SysBusDeviceInfo axidma_info = {
+    .init = xilinx_axidma_init,
+    .qdev.name  = "xilinx,axidma",
+    .qdev.size  = sizeof(struct XilinxAXIDMA),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+        DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xilinx_axidma_register(void)
+{
+    sysbus_register_withprop(&axidma_info);
+}
+
+device_init(xilinx_axidma_register)
diff --git a/qemu-0.15.x/hw/xilinx_axidma.h b/qemu-0.15.x/hw/xilinx_axidma.h
new file mode 100644
index 0000000..37cb6f0
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_axidma.h
@@ -0,0 +1,39 @@
+/* AXI DMA connection. Used until qdev provides a generic way.  */
+typedef void (*DMAPushFn)(void *opaque,
+                            unsigned char *buf, size_t len, uint32_t *app);
+
+struct XilinxDMAConnection {
+    void *dma;
+    void *client;
+
+    DMAPushFn to_dma;
+    DMAPushFn to_client;
+};
+
+static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
+                                          void *c, DMAPushFn f)
+{
+    dmach->client = c;
+    dmach->to_client = f;
+}
+
+static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
+                                       void *d, DMAPushFn f)
+{
+    dmach->dma = d;
+    dmach->to_dma = f;
+}
+
+static inline
+void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
+                         uint8_t *buf, size_t len, uint32_t *app)
+{
+    dmach->to_dma(dmach->dma, buf, len, app);
+}
+static inline
+void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
+                            uint8_t *buf, size_t len, uint32_t *app)
+{
+    dmach->to_client(dmach->client, buf, len, app);
+}
+
diff --git a/qemu-0.15.x/hw/xilinx_axienet.c b/qemu-0.15.x/hw/xilinx_axienet.c
new file mode 100644
index 0000000..464d275
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_axienet.c
@@ -0,0 +1,898 @@
+/*
+ * QEMU model of Xilinx AXI-Ethernet.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#include "xilinx_axidma.h"
+
+#define DPHY(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+struct PHY {
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct PHY *phy, unsigned int req);
+    void (*write)(struct PHY *phy, unsigned int req,
+                  unsigned int data);
+};
+
+static unsigned int tdk_read(struct PHY *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+        case 1:
+            if (!phy->link) {
+                break;
+            }
+            /* MR1.  */
+            /* Speeds and modes.  */
+            r |= (1 << 13) | (1 << 14);
+            r |= (1 << 11) | (1 << 12);
+            r |= (1 << 5); /* Autoneg complete.  */
+            r |= (1 << 3); /* Autoneg able.  */
+            r |= (1 << 2); /* link.  */
+            r |= (1 << 1); /* link.  */
+            break;
+        case 5:
+            /* Link partner ability.
+               We are kind; always agree with whatever best mode
+               the guest advertises.  */
+            r = 1 << 14; /* Success.  */
+            /* Copy advertised modes.  */
+            r |= phy->regs[4] & (15 << 5);
+            /* Autoneg support.  */
+            r |= 1;
+            break;
+        case 17:
+            /* Marvel PHY on many xilinx boards.  */
+            r = 0x8000; /* 1000Mb  */
+            break;
+        case 18:
+            {
+                /* Diagnostics reg.  */
+                int duplex = 0;
+                int speed_100 = 0;
+
+                if (!phy->link) {
+                    break;
+                }
+
+                /* Are we advertising 100 half or 100 duplex ? */
+                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+                /* Are we advertising 10 duplex or 100 duplex ? */
+                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+                r = (speed_100 << 10) | (duplex << 11);
+            }
+            break;
+
+        default:
+            r = phy->regs[regnum];
+            break;
+    }
+    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void
+tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+        default:
+            phy->regs[regnum] = data;
+            break;
+    }
+}
+
+static void
+tdk_init(struct PHY *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id.  */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg.  */
+    phy->regs[4] = 0x01E1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+struct MDIOBus {
+    /* bus.  */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct PHY *devs[32];
+};
+
+static void
+mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void
+mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
+                  unsigned int reg)
+{
+    struct PHY *phy;
+    uint16_t data;
+
+    phy = bus->devs[addr];
+    if (phy && phy->read) {
+        data = phy->read(phy, reg);
+    } else {
+        data = 0xffff;
+    }
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    return data;
+}
+
+static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
+               unsigned int reg, uint16_t data)
+{
+    struct PHY *phy;
+
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    phy = bus->devs[addr];
+    if (phy && phy->write) {
+        phy->write(phy, reg, data);
+    }
+}
+
+#define DENET(x)
+
+#define R_RAF      (0x000 / 4)
+enum {
+    RAF_MCAST_REJ = (1 << 1),
+    RAF_BCAST_REJ = (1 << 2),
+    RAF_EMCF_EN = (1 << 12),
+    RAF_NEWFUNC_EN = (1 << 11)
+};
+
+#define R_IS       (0x00C / 4)
+enum {
+    IS_HARD_ACCESS_COMPLETE = 1,
+    IS_AUTONEG = (1 << 1),
+    IS_RX_COMPLETE = (1 << 2),
+    IS_RX_REJECT = (1 << 3),
+    IS_TX_COMPLETE = (1 << 5),
+    IS_RX_DCM_LOCK = (1 << 6),
+    IS_MGM_RDY = (1 << 7),
+    IS_PHY_RST_DONE = (1 << 8),
+};
+
+#define R_IP       (0x010 / 4)
+#define R_IE       (0x014 / 4)
+#define R_UAWL     (0x020 / 4)
+#define R_UAWU     (0x024 / 4)
+#define R_PPST     (0x030 / 4)
+enum {
+    PPST_LINKSTATUS = (1 << 0),
+    PPST_PHY_LINKSTATUS = (1 << 7),
+};
+
+#define R_STATS_RX_BYTESL (0x200 / 4)
+#define R_STATS_RX_BYTESH (0x204 / 4)
+#define R_STATS_TX_BYTESL (0x208 / 4)
+#define R_STATS_TX_BYTESH (0x20C / 4)
+#define R_STATS_RXL       (0x290 / 4)
+#define R_STATS_RXH       (0x294 / 4)
+#define R_STATS_RX_BCASTL (0x2a0 / 4)
+#define R_STATS_RX_BCASTH (0x2a4 / 4)
+#define R_STATS_RX_MCASTL (0x2a8 / 4)
+#define R_STATS_RX_MCASTH (0x2ac / 4)
+
+#define R_RCW0     (0x400 / 4)
+#define R_RCW1     (0x404 / 4)
+enum {
+    RCW1_VLAN = (1 << 27),
+    RCW1_RX   = (1 << 28),
+    RCW1_FCS  = (1 << 29),
+    RCW1_JUM  = (1 << 30),
+    RCW1_RST  = (1 << 31),
+};
+
+#define R_TC       (0x408 / 4)
+enum {
+    TC_VLAN = (1 << 27),
+    TC_TX   = (1 << 28),
+    TC_FCS  = (1 << 29),
+    TC_JUM  = (1 << 30),
+    TC_RST  = (1 << 31),
+};
+
+#define R_EMMC     (0x410 / 4)
+enum {
+    EMMC_LINKSPEED_10MB = (0 << 30),
+    EMMC_LINKSPEED_100MB = (1 << 30),
+    EMMC_LINKSPEED_1000MB = (2 << 30),
+};
+
+#define R_PHYC     (0x414 / 4)
+
+#define R_MC       (0x500 / 4)
+#define MC_EN      (1 << 6)
+
+#define R_MCR      (0x504 / 4)
+#define R_MWD      (0x508 / 4)
+#define R_MRD      (0x50c / 4)
+#define R_MIS      (0x600 / 4)
+#define R_MIP      (0x620 / 4)
+#define R_MIE      (0x640 / 4)
+#define R_MIC      (0x640 / 4)
+
+#define R_UAW0     (0x700 / 4)
+#define R_UAW1     (0x704 / 4)
+#define R_FMI      (0x708 / 4)
+#define R_AF0      (0x710 / 4)
+#define R_AF1      (0x714 / 4)
+#define R_MAX      (0x34 / 4)
+
+/* Indirect registers.  */
+struct TEMAC  {
+    struct MDIOBus mdio_bus;
+    struct PHY phy;
+
+    void *parent;
+};
+
+struct XilinxAXIEnet {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    void *dmach;
+    NICState *nic;
+    NICConf conf;
+
+
+    uint32_t c_rxmem;
+    uint32_t c_txmem;
+    uint32_t c_phyaddr;
+
+    struct TEMAC TEMAC;
+
+    /* MII regs.  */
+    union {
+        uint32_t regs[4];
+        struct {
+            uint32_t mc;
+            uint32_t mcr;
+            uint32_t mwd;
+            uint32_t mrd;
+        };
+    } mii;
+
+    struct {
+        uint64_t rx_bytes;
+        uint64_t tx_bytes;
+
+        uint64_t rx;
+        uint64_t rx_bcast;
+        uint64_t rx_mcast;
+    } stats;
+
+    /* Receive configuration words.  */
+    uint32_t rcw[2];
+    /* Transmit config.  */
+    uint32_t tc;
+    uint32_t emmc;
+    uint32_t phyc;
+
+    /* Unicast Address Word.  */
+    uint32_t uaw[2];
+    /* Unicast address filter used with extended mcast.  */
+    uint32_t ext_uaw[2];
+    uint32_t fmi;
+
+    uint32_t regs[R_MAX];
+
+    /* Multicast filter addrs.  */
+    uint32_t maddr[4][2];
+    /* 32K x 1 lookup filter.  */
+    uint32_t ext_mtable[1024];
+
+
+    uint8_t *rxmem;
+};
+
+static void axienet_rx_reset(struct XilinxAXIEnet *s)
+{
+    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
+}
+
+static void axienet_tx_reset(struct XilinxAXIEnet *s)
+{
+    s->tc = TC_JUM | TC_TX | TC_VLAN;
+}
+
+static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RST;
+}
+
+static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RX;
+}
+
+static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
+}
+
+static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
+}
+
+static void axienet_reset(struct XilinxAXIEnet *s)
+{
+    axienet_rx_reset(s);
+    axienet_tx_reset(s);
+
+    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
+    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
+
+    s->emmc = EMMC_LINKSPEED_100MB;
+}
+
+static void enet_update_irq(struct XilinxAXIEnet *s)
+{
+    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
+    qemu_set_irq(s->irq, !!s->regs[R_IP]);
+}
+
+static uint32_t enet_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct XilinxAXIEnet *s = opaque;
+    uint32_t r = 0;
+    addr >>= 2;
+
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            r = s->rcw[addr & 1];
+            break;
+
+        case R_TC:
+            r = s->tc;
+            break;
+
+        case R_EMMC:
+            r = s->emmc;
+            break;
+
+        case R_PHYC:
+            r = s->phyc;
+            break;
+
+        case R_MCR:
+            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
+            break;
+
+        case R_STATS_RX_BYTESL:
+        case R_STATS_RX_BYTESH:
+            r = s->stats.rx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_TX_BYTESL:
+        case R_STATS_TX_BYTESH:
+            r = s->stats.tx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_RXL:
+        case R_STATS_RXH:
+            r = s->stats.rx >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_BCASTL:
+        case R_STATS_RX_BCASTH:
+            r = s->stats.rx_bcast >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_MCASTL:
+        case R_STATS_RX_MCASTH:
+            r = s->stats.rx_mcast >> (32 * (addr & 1));
+            break;
+
+        case R_MC:
+        case R_MWD:
+        case R_MRD:
+            r = s->mii.regs[addr & 3];
+            break;
+
+        case R_UAW0:
+        case R_UAW1:
+            r = s->uaw[addr & 1];
+            break;
+
+        case R_UAWU:
+        case R_UAWL:
+            r = s->ext_uaw[addr & 1];
+            break;
+
+        case R_FMI:
+            r = s->fmi;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            r = s->maddr[s->fmi & 3][addr & 1];
+            break;
+
+        case 0x8000 ... 0x83ff:
+            r = s->ext_mtable[addr - 0x8000];
+            break;
+
+        default:
+            if (addr < ARRAY_SIZE(s->regs)) {
+                r = s->regs[addr];
+            }
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                            __func__, addr * 4, r));
+            break;
+    }
+    return r;
+}
+
+static void
+enet_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct XilinxAXIEnet *s = opaque;
+    struct TEMAC *t = &s->TEMAC;
+
+    addr >>= 2;
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            s->rcw[addr & 1] = value;
+            if ((addr & 1) && value & RCW1_RST) {
+                axienet_rx_reset(s);
+            }
+            break;
+
+        case R_TC:
+            s->tc = value;
+            if (value & TC_RST) {
+                axienet_tx_reset(s);
+            }
+            break;
+
+        case R_EMMC:
+            s->emmc = value;
+            break;
+
+        case R_PHYC:
+            s->phyc = value;
+            break;
+
+        case R_MC:
+             value &= ((1 < 7) - 1);
+
+             /* Enable the MII.  */
+             if (value & MC_EN) {
+                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
+                 if (!miiclkdiv) {
+                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
+                 }
+             }
+             s->mii.mc = value;
+             break;
+
+        case R_MCR: {
+             unsigned int phyaddr = (value >> 24) & 0x1f;
+             unsigned int regaddr = (value >> 16) & 0x1f;
+             unsigned int op = (value >> 14) & 3;
+             unsigned int initiate = (value >> 11) & 1;
+
+             if (initiate) {
+                 if (op == 1) {
+                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
+                 } else if (op == 2) {
+                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
+                 } else {
+                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
+                 }
+             }
+             s->mii.mcr = value;
+             break;
+        }
+
+        case R_MWD:
+        case R_MRD:
+             s->mii.regs[addr & 3] = value;
+             break;
+
+
+        case R_UAW0:
+        case R_UAW1:
+            s->uaw[addr & 1] = value;
+            break;
+
+        case R_UAWL:
+        case R_UAWU:
+            s->ext_uaw[addr & 1] = value;
+            break;
+
+        case R_FMI:
+            s->fmi = value;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            s->maddr[s->fmi & 3][addr & 1] = value;
+            break;
+
+        case 0x8000 ... 0x83ff:
+            s->ext_mtable[addr - 0x8000] = value;
+            break;
+
+        default:
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, addr * 4, value));
+            if (addr < ARRAY_SIZE(s->regs)) {
+                s->regs[addr] = value;
+            }
+            break;
+    }
+    enet_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const enet_read[] = {
+    &enet_readl,
+    &enet_readl,
+    &enet_readl,
+};
+
+static CPUWriteMemoryFunc * const enet_write[] = {
+    &enet_writel,
+    &enet_writel,
+    &enet_writel,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    /* RX enabled?  */
+    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
+}
+
+static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
+{
+    int match = 1;
+
+    if (memcmp(buf, &f0, 4)) {
+        match = 0;
+    }
+
+    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
+        match = 0;
+    }
+
+    return match;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+                                              0xff, 0xff, 0xff};
+    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
+    uint32_t app[6] = {0};
+    int promisc = s->fmi & (1 << 31);
+    int unicast, broadcast, multicast, ip_multicast = 0;
+    uint32_t csum32;
+    uint16_t csum16;
+    int i;
+
+    s = s;
+    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
+
+    unicast = ~buf[0] & 0x1;
+    broadcast = memcmp(buf, sa_bcast, 6) == 0;
+    multicast = !unicast && !broadcast;
+    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
+        ip_multicast = 1;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->rcw[1] & RCW1_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
+            return size;
+        }
+    }
+
+    /* Basic Address filters.  If you want to use the extended filters
+       you'll generally have to place the ethernet mac into promiscuous mode
+       to avoid the basic filtering from dropping most frames.  */
+    if (!promisc) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast.  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int drop = 1;
+
+                /* Multicast.  */
+                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
+                    return size;
+                }
+
+                for (i = 0; i < 4; i++) {
+                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
+                        drop = 0;
+                        break;
+                    }
+                }
+
+                if (drop) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    /* Extended mcast filtering enabled?  */
+    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast. ???  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int idx, bit;
+
+                /* Multicast.  */
+                if (!memcmp(buf, sa_ipmcast, 3)) {
+                    return size;
+                }
+
+                idx  = (buf[4] & 0x7f) << 8;
+                idx |= buf[5];
+
+                bit = 1 << (idx & 0x1f);
+                idx >>= 5;
+
+                if (!(s->ext_mtable[idx] & bit)) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    if (size < 12) {
+        s->regs[R_IS] |= IS_RX_REJECT;
+        enet_update_irq(s);
+        return -1;
+    }
+
+    if (size > (s->c_rxmem - 4)) {
+        size = s->c_rxmem - 4;
+    }
+
+    memcpy(s->rxmem, buf, size);
+    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
+
+    if (s->rcw[1] & RCW1_FCS) {
+        size += 4; /* fcs is inband.  */
+    }
+
+    app[0] = 5 << 28;
+    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
+    /* Fold it once.  */
+    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
+    /* And twice to get rid of possible carries.  */
+    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
+    app[3] = csum16;
+    app[4] = size & 0xffff;
+
+    s->stats.rx_bytes += size;
+    s->stats.rx++;
+    if (multicast) {
+        s->stats.rx_mcast++;
+        app[2] |= 1 | (ip_multicast << 1);
+    } else if (broadcast) {
+        s->stats.rx_bcast++;
+        app[2] |= 1 << 3;
+    }
+
+    /* Good frame.  */
+    app[2] |= 1 << 6;
+
+    xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+
+    s->regs[R_IS] |= IS_RX_COMPLETE;
+    enet_update_irq(s);
+    return size;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+    /* FIXME.  */
+    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    qemu_free(s->rxmem);
+    qemu_free(s);
+}
+
+static void
+axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+{
+    struct XilinxAXIEnet *s = opaque;
+
+    /* TX enable ?  */
+    if (!(s->tc & TC_TX)) {
+        return;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->tc & TC_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
+            return;
+        }
+    }
+
+    if (hdr[0] & 1) {
+        unsigned int start_off = hdr[1] >> 16;
+        unsigned int write_off = hdr[1] & 0xffff;
+        uint32_t tmp_csum;
+        uint16_t csum;
+
+        tmp_csum = net_checksum_add(size - start_off,
+                                    (uint8_t *)buf + start_off);
+        /* Accumulate the seed.  */
+        tmp_csum += hdr[2] & 0xffff;
+
+        /* Fold the 32bit partial checksum.  */
+        csum = net_checksum_finish(tmp_csum);
+
+        /* Writeback.  */
+        buf[write_off] = csum >> 8;
+        buf[write_off + 1] = csum & 0xff;
+    }
+
+    qemu_send_packet(&s->nic->nc, buf, size);
+
+    s->stats.tx_bytes += size;
+    s->regs[R_IS] |= IS_TX_COMPLETE;
+    enet_update_irq(s);
+}
+
+static NetClientInfo net_xilinx_enet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_enet_init(SysBusDevice *dev)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
+    int enet_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    if (!s->dmach) {
+        hw_error("Unconnected Xilinx Ethernet MAC.\n");
+    }
+
+    xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
+
+    enet_regs = cpu_register_io_memory(enet_read, enet_write, s,
+                                       DEVICE_LITTLE_ENDIAN);
+    sysbus_init_mmio(dev, 0x40000, enet_regs);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    tdk_init(&s->TEMAC.phy);
+    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
+
+    s->TEMAC.parent = s;
+
+    s->rxmem = qemu_malloc(s->c_rxmem);
+    axienet_reset(s);
+
+    return 0;
+}
+
+static SysBusDeviceInfo xilinx_enet_info = {
+    .init = xilinx_enet_init,
+    .qdev.name  = "xilinx,axienet",
+    .qdev.size  = sizeof(struct XilinxAXIEnet),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+        DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+        DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+        DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
+        DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+static void xilinx_enet_register(void)
+{
+    sysbus_register_withprop(&xilinx_enet_info);
+}
+
+device_init(xilinx_enet_register)
diff --git a/qemu-0.15.x/hw/xilinx_ethlite.c b/qemu-0.15.x/hw/xilinx_ethlite.c
new file mode 100644
index 0000000..f35ba84
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_ethlite.c
@@ -0,0 +1,241 @@
+/*
+ * QEMU model of the Xilinx Ethernet Lite MAC.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+
+#define D(x)
+#define R_TX_BUF0     0
+#define R_TX_LEN0     (0x07f4 / 4)
+#define R_TX_GIE0     (0x07f8 / 4)
+#define R_TX_CTRL0    (0x07fc / 4)
+#define R_TX_BUF1     (0x0800 / 4)
+#define R_TX_LEN1     (0x0ff4 / 4)
+#define R_TX_CTRL1    (0x0ffc / 4)
+
+#define R_RX_BUF0     (0x1000 / 4)
+#define R_RX_CTRL0    (0x17fc / 4)
+#define R_RX_BUF1     (0x1800 / 4)
+#define R_RX_CTRL1    (0x1ffc / 4)
+#define R_MAX         (0x2000 / 4)
+
+#define GIE_GIE    0x80000000
+
+#define CTRL_I     0x8
+#define CTRL_P     0x2
+#define CTRL_S     0x1
+
+struct xlx_ethlite
+{
+    SysBusDevice busdev;
+    qemu_irq irq;
+    NICState *nic;
+    NICConf conf;
+
+    uint32_t c_tx_pingpong;
+    uint32_t c_rx_pingpong;
+    unsigned int txbuf;
+    unsigned int rxbuf;
+
+    uint32_t regs[R_MAX];
+};
+
+static inline void eth_pulse_irq(struct xlx_ethlite *s)
+{
+    /* Only the first gie reg is active.  */
+    if (s->regs[R_TX_GIE0] & GIE_GIE) {
+        qemu_irq_pulse(s->irq);
+    }
+}
+
+static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct xlx_ethlite *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+
+    switch (addr)
+    {
+        case R_TX_GIE0:
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_CTRL1:
+        case R_TX_CTRL0:
+        case R_RX_CTRL1:
+        case R_RX_CTRL0:
+            r = s->regs[addr];
+            D(qemu_log("%s %x=%x\n", __func__, addr * 4, r));
+            break;
+
+        default:
+            r = tswap32(s->regs[addr]);
+            break;
+    }
+    return r;
+}
+
+static void
+eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct xlx_ethlite *s = opaque;
+    unsigned int base = 0;
+
+    addr >>= 2;
+    switch (addr) 
+    {
+        case R_TX_CTRL0:
+        case R_TX_CTRL1:
+            if (addr == R_TX_CTRL1)
+                base = 0x800 / 4;
+
+            D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
+                qemu_send_packet(&s->nic->nc,
+                                 (void *) &s->regs[base],
+                                 s->regs[base + R_TX_LEN0]);
+                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
+                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            }
+
+            /* We are fast and get ready pretty much immediately so
+               we actually never flip the S nor P bits to one.  */
+            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
+            break;
+
+        /* Keep these native.  */
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_GIE0:
+        case R_RX_CTRL0:
+        case R_RX_CTRL1:
+            D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+            s->regs[addr] = value;
+            break;
+
+        default:
+            s->regs[addr] = tswap32(value);
+            break;
+    }
+}
+
+static CPUReadMemoryFunc * const eth_read[] = {
+    NULL, NULL, &eth_readl,
+};
+
+static CPUWriteMemoryFunc * const eth_write[] = {
+    NULL, NULL, &eth_writel,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+    struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    int r;
+    r = !(s->regs[R_RX_CTRL0] & CTRL_S);
+    return r;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    unsigned int rxbase = s->rxbuf * (0x800 / 4);
+
+    /* DA filter.  */
+    if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
+        return size;
+
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
+        D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
+        return -1;
+    }
+
+    D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase));
+    memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
+
+    s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
+        eth_pulse_irq(s);
+
+    /* If c_rx_pingpong was set flip buffers.  */
+    s->rxbuf ^= s->c_rx_pingpong;
+    return size;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+    struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_xilinx_ethlite_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_ethlite_init(SysBusDevice *dev)
+{
+    struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
+    int regs;
+
+    sysbus_init_irq(dev, &s->irq);
+    s->rxbuf = 0;
+
+    regs = cpu_register_io_memory(eth_read, eth_write, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, regs);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+    return 0;
+}
+
+static SysBusDeviceInfo xilinx_ethlite_info = {
+    .init = xilinx_ethlite_init,
+    .qdev.name  = "xilinx,ethlite",
+    .qdev.size  = sizeof(struct xlx_ethlite),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
+        DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
+        DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xilinx_ethlite_register(void)
+{
+    sysbus_register_withprop(&xilinx_ethlite_info);
+}
+
+device_init(xilinx_ethlite_register)
diff --git a/qemu-0.15.x/hw/xilinx_intc.c b/qemu-0.15.x/hw/xilinx_intc.c
new file mode 100644
index 0000000..cb72d5a
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_intc.c
@@ -0,0 +1,176 @@
+/*
+ * QEMU Xilinx OPB Interrupt Controller.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "hw.h"
+
+#define D(x)
+
+#define R_ISR       0
+#define R_IPR       1
+#define R_IER       2
+#define R_IAR       3
+#define R_SIE       4
+#define R_CIE       5
+#define R_IVR       6
+#define R_MER       7
+#define R_MAX       8
+
+struct xlx_pic
+{
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+
+    /* Configuration reg chosen at synthesis-time. QEMU populates
+       the bits at board-setup.  */
+    uint32_t c_kind_of_intr;
+
+    /* Runtime control registers.  */
+    uint32_t regs[R_MAX];
+};
+
+static void update_irq(struct xlx_pic *p)
+{
+    uint32_t i;
+    /* Update the pending register.  */
+    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
+
+    /* Update the vector register.  */
+    for (i = 0; i < 32; i++) {
+        if (p->regs[R_IPR] & (1 << i))
+            break;
+    }
+    if (i == 32)
+        i = ~0;
+
+    p->regs[R_IVR] = i;
+    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
+        qemu_irq_raise(p->parent_irq);
+    } else {
+        qemu_irq_lower(p->parent_irq);
+    }
+}
+
+static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct xlx_pic *p = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        default:
+            if (addr < ARRAY_SIZE(p->regs))
+                r = p->regs[addr];
+            break;
+
+    }
+    D(printf("%s %x=%x\n", __func__, addr * 4, r));
+    return r;
+}
+
+static void
+pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct xlx_pic *p = opaque;
+
+    addr >>= 2;
+    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+    switch (addr) 
+    {
+        case R_IAR:
+            p->regs[R_ISR] &= ~value; /* ACK.  */
+            break;
+        case R_SIE:
+            p->regs[R_IER] |= value;  /* Atomic set ie.  */
+            break;
+        case R_CIE:
+            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
+            break;
+        default:
+            if (addr < ARRAY_SIZE(p->regs))
+                p->regs[addr] = value;
+            break;
+    }
+    update_irq(p);
+}
+
+static CPUReadMemoryFunc * const pic_read[] = {
+    NULL, NULL,
+    &pic_readl,
+};
+
+static CPUWriteMemoryFunc * const pic_write[] = {
+    NULL, NULL,
+    &pic_writel,
+};
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    struct xlx_pic *p = opaque;
+
+    if (!(p->regs[R_MER] & 2)) {
+        qemu_irq_lower(p->parent_irq);
+        return;
+    }
+
+    /* Update source flops. Don't clear unless level triggered.
+       Edge triggered interrupts only go away when explicitely acked to
+       the interrupt controller.  */
+    if (!(p->c_kind_of_intr & (1 << irq)) || level) {
+        p->regs[R_ISR] &= ~(1 << irq);
+        p->regs[R_ISR] |= (level << irq);
+    }
+    update_irq(p);
+}
+
+static int xilinx_intc_init(SysBusDevice *dev)
+{
+    struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
+    int pic_regs;
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &p->parent_irq);
+
+    pic_regs = cpu_register_io_memory(pic_read, pic_write, p, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
+    return 0;
+}
+
+static SysBusDeviceInfo xilinx_intc_info = {
+    .init = xilinx_intc_init,
+    .qdev.name  = "xilinx,intc",
+    .qdev.size  = sizeof(struct xlx_pic),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xilinx_intc_register(void)
+{
+    sysbus_register_withprop(&xilinx_intc_info);
+}
+
+device_init(xilinx_intc_register)
diff --git a/qemu-0.15.x/hw/xilinx_timer.c b/qemu-0.15.x/hw/xilinx_timer.c
new file mode 100644
index 0000000..d398c18
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_timer.c
@@ -0,0 +1,234 @@
+/*
+ * QEMU model of the Xilinx timer block.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-timer.h"
+
+#define D(x)
+
+#define R_TCSR     0
+#define R_TLR      1
+#define R_TCR      2
+#define R_MAX      4
+
+#define TCSR_MDT        (1<<0)
+#define TCSR_UDT        (1<<1)
+#define TCSR_GENT       (1<<2)
+#define TCSR_CAPT       (1<<3)
+#define TCSR_ARHT       (1<<4)
+#define TCSR_LOAD       (1<<5)
+#define TCSR_ENIT       (1<<6)
+#define TCSR_ENT        (1<<7)
+#define TCSR_TINT       (1<<8)
+#define TCSR_PWMA       (1<<9)
+#define TCSR_ENALL      (1<<10)
+
+struct xlx_timer
+{
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+    void *parent;
+    int nr; /* for debug.  */
+
+    unsigned long timer_div;
+
+    uint32_t regs[R_MAX];
+};
+
+struct timerblock
+{
+    SysBusDevice busdev;
+    qemu_irq irq;
+    uint32_t nr_timers;
+    uint32_t freq_hz;
+    struct xlx_timer *timers;
+};
+
+static inline unsigned int timer_from_addr(target_phys_addr_t addr)
+{
+    /* Timers get a 4x32bit control reg area each.  */
+    return addr >> 2;
+}
+
+static void timer_update_irq(struct timerblock *t)
+{
+    unsigned int i, irq = 0;
+    uint32_t csr;
+
+    for (i = 0; i < t->nr_timers; i++) {
+        csr = t->timers[i].regs[R_TCSR];
+        irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
+    }
+
+    /* All timers within the same slave share a single IRQ line.  */
+    qemu_set_irq(t->irq, !!irq);
+}
+
+static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct timerblock *t = opaque;
+    struct xlx_timer *xt;
+    uint32_t r = 0;
+    unsigned int timer;
+
+    addr >>= 2;
+    timer = timer_from_addr(addr);
+    xt = &t->timers[timer];
+    /* Further decoding to address a specific timers reg.  */
+    addr &= 0x3;
+    switch (addr)
+    {
+        case R_TCR:
+                r = ptimer_get_count(xt->ptimer);
+                if (!(xt->regs[R_TCSR] & TCSR_UDT))
+                    r = ~r;
+                D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
+                         timer, r, xt->regs[R_TCSR] & TCSR_UDT));
+            break;
+        default:
+            if (addr < ARRAY_SIZE(xt->regs))
+                r = xt->regs[addr];
+            break;
+
+    }
+    D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
+    return r;
+}
+
+static void timer_enable(struct xlx_timer *xt)
+{
+    uint64_t count;
+
+    D(printf("%s timer=%d down=%d\n", __func__,
+              xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
+
+    ptimer_stop(xt->ptimer);
+
+    if (xt->regs[R_TCSR] & TCSR_UDT)
+        count = xt->regs[R_TLR];
+    else
+        count = ~0 - xt->regs[R_TLR];
+    ptimer_set_count(xt->ptimer, count);
+    ptimer_run(xt->ptimer, 1);
+}
+
+static void
+timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct timerblock *t = opaque;
+    struct xlx_timer *xt;
+    unsigned int timer;
+
+    addr >>= 2;
+    timer = timer_from_addr(addr);
+    xt = &t->timers[timer];
+    D(printf("%s addr=%x val=%x (timer=%d off=%d)\n",
+             __func__, addr * 4, value, timer, addr & 3));
+    /* Further decoding to address a specific timers reg.  */
+    addr &= 3;
+    switch (addr) 
+    {
+        case R_TCSR:
+            if (value & TCSR_TINT)
+                value &= ~TCSR_TINT;
+
+            xt->regs[addr] = value;
+            if (value & TCSR_ENT)
+                timer_enable(xt);
+            break;
+ 
+        default:
+            if (addr < ARRAY_SIZE(xt->regs))
+                xt->regs[addr] = value;
+            break;
+    }
+    timer_update_irq(t);
+}
+
+static CPUReadMemoryFunc * const timer_read[] = {
+    NULL, NULL,
+    &timer_readl,
+};
+
+static CPUWriteMemoryFunc * const timer_write[] = {
+    NULL, NULL,
+    &timer_writel,
+};
+
+static void timer_hit(void *opaque)
+{
+    struct xlx_timer *xt = opaque;
+    struct timerblock *t = xt->parent;
+    D(printf("%s %d\n", __func__, timer));
+    xt->regs[R_TCSR] |= TCSR_TINT;
+
+    if (xt->regs[R_TCSR] & TCSR_ARHT)
+        timer_enable(xt);
+    timer_update_irq(t);
+}
+
+static int xilinx_timer_init(SysBusDevice *dev)
+{
+    struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
+    unsigned int i;
+    int timer_regs;
+
+    /* All timers share a single irq line.  */
+    sysbus_init_irq(dev, &t->irq);
+
+    /* Init all the ptimers.  */
+    t->timers = qemu_mallocz(sizeof t->timers[0] * t->nr_timers);
+    for (i = 0; i < t->nr_timers; i++) {
+        struct xlx_timer *xt = &t->timers[i];
+
+        xt->parent = t;
+        xt->nr = i;
+        xt->bh = qemu_bh_new(timer_hit, xt);
+        xt->ptimer = ptimer_init(xt->bh);
+        ptimer_set_freq(xt->ptimer, t->freq_hz);
+    }
+
+    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
+                                        DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
+    return 0;
+}
+
+static SysBusDeviceInfo xilinx_timer_info = {
+    .init = xilinx_timer_init,
+    .qdev.name  = "xilinx,timer",
+    .qdev.size  = sizeof(struct timerblock),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz,   0),
+        DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xilinx_timer_register(void)
+{
+    sysbus_register_withprop(&xilinx_timer_info);
+}
+
+device_init(xilinx_timer_register)
diff --git a/qemu-0.15.x/hw/xilinx_uartlite.c b/qemu-0.15.x/hw/xilinx_uartlite.c
new file mode 100644
index 0000000..9b94e98
--- /dev/null
+++ b/qemu-0.15.x/hw/xilinx_uartlite.c
@@ -0,0 +1,220 @@
+/*
+ * QEMU model of Xilinx uartlite.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+
+#define DUART(x)
+
+#define R_RX            0
+#define R_TX            1
+#define R_STATUS        2
+#define R_CTRL          3
+#define R_MAX           4
+
+#define STATUS_RXVALID    0x01
+#define STATUS_RXFULL     0x02
+#define STATUS_TXEMPTY    0x04
+#define STATUS_TXFULL     0x08
+#define STATUS_IE         0x10
+#define STATUS_OVERRUN    0x20
+#define STATUS_FRAME      0x40
+#define STATUS_PARITY     0x80
+
+#define CONTROL_RST_TX    0x01
+#define CONTROL_RST_RX    0x02
+#define CONTROL_IE        0x10
+
+struct xlx_uartlite
+{
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint8_t rx_fifo[8];
+    unsigned int rx_fifo_pos;
+    unsigned int rx_fifo_len;
+
+    uint32_t regs[R_MAX];
+};
+
+static void uart_update_irq(struct xlx_uartlite *s)
+{
+    unsigned int irq;
+
+    if (s->rx_fifo_len)
+        s->regs[R_STATUS] |= STATUS_IE;
+
+    irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
+    qemu_set_irq(s->irq, irq);
+}
+
+static void uart_update_status(struct xlx_uartlite *s)
+{
+    uint32_t r;
+
+    r = s->regs[R_STATUS];
+    r &= ~7;
+    r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
+    r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
+    r |= (!!s->rx_fifo_len);
+    s->regs[R_STATUS] = r;
+}
+
+static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
+{
+    struct xlx_uartlite *s = opaque;
+    uint32_t r = 0;
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_RX:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
+            if (s->rx_fifo_len)
+                s->rx_fifo_len--;
+            uart_update_status(s);
+            uart_update_irq(s);
+            break;
+
+        default:
+            if (addr < ARRAY_SIZE(s->regs))
+                r = s->regs[addr];
+            DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
+            break;
+    }
+    return r;
+}
+
+static void
+uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct xlx_uartlite *s = opaque;
+    unsigned char ch = value;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_STATUS:
+            hw_error("write to UART STATUS?\n");
+            break;
+
+        case R_CTRL:
+            if (value & CONTROL_RST_RX) {
+                s->rx_fifo_pos = 0;
+                s->rx_fifo_len = 0;
+            }
+            s->regs[addr] = value;
+            break;
+
+        case R_TX:
+            if (s->chr)
+                qemu_chr_write(s->chr, &ch, 1);
+
+            s->regs[addr] = value;
+
+            /* hax.  */
+            s->regs[R_STATUS] |= STATUS_IE;
+            break;
+
+        default:
+            DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
+            if (addr < ARRAY_SIZE(s->regs))
+                s->regs[addr] = value;
+            break;
+    }
+    uart_update_status(s);
+    uart_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const uart_read[] = {
+    &uart_readl,
+    &uart_readl,
+    &uart_readl,
+};
+
+static CPUWriteMemoryFunc * const uart_write[] = {
+    &uart_writel,
+    &uart_writel,
+    &uart_writel,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    struct xlx_uartlite *s = opaque;
+
+    /* Got a byte.  */
+    if (s->rx_fifo_len >= 8) {
+        printf("WARNING: UART dropped char.\n");
+        return;
+    }
+    s->rx_fifo[s->rx_fifo_pos] = *buf;
+    s->rx_fifo_pos++;
+    s->rx_fifo_pos &= 0x7;
+    s->rx_fifo_len++;
+
+    uart_update_status(s);
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    struct xlx_uartlite *s = opaque;
+    int r;
+
+    r = s->rx_fifo_len < sizeof(s->rx_fifo);
+    if (!r)
+        printf("cannot receive!\n");
+    return r;
+}
+
+static void uart_event(void *opaque, int event)
+{
+
+}
+
+static int xilinx_uartlite_init(SysBusDevice *dev)
+{
+    struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    uart_update_status(s);
+    uart_regs = cpu_register_io_memory(uart_read, uart_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr)
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    return 0;
+}
+
+static void xilinx_uart_register(void)
+{
+    sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
+                        xilinx_uartlite_init);
+}
+
+device_init(xilinx_uart_register)
diff --git a/qemu-0.15.x/hw/xio3130_downstream.c b/qemu-0.15.x/hw/xio3130_downstream.c
new file mode 100644
index 0000000..d3c387d
--- /dev/null
+++ b/qemu-0.15.x/hw/xio3130_downstream.c
@@ -0,0 +1,211 @@
+/*
+ * x3130_downstream.c
+ * TI X3130 pci express downstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_downstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130D       0x8233  /* downstream port */
+#define XIO3130_REVISION                0x1
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
+                                         uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    pcie_cap_slot_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+}
+
+static void xio3130_downstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pcie_cap_ari_reset(d);
+    pci_bridge_reset(qdev);
+}
+
+static int xio3130_downstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+    int tmp;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
+                       p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_flr_init(d);
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        goto err_pcie_cap;
+    }
+    pcie_cap_ari_init(d);
+    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    pcie_chassis_del_slot(s);
+err_pcie_cap:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    tmp = pci_bridge_exitfn(d);
+    assert(!tmp);
+    return rc;
+}
+
+static int xio3130_downstream_exitfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+
+    pcie_aer_exit(d);
+    pcie_chassis_del_slot(s);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction,
+                                 "xio3130-downstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_xio3130_downstream = {
+    .name = "xio3130-express-downstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
+                       vmstate_pcie_aer_log, PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo xio3130_downstream_info = {
+    .qdev.name = "xio3130-downstream",
+    .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch",
+    .qdev.size = sizeof(PCIESlot),
+    .qdev.reset = xio3130_downstream_reset,
+    .qdev.vmsd = &vmstate_xio3130_downstream,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = xio3130_downstream_write_config,
+    .init = xio3130_downstream_initfn,
+    .exit = xio3130_downstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130D,
+    .revision = XIO3130_REVISION,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+        DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+                           port.br.dev.exp.aer_log.log_max,
+                           PCIE_AER_LOG_MAX_DEFAULT),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xio3130_downstream_register(void)
+{
+    pci_qdev_register(&xio3130_downstream_info);
+}
+
+device_init(xio3130_downstream_register);
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/qemu-0.15.x/hw/xio3130_downstream.h b/qemu-0.15.x/hw/xio3130_downstream.h
new file mode 100644
index 0000000..010487f
--- /dev/null
+++ b/qemu-0.15.x/hw/xio3130_downstream.h
@@ -0,0 +1,11 @@
+#ifndef QEMU_XIO3130_DOWNSTREAM_H
+#define QEMU_XIO3130_DOWNSTREAM_H
+
+#include "pcie_port.h"
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot);
+
+#endif /* QEMU_XIO3130_DOWNSTREAM_H */
diff --git a/qemu-0.15.x/hw/xio3130_upstream.c b/qemu-0.15.x/hw/xio3130_upstream.c
new file mode 100644
index 0000000..8283695
--- /dev/null
+++ b/qemu-0.15.x/hw/xio3130_upstream.c
@@ -0,0 +1,186 @@
+/*
+ * xio3130_upstream.c
+ * TI X3130 pci express upstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_upstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130U       0x8232  /* upstream port */
+#define XIO3130_REVISION                0x2
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
+                                          uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+}
+
+static void xio3130_upstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    pci_bridge_reset(qdev);
+    pcie_cap_deverr_reset(d);
+}
+
+static int xio3130_upstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    int rc;
+    int tmp;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
+                       p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_flr_init(d);
+    pcie_cap_deverr_init(d);
+    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    tmp =  pci_bridge_exitfn(d);
+    assert(!tmp);
+    return rc;
+}
+
+static int xio3130_upstream_exitfn(PCIDevice *d)
+{
+    pcie_aer_exit(d);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                             const char *bus_name, pci_map_irq_fn map_irq,
+                             uint8_t port)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIEPort, br, br);
+}
+
+static const VMStateDescription vmstate_xio3130_upstream = {
+    .name = "xio3130-express-upstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(br.dev, PCIEPort),
+        VMSTATE_STRUCT(br.dev.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log,
+                       PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo xio3130_upstream_info = {
+    .qdev.name = "x3130-upstream",
+    .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch",
+    .qdev.size = sizeof(PCIEPort),
+    .qdev.reset = xio3130_upstream_reset,
+    .qdev.vmsd = &vmstate_xio3130_upstream,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = xio3130_upstream_write_config,
+    .init = xio3130_upstream_initfn,
+    .exit = xio3130_upstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130U,
+    .revision = XIO3130_REVISION,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+        DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
+                           PCIE_AER_LOG_MAX_DEFAULT),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xio3130_upstream_register(void)
+{
+    pci_qdev_register(&xio3130_upstream_info);
+}
+
+device_init(xio3130_upstream_register);
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/qemu-0.15.x/hw/xio3130_upstream.h b/qemu-0.15.x/hw/xio3130_upstream.h
new file mode 100644
index 0000000..e996997
--- /dev/null
+++ b/qemu-0.15.x/hw/xio3130_upstream.h
@@ -0,0 +1,10 @@
+#ifndef QEMU_XIO3130_UPSTREAM_H
+#define QEMU_XIO3130_UPSTREAM_H
+
+#include "pcie_port.h"
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                const char *bus_name, pci_map_irq_fn map_irq,
+                                uint8_t port);
+
+#endif /* QEMU_XIO3130_H */
diff --git a/qemu-0.15.x/hw/zaurus.c b/qemu-0.15.x/hw/zaurus.c
new file mode 100644
index 0000000..c24aeb5
--- /dev/null
+++ b/qemu-0.15.x/hw/zaurus.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2006-2008 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "sharpsl.h"
+#include "sysbus.h"
+
+#undef REG_FMT
+#define REG_FMT			"0x%02lx"
+
+/* SCOOP devices */
+
+typedef struct ScoopInfo ScoopInfo;
+struct ScoopInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[16];
+    uint16_t status;
+    uint16_t power;
+    uint32_t gpio_level;
+    uint32_t gpio_dir;
+    uint32_t prev_level;
+
+    uint16_t mcr;
+    uint16_t cdr;
+    uint16_t ccr;
+    uint16_t irr;
+    uint16_t imr;
+    uint16_t isr;
+};
+
+#define SCOOP_MCR	0x00
+#define SCOOP_CDR	0x04
+#define SCOOP_CSR	0x08
+#define SCOOP_CPR	0x0c
+#define SCOOP_CCR	0x10
+#define SCOOP_IRR_IRM	0x14
+#define SCOOP_IMR	0x18
+#define SCOOP_ISR	0x1c
+#define SCOOP_GPCR	0x20
+#define SCOOP_GPWR	0x24
+#define SCOOP_GPRR	0x28
+
+static inline void scoop_gpio_handler_update(ScoopInfo *s) {
+    uint32_t level, diff;
+    int bit;
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+
+    switch (addr & 0x3f) {
+    case SCOOP_MCR:
+        return s->mcr;
+    case SCOOP_CDR:
+        return s->cdr;
+    case SCOOP_CSR:
+        return s->status;
+    case SCOOP_CPR:
+        return s->power;
+    case SCOOP_CCR:
+        return s->ccr;
+    case SCOOP_IRR_IRM:
+        return s->irr;
+    case SCOOP_IMR:
+        return s->imr;
+    case SCOOP_ISR:
+        return s->isr;
+    case SCOOP_GPCR:
+        return s->gpio_dir;
+    case SCOOP_GPWR:
+    case SCOOP_GPRR:
+        return s->gpio_level;
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+
+    return 0;
+}
+
+static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+    value &= 0xffff;
+
+    switch (addr & 0x3f) {
+    case SCOOP_MCR:
+        s->mcr = value;
+        break;
+    case SCOOP_CDR:
+        s->cdr = value;
+        break;
+    case SCOOP_CPR:
+        s->power = value;
+        if (value & 0x80)
+            s->power |= 0x8040;
+        break;
+    case SCOOP_CCR:
+        s->ccr = value;
+        break;
+    case SCOOP_IRR_IRM:
+        s->irr = value;
+        break;
+    case SCOOP_IMR:
+        s->imr = value;
+        break;
+    case SCOOP_ISR:
+        s->isr = value;
+        break;
+    case SCOOP_GPCR:
+        s->gpio_dir = value;
+        scoop_gpio_handler_update(s);
+        break;
+    case SCOOP_GPWR:
+    case SCOOP_GPRR:	/* GPRR is probably R/O in real HW */
+        s->gpio_level = value & s->gpio_dir;
+        scoop_gpio_handler_update(s);
+        break;
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+}
+
+static CPUReadMemoryFunc * const scoop_readfn[] = {
+    scoop_readb,
+    scoop_readb,
+    scoop_readb,
+};
+static CPUWriteMemoryFunc * const scoop_writefn[] = {
+    scoop_writeb,
+    scoop_writeb,
+    scoop_writeb,
+};
+
+static void scoop_gpio_set(void *opaque, int line, int level)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+
+    if (level)
+        s->gpio_level |= (1 << line);
+    else
+        s->gpio_level &= ~(1 << line);
+}
+
+static int scoop_init(SysBusDevice *dev)
+{
+    ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev);
+    int iomemtype;
+
+    s->status = 0x02;
+    qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16);
+    qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16);
+    iomemtype = cpu_register_io_memory(scoop_readfn,
+                    scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    return 0;
+}
+
+static int scoop_post_load(void *opaque, int version_id)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+    int i;
+    uint32_t level;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (i = 0; i < 16; i++) {
+        qemu_set_irq(s->handler[i], (level >> i) & 1);
+    }
+
+    s->prev_level = level;
+
+    return 0;
+}
+
+static bool is_version_0 (void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static const VMStateDescription vmstate_scoop_regs = {
+    .name = "scoop",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = scoop_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT16(status, ScoopInfo),
+        VMSTATE_UINT16(power, ScoopInfo),
+        VMSTATE_UINT32(gpio_level, ScoopInfo),
+        VMSTATE_UINT32(gpio_dir, ScoopInfo),
+        VMSTATE_UINT32(prev_level, ScoopInfo),
+        VMSTATE_UINT16(mcr, ScoopInfo),
+        VMSTATE_UINT16(cdr, ScoopInfo),
+        VMSTATE_UINT16(ccr, ScoopInfo),
+        VMSTATE_UINT16(irr, ScoopInfo),
+        VMSTATE_UINT16(imr, ScoopInfo),
+        VMSTATE_UINT16(isr, ScoopInfo),
+        VMSTATE_UNUSED_TEST(is_version_0, 2),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo scoop_sysbus_info = {
+    .init           = scoop_init,
+    .qdev.name      = "scoop",
+    .qdev.desc      = "Scoop2 Sharp custom ASIC",
+    .qdev.size      = sizeof(ScoopInfo),
+    .qdev.vmsd      = &vmstate_scoop_regs,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void scoop_register(void)
+{
+    sysbus_register_withprop(&scoop_sysbus_info);
+}
+device_init(scoop_register);
+
+/* Write the bootloader parameters memory area.  */
+
+#define MAGIC_CHG(a, b, c, d)	((d << 24) | (c << 16) | (b << 8) | a)
+
+static struct __attribute__ ((__packed__)) sl_param_info {
+    uint32_t comadj_keyword;
+    int32_t comadj;
+
+    uint32_t uuid_keyword;
+    char uuid[16];
+
+    uint32_t touch_keyword;
+    int32_t touch_xp;
+    int32_t touch_yp;
+    int32_t touch_xd;
+    int32_t touch_yd;
+
+    uint32_t adadj_keyword;
+    int32_t adadj;
+
+    uint32_t phad_keyword;
+    int32_t phadadj;
+} zaurus_bootparam = {
+    .comadj_keyword	= MAGIC_CHG('C', 'M', 'A', 'D'),
+    .comadj		= 125,
+    .uuid_keyword	= MAGIC_CHG('U', 'U', 'I', 'D'),
+    .uuid		= { -1 },
+    .touch_keyword	= MAGIC_CHG('T', 'U', 'C', 'H'),
+    .touch_xp		= -1,
+    .adadj_keyword	= MAGIC_CHG('B', 'V', 'A', 'D'),
+    .adadj		= -1,
+    .phad_keyword	= MAGIC_CHG('P', 'H', 'A', 'D'),
+    .phadadj		= 0x01,
+};
+
+void sl_bootparam_write(target_phys_addr_t ptr)
+{
+    cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam,
+                              sizeof(struct sl_param_info));
+}
diff --git a/qemu-0.15.x/i386-dis.c b/qemu-0.15.x/i386-dis.c
new file mode 100644
index 0000000..c4a81c9
--- /dev/null
+++ b/qemu-0.15.x/i386-dis.c
@@ -0,0 +1,6562 @@
+/* opcodes/i386-dis.c r1.126 */
+/* Print i386 instructions for GDB, the GNU debugger.
+   Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* 80386 instruction printer by Pace Willisson (pace at prep.ai.mit.edu)
+   July 1988
+    modified by John Hassey (hassey at dg-rtp.dg.com)
+    x86-64 support added by Jan Hubicka (jh at suse.cz)
+    VIA PadLock support by Michal Ludvig (mludvig at suse.cz).  */
+
+/* The main tables describing the instructions is essentially a copy
+   of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+   Programmers Manual.  Usually, there is a capital letter, followed
+   by a small letter.  The capital letter tell the addressing mode,
+   and the small letter tells about the operand size.  Refer to
+   the Intel manual for details.  */
+
+#include <stdlib.h>
+#include "dis-asm.h"
+/* include/opcode/i386.h r1.78 */
+
+/* opcode/i386.h -- Intel 80386 opcode macros
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived
+   ix86 Unix assemblers, generate floating point instructions with
+   reversed source and destination registers in certain cases.
+   Unfortunately, gcc and possibly many other programs use this
+   reversed syntax, so we're stuck with it.
+
+   eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but
+   `fsub %st,%st(3)' results in st(3) = st - st(3), rather than
+   the expected st(3) = st(3) - st
+
+   This happens with all the non-commutative arithmetic floating point
+   operations with two register operands, where the source register is
+   %st, and destination register is %st(i).
+
+   The affected opcode map is dceX, dcfX, deeX, defX.  */
+
+#ifndef SYSV386_COMPAT
+/* Set non-zero for broken, compatible instructions.  Set to zero for
+   non-broken opcodes at your peril.  gcc generates SystemV/386
+   compatible instructions.  */
+#define SYSV386_COMPAT 1
+#endif
+#ifndef OLDGCC_COMPAT
+/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could
+   generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands
+   reversed.  */
+#define OLDGCC_COMPAT SYSV386_COMPAT
+#endif
+
+#define MOV_AX_DISP32 0xa0
+#define POP_SEG_SHORT 0x07
+#define JUMP_PC_RELATIVE 0xeb
+#define INT_OPCODE  0xcd
+#define INT3_OPCODE 0xcc
+/* The opcode for the fwait instruction, which disassembler treats as a
+   prefix when it can.  */
+#define FWAIT_OPCODE 0x9b
+#define ADDR_PREFIX_OPCODE 0x67
+#define DATA_PREFIX_OPCODE 0x66
+#define LOCK_PREFIX_OPCODE 0xf0
+#define CS_PREFIX_OPCODE 0x2e
+#define DS_PREFIX_OPCODE 0x3e
+#define ES_PREFIX_OPCODE 0x26
+#define FS_PREFIX_OPCODE 0x64
+#define GS_PREFIX_OPCODE 0x65
+#define SS_PREFIX_OPCODE 0x36
+#define REPNE_PREFIX_OPCODE 0xf2
+#define REPE_PREFIX_OPCODE  0xf3
+
+#define TWO_BYTE_OPCODE_ESCAPE 0x0f
+#define NOP_OPCODE (char) 0x90
+
+/* register numbers */
+#define EBP_REG_NUM 5
+#define ESP_REG_NUM 4
+
+/* modrm_byte.regmem for twobyte escape */
+#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM
+/* index_base_byte.index for no index register addressing */
+#define NO_INDEX_REGISTER ESP_REG_NUM
+/* index_base_byte.base for no base register addressing */
+#define NO_BASE_REGISTER EBP_REG_NUM
+#define NO_BASE_REGISTER_16 6
+
+/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */
+#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */
+#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG)
+
+/* x86-64 extension prefix.  */
+#define REX_OPCODE	0x40
+
+/* Indicates 64 bit operand size.  */
+#define REX_W	8
+/* High extension to reg field of modrm byte.  */
+#define REX_R	4
+/* High extension to SIB index field.  */
+#define REX_X	2
+/* High extension to base field of modrm or SIB, or reg field of opcode.  */
+#define REX_B	1
+
+/* max operands per insn */
+#define MAX_OPERANDS 4
+
+/* max immediates per insn (lcall, ljmp, insertq, extrq) */
+#define MAX_IMMEDIATE_OPERANDS 2
+
+/* max memory refs per insn (string ops) */
+#define MAX_MEMORY_OPERANDS 2
+
+/* max size of insn mnemonics.  */
+#define MAX_MNEM_SIZE 16
+
+/* max size of register name in insn mnemonics.  */
+#define MAX_REG_NAME_SIZE 8
+
+/* opcodes/i386-dis.c r1.126 */
+#include "qemu-common.h"
+
+#include <setjmp.h>
+
+static int fetch_data2(struct disassemble_info *, bfd_byte *);
+static int fetch_data(struct disassemble_info *, bfd_byte *);
+static void ckprefix (void);
+static const char *prefix_name (int, int);
+static int print_insn (bfd_vma, disassemble_info *);
+static void dofloat (int);
+static void OP_ST (int, int);
+static void OP_STi (int, int);
+static int putop (const char *, int);
+static void oappend (const char *);
+static void append_seg (void);
+static void OP_indirE (int, int);
+static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp);
+static void print_displacement (char *, bfd_vma);
+static void OP_E (int, int);
+static void OP_G (int, int);
+static bfd_vma get64 (void);
+static bfd_signed_vma get32 (void);
+static bfd_signed_vma get32s (void);
+static int get16 (void);
+static void set_op (bfd_vma, int);
+static void OP_REG (int, int);
+static void OP_IMREG (int, int);
+static void OP_I (int, int);
+static void OP_I64 (int, int);
+static void OP_sI (int, int);
+static void OP_J (int, int);
+static void OP_SEG (int, int);
+static void OP_DIR (int, int);
+static void OP_OFF (int, int);
+static void OP_OFF64 (int, int);
+static void ptr_reg (int, int);
+static void OP_ESreg (int, int);
+static void OP_DSreg (int, int);
+static void OP_C (int, int);
+static void OP_D (int, int);
+static void OP_T (int, int);
+static void OP_R (int, int);
+static void OP_MMX (int, int);
+static void OP_XMM (int, int);
+static void OP_EM (int, int);
+static void OP_EX (int, int);
+static void OP_EMC (int,int);
+static void OP_MXC (int,int);
+static void OP_MS (int, int);
+static void OP_XS (int, int);
+static void OP_M (int, int);
+static void OP_VMX (int, int);
+static void OP_0fae (int, int);
+static void OP_0f07 (int, int);
+static void NOP_Fixup1 (int, int);
+static void NOP_Fixup2 (int, int);
+static void OP_3DNowSuffix (int, int);
+static void OP_SIMD_Suffix (int, int);
+static void SIMD_Fixup (int, int);
+static void PNI_Fixup (int, int);
+static void SVME_Fixup (int, int);
+static void INVLPG_Fixup (int, int);
+static void BadOp (void);
+static void VMX_Fixup (int, int);
+static void REP_Fixup (int, int);
+static void CMPXCHG8B_Fixup (int, int);
+static void XMM_Fixup (int, int);
+static void CRC32_Fixup (int, int);
+
+struct dis_private {
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAX_MNEM_SIZE];
+  bfd_vma insn_start;
+  int orig_sizeflag;
+  jmp_buf bailout;
+};
+
+enum address_mode
+{
+  mode_16bit,
+  mode_32bit,
+  mode_64bit
+};
+
+static enum address_mode address_mode;
+
+/* Flags for the prefixes for the current instruction.  See below.  */
+static int prefixes;
+
+/* REX prefix the current instruction.  See below.  */
+static int rex;
+/* Bits of REX we've already used.  */
+static int rex_used;
+/* Mark parts used in the REX prefix.  When we are testing for
+   empty prefix (for 8bit register REX extension), just mask it
+   out.  Otherwise test for REX bit is excuse for existence of REX
+   only in case value is nonzero.  */
+#define USED_REX(value)					\
+  {							\
+    if (value)						\
+      {							\
+	if ((rex & value))				\
+	  rex_used |= (value) | REX_OPCODE;		\
+      }							\
+    else						\
+      rex_used |= REX_OPCODE;				\
+  }
+
+/* Flags for prefixes which we somehow handled when printing the
+   current instruction.  */
+static int used_prefixes;
+
+/* Flags stored in PREFIXES.  */
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADDR 0x400
+#define PREFIX_FWAIT 0x800
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
+   on error.  */
+static int
+fetch_data2(struct disassemble_info *info, bfd_byte *addr)
+{
+  int status;
+  struct dis_private *priv = (struct dis_private *) info->private_data;
+  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+  if (addr <= priv->the_buffer + MAX_MNEM_SIZE)
+    status = (*info->read_memory_func) (start,
+					priv->max_fetched,
+					addr - priv->max_fetched,
+					info);
+  else
+    status = -1;
+  if (status != 0)
+    {
+      /* If we did manage to read at least one byte, then
+	 print_insn_i386 will do something sensible.  Otherwise, print
+	 an error.  We do that here because this is where we know
+	 STATUS.  */
+      if (priv->max_fetched == priv->the_buffer)
+	(*info->memory_error_func) (status, start, info);
+      longjmp (priv->bailout, 1);
+    }
+  else
+    priv->max_fetched = addr;
+  return 1;
+}
+
+static int
+fetch_data(struct disassemble_info *info, bfd_byte *addr)
+{
+    if (addr <= ((struct dis_private *) (info->private_data))->max_fetched) {
+        return 1;
+    } else {
+        return fetch_data2(info, addr);
+    }
+}
+
+
+#define XX { NULL, 0 }
+
+#define Eb { OP_E, b_mode }
+#define Ev { OP_E, v_mode }
+#define Ed { OP_E, d_mode }
+#define Edq { OP_E, dq_mode }
+#define Edqw { OP_E, dqw_mode }
+#define Edqb { OP_E, dqb_mode }
+#define Edqd { OP_E, dqd_mode }
+#define indirEv { OP_indirE, stack_v_mode }
+#define indirEp { OP_indirE, f_mode }
+#define stackEv { OP_E, stack_v_mode }
+#define Em { OP_E, m_mode }
+#define Ew { OP_E, w_mode }
+#define M { OP_M, 0 }		/* lea, lgdt, etc. */
+#define Ma { OP_M, v_mode }
+#define Mp { OP_M, f_mode }		/* 32 or 48 bit memory operand for LDS, LES etc */
+#define Mq { OP_M, q_mode }
+#define Gb { OP_G, b_mode }
+#define Gv { OP_G, v_mode }
+#define Gd { OP_G, d_mode }
+#define Gdq { OP_G, dq_mode }
+#define Gm { OP_G, m_mode }
+#define Gw { OP_G, w_mode }
+#define Rd { OP_R, d_mode }
+#define Rm { OP_R, m_mode }
+#define Ib { OP_I, b_mode }
+#define sIb { OP_sI, b_mode }	/* sign extened byte */
+#define Iv { OP_I, v_mode }
+#define Iq { OP_I, q_mode }
+#define Iv64 { OP_I64, v_mode }
+#define Iw { OP_I, w_mode }
+#define I1 { OP_I, const_1_mode }
+#define Jb { OP_J, b_mode }
+#define Jv { OP_J, v_mode }
+#define Cm { OP_C, m_mode }
+#define Dm { OP_D, m_mode }
+#define Td { OP_T, d_mode }
+
+#define RMeAX { OP_REG, eAX_reg }
+#define RMeBX { OP_REG, eBX_reg }
+#define RMeCX { OP_REG, eCX_reg }
+#define RMeDX { OP_REG, eDX_reg }
+#define RMeSP { OP_REG, eSP_reg }
+#define RMeBP { OP_REG, eBP_reg }
+#define RMeSI { OP_REG, eSI_reg }
+#define RMeDI { OP_REG, eDI_reg }
+#define RMrAX { OP_REG, rAX_reg }
+#define RMrBX { OP_REG, rBX_reg }
+#define RMrCX { OP_REG, rCX_reg }
+#define RMrDX { OP_REG, rDX_reg }
+#define RMrSP { OP_REG, rSP_reg }
+#define RMrBP { OP_REG, rBP_reg }
+#define RMrSI { OP_REG, rSI_reg }
+#define RMrDI { OP_REG, rDI_reg }
+#define RMAL { OP_REG, al_reg }
+#define RMAL { OP_REG, al_reg }
+#define RMCL { OP_REG, cl_reg }
+#define RMDL { OP_REG, dl_reg }
+#define RMBL { OP_REG, bl_reg }
+#define RMAH { OP_REG, ah_reg }
+#define RMCH { OP_REG, ch_reg }
+#define RMDH { OP_REG, dh_reg }
+#define RMBH { OP_REG, bh_reg }
+#define RMAX { OP_REG, ax_reg }
+#define RMDX { OP_REG, dx_reg }
+
+#define eAX { OP_IMREG, eAX_reg }
+#define eBX { OP_IMREG, eBX_reg }
+#define eCX { OP_IMREG, eCX_reg }
+#define eDX { OP_IMREG, eDX_reg }
+#define eSP { OP_IMREG, eSP_reg }
+#define eBP { OP_IMREG, eBP_reg }
+#define eSI { OP_IMREG, eSI_reg }
+#define eDI { OP_IMREG, eDI_reg }
+#define AL { OP_IMREG, al_reg }
+#define CL { OP_IMREG, cl_reg }
+#define DL { OP_IMREG, dl_reg }
+#define BL { OP_IMREG, bl_reg }
+#define AH { OP_IMREG, ah_reg }
+#define CH { OP_IMREG, ch_reg }
+#define DH { OP_IMREG, dh_reg }
+#define BH { OP_IMREG, bh_reg }
+#define AX { OP_IMREG, ax_reg }
+#define DX { OP_IMREG, dx_reg }
+#define zAX { OP_IMREG, z_mode_ax_reg }
+#define indirDX { OP_IMREG, indir_dx_reg }
+
+#define Sw { OP_SEG, w_mode }
+#define Sv { OP_SEG, v_mode }
+#define Ap { OP_DIR, 0 }
+#define Ob { OP_OFF64, b_mode }
+#define Ov { OP_OFF64, v_mode }
+#define Xb { OP_DSreg, eSI_reg }
+#define Xv { OP_DSreg, eSI_reg }
+#define Xz { OP_DSreg, eSI_reg }
+#define Yb { OP_ESreg, eDI_reg }
+#define Yv { OP_ESreg, eDI_reg }
+#define DSBX { OP_DSreg, eBX_reg }
+
+#define es { OP_REG, es_reg }
+#define ss { OP_REG, ss_reg }
+#define cs { OP_REG, cs_reg }
+#define ds { OP_REG, ds_reg }
+#define fs { OP_REG, fs_reg }
+#define gs { OP_REG, gs_reg }
+
+#define MX { OP_MMX, 0 }
+#define XM { OP_XMM, 0 }
+#define EM { OP_EM, v_mode }
+#define EMd { OP_EM, d_mode }
+#define EMq { OP_EM, q_mode }
+#define EXd { OP_EX, d_mode }
+#define EXq { OP_EX, q_mode }
+#define EXx { OP_EX, x_mode }
+#define MS { OP_MS, v_mode }
+#define XS { OP_XS, v_mode }
+#define EMC { OP_EMC, v_mode }
+#define MXC { OP_MXC, 0 }
+#define VM { OP_VMX, q_mode }
+#define OPSUF { OP_3DNowSuffix, 0 }
+#define OPSIMD { OP_SIMD_Suffix, 0 }
+#define XMM0 { XMM_Fixup, 0 }
+
+/* Used handle "rep" prefix for string instructions.  */
+#define Xbr { REP_Fixup, eSI_reg }
+#define Xvr { REP_Fixup, eSI_reg }
+#define Ybr { REP_Fixup, eDI_reg }
+#define Yvr { REP_Fixup, eDI_reg }
+#define Yzr { REP_Fixup, eDI_reg }
+#define indirDXr { REP_Fixup, indir_dx_reg }
+#define ALr { REP_Fixup, al_reg }
+#define eAXr { REP_Fixup, eAX_reg }
+
+#define cond_jump_flag { NULL, cond_jump_mode }
+#define loop_jcxz_flag { NULL, loop_jcxz_mode }
+
+/* bits in sizeflag */
+#define SUFFIX_ALWAYS 4
+#define AFLAG 2
+#define DFLAG 1
+
+#define b_mode 1  /* byte operand */
+#define v_mode 2  /* operand size depends on prefixes */
+#define w_mode 3  /* word operand */
+#define d_mode 4  /* double word operand  */
+#define q_mode 5  /* quad word operand */
+#define t_mode 6  /* ten-byte operand */
+#define x_mode 7  /* 16-byte XMM operand */
+#define m_mode 8  /* d_mode in 32bit, q_mode in 64bit mode.  */
+#define cond_jump_mode 9
+#define loop_jcxz_mode 10
+#define dq_mode 11 /* operand size depends on REX prefixes.  */
+#define dqw_mode 12 /* registers like dq_mode, memory like w_mode.  */
+#define f_mode 13 /* 4- or 6-byte pointer operand */
+#define const_1_mode 14
+#define stack_v_mode 15 /* v_mode for stack-related opcodes.  */
+#define z_mode 16 /* non-quad operand size depends on prefixes */
+#define o_mode 17  /* 16-byte operand */
+#define dqb_mode 18 /* registers like dq_mode, memory like b_mode.  */
+#define dqd_mode 19 /* registers like dq_mode, memory like d_mode.  */
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+
+#define eAX_reg 108
+#define eCX_reg 109
+#define eDX_reg 110
+#define eBX_reg 111
+#define eSP_reg 112
+#define eBP_reg 113
+#define eSI_reg 114
+#define eDI_reg 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define rAX_reg 132
+#define rCX_reg 133
+#define rDX_reg 134
+#define rBX_reg 135
+#define rSP_reg 136
+#define rBP_reg 137
+#define rSI_reg 138
+#define rDI_reg 139
+
+#define z_mode_ax_reg 149
+#define indir_dx_reg 150
+
+#define FLOATCODE 1
+#define USE_GROUPS 2
+#define USE_PREFIX_USER_TABLE 3
+#define X86_64_SPECIAL 4
+#define IS_3BYTE_OPCODE 5
+
+#define FLOAT	  NULL, { { NULL, FLOATCODE } }
+
+#define GRP1a	  NULL, { { NULL, USE_GROUPS }, { NULL,  0 } }
+#define GRP1b	  NULL, { { NULL, USE_GROUPS }, { NULL,  1 } }
+#define GRP1S	  NULL, { { NULL, USE_GROUPS }, { NULL,  2 } }
+#define GRP1Ss	  NULL, { { NULL, USE_GROUPS }, { NULL,  3 } }
+#define GRP2b	  NULL, { { NULL, USE_GROUPS }, { NULL,  4 } }
+#define GRP2S	  NULL, { { NULL, USE_GROUPS }, { NULL,  5 } }
+#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL,  6 } }
+#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL,  7 } }
+#define GRP2b_cl  NULL, { { NULL, USE_GROUPS }, { NULL,  8 } }
+#define GRP2S_cl  NULL, { { NULL, USE_GROUPS }, { NULL,  9 } }
+#define GRP3b	  NULL, { { NULL, USE_GROUPS }, { NULL, 10 } }
+#define GRP3S	  NULL, { { NULL, USE_GROUPS }, { NULL, 11 } }
+#define GRP4	  NULL, { { NULL, USE_GROUPS }, { NULL, 12 } }
+#define GRP5	  NULL, { { NULL, USE_GROUPS }, { NULL, 13 } }
+#define GRP6	  NULL, { { NULL, USE_GROUPS }, { NULL, 14 } }
+#define GRP7	  NULL, { { NULL, USE_GROUPS }, { NULL, 15 } }
+#define GRP8	  NULL, { { NULL, USE_GROUPS }, { NULL, 16 } }
+#define GRP9	  NULL, { { NULL, USE_GROUPS }, { NULL, 17 } }
+#define GRP11_C6  NULL, { { NULL, USE_GROUPS }, { NULL, 18 } }
+#define GRP11_C7  NULL, { { NULL, USE_GROUPS }, { NULL, 19 } }
+#define GRP12	  NULL, { { NULL, USE_GROUPS }, { NULL, 20 } }
+#define GRP13	  NULL, { { NULL, USE_GROUPS }, { NULL, 21 } }
+#define GRP14	  NULL, { { NULL, USE_GROUPS }, { NULL, 22 } }
+#define GRP15	  NULL, { { NULL, USE_GROUPS }, { NULL, 23 } }
+#define GRP16	  NULL, { { NULL, USE_GROUPS }, { NULL, 24 } }
+#define GRPAMD	  NULL, { { NULL, USE_GROUPS }, { NULL, 25 } }
+#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } }
+#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } }
+
+#define PREGRP0   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  0 } }
+#define PREGRP1   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  1 } }
+#define PREGRP2   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  2 } }
+#define PREGRP3   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  3 } }
+#define PREGRP4   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  4 } }
+#define PREGRP5   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  5 } }
+#define PREGRP6   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  6 } }
+#define PREGRP7   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  7 } }
+#define PREGRP8   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  8 } }
+#define PREGRP9   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  9 } }
+#define PREGRP10  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } }
+#define PREGRP11  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } }
+#define PREGRP12  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } }
+#define PREGRP13  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } }
+#define PREGRP14  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } }
+#define PREGRP15  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } }
+#define PREGRP16  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } }
+#define PREGRP17  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } }
+#define PREGRP18  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } }
+#define PREGRP19  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } }
+#define PREGRP20  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } }
+#define PREGRP21  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } }
+#define PREGRP22  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } }
+#define PREGRP23  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } }
+#define PREGRP24  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } }
+#define PREGRP25  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } }
+#define PREGRP26  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } }
+#define PREGRP27  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } }
+#define PREGRP28  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } }
+#define PREGRP29  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } }
+#define PREGRP30  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } }
+#define PREGRP31  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } }
+#define PREGRP32  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } }
+#define PREGRP33  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } }
+#define PREGRP34  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } }
+#define PREGRP35  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } }
+#define PREGRP36  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } }
+#define PREGRP37  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } }
+#define PREGRP38  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } }
+#define PREGRP39  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } }
+#define PREGRP40  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } }
+#define PREGRP41  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } }
+#define PREGRP42  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } }
+#define PREGRP43  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } }
+#define PREGRP44  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } }
+#define PREGRP45  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } }
+#define PREGRP46  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } }
+#define PREGRP47  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } }
+#define PREGRP48  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } }
+#define PREGRP49  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } }
+#define PREGRP50  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } }
+#define PREGRP51  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } }
+#define PREGRP52  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } }
+#define PREGRP53  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } }
+#define PREGRP54  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } }
+#define PREGRP55  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } }
+#define PREGRP56  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } }
+#define PREGRP57  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } }
+#define PREGRP58  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } }
+#define PREGRP59  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } }
+#define PREGRP60  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } }
+#define PREGRP61  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } }
+#define PREGRP62  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } }
+#define PREGRP63  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } }
+#define PREGRP64  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } }
+#define PREGRP65  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } }
+#define PREGRP66  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } }
+#define PREGRP67  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } }
+#define PREGRP68  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } }
+#define PREGRP69  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } }
+#define PREGRP70  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } }
+#define PREGRP71  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } }
+#define PREGRP72  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } }
+#define PREGRP73  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } }
+#define PREGRP74  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } }
+#define PREGRP75  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } }
+#define PREGRP76  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } }
+#define PREGRP77  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } }
+#define PREGRP78  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } }
+#define PREGRP79  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } }
+#define PREGRP80  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } }
+#define PREGRP81  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } }
+#define PREGRP82  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } }
+#define PREGRP83  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } }
+#define PREGRP84  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } }
+#define PREGRP85  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } }
+#define PREGRP86  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } }
+#define PREGRP87  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } }
+#define PREGRP88  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } }
+#define PREGRP89  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } }
+#define PREGRP90  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } }
+#define PREGRP91  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } }
+#define PREGRP92  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } }
+#define PREGRP93  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } }
+#define PREGRP94  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } }
+#define PREGRP95  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } }
+#define PREGRP96  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } }
+#define PREGRP97  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } }
+
+
+#define X86_64_0  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
+#define X86_64_1  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } }
+#define X86_64_2  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } }
+#define X86_64_3  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } }
+
+#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } }
+#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } }
+
+typedef void (*op_rtn) (int bytemode, int sizeflag);
+
+struct dis386 {
+  const char *name;
+  struct
+    {
+      op_rtn rtn;
+      int bytemode;
+    } op[MAX_OPERANDS];
+};
+
+/* Upper case letters in the instruction names here are macros.
+   'A' => print 'b' if no register operands or suffix_always is true
+   'B' => print 'b' if suffix_always is true
+   'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand
+   .      size prefix
+   'D' => print 'w' if no register operands or 'w', 'l' or 'q', if
+   .      suffix_always is true
+   'E' => print 'e' if 32-bit form of jcxz
+   'F' => print 'w' or 'l' depending on address size prefix (loop insns)
+   'G' => print 'w' or 'l' depending on operand size prefix (i/o insns)
+   'H' => print ",pt" or ",pn" branch hint
+   'I' => honor following macro letter even in Intel mode (implemented only
+   .      for some of the macro letters)
+   'J' => print 'l'
+   'K' => print 'd' or 'q' if rex prefix is present.
+   'L' => print 'l' if suffix_always is true
+   'N' => print 'n' if instruction has no wait "prefix"
+   'O' => print 'd' or 'o' (or 'q' in Intel mode)
+   'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix,
+   .      or suffix_always is true.  print 'q' if rex prefix is present.
+   'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always
+   .      is true
+   'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode)
+   'S' => print 'w', 'l' or 'q' if suffix_always is true
+   'T' => print 'q' in 64bit mode and behave as 'P' otherwise
+   'U' => print 'q' in 64bit mode and behave as 'Q' otherwise
+   'V' => print 'q' in 64bit mode and behave as 'S' otherwise
+   'W' => print 'b', 'w' or 'l' ('d' in Intel mode)
+   'X' => print 's', 'd' depending on data16 prefix (for XMM)
+   'Y' => 'q' if instruction has an REX 64bit overwrite prefix
+   'Z' => print 'q' in 64bit mode and behave as 'L' otherwise
+
+   Many of the above letters print nothing in Intel mode.  See "putop"
+   for the details.
+
+   Braces '{' and '}', and vertical bars '|', indicate alternative
+   mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel
+   modes.  In cases where there are only two alternatives, the X86_64
+   instruction is reserved, and "(bad)" is printed.
+*/
+
+static const struct dis386 dis386[] = {
+  /* 00 */
+  { "addB",		{ Eb, Gb } },
+  { "addS",		{ Ev, Gv } },
+  { "addB",		{ Gb, Eb } },
+  { "addS",		{ Gv, Ev } },
+  { "addB",		{ AL, Ib } },
+  { "addS",		{ eAX, Iv } },
+  { "push{T|}",		{ es } },
+  { "pop{T|}",		{ es } },
+  /* 08 */
+  { "orB",		{ Eb, Gb } },
+  { "orS",		{ Ev, Gv } },
+  { "orB",		{ Gb, Eb } },
+  { "orS",		{ Gv, Ev } },
+  { "orB",		{ AL, Ib } },
+  { "orS",		{ eAX, Iv } },
+  { "push{T|}",		{ cs } },
+  { "(bad)",		{ XX } },	/* 0x0f extended opcode escape */
+  /* 10 */
+  { "adcB",		{ Eb, Gb } },
+  { "adcS",		{ Ev, Gv } },
+  { "adcB",		{ Gb, Eb } },
+  { "adcS",		{ Gv, Ev } },
+  { "adcB",		{ AL, Ib } },
+  { "adcS",		{ eAX, Iv } },
+  { "push{T|}",		{ ss } },
+  { "pop{T|}",		{ ss } },
+  /* 18 */
+  { "sbbB",		{ Eb, Gb } },
+  { "sbbS",		{ Ev, Gv } },
+  { "sbbB",		{ Gb, Eb } },
+  { "sbbS",		{ Gv, Ev } },
+  { "sbbB",		{ AL, Ib } },
+  { "sbbS",		{ eAX, Iv } },
+  { "push{T|}",		{ ds } },
+  { "pop{T|}",		{ ds } },
+  /* 20 */
+  { "andB",		{ Eb, Gb } },
+  { "andS",		{ Ev, Gv } },
+  { "andB",		{ Gb, Eb } },
+  { "andS",		{ Gv, Ev } },
+  { "andB",		{ AL, Ib } },
+  { "andS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG ES prefix */
+  { "daa{|}",		{ XX } },
+  /* 28 */
+  { "subB",		{ Eb, Gb } },
+  { "subS",		{ Ev, Gv } },
+  { "subB",		{ Gb, Eb } },
+  { "subS",		{ Gv, Ev } },
+  { "subB",		{ AL, Ib } },
+  { "subS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG CS prefix */
+  { "das{|}",		{ XX } },
+  /* 30 */
+  { "xorB",		{ Eb, Gb } },
+  { "xorS",		{ Ev, Gv } },
+  { "xorB",		{ Gb, Eb } },
+  { "xorS",		{ Gv, Ev } },
+  { "xorB",		{ AL, Ib } },
+  { "xorS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG SS prefix */
+  { "aaa{|}",		{ XX } },
+  /* 38 */
+  { "cmpB",		{ Eb, Gb } },
+  { "cmpS",		{ Ev, Gv } },
+  { "cmpB",		{ Gb, Eb } },
+  { "cmpS",		{ Gv, Ev } },
+  { "cmpB",		{ AL, Ib } },
+  { "cmpS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG DS prefix */
+  { "aas{|}",		{ XX } },
+  /* 40 */
+  { "inc{S|}",		{ RMeAX } },
+  { "inc{S|}",		{ RMeCX } },
+  { "inc{S|}",		{ RMeDX } },
+  { "inc{S|}",		{ RMeBX } },
+  { "inc{S|}",		{ RMeSP } },
+  { "inc{S|}",		{ RMeBP } },
+  { "inc{S|}",		{ RMeSI } },
+  { "inc{S|}",		{ RMeDI } },
+  /* 48 */
+  { "dec{S|}",		{ RMeAX } },
+  { "dec{S|}",		{ RMeCX } },
+  { "dec{S|}",		{ RMeDX } },
+  { "dec{S|}",		{ RMeBX } },
+  { "dec{S|}",		{ RMeSP } },
+  { "dec{S|}",		{ RMeBP } },
+  { "dec{S|}",		{ RMeSI } },
+  { "dec{S|}",		{ RMeDI } },
+  /* 50 */
+  { "pushV",		{ RMrAX } },
+  { "pushV",		{ RMrCX } },
+  { "pushV",		{ RMrDX } },
+  { "pushV",		{ RMrBX } },
+  { "pushV",		{ RMrSP } },
+  { "pushV",		{ RMrBP } },
+  { "pushV",		{ RMrSI } },
+  { "pushV",		{ RMrDI } },
+  /* 58 */
+  { "popV",		{ RMrAX } },
+  { "popV",		{ RMrCX } },
+  { "popV",		{ RMrDX } },
+  { "popV",		{ RMrBX } },
+  { "popV",		{ RMrSP } },
+  { "popV",		{ RMrBP } },
+  { "popV",		{ RMrSI } },
+  { "popV",		{ RMrDI } },
+  /* 60 */
+  { X86_64_0 },
+  { X86_64_1 },
+  { X86_64_2 },
+  { X86_64_3 },
+  { "(bad)",		{ XX } },	/* seg fs */
+  { "(bad)",		{ XX } },	/* seg gs */
+  { "(bad)",		{ XX } },	/* op size prefix */
+  { "(bad)",		{ XX } },	/* adr size prefix */
+  /* 68 */
+  { "pushT",		{ Iq } },
+  { "imulS",		{ Gv, Ev, Iv } },
+  { "pushT",		{ sIb } },
+  { "imulS",		{ Gv, Ev, sIb } },
+  { "ins{b||b|}",	{ Ybr, indirDX } },
+  { "ins{R||G|}",	{ Yzr, indirDX } },
+  { "outs{b||b|}",	{ indirDXr, Xb } },
+  { "outs{R||G|}",	{ indirDXr, Xz } },
+  /* 70 */
+  { "joH",		{ Jb, XX, cond_jump_flag } },
+  { "jnoH",		{ Jb, XX, cond_jump_flag } },
+  { "jbH",		{ Jb, XX, cond_jump_flag } },
+  { "jaeH",		{ Jb, XX, cond_jump_flag } },
+  { "jeH",		{ Jb, XX, cond_jump_flag } },
+  { "jneH",		{ Jb, XX, cond_jump_flag } },
+  { "jbeH",		{ Jb, XX, cond_jump_flag } },
+  { "jaH",		{ Jb, XX, cond_jump_flag } },
+  /* 78 */
+  { "jsH",		{ Jb, XX, cond_jump_flag } },
+  { "jnsH",		{ Jb, XX, cond_jump_flag } },
+  { "jpH",		{ Jb, XX, cond_jump_flag } },
+  { "jnpH",		{ Jb, XX, cond_jump_flag } },
+  { "jlH",		{ Jb, XX, cond_jump_flag } },
+  { "jgeH",		{ Jb, XX, cond_jump_flag } },
+  { "jleH",		{ Jb, XX, cond_jump_flag } },
+  { "jgH",		{ Jb, XX, cond_jump_flag } },
+  /* 80 */
+  { GRP1b },
+  { GRP1S },
+  { "(bad)",		{ XX } },
+  { GRP1Ss },
+  { "testB",		{ Eb, Gb } },
+  { "testS",		{ Ev, Gv } },
+  { "xchgB",		{ Eb, Gb } },
+  { "xchgS",		{ Ev, Gv } },
+  /* 88 */
+  { "movB",		{ Eb, Gb } },
+  { "movS",		{ Ev, Gv } },
+  { "movB",		{ Gb, Eb } },
+  { "movS",		{ Gv, Ev } },
+  { "movD",		{ Sv, Sw } },
+  { "leaS",		{ Gv, M } },
+  { "movD",		{ Sw, Sv } },
+  { GRP1a },
+  /* 90 */
+  { PREGRP38 },
+  { "xchgS",		{ RMeCX, eAX } },
+  { "xchgS",		{ RMeDX, eAX } },
+  { "xchgS",		{ RMeBX, eAX } },
+  { "xchgS",		{ RMeSP, eAX } },
+  { "xchgS",		{ RMeBP, eAX } },
+  { "xchgS",		{ RMeSI, eAX } },
+  { "xchgS",		{ RMeDI, eAX } },
+  /* 98 */
+  { "cW{t||t|}R",	{ XX } },
+  { "cR{t||t|}O",	{ XX } },
+  { "Jcall{T|}",	{ Ap } },
+  { "(bad)",		{ XX } },	/* fwait */
+  { "pushfT",		{ XX } },
+  { "popfT",		{ XX } },
+  { "sahf{|}",		{ XX } },
+  { "lahf{|}",		{ XX } },
+  /* a0 */
+  { "movB",		{ AL, Ob } },
+  { "movS",		{ eAX, Ov } },
+  { "movB",		{ Ob, AL } },
+  { "movS",		{ Ov, eAX } },
+  { "movs{b||b|}",	{ Ybr, Xb } },
+  { "movs{R||R|}",	{ Yvr, Xv } },
+  { "cmps{b||b|}",	{ Xb, Yb } },
+  { "cmps{R||R|}",	{ Xv, Yv } },
+  /* a8 */
+  { "testB",		{ AL, Ib } },
+  { "testS",		{ eAX, Iv } },
+  { "stosB",		{ Ybr, AL } },
+  { "stosS",		{ Yvr, eAX } },
+  { "lodsB",		{ ALr, Xb } },
+  { "lodsS",		{ eAXr, Xv } },
+  { "scasB",		{ AL, Yb } },
+  { "scasS",		{ eAX, Yv } },
+  /* b0 */
+  { "movB",		{ RMAL, Ib } },
+  { "movB",		{ RMCL, Ib } },
+  { "movB",		{ RMDL, Ib } },
+  { "movB",		{ RMBL, Ib } },
+  { "movB",		{ RMAH, Ib } },
+  { "movB",		{ RMCH, Ib } },
+  { "movB",		{ RMDH, Ib } },
+  { "movB",		{ RMBH, Ib } },
+  /* b8 */
+  { "movS",		{ RMeAX, Iv64 } },
+  { "movS",		{ RMeCX, Iv64 } },
+  { "movS",		{ RMeDX, Iv64 } },
+  { "movS",		{ RMeBX, Iv64 } },
+  { "movS",		{ RMeSP, Iv64 } },
+  { "movS",		{ RMeBP, Iv64 } },
+  { "movS",		{ RMeSI, Iv64 } },
+  { "movS",		{ RMeDI, Iv64 } },
+  /* c0 */
+  { GRP2b },
+  { GRP2S },
+  { "retT",		{ Iw } },
+  { "retT",		{ XX } },
+  { "les{S|}",		{ Gv, Mp } },
+  { "ldsS",		{ Gv, Mp } },
+  { GRP11_C6 },
+  { GRP11_C7 },
+  /* c8 */
+  { "enterT",		{ Iw, Ib } },
+  { "leaveT",		{ XX } },
+  { "lretP",		{ Iw } },
+  { "lretP",		{ XX } },
+  { "int3",		{ XX } },
+  { "int",		{ Ib } },
+  { "into{|}",		{ XX } },
+  { "iretP",		{ XX } },
+  /* d0 */
+  { GRP2b_one },
+  { GRP2S_one },
+  { GRP2b_cl },
+  { GRP2S_cl },
+  { "aam{|}",		{ sIb } },
+  { "aad{|}",		{ sIb } },
+  { "(bad)",		{ XX } },
+  { "xlat",		{ DSBX } },
+  /* d8 */
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  { FLOAT },
+  /* e0 */
+  { "loopneFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "loopeFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "loopFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "jEcxzH",		{ Jb, XX, loop_jcxz_flag } },
+  { "inB",		{ AL, Ib } },
+  { "inG",		{ zAX, Ib } },
+  { "outB",		{ Ib, AL } },
+  { "outG",		{ Ib, zAX } },
+  /* e8 */
+  { "callT",		{ Jv } },
+  { "jmpT",		{ Jv } },
+  { "Jjmp{T|}",		{ Ap } },
+  { "jmp",		{ Jb } },
+  { "inB",		{ AL, indirDX } },
+  { "inG",		{ zAX, indirDX } },
+  { "outB",		{ indirDX, AL } },
+  { "outG",		{ indirDX, zAX } },
+  /* f0 */
+  { "(bad)",		{ XX } },	/* lock prefix */
+  { "icebp",		{ XX } },
+  { "(bad)",		{ XX } },	/* repne */
+  { "(bad)",		{ XX } },	/* repz */
+  { "hlt",		{ XX } },
+  { "cmc",		{ XX } },
+  { GRP3b },
+  { GRP3S },
+  /* f8 */
+  { "clc",		{ XX } },
+  { "stc",		{ XX } },
+  { "cli",		{ XX } },
+  { "sti",		{ XX } },
+  { "cld",		{ XX } },
+  { "std",		{ XX } },
+  { GRP4 },
+  { GRP5 },
+};
+
+static const struct dis386 dis386_twobyte[] = {
+  /* 00 */
+  { GRP6 },
+  { GRP7 },
+  { "larS",		{ Gv, Ew } },
+  { "lslS",		{ Gv, Ew } },
+  { "(bad)",		{ XX } },
+  { "syscall",		{ XX } },
+  { "clts",		{ XX } },
+  { "sysretP",		{ XX } },
+  /* 08 */
+  { "invd",		{ XX } },
+  { "wbinvd",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "ud2a",		{ XX } },
+  { "(bad)",		{ XX } },
+  { GRPAMD },
+  { "femms",		{ XX } },
+  { "",			{ MX, EM, OPSUF } }, /* See OP_3DNowSuffix.  */
+  /* 10 */
+  { PREGRP8 },
+  { PREGRP9 },
+  { PREGRP30 },
+  { "movlpX",		{ EXq, XM, { SIMD_Fixup, 'h' } } },
+  { "unpcklpX",		{ XM, EXq } },
+  { "unpckhpX",		{ XM, EXq } },
+  { PREGRP31 },
+  { "movhpX",		{ EXq, XM, { SIMD_Fixup, 'l' } } },
+  /* 18 */
+  { GRP16 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "nopQ",		{ Ev } },
+  /* 20 */
+  { "movZ",		{ Rm, Cm } },
+  { "movZ",		{ Rm, Dm } },
+  { "movZ",		{ Cm, Rm } },
+  { "movZ",		{ Dm, Rm } },
+  { "movL",		{ Rd, Td } },
+  { "(bad)",		{ XX } },
+  { "movL",		{ Td, Rd } },
+  { "(bad)",		{ XX } },
+  /* 28 */
+  { "movapX",		{ XM, EXx } },
+  { "movapX",		{ EXx,  XM } },
+  { PREGRP2 },
+  { PREGRP33 },
+  { PREGRP4 },
+  { PREGRP3 },
+  { PREGRP93 },
+  { PREGRP94 },
+  /* 30 */
+  { "wrmsr",		{ XX } },
+  { "rdtsc",		{ XX } },
+  { "rdmsr",		{ XX } },
+  { "rdpmc",		{ XX } },
+  { "sysenter",		{ XX } },
+  { "sysexit",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  /* 38 */
+  { THREE_BYTE_0 },
+  { "(bad)",		{ XX } },
+  { THREE_BYTE_1 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  /* 40 */
+  { "cmovo",		{ Gv, Ev } },
+  { "cmovno",		{ Gv, Ev } },
+  { "cmovb",		{ Gv, Ev } },
+  { "cmovae",		{ Gv, Ev } },
+  { "cmove",		{ Gv, Ev } },
+  { "cmovne",		{ Gv, Ev } },
+  { "cmovbe",		{ Gv, Ev } },
+  { "cmova",		{ Gv, Ev } },
+  /* 48 */
+  { "cmovs",		{ Gv, Ev } },
+  { "cmovns",		{ Gv, Ev } },
+  { "cmovp",		{ Gv, Ev } },
+  { "cmovnp",		{ Gv, Ev } },
+  { "cmovl",		{ Gv, Ev } },
+  { "cmovge",		{ Gv, Ev } },
+  { "cmovle",		{ Gv, Ev } },
+  { "cmovg",		{ Gv, Ev } },
+  /* 50 */
+  { "movmskpX",		{ Gdq, XS } },
+  { PREGRP13 },
+  { PREGRP12 },
+  { PREGRP11 },
+  { "andpX",		{ XM, EXx } },
+  { "andnpX",		{ XM, EXx } },
+  { "orpX",		{ XM, EXx } },
+  { "xorpX",		{ XM, EXx } },
+  /* 58 */
+  { PREGRP0 },
+  { PREGRP10 },
+  { PREGRP17 },
+  { PREGRP16 },
+  { PREGRP14 },
+  { PREGRP7 },
+  { PREGRP5 },
+  { PREGRP6 },
+  /* 60 */
+  { PREGRP95 },
+  { PREGRP96 },
+  { PREGRP97 },
+  { "packsswb",		{ MX, EM } },
+  { "pcmpgtb",		{ MX, EM } },
+  { "pcmpgtw",		{ MX, EM } },
+  { "pcmpgtd",		{ MX, EM } },
+  { "packuswb",		{ MX, EM } },
+  /* 68 */
+  { "punpckhbw",	{ MX, EM } },
+  { "punpckhwd",	{ MX, EM } },
+  { "punpckhdq",	{ MX, EM } },
+  { "packssdw",		{ MX, EM } },
+  { PREGRP26 },
+  { PREGRP24 },
+  { "movd",		{ MX, Edq } },
+  { PREGRP19 },
+  /* 70 */
+  { PREGRP22 },
+  { GRP12 },
+  { GRP13 },
+  { GRP14 },
+  { "pcmpeqb",		{ MX, EM } },
+  { "pcmpeqw",		{ MX, EM } },
+  { "pcmpeqd",		{ MX, EM } },
+  { "emms",		{ XX } },
+  /* 78 */
+  { PREGRP34 },
+  { PREGRP35 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { PREGRP28 },
+  { PREGRP29 },
+  { PREGRP23 },
+  { PREGRP20 },
+  /* 80 */
+  { "joH",		{ Jv, XX, cond_jump_flag } },
+  { "jnoH",		{ Jv, XX, cond_jump_flag } },
+  { "jbH",		{ Jv, XX, cond_jump_flag } },
+  { "jaeH",		{ Jv, XX, cond_jump_flag } },
+  { "jeH",		{ Jv, XX, cond_jump_flag } },
+  { "jneH",		{ Jv, XX, cond_jump_flag } },
+  { "jbeH",		{ Jv, XX, cond_jump_flag } },
+  { "jaH",		{ Jv, XX, cond_jump_flag } },
+  /* 88 */
+  { "jsH",		{ Jv, XX, cond_jump_flag } },
+  { "jnsH",		{ Jv, XX, cond_jump_flag } },
+  { "jpH",		{ Jv, XX, cond_jump_flag } },
+  { "jnpH",		{ Jv, XX, cond_jump_flag } },
+  { "jlH",		{ Jv, XX, cond_jump_flag } },
+  { "jgeH",		{ Jv, XX, cond_jump_flag } },
+  { "jleH",		{ Jv, XX, cond_jump_flag } },
+  { "jgH",		{ Jv, XX, cond_jump_flag } },
+  /* 90 */
+  { "seto",		{ Eb } },
+  { "setno",		{ Eb } },
+  { "setb",		{ Eb } },
+  { "setae",		{ Eb } },
+  { "sete",		{ Eb } },
+  { "setne",		{ Eb } },
+  { "setbe",		{ Eb } },
+  { "seta",		{ Eb } },
+  /* 98 */
+  { "sets",		{ Eb } },
+  { "setns",		{ Eb } },
+  { "setp",		{ Eb } },
+  { "setnp",		{ Eb } },
+  { "setl",		{ Eb } },
+  { "setge",		{ Eb } },
+  { "setle",		{ Eb } },
+  { "setg",		{ Eb } },
+  /* a0 */
+  { "pushT",		{ fs } },
+  { "popT",		{ fs } },
+  { "cpuid",		{ XX } },
+  { "btS",		{ Ev, Gv } },
+  { "shldS",		{ Ev, Gv, Ib } },
+  { "shldS",		{ Ev, Gv, CL } },
+  { GRPPADLCK2 },
+  { GRPPADLCK1 },
+  /* a8 */
+  { "pushT",		{ gs } },
+  { "popT",		{ gs } },
+  { "rsm",		{ XX } },
+  { "btsS",		{ Ev, Gv } },
+  { "shrdS",		{ Ev, Gv, Ib } },
+  { "shrdS",		{ Ev, Gv, CL } },
+  { GRP15 },
+  { "imulS",		{ Gv, Ev } },
+  /* b0 */
+  { "cmpxchgB",		{ Eb, Gb } },
+  { "cmpxchgS",		{ Ev, Gv } },
+  { "lssS",		{ Gv, Mp } },
+  { "btrS",		{ Ev, Gv } },
+  { "lfsS",		{ Gv, Mp } },
+  { "lgsS",		{ Gv, Mp } },
+  { "movz{bR|x|bR|x}",	{ Gv, Eb } },
+  { "movz{wR|x|wR|x}",	{ Gv, Ew } }, /* yes, there really is movzww ! */
+  /* b8 */
+  { PREGRP37 },
+  { "ud2b",		{ XX } },
+  { GRP8 },
+  { "btcS",		{ Ev, Gv } },
+  { "bsfS",		{ Gv, Ev } },
+  { PREGRP36 },
+  { "movs{bR|x|bR|x}",	{ Gv, Eb } },
+  { "movs{wR|x|wR|x}",	{ Gv, Ew } }, /* yes, there really is movsww ! */
+  /* c0 */
+  { "xaddB",		{ Eb, Gb } },
+  { "xaddS",		{ Ev, Gv } },
+  { PREGRP1 },
+  { "movntiS",		{ Ev, Gv } },
+  { "pinsrw",		{ MX, Edqw, Ib } },
+  { "pextrw",		{ Gdq, MS, Ib } },
+  { "shufpX",		{ XM, EXx, Ib } },
+  { GRP9 },
+  /* c8 */
+  { "bswap",		{ RMeAX } },
+  { "bswap",		{ RMeCX } },
+  { "bswap",		{ RMeDX } },
+  { "bswap",		{ RMeBX } },
+  { "bswap",		{ RMeSP } },
+  { "bswap",		{ RMeBP } },
+  { "bswap",		{ RMeSI } },
+  { "bswap",		{ RMeDI } },
+  /* d0 */
+  { PREGRP27 },
+  { "psrlw",		{ MX, EM } },
+  { "psrld",		{ MX, EM } },
+  { "psrlq",		{ MX, EM } },
+  { "paddq",		{ MX, EM } },
+  { "pmullw",		{ MX, EM } },
+  { PREGRP21 },
+  { "pmovmskb",		{ Gdq, MS } },
+  /* d8 */
+  { "psubusb",		{ MX, EM } },
+  { "psubusw",		{ MX, EM } },
+  { "pminub",		{ MX, EM } },
+  { "pand",		{ MX, EM } },
+  { "paddusb",		{ MX, EM } },
+  { "paddusw",		{ MX, EM } },
+  { "pmaxub",		{ MX, EM } },
+  { "pandn",		{ MX, EM } },
+  /* e0 */
+  { "pavgb",		{ MX, EM } },
+  { "psraw",		{ MX, EM } },
+  { "psrad",		{ MX, EM } },
+  { "pavgw",		{ MX, EM } },
+  { "pmulhuw",		{ MX, EM } },
+  { "pmulhw",		{ MX, EM } },
+  { PREGRP15 },
+  { PREGRP25 },
+  /* e8 */
+  { "psubsb",		{ MX, EM } },
+  { "psubsw",		{ MX, EM } },
+  { "pminsw",		{ MX, EM } },
+  { "por",		{ MX, EM } },
+  { "paddsb",		{ MX, EM } },
+  { "paddsw",		{ MX, EM } },
+  { "pmaxsw",		{ MX, EM } },
+  { "pxor",		{ MX, EM } },
+  /* f0 */
+  { PREGRP32 },
+  { "psllw",		{ MX, EM } },
+  { "pslld",		{ MX, EM } },
+  { "psllq",		{ MX, EM } },
+  { "pmuludq",		{ MX, EM } },
+  { "pmaddwd",		{ MX, EM } },
+  { "psadbw",		{ MX, EM } },
+  { PREGRP18 },
+  /* f8 */
+  { "psubb",		{ MX, EM } },
+  { "psubw",		{ MX, EM } },
+  { "psubd",		{ MX, EM } },
+  { "psubq",		{ MX, EM } },
+  { "paddb",		{ MX, EM } },
+  { "paddw",		{ MX, EM } },
+  { "paddd",		{ MX, EM } },
+  { "(bad)",		{ XX } },
+};
+
+static const unsigned char onebyte_has_modrm[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */
+  /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */
+  /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */
+  /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
+  /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
+  /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */
+  /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */
+  /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */
+  /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1  /* f0 */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_has_modrm[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */
+  /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */
+  /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
+  /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
+  /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */
+  /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */
+  /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */
+  /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */
+  /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */
+  /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */
+  /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */
+  /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0  /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_uses_DATA_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */
+  /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0  /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */
+  /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, /* bf */
+  /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses DATA prefix.  */
+static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */
+  /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */
+  /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */
+  /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */
+  /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix.  */
+static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses REPZ prefix.  */
+static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses DATA prefix.  */
+static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */
+  /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix.  */
+static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses REPZ prefix.  */
+static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *insn_codep;
+static unsigned char *codep;
+static disassemble_info *the_info;
+static struct
+  {
+    int mod;
+    int reg;
+    int rm;
+  }
+modrm;
+static unsigned char need_modrm;
+
+/* If we are accessing mod/rm/reg without need_modrm set, then the
+   values are stale.  Hitting this abort likely indicates that you
+   need to update onebyte_has_modrm or twobyte_has_modrm.  */
+#define MODRM_CHECK  if (!need_modrm) abort ()
+
+static const char * const *names64;
+static const char * const *names32;
+static const char * const *names16;
+static const char * const *names8;
+static const char * const *names8rex;
+static const char * const *names_seg;
+static const char * const *index16;
+
+static const char * const intel_names64[] = {
+  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
+  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+};
+static const char * const intel_names32[] = {
+  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
+  "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
+};
+static const char * const intel_names16[] = {
+  "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
+  "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
+};
+static const char * const intel_names8[] = {
+  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
+};
+static const char * const intel_names8rex[] = {
+  "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
+  "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
+};
+static const char * const intel_names_seg[] = {
+  "es", "cs", "ss", "ds", "fs", "gs", "?", "?",
+};
+static const char * const intel_index16[] = {
+  "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"
+};
+
+static const char * const att_names64[] = {
+  "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
+  "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
+};
+static const char * const att_names32[] = {
+  "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
+  "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d"
+};
+static const char * const att_names16[] = {
+  "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+  "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w"
+};
+static const char * const att_names8[] = {
+  "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
+};
+static const char * const att_names8rex[] = {
+  "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
+  "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b"
+};
+static const char * const att_names_seg[] = {
+  "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?",
+};
+static const char * const att_index16[] = {
+  "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx"
+};
+
+static const struct dis386 grps[][8] = {
+  /* GRP1a */
+  {
+    { "popU",	{ stackEv } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP1b */
+  {
+    { "addA",	{ Eb, Ib } },
+    { "orA",	{ Eb, Ib } },
+    { "adcA",	{ Eb, Ib } },
+    { "sbbA",	{ Eb, Ib } },
+    { "andA",	{ Eb, Ib } },
+    { "subA",	{ Eb, Ib } },
+    { "xorA",	{ Eb, Ib } },
+    { "cmpA",	{ Eb, Ib } },
+  },
+  /* GRP1S */
+  {
+    { "addQ",	{ Ev, Iv } },
+    { "orQ",	{ Ev, Iv } },
+    { "adcQ",	{ Ev, Iv } },
+    { "sbbQ",	{ Ev, Iv } },
+    { "andQ",	{ Ev, Iv } },
+    { "subQ",	{ Ev, Iv } },
+    { "xorQ",	{ Ev, Iv } },
+    { "cmpQ",	{ Ev, Iv } },
+  },
+  /* GRP1Ss */
+  {
+    { "addQ",	{ Ev, sIb } },
+    { "orQ",	{ Ev, sIb } },
+    { "adcQ",	{ Ev, sIb } },
+    { "sbbQ",	{ Ev, sIb } },
+    { "andQ",	{ Ev, sIb } },
+    { "subQ",	{ Ev, sIb } },
+    { "xorQ",	{ Ev, sIb } },
+    { "cmpQ",	{ Ev, sIb } },
+  },
+  /* GRP2b */
+  {
+    { "rolA",	{ Eb, Ib } },
+    { "rorA",	{ Eb, Ib } },
+    { "rclA",	{ Eb, Ib } },
+    { "rcrA",	{ Eb, Ib } },
+    { "shlA",	{ Eb, Ib } },
+    { "shrA",	{ Eb, Ib } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, Ib } },
+  },
+  /* GRP2S */
+  {
+    { "rolQ",	{ Ev, Ib } },
+    { "rorQ",	{ Ev, Ib } },
+    { "rclQ",	{ Ev, Ib } },
+    { "rcrQ",	{ Ev, Ib } },
+    { "shlQ",	{ Ev, Ib } },
+    { "shrQ",	{ Ev, Ib } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, Ib } },
+  },
+  /* GRP2b_one */
+  {
+    { "rolA",	{ Eb, I1 } },
+    { "rorA",	{ Eb, I1 } },
+    { "rclA",	{ Eb, I1 } },
+    { "rcrA",	{ Eb, I1 } },
+    { "shlA",	{ Eb, I1 } },
+    { "shrA",	{ Eb, I1 } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, I1 } },
+  },
+  /* GRP2S_one */
+  {
+    { "rolQ",	{ Ev, I1 } },
+    { "rorQ",	{ Ev, I1 } },
+    { "rclQ",	{ Ev, I1 } },
+    { "rcrQ",	{ Ev, I1 } },
+    { "shlQ",	{ Ev, I1 } },
+    { "shrQ",	{ Ev, I1 } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, I1 } },
+  },
+  /* GRP2b_cl */
+  {
+    { "rolA",	{ Eb, CL } },
+    { "rorA",	{ Eb, CL } },
+    { "rclA",	{ Eb, CL } },
+    { "rcrA",	{ Eb, CL } },
+    { "shlA",	{ Eb, CL } },
+    { "shrA",	{ Eb, CL } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, CL } },
+  },
+  /* GRP2S_cl */
+  {
+    { "rolQ",	{ Ev, CL } },
+    { "rorQ",	{ Ev, CL } },
+    { "rclQ",	{ Ev, CL } },
+    { "rcrQ",	{ Ev, CL } },
+    { "shlQ",	{ Ev, CL } },
+    { "shrQ",	{ Ev, CL } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, CL } },
+  },
+  /* GRP3b */
+  {
+    { "testA",	{ Eb, Ib } },
+    { "(bad)",	{ Eb } },
+    { "notA",	{ Eb } },
+    { "negA",	{ Eb } },
+    { "mulA",	{ Eb } },	/* Don't print the implicit %al register,  */
+    { "imulA",	{ Eb } },	/* to distinguish these opcodes from other */
+    { "divA",	{ Eb } },	/* mul/imul opcodes.  Do the same for div  */
+    { "idivA",	{ Eb } },	/* and idiv for consistency.		   */
+  },
+  /* GRP3S */
+  {
+    { "testQ",	{ Ev, Iv } },
+    { "(bad)",	{ XX } },
+    { "notQ",	{ Ev } },
+    { "negQ",	{ Ev } },
+    { "mulQ",	{ Ev } },	/* Don't print the implicit register.  */
+    { "imulQ",	{ Ev } },
+    { "divQ",	{ Ev } },
+    { "idivQ",	{ Ev } },
+  },
+  /* GRP4 */
+  {
+    { "incA",	{ Eb } },
+    { "decA",	{ Eb } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP5 */
+  {
+    { "incQ",	{ Ev } },
+    { "decQ",	{ Ev } },
+    { "callT",	{ indirEv } },
+    { "JcallT",	{ indirEp } },
+    { "jmpT",	{ indirEv } },
+    { "JjmpT",	{ indirEp } },
+    { "pushU",	{ stackEv } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP6 */
+  {
+    { "sldtD",	{ Sv } },
+    { "strD",	{ Sv } },
+    { "lldt",	{ Ew } },
+    { "ltr",	{ Ew } },
+    { "verr",	{ Ew } },
+    { "verw",	{ Ew } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP7 */
+  {
+    { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } },
+    { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } },
+    { "lgdt{Q|Q||}",	 { M } },
+    { "lidt{Q|Q||}",	 { { SVME_Fixup, 0 } } },
+    { "smswD",	{ Sv } },
+    { "(bad)",	{ XX } },
+    { "lmsw",	{ Ew } },
+    { "invlpg",	{ { INVLPG_Fixup, w_mode } } },
+  },
+  /* GRP8 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "btQ",	{ Ev, Ib } },
+    { "btsQ",	{ Ev, Ib } },
+    { "btrQ",	{ Ev, Ib } },
+    { "btcQ",	{ Ev, Ib } },
+  },
+  /* GRP9 */
+  {
+    { "(bad)",	{ XX } },
+    { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "",	{ VM } },		/* See OP_VMX.  */
+    { "vmptrst", { Mq } },
+  },
+  /* GRP11_C6 */
+  {
+    { "movA",	{ Eb, Ib } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP11_C7 */
+  {
+    { "movQ",	{ Ev, Iv } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",  { XX } },
+  },
+  /* GRP12 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrlw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psraw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psllw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP13 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrld",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psrad",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "pslld",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+  },
+  /* GRP14 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrlq",	{ MS, Ib } },
+    { "psrldq",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psllq",	{ MS, Ib } },
+    { "pslldq",	{ MS, Ib } },
+  },
+  /* GRP15 */
+  {
+    { "fxsave",		{ Ev } },
+    { "fxrstor",	{ Ev } },
+    { "ldmxcsr",	{ Ev } },
+    { "stmxcsr",	{ Ev } },
+    { "(bad)",		{ XX } },
+    { "lfence",		{ { OP_0fae, 0 } } },
+    { "mfence",		{ { OP_0fae, 0 } } },
+    { "clflush",	{ { OP_0fae, 0 } } },
+  },
+  /* GRP16 */
+  {
+    { "prefetchnta",	{ Ev } },
+    { "prefetcht0",	{ Ev } },
+    { "prefetcht1",	{ Ev } },
+    { "prefetcht2",	{ Ev } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+  },
+  /* GRPAMD */
+  {
+    { "prefetch",	{ Eb } },
+    { "prefetchw",	{ Eb } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+  },
+  /* GRPPADLCK1 */
+  {
+    { "xstore-rng",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ecb",	{ { OP_0f07, 0 } } },
+    { "xcrypt-cbc",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ctr",	{ { OP_0f07, 0 } } },
+    { "xcrypt-cfb",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ofb",	{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+  },
+  /* GRPPADLCK2 */
+  {
+    { "montmul",	{ { OP_0f07, 0 } } },
+    { "xsha1",		{ { OP_0f07, 0 } } },
+    { "xsha256",	{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+  }
+};
+
+static const struct dis386 prefix_user_table[][4] = {
+  /* PREGRP0 */
+  {
+    { "addps", { XM, EXx } },
+    { "addss", { XM, EXd } },
+    { "addpd", { XM, EXx } },
+    { "addsd", { XM, EXq } },
+  },
+  /* PREGRP1 */
+  {
+    { "", { XM, EXx, OPSIMD } },	/* See OP_SIMD_SUFFIX.  */
+    { "", { XM, EXx, OPSIMD } },
+    { "", { XM, EXx, OPSIMD } },
+    { "", { XM, EXx, OPSIMD } },
+  },
+  /* PREGRP2 */
+  {
+    { "cvtpi2ps", { XM, EMC } },
+    { "cvtsi2ssY", { XM, Ev } },
+    { "cvtpi2pd", { XM, EMC } },
+    { "cvtsi2sdY", { XM, Ev } },
+  },
+  /* PREGRP3 */
+  {
+    { "cvtps2pi", { MXC, EXx } },
+    { "cvtss2siY", { Gv, EXx } },
+    { "cvtpd2pi", { MXC, EXx } },
+    { "cvtsd2siY", { Gv, EXx } },
+  },
+  /* PREGRP4 */
+  {
+    { "cvttps2pi", { MXC, EXx } },
+    { "cvttss2siY", { Gv, EXx } },
+    { "cvttpd2pi", { MXC, EXx } },
+    { "cvttsd2siY", { Gv, EXx } },
+  },
+  /* PREGRP5 */
+  {
+    { "divps",	{ XM, EXx } },
+    { "divss",	{ XM, EXx } },
+    { "divpd",	{ XM, EXx } },
+    { "divsd",	{ XM, EXx } },
+  },
+  /* PREGRP6 */
+  {
+    { "maxps",	{ XM, EXx } },
+    { "maxss",	{ XM, EXx } },
+    { "maxpd",	{ XM, EXx } },
+    { "maxsd",	{ XM, EXx } },
+  },
+  /* PREGRP7 */
+  {
+    { "minps",	{ XM, EXx } },
+    { "minss",	{ XM, EXx } },
+    { "minpd",	{ XM, EXx } },
+    { "minsd",	{ XM, EXx } },
+  },
+  /* PREGRP8 */
+  {
+    { "movups",	{ XM, EXx } },
+    { "movss",	{ XM, EXx } },
+    { "movupd",	{ XM, EXx } },
+    { "movsd",	{ XM, EXx } },
+  },
+  /* PREGRP9 */
+  {
+    { "movups",	{ EXx,  XM } },
+    { "movss",	{ EXx,  XM } },
+    { "movupd",	{ EXx,  XM } },
+    { "movsd",	{ EXx,  XM } },
+  },
+  /* PREGRP10 */
+  {
+    { "mulps",	{ XM, EXx } },
+    { "mulss",	{ XM, EXx } },
+    { "mulpd",	{ XM, EXx } },
+    { "mulsd",	{ XM, EXx } },
+  },
+  /* PREGRP11 */
+  {
+    { "rcpps",	{ XM, EXx } },
+    { "rcpss",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP12 */
+  {
+    { "rsqrtps",{ XM, EXx } },
+    { "rsqrtss",{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP13 */
+  {
+    { "sqrtps", { XM, EXx } },
+    { "sqrtss", { XM, EXx } },
+    { "sqrtpd", { XM, EXx } },
+    { "sqrtsd",	{ XM, EXx } },
+  },
+  /* PREGRP14 */
+  {
+    { "subps",	{ XM, EXx } },
+    { "subss",	{ XM, EXx } },
+    { "subpd",	{ XM, EXx } },
+    { "subsd",	{ XM, EXx } },
+  },
+  /* PREGRP15 */
+  {
+    { "(bad)",	{ XM, EXx } },
+    { "cvtdq2pd", { XM, EXq } },
+    { "cvttpd2dq", { XM, EXx } },
+    { "cvtpd2dq", { XM, EXx } },
+  },
+  /* PREGRP16 */
+  {
+    { "cvtdq2ps", { XM, EXx } },
+    { "cvttps2dq", { XM, EXx } },
+    { "cvtps2dq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP17 */
+  {
+    { "cvtps2pd", { XM, EXq } },
+    { "cvtss2sd", { XM, EXx } },
+    { "cvtpd2ps", { XM, EXx } },
+    { "cvtsd2ss", { XM, EXx } },
+  },
+  /* PREGRP18 */
+  {
+    { "maskmovq", { MX, MS } },
+    { "(bad)",	{ XM, EXx } },
+    { "maskmovdqu", { XM, XS } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP19 */
+  {
+    { "movq",	{ MX, EM } },
+    { "movdqu",	{ XM, EXx } },
+    { "movdqa",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP20 */
+  {
+    { "movq",	{ EM, MX } },
+    { "movdqu",	{ EXx,  XM } },
+    { "movdqa",	{ EXx,  XM } },
+    { "(bad)",	{ EXx,  XM } },
+  },
+  /* PREGRP21 */
+  {
+    { "(bad)",	{ EXx,  XM } },
+    { "movq2dq",{ XM, MS } },
+    { "movq",	{ EXx,  XM } },
+    { "movdq2q",{ MX, XS } },
+  },
+  /* PREGRP22 */
+  {
+    { "pshufw",	{ MX, EM, Ib } },
+    { "pshufhw",{ XM, EXx, Ib } },
+    { "pshufd",	{ XM, EXx, Ib } },
+    { "pshuflw",{ XM, EXx, Ib } },
+  },
+  /* PREGRP23 */
+  {
+    { "movd",	{ Edq, MX } },
+    { "movq",	{ XM, EXx } },
+    { "movd",	{ Edq, XM } },
+    { "(bad)",	{ Ed, XM } },
+  },
+  /* PREGRP24 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "punpckhqdq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP25 */
+  {
+    { "movntq",	{ EM, MX } },
+    { "(bad)",	{ EM, XM } },
+    { "movntdq",{ EM, XM } },
+    { "(bad)",	{ EM, XM } },
+  },
+  /* PREGRP26 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "punpcklqdq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP27 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "addsubpd", { XM, EXx } },
+    { "addsubps", { XM, EXx } },
+  },
+  /* PREGRP28 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "haddpd",	{ XM, EXx } },
+    { "haddps",	{ XM, EXx } },
+  },
+  /* PREGRP29 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "hsubpd",	{ XM, EXx } },
+    { "hsubps",	{ XM, EXx } },
+  },
+  /* PREGRP30 */
+  {
+    { "movlpX",	{ XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */
+    { "movsldup", { XM, EXx } },
+    { "movlpd",	{ XM, EXq } },
+    { "movddup", { XM, EXq } },
+  },
+  /* PREGRP31 */
+  {
+    { "movhpX",	{ XM, EXq, { SIMD_Fixup, 'l' } } },
+    { "movshdup", { XM, EXx } },
+    { "movhpd",	{ XM, EXq } },
+    { "(bad)",	{ XM, EXq } },
+  },
+  /* PREGRP32 */
+  {
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "lddqu",	{ XM, M } },
+  },
+  /* PREGRP33 */
+  {
+    {"movntps", { Ev, XM } },
+    {"movntss", { Ev, XM } },
+    {"movntpd", { Ev, XM } },
+    {"movntsd", { Ev, XM } },
+  },
+
+  /* PREGRP34 */
+  {
+    {"vmread",	{ Em, Gm } },
+    {"(bad)",	{ XX } },
+    {"extrq",	{ XS, Ib, Ib } },
+    {"insertq",	{ XM, XS, Ib, Ib } },
+  },
+
+ /* PREGRP35 */
+  {
+    {"vmwrite",	{ Gm, Em } },
+    {"(bad)",	{ XX } },
+    {"extrq",	{ XM, XS } },
+    {"insertq",	{ XM, XS } },
+  },
+
+  /* PREGRP36 */
+  {
+    { "bsrS",	{ Gv, Ev } },
+    { "lzcntS",	{ Gv, Ev } },
+    { "bsrS",	{ Gv, Ev } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP37 */
+  {
+    { "(bad)", { XX } },
+    { "popcntS", { Gv, Ev } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  },
+
+  /* PREGRP38 */
+  {
+    { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+    { "pause", { XX } },
+    { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+    { "(bad)", { XX } },
+  },
+
+  /* PREGRP39 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pblendvb", {XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP40 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendvps", {XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP41 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendvpd", { XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP42 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "ptest",  { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP43 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP44 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP45 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP46 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxwd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP47 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxwq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP48 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxdq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP49 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmuldq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP50 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpeqq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP51 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "movntdqa", { XM, EM } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP52 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "packusdw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP53 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP54 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP55 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP56 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxwd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP57 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxwq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP58 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxdq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP59 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminsb",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP60 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminsd",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP61 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminuw",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP62 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminud",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP63 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxsb",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP64 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxsd",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP65 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxuw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP66 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxud", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP67 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmulld", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP68 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "phminposuw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP69 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP70 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundpd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP71 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundss", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP72 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundsd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP73 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP74 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendpd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP75 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pblendw", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP76 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrb",	{ Edqb, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP77 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrw",	{ Edqw, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP78 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrK",	{ Edq, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP79 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "extractps", { Edqd, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP80 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pinsrb",	{ XM, Edqb, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP81 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "insertps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP82 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pinsrK",	{ XM, Edq, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP83 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "dpps",	{ XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP84 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "dppd",	{ XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP85 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "mpsadbw", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP86 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpgtq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP87 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "crc32",	{ Gdq, { CRC32_Fixup, b_mode } } },
+  },
+
+  /* PREGRP88 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "crc32",	{ Gdq, { CRC32_Fixup, v_mode } } },
+  },
+
+  /* PREGRP89 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpestrm", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP90 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpestri", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP91 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpistrm", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP92 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpistri", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP93 */
+  {
+    { "ucomiss",{ XM, EXd } },
+    { "(bad)",	{ XX } },
+    { "ucomisd",{ XM, EXq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP94 */
+  {
+    { "comiss",	{ XM, EXd } },
+    { "(bad)",	{ XX } },
+    { "comisd",	{ XM, EXq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP95 */
+  {
+    { "punpcklbw",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpcklbw",{ MX, EMq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP96 */
+  {
+    { "punpcklwd",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpcklwd",{ MX, EMq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP97 */
+  {
+    { "punpckldq",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpckldq",{ MX, EMq } },
+    { "(bad)",	{ XX } },
+  },
+};
+
+static const struct dis386 x86_64_table[][2] = {
+  {
+    { "pusha{P|}", { XX } },
+    { "(bad)", { XX } },
+  },
+  {
+    { "popa{P|}", { XX } },
+    { "(bad)", { XX } },
+  },
+  {
+    { "bound{S|}", { Gv, Ma } },
+    { "(bad)", { XX } },
+  },
+  {
+    { "arpl", { Ew, Gw } },
+    { "movs{||lq|xd}", { Gv, Ed } },
+  },
+};
+
+static const struct dis386 three_byte_table[][256] = {
+  /* THREE_BYTE_0 */
+  {
+    /* 00 */
+    { "pshufb", { MX, EM } },
+    { "phaddw", { MX, EM } },
+    { "phaddd",	{ MX, EM } },
+    { "phaddsw", { MX, EM } },
+    { "pmaddubsw", { MX, EM } },
+    { "phsubw", { MX, EM } },
+    { "phsubd", { MX, EM } },
+    { "phsubsw", { MX, EM } },
+    /* 08 */
+    { "psignb", { MX, EM } },
+    { "psignw", { MX, EM } },
+    { "psignd", { MX, EM } },
+    { "pmulhrsw", { MX, EM } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 10 */
+    { PREGRP39 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { PREGRP40 },
+    { PREGRP41 },
+    { "(bad)", { XX } },
+    { PREGRP42 },
+    /* 18 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "pabsb", { MX, EM } },
+    { "pabsw", { MX, EM } },
+    { "pabsd", { MX, EM } },
+    { "(bad)", { XX } },
+    /* 20 */
+    { PREGRP43 },
+    { PREGRP44 },
+    { PREGRP45 },
+    { PREGRP46 },
+    { PREGRP47 },
+    { PREGRP48 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 28 */
+    { PREGRP49 },
+    { PREGRP50 },
+    { PREGRP51 },
+    { PREGRP52 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 30 */
+    { PREGRP53 },
+    { PREGRP54 },
+    { PREGRP55 },
+    { PREGRP56 },
+    { PREGRP57 },
+    { PREGRP58 },
+    { "(bad)", { XX } },
+    { PREGRP86 },
+    /* 38 */
+    { PREGRP59 },
+    { PREGRP60 },
+    { PREGRP61 },
+    { PREGRP62 },
+    { PREGRP63 },
+    { PREGRP64 },
+    { PREGRP65 },
+    { PREGRP66 },
+    /* 40 */
+    { PREGRP67 },
+    { PREGRP68 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 48 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 50 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 58 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 60 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 68 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 70 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 78 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 80 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 88 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 90 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 98 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f0 */
+    { PREGRP87 },
+    { PREGRP88 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  },
+  /* THREE_BYTE_1 */
+  {
+    /* 00 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 08 */
+    { PREGRP69 },
+    { PREGRP70 },
+    { PREGRP71 },
+    { PREGRP72 },
+    { PREGRP73 },
+    { PREGRP74 },
+    { PREGRP75 },
+    { "palignr", { MX, EM, Ib } },
+    /* 10 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { PREGRP76 },
+    { PREGRP77 },
+    { PREGRP78 },
+    { PREGRP79 },
+    /* 18 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 20 */
+    { PREGRP80 },
+    { PREGRP81 },
+    { PREGRP82 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 28 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 30 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 38 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 40 */
+    { PREGRP83 },
+    { PREGRP84 },
+    { PREGRP85 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 48 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 50 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 58 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 60 */
+    { PREGRP89 },
+    { PREGRP90 },
+    { PREGRP91 },
+    { PREGRP92 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 68 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 70 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 78 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 80 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 88 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 90 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 98 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  }
+};
+
+#define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>")
+
+static void
+ckprefix (void)
+{
+  int newrex;
+  rex = 0;
+  prefixes = 0;
+  used_prefixes = 0;
+  rex_used = 0;
+  while (1)
+    {
+      fetch_data(the_info, codep + 1);
+      newrex = 0;
+      switch (*codep)
+	{
+	/* REX prefixes family.  */
+	case 0x40:
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x44:
+	case 0x45:
+	case 0x46:
+	case 0x47:
+	case 0x48:
+	case 0x49:
+	case 0x4a:
+	case 0x4b:
+	case 0x4c:
+	case 0x4d:
+	case 0x4e:
+	case 0x4f:
+	    if (address_mode == mode_64bit)
+	      newrex = *codep;
+	    else
+	      return;
+	  break;
+	case 0xf3:
+	  prefixes |= PREFIX_REPZ;
+	  break;
+	case 0xf2:
+	  prefixes |= PREFIX_REPNZ;
+	  break;
+	case 0xf0:
+	  prefixes |= PREFIX_LOCK;
+	  break;
+	case 0x2e:
+	  prefixes |= PREFIX_CS;
+	  break;
+	case 0x36:
+	  prefixes |= PREFIX_SS;
+	  break;
+	case 0x3e:
+	  prefixes |= PREFIX_DS;
+	  break;
+	case 0x26:
+	  prefixes |= PREFIX_ES;
+	  break;
+	case 0x64:
+	  prefixes |= PREFIX_FS;
+	  break;
+	case 0x65:
+	  prefixes |= PREFIX_GS;
+	  break;
+	case 0x66:
+	  prefixes |= PREFIX_DATA;
+	  break;
+	case 0x67:
+	  prefixes |= PREFIX_ADDR;
+	  break;
+	case FWAIT_OPCODE:
+	  /* fwait is really an instruction.  If there are prefixes
+	     before the fwait, they belong to the fwait, *not* to the
+	     following instruction.  */
+	  if (prefixes || rex)
+	    {
+	      prefixes |= PREFIX_FWAIT;
+	      codep++;
+	      return;
+	    }
+	  prefixes = PREFIX_FWAIT;
+	  break;
+	default:
+	  return;
+	}
+      /* Rex is ignored when followed by another prefix.  */
+      if (rex)
+	{
+	  rex_used = rex;
+	  return;
+	}
+      rex = newrex;
+      codep++;
+    }
+}
+
+/* Return the name of the prefix byte PREF, or NULL if PREF is not a
+   prefix byte.  */
+
+static const char *
+prefix_name (int pref, int sizeflag)
+{
+  static const char * const rexes [16] =
+    {
+      "rex",		/* 0x40 */
+      "rex.B",		/* 0x41 */
+      "rex.X",		/* 0x42 */
+      "rex.XB",		/* 0x43 */
+      "rex.R",		/* 0x44 */
+      "rex.RB",		/* 0x45 */
+      "rex.RX",		/* 0x46 */
+      "rex.RXB",	/* 0x47 */
+      "rex.W",		/* 0x48 */
+      "rex.WB",		/* 0x49 */
+      "rex.WX",		/* 0x4a */
+      "rex.WXB",	/* 0x4b */
+      "rex.WR",		/* 0x4c */
+      "rex.WRB",	/* 0x4d */
+      "rex.WRX",	/* 0x4e */
+      "rex.WRXB",	/* 0x4f */
+    };
+
+  switch (pref)
+    {
+    /* REX prefixes family.  */
+    case 0x40:
+    case 0x41:
+    case 0x42:
+    case 0x43:
+    case 0x44:
+    case 0x45:
+    case 0x46:
+    case 0x47:
+    case 0x48:
+    case 0x49:
+    case 0x4a:
+    case 0x4b:
+    case 0x4c:
+    case 0x4d:
+    case 0x4e:
+    case 0x4f:
+      return rexes [pref - 0x40];
+    case 0xf3:
+      return "repz";
+    case 0xf2:
+      return "repnz";
+    case 0xf0:
+      return "lock";
+    case 0x2e:
+      return "cs";
+    case 0x36:
+      return "ss";
+    case 0x3e:
+      return "ds";
+    case 0x26:
+      return "es";
+    case 0x64:
+      return "fs";
+    case 0x65:
+      return "gs";
+    case 0x66:
+      return (sizeflag & DFLAG) ? "data16" : "data32";
+    case 0x67:
+      if (address_mode == mode_64bit)
+	return (sizeflag & AFLAG) ? "addr32" : "addr64";
+      else
+	return (sizeflag & AFLAG) ? "addr16" : "addr32";
+    case FWAIT_OPCODE:
+      return "fwait";
+    default:
+      return NULL;
+    }
+}
+
+static char op_out[MAX_OPERANDS][100];
+static int op_ad, op_index[MAX_OPERANDS];
+static int two_source_ops;
+static bfd_vma op_address[MAX_OPERANDS];
+static bfd_vma op_riprel[MAX_OPERANDS];
+static bfd_vma start_pc;
+
+/*
+ *   On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ *   (see topic "Redundant prefixes" in the "Differences from 8086"
+ *   section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ *   be used to print the target address if this is a relative jump or call
+ * The function returns the length of this instruction in bytes.
+ */
+
+static char intel_syntax;
+static char open_char;
+static char close_char;
+static char separator_char;
+static char scale_char;
+
+int
+print_insn_i386 (bfd_vma pc, disassemble_info *info)
+{
+  intel_syntax = -1;
+
+  return print_insn (pc, info);
+}
+
+static int
+print_insn (bfd_vma pc, disassemble_info *info)
+{
+  const struct dis386 *dp;
+  int i;
+  char *op_txt[MAX_OPERANDS];
+  int needcomma;
+  unsigned char uses_DATA_prefix, uses_LOCK_prefix;
+  unsigned char uses_REPNZ_prefix, uses_REPZ_prefix;
+  int sizeflag;
+  const char *p;
+  struct dis_private priv;
+  unsigned char op;
+
+  if (info->mach == bfd_mach_x86_64_intel_syntax
+      || info->mach == bfd_mach_x86_64)
+    address_mode = mode_64bit;
+  else
+    address_mode = mode_32bit;
+
+  if (intel_syntax == (char) -1)
+    intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax
+		    || info->mach == bfd_mach_x86_64_intel_syntax);
+
+  if (info->mach == bfd_mach_i386_i386
+      || info->mach == bfd_mach_x86_64
+      || info->mach == bfd_mach_i386_i386_intel_syntax
+      || info->mach == bfd_mach_x86_64_intel_syntax)
+    priv.orig_sizeflag = AFLAG | DFLAG;
+  else if (info->mach == bfd_mach_i386_i8086)
+    priv.orig_sizeflag = 0;
+  else
+    abort ();
+
+  for (p = info->disassembler_options; p != NULL; )
+    {
+      if (strncmp (p, "x86-64", 6) == 0)
+	{
+	  address_mode = mode_64bit;
+	  priv.orig_sizeflag = AFLAG | DFLAG;
+	}
+      else if (strncmp (p, "i386", 4) == 0)
+	{
+	  address_mode = mode_32bit;
+	  priv.orig_sizeflag = AFLAG | DFLAG;
+	}
+      else if (strncmp (p, "i8086", 5) == 0)
+	{
+	  address_mode = mode_16bit;
+	  priv.orig_sizeflag = 0;
+	}
+      else if (strncmp (p, "intel", 5) == 0)
+	{
+	  intel_syntax = 1;
+	}
+      else if (strncmp (p, "att", 3) == 0)
+	{
+	  intel_syntax = 0;
+	}
+      else if (strncmp (p, "addr", 4) == 0)
+	{
+	  if (address_mode == mode_64bit)
+	    {
+	      if (p[4] == '3' && p[5] == '2')
+		priv.orig_sizeflag &= ~AFLAG;
+	      else if (p[4] == '6' && p[5] == '4')
+		priv.orig_sizeflag |= AFLAG;
+	    }
+	  else
+	    {
+	      if (p[4] == '1' && p[5] == '6')
+		priv.orig_sizeflag &= ~AFLAG;
+	      else if (p[4] == '3' && p[5] == '2')
+		priv.orig_sizeflag |= AFLAG;
+	    }
+	}
+      else if (strncmp (p, "data", 4) == 0)
+	{
+	  if (p[4] == '1' && p[5] == '6')
+	    priv.orig_sizeflag &= ~DFLAG;
+	  else if (p[4] == '3' && p[5] == '2')
+	    priv.orig_sizeflag |= DFLAG;
+	}
+      else if (strncmp (p, "suffix", 6) == 0)
+	priv.orig_sizeflag |= SUFFIX_ALWAYS;
+
+      p = strchr (p, ',');
+      if (p != NULL)
+	p++;
+    }
+
+  if (intel_syntax)
+    {
+      names64 = intel_names64;
+      names32 = intel_names32;
+      names16 = intel_names16;
+      names8 = intel_names8;
+      names8rex = intel_names8rex;
+      names_seg = intel_names_seg;
+      index16 = intel_index16;
+      open_char = '[';
+      close_char = ']';
+      separator_char = '+';
+      scale_char = '*';
+    }
+  else
+    {
+      names64 = att_names64;
+      names32 = att_names32;
+      names16 = att_names16;
+      names8 = att_names8;
+      names8rex = att_names8rex;
+      names_seg = att_names_seg;
+      index16 = att_index16;
+      open_char = '(';
+      close_char =  ')';
+      separator_char = ',';
+      scale_char = ',';
+    }
+
+  /* The output looks better if we put 7 bytes on a line, since that
+     puts most long word instructions on a single line.  */
+  info->bytes_per_line = 7;
+
+  info->private_data = &priv;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = pc;
+
+  obuf[0] = 0;
+  for (i = 0; i < MAX_OPERANDS; ++i)
+    {
+      op_out[i][0] = 0;
+      op_index[i] = -1;
+    }
+
+  the_info = info;
+  start_pc = pc;
+  start_codep = priv.the_buffer;
+  codep = priv.the_buffer;
+
+  if (setjmp (priv.bailout) != 0)
+    {
+      const char *name;
+
+      /* Getting here means we tried for data but didn't get it.  That
+	 means we have an incomplete instruction of some sort.  Just
+	 print the first byte as a prefix or a .byte pseudo-op.  */
+      if (codep > priv.the_buffer)
+	{
+	  name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
+	  if (name != NULL)
+	    (*info->fprintf_func) (info->stream, "%s", name);
+	  else
+	    {
+	      /* Just print the first byte as a .byte instruction.  */
+	      (*info->fprintf_func) (info->stream, ".byte 0x%x",
+				     (unsigned int) priv.the_buffer[0]);
+	    }
+
+	  return 1;
+	}
+
+      return -1;
+    }
+
+  obufp = obuf;
+  ckprefix ();
+
+  insn_codep = codep;
+  sizeflag = priv.orig_sizeflag;
+
+  fetch_data(info, codep + 1);
+  two_source_ops = (*codep == 0x62) || (*codep == 0xc8);
+
+  if (((prefixes & PREFIX_FWAIT)
+       && ((*codep < 0xd8) || (*codep > 0xdf)))
+      || (rex && rex_used))
+    {
+      const char *name;
+
+      /* fwait not followed by floating point instruction, or rex followed
+	 by other prefixes.  Print the first prefix.  */
+      name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
+      if (name == NULL)
+	name = INTERNAL_DISASSEMBLER_ERROR;
+      (*info->fprintf_func) (info->stream, "%s", name);
+      return 1;
+    }
+
+  op = 0;
+  if (*codep == 0x0f)
+    {
+      unsigned char threebyte;
+      fetch_data(info, codep + 2);
+      threebyte = *++codep;
+      dp = &dis386_twobyte[threebyte];
+      need_modrm = twobyte_has_modrm[*codep];
+      uses_DATA_prefix = twobyte_uses_DATA_prefix[*codep];
+      uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[*codep];
+      uses_REPZ_prefix = twobyte_uses_REPZ_prefix[*codep];
+      uses_LOCK_prefix = (*codep & ~0x02) == 0x20;
+      codep++;
+      if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
+	{
+          fetch_data(info, codep + 2);
+	  op = *codep++;
+	  switch (threebyte)
+	    {
+	    case 0x38:
+	      uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op];
+	      uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op];
+	      uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op];
+	      break;
+	    case 0x3a:
+	      uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op];
+	      uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op];
+	      uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op];
+	      break;
+	    default:
+	      break;
+	    }
+	}
+    }
+  else
+    {
+      dp = &dis386[*codep];
+      need_modrm = onebyte_has_modrm[*codep];
+      uses_DATA_prefix = 0;
+      uses_REPNZ_prefix = 0;
+      /* pause is 0xf3 0x90.  */
+      uses_REPZ_prefix = *codep == 0x90;
+      uses_LOCK_prefix = 0;
+      codep++;
+    }
+
+  if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ))
+    {
+      oappend ("repz ");
+      used_prefixes |= PREFIX_REPZ;
+    }
+  if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ))
+    {
+      oappend ("repnz ");
+      used_prefixes |= PREFIX_REPNZ;
+    }
+
+  if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK))
+    {
+      oappend ("lock ");
+      used_prefixes |= PREFIX_LOCK;
+    }
+
+  if (prefixes & PREFIX_ADDR)
+    {
+      sizeflag ^= AFLAG;
+      if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax)
+	{
+	  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
+	    oappend ("addr32 ");
+	  else
+	    oappend ("addr16 ");
+	  used_prefixes |= PREFIX_ADDR;
+	}
+    }
+
+  if (!uses_DATA_prefix && (prefixes & PREFIX_DATA))
+    {
+      sizeflag ^= DFLAG;
+      if (dp->op[2].bytemode == cond_jump_mode
+	  && dp->op[0].bytemode == v_mode
+	  && !intel_syntax)
+	{
+	  if (sizeflag & DFLAG)
+	    oappend ("data32 ");
+	  else
+	    oappend ("data16 ");
+	  used_prefixes |= PREFIX_DATA;
+	}
+    }
+
+  if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
+    {
+      dp = &three_byte_table[dp->op[1].bytemode][op];
+      modrm.mod = (*codep >> 6) & 3;
+      modrm.reg = (*codep >> 3) & 7;
+      modrm.rm = *codep & 7;
+    }
+  else if (need_modrm)
+    {
+      fetch_data(info, codep + 1);
+      modrm.mod = (*codep >> 6) & 3;
+      modrm.reg = (*codep >> 3) & 7;
+      modrm.rm = *codep & 7;
+    }
+
+  if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE)
+    {
+      dofloat (sizeflag);
+    }
+  else
+    {
+      int index;
+      if (dp->name == NULL)
+	{
+	  switch (dp->op[0].bytemode)
+	    {
+	    case USE_GROUPS:
+	      dp = &grps[dp->op[1].bytemode][modrm.reg];
+	      break;
+
+	    case USE_PREFIX_USER_TABLE:
+	      index = 0;
+	      used_prefixes |= (prefixes & PREFIX_REPZ);
+	      if (prefixes & PREFIX_REPZ)
+		index = 1;
+	      else
+		{
+		  /* We should check PREFIX_REPNZ and PREFIX_REPZ
+		     before PREFIX_DATA.  */
+		  used_prefixes |= (prefixes & PREFIX_REPNZ);
+		  if (prefixes & PREFIX_REPNZ)
+		    index = 3;
+		  else
+		    {
+		      used_prefixes |= (prefixes & PREFIX_DATA);
+		      if (prefixes & PREFIX_DATA)
+			index = 2;
+		    }
+		}
+	      dp = &prefix_user_table[dp->op[1].bytemode][index];
+	      break;
+
+	    case X86_64_SPECIAL:
+	      index = address_mode == mode_64bit ? 1 : 0;
+	      dp = &x86_64_table[dp->op[1].bytemode][index];
+	      break;
+
+	    default:
+	      oappend (INTERNAL_DISASSEMBLER_ERROR);
+	      break;
+	    }
+	}
+
+      if (putop (dp->name, sizeflag) == 0)
+        {
+	  for (i = 0; i < MAX_OPERANDS; ++i)
+	    {
+	      obufp = op_out[i];
+	      op_ad = MAX_OPERANDS - 1 - i;
+	      if (dp->op[i].rtn)
+		(*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag);
+	    }
+	}
+    }
+
+  /* See if any prefixes were not used.  If so, print the first one
+     separately.  If we don't do this, we'll wind up printing an
+     instruction stream which does not precisely correspond to the
+     bytes we are disassembling.  */
+  if ((prefixes & ~used_prefixes) != 0)
+    {
+      const char *name;
+
+      name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
+      if (name == NULL)
+	name = INTERNAL_DISASSEMBLER_ERROR;
+      (*info->fprintf_func) (info->stream, "%s", name);
+      return 1;
+    }
+  if (rex & ~rex_used)
+    {
+      const char *name;
+      name = prefix_name (rex | 0x40, priv.orig_sizeflag);
+      if (name == NULL)
+	name = INTERNAL_DISASSEMBLER_ERROR;
+      (*info->fprintf_func) (info->stream, "%s ", name);
+    }
+
+  obufp = obuf + strlen (obuf);
+  for (i = strlen (obuf); i < 6; i++)
+    oappend (" ");
+  oappend (" ");
+  (*info->fprintf_func) (info->stream, "%s", obuf);
+
+  /* The enter and bound instructions are printed with operands in the same
+     order as the intel book; everything else is printed in reverse order.  */
+  if (intel_syntax || two_source_ops)
+    {
+      bfd_vma riprel;
+
+      for (i = 0; i < MAX_OPERANDS; ++i)
+        op_txt[i] = op_out[i];
+
+      for (i = 0; i < (MAX_OPERANDS >> 1); ++i)
+	{
+          op_ad = op_index[i];
+          op_index[i] = op_index[MAX_OPERANDS - 1 - i];
+          op_index[MAX_OPERANDS - 1 - i] = op_ad;
+	  riprel = op_riprel[i];
+	  op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i];
+	  op_riprel[MAX_OPERANDS - 1 - i] = riprel;
+	}
+    }
+  else
+    {
+      for (i = 0; i < MAX_OPERANDS; ++i)
+        op_txt[MAX_OPERANDS - 1 - i] = op_out[i];
+    }
+
+  needcomma = 0;
+  for (i = 0; i < MAX_OPERANDS; ++i)
+    if (*op_txt[i])
+      {
+	if (needcomma)
+	  (*info->fprintf_func) (info->stream, ",");
+	if (op_index[i] != -1 && !op_riprel[i])
+	  (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info);
+	else
+	  (*info->fprintf_func) (info->stream, "%s", op_txt[i]);
+	needcomma = 1;
+      }
+
+  for (i = 0; i < MAX_OPERANDS; i++)
+    if (op_index[i] != -1 && op_riprel[i])
+      {
+	(*info->fprintf_func) (info->stream, "        # ");
+	(*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep
+						+ op_address[op_index[i]]), info);
+	break;
+      }
+  return codep - priv.the_buffer;
+}
+
+static const char *float_mem[] = {
+  /* d8 */
+  "fadd{s||s|}",
+  "fmul{s||s|}",
+  "fcom{s||s|}",
+  "fcomp{s||s|}",
+  "fsub{s||s|}",
+  "fsubr{s||s|}",
+  "fdiv{s||s|}",
+  "fdivr{s||s|}",
+  /* d9 */
+  "fld{s||s|}",
+  "(bad)",
+  "fst{s||s|}",
+  "fstp{s||s|}",
+  "fldenvIC",
+  "fldcw",
+  "fNstenvIC",
+  "fNstcw",
+  /* da */
+  "fiadd{l||l|}",
+  "fimul{l||l|}",
+  "ficom{l||l|}",
+  "ficomp{l||l|}",
+  "fisub{l||l|}",
+  "fisubr{l||l|}",
+  "fidiv{l||l|}",
+  "fidivr{l||l|}",
+  /* db */
+  "fild{l||l|}",
+  "fisttp{l||l|}",
+  "fist{l||l|}",
+  "fistp{l||l|}",
+  "(bad)",
+  "fld{t||t|}",
+  "(bad)",
+  "fstp{t||t|}",
+  /* dc */
+  "fadd{l||l|}",
+  "fmul{l||l|}",
+  "fcom{l||l|}",
+  "fcomp{l||l|}",
+  "fsub{l||l|}",
+  "fsubr{l||l|}",
+  "fdiv{l||l|}",
+  "fdivr{l||l|}",
+  /* dd */
+  "fld{l||l|}",
+  "fisttp{ll||ll|}",
+  "fst{l||l|}",
+  "fstp{l||l|}",
+  "frstorIC",
+  "(bad)",
+  "fNsaveIC",
+  "fNstsw",
+  /* de */
+  "fiadd",
+  "fimul",
+  "ficom",
+  "ficomp",
+  "fisub",
+  "fisubr",
+  "fidiv",
+  "fidivr",
+  /* df */
+  "fild",
+  "fisttp",
+  "fist",
+  "fistp",
+  "fbld",
+  "fild{ll||ll|}",
+  "fbstp",
+  "fistp{ll||ll|}",
+};
+
+static const unsigned char float_mem_mode[] = {
+  /* d8 */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  /* d9 */
+  d_mode,
+  0,
+  d_mode,
+  d_mode,
+  0,
+  w_mode,
+  0,
+  w_mode,
+  /* da */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  /* db */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  0,
+  t_mode,
+  0,
+  t_mode,
+  /* dc */
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  /* dd */
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  0,
+  0,
+  0,
+  w_mode,
+  /* de */
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  /* df */
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  t_mode,
+  q_mode,
+  t_mode,
+  q_mode
+};
+
+#define ST { OP_ST, 0 }
+#define STi { OP_STi, 0 }
+
+#define FGRPd9_2 NULL, { { NULL, 0 } }
+#define FGRPd9_4 NULL, { { NULL, 1 } }
+#define FGRPd9_5 NULL, { { NULL, 2 } }
+#define FGRPd9_6 NULL, { { NULL, 3 } }
+#define FGRPd9_7 NULL, { { NULL, 4 } }
+#define FGRPda_5 NULL, { { NULL, 5 } }
+#define FGRPdb_4 NULL, { { NULL, 6 } }
+#define FGRPde_3 NULL, { { NULL, 7 } }
+#define FGRPdf_4 NULL, { { NULL, 8 } }
+
+static const struct dis386 float_reg[][8] = {
+  /* d8 */
+  {
+    { "fadd",	{ ST, STi } },
+    { "fmul",	{ ST, STi } },
+    { "fcom",	{ STi } },
+    { "fcomp",	{ STi } },
+    { "fsub",	{ ST, STi } },
+    { "fsubr",	{ ST, STi } },
+    { "fdiv",	{ ST, STi } },
+    { "fdivr",	{ ST, STi } },
+  },
+  /* d9 */
+  {
+    { "fld",	{ STi } },
+    { "fxch",	{ STi } },
+    { FGRPd9_2 },
+    { "(bad)",	{ XX } },
+    { FGRPd9_4 },
+    { FGRPd9_5 },
+    { FGRPd9_6 },
+    { FGRPd9_7 },
+  },
+  /* da */
+  {
+    { "fcmovb",	{ ST, STi } },
+    { "fcmove",	{ ST, STi } },
+    { "fcmovbe",{ ST, STi } },
+    { "fcmovu",	{ ST, STi } },
+    { "(bad)",	{ XX } },
+    { FGRPda_5 },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* db */
+  {
+    { "fcmovnb",{ ST, STi } },
+    { "fcmovne",{ ST, STi } },
+    { "fcmovnbe",{ ST, STi } },
+    { "fcmovnu",{ ST, STi } },
+    { FGRPdb_4 },
+    { "fucomi",	{ ST, STi } },
+    { "fcomi",	{ ST, STi } },
+    { "(bad)",	{ XX } },
+  },
+  /* dc */
+  {
+    { "fadd",	{ STi, ST } },
+    { "fmul",	{ STi, ST } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+#if SYSV386_COMPAT
+    { "fsub",	{ STi, ST } },
+    { "fsubr",	{ STi, ST } },
+    { "fdiv",	{ STi, ST } },
+    { "fdivr",	{ STi, ST } },
+#else
+    { "fsubr",	{ STi, ST } },
+    { "fsub",	{ STi, ST } },
+    { "fdivr",	{ STi, ST } },
+    { "fdiv",	{ STi, ST } },
+#endif
+  },
+  /* dd */
+  {
+    { "ffree",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "fst",	{ STi } },
+    { "fstp",	{ STi } },
+    { "fucom",	{ STi } },
+    { "fucomp",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
+  /* de */
+  {
+    { "faddp",	{ STi, ST } },
+    { "fmulp",	{ STi, ST } },
+    { "(bad)",	{ XX } },
+    { FGRPde_3 },
+#if SYSV386_COMPAT
+    { "fsubp",	{ STi, ST } },
+    { "fsubrp",	{ STi, ST } },
+    { "fdivp",	{ STi, ST } },
+    { "fdivrp",	{ STi, ST } },
+#else
+    { "fsubrp",	{ STi, ST } },
+    { "fsubp",	{ STi, ST } },
+    { "fdivrp",	{ STi, ST } },
+    { "fdivp",	{ STi, ST } },
+#endif
+  },
+  /* df */
+  {
+    { "ffreep",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { FGRPdf_4 },
+    { "fucomip", { ST, STi } },
+    { "fcomip", { ST, STi } },
+    { "(bad)",	{ XX } },
+  },
+};
+
+static const char *fgrps[][8] = {
+  /* d9_2  0 */
+  {
+    "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* d9_4  1 */
+  {
+    "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+  },
+
+  /* d9_5  2 */
+  {
+    "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+  },
+
+  /* d9_6  3 */
+  {
+    "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+  },
+
+  /* d9_7  4 */
+  {
+    "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+  },
+
+  /* da_5  5 */
+  {
+    "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* db_4  6 */
+  {
+    "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+    "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+  },
+
+  /* de_3  7 */
+  {
+    "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+
+  /* df_4  8 */
+  {
+    "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+  },
+};
+
+static void
+dofloat (int sizeflag)
+{
+  const struct dis386 *dp;
+  unsigned char floatop;
+
+  floatop = codep[-1];
+
+  if (modrm.mod != 3)
+    {
+      int fp_indx = (floatop - 0xd8) * 8 + modrm.reg;
+
+      putop (float_mem[fp_indx], sizeflag);
+      obufp = op_out[0];
+      op_ad = 2;
+      OP_E (float_mem_mode[fp_indx], sizeflag);
+      return;
+    }
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+
+  dp = &float_reg[floatop - 0xd8][modrm.reg];
+  if (dp->name == NULL)
+    {
+      putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag);
+
+      /* Instruction fnstsw is only one with strange arg.  */
+      if (floatop == 0xdf && codep[-1] == 0xe0)
+        pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]);
+    }
+  else
+    {
+      putop (dp->name, sizeflag);
+
+      obufp = op_out[0];
+      op_ad = 2;
+      if (dp->op[0].rtn)
+	(*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag);
+
+      obufp = op_out[1];
+      op_ad = 1;
+      if (dp->op[1].rtn)
+	(*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag);
+    }
+}
+
+static void
+OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  oappend ("%st" + intel_syntax);
+}
+
+static void
+OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm);
+  oappend (scratchbuf + intel_syntax);
+}
+
+/* Capital letters in template are macros.  */
+static int
+putop (const char *template, int sizeflag)
+{
+  const char *p;
+  int alt = 0;
+
+  for (p = template; *p; p++)
+    {
+      switch (*p)
+	{
+	default:
+	  *obufp++ = *p;
+	  break;
+	case '{':
+	  alt = 0;
+	  if (intel_syntax)
+	    alt += 1;
+	  if (address_mode == mode_64bit)
+	    alt += 2;
+	  while (alt != 0)
+	    {
+	      while (*++p != '|')
+		{
+		  if (*p == '}')
+		    {
+		      /* Alternative not valid.  */
+                      pstrcpy (obuf, sizeof(obuf), "(bad)");
+		      obufp = obuf + 5;
+		      return 1;
+		    }
+		  else if (*p == '\0')
+		    abort ();
+		}
+	      alt--;
+	    }
+	  /* Fall through.  */
+	case 'I':
+	  alt = 1;
+	  continue;
+	case '|':
+	  while (*++p != '}')
+	    {
+	      if (*p == '\0')
+		abort ();
+	    }
+	  break;
+	case '}':
+	  break;
+	case 'A':
+	  if (intel_syntax)
+	    break;
+	  if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+	    *obufp++ = 'b';
+	  break;
+	case 'B':
+	  if (intel_syntax)
+	    break;
+	  if (sizeflag & SUFFIX_ALWAYS)
+	    *obufp++ = 'b';
+	  break;
+	case 'C':
+	  if (intel_syntax && !alt)
+	    break;
+	  if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      if (sizeflag & DFLAG)
+		*obufp++ = intel_syntax ? 'd' : 'l';
+	      else
+		*obufp++ = intel_syntax ? 'w' : 's';
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  break;
+	case 'D':
+	  if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS))
+	    break;
+	  USED_REX (REX_W);
+	  if (modrm.mod == 3)
+	    {
+	      if (rex & REX_W)
+		*obufp++ = 'q';
+	      else if (sizeflag & DFLAG)
+		*obufp++ = intel_syntax ? 'd' : 'l';
+	      else
+		*obufp++ = 'w';
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  else
+	    *obufp++ = 'w';
+	  break;
+	case 'E':		/* For jcxz/jecxz */
+	  if (address_mode == mode_64bit)
+	    {
+	      if (sizeflag & AFLAG)
+		*obufp++ = 'r';
+	      else
+		*obufp++ = 'e';
+	    }
+	  else
+	    if (sizeflag & AFLAG)
+	      *obufp++ = 'e';
+	  used_prefixes |= (prefixes & PREFIX_ADDR);
+	  break;
+	case 'F':
+	  if (intel_syntax)
+	    break;
+	  if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      if (sizeflag & AFLAG)
+		*obufp++ = address_mode == mode_64bit ? 'q' : 'l';
+	      else
+		*obufp++ = address_mode == mode_64bit ? 'l' : 'w';
+	      used_prefixes |= (prefixes & PREFIX_ADDR);
+	    }
+	  break;
+	case 'G':
+	  if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS)))
+	    break;
+	  if ((rex & REX_W) || (sizeflag & DFLAG))
+	    *obufp++ = 'l';
+	  else
+	    *obufp++ = 'w';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	case 'H':
+	  if (intel_syntax)
+	    break;
+	  if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS
+	      || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS)
+	    {
+	      used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS);
+	      *obufp++ = ',';
+	      *obufp++ = 'p';
+	      if (prefixes & PREFIX_DS)
+		*obufp++ = 't';
+	      else
+		*obufp++ = 'n';
+	    }
+	  break;
+	case 'J':
+	  if (intel_syntax)
+	    break;
+	  *obufp++ = 'l';
+	  break;
+	case 'K':
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    *obufp++ = 'q';
+	  else
+	    *obufp++ = 'd';
+	  break;
+	case 'Z':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      *obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
+	case 'L':
+	  if (intel_syntax)
+	    break;
+	  if (sizeflag & SUFFIX_ALWAYS)
+	    *obufp++ = 'l';
+	  break;
+	case 'N':
+	  if ((prefixes & PREFIX_FWAIT) == 0)
+	    *obufp++ = 'n';
+	  else
+	    used_prefixes |= PREFIX_FWAIT;
+	  break;
+	case 'O':
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    *obufp++ = 'o';
+	  else if (intel_syntax && (sizeflag & DFLAG))
+	    *obufp++ = 'q';
+	  else
+	    *obufp++ = 'd';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	case 'T':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      *obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
+	case 'P':
+	  if (intel_syntax)
+	    break;
+	  if ((prefixes & PREFIX_DATA)
+	      || (rex & REX_W)
+	      || (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      USED_REX (REX_W);
+	      if (rex & REX_W)
+		*obufp++ = 'q';
+	      else
+		{
+		   if (sizeflag & DFLAG)
+		      *obufp++ = 'l';
+		   else
+		     *obufp++ = 'w';
+		}
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  break;
+	case 'U':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+		*obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
+	case 'Q':
+	  if (intel_syntax && !alt)
+	    break;
+	  USED_REX (REX_W);
+	  if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      if (rex & REX_W)
+		*obufp++ = 'q';
+	      else
+		{
+		  if (sizeflag & DFLAG)
+		    *obufp++ = intel_syntax ? 'd' : 'l';
+		  else
+		    *obufp++ = 'w';
+		}
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  break;
+	case 'R':
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    *obufp++ = 'q';
+	  else if (sizeflag & DFLAG)
+	    {
+	      if (intel_syntax)
+		  *obufp++ = 'd';
+	      else
+		  *obufp++ = 'l';
+	    }
+	  else
+	    *obufp++ = 'w';
+	  if (intel_syntax && !p[1]
+	      && ((rex & REX_W) || (sizeflag & DFLAG)))
+	    *obufp++ = 'e';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	case 'V':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      if (sizeflag & SUFFIX_ALWAYS)
+		*obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
+	case 'S':
+	  if (intel_syntax)
+	    break;
+	  if (sizeflag & SUFFIX_ALWAYS)
+	    {
+	      if (rex & REX_W)
+		*obufp++ = 'q';
+	      else
+		{
+		  if (sizeflag & DFLAG)
+		    *obufp++ = 'l';
+		  else
+		    *obufp++ = 'w';
+		  used_prefixes |= (prefixes & PREFIX_DATA);
+		}
+	    }
+	  break;
+	case 'X':
+	  if (prefixes & PREFIX_DATA)
+	    *obufp++ = 'd';
+	  else
+	    *obufp++ = 's';
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	case 'Y':
+	  if (intel_syntax)
+	    break;
+	  if (rex & REX_W)
+	    {
+	      USED_REX (REX_W);
+	      *obufp++ = 'q';
+	    }
+	  break;
+	  /* implicit operand size 'l' for i386 or 'q' for x86-64 */
+	case 'W':
+	  /* operand size flag for cwtl, cbtw */
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    {
+	      if (intel_syntax)
+		*obufp++ = 'd';
+	      else
+		*obufp++ = 'l';
+	    }
+	  else if (sizeflag & DFLAG)
+	    *obufp++ = 'w';
+	  else
+	    *obufp++ = 'b';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	}
+      alt = 0;
+    }
+  *obufp = 0;
+  return 0;
+}
+
+static void
+oappend (const char *s)
+{
+  strcpy (obufp, s);
+  obufp += strlen (s);
+}
+
+static void
+append_seg (void)
+{
+  if (prefixes & PREFIX_CS)
+    {
+      used_prefixes |= PREFIX_CS;
+      oappend ("%cs:" + intel_syntax);
+    }
+  if (prefixes & PREFIX_DS)
+    {
+      used_prefixes |= PREFIX_DS;
+      oappend ("%ds:" + intel_syntax);
+    }
+  if (prefixes & PREFIX_SS)
+    {
+      used_prefixes |= PREFIX_SS;
+      oappend ("%ss:" + intel_syntax);
+    }
+  if (prefixes & PREFIX_ES)
+    {
+      used_prefixes |= PREFIX_ES;
+      oappend ("%es:" + intel_syntax);
+    }
+  if (prefixes & PREFIX_FS)
+    {
+      used_prefixes |= PREFIX_FS;
+      oappend ("%fs:" + intel_syntax);
+    }
+  if (prefixes & PREFIX_GS)
+    {
+      used_prefixes |= PREFIX_GS;
+      oappend ("%gs:" + intel_syntax);
+    }
+}
+
+static void
+OP_indirE (int bytemode, int sizeflag)
+{
+  if (!intel_syntax)
+    oappend ("*");
+  OP_E (bytemode, sizeflag);
+}
+
+static void
+print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
+{
+  if (address_mode == mode_64bit)
+    {
+      if (hex)
+	{
+	  char tmp[30];
+	  int i;
+	  buf[0] = '0';
+	  buf[1] = 'x';
+          snprintf_vma (tmp, sizeof(tmp), disp);
+	  for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++);
+          pstrcpy (buf + 2, bufsize - 2, tmp + i);
+	}
+      else
+	{
+	  bfd_signed_vma v = disp;
+	  char tmp[30];
+	  int i;
+	  if (v < 0)
+	    {
+	      *(buf++) = '-';
+	      v = -disp;
+	      /* Check for possible overflow on 0x8000000000000000.  */
+	      if (v < 0)
+		{
+                  pstrcpy (buf, bufsize, "9223372036854775808");
+		  return;
+		}
+	    }
+	  if (!v)
+	    {
+                pstrcpy (buf, bufsize, "0");
+	      return;
+	    }
+
+	  i = 0;
+	  tmp[29] = 0;
+	  while (v)
+	    {
+	      tmp[28 - i] = (v % 10) + '0';
+	      v /= 10;
+	      i++;
+	    }
+          pstrcpy (buf, bufsize, tmp + 29 - i);
+	}
+    }
+  else
+    {
+      if (hex)
+        snprintf (buf, bufsize, "0x%x", (unsigned int) disp);
+      else
+        snprintf (buf, bufsize, "%d", (int) disp);
+    }
+}
+
+/* Put DISP in BUF as signed hex number.  */
+
+static void
+print_displacement (char *buf, bfd_vma disp)
+{
+  bfd_signed_vma val = disp;
+  char tmp[30];
+  int i, j = 0;
+
+  if (val < 0)
+    {
+      buf[j++] = '-';
+      val = -disp;
+
+      /* Check for possible overflow.  */
+      if (val < 0)
+	{
+	  switch (address_mode)
+	    {
+	    case mode_64bit:
+	      strcpy (buf + j, "0x8000000000000000");
+	      break;
+	    case mode_32bit:
+	      strcpy (buf + j, "0x80000000");
+	      break;
+	    case mode_16bit:
+	      strcpy (buf + j, "0x8000");
+	      break;
+	    }
+	  return;
+	}
+    }
+
+  buf[j++] = '0';
+  buf[j++] = 'x';
+
+  snprintf_vma (tmp, sizeof(tmp), val);
+  for (i = 0; tmp[i] == '0'; i++)
+    continue;
+  if (tmp[i] == '\0')
+    i--;
+  strcpy (buf + j, tmp + i);
+}
+
+static void
+intel_operand_size (int bytemode, int sizeflag)
+{
+  switch (bytemode)
+    {
+    case b_mode:
+    case dqb_mode:
+      oappend ("BYTE PTR ");
+      break;
+    case w_mode:
+    case dqw_mode:
+      oappend ("WORD PTR ");
+      break;
+    case stack_v_mode:
+      if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	{
+	  oappend ("QWORD PTR ");
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	}
+      /* FALLTHRU */
+    case v_mode:
+    case dq_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	oappend ("QWORD PTR ");
+      else if ((sizeflag & DFLAG) || bytemode == dq_mode)
+	oappend ("DWORD PTR ");
+      else
+	oappend ("WORD PTR ");
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case z_mode:
+      if ((rex & REX_W) || (sizeflag & DFLAG))
+	*obufp++ = 'D';
+      oappend ("WORD PTR ");
+      if (!(rex & REX_W))
+	used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case d_mode:
+    case dqd_mode:
+      oappend ("DWORD PTR ");
+      break;
+    case q_mode:
+      oappend ("QWORD PTR ");
+      break;
+    case m_mode:
+      if (address_mode == mode_64bit)
+	oappend ("QWORD PTR ");
+      else
+	oappend ("DWORD PTR ");
+      break;
+    case f_mode:
+      if (sizeflag & DFLAG)
+	oappend ("FWORD PTR ");
+      else
+	oappend ("DWORD PTR ");
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case t_mode:
+      oappend ("TBYTE PTR ");
+      break;
+    case x_mode:
+      oappend ("XMMWORD PTR ");
+      break;
+    case o_mode:
+      oappend ("OWORD PTR ");
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+OP_E (int bytemode, int sizeflag)
+{
+  bfd_vma disp;
+  int add = 0;
+  int riprel = 0;
+  USED_REX (REX_B);
+  if (rex & REX_B)
+    add += 8;
+
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+
+  if (modrm.mod == 3)
+    {
+      switch (bytemode)
+	{
+	case b_mode:
+	  USED_REX (0);
+	  if (rex)
+	    oappend (names8rex[modrm.rm + add]);
+	  else
+	    oappend (names8[modrm.rm + add]);
+	  break;
+	case w_mode:
+	  oappend (names16[modrm.rm + add]);
+	  break;
+	case d_mode:
+	  oappend (names32[modrm.rm + add]);
+	  break;
+	case q_mode:
+	  oappend (names64[modrm.rm + add]);
+	  break;
+	case m_mode:
+	  if (address_mode == mode_64bit)
+	    oappend (names64[modrm.rm + add]);
+	  else
+	    oappend (names32[modrm.rm + add]);
+	  break;
+	case stack_v_mode:
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      oappend (names64[modrm.rm + add]);
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	      break;
+	    }
+	  bytemode = v_mode;
+	  /* FALLTHRU */
+	case v_mode:
+	case dq_mode:
+	case dqb_mode:
+	case dqd_mode:
+	case dqw_mode:
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    oappend (names64[modrm.rm + add]);
+	  else if ((sizeflag & DFLAG) || bytemode != v_mode)
+	    oappend (names32[modrm.rm + add]);
+	  else
+	    oappend (names16[modrm.rm + add]);
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	case 0:
+	  break;
+	default:
+	  oappend (INTERNAL_DISASSEMBLER_ERROR);
+	  break;
+	}
+      return;
+    }
+
+  disp = 0;
+  if (intel_syntax)
+    intel_operand_size (bytemode, sizeflag);
+  append_seg ();
+
+  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
+    {
+      /* 32/64 bit address mode */
+      int havedisp;
+      int havesib;
+      int havebase;
+      int base;
+      int index = 0;
+      int scale = 0;
+
+      havesib = 0;
+      havebase = 1;
+      base = modrm.rm;
+
+      if (base == 4)
+	{
+	  havesib = 1;
+          fetch_data(the_info, codep + 1);
+	  index = (*codep >> 3) & 7;
+	  if (address_mode == mode_64bit || index != 0x4)
+	    /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored.  */
+	    scale = (*codep >> 6) & 3;
+	  base = *codep & 7;
+	  USED_REX (REX_X);
+	  if (rex & REX_X)
+	    index += 8;
+	  codep++;
+	}
+      base += add;
+
+      switch (modrm.mod)
+	{
+	case 0:
+	  if ((base & 7) == 5)
+	    {
+	      havebase = 0;
+	      if (address_mode == mode_64bit && !havesib)
+		riprel = 1;
+	      disp = get32s ();
+	    }
+	  break;
+	case 1:
+          fetch_data (the_info, codep + 1);
+	  disp = *codep++;
+	  if ((disp & 0x80) != 0)
+	    disp -= 0x100;
+	  break;
+	case 2:
+	  disp = get32s ();
+	  break;
+	}
+
+      havedisp = havebase || (havesib && (index != 4 || scale != 0));
+
+      if (!intel_syntax)
+	if (modrm.mod != 0 || (base & 7) == 5)
+	  {
+	    if (havedisp || riprel)
+	      print_displacement (scratchbuf, disp);
+	    else
+              print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
+	    oappend (scratchbuf);
+	    if (riprel)
+	      {
+		set_op (disp, 1);
+		oappend ("(%rip)");
+	      }
+	  }
+
+      if (havedisp || (intel_syntax && riprel))
+	{
+	  *obufp++ = open_char;
+	  if (intel_syntax && riprel)
+	    {
+	      set_op (disp, 1);
+	      oappend ("rip");
+	    }
+	  *obufp = '\0';
+	  if (havebase)
+	    oappend (address_mode == mode_64bit && (sizeflag & AFLAG)
+		     ? names64[base] : names32[base]);
+	  if (havesib)
+	    {
+	      if (index != 4)
+		{
+		  if (!intel_syntax || havebase)
+		    {
+		      *obufp++ = separator_char;
+		      *obufp = '\0';
+		    }
+		  oappend (address_mode == mode_64bit && (sizeflag & AFLAG)
+			   ? names64[index] : names32[index]);
+		}
+	      if (scale != 0 || (!intel_syntax && index != 4))
+		{
+		  *obufp++ = scale_char;
+		  *obufp = '\0';
+		  snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale);
+		  oappend (scratchbuf);
+		}
+	    }
+	  if (intel_syntax
+	      && (disp || modrm.mod != 0 || (base & 7) == 5))
+	    {
+	      if ((bfd_signed_vma) disp >= 0)
+		{
+		  *obufp++ = '+';
+		  *obufp = '\0';
+		}
+	      else if (modrm.mod != 1)
+		{
+		  *obufp++ = '-';
+		  *obufp = '\0';
+		  disp = - (bfd_signed_vma) disp;
+		}
+
+	      print_displacement (scratchbuf, disp);
+	      oappend (scratchbuf);
+	    }
+
+	  *obufp++ = close_char;
+	  *obufp = '\0';
+	}
+      else if (intel_syntax)
+	{
+	  if (modrm.mod != 0 || (base & 7) == 5)
+	    {
+	      if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
+			      | PREFIX_ES | PREFIX_FS | PREFIX_GS))
+		;
+	      else
+		{
+		  oappend (names_seg[ds_reg - es_reg]);
+		  oappend (":");
+		}
+	      print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
+	      oappend (scratchbuf);
+	    }
+	}
+    }
+  else
+    { /* 16 bit address mode */
+      switch (modrm.mod)
+	{
+	case 0:
+	  if (modrm.rm == 6)
+	    {
+	      disp = get16 ();
+	      if ((disp & 0x8000) != 0)
+		disp -= 0x10000;
+	    }
+	  break;
+	case 1:
+          fetch_data(the_info, codep + 1);
+	  disp = *codep++;
+	  if ((disp & 0x80) != 0)
+	    disp -= 0x100;
+	  break;
+	case 2:
+	  disp = get16 ();
+	  if ((disp & 0x8000) != 0)
+	    disp -= 0x10000;
+	  break;
+	}
+
+      if (!intel_syntax)
+	if (modrm.mod != 0 || modrm.rm == 6)
+	  {
+	    print_displacement (scratchbuf, disp);
+	    oappend (scratchbuf);
+	  }
+
+      if (modrm.mod != 0 || modrm.rm != 6)
+	{
+	  *obufp++ = open_char;
+	  *obufp = '\0';
+	  oappend (index16[modrm.rm]);
+	  if (intel_syntax
+	      && (disp || modrm.mod != 0 || modrm.rm == 6))
+	    {
+	      if ((bfd_signed_vma) disp >= 0)
+		{
+		  *obufp++ = '+';
+		  *obufp = '\0';
+		}
+	      else if (modrm.mod != 1)
+		{
+		  *obufp++ = '-';
+		  *obufp = '\0';
+		  disp = - (bfd_signed_vma) disp;
+		}
+
+	      print_displacement (scratchbuf, disp);
+	      oappend (scratchbuf);
+	    }
+
+	  *obufp++ = close_char;
+	  *obufp = '\0';
+	}
+      else if (intel_syntax)
+	{
+	  if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
+			  | PREFIX_ES | PREFIX_FS | PREFIX_GS))
+	    ;
+	  else
+	    {
+	      oappend (names_seg[ds_reg - es_reg]);
+	      oappend (":");
+	    }
+	  print_operand_value (scratchbuf, sizeof(scratchbuf), 1,
+                               disp & 0xffff);
+	  oappend (scratchbuf);
+	}
+    }
+}
+
+static void
+OP_G (int bytemode, int sizeflag)
+{
+  int add = 0;
+  USED_REX (REX_R);
+  if (rex & REX_R)
+    add += 8;
+  switch (bytemode)
+    {
+    case b_mode:
+      USED_REX (0);
+      if (rex)
+	oappend (names8rex[modrm.reg + add]);
+      else
+	oappend (names8[modrm.reg + add]);
+      break;
+    case w_mode:
+      oappend (names16[modrm.reg + add]);
+      break;
+    case d_mode:
+      oappend (names32[modrm.reg + add]);
+      break;
+    case q_mode:
+      oappend (names64[modrm.reg + add]);
+      break;
+    case v_mode:
+    case dq_mode:
+    case dqb_mode:
+    case dqd_mode:
+    case dqw_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	oappend (names64[modrm.reg + add]);
+      else if ((sizeflag & DFLAG) || bytemode != v_mode)
+	oappend (names32[modrm.reg + add]);
+      else
+	oappend (names16[modrm.reg + add]);
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case m_mode:
+      if (address_mode == mode_64bit)
+	oappend (names64[modrm.reg + add]);
+      else
+	oappend (names32[modrm.reg + add]);
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      break;
+    }
+}
+
+static bfd_vma
+get64 (void)
+{
+  bfd_vma x;
+#ifdef BFD64
+  unsigned int a;
+  unsigned int b;
+
+  fetch_data(the_info, codep + 8);
+  a = *codep++ & 0xff;
+  a |= (*codep++ & 0xff) << 8;
+  a |= (*codep++ & 0xff) << 16;
+  a |= (*codep++ & 0xff) << 24;
+  b = *codep++ & 0xff;
+  b |= (*codep++ & 0xff) << 8;
+  b |= (*codep++ & 0xff) << 16;
+  b |= (*codep++ & 0xff) << 24;
+  x = a + ((bfd_vma) b << 32);
+#else
+  abort ();
+  x = 0;
+#endif
+  return x;
+}
+
+static bfd_signed_vma
+get32 (void)
+{
+  bfd_signed_vma x = 0;
+
+  fetch_data(the_info, codep + 4);
+  x = *codep++ & (bfd_signed_vma) 0xff;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 8;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 16;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 24;
+  return x;
+}
+
+static bfd_signed_vma
+get32s (void)
+{
+  bfd_signed_vma x = 0;
+
+  fetch_data(the_info, codep + 4);
+  x = *codep++ & (bfd_signed_vma) 0xff;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 8;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 16;
+  x |= (*codep++ & (bfd_signed_vma) 0xff) << 24;
+
+  x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31);
+
+  return x;
+}
+
+static int
+get16 (void)
+{
+  int x = 0;
+
+  fetch_data(the_info, codep + 2);
+  x = *codep++ & 0xff;
+  x |= (*codep++ & 0xff) << 8;
+  return x;
+}
+
+static void
+set_op (bfd_vma op, int riprel)
+{
+  op_index[op_ad] = op_ad;
+  if (address_mode == mode_64bit)
+    {
+      op_address[op_ad] = op;
+      op_riprel[op_ad] = riprel;
+    }
+  else
+    {
+      /* Mask to get a 32-bit address.  */
+      op_address[op_ad] = op & 0xffffffff;
+      op_riprel[op_ad] = riprel & 0xffffffff;
+    }
+}
+
+static void
+OP_REG (int code, int sizeflag)
+{
+  const char *s;
+  int add = 0;
+  USED_REX (REX_B);
+  if (rex & REX_B)
+    add = 8;
+
+  switch (code)
+    {
+    case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+    case sp_reg: case bp_reg: case si_reg: case di_reg:
+      s = names16[code - ax_reg + add];
+      break;
+    case es_reg: case ss_reg: case cs_reg:
+    case ds_reg: case fs_reg: case gs_reg:
+      s = names_seg[code - es_reg + add];
+      break;
+    case al_reg: case ah_reg: case cl_reg: case ch_reg:
+    case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+      USED_REX (0);
+      if (rex)
+	s = names8rex[code - al_reg + add];
+      else
+	s = names8[code - al_reg];
+      break;
+    case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg:
+    case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg:
+      if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	{
+	  s = names64[code - rAX_reg + add];
+	  break;
+	}
+      code += eAX_reg - rAX_reg;
+      /* Fall through.  */
+    case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+    case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	s = names64[code - eAX_reg + add];
+      else if (sizeflag & DFLAG)
+	s = names32[code - eAX_reg + add];
+      else
+	s = names16[code - eAX_reg + add];
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    default:
+      s = INTERNAL_DISASSEMBLER_ERROR;
+      break;
+    }
+  oappend (s);
+}
+
+static void
+OP_IMREG (int code, int sizeflag)
+{
+  const char *s;
+
+  switch (code)
+    {
+    case indir_dx_reg:
+      if (intel_syntax)
+	s = "dx";
+      else
+	s = "(%dx)";
+      break;
+    case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+    case sp_reg: case bp_reg: case si_reg: case di_reg:
+      s = names16[code - ax_reg];
+      break;
+    case es_reg: case ss_reg: case cs_reg:
+    case ds_reg: case fs_reg: case gs_reg:
+      s = names_seg[code - es_reg];
+      break;
+    case al_reg: case ah_reg: case cl_reg: case ch_reg:
+    case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+      USED_REX (0);
+      if (rex)
+	s = names8rex[code - al_reg];
+      else
+	s = names8[code - al_reg];
+      break;
+    case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+    case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	s = names64[code - eAX_reg];
+      else if (sizeflag & DFLAG)
+	s = names32[code - eAX_reg];
+      else
+	s = names16[code - eAX_reg];
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case z_mode_ax_reg:
+      if ((rex & REX_W) || (sizeflag & DFLAG))
+	s = *names32;
+      else
+	s = *names16;
+      if (!(rex & REX_W))
+	used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    default:
+      s = INTERNAL_DISASSEMBLER_ERROR;
+      break;
+    }
+  oappend (s);
+}
+
+static void
+OP_I (int bytemode, int sizeflag)
+{
+  bfd_signed_vma op;
+  bfd_signed_vma mask = -1;
+
+  switch (bytemode)
+    {
+    case b_mode:
+      fetch_data(the_info, codep + 1);
+      op = *codep++;
+      mask = 0xff;
+      break;
+    case q_mode:
+      if (address_mode == mode_64bit)
+	{
+	  op = get32s ();
+	  break;
+	}
+      /* Fall through.  */
+    case v_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	op = get32s ();
+      else if (sizeflag & DFLAG)
+	{
+	  op = get32 ();
+	  mask = 0xffffffff;
+	}
+      else
+	{
+	  op = get16 ();
+	  mask = 0xfffff;
+	}
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case w_mode:
+      mask = 0xfffff;
+      op = get16 ();
+      break;
+    case const_1_mode:
+      if (intel_syntax)
+        oappend ("1");
+      return;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      return;
+    }
+
+  op &= mask;
+  scratchbuf[0] = '$';
+  print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op);
+  oappend (scratchbuf + intel_syntax);
+  scratchbuf[0] = '\0';
+}
+
+static void
+OP_I64 (int bytemode, int sizeflag)
+{
+  bfd_signed_vma op;
+  bfd_signed_vma mask = -1;
+
+  if (address_mode != mode_64bit)
+    {
+      OP_I (bytemode, sizeflag);
+      return;
+    }
+
+  switch (bytemode)
+    {
+    case b_mode:
+      fetch_data(the_info, codep + 1);
+      op = *codep++;
+      mask = 0xff;
+      break;
+    case v_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	op = get64 ();
+      else if (sizeflag & DFLAG)
+	{
+	  op = get32 ();
+	  mask = 0xffffffff;
+	}
+      else
+	{
+	  op = get16 ();
+	  mask = 0xfffff;
+	}
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case w_mode:
+      mask = 0xfffff;
+      op = get16 ();
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      return;
+    }
+
+  op &= mask;
+  scratchbuf[0] = '$';
+  print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op);
+  oappend (scratchbuf + intel_syntax);
+  scratchbuf[0] = '\0';
+}
+
+static void
+OP_sI (int bytemode, int sizeflag)
+{
+  bfd_signed_vma op;
+
+  switch (bytemode)
+    {
+    case b_mode:
+      fetch_data(the_info, codep + 1);
+      op = *codep++;
+      if ((op & 0x80) != 0)
+	op -= 0x100;
+      break;
+    case v_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	op = get32s ();
+      else if (sizeflag & DFLAG)
+	{
+	  op = get32s ();
+	}
+      else
+	{
+	  op = get16 ();
+	  if ((op & 0x8000) != 0)
+	    op -= 0x10000;
+	}
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case w_mode:
+      op = get16 ();
+      if ((op & 0x8000) != 0)
+	op -= 0x10000;
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      return;
+    }
+
+  scratchbuf[0] = '$';
+  print_operand_value (scratchbuf + 1, sizeof(scratchbuf) - 1, 1, op);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_J (int bytemode, int sizeflag)
+{
+  bfd_vma disp;
+  bfd_vma mask = -1;
+  bfd_vma segment = 0;
+
+  switch (bytemode)
+    {
+    case b_mode:
+      fetch_data(the_info, codep + 1);
+      disp = *codep++;
+      if ((disp & 0x80) != 0)
+	disp -= 0x100;
+      break;
+    case v_mode:
+      if ((sizeflag & DFLAG) || (rex & REX_W))
+	disp = get32s ();
+      else
+	{
+	  disp = get16 ();
+	  if ((disp & 0x8000) != 0)
+	    disp -= 0x10000;
+	  /* In 16bit mode, address is wrapped around at 64k within
+	     the same segment.  Otherwise, a data16 prefix on a jump
+	     instruction means that the pc is masked to 16 bits after
+	     the displacement is added!  */
+	  mask = 0xffff;
+	  if ((prefixes & PREFIX_DATA) == 0)
+	    segment = ((start_pc + codep - start_codep)
+		       & ~((bfd_vma) 0xffff));
+	}
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      return;
+    }
+  disp = ((start_pc + codep - start_codep + disp) & mask) | segment;
+  set_op (disp, 0);
+  print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
+  oappend (scratchbuf);
+}
+
+static void
+OP_SEG (int bytemode, int sizeflag)
+{
+  if (bytemode == w_mode)
+    oappend (names_seg[modrm.reg]);
+  else
+    OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag);
+}
+
+static void
+OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag)
+{
+  int seg, offset;
+
+  if (sizeflag & DFLAG)
+    {
+      offset = get32 ();
+      seg = get16 ();
+    }
+  else
+    {
+      offset = get16 ();
+      seg = get16 ();
+    }
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  if (intel_syntax)
+    snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset);
+  else
+    snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset);
+  oappend (scratchbuf);
+}
+
+static void
+OP_OFF (int bytemode, int sizeflag)
+{
+  bfd_vma off;
+
+  if (intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+    intel_operand_size (bytemode, sizeflag);
+  append_seg ();
+
+  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
+    off = get32 ();
+  else
+    off = get16 ();
+
+  if (intel_syntax)
+    {
+      if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
+			| PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+	{
+	  oappend (names_seg[ds_reg - es_reg]);
+	  oappend (":");
+	}
+    }
+  print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off);
+  oappend (scratchbuf);
+}
+
+static void
+OP_OFF64 (int bytemode, int sizeflag)
+{
+  bfd_vma off;
+
+  if (address_mode != mode_64bit
+      || (prefixes & PREFIX_ADDR))
+    {
+      OP_OFF (bytemode, sizeflag);
+      return;
+    }
+
+  if (intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+    intel_operand_size (bytemode, sizeflag);
+  append_seg ();
+
+  off = get64 ();
+
+  if (intel_syntax)
+    {
+      if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
+			| PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+	{
+	  oappend (names_seg[ds_reg - es_reg]);
+	  oappend (":");
+	}
+    }
+  print_operand_value (scratchbuf, sizeof(scratchbuf), 1, off);
+  oappend (scratchbuf);
+}
+
+static void
+ptr_reg (int code, int sizeflag)
+{
+  const char *s;
+
+  *obufp++ = open_char;
+  used_prefixes |= (prefixes & PREFIX_ADDR);
+  if (address_mode == mode_64bit)
+    {
+      if (!(sizeflag & AFLAG))
+	s = names32[code - eAX_reg];
+      else
+	s = names64[code - eAX_reg];
+    }
+  else if (sizeflag & AFLAG)
+    s = names32[code - eAX_reg];
+  else
+    s = names16[code - eAX_reg];
+  oappend (s);
+  *obufp++ = close_char;
+  *obufp = 0;
+}
+
+static void
+OP_ESreg (int code, int sizeflag)
+{
+  if (intel_syntax)
+    {
+      switch (codep[-1])
+	{
+	case 0x6d:	/* insw/insl */
+	  intel_operand_size (z_mode, sizeflag);
+	  break;
+	case 0xa5:	/* movsw/movsl/movsq */
+	case 0xa7:	/* cmpsw/cmpsl/cmpsq */
+	case 0xab:	/* stosw/stosl */
+	case 0xaf:	/* scasw/scasl */
+	  intel_operand_size (v_mode, sizeflag);
+	  break;
+	default:
+	  intel_operand_size (b_mode, sizeflag);
+	}
+    }
+  oappend ("%es:" + intel_syntax);
+  ptr_reg (code, sizeflag);
+}
+
+static void
+OP_DSreg (int code, int sizeflag)
+{
+  if (intel_syntax)
+    {
+      switch (codep[-1])
+	{
+	case 0x6f:	/* outsw/outsl */
+	  intel_operand_size (z_mode, sizeflag);
+	  break;
+	case 0xa5:	/* movsw/movsl/movsq */
+	case 0xa7:	/* cmpsw/cmpsl/cmpsq */
+	case 0xad:	/* lodsw/lodsl/lodsq */
+	  intel_operand_size (v_mode, sizeflag);
+	  break;
+	default:
+	  intel_operand_size (b_mode, sizeflag);
+	}
+    }
+  if ((prefixes
+       & (PREFIX_CS
+	  | PREFIX_DS
+	  | PREFIX_SS
+	  | PREFIX_ES
+	  | PREFIX_FS
+	  | PREFIX_GS)) == 0)
+    prefixes |= PREFIX_DS;
+  append_seg ();
+  ptr_reg (code, sizeflag);
+}
+
+static void
+OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  int add = 0;
+  if (rex & REX_R)
+    {
+      USED_REX (REX_R);
+      add = 8;
+    }
+  else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK))
+    {
+      used_prefixes |= PREFIX_LOCK;
+      add = 8;
+    }
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  int add = 0;
+  USED_REX (REX_R);
+  if (rex & REX_R)
+    add = 8;
+  if (intel_syntax)
+    snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add);
+  else
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add);
+  oappend (scratchbuf);
+}
+
+static void
+OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_R (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    OP_E (bytemode, sizeflag);
+  else
+    BadOp ();
+}
+
+static void
+OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  if (prefixes & PREFIX_DATA)
+    {
+      int add = 0;
+      USED_REX (REX_R);
+      if (rex & REX_R)
+	add = 8;
+      snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add);
+    }
+  else
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  int add = 0;
+  USED_REX (REX_R);
+  if (rex & REX_R)
+    add = 8;
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_EM (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3)
+    {
+      if (intel_syntax && bytemode == v_mode)
+	{
+	  bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+ 	}
+      OP_E (bytemode, sizeflag);
+      return;
+    }
+
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  if (prefixes & PREFIX_DATA)
+    {
+      int add = 0;
+
+      USED_REX (REX_B);
+      if (rex & REX_B)
+	add = 8;
+      snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add);
+    }
+  else
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm);
+  oappend (scratchbuf + intel_syntax);
+}
+
+/* cvt* are the only instructions in sse2 which have
+   both SSE and MMX operands and also have 0x66 prefix
+   in their opcode. 0x66 was originally used to differentiate
+   between SSE and MMX instruction(operands). So we have to handle the
+   cvt* separately using OP_EMC and OP_MXC */
+static void
+OP_EMC (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3)
+    {
+      if (intel_syntax && bytemode == v_mode)
+	{
+	  bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+ 	}
+      OP_E (bytemode, sizeflag);
+      return;
+    }
+
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_EX (int bytemode, int sizeflag)
+{
+  int add = 0;
+  if (modrm.mod != 3)
+    {
+      OP_E (bytemode, sizeflag);
+      return;
+    }
+  USED_REX (REX_B);
+  if (rex & REX_B)
+    add = 8;
+
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_MS (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    OP_EM (bytemode, sizeflag);
+  else
+    BadOp ();
+}
+
+static void
+OP_XS (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    OP_EX (bytemode, sizeflag);
+  else
+    BadOp ();
+}
+
+static void
+OP_M (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */
+    BadOp ();
+  else
+    OP_E (bytemode, sizeflag);
+}
+
+static void
+OP_0f07 (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3 || modrm.rm != 0)
+    BadOp ();
+  else
+    OP_E (bytemode, sizeflag);
+}
+
+static void
+OP_0fae (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    {
+      if (modrm.reg == 7)
+	strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence");
+
+      if (modrm.reg < 5 || modrm.rm != 0)
+	{
+	  BadOp ();	/* bad sfence, mfence, or lfence */
+	  return;
+	}
+    }
+  else if (modrm.reg != 7)
+    {
+      BadOp ();		/* bad clflush */
+      return;
+    }
+
+  OP_E (bytemode, sizeflag);
+}
+
+/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in
+   32bit mode and "xchg %rax,%rax" in 64bit mode.  */
+
+static void
+NOP_Fixup1 (int bytemode, int sizeflag)
+{
+  if ((prefixes & PREFIX_DATA) != 0
+      || (rex != 0
+	  && rex != 0x48
+	  && address_mode == mode_64bit))
+    OP_REG (bytemode, sizeflag);
+  else
+    strcpy (obuf, "nop");
+}
+
+static void
+NOP_Fixup2 (int bytemode, int sizeflag)
+{
+  if ((prefixes & PREFIX_DATA) != 0
+      || (rex != 0
+	  && rex != 0x48
+	  && address_mode == mode_64bit))
+    OP_IMREG (bytemode, sizeflag);
+}
+
+static const char *Suffix3DNow[] = {
+/* 00 */	NULL,		NULL,		NULL,		NULL,
+/* 04 */	NULL,		NULL,		NULL,		NULL,
+/* 08 */	NULL,		NULL,		NULL,		NULL,
+/* 0C */	"pi2fw",	"pi2fd",	NULL,		NULL,
+/* 10 */	NULL,		NULL,		NULL,		NULL,
+/* 14 */	NULL,		NULL,		NULL,		NULL,
+/* 18 */	NULL,		NULL,		NULL,		NULL,
+/* 1C */	"pf2iw",	"pf2id",	NULL,		NULL,
+/* 20 */	NULL,		NULL,		NULL,		NULL,
+/* 24 */	NULL,		NULL,		NULL,		NULL,
+/* 28 */	NULL,		NULL,		NULL,		NULL,
+/* 2C */	NULL,		NULL,		NULL,		NULL,
+/* 30 */	NULL,		NULL,		NULL,		NULL,
+/* 34 */	NULL,		NULL,		NULL,		NULL,
+/* 38 */	NULL,		NULL,		NULL,		NULL,
+/* 3C */	NULL,		NULL,		NULL,		NULL,
+/* 40 */	NULL,		NULL,		NULL,		NULL,
+/* 44 */	NULL,		NULL,		NULL,		NULL,
+/* 48 */	NULL,		NULL,		NULL,		NULL,
+/* 4C */	NULL,		NULL,		NULL,		NULL,
+/* 50 */	NULL,		NULL,		NULL,		NULL,
+/* 54 */	NULL,		NULL,		NULL,		NULL,
+/* 58 */	NULL,		NULL,		NULL,		NULL,
+/* 5C */	NULL,		NULL,		NULL,		NULL,
+/* 60 */	NULL,		NULL,		NULL,		NULL,
+/* 64 */	NULL,		NULL,		NULL,		NULL,
+/* 68 */	NULL,		NULL,		NULL,		NULL,
+/* 6C */	NULL,		NULL,		NULL,		NULL,
+/* 70 */	NULL,		NULL,		NULL,		NULL,
+/* 74 */	NULL,		NULL,		NULL,		NULL,
+/* 78 */	NULL,		NULL,		NULL,		NULL,
+/* 7C */	NULL,		NULL,		NULL,		NULL,
+/* 80 */	NULL,		NULL,		NULL,		NULL,
+/* 84 */	NULL,		NULL,		NULL,		NULL,
+/* 88 */	NULL,		NULL,		"pfnacc",	NULL,
+/* 8C */	NULL,		NULL,		"pfpnacc",	NULL,
+/* 90 */	"pfcmpge",	NULL,		NULL,		NULL,
+/* 94 */	"pfmin",	NULL,		"pfrcp",	"pfrsqrt",
+/* 98 */	NULL,		NULL,		"pfsub",	NULL,
+/* 9C */	NULL,		NULL,		"pfadd",	NULL,
+/* A0 */	"pfcmpgt",	NULL,		NULL,		NULL,
+/* A4 */	"pfmax",	NULL,		"pfrcpit1",	"pfrsqit1",
+/* A8 */	NULL,		NULL,		"pfsubr",	NULL,
+/* AC */	NULL,		NULL,		"pfacc",	NULL,
+/* B0 */	"pfcmpeq",	NULL,		NULL,		NULL,
+/* B4 */	"pfmul",	NULL,		"pfrcpit2",	"pmulhrw",
+/* B8 */	NULL,		NULL,		NULL,		"pswapd",
+/* BC */	NULL,		NULL,		NULL,		"pavgusb",
+/* C0 */	NULL,		NULL,		NULL,		NULL,
+/* C4 */	NULL,		NULL,		NULL,		NULL,
+/* C8 */	NULL,		NULL,		NULL,		NULL,
+/* CC */	NULL,		NULL,		NULL,		NULL,
+/* D0 */	NULL,		NULL,		NULL,		NULL,
+/* D4 */	NULL,		NULL,		NULL,		NULL,
+/* D8 */	NULL,		NULL,		NULL,		NULL,
+/* DC */	NULL,		NULL,		NULL,		NULL,
+/* E0 */	NULL,		NULL,		NULL,		NULL,
+/* E4 */	NULL,		NULL,		NULL,		NULL,
+/* E8 */	NULL,		NULL,		NULL,		NULL,
+/* EC */	NULL,		NULL,		NULL,		NULL,
+/* F0 */	NULL,		NULL,		NULL,		NULL,
+/* F4 */	NULL,		NULL,		NULL,		NULL,
+/* F8 */	NULL,		NULL,		NULL,		NULL,
+/* FC */	NULL,		NULL,		NULL,		NULL,
+};
+
+static void
+OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  const char *mnemonic;
+
+  fetch_data(the_info, codep + 1);
+  /* AMD 3DNow! instructions are specified by an opcode suffix in the
+     place where an 8-bit immediate would normally go.  ie. the last
+     byte of the instruction.  */
+  obufp = obuf + strlen (obuf);
+  mnemonic = Suffix3DNow[*codep++ & 0xff];
+  if (mnemonic)
+    oappend (mnemonic);
+  else
+    {
+      /* Since a variable sized modrm/sib chunk is between the start
+	 of the opcode (0x0f0f) and the opcode suffix, we need to do
+	 all the modrm processing first, and don't know until now that
+	 we have a bad opcode.  This necessitates some cleaning up.  */
+      op_out[0][0] = '\0';
+      op_out[1][0] = '\0';
+      BadOp ();
+    }
+}
+
+static const char *simd_cmp_op[] = {
+  "eq",
+  "lt",
+  "le",
+  "unord",
+  "neq",
+  "nlt",
+  "nle",
+  "ord"
+};
+
+static void
+OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  unsigned int cmp_type;
+
+  fetch_data(the_info, codep + 1);
+  obufp = obuf + strlen (obuf);
+  cmp_type = *codep++ & 0xff;
+  if (cmp_type < 8)
+    {
+      char suffix1 = 'p', suffix2 = 's';
+      used_prefixes |= (prefixes & PREFIX_REPZ);
+      if (prefixes & PREFIX_REPZ)
+	suffix1 = 's';
+      else
+	{
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+	  if (prefixes & PREFIX_DATA)
+	    suffix2 = 'd';
+	  else
+	    {
+	      used_prefixes |= (prefixes & PREFIX_REPNZ);
+	      if (prefixes & PREFIX_REPNZ)
+		suffix1 = 's', suffix2 = 'd';
+	    }
+	}
+      snprintf (scratchbuf, sizeof(scratchbuf), "cmp%s%c%c",
+                simd_cmp_op[cmp_type], suffix1, suffix2);
+      used_prefixes |= (prefixes & PREFIX_REPZ);
+      oappend (scratchbuf);
+    }
+  else
+    {
+      /* We have a bad extension byte.  Clean up.  */
+      op_out[0][0] = '\0';
+      op_out[1][0] = '\0';
+      BadOp ();
+    }
+}
+
+static void
+SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED)
+{
+  /* Change movlps/movhps to movhlps/movlhps for 2 register operand
+     forms of these instructions.  */
+  if (modrm.mod == 3)
+    {
+      char *p = obuf + strlen (obuf);
+      *(p + 1) = '\0';
+      *p       = *(p - 1);
+      *(p - 1) = *(p - 2);
+      *(p - 2) = *(p - 3);
+      *(p - 3) = extrachar;
+    }
+}
+
+static void
+PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag)
+{
+  if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1)
+    {
+      /* Override "sidt".  */
+      size_t olen = strlen (obuf);
+      char *p = obuf + olen - 4;
+      const char * const *names = (address_mode == mode_64bit
+			    ? names64 : names32);
+
+      /* We might have a suffix when disassembling with -Msuffix.  */
+      if (*p == 'i')
+	--p;
+
+      /* Remove "addr16/addr32" if we aren't in Intel mode.  */
+      if (!intel_syntax
+	  && (prefixes & PREFIX_ADDR)
+	  && olen >= (4 + 7)
+	  && *(p - 1) == ' '
+	  && strncmp (p - 7, "addr", 4) == 0
+	  && (strncmp (p - 3, "16", 2) == 0
+	      || strncmp (p - 3, "32", 2) == 0))
+	p -= 7;
+
+      if (modrm.rm)
+	{
+	  /* mwait %eax,%ecx  */
+	  strcpy (p, "mwait");
+	  if (!intel_syntax)
+	    strcpy (op_out[0], names[0]);
+	}
+      else
+	{
+	  /* monitor %eax,%ecx,%edx"  */
+	  strcpy (p, "monitor");
+	  if (!intel_syntax)
+	    {
+	      const char * const *op1_names;
+	      if (!(prefixes & PREFIX_ADDR))
+		op1_names = (address_mode == mode_16bit
+			     ? names16 : names);
+	      else
+		{
+		  op1_names = (address_mode != mode_32bit
+			       ? names32 : names16);
+		  used_prefixes |= PREFIX_ADDR;
+		}
+	      strcpy (op_out[0], op1_names[0]);
+	      strcpy (op_out[2], names[2]);
+	    }
+	}
+      if (!intel_syntax)
+	{
+	  strcpy (op_out[1], names[1]);
+	  two_source_ops = 1;
+	}
+
+      codep++;
+    }
+  else
+    OP_M (0, sizeflag);
+}
+
+static void
+SVME_Fixup (int bytemode, int sizeflag)
+{
+  const char *alt;
+  char *p;
+
+  switch (*codep)
+    {
+    case 0xd8:
+      alt = "vmrun";
+      break;
+    case 0xd9:
+      alt = "vmmcall";
+      break;
+    case 0xda:
+      alt = "vmload";
+      break;
+    case 0xdb:
+      alt = "vmsave";
+      break;
+    case 0xdc:
+      alt = "stgi";
+      break;
+    case 0xdd:
+      alt = "clgi";
+      break;
+    case 0xde:
+      alt = "skinit";
+      break;
+    case 0xdf:
+      alt = "invlpga";
+      break;
+    default:
+      OP_M (bytemode, sizeflag);
+      return;
+    }
+  /* Override "lidt".  */
+  p = obuf + strlen (obuf) - 4;
+  /* We might have a suffix.  */
+  if (*p == 'i')
+    --p;
+  strcpy (p, alt);
+  if (!(prefixes & PREFIX_ADDR))
+    {
+      ++codep;
+      return;
+    }
+  used_prefixes |= PREFIX_ADDR;
+  switch (*codep++)
+    {
+    case 0xdf:
+      strcpy (op_out[1], names32[1]);
+      two_source_ops = 1;
+	  /* Fall through.  */
+    case 0xd8:
+    case 0xda:
+    case 0xdb:
+      *obufp++ = open_char;
+      if (address_mode == mode_64bit || (sizeflag & AFLAG))
+        alt = names32[0];
+      else
+        alt = names16[0];
+      strcpy (obufp, alt);
+      obufp += strlen (alt);
+      *obufp++ = close_char;
+      *obufp = '\0';
+      break;
+    }
+}
+
+static void
+INVLPG_Fixup (int bytemode, int sizeflag)
+{
+  const char *alt;
+
+  switch (*codep)
+    {
+    case 0xf8:
+      alt = "swapgs";
+      break;
+    case 0xf9:
+      alt = "rdtscp";
+      break;
+    default:
+      OP_M (bytemode, sizeflag);
+      return;
+    }
+  /* Override "invlpg".  */
+  strcpy (obuf + strlen (obuf) - 6, alt);
+  codep++;
+}
+
+static void
+BadOp (void)
+{
+  /* Throw away prefixes and 1st. opcode byte.  */
+  codep = insn_codep + 1;
+  oappend ("(bad)");
+}
+
+static void
+VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag)
+{
+  if (modrm.mod == 3
+      && modrm.reg == 0
+      && modrm.rm >=1
+      && modrm.rm <= 4)
+    {
+      /* Override "sgdt".  */
+      char *p = obuf + strlen (obuf) - 4;
+
+      /* We might have a suffix when disassembling with -Msuffix.  */
+      if (*p == 'g')
+	--p;
+
+      switch (modrm.rm)
+	{
+	case 1:
+	  strcpy (p, "vmcall");
+	  break;
+	case 2:
+	  strcpy (p, "vmlaunch");
+	  break;
+	case 3:
+	  strcpy (p, "vmresume");
+	  break;
+	case 4:
+	  strcpy (p, "vmxoff");
+	  break;
+	}
+
+      codep++;
+    }
+  else
+    OP_E (0, sizeflag);
+}
+
+static void
+OP_VMX (int bytemode, int sizeflag)
+{
+  used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ));
+  if (prefixes & PREFIX_DATA)
+    strcpy (obuf, "vmclear");
+  else if (prefixes & PREFIX_REPZ)
+    strcpy (obuf, "vmxon");
+  else
+    strcpy (obuf, "vmptrld");
+  OP_E (bytemode, sizeflag);
+}
+
+static void
+REP_Fixup (int bytemode, int sizeflag)
+{
+  /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs,
+     lods and stos.  */
+  size_t ilen = 0;
+
+  if (prefixes & PREFIX_REPZ)
+    switch (*insn_codep)
+      {
+      case 0x6e:	/* outsb */
+      case 0x6f:	/* outsw/outsl */
+      case 0xa4:	/* movsb */
+      case 0xa5:	/* movsw/movsl/movsq */
+	if (!intel_syntax)
+	  ilen = 5;
+	else
+	  ilen = 4;
+	break;
+      case 0xaa:	/* stosb */
+      case 0xab:	/* stosw/stosl/stosq */
+      case 0xac:	/* lodsb */
+      case 0xad:	/* lodsw/lodsl/lodsq */
+	if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+	  ilen = 5;
+	else
+	  ilen = 4;
+	break;
+      case 0x6c:	/* insb */
+      case 0x6d:	/* insl/insw */
+	if (!intel_syntax)
+	  ilen = 4;
+	else
+	  ilen = 3;
+	break;
+      default:
+	abort ();
+	break;
+      }
+
+  if (ilen != 0)
+    {
+      size_t olen;
+      char *p;
+
+      olen = strlen (obuf);
+      p = obuf + olen - ilen - 1 - 4;
+      /* Handle "repz [addr16|addr32]".  */
+      if ((prefixes & PREFIX_ADDR))
+	p -= 1 + 6;
+
+      memmove (p + 3, p + 4, olen - (p + 3 - obuf));
+    }
+
+  switch (bytemode)
+    {
+    case al_reg:
+    case eAX_reg:
+    case indir_dx_reg:
+      OP_IMREG (bytemode, sizeflag);
+      break;
+    case eDI_reg:
+      OP_ESreg (bytemode, sizeflag);
+      break;
+    case eSI_reg:
+      OP_DSreg (bytemode, sizeflag);
+      break;
+    default:
+      abort ();
+      break;
+    }
+}
+
+static void
+CMPXCHG8B_Fixup (int bytemode, int sizeflag)
+{
+  USED_REX (REX_W);
+  if (rex & REX_W)
+    {
+      /* Change cmpxchg8b to cmpxchg16b.  */
+      char *p = obuf + strlen (obuf) - 2;
+      strcpy (p, "16b");
+      bytemode = o_mode;
+    }
+  OP_M (bytemode, sizeflag);
+}
+
+static void
+XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED)
+{
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+CRC32_Fixup (int bytemode, int sizeflag)
+{
+  /* Add proper suffix to "crc32".  */
+  char *p = obuf + strlen (obuf);
+
+  switch (bytemode)
+    {
+    case b_mode:
+      if (intel_syntax)
+	break;
+
+      *p++ = 'b';
+      break;
+    case v_mode:
+      if (intel_syntax)
+	break;
+
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	*p++ = 'q';
+      else if (sizeflag & DFLAG)
+	*p++ = 'l';
+      else
+	*p++ = 'w';
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      break;
+    }
+  *p = '\0';
+
+  if (modrm.mod == 3)
+    {
+      int add;
+
+      /* Skip mod/rm byte.  */
+      MODRM_CHECK;
+      codep++;
+
+      USED_REX (REX_B);
+      add = (rex & REX_B) ? 8 : 0;
+      if (bytemode == b_mode)
+	{
+	  USED_REX (0);
+	  if (rex)
+	    oappend (names8rex[modrm.rm + add]);
+	  else
+	    oappend (names8[modrm.rm + add]);
+	}
+      else
+	{
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    oappend (names64[modrm.rm + add]);
+	  else if ((prefixes & PREFIX_DATA))
+	    oappend (names16[modrm.rm + add]);
+	  else
+	    oappend (names32[modrm.rm + add]);
+	}
+    }
+  else
+    OP_E (bytemode, sizeflag);
+}
diff --git a/qemu-0.15.x/i386.ld b/qemu-0.15.x/i386.ld
new file mode 100644
index 0000000..cc3f160
--- /dev/null
+++ b/qemu-0.15.x/i386.ld
@@ -0,0 +1,153 @@
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj at atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp) 	}
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .gnu.version   : { *(.gnu.version)	}
+  .gnu.version_d   : { *(.gnu.version_d)	}
+  .gnu.version_r   : { *(.gnu.version_r)	}
+  .rel.text      :
+    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+  .rela.text     :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rel.data      :
+    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+  .rela.data     :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rel.rodata    :
+    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+  .rela.rodata   :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.init      : { *(.rel.init)	}
+  .rela.init     : { *(.rela.init)	}
+  .rel.fini      : { *(.rel.fini)	}
+  .rela.fini     : { *(.rela.fini)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt      :
+  {
+    *(.rel.plt)
+    PROVIDE (__rel_iplt_start = .);
+    *(.rel.iplt)
+    PROVIDE (__rel_iplt_end = .);
+  }
+  .rela.plt       :
+  {
+    *(.rela.plt)
+    PROVIDE (__rela_iplt_start = .);
+    *(.rela.iplt)
+    PROVIDE (__rela_iplt_end = .);
+  }
+  .init          : { *(.init)	} =0x47ff041f
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  } =0x47ff041f
+  _etext = .;
+  PROVIDE (etext = .);
+  .fini      : { *(.fini)    } =0x47ff041f
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x100000) + (. & (0x100000 - 1));
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .data    :
+  {
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+  .plt      : { *(.plt)	}
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff --git a/qemu-0.15.x/ia64-dis.c b/qemu-0.15.x/ia64-dis.c
new file mode 100644
index 0000000..2886df3
--- /dev/null
+++ b/qemu-0.15.x/ia64-dis.c
@@ -0,0 +1,10599 @@
+/* ia64-dis.c -- Disassemble ia64 instructions
+   Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
+   Contributed by David Mosberger-Tang <davidm at hpl.hp.com>
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   2, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <string.h>
+
+#include "dis-asm.h"
+
+/* ia64.h -- Header file for ia64 opcode table
+   Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006
+   Free Software Foundation, Inc.
+   Contributed by David Mosberger-Tang <davidm at hpl.hp.com> */
+
+#include <sys/types.h>
+
+typedef uint64_t ia64_insn;
+
+enum ia64_insn_type
+  {
+    IA64_TYPE_NIL = 0,	/* illegal type */
+    IA64_TYPE_A,	/* integer alu (I- or M-unit) */
+    IA64_TYPE_I,	/* non-alu integer (I-unit) */
+    IA64_TYPE_M,	/* memory (M-unit) */
+    IA64_TYPE_B,	/* branch (B-unit) */
+    IA64_TYPE_F,	/* floating-point (F-unit) */
+    IA64_TYPE_X,	/* long encoding (X-unit) */
+    IA64_TYPE_DYN,	/* Dynamic opcode */
+    IA64_NUM_TYPES
+  };
+
+enum ia64_unit
+  {
+    IA64_UNIT_NIL = 0,	/* illegal unit */
+    IA64_UNIT_I,	/* integer unit */
+    IA64_UNIT_M,	/* memory unit */
+    IA64_UNIT_B,	/* branching unit */
+    IA64_UNIT_F,	/* floating-point unit */
+    IA64_UNIT_L,	/* long "unit" */
+    IA64_UNIT_X,	/* may be integer or branch unit */
+    IA64_NUM_UNITS
+  };
+
+/* Changes to this enumeration must be propagated to the operand table in
+   bfd/cpu-ia64-opc.c
+ */
+enum ia64_opnd
+  {
+    IA64_OPND_NIL,	/* no operand---MUST BE FIRST!*/
+
+    /* constants */
+    IA64_OPND_AR_CSD,	/* application register csd (ar.csd) */
+    IA64_OPND_AR_CCV,	/* application register ccv (ar.ccv) */
+    IA64_OPND_AR_PFS,	/* application register pfs (ar.pfs) */
+    IA64_OPND_C1,	/* the constant 1 */
+    IA64_OPND_C8,	/* the constant 8 */
+    IA64_OPND_C16,	/* the constant 16 */
+    IA64_OPND_GR0,	/* gr0 */
+    IA64_OPND_IP,	/* instruction pointer (ip) */
+    IA64_OPND_PR,	/* predicate register (pr) */
+    IA64_OPND_PR_ROT,	/* rotating predicate register (pr.rot) */
+    IA64_OPND_PSR,	/* processor status register (psr) */
+    IA64_OPND_PSR_L,	/* processor status register L (psr.l) */
+    IA64_OPND_PSR_UM,	/* processor status register UM (psr.um) */
+
+    /* register operands: */
+    IA64_OPND_AR3,	/* third application register # (bits 20-26) */
+    IA64_OPND_B1,	/* branch register # (bits 6-8) */
+    IA64_OPND_B2,	/* branch register # (bits 13-15) */
+    IA64_OPND_CR3,	/* third control register # (bits 20-26) */
+    IA64_OPND_F1,	/* first floating-point register # */
+    IA64_OPND_F2,	/* second floating-point register # */
+    IA64_OPND_F3,	/* third floating-point register # */
+    IA64_OPND_F4,	/* fourth floating-point register # */
+    IA64_OPND_P1,	/* first predicate # */
+    IA64_OPND_P2,	/* second predicate # */
+    IA64_OPND_R1,	/* first register # */
+    IA64_OPND_R2,	/* second register # */
+    IA64_OPND_R3,	/* third register # */
+    IA64_OPND_R3_2,	/* third register # (limited to gr0-gr3) */
+
+    /* memory operands: */
+    IA64_OPND_MR3,	/* memory at addr of third register # */
+
+    /* indirect operands: */
+    IA64_OPND_CPUID_R3,	/* cpuid[reg] */
+    IA64_OPND_DBR_R3,	/* dbr[reg] */
+    IA64_OPND_DTR_R3,	/* dtr[reg] */
+    IA64_OPND_ITR_R3,	/* itr[reg] */
+    IA64_OPND_IBR_R3,	/* ibr[reg] */
+    IA64_OPND_MSR_R3,	/* msr[reg] */
+    IA64_OPND_PKR_R3,	/* pkr[reg] */
+    IA64_OPND_PMC_R3,	/* pmc[reg] */
+    IA64_OPND_PMD_R3,	/* pmd[reg] */
+    IA64_OPND_RR_R3,	/* rr[reg] */
+
+    /* immediate operands: */
+    IA64_OPND_CCNT5,	/* 5-bit count (31 - bits 20-24) */
+    IA64_OPND_CNT2a,	/* 2-bit count (1 + bits 27-28) */
+    IA64_OPND_CNT2b,	/* 2-bit count (bits 27-28): 1, 2, 3 */
+    IA64_OPND_CNT2c,	/* 2-bit count (bits 30-31): 0, 7, 15, or 16 */
+    IA64_OPND_CNT5,	/* 5-bit count (bits 14-18) */
+    IA64_OPND_CNT6,	/* 6-bit count (bits 27-32) */
+    IA64_OPND_CPOS6a,	/* 6-bit count (63 - bits 20-25) */
+    IA64_OPND_CPOS6b,	/* 6-bit count (63 - bits 14-19) */
+    IA64_OPND_CPOS6c,	/* 6-bit count (63 - bits 31-36) */
+    IA64_OPND_IMM1,	/* signed 1-bit immediate (bit 36) */
+    IA64_OPND_IMMU2,	/* unsigned 2-bit immediate (bits 13-14) */
+    IA64_OPND_IMMU5b,	/* unsigned 5-bit immediate (32 + bits 14-18) */
+    IA64_OPND_IMMU7a,	/* unsigned 7-bit immediate (bits 13-19) */
+    IA64_OPND_IMMU7b,	/* unsigned 7-bit immediate (bits 20-26) */
+    IA64_OPND_SOF,	/* 8-bit stack frame size */
+    IA64_OPND_SOL,	/* 8-bit size of locals */
+    IA64_OPND_SOR,	/* 6-bit number of rotating registers (scaled by 8) */
+    IA64_OPND_IMM8,	/* signed 8-bit immediate (bits 13-19 & 36) */
+    IA64_OPND_IMM8U4,	/* cmp4*u signed 8-bit immediate (bits 13-19 & 36) */
+    IA64_OPND_IMM8M1,	/* signed 8-bit immediate -1 (bits 13-19 & 36) */
+    IA64_OPND_IMM8M1U4,	/* cmp4*u signed 8-bit immediate -1 (bits 13-19 & 36)*/
+    IA64_OPND_IMM8M1U8,	/* cmp*u signed 8-bit immediate -1 (bits 13-19 & 36) */
+    IA64_OPND_IMMU9,	/* unsigned 9-bit immediate (bits 33-34, 20-26) */
+    IA64_OPND_IMM9a,	/* signed 9-bit immediate (bits 6-12, 27, 36) */
+    IA64_OPND_IMM9b,	/* signed 9-bit immediate (bits 13-19, 27, 36) */
+    IA64_OPND_IMM14,	/* signed 14-bit immediate (bits 13-19, 27-32, 36) */
+    IA64_OPND_IMM17,	/* signed 17-bit immediate (2*bits 6-12, 24-31, 36) */
+    IA64_OPND_IMMU21,	/* unsigned 21-bit immediate (bits 6-25, 36) */
+    IA64_OPND_IMM22,	/* signed 22-bit immediate (bits 13-19, 22-36) */
+    IA64_OPND_IMMU24,	/* unsigned 24-bit immediate (bits 6-26, 31-32, 36) */
+    IA64_OPND_IMM44,	/* signed 44-bit immediate (2^16*bits 6-32, 36) */
+    IA64_OPND_IMMU62,	/* unsigned 62-bit immediate */
+    IA64_OPND_IMMU64,	/* unsigned 64-bit immediate (lotsa bits...) */
+    IA64_OPND_INC3,	/* signed 3-bit (bits 13-15): +/-1, 4, 8, 16 */
+    IA64_OPND_LEN4,	/* 4-bit count (bits 27-30 + 1) */
+    IA64_OPND_LEN6,	/* 6-bit count (bits 27-32 + 1) */
+    IA64_OPND_MBTYPE4,	/* 4-bit mux type (bits 20-23) */
+    IA64_OPND_MHTYPE8,	/* 8-bit mux type (bits 20-27) */
+    IA64_OPND_POS6,	/* 6-bit count (bits 14-19) */
+    IA64_OPND_TAG13,	/* signed 13-bit tag (ip + 16*bits 6-12, 33-34) */
+    IA64_OPND_TAG13b,	/* signed 13-bit tag (ip + 16*bits 24-32) */
+    IA64_OPND_TGT25,	/* signed 25-bit (ip + 16*bits 6-25, 36) */
+    IA64_OPND_TGT25b,	/* signed 25-bit (ip + 16*bits 6-12, 20-32, 36) */
+    IA64_OPND_TGT25c,	/* signed 25-bit (ip + 16*bits 13-32, 36) */
+    IA64_OPND_TGT64,    /* 64-bit (ip + 16*bits 13-32, 36, 2-40(L)) */
+    IA64_OPND_LDXMOV,	/* any symbol, generates R_IA64_LDXMOV.  */
+
+    IA64_OPND_COUNT	/* # of operand types (MUST BE LAST!) */
+  };
+
+enum ia64_dependency_mode
+{
+  IA64_DV_RAW,
+  IA64_DV_WAW,
+  IA64_DV_WAR,
+};
+
+enum ia64_dependency_semantics
+{
+  IA64_DVS_NONE,
+  IA64_DVS_IMPLIED,
+  IA64_DVS_IMPLIEDF,
+  IA64_DVS_DATA,
+  IA64_DVS_INSTR,
+  IA64_DVS_SPECIFIC,
+  IA64_DVS_STOP,
+  IA64_DVS_OTHER,
+};
+
+enum ia64_resource_specifier
+{
+  IA64_RS_ANY,
+  IA64_RS_AR_K,
+  IA64_RS_AR_UNAT,
+  IA64_RS_AR, /* 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111 */
+  IA64_RS_ARb, /* 48-63, 112-127 */
+  IA64_RS_BR,
+  IA64_RS_CFM,
+  IA64_RS_CPUID,
+  IA64_RS_CR_IRR,
+  IA64_RS_CR_LRR,
+  IA64_RS_CR, /* 3-7,10-15,18,26-63,75-79,82-127 */
+  IA64_RS_DBR,
+  IA64_RS_FR,
+  IA64_RS_FRb,
+  IA64_RS_GR0,
+  IA64_RS_GR,
+  IA64_RS_IBR,
+  IA64_RS_INSERVICE, /* CR[EOI] or CR[IVR] */
+  IA64_RS_MSR,
+  IA64_RS_PKR,
+  IA64_RS_PMC,
+  IA64_RS_PMD,
+  IA64_RS_PR,  /* non-rotating, 1-15 */
+  IA64_RS_PRr, /* rotating, 16-62 */
+  IA64_RS_PR63,
+  IA64_RS_RR,
+
+  IA64_RS_ARX, /* ARs not in RS_AR or RS_ARb */
+  IA64_RS_CRX, /* CRs not in RS_CR */
+  IA64_RS_PSR, /* PSR bits */
+  IA64_RS_RSE, /* implementation-specific RSE resources */
+  IA64_RS_AR_FPSR,
+};
+
+enum ia64_rse_resource
+{
+  IA64_RSE_N_STACKED_PHYS,
+  IA64_RSE_BOF,
+  IA64_RSE_STORE_REG,
+  IA64_RSE_LOAD_REG,
+  IA64_RSE_BSPLOAD,
+  IA64_RSE_RNATBITINDEX,
+  IA64_RSE_CFLE,
+  IA64_RSE_NDIRTY,
+};
+
+/* Information about a given resource dependency */
+struct ia64_dependency
+{
+  /* Name of the resource */
+  const char *name;
+  /* Does this dependency need further specification? */
+  enum ia64_resource_specifier specifier;
+  /* Mode of dependency */
+  enum ia64_dependency_mode mode;
+  /* Dependency semantics */
+  enum ia64_dependency_semantics semantics;
+  /* Register index, if applicable (distinguishes AR, CR, and PSR deps) */
+#define REG_NONE (-1)
+  int regindex;
+  /* Special info on semantics */
+  const char *info;
+};
+
+/* Two arrays of indexes into the ia64_dependency table.
+   chks are dependencies to check for conflicts when an opcode is
+   encountered; regs are dependencies to register (mark as used) when an
+   opcode is used.  chks correspond to readers (RAW) or writers (WAW or
+   WAR) of a resource, while regs correspond to writers (RAW or WAW) and
+   readers (WAR) of a resource.  */
+struct ia64_opcode_dependency
+{
+  int nchks;
+  const unsigned short *chks;
+  int nregs;
+  const unsigned short *regs;
+};
+
+/* encode/extract the note/index for a dependency */
+#define RDEP(N,X) (((N)<<11)|(X))
+#define NOTE(X) (((X)>>11)&0x1F)
+#define DEP(X) ((X)&0x7FF)
+
+/* A template descriptor describes the execution units that are active
+   for each of the three slots.  It also specifies the location of
+   instruction group boundaries that may be present between two slots.  */
+struct ia64_templ_desc
+  {
+    int group_boundary;	/* 0=no boundary, 1=between slot 0 & 1, etc. */
+    enum ia64_unit exec_unit[3];
+    const char *name;
+  };
+
+/* The opcode table is an array of struct ia64_opcode.  */
+
+struct ia64_opcode
+  {
+    /* The opcode name.  */
+    const char *name;
+
+    /* The type of the instruction: */
+    enum ia64_insn_type type;
+
+    /* Number of output operands: */
+    int num_outputs;
+
+    /* The opcode itself.  Those bits which will be filled in with
+       operands are zeroes.  */
+    ia64_insn opcode;
+
+    /* The opcode mask.  This is used by the disassembler.  This is a
+       mask containing ones indicating those bits which must match the
+       opcode field, and zeroes indicating those bits which need not
+       match (and are presumably filled in by operands).  */
+    ia64_insn mask;
+
+    /* An array of operand codes.  Each code is an index into the
+       operand table.  They appear in the order which the operands must
+       appear in assembly code, and are terminated by a zero.  */
+    enum ia64_opnd operands[5];
+
+    /* One bit flags for the opcode.  These are primarily used to
+       indicate specific processors and environments support the
+       instructions.  The defined values are listed below. */
+    unsigned int flags;
+
+    /* Used by ia64_find_next_opcode (). */
+    short ent_index;
+
+    /* Opcode dependencies. */
+    const struct ia64_opcode_dependency *dependencies;
+  };
+
+/* Values defined for the flags field of a struct ia64_opcode.  */
+
+#define IA64_OPCODE_FIRST	(1<<0)	/* must be first in an insn group */
+#define IA64_OPCODE_X_IN_MLX	(1<<1)	/* insn is allowed in X slot of MLX */
+#define IA64_OPCODE_LAST	(1<<2)	/* must be last in an insn group */
+#define IA64_OPCODE_PRIV	(1<<3)	/* privileged instruct */
+#define IA64_OPCODE_SLOT2	(1<<4)	/* insn allowed in slot 2 only */
+#define IA64_OPCODE_NO_PRED	(1<<5)	/* insn cannot be predicated */
+#define IA64_OPCODE_PSEUDO	(1<<6)	/* insn is a pseudo-op */
+#define IA64_OPCODE_F2_EQ_F3	(1<<7)	/* constraint: F2 == F3 */
+#define IA64_OPCODE_LEN_EQ_64MCNT	(1<<8)	/* constraint: LEN == 64-CNT */
+#define IA64_OPCODE_MOD_RRBS    (1<<9)	/* modifies all rrbs in CFM */
+#define IA64_OPCODE_POSTINC	(1<<10)	/* postincrement MR3 operand */
+
+/* A macro to extract the major opcode from an instruction.  */
+#define IA64_OP(i)	(((i) >> 37) & 0xf)
+
+enum ia64_operand_class
+  {
+    IA64_OPND_CLASS_CST,	/* constant */
+    IA64_OPND_CLASS_REG,	/* register */
+    IA64_OPND_CLASS_IND,	/* indirect register */
+    IA64_OPND_CLASS_ABS,	/* absolute value */
+    IA64_OPND_CLASS_REL,	/* IP-relative value */
+  };
+
+/* The operands table is an array of struct ia64_operand.  */
+
+struct ia64_operand
+{
+  enum ia64_operand_class class;
+
+  /* Set VALUE as the operand bits for the operand of type SELF in the
+     instruction pointed to by CODE.  If an error occurs, *CODE is not
+     modified and the returned string describes the cause of the
+     error.  If no error occurs, NULL is returned.  */
+  const char *(*insert) (const struct ia64_operand *self, ia64_insn value,
+			 ia64_insn *code);
+
+  /* Extract the operand bits for an operand of type SELF from
+     instruction CODE store them in *VALUE.  If an error occurs, the
+     cause of the error is described by the string returned.  If no
+     error occurs, NULL is returned.  */
+  const char *(*extract) (const struct ia64_operand *self, ia64_insn code,
+			  ia64_insn *value);
+
+  /* A string whose meaning depends on the operand class.  */
+
+  const char *str;
+
+  struct bit_field
+    {
+      /* The number of bits in the operand.  */
+      int bits;
+
+      /* How far the operand is left shifted in the instruction.  */
+      int shift;
+    }
+  field[4];		/* no operand has more than this many bit-fields */
+
+  unsigned int flags;
+
+  const char *desc;	/* brief description */
+};
+
+/* Values defined for the flags field of a struct ia64_operand.  */
+
+/* Disassemble as signed decimal (instead of hex): */
+#define IA64_OPND_FLAG_DECIMAL_SIGNED	(1<<0)
+/* Disassemble as unsigned decimal (instead of hex): */
+#define IA64_OPND_FLAG_DECIMAL_UNSIGNED	(1<<1)
+
+#define NELEMS(a)	((int) (sizeof (a) / sizeof (a[0])))
+
+static const char*
+ins_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED,
+	  ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED)
+{
+  return "internal error---this shouldn't happen";
+}
+
+static const char*
+ext_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED,
+	  ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED)
+{
+  return "internal error---this shouldn't happen";
+}
+
+static const char*
+ins_const (const struct ia64_operand *self ATTRIBUTE_UNUSED,
+	   ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static const char*
+ext_const (const struct ia64_operand *self ATTRIBUTE_UNUSED,
+	   ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static const char*
+ins_reg (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  if (value >= 1u << self->field[0].bits)
+    return "register number out of range";
+
+  *code |= value << self->field[0].shift;
+  return 0;
+}
+
+static const char*
+ext_reg (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  *valuep = ((code >> self->field[0].shift)
+	     & ((1u << self->field[0].bits) - 1));
+  return 0;
+}
+
+static const char*
+ins_immu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  ia64_insn new = 0;
+  int i;
+
+  for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i)
+    {
+      new |= ((value & ((((ia64_insn) 1) << self->field[i].bits) - 1))
+	      << self->field[i].shift);
+      value >>= self->field[i].bits;
+    }
+  if (value)
+    return "integer operand out of range";
+
+  *code |= new;
+  return 0;
+}
+
+static const char*
+ext_immu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  uint64_t value = 0;
+  int i, bits = 0, total = 0;
+
+  for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i)
+    {
+      bits = self->field[i].bits;
+      value |= ((code >> self->field[i].shift)
+		& ((((uint64_t) 1) << bits) - 1)) << total;
+      total += bits;
+    }
+  *valuep = value;
+  return 0;
+}
+
+static const char*
+ins_immu5b (const struct ia64_operand *self, ia64_insn value,
+	    ia64_insn *code)
+{
+  if (value < 32 || value > 63)
+    return "value must be between 32 and 63";
+  return ins_immu (self, value - 32, code);
+}
+
+static const char*
+ext_immu5b (const struct ia64_operand *self, ia64_insn code,
+	    ia64_insn *valuep)
+{
+  const char *result;
+
+  result = ext_immu (self, code, valuep);
+  if (result)
+    return result;
+
+  *valuep = *valuep + 32;
+  return 0;
+}
+
+static const char*
+ins_immus8 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  if (value & 0x7)
+    return "value not an integer multiple of 8";
+  return ins_immu (self, value >> 3, code);
+}
+
+static const char*
+ext_immus8 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  const char *result;
+
+  result = ext_immu (self, code, valuep);
+  if (result)
+    return result;
+
+  *valuep = *valuep << 3;
+  return 0;
+}
+
+static const char*
+ins_imms_scaled (const struct ia64_operand *self, ia64_insn value,
+		 ia64_insn *code, int scale)
+{
+  int64_t svalue = value, sign_bit = 0;
+  ia64_insn new = 0;
+  int i;
+
+  svalue >>= scale;
+
+  for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i)
+    {
+      new |= ((svalue & ((((ia64_insn) 1) << self->field[i].bits) - 1))
+	      << self->field[i].shift);
+      sign_bit = (svalue >> (self->field[i].bits - 1)) & 1;
+      svalue >>= self->field[i].bits;
+    }
+  if ((!sign_bit && svalue != 0) || (sign_bit && svalue != -1))
+    return "integer operand out of range";
+
+  *code |= new;
+  return 0;
+}
+
+static const char*
+ext_imms_scaled (const struct ia64_operand *self, ia64_insn code,
+		 ia64_insn *valuep, int scale)
+{
+  int i, bits = 0, total = 0;
+  int64_t val = 0, sign;
+
+  for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i)
+    {
+      bits = self->field[i].bits;
+      val |= ((code >> self->field[i].shift)
+	      & ((((uint64_t) 1) << bits) - 1)) << total;
+      total += bits;
+    }
+  /* sign extend: */
+  sign = (int64_t) 1 << (total - 1);
+  val = (val ^ sign) - sign;
+
+  *valuep = (val << scale);
+  return 0;
+}
+
+static const char*
+ins_imms (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  return ins_imms_scaled (self, value, code, 0);
+}
+
+static const char*
+ins_immsu4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+  return ins_imms_scaled (self, value, code, 0);
+}
+
+static const char*
+ext_imms (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  return ext_imms_scaled (self, code, valuep, 0);
+}
+
+static const char*
+ins_immsm1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  --value;
+  return ins_imms_scaled (self, value, code, 0);
+}
+
+static const char*
+ins_immsm1u4 (const struct ia64_operand *self, ia64_insn value,
+	      ia64_insn *code)
+{
+  value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+  --value;
+  return ins_imms_scaled (self, value, code, 0);
+}
+
+static const char*
+ext_immsm1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  const char *res = ext_imms_scaled (self, code, valuep, 0);
+
+  ++*valuep;
+  return res;
+}
+
+static const char*
+ins_imms1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  return ins_imms_scaled (self, value, code, 1);
+}
+
+static const char*
+ext_imms1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  return ext_imms_scaled (self, code, valuep, 1);
+}
+
+static const char*
+ins_imms4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  return ins_imms_scaled (self, value, code, 4);
+}
+
+static const char*
+ext_imms4 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  return ext_imms_scaled (self, code, valuep, 4);
+}
+
+static const char*
+ins_imms16 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  return ins_imms_scaled (self, value, code, 16);
+}
+
+static const char*
+ext_imms16 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  return ext_imms_scaled (self, code, valuep, 16);
+}
+
+static const char*
+ins_cimmu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  ia64_insn mask = (((ia64_insn) 1) << self->field[0].bits) - 1;
+  return ins_immu (self, value ^ mask, code);
+}
+
+static const char*
+ext_cimmu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  const char *result;
+  ia64_insn mask;
+
+  mask = (((ia64_insn) 1) << self->field[0].bits) - 1;
+  result = ext_immu (self, code, valuep);
+  if (!result)
+    {
+      mask = (((ia64_insn) 1) << self->field[0].bits) - 1;
+      *valuep ^= mask;
+    }
+  return result;
+}
+
+static const char*
+ins_cnt (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  --value;
+  if (value >= ((uint64_t) 1) << self->field[0].bits)
+    return "count out of range";
+
+  *code |= value << self->field[0].shift;
+  return 0;
+}
+
+static const char*
+ext_cnt (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  *valuep = ((code >> self->field[0].shift)
+	     & ((((uint64_t) 1) << self->field[0].bits) - 1)) + 1;
+  return 0;
+}
+
+static const char*
+ins_cnt2b (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  --value;
+
+  if (value > 2)
+    return "count must be in range 1..3";
+
+  *code |= value << self->field[0].shift;
+  return 0;
+}
+
+static const char*
+ext_cnt2b (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  *valuep = ((code >> self->field[0].shift) & 0x3) + 1;
+  return 0;
+}
+
+static const char*
+ins_cnt2c (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  switch (value)
+    {
+    case 0:	value = 0; break;
+    case 7:	value = 1; break;
+    case 15:	value = 2; break;
+    case 16:	value = 3; break;
+    default:	return "count must be 0, 7, 15, or 16";
+    }
+  *code |= value << self->field[0].shift;
+  return 0;
+}
+
+static const char*
+ext_cnt2c (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  ia64_insn value;
+
+  value = (code >> self->field[0].shift) & 0x3;
+  switch (value)
+    {
+    case 0: value =  0; break;
+    case 1: value =  7; break;
+    case 2: value = 15; break;
+    case 3: value = 16; break;
+    }
+  *valuep = value;
+  return 0;
+}
+
+static const char*
+ins_inc3 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code)
+{
+  int64_t val = value;
+  uint64_t sign = 0;
+
+  if (val < 0)
+    {
+      sign = 0x4;
+      value = -value;
+    }
+  switch (value)
+    {
+    case  1:	value = 3; break;
+    case  4:	value = 2; break;
+    case  8:	value = 1; break;
+    case 16:	value = 0; break;
+    default:	return "count must be +/- 1, 4, 8, or 16";
+    }
+  *code |= (sign | value) << self->field[0].shift;
+  return 0;
+}
+
+static const char*
+ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep)
+{
+  int64_t val;
+  int negate;
+
+  val = (code >> self->field[0].shift) & 0x7;
+  negate = val & 0x4;
+  switch (val & 0x3)
+    {
+    case 0: val = 16; break;
+    case 1: val =  8; break;
+    case 2: val =  4; break;
+    case 3: val =  1; break;
+    }
+  if (negate)
+    val = -val;
+
+  *valuep = val;
+  return 0;
+}
+
+#define CST	IA64_OPND_CLASS_CST
+#define REG	IA64_OPND_CLASS_REG
+#define IND	IA64_OPND_CLASS_IND
+#define ABS	IA64_OPND_CLASS_ABS
+#define REL	IA64_OPND_CLASS_REL
+
+#define SDEC	IA64_OPND_FLAG_DECIMAL_SIGNED
+#define UDEC	IA64_OPND_FLAG_DECIMAL_UNSIGNED
+
+const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] =
+  {
+    /* constants: */
+    { CST, ins_const, ext_const, "NIL",		{{ 0, 0}}, 0, "<none>" },
+    { CST, ins_const, ext_const, "ar.csd",	{{ 0, 0}}, 0, "ar.csd" },
+    { CST, ins_const, ext_const, "ar.ccv",	{{ 0, 0}}, 0, "ar.ccv" },
+    { CST, ins_const, ext_const, "ar.pfs",	{{ 0, 0}}, 0, "ar.pfs" },
+    { CST, ins_const, ext_const, "1",		{{ 0, 0}}, 0, "1" },
+    { CST, ins_const, ext_const, "8",		{{ 0, 0}}, 0, "8" },
+    { CST, ins_const, ext_const, "16",		{{ 0, 0}}, 0, "16" },
+    { CST, ins_const, ext_const, "r0",		{{ 0, 0}}, 0, "r0" },
+    { CST, ins_const, ext_const, "ip",		{{ 0, 0}}, 0, "ip" },
+    { CST, ins_const, ext_const, "pr",		{{ 0, 0}}, 0, "pr" },
+    { CST, ins_const, ext_const, "pr.rot",	{{ 0, 0}}, 0, "pr.rot" },
+    { CST, ins_const, ext_const, "psr",		{{ 0, 0}}, 0, "psr" },
+    { CST, ins_const, ext_const, "psr.l",	{{ 0, 0}}, 0, "psr.l" },
+    { CST, ins_const, ext_const, "psr.um",	{{ 0, 0}}, 0, "psr.um" },
+
+    /* register operands: */
+    { REG, ins_reg,   ext_reg,	"ar", {{ 7, 20}}, 0,		/* AR3 */
+      "an application register" },
+    { REG, ins_reg,   ext_reg,	 "b", {{ 3,  6}}, 0,		/* B1 */
+      "a branch register" },
+    { REG, ins_reg,   ext_reg,	 "b", {{ 3, 13}}, 0,		/* B2 */
+      "a branch register"},
+    { REG, ins_reg,   ext_reg,	"cr", {{ 7, 20}}, 0,		/* CR */
+      "a control register"},
+    { REG, ins_reg,   ext_reg,	 "f", {{ 7,  6}}, 0,		/* F1 */
+      "a floating-point register" },
+    { REG, ins_reg,   ext_reg,	 "f", {{ 7, 13}}, 0,		/* F2 */
+      "a floating-point register" },
+    { REG, ins_reg,   ext_reg,	 "f", {{ 7, 20}}, 0,		/* F3 */
+      "a floating-point register" },
+    { REG, ins_reg,   ext_reg,	 "f", {{ 7, 27}}, 0,		/* F4 */
+      "a floating-point register" },
+    { REG, ins_reg,   ext_reg,	 "p", {{ 6,  6}}, 0,		/* P1 */
+      "a predicate register" },
+    { REG, ins_reg,   ext_reg,	 "p", {{ 6, 27}}, 0,		/* P2 */
+      "a predicate register" },
+    { REG, ins_reg,   ext_reg,	 "r", {{ 7,  6}}, 0,		/* R1 */
+      "a general register" },
+    { REG, ins_reg,   ext_reg,	 "r", {{ 7, 13}}, 0,		/* R2 */
+      "a general register" },
+    { REG, ins_reg,   ext_reg,	 "r", {{ 7, 20}}, 0,		/* R3 */
+      "a general register" },
+    { REG, ins_reg,   ext_reg,	 "r", {{ 2, 20}}, 0,		/* R3_2 */
+      "a general register r0-r3" },
+
+    /* memory operands: */
+    { IND, ins_reg,   ext_reg,	"",      {{7, 20}}, 0,		/* MR3 */
+      "a memory address" },
+
+    /* indirect operands: */
+    { IND, ins_reg,   ext_reg,	"cpuid", {{7, 20}}, 0,		/* CPUID_R3 */
+      "a cpuid register" },
+    { IND, ins_reg,   ext_reg,	"dbr",   {{7, 20}}, 0,		/* DBR_R3 */
+      "a dbr register" },
+    { IND, ins_reg,   ext_reg,	"dtr",   {{7, 20}}, 0,		/* DTR_R3 */
+      "a dtr register" },
+    { IND, ins_reg,   ext_reg,	"itr",   {{7, 20}}, 0,		/* ITR_R3 */
+      "an itr register" },
+    { IND, ins_reg,   ext_reg,	"ibr",   {{7, 20}}, 0,		/* IBR_R3 */
+      "an ibr register" },
+    { IND, ins_reg,   ext_reg,	"msr",   {{7, 20}}, 0,		/* MSR_R3 */
+      "an msr register" },
+    { IND, ins_reg,   ext_reg,	"pkr",   {{7, 20}}, 0,		/* PKR_R3 */
+      "a pkr register" },
+    { IND, ins_reg,   ext_reg,	"pmc",   {{7, 20}}, 0,		/* PMC_R3 */
+      "a pmc register" },
+    { IND, ins_reg,   ext_reg,	"pmd",   {{7, 20}}, 0,		/* PMD_R3 */
+      "a pmd register" },
+    { IND, ins_reg,   ext_reg,	"rr",    {{7, 20}}, 0,		/* RR_R3 */
+      "an rr register" },
+
+    /* immediate operands: */
+    { ABS, ins_cimmu, ext_cimmu, 0, {{ 5, 20 }}, UDEC,		/* CCNT5 */
+      "a 5-bit count (0-31)" },
+    { ABS, ins_cnt,   ext_cnt,   0, {{ 2, 27 }}, UDEC,		/* CNT2a */
+      "a 2-bit count (1-4)" },
+    { ABS, ins_cnt2b, ext_cnt2b, 0, {{ 2, 27 }}, UDEC,		/* CNT2b */
+      "a 2-bit count (1-3)" },
+    { ABS, ins_cnt2c, ext_cnt2c, 0, {{ 2, 30 }}, UDEC,		/* CNT2c */
+      "a count (0, 7, 15, or 16)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 5, 14}}, UDEC,		/* CNT5 */
+      "a 5-bit count (0-31)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 6, 27}}, UDEC,		/* CNT6 */
+      "a 6-bit count (0-63)" },
+    { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 20}}, UDEC,		/* CPOS6a */
+      "a 6-bit bit pos (0-63)" },
+    { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 14}}, UDEC,		/* CPOS6b */
+      "a 6-bit bit pos (0-63)" },
+    { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 31}}, UDEC,		/* CPOS6c */
+      "a 6-bit bit pos (0-63)" },
+    { ABS, ins_imms,  ext_imms,  0, {{ 1, 36}}, SDEC,		/* IMM1 */
+      "a 1-bit integer (-1, 0)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 2, 13}}, UDEC,		/* IMMU2 */
+      "a 2-bit unsigned (0-3)" },
+    { ABS, ins_immu5b,  ext_immu5b,  0, {{ 5, 14}}, UDEC,	/* IMMU5b */
+      "a 5-bit unsigned (32 + (0-31))" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 7, 13}}, 0,		/* IMMU7a */
+      "a 7-bit unsigned (0-127)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 7, 20}}, 0,		/* IMMU7b */
+      "a 7-bit unsigned (0-127)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 7, 13}}, UDEC,		/* SOF */
+      "a frame size (register count)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 7, 20}}, UDEC,		/* SOL */
+      "a local register count" },
+    { ABS, ins_immus8,ext_immus8,0, {{ 4, 27}}, UDEC,		/* SOR */
+      "a rotating register count (integer multiple of 8)" },
+    { ABS, ins_imms,  ext_imms,  0,				/* IMM8 */
+      {{ 7, 13}, { 1, 36}}, SDEC,
+      "an 8-bit integer (-128-127)" },
+    { ABS, ins_immsu4,  ext_imms,  0,				/* IMM8U4 */
+      {{ 7, 13}, { 1, 36}}, SDEC,
+      "an 8-bit signed integer for 32-bit unsigned compare (-128-127)" },
+    { ABS, ins_immsm1,  ext_immsm1,  0,				/* IMM8M1 */
+      {{ 7, 13}, { 1, 36}}, SDEC,
+      "an 8-bit integer (-127-128)" },
+    { ABS, ins_immsm1u4,  ext_immsm1,  0,			/* IMM8M1U4 */
+      {{ 7, 13}, { 1, 36}}, SDEC,
+      "an 8-bit integer for 32-bit unsigned compare (-127-(-1),1-128,0x100000000)" },
+    { ABS, ins_immsm1,  ext_immsm1,  0,				/* IMM8M1U8 */
+      {{ 7, 13}, { 1, 36}}, SDEC,
+      "an 8-bit integer for 64-bit unsigned compare (-127-(-1),1-128,0x10000000000000000)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 2, 33}, { 7, 20}}, 0,	/* IMMU9 */
+      "a 9-bit unsigned (0-511)" },
+    { ABS, ins_imms,  ext_imms,  0,				/* IMM9a */
+      {{ 7,  6}, { 1, 27}, { 1, 36}}, SDEC,
+      "a 9-bit integer (-256-255)" },
+    { ABS, ins_imms,  ext_imms, 0,				/* IMM9b */
+      {{ 7, 13}, { 1, 27}, { 1, 36}}, SDEC,
+      "a 9-bit integer (-256-255)" },
+    { ABS, ins_imms,  ext_imms, 0,				/* IMM14 */
+      {{ 7, 13}, { 6, 27}, { 1, 36}}, SDEC,
+      "a 14-bit integer (-8192-8191)" },
+    { ABS, ins_imms1, ext_imms1, 0,				/* IMM17 */
+      {{ 7,  6}, { 8, 24}, { 1, 36}}, 0,
+      "a 17-bit integer (-65536-65535)" },
+    { ABS, ins_immu,  ext_immu,  0, {{20,  6}, { 1, 36}}, 0,	/* IMMU21 */
+      "a 21-bit unsigned" },
+    { ABS, ins_imms,  ext_imms,  0,				/* IMM22 */
+      {{ 7, 13}, { 9, 27}, { 5, 22}, { 1, 36}}, SDEC,
+      "a 22-bit signed integer" },
+    { ABS, ins_immu,  ext_immu,  0,				/* IMMU24 */
+      {{21,  6}, { 2, 31}, { 1, 36}}, 0,
+      "a 24-bit unsigned" },
+    { ABS, ins_imms16,ext_imms16,0, {{27,  6}, { 1, 36}}, 0,	/* IMM44 */
+      "a 44-bit unsigned (least 16 bits ignored/zeroes)" },
+    { ABS, ins_rsvd,  ext_rsvd,	0, {{0,  0}}, 0,		/* IMMU62 */
+      "a 62-bit unsigned" },
+    { ABS, ins_rsvd,  ext_rsvd,	0, {{0,  0}}, 0,		/* IMMU64 */
+      "a 64-bit unsigned" },
+    { ABS, ins_inc3,  ext_inc3,  0, {{ 3, 13}}, SDEC,		/* INC3 */
+      "an increment (+/- 1, 4, 8, or 16)" },
+    { ABS, ins_cnt,   ext_cnt,   0, {{ 4, 27}}, UDEC,		/* LEN4 */
+      "a 4-bit length (1-16)" },
+    { ABS, ins_cnt,   ext_cnt,   0, {{ 6, 27}}, UDEC,		/* LEN6 */
+      "a 6-bit length (1-64)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 4, 20}},	0,		/* MBTYPE4 */
+      "a mix type (@rev, @mix, @shuf, @alt, or @brcst)" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 8, 20}},	0,		/* MBTYPE8 */
+      "an 8-bit mix type" },
+    { ABS, ins_immu,  ext_immu,  0, {{ 6, 14}}, UDEC,		/* POS6 */
+      "a 6-bit bit pos (0-63)" },
+    { REL, ins_imms4, ext_imms4, 0, {{ 7,  6}, { 2, 33}}, 0,	/* TAG13 */
+      "a branch tag" },
+    { REL, ins_imms4, ext_imms4, 0, {{ 9, 24}}, 0,		/* TAG13b */
+      "a branch tag" },
+    { REL, ins_imms4, ext_imms4, 0, {{20,  6}, { 1, 36}}, 0,	/* TGT25 */
+      "a branch target" },
+    { REL, ins_imms4, ext_imms4, 0,				/* TGT25b */
+      {{ 7,  6}, {13, 20}, { 1, 36}}, 0,
+      "a branch target" },
+    { REL, ins_imms4, ext_imms4, 0, {{20, 13}, { 1, 36}}, 0,	/* TGT25c */
+      "a branch target" },
+    { REL, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0,                  /* TGT64  */
+      "a branch target" },
+
+    { ABS, ins_const, ext_const, 0, {{0, 0}}, 0,		/* LDXMOV */
+      "ldxmov target" },
+  };
+
+
+/* ia64-asmtab.h -- Header for compacted IA-64 opcode tables.
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Bob Manson of Cygnus Support <manson at cygnus.com>
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   2, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+/* The primary opcode table is made up of the following: */
+struct ia64_main_table
+{
+  /* The entry in the string table that corresponds to the name of this
+     opcode. */
+  unsigned short name_index;
+
+  /* The type of opcode; corresponds to the TYPE field in
+     struct ia64_opcode. */
+  unsigned char opcode_type;
+
+  /* The number of outputs for this opcode. */
+  unsigned char num_outputs;
+
+  /* The base insn value for this opcode.  It may be modified by completers. */
+  ia64_insn opcode;
+
+  /* The mask of valid bits in OPCODE. Zeros indicate operand fields. */
+  ia64_insn mask;
+
+  /* The operands of this instruction.  Corresponds to the OPERANDS field
+     in struct ia64_opcode. */
+  unsigned char operands[5];
+
+  /* The flags for this instruction.  Corresponds to the FLAGS field in
+     struct ia64_opcode. */
+  short flags;
+
+  /* The tree of completers for this instruction; this is an offset into
+     completer_table. */
+  short completers;
+};
+
+/* Each instruction has a set of possible "completers", or additional
+   suffixes that can alter the instruction's behavior, and which has
+   potentially different dependencies.
+
+   The completer entries modify certain bits in the instruction opcode.
+   Which bits are to be modified are marked by the BITS, MASK and
+   OFFSET fields.  The completer entry may also note dependencies for the
+   opcode.
+
+   These completers are arranged in a DAG; the pointers are indexes
+   into the completer_table array.  The completer DAG is searched by
+   find_completer () and ia64_find_matching_opcode ().
+
+   Note that each completer needs to be applied in turn, so that if we
+   have the instruction
+	cmp.lt.unc
+   the completer entries for both "lt" and "unc" would need to be applied
+   to the opcode's value.
+
+   Some instructions do not require any completers; these contain an
+   empty completer entry.  Instructions that require a completer do
+   not contain an empty entry.
+
+   Terminal completers (those completers that validly complete an
+   instruction) are marked by having the TERMINAL_COMPLETER flag set.
+
+   Only dependencies listed in the terminal completer for an opcode are
+   considered to apply to that opcode instance. */
+
+struct ia64_completer_table
+{
+  /* The bit value that this completer sets. */
+  unsigned int bits;
+
+  /* And its mask. 1s are bits that are to be modified in the
+     instruction. */
+  unsigned int mask;
+
+  /* The entry in the string table that corresponds to the name of this
+     completer. */
+  unsigned short name_index;
+
+  /* An alternative completer, or -1 if this is the end of the chain. */
+  short alternative;
+
+  /* A pointer to the DAG of completers that can potentially follow
+     this one, or -1. */
+  short subentries;
+
+  /* The bit offset in the instruction where BITS and MASK should be
+     applied. */
+  unsigned char offset : 7;
+
+  unsigned char terminal_completer : 1;
+
+  /* Index into the dependency list table */
+  short dependencies;
+};
+
+/* This contains sufficient information for the disassembler to resolve
+   the complete name of the original instruction.  */
+struct ia64_dis_names
+{
+  /* COMPLETER_INDEX represents the tree of completers that make up
+     the instruction.  The LSB represents the top of the tree for the
+     specified instruction.
+
+     A 0 bit indicates to go to the next alternate completer via the
+     alternative field; a 1 bit indicates that the current completer
+     is part of the instruction, and to go down the subentries index.
+     We know we've reached the final completer when we run out of 1
+     bits.
+
+     There is always at least one 1 bit. */
+  unsigned int completer_index : 20;
+
+  /* The index in the main_table[] array for the instruction. */
+  unsigned short insn_index : 11;
+
+  /* If set, the next entry in this table is an alternate possibility
+     for this instruction encoding.  Which one to use is determined by
+     the instruction type and other factors (see opcode_verify ()).  */
+  unsigned int next_flag : 1;
+
+  /* The disassembly priority of this entry among instructions. */
+  unsigned short priority;
+};
+
+static const char * const ia64_strings[] = {
+  "", "0", "1", "a", "acq", "add", "addl", "addp4", "adds", "alloc", "and",
+  "andcm", "b", "bias", "br", "break", "brl", "brp", "bsw", "c", "call",
+  "cexit", "chk", "cloop", "clr", "clrrrb", "cmp", "cmp4", "cmp8xchg16",
+  "cmpxchg1", "cmpxchg2", "cmpxchg4", "cmpxchg8", "cond", "cover", "ctop",
+  "czx1", "czx2", "d", "dep", "dpnt", "dptk", "e", "epc", "eq", "excl",
+  "exit", "exp", "extr", "f", "fabs", "fadd", "famax", "famin", "fand",
+  "fandcm", "fault", "fc", "fchkf", "fclass", "fclrf", "fcmp", "fcvt",
+  "fetchadd4", "fetchadd8", "few", "fill", "flushrs", "fma", "fmax",
+  "fmerge", "fmin", "fmix", "fmpy", "fms", "fneg", "fnegabs", "fnma",
+  "fnmpy", "fnorm", "for", "fpabs", "fpack", "fpamax", "fpamin", "fpcmp",
+  "fpcvt", "fpma", "fpmax", "fpmerge", "fpmin", "fpmpy", "fpms", "fpneg",
+  "fpnegabs", "fpnma", "fpnmpy", "fprcpa", "fprsqrta", "frcpa", "frsqrta",
+  "fselect", "fsetc", "fsub", "fswap", "fsxt", "fwb", "fx", "fxor", "fxu",
+  "g", "ga", "ge", "getf", "geu", "gt", "gtu", "h", "hint", "hu", "i", "ia",
+  "imp", "invala", "itc", "itr", "l", "ld1", "ld16", "ld2", "ld4", "ld8",
+  "ldf", "ldf8", "ldfd", "ldfe", "ldfp8", "ldfpd", "ldfps", "ldfs", "le",
+  "leu", "lfetch", "loadrs", "loop", "lr", "lt", "ltu", "lu", "m", "many",
+  "mf", "mix1", "mix2", "mix4", "mov", "movl", "mux1", "mux2", "nc", "ne",
+  "neq", "nge", "ngt", "nl", "nle", "nlt", "nm", "nop", "nr", "ns", "nt1",
+  "nt2", "nta", "nz", "or", "orcm", "ord", "pack2", "pack4", "padd1",
+  "padd2", "padd4", "pavg1", "pavg2", "pavgsub1", "pavgsub2", "pcmp1",
+  "pcmp2", "pcmp4", "pmax1", "pmax2", "pmin1", "pmin2", "pmpy2", "pmpyshr2",
+  "popcnt", "pr", "probe", "psad1", "pshl2", "pshl4", "pshladd2", "pshr2",
+  "pshr4", "pshradd2", "psub1", "psub2", "psub4", "ptc", "ptr", "r", "raz",
+  "rel", "ret", "rfi", "rsm", "rum", "rw", "s", "s0", "s1", "s2", "s3",
+  "sa", "se", "setf", "shl", "shladd", "shladdp4", "shr", "shrp", "sig",
+  "spill", "spnt", "sptk", "srlz", "ssm", "sss", "st1", "st16", "st2",
+  "st4", "st8", "stf", "stf8", "stfd", "stfe", "stfs", "sub", "sum", "sxt1",
+  "sxt2", "sxt4", "sync", "tak", "tbit", "tf", "thash", "tnat", "tpa",
+  "trunc", "ttag", "u", "unc", "unord", "unpack1", "unpack2", "unpack4",
+  "uss", "uus", "uuu", "vmsw", "w", "wexit", "wtop", "x", "xchg1", "xchg2",
+  "xchg4", "xchg8", "xf", "xma", "xmpy", "xor", "xuf", "z", "zxt1", "zxt2",
+  "zxt4",
+};
+
+static const struct ia64_dependency
+dependencies[] = {
+  { "ALAT", 0, 0, 0, -1, NULL, },
+  { "AR[BSP]", 26, 0, 2, 17, NULL, },
+  { "AR[BSPSTORE]", 26, 0, 2, 18, NULL, },
+  { "AR[CCV]", 26, 0, 2, 32, NULL, },
+  { "AR[CFLG]", 26, 0, 2, 27, NULL, },
+  { "AR[CSD]", 26, 0, 2, 25, NULL, },
+  { "AR[EC]", 26, 0, 2, 66, NULL, },
+  { "AR[EFLAG]", 26, 0, 2, 24, NULL, },
+  { "AR[FCR]", 26, 0, 2, 21, NULL, },
+  { "AR[FDR]", 26, 0, 2, 30, NULL, },
+  { "AR[FIR]", 26, 0, 2, 29, NULL, },
+  { "AR[FPSR].sf0.controls", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf1.controls", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf2.controls", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf3.controls", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf0.flags", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf1.flags", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf2.flags", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].sf3.flags", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].traps", 30, 0, 2, -1, NULL, },
+  { "AR[FPSR].rv", 30, 0, 2, -1, NULL, },
+  { "AR[FSR]", 26, 0, 2, 28, NULL, },
+  { "AR[ITC]", 26, 0, 2, 44, NULL, },
+  { "AR[K%], % in 0 - 7", 1, 0, 2, -1, NULL, },
+  { "AR[LC]", 26, 0, 2, 65, NULL, },
+  { "AR[PFS]", 26, 0, 2, 64, NULL, },
+  { "AR[PFS]", 26, 0, 2, 64, NULL, },
+  { "AR[PFS]", 26, 0, 0, 64, NULL, },
+  { "AR[RNAT]", 26, 0, 2, 19, NULL, },
+  { "AR[RSC]", 26, 0, 2, 16, NULL, },
+  { "AR[SSD]", 26, 0, 2, 26, NULL, },
+  { "AR[UNAT]{%}, % in 0 - 63", 2, 0, 2, -1, NULL, },
+  { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 0, 0, -1, NULL, },
+  { "AR%, % in 48-63, 112-127", 4, 0, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 0, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 0, 0, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 0, 2, -1, NULL, },
+  { "CFM", 6, 0, 2, -1, NULL, },
+  { "CFM", 6, 0, 2, -1, NULL, },
+  { "CFM", 6, 0, 2, -1, NULL, },
+  { "CFM", 6, 0, 2, -1, NULL, },
+  { "CFM", 6, 0, 0, -1, NULL, },
+  { "CPUID#", 7, 0, 5, -1, NULL, },
+  { "CR[CMCV]", 27, 0, 3, 74, NULL, },
+  { "CR[DCR]", 27, 0, 3, 0, NULL, },
+  { "CR[EOI]", 27, 0, 7, 67, "SC Section 5.8.3.4, \"End of External Interrupt Register (EOI Ð CR67)\" on page 2:119", },
+  { "CR[GPTA]", 27, 0, 3, 9, NULL, },
+  { "CR[IFA]", 27, 0, 1, 20, NULL, },
+  { "CR[IFA]", 27, 0, 3, 20, NULL, },
+  { "CR[IFS]", 27, 0, 3, 23, NULL, },
+  { "CR[IFS]", 27, 0, 1, 23, NULL, },
+  { "CR[IFS]", 27, 0, 1, 23, NULL, },
+  { "CR[IHA]", 27, 0, 3, 25, NULL, },
+  { "CR[IIM]", 27, 0, 3, 24, NULL, },
+  { "CR[IIP]", 27, 0, 3, 19, NULL, },
+  { "CR[IIP]", 27, 0, 1, 19, NULL, },
+  { "CR[IIPA]", 27, 0, 3, 22, NULL, },
+  { "CR[IPSR]", 27, 0, 3, 16, NULL, },
+  { "CR[IPSR]", 27, 0, 1, 16, NULL, },
+  { "CR[IRR%], % in 0 - 3", 8, 0, 3, -1, NULL, },
+  { "CR[ISR]", 27, 0, 3, 17, NULL, },
+  { "CR[ITIR]", 27, 0, 3, 21, NULL, },
+  { "CR[ITIR]", 27, 0, 1, 21, NULL, },
+  { "CR[ITM]", 27, 0, 3, 1, NULL, },
+  { "CR[ITV]", 27, 0, 3, 72, NULL, },
+  { "CR[IVA]", 27, 0, 4, 2, NULL, },
+  { "CR[IVR]", 27, 0, 7, 65, "SC Section 5.8.3.2, \"External Interrupt Vector Register (IVR Ð CR65)\" on page 2:118", },
+  { "CR[LID]", 27, 0, 7, 64, "SC Section 5.8.3.1, \"Local ID (LID Ð CR64)\" on page 2:117", },
+  { "CR[LRR%], % in 0 - 1", 9, 0, 3, -1, NULL, },
+  { "CR[PMV]", 27, 0, 3, 73, NULL, },
+  { "CR[PTA]", 27, 0, 3, 8, NULL, },
+  { "CR[TPR]", 27, 0, 3, 66, NULL, },
+  { "CR[TPR]", 27, 0, 7, 66, "SC Section 5.8.3.3, \"Task Priority Register (TPR Ð CR66)\" on page 2:119", },
+  { "CR[TPR]", 27, 0, 1, 66, NULL, },
+  { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 0, 0, -1, NULL, },
+  { "DBR#", 11, 0, 2, -1, NULL, },
+  { "DBR#", 11, 0, 3, -1, NULL, },
+  { "DTC", 0, 0, 3, -1, NULL, },
+  { "DTC", 0, 0, 2, -1, NULL, },
+  { "DTC", 0, 0, 0, -1, NULL, },
+  { "DTC", 0, 0, 2, -1, NULL, },
+  { "DTC_LIMIT*", 0, 0, 2, -1, NULL, },
+  { "DTR", 0, 0, 3, -1, NULL, },
+  { "DTR", 0, 0, 2, -1, NULL, },
+  { "DTR", 0, 0, 3, -1, NULL, },
+  { "DTR", 0, 0, 0, -1, NULL, },
+  { "DTR", 0, 0, 2, -1, NULL, },
+  { "FR%, % in 0 - 1", 12, 0, 0, -1, NULL, },
+  { "FR%, % in 2 - 127", 13, 0, 2, -1, NULL, },
+  { "FR%, % in 2 - 127", 13, 0, 0, -1, NULL, },
+  { "GR0", 14, 0, 0, -1, NULL, },
+  { "GR%, % in 1 - 127", 15, 0, 0, -1, NULL, },
+  { "GR%, % in 1 - 127", 15, 0, 2, -1, NULL, },
+  { "IBR#", 16, 0, 2, -1, NULL, },
+  { "InService*", 17, 0, 3, -1, NULL, },
+  { "InService*", 17, 0, 2, -1, NULL, },
+  { "InService*", 17, 0, 2, -1, NULL, },
+  { "IP", 0, 0, 0, -1, NULL, },
+  { "ITC", 0, 0, 4, -1, NULL, },
+  { "ITC", 0, 0, 2, -1, NULL, },
+  { "ITC", 0, 0, 0, -1, NULL, },
+  { "ITC", 0, 0, 4, -1, NULL, },
+  { "ITC", 0, 0, 2, -1, NULL, },
+  { "ITC_LIMIT*", 0, 0, 2, -1, NULL, },
+  { "ITR", 0, 0, 2, -1, NULL, },
+  { "ITR", 0, 0, 4, -1, NULL, },
+  { "ITR", 0, 0, 2, -1, NULL, },
+  { "ITR", 0, 0, 0, -1, NULL, },
+  { "ITR", 0, 0, 4, -1, NULL, },
+  { "memory", 0, 0, 0, -1, NULL, },
+  { "MSR#", 18, 0, 5, -1, NULL, },
+  { "PKR#", 19, 0, 3, -1, NULL, },
+  { "PKR#", 19, 0, 0, -1, NULL, },
+  { "PKR#", 19, 0, 2, -1, NULL, },
+  { "PKR#", 19, 0, 2, -1, NULL, },
+  { "PMC#", 20, 0, 2, -1, NULL, },
+  { "PMC#", 20, 0, 7, -1, "SC Section 7.2.1, \"Generic Performance Counter Registers\" for PMC[0].fr on page 2:150", },
+  { "PMD#", 21, 0, 2, -1, NULL, },
+  { "PR0", 0, 0, 0, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 0, 2, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 0, 2, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 0, 0, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 0, 2, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 0, 2, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 0, 0, -1, NULL, },
+  { "PR63", 24, 0, 2, -1, NULL, },
+  { "PR63", 24, 0, 2, -1, NULL, },
+  { "PR63", 24, 0, 0, -1, NULL, },
+  { "PSR.ac", 28, 0, 1, 3, NULL, },
+  { "PSR.ac", 28, 0, 3, 3, NULL, },
+  { "PSR.ac", 28, 0, 2, 3, NULL, },
+  { "PSR.ac", 28, 0, 2, 3, NULL, },
+  { "PSR.be", 28, 0, 1, 1, NULL, },
+  { "PSR.be", 28, 0, 3, 1, NULL, },
+  { "PSR.be", 28, 0, 2, 1, NULL, },
+  { "PSR.be", 28, 0, 2, 1, NULL, },
+  { "PSR.bn", 28, 0, 2, 44, NULL, },
+  { "PSR.cpl", 28, 0, 1, 32, NULL, },
+  { "PSR.cpl", 28, 0, 2, 32, NULL, },
+  { "PSR.da", 28, 0, 2, 38, NULL, },
+  { "PSR.db", 28, 0, 3, 24, NULL, },
+  { "PSR.db", 28, 0, 2, 24, NULL, },
+  { "PSR.db", 28, 0, 2, 24, NULL, },
+  { "PSR.dd", 28, 0, 2, 39, NULL, },
+  { "PSR.dfh", 28, 0, 3, 19, NULL, },
+  { "PSR.dfh", 28, 0, 2, 19, NULL, },
+  { "PSR.dfh", 28, 0, 2, 19, NULL, },
+  { "PSR.dfl", 28, 0, 3, 18, NULL, },
+  { "PSR.dfl", 28, 0, 2, 18, NULL, },
+  { "PSR.dfl", 28, 0, 2, 18, NULL, },
+  { "PSR.di", 28, 0, 3, 22, NULL, },
+  { "PSR.di", 28, 0, 2, 22, NULL, },
+  { "PSR.di", 28, 0, 2, 22, NULL, },
+  { "PSR.dt", 28, 0, 3, 17, NULL, },
+  { "PSR.dt", 28, 0, 2, 17, NULL, },
+  { "PSR.dt", 28, 0, 2, 17, NULL, },
+  { "PSR.ed", 28, 0, 2, 43, NULL, },
+  { "PSR.i", 28, 0, 2, 14, NULL, },
+  { "PSR.ia", 28, 0, 0, 14, NULL, },
+  { "PSR.ic", 28, 0, 2, 13, NULL, },
+  { "PSR.ic", 28, 0, 3, 13, NULL, },
+  { "PSR.ic", 28, 0, 2, 13, NULL, },
+  { "PSR.id", 28, 0, 0, 14, NULL, },
+  { "PSR.is", 28, 0, 0, 14, NULL, },
+  { "PSR.it", 28, 0, 2, 14, NULL, },
+  { "PSR.lp", 28, 0, 2, 25, NULL, },
+  { "PSR.lp", 28, 0, 3, 25, NULL, },
+  { "PSR.lp", 28, 0, 2, 25, NULL, },
+  { "PSR.mc", 28, 0, 2, 35, NULL, },
+  { "PSR.mfh", 28, 0, 2, 5, NULL, },
+  { "PSR.mfl", 28, 0, 2, 4, NULL, },
+  { "PSR.pk", 28, 0, 3, 15, NULL, },
+  { "PSR.pk", 28, 0, 2, 15, NULL, },
+  { "PSR.pk", 28, 0, 2, 15, NULL, },
+  { "PSR.pp", 28, 0, 2, 21, NULL, },
+  { "PSR.ri", 28, 0, 0, 41, NULL, },
+  { "PSR.rt", 28, 0, 2, 27, NULL, },
+  { "PSR.rt", 28, 0, 3, 27, NULL, },
+  { "PSR.rt", 28, 0, 2, 27, NULL, },
+  { "PSR.si", 28, 0, 2, 23, NULL, },
+  { "PSR.si", 28, 0, 3, 23, NULL, },
+  { "PSR.si", 28, 0, 2, 23, NULL, },
+  { "PSR.sp", 28, 0, 2, 20, NULL, },
+  { "PSR.sp", 28, 0, 3, 20, NULL, },
+  { "PSR.sp", 28, 0, 2, 20, NULL, },
+  { "PSR.ss", 28, 0, 2, 40, NULL, },
+  { "PSR.tb", 28, 0, 3, 26, NULL, },
+  { "PSR.tb", 28, 0, 2, 26, NULL, },
+  { "PSR.tb", 28, 0, 2, 26, NULL, },
+  { "PSR.up", 28, 0, 2, 2, NULL, },
+  { "PSR.vm", 28, 0, 1, 46, NULL, },
+  { "PSR.vm", 28, 0, 2, 46, NULL, },
+  { "RR#", 25, 0, 3, -1, NULL, },
+  { "RR#", 25, 0, 2, -1, NULL, },
+  { "RSE", 29, 0, 2, -1, NULL, },
+  { "ALAT", 0, 1, 0, -1, NULL, },
+  { "AR[BSP]", 26, 1, 2, 17, NULL, },
+  { "AR[BSPSTORE]", 26, 1, 2, 18, NULL, },
+  { "AR[CCV]", 26, 1, 2, 32, NULL, },
+  { "AR[CFLG]", 26, 1, 2, 27, NULL, },
+  { "AR[CSD]", 26, 1, 2, 25, NULL, },
+  { "AR[EC]", 26, 1, 2, 66, NULL, },
+  { "AR[EFLAG]", 26, 1, 2, 24, NULL, },
+  { "AR[FCR]", 26, 1, 2, 21, NULL, },
+  { "AR[FDR]", 26, 1, 2, 30, NULL, },
+  { "AR[FIR]", 26, 1, 2, 29, NULL, },
+  { "AR[FPSR].sf0.controls", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf1.controls", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf2.controls", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf3.controls", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf0.flags", 30, 1, 0, -1, NULL, },
+  { "AR[FPSR].sf0.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf0.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf1.flags", 30, 1, 0, -1, NULL, },
+  { "AR[FPSR].sf1.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf1.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf2.flags", 30, 1, 0, -1, NULL, },
+  { "AR[FPSR].sf2.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf2.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf3.flags", 30, 1, 0, -1, NULL, },
+  { "AR[FPSR].sf3.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].sf3.flags", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].rv", 30, 1, 2, -1, NULL, },
+  { "AR[FPSR].traps", 30, 1, 2, -1, NULL, },
+  { "AR[FSR]", 26, 1, 2, 28, NULL, },
+  { "AR[ITC]", 26, 1, 2, 44, NULL, },
+  { "AR[K%], % in 0 - 7", 1, 1, 2, -1, NULL, },
+  { "AR[LC]", 26, 1, 2, 65, NULL, },
+  { "AR[PFS]", 26, 1, 0, 64, NULL, },
+  { "AR[PFS]", 26, 1, 2, 64, NULL, },
+  { "AR[PFS]", 26, 1, 2, 64, NULL, },
+  { "AR[RNAT]", 26, 1, 2, 19, NULL, },
+  { "AR[RSC]", 26, 1, 2, 16, NULL, },
+  { "AR[SSD]", 26, 1, 2, 26, NULL, },
+  { "AR[UNAT]{%}, % in 0 - 63", 2, 1, 2, -1, NULL, },
+  { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 1, 0, -1, NULL, },
+  { "AR%, % in 48 - 63, 112-127", 4, 1, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, },
+  { "BR%, % in 0 - 7", 5, 1, 0, -1, NULL, },
+  { "CFM", 6, 1, 2, -1, NULL, },
+  { "CPUID#", 7, 1, 0, -1, NULL, },
+  { "CR[CMCV]", 27, 1, 2, 74, NULL, },
+  { "CR[DCR]", 27, 1, 2, 0, NULL, },
+  { "CR[EOI]", 27, 1, 7, 67, "SC Section 5.8.3.4, \"End of External Interrupt Register (EOI Ð CR67)\" on page 2:119", },
+  { "CR[GPTA]", 27, 1, 2, 9, NULL, },
+  { "CR[IFA]", 27, 1, 2, 20, NULL, },
+  { "CR[IFS]", 27, 1, 2, 23, NULL, },
+  { "CR[IHA]", 27, 1, 2, 25, NULL, },
+  { "CR[IIM]", 27, 1, 2, 24, NULL, },
+  { "CR[IIP]", 27, 1, 2, 19, NULL, },
+  { "CR[IIPA]", 27, 1, 2, 22, NULL, },
+  { "CR[IPSR]", 27, 1, 2, 16, NULL, },
+  { "CR[IRR%], % in 0 - 3", 8, 1, 2, -1, NULL, },
+  { "CR[ISR]", 27, 1, 2, 17, NULL, },
+  { "CR[ITIR]", 27, 1, 2, 21, NULL, },
+  { "CR[ITM]", 27, 1, 2, 1, NULL, },
+  { "CR[ITV]", 27, 1, 2, 72, NULL, },
+  { "CR[IVA]", 27, 1, 2, 2, NULL, },
+  { "CR[IVR]", 27, 1, 7, 65, "SC", },
+  { "CR[LID]", 27, 1, 7, 64, "SC", },
+  { "CR[LRR%], % in 0 - 1", 9, 1, 2, -1, NULL, },
+  { "CR[PMV]", 27, 1, 2, 73, NULL, },
+  { "CR[PTA]", 27, 1, 2, 8, NULL, },
+  { "CR[TPR]", 27, 1, 2, 66, NULL, },
+  { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 1, 0, -1, NULL, },
+  { "DBR#", 11, 1, 2, -1, NULL, },
+  { "DTC", 0, 1, 0, -1, NULL, },
+  { "DTC", 0, 1, 2, -1, NULL, },
+  { "DTC", 0, 1, 2, -1, NULL, },
+  { "DTC_LIMIT*", 0, 1, 2, -1, NULL, },
+  { "DTR", 0, 1, 2, -1, NULL, },
+  { "DTR", 0, 1, 2, -1, NULL, },
+  { "DTR", 0, 1, 2, -1, NULL, },
+  { "DTR", 0, 1, 0, -1, NULL, },
+  { "FR%, % in 0 - 1", 12, 1, 0, -1, NULL, },
+  { "FR%, % in 2 - 127", 13, 1, 2, -1, NULL, },
+  { "GR0", 14, 1, 0, -1, NULL, },
+  { "GR%, % in 1 - 127", 15, 1, 2, -1, NULL, },
+  { "IBR#", 16, 1, 2, -1, NULL, },
+  { "InService*", 17, 1, 7, -1, "SC", },
+  { "IP", 0, 1, 0, -1, NULL, },
+  { "ITC", 0, 1, 0, -1, NULL, },
+  { "ITC", 0, 1, 2, -1, NULL, },
+  { "ITC", 0, 1, 2, -1, NULL, },
+  { "ITR", 0, 1, 2, -1, NULL, },
+  { "ITR", 0, 1, 2, -1, NULL, },
+  { "ITR", 0, 1, 0, -1, NULL, },
+  { "memory", 0, 1, 0, -1, NULL, },
+  { "MSR#", 18, 1, 7, -1, "SC", },
+  { "PKR#", 19, 1, 0, -1, NULL, },
+  { "PKR#", 19, 1, 0, -1, NULL, },
+  { "PKR#", 19, 1, 2, -1, NULL, },
+  { "PMC#", 20, 1, 2, -1, NULL, },
+  { "PMD#", 21, 1, 2, -1, NULL, },
+  { "PR0", 0, 1, 0, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 1, 0, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 1, 0, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 1, 2, -1, NULL, },
+  { "PR%, % in 1 - 15", 22, 1, 2, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 1, 0, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 1, 0, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 1, 2, -1, NULL, },
+  { "PR%, % in 16 - 62", 23, 1, 2, -1, NULL, },
+  { "PR63", 24, 1, 0, -1, NULL, },
+  { "PR63", 24, 1, 0, -1, NULL, },
+  { "PR63", 24, 1, 2, -1, NULL, },
+  { "PR63", 24, 1, 2, -1, NULL, },
+  { "PSR.ac", 28, 1, 2, 3, NULL, },
+  { "PSR.be", 28, 1, 2, 1, NULL, },
+  { "PSR.bn", 28, 1, 2, 44, NULL, },
+  { "PSR.cpl", 28, 1, 2, 32, NULL, },
+  { "PSR.da", 28, 1, 2, 38, NULL, },
+  { "PSR.db", 28, 1, 2, 24, NULL, },
+  { "PSR.dd", 28, 1, 2, 39, NULL, },
+  { "PSR.dfh", 28, 1, 2, 19, NULL, },
+  { "PSR.dfl", 28, 1, 2, 18, NULL, },
+  { "PSR.di", 28, 1, 2, 22, NULL, },
+  { "PSR.dt", 28, 1, 2, 17, NULL, },
+  { "PSR.ed", 28, 1, 2, 43, NULL, },
+  { "PSR.i", 28, 1, 2, 14, NULL, },
+  { "PSR.ia", 28, 1, 2, 14, NULL, },
+  { "PSR.ic", 28, 1, 2, 13, NULL, },
+  { "PSR.id", 28, 1, 2, 14, NULL, },
+  { "PSR.is", 28, 1, 2, 14, NULL, },
+  { "PSR.it", 28, 1, 2, 14, NULL, },
+  { "PSR.lp", 28, 1, 2, 25, NULL, },
+  { "PSR.mc", 28, 1, 2, 35, NULL, },
+  { "PSR.mfh", 28, 1, 0, 5, NULL, },
+  { "PSR.mfh", 28, 1, 2, 5, NULL, },
+  { "PSR.mfh", 28, 1, 2, 5, NULL, },
+  { "PSR.mfl", 28, 1, 0, 4, NULL, },
+  { "PSR.mfl", 28, 1, 2, 4, NULL, },
+  { "PSR.mfl", 28, 1, 2, 4, NULL, },
+  { "PSR.pk", 28, 1, 2, 15, NULL, },
+  { "PSR.pp", 28, 1, 2, 21, NULL, },
+  { "PSR.ri", 28, 1, 2, 41, NULL, },
+  { "PSR.rt", 28, 1, 2, 27, NULL, },
+  { "PSR.si", 28, 1, 2, 23, NULL, },
+  { "PSR.sp", 28, 1, 2, 20, NULL, },
+  { "PSR.ss", 28, 1, 2, 40, NULL, },
+  { "PSR.tb", 28, 1, 2, 26, NULL, },
+  { "PSR.up", 28, 1, 2, 2, NULL, },
+  { "PSR.vm", 28, 1, 2, 46, NULL, },
+  { "RR#", 25, 1, 2, -1, NULL, },
+  { "RSE", 29, 1, 2, -1, NULL, },
+  { "PR63", 24, 2, 6, -1, NULL, },
+};
+
+static const unsigned short dep0[] = {
+  97, 282, 2140, 2327,
+};
+
+static const unsigned short dep1[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2327, 4135, 20616,
+};
+
+static const unsigned short dep2[] = {
+  97, 282, 2166, 2167, 2169, 2170, 2172, 2173, 2175, 2344, 2347, 2348, 2351,
+  2352, 2355, 2356,
+};
+
+static const unsigned short dep3[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 20616,
+};
+
+static const unsigned short dep4[] = {
+  97, 282, 22646, 22647, 22649, 22650, 22652, 22653, 22655, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep5[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  4135, 20616, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep6[] = {
+  97, 282, 2166, 2167, 2169, 2170, 2172, 2173, 2175, 2344, 2345, 2347, 2349,
+  2351, 2353, 2355,
+};
+
+static const unsigned short dep7[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2344, 2345, 2348, 2349, 2352, 2353, 2356, 4135, 20616,
+};
+
+static const unsigned short dep8[] = {
+  97, 282, 2166, 2167, 2169, 2170, 2172, 2173, 2175, 2344, 2346, 2348, 2350,
+  2352, 2354, 2356,
+};
+
+static const unsigned short dep9[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2344, 2346, 2347, 2350, 2351, 2354, 2355, 4135, 20616,
+};
+
+static const unsigned short dep10[] = {
+  97, 282, 2166, 2167, 2169, 2170, 2172, 2173, 2175, 2344, 2345, 2346, 2347,
+  2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356,
+};
+
+static const unsigned short dep11[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356,
+  4135, 20616,
+};
+
+static const unsigned short dep12[] = {
+  97, 282, 2395,
+};
+
+static const unsigned short dep13[] = {
+  40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2082, 2083, 2166, 2168,
+  2169, 2171, 2172, 2174, 2175, 4135,
+};
+
+static const unsigned short dep14[] = {
+  97, 163, 282, 325, 2395, 28866, 29018,
+};
+
+static const unsigned short dep15[] = {
+  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+  22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 40, 41, 97, 150, 152, 158, 162,
+  164, 175, 185, 186, 188, 282, 325, 2082, 2083, 2166, 2168, 2169, 2171, 2172,
+  2174, 2175, 4135, 28866, 29018,
+};
+
+static const unsigned short dep16[] = {
+  1, 6, 40, 97, 137, 196, 201, 241, 282, 312, 2395, 28866, 29018,
+};
+
+static const unsigned short dep17[] = {
+  1, 25, 27, 38, 40, 41, 97, 158, 162, 164, 166, 167, 175, 185, 186, 188, 196,
+  201, 241, 282, 312, 2082, 2083, 2166, 2168, 2169, 2171, 2172, 2174, 2175,
+  4135, 28866, 29018,
+};
+
+static const unsigned short dep18[] = {
+  1, 40, 51, 97, 196, 241, 248, 282, 28866, 29018,
+};
+
+static const unsigned short dep19[] = {
+  1, 38, 40, 41, 97, 158, 160, 161, 162, 175, 185, 190, 191, 196, 241, 248,
+  282, 4135, 28866, 29018,
+};
+
+static const unsigned short dep20[] = {
+  40, 97, 241, 282,
+};
+
+static const unsigned short dep21[] = {
+  97, 158, 162, 175, 185, 241, 282,
+};
+
+static const unsigned short dep22[] = {
+  1, 40, 97, 131, 135, 136, 138, 139, 142, 143, 146, 149, 152, 155, 156, 157,
+  158, 161, 162, 163, 164, 167, 168, 169, 170, 173, 174, 175, 178, 181, 184,
+  185, 188, 189, 191, 196, 241, 282, 309, 310, 311, 312, 313, 314, 315, 316,
+  317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 330, 331, 333,
+  334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 28866, 29018,
+};
+
+static const unsigned short dep23[] = {
+  1, 38, 40, 41, 50, 51, 55, 58, 73, 97, 137, 138, 158, 162, 175, 185, 190,
+  191, 196, 241, 282, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+  320, 321, 322, 323, 324, 325, 326, 327, 328, 330, 331, 333, 334, 335, 336,
+  337, 338, 339, 340, 341, 342, 343, 344, 4135, 28866, 29018,
+};
+
+static const unsigned short dep24[] = {
+  97, 136, 282, 311,
+};
+
+static const unsigned short dep25[] = {
+  97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 311,
+};
+
+static const unsigned short dep26[] = {
+  97, 137, 282, 312,
+};
+
+static const unsigned short dep27[] = {
+  25, 26, 97, 98, 101, 105, 108, 137, 138, 158, 162, 164, 175, 185, 282, 312,
+
+};
+
+static const unsigned short dep28[] = {
+  97, 190, 282, 344,
+};
+
+static const unsigned short dep29[] = {
+  97, 98, 101, 105, 108, 137, 138, 158, 162, 164, 175, 185, 282, 344,
+};
+
+static const unsigned short dep30[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2168, 2169, 2171, 2172, 2174, 2175,
+  4135,
+};
+
+static const unsigned short dep31[] = {
+  1, 25, 40, 97, 196, 228, 229, 241, 282, 2082, 2285, 2288, 2395, 28866, 29018,
+
+};
+
+static const unsigned short dep32[] = {
+  1, 6, 38, 40, 41, 97, 137, 138, 158, 162, 164, 175, 185, 186, 188, 196, 228,
+  230, 241, 282, 2082, 2083, 2166, 2168, 2169, 2171, 2172, 2174, 2175, 2286,
+  2288, 4135, 28866, 29018,
+};
+
+static const unsigned short dep33[] = {
+  97, 282,
+};
+
+static const unsigned short dep34[] = {
+  97, 158, 162, 175, 185, 282, 2082, 2084,
+};
+
+static const unsigned short dep35[] = {
+  40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166, 2168, 2169, 2171,
+  2172, 2174, 2175, 4135,
+};
+
+static const unsigned short dep36[] = {
+  6, 37, 38, 39, 97, 125, 126, 201, 241, 282, 307, 308, 2395,
+};
+
+static const unsigned short dep37[] = {
+  6, 37, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 201, 241, 282, 307,
+  308, 347, 2166, 2168, 2169, 2171, 2172, 2174, 2175, 4135,
+};
+
+static const unsigned short dep38[] = {
+  24, 97, 227, 282, 2395,
+};
+
+static const unsigned short dep39[] = {
+  24, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 227, 282, 2166, 2168, 2169,
+  2171, 2172, 2174, 2175, 4135,
+};
+
+static const unsigned short dep40[] = {
+  6, 24, 37, 38, 39, 97, 125, 126, 201, 227, 241, 282, 307, 308, 2395,
+};
+
+static const unsigned short dep41[] = {
+  6, 24, 37, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 201, 227, 241, 282,
+  307, 308, 347, 2166, 2168, 2169, 2171, 2172, 2174, 2175, 4135,
+};
+
+static const unsigned short dep42[] = {
+  1, 6, 38, 40, 41, 97, 137, 138, 158, 162, 164, 175, 185, 186, 188, 196, 228,
+  230, 241, 282, 2166, 2168, 2169, 2171, 2172, 2174, 2175, 2286, 2288, 4135,
+  28866, 29018,
+};
+
+static const unsigned short dep43[] = {
+  97, 158, 162, 175, 185, 282,
+};
+
+static const unsigned short dep44[] = {
+  15, 97, 210, 211, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+  22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828, 22831,
+  22832, 22835, 22836,
+};
+
+static const unsigned short dep45[] = {
+  11, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep46[] = {
+  15, 16, 17, 18, 97, 210, 211, 213, 214, 216, 217, 219, 220, 282, 2136, 2325,
+  18601, 18602, 18761, 18762, 18764, 18765, 22646, 22647, 22648, 22650, 22651,
+  22653, 22654, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep47[] = {
+  11, 12, 13, 14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 213, 215,
+  216, 218, 219, 221, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173, 2325, 4135,
+  16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep48[] = {
+  16, 97, 213, 214, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+  22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828, 22831,
+  22832, 22835, 22836,
+};
+
+static const unsigned short dep49[] = {
+  12, 19, 20, 40, 41, 97, 158, 162, 175, 185, 213, 215, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep50[] = {
+  17, 97, 216, 217, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+  22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828, 22831,
+  22832, 22835, 22836,
+};
+
+static const unsigned short dep51[] = {
+  13, 19, 20, 40, 41, 97, 158, 162, 175, 185, 216, 218, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep52[] = {
+  18, 97, 219, 220, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+  22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828, 22831,
+  22832, 22835, 22836,
+};
+
+static const unsigned short dep53[] = {
+  14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 219, 221, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep54[] = {
+  15, 97, 210, 211, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+
+};
+
+static const unsigned short dep55[] = {
+  11, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766,
+};
+
+static const unsigned short dep56[] = {
+  15, 16, 17, 18, 97, 210, 211, 213, 214, 216, 217, 219, 220, 282, 2136, 2325,
+  18601, 18602, 18761, 18762, 18764, 18765,
+};
+
+static const unsigned short dep57[] = {
+  11, 12, 13, 14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 213, 215,
+  216, 218, 219, 221, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173, 2325, 4135,
+  16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766,
+};
+
+static const unsigned short dep58[] = {
+  16, 97, 213, 214, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+
+};
+
+static const unsigned short dep59[] = {
+  12, 19, 20, 40, 41, 97, 158, 162, 175, 185, 213, 215, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766,
+};
+
+static const unsigned short dep60[] = {
+  17, 97, 216, 217, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+
+};
+
+static const unsigned short dep61[] = {
+  13, 19, 20, 40, 41, 97, 158, 162, 175, 185, 216, 218, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766,
+};
+
+static const unsigned short dep62[] = {
+  18, 97, 219, 220, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+
+};
+
+static const unsigned short dep63[] = {
+  14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 219, 221, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763,
+  18764, 18766,
+};
+
+static const unsigned short dep64[] = {
+  97, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+};
+
+static const unsigned short dep65[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173,
+  2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766,
+};
+
+static const unsigned short dep66[] = {
+  11, 97, 206, 282,
+};
+
+static const unsigned short dep67[] = {
+  11, 40, 41, 97, 158, 162, 175, 185, 206, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep68[] = {
+  11, 40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep69[] = {
+  12, 97, 207, 282,
+};
+
+static const unsigned short dep70[] = {
+  11, 40, 41, 97, 158, 162, 175, 185, 207, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep71[] = {
+  13, 97, 208, 282,
+};
+
+static const unsigned short dep72[] = {
+  11, 40, 41, 97, 158, 162, 175, 185, 208, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep73[] = {
+  14, 97, 209, 282,
+};
+
+static const unsigned short dep74[] = {
+  11, 40, 41, 97, 158, 162, 175, 185, 209, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep75[] = {
+  15, 97, 211, 212, 282,
+};
+
+static const unsigned short dep76[] = {
+  40, 41, 97, 158, 162, 175, 185, 211, 212, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep77[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep78[] = {
+  16, 97, 214, 215, 282,
+};
+
+static const unsigned short dep79[] = {
+  40, 41, 97, 158, 162, 175, 185, 214, 215, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep80[] = {
+  17, 97, 217, 218, 282,
+};
+
+static const unsigned short dep81[] = {
+  40, 41, 97, 158, 162, 175, 185, 217, 218, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep82[] = {
+  18, 97, 220, 221, 282,
+};
+
+static const unsigned short dep83[] = {
+  40, 41, 97, 158, 162, 175, 185, 220, 221, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep84[] = {
+  15, 19, 20, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166, 2167,
+  2170, 2173, 4135,
+};
+
+static const unsigned short dep85[] = {
+  15, 16, 19, 20, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166,
+  2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep86[] = {
+  15, 17, 19, 20, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166,
+  2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep87[] = {
+  15, 18, 19, 20, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166,
+  2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep88[] = {
+  15, 97, 210, 211, 282,
+};
+
+static const unsigned short dep89[] = {
+  11, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 282, 2166, 2167, 2170,
+  2173, 4135,
+};
+
+static const unsigned short dep90[] = {
+  15, 16, 17, 18, 97, 210, 211, 213, 214, 216, 217, 219, 220, 282,
+};
+
+static const unsigned short dep91[] = {
+  11, 12, 13, 14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 213, 215,
+  216, 218, 219, 221, 282, 2166, 2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep92[] = {
+  16, 97, 213, 214, 282,
+};
+
+static const unsigned short dep93[] = {
+  12, 19, 20, 40, 41, 97, 158, 162, 175, 185, 213, 215, 282, 2166, 2167, 2170,
+  2173, 4135,
+};
+
+static const unsigned short dep94[] = {
+  17, 97, 216, 217, 282,
+};
+
+static const unsigned short dep95[] = {
+  13, 19, 20, 40, 41, 97, 158, 162, 175, 185, 216, 218, 282, 2166, 2167, 2170,
+  2173, 4135,
+};
+
+static const unsigned short dep96[] = {
+  18, 97, 219, 220, 282,
+};
+
+static const unsigned short dep97[] = {
+  14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 219, 221, 282, 2166, 2167, 2170,
+  2173, 4135,
+};
+
+static const unsigned short dep98[] = {
+  15, 97, 210, 211, 282, 2166, 2167, 2168, 2170, 2171, 2173, 2174, 2344, 2347,
+  2348, 2351, 2352, 2355, 2356,
+};
+
+static const unsigned short dep99[] = {
+  11, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 16528,
+  16530, 16531, 16533,
+};
+
+static const unsigned short dep100[] = {
+  15, 16, 17, 18, 97, 210, 211, 213, 214, 216, 217, 219, 220, 282, 2166, 2167,
+  2168, 2170, 2171, 2173, 2174, 2344, 2347, 2348, 2351, 2352, 2355, 2356,
+};
+
+static const unsigned short dep101[] = {
+  11, 12, 13, 14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 213, 215,
+  216, 218, 219, 221, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173, 2344, 2347,
+  2348, 2351, 2352, 2355, 2356, 4135, 16528, 16530, 16531, 16533,
+};
+
+static const unsigned short dep102[] = {
+  16, 97, 213, 214, 282, 2166, 2167, 2168, 2170, 2171, 2173, 2174, 2344, 2347,
+  2348, 2351, 2352, 2355, 2356,
+};
+
+static const unsigned short dep103[] = {
+  12, 19, 20, 40, 41, 97, 158, 162, 175, 185, 213, 215, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 16528,
+  16530, 16531, 16533,
+};
+
+static const unsigned short dep104[] = {
+  17, 97, 216, 217, 282, 2166, 2167, 2168, 2170, 2171, 2173, 2174, 2344, 2347,
+  2348, 2351, 2352, 2355, 2356,
+};
+
+static const unsigned short dep105[] = {
+  13, 19, 20, 40, 41, 97, 158, 162, 175, 185, 216, 218, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 16528,
+  16530, 16531, 16533,
+};
+
+static const unsigned short dep106[] = {
+  18, 97, 219, 220, 282, 2166, 2167, 2168, 2170, 2171, 2173, 2174, 2344, 2347,
+  2348, 2351, 2352, 2355, 2356,
+};
+
+static const unsigned short dep107[] = {
+  14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 219, 221, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 16528,
+  16530, 16531, 16533,
+};
+
+static const unsigned short dep108[] = {
+  15, 97, 210, 211, 282, 22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824,
+  22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep109[] = {
+  11, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 4135, 16528, 16530, 16531, 16533, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep110[] = {
+  15, 16, 17, 18, 97, 210, 211, 213, 214, 216, 217, 219, 220, 282, 22646, 22647,
+  22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828, 22831, 22832, 22835,
+  22836,
+};
+
+static const unsigned short dep111[] = {
+  11, 12, 13, 14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 210, 212, 213, 215,
+  216, 218, 219, 221, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173, 4135, 16528,
+  16530, 16531, 16533, 22824, 22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep112[] = {
+  16, 97, 213, 214, 282, 22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824,
+  22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep113[] = {
+  12, 19, 20, 40, 41, 97, 158, 162, 175, 185, 213, 215, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 4135, 16528, 16530, 16531, 16533, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep114[] = {
+  17, 97, 216, 217, 282, 22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824,
+  22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep115[] = {
+  13, 19, 20, 40, 41, 97, 158, 162, 175, 185, 216, 218, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 4135, 16528, 16530, 16531, 16533, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep116[] = {
+  18, 97, 219, 220, 282, 22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824,
+  22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep117[] = {
+  14, 19, 20, 40, 41, 97, 158, 162, 175, 185, 219, 221, 282, 2135, 2136, 2137,
+  2166, 2167, 2170, 2173, 4135, 16528, 16530, 16531, 16533, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep118[] = {
+  97, 282, 2166, 2167, 2168, 2170, 2171, 2173, 2174, 2344, 2347, 2348, 2351,
+  2352, 2355, 2356,
+};
+
+static const unsigned short dep119[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173,
+  2344, 2347, 2348, 2351, 2352, 2355, 2356, 4135, 16528, 16530, 16531, 16533,
+
+};
+
+static const unsigned short dep120[] = {
+  97, 282, 22646, 22647, 22648, 22650, 22651, 22653, 22654, 22824, 22827, 22828,
+  22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep121[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173,
+  4135, 16528, 16530, 16531, 16533, 22824, 22827, 22828, 22831, 22832, 22835,
+  22836,
+};
+
+static const unsigned short dep122[] = {
+  19, 20, 40, 41, 97, 158, 162, 175, 185, 282, 2135, 2136, 2137, 2166, 2167,
+  2170, 2173, 2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766,
+
+};
+
+static const unsigned short dep123[] = {
+  40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep124[] = {
+  97, 282, 2083, 2084, 2286, 2287,
+};
+
+static const unsigned short dep125[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2285, 2287, 4135, 20616,
+};
+
+static const unsigned short dep126[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2082, 2084, 2166, 2167, 2170, 2173, 2327,
+  4135, 20616,
+};
+
+static const unsigned short dep127[] = {
+  97, 282, 14455, 14457, 14458, 14460, 14461, 14463, 14635, 14636, 14639, 14640,
+  14643, 14644,
+};
+
+static const unsigned short dep128[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 4135, 14635, 14636,
+  14639, 14640, 14643, 14644, 20616, 24694, 24695, 24698, 24701,
+};
+
+static const unsigned short dep129[] = {
+  97, 122, 124, 125, 127, 282, 303, 304, 307, 308,
+};
+
+static const unsigned short dep130[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 303, 304, 307, 308, 4135, 24694, 24695,
+  24698, 24701,
+};
+
+static const unsigned short dep131[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+
+};
+
+static const unsigned short dep132[] = {
+  40, 41, 97, 119, 122, 125, 158, 162, 175, 185, 282, 2327, 4135, 20616, 24694,
+
+};
+
+static const unsigned short dep133[] = {
+  6, 24, 26, 27, 97, 201, 227, 230, 282, 2081, 2284,
+};
+
+static const unsigned short dep134[] = {
+  40, 41, 97, 158, 162, 175, 185, 201, 227, 229, 282, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 2284, 4135, 20616,
+};
+
+static const unsigned short dep135[] = {
+  6, 24, 25, 26, 40, 41, 97, 158, 162, 175, 185, 282, 2081, 2166, 2167, 2170,
+  2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep136[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 2344, 2347, 2348,
+  2351, 2352, 2355, 2356, 4135,
+};
+
+static const unsigned short dep137[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 4135, 22824,
+  22827, 22828, 22831, 22832, 22835, 22836,
+};
+
+static const unsigned short dep138[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 2344, 2345, 2348,
+  2349, 2352, 2353, 2356, 4135,
+};
+
+static const unsigned short dep139[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 2344, 2346, 2347,
+  2350, 2351, 2354, 2355, 4135,
+};
+
+static const unsigned short dep140[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2166, 2167, 2170, 2173, 2344, 2345, 2346,
+  2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 4135,
+};
+
+static const unsigned short dep141[] = {
+  0, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2166, 2167, 2170, 2173,
+  4135,
+};
+
+static const unsigned short dep142[] = {
+  0, 97, 195, 282,
+};
+
+static const unsigned short dep143[] = {
+  0, 40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 195, 282, 2166, 2167, 2170,
+  2173, 4135,
+};
+
+static const unsigned short dep144[] = {
+  40, 41, 97, 158, 162, 175, 185, 195, 282, 2166, 2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep145[] = {
+  2, 28, 97, 197, 231, 282, 28866, 29018,
+};
+
+static const unsigned short dep146[] = {
+  1, 2, 28, 29, 97, 158, 162, 175, 177, 178, 185, 197, 231, 282, 28866, 29018,
+
+};
+
+static const unsigned short dep147[] = {
+  1, 28, 29, 38, 40, 41, 97, 158, 162, 175, 177, 178, 185, 197, 231, 282, 4135,
+  28866, 29018,
+};
+
+static const unsigned short dep148[] = {
+  0, 40, 41, 97, 158, 162, 175, 185, 195, 282, 2166, 2167, 2170, 2173, 4135,
+
+};
+
+static const unsigned short dep149[] = {
+  1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+  28, 29, 30, 31, 97, 196, 197, 198, 199, 200, 202, 203, 204, 205, 206, 207,
+  208, 209, 211, 212, 214, 215, 217, 218, 220, 221, 222, 223, 224, 225, 231,
+  232, 233, 234, 282, 2071, 2081, 2274, 2284, 28866, 29018,
+};
+
+static const unsigned short dep150[] = {
+  29, 40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 196, 197, 198, 199,
+  200, 202, 203, 204, 205, 206, 207, 208, 209, 211, 212, 214, 215, 217, 218,
+  220, 221, 222, 223, 224, 225, 231, 232, 233, 234, 282, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 2274, 2284, 4135, 20616, 28866, 29018,
+};
+
+static const unsigned short dep151[] = {
+  97, 282, 14464, 14466, 14468, 14470, 14505, 14506, 14525, 14645, 14646, 14666,
+  14667, 14669, 14670, 14679,
+};
+
+static const unsigned short dep152[] = {
+  40, 41, 97, 158, 162, 175, 183, 184, 185, 282, 2166, 2167, 2170, 2173, 4135,
+  14645, 14646, 14666, 14667, 14669, 14670, 14679,
+};
+
+static const unsigned short dep153[] = {
+  14464, 14466, 14468, 14470, 14505, 14506, 14525, 14645, 14646, 14666, 14667,
+  14669, 14670, 14679,
+};
+
+static const unsigned short dep154[] = {
+  183, 184, 14645, 14646, 14666, 14667, 14669, 14670, 14679,
+};
+
+static const unsigned short dep155[] = {
+  97, 282, 14465, 14466, 14469, 14470, 14480, 14481, 14483, 14484, 14486, 14487,
+  14489, 14490, 14493, 14495, 14496, 14505, 14506, 14507, 14508, 14510, 14515,
+  14516, 14518, 14519, 14525, 14645, 14646, 14652, 14653, 14654, 14655, 14657,
+  14659, 14666, 14667, 14669, 14670, 14671, 14672, 14675, 14676, 14679,
+};
+
+static const unsigned short dep156[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2166, 2167, 2170,
+  2173, 4135, 14645, 14646, 14652, 14653, 14654, 14655, 14657, 14659, 14666,
+  14667, 14669, 14670, 14671, 14672, 14675, 14676, 14679, 34888,
+};
+
+static const unsigned short dep157[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2166, 2167, 2170,
+  2173, 4135, 14645, 14646, 14652, 14653, 14654, 14655, 14657, 14659, 14666,
+  14667, 14669, 14670, 14671, 14672, 14675, 14676, 14679,
+};
+
+static const unsigned short dep158[] = {
+  1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+  28, 29, 30, 31, 40, 41, 97, 137, 138, 158, 162, 175, 180, 181, 185, 190, 191,
+  282, 2071, 2081, 2166, 2167, 2170, 2173, 2327, 4135, 20616, 28866,
+};
+
+static const unsigned short dep159[] = {
+  43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63,
+  64, 65, 67, 69, 70, 71, 72, 73, 94, 96, 97, 243, 244, 245, 246, 247, 248,
+  249, 250, 251, 252, 253, 255, 256, 257, 258, 259, 261, 263, 264, 265, 281,
+  282, 2116, 2310,
+};
+
+static const unsigned short dep160[] = {
+  40, 41, 96, 97, 137, 138, 158, 160, 161, 162, 175, 185, 190, 191, 243, 244,
+  245, 246, 247, 248, 249, 250, 251, 252, 253, 255, 256, 257, 258, 259, 261,
+  263, 264, 265, 281, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2310, 4135,
+  20616,
+};
+
+static const unsigned short dep161[] = {
+  59, 95, 97, 254, 281, 282, 2140, 2327,
+};
+
+static const unsigned short dep162[] = {
+  40, 41, 43, 44, 46, 48, 49, 51, 52, 53, 54, 56, 57, 60, 61, 63, 64, 65, 66,
+  67, 69, 70, 71, 94, 95, 97, 137, 138, 158, 160, 161, 162, 175, 185, 190, 191,
+  254, 281, 282, 2107, 2116, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep163[] = {
+  2, 28, 41, 97, 197, 231, 241, 282, 2140, 2327, 28866, 29018,
+};
+
+static const unsigned short dep164[] = {
+  2, 25, 26, 28, 29, 38, 40, 41, 97, 158, 162, 175, 177, 178, 185, 197, 231,
+  241, 282, 2327, 4135, 20616, 28866, 29018,
+};
+
+static const unsigned short dep165[] = {
+  97, 129, 130, 133, 134, 140, 141, 144, 145, 147, 148, 150, 151, 153, 154,
+  157, 159, 160, 165, 166, 169, 170, 171, 172, 174, 176, 177, 179, 180, 182,
+  183, 186, 187, 189, 282, 309, 310, 314, 316, 317, 318, 319, 321, 323, 327,
+  330, 331, 333, 334, 335, 336, 338, 339, 340, 342, 343,
+};
+
+static const unsigned short dep166[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 309, 310, 314, 316,
+  317, 318, 319, 321, 323, 327, 330, 331, 333, 334, 335, 336, 338, 339, 340,
+  342, 343, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616, 34888,
+};
+
+static const unsigned short dep167[] = {
+  97, 128, 130, 132, 134, 169, 170, 189, 282, 309, 310, 330, 331, 333, 334,
+  343,
+};
+
+static const unsigned short dep168[] = {
+  40, 41, 97, 158, 162, 175, 183, 184, 185, 282, 309, 310, 330, 331, 333, 334,
+  343, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep169[] = {
+  40, 41, 97, 130, 131, 134, 135, 137, 138, 141, 142, 145, 146, 148, 149, 151,
+  152, 154, 155, 157, 158, 159, 161, 162, 164, 165, 167, 168, 169, 170, 172,
+  173, 174, 175, 176, 178, 179, 181, 182, 184, 185, 187, 188, 189, 190, 191,
+  282, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep170[] = {
+  40, 41, 97, 130, 131, 134, 135, 158, 162, 169, 170, 175, 185, 189, 282, 2166,
+  2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep171[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 111, 137, 138, 153, 155, 158, 162, 171, 173,
+  175, 185, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep172[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 111, 137, 138, 139, 140, 142, 143, 153, 155,
+  158, 162, 171, 173, 175, 185, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 4135, 20616,
+};
+
+static const unsigned short dep173[] = {
+  77, 78, 97, 101, 102, 269, 270, 282, 284, 285,
+};
+
+static const unsigned short dep174[] = {
+  40, 41, 47, 62, 78, 80, 86, 97, 99, 102, 137, 138, 158, 160, 161, 162, 175,
+  185, 190, 191, 192, 269, 270, 282, 284, 285, 2138, 2139, 2140, 2166, 2167,
+  2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep175[] = {
+  40, 41, 47, 62, 78, 80, 97, 99, 102, 104, 106, 137, 138, 158, 160, 161, 162,
+  175, 185, 190, 191, 192, 269, 270, 282, 284, 285, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep176[] = {
+  97, 282, 12480, 12481, 12633,
+};
+
+static const unsigned short dep177[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 12633, 20616,
+};
+
+static const unsigned short dep178[] = {
+  97, 282, 6219, 6220, 6411,
+};
+
+static const unsigned short dep179[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 6411, 20616,
+};
+
+static const unsigned short dep180[] = {
+  97, 282, 6237, 6424,
+};
+
+static const unsigned short dep181[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 6424, 20616,
+};
+
+static const unsigned short dep182[] = {
+  97, 282, 6255, 6256, 6257, 6258, 6435, 6437, 8484,
+};
+
+static const unsigned short dep183[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 6258, 6436, 6437, 8304, 8483, 20616,
+};
+
+static const unsigned short dep184[] = {
+  97, 282, 6259, 6260, 6438,
+};
+
+static const unsigned short dep185[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 6438, 20616,
+};
+
+static const unsigned short dep186[] = {
+  97, 282, 6261, 6439,
+};
+
+static const unsigned short dep187[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 6439, 20616,
+};
+
+static const unsigned short dep188[] = {
+  97, 282, 10350, 10530,
+};
+
+static const unsigned short dep189[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 10530, 20616,
+};
+
+static const unsigned short dep190[] = {
+  77, 78, 82, 83, 97, 101, 102, 269, 270, 272, 273, 282, 284, 285,
+};
+
+static const unsigned short dep191[] = {
+  40, 41, 47, 62, 78, 80, 83, 86, 97, 99, 102, 137, 138, 158, 160, 161, 162,
+  175, 185, 190, 191, 192, 269, 270, 272, 274, 282, 284, 285, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep192[] = {
+  77, 78, 97, 101, 102, 104, 105, 269, 270, 282, 284, 285, 286, 287,
+};
+
+static const unsigned short dep193[] = {
+  40, 41, 47, 62, 78, 80, 97, 99, 102, 104, 106, 137, 138, 158, 160, 161, 162,
+  175, 185, 190, 191, 192, 269, 270, 282, 284, 285, 286, 287, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep194[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 12481, 20616,
+};
+
+static const unsigned short dep195[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 6219, 20616,
+};
+
+static const unsigned short dep196[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 6237, 20616,
+};
+
+static const unsigned short dep197[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 6257, 8303, 20616,
+};
+
+static const unsigned short dep198[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 6259, 20616,
+};
+
+static const unsigned short dep199[] = {
+  40, 41, 97, 137, 138, 158, 162, 175, 183, 184, 185, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 6260, 6261, 20616,
+};
+
+static const unsigned short dep200[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2327, 4135, 10350, 20616,
+};
+
+static const unsigned short dep201[] = {
+  40, 41, 97, 158, 162, 175, 185, 190, 191, 282, 2138, 2139, 2140, 2166, 2167,
+  2170, 2173, 2327, 4135, 6186, 20616,
+};
+
+static const unsigned short dep202[] = {
+  77, 79, 80, 97, 98, 99, 100, 268, 269, 282, 283, 284,
+};
+
+static const unsigned short dep203[] = {
+  40, 41, 78, 79, 83, 85, 97, 100, 102, 104, 107, 137, 138, 158, 162, 175, 185,
+  190, 191, 192, 268, 270, 282, 283, 285, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 4135, 20616,
+};
+
+static const unsigned short dep204[] = {
+  77, 79, 80, 81, 97, 98, 99, 100, 103, 268, 269, 271, 282, 283, 284,
+};
+
+static const unsigned short dep205[] = {
+  40, 41, 78, 79, 81, 83, 85, 97, 100, 102, 103, 104, 107, 137, 138, 158, 162,
+  175, 185, 190, 191, 192, 268, 270, 271, 282, 283, 285, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep206[] = {
+  77, 79, 80, 84, 85, 86, 97, 98, 99, 100, 268, 269, 274, 275, 282, 283, 284,
+
+};
+
+static const unsigned short dep207[] = {
+  40, 41, 78, 79, 83, 85, 97, 100, 102, 137, 138, 158, 162, 175, 185, 190, 191,
+  192, 268, 270, 273, 275, 282, 283, 285, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 4135, 20616,
+};
+
+static const unsigned short dep208[] = {
+  77, 79, 80, 97, 98, 99, 100, 106, 107, 108, 268, 269, 282, 283, 284, 287,
+  288,
+};
+
+static const unsigned short dep209[] = {
+  40, 41, 78, 79, 97, 100, 102, 104, 107, 137, 138, 158, 162, 175, 185, 190,
+  191, 192, 268, 270, 282, 283, 285, 286, 288, 2138, 2139, 2140, 2166, 2167,
+  2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep210[] = {
+  40, 41, 46, 70, 97, 158, 162, 175, 185, 190, 191, 192, 282, 2138, 2139, 2140,
+  2166, 2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep211[] = {
+  40, 41, 97, 158, 162, 175, 185, 190, 191, 192, 282, 2138, 2139, 2140, 2166,
+  2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep212[] = {
+  40, 41, 70, 77, 82, 84, 97, 137, 138, 153, 155, 158, 162, 175, 185, 190, 191,
+  192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep213[] = {
+  40, 41, 97, 158, 162, 164, 175, 185, 186, 188, 282, 2135, 2136, 2137, 2138,
+  2139, 2140, 2166, 2167, 2170, 2173, 4135, 16528, 16530, 16531, 16533, 20616,
+
+};
+
+static const unsigned short dep214[] = {
+  40, 41, 70, 77, 82, 84, 97, 153, 155, 158, 162, 175, 185, 192, 282, 2138,
+  2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep215[] = {
+  40, 41, 78, 79, 97, 100, 137, 138, 158, 162, 175, 185, 190, 191, 268, 270,
+  282, 283, 285, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+};
+
+static const unsigned short dep216[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep217[] = {
+  5, 97, 200, 282, 2140, 2327,
+};
+
+static const unsigned short dep218[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 200, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+
+};
+
+static const unsigned short dep219[] = {
+  40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175, 185,
+  190, 191, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep220[] = {
+  0, 97, 195, 282, 2140, 2327,
+};
+
+static const unsigned short dep221[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep222[] = {
+  0, 40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133,
+  135, 137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175,
+  185, 190, 191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327,
+  4135, 20616,
+};
+
+static const unsigned short dep223[] = {
+  31, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135, 20616,
+
+};
+
+static const unsigned short dep224[] = {
+  0, 97, 195, 282, 2327, 26715,
+};
+
+static const unsigned short dep225[] = {
+  0, 97, 109, 195, 282, 289,
+};
+
+static const unsigned short dep226[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+
+};
+
+static const unsigned short dep227[] = {
+  0, 5, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+
+};
+
+static const unsigned short dep228[] = {
+  0, 31, 97, 109, 195, 234, 282, 289,
+};
+
+static const unsigned short dep229[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 234, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 4135, 20616,
+
+};
+
+static const unsigned short dep230[] = {
+  0, 97, 109, 195, 282, 289, 2140, 2327,
+};
+
+static const unsigned short dep231[] = {
+  0, 3, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep232[] = {
+  0, 3, 5, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133,
+  135, 137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185,
+  190, 191, 192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327,
+  4135, 20616,
+};
+
+static const unsigned short dep233[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep234[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2135, 2136, 2137, 2166, 2167, 2170, 2173,
+  2327, 4135, 16528, 16530, 16531, 16533, 20616,
+};
+
+static const unsigned short dep235[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep236[] = {
+  0, 31, 97, 109, 195, 234, 282, 289, 2140, 2327,
+};
+
+static const unsigned short dep237[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 234, 282, 289, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2327, 4135,
+  20616,
+};
+
+static const unsigned short dep238[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 4135, 16528, 16530,
+  16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep239[] = {
+  40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175, 185,
+  190, 191, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 4135,
+  16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep240[] = {
+  0, 97, 195, 282, 2136, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+};
+
+static const unsigned short dep241[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 4135,
+  16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep242[] = {
+  0, 40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133,
+  135, 137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175,
+  185, 190, 191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325,
+  4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep243[] = {
+  0, 97, 195, 282, 2137, 2325, 18601, 18602, 18761, 18762, 18764, 18765,
+};
+
+static const unsigned short dep244[] = {
+  97, 282, 2136, 2140, 2325, 2327, 18601, 18602, 18761, 18762, 18764, 18765,
+
+};
+
+static const unsigned short dep245[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 2327, 4135, 16528,
+  16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep246[] = {
+  40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175, 185,
+  190, 191, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 2327,
+  4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep247[] = {
+  0, 97, 195, 282, 2136, 2140, 2325, 2327, 18601, 18602, 18761, 18762, 18764,
+  18765,
+};
+
+static const unsigned short dep248[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133, 135,
+  137, 138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190,
+  191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325, 2327,
+  4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+};
+
+static const unsigned short dep249[] = {
+  0, 40, 41, 44, 70, 76, 77, 82, 84, 97, 109, 111, 128, 129, 131, 132, 133,
+  135, 137, 138, 139, 140, 142, 143, 153, 155, 156, 158, 162, 171, 173, 175,
+  185, 190, 191, 192, 195, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173, 2325,
+  2327, 4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+
+};
+
+static const unsigned short dep250[] = {
+  0, 97, 195, 282, 2137, 2140, 2325, 2327, 18601, 18602, 18761, 18762, 18764,
+  18765,
+};
+
+static const unsigned short dep251[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 282, 289, 2135, 2136, 2137, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 4135, 16528, 16530, 16531, 16533, 20616,
+};
+
+static const unsigned short dep252[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 137, 138, 139, 140, 142, 143, 153, 155, 156,
+  158, 162, 171, 173, 175, 185, 192, 282, 2166, 2167, 2170, 2173, 4135,
+};
+
+static const unsigned short dep253[] = {
+  40, 41, 70, 76, 77, 82, 84, 97, 137, 138, 139, 140, 142, 143, 153, 155, 156,
+  158, 162, 171, 173, 175, 185, 192, 282, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 2327, 4135, 20616,
+};
+
+static const unsigned short dep254[] = {
+  40, 41, 97, 158, 162, 175, 185, 282, 2138, 2139, 2140, 2166, 2167, 2170, 2173,
+  2325, 4135, 16528, 16530, 16531, 16533, 18761, 18763, 18764, 18766, 20616,
+
+};
+
+static const unsigned short dep255[] = {
+  0, 40, 41, 70, 76, 77, 82, 84, 97, 111, 128, 129, 131, 132, 133, 135, 137,
+  138, 139, 140, 142, 143, 153, 155, 158, 162, 171, 173, 175, 185, 190, 191,
+  192, 195, 282, 289, 2135, 2136, 2137, 2138, 2139, 2140, 2166, 2167, 2170,
+  2173, 2327, 4135, 16528, 16530, 16531, 16533, 20616,
+};
+
+static const unsigned short dep256[] = {
+  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+  22, 24, 26, 27, 28, 29, 30, 31, 97, 196, 197, 198, 199, 200, 201, 202, 203,
+  204, 205, 206, 207, 208, 209, 211, 212, 214, 215, 217, 218, 220, 221, 222,
+  223, 224, 225, 227, 230, 231, 232, 233, 234, 282, 2071, 2081, 2140, 2274,
+  2284, 2327, 28866, 29018,
+};
+
+static const unsigned short dep257[] = {
+  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+  22, 24, 25, 26, 28, 29, 30, 31, 40, 41, 97, 137, 138, 158, 162, 175, 180,
+  181, 185, 190, 191, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+  207, 208, 209, 211, 212, 214, 215, 217, 218, 220, 221, 222, 223, 224, 225,
+  227, 229, 231, 232, 233, 234, 282, 2071, 2081, 2138, 2139, 2140, 2166, 2167,
+  2170, 2173, 2274, 2284, 2327, 4135, 20616, 28866, 29018,
+};
+
+#define NELS(X) (sizeof(X)/sizeof(X[0]))
+static const struct ia64_opcode_dependency
+op_dependencies[] = {
+  { NELS(dep1), dep1, NELS(dep0), dep0, },
+  { NELS(dep3), dep3, NELS(dep2), dep2, },
+  { NELS(dep5), dep5, NELS(dep4), dep4, },
+  { NELS(dep7), dep7, NELS(dep6), dep6, },
+  { NELS(dep9), dep9, NELS(dep8), dep8, },
+  { NELS(dep11), dep11, NELS(dep10), dep10, },
+  { NELS(dep13), dep13, NELS(dep12), dep12, },
+  { NELS(dep15), dep15, NELS(dep14), dep14, },
+  { NELS(dep17), dep17, NELS(dep16), dep16, },
+  { NELS(dep19), dep19, NELS(dep18), dep18, },
+  { NELS(dep21), dep21, NELS(dep20), dep20, },
+  { NELS(dep23), dep23, NELS(dep22), dep22, },
+  { NELS(dep25), dep25, NELS(dep24), dep24, },
+  { NELS(dep27), dep27, NELS(dep26), dep26, },
+  { NELS(dep29), dep29, NELS(dep28), dep28, },
+  { NELS(dep30), dep30, NELS(dep12), dep12, },
+  { NELS(dep32), dep32, NELS(dep31), dep31, },
+  { NELS(dep34), dep34, NELS(dep33), dep33, },
+  { NELS(dep35), dep35, NELS(dep12), dep12, },
+  { NELS(dep37), dep37, NELS(dep36), dep36, },
+  { NELS(dep39), dep39, NELS(dep38), dep38, },
+  { NELS(dep41), dep41, NELS(dep40), dep40, },
+  { NELS(dep42), dep42, NELS(dep31), dep31, },
+  { NELS(dep43), dep43, NELS(dep33), dep33, },
+  { NELS(dep45), dep45, NELS(dep44), dep44, },
+  { NELS(dep47), dep47, NELS(dep46), dep46, },
+  { NELS(dep49), dep49, NELS(dep48), dep48, },
+  { NELS(dep51), dep51, NELS(dep50), dep50, },
+  { NELS(dep53), dep53, NELS(dep52), dep52, },
+  { NELS(dep55), dep55, NELS(dep54), dep54, },
+  { NELS(dep57), dep57, NELS(dep56), dep56, },
+  { NELS(dep59), dep59, NELS(dep58), dep58, },
+  { NELS(dep61), dep61, NELS(dep60), dep60, },
+  { NELS(dep63), dep63, NELS(dep62), dep62, },
+  { NELS(dep65), dep65, NELS(dep64), dep64, },
+  { NELS(dep67), dep67, NELS(dep66), dep66, },
+  { NELS(dep68), dep68, NELS(dep33), dep33, },
+  { NELS(dep70), dep70, NELS(dep69), dep69, },
+  { NELS(dep72), dep72, NELS(dep71), dep71, },
+  { NELS(dep74), dep74, NELS(dep73), dep73, },
+  { NELS(dep76), dep76, NELS(dep75), dep75, },
+  { NELS(dep77), dep77, NELS(dep33), dep33, },
+  { NELS(dep79), dep79, NELS(dep78), dep78, },
+  { NELS(dep81), dep81, NELS(dep80), dep80, },
+  { NELS(dep83), dep83, NELS(dep82), dep82, },
+  { NELS(dep84), dep84, NELS(dep33), dep33, },
+  { NELS(dep85), dep85, NELS(dep33), dep33, },
+  { NELS(dep86), dep86, NELS(dep33), dep33, },
+  { NELS(dep87), dep87, NELS(dep33), dep33, },
+  { NELS(dep89), dep89, NELS(dep88), dep88, },
+  { NELS(dep91), dep91, NELS(dep90), dep90, },
+  { NELS(dep93), dep93, NELS(dep92), dep92, },
+  { NELS(dep95), dep95, NELS(dep94), dep94, },
+  { NELS(dep97), dep97, NELS(dep96), dep96, },
+  { NELS(dep99), dep99, NELS(dep98), dep98, },
+  { NELS(dep101), dep101, NELS(dep100), dep100, },
+  { NELS(dep103), dep103, NELS(dep102), dep102, },
+  { NELS(dep105), dep105, NELS(dep104), dep104, },
+  { NELS(dep107), dep107, NELS(dep106), dep106, },
+  { NELS(dep109), dep109, NELS(dep108), dep108, },
+  { NELS(dep111), dep111, NELS(dep110), dep110, },
+  { NELS(dep113), dep113, NELS(dep112), dep112, },
+  { NELS(dep115), dep115, NELS(dep114), dep114, },
+  { NELS(dep117), dep117, NELS(dep116), dep116, },
+  { NELS(dep119), dep119, NELS(dep118), dep118, },
+  { NELS(dep121), dep121, NELS(dep120), dep120, },
+  { NELS(dep122), dep122, NELS(dep64), dep64, },
+  { NELS(dep123), dep123, NELS(dep33), dep33, },
+  { NELS(dep125), dep125, NELS(dep124), dep124, },
+  { NELS(dep126), dep126, NELS(dep0), dep0, },
+  { NELS(dep128), dep128, NELS(dep127), dep127, },
+  { NELS(dep130), dep130, NELS(dep129), dep129, },
+  { NELS(dep131), dep131, NELS(dep0), dep0, },
+  { NELS(dep132), dep132, NELS(dep0), dep0, },
+  { NELS(dep134), dep134, NELS(dep133), dep133, },
+  { NELS(dep135), dep135, NELS(dep0), dep0, },
+  { NELS(dep136), dep136, NELS(dep2), dep2, },
+  { NELS(dep137), dep137, NELS(dep4), dep4, },
+  { NELS(dep138), dep138, NELS(dep6), dep6, },
+  { NELS(dep139), dep139, NELS(dep8), dep8, },
+  { NELS(dep140), dep140, NELS(dep10), dep10, },
+  { NELS(dep141), dep141, NELS(dep33), dep33, },
+  { NELS(dep143), dep143, NELS(dep142), dep142, },
+  { NELS(dep144), dep144, NELS(dep142), dep142, },
+  { NELS(dep146), dep146, NELS(dep145), dep145, },
+  { NELS(dep147), dep147, NELS(dep145), dep145, },
+  { NELS(dep148), dep148, NELS(dep142), dep142, },
+  { NELS(dep150), dep150, NELS(dep149), dep149, },
+  { NELS(dep152), dep152, NELS(dep151), dep151, },
+  { NELS(dep154), dep154, NELS(dep153), dep153, },
+  { NELS(dep156), dep156, NELS(dep155), dep155, },
+  { NELS(dep157), dep157, NELS(dep155), dep155, },
+  { NELS(dep158), dep158, NELS(dep0), dep0, },
+  { NELS(dep160), dep160, NELS(dep159), dep159, },
+  { NELS(dep162), dep162, NELS(dep161), dep161, },
+  { NELS(dep164), dep164, NELS(dep163), dep163, },
+  { NELS(dep166), dep166, NELS(dep165), dep165, },
+  { NELS(dep168), dep168, NELS(dep167), dep167, },
+  { NELS(dep169), dep169, NELS(dep0), dep0, },
+  { NELS(dep170), dep170, NELS(dep0), dep0, },
+  { NELS(dep171), dep171, NELS(dep0), dep0, },
+  { NELS(dep172), dep172, NELS(dep33), dep33, },
+  { NELS(dep174), dep174, NELS(dep173), dep173, },
+  { NELS(dep175), dep175, NELS(dep173), dep173, },
+  { NELS(dep177), dep177, NELS(dep176), dep176, },
+  { NELS(dep179), dep179, NELS(dep178), dep178, },
+  { NELS(dep181), dep181, NELS(dep180), dep180, },
+  { NELS(dep183), dep183, NELS(dep182), dep182, },
+  { NELS(dep185), dep185, NELS(dep184), dep184, },
+  { NELS(dep187), dep187, NELS(dep186), dep186, },
+  { NELS(dep189), dep189, NELS(dep188), dep188, },
+  { NELS(dep191), dep191, NELS(dep190), dep190, },
+  { NELS(dep193), dep193, NELS(dep192), dep192, },
+  { NELS(dep194), dep194, NELS(dep0), dep0, },
+  { NELS(dep195), dep195, NELS(dep0), dep0, },
+  { NELS(dep196), dep196, NELS(dep0), dep0, },
+  { NELS(dep197), dep197, NELS(dep0), dep0, },
+  { NELS(dep198), dep198, NELS(dep0), dep0, },
+  { NELS(dep199), dep199, NELS(dep0), dep0, },
+  { NELS(dep200), dep200, NELS(dep0), dep0, },
+  { NELS(dep201), dep201, NELS(dep0), dep0, },
+  { NELS(dep203), dep203, NELS(dep202), dep202, },
+  { NELS(dep205), dep205, NELS(dep204), dep204, },
+  { NELS(dep207), dep207, NELS(dep206), dep206, },
+  { NELS(dep209), dep209, NELS(dep208), dep208, },
+  { NELS(dep210), dep210, NELS(dep0), dep0, },
+  { NELS(dep211), dep211, NELS(dep0), dep0, },
+  { NELS(dep212), dep212, NELS(dep0), dep0, },
+  { NELS(dep213), dep213, NELS(dep33), dep33, },
+  { NELS(dep214), dep214, NELS(dep33), dep33, },
+  { NELS(dep215), dep215, NELS(dep202), dep202, },
+  { NELS(dep216), dep216, NELS(dep0), dep0, },
+  { NELS(dep218), dep218, NELS(dep217), dep217, },
+  { NELS(dep219), dep219, NELS(dep0), dep0, },
+  { NELS(dep221), dep221, NELS(dep220), dep220, },
+  { NELS(dep222), dep222, NELS(dep220), dep220, },
+  { NELS(dep223), dep223, NELS(dep0), dep0, },
+  { NELS(dep221), dep221, NELS(dep224), dep224, },
+  { NELS(dep226), dep226, NELS(dep225), dep225, },
+  { NELS(dep227), dep227, NELS(dep225), dep225, },
+  { NELS(dep229), dep229, NELS(dep228), dep228, },
+  { NELS(dep231), dep231, NELS(dep230), dep230, },
+  { NELS(dep232), dep232, NELS(dep230), dep230, },
+  { NELS(dep233), dep233, NELS(dep230), dep230, },
+  { NELS(dep234), dep234, NELS(dep0), dep0, },
+  { NELS(dep235), dep235, NELS(dep230), dep230, },
+  { NELS(dep237), dep237, NELS(dep236), dep236, },
+  { NELS(dep238), dep238, NELS(dep64), dep64, },
+  { NELS(dep239), dep239, NELS(dep64), dep64, },
+  { NELS(dep241), dep241, NELS(dep240), dep240, },
+  { NELS(dep242), dep242, NELS(dep240), dep240, },
+  { NELS(dep241), dep241, NELS(dep243), dep243, },
+  { NELS(dep245), dep245, NELS(dep244), dep244, },
+  { NELS(dep246), dep246, NELS(dep244), dep244, },
+  { NELS(dep248), dep248, NELS(dep247), dep247, },
+  { NELS(dep249), dep249, NELS(dep247), dep247, },
+  { NELS(dep248), dep248, NELS(dep250), dep250, },
+  { NELS(dep251), dep251, NELS(dep225), dep225, },
+  { NELS(dep252), dep252, NELS(dep33), dep33, },
+  { NELS(dep253), dep253, NELS(dep0), dep0, },
+  { NELS(dep254), dep254, NELS(dep64), dep64, },
+  { NELS(dep255), dep255, NELS(dep230), dep230, },
+  { 0, NULL, 0, NULL, },
+  { NELS(dep257), dep257, NELS(dep256), dep256, },
+};
+
+static const struct ia64_completer_table
+completer_table[] = {
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 95 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 95 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 594, -1, 0, 1, 6 },
+  { 0x0, 0x0, 0, 657, -1, 0, 1, 18 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 162 },
+  { 0x0, 0x0, 0, 756, -1, 0, 1, 18 },
+  { 0x0, 0x0, 0, 2198, -1, 0, 1, 10 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 9 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 13 },
+  { 0x1, 0x1, 0, -1, -1, 13, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, 2406, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, 1140, -1, 0, 1, 129 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 45 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 84 },
+  { 0x0, 0x0, 0, 2246, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2473, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2250, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, 2252, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2482, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2485, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2507, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 2510, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 25 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 25 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 25 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 25 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 36 },
+  { 0x0, 0x0, 0, 2518, -1, 0, 1, 30 },
+  { 0x0, 0x0, 0, 1409, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 162 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 83 },
+  { 0x0, 0x0, 0, 1457, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1466, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1475, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1477, -1, 0, 1, 132 },
+  { 0x0, 0x0, 0, 1479, -1, 0, 1, 132 },
+  { 0x0, 0x0, 0, 1488, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1497, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1506, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1515, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1524, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1533, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1543, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1553, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1563, -1, 0, 1, 131 },
+  { 0x0, 0x0, 0, 1572, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1578, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1584, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1590, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1596, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1602, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1608, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1614, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1620, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1626, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1632, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1638, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1644, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1650, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1656, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1662, -1, 0, 1, 147 },
+  { 0x0, 0x0, 0, 1668, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1674, -1, 0, 1, 152 },
+  { 0x0, 0x0, 0, 1678, -1, 0, 1, 158 },
+  { 0x0, 0x0, 0, 1682, -1, 0, 1, 159 },
+  { 0x0, 0x0, 0, 1686, -1, 0, 1, 159 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 85 },
+  { 0x0, 0x0, 0, 258, -1, 0, 1, 41 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 68 },
+  { 0x1, 0x1, 0, 1166, -1, 20, 1, 68 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 69 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 70 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 70 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 71 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 72 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 73 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 93 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 94 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 96 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 97 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 98 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 99 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 104 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 105 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 106 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 107 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 108 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 109 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 110 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 113 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 114 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 115 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 116 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 117 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 118 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 119 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 120 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 163 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 163 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 163 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 72 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 162 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2858, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2859, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2210, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2211, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2873, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2874, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2875, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2876, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2877, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2860, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, 2861, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 11 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 91 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 89 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x1, 0x1, 0, -1, -1, 13, 1, 0 },
+  { 0x0, 0x0, 0, 2879, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 90 },
+  { 0x0, 0x0, 0, 1966, -1, 0, 1, 138 },
+  { 0x0, 0x0, 0, 1968, -1, 0, 1, 145 },
+  { 0x0, 0x0, 0, 1970, -1, 0, 1, 139 },
+  { 0x0, 0x0, 0, 1972, -1, 0, 1, 139 },
+  { 0x0, 0x0, 0, 1974, -1, 0, 1, 138 },
+  { 0x0, 0x0, 0, 1976, -1, 0, 1, 145 },
+  { 0x0, 0x0, 0, 1978, -1, 0, 1, 138 },
+  { 0x0, 0x0, 0, 1980, -1, 0, 1, 145 },
+  { 0x0, 0x0, 0, 1983, -1, 0, 1, 138 },
+  { 0x0, 0x0, 0, 1986, -1, 0, 1, 145 },
+  { 0x0, 0x0, 0, 1989, -1, 0, 1, 157 },
+  { 0x0, 0x0, 0, 1990, -1, 0, 1, 161 },
+  { 0x0, 0x0, 0, 1991, -1, 0, 1, 157 },
+  { 0x0, 0x0, 0, 1992, -1, 0, 1, 161 },
+  { 0x0, 0x0, 0, 1993, -1, 0, 1, 157 },
+  { 0x0, 0x0, 0, 1994, -1, 0, 1, 161 },
+  { 0x0, 0x0, 0, 1995, -1, 0, 1, 157 },
+  { 0x0, 0x0, 0, 1996, -1, 0, 1, 161 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 88 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 127 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 125 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 127 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 126 },
+  { 0x0, 0x0, 0, 1687, -1, 0, 1, 143 },
+  { 0x0, 0x0, 0, 1688, -1, 0, 1, 143 },
+  { 0x0, 0x0, 0, 1689, -1, 0, 1, 143 },
+  { 0x0, 0x0, 0, 1690, -1, 0, 1, 143 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 0, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 1, 224, -1, 0, 1, 12 },
+  { 0x0, 0x0, 1, 225, -1, 0, 1, 14 },
+  { 0x1, 0x1, 2, -1, -1, 27, 1, 12 },
+  { 0x1, 0x1, 2, -1, -1, 27, 1, 14 },
+  { 0x0, 0x0, 3, -1, 1340, 0, 0, -1 },
+  { 0x0, 0x0, 3, -1, 1341, 0, 0, -1 },
+  { 0x1, 0x1, 3, 2749, 1450, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2750, 1459, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2751, 1468, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2752, 1481, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2753, 1490, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2754, 1499, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2755, 1508, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2756, 1517, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2757, 1526, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2758, 1535, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2759, 1545, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2760, 1555, 33, 1, 134 },
+  { 0x1, 0x1, 3, 2761, 1568, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2762, 1574, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2763, 1580, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2764, 1586, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2765, 1592, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2766, 1598, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2767, 1604, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2768, 1610, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2769, 1616, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2770, 1622, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2771, 1628, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2772, 1634, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2773, 1640, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2774, 1646, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2775, 1652, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2776, 1658, 33, 1, 149 },
+  { 0x1, 0x1, 3, 2777, 1664, 33, 1, 154 },
+  { 0x1, 0x1, 3, 2778, 1670, 33, 1, 154 },
+  { 0x1, 0x1, 3, -1, -1, 27, 1, 41 },
+  { 0x0, 0x0, 4, 2212, 1425, 0, 1, 142 },
+  { 0x0, 0x0, 4, 2213, 1427, 0, 1, 142 },
+  { 0x0, 0x0, 4, 2214, 1429, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2215, 1431, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2216, 1433, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2217, 1435, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2218, 1437, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2219, 1439, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2220, 1441, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2221, 1443, 0, 1, 141 },
+  { 0x0, 0x0, 4, 2222, 1445, 0, 1, 143 },
+  { 0x0, 0x0, 4, 2223, 1447, 0, 1, 143 },
+  { 0x1, 0x1, 4, -1, 1454, 33, 1, 137 },
+  { 0x5, 0x5, 4, 552, 1453, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1463, 33, 1, 137 },
+  { 0x5, 0x5, 4, 553, 1462, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1472, 33, 1, 137 },
+  { 0x5, 0x5, 4, 554, 1471, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1476, 32, 1, 132 },
+  { 0x1, 0x1, 4, -1, 1478, 32, 1, 132 },
+  { 0x1, 0x1, 4, -1, 1485, 33, 1, 137 },
+  { 0x5, 0x5, 4, 555, 1484, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1494, 33, 1, 137 },
+  { 0x5, 0x5, 4, 556, 1493, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1503, 33, 1, 137 },
+  { 0x5, 0x5, 4, 557, 1502, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1512, 33, 1, 137 },
+  { 0x5, 0x5, 4, 558, 1511, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1521, 33, 1, 137 },
+  { 0x5, 0x5, 4, 559, 1520, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1530, 33, 1, 137 },
+  { 0x5, 0x5, 4, 560, 1529, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1540, 33, 1, 137 },
+  { 0x5, 0x5, 4, 1036, 1538, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1550, 33, 1, 137 },
+  { 0x5, 0x5, 4, 1037, 1548, 32, 1, 131 },
+  { 0x1, 0x1, 4, -1, 1560, 33, 1, 137 },
+  { 0x5, 0x5, 4, 1038, 1558, 32, 1, 131 },
+  { 0x1, 0x21, 10, 2013, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2014, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 420, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2074, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2075, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2076, 0, 0, -1 },
+  { 0x0, 0x0, 10, 2017, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2018, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 2019, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2020, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 430, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2080, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 434, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2082, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 438, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2084, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 442, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2086, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 446, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2088, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 450, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2090, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 2033, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2034, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 460, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2096, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2097, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2098, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2101, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2102, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2103, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2104, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2105, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2106, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2107, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2108, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2109, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2110, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2111, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2112, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2113, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2114, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2115, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2116, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2117, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2118, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2119, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2120, 0, 0, -1 },
+  { 0x1, 0x21, 10, 2037, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2038, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 468, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2122, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2123, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2124, 0, 0, -1 },
+  { 0x0, 0x0, 10, 2041, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2042, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 2043, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2044, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 478, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2128, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 482, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2130, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 486, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2132, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 490, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2134, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, 494, -1, 0, 1, 3 },
+  { 0x1, 0x1, 10, 2136, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 498, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2138, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 2057, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2058, -1, 12, 1, 3 },
+  { 0x1, 0x21, 10, 508, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 10, 2144, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2145, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2146, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2149, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2150, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2151, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2152, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2153, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2154, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2155, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2156, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2157, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2158, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2159, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2160, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2161, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2162, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2163, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2164, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2165, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2166, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2167, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2168, 0, 0, -1 },
+  { 0x1, 0x1, 10, 2061, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 10, 2062, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 2063, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 10, 2064, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2169, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2171, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2173, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2175, 0, 0, -1 },
+  { 0x1, 0x1, 10, 2065, -1, 36, 1, 78 },
+  { 0x1000001, 0x1000001, 10, 2066, -1, 12, 1, 78 },
+  { 0x1, 0x1, 10, 2067, -1, 36, 1, 78 },
+  { 0x1000001, 0x1000001, 10, 2068, -1, 12, 1, 78 },
+  { 0x0, 0x0, 10, -1, 2177, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2179, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2181, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2183, 0, 0, -1 },
+  { 0x1, 0x1, 10, 2069, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 10, 2070, -1, 12, 1, 3 },
+  { 0x1, 0x1, 10, 2071, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 10, 2072, -1, 12, 1, 3 },
+  { 0x0, 0x0, 10, -1, 2185, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2187, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2189, 0, 0, -1 },
+  { 0x0, 0x0, 10, -1, 2191, 0, 0, -1 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x4200001, 11, 2015, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 300, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2077, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2078, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2021, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 308, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2023, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 310, -1, 33, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2025, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 312, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2027, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 314, -1, 33, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2029, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 316, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2031, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 318, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2091, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2092, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, 2093, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 11, 2094, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x4200001, 11, 2035, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 322, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2099, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2100, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x4200001, 11, 2039, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 348, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2125, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2126, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2045, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 356, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2047, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 358, -1, 33, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2049, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 360, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2051, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 362, -1, 33, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 2053, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x0, 0x0, 11, 364, -1, 0, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x200001, 11, 2055, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 366, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2139, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2140, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, 2141, -1, 33, 1, 3 },
+  { 0x200001, 0x200001, 11, 2142, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x200001, 0x4200001, 11, 2059, -1, 12, 1, 3 },
+  { 0x2, 0x3, 11, -1, -1, 37, 1, 5 },
+  { 0x1, 0x1, 11, 370, -1, 33, 1, 3 },
+  { 0x0, 0x0, 11, 2147, -1, 0, 1, 3 },
+  { 0x1, 0x1, 11, 2148, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, 2170, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 11, 2172, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, 2174, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 11, 2176, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 80 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 80 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 80 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 80 },
+  { 0x1, 0x1, 11, 2178, -1, 36, 1, 78 },
+  { 0x1000001, 0x1000001, 11, 2180, -1, 12, 1, 78 },
+  { 0x1, 0x1, 11, 2182, -1, 36, 1, 78 },
+  { 0x1000001, 0x1000001, 11, 2184, -1, 12, 1, 78 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, -1, -1, 36, 1, 5 },
+  { 0x1, 0x1, 11, 2186, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 11, 2188, -1, 12, 1, 3 },
+  { 0x1, 0x1, 11, 2190, -1, 36, 1, 3 },
+  { 0x1000001, 0x1000001, 11, 2192, -1, 12, 1, 3 },
+  { 0x0, 0x0, 12, -1, -1, 0, 1, 15 },
+  { 0x0, 0x0, 12, -1, -1, 0, 1, 15 },
+  { 0x0, 0x0, 12, -1, -1, 0, 1, 15 },
+  { 0x1, 0x1, 13, 272, 1452, 34, 1, 131 },
+  { 0x1, 0x1, 13, 274, 1461, 34, 1, 131 },
+  { 0x1, 0x1, 13, 276, 1470, 34, 1, 131 },
+  { 0x1, 0x1, 13, 280, 1483, 34, 1, 131 },
+  { 0x1, 0x1, 13, 282, 1492, 34, 1, 131 },
+  { 0x1, 0x1, 13, 284, 1501, 34, 1, 131 },
+  { 0x1, 0x1, 13, 286, 1510, 34, 1, 131 },
+  { 0x1, 0x1, 13, 288, 1519, 34, 1, 131 },
+  { 0x1, 0x1, 13, 290, 1528, 34, 1, 131 },
+  { 0x1, 0x1, 13, 292, 1537, 34, 1, 131 },
+  { 0x1, 0x1, 13, 294, 1547, 34, 1, 131 },
+  { 0x1, 0x1, 13, 296, 1557, 34, 1, 131 },
+  { 0x0, 0x0, 19, -1, 795, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 796, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 797, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 798, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 799, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 800, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 801, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 802, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 803, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 804, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 805, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 806, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 807, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 808, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 809, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 810, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 811, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 812, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 813, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 814, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 815, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 816, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 817, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 818, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 819, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 820, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 821, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 822, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 823, 0, 0, -1 },
+  { 0x0, 0x0, 19, -1, 824, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2827, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2828, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2843, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2844, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2849, 0, 0, -1 },
+  { 0x0, 0x0, 20, -1, 2850, 0, 0, -1 },
+  { 0x0, 0x0, 21, 831, 2839, 0, 0, -1 },
+  { 0x0, 0x0, 21, 832, 2841, 0, 0, -1 },
+  { 0x0, 0x0, 23, -1, 2837, 0, 0, -1 },
+  { 0x0, 0x0, 23, -1, 2838, 0, 0, -1 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, 1272, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 6 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 7 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 8 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 16 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, 1293, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 19 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 20 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 21 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, 1326, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 18 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 35, 1, 22 },
+  { 0x1, 0x1, 24, -1, -1, 33, 1, 82 },
+  { 0x1, 0x1, 24, -1, -1, 33, 1, 82 },
+  { 0x1, 0x1, 24, 1342, 1455, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1343, 1464, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1344, 1473, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1345, 1486, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1346, 1495, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1347, 1504, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1348, 1513, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1349, 1522, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1350, 1531, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1351, 1541, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1352, 1551, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1353, 1561, 35, 1, 137 },
+  { 0x1, 0x1, 24, 1354, 1570, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1355, 1576, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1356, 1582, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1357, 1588, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1358, 1594, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1359, 1600, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1360, 1606, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1361, 1612, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1362, 1618, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1363, 1624, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1364, 1630, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1365, 1636, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1366, 1642, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1367, 1648, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1368, 1654, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1369, 1660, 35, 1, 151 },
+  { 0x1, 0x1, 24, 1370, 1666, 35, 1, 156 },
+  { 0x1, 0x1, 24, 1371, 1672, 35, 1, 156 },
+  { 0x0, 0x0, 33, 2821, 2819, 0, 0, -1 },
+  { 0x0, 0x0, 33, 2824, 2822, 0, 0, -1 },
+  { 0x0, 0x0, 33, 2830, 2829, 0, 0, -1 },
+  { 0x0, 0x0, 33, 2832, 2831, 0, 0, -1 },
+  { 0x0, 0x0, 33, 2846, 2845, 0, 0, -1 },
+  { 0x0, 0x0, 33, 2848, 2847, 0, 0, -1 },
+  { 0x0, 0x0, 35, -1, 2840, 0, 0, -1 },
+  { 0x0, 0x0, 35, -1, 2842, 0, 0, -1 },
+  { 0x1, 0x1, 38, -1, 2290, 37, 1, 30 },
+  { 0x1, 0x1, 38, -1, 2349, 37, 1, 30 },
+  { 0x0, 0x0, 38, -1, 2352, 0, 0, -1 },
+  { 0x1, 0x1, 38, -1, -1, 37, 1, 30 },
+  { 0x1, 0x1, 38, -1, 2357, 37, 1, 30 },
+  { 0x0, 0x0, 38, -1, 2360, 0, 0, -1 },
+  { 0x1, 0x1, 38, -1, -1, 37, 1, 30 },
+  { 0x0, 0x0, 38, -1, 2363, 0, 0, -1 },
+  { 0x1, 0x1, 38, -1, -1, 37, 1, 30 },
+  { 0x1, 0x1, 38, -1, 2366, 37, 1, 30 },
+  { 0x1, 0x1, 38, -1, 2369, 37, 1, 30 },
+  { 0x1, 0x1, 38, -1, 2402, 37, 1, 30 },
+  { 0x3, 0x3, 38, -1, -1, 30, 1, 144 },
+  { 0x0, 0x0, 38, 1142, -1, 0, 1, 102 },
+  { 0x0, 0x0, 38, -1, -1, 0, 1, 111 },
+  { 0x0, 0x0, 38, 1148, -1, 0, 1, 123 },
+  { 0x3, 0x3, 38, -1, -1, 30, 1, 160 },
+  { 0x0, 0x0, 38, 1149, -1, 0, 1, 41 },
+  { 0x0, 0x0, 40, -1, 973, 0, 0, -1 },
+  { 0x0, 0x0, 40, -1, 981, 0, 0, -1 },
+  { 0x0, 0x0, 40, 1151, 977, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 622, 33, 1, 6 },
+  { 0x18000001, 0x18000001, 40, -1, 630, 6, 1, 7 },
+  { 0x3, 0x3, 40, 1152, 626, 33, 1, 6 },
+  { 0x0, 0x0, 40, -1, 985, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 642, 33, 1, 8 },
+  { 0x0, 0x0, 40, -1, 989, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 654, 33, 1, 16 },
+  { 0x0, 0x0, 40, -1, 994, 0, 0, -1 },
+  { 0x0, 0x0, 40, -1, 998, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 677, 33, 1, 18 },
+  { 0x3, 0x3, 40, -1, 681, 33, 1, 18 },
+  { 0x0, 0x0, 40, -1, 1002, 0, 0, -1 },
+  { 0x0, 0x0, 40, -1, 1006, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 701, 33, 1, 19 },
+  { 0x18000001, 0x18000001, 40, -1, 705, 6, 1, 19 },
+  { 0x0, 0x0, 40, -1, 1010, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 717, 33, 1, 20 },
+  { 0x0, 0x0, 40, -1, 1014, 0, 0, -1 },
+  { 0x0, 0x0, 40, -1, 1018, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 737, 33, 1, 21 },
+  { 0x18000001, 0x18000001, 40, -1, 741, 6, 1, 21 },
+  { 0x0, 0x0, 40, -1, 1022, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 753, 33, 1, 22 },
+  { 0x0, 0x0, 40, -1, 1027, 0, 0, -1 },
+  { 0x0, 0x0, 40, -1, 1031, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 776, 33, 1, 18 },
+  { 0x3, 0x3, 40, -1, 780, 33, 1, 18 },
+  { 0x0, 0x0, 40, -1, 1035, 0, 0, -1 },
+  { 0x3, 0x3, 40, -1, 792, 33, 1, 22 },
+  { 0x0, 0x0, 41, 851, 972, 0, 0, -1 },
+  { 0x0, 0x0, 41, 852, 980, 0, 0, -1 },
+  { 0x0, 0x0, 41, 853, 976, 0, 0, -1 },
+  { 0x1, 0x1, 41, 854, 621, 34, 1, 6 },
+  { 0x10000001, 0x10000001, 41, 855, 629, 6, 1, 7 },
+  { 0x1, 0x1, 41, 856, 625, 34, 1, 6 },
+  { 0x0, 0x0, 41, 857, 984, 0, 0, -1 },
+  { 0x1, 0x1, 41, 858, 641, 34, 1, 8 },
+  { 0x0, 0x0, 41, 859, 988, 0, 0, -1 },
+  { 0x1, 0x1, 41, 860, 653, 34, 1, 16 },
+  { 0x0, 0x0, 41, 861, 993, 0, 0, -1 },
+  { 0x0, 0x0, 41, 862, 997, 0, 0, -1 },
+  { 0x1, 0x1, 41, 863, 676, 34, 1, 18 },
+  { 0x1, 0x1, 41, 864, 680, 34, 1, 18 },
+  { 0x0, 0x0, 41, 865, 1001, 0, 0, -1 },
+  { 0x0, 0x0, 41, 866, 1005, 0, 0, -1 },
+  { 0x1, 0x1, 41, 867, 700, 34, 1, 19 },
+  { 0x10000001, 0x10000001, 41, 868, 704, 6, 1, 19 },
+  { 0x0, 0x0, 41, 869, 1009, 0, 0, -1 },
+  { 0x1, 0x1, 41, 870, 716, 34, 1, 20 },
+  { 0x0, 0x0, 41, 871, 1013, 0, 0, -1 },
+  { 0x0, 0x0, 41, 872, 1017, 0, 0, -1 },
+  { 0x1, 0x1, 41, 873, 736, 34, 1, 21 },
+  { 0x10000001, 0x10000001, 41, 874, 740, 6, 1, 21 },
+  { 0x0, 0x0, 41, 875, 1021, 0, 0, -1 },
+  { 0x1, 0x1, 41, 876, 752, 34, 1, 22 },
+  { 0x0, 0x0, 41, 877, 1026, 0, 0, -1 },
+  { 0x0, 0x0, 41, 878, 1030, 0, 0, -1 },
+  { 0x1, 0x1, 41, 879, 775, 34, 1, 18 },
+  { 0x1, 0x1, 41, 880, 779, 34, 1, 18 },
+  { 0x0, 0x0, 41, 881, 1034, 0, 0, -1 },
+  { 0x1, 0x1, 41, 882, 791, 34, 1, 22 },
+  { 0x800001, 0x800001, 41, -1, 1156, 4, 1, 17 },
+  { 0x1, 0x1, 41, 2236, 1154, 4, 1, 17 },
+  { 0x1, 0x1, 41, 957, 1159, 4, 1, 23 },
+  { 0x2, 0x3, 41, -1, 1164, 20, 1, 68 },
+  { 0x1, 0x1, 41, 2237, 1162, 21, 1, 68 },
+  { 0x0, 0x0, 42, -1, -1, 0, 1, 86 },
+  { 0x0, 0x0, 42, -1, -1, 0, 1, 86 },
+  { 0x0, 0x0, 42, -1, -1, 0, 1, 130 },
+  { 0x1, 0x1, 44, 1372, 297, 38, 1, 1 },
+  { 0x1, 0x1, 44, 1373, 299, 38, 1, 1 },
+  { 0x0, 0x0, 44, -1, 302, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 424, 0, 0, -1 },
+  { 0x1, 0x1, 44, 1377, 319, 38, 1, 1 },
+  { 0x1, 0x1, 44, 1378, 321, 38, 1, 1 },
+  { 0x0, 0x0, 44, -1, 324, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 464, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 326, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 344, 0, 0, -1 },
+  { 0x1, 0x1, 44, 1384, 345, 38, 1, 1 },
+  { 0x1, 0x1, 44, 1385, 347, 38, 1, 1 },
+  { 0x0, 0x0, 44, -1, 350, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 472, 0, 0, -1 },
+  { 0x1, 0x1, 44, 1389, 367, 38, 1, 1 },
+  { 0x1, 0x1, 44, 1390, 369, 38, 1, 1 },
+  { 0x0, 0x0, 44, -1, 372, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 512, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 374, 0, 0, -1 },
+  { 0x0, 0x0, 44, -1, 392, 0, 0, -1 },
+  { 0x0, 0x0, 44, 1248, 2297, 0, 0, -1 },
+  { 0x0, 0x0, 44, 1249, 2305, 0, 1, 55 },
+  { 0x0, 0x0, 44, 1250, 2972, 0, 1, 55 },
+  { 0x0, 0x0, 44, 1251, 2373, 0, 0, -1 },
+  { 0x0, 0x0, 44, 1252, -1, 0, 1, 50 },
+  { 0x0, 0x0, 44, 1120, -1, 0, 1, 0 },
+  { 0x0, 0x0, 44, 1121, -1, 0, 1, 0 },
+  { 0x0, 0x0, 44, 1122, -1, 0, 1, 0 },
+  { 0x1, 0x1, 45, -1, 1676, 30, 1, 158 },
+  { 0x1, 0x1, 45, 963, 1675, 30, 1, 158 },
+  { 0x1, 0x1, 45, -1, 1680, 30, 1, 159 },
+  { 0x1, 0x1, 45, 964, 1679, 30, 1, 159 },
+  { 0x1, 0x1, 45, -1, 1684, 30, 1, 159 },
+  { 0x1, 0x1, 45, 965, 1683, 30, 1, 159 },
+  { 0x3, 0x3, 46, -1, 1160, 3, 1, 23 },
+  { 0x1, 0x1, 47, 2257, -1, 30, 1, 144 },
+  { 0x1, 0x1, 47, 2288, -1, 30, 1, 160 },
+  { 0x0, 0x0, 49, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 49, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 49, -1, -1, 0, 1, 41 },
+  { 0x1, 0x1, 56, -1, 1677, 31, 1, 158 },
+  { 0x1, 0x1, 56, -1, 1681, 31, 1, 159 },
+  { 0x1, 0x1, 56, -1, 1685, 31, 1, 159 },
+  { 0x0, 0x0, 56, -1, -1, 0, 1, 101 },
+  { 0x2, 0x3, 56, -1, -1, 27, 1, 101 },
+  { 0x1, 0x1, 56, -1, -1, 28, 1, 101 },
+  { 0x0, 0x0, 65, 14, 592, 0, 1, 6 },
+  { 0x0, 0x0, 65, 1273, 595, 0, 1, 6 },
+  { 0x1, 0x1, 65, 1274, 597, 33, 1, 6 },
+  { 0x1, 0x1, 65, 1275, 599, 34, 1, 6 },
+  { 0x3, 0x3, 65, 1276, 601, 33, 1, 6 },
+  { 0x0, 0x0, 65, 1277, 603, 0, 1, 6 },
+  { 0x1, 0x1, 65, 1278, 605, 33, 1, 6 },
+  { 0x1, 0x1, 65, 1279, 607, 34, 1, 6 },
+  { 0x3, 0x3, 65, 1280, 609, 33, 1, 6 },
+  { 0x1, 0x1, 65, 1281, 611, 6, 1, 7 },
+  { 0x8000001, 0x8000001, 65, 1282, 613, 6, 1, 7 },
+  { 0x10000001, 0x10000001, 65, 1283, 615, 6, 1, 7 },
+  { 0x18000001, 0x18000001, 65, 1284, 617, 6, 1, 7 },
+  { 0x0, 0x0, 65, 1285, 631, 0, 1, 8 },
+  { 0x1, 0x1, 65, 1286, 633, 33, 1, 8 },
+  { 0x1, 0x1, 65, 1287, 635, 34, 1, 8 },
+  { 0x3, 0x3, 65, 1288, 637, 33, 1, 8 },
+  { 0x0, 0x0, 65, 1289, 643, 0, 1, 16 },
+  { 0x1, 0x1, 65, 1290, 645, 33, 1, 16 },
+  { 0x1, 0x1, 65, 1291, 647, 34, 1, 16 },
+  { 0x3, 0x3, 65, 1292, 649, 33, 1, 16 },
+  { 0x0, 0x0, 65, 15, 655, 0, 1, 18 },
+  { 0x0, 0x0, 65, 1294, 658, 0, 1, 18 },
+  { 0x1, 0x1, 65, 1295, 660, 33, 1, 18 },
+  { 0x1, 0x1, 65, 1296, 662, 34, 1, 18 },
+  { 0x3, 0x3, 65, 1297, 664, 33, 1, 18 },
+  { 0x0, 0x0, 65, 1298, 666, 0, 1, 18 },
+  { 0x1, 0x1, 65, 1299, 668, 33, 1, 18 },
+  { 0x1, 0x1, 65, 1300, 670, 34, 1, 18 },
+  { 0x3, 0x3, 65, 1301, 672, 33, 1, 18 },
+  { 0x0, 0x0, 65, 1302, 682, 0, 1, 19 },
+  { 0x1, 0x1, 65, 1303, 684, 33, 1, 19 },
+  { 0x1, 0x1, 65, 1304, 686, 34, 1, 19 },
+  { 0x3, 0x3, 65, 1305, 688, 33, 1, 19 },
+  { 0x1, 0x1, 65, 1306, 690, 6, 1, 19 },
+  { 0x8000001, 0x8000001, 65, 1307, 692, 6, 1, 19 },
+  { 0x10000001, 0x10000001, 65, 1308, 694, 6, 1, 19 },
+  { 0x18000001, 0x18000001, 65, 1309, 696, 6, 1, 19 },
+  { 0x0, 0x0, 65, 1310, 706, 0, 1, 20 },
+  { 0x1, 0x1, 65, 1311, 708, 33, 1, 20 },
+  { 0x1, 0x1, 65, 1312, 710, 34, 1, 20 },
+  { 0x3, 0x3, 65, 1313, 712, 33, 1, 20 },
+  { 0x0, 0x0, 65, 1314, 718, 0, 1, 21 },
+  { 0x1, 0x1, 65, 1315, 720, 33, 1, 21 },
+  { 0x1, 0x1, 65, 1316, 722, 34, 1, 21 },
+  { 0x3, 0x3, 65, 1317, 724, 33, 1, 21 },
+  { 0x1, 0x1, 65, 1318, 726, 6, 1, 21 },
+  { 0x8000001, 0x8000001, 65, 1319, 728, 6, 1, 21 },
+  { 0x10000001, 0x10000001, 65, 1320, 730, 6, 1, 21 },
+  { 0x18000001, 0x18000001, 65, 1321, 732, 6, 1, 21 },
+  { 0x0, 0x0, 65, 1322, 742, 0, 1, 22 },
+  { 0x1, 0x1, 65, 1323, 744, 33, 1, 22 },
+  { 0x1, 0x1, 65, 1324, 746, 34, 1, 22 },
+  { 0x3, 0x3, 65, 1325, 748, 33, 1, 22 },
+  { 0x0, 0x0, 65, 17, 754, 0, 1, 18 },
+  { 0x0, 0x0, 65, 1327, 757, 0, 1, 18 },
+  { 0x1, 0x1, 65, 1328, 759, 33, 1, 18 },
+  { 0x1, 0x1, 65, 1329, 761, 34, 1, 18 },
+  { 0x3, 0x3, 65, 1330, 763, 33, 1, 18 },
+  { 0x0, 0x0, 65, 1331, 765, 0, 1, 18 },
+  { 0x1, 0x1, 65, 1332, 767, 33, 1, 18 },
+  { 0x1, 0x1, 65, 1333, 769, 34, 1, 18 },
+  { 0x3, 0x3, 65, 1334, 771, 33, 1, 18 },
+  { 0x0, 0x0, 65, 1335, 781, 0, 1, 22 },
+  { 0x1, 0x1, 65, 1336, 783, 33, 1, 22 },
+  { 0x1, 0x1, 65, 1337, 785, 34, 1, 22 },
+  { 0x3, 0x3, 65, 1338, 787, 33, 1, 22 },
+  { 0x3, 0x3, 66, 561, 1539, 33, 1, 136 },
+  { 0x3, 0x3, 66, 562, 1549, 33, 1, 136 },
+  { 0x3, 0x3, 66, 563, 1559, 33, 1, 136 },
+  { 0x0, 0x0, 66, -1, 1564, 0, 1, 147 },
+  { 0x0, 0x0, 66, -1, 1565, 0, 1, 152 },
+  { 0x0, 0x0, 66, -1, 1566, 0, 1, 152 },
+  { 0x0, 0x0, 107, 1046, 2345, 0, 0, -1 },
+  { 0x0, 0x0, 107, 1047, 2864, 0, 1, 30 },
+  { 0x0, 0x0, 107, 1048, 2386, 0, 0, -1 },
+  { 0x0, 0x0, 107, 1049, 2868, 0, 1, 30 },
+  { 0x0, 0x0, 109, -1, 2347, 0, 0, -1 },
+  { 0x1, 0x1, 109, -1, 2865, 27, 1, 30 },
+  { 0x0, 0x0, 109, -1, 2388, 0, 0, -1 },
+  { 0x1, 0x1, 109, -1, 2869, 27, 1, 30 },
+  { 0x0, 0x0, 110, 1051, -1, 0, 1, 122 },
+  { 0x1, 0x1, 111, -1, -1, 27, 1, 122 },
+  { 0x0, 0x0, 112, 1082, 2894, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1083, 2897, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1224, 305, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1225, 309, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1185, 440, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1186, 448, 0, 0, -1 },
+  { 0x0, 0x0, 112, -1, 456, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1084, 2910, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1085, 2913, 0, 1, 1 },
+  { 0x0, 0x0, 112, -1, 330, 0, 0, -1 },
+  { 0x0, 0x0, 112, -1, 334, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1233, 335, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1234, 339, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1086, 2934, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1087, 2937, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1237, 353, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1238, 357, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1198, 488, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1199, 496, 0, 0, -1 },
+  { 0x0, 0x0, 112, -1, 504, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1391, 2948, 0, 1, 1 },
+  { 0x0, 0x0, 112, 1392, 2950, 0, 1, 1 },
+  { 0x0, 0x0, 112, -1, 378, 0, 0, -1 },
+  { 0x0, 0x0, 112, -1, 382, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1246, 383, 0, 0, -1 },
+  { 0x0, 0x0, 112, 1247, 387, 0, 0, -1 },
+  { 0x0, 0x0, 112, -1, 2315, 0, 0, -1 },
+  { 0x1, 0x9, 112, -1, 2319, 33, 1, 55 },
+  { 0x1, 0x9, 112, -1, 2981, 33, 1, 55 },
+  { 0x2, 0x3, 112, 1408, 2382, 27, 1, 50 },
+  { 0x1, 0x1, 114, 1374, 2895, 37, 1, 1 },
+  { 0x1, 0x1, 114, 1375, 2898, 37, 1, 1 },
+  { 0x1, 0x1, 114, 1379, 2911, 37, 1, 1 },
+  { 0x1, 0x1, 114, 1380, 2914, 37, 1, 1 },
+  { 0x1, 0x1, 114, 1386, 2935, 37, 1, 1 },
+  { 0x1, 0x1, 114, 1387, 2938, 37, 1, 1 },
+  { 0x0, 0x0, 114, -1, 2958, 0, 1, 1 },
+  { 0x0, 0x0, 114, -1, 2959, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1123, 2890, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1124, 2892, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1183, 303, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1184, 307, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 444, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 452, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1228, 454, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 2908, 0, 1, 1 },
+  { 0x0, 0x0, 115, -1, 2909, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1231, 328, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1232, 332, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1192, 337, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1193, 341, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1127, 2930, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1128, 2932, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1196, 351, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1197, 355, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 492, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 500, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1241, 502, 0, 0, -1 },
+  { 0x0, 0x0, 115, -1, 2946, 0, 1, 1 },
+  { 0x0, 0x0, 115, -1, 2947, 0, 1, 1 },
+  { 0x0, 0x0, 115, 1244, 376, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1245, 380, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1205, 385, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1206, 389, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1078, 2313, 0, 0, -1 },
+  { 0x0, 0x0, 115, 1079, 2317, 0, 1, 55 },
+  { 0x0, 0x0, 115, 1080, 2980, 0, 1, 55 },
+  { 0x0, 0x0, 115, 1081, 2381, 0, 1, 50 },
+  { 0x1, 0x1, 115, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 115, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 115, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 116, -1, 2891, 37, 1, 1 },
+  { 0x1, 0x1, 116, -1, 2893, 37, 1, 1 },
+  { 0x0, 0x0, 116, -1, 2918, 0, 1, 1 },
+  { 0x0, 0x0, 116, -1, 2919, 0, 1, 1 },
+  { 0x1, 0x1, 116, -1, 2931, 37, 1, 1 },
+  { 0x1, 0x1, 116, -1, 2933, 37, 1, 1 },
+  { 0x0, 0x0, 116, -1, 2956, 0, 1, 1 },
+  { 0x0, 0x0, 116, -1, 2957, 0, 1, 1 },
+  { 0x0, 0x0, 117, 1176, -1, 0, 1, 0 },
+  { 0x0, 0x0, 117, 1177, -1, 0, 1, 0 },
+  { 0x0, 0x0, 117, 1178, -1, 0, 1, 0 },
+  { 0x3, 0x3, 117, 1136, -1, 34, 1, 34 },
+  { 0x3, 0x3, 117, 1137, -1, 34, 1, 41 },
+  { 0x1, 0x1, 119, -1, -1, 35, 1, 34 },
+  { 0x1, 0x1, 119, -1, -1, 35, 1, 41 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 67 },
+  { 0x1, 0x1, 120, -1, -1, 36, 1, 129 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 41 },
+  { 0x1, 0x1, 120, -1, -1, 27, 1, 103 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 112 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 74 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 74 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 75 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 41 },
+  { 0x1, 0x1, 120, -1, -1, 27, 1, 124 },
+  { 0x1, 0x1, 120, -1, -1, 27, 1, 41 },
+  { 0x0, 0x0, 120, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 121, -1, 2820, 0, 0, -1 },
+  { 0x0, 0x0, 121, -1, 2823, 0, 0, -1 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 17 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 17 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 17 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 17 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 23 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 23 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 23 },
+  { 0x1, 0x1, 122, -1, -1, 35, 1, 23 },
+  { 0x1, 0x1, 122, -1, -1, 23, 1, 68 },
+  { 0x1, 0x1, 122, -1, -1, 23, 1, 68 },
+  { 0x1, 0x1, 122, -1, -1, 23, 1, 68 },
+  { 0x1, 0x1, 122, -1, -1, 23, 1, 68 },
+  { 0x1, 0x1, 122, 918, -1, 23, 1, 68 },
+  { 0x9, 0x9, 122, 919, -1, 20, 1, 68 },
+  { 0x0, 0x0, 126, 2199, -1, 0, 1, 0 },
+  { 0x0, 0x0, 126, 2200, -1, 0, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 28, 1, 34 },
+  { 0x1, 0x1, 126, -1, -1, 27, 1, 34 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x0, 0x0, 126, -1, -1, 0, 1, 121 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 126, -1, -1, 29, 1, 0 },
+  { 0x0, 0x0, 126, 1134, -1, 0, 1, 34 },
+  { 0x0, 0x0, 126, 1262, -1, 0, 1, 41 },
+  { 0x0, 0x0, 140, 1212, 2886, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1213, 2888, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1054, 304, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1055, 432, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1094, 313, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1095, 317, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1096, 453, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 2906, 0, 1, 1 },
+  { 0x0, 0x0, 140, -1, 2907, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1099, 327, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1100, 331, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 338, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 342, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1216, 2926, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1217, 2928, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1067, 352, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1068, 480, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1107, 361, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1108, 365, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1109, 501, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 2944, 0, 1, 1 },
+  { 0x0, 0x0, 140, -1, 2945, 0, 1, 1 },
+  { 0x0, 0x0, 140, 1112, 375, 0, 0, -1 },
+  { 0x0, 0x0, 140, 1113, 379, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 386, 0, 0, -1 },
+  { 0x0, 0x0, 140, -1, 390, 0, 0, -1 },
+  { 0x0, 0x0, 140, 3012, 2301, 0, 0, -1 },
+  { 0x1, 0x1, 140, 3013, 2309, 33, 1, 55 },
+  { 0x1, 0x1, 140, 3014, 2974, 33, 1, 55 },
+  { 0x0, 0x0, 140, 3015, 2375, 0, 0, -1 },
+  { 0x1, 0x1, 140, 3016, -1, 28, 1, 50 },
+  { 0x1, 0x1, 141, -1, 2887, 37, 1, 1 },
+  { 0x1, 0x1, 141, -1, 2889, 37, 1, 1 },
+  { 0x0, 0x0, 141, -1, 2916, 0, 1, 1 },
+  { 0x0, 0x0, 141, -1, 2917, 0, 1, 1 },
+  { 0x1, 0x1, 141, -1, 2927, 37, 1, 1 },
+  { 0x1, 0x1, 141, -1, 2929, 37, 1, 1 },
+  { 0x0, 0x0, 141, -1, 2954, 0, 1, 1 },
+  { 0x0, 0x0, 141, -1, 2955, 0, 1, 1 },
+  { 0x1, 0x1, 144, 917, 1158, 3, 1, 23 },
+  { 0x0, 0x0, 145, 2201, -1, 0, 1, 34 },
+  { 0x0, 0x0, 146, 923, 2880, 0, 1, 1 },
+  { 0x0, 0x0, 146, 924, 2883, 0, 1, 1 },
+  { 0x0, 0x0, 146, -1, 306, 0, 0, -1 },
+  { 0x0, 0x0, 146, -1, 436, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1056, 311, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1057, 315, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1058, 455, 0, 0, -1 },
+  { 0x0, 0x0, 146, 927, 2900, 0, 1, 1 },
+  { 0x0, 0x0, 146, 928, 2903, 0, 1, 1 },
+  { 0x0, 0x0, 146, 1061, 329, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1062, 333, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1101, 336, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1102, 340, 0, 0, -1 },
+  { 0x0, 0x0, 146, 933, 2920, 0, 1, 1 },
+  { 0x0, 0x0, 146, 934, 2923, 0, 1, 1 },
+  { 0x0, 0x0, 146, -1, 354, 0, 0, -1 },
+  { 0x0, 0x0, 146, -1, 484, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1069, 359, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1070, 363, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1071, 503, 0, 0, -1 },
+  { 0x0, 0x0, 146, 937, 2940, 0, 1, 1 },
+  { 0x0, 0x0, 146, 938, 2942, 0, 1, 1 },
+  { 0x0, 0x0, 146, 1074, 377, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1075, 381, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1114, 384, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1115, 388, 0, 0, -1 },
+  { 0x0, 0x0, 146, 1207, 2299, 0, 0, -1 },
+  { 0x1, 0x1, 146, 1208, 2307, 36, 1, 55 },
+  { 0x1, 0x1, 146, 1209, 2973, 36, 1, 55 },
+  { 0x0, 0x0, 146, 1210, 2374, 0, 0, -1 },
+  { 0x1, 0x1, 146, 1211, -1, 27, 1, 50 },
+  { 0x1, 0x1, 147, -1, 2882, 37, 1, 1 },
+  { 0x1, 0x1, 147, -1, 2885, 37, 1, 1 },
+  { 0x1, 0x1, 147, -1, 2902, 37, 1, 1 },
+  { 0x1, 0x1, 147, -1, 2905, 37, 1, 1 },
+  { 0x1, 0x1, 147, -1, 2922, 37, 1, 1 },
+  { 0x1, 0x1, 147, -1, 2925, 37, 1, 1 },
+  { 0x0, 0x0, 147, -1, 2952, 0, 1, 1 },
+  { 0x0, 0x0, 147, -1, 2953, 0, 1, 1 },
+  { 0x0, 0x0, 148, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 148, 1135, -1, 0, 1, 41 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 67 },
+  { 0x0, 0x0, 149, -1, 2960, 0, 1, 64 },
+  { 0x0, 0x0, 149, -1, 2961, 0, 1, 64 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 87 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 87 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 92 },
+  { 0x0, 0x0, 149, -1, -1, 0, 1, 41 },
+  { 0x1, 0x1, 150, -1, 593, 12, 1, 6 },
+  { 0x1, 0x1, 150, -1, 596, 12, 1, 6 },
+  { 0x200001, 0x200001, 150, -1, 598, 12, 1, 6 },
+  { 0x400001, 0x400001, 150, -1, 600, 12, 1, 6 },
+  { 0x600001, 0x600001, 150, -1, 602, 12, 1, 6 },
+  { 0x1, 0x1, 150, -1, 604, 12, 1, 6 },
+  { 0x200001, 0x200001, 150, -1, 606, 12, 1, 6 },
+  { 0x400001, 0x400001, 150, -1, 608, 12, 1, 6 },
+  { 0x600001, 0x600001, 150, -1, 610, 12, 1, 6 },
+  { 0x41, 0x41, 150, -1, 612, 6, 1, 7 },
+  { 0x8000041, 0x8000041, 150, -1, 614, 6, 1, 7 },
+  { 0x10000041, 0x10000041, 150, -1, 616, 6, 1, 7 },
+  { 0x18000041, 0x18000041, 150, -1, 618, 6, 1, 7 },
+  { 0x1, 0x1, 150, -1, 632, 12, 1, 8 },
+  { 0x200001, 0x200001, 150, -1, 634, 12, 1, 8 },
+  { 0x400001, 0x400001, 150, -1, 636, 12, 1, 8 },
+  { 0x600001, 0x600001, 150, -1, 638, 12, 1, 8 },
+  { 0x1, 0x1, 150, -1, 644, 12, 1, 16 },
+  { 0x200001, 0x200001, 150, -1, 646, 12, 1, 16 },
+  { 0x400001, 0x400001, 150, -1, 648, 12, 1, 16 },
+  { 0x600001, 0x600001, 150, -1, 650, 12, 1, 16 },
+  { 0x1, 0x1, 150, -1, 656, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 659, 12, 1, 18 },
+  { 0x200001, 0x200001, 150, -1, 661, 12, 1, 18 },
+  { 0x400001, 0x400001, 150, -1, 663, 12, 1, 18 },
+  { 0x600001, 0x600001, 150, -1, 665, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 667, 12, 1, 18 },
+  { 0x200001, 0x200001, 150, -1, 669, 12, 1, 18 },
+  { 0x400001, 0x400001, 150, -1, 671, 12, 1, 18 },
+  { 0x600001, 0x600001, 150, -1, 673, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 683, 12, 1, 19 },
+  { 0x200001, 0x200001, 150, -1, 685, 12, 1, 19 },
+  { 0x400001, 0x400001, 150, -1, 687, 12, 1, 19 },
+  { 0x600001, 0x600001, 150, -1, 689, 12, 1, 19 },
+  { 0x41, 0x41, 150, -1, 691, 6, 1, 19 },
+  { 0x8000041, 0x8000041, 150, -1, 693, 6, 1, 19 },
+  { 0x10000041, 0x10000041, 150, -1, 695, 6, 1, 19 },
+  { 0x18000041, 0x18000041, 150, -1, 697, 6, 1, 19 },
+  { 0x1, 0x1, 150, -1, 707, 12, 1, 20 },
+  { 0x200001, 0x200001, 150, -1, 709, 12, 1, 20 },
+  { 0x400001, 0x400001, 150, -1, 711, 12, 1, 20 },
+  { 0x600001, 0x600001, 150, -1, 713, 12, 1, 20 },
+  { 0x1, 0x1, 150, -1, 719, 12, 1, 21 },
+  { 0x200001, 0x200001, 150, -1, 721, 12, 1, 21 },
+  { 0x400001, 0x400001, 150, -1, 723, 12, 1, 21 },
+  { 0x600001, 0x600001, 150, -1, 725, 12, 1, 21 },
+  { 0x41, 0x41, 150, -1, 727, 6, 1, 21 },
+  { 0x8000041, 0x8000041, 150, -1, 729, 6, 1, 21 },
+  { 0x10000041, 0x10000041, 150, -1, 731, 6, 1, 21 },
+  { 0x18000041, 0x18000041, 150, -1, 733, 6, 1, 21 },
+  { 0x1, 0x1, 150, -1, 743, 12, 1, 22 },
+  { 0x200001, 0x200001, 150, -1, 745, 12, 1, 22 },
+  { 0x400001, 0x400001, 150, -1, 747, 12, 1, 22 },
+  { 0x600001, 0x600001, 150, -1, 749, 12, 1, 22 },
+  { 0x1, 0x1, 150, -1, 755, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 758, 12, 1, 18 },
+  { 0x200001, 0x200001, 150, -1, 760, 12, 1, 18 },
+  { 0x400001, 0x400001, 150, -1, 762, 12, 1, 18 },
+  { 0x600001, 0x600001, 150, -1, 764, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 766, 12, 1, 18 },
+  { 0x200001, 0x200001, 150, -1, 768, 12, 1, 18 },
+  { 0x400001, 0x400001, 150, -1, 770, 12, 1, 18 },
+  { 0x600001, 0x600001, 150, -1, 772, 12, 1, 18 },
+  { 0x1, 0x1, 150, -1, 782, 12, 1, 22 },
+  { 0x200001, 0x200001, 150, -1, 784, 12, 1, 22 },
+  { 0x400001, 0x400001, 150, -1, 786, 12, 1, 22 },
+  { 0x600001, 0x600001, 150, -1, 788, 12, 1, 22 },
+  { 0x0, 0x0, 155, -1, -1, 0, 1, 131 },
+  { 0x0, 0x0, 159, 793, -1, 0, 1, 81 },
+  { 0x0, 0x0, 159, 794, -1, 0, 1, 81 },
+  { 0x9, 0x9, 159, -1, 1456, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1465, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1474, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1487, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1496, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1505, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1514, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1523, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1532, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1542, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1552, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1562, 32, 1, 137 },
+  { 0x9, 0x9, 159, -1, 1571, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1577, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1583, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1589, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1595, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1601, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1607, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1613, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1619, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1625, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1631, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1637, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1643, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1649, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1655, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1661, 32, 1, 151 },
+  { 0x9, 0x9, 159, -1, 1667, 32, 1, 156 },
+  { 0x9, 0x9, 159, -1, 1673, 32, 1, 156 },
+  { 0x0, 0x0, 160, 1253, 298, 0, 0, -1 },
+  { 0x0, 0x0, 160, 1254, 422, 0, 0, -1 },
+  { 0x1, 0x1, 160, -1, 2896, 38, 1, 1 },
+  { 0x1, 0x1, 160, 925, 2899, 38, 1, 1 },
+  { 0x0, 0x0, 160, 926, 423, 0, 0, -1 },
+  { 0x0, 0x0, 160, 1255, 320, 0, 0, -1 },
+  { 0x0, 0x0, 160, 1256, 462, 0, 0, -1 },
+  { 0x1, 0x1, 160, -1, 2912, 38, 1, 1 },
+  { 0x1, 0x1, 160, 929, 2915, 38, 1, 1 },
+  { 0x0, 0x0, 160, 930, 463, 0, 0, -1 },
+  { 0x0, 0x0, 160, 931, 325, 0, 0, -1 },
+  { 0x0, 0x0, 160, 932, 343, 0, 0, -1 },
+  { 0x0, 0x0, 160, 1257, 346, 0, 0, -1 },
+  { 0x0, 0x0, 160, 1258, 470, 0, 0, -1 },
+  { 0x1, 0x1, 160, -1, 2936, 38, 1, 1 },
+  { 0x1, 0x1, 160, 935, 2939, 38, 1, 1 },
+  { 0x0, 0x0, 160, 936, 471, 0, 0, -1 },
+  { 0x0, 0x0, 160, -1, 368, 0, 0, -1 },
+  { 0x0, 0x0, 160, -1, 510, 0, 0, -1 },
+  { 0x1, 0x1, 160, -1, 2949, 38, 1, 1 },
+  { 0x1, 0x1, 160, 939, 2951, 38, 1, 1 },
+  { 0x0, 0x0, 160, 940, 511, 0, 0, -1 },
+  { 0x0, 0x0, 160, 941, 373, 0, 0, -1 },
+  { 0x0, 0x0, 160, 942, 391, 0, 0, -1 },
+  { 0x0, 0x0, 161, 1415, 2321, 0, 0, -1 },
+  { 0x0, 0x0, 161, 1416, 2329, 0, 1, 55 },
+  { 0x0, 0x0, 161, 1417, 2990, 0, 1, 55 },
+  { 0x0, 0x0, 161, 1418, 2377, 0, 0, -1 },
+  { 0x1, 0x1, 161, 1419, -1, 29, 1, 50 },
+  { 0x0, 0x0, 162, -1, 2339, 0, 0, -1 },
+  { 0x1, 0x9, 162, -1, 2343, 33, 1, 55 },
+  { 0x1, 0x9, 162, -1, 2999, 33, 1, 55 },
+  { 0x6, 0x7, 162, -1, 2384, 27, 1, 50 },
+  { 0x0, 0x0, 163, 1401, 2337, 0, 0, -1 },
+  { 0x0, 0x0, 163, 1402, 2341, 0, 1, 55 },
+  { 0x0, 0x0, 163, 1403, 2998, 0, 1, 55 },
+  { 0x1, 0x1, 163, 1404, 2383, 29, 1, 50 },
+  { 0x1, 0x1, 164, 1422, -1, 27, 1, 34 },
+  { 0x0, 0x0, 165, 2193, 2325, 0, 0, -1 },
+  { 0x1, 0x1, 165, 2194, 2333, 33, 1, 55 },
+  { 0x1, 0x1, 165, 2195, 2992, 33, 1, 55 },
+  { 0x0, 0x0, 165, 2196, 2379, 0, 0, -1 },
+  { 0x3, 0x3, 165, 2197, -1, 28, 1, 50 },
+  { 0x0, 0x0, 166, 1410, 2323, 0, 0, -1 },
+  { 0x1, 0x1, 166, 1411, 2331, 36, 1, 55 },
+  { 0x1, 0x1, 166, 1412, 2991, 36, 1, 55 },
+  { 0x0, 0x0, 166, 1413, 2378, 0, 0, -1 },
+  { 0x5, 0x5, 166, 1414, -1, 27, 1, 50 },
+  { 0x0, 0x0, 167, -1, 2962, 0, 1, 64 },
+  { 0x0, 0x0, 167, -1, 2963, 0, 1, 64 },
+  { 0x1, 0x1, 169, -1, -1, 28, 1, 34 },
+  { 0x1, 0x1, 170, 2779, -1, 27, 1, 34 },
+  { 0x1, 0x1, 170, 2780, -1, 27, 1, 34 },
+  { 0x1, 0x1, 171, 1703, -1, 28, 1, 142 },
+  { 0x1, 0x1, 171, 1704, -1, 28, 1, 142 },
+  { 0x1, 0x1, 171, 1705, -1, 28, 1, 142 },
+  { 0x1, 0x1, 171, 1706, -1, 28, 1, 142 },
+  { 0x1, 0x1, 171, 1707, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1708, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1709, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1710, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1711, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1712, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1713, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1714, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1715, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1716, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1717, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1718, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1719, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1720, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1721, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1722, -1, 28, 1, 141 },
+  { 0x1, 0x1, 171, 1723, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1724, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1725, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1726, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1727, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1728, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1729, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1730, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1731, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1732, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1733, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1734, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1735, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1736, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1737, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1738, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1739, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1740, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1741, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1742, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1743, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1744, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1745, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1746, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1747, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1748, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1749, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1750, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1751, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1752, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1753, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1754, -1, 28, 1, 132 },
+  { 0x1, 0x1, 171, 1755, -1, 28, 1, 132 },
+  { 0x1, 0x1, 171, 1756, -1, 28, 1, 132 },
+  { 0x1, 0x1, 171, 1757, -1, 28, 1, 132 },
+  { 0x1, 0x1, 171, 1758, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1759, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1760, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1761, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1762, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1763, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1764, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1765, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1766, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1767, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1768, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1769, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1770, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1771, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1772, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1773, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1774, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1775, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1776, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1777, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1778, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1779, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1780, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1781, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1782, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1783, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1784, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1785, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1786, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1787, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1788, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1789, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1790, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1791, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1792, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1793, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1794, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1795, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1796, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1797, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1798, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1799, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1800, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1801, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1802, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1803, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1804, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1805, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1806, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1807, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1808, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1809, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1810, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1811, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1812, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1813, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1814, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1815, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1816, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1817, -1, 28, 1, 136 },
+  { 0x1, 0x1, 171, 1818, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1819, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1820, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1821, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1822, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1823, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1824, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1825, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1826, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1827, -1, 28, 1, 136 },
+  { 0x1, 0x1, 171, 1828, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1829, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1830, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1831, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1832, -1, 28, 1, 133 },
+  { 0x1, 0x1, 171, 1833, -1, 28, 1, 134 },
+  { 0x1, 0x1, 171, 1834, -1, 28, 1, 135 },
+  { 0x1, 0x1, 171, 1835, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1836, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1837, -1, 28, 1, 136 },
+  { 0x1, 0x1, 171, 1838, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1839, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1840, -1, 28, 1, 137 },
+  { 0x1, 0x1, 171, 1841, -1, 28, 1, 131 },
+  { 0x1, 0x1, 171, 1842, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1843, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1844, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1845, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1846, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1847, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1848, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1849, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1850, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1851, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1852, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1853, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1854, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1855, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1856, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1857, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1858, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1859, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1860, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1861, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1862, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1863, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1864, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1865, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1866, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1867, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1868, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1869, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1870, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1871, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1872, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1873, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1874, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1875, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1876, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1877, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1878, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1879, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1880, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1881, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1882, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1883, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1884, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1885, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1886, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1887, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1888, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1889, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1890, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1891, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1892, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1893, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1894, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1895, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1896, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1897, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1898, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1899, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1900, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1901, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1902, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1903, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1904, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1905, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1906, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1907, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1908, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1909, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1910, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1911, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1912, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1913, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1914, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1915, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1916, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1917, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1918, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1919, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1920, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1921, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1922, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1923, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1924, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1925, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1926, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1927, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1928, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1929, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1930, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1931, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1932, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1933, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1934, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1935, -1, 28, 1, 148 },
+  { 0x1, 0x1, 171, 1936, -1, 28, 1, 149 },
+  { 0x1, 0x1, 171, 1937, -1, 28, 1, 150 },
+  { 0x1, 0x1, 171, 1938, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1939, -1, 28, 1, 151 },
+  { 0x1, 0x1, 171, 1940, -1, 28, 1, 147 },
+  { 0x1, 0x1, 171, 1941, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1942, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1943, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1944, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1945, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1946, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1947, -1, 28, 1, 153 },
+  { 0x1, 0x1, 171, 1948, -1, 28, 1, 154 },
+  { 0x1, 0x1, 171, 1949, -1, 28, 1, 155 },
+  { 0x1, 0x1, 171, 1950, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1951, -1, 28, 1, 156 },
+  { 0x1, 0x1, 171, 1952, -1, 28, 1, 152 },
+  { 0x1, 0x1, 171, 1691, -1, 28, 1, 158 },
+  { 0x1, 0x1, 171, 1692, -1, 28, 1, 158 },
+  { 0x1, 0x1, 171, 1693, -1, 28, 1, 158 },
+  { 0x1, 0x1, 171, 1694, -1, 28, 1, 158 },
+  { 0x1, 0x1, 171, 1695, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1696, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1697, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1698, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1699, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1700, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1701, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1702, -1, 28, 1, 159 },
+  { 0x1, 0x1, 171, 1997, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1998, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 1999, -1, 28, 1, 143 },
+  { 0x1, 0x1, 171, 2000, -1, 28, 1, 143 },
+  { 0x1, 0x1, 172, 1953, -1, 29, 1, 158 },
+  { 0x1, 0x1, 172, 1954, -1, 29, 1, 158 },
+  { 0x1, 0x1, 172, 1955, -1, 29, 1, 158 },
+  { 0x1, 0x1, 172, 1956, -1, 29, 1, 158 },
+  { 0x1, 0x1, 172, 1957, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1958, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1959, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1960, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1961, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1962, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1963, -1, 29, 1, 159 },
+  { 0x1, 0x1, 172, 1964, -1, 29, 1, 159 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 142 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 142 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 142 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 142 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 141 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 271, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2258, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 273, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2259, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 275, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2260, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 132 },
+  { 0x3, 0x3, 173, 277, -1, 28, 1, 132 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 132 },
+  { 0x3, 0x3, 173, 278, -1, 28, 1, 132 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 279, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2261, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 281, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2262, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 283, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2263, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 285, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2264, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 287, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2265, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 289, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2266, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 136 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 291, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2267, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 136 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 293, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2268, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 133 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 134 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 135 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 136 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 295, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 137 },
+  { 0x3, 0x3, 173, 2269, -1, 28, 1, 131 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2270, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2271, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2272, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2273, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2274, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2275, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2276, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2277, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2278, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2279, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2280, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2281, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2282, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2283, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2284, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 148 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 149 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 150 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 151 },
+  { 0x3, 0x3, 173, 2285, -1, 28, 1, 147 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2286, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 153 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 154 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 155 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 156 },
+  { 0x3, 0x3, 173, 2287, -1, 28, 1, 152 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 158 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 158 },
+  { 0x3, 0x3, 173, 951, -1, 28, 1, 158 },
+  { 0x3, 0x3, 173, 952, -1, 28, 1, 158 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, 953, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, 954, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, 955, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, 956, -1, 28, 1, 159 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, 2224, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, 2225, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 139 },
+  { 0x3, 0x3, 173, 2226, -1, 28, 1, 139 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 139 },
+  { 0x3, 0x3, 173, 2227, -1, 28, 1, 139 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, 2228, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, 2229, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, 2230, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, 2231, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 140 },
+  { 0x3, 0x3, 173, 2232, -1, 28, 1, 138 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 146 },
+  { 0x3, 0x3, 173, 2233, -1, 28, 1, 145 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 157 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 161 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 157 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 161 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 157 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 161 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 157 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 161 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 157 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 161 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x3, 0x3, 173, -1, -1, 28, 1, 143 },
+  { 0x0, 0x0, 174, -1, 394, 0, 0, -1 },
+  { 0x0, 0x0, 174, -1, 396, 0, 0, -1 },
+  { 0x0, 0x0, 174, 3042, 3002, 0, 1, 1 },
+  { 0x0, 0x0, 174, 3043, 3003, 0, 1, 1 },
+  { 0x0, 0x0, 174, -1, 402, 0, 0, -1 },
+  { 0x0, 0x0, 174, -1, 404, 0, 0, -1 },
+  { 0x0, 0x0, 174, 3046, 3006, 0, 1, 76 },
+  { 0x0, 0x0, 174, 3047, 3007, 0, 1, 76 },
+  { 0x0, 0x0, 174, -1, 410, 0, 0, -1 },
+  { 0x0, 0x0, 174, -1, 412, 0, 0, -1 },
+  { 0x0, 0x0, 174, 3050, 3010, 0, 1, 1 },
+  { 0x0, 0x0, 174, 3051, 3011, 0, 1, 1 },
+  { 0x11, 0x31, 175, 2881, 417, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 418, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2073, 419, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 421, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 425, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 426, 12, 1, 4 },
+  { 0x11, 0x11, 175, -1, 427, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 428, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2079, 429, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 431, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2081, 433, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 435, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2083, 437, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 439, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2085, 441, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 443, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2087, 445, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 447, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2089, 449, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 451, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2901, 457, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 458, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2095, 459, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 461, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2921, 465, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 466, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2121, 467, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 469, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 473, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 474, 12, 1, 4 },
+  { 0x11, 0x11, 175, -1, 475, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 476, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2127, 477, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 479, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2129, 481, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 483, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2131, 485, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 487, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2133, 489, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 491, 12, 1, 4 },
+  { 0x1, 0x1, 175, 2135, 493, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 175, -1, 495, 12, 1, 4 },
+  { 0x11, 0x11, 175, 2137, 497, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 499, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2941, 505, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 506, 12, 1, 4 },
+  { 0x11, 0x31, 175, 2143, 507, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 175, -1, 509, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 513, 33, 1, 4 },
+  { 0x200001, 0x200001, 175, -1, 514, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 515, 33, 1, 4 },
+  { 0x200001, 0x200001, 175, -1, 516, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 521, 33, 1, 79 },
+  { 0x200001, 0x200001, 175, -1, 522, 12, 1, 79 },
+  { 0x1, 0x1, 175, -1, 523, 33, 1, 79 },
+  { 0x200001, 0x200001, 175, -1, 524, 12, 1, 79 },
+  { 0x1, 0x1, 175, -1, 529, 33, 1, 4 },
+  { 0x200001, 0x200001, 175, -1, 530, 12, 1, 4 },
+  { 0x1, 0x1, 175, -1, 531, 33, 1, 4 },
+  { 0x200001, 0x200001, 175, -1, 532, 12, 1, 4 },
+  { 0x2200001, 0x6200001, 176, 2884, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2016, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2022, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2024, -1, 33, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2026, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2028, -1, 33, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2030, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2032, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, -1, -1, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x2200001, 0x6200001, 176, 2904, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2036, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x2200001, 0x6200001, 176, 2924, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2040, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2046, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2048, -1, 33, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2050, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2052, -1, 33, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x1, 0x1, 176, 2054, -1, 37, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2056, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, -1, -1, 33, 1, 4 },
+  { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 },
+  { 0x2200001, 0x6200001, 176, 2943, -1, 12, 1, 4 },
+  { 0x11, 0x11, 176, 2060, -1, 33, 1, 4 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 37, 1, 4 },
+  { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 33, 1, 5 },
+  { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 },
+  { 0x0, 0x0, 176, -1, -1, 0, 1, 5 },
+  { 0x1, 0x1, 176, -1, -1, 12, 1, 5 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 5 },
+  { 0x1, 0x1, 176, 397, -1, 33, 1, 4 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 },
+  { 0x200001, 0x200001, 176, 398, -1, 12, 1, 4 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 5 },
+  { 0x1, 0x1, 176, 399, -1, 33, 1, 4 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 },
+  { 0x200001, 0x200001, 176, 400, -1, 12, 1, 4 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 80 },
+  { 0x1, 0x1, 176, 405, -1, 33, 1, 79 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 80 },
+  { 0x200001, 0x200001, 176, 406, -1, 12, 1, 79 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 80 },
+  { 0x1, 0x1, 176, 407, -1, 33, 1, 79 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 80 },
+  { 0x200001, 0x200001, 176, 408, -1, 12, 1, 79 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 5 },
+  { 0x1, 0x1, 176, 413, -1, 33, 1, 4 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 },
+  { 0x200001, 0x200001, 176, 414, -1, 12, 1, 4 },
+  { 0x9, 0x9, 176, -1, -1, 33, 1, 5 },
+  { 0x1, 0x1, 176, 415, -1, 33, 1, 4 },
+  { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 },
+  { 0x200001, 0x200001, 176, 416, -1, 12, 1, 4 },
+  { 0x0, 0x0, 177, -1, 2327, 0, 0, -1 },
+  { 0x9, 0x9, 177, -1, 2335, 33, 1, 50 },
+  { 0x9, 0x9, 177, -1, 2993, 33, 1, 50 },
+  { 0x0, 0x0, 177, -1, 2380, 0, 0, -1 },
+  { 0x7, 0x7, 177, -1, -1, 27, 1, 50 },
+  { 0x1, 0x1, 197, -1, -1, 27, 1, 10 },
+  { 0x1, 0x1, 211, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 211, -1, -1, 29, 1, 0 },
+  { 0x2, 0x3, 211, 1169, -1, 27, 1, 34 },
+  { 0x0, 0x0, 211, 1170, -1, 0, 1, 34 },
+  { 0x0, 0x0, 211, 1171, -1, 0, 1, 0 },
+  { 0x0, 0x0, 211, 1172, -1, 0, 1, 0 },
+  { 0x0, 0x0, 211, 1173, -1, 0, 1, 0 },
+  { 0x0, 0x0, 211, 1174, -1, 0, 1, 0 },
+  { 0x0, 0x0, 211, 3026, -1, 0, 1, 100 },
+  { 0x0, 0x0, 211, 3027, -1, 0, 1, 100 },
+  { 0x0, 0x0, 211, 3028, 967, 0, 0, -1 },
+  { 0x1, 0x1, 212, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 212, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 213, -1, 1426, 32, 1, 142 },
+  { 0x1, 0x1, 213, -1, 1428, 32, 1, 142 },
+  { 0x1, 0x1, 213, -1, 1430, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1432, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1434, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1436, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1438, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1440, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1442, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1444, 32, 1, 141 },
+  { 0x1, 0x1, 213, -1, 1446, 32, 1, 143 },
+  { 0x1, 0x1, 213, -1, 1448, 32, 1, 143 },
+  { 0x1, 0x1, 213, -1, 1965, 32, 1, 138 },
+  { 0x1, 0x1, 213, -1, 1967, 32, 1, 145 },
+  { 0x1, 0x1, 213, -1, 1969, 32, 1, 139 },
+  { 0x1, 0x1, 213, -1, 1971, 32, 1, 139 },
+  { 0x1, 0x1, 213, -1, 1973, 32, 1, 138 },
+  { 0x1, 0x1, 213, -1, 1975, 32, 1, 145 },
+  { 0x1, 0x1, 213, -1, 1977, 32, 1, 138 },
+  { 0x1, 0x1, 213, -1, 1979, 32, 1, 145 },
+  { 0x1, 0x1, 213, 2783, 1981, 32, 1, 138 },
+  { 0x1, 0x1, 213, 2784, 1984, 32, 1, 145 },
+  { 0x0, 0x0, 214, -1, 2825, 0, 0, -1 },
+  { 0x0, 0x0, 214, -1, 2826, 0, 0, -1 },
+  { 0x0, 0x0, 214, -1, 2851, 0, 0, -1 },
+  { 0x5, 0x5, 214, -1, 2854, 20, 1, 68 },
+  { 0x0, 0x0, 218, 2209, 966, 0, 0, -1 },
+  { 0x0, 0x0, 219, -1, 1139, 0, 0, -1 },
+  { 0x0, 0x0, 219, -1, 1264, 0, 0, -1 },
+  { 0x0, 0x0, 219, -1, -1, 0, 1, 128 },
+  { 0x0, 0x0, 219, -1, -1, 0, 1, 67 },
+  { 0x1, 0x1, 219, 833, 2289, 36, 1, 66 },
+  { 0x1, 0x1, 219, 834, 2348, 36, 1, 66 },
+  { 0x0, 0x0, 219, 835, 2351, 0, 0, -1 },
+  { 0x1, 0x1, 219, 836, -1, 36, 1, 66 },
+  { 0x0, 0x0, 219, 1423, -1, 0, 1, 34 },
+  { 0x1, 0x1, 219, 837, 2356, 36, 1, 66 },
+  { 0x0, 0x0, 219, 838, 2359, 0, 0, -1 },
+  { 0x1, 0x1, 219, 839, -1, 36, 1, 66 },
+  { 0x0, 0x0, 219, 840, 2362, 0, 0, -1 },
+  { 0x1, 0x1, 219, 841, -1, 36, 1, 66 },
+  { 0x1, 0x1, 219, 842, 2365, 36, 1, 66 },
+  { 0x1, 0x1, 219, 843, 2368, 36, 1, 66 },
+  { 0x0, 0x0, 219, 1424, -1, 0, 1, 34 },
+  { 0x1, 0x1, 219, 844, 2401, 36, 1, 66 },
+  { 0x1, 0x1, 219, 845, -1, 31, 1, 144 },
+  { 0x1, 0x1, 219, 228, 1449, 32, 1, 133 },
+  { 0x1, 0x1, 219, 229, 1458, 32, 1, 133 },
+  { 0x1, 0x1, 219, 230, 1467, 32, 1, 133 },
+  { 0x1, 0x1, 219, 231, 1480, 32, 1, 133 },
+  { 0x1, 0x1, 219, 232, 1489, 32, 1, 133 },
+  { 0x1, 0x1, 219, 233, 1498, 32, 1, 133 },
+  { 0x1, 0x1, 219, 234, 1507, 32, 1, 133 },
+  { 0x1, 0x1, 219, 235, 1516, 32, 1, 133 },
+  { 0x1, 0x1, 219, 236, 1525, 32, 1, 133 },
+  { 0x1, 0x1, 219, 237, 1534, 32, 1, 133 },
+  { 0x1, 0x1, 219, 238, 1544, 32, 1, 133 },
+  { 0x1, 0x1, 219, 239, 1554, 32, 1, 133 },
+  { 0x1, 0x1, 219, 240, 1567, 32, 1, 148 },
+  { 0x1, 0x1, 219, 241, 1573, 32, 1, 153 },
+  { 0x1, 0x1, 219, 242, 1579, 32, 1, 153 },
+  { 0x1, 0x1, 219, 243, 1585, 32, 1, 148 },
+  { 0x1, 0x1, 219, 244, 1591, 32, 1, 153 },
+  { 0x1, 0x1, 219, 245, 1597, 32, 1, 153 },
+  { 0x1, 0x1, 219, 246, 1603, 32, 1, 148 },
+  { 0x1, 0x1, 219, 247, 1609, 32, 1, 153 },
+  { 0x1, 0x1, 219, 248, 1615, 32, 1, 153 },
+  { 0x1, 0x1, 219, 249, 1621, 32, 1, 148 },
+  { 0x1, 0x1, 219, 250, 1627, 32, 1, 153 },
+  { 0x1, 0x1, 219, 251, 1633, 32, 1, 148 },
+  { 0x1, 0x1, 219, 252, 1639, 32, 1, 153 },
+  { 0x1, 0x1, 219, 253, 1645, 32, 1, 148 },
+  { 0x1, 0x1, 219, 254, 1651, 32, 1, 153 },
+  { 0x1, 0x1, 219, 255, 1657, 32, 1, 148 },
+  { 0x1, 0x1, 219, 256, 1663, 32, 1, 153 },
+  { 0x1, 0x1, 219, 257, 1669, 32, 1, 153 },
+  { 0x1, 0x1, 219, 849, -1, 31, 1, 160 },
+  { 0x0, 0x0, 220, 2404, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2405, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 25, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2407, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2408, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2409, -1, 0, 1, 45 },
+  { 0x0, 0x0, 220, 2410, -1, 0, 1, 40 },
+  { 0x1, 0x1, 220, 2411, -1, 12, 1, 59 },
+  { 0x0, 0x0, 220, 2412, -1, 0, 1, 54 },
+  { 0x1000001, 0x1000001, 220, 2413, -1, 12, 1, 59 },
+  { 0x1, 0x1, 220, 2414, -1, 36, 1, 54 },
+  { 0x200001, 0x200001, 220, 2415, -1, 12, 1, 59 },
+  { 0x1, 0x1, 220, 2416, -1, 33, 1, 54 },
+  { 0x1200001, 0x1200001, 220, 2417, -1, 12, 1, 49 },
+  { 0x9, 0x9, 220, 2418, -1, 33, 1, 49 },
+  { 0x0, 0x0, 220, 2419, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2420, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2421, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2422, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2423, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2424, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2425, -1, 0, 1, 49 },
+  { 0x0, 0x0, 220, 2426, -1, 0, 1, 49 },
+  { 0x1, 0x1, 220, 2427, -1, 12, 1, 59 },
+  { 0x0, 0x0, 220, 2428, -1, 0, 1, 54 },
+  { 0x200001, 0x1200001, 220, 2429, -1, 12, 1, 59 },
+  { 0x1, 0x9, 220, 2430, -1, 33, 1, 54 },
+  { 0x0, 0x0, 220, 2431, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2432, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2433, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2434, -1, 0, 1, 54 },
+  { 0x1, 0x1, 220, 2435, -1, 12, 1, 59 },
+  { 0x0, 0x0, 220, 2436, -1, 0, 1, 54 },
+  { 0x1000001, 0x1000001, 220, 2437, -1, 12, 1, 59 },
+  { 0x1, 0x1, 220, 2438, -1, 36, 1, 54 },
+  { 0x200001, 0x200001, 220, 2439, -1, 12, 1, 59 },
+  { 0x1, 0x1, 220, 2440, -1, 33, 1, 54 },
+  { 0x1200001, 0x1200001, 220, 2441, -1, 12, 1, 49 },
+  { 0x9, 0x9, 220, 2442, -1, 33, 1, 49 },
+  { 0x0, 0x0, 220, 2443, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2444, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2445, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2446, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2447, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2448, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2449, -1, 0, 1, 49 },
+  { 0x0, 0x0, 220, 2450, -1, 0, 1, 49 },
+  { 0x1, 0x1, 220, 2451, -1, 12, 1, 59 },
+  { 0x0, 0x0, 220, 2452, -1, 0, 1, 54 },
+  { 0x200001, 0x1200001, 220, 2453, -1, 12, 1, 59 },
+  { 0x1, 0x9, 220, 2454, -1, 33, 1, 54 },
+  { 0x0, 0x0, 220, 2455, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2456, -1, 0, 1, 54 },
+  { 0x0, 0x0, 220, 2457, -1, 0, 1, 59 },
+  { 0x0, 0x0, 220, 2458, -1, 0, 1, 54 },
+  { 0x1, 0x1, 220, 2459, -1, 28, 1, 29 },
+  { 0x0, 0x0, 220, 2460, -1, 0, 1, 29 },
+  { 0x3, 0x3, 220, 2461, -1, 27, 1, 29 },
+  { 0x1, 0x1, 220, 2462, -1, 27, 1, 29 },
+  { 0x0, 0x0, 220, 2463, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2464, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2465, -1, 0, 1, 29 },
+  { 0x1, 0x1, 220, 2466, -1, 36, 1, 66 },
+  { 0x1, 0x1, 220, 2467, -1, 37, 1, 29 },
+  { 0x0, 0x0, 220, 2468, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2469, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2470, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2471, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2472, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 37, -1, 0, 1, 29 },
+  { 0x1, 0x1, 220, 2474, -1, 36, 1, 66 },
+  { 0x1, 0x1, 220, 2475, -1, 37, 1, 29 },
+  { 0x0, 0x0, 220, 2476, -1, 0, 1, 29 },
+  { 0x1, 0x1, 220, 2477, -1, 36, 1, 66 },
+  { 0x1, 0x1, 220, 2478, -1, 37, 1, 29 },
+  { 0x0, 0x0, 220, 2479, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2480, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2481, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 42, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2483, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2484, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 43, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2486, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2487, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2488, -1, 0, 1, 49 },
+  { 0x1, 0x1, 220, 2489, -1, 27, 1, 49 },
+  { 0x1, 0x1, 220, 2490, -1, 28, 1, 49 },
+  { 0x3, 0x3, 220, 2491, -1, 27, 1, 49 },
+  { 0x1, 0x1, 220, 2492, -1, 29, 1, 49 },
+  { 0x5, 0x5, 220, 2493, -1, 27, 1, 49 },
+  { 0x3, 0x3, 220, 2494, -1, 28, 1, 49 },
+  { 0x7, 0x7, 220, 2495, -1, 27, 1, 49 },
+  { 0x0, 0x0, 220, 2496, -1, 0, 1, 49 },
+  { 0x0, 0x0, 220, 2497, -1, 0, 1, 49 },
+  { 0x0, 0x0, 220, 2498, -1, 0, 1, 49 },
+  { 0x0, 0x0, 220, 2499, -1, 0, 1, 49 },
+  { 0x1, 0x1, 220, 2500, -1, 28, 1, 29 },
+  { 0x0, 0x0, 220, 2501, -1, 0, 1, 29 },
+  { 0x3, 0x3, 220, 2502, -1, 27, 1, 29 },
+  { 0x1, 0x1, 220, 2503, -1, 27, 1, 29 },
+  { 0x0, 0x0, 220, 2504, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2505, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2506, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 52, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2508, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2509, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 57, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 2511, -1, 0, 1, 24 },
+  { 0x0, 0x0, 220, 2512, -1, 0, 1, 24 },
+  { 0x0, 0x0, 220, 2513, -1, 0, 1, 24 },
+  { 0x0, 0x0, 220, 2514, -1, 0, 1, 24 },
+  { 0x0, 0x0, 220, 2515, -1, 0, 1, 35 },
+  { 0x0, 0x0, 220, 2516, -1, 0, 1, 66 },
+  { 0x0, 0x0, 220, 2517, -1, 0, 1, 29 },
+  { 0x0, 0x0, 220, 64, -1, 0, 1, 29 },
+  { 0x1, 0x1, 221, 2519, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2520, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2521, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2522, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2523, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2524, -1, 34, 1, 46 },
+  { 0x1, 0x1, 221, 2525, -1, 34, 1, 42 },
+  { 0x400001, 0x400001, 221, 2526, -1, 12, 1, 61 },
+  { 0x1, 0x1, 221, 2527, -1, 34, 1, 56 },
+  { 0x1400001, 0x1400001, 221, 2528, -1, 12, 1, 61 },
+  { 0x5, 0x5, 221, 2529, -1, 34, 1, 56 },
+  { 0x600001, 0x600001, 221, 2530, -1, 12, 1, 61 },
+  { 0x3, 0x3, 221, 2531, -1, 33, 1, 56 },
+  { 0x1600001, 0x1600001, 221, 2532, -1, 12, 1, 51 },
+  { 0xb, 0xb, 221, 2533, -1, 33, 1, 51 },
+  { 0x1, 0x1, 221, 2534, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2535, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2536, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2537, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2538, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2539, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2540, -1, 34, 1, 51 },
+  { 0x1, 0x1, 221, 2541, -1, 34, 1, 51 },
+  { 0x400001, 0x400001, 221, 2542, -1, 12, 1, 61 },
+  { 0x1, 0x1, 221, 2543, -1, 34, 1, 56 },
+  { 0x600001, 0x1600001, 221, 2544, -1, 12, 1, 61 },
+  { 0x3, 0xb, 221, 2545, -1, 33, 1, 56 },
+  { 0x1, 0x1, 221, 2546, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2547, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2548, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2549, -1, 34, 1, 56 },
+  { 0x400001, 0x400001, 221, 2550, -1, 12, 1, 61 },
+  { 0x1, 0x1, 221, 2551, -1, 34, 1, 56 },
+  { 0x1400001, 0x1400001, 221, 2552, -1, 12, 1, 61 },
+  { 0x5, 0x5, 221, 2553, -1, 34, 1, 56 },
+  { 0x600001, 0x600001, 221, 2554, -1, 12, 1, 61 },
+  { 0x3, 0x3, 221, 2555, -1, 33, 1, 56 },
+  { 0x1600001, 0x1600001, 221, 2556, -1, 12, 1, 51 },
+  { 0xb, 0xb, 221, 2557, -1, 33, 1, 51 },
+  { 0x1, 0x1, 221, 2558, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2559, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2560, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2561, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2562, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2563, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2564, -1, 34, 1, 51 },
+  { 0x1, 0x1, 221, 2565, -1, 34, 1, 51 },
+  { 0x400001, 0x400001, 221, 2566, -1, 12, 1, 61 },
+  { 0x1, 0x1, 221, 2567, -1, 34, 1, 56 },
+  { 0x600001, 0x1600001, 221, 2568, -1, 12, 1, 61 },
+  { 0x3, 0xb, 221, 2569, -1, 33, 1, 56 },
+  { 0x1, 0x1, 221, 2570, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2571, -1, 34, 1, 56 },
+  { 0x1, 0x1, 221, 2572, -1, 34, 1, 61 },
+  { 0x1, 0x1, 221, 2573, -1, 34, 1, 56 },
+  { 0x41, 0x41, 221, 2574, -1, 28, 1, 31 },
+  { 0x1, 0x1, 221, 2575, -1, 34, 1, 31 },
+  { 0x83, 0x83, 221, 2576, -1, 27, 1, 31 },
+  { 0x81, 0x81, 221, 2577, -1, 27, 1, 31 },
+  { 0x1, 0x1, 221, 2578, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2579, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2580, -1, 34, 1, 31 },
+  { 0x5, 0x5, 221, 2581, -1, 34, 1, 66 },
+  { 0x9, 0x9, 221, 2582, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2583, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2584, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2585, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2586, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2587, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2588, -1, 34, 1, 31 },
+  { 0x5, 0x5, 221, 2589, -1, 34, 1, 66 },
+  { 0x9, 0x9, 221, 2590, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2591, -1, 34, 1, 31 },
+  { 0x5, 0x5, 221, 2592, -1, 34, 1, 66 },
+  { 0x9, 0x9, 221, 2593, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2594, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2595, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2596, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2597, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2598, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2599, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2600, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2601, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2602, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2603, -1, 34, 1, 51 },
+  { 0x81, 0x81, 221, 2604, -1, 27, 1, 51 },
+  { 0x41, 0x41, 221, 2605, -1, 28, 1, 51 },
+  { 0x83, 0x83, 221, 2606, -1, 27, 1, 51 },
+  { 0x21, 0x21, 221, 2607, -1, 29, 1, 51 },
+  { 0x85, 0x85, 221, 2608, -1, 27, 1, 51 },
+  { 0x43, 0x43, 221, 2609, -1, 28, 1, 51 },
+  { 0x87, 0x87, 221, 2610, -1, 27, 1, 51 },
+  { 0x1, 0x1, 221, 2611, -1, 34, 1, 51 },
+  { 0x1, 0x1, 221, 2612, -1, 34, 1, 51 },
+  { 0x1, 0x1, 221, 2613, -1, 34, 1, 51 },
+  { 0x1, 0x1, 221, 2614, -1, 34, 1, 51 },
+  { 0x41, 0x41, 221, 2615, -1, 28, 1, 31 },
+  { 0x1, 0x1, 221, 2616, -1, 34, 1, 31 },
+  { 0x83, 0x83, 221, 2617, -1, 27, 1, 31 },
+  { 0x81, 0x81, 221, 2618, -1, 27, 1, 31 },
+  { 0x1, 0x1, 221, 2619, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2620, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2621, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2622, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2623, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2624, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2625, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2626, -1, 34, 1, 26 },
+  { 0x1, 0x1, 221, 2627, -1, 34, 1, 26 },
+  { 0x1, 0x1, 221, 2628, -1, 34, 1, 26 },
+  { 0x1, 0x1, 221, 2629, -1, 34, 1, 26 },
+  { 0x1, 0x1, 221, 2630, -1, 34, 1, 37 },
+  { 0x1, 0x1, 221, 2631, -1, 34, 1, 66 },
+  { 0x1, 0x1, 221, 2632, -1, 34, 1, 31 },
+  { 0x1, 0x1, 221, 2633, -1, 34, 1, 31 },
+  { 0x1, 0x1, 222, 2634, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2635, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2636, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2637, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2638, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2639, -1, 35, 1, 47 },
+  { 0x1, 0x1, 222, 2640, -1, 35, 1, 43 },
+  { 0x800001, 0x800001, 222, 2641, -1, 12, 1, 62 },
+  { 0x1, 0x1, 222, 2642, -1, 35, 1, 57 },
+  { 0x1800001, 0x1800001, 222, 2643, -1, 12, 1, 62 },
+  { 0x3, 0x3, 222, 2644, -1, 35, 1, 57 },
+  { 0xa00001, 0xa00001, 222, 2645, -1, 12, 1, 62 },
+  { 0x5, 0x5, 222, 2646, -1, 33, 1, 57 },
+  { 0x1a00001, 0x1a00001, 222, 2647, -1, 12, 1, 52 },
+  { 0xd, 0xd, 222, 2648, -1, 33, 1, 52 },
+  { 0x1, 0x1, 222, 2649, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2650, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2651, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2652, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2653, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2654, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2655, -1, 35, 1, 52 },
+  { 0x1, 0x1, 222, 2656, -1, 35, 1, 52 },
+  { 0x800001, 0x800001, 222, 2657, -1, 12, 1, 62 },
+  { 0x1, 0x1, 222, 2658, -1, 35, 1, 57 },
+  { 0xa00001, 0x1a00001, 222, 2659, -1, 12, 1, 62 },
+  { 0x5, 0xd, 222, 2660, -1, 33, 1, 57 },
+  { 0x1, 0x1, 222, 2661, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2662, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2663, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2664, -1, 35, 1, 57 },
+  { 0x800001, 0x800001, 222, 2665, -1, 12, 1, 62 },
+  { 0x1, 0x1, 222, 2666, -1, 35, 1, 57 },
+  { 0x1800001, 0x1800001, 222, 2667, -1, 12, 1, 62 },
+  { 0x3, 0x3, 222, 2668, -1, 35, 1, 57 },
+  { 0xa00001, 0xa00001, 222, 2669, -1, 12, 1, 62 },
+  { 0x5, 0x5, 222, 2670, -1, 33, 1, 57 },
+  { 0x1a00001, 0x1a00001, 222, 2671, -1, 12, 1, 52 },
+  { 0xd, 0xd, 222, 2672, -1, 33, 1, 52 },
+  { 0x1, 0x1, 222, 2673, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2674, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2675, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2676, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2677, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2678, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2679, -1, 35, 1, 52 },
+  { 0x1, 0x1, 222, 2680, -1, 35, 1, 52 },
+  { 0x800001, 0x800001, 222, 2681, -1, 12, 1, 62 },
+  { 0x1, 0x1, 222, 2682, -1, 35, 1, 57 },
+  { 0xa00001, 0x1a00001, 222, 2683, -1, 12, 1, 62 },
+  { 0x5, 0xd, 222, 2684, -1, 33, 1, 57 },
+  { 0x1, 0x1, 222, 2685, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2686, -1, 35, 1, 57 },
+  { 0x1, 0x1, 222, 2687, -1, 35, 1, 62 },
+  { 0x1, 0x1, 222, 2688, -1, 35, 1, 57 },
+  { 0x81, 0x81, 222, 2689, -1, 28, 1, 32 },
+  { 0x1, 0x1, 222, 2690, -1, 35, 1, 32 },
+  { 0x103, 0x103, 222, 2691, -1, 27, 1, 32 },
+  { 0x101, 0x101, 222, 2692, -1, 27, 1, 32 },
+  { 0x1, 0x1, 222, 2693, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2694, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2695, -1, 35, 1, 32 },
+  { 0x3, 0x3, 222, 2696, -1, 35, 1, 66 },
+  { 0x5, 0x5, 222, 2697, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2698, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2699, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2700, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2701, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2702, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2703, -1, 35, 1, 32 },
+  { 0x3, 0x3, 222, 2704, -1, 35, 1, 66 },
+  { 0x5, 0x5, 222, 2705, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2706, -1, 35, 1, 32 },
+  { 0x3, 0x3, 222, 2707, -1, 35, 1, 66 },
+  { 0x5, 0x5, 222, 2708, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2709, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2710, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2711, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2712, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2713, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2714, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2715, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2716, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2717, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2718, -1, 35, 1, 52 },
+  { 0x101, 0x101, 222, 2719, -1, 27, 1, 52 },
+  { 0x81, 0x81, 222, 2720, -1, 28, 1, 52 },
+  { 0x103, 0x103, 222, 2721, -1, 27, 1, 52 },
+  { 0x41, 0x41, 222, 2722, -1, 29, 1, 52 },
+  { 0x105, 0x105, 222, 2723, -1, 27, 1, 52 },
+  { 0x83, 0x83, 222, 2724, -1, 28, 1, 52 },
+  { 0x107, 0x107, 222, 2725, -1, 27, 1, 52 },
+  { 0x1, 0x1, 222, 2726, -1, 35, 1, 52 },
+  { 0x1, 0x1, 222, 2727, -1, 35, 1, 52 },
+  { 0x1, 0x1, 222, 2728, -1, 35, 1, 52 },
+  { 0x1, 0x1, 222, 2729, -1, 35, 1, 52 },
+  { 0x81, 0x81, 222, 2730, -1, 28, 1, 32 },
+  { 0x1, 0x1, 222, 2731, -1, 35, 1, 32 },
+  { 0x103, 0x103, 222, 2732, -1, 27, 1, 32 },
+  { 0x101, 0x101, 222, 2733, -1, 27, 1, 32 },
+  { 0x1, 0x1, 222, 2734, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2735, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2736, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2737, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2738, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2739, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2740, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2741, -1, 35, 1, 27 },
+  { 0x1, 0x1, 222, 2742, -1, 35, 1, 27 },
+  { 0x1, 0x1, 222, 2743, -1, 35, 1, 27 },
+  { 0x1, 0x1, 222, 2744, -1, 35, 1, 27 },
+  { 0x1, 0x1, 222, 2745, -1, 35, 1, 38 },
+  { 0x1, 0x1, 222, 2746, -1, 35, 1, 66 },
+  { 0x1, 0x1, 222, 2747, -1, 35, 1, 32 },
+  { 0x1, 0x1, 222, 2748, -1, 35, 1, 32 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2243, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 48 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 44 },
+  { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 63 },
+  { 0x3, 0x3, 223, 2964, -1, 34, 1, 58 },
+  { 0x1c00001, 0x1c00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0x7, 223, 2965, -1, 34, 1, 58 },
+  { 0xe00001, 0xe00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0x7, 223, 2966, -1, 33, 1, 58 },
+  { 0x1e00001, 0x1e00001, 223, -1, -1, 12, 1, 53 },
+  { 0xf, 0xf, 223, 2967, -1, 33, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2968, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2969, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2970, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x3, 0x3, 223, 2971, -1, 34, 1, 53 },
+  { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 63 },
+  { 0x3, 0x3, 223, 2976, -1, 34, 1, 58 },
+  { 0xe00001, 0x1e00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0xf, 223, 2977, -1, 33, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2978, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2979, -1, 34, 1, 58 },
+  { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 63 },
+  { 0x3, 0x3, 223, 2982, -1, 34, 1, 58 },
+  { 0x1c00001, 0x1c00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0x7, 223, 2983, -1, 34, 1, 58 },
+  { 0xe00001, 0xe00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0x7, 223, 2984, -1, 33, 1, 58 },
+  { 0x1e00001, 0x1e00001, 223, -1, -1, 12, 1, 53 },
+  { 0xf, 0xf, 223, 2985, -1, 33, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2986, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2987, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2988, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x3, 0x3, 223, 2989, -1, 34, 1, 53 },
+  { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 63 },
+  { 0x3, 0x3, 223, 2994, -1, 34, 1, 58 },
+  { 0xe00001, 0x1e00001, 223, -1, -1, 12, 1, 63 },
+  { 0x7, 0xf, 223, 2995, -1, 33, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2996, -1, 34, 1, 58 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 63 },
+  { 0x3, 0x3, 223, 2997, -1, 34, 1, 58 },
+  { 0xc1, 0xc1, 223, -1, -1, 28, 1, 33 },
+  { 0x3, 0x3, 223, 2862, -1, 34, 1, 33 },
+  { 0x183, 0x183, 223, -1, -1, 27, 1, 33 },
+  { 0x181, 0x181, 223, 2863, -1, 27, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2244, -1, 34, 1, 33 },
+  { 0x7, 0x7, 223, -1, -1, 34, 1, 66 },
+  { 0xb, 0xb, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2245, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2248, -1, 34, 1, 33 },
+  { 0x7, 0x7, 223, -1, -1, 34, 1, 66 },
+  { 0xb, 0xb, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2249, -1, 34, 1, 33 },
+  { 0x7, 0x7, 223, -1, -1, 34, 1, 66 },
+  { 0xb, 0xb, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2251, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2253, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2254, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x181, 0x181, 223, -1, -1, 27, 1, 53 },
+  { 0xc1, 0xc1, 223, -1, -1, 28, 1, 53 },
+  { 0x183, 0x183, 223, -1, -1, 27, 1, 53 },
+  { 0x61, 0x61, 223, -1, -1, 29, 1, 53 },
+  { 0x185, 0x185, 223, -1, -1, 27, 1, 53 },
+  { 0xc3, 0xc3, 223, -1, -1, 28, 1, 53 },
+  { 0x187, 0x187, 223, -1, -1, 27, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 53 },
+  { 0xc1, 0xc1, 223, -1, -1, 28, 1, 33 },
+  { 0x3, 0x3, 223, 2866, -1, 34, 1, 33 },
+  { 0x183, 0x183, 223, -1, -1, 27, 1, 33 },
+  { 0x181, 0x181, 223, 2867, -1, 27, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 28 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 28 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 28 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 28 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 39 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 66 },
+  { 0x3, 0x3, 223, -1, -1, 34, 1, 33 },
+  { 0x3, 0x3, 223, 2256, -1, 34, 1, 33 },
+  { 0x3, 0x3, 224, 540, 1451, 32, 1, 135 },
+  { 0x3, 0x3, 224, 541, 1460, 32, 1, 135 },
+  { 0x3, 0x3, 224, 542, 1469, 32, 1, 135 },
+  { 0x3, 0x3, 224, 543, 1482, 32, 1, 135 },
+  { 0x3, 0x3, 224, 544, 1491, 32, 1, 135 },
+  { 0x3, 0x3, 224, 545, 1500, 32, 1, 135 },
+  { 0x3, 0x3, 224, 546, 1509, 32, 1, 135 },
+  { 0x3, 0x3, 224, 547, 1518, 32, 1, 135 },
+  { 0x3, 0x3, 224, 548, 1527, 32, 1, 135 },
+  { 0x3, 0x3, 224, 549, 1536, 32, 1, 135 },
+  { 0x3, 0x3, 224, 550, 1546, 32, 1, 135 },
+  { 0x3, 0x3, 224, 551, 1556, 32, 1, 135 },
+  { 0x3, 0x3, 224, 564, 1569, 32, 1, 150 },
+  { 0x3, 0x3, 224, 565, 1575, 32, 1, 155 },
+  { 0x3, 0x3, 224, 566, 1581, 32, 1, 155 },
+  { 0x3, 0x3, 224, 567, 1587, 32, 1, 150 },
+  { 0x3, 0x3, 224, 568, 1593, 32, 1, 155 },
+  { 0x3, 0x3, 224, 569, 1599, 32, 1, 155 },
+  { 0x3, 0x3, 224, 570, 1605, 32, 1, 150 },
+  { 0x3, 0x3, 224, 571, 1611, 32, 1, 155 },
+  { 0x3, 0x3, 224, 572, 1617, 32, 1, 155 },
+  { 0x3, 0x3, 224, 573, 1623, 32, 1, 150 },
+  { 0x3, 0x3, 224, 574, 1629, 32, 1, 155 },
+  { 0x3, 0x3, 224, 575, 1635, 32, 1, 150 },
+  { 0x3, 0x3, 224, 576, 1641, 32, 1, 155 },
+  { 0x3, 0x3, 224, 577, 1647, 32, 1, 150 },
+  { 0x3, 0x3, 224, 578, 1653, 32, 1, 155 },
+  { 0x3, 0x3, 224, 579, 1659, 32, 1, 150 },
+  { 0x3, 0x3, 224, 580, 1665, 32, 1, 155 },
+  { 0x3, 0x3, 224, 581, 1671, 32, 1, 155 },
+  { 0x1, 0x1, 225, -1, -1, 28, 1, 34 },
+  { 0x1, 0x1, 225, -1, -1, 28, 1, 34 },
+  { 0x0, 0x0, 232, 958, -1, 0, 1, 144 },
+  { 0x0, 0x0, 232, 959, -1, 0, 1, 160 },
+  { 0x1, 0x1, 233, -1, 1982, 33, 1, 140 },
+  { 0x1, 0x1, 233, -1, 1985, 33, 1, 146 },
+  { 0x0, 0x0, 233, -1, 1987, 0, 1, 157 },
+  { 0x0, 0x0, 233, -1, 1988, 0, 1, 161 },
+  { 0x0, 0x0, 234, 883, 971, 0, 0, -1 },
+  { 0x0, 0x0, 234, 884, 979, 0, 0, -1 },
+  { 0x0, 0x0, 234, 885, 975, 0, 0, -1 },
+  { 0x1, 0x1, 234, 886, 620, 33, 1, 6 },
+  { 0x8000001, 0x8000001, 234, 887, 628, 6, 1, 7 },
+  { 0x1, 0x1, 234, 888, 624, 33, 1, 6 },
+  { 0x0, 0x0, 234, 889, 983, 0, 0, -1 },
+  { 0x1, 0x1, 234, 890, 640, 33, 1, 8 },
+  { 0x0, 0x0, 234, 891, 987, 0, 0, -1 },
+  { 0x1, 0x1, 234, 892, 652, 33, 1, 16 },
+  { 0x0, 0x0, 234, 893, 992, 0, 0, -1 },
+  { 0x0, 0x0, 234, 894, 996, 0, 0, -1 },
+  { 0x1, 0x1, 234, 895, 675, 33, 1, 18 },
+  { 0x1, 0x1, 234, 896, 679, 33, 1, 18 },
+  { 0x0, 0x0, 234, 897, 1000, 0, 0, -1 },
+  { 0x0, 0x0, 234, 898, 1004, 0, 0, -1 },
+  { 0x1, 0x1, 234, 899, 699, 33, 1, 19 },
+  { 0x8000001, 0x8000001, 234, 900, 703, 6, 1, 19 },
+  { 0x0, 0x0, 234, 901, 1008, 0, 0, -1 },
+  { 0x1, 0x1, 234, 902, 715, 33, 1, 20 },
+  { 0x0, 0x0, 234, 903, 1012, 0, 0, -1 },
+  { 0x0, 0x0, 234, 904, 1016, 0, 0, -1 },
+  { 0x1, 0x1, 234, 905, 735, 33, 1, 21 },
+  { 0x8000001, 0x8000001, 234, 906, 739, 6, 1, 21 },
+  { 0x0, 0x0, 234, 907, 1020, 0, 0, -1 },
+  { 0x1, 0x1, 234, 908, 751, 33, 1, 22 },
+  { 0x0, 0x0, 234, 909, 1025, 0, 0, -1 },
+  { 0x0, 0x0, 234, 910, 1029, 0, 0, -1 },
+  { 0x1, 0x1, 234, 911, 774, 33, 1, 18 },
+  { 0x1, 0x1, 234, 912, 778, 33, 1, 18 },
+  { 0x0, 0x0, 234, 913, 1033, 0, 0, -1 },
+  { 0x1, 0x1, 234, 914, 790, 33, 1, 22 },
+  { 0x0, 0x0, 235, 2787, 970, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2788, 978, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2789, 974, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2790, 619, 0, 1, 6 },
+  { 0x1, 0x1, 235, 2791, 627, 6, 1, 7 },
+  { 0x0, 0x0, 235, 2792, 623, 0, 1, 6 },
+  { 0x0, 0x0, 235, 2793, 982, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2794, 639, 0, 1, 8 },
+  { 0x0, 0x0, 235, 2795, 986, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2796, 651, 0, 1, 16 },
+  { 0x0, 0x0, 235, 2797, 991, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2798, 995, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2799, 674, 0, 1, 18 },
+  { 0x0, 0x0, 235, 2800, 678, 0, 1, 18 },
+  { 0x0, 0x0, 235, 2801, 999, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2802, 1003, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2803, 698, 0, 1, 19 },
+  { 0x1, 0x1, 235, 2804, 702, 6, 1, 19 },
+  { 0x0, 0x0, 235, 2805, 1007, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2806, 714, 0, 1, 20 },
+  { 0x0, 0x0, 235, 2807, 1011, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2808, 1015, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2809, 734, 0, 1, 21 },
+  { 0x1, 0x1, 235, 2810, 738, 6, 1, 21 },
+  { 0x0, 0x0, 235, 2811, 1019, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2812, 750, 0, 1, 22 },
+  { 0x0, 0x0, 235, 2813, 1024, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2814, 1028, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2815, 773, 0, 1, 18 },
+  { 0x0, 0x0, 235, 2816, 777, 0, 1, 18 },
+  { 0x0, 0x0, 235, 2817, 1032, 0, 0, -1 },
+  { 0x0, 0x0, 235, 2818, 789, 0, 1, 22 },
+  { 0x1, 0x1, 235, 915, 1155, 27, 1, 17 },
+  { 0x0, 0x0, 235, 916, 1153, 0, 1, 17 },
+  { 0x0, 0x0, 235, 1220, 1157, 0, 1, 23 },
+  { 0x0, 0x1, 235, 1165, 1163, 20, 1, 68 },
+  { 0x0, 0x0, 235, 111, 1161, 0, 1, 68 },
+  { 0x1, 0x1, 238, -1, -1, 29, 1, 0 },
+  { 0x0, 0x0, 238, -1, -1, 0, 1, 0 },
+  { 0x1, 0x1, 238, 3022, -1, 27, 1, 0 },
+  { 0x1, 0x1, 238, 3023, -1, 27, 1, 0 },
+  { 0x1, 0x1, 238, 3024, -1, 27, 1, 0 },
+  { 0x1, 0x1, 238, 3025, -1, 27, 1, 0 },
+  { 0x0, 0x0, 261, -1, 2344, 0, 0, -1 },
+  { 0x0, 0x0, 261, -1, 2346, 0, 0, -1 },
+  { 0x1, 0x1, 261, -1, -1, 28, 1, 30 },
+  { 0x1, 0x1, 261, -1, -1, 28, 1, 30 },
+  { 0x0, 0x0, 261, -1, 2385, 0, 0, -1 },
+  { 0x0, 0x0, 261, -1, 2387, 0, 0, -1 },
+  { 0x1, 0x1, 261, -1, -1, 28, 1, 30 },
+  { 0x1, 0x1, 261, -1, -1, 28, 1, 30 },
+  { 0x0, 0x0, 263, 23, -1, 0, 1, 0 },
+  { 0x0, 0x0, 263, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 263, -1, -1, 0, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x0, 0x0, 263, 180, -1, 0, 1, 0 },
+  { 0x0, 0x1, 263, -1, -1, 29, 1, 0 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 301, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 323, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 349, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 371, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 65 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 65 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 65 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 65 },
+  { 0x0, 0x0, 264, -1, 2296, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2298, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2300, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2302, 0, 0, -1 },
+  { 0x1, 0x1, 264, -1, 2304, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2306, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2308, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2310, 12, 1, 50 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 50 },
+  { 0x0, 0x0, 264, -1, 2312, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2314, 0, 0, -1 },
+  { 0x1, 0x1, 264, -1, 2316, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2318, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x0, 0x0, 264, -1, 2320, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2322, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2324, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2326, 0, 0, -1 },
+  { 0x1, 0x1, 264, -1, 2328, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2330, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2332, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2334, 12, 1, 50 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 50 },
+  { 0x0, 0x0, 264, -1, 2336, 0, 0, -1 },
+  { 0x0, 0x0, 264, -1, 2338, 0, 0, -1 },
+  { 0x1, 0x1, 264, -1, 2340, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, 2342, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, -1, -1, 12, 1, 60 },
+  { 0x1, 0x1, 264, 393, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 395, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 517, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 519, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 401, -1, 12, 1, 77 },
+  { 0x1, 0x1, 264, 403, -1, 12, 1, 77 },
+  { 0x1, 0x1, 264, 525, -1, 12, 1, 77 },
+  { 0x1, 0x1, 264, 527, -1, 12, 1, 77 },
+  { 0x1, 0x1, 264, 409, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 411, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 533, -1, 12, 1, 2 },
+  { 0x1, 0x1, 264, 535, -1, 12, 1, 2 },
+  { 0x0, 0x0, 265, -1, 2303, 0, 0, -1 },
+  { 0x9, 0x9, 265, -1, 2311, 33, 1, 50 },
+  { 0x9, 0x9, 265, -1, 2975, 33, 1, 50 },
+  { 0x0, 0x0, 265, 1399, 2376, 0, 0, -1 },
+  { 0x3, 0x3, 265, 1400, -1, 27, 1, 50 },
+  { 0x0, 0x0, 269, 2856, -1, 0, 1, 0 },
+  { 0x3, 0x3, 270, -1, -1, 27, 1, 0 },
+  { 0x3, 0x3, 270, -1, -1, 27, 1, 0 },
+  { 0x3, 0x3, 270, -1, -1, 27, 1, 0 },
+  { 0x3, 0x3, 270, -1, -1, 27, 1, 0 },
+  { 0x1, 0x1, 271, 3018, -1, 28, 1, 0 },
+  { 0x1, 0x1, 271, 3019, -1, 28, 1, 0 },
+  { 0x1, 0x1, 271, 3020, -1, 28, 1, 0 },
+  { 0x1, 0x1, 271, 3021, -1, 28, 1, 0 },
+  { 0x1, 0x1, 273, -1, -1, 27, 1, 100 },
+  { 0x1, 0x1, 273, -1, -1, 27, 1, 100 },
+  { 0x0, 0x0, 273, -1, 968, 0, 0, -1 },
+  { 0x0, 0x0, 274, 3031, 2833, 0, 0, -1 },
+  { 0x0, 0x0, 274, 3032, 2835, 0, 0, -1 },
+  { 0x0, 0x0, 275, -1, 2834, 0, 0, -1 },
+  { 0x0, 0x0, 275, -1, 2836, 0, 0, -1 },
+  { 0x0, 0x0, 276, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 276, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 276, -1, -1, 0, 1, 41 },
+  { 0x0, 0x0, 281, -1, -1, 0, 1, 34 },
+  { 0x0, 0x0, 285, -1, 2350, 0, 1, 30 },
+  { 0x0, 0x0, 286, -1, -1, 0, 1, 0 },
+  { 0x0, 0x0, 286, -1, -1, 0, 1, 72 },
+  { 0x0, 0x0, 286, 2001, 3000, 0, 1, 1 },
+  { 0x0, 0x0, 286, 2002, 3001, 0, 1, 1 },
+  { 0x0, 0x0, 286, -1, 518, 0, 0, -1 },
+  { 0x0, 0x0, 286, -1, 520, 0, 0, -1 },
+  { 0x0, 0x0, 286, 2005, 3004, 0, 1, 76 },
+  { 0x0, 0x0, 286, 2006, 3005, 0, 1, 76 },
+  { 0x0, 0x0, 286, -1, 526, 0, 0, -1 },
+  { 0x0, 0x0, 286, -1, 528, 0, 0, -1 },
+  { 0x0, 0x0, 286, 2009, 3008, 0, 1, 1 },
+  { 0x0, 0x0, 286, 2010, 3009, 0, 1, 1 },
+  { 0x0, 0x0, 286, -1, 534, 0, 0, -1 },
+  { 0x0, 0x0, 286, -1, 536, 0, 0, -1 },
+};
+
+static const struct ia64_main_table
+main_table[] = {
+  { 5, 1, 1, 0x0000010000000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 0, },
+  { 5, 1, 1, 0x0000010008000000ull, 0x000001eff8000000ull, { 24, 25, 26, 4, 0 }, 0x0, 1, },
+  { 5, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 67, 27, 0, 0 }, 0x0, 2, },
+  { 5, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 64, 26, 0, 0 }, 0x0, 3, },
+  { 6, 1, 1, 0x0000012000000000ull, 0x000001e000000000ull, { 24, 67, 27, 0, 0 }, 0x0, 4, },
+  { 7, 1, 1, 0x0000010040000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 5, },
+  { 7, 1, 1, 0x0000010c00000000ull, 0x000001ee00000000ull, { 24, 64, 26, 0, 0 }, 0x0, 6, },
+  { 8, 1, 1, 0x0000010800000000ull, 0x000001ee00000000ull, { 24, 64, 26, 0, 0 }, 0x0, 7, },
+  { 9, 3, 1, 0x0000002c00000000ull, 0x000001ee00000000ull, { 24, 3, 53, 54, 55 }, 0x221, 8, },
+  { 9, 3, 1, 0x0000002c00000000ull, 0x000001ee00000000ull, { 24, 53, 54, 55, 0 }, 0x261, 9, },
+  { 10, 1, 1, 0x0000010060000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 10, },
+  { 10, 1, 1, 0x0000010160000000ull, 0x000001eff8000000ull, { 24, 56, 26, 0, 0 }, 0x0, 11, },
+  { 11, 1, 1, 0x0000010068000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 12, },
+  { 11, 1, 1, 0x0000010168000000ull, 0x000001eff8000000ull, { 24, 56, 26, 0, 0 }, 0x0, 13, },
+  { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011ffull, { 16, 0, 0, 0, 0 }, 0x40, 969, },
+  { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x0, 825, },
+  { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x40, 826, },
+  { 14, 4, 0, 0x0000000108000100ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x200, 2234, },
+  { 14, 4, 0, 0x0000000108000100ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x240, 2235, },
+  { 14, 4, 1, 0x0000002100000000ull, 0x000001ef00001000ull, { 15, 16, 0, 0, 0 }, 0x0, 582, },
+  { 14, 4, 1, 0x0000002100000000ull, 0x000001ef00001000ull, { 15, 16, 0, 0, 0 }, 0x40, 583, },
+  { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011ffull, { 82, 0, 0, 0, 0 }, 0x40, 990, },
+  { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x0, 827, },
+  { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x40, 828, },
+  { 14, 4, 0, 0x0000008000000080ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x210, 3029, },
+  { 14, 4, 0, 0x0000008000000080ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x250, 3030, },
+  { 14, 4, 0, 0x0000008000000140ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x30, 590, },
+  { 14, 4, 0, 0x0000008000000140ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x70, 591, },
+  { 14, 4, 0, 0x0000008000000180ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x230, 588, },
+  { 14, 4, 0, 0x0000008000000180ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x270, 589, },
+  { 14, 4, 1, 0x000000a000000000ull, 0x000001ee00001000ull, { 15, 82, 0, 0, 0 }, 0x0, 584, },
+  { 14, 4, 1, 0x000000a000000000ull, 0x000001ee00001000ull, { 15, 82, 0, 0, 0 }, 0x40, 585, },
+  { 15, 4, 0, 0x0000000000000000ull, 0x000001e1f8000000ull, { 66, 0, 0, 0, 0 }, 0x0, 537, },
+  { 15, 5, 0, 0x0000000000000000ull, 0x000001e3f8000000ull, { 66, 0, 0, 0, 0 }, 0x0, 960, },
+  { 15, 2, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 66, 0, 0, 0, 0 }, 0x2, 1138, },
+  { 15, 3, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 66, 0, 0, 0, 0 }, 0x0, 1263, },
+  { 15, 6, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 70, 0, 0, 0, 0 }, 0x0, 3033, },
+  { 15, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 66, 0, 0, 0, 0 }, 0x0, 16, },
+  { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011ffull, { 83, 0, 0, 0, 0 }, 0x40, 1023, },
+  { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011c0ull, { 83, 0, 0, 0, 0 }, 0x0, 829, },
+  { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011c0ull, { 83, 0, 0, 0, 0 }, 0x40, 830, },
+  { 16, 6, 1, 0x000001a000000000ull, 0x000001ee00001000ull, { 15, 83, 0, 0, 0 }, 0x0, 586, },
+  { 16, 6, 1, 0x000001a000000000ull, 0x000001ee00001000ull, { 15, 83, 0, 0, 0 }, 0x40, 587, },
+  { 17, 4, 0, 0x0000004080000000ull, 0x000001e9f8000018ull, { 16, 78, 0, 0, 0 }, 0x20, 2852, },
+  { 17, 4, 0, 0x000000e000000000ull, 0x000001e800000018ull, { 82, 78, 0, 0, 0 }, 0x20, 2853, },
+  { 18, 4, 0, 0x0000000060000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x2c, 222, },
+  { 22, 2, 0, 0x0000000200000000ull, 0x000001ee00000000ull, { 25, 81, 0, 0, 0 }, 0x0, 2239, },
+  { 22, 3, 0, 0x0000000800000000ull, 0x000001ee00000000ull, { 24, 82, 0, 0, 0 }, 0x0, 226, },
+  { 22, 3, 0, 0x0000000c00000000ull, 0x000001ee00000000ull, { 18, 82, 0, 0, 0 }, 0x0, 227, },
+  { 22, 3, 0, 0x0000002200000000ull, 0x000001ee00000000ull, { 25, 81, 0, 0, 0 }, 0x0, 2240, },
+  { 22, 3, 0, 0x0000002600000000ull, 0x000001ee00000000ull, { 19, 81, 0, 0, 0 }, 0x0, 2241, },
+  { 22, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 25, 81, 0, 0, 0 }, 0x0, 2242, },
+  { 25, 4, 0, 0x0000000020000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 18, },
+  { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x0, 1222, },
+  { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 25, 26, 0, 0 }, 0x40, 1223, },
+  { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 22, 26, 25, 0 }, 0x0, 1181, },
+  { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 26, 25, 0, 0 }, 0x40, 1182, },
+  { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 23, 26, 25, 0 }, 0x0, 1090, },
+  { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 26, 25, 0, 0 }, 0x40, 1091, },
+  { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x0, 1052, },
+  { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 25, 26, 0, 0 }, 0x40, 1053, },
+  { 26, 1, 2, 0x0000018200000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x40, 1376, },
+  { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x0, 1092, },
+  { 26, 1, 1, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 7, 26, 0, 0 }, 0x40, 1093, },
+  { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 26, 7, 0 }, 0x40, 1226, },
+  { 26, 1, 1, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 26, 7, 0, 0 }, 0x40, 1227, },
+  { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x40, 1187, },
+  { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 23, 56, 26, 0 }, 0x0, 1229, },
+  { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 56, 26, 0, 0 }, 0x40, 1230, },
+  { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 23, 58, 26, 0 }, 0x0, 1188, },
+  { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 58, 26, 0, 0 }, 0x40, 1189, },
+  { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 22, 58, 26, 0 }, 0x0, 1097, },
+  { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 58, 26, 0, 0 }, 0x40, 1098, },
+  { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 22, 56, 26, 0 }, 0x0, 1059, },
+  { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 56, 26, 0, 0 }, 0x40, 1060, },
+  { 26, 1, 2, 0x0000018a00000000ull, 0x000001ee00001000ull, { 22, 23, 56, 26, 0 }, 0x40, 1381, },
+  { 26, 1, 2, 0x000001a800000000ull, 0x000001ee00001000ull, { 22, 23, 60, 26, 0 }, 0x0, 1214, },
+  { 26, 1, 1, 0x000001a800000000ull, 0x000001ee00001000ull, { 22, 60, 26, 0, 0 }, 0x40, 1215, },
+  { 26, 1, 2, 0x000001a800000000ull, 0x000001ee00001000ull, { 23, 22, 60, 26, 0 }, 0x0, 1125, },
+  { 26, 1, 1, 0x000001a800000000ull, 0x000001ee00001000ull, { 23, 60, 26, 0, 0 }, 0x40, 1126, },
+  { 26, 1, 2, 0x000001c200000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x40, 1382, },
+  { 26, 1, 2, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 22, 7, 26, 0 }, 0x40, 1190, },
+  { 26, 1, 1, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 7, 26, 0, 0 }, 0x40, 1191, },
+  { 26, 1, 2, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 22, 26, 7, 0 }, 0x40, 1063, },
+  { 26, 1, 1, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 26, 7, 0, 0 }, 0x40, 1064, },
+  { 26, 1, 2, 0x000001ca00000000ull, 0x000001ee00001000ull, { 23, 22, 56, 26, 0 }, 0x40, 1383, },
+  { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x0, 1235, },
+  { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 25, 26, 0, 0 }, 0x40, 1236, },
+  { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 22, 26, 25, 0 }, 0x0, 1194, },
+  { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 26, 25, 0, 0 }, 0x40, 1195, },
+  { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 23, 26, 25, 0 }, 0x0, 1103, },
+  { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 26, 25, 0, 0 }, 0x40, 1104, },
+  { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x0, 1065, },
+  { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 25, 26, 0, 0 }, 0x40, 1066, },
+  { 27, 1, 2, 0x0000018600000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x40, 1388, },
+  { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x0, 1105, },
+  { 27, 1, 1, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 7, 26, 0, 0 }, 0x40, 1106, },
+  { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 26, 7, 0 }, 0x40, 1239, },
+  { 27, 1, 1, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 26, 7, 0, 0 }, 0x40, 1240, },
+  { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x40, 1200, },
+  { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 23, 56, 26, 0 }, 0x0, 1242, },
+  { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 56, 26, 0, 0 }, 0x40, 1243, },
+  { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 23, 58, 26, 0 }, 0x0, 1201, },
+  { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 58, 26, 0, 0 }, 0x40, 1202, },
+  { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 22, 58, 26, 0 }, 0x0, 1110, },
+  { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 58, 26, 0, 0 }, 0x40, 1111, },
+  { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 22, 56, 26, 0 }, 0x0, 1072, },
+  { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 56, 26, 0, 0 }, 0x40, 1073, },
+  { 27, 1, 2, 0x0000018e00000000ull, 0x000001ee00001000ull, { 22, 23, 56, 26, 0 }, 0x40, 1393, },
+  { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 23, 57, 26, 0 }, 0x0, 1259, },
+  { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 57, 26, 0, 0 }, 0x40, 1260, },
+  { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 23, 59, 26, 0 }, 0x0, 1218, },
+  { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 59, 26, 0, 0 }, 0x40, 1219, },
+  { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 22, 59, 26, 0 }, 0x0, 1129, },
+  { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 59, 26, 0, 0 }, 0x40, 1130, },
+  { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 22, 57, 26, 0 }, 0x0, 1088, },
+  { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 57, 26, 0, 0 }, 0x40, 1089, },
+  { 27, 1, 2, 0x000001c600000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x40, 1394, },
+  { 27, 1, 2, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 22, 7, 26, 0 }, 0x40, 1203, },
+  { 27, 1, 1, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 7, 26, 0, 0 }, 0x40, 1204, },
+  { 27, 1, 2, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 22, 26, 7, 0 }, 0x40, 1076, },
+  { 27, 1, 1, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 26, 7, 0, 0 }, 0x40, 1077, },
+  { 27, 1, 2, 0x000001ce00000000ull, 0x000001ee00001000ull, { 23, 22, 56, 26, 0 }, 0x40, 1395, },
+  { 28, 3, 1, 0x0000008808000000ull, 0x000001fff8000000ull, { 24, 28, 25, 1, 2 }, 0x0, 259, },
+  { 28, 3, 1, 0x0000008808000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x40, 260, },
+  { 29, 3, 1, 0x0000008008000000ull, 0x000001fff8000000ull, { 24, 28, 25, 2, 0 }, 0x0, 261, },
+  { 29, 3, 1, 0x0000008008000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x40, 262, },
+  { 30, 3, 1, 0x0000008048000000ull, 0x000001fff8000000ull, { 24, 28, 25, 2, 0 }, 0x0, 263, },
+  { 30, 3, 1, 0x0000008048000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x40, 264, },
+  { 31, 3, 1, 0x0000008088000000ull, 0x000001fff8000000ull, { 24, 28, 25, 2, 0 }, 0x0, 265, },
+  { 31, 3, 1, 0x0000008088000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x40, 266, },
+  { 32, 3, 1, 0x00000080c8000000ull, 0x000001fff8000000ull, { 24, 28, 25, 2, 0 }, 0x0, 267, },
+  { 32, 3, 1, 0x00000080c8000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x40, 268, },
+  { 34, 4, 0, 0x0000000010000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 19, },
+  { 36, 2, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 1167, },
+  { 37, 2, 1, 0x00000000c8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 1168, },
+  { 39, 2, 1, 0x0000008000000000ull, 0x000001e000000000ull, { 24, 25, 26, 47, 73 }, 0x0, 20, },
+  { 39, 2, 1, 0x000000a600000000ull, 0x000001ee04000000ull, { 24, 25, 45, 74, 0 }, 0x0, 3038, },
+  { 39, 2, 1, 0x000000a604000000ull, 0x000001ee04000000ull, { 24, 56, 45, 74, 0 }, 0x0, 3039, },
+  { 39, 2, 1, 0x000000ae00000000ull, 0x000001ee00000000ull, { 24, 48, 26, 46, 74 }, 0x0, 21, },
+  { 43, 4, 0, 0x0000000080000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x20, 22, },
+  { 48, 2, 1, 0x000000a400000000ull, 0x000001ee00002000ull, { 24, 26, 77, 74, 0 }, 0x0, 2870, },
+  { 50, 5, 1, 0x0000000080000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 24, },
+  { 51, 5, 1, 0x0000010008000000ull, 0x000001fff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 2291, },
+  { 52, 5, 1, 0x00000000b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2292, },
+  { 52, 5, 1, 0x00000000b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 26, },
+  { 53, 5, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2293, },
+  { 53, 5, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 27, },
+  { 54, 5, 1, 0x0000000160000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 28, },
+  { 55, 5, 1, 0x0000000168000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 29, },
+  { 57, 3, 0, 0x0000002180000000ull, 0x000001fff8000000ull, { 26, 0, 0, 0, 0 }, 0x0, 30, },
+  { 58, 5, 0, 0x0000000040000000ull, 0x000001eff8000000ull, { 80, 0, 0, 0, 0 }, 0x0, 2294, },
+  { 58, 5, 0, 0x0000000040000000ull, 0x000001eff8000000ull, { 80, 0, 0, 0, 0 }, 0x40, 31, },
+  { 59, 5, 2, 0x000000a000000000ull, 0x000001e000001000ull, { 22, 23, 19, 61, 0 }, 0x0, 1265, },
+  { 59, 5, 1, 0x000000a000000000ull, 0x000001e000001000ull, { 22, 19, 61, 0, 0 }, 0x40, 1266, },
+  { 59, 5, 2, 0x000000a000000000ull, 0x000001e000001000ull, { 23, 22, 19, 61, 0 }, 0x40, 1420, },
+  { 59, 5, 1, 0x000000a000000000ull, 0x000001e000001000ull, { 23, 19, 61, 0, 0 }, 0x40, 1421, },
+  { 60, 5, 0, 0x0000000028000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 2295, },
+  { 60, 5, 0, 0x0000000028000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x40, 32, },
+  { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 23, 19, 20, 0 }, 0x0, 943, },
+  { 61, 5, 1, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 19, 20, 0, 0 }, 0x40, 944, },
+  { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 23, 19, 20, 0 }, 0x40, 945, },
+  { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 23, 20, 19, 0 }, 0x0, 1116, },
+  { 61, 5, 1, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 20, 19, 0, 0 }, 0x40, 1117, },
+  { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 23, 20, 19, 0 }, 0x40, 1118, },
+  { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 22, 19, 20, 0 }, 0x0, 1396, },
+  { 61, 5, 1, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 19, 20, 0, 0 }, 0x40, 1397, },
+  { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 22, 19, 20, 0 }, 0x40, 1398, },
+  { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 22, 20, 19, 0 }, 0x0, 1405, },
+  { 61, 5, 1, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 20, 19, 0, 0 }, 0x40, 1406, },
+  { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 22, 20, 19, 0 }, 0x40, 1407, },
+  { 62, 5, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 1042, },
+  { 62, 5, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x40, 1043, },
+  { 62, 5, 1, 0x00000000e0000000ull, 0x000001e3f8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 3036, },
+  { 62, 5, 1, 0x0000010008000000ull, 0x000001fff80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 3037, },
+  { 63, 3, 1, 0x0000008488000000ull, 0x000001fff8000000ull, { 24, 28, 72, 0, 0 }, 0x0, 269, },
+  { 64, 3, 1, 0x00000084c8000000ull, 0x000001fff8000000ull, { 24, 28, 72, 0, 0 }, 0x0, 270, },
+  { 67, 3, 0, 0x0000000060000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 33, },
+  { 68, 5, 1, 0x0000010000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2353, },
+  { 68, 5, 1, 0x0000010000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 34, },
+  { 69, 5, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2354, },
+  { 69, 5, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 35, },
+  { 70, 5, 1, 0x0000000080000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2247, },
+  { 71, 5, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2355, },
+  { 71, 5, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 36, },
+  { 72, 5, 1, 0x00000001c8000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 1221, },
+  { 73, 5, 1, 0x0000010000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2358, },
+  { 74, 5, 1, 0x0000014000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2361, },
+  { 74, 5, 1, 0x0000014000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 38, },
+  { 75, 5, 1, 0x0000000088000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 39, },
+  { 76, 5, 1, 0x0000000088000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 40, },
+  { 77, 5, 1, 0x0000018000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2364, },
+  { 77, 5, 1, 0x0000018000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 41, },
+  { 78, 5, 1, 0x0000018000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2367, },
+  { 79, 5, 1, 0x0000010008000000ull, 0x000001fff80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 2370, },
+  { 80, 5, 1, 0x0000000170000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 44, },
+  { 81, 5, 1, 0x0000002080000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 45, },
+  { 82, 5, 1, 0x0000000140000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 46, },
+  { 83, 5, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2371, },
+  { 83, 5, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 47, },
+  { 84, 5, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2372, },
+  { 84, 5, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 48, },
+  { 85, 5, 1, 0x0000002180000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 946, },
+  { 85, 5, 1, 0x0000002180000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 947, },
+  { 85, 5, 1, 0x0000002188000000ull, 0x000001eff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 1119, },
+  { 86, 5, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 1044, },
+  { 86, 5, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x40, 1045, },
+  { 87, 5, 1, 0x0000013000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2389, },
+  { 87, 5, 1, 0x0000013000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 49, },
+  { 88, 5, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2390, },
+  { 88, 5, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 50, },
+  { 89, 5, 1, 0x0000002080000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2255, },
+  { 90, 5, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2391, },
+  { 90, 5, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 51, },
+  { 91, 5, 1, 0x0000013000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2392, },
+  { 92, 5, 1, 0x0000017000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2393, },
+  { 92, 5, 1, 0x0000017000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 53, },
+  { 93, 5, 1, 0x0000002088000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 54, },
+  { 94, 5, 1, 0x0000002088000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 55, },
+  { 95, 5, 1, 0x000001b000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2394, },
+  { 95, 5, 1, 0x000001b000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 56, },
+  { 96, 5, 1, 0x000001b000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2395, },
+  { 97, 5, 2, 0x0000002200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x0, 2396, },
+  { 97, 5, 2, 0x0000002200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x40, 58, },
+  { 98, 5, 2, 0x0000003200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x0, 2397, },
+  { 98, 5, 2, 0x0000003200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x40, 59, },
+  { 99, 5, 2, 0x0000000200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x0, 2398, },
+  { 99, 5, 2, 0x0000000200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x40, 60, },
+  { 100, 5, 2, 0x0000001200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x0, 2399, },
+  { 100, 5, 2, 0x0000001200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x40, 61, },
+  { 101, 5, 1, 0x000001c000000000ull, 0x000001f000000000ull, { 18, 20, 21, 19, 0 }, 0x0, 62, },
+  { 102, 5, 0, 0x0000000020000000ull, 0x000001eff8000000ull, { 51, 52, 0, 0, 0 }, 0x0, 2400, },
+  { 102, 5, 0, 0x0000000020000000ull, 0x000001eff8000000ull, { 51, 52, 0, 0, 0 }, 0x40, 63, },
+  { 103, 5, 1, 0x0000014008000000ull, 0x000001fff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 2403, },
+  { 104, 5, 1, 0x00000001a0000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 65, },
+  { 105, 5, 1, 0x00000001e0000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2202, },
+  { 106, 3, 0, 0x0000000100000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 66, },
+  { 108, 5, 1, 0x0000000178000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 67, },
+  { 113, 3, 1, 0x0000008708000000ull, 0x000001ffc8000000ull, { 24, 19, 0, 0, 0 }, 0x0, 2781, },
+  { 118, 4, 0, 0x0000004008000000ull, 0x000001e1f8000000ull, { 66, 0, 0, 0, 0 }, 0x0, 538, },
+  { 118, 5, 0, 0x000000000c000000ull, 0x000001e3fc000000ull, { 66, 0, 0, 0, 0 }, 0x0, 961, },
+  { 118, 2, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 66, 0, 0, 0, 0 }, 0x2, 1141, },
+  { 118, 3, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 66, 0, 0, 0, 0 }, 0x0, 1267, },
+  { 118, 6, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 70, 0, 0, 0, 0 }, 0x0, 3034, },
+  { 118, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 66, 0, 0, 0, 0 }, 0x0, 68, },
+  { 123, 3, 0, 0x0000000080000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 69, },
+  { 123, 3, 0, 0x0000000090000000ull, 0x000001eff8000000ull, { 24, 0, 0, 0, 0 }, 0x0, 920, },
+  { 123, 3, 0, 0x0000000098000000ull, 0x000001eff8000000ull, { 18, 0, 0, 0, 0 }, 0x0, 921, },
+  { 124, 3, 0, 0x0000002170000000ull, 0x000001eff8000000ull, { 25, 0, 0, 0, 0 }, 0xc, 846, },
+  { 125, 3, 1, 0x0000002070000000ull, 0x000001eff8000000ull, { 31, 25, 0, 0, 0 }, 0x8, 847, },
+  { 125, 3, 1, 0x0000002078000000ull, 0x000001eff8000000ull, { 32, 25, 0, 0, 0 }, 0x8, 1143, },
+  { 127, 3, 1, 0x0000008000000000ull, 0x000001fff8000000ull, { 24, 28, 0, 0, 0 }, 0x0, 70, },
+  { 127, 3, 1, 0x0000009000000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x400, 71, },
+  { 127, 3, 1, 0x000000a000000000ull, 0x000001eff0000000ull, { 24, 28, 63, 0, 0 }, 0x400, 72, },
+  { 128, 3, 2, 0x0000008a08000000ull, 0x000001fff8000000ull, { 24, 1, 28, 0, 0 }, 0x0, 73, },
+  { 128, 3, 1, 0x0000008a08000000ull, 0x000001fff8000000ull, { 24, 28, 0, 0, 0 }, 0x40, 74, },
+  { 129, 3, 1, 0x0000008040000000ull, 0x000001fff8000000ull, { 24, 28, 0, 0, 0 }, 0x0, 75, },
+  { 129, 3, 1, 0x0000009040000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x400, 76, },
+  { 129, 3, 1, 0x000000a040000000ull, 0x000001eff0000000ull, { 24, 28, 63, 0, 0 }, 0x400, 77, },
+  { 130, 3, 1, 0x0000008080000000ull, 0x000001fff8000000ull, { 24, 28, 0, 0, 0 }, 0x0, 78, },
+  { 130, 3, 1, 0x0000009080000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x400, 79, },
+  { 130, 3, 1, 0x000000a080000000ull, 0x000001eff0000000ull, { 24, 28, 63, 0, 0 }, 0x400, 80, },
+  { 131, 3, 1, 0x00000080c0000000ull, 0x000001fff8000000ull, { 24, 28, 0, 0, 0 }, 0x0, 81, },
+  { 131, 3, 1, 0x00000080c0000000ull, 0x000001fff8000000ull, { 24, 28, 84, 0, 0 }, 0x0, 1339, },
+  { 131, 3, 1, 0x00000090c0000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x400, 82, },
+  { 131, 3, 1, 0x000000a0c0000000ull, 0x000001eff0000000ull, { 24, 28, 63, 0, 0 }, 0x400, 83, },
+  { 132, 3, 1, 0x000000c6c0000000ull, 0x000001fff8000000ull, { 18, 28, 0, 0, 0 }, 0x0, 1039, },
+  { 132, 3, 1, 0x000000d6c0000000ull, 0x000001fff8000000ull, { 18, 28, 25, 0, 0 }, 0x400, 1040, },
+  { 132, 3, 1, 0x000000e6c0000000ull, 0x000001eff0000000ull, { 18, 28, 63, 0, 0 }, 0x400, 1041, },
+  { 133, 3, 1, 0x000000c040000000ull, 0x000001fff8000000ull, { 18, 28, 0, 0, 0 }, 0x0, 84, },
+  { 133, 3, 1, 0x000000d040000000ull, 0x000001fff8000000ull, { 18, 28, 25, 0, 0 }, 0x400, 85, },
+  { 133, 3, 1, 0x000000e040000000ull, 0x000001eff0000000ull, { 18, 28, 63, 0, 0 }, 0x400, 86, },
+  { 134, 3, 1, 0x000000c0c0000000ull, 0x000001fff8000000ull, { 18, 28, 0, 0, 0 }, 0x0, 87, },
+  { 134, 3, 1, 0x000000d0c0000000ull, 0x000001fff8000000ull, { 18, 28, 25, 0, 0 }, 0x400, 88, },
+  { 134, 3, 1, 0x000000e0c0000000ull, 0x000001eff0000000ull, { 18, 28, 63, 0, 0 }, 0x400, 89, },
+  { 135, 3, 1, 0x000000c000000000ull, 0x000001fff8000000ull, { 18, 28, 0, 0, 0 }, 0x0, 90, },
+  { 135, 3, 1, 0x000000d000000000ull, 0x000001fff8000000ull, { 18, 28, 25, 0, 0 }, 0x400, 91, },
+  { 135, 3, 1, 0x000000e000000000ull, 0x000001eff0000000ull, { 18, 28, 63, 0, 0 }, 0x400, 92, },
+  { 136, 3, 2, 0x000000c048000000ull, 0x000001fff8000000ull, { 18, 19, 28, 0, 0 }, 0x0, 93, },
+  { 136, 3, 2, 0x000000d048000000ull, 0x000001fff8000000ull, { 18, 19, 28, 6, 0 }, 0x400, 94, },
+  { 137, 3, 2, 0x000000c0c8000000ull, 0x000001fff8000000ull, { 18, 19, 28, 0, 0 }, 0x0, 95, },
+  { 137, 3, 2, 0x000000d0c8000000ull, 0x000001fff8000000ull, { 18, 19, 28, 6, 0 }, 0x400, 96, },
+  { 138, 3, 2, 0x000000c088000000ull, 0x000001fff8000000ull, { 18, 19, 28, 0, 0 }, 0x0, 97, },
+  { 138, 3, 2, 0x000000d088000000ull, 0x000001fff8000000ull, { 18, 19, 28, 5, 0 }, 0x400, 98, },
+  { 139, 3, 1, 0x000000c080000000ull, 0x000001fff8000000ull, { 18, 28, 0, 0, 0 }, 0x0, 99, },
+  { 139, 3, 1, 0x000000d080000000ull, 0x000001fff8000000ull, { 18, 28, 25, 0, 0 }, 0x400, 100, },
+  { 139, 3, 1, 0x000000e080000000ull, 0x000001eff0000000ull, { 18, 28, 63, 0, 0 }, 0x400, 101, },
+  { 142, 3, 0, 0x000000cb00000000ull, 0x000001fff8000000ull, { 28, 0, 0, 0, 0 }, 0x0, 102, },
+  { 142, 3, 0, 0x000000db00000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x400, 103, },
+  { 142, 3, 0, 0x000000eb00000000ull, 0x000001eff0000000ull, { 28, 63, 0, 0, 0 }, 0x400, 104, },
+  { 143, 3, 0, 0x0000000050000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 105, },
+  { 151, 3, 0, 0x0000000110000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 106, },
+  { 152, 2, 1, 0x000000e880000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2203, },
+  { 153, 2, 1, 0x000000ea80000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2204, },
+  { 154, 2, 1, 0x000000f880000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2205, },
+  { 155, 1, 1, 0x0000010800000000ull, 0x000001fff80fe000ull, { 24, 26, 0, 0, 0 }, 0x0, 107, },
+  { 155, 1, 1, 0x0000012000000000ull, 0x000001e000300000ull, { 24, 67, 0, 0, 0 }, 0x40, 108, },
+  { 155, 5, 1, 0x0000000080000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 109, },
+  { 155, 2, 1, 0x0000000e00100000ull, 0x000001ee00f00000ull, { 15, 25, 0, 0, 0 }, 0x40, 110, },
+  { 155, 2, 1, 0x0000000e00000000ull, 0x000001ee00f00000ull, { 15, 25, 79, 0, 0 }, 0x0, 2855, },
+  { 155, 2, 1, 0x0000000188000000ull, 0x000001eff8000000ull, { 24, 16, 0, 0, 0 }, 0x0, 112, },
+  { 155, 2, 1, 0x0000000600000000ull, 0x000001ee00000000ull, { 9, 25, 65, 0, 0 }, 0x0, 113, },
+  { 155, 2, 1, 0x00000016ff001fc0ull, 0x000001feff001fc0ull, { 9, 25, 0, 0, 0 }, 0x40, 114, },
+  { 155, 2, 1, 0x0000000400000000ull, 0x000001ee00000000ull, { 10, 69, 0, 0, 0 }, 0x0, 115, },
+  { 155, 2, 1, 0x0000000180000000ull, 0x000001eff8000000ull, { 24, 8, 0, 0, 0 }, 0x0, 116, },
+  { 155, 2, 1, 0x0000000198000000ull, 0x000001eff8000000ull, { 24, 9, 0, 0, 0 }, 0x0, 117, },
+  { 155, 2, 1, 0x0000000150000000ull, 0x000001eff8000000ull, { 14, 25, 0, 0, 0 }, 0x0, 1144, },
+  { 155, 2, 1, 0x0000000050000000ull, 0x000001eff8000000ull, { 14, 56, 0, 0, 0 }, 0x0, 1145, },
+  { 155, 2, 1, 0x0000000190000000ull, 0x000001eff8000000ull, { 24, 14, 0, 0, 0 }, 0x0, 1146, },
+  { 155, 3, 1, 0x0000000140000000ull, 0x000001eff8000000ull, { 14, 56, 0, 0, 0 }, 0x0, 1268, },
+  { 155, 3, 1, 0x0000002150000000ull, 0x000001eff8000000ull, { 14, 25, 0, 0, 0 }, 0x0, 1269, },
+  { 155, 3, 1, 0x0000002110000000ull, 0x000001eff8000000ull, { 24, 14, 0, 0, 0 }, 0x0, 1270, },
+  { 155, 3, 1, 0x0000002160000000ull, 0x000001eff8000000ull, { 17, 25, 0, 0, 0 }, 0x8, 118, },
+  { 155, 3, 1, 0x0000002120000000ull, 0x000001eff8000000ull, { 24, 17, 0, 0, 0 }, 0x8, 119, },
+  { 155, 3, 1, 0x0000002168000000ull, 0x000001eff8000000ull, { 12, 25, 0, 0, 0 }, 0x8, 120, },
+  { 155, 3, 1, 0x0000002148000000ull, 0x000001eff8000000ull, { 13, 25, 0, 0, 0 }, 0x0, 121, },
+  { 155, 3, 1, 0x0000002128000000ull, 0x000001eff8000000ull, { 24, 11, 0, 0, 0 }, 0x8, 122, },
+  { 155, 3, 1, 0x0000002108000000ull, 0x000001eff8000000ull, { 24, 13, 0, 0, 0 }, 0x0, 123, },
+  { 155, 3, 1, 0x0000002000000000ull, 0x000001eff8000000ull, { 38, 25, 0, 0, 0 }, 0x8, 124, },
+  { 155, 3, 1, 0x0000002008000000ull, 0x000001eff8000000ull, { 30, 25, 0, 0, 0 }, 0x8, 125, },
+  { 155, 3, 1, 0x0000002010000000ull, 0x000001eff8000000ull, { 33, 25, 0, 0, 0 }, 0x8, 126, },
+  { 155, 3, 1, 0x0000002018000000ull, 0x000001eff8000000ull, { 35, 25, 0, 0, 0 }, 0x8, 127, },
+  { 155, 3, 1, 0x0000002020000000ull, 0x000001eff8000000ull, { 36, 25, 0, 0, 0 }, 0x8, 128, },
+  { 155, 3, 1, 0x0000002028000000ull, 0x000001eff8000000ull, { 37, 25, 0, 0, 0 }, 0x8, 129, },
+  { 155, 3, 1, 0x0000002030000000ull, 0x000001eff8000000ull, { 34, 25, 0, 0, 0 }, 0x8, 130, },
+  { 155, 3, 1, 0x0000002080000000ull, 0x000001eff8000000ull, { 24, 38, 0, 0, 0 }, 0x8, 131, },
+  { 155, 3, 1, 0x0000002088000000ull, 0x000001eff8000000ull, { 24, 30, 0, 0, 0 }, 0x8, 132, },
+  { 155, 3, 1, 0x0000002090000000ull, 0x000001eff8000000ull, { 24, 33, 0, 0, 0 }, 0x8, 133, },
+  { 155, 3, 1, 0x0000002098000000ull, 0x000001eff8000000ull, { 24, 35, 0, 0, 0 }, 0x8, 134, },
+  { 155, 3, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 24, 36, 0, 0, 0 }, 0x8, 135, },
+  { 155, 3, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 24, 37, 0, 0, 0 }, 0x0, 136, },
+  { 155, 3, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 24, 34, 0, 0, 0 }, 0x8, 137, },
+  { 155, 3, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 24, 29, 0, 0, 0 }, 0x0, 138, },
+  { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 14, 0, 0, 0 }, 0x0, 139, },
+  { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 14, 56, 0, 0, 0 }, 0x0, 140, },
+  { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 14, 25, 0, 0, 0 }, 0x0, 141, },
+  { 156, 6, 1, 0x000000c000000000ull, 0x000001e000100000ull, { 24, 71, 0, 0, 0 }, 0x0, 142, },
+  { 157, 2, 1, 0x000000eca0000000ull, 0x000001fff0000000ull, { 24, 25, 75, 0, 0 }, 0x0, 143, },
+  { 158, 2, 1, 0x000000eea0000000ull, 0x000001fff0000000ull, { 24, 25, 76, 0, 0 }, 0x0, 144, },
+  { 168, 4, 0, 0x0000004000000000ull, 0x000001e1f8000000ull, { 66, 0, 0, 0, 0 }, 0x0, 539, },
+  { 168, 5, 0, 0x0000000008000000ull, 0x000001e3fc000000ull, { 66, 0, 0, 0, 0 }, 0x0, 962, },
+  { 168, 2, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 66, 0, 0, 0, 0 }, 0x2, 1147, },
+  { 168, 3, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 66, 0, 0, 0, 0 }, 0x0, 1271, },
+  { 168, 6, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 70, 0, 0, 0, 0 }, 0x0, 3035, },
+  { 168, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 66, 0, 0, 0, 0 }, 0x0, 145, },
+  { 175, 1, 1, 0x0000010070000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 146, },
+  { 175, 1, 1, 0x0000010170000000ull, 0x000001eff8000000ull, { 24, 56, 26, 0, 0 }, 0x0, 147, },
+  { 178, 2, 1, 0x000000ea00000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 3017, },
+  { 179, 2, 1, 0x000000f820000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2857, },
+  { 180, 1, 1, 0x0000010400000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 148, },
+  { 181, 1, 1, 0x0000010600000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 149, },
+  { 182, 1, 1, 0x0000011400000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 150, },
+  { 183, 1, 1, 0x0000010450000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 151, },
+  { 184, 1, 1, 0x0000010650000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 152, },
+  { 185, 1, 1, 0x0000010470000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 153, },
+  { 186, 1, 1, 0x0000010670000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 154, },
+  { 187, 1, 1, 0x0000010520000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 948, },
+  { 188, 1, 1, 0x0000010720000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 949, },
+  { 189, 1, 1, 0x0000011520000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 950, },
+  { 190, 2, 1, 0x000000e850000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2871, },
+  { 191, 2, 1, 0x000000ea70000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 155, },
+  { 192, 2, 1, 0x000000e810000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2872, },
+  { 193, 2, 1, 0x000000ea30000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 156, },
+  { 194, 2, 1, 0x000000ead0000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2206, },
+  { 195, 2, 1, 0x000000e230000000ull, 0x000001ff30000000ull, { 24, 25, 26, 42, 0 }, 0x0, 157, },
+  { 196, 2, 1, 0x000000e690000000ull, 0x000001fff0000000ull, { 24, 26, 0, 0, 0 }, 0x0, 158, },
+  { 198, 3, 1, 0x00000021c0000000ull, 0x000001eff8000000ull, { 24, 26, 25, 0, 0 }, 0x0, 2207, },
+  { 198, 3, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 24, 26, 49, 0, 0 }, 0x0, 2208, },
+  { 198, 3, 0, 0x0000002188000000ull, 0x000001eff8000000ull, { 26, 49, 0, 0, 0 }, 0x0, 2238, },
+  { 199, 2, 1, 0x000000e8b0000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 159, },
+  { 200, 2, 1, 0x000000e240000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 160, },
+  { 200, 2, 1, 0x000000ee50000000ull, 0x000001fff0000000ull, { 24, 25, 39, 0, 0 }, 0x0, 161, },
+  { 201, 2, 1, 0x000000f040000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 162, },
+  { 201, 2, 1, 0x000000fc50000000ull, 0x000001fff0000000ull, { 24, 25, 39, 0, 0 }, 0x0, 163, },
+  { 202, 1, 1, 0x0000010680000000ull, 0x000001ffe0000000ull, { 24, 25, 41, 26, 0 }, 0x0, 164, },
+  { 203, 2, 1, 0x000000e220000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 165, },
+  { 203, 2, 1, 0x000000e630000000ull, 0x000001fff0000000ull, { 24, 26, 43, 0, 0 }, 0x0, 166, },
+  { 204, 2, 1, 0x000000f020000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 167, },
+  { 204, 2, 1, 0x000000f430000000ull, 0x000001fff0000000ull, { 24, 26, 43, 0, 0 }, 0x0, 168, },
+  { 205, 1, 1, 0x00000106c0000000ull, 0x000001ffe0000000ull, { 24, 25, 41, 26, 0 }, 0x0, 169, },
+  { 206, 1, 1, 0x0000010420000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 170, },
+  { 207, 1, 1, 0x0000010620000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 171, },
+  { 208, 1, 1, 0x0000011420000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 172, },
+  { 209, 3, 0, 0x0000002048000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0x8, 1175, },
+  { 209, 3, 0, 0x0000002050000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0xc, 1050, },
+  { 209, 3, 0, 0x00000021a0000000ull, 0x000001eff8000000ull, { 26, 0, 0, 0, 0 }, 0x8, 922, },
+  { 210, 3, 0, 0x0000002060000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0x8, 848, },
+  { 215, 4, 0, 0x0000000040000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x22c, 173, },
+  { 216, 3, 0, 0x0000000038000000ull, 0x000001ee78000000ull, { 68, 0, 0, 0, 0 }, 0x8, 174, },
+  { 217, 3, 0, 0x0000000028000000ull, 0x000001ee78000000ull, { 68, 0, 0, 0, 0 }, 0x0, 175, },
+  { 226, 3, 1, 0x000000c708000000ull, 0x000001ffc8000000ull, { 18, 25, 0, 0, 0 }, 0x0, 2782, },
+  { 227, 2, 1, 0x000000a600000000ull, 0x000001ee04000000ull, { 24, 25, 45, 0, 0 }, 0x140, 176, },
+  { 227, 2, 1, 0x000000f240000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 177, },
+  { 228, 1, 1, 0x0000010080000000ull, 0x000001efe0000000ull, { 24, 25, 40, 26, 0 }, 0x0, 178, },
+  { 229, 1, 1, 0x00000100c0000000ull, 0x000001efe0000000ull, { 24, 25, 40, 26, 0 }, 0x0, 179, },
+  { 230, 2, 1, 0x000000a400000000ull, 0x000001ee00002000ull, { 24, 26, 77, 0, 0 }, 0x140, 2878, },
+  { 230, 2, 1, 0x000000f220000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 181, },
+  { 231, 2, 1, 0x000000ac00000000ull, 0x000001ee00000000ull, { 24, 25, 26, 44, 0 }, 0x0, 182, },
+  { 236, 3, 0, 0x0000000180000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 850, },
+  { 237, 3, 0, 0x0000000030000000ull, 0x000001ee78000000ull, { 68, 0, 0, 0, 0 }, 0x8, 183, },
+  { 239, 3, 1, 0x0000008c00000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x0, 184, },
+  { 239, 3, 1, 0x000000ac00000000ull, 0x000001eff0000000ull, { 28, 25, 62, 0, 0 }, 0x400, 185, },
+  { 240, 3, 1, 0x0000008c08000000ull, 0x000001fff8000000ull, { 28, 25, 1, 0, 0 }, 0x0, 186, },
+  { 240, 3, 1, 0x0000008c08000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x40, 187, },
+  { 241, 3, 1, 0x0000008c40000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x0, 188, },
+  { 241, 3, 1, 0x000000ac40000000ull, 0x000001eff0000000ull, { 28, 25, 62, 0, 0 }, 0x400, 189, },
+  { 242, 3, 1, 0x0000008c80000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x0, 190, },
+  { 242, 3, 1, 0x000000ac80000000ull, 0x000001eff0000000ull, { 28, 25, 62, 0, 0 }, 0x400, 191, },
+  { 243, 3, 1, 0x0000008cc0000000ull, 0x000001fff8000000ull, { 28, 25, 0, 0, 0 }, 0x0, 192, },
+  { 243, 3, 1, 0x000000acc0000000ull, 0x000001eff0000000ull, { 28, 25, 62, 0, 0 }, 0x400, 193, },
+  { 244, 3, 1, 0x000000cec0000000ull, 0x000001fff8000000ull, { 28, 19, 0, 0, 0 }, 0x0, 2785, },
+  { 244, 3, 1, 0x000000eec0000000ull, 0x000001eff0000000ull, { 28, 19, 62, 0, 0 }, 0x400, 2786, },
+  { 245, 3, 1, 0x000000cc40000000ull, 0x000001fff8000000ull, { 28, 19, 0, 0, 0 }, 0x0, 194, },
+  { 245, 3, 1, 0x000000ec40000000ull, 0x000001eff0000000ull, { 28, 19, 62, 0, 0 }, 0x400, 195, },
+  { 246, 3, 1, 0x000000ccc0000000ull, 0x000001fff8000000ull, { 28, 19, 0, 0, 0 }, 0x0, 196, },
+  { 246, 3, 1, 0x000000ecc0000000ull, 0x000001eff0000000ull, { 28, 19, 62, 0, 0 }, 0x400, 197, },
+  { 247, 3, 1, 0x000000cc00000000ull, 0x000001fff8000000ull, { 28, 19, 0, 0, 0 }, 0x0, 198, },
+  { 247, 3, 1, 0x000000ec00000000ull, 0x000001eff0000000ull, { 28, 19, 62, 0, 0 }, 0x400, 199, },
+  { 248, 3, 1, 0x000000cc80000000ull, 0x000001fff8000000ull, { 28, 19, 0, 0, 0 }, 0x0, 200, },
+  { 248, 3, 1, 0x000000ec80000000ull, 0x000001eff0000000ull, { 28, 19, 62, 0, 0 }, 0x400, 201, },
+  { 249, 1, 1, 0x0000010028000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 202, },
+  { 249, 1, 1, 0x0000010020000000ull, 0x000001eff8000000ull, { 24, 25, 26, 4, 0 }, 0x0, 203, },
+  { 249, 1, 1, 0x0000010128000000ull, 0x000001eff8000000ull, { 24, 56, 26, 0, 0 }, 0x0, 204, },
+  { 250, 3, 0, 0x0000000020000000ull, 0x000001ee78000000ull, { 68, 0, 0, 0, 0 }, 0x0, 205, },
+  { 251, 2, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 206, },
+  { 252, 2, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 207, },
+  { 253, 2, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 208, },
+  { 254, 3, 0, 0x0000000198000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 1150, },
+  { 255, 3, 1, 0x00000020f8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x8, 209, },
+  { 256, 2, 2, 0x000000a000000000ull, 0x000001fe00003000ull, { 22, 23, 26, 77, 0 }, 0x0, 3040, },
+  { 256, 2, 1, 0x000000a000000000ull, 0x000001fe00003000ull, { 22, 26, 77, 0, 0 }, 0x40, 3041, },
+  { 256, 2, 2, 0x000000a000000000ull, 0x000001fe00003000ull, { 23, 22, 26, 77, 0 }, 0x40, 2003, },
+  { 256, 2, 1, 0x000000a000000000ull, 0x000001fe00003000ull, { 23, 26, 77, 0, 0 }, 0x40, 2004, },
+  { 257, 2, 2, 0x000000a000082000ull, 0x000001fe00083000ull, { 22, 23, 50, 0, 0 }, 0x0, 3044, },
+  { 257, 2, 1, 0x000000a000082000ull, 0x000001fe00083000ull, { 22, 50, 0, 0, 0 }, 0x40, 3045, },
+  { 257, 2, 2, 0x000000a000082000ull, 0x000001fe00083000ull, { 23, 22, 50, 0, 0 }, 0x40, 2007, },
+  { 257, 2, 1, 0x000000a000082000ull, 0x000001fe00083000ull, { 23, 50, 0, 0, 0 }, 0x40, 2008, },
+  { 258, 3, 1, 0x00000020d0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 210, },
+  { 259, 2, 2, 0x000000a000002000ull, 0x000001fe00003000ull, { 22, 23, 26, 0, 0 }, 0x0, 3048, },
+  { 259, 2, 1, 0x000000a000002000ull, 0x000001fe00003000ull, { 22, 26, 0, 0, 0 }, 0x40, 3049, },
+  { 259, 2, 2, 0x000000a000002000ull, 0x000001fe00003000ull, { 23, 22, 26, 0, 0 }, 0x40, 2011, },
+  { 259, 2, 1, 0x000000a000002000ull, 0x000001fe00003000ull, { 23, 26, 0, 0, 0 }, 0x40, 2012, },
+  { 260, 3, 1, 0x00000020f0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x8, 211, },
+  { 262, 3, 1, 0x00000020d8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 212, },
+  { 266, 2, 1, 0x000000e840000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1131, },
+  { 267, 2, 1, 0x000000ea40000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1132, },
+  { 268, 2, 1, 0x000000f840000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1133, },
+  { 272, 4, 0, 0x00000000c0000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x28, 223, },
+  { 277, 3, 1, 0x0000008208000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x0, 213, },
+  { 278, 3, 1, 0x0000008248000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x0, 214, },
+  { 279, 3, 1, 0x0000008288000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x0, 215, },
+  { 280, 3, 1, 0x00000082c8000000ull, 0x000001fff8000000ull, { 24, 28, 25, 0, 0 }, 0x0, 216, },
+  { 282, 5, 1, 0x000001d000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 1179, },
+  { 282, 5, 1, 0x000001d000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 1261, },
+  { 283, 5, 1, 0x000001d000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 1180, },
+  { 284, 1, 1, 0x0000010078000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 217, },
+  { 284, 1, 1, 0x0000010178000000ull, 0x000001eff8000000ull, { 24, 56, 26, 0, 0 }, 0x0, 218, },
+  { 287, 2, 1, 0x0000000080000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 219, },
+  { 288, 2, 1, 0x0000000088000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 220, },
+  { 289, 2, 1, 0x0000000090000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 221, },
+};
+
+static const char dis_table[] = {
+0xa0, 0xc7, 0xc8, 0xa0, 0x2e, 0xd8, 0xa0, 0x2c, 0xc0, 0xa0, 0x1c, 0x00,
+0x98, 0xb0, 0x02, 0x50, 0x90, 0x50, 0x90, 0x28, 0x24, 0x39, 0x28, 0x24,
+0x39, 0x20, 0x90, 0x28, 0x24, 0x39, 0x18, 0x24, 0x39, 0x10, 0x91, 0x60,
+0x90, 0x28, 0x24, 0x39, 0x00, 0x10, 0x10, 0x58, 0x41, 0x61, 0xc7, 0xc0,
+0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+0x10, 0x10, 0x52, 0xc0, 0xc0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+0x10, 0x10, 0x10, 0x24, 0x24, 0x70, 0x90, 0x28, 0x24, 0x38, 0xf0, 0x24,
+0x38, 0xe8, 0xa8, 0x0b, 0x48, 0x15, 0x20, 0x97, 0x20, 0x95, 0xc8, 0x9a,
+0xb8, 0x05, 0x38, 0x91, 0x18, 0x90, 0xa0, 0x90, 0x60, 0x80, 0x90, 0x20,
+0x34, 0xa6, 0xa4, 0x25, 0x00, 0x34, 0xa3, 0x80, 0xa4, 0x36, 0xa0, 0x36,
+0xd9, 0x90, 0x50, 0x90, 0x28, 0x80, 0x36, 0xcf, 0x80, 0x34, 0x86, 0x81,
+0x33, 0xe2, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x24, 0x10, 0x34,
+0x83, 0xa4, 0x1f, 0x08, 0x34, 0x80, 0x90, 0x38, 0xa4, 0x38, 0xa0, 0x37,
+0x1a, 0xa4, 0x38, 0x48, 0x37, 0x0e, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x37,
+0x20, 0x36, 0xef, 0xa4, 0x36, 0xf8, 0x36, 0xea, 0x80, 0xa4, 0x23, 0xf0,
+0x34, 0x7f, 0x92, 0x18, 0x91, 0xc0, 0x80, 0x91, 0x80, 0x90, 0xf8, 0xdb,
+0x84, 0x60, 0xf9, 0x40, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x68, 0x8c, 0x43,
+0xc8, 0x84, 0x38, 0x83, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x58, 0x8c, 0x43,
+0xa8, 0x84, 0x38, 0x81, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38,
+0x35, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x33, 0xa4, 0x1f, 0x18, 0x33, 0xe4,
+0x80, 0x90, 0x28, 0x80, 0x33, 0xe0, 0x80, 0x34, 0x88, 0x81, 0x90, 0x38,
+0xa4, 0x24, 0x80, 0x34, 0x8b, 0xa4, 0x24, 0x48, 0x34, 0x85, 0xc0, 0x40,
+0x10, 0x10, 0x90, 0x38, 0xa4, 0x1e, 0xf0, 0x33, 0xdf, 0xa4, 0x1e, 0xe0,
+0x33, 0xdd, 0x18, 0x24, 0x24, 0xf8, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0,
+0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x38, 0x38, 0x6d, 0xc0, 0xc0, 0x80, 0xa4,
+0x42, 0x28, 0x38, 0x69, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38,
+0x2f, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x2d, 0x92, 0xb8, 0x99, 0x84, 0x24,
+0x68, 0x90, 0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x36, 0x98, 0x36,
+0xd8, 0x82, 0x36, 0xce, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x38,
+0x98, 0x37, 0x19, 0xa4, 0x38, 0x40, 0x37, 0x0d, 0x80, 0x90, 0x38, 0xa4,
+0x37, 0x18, 0x36, 0xee, 0xa4, 0x36, 0xf0, 0x36, 0xe9, 0x83, 0x90, 0xa8,
+0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x08, 0x38, 0x61, 0xc0,
+0xc0, 0x80, 0xa4, 0x41, 0xf8, 0x38, 0x5d, 0xd3, 0x82, 0x40, 0x50, 0xc0,
+0xc0, 0x81, 0x38, 0x29, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x27, 0x18, 0x24,
+0x24, 0x78, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4,
+0x41, 0xd8, 0x38, 0x55, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0xc8, 0x38, 0x51,
+0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x23, 0x50, 0xc0, 0xc0,
+0x81, 0x38, 0x21, 0x94, 0x50, 0x92, 0xf8, 0x99, 0x84, 0x1f, 0x48, 0x90,
+0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x36, 0x90, 0x36, 0xd7, 0x82,
+0x36, 0xcd, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x38, 0x90, 0x37,
+0x18, 0xa4, 0x38, 0x38, 0x37, 0x0c, 0x80, 0x90, 0x38, 0xa4, 0x37, 0x10,
+0x36, 0xed, 0xa4, 0x36, 0xe8, 0x36, 0xe8, 0x83, 0x90, 0xe8, 0xd3, 0x83,
+0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x78, 0x8c, 0x43, 0xe8, 0x84, 0x38,
+0x85, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x60, 0x8c, 0x43, 0xb8, 0x84, 0x38,
+0x82, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x37, 0x50, 0xc0,
+0xc0, 0x81, 0x38, 0x34, 0x18, 0x24, 0x1f, 0x40, 0x83, 0x90, 0xa8, 0xd3,
+0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x48, 0x38, 0x71, 0xc0, 0xc0,
+0x80, 0xa4, 0x42, 0x30, 0x38, 0x6b, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0,
+0x81, 0x38, 0x31, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x2e, 0x92, 0xb8, 0x99,
+0x84, 0x1f, 0x38, 0x90, 0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x36,
+0x88, 0x36, 0xd6, 0x82, 0x36, 0xcc, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38,
+0xa4, 0x38, 0x88, 0x37, 0x17, 0xa4, 0x38, 0x30, 0x37, 0x0b, 0x80, 0x90,
+0x38, 0xa4, 0x37, 0x08, 0x36, 0xec, 0xa4, 0x36, 0xe0, 0x36, 0xe7, 0x83,
+0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x18, 0x38,
+0x65, 0xc0, 0xc0, 0x80, 0xa4, 0x42, 0x00, 0x38, 0x5f, 0xd3, 0x82, 0x40,
+0x50, 0xc0, 0xc0, 0x81, 0x38, 0x2b, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x28,
+0x18, 0x20, 0x01, 0x48, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0,
+0x80, 0xa4, 0x41, 0xe8, 0x38, 0x59, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0xd0,
+0x38, 0x53, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x25, 0x50,
+0xc0, 0xc0, 0x81, 0x38, 0x22, 0xda, 0x06, 0xe0, 0xf9, 0x80, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x24, 0xe8, 0x34, 0x9b, 0x80, 0x34, 0x98, 0x90, 0x38,
+0xa4, 0x24, 0x90, 0x34, 0x96, 0x80, 0x34, 0x93, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x24, 0xd0, 0x34, 0x9c, 0x80, 0x34, 0x99, 0x90, 0x38, 0xa4, 0x24,
+0xa8, 0x34, 0x97, 0x80, 0x34, 0x94, 0xc8, 0x40, 0x19, 0x00, 0x91, 0x58,
+0x90, 0x60, 0x82, 0x90, 0x20, 0x36, 0xcb, 0xa4, 0x36, 0x48, 0x36, 0xca,
+0x90, 0xc0, 0x80, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, 0xc1, 0x00, 0x85,
+0x37, 0x03, 0xc9, 0xe1, 0xc0, 0x40, 0x85, 0x37, 0x00, 0x80, 0x36, 0xff,
+0x10, 0x10, 0x81, 0x36, 0xdb, 0x90, 0xa8, 0x10, 0x10, 0x90, 0x28, 0x81,
+0x36, 0xf9, 0x90, 0x38, 0xa4, 0x37, 0xa0, 0x36, 0xf5, 0xa4, 0x37, 0x90,
+0x36, 0xf3, 0x90, 0x70, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x37, 0xb8, 0x36,
+0xf8, 0x80, 0x36, 0xf6, 0x90, 0x60, 0x90, 0x28, 0x24, 0x37, 0xf0, 0xa4,
+0x37, 0xe0, 0x36, 0xfd, 0x80, 0xa4, 0x37, 0xd0, 0x36, 0xfb, 0x80, 0x90,
+0xf8, 0x90, 0x90, 0x90, 0x50, 0x90, 0x28, 0x80, 0x38, 0x17, 0x80, 0x38,
+0x20, 0x80, 0xa4, 0x40, 0xf0, 0x38, 0x1f, 0x90, 0x28, 0x81, 0x38, 0x1d,
+0x80, 0xa4, 0x40, 0xd8, 0x38, 0x1c, 0x90, 0x28, 0x82, 0x38, 0x1a, 0x81,
+0xa4, 0x40, 0xc0, 0x38, 0x19, 0x98, 0xe8, 0x01, 0xb0, 0x90, 0x88, 0x90,
+0x60, 0xa4, 0x36, 0x38, 0x10, 0x10, 0x10, 0x10, 0x83, 0x33, 0xb7, 0x24,
+0x36, 0x30, 0x90, 0x28, 0x24, 0x36, 0x28, 0x24, 0x36, 0x20, 0x90, 0x88,
+0x90, 0x60, 0xa4, 0x36, 0x10, 0x10, 0x10, 0x10, 0x10, 0x83, 0x33, 0xb6,
+0x24, 0x36, 0x08, 0x90, 0x28, 0x24, 0x36, 0x00, 0x24, 0x35, 0xf8, 0xa8,
+0x09, 0x00, 0x0e, 0x20, 0x96, 0x48, 0x95, 0xe8, 0x93, 0x38, 0x91, 0xa0,
+0x90, 0xd0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x1e, 0x60, 0x33, 0xcd, 0xa4,
+0x1e, 0x50, 0x33, 0xcb, 0x90, 0x38, 0xa4, 0x1e, 0x40, 0x33, 0xc9, 0x80,
+0x33, 0xc7, 0x90, 0x60, 0x90, 0x28, 0x24, 0x1e, 0x00, 0xa4, 0x1d, 0xf0,
+0x33, 0xbf, 0x90, 0x38, 0xa4, 0x1d, 0xe0, 0x33, 0xbd, 0xa4, 0x1e, 0x28,
+0x33, 0xc6, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x1e, 0x18, 0x33,
+0xc4, 0xa4, 0x1e, 0x08, 0x33, 0xc2, 0x90, 0x38, 0xa4, 0x35, 0xb0, 0x36,
+0xbc, 0xa4, 0x35, 0x50, 0x36, 0xb0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x32,
+0x90, 0x36, 0x5e, 0xa4, 0x32, 0x60, 0x36, 0x58, 0x10, 0x10, 0xa4, 0x1d,
+0xd0, 0x33, 0xbb, 0x99, 0x60, 0x02, 0x70, 0x90, 0x90, 0x90, 0x50, 0x90,
+0x28, 0x24, 0x1e, 0x90, 0x80, 0x33, 0xda, 0x80, 0xa4, 0x1e, 0x98, 0x33,
+0xd8, 0x90, 0x50, 0x90, 0x28, 0x24, 0x1e, 0xa0, 0x80, 0x33, 0xdb, 0x90,
+0x38, 0xa4, 0x1e, 0xa8, 0x33, 0xd9, 0xa4, 0x1e, 0x70, 0x33, 0xcf, 0x90,
+0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xe8, 0x36, 0xa5, 0xa4, 0x34,
+0x48, 0x36, 0x92, 0x90, 0x38, 0xa4, 0x33, 0xe0, 0x36, 0x83, 0xa4, 0x33,
+0x50, 0x36, 0x72, 0x81, 0xa4, 0x1e, 0x80, 0x33, 0xd1, 0xe4, 0xa2, 0x04,
+0x40, 0x38, 0x13, 0x18, 0x24, 0x1d, 0xc8, 0xe4, 0xe2, 0x02, 0xc0, 0x38,
+0x0d, 0x92, 0x40, 0x91, 0x08, 0x10, 0x10, 0x90, 0x80, 0x10, 0x10, 0x90,
+0x38, 0xa4, 0x35, 0xa8, 0x36, 0xbb, 0xa4, 0x35, 0x48, 0x36, 0xaf, 0x80,
+0x90, 0x38, 0xa4, 0x32, 0x88, 0x36, 0x5d, 0xa4, 0x32, 0x58, 0x36, 0x57,
+0x18, 0x20, 0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xd8,
+0x36, 0xa4, 0xa4, 0x34, 0x40, 0x36, 0x90, 0x90, 0x38, 0xa4, 0x33, 0xd0,
+0x36, 0x82, 0xa4, 0x33, 0x48, 0x36, 0x70, 0xe4, 0xa2, 0x01, 0x40, 0x38,
+0x07, 0x18, 0x24, 0x1d, 0xc0, 0xe4, 0xe1, 0xff, 0xc0, 0x38, 0x01, 0x92,
+0x90, 0x92, 0x40, 0x91, 0x08, 0x10, 0x10, 0x90, 0x80, 0x10, 0x10, 0x90,
+0x38, 0xa4, 0x35, 0xa0, 0x36, 0xba, 0xa4, 0x35, 0x40, 0x36, 0xae, 0x80,
+0x90, 0x38, 0xa4, 0x32, 0x80, 0x36, 0x5c, 0xa4, 0x32, 0x50, 0x36, 0x56,
+0x18, 0x20, 0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xc8,
+0x36, 0xa3, 0xa4, 0x34, 0x38, 0x36, 0x8e, 0x90, 0x38, 0xa4, 0x33, 0xc0,
+0x36, 0x81, 0xa4, 0x33, 0x40, 0x36, 0x6e, 0xe4, 0xa2, 0x04, 0x80, 0x38,
+0x15, 0x10, 0x10, 0xe4, 0xe2, 0x03, 0x00, 0x38, 0x0f, 0x92, 0x50, 0x99,
+0x1c, 0x1e, 0xb0, 0x10, 0x10, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4,
+0x35, 0x98, 0x36, 0xb9, 0xa4, 0x35, 0x38, 0x36, 0xad, 0x80, 0x90, 0x38,
+0xa4, 0x32, 0x78, 0x36, 0x5b, 0xa4, 0x32, 0x48, 0x36, 0x55, 0x18, 0x20,
+0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xb8, 0x36, 0xa2,
+0xa4, 0x34, 0x30, 0x36, 0x8c, 0x90, 0x38, 0xa4, 0x33, 0xb0, 0x36, 0x80,
+0xa4, 0x33, 0x38, 0x36, 0x6c, 0xe4, 0xa2, 0x01, 0x80, 0x38, 0x09, 0x10,
+0x10, 0xe4, 0xe2, 0x00, 0x00, 0x38, 0x03, 0xc0, 0x40, 0x80, 0x10, 0x10,
+0x81, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, 0x98, 0x80, 0x85, 0x36, 0x66,
+0xc9, 0xe1, 0x99, 0x00, 0x85, 0x36, 0x63, 0x80, 0x36, 0x61, 0x80, 0xd8,
+0x47, 0x80, 0x0d, 0xc0, 0xc0, 0x80, 0x10, 0x10, 0x82, 0x90, 0x58, 0xd5,
+0x81, 0x80, 0x80, 0x37, 0xfd, 0x80, 0x37, 0xfb, 0xd5, 0x81, 0x80, 0x80,
+0x37, 0xf9, 0x80, 0x37, 0xf7, 0xc0, 0x80, 0x10, 0x10, 0x82, 0x90, 0x58,
+0xd5, 0x81, 0x80, 0x80, 0x37, 0xfe, 0x80, 0x37, 0xfc, 0xd5, 0x81, 0x80,
+0x80, 0x37, 0xfa, 0x80, 0x37, 0xf8, 0xc0, 0x80, 0x83, 0xa4, 0x3f, 0xa8,
+0x37, 0xf6, 0xa0, 0x59, 0x60, 0xa0, 0x41, 0xe0, 0xa8, 0x1e, 0xb0, 0x34,
+0x88, 0xa0, 0x12, 0x38, 0xa0, 0x0b, 0x48, 0x96, 0x00, 0x9a, 0xf0, 0x05,
+0xc0, 0x91, 0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x15, 0x58,
+0x33, 0xb5, 0xa4, 0x15, 0x78, 0x33, 0xb4, 0x10, 0x10, 0xa4, 0x15, 0x68,
+0x33, 0xb3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0xf8, 0x33, 0x9a, 0xa4,
+0x15, 0x18, 0x33, 0x99, 0x10, 0x10, 0xa4, 0x15, 0x08, 0x33, 0x98, 0x90,
+0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x98, 0x33, 0x7f, 0xa4, 0x14,
+0xb8, 0x33, 0x7e, 0x10, 0x10, 0xa4, 0x14, 0xa8, 0x33, 0x7d, 0x90, 0x70,
+0x90, 0x38, 0xa4, 0x14, 0x38, 0x33, 0x63, 0xa4, 0x14, 0x58, 0x33, 0x62,
+0x10, 0x10, 0xa4, 0x14, 0x48, 0x33, 0x61, 0x91, 0x70, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x15, 0x28, 0x33, 0xb0, 0xa4, 0x15, 0x48, 0x33,
+0xb2, 0x10, 0x10, 0xa4, 0x15, 0x38, 0x33, 0xb1, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x14, 0xc8, 0x33, 0x95, 0xa4, 0x14, 0xe8, 0x33, 0x97, 0x10, 0x10,
+0xa4, 0x14, 0xd8, 0x33, 0x96, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4,
+0x14, 0x68, 0x33, 0x7a, 0xa4, 0x14, 0x88, 0x33, 0x7c, 0x10, 0x10, 0xa4,
+0x14, 0x78, 0x33, 0x7b, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x08, 0x33,
+0x5e, 0xa4, 0x14, 0x28, 0x33, 0x60, 0x10, 0x10, 0xa4, 0x14, 0x18, 0x33,
+0x5f, 0xe4, 0xe1, 0x8b, 0x40, 0x36, 0x41, 0x9a, 0xf0, 0x05, 0x00, 0x91,
+0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xa0, 0x33, 0xad,
+0xa4, 0x13, 0x98, 0x33, 0xaf, 0x10, 0x10, 0xa4, 0x13, 0x90, 0x33, 0xae,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x88, 0x33, 0x92, 0xa4, 0x13, 0x80,
+0x33, 0x94, 0x10, 0x10, 0xa4, 0x13, 0x78, 0x33, 0x93, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x13, 0x70, 0x33, 0x77, 0xa4, 0x13, 0x68, 0x33,
+0x79, 0x10, 0x10, 0xa4, 0x13, 0x60, 0x33, 0x78, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x13, 0x58, 0x33, 0x5b, 0xa4, 0x13, 0x50, 0x33, 0x5d, 0x10, 0x10,
+0xa4, 0x13, 0x48, 0x33, 0x5c, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x33, 0xaa, 0x80, 0x33, 0xac, 0x10, 0x10, 0x80, 0x33, 0xab,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x8f, 0x80, 0x33, 0x91, 0x10, 0x10,
+0x80, 0x33, 0x90, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x74,
+0x80, 0x33, 0x76, 0x10, 0x10, 0x80, 0x33, 0x75, 0x90, 0x50, 0x90, 0x28,
+0x80, 0x33, 0x58, 0x80, 0x33, 0x5a, 0x10, 0x10, 0x80, 0x33, 0x59, 0xe4,
+0xe1, 0x66, 0x40, 0x35, 0xc1, 0x95, 0x40, 0x9a, 0x90, 0x05, 0x00, 0x91,
+0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xa7, 0x80, 0x33,
+0xa9, 0x10, 0x10, 0x80, 0x33, 0xa8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33,
+0x8c, 0x80, 0x33, 0x8e, 0x10, 0x10, 0x80, 0x33, 0x8d, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x13, 0x30, 0x33, 0x71, 0xa4, 0x13, 0x40, 0x33,
+0x73, 0x10, 0x10, 0xa4, 0x13, 0x38, 0x33, 0x72, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x13, 0x00, 0x33, 0x55, 0xa4, 0x13, 0x10, 0x33, 0x57, 0x10, 0x10,
+0xa4, 0x13, 0x08, 0x33, 0x56, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x33, 0xa4, 0x80, 0x33, 0xa6, 0x10, 0x10, 0x80, 0x33, 0xa5,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x89, 0x80, 0x33, 0x8b, 0x10, 0x10,
+0x80, 0x33, 0x8a, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x18,
+0x33, 0x6e, 0xa4, 0x13, 0x28, 0x33, 0x70, 0x10, 0x10, 0xa4, 0x13, 0x20,
+0x33, 0x6f, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0xe8, 0x33, 0x52, 0xa4,
+0x12, 0xf8, 0x33, 0x54, 0x10, 0x10, 0xa4, 0x12, 0xf0, 0x33, 0x53, 0xe4,
+0xe1, 0x8a, 0x40, 0x36, 0x3d, 0x98, 0xb8, 0x01, 0x68, 0x10, 0x10, 0x10,
+0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x4f, 0x80, 0x33, 0x51, 0x10,
+0x10, 0x80, 0x33, 0x50, 0x90, 0x60, 0x90, 0x30, 0x60, 0xa0, 0x97, 0x00,
+0x60, 0xa0, 0x96, 0xc0, 0x90, 0x30, 0x60, 0xa0, 0x96, 0x80, 0x60, 0xa0,
+0x96, 0x40, 0xe4, 0xe1, 0x64, 0x40, 0x35, 0xb9, 0xa0, 0x08, 0x08, 0x94,
+0xe0, 0x9a, 0x60, 0x04, 0xa0, 0x91, 0x40, 0x90, 0xb8, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x13, 0xd8, 0x33, 0x9e, 0xa4, 0x13, 0xf8, 0x33, 0xa3, 0x10,
+0x10, 0xa4, 0x13, 0xe8, 0x33, 0xa2, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33,
+0x83, 0x80, 0x33, 0x88, 0x10, 0x10, 0x80, 0x33, 0x87, 0x90, 0x88, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x68, 0x80, 0x33, 0x6d, 0x10, 0x10, 0x80,
+0x33, 0x6c, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x49, 0x80, 0x33, 0x4e,
+0x10, 0x10, 0x80, 0x33, 0x4d, 0x91, 0x40, 0x90, 0xb8, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x13, 0xa8, 0x33, 0x9b, 0xa4, 0x13, 0xc8, 0x33, 0x9d, 0x10,
+0x10, 0xa4, 0x13, 0xb8, 0x33, 0x9c, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33,
+0x80, 0x80, 0x33, 0x82, 0x10, 0x10, 0x80, 0x33, 0x81, 0x90, 0x88, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x65, 0x80, 0x33, 0x67, 0x10, 0x10, 0x80,
+0x33, 0x66, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x46, 0x80, 0x33, 0x48,
+0x10, 0x10, 0x80, 0x33, 0x47, 0xe4, 0xe1, 0x89, 0x40, 0x36, 0x39, 0x9a,
+0x60, 0x02, 0xe0, 0x91, 0x40, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4,
+0x1a, 0x20, 0x33, 0x9f, 0xa4, 0x1a, 0x10, 0x33, 0xa1, 0x10, 0x10, 0xa4,
+0x1a, 0x00, 0x33, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x84, 0x80,
+0x33, 0x86, 0x10, 0x10, 0x80, 0x33, 0x85, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x33, 0x69, 0x80, 0x33, 0x6b, 0x10, 0x10, 0x80, 0x33, 0x6a,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x4a, 0x80, 0x33, 0x4c, 0x10, 0x10,
+0x80, 0x33, 0x4b, 0x81, 0x90, 0x50, 0x90, 0x28, 0x24, 0x19, 0xd0, 0x24,
+0x19, 0xf0, 0x10, 0x10, 0x24, 0x19, 0xe0, 0xe4, 0xe1, 0x62, 0x40, 0x35,
+0xb1, 0x93, 0x90, 0x99, 0xb8, 0x03, 0x50, 0x90, 0xe8, 0x90, 0x88, 0x90,
+0x40, 0x80, 0xa4, 0x15, 0xb8, 0x32, 0xca, 0x10, 0x10, 0xa4, 0x15, 0xa8,
+0x32, 0xc9, 0x90, 0x28, 0x81, 0x32, 0xc6, 0x10, 0x10, 0x80, 0x32, 0xc5,
+0x90, 0x60, 0x90, 0x28, 0x81, 0x32, 0xc2, 0x10, 0x10, 0x80, 0x32, 0xc1,
+0x90, 0x28, 0x81, 0x32, 0xbe, 0x10, 0x10, 0x80, 0x32, 0xbd, 0x90, 0xe8,
+0x90, 0x88, 0x90, 0x40, 0x80, 0xa4, 0x15, 0x88, 0x32, 0xc7, 0x10, 0x10,
+0xa4, 0x15, 0x98, 0x32, 0xc8, 0x90, 0x28, 0x81, 0x32, 0xc3, 0x10, 0x10,
+0x80, 0x32, 0xc4, 0x90, 0x60, 0x90, 0x28, 0x81, 0x32, 0xbf, 0x10, 0x10,
+0x80, 0x32, 0xc0, 0x90, 0x28, 0x81, 0x32, 0xbb, 0x10, 0x10, 0x80, 0x32,
+0xbc, 0xe4, 0xe1, 0x88, 0x40, 0x36, 0x35, 0x88, 0x00, 0x88, 0x10, 0x10,
+0x10, 0x10, 0x90, 0x28, 0x81, 0x32, 0xb9, 0x10, 0x10, 0x80, 0x32, 0xba,
+0xe4, 0xe1, 0x60, 0x40, 0x35, 0xa9, 0xa0, 0x0e, 0x80, 0xa0, 0x09, 0x08,
+0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x33, 0x39, 0x80, 0x33, 0x38, 0x10, 0x10, 0x80, 0x33,
+0x37, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x1e, 0x80, 0x33, 0x1d, 0x10,
+0x10, 0x80, 0x33, 0x1c, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33,
+0x03, 0x80, 0x33, 0x02, 0x10, 0x10, 0x80, 0x33, 0x01, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x32, 0xe8, 0x80, 0x32, 0xe7, 0x10, 0x10, 0x80, 0x32, 0xe6,
+0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x34, 0x80,
+0x33, 0x36, 0x10, 0x10, 0x80, 0x33, 0x35, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x33, 0x19, 0x80, 0x33, 0x1b, 0x10, 0x10, 0x80, 0x33, 0x1a, 0x90, 0x88,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xfe, 0x80, 0x33, 0x00, 0x10, 0x10,
+0x80, 0x32, 0xff, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xe3, 0x80, 0x32,
+0xe5, 0x10, 0x10, 0x80, 0x32, 0xe4, 0xe4, 0xe1, 0x7a, 0x40, 0x36, 0x11,
+0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28,
+0x80, 0x33, 0x31, 0x80, 0x33, 0x33, 0x10, 0x10, 0x80, 0x33, 0x32, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x16, 0x80, 0x33, 0x18, 0x10, 0x10, 0x80,
+0x33, 0x17, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xfb, 0x80,
+0x32, 0xfd, 0x10, 0x10, 0x80, 0x32, 0xfc, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x32, 0xe0, 0x80, 0x32, 0xe2, 0x10, 0x10, 0x80, 0x32, 0xe1, 0x91, 0x10,
+0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x2e, 0x80, 0x33, 0x30,
+0x10, 0x10, 0x80, 0x33, 0x2f, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x13,
+0x80, 0x33, 0x15, 0x10, 0x10, 0x80, 0x33, 0x14, 0x90, 0x88, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x32, 0xf8, 0x80, 0x32, 0xfa, 0x10, 0x10, 0x80, 0x32,
+0xf9, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xdd, 0x80, 0x32, 0xdf, 0x10,
+0x10, 0x80, 0x32, 0xde, 0xe4, 0xe1, 0x59, 0x40, 0x35, 0x79, 0x94, 0x80,
+0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28,
+0x80, 0x33, 0x2b, 0x80, 0x33, 0x2d, 0x10, 0x10, 0x80, 0x33, 0x2c, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x10, 0x80, 0x33, 0x12, 0x10, 0x10, 0x80,
+0x33, 0x11, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xf5, 0x80,
+0x32, 0xf7, 0x10, 0x10, 0x80, 0x32, 0xf6, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x32, 0xda, 0x80, 0x32, 0xdc, 0x10, 0x10, 0x80, 0x32, 0xdb, 0x91, 0x10,
+0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x28, 0x80, 0x33, 0x2a,
+0x10, 0x10, 0x80, 0x33, 0x29, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x0d,
+0x80, 0x33, 0x0f, 0x10, 0x10, 0x80, 0x33, 0x0e, 0x90, 0x88, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x32, 0xf2, 0x80, 0x32, 0xf4, 0x10, 0x10, 0x80, 0x32,
+0xf3, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xd7, 0x80, 0x32, 0xd9, 0x10,
+0x10, 0x80, 0x32, 0xd8, 0xe4, 0xe1, 0x78, 0x40, 0x36, 0x09, 0x88, 0x00,
+0xb0, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xd4,
+0x80, 0x32, 0xd6, 0x10, 0x10, 0x80, 0x32, 0xd5, 0xe4, 0xe1, 0x58, 0x40,
+0x35, 0x75, 0x96, 0xe8, 0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10,
+0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x22, 0x80, 0x33, 0x27,
+0x10, 0x10, 0x80, 0x33, 0x26, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x07,
+0x80, 0x33, 0x0c, 0x10, 0x10, 0x80, 0x33, 0x0b, 0x90, 0x88, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x32, 0xec, 0x80, 0x32, 0xf1, 0x10, 0x10, 0x80, 0x32,
+0xf0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xce, 0x80, 0x32, 0xd3, 0x10,
+0x10, 0x80, 0x32, 0xd2, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28,
+0x80, 0x33, 0x1f, 0x80, 0x33, 0x21, 0x10, 0x10, 0x80, 0x33, 0x20, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x04, 0x80, 0x33, 0x06, 0x10, 0x10, 0x80,
+0x33, 0x05, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xe9, 0x80,
+0x32, 0xeb, 0x10, 0x10, 0x80, 0x32, 0xea, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x32, 0xcb, 0x80, 0x32, 0xcd, 0x10, 0x10, 0x80, 0x32, 0xcc, 0xe4, 0xe1,
+0x76, 0x40, 0x36, 0x01, 0x88, 0x02, 0x28, 0x91, 0x10, 0x90, 0x88, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x33, 0x23, 0x80, 0x33, 0x25, 0x10, 0x10, 0x80,
+0x33, 0x24, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x08, 0x80, 0x33, 0x0a,
+0x10, 0x10, 0x80, 0x33, 0x09, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x32, 0xed, 0x80, 0x32, 0xef, 0x10, 0x10, 0x80, 0x32, 0xee, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x32, 0xcf, 0x80, 0x32, 0xd1, 0x10, 0x10, 0x80, 0x32,
+0xd0, 0xe4, 0xe1, 0x57, 0x40, 0x35, 0x71, 0x90, 0x40, 0xe5, 0x21, 0x74,
+0x40, 0x35, 0xf9, 0xe5, 0x21, 0x56, 0x40, 0x35, 0x6d, 0x9e, 0xb4, 0x23,
+0xe8, 0x93, 0x70, 0x91, 0xd8, 0xd5, 0x07, 0x80, 0xd0, 0xc4, 0x40, 0x90,
+0x48, 0x80, 0x8c, 0x3f, 0x38, 0x84, 0x37, 0xf1, 0xa4, 0x3d, 0x18, 0x37,
+0xbb, 0x90, 0x28, 0x24, 0x3c, 0x58, 0xa4, 0x3a, 0xd8, 0x37, 0x73, 0xd0,
+0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x3f, 0x18, 0x84, 0x37, 0xef, 0xa4,
+0x3d, 0x08, 0x37, 0xb9, 0x90, 0x28, 0x24, 0x3c, 0x48, 0xa4, 0x3a, 0xc8,
+0x37, 0x71, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37,
+0xdb, 0xa4, 0x3c, 0xe8, 0x37, 0xb5, 0x90, 0x28, 0x24, 0x3c, 0x28, 0xa4,
+0x3a, 0xa8, 0x37, 0x6d, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xd7,
+0xa4, 0x3c, 0xd8, 0x37, 0xb3, 0x90, 0x28, 0x24, 0x3c, 0x18, 0xa4, 0x3a,
+0x98, 0x37, 0x6b, 0x91, 0x98, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90,
+0x28, 0x80, 0x37, 0xcf, 0xa4, 0x3c, 0xb8, 0x37, 0xaf, 0x90, 0x28, 0x24,
+0x3b, 0xf8, 0xa4, 0x3a, 0x78, 0x37, 0x67, 0xd0, 0xc3, 0x40, 0x90, 0x28,
+0x80, 0x37, 0xcb, 0xa4, 0x3c, 0xa8, 0x37, 0xad, 0x90, 0x28, 0x24, 0x3b,
+0xe8, 0xa4, 0x3a, 0x68, 0x37, 0x65, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40,
+0x90, 0x28, 0x80, 0x37, 0xc3, 0xa4, 0x3c, 0x88, 0x37, 0xa9, 0x90, 0x28,
+0x24, 0x3b, 0xc8, 0xa4, 0x3a, 0x48, 0x37, 0x61, 0xd0, 0xc3, 0x40, 0x90,
+0x28, 0x80, 0x37, 0xbf, 0xa4, 0x3c, 0x78, 0x37, 0xa7, 0x90, 0x28, 0x24,
+0x3b, 0xb8, 0xa4, 0x3a, 0x38, 0x37, 0x5f, 0x93, 0x70, 0x91, 0xd8, 0xd5,
+0x07, 0x80, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x3f, 0x58, 0x84,
+0x37, 0xf3, 0xa4, 0x3d, 0x28, 0x37, 0xbd, 0x90, 0x28, 0x24, 0x3c, 0x68,
+0xa4, 0x3a, 0xe8, 0x37, 0x75, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c,
+0x3f, 0x28, 0x84, 0x37, 0xf0, 0xa4, 0x3d, 0x10, 0x37, 0xba, 0x90, 0x28,
+0x24, 0x3c, 0x50, 0xa4, 0x3a, 0xd0, 0x37, 0x72, 0xd5, 0x06, 0x80, 0xd0,
+0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xdf, 0xa4, 0x3c, 0xf8, 0x37, 0xb7,
+0x90, 0x28, 0x24, 0x3c, 0x38, 0xa4, 0x3a, 0xb8, 0x37, 0x6f, 0xd0, 0xc3,
+0x40, 0x90, 0x28, 0x80, 0x37, 0xd9, 0xa4, 0x3c, 0xe0, 0x37, 0xb4, 0x90,
+0x28, 0x24, 0x3c, 0x20, 0xa4, 0x3a, 0xa0, 0x37, 0x6c, 0x91, 0x98, 0xd5,
+0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xd3, 0xa4, 0x3c,
+0xc8, 0x37, 0xb1, 0x90, 0x28, 0x24, 0x3c, 0x08, 0xa4, 0x3a, 0x88, 0x37,
+0x69, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xcd, 0xa4, 0x3c, 0xb0,
+0x37, 0xae, 0x90, 0x28, 0x24, 0x3b, 0xf0, 0xa4, 0x3a, 0x70, 0x37, 0x66,
+0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xc7, 0xa4,
+0x3c, 0x98, 0x37, 0xab, 0x90, 0x28, 0x24, 0x3b, 0xd8, 0xa4, 0x3a, 0x58,
+0x37, 0x63, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xc1, 0xa4, 0x3c,
+0x80, 0x37, 0xa8, 0x90, 0x28, 0x24, 0x3b, 0xc0, 0xa4, 0x3a, 0x40, 0x37,
+0x60, 0x99, 0xd8, 0x03, 0x90, 0x81, 0x90, 0xe0, 0x5b, 0x41, 0x40, 0x03,
+0x40, 0x51, 0x40, 0xc0, 0xa4, 0x23, 0x80, 0x34, 0x60, 0xd1, 0x42, 0x00,
+0xa4, 0x22, 0x80, 0x34, 0x40, 0xa4, 0x21, 0x80, 0x34, 0x20, 0x5b, 0x41,
+0x40, 0x03, 0x40, 0x51, 0x40, 0xc0, 0xa4, 0x22, 0xa0, 0x34, 0x64, 0xd1,
+0x42, 0x00, 0xa4, 0x21, 0xa0, 0x34, 0x44, 0xa4, 0x20, 0xa0, 0x34, 0x24,
+0x81, 0x90, 0xe0, 0x5b, 0x41, 0x40, 0x03, 0x40, 0x51, 0x40, 0xc0, 0xa4,
+0x22, 0xe0, 0x34, 0x6c, 0xd1, 0x42, 0x00, 0xa4, 0x21, 0xe0, 0x34, 0x4c,
+0xa4, 0x20, 0xe0, 0x34, 0x2c, 0x5b, 0x41, 0x40, 0x03, 0x40, 0x51, 0x40,
+0xc0, 0xa4, 0x22, 0xc0, 0x34, 0x68, 0xd1, 0x42, 0x00, 0xa4, 0x21, 0xc0,
+0x34, 0x48, 0xa4, 0x20, 0xc0, 0x34, 0x28, 0xa8, 0x0b, 0x18, 0x13, 0xa8,
+0x96, 0x80, 0x93, 0x40, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x12, 0xb8, 0x32, 0x58, 0x24, 0x12, 0xb0, 0x90, 0x38,
+0xa4, 0x11, 0xe0, 0x32, 0x3d, 0x24, 0x11, 0xd8, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x11, 0x08, 0x32, 0x22, 0x24, 0x11, 0x00, 0x90, 0x38, 0xa4, 0x10,
+0x30, 0x32, 0x07, 0x24, 0x10, 0x28, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x12, 0xa8, 0x32, 0x53, 0x24, 0x12, 0xa0, 0x90, 0x38, 0xa4, 0x11,
+0xd0, 0x32, 0x38, 0x24, 0x11, 0xc8, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10,
+0xf8, 0x32, 0x1d, 0x24, 0x10, 0xf0, 0x90, 0x38, 0xa4, 0x10, 0x20, 0x32,
+0x02, 0x24, 0x10, 0x18, 0xe4, 0xe1, 0xd0, 0x40, 0x37, 0x43, 0x99, 0x90,
+0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x90, 0x32,
+0x50, 0x24, 0x12, 0x88, 0x90, 0x38, 0xa4, 0x11, 0xb8, 0x32, 0x35, 0x24,
+0x11, 0xb0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0xe0, 0x32, 0x1a, 0x24,
+0x10, 0xd8, 0x90, 0x38, 0xa4, 0x10, 0x08, 0x31, 0xff, 0x24, 0x10, 0x00,
+0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x78, 0x32, 0x4d, 0x24,
+0x12, 0x70, 0x90, 0x38, 0xa4, 0x11, 0xa0, 0x32, 0x32, 0x24, 0x11, 0x98,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0xc8, 0x32, 0x17, 0x24, 0x10, 0xc0,
+0x90, 0x38, 0xa4, 0x0f, 0xf0, 0x31, 0xfc, 0x24, 0x0f, 0xe8, 0xe4, 0xe1,
+0xce, 0xc0, 0x37, 0x3d, 0x93, 0x78, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x60, 0x32, 0x4a, 0x24, 0x12, 0x58,
+0x90, 0x38, 0xa4, 0x11, 0x88, 0x32, 0x2f, 0x24, 0x11, 0x80, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x10, 0xb0, 0x32, 0x14, 0x24, 0x10, 0xa8, 0x90, 0x38,
+0xa4, 0x0f, 0xd8, 0x31, 0xf9, 0x24, 0x0f, 0xd0, 0x90, 0xc0, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x12, 0x48, 0x32, 0x47, 0x24, 0x12, 0x40, 0x90, 0x38,
+0xa4, 0x11, 0x70, 0x32, 0x2c, 0x24, 0x11, 0x68, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x10, 0x98, 0x32, 0x11, 0x24, 0x10, 0x90, 0x90, 0x38, 0xa4, 0x0f,
+0xc0, 0x31, 0xf6, 0x24, 0x0f, 0xb8, 0xec, 0xa1, 0x1e, 0x00, 0x02, 0x00,
+0x34, 0x7a, 0xa4, 0x39, 0xa8, 0x37, 0x37, 0x88, 0x00, 0x88, 0x10, 0x10,
+0x10, 0x10, 0x90, 0x38, 0xa4, 0x0f, 0xa8, 0x31, 0xf3, 0x24, 0x0f, 0xa0,
+0xe9, 0x61, 0x1d, 0x40, 0x02, 0x00, 0x34, 0x76, 0xe3, 0x61, 0xcb, 0xc0,
+0x37, 0x31, 0x95, 0x08, 0x93, 0x40, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x30, 0x32, 0x41, 0x24, 0x12, 0x28,
+0x90, 0x38, 0xa4, 0x11, 0x58, 0x32, 0x26, 0x24, 0x11, 0x50, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x10, 0x80, 0x32, 0x0b, 0x24, 0x10, 0x78, 0x90, 0x38,
+0xa4, 0x0f, 0x90, 0x31, 0xed, 0x24, 0x0f, 0x88, 0x90, 0xc0, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x12, 0x00, 0x32, 0x3e, 0x24, 0x11, 0xf8, 0x90, 0x38,
+0xa4, 0x11, 0x28, 0x32, 0x23, 0x24, 0x11, 0x20, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x10, 0x50, 0x32, 0x08, 0x24, 0x10, 0x48, 0x90, 0x38, 0xa4, 0x0f,
+0x60, 0x31, 0xea, 0x24, 0x0f, 0x58, 0xe4, 0xe1, 0xd0, 0x80, 0x37, 0x45,
+0x88, 0x01, 0x88, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x20,
+0x32, 0x42, 0x24, 0x12, 0x18, 0x90, 0x38, 0xa4, 0x11, 0x48, 0x32, 0x27,
+0x24, 0x11, 0x40, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0x70, 0x32, 0x0c,
+0x24, 0x10, 0x68, 0x90, 0x38, 0xa4, 0x0f, 0x80, 0x31, 0xee, 0x24, 0x0f,
+0x78, 0xe4, 0xe1, 0xcf, 0x00, 0x37, 0x3f, 0x92, 0xd0, 0x99, 0x50, 0x02,
+0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xe9, 0x24, 0x0f,
+0x40, 0x90, 0x28, 0x80, 0x31, 0xe5, 0x24, 0x0f, 0x20, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x31, 0xe1, 0x24, 0x0f, 0x00, 0x90, 0x28, 0x80, 0x31, 0xdd,
+0x24, 0x0e, 0xe0, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xe6,
+0x24, 0x0f, 0x38, 0x90, 0x28, 0x80, 0x31, 0xe2, 0x24, 0x0f, 0x18, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x31, 0xde, 0x24, 0x0e, 0xf8, 0x90, 0x28, 0x80,
+0x31, 0xda, 0x24, 0x0e, 0xd8, 0xec, 0xe1, 0xcd, 0xa1, 0x1f, 0x00, 0x37,
+0x39, 0x88, 0x00, 0x78, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, 0x80, 0x31,
+0xd8, 0x24, 0x0e, 0xc8, 0xec, 0xe1, 0xcc, 0x21, 0x1d, 0x00, 0x37, 0x33,
+0xe5, 0xa1, 0x55, 0x40, 0x35, 0x51, 0xa0, 0x2a, 0x10, 0xa8, 0x16, 0x60,
+0x29, 0xd8, 0xa0, 0x0c, 0x48, 0xa0, 0x0a, 0xc8, 0x95, 0x60, 0x92, 0xb0,
+0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xa1, 0x80,
+0x31, 0xa0, 0x10, 0x10, 0x80, 0x31, 0x9f, 0x90, 0x70, 0x90, 0x38, 0xa4,
+0x08, 0x98, 0x31, 0xb3, 0xa4, 0x08, 0x90, 0x31, 0xb2, 0x10, 0x10, 0xa4,
+0x08, 0x88, 0x31, 0xb1, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09,
+0xb8, 0x31, 0xd7, 0xa4, 0x09, 0xb0, 0x31, 0xd6, 0x10, 0x10, 0xa4, 0x09,
+0xa8, 0x31, 0xd5, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0x28, 0x31, 0xc5,
+0xa4, 0x09, 0x20, 0x31, 0xc4, 0x10, 0x10, 0xa4, 0x09, 0x18, 0x31, 0xc3,
+0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x9c, 0x80,
+0x31, 0x9e, 0x10, 0x10, 0x80, 0x31, 0x9d, 0x90, 0x70, 0x90, 0x38, 0xa4,
+0x08, 0x70, 0x31, 0xae, 0xa4, 0x08, 0x80, 0x31, 0xb0, 0x10, 0x10, 0xa4,
+0x08, 0x78, 0x31, 0xaf, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09,
+0x90, 0x31, 0xd2, 0xa4, 0x09, 0xa0, 0x31, 0xd4, 0x10, 0x10, 0xa4, 0x09,
+0x98, 0x31, 0xd3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0x00, 0x31, 0xc0,
+0xa4, 0x09, 0x10, 0x31, 0xc2, 0x10, 0x10, 0xa4, 0x09, 0x08, 0x31, 0xc1,
+0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31,
+0x99, 0x80, 0x31, 0x9b, 0x10, 0x10, 0x80, 0x31, 0x9a, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x08, 0x58, 0x31, 0xab, 0xa4, 0x08, 0x68, 0x31, 0xad, 0x10,
+0x10, 0xa4, 0x08, 0x60, 0x31, 0xac, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x09, 0x78, 0x31, 0xcf, 0xa4, 0x09, 0x88, 0x31, 0xd1, 0x10, 0x10,
+0xa4, 0x09, 0x80, 0x31, 0xd0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0xe8,
+0x31, 0xbd, 0xa4, 0x08, 0xf8, 0x31, 0xbf, 0x10, 0x10, 0xa4, 0x08, 0xf0,
+0x31, 0xbe, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31,
+0x96, 0x80, 0x31, 0x98, 0x10, 0x10, 0x80, 0x31, 0x97, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x08, 0x40, 0x31, 0xa8, 0xa4, 0x08, 0x50, 0x31, 0xaa, 0x10,
+0x10, 0xa4, 0x08, 0x48, 0x31, 0xa9, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x09, 0x60, 0x31, 0xcc, 0xa4, 0x09, 0x70, 0x31, 0xce, 0x10, 0x10,
+0xa4, 0x09, 0x68, 0x31, 0xcd, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0xd0,
+0x31, 0xba, 0xa4, 0x08, 0xe0, 0x31, 0xbc, 0x10, 0x10, 0xa4, 0x08, 0xd8,
+0x31, 0xbb, 0x10, 0x10, 0x90, 0xa8, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x31, 0x8d, 0x80, 0x31, 0x8f, 0x10, 0x10, 0x80, 0x31,
+0x8e, 0x90, 0x60, 0x90, 0x30, 0x60, 0xa0, 0x2a, 0xc0, 0x60, 0xa0, 0x2a,
+0x80, 0x90, 0x30, 0x60, 0xa0, 0x2a, 0x40, 0x60, 0xa0, 0x2a, 0x00, 0x97,
+0xf0, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x31, 0x93, 0x80, 0x31, 0x95, 0x10, 0x10, 0x80, 0x31, 0x94,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0x28, 0x31, 0xa5, 0xa4, 0x08, 0x38,
+0x31, 0xa7, 0x10, 0x10, 0xa4, 0x08, 0x30, 0x31, 0xa6, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x09, 0x48, 0x31, 0xc9, 0xa4, 0x09, 0x58, 0x31,
+0xcb, 0x10, 0x10, 0xa4, 0x09, 0x50, 0x31, 0xca, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x08, 0xb8, 0x31, 0xb7, 0xa4, 0x08, 0xc8, 0x31, 0xb9, 0x10, 0x10,
+0xa4, 0x08, 0xc0, 0x31, 0xb8, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x31, 0x90, 0x80, 0x31, 0x92, 0x10, 0x10, 0x80, 0x31, 0x91,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0x10, 0x31, 0xa2, 0xa4, 0x08, 0x20,
+0x31, 0xa4, 0x10, 0x10, 0xa4, 0x08, 0x18, 0x31, 0xa3, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x09, 0x30, 0x31, 0xc6, 0xa4, 0x09, 0x40, 0x31,
+0xc8, 0x10, 0x10, 0xa4, 0x09, 0x38, 0x31, 0xc7, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x08, 0xa0, 0x31, 0xb4, 0xa4, 0x08, 0xb0, 0x31, 0xb6, 0x10, 0x10,
+0xa4, 0x08, 0xa8, 0x31, 0xb5, 0x10, 0x10, 0x91, 0x40, 0x90, 0xa0, 0x90,
+0x50, 0x90, 0x28, 0x80, 0x30, 0xcb, 0x80, 0x30, 0xca, 0x90, 0x28, 0x80,
+0x30, 0xc9, 0x80, 0x30, 0xc8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xc4,
+0x80, 0x30, 0xc7, 0x90, 0x28, 0x80, 0x30, 0xc6, 0x80, 0x30, 0xc5, 0x90,
+0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xbc, 0x80, 0x30, 0xc3, 0x90,
+0x28, 0x80, 0x30, 0xc2, 0x80, 0x30, 0xc1, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x30, 0xbd, 0x80, 0x30, 0xc0, 0x90, 0x28, 0x80, 0x30, 0xbf, 0x80, 0x30,
+0xbe, 0x91, 0x88, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x81, 0x31,
+0x3b, 0x10, 0x10, 0x80, 0x31, 0x3a, 0x90, 0x28, 0x81, 0x31, 0x3d, 0x10,
+0x10, 0x80, 0x31, 0x3c, 0x90, 0x60, 0x90, 0x28, 0x81, 0x31, 0x41, 0x10,
+0x10, 0x80, 0x31, 0x40, 0x90, 0x28, 0x81, 0x31, 0x3f, 0x10, 0x10, 0x80,
+0x31, 0x3e, 0x80, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, 0x81, 0x31, 0x38,
+0x10, 0x10, 0x80, 0x31, 0x39, 0xa0, 0x0b, 0x90, 0xa0, 0x0a, 0xc8, 0x95,
+0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x31, 0x56, 0x80, 0x31, 0x55, 0x10, 0x10, 0x80, 0x31, 0x54, 0x90, 0x70,
+0x90, 0x38, 0xa4, 0x06, 0xe8, 0x31, 0x68, 0xa4, 0x06, 0xe0, 0x31, 0x67,
+0x10, 0x10, 0xa4, 0x06, 0xd8, 0x31, 0x66, 0x90, 0xb8, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x08, 0x08, 0x31, 0x8c, 0xa4, 0x08, 0x00, 0x31, 0x8b, 0x10,
+0x10, 0xa4, 0x07, 0xf8, 0x31, 0x8a, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07,
+0x78, 0x31, 0x7a, 0xa4, 0x07, 0x70, 0x31, 0x79, 0x10, 0x10, 0xa4, 0x07,
+0x68, 0x31, 0x78, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x31, 0x51, 0x80, 0x31, 0x53, 0x10, 0x10, 0x80, 0x31, 0x52, 0x90, 0x70,
+0x90, 0x38, 0xa4, 0x06, 0xc0, 0x31, 0x63, 0xa4, 0x06, 0xd0, 0x31, 0x65,
+0x10, 0x10, 0xa4, 0x06, 0xc8, 0x31, 0x64, 0x90, 0xb8, 0x90, 0x70, 0x90,
+0x38, 0xa4, 0x07, 0xe0, 0x31, 0x87, 0xa4, 0x07, 0xf0, 0x31, 0x89, 0x10,
+0x10, 0xa4, 0x07, 0xe8, 0x31, 0x88, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07,
+0x50, 0x31, 0x75, 0xa4, 0x07, 0x60, 0x31, 0x77, 0x10, 0x10, 0xa4, 0x07,
+0x58, 0x31, 0x76, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x31, 0x4e, 0x80, 0x31, 0x50, 0x10, 0x10, 0x80, 0x31, 0x4f,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0xa8, 0x31, 0x60, 0xa4, 0x06, 0xb8,
+0x31, 0x62, 0x10, 0x10, 0xa4, 0x06, 0xb0, 0x31, 0x61, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x07, 0xc8, 0x31, 0x84, 0xa4, 0x07, 0xd8, 0x31,
+0x86, 0x10, 0x10, 0xa4, 0x07, 0xd0, 0x31, 0x85, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x07, 0x38, 0x31, 0x72, 0xa4, 0x07, 0x48, 0x31, 0x74, 0x10, 0x10,
+0xa4, 0x07, 0x40, 0x31, 0x73, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90,
+0x28, 0x80, 0x31, 0x4b, 0x80, 0x31, 0x4d, 0x10, 0x10, 0x80, 0x31, 0x4c,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x90, 0x31, 0x5d, 0xa4, 0x06, 0xa0,
+0x31, 0x5f, 0x10, 0x10, 0xa4, 0x06, 0x98, 0x31, 0x5e, 0x90, 0xb8, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x07, 0xb0, 0x31, 0x81, 0xa4, 0x07, 0xc0, 0x31,
+0x83, 0x10, 0x10, 0xa4, 0x07, 0xb8, 0x31, 0x82, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x07, 0x20, 0x31, 0x6f, 0xa4, 0x07, 0x30, 0x31, 0x71, 0x10, 0x10,
+0xa4, 0x07, 0x28, 0x31, 0x70, 0x10, 0x10, 0x80, 0x10, 0x10, 0x10, 0x10,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x42, 0x80, 0x31, 0x44, 0x10, 0x10,
+0x80, 0x31, 0x43, 0x80, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x48, 0x80, 0x31, 0x4a, 0x10, 0x10,
+0x80, 0x31, 0x49, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x78, 0x31, 0x5a,
+0xa4, 0x06, 0x88, 0x31, 0x5c, 0x10, 0x10, 0xa4, 0x06, 0x80, 0x31, 0x5b,
+0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, 0x98, 0x31, 0x7e, 0xa4,
+0x07, 0xa8, 0x31, 0x80, 0x10, 0x10, 0xa4, 0x07, 0xa0, 0x31, 0x7f, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x07, 0x08, 0x31, 0x6c, 0xa4, 0x07, 0x18, 0x31,
+0x6e, 0x10, 0x10, 0xa4, 0x07, 0x10, 0x31, 0x6d, 0x91, 0x40, 0x90, 0x88,
+0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x45, 0x80, 0x31, 0x47, 0x10, 0x10,
+0x80, 0x31, 0x46, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x60, 0x31, 0x57,
+0xa4, 0x06, 0x70, 0x31, 0x59, 0x10, 0x10, 0xa4, 0x06, 0x68, 0x31, 0x58,
+0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, 0x80, 0x31, 0x7b, 0xa4,
+0x07, 0x90, 0x31, 0x7d, 0x10, 0x10, 0xa4, 0x07, 0x88, 0x31, 0x7c, 0x90,
+0x70, 0x90, 0x38, 0xa4, 0x06, 0xf0, 0x31, 0x69, 0xa4, 0x07, 0x00, 0x31,
+0x6b, 0x10, 0x10, 0xa4, 0x06, 0xf8, 0x31, 0x6a, 0x10, 0x10, 0x91, 0x40,
+0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xbb, 0x80, 0x30, 0xba,
+0x90, 0x28, 0x80, 0x30, 0xb9, 0x80, 0x30, 0xb8, 0x90, 0x50, 0x90, 0x28,
+0x80, 0x30, 0xb4, 0x80, 0x30, 0xb7, 0x90, 0x28, 0x80, 0x30, 0xb6, 0x80,
+0x30, 0xb5, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xac, 0x80,
+0x30, 0xb3, 0x90, 0x28, 0x80, 0x30, 0xb2, 0x80, 0x30, 0xb1, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x30, 0xad, 0x80, 0x30, 0xb0, 0x90, 0x28, 0x80, 0x30,
+0xaf, 0x80, 0x30, 0xae, 0xc3, 0xc0, 0x30, 0x42, 0x9c, 0xe8, 0x07, 0x60,
+0x91, 0x90, 0x90, 0xf0, 0x10, 0x10, 0x80, 0x88, 0x00, 0x80, 0x90, 0x50,
+0x90, 0x28, 0x80, 0x33, 0xf8, 0x80, 0x33, 0xf9, 0x81, 0x33, 0xef, 0xd0,
+0x41, 0x80, 0x24, 0x20, 0x90, 0x24, 0x20, 0x98, 0x10, 0x10, 0x80, 0x90,
+0x58, 0x80, 0x90, 0x28, 0x24, 0x1f, 0x90, 0x24, 0x1f, 0x98, 0x81, 0x24,
+0x1f, 0x50, 0x92, 0x68, 0x91, 0x00, 0x80, 0x90, 0x90, 0x90, 0x30, 0x80,
+0x24, 0x20, 0x00, 0x90, 0x38, 0xa4, 0x1f, 0xf8, 0x34, 0x06, 0x80, 0x34,
+0x05, 0x80, 0x90, 0x28, 0x80, 0x34, 0x0f, 0xa4, 0x1f, 0xe0, 0x34, 0x0e,
+0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x80, 0x34, 0x09, 0xa4, 0x1f,
+0xf0, 0x34, 0x08, 0x90, 0x28, 0x80, 0x34, 0x04, 0xa4, 0x1f, 0xe8, 0x34,
+0x03, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x0d, 0x80, 0x34, 0x0c, 0x90,
+0x28, 0x24, 0x20, 0x88, 0x24, 0x20, 0x80, 0x90, 0x58, 0x80, 0x10, 0x10,
+0x80, 0x10, 0x10, 0x80, 0x33, 0xfb, 0x80, 0x90, 0x40, 0x10, 0x10, 0x80,
+0x24, 0x1f, 0x60, 0x80, 0x10, 0x10, 0x80, 0x33, 0xfa, 0x91, 0x58, 0x91,
+0x00, 0x90, 0x80, 0x81, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xf6, 0x80,
+0x33, 0xf7, 0x81, 0x33, 0xee, 0x81, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33,
+0xf4, 0x80, 0x33, 0xf5, 0x81, 0x33, 0xed, 0x83, 0x90, 0x28, 0x24, 0x1f,
+0x80, 0x24, 0x1f, 0x88, 0x90, 0xe8, 0x81, 0x90, 0x88, 0x90, 0x38, 0x10,
+0x10, 0x80, 0x34, 0x07, 0x90, 0x28, 0x80, 0x34, 0x02, 0x80, 0x34, 0x01,
+0x80, 0x90, 0x28, 0x80, 0x34, 0x0b, 0x80, 0x34, 0x0a, 0x82, 0x10, 0x10,
+0x80, 0x24, 0x1f, 0x58, 0x97, 0x10, 0x9e, 0x10, 0x06, 0x98, 0x93, 0x00,
+0x91, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x80, 0x30,
+0x71, 0x24, 0x03, 0x78, 0x90, 0x38, 0xa4, 0x04, 0x10, 0x30, 0x83, 0x24,
+0x04, 0x08, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x30, 0x30, 0xa7, 0x24,
+0x05, 0x28, 0x90, 0x38, 0xa4, 0x04, 0xa0, 0x30, 0x95, 0x24, 0x04, 0x98,
+0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x70, 0x30, 0x6c, 0x24,
+0x03, 0x68, 0x90, 0x38, 0xa4, 0x04, 0x00, 0x30, 0x7e, 0x24, 0x03, 0xf8,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x20, 0x30, 0xa2, 0x24, 0x05, 0x18,
+0x90, 0x38, 0xa4, 0x04, 0x90, 0x30, 0x90, 0x24, 0x04, 0x88, 0x91, 0x80,
+0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x58, 0x30, 0x69, 0x24,
+0x03, 0x50, 0x90, 0x38, 0xa4, 0x03, 0xe8, 0x30, 0x7b, 0x24, 0x03, 0xe0,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x08, 0x30, 0x9f, 0x24, 0x05, 0x00,
+0x90, 0x38, 0xa4, 0x04, 0x78, 0x30, 0x8d, 0x24, 0x04, 0x70, 0x90, 0xc0,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x40, 0x30, 0x66, 0x24, 0x03, 0x38,
+0x90, 0x38, 0xa4, 0x03, 0xd0, 0x30, 0x78, 0x24, 0x03, 0xc8, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x04, 0xf0, 0x30, 0x9c, 0x24, 0x04, 0xe8, 0x90, 0x38,
+0xa4, 0x04, 0x60, 0x30, 0x8a, 0x24, 0x04, 0x58, 0x10, 0x10, 0x80, 0x10,
+0x10, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x02, 0xf8, 0x30, 0x5d, 0x24, 0x02,
+0xf0, 0xd7, 0x42, 0x00, 0xa4, 0x39, 0x58, 0x37, 0x2d, 0xa4, 0x39, 0x38,
+0x37, 0x29, 0x9c, 0xe0, 0x06, 0x90, 0x93, 0x00, 0x91, 0x80, 0x90, 0xc0,
+0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x28, 0x30, 0x63, 0x24, 0x03, 0x20,
+0x90, 0x38, 0xa4, 0x03, 0xb8, 0x30, 0x75, 0x24, 0x03, 0xb0, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x04, 0xd8, 0x30, 0x99, 0x24, 0x04, 0xd0, 0x90, 0x38,
+0xa4, 0x04, 0x48, 0x30, 0x87, 0x24, 0x04, 0x40, 0x90, 0xc0, 0x90, 0x60,
+0x90, 0x38, 0xa4, 0x03, 0x10, 0x30, 0x60, 0x24, 0x03, 0x08, 0x90, 0x38,
+0xa4, 0x03, 0xa0, 0x30, 0x72, 0x24, 0x03, 0x98, 0x90, 0x60, 0x90, 0x38,
+0xa4, 0x04, 0xc0, 0x30, 0x96, 0x24, 0x04, 0xb8, 0x90, 0x38, 0xa4, 0x04,
+0x30, 0x30, 0x84, 0x24, 0x04, 0x28, 0x10, 0x10, 0x90, 0xe0, 0x90, 0x70,
+0x90, 0x38, 0xa4, 0x02, 0x88, 0x30, 0x52, 0xa4, 0x02, 0x78, 0x30, 0x50,
+0x90, 0x38, 0xa4, 0x02, 0x70, 0x30, 0x4b, 0xa4, 0x02, 0x60, 0x30, 0x4d,
+0x90, 0x70, 0x90, 0x38, 0xa4, 0x02, 0x50, 0x30, 0x43, 0xa4, 0x02, 0x40,
+0x30, 0x49, 0x90, 0x38, 0xa4, 0x02, 0x38, 0x30, 0x44, 0xa4, 0x02, 0x28,
+0x30, 0x46, 0x91, 0x48, 0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80,
+0x30, 0x56, 0x24, 0x02, 0xa8, 0x90, 0x28, 0x80, 0x30, 0x58, 0x24, 0x02,
+0xb8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x5c, 0x24, 0x02, 0xd8, 0x90,
+0x28, 0x80, 0x30, 0x5a, 0x24, 0x02, 0xc8, 0x80, 0x10, 0x10, 0x10, 0x10,
+0x90, 0x28, 0x80, 0x30, 0x53, 0x24, 0x02, 0xa0, 0xd7, 0x42, 0x00, 0xa4,
+0x39, 0x60, 0x37, 0x2e, 0xa4, 0x39, 0x40, 0x37, 0x2a, 0xa0, 0x14, 0x68,
+0xa0, 0x10, 0x90, 0xa0, 0x0c, 0x60, 0x9e, 0x88, 0x09, 0xd0, 0x94, 0xf0,
+0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x4c, 0x40,
+0x85, 0x35, 0x4d, 0xcb, 0x61, 0x45, 0x00, 0x85, 0x35, 0x23, 0x9a, 0x00,
+0x03, 0xf8, 0x91, 0x98, 0x80, 0x91, 0x10, 0x90, 0xa0, 0x90, 0x68, 0x90,
+0x20, 0x3a, 0x75, 0xc9, 0xe2, 0x9c, 0xc0, 0x85, 0x35, 0x4b, 0xa4, 0x53,
+0x88, 0x3a, 0x72, 0x90, 0x38, 0xa4, 0x53, 0x50, 0x3a, 0x6b, 0xa4, 0x53,
+0x40, 0x3a, 0x69, 0x90, 0x48, 0x10, 0x10, 0xa4, 0x53, 0x08, 0x3a, 0x62,
+0x10, 0x10, 0x80, 0x3a, 0x5e, 0x81, 0x10, 0x10, 0x80, 0xa4, 0x52, 0xd8,
+0x3a, 0x5c, 0x91, 0xb0, 0x91, 0x60, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38,
+0xa4, 0x53, 0x78, 0x3a, 0x70, 0xa4, 0x53, 0x68, 0x3a, 0x6e, 0x90, 0x38,
+0xa4, 0x53, 0x30, 0x3a, 0x67, 0xa4, 0x53, 0x20, 0x3a, 0x65, 0x90, 0x48,
+0x10, 0x10, 0xa4, 0x52, 0xf8, 0x3a, 0x60, 0x10, 0x10, 0x80, 0x3a, 0x5d,
+0x90, 0x28, 0x80, 0x3a, 0x56, 0x80, 0x3a, 0x55, 0x81, 0x10, 0x10, 0x80,
+0xa4, 0x52, 0xc8, 0x3a, 0x5a, 0xcb, 0x61, 0x44, 0xc0, 0x85, 0x35, 0x22,
+0x90, 0xd8, 0x88, 0x00, 0x90, 0x84, 0x90, 0x38, 0xc1, 0xc0, 0x85, 0x3a,
+0x78, 0xc9, 0xe1, 0x4c, 0x00, 0x85, 0x35, 0x49, 0xcb, 0x61, 0x44, 0x80,
+0x85, 0x35, 0x21, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x4b,
+0xc0, 0x85, 0x35, 0x47, 0xcb, 0x61, 0x44, 0x40, 0x85, 0x35, 0x20, 0x91,
+0xf8, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x4b,
+0x40, 0x85, 0x35, 0x43, 0xcb, 0x61, 0x43, 0xc0, 0x85, 0x35, 0x1e, 0x88,
+0x01, 0x00, 0x90, 0xa0, 0x81, 0x90, 0x70, 0x80, 0x90, 0x20, 0x3a, 0x6c,
+0xc9, 0xe1, 0x4b, 0x00, 0x85, 0x35, 0x41, 0x81, 0x3a, 0x63, 0x81, 0x10,
+0x10, 0x80, 0xa4, 0x52, 0xb8, 0x3a, 0x58, 0xcb, 0x61, 0x43, 0x80, 0x85,
+0x35, 0x1d, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1,
+0x4a, 0xc0, 0x85, 0x35, 0x3f, 0xcb, 0x61, 0x43, 0x40, 0x85, 0x35, 0x1c,
+0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x4a, 0x80, 0x85, 0x35,
+0x3d, 0xcb, 0x61, 0x43, 0x00, 0x85, 0x35, 0x1b, 0x92, 0x38, 0x81, 0x91,
+0x68, 0x91, 0x18, 0x90, 0x80, 0x90, 0x40, 0x80, 0xa4, 0x54, 0x38, 0x3a,
+0x88, 0x80, 0xa4, 0x54, 0x30, 0x3a, 0x85, 0x90, 0x28, 0x81, 0x3a, 0x84,
+0x90, 0x38, 0xa4, 0x54, 0x10, 0x3a, 0x83, 0xa4, 0x54, 0x00, 0x3a, 0x81,
+0x90, 0x28, 0x80, 0x3a, 0x7f, 0x80, 0x3a, 0x7e, 0x80, 0x90, 0x40, 0x10,
+0x10, 0x80, 0x24, 0x53, 0xe8, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x53, 0xd8,
+0x3a, 0x7c, 0xa4, 0x53, 0xc8, 0x3a, 0x7a, 0x90, 0x28, 0x80, 0x3a, 0x77,
+0x80, 0x3a, 0x76, 0x9a, 0xd0, 0x03, 0xe0, 0x91, 0x60, 0x90, 0xb0, 0x88,
+0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x4a, 0x00, 0x85, 0x35, 0x39,
+0xcb, 0x61, 0x42, 0x80, 0x85, 0x35, 0x19, 0x88, 0x00, 0x68, 0x84, 0x10,
+0x10, 0xc9, 0xe1, 0x49, 0xc0, 0x85, 0x35, 0x37, 0xcb, 0x61, 0x42, 0x40,
+0x85, 0x35, 0x18, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9,
+0xe1, 0x49, 0x80, 0x85, 0x35, 0x35, 0xcb, 0x61, 0x42, 0x00, 0x85, 0x35,
+0x17, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x49, 0x40, 0x85,
+0x35, 0x33, 0xcb, 0x61, 0x41, 0xc0, 0x85, 0x35, 0x16, 0x90, 0x90, 0x90,
+0x48, 0xcb, 0xa1, 0x40, 0x00, 0x85, 0x35, 0x05, 0xcb, 0xa1, 0x3f, 0xc0,
+0x85, 0x35, 0x04, 0x90, 0x48, 0xcb, 0xa1, 0x3f, 0x80, 0x85, 0x35, 0x03,
+0xcb, 0xa1, 0x3f, 0x40, 0x85, 0x35, 0x02, 0xcb, 0xa2, 0x94, 0xc0, 0x80,
+0x3a, 0x54, 0x92, 0x40, 0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x27,
+0x60, 0x84, 0x24, 0x27, 0xd8, 0x8c, 0x27, 0x58, 0x84, 0x24, 0x27, 0xd0,
+0x90, 0x48, 0x8c, 0x27, 0x50, 0x84, 0x24, 0x27, 0xc8, 0x8c, 0x27, 0x48,
+0x84, 0x24, 0x27, 0xc0, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x27, 0x38, 0x84,
+0x24, 0x27, 0xb0, 0x8c, 0x27, 0x30, 0x84, 0x24, 0x27, 0xa8, 0x90, 0x48,
+0x8c, 0x27, 0x28, 0x84, 0x24, 0x27, 0xa0, 0x8c, 0x27, 0x20, 0x84, 0x24,
+0x27, 0x98, 0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x27, 0x10, 0x84,
+0x24, 0x27, 0x88, 0x8c, 0x27, 0x08, 0x84, 0x24, 0x27, 0x80, 0x90, 0x48,
+0x8c, 0x27, 0x00, 0x84, 0x24, 0x27, 0x78, 0x8c, 0x26, 0xf8, 0x84, 0x24,
+0x27, 0x70, 0x90, 0x38, 0xa4, 0x26, 0xe0, 0x34, 0xdd, 0xa4, 0x26, 0xd0,
+0x34, 0xdb, 0xa0, 0x0f, 0x50, 0xa0, 0x09, 0x08, 0x9a, 0x30, 0x04, 0x40,
+0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x92, 0xc0,
+0x3a, 0x43, 0xe5, 0x22, 0x8a, 0xc0, 0x3a, 0x3f, 0xcb, 0x61, 0x32, 0x40,
+0x85, 0x34, 0xd8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x82, 0xc0, 0x3a,
+0x03, 0xe5, 0x22, 0x7a, 0xc0, 0x39, 0xff, 0xcb, 0x61, 0x32, 0x00, 0x85,
+0x34, 0xd7, 0x90, 0x48, 0xcb, 0xa1, 0x31, 0xc0, 0x85, 0x34, 0xd6, 0xcb,
+0xa1, 0x31, 0x80, 0x85, 0x34, 0xd5, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50,
+0x00, 0x80, 0xe5, 0x22, 0x6c, 0xc0, 0x39, 0xcb, 0xe5, 0x22, 0x60, 0xc0,
+0x39, 0x9b, 0xcb, 0x61, 0x31, 0x00, 0x85, 0x34, 0xd3, 0x98, 0x50, 0x00,
+0x80, 0xe5, 0x22, 0x54, 0xc0, 0x39, 0x6b, 0xe5, 0x22, 0x48, 0xc0, 0x39,
+0x3b, 0xcb, 0x61, 0x30, 0xc0, 0x85, 0x34, 0xd2, 0x90, 0x48, 0xcb, 0xa1,
+0x30, 0x80, 0x85, 0x34, 0xd1, 0xcb, 0xa1, 0x30, 0x40, 0x85, 0x34, 0xd0,
+0x92, 0x20, 0x91, 0x30, 0x90, 0xb8, 0xd5, 0x03, 0x00, 0xc0, 0xc0, 0x81,
+0x8c, 0x01, 0xa0, 0x84, 0x30, 0x3e, 0xc0, 0xc0, 0x81, 0x8c, 0x01, 0x80,
+0x84, 0x30, 0x3c, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, 0x30, 0x28, 0xc0,
+0xc0, 0x81, 0x30, 0x24, 0x90, 0x78, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81,
+0x30, 0x1c, 0xc0, 0xc0, 0x81, 0x30, 0x18, 0xd5, 0x02, 0x00, 0xc0, 0xc0,
+0x81, 0x30, 0x10, 0xc0, 0xc0, 0x81, 0x30, 0x0c, 0x91, 0x70, 0x90, 0xd8,
+0xd5, 0x03, 0x80, 0xc8, 0xe2, 0x40, 0xc0, 0x81, 0x8c, 0x01, 0xc0, 0x84,
+0x30, 0x40, 0xc8, 0xe2, 0x42, 0xc0, 0x81, 0x8c, 0x01, 0x90, 0x84, 0x30,
+0x3d, 0xd5, 0x02, 0x80, 0xc8, 0xe2, 0x3f, 0xc0, 0x81, 0x30, 0x2c, 0xc8,
+0xe2, 0x3a, 0x40, 0x81, 0x30, 0x26, 0x90, 0x98, 0xd5, 0x02, 0x80, 0xc8,
+0xe2, 0x2f, 0x40, 0x81, 0x30, 0x20, 0xc8, 0xe2, 0x31, 0x40, 0x81, 0x30,
+0x1a, 0xd5, 0x02, 0x80, 0xc8, 0xe2, 0x2e, 0x40, 0x81, 0x30, 0x14, 0xc8,
+0xe2, 0x28, 0xc0, 0x81, 0x30, 0x0e, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x90,
+0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x86, 0xc0, 0x3a, 0x13,
+0xe5, 0x22, 0x88, 0xc0, 0x3a, 0x37, 0xcb, 0x61, 0x2f, 0xc0, 0x85, 0x34,
+0xce, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x76, 0xc0, 0x39, 0xd3, 0xe5,
+0x22, 0x78, 0xc0, 0x39, 0xf7, 0xcb, 0x61, 0x2f, 0x80, 0x85, 0x34, 0xcd,
+0x90, 0x48, 0xcb, 0xa1, 0x2f, 0x40, 0x85, 0x34, 0xcc, 0xcb, 0xa1, 0x2f,
+0x00, 0x85, 0x34, 0xcb, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80,
+0xe5, 0x22, 0x68, 0xc0, 0x39, 0xbb, 0xe5, 0x22, 0x5c, 0xc0, 0x39, 0x8b,
+0xcb, 0x61, 0x2d, 0x40, 0x85, 0x34, 0xba, 0x98, 0x50, 0x00, 0x80, 0xe5,
+0x22, 0x50, 0xc0, 0x39, 0x5b, 0xe5, 0x22, 0x44, 0xc0, 0x39, 0x2b, 0xcb,
+0x61, 0x2d, 0x00, 0x85, 0x34, 0xb9, 0x90, 0x48, 0xcb, 0xa1, 0x2c, 0xc0,
+0x85, 0x34, 0xb8, 0xcb, 0xa1, 0x2c, 0x80, 0x85, 0x34, 0xb7, 0x91, 0x00,
+0x90, 0x80, 0x90, 0x40, 0xe5, 0x20, 0x02, 0x40, 0x30, 0x0a, 0xe5, 0x20,
+0x01, 0x80, 0x30, 0x07, 0x90, 0x40, 0xe5, 0x20, 0x00, 0xc0, 0x30, 0x04,
+0xe5, 0x20, 0x00, 0x00, 0x30, 0x01, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x22,
+0x35, 0xc0, 0x38, 0xcd, 0xe5, 0x22, 0x38, 0x00, 0x38, 0xf5, 0x90, 0x40,
+0xe5, 0x22, 0x24, 0x40, 0x38, 0x87, 0xe5, 0x22, 0x26, 0x80, 0x38, 0xaf,
+0x80, 0x99, 0x28, 0x02, 0xf0, 0x8c, 0x25, 0x48, 0x90, 0x80, 0x90, 0x40,
+0xe5, 0x22, 0x8c, 0xc0, 0x3a, 0x2f, 0xe5, 0x22, 0x89, 0xc0, 0x3a, 0x3b,
+0x90, 0x40, 0xe5, 0x22, 0x7c, 0xc0, 0x39, 0xef, 0xe5, 0x22, 0x79, 0xc0,
+0x39, 0xfb, 0x91, 0x48, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22,
+0x6a, 0xc0, 0x39, 0xc3, 0xe5, 0x22, 0x5e, 0xc0, 0x39, 0x93, 0xcb, 0x61,
+0x2b, 0x00, 0x85, 0x34, 0xb0, 0x90, 0x40, 0xe5, 0x22, 0x52, 0xc0, 0x39,
+0x63, 0xe5, 0x22, 0x46, 0xc0, 0x39, 0x33, 0x90, 0x48, 0xcb, 0xa1, 0x2a,
+0x80, 0x85, 0x34, 0xae, 0xcb, 0xa1, 0x2a, 0xc0, 0x85, 0x34, 0xaf, 0x10,
+0x10, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x22, 0x3c, 0x40, 0x38, 0xed, 0xe5,
+0x22, 0x39, 0x40, 0x38, 0xfb, 0x90, 0x40, 0xe5, 0x22, 0x2a, 0xc0, 0x38,
+0xa7, 0xe5, 0x22, 0x27, 0xc0, 0x38, 0xb5,
+};
+
+static const struct ia64_dis_names ia64_dis_names[] = {
+{ 0x51, 41, 0, 10 },
+{ 0x31, 41, 1, 20 },
+{ 0x11, 42, 0, 19 },
+{ 0x29, 41, 0, 12 },
+{ 0x19, 41, 1, 24 },
+{ 0x9, 42, 0, 23 },
+{ 0x15, 41, 0, 14 },
+{ 0xd, 41, 1, 28 },
+{ 0x5, 42, 0, 27 },
+{ 0xb, 41, 0, 16 },
+{ 0x7, 41, 1, 32 },
+{ 0x3, 42, 0, 31 },
+{ 0x51, 39, 1, 58 },
+{ 0x50, 39, 0, 34 },
+{ 0xd1, 39, 1, 57 },
+{ 0xd0, 39, 0, 33 },
+{ 0x31, 39, 1, 68 },
+{ 0x30, 39, 1, 44 },
+{ 0x11, 40, 1, 67 },
+{ 0x10, 40, 0, 43 },
+{ 0x71, 39, 1, 66 },
+{ 0x70, 39, 1, 42 },
+{ 0x31, 40, 1, 65 },
+{ 0x30, 40, 0, 41 },
+{ 0x29, 39, 1, 60 },
+{ 0x28, 39, 0, 36 },
+{ 0x69, 39, 1, 59 },
+{ 0x68, 39, 0, 35 },
+{ 0x19, 39, 1, 72 },
+{ 0x18, 39, 1, 48 },
+{ 0x9, 40, 1, 71 },
+{ 0x8, 40, 0, 47 },
+{ 0x39, 39, 1, 70 },
+{ 0x38, 39, 1, 46 },
+{ 0x19, 40, 1, 69 },
+{ 0x18, 40, 0, 45 },
+{ 0x15, 39, 1, 62 },
+{ 0x14, 39, 0, 38 },
+{ 0x35, 39, 1, 61 },
+{ 0x34, 39, 0, 37 },
+{ 0xd, 39, 1, 76 },
+{ 0xc, 39, 1, 52 },
+{ 0x5, 40, 1, 75 },
+{ 0x4, 40, 0, 51 },
+{ 0x1d, 39, 1, 74 },
+{ 0x1c, 39, 1, 50 },
+{ 0xd, 40, 1, 73 },
+{ 0xc, 40, 0, 49 },
+{ 0xb, 39, 1, 64 },
+{ 0xa, 39, 0, 40 },
+{ 0x1b, 39, 1, 63 },
+{ 0x1a, 39, 0, 39 },
+{ 0x7, 39, 1, 80 },
+{ 0x6, 39, 1, 56 },
+{ 0x3, 40, 1, 79 },
+{ 0x2, 40, 0, 55 },
+{ 0xf, 39, 1, 78 },
+{ 0xe, 39, 1, 54 },
+{ 0x7, 40, 1, 77 },
+{ 0x6, 40, 0, 53 },
+{ 0x8, 38, 0, 82 },
+{ 0x18, 38, 0, 81 },
+{ 0x1, 38, 1, 86 },
+{ 0x2, 38, 0, 85 },
+{ 0x3, 38, 1, 84 },
+{ 0x4, 38, 0, 83 },
+{ 0x1, 336, 0, 87 },
+{ 0x20, 289, 0, 98 },
+{ 0x220, 289, 0, 94 },
+{ 0x1220, 289, 0, 91 },
+{ 0xa20, 289, 0, 92 },
+{ 0x620, 289, 0, 93 },
+{ 0x120, 289, 0, 95 },
+{ 0xa0, 289, 0, 96 },
+{ 0x60, 289, 0, 97 },
+{ 0x10, 289, 0, 102 },
+{ 0x90, 289, 0, 99 },
+{ 0x50, 289, 0, 100 },
+{ 0x30, 289, 0, 101 },
+{ 0x8, 289, 0, 103 },
+{ 0x4, 289, 0, 104 },
+{ 0x2, 289, 0, 105 },
+{ 0x1, 289, 0, 106 },
+{ 0x1, 411, 0, 108 },
+{ 0x3, 411, 0, 107 },
+{ 0x2, 417, 0, 109 },
+{ 0x1, 417, 0, 110 },
+{ 0x2, 413, 0, 111 },
+{ 0x1, 413, 0, 112 },
+{ 0x2, 415, 0, 113 },
+{ 0x1, 415, 0, 114 },
+{ 0x2, 419, 0, 115 },
+{ 0x1, 419, 0, 116 },
+{ 0x1, 268, 0, 143 },
+{ 0x5, 268, 0, 141 },
+{ 0x3, 268, 0, 142 },
+{ 0x140, 277, 0, 119 },
+{ 0x540, 277, 0, 117 },
+{ 0x340, 277, 0, 118 },
+{ 0xc0, 277, 0, 131 },
+{ 0x2c0, 277, 0, 129 },
+{ 0x1c0, 277, 0, 130 },
+{ 0x20, 277, 0, 146 },
+{ 0xa0, 277, 0, 144 },
+{ 0x60, 277, 0, 145 },
+{ 0x10, 277, 0, 158 },
+{ 0x50, 277, 0, 156 },
+{ 0x30, 277, 0, 157 },
+{ 0x8, 277, 0, 170 },
+{ 0x28, 277, 0, 168 },
+{ 0x18, 277, 0, 169 },
+{ 0x4, 277, 0, 180 },
+{ 0x2, 277, 0, 181 },
+{ 0x1, 277, 0, 182 },
+{ 0x140, 271, 0, 122 },
+{ 0x540, 271, 0, 120 },
+{ 0x340, 271, 0, 121 },
+{ 0xc0, 271, 0, 134 },
+{ 0x2c0, 271, 0, 132 },
+{ 0x1c0, 271, 0, 133 },
+{ 0x20, 271, 0, 149 },
+{ 0xa0, 271, 0, 147 },
+{ 0x60, 271, 0, 148 },
+{ 0x10, 271, 0, 161 },
+{ 0x50, 271, 0, 159 },
+{ 0x30, 271, 0, 160 },
+{ 0x8, 271, 0, 173 },
+{ 0x28, 271, 0, 171 },
+{ 0x18, 271, 0, 172 },
+{ 0x4, 271, 0, 183 },
+{ 0x2, 271, 0, 184 },
+{ 0x1, 271, 0, 185 },
+{ 0x140, 274, 0, 125 },
+{ 0x540, 274, 0, 123 },
+{ 0x340, 274, 0, 124 },
+{ 0xc0, 274, 0, 137 },
+{ 0x2c0, 274, 0, 135 },
+{ 0x1c0, 274, 0, 136 },
+{ 0x20, 274, 0, 152 },
+{ 0xa0, 274, 0, 150 },
+{ 0x60, 274, 0, 151 },
+{ 0x10, 274, 0, 164 },
+{ 0x50, 274, 0, 162 },
+{ 0x30, 274, 0, 163 },
+{ 0x8, 274, 0, 176 },
+{ 0x28, 274, 0, 174 },
+{ 0x18, 274, 0, 175 },
+{ 0x4, 274, 0, 186 },
+{ 0x2, 274, 0, 187 },
+{ 0x1, 274, 0, 188 },
+{ 0x140, 286, 0, 128 },
+{ 0x540, 286, 0, 126 },
+{ 0x340, 286, 0, 127 },
+{ 0xc0, 286, 0, 140 },
+{ 0x2c0, 286, 0, 138 },
+{ 0x1c0, 286, 0, 139 },
+{ 0x20, 286, 0, 155 },
+{ 0xa0, 286, 0, 153 },
+{ 0x60, 286, 0, 154 },
+{ 0x10, 286, 0, 167 },
+{ 0x50, 286, 0, 165 },
+{ 0x30, 286, 0, 166 },
+{ 0x8, 286, 0, 179 },
+{ 0x28, 286, 0, 177 },
+{ 0x18, 286, 0, 178 },
+{ 0x4, 286, 0, 189 },
+{ 0x2, 286, 0, 190 },
+{ 0x1, 286, 0, 191 },
+{ 0x8, 390, 0, 192 },
+{ 0x4, 390, 0, 193 },
+{ 0x2, 390, 0, 194 },
+{ 0x1, 390, 0, 195 },
+{ 0x20, 288, 0, 203 },
+{ 0x220, 288, 0, 199 },
+{ 0x1220, 288, 0, 196 },
+{ 0xa20, 288, 0, 197 },
+{ 0x620, 288, 0, 198 },
+{ 0x120, 288, 0, 200 },
+{ 0xa0, 288, 0, 201 },
+{ 0x60, 288, 0, 202 },
+{ 0x10, 288, 0, 207 },
+{ 0x90, 288, 0, 204 },
+{ 0x50, 288, 0, 205 },
+{ 0x30, 288, 0, 206 },
+{ 0x8, 288, 0, 208 },
+{ 0x4, 288, 0, 209 },
+{ 0x2, 288, 0, 210 },
+{ 0x1, 288, 0, 211 },
+{ 0x20, 287, 0, 219 },
+{ 0x220, 287, 0, 215 },
+{ 0x1220, 287, 0, 212 },
+{ 0xa20, 287, 0, 213 },
+{ 0x620, 287, 0, 214 },
+{ 0x120, 287, 0, 216 },
+{ 0xa0, 287, 0, 217 },
+{ 0x60, 287, 0, 218 },
+{ 0x10, 287, 0, 223 },
+{ 0x90, 287, 0, 220 },
+{ 0x50, 287, 0, 221 },
+{ 0x30, 287, 0, 222 },
+{ 0x8, 287, 0, 224 },
+{ 0x4, 287, 0, 225 },
+{ 0x2, 287, 0, 226 },
+{ 0x1, 287, 0, 227 },
+{ 0x140, 279, 0, 230 },
+{ 0x540, 279, 0, 228 },
+{ 0x340, 279, 0, 229 },
+{ 0xc0, 279, 0, 239 },
+{ 0x2c0, 279, 0, 237 },
+{ 0x1c0, 279, 0, 238 },
+{ 0x20, 279, 0, 248 },
+{ 0xa0, 279, 0, 246 },
+{ 0x60, 279, 0, 247 },
+{ 0x10, 279, 0, 257 },
+{ 0x50, 279, 0, 255 },
+{ 0x30, 279, 0, 256 },
+{ 0x8, 279, 0, 266 },
+{ 0x28, 279, 0, 264 },
+{ 0x18, 279, 0, 265 },
+{ 0x4, 279, 0, 273 },
+{ 0x2, 279, 0, 274 },
+{ 0x1, 279, 0, 275 },
+{ 0x140, 281, 0, 233 },
+{ 0x540, 281, 0, 231 },
+{ 0x340, 281, 0, 232 },
+{ 0xc0, 281, 0, 242 },
+{ 0x2c0, 281, 0, 240 },
+{ 0x1c0, 281, 0, 241 },
+{ 0x20, 281, 0, 251 },
+{ 0xa0, 281, 0, 249 },
+{ 0x60, 281, 0, 250 },
+{ 0x10, 281, 0, 260 },
+{ 0x50, 281, 0, 258 },
+{ 0x30, 281, 0, 259 },
+{ 0x8, 281, 0, 269 },
+{ 0x28, 281, 0, 267 },
+{ 0x18, 281, 0, 268 },
+{ 0x4, 281, 0, 276 },
+{ 0x2, 281, 0, 277 },
+{ 0x1, 281, 0, 278 },
+{ 0x140, 283, 0, 236 },
+{ 0x540, 283, 0, 234 },
+{ 0x340, 283, 0, 235 },
+{ 0xc0, 283, 0, 245 },
+{ 0x2c0, 283, 0, 243 },
+{ 0x1c0, 283, 0, 244 },
+{ 0x20, 283, 0, 254 },
+{ 0xa0, 283, 0, 252 },
+{ 0x60, 283, 0, 253 },
+{ 0x10, 283, 0, 263 },
+{ 0x50, 283, 0, 261 },
+{ 0x30, 283, 0, 262 },
+{ 0x8, 283, 0, 272 },
+{ 0x28, 283, 0, 270 },
+{ 0x18, 283, 0, 271 },
+{ 0x4, 283, 0, 279 },
+{ 0x2, 283, 0, 280 },
+{ 0x1, 283, 0, 281 },
+{ 0x140, 278, 0, 284 },
+{ 0x540, 278, 0, 282 },
+{ 0x340, 278, 0, 283 },
+{ 0xc0, 278, 0, 293 },
+{ 0x2c0, 278, 0, 291 },
+{ 0x1c0, 278, 0, 292 },
+{ 0x20, 278, 0, 302 },
+{ 0xa0, 278, 0, 300 },
+{ 0x60, 278, 0, 301 },
+{ 0x10, 278, 0, 311 },
+{ 0x50, 278, 0, 309 },
+{ 0x30, 278, 0, 310 },
+{ 0x8, 278, 0, 320 },
+{ 0x28, 278, 0, 318 },
+{ 0x18, 278, 0, 319 },
+{ 0x4, 278, 0, 327 },
+{ 0x2, 278, 0, 328 },
+{ 0x1, 278, 0, 329 },
+{ 0x140, 280, 0, 287 },
+{ 0x540, 280, 0, 285 },
+{ 0x340, 280, 0, 286 },
+{ 0xc0, 280, 0, 296 },
+{ 0x2c0, 280, 0, 294 },
+{ 0x1c0, 280, 0, 295 },
+{ 0x20, 280, 0, 305 },
+{ 0xa0, 280, 0, 303 },
+{ 0x60, 280, 0, 304 },
+{ 0x10, 280, 0, 314 },
+{ 0x50, 280, 0, 312 },
+{ 0x30, 280, 0, 313 },
+{ 0x8, 280, 0, 323 },
+{ 0x28, 280, 0, 321 },
+{ 0x18, 280, 0, 322 },
+{ 0x4, 280, 0, 330 },
+{ 0x2, 280, 0, 331 },
+{ 0x1, 280, 0, 332 },
+{ 0x140, 282, 0, 290 },
+{ 0x540, 282, 0, 288 },
+{ 0x340, 282, 0, 289 },
+{ 0xc0, 282, 0, 299 },
+{ 0x2c0, 282, 0, 297 },
+{ 0x1c0, 282, 0, 298 },
+{ 0x20, 282, 0, 308 },
+{ 0xa0, 282, 0, 306 },
+{ 0x60, 282, 0, 307 },
+{ 0x10, 282, 0, 317 },
+{ 0x50, 282, 0, 315 },
+{ 0x30, 282, 0, 316 },
+{ 0x8, 282, 0, 326 },
+{ 0x28, 282, 0, 324 },
+{ 0x18, 282, 0, 325 },
+{ 0x4, 282, 0, 333 },
+{ 0x2, 282, 0, 334 },
+{ 0x1, 282, 0, 335 },
+{ 0x1, 410, 0, 337 },
+{ 0x3, 410, 0, 336 },
+{ 0x2, 416, 0, 338 },
+{ 0x1, 416, 0, 339 },
+{ 0x2, 412, 0, 340 },
+{ 0x1, 412, 0, 341 },
+{ 0x2, 414, 0, 342 },
+{ 0x1, 414, 0, 343 },
+{ 0x2, 418, 0, 344 },
+{ 0x1, 418, 0, 345 },
+{ 0x1, 267, 0, 372 },
+{ 0x5, 267, 0, 370 },
+{ 0x3, 267, 0, 371 },
+{ 0x140, 276, 0, 348 },
+{ 0x540, 276, 0, 346 },
+{ 0x340, 276, 0, 347 },
+{ 0xc0, 276, 0, 360 },
+{ 0x2c0, 276, 0, 358 },
+{ 0x1c0, 276, 0, 359 },
+{ 0x20, 276, 0, 375 },
+{ 0xa0, 276, 0, 373 },
+{ 0x60, 276, 0, 374 },
+{ 0x10, 276, 0, 387 },
+{ 0x50, 276, 0, 385 },
+{ 0x30, 276, 0, 386 },
+{ 0x8, 276, 0, 399 },
+{ 0x28, 276, 0, 397 },
+{ 0x18, 276, 0, 398 },
+{ 0x4, 276, 0, 409 },
+{ 0x2, 276, 0, 410 },
+{ 0x1, 276, 0, 411 },
+{ 0x140, 270, 0, 351 },
+{ 0x540, 270, 0, 349 },
+{ 0x340, 270, 0, 350 },
+{ 0xc0, 270, 0, 363 },
+{ 0x2c0, 270, 0, 361 },
+{ 0x1c0, 270, 0, 362 },
+{ 0x20, 270, 0, 378 },
+{ 0xa0, 270, 0, 376 },
+{ 0x60, 270, 0, 377 },
+{ 0x10, 270, 0, 390 },
+{ 0x50, 270, 0, 388 },
+{ 0x30, 270, 0, 389 },
+{ 0x8, 270, 0, 402 },
+{ 0x28, 270, 0, 400 },
+{ 0x18, 270, 0, 401 },
+{ 0x4, 270, 0, 412 },
+{ 0x2, 270, 0, 413 },
+{ 0x1, 270, 0, 414 },
+{ 0x140, 273, 0, 354 },
+{ 0x540, 273, 0, 352 },
+{ 0x340, 273, 0, 353 },
+{ 0xc0, 273, 0, 366 },
+{ 0x2c0, 273, 0, 364 },
+{ 0x1c0, 273, 0, 365 },
+{ 0x20, 273, 0, 381 },
+{ 0xa0, 273, 0, 379 },
+{ 0x60, 273, 0, 380 },
+{ 0x10, 273, 0, 393 },
+{ 0x50, 273, 0, 391 },
+{ 0x30, 273, 0, 392 },
+{ 0x8, 273, 0, 405 },
+{ 0x28, 273, 0, 403 },
+{ 0x18, 273, 0, 404 },
+{ 0x4, 273, 0, 415 },
+{ 0x2, 273, 0, 416 },
+{ 0x1, 273, 0, 417 },
+{ 0x140, 285, 0, 357 },
+{ 0x540, 285, 0, 355 },
+{ 0x340, 285, 0, 356 },
+{ 0xc0, 285, 0, 369 },
+{ 0x2c0, 285, 0, 367 },
+{ 0x1c0, 285, 0, 368 },
+{ 0x20, 285, 0, 384 },
+{ 0xa0, 285, 0, 382 },
+{ 0x60, 285, 0, 383 },
+{ 0x10, 285, 0, 396 },
+{ 0x50, 285, 0, 394 },
+{ 0x30, 285, 0, 395 },
+{ 0x8, 285, 0, 408 },
+{ 0x28, 285, 0, 406 },
+{ 0x18, 285, 0, 407 },
+{ 0x4, 285, 0, 418 },
+{ 0x2, 285, 0, 419 },
+{ 0x1, 285, 0, 420 },
+{ 0x1, 266, 0, 447 },
+{ 0x5, 266, 0, 445 },
+{ 0x3, 266, 0, 446 },
+{ 0x140, 275, 0, 423 },
+{ 0x540, 275, 0, 421 },
+{ 0x340, 275, 0, 422 },
+{ 0xc0, 275, 0, 435 },
+{ 0x2c0, 275, 0, 433 },
+{ 0x1c0, 275, 0, 434 },
+{ 0x20, 275, 0, 450 },
+{ 0xa0, 275, 0, 448 },
+{ 0x60, 275, 0, 449 },
+{ 0x10, 275, 0, 462 },
+{ 0x50, 275, 0, 460 },
+{ 0x30, 275, 0, 461 },
+{ 0x8, 275, 0, 474 },
+{ 0x28, 275, 0, 472 },
+{ 0x18, 275, 0, 473 },
+{ 0x4, 275, 0, 484 },
+{ 0x2, 275, 0, 485 },
+{ 0x1, 275, 0, 486 },
+{ 0x140, 269, 0, 426 },
+{ 0x540, 269, 0, 424 },
+{ 0x340, 269, 0, 425 },
+{ 0xc0, 269, 0, 438 },
+{ 0x2c0, 269, 0, 436 },
+{ 0x1c0, 269, 0, 437 },
+{ 0x20, 269, 0, 453 },
+{ 0xa0, 269, 0, 451 },
+{ 0x60, 269, 0, 452 },
+{ 0x10, 269, 0, 465 },
+{ 0x50, 269, 0, 463 },
+{ 0x30, 269, 0, 464 },
+{ 0x8, 269, 0, 477 },
+{ 0x28, 269, 0, 475 },
+{ 0x18, 269, 0, 476 },
+{ 0x4, 269, 0, 487 },
+{ 0x2, 269, 0, 488 },
+{ 0x1, 269, 0, 489 },
+{ 0x140, 272, 0, 429 },
+{ 0x540, 272, 0, 427 },
+{ 0x340, 272, 0, 428 },
+{ 0xc0, 272, 0, 441 },
+{ 0x2c0, 272, 0, 439 },
+{ 0x1c0, 272, 0, 440 },
+{ 0x20, 272, 0, 456 },
+{ 0xa0, 272, 0, 454 },
+{ 0x60, 272, 0, 455 },
+{ 0x10, 272, 0, 468 },
+{ 0x50, 272, 0, 466 },
+{ 0x30, 272, 0, 467 },
+{ 0x8, 272, 0, 480 },
+{ 0x28, 272, 0, 478 },
+{ 0x18, 272, 0, 479 },
+{ 0x4, 272, 0, 490 },
+{ 0x2, 272, 0, 491 },
+{ 0x1, 272, 0, 492 },
+{ 0x140, 284, 0, 432 },
+{ 0x540, 284, 0, 430 },
+{ 0x340, 284, 0, 431 },
+{ 0xc0, 284, 0, 444 },
+{ 0x2c0, 284, 0, 442 },
+{ 0x1c0, 284, 0, 443 },
+{ 0x20, 284, 0, 459 },
+{ 0xa0, 284, 0, 457 },
+{ 0x60, 284, 0, 458 },
+{ 0x10, 284, 0, 471 },
+{ 0x50, 284, 0, 469 },
+{ 0x30, 284, 0, 470 },
+{ 0x8, 284, 0, 483 },
+{ 0x28, 284, 0, 481 },
+{ 0x18, 284, 0, 482 },
+{ 0x4, 284, 0, 493 },
+{ 0x2, 284, 0, 494 },
+{ 0x1, 284, 0, 495 },
+{ 0x8, 409, 0, 497 },
+{ 0x18, 409, 0, 496 },
+{ 0x4, 409, 0, 499 },
+{ 0xc, 409, 0, 498 },
+{ 0x2, 409, 0, 506 },
+{ 0x1, 409, 0, 507 },
+{ 0x4, 407, 0, 501 },
+{ 0xc, 407, 0, 500 },
+{ 0x2, 407, 0, 508 },
+{ 0x1, 407, 0, 509 },
+{ 0x4, 405, 0, 503 },
+{ 0xc, 405, 0, 502 },
+{ 0x2, 405, 0, 510 },
+{ 0x1, 405, 0, 511 },
+{ 0x4, 401, 0, 505 },
+{ 0xc, 401, 0, 504 },
+{ 0x2, 401, 0, 512 },
+{ 0x1, 401, 0, 513 },
+{ 0xa00, 265, 0, 528 },
+{ 0x2a00, 265, 0, 526 },
+{ 0x1a00, 265, 0, 527 },
+{ 0x600, 265, 0, 540 },
+{ 0x2600, 265, 0, 516 },
+{ 0xa600, 265, 0, 514 },
+{ 0x6600, 265, 0, 515 },
+{ 0x1600, 265, 0, 538 },
+{ 0xe00, 265, 0, 539 },
+{ 0x100, 265, 0, 552 },
+{ 0x500, 265, 0, 550 },
+{ 0x300, 265, 0, 551 },
+{ 0x80, 265, 0, 555 },
+{ 0x280, 265, 0, 553 },
+{ 0x180, 265, 0, 554 },
+{ 0x40, 265, 0, 567 },
+{ 0x140, 265, 0, 565 },
+{ 0xc0, 265, 0, 566 },
+{ 0x20, 265, 0, 579 },
+{ 0xa0, 265, 0, 577 },
+{ 0x60, 265, 0, 578 },
+{ 0x10, 265, 0, 591 },
+{ 0x50, 265, 0, 589 },
+{ 0x30, 265, 0, 590 },
+{ 0x8, 265, 0, 603 },
+{ 0x28, 265, 0, 601 },
+{ 0x18, 265, 0, 602 },
+{ 0x4, 265, 0, 613 },
+{ 0x2, 265, 0, 614 },
+{ 0x1, 265, 0, 615 },
+{ 0x500, 261, 0, 531 },
+{ 0x1500, 261, 0, 529 },
+{ 0xd00, 261, 0, 530 },
+{ 0x300, 261, 0, 543 },
+{ 0x1300, 261, 0, 519 },
+{ 0x5300, 261, 0, 517 },
+{ 0x3300, 261, 0, 518 },
+{ 0xb00, 261, 0, 541 },
+{ 0x700, 261, 0, 542 },
+{ 0x80, 261, 0, 558 },
+{ 0x280, 261, 0, 556 },
+{ 0x180, 261, 0, 557 },
+{ 0x40, 261, 0, 570 },
+{ 0x140, 261, 0, 568 },
+{ 0xc0, 261, 0, 569 },
+{ 0x20, 261, 0, 582 },
+{ 0xa0, 261, 0, 580 },
+{ 0x60, 261, 0, 581 },
+{ 0x10, 261, 0, 594 },
+{ 0x50, 261, 0, 592 },
+{ 0x30, 261, 0, 593 },
+{ 0x8, 261, 0, 606 },
+{ 0x28, 261, 0, 604 },
+{ 0x18, 261, 0, 605 },
+{ 0x4, 261, 0, 616 },
+{ 0x2, 261, 0, 617 },
+{ 0x1, 261, 0, 618 },
+{ 0x500, 258, 0, 534 },
+{ 0x1500, 258, 0, 532 },
+{ 0xd00, 258, 0, 533 },
+{ 0x300, 258, 0, 546 },
+{ 0x1300, 258, 0, 522 },
+{ 0x5300, 258, 0, 520 },
+{ 0x3300, 258, 0, 521 },
+{ 0xb00, 258, 0, 544 },
+{ 0x700, 258, 0, 545 },
+{ 0x80, 258, 0, 561 },
+{ 0x280, 258, 0, 559 },
+{ 0x180, 258, 0, 560 },
+{ 0x40, 258, 0, 573 },
+{ 0x140, 258, 0, 571 },
+{ 0xc0, 258, 0, 572 },
+{ 0x20, 258, 0, 585 },
+{ 0xa0, 258, 0, 583 },
+{ 0x60, 258, 0, 584 },
+{ 0x10, 258, 0, 597 },
+{ 0x50, 258, 0, 595 },
+{ 0x30, 258, 0, 596 },
+{ 0x8, 258, 0, 609 },
+{ 0x28, 258, 0, 607 },
+{ 0x18, 258, 0, 608 },
+{ 0x4, 258, 0, 619 },
+{ 0x2, 258, 0, 620 },
+{ 0x1, 258, 0, 621 },
+{ 0x500, 253, 0, 537 },
+{ 0x1500, 253, 0, 535 },
+{ 0xd00, 253, 0, 536 },
+{ 0x300, 253, 0, 549 },
+{ 0x1300, 253, 0, 525 },
+{ 0x5300, 253, 0, 523 },
+{ 0x3300, 253, 0, 524 },
+{ 0xb00, 253, 0, 547 },
+{ 0x700, 253, 0, 548 },
+{ 0x80, 253, 0, 564 },
+{ 0x280, 253, 0, 562 },
+{ 0x180, 253, 0, 563 },
+{ 0x40, 253, 0, 576 },
+{ 0x140, 253, 0, 574 },
+{ 0xc0, 253, 0, 575 },
+{ 0x20, 253, 0, 588 },
+{ 0xa0, 253, 0, 586 },
+{ 0x60, 253, 0, 587 },
+{ 0x10, 253, 0, 600 },
+{ 0x50, 253, 0, 598 },
+{ 0x30, 253, 0, 599 },
+{ 0x8, 253, 0, 612 },
+{ 0x28, 253, 0, 610 },
+{ 0x18, 253, 0, 611 },
+{ 0x4, 253, 0, 622 },
+{ 0x2, 253, 0, 623 },
+{ 0x1, 253, 0, 624 },
+{ 0x8, 238, 0, 625 },
+{ 0x4, 238, 0, 626 },
+{ 0x2, 238, 0, 627 },
+{ 0x1, 238, 0, 628 },
+{ 0x2, 176, 0, 631 },
+{ 0xa, 176, 0, 629 },
+{ 0x6, 176, 0, 630 },
+{ 0x1, 176, 0, 637 },
+{ 0x5, 176, 0, 635 },
+{ 0x3, 176, 0, 636 },
+{ 0x2, 175, 0, 634 },
+{ 0xa, 175, 0, 632 },
+{ 0x6, 175, 0, 633 },
+{ 0x1, 175, 0, 640 },
+{ 0x5, 175, 0, 638 },
+{ 0x3, 175, 0, 639 },
+{ 0x4, 451, 0, 641 },
+{ 0x2, 451, 0, 642 },
+{ 0x1, 451, 0, 643 },
+{ 0x4, 450, 0, 644 },
+{ 0x2, 450, 0, 645 },
+{ 0x1, 450, 0, 646 },
+{ 0x4, 449, 0, 647 },
+{ 0x2, 449, 0, 648 },
+{ 0x1, 449, 0, 649 },
+{ 0x4, 448, 0, 650 },
+{ 0x2, 448, 0, 651 },
+{ 0x1, 448, 0, 652 },
+{ 0x2, 123, 1, 658 },
+{ 0x2, 124, 0, 657 },
+{ 0xa, 123, 1, 654 },
+{ 0xa, 124, 0, 653 },
+{ 0x6, 123, 1, 656 },
+{ 0x6, 124, 0, 655 },
+{ 0x1, 123, 1, 688 },
+{ 0x1, 124, 0, 687 },
+{ 0x5, 123, 1, 684 },
+{ 0x5, 124, 0, 683 },
+{ 0x3, 123, 1, 686 },
+{ 0x3, 124, 0, 685 },
+{ 0x2, 131, 1, 664 },
+{ 0x2, 132, 0, 663 },
+{ 0xa, 131, 1, 660 },
+{ 0xa, 132, 0, 659 },
+{ 0x6, 131, 1, 662 },
+{ 0x6, 132, 0, 661 },
+{ 0x1, 131, 1, 694 },
+{ 0x1, 132, 0, 693 },
+{ 0x5, 131, 1, 690 },
+{ 0x5, 132, 0, 689 },
+{ 0x3, 131, 1, 692 },
+{ 0x3, 132, 0, 691 },
+{ 0x2, 129, 1, 670 },
+{ 0x2, 130, 0, 669 },
+{ 0xa, 129, 1, 666 },
+{ 0xa, 130, 0, 665 },
+{ 0x6, 129, 1, 668 },
+{ 0x6, 130, 0, 667 },
+{ 0x1, 129, 1, 700 },
+{ 0x1, 130, 0, 699 },
+{ 0x5, 129, 1, 696 },
+{ 0x5, 130, 0, 695 },
+{ 0x3, 129, 1, 698 },
+{ 0x3, 130, 0, 697 },
+{ 0x2, 127, 1, 676 },
+{ 0x2, 128, 0, 675 },
+{ 0xa, 127, 1, 672 },
+{ 0xa, 128, 0, 671 },
+{ 0x6, 127, 1, 674 },
+{ 0x6, 128, 0, 673 },
+{ 0x1, 127, 1, 706 },
+{ 0x1, 128, 0, 705 },
+{ 0x5, 127, 1, 702 },
+{ 0x5, 128, 0, 701 },
+{ 0x3, 127, 1, 704 },
+{ 0x3, 128, 0, 703 },
+{ 0x2, 125, 1, 682 },
+{ 0x2, 126, 0, 681 },
+{ 0xa, 125, 1, 678 },
+{ 0xa, 126, 0, 677 },
+{ 0x6, 125, 1, 680 },
+{ 0x6, 126, 0, 679 },
+{ 0x1, 125, 1, 712 },
+{ 0x1, 126, 0, 711 },
+{ 0x5, 125, 1, 708 },
+{ 0x5, 126, 0, 707 },
+{ 0x3, 125, 1, 710 },
+{ 0x3, 126, 0, 709 },
+{ 0x4, 402, 1, 718 },
+{ 0x4, 403, 0, 717 },
+{ 0xc, 402, 1, 716 },
+{ 0xc, 403, 0, 715 },
+{ 0x2, 402, 1, 728 },
+{ 0x2, 403, 0, 727 },
+{ 0x1, 402, 1, 730 },
+{ 0x1, 403, 0, 729 },
+{ 0x8, 408, 0, 714 },
+{ 0x18, 408, 0, 713 },
+{ 0x4, 408, 0, 720 },
+{ 0xc, 408, 0, 719 },
+{ 0x2, 408, 0, 731 },
+{ 0x1, 408, 0, 732 },
+{ 0x4, 406, 0, 722 },
+{ 0xc, 406, 0, 721 },
+{ 0x2, 406, 0, 733 },
+{ 0x1, 406, 0, 734 },
+{ 0x4, 404, 0, 724 },
+{ 0xc, 404, 0, 723 },
+{ 0x2, 404, 0, 735 },
+{ 0x1, 404, 0, 736 },
+{ 0x4, 400, 0, 726 },
+{ 0xc, 400, 0, 725 },
+{ 0x2, 400, 0, 737 },
+{ 0x1, 400, 0, 738 },
+{ 0xa00, 264, 0, 753 },
+{ 0x2a00, 264, 0, 751 },
+{ 0x1a00, 264, 0, 752 },
+{ 0x600, 264, 0, 765 },
+{ 0x2600, 264, 0, 741 },
+{ 0xa600, 264, 0, 739 },
+{ 0x6600, 264, 0, 740 },
+{ 0x1600, 264, 0, 763 },
+{ 0xe00, 264, 0, 764 },
+{ 0x100, 264, 0, 777 },
+{ 0x500, 264, 0, 775 },
+{ 0x300, 264, 0, 776 },
+{ 0x80, 264, 0, 780 },
+{ 0x280, 264, 0, 778 },
+{ 0x180, 264, 0, 779 },
+{ 0x40, 264, 0, 792 },
+{ 0x140, 264, 0, 790 },
+{ 0xc0, 264, 0, 791 },
+{ 0x20, 264, 0, 804 },
+{ 0xa0, 264, 0, 802 },
+{ 0x60, 264, 0, 803 },
+{ 0x10, 264, 0, 816 },
+{ 0x50, 264, 0, 814 },
+{ 0x30, 264, 0, 815 },
+{ 0x8, 264, 0, 828 },
+{ 0x28, 264, 0, 826 },
+{ 0x18, 264, 0, 827 },
+{ 0x4, 264, 0, 838 },
+{ 0x2, 264, 0, 839 },
+{ 0x1, 264, 0, 840 },
+{ 0x500, 260, 0, 756 },
+{ 0x1500, 260, 0, 754 },
+{ 0xd00, 260, 0, 755 },
+{ 0x300, 260, 0, 768 },
+{ 0x1300, 260, 0, 744 },
+{ 0x5300, 260, 0, 742 },
+{ 0x3300, 260, 0, 743 },
+{ 0xb00, 260, 0, 766 },
+{ 0x700, 260, 0, 767 },
+{ 0x80, 260, 0, 783 },
+{ 0x280, 260, 0, 781 },
+{ 0x180, 260, 0, 782 },
+{ 0x40, 260, 0, 795 },
+{ 0x140, 260, 0, 793 },
+{ 0xc0, 260, 0, 794 },
+{ 0x20, 260, 0, 807 },
+{ 0xa0, 260, 0, 805 },
+{ 0x60, 260, 0, 806 },
+{ 0x10, 260, 0, 819 },
+{ 0x50, 260, 0, 817 },
+{ 0x30, 260, 0, 818 },
+{ 0x8, 260, 0, 831 },
+{ 0x28, 260, 0, 829 },
+{ 0x18, 260, 0, 830 },
+{ 0x4, 260, 0, 841 },
+{ 0x2, 260, 0, 842 },
+{ 0x1, 260, 0, 843 },
+{ 0x500, 257, 0, 759 },
+{ 0x1500, 257, 0, 757 },
+{ 0xd00, 257, 0, 758 },
+{ 0x300, 257, 0, 771 },
+{ 0x1300, 257, 0, 747 },
+{ 0x5300, 257, 0, 745 },
+{ 0x3300, 257, 0, 746 },
+{ 0xb00, 257, 0, 769 },
+{ 0x700, 257, 0, 770 },
+{ 0x80, 257, 0, 786 },
+{ 0x280, 257, 0, 784 },
+{ 0x180, 257, 0, 785 },
+{ 0x40, 257, 0, 798 },
+{ 0x140, 257, 0, 796 },
+{ 0xc0, 257, 0, 797 },
+{ 0x20, 257, 0, 810 },
+{ 0xa0, 257, 0, 808 },
+{ 0x60, 257, 0, 809 },
+{ 0x10, 257, 0, 822 },
+{ 0x50, 257, 0, 820 },
+{ 0x30, 257, 0, 821 },
+{ 0x8, 257, 0, 834 },
+{ 0x28, 257, 0, 832 },
+{ 0x18, 257, 0, 833 },
+{ 0x4, 257, 0, 844 },
+{ 0x2, 257, 0, 845 },
+{ 0x1, 257, 0, 846 },
+{ 0x500, 252, 0, 762 },
+{ 0x1500, 252, 0, 760 },
+{ 0xd00, 252, 0, 761 },
+{ 0x300, 252, 0, 774 },
+{ 0x1300, 252, 0, 750 },
+{ 0x5300, 252, 0, 748 },
+{ 0x3300, 252, 0, 749 },
+{ 0xb00, 252, 0, 772 },
+{ 0x700, 252, 0, 773 },
+{ 0x80, 252, 0, 789 },
+{ 0x280, 252, 0, 787 },
+{ 0x180, 252, 0, 788 },
+{ 0x40, 252, 0, 801 },
+{ 0x140, 252, 0, 799 },
+{ 0xc0, 252, 0, 800 },
+{ 0x20, 252, 0, 813 },
+{ 0xa0, 252, 0, 811 },
+{ 0x60, 252, 0, 812 },
+{ 0x10, 252, 0, 825 },
+{ 0x50, 252, 0, 823 },
+{ 0x30, 252, 0, 824 },
+{ 0x8, 252, 0, 837 },
+{ 0x28, 252, 0, 835 },
+{ 0x18, 252, 0, 836 },
+{ 0x4, 252, 0, 847 },
+{ 0x2, 252, 0, 848 },
+{ 0x1, 252, 0, 849 },
+{ 0x8, 254, 1, 895 },
+{ 0x8, 255, 0, 894 },
+{ 0x28, 254, 1, 891 },
+{ 0x28, 255, 0, 890 },
+{ 0x18, 254, 1, 893 },
+{ 0x18, 255, 0, 892 },
+{ 0x4, 254, 1, 957 },
+{ 0x4, 255, 0, 956 },
+{ 0x2, 254, 1, 959 },
+{ 0x2, 255, 0, 958 },
+{ 0x1, 254, 1, 961 },
+{ 0x1, 255, 0, 960 },
+{ 0xa00, 262, 0, 865 },
+{ 0x2a00, 262, 0, 863 },
+{ 0x1a00, 262, 0, 864 },
+{ 0x600, 262, 0, 877 },
+{ 0x2600, 262, 0, 853 },
+{ 0xa600, 262, 0, 851 },
+{ 0x6600, 262, 0, 852 },
+{ 0x1600, 262, 0, 875 },
+{ 0xe00, 262, 0, 876 },
+{ 0x100, 262, 0, 889 },
+{ 0x500, 262, 0, 887 },
+{ 0x300, 262, 0, 888 },
+{ 0x80, 262, 0, 898 },
+{ 0x280, 262, 0, 896 },
+{ 0x180, 262, 0, 897 },
+{ 0x40, 262, 0, 910 },
+{ 0x140, 262, 0, 908 },
+{ 0xc0, 262, 0, 909 },
+{ 0x20, 262, 0, 922 },
+{ 0xa0, 262, 0, 920 },
+{ 0x60, 262, 0, 921 },
+{ 0x10, 262, 0, 934 },
+{ 0x50, 262, 0, 932 },
+{ 0x30, 262, 0, 933 },
+{ 0x8, 262, 0, 946 },
+{ 0x28, 262, 0, 944 },
+{ 0x18, 262, 0, 945 },
+{ 0x4, 262, 0, 962 },
+{ 0x2, 262, 0, 963 },
+{ 0x1, 262, 1, 964 },
+{ 0x1, 263, 0, 850 },
+{ 0x500, 259, 0, 868 },
+{ 0x1500, 259, 0, 866 },
+{ 0xd00, 259, 0, 867 },
+{ 0x300, 259, 0, 880 },
+{ 0x1300, 259, 0, 856 },
+{ 0x5300, 259, 0, 854 },
+{ 0x3300, 259, 0, 855 },
+{ 0xb00, 259, 0, 878 },
+{ 0x700, 259, 0, 879 },
+{ 0x80, 259, 0, 901 },
+{ 0x280, 259, 0, 899 },
+{ 0x180, 259, 0, 900 },
+{ 0x40, 259, 0, 913 },
+{ 0x140, 259, 0, 911 },
+{ 0xc0, 259, 0, 912 },
+{ 0x20, 259, 0, 925 },
+{ 0xa0, 259, 0, 923 },
+{ 0x60, 259, 0, 924 },
+{ 0x10, 259, 0, 937 },
+{ 0x50, 259, 0, 935 },
+{ 0x30, 259, 0, 936 },
+{ 0x8, 259, 0, 949 },
+{ 0x28, 259, 0, 947 },
+{ 0x18, 259, 0, 948 },
+{ 0x4, 259, 0, 965 },
+{ 0x2, 259, 0, 966 },
+{ 0x1, 259, 0, 967 },
+{ 0x500, 256, 0, 871 },
+{ 0x1500, 256, 0, 869 },
+{ 0xd00, 256, 0, 870 },
+{ 0x300, 256, 0, 883 },
+{ 0x1300, 256, 0, 859 },
+{ 0x5300, 256, 0, 857 },
+{ 0x3300, 256, 0, 858 },
+{ 0xb00, 256, 0, 881 },
+{ 0x700, 256, 0, 882 },
+{ 0x80, 256, 0, 904 },
+{ 0x280, 256, 0, 902 },
+{ 0x180, 256, 0, 903 },
+{ 0x40, 256, 0, 916 },
+{ 0x140, 256, 0, 914 },
+{ 0xc0, 256, 0, 915 },
+{ 0x20, 256, 0, 928 },
+{ 0xa0, 256, 0, 926 },
+{ 0x60, 256, 0, 927 },
+{ 0x10, 256, 0, 940 },
+{ 0x50, 256, 0, 938 },
+{ 0x30, 256, 0, 939 },
+{ 0x8, 256, 0, 952 },
+{ 0x28, 256, 0, 950 },
+{ 0x18, 256, 0, 951 },
+{ 0x4, 256, 0, 968 },
+{ 0x2, 256, 0, 969 },
+{ 0x1, 256, 0, 970 },
+{ 0x500, 251, 0, 874 },
+{ 0x1500, 251, 0, 872 },
+{ 0xd00, 251, 0, 873 },
+{ 0x300, 251, 0, 886 },
+{ 0x1300, 251, 0, 862 },
+{ 0x5300, 251, 0, 860 },
+{ 0x3300, 251, 0, 861 },
+{ 0xb00, 251, 0, 884 },
+{ 0x700, 251, 0, 885 },
+{ 0x80, 251, 0, 907 },
+{ 0x280, 251, 0, 905 },
+{ 0x180, 251, 0, 906 },
+{ 0x40, 251, 0, 919 },
+{ 0x140, 251, 0, 917 },
+{ 0xc0, 251, 0, 918 },
+{ 0x20, 251, 0, 931 },
+{ 0xa0, 251, 0, 929 },
+{ 0x60, 251, 0, 930 },
+{ 0x10, 251, 0, 943 },
+{ 0x50, 251, 0, 941 },
+{ 0x30, 251, 0, 942 },
+{ 0x8, 251, 0, 955 },
+{ 0x28, 251, 0, 953 },
+{ 0x18, 251, 0, 954 },
+{ 0x4, 251, 0, 971 },
+{ 0x2, 251, 0, 972 },
+{ 0x1, 251, 0, 973 },
+{ 0x2, 150, 0, 975 },
+{ 0x1, 150, 0, 976 },
+{ 0x1, 50, 0, 977 },
+{ 0x3, 49, 0, 978 },
+{ 0x1, 428, 0, 979 },
+{ 0x1, 442, 0, 980 },
+{ 0x2, 386, 0, 983 },
+{ 0x1, 386, 0, 984 },
+{ 0x2, 384, 0, 985 },
+{ 0x1, 384, 0, 986 },
+{ 0x1, 383, 0, 987 },
+{ 0x1, 328, 0, 992 },
+{ 0x1, 327, 0, 993 },
+{ 0x1, 326, 0, 994 },
+{ 0x1, 325, 0, 995 },
+{ 0x1, 250, 0, 996 },
+{ 0x1, 249, 0, 997 },
+{ 0x1, 324, 0, 998 },
+{ 0x1, 323, 0, 999 },
+{ 0x1, 322, 0, 1000 },
+{ 0x1, 321, 0, 1001 },
+{ 0x1, 320, 0, 1002 },
+{ 0x1, 319, 0, 1003 },
+{ 0x1, 318, 0, 1004 },
+{ 0x2, 248, 0, 1005 },
+{ 0x1, 248, 0, 1006 },
+{ 0x2, 366, 0, 1012 },
+{ 0x1, 366, 0, 1013 },
+{ 0x1, 317, 0, 1014 },
+{ 0x1, 316, 0, 1015 },
+{ 0x1, 315, 0, 1016 },
+{ 0x1, 314, 0, 1017 },
+{ 0x1, 8, 1, 1019 },
+{ 0x1, 9, 0, 1018 },
+{ 0x1, 313, 0, 1020 },
+{ 0x1, 312, 0, 1021 },
+{ 0x1, 311, 0, 1022 },
+{ 0x1, 310, 0, 1023 },
+{ 0x1, 388, 0, 1024 },
+{ 0x1, 399, 0, 1025 },
+{ 0x1, 389, 0, 1026 },
+{ 0x1, 423, 0, 1027 },
+{ 0x1, 309, 0, 1031 },
+{ 0x1, 247, 0, 1032 },
+{ 0x1, 177, 0, 1035 },
+{ 0x2, 291, 0, 1039 },
+{ 0x1, 291, 0, 1040 },
+{ 0x1, 236, 0, 1041 },
+{ 0x5, 48, 0, 1043 },
+{ 0x3, 48, 0, 1044 },
+{ 0x5, 47, 0, 1045 },
+{ 0x3, 47, 0, 1046 },
+{ 0x1, 365, 0, 1047 },
+{ 0x1, 373, 0, 1048 },
+{ 0x1, 371, 0, 1049 },
+{ 0x1, 392, 0, 1050 },
+{ 0x1, 372, 0, 1051 },
+{ 0x1, 370, 0, 1052 },
+{ 0x2, 378, 0, 1053 },
+{ 0x1, 378, 0, 1055 },
+{ 0x2, 376, 0, 1054 },
+{ 0x1, 376, 0, 1056 },
+{ 0x2, 396, 0, 1057 },
+{ 0x1, 396, 0, 1060 },
+{ 0x2, 377, 0, 1058 },
+{ 0x1, 377, 0, 1061 },
+{ 0x2, 375, 0, 1059 },
+{ 0x1, 375, 0, 1062 },
+{ 0x1, 338, 0, 1063 },
+{ 0x1, 337, 0, 1064 },
+{ 0x1, 369, 0, 1065 },
+{ 0x1, 360, 0, 1066 },
+{ 0x1, 362, 0, 1067 },
+{ 0x1, 359, 0, 1068 },
+{ 0x1, 361, 0, 1069 },
+{ 0x2, 446, 0, 1070 },
+{ 0x1, 446, 0, 1073 },
+{ 0x2, 445, 0, 1071 },
+{ 0x1, 445, 0, 1074 },
+{ 0x2, 444, 0, 1072 },
+{ 0x1, 444, 0, 1075 },
+{ 0x1, 348, 0, 1076 },
+{ 0x2, 347, 0, 1077 },
+{ 0x1, 347, 0, 1078 },
+{ 0x2, 294, 0, 1079 },
+{ 0x1, 294, 0, 1082 },
+{ 0x2, 293, 0, 1080 },
+{ 0x1, 293, 0, 1083 },
+{ 0x2, 292, 0, 1081 },
+{ 0x1, 292, 0, 1084 },
+{ 0x2, 363, 0, 1085 },
+{ 0x1, 363, 0, 1086 },
+{ 0x2, 364, 0, 1087 },
+{ 0x1, 364, 0, 1088 },
+{ 0xa, 438, 1, 1100 },
+{ 0xa, 439, 1, 1099 },
+{ 0xa, 440, 1, 1098 },
+{ 0xa, 441, 0, 1097 },
+{ 0x1a, 438, 1, 1092 },
+{ 0x1a, 439, 1, 1091 },
+{ 0x32, 440, 1, 1090 },
+{ 0x32, 441, 0, 1089 },
+{ 0x6, 438, 1, 1108 },
+{ 0x6, 439, 1, 1107 },
+{ 0x6, 440, 1, 1106 },
+{ 0x6, 441, 0, 1105 },
+{ 0x1, 438, 1, 1120 },
+{ 0x1, 439, 1, 1119 },
+{ 0x1, 440, 1, 1118 },
+{ 0x1, 441, 0, 1117 },
+{ 0x9, 438, 1, 1104 },
+{ 0x9, 439, 1, 1103 },
+{ 0x9, 440, 1, 1102 },
+{ 0x9, 441, 0, 1101 },
+{ 0x19, 438, 1, 1096 },
+{ 0x19, 439, 1, 1095 },
+{ 0x31, 440, 1, 1094 },
+{ 0x31, 441, 0, 1093 },
+{ 0x5, 438, 1, 1112 },
+{ 0x5, 439, 1, 1111 },
+{ 0x5, 440, 1, 1110 },
+{ 0x5, 441, 0, 1109 },
+{ 0x3, 438, 1, 1116 },
+{ 0x3, 439, 1, 1115 },
+{ 0x3, 440, 1, 1114 },
+{ 0x3, 441, 0, 1113 },
+{ 0xa, 429, 1, 1132 },
+{ 0xa, 430, 1, 1131 },
+{ 0xa, 431, 1, 1130 },
+{ 0xa, 432, 0, 1129 },
+{ 0x1a, 429, 1, 1124 },
+{ 0x1a, 430, 1, 1123 },
+{ 0x32, 431, 1, 1122 },
+{ 0x32, 432, 0, 1121 },
+{ 0x6, 429, 1, 1140 },
+{ 0x6, 430, 1, 1139 },
+{ 0x6, 431, 1, 1138 },
+{ 0x6, 432, 0, 1137 },
+{ 0x1, 429, 1, 1152 },
+{ 0x1, 430, 1, 1151 },
+{ 0x1, 431, 1, 1150 },
+{ 0x1, 432, 0, 1149 },
+{ 0x9, 429, 1, 1136 },
+{ 0x9, 430, 1, 1135 },
+{ 0x9, 431, 1, 1134 },
+{ 0x9, 432, 0, 1133 },
+{ 0x19, 429, 1, 1128 },
+{ 0x19, 430, 1, 1127 },
+{ 0x31, 431, 1, 1126 },
+{ 0x31, 432, 0, 1125 },
+{ 0x5, 429, 1, 1144 },
+{ 0x5, 430, 1, 1143 },
+{ 0x5, 431, 1, 1142 },
+{ 0x5, 432, 0, 1141 },
+{ 0x3, 429, 1, 1148 },
+{ 0x3, 430, 1, 1147 },
+{ 0x3, 431, 1, 1146 },
+{ 0x3, 432, 0, 1145 },
+{ 0xa, 433, 1, 1164 },
+{ 0xa, 434, 1, 1163 },
+{ 0xa, 435, 1, 1162 },
+{ 0xa, 436, 0, 1161 },
+{ 0x1a, 433, 1, 1156 },
+{ 0x1a, 434, 1, 1155 },
+{ 0x32, 435, 1, 1154 },
+{ 0x32, 436, 0, 1153 },
+{ 0x6, 433, 1, 1172 },
+{ 0x6, 434, 1, 1171 },
+{ 0x6, 435, 1, 1170 },
+{ 0x6, 436, 0, 1169 },
+{ 0x1, 433, 1, 1184 },
+{ 0x1, 434, 1, 1183 },
+{ 0x1, 435, 1, 1182 },
+{ 0x1, 436, 0, 1181 },
+{ 0x9, 433, 1, 1168 },
+{ 0x9, 434, 1, 1167 },
+{ 0x9, 435, 1, 1166 },
+{ 0x9, 436, 0, 1165 },
+{ 0x19, 433, 1, 1160 },
+{ 0x19, 434, 1, 1159 },
+{ 0x31, 435, 1, 1158 },
+{ 0x31, 436, 0, 1157 },
+{ 0x5, 433, 1, 1176 },
+{ 0x5, 434, 1, 1175 },
+{ 0x5, 435, 1, 1174 },
+{ 0x5, 436, 0, 1173 },
+{ 0x3, 433, 1, 1180 },
+{ 0x3, 434, 1, 1179 },
+{ 0x3, 435, 1, 1178 },
+{ 0x3, 436, 0, 1177 },
+{ 0x1, 139, 0, 1185 },
+{ 0x1, 138, 0, 1186 },
+{ 0x1, 391, 1, 1188 },
+{ 0x1, 137, 0, 1187 },
+{ 0x2, 395, 1, 1190 },
+{ 0x2, 141, 0, 1189 },
+{ 0x1, 395, 1, 1192 },
+{ 0x1, 141, 0, 1191 },
+{ 0x1, 397, 0, 1193 },
+{ 0x1, 136, 0, 1194 },
+{ 0x2, 135, 0, 1195 },
+{ 0x2, 134, 0, 1196 },
+{ 0x1, 459, 1, 1202 },
+{ 0x1, 246, 0, 1033 },
+{ 0x1, 458, 0, 1203 },
+{ 0x1, 457, 1, 1204 },
+{ 0x1, 245, 0, 1042 },
+{ 0x1, 308, 0, 1205 },
+{ 0x1, 307, 1, 1206 },
+{ 0x1, 290, 0, 1034 },
+{ 0x1, 306, 0, 1207 },
+{ 0x1, 305, 1, 1208 },
+{ 0x1, 427, 0, 1036 },
+{ 0x1, 304, 1, 1209 },
+{ 0x1, 398, 0, 1038 },
+{ 0x1, 303, 0, 1210 },
+{ 0x1, 302, 0, 1211 },
+{ 0x1, 301, 0, 1212 },
+{ 0x1, 300, 1, 1213 },
+{ 0x2, 398, 0, 1037 },
+{ 0x10, 299, 0, 1217 },
+{ 0x90, 299, 0, 1215 },
+{ 0x190, 299, 0, 1214 },
+{ 0x50, 299, 0, 1216 },
+{ 0x30, 299, 0, 1219 },
+{ 0x70, 299, 0, 1218 },
+{ 0x8, 299, 0, 1221 },
+{ 0x18, 299, 0, 1220 },
+{ 0x4, 299, 0, 1222 },
+{ 0x1, 299, 0, 1225 },
+{ 0x3, 299, 0, 1224 },
+{ 0x1, 298, 1, 1226 },
+{ 0x2, 299, 0, 1223 },
+{ 0x3, 46, 0, 1227 },
+{ 0x1, 241, 1, 1228 },
+{ 0x1, 242, 1, 1028 },
+{ 0x1, 243, 0, 88 },
+{ 0x1, 341, 1, 1229 },
+{ 0x1, 342, 1, 1029 },
+{ 0x1, 343, 0, 89 },
+{ 0x1, 34, 1, 1230 },
+{ 0x1, 35, 1, 1030 },
+{ 0x1, 36, 0, 90 },
+{ 0x1, 230, 0, 1231 },
+{ 0x4, 452, 0, 1232 },
+{ 0x2, 452, 0, 1233 },
+{ 0x1, 452, 1, 1235 },
+{ 0x1, 453, 0, 1234 },
+{ 0x8, 454, 0, 1236 },
+{ 0x4, 454, 0, 1237 },
+{ 0x1, 454, 1, 1239 },
+{ 0x2, 454, 0, 1238 },
+{ 0x8, 219, 0, 1240 },
+{ 0x4, 219, 0, 1241 },
+{ 0x2, 219, 0, 1242 },
+{ 0x1, 219, 1, 1244 },
+{ 0x1, 220, 0, 1243 },
+{ 0x10, 221, 0, 1245 },
+{ 0x8, 221, 0, 1246 },
+{ 0x4, 221, 0, 1247 },
+{ 0x1, 221, 1, 1249 },
+{ 0x2, 221, 0, 1248 },
+{ 0x220, 191, 0, 1250 },
+{ 0x120, 191, 0, 1251 },
+{ 0xa0, 191, 0, 1252 },
+{ 0x60, 191, 1, 1254 },
+{ 0x4, 192, 0, 1253 },
+{ 0x110, 191, 0, 1260 },
+{ 0x90, 191, 0, 1261 },
+{ 0x50, 191, 0, 1262 },
+{ 0x30, 191, 1, 1264 },
+{ 0x2, 192, 0, 1263 },
+{ 0x8, 191, 0, 1265 },
+{ 0x4, 191, 0, 1266 },
+{ 0x2, 191, 0, 1267 },
+{ 0x1, 191, 1, 1269 },
+{ 0x1, 192, 0, 1268 },
+{ 0x440, 193, 0, 1255 },
+{ 0x240, 193, 0, 1256 },
+{ 0x140, 193, 0, 1257 },
+{ 0xc0, 193, 1, 1259 },
+{ 0x40, 193, 0, 1258 },
+{ 0x220, 193, 0, 1270 },
+{ 0x120, 193, 0, 1271 },
+{ 0xa0, 193, 0, 1272 },
+{ 0x60, 193, 1, 1274 },
+{ 0x20, 193, 0, 1273 },
+{ 0x10, 193, 0, 1275 },
+{ 0x8, 193, 0, 1276 },
+{ 0x4, 193, 0, 1277 },
+{ 0x1, 193, 1, 1279 },
+{ 0x2, 193, 0, 1278 },
+{ 0x8, 215, 0, 1280 },
+{ 0x4, 215, 0, 1281 },
+{ 0x2, 215, 0, 1282 },
+{ 0x1, 215, 1, 1284 },
+{ 0x1, 216, 0, 1283 },
+{ 0x220, 187, 0, 1285 },
+{ 0x120, 187, 0, 1286 },
+{ 0xa0, 187, 0, 1287 },
+{ 0x60, 187, 1, 1289 },
+{ 0x4, 188, 0, 1288 },
+{ 0x110, 187, 0, 1295 },
+{ 0x90, 187, 0, 1296 },
+{ 0x50, 187, 0, 1297 },
+{ 0x30, 187, 1, 1299 },
+{ 0x2, 188, 0, 1298 },
+{ 0x8, 187, 0, 1300 },
+{ 0x4, 187, 0, 1301 },
+{ 0x2, 187, 0, 1302 },
+{ 0x1, 187, 1, 1304 },
+{ 0x1, 188, 0, 1303 },
+{ 0x440, 233, 0, 1290 },
+{ 0x240, 233, 0, 1291 },
+{ 0x140, 233, 0, 1292 },
+{ 0xc0, 233, 1, 1294 },
+{ 0x40, 233, 0, 1293 },
+{ 0x220, 233, 0, 1305 },
+{ 0x120, 233, 0, 1306 },
+{ 0xa0, 233, 0, 1307 },
+{ 0x60, 233, 1, 1309 },
+{ 0x20, 233, 0, 1308 },
+{ 0x10, 233, 0, 1310 },
+{ 0x8, 233, 0, 1311 },
+{ 0x4, 233, 0, 1312 },
+{ 0x1, 233, 1, 1314 },
+{ 0x2, 233, 0, 1313 },
+{ 0x8, 207, 0, 1315 },
+{ 0x4, 207, 0, 1316 },
+{ 0x2, 207, 0, 1317 },
+{ 0x1, 207, 1, 1319 },
+{ 0x1, 208, 0, 1318 },
+{ 0x10, 214, 0, 1320 },
+{ 0x8, 214, 0, 1321 },
+{ 0x4, 214, 0, 1322 },
+{ 0x1, 214, 1, 1324 },
+{ 0x2, 214, 0, 1323 },
+{ 0x220, 178, 0, 1325 },
+{ 0x120, 178, 0, 1326 },
+{ 0xa0, 178, 0, 1327 },
+{ 0x60, 178, 1, 1329 },
+{ 0x4, 179, 0, 1328 },
+{ 0x110, 178, 0, 1350 },
+{ 0x90, 178, 0, 1351 },
+{ 0x50, 178, 0, 1352 },
+{ 0x30, 178, 1, 1354 },
+{ 0x2, 179, 0, 1353 },
+{ 0x8, 178, 0, 1355 },
+{ 0x4, 178, 0, 1356 },
+{ 0x2, 178, 0, 1357 },
+{ 0x1, 178, 1, 1359 },
+{ 0x1, 179, 0, 1358 },
+{ 0x440, 186, 0, 1330 },
+{ 0x240, 186, 0, 1331 },
+{ 0x140, 186, 0, 1332 },
+{ 0xc0, 186, 1, 1334 },
+{ 0x40, 186, 0, 1333 },
+{ 0x220, 186, 0, 1360 },
+{ 0x120, 186, 0, 1361 },
+{ 0xa0, 186, 0, 1362 },
+{ 0x60, 186, 1, 1364 },
+{ 0x20, 186, 0, 1363 },
+{ 0x10, 186, 0, 1365 },
+{ 0x8, 186, 0, 1366 },
+{ 0x4, 186, 0, 1367 },
+{ 0x1, 186, 1, 1369 },
+{ 0x2, 186, 0, 1368 },
+{ 0x440, 143, 0, 1335 },
+{ 0x240, 143, 0, 1336 },
+{ 0x140, 143, 0, 1337 },
+{ 0xc0, 143, 1, 1339 },
+{ 0x40, 143, 0, 1338 },
+{ 0x220, 143, 0, 1370 },
+{ 0x120, 143, 0, 1371 },
+{ 0xa0, 143, 0, 1372 },
+{ 0x60, 143, 1, 1374 },
+{ 0x20, 143, 0, 1373 },
+{ 0x10, 143, 0, 1375 },
+{ 0x8, 143, 0, 1376 },
+{ 0x1, 143, 1, 1379 },
+{ 0x2, 143, 0, 1378 },
+{ 0x440, 194, 1, 1345 },
+{ 0x441, 174, 0, 1340 },
+{ 0x240, 194, 1, 1346 },
+{ 0x241, 174, 0, 1341 },
+{ 0x140, 194, 1, 1347 },
+{ 0x141, 174, 0, 1342 },
+{ 0xc0, 194, 1, 1349 },
+{ 0x40, 194, 1, 1348 },
+{ 0xc1, 174, 1, 1344 },
+{ 0x41, 174, 0, 1343 },
+{ 0x220, 194, 1, 1390 },
+{ 0x221, 174, 0, 1380 },
+{ 0x120, 194, 1, 1391 },
+{ 0x121, 174, 0, 1381 },
+{ 0xa0, 194, 1, 1392 },
+{ 0xa1, 174, 0, 1382 },
+{ 0x60, 194, 1, 1394 },
+{ 0x20, 194, 1, 1393 },
+{ 0x61, 174, 1, 1384 },
+{ 0x21, 174, 0, 1383 },
+{ 0x10, 194, 1, 1395 },
+{ 0x11, 174, 0, 1385 },
+{ 0x8, 194, 1, 1396 },
+{ 0x9, 174, 0, 1386 },
+{ 0x4, 194, 1, 1397 },
+{ 0x5, 174, 0, 1387 },
+{ 0x1, 194, 1, 1399 },
+{ 0x2, 194, 1, 1398 },
+{ 0x3, 174, 1, 1389 },
+{ 0x1, 174, 0, 1388 },
+{ 0x1, 153, 1, 1407 },
+{ 0x1, 154, 1, 1406 },
+{ 0x1, 155, 1, 1405 },
+{ 0x1, 156, 0, 1404 },
+{ 0x3, 153, 1, 1403 },
+{ 0x3, 154, 1, 1402 },
+{ 0x3, 155, 1, 1401 },
+{ 0x3, 156, 0, 1400 },
+{ 0x1108, 159, 1, 1569 },
+{ 0x1108, 160, 1, 1568 },
+{ 0x1108, 165, 1, 1409 },
+{ 0x1108, 166, 0, 1408 },
+{ 0x908, 159, 1, 1571 },
+{ 0x908, 160, 1, 1570 },
+{ 0x908, 165, 1, 1411 },
+{ 0x908, 166, 0, 1410 },
+{ 0x508, 159, 1, 1573 },
+{ 0x508, 160, 1, 1572 },
+{ 0x508, 165, 1, 1413 },
+{ 0x508, 166, 0, 1412 },
+{ 0x308, 159, 1, 1577 },
+{ 0x308, 160, 1, 1576 },
+{ 0x108, 160, 1, 1574 },
+{ 0x18, 161, 1, 1575 },
+{ 0x308, 165, 1, 1417 },
+{ 0x308, 166, 1, 1416 },
+{ 0x108, 166, 1, 1414 },
+{ 0x18, 167, 0, 1415 },
+{ 0x88, 159, 1, 1609 },
+{ 0x88, 160, 1, 1608 },
+{ 0x88, 165, 1, 1489 },
+{ 0x88, 166, 0, 1488 },
+{ 0x48, 159, 1, 1611 },
+{ 0x48, 160, 1, 1610 },
+{ 0x48, 165, 1, 1491 },
+{ 0x48, 166, 0, 1490 },
+{ 0x28, 159, 1, 1613 },
+{ 0x28, 160, 1, 1612 },
+{ 0x28, 165, 1, 1493 },
+{ 0x28, 166, 0, 1492 },
+{ 0x18, 159, 1, 1617 },
+{ 0x18, 160, 1, 1616 },
+{ 0x8, 160, 1, 1614 },
+{ 0x8, 161, 1, 1615 },
+{ 0x18, 165, 1, 1497 },
+{ 0x18, 166, 1, 1496 },
+{ 0x8, 166, 1, 1494 },
+{ 0x8, 167, 0, 1495 },
+{ 0x884, 159, 1, 1579 },
+{ 0x884, 160, 1, 1578 },
+{ 0x442, 162, 1, 1469 },
+{ 0x442, 163, 1, 1468 },
+{ 0x884, 165, 1, 1439 },
+{ 0x884, 166, 1, 1438 },
+{ 0x442, 168, 1, 1419 },
+{ 0x442, 169, 0, 1418 },
+{ 0x484, 159, 1, 1581 },
+{ 0x484, 160, 1, 1580 },
+{ 0x242, 162, 1, 1471 },
+{ 0x242, 163, 1, 1470 },
+{ 0x484, 165, 1, 1441 },
+{ 0x484, 166, 1, 1440 },
+{ 0x242, 168, 1, 1421 },
+{ 0x242, 169, 0, 1420 },
+{ 0x284, 159, 1, 1583 },
+{ 0x284, 160, 1, 1582 },
+{ 0x142, 162, 1, 1473 },
+{ 0x142, 163, 1, 1472 },
+{ 0x284, 165, 1, 1443 },
+{ 0x284, 166, 1, 1442 },
+{ 0x142, 168, 1, 1423 },
+{ 0x142, 169, 0, 1422 },
+{ 0x184, 159, 1, 1587 },
+{ 0x184, 160, 1, 1586 },
+{ 0x84, 160, 1, 1584 },
+{ 0xc, 161, 1, 1585 },
+{ 0xc2, 162, 1, 1477 },
+{ 0xc2, 163, 1, 1476 },
+{ 0x42, 163, 1, 1474 },
+{ 0x6, 164, 1, 1475 },
+{ 0x184, 165, 1, 1447 },
+{ 0x184, 166, 1, 1446 },
+{ 0x84, 166, 1, 1444 },
+{ 0xc, 167, 1, 1445 },
+{ 0xc2, 168, 1, 1427 },
+{ 0xc2, 169, 1, 1426 },
+{ 0x42, 169, 1, 1424 },
+{ 0x6, 170, 0, 1425 },
+{ 0x44, 159, 1, 1619 },
+{ 0x44, 160, 1, 1618 },
+{ 0x22, 162, 1, 1549 },
+{ 0x22, 163, 1, 1548 },
+{ 0x44, 165, 1, 1519 },
+{ 0x44, 166, 1, 1518 },
+{ 0x22, 168, 1, 1499 },
+{ 0x22, 169, 0, 1498 },
+{ 0x24, 159, 1, 1621 },
+{ 0x24, 160, 1, 1620 },
+{ 0x12, 162, 1, 1551 },
+{ 0x12, 163, 1, 1550 },
+{ 0x24, 165, 1, 1521 },
+{ 0x24, 166, 1, 1520 },
+{ 0x12, 168, 1, 1501 },
+{ 0x12, 169, 0, 1500 },
+{ 0x14, 159, 1, 1623 },
+{ 0x14, 160, 1, 1622 },
+{ 0xa, 162, 1, 1553 },
+{ 0xa, 163, 1, 1552 },
+{ 0x14, 165, 1, 1523 },
+{ 0x14, 166, 1, 1522 },
+{ 0xa, 168, 1, 1503 },
+{ 0xa, 169, 0, 1502 },
+{ 0xc, 159, 1, 1627 },
+{ 0xc, 160, 1, 1626 },
+{ 0x4, 160, 1, 1624 },
+{ 0x4, 161, 1, 1625 },
+{ 0x6, 162, 1, 1557 },
+{ 0x6, 163, 1, 1556 },
+{ 0x2, 163, 1, 1554 },
+{ 0x2, 164, 1, 1555 },
+{ 0xc, 165, 1, 1527 },
+{ 0xc, 166, 1, 1526 },
+{ 0x4, 166, 1, 1524 },
+{ 0x4, 167, 1, 1525 },
+{ 0x6, 168, 1, 1507 },
+{ 0x6, 169, 1, 1506 },
+{ 0x2, 169, 1, 1504 },
+{ 0x2, 170, 0, 1505 },
+{ 0x442, 159, 1, 1589 },
+{ 0x442, 160, 1, 1588 },
+{ 0x221, 162, 1, 1479 },
+{ 0x221, 163, 1, 1478 },
+{ 0x442, 165, 1, 1449 },
+{ 0x442, 166, 1, 1448 },
+{ 0x221, 168, 1, 1429 },
+{ 0x221, 169, 0, 1428 },
+{ 0x242, 159, 1, 1591 },
+{ 0x242, 160, 1, 1590 },
+{ 0x121, 162, 1, 1481 },
+{ 0x121, 163, 1, 1480 },
+{ 0x242, 165, 1, 1451 },
+{ 0x242, 166, 1, 1450 },
+{ 0x121, 168, 1, 1431 },
+{ 0x121, 169, 0, 1430 },
+{ 0x142, 159, 1, 1593 },
+{ 0x142, 160, 1, 1592 },
+{ 0xa1, 162, 1, 1483 },
+{ 0xa1, 163, 1, 1482 },
+{ 0x142, 165, 1, 1453 },
+{ 0x142, 166, 1, 1452 },
+{ 0xa1, 168, 1, 1433 },
+{ 0xa1, 169, 0, 1432 },
+{ 0xc2, 159, 1, 1597 },
+{ 0xc2, 160, 1, 1596 },
+{ 0x42, 160, 1, 1594 },
+{ 0x6, 161, 1, 1595 },
+{ 0x61, 162, 1, 1487 },
+{ 0x61, 163, 1, 1486 },
+{ 0x21, 163, 1, 1484 },
+{ 0x3, 164, 1, 1485 },
+{ 0xc2, 165, 1, 1457 },
+{ 0xc2, 166, 1, 1456 },
+{ 0x42, 166, 1, 1454 },
+{ 0x6, 167, 1, 1455 },
+{ 0x61, 168, 1, 1437 },
+{ 0x61, 169, 1, 1436 },
+{ 0x21, 169, 1, 1434 },
+{ 0x3, 170, 0, 1435 },
+{ 0x22, 159, 1, 1629 },
+{ 0x22, 160, 1, 1628 },
+{ 0x11, 162, 1, 1559 },
+{ 0x11, 163, 1, 1558 },
+{ 0x22, 165, 1, 1529 },
+{ 0x22, 166, 1, 1528 },
+{ 0x11, 168, 1, 1509 },
+{ 0x11, 169, 0, 1508 },
+{ 0x12, 159, 1, 1631 },
+{ 0x12, 160, 1, 1630 },
+{ 0x9, 162, 1, 1561 },
+{ 0x9, 163, 1, 1560 },
+{ 0x12, 165, 1, 1531 },
+{ 0x12, 166, 1, 1530 },
+{ 0x9, 168, 1, 1511 },
+{ 0x9, 169, 0, 1510 },
+{ 0xa, 159, 1, 1633 },
+{ 0xa, 160, 1, 1632 },
+{ 0x5, 162, 1, 1563 },
+{ 0x5, 163, 1, 1562 },
+{ 0xa, 165, 1, 1533 },
+{ 0xa, 166, 1, 1532 },
+{ 0x5, 168, 1, 1513 },
+{ 0x5, 169, 0, 1512 },
+{ 0x6, 159, 1, 1637 },
+{ 0x6, 160, 1, 1636 },
+{ 0x2, 160, 1, 1634 },
+{ 0x2, 161, 1, 1635 },
+{ 0x3, 162, 1, 1567 },
+{ 0x3, 163, 1, 1566 },
+{ 0x1, 163, 1, 1564 },
+{ 0x1, 164, 1, 1565 },
+{ 0x6, 165, 1, 1537 },
+{ 0x6, 166, 1, 1536 },
+{ 0x2, 166, 1, 1534 },
+{ 0x2, 167, 1, 1535 },
+{ 0x3, 168, 1, 1517 },
+{ 0x3, 169, 1, 1516 },
+{ 0x1, 169, 1, 1514 },
+{ 0x1, 170, 0, 1515 },
+{ 0x221, 159, 1, 1599 },
+{ 0x221, 160, 1, 1598 },
+{ 0x221, 165, 1, 1459 },
+{ 0x221, 166, 0, 1458 },
+{ 0x121, 159, 1, 1601 },
+{ 0x121, 160, 1, 1600 },
+{ 0x121, 165, 1, 1461 },
+{ 0x121, 166, 0, 1460 },
+{ 0xa1, 159, 1, 1603 },
+{ 0xa1, 160, 1, 1602 },
+{ 0xa1, 165, 1, 1463 },
+{ 0xa1, 166, 0, 1462 },
+{ 0x61, 159, 1, 1607 },
+{ 0x61, 160, 1, 1606 },
+{ 0x21, 160, 1, 1604 },
+{ 0x3, 161, 1, 1605 },
+{ 0x61, 165, 1, 1467 },
+{ 0x61, 166, 1, 1466 },
+{ 0x21, 166, 1, 1464 },
+{ 0x3, 167, 0, 1465 },
+{ 0x11, 159, 1, 1639 },
+{ 0x11, 160, 1, 1638 },
+{ 0x11, 165, 1, 1539 },
+{ 0x11, 166, 0, 1538 },
+{ 0x9, 159, 1, 1641 },
+{ 0x9, 160, 1, 1640 },
+{ 0x9, 165, 1, 1541 },
+{ 0x9, 166, 0, 1540 },
+{ 0x5, 159, 1, 1643 },
+{ 0x5, 160, 1, 1642 },
+{ 0x5, 165, 1, 1543 },
+{ 0x5, 166, 0, 1542 },
+{ 0x3, 159, 1, 1647 },
+{ 0x3, 160, 1, 1646 },
+{ 0x1, 160, 1, 1644 },
+{ 0x1, 161, 1, 1645 },
+{ 0x3, 165, 1, 1547 },
+{ 0x3, 166, 1, 1546 },
+{ 0x1, 166, 1, 1544 },
+{ 0x1, 167, 0, 1545 },
+{ 0x442, 205, 0, 1648 },
+{ 0x242, 205, 0, 1649 },
+{ 0x142, 205, 0, 1650 },
+{ 0xc2, 205, 1, 1652 },
+{ 0x6, 206, 1, 1651 },
+{ 0x1, 443, 0, 981 },
+{ 0x22, 205, 0, 1658 },
+{ 0x12, 205, 0, 1659 },
+{ 0xa, 205, 0, 1660 },
+{ 0x6, 205, 1, 1662 },
+{ 0x2, 206, 1, 1661 },
+{ 0x2, 367, 0, 1010 },
+{ 0x221, 205, 0, 1653 },
+{ 0x121, 205, 0, 1654 },
+{ 0xa1, 205, 0, 1655 },
+{ 0x61, 205, 1, 1657 },
+{ 0x3, 206, 1, 1656 },
+{ 0x1, 437, 0, 982 },
+{ 0x11, 205, 0, 1663 },
+{ 0x9, 205, 0, 1664 },
+{ 0x5, 205, 0, 1665 },
+{ 0x3, 205, 1, 1667 },
+{ 0x1, 206, 1, 1666 },
+{ 0x1, 367, 0, 1011 },
+{ 0x4, 211, 0, 1668 },
+{ 0x1, 211, 0, 1670 },
+{ 0x1, 218, 0, 1671 },
+{ 0x1, 217, 1, 1672 },
+{ 0x2, 211, 0, 1669 },
+{ 0x1, 196, 0, 1673 },
+{ 0x880, 202, 0, 1674 },
+{ 0x480, 202, 0, 1675 },
+{ 0x280, 202, 0, 1676 },
+{ 0x180, 202, 1, 1678 },
+{ 0x80, 203, 0, 1677 },
+{ 0x440, 202, 1, 1689 },
+{ 0x88, 204, 0, 1679 },
+{ 0x240, 202, 1, 1690 },
+{ 0x48, 204, 0, 1680 },
+{ 0x140, 202, 1, 1691 },
+{ 0x28, 204, 0, 1681 },
+{ 0xc0, 202, 1, 1693 },
+{ 0x40, 203, 1, 1692 },
+{ 0x18, 204, 1, 1683 },
+{ 0x8, 204, 0, 1682 },
+{ 0x220, 202, 1, 1694 },
+{ 0x44, 204, 0, 1684 },
+{ 0x120, 202, 1, 1695 },
+{ 0x24, 204, 0, 1685 },
+{ 0xa0, 202, 1, 1696 },
+{ 0x14, 204, 0, 1686 },
+{ 0x60, 202, 1, 1698 },
+{ 0x20, 203, 1, 1697 },
+{ 0xc, 204, 1, 1688 },
+{ 0x4, 204, 0, 1687 },
+{ 0x110, 202, 0, 1699 },
+{ 0x90, 202, 0, 1700 },
+{ 0x50, 202, 0, 1701 },
+{ 0x30, 202, 1, 1703 },
+{ 0x10, 203, 1, 1702 },
+{ 0x1, 385, 0, 974 },
+{ 0x88, 202, 0, 1704 },
+{ 0x48, 202, 0, 1705 },
+{ 0x28, 202, 0, 1706 },
+{ 0x18, 202, 1, 1708 },
+{ 0x8, 203, 1, 1707 },
+{ 0xc, 368, 0, 1007 },
+{ 0x44, 202, 1, 1719 },
+{ 0x22, 204, 0, 1709 },
+{ 0x24, 202, 1, 1720 },
+{ 0x12, 204, 0, 1710 },
+{ 0x14, 202, 1, 1721 },
+{ 0xa, 204, 0, 1711 },
+{ 0xc, 202, 1, 1723 },
+{ 0x4, 203, 1, 1722 },
+{ 0x6, 204, 1, 1713 },
+{ 0x2, 204, 1, 1712 },
+{ 0x6, 368, 0, 1008 },
+{ 0x22, 202, 1, 1724 },
+{ 0x11, 204, 0, 1714 },
+{ 0x12, 202, 1, 1725 },
+{ 0x9, 204, 0, 1715 },
+{ 0xa, 202, 1, 1726 },
+{ 0x5, 204, 0, 1716 },
+{ 0x6, 202, 1, 1728 },
+{ 0x2, 203, 1, 1727 },
+{ 0x3, 204, 1, 1718 },
+{ 0x1, 204, 1, 1717 },
+{ 0x3, 368, 0, 1009 },
+{ 0x11, 202, 0, 1729 },
+{ 0x9, 202, 0, 1730 },
+{ 0x5, 202, 0, 1731 },
+{ 0x3, 202, 1, 1733 },
+{ 0x1, 203, 0, 1732 },
+{ 0x8, 198, 0, 1734 },
+{ 0x4, 198, 0, 1735 },
+{ 0x2, 198, 0, 1736 },
+{ 0x1, 198, 1, 1738 },
+{ 0x1, 199, 1, 1737 },
+{ 0x1, 332, 0, 988 },
+{ 0x8, 200, 0, 1739 },
+{ 0x4, 200, 0, 1740 },
+{ 0x2, 200, 0, 1741 },
+{ 0x1, 200, 1, 1743 },
+{ 0x1, 201, 1, 1742 },
+{ 0x1, 331, 0, 989 },
+{ 0x8, 209, 0, 1744 },
+{ 0x4, 209, 0, 1745 },
+{ 0x2, 209, 0, 1746 },
+{ 0x1, 209, 1, 1748 },
+{ 0x1, 210, 1, 1747 },
+{ 0x1, 330, 0, 990 },
+{ 0x8, 212, 0, 1749 },
+{ 0x4, 212, 0, 1750 },
+{ 0x2, 212, 0, 1751 },
+{ 0x1, 212, 1, 1753 },
+{ 0x1, 213, 1, 1752 },
+{ 0x1, 329, 0, 991 },
+{ 0x8, 224, 0, 1754 },
+{ 0x4, 224, 0, 1755 },
+{ 0x2, 224, 0, 1756 },
+{ 0x1, 224, 1, 1758 },
+{ 0x1, 225, 0, 1757 },
+{ 0x8, 222, 0, 1759 },
+{ 0x4, 222, 0, 1760 },
+{ 0x2, 222, 0, 1761 },
+{ 0x1, 222, 1, 1763 },
+{ 0x1, 223, 0, 1762 },
+{ 0x1, 240, 0, 1764 },
+{ 0x1, 340, 0, 1765 },
+{ 0x1, 33, 0, 1766 },
+{ 0x8, 151, 0, 1767 },
+{ 0x4, 151, 0, 1768 },
+{ 0x2, 151, 0, 1769 },
+{ 0x1, 151, 1, 1771 },
+{ 0x1, 152, 0, 1770 },
+{ 0x8, 157, 0, 1772 },
+{ 0x4, 157, 0, 1773 },
+{ 0x2, 157, 0, 1774 },
+{ 0x1, 157, 1, 1776 },
+{ 0x1, 158, 0, 1775 },
+{ 0x8, 231, 0, 1777 },
+{ 0x4, 231, 0, 1778 },
+{ 0x2, 231, 0, 1779 },
+{ 0x1, 231, 1, 1781 },
+{ 0x1, 232, 0, 1780 },
+{ 0x1, 173, 0, 1782 },
+{ 0x442, 171, 0, 1783 },
+{ 0x242, 171, 0, 1784 },
+{ 0x142, 171, 0, 1785 },
+{ 0xc2, 171, 1, 1787 },
+{ 0x6, 172, 0, 1786 },
+{ 0x22, 171, 0, 1793 },
+{ 0x12, 171, 0, 1794 },
+{ 0xa, 171, 0, 1795 },
+{ 0x6, 171, 1, 1797 },
+{ 0x2, 172, 1, 1796 },
+{ 0x1, 135, 0, 1197 },
+{ 0x221, 171, 0, 1788 },
+{ 0x121, 171, 0, 1789 },
+{ 0xa1, 171, 0, 1790 },
+{ 0x61, 171, 1, 1792 },
+{ 0x3, 172, 0, 1791 },
+{ 0x11, 171, 0, 1798 },
+{ 0x9, 171, 0, 1799 },
+{ 0x5, 171, 0, 1800 },
+{ 0x3, 171, 1, 1802 },
+{ 0x1, 172, 1, 1801 },
+{ 0x1, 134, 0, 1198 },
+{ 0x1, 237, 0, 1803 },
+{ 0x1, 195, 0, 1804 },
+{ 0x1, 149, 0, 1805 },
+{ 0x1, 148, 0, 1806 },
+{ 0x4, 234, 0, 1807 },
+{ 0x2, 234, 0, 1808 },
+{ 0x1, 234, 0, 1809 },
+{ 0x1, 197, 0, 1810 },
+{ 0x2, 235, 0, 1811 },
+{ 0x1, 235, 0, 1812 },
+{ 0x4, 185, 0, 1813 },
+{ 0x2, 185, 0, 1814 },
+{ 0x1, 185, 0, 1815 },
+{ 0x4, 182, 0, 1816 },
+{ 0x1, 190, 0, 1819 },
+{ 0x1, 189, 1, 1820 },
+{ 0x2, 182, 0, 1817 },
+{ 0x1, 142, 0, 1821 },
+{ 0x1, 297, 1, 1822 },
+{ 0x1, 182, 0, 1818 },
+{ 0x8, 144, 0, 1823 },
+{ 0x4, 144, 0, 1824 },
+{ 0x2, 144, 0, 1825 },
+{ 0x1, 144, 1, 1827 },
+{ 0x1, 145, 0, 1826 },
+{ 0x8, 146, 0, 1828 },
+{ 0x4, 146, 0, 1829 },
+{ 0x2, 146, 0, 1830 },
+{ 0x1, 146, 1, 1832 },
+{ 0x1, 147, 1, 1831 },
+{ 0x1, 426, 0, 1199 },
+{ 0x8, 180, 0, 1833 },
+{ 0x4, 180, 0, 1834 },
+{ 0x2, 180, 0, 1835 },
+{ 0x1, 180, 1, 1837 },
+{ 0x1, 181, 1, 1836 },
+{ 0x1, 425, 0, 1200 },
+{ 0x8, 183, 0, 1838 },
+{ 0x4, 183, 0, 1839 },
+{ 0x2, 183, 0, 1840 },
+{ 0x1, 183, 1, 1842 },
+{ 0x1, 184, 1, 1841 },
+{ 0x1, 424, 0, 1201 },
+{ 0x8, 228, 0, 1843 },
+{ 0x4, 228, 0, 1844 },
+{ 0x2, 228, 0, 1845 },
+{ 0x1, 228, 1, 1847 },
+{ 0x1, 229, 0, 1846 },
+{ 0x8, 226, 0, 1848 },
+{ 0x4, 226, 0, 1849 },
+{ 0x2, 226, 0, 1850 },
+{ 0x1, 226, 1, 1852 },
+{ 0x1, 227, 0, 1851 },
+{ 0x8, 44, 0, 1857 },
+{ 0x18, 44, 0, 1853 },
+{ 0x4, 44, 0, 1858 },
+{ 0xc, 44, 0, 1854 },
+{ 0x2, 44, 0, 1859 },
+{ 0x6, 44, 0, 1855 },
+{ 0x1, 44, 0, 1860 },
+{ 0x3, 44, 0, 1856 },
+{ 0x51, 30, 0, 1862 },
+{ 0xd1, 30, 0, 1861 },
+{ 0x31, 30, 1, 1872 },
+{ 0x11, 31, 0, 1871 },
+{ 0x71, 30, 1, 1870 },
+{ 0x31, 31, 0, 1869 },
+{ 0x29, 30, 0, 1864 },
+{ 0x69, 30, 0, 1863 },
+{ 0x19, 30, 1, 1876 },
+{ 0x9, 31, 0, 1875 },
+{ 0x39, 30, 1, 1874 },
+{ 0x19, 31, 0, 1873 },
+{ 0x15, 30, 0, 1866 },
+{ 0x35, 30, 0, 1865 },
+{ 0xd, 30, 1, 1880 },
+{ 0x5, 31, 0, 1879 },
+{ 0x1d, 30, 1, 1878 },
+{ 0xd, 31, 0, 1877 },
+{ 0xb, 30, 0, 1868 },
+{ 0x1b, 30, 0, 1867 },
+{ 0x7, 30, 1, 1884 },
+{ 0x3, 31, 0, 1883 },
+{ 0xf, 30, 1, 1882 },
+{ 0x7, 31, 0, 1881 },
+{ 0xa2, 28, 0, 1886 },
+{ 0x1a2, 28, 0, 1885 },
+{ 0x62, 28, 1, 1896 },
+{ 0x22, 29, 0, 1895 },
+{ 0xe2, 28, 1, 1894 },
+{ 0x62, 29, 0, 1893 },
+{ 0x52, 28, 0, 1888 },
+{ 0xd2, 28, 0, 1887 },
+{ 0x32, 28, 1, 1900 },
+{ 0x12, 29, 0, 1899 },
+{ 0x72, 28, 1, 1898 },
+{ 0x32, 29, 0, 1897 },
+{ 0x2a, 28, 0, 1890 },
+{ 0x6a, 28, 0, 1889 },
+{ 0x1a, 28, 1, 1904 },
+{ 0xa, 29, 0, 1903 },
+{ 0x3a, 28, 1, 1902 },
+{ 0x1a, 29, 0, 1901 },
+{ 0x16, 28, 0, 1892 },
+{ 0x36, 28, 0, 1891 },
+{ 0xe, 28, 1, 1908 },
+{ 0x6, 29, 0, 1907 },
+{ 0x1e, 28, 1, 1906 },
+{ 0xe, 29, 0, 1905 },
+{ 0x51, 28, 0, 1910 },
+{ 0xd1, 28, 0, 1909 },
+{ 0x31, 28, 1, 1920 },
+{ 0x11, 29, 0, 1919 },
+{ 0x71, 28, 1, 1918 },
+{ 0x31, 29, 0, 1917 },
+{ 0x29, 28, 0, 1912 },
+{ 0x69, 28, 0, 1911 },
+{ 0x19, 28, 1, 1924 },
+{ 0x9, 29, 0, 1923 },
+{ 0x39, 28, 1, 1922 },
+{ 0x19, 29, 0, 1921 },
+{ 0x15, 28, 0, 1914 },
+{ 0x35, 28, 0, 1913 },
+{ 0xd, 28, 1, 1928 },
+{ 0x5, 29, 0, 1927 },
+{ 0x1d, 28, 1, 1926 },
+{ 0xd, 29, 0, 1925 },
+{ 0xb, 28, 0, 1916 },
+{ 0x1b, 28, 0, 1915 },
+{ 0x7, 28, 1, 1932 },
+{ 0x3, 29, 0, 1931 },
+{ 0xf, 28, 1, 1930 },
+{ 0x7, 29, 0, 1929 },
+{ 0x51, 26, 0, 1934 },
+{ 0xd1, 26, 0, 1933 },
+{ 0x31, 26, 1, 1944 },
+{ 0x11, 27, 0, 1943 },
+{ 0x71, 26, 1, 1942 },
+{ 0x31, 27, 0, 1941 },
+{ 0x29, 26, 0, 1936 },
+{ 0x69, 26, 0, 1935 },
+{ 0x19, 26, 1, 1948 },
+{ 0x9, 27, 0, 1947 },
+{ 0x39, 26, 1, 1946 },
+{ 0x19, 27, 0, 1945 },
+{ 0x15, 26, 0, 1938 },
+{ 0x35, 26, 0, 1937 },
+{ 0xd, 26, 1, 1952 },
+{ 0x5, 27, 0, 1951 },
+{ 0x1d, 26, 1, 1950 },
+{ 0xd, 27, 0, 1949 },
+{ 0xb, 26, 0, 1940 },
+{ 0x1b, 26, 0, 1939 },
+{ 0x7, 26, 1, 1956 },
+{ 0x3, 27, 0, 1955 },
+{ 0xf, 26, 1, 1954 },
+{ 0x7, 27, 0, 1953 },
+{ 0xa2, 24, 0, 1958 },
+{ 0x1a2, 24, 0, 1957 },
+{ 0x62, 24, 1, 1968 },
+{ 0x22, 25, 0, 1967 },
+{ 0xe2, 24, 1, 1966 },
+{ 0x62, 25, 0, 1965 },
+{ 0x52, 24, 0, 1960 },
+{ 0xd2, 24, 0, 1959 },
+{ 0x32, 24, 1, 1972 },
+{ 0x12, 25, 0, 1971 },
+{ 0x72, 24, 1, 1970 },
+{ 0x32, 25, 0, 1969 },
+{ 0x2a, 24, 0, 1962 },
+{ 0x6a, 24, 0, 1961 },
+{ 0x1a, 24, 1, 1976 },
+{ 0xa, 25, 0, 1975 },
+{ 0x3a, 24, 1, 1974 },
+{ 0x1a, 25, 0, 1973 },
+{ 0x16, 24, 0, 1964 },
+{ 0x36, 24, 0, 1963 },
+{ 0xe, 24, 1, 1980 },
+{ 0x6, 25, 0, 1979 },
+{ 0x1e, 24, 1, 1978 },
+{ 0xe, 25, 0, 1977 },
+{ 0x51, 24, 0, 1982 },
+{ 0xd1, 24, 0, 1981 },
+{ 0x31, 24, 1, 1992 },
+{ 0x11, 25, 0, 1991 },
+{ 0x71, 24, 1, 1990 },
+{ 0x31, 25, 0, 1989 },
+{ 0x29, 24, 0, 1984 },
+{ 0x69, 24, 0, 1983 },
+{ 0x19, 24, 1, 1996 },
+{ 0x9, 25, 0, 1995 },
+{ 0x39, 24, 1, 1994 },
+{ 0x19, 25, 0, 1993 },
+{ 0x15, 24, 0, 1986 },
+{ 0x35, 24, 0, 1985 },
+{ 0xd, 24, 1, 2000 },
+{ 0x5, 25, 0, 1999 },
+{ 0x1d, 24, 1, 1998 },
+{ 0xd, 25, 0, 1997 },
+{ 0xb, 24, 0, 1988 },
+{ 0x1b, 24, 0, 1987 },
+{ 0x7, 24, 1, 2004 },
+{ 0x3, 25, 0, 2003 },
+{ 0xf, 24, 1, 2002 },
+{ 0x7, 25, 0, 2001 },
+{ 0x51, 22, 1, 2030 },
+{ 0x50, 22, 0, 2006 },
+{ 0xd1, 22, 1, 2029 },
+{ 0xd0, 22, 0, 2005 },
+{ 0x31, 22, 1, 2040 },
+{ 0x30, 22, 1, 2016 },
+{ 0x11, 23, 1, 2039 },
+{ 0x10, 23, 0, 2015 },
+{ 0x71, 22, 1, 2038 },
+{ 0x70, 22, 1, 2014 },
+{ 0x31, 23, 1, 2037 },
+{ 0x30, 23, 0, 2013 },
+{ 0x29, 22, 1, 2032 },
+{ 0x28, 22, 0, 2008 },
+{ 0x69, 22, 1, 2031 },
+{ 0x68, 22, 0, 2007 },
+{ 0x19, 22, 1, 2044 },
+{ 0x18, 22, 1, 2020 },
+{ 0x9, 23, 1, 2043 },
+{ 0x8, 23, 0, 2019 },
+{ 0x39, 22, 1, 2042 },
+{ 0x38, 22, 1, 2018 },
+{ 0x19, 23, 1, 2041 },
+{ 0x18, 23, 0, 2017 },
+{ 0x15, 22, 1, 2034 },
+{ 0x14, 22, 0, 2010 },
+{ 0x35, 22, 1, 2033 },
+{ 0x34, 22, 0, 2009 },
+{ 0xd, 22, 1, 2048 },
+{ 0xc, 22, 1, 2024 },
+{ 0x5, 23, 1, 2047 },
+{ 0x4, 23, 0, 2023 },
+{ 0x1d, 22, 1, 2046 },
+{ 0x1c, 22, 1, 2022 },
+{ 0xd, 23, 1, 2045 },
+{ 0xc, 23, 0, 2021 },
+{ 0xb, 22, 1, 2036 },
+{ 0xa, 22, 0, 2012 },
+{ 0x1b, 22, 1, 2035 },
+{ 0x1a, 22, 0, 2011 },
+{ 0x7, 22, 1, 2052 },
+{ 0x6, 22, 1, 2028 },
+{ 0x3, 23, 1, 2051 },
+{ 0x2, 23, 0, 2027 },
+{ 0xf, 22, 1, 2050 },
+{ 0xe, 22, 1, 2026 },
+{ 0x7, 23, 1, 2049 },
+{ 0x6, 23, 0, 2025 },
+{ 0x8, 21, 0, 2054 },
+{ 0x18, 21, 0, 2053 },
+{ 0x1, 21, 1, 2058 },
+{ 0x2, 21, 0, 2057 },
+{ 0x3, 21, 1, 2056 },
+{ 0x4, 21, 0, 2055 },
+{ 0x1, 239, 0, 2059 },
+{ 0x1, 339, 0, 2060 },
+{ 0x14, 43, 0, 2063 },
+{ 0x34, 43, 0, 2061 },
+{ 0xc, 43, 0, 2064 },
+{ 0x1c, 43, 0, 2062 },
+{ 0x2, 43, 0, 2067 },
+{ 0x6, 43, 0, 2065 },
+{ 0x1, 43, 0, 2068 },
+{ 0x3, 43, 0, 2066 },
+{ 0x51, 19, 0, 2070 },
+{ 0xd1, 19, 0, 2069 },
+{ 0x31, 19, 1, 2080 },
+{ 0x11, 20, 0, 2079 },
+{ 0x71, 19, 1, 2078 },
+{ 0x31, 20, 0, 2077 },
+{ 0x29, 19, 0, 2072 },
+{ 0x69, 19, 0, 2071 },
+{ 0x19, 19, 1, 2084 },
+{ 0x9, 20, 0, 2083 },
+{ 0x39, 19, 1, 2082 },
+{ 0x19, 20, 0, 2081 },
+{ 0x15, 19, 0, 2074 },
+{ 0x35, 19, 0, 2073 },
+{ 0xd, 19, 1, 2088 },
+{ 0x5, 20, 0, 2087 },
+{ 0x1d, 19, 1, 2086 },
+{ 0xd, 20, 0, 2085 },
+{ 0xb, 19, 0, 2076 },
+{ 0x1b, 19, 0, 2075 },
+{ 0x7, 19, 1, 2092 },
+{ 0x3, 20, 0, 2091 },
+{ 0xf, 19, 1, 2090 },
+{ 0x7, 20, 0, 2089 },
+{ 0x1, 32, 0, 2093 },
+{ 0x2, 447, 0, 2094 },
+{ 0x1, 447, 0, 2095 },
+{ 0x1, 140, 0, 2096 },
+{ 0x2, 45, 0, 2097 },
+{ 0x1, 45, 0, 2098 },
+{ 0x1, 387, 0, 2099 },
+{ 0x2, 52, 0, 2100 },
+{ 0x1, 52, 0, 2101 },
+{ 0x1, 133, 0, 2102 },
+{ 0x51, 17, 0, 2104 },
+{ 0xd1, 17, 0, 2103 },
+{ 0x31, 17, 1, 2114 },
+{ 0x11, 18, 0, 2113 },
+{ 0x71, 17, 1, 2112 },
+{ 0x31, 18, 0, 2111 },
+{ 0x29, 17, 0, 2106 },
+{ 0x69, 17, 0, 2105 },
+{ 0x19, 17, 1, 2118 },
+{ 0x9, 18, 0, 2117 },
+{ 0x39, 17, 1, 2116 },
+{ 0x19, 18, 0, 2115 },
+{ 0x15, 17, 0, 2108 },
+{ 0x35, 17, 0, 2107 },
+{ 0xd, 17, 1, 2122 },
+{ 0x5, 18, 0, 2121 },
+{ 0x1d, 17, 1, 2120 },
+{ 0xd, 18, 0, 2119 },
+{ 0xb, 17, 0, 2110 },
+{ 0x1b, 17, 0, 2109 },
+{ 0x7, 17, 1, 2126 },
+{ 0x3, 18, 0, 2125 },
+{ 0xf, 17, 1, 2124 },
+{ 0x7, 18, 0, 2123 },
+{ 0xa20, 15, 0, 2128 },
+{ 0x1a20, 15, 0, 2127 },
+{ 0x620, 15, 1, 2138 },
+{ 0x220, 16, 0, 2137 },
+{ 0xe20, 15, 1, 2136 },
+{ 0x620, 16, 0, 2135 },
+{ 0x520, 15, 0, 2130 },
+{ 0xd20, 15, 0, 2129 },
+{ 0x320, 15, 1, 2142 },
+{ 0x120, 16, 0, 2141 },
+{ 0x720, 15, 1, 2140 },
+{ 0x320, 16, 0, 2139 },
+{ 0x2a0, 15, 0, 2132 },
+{ 0x6a0, 15, 0, 2131 },
+{ 0x1a0, 15, 1, 2146 },
+{ 0xa0, 16, 0, 2145 },
+{ 0x3a0, 15, 1, 2144 },
+{ 0x1a0, 16, 0, 2143 },
+{ 0x160, 15, 0, 2134 },
+{ 0x360, 15, 0, 2133 },
+{ 0xe0, 15, 1, 2150 },
+{ 0x60, 16, 0, 2149 },
+{ 0x1e0, 15, 1, 2148 },
+{ 0xe0, 16, 0, 2147 },
+{ 0x51, 15, 1, 2176 },
+{ 0x50, 15, 0, 2152 },
+{ 0xd1, 15, 1, 2175 },
+{ 0xd0, 15, 0, 2151 },
+{ 0x31, 15, 1, 2186 },
+{ 0x30, 15, 1, 2162 },
+{ 0x11, 16, 1, 2185 },
+{ 0x10, 16, 0, 2161 },
+{ 0x71, 15, 1, 2184 },
+{ 0x70, 15, 1, 2160 },
+{ 0x31, 16, 1, 2183 },
+{ 0x30, 16, 0, 2159 },
+{ 0x29, 15, 1, 2178 },
+{ 0x28, 15, 0, 2154 },
+{ 0x69, 15, 1, 2177 },
+{ 0x68, 15, 0, 2153 },
+{ 0x19, 15, 1, 2190 },
+{ 0x18, 15, 1, 2166 },
+{ 0x9, 16, 1, 2189 },
+{ 0x8, 16, 0, 2165 },
+{ 0x39, 15, 1, 2188 },
+{ 0x38, 15, 1, 2164 },
+{ 0x19, 16, 1, 2187 },
+{ 0x18, 16, 0, 2163 },
+{ 0x15, 15, 1, 2180 },
+{ 0x14, 15, 0, 2156 },
+{ 0x35, 15, 1, 2179 },
+{ 0x34, 15, 0, 2155 },
+{ 0xd, 15, 1, 2194 },
+{ 0xc, 15, 1, 2170 },
+{ 0x5, 16, 1, 2193 },
+{ 0x4, 16, 0, 2169 },
+{ 0x1d, 15, 1, 2192 },
+{ 0x1c, 15, 1, 2168 },
+{ 0xd, 16, 1, 2191 },
+{ 0xc, 16, 0, 2167 },
+{ 0xb, 15, 1, 2182 },
+{ 0xa, 15, 0, 2158 },
+{ 0x1b, 15, 1, 2181 },
+{ 0x1a, 15, 0, 2157 },
+{ 0x7, 15, 1, 2198 },
+{ 0x6, 15, 1, 2174 },
+{ 0x3, 16, 1, 2197 },
+{ 0x2, 16, 0, 2173 },
+{ 0xf, 15, 1, 2196 },
+{ 0xe, 15, 1, 2172 },
+{ 0x7, 16, 1, 2195 },
+{ 0x6, 16, 0, 2171 },
+{ 0x8, 14, 0, 2200 },
+{ 0x18, 14, 0, 2199 },
+{ 0x1, 14, 1, 2204 },
+{ 0x2, 14, 0, 2203 },
+{ 0x3, 14, 1, 2202 },
+{ 0x4, 14, 0, 2201 },
+{ 0x1, 109, 1, 2356 },
+{ 0x1, 110, 1, 2355 },
+{ 0x1, 111, 1, 2354 },
+{ 0x1, 112, 1, 2353 },
+{ 0x1, 113, 1, 2352 },
+{ 0x1, 114, 1, 2351 },
+{ 0x1, 115, 1, 2350 },
+{ 0x1, 116, 1, 2349 },
+{ 0x39, 41, 1, 22 },
+{ 0x19, 42, 0, 21 },
+{ 0x3, 109, 1, 2348 },
+{ 0x3, 110, 1, 2347 },
+{ 0x3, 111, 1, 2346 },
+{ 0x3, 112, 1, 2345 },
+{ 0x3, 113, 1, 2344 },
+{ 0x3, 114, 1, 2343 },
+{ 0x3, 115, 1, 2342 },
+{ 0x3, 116, 1, 2341 },
+{ 0x69, 41, 0, 11 },
+{ 0x14, 100, 1, 2336 },
+{ 0x22, 101, 1, 2333 },
+{ 0x44, 101, 1, 2335 },
+{ 0xa, 108, 1, 2334 },
+{ 0xd1, 41, 0, 9 },
+{ 0x34, 100, 1, 2208 },
+{ 0xc4, 101, 1, 2207 },
+{ 0x1c, 107, 1, 2205 },
+{ 0xe, 122, 0, 2206 },
+{ 0xc, 100, 1, 2496 },
+{ 0xa, 101, 1, 2493 },
+{ 0x14, 101, 1, 2495 },
+{ 0x6, 108, 0, 2494 },
+{ 0x2, 100, 1, 2220 },
+{ 0x2, 101, 1, 2219 },
+{ 0x2, 106, 1, 2218 },
+{ 0x2, 107, 0, 2217 },
+{ 0x12, 100, 1, 2216 },
+{ 0x42, 101, 1, 2215 },
+{ 0x6, 106, 1, 2214 },
+{ 0x6, 107, 0, 2213 },
+{ 0xa, 100, 1, 2340 },
+{ 0x12, 101, 1, 2339 },
+{ 0x24, 101, 1, 2337 },
+{ 0x5, 108, 1, 2338 },
+{ 0x71, 41, 1, 18 },
+{ 0x31, 42, 0, 17 },
+{ 0x1a, 100, 1, 2212 },
+{ 0x32, 101, 1, 2211 },
+{ 0x1a, 107, 1, 2209 },
+{ 0x7, 122, 0, 2210 },
+{ 0x6, 100, 1, 2500 },
+{ 0x6, 101, 1, 2499 },
+{ 0xc, 101, 1, 2497 },
+{ 0x3, 108, 0, 2498 },
+{ 0x1, 100, 1, 2516 },
+{ 0x1, 101, 1, 2515 },
+{ 0x1, 102, 1, 2514 },
+{ 0x1, 103, 1, 2513 },
+{ 0x1, 104, 1, 2512 },
+{ 0x1, 105, 1, 2511 },
+{ 0x1, 106, 1, 2510 },
+{ 0x1, 107, 0, 2509 },
+{ 0x3, 100, 1, 2508 },
+{ 0x3, 101, 1, 2507 },
+{ 0x3, 102, 1, 2506 },
+{ 0x3, 103, 1, 2505 },
+{ 0x3, 104, 1, 2504 },
+{ 0x3, 105, 1, 2503 },
+{ 0x3, 106, 1, 2502 },
+{ 0x3, 107, 0, 2501 },
+{ 0x8, 67, 1, 2380 },
+{ 0x8, 68, 1, 2379 },
+{ 0x2, 73, 1, 2374 },
+{ 0x2, 74, 1, 2373 },
+{ 0x1, 76, 1, 2378 },
+{ 0x1, 77, 1, 2377 },
+{ 0x1, 78, 1, 2376 },
+{ 0x1, 79, 1, 2375 },
+{ 0xf, 41, 1, 30 },
+{ 0x7, 42, 0, 29 },
+{ 0x18, 67, 1, 2372 },
+{ 0x18, 68, 1, 2371 },
+{ 0x6, 73, 1, 2366 },
+{ 0x6, 74, 1, 2365 },
+{ 0x3, 76, 1, 2370 },
+{ 0x3, 77, 1, 2369 },
+{ 0x3, 78, 1, 2368 },
+{ 0x3, 79, 1, 2367 },
+{ 0x1b, 41, 0, 15 },
+{ 0x14, 67, 1, 2360 },
+{ 0x22, 68, 1, 2357 },
+{ 0x44, 68, 1, 2359 },
+{ 0xa, 75, 1, 2358 },
+{ 0x35, 41, 0, 13 },
+{ 0x34, 67, 1, 2224 },
+{ 0xc4, 68, 1, 2223 },
+{ 0x38, 74, 1, 2221 },
+{ 0xe, 85, 0, 2222 },
+{ 0xc, 67, 1, 2520 },
+{ 0xa, 68, 1, 2517 },
+{ 0x14, 68, 1, 2519 },
+{ 0x6, 75, 0, 2518 },
+{ 0x2, 67, 1, 2236 },
+{ 0x2, 68, 1, 2235 },
+{ 0x4, 73, 1, 2234 },
+{ 0x4, 74, 0, 2233 },
+{ 0x12, 67, 1, 2232 },
+{ 0x42, 68, 1, 2231 },
+{ 0xc, 73, 1, 2230 },
+{ 0xc, 74, 0, 2229 },
+{ 0xa, 67, 1, 2364 },
+{ 0x12, 68, 1, 2363 },
+{ 0x24, 68, 1, 2361 },
+{ 0x5, 75, 1, 2362 },
+{ 0x1d, 41, 1, 26 },
+{ 0xd, 42, 0, 25 },
+{ 0x1a, 67, 1, 2228 },
+{ 0x32, 68, 1, 2227 },
+{ 0x34, 74, 1, 2225 },
+{ 0x7, 85, 0, 2226 },
+{ 0x6, 67, 1, 2524 },
+{ 0x6, 68, 1, 2523 },
+{ 0xc, 68, 1, 2521 },
+{ 0x3, 75, 0, 2522 },
+{ 0x1, 67, 1, 2540 },
+{ 0x1, 68, 1, 2539 },
+{ 0x1, 69, 1, 2538 },
+{ 0x1, 70, 1, 2537 },
+{ 0x1, 71, 1, 2536 },
+{ 0x1, 72, 1, 2535 },
+{ 0x1, 73, 1, 2534 },
+{ 0x1, 74, 0, 2533 },
+{ 0x3, 67, 1, 2532 },
+{ 0x3, 68, 1, 2531 },
+{ 0x3, 69, 1, 2530 },
+{ 0x3, 70, 1, 2529 },
+{ 0x3, 71, 1, 2528 },
+{ 0x3, 72, 1, 2527 },
+{ 0x3, 73, 1, 2526 },
+{ 0x3, 74, 0, 2525 },
+{ 0x28, 95, 1, 2388 },
+{ 0x44, 96, 1, 2383 },
+{ 0x88, 96, 1, 2387 },
+{ 0x44, 97, 1, 2382 },
+{ 0x88, 97, 1, 2386 },
+{ 0x44, 98, 1, 2381 },
+{ 0x88, 98, 1, 2385 },
+{ 0x28, 99, 0, 2384 },
+{ 0x68, 95, 1, 2244 },
+{ 0x188, 96, 1, 2243 },
+{ 0x188, 97, 1, 2242 },
+{ 0x188, 98, 1, 2241 },
+{ 0x38, 118, 1, 2240 },
+{ 0x38, 119, 1, 2239 },
+{ 0x38, 120, 1, 2238 },
+{ 0x38, 121, 0, 2237 },
+{ 0x18, 95, 1, 2548 },
+{ 0x14, 96, 1, 2543 },
+{ 0x28, 96, 1, 2547 },
+{ 0x14, 97, 1, 2542 },
+{ 0x28, 97, 1, 2546 },
+{ 0x14, 98, 1, 2541 },
+{ 0x28, 98, 1, 2545 },
+{ 0x18, 99, 0, 2544 },
+{ 0x14, 95, 1, 2396 },
+{ 0x24, 96, 1, 2395 },
+{ 0x48, 96, 1, 2391 },
+{ 0x24, 97, 1, 2394 },
+{ 0x48, 97, 1, 2390 },
+{ 0x24, 98, 1, 2393 },
+{ 0x48, 98, 1, 2389 },
+{ 0x14, 99, 0, 2392 },
+{ 0x34, 95, 1, 2252 },
+{ 0x64, 96, 1, 2251 },
+{ 0x64, 97, 1, 2250 },
+{ 0x64, 98, 1, 2249 },
+{ 0x1c, 118, 1, 2248 },
+{ 0x1c, 119, 1, 2247 },
+{ 0x1c, 120, 1, 2246 },
+{ 0x1c, 121, 0, 2245 },
+{ 0xc, 95, 1, 2556 },
+{ 0xc, 96, 1, 2555 },
+{ 0x18, 96, 1, 2551 },
+{ 0xc, 97, 1, 2554 },
+{ 0x18, 97, 1, 2550 },
+{ 0xc, 98, 1, 2553 },
+{ 0x18, 98, 1, 2549 },
+{ 0xc, 99, 0, 2552 },
+{ 0xa, 95, 1, 2404 },
+{ 0x11, 96, 1, 2399 },
+{ 0x22, 96, 1, 2403 },
+{ 0x11, 97, 1, 2398 },
+{ 0x22, 97, 1, 2402 },
+{ 0x11, 98, 1, 2397 },
+{ 0x22, 98, 1, 2401 },
+{ 0xa, 99, 0, 2400 },
+{ 0x1a, 95, 1, 2260 },
+{ 0x62, 96, 1, 2259 },
+{ 0x62, 97, 1, 2258 },
+{ 0x62, 98, 1, 2257 },
+{ 0xe, 118, 1, 2256 },
+{ 0xe, 119, 1, 2255 },
+{ 0xe, 120, 1, 2254 },
+{ 0xe, 121, 0, 2253 },
+{ 0x6, 95, 1, 2564 },
+{ 0x5, 96, 1, 2559 },
+{ 0xa, 96, 1, 2563 },
+{ 0x5, 97, 1, 2558 },
+{ 0xa, 97, 1, 2562 },
+{ 0x5, 98, 1, 2557 },
+{ 0xa, 98, 1, 2561 },
+{ 0x6, 99, 0, 2560 },
+{ 0x5, 95, 1, 2412 },
+{ 0x9, 96, 1, 2411 },
+{ 0x12, 96, 1, 2407 },
+{ 0x9, 97, 1, 2410 },
+{ 0x12, 97, 1, 2406 },
+{ 0x9, 98, 1, 2409 },
+{ 0x12, 98, 1, 2405 },
+{ 0x5, 99, 0, 2408 },
+{ 0xd, 95, 1, 2268 },
+{ 0x19, 96, 1, 2267 },
+{ 0x19, 97, 1, 2266 },
+{ 0x19, 98, 1, 2265 },
+{ 0x7, 118, 1, 2264 },
+{ 0x7, 119, 1, 2263 },
+{ 0x7, 120, 1, 2262 },
+{ 0x7, 121, 0, 2261 },
+{ 0x3, 95, 1, 2572 },
+{ 0x3, 96, 1, 2571 },
+{ 0x6, 96, 1, 2567 },
+{ 0x3, 97, 1, 2570 },
+{ 0x6, 97, 1, 2566 },
+{ 0x3, 98, 1, 2569 },
+{ 0x6, 98, 1, 2565 },
+{ 0x3, 99, 0, 2568 },
+{ 0x28, 62, 1, 2420 },
+{ 0x44, 63, 1, 2415 },
+{ 0x88, 63, 1, 2419 },
+{ 0x44, 64, 1, 2414 },
+{ 0x88, 64, 1, 2418 },
+{ 0x44, 65, 1, 2413 },
+{ 0x88, 65, 1, 2417 },
+{ 0x28, 66, 0, 2416 },
+{ 0x68, 62, 1, 2276 },
+{ 0x188, 63, 1, 2275 },
+{ 0x188, 64, 1, 2274 },
+{ 0x188, 65, 1, 2273 },
+{ 0x38, 81, 1, 2272 },
+{ 0x38, 82, 1, 2271 },
+{ 0x38, 83, 1, 2270 },
+{ 0x38, 84, 0, 2269 },
+{ 0x18, 62, 1, 2580 },
+{ 0x14, 63, 1, 2575 },
+{ 0x28, 63, 1, 2579 },
+{ 0x14, 64, 1, 2574 },
+{ 0x28, 64, 1, 2578 },
+{ 0x14, 65, 1, 2573 },
+{ 0x28, 65, 1, 2577 },
+{ 0x18, 66, 0, 2576 },
+{ 0x14, 62, 1, 2428 },
+{ 0x24, 63, 1, 2427 },
+{ 0x48, 63, 1, 2423 },
+{ 0x24, 64, 1, 2426 },
+{ 0x48, 64, 1, 2422 },
+{ 0x24, 65, 1, 2425 },
+{ 0x48, 65, 1, 2421 },
+{ 0x14, 66, 0, 2424 },
+{ 0x34, 62, 1, 2284 },
+{ 0x64, 63, 1, 2283 },
+{ 0x64, 64, 1, 2282 },
+{ 0x64, 65, 1, 2281 },
+{ 0x1c, 81, 1, 2280 },
+{ 0x1c, 82, 1, 2279 },
+{ 0x1c, 83, 1, 2278 },
+{ 0x1c, 84, 0, 2277 },
+{ 0xc, 62, 1, 2588 },
+{ 0xc, 63, 1, 2587 },
+{ 0x18, 63, 1, 2583 },
+{ 0xc, 64, 1, 2586 },
+{ 0x18, 64, 1, 2582 },
+{ 0xc, 65, 1, 2585 },
+{ 0x18, 65, 1, 2581 },
+{ 0xc, 66, 0, 2584 },
+{ 0xa, 62, 1, 2436 },
+{ 0x11, 63, 1, 2431 },
+{ 0x22, 63, 1, 2435 },
+{ 0x11, 64, 1, 2430 },
+{ 0x22, 64, 1, 2434 },
+{ 0x11, 65, 1, 2429 },
+{ 0x22, 65, 1, 2433 },
+{ 0xa, 66, 0, 2432 },
+{ 0x1a, 62, 1, 2292 },
+{ 0x62, 63, 1, 2291 },
+{ 0x62, 64, 1, 2290 },
+{ 0x62, 65, 1, 2289 },
+{ 0xe, 81, 1, 2288 },
+{ 0xe, 82, 1, 2287 },
+{ 0xe, 83, 1, 2286 },
+{ 0xe, 84, 0, 2285 },
+{ 0x6, 62, 1, 2596 },
+{ 0x5, 63, 1, 2591 },
+{ 0xa, 63, 1, 2595 },
+{ 0x5, 64, 1, 2590 },
+{ 0xa, 64, 1, 2594 },
+{ 0x5, 65, 1, 2589 },
+{ 0xa, 65, 1, 2593 },
+{ 0x6, 66, 0, 2592 },
+{ 0x5, 62, 1, 2444 },
+{ 0x9, 63, 1, 2443 },
+{ 0x12, 63, 1, 2439 },
+{ 0x9, 64, 1, 2442 },
+{ 0x12, 64, 1, 2438 },
+{ 0x9, 65, 1, 2441 },
+{ 0x12, 65, 1, 2437 },
+{ 0x5, 66, 0, 2440 },
+{ 0xd, 62, 1, 2300 },
+{ 0x19, 63, 1, 2299 },
+{ 0x19, 64, 1, 2298 },
+{ 0x19, 65, 1, 2297 },
+{ 0x7, 81, 1, 2296 },
+{ 0x7, 82, 1, 2295 },
+{ 0x7, 83, 1, 2294 },
+{ 0x7, 84, 0, 2293 },
+{ 0x3, 62, 1, 2604 },
+{ 0x3, 63, 1, 2603 },
+{ 0x6, 63, 1, 2599 },
+{ 0x3, 64, 1, 2602 },
+{ 0x6, 64, 1, 2598 },
+{ 0x3, 65, 1, 2601 },
+{ 0x6, 65, 1, 2597 },
+{ 0x3, 66, 0, 2600 },
+{ 0x8, 86, 1, 2468 },
+{ 0x8, 87, 1, 2467 },
+{ 0x2, 88, 1, 2466 },
+{ 0x2, 89, 1, 2465 },
+{ 0x2, 90, 1, 2464 },
+{ 0x2, 91, 1, 2463 },
+{ 0x2, 92, 1, 2462 },
+{ 0x2, 93, 0, 2461 },
+{ 0x18, 86, 1, 2460 },
+{ 0x18, 87, 1, 2459 },
+{ 0x6, 88, 1, 2458 },
+{ 0x6, 89, 1, 2457 },
+{ 0x6, 90, 1, 2456 },
+{ 0x6, 91, 1, 2455 },
+{ 0x6, 92, 1, 2454 },
+{ 0x6, 93, 0, 2453 },
+{ 0x14, 86, 1, 2448 },
+{ 0x22, 87, 1, 2445 },
+{ 0x44, 87, 1, 2447 },
+{ 0xa, 94, 0, 2446 },
+{ 0x34, 86, 1, 2304 },
+{ 0xc4, 87, 1, 2303 },
+{ 0x38, 93, 1, 2301 },
+{ 0xe, 117, 0, 2302 },
+{ 0xc, 86, 1, 2608 },
+{ 0xa, 87, 1, 2605 },
+{ 0x14, 87, 1, 2607 },
+{ 0x6, 94, 0, 2606 },
+{ 0x2, 86, 1, 2316 },
+{ 0x2, 87, 1, 2315 },
+{ 0x4, 92, 1, 2314 },
+{ 0x4, 93, 0, 2313 },
+{ 0x12, 86, 1, 2312 },
+{ 0x42, 87, 1, 2311 },
+{ 0xc, 92, 1, 2310 },
+{ 0xc, 93, 0, 2309 },
+{ 0xa, 86, 1, 2452 },
+{ 0x12, 87, 1, 2451 },
+{ 0x24, 87, 1, 2449 },
+{ 0x5, 94, 0, 2450 },
+{ 0x1a, 86, 1, 2308 },
+{ 0x32, 87, 1, 2307 },
+{ 0x34, 93, 1, 2305 },
+{ 0x7, 117, 0, 2306 },
+{ 0x6, 86, 1, 2612 },
+{ 0x6, 87, 1, 2611 },
+{ 0xc, 87, 1, 2609 },
+{ 0x3, 94, 0, 2610 },
+{ 0x1, 86, 1, 2628 },
+{ 0x1, 87, 1, 2627 },
+{ 0x1, 88, 1, 2626 },
+{ 0x1, 89, 1, 2625 },
+{ 0x1, 90, 1, 2624 },
+{ 0x1, 91, 1, 2623 },
+{ 0x1, 92, 1, 2622 },
+{ 0x1, 93, 0, 2621 },
+{ 0x3, 86, 1, 2620 },
+{ 0x3, 87, 1, 2619 },
+{ 0x3, 88, 1, 2618 },
+{ 0x3, 89, 1, 2617 },
+{ 0x3, 90, 1, 2616 },
+{ 0x3, 91, 1, 2615 },
+{ 0x3, 92, 1, 2614 },
+{ 0x3, 93, 0, 2613 },
+{ 0x8, 53, 1, 2492 },
+{ 0x8, 54, 1, 2491 },
+{ 0x2, 55, 1, 2490 },
+{ 0x2, 56, 1, 2489 },
+{ 0x2, 57, 1, 2488 },
+{ 0x2, 58, 1, 2487 },
+{ 0x2, 59, 1, 2486 },
+{ 0x2, 60, 0, 2485 },
+{ 0x18, 53, 1, 2484 },
+{ 0x18, 54, 1, 2483 },
+{ 0x6, 55, 1, 2482 },
+{ 0x6, 56, 1, 2481 },
+{ 0x6, 57, 1, 2480 },
+{ 0x6, 58, 1, 2479 },
+{ 0x6, 59, 1, 2478 },
+{ 0x6, 60, 0, 2477 },
+{ 0x14, 53, 1, 2472 },
+{ 0x22, 54, 1, 2469 },
+{ 0x44, 54, 1, 2471 },
+{ 0xa, 61, 0, 2470 },
+{ 0x34, 53, 1, 2320 },
+{ 0xc4, 54, 1, 2319 },
+{ 0x38, 60, 1, 2317 },
+{ 0xe, 80, 0, 2318 },
+{ 0xc, 53, 1, 2632 },
+{ 0xa, 54, 1, 2629 },
+{ 0x14, 54, 1, 2631 },
+{ 0x6, 61, 0, 2630 },
+{ 0x2, 53, 1, 2332 },
+{ 0x2, 54, 1, 2331 },
+{ 0x4, 59, 1, 2330 },
+{ 0x4, 60, 0, 2329 },
+{ 0x12, 53, 1, 2328 },
+{ 0x42, 54, 1, 2327 },
+{ 0xc, 59, 1, 2326 },
+{ 0xc, 60, 0, 2325 },
+{ 0xa, 53, 1, 2476 },
+{ 0x12, 54, 1, 2475 },
+{ 0x24, 54, 1, 2473 },
+{ 0x5, 61, 0, 2474 },
+{ 0x1a, 53, 1, 2324 },
+{ 0x32, 54, 1, 2323 },
+{ 0x34, 60, 1, 2321 },
+{ 0x7, 80, 0, 2322 },
+{ 0x6, 53, 1, 2636 },
+{ 0x6, 54, 1, 2635 },
+{ 0xc, 54, 1, 2633 },
+{ 0x3, 61, 0, 2634 },
+{ 0x1, 53, 1, 2652 },
+{ 0x1, 54, 1, 2651 },
+{ 0x1, 55, 1, 2650 },
+{ 0x1, 56, 1, 2649 },
+{ 0x1, 57, 1, 2648 },
+{ 0x1, 58, 1, 2647 },
+{ 0x1, 59, 1, 2646 },
+{ 0x1, 60, 0, 2645 },
+{ 0x3, 53, 1, 2644 },
+{ 0x3, 54, 1, 2643 },
+{ 0x3, 55, 1, 2642 },
+{ 0x3, 56, 1, 2641 },
+{ 0x3, 57, 1, 2640 },
+{ 0x3, 58, 1, 2639 },
+{ 0x3, 59, 1, 2638 },
+{ 0x3, 60, 0, 2637 },
+{ 0x1, 4, 0, 2653 },
+{ 0x1, 296, 0, 2654 },
+{ 0x1, 379, 0, 2655 },
+{ 0x1, 374, 0, 2656 },
+{ 0x2, 358, 0, 2657 },
+{ 0x1, 358, 0, 2660 },
+{ 0x2, 357, 0, 2658 },
+{ 0x1, 357, 0, 2661 },
+{ 0x2, 356, 0, 2659 },
+{ 0x1, 356, 0, 2662 },
+{ 0x1, 355, 0, 2663 },
+{ 0x1, 354, 0, 2664 },
+{ 0x2, 353, 0, 2665 },
+{ 0x1, 353, 0, 2667 },
+{ 0x2, 352, 0, 2666 },
+{ 0x1, 352, 0, 2668 },
+{ 0x1, 382, 0, 2675 },
+{ 0x8, 381, 0, 2669 },
+{ 0x4, 381, 0, 2671 },
+{ 0x2, 381, 0, 2673 },
+{ 0x1, 381, 0, 2676 },
+{ 0x8, 380, 0, 2670 },
+{ 0x4, 380, 0, 2672 },
+{ 0x2, 380, 0, 2674 },
+{ 0x1, 380, 0, 2677 },
+{ 0x1, 351, 0, 2684 },
+{ 0x8, 350, 0, 2678 },
+{ 0x4, 350, 0, 2680 },
+{ 0x2, 350, 0, 2682 },
+{ 0x1, 350, 0, 2685 },
+{ 0x8, 349, 0, 2679 },
+{ 0x4, 349, 0, 2681 },
+{ 0x2, 349, 1, 2683 },
+{ 0x4, 143, 0, 1377 },
+{ 0x1, 349, 0, 2686 },
+{ 0x1, 6, 0, 2687 },
+{ 0x1, 7, 0, 2688 },
+{ 0x1, 295, 0, 2689 },
+{ 0x1, 456, 0, 2690 },
+{ 0x1, 346, 0, 2691 },
+{ 0x1, 13, 0, 2692 },
+{ 0x1, 11, 0, 2693 },
+{ 0x1, 422, 0, 2694 },
+{ 0x1, 394, 0, 2695 },
+{ 0x1, 393, 0, 2696 },
+{ 0x1, 455, 0, 2697 },
+{ 0x1, 345, 0, 2698 },
+{ 0x1, 12, 0, 2699 },
+{ 0x1, 10, 0, 2700 },
+{ 0x1, 5, 0, 2701 },
+{ 0x1, 421, 0, 2702 },
+{ 0x1, 420, 0, 2703 },
+{ 0x1, 1, 0, 2704 },
+{ 0x1, 0, 0, 2705 },
+};
+
+
+/* ia64-opc.c -- Functions to access the compacted opcode table
+   Copyright 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
+   Written by Bob Manson of Cygnus Solutions, <manson at cygnus.com>
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   2, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+static const struct ia64_templ_desc ia64_templ_desc[16] =
+  {
+    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },	/* 0 */
+    { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" },
+    { 0, { 0, },				    "-3-" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },	/* 4 */
+    { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" },	/* 8 */
+    { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" },
+    { 0, { 0, },				    "-a-" },
+    { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" },	/* c */
+    { 0, { 0, },				    "-d-" },
+    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" },
+    { 0, { 0, },				    "-f-" },
+  };
+
+/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and
+   return the result. */
+
+static ia64_insn
+apply_completer (ia64_insn opcode, int completer_index)
+{
+  ia64_insn mask = completer_table[completer_index].mask;
+  ia64_insn bits = completer_table[completer_index].bits;
+  int shiftamt = (completer_table[completer_index].offset & 63);
+
+  mask = mask << shiftamt;
+  bits = bits << shiftamt;
+  opcode = (opcode & ~mask) | bits;
+  return opcode;
+}
+
+/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in
+   the dis_table array, and return its value.  (BITOFFSET is numbered
+   starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the
+   first byte in OP_POINTER.) */
+
+static int
+extract_op_bits (int op_pointer, int bitoffset, int bits)
+{
+  int res = 0;
+
+  op_pointer += (bitoffset / 8);
+
+  if (bitoffset % 8)
+    {
+      unsigned int op = dis_table[op_pointer++];
+      int numb = 8 - (bitoffset % 8);
+      int mask = (1 << numb) - 1;
+      int bata = (bits < numb) ? bits : numb;
+      int delta = numb - bata;
+
+      res = (res << bata) | ((op & mask) >> delta);
+      bitoffset += bata;
+      bits -= bata;
+    }
+  while (bits >= 8)
+    {
+      res = (res << 8) | (dis_table[op_pointer++] & 255);
+      bits -= 8;
+    }
+  if (bits > 0)
+    {
+      unsigned int op = (dis_table[op_pointer++] & 255);
+      res = (res << bits) | (op >> (8 - bits));
+    }
+  return res;
+}
+
+/* Examine the state machine entry at OP_POINTER in the dis_table
+   array, and extract its values into OPVAL and OP.  The length of the
+   state entry in bits is returned. */
+
+static int
+extract_op (int op_pointer, int *opval, unsigned int *op)
+{
+  int oplen = 5;
+
+  *op = dis_table[op_pointer];
+
+  if ((*op) & 0x40)
+    {
+      opval[0] = extract_op_bits (op_pointer, oplen, 5);
+      oplen += 5;
+    }
+  switch ((*op) & 0x30)
+    {
+    case 0x10:
+      {
+	opval[1] = extract_op_bits (op_pointer, oplen, 8);
+	oplen += 8;
+	opval[1] += op_pointer;
+	break;
+      }
+    case 0x20:
+      {
+	opval[1] = extract_op_bits (op_pointer, oplen, 16);
+	if (! (opval[1] & 32768))
+	  {
+	    opval[1] += op_pointer;
+	  }
+	oplen += 16;
+	break;
+      }
+    case 0x30:
+      {
+	oplen--;
+	opval[2] = extract_op_bits (op_pointer, oplen, 12);
+	oplen += 12;
+	opval[2] |= 32768;
+	break;
+      }
+    }
+  if (((*op) & 0x08) && (((*op) & 0x30) != 0x30))
+    {
+      opval[2] = extract_op_bits (op_pointer, oplen, 16);
+      oplen += 16;
+      if (! (opval[2] & 32768))
+	{
+	  opval[2] += op_pointer;
+	}
+    }
+  return oplen;
+}
+
+/* Returns a non-zero value if the opcode in the main_table list at
+   PLACE matches OPCODE and is of type TYPE. */
+
+static int
+opcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type)
+{
+  if (main_table[place].opcode_type != type)
+    {
+      return 0;
+    }
+  if (main_table[place].flags
+      & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT))
+    {
+      const struct ia64_operand *o1, *o2;
+      ia64_insn f2, f3;
+
+      if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3)
+	{
+	  o1 = elf64_ia64_operands + IA64_OPND_F2;
+	  o2 = elf64_ia64_operands + IA64_OPND_F3;
+	  (*o1->extract) (o1, opcode, &f2);
+	  (*o2->extract) (o2, opcode, &f3);
+	  if (f2 != f3)
+	    return 0;
+	}
+      else
+	{
+	  ia64_insn len, count;
+
+	  /* length must equal 64-count: */
+	  o1 = elf64_ia64_operands + IA64_OPND_LEN6;
+	  o2 = elf64_ia64_operands + main_table[place].operands[2];
+	  (*o1->extract) (o1, opcode, &len);
+	  (*o2->extract) (o2, opcode, &count);
+	  if (len != 64 - count)
+	    return 0;
+	}
+    }
+  return 1;
+}
+
+/* Find an instruction entry in the ia64_dis_names array that matches
+   opcode OPCODE and is of type TYPE.  Returns either a positive index
+   into the array, or a negative value if an entry for OPCODE could
+   not be found.  Checks all matches and returns the one with the highest
+   priority. */
+
+static int
+locate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type)
+{
+  int currtest[41];
+  int bitpos[41];
+  int op_ptr[41];
+  int currstatenum = 0;
+  short found_disent = -1;
+  short found_priority = -1;
+
+  currtest[currstatenum] = 0;
+  op_ptr[currstatenum] = 0;
+  bitpos[currstatenum] = 40;
+
+  while (1)
+    {
+      int op_pointer = op_ptr[currstatenum];
+      unsigned int op;
+      int currbitnum = bitpos[currstatenum];
+      int oplen;
+      int opval[3] = {0};
+      int next_op;
+      int currbit;
+
+      oplen = extract_op (op_pointer, opval, &op);
+
+      bitpos[currstatenum] = currbitnum;
+
+      /* Skip opval[0] bits in the instruction. */
+      if (op & 0x40)
+	{
+	  currbitnum -= opval[0];
+	}
+
+      /* The value of the current bit being tested. */
+      currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0;
+      next_op = -1;
+
+      /* We always perform the tests specified in the current state in
+	 a particular order, falling through to the next test if the
+	 previous one failed. */
+      switch (currtest[currstatenum])
+	{
+	case 0:
+	  currtest[currstatenum]++;
+	  if (currbit == 0 && (op & 0x80))
+	    {
+	      /* Check for a zero bit.  If this test solely checks for
+		 a zero bit, we can check for up to 8 consecutive zero
+		 bits (the number to check is specified by the lower 3
+		 bits in the state code.)
+
+		 If the state instruction matches, we go to the very
+		 next state instruction; otherwise, try the next test. */
+
+	      if ((op & 0xf8) == 0x80)
+		{
+		  int count = op & 0x7;
+		  int x;
+
+		  for (x = 0; x <= count; x++)
+		    {
+		      int i =
+			opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0;
+		      if (i)
+			{
+			  break;
+			}
+		    }
+		  if (x > count)
+		    {
+		      next_op = op_pointer + ((oplen + 7) / 8);
+		      currbitnum -= count;
+		      break;
+		    }
+		}
+	      else if (! currbit)
+		{
+		  next_op = op_pointer + ((oplen + 7) / 8);
+		  break;
+		}
+	    }
+	  /* FALLTHROUGH */
+	case 1:
+	  /* If the bit in the instruction is one, go to the state
+	     instruction specified by opval[1]. */
+	  currtest[currstatenum]++;
+	  if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30))
+	    {
+	      next_op = opval[1];
+	      break;
+	    }
+	  /* FALLTHROUGH */
+	case 2:
+	  /* Don't care.  Skip the current bit and go to the state
+	     instruction specified by opval[2].
+
+	     An encoding of 0x30 is special; this means that a 12-bit
+	     offset into the ia64_dis_names[] array is specified.  */
+	  currtest[currstatenum]++;
+	  if ((op & 0x08) || ((op & 0x30) == 0x30))
+	    {
+	      next_op = opval[2];
+	      break;
+	    }
+	}
+
+      /* If bit 15 is set in the address of the next state, an offset
+	 in the ia64_dis_names array was specified instead.  We then
+	 check to see if an entry in the list of opcodes matches the
+	 opcode we were given; if so, we have succeeded.  */
+
+      if ((next_op >= 0) && (next_op & 32768))
+	{
+	  short disent = next_op & 32767;
+          short priority = -1;
+
+	  if (next_op > 65535)
+	    {
+	      abort ();
+	    }
+
+	  /* Run through the list of opcodes to check, trying to find
+	     one that matches.  */
+	  while (disent >= 0)
+	    {
+	      int place = ia64_dis_names[disent].insn_index;
+
+              priority = ia64_dis_names[disent].priority;
+
+	      if (opcode_verify (opcode, place, type)
+                  && priority > found_priority)
+		{
+		  break;
+		}
+	      if (ia64_dis_names[disent].next_flag)
+		{
+		  disent++;
+		}
+	      else
+		{
+		  disent = -1;
+		}
+	    }
+
+	  if (disent >= 0)
+	    {
+              found_disent = disent;
+              found_priority = priority;
+	    }
+          /* Try the next test in this state, regardless of whether a match
+             was found. */
+          next_op = -2;
+	}
+
+      /* next_op == -1 is "back up to the previous state".
+	 next_op == -2 is "stay in this state and try the next test".
+	 Otherwise, transition to the state indicated by next_op. */
+
+      if (next_op == -1)
+	{
+	  currstatenum--;
+	  if (currstatenum < 0)
+	    {
+              return found_disent;
+	    }
+	}
+      else if (next_op >= 0)
+	{
+	  currstatenum++;
+	  bitpos[currstatenum] = currbitnum - 1;
+	  op_ptr[currstatenum] = next_op;
+	  currtest[currstatenum] = 0;
+	}
+    }
+}
+
+/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */
+
+static struct ia64_opcode *
+make_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind)
+{
+  struct ia64_opcode *res =
+    (struct ia64_opcode *) malloc (sizeof (struct ia64_opcode));
+  res->name = strdup (name);
+  res->type = main_table[place].opcode_type;
+  res->num_outputs = main_table[place].num_outputs;
+  res->opcode = opcode;
+  res->mask = main_table[place].mask;
+  res->operands[0] = main_table[place].operands[0];
+  res->operands[1] = main_table[place].operands[1];
+  res->operands[2] = main_table[place].operands[2];
+  res->operands[3] = main_table[place].operands[3];
+  res->operands[4] = main_table[place].operands[4];
+  res->flags = main_table[place].flags;
+  res->ent_index = place;
+  res->dependencies = &op_dependencies[depind];
+  return res;
+}
+
+/* Determine the ia64_opcode entry for the opcode specified by INSN
+   and TYPE.  If a valid entry is not found, return NULL. */
+static struct ia64_opcode *
+ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type)
+{
+  int disent = locate_opcode_ent (insn, type);
+
+  if (disent < 0)
+    {
+      return NULL;
+    }
+  else
+    {
+      unsigned int cb = ia64_dis_names[disent].completer_index;
+      static char name[128];
+      int place = ia64_dis_names[disent].insn_index;
+      int ci = main_table[place].completers;
+      ia64_insn tinsn = main_table[place].opcode;
+
+      strcpy (name, ia64_strings [main_table[place].name_index]);
+
+      while (cb)
+	{
+	  if (cb & 1)
+	    {
+	      int cname = completer_table[ci].name_index;
+
+	      tinsn = apply_completer (tinsn, ci);
+
+	      if (ia64_strings[cname][0] != '\0')
+		{
+		  strcat (name, ".");
+		  strcat (name, ia64_strings[cname]);
+		}
+	      if (cb != 1)
+		{
+		  ci = completer_table[ci].subentries;
+		}
+	    }
+	  else
+	    {
+	      ci = completer_table[ci].alternative;
+	    }
+	  if (ci < 0)
+	    {
+	      abort ();
+	    }
+	  cb = cb >> 1;
+	}
+      if (tinsn != (insn & main_table[place].mask))
+	{
+	  abort ();
+	}
+      return make_ia64_opcode (insn, name, place,
+                               completer_table[ci].dependencies);
+    }
+}
+
+/* Free any resources used by ENT. */
+static void
+ia64_free_opcode (struct ia64_opcode *ent)
+{
+  free ((void *)ent->name);
+  free (ent);
+}
+
+/* Disassemble ia64 instruction.  */
+
+/* Return the instruction type for OPCODE found in unit UNIT. */
+
+static enum ia64_insn_type
+unit_to_type (ia64_insn opcode, enum ia64_unit unit)
+{
+  enum ia64_insn_type type;
+  int op;
+
+  op = IA64_OP (opcode);
+
+  if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M))
+    {
+      type = IA64_TYPE_A;
+    }
+  else
+    {
+      switch (unit)
+	{
+	case IA64_UNIT_I:
+	  type = IA64_TYPE_I; break;
+	case IA64_UNIT_M:
+	  type = IA64_TYPE_M; break;
+	case IA64_UNIT_B:
+	  type = IA64_TYPE_B; break;
+	case IA64_UNIT_F:
+	  type = IA64_TYPE_F; break;
+        case IA64_UNIT_L:
+	case IA64_UNIT_X:
+	  type = IA64_TYPE_X; break;
+	default:
+	  type = -1;
+	}
+    }
+  return type;
+}
+
+int
+print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  ia64_insn t0, t1, slot[3], template, s_bit, insn;
+  int slotnum, j, status, need_comma, retval, slot_multiplier;
+  const struct ia64_operand *odesc;
+  const struct ia64_opcode *idesc;
+  const char *err, *str, *tname;
+  uint64_t value;
+  bfd_byte bundle[16];
+  enum ia64_unit unit;
+  char regname[16];
+
+  if (info->bytes_per_line == 0)
+    info->bytes_per_line = 6;
+  info->display_endian = info->endian;
+
+  slot_multiplier = info->bytes_per_line;
+  retval = slot_multiplier;
+
+  slotnum = (((long) memaddr) & 0xf) / slot_multiplier;
+  if (slotnum > 2)
+    return -1;
+
+  memaddr -= (memaddr & 0xf);
+  status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+  /* bundles are always in little-endian byte order */
+  t0 = bfd_getl64 (bundle);
+  t1 = bfd_getl64 (bundle + 8);
+  s_bit = t0 & 1;
+  template = (t0 >> 1) & 0xf;
+  slot[0] = (t0 >>  5) & 0x1ffffffffffLL;
+  slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
+  slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
+
+  tname = ia64_templ_desc[template].name;
+  if (slotnum == 0)
+    (*info->fprintf_func) (info->stream, "[%s] ", tname);
+  else
+    (*info->fprintf_func) (info->stream, "      ");
+
+  unit = ia64_templ_desc[template].exec_unit[slotnum];
+
+  if (template == 2 && slotnum == 1)
+    {
+      /* skip L slot in MLI template: */
+      slotnum = 2;
+      retval += slot_multiplier;
+    }
+
+  insn = slot[slotnum];
+
+  if (unit == IA64_UNIT_NIL)
+    goto decoding_failed;
+
+  idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit));
+  if (idesc == NULL)
+    goto decoding_failed;
+
+  /* print predicate, if any: */
+
+  if ((idesc->flags & IA64_OPCODE_NO_PRED)
+      || (insn & 0x3f) == 0)
+    (*info->fprintf_func) (info->stream, "      ");
+  else
+    (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f));
+
+  /* now the actual instruction: */
+
+  (*info->fprintf_func) (info->stream, "%s", idesc->name);
+  if (idesc->operands[0])
+    (*info->fprintf_func) (info->stream, " ");
+
+  need_comma = 0;
+  for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j)
+    {
+      odesc = elf64_ia64_operands + idesc->operands[j];
+
+      if (need_comma)
+	(*info->fprintf_func) (info->stream, ",");
+
+      if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64)
+	{
+	  /* special case of 64 bit immediate load: */
+	  value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7)
+	    | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21)
+	    | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63);
+	}
+      else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62)
+        {
+          /* 62-bit immediate for nop.x/break.x */
+          value = ((slot[1] & 0x1ffffffffffLL) << 21)
+            | (((insn >> 36) & 0x1) << 20)
+            | ((insn >> 6) & 0xfffff);
+        }
+      else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64)
+	{
+	  /* 60-bit immediate for long branches. */
+	  value = (((insn >> 13) & 0xfffff)
+		   | (((insn >> 36) & 1) << 59)
+		   | (((slot[1] >> 2) & 0x7fffffffffLL) << 20)) << 4;
+	}
+      else
+	{
+	  err = (*odesc->extract) (odesc, insn, &value);
+	  if (err)
+	    {
+	      (*info->fprintf_func) (info->stream, "%s", err);
+	      goto done;
+	    }
+	}
+
+	switch (odesc->class)
+	  {
+	  case IA64_OPND_CLASS_CST:
+	    (*info->fprintf_func) (info->stream, "%s", odesc->str);
+	    break;
+
+	  case IA64_OPND_CLASS_REG:
+	    if (odesc->str[0] == 'a' && odesc->str[1] == 'r')
+	      {
+		switch (value)
+		  {
+		  case 0: case 1: case 2: case 3:
+		  case 4: case 5: case 6: case 7:
+		    sprintf (regname, "ar.k%u", (unsigned int) value);
+		    break;
+		  case 16:	strcpy (regname, "ar.rsc"); break;
+		  case 17:	strcpy (regname, "ar.bsp"); break;
+		  case 18:	strcpy (regname, "ar.bspstore"); break;
+		  case 19:	strcpy (regname, "ar.rnat"); break;
+		  case 32:	strcpy (regname, "ar.ccv"); break;
+		  case 36:	strcpy (regname, "ar.unat"); break;
+		  case 40:	strcpy (regname, "ar.fpsr"); break;
+		  case 44:	strcpy (regname, "ar.itc"); break;
+		  case 64:	strcpy (regname, "ar.pfs"); break;
+		  case 65:	strcpy (regname, "ar.lc"); break;
+		  case 66:	strcpy (regname, "ar.ec"); break;
+		  default:
+		    sprintf (regname, "ar%u", (unsigned int) value);
+		    break;
+		  }
+		(*info->fprintf_func) (info->stream, "%s", regname);
+	      }
+	    else
+	      (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value);
+	    break;
+
+	  case IA64_OPND_CLASS_IND:
+	    (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value);
+	    break;
+
+	  case IA64_OPND_CLASS_ABS:
+	    str = 0;
+	    if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4)
+	      switch (value)
+		{
+		case 0x0: str = "@brcst"; break;
+		case 0x8: str = "@mix"; break;
+		case 0x9: str = "@shuf"; break;
+		case 0xa: str = "@alt"; break;
+		case 0xb: str = "@rev"; break;
+		}
+
+	    if (str)
+	      (*info->fprintf_func) (info->stream, "%s", str);
+	    else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED)
+              (*info->fprintf_func) (info->stream, "%" PRId64,
+                                     (int64_t) value);
+	    else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED)
+              (*info->fprintf_func) (info->stream, "%" PRIu64,
+                                     (uint64_t) value);
+	    else
+              (*info->fprintf_func) (info->stream, "0x%" PRIx64,
+                                     (uint64_t) value);
+	    break;
+
+	  case IA64_OPND_CLASS_REL:
+	    (*info->print_address_func) (memaddr + value, info);
+	    break;
+	  }
+
+      need_comma = 1;
+      if (j + 1 == idesc->num_outputs)
+	{
+	  (*info->fprintf_func) (info->stream, "=");
+	  need_comma = 0;
+	}
+    }
+  if (slotnum + 1 == ia64_templ_desc[template].group_boundary
+      || ((slotnum == 2) && s_bit))
+    (*info->fprintf_func) (info->stream, ";;");
+
+ done:
+  ia64_free_opcode ((struct ia64_opcode *)idesc);
+ failed:
+  if (slotnum == 2)
+    retval += 16 - 3*slot_multiplier;
+  return retval;
+
+ decoding_failed:
+  (*info->fprintf_func) (info->stream, "      data8 %#011llx", (long long) insn);
+  goto failed;
+}
diff --git a/qemu-0.15.x/ia64.ld b/qemu-0.15.x/ia64.ld
new file mode 100644
index 0000000..0c37796
--- /dev/null
+++ b/qemu-0.15.x/ia64.ld
@@ -0,0 +1,209 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little",
+	      "elf64-ia64-little")
+OUTPUT_ARCH(ia64)
+ENTRY(_start)
+/* __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .rela.IA_64.pltoff   : { *(.rela.IA_64.pltoff) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x00300000010070000002000001000400
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x00300000010070000002000001000400
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x00300000010070000002000001000400
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .opd            : { *(.opd) }
+  .IA_64.unwind_info   : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) }
+  .IA_64.unwind   : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x10000) + (. & (0x10000 - 1));
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(64 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  /* Ensure __gp is outside the range of any normal data.  We need to
+     do this to avoid the linker optimizing the code in op.o and getting
+     it out of sync with the relocs that we read when processing that
+     file.  A better solution might be to ensure that the dynamically
+     generated code and static qemu code share a single gp-value.  */
+  __gp = . + 0x200000;
+  .got            : { *(.got.plt) *(.got) }
+  .IA_64.pltoff   : { *(.IA_64.pltoff) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .);
+    PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .);
+    PROVIDE (___sbss_end = .);
+  }
+  .bss            :
+  {
+   . += 0x400000;	/* ensure .bss stuff is out of reach of gp */
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(64 / 8);
+  }
+  . = ALIGN(64 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/qemu-0.15.x/input.c b/qemu-0.15.x/input.c
new file mode 100644
index 0000000..310bad5
--- /dev/null
+++ b/qemu-0.15.x/input.c
@@ -0,0 +1,304 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "sysemu.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "qjson.h"
+
+static QEMUPutKBDEvent *qemu_put_kbd_event;
+static void *qemu_put_kbd_event_opaque;
+static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
+static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
+    QTAILQ_HEAD_INITIALIZER(mouse_handlers);
+static NotifierList mouse_mode_notifiers = 
+    NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
+
+void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+{
+    qemu_put_kbd_event_opaque = opaque;
+    qemu_put_kbd_event = func;
+}
+
+void qemu_remove_kbd_event_handler(void)
+{
+    qemu_put_kbd_event_opaque = NULL;
+    qemu_put_kbd_event = NULL;
+}
+
+static void check_mode_change(void)
+{
+    static int current_is_absolute, current_has_absolute;
+    int is_absolute;
+    int has_absolute;
+
+    is_absolute = kbd_mouse_is_absolute();
+    has_absolute = kbd_mouse_has_absolute();
+
+    if (is_absolute != current_is_absolute ||
+        has_absolute != current_has_absolute) {
+        notifier_list_notify(&mouse_mode_notifiers, NULL);
+    }
+
+    current_is_absolute = is_absolute;
+    current_has_absolute = has_absolute;
+}
+
+QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+                                                void *opaque, int absolute,
+                                                const char *name)
+{
+    QEMUPutMouseEntry *s;
+    static int mouse_index = 0;
+
+    s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
+
+    s->qemu_put_mouse_event = func;
+    s->qemu_put_mouse_event_opaque = opaque;
+    s->qemu_put_mouse_event_absolute = absolute;
+    s->qemu_put_mouse_event_name = qemu_strdup(name);
+    s->index = mouse_index++;
+
+    QTAILQ_INSERT_TAIL(&mouse_handlers, s, node);
+
+    check_mode_change();
+
+    return s;
+}
+
+void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
+{
+    QTAILQ_REMOVE(&mouse_handlers, entry, node);
+    QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node);
+
+    check_mode_change();
+}
+
+void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
+{
+    QTAILQ_REMOVE(&mouse_handlers, entry, node);
+
+    qemu_free(entry->qemu_put_mouse_event_name);
+    qemu_free(entry);
+
+    check_mode_change();
+}
+
+QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
+                                            void *opaque)
+{
+    QEMUPutLEDEntry *s;
+
+    s = qemu_mallocz(sizeof(QEMUPutLEDEntry));
+
+    s->put_led = func;
+    s->opaque = opaque;
+    QTAILQ_INSERT_TAIL(&led_handlers, s, next);
+    return s;
+}
+
+void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
+{
+    if (entry == NULL)
+        return;
+    QTAILQ_REMOVE(&led_handlers, entry, next);
+    qemu_free(entry);
+}
+
+void kbd_put_keycode(int keycode)
+{
+    if (qemu_put_kbd_event) {
+        qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
+    }
+}
+
+void kbd_put_ledstate(int ledstate)
+{
+    QEMUPutLEDEntry *cursor;
+
+    QTAILQ_FOREACH(cursor, &led_handlers, next) {
+        cursor->put_led(cursor->opaque, ledstate);
+    }
+}
+
+void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
+{
+    QEMUPutMouseEntry *entry;
+    QEMUPutMouseEvent *mouse_event;
+    void *mouse_event_opaque;
+    int width, height;
+
+    if (QTAILQ_EMPTY(&mouse_handlers)) {
+        return;
+    }
+
+    entry = QTAILQ_FIRST(&mouse_handlers);
+
+    mouse_event = entry->qemu_put_mouse_event;
+    mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
+
+    if (mouse_event) {
+        if (entry->qemu_put_mouse_event_absolute) {
+            width = 0x7fff;
+            height = 0x7fff;
+        } else {
+            width = graphic_width - 1;
+            height = graphic_height - 1;
+        }
+
+        switch (graphic_rotate) {
+        case 0:
+            mouse_event(mouse_event_opaque,
+                        dx, dy, dz, buttons_state);
+            break;
+        case 90:
+            mouse_event(mouse_event_opaque,
+                        width - dy, dx, dz, buttons_state);
+            break;
+        case 180:
+            mouse_event(mouse_event_opaque,
+                        width - dx, height - dy, dz, buttons_state);
+            break;
+        case 270:
+            mouse_event(mouse_event_opaque,
+                        dy, height - dx, dz, buttons_state);
+            break;
+        }
+    }
+}
+
+int kbd_mouse_is_absolute(void)
+{
+    if (QTAILQ_EMPTY(&mouse_handlers)) {
+        return 0;
+    }
+
+    return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute;
+}
+
+int kbd_mouse_has_absolute(void)
+{
+    QEMUPutMouseEntry *entry;
+
+    QTAILQ_FOREACH(entry, &mouse_handlers, node) {
+        if (entry->qemu_put_mouse_event_absolute) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void info_mice_iter(QObject *data, void *opaque)
+{
+    QDict *mouse;
+    Monitor *mon = opaque;
+
+    mouse = qobject_to_qdict(data);
+    monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
+                  (qdict_get_bool(mouse, "current") ? '*' : ' '),
+                   qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
+                   qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
+}
+
+void do_info_mice_print(Monitor *mon, const QObject *data)
+{
+    QList *mice_list;
+
+    mice_list = qobject_to_qlist(data);
+    if (qlist_empty(mice_list)) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    qlist_iter(mice_list, info_mice_iter, mon);
+}
+
+void do_info_mice(Monitor *mon, QObject **ret_data)
+{
+    QEMUPutMouseEntry *cursor;
+    QList *mice_list;
+    int current;
+
+    mice_list = qlist_new();
+
+    if (QTAILQ_EMPTY(&mouse_handlers)) {
+        goto out;
+    }
+
+    current = QTAILQ_FIRST(&mouse_handlers)->index;
+
+    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
+        QObject *obj;
+        obj = qobject_from_jsonf("{ 'name': %s,"
+                                 "  'index': %d,"
+                                 "  'current': %i,"
+                                 "  'absolute': %i }",
+                                 cursor->qemu_put_mouse_event_name,
+                                 cursor->index,
+                                 cursor->index == current,
+                                 !!cursor->qemu_put_mouse_event_absolute);
+        qlist_append_obj(mice_list, obj);
+    }
+
+out:
+    *ret_data = QOBJECT(mice_list);
+}
+
+void do_mouse_set(Monitor *mon, const QDict *qdict)
+{
+    QEMUPutMouseEntry *cursor;
+    int index = qdict_get_int(qdict, "index");
+    int found = 0;
+
+    if (QTAILQ_EMPTY(&mouse_handlers)) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
+        if (cursor->index == index) {
+            found = 1;
+            qemu_activate_mouse_event_handler(cursor);
+            break;
+        }
+    }
+
+    if (!found) {
+        monitor_printf(mon, "Mouse at given index not found\n");
+    }
+
+    check_mode_change();
+}
+
+void qemu_add_mouse_mode_change_notifier(Notifier *notify)
+{
+    notifier_list_add(&mouse_mode_notifiers, notify);
+}
+
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
+{
+    notifier_list_remove(&mouse_mode_notifiers, notify);
+}
diff --git a/qemu-0.15.x/iohandler.c b/qemu-0.15.x/iohandler.c
new file mode 100644
index 0000000..2b82421
--- /dev/null
+++ b/qemu-0.15.x/iohandler.c
@@ -0,0 +1,193 @@
+/*
+ * QEMU System Emulator - managing I/O handler
+ *
+ * Copyright (c) 2003-2008 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 "config-host.h"
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "qemu-queue.h"
+
+#ifndef _WIN32
+#include <sys/wait.h>
+#endif
+
+typedef struct IOHandlerRecord {
+    int fd;
+    IOCanReadHandler *fd_read_poll;
+    IOHandler *fd_read;
+    IOHandler *fd_write;
+    int deleted;
+    void *opaque;
+    QLIST_ENTRY(IOHandlerRecord) next;
+} IOHandlerRecord;
+
+static QLIST_HEAD(, IOHandlerRecord) io_handlers =
+    QLIST_HEAD_INITIALIZER(io_handlers);
+
+
+/* XXX: fd_read_poll should be suppressed, but an API change is
+   necessary in the character devices to suppress fd_can_read(). */
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    IOHandlerRecord *ioh;
+
+    if (!fd_read && !fd_write) {
+        QLIST_FOREACH(ioh, &io_handlers, next) {
+            if (ioh->fd == fd) {
+                ioh->deleted = 1;
+                break;
+            }
+        }
+    } else {
+        QLIST_FOREACH(ioh, &io_handlers, next) {
+            if (ioh->fd == fd)
+                goto found;
+        }
+        ioh = qemu_mallocz(sizeof(IOHandlerRecord));
+        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
+    found:
+        ioh->fd = fd;
+        ioh->fd_read_poll = fd_read_poll;
+        ioh->fd_read = fd_read;
+        ioh->fd_write = fd_write;
+        ioh->opaque = opaque;
+        ioh->deleted = 0;
+    }
+    return 0;
+}
+
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque)
+{
+    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
+}
+
+void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    IOHandlerRecord *ioh;
+
+    QLIST_FOREACH(ioh, &io_handlers, next) {
+        if (ioh->deleted)
+            continue;
+        if (ioh->fd_read &&
+            (!ioh->fd_read_poll ||
+             ioh->fd_read_poll(ioh->opaque) != 0)) {
+            FD_SET(ioh->fd, readfds);
+            if (ioh->fd > *pnfds)
+                *pnfds = ioh->fd;
+        }
+        if (ioh->fd_write) {
+            FD_SET(ioh->fd, writefds);
+            if (ioh->fd > *pnfds)
+                *pnfds = ioh->fd;
+        }
+    }
+}
+
+void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret)
+{
+    if (ret > 0) {
+        IOHandlerRecord *pioh, *ioh;
+
+        QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
+            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) {
+                ioh->fd_read(ioh->opaque);
+            }
+            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) {
+                ioh->fd_write(ioh->opaque);
+            }
+
+            /* Do this last in case read/write handlers marked it for deletion */
+            if (ioh->deleted) {
+                QLIST_REMOVE(ioh, next);
+                qemu_free(ioh);
+            }
+        }
+    }
+}
+
+/* reaping of zombies.  right now we're not passing the status to
+   anyone, but it would be possible to add a callback.  */
+#ifndef _WIN32
+typedef struct ChildProcessRecord {
+    int pid;
+    QLIST_ENTRY(ChildProcessRecord) next;
+} ChildProcessRecord;
+
+static QLIST_HEAD(, ChildProcessRecord) child_watches =
+    QLIST_HEAD_INITIALIZER(child_watches);
+
+static QEMUBH *sigchld_bh;
+
+static void sigchld_handler(int signal)
+{
+    qemu_bh_schedule(sigchld_bh);
+}
+
+static void sigchld_bh_handler(void *opaque)
+{
+    ChildProcessRecord *rec, *next;
+
+    QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
+        if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
+            QLIST_REMOVE(rec, next);
+            qemu_free(rec);
+        }
+    }
+}
+
+static void qemu_init_child_watch(void)
+{
+    struct sigaction act;
+    sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, NULL);
+}
+
+int qemu_add_child_watch(pid_t pid)
+{
+    ChildProcessRecord *rec;
+
+    if (!sigchld_bh) {
+        qemu_init_child_watch();
+    }
+
+    QLIST_FOREACH(rec, &child_watches, next) {
+        if (rec->pid == pid) {
+            return 1;
+        }
+    }
+    rec = qemu_mallocz(sizeof(ChildProcessRecord));
+    rec->pid = pid;
+    QLIST_INSERT_HEAD(&child_watches, rec, next);
+    return 0;
+}
+#endif
diff --git a/qemu-0.15.x/ioport-user.c b/qemu-0.15.x/ioport-user.c
new file mode 100644
index 0000000..03fac22
--- /dev/null
+++ b/qemu-0.15.x/ioport-user.c
@@ -0,0 +1,60 @@
+/*
+ *  qemu user ioport functions
+ *
+ *  Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+#include "ioport.h"
+
+void cpu_outb(pio_addr_t addr, uint8_t val)
+{
+    fprintf(stderr, "outb: port=0x%04"FMT_pioaddr", data=%02"PRIx8"\n",
+            addr, val);
+}
+
+void cpu_outw(pio_addr_t addr, uint16_t val)
+{
+    fprintf(stderr, "outw: port=0x%04"FMT_pioaddr", data=%04"PRIx16"\n",
+            addr, val);
+}
+
+void cpu_outl(pio_addr_t addr, uint32_t val)
+{
+    fprintf(stderr, "outl: port=0x%04"FMT_pioaddr", data=%08"PRIx32"\n",
+            addr, val);
+}
+
+uint8_t cpu_inb(pio_addr_t addr)
+{
+    fprintf(stderr, "inb: port=0x%04"FMT_pioaddr"\n", addr);
+    return 0;
+}
+
+uint16_t cpu_inw(pio_addr_t addr)
+{
+    fprintf(stderr, "inw: port=0x%04"FMT_pioaddr"\n", addr);
+    return 0;
+}
+
+uint32_t cpu_inl(pio_addr_t addr)
+{
+    fprintf(stderr, "inl: port=0x%04"FMT_pioaddr"\n", addr);
+    return 0;
+}
diff --git a/qemu-0.15.x/ioport.c b/qemu-0.15.x/ioport.c
new file mode 100644
index 0000000..0d2611d
--- /dev/null
+++ b/qemu-0.15.x/ioport.c
@@ -0,0 +1,315 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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.
+ */
+/*
+ * splitted out ioport related stuffs from vl.c.
+ */
+
+#include "ioport.h"
+#include "trace.h"
+
+/***********************************************************/
+/* IO Port */
+
+//#define DEBUG_UNUSED_IOPORT
+//#define DEBUG_IOPORT
+
+#ifdef DEBUG_UNUSED_IOPORT
+#  define LOG_UNUSED_IOPORT(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
+#else
+#  define LOG_UNUSED_IOPORT(fmt, ...) do{ } while (0)
+#endif
+
+#ifdef DEBUG_IOPORT
+#  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
+#else
+#  define LOG_IOPORT(...) do { } while (0)
+#endif
+
+/* XXX: use a two level table to limit memory usage */
+
+static void *ioport_opaque[MAX_IOPORTS];
+static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
+static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
+
+static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
+static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
+
+static uint32_t ioport_read(int index, uint32_t address)
+{
+    static IOPortReadFunc * const default_func[3] = {
+        default_ioport_readb,
+        default_ioport_readw,
+        default_ioport_readl
+    };
+    IOPortReadFunc *func = ioport_read_table[index][address];
+    if (!func)
+        func = default_func[index];
+    return func(ioport_opaque[address], address);
+}
+
+static void ioport_write(int index, uint32_t address, uint32_t data)
+{
+    static IOPortWriteFunc * const default_func[3] = {
+        default_ioport_writeb,
+        default_ioport_writew,
+        default_ioport_writel
+    };
+    IOPortWriteFunc *func = ioport_write_table[index][address];
+    if (!func)
+        func = default_func[index];
+    func(ioport_opaque[address], address, data);
+}
+
+static uint32_t default_ioport_readb(void *opaque, uint32_t address)
+{
+    LOG_UNUSED_IOPORT("unused inb: port=0x%04"PRIx32"\n", address);
+    return 0xff;
+}
+
+static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
+{
+    LOG_UNUSED_IOPORT("unused outb: port=0x%04"PRIx32" data=0x%02"PRIx32"\n",
+                      address, data);
+}
+
+/* default is to make two byte accesses */
+static uint32_t default_ioport_readw(void *opaque, uint32_t address)
+{
+    uint32_t data;
+    data = ioport_read(0, address);
+    address = (address + 1) & IOPORTS_MASK;
+    data |= ioport_read(0, address) << 8;
+    return data;
+}
+
+static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
+{
+    ioport_write(0, address, data & 0xff);
+    address = (address + 1) & IOPORTS_MASK;
+    ioport_write(0, address, (data >> 8) & 0xff);
+}
+
+static uint32_t default_ioport_readl(void *opaque, uint32_t address)
+{
+    LOG_UNUSED_IOPORT("unused inl: port=0x%04"PRIx32"\n", address);
+    return 0xffffffff;
+}
+
+static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
+{
+    LOG_UNUSED_IOPORT("unused outl: port=0x%04"PRIx32" data=0x%02"PRIx32"\n",
+                      address, data);
+}
+
+static int ioport_bsize(int size, int *bsize)
+{
+    if (size == 1) {
+        *bsize = 0;
+    } else if (size == 2) {
+        *bsize = 1;
+    } else if (size == 4) {
+        *bsize = 2;
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+/* size is the word size in byte */
+int register_ioport_read(pio_addr_t start, int length, int size,
+                         IOPortReadFunc *func, void *opaque)
+{
+    int i, bsize;
+
+    if (ioport_bsize(size, &bsize)) {
+        hw_error("register_ioport_read: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+        ioport_read_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_read: invalid opaque for address 0x%x",
+                     i);
+        ioport_opaque[i] = opaque;
+    }
+    return 0;
+}
+
+/* size is the word size in byte */
+int register_ioport_write(pio_addr_t start, int length, int size,
+                          IOPortWriteFunc *func, void *opaque)
+{
+    int i, bsize;
+
+    if (ioport_bsize(size, &bsize)) {
+        hw_error("register_ioport_write: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+        ioport_write_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_write: invalid opaque for address 0x%x",
+                     i);
+        ioport_opaque[i] = opaque;
+    }
+    return 0;
+}
+
+static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 1, &data);
+    return data;
+}
+
+static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 2, &data);
+    return data;
+}
+
+static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 4, &data);
+    return data;
+}
+
+static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 1, data);
+}
+
+static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 2, data);
+}
+
+static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 4, data);
+}
+
+void ioport_register(IORange *ioport)
+{
+    register_ioport_read(ioport->base, ioport->len, 1,
+                         ioport_readb_thunk, ioport);
+    register_ioport_read(ioport->base, ioport->len, 2,
+                         ioport_readw_thunk, ioport);
+    register_ioport_read(ioport->base, ioport->len, 4,
+                         ioport_readl_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 1,
+                          ioport_writeb_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 2,
+                          ioport_writew_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 4,
+                          ioport_writel_thunk, ioport);
+}
+
+void isa_unassign_ioport(pio_addr_t start, int length)
+{
+    int i;
+
+    for(i = start; i < start + length; i++) {
+        ioport_read_table[0][i] = NULL;
+        ioport_read_table[1][i] = NULL;
+        ioport_read_table[2][i] = NULL;
+
+        ioport_write_table[0][i] = NULL;
+        ioport_write_table[1][i] = NULL;
+        ioport_write_table[2][i] = NULL;
+
+        ioport_opaque[i] = NULL;
+    }
+}
+
+bool isa_is_ioport_assigned(pio_addr_t start)
+{
+    return (ioport_read_table[0][start] || ioport_write_table[0][start] ||
+	    ioport_read_table[1][start] || ioport_write_table[1][start] ||
+	    ioport_read_table[2][start] || ioport_write_table[2][start]);
+}
+
+/***********************************************************/
+
+void cpu_outb(pio_addr_t addr, uint8_t val)
+{
+    LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
+    trace_cpu_out(addr, val);
+    ioport_write(0, addr, val);
+}
+
+void cpu_outw(pio_addr_t addr, uint16_t val)
+{
+    LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
+    trace_cpu_out(addr, val);
+    ioport_write(1, addr, val);
+}
+
+void cpu_outl(pio_addr_t addr, uint32_t val)
+{
+    LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
+    trace_cpu_out(addr, val);
+    ioport_write(2, addr, val);
+}
+
+uint8_t cpu_inb(pio_addr_t addr)
+{
+    uint8_t val;
+    val = ioport_read(0, addr);
+    trace_cpu_in(addr, val);
+    LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
+    return val;
+}
+
+uint16_t cpu_inw(pio_addr_t addr)
+{
+    uint16_t val;
+    val = ioport_read(1, addr);
+    trace_cpu_in(addr, val);
+    LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
+    return val;
+}
+
+uint32_t cpu_inl(pio_addr_t addr)
+{
+    uint32_t val;
+    val = ioport_read(2, addr);
+    trace_cpu_in(addr, val);
+    LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
+    return val;
+}
diff --git a/qemu-0.15.x/ioport.h b/qemu-0.15.x/ioport.h
new file mode 100644
index 0000000..82ffd9d
--- /dev/null
+++ b/qemu-0.15.x/ioport.h
@@ -0,0 +1,55 @@
+/*
+ * defines ioport related functions
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**************************************************************************
+ * IO ports API
+ */
+
+#ifndef IOPORT_H
+#define IOPORT_H
+
+#include "qemu-common.h"
+#include "iorange.h"
+
+typedef uint32_t pio_addr_t;
+#define FMT_pioaddr     PRIx32
+
+#define MAX_IOPORTS     (64 * 1024)
+#define IOPORTS_MASK    (MAX_IOPORTS - 1)
+
+/* These should really be in isa.h, but are here to make pc.h happy.  */
+typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
+typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
+
+void ioport_register(IORange *iorange);
+int register_ioport_read(pio_addr_t start, int length, int size,
+                         IOPortReadFunc *func, void *opaque);
+int register_ioport_write(pio_addr_t start, int length, int size,
+                          IOPortWriteFunc *func, void *opaque);
+void isa_unassign_ioport(pio_addr_t start, int length);
+bool isa_is_ioport_assigned(pio_addr_t start);
+
+void cpu_outb(pio_addr_t addr, uint8_t val);
+void cpu_outw(pio_addr_t addr, uint16_t val);
+void cpu_outl(pio_addr_t addr, uint32_t val);
+uint8_t cpu_inb(pio_addr_t addr);
+uint16_t cpu_inw(pio_addr_t addr);
+uint32_t cpu_inl(pio_addr_t addr);
+
+#endif /* IOPORT_H */
diff --git a/qemu-0.15.x/iorange.h b/qemu-0.15.x/iorange.h
new file mode 100644
index 0000000..9783168
--- /dev/null
+++ b/qemu-0.15.x/iorange.h
@@ -0,0 +1,30 @@
+#ifndef IORANGE_H
+#define IORANGE_H
+
+#include <stdint.h>
+
+typedef struct IORange IORange;
+typedef struct IORangeOps IORangeOps;
+
+struct IORangeOps {
+    void (*read)(IORange *iorange, uint64_t offset, unsigned width,
+                 uint64_t *data);
+    void (*write)(IORange *iorange, uint64_t offset, unsigned width,
+                  uint64_t data);
+};
+
+struct IORange {
+    const IORangeOps *ops;
+    uint64_t base;
+    uint64_t len;
+};
+
+static inline void iorange_init(IORange *iorange, const IORangeOps *ops,
+                                uint64_t base, uint64_t len)
+{
+    iorange->ops = ops;
+    iorange->base = base;
+    iorange->len = len;
+}
+
+#endif
diff --git a/qemu-0.15.x/iov.c b/qemu-0.15.x/iov.c
new file mode 100644
index 0000000..1e02791
--- /dev/null
+++ b/qemu-0.15.x/iov.c
@@ -0,0 +1,75 @@
+/*
+ * Helpers for getting linearized buffers from iov / filling buffers into iovs
+ *
+ * Copyright IBM, Corp. 2007, 2008
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * Author(s):
+ *  Anthony Liguori <aliguori at us.ibm.com>
+ *  Amit Shah <amit.shah at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "iov.h"
+
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size)
+{
+    size_t iovec_off, buf_off;
+    unsigned int i;
+
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off, size);
+
+            memcpy(iov[i].iov_base + (iov_off - iovec_off), buf + buf_off, len);
+
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
+    }
+    return buf_off;
+}
+
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size)
+{
+    uint8_t *ptr;
+    size_t iovec_off, buf_off;
+    unsigned int i;
+
+    ptr = buf;
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
+
+            memcpy(ptr + buf_off, iov[i].iov_base + (iov_off - iovec_off), len);
+
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
+    }
+    return buf_off;
+}
+
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
+{
+    size_t len;
+    unsigned int i;
+
+    len = 0;
+    for (i = 0; i < iov_cnt; i++) {
+        len += iov[i].iov_len;
+    }
+    return len;
+}
diff --git a/qemu-0.15.x/iov.h b/qemu-0.15.x/iov.h
new file mode 100644
index 0000000..110f67a
--- /dev/null
+++ b/qemu-0.15.x/iov.h
@@ -0,0 +1,19 @@
+/*
+ * Helpers for getting linearized buffers from iov / filling buffers into iovs
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * Author(s):
+ *  Amit Shah <amit.shah at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
+                    const void *buf, size_t iov_off, size_t size);
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                  void *buf, size_t iov_off, size_t size);
+size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
diff --git a/qemu-0.15.x/json-lexer.c b/qemu-0.15.x/json-lexer.c
new file mode 100644
index 0000000..c21338f
--- /dev/null
+++ b/qemu-0.15.x/json-lexer.c
@@ -0,0 +1,372 @@
+/*
+ * JSON lexer
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qstring.h"
+#include "qlist.h"
+#include "qdict.h"
+#include "qint.h"
+#include "qemu-common.h"
+#include "json-lexer.h"
+
+#define MAX_TOKEN_SIZE (64ULL << 20)
+
+/*
+ * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
+ * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
+ * 0|([1-9][0-9]*(.[0-9]+)?([eE]([-+])?[0-9]+))
+ * [{}\[\],:]
+ * [a-z]+
+ *
+ */
+
+enum json_lexer_state {
+    IN_ERROR = 0,
+    IN_DQ_UCODE3,
+    IN_DQ_UCODE2,
+    IN_DQ_UCODE1,
+    IN_DQ_UCODE0,
+    IN_DQ_STRING_ESCAPE,
+    IN_DQ_STRING,
+    IN_SQ_UCODE3,
+    IN_SQ_UCODE2,
+    IN_SQ_UCODE1,
+    IN_SQ_UCODE0,
+    IN_SQ_STRING_ESCAPE,
+    IN_SQ_STRING,
+    IN_ZERO,
+    IN_DIGITS,
+    IN_DIGIT,
+    IN_EXP_E,
+    IN_MANTISSA,
+    IN_MANTISSA_DIGITS,
+    IN_NONZERO_NUMBER,
+    IN_NEG_NONZERO_NUMBER,
+    IN_KEYWORD,
+    IN_ESCAPE,
+    IN_ESCAPE_L,
+    IN_ESCAPE_LL,
+    IN_ESCAPE_I,
+    IN_ESCAPE_I6,
+    IN_ESCAPE_I64,
+    IN_WHITESPACE,
+    IN_START,
+};
+
+#define TERMINAL(state) [0 ... 0x7F] = (state)
+
+/* Return whether TERMINAL is a terminal state and the transition to it
+   from OLD_STATE required lookahead.  This happens whenever the table
+   below uses the TERMINAL macro.  */
+#define TERMINAL_NEEDED_LOOKAHEAD(old_state, terminal) \
+            (json_lexer[(old_state)][0] == (terminal))
+
+static const uint8_t json_lexer[][256] =  {
+    /* double quote string */
+    [IN_DQ_UCODE3] = {
+        ['0' ... '9'] = IN_DQ_STRING,
+        ['a' ... 'f'] = IN_DQ_STRING,
+        ['A' ... 'F'] = IN_DQ_STRING,
+    },
+    [IN_DQ_UCODE2] = {
+        ['0' ... '9'] = IN_DQ_UCODE3,
+        ['a' ... 'f'] = IN_DQ_UCODE3,
+        ['A' ... 'F'] = IN_DQ_UCODE3,
+    },
+    [IN_DQ_UCODE1] = {
+        ['0' ... '9'] = IN_DQ_UCODE2,
+        ['a' ... 'f'] = IN_DQ_UCODE2,
+        ['A' ... 'F'] = IN_DQ_UCODE2,
+    },
+    [IN_DQ_UCODE0] = {
+        ['0' ... '9'] = IN_DQ_UCODE1,
+        ['a' ... 'f'] = IN_DQ_UCODE1,
+        ['A' ... 'F'] = IN_DQ_UCODE1,
+    },
+    [IN_DQ_STRING_ESCAPE] = {
+        ['b'] = IN_DQ_STRING,
+        ['f'] =  IN_DQ_STRING,
+        ['n'] =  IN_DQ_STRING,
+        ['r'] =  IN_DQ_STRING,
+        ['t'] =  IN_DQ_STRING,
+        ['/'] = IN_DQ_STRING,
+        ['\\'] = IN_DQ_STRING,
+        ['\''] = IN_DQ_STRING,
+        ['\"'] = IN_DQ_STRING,
+        ['u'] = IN_DQ_UCODE0,
+    },
+    [IN_DQ_STRING] = {
+        [1 ... 0xBF] = IN_DQ_STRING,
+        [0xC2 ... 0xF4] = IN_DQ_STRING,
+        ['\\'] = IN_DQ_STRING_ESCAPE,
+        ['"'] = JSON_STRING,
+    },
+
+    /* single quote string */
+    [IN_SQ_UCODE3] = {
+        ['0' ... '9'] = IN_SQ_STRING,
+        ['a' ... 'f'] = IN_SQ_STRING,
+        ['A' ... 'F'] = IN_SQ_STRING,
+    },
+    [IN_SQ_UCODE2] = {
+        ['0' ... '9'] = IN_SQ_UCODE3,
+        ['a' ... 'f'] = IN_SQ_UCODE3,
+        ['A' ... 'F'] = IN_SQ_UCODE3,
+    },
+    [IN_SQ_UCODE1] = {
+        ['0' ... '9'] = IN_SQ_UCODE2,
+        ['a' ... 'f'] = IN_SQ_UCODE2,
+        ['A' ... 'F'] = IN_SQ_UCODE2,
+    },
+    [IN_SQ_UCODE0] = {
+        ['0' ... '9'] = IN_SQ_UCODE1,
+        ['a' ... 'f'] = IN_SQ_UCODE1,
+        ['A' ... 'F'] = IN_SQ_UCODE1,
+    },
+    [IN_SQ_STRING_ESCAPE] = {
+        ['b'] = IN_SQ_STRING,
+        ['f'] =  IN_SQ_STRING,
+        ['n'] =  IN_SQ_STRING,
+        ['r'] =  IN_SQ_STRING,
+        ['t'] =  IN_SQ_STRING,
+        ['/'] = IN_DQ_STRING,
+        ['\\'] = IN_DQ_STRING,
+        ['\''] = IN_SQ_STRING,
+        ['\"'] = IN_SQ_STRING,
+        ['u'] = IN_SQ_UCODE0,
+    },
+    [IN_SQ_STRING] = {
+        [1 ... 0xBF] = IN_SQ_STRING,
+        [0xC2 ... 0xF4] = IN_SQ_STRING,
+        ['\\'] = IN_SQ_STRING_ESCAPE,
+        ['\''] = JSON_STRING,
+    },
+
+    /* Zero */
+    [IN_ZERO] = {
+        TERMINAL(JSON_INTEGER),
+        ['0' ... '9'] = IN_ERROR,
+        ['.'] = IN_MANTISSA,
+    },
+
+    /* Float */
+    [IN_DIGITS] = {
+        TERMINAL(JSON_FLOAT),
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_DIGIT] = {
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_EXP_E] = {
+        ['-'] = IN_DIGIT,
+        ['+'] = IN_DIGIT,
+        ['0' ... '9'] = IN_DIGITS,
+    },
+
+    [IN_MANTISSA_DIGITS] = {
+        TERMINAL(JSON_FLOAT),
+        ['0' ... '9'] = IN_MANTISSA_DIGITS,
+        ['e'] = IN_EXP_E,
+        ['E'] = IN_EXP_E,
+    },
+
+    [IN_MANTISSA] = {
+        ['0' ... '9'] = IN_MANTISSA_DIGITS,
+    },
+
+    /* Number */
+    [IN_NONZERO_NUMBER] = {
+        TERMINAL(JSON_INTEGER),
+        ['0' ... '9'] = IN_NONZERO_NUMBER,
+        ['e'] = IN_EXP_E,
+        ['E'] = IN_EXP_E,
+        ['.'] = IN_MANTISSA,
+    },
+
+    [IN_NEG_NONZERO_NUMBER] = {
+        ['0'] = IN_ZERO,
+        ['1' ... '9'] = IN_NONZERO_NUMBER,
+    },
+
+    /* keywords */
+    [IN_KEYWORD] = {
+        TERMINAL(JSON_KEYWORD),
+        ['a' ... 'z'] = IN_KEYWORD,
+    },
+
+    /* whitespace */
+    [IN_WHITESPACE] = {
+        TERMINAL(JSON_SKIP),
+        [' '] = IN_WHITESPACE,
+        ['\t'] = IN_WHITESPACE,
+        ['\r'] = IN_WHITESPACE,
+        ['\n'] = IN_WHITESPACE,
+    },        
+
+    /* escape */
+    [IN_ESCAPE_LL] = {
+        ['d'] = JSON_ESCAPE,
+    },
+
+    [IN_ESCAPE_L] = {
+        ['d'] = JSON_ESCAPE,
+        ['l'] = IN_ESCAPE_LL,
+    },
+
+    [IN_ESCAPE_I64] = {
+        ['d'] = JSON_ESCAPE,
+    },
+
+    [IN_ESCAPE_I6] = {
+        ['4'] = IN_ESCAPE_I64,
+    },
+
+    [IN_ESCAPE_I] = {
+        ['6'] = IN_ESCAPE_I6,
+    },
+
+    [IN_ESCAPE] = {
+        ['d'] = JSON_ESCAPE,
+        ['i'] = JSON_ESCAPE,
+        ['p'] = JSON_ESCAPE,
+        ['s'] = JSON_ESCAPE,
+        ['f'] = JSON_ESCAPE,
+        ['l'] = IN_ESCAPE_L,
+        ['I'] = IN_ESCAPE_I,
+    },
+
+    /* top level rule */
+    [IN_START] = {
+        ['"'] = IN_DQ_STRING,
+        ['\''] = IN_SQ_STRING,
+        ['0'] = IN_ZERO,
+        ['1' ... '9'] = IN_NONZERO_NUMBER,
+        ['-'] = IN_NEG_NONZERO_NUMBER,
+        ['{'] = JSON_OPERATOR,
+        ['}'] = JSON_OPERATOR,
+        ['['] = JSON_OPERATOR,
+        [']'] = JSON_OPERATOR,
+        [','] = JSON_OPERATOR,
+        [':'] = JSON_OPERATOR,
+        ['a' ... 'z'] = IN_KEYWORD,
+        ['%'] = IN_ESCAPE,
+        [' '] = IN_WHITESPACE,
+        ['\t'] = IN_WHITESPACE,
+        ['\r'] = IN_WHITESPACE,
+        ['\n'] = IN_WHITESPACE,
+    },
+};
+
+void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
+{
+    lexer->emit = func;
+    lexer->state = IN_START;
+    lexer->token = qstring_new();
+    lexer->x = lexer->y = 0;
+}
+
+static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
+{
+    int char_consumed, new_state;
+
+    lexer->x++;
+    if (ch == '\n') {
+        lexer->x = 0;
+        lexer->y++;
+    }
+
+    do {
+        new_state = json_lexer[lexer->state][(uint8_t)ch];
+        char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
+        if (char_consumed) {
+            qstring_append_chr(lexer->token, ch);
+        }
+
+        switch (new_state) {
+        case JSON_OPERATOR:
+        case JSON_ESCAPE:
+        case JSON_INTEGER:
+        case JSON_FLOAT:
+        case JSON_KEYWORD:
+        case JSON_STRING:
+            lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
+        case JSON_SKIP:
+            QDECREF(lexer->token);
+            lexer->token = qstring_new();
+            new_state = IN_START;
+            break;
+        case IN_ERROR:
+            /* XXX: To avoid having previous bad input leaving the parser in an
+             * unresponsive state where we consume unpredictable amounts of
+             * subsequent "good" input, percolate this error state up to the
+             * tokenizer/parser by forcing a NULL object to be emitted, then
+             * reset state.
+             *
+             * Also note that this handling is required for reliable channel
+             * negotiation between QMP and the guest agent, since chr(0xFF)
+             * is placed at the beginning of certain events to ensure proper
+             * delivery when the channel is in an unknown state. chr(0xFF) is
+             * never a valid ASCII/UTF-8 sequence, so this should reliably
+             * induce an error/flush state.
+             */
+            lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
+            QDECREF(lexer->token);
+            lexer->token = qstring_new();
+            new_state = IN_START;
+            lexer->state = new_state;
+            return 0;
+        default:
+            break;
+        }
+        lexer->state = new_state;
+    } while (!char_consumed && !flush);
+
+    /* Do not let a single token grow to an arbitrarily large size,
+     * this is a security consideration.
+     */
+    if (lexer->token->length > MAX_TOKEN_SIZE) {
+        lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
+        QDECREF(lexer->token);
+        lexer->token = qstring_new();
+        lexer->state = IN_START;
+    }
+
+    return 0;
+}
+
+int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
+{
+    size_t i;
+
+    for (i = 0; i < size; i++) {
+        int err;
+
+        err = json_lexer_feed_char(lexer, buffer[i], false);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int json_lexer_flush(JSONLexer *lexer)
+{
+    return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
+}
+
+void json_lexer_destroy(JSONLexer *lexer)
+{
+    QDECREF(lexer->token);
+}
diff --git a/qemu-0.15.x/json-lexer.h b/qemu-0.15.x/json-lexer.h
new file mode 100644
index 0000000..10bc0a7
--- /dev/null
+++ b/qemu-0.15.x/json-lexer.h
@@ -0,0 +1,51 @@
+/*
+ * JSON lexer
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_LEXER_H
+#define QEMU_JSON_LEXER_H
+
+#include "qstring.h"
+#include "qlist.h"
+
+typedef enum json_token_type {
+    JSON_OPERATOR = 100,
+    JSON_INTEGER,
+    JSON_FLOAT,
+    JSON_KEYWORD,
+    JSON_STRING,
+    JSON_ESCAPE,
+    JSON_SKIP,
+    JSON_ERROR,
+} JSONTokenType;
+
+typedef struct JSONLexer JSONLexer;
+
+typedef void (JSONLexerEmitter)(JSONLexer *, QString *, JSONTokenType, int x, int y);
+
+struct JSONLexer
+{
+    JSONLexerEmitter *emit;
+    int state;
+    QString *token;
+    int x, y;
+};
+
+void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func);
+
+int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size);
+
+int json_lexer_flush(JSONLexer *lexer);
+
+void json_lexer_destroy(JSONLexer *lexer);
+
+#endif
diff --git a/qemu-0.15.x/json-parser.c b/qemu-0.15.x/json-parser.c
new file mode 100644
index 0000000..849e215
--- /dev/null
+++ b/qemu-0.15.x/json-parser.c
@@ -0,0 +1,650 @@
+/*
+ * JSON Parser 
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <stdarg.h>
+
+#include "qemu-common.h"
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "json-parser.h"
+#include "json-lexer.h"
+#include "qerror.h"
+
+typedef struct JSONParserContext
+{
+    Error *err;
+} JSONParserContext;
+
+#define BUG_ON(cond) assert(!(cond))
+
+/**
+ * TODO
+ *
+ * 0) make errors meaningful again
+ * 1) add geometry information to tokens
+ * 3) should we return a parsed size?
+ * 4) deal with premature EOI
+ */
+
+static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap);
+
+/**
+ * Token manipulators
+ *
+ * tokens are dictionaries that contain a type, a string value, and geometry information
+ * about a token identified by the lexer.  These are routines that make working with
+ * these objects a bit easier.
+ */
+static const char *token_get_value(QObject *obj)
+{
+    return qdict_get_str(qobject_to_qdict(obj), "token");
+}
+
+static JSONTokenType token_get_type(QObject *obj)
+{
+    return qdict_get_int(qobject_to_qdict(obj), "type");
+}
+
+static int token_is_operator(QObject *obj, char op)
+{
+    const char *val;
+
+    if (token_get_type(obj) != JSON_OPERATOR) {
+        return 0;
+    }
+
+    val = token_get_value(obj);
+
+    return (val[0] == op) && (val[1] == 0);
+}
+
+static int token_is_keyword(QObject *obj, const char *value)
+{
+    if (token_get_type(obj) != JSON_KEYWORD) {
+        return 0;
+    }
+
+    return strcmp(token_get_value(obj), value) == 0;
+}
+
+static int token_is_escape(QObject *obj, const char *value)
+{
+    if (token_get_type(obj) != JSON_ESCAPE) {
+        return 0;
+    }
+
+    return (strcmp(token_get_value(obj), value) == 0);
+}
+
+/**
+ * Error handler
+ */
+static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
+                                           QObject *token, const char *msg, ...)
+{
+    va_list ap;
+    char message[1024];
+    va_start(ap, msg);
+    vsnprintf(message, sizeof(message), msg, ap);
+    va_end(ap);
+    if (ctxt->err) {
+        error_free(ctxt->err);
+        ctxt->err = NULL;
+    }
+    error_set(&ctxt->err, QERR_JSON_PARSE_ERROR, message);
+}
+
+/**
+ * String helpers
+ *
+ * These helpers are used to unescape strings.
+ */
+static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length)
+{
+    if (wchar <= 0x007F) {
+        BUG_ON(buffer_length < 2);
+
+        buffer[0] = wchar & 0x7F;
+        buffer[1] = 0;
+    } else if (wchar <= 0x07FF) {
+        BUG_ON(buffer_length < 3);
+
+        buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F);
+        buffer[1] = 0x80 | (wchar & 0x3F);
+        buffer[2] = 0;
+    } else {
+        BUG_ON(buffer_length < 4);
+
+        buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F);
+        buffer[1] = 0x80 | ((wchar >> 6) & 0x3F);
+        buffer[2] = 0x80 | (wchar & 0x3F);
+        buffer[3] = 0;
+    }
+}
+
+static int hex2decimal(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return (ch - '0');
+    } else if (ch >= 'a' && ch <= 'f') {
+        return 10 + (ch - 'a');
+    } else if (ch >= 'A' && ch <= 'F') {
+        return 10 + (ch - 'A');
+    }
+
+    return -1;
+}
+
+/**
+ * parse_string(): Parse a json string and return a QObject
+ *
+ *  string
+ *      ""
+ *      " chars "
+ *  chars
+ *      char
+ *      char chars
+ *  char
+ *      any-Unicode-character-
+ *          except-"-or-\-or-
+ *          control-character
+ *      \"
+ *      \\
+ *      \/
+ *      \b
+ *      \f
+ *      \n
+ *      \r
+ *      \t
+ *      \u four-hex-digits 
+ */
+static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
+{
+    const char *ptr = token_get_value(token);
+    QString *str;
+    int double_quote = 1;
+
+    if (*ptr == '"') {
+        double_quote = 1;
+    } else {
+        double_quote = 0;
+    }
+    ptr++;
+
+    str = qstring_new();
+    while (*ptr && 
+           ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\''))) {
+        if (*ptr == '\\') {
+            ptr++;
+
+            switch (*ptr) {
+            case '"':
+                qstring_append(str, "\"");
+                ptr++;
+                break;
+            case '\'':
+                qstring_append(str, "'");
+                ptr++;
+                break;
+            case '\\':
+                qstring_append(str, "\\");
+                ptr++;
+                break;
+            case '/':
+                qstring_append(str, "/");
+                ptr++;
+                break;
+            case 'b':
+                qstring_append(str, "\b");
+                ptr++;
+                break;
+            case 'f':
+                qstring_append(str, "\f");
+                ptr++;
+                break;
+            case 'n':
+                qstring_append(str, "\n");
+                ptr++;
+                break;
+            case 'r':
+                qstring_append(str, "\r");
+                ptr++;
+                break;
+            case 't':
+                qstring_append(str, "\t");
+                ptr++;
+                break;
+            case 'u': {
+                uint16_t unicode_char = 0;
+                char utf8_char[4];
+                int i = 0;
+
+                ptr++;
+
+                for (i = 0; i < 4; i++) {
+                    if (qemu_isxdigit(*ptr)) {
+                        unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4);
+                    } else {
+                        parse_error(ctxt, token,
+                                    "invalid hex escape sequence in string");
+                        goto out;
+                    }
+                    ptr++;
+                }
+
+                wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char));
+                qstring_append(str, utf8_char);
+            }   break;
+            default:
+                parse_error(ctxt, token, "invalid escape sequence in string");
+                goto out;
+            }
+        } else {
+            char dummy[2];
+
+            dummy[0] = *ptr++;
+            dummy[1] = 0;
+
+            qstring_append(str, dummy);
+        }
+    }
+
+    return str;
+
+out:
+    QDECREF(str);
+    return NULL;
+}
+
+/**
+ * Parsing rules
+ */
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
+{
+    QObject *key = NULL, *token = NULL, *value, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
+    key = parse_value(ctxt, &working, ap);
+    if (!key || qobject_type(key) != QTYPE_QSTRING) {
+        parse_error(ctxt, peek, "key is not a string in object");
+        goto out;
+    }
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
+    if (!token_is_operator(token, ':')) {
+        parse_error(ctxt, token, "missing : in object pair");
+        goto out;
+    }
+
+    value = parse_value(ctxt, &working, ap);
+    if (value == NULL) {
+        parse_error(ctxt, token, "Missing value in dict");
+        goto out;
+    }
+
+    qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value);
+
+    qobject_decref(token);
+    qobject_decref(key);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return 0;
+
+out:
+    qobject_decref(token);
+    qobject_decref(key);
+    QDECREF(working);
+
+    return -1;
+}
+
+static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QDict *dict = NULL;
+    QObject *token, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
+    if (!token_is_operator(token, '{')) {
+        goto out;
+    }
+    qobject_decref(token);
+    token = NULL;
+
+    dict = qdict_new();
+
+    peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
+    if (!token_is_operator(peek, '}')) {
+        if (parse_pair(ctxt, dict, &working, ap) == -1) {
+            goto out;
+        }
+
+        token = qlist_pop(working);
+        if (token == NULL) {
+            parse_error(ctxt, NULL, "premature EOI");
+            goto out;
+        }
+
+        while (!token_is_operator(token, '}')) {
+            if (!token_is_operator(token, ',')) {
+                parse_error(ctxt, token, "expected separator in dict");
+                goto out;
+            }
+            qobject_decref(token);
+            token = NULL;
+
+            if (parse_pair(ctxt, dict, &working, ap) == -1) {
+                goto out;
+            }
+
+            token = qlist_pop(working);
+            if (token == NULL) {
+                parse_error(ctxt, NULL, "premature EOI");
+                goto out;
+            }
+        }
+        qobject_decref(token);
+        token = NULL;
+    } else {
+        token = qlist_pop(working);
+        qobject_decref(token);
+        token = NULL;
+    }
+
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return QOBJECT(dict);
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+    QDECREF(dict);
+    return NULL;
+}
+
+static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QList *list = NULL;
+    QObject *token, *peek;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
+    if (!token_is_operator(token, '[')) {
+        goto out;
+    }
+    qobject_decref(token);
+    token = NULL;
+
+    list = qlist_new();
+
+    peek = qlist_peek(working);
+    if (peek == NULL) {
+        parse_error(ctxt, NULL, "premature EOI");
+        goto out;
+    }
+
+    if (!token_is_operator(peek, ']')) {
+        QObject *obj;
+
+        obj = parse_value(ctxt, &working, ap);
+        if (obj == NULL) {
+            parse_error(ctxt, token, "expecting value");
+            goto out;
+        }
+
+        qlist_append_obj(list, obj);
+
+        token = qlist_pop(working);
+        if (token == NULL) {
+            parse_error(ctxt, NULL, "premature EOI");
+            goto out;
+        }
+
+        while (!token_is_operator(token, ']')) {
+            if (!token_is_operator(token, ',')) {
+                parse_error(ctxt, token, "expected separator in list");
+                goto out;
+            }
+
+            qobject_decref(token);
+            token = NULL;
+
+            obj = parse_value(ctxt, &working, ap);
+            if (obj == NULL) {
+                parse_error(ctxt, token, "expecting value");
+                goto out;
+            }
+
+            qlist_append_obj(list, obj);
+
+            token = qlist_pop(working);
+            if (token == NULL) {
+                parse_error(ctxt, NULL, "premature EOI");
+                goto out;
+            }
+        }
+
+        qobject_decref(token);
+        token = NULL;
+    } else {
+        token = qlist_pop(working);
+        qobject_decref(token);
+        token = NULL;
+    }
+
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return QOBJECT(list);
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+    QDECREF(list);
+    return NULL;
+}
+
+static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
+{
+    QObject *token, *ret;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
+    if (token_get_type(token) != JSON_KEYWORD) {
+        goto out;
+    }
+
+    if (token_is_keyword(token, "true")) {
+        ret = QOBJECT(qbool_from_int(true));
+    } else if (token_is_keyword(token, "false")) {
+        ret = QOBJECT(qbool_from_int(false));
+    } else {
+        parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token));
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return ret;
+
+out: 
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QObject *token = NULL, *obj;
+    QList *working = qlist_copy(*tokens);
+
+    if (ap == NULL) {
+        goto out;
+    }
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
+    if (token_is_escape(token, "%p")) {
+        obj = va_arg(*ap, QObject *);
+    } else if (token_is_escape(token, "%i")) {
+        obj = QOBJECT(qbool_from_int(va_arg(*ap, int)));
+    } else if (token_is_escape(token, "%d")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
+    } else if (token_is_escape(token, "%ld")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
+    } else if (token_is_escape(token, "%lld") ||
+               token_is_escape(token, "%I64d")) {
+        obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
+    } else if (token_is_escape(token, "%s")) {
+        obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
+    } else if (token_is_escape(token, "%f")) {
+        obj = QOBJECT(qfloat_from_double(va_arg(*ap, double)));
+    } else {
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return obj;
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
+{
+    QObject *token, *obj;
+    QList *working = qlist_copy(*tokens);
+
+    token = qlist_pop(working);
+    if (token == NULL) {
+        goto out;
+    }
+
+    switch (token_get_type(token)) {
+    case JSON_STRING:
+        obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
+        break;
+    case JSON_INTEGER:
+        obj = QOBJECT(qint_from_int(strtoll(token_get_value(token), NULL, 10)));
+        break;
+    case JSON_FLOAT:
+        /* FIXME dependent on locale */
+        obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL)));
+        break;
+    default:
+        goto out;
+    }
+
+    qobject_decref(token);
+    QDECREF(*tokens);
+    *tokens = working;
+
+    return obj;
+
+out:
+    qobject_decref(token);
+    QDECREF(working);
+
+    return NULL;
+}
+
+static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+{
+    QObject *obj;
+
+    obj = parse_object(ctxt, tokens, ap);
+    if (obj == NULL) {
+        obj = parse_array(ctxt, tokens, ap);
+    }
+    if (obj == NULL) {
+        obj = parse_escape(ctxt, tokens, ap);
+    }
+    if (obj == NULL) {
+        obj = parse_keyword(ctxt, tokens);
+    } 
+    if (obj == NULL) {
+        obj = parse_literal(ctxt, tokens);
+    }
+
+    return obj;
+}
+
+QObject *json_parser_parse(QList *tokens, va_list *ap)
+{
+    return json_parser_parse_err(tokens, ap, NULL);
+}
+
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
+{
+    JSONParserContext ctxt = {};
+    QList *working;
+    QObject *result;
+
+    if (!tokens) {
+        return NULL;
+    }
+    working = qlist_copy(tokens);
+    result = parse_value(&ctxt, &working, ap);
+
+    QDECREF(working);
+
+    error_propagate(errp, ctxt.err);
+
+    return result;
+}
diff --git a/qemu-0.15.x/json-parser.h b/qemu-0.15.x/json-parser.h
new file mode 100644
index 0000000..8f2b5ec
--- /dev/null
+++ b/qemu-0.15.x/json-parser.h
@@ -0,0 +1,24 @@
+/*
+ * JSON Parser 
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_PARSER_H
+#define QEMU_JSON_PARSER_H
+
+#include "qemu-common.h"
+#include "qlist.h"
+#include "error.h"
+
+QObject *json_parser_parse(QList *tokens, va_list *ap);
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp);
+
+#endif
diff --git a/qemu-0.15.x/json-streamer.c b/qemu-0.15.x/json-streamer.c
new file mode 100644
index 0000000..c255c78
--- /dev/null
+++ b/qemu-0.15.x/json-streamer.c
@@ -0,0 +1,122 @@
+/*
+ * JSON streaming support
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qlist.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qemu-common.h"
+#include "json-lexer.h"
+#include "json-streamer.h"
+
+#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_NESTING (1ULL << 10)
+
+static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
+{
+    JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
+    QDict *dict;
+
+    if (type == JSON_OPERATOR) {
+        switch (qstring_get_str(token)[0]) {
+        case '{':
+            parser->brace_count++;
+            break;
+        case '}':
+            parser->brace_count--;
+            break;
+        case '[':
+            parser->bracket_count++;
+            break;
+        case ']':
+            parser->bracket_count--;
+            break;
+        default:
+            break;
+        }
+    }
+
+    dict = qdict_new();
+    qdict_put(dict, "type", qint_from_int(type));
+    QINCREF(token);
+    qdict_put(dict, "token", token);
+    qdict_put(dict, "x", qint_from_int(x));
+    qdict_put(dict, "y", qint_from_int(y));
+
+    parser->token_size += token->length;
+
+    qlist_append(parser->tokens, dict);
+
+    if (type == JSON_ERROR) {
+        goto out_emit_bad;
+    } else if (parser->brace_count < 0 ||
+        parser->bracket_count < 0 ||
+        (parser->brace_count == 0 &&
+         parser->bracket_count == 0)) {
+        goto out_emit;
+    } else if (parser->token_size > MAX_TOKEN_SIZE ||
+               parser->bracket_count > MAX_NESTING ||
+               parser->brace_count > MAX_NESTING) {
+        /* Security consideration, we limit total memory allocated per object
+         * and the maximum recursion depth that a message can force.
+         */
+        goto out_emit;
+    }
+
+    return;
+
+out_emit_bad:
+    /* clear out token list and tell the parser to emit and error
+     * indication by passing it a NULL list
+     */
+    QDECREF(parser->tokens);
+    parser->tokens = NULL;
+out_emit:
+    /* send current list of tokens to parser and reset tokenizer */
+    parser->brace_count = 0;
+    parser->bracket_count = 0;
+    parser->emit(parser, parser->tokens);
+    if (parser->tokens) {
+        QDECREF(parser->tokens);
+    }
+    parser->tokens = qlist_new();
+    parser->token_size = 0;
+}
+
+void json_message_parser_init(JSONMessageParser *parser,
+                              void (*func)(JSONMessageParser *, QList *))
+{
+    parser->emit = func;
+    parser->brace_count = 0;
+    parser->bracket_count = 0;
+    parser->tokens = qlist_new();
+    parser->token_size = 0;
+
+    json_lexer_init(&parser->lexer, json_message_process_token);
+}
+
+int json_message_parser_feed(JSONMessageParser *parser,
+                             const char *buffer, size_t size)
+{
+    return json_lexer_feed(&parser->lexer, buffer, size);
+}
+
+int json_message_parser_flush(JSONMessageParser *parser)
+{
+    return json_lexer_flush(&parser->lexer);
+}
+
+void json_message_parser_destroy(JSONMessageParser *parser)
+{
+    json_lexer_destroy(&parser->lexer);
+    QDECREF(parser->tokens);
+}
diff --git a/qemu-0.15.x/json-streamer.h b/qemu-0.15.x/json-streamer.h
new file mode 100644
index 0000000..f09bc4d
--- /dev/null
+++ b/qemu-0.15.x/json-streamer.h
@@ -0,0 +1,40 @@
+/*
+ * JSON streaming support
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_JSON_STREAMER_H
+#define QEMU_JSON_STREAMER_H
+
+#include "qlist.h"
+#include "json-lexer.h"
+
+typedef struct JSONMessageParser
+{
+    void (*emit)(struct JSONMessageParser *parser, QList *tokens);
+    JSONLexer lexer;
+    int brace_count;
+    int bracket_count;
+    QList *tokens;
+    uint64_t token_size;
+} JSONMessageParser;
+
+void json_message_parser_init(JSONMessageParser *parser,
+                              void (*func)(JSONMessageParser *, QList *));
+
+int json_message_parser_feed(JSONMessageParser *parser,
+                             const char *buffer, size_t size);
+
+int json_message_parser_flush(JSONMessageParser *parser);
+
+void json_message_parser_destroy(JSONMessageParser *parser);
+
+#endif
diff --git a/qemu-0.15.x/kvm-all.c b/qemu-0.15.x/kvm-all.c
new file mode 100644
index 0000000..cbc2532
--- /dev/null
+++ b/qemu-0.15.x/kvm-all.c
@@ -0,0 +1,1396 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright IBM, Corp. 2008
+ *           Red Hat, Inc. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Glauber Costa     <gcosta at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu-barrier.h"
+#include "sysemu.h"
+#include "hw/hw.h"
+#include "gdbstub.h"
+#include "kvm.h"
+#include "bswap.h"
+
+/* This check must be after config-host.h is included */
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
+#define PAGE_SIZE TARGET_PAGE_SIZE
+
+//#define DEBUG_KVM
+
+#ifdef DEBUG_KVM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef struct KVMSlot
+{
+    target_phys_addr_t start_addr;
+    ram_addr_t memory_size;
+    ram_addr_t phys_offset;
+    int slot;
+    int flags;
+} KVMSlot;
+
+typedef struct kvm_dirty_log KVMDirtyLog;
+
+struct KVMState
+{
+    KVMSlot slots[32];
+    int fd;
+    int vmfd;
+    int coalesced_mmio;
+    struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+    int broken_set_mem_region;
+    int migration_log;
+    int vcpu_events;
+    int robust_singlestep;
+    int debugregs;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
+#endif
+    int irqchip_in_kernel;
+    int pit_in_kernel;
+    int xsave, xcrs;
+    int many_ioeventfds;
+};
+
+KVMState *kvm_state;
+
+static const KVMCapabilityInfo kvm_required_capabilites[] = {
+    KVM_CAP_INFO(USER_MEMORY),
+    KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
+    KVM_CAP_LAST_INFO
+};
+
+static KVMSlot *kvm_alloc_slot(KVMState *s)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        if (s->slots[i].memory_size == 0) {
+            return &s->slots[i];
+        }
+    }
+
+    fprintf(stderr, "%s: no free slot available\n", __func__);
+    abort();
+}
+
+static KVMSlot *kvm_lookup_matching_slot(KVMState *s,
+                                         target_phys_addr_t start_addr,
+                                         target_phys_addr_t end_addr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (start_addr == mem->start_addr &&
+            end_addr == mem->start_addr + mem->memory_size) {
+            return mem;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Find overlapping slot with lowest start address
+ */
+static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
+                                            target_phys_addr_t start_addr,
+                                            target_phys_addr_t end_addr)
+{
+    KVMSlot *found = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (mem->memory_size == 0 ||
+            (found && found->start_addr < mem->start_addr)) {
+            continue;
+        }
+
+        if (end_addr > mem->start_addr &&
+            start_addr < mem->start_addr + mem->memory_size) {
+            found = mem;
+        }
+    }
+
+    return found;
+}
+
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (ram_addr >= mem->phys_offset &&
+            ram_addr < mem->phys_offset + mem->memory_size) {
+            *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
+{
+    struct kvm_userspace_memory_region mem;
+
+    mem.slot = slot->slot;
+    mem.guest_phys_addr = slot->start_addr;
+    mem.memory_size = slot->memory_size;
+    mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset);
+    mem.flags = slot->flags;
+    if (s->migration_log) {
+        mem.flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+    return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+}
+
+static void kvm_reset_vcpu(void *opaque)
+{
+    CPUState *env = opaque;
+
+    kvm_arch_reset_vcpu(env);
+}
+
+int kvm_irqchip_in_kernel(void)
+{
+    return kvm_state->irqchip_in_kernel;
+}
+
+int kvm_pit_in_kernel(void)
+{
+    return kvm_state->pit_in_kernel;
+}
+
+int kvm_init_vcpu(CPUState *env)
+{
+    KVMState *s = kvm_state;
+    long mmap_size;
+    int ret;
+
+    DPRINTF("kvm_init_vcpu\n");
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index);
+    if (ret < 0) {
+        DPRINTF("kvm_create_vcpu failed\n");
+        goto err;
+    }
+
+    env->kvm_fd = ret;
+    env->kvm_state = s;
+    env->kvm_vcpu_dirty = 1;
+
+    mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
+    if (mmap_size < 0) {
+        ret = mmap_size;
+        DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
+        goto err;
+    }
+
+    env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        env->kvm_fd, 0);
+    if (env->kvm_run == MAP_FAILED) {
+        ret = -errno;
+        DPRINTF("mmap'ing vcpu state failed\n");
+        goto err;
+    }
+
+    if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
+        s->coalesced_mmio_ring =
+            (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
+    }
+
+    ret = kvm_arch_init_vcpu(env);
+    if (ret == 0) {
+        qemu_register_reset(kvm_reset_vcpu, env);
+        kvm_arch_reset_vcpu(env);
+    }
+err:
+    return ret;
+}
+
+/*
+ * dirty pages logging control
+ */
+
+static int kvm_mem_flags(KVMState *s, bool log_dirty)
+{
+    return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0;
+}
+
+static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    int flags, mask = KVM_MEM_LOG_DIRTY_PAGES;
+    int old_flags;
+
+    old_flags = mem->flags;
+
+    flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty);
+    mem->flags = flags;
+
+    /* If nothing changed effectively, no need to issue ioctl */
+    if (s->migration_log) {
+        flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+
+    if (flags == old_flags) {
+        return 0;
+    }
+
+    return kvm_set_user_memory_region(s, mem);
+}
+
+static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
+                                      ram_addr_t size, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
+
+    if (mem == NULL)  {
+        fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
+                TARGET_FMT_plx "\n", __func__, phys_addr,
+                (target_phys_addr_t)(phys_addr + size - 1));
+        return -EINVAL;
+    }
+    return kvm_slot_dirty_pages_log_change(mem, log_dirty);
+}
+
+static int kvm_log_start(CPUPhysMemoryClient *client,
+                         target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    return kvm_dirty_pages_log_change(phys_addr, size, true);
+}
+
+static int kvm_log_stop(CPUPhysMemoryClient *client,
+                        target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    return kvm_dirty_pages_log_change(phys_addr, size, false);
+}
+
+static int kvm_set_migration_log(int enable)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem;
+    int i, err;
+
+    s->migration_log = enable;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        mem = &s->slots[i];
+
+        if (!mem->memory_size) {
+            continue;
+        }
+        if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) {
+            continue;
+        }
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+/* get kvm's dirty pages bitmap and update qemu's */
+static int kvm_get_dirty_pages_log_range(unsigned long start_addr,
+                                         unsigned long *bitmap,
+                                         unsigned long offset,
+                                         unsigned long mem_size)
+{
+    unsigned int i, j;
+    unsigned long page_number, addr, addr1, c;
+    ram_addr_t ram_addr;
+    unsigned int len = ((mem_size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) /
+        HOST_LONG_BITS;
+
+    /*
+     * bitmap-traveling is faster than memory-traveling (for addr...)
+     * especially when most of the memory is not dirty.
+     */
+    for (i = 0; i < len; i++) {
+        if (bitmap[i] != 0) {
+            c = leul_to_cpu(bitmap[i]);
+            do {
+                j = ffsl(c) - 1;
+                c &= ~(1ul << j);
+                page_number = i * HOST_LONG_BITS + j;
+                addr1 = page_number * TARGET_PAGE_SIZE;
+                addr = offset + addr1;
+                ram_addr = cpu_get_physical_page_desc(addr);
+                cpu_physical_memory_set_dirty(ram_addr);
+            } while (c != 0);
+        }
+    }
+    return 0;
+}
+
+#define ALIGN(x, y)  (((x)+(y)-1) & ~((y)-1))
+
+/**
+ * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
+ * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
+ * This means all bits are set to dirty.
+ *
+ * @start_add: start of logged region.
+ * @end_addr: end of logged region.
+ */
+static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                          target_phys_addr_t end_addr)
+{
+    KVMState *s = kvm_state;
+    unsigned long size, allocated_size = 0;
+    KVMDirtyLog d;
+    KVMSlot *mem;
+    int ret = 0;
+
+    d.dirty_bitmap = NULL;
+    while (start_addr < end_addr) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, end_addr);
+        if (mem == NULL) {
+            break;
+        }
+
+        /* XXX bad kernel interface alert
+         * For dirty bitmap, kernel allocates array of size aligned to
+         * bits-per-long.  But for case when the kernel is 64bits and
+         * the userspace is 32bits, userspace can't align to the same
+         * bits-per-long, since sizeof(long) is different between kernel
+         * and user space.  This way, userspace will provide buffer which
+         * may be 4 bytes less than the kernel will use, resulting in
+         * userspace memory corruption (which is not detectable by valgrind
+         * too, in most cases).
+         * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
+         * a hope that sizeof(long) wont become >8 any time soon.
+         */
+        size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
+                     /*HOST_LONG_BITS*/ 64) / 8;
+        if (!d.dirty_bitmap) {
+            d.dirty_bitmap = qemu_malloc(size);
+        } else if (size > allocated_size) {
+            d.dirty_bitmap = qemu_realloc(d.dirty_bitmap, size);
+        }
+        allocated_size = size;
+        memset(d.dirty_bitmap, 0, allocated_size);
+
+        d.slot = mem->slot;
+
+        if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
+            DPRINTF("ioctl failed %d\n", errno);
+            ret = -1;
+            break;
+        }
+
+        kvm_get_dirty_pages_log_range(mem->start_addr, d.dirty_bitmap,
+                                      mem->start_addr, mem->memory_size);
+        start_addr = mem->start_addr + mem->memory_size;
+    }
+    qemu_free(d.dirty_bitmap);
+
+    return ret;
+}
+
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
+    }
+
+    return ret;
+}
+
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+    }
+
+    return ret;
+}
+
+int kvm_check_extension(KVMState *s, unsigned int extension)
+{
+    int ret;
+
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
+    if (ret < 0) {
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static int kvm_check_many_ioeventfds(void)
+{
+    /* Userspace can use ioeventfd for io notification.  This requires a host
+     * that supports eventfd(2) and an I/O thread; since eventfd does not
+     * support SIGIO it cannot interrupt the vcpu.
+     *
+     * Older kernels have a 6 device limit on the KVM io bus.  Find out so we
+     * can avoid creating too many ioeventfds.
+     */
+#if defined(CONFIG_EVENTFD) && defined(CONFIG_IOTHREAD)
+    int ioeventfds[7];
+    int i, ret = 0;
+    for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
+        ioeventfds[i] = eventfd(0, EFD_CLOEXEC);
+        if (ioeventfds[i] < 0) {
+            break;
+        }
+        ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true);
+        if (ret < 0) {
+            close(ioeventfds[i]);
+            break;
+        }
+    }
+
+    /* Decide whether many devices are supported or not */
+    ret = i == ARRAY_SIZE(ioeventfds);
+
+    while (i-- > 0) {
+        kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false);
+        close(ioeventfds[i]);
+    }
+    return ret;
+#else
+    return 0;
+#endif
+}
+
+static const KVMCapabilityInfo *
+kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
+{
+    while (list->name) {
+        if (!kvm_check_extension(s, list->value)) {
+            return list;
+        }
+        list++;
+    }
+    return NULL;
+}
+
+static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
+                             ram_addr_t phys_offset, bool log_dirty)
+{
+    KVMState *s = kvm_state;
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    KVMSlot *mem, old;
+    int err;
+
+    /* kvm works in page size chunks, but the function may be called
+       with sub-page size and unaligned start address. */
+    size = TARGET_PAGE_ALIGN(size);
+    start_addr = TARGET_PAGE_ALIGN(start_addr);
+
+    /* KVM does not support read-only slots */
+    phys_offset &= ~IO_MEM_ROM;
+
+    while (1) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
+        if (!mem) {
+            break;
+        }
+
+        if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
+            (start_addr + size <= mem->start_addr + mem->memory_size) &&
+            (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
+            /* The new slot fits into the existing one and comes with
+             * identical parameters - update flags and done. */
+            kvm_slot_dirty_pages_log_change(mem, log_dirty);
+            return;
+        }
+
+        old = *mem;
+
+        /* unregister the overlapping slot */
+        mem->memory_size = 0;
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
+                    __func__, strerror(-err));
+            abort();
+        }
+
+        /* Workaround for older KVM versions: we can't join slots, even not by
+         * unregistering the previous ones and then registering the larger
+         * slot. We have to maintain the existing fragmentation. Sigh.
+         *
+         * This workaround assumes that the new slot starts at the same
+         * address as the first existing one. If not or if some overlapping
+         * slot comes around later, we will fail (not seen in practice so far)
+         * - and actually require a recent KVM version. */
+        if (s->broken_set_mem_region &&
+            old.start_addr == start_addr && old.memory_size < size &&
+            flags < IO_MEM_UNASSIGNED) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = old.memory_size;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags = kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error updating slot: %s\n", __func__,
+                        strerror(-err));
+                abort();
+            }
+
+            start_addr += old.memory_size;
+            phys_offset += old.memory_size;
+            size -= old.memory_size;
+            continue;
+        }
+
+        /* register prefix slot */
+        if (old.start_addr < start_addr) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = start_addr - old.start_addr;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags =  kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering prefix slot: %s\n",
+                        __func__, strerror(-err));
+#ifdef TARGET_PPC
+                fprintf(stderr, "%s: This is probably because your kernel's " \
+                                "PAGE_SIZE is too big. Please try to use 4k " \
+                                "PAGE_SIZE!\n", __func__);
+#endif
+                abort();
+            }
+        }
+
+        /* register suffix slot */
+        if (old.start_addr + old.memory_size > start_addr + size) {
+            ram_addr_t size_delta;
+
+            mem = kvm_alloc_slot(s);
+            mem->start_addr = start_addr + size;
+            size_delta = mem->start_addr - old.start_addr;
+            mem->memory_size = old.memory_size - size_delta;
+            mem->phys_offset = old.phys_offset + size_delta;
+            mem->flags = kvm_mem_flags(s, log_dirty);
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering suffix slot: %s\n",
+                        __func__, strerror(-err));
+                abort();
+            }
+        }
+    }
+
+    /* in case the KVM bug workaround already "consumed" the new slot */
+    if (!size) {
+        return;
+    }
+    /* KVM does not need to know about this memory */
+    if (flags >= IO_MEM_UNASSIGNED) {
+        return;
+    }
+    mem = kvm_alloc_slot(s);
+    mem->memory_size = size;
+    mem->start_addr = start_addr;
+    mem->phys_offset = phys_offset;
+    mem->flags = kvm_mem_flags(s, log_dirty);
+
+    err = kvm_set_user_memory_region(s, mem);
+    if (err) {
+        fprintf(stderr, "%s: error registering slot: %s\n", __func__,
+                strerror(-err));
+        abort();
+    }
+}
+
+static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
+                                  target_phys_addr_t start_addr,
+                                  ram_addr_t size, ram_addr_t phys_offset,
+                                  bool log_dirty)
+{
+    kvm_set_phys_mem(start_addr, size, phys_offset, log_dirty);
+}
+
+static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+                                        target_phys_addr_t start_addr,
+                                        target_phys_addr_t end_addr)
+{
+    return kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
+}
+
+static int kvm_client_migration_log(struct CPUPhysMemoryClient *client,
+                                    int enable)
+{
+    return kvm_set_migration_log(enable);
+}
+
+static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
+    .set_memory = kvm_client_set_memory,
+    .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap,
+    .migration_log = kvm_client_migration_log,
+    .log_start = kvm_log_start,
+    .log_stop = kvm_log_stop,
+};
+
+static void kvm_handle_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+
+    if (!qemu_cpu_is_self(env)) {
+        qemu_cpu_kick(env);
+    }
+}
+
+int kvm_init(void)
+{
+    static const char upgrade_note[] =
+        "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
+        "(see http://sourceforge.net/projects/kvm).\n";
+    KVMState *s;
+    const KVMCapabilityInfo *missing_cap;
+    int ret;
+    int i;
+
+    s = qemu_mallocz(sizeof(KVMState));
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    QTAILQ_INIT(&s->kvm_sw_breakpoints);
+#endif
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        s->slots[i].slot = i;
+    }
+    s->vmfd = -1;
+    s->fd = qemu_open("/dev/kvm", O_RDWR);
+    if (s->fd == -1) {
+        fprintf(stderr, "Could not access KVM kernel module: %m\n");
+        ret = -errno;
+        goto err;
+    }
+
+    ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
+    if (ret < KVM_API_VERSION) {
+        if (ret > 0) {
+            ret = -EINVAL;
+        }
+        fprintf(stderr, "kvm version too old\n");
+        goto err;
+    }
+
+    if (ret > KVM_API_VERSION) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm version not supported\n");
+        goto err;
+    }
+
+    s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
+    if (s->vmfd < 0) {
+#ifdef TARGET_S390X
+        fprintf(stderr, "Please add the 'switch_amode' kernel parameter to "
+                        "your host kernel command line\n");
+#endif
+        goto err;
+    }
+
+    missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
+    if (!missing_cap) {
+        missing_cap =
+            kvm_check_extension_list(s, kvm_arch_required_capabilities);
+    }
+    if (missing_cap) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm does not support %s\n%s",
+                missing_cap->name, upgrade_note);
+        goto err;
+    }
+
+    s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
+
+    s->broken_set_mem_region = 1;
+    ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
+    if (ret > 0) {
+        s->broken_set_mem_region = 0;
+    }
+
+#ifdef KVM_CAP_VCPU_EVENTS
+    s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
+#endif
+
+    s->robust_singlestep =
+        kvm_check_extension(s, KVM_CAP_X86_ROBUST_SINGLESTEP);
+
+#ifdef KVM_CAP_DEBUGREGS
+    s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS);
+#endif
+
+#ifdef KVM_CAP_XSAVE
+    s->xsave = kvm_check_extension(s, KVM_CAP_XSAVE);
+#endif
+
+#ifdef KVM_CAP_XCRS
+    s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
+#endif
+
+    ret = kvm_arch_init(s);
+    if (ret < 0) {
+        goto err;
+    }
+
+    kvm_state = s;
+    cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
+
+    s->many_ioeventfds = kvm_check_many_ioeventfds();
+
+    cpu_interrupt_handler = kvm_handle_interrupt;
+
+    return 0;
+
+err:
+    if (s) {
+        if (s->vmfd != -1) {
+            close(s->vmfd);
+        }
+        if (s->fd != -1) {
+            close(s->fd);
+        }
+    }
+    qemu_free(s);
+
+    return ret;
+}
+
+static void kvm_handle_io(uint16_t port, void *data, int direction, int size,
+                          uint32_t count)
+{
+    int i;
+    uint8_t *ptr = data;
+
+    for (i = 0; i < count; i++) {
+        if (direction == KVM_EXIT_IO_IN) {
+            switch (size) {
+            case 1:
+                stb_p(ptr, cpu_inb(port));
+                break;
+            case 2:
+                stw_p(ptr, cpu_inw(port));
+                break;
+            case 4:
+                stl_p(ptr, cpu_inl(port));
+                break;
+            }
+        } else {
+            switch (size) {
+            case 1:
+                cpu_outb(port, ldub_p(ptr));
+                break;
+            case 2:
+                cpu_outw(port, lduw_p(ptr));
+                break;
+            case 4:
+                cpu_outl(port, ldl_p(ptr));
+                break;
+            }
+        }
+
+        ptr += size;
+    }
+}
+
+static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
+{
+    fprintf(stderr, "KVM internal error.");
+    if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
+        int i;
+
+        fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
+        for (i = 0; i < run->internal.ndata; ++i) {
+            fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
+                    i, (uint64_t)run->internal.data[i]);
+        }
+    } else {
+        fprintf(stderr, "\n");
+    }
+    if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
+        fprintf(stderr, "emulation failure\n");
+        if (!kvm_arch_stop_on_emulation_error(env)) {
+            cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
+            return EXCP_INTERRUPT;
+        }
+    }
+    /* FIXME: Should trigger a qmp message to let management know
+     * something went wrong.
+     */
+    return -1;
+}
+
+void kvm_flush_coalesced_mmio_buffer(void)
+{
+    KVMState *s = kvm_state;
+    if (s->coalesced_mmio_ring) {
+        struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
+        while (ring->first != ring->last) {
+            struct kvm_coalesced_mmio *ent;
+
+            ent = &ring->coalesced_mmio[ring->first];
+
+            cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
+            smp_wmb();
+            ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+        }
+    }
+}
+
+static void do_kvm_cpu_synchronize_state(void *_env)
+{
+    CPUState *env = _env;
+
+    if (!env->kvm_vcpu_dirty) {
+        kvm_arch_get_registers(env);
+        env->kvm_vcpu_dirty = 1;
+    }
+}
+
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+    if (!env->kvm_vcpu_dirty) {
+        run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
+    }
+}
+
+void kvm_cpu_synchronize_post_reset(CPUState *env)
+{
+    kvm_arch_put_registers(env, KVM_PUT_RESET_STATE);
+    env->kvm_vcpu_dirty = 0;
+}
+
+void kvm_cpu_synchronize_post_init(CPUState *env)
+{
+    kvm_arch_put_registers(env, KVM_PUT_FULL_STATE);
+    env->kvm_vcpu_dirty = 0;
+}
+
+int kvm_cpu_exec(CPUState *env)
+{
+    struct kvm_run *run = env->kvm_run;
+    int ret, run_ret;
+
+    DPRINTF("kvm_cpu_exec()\n");
+
+    if (kvm_arch_process_async_events(env)) {
+        env->exit_request = 0;
+        return EXCP_HLT;
+    }
+
+    cpu_single_env = env;
+
+    do {
+        if (env->kvm_vcpu_dirty) {
+            kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
+            env->kvm_vcpu_dirty = 0;
+        }
+
+        kvm_arch_pre_run(env, run);
+        if (env->exit_request) {
+            DPRINTF("interrupt exit requested\n");
+            /*
+             * KVM requires us to reenter the kernel after IO exits to complete
+             * instruction emulation. This self-signal will ensure that we
+             * leave ASAP again.
+             */
+            qemu_cpu_kick_self();
+        }
+        cpu_single_env = NULL;
+        qemu_mutex_unlock_iothread();
+
+        run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
+
+        qemu_mutex_lock_iothread();
+        cpu_single_env = env;
+        kvm_arch_post_run(env, run);
+
+        kvm_flush_coalesced_mmio_buffer();
+
+        if (run_ret < 0) {
+            if (run_ret == -EINTR || run_ret == -EAGAIN) {
+                DPRINTF("io window exit\n");
+                ret = EXCP_INTERRUPT;
+                break;
+            }
+            DPRINTF("kvm run failed %s\n", strerror(-run_ret));
+            abort();
+        }
+
+        switch (run->exit_reason) {
+        case KVM_EXIT_IO:
+            DPRINTF("handle_io\n");
+            kvm_handle_io(run->io.port,
+                          (uint8_t *)run + run->io.data_offset,
+                          run->io.direction,
+                          run->io.size,
+                          run->io.count);
+            ret = 0;
+            break;
+        case KVM_EXIT_MMIO:
+            DPRINTF("handle_mmio\n");
+            cpu_physical_memory_rw(run->mmio.phys_addr,
+                                   run->mmio.data,
+                                   run->mmio.len,
+                                   run->mmio.is_write);
+            ret = 0;
+            break;
+        case KVM_EXIT_IRQ_WINDOW_OPEN:
+            DPRINTF("irq_window_open\n");
+            ret = EXCP_INTERRUPT;
+            break;
+        case KVM_EXIT_SHUTDOWN:
+            DPRINTF("shutdown\n");
+            qemu_system_reset_request();
+            ret = EXCP_INTERRUPT;
+            break;
+        case KVM_EXIT_UNKNOWN:
+            fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
+                    (uint64_t)run->hw.hardware_exit_reason);
+            ret = -1;
+            break;
+        case KVM_EXIT_INTERNAL_ERROR:
+            ret = kvm_handle_internal_error(env, run);
+            break;
+        default:
+            DPRINTF("kvm_arch_handle_exit\n");
+            ret = kvm_arch_handle_exit(env, run);
+            break;
+        }
+    } while (ret == 0);
+
+    if (ret < 0) {
+        cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
+        vm_stop(VMSTOP_PANIC);
+    }
+
+    env->exit_request = 0;
+    cpu_single_env = NULL;
+    return ret;
+}
+
+int kvm_ioctl(KVMState *s, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->fd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
+}
+
+int kvm_vm_ioctl(KVMState *s, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->vmfd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
+}
+
+int kvm_vcpu_ioctl(CPUState *env, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(env->kvm_fd, type, arg);
+    if (ret == -1) {
+        ret = -errno;
+    }
+    return ret;
+}
+
+int kvm_has_sync_mmu(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
+}
+
+int kvm_has_vcpu_events(void)
+{
+    return kvm_state->vcpu_events;
+}
+
+int kvm_has_robust_singlestep(void)
+{
+    return kvm_state->robust_singlestep;
+}
+
+int kvm_has_debugregs(void)
+{
+    return kvm_state->debugregs;
+}
+
+int kvm_has_xsave(void)
+{
+    return kvm_state->xsave;
+}
+
+int kvm_has_xcrs(void)
+{
+    return kvm_state->xcrs;
+}
+
+int kvm_has_many_ioeventfds(void)
+{
+    if (!kvm_enabled()) {
+        return 0;
+    }
+    return kvm_state->many_ioeventfds;
+}
+
+void kvm_setup_guest_memory(void *start, size_t size)
+{
+    if (!kvm_has_sync_mmu()) {
+        int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
+
+        if (ret) {
+            perror("qemu_madvise");
+            fprintf(stderr,
+                    "Need MADV_DONTFORK in absence of synchronous KVM MMU\n");
+            exit(1);
+        }
+    }
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
+                                                 target_ulong pc)
+{
+    struct kvm_sw_breakpoint *bp;
+
+    QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
+        if (bp->pc == pc) {
+            return bp;
+        }
+    }
+    return NULL;
+}
+
+int kvm_sw_breakpoints_active(CPUState *env)
+{
+    return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
+}
+
+struct kvm_set_guest_debug_data {
+    struct kvm_guest_debug dbg;
+    CPUState *env;
+    int err;
+};
+
+static void kvm_invoke_set_guest_debug(void *data)
+{
+    struct kvm_set_guest_debug_data *dbg_data = data;
+    CPUState *env = dbg_data->env;
+
+    dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg);
+}
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    struct kvm_set_guest_debug_data data;
+
+    data.dbg.control = reinject_trap;
+
+    if (env->singlestep_enabled) {
+        data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+    }
+    kvm_arch_update_guest_debug(env, &data.dbg);
+    data.env = env;
+
+    run_on_cpu(env, kvm_invoke_set_guest_debug, &data);
+    return data.err;
+}
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (bp) {
+            bp->use_count++;
+            return 0;
+        }
+
+        bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint));
+        if (!bp) {
+            return -ENOMEM;
+        }
+
+        bp->pc = addr;
+        bp->use_count = 1;
+        err = kvm_arch_insert_sw_breakpoint(current_env, bp);
+        if (err) {
+            qemu_free(bp);
+            return err;
+        }
+
+        QTAILQ_INSERT_HEAD(&current_env->kvm_state->kvm_sw_breakpoints,
+                          bp, entry);
+    } else {
+        err = kvm_arch_insert_hw_breakpoint(addr, len, type);
+        if (err) {
+            return err;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (!bp) {
+            return -ENOENT;
+        }
+
+        if (bp->use_count > 1) {
+            bp->use_count--;
+            return 0;
+        }
+
+        err = kvm_arch_remove_sw_breakpoint(current_env, bp);
+        if (err) {
+            return err;
+        }
+
+        QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry);
+        qemu_free(bp);
+    } else {
+        err = kvm_arch_remove_hw_breakpoint(addr, len, type);
+        if (err) {
+            return err;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+void kvm_remove_all_breakpoints(CPUState *current_env)
+{
+    struct kvm_sw_breakpoint *bp, *next;
+    KVMState *s = current_env->kvm_state;
+    CPUState *env;
+
+    QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
+        if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
+            /* Try harder to find a CPU that currently sees the breakpoint. */
+            for (env = first_cpu; env != NULL; env = env->next_cpu) {
+                if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) {
+                    break;
+                }
+            }
+        }
+    }
+    kvm_arch_remove_all_hw_breakpoints();
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        kvm_update_guest_debug(env, 0);
+    }
+}
+
+#else /* !KVM_CAP_SET_GUEST_DEBUG */
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    return -EINVAL;
+}
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+void kvm_remove_all_breakpoints(CPUState *current_env)
+{
+}
+#endif /* !KVM_CAP_SET_GUEST_DEBUG */
+
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
+{
+    struct kvm_signal_mask *sigmask;
+    int r;
+
+    if (!sigset) {
+        return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
+    }
+
+    sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
+
+    sigmask->len = 8;
+    memcpy(sigmask->sigset, sigset, sizeof(*sigset));
+    r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
+    qemu_free(sigmask);
+
+    return r;
+}
+
+int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign)
+{
+#ifdef KVM_IOEVENTFD
+    int ret;
+    struct kvm_ioeventfd iofd;
+
+    iofd.datamatch = val;
+    iofd.addr = addr;
+    iofd.len = 4;
+    iofd.flags = KVM_IOEVENTFD_FLAG_DATAMATCH;
+    iofd.fd = fd;
+
+    if (!kvm_enabled()) {
+        return -ENOSYS;
+    }
+
+    if (!assign) {
+        iofd.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+    }
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd);
+
+    if (ret < 0) {
+        return -errno;
+    }
+
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
+{
+#ifdef KVM_IOEVENTFD
+    struct kvm_ioeventfd kick = {
+        .datamatch = val,
+        .addr = addr,
+        .len = 2,
+        .flags = KVM_IOEVENTFD_FLAG_DATAMATCH | KVM_IOEVENTFD_FLAG_PIO,
+        .fd = fd,
+    };
+    int r;
+    if (!kvm_enabled()) {
+        return -ENOSYS;
+    }
+    if (!assign) {
+        kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+    }
+    r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
+    if (r < 0) {
+        return r;
+    }
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return kvm_arch_on_sigbus_vcpu(env, code, addr);
+}
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return kvm_arch_on_sigbus(code, addr);
+}
diff --git a/qemu-0.15.x/kvm-stub.c b/qemu-0.15.x/kvm-stub.c
new file mode 100644
index 0000000..06064b9
--- /dev/null
+++ b/qemu-0.15.x/kvm-stub.c
@@ -0,0 +1,131 @@
+/*
+ * QEMU KVM stub
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Author: Paolo Bonzini     <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "cpu.h"
+#include "gdbstub.h"
+#include "kvm.h"
+
+int kvm_irqchip_in_kernel(void)
+{
+    return 0;
+}
+
+int kvm_pit_in_kernel(void)
+{
+    return 0;
+}
+
+
+int kvm_init_vcpu(CPUState *env)
+{
+    return -ENOSYS;
+}
+
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    return -ENOSYS;
+}
+
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    return -ENOSYS;
+}
+
+int kvm_init(void)
+{
+    return -ENOSYS;
+}
+
+void kvm_flush_coalesced_mmio_buffer(void)
+{
+}
+
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+}
+
+void kvm_cpu_synchronize_post_reset(CPUState *env)
+{
+}
+
+void kvm_cpu_synchronize_post_init(CPUState *env)
+{
+}
+
+int kvm_cpu_exec(CPUState *env)
+{
+    abort ();
+}
+
+int kvm_has_sync_mmu(void)
+{
+    return 0;
+}
+
+int kvm_has_many_ioeventfds(void)
+{
+    return 0;
+}
+
+void kvm_setup_guest_memory(void *start, size_t size)
+{
+}
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    return -ENOSYS;
+}
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+void kvm_remove_all_breakpoints(CPUState *current_env)
+{
+}
+
+#ifndef _WIN32
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
+{
+    abort();
+}
+#endif
+
+int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
+{
+    return -ENOSYS;
+}
+
+int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
+{
+    return -ENOSYS;
+}
+
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
diff --git a/qemu-0.15.x/kvm.h b/qemu-0.15.x/kvm.h
new file mode 100644
index 0000000..243b063
--- /dev/null
+++ b/qemu-0.15.x/kvm.h
@@ -0,0 +1,199 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_KVM_H
+#define QEMU_KVM_H
+
+#include <errno.h>
+#include "config-host.h"
+#include "qemu-queue.h"
+
+#ifdef CONFIG_KVM
+#include <linux/kvm.h>
+#endif
+
+extern int kvm_allowed;
+
+#if defined CONFIG_KVM || !defined NEED_CPU_H
+#define kvm_enabled() (kvm_allowed)
+#else
+#define kvm_enabled() (0)
+#endif
+
+struct kvm_run;
+
+typedef struct KVMCapabilityInfo {
+    const char *name;
+    int value;
+} KVMCapabilityInfo;
+
+#define KVM_CAP_INFO(CAP) { "KVM_CAP_" stringify(CAP), KVM_CAP_##CAP }
+#define KVM_CAP_LAST_INFO { NULL, 0 }
+
+/* external API */
+
+int kvm_init(void);
+
+int kvm_has_sync_mmu(void);
+int kvm_has_vcpu_events(void);
+int kvm_has_robust_singlestep(void);
+int kvm_has_debugregs(void);
+int kvm_has_xsave(void);
+int kvm_has_xcrs(void);
+int kvm_has_many_ioeventfds(void);
+
+#ifdef NEED_CPU_H
+int kvm_init_vcpu(CPUState *env);
+
+int kvm_cpu_exec(CPUState *env);
+
+#if !defined(CONFIG_USER_ONLY)
+void kvm_setup_guest_memory(void *start, size_t size);
+
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+void kvm_flush_coalesced_mmio_buffer(void);
+#endif
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type);
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type);
+void kvm_remove_all_breakpoints(CPUState *current_env);
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap);
+#ifndef _WIN32
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
+#endif
+
+int kvm_pit_in_kernel(void);
+int kvm_irqchip_in_kernel(void);
+
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_on_sigbus(int code, void *addr);
+
+/* internal API */
+
+struct KVMState;
+typedef struct KVMState KVMState;
+extern KVMState *kvm_state;
+
+int kvm_ioctl(KVMState *s, int type, ...);
+
+int kvm_vm_ioctl(KVMState *s, int type, ...);
+
+int kvm_vcpu_ioctl(CPUState *env, int type, ...);
+
+/* Arch specific hooks */
+
+extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
+
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run);
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
+
+int kvm_arch_process_async_events(CPUState *env);
+
+int kvm_arch_get_registers(CPUState *env);
+
+/* state subset only touched by the VCPU itself during runtime */
+#define KVM_PUT_RUNTIME_STATE   1
+/* state subset modified during VCPU reset */
+#define KVM_PUT_RESET_STATE     2
+/* full state set, modified during initialization or on vmload */
+#define KVM_PUT_FULL_STATE      3
+
+int kvm_arch_put_registers(CPUState *env, int level);
+
+int kvm_arch_init(KVMState *s);
+
+int kvm_arch_init_vcpu(CPUState *env);
+
+void kvm_arch_reset_vcpu(CPUState *env);
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_arch_on_sigbus(int code, void *addr);
+
+struct kvm_guest_debug;
+struct kvm_debug_exit_arch;
+
+struct kvm_sw_breakpoint {
+    target_ulong pc;
+    target_ulong saved_insn;
+    int use_count;
+    QTAILQ_ENTRY(kvm_sw_breakpoint) entry;
+};
+
+QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
+
+struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
+                                                 target_ulong pc);
+
+int kvm_sw_breakpoints_active(CPUState *env);
+
+int kvm_arch_insert_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_remove_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type);
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type);
+void kvm_arch_remove_all_hw_breakpoints(void);
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env);
+
+int kvm_check_extension(KVMState *s, unsigned int extension);
+
+uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
+                                      uint32_t index, int reg);
+void kvm_cpu_synchronize_state(CPUState *env);
+void kvm_cpu_synchronize_post_reset(CPUState *env);
+void kvm_cpu_synchronize_post_init(CPUState *env);
+
+/* generic hooks - to be moved/refactored once there are more users */
+
+static inline void cpu_synchronize_state(CPUState *env)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_state(env);
+    }
+}
+
+static inline void cpu_synchronize_post_reset(CPUState *env)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_reset(env);
+    }
+}
+
+static inline void cpu_synchronize_post_init(CPUState *env)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_init(env);
+    }
+}
+
+
+#if !defined(CONFIG_USER_ONLY)
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr);
+#endif
+
+#endif
+int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
+
+int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
+#endif
diff --git a/qemu-0.15.x/libcacard/Makefile b/qemu-0.15.x/libcacard/Makefile
new file mode 100644
index 0000000..9802c37
--- /dev/null
+++ b/qemu-0.15.x/libcacard/Makefile
@@ -0,0 +1,42 @@
+-include ../config-host.mak
+-include $(SRC_PATH)/Makefile.objs
+-include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
+
+# objects linked against normal qemu binaries, not compiled with libtool
+QEMU_OBJS=$(addprefix ../,$(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(trace-obj-y))
+
+# objects linked into a shared library, built with libtool with -fPIC if required
+QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS)))
+
+QEMU_CFLAGS+=-I../
+
+libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
+
+vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
+	$(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^,"  LINK  $@")
+
+clean:
+	rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la
+	rm -Rf .libs
+
+all: vscclient
+
+#########################################################################
+# Rules for building libcacard standalone library
+
+ifeq ($(LIBTOOL),)
+libcacard.la:
+	@echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+	@echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB)
+	$(call quiet-command,libtool --mode=link --quiet --tag=CC $(CC) $(libcacard_libs) -lrt -rpath $(libdir) -o $@ $^,"  lt LINK $@")
+
+install-libcacard: libcacard.la
+	$(INSTALL_DIR) "$(DESTDIR)$(libdir)"
+	libtool --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)"
+endif
diff --git a/qemu-0.15.x/libcacard/cac.c b/qemu-0.15.x/libcacard/cac.c
new file mode 100644
index 0000000..f34f63a
--- /dev/null
+++ b/qemu-0.15.x/libcacard/cac.c
@@ -0,0 +1,403 @@
+/*
+ * implement the applets for the CAC card.
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "cac.h"
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+
+#define CAC_GET_PROPERTIES  0x56
+#define CAC_GET_ACR         0x4c
+#define CAC_READ_BUFFER     0x52
+#define CAC_UPDATE_BUFFER   0x58
+#define CAC_SIGN_DECRYPT    0x42
+#define CAC_GET_CERTIFICATE 0x36
+
+/* private data for PKI applets */
+typedef struct CACPKIAppletDataStruct {
+    unsigned char *cert;
+    int cert_len;
+    unsigned char *cert_buffer;
+    int cert_buffer_len;
+    unsigned char *sign_buffer;
+    int sign_buffer_len;
+    VCardKey *key;
+} CACPKIAppletData;
+
+/*
+ * CAC applet private data
+ */
+struct VCardAppletPrivateStruct {
+    union {
+        CACPKIAppletData pki_data;
+        void *reserved;
+    } u;
+};
+
+/*
+ * handle all the APDU's that are common to all CAC applets
+ */
+static VCardStatus
+cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
+{
+    int ef;
+
+    switch (apdu->a_ins) {
+    case VCARD7816_INS_SELECT_FILE:
+        if (apdu->a_p1 != 0x02) {
+            /* let the 7816 code handle applet switches */
+            return VCARD_NEXT;
+        }
+        /* handle file id setting */
+        if (apdu->a_Lc != 2) {
+            *response = vcard_make_response(
+                VCARD7816_STATUS_ERROR_DATA_INVALID);
+            return VCARD_DONE;
+        }
+        /* CAC 1.0 only supports ef = 0 */
+        ef = apdu->a_body[0] | (apdu->a_body[1] << 8);
+        if (ef != 0) {
+            *response = vcard_make_response(
+                VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+            return VCARD_DONE;
+        }
+        *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
+        return VCARD_DONE;
+    case VCARD7816_INS_GET_RESPONSE:
+    case VCARD7816_INS_VERIFY:
+        /* let the 7816 code handle these */
+        return VCARD_NEXT;
+    case CAC_GET_PROPERTIES:
+    case CAC_GET_ACR:
+        /* skip these for now, this will probably be needed */
+        *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+        return VCARD_DONE;
+    }
+    *response = vcard_make_response(
+        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
+
+/*
+ *  reset the inter call state between applet selects
+ */
+static VCardStatus
+cac_applet_pki_reset(VCard *card, int channel)
+{
+    VCardAppletPrivate *applet_private = NULL;
+    CACPKIAppletData *pki_applet = NULL;
+    applet_private = vcard_get_current_applet_private(card, channel);
+    assert(applet_private);
+    pki_applet = &(applet_private->u.pki_data);
+
+    pki_applet->cert_buffer = NULL;
+    if (pki_applet->sign_buffer) {
+        qemu_free(pki_applet->sign_buffer);
+        pki_applet->sign_buffer = NULL;
+    }
+    pki_applet->cert_buffer_len = 0;
+    pki_applet->sign_buffer_len = 0;
+    return VCARD_DONE;
+}
+
+static VCardStatus
+cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
+                            VCardResponse **response)
+{
+    CACPKIAppletData *pki_applet = NULL;
+    VCardAppletPrivate *applet_private = NULL;
+    int size, next;
+    unsigned char *sign_buffer;
+    vcard_7816_status_t status;
+
+    applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
+    assert(applet_private);
+    pki_applet = &(applet_private->u.pki_data);
+
+    switch (apdu->a_ins) {
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+            VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+        return VCARD_DONE;
+    case CAC_GET_CERTIFICATE:
+        if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        assert(pki_applet->cert != NULL);
+        size = apdu->a_Le;
+        if (pki_applet->cert_buffer == NULL) {
+            pki_applet->cert_buffer = pki_applet->cert;
+            pki_applet->cert_buffer_len = pki_applet->cert_len;
+        }
+        size = MIN(size, pki_applet->cert_buffer_len);
+        next = MIN(255, pki_applet->cert_buffer_len - size);
+        *response = vcard_response_new_bytes(
+                        card, pki_applet->cert_buffer, size,
+                        apdu->a_Le, next ?
+                        VCARD7816_SW1_WARNING_CHANGE :
+                        VCARD7816_SW1_SUCCESS,
+                        next);
+        pki_applet->cert_buffer += size;
+        pki_applet->cert_buffer_len -= size;
+        if ((*response == NULL) || (next == 0)) {
+            pki_applet->cert_buffer = NULL;
+        }
+        if (*response == NULL) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+        return VCARD_DONE;
+    case CAC_SIGN_DECRYPT:
+        if (apdu->a_p2 != 0) {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        size = apdu->a_Lc;
+
+        sign_buffer = realloc(pki_applet->sign_buffer,
+                      pki_applet->sign_buffer_len+size);
+        if (sign_buffer == NULL) {
+            qemu_free(pki_applet->sign_buffer);
+            pki_applet->sign_buffer = NULL;
+            pki_applet->sign_buffer_len = 0;
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+            return VCARD_DONE;
+        }
+        memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
+        size += pki_applet->sign_buffer_len;
+        switch (apdu->a_p1) {
+        case  0x80:
+            /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
+             * the rest */
+            pki_applet->sign_buffer = sign_buffer;
+            pki_applet->sign_buffer_len = size;
+            *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
+            return VCARD_DONE;
+        case 0x00:
+            /* we now have the whole buffer, do the operation, result will be
+             * in the sign_buffer */
+            status = vcard_emul_rsa_op(card, pki_applet->key,
+                                       sign_buffer, size);
+            if (status != VCARD7816_STATUS_SUCCESS) {
+                *response = vcard_make_response(status);
+                break;
+            }
+            *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le,
+                                                     VCARD7816_STATUS_SUCCESS);
+            if (*response == NULL) {
+                *response = vcard_make_response(
+                                VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+            }
+            break;
+        default:
+           *response = vcard_make_response(
+                                VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        qemu_free(sign_buffer);
+        pki_applet->sign_buffer = NULL;
+        pki_applet->sign_buffer_len = 0;
+        return VCARD_DONE;
+    case CAC_READ_BUFFER:
+        /* new CAC call, go ahead and use the old version for now */
+        /* TODO: implement */
+        *response = vcard_make_response(
+                                VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+
+static VCardStatus
+cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
+                           VCardResponse **response)
+{
+    switch (apdu->a_ins) {
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+        return VCARD_DONE;
+    case CAC_READ_BUFFER:
+        /* new CAC call, go ahead and use the old version for now */
+        /* TODO: implement */
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+
+/*
+ * TODO: if we ever want to support general CAC middleware, we will need to
+ * implement the various containers.
+ */
+static VCardStatus
+cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
+                                  VCardResponse **response)
+{
+    switch (apdu->a_ins) {
+    case CAC_READ_BUFFER:
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    default:
+        break;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+/*
+ * utilities for creating and destroying the private applet data
+ */
+static void
+cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
+{
+    CACPKIAppletData *pki_applet_data = NULL;
+    if (pki_applet_data == NULL) {
+        return;
+    }
+    pki_applet_data = &(applet_private->u.pki_data);
+    if (pki_applet_data->cert != NULL) {
+        qemu_free(pki_applet_data->cert);
+    }
+    if (pki_applet_data->sign_buffer != NULL) {
+        qemu_free(pki_applet_data->sign_buffer);
+    }
+    if (pki_applet_data->key != NULL) {
+        vcard_emul_delete_key(pki_applet_data->key);
+    }
+    qemu_free(applet_private);
+}
+
+static VCardAppletPrivate *
+cac_new_pki_applet_private(const unsigned char *cert,
+                           int cert_len, VCardKey *key)
+{
+    CACPKIAppletData *pki_applet_data = NULL;
+    VCardAppletPrivate *applet_private = NULL;
+    applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate));
+
+    pki_applet_data = &(applet_private->u.pki_data);
+    pki_applet_data->cert_buffer = NULL;
+    pki_applet_data->cert_buffer_len = 0;
+    pki_applet_data->sign_buffer = NULL;
+    pki_applet_data->sign_buffer_len = 0;
+    pki_applet_data->key = NULL;
+    pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1);
+    /*
+     * if we want to support compression, then we simply change the 0 to a 1
+     * and compress the cert data with libz
+     */
+    pki_applet_data->cert[0] = 0; /* not compressed */
+    memcpy(&pki_applet_data->cert[1], cert, cert_len);
+    pki_applet_data->cert_len = cert_len+1;
+
+    pki_applet_data->key = key;
+    return applet_private;
+}
+
+
+/*
+ * create a new cac applet which links to a given cert
+ */
+static VCardApplet *
+cac_new_pki_applet(int i, const unsigned char *cert,
+                   int cert_len, VCardKey *key)
+{
+    VCardAppletPrivate *applet_private = NULL;
+    VCardApplet *applet = NULL;
+    unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
+    int pki_aid_len = sizeof(pki_aid);
+
+    pki_aid[pki_aid_len-1] = i;
+
+    applet_private = cac_new_pki_applet_private(cert, cert_len, key);
+    if (applet_private == NULL) {
+        goto failure;
+    }
+    applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
+                              pki_aid, pki_aid_len);
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_set_applet_private(applet, applet_private,
+                             cac_delete_pki_applet_private);
+    applet_private = NULL;
+
+    return applet;
+
+failure:
+    if (applet_private != NULL) {
+        cac_delete_pki_applet_private(applet_private);
+    }
+    return NULL;
+}
+
+
+static unsigned char cac_default_container_aid[] = {
+    0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
+static unsigned char cac_id_aid[] = {
+    0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
+/*
+ * Initialize the cac card. This is the only public function in this file. All
+ * the rest are connected through function pointers.
+ */
+VCardStatus
+cac_card_init(VReader *reader, VCard *card,
+              const char *params,
+              unsigned char * const *cert,
+              int cert_len[],
+              VCardKey *key[] /* adopt the keys*/,
+              int cert_count)
+{
+    int i;
+    VCardApplet *applet;
+
+    /* CAC Cards are VM Cards */
+    vcard_set_type(card, VCARD_VM);
+
+    /* create one PKI applet for each cert */
+    for (i = 0; i < cert_count; i++) {
+        applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
+        if (applet == NULL) {
+            goto failure;
+        }
+        vcard_add_applet(card, applet);
+    }
+
+    /* create a default blank container applet */
+    applet = vcard_new_applet(cac_applet_container_process_apdu,
+                              NULL, cac_default_container_aid,
+                              sizeof(cac_default_container_aid));
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_add_applet(card, applet);
+
+    /* create a default blank container applet */
+    applet = vcard_new_applet(cac_applet_id_process_apdu,
+                              NULL, cac_id_aid,
+                              sizeof(cac_id_aid));
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_add_applet(card, applet);
+    return VCARD_DONE;
+
+failure:
+    return VCARD_FAIL;
+}
+
diff --git a/qemu-0.15.x/libcacard/cac.h b/qemu-0.15.x/libcacard/cac.h
new file mode 100644
index 0000000..15a61be
--- /dev/null
+++ b/qemu-0.15.x/libcacard/cac.h
@@ -0,0 +1,23 @@
+/*
+ * defines the entry point for the cac card. Only used by cac.c anc
+ * vcard_emul_type.c
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef CAC_H
+#define CAC_H 1
+#include "vcard.h"
+#include "vreader.h"
+/*
+ * Initialize the cac card. This is the only public function in this file. All
+ * the rest are connected through function pointers.
+ */
+VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params,
+              unsigned char * const *cert, int cert_len[],
+              VCardKey *key[] /* adopt the keys*/,
+              int cert_count);
+
+/* not yet implemented */
+VCardStatus cac_is_cac_card(VReader *reader);
+#endif
diff --git a/qemu-0.15.x/libcacard/card_7816.c b/qemu-0.15.x/libcacard/card_7816.c
new file mode 100644
index 0000000..eeea849
--- /dev/null
+++ b/qemu-0.15.x/libcacard/card_7816.c
@@ -0,0 +1,763 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+
+/*
+ * set the status bytes based on the status word
+ */
+static void
+vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status)
+{
+    unsigned char sw1, sw2;
+    response->b_status = status; /* make sure the status and swX representations
+                                  * are consistent */
+    sw1 = (status >> 8) & 0xff;
+    sw2 = status & 0xff;
+    response->b_sw1 = sw1;
+    response->b_sw2 = sw2;
+    response->b_data[response->b_len] = sw1;
+    response->b_data[response->b_len+1] = sw2;
+}
+
+/*
+ * set the status bytes in a response buffer
+ */
+static void
+vcard_response_set_status_bytes(VCardResponse *response,
+                               unsigned char sw1, unsigned char sw2)
+{
+    response->b_status = sw1 << 8 | sw2;
+    response->b_sw1 = sw1;
+    response->b_sw2 = sw2;
+    response->b_data[response->b_len] = sw1;
+    response->b_data[response->b_len+1] = sw2;
+}
+
+/*
+ * allocate a VCardResponse structure, plus space for the data buffer, and
+ * set up everything but the resonse bytes.
+ */
+VCardResponse *
+vcard_response_new_data(unsigned char *buf, int len)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = qemu_malloc(len + 2);
+    memcpy(new_response->b_data, buf, len);
+    new_response->b_total_len = len+2;
+    new_response->b_len = len;
+    new_response->b_type = VCARD_MALLOC;
+    return new_response;
+}
+
+static VCardResponse *
+vcard_init_buffer_response(VCard *card, unsigned char *buf, int len)
+{
+    VCardResponse *response;
+    VCardBufferResponse *buffer_response;
+
+    buffer_response = vcard_get_buffer_response(card);
+    if (buffer_response) {
+        vcard_set_buffer_response(card, NULL);
+        vcard_buffer_response_delete(buffer_response);
+    }
+    buffer_response = vcard_buffer_response_new(buf, len);
+    if (buffer_response == NULL) {
+        return NULL;
+    }
+    response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES,
+                                               len > 255 ? 0 : len);
+    if (response == NULL) {
+        return NULL;
+    }
+    vcard_set_buffer_response(card, buffer_response);
+    return response;
+}
+
+/*
+ * general buffer to hold results from APDU calls
+ */
+VCardResponse *
+vcard_response_new(VCard *card, unsigned char *buf,
+                   int len, int Le, vcard_7816_status_t status)
+{
+    VCardResponse *new_response;
+
+    if (len > Le) {
+        return vcard_init_buffer_response(card, buf, len);
+    }
+    new_response = vcard_response_new_data(buf, len);
+    if (new_response == NULL) {
+        return NULL;
+    }
+    vcard_response_set_status(new_response, status);
+    return new_response;
+}
+
+/*
+ * general buffer to hold results from APDU calls
+ */
+VCardResponse *
+vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le,
+                         unsigned char sw1, unsigned char sw2)
+{
+    VCardResponse *new_response;
+
+    if (len > Le) {
+        return vcard_init_buffer_response(card, buf, len);
+    }
+    new_response = vcard_response_new_data(buf, len);
+    if (new_response == NULL) {
+        return NULL;
+    }
+    vcard_response_set_status_bytes(new_response, sw1, sw2);
+    return new_response;
+}
+
+/*
+ * get a new Reponse buffer that only has a status.
+ */
+static VCardResponse *
+vcard_response_new_status(vcard_7816_status_t status)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = &new_response->b_sw1;
+    new_response->b_len = 0;
+    new_response->b_total_len = 2;
+    new_response->b_type = VCARD_MALLOC_STRUCT;
+    vcard_response_set_status(new_response, status);
+    return new_response;
+}
+
+/*
+ * same as above, but specify the status as separate bytes
+ */
+VCardResponse *
+vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = &new_response->b_sw1;
+    new_response->b_len = 0;
+    new_response->b_total_len = 2;
+    new_response->b_type = VCARD_MALLOC_STRUCT;
+    vcard_response_set_status_bytes(new_response, sw1, sw2);
+    return new_response;
+}
+
+
+/*
+ * free the response buffer. The Buffer has a type to handle the buffer
+ * allocated in other ways than through malloc.
+ */
+void
+vcard_response_delete(VCardResponse *response)
+{
+    if (response == NULL) {
+        return;
+    }
+    switch (response->b_type) {
+    case VCARD_MALLOC:
+        /* everything was malloc'ed */
+        if (response->b_data) {
+            qemu_free(response->b_data);
+        }
+        qemu_free(response);
+        break;
+    case VCARD_MALLOC_DATA:
+        /* only the data buffer was malloc'ed */
+        if (response->b_data) {
+            qemu_free(response->b_data);
+        }
+        break;
+    case VCARD_MALLOC_STRUCT:
+        /* only the structure was malloc'ed */
+        qemu_free(response);
+        break;
+    case VCARD_STATIC:
+        break;
+    }
+}
+
+/*
+ * decode the class bit and set our generic type field, channel, and
+ * secure messaging values.
+ */
+static vcard_7816_status_t
+vcard_apdu_set_class(VCardAPDU *apdu) {
+    apdu->a_channel = 0;
+    apdu->a_secure_messaging = 0;
+    apdu->a_type = apdu->a_cla & 0xf0;
+    apdu->a_gen_type = VCARD_7816_ISO;
+
+    /* parse the class  tables 8 & 9 of the 7816-4 Part 4 spec */
+    switch (apdu->a_type) {
+        /* we only support the basic types */
+    case 0x00:
+    case 0x80:
+    case 0x90:
+    case 0xa0:
+        apdu->a_channel = apdu->a_cla & 3;
+        apdu->a_secure_messaging = apdu->a_cla & 0xe;
+        break;
+    case 0xb0:
+    case 0xc0:
+        break;
+
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+        /* Reserved for future use */
+        apdu->a_gen_type = VCARD_7816_RFU;
+        break;
+    case 0xd0:
+    case 0xe0:
+    case 0xf0:
+    default:
+        apdu->a_gen_type =
+            (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY;
+        break;
+    }
+    return VCARD7816_STATUS_SUCCESS;
+}
+
+/*
+ * set the Le and Lc fiels according to table 5 of the
+ * 7816-4 part 4 spec
+ */
+static vcard_7816_status_t
+vcard_apdu_set_length(VCardAPDU *apdu)
+{
+    int L, Le;
+
+    /* process according to table 5 of the 7816-4 Part 4 spec.
+     * variable names match the variables in the spec */
+    L = apdu->a_len-4; /* fixed APDU header */
+    apdu->a_Lc = 0;
+    apdu->a_Le = 0;
+    apdu->a_body = NULL;
+    switch (L) {
+    case 0:
+        /* 1 minimal apdu */
+        return VCARD7816_STATUS_SUCCESS;
+    case 1:
+        /* 2S only return values apdu */
+        /*   zero maps to 256 here */
+        apdu->a_Le = apdu->a_header->ah_Le ?
+                         apdu->a_header->ah_Le : 256;
+        return VCARD7816_STATUS_SUCCESS;
+    default:
+        /* if the ah_Le byte is zero and we have more than
+         * 1 byte in the header, then we must be using extended Le and Lc.
+         * process the extended now. */
+        if (apdu->a_header->ah_Le == 0) {
+            if (L < 3) {
+                /* coding error, need at least 3 bytes */
+                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+            }
+            /* calculate the first extended value. Could be either Le or Lc */
+            Le = (apdu->a_header->ah_body[0] << 8)
+               || apdu->a_header->ah_body[1];
+            if (L == 3) {
+                /* 2E extended, return data only */
+                /*   zero maps to 65536 */
+                apdu->a_Le = Le ? Le : 65536;
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            if (Le == 0) {
+                /* reserved for future use, probably for next time we need
+                 * to extend the lengths */
+                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+            }
+            /* we know that the first extended value is Lc now */
+            apdu->a_Lc = Le;
+            apdu->a_body = &apdu->a_header->ah_body[2];
+            if (L == Le+3) {
+                /* 3E extended, only body parameters */
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            if (L == Le+5) {
+                /* 4E extended, parameters and return data */
+                Le = (apdu->a_data[apdu->a_len-2] << 8)
+                   || apdu->a_data[apdu->a_len-1];
+                apdu->a_Le = Le ? Le : 65536;
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+        }
+        /* not extended */
+        apdu->a_Lc = apdu->a_header->ah_Le;
+        apdu->a_body = &apdu->a_header->ah_body[0];
+        if (L ==  apdu->a_Lc + 1) {
+            /* 3S only body parameters */
+            return VCARD7816_STATUS_SUCCESS;
+        }
+        if (L ==  apdu->a_Lc + 2) {
+            /* 4S parameters and return data */
+            Le = apdu->a_data[apdu->a_len-1];
+            apdu->a_Le = Le ?  Le : 256;
+            return VCARD7816_STATUS_SUCCESS;
+        }
+        break;
+    }
+    return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+}
+
+/*
+ * create a new APDU from a raw set of bytes. This will decode all the
+ * above fields. users of VCARDAPDU's can then depend on the already decoded
+ * values.
+ */
+VCardAPDU *
+vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status)
+{
+    VCardAPDU *new_apdu;
+
+    *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
+    if (len < 4) {
+        *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+        return NULL;
+    }
+
+    new_apdu = (VCardAPDU *)qemu_malloc(sizeof(VCardAPDU));
+    new_apdu->a_data = qemu_malloc(len);
+    memcpy(new_apdu->a_data, raw_apdu, len);
+    new_apdu->a_len = len;
+    *status = vcard_apdu_set_class(new_apdu);
+    if (*status != VCARD7816_STATUS_SUCCESS) {
+        qemu_free(new_apdu);
+        return NULL;
+    }
+    *status = vcard_apdu_set_length(new_apdu);
+    if (*status != VCARD7816_STATUS_SUCCESS) {
+        qemu_free(new_apdu);
+        new_apdu = NULL;
+    }
+    return new_apdu;
+}
+
+void
+vcard_apdu_delete(VCardAPDU *apdu)
+{
+    if (apdu == NULL) {
+        return;
+    }
+    if (apdu->a_data) {
+        qemu_free(apdu->a_data);
+    }
+    qemu_free(apdu);
+}
+
+
+/*
+ * declare response buffers for all the 7816 defined error codes
+ */
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(
+                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS)
+VCARD_RESPONSE_NEW_STATIC_STATUS(
+                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL)
+
+/*
+ * return a single response code. This function cannot fail. It will always
+ * return a response.
+ */
+VCardResponse *
+vcard_make_response(vcard_7816_status_t status)
+{
+    VCardResponse *response = NULL;
+
+    switch (status) {
+    /* known 7816 response codes */
+    case VCARD7816_STATUS_SUCCESS:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_SUCCESS);
+    case VCARD7816_STATUS_WARNING:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING);
+    case VCARD7816_STATUS_WARNING_RET_CORUPT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_RET_CORUPT);
+    case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE);
+    case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED);
+    case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID);
+    case VCARD7816_STATUS_WARNING_CHANGE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_CHANGE);
+    case VCARD7816_STATUS_WARNING_FILE_FILLED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_FILE_FILLED);
+    case VCARD7816_STATUS_EXC_ERROR:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR);
+    case VCARD7816_STATUS_EXC_ERROR_CHANGE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR_CHANGE);
+    case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+    case VCARD7816_STATUS_ERROR_WRONG_LENGTH:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_LENGTH);
+    case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE);
+    case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED);
+    case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED);
+    case VCARD7816_STATUS_ERROR_DATA_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_INVALID);
+    case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+    case VCARD7816_STATUS_ERROR_DATA_NO_EF:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_NO_EF);
+    case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING);
+    case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA);
+    case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE);
+    case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT);
+    case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+    case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT);
+    case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2);
+    case VCARD7816_STATUS_ERROR_INS_CODE_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_INS_CODE_INVALID);
+    case VCARD7816_STATUS_ERROR_CLA_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CLA_INVALID);
+    case VCARD7816_STATUS_ERROR_GENERAL:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_GENERAL);
+    default:
+        /* we don't know this status code, create a response buffer to
+         * hold it */
+        response = vcard_response_new_status(status);
+        if (response == NULL) {
+            /* couldn't allocate the buffer, return memmory error */
+            return VCARD_RESPONSE_GET_STATIC(
+                        VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+    }
+    assert(response);
+    return response;
+}
+
+/*
+ * Add File card support here if you need it.
+ */
+static VCardStatus
+vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu,
+                                   VCardResponse **response)
+{
+    /* TODO: if we want to support a virtual file system card, we do it here.
+     * It would probably be a pkcs #15 card type */
+    *response = vcard_make_response(
+                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
+
+/*
+ * VM card (including java cards)
+ */
+static VCardStatus
+vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
+                          VCardResponse **response)
+{
+    int bytes_to_copy, next_byte_count, count;
+    VCardApplet *current_applet;
+    VCardBufferResponse *buffer_response;
+    vcard_7816_status_t status;
+
+    /* parse the class first */
+    if (apdu->a_gen_type !=  VCARD_7816_ISO) {
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+
+    /* use a switch so that if we need to support secure channel stuff later,
+     * we know where to put it */
+    switch (apdu->a_secure_messaging) {
+    case 0x0: /* no SM */
+        break;
+    case 0x4: /* proprietary SM */
+    case 0x8: /* header not authenticated */
+    case 0xc: /* header authenticated */
+    default:
+        /* for now, don't try to support secure channel stuff in the
+         * virtual card. */
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+
+    /* now parse the instruction */
+    switch (apdu->a_ins) {
+    case  VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */
+    case  VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */
+    case  VCARD7816_INS_GET_CHALLENGE: /* secure channel op */
+    case  VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */
+    case  VCARD7816_INS_ERASE_BINARY: /* applet control op */
+    case  VCARD7816_INS_READ_BINARY: /* applet control op */
+    case  VCARD7816_INS_WRITE_BINARY: /* applet control op */
+    case  VCARD7816_INS_UPDATE_BINARY: /* applet control op */
+    case  VCARD7816_INS_READ_RECORD: /* file op */
+    case  VCARD7816_INS_WRITE_RECORD: /* file op */
+    case  VCARD7816_INS_UPDATE_RECORD: /* file op */
+    case  VCARD7816_INS_APPEND_RECORD: /* file op */
+    case  VCARD7816_INS_ENVELOPE:
+    case  VCARD7816_INS_PUT_DATA:
+        *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+
+    case  VCARD7816_INS_SELECT_FILE:
+        if (apdu->a_p1 != 0x04) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
+            break;
+        }
+
+        /* side effect, deselect the current applet if no applet has been found
+         * */
+        current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc);
+        vcard_select_applet(card, apdu->a_channel, current_applet);
+        if (current_applet) {
+            unsigned char *aid;
+            int aid_len;
+            aid = vcard_applet_get_aid(current_applet, &aid_len);
+            *response = vcard_response_new(card, aid, aid_len, apdu->a_Le,
+                                          VCARD7816_STATUS_SUCCESS);
+        } else {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+        }
+        break;
+
+    case  VCARD7816_INS_VERIFY:
+        if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
+        } else {
+            if (apdu->a_Lc == 0) {
+                /* handle pin count if possible */
+                count = vcard_emul_get_login_count(card);
+                if (count < 0) {
+                    *response = vcard_make_response(
+                                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+                } else {
+                    if (count > 0xf) {
+                        count = 0xf;
+                    }
+                    *response = vcard_response_new_status_bytes(
+                                                VCARD7816_SW1_WARNING_CHANGE,
+                                                                0xc0 | count);
+                    if (*response == NULL) {
+                        *response = vcard_make_response(
+                                    VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+                    }
+                }
+            } else {
+                    status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc);
+                *response = vcard_make_response(status);
+            }
+        }
+        break;
+
+    case VCARD7816_INS_GET_RESPONSE:
+        buffer_response = vcard_get_buffer_response(card);
+        if (!buffer_response) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+            /* handle error */
+            break;
+        }
+        bytes_to_copy = MIN(buffer_response->len, apdu->a_Le);
+        next_byte_count = MIN(256, buffer_response->len - bytes_to_copy);
+        *response = vcard_response_new_bytes(
+                        card, buffer_response->current, bytes_to_copy,
+                        apdu->a_Le,
+                        next_byte_count ?
+                        VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS,
+                        next_byte_count);
+        buffer_response->current += bytes_to_copy;
+        buffer_response->len -= bytes_to_copy;
+        if (*response == NULL || (next_byte_count == 0)) {
+            vcard_set_buffer_response(card, NULL);
+            vcard_buffer_response_delete(buffer_response);
+        }
+        if (*response == NULL) {
+            *response =
+                vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+        break;
+
+    case VCARD7816_INS_GET_DATA:
+        *response =
+            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+
+    default:
+        *response =
+            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+    }
+
+    /* response should have been set somewhere */
+    assert(*response != NULL);
+    return VCARD_DONE;
+}
+
+
+/*
+ * APDU processing starts here. This routes the card processing stuff to the
+ * right location.
+ */
+VCardStatus
+vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
+{
+    VCardStatus status;
+    VCardBufferResponse *buffer_response;
+
+    /* first handle any PTS commands, which aren't really APDU's */
+    if (apdu->a_type == VCARD_7816_PTS) {
+        /* the PTS responses aren't really responses either */
+        *response = vcard_response_new_data(apdu->a_data, apdu->a_len);
+        /* PTS responses have no status bytes */
+        (*response)->b_total_len = (*response)->b_len;
+        return VCARD_DONE;
+    }
+    buffer_response = vcard_get_buffer_response(card);
+    if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) {
+        /* clear out buffer_response, return an error */
+        vcard_set_buffer_response(card, NULL);
+        vcard_buffer_response_delete(buffer_response);
+        *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR);
+        return VCARD_DONE;
+    }
+
+    status = vcard_process_applet_apdu(card, apdu, response);
+    if (status != VCARD_NEXT) {
+        return status;
+    }
+    switch (vcard_get_type(card)) {
+    case VCARD_FILE_SYSTEM:
+        return vcard7816_file_system_process_apdu(card, apdu, response);
+    case VCARD_VM:
+        return vcard7816_vm_process_apdu(card, apdu, response);
+    case VCARD_DIRECT:
+        /* if we are type direct, then the applet should handle everything */
+        assert("VCARD_DIRECT: applet failure");
+        break;
+    }
+    *response =
+        vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
diff --git a/qemu-0.15.x/libcacard/card_7816.h b/qemu-0.15.x/libcacard/card_7816.h
new file mode 100644
index 0000000..2bb2a0d
--- /dev/null
+++ b/qemu-0.15.x/libcacard/card_7816.h
@@ -0,0 +1,62 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef CARD_7816_H
+#define CARD_7816_H  1
+
+#include "card_7816t.h"
+#include "vcardt.h"
+
+/*
+ * constructors for VCardResponse's
+ */
+/* response from a return buffer and a status */
+VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len,
+                                  int Le, vcard_7816_status_t status);
+/* response from a return buffer and status bytes */
+VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf,
+                                        int len, int Le,
+                                        unsigned char sw1, unsigned char sw2);
+/* response from just status bytes */
+VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
+                                               unsigned char sw2);
+/* response from just status: NOTE this cannot fail, it will alwyas return a
+ * valid response, if it can't allocate memory, the response will be
+ * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */
+VCardResponse *vcard_make_response(vcard_7816_status_t status);
+
+/* create a raw response (status has already been encoded */
+VCardResponse *vcard_response_new_data(unsigned char *buf, int len);
+
+
+
+
+/*
+ * destructor for VCardResponse.
+ *  Can be called with a NULL response
+ */
+void vcard_response_delete(VCardResponse *response);
+
+/*
+ * constructor for VCardAPDU
+ */
+VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len,
+                          unsigned short *status);
+
+/*
+ * destructor for VCardAPDU
+ *  Can be called with a NULL apdu
+ */
+void vcard_apdu_delete(VCardAPDU *apdu);
+
+/*
+ * APDU processing starts here. This routes the card processing stuff to the
+ * right location. Always returns a valid response.
+ */
+VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu,
+                               VCardResponse **response);
+
+#endif
diff --git a/qemu-0.15.x/libcacard/card_7816t.h b/qemu-0.15.x/libcacard/card_7816t.h
new file mode 100644
index 0000000..9333285
--- /dev/null
+++ b/qemu-0.15.x/libcacard/card_7816t.h
@@ -0,0 +1,165 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef CARD_7816T_H
+#define CARD_7816T_H 1
+
+typedef unsigned short vcard_7816_status_t;
+
+struct VCardResponseStruct {
+    unsigned char *b_data;
+    vcard_7816_status_t b_status;
+    unsigned char b_sw1;
+    unsigned char b_sw2;
+    int b_len;
+    int b_total_len;
+    enum VCardResponseBufferType {
+        VCARD_MALLOC,
+        VCARD_MALLOC_DATA,
+        VCARD_MALLOC_STRUCT,
+        VCARD_STATIC
+    } b_type;
+};
+
+#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \
+static const VCardResponse VCardResponse##stat = \
+        {(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \
+         ((stat) & 0xff), 0, 2, VCARD_STATIC};
+
+#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \
+static const VCardResponse VCARDResponse##sw1 = \
+        {(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \
+         (sw1), (sw2), 0, 2, VCARD_STATIC};
+
+/* cast away the const, callers need may need to 'free' the
+ * result, and const implies that they don't */
+#define VCARD_RESPONSE_GET_STATIC(name) \
+        ((VCardResponse *)(&VCardResponse##name))
+
+typedef enum {
+    VCARD_7816_ISO,
+    VCARD_7816_RFU,
+    VCARD_7816_PTS,
+    VCARD_7816_PROPIETARY
+} VCardAPDUType;
+
+
+/*
+ * 7816 header. All APDU's have this header.
+ * They must be laid out in this order.
+ */
+struct VCardAPDUHeader {
+    unsigned char ah_cla;
+    unsigned char ah_ins;
+    unsigned char ah_p1;
+    unsigned char ah_p2;
+    unsigned char ah_Le;
+    unsigned char ah_body[1]; /* indefinate length */
+};
+
+/*
+ * 7816 APDU structure. The raw bytes are stored in the union and can be
+ * accessed directly through u.data (which is aliased as a_data).
+ *
+ * Names of the fields match the 7816 documentation.
+ */
+struct VCardAPDUStruct {
+    int a_len;                /* length of the whole buffer, including header */
+    int a_Lc;                 /* 7816 Lc (parameter length) value */
+    int a_Le;                 /* 7816 Le (expected result length) value */
+    unsigned char *a_body;    /* pointer to the parameter */
+    int a_channel;            /* decoded channel */
+    int a_secure_messaging;   /* decoded secure messaging type */
+    int a_type;               /* decoded type from cla (top nibble of class) */
+    VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */
+    union {
+        struct VCardAPDUHeader *header;
+        unsigned char   *data;
+    } u;
+/* give the subfields a unified look */
+#define a_header u.header
+#define a_data u.data
+#define a_cla a_header->ah_cla /* class */
+#define a_ins a_header->ah_ins /* instruction */
+#define a_p1 a_header->ah_p1   /* parameter 1 */
+#define a_p2 a_header->ah_p2   /* parameter 2 */
+};
+
+/* 7816 status codes */
+#define VCARD7816_STATUS_SUCCESS                              0x9000
+#define VCARD7816_STATUS_WARNING                              0x6200
+#define VCARD7816_STATUS_WARNING_RET_CORUPT                   0x6281
+#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE            0x6282
+#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED        0x6283
+#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID           0x6284
+#define VCARD7816_STATUS_WARNING_CHANGE                       0x6300
+#define VCARD7816_STATUS_WARNING_FILE_FILLED                  0x6381
+#define VCARD7816_STATUS_EXC_ERROR                            0x6400
+#define VCARD7816_STATUS_EXC_ERROR_CHANGE                     0x6500
+#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE             0x6581
+#define VCARD7816_STATUS_ERROR_WRONG_LENGTH                   0x6700
+#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED              0x6800
+#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED          0x6881
+#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED           0x6882
+#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED          0x6900
+#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981
+#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED         0x6982
+#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED         0x6983
+#define VCARD7816_STATUS_ERROR_DATA_INVALID                   0x6984
+#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED        0x6985
+#define VCARD7816_STATUS_ERROR_DATA_NO_EF                     0x6986
+#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING              0x6987
+#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT            0x6988
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS               0x6a00
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA       0x6a80
+#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED         0x6a81
+#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND                 0x6a82
+#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND               0x6a83
+#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE              0x6a84
+#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT            0x6a85
+#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT                0x6a86
+#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT          0x6a87
+#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND                 0x6a88
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2             0x6b00
+#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID               0x6d00
+#define VCARD7816_STATUS_ERROR_CLA_INVALID                    0x6e00
+#define VCARD7816_STATUS_ERROR_GENERAL                        0x6f00
+/* 7816 sw1 codes */
+#define VCARD7816_SW1_SUCCESS               0x90
+#define VCARD7816_SW1_RESPONSE_BYTES        0x61
+#define VCARD7816_SW1_WARNING               0x62
+#define VCARD7816_SW1_WARNING_CHANGE        0x63
+#define VCARD7816_SW1_EXC_ERROR             0x64
+#define VCARD7816_SW1_EXC_ERROR_CHANGE      0x65
+#define VCARD7816_SW1_ERROR_WRONG_LENGTH    0x67
+#define VCARD7816_SW1_CLA_ERROR             0x68
+#define VCARD7816_SW1_COMMAND_ERROR         0x69
+#define VCARD7816_SW1_P1_P2_ERROR           0x6a
+#define VCARD7816_SW1_LE_ERROR              0x6c
+#define VCARD7816_SW1_INS_ERROR             0x6d
+#define VCARD7816_SW1_CLA_NOT_SUPPORTED     0x6e
+
+/* 7816 Instructions */
+#define VCARD7816_INS_MANAGE_CHANNEL        0x70
+#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82
+#define VCARD7816_INS_GET_CHALLENGE         0x84
+#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88
+#define VCARD7816_INS_ERASE_BINARY          0x0e
+#define VCARD7816_INS_READ_BINARY           0xb0
+#define VCARD7816_INS_WRITE_BINARY          0xd0
+#define VCARD7816_INS_UPDATE_BINARY         0xd6
+#define VCARD7816_INS_READ_RECORD           0xb2
+#define VCARD7816_INS_WRITE_RECORD          0xd2
+#define VCARD7816_INS_UPDATE_RECORD         0xdc
+#define VCARD7816_INS_APPEND_RECORD         0xe2
+#define VCARD7816_INS_ENVELOPE              0xc2
+#define VCARD7816_INS_PUT_DATA              0xda
+#define VCARD7816_INS_GET_DATA              0xca
+#define VCARD7816_INS_SELECT_FILE           0xa4
+#define VCARD7816_INS_VERIFY                0x20
+#define VCARD7816_INS_GET_RESPONSE          0xc0
+
+#endif
diff --git a/qemu-0.15.x/libcacard/event.c b/qemu-0.15.x/libcacard/event.c
new file mode 100644
index 0000000..bb2f921
--- /dev/null
+++ b/qemu-0.15.x/libcacard/event.c
@@ -0,0 +1,106 @@
+/*
+ * event queue implementation.
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu-thread.h"
+
+#include "vcard.h"
+#include "vreader.h"
+#include "vevent.h"
+
+VEvent *
+vevent_new(VEventType type, VReader *reader, VCard *card)
+{
+    VEvent *new_vevent;
+
+    new_vevent = (VEvent *)qemu_malloc(sizeof(VEvent));
+    new_vevent->next = NULL;
+    new_vevent->type = type;
+    new_vevent->reader = vreader_reference(reader);
+    new_vevent->card = vcard_reference(card);
+
+    return new_vevent;
+}
+
+void
+vevent_delete(VEvent *vevent)
+{
+    if (vevent == NULL) {
+        return;
+    }
+    vreader_free(vevent->reader);
+    vcard_free(vevent->card);
+    qemu_free(vevent);
+}
+
+/*
+ * VEvent queue management
+ */
+
+static VEvent *vevent_queue_head;
+static VEvent *vevent_queue_tail;
+static QemuMutex vevent_queue_lock;
+static QemuCond vevent_queue_condition;
+
+void vevent_queue_init(void)
+{
+    qemu_mutex_init(&vevent_queue_lock);
+    qemu_cond_init(&vevent_queue_condition);
+    vevent_queue_head = vevent_queue_tail = NULL;
+}
+
+void
+vevent_queue_vevent(VEvent *vevent)
+{
+    vevent->next = NULL;
+    qemu_mutex_lock(&vevent_queue_lock);
+    if (vevent_queue_head) {
+        assert(vevent_queue_tail);
+        vevent_queue_tail->next = vevent;
+    } else {
+        vevent_queue_head = vevent;
+    }
+    vevent_queue_tail = vevent;
+    qemu_cond_signal(&vevent_queue_condition);
+    qemu_mutex_unlock(&vevent_queue_lock);
+}
+
+/* must have lock */
+static VEvent *
+vevent_dequeue_vevent(void)
+{
+    VEvent *vevent = NULL;
+    if (vevent_queue_head) {
+        vevent = vevent_queue_head;
+        vevent_queue_head = vevent->next;
+        vevent->next = NULL;
+    }
+    return vevent;
+}
+
+VEvent *vevent_wait_next_vevent(void)
+{
+    VEvent *vevent;
+
+    qemu_mutex_lock(&vevent_queue_lock);
+    while ((vevent = vevent_dequeue_vevent()) == NULL) {
+        qemu_cond_wait(&vevent_queue_condition, &vevent_queue_lock);
+    }
+    qemu_mutex_unlock(&vevent_queue_lock);
+    return vevent;
+}
+
+VEvent *vevent_get_next_vevent(void)
+{
+    VEvent *vevent;
+
+    qemu_mutex_lock(&vevent_queue_lock);
+    vevent = vevent_dequeue_vevent();
+    qemu_mutex_unlock(&vevent_queue_lock);
+    return vevent;
+}
+
diff --git a/qemu-0.15.x/libcacard/eventt.h b/qemu-0.15.x/libcacard/eventt.h
new file mode 100644
index 0000000..0dc7bd4
--- /dev/null
+++ b/qemu-0.15.x/libcacard/eventt.h
@@ -0,0 +1,29 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef EVENTT_H
+#define EVENTT_H 1
+#include "vreadert.h"
+#include "vcardt.h"
+
+typedef struct VEventStruct VEvent;
+
+typedef enum {
+    VEVENT_READER_INSERT,
+    VEVENT_READER_REMOVE,
+    VEVENT_CARD_INSERT,
+    VEVENT_CARD_REMOVE,
+    VEVENT_LAST,
+} VEventType;
+
+struct VEventStruct {
+    VEvent *next;
+    VEventType type;
+    VReader *reader;
+    VCard *card;
+};
+#endif
+
+
diff --git a/qemu-0.15.x/libcacard/link_test.c b/qemu-0.15.x/libcacard/link_test.c
new file mode 100644
index 0000000..6f67a23
--- /dev/null
+++ b/qemu-0.15.x/libcacard/link_test.c
@@ -0,0 +1,22 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include "vcard.h"
+
+VCardStatus cac_card_init(const char *flags, VCard *card,
+                const unsigned char *cert[],
+                int cert_len[], VCardKey *key[] /* adopt the keys*/,
+                int cert_count);
+/*
+ * this will crash... just test the linkage right now
+ */
+
+main(int argc, char **argv)
+{
+    VCard *card; /* no constructor yet */
+    cac_card_init("", card, NULL, 0, NULL, 0);
+}
+
diff --git a/qemu-0.15.x/libcacard/vcard.c b/qemu-0.15.x/libcacard/vcard.c
new file mode 100644
index 0000000..29b4cce
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard.c
@@ -0,0 +1,339 @@
+/*
+ * implement the Java card standard.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816t.h"
+
+struct VCardAppletStruct {
+    VCardApplet   *next;
+    VCardProcessAPDU process_apdu;
+    VCardResetApplet reset_applet;
+    unsigned char *aid;
+    int aid_len;
+    void *applet_private;
+    VCardAppletPrivateFree applet_private_free;
+};
+
+struct VCardStruct {
+    int reference_count;
+    VCardApplet *applet_list;
+    VCardApplet *current_applet[MAX_CHANNEL];
+    VCardBufferResponse *vcard_buffer_response;
+    VCardType type;
+    VCardEmul *vcard_private;
+    VCardEmulFree vcard_private_free;
+    VCardGetAtr vcard_get_atr;
+};
+
+VCardBufferResponse *
+vcard_buffer_response_new(unsigned char *buffer, int size)
+{
+    VCardBufferResponse *new_buffer;
+
+    new_buffer = (VCardBufferResponse *)qemu_malloc(sizeof(VCardBufferResponse));
+    new_buffer->buffer = (unsigned char *)qemu_malloc(size);
+    memcpy(new_buffer->buffer, buffer, size);
+    new_buffer->buffer_len = size;
+    new_buffer->current = new_buffer->buffer;
+    new_buffer->len = size;
+    return new_buffer;
+}
+
+void
+vcard_buffer_response_delete(VCardBufferResponse *buffer_response)
+{
+    if (buffer_response == NULL) {
+        return;
+    }
+    if (buffer_response->buffer) {
+        qemu_free(buffer_response->buffer);
+    }
+    qemu_free(buffer_response);
+}
+
+
+/*
+ * clean up state after a reset
+ */
+void
+vcard_reset(VCard *card, VCardPower power)
+{
+    int i;
+    VCardApplet *applet = NULL;
+
+    if (card->type ==  VCARD_DIRECT) {
+        /* select the last applet */
+        VCardApplet *current_applet = NULL;
+        for (current_applet = card->applet_list; current_applet;
+                                       current_applet = current_applet->next) {
+            applet = current_applet;
+        }
+    }
+    for (i = 0; i < MAX_CHANNEL; i++) {
+        card->current_applet[i] = applet;
+    }
+    if (card->vcard_buffer_response) {
+        vcard_buffer_response_delete(card->vcard_buffer_response);
+        card->vcard_buffer_response = NULL;
+    }
+    vcard_emul_reset(card, power);
+    if (applet) {
+        applet->reset_applet(card, 0);
+    }
+}
+
+/* applet utilities */
+
+/*
+ * applet utilities
+ */
+/* constructor */
+VCardApplet *
+vcard_new_applet(VCardProcessAPDU applet_process_function,
+                 VCardResetApplet applet_reset_function,
+                 unsigned char *aid, int aid_len)
+{
+    VCardApplet *applet;
+
+    applet = (VCardApplet *)qemu_malloc(sizeof(VCardApplet));
+    applet->next = NULL;
+    applet->applet_private = NULL;
+    applet->applet_private_free = NULL;
+    applet->process_apdu = applet_process_function;
+    applet->reset_applet = applet_reset_function;
+
+    applet->aid = qemu_malloc(aid_len);
+    memcpy(applet->aid, aid, aid_len);
+    applet->aid_len = aid_len;
+    return applet;
+}
+
+/* destructor */
+void
+vcard_delete_applet(VCardApplet *applet)
+{
+    if (applet == NULL) {
+        return;
+    }
+    if (applet->applet_private_free) {
+        applet->applet_private_free(applet->applet_private);
+        applet->applet_private = NULL;
+    }
+    if (applet->aid) {
+        qemu_free(applet->aid);
+        applet->aid = NULL;
+    }
+    qemu_free(applet);
+}
+
+/* accessor */
+void
+vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private,
+                         VCardAppletPrivateFree private_free)
+{
+    if (applet->applet_private_free) {
+        applet->applet_private_free(applet->applet_private);
+    }
+    applet->applet_private = private;
+    applet->applet_private_free = private_free;
+}
+
+VCard *
+vcard_new(VCardEmul *private, VCardEmulFree private_free)
+{
+    VCard *new_card;
+    int i;
+
+    new_card = (VCard *)qemu_malloc(sizeof(VCard));
+    new_card->applet_list = NULL;
+    for (i = 0; i < MAX_CHANNEL; i++) {
+        new_card->current_applet[i] = NULL;
+    }
+    new_card->vcard_buffer_response = NULL;
+    new_card->type = VCARD_VM;
+    new_card->vcard_private = private;
+    new_card->vcard_private_free = private_free;
+    new_card->vcard_get_atr = NULL;
+    new_card->reference_count = 1;
+    return new_card;
+}
+
+VCard *
+vcard_reference(VCard *vcard)
+{
+    if (vcard == NULL) {
+        return NULL;
+    }
+    vcard->reference_count++;
+    return vcard;
+}
+
+void
+vcard_free(VCard *vcard)
+{
+    VCardApplet *current_applet = NULL;
+    VCardApplet *next_applet = NULL;
+
+    if (vcard == NULL) {
+        return;
+    }
+    vcard->reference_count--;
+    if (vcard->reference_count != 0) {
+        return;
+    }
+    if (vcard->vcard_private_free) {
+        (*vcard->vcard_private_free)(vcard->vcard_private);
+        vcard->vcard_private_free = 0;
+        vcard->vcard_private = 0;
+    }
+    for (current_applet = vcard->applet_list; current_applet;
+                                        current_applet = next_applet) {
+        next_applet = current_applet->next;
+        vcard_delete_applet(current_applet);
+    }
+    vcard_buffer_response_delete(vcard->vcard_buffer_response);
+    qemu_free(vcard);
+    return;
+}
+
+void
+vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len)
+{
+    if (vcard->vcard_get_atr) {
+        (*vcard->vcard_get_atr)(vcard, atr, atr_len);
+        return;
+    }
+    vcard_emul_get_atr(vcard, atr, atr_len);
+}
+
+void
+vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr)
+{
+    card->vcard_get_atr = vcard_get_atr;
+}
+
+
+VCardStatus
+vcard_add_applet(VCard *card, VCardApplet *applet)
+{
+    applet->next = card->applet_list;
+    card->applet_list = applet;
+    /* if our card-type is direct, always call the applet */
+    if (card->type ==  VCARD_DIRECT) {
+        int i;
+
+        for (i = 0; i < MAX_CHANNEL; i++) {
+            card->current_applet[i] = applet;
+        }
+    }
+    return VCARD_DONE;
+}
+
+/*
+ * manage applets
+ */
+VCardApplet *
+vcard_find_applet(VCard *card, unsigned char *aid, int aid_len)
+{
+    VCardApplet *current_applet;
+
+    for (current_applet = card->applet_list; current_applet;
+                                        current_applet = current_applet->next) {
+        if (current_applet->aid_len != aid_len) {
+            continue;
+        }
+        if (memcmp(current_applet->aid, aid, aid_len) == 0) {
+            break;
+        }
+    }
+    return current_applet;
+}
+
+unsigned char *
+vcard_applet_get_aid(VCardApplet *applet, int *aid_len)
+{
+    if (applet == NULL) {
+        return NULL;
+    }
+    *aid_len = applet->aid_len;
+    return applet->aid;
+}
+
+
+void
+vcard_select_applet(VCard *card, int channel, VCardApplet *applet)
+{
+    assert(channel < MAX_CHANNEL);
+    card->current_applet[channel] = applet;
+    /* reset the applet */
+    if (applet && applet->reset_applet) {
+        applet->reset_applet(card, channel);
+    }
+}
+
+VCardAppletPrivate *
+vcard_get_current_applet_private(VCard *card, int channel)
+{
+    VCardApplet *applet = card->current_applet[channel];
+
+    if (applet == NULL) {
+        return NULL;
+    }
+    return applet->applet_private;
+}
+
+VCardStatus
+vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu,
+                          VCardResponse **response)
+{
+    if (card->current_applet[apdu->a_channel]) {
+        return card->current_applet[apdu->a_channel]->process_apdu(
+                                                        card, apdu, response);
+    }
+    return VCARD_NEXT;
+}
+
+/*
+ * Accessor functions
+ */
+/* accessor functions for the response buffer */
+VCardBufferResponse *
+vcard_get_buffer_response(VCard *card)
+{
+    return card->vcard_buffer_response;
+}
+
+void
+vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer)
+{
+    card->vcard_buffer_response = buffer;
+}
+
+
+/* accessor functions for the type */
+VCardType
+vcard_get_type(VCard *card)
+{
+    return card->type;
+}
+
+void
+vcard_set_type(VCard *card, VCardType type)
+{
+    card->type = type;
+}
+
+/* accessor for private data */
+VCardEmul *
+vcard_get_private(VCard *vcard)
+{
+    return vcard->vcard_private;
+}
+
diff --git a/qemu-0.15.x/libcacard/vcard.h b/qemu-0.15.x/libcacard/vcard.h
new file mode 100644
index 0000000..47dc703
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard.h
@@ -0,0 +1,86 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef VCARD_H
+#define VCARD_H 1
+
+#include "vcardt.h"
+
+/*
+ * response buffer constructors and destructors.
+ *
+ * response buffers are used when we need to return more data than will fit in
+ * a normal APDU response (nominally 254 bytes).
+ */
+VCardBufferResponse *vcard_buffer_response_new(unsigned char *buffer, int size);
+void vcard_buffer_response_delete(VCardBufferResponse *buffer_response);
+
+
+/*
+ * clean up state on reset
+ */
+void vcard_reset(VCard *card, VCardPower power);
+
+/*
+ * applet utilities
+ */
+/*
+ * Constructor for a VCardApplet
+ */
+VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function,
+                              VCardResetApplet applet_reset_function,
+                              unsigned char *aid, int aid_len);
+
+/*
+ * destructor for a VCardApplet
+ *  Can be called with a NULL applet
+ */
+void vcard_delete_applet(VCardApplet *applet);
+
+/* accessor - set the card type specific private data */
+void vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *_private,
+                              VCardAppletPrivateFree private_free);
+
+/* set type of vcard */
+void vcard_set_type(VCard *card, VCardType type);
+
+/*
+ * utilities interacting with the current applet
+ */
+/* add a new applet to a card */
+VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
+/* find the applet on the card with the given aid */
+VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len);
+/* set the following applet to be current on the given channel */
+void vcard_select_applet(VCard *card, int channel, VCardApplet *applet);
+/* get the card type specific private data on the given channel */
+VCardAppletPrivate *vcard_get_current_applet_private(VCard *card, int channel);
+/* fetch the applet's id */
+unsigned char *vcard_applet_get_aid(VCardApplet *applet, int *aid_len);
+
+/* process the apdu for the current selected applet/file */
+VCardStatus vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu,
+                                      VCardResponse **response);
+/*
+ * VCard utilities
+ */
+/* constructor */
+VCard *vcard_new(VCardEmul *_private, VCardEmulFree private_free);
+/* get a reference */
+VCard *vcard_reference(VCard *);
+/* destructor (reference counted) */
+void vcard_free(VCard *);
+/* get the atr from the card */
+void vcard_get_atr(VCard *card, unsigned char *atr, int *atr_len);
+void vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr);
+
+/* accessor functions for the response buffer */
+VCardBufferResponse *vcard_get_buffer_response(VCard *card);
+void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer);
+/* accessor functions for the type */
+VCardType vcard_get_type(VCard *card);
+/* get the private data */
+VCardEmul *vcard_get_private(VCard *card);
+
+#endif
diff --git a/qemu-0.15.x/libcacard/vcard_emul.h b/qemu-0.15.x/libcacard/vcard_emul.h
new file mode 100644
index 0000000..963563f
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard_emul.h
@@ -0,0 +1,65 @@
+/*
+ * This is the actual card emulator.
+ *
+ * These functions can be implemented in different ways on different platforms
+ * using the underlying system primitives. For Linux it uses NSS, though direct
+ * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
+ * used. On Windows CAPI could be used.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef VCARD_EMUL_H
+#define VCARD_EMUL_H 1
+
+#include "card_7816t.h"
+#include "vcard.h"
+#include "vcard_emul_type.h"
+
+/*
+ * types
+ */
+typedef enum {
+    VCARD_EMUL_OK = 0,
+    VCARD_EMUL_FAIL,
+    /* return values by vcard_emul_init */
+    VCARD_EMUL_INIT_ALREADY_INITED,
+} VCardEmulError;
+
+/* options are emul specific. call card_emul_parse_args to change a string
+ * To an options struct */
+typedef struct VCardEmulOptionsStruct VCardEmulOptions;
+
+/*
+ * Login functions
+ */
+/* return the number of login attempts still possible on the card. if unknown,
+ * return -1 */
+int vcard_emul_get_login_count(VCard *card);
+/* login into the card, return the 7816 status word (sw2 || sw1) */
+vcard_7816_status_t vcard_emul_login(VCard *card, unsigned char *pin,
+                                     int pin_len);
+
+/*
+ * key functions
+ */
+/* delete a key */
+void vcard_emul_delete_key(VCardKey *key);
+/* RSA sign/decrypt with the key, signature happens 'in place' */
+vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                                  unsigned char *buffer, int buffer_size);
+
+void vcard_emul_reset(VCard *card, VCardPower power);
+void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len);
+
+/* Re-insert of a card that has been removed by force removal */
+VCardEmulError vcard_emul_force_card_insert(VReader *vreader);
+/* Force a card removal even if the card is not physically removed */
+VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
+
+VCardEmulOptions *vcard_emul_options(const char *args);
+VCardEmulError vcard_emul_init(const VCardEmulOptions *options);
+void vcard_emul_replay_insertion_events(void);
+void vcard_emul_usage(void);
+#endif
diff --git a/qemu-0.15.x/libcacard/vcard_emul_nss.c b/qemu-0.15.x/libcacard/vcard_emul_nss.c
new file mode 100644
index 0000000..f3db657
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard_emul_nss.c
@@ -0,0 +1,1157 @@
+/*
+ * This is the actual card emulator.
+ *
+ * These functions can be implemented in different ways on different platforms
+ * using the underlying system primitives. For Linux it uses NSS, though direct
+ * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
+ * used. On Windows CAPI could be used.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+/*
+ * NSS headers
+ */
+
+/* avoid including prototypes.h that redefines uint32 */
+#define NO_NSPR_10_SUPPORT
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <cert.h>
+#include <key.h>
+#include <secmod.h>
+#include <prthread.h>
+#include <secerr.h>
+
+#include "qemu-common.h"
+
+#include "vcard.h"
+#include "card_7816t.h"
+#include "vcard_emul.h"
+#include "vreader.h"
+#include "vevent.h"
+
+struct VCardKeyStruct {
+    CERTCertificate *cert;
+    PK11SlotInfo *slot;
+    SECKEYPrivateKey *key;
+};
+
+
+typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
+
+struct VReaderEmulStruct {
+    PK11SlotInfo *slot;
+    VCardEmulType default_type;
+    char *type_params;
+    PRBool present;
+    int     series;
+    VCard *saved_vcard;
+};
+
+/*
+ *  NSS Specific options
+ */
+struct VirtualReaderOptionsStruct {
+    char *name;
+    char *vname;
+    VCardEmulType card_type;
+    char *type_params;
+    char **cert_name;
+    int cert_count;
+};
+
+struct VCardEmulOptionsStruct {
+    void *nss_db;
+    VirtualReaderOptions *vreader;
+    int vreader_count;
+    VCardEmulType hw_card_type;
+    const char *hw_type_params;
+    PRBool use_hw;
+};
+
+static int nss_emul_init;
+
+/* if we have more that just the slot, define
+ * VCardEmulStruct here */
+
+/*
+ * allocate the set of arrays for certs, cert_len, key
+ */
+static PRBool
+vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
+                        VCardKey ***keysp, int cert_count)
+{
+    *certsp = NULL;
+    *cert_lenp = NULL;
+    *keysp = NULL;
+    *certsp = (unsigned char **)qemu_malloc(sizeof(unsigned char *)*cert_count);
+    *cert_lenp = (int *)qemu_malloc(sizeof(int)*cert_count);
+    *keysp = (VCardKey **)qemu_malloc(sizeof(VCardKey *)*cert_count);
+    return PR_TRUE;
+}
+
+/*
+ * Emulator specific card information
+ */
+typedef struct CardEmulCardStruct CardEmulPrivate;
+
+static VCardEmul *
+vcard_emul_new_card(PK11SlotInfo *slot)
+{
+    PK11_ReferenceSlot(slot);
+    /* currently we don't need anything other than the slot */
+    return (VCardEmul *)slot;
+}
+
+static void
+vcard_emul_delete_card(VCardEmul *vcard_emul)
+{
+    PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
+    if (slot == NULL) {
+        return;
+    }
+    PK11_FreeSlot(slot);
+}
+
+static PK11SlotInfo *
+vcard_emul_card_get_slot(VCard *card)
+{
+    /* note, the card is holding the reference, no need to get another one */
+    return (PK11SlotInfo *)vcard_get_private(card);
+}
+
+
+/*
+ * key functions
+ */
+/* private constructure */
+static VCardKey *
+vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
+{
+    VCardKey *key;
+
+    key = (VCardKey *)qemu_malloc(sizeof(VCardKey));
+    key->slot = PK11_ReferenceSlot(slot);
+    key->cert = CERT_DupCertificate(cert);
+    /* NOTE: if we aren't logged into the token, this could return NULL */
+    /* NOTE: the cert is a temp cert, not necessarily the cert in the token,
+     * use the DER version of this function */
+    key->key = PK11_FindKeyByDERCert(slot, cert, NULL);
+    return key;
+}
+
+/* destructor */
+void
+vcard_emul_delete_key(VCardKey *key)
+{
+    if (!nss_emul_init || (key == NULL)) {
+        return;
+    }
+    if (key->key) {
+        SECKEY_DestroyPrivateKey(key->key);
+        key->key = NULL;
+    }
+    if (key->cert) {
+        CERT_DestroyCertificate(key->cert);
+    }
+    if (key->slot) {
+        PK11_FreeSlot(key->slot);
+    }
+    return;
+}
+
+/*
+ * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
+ */
+static SECKEYPrivateKey *
+vcard_emul_get_nss_key(VCardKey *key)
+{
+    if (key->key) {
+        return key->key;
+    }
+    /* NOTE: if we aren't logged into the token, this could return NULL */
+    key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
+    return key->key;
+}
+
+/*
+ * Map NSS errors to 7816 errors
+ */
+static vcard_7816_status_t
+vcard_emul_map_error(int error)
+{
+    switch (error) {
+    case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    case SEC_ERROR_BAD_DATA:
+    case SEC_ERROR_OUTPUT_LEN:
+    case SEC_ERROR_INPUT_LEN:
+    case SEC_ERROR_INVALID_ARGS:
+    case SEC_ERROR_INVALID_ALGORITHM:
+    case SEC_ERROR_NO_KEY:
+    case SEC_ERROR_INVALID_KEY:
+    case SEC_ERROR_DECRYPTION_DISALLOWED:
+        return VCARD7816_STATUS_ERROR_DATA_INVALID;
+    case SEC_ERROR_NO_MEMORY:
+        return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
+    }
+    return VCARD7816_STATUS_EXC_ERROR_CHANGE;
+}
+
+/* RSA sign/decrypt with the key, signature happens 'in place' */
+vcard_7816_status_t
+vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                  unsigned char *buffer, int buffer_size)
+{
+    SECKEYPrivateKey *priv_key;
+    unsigned signature_len;
+    SECStatus rv;
+
+    if ((!nss_emul_init) || (key == NULL)) {
+        /* couldn't get the key, indicate that we aren't logged in */
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    }
+    priv_key = vcard_emul_get_nss_key(key);
+
+    /*
+     * this is only true of the rsa signature
+     */
+    signature_len = PK11_SignatureLen(priv_key);
+    if (buffer_size != signature_len) {
+        return  VCARD7816_STATUS_ERROR_DATA_INVALID;
+    }
+    rv = PK11_PrivDecryptRaw(priv_key, buffer, &signature_len, signature_len,
+                             buffer, buffer_size);
+    if (rv != SECSuccess) {
+        return vcard_emul_map_error(PORT_GetError());
+    }
+    assert(buffer_size == signature_len);
+    return VCARD7816_STATUS_SUCCESS;
+}
+
+/*
+ * Login functions
+ */
+/* return the number of login attempts still possible on the card. if unknown,
+ * return -1 */
+int
+vcard_emul_get_login_count(VCard *card)
+{
+    return -1;
+}
+
+/* login into the card, return the 7816 status word (sw2 || sw1) */
+vcard_7816_status_t
+vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
+{
+    PK11SlotInfo *slot;
+    unsigned char *pin_string = NULL;
+    int i;
+    SECStatus rv;
+
+    if (!nss_emul_init) {
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    }
+    slot = vcard_emul_card_get_slot(card);
+     /* We depend on the PKCS #11 module internal login state here because we
+      * create a separate process to handle each guest instance. If we needed
+      * to handle multiple guests from one process, then we would need to keep
+      * a lot of extra state in our card structure
+      * */
+    pin_string = qemu_malloc(pin_len+1);
+    memcpy(pin_string, pin, pin_len);
+    pin_string[pin_len] = 0;
+
+    /* handle CAC expanded pins correctly */
+    for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
+        pin_string[i] = 0;
+    }
+
+    rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
+    memset(pin_string, 0, pin_len);  /* don't let the pin hang around in memory
+                                        to be snooped */
+    qemu_free(pin_string);
+    if (rv == SECSuccess) {
+        return VCARD7816_STATUS_SUCCESS;
+    }
+    /* map the error from port get error */
+    return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+}
+
+void
+vcard_emul_reset(VCard *card, VCardPower power)
+{
+    PK11SlotInfo *slot;
+
+    if (!nss_emul_init) {
+        return;
+    }
+
+    /*
+     * if we reset the card (either power on or power off), we lose our login
+     * state
+     */
+    /* TODO: we may also need to send insertion/removal events? */
+    slot = vcard_emul_card_get_slot(card);
+    PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
+    return;
+}
+
+
+static VReader *
+vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
+{
+    VReaderList *reader_list = vreader_get_reader_list();
+    VReaderListEntry *current_entry = NULL;
+
+    if (reader_list == NULL) {
+        return NULL;
+    }
+    for (current_entry = vreader_list_get_first(reader_list); current_entry;
+                        current_entry = vreader_list_get_next(current_entry)) {
+        VReader *reader = vreader_list_get_reader(current_entry);
+        VReaderEmul *reader_emul = vreader_get_private(reader);
+        if (reader_emul->slot == slot) {
+            return reader;
+        }
+        vreader_free(reader);
+    }
+
+    return NULL;
+}
+
+/*
+ * create a new reader emul
+ */
+static VReaderEmul *
+vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
+{
+    VReaderEmul *new_reader_emul;
+
+    new_reader_emul = (VReaderEmul *)qemu_malloc(sizeof(VReaderEmul));
+
+    new_reader_emul->slot = PK11_ReferenceSlot(slot);
+    new_reader_emul->default_type = type;
+    new_reader_emul->type_params = strdup(params);
+    new_reader_emul->present = PR_FALSE;
+    new_reader_emul->series = 0;
+    new_reader_emul->saved_vcard = NULL;
+    return new_reader_emul;
+}
+
+static void
+vreader_emul_delete(VReaderEmul *vreader_emul)
+{
+    if (vreader_emul == NULL) {
+        return;
+    }
+    if (vreader_emul->slot) {
+        PK11_FreeSlot(vreader_emul->slot);
+    }
+    if (vreader_emul->type_params) {
+        qemu_free(vreader_emul->type_params);
+    }
+    qemu_free(vreader_emul);
+}
+
+/*
+ *  TODO: move this to emulater non-specific file
+ */
+static VCardEmulType
+vcard_emul_get_type(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+
+    vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
+        return vreader_emul->default_type;
+    }
+
+    return vcard_emul_type_select(vreader);
+}
+/*
+ *  TODO: move this to emulater non-specific file
+ */
+static const char *
+vcard_emul_get_type_params(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+
+    vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul && vreader_emul->type_params) {
+        return vreader_emul->type_params;
+    }
+
+    return "";
+}
+
+/* pull the slot out of the reader private data */
+static PK11SlotInfo *
+vcard_emul_reader_get_slot(VReader *vreader)
+{
+    VReaderEmul *vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul == NULL) {
+        return NULL;
+    }
+    return vreader_emul->slot;
+}
+
+/*
+ *  Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate
+ *  historical bytes for any software emulated card. The remaining bytes can be
+ *  used to indicate the actual emulator
+ */
+static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' };
+
+void
+vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len)
+{
+    int len = MIN(sizeof(nss_atr), *atr_len);
+    assert(atr != NULL);
+
+    memcpy(atr, nss_atr, len);
+    *atr_len = len;
+    return;
+}
+
+/*
+ * create a new card from certs and keys
+ */
+static VCard *
+vcard_emul_make_card(VReader *reader,
+                     unsigned char * const *certs, int *cert_len,
+                     VCardKey *keys[], int cert_count)
+{
+    VCardEmul *vcard_emul;
+    VCard *vcard;
+    PK11SlotInfo *slot;
+    VCardEmulType type;
+    const char *params;
+
+    type = vcard_emul_get_type(reader);
+
+    /* ignore the inserted card */
+    if (type == VCARD_EMUL_NONE) {
+        return NULL;
+    }
+    slot = vcard_emul_reader_get_slot(reader);
+    if (slot == NULL) {
+        return NULL;
+    }
+
+    params = vcard_emul_get_type_params(reader);
+    /* params these can be NULL */
+
+    vcard_emul = vcard_emul_new_card(slot);
+    if (vcard_emul == NULL) {
+        return NULL;
+    }
+    vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
+    if (vcard == NULL) {
+        vcard_emul_delete_card(vcard_emul);
+        return NULL;
+    }
+    vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
+    return vcard;
+}
+
+
+/*
+ * 'clone' a physical card as a virtual card
+ */
+static VCard *
+vcard_emul_mirror_card(VReader *vreader)
+{
+    /*
+     * lookup certs using the C_FindObjects. The Stan Cert handle won't give
+     * us the real certs until we log in.
+     */
+    PK11GenericObject *firstObj, *thisObj;
+    int cert_count;
+    unsigned char **certs;
+    int *cert_len;
+    VCardKey **keys;
+    PK11SlotInfo *slot;
+    PRBool ret;
+
+    slot = vcard_emul_reader_get_slot(vreader);
+    if (slot == NULL) {
+        return NULL;
+    }
+
+    firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
+    if (firstObj == NULL) {
+        return NULL;
+    }
+
+    /* count the certs */
+    cert_count = 0;
+    for (thisObj = firstObj; thisObj;
+                             thisObj = PK11_GetNextGenericObject(thisObj)) {
+        cert_count++;
+    }
+
+    if (cert_count == 0) {
+        PK11_DestroyGenericObjects(firstObj);
+        return NULL;
+    }
+
+    /* allocate the arrays */
+    ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
+    if (ret == PR_FALSE) {
+        return NULL;
+    }
+
+    /* fill in the arrays */
+    cert_count = 0;
+    for (thisObj = firstObj; thisObj;
+                             thisObj = PK11_GetNextGenericObject(thisObj)) {
+        SECItem derCert;
+        CERTCertificate *cert;
+        SECStatus rv;
+
+        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
+                                   CKA_VALUE, &derCert);
+        if (rv != SECSuccess) {
+            continue;
+        }
+        /* create floating temp cert. This gives us a cert structure even if
+         * the token isn't logged in */
+        cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
+                                       NULL, PR_FALSE, PR_TRUE);
+        SECITEM_FreeItem(&derCert, PR_FALSE);
+        if (cert == NULL) {
+            continue;
+        }
+
+        certs[cert_count] = cert->derCert.data;
+        cert_len[cert_count] = cert->derCert.len;
+        keys[cert_count] = vcard_emul_make_key(slot, cert);
+        cert_count++;
+        CERT_DestroyCertificate(cert); /* key obj still has a reference */
+    }
+
+    /* now create the card */
+    return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
+}
+
+static VCardEmulType default_card_type = VCARD_EMUL_NONE;
+static const char *default_type_params = "";
+
+/*
+ * This thread looks for card and reader insertions and puts events on the
+ * event queue
+ */
+static void
+vcard_emul_event_thread(void *arg)
+{
+    PK11SlotInfo *slot;
+    VReader *vreader;
+    VReaderEmul *vreader_emul;
+    VCard *vcard;
+    SECMODModule *module = (SECMODModule *)arg;
+
+    do {
+        slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
+        if (slot == NULL) {
+            break;
+        }
+        vreader = vcard_emul_find_vreader_from_slot(slot);
+        if (vreader == NULL) {
+            /* new vreader */
+            vreader_emul = vreader_emul_new(slot, default_card_type,
+                                            default_type_params);
+            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
+                                  vreader_emul_delete);
+            PK11_FreeSlot(slot);
+            slot = NULL;
+            vreader_add_reader(vreader);
+            vreader_free(vreader);
+            continue;
+        }
+        /* card remove/insert */
+        vreader_emul = vreader_get_private(vreader);
+        if (PK11_IsPresent(slot)) {
+            int series = PK11_GetSlotSeries(slot);
+            if (series != vreader_emul->series) {
+                if (vreader_emul->present) {
+                    vreader_insert_card(vreader, NULL);
+                }
+                vcard = vcard_emul_mirror_card(vreader);
+                vreader_insert_card(vreader, vcard);
+                vcard_free(vcard);
+            }
+            vreader_emul->series = series;
+            vreader_emul->present = 1;
+            vreader_free(vreader);
+            PK11_FreeSlot(slot);
+            continue;
+        }
+        if (vreader_emul->present) {
+            vreader_insert_card(vreader, NULL);
+        }
+        vreader_emul->series = 0;
+        vreader_emul->present = 0;
+        PK11_FreeSlot(slot);
+        vreader_free(vreader);
+    } while (1);
+}
+
+/* if the card is inserted when we start up, make sure our state is correct */
+static void
+vcard_emul_init_series(VReader *vreader, VCard *vcard)
+{
+    VReaderEmul *vreader_emul = vreader_get_private(vreader);
+    PK11SlotInfo *slot = vreader_emul->slot;
+
+    vreader_emul->present = PK11_IsPresent(slot);
+    vreader_emul->series = PK11_GetSlotSeries(slot);
+    if (vreader_emul->present == 0) {
+        vreader_insert_card(vreader, NULL);
+    }
+}
+
+/*
+ * each module has a separate wait call, create a thread for each module that
+ * we are using.
+ */
+static void
+vcard_emul_new_event_thread(SECMODModule *module)
+{
+    PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
+                     module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
+                     PR_UNJOINABLE_THREAD, 0);
+}
+
+static const VCardEmulOptions default_options = {
+    .nss_db = NULL,
+    .vreader = NULL,
+    .vreader_count = 0,
+    .hw_card_type = VCARD_EMUL_CAC,
+    .hw_type_params = "",
+    .use_hw = PR_TRUE
+};
+
+
+/*
+ *  NSS needs the app to supply a password prompt. In our case the only time
+ *  the password is supplied is as part of the Login APDU. The actual password
+ *  is passed in the pw_arg in that case. In all other cases pw_arg should be
+ *  NULL.
+ */
+static char *
+vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
+{
+    /* if it didn't work the first time, don't keep trying */
+    if (retries) {
+        return NULL;
+    }
+    /* we are looking up a password when we don't have one in hand */
+    if (pw_arg == NULL) {
+        return NULL;
+    }
+    /* TODO: we really should verify that were are using the right slot */
+    return PORT_Strdup(pw_arg);
+}
+
+/* Force a card removal even if the card is not physically removed */
+VCardEmulError
+vcard_emul_force_card_remove(VReader *vreader)
+{
+    if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
+        return VCARD_EMUL_FAIL; /* card is already removed */
+    }
+
+    /* OK, remove it */
+    vreader_insert_card(vreader, NULL);
+    return VCARD_EMUL_OK;
+}
+
+/* Re-insert of a card that has been removed by force removal */
+VCardEmulError
+vcard_emul_force_card_insert(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+    VCard *vcard;
+
+    if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
+        return VCARD_EMUL_FAIL; /* card is already removed */
+    }
+    vreader_emul = vreader_get_private(vreader);
+
+    /* if it's a softcard, get the saved vcard from the reader emul structure */
+    if (vreader_emul->saved_vcard) {
+        vcard = vcard_reference(vreader_emul->saved_vcard);
+    } else {
+        /* it must be a physical card, rebuild it */
+        if (!PK11_IsPresent(vreader_emul->slot)) {
+            /* physical card has been removed, not way to reinsert it */
+            return VCARD_EMUL_FAIL;
+        }
+        vcard = vcard_emul_mirror_card(vreader);
+    }
+    vreader_insert_card(vreader, vcard);
+    vcard_free(vcard);
+
+    return VCARD_EMUL_OK;
+}
+
+
+static PRBool
+module_has_removable_hw_slots(SECMODModule *mod)
+{
+    int i;
+    PRBool ret = PR_FALSE;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+
+    if (!moduleLock) {
+        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+        return ret;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for (i = 0; i < mod->slotCount; i++) {
+        PK11SlotInfo *slot = mod->slots[i];
+        if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
+            ret = PR_TRUE;
+            break;
+        }
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    return ret;
+}
+
+/* Previously we returned FAIL if no readers found. This makes
+ * no sense when using hardware, since there may be no readers connected
+ * at the time vcard_emul_init is called, but they will be properly
+ * recognized later. So Instead return FAIL only if no_hw==1 and no
+ * vcards can be created (indicates error with certificates provided
+ * or db), or if any other higher level error (NSS error, missing coolkey). */
+static int vcard_emul_init_called;
+
+VCardEmulError
+vcard_emul_init(const VCardEmulOptions *options)
+{
+    SECStatus rv;
+    PRBool ret, has_readers = PR_FALSE, need_coolkey_module;
+    VReader *vreader;
+    VReaderEmul *vreader_emul;
+    SECMODListLock *module_lock;
+    SECMODModuleList *module_list;
+    SECMODModuleList *mlp;
+    int i;
+
+    if (vcard_emul_init_called) {
+        return VCARD_EMUL_INIT_ALREADY_INITED;
+    }
+    vcard_emul_init_called = 1;
+    vreader_init();
+    vevent_queue_init();
+
+    if (options == NULL) {
+        options = &default_options;
+    }
+
+    /* first initialize NSS */
+    if (options->nss_db) {
+        rv = NSS_Init(options->nss_db);
+    } else {
+        rv = NSS_Init("sql:/etc/pki/nssdb");
+    }
+    if (rv != SECSuccess) {
+        return VCARD_EMUL_FAIL;
+    }
+    /* Set password callback function */
+    PK11_SetPasswordFunc(vcard_emul_get_password);
+
+    /* set up soft cards emulated by software certs rather than physical cards
+     * */
+    for (i = 0; i < options->vreader_count; i++) {
+        int j;
+        int cert_count;
+        unsigned char **certs;
+        int *cert_len;
+        VCardKey **keys;
+        PK11SlotInfo *slot;
+
+        slot = PK11_FindSlotByName(options->vreader[i].name);
+        if (slot == NULL) {
+            continue;
+        }
+        vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
+                                        options->vreader[i].type_params);
+        vreader = vreader_new(options->vreader[i].vname, vreader_emul,
+                              vreader_emul_delete);
+        vreader_add_reader(vreader);
+        cert_count = options->vreader[i].cert_count;
+
+        ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
+                                      options->vreader[i].cert_count);
+        if (ret == PR_FALSE) {
+            continue;
+        }
+        cert_count = 0;
+        for (j = 0; j < options->vreader[i].cert_count; j++) {
+            /* we should have a better way of identifying certs than by
+             * nickname here */
+            CERTCertificate *cert = PK11_FindCertFromNickname(
+                                        options->vreader[i].cert_name[j],
+                                        NULL);
+            if (cert == NULL) {
+                continue;
+            }
+            certs[cert_count] = cert->derCert.data;
+            cert_len[cert_count] = cert->derCert.len;
+            keys[cert_count] = vcard_emul_make_key(slot, cert);
+            /* this is safe because the key is still holding a cert reference */
+            CERT_DestroyCertificate(cert);
+            cert_count++;
+        }
+        if (cert_count) {
+            VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
+                                                keys, cert_count);
+            vreader_insert_card(vreader, vcard);
+            vcard_emul_init_series(vreader, vcard);
+            /* allow insertion and removal of soft cards */
+            vreader_emul->saved_vcard = vcard_reference(vcard);
+            vcard_free(vcard);
+            vreader_free(vreader);
+            has_readers = PR_TRUE;
+        }
+    }
+
+    /* if we aren't suppose to use hw, skip looking up hardware tokens */
+    if (!options->use_hw) {
+        nss_emul_init = has_readers;
+        return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
+    }
+
+    /* make sure we have some PKCS #11 module loaded */
+    module_lock = SECMOD_GetDefaultModuleListLock();
+    module_list = SECMOD_GetDefaultModuleList();
+    need_coolkey_module = !has_readers;
+    SECMOD_GetReadLock(module_lock);
+    for (mlp = module_list; mlp; mlp = mlp->next) {
+        SECMODModule *module = mlp->module;
+        if (module_has_removable_hw_slots(module)) {
+            need_coolkey_module = PR_FALSE;
+            break;
+        }
+    }
+    SECMOD_ReleaseReadLock(module_lock);
+
+    if (need_coolkey_module) {
+        SECMODModule *module;
+        module = SECMOD_LoadUserModule(
+                    (char *)"library=libcoolkeypk11.so name=Coolkey",
+                    NULL, PR_FALSE);
+        if (module == NULL) {
+            return VCARD_EMUL_FAIL;
+        }
+        SECMOD_DestroyModule(module); /* free our reference, Module will still
+                                       * be on the list.
+                                       * until we destroy it */
+    }
+
+    /* now examine all the slots, finding which should be readers */
+    /* We should control this with options. For now we mirror out any
+     * removable hardware slot */
+    default_card_type = options->hw_card_type;
+    default_type_params = strdup(options->hw_type_params);
+
+    SECMOD_GetReadLock(module_lock);
+    for (mlp = module_list; mlp; mlp = mlp->next) {
+        SECMODModule *module = mlp->module;
+        PRBool has_emul_slots = PR_FALSE;
+
+        if (module == NULL) {
+                continue;
+        }
+
+        for (i = 0; i < module->slotCount; i++) {
+            PK11SlotInfo *slot = module->slots[i];
+
+            /* only map removable HW slots */
+            if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
+                continue;
+            }
+            vreader_emul = vreader_emul_new(slot, options->hw_card_type,
+                                            options->hw_type_params);
+            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
+                                  vreader_emul_delete);
+            vreader_add_reader(vreader);
+
+            has_readers = PR_TRUE;
+            has_emul_slots = PR_TRUE;
+
+            if (PK11_IsPresent(slot)) {
+                VCard *vcard;
+                vcard = vcard_emul_mirror_card(vreader);
+                vreader_insert_card(vreader, vcard);
+                vcard_emul_init_series(vreader, vcard);
+                vcard_free(vcard);
+            }
+        }
+        if (has_emul_slots) {
+            vcard_emul_new_event_thread(module);
+        }
+    }
+    SECMOD_ReleaseReadLock(module_lock);
+    nss_emul_init = has_readers;
+
+    return VCARD_EMUL_OK;
+}
+
+/* Recreate card insert events for all readers (user should
+ * deduce implied reader insert. perhaps do a reader insert as well?)
+ */
+void
+vcard_emul_replay_insertion_events(void)
+{
+    VReaderListEntry *current_entry;
+    VReaderListEntry *next_entry = NULL;
+    VReaderList *list = vreader_get_reader_list();
+
+    for (current_entry = vreader_list_get_first(list); current_entry;
+            current_entry = next_entry) {
+        VReader *vreader = vreader_list_get_reader(current_entry);
+        next_entry = vreader_list_get_next(current_entry);
+        vreader_queue_card_event(vreader);
+    }
+}
+
+/*
+ *  Silly little functions to help parsing our argument string
+ */
+static char *
+copy_string(const char *str, int str_len)
+{
+    char *new_str;
+
+    new_str = qemu_malloc(str_len+1);
+    memcpy(new_str, str, str_len);
+    new_str[str_len] = 0;
+    return new_str;
+}
+
+static int
+count_tokens(const char *str, char token, char token_end)
+{
+    int count = 0;
+
+    for (; *str; str++) {
+        if (*str == token) {
+            count++;
+        }
+        if (*str == token_end) {
+            break;
+        }
+    }
+    return count;
+}
+
+static const char *
+strip(const char *str)
+{
+    for (; *str && isspace(*str); str++) {
+    }
+    return str;
+}
+
+static const char *
+find_blank(const char *str)
+{
+    for (; *str && !isspace(*str); str++) {
+    }
+    return str;
+}
+
+
+/*
+ *  We really want to use some existing argument parsing library here. That
+ *  would give us a consistent look */
+static VCardEmulOptions options;
+#define READER_STEP 4
+
+VCardEmulOptions *
+vcard_emul_options(const char *args)
+{
+    int reader_count = 0;
+    VCardEmulOptions *opts;
+    char type_str[100];
+    int type_len;
+
+    /* Allow the future use of allocating the options structure on the fly */
+    memcpy(&options, &default_options, sizeof(options));
+    opts = &options;
+
+    do {
+        args = strip(args); /* strip off the leading spaces */
+        if (*args == ',') {
+            continue;
+        }
+        /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
+         *       cert_2,cert_3...) */
+        if (strncmp(args, "soft=", 5) == 0) {
+            const char *name;
+            const char *vname;
+            const char *type_params;
+            VCardEmulType type;
+            int name_length, vname_length, type_params_length, count, i;
+            VirtualReaderOptions *vreaderOpt = NULL;
+
+            args = strip(args + 5);
+            if (*args != '(') {
+                continue;
+            }
+            name = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            args = strip(args+1);
+            name_length = args - name - 2;
+            vname = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            vname_length = args - name - 2;
+            args = strip(args+1);
+            type_len = strpbrk(args, ",)") - args;
+            assert(sizeof(type_str) > type_len);
+            strncpy(type_str, args, type_len);
+            type_str[type_len] = 0;
+            type = vcard_emul_type_from_string(type_str);
+            args = strpbrk(args, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            args = strip(args++);
+            type_params = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            type_params_length = args - name;
+            args = strip(args++);
+            if (*args == 0) {
+                break;
+            }
+
+            if (opts->vreader_count >= reader_count) {
+                reader_count += READER_STEP;
+                vreaderOpt = realloc(opts->vreader,
+                                reader_count * sizeof(*vreaderOpt));
+                if (vreaderOpt == NULL) {
+                    return opts; /* we're done */
+                }
+            }
+            opts->vreader = vreaderOpt;
+            vreaderOpt = &vreaderOpt[opts->vreader_count];
+            vreaderOpt->name = copy_string(name, name_length);
+            vreaderOpt->vname = copy_string(vname, vname_length);
+            vreaderOpt->card_type = type;
+            vreaderOpt->type_params =
+                copy_string(type_params, type_params_length);
+            count = count_tokens(args, ',', ')');
+            vreaderOpt->cert_count = count;
+            vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *));
+            for (i = 0; i < count; i++) {
+                const char *cert = args + 1;
+                args = strpbrk(args + 1, ",)");
+                vreaderOpt->cert_name[i] = copy_string(cert, args - cert);
+            }
+            if (*args == ')') {
+                args++;
+            }
+            opts->vreader_count++;
+        /* use_hw= */
+        } else if (strncmp(args, "use_hw=", 7) == 0) {
+            args = strip(args+7);
+            if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
+                opts->use_hw = PR_FALSE;
+            } else {
+                opts->use_hw = PR_TRUE;
+            }
+            args = find_blank(args);
+        /* hw_type= */
+        } else if (strncmp(args, "hw_type=", 8) == 0) {
+            args = strip(args+8);
+            opts->hw_card_type = vcard_emul_type_from_string(args);
+            args = find_blank(args);
+        /* hw_params= */
+        } else if (strncmp(args, "hw_params=", 10) == 0) {
+            const char *params;
+            args = strip(args+10);
+            params = args;
+            args = find_blank(args);
+            opts->hw_type_params = copy_string(params, args-params);
+        /* db="/data/base/path" */
+        } else if (strncmp(args, "db=", 3) == 0) {
+            const char *db;
+            args = strip(args+3);
+            if (*args != '"') {
+                continue;
+            }
+            args++;
+            db = args;
+            args = strpbrk(args, "\"\n");
+            opts->nss_db = copy_string(db, args-db);
+            if (*args != 0) {
+                args++;
+            }
+        } else {
+            args = find_blank(args);
+        }
+    } while (*args != 0);
+
+    return opts;
+}
+
+void
+vcard_emul_usage(void)
+{
+   fprintf(stderr,
+"emul args: comma separated list of the following arguments\n"
+" db={nss_database}               (default sql:/etc/pki/nssdb)\n"
+" use_hw=[yes|no]                 (default yes)\n"
+" hw_type={card_type_to_emulate}  (default CAC)\n"
+" hw_param={param_for_card}       (default \"\")\n"
+" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
+"       {cert1},{cert2},{cert3}    (default none)\n"
+"\n"
+"  {nss_database}          The location of the NSS cert & key database\n"
+"  {card_type_to_emulate}  What card interface to present to the guest\n"
+"  {param_for_card}        Card interface specific parameters\n"
+"  {slot_name}             NSS slot that contains the certs\n"
+"  {vreader_name}          Virutal reader name to present to the guest\n"
+"  {certN}                 Nickname of the certificate n on the virtual card\n"
+"\n"
+"These parameters come as a single string separated by blanks or newlines."
+"\n"
+"Unless use_hw is set to no, all tokens that look like removable hardware\n"
+"tokens will be presented to the guest using the emulator specified by\n"
+"hw_type, and parameters of hw_param.\n"
+"\n"
+"If more one or more soft= parameters are specified, these readers will be\n"
+"presented to the guest\n");
+}
diff --git a/qemu-0.15.x/libcacard/vcard_emul_type.c b/qemu-0.15.x/libcacard/vcard_emul_type.c
new file mode 100644
index 0000000..59a1458
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard_emul_type.c
@@ -0,0 +1,57 @@
+/*
+ *  This file contains utility functions which abstract the different card
+ *  types.  The goal is that new card types can easily be added by simply
+ *  changing this file and vcard_emul_type.h. It is currently not a requirement
+ *  to dynamically add new card types.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <strings.h>
+#include "vcardt.h"
+#include "vcard_emul_type.h"
+#include "cac.h"
+
+VCardStatus vcard_init(VReader *vreader, VCard *vcard,
+                       VCardEmulType type, const char *params,
+                       unsigned char *const *cert, int cert_len[],
+                       VCardKey *key[], int cert_count)
+{
+    switch (type) {
+    case VCARD_EMUL_NONE:
+        break;
+    case VCARD_EMUL_CAC:
+        return cac_card_init(vreader, vcard, params,
+                             cert, cert_len, key,  cert_count);
+    /* add new ones here */
+    default:
+        break;
+    }
+    return VCARD_FAIL;
+}
+
+VCardEmulType vcard_emul_type_select(VReader *vreader)
+{
+#ifdef notdef
+    /* since there is only one emulator no need to call this function */
+    if (cac_is_cac_card(vreader) == VCARD_DONE) {
+        return VCARD_EMUL_CAC;
+    }
+#endif
+    /* return the default */
+    return VCARD_EMUL_CAC;
+}
+
+VCardEmulType vcard_emul_type_from_string(const char *type_string)
+{
+     if (strcasecmp(type_string, "CAC") == 0) {
+        return VCARD_EMUL_CAC;
+     }
+#ifdef USE_PASSTHRU
+     if (strcasecmp(type_string, "PASSTHRU") == 0) {
+        return VCARD_EMUL_PASSTHRU;
+     }
+#endif
+     return VCARD_EMUL_NONE;
+}
diff --git a/qemu-0.15.x/libcacard/vcard_emul_type.h b/qemu-0.15.x/libcacard/vcard_emul_type.h
new file mode 100644
index 0000000..0242f40
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcard_emul_type.h
@@ -0,0 +1,32 @@
+/*
+ *  This header file abstracts the different card types. The goal is new card
+ *  types can easily be added by simply changing this file and
+ *  vcard_emul_type.c. It is currently not a requirement to dynamically add new
+ *  card types.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef VCARD_EMUL_TYPE_H
+#define VCARD_EMUL_TYPE_H 1
+#include "vcardt.h"
+#include "vreadert.h"
+
+/*
+ * types
+ */
+typedef enum {
+     VCARD_EMUL_NONE = 0,
+     VCARD_EMUL_CAC,
+     VCARD_EMUL_PASSTHRU
+} VCardEmulType;
+
+/* functions used by the rest of the emulator */
+VCardStatus vcard_init(VReader *vreader, VCard *vcard, VCardEmulType type,
+                       const char *params, unsigned char * const *cert,
+                       int cert_len[], VCardKey *key[], int cert_count);
+VCardEmulType vcard_emul_type_select(VReader *vreader);
+VCardEmulType vcard_emul_type_from_string(const char *type_string);
+
+#endif
diff --git a/qemu-0.15.x/libcacard/vcardt.h b/qemu-0.15.x/libcacard/vcardt.h
new file mode 100644
index 0000000..538bdde
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vcardt.h
@@ -0,0 +1,64 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef VCARDT_H
+#define VCARDT_H 1
+
+/*
+ * these should come from some common spice header file
+ */
+#include <assert.h>
+#ifndef MIN
+#define MIN(x, y) ((x) > (y) ? (y) : (x))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+typedef struct VCardStruct VCard;
+typedef struct VCardAPDUStruct VCardAPDU;
+typedef struct VCardResponseStruct VCardResponse;
+typedef struct VCardBufferResponseStruct VCardBufferResponse;
+typedef struct VCardAppletStruct VCardApplet;
+typedef struct VCardAppletPrivateStruct VCardAppletPrivate;
+typedef struct VCardKeyStruct VCardKey;  /* opaque */
+typedef struct VCardEmulStruct VCardEmul;
+
+#define MAX_CHANNEL 4
+
+/* create an ATR with appropriate historical bytes */
+#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \
+                               'V', 'C', 'A', 'R', 'D', '_'
+
+
+typedef enum {
+    VCARD_DONE,
+    VCARD_NEXT,
+    VCARD_FAIL
+} VCardStatus;
+
+typedef enum {
+    VCARD_FILE_SYSTEM,
+    VCARD_VM,
+    VCARD_DIRECT
+} VCardType;
+
+typedef enum {
+    VCARD_POWER_ON,
+    VCARD_POWER_OFF
+} VCardPower;
+
+typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
+                                        VCardResponse **response);
+typedef VCardStatus (*VCardResetApplet)(VCard *card, int channel);
+typedef void (*VCardAppletPrivateFree) (VCardAppletPrivate *);
+typedef void (*VCardEmulFree) (VCardEmul *);
+typedef void (*VCardGetAtr) (VCard *, unsigned char *atr, int *atr_len);
+
+struct VCardBufferResponseStruct {
+    unsigned char *buffer;
+    int buffer_len;
+    unsigned char *current;
+    int len;
+};
+
+#endif
diff --git a/qemu-0.15.x/libcacard/vevent.h b/qemu-0.15.x/libcacard/vevent.h
new file mode 100644
index 0000000..38c3482
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vevent.h
@@ -0,0 +1,27 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef EVENT_H
+#define EVENT_H 1
+#include "eventt.h"
+#include "vreadert.h"
+#include "vcardt.h"
+
+VEvent *vevent_new(VEventType type, VReader *reader, VCard *card);
+void vevent_delete(VEvent *);
+
+/*
+ * VEvent queueing services
+ */
+void vevent_queue_vevent(VEvent *);
+void vevent_queue_init(void);
+
+/*
+ *  VEvent dequeing services
+ */
+VEvent *vevent_wait_next_vevent(void);
+VEvent *vevent_get_next_vevent(void);
+
+
+#endif
diff --git a/qemu-0.15.x/libcacard/vreader.c b/qemu-0.15.x/libcacard/vreader.c
new file mode 100644
index 0000000..4a0125b
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vreader.c
@@ -0,0 +1,513 @@
+/*
+ * emulate the reader
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu-thread.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+#include "vreader.h"
+#include "vevent.h"
+
+struct VReaderStruct {
+    int    reference_count;
+    VCard *card;
+    char *name;
+    vreader_id_t id;
+    QemuMutex lock;
+    VReaderEmul  *reader_private;
+    VReaderEmulFree reader_private_free;
+};
+
+/* manage locking */
+static inline void
+vreader_lock(VReader *reader)
+{
+    qemu_mutex_lock(&reader->lock);
+}
+
+static inline void
+vreader_unlock(VReader *reader)
+{
+    qemu_mutex_unlock(&reader->lock);
+}
+
+/*
+ * vreader constructor
+ */
+VReader *
+vreader_new(const char *name, VReaderEmul *private,
+            VReaderEmulFree private_free)
+{
+    VReader *reader;
+
+    reader = (VReader *)qemu_malloc(sizeof(VReader));
+    qemu_mutex_init(&reader->lock);
+    reader->reference_count = 1;
+    reader->name = name ? strdup(name) : NULL;
+    reader->card = NULL;
+    reader->id = (vreader_id_t)-1;
+    reader->reader_private = private;
+    reader->reader_private_free = private_free;
+    return reader;
+}
+
+/* get a reference */
+VReader*
+vreader_reference(VReader *reader)
+{
+    if (reader == NULL) {
+        return NULL;
+    }
+    vreader_lock(reader);
+    reader->reference_count++;
+    vreader_unlock(reader);
+    return reader;
+}
+
+/* free a reference */
+void
+vreader_free(VReader *reader)
+{
+    if (reader == NULL) {
+        return;
+    }
+    vreader_lock(reader);
+    if (reader->reference_count-- > 1) {
+        vreader_unlock(reader);
+        return;
+    }
+    vreader_unlock(reader);
+    if (reader->card) {
+        vcard_free(reader->card);
+    }
+    if (reader->name) {
+        qemu_free(reader->name);
+    }
+    if (reader->reader_private_free) {
+        reader->reader_private_free(reader->reader_private);
+    }
+    qemu_free(reader);
+    return;
+}
+
+static VCard *
+vreader_get_card(VReader *reader)
+{
+    VCard *card;
+
+    vreader_lock(reader);
+    card = vcard_reference(reader->card);
+    vreader_unlock(reader);
+    return card;
+}
+
+VReaderStatus
+vreader_card_is_present(VReader *reader)
+{
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+    vcard_free(card);
+    return VREADER_OK;
+}
+
+vreader_id_t
+vreader_get_id(VReader *reader)
+{
+    if (reader == NULL) {
+        return (vreader_id_t)-1;
+    }
+    return reader->id;
+}
+
+VReaderStatus
+vreader_set_id(VReader *reader, vreader_id_t id)
+{
+    if (reader == NULL) {
+        return VREADER_NO_CARD;
+    }
+    reader->id = id;
+    return VREADER_OK;
+}
+
+const char *
+vreader_get_name(VReader *reader)
+{
+    if (reader == NULL) {
+        return NULL;
+    }
+    return reader->name;
+}
+
+VReaderEmul *
+vreader_get_private(VReader *reader)
+{
+    return reader->reader_private;
+}
+
+static VReaderStatus
+vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
+{
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+    /*
+     * clean up our state
+     */
+    vcard_reset(card, power);
+    if (atr) {
+        vcard_get_atr(card, atr, len);
+    }
+    vcard_free(card); /* free our reference */
+    return VREADER_OK;
+}
+
+VReaderStatus
+vreader_power_on(VReader *reader, unsigned char *atr, int *len)
+{
+    return vreader_reset(reader, VCARD_POWER_ON, atr, len);
+}
+
+VReaderStatus
+vreader_power_off(VReader *reader)
+{
+    return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
+}
+
+
+VReaderStatus
+vreader_xfr_bytes(VReader *reader,
+                  unsigned char *send_buf, int send_buf_len,
+                  unsigned char *receive_buf, int *receive_buf_len)
+{
+    VCardAPDU *apdu;
+    VCardResponse *response = NULL;
+    VCardStatus card_status;
+    unsigned short status;
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+
+    apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
+    if (apdu == NULL) {
+        response = vcard_make_response(status);
+        card_status = VCARD_DONE;
+    } else {
+        card_status = vcard_process_apdu(card, apdu, &response);
+    }
+    assert(card_status == VCARD_DONE);
+    if (card_status == VCARD_DONE) {
+        int size = MIN(*receive_buf_len, response->b_total_len);
+        memcpy(receive_buf, response->b_data, size);
+        *receive_buf_len = size;
+    }
+    vcard_response_delete(response);
+    vcard_apdu_delete(apdu);
+    vcard_free(card); /* free our reference */
+    return VREADER_OK;
+}
+
+struct VReaderListStruct {
+    VReaderListEntry *head;
+    VReaderListEntry *tail;
+};
+
+struct VReaderListEntryStruct {
+    VReaderListEntry *next;
+    VReaderListEntry *prev;
+    VReader *reader;
+};
+
+
+static VReaderListEntry *
+vreader_list_entry_new(VReader *reader)
+{
+    VReaderListEntry *new_reader_list_entry;
+
+    new_reader_list_entry = (VReaderListEntry *)
+                               qemu_malloc(sizeof(VReaderListEntry));
+    new_reader_list_entry->next = NULL;
+    new_reader_list_entry->prev = NULL;
+    new_reader_list_entry->reader = vreader_reference(reader);
+    return new_reader_list_entry;
+}
+
+static void
+vreader_list_entry_delete(VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    vreader_free(entry->reader);
+    qemu_free(entry);
+}
+
+
+static VReaderList *
+vreader_list_new(void)
+{
+    VReaderList *new_reader_list;
+
+    new_reader_list = (VReaderList *)qemu_malloc(sizeof(VReaderList));
+    new_reader_list->head = NULL;
+    new_reader_list->tail = NULL;
+    return new_reader_list;
+}
+
+void
+vreader_list_delete(VReaderList *list)
+{
+    VReaderListEntry *current_entry;
+    VReaderListEntry *next_entry = NULL;
+    for (current_entry = vreader_list_get_first(list); current_entry;
+         current_entry = next_entry) {
+        next_entry = vreader_list_get_next(current_entry);
+        vreader_list_entry_delete(current_entry);
+    }
+    list->head = NULL;
+    list->tail = NULL;
+    qemu_free(list);
+}
+
+
+VReaderListEntry *
+vreader_list_get_first(VReaderList *list)
+{
+    return list ? list->head : NULL;
+}
+
+VReaderListEntry *
+vreader_list_get_next(VReaderListEntry *current)
+{
+    return current ? current->next : NULL;
+}
+
+VReader *
+vreader_list_get_reader(VReaderListEntry *entry)
+{
+    return entry ? vreader_reference(entry->reader) : NULL;
+}
+
+static void
+vreader_queue(VReaderList *list, VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    entry->next = NULL;
+    entry->prev = list->tail;
+    if (list->head) {
+        list->tail->next = entry;
+    } else {
+        list->head = entry;
+    }
+    list->tail = entry;
+}
+
+static void
+vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    if (entry->next == NULL) {
+        list->tail = entry->prev;
+    } else if (entry->prev == NULL) {
+        list->head = entry->next;
+    } else {
+        entry->prev->next = entry->next;
+        entry->next->prev = entry->prev;
+    }
+    if ((list->tail == NULL) || (list->head == NULL)) {
+        list->head = list->tail = NULL;
+    }
+    entry->next = entry->prev = NULL;
+}
+
+static VReaderList *vreader_list;
+static QemuMutex vreader_list_mutex;
+
+static void
+vreader_list_init(void)
+{
+    vreader_list = vreader_list_new();
+    qemu_mutex_init(&vreader_list_mutex);
+}
+
+static void
+vreader_list_lock(void)
+{
+    qemu_mutex_lock(&vreader_list_mutex);
+}
+
+static void
+vreader_list_unlock(void)
+{
+    qemu_mutex_unlock(&vreader_list_mutex);
+}
+
+static VReaderList *
+vreader_copy_list(VReaderList *list)
+{
+    VReaderList *new_list = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    new_list = vreader_list_new();
+    if (new_list == NULL) {
+        return NULL;
+    }
+    for (current_entry = vreader_list_get_first(list); current_entry;
+         current_entry = vreader_list_get_next(current_entry)) {
+        VReader *reader = vreader_list_get_reader(current_entry);
+        VReaderListEntry *new_entry = vreader_list_entry_new(reader);
+
+        vreader_free(reader);
+        vreader_queue(new_list, new_entry);
+    }
+    return new_list;
+}
+
+VReaderList *
+vreader_get_reader_list(void)
+{
+    VReaderList *new_reader_list;
+
+    vreader_list_lock();
+    new_reader_list = vreader_copy_list(vreader_list);
+    vreader_list_unlock();
+    return new_reader_list;
+}
+
+VReader *
+vreader_get_reader_by_id(vreader_id_t id)
+{
+    VReader *reader = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    if (id == (vreader_id_t) -1) {
+        return NULL;
+    }
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+            current_entry = vreader_list_get_next(current_entry)) {
+        VReader *creader = vreader_list_get_reader(current_entry);
+        if (creader->id == id) {
+            reader = creader;
+            break;
+        }
+        vreader_free(creader);
+    }
+    vreader_list_unlock();
+    return reader;
+}
+
+VReader *
+vreader_get_reader_by_name(const char *name)
+{
+    VReader *reader = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+            current_entry = vreader_list_get_next(current_entry)) {
+        VReader *creader = vreader_list_get_reader(current_entry);
+        if (strcmp(creader->name, name) == 0) {
+            reader = creader;
+            break;
+        }
+        vreader_free(creader);
+    }
+    vreader_list_unlock();
+    return reader;
+}
+
+/* called from card_emul to initialize the readers */
+VReaderStatus
+vreader_add_reader(VReader *reader)
+{
+    VReaderListEntry *reader_entry;
+
+    reader_entry = vreader_list_entry_new(reader);
+    if (reader_entry == NULL) {
+        return VREADER_OUT_OF_MEMORY;
+    }
+    vreader_list_lock();
+    vreader_queue(vreader_list, reader_entry);
+    vreader_list_unlock();
+    vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
+    return VREADER_OK;
+}
+
+
+VReaderStatus
+vreader_remove_reader(VReader *reader)
+{
+    VReaderListEntry *current_entry;
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+         current_entry = vreader_list_get_next(current_entry)) {
+        if (current_entry->reader == reader) {
+            break;
+        }
+    }
+    vreader_dequeue(vreader_list, current_entry);
+    vreader_list_unlock();
+    vreader_list_entry_delete(current_entry);
+    vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
+    return VREADER_OK;
+}
+
+/*
+ * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
+ * state. Separated from vreader_insert_card to allow replaying events
+ * for a given state.
+ */
+void
+vreader_queue_card_event(VReader *reader)
+{
+    vevent_queue_vevent(vevent_new(
+        reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
+        reader->card));
+}
+
+/*
+ * insert/remove a new card. for removal, card == NULL
+ */
+VReaderStatus
+vreader_insert_card(VReader *reader, VCard *card)
+{
+    vreader_lock(reader);
+    if (reader->card) {
+        /* decrement reference count */
+        vcard_free(reader->card);
+        reader->card = NULL;
+    }
+    reader->card = vcard_reference(card);
+    vreader_unlock(reader);
+    vreader_queue_card_event(reader);
+    return VREADER_OK;
+}
+
+/*
+ * initialize all the static reader structures
+ */
+void
+vreader_init(void)
+{
+    vreader_list_init();
+}
+
diff --git a/qemu-0.15.x/libcacard/vreader.h b/qemu-0.15.x/libcacard/vreader.h
new file mode 100644
index 0000000..ec20421
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vreader.h
@@ -0,0 +1,55 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef VREADER_H
+#define VREADER_H 1
+
+#include "eventt.h"
+#include "vreadert.h"
+#include "vcardt.h"
+
+/*
+ * calls for reader front end
+ */
+VReaderStatus vreader_power_on(VReader *reader, unsigned char *atr, int *len);
+VReaderStatus vreader_power_off(VReader *reader);
+VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf,
+                                int send_buf_len, unsigned char *receive_buf,
+                                int *receive_buf_len);
+
+/* constructor */
+VReader *vreader_new(const char *readerName, VReaderEmul *emul_private,
+                     VReaderEmulFree private_free);
+/* get a new reference to a reader */
+VReader *vreader_reference(VReader *reader);
+/* "destructor" (readers are reference counted) */
+void vreader_free(VReader *reader);
+
+/* accessors */
+VReaderEmul *vreader_get_private(VReader *);
+VReaderStatus vreader_card_is_present(VReader *reader);
+void vreader_queue_card_event(VReader *reader);
+const char *vreader_get_name(VReader *reader);
+vreader_id_t vreader_get_id(VReader *reader);
+VReaderStatus vreader_set_id(VReader *reader, vreader_id_t id);
+
+/* list operations */
+VReaderList *vreader_get_reader_list(void);
+void vreader_list_delete(VReaderList *list);
+VReader *vreader_list_get_reader(VReaderListEntry *entry);
+VReaderListEntry *vreader_list_get_first(VReaderList *list);
+VReaderListEntry *vreader_list_get_next(VReaderListEntry *list);
+VReader *vreader_get_reader_by_id(vreader_id_t id);
+VReader *vreader_get_reader_by_name(const char *name);
+
+/*
+ * list tools for vcard_emul
+ */
+void vreader_init(void);
+VReaderStatus vreader_add_reader(VReader *reader);
+VReaderStatus vreader_remove_reader(VReader *reader);
+VReaderStatus vreader_insert_card(VReader *reader, VCard *card);
+
+#endif
diff --git a/qemu-0.15.x/libcacard/vreadert.h b/qemu-0.15.x/libcacard/vreadert.h
new file mode 100644
index 0000000..f97e0a7
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vreadert.h
@@ -0,0 +1,24 @@
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef VREADERT_H
+#define VREADERT_H 1
+
+typedef enum {
+    VREADER_OK = 0,
+    VREADER_NO_CARD,
+    VREADER_OUT_OF_MEMORY
+} VReaderStatus;
+
+typedef unsigned int vreader_id_t;
+typedef struct VReaderStruct VReader;
+typedef struct VReaderListStruct VReaderList;
+typedef struct VReaderListEntryStruct VReaderListEntry;
+
+typedef struct VReaderEmulStruct VReaderEmul;
+typedef void (*VReaderEmulFree)(VReaderEmul *);
+
+#endif
+
diff --git a/qemu-0.15.x/libcacard/vscard_common.h b/qemu-0.15.x/libcacard/vscard_common.h
new file mode 100644
index 0000000..609ae98
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vscard_common.h
@@ -0,0 +1,178 @@
+/* Virtual Smart Card protocol definition
+ *
+ * This protocol is between a host using virtual smart card readers,
+ * and a client providing the smart cards, perhaps by emulating them or by
+ * access to real cards.
+ *
+ * Definitions for this protocol:
+ *  Host   - user of the card
+ *  Client - owner of the card
+ *
+ * The current implementation passes the raw APDU's from 7816 and additionally
+ * contains messages to setup and teardown readers, handle insertion and
+ * removal of cards, negotiate the protocol via capabilities and provide
+ * for error responses.
+ *
+ * Copyright (c) 2011 Red Hat.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef VSCARD_COMMON_H
+#define VSCARD_COMMON_H
+
+#include <stdint.h>
+
+#define VERSION_MAJOR_BITS 11
+#define VERSION_MIDDLE_BITS 11
+#define VERSION_MINOR_BITS 10
+
+#define MAKE_VERSION(major, middle, minor) \
+     ((major  << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \
+      | (middle <<  VERSION_MINOR_BITS) \
+      | (minor))
+
+/*
+ * IMPORTANT NOTE on VERSION
+ *
+ * The version below MUST be changed whenever a change in this file is made.
+ *
+ * The last digit, the minor, is for bug fix changes only.
+ *
+ * The middle digit is for backward / forward compatible changes, updates
+ * to the existing messages, addition of fields.
+ *
+ * The major digit is for a breaking change of protocol, presumably
+ * something that cannot be accomodated with the existing protocol.
+ */
+
+#define VSCARD_VERSION MAKE_VERSION(0, 0, 2)
+
+typedef enum VSCMsgType {
+    VSC_Init = 1,
+    VSC_Error,
+    VSC_ReaderAdd,
+    VSC_ReaderRemove,
+    VSC_ATR,
+    VSC_CardRemove,
+    VSC_APDU,
+    VSC_Flush,
+    VSC_FlushComplete
+} VSCMsgType;
+
+typedef enum VSCErrorCode {
+    VSC_SUCCESS = 0,
+    VSC_GENERAL_ERROR = 1,
+    VSC_CANNOT_ADD_MORE_READERS,
+    VSC_CARD_ALREAY_INSERTED,
+} VSCErrorCode;
+
+#define VSCARD_UNDEFINED_READER_ID  0xffffffff
+#define VSCARD_MINIMAL_READER_ID    0
+
+#define VSCARD_MAGIC (*(uint32_t *)"VSCD")
+
+/*
+ * Header
+ * Each message starts with the header.
+ * type - message type
+ * reader_id - used by messages that are reader specific
+ * length - length of payload (not including header, i.e. zero for
+ *  messages containing empty payloads)
+ */
+typedef struct VSCMsgHeader {
+    uint32_t   type;
+    uint32_t   reader_id;
+    uint32_t   length;
+    uint8_t    data[0];
+} VSCMsgHeader;
+
+/*
+ * VSCMsgInit               Client <-> Host
+ * Client sends it on connection, with its own capabilities.
+ * Host replies with VSCMsgInit filling in its capabilities.
+ *
+ * It is not meant to be used for negotiation, i.e. sending more then
+ * once from any side, but could be used for that in the future.
+ */
+typedef struct VSCMsgInit {
+    uint32_t   magic;
+    uint32_t   version;
+    uint32_t   capabilities[1]; /* receiver must check length,
+                                   array may grow in the future*/
+} VSCMsgInit;
+
+/*
+ * VSCMsgError              Client <-> Host
+ * This message is a response to any of:
+ *  Reader Add
+ *  Reader Remove
+ *  Card Remove
+ * If the operation was successful then VSC_SUCCESS
+ * is returned, other wise a specific error code.
+ */
+typedef struct VSCMsgError {
+    uint32_t   code;
+} VSCMsgError;
+
+/*
+ * VSCMsgReaderAdd          Client -> Host
+ * Host replies with allocated reader id in VSCMsgError with code==SUCCESS.
+ *
+ * name - name of the reader on client side, UTF-8 encoded. Only used
+ *  for client presentation (may be translated to the device presented to the
+ *  guest), protocol wise only reader_id is important.
+ */
+typedef struct VSCMsgReaderAdd {
+    uint8_t    name[0];
+} VSCMsgReaderAdd;
+
+/*
+ * VSCMsgReaderRemove       Client -> Host
+ * The client's reader has been removed.
+ */
+typedef struct VSCMsgReaderRemove {
+} VSCMsgReaderRemove;
+
+/*
+ * VSCMsgATR                Client -> Host
+ * Answer to reset. Sent for card insertion or card reset. The reset/insertion
+ * happens on the client side, they do not require any action from the host.
+ */
+typedef struct VSCMsgATR {
+    uint8_t     atr[0];
+} VSCMsgATR;
+
+/*
+ * VSCMsgCardRemove         Client -> Host
+ * The client card has been removed.
+ */
+typedef struct VSCMsgCardRemove {
+} VSCMsgCardRemove;
+
+/*
+ * VSCMsgAPDU               Client <-> Host
+ * Main reason of existence. Transfer a single APDU in either direction.
+ */
+typedef struct VSCMsgAPDU {
+    uint8_t    data[0];
+} VSCMsgAPDU;
+
+/*
+ * VSCMsgFlush               Host -> Client
+ * Request client to send a FlushComplete message when it is done
+ * servicing all outstanding APDUs
+ */
+typedef struct VSCMsgFlush {
+} VSCMsgFlush;
+
+/*
+ * VSCMsgFlush               Client -> Host
+ * Client response to Flush after all APDUs have been processed and
+ * responses sent.
+ */
+typedef struct VSCMsgFlushComplete {
+} VSCMsgFlushComplete;
+
+#endif /* VSCARD_COMMON_H */
diff --git a/qemu-0.15.x/libcacard/vscclient.c b/qemu-0.15.x/libcacard/vscclient.c
new file mode 100644
index 0000000..ce33f5a
--- /dev/null
+++ b/qemu-0.15.x/libcacard/vscclient.c
@@ -0,0 +1,652 @@
+/*
+ * Tester for VSCARD protocol, client side.
+ *
+ * Can be used with ccid-card-passthru.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <netdb.h>
+
+#include "qemu-common.h"
+#include "qemu-thread.h"
+#include "qemu_socket.h"
+
+#include "vscard_common.h"
+
+#include "vreader.h"
+#include "vcard_emul.h"
+#include "vevent.h"
+
+int verbose;
+
+int sock;
+
+static void
+print_byte_array(
+    uint8_t *arrBytes,
+    unsigned int nSize
+) {
+    int i;
+    for (i = 0; i < nSize; i++) {
+        printf("%02X ", arrBytes[i]);
+    }
+    printf("\n");
+}
+
+static void
+print_usage(void) {
+    printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
+            "<host> <port>\n",
+#ifdef USE_PASSTHRU
+    " -p");
+    printf(" -p use passthrough mode\n");
+#else
+   "");
+#endif
+    vcard_emul_usage();
+}
+
+static QemuMutex write_lock;
+
+static int
+send_msg(
+    VSCMsgType type,
+    uint32_t reader_id,
+    const void *msg,
+    unsigned int length
+) {
+    int rv;
+    VSCMsgHeader mhHeader;
+
+    qemu_mutex_lock(&write_lock);
+
+    if (verbose > 10) {
+        printf("sending type=%d id=%d, len =%d (0x%x)\n",
+               type, reader_id, length, length);
+    }
+
+    mhHeader.type = htonl(type);
+    mhHeader.reader_id = 0;
+    mhHeader.length = htonl(length);
+    rv = write(sock, &mhHeader, sizeof(mhHeader));
+    if (rv < 0) {
+        /* Error */
+        fprintf(stderr, "write header error\n");
+        close(sock);
+        qemu_mutex_unlock(&write_lock);
+        return 16;
+    }
+    rv = write(sock, msg, length);
+    if (rv < 0) {
+        /* Error */
+        fprintf(stderr, "write error\n");
+        close(sock);
+        qemu_mutex_unlock(&write_lock);
+        return 16;
+    }
+    qemu_mutex_unlock(&write_lock);
+
+    return 0;
+}
+
+static VReader *pending_reader;
+static QemuMutex pending_reader_lock;
+static QemuCond pending_reader_condition;
+
+#define MAX_ATR_LEN 40
+static void *
+event_thread(void *arg)
+{
+    unsigned char atr[MAX_ATR_LEN];
+    int atr_len = MAX_ATR_LEN;
+    VEvent *event = NULL;
+    unsigned int reader_id;
+
+
+    while (1) {
+        const char *reader_name;
+
+        event = vevent_wait_next_vevent();
+        if (event == NULL) {
+            break;
+        }
+        reader_id = vreader_get_id(event->reader);
+        if (reader_id == VSCARD_UNDEFINED_READER_ID &&
+            event->type != VEVENT_READER_INSERT) {
+            /* ignore events from readers qemu has rejected */
+            /* if qemu is still deciding on this reader, wait to see if need to
+             * forward this event */
+            qemu_mutex_lock(&pending_reader_lock);
+            if (!pending_reader || (pending_reader != event->reader)) {
+                /* wasn't for a pending reader, this reader has already been
+                 * rejected by qemu */
+                qemu_mutex_unlock(&pending_reader_lock);
+                vevent_delete(event);
+                continue;
+            }
+            /* this reader hasn't been told it's status from qemu yet, wait for
+             * that status */
+            while (pending_reader != NULL) {
+                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
+            }
+            qemu_mutex_unlock(&pending_reader_lock);
+            /* now recheck the id */
+            reader_id = vreader_get_id(event->reader);
+            if (reader_id == VSCARD_UNDEFINED_READER_ID) {
+                /* this reader was rejected */
+                vevent_delete(event);
+                continue;
+            }
+            /* reader was accepted, now forward the event */
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+            /* tell qemu to insert a new CCID reader */
+            /* wait until qemu has responded to our first reader insert
+             * before we send a second. That way we won't confuse the responses
+             * */
+            qemu_mutex_lock(&pending_reader_lock);
+            while (pending_reader != NULL) {
+                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
+            }
+            pending_reader = vreader_reference(event->reader);
+            qemu_mutex_unlock(&pending_reader_lock);
+            reader_name = vreader_get_name(event->reader);
+            if (verbose > 10) {
+                printf(" READER INSERT: %s\n", reader_name);
+            }
+            send_msg(VSC_ReaderAdd,
+                reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */
+                NULL, 0 /* TODO reader_name, strlen(reader_name) */);
+            break;
+        case VEVENT_READER_REMOVE:
+            /* future, tell qemu that an old CCID reader has been removed */
+            if (verbose > 10) {
+                printf(" READER REMOVE: %d\n", reader_id);
+            }
+            send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
+            break;
+        case VEVENT_CARD_INSERT:
+            /* get the ATR (intended as a response to a power on from the
+             * reader */
+            atr_len = MAX_ATR_LEN;
+            vreader_power_on(event->reader, atr, &atr_len);
+            /* ATR call functions as a Card Insert event */
+            if (verbose > 10) {
+                printf(" CARD INSERT %d: ", reader_id);
+                print_byte_array(atr, atr_len);
+            }
+            send_msg(VSC_ATR, reader_id, atr, atr_len);
+            break;
+        case VEVENT_CARD_REMOVE:
+            /* Card removed */
+            if (verbose > 10) {
+                printf(" CARD REMOVE %d:\n", reader_id);
+            }
+            send_msg(VSC_CardRemove, reader_id, NULL, 0);
+            break;
+        default:
+            break;
+        }
+        vevent_delete(event);
+    }
+    return NULL;
+}
+
+
+static unsigned int
+get_id_from_string(char *string, unsigned int default_id)
+{
+    unsigned int id = atoi(string);
+
+    /* don't accidentally swith to zero because no numbers have been supplied */
+    if ((id == 0) && *string != '0') {
+        return default_id;
+    }
+    return id;
+}
+
+static void
+do_command(void)
+{
+    char inbuf[255];
+    char *string;
+    VCardEmulError error;
+    static unsigned int default_reader_id;
+    unsigned int reader_id;
+    VReader *reader = NULL;
+
+    reader_id = default_reader_id;
+    string = fgets(inbuf, sizeof(inbuf), stdin);
+    if (string != NULL) {
+        if (strncmp(string, "exit", 4) == 0) {
+            /* remove all the readers */
+            VReaderList *list = vreader_get_reader_list();
+            VReaderListEntry *reader_entry;
+            printf("Active Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id == -1) {
+                    continue;
+                }
+                /* be nice and signal card removal first (qemu probably should
+                 * do this itself) */
+                if (vreader_card_is_present(reader) == VREADER_OK) {
+                    send_msg(VSC_CardRemove, reader_id, NULL, 0);
+                }
+                send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
+            }
+            exit(0);
+        } else if (strncmp(string, "insert", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7], reader_id);
+            }
+            reader = vreader_get_reader_by_id(reader_id);
+            if (reader != NULL) {
+                error = vcard_emul_force_card_insert(reader);
+                printf("insert %s, returned %d\n",
+                       reader ? vreader_get_name(reader)
+                       : "invalid reader", error);
+            } else {
+                printf("no reader by id %d found\n", reader_id);
+            }
+        } else if (strncmp(string, "remove", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7], reader_id);
+            }
+            reader = vreader_get_reader_by_id(reader_id);
+            if (reader != NULL) {
+                error = vcard_emul_force_card_remove(reader);
+                printf("remove %s, returned %d\n",
+                        reader ? vreader_get_name(reader)
+                        : "invalid reader", error);
+            } else {
+                printf("no reader by id %d found\n", reader_id);
+            }
+        } else if (strncmp(string, "select", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7],
+                                               VSCARD_UNDEFINED_READER_ID);
+            }
+            if (reader_id != VSCARD_UNDEFINED_READER_ID) {
+                reader = vreader_get_reader_by_id(reader_id);
+            }
+            if (reader) {
+                printf("Selecting reader %d, %s\n", reader_id,
+                        vreader_get_name(reader));
+                default_reader_id = reader_id;
+            } else {
+                printf("Reader with id %d not found\n", reader_id);
+            }
+        } else if (strncmp(string, "debug", 5) == 0) {
+            if (string[5] == ' ') {
+                verbose = get_id_from_string(&string[6], 0);
+            }
+            printf("debug level = %d\n", verbose);
+        } else if (strncmp(string, "list", 4) == 0) {
+            VReaderList *list = vreader_get_reader_list();
+            VReaderListEntry *reader_entry;
+            printf("Active Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id == -1) {
+                    continue;
+                }
+                printf("%3d %s %s\n", reader_id,
+                       vreader_card_is_present(reader) == VREADER_OK ?
+                       "CARD_PRESENT" : "            ",
+                       vreader_get_name(reader));
+            }
+            printf("Inactive Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id != -1) {
+                    continue;
+                }
+
+                printf("INA %s %s\n",
+                       vreader_card_is_present(reader) == VREADER_OK ?
+                       "CARD_PRESENT" : "            ",
+                       vreader_get_name(reader));
+            }
+        } else if (*string != 0) {
+            printf("valid commands:\n");
+            printf("insert [reader_id]\n");
+            printf("remove [reader_id]\n");
+            printf("select reader_id\n");
+            printf("list\n");
+            printf("debug [level]\n");
+            printf("exit\n");
+        }
+    }
+    vreader_free(reader);
+    printf("> ");
+    fflush(stdout);
+}
+
+
+#define APDUBufSize 270
+
+/* just for ease of parsing command line arguments. */
+#define MAX_CERTS 100
+
+static int
+connect_to_qemu(
+    const char *host,
+    const char *port
+) {
+    struct addrinfo hints;
+    struct addrinfo *server;
+    int ret;
+
+    sock = qemu_socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        /* Error */
+        fprintf(stderr, "Error opening socket!\n");
+    }
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = 0;
+    hints.ai_protocol = 0;          /* Any protocol */
+
+    ret = getaddrinfo(host, port, &hints, &server);
+
+    if (ret != 0) {
+        /* Error */
+        fprintf(stderr, "getaddrinfo failed\n");
+        return 5;
+    }
+
+    if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
+        /* Error */
+        fprintf(stderr, "Could not connect\n");
+        return 5;
+    }
+    if (verbose) {
+        printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
+    }
+    return sock;
+}
+
+static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
+{
+    uint32_t *capabilities = (incoming->capabilities);
+    int num_capabilities =
+        1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
+    int i;
+    int rv;
+    pthread_t thread_id;
+
+    incoming->version = ntohl(incoming->version);
+    if (incoming->version != VSCARD_VERSION) {
+        if (verbose > 0) {
+            printf("warning: host has version %d, we have %d\n",
+                verbose, VSCARD_VERSION);
+        }
+    }
+    if (incoming->magic != VSCARD_MAGIC) {
+        printf("unexpected magic: got %d, expected %d\n",
+            incoming->magic, VSCARD_MAGIC);
+        return -1;
+    }
+    for (i = 0 ; i < num_capabilities; ++i) {
+        capabilities[i] = ntohl(capabilities[i]);
+    }
+    /* Future: check capabilities */
+    /* remove whatever reader might be left in qemu,
+     * in case of an unclean previous exit. */
+    send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
+    /* launch the event_thread. This will trigger reader adds for all the
+     * existing readers */
+    rv = pthread_create(&thread_id, NULL, event_thread, NULL);
+    if (rv < 0) {
+        perror("pthread_create");
+        return rv;
+    }
+    return 0;
+}
+
+int
+main(
+    int argc,
+    char *argv[]
+) {
+    char *qemu_host;
+    char *qemu_port;
+    VSCMsgHeader mhHeader;
+    VSCMsgError *error_msg;
+
+    int rv;
+    int dwSendLength;
+    int dwRecvLength;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t pbSendBuffer[APDUBufSize];
+     VReaderStatus reader_status;
+    VReader *reader = NULL;
+    VCardEmulOptions *command_line_options = NULL;
+
+    char *cert_names[MAX_CERTS];
+    char *emul_args = NULL;
+    int cert_count = 0;
+    int c;
+
+    while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
+        switch (c) {
+        case 'c':
+            if (cert_count >= MAX_CERTS) {
+                printf("too many certificates (max = %d)\n", MAX_CERTS);
+                exit(5);
+            }
+            cert_names[cert_count++] = optarg;
+            break;
+        case 'e':
+            emul_args = optarg;
+            break;
+        case 'p':
+            print_usage();
+            exit(4);
+            break;
+        case 'd':
+            verbose = get_id_from_string(optarg, 1);
+            break;
+        }
+    }
+
+    if (argc - optind != 2) {
+        print_usage();
+        exit(4);
+    }
+
+    if (cert_count > 0) {
+        char *new_args;
+        int len, i;
+        /* if we've given some -c options, we clearly we want do so some
+         * software emulation.  add that emulation now. this is NSS Emulator
+         * specific */
+        if (emul_args == NULL) {
+            emul_args = (char *)"db=\"/etc/pki/nssdb\"";
+        }
+#define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
+             /* 2 == close paren & null */
+        len = strlen(emul_args) + strlen(SOFT_STRING) + 2;
+        for (i = 0; i < cert_count; i++) {
+            len += strlen(cert_names[i])+1; /* 1 == comma */
+        }
+        new_args = qemu_malloc(len);
+        strcpy(new_args, emul_args);
+        strcat(new_args, SOFT_STRING);
+        for (i = 0; i < cert_count; i++) {
+            strcat(new_args, cert_names[i]);
+            strcat(new_args, ",");
+        }
+        strcat(new_args, ")");
+        emul_args = new_args;
+    }
+    if (emul_args) {
+        command_line_options = vcard_emul_options(emul_args);
+    }
+
+    qemu_host = strdup(argv[argc - 2]);
+    qemu_port = strdup(argv[argc - 1]);
+    sock = connect_to_qemu(qemu_host, qemu_port);
+
+    qemu_mutex_init(&write_lock);
+    qemu_mutex_init(&pending_reader_lock);
+    qemu_cond_init(&pending_reader_condition);
+
+    vcard_emul_init(command_line_options);
+
+    printf("> ");
+    fflush(stdout);
+
+    /* Send init message, Host responds (and then we send reader attachments) */
+    VSCMsgInit init = {
+        .version = htonl(VSCARD_VERSION),
+        .magic = VSCARD_MAGIC,
+        .capabilities = {0}
+    };
+    send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init));
+
+    do {
+        fd_set fds;
+
+        FD_ZERO(&fds);
+        FD_SET(1, &fds);
+        FD_SET(sock, &fds);
+
+        /* waiting on input from the socket */
+        rv = select(sock+1, &fds, NULL, NULL, NULL);
+        if (rv < 0) {
+            /* handle error */
+            perror("select");
+            return 7;
+        }
+        if (FD_ISSET(1, &fds)) {
+            do_command();
+        }
+        if (!FD_ISSET(sock, &fds)) {
+            continue;
+        }
+
+        rv = read(sock, &mhHeader, sizeof(mhHeader));
+        if (rv < sizeof(mhHeader)) {
+            /* Error */
+            if (rv < 0) {
+                perror("header read error\n");
+            } else {
+                fprintf(stderr, "header short read %d\n", rv);
+            }
+            return 8;
+        }
+        mhHeader.type = ntohl(mhHeader.type);
+        mhHeader.reader_id = ntohl(mhHeader.reader_id);
+        mhHeader.length = ntohl(mhHeader.length);
+        if (verbose) {
+            printf("Header: type=%d, reader_id=%d length=%d (0x%x)\n",
+                    mhHeader.type, mhHeader.reader_id, mhHeader.length,
+                                               mhHeader.length);
+        }
+        switch (mhHeader.type) {
+        case VSC_APDU:
+        case VSC_Flush:
+        case VSC_Error:
+        case VSC_Init:
+            rv = read(sock, pbSendBuffer, mhHeader.length);
+            break;
+        default:
+            fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
+            return 0;
+        }
+        switch (mhHeader.type) {
+        case VSC_APDU:
+            if (rv < 0) {
+                /* Error */
+                fprintf(stderr, "read error\n");
+                close(sock);
+                return 8;
+            }
+            if (verbose) {
+                printf(" recv APDU: ");
+                print_byte_array(pbSendBuffer, mhHeader.length);
+            }
+            /* Transmit recieved APDU */
+            dwSendLength = mhHeader.length;
+            dwRecvLength = sizeof(pbRecvBuffer);
+            reader = vreader_get_reader_by_id(mhHeader.reader_id);
+            reader_status = vreader_xfr_bytes(reader,
+                pbSendBuffer, dwSendLength,
+                pbRecvBuffer, &dwRecvLength);
+            if (reader_status == VREADER_OK) {
+                mhHeader.length = dwRecvLength;
+                if (verbose) {
+                    printf(" send response: ");
+                    print_byte_array(pbRecvBuffer, mhHeader.length);
+                }
+                send_msg(VSC_APDU, mhHeader.reader_id,
+                         pbRecvBuffer, dwRecvLength);
+            } else {
+                rv = reader_status; /* warning: not meaningful */
+                send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
+            }
+            vreader_free(reader);
+            reader = NULL; /* we've freed it, don't use it by accident
+                              again */
+            break;
+        case VSC_Flush:
+            /* TODO: actually flush */
+            send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
+            break;
+        case VSC_Error:
+            error_msg = (VSCMsgError *) pbSendBuffer;
+            if (error_msg->code == VSC_SUCCESS) {
+                qemu_mutex_lock(&pending_reader_lock);
+                if (pending_reader) {
+                    vreader_set_id(pending_reader, mhHeader.reader_id);
+                    vreader_free(pending_reader);
+                    pending_reader = NULL;
+                    qemu_cond_signal(&pending_reader_condition);
+                }
+                qemu_mutex_unlock(&pending_reader_lock);
+                break;
+            }
+            printf("warning: qemu refused to add reader\n");
+            if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
+                /* clear pending reader, qemu can't handle any more */
+                qemu_mutex_lock(&pending_reader_lock);
+                if (pending_reader) {
+                    pending_reader = NULL;
+                    /* make sure the event loop doesn't hang */
+                    qemu_cond_signal(&pending_reader_condition);
+                }
+                qemu_mutex_unlock(&pending_reader_lock);
+            }
+            break;
+        case VSC_Init:
+            if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
+                return -1;
+            }
+            break;
+        default:
+            printf("Default\n");
+            return 0;
+        }
+    } while (rv >= 0);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/libfdt_env.h b/qemu-0.15.x/libfdt_env.h
new file mode 100644
index 0000000..90d7f3b
--- /dev/null
+++ b/qemu-0.15.x/libfdt_env.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright IBM Corp. 2008
+ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ */
+
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include "bswap.h"
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define fdt32_to_cpu(x)		(x)
+#define cpu_to_fdt32(x)		(x)
+#define fdt64_to_cpu(x)		(x)
+#define cpu_to_fdt64(x)		(x)
+#else
+#define fdt32_to_cpu(x)		(bswap_32((x)))
+#define cpu_to_fdt32(x)		(bswap_32((x)))
+#define fdt64_to_cpu(x)		(bswap_64((x)))
+#define cpu_to_fdt64(x)		(bswap_64((x)))
+#endif
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/qemu-0.15.x/linux-aio.c b/qemu-0.15.x/linux-aio.c
new file mode 100644
index 0000000..68f4b3d
--- /dev/null
+++ b/qemu-0.15.x/linux-aio.c
@@ -0,0 +1,261 @@
+/*
+ * Linux native AIO support.
+ *
+ * Copyright (C) 2009 IBM, Corp.
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu-common.h"
+#include "qemu-aio.h"
+#include "block_int.h"
+#include "block/raw-posix-aio.h"
+
+#include <sys/eventfd.h>
+#include <libaio.h>
+
+/*
+ * Queue size (per-device).
+ *
+ * XXX: eventually we need to communicate this to the guest and/or make it
+ *      tunable by the guest.  If we get more outstanding requests at a time
+ *      than this we will get EAGAIN from io_submit which is communicated to
+ *      the guest as an I/O error.
+ */
+#define MAX_EVENTS 128
+
+struct qemu_laiocb {
+    BlockDriverAIOCB common;
+    struct qemu_laio_state *ctx;
+    struct iocb iocb;
+    ssize_t ret;
+    size_t nbytes;
+    int async_context_id;
+    QLIST_ENTRY(qemu_laiocb) node;
+};
+
+struct qemu_laio_state {
+    io_context_t ctx;
+    int efd;
+    int count;
+    QLIST_HEAD(, qemu_laiocb) completed_reqs;
+};
+
+static inline ssize_t io_event_ret(struct io_event *ev)
+{
+    return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
+}
+
+/*
+ * Completes an AIO request (calls the callback and frees the ACB).
+ * Be sure to be in the right AsyncContext before calling this function.
+ */
+static void qemu_laio_process_completion(struct qemu_laio_state *s,
+    struct qemu_laiocb *laiocb)
+{
+    int ret;
+
+    s->count--;
+
+    ret = laiocb->ret;
+    if (ret != -ECANCELED) {
+        if (ret == laiocb->nbytes)
+            ret = 0;
+        else if (ret >= 0)
+            ret = -EINVAL;
+
+        laiocb->common.cb(laiocb->common.opaque, ret);
+    }
+
+    qemu_aio_release(laiocb);
+}
+
+/*
+ * Processes all queued AIO requests, i.e. requests that have return from OS
+ * but their callback was not called yet. Requests that cannot have their
+ * callback called in the current AsyncContext, remain in the queue.
+ *
+ * Returns 1 if at least one request could be completed, 0 otherwise.
+ */
+static int qemu_laio_process_requests(void *opaque)
+{
+    struct qemu_laio_state *s = opaque;
+    struct qemu_laiocb *laiocb, *next;
+    int res = 0;
+
+    QLIST_FOREACH_SAFE (laiocb, &s->completed_reqs, node, next) {
+        if (laiocb->async_context_id == get_async_context_id()) {
+            qemu_laio_process_completion(s, laiocb);
+            QLIST_REMOVE(laiocb, node);
+            res = 1;
+        }
+    }
+
+    return res;
+}
+
+/*
+ * Puts a request in the completion queue so that its callback is called the
+ * next time when it's possible. If we already are in the right AsyncContext,
+ * the request is completed immediately instead.
+ */
+static void qemu_laio_enqueue_completed(struct qemu_laio_state *s,
+    struct qemu_laiocb* laiocb)
+{
+    if (laiocb->async_context_id == get_async_context_id()) {
+        qemu_laio_process_completion(s, laiocb);
+    } else {
+        QLIST_INSERT_HEAD(&s->completed_reqs, laiocb, node);
+    }
+}
+
+static void qemu_laio_completion_cb(void *opaque)
+{
+    struct qemu_laio_state *s = opaque;
+
+    while (1) {
+        struct io_event events[MAX_EVENTS];
+        uint64_t val;
+        ssize_t ret;
+        struct timespec ts = { 0 };
+        int nevents, i;
+
+        do {
+            ret = read(s->efd, &val, sizeof(val));
+        } while (ret == -1 && errno == EINTR);
+
+        if (ret == -1 && errno == EAGAIN)
+            break;
+
+        if (ret != 8)
+            break;
+
+        do {
+            nevents = io_getevents(s->ctx, val, MAX_EVENTS, events, &ts);
+        } while (nevents == -EINTR);
+
+        for (i = 0; i < nevents; i++) {
+            struct iocb *iocb = events[i].obj;
+            struct qemu_laiocb *laiocb =
+                    container_of(iocb, struct qemu_laiocb, iocb);
+
+            laiocb->ret = io_event_ret(&events[i]);
+            qemu_laio_enqueue_completed(s, laiocb);
+        }
+    }
+}
+
+static int qemu_laio_flush_cb(void *opaque)
+{
+    struct qemu_laio_state *s = opaque;
+
+    return (s->count > 0) ? 1 : 0;
+}
+
+static void laio_cancel(BlockDriverAIOCB *blockacb)
+{
+    struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
+    struct io_event event;
+    int ret;
+
+    if (laiocb->ret != -EINPROGRESS)
+        return;
+
+    /*
+     * Note that as of Linux 2.6.31 neither the block device code nor any
+     * filesystem implements cancellation of AIO request.
+     * Thus the polling loop below is the normal code path.
+     */
+    ret = io_cancel(laiocb->ctx->ctx, &laiocb->iocb, &event);
+    if (ret == 0) {
+        laiocb->ret = -ECANCELED;
+        return;
+    }
+
+    /*
+     * We have to wait for the iocb to finish.
+     *
+     * The only way to get the iocb status update is by polling the io context.
+     * We might be able to do this slightly more optimal by removing the
+     * O_NONBLOCK flag.
+     */
+    while (laiocb->ret == -EINPROGRESS)
+        qemu_laio_completion_cb(laiocb->ctx);
+}
+
+static AIOPool laio_pool = {
+    .aiocb_size         = sizeof(struct qemu_laiocb),
+    .cancel             = laio_cancel,
+};
+
+BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+    struct qemu_laio_state *s = aio_ctx;
+    struct qemu_laiocb *laiocb;
+    struct iocb *iocbs;
+    off_t offset = sector_num * 512;
+
+    laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque);
+    if (!laiocb)
+        return NULL;
+    laiocb->nbytes = nb_sectors * 512;
+    laiocb->ctx = s;
+    laiocb->ret = -EINPROGRESS;
+    laiocb->async_context_id = get_async_context_id();
+
+    iocbs = &laiocb->iocb;
+
+    switch (type) {
+    case QEMU_AIO_WRITE:
+        io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset);
+	break;
+    case QEMU_AIO_READ:
+        io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
+	break;
+    default:
+        fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
+                        __func__, type);
+        goto out_free_aiocb;
+    }
+    io_set_eventfd(&laiocb->iocb, s->efd);
+    s->count++;
+
+    if (io_submit(s->ctx, 1, &iocbs) < 0)
+        goto out_dec_count;
+    return &laiocb->common;
+
+out_free_aiocb:
+    qemu_aio_release(laiocb);
+out_dec_count:
+    s->count--;
+    return NULL;
+}
+
+void *laio_init(void)
+{
+    struct qemu_laio_state *s;
+
+    s = qemu_mallocz(sizeof(*s));
+    QLIST_INIT(&s->completed_reqs);
+    s->efd = eventfd(0, 0);
+    if (s->efd == -1)
+        goto out_free_state;
+    fcntl(s->efd, F_SETFL, O_NONBLOCK);
+
+    if (io_setup(MAX_EVENTS, &s->ctx) != 0)
+        goto out_close_efd;
+
+    qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
+        qemu_laio_flush_cb, qemu_laio_process_requests, s);
+
+    return s;
+
+out_close_efd:
+    close(s->efd);
+out_free_state:
+    qemu_free(s);
+    return NULL;
+}
diff --git a/qemu-0.15.x/linux-headers/COPYING b/qemu-0.15.x/linux-headers/COPYING
new file mode 100644
index 0000000..ca442d3
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/COPYING
@@ -0,0 +1,356 @@
+
+   NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+			Linus Torvalds
+
+----------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/qemu-0.15.x/linux-headers/README b/qemu-0.15.x/linux-headers/README
new file mode 100644
index 0000000..5c9026b
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/README
@@ -0,0 +1,2 @@
+Automatically imported Linux kernel headers.
+Only use scripts/update-linux-headers.sh to update!
diff --git a/qemu-0.15.x/linux-headers/asm-powerpc/kvm.h b/qemu-0.15.x/linux-headers/asm-powerpc/kvm.h
new file mode 100644
index 0000000..777d307
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-powerpc/kvm.h
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
+ */
+
+#ifndef __LINUX_KVM_POWERPC_H
+#define __LINUX_KVM_POWERPC_H
+
+#include <linux/types.h>
+
+struct kvm_regs {
+	__u64 pc;
+	__u64 cr;
+	__u64 ctr;
+	__u64 lr;
+	__u64 xer;
+	__u64 msr;
+	__u64 srr0;
+	__u64 srr1;
+	__u64 pid;
+
+	__u64 sprg0;
+	__u64 sprg1;
+	__u64 sprg2;
+	__u64 sprg3;
+	__u64 sprg4;
+	__u64 sprg5;
+	__u64 sprg6;
+	__u64 sprg7;
+
+	__u64 gpr[32];
+};
+
+#define KVM_SREGS_E_IMPL_NONE	0
+#define KVM_SREGS_E_IMPL_FSL	1
+
+#define KVM_SREGS_E_FSL_PIDn	(1 << 0) /* PID1/PID2 */
+
+/*
+ * Feature bits indicate which sections of the sregs struct are valid,
+ * both in KVM_GET_SREGS and KVM_SET_SREGS.  On KVM_SET_SREGS, registers
+ * corresponding to unset feature bits will not be modified.  This allows
+ * restoring a checkpoint made without that feature, while keeping the
+ * default values of the new registers.
+ *
+ * KVM_SREGS_E_BASE contains:
+ * CSRR0/1 (refers to SRR2/3 on 40x)
+ * ESR
+ * DEAR
+ * MCSR
+ * TSR
+ * TCR
+ * DEC
+ * TB
+ * VRSAVE (USPRG0)
+ */
+#define KVM_SREGS_E_BASE		(1 << 0)
+
+/*
+ * KVM_SREGS_E_ARCH206 contains:
+ *
+ * PIR
+ * MCSRR0/1
+ * DECAR
+ * IVPR
+ */
+#define KVM_SREGS_E_ARCH206		(1 << 1)
+
+/*
+ * Contains EPCR, plus the upper half of 64-bit registers
+ * that are 32-bit on 32-bit implementations.
+ */
+#define KVM_SREGS_E_64			(1 << 2)
+
+#define KVM_SREGS_E_SPRG8		(1 << 3)
+#define KVM_SREGS_E_MCIVPR		(1 << 4)
+
+/*
+ * IVORs are used -- contains IVOR0-15, plus additional IVORs
+ * in combination with an appropriate feature bit.
+ */
+#define KVM_SREGS_E_IVOR		(1 << 5)
+
+/*
+ * Contains MAS0-4, MAS6-7, TLBnCFG, MMUCFG.
+ * Also TLBnPS if MMUCFG[MAVN] = 1.
+ */
+#define KVM_SREGS_E_ARCH206_MMU		(1 << 6)
+
+/* DBSR, DBCR, IAC, DAC, DVC */
+#define KVM_SREGS_E_DEBUG		(1 << 7)
+
+/* Enhanced debug -- DSRR0/1, SPRG9 */
+#define KVM_SREGS_E_ED			(1 << 8)
+
+/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_SPE			(1 << 9)
+
+/* External Proxy (EXP) -- EPR */
+#define KVM_SREGS_EXP			(1 << 10)
+
+/* External PID (E.PD) -- EPSC/EPLC */
+#define KVM_SREGS_E_PD			(1 << 11)
+
+/* Processor Control (E.PC) -- IVOR36-37 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PC			(1 << 12)
+
+/* Page table (E.PT) -- EPTCFG */
+#define KVM_SREGS_E_PT			(1 << 13)
+
+/* Embedded Performance Monitor (E.PM) -- IVOR35 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PM			(1 << 14)
+
+/*
+ * Special updates:
+ *
+ * Some registers may change even while a vcpu is not running.
+ * To avoid losing these changes, by default these registers are
+ * not updated by KVM_SET_SREGS.  To force an update, set the bit
+ * in u.e.update_special corresponding to the register to be updated.
+ *
+ * The update_special field is zero on return from KVM_GET_SREGS.
+ *
+ * When restoring a checkpoint, the caller can set update_special
+ * to 0xffffffff to ensure that everything is restored, even new features
+ * that the caller doesn't know about.
+ */
+#define KVM_SREGS_E_UPDATE_MCSR		(1 << 0)
+#define KVM_SREGS_E_UPDATE_TSR		(1 << 1)
+#define KVM_SREGS_E_UPDATE_DEC		(1 << 2)
+#define KVM_SREGS_E_UPDATE_DBSR		(1 << 3)
+
+/*
+ * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
+ * previous KVM_GET_REGS.
+ *
+ * Unless otherwise indicated, setting any register with KVM_SET_SREGS
+ * directly sets its value.  It does not trigger any special semantics such
+ * as write-one-to-clear.  Calling KVM_SET_SREGS on an unmodified struct
+ * just received from KVM_GET_SREGS is always a no-op.
+ */
+struct kvm_sregs {
+	__u32 pvr;
+	union {
+		struct {
+			__u64 sdr1;
+			struct {
+				struct {
+					__u64 slbe;
+					__u64 slbv;
+				} slb[64];
+			} ppc64;
+			struct {
+				__u32 sr[16];
+				__u64 ibat[8];
+				__u64 dbat[8];
+			} ppc32;
+		} s;
+		struct {
+			union {
+				struct { /* KVM_SREGS_E_IMPL_FSL */
+					__u32 features; /* KVM_SREGS_E_FSL_ */
+					__u32 svr;
+					__u64 mcar;
+					__u32 hid0;
+
+					/* KVM_SREGS_E_FSL_PIDn */
+					__u32 pid1, pid2;
+				} fsl;
+				__u8 pad[256];
+			} impl;
+
+			__u32 features; /* KVM_SREGS_E_ */
+			__u32 impl_id;	/* KVM_SREGS_E_IMPL_ */
+			__u32 update_special; /* KVM_SREGS_E_UPDATE_ */
+			__u32 pir;	/* read-only */
+			__u64 sprg8;
+			__u64 sprg9;	/* E.ED */
+			__u64 csrr0;
+			__u64 dsrr0;	/* E.ED */
+			__u64 mcsrr0;
+			__u32 csrr1;
+			__u32 dsrr1;	/* E.ED */
+			__u32 mcsrr1;
+			__u32 esr;
+			__u64 dear;
+			__u64 ivpr;
+			__u64 mcivpr;
+			__u64 mcsr;	/* KVM_SREGS_E_UPDATE_MCSR */
+
+			__u32 tsr;	/* KVM_SREGS_E_UPDATE_TSR */
+			__u32 tcr;
+			__u32 decar;
+			__u32 dec;	/* KVM_SREGS_E_UPDATE_DEC */
+
+			/*
+			 * Userspace can read TB directly, but the
+			 * value reported here is consistent with "dec".
+			 *
+			 * Read-only.
+			 */
+			__u64 tb;
+
+			__u32 dbsr;	/* KVM_SREGS_E_UPDATE_DBSR */
+			__u32 dbcr[3];
+			__u32 iac[4];
+			__u32 dac[2];
+			__u32 dvc[2];
+			__u8 num_iac;	/* read-only */
+			__u8 num_dac;	/* read-only */
+			__u8 num_dvc;	/* read-only */
+			__u8 pad;
+
+			__u32 epr;	/* EXP */
+			__u32 vrsave;	/* a.k.a. USPRG0 */
+			__u32 epcr;	/* KVM_SREGS_E_64 */
+
+			__u32 mas0;
+			__u32 mas1;
+			__u64 mas2;
+			__u64 mas7_3;
+			__u32 mas4;
+			__u32 mas6;
+
+			__u32 ivor_low[16]; /* IVOR0-15 */
+			__u32 ivor_high[18]; /* IVOR32+, plus room to expand */
+
+			__u32 mmucfg;	/* read-only */
+			__u32 eptcfg;	/* E.PT, read-only */
+			__u32 tlbcfg[4];/* read-only */
+			__u32 tlbps[4]; /* read-only */
+
+			__u32 eplc, epsc; /* E.PD */
+		} e;
+		__u8 pad[1020];
+	} u;
+};
+
+struct kvm_fpu {
+	__u64 fpr[32];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#define KVM_REG_MASK		0x001f
+#define KVM_REG_EXT_MASK	0xffe0
+#define KVM_REG_GPR		0x0000
+#define KVM_REG_FPR		0x0020
+#define KVM_REG_QPR		0x0040
+#define KVM_REG_FQPR		0x0060
+
+#define KVM_INTERRUPT_SET	-1U
+#define KVM_INTERRUPT_UNSET	-2U
+#define KVM_INTERRUPT_SET_LEVEL	-3U
+
+#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/qemu-0.15.x/linux-headers/asm-powerpc/kvm_para.h b/qemu-0.15.x/linux-headers/asm-powerpc/kvm_para.h
new file mode 100644
index 0000000..ad58c90
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-powerpc/kvm_para.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
+
+#include <linux/types.h>
+
+struct kvm_vcpu_arch_shared {
+	__u64 scratch1;
+	__u64 scratch2;
+	__u64 scratch3;
+	__u64 critical;		/* Guest may not get interrupts if == r1 */
+	__u64 sprg0;
+	__u64 sprg1;
+	__u64 sprg2;
+	__u64 sprg3;
+	__u64 srr0;
+	__u64 srr1;
+	__u64 dar;
+	__u64 msr;
+	__u32 dsisr;
+	__u32 int_pending;	/* Tells the guest if we have an interrupt */
+	__u32 sr[16];
+};
+
+#define KVM_SC_MAGIC_R0		0x4b564d21 /* "KVM!" */
+#define HC_VENDOR_KVM		(42 << 16)
+#define HC_EV_SUCCESS		0
+#define HC_EV_UNIMPLEMENTED	12
+
+#define KVM_FEATURE_MAGIC_PAGE	1
+
+#define KVM_MAGIC_FEAT_SR	(1 << 0)
+
+
+#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/qemu-0.15.x/linux-headers/asm-s390/kvm.h b/qemu-0.15.x/linux-headers/asm-s390/kvm.h
new file mode 100644
index 0000000..82b32a1
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-s390/kvm.h
@@ -0,0 +1,44 @@
+#ifndef __LINUX_KVM_S390_H
+#define __LINUX_KVM_S390_H
+/*
+ * asm-s390/kvm.h - KVM s390 specific structures and definitions
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Carsten Otte <cotte at de.ibm.com>
+ *               Christian Borntraeger <borntraeger at de.ibm.com>
+ */
+#include <linux/types.h>
+
+#define __KVM_S390
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+	/* general purpose regs for s390 */
+	__u64 gprs[16];
+};
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+	__u32 acrs[16];
+	__u64 crs[16];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+	__u32 fpc;
+	__u64 fprs[16];
+};
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+#endif
diff --git a/qemu-0.15.x/linux-headers/asm-s390/kvm_para.h b/qemu-0.15.x/linux-headers/asm-s390/kvm_para.h
new file mode 100644
index 0000000..8e2dd67
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-s390/kvm_para.h
@@ -0,0 +1,17 @@
+/*
+ * asm-s390/kvm_para.h - definition for paravirtual devices on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Christian Borntraeger <borntraeger at de.ibm.com>
+ */
+
+#ifndef __S390_KVM_PARA_H
+#define __S390_KVM_PARA_H
+
+
+#endif /* __S390_KVM_PARA_H */
diff --git a/qemu-0.15.x/linux-headers/asm-x86/hyperv.h b/qemu-0.15.x/linux-headers/asm-x86/hyperv.h
new file mode 100644
index 0000000..5df477a
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-x86/hyperv.h
@@ -0,0 +1,193 @@
+#ifndef _ASM_X86_HYPERV_H
+#define _ASM_X86_HYPERV_H
+
+#include <linux/types.h>
+
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HvCpuIdFunctionVersionAndFeatures).
+ */
+#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS	0x40000000
+#define HYPERV_CPUID_INTERFACE			0x40000001
+#define HYPERV_CPUID_VERSION			0x40000002
+#define HYPERV_CPUID_FEATURES			0x40000003
+#define HYPERV_CPUID_ENLIGHTMENT_INFO		0x40000004
+#define HYPERV_CPUID_IMPLEMENT_LIMITS		0x40000005
+
+#define HYPERV_HYPERVISOR_PRESENT_BIT		0x80000000
+#define HYPERV_CPUID_MIN			0x40000005
+#define HYPERV_CPUID_MAX			0x4000ffff
+
+/*
+ * Feature identification. EAX indicates which features are available
+ * to the partition based upon the current partition privileges.
+ */
+
+/* VP Runtime (HV_X64_MSR_VP_RUNTIME) available */
+#define HV_X64_MSR_VP_RUNTIME_AVAILABLE		(1 << 0)
+/* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/
+#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE	(1 << 1)
+/*
+ * Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
+ * and HV_X64_MSR_SINT0 through HV_X64_MSR_SINT15) available
+ */
+#define HV_X64_MSR_SYNIC_AVAILABLE		(1 << 2)
+/*
+ * Synthetic Timer MSRs (HV_X64_MSR_STIMER0_CONFIG through
+ * HV_X64_MSR_STIMER3_COUNT) available
+ */
+#define HV_X64_MSR_SYNTIMER_AVAILABLE		(1 << 3)
+/*
+ * APIC access MSRs (HV_X64_MSR_EOI, HV_X64_MSR_ICR and HV_X64_MSR_TPR)
+ * are available
+ */
+#define HV_X64_MSR_APIC_ACCESS_AVAILABLE	(1 << 4)
+/* Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL) available*/
+#define HV_X64_MSR_HYPERCALL_AVAILABLE		(1 << 5)
+/* Access virtual processor index MSR (HV_X64_MSR_VP_INDEX) available*/
+#define HV_X64_MSR_VP_INDEX_AVAILABLE		(1 << 6)
+/* Virtual system reset MSR (HV_X64_MSR_RESET) is available*/
+#define HV_X64_MSR_RESET_AVAILABLE		(1 << 7)
+ /*
+  * Access statistics pages MSRs (HV_X64_MSR_STATS_PARTITION_RETAIL_PAGE,
+  * HV_X64_MSR_STATS_PARTITION_INTERNAL_PAGE, HV_X64_MSR_STATS_VP_RETAIL_PAGE,
+  * HV_X64_MSR_STATS_VP_INTERNAL_PAGE) available
+  */
+#define HV_X64_MSR_STAT_PAGES_AVAILABLE		(1 << 8)
+
+/*
+ * Feature identification: EBX indicates which flags were specified at
+ * partition creation. The format is the same as the partition creation
+ * flag structure defined in section Partition Creation Flags.
+ */
+#define HV_X64_CREATE_PARTITIONS		(1 << 0)
+#define HV_X64_ACCESS_PARTITION_ID		(1 << 1)
+#define HV_X64_ACCESS_MEMORY_POOL		(1 << 2)
+#define HV_X64_ADJUST_MESSAGE_BUFFERS		(1 << 3)
+#define HV_X64_POST_MESSAGES			(1 << 4)
+#define HV_X64_SIGNAL_EVENTS			(1 << 5)
+#define HV_X64_CREATE_PORT			(1 << 6)
+#define HV_X64_CONNECT_PORT			(1 << 7)
+#define HV_X64_ACCESS_STATS			(1 << 8)
+#define HV_X64_DEBUGGING			(1 << 11)
+#define HV_X64_CPU_POWER_MANAGEMENT		(1 << 12)
+#define HV_X64_CONFIGURE_PROFILER		(1 << 13)
+
+/*
+ * Feature identification. EDX indicates which miscellaneous features
+ * are available to the partition.
+ */
+/* The MWAIT instruction is available (per section MONITOR / MWAIT) */
+#define HV_X64_MWAIT_AVAILABLE				(1 << 0)
+/* Guest debugging support is available */
+#define HV_X64_GUEST_DEBUGGING_AVAILABLE		(1 << 1)
+/* Performance Monitor support is available*/
+#define HV_X64_PERF_MONITOR_AVAILABLE			(1 << 2)
+/* Support for physical CPU dynamic partitioning events is available*/
+#define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE	(1 << 3)
+/*
+ * Support for passing hypercall input parameter block via XMM
+ * registers is available
+ */
+#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE		(1 << 4)
+/* Support for a virtual guest idle state is available */
+#define HV_X64_GUEST_IDLE_STATE_AVAILABLE		(1 << 5)
+
+/*
+ * Implementation recommendations. Indicates which behaviors the hypervisor
+ * recommends the OS implement for optimal performance.
+ */
+ /*
+  * Recommend using hypercall for address space switches rather
+  * than MOV to CR3 instruction
+  */
+#define HV_X64_MWAIT_RECOMMENDED		(1 << 0)
+/* Recommend using hypercall for local TLB flushes rather
+ * than INVLPG or MOV to CR3 instructions */
+#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED	(1 << 1)
+/*
+ * Recommend using hypercall for remote TLB flushes rather
+ * than inter-processor interrupts
+ */
+#define HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED	(1 << 2)
+/*
+ * Recommend using MSRs for accessing APIC registers
+ * EOI, ICR and TPR rather than their memory-mapped counterparts
+ */
+#define HV_X64_APIC_ACCESS_RECOMMENDED		(1 << 3)
+/* Recommend using the hypervisor-provided MSR to initiate a system RESET */
+#define HV_X64_SYSTEM_RESET_RECOMMENDED		(1 << 4)
+/*
+ * Recommend using relaxed timing for this partition. If used,
+ * the VM should disable any watchdog timeouts that rely on the
+ * timely delivery of external interrupts
+ */
+#define HV_X64_RELAXED_TIMING_RECOMMENDED	(1 << 5)
+
+/* MSR used to identify the guest OS. */
+#define HV_X64_MSR_GUEST_OS_ID			0x40000000
+
+/* MSR used to setup pages used to communicate with the hypervisor. */
+#define HV_X64_MSR_HYPERCALL			0x40000001
+
+/* MSR used to provide vcpu index */
+#define HV_X64_MSR_VP_INDEX			0x40000002
+
+/* MSR used to read the per-partition time reference counter */
+#define HV_X64_MSR_TIME_REF_COUNT		0x40000020
+
+/* Define the virtual APIC registers */
+#define HV_X64_MSR_EOI				0x40000070
+#define HV_X64_MSR_ICR				0x40000071
+#define HV_X64_MSR_TPR				0x40000072
+#define HV_X64_MSR_APIC_ASSIST_PAGE		0x40000073
+
+/* Define synthetic interrupt controller model specific registers. */
+#define HV_X64_MSR_SCONTROL			0x40000080
+#define HV_X64_MSR_SVERSION			0x40000081
+#define HV_X64_MSR_SIEFP			0x40000082
+#define HV_X64_MSR_SIMP				0x40000083
+#define HV_X64_MSR_EOM				0x40000084
+#define HV_X64_MSR_SINT0			0x40000090
+#define HV_X64_MSR_SINT1			0x40000091
+#define HV_X64_MSR_SINT2			0x40000092
+#define HV_X64_MSR_SINT3			0x40000093
+#define HV_X64_MSR_SINT4			0x40000094
+#define HV_X64_MSR_SINT5			0x40000095
+#define HV_X64_MSR_SINT6			0x40000096
+#define HV_X64_MSR_SINT7			0x40000097
+#define HV_X64_MSR_SINT8			0x40000098
+#define HV_X64_MSR_SINT9			0x40000099
+#define HV_X64_MSR_SINT10			0x4000009A
+#define HV_X64_MSR_SINT11			0x4000009B
+#define HV_X64_MSR_SINT12			0x4000009C
+#define HV_X64_MSR_SINT13			0x4000009D
+#define HV_X64_MSR_SINT14			0x4000009E
+#define HV_X64_MSR_SINT15			0x4000009F
+
+
+#define HV_X64_MSR_HYPERCALL_ENABLE		0x00000001
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT	12
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK	\
+		(~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1))
+
+/* Declare the various hypercall operations. */
+#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT		0x0008
+
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE		0x00000001
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT	12
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK	\
+		(~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1))
+
+#define HV_PROCESSOR_POWER_STATE_C0		0
+#define HV_PROCESSOR_POWER_STATE_C1		1
+#define HV_PROCESSOR_POWER_STATE_C2		2
+#define HV_PROCESSOR_POWER_STATE_C3		3
+
+/* hypercall status code */
+#define HV_STATUS_SUCCESS			0
+#define HV_STATUS_INVALID_HYPERCALL_CODE	2
+#define HV_STATUS_INVALID_HYPERCALL_INPUT	3
+#define HV_STATUS_INVALID_ALIGNMENT		4
+
+#endif
diff --git a/qemu-0.15.x/linux-headers/asm-x86/kvm.h b/qemu-0.15.x/linux-headers/asm-x86/kvm.h
new file mode 100644
index 0000000..4d8dcbd
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-x86/kvm.h
@@ -0,0 +1,324 @@
+#ifndef _ASM_X86_KVM_H
+#define _ASM_X86_KVM_H
+
+/*
+ * KVM x86 specific structures and definitions
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_PIT
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+#define __KVM_HAVE_MSI
+#define __KVM_HAVE_USER_NMI
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
+#define __KVM_HAVE_PIT_STATE2
+#define __KVM_HAVE_XEN_HVM
+#define __KVM_HAVE_VCPU_EVENTS
+#define __KVM_HAVE_DEBUGREGS
+#define __KVM_HAVE_XSAVE
+#define __KVM_HAVE_XCRS
+
+/* Architectural interrupt line count. */
+#define KVM_NR_INTERRUPTS 256
+
+struct kvm_memory_alias {
+	__u32 slot;  /* this has a different namespace than memory slots */
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size;
+	__u64 target_phys_addr;
+};
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+	__u8 last_irr;	/* edge detection */
+	__u8 irr;		/* interrupt request register */
+	__u8 imr;		/* interrupt mask register */
+	__u8 isr;		/* interrupt service register */
+	__u8 priority_add;	/* highest irq priority */
+	__u8 irq_base;
+	__u8 read_reg_select;
+	__u8 poll;
+	__u8 special_mask;
+	__u8 init_state;
+	__u8 auto_eoi;
+	__u8 rotate_on_auto_eoi;
+	__u8 special_fully_nested_mode;
+	__u8 init4;		/* true if 4 byte init */
+	__u8 elcr;		/* PIIX edge/trigger selection */
+	__u8 elcr_mask;
+};
+
+#define KVM_IOAPIC_NUM_PINS  24
+struct kvm_ioapic_state {
+	__u64 base_address;
+	__u32 ioregsel;
+	__u32 id;
+	__u32 irr;
+	__u32 pad;
+	union {
+		__u64 bits;
+		struct {
+			__u8 vector;
+			__u8 delivery_mode:3;
+			__u8 dest_mode:1;
+			__u8 delivery_status:1;
+			__u8 polarity:1;
+			__u8 remote_irr:1;
+			__u8 trig_mode:1;
+			__u8 mask:1;
+			__u8 reserve:7;
+			__u8 reserved[4];
+			__u8 dest_id;
+		} fields;
+	} redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
+#define KVM_IRQCHIP_PIC_MASTER   0
+#define KVM_IRQCHIP_PIC_SLAVE    1
+#define KVM_IRQCHIP_IOAPIC       2
+#define KVM_NR_IRQCHIPS          3
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+	/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+	__u64 rax, rbx, rcx, rdx;
+	__u64 rsi, rdi, rsp, rbp;
+	__u64 r8,  r9,  r10, r11;
+	__u64 r12, r13, r14, r15;
+	__u64 rip, rflags;
+};
+
+/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
+#define KVM_APIC_REG_SIZE 0x400
+struct kvm_lapic_state {
+	char regs[KVM_APIC_REG_SIZE];
+};
+
+struct kvm_segment {
+	__u64 base;
+	__u32 limit;
+	__u16 selector;
+	__u8  type;
+	__u8  present, dpl, db, s, l, g, avl;
+	__u8  unusable;
+	__u8  padding;
+};
+
+struct kvm_dtable {
+	__u64 base;
+	__u16 limit;
+	__u16 padding[3];
+};
+
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+	/* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
+	struct kvm_segment cs, ds, es, fs, gs, ss;
+	struct kvm_segment tr, ldt;
+	struct kvm_dtable gdt, idt;
+	__u64 cr0, cr2, cr3, cr4, cr8;
+	__u64 efer;
+	__u64 apic_base;
+	__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+	__u8  fpr[8][16];
+	__u16 fcw;
+	__u16 fsw;
+	__u8  ftwx;  /* in fxsave format */
+	__u8  pad1;
+	__u16 last_opcode;
+	__u64 last_ip;
+	__u64 last_dp;
+	__u8  xmm[16][16];
+	__u32 mxcsr;
+	__u32 pad2;
+};
+
+struct kvm_msr_entry {
+	__u32 index;
+	__u32 reserved;
+	__u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 pad;
+
+	struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 indices[0];
+};
+
+
+struct kvm_cpuid_entry {
+	__u32 function;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry entries[0];
+};
+
+struct kvm_cpuid_entry2 {
+	__u32 function;
+	__u32 index;
+	__u32 flags;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding[3];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
+#define KVM_CPUID_FLAG_STATEFUL_FUNC    2
+#define KVM_CPUID_FLAG_STATE_READ_NEXT  4
+
+/* for KVM_SET_CPUID2 */
+struct kvm_cpuid2 {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry2 entries[0];
+};
+
+/* for KVM_GET_PIT and KVM_SET_PIT */
+struct kvm_pit_channel_state {
+	__u32 count; /* can be 65536 */
+	__u16 latched_count;
+	__u8 count_latched;
+	__u8 status_latched;
+	__u8 status;
+	__u8 read_state;
+	__u8 write_state;
+	__u8 write_latch;
+	__u8 rw_mode;
+	__u8 mode;
+	__u8 bcd;
+	__u8 gate;
+	__s64 count_load_time;
+};
+
+struct kvm_debug_exit_arch {
+	__u32 exception;
+	__u32 pad;
+	__u64 pc;
+	__u64 dr6;
+	__u64 dr7;
+};
+
+#define KVM_GUESTDBG_USE_SW_BP		0x00010000
+#define KVM_GUESTDBG_USE_HW_BP		0x00020000
+#define KVM_GUESTDBG_INJECT_DB		0x00040000
+#define KVM_GUESTDBG_INJECT_BP		0x00080000
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+	__u64 debugreg[8];
+};
+
+struct kvm_pit_state {
+	struct kvm_pit_channel_state channels[3];
+};
+
+#define KVM_PIT_FLAGS_HPET_LEGACY  0x00000001
+
+struct kvm_pit_state2 {
+	struct kvm_pit_channel_state channels[3];
+	__u32 flags;
+	__u32 reserved[9];
+};
+
+struct kvm_reinject_control {
+	__u8 pit_reinject;
+	__u8 reserved[31];
+};
+
+/* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
+#define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001
+#define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW	0x00000004
+
+/* Interrupt shadow states */
+#define KVM_X86_SHADOW_INT_MOV_SS	0x01
+#define KVM_X86_SHADOW_INT_STI		0x02
+
+/* for KVM_GET/SET_VCPU_EVENTS */
+struct kvm_vcpu_events {
+	struct {
+		__u8 injected;
+		__u8 nr;
+		__u8 has_error_code;
+		__u8 pad;
+		__u32 error_code;
+	} exception;
+	struct {
+		__u8 injected;
+		__u8 nr;
+		__u8 soft;
+		__u8 shadow;
+	} interrupt;
+	struct {
+		__u8 injected;
+		__u8 pending;
+		__u8 masked;
+		__u8 pad;
+	} nmi;
+	__u32 sipi_vector;
+	__u32 flags;
+	__u32 reserved[10];
+};
+
+/* for KVM_GET/SET_DEBUGREGS */
+struct kvm_debugregs {
+	__u64 db[4];
+	__u64 dr6;
+	__u64 dr7;
+	__u64 flags;
+	__u64 reserved[9];
+};
+
+/* for KVM_CAP_XSAVE */
+struct kvm_xsave {
+	__u32 region[1024];
+};
+
+#define KVM_MAX_XCRS	16
+
+struct kvm_xcr {
+	__u32 xcr;
+	__u32 reserved;
+	__u64 value;
+};
+
+struct kvm_xcrs {
+	__u32 nr_xcrs;
+	__u32 flags;
+	struct kvm_xcr xcrs[KVM_MAX_XCRS];
+	__u64 padding[16];
+};
+
+#endif /* _ASM_X86_KVM_H */
diff --git a/qemu-0.15.x/linux-headers/asm-x86/kvm_para.h b/qemu-0.15.x/linux-headers/asm-x86/kvm_para.h
new file mode 100644
index 0000000..834d71e
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/asm-x86/kvm_para.h
@@ -0,0 +1,79 @@
+#ifndef _ASM_X86_KVM_PARA_H
+#define _ASM_X86_KVM_PARA_H
+
+#include <linux/types.h>
+#include <asm/hyperv.h>
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE	0x40000000
+
+/* This CPUID returns a feature bitmap in eax.  Before enabling a particular
+ * paravirtualization, the appropriate feature bit should be checked.
+ */
+#define KVM_CPUID_FEATURES	0x40000001
+#define KVM_FEATURE_CLOCKSOURCE		0
+#define KVM_FEATURE_NOP_IO_DELAY	1
+#define KVM_FEATURE_MMU_OP		2
+/* This indicates that the new set of kvmclock msrs
+ * are available. The use of 0x11 and 0x12 is deprecated
+ */
+#define KVM_FEATURE_CLOCKSOURCE2        3
+#define KVM_FEATURE_ASYNC_PF		4
+
+/* The last 8 bits are used to indicate how to interpret the flags field
+ * in pvclock structure. If no bits are set, all flags are ignored.
+ */
+#define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT	24
+
+#define MSR_KVM_WALL_CLOCK  0x11
+#define MSR_KVM_SYSTEM_TIME 0x12
+
+/* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */
+#define MSR_KVM_WALL_CLOCK_NEW  0x4b564d00
+#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
+#define MSR_KVM_ASYNC_PF_EN 0x4b564d02
+
+#define KVM_MAX_MMU_OP_BATCH           32
+
+#define KVM_ASYNC_PF_ENABLED			(1 << 0)
+#define KVM_ASYNC_PF_SEND_ALWAYS		(1 << 1)
+
+/* Operations for KVM_HC_MMU_OP */
+#define KVM_MMU_OP_WRITE_PTE            1
+#define KVM_MMU_OP_FLUSH_TLB	        2
+#define KVM_MMU_OP_RELEASE_PT	        3
+
+/* Payload for KVM_HC_MMU_OP */
+struct kvm_mmu_op_header {
+	__u32 op;
+	__u32 pad;
+};
+
+struct kvm_mmu_op_write_pte {
+	struct kvm_mmu_op_header header;
+	__u64 pte_phys;
+	__u64 pte_val;
+};
+
+struct kvm_mmu_op_flush_tlb {
+	struct kvm_mmu_op_header header;
+};
+
+struct kvm_mmu_op_release_pt {
+	struct kvm_mmu_op_header header;
+	__u64 pt_phys;
+};
+
+#define KVM_PV_REASON_PAGE_NOT_PRESENT 1
+#define KVM_PV_REASON_PAGE_READY 2
+
+struct kvm_vcpu_pv_apf_data {
+	__u32 reason;
+	__u8 pad[60];
+	__u32 enabled;
+};
+
+
+#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/qemu-0.15.x/linux-headers/linux/kvm.h b/qemu-0.15.x/linux-headers/linux/kvm.h
new file mode 100644
index 0000000..fc63b73
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/linux/kvm.h
@@ -0,0 +1,804 @@
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+/*
+ * Userspace interface for /dev/kvm - kernel based virtual machine
+ *
+ * Note: you must update KVM_API_VERSION if you change this interface.
+ */
+
+#include <linux/types.h>
+
+#include <linux/ioctl.h>
+#include <asm/kvm.h>
+
+#define KVM_API_VERSION 12
+
+/* *** Deprecated interfaces *** */
+
+#define KVM_TRC_SHIFT           16
+
+#define KVM_TRC_ENTRYEXIT       (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER         (1 << (KVM_TRC_SHIFT + 1))
+
+#define KVM_TRC_VMENTRY         (KVM_TRC_ENTRYEXIT + 0x01)
+#define KVM_TRC_VMEXIT          (KVM_TRC_ENTRYEXIT + 0x02)
+#define KVM_TRC_PAGE_FAULT      (KVM_TRC_HANDLER + 0x01)
+
+#define KVM_TRC_HEAD_SIZE       12
+#define KVM_TRC_CYCLE_SIZE      8
+#define KVM_TRC_EXTRA_MAX       7
+
+#define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
+#define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
+#define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
+#define KVM_TRC_IO_READ          (KVM_TRC_HANDLER + 0x05)
+#define KVM_TRC_IO_WRITE         (KVM_TRC_HANDLER + 0x06)
+#define KVM_TRC_CR_READ          (KVM_TRC_HANDLER + 0x07)
+#define KVM_TRC_CR_WRITE         (KVM_TRC_HANDLER + 0x08)
+#define KVM_TRC_DR_READ          (KVM_TRC_HANDLER + 0x09)
+#define KVM_TRC_DR_WRITE         (KVM_TRC_HANDLER + 0x0A)
+#define KVM_TRC_MSR_READ         (KVM_TRC_HANDLER + 0x0B)
+#define KVM_TRC_MSR_WRITE        (KVM_TRC_HANDLER + 0x0C)
+#define KVM_TRC_CPUID            (KVM_TRC_HANDLER + 0x0D)
+#define KVM_TRC_INTR             (KVM_TRC_HANDLER + 0x0E)
+#define KVM_TRC_NMI              (KVM_TRC_HANDLER + 0x0F)
+#define KVM_TRC_VMMCALL          (KVM_TRC_HANDLER + 0x10)
+#define KVM_TRC_HLT              (KVM_TRC_HANDLER + 0x11)
+#define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
+#define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
+#define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
+#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
+#define KVM_TRC_GTLB_WRITE       (KVM_TRC_HANDLER + 0x16)
+#define KVM_TRC_STLB_WRITE       (KVM_TRC_HANDLER + 0x17)
+#define KVM_TRC_STLB_INVAL       (KVM_TRC_HANDLER + 0x18)
+#define KVM_TRC_PPC_INSTR        (KVM_TRC_HANDLER + 0x19)
+
+struct kvm_user_trace_setup {
+	__u32 buf_size;
+	__u32 buf_nr;
+};
+
+#define __KVM_DEPRECATED_MAIN_W_0x06 \
+	_IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
+#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
+
+#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
+
+struct kvm_breakpoint {
+	__u32 enabled;
+	__u32 padding;
+	__u64 address;
+};
+
+struct kvm_debug_guest {
+	__u32 enabled;
+	__u32 pad;
+	struct kvm_breakpoint breakpoints[4];
+	__u32 singlestep;
+};
+
+#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
+
+/* *** End of deprecated interfaces *** */
+
+
+/* for KVM_CREATE_MEMORY_REGION */
+struct kvm_memory_region {
+	__u32 slot;
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+};
+
+/* for KVM_SET_USER_MEMORY_REGION */
+struct kvm_userspace_memory_region {
+	__u32 slot;
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+	__u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES  1UL
+#define KVM_MEMSLOT_INVALID      (1UL << 1)
+
+/* for KVM_IRQ_LINE */
+struct kvm_irq_level {
+	/*
+	 * ACPI gsi notion of irq.
+	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
+	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+	 */
+	union {
+		__u32 irq;
+		__s32 status;
+	};
+	__u32 level;
+};
+
+
+struct kvm_irqchip {
+	__u32 chip_id;
+	__u32 pad;
+        union {
+		char dummy[512];  /* reserving space */
+#ifdef __KVM_HAVE_PIT
+		struct kvm_pic_state pic;
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+		struct kvm_ioapic_state ioapic;
+#endif
+	} chip;
+};
+
+/* for KVM_CREATE_PIT2 */
+struct kvm_pit_config {
+	__u32 flags;
+	__u32 pad[15];
+};
+
+#define KVM_PIT_SPEAKER_DUMMY     1
+
+#define KVM_EXIT_UNKNOWN          0
+#define KVM_EXIT_EXCEPTION        1
+#define KVM_EXIT_IO               2
+#define KVM_EXIT_HYPERCALL        3
+#define KVM_EXIT_DEBUG            4
+#define KVM_EXIT_HLT              5
+#define KVM_EXIT_MMIO             6
+#define KVM_EXIT_IRQ_WINDOW_OPEN  7
+#define KVM_EXIT_SHUTDOWN         8
+#define KVM_EXIT_FAIL_ENTRY       9
+#define KVM_EXIT_INTR             10
+#define KVM_EXIT_SET_TPR          11
+#define KVM_EXIT_TPR_ACCESS       12
+#define KVM_EXIT_S390_SIEIC       13
+#define KVM_EXIT_S390_RESET       14
+#define KVM_EXIT_DCR              15
+#define KVM_EXIT_NMI              16
+#define KVM_EXIT_INTERNAL_ERROR   17
+#define KVM_EXIT_OSI              18
+
+/* For KVM_EXIT_INTERNAL_ERROR */
+#define KVM_INTERNAL_ERROR_EMULATION 1
+#define KVM_INTERNAL_ERROR_SIMUL_EX 2
+
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
+struct kvm_run {
+	/* in */
+	__u8 request_interrupt_window;
+	__u8 padding1[7];
+
+	/* out */
+	__u32 exit_reason;
+	__u8 ready_for_interrupt_injection;
+	__u8 if_flag;
+	__u8 padding2[2];
+
+	/* in (pre_kvm_run), out (post_kvm_run) */
+	__u64 cr8;
+	__u64 apic_base;
+
+#ifdef __KVM_S390
+	/* the processor status word for s390 */
+	__u64 psw_mask; /* psw upper half */
+	__u64 psw_addr; /* psw lower half */
+#endif
+	union {
+		/* KVM_EXIT_UNKNOWN */
+		struct {
+			__u64 hardware_exit_reason;
+		} hw;
+		/* KVM_EXIT_FAIL_ENTRY */
+		struct {
+			__u64 hardware_entry_failure_reason;
+		} fail_entry;
+		/* KVM_EXIT_EXCEPTION */
+		struct {
+			__u32 exception;
+			__u32 error_code;
+		} ex;
+		/* KVM_EXIT_IO */
+		struct {
+#define KVM_EXIT_IO_IN  0
+#define KVM_EXIT_IO_OUT 1
+			__u8 direction;
+			__u8 size; /* bytes */
+			__u16 port;
+			__u32 count;
+			__u64 data_offset; /* relative to kvm_run start */
+		} io;
+		struct {
+			struct kvm_debug_exit_arch arch;
+		} debug;
+		/* KVM_EXIT_MMIO */
+		struct {
+			__u64 phys_addr;
+			__u8  data[8];
+			__u32 len;
+			__u8  is_write;
+		} mmio;
+		/* KVM_EXIT_HYPERCALL */
+		struct {
+			__u64 nr;
+			__u64 args[6];
+			__u64 ret;
+			__u32 longmode;
+			__u32 pad;
+		} hypercall;
+		/* KVM_EXIT_TPR_ACCESS */
+		struct {
+			__u64 rip;
+			__u32 is_write;
+			__u32 pad;
+		} tpr_access;
+		/* KVM_EXIT_S390_SIEIC */
+		struct {
+			__u8 icptcode;
+			__u16 ipa;
+			__u32 ipb;
+		} s390_sieic;
+		/* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR       1
+#define KVM_S390_RESET_CLEAR     2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT  8
+#define KVM_S390_RESET_IPL       16
+		__u64 s390_reset_flags;
+		/* KVM_EXIT_DCR */
+		struct {
+			__u32 dcrn;
+			__u32 data;
+			__u8  is_write;
+		} dcr;
+		struct {
+			__u32 suberror;
+			/* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
+			__u32 ndata;
+			__u64 data[16];
+		} internal;
+		/* KVM_EXIT_OSI */
+		struct {
+			__u64 gprs[32];
+		} osi;
+		/* Fix the size of the union. */
+		char padding[256];
+	};
+};
+
+/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
+
+struct kvm_coalesced_mmio_zone {
+	__u64 addr;
+	__u32 size;
+	__u32 pad;
+};
+
+struct kvm_coalesced_mmio {
+	__u64 phys_addr;
+	__u32 len;
+	__u32 pad;
+	__u8  data[8];
+};
+
+struct kvm_coalesced_mmio_ring {
+	__u32 first, last;
+	struct kvm_coalesced_mmio coalesced_mmio[0];
+};
+
+#define KVM_COALESCED_MMIO_MAX \
+	((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
+	 sizeof(struct kvm_coalesced_mmio))
+
+/* for KVM_TRANSLATE */
+struct kvm_translation {
+	/* in */
+	__u64 linear_address;
+
+	/* out */
+	__u64 physical_address;
+	__u8  valid;
+	__u8  writeable;
+	__u8  usermode;
+	__u8  pad[5];
+};
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+	/* in */
+	__u32 irq;
+};
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+	__u32 slot;
+	__u32 padding1;
+	union {
+		void *dirty_bitmap; /* one bit per page */
+		__u64 padding2;
+	};
+};
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+	__u32 len;
+	__u8  sigset[0];
+};
+
+/* for KVM_TPR_ACCESS_REPORTING */
+struct kvm_tpr_access_ctl {
+	__u32 enabled;
+	__u32 flags;
+	__u32 reserved[8];
+};
+
+/* for KVM_SET_VAPIC_ADDR */
+struct kvm_vapic_addr {
+	__u64 vapic_addr;
+};
+
+/* for KVM_SET_MPSTATE */
+
+#define KVM_MP_STATE_RUNNABLE          0
+#define KVM_MP_STATE_UNINITIALIZED     1
+#define KVM_MP_STATE_INIT_RECEIVED     2
+#define KVM_MP_STATE_HALTED            3
+#define KVM_MP_STATE_SIPI_RECEIVED     4
+
+struct kvm_mp_state {
+	__u32 mp_state;
+};
+
+struct kvm_s390_psw {
+	__u64 mask;
+	__u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP		0xfffe0000u
+#define KVM_S390_PROGRAM_INT		0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
+#define KVM_S390_RESTART		0xfffe0003u
+#define KVM_S390_INT_VIRTIO		0xffff2603u
+#define KVM_S390_INT_SERVICE		0xffff2401u
+#define KVM_S390_INT_EMERGENCY		0xffff1201u
+
+struct kvm_s390_interrupt {
+	__u32 type;
+	__u32 parm;
+	__u64 parm64;
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+
+#define KVM_GUESTDBG_ENABLE		0x00000001
+#define KVM_GUESTDBG_SINGLESTEP		0x00000002
+
+struct kvm_guest_debug {
+	__u32 control;
+	__u32 pad;
+	struct kvm_guest_debug_arch arch;
+};
+
+enum {
+	kvm_ioeventfd_flag_nr_datamatch,
+	kvm_ioeventfd_flag_nr_pio,
+	kvm_ioeventfd_flag_nr_deassign,
+	kvm_ioeventfd_flag_nr_max,
+};
+
+#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
+#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
+#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
+
+#define KVM_IOEVENTFD_VALID_FLAG_MASK  ((1 << kvm_ioeventfd_flag_nr_max) - 1)
+
+struct kvm_ioeventfd {
+	__u64 datamatch;
+	__u64 addr;        /* legal pio/mmio address */
+	__u32 len;         /* 1, 2, 4, or 8 bytes    */
+	__s32 fd;
+	__u32 flags;
+	__u8  pad[36];
+};
+
+/* for KVM_ENABLE_CAP */
+struct kvm_enable_cap {
+	/* in */
+	__u32 cap;
+	__u32 flags;
+	__u64 args[4];
+	__u8  pad[64];
+};
+
+/* for KVM_PPC_GET_PVINFO */
+struct kvm_ppc_pvinfo {
+	/* out */
+	__u32 flags;
+	__u32 hcall[4];
+	__u8  pad[108];
+};
+
+#define KVMIO 0xAE
+
+/*
+ * ioctls for /dev/kvm fds:
+ */
+#define KVM_GET_API_VERSION       _IO(KVMIO,   0x00)
+#define KVM_CREATE_VM             _IO(KVMIO,   0x01) /* returns a VM fd */
+#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+
+#define KVM_S390_ENABLE_SIE       _IO(KVMIO,   0x06)
+/*
+ * Check if a kvm extension is available.  Argument is extension number,
+ * return is 1 (yes) or 0 (no, sorry).
+ */
+#define KVM_CHECK_EXTENSION       _IO(KVMIO,   0x03)
+/*
+ * Get size for mmap(vcpu_fd)
+ */
+#define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
+#define KVM_GET_SUPPORTED_CPUID   _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
+#define KVM_TRACE_ENABLE          __KVM_DEPRECATED_MAIN_W_0x06
+#define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
+#define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
+
+/*
+ * Extension capability list.
+ */
+#define KVM_CAP_IRQCHIP	  0
+#define KVM_CAP_HLT	  1
+#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
+#define KVM_CAP_USER_MEMORY 3
+#define KVM_CAP_SET_TSS_ADDR 4
+#define KVM_CAP_VAPIC 6
+#define KVM_CAP_EXT_CPUID 7
+#define KVM_CAP_CLOCKSOURCE 8
+#define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
+#define KVM_CAP_NR_MEMSLOTS 10   /* returns max memory slots per vm */
+#define KVM_CAP_PIT 11
+#define KVM_CAP_NOP_IO_DELAY 12
+#define KVM_CAP_PV_MMU 13
+#define KVM_CAP_MP_STATE 14
+#define KVM_CAP_COALESCED_MMIO 15
+#define KVM_CAP_SYNC_MMU 16  /* Changes to host mmap are reflected in guest */
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_ASSIGNMENT 17
+#endif
+#define KVM_CAP_IOMMU 18
+#ifdef __KVM_HAVE_MSI
+#define KVM_CAP_DEVICE_MSI 20
+#endif
+/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
+#ifdef __KVM_HAVE_USER_NMI
+#define KVM_CAP_USER_NMI 22
+#endif
+#ifdef __KVM_HAVE_GUEST_DEBUG
+#define KVM_CAP_SET_GUEST_DEBUG 23
+#endif
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_REINJECT_CONTROL 24
+#endif
+#ifdef __KVM_HAVE_IOAPIC
+#define KVM_CAP_IRQ_ROUTING 25
+#endif
+#define KVM_CAP_IRQ_INJECT_STATUS 26
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+#define KVM_CAP_DEVICE_DEASSIGNMENT 27
+#endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
+#define KVM_CAP_ASSIGN_DEV_IRQ 29
+/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
+#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
+#define KVM_CAP_IRQFD 32
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_PIT2 33
+#endif
+#define KVM_CAP_SET_BOOT_CPU_ID 34
+#ifdef __KVM_HAVE_PIT_STATE2
+#define KVM_CAP_PIT_STATE2 35
+#endif
+#define KVM_CAP_IOEVENTFD 36
+#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+#ifdef __KVM_HAVE_XEN_HVM
+#define KVM_CAP_XEN_HVM 38
+#endif
+#define KVM_CAP_ADJUST_CLOCK 39
+#define KVM_CAP_INTERNAL_ERROR_DATA 40
+#ifdef __KVM_HAVE_VCPU_EVENTS
+#define KVM_CAP_VCPU_EVENTS 41
+#endif
+#define KVM_CAP_S390_PSW 42
+#define KVM_CAP_PPC_SEGSTATE 43
+#define KVM_CAP_HYPERV 44
+#define KVM_CAP_HYPERV_VAPIC 45
+#define KVM_CAP_HYPERV_SPIN 46
+#define KVM_CAP_PCI_SEGMENT 47
+#define KVM_CAP_PPC_PAIRED_SINGLES 48
+#define KVM_CAP_INTR_SHADOW 49
+#ifdef __KVM_HAVE_DEBUGREGS
+#define KVM_CAP_DEBUGREGS 50
+#endif
+#define KVM_CAP_X86_ROBUST_SINGLESTEP 51
+#define KVM_CAP_PPC_OSI 52
+#define KVM_CAP_PPC_UNSET_IRQ 53
+#define KVM_CAP_ENABLE_CAP 54
+#ifdef __KVM_HAVE_XSAVE
+#define KVM_CAP_XSAVE 55
+#endif
+#ifdef __KVM_HAVE_XCRS
+#define KVM_CAP_XCRS 56
+#endif
+#define KVM_CAP_PPC_GET_PVINFO 57
+#define KVM_CAP_PPC_IRQ_LEVEL 58
+#define KVM_CAP_ASYNC_PF 59
+#define KVM_CAP_TSC_CONTROL 60
+#define KVM_CAP_GET_TSC_KHZ 61
+#define KVM_CAP_PPC_BOOKE_SREGS 62
+
+#ifdef KVM_CAP_IRQ_ROUTING
+
+struct kvm_irq_routing_irqchip {
+	__u32 irqchip;
+	__u32 pin;
+};
+
+struct kvm_irq_routing_msi {
+	__u32 address_lo;
+	__u32 address_hi;
+	__u32 data;
+	__u32 pad;
+};
+
+/* gsi routing entry types */
+#define KVM_IRQ_ROUTING_IRQCHIP 1
+#define KVM_IRQ_ROUTING_MSI 2
+
+struct kvm_irq_routing_entry {
+	__u32 gsi;
+	__u32 type;
+	__u32 flags;
+	__u32 pad;
+	union {
+		struct kvm_irq_routing_irqchip irqchip;
+		struct kvm_irq_routing_msi msi;
+		__u32 pad[8];
+	} u;
+};
+
+struct kvm_irq_routing {
+	__u32 nr;
+	__u32 flags;
+	struct kvm_irq_routing_entry entries[0];
+};
+
+#endif
+
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+	__u64 status;
+	__u64 addr;
+	__u64 misc;
+	__u64 mcg_status;
+	__u8 bank;
+	__u8 pad1[7];
+	__u64 pad2[3];
+};
+#endif
+
+#ifdef KVM_CAP_XEN_HVM
+struct kvm_xen_hvm_config {
+	__u32 flags;
+	__u32 msr;
+	__u64 blob_addr_32;
+	__u64 blob_addr_64;
+	__u8 blob_size_32;
+	__u8 blob_size_64;
+	__u8 pad2[30];
+};
+#endif
+
+#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
+
+struct kvm_irqfd {
+	__u32 fd;
+	__u32 gsi;
+	__u32 flags;
+	__u8  pad[20];
+};
+
+struct kvm_clock_data {
+	__u64 clock;
+	__u32 flags;
+	__u32 pad[9];
+};
+
+/*
+ * ioctls for VM fds
+ */
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO,  0x40, struct kvm_memory_region)
+/*
+ * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
+ * a vcpu fd.
+ */
+#define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO,  0x42, struct kvm_dirty_log)
+/* KVM_SET_MEMORY_ALIAS is obsolete: */
+#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO,  0x43, struct kvm_memory_alias)
+#define KVM_SET_NR_MMU_PAGES      _IO(KVMIO,   0x44)
+#define KVM_GET_NR_MMU_PAGES      _IO(KVMIO,   0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
+					struct kvm_userspace_memory_region)
+#define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
+#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+/* Device model IOC */
+#define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
+#define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
+#define KVM_GET_IRQCHIP           _IOWR(KVMIO, 0x62, struct kvm_irqchip)
+#define KVM_SET_IRQCHIP           _IOR(KVMIO,  0x63, struct kvm_irqchip)
+#define KVM_CREATE_PIT            _IO(KVMIO,   0x64)
+#define KVM_GET_PIT               _IOWR(KVMIO, 0x65, struct kvm_pit_state)
+#define KVM_SET_PIT               _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_IRQ_LINE_STATUS       _IOWR(KVMIO, 0x67, struct kvm_irq_level)
+#define KVM_REGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
+#define KVM_UNREGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
+#define KVM_ASSIGN_PCI_DEVICE     _IOR(KVMIO,  0x69, \
+				       struct kvm_assigned_pci_dev)
+#define KVM_SET_GSI_ROUTING       _IOW(KVMIO,  0x6a, struct kvm_irq_routing)
+/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
+#define KVM_ASSIGN_IRQ            __KVM_DEPRECATED_VM_R_0x70
+#define KVM_ASSIGN_DEV_IRQ        _IOW(KVMIO,  0x70, struct kvm_assigned_irq)
+#define KVM_REINJECT_CONTROL      _IO(KVMIO,   0x71)
+#define KVM_DEASSIGN_PCI_DEVICE   _IOW(KVMIO,  0x72, \
+				       struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR    _IOW(KVMIO,  0x73, \
+				       struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO,  0x74, \
+				       struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ      _IOW(KVMIO,  0x75, struct kvm_assigned_irq)
+#define KVM_IRQFD                 _IOW(KVMIO,  0x76, struct kvm_irqfd)
+#define KVM_CREATE_PIT2		  _IOW(KVMIO,  0x77, struct kvm_pit_config)
+#define KVM_SET_BOOT_CPU_ID       _IO(KVMIO,   0x78)
+#define KVM_IOEVENTFD             _IOW(KVMIO,  0x79, struct kvm_ioeventfd)
+#define KVM_XEN_HVM_CONFIG        _IOW(KVMIO,  0x7a, struct kvm_xen_hvm_config)
+#define KVM_SET_CLOCK             _IOW(KVMIO,  0x7b, struct kvm_clock_data)
+#define KVM_GET_CLOCK             _IOR(KVMIO,  0x7c, struct kvm_clock_data)
+/* Available with KVM_CAP_PIT_STATE2 */
+#define KVM_GET_PIT2              _IOR(KVMIO,  0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
+/* Available with KVM_CAP_PPC_GET_PVINFO */
+#define KVM_PPC_GET_PVINFO	  _IOW(KVMIO,  0xa1, struct kvm_ppc_pvinfo)
+/* Available with KVM_CAP_TSC_CONTROL */
+#define KVM_SET_TSC_KHZ           _IO(KVMIO,  0xa2)
+#define KVM_GET_TSC_KHZ           _IO(KVMIO,  0xa3)
+
+/*
+ * ioctls for vcpu fds
+ */
+#define KVM_RUN                   _IO(KVMIO,   0x80)
+#define KVM_GET_REGS              _IOR(KVMIO,  0x81, struct kvm_regs)
+#define KVM_SET_REGS              _IOW(KVMIO,  0x82, struct kvm_regs)
+#define KVM_GET_SREGS             _IOR(KVMIO,  0x83, struct kvm_sregs)
+#define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
+#define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
+#define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
+/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
+#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_VCPU_W_0x87
+#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
+#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
+#define KVM_GET_FPU               _IOR(KVMIO,  0x8c, struct kvm_fpu)
+#define KVM_SET_FPU               _IOW(KVMIO,  0x8d, struct kvm_fpu)
+#define KVM_GET_LAPIC             _IOR(KVMIO,  0x8e, struct kvm_lapic_state)
+#define KVM_SET_LAPIC             _IOW(KVMIO,  0x8f, struct kvm_lapic_state)
+#define KVM_SET_CPUID2            _IOW(KVMIO,  0x90, struct kvm_cpuid2)
+#define KVM_GET_CPUID2            _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_TPR_ACCESS_REPORTING  _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
+/* Available with KVM_CAP_VAPIC */
+#define KVM_SET_VAPIC_ADDR        _IOW(KVMIO,  0x93, struct kvm_vapic_addr)
+/* valid for virtual machine (for floating interrupt)_and_ vcpu */
+#define KVM_S390_INTERRUPT        _IOW(KVMIO,  0x94, struct kvm_s390_interrupt)
+/* store status for s390 */
+#define KVM_S390_STORE_STATUS_NOADDR    (-1ul)
+#define KVM_S390_STORE_STATUS_PREFIXED  (-2ul)
+#define KVM_S390_STORE_STATUS	  _IOW(KVMIO,  0x95, unsigned long)
+/* initial ipl psw for s390 */
+#define KVM_S390_SET_INITIAL_PSW  _IOW(KVMIO,  0x96, struct kvm_s390_psw)
+/* initial reset for s390 */
+#define KVM_S390_INITIAL_RESET    _IO(KVMIO,   0x97)
+#define KVM_GET_MP_STATE          _IOR(KVMIO,  0x98, struct kvm_mp_state)
+#define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
+/* Available with KVM_CAP_NMI */
+#define KVM_NMI                   _IO(KVMIO,   0x9a)
+/* Available with KVM_CAP_SET_GUEST_DEBUG */
+#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE         _IOW(KVMIO,  0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO,  0x9d, __u64)
+#define KVM_X86_SET_MCE           _IOW(KVMIO,  0x9e, struct kvm_x86_mce)
+/* IA64 stack access */
+#define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
+#define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
+/* Available with KVM_CAP_VCPU_EVENTS */
+#define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
+#define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
+/* Available with KVM_CAP_DEBUGREGS */
+#define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
+#define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
+#define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap)
+/* Available with KVM_CAP_XSAVE */
+#define KVM_GET_XSAVE		  _IOR(KVMIO,  0xa4, struct kvm_xsave)
+#define KVM_SET_XSAVE		  _IOW(KVMIO,  0xa5, struct kvm_xsave)
+/* Available with KVM_CAP_XCRS */
+#define KVM_GET_XCRS		  _IOR(KVMIO,  0xa6, struct kvm_xcrs)
+#define KVM_SET_XCRS		  _IOW(KVMIO,  0xa7, struct kvm_xcrs)
+
+#define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
+
+struct kvm_assigned_pci_dev {
+	__u32 assigned_dev_id;
+	__u32 busnr;
+	__u32 devfn;
+	__u32 flags;
+	__u32 segnr;
+	union {
+		__u32 reserved[11];
+	};
+};
+
+#define KVM_DEV_IRQ_HOST_INTX    (1 << 0)
+#define KVM_DEV_IRQ_HOST_MSI     (1 << 1)
+#define KVM_DEV_IRQ_HOST_MSIX    (1 << 2)
+
+#define KVM_DEV_IRQ_GUEST_INTX   (1 << 8)
+#define KVM_DEV_IRQ_GUEST_MSI    (1 << 9)
+#define KVM_DEV_IRQ_GUEST_MSIX   (1 << 10)
+
+#define KVM_DEV_IRQ_HOST_MASK	 0x00ff
+#define KVM_DEV_IRQ_GUEST_MASK   0xff00
+
+struct kvm_assigned_irq {
+	__u32 assigned_dev_id;
+	__u32 host_irq;
+	__u32 guest_irq;
+	__u32 flags;
+	union {
+		struct {
+			__u32 addr_lo;
+			__u32 addr_hi;
+			__u32 data;
+		} guest_msi;
+		__u32 reserved[12];
+	};
+};
+
+
+struct kvm_assigned_msix_nr {
+	__u32 assigned_dev_id;
+	__u16 entry_nr;
+	__u16 padding;
+};
+
+#define KVM_MAX_MSIX_PER_DEV		256
+struct kvm_assigned_msix_entry {
+	__u32 assigned_dev_id;
+	__u32 gsi;
+	__u16 entry; /* The index of entry in the MSI-X table */
+	__u16 padding[3];
+};
+
+#endif /* __LINUX_KVM_H */
diff --git a/qemu-0.15.x/linux-headers/linux/kvm_para.h b/qemu-0.15.x/linux-headers/linux/kvm_para.h
new file mode 100644
index 0000000..7bdcf93
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/linux/kvm_para.h
@@ -0,0 +1,28 @@
+#ifndef __LINUX_KVM_PARA_H
+#define __LINUX_KVM_PARA_H
+
+/*
+ * This header file provides a method for making a hypercall to the host
+ * Architectures should define:
+ * - kvm_hypercall0, kvm_hypercall1...
+ * - kvm_arch_para_features
+ * - kvm_para_available
+ */
+
+/* Return values for hypercalls */
+#define KVM_ENOSYS		1000
+#define KVM_EFAULT		EFAULT
+#define KVM_E2BIG		E2BIG
+#define KVM_EPERM		EPERM
+
+#define KVM_HC_VAPIC_POLL_IRQ		1
+#define KVM_HC_MMU_OP			2
+#define KVM_HC_FEATURES			3
+#define KVM_HC_PPC_MAP_MAGIC_PAGE	4
+
+/*
+ * hypercalls use architecture specific
+ */
+#include <asm/kvm_para.h>
+
+#endif /* __LINUX_KVM_PARA_H */
diff --git a/qemu-0.15.x/linux-headers/linux/vhost.h b/qemu-0.15.x/linux-headers/linux/vhost.h
new file mode 100644
index 0000000..165a484
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/linux/vhost.h
@@ -0,0 +1,130 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+	unsigned int index;
+	unsigned int num;
+};
+
+struct vhost_vring_file {
+	unsigned int index;
+	int fd; /* Pass -1 to unbind from file. */
+
+};
+
+struct vhost_vring_addr {
+	unsigned int index;
+	/* Option flags. */
+	unsigned int flags;
+	/* Flag values: */
+	/* Whether log address is valid. If set enables logging. */
+#define VHOST_VRING_F_LOG 0
+
+	/* Start of array of descriptors (virtually contiguous) */
+	__u64 desc_user_addr;
+	/* Used structure address. Must be 32 bit aligned */
+	__u64 used_user_addr;
+	/* Available structure address. Must be 16 bit aligned */
+	__u64 avail_user_addr;
+	/* Logging support. */
+	/* Log writes to used structure, at offset calculated from specified
+	 * address. Address must be 32 bit aligned. */
+	__u64 log_guest_addr;
+};
+
+struct vhost_memory_region {
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+	__u64 userspace_addr;
+	__u64 flags_padding; /* No flags are currently specified. */
+};
+
+/* All region addresses and sizes must be 4K aligned. */
+#define VHOST_PAGE_SIZE 0x1000
+
+struct vhost_memory {
+	__u32 nregions;
+	__u32 padding;
+	struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility.  Transport bits are used for
+ * vhost specific features. */
+#define VHOST_GET_FEATURES	_IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_FEATURES	_IOW(VHOST_VIRTIO, 0x00, __u64)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE	_IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Write logging setup. */
+/* Memory writes can optionally be logged by setting bit at an offset
+ * (calculated from the physical address) from specified log base.
+ * The bit is set using an atomic 32 bit operation. */
+/* Set base address for logging. */
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+/* Specify an eventfd file descriptor to signal on log write. */
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+
+/* Ring setup. */
+/* Set number of descriptors in ring. This parameter can not
+ * be modified while ring is running (bound to a device). */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Set addresses for the ring. */
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net ring to a raw socket, or tap device.
+ * The socket must be already bound to an ethernet device, this device will be
+ * used for transmit.  Pass fd -1 to unbind from the socket and the transmit
+ * device.  This can be used to stop the ring (e.g. for migration). */
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* Feature bits */
+/* Log all write descriptors. Can be changed while device is active. */
+#define VHOST_F_LOG_ALL 26
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
+
+#endif
diff --git a/qemu-0.15.x/linux-headers/linux/virtio_config.h b/qemu-0.15.x/linux-headers/linux/virtio_config.h
new file mode 100644
index 0000000..4f51d8f
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/linux/virtio_config.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * 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. Neither the name of IBM 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 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 IBM 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. */
+
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE	1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER		2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK	4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED		0x80
+
+/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
+ * transport being used (eg. virtio_ring), the rest are per-device feature
+ * bits. */
+#define VIRTIO_TRANSPORT_F_START	28
+#define VIRTIO_TRANSPORT_F_END		32
+
+/* Do we get callbacks when the ring is completely used, even if we've
+ * suppressed them? */
+#define VIRTIO_F_NOTIFY_ON_EMPTY	24
+
+#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/qemu-0.15.x/linux-headers/linux/virtio_ring.h b/qemu-0.15.x/linux-headers/linux/virtio_ring.h
new file mode 100644
index 0000000..78289ee
--- /dev/null
+++ b/qemu-0.15.x/linux-headers/linux/virtio_ring.h
@@ -0,0 +1,163 @@
+#ifndef _LINUX_VIRTIO_RING_H
+#define _LINUX_VIRTIO_RING_H
+/* An interface for efficient virtio implementation, currently for use by KVM
+ * and lguest, but hopefully others soon.  Do NOT change this since it will
+ * break existing servers and clients.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * 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. Neither the name of IBM 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 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 IBM 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.
+ *
+ * Copyright Rusty Russell IBM Corporation 2007. */
+#include <linux/types.h>
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT	1
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE	2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT	4
+
+/* The Host uses this in used->flags to advise the Guest: don't kick me when
+ * you add a buffer.  It's unreliable, so it's simply an optimization.  Guest
+ * will still kick if it's out of buffers. */
+#define VRING_USED_F_NO_NOTIFY	1
+/* The Guest uses this in avail->flags to advise the Host: don't interrupt me
+ * when you consume a buffer.  It's unreliable, so it's simply an
+ * optimization.  */
+#define VRING_AVAIL_F_NO_INTERRUPT	1
+
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC	28
+
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX		29
+
+/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
+struct vring_desc {
+	/* Address (guest-physical). */
+	__u64 addr;
+	/* Length. */
+	__u32 len;
+	/* The flags as indicated above. */
+	__u16 flags;
+	/* We chain unused descriptors via this, too */
+	__u16 next;
+};
+
+struct vring_avail {
+	__u16 flags;
+	__u16 idx;
+	__u16 ring[];
+};
+
+/* u32 is used here for ids for padding reasons. */
+struct vring_used_elem {
+	/* Index of start of used descriptor chain. */
+	__u32 id;
+	/* Total length of the descriptor chain which was used (written to) */
+	__u32 len;
+};
+
+struct vring_used {
+	__u16 flags;
+	__u16 idx;
+	struct vring_used_elem ring[];
+};
+
+struct vring {
+	unsigned int num;
+
+	struct vring_desc *desc;
+
+	struct vring_avail *avail;
+
+	struct vring_used *used;
+};
+
+/* The standard layout for the ring is a continuous chunk of memory which looks
+ * like this.  We assume num is a power of 2.
+ *
+ * struct vring
+ * {
+ *	// The actual descriptors (16 bytes each)
+ *	struct vring_desc desc[num];
+ *
+ *	// A ring of available descriptor heads with free-running index.
+ *	__u16 avail_flags;
+ *	__u16 avail_idx;
+ *	__u16 available[num];
+ *	__u16 used_event_idx;
+ *
+ *	// Padding to the next align boundary.
+ *	char pad[];
+ *
+ *	// A ring of used descriptor heads with free-running index.
+ *	__u16 used_flags;
+ *	__u16 used_idx;
+ *	struct vring_used_elem used[num];
+ *	__u16 avail_event_idx;
+ * };
+ */
+/* We publish the used event index at the end of the available ring, and vice
+ * versa. They are at the end for backwards compatibility. */
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+
+static __inline__ void vring_init(struct vring *vr, unsigned int num, void *p,
+			      unsigned long align)
+{
+	vr->num = num;
+	vr->desc = p;
+	vr->avail = p + num*sizeof(struct vring_desc);
+	vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
+			    & ~(align - 1));
+}
+
+static __inline__ unsigned vring_size(unsigned int num, unsigned long align)
+{
+	return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+		 + align - 1) & ~(align - 1))
+		+ sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+}
+
+/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
+{
+	/* Note: Xen has similar logic for notification hold-off
+	 * in include/xen/interface/io/ring.h with req_event and req_prod
+	 * corresponding to event_idx + 1 and new_idx respectively.
+	 * Note also that req_event and req_prod in Xen start at 1,
+	 * event indexes in virtio start at 0. */
+	return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
+}
+
+#endif /* _LINUX_VIRTIO_RING_H */
diff --git a/qemu-0.15.x/linux-user/alpha/syscall.h b/qemu-0.15.x/linux-user/alpha/syscall.h
new file mode 100644
index 0000000..15a0100
--- /dev/null
+++ b/qemu-0.15.x/linux-user/alpha/syscall.h
@@ -0,0 +1,253 @@
+/* default linux values for the selectors */
+#define __USER_DS	(1)
+
+struct target_pt_regs {
+	abi_ulong r0;
+	abi_ulong r1;
+	abi_ulong r2;
+	abi_ulong r3;
+	abi_ulong r4;
+	abi_ulong r5;
+	abi_ulong r6;
+	abi_ulong r7;
+	abi_ulong r8;
+	abi_ulong r19;
+	abi_ulong r20;
+	abi_ulong r21;
+	abi_ulong r22;
+	abi_ulong r23;
+	abi_ulong r24;
+	abi_ulong r25;
+	abi_ulong r26;
+	abi_ulong r27;
+	abi_ulong r28;
+	abi_ulong hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+	abi_ulong trap_a0;
+	abi_ulong trap_a1;
+	abi_ulong trap_a2;
+/* These are saved by PAL-code: */
+	abi_ulong ps;
+	abi_ulong pc;
+	abi_ulong gp;
+	abi_ulong r16;
+	abi_ulong r17;
+	abi_ulong r18;
+/* Those is needed by qemu to temporary store the user stack pointer */
+        abi_ulong usp;
+        abi_ulong unique;
+};
+
+#define UNAME_MACHINE "alpha"
+
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK		11
+#undef TARGET_EAGAIN
+#define TARGET_EAGAIN		35
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS	36
+#undef TARGET_EALREADY
+#define TARGET_EALREADY		37
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK		38
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ	39
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE		40
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE	41
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT	42
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT	43
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT	44
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP	45
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT	46
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT	47
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE	48
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL	49
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN		50
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH	51
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET	52
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED	53
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET	54
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS		55
+#undef TARGET_EISCONN
+#define TARGET_EISCONN		56
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN		57
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN	58
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS	59
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT	60
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED	61
+#undef TARGET_ELOOP
+#define TARGET_ELOOP		62
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG	63
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN	64
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH	65
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY	66
+// Unused			67
+#undef TARGET_EUSERS
+#define TARGET_EUSERS		68
+#undef TARGET_EDQUOT
+#define TARGET_EDQUOT		69
+#undef TARGET_ESTALE
+#define TARGET_ESTALE		70
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE		71
+// Unused			72-76
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK		77
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS		78
+// Unused			79
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG		80
+#undef TARGET_EIDRM
+#define TARGET_EIDRM		81
+#undef TARGET_ENOSR
+#define TARGET_ENOSR		82
+#undef TARGET_ETIME
+#define TARGET_ETIME		83
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG		84
+#undef TARGET_EPROTO
+#define TARGET_EPROTO		85
+#undef TARGET_ENODATA
+#define TARGET_ENODATA		86
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR		87
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG		88
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC		89
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT		90
+#undef TARGET_EL3RST
+#define TARGET_EL3RST		91
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG		92
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG		93
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH		94
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI		95
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT		96
+#undef TARGET_EBADE
+#define TARGET_EBADE		97
+#undef TARGET_EBADR
+#define TARGET_EBADR		98
+#undef TARGET_EXFULL
+#define TARGET_EXFULL		99
+#undef TARGET_ENOANO
+#define TARGET_ENOANO		100
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC		101
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT		102
+// Unused			103
+#undef TARGET_EBFONT
+#define TARGET_EBFONT		104
+#undef TARGET_ENONET
+#define TARGET_ENONET		105
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK		106
+#undef TARGET_EADV
+#define TARGET_EADV		107
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT		108
+#undef TARGET_ECOMM
+#define TARGET_ECOMM		109
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP	110
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT		111
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW	112
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ		113
+#undef TARGET_EBADFD
+#define TARGET_EBADFD		114
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG		115
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ		116
+
+// Same as default		117-121
+
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC		122
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD		123
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN		124
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX		125
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC		126
+#undef TARGET_ERESTART
+#define TARGET_ERESTART		127
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE		128
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM	129
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE	130
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED	131
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY		132
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED	133
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED	134
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED	135
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD	136
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE	137
+#undef TARGET_ERFKILL
+#define TARGET_ERFKILL		138
+
+// For sys_osf_getsysinfo
+#define TARGET_GSI_UACPROC		8
+#define TARGET_GSI_IEEE_FP_CONTROL	45
+#define TARGET_GSI_IEEE_STATE_AT_SIGNAL	46
+#define TARGET_GSI_PROC_TYPE		60
+#define TARGET_GSI_GET_HWRPB		101
+
+// For sys_ofs_setsysinfo
+#define TARGET_SSI_NVPAIRS		1
+#define TARGET_SSI_IEEE_FP_CONTROL	14
+#define TARGET_SSI_IEEE_STATE_AT_SIGNAL	15
+#define TARGET_SSI_IEEE_IGNORE_STATE_AT_SIGNAL 16
+#define TARGET_SSI_IEEE_RAISE_EXCEPTION	1001
+
+#define TARGET_SSIN_UACPROC		6
+
+#define TARGET_UAC_NOPRINT		1
+#define TARGET_UAC_NOFIX		2
+#define TARGET_UAC_SIGBUS		4
diff --git a/qemu-0.15.x/linux-user/alpha/syscall_nr.h b/qemu-0.15.x/linux-user/alpha/syscall_nr.h
new file mode 100644
index 0000000..f6284db
--- /dev/null
+++ b/qemu-0.15.x/linux-user/alpha/syscall_nr.h
@@ -0,0 +1,435 @@
+#define TARGET_NR_osf_syscall	  0	/* not implemented */
+#define TARGET_NR_exit		  1
+#define TARGET_NR_fork		  2
+#define TARGET_NR_read		  3
+#define TARGET_NR_write		  4
+#define TARGET_NR_osf_old_open	  5	/* not implemented */
+#define TARGET_NR_close		  6
+#define TARGET_NR_osf_wait4		  7
+#define TARGET_NR_osf_old_creat	  8	/* not implemented */
+#define TARGET_NR_link		  9
+#define TARGET_NR_unlink		 10
+#define TARGET_NR_osf_execve		 11	/* not implemented */
+#define TARGET_NR_chdir		 12
+#define TARGET_NR_fchdir		 13
+#define TARGET_NR_mknod		 14
+#define TARGET_NR_chmod		 15
+#define TARGET_NR_chown		 16
+#define TARGET_NR_brk		 17
+#define TARGET_NR_osf_getfsstat	 18	/* not implemented */
+#define TARGET_NR_lseek		 19
+#define TARGET_NR_getxpid		 20
+#define TARGET_NR_osf_mount		 21
+#define TARGET_NR_umount		 22
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getxuid		 24
+#define TARGET_NR_exec_with_loader	 25	/* not implemented */
+#define TARGET_NR_ptrace		 26
+#define TARGET_NR_osf_nrecvmsg	 27	/* not implemented */
+#define TARGET_NR_osf_nsendmsg	 28	/* not implemented */
+#define TARGET_NR_osf_nrecvfrom	 29	/* not implemented */
+#define TARGET_NR_osf_naccept	 30	/* not implemented */
+#define TARGET_NR_osf_ngetpeername	 31	/* not implemented */
+#define TARGET_NR_osf_ngetsockname	 32	/* not implemented */
+#define TARGET_NR_access		 33
+#define TARGET_NR_osf_chflags	 34	/* not implemented */
+#define TARGET_NR_osf_fchflags	 35	/* not implemented */
+#define TARGET_NR_sync		 36
+#define TARGET_NR_kill		 37
+#define TARGET_NR_osf_old_stat	 38	/* not implemented */
+#define TARGET_NR_setpgid		 39
+#define TARGET_NR_osf_old_lstat	 40	/* not implemented */
+#define TARGET_NR_dup		 41
+#define TARGET_NR_pipe		 42
+#define TARGET_NR_osf_set_program_attributes	43
+#define TARGET_NR_osf_profil		 44	/* not implemented */
+#define TARGET_NR_open		 45
+#define TARGET_NR_osf_old_sigaction	 46	/* not implemented */
+#define TARGET_NR_getxgid		 47
+#define TARGET_NR_osf_sigprocmask	 48
+#define TARGET_NR_osf_getlogin	 49	/* not implemented */
+#define TARGET_NR_osf_setlogin	 50	/* not implemented */
+#define TARGET_NR_acct		 51
+#define TARGET_NR_sigpending		 52
+
+#define TARGET_NR_ioctl		 54
+#define TARGET_NR_osf_reboot		 55	/* not implemented */
+#define TARGET_NR_osf_revoke		 56	/* not implemented */
+#define TARGET_NR_symlink		 57
+#define TARGET_NR_readlink		 58
+#define TARGET_NR_execve		 59
+#define TARGET_NR_umask		 60
+#define TARGET_NR_chroot		 61
+#define TARGET_NR_osf_old_fstat	 62	/* not implemented */
+#define TARGET_NR_getpgrp		 63
+#define TARGET_NR_getpagesize	 64
+#define TARGET_NR_osf_mremap		 65	/* not implemented */
+#define TARGET_NR_vfork		 66
+#define TARGET_NR_stat		 67
+#define TARGET_NR_lstat		 68
+#define TARGET_NR_osf_sbrk		 69	/* not implemented */
+#define TARGET_NR_osf_sstk		 70	/* not implemented */
+#define TARGET_NR_mmap		 71	/* OSF/1 mmap is superset of Linux */
+#define TARGET_NR_osf_old_vadvise	 72	/* not implemented */
+#define TARGET_NR_munmap		 73
+#define TARGET_NR_mprotect		 74
+#define TARGET_NR_madvise		 75
+#define TARGET_NR_vhangup		 76
+#define TARGET_NR_osf_kmodcall	 77	/* not implemented */
+#define TARGET_NR_osf_mincore	 78	/* not implemented */
+#define TARGET_NR_getgroups		 79
+#define TARGET_NR_setgroups		 80
+#define TARGET_NR_osf_old_getpgrp	 81	/* not implemented */
+#define TARGET_NR_setpgrp		 82	/* BSD alias for setpgid */
+#define TARGET_NR_osf_setitimer	 83
+#define TARGET_NR_osf_old_wait	 84	/* not implemented */
+#define TARGET_NR_osf_table		 85	/* not implemented */
+#define TARGET_NR_osf_getitimer	 86
+#define TARGET_NR_gethostname	 87
+#define TARGET_NR_sethostname	 88
+#define TARGET_NR_getdtablesize	 89
+#define TARGET_NR_dup2		 90
+#define TARGET_NR_fstat		 91
+#define TARGET_NR_fcntl		 92
+#define TARGET_NR_osf_select		 93
+#define TARGET_NR_poll		 94
+#define TARGET_NR_fsync		 95
+#define TARGET_NR_setpriority	 96
+#define TARGET_NR_socket		 97
+#define TARGET_NR_connect		 98
+#define TARGET_NR_accept		 99
+#define TARGET_NR_getpriority	100
+#define TARGET_NR_send		101
+#define TARGET_NR_recv		102
+#define TARGET_NR_sigreturn		103
+#define TARGET_NR_bind		104
+#define TARGET_NR_setsockopt		105
+#define TARGET_NR_listen		106
+#define TARGET_NR_osf_plock		107	/* not implemented */
+#define TARGET_NR_osf_old_sigvec	108	/* not implemented */
+#define TARGET_NR_osf_old_sigblock	109	/* not implemented */
+#define TARGET_NR_osf_old_sigsetmask	110	/* not implemented */
+#define TARGET_NR_sigsuspend		111
+#define TARGET_NR_osf_sigstack	112
+#define TARGET_NR_recvmsg		113
+#define TARGET_NR_sendmsg		114
+#define TARGET_NR_osf_old_vtrace	115	/* not implemented */
+#define TARGET_NR_osf_gettimeofday	116
+#define TARGET_NR_osf_getrusage	117
+#define TARGET_NR_getsockopt		118
+
+#define TARGET_NR_readv		120
+#define TARGET_NR_writev		121
+#define TARGET_NR_osf_settimeofday	122
+#define TARGET_NR_fchown		123
+#define TARGET_NR_fchmod		124
+#define TARGET_NR_recvfrom		125
+#define TARGET_NR_setreuid		126
+#define TARGET_NR_setregid		127
+#define TARGET_NR_rename		128
+#define TARGET_NR_truncate		129
+#define TARGET_NR_ftruncate		130
+#define TARGET_NR_flock		131
+#define TARGET_NR_setgid		132
+#define TARGET_NR_sendto		133
+#define TARGET_NR_shutdown		134
+#define TARGET_NR_socketpair		135
+#define TARGET_NR_mkdir		136
+#define TARGET_NR_rmdir		137
+#define TARGET_NR_osf_utimes		138
+#define TARGET_NR_osf_old_sigreturn	139	/* not implemented */
+#define TARGET_NR_osf_adjtime	140	/* not implemented */
+#define TARGET_NR_getpeername	141
+#define TARGET_NR_osf_gethostid	142	/* not implemented */
+#define TARGET_NR_osf_sethostid	143	/* not implemented */
+#define TARGET_NR_getrlimit		144
+#define TARGET_NR_setrlimit		145
+#define TARGET_NR_osf_old_killpg	146	/* not implemented */
+#define TARGET_NR_setsid		147
+#define TARGET_NR_quotactl		148
+#define TARGET_NR_osf_oldquota	149	/* not implemented */
+#define TARGET_NR_getsockname	150
+
+#define TARGET_NR_osf_pid_block	153	/* not implemented */
+#define TARGET_NR_osf_pid_unblock	154	/* not implemented */
+
+#define TARGET_NR_sigaction		156
+#define TARGET_NR_osf_sigwaitprim	157	/* not implemented */
+#define TARGET_NR_osf_nfssvc		158	/* not implemented */
+#define TARGET_NR_osf_getdirentries	159
+#define TARGET_NR_osf_statfs		160
+#define TARGET_NR_osf_fstatfs	161
+
+#define TARGET_NR_osf_asynch_daemon	163	/* not implemented */
+#define TARGET_NR_osf_getfh		164	/* not implemented */
+#define TARGET_NR_osf_getdomainname	165
+#define TARGET_NR_setdomainname	166
+
+#define TARGET_NR_osf_exportfs	169	/* not implemented */
+
+#define TARGET_NR_osf_alt_plock	181	/* not implemented */
+
+#define TARGET_NR_osf_getmnt		184	/* not implemented */
+
+#define TARGET_NR_osf_alt_sigpending	187	/* not implemented */
+#define TARGET_NR_osf_alt_setsid	188	/* not implemented */
+
+#define TARGET_NR_osf_swapon		199
+#define TARGET_NR_msgctl		200
+#define TARGET_NR_msgget		201
+#define TARGET_NR_msgrcv		202
+#define TARGET_NR_msgsnd		203
+#define TARGET_NR_semctl		204
+#define TARGET_NR_semget		205
+#define TARGET_NR_semop		206
+#define TARGET_NR_osf_utsname	207
+#define TARGET_NR_lchown		208
+#define TARGET_NR_osf_shmat		209
+#define TARGET_NR_shmctl		210
+#define TARGET_NR_shmdt		211
+#define TARGET_NR_shmget		212
+#define TARGET_NR_osf_mvalid		213	/* not implemented */
+#define TARGET_NR_osf_getaddressconf	214	/* not implemented */
+#define TARGET_NR_osf_msleep		215	/* not implemented */
+#define TARGET_NR_osf_mwakeup	216	/* not implemented */
+#define TARGET_NR_msync		217
+#define TARGET_NR_osf_signal		218	/* not implemented */
+#define TARGET_NR_osf_utc_gettime	219	/* not implemented */
+#define TARGET_NR_osf_utc_adjtime	220	/* not implemented */
+
+#define TARGET_NR_osf_security	222	/* not implemented */
+#define TARGET_NR_osf_kloadcall	223	/* not implemented */
+
+#define TARGET_NR_getpgid		233
+#define TARGET_NR_getsid		234
+#define TARGET_NR_sigaltstack	235
+#define TARGET_NR_osf_waitid		236	/* not implemented */
+#define TARGET_NR_osf_priocntlset	237	/* not implemented */
+#define TARGET_NR_osf_sigsendset	238	/* not implemented */
+#define TARGET_NR_osf_set_speculative	239	/* not implemented */
+#define TARGET_NR_osf_msfs_syscall	240	/* not implemented */
+#define TARGET_NR_osf_sysinfo	241
+#define TARGET_NR_osf_uadmin		242	/* not implemented */
+#define TARGET_NR_osf_fuser		243	/* not implemented */
+#define TARGET_NR_osf_proplist_syscall    244
+#define TARGET_NR_osf_ntp_adjtime	245	/* not implemented */
+#define TARGET_NR_osf_ntp_gettime	246	/* not implemented */
+#define TARGET_NR_osf_pathconf	247	/* not implemented */
+#define TARGET_NR_osf_fpathconf	248	/* not implemented */
+
+#define TARGET_NR_osf_uswitch	250	/* not implemented */
+#define TARGET_NR_osf_usleep_thread	251
+#define TARGET_NR_osf_audcntl	252	/* not implemented */
+#define TARGET_NR_osf_audgen		253	/* not implemented */
+#define TARGET_NR_sysfs		254
+#define TARGET_NR_osf_subsys_info	255	/* not implemented */
+#define TARGET_NR_osf_getsysinfo	256
+#define TARGET_NR_osf_setsysinfo	257
+#define TARGET_NR_osf_afs_syscall	258	/* not implemented */
+#define TARGET_NR_osf_swapctl	259	/* not implemented */
+#define TARGET_NR_osf_memcntl	260	/* not implemented */
+#define TARGET_NR_osf_fdatasync	261	/* not implemented */
+
+
+/*
+ * Linux-specific system calls begin at 300
+ */
+#define TARGET_NR_bdflush		300
+#define TARGET_NR_sethae		301
+#define TARGET_NR_mount		302
+#define TARGET_NR_old_adjtimex	303
+#define TARGET_NR_swapoff		304
+#define TARGET_NR_getdents		305
+#define TARGET_NR_create_module	306
+#define TARGET_NR_init_module	307
+#define TARGET_NR_delete_module	308
+#define TARGET_NR_get_kernel_syms	309
+#define TARGET_NR_syslog		310
+#define TARGET_NR_reboot		311
+#define TARGET_NR_clone		312
+#define TARGET_NR_uselib		313
+#define TARGET_NR_mlock		314
+#define TARGET_NR_munlock		315
+#define TARGET_NR_mlockall		316
+#define TARGET_NR_munlockall		317
+#define TARGET_NR_sysinfo		318
+#define TARGET_NR__sysctl		319
+/* 320 was sys_idle.  */
+#define TARGET_NR_oldumount		321
+#define TARGET_NR_swapon		322
+#define TARGET_NR_times		323
+#define TARGET_NR_personality	324
+#define TARGET_NR_setfsuid		325
+#define TARGET_NR_setfsgid		326
+#define TARGET_NR_ustat		327
+#define TARGET_NR_statfs		328
+#define TARGET_NR_fstatfs		329
+#define TARGET_NR_sched_setparam		330
+#define TARGET_NR_sched_getparam		331
+#define TARGET_NR_sched_setscheduler		332
+#define TARGET_NR_sched_getscheduler		333
+#define TARGET_NR_sched_yield		334
+#define TARGET_NR_sched_get_priority_max	335
+#define TARGET_NR_sched_get_priority_min	336
+#define TARGET_NR_sched_rr_get_interval	337
+#define TARGET_NR_afs_syscall		338
+#define TARGET_NR_uname			339
+#define TARGET_NR_nanosleep			340
+#define TARGET_NR_mremap			341
+#define TARGET_NR_nfsservctl			342
+#define TARGET_NR_setresuid			343
+#define TARGET_NR_getresuid			344
+#define TARGET_NR_pciconfig_read		345
+#define TARGET_NR_pciconfig_write		346
+#define TARGET_NR_query_module		347
+#define TARGET_NR_prctl			348
+#define TARGET_NR_pread64			349
+#define TARGET_NR_pwrite64			350
+#define TARGET_NR_rt_sigreturn		351
+#define TARGET_NR_rt_sigaction		352
+#define TARGET_NR_rt_sigprocmask		353
+#define TARGET_NR_rt_sigpending		354
+#define TARGET_NR_rt_sigtimedwait		355
+#define TARGET_NR_rt_sigqueueinfo		356
+#define TARGET_NR_rt_sigsuspend		357
+#define TARGET_NR_select			358
+#define TARGET_NR_gettimeofday		359
+#define TARGET_NR_settimeofday		360
+#define TARGET_NR_getitimer			361
+#define TARGET_NR_setitimer			362
+#define TARGET_NR_utimes			363
+#define TARGET_NR_getrusage			364
+#define TARGET_NR_wait4			365
+#define TARGET_NR_adjtimex			366
+#define TARGET_NR_getcwd			367
+#define TARGET_NR_capget			368
+#define TARGET_NR_capset			369
+#define TARGET_NR_sendfile			370
+#define TARGET_NR_setresgid			371
+#define TARGET_NR_getresgid			372
+#define TARGET_NR_dipc			373
+#define TARGET_NR_pivot_root			374
+#define TARGET_NR_mincore			375
+#define TARGET_NR_pciconfig_iobase		376
+#define TARGET_NR_getdents64			377
+#define TARGET_NR_gettid			378
+#define TARGET_NR_readahead			379
+/* 380 is unused */
+#define TARGET_NR_tkill			381
+#define TARGET_NR_setxattr			382
+#define TARGET_NR_lsetxattr			383
+#define TARGET_NR_fsetxattr			384
+#define TARGET_NR_getxattr			385
+#define TARGET_NR_lgetxattr			386
+#define TARGET_NR_fgetxattr			387
+#define TARGET_NR_listxattr			388
+#define TARGET_NR_llistxattr			389
+#define TARGET_NR_flistxattr			390
+#define TARGET_NR_removexattr		391
+#define TARGET_NR_lremovexattr		392
+#define TARGET_NR_fremovexattr		393
+#define TARGET_NR_futex			394
+#define TARGET_NR_sched_setaffinity		395
+#define TARGET_NR_sched_getaffinity		396
+#define TARGET_NR_tuxcall			397
+#define TARGET_NR_io_setup			398
+#define TARGET_NR_io_destroy			399
+#define TARGET_NR_io_getevents		400
+#define TARGET_NR_io_submit			401
+#define TARGET_NR_io_cancel			402
+#define TARGET_NR_exit_group			405
+#define TARGET_NR_lookup_dcookie		406
+#define TARGET_NR_sys_epoll_create		407
+#define TARGET_NR_sys_epoll_ctl		408
+#define TARGET_NR_sys_epoll_wait		409
+#define TARGET_NR_remap_file_pages		410
+#define TARGET_NR_set_tid_address		411
+#define TARGET_NR_restart_syscall		412
+#define TARGET_NR_fadvise64			413
+#define TARGET_NR_timer_create		414
+#define TARGET_NR_timer_settime		415
+#define TARGET_NR_timer_gettime		416
+#define TARGET_NR_timer_getoverrun		417
+#define TARGET_NR_timer_delete		418
+#define TARGET_NR_clock_settime		419
+#define TARGET_NR_clock_gettime		420
+#define TARGET_NR_clock_getres		421
+#define TARGET_NR_clock_nanosleep		422
+#define TARGET_NR_semtimedop			423
+#define TARGET_NR_tgkill			424
+#define TARGET_NR_stat64			425
+#define TARGET_NR_lstat64			426
+#define TARGET_NR_fstat64			427
+#define TARGET_NR_vserver			428
+#define TARGET_NR_mbind			429
+#define TARGET_NR_get_mempolicy		430
+#define TARGET_NR_set_mempolicy		431
+#define TARGET_NR_mq_open			432
+#define TARGET_NR_mq_unlink			433
+#define TARGET_NR_mq_timedsend		434
+#define TARGET_NR_mq_timedreceive		435
+#define TARGET_NR_mq_notify			436
+#define TARGET_NR_mq_getsetattr		437
+#define TARGET_NR_waitid			438
+#define TARGET_NR_add_key			439
+#define TARGET_NR_request_key		440
+#define TARGET_NR_keyctl			441
+#define TARGET_NR_ioprio_set			442
+#define TARGET_NR_ioprio_get			443
+#define TARGET_NR_inotify_init		444
+#define TARGET_NR_inotify_add_watch		445
+#define TARGET_NR_inotify_rm_watch		446
+#define TARGET_NR_fdatasync			447
+#define TARGET_NR_kexec_load			448
+#define TARGET_NR_migrate_pages		449
+#define TARGET_NR_openat			450
+#define TARGET_NR_mkdirat			451
+#define TARGET_NR_mknodat			452
+#define TARGET_NR_fchownat			453
+#define TARGET_NR_futimesat			454
+#define TARGET_NR_fstatat64			455
+#define TARGET_NR_unlinkat			456
+#define TARGET_NR_renameat			457
+#define TARGET_NR_linkat			458
+#define TARGET_NR_symlinkat			459
+#define TARGET_NR_readlinkat			460
+#define TARGET_NR_fchmodat			461
+#define TARGET_NR_faccessat			462
+#define TARGET_NR_pselect6			463
+#define TARGET_NR_ppoll			464
+#define TARGET_NR_unshare			465
+#define TARGET_NR_set_robust_list		466
+#define TARGET_NR_get_robust_list		467
+#define TARGET_NR_splice			468
+#define TARGET_NR_sync_file_range		469
+#define TARGET_NR_tee			470
+#define TARGET_NR_vmsplice			471
+#define TARGET_NR_move_pages			472
+#define TARGET_NR_getcpu			473
+#define TARGET_NR_epoll_pwait		474
+#define TARGET_NR_utimensat			475
+#define TARGET_NR_signalfd			476
+#define TARGET_NR_timerfd			477
+#define TARGET_NR_eventfd			478
+#define TARGET_NR_recvmmsg                      479
+#define TARGET_NR_fallocate                     480
+#define TARGET_NR_timerfd_create                481
+#define TARGET_NR_timerfd_settime               482
+#define TARGET_NR_timerfd_gettime               483
+#define TARGET_NR_signalfd4                     484
+#define TARGET_NR_eventfd2                      485
+#define TARGET_NR_epoll_create1                 486
+#define TARGET_NR_dup3                          487
+#define TARGET_NR_pipe2                         488
+#define TARGET_NR_inotify_init1                 489
+#define TARGET_NR_preadv                        490
+#define TARGET_NR_pwritev                       491
+#define TARGET_NR_rt_tgsigqueueinfo             492
+#define TARGET_NR_perf_event_open               493
+#define TARGET_NR_fanotify_init                 494
+#define TARGET_NR_fanotify_mark                 495
+#define TARGET_NR_prlimit64                     496
+#define TARGET_NR_name_to_handle_at             497
+#define TARGET_NR_open_by_handle_at             498
+#define TARGET_NR_clock_adjtime                 499
+#define TARGET_NR_syncfs                        500
diff --git a/qemu-0.15.x/linux-user/alpha/target_signal.h b/qemu-0.15.x/linux-user/alpha/target_signal.h
new file mode 100644
index 0000000..94f15f6
--- /dev/null
+++ b/qemu-0.15.x/linux-user/alpha/target_signal.h
@@ -0,0 +1,56 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state)
+{
+    return state->ir[IR_SP];
+}
+
+/* From <asm/gentrap.h>.  */
+#define TARGET_GEN_INTOVF      -1      /* integer overflow */
+#define TARGET_GEN_INTDIV      -2      /* integer division by zero */
+#define TARGET_GEN_FLTOVF      -3      /* fp overflow */
+#define TARGET_GEN_FLTDIV      -4      /* fp division by zero */
+#define TARGET_GEN_FLTUND      -5      /* fp underflow */
+#define TARGET_GEN_FLTINV      -6      /* invalid fp operand */
+#define TARGET_GEN_FLTINE      -7      /* inexact fp operand */
+#define TARGET_GEN_DECOVF      -8      /* decimal overflow (for COBOL??) */
+#define TARGET_GEN_DECDIV      -9      /* decimal division by zero */
+#define TARGET_GEN_DECINV      -10     /* invalid decimal operand */
+#define TARGET_GEN_ROPRAND     -11     /* reserved operand */
+#define TARGET_GEN_ASSERTERR   -12     /* assertion error */
+#define TARGET_GEN_NULPTRERR   -13     /* null pointer error */
+#define TARGET_GEN_STKOVF      -14     /* stack overflow */
+#define TARGET_GEN_STRLENERR   -15     /* string length error */
+#define TARGET_GEN_SUBSTRERR   -16     /* substring error */
+#define TARGET_GEN_RANGERR     -17     /* range error */
+#define TARGET_GEN_SUBRNG      -18
+#define TARGET_GEN_SUBRNG1     -19
+#define TARGET_GEN_SUBRNG2     -20
+#define TARGET_GEN_SUBRNG3     -21
+#define TARGET_GEN_SUBRNG4     -22
+#define TARGET_GEN_SUBRNG5     -23
+#define TARGET_GEN_SUBRNG6     -24
+#define TARGET_GEN_SUBRNG7     -25
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/alpha/termbits.h b/qemu-0.15.x/linux-user/alpha/termbits.h
new file mode 100644
index 0000000..6406b6a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/alpha/termbits.h
@@ -0,0 +1,264 @@
+typedef unsigned char	target_cc_t;
+typedef unsigned int	target_speed_t;
+typedef unsigned int	target_tcflag_t;
+
+#define TARGET_NCCS 19
+struct target_termios {
+	target_tcflag_t c_iflag;		/* input mode flags */
+	target_tcflag_t c_oflag;		/* output mode flags */
+	target_tcflag_t c_cflag;		/* control mode flags */
+	target_tcflag_t c_lflag;		/* local mode flags */
+	target_cc_t c_cc[TARGET_NCCS];		/* control characters */
+	target_cc_t c_line;			/* line discipline (== c_cc[19]) */
+	target_speed_t c_ispeed;		/* input speed */
+	target_speed_t c_ospeed;		/* output speed */
+};
+
+/* c_cc characters */
+#define TARGET_VEOF 0
+#define TARGET_VEOL 1
+#define TARGET_VEOL2 2
+#define TARGET_VERASE 3
+#define TARGET_VWERASE 4
+#define TARGET_VKILL 5
+#define TARGET_VREPRINT 6
+#define TARGET_VSWTC 7
+#define TARGET_VINTR 8
+#define TARGET_VQUIT 9
+#define TARGET_VSUSP 10
+#define TARGET_VSTART 12
+#define TARGET_VSTOP 13
+#define TARGET_VLNEXT 14
+#define TARGET_VDISCARD 15
+#define TARGET_VMIN 16
+#define TARGET_VTIME 17
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IXON	0001000
+#define TARGET_IXOFF	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IUCLC	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_ONLCR	0000002
+#define TARGET_OLCUC	0000004
+
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+
+#define TARGET_OFILL	00000100
+#define TARGET_OFDEL	00000200
+#define TARGET_NLDLY	00001400
+#define   TARGET_NL0	00000000
+#define   TARGET_NL1	00000400
+#define   TARGET_NL2	00001000
+#define   TARGET_NL3	00001400
+#define TARGET_TABDLY	00006000
+#define   TARGET_TAB0	00000000
+#define   TARGET_TAB1	00002000
+#define   TARGET_TAB2	00004000
+#define   TARGET_TAB3	00006000
+#define TARGET_CRDLY	00030000
+#define   TARGET_CR0	00000000
+#define   TARGET_CR1	00010000
+#define   TARGET_CR2	00020000
+#define   TARGET_CR3	00030000
+#define TARGET_FFDLY	00040000
+#define   TARGET_FF0	00000000
+#define   TARGET_FF1	00040000
+#define TARGET_BSDLY	00100000
+#define   TARGET_BS0	00000000
+#define   TARGET_BS1	00100000
+#define TARGET_VTDLY	00200000
+#define   TARGET_VT0	00000000
+#define   TARGET_VT1	00200000
+#define TARGET_XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0000037
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define  TARGET_B57600   00020
+#define  TARGET_B115200  00021
+#define  TARGET_B230400  00022
+#define  TARGET_B460800  00023
+#define  TARGET_B500000  00024
+#define  TARGET_B576000  00025
+#define  TARGET_B921600  00026
+#define TARGET_B1000000  00027
+#define TARGET_B1152000  00030
+#define TARGET_B1500000  00031
+#define TARGET_B2000000  00032
+#define TARGET_B2500000  00033
+#define TARGET_B3000000  00034
+#define TARGET_B3500000  00035
+#define TARGET_B4000000  00036
+
+#define TARGET_CSIZE	00001400
+#define   TARGET_CS5	00000000
+#define   TARGET_CS6	00000400
+#define   TARGET_CS7	00001000
+#define   TARGET_CS8	00001400
+
+#define TARGET_CSTOPB	00002000
+#define TARGET_CREAD	00004000
+#define TARGET_PARENB	00010000
+#define TARGET_PARODD	00020000
+#define TARGET_HUPCL	00040000
+
+#define TARGET_CLOCAL	00100000
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000080
+#define TARGET_ICANON	0x00000100
+#define TARGET_XCASE	0x00004000
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000002
+#define TARGET_ECHOK	0x00000004
+#define TARGET_ECHONL	0x00000010
+#define TARGET_NOFLSH	0x80000000
+#define TARGET_TOSTOP	0x00400000
+#define TARGET_ECHOCTL	0x00000040
+#define TARGET_ECHOPRT	0x00000020
+#define TARGET_ECHOKE	0x00000001
+#define TARGET_FLUSHO	0x00800000
+#define TARGET_PENDIN	0x20000000
+#define TARGET_IEXTEN	0x00000400
+
+#define TARGET_FIOCLEX		TARGET_IO('f', 1)
+#define TARGET_FIONCLEX	TARGET_IO('f', 2)
+#define TARGET_FIOASYNC	TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO		TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD	TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ		FIONREAD
+#define TARGET_FIOQSIZE	TARGET_IOR('f', 128, loff_t)
+
+#define TARGET_TIOCGETP	TARGET_IOR('t', 8, struct target_sgttyb)
+#define TARGET_TIOCSETP	TARGET_IOW('t', 9, struct target_sgttyb)
+#define TARGET_TIOCSETN	TARGET_IOW('t', 10, struct target_sgttyb)	/* TIOCSETP wo flush */
+
+#define TARGET_TIOCSETC	TARGET_IOW('t', 17, struct target_tchars)
+#define TARGET_TIOCGETC	TARGET_IOR('t', 18, struct target_tchars)
+#define TARGET_TCGETS		TARGET_IOR('t', 19, struct target_termios)
+#define TARGET_TCSETS		TARGET_IOW('t', 20, struct target_termios)
+#define TARGET_TCSETSW		TARGET_IOW('t', 21, struct target_termios)
+#define TARGET_TCSETSF		TARGET_IOW('t', 22, struct target_termios)
+
+#define TARGET_TCGETA		TARGET_IOR('t', 23, struct target_termio)
+#define TARGET_TCSETA		TARGET_IOW('t', 24, struct target_termio)
+#define TARGET_TCSETAW		TARGET_IOW('t', 25, struct target_termio)
+#define TARGET_TCSETAF		TARGET_IOW('t', 28, struct target_termio)
+
+#define TARGET_TCSBRK		TARGET_IO('t', 29)
+#define TARGET_TCXONC		TARGET_IO('t', 30)
+#define TARGET_TCFLSH		TARGET_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct target_winsize)
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct target_winsize)
+#define	TARGET_TIOCSTART	TARGET_IO('t', 110)		/* start output, like ^Q */
+#define	TARGET_TIOCSTOP	TARGET_IO('t', 111)		/* stop output, like ^S */
+#define TARGET_TIOCOUTQ        TARGET_IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCGLTC	TARGET_IOR('t', 116, struct target_ltchars)
+#define TARGET_TIOCSLTC	TARGET_IOW('t', 117, struct target_ltchars)
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+# define TARGET_TIOCM_LE	0x001
+# define TARGET_TIOCM_DTR	0x002
+# define TARGET_TIOCM_RTS	0x004
+# define TARGET_TIOCM_ST	0x008
+# define TARGET_TIOCM_SR	0x010
+# define TARGET_TIOCM_CTS	0x020
+# define TARGET_TIOCM_CAR	0x040
+# define TARGET_TIOCM_RNG	0x080
+# define TARGET_TIOCM_DSR	0x100
+# define TARGET_TIOCM_CD	TIOCM_CAR
+# define TARGET_TIOCM_RI	TIOCM_RNG
+# define TARGET_TIOCM_OUT1	0x2000
+# define TARGET_TIOCM_OUT2	0x4000
+# define TARGET_TIOCM_LOOP	0x8000
+
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+# define TARGET_TIOCPKT_DATA		 0
+# define TARGET_TIOCPKT_FLUSHREAD	 1
+# define TARGET_TIOCPKT_FLUSHWRITE	 2
+# define TARGET_TIOCPKT_STOP		 4
+# define TARGET_TIOCPKT_START		 8
+# define TARGET_TIOCPKT_NOSTOP		16
+# define TARGET_TIOCPKT_DOSTOP		32
+
+
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x545F  /* Set Hayes ESP configuration */
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/double_cpdo.c b/qemu-0.15.x/linux-user/arm/nwfpe/double_cpdo.c
new file mode 100644
index 0000000..8e9b28f
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/double_cpdo.c
@@ -0,0 +1,295 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+
+float64 float64_exp(float64 Fm);
+float64 float64_ln(float64 Fm);
+float64 float64_sin(float64 rFm);
+float64 float64_cos(float64 rFm);
+float64 float64_arcsin(float64 rFm);
+float64 float64_arctan(float64 rFm);
+float64 float64_log(float64 rFm);
+float64 float64_tan(float64 rFm);
+float64 float64_arccos(float64 rFm);
+float64 float64_pow(float64 rFn,float64 rFm);
+float64 float64_pol(float64 rFn,float64 rFm);
+
+unsigned int DoubleCPDO(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   float64 rFm, rFn = float64_zero;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   //printk("DoubleCPDO(0x%08x)\n",opcode);
+
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getDoubleConstant(Fm);
+   }
+   else
+   {
+     switch (fpa11->fType[Fm])
+     {
+        case typeSingle:
+          rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
+        break;
+
+        case typeDouble:
+          rFm = fpa11->fpreg[Fm].fDouble;
+          break;
+
+        case typeExtended:
+            // !! patb
+	    //printk("not implemented! why not?\n");
+            //!! ScottB
+            // should never get here, if extended involved
+            // then other operand should be promoted then
+            // ExtendedCPDO called.
+            break;
+
+        default: return 0;
+     }
+   }
+
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fType[Fn])
+      {
+        case typeSingle:
+          rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
+        break;
+
+        case typeDouble:
+          rFn = fpa11->fpreg[Fn].fDouble;
+        break;
+
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn, &fpa11->fp_status);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fDouble = rFm;
+      break;
+
+      case MNF_CODE:
+      {
+         unsigned int *p = (unsigned int*)&rFm;
+#ifdef HOST_WORDS_BIGENDIAN
+         p[0] ^= 0x80000000;
+#else
+         p[1] ^= 0x80000000;
+#endif
+         fpa11->fpreg[Fd].fDouble = rFm;
+      }
+      break;
+
+      case ABS_CODE:
+      {
+         unsigned int *p = (unsigned int*)&rFm;
+#ifdef HOST_WORDS_BIGENDIAN
+         p[0] &= 0x7fffffff;
+#else
+         p[1] &= 0x7fffffff;
+#endif
+         fpa11->fpreg[Fd].fDouble = rFm;
+      }
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm, &fpa11->fp_status);
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+
+      default:
+      {
+        nRc = 0;
+      }
+   }
+
+   if (0 != nRc) fpa11->fType[Fd] = typeDouble;
+   return nRc;
+}
+
+#if 0
+float64 float64_exp(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_ln(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_sin(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_cos(float64 rFm)
+{
+   return rFm;
+   //series
+}
+
+#if 0
+float64 float64_arcsin(float64 rFm)
+{
+//series
+}
+
+float64 float64_arctan(float64 rFm)
+{
+  //series
+}
+#endif
+
+float64 float64_log(float64 rFm)
+{
+  return float64_div(float64_ln(rFm),getDoubleConstant(7));
+}
+
+float64 float64_tan(float64 rFm)
+{
+  return float64_div(float64_sin(rFm),float64_cos(rFm));
+}
+
+float64 float64_arccos(float64 rFm)
+{
+return rFm;
+   //return float64_sub(halfPi,float64_arcsin(rFm));
+}
+
+float64 float64_pow(float64 rFn,float64 rFm)
+{
+  return float64_exp(float64_mul(rFm,float64_ln(rFn)));
+}
+
+float64 float64_pol(float64 rFn,float64 rFm)
+{
+  return float64_arctan(float64_div(rFn,rFm));
+}
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/extended_cpdo.c b/qemu-0.15.x/linux-user/arm/nwfpe/extended_cpdo.c
new file mode 100644
index 0000000..880ce03
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/extended_cpdo.c
@@ -0,0 +1,272 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+
+floatx80 floatx80_exp(floatx80 Fm);
+floatx80 floatx80_ln(floatx80 Fm);
+floatx80 floatx80_sin(floatx80 rFm);
+floatx80 floatx80_cos(floatx80 rFm);
+floatx80 floatx80_arcsin(floatx80 rFm);
+floatx80 floatx80_arctan(floatx80 rFm);
+floatx80 floatx80_log(floatx80 rFm);
+floatx80 floatx80_tan(floatx80 rFm);
+floatx80 floatx80_arccos(floatx80 rFm);
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm);
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm);
+
+unsigned int ExtendedCPDO(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   floatx80 rFm, rFn;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   //printk("ExtendedCPDO(0x%08x)\n",opcode);
+
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getExtendedConstant(Fm);
+   }
+   else
+   {
+     switch (fpa11->fType[Fm])
+     {
+        case typeSingle:
+          rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
+        break;
+
+        case typeDouble:
+          rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
+        break;
+
+        case typeExtended:
+          rFm = fpa11->fpreg[Fm].fExtended;
+        break;
+
+        default: return 0;
+     }
+   }
+
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fType[Fn])
+      {
+        case typeSingle:
+          rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
+        break;
+
+        case typeDouble:
+          rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
+        break;
+
+        case typeExtended:
+          rFn = fpa11->fpreg[Fn].fExtended;
+        break;
+
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fExtended = rFm;
+      break;
+
+      case MNF_CODE:
+         rFm.high ^= 0x8000;
+         fpa11->fpreg[Fd].fExtended = rFm;
+      break;
+
+      case ABS_CODE:
+         rFm.high &= 0x7fff;
+         fpa11->fpreg[Fd].fExtended = rFm;
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status);
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+
+      default:
+      {
+        nRc = 0;
+      }
+   }
+
+   if (0 != nRc) fpa11->fType[Fd] = typeExtended;
+   return nRc;
+}
+
+#if 0
+floatx80 floatx80_exp(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_ln(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_sin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_cos(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arcsin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arctan(floatx80 rFm)
+{
+  //series
+}
+
+floatx80 floatx80_log(floatx80 rFm)
+{
+  return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7));
+}
+
+floatx80 floatx80_tan(floatx80 rFm)
+{
+  return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm));
+}
+
+floatx80 floatx80_arccos(floatx80 rFm)
+{
+   //return floatx80_sub(halfPi,floatx80_arcsin(rFm));
+}
+
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm)
+{
+  return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn)));
+}
+
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm)
+{
+  return floatx80_arctan(floatx80_div(rFn,rFm));
+}
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.c b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.c
new file mode 100644
index 0000000..eebd93f
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.c
@@ -0,0 +1,237 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+
+#include "fpopcode.h"
+
+//#include "fpmodule.h"
+//#include "fpmodule.inl"
+
+//#include <asm/system.h>
+
+#include <stdio.h>
+
+FPA11* qemufpa = NULL;
+CPUARMState* user_registers;
+
+/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
+void resetFPA11(void)
+{
+  int i;
+  FPA11 *fpa11 = GET_FPA11();
+
+  /* initialize the register type array */
+  for (i=0;i<=7;i++)
+  {
+    fpa11->fType[i] = typeNone;
+  }
+
+  /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
+  fpa11->fpsr = FP_EMULATOR | BIT_AC;
+
+  /* FPCR: set SB, AB and DA bits, clear all others */
+#ifdef MAINTAIN_FPCR
+  fpa11->fpcr = MASK_RESET;
+#endif
+}
+
+void SetRoundingMode(const unsigned int opcode)
+{
+    int rounding_mode;
+   FPA11 *fpa11 = GET_FPA11();
+
+#ifdef MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_MODE;
+#endif
+   switch (opcode & MASK_ROUNDING_MODE)
+   {
+      default:
+      case ROUND_TO_NEAREST:
+         rounding_mode = float_round_nearest_even;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_NEAREST;
+#endif
+      break;
+
+      case ROUND_TO_PLUS_INFINITY:
+         rounding_mode = float_round_up;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
+#endif
+      break;
+
+      case ROUND_TO_MINUS_INFINITY:
+         rounding_mode = float_round_down;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
+#endif
+      break;
+
+      case ROUND_TO_ZERO:
+         rounding_mode = float_round_to_zero;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_ZERO;
+#endif
+      break;
+  }
+   set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
+}
+
+void SetRoundingPrecision(const unsigned int opcode)
+{
+    int rounding_precision;
+   FPA11 *fpa11 = GET_FPA11();
+#ifdef MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
+#endif
+   switch (opcode & MASK_ROUNDING_PRECISION)
+   {
+      case ROUND_SINGLE:
+         rounding_precision = 32;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_SINGLE;
+#endif
+      break;
+
+      case ROUND_DOUBLE:
+         rounding_precision = 64;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_DOUBLE;
+#endif
+      break;
+
+      case ROUND_EXTENDED:
+         rounding_precision = 80;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_EXTENDED;
+#endif
+      break;
+
+      default: rounding_precision = 80;
+  }
+   set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
+}
+
+/* Emulate the instruction in the opcode. */
+/* ??? This is not thread safe.  */
+unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs)
+{
+  unsigned int nRc = 0;
+//  unsigned long flags;
+  FPA11 *fpa11;
+//  save_flags(flags); sti();
+
+  qemufpa=qfpa;
+  user_registers=qregs;
+
+#if 0
+  fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
+          opcode, qregs[ARM_REG_PC]);
+#endif
+  fpa11 = GET_FPA11();
+
+  if (fpa11->initflag == 0)		/* good place for __builtin_expect */
+  {
+    resetFPA11();
+    SetRoundingMode(ROUND_TO_NEAREST);
+    SetRoundingPrecision(ROUND_EXTENDED);
+    fpa11->initflag = 1;
+  }
+
+  set_float_exception_flags(0, &fpa11->fp_status);
+
+  if (TEST_OPCODE(opcode,MASK_CPRT))
+  {
+    //fprintf(stderr,"emulating CPRT\n");
+    /* Emulate conversion opcodes. */
+    /* Emulate register transfer opcodes. */
+    /* Emulate comparison opcodes. */
+    nRc = EmulateCPRT(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDO))
+  {
+    //fprintf(stderr,"emulating CPDO\n");
+    /* Emulate monadic arithmetic opcodes. */
+    /* Emulate dyadic arithmetic opcodes. */
+    nRc = EmulateCPDO(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDT))
+  {
+    //fprintf(stderr,"emulating CPDT\n");
+    /* Emulate load/store opcodes. */
+    /* Emulate load/store multiple opcodes. */
+    nRc = EmulateCPDT(opcode);
+  }
+  else
+  {
+    /* Invalid instruction detected.  Return FALSE. */
+    nRc = 0;
+  }
+
+//  restore_flags(flags);
+  if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status))
+  {
+    //printf("fef 0x%x\n",float_exception_flags);
+    nRc = -get_float_exception_flags(&fpa11->fp_status);
+  }
+
+  //printf("returning %d\n",nRc);
+  return(nRc);
+}
+
+#if 0
+unsigned int EmulateAll1(unsigned int opcode)
+{
+  switch ((opcode >> 24) & 0xf)
+  {
+     case 0xc:
+     case 0xd:
+       if ((opcode >> 20) & 0x1)
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformLDF(opcode); break;
+             case 0x2: return PerformLFM(opcode); break;
+             default: return 0;
+          }
+       }
+       else
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformSTF(opcode); break;
+             case 0x2: return PerformSFM(opcode); break;
+             default: return 0;
+          }
+      }
+     break;
+
+     case 0xe:
+       if (opcode & 0x10)
+         return EmulateCPDO(opcode);
+       else
+         return EmulateCPRT(opcode);
+     break;
+
+     default: return 0;
+  }
+}
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.h b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.h
new file mode 100644
index 0000000..002b3cb
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.h
@@ -0,0 +1,130 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.com, 1998-1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FPA11_H__
+#define __FPA11_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <cpu.h>
+
+#define GET_FPA11() (qemufpa)
+
+/*
+ * The processes registers are always at the very top of the 8K
+ * stack+task struct.  Use the same method as 'current' uses to
+ * reach them.
+ */
+extern CPUARMState *user_registers;
+
+#define GET_USERREG() (user_registers)
+
+/* Need task_struct */
+//#include <linux/sched.h>
+
+/* includes */
+#include "fpsr.h"		/* FP control and status register definitions */
+#include "softfloat.h"
+
+#define		typeNone		0x00
+#define		typeSingle		0x01
+#define		typeDouble		0x02
+#define		typeExtended		0x03
+
+/*
+ * This must be no more and no less than 12 bytes.
+ */
+typedef union tagFPREG {
+   floatx80 fExtended;
+   float64  fDouble;
+   float32  fSingle;
+} FPREG;
+
+/*
+ * FPA11 device model.
+ *
+ * This structure is exported to user space.  Do not re-order.
+ * Only add new stuff to the end, and do not change the size of
+ * any element.  Elements of this structure are used by user
+ * space, and must match struct user_fp in include/asm-arm/user.h.
+ * We include the byte offsets below for documentation purposes.
+ *
+ * The size of this structure and FPREG are checked by fpmodule.c
+ * on initialisation.  If the rules have been broken, NWFPE will
+ * not initialise.
+ */
+typedef struct tagFPA11 {
+/*   0 */  FPREG fpreg[8];		/* 8 floating point registers */
+/*  96 */  FPSR fpsr;			/* floating point status register */
+/* 100 */  FPCR fpcr;			/* floating point control register */
+/* 104 */  unsigned char fType[8];	/* type of floating point value held in
+					   floating point registers.  One of none
+					   single, double or extended. */
+/* 112 */  int initflag;		/* this is special.  The kernel guarantees
+					   to set it to 0 when a thread is launched,
+					   so we can use it to detect whether this
+					   instance of the emulator needs to be
+					   initialised. */
+    float_status fp_status;      /* QEMU float emulator status */
+} FPA11;
+
+extern FPA11* qemufpa;
+
+void resetFPA11(void);
+void SetRoundingMode(const unsigned int);
+void SetRoundingPrecision(const unsigned int);
+
+static inline unsigned int readRegister(unsigned int reg)
+{
+    return (user_registers->regs[(reg)]);
+}
+
+static inline void writeRegister(unsigned int x, unsigned int y)
+{
+#if 0
+	printf("writing %d to r%d\n",y,x);
+#endif
+        user_registers->regs[(x)]=(y);
+}
+
+static inline void writeConditionCodes(unsigned int x)
+{
+        cpsr_write(user_registers,x,CPSR_NZCV);
+}
+
+#define ARM_REG_PC 15
+
+unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs);
+
+unsigned int EmulateCPDO(const unsigned int);
+unsigned int EmulateCPDT(const unsigned int);
+unsigned int EmulateCPRT(const unsigned int);
+
+unsigned int SingleCPDO(const unsigned int opcode);
+unsigned int DoubleCPDO(const unsigned int opcode);
+unsigned int ExtendedCPDO(const unsigned int opcode);
+
+
+/* included only for get_user/put_user macros */
+#include "qemu.h"
+
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.inl b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.inl
new file mode 100644
index 0000000..6c6f380
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11.inl
@@ -0,0 +1,50 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+
+/* Read and write floating point status register */
+static inline unsigned int readFPSR(void)
+{
+  FPA11 *fpa11 = GET_FPA11();
+  return(fpa11->fpsr);
+}
+
+static inline void writeFPSR(FPSR reg)
+{
+  FPA11 *fpa11 = GET_FPA11();
+  /* the sysid byte in the status register is readonly */
+  fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID);
+}
+
+/* Read and write floating point control register */
+static inline FPCR readFPCR(void)
+{
+  FPA11 *fpa11 = GET_FPA11();
+  /* clear SB, AB and DA bits before returning FPCR */
+  return(fpa11->fpcr & ~MASK_RFC);
+}
+
+static inline void writeFPCR(FPCR reg)
+{
+  FPA11 *fpa11 = GET_FPA11();
+  fpa11->fpcr &= ~MASK_WFC;		/* clear SB, AB and DA bits */
+  fpa11->fpcr |= (reg & MASK_WFC);	/* write SB, AB and DA bits */
+}
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdo.c b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdo.c
new file mode 100644
index 0000000..5f4a6a4
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdo.c
@@ -0,0 +1,112 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "fpopcode.h"
+
+unsigned int EmulateCPDO(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int Fd, nType, nDest, nRc = 1;
+
+   //printk("EmulateCPDO(0x%08x)\n",opcode);
+
+   /* Get the destination size.  If not valid let Linux perform
+      an invalid instruction trap. */
+   nDest = getDestinationSize(opcode);
+   if (typeNone == nDest) return 0;
+
+   SetRoundingMode(opcode);
+
+   /* Compare the size of the operands in Fn and Fm.
+      Choose the largest size and perform operations in that size,
+      in order to make use of all the precision of the operands.
+      If Fm is a constant, we just grab a constant of a size
+      matching the size of the operand in Fn. */
+   if (MONADIC_INSTRUCTION(opcode))
+     nType = nDest;
+   else
+     nType = fpa11->fType[getFn(opcode)];
+
+   if (!CONSTANT_FM(opcode))
+   {
+     register unsigned int Fm = getFm(opcode);
+     if (nType < fpa11->fType[Fm])
+     {
+        nType = fpa11->fType[Fm];
+     }
+   }
+
+   switch (nType)
+   {
+      case typeSingle   : nRc = SingleCPDO(opcode);   break;
+      case typeDouble   : nRc = DoubleCPDO(opcode);   break;
+      case typeExtended : nRc = ExtendedCPDO(opcode); break;
+      default           : nRc = 0;
+   }
+
+   /* If the operation succeeded, check to see if the result in the
+      destination register is the correct size.  If not force it
+      to be. */
+   Fd = getFd(opcode);
+   nType = fpa11->fType[Fd];
+   if ((0 != nRc) && (nDest != nType))
+   {
+     switch (nDest)
+     {
+       case typeSingle:
+       {
+         if (typeDouble == nType)
+           fpa11->fpreg[Fd].fSingle =
+              float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
+         else
+           fpa11->fpreg[Fd].fSingle =
+              floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
+       }
+       break;
+
+       case typeDouble:
+       {
+         if (typeSingle == nType)
+           fpa11->fpreg[Fd].fDouble =
+              float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
+         else
+           fpa11->fpreg[Fd].fDouble =
+              floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
+       }
+       break;
+
+       case typeExtended:
+       {
+         if (typeSingle == nType)
+           fpa11->fpreg[Fd].fExtended =
+              float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
+         else
+           fpa11->fpreg[Fd].fExtended =
+              float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
+       }
+       break;
+     }
+
+     fpa11->fType[Fd] = nDest;
+   }
+
+   return nRc;
+}
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdt.c b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdt.c
new file mode 100644
index 0000000..3e7a938
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cpdt.c
@@ -0,0 +1,381 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.com, 1998-1999
+    (c) Philip Blundell, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+//#include "fpmodule.h"
+//#include "fpmodule.inl"
+
+//#include <asm/uaccess.h>
+
+static inline
+void loadSingle(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   fpa11->fType[Fn] = typeSingle;
+   /* FIXME - handle failure of get_user() */
+   get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr);
+}
+
+static inline
+void loadDouble(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int *p;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
+   fpa11->fType[Fn] = typeDouble;
+#ifdef HOST_WORDS_BIGENDIAN
+   /* FIXME - handle failure of get_user() */
+   get_user_u32(p[0], addr); /* sign & exponent */
+   get_user_u32(p[1], addr + 4);
+#else
+   /* FIXME - handle failure of get_user() */
+   get_user_u32(p[0], addr + 4);
+   get_user_u32(p[1], addr); /* sign & exponent */
+#endif
+}
+
+static inline
+void loadExtended(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int *p;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
+   fpa11->fType[Fn] = typeExtended;
+   /* FIXME - handle failure of get_user() */
+   get_user_u32(p[0], addr);  /* sign & exponent */
+   get_user_u32(p[1], addr + 8);  /* ls bits */
+   get_user_u32(p[2], addr + 4);  /* ms bits */
+}
+
+static inline
+void loadMultiple(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   register unsigned int *p;
+   unsigned long x;
+
+   p = (unsigned int*)&(fpa11->fpreg[Fn]);
+   /* FIXME - handle failure of get_user() */
+   get_user_u32(x, addr);
+   fpa11->fType[Fn] = (x >> 14) & 0x00000003;
+
+   switch (fpa11->fType[Fn])
+   {
+      case typeSingle:
+      case typeDouble:
+      {
+         /* FIXME - handle failure of get_user() */
+         get_user_u32(p[0], addr + 8);  /* Single */
+         get_user_u32(p[1], addr + 4);  /* double msw */
+         p[2] = 0;        /* empty */
+      }
+      break;
+
+      case typeExtended:
+      {
+         /* FIXME - handle failure of get_user() */
+         get_user_u32(p[1], addr + 8);
+         get_user_u32(p[2], addr + 4);  /* msw */
+         p[0] = (x & 0x80003fff);
+      }
+      break;
+   }
+}
+
+static inline
+void storeSingle(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   float32 val;
+   register unsigned int *p = (unsigned int*)&val;
+
+   switch (fpa11->fType[Fn])
+   {
+      case typeDouble:
+         val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
+      break;
+
+      case typeExtended:
+         val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fSingle;
+   }
+
+   /* FIXME - handle put_user() failures */
+   put_user_u32(p[0], addr);
+}
+
+static inline
+void storeDouble(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   float64 val;
+   register unsigned int *p = (unsigned int*)&val;
+
+   switch (fpa11->fType[Fn])
+   {
+      case typeSingle:
+         val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
+      break;
+
+      case typeExtended:
+         val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fDouble;
+   }
+   /* FIXME - handle put_user() failures */
+#ifdef HOST_WORDS_BIGENDIAN
+   put_user_u32(p[0], addr);	/* msw */
+   put_user_u32(p[1], addr + 4);	/* lsw */
+#else
+   put_user_u32(p[1], addr);	/* msw */
+   put_user_u32(p[0], addr + 4);	/* lsw */
+#endif
+}
+
+static inline
+void storeExtended(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   floatx80 val;
+   register unsigned int *p = (unsigned int*)&val;
+
+   switch (fpa11->fType[Fn])
+   {
+      case typeSingle:
+         val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
+      break;
+
+      case typeDouble:
+         val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fExtended;
+   }
+
+   /* FIXME - handle put_user() failures */
+   put_user_u32(p[0], addr); /* sign & exp */
+   put_user_u32(p[1], addr + 8);
+   put_user_u32(p[2], addr + 4); /* msw */
+}
+
+static inline
+void storeMultiple(const unsigned int Fn, target_ulong addr)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   register unsigned int nType, *p;
+
+   p = (unsigned int*)&(fpa11->fpreg[Fn]);
+   nType = fpa11->fType[Fn];
+
+   switch (nType)
+   {
+      case typeSingle:
+      case typeDouble:
+      {
+         put_user_u32(p[0], addr + 8); /* single */
+	 put_user_u32(p[1], addr + 4); /* double msw */
+	 put_user_u32(nType << 14, addr);
+      }
+      break;
+
+      case typeExtended:
+      {
+         put_user_u32(p[2], addr + 4); /* msw */
+	 put_user_u32(p[1], addr + 8);
+	 put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr);
+      }
+      break;
+   }
+}
+
+static unsigned int PerformLDF(const unsigned int opcode)
+{
+    target_ulong pBase, pAddress, pFinal;
+    unsigned int nRc = 1,
+     write_back = WRITE_BACK(opcode);
+
+   //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+
+   pBase = readRegister(getRn(opcode));
+   if (ARM_REG_PC == getRn(opcode))
+   {
+     pBase += 8;
+     write_back = 0;
+   }
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode) * 4;
+   else
+     pFinal -= getOffset(opcode) * 4;
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   switch (opcode & MASK_TRANSFER_LENGTH)
+   {
+      case TRANSFER_SINGLE  : loadSingle(getFd(opcode),pAddress);   break;
+      case TRANSFER_DOUBLE  : loadDouble(getFd(opcode),pAddress);   break;
+      case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
+      default: nRc = 0;
+   }
+
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return nRc;
+}
+
+static unsigned int PerformSTF(const unsigned int opcode)
+{
+   target_ulong pBase, pAddress, pFinal;
+   unsigned int nRc = 1,
+     write_back = WRITE_BACK(opcode);
+
+   //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+   SetRoundingMode(ROUND_TO_NEAREST);
+
+   pBase = readRegister(getRn(opcode));
+   if (ARM_REG_PC == getRn(opcode))
+   {
+     pBase += 8;
+     write_back = 0;
+   }
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode) * 4;
+   else
+     pFinal -= getOffset(opcode) * 4;
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   switch (opcode & MASK_TRANSFER_LENGTH)
+   {
+      case TRANSFER_SINGLE  : storeSingle(getFd(opcode),pAddress);   break;
+      case TRANSFER_DOUBLE  : storeDouble(getFd(opcode),pAddress);   break;
+      case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
+      default: nRc = 0;
+   }
+
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return nRc;
+}
+
+static unsigned int PerformLFM(const unsigned int opcode)
+{
+   unsigned int i, Fd,
+     write_back = WRITE_BACK(opcode);
+   target_ulong pBase, pAddress, pFinal;
+
+   pBase = readRegister(getRn(opcode));
+   if (ARM_REG_PC == getRn(opcode))
+   {
+     pBase += 8;
+     write_back = 0;
+   }
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode) * 4;
+   else
+     pFinal -= getOffset(opcode) * 4;
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   Fd = getFd(opcode);
+   for (i=getRegisterCount(opcode);i>0;i--)
+   {
+     loadMultiple(Fd,pAddress);
+     pAddress += 12; Fd++;
+     if (Fd == 8) Fd = 0;
+   }
+
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return 1;
+}
+
+static unsigned int PerformSFM(const unsigned int opcode)
+{
+   unsigned int i, Fd,
+     write_back = WRITE_BACK(opcode);
+   target_ulong pBase, pAddress, pFinal;
+
+   pBase = readRegister(getRn(opcode));
+   if (ARM_REG_PC == getRn(opcode))
+   {
+     pBase += 8;
+     write_back = 0;
+   }
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode) * 4;
+   else
+     pFinal -= getOffset(opcode) * 4;
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   Fd = getFd(opcode);
+   for (i=getRegisterCount(opcode);i>0;i--)
+   {
+     storeMultiple(Fd,pAddress);
+     pAddress += 12; Fd++;
+     if (Fd == 8) Fd = 0;
+   }
+
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return 1;
+}
+
+#if 1
+unsigned int EmulateCPDT(const unsigned int opcode)
+{
+  unsigned int nRc = 0;
+
+  //printk("EmulateCPDT(0x%08x)\n",opcode);
+
+  if (LDF_OP(opcode))
+  {
+    nRc = PerformLDF(opcode);
+  }
+  else if (LFM_OP(opcode))
+  {
+    nRc = PerformLFM(opcode);
+  }
+  else if (STF_OP(opcode))
+  {
+    nRc = PerformSTF(opcode);
+  }
+  else if (SFM_OP(opcode))
+  {
+    nRc = PerformSFM(opcode);
+  }
+  else
+  {
+    nRc = 0;
+  }
+
+  return nRc;
+}
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cprt.c b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cprt.c
new file mode 100644
index 0000000..8011897
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpa11_cprt.c
@@ -0,0 +1,283 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+    (c) Philip Blundell, 1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.inl"
+//#include "fpmodule.h"
+//#include "fpmodule.inl"
+
+unsigned int PerformFLT(const unsigned int opcode);
+unsigned int PerformFIX(const unsigned int opcode);
+
+static unsigned int
+PerformComparison(const unsigned int opcode);
+
+unsigned int EmulateCPRT(const unsigned int opcode)
+{
+  unsigned int nRc = 1;
+
+  //printk("EmulateCPRT(0x%08x)\n",opcode);
+
+  if (opcode & 0x800000)
+  {
+     /* This is some variant of a comparison (PerformComparison will
+	sort out which one).  Since most of the other CPRT
+	instructions are oddball cases of some sort or other it makes
+	sense to pull this out into a fast path.  */
+     return PerformComparison(opcode);
+  }
+
+  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
+  switch ((opcode & 0x700000) >> 20)
+  {
+    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
+    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
+
+    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
+    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
+
+#if 0    /* We currently have no use for the FPCR, so there's no point
+	    in emulating it. */
+    case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
+    case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
+#endif
+
+    default: nRc = 0;
+  }
+
+  return nRc;
+}
+
+unsigned int PerformFLT(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+
+   unsigned int nRc = 1;
+   SetRoundingMode(opcode);
+
+   switch (opcode & MASK_ROUNDING_PRECISION)
+   {
+      case ROUND_SINGLE:
+      {
+        fpa11->fType[getFn(opcode)] = typeSingle;
+        fpa11->fpreg[getFn(opcode)].fSingle =
+	   int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
+      }
+      break;
+
+      case ROUND_DOUBLE:
+      {
+        fpa11->fType[getFn(opcode)] = typeDouble;
+        fpa11->fpreg[getFn(opcode)].fDouble =
+            int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
+      }
+      break;
+
+      case ROUND_EXTENDED:
+      {
+        fpa11->fType[getFn(opcode)] = typeExtended;
+        fpa11->fpreg[getFn(opcode)].fExtended =
+	   int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
+      }
+      break;
+
+      default: nRc = 0;
+  }
+
+  return nRc;
+}
+
+unsigned int PerformFIX(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int nRc = 1;
+   unsigned int Fn = getFm(opcode);
+
+   SetRoundingMode(opcode);
+
+   switch (fpa11->fType[Fn])
+   {
+      case typeSingle:
+      {
+         writeRegister(getRd(opcode),
+	               float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
+      }
+      break;
+
+      case typeDouble:
+      {
+         //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
+         writeRegister(getRd(opcode),
+	               float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
+      }
+      break;
+
+      case typeExtended:
+      {
+         writeRegister(getRd(opcode),
+	               floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
+      }
+      break;
+
+      default: nRc = 0;
+  }
+
+  return nRc;
+}
+
+
+static __inline unsigned int
+PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int flags = 0;
+
+   /* test for less than condition */
+   if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
+   {
+      flags |= CC_NEGATIVE;
+   }
+
+   /* test for equal condition */
+   if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status))
+   {
+      flags |= CC_ZERO;
+   }
+
+   /* test for greater than or equal condition */
+   if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
+   {
+      flags |= CC_CARRY;
+   }
+
+   writeConditionCodes(flags);
+   return 1;
+}
+
+/* This instruction sets the flags N, Z, C, V in the FPSR. */
+
+static unsigned int PerformComparison(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   unsigned int Fn, Fm;
+   floatx80 rFn, rFm;
+   int e_flag = opcode & 0x400000;	/* 1 if CxFE */
+   int n_flag = opcode & 0x200000;	/* 1 if CNxx */
+   unsigned int flags = 0;
+
+   //printk("PerformComparison(0x%08x)\n",opcode);
+
+   Fn = getFn(opcode);
+   Fm = getFm(opcode);
+
+   /* Check for unordered condition and convert all operands to 80-bit
+      format.
+      ?? Might be some mileage in avoiding this conversion if possible.
+      Eg, if both operands are 32-bit, detect this and do a 32-bit
+      comparison (cheaper than an 80-bit one).  */
+   switch (fpa11->fType[Fn])
+   {
+      case typeSingle:
+        //printk("single.\n");
+	if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle))
+	   goto unordered;
+        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
+      break;
+
+      case typeDouble:
+        //printk("double.\n");
+	if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble))
+	   goto unordered;
+        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
+      break;
+
+      case typeExtended:
+        //printk("extended.\n");
+	if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended))
+	   goto unordered;
+        rFn = fpa11->fpreg[Fn].fExtended;
+      break;
+
+      default: return 0;
+   }
+
+   if (CONSTANT_FM(opcode))
+   {
+     //printk("Fm is a constant: #%d.\n",Fm);
+     rFm = getExtendedConstant(Fm);
+     if (floatx80_is_any_nan(rFm))
+        goto unordered;
+   }
+   else
+   {
+     //printk("Fm = r%d which contains a ",Fm);
+      switch (fpa11->fType[Fm])
+      {
+         case typeSingle:
+           //printk("single.\n");
+	   if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle))
+	      goto unordered;
+           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
+         break;
+
+         case typeDouble:
+           //printk("double.\n");
+	   if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble))
+	      goto unordered;
+           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
+         break;
+
+         case typeExtended:
+           //printk("extended.\n");
+	   if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended))
+	      goto unordered;
+           rFm = fpa11->fpreg[Fm].fExtended;
+         break;
+
+         default: return 0;
+      }
+   }
+
+   if (n_flag)
+   {
+      rFm.high ^= 0x8000;
+   }
+
+   return PerformComparisonOperation(rFn,rFm);
+
+ unordered:
+   /* ?? The FPA data sheet is pretty vague about this, in particular
+      about whether the non-E comparisons can ever raise exceptions.
+      This implementation is based on a combination of what it says in
+      the data sheet, observation of how the Acorn emulator actually
+      behaves (and how programs expect it to) and guesswork.  */
+   flags |= CC_OVERFLOW;
+   flags &= ~(CC_ZERO | CC_NEGATIVE);
+
+   if (BIT_AC & readFPSR()) flags |= CC_CARRY;
+
+   if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
+
+   writeConditionCodes(flags);
+   return 1;
+}
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.c b/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.c
new file mode 100644
index 0000000..82ac92f
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.c
@@ -0,0 +1,112 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpsr.h"
+//#include "fpmodule.h"
+//#include "fpmodule.inl"
+
+const floatx80 floatx80Constant[] = {
+  { 0x0000000000000000ULL, 0x0000},	/* extended 0.0 */
+  { 0x8000000000000000ULL, 0x3fff},	/* extended 1.0 */
+  { 0x8000000000000000ULL, 0x4000},	/* extended 2.0 */
+  { 0xc000000000000000ULL, 0x4000},	/* extended 3.0 */
+  { 0x8000000000000000ULL, 0x4001},	/* extended 4.0 */
+  { 0xa000000000000000ULL, 0x4001},	/* extended 5.0 */
+  { 0x8000000000000000ULL, 0x3ffe},	/* extended 0.5 */
+  { 0xa000000000000000ULL, 0x4002}	/* extended 10.0 */
+};
+
+const float64 float64Constant[] = {
+  const_float64(0x0000000000000000ULL),		/* double 0.0 */
+  const_float64(0x3ff0000000000000ULL),		/* double 1.0 */
+  const_float64(0x4000000000000000ULL),		/* double 2.0 */
+  const_float64(0x4008000000000000ULL),		/* double 3.0 */
+  const_float64(0x4010000000000000ULL),		/* double 4.0 */
+  const_float64(0x4014000000000000ULL),		/* double 5.0 */
+  const_float64(0x3fe0000000000000ULL),		/* double 0.5 */
+  const_float64(0x4024000000000000ULL)			/* double 10.0 */
+};
+
+const float32 float32Constant[] = {
+  const_float32(0x00000000),				/* single 0.0 */
+  const_float32(0x3f800000),				/* single 1.0 */
+  const_float32(0x40000000),				/* single 2.0 */
+  const_float32(0x40400000),				/* single 3.0 */
+  const_float32(0x40800000),				/* single 4.0 */
+  const_float32(0x40a00000),				/* single 5.0 */
+  const_float32(0x3f000000),				/* single 0.5 */
+  const_float32(0x41200000)				/* single 10.0 */
+};
+
+unsigned int getRegisterCount(const unsigned int opcode)
+{
+  unsigned int nRc;
+
+  switch (opcode & MASK_REGISTER_COUNT)
+  {
+    case 0x00000000: nRc = 4; break;
+    case 0x00008000: nRc = 1; break;
+    case 0x00400000: nRc = 2; break;
+    case 0x00408000: nRc = 3; break;
+    default: nRc = 0;
+  }
+
+  return(nRc);
+}
+
+unsigned int getDestinationSize(const unsigned int opcode)
+{
+  unsigned int nRc;
+
+  switch (opcode & MASK_DESTINATION_SIZE)
+  {
+    case 0x00000000: nRc = typeSingle; break;
+    case 0x00000080: nRc = typeDouble; break;
+    case 0x00080000: nRc = typeExtended; break;
+    default: nRc = typeNone;
+  }
+
+  return(nRc);
+}
+
+/* condition code lookup table
+ index into the table is test code: EQ, NE, ... LT, GT, AL, NV
+ bit position in short is condition code: NZCV */
+static const unsigned short aCC[16] = {
+    0xF0F0, // EQ == Z set
+    0x0F0F, // NE
+    0xCCCC, // CS == C set
+    0x3333, // CC
+    0xFF00, // MI == N set
+    0x00FF, // PL
+    0xAAAA, // VS == V set
+    0x5555, // VC
+    0x0C0C, // HI == C set && Z clear
+    0xF3F3, // LS == C clear || Z set
+    0xAA55, // GE == (N==V)
+    0x55AA, // LT == (N!=V)
+    0x0A05, // GT == (!Z && (N==V))
+    0xF5FA, // LE == (Z || (N!=V))
+    0xFFFF, // AL always
+    0 // NV
+};
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.h b/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.h
new file mode 100644
index 0000000..e7d1009
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpopcode.h
@@ -0,0 +1,390 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FPOPCODE_H__
+#define __FPOPCODE_H__
+
+/*
+ARM Floating Point Instruction Classes
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+|c o n d|1 1 0 P|U|u|W|L|   Rn  |v|  Fd |0|0|0|1|  o f f s e t  | CPDT
+|c o n d|1 1 0 P|U|w|W|L|   Rn  |x|  Fd |0|0|0|1|  o f f s e t  | CPDT
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+|c o n d|1 1 1 0|a|b|c|d|e|  Fn |j|  Fd |0|0|0|1|f|g|h|0|i|  Fm | CPDO
+|c o n d|1 1 1 0|a|b|c|L|e|  Fn |   Rd  |0|0|0|1|f|g|h|1|i|  Fm | CPRT
+|c o n d|1 1 1 0|a|b|c|1|e|  Fn |1|1|1|1|0|0|0|1|f|g|h|1|i|  Fm | comparisons
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+
+CPDT		data transfer instructions
+		LDF, STF, LFM, SFM
+
+CPDO		dyadic arithmetic instructions
+		ADF, MUF, SUF, RSF, DVF, RDF,
+		POW, RPW, RMF, FML, FDV, FRD, POL
+
+CPDO		monadic arithmetic instructions
+		MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
+		SIN, COS, TAN, ASN, ACS, ATN, URD, NRM
+
+CPRT		joint arithmetic/data transfer instructions
+		FIX (arithmetic followed by load/store)
+		FLT (load/store followed by arithmetic)
+		CMF, CNF CMFE, CNFE (comparisons)
+		WFS, RFS (write/read floating point status register)
+		WFC, RFC (write/read floating point control register)
+
+cond		condition codes
+P		pre/post index bit: 0 = postindex, 1 = preindex
+U		up/down bit: 0 = stack grows down, 1 = stack grows up
+W		write back bit: 1 = update base register (Rn)
+L		load/store bit: 0 = store, 1 = load
+Rn		base register
+Rd		destination/source register
+Fd		floating point destination register
+Fn		floating point source register
+Fm		floating point source register or floating point constant
+
+uv		transfer length (TABLE 1)
+wx		register count (TABLE 2)
+abcd		arithmetic opcode (TABLES 3 & 4)
+ef		destination size (rounding precision) (TABLE 5)
+gh		rounding mode (TABLE 6)
+j		dyadic/monadic bit: 0 = dyadic, 1 = monadic
+i 		constant bit: 1 = constant (TABLE 6)
+*/
+
+/*
+TABLE 1
++-------------------------+---+---+---------+---------+
+|  Precision              | u | v | FPSR.EP | length  |
++-------------------------+---+---+---------+---------+
+| Single                  | 0 ü 0 |    x    | 1 words |
+| Double                  | 1 ü 1 |    x    | 2 words |
+| Extended                | 1 ü 1 |    x    | 3 words |
+| Packed decimal          | 1 ü 1 |    0    | 3 words |
+| Expanded packed decimal | 1 ü 1 |    1    | 4 words |
++-------------------------+---+---+---------+---------+
+Note: x = don't care
+*/
+
+/*
+TABLE 2
++---+---+---------------------------------+
+| w | x | Number of registers to transfer |
++---+---+---------------------------------+
+| 0 ü 1 |  1                              |
+| 1 ü 0 |  2                              |
+| 1 ü 1 |  3                              |
+| 0 ü 0 |  4                              |
++---+---+---------------------------------+
+*/
+
+/*
+TABLE 3: Dyadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description           | Operation             |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | ADF      | Add                   | Fd := Fn + Fm         |
+| 0 | 0 | 0 | 1 | MUF      | Multiply              | Fd := Fn * Fm         |
+| 0 | 0 | 1 | 0 | SUF      | Subtract              | Fd := Fn - Fm         |
+| 0 | 0 | 1 | 1 | RSF      | Reverse subtract      | Fd := Fm - Fn         |
+| 0 | 1 | 0 | 0 | DVF      | Divide                | Fd := Fn / Fm         |
+| 0 | 1 | 0 | 1 | RDF      | Reverse divide        | Fd := Fm / Fn         |
+| 0 | 1 | 1 | 0 | POW      | Power                 | Fd := Fn ^ Fm         |
+| 0 | 1 | 1 | 1 | RPW      | Reverse power         | Fd := Fm ^ Fn         |
+| 1 | 0 | 0 | 0 | RMF      | Remainder             | Fd := IEEE rem(Fn/Fm) |
+| 1 | 0 | 0 | 1 | FML      | Fast Multiply         | Fd := Fn * Fm         |
+| 1 | 0 | 1 | 0 | FDV      | Fast Divide           | Fd := Fn / Fm         |
+| 1 | 0 | 1 | 1 | FRD      | Fast reverse divide   | Fd := Fm / Fn         |
+| 1 | 1 | 0 | 0 | POL      | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm)  |
+| 1 | 1 | 0 | 1 |          | undefined instruction | trap                  |
+| 1 | 1 | 1 | 0 |          | undefined instruction | trap                  |
+| 1 | 1 | 1 | 1 |          | undefined instruction | trap                  |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: POW, RPW, POL are deprecated, and are available for backwards
+      compatibility only.
+*/
+
+/*
+TABLE 4: Monadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description           | Operation             |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | MVF      | Move                  | Fd := Fm              |
+| 0 | 0 | 0 | 1 | MNF      | Move negated          | Fd := - Fm            |
+| 0 | 0 | 1 | 0 | ABS      | Absolute value        | Fd := abs(Fm)         |
+| 0 | 0 | 1 | 1 | RND      | Round to integer      | Fd := int(Fm)         |
+| 0 | 1 | 0 | 0 | SQT      | Square root           | Fd := sqrt(Fm)        |
+| 0 | 1 | 0 | 1 | LOG      | Log base 10           | Fd := log10(Fm)       |
+| 0 | 1 | 1 | 0 | LGN      | Log base e            | Fd := ln(Fm)          |
+| 0 | 1 | 1 | 1 | EXP      | Exponent              | Fd := e ^ Fm          |
+| 1 | 0 | 0 | 0 | SIN      | Sine                  | Fd := sin(Fm)         |
+| 1 | 0 | 0 | 1 | COS      | Cosine                | Fd := cos(Fm)         |
+| 1 | 0 | 1 | 0 | TAN      | Tangent               | Fd := tan(Fm)         |
+| 1 | 0 | 1 | 1 | ASN      | Arc Sine              | Fd := arcsin(Fm)      |
+| 1 | 1 | 0 | 0 | ACS      | Arc Cosine            | Fd := arccos(Fm)      |
+| 1 | 1 | 0 | 1 | ATN      | Arc Tangent           | Fd := arctan(Fm)      |
+| 1 | 1 | 1 | 0 | URD      | Unnormalized round    | Fd := int(Fm)         |
+| 1 | 1 | 1 | 1 | NRM      | Normalize             | Fd := norm(Fm)        |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are
+      available for backwards compatibility only.
+*/
+
+/*
+TABLE 5
++-------------------------+---+---+
+|  Rounding Precision     | e | f |
++-------------------------+---+---+
+| IEEE Single precision   | 0 ü 0 |
+| IEEE Double precision   | 0 ü 1 |
+| IEEE Extended precision | 1 ü 0 |
+| undefined (trap)        | 1 ü 1 |
++-------------------------+---+---+
+*/
+
+/*
+TABLE 5
++---------------------------------+---+---+
+|  Rounding Mode                  | g | h |
++---------------------------------+---+---+
+| Round to nearest (default)      | 0 ü 0 |
+| Round toward plus infinity      | 0 ü 1 |
+| Round toward negative infinity  | 1 ü 0 |
+| Round toward zero               | 1 ü 1 |
++---------------------------------+---+---+
+*/
+
+/*
+===
+=== Definitions for load and store instructions
+===
+*/
+
+/* bit masks */
+#define BIT_PREINDEX	0x01000000
+#define BIT_UP		0x00800000
+#define BIT_WRITE_BACK	0x00200000
+#define BIT_LOAD	0x00100000
+
+/* masks for load/store */
+#define MASK_CPDT		0x0c000000  /* data processing opcode */
+#define MASK_OFFSET		0x000000ff
+#define MASK_TRANSFER_LENGTH	0x00408000
+#define MASK_REGISTER_COUNT	MASK_TRANSFER_LENGTH
+#define MASK_COPROCESSOR	0x00000f00
+
+/* Tests for transfer length */
+#define TRANSFER_SINGLE		0x00000000
+#define TRANSFER_DOUBLE		0x00008000
+#define TRANSFER_EXTENDED	0x00400000
+#define TRANSFER_PACKED		MASK_TRANSFER_LENGTH
+
+/* Get the coprocessor number from the opcode. */
+#define getCoprocessorNumber(opcode)	((opcode & MASK_COPROCESSOR) >> 8)
+
+/* Get the offset from the opcode. */
+#define getOffset(opcode)		(opcode & MASK_OFFSET)
+
+/* Tests for specific data transfer load/store opcodes. */
+#define TEST_OPCODE(opcode,mask)	(((opcode) & (mask)) == (mask))
+
+#define LOAD_OP(opcode)   TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD)
+#define STORE_OP(opcode)  ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT)
+
+#define LDF_OP(opcode)	(LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define LFM_OP(opcode)	(LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+#define STF_OP(opcode)	(STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define SFM_OP(opcode)	(STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+
+#define PREINDEXED(opcode)		((opcode & BIT_PREINDEX) != 0)
+#define POSTINDEXED(opcode)		((opcode & BIT_PREINDEX) == 0)
+#define BIT_UP_SET(opcode)		((opcode & BIT_UP) != 0)
+#define BIT_UP_CLEAR(opcode)		((opcode & BIT_DOWN) == 0)
+#define WRITE_BACK(opcode)		((opcode & BIT_WRITE_BACK) != 0)
+#define LOAD(opcode)			((opcode & BIT_LOAD) != 0)
+#define STORE(opcode)			((opcode & BIT_LOAD) == 0)
+
+/*
+===
+=== Definitions for arithmetic instructions
+===
+*/
+/* bit masks */
+#define BIT_MONADIC	0x00008000
+#define BIT_CONSTANT	0x00000008
+
+#define CONSTANT_FM(opcode)		((opcode & BIT_CONSTANT) != 0)
+#define MONADIC_INSTRUCTION(opcode)	((opcode & BIT_MONADIC) != 0)
+
+/* instruction identification masks */
+#define MASK_CPDO		0x0e000000  /* arithmetic opcode */
+#define MASK_ARITHMETIC_OPCODE	0x00f08000
+#define MASK_DESTINATION_SIZE	0x00080080
+
+/* dyadic arithmetic opcodes. */
+#define ADF_CODE	0x00000000
+#define MUF_CODE	0x00100000
+#define SUF_CODE	0x00200000
+#define RSF_CODE	0x00300000
+#define DVF_CODE	0x00400000
+#define RDF_CODE	0x00500000
+#define POW_CODE	0x00600000
+#define RPW_CODE	0x00700000
+#define RMF_CODE	0x00800000
+#define FML_CODE	0x00900000
+#define FDV_CODE	0x00a00000
+#define FRD_CODE	0x00b00000
+#define POL_CODE	0x00c00000
+/* 0x00d00000 is an invalid dyadic arithmetic opcode */
+/* 0x00e00000 is an invalid dyadic arithmetic opcode */
+/* 0x00f00000 is an invalid dyadic arithmetic opcode */
+
+/* monadic arithmetic opcodes. */
+#define MVF_CODE	0x00008000
+#define MNF_CODE	0x00108000
+#define ABS_CODE	0x00208000
+#define RND_CODE	0x00308000
+#define SQT_CODE	0x00408000
+#define LOG_CODE	0x00508000
+#define LGN_CODE	0x00608000
+#define EXP_CODE	0x00708000
+#define SIN_CODE	0x00808000
+#define COS_CODE	0x00908000
+#define TAN_CODE	0x00a08000
+#define ASN_CODE	0x00b08000
+#define ACS_CODE	0x00c08000
+#define ATN_CODE	0x00d08000
+#define URD_CODE	0x00e08000
+#define NRM_CODE	0x00f08000
+
+/*
+===
+=== Definitions for register transfer and comparison instructions
+===
+*/
+
+#define MASK_CPRT		0x0e000010  /* register transfer opcode */
+#define MASK_CPRT_CODE		0x00f00000
+#define FLT_CODE		0x00000000
+#define FIX_CODE		0x00100000
+#define WFS_CODE		0x00200000
+#define RFS_CODE		0x00300000
+#define WFC_CODE		0x00400000
+#define RFC_CODE		0x00500000
+#define CMF_CODE		0x00900000
+#define CNF_CODE		0x00b00000
+#define CMFE_CODE		0x00d00000
+#define CNFE_CODE		0x00f00000
+
+/*
+===
+=== Common definitions
+===
+*/
+
+/* register masks */
+#define MASK_Rd		0x0000f000
+#define MASK_Rn		0x000f0000
+#define MASK_Fd		0x00007000
+#define MASK_Fm		0x00000007
+#define MASK_Fn		0x00070000
+
+/* condition code masks */
+#define CC_MASK		0xf0000000
+#define CC_NEGATIVE	0x80000000
+#define CC_ZERO		0x40000000
+#define CC_CARRY	0x20000000
+#define CC_OVERFLOW	0x10000000
+#define CC_EQ		0x00000000
+#define CC_NE		0x10000000
+#define CC_CS		0x20000000
+#define CC_HS		CC_CS
+#define CC_CC		0x30000000
+#define CC_LO		CC_CC
+#define CC_MI		0x40000000
+#define CC_PL		0x50000000
+#define CC_VS		0x60000000
+#define CC_VC		0x70000000
+#define CC_HI		0x80000000
+#define CC_LS		0x90000000
+#define CC_GE		0xa0000000
+#define CC_LT		0xb0000000
+#define CC_GT		0xc0000000
+#define CC_LE		0xd0000000
+#define CC_AL		0xe0000000
+#define CC_NV		0xf0000000
+
+/* rounding masks/values */
+#define MASK_ROUNDING_MODE	0x00000060
+#define ROUND_TO_NEAREST	0x00000000
+#define ROUND_TO_PLUS_INFINITY	0x00000020
+#define ROUND_TO_MINUS_INFINITY	0x00000040
+#define ROUND_TO_ZERO		0x00000060
+
+#define MASK_ROUNDING_PRECISION	0x00080080
+#define ROUND_SINGLE		0x00000000
+#define ROUND_DOUBLE		0x00000080
+#define ROUND_EXTENDED		0x00080000
+
+/* Get the condition code from the opcode. */
+#define getCondition(opcode)		(opcode >> 28)
+
+/* Get the source register from the opcode. */
+#define getRn(opcode)			((opcode & MASK_Rn) >> 16)
+
+/* Get the destination floating point register from the opcode. */
+#define getFd(opcode)			((opcode & MASK_Fd) >> 12)
+
+/* Get the first source floating point register from the opcode. */
+#define getFn(opcode)		((opcode & MASK_Fn) >> 16)
+
+/* Get the second source floating point register from the opcode. */
+#define getFm(opcode)		(opcode & MASK_Fm)
+
+/* Get the destination register from the opcode. */
+#define getRd(opcode)		((opcode & MASK_Rd) >> 12)
+
+/* Get the rounding mode from the opcode. */
+#define getRoundingMode(opcode)		((opcode & MASK_ROUNDING_MODE) >> 5)
+
+extern const floatx80 floatx80Constant[];
+extern const float64 float64Constant[];
+extern const float32 float32Constant[];
+
+static inline floatx80 getExtendedConstant(const unsigned int nIndex)
+{
+   return floatx80Constant[nIndex];
+}
+
+static inline float64 getDoubleConstant(const unsigned int nIndex)
+{
+   return float64Constant[nIndex];
+}
+
+static inline float32 getSingleConstant(const unsigned int nIndex)
+{
+   return float32Constant[nIndex];
+}
+
+unsigned int getRegisterCount(const unsigned int opcode);
+unsigned int getDestinationSize(const unsigned int opcode);
+
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/fpsr.h b/qemu-0.15.x/linux-user/arm/nwfpe/fpsr.h
new file mode 100644
index 0000000..859dcd5
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/fpsr.h
@@ -0,0 +1,107 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.com, 1998-1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FPSR_H__
+#define __FPSR_H__
+
+/*
+The FPSR is a 32 bit register consisting of 4 parts, each exactly
+one byte.
+
+	SYSTEM ID
+	EXCEPTION TRAP ENABLE BYTE
+	SYSTEM CONTROL BYTE
+	CUMULATIVE EXCEPTION FLAGS BYTE
+
+The FPCR is a 32 bit register consisting of bit flags.
+*/
+
+/* SYSTEM ID
+------------
+Note: the system id byte is read only  */
+
+typedef unsigned int FPSR;  /* type for floating point status register */
+typedef unsigned int FPCR;  /* type for floating point control register */
+
+#define MASK_SYSID		0xff000000
+#define BIT_HARDWARE		0x80000000
+#define FP_EMULATOR		0x01000000	/* System ID for emulator */
+#define FP_ACCELERATOR		0x81000000	/* System ID for FPA11 */
+
+/* EXCEPTION TRAP ENABLE BYTE
+----------------------------- */
+
+#define MASK_TRAP_ENABLE	0x00ff0000
+#define MASK_TRAP_ENABLE_STRICT	0x001f0000
+#define BIT_IXE		0x00100000   /* inexact exception enable */
+#define BIT_UFE		0x00080000   /* underflow exception enable */
+#define BIT_OFE		0x00040000   /* overflow exception enable */
+#define BIT_DZE		0x00020000   /* divide by zero exception enable */
+#define BIT_IOE		0x00010000   /* invalid operation exception enable */
+
+/* SYSTEM CONTROL BYTE
+---------------------- */
+
+#define MASK_SYSTEM_CONTROL	0x0000ff00
+#define MASK_TRAP_STRICT	0x00001f00
+
+#define BIT_AC	0x00001000	/* use alternative C-flag definition
+				   for compares */
+#define BIT_EP	0x00000800	/* use expanded packed decimal format */
+#define BIT_SO	0x00000400	/* select synchronous operation of FPA */
+#define BIT_NE	0x00000200	/* NaN exception bit */
+#define BIT_ND	0x00000100	/* no denormalized numbers bit */
+
+/* CUMULATIVE EXCEPTION FLAGS BYTE
+---------------------------------- */
+
+#define MASK_EXCEPTION_FLAGS		0x000000ff
+#define MASK_EXCEPTION_FLAGS_STRICT	0x0000001f
+
+#define BIT_IXC		0x00000010	/* inexact exception flag */
+#define BIT_UFC		0x00000008	/* underflow exception flag */
+#define BIT_OFC		0x00000004	/* overfloat exception flag */
+#define BIT_DZC		0x00000002	/* divide by zero exception flag */
+#define BIT_IOC		0x00000001	/* invalid operation exception flag */
+
+/* Floating Point Control Register
+----------------------------------*/
+
+#define BIT_RU		0x80000000	/* rounded up bit */
+#define BIT_IE		0x10000000	/* inexact bit */
+#define BIT_MO		0x08000000	/* mantissa overflow bit */
+#define BIT_EO		0x04000000	/* exponent overflow bit */
+#define BIT_SB		0x00000800	/* store bounce */
+#define BIT_AB		0x00000400	/* arithmetic bounce */
+#define BIT_RE		0x00000200	/* rounding exception */
+#define BIT_DA		0x00000100	/* disable FPA */
+
+#define MASK_OP		0x00f08010	/* AU operation code */
+#define MASK_PR		0x00080080	/* AU precision */
+#define MASK_S1		0x00070000	/* AU source register 1 */
+#define MASK_S2		0x00000007	/* AU source register 2 */
+#define MASK_DS		0x00007000	/* AU destination register */
+#define MASK_RM		0x00000060	/* AU rounding mode */
+#define MASK_ALU	0x9cfff2ff	/* only ALU can write these bits */
+#define MASK_RESET	0x00000d00	/* bits set on reset, all others cleared */
+#define MASK_WFC	MASK_RESET
+#define MASK_RFC	~MASK_RESET
+
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/nwfpe/single_cpdo.c b/qemu-0.15.x/linux-user/arm/nwfpe/single_cpdo.c
new file mode 100644
index 0000000..26168e2
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/nwfpe/single_cpdo.c
@@ -0,0 +1,252 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb at netwinder.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+
+float32 float32_exp(float32 Fm);
+float32 float32_ln(float32 Fm);
+float32 float32_sin(float32 rFm);
+float32 float32_cos(float32 rFm);
+float32 float32_arcsin(float32 rFm);
+float32 float32_arctan(float32 rFm);
+float32 float32_log(float32 rFm);
+float32 float32_tan(float32 rFm);
+float32 float32_arccos(float32 rFm);
+float32 float32_pow(float32 rFn,float32 rFm);
+float32 float32_pol(float32 rFn,float32 rFm);
+
+unsigned int SingleCPDO(const unsigned int opcode)
+{
+   FPA11 *fpa11 = GET_FPA11();
+   float32 rFm, rFn = float32_zero;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getSingleConstant(Fm);
+   }
+   else
+   {
+     switch (fpa11->fType[Fm])
+     {
+        case typeSingle:
+          rFm = fpa11->fpreg[Fm].fSingle;
+        break;
+
+        default: return 0;
+     }
+   }
+
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fType[Fn])
+      {
+        case typeSingle:
+          rFn = fpa11->fpreg[Fn].fSingle;
+        break;
+
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+        fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fSingle = rFm;
+      break;
+
+      case MNF_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_chs(rFm);
+      break;
+
+      case ABS_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_abs(rFm);
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status);
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fSingle = float32_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+
+      default:
+      {
+        nRc = 0;
+      }
+   }
+
+   if (0 != nRc) fpa11->fType[Fd] = typeSingle;
+   return nRc;
+}
+
+#if 0
+float32 float32_exp(float32 Fm)
+{
+//series
+}
+
+float32 float32_ln(float32 Fm)
+{
+//series
+}
+
+float32 float32_sin(float32 rFm)
+{
+//series
+}
+
+float32 float32_cos(float32 rFm)
+{
+//series
+}
+
+float32 float32_arcsin(float32 rFm)
+{
+//series
+}
+
+float32 float32_arctan(float32 rFm)
+{
+  //series
+}
+
+float32 float32_arccos(float32 rFm)
+{
+   //return float32_sub(halfPi,float32_arcsin(rFm));
+}
+
+float32 float32_log(float32 rFm)
+{
+  return float32_div(float32_ln(rFm),getSingleConstant(7));
+}
+
+float32 float32_tan(float32 rFm)
+{
+  return float32_div(float32_sin(rFm),float32_cos(rFm));
+}
+
+float32 float32_pow(float32 rFn,float32 rFm)
+{
+  return float32_exp(float32_mul(rFm,float32_ln(rFn)));
+}
+
+float32 float32_pol(float32 rFn,float32 rFm)
+{
+  return float32_arctan(float32_div(rFn,rFm));
+}
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/syscall.h b/qemu-0.15.x/linux-user/arm/syscall.h
new file mode 100644
index 0000000..003d424
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/syscall.h
@@ -0,0 +1,42 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+    abi_long uregs[18];
+};
+
+#define ARM_cpsr	uregs[16]
+#define ARM_pc		uregs[15]
+#define ARM_lr		uregs[14]
+#define ARM_sp		uregs[13]
+#define ARM_ip		uregs[12]
+#define ARM_fp		uregs[11]
+#define ARM_r10		uregs[10]
+#define ARM_r9		uregs[9]
+#define ARM_r8		uregs[8]
+#define ARM_r7		uregs[7]
+#define ARM_r6		uregs[6]
+#define ARM_r5		uregs[5]
+#define ARM_r4		uregs[4]
+#define ARM_r3		uregs[3]
+#define ARM_r2		uregs[2]
+#define ARM_r1		uregs[1]
+#define ARM_r0		uregs[0]
+#define ARM_ORIG_r0	uregs[17]
+
+#define ARM_SYSCALL_BASE	0x900000
+#define ARM_THUMB_SYSCALL	0
+
+#define ARM_NR_BASE	  0xf0000
+#define ARM_NR_cacheflush (ARM_NR_BASE + 2)
+#define ARM_NR_set_tls	  (ARM_NR_BASE + 5)
+
+#define ARM_NR_semihosting	  0x123456
+#define ARM_NR_thumb_semihosting  0xAB
+
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define UNAME_MACHINE "armv5teb"
+#else
+#define UNAME_MACHINE "armv5tel"
+#endif
diff --git a/qemu-0.15.x/linux-user/arm/syscall_nr.h b/qemu-0.15.x/linux-user/arm/syscall_nr.h
new file mode 100644
index 0000000..7f05879
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/syscall_nr.h
@@ -0,0 +1,380 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_restart_syscall		(  0)
+#define TARGET_NR_exit			(  1)
+#define TARGET_NR_fork			(  2)
+#define TARGET_NR_read			(  3)
+#define TARGET_NR_write			(  4)
+#define TARGET_NR_open			(  5)
+#define TARGET_NR_close			(  6)
+#define TARGET_NR_waitpid			(  7)	/* removed */
+#define TARGET_NR_creat			(  8)
+#define TARGET_NR_link			(  9)
+#define TARGET_NR_unlink			( 10)
+#define TARGET_NR_execve			( 11)
+#define TARGET_NR_chdir			( 12)
+#define TARGET_NR_time			( 13)
+#define TARGET_NR_mknod			( 14)
+#define TARGET_NR_chmod			( 15)
+#define TARGET_NR_lchown			( 16)
+#define TARGET_NR_break			( 17)	/* removed */
+					/* 18 was sys_stat */
+#define TARGET_NR_lseek			( 19)
+#define TARGET_NR_getpid			( 20)
+#define TARGET_NR_mount			( 21)
+#define TARGET_NR_umount			( 22)
+#define TARGET_NR_setuid			( 23)
+#define TARGET_NR_getuid			( 24)
+#define TARGET_NR_stime			( 25)
+#define TARGET_NR_ptrace			( 26)
+#define TARGET_NR_alarm			( 27)
+
+#define TARGET_NR_pause			( 29)
+#define TARGET_NR_utime			( 30)
+#define TARGET_NR_stty			( 31)	/* removed */
+#define TARGET_NR_gtty			( 32)	/* removed */
+#define TARGET_NR_access			( 33)
+#define TARGET_NR_nice			( 34)
+#define TARGET_NR_ftime			( 35)	/* removed */
+#define TARGET_NR_sync			( 36)
+#define TARGET_NR_kill			( 37)
+#define TARGET_NR_rename			( 38)
+#define TARGET_NR_mkdir			( 39)
+#define TARGET_NR_rmdir			( 40)
+#define TARGET_NR_dup			( 41)
+#define TARGET_NR_pipe			( 42)
+#define TARGET_NR_times			( 43)
+#define TARGET_NR_prof			( 44)	/* removed */
+#define TARGET_NR_brk			( 45)
+#define TARGET_NR_setgid			( 46)
+#define TARGET_NR_getgid			( 47)
+#define TARGET_NR_signal			( 48)	/* removed */
+#define TARGET_NR_geteuid			( 49)
+#define TARGET_NR_getegid			( 50)
+#define TARGET_NR_acct			( 51)
+#define TARGET_NR_umount2			( 52)
+#define TARGET_NR_lock			( 53)	/* removed */
+#define TARGET_NR_ioctl			( 54)
+#define TARGET_NR_fcntl			( 55)
+#define TARGET_NR_mpx			( 56)	/* removed */
+#define TARGET_NR_setpgid			( 57)
+#define TARGET_NR_ulimit			( 58)	/* removed */
+					/* 59 was sys_olduname */
+#define TARGET_NR_umask			( 60)
+#define TARGET_NR_chroot			( 61)
+#define TARGET_NR_ustat			( 62)
+#define TARGET_NR_dup2			( 63)
+#define TARGET_NR_getppid			( 64)
+#define TARGET_NR_getpgrp			( 65)
+#define TARGET_NR_setsid			( 66)
+#define TARGET_NR_sigaction			( 67)
+#define TARGET_NR_sgetmask			( 68)	/* removed */
+#define TARGET_NR_ssetmask			( 69)	/* removed */
+#define TARGET_NR_setreuid			( 70)
+#define TARGET_NR_setregid			( 71)
+#define TARGET_NR_sigsuspend			( 72)
+#define TARGET_NR_sigpending			( 73)
+#define TARGET_NR_sethostname		( 74)
+#define TARGET_NR_setrlimit			( 75)
+#define TARGET_NR_getrlimit			( 76)	/* Back compat 2GB limited rlimit */
+#define TARGET_NR_getrusage			( 77)
+#define TARGET_NR_gettimeofday		( 78)
+#define TARGET_NR_settimeofday		( 79)
+#define TARGET_NR_getgroups			( 80)
+#define TARGET_NR_setgroups			( 81)
+#define TARGET_NR_select			( 82)
+#define TARGET_NR_symlink			( 83)
+					/* 84 was sys_lstat */
+#define TARGET_NR_readlink			( 85)
+#define TARGET_NR_uselib			( 86)
+#define TARGET_NR_swapon			( 87)
+#define TARGET_NR_reboot			( 88)
+#define TARGET_NR_readdir			( 89)
+#define TARGET_NR_mmap			( 90)
+#define TARGET_NR_munmap			( 91)
+#define TARGET_NR_truncate			( 92)
+#define TARGET_NR_ftruncate			( 93)
+#define TARGET_NR_fchmod			( 94)
+#define TARGET_NR_fchown			( 95)
+#define TARGET_NR_getpriority		( 96)
+#define TARGET_NR_setpriority		( 97)
+#define TARGET_NR_profil			( 98)	/* removed */
+#define TARGET_NR_statfs			( 99)
+#define TARGET_NR_fstatfs			(100)
+#define TARGET_NR_ioperm			(101)
+#define TARGET_NR_socketcall			(102)
+#define TARGET_NR_syslog			(103)
+#define TARGET_NR_setitimer			(104)
+#define TARGET_NR_getitimer			(105)
+#define TARGET_NR_stat			(106)
+#define TARGET_NR_lstat			(107)
+#define TARGET_NR_fstat			(108)
+					/* 109 was sys_uname */
+					/* 110 was sys_iopl */
+#define TARGET_NR_vhangup			(111)
+#define TARGET_NR_idle			(112)
+#define TARGET_NR_syscall			(113) /* syscall to call a syscall! */
+#define TARGET_NR_wait4			(114)
+#define TARGET_NR_swapoff			(115)
+#define TARGET_NR_sysinfo			(116)
+#define TARGET_NR_ipc			(117)
+#define TARGET_NR_fsync			(118)
+#define TARGET_NR_sigreturn			(119)
+#define TARGET_NR_clone			(120)
+#define TARGET_NR_setdomainname		(121)
+#define TARGET_NR_uname			(122)
+#define TARGET_NR_modify_ldt			(123)
+#define TARGET_NR_adjtimex			(124)
+#define TARGET_NR_mprotect			(125)
+#define TARGET_NR_sigprocmask		(126)
+#define TARGET_NR_create_module		(127)	/* removed */
+#define TARGET_NR_init_module		(128)
+#define TARGET_NR_delete_module		(129)
+#define TARGET_NR_get_kernel_syms		(130)	/* removed */
+#define TARGET_NR_quotactl			(131)
+#define TARGET_NR_getpgid			(132)
+#define TARGET_NR_fchdir			(133)
+#define TARGET_NR_bdflush			(134)
+#define TARGET_NR_sysfs			(135)
+#define TARGET_NR_personality		(136)
+#define TARGET_NR_afs_syscall		(137) /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid			(138)
+#define TARGET_NR_setfsgid			(139)
+#define TARGET_NR__llseek			(140)
+#define TARGET_NR_getdents			(141)
+#define TARGET_NR__newselect			(142)
+#define TARGET_NR_flock			(143)
+#define TARGET_NR_msync			(144)
+#define TARGET_NR_readv			(145)
+#define TARGET_NR_writev			(146)
+#define TARGET_NR_getsid			(147)
+#define TARGET_NR_fdatasync			(148)
+#define TARGET_NR__sysctl			(149)
+#define TARGET_NR_mlock			(150)
+#define TARGET_NR_munlock			(151)
+#define TARGET_NR_mlockall			(152)
+#define TARGET_NR_munlockall			(153)
+#define TARGET_NR_sched_setparam		(154)
+#define TARGET_NR_sched_getparam		(155)
+#define TARGET_NR_sched_setscheduler		(156)
+#define TARGET_NR_sched_getscheduler		(157)
+#define TARGET_NR_sched_yield		(158)
+#define TARGET_NR_sched_get_priority_max	(159)
+#define TARGET_NR_sched_get_priority_min	(160)
+#define TARGET_NR_sched_rr_get_interval	(161)
+#define TARGET_NR_nanosleep			(162)
+#define TARGET_NR_mremap			(163)
+#define TARGET_NR_setresuid			(164)
+#define TARGET_NR_getresuid			(165)
+#define TARGET_NR_vm86			(166)	/* removed */
+#define TARGET_NR_query_module		(167)	/* removed */
+#define TARGET_NR_poll			(168)
+#define TARGET_NR_nfsservctl			(169)
+#define TARGET_NR_setresgid			(170)
+#define TARGET_NR_getresgid			(171)
+#define TARGET_NR_prctl			(172)
+#define TARGET_NR_rt_sigreturn		(173)
+#define TARGET_NR_rt_sigaction		(174)
+#define TARGET_NR_rt_sigprocmask		(175)
+#define TARGET_NR_rt_sigpending		(176)
+#define TARGET_NR_rt_sigtimedwait		(177)
+#define TARGET_NR_rt_sigqueueinfo		(178)
+#define TARGET_NR_rt_sigsuspend		(179)
+#define TARGET_NR_pread			(180)
+#define TARGET_NR_pwrite			(181)
+#define TARGET_NR_chown			(182)
+#define TARGET_NR_getcwd			(183)
+#define TARGET_NR_capget			(184)
+#define TARGET_NR_capset			(185)
+#define TARGET_NR_sigaltstack		(186)
+#define TARGET_NR_sendfile			(187)
+					/* 188 reserved */
+					/* 189 reserved */
+#define TARGET_NR_vfork			(190)
+#define TARGET_NR_ugetrlimit			(191)	/* SuS compliant getrlimit */
+#define TARGET_NR_mmap2			(192)
+#define TARGET_NR_truncate64			(193)
+#define TARGET_NR_ftruncate64		(194)
+#define TARGET_NR_stat64			(195)
+#define TARGET_NR_lstat64			(196)
+#define TARGET_NR_fstat64			(197)
+#define TARGET_NR_lchown32			(198)
+#define TARGET_NR_getuid32			(199)
+#define TARGET_NR_getgid32			(200)
+#define TARGET_NR_geteuid32			(201)
+#define TARGET_NR_getegid32			(202)
+#define TARGET_NR_setreuid32			(203)
+#define TARGET_NR_setregid32			(204)
+#define TARGET_NR_getgroups32		(205)
+#define TARGET_NR_setgroups32		(206)
+#define TARGET_NR_fchown32			(207)
+#define TARGET_NR_setresuid32		(208)
+#define TARGET_NR_getresuid32		(209)
+#define TARGET_NR_setresgid32		(210)
+#define TARGET_NR_getresgid32		(211)
+#define TARGET_NR_chown32			(212)
+#define TARGET_NR_setuid32			(213)
+#define TARGET_NR_setgid32			(214)
+#define TARGET_NR_setfsuid32			(215)
+#define TARGET_NR_setfsgid32			(216)
+#define TARGET_NR_getdents64			(217)
+#define TARGET_NR_pivot_root			(218)
+#define TARGET_NR_mincore			(219)
+#define TARGET_NR_madvise			(220)
+#define TARGET_NR_fcntl64			(221)
+					/* 222 for tux */
+					/* 223 is unused */
+#define TARGET_NR_gettid			(224)
+#define TARGET_NR_readahead			(225)
+#define TARGET_NR_setxattr			(226)
+#define TARGET_NR_lsetxattr			(227)
+#define TARGET_NR_fsetxattr			(228)
+#define TARGET_NR_getxattr			(229)
+#define TARGET_NR_lgetxattr			(230)
+#define TARGET_NR_fgetxattr			(231)
+#define TARGET_NR_listxattr			(232)
+#define TARGET_NR_llistxattr			(233)
+#define TARGET_NR_flistxattr			(234)
+#define TARGET_NR_removexattr		(235)
+#define TARGET_NR_lremovexattr		(236)
+#define TARGET_NR_fremovexattr		(237)
+#define TARGET_NR_tkill			(238)
+#define TARGET_NR_sendfile64			(239)
+#define TARGET_NR_futex			(240)
+#define TARGET_NR_sched_setaffinity		(241)
+#define TARGET_NR_sched_getaffinity		(242)
+#define TARGET_NR_io_setup			(243)
+#define TARGET_NR_io_destroy			(244)
+#define TARGET_NR_io_getevents		(245)
+#define TARGET_NR_io_submit			(246)
+#define TARGET_NR_io_cancel			(247)
+#define TARGET_NR_exit_group			(248)
+#define TARGET_NR_lookup_dcookie		(249)
+#define TARGET_NR_epoll_create		(250)
+#define TARGET_NR_epoll_ctl			(251)
+#define TARGET_NR_epoll_wait			(252)
+#define TARGET_NR_remap_file_pages		(253)
+					/* 254 for set_thread_area */
+					/* 255 for get_thread_area */
+					/* 256 for set_tid_address */
+#define TARGET_NR_set_tid_address		256
+#define TARGET_NR_timer_create		257
+#define TARGET_NR_timer_settime		258
+#define TARGET_NR_timer_gettime		259
+#define TARGET_NR_timer_getoverrun		260
+#define TARGET_NR_timer_delete		261
+#define TARGET_NR_clock_settime		262
+#define TARGET_NR_clock_gettime		263
+#define TARGET_NR_clock_getres		264
+#define TARGET_NR_clock_nanosleep		265
+#define TARGET_NR_statfs64			266
+#define TARGET_NR_fstatfs64			267
+#define TARGET_NR_tgkill			268
+#define TARGET_NR_utimes			269
+#define TARGET_NR_arm_fadvise64_64		270
+#define TARGET_NR_pciconfig_iobase		271
+#define TARGET_NR_pciconfig_read		272
+#define TARGET_NR_pciconfig_write		273
+#define TARGET_NR_mq_open			274
+#define TARGET_NR_mq_unlink			275
+#define TARGET_NR_mq_timedsend		276
+#define TARGET_NR_mq_timedreceive		277
+#define TARGET_NR_mq_notify			278
+#define TARGET_NR_mq_getsetattr		279
+#define TARGET_NR_waitid			280
+#define TARGET_NR_socket			281
+#define TARGET_NR_bind			282
+#define TARGET_NR_connect			283
+#define TARGET_NR_listen			284
+#define TARGET_NR_accept			285
+#define TARGET_NR_getsockname		286
+#define TARGET_NR_getpeername		287
+#define TARGET_NR_socketpair			288
+#define TARGET_NR_send			289
+#define TARGET_NR_sendto			290
+#define TARGET_NR_recv			291
+#define TARGET_NR_recvfrom			292
+#define TARGET_NR_shutdown			293
+#define TARGET_NR_setsockopt			294
+#define TARGET_NR_getsockopt			295
+#define TARGET_NR_sendmsg			296
+#define TARGET_NR_recvmsg			297
+#define TARGET_NR_semop			298
+#define TARGET_NR_semget			299
+#define TARGET_NR_semctl			300
+#define TARGET_NR_msgsnd			301
+#define TARGET_NR_msgrcv			302
+#define TARGET_NR_msgget			303
+#define TARGET_NR_msgctl			304
+#define TARGET_NR_shmat			305
+#define TARGET_NR_shmdt			306
+#define TARGET_NR_shmget			307
+#define TARGET_NR_shmctl			308
+#define TARGET_NR_add_key			309
+#define TARGET_NR_request_key		310
+#define TARGET_NR_keyctl			311
+#define TARGET_NR_semtimedop			312
+#define TARGET_NR_vserver			313
+#define TARGET_NR_ioprio_set			314
+#define TARGET_NR_ioprio_get			315
+#define TARGET_NR_inotify_init		316
+#define TARGET_NR_inotify_add_watch		317
+#define TARGET_NR_inotify_rm_watch		318
+#define TARGET_NR_mbind			319
+#define TARGET_NR_get_mempolicy		320
+#define TARGET_NR_set_mempolicy		321
+#define TARGET_NR_openat			(322)
+#define TARGET_NR_mkdirat			(323)
+#define TARGET_NR_mknodat			(324)
+#define TARGET_NR_fchownat			(325)
+#define TARGET_NR_futimesat			(326)
+#define TARGET_NR_fstatat64			(327)
+#define TARGET_NR_unlinkat			(328)
+#define TARGET_NR_renameat			(329)
+#define TARGET_NR_linkat			(330)
+#define TARGET_NR_symlinkat			(331)
+#define TARGET_NR_readlinkat			(332)
+#define TARGET_NR_fchmodat			(333)
+#define TARGET_NR_faccessat			(334)
+#define TARGET_NR_pselect6			(335)
+					/* 336 for ppoll */
+#define TARGET_NR_unshare			(337)
+#define TARGET_NR_set_robust_list		(338)
+#define TARGET_NR_get_robust_list		(339)
+#define TARGET_NR_splice			(340)
+#define TARGET_NR_arm_sync_file_range	(341)
+#define TARGET_NR_sync_file_range2		TARGET_NR_arm_sync_file_range
+#define TARGET_NR_tee			(342)
+#define TARGET_NR_vmsplice			(343)
+#define TARGET_NR_move_pages			(344)
+#define TARGET_NR_getcpu			(345)
+					/* 346 for epoll_pwait */
+#define TARGET_NR_kexec_load			(347)
+#define TARGET_NR_utimensat			(348)
+#define TARGET_NR_signalfd			(349)
+#define TARGET_NR_timerfd			(350)
+#define TARGET_NR_eventfd			(351)
+#define TARGET_NR_fallocate			(352)
+#define TARGET_NR_timerfd_settime		(353)
+#define TARGET_NR_timerfd_gettime		(354)
+#define TARGET_NR_signalfd4			(355)
+#define TARGET_NR_eventfd2			(356)
+#define TARGET_NR_epoll_create1		(357)
+#define TARGET_NR_dup3				(358)
+#define TARGET_NR_pipe2			(359)
+#define TARGET_NR_inotify_init1		(360)
+#define TARGET_NR_preadv                       (361)
+#define TARGET_NR_pwritev                      (362)
+#define TARGET_NR_rt_tgsigqueueinfo            (363)
+#define TARGET_NR_perf_event_open              (364)
+#define TARGET_NR_recvmmsg                     (365)
+#define TARGET_NR_accept4                      (366)
+#define TARGET_NR_fanotify_init                (367)
+#define TARGET_NR_fanotify_mark                (368)
+#define TARGET_NR_prlimit64                    (369)
+#define TARGET_NR_name_to_handle_at            (370)
+#define TARGET_NR_open_by_handle_at            (371)
+#define TARGET_NR_clock_adjtime                (372)
+#define TARGET_NR_syncfs                       (373)
diff --git a/qemu-0.15.x/linux-user/arm/target_signal.h b/qemu-0.15.x/linux-user/arm/target_signal.h
new file mode 100644
index 0000000..2b32813
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+   return state->regs[13];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/arm/termbits.h b/qemu-0.15.x/linux-user/arm/termbits.h
new file mode 100644
index 0000000..7772df1
--- /dev/null
+++ b/qemu-0.15.x/linux-user/arm/termbits.h
@@ -0,0 +1,216 @@
+/* from asm/termbits.h */
+/* NOTE: exactly the same as i386 */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VTIME	5
+#define TARGET_VMIN	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+#define TARGET_VEOL	11
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOL2	16
+
+/* ioctls */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/linux-user/cpu-uname.c b/qemu-0.15.x/linux-user/cpu-uname.c
new file mode 100644
index 0000000..23afede
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cpu-uname.c
@@ -0,0 +1,72 @@
+/*
+ *  cpu to uname machine name map
+ *
+ *  Copyright (c) 2009 Loïc Minier
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "qemu.h"
+//#include "qemu-common.h"
+#include "cpu-uname.h"
+
+/* return highest utsname machine name for emulated instruction set
+ *
+ * NB: the default emulated CPU ("any") might not match any existing CPU, e.g.
+ * on ARM it has all features turned on, so there is no perfect arch string to
+ * return here */
+const char *cpu_to_uname_machine(void *cpu_env)
+{
+#ifdef TARGET_ARM
+    /* utsname machine name on linux arm is CPU arch name + endianness, e.g.
+     * armv7l; to get a list of CPU arch names from the linux source, use:
+     *     grep arch_name: -A1 linux/arch/arm/mm/proc-*.S
+     * see arch/arm/kernel/setup.c: setup_processor()
+     *
+     * to test by CPU id, compare cpu_env->cp15.c0_cpuid to ARM_CPUID_*
+     * defines and to test by CPU feature, use arm_feature(cpu_env,
+     * ARM_FEATURE_*) */
+
+    /* in theory, endianness is configurable on some ARM CPUs, but this isn't
+     * used in user mode emulation */
+#ifdef TARGET_WORDS_BIGENDIAN
+#define utsname_suffix "b"
+#else
+#define utsname_suffix "l"
+#endif
+    if (arm_feature(cpu_env, ARM_FEATURE_V7))
+        return "armv7" utsname_suffix;
+    if (arm_feature(cpu_env, ARM_FEATURE_V6))
+        return "armv6" utsname_suffix;
+    /* earliest emulated CPU is ARMv5TE; qemu can emulate the 1026, but not its
+     * Jazelle support */
+    return "armv5te" utsname_suffix;
+#elif defined(TARGET_X86_64)
+    return "x86-64";
+#elif defined(TARGET_I386)
+    /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */
+    uint32_t cpuid_version = ((CPUX86State *)cpu_env)->cpuid_version;
+    int family = ((cpuid_version >> 8) & 0x0f) + ((cpuid_version >> 20) & 0xff);
+    if (family == 4)
+        return "i486";
+    if (family == 5)
+        return "i586";
+    return "i686";
+#else
+    /* default is #define-d in each arch/ subdir */
+    return UNAME_MACHINE;
+#endif
+}
diff --git a/qemu-0.15.x/linux-user/cpu-uname.h b/qemu-0.15.x/linux-user/cpu-uname.h
new file mode 100644
index 0000000..32492de
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cpu-uname.h
@@ -0,0 +1 @@
+const char *cpu_to_uname_machine(void *cpu_env);
diff --git a/qemu-0.15.x/linux-user/cris/syscall.h b/qemu-0.15.x/linux-user/cris/syscall.h
new file mode 100644
index 0000000..24f92ba
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cris/syscall.h
@@ -0,0 +1,36 @@
+
+#define UNAME_MACHINE "cris"
+
+/* pt_regs not only specifices the format in the user-struct during
+ * ptrace but is also the frame format used in the kernel prologue/epilogues
+ * themselves
+ */
+
+struct target_pt_regs {
+        unsigned long orig_r10;
+        /* pushed by movem r13, [sp] in SAVE_ALL. */
+        unsigned long r0;
+        unsigned long r1;
+        unsigned long r2;
+        unsigned long r3;
+        unsigned long r4;
+        unsigned long r5;
+        unsigned long r6;
+        unsigned long r7;
+        unsigned long r8;
+        unsigned long r9;
+        unsigned long r10;
+        unsigned long r11;
+        unsigned long r12;
+        unsigned long r13;
+        unsigned long acr;
+        unsigned long srs;
+        unsigned long mof;
+        unsigned long spc;
+        unsigned long ccs;
+        unsigned long srp;
+        unsigned long erp; /* This is actually the debugged process' PC */
+        /* For debugging purposes; saved only when needed. */
+        unsigned long exs;
+        unsigned long eda;
+};
diff --git a/qemu-0.15.x/linux-user/cris/syscall_nr.h b/qemu-0.15.x/linux-user/cris/syscall_nr.h
new file mode 100644
index 0000000..98f1a0b
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cris/syscall_nr.h
@@ -0,0 +1,337 @@
+/*
+ * This file contains the system call numbers, and stub macros for libc.
+ */
+
+#define TARGET_NR_restart_syscall      0
+#define TARGET_NR_exit		  1
+#define TARGET_NR_fork		  2
+#define TARGET_NR_read		  3
+#define TARGET_NR_write		  4
+#define TARGET_NR_open		  5
+#define TARGET_NR_close		  6
+#define TARGET_NR_waitpid		  7
+#define TARGET_NR_creat		  8
+#define TARGET_NR_link		  9
+#define TARGET_NR_unlink		 10
+#define TARGET_NR_execve		 11
+#define TARGET_NR_chdir		 12
+#define TARGET_NR_time		 13
+#define TARGET_NR_mknod		 14
+#define TARGET_NR_chmod		 15
+#define TARGET_NR_lchown		 16
+#define TARGET_NR_break		 17
+#define TARGET_NR_oldstat		 18
+#define TARGET_NR_lseek		 19
+#define TARGET_NR_getpid		 20
+#define TARGET_NR_mount		 21
+#define TARGET_NR_umount		 22
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getuid		 24
+#define TARGET_NR_stime		 25
+#define TARGET_NR_ptrace		 26
+#define TARGET_NR_alarm		 27
+#define TARGET_NR_oldfstat		 28
+#define TARGET_NR_pause		 29
+#define TARGET_NR_utime		 30
+#define TARGET_NR_stty		 31
+#define TARGET_NR_gtty		 32
+#define TARGET_NR_access		 33
+#define TARGET_NR_nice		 34
+#define TARGET_NR_ftime		 35
+#define TARGET_NR_sync		 36
+#define TARGET_NR_kill		 37
+#define TARGET_NR_rename		 38
+#define TARGET_NR_mkdir		 39
+#define TARGET_NR_rmdir		 40
+#define TARGET_NR_dup		 41
+#define TARGET_NR_pipe		 42
+#define TARGET_NR_times		 43
+#define TARGET_NR_prof		 44
+#define TARGET_NR_brk		 45
+#define TARGET_NR_setgid		 46
+#define TARGET_NR_getgid		 47
+#define TARGET_NR_signal		 48
+#define TARGET_NR_geteuid		 49
+#define TARGET_NR_getegid		 50
+#define TARGET_NR_acct		 51
+#define TARGET_NR_umount2		 52
+#define TARGET_NR_lock		 53
+#define TARGET_NR_ioctl		 54
+#define TARGET_NR_fcntl		 55
+#define TARGET_NR_mpx		 56
+#define TARGET_NR_setpgid		 57
+#define TARGET_NR_ulimit		 58
+#define TARGET_NR_oldolduname	 59
+#define TARGET_NR_umask		 60
+#define TARGET_NR_chroot		 61
+#define TARGET_NR_ustat		 62
+#define TARGET_NR_dup2		 63
+#define TARGET_NR_getppid		 64
+#define TARGET_NR_getpgrp		 65
+#define TARGET_NR_setsid		 66
+#define TARGET_NR_sigaction		 67
+#define TARGET_NR_sgetmask		 68
+#define TARGET_NR_ssetmask		 69
+#define TARGET_NR_setreuid		 70
+#define TARGET_NR_setregid		 71
+#define TARGET_NR_sigsuspend		 72
+#define TARGET_NR_sigpending		 73
+#define TARGET_NR_sethostname	 74
+#define TARGET_NR_setrlimit		 75
+#define TARGET_NR_getrlimit		 76
+#define TARGET_NR_getrusage		 77
+#define TARGET_NR_gettimeofday	 78
+#define TARGET_NR_settimeofday	 79
+#define TARGET_NR_getgroups		 80
+#define TARGET_NR_setgroups		 81
+#define TARGET_NR_select		 82
+#define TARGET_NR_symlink		 83
+#define TARGET_NR_oldlstat		 84
+#define TARGET_NR_readlink		 85
+#define TARGET_NR_uselib		 86
+#define TARGET_NR_swapon		 87
+#define TARGET_NR_reboot		 88
+#define TARGET_NR_readdir		 89
+#define TARGET_NR_mmap		 90
+#define TARGET_NR_munmap		 91
+#define TARGET_NR_truncate		 92
+#define TARGET_NR_ftruncate		 93
+#define TARGET_NR_fchmod		 94
+#define TARGET_NR_fchown		 95
+#define TARGET_NR_getpriority	 96
+#define TARGET_NR_setpriority	 97
+#define TARGET_NR_profil		 98
+#define TARGET_NR_statfs		 99
+#define TARGET_NR_fstatfs		100
+#define TARGET_NR_ioperm		101
+#define TARGET_NR_socketcall		102
+#define TARGET_NR_syslog		103
+#define TARGET_NR_setitimer		104
+#define TARGET_NR_getitimer		105
+#define TARGET_NR_stat		106
+#define TARGET_NR_lstat		107
+#define TARGET_NR_fstat		108
+#define TARGET_NR_olduname		109
+#define TARGET_NR_iopl		110
+#define TARGET_NR_vhangup		111
+#define TARGET_NR_idle		112
+#define TARGET_NR_vm86		113
+#define TARGET_NR_wait4		114
+#define TARGET_NR_swapoff		115
+#define TARGET_NR_sysinfo		116
+#define TARGET_NR_ipc		117
+#define TARGET_NR_fsync		118
+#define TARGET_NR_sigreturn		119
+#define TARGET_NR_clone		120
+#define TARGET_NR_setdomainname	121
+#define TARGET_NR_uname		122
+#define TARGET_NR_modify_ldt		123
+#define TARGET_NR_adjtimex		124
+#define TARGET_NR_mprotect		125
+#define TARGET_NR_sigprocmask	126
+#define TARGET_NR_create_module	127
+#define TARGET_NR_init_module	128
+#define TARGET_NR_delete_module	129
+#define TARGET_NR_get_kernel_syms	130
+#define TARGET_NR_quotactl		131
+#define TARGET_NR_getpgid		132
+#define TARGET_NR_fchdir		133
+#define TARGET_NR_bdflush		134
+#define TARGET_NR_sysfs		135
+#define TARGET_NR_personality	136
+#define TARGET_NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid		138
+#define TARGET_NR_setfsgid		139
+#define TARGET_NR__llseek		140
+#define TARGET_NR_getdents		141
+#define TARGET_NR__newselect		142
+#define TARGET_NR_flock		143
+#define TARGET_NR_msync		144
+#define TARGET_NR_readv		145
+#define TARGET_NR_writev		146
+#define TARGET_NR_getsid		147
+#define TARGET_NR_fdatasync		148
+#define TARGET_NR__sysctl		149
+#define TARGET_NR_mlock		150
+#define TARGET_NR_munlock		151
+#define TARGET_NR_mlockall		152
+#define TARGET_NR_munlockall		153
+#define TARGET_NR_sched_setparam		154
+#define TARGET_NR_sched_getparam		155
+#define TARGET_NR_sched_setscheduler		156
+#define TARGET_NR_sched_getscheduler		157
+#define TARGET_NR_sched_yield		158
+#define TARGET_NR_sched_get_priority_max	159
+#define TARGET_NR_sched_get_priority_min	160
+#define TARGET_NR_sched_rr_get_interval	161
+#define TARGET_NR_nanosleep		162
+#define TARGET_NR_mremap		163
+#define TARGET_NR_setresuid		164
+#define TARGET_NR_getresuid		165
+
+#define TARGET_NR_query_module	167
+#define TARGET_NR_poll		168
+#define TARGET_NR_nfsservctl		169
+#define TARGET_NR_setresgid		170
+#define TARGET_NR_getresgid		171
+#define TARGET_NR_prctl              172
+#define TARGET_NR_rt_sigreturn	173
+#define TARGET_NR_rt_sigaction	174
+#define TARGET_NR_rt_sigprocmask	175
+#define TARGET_NR_rt_sigpending	176
+#define TARGET_NR_rt_sigtimedwait	177
+#define TARGET_NR_rt_sigqueueinfo	178
+#define TARGET_NR_rt_sigsuspend	179
+#define TARGET_NR_pread64		180
+#define TARGET_NR_pwrite64		181
+#define TARGET_NR_chown		182
+#define TARGET_NR_getcwd		183
+#define TARGET_NR_capget		184
+#define TARGET_NR_capset		185
+#define TARGET_NR_sigaltstack	186
+#define TARGET_NR_sendfile		187
+#define TARGET_NR_getpmsg		188	/* some people actually want streams */
+#define TARGET_NR_putpmsg		189	/* some people actually want streams */
+#define TARGET_NR_vfork		190
+#define TARGET_NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define TARGET_NR_mmap2		192
+#define TARGET_NR_truncate64		193
+#define TARGET_NR_ftruncate64	194
+#define TARGET_NR_stat64		195
+#define TARGET_NR_lstat64		196
+#define TARGET_NR_fstat64		197
+#define TARGET_NR_lchown32		198
+#define TARGET_NR_getuid32		199
+#define TARGET_NR_getgid32		200
+#define TARGET_NR_geteuid32		201
+#define TARGET_NR_getegid32		202
+#define TARGET_NR_setreuid32		203
+#define TARGET_NR_setregid32		204
+#define TARGET_NR_getgroups32	205
+#define TARGET_NR_setgroups32	206
+#define TARGET_NR_fchown32		207
+#define TARGET_NR_setresuid32	208
+#define TARGET_NR_getresuid32	209
+#define TARGET_NR_setresgid32	210
+#define TARGET_NR_getresgid32	211
+#define TARGET_NR_chown32		212
+#define TARGET_NR_setuid32		213
+#define TARGET_NR_setgid32		214
+#define TARGET_NR_setfsuid32		215
+#define TARGET_NR_setfsgid32		216
+#define TARGET_NR_pivot_root		217
+#define TARGET_NR_mincore		218
+#define TARGET_NR_madvise		219
+#define TARGET_NR_getdents64		220
+#define TARGET_NR_fcntl64		221
+/* 223 is unused */
+#define TARGET_NR_gettid             224
+#define TARGET_NR_readahead          225
+#define TARGET_NR_setxattr		226
+#define TARGET_NR_lsetxattr		227
+#define TARGET_NR_fsetxattr		228
+#define TARGET_NR_getxattr		229
+#define TARGET_NR_lgetxattr		230
+#define TARGET_NR_fgetxattr		231
+#define TARGET_NR_listxattr		232
+#define TARGET_NR_llistxattr		233
+#define TARGET_NR_flistxattr		234
+#define TARGET_NR_removexattr	235
+#define TARGET_NR_lremovexattr	236
+#define TARGET_NR_fremovexattr	237
+#define TARGET_NR_tkill		238
+#define TARGET_NR_sendfile64		239
+#define TARGET_NR_futex		240
+#define TARGET_NR_sched_setaffinity	241
+#define TARGET_NR_sched_getaffinity	242
+#define TARGET_NR_set_thread_area	243
+#define TARGET_NR_get_thread_area	244
+#define TARGET_NR_io_setup		245
+#define TARGET_NR_io_destroy		246
+#define TARGET_NR_io_getevents	247
+#define TARGET_NR_io_submit		248
+#define TARGET_NR_io_cancel		249
+#define TARGET_NR_fadvise64		250
+#define TARGET_NR_exit_group		252
+#define TARGET_NR_lookup_dcookie	253
+#define TARGET_NR_epoll_create	254
+#define TARGET_NR_epoll_ctl		255
+#define TARGET_NR_epoll_wait		256
+#define TARGET_NR_remap_file_pages	257
+#define TARGET_NR_set_tid_address	258
+#define TARGET_NR_timer_create	259
+#define TARGET_NR_timer_settime	(TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime	(TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete	(TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime	(TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
+#define TARGET_NR_statfs64		268
+#define TARGET_NR_fstatfs64		269
+#define TARGET_NR_tgkill		270
+#define TARGET_NR_utimes		271
+#define TARGET_NR_fadvise64_64	272
+#define TARGET_NR_vserver		273
+#define TARGET_NR_mbind		274
+#define TARGET_NR_get_mempolicy	275
+#define TARGET_NR_set_mempolicy	276
+#define TARGET_NR_mq_open 		277
+#define TARGET_NR_mq_unlink		(TARGET_NR_mq_open+1)
+#define TARGET_NR_mq_timedsend	(TARGET_NR_mq_open+2)
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_mq_open+3)
+#define TARGET_NR_mq_notify		(TARGET_NR_mq_open+4)
+#define TARGET_NR_mq_getsetattr	(TARGET_NR_mq_open+5)
+#define TARGET_NR_kexec_load		283
+#define TARGET_NR_waitid		284
+/* #define TARGET_NR_sys_setaltroot	285 */
+#define TARGET_NR_add_key		286
+#define TARGET_NR_request_key	287
+#define TARGET_NR_keyctl		288
+#define TARGET_NR_ioprio_set         289
+#define TARGET_NR_ioprio_get         290
+#define TARGET_NR_inotify_init       291
+#define TARGET_NR_inotify_add_watch  292
+#define TARGET_NR_inotify_rm_watch   293
+#define TARGET_NR_migrate_pages      294
+#define TARGET_NR_openat             295
+#define TARGET_NR_mkdirat            296
+#define TARGET_NR_mknodat            297
+#define TARGET_NR_fchownat           298
+#define TARGET_NR_futimesat          299
+#define TARGET_NR_fstatat64          300
+#define TARGET_NR_unlinkat           301
+#define TARGET_NR_renameat           302
+#define TARGET_NR_linkat             303
+#define TARGET_NR_symlinkat          304
+#define TARGET_NR_readlinkat         305
+#define TARGET_NR_fchmodat           306
+#define TARGET_NR_faccessat          307
+#define TARGET_NR_pselect6           308
+#define TARGET_NR_ppoll              309
+#define TARGET_NR_unshare            310
+#define TARGET_NR_set_robust_list    311
+#define TARGET_NR_get_robust_list    312
+#define TARGET_NR_splice             313
+#define TARGET_NR_sync_file_range    314
+#define TARGET_NR_tee                315
+#define TARGET_NR_vmsplice           316
+#define TARGET_NR_move_pages         317
+#define TARGET_NR_getcpu             318
+#define TARGET_NR_epoll_pwait        319
+#define TARGET_NR_utimensat          320
+#define TARGET_NR_signalfd           321
+#define TARGET_NR_timerfd_create     322
+#define TARGET_NR_eventfd            323
+#define TARGET_NR_fallocate          324
+#define TARGET_NR_timerfd_settime    325
+#define TARGET_NR_timerfd_gettime    326
+#define TARGET_NR_signalfd4          327
+#define TARGET_NR_eventfd2           328
+#define TARGET_NR_epoll_create1      329
+#define TARGET_NR_dup3               330
+#define TARGET_NR_pipe2              331
+#define TARGET_NR_inotify_init1      332
+#define TARGET_NR_preadv             333
+#define TARGET_NR_pwritev            334
diff --git a/qemu-0.15.x/linux-user/cris/target_signal.h b/qemu-0.15.x/linux-user/cris/target_signal.h
new file mode 100644
index 0000000..5611840
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cris/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_ulong ss_size;
+	abi_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state)
+{
+    return state->regs[14];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/cris/termbits.h b/qemu-0.15.x/linux-user/cris/termbits.h
new file mode 100644
index 0000000..fc82ca0
--- /dev/null
+++ b/qemu-0.15.x/linux-user/cris/termbits.h
@@ -0,0 +1,213 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CRTSCTS   020000000000          /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VTIME	5
+#define TARGET_VMIN	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+#define TARGET_VEOL	11
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOL2	16
+
+/* ioctls */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/linux-user/elfload.c b/qemu-0.15.x/linux-user/elfload.c
new file mode 100644
index 0000000..443d246
--- /dev/null
+++ b/qemu-0.15.x/linux-user/elfload.c
@@ -0,0 +1,2703 @@
+/* This is the Linux kernel elf-loading code, ported into user space */
+#include <sys/time.h>
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "qemu.h"
+#include "disas.h"
+
+#ifdef _ARCH_PPC64
+#undef ARCH_DLINFO
+#undef ELF_PLATFORM
+#undef ELF_HWCAP
+#undef ELF_CLASS
+#undef ELF_DATA
+#undef ELF_ARCH
+#endif
+
+#define ELF_OSABI   ELFOSABI_SYSV
+
+/* from personality.h */
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+    ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
+    FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
+                                           descriptors (signal handling) */
+    MMAP_PAGE_ZERO =    0x0100000,
+    ADDR_COMPAT_LAYOUT = 0x0200000,
+    READ_IMPLIES_EXEC = 0x0400000,
+    ADDR_LIMIT_32BIT =  0x0800000,
+    SHORT_INODE =       0x1000000,
+    WHOLE_SECONDS =     0x2000000,
+    STICKY_TIMEOUTS =   0x4000000,
+    ADDR_LIMIT_3GB =    0x8000000,
+};
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+    PER_LINUX =         0x0000,
+    PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
+    PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
+    PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+    PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
+    PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
+    PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
+    PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
+    PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
+    PER_BSD =           0x0006,
+    PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
+    PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
+    PER_LINUX32 =       0x0008,
+    PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
+    PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
+    PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
+    PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
+    PER_RISCOS =        0x000c,
+    PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
+    PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+    PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
+    PER_HPUX =          0x0010,
+    PER_MASK =          0x00ff,
+};
+
+/*
+ * Return the base personality without flags.
+ */
+#define personality(pers)       (pers & PER_MASK)
+
+/* this flag is uneffective under linux too, should be deleted */
+#ifndef MAP_DENYWRITE
+#define MAP_DENYWRITE 0
+#endif
+
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA        ELFDATA2MSB
+#else
+#define ELF_DATA        ELFDATA2LSB
+#endif
+
+typedef target_ulong    target_elf_greg_t;
+#ifdef USE_UID16
+typedef target_ushort   target_uid_t;
+typedef target_ushort   target_gid_t;
+#else
+typedef target_uint     target_uid_t;
+typedef target_uint     target_gid_t;
+#endif
+typedef target_int      target_pid_t;
+
+#ifdef TARGET_I386
+
+#define ELF_PLATFORM get_elf_platform()
+
+static const char *get_elf_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (thread_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+    return thread_env->cpuid_features;
+}
+
+#ifdef TARGET_X86_64
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_ARCH       EM_X86_64
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+}
+
+#define ELF_NREG    27
+typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
+
+/*
+ * Note that ELF_NREG should be 29 as there should be place for
+ * TRAPNO and ERR "registers" as well but linux doesn't dump
+ * those.
+ *
+ * See linux kernel: arch/x86/include/asm/elf.h
+ */
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = env->regs[15];
+    (*regs)[1] = env->regs[14];
+    (*regs)[2] = env->regs[13];
+    (*regs)[3] = env->regs[12];
+    (*regs)[4] = env->regs[R_EBP];
+    (*regs)[5] = env->regs[R_EBX];
+    (*regs)[6] = env->regs[11];
+    (*regs)[7] = env->regs[10];
+    (*regs)[8] = env->regs[9];
+    (*regs)[9] = env->regs[8];
+    (*regs)[10] = env->regs[R_EAX];
+    (*regs)[11] = env->regs[R_ECX];
+    (*regs)[12] = env->regs[R_EDX];
+    (*regs)[13] = env->regs[R_ESI];
+    (*regs)[14] = env->regs[R_EDI];
+    (*regs)[15] = env->regs[R_EAX]; /* XXX */
+    (*regs)[16] = env->eip;
+    (*regs)[17] = env->segs[R_CS].selector & 0xffff;
+    (*regs)[18] = env->eflags;
+    (*regs)[19] = env->regs[R_ESP];
+    (*regs)[20] = env->segs[R_SS].selector & 0xffff;
+    (*regs)[21] = env->segs[R_FS].selector & 0xffff;
+    (*regs)[22] = env->segs[R_GS].selector & 0xffff;
+    (*regs)[23] = env->segs[R_DS].selector & 0xffff;
+    (*regs)[24] = env->segs[R_ES].selector & 0xffff;
+    (*regs)[25] = env->segs[R_FS].selector & 0xffff;
+    (*regs)[26] = env->segs[R_GS].selector & 0xffff;
+}
+
+#else
+
+#define ELF_START_MMAP 0x80000000
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS       ELFCLASS32
+#define ELF_ARCH        EM_386
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->esp = infop->start_stack;
+    regs->eip = infop->entry;
+
+    /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+       starts %edx contains a pointer to a function which might be
+       registered using `atexit'.  This provides a mean for the
+       dynamic linker to call DT_FINI functions for shared libraries
+       that have been loaded before the code runs.
+
+       A value of 0 tells we have no such handler.  */
+    regs->edx = 0;
+}
+
+#define ELF_NREG    17
+typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
+
+/*
+ * Note that ELF_NREG should be 19 as there should be place for
+ * TRAPNO and ERR "registers" as well but linux doesn't dump
+ * those.
+ *
+ * See linux kernel: arch/x86/include/asm/elf.h
+ */
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = env->regs[R_EBX];
+    (*regs)[1] = env->regs[R_ECX];
+    (*regs)[2] = env->regs[R_EDX];
+    (*regs)[3] = env->regs[R_ESI];
+    (*regs)[4] = env->regs[R_EDI];
+    (*regs)[5] = env->regs[R_EBP];
+    (*regs)[6] = env->regs[R_EAX];
+    (*regs)[7] = env->segs[R_DS].selector & 0xffff;
+    (*regs)[8] = env->segs[R_ES].selector & 0xffff;
+    (*regs)[9] = env->segs[R_FS].selector & 0xffff;
+    (*regs)[10] = env->segs[R_GS].selector & 0xffff;
+    (*regs)[11] = env->regs[R_EAX]; /* XXX */
+    (*regs)[12] = env->eip;
+    (*regs)[13] = env->segs[R_CS].selector & 0xffff;
+    (*regs)[14] = env->eflags;
+    (*regs)[15] = env->regs[R_ESP];
+    (*regs)[16] = env->segs[R_SS].selector & 0xffff;
+}
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+#endif
+
+#ifdef TARGET_ARM
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_ARM )
+
+#define ELF_CLASS       ELFCLASS32
+#define ELF_ARCH        EM_ARM
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->ARM_cpsr = 0x10;
+    if (infop->entry & 1)
+        regs->ARM_cpsr |= CPSR_T;
+    regs->ARM_pc = infop->entry & 0xfffffffe;
+    regs->ARM_sp = infop->start_stack;
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->ARM_r2, stack + 8); /* envp */
+    get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->ARM_r0 = 0;
+    /* For uClinux PIC binaries.  */
+    /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
+    regs->ARM_r10 = infop->start_data;
+}
+
+#define ELF_NREG    18
+typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = tswapl(env->regs[0]);
+    (*regs)[1] = tswapl(env->regs[1]);
+    (*regs)[2] = tswapl(env->regs[2]);
+    (*regs)[3] = tswapl(env->regs[3]);
+    (*regs)[4] = tswapl(env->regs[4]);
+    (*regs)[5] = tswapl(env->regs[5]);
+    (*regs)[6] = tswapl(env->regs[6]);
+    (*regs)[7] = tswapl(env->regs[7]);
+    (*regs)[8] = tswapl(env->regs[8]);
+    (*regs)[9] = tswapl(env->regs[9]);
+    (*regs)[10] = tswapl(env->regs[10]);
+    (*regs)[11] = tswapl(env->regs[11]);
+    (*regs)[12] = tswapl(env->regs[12]);
+    (*regs)[13] = tswapl(env->regs[13]);
+    (*regs)[14] = tswapl(env->regs[14]);
+    (*regs)[15] = tswapl(env->regs[15]);
+
+    (*regs)[16] = tswapl(cpsr_read((CPUState *)env));
+    (*regs)[17] = tswapl(env->regs[0]); /* XXX */
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+enum
+{
+    ARM_HWCAP_ARM_SWP       = 1 << 0,
+    ARM_HWCAP_ARM_HALF      = 1 << 1,
+    ARM_HWCAP_ARM_THUMB     = 1 << 2,
+    ARM_HWCAP_ARM_26BIT     = 1 << 3,
+    ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+    ARM_HWCAP_ARM_FPA       = 1 << 5,
+    ARM_HWCAP_ARM_VFP       = 1 << 6,
+    ARM_HWCAP_ARM_EDSP      = 1 << 7,
+    ARM_HWCAP_ARM_JAVA      = 1 << 8,
+    ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
+    ARM_HWCAP_ARM_THUMBEE   = 1 << 10,
+    ARM_HWCAP_ARM_NEON      = 1 << 11,
+    ARM_HWCAP_ARM_VFPv3     = 1 << 12,
+    ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
+                   | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
+                   | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
+                   | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
+
+#endif
+
+#ifdef TARGET_UNICORE32
+
+#define ELF_START_MMAP          0x80000000
+
+#define elf_check_arch(x)       ((x) == EM_UNICORE32)
+
+#define ELF_CLASS               ELFCLASS32
+#define ELF_DATA                ELFDATA2LSB
+#define ELF_ARCH                EM_UNICORE32
+
+static inline void init_thread(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->UC32_REG_asr = 0x10;
+    regs->UC32_REG_pc = infop->entry & 0xfffffffe;
+    regs->UC32_REG_sp = infop->start_stack;
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
+    get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->UC32_REG_00 = 0;
+}
+
+#define ELF_NREG    34
+typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = env->regs[0];
+    (*regs)[1] = env->regs[1];
+    (*regs)[2] = env->regs[2];
+    (*regs)[3] = env->regs[3];
+    (*regs)[4] = env->regs[4];
+    (*regs)[5] = env->regs[5];
+    (*regs)[6] = env->regs[6];
+    (*regs)[7] = env->regs[7];
+    (*regs)[8] = env->regs[8];
+    (*regs)[9] = env->regs[9];
+    (*regs)[10] = env->regs[10];
+    (*regs)[11] = env->regs[11];
+    (*regs)[12] = env->regs[12];
+    (*regs)[13] = env->regs[13];
+    (*regs)[14] = env->regs[14];
+    (*regs)[15] = env->regs[15];
+    (*regs)[16] = env->regs[16];
+    (*regs)[17] = env->regs[17];
+    (*regs)[18] = env->regs[18];
+    (*regs)[19] = env->regs[19];
+    (*regs)[20] = env->regs[20];
+    (*regs)[21] = env->regs[21];
+    (*regs)[22] = env->regs[22];
+    (*regs)[23] = env->regs[23];
+    (*regs)[24] = env->regs[24];
+    (*regs)[25] = env->regs[25];
+    (*regs)[26] = env->regs[26];
+    (*regs)[27] = env->regs[27];
+    (*regs)[28] = env->regs[28];
+    (*regs)[29] = env->regs[29];
+    (*regs)[30] = env->regs[30];
+    (*regs)[31] = env->regs[31];
+
+    (*regs)[32] = cpu_asr_read((CPUState *)env);
+    (*regs)[33] = env->regs[0]; /* XXX */
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE               4096
+
+#define ELF_HWCAP                       (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)
+
+#endif
+
+#ifdef TARGET_SPARC
+#ifdef TARGET_SPARC64
+
+#define ELF_START_MMAP 0x80000000
+#define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
+                    | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
+#ifndef TARGET_ABI32
+#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
+#else
+#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
+#endif
+
+#define ELF_CLASS   ELFCLASS64
+#define ELF_ARCH    EM_SPARCV9
+
+#define STACK_BIAS              2047
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+#ifndef TARGET_ABI32
+    regs->tstate = 0;
+#endif
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+#ifdef TARGET_ABI32
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+#else
+    if (personality(infop->personality) == PER_LINUX32)
+        regs->u_regs[14] = infop->start_stack - 16 * 4;
+    else
+        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+#endif
+}
+
+#else
+#define ELF_START_MMAP 0x80000000
+#define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
+                    | HWCAP_SPARC_MULDIV)
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_ARCH    EM_SPARC
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->psr = 0;
+    regs->pc = infop->entry;
+    regs->npc = regs->pc + 4;
+    regs->y = 0;
+    regs->u_regs[14] = infop->start_stack - 16 * 4;
+}
+
+#endif
+#endif
+
+#ifdef TARGET_PPC
+
+#define ELF_START_MMAP 0x80000000
+
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+
+#define elf_check_arch(x) ( (x) == EM_PPC64 )
+
+#define ELF_CLASS       ELFCLASS64
+
+#else
+
+#define elf_check_arch(x) ( (x) == EM_PPC )
+
+#define ELF_CLASS       ELFCLASS32
+
+#endif
+
+#define ELF_ARCH        EM_PPC
+
+/* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
+   See arch/powerpc/include/asm/cputable.h.  */
+enum {
+    QEMU_PPC_FEATURE_32 = 0x80000000,
+    QEMU_PPC_FEATURE_64 = 0x40000000,
+    QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
+    QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
+    QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
+    QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
+    QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
+    QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
+    QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
+    QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
+    QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
+    QEMU_PPC_FEATURE_NO_TB = 0x00100000,
+    QEMU_PPC_FEATURE_POWER4 = 0x00080000,
+    QEMU_PPC_FEATURE_POWER5 = 0x00040000,
+    QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
+    QEMU_PPC_FEATURE_CELL = 0x00010000,
+    QEMU_PPC_FEATURE_BOOKE = 0x00008000,
+    QEMU_PPC_FEATURE_SMT = 0x00004000,
+    QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
+    QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
+    QEMU_PPC_FEATURE_PA6T = 0x00000800,
+    QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
+    QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
+    QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
+    QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
+    QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
+
+    QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
+    QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
+};
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+    CPUState *e = thread_env;
+    uint32_t features = 0;
+
+    /* We don't have to be terribly complete here; the high points are
+       Altivec/FP/SPE support.  Anything else is just a bonus.  */
+#define GET_FEATURE(flag, feature)                                      \
+    do {if (e->insns_flags & flag) features |= feature; } while(0)
+    GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
+    GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
+    GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
+    GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
+    GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
+    GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
+    GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
+    GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
+#undef GET_FEATURE
+
+    return features;
+}
+
+/*
+ * The requirements here are:
+ * - keep the final alignment of sp (sp & 0xf)
+ * - make sure the 32-bit value at the first 16 byte aligned position of
+ *   AUXV is greater than 16 for glibc compatibility.
+ *   AT_IGNOREPPC is used for that.
+ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
+ *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
+ */
+#define DLINFO_ARCH_ITEMS       5
+#define ARCH_DLINFO                                     \
+    do {                                                \
+        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);              \
+        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);              \
+        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
+        /*                                              \
+         * Now handle glibc compatibility.              \
+         */                                             \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
+    } while (0)
+
+static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
+{
+    _regs->gpr[1] = infop->start_stack;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_addr;
+    infop->entry = ldq_raw(infop->entry) + infop->load_addr;
+#endif
+    _regs->nip = infop->entry;
+}
+
+/* See linux kernel: arch/powerpc/include/asm/elf.h.  */
+#define ELF_NREG 48
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    int i;
+    target_ulong ccr = 0;
+
+    for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+        (*regs)[i] = tswapl(env->gpr[i]);
+    }
+
+    (*regs)[32] = tswapl(env->nip);
+    (*regs)[33] = tswapl(env->msr);
+    (*regs)[35] = tswapl(env->ctr);
+    (*regs)[36] = tswapl(env->lr);
+    (*regs)[37] = tswapl(env->xer);
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+    }
+    (*regs)[38] = tswapl(ccr);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       4096
+
+#endif
+
+#ifdef TARGET_MIPS
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+
+#ifdef TARGET_MIPS64
+#define ELF_CLASS   ELFCLASS64
+#else
+#define ELF_CLASS   ELFCLASS32
+#endif
+#define ELF_ARCH    EM_MIPS
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->cp0_status = 2 << CP0St_KSU;
+    regs->cp0_epc = infop->entry;
+    regs->regs[29] = infop->start_stack;
+}
+
+/* See linux kernel: arch/mips/include/asm/elf.h.  */
+#define ELF_NREG 45
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/mips/include/asm/reg.h.  */
+enum {
+#ifdef TARGET_MIPS64
+    TARGET_EF_R0 = 0,
+#else
+    TARGET_EF_R0 = 6,
+#endif
+    TARGET_EF_R26 = TARGET_EF_R0 + 26,
+    TARGET_EF_R27 = TARGET_EF_R0 + 27,
+    TARGET_EF_LO = TARGET_EF_R0 + 32,
+    TARGET_EF_HI = TARGET_EF_R0 + 33,
+    TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
+    TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
+    TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
+    TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
+};
+
+/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    int i;
+
+    for (i = 0; i < TARGET_EF_R0; i++) {
+        (*regs)[i] = 0;
+    }
+    (*regs)[TARGET_EF_R0] = 0;
+
+    for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
+        (*regs)[TARGET_EF_R0 + i] = tswapl(env->active_tc.gpr[i]);
+    }
+
+    (*regs)[TARGET_EF_R26] = 0;
+    (*regs)[TARGET_EF_R27] = 0;
+    (*regs)[TARGET_EF_LO] = tswapl(env->active_tc.LO[0]);
+    (*regs)[TARGET_EF_HI] = tswapl(env->active_tc.HI[0]);
+    (*regs)[TARGET_EF_CP0_EPC] = tswapl(env->active_tc.PC);
+    (*regs)[TARGET_EF_CP0_BADVADDR] = tswapl(env->CP0_BadVAddr);
+    (*regs)[TARGET_EF_CP0_STATUS] = tswapl(env->CP0_Status);
+    (*regs)[TARGET_EF_CP0_CAUSE] = tswapl(env->CP0_Cause);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif /* TARGET_MIPS */
+
+#ifdef TARGET_MICROBLAZE
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_ARCH    EM_MICROBLAZE
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->pc = infop->entry;
+    regs->r1 = infop->start_stack;
+
+}
+
+#define ELF_EXEC_PAGESIZE        4096
+
+#define USE_ELF_CORE_DUMP
+#define ELF_NREG 38
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    int i, pos = 0;
+
+    for (i = 0; i < 32; i++) {
+        (*regs)[pos++] = tswapl(env->regs[i]);
+    }
+
+    for (i = 0; i < 6; i++) {
+        (*regs)[pos++] = tswapl(env->sregs[i]);
+    }
+}
+
+#endif /* TARGET_MICROBLAZE */
+
+#ifdef TARGET_SH4
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SH )
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH  EM_SH
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    /* Check other registers XXXXX */
+    regs->pc = infop->entry;
+    regs->regs[15] = infop->start_stack;
+}
+
+/* See linux kernel: arch/sh/include/asm/elf.h.  */
+#define ELF_NREG 23
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/sh/include/asm/ptrace.h.  */
+enum {
+    TARGET_REG_PC = 16,
+    TARGET_REG_PR = 17,
+    TARGET_REG_SR = 18,
+    TARGET_REG_GBR = 19,
+    TARGET_REG_MACH = 20,
+    TARGET_REG_MACL = 21,
+    TARGET_REG_SYSCALL = 22
+};
+
+static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
+                                      const CPUState *env)
+{
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        (*regs[i]) = tswapl(env->gregs[i]);
+    }
+
+    (*regs)[TARGET_REG_PC] = tswapl(env->pc);
+    (*regs)[TARGET_REG_PR] = tswapl(env->pr);
+    (*regs)[TARGET_REG_SR] = tswapl(env->sr);
+    (*regs)[TARGET_REG_GBR] = tswapl(env->gbr);
+    (*regs)[TARGET_REG_MACH] = tswapl(env->mach);
+    (*regs)[TARGET_REG_MACL] = tswapl(env->macl);
+    (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
+#endif
+
+#ifdef TARGET_CRIS
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_CRIS )
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH  EM_CRIS
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->erp = infop->entry;
+}
+
+#define ELF_EXEC_PAGESIZE        8192
+
+#endif
+
+#ifdef TARGET_M68K
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_68K )
+
+#define ELF_CLASS       ELFCLASS32
+#define ELF_ARCH        EM_68K
+
+/* ??? Does this need to do anything?
+   #define ELF_PLAT_INIT(_r) */
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->usp = infop->start_stack;
+    regs->sr = 0;
+    regs->pc = infop->entry;
+}
+
+/* See linux kernel: arch/m68k/include/asm/elf.h.  */
+#define ELF_NREG 20
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = tswapl(env->dregs[1]);
+    (*regs)[1] = tswapl(env->dregs[2]);
+    (*regs)[2] = tswapl(env->dregs[3]);
+    (*regs)[3] = tswapl(env->dregs[4]);
+    (*regs)[4] = tswapl(env->dregs[5]);
+    (*regs)[5] = tswapl(env->dregs[6]);
+    (*regs)[6] = tswapl(env->dregs[7]);
+    (*regs)[7] = tswapl(env->aregs[0]);
+    (*regs)[8] = tswapl(env->aregs[1]);
+    (*regs)[9] = tswapl(env->aregs[2]);
+    (*regs)[10] = tswapl(env->aregs[3]);
+    (*regs)[11] = tswapl(env->aregs[4]);
+    (*regs)[12] = tswapl(env->aregs[5]);
+    (*regs)[13] = tswapl(env->aregs[6]);
+    (*regs)[14] = tswapl(env->dregs[0]);
+    (*regs)[15] = tswapl(env->aregs[7]);
+    (*regs)[16] = tswapl(env->dregs[0]); /* FIXME: orig_d0 */
+    (*regs)[17] = tswapl(env->sr);
+    (*regs)[18] = tswapl(env->pc);
+    (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE       8192
+
+#endif
+
+#ifdef TARGET_ALPHA
+
+#define ELF_START_MMAP (0x30000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_ARCH       EM_ALPHA
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->pc = infop->entry;
+    regs->ps = 8;
+    regs->usp = infop->start_stack;
+}
+
+#define ELF_EXEC_PAGESIZE        8192
+
+#endif /* TARGET_ALPHA */
+
+#ifdef TARGET_S390X
+
+#define ELF_START_MMAP (0x20000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS	ELFCLASS64
+#define ELF_DATA	ELFDATA2MSB
+#define ELF_ARCH	EM_S390
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->psw.addr = infop->entry;
+    regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
+    regs->gprs[15] = infop->start_stack;
+}
+
+#endif /* TARGET_S390X */
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
+#ifdef TARGET_ABI32
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+#undef bswaptls
+#define bswaptls(ptr) bswap32s(ptr)
+#endif
+
+#include "elf.h"
+
+struct exec
+{
+    unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
+    unsigned int a_text;   /* length of text, in bytes */
+    unsigned int a_data;   /* length of data, in bytes */
+    unsigned int a_bss;    /* length of uninitialized data area, in bytes */
+    unsigned int a_syms;   /* length of symbol table data in file, in bytes */
+    unsigned int a_entry;  /* start address */
+    unsigned int a_trsize; /* length of relocation info for text, in bytes */
+    unsigned int a_drsize; /* length of relocation info for data, in bytes */
+};
+
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+
+/* Necessary parameters */
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#define DLINFO_ITEMS 13
+
+static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
+{
+    memcpy(to, from, n);
+}
+
+#ifdef BSWAP_NEEDED
+static void bswap_ehdr(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);            /* Object file type */
+    bswap16s(&ehdr->e_machine);         /* Architecture */
+    bswap32s(&ehdr->e_version);         /* Object file version */
+    bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
+    bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
+    bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
+}
+
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
+{
+    int i;
+    for (i = 0; i < phnum; ++i, ++phdr) {
+        bswap32s(&phdr->p_type);        /* Segment type */
+        bswap32s(&phdr->p_flags);       /* Segment flags */
+        bswaptls(&phdr->p_offset);      /* Segment file offset */
+        bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
+        bswaptls(&phdr->p_paddr);       /* Segment physical address */
+        bswaptls(&phdr->p_filesz);      /* Segment size in file */
+        bswaptls(&phdr->p_memsz);       /* Segment size in memory */
+        bswaptls(&phdr->p_align);       /* Segment alignment */
+    }
+}
+
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
+{
+    int i;
+    for (i = 0; i < shnum; ++i, ++shdr) {
+        bswap32s(&shdr->sh_name);
+        bswap32s(&shdr->sh_type);
+        bswaptls(&shdr->sh_flags);
+        bswaptls(&shdr->sh_addr);
+        bswaptls(&shdr->sh_offset);
+        bswaptls(&shdr->sh_size);
+        bswap32s(&shdr->sh_link);
+        bswap32s(&shdr->sh_info);
+        bswaptls(&shdr->sh_addralign);
+        bswaptls(&shdr->sh_entsize);
+    }
+}
+
+static void bswap_sym(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswaptls(&sym->st_value);
+    bswaptls(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+#else
+static inline void bswap_ehdr(struct elfhdr *ehdr) { }
+static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
+static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
+static inline void bswap_sym(struct elf_sym *sym) { }
+#endif
+
+#ifdef USE_ELF_CORE_DUMP
+static int elf_core_dump(int, const CPUState *);
+#endif /* USE_ELF_CORE_DUMP */
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
+
+/* Verify the portions of EHDR within E_IDENT for the target.
+   This can be performed before bswapping the entire header.  */
+static bool elf_check_ident(struct elfhdr *ehdr)
+{
+    return (ehdr->e_ident[EI_MAG0] == ELFMAG0
+            && ehdr->e_ident[EI_MAG1] == ELFMAG1
+            && ehdr->e_ident[EI_MAG2] == ELFMAG2
+            && ehdr->e_ident[EI_MAG3] == ELFMAG3
+            && ehdr->e_ident[EI_CLASS] == ELF_CLASS
+            && ehdr->e_ident[EI_DATA] == ELF_DATA
+            && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
+}
+
+/* Verify the portions of EHDR outside of E_IDENT for the target.
+   This has to wait until after bswapping the header.  */
+static bool elf_check_ehdr(struct elfhdr *ehdr)
+{
+    return (elf_check_arch(ehdr->e_machine)
+            && ehdr->e_ehsize == sizeof(struct elfhdr)
+            && ehdr->e_phentsize == sizeof(struct elf_phdr)
+            && ehdr->e_shentsize == sizeof(struct elf_shdr)
+            && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
+}
+
+/*
+ * 'copy_elf_strings()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ *
+ */
+static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
+                                  abi_ulong p)
+{
+    char *tmp, *tmp1, *pag = NULL;
+    int len, offset = 0;
+
+    if (!p) {
+        return 0;       /* bullet-proofing */
+    }
+    while (argc-- > 0) {
+        tmp = argv[argc];
+        if (!tmp) {
+            fprintf(stderr, "VFS: argc is wrong");
+            exit(-1);
+        }
+        tmp1 = tmp;
+        while (*tmp++);
+        len = tmp - tmp1;
+        if (p < len) {  /* this shouldn't happen - 128kB */
+            return 0;
+        }
+        while (len) {
+            --p; --tmp; --len;
+            if (--offset < 0) {
+                offset = p % TARGET_PAGE_SIZE;
+                pag = (char *)page[p/TARGET_PAGE_SIZE];
+                if (!pag) {
+                    pag = (char *)malloc(TARGET_PAGE_SIZE);
+                    memset(pag, 0, TARGET_PAGE_SIZE);
+                    page[p/TARGET_PAGE_SIZE] = pag;
+                    if (!pag)
+                        return 0;
+                }
+            }
+            if (len == 0 || offset == 0) {
+                *(pag + offset) = *tmp;
+            }
+            else {
+                int bytes_to_copy = (len > offset) ? offset : len;
+                tmp -= bytes_to_copy;
+                p -= bytes_to_copy;
+                offset -= bytes_to_copy;
+                len -= bytes_to_copy;
+                memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+            }
+        }
+    }
+    return p;
+}
+
+static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+                                 struct image_info *info)
+{
+    abi_ulong stack_base, size, error, guard;
+    int i;
+
+    /* Create enough stack to hold everything.  If we don't use
+       it for args, we'll use it for something else.  */
+    size = guest_stack_size;
+    if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
+        size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+    }
+    guard = TARGET_PAGE_SIZE;
+    if (guard < qemu_real_host_page_size) {
+        guard = qemu_real_host_page_size;
+    }
+
+    error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (error == -1) {
+        perror("mmap stack");
+        exit(-1);
+    }
+
+    /* We reserve one extra page at the top of the stack as guard.  */
+    target_mprotect(error, guard, PROT_NONE);
+
+    info->stack_limit = error + guard;
+    stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+    p += stack_base;
+
+    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
+            free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+    return p;
+}
+
+/* Map and zero the bss.  We need to explicitly zero any fractional pages
+   after the data section (i.e. bss).  */
+static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
+{
+    uintptr_t host_start, host_map_start, host_end;
+
+    last_bss = TARGET_PAGE_ALIGN(last_bss);
+
+    /* ??? There is confusion between qemu_real_host_page_size and
+       qemu_host_page_size here and elsewhere in target_mmap, which
+       may lead to the end of the data section mapping from the file
+       not being mapped.  At least there was an explicit test and
+       comment for that here, suggesting that "the file size must
+       be known".  The comment probably pre-dates the introduction
+       of the fstat system call in target_mmap which does in fact
+       find out the size.  What isn't clear is if the workaround
+       here is still actually needed.  For now, continue with it,
+       but merge it with the "normal" mmap that would allocate the bss.  */
+
+    host_start = (uintptr_t) g2h(elf_bss);
+    host_end = (uintptr_t) g2h(last_bss);
+    host_map_start = (host_start + qemu_real_host_page_size - 1);
+    host_map_start &= -qemu_real_host_page_size;
+
+    if (host_map_start < host_end) {
+        void *p = mmap((void *)host_map_start, host_end - host_map_start,
+                       prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+        if (p == MAP_FAILED) {
+            perror("cannot mmap brk");
+            exit(-1);
+        }
+
+        /* Since we didn't use target_mmap, make sure to record
+           the validity of the pages with qemu.  */
+        page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
+    }
+
+    if (host_start < host_map_start) {
+        memset((void *)host_start, 0, host_map_start - host_start);
+    }
+}
+
+#ifdef CONFIG_USE_FDPIC
+static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
+{
+    uint16_t n;
+    struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
+
+    /* elf32_fdpic_loadseg */
+    n = info->nsegs;
+    while (n--) {
+        sp -= 12;
+        put_user_u32(loadsegs[n].addr, sp+0);
+        put_user_u32(loadsegs[n].p_vaddr, sp+4);
+        put_user_u32(loadsegs[n].p_memsz, sp+8);
+    }
+
+    /* elf32_fdpic_loadmap */
+    sp -= 4;
+    put_user_u16(0, sp+0); /* version */
+    put_user_u16(info->nsegs, sp+2); /* nsegs */
+
+    info->personality = PER_LINUX_FDPIC;
+    info->loadmap_addr = sp;
+
+    return sp;
+}
+#endif
+
+static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
+                                   struct elfhdr *exec,
+                                   struct image_info *info,
+                                   struct image_info *interp_info)
+{
+    abi_ulong sp;
+    int size;
+    int i;
+    abi_ulong u_rand_bytes;
+    uint8_t k_rand_bytes[16];
+    abi_ulong u_platform;
+    const char *k_platform;
+    const int n = sizeof(elf_addr_t);
+
+    sp = p;
+
+#ifdef CONFIG_USE_FDPIC
+    /* Needs to be before we load the env/argc/... */
+    if (elf_is_fdpic(exec)) {
+        /* Need 4 byte alignment for these structs */
+        sp &= ~3;
+        sp = loader_build_fdpic_loadmap(info, sp);
+        info->other_info = interp_info;
+        if (interp_info) {
+            interp_info->other_info = info;
+            sp = loader_build_fdpic_loadmap(interp_info, sp);
+        }
+    }
+#endif
+
+    u_platform = 0;
+    k_platform = ELF_PLATFORM;
+    if (k_platform) {
+        size_t len = strlen(k_platform) + 1;
+        sp -= (len + n - 1) & ~(n - 1);
+        u_platform = sp;
+        /* FIXME - check return value of memcpy_to_target() for failure */
+        memcpy_to_target(sp, k_platform, len);
+    }
+
+    /*
+     * Generate 16 random bytes for userspace PRNG seeding (not
+     * cryptically secure but it's not the aim of QEMU).
+     */
+    srand((unsigned int) time(NULL));
+    for (i = 0; i < 16; i++) {
+        k_rand_bytes[i] = rand();
+    }
+    sp -= 16;
+    u_rand_bytes = sp;
+    /* FIXME - check return value of memcpy_to_target() for failure */
+    memcpy_to_target(sp, k_rand_bytes, 16);
+
+    /*
+     * Force 16 byte _final_ alignment here for generality.
+     */
+    sp = sp &~ (abi_ulong)15;
+    size = (DLINFO_ITEMS + 1) * 2;
+    if (k_platform)
+        size += 2;
+#ifdef DLINFO_ARCH_ITEMS
+    size += DLINFO_ARCH_ITEMS * 2;
+#endif
+    size += envc + argc + 2;
+    size += 1;  /* argc itself */
+    size *= n;
+    if (size & 15)
+        sp -= 16 - (size & 15);
+
+    /* This is correct because Linux defines
+     * elf_addr_t as Elf32_Off / Elf64_Off
+     */
+#define NEW_AUX_ENT(id, val) do {               \
+        sp -= n; put_user_ual(val, sp);         \
+        sp -= n; put_user_ual(id, sp);          \
+    } while(0)
+
+    NEW_AUX_ENT (AT_NULL, 0);
+
+    /* There must be exactly DLINFO_ITEMS entries here.  */
+    NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
+    NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
+    NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
+    NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+    NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
+    NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
+    NEW_AUX_ENT(AT_ENTRY, info->entry);
+    NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
+    NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
+    NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
+    NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+    NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
+    NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+    NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
+
+    if (k_platform)
+        NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#ifdef ARCH_DLINFO
+    /*
+     * ARCH_DLINFO must come last so platform specific code can enforce
+     * special alignment requirements on the AUXV if necessary (eg. PPC).
+     */
+    ARCH_DLINFO;
+#endif
+#undef NEW_AUX_ENT
+
+    info->saved_auxv = sp;
+
+    sp = loader_build_argptr(envc, argc, sp, p, 0);
+    return sp;
+}
+
+static void probe_guest_base(const char *image_name,
+                             abi_ulong loaddr, abi_ulong hiaddr)
+{
+    /* Probe for a suitable guest base address, if the user has not set
+     * it explicitly, and set guest_base appropriately.
+     * In case of error we will print a suitable message and exit.
+     */
+#if defined(CONFIG_USE_GUEST_BASE)
+    const char *errmsg;
+    if (!have_guest_base && !reserved_va) {
+        unsigned long host_start, real_start, host_size;
+
+        /* Round addresses to page boundaries.  */
+        loaddr &= qemu_host_page_mask;
+        hiaddr = HOST_PAGE_ALIGN(hiaddr);
+
+        if (loaddr < mmap_min_addr) {
+            host_start = HOST_PAGE_ALIGN(mmap_min_addr);
+        } else {
+            host_start = loaddr;
+            if (host_start != loaddr) {
+                errmsg = "Address overflow loading ELF binary";
+                goto exit_errmsg;
+            }
+        }
+        host_size = hiaddr - loaddr;
+        while (1) {
+            /* Do not use mmap_find_vma here because that is limited to the
+               guest address space.  We are going to make the
+               guest address space fit whatever we're given.  */
+            real_start = (unsigned long)
+                mmap((void *)host_start, host_size, PROT_NONE,
+                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
+            if (real_start == (unsigned long)-1) {
+                goto exit_perror;
+            }
+            if (real_start == host_start) {
+                break;
+            }
+            /* That address didn't work.  Unmap and try a different one.
+               The address the host picked because is typically right at
+               the top of the host address space and leaves the guest with
+               no usable address space.  Resort to a linear search.  We
+               already compensated for mmap_min_addr, so this should not
+               happen often.  Probably means we got unlucky and host
+               address space randomization put a shared library somewhere
+               inconvenient.  */
+            munmap((void *)real_start, host_size);
+            host_start += qemu_host_page_size;
+            if (host_start == loaddr) {
+                /* Theoretically possible if host doesn't have any suitably
+                   aligned areas.  Normally the first mmap will fail.  */
+                errmsg = "Unable to find space for application";
+                goto exit_errmsg;
+            }
+        }
+        qemu_log("Relocating guest address space from 0x"
+                 TARGET_ABI_FMT_lx " to 0x%lx\n",
+                 loaddr, real_start);
+        guest_base = real_start - loaddr;
+    }
+    return;
+
+exit_perror:
+    errmsg = strerror(errno);
+exit_errmsg:
+    fprintf(stderr, "%s: %s\n", image_name, errmsg);
+    exit(-1);
+#endif
+}
+
+
+/* Load an ELF image into the address space.
+
+   IMAGE_NAME is the filename of the image, to use in error messages.
+   IMAGE_FD is the open file descriptor for the image.
+
+   BPRM_BUF is a copy of the beginning of the file; this of course
+   contains the elf file header at offset 0.  It is assumed that this
+   buffer is sufficiently aligned to present no problems to the host
+   in accessing data at aligned offsets within the buffer.
+
+   On return: INFO values will be filled in, as necessary or available.  */
+
+static void load_elf_image(const char *image_name, int image_fd,
+                           struct image_info *info, char **pinterp_name,
+                           char bprm_buf[BPRM_BUF_SIZE])
+{
+    struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+    struct elf_phdr *phdr;
+    abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
+    int i, retval;
+    const char *errmsg;
+
+    /* First of all, some simple consistency checks */
+    errmsg = "Invalid ELF image for this architecture";
+    if (!elf_check_ident(ehdr)) {
+        goto exit_errmsg;
+    }
+    bswap_ehdr(ehdr);
+    if (!elf_check_ehdr(ehdr)) {
+        goto exit_errmsg;
+    }
+
+    i = ehdr->e_phnum * sizeof(struct elf_phdr);
+    if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
+        phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
+    } else {
+        phdr = (struct elf_phdr *) alloca(i);
+        retval = pread(image_fd, phdr, i, ehdr->e_phoff);
+        if (retval != i) {
+            goto exit_read;
+        }
+    }
+    bswap_phdr(phdr, ehdr->e_phnum);
+
+#ifdef CONFIG_USE_FDPIC
+    info->nsegs = 0;
+    info->pt_dynamic_addr = 0;
+#endif
+
+    /* Find the maximum size of the image and allocate an appropriate
+       amount of memory to handle that.  */
+    loaddr = -1, hiaddr = 0;
+    for (i = 0; i < ehdr->e_phnum; ++i) {
+        if (phdr[i].p_type == PT_LOAD) {
+            abi_ulong a = phdr[i].p_vaddr;
+            if (a < loaddr) {
+                loaddr = a;
+            }
+            a += phdr[i].p_memsz;
+            if (a > hiaddr) {
+                hiaddr = a;
+            }
+#ifdef CONFIG_USE_FDPIC
+            ++info->nsegs;
+#endif
+        }
+    }
+
+    load_addr = loaddr;
+    if (ehdr->e_type == ET_DYN) {
+        /* The image indicates that it can be loaded anywhere.  Find a
+           location that can hold the memory space required.  If the
+           image is pre-linked, LOADDR will be non-zero.  Since we do
+           not supply MAP_FIXED here we'll use that address if and
+           only if it remains available.  */
+        load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
+                                MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+                                -1, 0);
+        if (load_addr == -1) {
+            goto exit_perror;
+        }
+    } else if (pinterp_name != NULL) {
+        /* This is the main executable.  Make sure that the low
+           address does not conflict with MMAP_MIN_ADDR or the
+           QEMU application itself.  */
+        probe_guest_base(image_name, loaddr, hiaddr);
+    }
+    load_bias = load_addr - loaddr;
+
+#ifdef CONFIG_USE_FDPIC
+    {
+        struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
+            qemu_malloc(sizeof(*loadsegs) * info->nsegs);
+
+        for (i = 0; i < ehdr->e_phnum; ++i) {
+            switch (phdr[i].p_type) {
+            case PT_DYNAMIC:
+                info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
+                break;
+            case PT_LOAD:
+                loadsegs->addr = phdr[i].p_vaddr + load_bias;
+                loadsegs->p_vaddr = phdr[i].p_vaddr;
+                loadsegs->p_memsz = phdr[i].p_memsz;
+                ++loadsegs;
+                break;
+            }
+        }
+    }
+#endif
+
+    info->load_bias = load_bias;
+    info->load_addr = load_addr;
+    info->entry = ehdr->e_entry + load_bias;
+    info->start_code = -1;
+    info->end_code = 0;
+    info->start_data = -1;
+    info->end_data = 0;
+    info->brk = 0;
+
+    for (i = 0; i < ehdr->e_phnum; i++) {
+        struct elf_phdr *eppnt = phdr + i;
+        if (eppnt->p_type == PT_LOAD) {
+            abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
+            int elf_prot = 0;
+
+            if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
+            if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+            if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
+            vaddr = load_bias + eppnt->p_vaddr;
+            vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
+            vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
+
+            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+                                elf_prot, MAP_PRIVATE | MAP_FIXED,
+                                image_fd, eppnt->p_offset - vaddr_po);
+            if (error == -1) {
+                goto exit_perror;
+            }
+
+            vaddr_ef = vaddr + eppnt->p_filesz;
+            vaddr_em = vaddr + eppnt->p_memsz;
+
+            /* If the load segment requests extra zeros (e.g. bss), map it.  */
+            if (vaddr_ef < vaddr_em) {
+                zero_bss(vaddr_ef, vaddr_em, elf_prot);
+            }
+
+            /* Find the full program boundaries.  */
+            if (elf_prot & PROT_EXEC) {
+                if (vaddr < info->start_code) {
+                    info->start_code = vaddr;
+                }
+                if (vaddr_ef > info->end_code) {
+                    info->end_code = vaddr_ef;
+                }
+            }
+            if (elf_prot & PROT_WRITE) {
+                if (vaddr < info->start_data) {
+                    info->start_data = vaddr;
+                }
+                if (vaddr_ef > info->end_data) {
+                    info->end_data = vaddr_ef;
+                }
+                if (vaddr_em > info->brk) {
+                    info->brk = vaddr_em;
+                }
+            }
+        } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
+            char *interp_name;
+
+            if (*pinterp_name) {
+                errmsg = "Multiple PT_INTERP entries";
+                goto exit_errmsg;
+            }
+            interp_name = malloc(eppnt->p_filesz);
+            if (!interp_name) {
+                goto exit_perror;
+            }
+
+            if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
+                memcpy(interp_name, bprm_buf + eppnt->p_offset,
+                       eppnt->p_filesz);
+            } else {
+                retval = pread(image_fd, interp_name, eppnt->p_filesz,
+                               eppnt->p_offset);
+                if (retval != eppnt->p_filesz) {
+                    goto exit_perror;
+                }
+            }
+            if (interp_name[eppnt->p_filesz - 1] != 0) {
+                errmsg = "Invalid PT_INTERP entry";
+                goto exit_errmsg;
+            }
+            *pinterp_name = interp_name;
+        }
+    }
+
+    if (info->end_data == 0) {
+        info->start_data = info->end_code;
+        info->end_data = info->end_code;
+        info->brk = info->end_code;
+    }
+
+    if (qemu_log_enabled()) {
+        load_symbols(ehdr, image_fd, load_bias);
+    }
+
+    close(image_fd);
+    return;
+
+ exit_read:
+    if (retval >= 0) {
+        errmsg = "Incomplete read of file header";
+        goto exit_errmsg;
+    }
+ exit_perror:
+    errmsg = strerror(errno);
+ exit_errmsg:
+    fprintf(stderr, "%s: %s\n", image_name, errmsg);
+    exit(-1);
+}
+
+static void load_elf_interp(const char *filename, struct image_info *info,
+                            char bprm_buf[BPRM_BUF_SIZE])
+{
+    int fd, retval;
+
+    fd = open(path(filename), O_RDONLY);
+    if (fd < 0) {
+        goto exit_perror;
+    }
+
+    retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+    if (retval < 0) {
+        goto exit_perror;
+    }
+    if (retval < BPRM_BUF_SIZE) {
+        memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+    }
+
+    load_elf_image(filename, fd, info, NULL, bprm_buf);
+    return;
+
+ exit_perror:
+    fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+    exit(-1);
+}
+
+static int symfind(const void *s0, const void *s1)
+{
+    struct elf_sym *key = (struct elf_sym *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (key->st_value < sym->st_value) {
+        result = -1;
+    } else if (key->st_value >= sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
+{
+#if ELF_CLASS == ELFCLASS32
+    struct elf_sym *syms = s->disas_symtab.elf32;
+#else
+    struct elf_sym *syms = s->disas_symtab.elf64;
+#endif
+
+    // binary search
+    struct elf_sym key;
+    struct elf_sym *sym;
+
+    key.st_value = orig_addr;
+
+    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
+    if (sym != NULL) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+/* FIXME: This should use elf_ops.h  */
+static int symcmp(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+/* Best attempt to load symbols from this ELF object. */
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
+{
+    int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
+    struct elf_shdr *shdr;
+    char *strings = NULL;
+    struct syminfo *s = NULL;
+    struct elf_sym *new_syms, *syms = NULL;
+
+    shnum = hdr->e_shnum;
+    i = shnum * sizeof(struct elf_shdr);
+    shdr = (struct elf_shdr *)alloca(i);
+    if (pread(fd, shdr, i, hdr->e_shoff) != i) {
+        return;
+    }
+
+    bswap_shdr(shdr, shnum);
+    for (i = 0; i < shnum; ++i) {
+        if (shdr[i].sh_type == SHT_SYMTAB) {
+            sym_idx = i;
+            str_idx = shdr[i].sh_link;
+            goto found;
+        }
+    }
+
+    /* There will be no symbol table if the file was stripped.  */
+    return;
+
+ found:
+    /* Now know where the strtab and symtab are.  Snarf them.  */
+    s = malloc(sizeof(*s));
+    if (!s) {
+        goto give_up;
+    }
+
+    i = shdr[str_idx].sh_size;
+    s->disas_strtab = strings = malloc(i);
+    if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
+        goto give_up;
+    }
+
+    i = shdr[sym_idx].sh_size;
+    syms = malloc(i);
+    if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
+        goto give_up;
+    }
+
+    nsyms = i / sizeof(struct elf_sym);
+    for (i = 0; i < nsyms; ) {
+        bswap_sym(syms + i);
+        /* Throw away entries which we do not need.  */
+        if (syms[i].st_shndx == SHN_UNDEF
+            || syms[i].st_shndx >= SHN_LORESERVE
+            || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            if (i < --nsyms) {
+                syms[i] = syms[nsyms];
+            }
+        } else {
+#if defined(TARGET_ARM) || defined (TARGET_MIPS)
+            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+            syms[i].st_value &= ~(target_ulong)1;
+#endif
+            syms[i].st_value += load_bias;
+            i++;
+        }
+    }
+
+    /* No "useful" symbol.  */
+    if (nsyms == 0) {
+        goto give_up;
+    }
+
+    /* Attempt to free the storage associated with the local symbols
+       that we threw away.  Whether or not this has any effect on the
+       memory allocation depends on the malloc implementation and how
+       many symbols we managed to discard.  */
+    new_syms = realloc(syms, nsyms * sizeof(*syms));
+    if (new_syms == NULL) {
+        goto give_up;
+    }
+    syms = new_syms;
+
+    qsort(syms, nsyms, sizeof(*syms), symcmp);
+
+    s->disas_num_syms = nsyms;
+#if ELF_CLASS == ELFCLASS32
+    s->disas_symtab.elf32 = syms;
+#else
+    s->disas_symtab.elf64 = syms;
+#endif
+    s->lookup_symbol = lookup_symbolxx;
+    s->next = syminfos;
+    syminfos = s;
+
+    return;
+
+give_up:
+    free(s);
+    free(strings);
+    free(syms);
+}
+
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info)
+{
+    struct image_info interp_info;
+    struct elfhdr elf_ex;
+    char *elf_interpreter = NULL;
+
+    info->start_mmap = (abi_ulong)ELF_START_MMAP;
+    info->mmap = 0;
+    info->rss = 0;
+
+    load_elf_image(bprm->filename, bprm->fd, info,
+                   &elf_interpreter, bprm->buf);
+
+    /* ??? We need a copy of the elf header for passing to create_elf_tables.
+       If we do nothing, we'll have overwritten this when we re-use bprm->buf
+       when we load the interpreter.  */
+    elf_ex = *(struct elfhdr *)bprm->buf;
+
+    bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
+    bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
+    bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+    if (!bprm->p) {
+        fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
+        exit(-1);
+    }
+
+    /* Do this so that we can load the interpreter, if need be.  We will
+       change some of these later */
+    bprm->p = setup_arg_pages(bprm->p, bprm, info);
+
+    if (elf_interpreter) {
+        load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
+
+        /* If the program interpreter is one of these two, then assume
+           an iBCS2 image.  Otherwise assume a native linux image.  */
+
+        if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
+            || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+            info->personality = PER_SVR4;
+
+            /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+               and some applications "depend" upon this behavior.  Since
+               we do not have the power to recompile these, we emulate
+               the SVr4 behavior.  Sigh.  */
+            target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
+                        MAP_FIXED | MAP_PRIVATE, -1, 0);
+        }
+    }
+
+    bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
+                                info, (elf_interpreter ? &interp_info : NULL));
+    info->start_stack = bprm->p;
+
+    /* If we have an interpreter, set that as the program's entry point.
+       Copy the load_addr as well, to help PPC64 interpret the entry
+       point as a function descriptor.  Do this after creating elf tables
+       so that we copy the original program entry point into the AUXV.  */
+    if (elf_interpreter) {
+        info->load_addr = interp_info.load_addr;
+        info->entry = interp_info.entry;
+        free(elf_interpreter);
+    }
+
+#ifdef USE_ELF_CORE_DUMP
+    bprm->core_dump = &elf_core_dump;
+#endif
+
+    return 0;
+}
+
+#ifdef USE_ELF_CORE_DUMP
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "target_elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided.  This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ *
+ * Fields we don't dump (their contents is zero) in linux-user qemu
+ * are marked with XXX.
+ *
+ * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
+ *
+ * Porting ELF coredump for target is (quite) simple process.  First you
+ * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
+ * the target resides):
+ *
+ * #define USE_ELF_CORE_DUMP
+ *
+ * Next you define type of register set used for dumping.  ELF specification
+ * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
+ *
+ * typedef <target_regtype> target_elf_greg_t;
+ * #define ELF_NREG <number of registers>
+ * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
+ *
+ * Last step is to implement target specific function that copies registers
+ * from given cpu into just specified register set.  Prototype is:
+ *
+ * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
+ *                                const CPUState *env);
+ *
+ * Parameters:
+ *     regs - copy register values into here (allocated and zeroed by caller)
+ *     env - copy registers from here
+ *
+ * Example for ARM target is provided in this file.
+ */
+
+/* An ELF note in memory */
+struct memelfnote {
+    const char *name;
+    size_t     namesz;
+    size_t     namesz_rounded;
+    int        type;
+    size_t     datasz;
+    size_t     datasz_rounded;
+    void       *data;
+    size_t     notesz;
+};
+
+struct target_elf_siginfo {
+    target_int  si_signo; /* signal number */
+    target_int  si_code;  /* extra code */
+    target_int  si_errno; /* errno */
+};
+
+struct target_elf_prstatus {
+    struct target_elf_siginfo pr_info;      /* Info associated with signal */
+    target_short       pr_cursig;    /* Current signal */
+    target_ulong       pr_sigpend;   /* XXX */
+    target_ulong       pr_sighold;   /* XXX */
+    target_pid_t       pr_pid;
+    target_pid_t       pr_ppid;
+    target_pid_t       pr_pgrp;
+    target_pid_t       pr_sid;
+    struct target_timeval pr_utime;  /* XXX User time */
+    struct target_timeval pr_stime;  /* XXX System time */
+    struct target_timeval pr_cutime; /* XXX Cumulative user time */
+    struct target_timeval pr_cstime; /* XXX Cumulative system time */
+    target_elf_gregset_t      pr_reg;       /* GP registers */
+    target_int         pr_fpvalid;   /* XXX */
+};
+
+#define ELF_PRARGSZ     (80) /* Number of chars for args */
+
+struct target_elf_prpsinfo {
+    char         pr_state;       /* numeric process state */
+    char         pr_sname;       /* char for pr_state */
+    char         pr_zomb;        /* zombie */
+    char         pr_nice;        /* nice val */
+    target_ulong pr_flag;        /* flags */
+    target_uid_t pr_uid;
+    target_gid_t pr_gid;
+    target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+    /* Lots missing */
+    char    pr_fname[16];           /* filename of executable */
+    char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+/* Here is the structure in which status of each thread is captured. */
+struct elf_thread_status {
+    QTAILQ_ENTRY(elf_thread_status)  ets_link;
+    struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
+#if 0
+    elf_fpregset_t fpu;             /* NT_PRFPREG */
+    struct task_struct *thread;
+    elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
+#endif
+    struct memelfnote notes[1];
+    int num_notes;
+};
+
+struct elf_note_info {
+    struct memelfnote   *notes;
+    struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
+    struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
+
+    QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
+#if 0
+    /*
+     * Current version of ELF coredump doesn't support
+     * dumping fp regs etc.
+     */
+    elf_fpregset_t *fpu;
+    elf_fpxregset_t *xfpu;
+    int thread_status_size;
+#endif
+    int notes_size;
+    int numnote;
+};
+
+struct vm_area_struct {
+    abi_ulong   vma_start;  /* start vaddr of memory region */
+    abi_ulong   vma_end;    /* end vaddr of memory region */
+    abi_ulong   vma_flags;  /* protection etc. flags for the region */
+    QTAILQ_ENTRY(vm_area_struct) vma_link;
+};
+
+struct mm_struct {
+    QTAILQ_HEAD(, vm_area_struct) mm_mmap;
+    int mm_count;           /* number of mappings */
+};
+
+static struct mm_struct *vma_init(void);
+static void vma_delete(struct mm_struct *);
+static int vma_add_mapping(struct mm_struct *, abi_ulong,
+                           abi_ulong, abi_ulong);
+static int vma_get_mapping_count(const struct mm_struct *);
+static struct vm_area_struct *vma_first(const struct mm_struct *);
+static struct vm_area_struct *vma_next(struct vm_area_struct *);
+static abi_ulong vma_dump_size(const struct vm_area_struct *);
+static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
+                      unsigned long flags);
+
+static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
+static void fill_note(struct memelfnote *, const char *, int,
+                      unsigned int, void *);
+static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
+static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
+static void fill_auxv_note(struct memelfnote *, const TaskState *);
+static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
+static size_t note_size(const struct memelfnote *);
+static void free_note_info(struct elf_note_info *);
+static int fill_note_info(struct elf_note_info *, long, const CPUState *);
+static void fill_thread_info(struct elf_note_info *, const CPUState *);
+static int core_dump_filename(const TaskState *, char *, size_t);
+
+static int dump_write(int, const void *, size_t);
+static int write_note(struct memelfnote *, int);
+static int write_note_info(struct elf_note_info *, int);
+
+#ifdef BSWAP_NEEDED
+static void bswap_prstatus(struct target_elf_prstatus *prstatus)
+{
+    prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
+    prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code);
+    prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno);
+    prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
+    prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend);
+    prstatus->pr_sighold = tswapl(prstatus->pr_sighold);
+    prstatus->pr_pid = tswap32(prstatus->pr_pid);
+    prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
+    prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
+    prstatus->pr_sid = tswap32(prstatus->pr_sid);
+    /* cpu times are not filled, so we skip them */
+    /* regs should be in correct format already */
+    prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
+}
+
+static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
+{
+    psinfo->pr_flag = tswapl(psinfo->pr_flag);
+    psinfo->pr_uid = tswap16(psinfo->pr_uid);
+    psinfo->pr_gid = tswap16(psinfo->pr_gid);
+    psinfo->pr_pid = tswap32(psinfo->pr_pid);
+    psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
+    psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
+    psinfo->pr_sid = tswap32(psinfo->pr_sid);
+}
+
+static void bswap_note(struct elf_note *en)
+{
+    bswap32s(&en->n_namesz);
+    bswap32s(&en->n_descsz);
+    bswap32s(&en->n_type);
+}
+#else
+static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
+static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
+static inline void bswap_note(struct elf_note *en) { }
+#endif /* BSWAP_NEEDED */
+
+/*
+ * Minimal support for linux memory regions.  These are needed
+ * when we are finding out what memory exactly belongs to
+ * emulated process.  No locks needed here, as long as
+ * thread that received the signal is stopped.
+ */
+
+static struct mm_struct *vma_init(void)
+{
+    struct mm_struct *mm;
+
+    if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
+        return (NULL);
+
+    mm->mm_count = 0;
+    QTAILQ_INIT(&mm->mm_mmap);
+
+    return (mm);
+}
+
+static void vma_delete(struct mm_struct *mm)
+{
+    struct vm_area_struct *vma;
+
+    while ((vma = vma_first(mm)) != NULL) {
+        QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
+        qemu_free(vma);
+    }
+    qemu_free(mm);
+}
+
+static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
+                           abi_ulong end, abi_ulong flags)
+{
+    struct vm_area_struct *vma;
+
+    if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
+        return (-1);
+
+    vma->vma_start = start;
+    vma->vma_end = end;
+    vma->vma_flags = flags;
+
+    QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
+    mm->mm_count++;
+
+    return (0);
+}
+
+static struct vm_area_struct *vma_first(const struct mm_struct *mm)
+{
+    return (QTAILQ_FIRST(&mm->mm_mmap));
+}
+
+static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
+{
+    return (QTAILQ_NEXT(vma, vma_link));
+}
+
+static int vma_get_mapping_count(const struct mm_struct *mm)
+{
+    return (mm->mm_count);
+}
+
+/*
+ * Calculate file (dump) size of given memory region.
+ */
+static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
+{
+    /* if we cannot even read the first page, skip it */
+    if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
+        return (0);
+
+    /*
+     * Usually we don't dump executable pages as they contain
+     * non-writable code that debugger can read directly from
+     * target library etc.  However, thread stacks are marked
+     * also executable so we read in first page of given region
+     * and check whether it contains elf header.  If there is
+     * no elf header, we dump it.
+     */
+    if (vma->vma_flags & PROT_EXEC) {
+        char page[TARGET_PAGE_SIZE];
+
+        copy_from_user(page, vma->vma_start, sizeof (page));
+        if ((page[EI_MAG0] == ELFMAG0) &&
+            (page[EI_MAG1] == ELFMAG1) &&
+            (page[EI_MAG2] == ELFMAG2) &&
+            (page[EI_MAG3] == ELFMAG3)) {
+            /*
+             * Mappings are possibly from ELF binary.  Don't dump
+             * them.
+             */
+            return (0);
+        }
+    }
+
+    return (vma->vma_end - vma->vma_start);
+}
+
+static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
+                      unsigned long flags)
+{
+    struct mm_struct *mm = (struct mm_struct *)priv;
+
+    vma_add_mapping(mm, start, end, flags);
+    return (0);
+}
+
+static void fill_note(struct memelfnote *note, const char *name, int type,
+                      unsigned int sz, void *data)
+{
+    unsigned int namesz;
+
+    namesz = strlen(name) + 1;
+    note->name = name;
+    note->namesz = namesz;
+    note->namesz_rounded = roundup(namesz, sizeof (int32_t));
+    note->type = type;
+    note->datasz = sz;
+    note->datasz_rounded = roundup(sz, sizeof (int32_t));
+
+    note->data = data;
+
+    /*
+     * We calculate rounded up note size here as specified by
+     * ELF document.
+     */
+    note->notesz = sizeof (struct elf_note) +
+        note->namesz_rounded + note->datasz_rounded;
+}
+
+static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
+                            uint32_t flags)
+{
+    (void) memset(elf, 0, sizeof(*elf));
+
+    (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
+    elf->e_ident[EI_CLASS] = ELF_CLASS;
+    elf->e_ident[EI_DATA] = ELF_DATA;
+    elf->e_ident[EI_VERSION] = EV_CURRENT;
+    elf->e_ident[EI_OSABI] = ELF_OSABI;
+
+    elf->e_type = ET_CORE;
+    elf->e_machine = machine;
+    elf->e_version = EV_CURRENT;
+    elf->e_phoff = sizeof(struct elfhdr);
+    elf->e_flags = flags;
+    elf->e_ehsize = sizeof(struct elfhdr);
+    elf->e_phentsize = sizeof(struct elf_phdr);
+    elf->e_phnum = segs;
+
+    bswap_ehdr(elf);
+}
+
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+    phdr->p_type = PT_NOTE;
+    phdr->p_offset = offset;
+    phdr->p_vaddr = 0;
+    phdr->p_paddr = 0;
+    phdr->p_filesz = sz;
+    phdr->p_memsz = 0;
+    phdr->p_flags = 0;
+    phdr->p_align = 0;
+
+    bswap_phdr(phdr, 1);
+}
+
+static size_t note_size(const struct memelfnote *note)
+{
+    return (note->notesz);
+}
+
+static void fill_prstatus(struct target_elf_prstatus *prstatus,
+                          const TaskState *ts, int signr)
+{
+    (void) memset(prstatus, 0, sizeof (*prstatus));
+    prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
+    prstatus->pr_pid = ts->ts_tid;
+    prstatus->pr_ppid = getppid();
+    prstatus->pr_pgrp = getpgrp();
+    prstatus->pr_sid = getsid(0);
+
+    bswap_prstatus(prstatus);
+}
+
+static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
+{
+    char *filename, *base_filename;
+    unsigned int i, len;
+
+    (void) memset(psinfo, 0, sizeof (*psinfo));
+
+    len = ts->info->arg_end - ts->info->arg_start;
+    if (len >= ELF_PRARGSZ)
+        len = ELF_PRARGSZ - 1;
+    if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
+        return -EFAULT;
+    for (i = 0; i < len; i++)
+        if (psinfo->pr_psargs[i] == 0)
+            psinfo->pr_psargs[i] = ' ';
+    psinfo->pr_psargs[len] = 0;
+
+    psinfo->pr_pid = getpid();
+    psinfo->pr_ppid = getppid();
+    psinfo->pr_pgrp = getpgrp();
+    psinfo->pr_sid = getsid(0);
+    psinfo->pr_uid = getuid();
+    psinfo->pr_gid = getgid();
+
+    filename = strdup(ts->bprm->filename);
+    base_filename = strdup(basename(filename));
+    (void) strncpy(psinfo->pr_fname, base_filename,
+                   sizeof(psinfo->pr_fname));
+    free(base_filename);
+    free(filename);
+
+    bswap_psinfo(psinfo);
+    return (0);
+}
+
+static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
+{
+    elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
+    elf_addr_t orig_auxv = auxv;
+    abi_ulong val;
+    void *ptr;
+    int i, len;
+
+    /*
+     * Auxiliary vector is stored in target process stack.  It contains
+     * {type, value} pairs that we need to dump into note.  This is not
+     * strictly necessary but we do it here for sake of completeness.
+     */
+
+    /* find out lenght of the vector, AT_NULL is terminator */
+    i = len = 0;
+    do {
+        get_user_ual(val, auxv);
+        i += 2;
+        auxv += 2 * sizeof (elf_addr_t);
+    } while (val != AT_NULL);
+    len = i * sizeof (elf_addr_t);
+
+    /* read in whole auxv vector and copy it to memelfnote */
+    ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
+    if (ptr != NULL) {
+        fill_note(note, "CORE", NT_AUXV, len, ptr);
+        unlock_user(ptr, auxv, len);
+    }
+}
+
+/*
+ * Constructs name of coredump file.  We have following convention
+ * for the name:
+ *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
+ *
+ * Returns 0 in case of success, -1 otherwise (errno is set).
+ */
+static int core_dump_filename(const TaskState *ts, char *buf,
+                              size_t bufsize)
+{
+    char timestamp[64];
+    char *filename = NULL;
+    char *base_filename = NULL;
+    struct timeval tv;
+    struct tm tm;
+
+    assert(bufsize >= PATH_MAX);
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        (void) fprintf(stderr, "unable to get current timestamp: %s",
+                       strerror(errno));
+        return (-1);
+    }
+
+    filename = strdup(ts->bprm->filename);
+    base_filename = strdup(basename(filename));
+    (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
+                    localtime_r(&tv.tv_sec, &tm));
+    (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
+                    base_filename, timestamp, (int)getpid());
+    free(base_filename);
+    free(filename);
+
+    return (0);
+}
+
+static int dump_write(int fd, const void *ptr, size_t size)
+{
+    const char *bufp = (const char *)ptr;
+    ssize_t bytes_written, bytes_left;
+    struct rlimit dumpsize;
+    off_t pos;
+
+    bytes_written = 0;
+    getrlimit(RLIMIT_CORE, &dumpsize);
+    if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
+        if (errno == ESPIPE) { /* not a seekable stream */
+            bytes_left = size;
+        } else {
+            return pos;
+        }
+    } else {
+        if (dumpsize.rlim_cur <= pos) {
+            return -1;
+        } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
+            bytes_left = size;
+        } else {
+            size_t limit_left=dumpsize.rlim_cur - pos;
+            bytes_left = limit_left >= size ? size : limit_left ;
+        }
+    }
+
+    /*
+     * In normal conditions, single write(2) should do but
+     * in case of socket etc. this mechanism is more portable.
+     */
+    do {
+        bytes_written = write(fd, bufp, bytes_left);
+        if (bytes_written < 0) {
+            if (errno == EINTR)
+                continue;
+            return (-1);
+        } else if (bytes_written == 0) { /* eof */
+            return (-1);
+        }
+        bufp += bytes_written;
+        bytes_left -= bytes_written;
+    } while (bytes_left > 0);
+
+    return (0);
+}
+
+static int write_note(struct memelfnote *men, int fd)
+{
+    struct elf_note en;
+
+    en.n_namesz = men->namesz;
+    en.n_type = men->type;
+    en.n_descsz = men->datasz;
+
+    bswap_note(&en);
+
+    if (dump_write(fd, &en, sizeof(en)) != 0)
+        return (-1);
+    if (dump_write(fd, men->name, men->namesz_rounded) != 0)
+        return (-1);
+    if (dump_write(fd, men->data, men->datasz_rounded) != 0)
+        return (-1);
+
+    return (0);
+}
+
+static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
+{
+    TaskState *ts = (TaskState *)env->opaque;
+    struct elf_thread_status *ets;
+
+    ets = qemu_mallocz(sizeof (*ets));
+    ets->num_notes = 1; /* only prstatus is dumped */
+    fill_prstatus(&ets->prstatus, ts, 0);
+    elf_core_copy_regs(&ets->prstatus.pr_reg, env);
+    fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
+              &ets->prstatus);
+
+    QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
+
+    info->notes_size += note_size(&ets->notes[0]);
+}
+
+static int fill_note_info(struct elf_note_info *info,
+                          long signr, const CPUState *env)
+{
+#define NUMNOTES 3
+    CPUState *cpu = NULL;
+    TaskState *ts = (TaskState *)env->opaque;
+    int i;
+
+    (void) memset(info, 0, sizeof (*info));
+
+    QTAILQ_INIT(&info->thread_list);
+
+    info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
+    if (info->notes == NULL)
+        return (-ENOMEM);
+    info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
+    if (info->prstatus == NULL)
+        return (-ENOMEM);
+    info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
+    if (info->prstatus == NULL)
+        return (-ENOMEM);
+
+    /*
+     * First fill in status (and registers) of current thread
+     * including process info & aux vector.
+     */
+    fill_prstatus(info->prstatus, ts, signr);
+    elf_core_copy_regs(&info->prstatus->pr_reg, env);
+    fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
+              sizeof (*info->prstatus), info->prstatus);
+    fill_psinfo(info->psinfo, ts);
+    fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
+              sizeof (*info->psinfo), info->psinfo);
+    fill_auxv_note(&info->notes[2], ts);
+    info->numnote = 3;
+
+    info->notes_size = 0;
+    for (i = 0; i < info->numnote; i++)
+        info->notes_size += note_size(&info->notes[i]);
+
+    /* read and fill status of all threads */
+    cpu_list_lock();
+    for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+        if (cpu == thread_env)
+            continue;
+        fill_thread_info(info, cpu);
+    }
+    cpu_list_unlock();
+
+    return (0);
+}
+
+static void free_note_info(struct elf_note_info *info)
+{
+    struct elf_thread_status *ets;
+
+    while (!QTAILQ_EMPTY(&info->thread_list)) {
+        ets = QTAILQ_FIRST(&info->thread_list);
+        QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
+        qemu_free(ets);
+    }
+
+    qemu_free(info->prstatus);
+    qemu_free(info->psinfo);
+    qemu_free(info->notes);
+}
+
+static int write_note_info(struct elf_note_info *info, int fd)
+{
+    struct elf_thread_status *ets;
+    int i, error = 0;
+
+    /* write prstatus, psinfo and auxv for current thread */
+    for (i = 0; i < info->numnote; i++)
+        if ((error = write_note(&info->notes[i], fd)) != 0)
+            return (error);
+
+    /* write prstatus for each thread */
+    for (ets = info->thread_list.tqh_first; ets != NULL;
+         ets = ets->ets_link.tqe_next) {
+        if ((error = write_note(&ets->notes[0], fd)) != 0)
+            return (error);
+    }
+
+    return (0);
+}
+
+/*
+ * Write out ELF coredump.
+ *
+ * See documentation of ELF object file format in:
+ * http://www.caldera.com/developers/devspecs/gabi41.pdf
+ *
+ * Coredump format in linux is following:
+ *
+ * 0   +----------------------+         \
+ *     | ELF header           | ET_CORE  |
+ *     +----------------------+          |
+ *     | ELF program headers  |          |--- headers
+ *     | - NOTE section       |          |
+ *     | - PT_LOAD sections   |          |
+ *     +----------------------+         /
+ *     | NOTEs:               |
+ *     | - NT_PRSTATUS        |
+ *     | - NT_PRSINFO         |
+ *     | - NT_AUXV            |
+ *     +----------------------+ <-- aligned to target page
+ *     | Process memory dump  |
+ *     :                      :
+ *     .                      .
+ *     :                      :
+ *     |                      |
+ *     +----------------------+
+ *
+ * NT_PRSTATUS -> struct elf_prstatus (per thread)
+ * NT_PRSINFO  -> struct elf_prpsinfo
+ * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
+ *
+ * Format follows System V format as close as possible.  Current
+ * version limitations are as follows:
+ *     - no floating point registers are dumped
+ *
+ * Function returns 0 in case of success, negative errno otherwise.
+ *
+ * TODO: make this work also during runtime: it should be
+ * possible to force coredump from running process and then
+ * continue processing.  For example qemu could set up SIGUSR2
+ * handler (provided that target process haven't registered
+ * handler for that) that does the dump when signal is received.
+ */
+static int elf_core_dump(int signr, const CPUState *env)
+{
+    const TaskState *ts = (const TaskState *)env->opaque;
+    struct vm_area_struct *vma = NULL;
+    char corefile[PATH_MAX];
+    struct elf_note_info info;
+    struct elfhdr elf;
+    struct elf_phdr phdr;
+    struct rlimit dumpsize;
+    struct mm_struct *mm = NULL;
+    off_t offset = 0, data_offset = 0;
+    int segs = 0;
+    int fd = -1;
+
+    errno = 0;
+    getrlimit(RLIMIT_CORE, &dumpsize);
+    if (dumpsize.rlim_cur == 0)
+        return 0;
+
+    if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
+        return (-errno);
+
+    if ((fd = open(corefile, O_WRONLY | O_CREAT,
+                   S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+        return (-errno);
+
+    /*
+     * Walk through target process memory mappings and
+     * set up structure containing this information.  After
+     * this point vma_xxx functions can be used.
+     */
+    if ((mm = vma_init()) == NULL)
+        goto out;
+
+    walk_memory_regions(mm, vma_walker);
+    segs = vma_get_mapping_count(mm);
+
+    /*
+     * Construct valid coredump ELF header.  We also
+     * add one more segment for notes.
+     */
+    fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
+    if (dump_write(fd, &elf, sizeof (elf)) != 0)
+        goto out;
+
+    /* fill in in-memory version of notes */
+    if (fill_note_info(&info, signr, env) < 0)
+        goto out;
+
+    offset += sizeof (elf);                             /* elf header */
+    offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
+
+    /* write out notes program header */
+    fill_elf_note_phdr(&phdr, info.notes_size, offset);
+
+    offset += info.notes_size;
+    if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
+        goto out;
+
+    /*
+     * ELF specification wants data to start at page boundary so
+     * we align it here.
+     */
+    data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+
+    /*
+     * Write program headers for memory regions mapped in
+     * the target process.
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        (void) memset(&phdr, 0, sizeof (phdr));
+
+        phdr.p_type = PT_LOAD;
+        phdr.p_offset = offset;
+        phdr.p_vaddr = vma->vma_start;
+        phdr.p_paddr = 0;
+        phdr.p_filesz = vma_dump_size(vma);
+        offset += phdr.p_filesz;
+        phdr.p_memsz = vma->vma_end - vma->vma_start;
+        phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
+        if (vma->vma_flags & PROT_WRITE)
+            phdr.p_flags |= PF_W;
+        if (vma->vma_flags & PROT_EXEC)
+            phdr.p_flags |= PF_X;
+        phdr.p_align = ELF_EXEC_PAGESIZE;
+
+        bswap_phdr(&phdr, 1);
+        dump_write(fd, &phdr, sizeof (phdr));
+    }
+
+    /*
+     * Next we write notes just after program headers.  No
+     * alignment needed here.
+     */
+    if (write_note_info(&info, fd) < 0)
+        goto out;
+
+    /* align data to page boundary */
+    if (lseek(fd, data_offset, SEEK_SET) != data_offset)
+        goto out;
+
+    /*
+     * Finally we can dump process memory into corefile as well.
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        abi_ulong addr;
+        abi_ulong end;
+
+        end = vma->vma_start + vma_dump_size(vma);
+
+        for (addr = vma->vma_start; addr < end;
+             addr += TARGET_PAGE_SIZE) {
+            char page[TARGET_PAGE_SIZE];
+            int error;
+
+            /*
+             *  Read in page from target process memory and
+             *  write it to coredump file.
+             */
+            error = copy_from_user(page, addr, sizeof (page));
+            if (error != 0) {
+                (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
+                               addr);
+                errno = -error;
+                goto out;
+            }
+            if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
+                goto out;
+        }
+    }
+
+ out:
+    free_note_info(&info);
+    if (mm != NULL)
+        vma_delete(mm);
+    (void) close(fd);
+
+    if (errno != 0)
+        return (-errno);
+    return (0);
+}
+#endif /* USE_ELF_CORE_DUMP */
+
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    init_thread(regs, infop);
+}
diff --git a/qemu-0.15.x/linux-user/errno_defs.h b/qemu-0.15.x/linux-user/errno_defs.h
new file mode 100644
index 0000000..8a1cf76
--- /dev/null
+++ b/qemu-0.15.x/linux-user/errno_defs.h
@@ -0,0 +1,141 @@
+/*
+ * Target definitions of errnos. These may be overridden by an
+ * architecture specific header if needed.
+ *
+ * Taken from asm-generic/errno-base.h and asm-generic/errno.h
+ */
+#define TARGET_EPERM            1      /* Operation not permitted */
+#define TARGET_ENOENT           2      /* No such file or directory */
+#define TARGET_ESRCH            3      /* No such process */
+#define TARGET_EINTR            4      /* Interrupted system call */
+#define TARGET_EIO              5      /* I/O error */
+#define TARGET_ENXIO            6      /* No such device or address */
+#define TARGET_E2BIG            7      /* Argument list too long */
+#define TARGET_ENOEXEC          8      /* TARGET_Exec format error */
+#define TARGET_EBADF            9      /* Bad file number */
+#define TARGET_ECHILD          10      /* No child processes */
+#define TARGET_EAGAIN          11      /* Try again */
+#define TARGET_ENOMEM          12      /* Out of memory */
+#define TARGET_EACCES          13      /* Permission denied */
+#define TARGET_EFAULT          14      /* Bad address */
+#define TARGET_ENOTBLK         15      /* Block device required */
+#define TARGET_EBUSY           16      /* Device or resource busy */
+#define TARGET_EEXIST          17      /* File exists */
+#define TARGET_EXDEV           18      /* Cross-device link */
+#define TARGET_ENODEV          19      /* No such device */
+#define TARGET_ENOTDIR         20      /* Not a directory */
+#define TARGET_EISDIR          21      /* Is a directory */
+#define TARGET_EINVAL          22      /* Invalid argument */
+#define TARGET_ENFILE          23      /* File table overflow */
+#define TARGET_EMFILE          24      /* Too many open files */
+#define TARGET_ENOTTY          25      /* Not a typewriter */
+#define TARGET_ETXTBSY         26      /* Text file busy */
+#define TARGET_EFBIG           27      /* File too large */
+#define TARGET_ENOSPC          28      /* No space left on device */
+#define TARGET_ESPIPE          29      /* Illegal seek */
+#define TARGET_EROFS           30      /* Read-only file system */
+#define TARGET_EMLINK          31      /* Too many links */
+#define TARGET_EPIPE           32      /* Broken pipe */
+#define TARGET_EDOM            33      /* Math argument out of domain of func */
+#define TARGET_ERANGE          34      /* Math result not representable */
+
+#define TARGET_EDEADLK         35      /* Resource deadlock would occur */
+#define TARGET_ENAMETOOLONG    36      /* File name too long */
+#define TARGET_ENOLCK          37      /* No record locks available */
+#define TARGET_ENOSYS          38      /* Function not implemented */
+#define TARGET_ENOTEMPTY       39      /* Directory not empty */
+#define TARGET_ELOOP           40      /* Too many symbolic links encountered */
+
+#define TARGET_ENOMSG          42      /* No message of desired type */
+#define TARGET_EIDRM           43      /* Identifier removed */
+#define TARGET_ECHRNG          44      /* Channel number out of range */
+#define TARGET_EL2NSYNC        45      /* Level 2 not synchronized */
+#define TARGET_EL3HLT          46      /* Level 3 halted */
+#define TARGET_EL3RST          47      /* Level 3 reset */
+#define TARGET_ELNRNG          48      /* Link number out of range */
+#define TARGET_EUNATCH         49      /* Protocol driver not attached */
+#define TARGET_ENOCSI          50      /* No CSI structure available */
+#define TARGET_EL2HLT          51      /* Level 2 halted */
+#define TARGET_EBADE           52      /* Invalid exchange */
+#define TARGET_EBADR           53      /* Invalid request descriptor */
+#define TARGET_EXFULL          54      /* TARGET_Exchange full */
+#define TARGET_ENOANO          55      /* No anode */
+#define TARGET_EBADRQC         56      /* Invalid request code */
+#define TARGET_EBADSLT         57      /* Invalid slot */
+
+#define TARGET_EBFONT          59      /* Bad font file format */
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#define TARGET_ENODATA         61      /* No data available */
+#define TARGET_ETIME           62      /* Timer expired */
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#define TARGET_ENOPKG          65      /* Package not installed */
+#define TARGET_EREMOTE         66      /* Object is remote */
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#define TARGET_EADV            68      /* Advertise error */
+#define TARGET_ESRMNT          69      /* Srmount error */
+#define TARGET_ECOMM           70      /* Communication error on send */
+#define TARGET_EPROTO          71      /* Protocol error */
+#define TARGET_EMULTIHOP       72      /* Multihop attempted */
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#define TARGET_EBADMSG         74      /* Not a data message */
+#define TARGET_EOVERFLOW       75      /* Value too large for defined data type */
+#define TARGET_ENOTUNIQ        76      /* Name not unique on network */
+#define TARGET_EBADFD          77      /* File descriptor in bad state */
+#define TARGET_EREMCHG         78      /* Remote address changed */
+#define TARGET_ELIBACC         79      /* Can not access a needed shared library */
+#define TARGET_ELIBBAD         80      /* Accessing a corrupted shared library */
+#define TARGET_ELIBSCN         81      /* .lib section in a.out corrupted */
+#define TARGET_ELIBMAX         82      /* Attempting to link in too many shared libraries */
+#define TARGET_ELIBEXEC        83      /* Cannot exec a shared library directly */
+#define TARGET_EILSEQ          84      /* Illegal byte sequence */
+#define TARGET_ERESTART        85      /* Interrupted system call should be restarted */
+#define TARGET_ESTRPIPE        86      /* Streams pipe error */
+#define TARGET_EUSERS          87      /* Too many users */
+#define TARGET_ENOTSOCK        88      /* Socket operation on non-socket */
+#define TARGET_EDESTADDRREQ    89      /* Destination address required */
+#define TARGET_EMSGSIZE        90      /* Message too long */
+#define TARGET_EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define TARGET_ENOPROTOOPT     92      /* Protocol not available */
+#define TARGET_EPROTONOSUPPORT 93      /* Protocol not supported */
+#define TARGET_ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define TARGET_EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
+#define TARGET_EPFNOSUPPORT    96      /* Protocol family not supported */
+#define TARGET_EAFNOSUPPORT    97      /* Address family not supported by protocol */
+#define TARGET_EADDRINUSE      98      /* Address already in use */
+#define TARGET_EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define TARGET_ENETDOWN        100     /* Network is down */
+#define TARGET_ENETUNREACH     101     /* Network is unreachable */
+#define TARGET_ENETRESET       102     /* Network dropped connection because of reset */
+#define TARGET_ECONNABORTED    103     /* Software caused connection abort */
+#define TARGET_ECONNRESET      104     /* Connection reset by peer */
+#define TARGET_ENOBUFS         105     /* No buffer space available */
+#define TARGET_EISCONN         106     /* Transport endpoint is already connected */
+#define TARGET_ENOTCONN        107     /* Transport endpoint is not connected */
+#define TARGET_ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
+#define TARGET_ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define TARGET_ETIMEDOUT       110     /* Connection timed out */
+#define TARGET_ECONNREFUSED    111     /* Connection refused */
+#define TARGET_EHOSTDOWN       112     /* Host is down */
+#define TARGET_EHOSTUNREACH    113     /* No route to host */
+#define TARGET_EALREADY        114     /* Operation already in progress */
+#define TARGET_EINPROGRESS     115     /* Operation now in progress */
+#define TARGET_ESTALE          116     /* Stale NFS file handle */
+#define TARGET_EUCLEAN         117     /* Structure needs cleaning */
+#define TARGET_ENOTNAM         118     /* Not a XENIX named type file */
+#define TARGET_ENAVAIL         119     /* No XENIX semaphores available */
+#define TARGET_EISNAM          120     /* Is a named type file */
+#define TARGET_EREMOTEIO       121     /* Remote I/O error */
+#define TARGET_EDQUOT          122     /* Quota exceeded */
+
+#define TARGET_ENOMEDIUM       123     /* No medium found */
+#define TARGET_EMEDIUMTYPE     124     /* Wrong medium type */
+#define TARGET_ECANCELED       125     /* Operation Canceled */
+#define TARGET_ENOKEY          126     /* Required key not available */
+#define TARGET_EKEYEXPIRED     127     /* Key has expired */
+#define TARGET_EKEYREVOKED     128     /* Key has been revoked */
+#define TARGET_EKEYREJECTED    129     /* Key was rejected by service */
+
+/* for robust mutexes */
+#define TARGET_EOWNERDEAD      130     /* Owner died */
+#define TARGET_ENOTRECOVERABLE 131     /* State not recoverable */
diff --git a/qemu-0.15.x/linux-user/flat.h b/qemu-0.15.x/linux-user/flat.h
new file mode 100644
index 0000000..6f2d0c4
--- /dev/null
+++ b/qemu-0.15.x/linux-user/flat.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2002-2003  David McCullough <davidm at snapgear.com>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds at kjahds.com>
+ *                          The Silver Hammer Group, Ltd.
+ *
+ * This file provides the definitions and structures needed to
+ * support uClinux flat-format executables.
+ */
+
+#define	FLAT_VERSION			0x00000004L
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#define	MAX_SHARED_LIBS			(4)
+#else
+#define	MAX_SHARED_LIBS			(1)
+#endif
+
+/*
+ * To make everything easier to port and manage cross platform
+ * development,  all fields are in network byte order.
+ */
+
+struct flat_hdr {
+	char magic[4];
+	abi_ulong rev;          /* version (as above) */
+	abi_ulong entry;        /* Offset of first executable instruction
+                                   with text segment from beginning of file */
+	abi_ulong data_start;   /* Offset of data segment from beginning of
+                                   file */
+	abi_ulong data_end;     /* Offset of end of data segment
+                                   from beginning of file */
+	abi_ulong bss_end;      /* Offset of end of bss segment from beginning
+                                   of file */
+
+	/* (It is assumed that data_end through bss_end forms the bss segment.) */
+
+	abi_ulong stack_size;   /* Size of stack, in bytes */
+	abi_ulong reloc_start;  /* Offset of relocation records from
+                                   beginning of file */
+	abi_ulong reloc_count;  /* Number of relocation records */
+	abi_ulong flags;
+	abi_ulong build_date;   /* When the program/library was built */
+	abi_ulong filler[5];    /* Reservered, set to zero */
+};
+
+#define FLAT_FLAG_RAM    0x0001 /* load program entirely into RAM */
+#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
+#define FLAT_FLAG_GZIP   0x0004 /* all but the header is compressed */
+#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
+#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
+
+
+/*
+ * While it would be nice to keep this header clean,  users of older
+ * tools still need this support in the kernel.  So this section is
+ * purely for compatibility with old tool chains.
+ *
+ * DO NOT make changes or enhancements to the old format please,  just work
+ *        with the format above,  except to fix bugs with old format support.
+ */
+
+#define	OLD_FLAT_VERSION			0x00000002L
+#define OLD_FLAT_RELOC_TYPE_TEXT	0
+#define OLD_FLAT_RELOC_TYPE_DATA	1
+#define OLD_FLAT_RELOC_TYPE_BSS		2
+
+#   	define OLD_FLAT_FLAG_RAM    0x1 /* load program entirely into RAM */
diff --git a/qemu-0.15.x/linux-user/flatload.c b/qemu-0.15.x/linux-user/flatload.c
new file mode 100644
index 0000000..1062da3
--- /dev/null
+++ b/qemu-0.15.x/linux-user/flatload.c
@@ -0,0 +1,813 @@
+/****************************************************************************/
+/*
+ *  QEMU bFLT binary loader.  Based on linux/fs/binfmt_flat.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *      Copyright (C) 2006 CodeSourcery.
+ *	Copyright (C) 2000-2003 David McCullough <davidm at snapgear.com>
+ *	Copyright (C) 2002 Greg Ungerer <gerg at snapgear.com>
+ *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli at snapgear.com>
+ *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm at lineo.com>
+ *  based heavily on:
+ *
+ *  linux/fs/binfmt_aout.c:
+ *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
+ *  linux/fs/binfmt_flat.c for 2.0 kernel
+ *	    Copyright (C) 1998  Kenneth Albanowski <kjahds at kjahds.com>
+ *	JAN/99 -- coded full program relocation (gerg at snapgear.com)
+ */
+
+/* ??? ZFLAT and shared library support is currently disabled.  */
+
+/****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "qemu.h"
+#include "flat.h"
+#define ntohl(x) be32_to_cpu(x)
+#include <target_flat.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define	DBG_FLT(...)	printf(__VA_ARGS__)
+#else
+#define	DBG_FLT(...)
+#endif
+
+#define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
+#define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
+
+struct lib_info {
+    abi_ulong start_code;       /* Start of text segment */
+    abi_ulong start_data;       /* Start of data segment */
+    abi_ulong end_data;         /* Start of bss section */
+    abi_ulong start_brk;        /* End of data segment */
+    abi_ulong text_len;	        /* Length of text segment */
+    abi_ulong entry;	        /* Start address for this module */
+    abi_ulong build_date;       /* When this one was compiled */
+    short loaded;		/* Has this library been loaded? */
+};
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+static int load_flat_shared_library(int id, struct lib_info *p);
+#endif
+
+struct linux_binprm;
+
+/****************************************************************************/
+/*
+ * create_flat_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+
+/* Push a block of strings onto the guest stack.  */
+static abi_ulong copy_strings(abi_ulong p, int n, char **s)
+{
+    int len;
+
+    while (n-- > 0) {
+        len = strlen(s[n]) + 1;
+        p -= len;
+        memcpy_to_target(p, s[n], len);
+    }
+
+    return p;
+}
+
+static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
+                        abi_ulong offset)
+{
+    void *buf;
+    int ret;
+
+    buf = lock_user(VERIFY_WRITE, ptr, len, 0);
+    ret = pread(fd, buf, len, offset);
+    unlock_user(buf, ptr, len);
+    return ret;
+}
+/****************************************************************************/
+
+#ifdef CONFIG_BINFMT_ZFLAT
+
+#include <linux/zlib.h>
+
+#define LBUFSIZE	4000
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+static int decompress_exec(
+	struct linux_binprm *bprm,
+	unsigned long offset,
+	char *dst,
+	long len,
+	int fd)
+{
+	unsigned char *buf;
+	z_stream strm;
+	loff_t fpos;
+	int ret, retval;
+
+	DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
+
+	memset(&strm, 0, sizeof(strm));
+	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+	if (strm.workspace == NULL) {
+		DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
+		return -ENOMEM;
+	}
+	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
+	if (buf == NULL) {
+		DBG_FLT("binfmt_flat: no memory for read buffer\n");
+		retval = -ENOMEM;
+		goto out_free;
+	}
+
+	/* Read in first chunk of data and parse gzip header. */
+	fpos = offset;
+	ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
+
+	strm.next_in = buf;
+	strm.avail_in = ret;
+	strm.total_in = 0;
+
+	retval = -ENOEXEC;
+
+	/* Check minimum size -- gzip header */
+	if (ret < 10) {
+		DBG_FLT("binfmt_flat: file too small?\n");
+		goto out_free_buf;
+	}
+
+	/* Check gzip magic number */
+	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
+		DBG_FLT("binfmt_flat: unknown compression magic?\n");
+		goto out_free_buf;
+	}
+
+	/* Check gzip method */
+	if (buf[2] != 8) {
+		DBG_FLT("binfmt_flat: unknown compression method?\n");
+		goto out_free_buf;
+	}
+	/* Check gzip flags */
+	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
+	    (buf[3] & RESERVED)) {
+		DBG_FLT("binfmt_flat: unknown flags?\n");
+		goto out_free_buf;
+	}
+
+	ret = 10;
+	if (buf[3] & EXTRA_FIELD) {
+		ret += 2 + buf[10] + (buf[11] << 8);
+		if (unlikely(LBUFSIZE == ret)) {
+			DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
+			goto out_free_buf;
+		}
+	}
+	if (buf[3] & ORIG_NAME) {
+		for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
+			;
+		if (unlikely(LBUFSIZE == ret)) {
+			DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
+			goto out_free_buf;
+		}
+	}
+	if (buf[3] & COMMENT) {
+		for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
+			;
+		if (unlikely(LBUFSIZE == ret)) {
+			DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
+			goto out_free_buf;
+		}
+	}
+
+	strm.next_in += ret;
+	strm.avail_in -= ret;
+
+	strm.next_out = dst;
+	strm.avail_out = len;
+	strm.total_out = 0;
+
+	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
+		DBG_FLT("binfmt_flat: zlib init failed?\n");
+		goto out_free_buf;
+	}
+
+	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
+		ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
+		if (ret <= 0)
+			break;
+		if (ret >= (unsigned long) -4096)
+			break;
+		len -= ret;
+
+		strm.next_in = buf;
+		strm.avail_in = ret;
+		strm.total_in = 0;
+	}
+
+	if (ret < 0) {
+		DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
+			ret, strm.msg);
+		goto out_zlib;
+	}
+
+	retval = 0;
+out_zlib:
+	zlib_inflateEnd(&strm);
+out_free_buf:
+	kfree(buf);
+out_free:
+	kfree(strm.workspace);
+out:
+	return retval;
+}
+
+#endif /* CONFIG_BINFMT_ZFLAT */
+
+/****************************************************************************/
+
+static abi_ulong
+calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
+{
+    abi_ulong addr;
+    int id;
+    abi_ulong start_brk;
+    abi_ulong start_data;
+    abi_ulong text_len;
+    abi_ulong start_code;
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#error needs checking
+    if (r == 0)
+        id = curid;	/* Relocs of 0 are always self referring */
+    else {
+        id = (r >> 24) & 0xff;	/* Find ID for this reloc */
+        r &= 0x00ffffff;	/* Trim ID off here */
+    }
+    if (id >= MAX_SHARED_LIBS) {
+        fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
+                (unsigned) r, id);
+        goto failed;
+    }
+    if (curid != id) {
+        if (internalp) {
+            fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
+                    "in same module (%d != %d)\n",
+                    (unsigned) r, curid, id);
+            goto failed;
+        } else if ( ! p[id].loaded &&
+                    load_flat_shared_library(id, p) > (unsigned long) -4096) {
+            fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
+            goto failed;
+        }
+        /* Check versioning information (i.e. time stamps) */
+        if (p[id].build_date && p[curid].build_date
+            && p[curid].build_date < p[id].build_date) {
+            fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
+                    id, curid);
+            goto failed;
+        }
+    }
+#else
+    id = 0;
+#endif
+
+    start_brk = p[id].start_brk;
+    start_data = p[id].start_data;
+    start_code = p[id].start_code;
+    text_len = p[id].text_len;
+
+    if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
+        fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
+                "(0 - 0x%x/0x%x)\n",
+               (int) r,(int)(start_brk-start_code),(int)text_len);
+        goto failed;
+    }
+
+    if (r < text_len)			/* In text segment */
+        addr = r + start_code;
+    else					/* In data segment */
+        addr = r - text_len + start_data;
+
+    /* Range checked already above so doing the range tests is redundant...*/
+    return(addr);
+
+failed:
+    abort();
+    return RELOC_FAILED;
+}
+
+/****************************************************************************/
+
+/* ??? This does not handle endianness correctly.  */
+static void old_reloc(struct lib_info *libinfo, uint32_t rl)
+{
+#ifdef DEBUG
+	const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
+#endif
+	uint32_t *ptr;
+        uint32_t offset;
+        int reloc_type;
+
+        offset = rl & 0x3fffffff;
+        reloc_type = rl >> 30;
+        /* ??? How to handle this?  */
+#if defined(CONFIG_COLDFIRE)
+	ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset);
+#else
+	ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset);
+#endif
+
+#ifdef DEBUG
+	fprintf(stderr, "Relocation of variable at DATASEG+%x "
+		"(address %p, currently %x) into segment %s\n",
+		offset, ptr, (int)*ptr, segment[reloc_type]);
+#endif
+
+	switch (reloc_type) {
+	case OLD_FLAT_RELOC_TYPE_TEXT:
+		*ptr += libinfo->start_code;
+		break;
+	case OLD_FLAT_RELOC_TYPE_DATA:
+		*ptr += libinfo->start_data;
+		break;
+	case OLD_FLAT_RELOC_TYPE_BSS:
+		*ptr += libinfo->end_data;
+		break;
+	default:
+		fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
+                        reloc_type);
+		break;
+	}
+	DBG_FLT("Relocation became %x\n", (int)*ptr);
+}
+
+/****************************************************************************/
+
+static int load_flat_file(struct linux_binprm * bprm,
+		struct lib_info *libinfo, int id, abi_ulong *extra_stack)
+{
+    struct flat_hdr * hdr;
+    abi_ulong textpos = 0, datapos = 0;
+    abi_long result;
+    abi_ulong realdatastart = 0;
+    abi_ulong text_len, data_len, bss_len, stack_len, flags;
+    abi_ulong extra;
+    abi_ulong reloc = 0, rp;
+    int i, rev, relocs = 0;
+    abi_ulong fpos;
+    abi_ulong start_code;
+    abi_ulong indx_len;
+
+    hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
+
+    text_len  = ntohl(hdr->data_start);
+    data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
+    bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
+    stack_len = ntohl(hdr->stack_size);
+    if (extra_stack) {
+        stack_len += *extra_stack;
+        *extra_stack = stack_len;
+    }
+    relocs    = ntohl(hdr->reloc_count);
+    flags     = ntohl(hdr->flags);
+    rev       = ntohl(hdr->rev);
+
+    DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
+
+    if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
+        fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
+                rev, (int) FLAT_VERSION);
+        return -ENOEXEC;
+    }
+
+    /* Don't allow old format executables to use shared libraries */
+    if (rev == OLD_FLAT_VERSION && id != 0) {
+        fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
+        return -ENOEXEC;
+    }
+
+    /*
+     * fix up the flags for the older format,  there were all kinds
+     * of endian hacks,  this only works for the simple cases
+     */
+    if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
+        flags = FLAT_FLAG_RAM;
+
+#ifndef CONFIG_BINFMT_ZFLAT
+    if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
+        fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
+        return -ENOEXEC;
+    }
+#endif
+
+    /*
+     * calculate the extra space we need to map in
+     */
+    extra = relocs * sizeof(abi_ulong);
+    if (extra < bss_len + stack_len)
+        extra = bss_len + stack_len;
+
+    /* Add space for library base pointers.  Make sure this does not
+       misalign the  doesn't misalign the data segment.  */
+    indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
+    indx_len = (indx_len + 15) & ~(abi_ulong)15;
+
+    /*
+     * there are a couple of cases here,  the separate code/data
+     * case,  and then the fully copied to RAM case which lumps
+     * it all together.
+     */
+    if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
+        /*
+         * this should give us a ROM ptr,  but if it doesn't we don't
+         * really care
+         */
+        DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
+
+        textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
+                              MAP_PRIVATE, bprm->fd, 0);
+        if (textpos == -1) {
+            fprintf(stderr, "Unable to mmap process text\n");
+            return -1;
+        }
+
+        realdatastart = target_mmap(0, data_len + extra + indx_len,
+                                    PROT_READ|PROT_WRITE|PROT_EXEC,
+                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+        if (realdatastart == -1) {
+            fprintf(stderr, "Unable to allocate RAM for process data\n");
+            return realdatastart;
+        }
+        datapos = realdatastart + indx_len;
+
+        DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
+                        (int)(data_len + bss_len + stack_len), (int)datapos);
+
+        fpos = ntohl(hdr->data_start);
+#ifdef CONFIG_BINFMT_ZFLAT
+        if (flags & FLAT_FLAG_GZDATA) {
+            result = decompress_exec(bprm, fpos, (char *) datapos,
+                                     data_len + (relocs * sizeof(abi_ulong)))
+        } else
+#endif
+        {
+            result = target_pread(bprm->fd, datapos,
+                                  data_len + (relocs * sizeof(abi_ulong)),
+                                  fpos);
+        }
+        if (result < 0) {
+            fprintf(stderr, "Unable to read data+bss\n");
+            return result;
+        }
+
+        reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
+
+    } else {
+
+        textpos = target_mmap(0, text_len + data_len + extra + indx_len,
+                              PROT_READ | PROT_EXEC | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+        if (textpos == -1 ) {
+            fprintf(stderr, "Unable to allocate RAM for process text/data\n");
+            return -1;
+        }
+
+        realdatastart = textpos + ntohl(hdr->data_start);
+        datapos = realdatastart + indx_len;
+        reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
+
+#ifdef CONFIG_BINFMT_ZFLAT
+#error code needs checking
+        /*
+         * load it all in and treat it like a RAM load from now on
+         */
+        if (flags & FLAT_FLAG_GZIP) {
+                result = decompress_exec(bprm, sizeof (struct flat_hdr),
+                                 (((char *) textpos) + sizeof (struct flat_hdr)),
+                                 (text_len + data_len + (relocs * sizeof(unsigned long))
+                                          - sizeof (struct flat_hdr)),
+                                 0);
+                memmove((void *) datapos, (void *) realdatastart,
+                                data_len + (relocs * sizeof(unsigned long)));
+        } else if (flags & FLAT_FLAG_GZDATA) {
+                fpos = 0;
+                result = bprm->file->f_op->read(bprm->file,
+                                (char *) textpos, text_len, &fpos);
+                if (result < (unsigned long) -4096)
+                        result = decompress_exec(bprm, text_len, (char *) datapos,
+                                         data_len + (relocs * sizeof(unsigned long)), 0);
+        }
+        else
+#endif
+        {
+            result = target_pread(bprm->fd, textpos,
+                                  text_len, 0);
+            if (result >= 0) {
+                result = target_pread(bprm->fd, datapos,
+                    data_len + (relocs * sizeof(abi_ulong)),
+                    ntohl(hdr->data_start));
+            }
+        }
+        if (result < 0) {
+            fprintf(stderr, "Unable to read code+data+bss\n");
+            return result;
+        }
+    }
+
+    DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n",
+            (int)textpos, 0x00ffffff&ntohl(hdr->entry),
+            ntohl(hdr->data_start));
+
+    /* The main program needs a little extra setup in the task structure */
+    start_code = textpos + sizeof (struct flat_hdr);
+
+    DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
+            id ? "Lib" : "Load", bprm->filename,
+            (int) start_code, (int) (textpos + text_len),
+            (int) datapos,
+            (int) (datapos + data_len),
+            (int) (datapos + data_len),
+            (int) (((datapos + data_len + bss_len) + 3) & ~3));
+
+    text_len -= sizeof(struct flat_hdr); /* the real code len */
+
+    /* Store the current module values into the global library structure */
+    libinfo[id].start_code = start_code;
+    libinfo[id].start_data = datapos;
+    libinfo[id].end_data = datapos + data_len;
+    libinfo[id].start_brk = datapos + data_len + bss_len;
+    libinfo[id].text_len = text_len;
+    libinfo[id].loaded = 1;
+    libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
+    libinfo[id].build_date = ntohl(hdr->build_date);
+
+    /*
+     * We just load the allocations into some temporary memory to
+     * help simplify all this mumbo jumbo
+     *
+     * We've got two different sections of relocation entries.
+     * The first is the GOT which resides at the begining of the data segment
+     * and is terminated with a -1.  This one can be relocated in place.
+     * The second is the extra relocation entries tacked after the image's
+     * data segment. These require a little more processing as the entry is
+     * really an offset into the image which contains an offset into the
+     * image.
+     */
+    if (flags & FLAT_FLAG_GOTPIC) {
+        rp = datapos;
+        while (1) {
+            abi_ulong addr;
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
+            if (addr == -1)
+                break;
+            if (addr) {
+                addr = calc_reloc(addr, libinfo, id, 0);
+                if (addr == RELOC_FAILED)
+                    return -ENOEXEC;
+                if (put_user_ual(addr, rp))
+                    return -EFAULT;
+            }
+            rp += sizeof(abi_ulong);
+        }
+    }
+
+    /*
+     * Now run through the relocation entries.
+     * We've got to be careful here as C++ produces relocatable zero
+     * entries in the constructor and destructor tables which are then
+     * tested for being not zero (which will always occur unless we're
+     * based from address zero).  This causes an endless loop as __start
+     * is at zero.  The solution used is to not relocate zero addresses.
+     * This has the negative side effect of not allowing a global data
+     * reference to be statically initialised to _stext (I've moved
+     * __start to address 4 so that is okay).
+     */
+    if (rev > OLD_FLAT_VERSION) {
+        abi_ulong persistent = 0;
+        for (i = 0; i < relocs; i++) {
+            abi_ulong addr, relval;
+
+            /* Get the address of the pointer to be
+               relocated (of course, the address has to be
+               relocated first).  */
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
+            relval = ntohl(relval);
+            if (flat_set_persistent(relval, &persistent))
+                continue;
+            addr = flat_get_relocate_addr(relval);
+            rp = calc_reloc(addr, libinfo, id, 1);
+            if (rp == RELOC_FAILED)
+                return -ENOEXEC;
+
+            /* Get the pointer's value.  */
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
+            addr = flat_get_addr_from_rp(rp, relval, flags, &persistent);
+            if (addr != 0) {
+                /*
+                 * Do the relocation.  PIC relocs in the data section are
+                 * already in target order
+                 */
+                if ((flags & FLAT_FLAG_GOTPIC) == 0)
+                    addr = ntohl(addr);
+                addr = calc_reloc(addr, libinfo, id, 0);
+                if (addr == RELOC_FAILED)
+                    return -ENOEXEC;
+
+                /* Write back the relocated pointer.  */
+                if (flat_put_addr_at_rp(rp, addr, relval))
+                    return -EFAULT;
+            }
+        }
+    } else {
+        for (i = 0; i < relocs; i++) {
+            abi_ulong relval;
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
+            old_reloc(&libinfo[0], relval);
+        }
+    }
+
+    /* zero the BSS.  */
+    memset((void *)((unsigned long)datapos + data_len), 0, bss_len);
+
+    return 0;
+}
+
+
+/****************************************************************************/
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+
+/*
+ * Load a shared library into memory.  The library gets its own data
+ * segment (including bss) but not argv/argc/environ.
+ */
+
+static int load_flat_shared_library(int id, struct lib_info *libs)
+{
+	struct linux_binprm bprm;
+	int res;
+	char buf[16];
+
+	/* Create the file name */
+	sprintf(buf, "/lib/lib%d.so", id);
+
+	/* Open the file up */
+	bprm.filename = buf;
+	bprm.file = open_exec(bprm.filename);
+	res = PTR_ERR(bprm.file);
+	if (IS_ERR(bprm.file))
+		return res;
+
+	res = prepare_binprm(&bprm);
+
+	if (res <= (unsigned long)-4096)
+		res = load_flat_file(&bprm, libs, id, NULL);
+	if (bprm.file) {
+		allow_write_access(bprm.file);
+		fput(bprm.file);
+		bprm.file = NULL;
+	}
+	return(res);
+}
+
+#endif /* CONFIG_BINFMT_SHARED_FLAT */
+
+int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info)
+{
+    struct lib_info libinfo[MAX_SHARED_LIBS];
+    abi_ulong p = bprm->p;
+    abi_ulong stack_len;
+    abi_ulong start_addr;
+    abi_ulong sp;
+    int res;
+    int i, j;
+
+    memset(libinfo, 0, sizeof(libinfo));
+    /*
+     * We have to add the size of our arguments to our stack size
+     * otherwise it's too easy for users to create stack overflows
+     * by passing in a huge argument list.  And yes,  we have to be
+     * pedantic and include space for the argv/envp array as it may have
+     * a lot of entries.
+     */
+    stack_len = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        /* the argv strings */
+        stack_len += strlen(bprm->argv[i]);
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        /* the envp strings */
+        stack_len += strlen(bprm->envp[i]);
+    }
+    stack_len += (bprm->argc + 1) * 4; /* the argv array */
+    stack_len += (bprm->envc + 1) * 4; /* the envp array */
+
+
+    res = load_flat_file(bprm, libinfo, 0, &stack_len);
+    if (res > (unsigned long)-4096)
+            return res;
+
+    /* Update data segment pointers for all libraries */
+    for (i=0; i<MAX_SHARED_LIBS; i++) {
+        if (libinfo[i].loaded) {
+            abi_ulong p;
+            p = libinfo[i].start_data;
+            for (j=0; j<MAX_SHARED_LIBS; j++) {
+                p -= 4;
+                /* FIXME - handle put_user() failures */
+                if (put_user_ual(libinfo[j].loaded
+                                 ? libinfo[j].start_data
+                                 : UNLOADED_LIB,
+                                 p))
+                    return -EFAULT;
+            }
+        }
+    }
+
+    p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4;
+    DBG_FLT("p=%x\n", (int)p);
+
+    /* Copy argv/envp.  */
+    p = copy_strings(p, bprm->envc, bprm->envp);
+    p = copy_strings(p, bprm->argc, bprm->argv);
+    /* Align stack.  */
+    sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1);
+    /* Enforce final stack alignment of 16 bytes.  This is sufficient
+       for all current targets, and excess alignment is harmless.  */
+    stack_len = bprm->envc + bprm->argc + 2;
+    stack_len += 3;	/* argc, arvg, argp */
+    stack_len *= sizeof(abi_ulong);
+    if ((sp + stack_len) & 15)
+        sp -= 16 - ((sp + stack_len) & 15);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
+                             flat_argvp_envp_on_stack());
+
+    /* Fake some return addresses to ensure the call chain will
+     * initialise library in order for us.  We are required to call
+     * lib 1 first, then 2, ... and finally the main program (id 0).
+     */
+    start_addr = libinfo[0].entry;
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+#error here
+    for (i = MAX_SHARED_LIBS-1; i>0; i--) {
+            if (libinfo[i].loaded) {
+                    /* Push previos first to call address */
+                    --sp;
+                    if (put_user_ual(start_addr, sp))
+                        return -EFAULT;
+                    start_addr = libinfo[i].entry;
+            }
+    }
+#endif
+
+    /* Stash our initial stack pointer into the mm structure */
+    info->start_code = libinfo[0].start_code;
+    info->end_code = libinfo[0].start_code = libinfo[0].text_len;
+    info->start_data = libinfo[0].start_data;
+    info->end_data = libinfo[0].end_data;
+    info->start_brk = libinfo[0].start_brk;
+    info->start_stack = sp;
+    info->stack_limit = libinfo[0].start_brk;
+    info->entry = start_addr;
+    info->code_offset = info->start_code;
+    info->data_offset = info->start_data - libinfo[0].text_len;
+
+    DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
+            (int)info->entry, (int)info->start_stack);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/linux-user/i386/syscall.h b/qemu-0.15.x/linux-user/i386/syscall.h
new file mode 100644
index 0000000..266e2c4
--- /dev/null
+++ b/qemu-0.15.x/linux-user/i386/syscall.h
@@ -0,0 +1,146 @@
+/* default linux values for the selectors */
+#define __USER_CS	(0x23)
+#define __USER_DS	(0x2B)
+
+struct target_pt_regs {
+	long ebx;
+	long ecx;
+	long edx;
+	long esi;
+	long edi;
+	long ebp;
+	long eax;
+	int  xds;
+	int  xes;
+	long orig_eax;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+
+/* ioctls */
+
+#define TARGET_LDT_ENTRIES      8192
+#define TARGET_LDT_ENTRY_SIZE	8
+
+#define TARGET_GDT_ENTRIES             9
+#define TARGET_GDT_ENTRY_TLS_ENTRIES   3
+#define TARGET_GDT_ENTRY_TLS_MIN       6
+#define TARGET_GDT_ENTRY_TLS_MAX       (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
+
+struct target_modify_ldt_ldt_s {
+    unsigned int  entry_number;
+    abi_ulong base_addr;
+    unsigned int limit;
+    unsigned int flags;
+};
+
+/* vm86 defines */
+
+#define TARGET_BIOSSEG		0x0f000
+
+#define TARGET_CPU_086		0
+#define TARGET_CPU_186		1
+#define TARGET_CPU_286		2
+#define TARGET_CPU_386		3
+#define TARGET_CPU_486		4
+#define TARGET_CPU_586		5
+
+#define TARGET_VM86_SIGNAL	0	/* return due to signal */
+#define TARGET_VM86_UNKNOWN	1	/* unhandled GP fault - IO-instruction or similar */
+#define TARGET_VM86_INTx	2	/* int3/int x instruction (ARG = x) */
+#define TARGET_VM86_STI	3	/* sti/popf/iret instruction enabled virtual interrupts */
+
+/*
+ * Additional return values when invoking new vm86()
+ */
+#define TARGET_VM86_PICRETURN	4	/* return due to pending PIC request */
+#define TARGET_VM86_TRAP	6	/* return due to DOS-debugger request */
+
+/*
+ * function codes when invoking new vm86()
+ */
+#define TARGET_VM86_PLUS_INSTALL_CHECK	0
+#define TARGET_VM86_ENTER		1
+#define TARGET_VM86_ENTER_NO_BYPASS	2
+#define	TARGET_VM86_REQUEST_IRQ	3
+#define TARGET_VM86_FREE_IRQ		4
+#define TARGET_VM86_GET_IRQ_BITS	5
+#define TARGET_VM86_GET_AND_RESET_IRQ	6
+
+/*
+ * This is the stack-layout seen by the user space program when we have
+ * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
+ * is 'kernel_vm86_regs' (see below).
+ */
+
+struct target_vm86_regs {
+/*
+ * normal regs, with special meaning for the segment descriptors..
+ */
+	abi_long ebx;
+	abi_long ecx;
+	abi_long edx;
+	abi_long esi;
+	abi_long edi;
+	abi_long ebp;
+	abi_long eax;
+	abi_long __null_ds;
+	abi_long __null_es;
+	abi_long __null_fs;
+	abi_long __null_gs;
+	abi_long orig_eax;
+	abi_long eip;
+	unsigned short cs, __csh;
+	abi_long eflags;
+	abi_long esp;
+	unsigned short ss, __ssh;
+/*
+ * these are specific to v86 mode:
+ */
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned short fs, __fsh;
+	unsigned short gs, __gsh;
+};
+
+struct target_revectored_struct {
+	abi_ulong __map[8];			/* 256 bits */
+};
+
+struct target_vm86_struct {
+	struct target_vm86_regs regs;
+	abi_ulong flags;
+	abi_ulong screen_bitmap;
+	abi_ulong cpu_type;
+	struct target_revectored_struct int_revectored;
+	struct target_revectored_struct int21_revectored;
+};
+
+/*
+ * flags masks
+ */
+#define TARGET_VM86_SCREEN_BITMAP	0x0001
+
+struct target_vm86plus_info_struct {
+        abi_ulong flags;
+#define TARGET_force_return_for_pic (1 << 0)
+#define TARGET_vm86dbg_active       (1 << 1)  /* for debugger */
+#define TARGET_vm86dbg_TFpendig     (1 << 2)  /* for debugger */
+#define TARGET_is_vm86pus           (1 << 31) /* for vm86 internal use */
+	unsigned char vm86dbg_intxxtab[32];   /* for debugger */
+};
+
+struct target_vm86plus_struct {
+	struct target_vm86_regs regs;
+	abi_ulong flags;
+	abi_ulong screen_bitmap;
+	abi_ulong cpu_type;
+	struct target_revectored_struct int_revectored;
+	struct target_revectored_struct int21_revectored;
+	struct target_vm86plus_info_struct vm86plus;
+};
+
+#define UNAME_MACHINE "i686"
diff --git a/qemu-0.15.x/linux-user/i386/syscall_nr.h b/qemu-0.15.x/linux-user/i386/syscall_nr.h
new file mode 100644
index 0000000..74abfca
--- /dev/null
+++ b/qemu-0.15.x/linux-user/i386/syscall_nr.h
@@ -0,0 +1,349 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_restart_syscall      0
+#define TARGET_NR_exit		  1
+#define TARGET_NR_fork		  2
+#define TARGET_NR_read		  3
+#define TARGET_NR_write		  4
+#define TARGET_NR_open		  5
+#define TARGET_NR_close		  6
+#define TARGET_NR_waitpid		  7
+#define TARGET_NR_creat		  8
+#define TARGET_NR_link		  9
+#define TARGET_NR_unlink		 10
+#define TARGET_NR_execve		 11
+#define TARGET_NR_chdir		 12
+#define TARGET_NR_time		 13
+#define TARGET_NR_mknod		 14
+#define TARGET_NR_chmod		 15
+#define TARGET_NR_lchown		 16
+#define TARGET_NR_break		 17
+#define TARGET_NR_oldstat		 18
+#define TARGET_NR_lseek		 19
+#define TARGET_NR_getpid		 20
+#define TARGET_NR_mount		 21
+#define TARGET_NR_umount		 22
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getuid		 24
+#define TARGET_NR_stime		 25
+#define TARGET_NR_ptrace		 26
+#define TARGET_NR_alarm		 27
+#define TARGET_NR_oldfstat		 28
+#define TARGET_NR_pause		 29
+#define TARGET_NR_utime		 30
+#define TARGET_NR_stty		 31
+#define TARGET_NR_gtty		 32
+#define TARGET_NR_access		 33
+#define TARGET_NR_nice		 34
+#define TARGET_NR_ftime		 35
+#define TARGET_NR_sync		 36
+#define TARGET_NR_kill		 37
+#define TARGET_NR_rename		 38
+#define TARGET_NR_mkdir		 39
+#define TARGET_NR_rmdir		 40
+#define TARGET_NR_dup		 41
+#define TARGET_NR_pipe		 42
+#define TARGET_NR_times		 43
+#define TARGET_NR_prof		 44
+#define TARGET_NR_brk		 45
+#define TARGET_NR_setgid		 46
+#define TARGET_NR_getgid		 47
+#define TARGET_NR_signal		 48
+#define TARGET_NR_geteuid		 49
+#define TARGET_NR_getegid		 50
+#define TARGET_NR_acct		 51
+#define TARGET_NR_umount2		 52
+#define TARGET_NR_lock		 53
+#define TARGET_NR_ioctl		 54
+#define TARGET_NR_fcntl		 55
+#define TARGET_NR_mpx		 56
+#define TARGET_NR_setpgid		 57
+#define TARGET_NR_ulimit		 58
+#define TARGET_NR_oldolduname	 59
+#define TARGET_NR_umask		 60
+#define TARGET_NR_chroot		 61
+#define TARGET_NR_ustat		 62
+#define TARGET_NR_dup2		 63
+#define TARGET_NR_getppid		 64
+#define TARGET_NR_getpgrp		 65
+#define TARGET_NR_setsid		 66
+#define TARGET_NR_sigaction		 67
+#define TARGET_NR_sgetmask		 68
+#define TARGET_NR_ssetmask		 69
+#define TARGET_NR_setreuid		 70
+#define TARGET_NR_setregid		 71
+#define TARGET_NR_sigsuspend		 72
+#define TARGET_NR_sigpending		 73
+#define TARGET_NR_sethostname	 74
+#define TARGET_NR_setrlimit		 75
+#define TARGET_NR_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
+#define TARGET_NR_getrusage		 77
+#define TARGET_NR_gettimeofday	 78
+#define TARGET_NR_settimeofday	 79
+#define TARGET_NR_getgroups		 80
+#define TARGET_NR_setgroups		 81
+#define TARGET_NR_select		 82
+#define TARGET_NR_symlink		 83
+#define TARGET_NR_oldlstat		 84
+#define TARGET_NR_readlink		 85
+#define TARGET_NR_uselib		 86
+#define TARGET_NR_swapon		 87
+#define TARGET_NR_reboot		 88
+#define TARGET_NR_readdir		 89
+#define TARGET_NR_mmap		 90
+#define TARGET_NR_munmap		 91
+#define TARGET_NR_truncate		 92
+#define TARGET_NR_ftruncate		 93
+#define TARGET_NR_fchmod		 94
+#define TARGET_NR_fchown		 95
+#define TARGET_NR_getpriority	 96
+#define TARGET_NR_setpriority	 97
+#define TARGET_NR_profil		 98
+#define TARGET_NR_statfs		 99
+#define TARGET_NR_fstatfs		100
+#define TARGET_NR_ioperm		101
+#define TARGET_NR_socketcall		102
+#define TARGET_NR_syslog		103
+#define TARGET_NR_setitimer		104
+#define TARGET_NR_getitimer		105
+#define TARGET_NR_stat		106
+#define TARGET_NR_lstat		107
+#define TARGET_NR_fstat		108
+#define TARGET_NR_olduname		109
+#define TARGET_NR_iopl		110
+#define TARGET_NR_vhangup		111
+#define TARGET_NR_idle		112
+#define TARGET_NR_vm86old		113
+#define TARGET_NR_wait4		114
+#define TARGET_NR_swapoff		115
+#define TARGET_NR_sysinfo		116
+#define TARGET_NR_ipc		117
+#define TARGET_NR_fsync		118
+#define TARGET_NR_sigreturn		119
+#define TARGET_NR_clone		120
+#define TARGET_NR_setdomainname	121
+#define TARGET_NR_uname		122
+#define TARGET_NR_modify_ldt		123
+#define TARGET_NR_adjtimex		124
+#define TARGET_NR_mprotect		125
+#define TARGET_NR_sigprocmask	126
+#define TARGET_NR_create_module	127
+#define TARGET_NR_init_module	128
+#define TARGET_NR_delete_module	129
+#define TARGET_NR_get_kernel_syms	130
+#define TARGET_NR_quotactl		131
+#define TARGET_NR_getpgid		132
+#define TARGET_NR_fchdir		133
+#define TARGET_NR_bdflush		134
+#define TARGET_NR_sysfs		135
+#define TARGET_NR_personality	136
+#define TARGET_NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid		138
+#define TARGET_NR_setfsgid		139
+#define TARGET_NR__llseek		140
+#define TARGET_NR_getdents		141
+#define TARGET_NR__newselect		142
+#define TARGET_NR_flock		143
+#define TARGET_NR_msync		144
+#define TARGET_NR_readv		145
+#define TARGET_NR_writev		146
+#define TARGET_NR_getsid		147
+#define TARGET_NR_fdatasync		148
+#define TARGET_NR__sysctl		149
+#define TARGET_NR_mlock		150
+#define TARGET_NR_munlock		151
+#define TARGET_NR_mlockall		152
+#define TARGET_NR_munlockall		153
+#define TARGET_NR_sched_setparam		154
+#define TARGET_NR_sched_getparam		155
+#define TARGET_NR_sched_setscheduler		156
+#define TARGET_NR_sched_getscheduler		157
+#define TARGET_NR_sched_yield		158
+#define TARGET_NR_sched_get_priority_max	159
+#define TARGET_NR_sched_get_priority_min	160
+#define TARGET_NR_sched_rr_get_interval	161
+#define TARGET_NR_nanosleep		162
+#define TARGET_NR_mremap		163
+#define TARGET_NR_setresuid		164
+#define TARGET_NR_getresuid		165
+#define TARGET_NR_vm86		166
+#define TARGET_NR_query_module	167
+#define TARGET_NR_poll		168
+#define TARGET_NR_nfsservctl		169
+#define TARGET_NR_setresgid		170
+#define TARGET_NR_getresgid		171
+#define TARGET_NR_prctl              172
+#define TARGET_NR_rt_sigreturn	173
+#define TARGET_NR_rt_sigaction	174
+#define TARGET_NR_rt_sigprocmask	175
+#define TARGET_NR_rt_sigpending	176
+#define TARGET_NR_rt_sigtimedwait	177
+#define TARGET_NR_rt_sigqueueinfo	178
+#define TARGET_NR_rt_sigsuspend	179
+#define TARGET_NR_pread		180
+#define TARGET_NR_pwrite		181
+#define TARGET_NR_chown		182
+#define TARGET_NR_getcwd		183
+#define TARGET_NR_capget		184
+#define TARGET_NR_capset		185
+#define TARGET_NR_sigaltstack	186
+#define TARGET_NR_sendfile		187
+#define TARGET_NR_getpmsg		188	/* some people actually want streams */
+#define TARGET_NR_putpmsg		189	/* some people actually want streams */
+#define TARGET_NR_vfork		190
+#define TARGET_NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define TARGET_NR_mmap2		192
+#define TARGET_NR_truncate64		193
+#define TARGET_NR_ftruncate64	194
+#define TARGET_NR_stat64		195
+#define TARGET_NR_lstat64		196
+#define TARGET_NR_fstat64		197
+#define TARGET_NR_lchown32		198
+#define TARGET_NR_getuid32		199
+#define TARGET_NR_getgid32		200
+#define TARGET_NR_geteuid32		201
+#define TARGET_NR_getegid32		202
+#define TARGET_NR_setreuid32		203
+#define TARGET_NR_setregid32		204
+#define TARGET_NR_getgroups32	205
+#define TARGET_NR_setgroups32	206
+#define TARGET_NR_fchown32		207
+#define TARGET_NR_setresuid32	208
+#define TARGET_NR_getresuid32	209
+#define TARGET_NR_setresgid32	210
+#define TARGET_NR_getresgid32	211
+#define TARGET_NR_chown32		212
+#define TARGET_NR_setuid32		213
+#define TARGET_NR_setgid32		214
+#define TARGET_NR_setfsuid32		215
+#define TARGET_NR_setfsgid32		216
+#define TARGET_NR_pivot_root		217
+#define TARGET_NR_mincore		218
+#define TARGET_NR_madvise		219
+#define TARGET_NR_madvise1		219	/* delete when C lib stub is removed */
+#define TARGET_NR_getdents64		220
+#define TARGET_NR_fcntl64		221
+/* 223 is unused */
+#define TARGET_NR_gettid		224
+#define TARGET_NR_readahead		225
+#define TARGET_NR_setxattr		226
+#define TARGET_NR_lsetxattr		227
+#define TARGET_NR_fsetxattr		228
+#define TARGET_NR_getxattr		229
+#define TARGET_NR_lgetxattr		230
+#define TARGET_NR_fgetxattr		231
+#define TARGET_NR_listxattr		232
+#define TARGET_NR_llistxattr		233
+#define TARGET_NR_flistxattr		234
+#define TARGET_NR_removexattr	235
+#define TARGET_NR_lremovexattr	236
+#define TARGET_NR_fremovexattr	237
+#define TARGET_NR_tkill		238
+#define TARGET_NR_sendfile64		239
+#define TARGET_NR_futex		240
+#define TARGET_NR_sched_setaffinity	241
+#define TARGET_NR_sched_getaffinity	242
+#define TARGET_NR_set_thread_area	243
+#define TARGET_NR_get_thread_area	244
+#define TARGET_NR_io_setup		245
+#define TARGET_NR_io_destroy		246
+#define TARGET_NR_io_getevents	247
+#define TARGET_NR_io_submit		248
+#define TARGET_NR_io_cancel		249
+#define TARGET_NR_fadvise64		250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define TARGET_NR_exit_group		252
+#define TARGET_NR_lookup_dcookie	253
+#define TARGET_NR_epoll_create	254
+#define TARGET_NR_epoll_ctl		255
+#define TARGET_NR_epoll_wait		256
+#define TARGET_NR_remap_file_pages	257
+#define TARGET_NR_set_tid_address	258
+#define TARGET_NR_timer_create	259
+#define TARGET_NR_timer_settime	(TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime	(TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete	(TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime	(TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
+#define TARGET_NR_statfs64		268
+#define TARGET_NR_fstatfs64		269
+#define TARGET_NR_tgkill		270
+#define TARGET_NR_utimes		271
+#define TARGET_NR_fadvise64_64	272
+#define TARGET_NR_vserver		273
+#define TARGET_NR_mbind		274
+#define TARGET_NR_get_mempolicy	275
+#define TARGET_NR_set_mempolicy	276
+#define TARGET_NR_mq_open 		277
+#define TARGET_NR_mq_unlink		(TARGET_NR_mq_open+1)
+#define TARGET_NR_mq_timedsend	(TARGET_NR_mq_open+2)
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_mq_open+3)
+#define TARGET_NR_mq_notify		(TARGET_NR_mq_open+4)
+#define TARGET_NR_mq_getsetattr	(TARGET_NR_mq_open+5)
+#define TARGET_NR_kexec_load		283
+#define TARGET_NR_waitid		284
+/* #define TARGET_NR_sys_setaltroot	285 */
+#define TARGET_NR_add_key		286
+#define TARGET_NR_request_key	287
+#define TARGET_NR_keyctl		288
+#define TARGET_NR_ioprio_set		289
+#define TARGET_NR_ioprio_get		290
+#define TARGET_NR_inotify_init	291
+#define TARGET_NR_inotify_add_watch	292
+#define TARGET_NR_inotify_rm_watch	293
+#define TARGET_NR_migrate_pages	294
+#define TARGET_NR_openat		295
+#define TARGET_NR_mkdirat		296
+#define TARGET_NR_mknodat		297
+#define TARGET_NR_fchownat		298
+#define TARGET_NR_futimesat		299
+#define TARGET_NR_fstatat64		300
+#define TARGET_NR_unlinkat		301
+#define TARGET_NR_renameat		302
+#define TARGET_NR_linkat		303
+#define TARGET_NR_symlinkat		304
+#define TARGET_NR_readlinkat		305
+#define TARGET_NR_fchmodat		306
+#define TARGET_NR_faccessat		307
+#define TARGET_NR_pselect6		308
+#define TARGET_NR_ppoll		309
+#define TARGET_NR_unshare		310
+#define TARGET_NR_set_robust_list	311
+#define TARGET_NR_get_robust_list	312
+#define TARGET_NR_splice		313
+#define TARGET_NR_sync_file_range	314
+#define TARGET_NR_tee		315
+#define TARGET_NR_vmsplice		316
+#define TARGET_NR_move_pages		317
+#define TARGET_NR_getcpu		318
+#define TARGET_NR_epoll_pwait	319
+#define TARGET_NR_utimensat		320
+#define TARGET_NR_signalfd		321
+#define TARGET_NR_timerfd		322
+#define TARGET_NR_eventfd		323
+#define TARGET_NR_fallocate		324
+#define TARGET_NR_timerfd_settime	325
+#define TARGET_NR_timerfd_gettime	326
+#define TARGET_NR_signalfd4		327
+#define TARGET_NR_eventfd2		328
+#define TARGET_NR_epoll_create1	329
+#define TARGET_NR_dup3			330
+#define TARGET_NR_pipe2		331
+#define TARGET_NR_inotify_init1	332
+#define TARGET_NR_preadv                333
+#define TARGET_NR_pwritev               334
+#define TARGET_NR_rt_tgsigqueueinfo     335
+#define TARGET_NR_perf_event_open       336
+#define TARGET_NR_recvmmsg              337
+#define TARGET_NR_fanotify_init         338
+#define TARGET_NR_fanotify_mark         339
+#define TARGET_NR_prlimit64             340
+#define TARGET_NR_name_to_handle_at     341
+#define TARGET_NR_open_by_handle_at     342
+#define TARGET_NR_clock_adjtime         343
+#define TARGET_NR_syncfs                344
diff --git a/qemu-0.15.x/linux-user/i386/target_signal.h b/qemu-0.15.x/linux-user/i386/target_signal.h
new file mode 100644
index 0000000..9baf7fb
--- /dev/null
+++ b/qemu-0.15.x/linux-user/i386/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/i386/termbits.h b/qemu-0.15.x/linux-user/i386/termbits.h
new file mode 100644
index 0000000..e051a3a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/i386/termbits.h
@@ -0,0 +1,226 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define  TARGET_B500000 0010005
+#define  TARGET_B576000 0010006
+#define  TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VTIME	5
+#define TARGET_VMIN	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+#define TARGET_VEOL	11
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOL2	16
+
+/* ioctls */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/linux-user/ioctls.h b/qemu-0.15.x/linux-user/ioctls.h
new file mode 100644
index 0000000..6514502
--- /dev/null
+++ b/qemu-0.15.x/linux-user/ioctls.h
@@ -0,0 +1,347 @@
+     /* emulated ioctl list */
+
+     IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+     IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
+     IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TCGETA, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TCSETA, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TCSETAW, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TCSETAF, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TCSBRK, 0, TYPE_INT)
+     IOCTL(TCSBRKP, 0, TYPE_INT)
+     IOCTL(TCXONC, 0, TYPE_INT)
+     IOCTL(TCFLSH, 0, TYPE_INT)
+     IOCTL(TIOCEXCL, 0, TYPE_NULL)
+     IOCTL(TIOCNXCL, 0, TYPE_NULL)
+     IOCTL(TIOCSCTTY, 0, TYPE_INT)
+     IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCGSOFTCAR, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSSOFTCAR, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCLINUX, IOC_R | IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCCONS, 0, TYPE_NULL)
+     IOCTL(TIOCGSERIAL, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSSERIAL, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCPKT, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCNOTTY, 0, TYPE_NULL)
+     IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(FIOCLEX, 0, TYPE_NULL)
+     IOCTL(FIONCLEX, 0, TYPE_NULL)
+     IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(TIOCGLCKTRMIOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TIOCSLCKTRMIOS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
+     IOCTL(TIOCSERCONFIG, 0, TYPE_NULL)
+     IOCTL(TIOCSERGETLSR, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(TIOCSERGETMULTI, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct)))
+     IOCTL(TIOCSERSETMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct)))
+     IOCTL(TIOCMIWAIT, 0, TYPE_INT)
+     IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct)))
+
+     IOCTL(KIOCSOUND, 0, TYPE_INT)
+     IOCTL(KDMKTONE, 0, TYPE_INT)
+     IOCTL(KDSETMODE, 0, TYPE_INT)
+     IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR))
+     IOCTL(KDGKBMODE, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(KDSKBMODE, 0, TYPE_INT)
+     IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
+     IOCTL(KDGKBSENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbsentry)))
+     IOCTL(KDGKBLED, 0, TYPE_INT)
+     IOCTL(KDSKBLED, 0, TYPE_INT)
+     IOCTL(KDGETLED, 0, TYPE_INT)
+     IOCTL(KDSETLED, 0, TYPE_INT)
+
+     IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
+     IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
+     IOCTL(BLKRRPART, 0, TYPE_NULL)
+     IOCTL(BLKGETSIZE, IOC_R, MK_PTR(TYPE_ULONG))
+#ifdef BLKGETSIZE64
+     IOCTL(BLKGETSIZE64, IOC_R, MK_PTR(TYPE_ULONGLONG))
+#endif
+     IOCTL(BLKFLSBUF, 0, TYPE_NULL)
+     IOCTL(BLKRASET, 0, TYPE_INT)
+     IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG))
+#ifdef FIBMAP
+     IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
+#endif
+#ifdef FIGETBSZ
+     IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
+#endif
+#ifdef CONFIG_FIEMAP
+     IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap,
+                   MK_PTR(MK_STRUCT(STRUCT_fiemap)))
+#endif
+
+  IOCTL(SIOCATMARK, 0, TYPE_NULL)
+  IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
+  IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
+  IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
+  IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
+  IOCTL(SIOCGIFADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFBRDADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFBRDADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFDSTADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFDSTADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFNETMASK, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFNETMASK, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFHWADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFHWADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFTXQLEN, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFTXQLEN, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCGIFMETRIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
+  IOCTL(SIOCSIFMETRIC, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
+  IOCTL(SIOCGIFMTU, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
+  IOCTL(SIOCSIFMTU, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
+  IOCTL(SIOCGIFMAP, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq)))
+  IOCTL(SIOCSIFMAP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq)))
+  IOCTL(SIOCGIFSLAVE, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
+  IOCTL(SIOCSIFSLAVE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
+  IOCTL(SIOCGIFMEM, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
+  IOCTL(SIOCSIFMEM, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
+  IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
+  IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
+  IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
+                MK_PTR(MK_STRUCT(STRUCT_ifconf)))
+  IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCSARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCGARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCDRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
+
+  IOCTL(CDROMPAUSE, 0, TYPE_NULL)
+  IOCTL(CDROMSTART, 0, TYPE_NULL)
+  IOCTL(CDROMSTOP, 0, TYPE_NULL)
+  IOCTL(CDROMRESUME, 0, TYPE_NULL)
+  IOCTL(CDROMEJECT, 0, TYPE_NULL)
+  IOCTL(CDROMEJECT_SW, 0, TYPE_INT)
+  IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL)
+  IOCTL(CDROMRESET, 0, TYPE_NULL)
+  IOCTL(CDROMPLAYMSF, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(CDROMPLAYTRKIND, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADTOCHDR, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADTOCENTRY, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMVOLCTRL, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(CDROMSUBCHNL, IOC_RW, MK_PTR(TYPE_INT))
+  /* XXX: incorrect (need specific handling) */
+  IOCTL(CDROMREADAUDIO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_cdrom_read_audio)))
+  IOCTL(CDROMREADCOOKED, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADRAW, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADMODE1, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADMODE2, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMREADALL, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROMMULTISESSION, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(CDROM_GET_UPC, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(CDROMVOLREAD, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(CDROMSEEK, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(CDROMPLAYBLK, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(CDROM_MEDIA_CHANGED, 0, TYPE_NULL)
+  IOCTL(CDROM_SET_OPTIONS, 0, TYPE_INT)
+  IOCTL(CDROM_CLEAR_OPTIONS, 0, TYPE_INT)
+  IOCTL(CDROM_SELECT_SPEED, 0, TYPE_INT)
+  IOCTL(CDROM_SELECT_DISC, 0, TYPE_INT)
+  IOCTL(CDROM_DRIVE_STATUS, 0, TYPE_NULL)
+  IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
+  IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
+
+#if 0
+  IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_RCVMSG, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_RDATA, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_RESET, 0, TYPE_NULL)
+  IOCTL(SNDCTL_COPR_RUN, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
+#endif
+  IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
+  IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
+  IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
+  IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
+  IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_NONBLOCK, 0, TYPE_NULL)
+  IOCTL(SNDCTL_DSP_POST, 0, TYPE_NULL)
+  IOCTL(SNDCTL_DSP_RESET, 0, TYPE_NULL)
+  IOCTL(SNDCTL_DSP_SETDUPLEX, 0, TYPE_NULL)
+  IOCTL(SNDCTL_DSP_SETFMT, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_SETFRAGMENT, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_SETSYNCRO, 0, TYPE_NULL)
+  IOCTL(SNDCTL_DSP_SETTRIGGER, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_SPEED, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
+#if 0
+  IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_MIDI_MPUCMD, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_MIDI_MPUMODE, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_MIDI_PRETIME, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_CTRLRATE, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_GETINCOUNT, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_GETOUTCOUNT, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_NRMIDIS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_NRSYNTHS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_OUTOFBAND, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_PANIC, 0, TYPE_NULL)
+  IOCTL(SNDCTL_SEQ_PERCMODE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_RESET, 0, TYPE_NULL)
+  IOCTL(SNDCTL_SEQ_RESETSAMPLES, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_SYNC, 0, TYPE_NULL)
+  IOCTL(SNDCTL_SEQ_TESTMIDI, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SEQ_THRESHOLD, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SYNTH_INFO, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_SYNTH_MEMAVL, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_TMR_CONTINUE, 0, TYPE_NULL)
+  IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
+#if 0
+     /* we invalidate these defines because they have a same number as
+        termios ioctls */
+  IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
+  IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
+#endif
+  IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
+
+  IOCTL(SOUND_PCM_WRITE_FILTER, IOC_W | IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_PCM_READ_RATE, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
+#endif
+  IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
+  IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_PRIVATE2, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_PRIVATE3, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_PRIVATE4, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_PRIVATE5, IOC_RW, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_VOLUME, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_BASS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_TREBLE, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_SYNTH, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_PCM, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_SPEAKER, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_LINE, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_MIC, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_CD, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_IMIX, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_ALTPCM, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_RECLEV, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_IGAIN, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_OGAIN, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_LINE1, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_LINE2, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_LINE3, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_MUTE, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_ENHANCE, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_LOUD, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_RECSRC, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_DEVMASK, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_RECMASK, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_STEREODEVS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_READ_CAPS, IOC_R, MK_PTR(TYPE_INT))
+
+  IOCTL(SOUND_MIXER_WRITE_VOLUME, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_BASS, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_TREBLE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_SYNTH, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_PCM, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_SPEAKER, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_LINE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_MIC, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_CD, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_IMIX, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_ALTPCM, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_RECLEV, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_IGAIN, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_OGAIN, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_LINE1, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_LINE2, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_LINE3, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_MUTE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_ENHANCE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_LOUD, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(SOUND_MIXER_WRITE_RECSRC, IOC_W, MK_PTR(TYPE_INT))
+
+  IOCTL(HDIO_GETGEO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_hd_geometry)))
+  IOCTL(HDIO_GET_UNMASKINTR, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_MULTCOUNT, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_IDENTITY, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_KEEPSETTINGS, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_NOWERR, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_DMA, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_GET_32BIT, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_DRIVE_CMD, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(HDIO_SET_UNMASKINTR, 0, TYPE_INT)
+  IOCTL(HDIO_SET_MULTCOUNT, 0, TYPE_INT)
+  IOCTL(HDIO_SET_KEEPSETTINGS, 0, TYPE_INT)
+  IOCTL(HDIO_SET_NOWERR, 0, TYPE_INT)
+  IOCTL(HDIO_SET_DMA, 0, TYPE_INT)
+  IOCTL(HDIO_SET_32BIT, 0, TYPE_INT)
+  IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT)
+
+  IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
+  IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
+
+  IOCTL(LOOP_SET_FD, 0, TYPE_INT)
+  IOCTL(LOOP_CLR_FD, 0, TYPE_INT)
+  IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
+  IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
+  IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
+  IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
+  IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT)
+
+  IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop)))
+  IOCTL(MTIOCGET, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtget)))
+  IOCTL(MTIOCPOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_mtpos)))
+
+  IOCTL(FBIOGET_FSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_fix_screeninfo)))
+  IOCTL(FBIOGET_VSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
+  IOCTL(FBIOPUT_VSCREENINFO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
+  IOCTL(FBIOGETCMAP,        IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap)))
+  IOCTL(FBIOPUTCMAP,        IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap)))
+  IOCTL(FBIOPAN_DISPLAY,    IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo)))
+  IOCTL(FBIOGET_CON2FBMAP,  IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap)))
+  IOCTL(FBIOPUT_CON2FBMAP,  IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap)))
+
+  IOCTL(VT_OPENQRY, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(VT_GETSTATE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_vt_stat)))
+  IOCTL(VT_ACTIVATE, 0, TYPE_INT)
+  IOCTL(VT_WAITACTIVE, 0, TYPE_INT)
+  IOCTL(VT_LOCKSWITCH, 0, TYPE_INT)
+  IOCTL(VT_UNLOCKSWITCH, 0, TYPE_INT)
+  IOCTL(VT_GETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode)))
+  IOCTL(VT_SETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode)))
+  IOCTL(VT_RELDISP, 0, TYPE_INT)
+  IOCTL(VT_DISALLOCATE, 0, TYPE_INT)
diff --git a/qemu-0.15.x/linux-user/linux_loop.h b/qemu-0.15.x/linux-user/linux_loop.h
new file mode 100644
index 0000000..8974caa
--- /dev/null
+++ b/qemu-0.15.x/linux-user/linux_loop.h
@@ -0,0 +1,95 @@
+/* Copied from 2.6.25 kernel headers to avoid problems on older hosts.  */
+#ifndef _LINUX_LOOP_H
+#define _LINUX_LOOP_H
+
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
+ * permitted under the GNU General Public License.
+ */
+
+#define LO_NAME_SIZE	64
+#define LO_KEY_SIZE	32
+
+
+/*
+ * Loop flags
+ */
+enum {
+	LO_FLAGS_READ_ONLY	= 1,
+	LO_FLAGS_USE_AOPS	= 2,
+	LO_FLAGS_AUTOCLEAR	= 4,
+};
+
+#include <linux/version.h>
+#include <asm/posix_types.h>	/* for __kernel_old_dev_t */
+#include <asm/types.h>		/* for __u64 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* This is a guess.  */
+#define __kernel_old_dev_t __kernel_dev_t
+#endif
+
+/* Backwards compatibility version */
+struct loop_info {
+	int		   lo_number;		/* ioctl r/o */
+	__kernel_old_dev_t lo_device; 		/* ioctl r/o */
+	unsigned long	   lo_inode; 		/* ioctl r/o */
+	__kernel_old_dev_t lo_rdevice; 		/* ioctl r/o */
+	int		   lo_offset;
+	int		   lo_encrypt_type;
+	int		   lo_encrypt_key_size; 	/* ioctl w/o */
+	int		   lo_flags;			/* ioctl r/o */
+	char		   lo_name[LO_NAME_SIZE];
+	unsigned char	   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned long	   lo_init[2];
+	char		   reserved[4];
+};
+
+struct loop_info64 {
+	__u64		   lo_device;			/* ioctl r/o */
+	__u64		   lo_inode;			/* ioctl r/o */
+	__u64		   lo_rdevice;			/* ioctl r/o */
+	__u64		   lo_offset;
+	__u64		   lo_sizelimit;/* bytes, 0 == max available */
+	__u32		   lo_number;			/* ioctl r/o */
+	__u32		   lo_encrypt_type;
+	__u32		   lo_encrypt_key_size;		/* ioctl w/o */
+	__u32		   lo_flags;			/* ioctl r/o */
+	__u8		   lo_file_name[LO_NAME_SIZE];
+	__u8		   lo_crypt_name[LO_NAME_SIZE];
+	__u8		   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	__u64		   lo_init[2];
+};
+
+/*
+ * Loop filter types
+ */
+
+#define LO_CRYPT_NONE		0
+#define LO_CRYPT_XOR		1
+#define LO_CRYPT_DES		2
+#define LO_CRYPT_FISH2		3    /* Twofish encryption */
+#define LO_CRYPT_BLOW		4
+#define LO_CRYPT_CAST128	5
+#define LO_CRYPT_IDEA		6
+#define LO_CRYPT_DUMMY		9
+#define LO_CRYPT_SKIPJACK	10
+#define LO_CRYPT_CRYPTOAPI	18
+#define MAX_LO_CRYPT		20
+
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+
+#define LOOP_SET_FD		0x4C00
+#define LOOP_CLR_FD		0x4C01
+#define LOOP_SET_STATUS		0x4C02
+#define LOOP_GET_STATUS		0x4C03
+#define LOOP_SET_STATUS64	0x4C04
+#define LOOP_GET_STATUS64	0x4C05
+#define LOOP_CHANGE_FD		0x4C06
+
+#endif
diff --git a/qemu-0.15.x/linux-user/linuxload.c b/qemu-0.15.x/linux-user/linuxload.c
new file mode 100644
index 0000000..62ebc7e
--- /dev/null
+++ b/qemu-0.15.x/linux-user/linuxload.c
@@ -0,0 +1,184 @@
+/* Code for loading Linux executables.  Mostly linux kernel code.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "qemu.h"
+
+#define NGROUPS 32
+
+/* ??? This should really be somewhere else.  */
+abi_long memcpy_to_target(abi_ulong dest, const void *src,
+                          unsigned long len)
+{
+    void *host_ptr;
+
+    host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
+    if (!host_ptr)
+        return -TARGET_EFAULT;
+    memcpy(host_ptr, src, len);
+    unlock_user(host_ptr, dest, 1);
+    return 0;
+}
+
+static int count(char ** vec)
+{
+    int		i;
+
+    for(i = 0; *vec; i++) {
+        vec++;
+    }
+
+    return(i);
+}
+
+static int prepare_binprm(struct linux_binprm *bprm)
+{
+    struct stat		st;
+    int mode;
+    int retval;
+
+    if(fstat(bprm->fd, &st) < 0) {
+	return(-errno);
+    }
+
+    mode = st.st_mode;
+    if(!S_ISREG(mode)) {	/* Must be regular file */
+	return(-EACCES);
+    }
+    if(!(mode & 0111)) {	/* Must have at least one execute bit set */
+	return(-EACCES);
+    }
+
+    bprm->e_uid = geteuid();
+    bprm->e_gid = getegid();
+
+    /* Set-uid? */
+    if(mode & S_ISUID) {
+    	bprm->e_uid = st.st_uid;
+    }
+
+    /* Set-gid? */
+    /*
+     * If setgid is set but no group execute bit then this
+     * is a candidate for mandatory locking, not a setgid
+     * executable.
+     */
+    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+	bprm->e_gid = st.st_gid;
+    }
+
+    retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
+    if (retval < 0) {
+	perror("prepare_binprm");
+	exit(-1);
+    }
+    if (retval < BPRM_BUF_SIZE) {
+        /* Make sure the rest of the loader won't read garbage.  */
+        memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
+    }
+    return retval;
+}
+
+/* Construct the envp and argv tables on the target stack.  */
+abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
+                              abi_ulong stringp, int push_ptr)
+{
+    TaskState *ts = (TaskState *)thread_env->opaque;
+    int n = sizeof(abi_ulong);
+    abi_ulong envp;
+    abi_ulong argv;
+
+    sp -= (envc + 1) * n;
+    envp = sp;
+    sp -= (argc + 1) * n;
+    argv = sp;
+    if (push_ptr) {
+        /* FIXME - handle put_user() failures */
+        sp -= n;
+        put_user_ual(envp, sp);
+        sp -= n;
+        put_user_ual(argv, sp);
+    }
+    sp -= n;
+    /* FIXME - handle put_user() failures */
+    put_user_ual(argc, sp);
+    ts->info->arg_start = stringp;
+    while (argc-- > 0) {
+        /* FIXME - handle put_user() failures */
+        put_user_ual(stringp, argv);
+        argv += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    ts->info->arg_end = stringp;
+    /* FIXME - handle put_user() failures */
+    put_user_ual(0, argv);
+    while (envc-- > 0) {
+        /* FIXME - handle put_user() failures */
+        put_user_ual(stringp, envp);
+        envp += n;
+        stringp += target_strlen(stringp) + 1;
+    }
+    /* FIXME - handle put_user() failures */
+    put_user_ual(0, envp);
+
+    return sp;
+}
+
+int loader_exec(const char * filename, char ** argv, char ** envp,
+             struct target_pt_regs * regs, struct image_info *infop,
+             struct linux_binprm *bprm)
+{
+    int retval;
+    int i;
+
+    bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    memset(bprm->page, 0, sizeof(bprm->page));
+    retval = open(filename, O_RDONLY);
+    if (retval < 0)
+        return retval;
+    bprm->fd = retval;
+    bprm->filename = (char *)filename;
+    bprm->argc = count(argv);
+    bprm->argv = argv;
+    bprm->envc = count(envp);
+    bprm->envp = envp;
+
+    retval = prepare_binprm(bprm);
+
+    if(retval>=0) {
+        if (bprm->buf[0] == 0x7f
+                && bprm->buf[1] == 'E'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'F') {
+            retval = load_elf_binary(bprm, regs, infop);
+#if defined(TARGET_HAS_BFLT)
+        } else if (bprm->buf[0] == 'b'
+                && bprm->buf[1] == 'F'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'T') {
+            retval = load_flt_binary(bprm,regs,infop);
+#endif
+        } else {
+            fprintf(stderr, "Unknown binary format\n");
+            return -1;
+        }
+    }
+
+    if(retval>=0) {
+        /* success.  Initialize important registers */
+        do_init_thread(regs, infop);
+        return retval;
+    }
+
+    /* Something went wrong, return the inode and free the argument pages*/
+    for (i=0 ; i<MAX_ARG_PAGES ; i++) {
+        free(bprm->page[i]);
+    }
+    return(retval);
+}
diff --git a/qemu-0.15.x/linux-user/m68k-sim.c b/qemu-0.15.x/linux-user/m68k-sim.c
new file mode 100644
index 0000000..d5926ee
--- /dev/null
+++ b/qemu-0.15.x/linux-user/m68k-sim.c
@@ -0,0 +1,170 @@
+/*
+ *  m68k simulator syscall interface
+ *
+ *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "qemu.h"
+
+#define SYS_EXIT        1
+#define SYS_READ        3
+#define SYS_WRITE       4
+#define SYS_OPEN        5
+#define SYS_CLOSE       6
+#define SYS_BRK         17
+#define SYS_FSTAT       28
+#define SYS_ISATTY      29
+#define SYS_LSEEK       199
+
+struct m68k_sim_stat {
+    uint16_t sim_st_dev;
+    uint16_t sim_st_ino;
+    uint32_t sim_st_mode;
+    uint16_t sim_st_nlink;
+    uint16_t sim_st_uid;
+    uint16_t sim_st_gid;
+    uint16_t sim_st_rdev;
+    uint32_t sim_st_size;
+    uint32_t sim_st_atime;
+    uint32_t sim_st_mtime;
+    uint32_t sim_st_ctime;
+    uint32_t sim_st_blksize;
+    uint32_t sim_st_blocks;
+};
+
+static inline uint32_t check_err(CPUM68KState *env, uint32_t code)
+{
+  env->dregs[0] = code;
+  if (code == (uint32_t)-1) {
+      env->dregs[1] = errno;
+  } else {
+      env->dregs[1] = 0;
+  }
+  return code;
+}
+
+#define SIM_O_APPEND    0x0008
+#define SIM_O_CREAT     0x0200
+#define SIM_O_TRUNC     0x0400
+#define SIM_O_EXCL      0x0800
+#define SIM_O_NONBLOCK  0x4000
+#define SIM_O_NOCTTY    0x8000
+#define SIM_O_SYNC      0x2000
+
+static int translate_openflags(int flags)
+{
+    int hf;
+
+    switch (flags & 3) {
+    case 0: hf = O_RDONLY; break;
+    case 1: hf = O_WRONLY; break;
+    case 2: hf = O_RDWR; break;
+    default: hf = O_RDWR; break;
+    }
+
+    if (flags & SIM_O_APPEND) hf |= O_APPEND;
+    if (flags & SIM_O_CREAT) hf |= O_CREAT;
+    if (flags & SIM_O_TRUNC) hf |= O_TRUNC;
+    if (flags & SIM_O_EXCL) hf |= O_EXCL;
+    if (flags & SIM_O_NONBLOCK) hf |= O_NONBLOCK;
+    if (flags & SIM_O_NOCTTY) hf |= O_NOCTTY;
+    if (flags & SIM_O_SYNC) hf |= O_SYNC;
+
+    return hf;
+}
+
+#define ARG(x) tswap32(args[x])
+void do_m68k_simcall(CPUM68KState *env, int nr)
+{
+    uint32_t *args;
+
+    args = (uint32_t *)(unsigned long)(env->aregs[7] + 4);
+    switch (nr) {
+    case SYS_EXIT:
+        exit(ARG(0));
+    case SYS_READ:
+        check_err(env, read(ARG(0), (void *)(unsigned long)ARG(1), ARG(2)));
+        break;
+    case SYS_WRITE:
+        check_err(env, write(ARG(0), (void *)(unsigned long)ARG(1), ARG(2)));
+        break;
+    case SYS_OPEN:
+        check_err(env, open((char *)(unsigned long)ARG(0),
+                            translate_openflags(ARG(1)), ARG(2)));
+        break;
+    case SYS_CLOSE:
+        {
+            /* Ignore attempts to close stdin/out/err.  */
+            int fd = ARG(0);
+            if (fd > 2)
+              check_err(env, close(fd));
+            else
+              check_err(env, 0);
+            break;
+        }
+    case SYS_BRK:
+        {
+            int32_t ret;
+
+            ret = do_brk((abi_ulong)ARG(0));
+            if (ret == -ENOMEM)
+                ret = -1;
+            check_err(env, ret);
+        }
+        break;
+    case SYS_FSTAT:
+        {
+            struct stat s;
+            int rc;
+            struct m68k_sim_stat *p;
+            rc = check_err(env, fstat(ARG(0), &s));
+            if (rc == 0) {
+                p = (struct m68k_sim_stat *)(unsigned long)ARG(1);
+                p->sim_st_dev = tswap16(s.st_dev);
+                p->sim_st_ino = tswap16(s.st_ino);
+                p->sim_st_mode = tswap32(s.st_mode);
+                p->sim_st_nlink = tswap16(s.st_nlink);
+                p->sim_st_uid = tswap16(s.st_uid);
+                p->sim_st_gid = tswap16(s.st_gid);
+                p->sim_st_rdev = tswap16(s.st_rdev);
+                p->sim_st_size = tswap32(s.st_size);
+                p->sim_st_atime = tswap32(s.st_atime);
+                p->sim_st_mtime = tswap32(s.st_mtime);
+                p->sim_st_ctime = tswap32(s.st_ctime);
+                p->sim_st_blksize = tswap32(s.st_blksize);
+                p->sim_st_blocks = tswap32(s.st_blocks);
+            }
+        }
+        break;
+    case SYS_ISATTY:
+        check_err(env, isatty(ARG(0)));
+        break;
+    case SYS_LSEEK:
+        check_err(env, lseek(ARG(0), (int32_t)ARG(1), ARG(2)));
+        break;
+    default:
+        cpu_abort(env, "Unsupported m68k sim syscall %d\n", nr);
+    }
+}
diff --git a/qemu-0.15.x/linux-user/m68k/syscall.h b/qemu-0.15.x/linux-user/m68k/syscall.h
new file mode 100644
index 0000000..2fd85dd
--- /dev/null
+++ b/qemu-0.15.x/linux-user/m68k/syscall.h
@@ -0,0 +1,21 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+    abi_long d1, d2, d3, d4, d5, d6, d7;
+    abi_long a0, a1, a2, a3, a4, a5, a6;
+    abi_ulong d0;
+    abi_ulong usp;
+    abi_ulong orig_d0;
+    int16_t stkadj;
+    uint16_t sr;
+    abi_ulong pc;
+    uint16_t fntvex;
+    uint16_t __fill;
+};
+
+
+#define UNAME_MACHINE "m68k"
+
+void do_m68k_simcall(CPUState *, int);
diff --git a/qemu-0.15.x/linux-user/m68k/syscall_nr.h b/qemu-0.15.x/linux-user/m68k/syscall_nr.h
new file mode 100644
index 0000000..4d0937e
--- /dev/null
+++ b/qemu-0.15.x/linux-user/m68k/syscall_nr.h
@@ -0,0 +1,346 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_exit                 1
+#define TARGET_NR_fork                 2
+#define TARGET_NR_read                 3
+#define TARGET_NR_write                4
+#define TARGET_NR_open                 5
+#define TARGET_NR_close                6
+#define TARGET_NR_waitpid              7
+#define TARGET_NR_creat                8
+#define TARGET_NR_link                 9
+#define TARGET_NR_unlink              10
+#define TARGET_NR_execve              11
+#define TARGET_NR_chdir               12
+#define TARGET_NR_time                13
+#define TARGET_NR_mknod               14
+#define TARGET_NR_chmod               15
+#define TARGET_NR_chown               16
+#define TARGET_NR_break               17
+#define TARGET_NR_oldstat             18
+#define TARGET_NR_lseek               19
+#define TARGET_NR_getpid              20
+#define TARGET_NR_mount               21
+#define TARGET_NR_umount              22
+#define TARGET_NR_setuid              23
+#define TARGET_NR_getuid              24
+#define TARGET_NR_stime               25
+#define TARGET_NR_ptrace              26
+#define TARGET_NR_alarm               27
+#define TARGET_NR_oldfstat            28
+#define TARGET_NR_pause               29
+#define TARGET_NR_utime               30
+#define TARGET_NR_stty                31
+#define TARGET_NR_gtty                32
+#define TARGET_NR_access              33
+#define TARGET_NR_nice                34
+#define TARGET_NR_ftime               35
+#define TARGET_NR_sync                36
+#define TARGET_NR_kill                37
+#define TARGET_NR_rename              38
+#define TARGET_NR_mkdir               39
+#define TARGET_NR_rmdir               40
+#define TARGET_NR_dup                 41
+#define TARGET_NR_pipe                42
+#define TARGET_NR_times               43
+#define TARGET_NR_prof                44
+#define TARGET_NR_brk                 45
+#define TARGET_NR_setgid              46
+#define TARGET_NR_getgid              47
+#define TARGET_NR_signal              48
+#define TARGET_NR_geteuid             49
+#define TARGET_NR_getegid             50
+#define TARGET_NR_acct                51
+#define TARGET_NR_umount2             52
+#define TARGET_NR_lock                53
+#define TARGET_NR_ioctl               54
+#define TARGET_NR_fcntl               55
+#define TARGET_NR_mpx                 56
+#define TARGET_NR_setpgid             57
+#define TARGET_NR_ulimit              58
+#define TARGET_NR_oldolduname         59
+#define TARGET_NR_umask               60
+#define TARGET_NR_chroot              61
+#define TARGET_NR_ustat               62
+#define TARGET_NR_dup2                63
+#define TARGET_NR_getppid             64
+#define TARGET_NR_getpgrp             65
+#define TARGET_NR_setsid              66
+#define TARGET_NR_sigaction           67
+#define TARGET_NR_sgetmask            68
+#define TARGET_NR_ssetmask            69
+#define TARGET_NR_setreuid            70
+#define TARGET_NR_setregid            71
+#define TARGET_NR_sigsuspend          72
+#define TARGET_NR_sigpending          73
+#define TARGET_NR_sethostname         74
+#define TARGET_NR_setrlimit           75
+#define TARGET_NR_getrlimit           76
+#define TARGET_NR_getrusage           77
+#define TARGET_NR_gettimeofday        78
+#define TARGET_NR_settimeofday        79
+#define TARGET_NR_getgroups           80
+#define TARGET_NR_setgroups           81
+#define TARGET_NR_select              82
+#define TARGET_NR_symlink             83
+#define TARGET_NR_oldlstat            84
+#define TARGET_NR_readlink            85
+#define TARGET_NR_uselib              86
+#define TARGET_NR_swapon              87
+#define TARGET_NR_reboot              88
+#define TARGET_NR_readdir             89
+#define TARGET_NR_mmap                90
+#define TARGET_NR_munmap              91
+#define TARGET_NR_truncate            92
+#define TARGET_NR_ftruncate           93
+#define TARGET_NR_fchmod              94
+#define TARGET_NR_fchown              95
+#define TARGET_NR_getpriority         96
+#define TARGET_NR_setpriority         97
+#define TARGET_NR_profil              98
+#define TARGET_NR_statfs              99
+#define TARGET_NR_fstatfs            100
+#define TARGET_NR_ioperm             101
+#define TARGET_NR_socketcall         102
+#define TARGET_NR_syslog             103
+#define TARGET_NR_setitimer          104
+#define TARGET_NR_getitimer          105
+#define TARGET_NR_stat               106
+#define TARGET_NR_lstat              107
+#define TARGET_NR_fstat              108
+#define TARGET_NR_olduname           109
+//#define TARGET_NR_iopl               /* 110 */ not supported
+#define TARGET_NR_vhangup            111
+//#define TARGET_NR_idle               /* 112 */ Obsolete
+//#define TARGET_NR_vm86               /* 113 */ not supported
+#define TARGET_NR_wait4              114
+#define TARGET_NR_swapoff            115
+#define TARGET_NR_sysinfo            116
+#define TARGET_NR_ipc                117
+#define TARGET_NR_fsync              118
+#define TARGET_NR_sigreturn          119
+#define TARGET_NR_clone              120
+#define TARGET_NR_setdomainname      121
+#define TARGET_NR_uname              122
+#define TARGET_NR_cacheflush         123
+#define TARGET_NR_adjtimex           124
+#define TARGET_NR_mprotect           125
+#define TARGET_NR_sigprocmask        126
+#define TARGET_NR_create_module      127
+#define TARGET_NR_init_module        128
+#define TARGET_NR_delete_module      129
+#define TARGET_NR_get_kernel_syms    130
+#define TARGET_NR_quotactl           131
+#define TARGET_NR_getpgid            132
+#define TARGET_NR_fchdir             133
+#define TARGET_NR_bdflush            134
+#define TARGET_NR_sysfs              135
+#define TARGET_NR_personality        136
+#define TARGET_NR_afs_syscall        137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid           138
+#define TARGET_NR_setfsgid           139
+#define TARGET_NR__llseek            140
+#define TARGET_NR_getdents           141
+#define TARGET_NR__newselect         142
+#define TARGET_NR_flock              143
+#define TARGET_NR_msync              144
+#define TARGET_NR_readv              145
+#define TARGET_NR_writev             146
+#define TARGET_NR_getsid             147
+#define TARGET_NR_fdatasync          148
+#define TARGET_NR__sysctl            149
+#define TARGET_NR_mlock              150
+#define TARGET_NR_munlock            151
+#define TARGET_NR_mlockall           152
+#define TARGET_NR_munlockall         153
+#define TARGET_NR_sched_setparam             154
+#define TARGET_NR_sched_getparam             155
+#define TARGET_NR_sched_setscheduler         156
+#define TARGET_NR_sched_getscheduler         157
+#define TARGET_NR_sched_yield                158
+#define TARGET_NR_sched_get_priority_max     159
+#define TARGET_NR_sched_get_priority_min     160
+#define TARGET_NR_sched_rr_get_interval      161
+#define TARGET_NR_nanosleep          162
+#define TARGET_NR_mremap             163
+#define TARGET_NR_setresuid          164
+#define TARGET_NR_getresuid          165
+#define TARGET_NR_getpagesize        166
+#define TARGET_NR_query_module       167
+#define TARGET_NR_poll               168
+#define TARGET_NR_nfsservctl         169
+#define TARGET_NR_setresgid          170
+#define TARGET_NR_getresgid          171
+#define TARGET_NR_prctl              172
+#define TARGET_NR_rt_sigreturn       173
+#define TARGET_NR_rt_sigaction       174
+#define TARGET_NR_rt_sigprocmask     175
+#define TARGET_NR_rt_sigpending      176
+#define TARGET_NR_rt_sigtimedwait    177
+#define TARGET_NR_rt_sigqueueinfo    178
+#define TARGET_NR_rt_sigsuspend      179
+#define TARGET_NR_pread64            180
+#define TARGET_NR_pwrite64           181
+#define TARGET_NR_lchown             182
+#define TARGET_NR_getcwd             183
+#define TARGET_NR_capget             184
+#define TARGET_NR_capset             185
+#define TARGET_NR_sigaltstack        186
+#define TARGET_NR_sendfile           187
+#define TARGET_NR_getpmsg            188     /* some people actually want streams */
+#define TARGET_NR_putpmsg            189     /* some people actually want streams */
+#define TARGET_NR_vfork              190
+#define TARGET_NR_ugetrlimit         191
+#define TARGET_NR_mmap2              192
+#define TARGET_NR_truncate64         193
+#define TARGET_NR_ftruncate64        194
+#define TARGET_NR_stat64             195
+#define TARGET_NR_lstat64            196
+#define TARGET_NR_fstat64            197
+#define TARGET_NR_chown32            198
+#define TARGET_NR_getuid32           199
+#define TARGET_NR_getgid32           200
+#define TARGET_NR_geteuid32          201
+#define TARGET_NR_getegid32          202
+#define TARGET_NR_setreuid32         203
+#define TARGET_NR_setregid32         204
+#define TARGET_NR_getgroups32        205
+#define TARGET_NR_setgroups32        206
+#define TARGET_NR_fchown32           207
+#define TARGET_NR_setresuid32        208
+#define TARGET_NR_getresuid32        209
+#define TARGET_NR_setresgid32        210
+#define TARGET_NR_getresgid32        211
+#define TARGET_NR_lchown32           212
+#define TARGET_NR_setuid32           213
+#define TARGET_NR_setgid32           214
+#define TARGET_NR_setfsuid32         215
+#define TARGET_NR_setfsgid32         216
+#define TARGET_NR_pivot_root         217
+#define TARGET_NR_getdents64         220
+#define TARGET_NR_gettid             221
+#define TARGET_NR_tkill              222
+#define TARGET_NR_setxattr           223
+#define TARGET_NR_lsetxattr          224
+#define TARGET_NR_fsetxattr          225
+#define TARGET_NR_getxattr           226
+#define TARGET_NR_lgetxattr          227
+#define TARGET_NR_fgetxattr          228
+#define TARGET_NR_listxattr          229
+#define TARGET_NR_llistxattr         230
+#define TARGET_NR_flistxattr         231
+#define TARGET_NR_removexattr        232
+#define TARGET_NR_lremovexattr       233
+#define TARGET_NR_fremovexattr       234
+#define TARGET_NR_futex              235
+#define TARGET_NR_sendfile64         236
+#define TARGET_NR_mincore            237
+#define TARGET_NR_madvise            238
+#define TARGET_NR_fcntl64            239
+#define TARGET_NR_readahead          240
+#define TARGET_NR_io_setup           241
+#define TARGET_NR_io_destroy         242
+#define TARGET_NR_io_getevents       243
+#define TARGET_NR_io_submit          244
+#define TARGET_NR_io_cancel          245
+#define TARGET_NR_fadvise64          246
+#define TARGET_NR_exit_group         247
+#define TARGET_NR_lookup_dcookie     248
+#define TARGET_NR_epoll_create       249
+#define TARGET_NR_epoll_ctl          250
+#define TARGET_NR_epoll_wait         251
+#define TARGET_NR_remap_file_pages   252
+#define TARGET_NR_set_tid_address    253
+#define TARGET_NR_timer_create       254
+#define TARGET_NR_timer_settime      255
+#define TARGET_NR_timer_gettime      256
+#define TARGET_NR_timer_getoverrun   257
+#define TARGET_NR_timer_delete       258
+#define TARGET_NR_clock_settime      259
+#define TARGET_NR_clock_gettime      260
+#define TARGET_NR_clock_getres       261
+#define TARGET_NR_clock_nanosleep    262
+#define TARGET_NR_statfs64           263
+#define TARGET_NR_fstatfs64          264
+#define TARGET_NR_tgkill             265
+#define TARGET_NR_utimes             266
+#define TARGET_NR_fadvise64_64       267
+#define TARGET_NR_mbind              268
+#define TARGET_NR_get_mempolicy      269
+#define TARGET_NR_set_mempolicy      270
+#define TARGET_NR_mq_open            271
+#define TARGET_NR_mq_unlink          272
+#define TARGET_NR_mq_timedsend       273
+#define TARGET_NR_mq_timedreceive    274
+#define TARGET_NR_mq_notify          275
+#define TARGET_NR_mq_getsetattr      276
+#define TARGET_NR_waitid             277
+#define TARGET_NR_vserver            278
+#define TARGET_NR_add_key            279
+#define TARGET_NR_request_key        280
+#define TARGET_NR_keyctl             281
+#define TARGET_NR_ioprio_set		282
+#define TARGET_NR_ioprio_get		283
+#define TARGET_NR_inotify_init	284
+#define TARGET_NR_inotify_add_watch	285
+#define TARGET_NR_inotify_rm_watch	286
+#define TARGET_NR_migrate_pages	287
+#define TARGET_NR_openat		288
+#define TARGET_NR_mkdirat		289
+#define TARGET_NR_mknodat		290
+#define TARGET_NR_fchownat		291
+#define TARGET_NR_futimesat		292
+#define TARGET_NR_fstatat64		293
+#define TARGET_NR_unlinkat		294
+#define TARGET_NR_renameat		295
+#define TARGET_NR_linkat		296
+#define TARGET_NR_symlinkat		297
+#define TARGET_NR_readlinkat		298
+#define TARGET_NR_fchmodat		299
+#define TARGET_NR_faccessat		300
+#define TARGET_NR_pselect6		301
+#define TARGET_NR_ppoll		302
+#define TARGET_NR_unshare		303
+#define TARGET_NR_set_robust_list	304
+#define TARGET_NR_get_robust_list	305
+#define TARGET_NR_splice		306
+#define TARGET_NR_sync_file_range	307
+#define TARGET_NR_tee		308
+#define TARGET_NR_vmsplice		309
+#define TARGET_NR_move_pages		310
+#define TARGET_NR_sched_setaffinity	311
+#define TARGET_NR_sched_getaffinity	312
+#define TARGET_NR_kexec_load		313
+#define TARGET_NR_getcpu		314
+#define TARGET_NR_epoll_pwait	315
+#define TARGET_NR_utimensat		316
+#define TARGET_NR_signalfd		317
+#define TARGET_NR_timerfd		318
+#define TARGET_NR_eventfd		319
+#define TARGET_NR_fallocate		320
+#define TARGET_NR_timerfd_settime	321
+#define TARGET_NR_timerfd_gettime	322
+#define TARGET_NR_signalfd4		323
+#define TARGET_NR_eventfd2		324
+#define TARGET_NR_epoll_create1	325
+#define TARGET_NR_dup3			326
+#define TARGET_NR_pipe2		327
+#define TARGET_NR_inotify_init1	328
+#define TARGET_NR_inotify_init1         328
+#define TARGET_NR_preadv                329
+#define TARGET_NR_pwritev               330
+#define TARGET_NR_rt_tgsigqueueinfo     331
+#define TARGET_NR_perf_event_open       332
+#define TARGET_NR_get_thread_area       333
+#define TARGET_NR_set_thread_area       334
+#define TARGET_NR_atomic_cmpxchg_32     335
+#define TARGET_NR_atomic_barrier        336
+#define TARGET_NR_fanotify_init         337
+#define TARGET_NR_fanotify_mark         338
+#define TARGET_NR_prlimit64             339
+#define TARGET_NR_name_to_handle_at     340
+#define TARGET_NR_open_by_handle_at     341
+#define TARGET_NR_clock_adjtime         342
+#define TARGET_NR_syncfs                343
diff --git a/qemu-0.15.x/linux-user/m68k/target_signal.h b/qemu-0.15.x/linux-user/m68k/target_signal.h
new file mode 100644
index 0000000..479758a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/m68k/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ	8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUM68KState *state)
+{
+    return state->aregs[7];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/m68k/termbits.h b/qemu-0.15.x/linux-user/m68k/termbits.h
new file mode 100644
index 0000000..f7982fb
--- /dev/null
+++ b/qemu-0.15.x/linux-user/m68k/termbits.h
@@ -0,0 +1,227 @@
+/* from asm/termbits.h */
+/* NOTE: exactly the same as i386 */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define  TARGET_B500000 0010005
+#define  TARGET_B576000 0010006
+#define  TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VTIME	5
+#define TARGET_VMIN	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+#define TARGET_VEOL	11
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOL2	16
+
+/* ioctls */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/linux-user/main.c b/qemu-0.15.x/linux-user/main.c
new file mode 100644
index 0000000..6a8f4bd
--- /dev/null
+++ b/qemu-0.15.x/linux-user/main.c
@@ -0,0 +1,3569 @@
+/*
+ *  qemu user main
+ *
+ *  Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+#include "cache-utils.h"
+#include "cpu.h"
+#include "tcg.h"
+#include "qemu-timer.h"
+#include "envlist.h"
+
+#define DEBUG_LOGFILE "/tmp/qemu.log"
+
+char *exec_path;
+
+int singlestep;
+unsigned long mmap_min_addr;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long guest_base;
+int have_guest_base;
+unsigned long reserved_va;
+#endif
+
+static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
+const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
+
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+   we allocate a bigger stack. Need a better solution, for example
+   by remapping the process stack directly at the right place */
+unsigned long guest_stack_size = 8 * 1024 * 1024UL;
+
+void gemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
+#if defined(TARGET_I386)
+int cpu_get_pic_interrupt(CPUState *env)
+{
+    return -1;
+}
+#endif
+
+/* timers for rdtsc */
+
+#if 0
+
+static uint64_t emu_time;
+
+int64_t cpu_get_real_ticks(void)
+{
+    return emu_time++;
+}
+
+#endif
+
+#if defined(CONFIG_USE_NPTL)
+/***********************************************************/
+/* Helper routines for implementing atomic operations.  */
+
+/* To implement exclusive operations we force all cpus to syncronise.
+   We don't require a full sync, only that no cpus are executing guest code.
+   The alternative is to map target atomic ops onto host equivalents,
+   which requires quite a lot of per host/target work.  */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
+static int pending_cpus;
+
+/* Make sure everything is in a consistent state for calling fork().  */
+void fork_start(void)
+{
+    pthread_mutex_lock(&tb_lock);
+    pthread_mutex_lock(&exclusive_lock);
+    mmap_fork_start();
+}
+
+void fork_end(int child)
+{
+    mmap_fork_end(child);
+    if (child) {
+        /* Child processes created by fork() only have a single thread.
+           Discard information about the parent threads.  */
+        first_cpu = thread_env;
+        thread_env->next_cpu = NULL;
+        pending_cpus = 0;
+        pthread_mutex_init(&exclusive_lock, NULL);
+        pthread_mutex_init(&cpu_list_mutex, NULL);
+        pthread_cond_init(&exclusive_cond, NULL);
+        pthread_cond_init(&exclusive_resume, NULL);
+        pthread_mutex_init(&tb_lock, NULL);
+        gdbserver_fork(thread_env);
+    } else {
+        pthread_mutex_unlock(&exclusive_lock);
+        pthread_mutex_unlock(&tb_lock);
+    }
+}
+
+/* Wait for pending exclusive operations to complete.  The exclusive lock
+   must be held.  */
+static inline void exclusive_idle(void)
+{
+    while (pending_cpus) {
+        pthread_cond_wait(&exclusive_resume, &exclusive_lock);
+    }
+}
+
+/* Start an exclusive operation.
+   Must only be called from outside cpu_arm_exec.   */
+static inline void start_exclusive(void)
+{
+    CPUState *other;
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+
+    pending_cpus = 1;
+    /* Make all other cpus stop executing.  */
+    for (other = first_cpu; other; other = other->next_cpu) {
+        if (other->running) {
+            pending_cpus++;
+            cpu_exit(other);
+        }
+    }
+    if (pending_cpus > 1) {
+        pthread_cond_wait(&exclusive_cond, &exclusive_lock);
+    }
+}
+
+/* Finish an exclusive operation.  */
+static inline void end_exclusive(void)
+{
+    pending_cpus = 0;
+    pthread_cond_broadcast(&exclusive_resume);
+    pthread_mutex_unlock(&exclusive_lock);
+}
+
+/* Wait for exclusive ops to finish, and begin cpu execution.  */
+static inline void cpu_exec_start(CPUState *env)
+{
+    pthread_mutex_lock(&exclusive_lock);
+    exclusive_idle();
+    env->running = 1;
+    pthread_mutex_unlock(&exclusive_lock);
+}
+
+/* Mark cpu as not executing, and release pending exclusive ops.  */
+static inline void cpu_exec_end(CPUState *env)
+{
+    pthread_mutex_lock(&exclusive_lock);
+    env->running = 0;
+    if (pending_cpus > 1) {
+        pending_cpus--;
+        if (pending_cpus == 1) {
+            pthread_cond_signal(&exclusive_cond);
+        }
+    }
+    exclusive_idle();
+    pthread_mutex_unlock(&exclusive_lock);
+}
+
+void cpu_list_lock(void)
+{
+    pthread_mutex_lock(&cpu_list_mutex);
+}
+
+void cpu_list_unlock(void)
+{
+    pthread_mutex_unlock(&cpu_list_mutex);
+}
+#else /* if !CONFIG_USE_NPTL */
+/* These are no-ops because we are not threadsafe.  */
+static inline void cpu_exec_start(CPUState *env)
+{
+}
+
+static inline void cpu_exec_end(CPUState *env)
+{
+}
+
+static inline void start_exclusive(void)
+{
+}
+
+static inline void end_exclusive(void)
+{
+}
+
+void fork_start(void)
+{
+}
+
+void fork_end(int child)
+{
+    if (child) {
+        gdbserver_fork(thread_env);
+    }
+}
+
+void cpu_list_lock(void)
+{
+}
+
+void cpu_list_unlock(void)
+{
+}
+#endif
+
+
+#ifdef TARGET_I386
+/***********************************************************/
+/* CPUX86 core interface */
+
+void cpu_smm_update(CPUState *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+    return cpu_get_real_ticks();
+}
+
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+                     int flags)
+{
+    unsigned int e1, e2;
+    uint32_t *p;
+    e1 = (addr << 16) | (limit & 0xffff);
+    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+    e2 |= flags;
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+static uint64_t *idt_table;
+#ifdef TARGET_X86_64
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+                       uint64_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+    p[2] = tswap32(addr >> 32);
+    p[3] = 0;
+}
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     uint32_t addr, unsigned int sel)
+{
+    uint32_t *p, e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    p = ptr;
+    p[0] = tswap32(e1);
+    p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+#endif
+
+void cpu_loop(CPUX86State *env)
+{
+    int trapnr;
+    abi_ulong pc;
+    target_siginfo_t info;
+
+    for(;;) {
+        trapnr = cpu_x86_exec(env);
+        switch(trapnr) {
+        case 0x80:
+            /* linux syscall from int $0x80 */
+            env->regs[R_EAX] = do_syscall(env,
+                                          env->regs[R_EAX],
+                                          env->regs[R_EBX],
+                                          env->regs[R_ECX],
+                                          env->regs[R_EDX],
+                                          env->regs[R_ESI],
+                                          env->regs[R_EDI],
+                                          env->regs[R_EBP],
+                                          0, 0);
+            break;
+#ifndef TARGET_ABI32
+        case EXCP_SYSCALL:
+            /* linux syscall from syscall instruction */
+            env->regs[R_EAX] = do_syscall(env,
+                                          env->regs[R_EAX],
+                                          env->regs[R_EDI],
+                                          env->regs[R_ESI],
+                                          env->regs[R_EDX],
+                                          env->regs[10],
+                                          env->regs[8],
+                                          env->regs[9],
+                                          0, 0);
+            env->eip = env->exception_next_eip;
+            break;
+#endif
+        case EXCP0B_NOSEG:
+        case EXCP0C_STACK:
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_SI_KERNEL;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP0D_GPF:
+            /* XXX: potential problem if ABI32 */
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_fault(env);
+            } else
+#endif
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP0E_PAGE:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            if (!(env->error_code & 1))
+                info.si_code = TARGET_SEGV_MAPERR;
+            else
+                info.si_code = TARGET_SEGV_ACCERR;
+            info._sifields._sigfault._addr = env->cr[2];
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                /* division by zero */
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->eip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP01_DB:
+        case EXCP03_INT3:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                info.si_signo = SIGTRAP;
+                info.si_errno = 0;
+                if (trapnr == EXCP01_DB) {
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    info._sifields._sigfault._addr = env->eip;
+                } else {
+                    info.si_code = TARGET_SI_KERNEL;
+                    info._sifields._sigfault._addr = 0;
+                }
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+#ifndef TARGET_X86_64
+            if (env->eflags & VM_MASK) {
+                handle_vm86_trap(env, trapnr);
+            } else
+#endif
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SI_KERNEL;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            pc = env->segs[R_CS].base + env->eip;
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+                    (long)pc, trapnr);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+#ifdef TARGET_ARM
+
+/* Handle a jump to the kernel code page.  */
+static int
+do_kernel_trap(CPUARMState *env)
+{
+    uint32_t addr;
+    uint32_t cpsr;
+    uint32_t val;
+
+    switch (env->regs[15]) {
+    case 0xffff0fa0: /* __kernel_memory_barrier */
+        /* ??? No-op. Will need to do better for SMP.  */
+        break;
+    case 0xffff0fc0: /* __kernel_cmpxchg */
+         /* XXX: This only works between threads, not between processes.
+            It's probably possible to implement this with native host
+            operations. However things like ldrex/strex are much harder so
+            there's not much point trying.  */
+        start_exclusive();
+        cpsr = cpsr_read(env);
+        addr = env->regs[2];
+        /* FIXME: This should SEGV if the access fails.  */
+        if (get_user_u32(val, addr))
+            val = ~env->regs[0];
+        if (val == env->regs[0]) {
+            val = env->regs[1];
+            /* FIXME: Check for segfaults.  */
+            put_user_u32(val, addr);
+            env->regs[0] = 0;
+            cpsr |= CPSR_C;
+        } else {
+            env->regs[0] = -1;
+            cpsr &= ~CPSR_C;
+        }
+        cpsr_write(env, cpsr, CPSR_C);
+        end_exclusive();
+        break;
+    case 0xffff0fe0: /* __kernel_get_tls */
+        env->regs[0] = env->cp15.c13_tls2;
+        break;
+    default:
+        return 1;
+    }
+    /* Jump back to the caller.  */
+    addr = env->regs[14];
+    if (addr & 1) {
+        env->thumb = 1;
+        addr &= ~1;
+    }
+    env->regs[15] = addr;
+
+    return 0;
+}
+
+static int do_strex(CPUARMState *env)
+{
+    uint32_t val;
+    int size;
+    int rc = 1;
+    int segv = 0;
+    uint32_t addr;
+    start_exclusive();
+    addr = env->exclusive_addr;
+    if (addr != env->exclusive_test) {
+        goto fail;
+    }
+    size = env->exclusive_info & 0xf;
+    switch (size) {
+    case 0:
+        segv = get_user_u8(val, addr);
+        break;
+    case 1:
+        segv = get_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = get_user_u32(val, addr);
+        break;
+    default:
+        abort();
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (val != env->exclusive_val) {
+        goto fail;
+    }
+    if (size == 3) {
+        segv = get_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+        if (val != env->exclusive_high) {
+            goto fail;
+        }
+    }
+    val = env->regs[(env->exclusive_info >> 8) & 0xf];
+    switch (size) {
+    case 0:
+        segv = put_user_u8(val, addr);
+        break;
+    case 1:
+        segv = put_user_u16(val, addr);
+        break;
+    case 2:
+    case 3:
+        segv = put_user_u32(val, addr);
+        break;
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto done;
+    }
+    if (size == 3) {
+        val = env->regs[(env->exclusive_info >> 12) & 0xf];
+        segv = put_user_u32(val, addr + 4);
+        if (segv) {
+            env->cp15.c6_data = addr + 4;
+            goto done;
+        }
+    }
+    rc = 0;
+fail:
+    env->regs[15] += 4;
+    env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
+done:
+    end_exclusive();
+    return segv;
+}
+
+void cpu_loop(CPUARMState *env)
+{
+    int trapnr;
+    unsigned int n, insn;
+    target_siginfo_t info;
+    uint32_t addr;
+
+    for(;;) {
+        cpu_exec_start(env);
+        trapnr = cpu_arm_exec(env);
+        cpu_exec_end(env);
+        switch(trapnr) {
+        case EXCP_UDEF:
+            {
+                TaskState *ts = env->opaque;
+                uint32_t opcode;
+                int rc;
+
+                /* we handle the FPU emulation here, as Linux */
+                /* we get the opcode */
+                /* FIXME - what to do if get_user() fails? */
+                get_user_u32(opcode, env->regs[15]);
+
+                rc = EmulateAll(opcode, &ts->fpa, env);
+                if (rc == 0) { /* illegal instruction */
+                    info.si_signo = SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_ILL_ILLOPN;
+                    info._sifields._sigfault._addr = env->regs[15];
+                    queue_signal(env, info.si_signo, &info);
+                } else if (rc < 0) { /* FP exception */
+                    int arm_fpe=0;
+
+                    /* translate softfloat flags to FPSR flags */
+                    if (-rc & float_flag_invalid)
+                      arm_fpe |= BIT_IOC;
+                    if (-rc & float_flag_divbyzero)
+                      arm_fpe |= BIT_DZC;
+                    if (-rc & float_flag_overflow)
+                      arm_fpe |= BIT_OFC;
+                    if (-rc & float_flag_underflow)
+                      arm_fpe |= BIT_UFC;
+                    if (-rc & float_flag_inexact)
+                      arm_fpe |= BIT_IXC;
+
+                    FPSR fpsr = ts->fpa.fpsr;
+                    //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
+
+                    if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
+                      info.si_signo = SIGFPE;
+                      info.si_errno = 0;
+
+                      /* ordered by priority, least first */
+                      if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
+                      if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
+                      if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
+                      if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
+                      if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
+
+                      info._sifields._sigfault._addr = env->regs[15];
+                      queue_signal(env, info.si_signo, &info);
+                    } else {
+                      env->regs[15] += 4;
+                    }
+
+                    /* accumulate unenabled exceptions */
+                    if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
+                      fpsr |= BIT_IXC;
+                    if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
+                      fpsr |= BIT_UFC;
+                    if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
+                      fpsr |= BIT_OFC;
+                    if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
+                      fpsr |= BIT_DZC;
+                    if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
+                      fpsr |= BIT_IOC;
+                    ts->fpa.fpsr=fpsr;
+                } else { /* everything OK */
+                    /* increment PC */
+                    env->regs[15] += 4;
+                }
+            }
+            break;
+        case EXCP_SWI:
+        case EXCP_BKPT:
+            {
+                env->eabi = 1;
+                /* system call */
+                if (trapnr == EXCP_BKPT) {
+                    if (env->thumb) {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u16(insn, env->regs[15]);
+                        n = insn & 0xff;
+                        env->regs[15] += 2;
+                    } else {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u32(insn, env->regs[15]);
+                        n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+                        env->regs[15] += 4;
+                    }
+                } else {
+                    if (env->thumb) {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u16(insn, env->regs[15] - 2);
+                        n = insn & 0xff;
+                    } else {
+                        /* FIXME - what to do if get_user() fails? */
+                        get_user_u32(insn, env->regs[15] - 4);
+                        n = insn & 0xffffff;
+                    }
+                }
+
+                if (n == ARM_NR_cacheflush) {
+                    /* nop */
+                } else if (n == ARM_NR_semihosting
+                           || n == ARM_NR_thumb_semihosting) {
+                    env->regs[0] = do_arm_semihosting (env);
+                } else if (n == 0 || n >= ARM_SYSCALL_BASE
+                           || (env->thumb && n == ARM_THUMB_SYSCALL)) {
+                    /* linux syscall */
+                    if (env->thumb || n == 0) {
+                        n = env->regs[7];
+                    } else {
+                        n -= ARM_SYSCALL_BASE;
+                        env->eabi = 0;
+                    }
+                    if ( n > ARM_NR_BASE) {
+                        switch (n) {
+                        case ARM_NR_cacheflush:
+                            /* nop */
+                            break;
+                        case ARM_NR_set_tls:
+                            cpu_set_tls(env, env->regs[0]);
+                            env->regs[0] = 0;
+                            break;
+                        default:
+                            gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
+                                     n);
+                            env->regs[0] = -TARGET_ENOSYS;
+                            break;
+                        }
+                    } else {
+                        env->regs[0] = do_syscall(env,
+                                                  n,
+                                                  env->regs[0],
+                                                  env->regs[1],
+                                                  env->regs[2],
+                                                  env->regs[3],
+                                                  env->regs[4],
+                                                  env->regs[5],
+                                                  0, 0);
+                    }
+                } else {
+                    goto error;
+                }
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_PREFETCH_ABORT:
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        case EXCP_DATA_ABORT:
+            addr = env->cp15.c6_data;
+            goto do_segv;
+        do_segv:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        case EXCP_KERNEL_TRAP:
+            if (do_kernel_trap(env))
+              goto error;
+            break;
+        case EXCP_STREX:
+            if (do_strex(env)) {
+                addr = env->cp15.c6_data;
+                goto do_segv;
+            }
+            break;
+        default:
+        error:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+
+#endif
+
+#ifdef TARGET_UNICORE32
+
+void cpu_loop(CPUState *env)
+{
+    int trapnr;
+    unsigned int n, insn;
+    target_siginfo_t info;
+
+    for (;;) {
+        cpu_exec_start(env);
+        trapnr = uc32_cpu_exec(env);
+        cpu_exec_end(env);
+        switch (trapnr) {
+        case UC32_EXCP_PRIV:
+            {
+                /* system call */
+                get_user_u32(insn, env->regs[31] - 4);
+                n = insn & 0xffffff;
+
+                if (n >= UC32_SYSCALL_BASE) {
+                    /* linux syscall */
+                    n -= UC32_SYSCALL_BASE;
+                    if (n == UC32_SYSCALL_NR_set_tls) {
+                            cpu_set_tls(env, env->regs[0]);
+                            env->regs[0] = 0;
+                    } else {
+                        env->regs[0] = do_syscall(env,
+                                                  n,
+                                                  env->regs[0],
+                                                  env->regs[1],
+                                                  env->regs[2],
+                                                  env->regs[3],
+                                                  env->regs[4],
+                                                  env->regs[5],
+                                                  0, 0);
+                    }
+                } else {
+                    goto error;
+                }
+            }
+            break;
+        case UC32_EXCP_TRAP:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            /* XXX: check env->error_code */
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+        default:
+            goto error;
+        }
+        process_pending_signals(env);
+    }
+
+error:
+    fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+    cpu_dump_state(env, stderr, fprintf, 0);
+    abort();
+}
+#endif
+
+#ifdef TARGET_SPARC
+#define SPARC64_STACK_BIAS 2047
+
+//#define DEBUG_WIN
+
+/* WARNING: dealing with register windows _is_ complicated. More info
+   can be found at http://www.sics.se/~psm/sparcstack.html */
+static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+    index = (index + cwp * 16) % (16 * env->nwindows);
+    /* wrap handling : if cwp is on the last window, then we use the
+       registers 'after' the end */
+    if (index < 8 && env->cwp == env->nwindows - 1)
+        index += 16 * env->nwindows;
+    return index;
+}
+
+/* save the register window 'cwp1' */
+static inline void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+    unsigned int i;
+    abi_ulong sp_ptr;
+
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+    if (sp_ptr & 3)
+        sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for(i = 0; i < 16; i++) {
+        /* FIXME - what to do if put_user() fails? */
+        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+}
+
+static void save_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+    unsigned int new_wim;
+    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->wim = new_wim;
+#else
+    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+    env->cansave++;
+    env->canrestore--;
+#endif
+}
+
+static void restore_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+    unsigned int new_wim;
+#endif
+    unsigned int i, cwp1;
+    abi_ulong sp_ptr;
+
+#ifndef TARGET_SPARC64
+    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+        ((1LL << env->nwindows) - 1);
+#endif
+
+    /* restore the invalid window */
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+    if (sp_ptr & 3)
+        sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+           sp_ptr, cwp1);
+#endif
+    for(i = 0; i < 16; i++) {
+        /* FIXME - what to do if get_user() fails? */
+        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+        sp_ptr += sizeof(abi_ulong);
+    }
+#ifdef TARGET_SPARC64
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1)
+        env->cleanwin++;
+    env->cansave--;
+#else
+    env->wim = new_wim;
+#endif
+}
+
+static void flush_windows(CPUSPARCState *env)
+{
+    int offset, cwp1;
+
+    offset = 1;
+    for(;;) {
+        /* if restore would invoke restore_window(), then we can stop */
+        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+#ifndef TARGET_SPARC64
+        if (env->wim & (1 << cwp1))
+            break;
+#else
+        if (env->canrestore == 0)
+            break;
+        env->cansave++;
+        env->canrestore--;
+#endif
+        save_window_offset(env, cwp1);
+        offset++;
+    }
+    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#ifndef TARGET_SPARC64
+    /* set wim so that restore will reload the registers */
+    env->wim = 1 << cwp1;
+#endif
+#if defined(DEBUG_WIN)
+    printf("flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
+void cpu_loop (CPUSPARCState *env)
+{
+    int trapnr;
+    abi_long ret;
+    target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_sparc_exec (env);
+
+        switch (trapnr) {
+#ifndef TARGET_SPARC64
+        case 0x88:
+        case 0x90:
+#else
+        case 0x110:
+        case 0x16d:
+#endif
+            ret = do_syscall (env, env->gregs[1],
+                              env->regwptr[0], env->regwptr[1],
+                              env->regwptr[2], env->regwptr[3],
+                              env->regwptr[4], env->regwptr[5],
+                              0, 0);
+            if ((abi_ulong)ret >= (abi_ulong)(-515)) {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+                env->xcc |= PSR_CARRY;
+#else
+                env->psr |= PSR_CARRY;
+#endif
+                ret = -ret;
+            } else {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+                env->xcc &= ~PSR_CARRY;
+#else
+                env->psr &= ~PSR_CARRY;
+#endif
+            }
+            env->regwptr[0] = ret;
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+        case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+        case 0x103:
+#endif
+            flush_windows(env);
+            /* next instruction */
+            env->pc = env->npc;
+            env->npc = env->npc + 4;
+            break;
+#ifndef TARGET_SPARC64
+        case TT_WIN_OVF: /* window overflow */
+            save_window(env);
+            break;
+        case TT_WIN_UNF: /* window underflow */
+            restore_window(env);
+            break;
+        case TT_TFAULT:
+        case TT_DFAULT:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmuregs[4];
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+#else
+        case TT_SPILL: /* window overflow */
+            save_window(env);
+            break;
+        case TT_FILL: /* window underflow */
+            restore_window(env);
+            break;
+        case TT_TFAULT:
+        case TT_DFAULT:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT)
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                else
+                    info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+#ifndef TARGET_ABI32
+        case 0x16e:
+            flush_windows(env);
+            sparc64_get_context(env);
+            break;
+        case 0x16f:
+            flush_windows(env);
+            sparc64_set_context(env);
+            break;
+#endif
+#endif
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+
+#endif
+
+#ifdef TARGET_PPC
+static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+{
+    /* TO FIX */
+    return 0;
+}
+
+uint64_t cpu_ppc_load_tbl (CPUState *env)
+{
+    return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint64_t cpu_ppc_load_atbl (CPUState *env)
+{
+    return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_atbu (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
+{
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
+{
+    return -1;
+}
+
+#define EXCP_DUMP(env, fmt, ...)                                        \
+do {                                                                    \
+    fprintf(stderr, fmt , ## __VA_ARGS__);                              \
+    cpu_dump_state(env, stderr, fprintf, 0);                            \
+    qemu_log(fmt, ## __VA_ARGS__);                                      \
+    if (logfile)                                                        \
+        log_cpu_state(env, 0);                                          \
+} while (0)
+
+static int do_store_exclusive(CPUPPCState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+
+    addr = env->reserve_ea;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        int reg = env->reserve_info & 0x1f;
+        int size = (env->reserve_info >> 5) & 0xf;
+        int stored = 0;
+
+        if (addr == env->reserve_addr) {
+            switch (size) {
+            case 1: segv = get_user_u8(val, addr); break;
+            case 2: segv = get_user_u16(val, addr); break;
+            case 4: segv = get_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+            case 8: segv = get_user_u64(val, addr); break;
+#endif
+            default: abort();
+            }
+            if (!segv && val == env->reserve_val) {
+                val = env->gpr[reg];
+                switch (size) {
+                case 1: segv = put_user_u8(val, addr); break;
+                case 2: segv = put_user_u16(val, addr); break;
+                case 4: segv = put_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+                case 8: segv = put_user_u64(val, addr); break;
+#endif
+                default: abort();
+                }
+                if (!segv) {
+                    stored = 1;
+                }
+            }
+        }
+        env->crf[0] = (stored << 1) | xer_so;
+        env->reserve_addr = (target_ulong)-1;
+    }
+    if (!segv) {
+        env->nip += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+void cpu_loop(CPUPPCState *env)
+{
+    target_siginfo_t info;
+    int trapnr;
+    uint32_t ret;
+
+    for(;;) {
+        cpu_exec_start(env);
+        trapnr = cpu_ppc_exec(env);
+        cpu_exec_end(env);
+        switch(trapnr) {
+        case POWERPC_EXCP_NONE:
+            /* Just go on */
+            break;
+        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
+            cpu_abort(env, "Critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
+            cpu_abort(env, "Machine check exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSI:      /* Data storage exception                */
+            EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
+                      env->spr[SPR_DAR]);
+            /* XXX: check this. Seems bugged */
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            case 0x04000000:
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLADR;
+                break;
+            case 0x08000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_ACCERR;
+                break;
+            default:
+                /* Let's send a regular segfault... */
+                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+                          env->error_code);
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
+            EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
+                      "\n", env->spr[SPR_SRR0]);
+            /* XXX: check this */
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
+                info.si_signo = TARGET_SIGSEGV;
+            info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            case 0x10000000:
+            case 0x08000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_ACCERR;
+                break;
+            default:
+                /* Let's send a regular segfault... */
+                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+                          env->error_code);
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EXTERNAL: /* External input                        */
+            cpu_abort(env, "External interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
+            EXCP_DUMP(env, "Unaligned memory access\n");
+            /* XXX: check this */
+            info.si_signo = TARGET_SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_BUS_ADRALN;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
+            /* XXX: check this */
+            switch (env->error_code & ~0xF) {
+            case POWERPC_EXCP_FP:
+                EXCP_DUMP(env, "Floating point program exception\n");
+                info.si_signo = TARGET_SIGFPE;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_FP_OX:
+                    info.si_code = TARGET_FPE_FLTOVF;
+                    break;
+                case POWERPC_EXCP_FP_UX:
+                    info.si_code = TARGET_FPE_FLTUND;
+                    break;
+                case POWERPC_EXCP_FP_ZX:
+                case POWERPC_EXCP_FP_VXZDZ:
+                    info.si_code = TARGET_FPE_FLTDIV;
+                    break;
+                case POWERPC_EXCP_FP_XX:
+                    info.si_code = TARGET_FPE_FLTRES;
+                    break;
+                case POWERPC_EXCP_FP_VXSOFT:
+                    info.si_code = TARGET_FPE_FLTINV;
+                    break;
+                case POWERPC_EXCP_FP_VXSNAN:
+                case POWERPC_EXCP_FP_VXISI:
+                case POWERPC_EXCP_FP_VXIDI:
+                case POWERPC_EXCP_FP_VXIMZ:
+                case POWERPC_EXCP_FP_VXVC:
+                case POWERPC_EXCP_FP_VXSQRT:
+                case POWERPC_EXCP_FP_VXCVI:
+                    info.si_code = TARGET_FPE_FLTSUB;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+                              env->error_code);
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_INVAL:
+                EXCP_DUMP(env, "Invalid instruction\n");
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_INVAL_INVAL:
+                    info.si_code = TARGET_ILL_ILLOPC;
+                    break;
+                case POWERPC_EXCP_INVAL_LSWX:
+                    info.si_code = TARGET_ILL_ILLOPN;
+                    break;
+                case POWERPC_EXCP_INVAL_SPR:
+                    info.si_code = TARGET_ILL_PRVREG;
+                    break;
+                case POWERPC_EXCP_INVAL_FP:
+                    info.si_code = TARGET_ILL_COPROC;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = TARGET_ILL_ILLADR;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_PRIV:
+                EXCP_DUMP(env, "Privilege violation\n");
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_PRIV_OPC:
+                    info.si_code = TARGET_ILL_PRVOPC;
+                    break;
+                case POWERPC_EXCP_PRIV_REG:
+                    info.si_code = TARGET_ILL_PRVREG;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = TARGET_ILL_PRVOPC;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_TRAP:
+                cpu_abort(env, "Tried to call a TRAP\n");
+                break;
+            default:
+                /* Should not happen ! */
+                cpu_abort(env, "Unknown program exception (%02x)\n",
+                          env->error_code);
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
+            EXCP_DUMP(env, "No floating point allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
+            cpu_abort(env, "Syscall exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
+            EXCP_DUMP(env, "No APU instruction allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
+            cpu_abort(env, "Decrementer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
+            cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
+            cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
+            cpu_abort(env, "Data TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
+            cpu_abort(env, "Instruction TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
+            EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
+            cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
+            cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
+            cpu_abort(env, "Doorbell interrupt while in user mode. "
+                       "Aborting\n");
+            break;
+        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
+            cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RESET:    /* System reset exception                */
+            cpu_abort(env, "Reset interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
+            cpu_abort(env, "Data segment exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
+            cpu_abort(env, "Instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
+            cpu_abort(env, "Hypervisor decrementer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
+            /* Nothing to do:
+             * we use this exception to emulate step-by-step execution mode.
+             */
+            break;
+        /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
+            cpu_abort(env, "Hypervisor data storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
+            cpu_abort(env, "Hypervisor instruction storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
+            cpu_abort(env, "Hypervisor data segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
+            cpu_abort(env, "Hypervisor instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
+            EXCP_DUMP(env, "No Altivec instructions allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
+            cpu_abort(env, "Programable interval timer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_IO:       /* IO error exception                    */
+            cpu_abort(env, "IO error exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
+            cpu_abort(env, "Run mode exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
+            cpu_abort(env, "Emulation trap exception not handled\n");
+            break;
+        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
+            cpu_abort(env, "Instruction fetch TLB exception "
+                      "while in user-mode. Aborting");
+            break;
+        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
+            cpu_abort(env, "Data load TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
+            cpu_abort(env, "Data store TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
+            cpu_abort(env, "Floating-point assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
+            cpu_abort(env, "Instruction address breakpoint exception "
+                      "not handled\n");
+            break;
+        case POWERPC_EXCP_SMI:      /* System management interrupt           */
+            cpu_abort(env, "System management interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
+            cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
+            cpu_abort(env, "Vector assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
+            cpu_abort(env, "Soft patch exception not handled\n");
+            break;
+        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
+            cpu_abort(env, "Maintenance exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_STOP:     /* stop translation                      */
+            /* We did invalidate the instruction cache. Go on */
+            break;
+        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
+            /* We just stopped because of a branch. Go on */
+            break;
+        case POWERPC_EXCP_SYSCALL_USER:
+            /* system call in user-mode emulation */
+            /* WARNING:
+             * PPC ABI uses overflow flag in cr0 to signal an error
+             * in syscalls.
+             */
+#if 0
+            printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
+                   env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
+#endif
+            env->crf[0] &= ~0x1;
+            ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+                             env->gpr[5], env->gpr[6], env->gpr[7],
+                             env->gpr[8], 0, 0);
+            if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+                /* Returning from a successful sigreturn syscall.
+                   Avoid corrupting register state.  */
+                break;
+            }
+            if (ret > (uint32_t)(-515)) {
+                env->crf[0] |= 0x1;
+                ret = -ret;
+            }
+            env->gpr[3] = ret;
+#if 0
+            printf("syscall returned 0x%08x (%d)\n", ret, ret);
+#endif
+            break;
+        case POWERPC_EXCP_STCX:
+            if (do_store_exclusive(env)) {
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->nip;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        default:
+            cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+            break;
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+#ifdef TARGET_MIPS
+
+#define MIPS_SYS(name, args) args,
+
+static const uint8_t mips_syscall_args[] = {
+	MIPS_SYS(sys_syscall	, 0)	/* 4000 */
+	MIPS_SYS(sys_exit	, 1)
+	MIPS_SYS(sys_fork	, 0)
+	MIPS_SYS(sys_read	, 3)
+	MIPS_SYS(sys_write	, 3)
+	MIPS_SYS(sys_open	, 3)	/* 4005 */
+	MIPS_SYS(sys_close	, 1)
+	MIPS_SYS(sys_waitpid	, 3)
+	MIPS_SYS(sys_creat	, 2)
+	MIPS_SYS(sys_link	, 2)
+	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
+	MIPS_SYS(sys_execve	, 0)
+	MIPS_SYS(sys_chdir	, 1)
+	MIPS_SYS(sys_time	, 1)
+	MIPS_SYS(sys_mknod	, 3)
+	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
+	MIPS_SYS(sys_lchown	, 3)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
+	MIPS_SYS(sys_lseek	, 3)
+	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
+	MIPS_SYS(sys_mount	, 5)
+	MIPS_SYS(sys_oldumount	, 1)
+	MIPS_SYS(sys_setuid	, 1)
+	MIPS_SYS(sys_getuid	, 0)
+	MIPS_SYS(sys_stime	, 1)	/* 4025 */
+	MIPS_SYS(sys_ptrace	, 4)
+	MIPS_SYS(sys_alarm	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
+	MIPS_SYS(sys_pause	, 0)
+	MIPS_SYS(sys_utime	, 2)	/* 4030 */
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_access	, 2)
+	MIPS_SYS(sys_nice	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
+	MIPS_SYS(sys_sync	, 0)
+	MIPS_SYS(sys_kill	, 2)
+	MIPS_SYS(sys_rename	, 2)
+	MIPS_SYS(sys_mkdir	, 2)
+	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
+	MIPS_SYS(sys_dup		, 1)
+	MIPS_SYS(sys_pipe	, 0)
+	MIPS_SYS(sys_times	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_brk		, 1)	/* 4045 */
+	MIPS_SYS(sys_setgid	, 1)
+	MIPS_SYS(sys_getgid	, 0)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
+	MIPS_SYS(sys_geteuid	, 0)
+	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
+	MIPS_SYS(sys_acct	, 0)
+	MIPS_SYS(sys_umount	, 2)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_ioctl	, 3)
+	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
+	MIPS_SYS(sys_ni_syscall	, 2)
+	MIPS_SYS(sys_setpgid	, 2)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_olduname	, 1)
+	MIPS_SYS(sys_umask	, 1)	/* 4060 */
+	MIPS_SYS(sys_chroot	, 1)
+	MIPS_SYS(sys_ustat	, 2)
+	MIPS_SYS(sys_dup2	, 2)
+	MIPS_SYS(sys_getppid	, 0)
+	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
+	MIPS_SYS(sys_setsid	, 0)
+	MIPS_SYS(sys_sigaction	, 3)
+	MIPS_SYS(sys_sgetmask	, 0)
+	MIPS_SYS(sys_ssetmask	, 1)
+	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
+	MIPS_SYS(sys_setregid	, 2)
+	MIPS_SYS(sys_sigsuspend	, 0)
+	MIPS_SYS(sys_sigpending	, 1)
+	MIPS_SYS(sys_sethostname	, 2)
+	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
+	MIPS_SYS(sys_getrlimit	, 2)
+	MIPS_SYS(sys_getrusage	, 2)
+	MIPS_SYS(sys_gettimeofday, 2)
+	MIPS_SYS(sys_settimeofday, 2)
+	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
+	MIPS_SYS(sys_setgroups	, 2)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
+	MIPS_SYS(sys_symlink	, 2)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
+	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
+	MIPS_SYS(sys_uselib	, 1)
+	MIPS_SYS(sys_swapon	, 2)
+	MIPS_SYS(sys_reboot	, 3)
+	MIPS_SYS(old_readdir	, 3)
+	MIPS_SYS(old_mmap	, 6)	/* 4090 */
+	MIPS_SYS(sys_munmap	, 2)
+	MIPS_SYS(sys_truncate	, 2)
+	MIPS_SYS(sys_ftruncate	, 2)
+	MIPS_SYS(sys_fchmod	, 2)
+	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
+	MIPS_SYS(sys_getpriority	, 2)
+	MIPS_SYS(sys_setpriority	, 3)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_statfs	, 2)
+	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
+	MIPS_SYS(sys_socketcall	, 2)
+	MIPS_SYS(sys_syslog	, 3)
+	MIPS_SYS(sys_setitimer	, 3)
+	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
+	MIPS_SYS(sys_newstat	, 2)
+	MIPS_SYS(sys_newlstat	, 2)
+	MIPS_SYS(sys_newfstat	, 2)
+	MIPS_SYS(sys_uname	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
+	MIPS_SYS(sys_vhangup	, 0)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
+	MIPS_SYS(sys_wait4	, 4)
+	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
+	MIPS_SYS(sys_sysinfo	, 1)
+	MIPS_SYS(sys_ipc		, 6)
+	MIPS_SYS(sys_fsync	, 1)
+	MIPS_SYS(sys_sigreturn	, 0)
+	MIPS_SYS(sys_clone	, 6)	/* 4120 */
+	MIPS_SYS(sys_setdomainname, 2)
+	MIPS_SYS(sys_newuname	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
+	MIPS_SYS(sys_adjtimex	, 1)
+	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
+	MIPS_SYS(sys_sigprocmask	, 3)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
+	MIPS_SYS(sys_init_module	, 5)
+	MIPS_SYS(sys_delete_module, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
+	MIPS_SYS(sys_quotactl	, 0)
+	MIPS_SYS(sys_getpgid	, 1)
+	MIPS_SYS(sys_fchdir	, 1)
+	MIPS_SYS(sys_bdflush	, 2)
+	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
+	MIPS_SYS(sys_personality	, 1)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
+	MIPS_SYS(sys_setfsuid	, 1)
+	MIPS_SYS(sys_setfsgid	, 1)
+	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
+	MIPS_SYS(sys_getdents	, 3)
+	MIPS_SYS(sys_select	, 5)
+	MIPS_SYS(sys_flock	, 2)
+	MIPS_SYS(sys_msync	, 3)
+	MIPS_SYS(sys_readv	, 3)	/* 4145 */
+	MIPS_SYS(sys_writev	, 3)
+	MIPS_SYS(sys_cacheflush	, 3)
+	MIPS_SYS(sys_cachectl	, 3)
+	MIPS_SYS(sys_sysmips	, 4)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
+	MIPS_SYS(sys_getsid	, 1)
+	MIPS_SYS(sys_fdatasync	, 0)
+	MIPS_SYS(sys_sysctl	, 1)
+	MIPS_SYS(sys_mlock	, 2)
+	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
+	MIPS_SYS(sys_mlockall	, 1)
+	MIPS_SYS(sys_munlockall	, 0)
+	MIPS_SYS(sys_sched_setparam, 2)
+	MIPS_SYS(sys_sched_getparam, 2)
+	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
+	MIPS_SYS(sys_sched_getscheduler, 1)
+	MIPS_SYS(sys_sched_yield	, 0)
+	MIPS_SYS(sys_sched_get_priority_max, 1)
+	MIPS_SYS(sys_sched_get_priority_min, 1)
+	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
+	MIPS_SYS(sys_nanosleep,	2)
+	MIPS_SYS(sys_mremap	, 4)
+	MIPS_SYS(sys_accept	, 3)
+	MIPS_SYS(sys_bind	, 3)
+	MIPS_SYS(sys_connect	, 3)	/* 4170 */
+	MIPS_SYS(sys_getpeername	, 3)
+	MIPS_SYS(sys_getsockname	, 3)
+	MIPS_SYS(sys_getsockopt	, 5)
+	MIPS_SYS(sys_listen	, 2)
+	MIPS_SYS(sys_recv	, 4)	/* 4175 */
+	MIPS_SYS(sys_recvfrom	, 6)
+	MIPS_SYS(sys_recvmsg	, 3)
+	MIPS_SYS(sys_send	, 4)
+	MIPS_SYS(sys_sendmsg	, 3)
+	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
+	MIPS_SYS(sys_setsockopt	, 5)
+	MIPS_SYS(sys_shutdown	, 2)
+	MIPS_SYS(sys_socket	, 3)
+	MIPS_SYS(sys_socketpair	, 4)
+	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
+	MIPS_SYS(sys_getresuid	, 3)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
+	MIPS_SYS(sys_poll	, 3)
+	MIPS_SYS(sys_nfsservctl	, 3)
+	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
+	MIPS_SYS(sys_getresgid	, 3)
+	MIPS_SYS(sys_prctl	, 5)
+	MIPS_SYS(sys_rt_sigreturn, 0)
+	MIPS_SYS(sys_rt_sigaction, 4)
+	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
+	MIPS_SYS(sys_rt_sigpending, 2)
+	MIPS_SYS(sys_rt_sigtimedwait, 4)
+	MIPS_SYS(sys_rt_sigqueueinfo, 3)
+	MIPS_SYS(sys_rt_sigsuspend, 0)
+	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
+	MIPS_SYS(sys_pwrite64	, 6)
+	MIPS_SYS(sys_chown	, 3)
+	MIPS_SYS(sys_getcwd	, 2)
+	MIPS_SYS(sys_capget	, 2)
+	MIPS_SYS(sys_capset	, 2)	/* 4205 */
+	MIPS_SYS(sys_sigaltstack	, 2)
+	MIPS_SYS(sys_sendfile	, 4)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
+	MIPS_SYS(sys_truncate64	, 4)
+	MIPS_SYS(sys_ftruncate64	, 4)
+	MIPS_SYS(sys_stat64	, 2)
+	MIPS_SYS(sys_lstat64	, 2)
+	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
+	MIPS_SYS(sys_pivot_root	, 2)
+	MIPS_SYS(sys_mincore	, 3)
+	MIPS_SYS(sys_madvise	, 3)
+	MIPS_SYS(sys_getdents64	, 3)
+	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
+	MIPS_SYS(sys_ni_syscall	, 0)
+	MIPS_SYS(sys_gettid	, 0)
+	MIPS_SYS(sys_readahead	, 5)
+	MIPS_SYS(sys_setxattr	, 5)
+	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
+	MIPS_SYS(sys_fsetxattr	, 5)
+	MIPS_SYS(sys_getxattr	, 4)
+	MIPS_SYS(sys_lgetxattr	, 4)
+	MIPS_SYS(sys_fgetxattr	, 4)
+	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
+	MIPS_SYS(sys_llistxattr	, 3)
+	MIPS_SYS(sys_flistxattr	, 3)
+	MIPS_SYS(sys_removexattr	, 2)
+	MIPS_SYS(sys_lremovexattr, 2)
+	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
+	MIPS_SYS(sys_tkill	, 2)
+	MIPS_SYS(sys_sendfile64	, 5)
+	MIPS_SYS(sys_futex	, 2)
+	MIPS_SYS(sys_sched_setaffinity, 3)
+	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
+	MIPS_SYS(sys_io_setup	, 2)
+	MIPS_SYS(sys_io_destroy	, 1)
+	MIPS_SYS(sys_io_getevents, 5)
+	MIPS_SYS(sys_io_submit	, 3)
+	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
+	MIPS_SYS(sys_exit_group	, 1)
+	MIPS_SYS(sys_lookup_dcookie, 3)
+	MIPS_SYS(sys_epoll_create, 1)
+	MIPS_SYS(sys_epoll_ctl	, 4)
+	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
+	MIPS_SYS(sys_remap_file_pages, 5)
+	MIPS_SYS(sys_set_tid_address, 1)
+	MIPS_SYS(sys_restart_syscall, 0)
+	MIPS_SYS(sys_fadvise64_64, 7)
+	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
+	MIPS_SYS(sys_fstatfs64	, 2)
+	MIPS_SYS(sys_timer_create, 3)
+	MIPS_SYS(sys_timer_settime, 4)
+	MIPS_SYS(sys_timer_gettime, 2)
+	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
+	MIPS_SYS(sys_timer_delete, 1)
+	MIPS_SYS(sys_clock_settime, 2)
+	MIPS_SYS(sys_clock_gettime, 2)
+	MIPS_SYS(sys_clock_getres, 2)
+	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
+	MIPS_SYS(sys_tgkill	, 3)
+	MIPS_SYS(sys_utimes	, 2)
+	MIPS_SYS(sys_mbind	, 4)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
+	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
+	MIPS_SYS(sys_mq_open	, 4)
+	MIPS_SYS(sys_mq_unlink	, 1)
+	MIPS_SYS(sys_mq_timedsend, 5)
+	MIPS_SYS(sys_mq_timedreceive, 5)
+	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
+	MIPS_SYS(sys_mq_getsetattr, 3)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
+	MIPS_SYS(sys_waitid	, 4)
+	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
+	MIPS_SYS(sys_add_key	, 5)
+	MIPS_SYS(sys_request_key, 4)
+	MIPS_SYS(sys_keyctl	, 5)
+	MIPS_SYS(sys_set_thread_area, 1)
+	MIPS_SYS(sys_inotify_init, 0)
+	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
+	MIPS_SYS(sys_inotify_rm_watch, 2)
+	MIPS_SYS(sys_migrate_pages, 4)
+	MIPS_SYS(sys_openat, 4)
+	MIPS_SYS(sys_mkdirat, 3)
+	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
+	MIPS_SYS(sys_fchownat, 5)
+	MIPS_SYS(sys_futimesat, 3)
+	MIPS_SYS(sys_fstatat64, 4)
+	MIPS_SYS(sys_unlinkat, 3)
+	MIPS_SYS(sys_renameat, 4)	/* 4295 */
+	MIPS_SYS(sys_linkat, 5)
+	MIPS_SYS(sys_symlinkat, 3)
+	MIPS_SYS(sys_readlinkat, 4)
+	MIPS_SYS(sys_fchmodat, 3)
+	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
+	MIPS_SYS(sys_pselect6, 6)
+	MIPS_SYS(sys_ppoll, 5)
+	MIPS_SYS(sys_unshare, 1)
+	MIPS_SYS(sys_splice, 4)
+	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
+	MIPS_SYS(sys_tee, 4)
+	MIPS_SYS(sys_vmsplice, 4)
+	MIPS_SYS(sys_move_pages, 6)
+	MIPS_SYS(sys_set_robust_list, 2)
+	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
+	MIPS_SYS(sys_kexec_load, 4)
+	MIPS_SYS(sys_getcpu, 3)
+	MIPS_SYS(sys_epoll_pwait, 6)
+	MIPS_SYS(sys_ioprio_set, 3)
+	MIPS_SYS(sys_ioprio_get, 2)
+        MIPS_SYS(sys_utimensat, 4)
+        MIPS_SYS(sys_signalfd, 3)
+        MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
+        MIPS_SYS(sys_eventfd, 1)
+        MIPS_SYS(sys_fallocate, 6)      /* 4320 */
+        MIPS_SYS(sys_timerfd_create, 2)
+        MIPS_SYS(sys_timerfd_gettime, 2)
+        MIPS_SYS(sys_timerfd_settime, 4)
+        MIPS_SYS(sys_signalfd4, 4)
+        MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
+        MIPS_SYS(sys_epoll_create1, 1)
+        MIPS_SYS(sys_dup3, 3)
+        MIPS_SYS(sys_pipe2, 2)
+        MIPS_SYS(sys_inotify_init1, 1)
+        MIPS_SYS(sys_preadv, 6)         /* 4330 */
+        MIPS_SYS(sys_pwritev, 6)
+        MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
+        MIPS_SYS(sys_perf_event_open, 5)
+        MIPS_SYS(sys_accept4, 4)
+        MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
+        MIPS_SYS(sys_fanotify_init, 2)
+        MIPS_SYS(sys_fanotify_mark, 6)
+        MIPS_SYS(sys_prlimit64, 4)
+        MIPS_SYS(sys_name_to_handle_at, 5)
+        MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
+        MIPS_SYS(sys_clock_adjtime, 2)
+        MIPS_SYS(sys_syncfs, 1)
+};
+
+#undef MIPS_SYS
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+    target_ulong addr;
+    target_ulong page_addr;
+    target_ulong val;
+    int flags;
+    int segv = 0;
+    int reg;
+    int d;
+
+    addr = env->lladdr;
+    page_addr = addr & TARGET_PAGE_MASK;
+    start_exclusive();
+    mmap_lock();
+    flags = page_get_flags(page_addr);
+    if ((flags & PAGE_READ) == 0) {
+        segv = 1;
+    } else {
+        reg = env->llreg & 0x1f;
+        d = (env->llreg & 0x20) != 0;
+        if (d) {
+            segv = get_user_s64(val, addr);
+        } else {
+            segv = get_user_s32(val, addr);
+        }
+        if (!segv) {
+            if (val != env->llval) {
+                env->active_tc.gpr[reg] = 0;
+            } else {
+                if (d) {
+                    segv = put_user_u64(env->llnewval, addr);
+                } else {
+                    segv = put_user_u32(env->llnewval, addr);
+                }
+                if (!segv) {
+                    env->active_tc.gpr[reg] = 1;
+                }
+            }
+        }
+    }
+    env->lladdr = -1;
+    if (!segv) {
+        env->active_tc.PC += 4;
+    }
+    mmap_unlock();
+    end_exclusive();
+    return segv;
+}
+
+void cpu_loop(CPUMIPSState *env)
+{
+    target_siginfo_t info;
+    int trapnr, ret;
+    unsigned int syscall_num;
+
+    for(;;) {
+        cpu_exec_start(env);
+        trapnr = cpu_mips_exec(env);
+        cpu_exec_end(env);
+        switch(trapnr) {
+        case EXCP_SYSCALL:
+            syscall_num = env->active_tc.gpr[2] - 4000;
+            env->active_tc.PC += 4;
+            if (syscall_num >= sizeof(mips_syscall_args)) {
+                ret = -TARGET_ENOSYS;
+            } else {
+                int nb_args;
+                abi_ulong sp_reg;
+                abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
+
+                nb_args = mips_syscall_args[syscall_num];
+                sp_reg = env->active_tc.gpr[29];
+                switch (nb_args) {
+                /* these arguments are taken from the stack */
+                /* FIXME - what to do if get_user() fails? */
+                case 8: get_user_ual(arg8, sp_reg + 28);
+                case 7: get_user_ual(arg7, sp_reg + 24);
+                case 6: get_user_ual(arg6, sp_reg + 20);
+                case 5: get_user_ual(arg5, sp_reg + 16);
+                default:
+                    break;
+                }
+                ret = do_syscall(env, env->active_tc.gpr[2],
+                                 env->active_tc.gpr[4],
+                                 env->active_tc.gpr[5],
+                                 env->active_tc.gpr[6],
+                                 env->active_tc.gpr[7],
+                                 arg5, arg6, arg7, arg8);
+            }
+            if (ret == -TARGET_QEMU_ESIGRETURN) {
+                /* Returning from a successful sigreturn syscall.
+                   Avoid clobbering register state.  */
+                break;
+            }
+            if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                env->active_tc.gpr[7] = 1; /* error flag */
+                ret = -ret;
+            } else {
+                env->active_tc.gpr[7] = 0; /* error flag */
+            }
+            env->active_tc.gpr[2] = ret;
+            break;
+        case EXCP_TLBL:
+        case EXCP_TLBS:
+        case EXCP_AdEL:
+        case EXCP_AdES:
+            info.si_signo = TARGET_SIGSEGV;
+            info.si_errno = 0;
+            /* XXX: check env->error_code */
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->CP0_BadVAddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_CpU:
+        case EXCP_RI:
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = 0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        case EXCP_SC:
+            if (do_store_exclusive(env)) {
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->active_tc.PC;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        default:
+            //        error:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
+#ifdef TARGET_SH4
+void cpu_loop (CPUState *env)
+{
+    int trapnr, ret;
+    target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_sh4_exec (env);
+
+        switch (trapnr) {
+        case 0x160:
+            env->pc += 2;
+            ret = do_syscall(env,
+                             env->gregs[3],
+                             env->gregs[4],
+                             env->gregs[5],
+                             env->gregs[6],
+                             env->gregs[7],
+                             env->gregs[0],
+                             env->gregs[1],
+                             0, 0);
+            env->gregs[0] = ret;
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+	case 0xa0:
+	case 0xc0:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->tea;
+            queue_signal(env, info.si_signo, &info);
+	    break;
+
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+#endif
+
+#ifdef TARGET_CRIS
+void cpu_loop (CPUState *env)
+{
+    int trapnr, ret;
+    target_siginfo_t info;
+    
+    while (1) {
+        trapnr = cpu_cris_exec (env);
+        switch (trapnr) {
+        case 0xaa:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->pregs[PR_EDA];
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+	case EXCP_INTERRUPT:
+	  /* just indicate that signals should be handled asap */
+	  break;
+        case EXCP_BREAK:
+            ret = do_syscall(env, 
+                             env->regs[9], 
+                             env->regs[10], 
+                             env->regs[11], 
+                             env->regs[12], 
+                             env->regs[13], 
+                             env->pregs[7], 
+                             env->pregs[11],
+                             0, 0);
+            env->regs[10] = ret;
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+#endif
+
+#ifdef TARGET_MICROBLAZE
+void cpu_loop (CPUState *env)
+{
+    int trapnr, ret;
+    target_siginfo_t info;
+    
+    while (1) {
+        trapnr = cpu_mb_exec (env);
+        switch (trapnr) {
+        case 0xaa:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+	case EXCP_INTERRUPT:
+	  /* just indicate that signals should be handled asap */
+	  break;
+        case EXCP_BREAK:
+            /* Return address is 4 bytes after the call.  */
+            env->regs[14] += 4;
+            ret = do_syscall(env, 
+                             env->regs[12], 
+                             env->regs[5], 
+                             env->regs[6], 
+                             env->regs[7], 
+                             env->regs[8], 
+                             env->regs[9], 
+                             env->regs[10],
+                             0, 0);
+            env->regs[3] = ret;
+            env->sregs[SR_PC] = env->regs[14];
+            break;
+        case EXCP_HW_EXCP:
+            env->regs[17] = env->sregs[SR_PC] + 4;
+            if (env->iflags & D_FLAG) {
+                env->sregs[SR_ESR] |= 1 << 12;
+                env->sregs[SR_PC] -= 4;
+                /* FIXME: if branch was immed, replay the imm aswell.  */
+            }
+
+            env->iflags &= ~(IMM_FLAG | D_FLAG);
+
+            switch (env->sregs[SR_ESR] & 31) {
+                case ESR_EC_FPU:
+                    info.si_signo = SIGFPE;
+                    info.si_errno = 0;
+                    if (env->sregs[SR_FSR] & FSR_IO) {
+                        info.si_code = TARGET_FPE_FLTINV;
+                    }
+                    if (env->sregs[SR_FSR] & FSR_DZ) {
+                        info.si_code = TARGET_FPE_FLTDIV;
+                    }
+                    info._sifields._sigfault._addr = 0;
+                    queue_signal(env, info.si_signo, &info);
+                    break;
+                default:
+                    printf ("Unhandled hw-exception: 0x%x\n",
+                            env->sregs[SR_ESR] & ESR_EC_MASK);
+                    cpu_dump_state(env, stderr, fprintf, 0);
+                    exit (1);
+                    break;
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+#endif
+
+#ifdef TARGET_M68K
+
+void cpu_loop(CPUM68KState *env)
+{
+    int trapnr;
+    unsigned int n;
+    target_siginfo_t info;
+    TaskState *ts = env->opaque;
+
+    for(;;) {
+        trapnr = cpu_m68k_exec(env);
+        switch(trapnr) {
+        case EXCP_ILLEGAL:
+            {
+                if (ts->sim_syscalls) {
+                    uint16_t nr;
+                    nr = lduw(env->pc + 2);
+                    env->pc += 4;
+                    do_m68k_simcall(env, nr);
+                } else {
+                    goto do_sigill;
+                }
+            }
+            break;
+        case EXCP_HALT_INSN:
+            /* Semihosing syscall.  */
+            env->pc += 4;
+            do_m68k_semihosting(env, env->dregs[0]);
+            break;
+        case EXCP_LINEA:
+        case EXCP_LINEF:
+        case EXCP_UNSUPPORTED:
+        do_sigill:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->pc;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_TRAP0:
+            {
+                ts->sim_syscalls = 0;
+                n = env->dregs[0];
+                env->pc += 2;
+                env->dregs[0] = do_syscall(env,
+                                          n,
+                                          env->dregs[1],
+                                          env->dregs[2],
+                                          env->dregs[3],
+                                          env->dregs[4],
+                                          env->dregs[5],
+                                          env->aregs[0],
+                                          0, 0);
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_ACCESS:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmu.ar;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif /* TARGET_M68K */
+
+#ifdef TARGET_ALPHA
+static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
+{
+    target_ulong addr, val, tmp;
+    target_siginfo_t info;
+    int ret = 0;
+
+    addr = env->lock_addr;
+    tmp = env->lock_st_addr;
+    env->lock_addr = -1;
+    env->lock_st_addr = 0;
+
+    start_exclusive();
+    mmap_lock();
+
+    if (addr == tmp) {
+        if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+            goto do_sigsegv;
+        }
+
+        if (val == env->lock_value) {
+            tmp = env->ir[reg];
+            if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
+                goto do_sigsegv;
+            }
+            ret = 1;
+        }
+    }
+    env->ir[reg] = ret;
+    env->pc += 4;
+
+    mmap_unlock();
+    end_exclusive();
+    return;
+
+ do_sigsegv:
+    mmap_unlock();
+    end_exclusive();
+
+    info.si_signo = TARGET_SIGSEGV;
+    info.si_errno = 0;
+    info.si_code = TARGET_SEGV_MAPERR;
+    info._sifields._sigfault._addr = addr;
+    queue_signal(env, TARGET_SIGSEGV, &info);
+}
+
+void cpu_loop (CPUState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+    abi_long sysret;
+
+    while (1) {
+        trapnr = cpu_alpha_exec (env);
+
+        /* All of the traps imply a transition through PALcode, which
+           implies an REI instruction has been executed.  Which means
+           that the intr_flag should be cleared.  */
+        env->intr_flag = 0;
+
+        switch (trapnr) {
+        case EXCP_RESET:
+            fprintf(stderr, "Reset requested. Exit\n");
+            exit(1);
+            break;
+        case EXCP_MCHK:
+            fprintf(stderr, "Machine check exception. Exit\n");
+            exit(1);
+            break;
+        case EXCP_SMP_INTERRUPT:
+        case EXCP_CLK_INTERRUPT:
+        case EXCP_DEV_INTERRUPT:
+            fprintf(stderr, "External interrupt. Exit\n");
+            exit(1);
+            break;
+        case EXCP_MMFAULT:
+            env->lock_addr = -1;
+            info.si_signo = TARGET_SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
+                            ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
+            info._sifields._sigfault._addr = env->trap_arg0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_UNALIGN:
+            env->lock_addr = -1;
+            info.si_signo = TARGET_SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_BUS_ADRALN;
+            info._sifields._sigfault._addr = env->trap_arg0;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_OPCDEC:
+        do_sigill:
+            env->lock_addr = -1;
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPC;
+            info._sifields._sigfault._addr = env->pc;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_ARITH:
+            env->lock_addr = -1;
+            info.si_signo = TARGET_SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_FLTINV;
+            info._sifields._sigfault._addr = env->pc;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_FEN:
+            /* No-op.  Linux simply re-enables the FPU.  */
+            break;
+        case EXCP_CALL_PAL:
+            env->lock_addr = -1;
+            switch (env->error_code) {
+            case 0x80:
+                /* BPT */
+                info.si_signo = TARGET_SIGTRAP;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                info._sifields._sigfault._addr = env->pc;
+                queue_signal(env, info.si_signo, &info);
+                break;
+            case 0x81:
+                /* BUGCHK */
+                info.si_signo = TARGET_SIGTRAP;
+                info.si_errno = 0;
+                info.si_code = 0;
+                info._sifields._sigfault._addr = env->pc;
+                queue_signal(env, info.si_signo, &info);
+                break;
+            case 0x83:
+                /* CALLSYS */
+                trapnr = env->ir[IR_V0];
+                sysret = do_syscall(env, trapnr,
+                                    env->ir[IR_A0], env->ir[IR_A1],
+                                    env->ir[IR_A2], env->ir[IR_A3],
+                                    env->ir[IR_A4], env->ir[IR_A5],
+                                    0, 0);
+                if (trapnr == TARGET_NR_sigreturn
+                    || trapnr == TARGET_NR_rt_sigreturn) {
+                    break;
+                }
+                /* Syscall writes 0 to V0 to bypass error check, similar
+                   to how this is handled internal to Linux kernel.  */
+                if (env->ir[IR_V0] == 0) {
+                    env->ir[IR_V0] = sysret;
+                } else {
+                    env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret);
+                    env->ir[IR_A3] = (sysret < 0);
+                }
+                break;
+            case 0x86:
+                /* IMB */
+                /* ??? We can probably elide the code using page_unprotect
+                   that is checking for self-modifying code.  Instead we
+                   could simply call tb_flush here.  Until we work out the
+                   changes required to turn off the extra write protection,
+                   this can be a no-op.  */
+                break;
+            case 0x9E:
+                /* RDUNIQUE */
+                /* Handled in the translator for usermode.  */
+                abort();
+            case 0x9F:
+                /* WRUNIQUE */
+                /* Handled in the translator for usermode.  */
+                abort();
+            case 0xAA:
+                /* GENTRAP */
+                info.si_signo = TARGET_SIGFPE;
+                switch (env->ir[IR_A0]) {
+                case TARGET_GEN_INTOVF:
+                    info.si_code = TARGET_FPE_INTOVF;
+                    break;
+                case TARGET_GEN_INTDIV:
+                    info.si_code = TARGET_FPE_INTDIV;
+                    break;
+                case TARGET_GEN_FLTOVF:
+                    info.si_code = TARGET_FPE_FLTOVF;
+                    break;
+                case TARGET_GEN_FLTUND:
+                    info.si_code = TARGET_FPE_FLTUND;
+                    break;
+                case TARGET_GEN_FLTINV:
+                    info.si_code = TARGET_FPE_FLTINV;
+                    break;
+                case TARGET_GEN_FLTINE:
+                    info.si_code = TARGET_FPE_FLTRES;
+                    break;
+                case TARGET_GEN_ROPRAND:
+                    info.si_code = 0;
+                    break;
+                default:
+                    info.si_signo = TARGET_SIGTRAP;
+                    info.si_code = 0;
+                    break;
+                }
+                info.si_errno = 0;
+                info._sifields._sigfault._addr = env->pc;
+                queue_signal(env, info.si_signo, &info);
+                break;
+            default:
+                goto do_sigill;
+            }
+            break;
+        case EXCP_DEBUG:
+            info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
+            if (info.si_signo) {
+                env->lock_addr = -1;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_STL_C:
+        case EXCP_STQ_C:
+            do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+#endif /* TARGET_ALPHA */
+
+#ifdef TARGET_S390X
+void cpu_loop(CPUS390XState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_s390x_exec (env);
+
+        switch (trapnr) {
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+        case EXCP_SVC:
+            {
+                int n = env->int_svc_code;
+                if (!n) {
+                    /* syscalls > 255 */
+                    n = env->regs[1];
+                }
+                env->psw.addr += env->int_svc_ilc;
+                env->regs[2] = do_syscall(env, n,
+                           env->regs[2],
+                           env->regs[3],
+                           env->regs[4],
+                           env->regs[5],
+                           env->regs[6],
+                           env->regs[7],
+                           0, 0);
+            }
+            break;
+        case EXCP_ADDR:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->__excp_addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        case EXCP_SPEC:
+            {
+                fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4));
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLOPC;
+                info._sifields._sigfault._addr = env->__excp_addr;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+
+#endif /* TARGET_S390X */
+
+static void version(void)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
+           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+static void usage(void)
+{
+    version();
+    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+           "Linux CPU emulator (compiled for %s emulation)\n"
+           "\n"
+           "Standard options:\n"
+           "-h                print this help\n"
+           "-version          display version information and exit\n"
+           "-g port           wait gdb connection to port\n"
+           "-L path           set the elf interpreter prefix (default=%s)\n"
+           "-s size           set the stack size in bytes (default=%ld)\n"
+           "-cpu model        select CPU (-cpu ? for list)\n"
+           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
+           "-E var=value      sets/modifies targets environment variable(s)\n"
+           "-U var            unsets targets environment variable(s)\n"
+           "-0 argv0          forces target process argv[0] to be argv0\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+           "-B address        set guest_base address to address\n"
+           "-R size           reserve size bytes for guest virtual address space\n"
+#endif
+           "\n"
+           "Debug options:\n"
+           "-d options   activate log (logfile=%s)\n"
+           "-p pagesize  set the host page size to 'pagesize'\n"
+           "-singlestep  always run in singlestep mode\n"
+           "-strace      log system calls\n"
+           "\n"
+           "Environment variables:\n"
+           "QEMU_STRACE       Print system calls and arguments similar to the\n"
+           "                  'strace' program.  Enable by setting to any value.\n"
+           "You can use -E and -U options to set/unset environment variables\n"
+           "for target process.  It is possible to provide several variables\n"
+           "by repeating the option.  For example:\n"
+           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+           "Note that if you provide several changes to single variable\n"
+           "last change will stay in effect.\n"
+           ,
+           TARGET_ARCH,
+           interp_prefix,
+           guest_stack_size,
+           DEBUG_LOGFILE);
+    exit(1);
+}
+
+THREAD CPUState *thread_env;
+
+void task_settid(TaskState *ts)
+{
+    if (ts->ts_tid == 0) {
+#ifdef CONFIG_USE_NPTL
+        ts->ts_tid = (pid_t)syscall(SYS_gettid);
+#else
+        /* when no threads are used, tid becomes pid */
+        ts->ts_tid = getpid();
+#endif
+    }
+}
+
+void stop_all_tasks(void)
+{
+    /*
+     * We trust that when using NPTL, start_exclusive()
+     * handles thread stopping correctly.
+     */
+    start_exclusive();
+}
+
+/* Assumes contents are already zeroed.  */
+void init_task_state(TaskState *ts)
+{
+    int i;
+ 
+    ts->used = 1;
+    ts->first_free = ts->sigqueue_table;
+    for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
+        ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
+    }
+    ts->sigqueue_table[i].next = NULL;
+}
+ 
+int main(int argc, char **argv, char **envp)
+{
+    const char *filename;
+    const char *cpu_model;
+    const char *log_file = DEBUG_LOGFILE;
+    const char *log_mask = NULL;
+    struct target_pt_regs regs1, *regs = &regs1;
+    struct image_info info1, *info = &info1;
+    struct linux_binprm bprm;
+    TaskState *ts;
+    CPUState *env;
+    int optind;
+    const char *r;
+    int gdbstub_port = 0;
+    char **target_environ, **wrk;
+    char **target_argv;
+    int target_argc;
+    envlist_t *envlist = NULL;
+    const char *argv0 = NULL;
+    int i;
+    int ret;
+
+    if (argc <= 1)
+        usage();
+
+    qemu_cache_utils_init(envp);
+
+    if ((envlist = envlist_create()) == NULL) {
+        (void) fprintf(stderr, "Unable to allocate envlist\n");
+        exit(1);
+    }
+
+    /* add current environment into the list */
+    for (wrk = environ; *wrk != NULL; wrk++) {
+        (void) envlist_setenv(envlist, *wrk);
+    }
+
+    /* Read the stack limit from the kernel.  If it's "unlimited",
+       then we can do little else besides use the default.  */
+    {
+        struct rlimit lim;
+        if (getrlimit(RLIMIT_STACK, &lim) == 0
+            && lim.rlim_cur != RLIM_INFINITY
+            && lim.rlim_cur == (target_long)lim.rlim_cur) {
+            guest_stack_size = lim.rlim_cur;
+        }
+    }
+
+    cpu_model = NULL;
+#if defined(cpudef_setup)
+    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+        r = argv[optind];
+        if (r[0] != '-')
+            break;
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        } else if (!strcmp(r, "d")) {
+            if (optind >= argc) {
+		break;
+            }
+            log_mask = argv[optind++];
+        } else if (!strcmp(r, "D")) {
+            if (optind >= argc) {
+                break;
+            }
+            log_file = argv[optind++];
+        } else if (!strcmp(r, "E")) {
+            r = argv[optind++];
+            if (envlist_setenv(envlist, r) != 0)
+                usage();
+        } else if (!strcmp(r, "ignore-environment")) {
+            envlist_free(envlist);
+            if ((envlist = envlist_create()) == NULL) {
+                (void) fprintf(stderr, "Unable to allocate envlist\n");
+                exit(1);
+            }
+        } else if (!strcmp(r, "U")) {
+            r = argv[optind++];
+            if (envlist_unsetenv(envlist, r) != 0)
+                usage();
+        } else if (!strcmp(r, "0")) {
+            r = argv[optind++];
+            argv0 = r;
+        } else if (!strcmp(r, "s")) {
+            if (optind >= argc)
+                break;
+            r = argv[optind++];
+            guest_stack_size = strtoul(r, (char **)&r, 0);
+            if (guest_stack_size == 0)
+                usage();
+            if (*r == 'M')
+                guest_stack_size *= 1024 * 1024;
+            else if (*r == 'k' || *r == 'K')
+                guest_stack_size *= 1024;
+        } else if (!strcmp(r, "L")) {
+            interp_prefix = argv[optind++];
+        } else if (!strcmp(r, "p")) {
+            if (optind >= argc)
+                break;
+            qemu_host_page_size = atoi(argv[optind++]);
+            if (qemu_host_page_size == 0 ||
+                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+                fprintf(stderr, "page size must be a power of two\n");
+                exit(1);
+            }
+        } else if (!strcmp(r, "g")) {
+            if (optind >= argc)
+                break;
+            gdbstub_port = atoi(argv[optind++]);
+	} else if (!strcmp(r, "r")) {
+	    qemu_uname_release = argv[optind++];
+        } else if (!strcmp(r, "cpu")) {
+            cpu_model = argv[optind++];
+            if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
+/* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list_id)
+                cpu_list_id(stdout, &fprintf, "");
+#elif defined(cpu_list)
+                cpu_list(stdout, &fprintf); /* deprecated */
+#endif
+                exit(1);
+            }
+#if defined(CONFIG_USE_GUEST_BASE)
+        } else if (!strcmp(r, "B")) {
+           guest_base = strtol(argv[optind++], NULL, 0);
+           have_guest_base = 1;
+        } else if (!strcmp(r, "R")) {
+            char *p;
+            int shift = 0;
+            reserved_va = strtoul(argv[optind++], &p, 0);
+            switch (*p) {
+            case 'k':
+            case 'K':
+                shift = 10;
+                break;
+            case 'M':
+                shift = 20;
+                break;
+            case 'G':
+                shift = 30;
+                break;
+            }
+            if (shift) {
+                unsigned long unshifted = reserved_va;
+                p++;
+                reserved_va <<= shift;
+                if (((reserved_va >> shift) != unshifted)
+#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
+#endif
+                    ) {
+                    fprintf(stderr, "Reserved virtual address too big\n");
+                    exit(1);
+                }
+            }
+            if (*p) {
+                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
+                exit(1);
+            }
+#endif
+        } else if (!strcmp(r, "drop-ld-preload")) {
+            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+        } else if (!strcmp(r, "singlestep")) {
+            singlestep = 1;
+        } else if (!strcmp(r, "strace")) {
+            do_strace = 1;
+        } else if (!strcmp(r, "version")) {
+            version();
+            exit(0);
+        } else {
+            usage();
+        }
+    }
+    /* init debug */
+    cpu_set_log_filename(log_file);
+    if (log_mask) {
+        int mask;
+        const CPULogItem *item;
+
+        mask = cpu_str_to_log_mask(log_mask);
+        if (!mask) {
+            printf("Log items (comma separated):\n");
+            for (item = cpu_log_items; item->mask != 0; item++) {
+                printf("%-10s %s\n", item->name, item->help);
+            }
+            exit(1);
+        }
+        cpu_set_log(mask);
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+    filename = argv[optind];
+    exec_path = argv[optind];
+
+    /* Zero out regs */
+    memset(regs, 0, sizeof(struct target_pt_regs));
+
+    /* Zero out image_info */
+    memset(info, 0, sizeof(struct image_info));
+
+    memset(&bprm, 0, sizeof (bprm));
+
+    /* Scan interp_prefix dir for replacement files. */
+    init_paths(interp_prefix);
+
+    if (cpu_model == NULL) {
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+#elif defined(TARGET_ARM)
+        cpu_model = "any";
+#elif defined(TARGET_UNICORE32)
+        cpu_model = "any";
+#elif defined(TARGET_M68K)
+        cpu_model = "any";
+#elif defined(TARGET_SPARC)
+#ifdef TARGET_SPARC64
+        cpu_model = "TI UltraSparc II";
+#else
+        cpu_model = "Fujitsu MB86904";
+#endif
+#elif defined(TARGET_MIPS)
+#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
+        cpu_model = "20Kc";
+#else
+        cpu_model = "24Kf";
+#endif
+#elif defined(TARGET_PPC)
+#ifdef TARGET_PPC64
+        cpu_model = "970fx";
+#else
+        cpu_model = "750";
+#endif
+#else
+        cpu_model = "any";
+#endif
+    }
+    cpu_exec_init_all(0);
+    /* NOTE: we need to init the CPU at this stage to get
+       qemu_host_page_size */
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
+    cpu_reset(env);
+#endif
+
+    thread_env = env;
+
+    if (getenv("QEMU_STRACE")) {
+        do_strace = 1;
+    }
+
+    target_environ = envlist_to_environ(envlist, NULL);
+    envlist_free(envlist);
+
+#if defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Now that page sizes are configured in cpu_init() we can do
+     * proper page alignment for guest_base.
+     */
+    guest_base = HOST_PAGE_ALIGN(guest_base);
+
+    if (reserved_va) {
+        void *p;
+        int flags;
+
+        flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
+        if (have_guest_base) {
+            flags |= MAP_FIXED;
+        }
+        p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
+        if (p == MAP_FAILED) {
+            fprintf(stderr, "Unable to reserve guest address space\n");
+            exit(1);
+        }
+        guest_base = (unsigned long)p;
+        /* Make sure the address is properly aligned.  */
+        if (guest_base & ~qemu_host_page_mask) {
+            munmap(p, reserved_va);
+            p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
+                     PROT_NONE, flags, -1, 0);
+            if (p == MAP_FAILED) {
+                fprintf(stderr, "Unable to reserve guest address space\n");
+                exit(1);
+            }
+            guest_base = HOST_PAGE_ALIGN((unsigned long)p);
+        }
+        qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+    /*
+     * Read in mmap_min_addr kernel parameter.  This value is used
+     * When loading the ELF image to determine whether guest_base
+     * is needed.  It is also used in mmap_find_vma.
+     */
+    {
+        FILE *fp;
+
+        if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
+            unsigned long tmp;
+            if (fscanf(fp, "%lu", &tmp) == 1) {
+                mmap_min_addr = tmp;
+                qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
+            }
+            fclose(fp);
+        }
+    }
+
+    /*
+     * Prepare copy of argv vector for target.
+     */
+    target_argc = argc - optind;
+    target_argv = calloc(target_argc + 1, sizeof (char *));
+    if (target_argv == NULL) {
+	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+	exit(1);
+    }
+
+    /*
+     * If argv0 is specified (using '-0' switch) we replace
+     * argv[0] pointer with the given one.
+     */
+    i = 0;
+    if (argv0 != NULL) {
+        target_argv[i++] = strdup(argv0);
+    }
+    for (; i < target_argc; i++) {
+        target_argv[i] = strdup(argv[optind + i]);
+    }
+    target_argv[target_argc] = NULL;
+
+    ts = qemu_mallocz (sizeof(TaskState));
+    init_task_state(ts);
+    /* build Task State */
+    ts->info = info;
+    ts->bprm = &bprm;
+    env->opaque = ts;
+    task_settid(ts);
+
+    ret = loader_exec(filename, target_argv, target_environ, regs,
+        info, &bprm);
+    if (ret != 0) {
+        printf("Error %d while loading %s\n", ret, filename);
+        _exit(1);
+    }
+
+    for (i = 0; i < target_argc; i++) {
+        free(target_argv[i]);
+    }
+    free(target_argv);
+
+    for (wrk = target_environ; *wrk; wrk++) {
+        free(*wrk);
+    }
+
+    free(target_environ);
+
+    if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+        qemu_log("guest_base  0x%lx\n", guest_base);
+#endif
+        log_page_dump();
+
+        qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
+        qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
+        qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_code);
+        qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_data);
+        qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
+        qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
+                 info->start_stack);
+        qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
+        qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
+    }
+
+    target_set_brk(info->brk);
+    syscall_init();
+    signal_init();
+
+#if defined(CONFIG_USE_GUEST_BASE)
+    /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
+       generating the prologue until now so that the prologue can take
+       the real value of GUEST_BASE into account.  */
+    tcg_prologue_init(&tcg_ctx);
+#endif
+
+#if defined(TARGET_I386)
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    env->hflags |= HF_PE_MASK;
+    if (env->cpuid_features & CPUID_SSE) {
+        env->cr[4] |= CR4_OSFXSR_MASK;
+        env->hflags |= HF_OSFXSR_MASK;
+    }
+#ifndef TARGET_ABI32
+    /* enable 64 bit mode if possible */
+    if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
+        fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+        exit(1);
+    }
+    env->cr[4] |= CR4_PAE_MASK;
+    env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+    env->hflags |= HF_LMA_MASK;
+#endif
+
+    /* flags setup : we activate the IRQs by default as in user mode */
+    env->eflags |= IF_MASK;
+
+    /* linux register setup */
+#ifndef TARGET_ABI32
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+#else
+    env->regs[R_EAX] = regs->eax;
+    env->regs[R_EBX] = regs->ebx;
+    env->regs[R_ECX] = regs->ecx;
+    env->regs[R_EDX] = regs->edx;
+    env->regs[R_ESI] = regs->esi;
+    env->regs[R_EDI] = regs->edi;
+    env->regs[R_EBP] = regs->ebp;
+    env->regs[R_ESP] = regs->esp;
+    env->eip = regs->eip;
+#endif
+
+    /* linux interrupt setup */
+#ifndef TARGET_ABI32
+    env->idt.limit = 511;
+#else
+    env->idt.limit = 255;
+#endif
+    env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+                                PROT_READ|PROT_WRITE,
+                                MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+    idt_table = g2h(env->idt.base);
+    set_idt(0, 0);
+    set_idt(1, 0);
+    set_idt(2, 0);
+    set_idt(3, 3);
+    set_idt(4, 3);
+    set_idt(5, 0);
+    set_idt(6, 0);
+    set_idt(7, 0);
+    set_idt(8, 0);
+    set_idt(9, 0);
+    set_idt(10, 0);
+    set_idt(11, 0);
+    set_idt(12, 0);
+    set_idt(13, 0);
+    set_idt(14, 0);
+    set_idt(15, 0);
+    set_idt(16, 0);
+    set_idt(17, 0);
+    set_idt(18, 0);
+    set_idt(19, 0);
+    set_idt(0x80, 3);
+
+    /* linux segment setup */
+    {
+        uint64_t *gdt_table;
+        env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+                                    PROT_READ|PROT_WRITE,
+                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+        env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+        gdt_table = g2h(env->gdt.base);
+#ifdef TARGET_ABI32
+        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+        /* 64 bit code segment */
+        write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 DESC_L_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
+        write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+                 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+    }
+    cpu_x86_load_seg(env, R_CS, __USER_CS);
+    cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
+    cpu_x86_load_seg(env, R_DS, __USER_DS);
+    cpu_x86_load_seg(env, R_ES, __USER_DS);
+    cpu_x86_load_seg(env, R_FS, __USER_DS);
+    cpu_x86_load_seg(env, R_GS, __USER_DS);
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
+#else
+    cpu_x86_load_seg(env, R_DS, 0);
+    cpu_x86_load_seg(env, R_ES, 0);
+    cpu_x86_load_seg(env, R_FS, 0);
+    cpu_x86_load_seg(env, R_GS, 0);
+#endif
+#elif defined(TARGET_ARM)
+    {
+        int i;
+        cpsr_write(env, regs->uregs[16], 0xffffffff);
+        for(i = 0; i < 16; i++) {
+            env->regs[i] = regs->uregs[i];
+        }
+    }
+#elif defined(TARGET_UNICORE32)
+    {
+        int i;
+        cpu_asr_write(env, regs->uregs[32], 0xffffffff);
+        for (i = 0; i < 32; i++) {
+            env->regs[i] = regs->uregs[i];
+        }
+    }
+#elif defined(TARGET_SPARC)
+    {
+        int i;
+	env->pc = regs->pc;
+	env->npc = regs->npc;
+        env->y = regs->y;
+        for(i = 0; i < 8; i++)
+            env->gregs[i] = regs->u_regs[i];
+        for(i = 0; i < 8; i++)
+            env->regwptr[i] = regs->u_regs[i + 8];
+    }
+#elif defined(TARGET_PPC)
+    {
+        int i;
+
+#if defined(TARGET_PPC64)
+#if defined(TARGET_ABI32)
+        env->msr &= ~((target_ulong)1 << MSR_SF);
+#else
+        env->msr |= (target_ulong)1 << MSR_SF;
+#endif
+#endif
+        env->nip = regs->nip;
+        for(i = 0; i < 32; i++) {
+            env->gpr[i] = regs->gpr[i];
+        }
+    }
+#elif defined(TARGET_M68K)
+    {
+        env->pc = regs->pc;
+        env->dregs[0] = regs->d0;
+        env->dregs[1] = regs->d1;
+        env->dregs[2] = regs->d2;
+        env->dregs[3] = regs->d3;
+        env->dregs[4] = regs->d4;
+        env->dregs[5] = regs->d5;
+        env->dregs[6] = regs->d6;
+        env->dregs[7] = regs->d7;
+        env->aregs[0] = regs->a0;
+        env->aregs[1] = regs->a1;
+        env->aregs[2] = regs->a2;
+        env->aregs[3] = regs->a3;
+        env->aregs[4] = regs->a4;
+        env->aregs[5] = regs->a5;
+        env->aregs[6] = regs->a6;
+        env->aregs[7] = regs->usp;
+        env->sr = regs->sr;
+        ts->sim_syscalls = 1;
+    }
+#elif defined(TARGET_MICROBLAZE)
+    {
+        env->regs[0] = regs->r0;
+        env->regs[1] = regs->r1;
+        env->regs[2] = regs->r2;
+        env->regs[3] = regs->r3;
+        env->regs[4] = regs->r4;
+        env->regs[5] = regs->r5;
+        env->regs[6] = regs->r6;
+        env->regs[7] = regs->r7;
+        env->regs[8] = regs->r8;
+        env->regs[9] = regs->r9;
+        env->regs[10] = regs->r10;
+        env->regs[11] = regs->r11;
+        env->regs[12] = regs->r12;
+        env->regs[13] = regs->r13;
+        env->regs[14] = regs->r14;
+        env->regs[15] = regs->r15;	    
+        env->regs[16] = regs->r16;	    
+        env->regs[17] = regs->r17;	    
+        env->regs[18] = regs->r18;	    
+        env->regs[19] = regs->r19;	    
+        env->regs[20] = regs->r20;	    
+        env->regs[21] = regs->r21;	    
+        env->regs[22] = regs->r22;	    
+        env->regs[23] = regs->r23;	    
+        env->regs[24] = regs->r24;	    
+        env->regs[25] = regs->r25;	    
+        env->regs[26] = regs->r26;	    
+        env->regs[27] = regs->r27;	    
+        env->regs[28] = regs->r28;	    
+        env->regs[29] = regs->r29;	    
+        env->regs[30] = regs->r30;	    
+        env->regs[31] = regs->r31;	    
+        env->sregs[SR_PC] = regs->pc;
+    }
+#elif defined(TARGET_MIPS)
+    {
+        int i;
+
+        for(i = 0; i < 32; i++) {
+            env->active_tc.gpr[i] = regs->regs[i];
+        }
+        env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+        if (regs->cp0_epc & 1) {
+            env->hflags |= MIPS_HFLAG_M16;
+        }
+    }
+#elif defined(TARGET_SH4)
+    {
+        int i;
+
+        for(i = 0; i < 16; i++) {
+            env->gregs[i] = regs->regs[i];
+        }
+        env->pc = regs->pc;
+    }
+#elif defined(TARGET_ALPHA)
+    {
+        int i;
+
+        for(i = 0; i < 28; i++) {
+            env->ir[i] = ((abi_ulong *)regs)[i];
+        }
+        env->ir[IR_SP] = regs->usp;
+        env->pc = regs->pc;
+    }
+#elif defined(TARGET_CRIS)
+    {
+	    env->regs[0] = regs->r0;
+	    env->regs[1] = regs->r1;
+	    env->regs[2] = regs->r2;
+	    env->regs[3] = regs->r3;
+	    env->regs[4] = regs->r4;
+	    env->regs[5] = regs->r5;
+	    env->regs[6] = regs->r6;
+	    env->regs[7] = regs->r7;
+	    env->regs[8] = regs->r8;
+	    env->regs[9] = regs->r9;
+	    env->regs[10] = regs->r10;
+	    env->regs[11] = regs->r11;
+	    env->regs[12] = regs->r12;
+	    env->regs[13] = regs->r13;
+	    env->regs[14] = info->start_stack;
+	    env->regs[15] = regs->acr;	    
+	    env->pc = regs->erp;
+    }
+#elif defined(TARGET_S390X)
+    {
+            int i;
+            for (i = 0; i < 16; i++) {
+                env->regs[i] = regs->gprs[i];
+            }
+            env->psw.mask = regs->psw.mask;
+            env->psw.addr = regs->psw.addr;
+    }
+#else
+#error unsupported target CPU
+#endif
+
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+    ts->stack_base = info->start_stack;
+    ts->heap_base = info->brk;
+    /* This will be filled in on the first SYS_HEAPINFO call.  */
+    ts->heap_limit = 0;
+#endif
+
+    if (gdbstub_port) {
+        gdbserver_start (gdbstub_port);
+        gdb_handlesig(env, 0);
+    }
+    cpu_loop(env);
+    /* never exits */
+    return 0;
+}
diff --git a/qemu-0.15.x/linux-user/microblaze/syscall.h b/qemu-0.15.x/linux-user/microblaze/syscall.h
new file mode 100644
index 0000000..db1f98a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/microblaze/syscall.h
@@ -0,0 +1,45 @@
+#define UNAME_MACHINE "microblaze"
+
+/* We use microblaze_reg_t to keep things similar to the kernel sources.  */
+typedef uint32_t microblaze_reg_t;
+
+struct target_pt_regs {
+        microblaze_reg_t r0;
+        microblaze_reg_t r1;
+        microblaze_reg_t r2;
+        microblaze_reg_t r3;
+        microblaze_reg_t r4;
+        microblaze_reg_t r5;
+        microblaze_reg_t r6;
+        microblaze_reg_t r7;
+        microblaze_reg_t r8;
+        microblaze_reg_t r9;
+        microblaze_reg_t r10;
+        microblaze_reg_t r11;
+        microblaze_reg_t r12;
+        microblaze_reg_t r13;
+        microblaze_reg_t r14;
+        microblaze_reg_t r15;
+        microblaze_reg_t r16;
+        microblaze_reg_t r17;
+        microblaze_reg_t r18;
+        microblaze_reg_t r19;
+        microblaze_reg_t r20;
+        microblaze_reg_t r21;
+        microblaze_reg_t r22;
+        microblaze_reg_t r23;
+        microblaze_reg_t r24;
+        microblaze_reg_t r25;
+        microblaze_reg_t r26;
+        microblaze_reg_t r27;
+        microblaze_reg_t r28;
+        microblaze_reg_t r29;
+        microblaze_reg_t r30;
+        microblaze_reg_t r31;
+        microblaze_reg_t pc;
+        microblaze_reg_t msr;
+        microblaze_reg_t ear;
+        microblaze_reg_t esr;
+        microblaze_reg_t fsr;
+        uint32_t kernel_mode;
+};
diff --git a/qemu-0.15.x/linux-user/microblaze/syscall_nr.h b/qemu-0.15.x/linux-user/microblaze/syscall_nr.h
new file mode 100644
index 0000000..f1fe0e7
--- /dev/null
+++ b/qemu-0.15.x/linux-user/microblaze/syscall_nr.h
@@ -0,0 +1,379 @@
+#define TARGET_NR_restart_syscall	0 /* ok */
+#define TARGET_NR_exit		1 /* ok */
+#define TARGET_NR_fork		2 /* not for no MMU - weird */
+#define TARGET_NR_read		3 /* ok */
+#define TARGET_NR_write		4 /* ok */
+#define TARGET_NR_open		5 /* openat */
+#define TARGET_NR_close		6 /* ok */
+#define TARGET_NR_waitpid		7 /* waitid */
+#define TARGET_NR_creat		8 /* openat */
+#define TARGET_NR_link		9 /* linkat */
+#define TARGET_NR_unlink		10 /* unlinkat */
+#define TARGET_NR_execve		11 /* ok */
+#define TARGET_NR_chdir		12 /* ok */
+#define TARGET_NR_time		13 /* obsolete -> sys_gettimeofday */
+#define TARGET_NR_mknod		14 /* mknodat */
+#define TARGET_NR_chmod		15 /* fchmodat */
+#define TARGET_NR_lchown		16 /* ok */
+#define TARGET_NR_break		17 /* don't know */
+#define TARGET_NR_oldstat		18 /* remove */
+#define TARGET_NR_lseek		19 /* ok */
+#define TARGET_NR_getpid		20 /* ok */
+#define TARGET_NR_mount		21 /* ok */
+#define TARGET_NR_umount		22 /* ok */  /* use only umount2 */
+#define TARGET_NR_setuid		23 /* ok */
+#define TARGET_NR_getuid		24 /* ok */
+#define TARGET_NR_stime		25 /* obsolete -> sys_settimeofday */
+#define TARGET_NR_ptrace		26 /* ok */
+#define TARGET_NR_alarm		27 /* obsolete -> sys_setitimer */
+#define TARGET_NR_oldfstat		28 /* remove */
+#define TARGET_NR_pause		29 /* obsolete -> sys_rt_sigtimedwait */
+#define TARGET_NR_utime		30 /* obsolete -> sys_utimesat */
+#define TARGET_NR_stty		31 /* remove */
+#define TARGET_NR_gtty		32 /* remove */
+#define TARGET_NR_access		33 /* faccessat */
+#define TARGET_NR_nice		34 /* can be implemented by sys_setpriority */
+#define TARGET_NR_ftime		35 /* remove */
+#define TARGET_NR_sync		36 /* ok */
+#define TARGET_NR_kill		37 /* ok */
+#define TARGET_NR_rename		38 /* renameat */
+#define TARGET_NR_mkdir		39 /* mkdirat */
+#define TARGET_NR_rmdir		40 /* unlinkat */
+#define TARGET_NR_dup		41 /* ok */
+#define TARGET_NR_pipe		42 /* ok */
+#define TARGET_NR_times		43 /* ok */
+#define TARGET_NR_prof		44 /* remove */
+#define TARGET_NR_brk		45 /* ok -mmu, nommu specific */
+#define TARGET_NR_setgid		46 /* ok */
+#define TARGET_NR_getgid		47 /* ok */
+#define TARGET_NR_signal		48 /* obsolete -> sys_rt_sigaction */
+#define TARGET_NR_geteuid		49 /* ok */
+#define TARGET_NR_getegid		50 /* ok */
+#define TARGET_NR_acct		51 /* add it and then I can disable it */
+#define TARGET_NR_umount2		52 /* remove */
+#define TARGET_NR_lock		53 /* remove */
+#define TARGET_NR_ioctl		54 /* ok */
+#define TARGET_NR_fcntl		55 /* ok -> 64bit version*/
+#define TARGET_NR_mpx		56 /* remove */
+#define TARGET_NR_setpgid		57 /* ok */
+#define TARGET_NR_ulimit		58 /* remove */
+#define TARGET_NR_oldolduname	59 /* remove */
+#define TARGET_NR_umask		60 /* ok */
+#define TARGET_NR_chroot		61 /* ok */
+#define TARGET_NR_ustat		62 /* obsolete -> statfs64 */
+#define TARGET_NR_dup2		63 /* ok */
+#define TARGET_NR_getppid		64 /* ok */
+#define TARGET_NR_getpgrp		65 /* obsolete -> sys_getpgid */
+#define TARGET_NR_setsid		66 /* ok */
+#define TARGET_NR_sigaction		67 /* obsolete -> rt_sigaction */
+#define TARGET_NR_sgetmask		68 /* obsolete -> sys_rt_sigprocmask */
+#define TARGET_NR_ssetmask		69 /* obsolete ->sys_rt_sigprocmask */
+#define TARGET_NR_setreuid		70 /* ok */
+#define TARGET_NR_setregid		71 /* ok */
+#define TARGET_NR_sigsuspend		72 /* obsolete -> rt_sigsuspend */
+#define TARGET_NR_sigpending		73 /* obsolete -> sys_rt_sigpending */
+#define TARGET_NR_sethostname	74 /* ok */
+#define TARGET_NR_setrlimit		75 /* ok */
+#define TARGET_NR_getrlimit		76 /* ok Back compatible 2Gig limited rlimit */
+#define TARGET_NR_getrusage		77 /* ok */
+#define TARGET_NR_gettimeofday	78 /* ok */
+#define TARGET_NR_settimeofday	79 /* ok */
+#define TARGET_NR_getgroups		80 /* ok */
+#define TARGET_NR_setgroups		81 /* ok */
+#define TARGET_NR_select		82 /* obsolete -> sys_pselect7 */
+#define TARGET_NR_symlink		83 /* symlinkat */
+#define TARGET_NR_oldlstat		84 /* remove */
+#define TARGET_NR_readlink		85 /* obsolete -> sys_readlinkat */
+#define TARGET_NR_uselib		86 /* remove */
+#define TARGET_NR_swapon		87 /* ok */
+#define TARGET_NR_reboot		88 /* ok */
+#define TARGET_NR_readdir		89 /* remove ? */
+#define TARGET_NR_mmap		90 /* obsolete -> sys_mmap2 */
+#define TARGET_NR_munmap		91 /* ok - mmu and nommu */
+#define TARGET_NR_truncate		92 /* ok or truncate64 */
+#define TARGET_NR_ftruncate		93 /* ok or ftruncate64 */
+#define TARGET_NR_fchmod		94 /* ok */
+#define TARGET_NR_fchown		95 /* ok */
+#define TARGET_NR_getpriority	96 /* ok */
+#define TARGET_NR_setpriority	97 /* ok */
+#define TARGET_NR_profil		98 /* remove */
+#define TARGET_NR_statfs		99 /* ok or statfs64 */
+#define TARGET_NR_fstatfs		100  /* ok or fstatfs64 */
+#define TARGET_NR_ioperm		101 /* remove */
+#define TARGET_NR_socketcall		102 /* remove */
+#define TARGET_NR_syslog		103 /* ok */
+#define TARGET_NR_setitimer		104 /* ok */
+#define TARGET_NR_getitimer		105 /* ok */
+#define TARGET_NR_stat		106 /* remove */
+#define TARGET_NR_lstat		107 /* remove */
+#define TARGET_NR_fstat		108 /* remove */
+#define TARGET_NR_olduname		109 /* remove */
+#define TARGET_NR_iopl		110 /* remove */
+#define TARGET_NR_vhangup		111 /* ok */
+#define TARGET_NR_idle		112 /* remove */
+#define TARGET_NR_vm86old		113 /* remove */
+#define TARGET_NR_wait4		114 /* obsolete -> waitid */
+#define TARGET_NR_swapoff		115 /* ok */
+#define TARGET_NR_sysinfo		116 /* ok */
+#define TARGET_NR_ipc		117 /* remove - direct call */
+#define TARGET_NR_fsync		118 /* ok */
+#define TARGET_NR_sigreturn		119 /* obsolete -> sys_rt_sigreturn */
+#define TARGET_NR_clone		120 /* ok */
+#define TARGET_NR_setdomainname	121 /* ok */
+#define TARGET_NR_uname		122 /* remove */
+#define TARGET_NR_modify_ldt		123 /* remove */
+#define TARGET_NR_adjtimex		124 /* ok */
+#define TARGET_NR_mprotect		125 /* remove */
+#define TARGET_NR_sigprocmask	126 /* obsolete -> sys_rt_sigprocmask */
+#define TARGET_NR_create_module	127 /* remove */
+#define TARGET_NR_init_module	128 /* ok */
+#define TARGET_NR_delete_module	129 /* ok */
+#define TARGET_NR_get_kernel_syms	130 /* remove */
+#define TARGET_NR_quotactl		131 /* ok */
+#define TARGET_NR_getpgid		132 /* ok */
+#define TARGET_NR_fchdir		133 /* ok */
+#define TARGET_NR_bdflush		134 /* remove */
+#define TARGET_NR_sysfs		135 /* needed for busybox */
+#define TARGET_NR_personality	136 /* ok */
+#define TARGET_NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid		138 /* ok */
+#define TARGET_NR_setfsgid		139 /* ok */
+#define TARGET_NR__llseek		140 /* remove only lseek */
+#define TARGET_NR_getdents		141 /* ok or getdents64 */
+#define TARGET_NR__newselect		142 /* remove */
+#define TARGET_NR_flock		143 /* ok */
+#define TARGET_NR_msync		144 /* remove */
+#define TARGET_NR_readv		145 /* ok */
+#define TARGET_NR_writev		146 /* ok */
+#define TARGET_NR_getsid		147 /* ok */
+#define TARGET_NR_fdatasync		148 /* ok */
+#define TARGET_NR__sysctl		149 /* remove */
+#define TARGET_NR_mlock		150 /* ok - nommu or mmu */
+#define TARGET_NR_munlock		151 /* ok - nommu or mmu */
+#define TARGET_NR_mlockall		152 /* ok - nommu or mmu */
+#define TARGET_NR_munlockall		153 /* ok - nommu or mmu */
+#define TARGET_NR_sched_setparam		154 /* ok */
+#define TARGET_NR_sched_getparam		155 /* ok */
+#define TARGET_NR_sched_setscheduler		156 /* ok */
+#define TARGET_NR_sched_getscheduler		157 /* ok */
+#define TARGET_NR_sched_yield		158 /* ok */
+#define TARGET_NR_sched_get_priority_max	159 /* ok */
+#define TARGET_NR_sched_get_priority_min	160 /* ok */
+#define TARGET_NR_sched_rr_get_interval	161 /* ok */
+#define TARGET_NR_nanosleep		162 /* ok */
+#define TARGET_NR_mremap		163 /* ok - nommu or mmu */
+#define TARGET_NR_setresuid		164 /* ok */
+#define TARGET_NR_getresuid		165 /* ok */
+#define TARGET_NR_vm86		166 /* remove */
+#define TARGET_NR_query_module	167 /* ok */
+#define TARGET_NR_poll		168 /* obsolete -> sys_ppoll */
+#define TARGET_NR_nfsservctl		169 /* ok */
+#define TARGET_NR_setresgid		170 /* ok */
+#define TARGET_NR_getresgid		171 /* ok */
+#define TARGET_NR_prctl		172 /* ok */
+#define TARGET_NR_rt_sigreturn	173 /* ok */
+#define TARGET_NR_rt_sigaction	174 /* ok */
+#define TARGET_NR_rt_sigprocmask	175 /* ok */
+#define TARGET_NR_rt_sigpending	176 /* ok */
+#define TARGET_NR_rt_sigtimedwait	177 /* ok */
+#define TARGET_NR_rt_sigqueueinfo	178 /* ok */
+#define TARGET_NR_rt_sigsuspend	179 /* ok */
+#define TARGET_NR_pread64		180 /* ok */
+#define TARGET_NR_pwrite64		181 /* ok */
+#define TARGET_NR_chown		182 /* obsolete -> fchownat */
+#define TARGET_NR_getcwd		183 /* ok */
+#define TARGET_NR_capget		184 /* ok */
+#define TARGET_NR_capset		185 /* ok */
+#define TARGET_NR_sigaltstack	186 /* remove */
+#define TARGET_NR_sendfile		187 /* ok -> exist 64bit version*/
+#define TARGET_NR_getpmsg		188 /* remove - some people actually want streams */
+#define TARGET_NR_putpmsg		189 /* remove - some people actually want streams */
+#define TARGET_NR_vfork		190 /* for noMMU - group with clone -> maybe remove */
+#define TARGET_NR_ugetrlimit		191 /* remove - SuS compliant getrlimit */
+#define TARGET_NR_mmap2		192 /* ok */
+#define TARGET_NR_truncate64		193 /* ok */
+#define TARGET_NR_ftruncate64	194 /* ok */
+#define TARGET_NR_stat64		195 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_lstat64		196 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_fstat64		197 /* remove _ARCH_WANT_STAT64 */
+#define TARGET_NR_lchown32		198 /* ok - without 32 */
+#define TARGET_NR_getuid32		199 /* ok - without 32 */
+#define TARGET_NR_getgid32		200 /* ok - without 32 */
+#define TARGET_NR_geteuid32		201 /* ok - without 32 */
+#define TARGET_NR_getegid32		202 /* ok - without 32 */
+#define TARGET_NR_setreuid32		203 /* ok - without 32 */
+#define TARGET_NR_setregid32		204 /* ok - without 32 */
+#define TARGET_NR_getgroups32	205 /* ok - without 32 */
+#define TARGET_NR_setgroups32	206 /* ok - without 32 */
+#define TARGET_NR_fchown32		207 /* ok - without 32 */
+#define TARGET_NR_setresuid32	208 /* ok - without 32 */
+#define TARGET_NR_getresuid32	209 /* ok - without 32 */
+#define TARGET_NR_setresgid32	210 /* ok - without 32 */
+#define TARGET_NR_getresgid32	211 /* ok - without 32 */
+#define TARGET_NR_chown32		212 /* ok - without 32 -obsolete -> fchownat */
+#define TARGET_NR_setuid32		213 /* ok - without 32 */
+#define TARGET_NR_setgid32		214 /* ok - without 32 */
+#define TARGET_NR_setfsuid32		215 /* ok - without 32 */
+#define TARGET_NR_setfsgid32		216 /* ok - without 32 */
+#define TARGET_NR_pivot_root		217 /* ok */
+#define TARGET_NR_mincore		218 /* ok */
+#define TARGET_NR_madvise		219 /* ok */
+//#define TARGET_NR_madvise1		219 /* remove delete when C lib stub is removed */
+#define TARGET_NR_getdents64		220 /* ok */
+#define TARGET_NR_fcntl64		221 /* ok */
+/* 223 is unused */
+#define TARGET_NR_gettid		224 /* ok */
+#define TARGET_NR_readahead		225 /* ok */
+#define TARGET_NR_setxattr		226 /* ok */
+#define TARGET_NR_lsetxattr		227 /* ok */
+#define TARGET_NR_fsetxattr		228 /* ok */
+#define TARGET_NR_getxattr		229 /* ok */
+#define TARGET_NR_lgetxattr		230 /* ok */
+#define TARGET_NR_fgetxattr		231 /* ok */
+#define TARGET_NR_listxattr		232 /* ok */
+#define TARGET_NR_llistxattr		233 /* ok */
+#define TARGET_NR_flistxattr		234 /* ok */
+#define TARGET_NR_removexattr	235 /* ok */
+#define TARGET_NR_lremovexattr	236 /* ok */
+#define TARGET_NR_fremovexattr	237 /* ok */
+#define TARGET_NR_tkill		238 /* ok */
+#define TARGET_NR_sendfile64		239 /* ok */
+#define TARGET_NR_futex		240 /* ok */
+#define TARGET_NR_sched_setaffinity	241 /* ok */
+#define TARGET_NR_sched_getaffinity	242 /* ok */
+#define TARGET_NR_set_thread_area	243 /* remove */
+#define TARGET_NR_get_thread_area	244 /* remove */
+#define TARGET_NR_io_setup		245 /* ok */
+#define TARGET_NR_io_destroy		246 /* ok */
+#define TARGET_NR_io_getevents	247 /* ok */
+#define TARGET_NR_io_submit		248 /* ok */
+#define TARGET_NR_io_cancel		249 /* ok */
+#define TARGET_NR_fadvise64		250 /* remove -> sys_fadvise64_64 */
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define TARGET_NR_exit_group		252 /* ok */
+#define TARGET_NR_lookup_dcookie	253 /* ok */
+#define TARGET_NR_epoll_create	254 /* ok */
+#define TARGET_NR_epoll_ctl		255 /* ok */
+#define TARGET_NR_epoll_wait		256 /* obsolete -> sys_epoll_pwait */
+#define TARGET_NR_remap_file_pages	257 /* only for mmu */
+#define TARGET_NR_set_tid_address	258 /* ok */
+#define TARGET_NR_timer_create	259 /* ok */
+#define TARGET_NR_timer_settime	(TARGET_NR_timer_create+1) /* 260 */ /* ok */
+#define TARGET_NR_timer_gettime	(TARGET_NR_timer_create+2) /* 261 */ /* ok */
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_timer_create+3) /* 262 */ /* ok */
+#define TARGET_NR_timer_delete	(TARGET_NR_timer_create+4) /* 263 */ /* ok */
+#define TARGET_NR_clock_settime	(TARGET_NR_timer_create+5) /* 264 */ /* ok */
+#define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6) /* 265 */ /* ok */
+#define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7) /* 266 */ /* ok */
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8) /* 267 */ /* ok */
+#define TARGET_NR_statfs64		268 /* ok */
+#define TARGET_NR_fstatfs64		269 /* ok */
+#define TARGET_NR_tgkill		270 /* ok */
+#define TARGET_NR_utimes		271 /* obsolete -> sys_futimesat */
+#define TARGET_NR_fadvise64_64	272 /* ok */
+#define TARGET_NR_vserver		273 /* ok */
+#define TARGET_NR_mbind		274 /* only for mmu */
+#define TARGET_NR_get_mempolicy	275 /* only for mmu */
+#define TARGET_NR_set_mempolicy	276 /* only for mmu */
+#define TARGET_NR_mq_open		277 /* ok */
+#define TARGET_NR_mq_unlink		(TARGET_NR_mq_open+1) /* 278 */ /* ok */
+#define TARGET_NR_mq_timedsend	(TARGET_NR_mq_open+2) /* 279 */ /* ok */
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_mq_open+3) /* 280 */ /* ok */
+#define TARGET_NR_mq_notify		(TARGET_NR_mq_open+4) /* 281 */ /* ok */
+#define TARGET_NR_mq_getsetattr	(TARGET_NR_mq_open+5) /* 282 */ /* ok */
+#define TARGET_NR_kexec_load		283 /* ok */
+#define TARGET_NR_waitid		284 /* ok */
+/* #define TARGET_NR_sys_setaltroot	285 */
+#define TARGET_NR_add_key		286 /* ok */
+#define TARGET_NR_request_key	287 /* ok */
+#define TARGET_NR_keyctl		288 /* ok */
+#define TARGET_NR_ioprio_set		289 /* ok */
+#define TARGET_NR_ioprio_get		290 /* ok */
+#define TARGET_NR_inotify_init	291 /* ok */
+#define TARGET_NR_inotify_add_watch	292 /* ok */
+#define TARGET_NR_inotify_rm_watch	293 /* ok */
+#define TARGET_NR_migrate_pages	294 /* mmu */
+#define TARGET_NR_openat		295 /* ok */
+#define TARGET_NR_mkdirat		296 /* ok */
+#define TARGET_NR_mknodat		297 /* ok */
+#define TARGET_NR_fchownat		298 /* ok */
+#define TARGET_NR_futimesat		299 /* obsolete -> sys_utimesat */
+#define TARGET_NR_fstatat64		300 /* stat64 */
+#define TARGET_NR_unlinkat		301 /* ok */
+#define TARGET_NR_renameat		302 /* ok */
+#define TARGET_NR_linkat		303 /* ok */
+#define TARGET_NR_symlinkat		304 /* ok */
+#define TARGET_NR_readlinkat		305 /* ok */
+#define TARGET_NR_fchmodat		306 /* ok */
+#define TARGET_NR_faccessat		307 /* ok */
+#define TARGET_NR_pselect6		308 /* obsolete -> sys_pselect7 */
+#define TARGET_NR_ppoll		309 /* ok */
+#define TARGET_NR_unshare		310 /* ok */
+#define TARGET_NR_set_robust_list	311 /* ok */
+#define TARGET_NR_get_robust_list	312 /* ok */
+#define TARGET_NR_splice		313 /* ok */
+#define TARGET_NR_sync_file_range	314 /* ok */
+#define TARGET_NR_tee		315 /* ok */
+#define TARGET_NR_vmsplice		316 /* ok */
+#define TARGET_NR_move_pages		317 /* mmu */
+#define TARGET_NR_getcpu		318 /* ok */
+#define TARGET_NR_epoll_pwait	319 /* ok */
+#define TARGET_NR_utimensat		320 /* ok */
+#define TARGET_NR_signalfd		321 /* ok */
+#define TARGET_NR_timerfd_create	322 /* ok */
+#define TARGET_NR_eventfd		323 /* ok */
+#define TARGET_NR_fallocate		324 /* ok */
+#define TARGET_NR_semtimedop		325 /* ok - semaphore group */
+#define TARGET_NR_timerfd_settime	326 /* ok */
+#define TARGET_NR_timerfd_gettime	327 /* ok */
+/* sysv ipc syscalls */
+#define TARGET_NR_semctl		328 /* ok */
+#define TARGET_NR_semget		329 /* ok */
+#define TARGET_NR_semop		330 /* ok */
+#define TARGET_NR_msgctl		331 /* ok */
+#define TARGET_NR_msgget		332 /* ok */
+#define TARGET_NR_msgrcv		333 /* ok */
+#define TARGET_NR_msgsnd		334 /* ok */
+#define TARGET_NR_shmat		335 /* ok */
+#define TARGET_NR_shmctl		336 /* ok */
+#define TARGET_NR_shmdt		337 /* ok */
+#define TARGET_NR_shmget		338 /* ok */
+
+
+#define TARGET_NR_signalfd4		339 /* new */
+#define TARGET_NR_eventfd2		340 /* new */
+#define TARGET_NR_epoll_create1	341 /* new */
+#define TARGET_NR_dup3		342 /* new */
+#define TARGET_NR_pipe2		343 /* new */
+#define TARGET_NR_inotify_init1	344 /* new */
+#define TARGET_NR_socket		345 /* new */
+#define TARGET_NR_socketpair		346 /* new */
+#define TARGET_NR_bind		347 /* new */
+#define TARGET_NR_listen		348 /* new */
+#define TARGET_NR_accept		349 /* new */
+#define TARGET_NR_connect		350 /* new */
+#define TARGET_NR_getsockname	351 /* new */
+#define TARGET_NR_getpeername	352 /* new */
+#define TARGET_NR_sendto		353 /* new */
+#define TARGET_NR_send		354 /* new */
+#define TARGET_NR_recvfrom		355 /* new */
+#define TARGET_NR_recv		356 /* new */
+#define TARGET_NR_setsockopt		357 /* new */
+#define TARGET_NR_getsockopt		358 /* new */
+#define TARGET_NR_shutdown		359 /* new */
+#define TARGET_NR_sendmsg		360 /* new */
+#define TARGET_NR_recvmsg		361 /* new */
+#define TARGET_NR_accept04		362 /* new */
+#define TARGET_NR_preadv                363 /* new */
+#define TARGET_NR_pwritev               364 /* new */
+#define TARGET_NR_rt_tgsigqueueinfo     365 /* new */
+#define TARGET_NR_perf_event_open       366 /* new */
+#define TARGET_NR_recvmmsg              367 /* new */
+#define TARGET_NR_fanotify_init         368
+#define TARGET_NR_fanotify_mark         369
+#define TARGET_NR_prlimit64             370
+#define TARGET_NR_name_to_handle_at     371
+#define TARGET_NR_open_by_handle_at     372
+#define TARGET_NR_clock_adjtime         373
+#define TARGET_NR_syncfs                374
+
diff --git a/qemu-0.15.x/linux-user/microblaze/target_signal.h b/qemu-0.15.x/linux-user/microblaze/target_signal.h
new file mode 100644
index 0000000..3d1f7a7
--- /dev/null
+++ b/qemu-0.15.x/linux-user/microblaze/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_ulong ss_size;
+	abi_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUMBState *state)
+{
+    return state->regs[14];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/microblaze/termbits.h b/qemu-0.15.x/linux-user/microblaze/termbits.h
new file mode 100644
index 0000000..fc82ca0
--- /dev/null
+++ b/qemu-0.15.x/linux-user/microblaze/termbits.h
@@ -0,0 +1,213 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CRTSCTS   020000000000          /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VTIME	5
+#define TARGET_VMIN	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+#define TARGET_VEOL	11
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOL2	16
+
+/* ioctls */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/linux-user/mips/syscall.h b/qemu-0.15.x/linux-user/mips/syscall.h
new file mode 100644
index 0000000..3deb862
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips/syscall.h
@@ -0,0 +1,227 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+	/* Pad bytes for argument save space on the stack. */
+	abi_ulong pad0[6];
+
+	/* Saved main processor registers. */
+	abi_ulong regs[32];
+
+	/* Saved special registers. */
+	abi_ulong cp0_status;
+	abi_ulong lo;
+	abi_ulong hi;
+	abi_ulong cp0_badvaddr;
+	abi_ulong cp0_cause;
+	abi_ulong cp0_epc;
+};
+
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
+/* Nasty hack: define a fake errno value for use by sigreturn.  */
+#define TARGET_QEMU_ESIGRETURN 255
+
+#define UNAME_MACHINE "mips"
diff --git a/qemu-0.15.x/linux-user/mips/syscall_nr.h b/qemu-0.15.x/linux-user/mips/syscall_nr.h
new file mode 100644
index 0000000..fbdc348
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips/syscall_nr.h
@@ -0,0 +1,347 @@
+/*
+ * Linux o32 style syscalls are in the range from 4000 to 4999.
+ */
+#define TARGET_NR_Linux			4000
+#define TARGET_NR_syscall		(TARGET_NR_Linux +   0)
+#define TARGET_NR_exit			(TARGET_NR_Linux +   1)
+#define TARGET_NR_fork			(TARGET_NR_Linux +   2)
+#define TARGET_NR_read			(TARGET_NR_Linux +   3)
+#define TARGET_NR_write			(TARGET_NR_Linux +   4)
+#define TARGET_NR_open			(TARGET_NR_Linux +   5)
+#define TARGET_NR_close			(TARGET_NR_Linux +   6)
+#define TARGET_NR_waitpid		(TARGET_NR_Linux +   7)
+#define TARGET_NR_creat			(TARGET_NR_Linux +   8)
+#define TARGET_NR_link			(TARGET_NR_Linux +   9)
+#define TARGET_NR_unlink		(TARGET_NR_Linux +  10)
+#define TARGET_NR_execve		(TARGET_NR_Linux +  11)
+#define TARGET_NR_chdir			(TARGET_NR_Linux +  12)
+#define TARGET_NR_time			(TARGET_NR_Linux +  13)
+#define TARGET_NR_mknod			(TARGET_NR_Linux +  14)
+#define TARGET_NR_chmod			(TARGET_NR_Linux +  15)
+#define TARGET_NR_lchown		(TARGET_NR_Linux +  16)
+#define TARGET_NR_break			(TARGET_NR_Linux +  17)
+#define TARGET_NR_unused18		(TARGET_NR_Linux +  18)
+#define TARGET_NR_lseek			(TARGET_NR_Linux +  19)
+#define TARGET_NR_getpid		(TARGET_NR_Linux +  20)
+#define TARGET_NR_mount			(TARGET_NR_Linux +  21)
+#define TARGET_NR_umount		(TARGET_NR_Linux +  22)
+#define TARGET_NR_setuid		(TARGET_NR_Linux +  23)
+#define TARGET_NR_getuid		(TARGET_NR_Linux +  24)
+#define TARGET_NR_stime			(TARGET_NR_Linux +  25)
+#define TARGET_NR_ptrace		(TARGET_NR_Linux +  26)
+#define TARGET_NR_alarm			(TARGET_NR_Linux +  27)
+#define TARGET_NR_unused28		(TARGET_NR_Linux +  28)
+#define TARGET_NR_pause			(TARGET_NR_Linux +  29)
+#define TARGET_NR_utime			(TARGET_NR_Linux +  30)
+#define TARGET_NR_stty			(TARGET_NR_Linux +  31)
+#define TARGET_NR_gtty			(TARGET_NR_Linux +  32)
+#define TARGET_NR_access		(TARGET_NR_Linux +  33)
+#define TARGET_NR_nice			(TARGET_NR_Linux +  34)
+#define TARGET_NR_ftime			(TARGET_NR_Linux +  35)
+#define TARGET_NR_sync			(TARGET_NR_Linux +  36)
+#define TARGET_NR_kill			(TARGET_NR_Linux +  37)
+#define TARGET_NR_rename		(TARGET_NR_Linux +  38)
+#define TARGET_NR_mkdir			(TARGET_NR_Linux +  39)
+#define TARGET_NR_rmdir			(TARGET_NR_Linux +  40)
+#define TARGET_NR_dup			(TARGET_NR_Linux +  41)
+#define TARGET_NR_pipe			(TARGET_NR_Linux +  42)
+#define TARGET_NR_times			(TARGET_NR_Linux +  43)
+#define TARGET_NR_prof			(TARGET_NR_Linux +  44)
+#define TARGET_NR_brk			(TARGET_NR_Linux +  45)
+#define TARGET_NR_setgid		(TARGET_NR_Linux +  46)
+#define TARGET_NR_getgid		(TARGET_NR_Linux +  47)
+#define TARGET_NR_signal		(TARGET_NR_Linux +  48)
+#define TARGET_NR_geteuid		(TARGET_NR_Linux +  49)
+#define TARGET_NR_getegid		(TARGET_NR_Linux +  50)
+#define TARGET_NR_acct			(TARGET_NR_Linux +  51)
+#define TARGET_NR_umount2		(TARGET_NR_Linux +  52)
+#define TARGET_NR_lock			(TARGET_NR_Linux +  53)
+#define TARGET_NR_ioctl			(TARGET_NR_Linux +  54)
+#define TARGET_NR_fcntl			(TARGET_NR_Linux +  55)
+#define TARGET_NR_mpx			(TARGET_NR_Linux +  56)
+#define TARGET_NR_setpgid		(TARGET_NR_Linux +  57)
+#define TARGET_NR_ulimit		(TARGET_NR_Linux +  58)
+#define TARGET_NR_unused59		(TARGET_NR_Linux +  59)
+#define TARGET_NR_umask			(TARGET_NR_Linux +  60)
+#define TARGET_NR_chroot		(TARGET_NR_Linux +  61)
+#define TARGET_NR_ustat			(TARGET_NR_Linux +  62)
+#define TARGET_NR_dup2			(TARGET_NR_Linux +  63)
+#define TARGET_NR_getppid		(TARGET_NR_Linux +  64)
+#define TARGET_NR_getpgrp		(TARGET_NR_Linux +  65)
+#define TARGET_NR_setsid		(TARGET_NR_Linux +  66)
+#define TARGET_NR_sigaction		(TARGET_NR_Linux +  67)
+#define TARGET_NR_sgetmask		(TARGET_NR_Linux +  68)
+#define TARGET_NR_ssetmask		(TARGET_NR_Linux +  69)
+#define TARGET_NR_setreuid		(TARGET_NR_Linux +  70)
+#define TARGET_NR_setregid		(TARGET_NR_Linux +  71)
+#define TARGET_NR_sigsuspend		(TARGET_NR_Linux +  72)
+#define TARGET_NR_sigpending		(TARGET_NR_Linux +  73)
+#define TARGET_NR_sethostname		(TARGET_NR_Linux +  74)
+#define TARGET_NR_setrlimit		(TARGET_NR_Linux +  75)
+#define TARGET_NR_getrlimit		(TARGET_NR_Linux +  76)
+#define TARGET_NR_getrusage		(TARGET_NR_Linux +  77)
+#define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  78)
+#define TARGET_NR_settimeofday		(TARGET_NR_Linux +  79)
+#define TARGET_NR_getgroups		(TARGET_NR_Linux +  80)
+#define TARGET_NR_setgroups		(TARGET_NR_Linux +  81)
+#define TARGET_NR_reserved82		(TARGET_NR_Linux +  82)
+#define TARGET_NR_symlink		(TARGET_NR_Linux +  83)
+#define TARGET_NR_unused84		(TARGET_NR_Linux +  84)
+#define TARGET_NR_readlink		(TARGET_NR_Linux +  85)
+#define TARGET_NR_uselib		(TARGET_NR_Linux +  86)
+#define TARGET_NR_swapon		(TARGET_NR_Linux +  87)
+#define TARGET_NR_reboot		(TARGET_NR_Linux +  88)
+#define TARGET_NR_readdir		(TARGET_NR_Linux +  89)
+#define TARGET_NR_mmap			(TARGET_NR_Linux +  90)
+#define TARGET_NR_munmap		(TARGET_NR_Linux +  91)
+#define TARGET_NR_truncate		(TARGET_NR_Linux +  92)
+#define TARGET_NR_ftruncate		(TARGET_NR_Linux +  93)
+#define TARGET_NR_fchmod		(TARGET_NR_Linux +  94)
+#define TARGET_NR_fchown		(TARGET_NR_Linux +  95)
+#define TARGET_NR_getpriority		(TARGET_NR_Linux +  96)
+#define TARGET_NR_setpriority		(TARGET_NR_Linux +  97)
+#define TARGET_NR_profil		(TARGET_NR_Linux +  98)
+#define TARGET_NR_statfs		(TARGET_NR_Linux +  99)
+#define TARGET_NR_fstatfs		(TARGET_NR_Linux + 100)
+#define TARGET_NR_ioperm		(TARGET_NR_Linux + 101)
+#define TARGET_NR_socketcall		(TARGET_NR_Linux + 102)
+#define TARGET_NR_syslog		(TARGET_NR_Linux + 103)
+#define TARGET_NR_setitimer		(TARGET_NR_Linux + 104)
+#define TARGET_NR_getitimer		(TARGET_NR_Linux + 105)
+#define TARGET_NR_stat			(TARGET_NR_Linux + 106)
+#define TARGET_NR_lstat			(TARGET_NR_Linux + 107)
+#define TARGET_NR_fstat			(TARGET_NR_Linux + 108)
+#define TARGET_NR_unused109		(TARGET_NR_Linux + 109)
+#define TARGET_NR_iopl			(TARGET_NR_Linux + 110)
+#define TARGET_NR_vhangup		(TARGET_NR_Linux + 111)
+#define TARGET_NR_idle			(TARGET_NR_Linux + 112)
+#define TARGET_NR_vm86			(TARGET_NR_Linux + 113)
+#define TARGET_NR_wait4			(TARGET_NR_Linux + 114)
+#define TARGET_NR_swapoff		(TARGET_NR_Linux + 115)
+#define TARGET_NR_sysinfo		(TARGET_NR_Linux + 116)
+#define TARGET_NR_ipc			(TARGET_NR_Linux + 117)
+#define TARGET_NR_fsync			(TARGET_NR_Linux + 118)
+#define TARGET_NR_sigreturn		(TARGET_NR_Linux + 119)
+#define TARGET_NR_clone			(TARGET_NR_Linux + 120)
+#define TARGET_NR_setdomainname		(TARGET_NR_Linux + 121)
+#define TARGET_NR_uname			(TARGET_NR_Linux + 122)
+#define TARGET_NR_modify_ldt		(TARGET_NR_Linux + 123)
+#define TARGET_NR_adjtimex		(TARGET_NR_Linux + 124)
+#define TARGET_NR_mprotect		(TARGET_NR_Linux + 125)
+#define TARGET_NR_sigprocmask		(TARGET_NR_Linux + 126)
+#define TARGET_NR_create_module		(TARGET_NR_Linux + 127)
+#define TARGET_NR_init_module		(TARGET_NR_Linux + 128)
+#define TARGET_NR_delete_module		(TARGET_NR_Linux + 129)
+#define TARGET_NR_get_kernel_syms	(TARGET_NR_Linux + 130)
+#define TARGET_NR_quotactl		(TARGET_NR_Linux + 131)
+#define TARGET_NR_getpgid		(TARGET_NR_Linux + 132)
+#define TARGET_NR_fchdir		(TARGET_NR_Linux + 133)
+#define TARGET_NR_bdflush		(TARGET_NR_Linux + 134)
+#define TARGET_NR_sysfs			(TARGET_NR_Linux + 135)
+#define TARGET_NR_personality		(TARGET_NR_Linux + 136)
+#define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 137) /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid		(TARGET_NR_Linux + 138)
+#define TARGET_NR_setfsgid		(TARGET_NR_Linux + 139)
+#define TARGET_NR__llseek		(TARGET_NR_Linux + 140)
+#define TARGET_NR_getdents		(TARGET_NR_Linux + 141)
+#define TARGET_NR__newselect		(TARGET_NR_Linux + 142)
+#define TARGET_NR_flock			(TARGET_NR_Linux + 143)
+#define TARGET_NR_msync			(TARGET_NR_Linux + 144)
+#define TARGET_NR_readv			(TARGET_NR_Linux + 145)
+#define TARGET_NR_writev		(TARGET_NR_Linux + 146)
+#define TARGET_NR_cacheflush		(TARGET_NR_Linux + 147)
+#define TARGET_NR_cachectl		(TARGET_NR_Linux + 148)
+#define TARGET_NR_sysmips		(TARGET_NR_Linux + 149)
+#define TARGET_NR_unused150		(TARGET_NR_Linux + 150)
+#define TARGET_NR_getsid		(TARGET_NR_Linux + 151)
+#define TARGET_NR_fdatasync		(TARGET_NR_Linux + 152)
+#define TARGET_NR__sysctl		(TARGET_NR_Linux + 153)
+#define TARGET_NR_mlock			(TARGET_NR_Linux + 154)
+#define TARGET_NR_munlock		(TARGET_NR_Linux + 155)
+#define TARGET_NR_mlockall		(TARGET_NR_Linux + 156)
+#define TARGET_NR_munlockall		(TARGET_NR_Linux + 157)
+#define TARGET_NR_sched_setparam	(TARGET_NR_Linux + 158)
+#define TARGET_NR_sched_getparam	(TARGET_NR_Linux + 159)
+#define TARGET_NR_sched_setscheduler	(TARGET_NR_Linux + 160)
+#define TARGET_NR_sched_getscheduler	(TARGET_NR_Linux + 161)
+#define TARGET_NR_sched_yield		(TARGET_NR_Linux + 162)
+#define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 163)
+#define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 164)
+#define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 165)
+#define TARGET_NR_nanosleep		(TARGET_NR_Linux + 166)
+#define TARGET_NR_mremap		(TARGET_NR_Linux + 167)
+#define TARGET_NR_accept		(TARGET_NR_Linux + 168)
+#define TARGET_NR_bind			(TARGET_NR_Linux + 169)
+#define TARGET_NR_connect		(TARGET_NR_Linux + 170)
+#define TARGET_NR_getpeername		(TARGET_NR_Linux + 171)
+#define TARGET_NR_getsockname		(TARGET_NR_Linux + 172)
+#define TARGET_NR_getsockopt		(TARGET_NR_Linux + 173)
+#define TARGET_NR_listen		(TARGET_NR_Linux + 174)
+#define TARGET_NR_recv			(TARGET_NR_Linux + 175)
+#define TARGET_NR_recvfrom		(TARGET_NR_Linux + 176)
+#define TARGET_NR_recvmsg		(TARGET_NR_Linux + 177)
+#define TARGET_NR_send			(TARGET_NR_Linux + 178)
+#define TARGET_NR_sendmsg		(TARGET_NR_Linux + 179)
+#define TARGET_NR_sendto		(TARGET_NR_Linux + 180)
+#define TARGET_NR_setsockopt		(TARGET_NR_Linux + 181)
+#define TARGET_NR_shutdown		(TARGET_NR_Linux + 182)
+#define TARGET_NR_socket		(TARGET_NR_Linux + 183)
+#define TARGET_NR_socketpair		(TARGET_NR_Linux + 184)
+#define TARGET_NR_setresuid		(TARGET_NR_Linux + 185)
+#define TARGET_NR_getresuid		(TARGET_NR_Linux + 186)
+#define TARGET_NR_query_module		(TARGET_NR_Linux + 187)
+#define TARGET_NR_poll			(TARGET_NR_Linux + 188)
+#define TARGET_NR_nfsservctl		(TARGET_NR_Linux + 189)
+#define TARGET_NR_setresgid		(TARGET_NR_Linux + 190)
+#define TARGET_NR_getresgid		(TARGET_NR_Linux + 191)
+#define TARGET_NR_prctl			(TARGET_NR_Linux + 192)
+#define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 193)
+#define TARGET_NR_rt_sigaction		(TARGET_NR_Linux + 194)
+#define TARGET_NR_rt_sigprocmask	(TARGET_NR_Linux + 195)
+#define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 196)
+#define TARGET_NR_rt_sigtimedwait	(TARGET_NR_Linux + 197)
+#define TARGET_NR_rt_sigqueueinfo	(TARGET_NR_Linux + 198)
+#define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 199)
+#define TARGET_NR_pread64		(TARGET_NR_Linux + 200)
+#define TARGET_NR_pwrite64		(TARGET_NR_Linux + 201)
+#define TARGET_NR_chown 		(TARGET_NR_Linux + 202)
+#define TARGET_NR_getcwd		(TARGET_NR_Linux + 203)
+#define TARGET_NR_capget		(TARGET_NR_Linux + 204)
+#define TARGET_NR_capset		(TARGET_NR_Linux + 205)
+#define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 206)
+#define TARGET_NR_sendfile		(TARGET_NR_Linux + 207)
+#define TARGET_NR_getpmsg		(TARGET_NR_Linux + 208)
+#define TARGET_NR_putpmsg		(TARGET_NR_Linux + 209)
+#define TARGET_NR_mmap2			(TARGET_NR_Linux + 210)
+#define TARGET_NR_truncate64		(TARGET_NR_Linux + 211)
+#define TARGET_NR_ftruncate64		(TARGET_NR_Linux + 212)
+#define TARGET_NR_stat64		(TARGET_NR_Linux + 213)
+#define TARGET_NR_lstat64		(TARGET_NR_Linux + 214)
+#define TARGET_NR_fstat64		(TARGET_NR_Linux + 215)
+#define TARGET_NR_pivot_root		(TARGET_NR_Linux + 216)
+#define TARGET_NR_mincore		(TARGET_NR_Linux + 217)
+#define TARGET_NR_madvise		(TARGET_NR_Linux + 218)
+#define TARGET_NR_getdents64		(TARGET_NR_Linux + 219)
+#define TARGET_NR_fcntl64		(TARGET_NR_Linux + 220)
+#define TARGET_NR_reserved221		(TARGET_NR_Linux + 221)
+#define TARGET_NR_gettid		(TARGET_NR_Linux + 222)
+#define TARGET_NR_readahead		(TARGET_NR_Linux + 223)
+#define TARGET_NR_setxattr		(TARGET_NR_Linux + 224)
+#define TARGET_NR_lsetxattr		(TARGET_NR_Linux + 225)
+#define TARGET_NR_fsetxattr		(TARGET_NR_Linux + 226)
+#define TARGET_NR_getxattr		(TARGET_NR_Linux + 227)
+#define TARGET_NR_lgetxattr		(TARGET_NR_Linux + 228)
+#define TARGET_NR_fgetxattr		(TARGET_NR_Linux + 229)
+#define TARGET_NR_listxattr		(TARGET_NR_Linux + 230)
+#define TARGET_NR_llistxattr		(TARGET_NR_Linux + 231)
+#define TARGET_NR_flistxattr		(TARGET_NR_Linux + 232)
+#define TARGET_NR_removexattr		(TARGET_NR_Linux + 233)
+#define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 234)
+#define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 235)
+#define TARGET_NR_tkill			(TARGET_NR_Linux + 236)
+#define TARGET_NR_sendfile64		(TARGET_NR_Linux + 237)
+#define TARGET_NR_futex			(TARGET_NR_Linux + 238)
+#define TARGET_NR_sched_setaffinity	(TARGET_NR_Linux + 239)
+#define TARGET_NR_sched_getaffinity	(TARGET_NR_Linux + 240)
+#define TARGET_NR_io_setup		(TARGET_NR_Linux + 241)
+#define TARGET_NR_io_destroy		(TARGET_NR_Linux + 242)
+#define TARGET_NR_io_getevents		(TARGET_NR_Linux + 243)
+#define TARGET_NR_io_submit		(TARGET_NR_Linux + 244)
+#define TARGET_NR_io_cancel		(TARGET_NR_Linux + 245)
+#define TARGET_NR_exit_group		(TARGET_NR_Linux + 246)
+#define TARGET_NR_lookup_dcookie	(TARGET_NR_Linux + 247)
+#define TARGET_NR_epoll_create		(TARGET_NR_Linux + 248)
+#define TARGET_NR_epoll_ctl		(TARGET_NR_Linux + 249)
+#define TARGET_NR_epoll_wait		(TARGET_NR_Linux + 250)
+#define TARGET_NR_remap_file_pages	(TARGET_NR_Linux + 251)
+#define TARGET_NR_set_tid_address	(TARGET_NR_Linux + 252)
+#define TARGET_NR_restart_syscall	(TARGET_NR_Linux + 253)
+#define TARGET_NR_fadvise64		(TARGET_NR_Linux + 254)
+#define TARGET_NR_statfs64		(TARGET_NR_Linux + 255)
+#define TARGET_NR_fstatfs64		(TARGET_NR_Linux + 256)
+#define TARGET_NR_timer_create		(TARGET_NR_Linux + 257)
+#define TARGET_NR_timer_settime		(TARGET_NR_Linux + 258)
+#define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 259)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_Linux + 260)
+#define TARGET_NR_timer_delete		(TARGET_NR_Linux + 261)
+#define TARGET_NR_clock_settime		(TARGET_NR_Linux + 262)
+#define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 263)
+#define TARGET_NR_clock_getres		(TARGET_NR_Linux + 264)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_Linux + 265)
+#define TARGET_NR_tgkill		(TARGET_NR_Linux + 266)
+#define TARGET_NR_utimes		(TARGET_NR_Linux + 267)
+#define TARGET_NR_mbind			(TARGET_NR_Linux + 268)
+#define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 269)
+#define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 270)
+#define TARGET_NR_mq_open		(TARGET_NR_Linux + 271)
+#define TARGET_NR_mq_unlink		(TARGET_NR_Linux + 272)
+#define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 273)
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_Linux + 274)
+#define TARGET_NR_mq_notify		(TARGET_NR_Linux + 275)
+#define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 276)
+#define TARGET_NR_vserver		(TARGET_NR_Linux + 277)
+#define TARGET_NR_waitid		(TARGET_NR_Linux + 278)
+/* #define TARGET_NR_sys_setaltroot	(TARGET_NR_Linux + 279) */
+#define TARGET_NR_add_key		(TARGET_NR_Linux + 280)
+#define TARGET_NR_request_key		(TARGET_NR_Linux + 281)
+#define TARGET_NR_keyctl		(TARGET_NR_Linux + 282)
+#define TARGET_NR_set_thread_area	(TARGET_NR_Linux + 283)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 284)
+#define TARGET_NR_inotify_add_watch	(TARGET_NR_Linux + 285)
+#define TARGET_NR_inotify_rm_watch	(TARGET_NR_Linux + 286)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 287)
+#define TARGET_NR_openat		(TARGET_NR_Linux + 288)
+#define TARGET_NR_mkdirat		(TARGET_NR_Linux + 289)
+#define TARGET_NR_mknodat		(TARGET_NR_Linux + 290)
+#define TARGET_NR_fchownat		(TARGET_NR_Linux + 291)
+#define TARGET_NR_futimesat		(TARGET_NR_Linux + 292)
+#define TARGET_NR_fstatat64		(TARGET_NR_Linux + 293)
+#define TARGET_NR_unlinkat		(TARGET_NR_Linux + 294)
+#define TARGET_NR_renameat		(TARGET_NR_Linux + 295)
+#define TARGET_NR_linkat		(TARGET_NR_Linux + 296)
+#define TARGET_NR_symlinkat		(TARGET_NR_Linux + 297)
+#define TARGET_NR_readlinkat		(TARGET_NR_Linux + 298)
+#define TARGET_NR_fchmodat		(TARGET_NR_Linux + 299)
+#define TARGET_NR_faccessat		(TARGET_NR_Linux + 300)
+#define TARGET_NR_pselect6		(TARGET_NR_Linux + 301)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 302)
+#define TARGET_NR_unshare		(TARGET_NR_Linux + 303)
+#define TARGET_NR_splice		(TARGET_NR_Linux + 304)
+#define TARGET_NR_sync_file_range	(TARGET_NR_Linux + 305)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 306)
+#define TARGET_NR_vmsplice		(TARGET_NR_Linux + 307)
+#define TARGET_NR_move_pages		(TARGET_NR_Linux + 308)
+#define TARGET_NR_set_robust_list	(TARGET_NR_Linux + 309)
+#define TARGET_NR_get_robust_list	(TARGET_NR_Linux + 310)
+#define TARGET_NR_kexec_load		(TARGET_NR_Linux + 311)
+#define TARGET_NR_getcpu		(TARGET_NR_Linux + 312)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 313)
+#define TARGET_NR_ioprio_set		(TARGET_NR_Linux + 314)
+#define TARGET_NR_ioprio_get		(TARGET_NR_Linux + 315)
+#define TARGET_NR_utimensat		(TARGET_NR_Linux + 316)
+#define TARGET_NR_signalfd		(TARGET_NR_Linux + 317)
+#define TARGET_NR_timerfd		(TARGET_NR_Linux + 318)
+#define TARGET_NR_eventfd		(TARGET_NR_Linux + 319)
+#define TARGET_NR_fallocate		(TARGET_NR_Linux + 320)
+#define TARGET_NR_timerfd_create	(TARGET_NR_Linux + 321)
+#define TARGET_NR_timerfd_gettime	(TARGET_NR_Linux + 322)
+#define TARGET_NR_timerfd_settime	(TARGET_NR_Linux + 323)
+#define TARGET_NR_signalfd4		(TARGET_NR_Linux + 324)
+#define TARGET_NR_eventfd2		(TARGET_NR_Linux + 325)
+#define TARGET_NR_epoll_create1	(TARGET_NR_Linux + 326)
+#define TARGET_NR_dup3			(TARGET_NR_Linux + 327)
+#define TARGET_NR_pipe2		(TARGET_NR_Linux + 328)
+#define TARGET_NR_inotify_init1	(TARGET_NR_Linux + 329)
+#define TARGET_NR_preadv                (TARGET_NR_Linux + 330)
+#define TARGET_NR_pwritev               (TARGET_NR_Linux + 331)
+#define TARGET_NR_rt_tgsigqueueinfo     (TARGET_NR_Linux + 332)
+#define TARGET_NR_perf_event_open       (TARGET_NR_Linux + 333)
+#define TARGET_NR_accept4               (TARGET_NR_Linux + 334)
+#define TARGET_NR_recvmmsg              (TARGET_NR_Linux + 335)
+#define TARGET_NR_fanotify_init         (TARGET_NR_Linux + 336)
+#define TARGET_NR_fanotify_mark         (TARGET_NR_Linux + 337)
+#define TARGET_NR_prlimit64             (TARGET_NR_Linux + 338)
+#define TARGET_NR_name_to_handle_at     (TARGET_NR_Linux + 339)
+#define TARGET_NR_open_by_handle_at     (TARGET_NR_Linux + 340)
+#define TARGET_NR_clock_adjtime         (TARGET_NR_Linux + 341)
+#define TARGET_NR_syncfs                (TARGET_NR_Linux + 342)
diff --git a/qemu-0.15.x/linux-user/mips/target_signal.h b/qemu-0.15.x/linux-user/mips/target_signal.h
new file mode 100644
index 0000000..6e1dc8b
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_long ss_sp;
+	abi_ulong ss_size;
+	abi_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/mips/termbits.h b/qemu-0.15.x/linux-user/mips/termbits.h
new file mode 100644
index 0000000..d3a6cf8
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips/termbits.h
@@ -0,0 +1,245 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 23
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_IEXTEN  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VMIN	4
+#define TARGET_VTIME	5
+#define TARGET_VEOL2	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+/* VDSUSP not supported */
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
+
+/* ioctls */
+
+#define TARGET_TCGETA		0x5401
+#define TARGET_TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TARGET_TCSETAW		0x5403
+#define TARGET_TCSETAF		0x5404
+
+#define TARGET_TCSBRK		0x5405
+#define TARGET_TCXONC		0x5406
+#define TARGET_TCFLSH		0x5407
+
+#define TARGET_TCGETS		0x540d
+#define TARGET_TCSETS		0x540e
+#define TARGET_TCSETSW		0x540f
+#define TARGET_TCSETSF		0x5410
+
+#define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
+#define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
+#define TARGET_TIOCOUTQ	0x7472		/* output queue size */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
+#define TARGET_TIOCMGET	0x741d		/* get all modem bits */
+#define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
+#define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
+#define TARGET_TIOCMSET	0x741a		/* set all modem bits */
+#define TARGET_TIOCPKT		0x5470		/* pty: set/clear packet mode */
+#define	 TARGET_TIOCPKT_DATA		0x00	/* data packet */
+#define	 TARGET_TIOCPKT_FLUSHREAD	0x01	/* flush packet */
+#define	 TARGET_TIOCPKT_FLUSHWRITE	0x02	/* flush packet */
+#define	 TARGET_TIOCPKT_STOP		0x04	/* stop output */
+#define	 TARGET_TIOCPKT_START		0x08	/* start output */
+#define	 TARGET_TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+#define	 TARGET_TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
+/* #define  TIOCPKT_IOCTL		0x40	state change of pty driver */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)	/* set window size */
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)	/* get window size */
+#define TARGET_TIOCNOTTY	0x5471		/* void tty association */
+#define TARGET_TIOCSETD	0x7401
+#define TARGET_TIOCGETD	0x7400
+
+#define TARGET_FIOCLEX		0x6601
+#define TARGET_FIONCLEX	0x6602
+#define TARGET_FIOASYNC	0x667d
+#define TARGET_FIONBIO		0x667e
+#define TARGET_FIOQSIZE	0x667f
+
+#define TARGET_TIOCGLTC	0x7474			/* get special local chars */
+#define TARGET_TIOCSLTC	0x7475			/* set special local chars */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)	/* set pgrp of tty */
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)	/* get pgrp of tty */
+#define TARGET_TIOCCONS	TARGET_IOW('t', 120, int)	/* become virtual console */
+
+#define TARGET_FIONREAD	0x467f
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+#define TARGET_TIOCGETP        0x7408
+#define TARGET_TIOCSETP        0x7409
+#define TARGET_TIOCSETN        0x740a			/* TIOCSETP wo flush */
+
+/* #define TARGET_TIOCSETA	TARGET_IOW('t', 20, struct termios) set termios struct */
+/* #define TARGET_TIOCSETAW	TARGET_IOW('t', 21, struct termios) drain output, set */
+/* #define TARGET_TIOCSETAF	TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
+/* #define TARGET_TIOCGETD	TARGET_IOR('t', 26, int)	get line discipline */
+/* #define TARGET_TIOCSETD	TARGET_IOW('t', 27, int)	set line discipline */
+						/* 127-124 compat */
+
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x7416  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+/* I hope the range from 0x5480 on is free ... */
+#define TARGET_TIOCSCTTY	0x5480		/* become controlling tty */
+#define TARGET_TIOCGSOFTCAR	0x5481
+#define TARGET_TIOCSSOFTCAR	0x5482
+#define TARGET_TIOCLINUX	0x5483
+#define TARGET_TIOCGSERIAL	0x5484
+#define TARGET_TIOCSSERIAL	0x5485
+#define TARGET_TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSERCONFIG	0x5488
+#define TARGET_TIOCSERGWILD	0x5489
+#define TARGET_TIOCSERSWILD	0x548a
+#define TARGET_TIOCGLCKTRMIOS	0x548b
+#define TARGET_TIOCSLCKTRMIOS	0x548c
+#define TARGET_TIOCSERGSTRUCT	0x548d /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x548e /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
+#define TARGET_TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x5493 /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x5494 /* Set Hayes ESP configuration */
diff --git a/qemu-0.15.x/linux-user/mips64/syscall.h b/qemu-0.15.x/linux-user/mips64/syscall.h
new file mode 100644
index 0000000..668a2b9
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips64/syscall.h
@@ -0,0 +1,221 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+	/* Saved main processor registers. */
+	abi_ulong regs[32];
+
+	/* Saved special registers. */
+	abi_ulong cp0_status;
+	abi_ulong lo;
+	abi_ulong hi;
+	abi_ulong cp0_badvaddr;
+	abi_ulong cp0_cause;
+	abi_ulong cp0_epc;
+};
+
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
+#define UNAME_MACHINE "mips64"
diff --git a/qemu-0.15.x/linux-user/mips64/syscall_nr.h b/qemu-0.15.x/linux-user/mips64/syscall_nr.h
new file mode 100644
index 0000000..36d27b5
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips64/syscall_nr.h
@@ -0,0 +1,306 @@
+/*
+ * Linux 64-bit syscalls are in the range from 5000 to 5999.
+ */
+#define TARGET_NR_Linux			5000
+#define TARGET_NR_read			(TARGET_NR_Linux +   0)
+#define TARGET_NR_write			(TARGET_NR_Linux +   1)
+#define TARGET_NR_open			(TARGET_NR_Linux +   2)
+#define TARGET_NR_close			(TARGET_NR_Linux +   3)
+#define TARGET_NR_stat			(TARGET_NR_Linux +   4)
+#define TARGET_NR_fstat			(TARGET_NR_Linux +   5)
+#define TARGET_NR_lstat			(TARGET_NR_Linux +   6)
+#define TARGET_NR_poll			(TARGET_NR_Linux +   7)
+#define TARGET_NR_lseek			(TARGET_NR_Linux +   8)
+#define TARGET_NR_mmap			(TARGET_NR_Linux +   9)
+#define TARGET_NR_mprotect			(TARGET_NR_Linux +  10)
+#define TARGET_NR_munmap			(TARGET_NR_Linux +  11)
+#define TARGET_NR_brk			(TARGET_NR_Linux +  12)
+#define TARGET_NR_rt_sigaction		(TARGET_NR_Linux +  13)
+#define TARGET_NR_rt_sigprocmask		(TARGET_NR_Linux +  14)
+#define TARGET_NR_ioctl			(TARGET_NR_Linux +  15)
+#define TARGET_NR_pread64			(TARGET_NR_Linux +  16)
+#define TARGET_NR_pwrite64			(TARGET_NR_Linux +  17)
+#define TARGET_NR_readv			(TARGET_NR_Linux +  18)
+#define TARGET_NR_writev			(TARGET_NR_Linux +  19)
+#define TARGET_NR_access			(TARGET_NR_Linux +  20)
+#define TARGET_NR_pipe			(TARGET_NR_Linux +  21)
+#define TARGET_NR__newselect			(TARGET_NR_Linux +  22)
+#define TARGET_NR_sched_yield		(TARGET_NR_Linux +  23)
+#define TARGET_NR_mremap			(TARGET_NR_Linux +  24)
+#define TARGET_NR_msync			(TARGET_NR_Linux +  25)
+#define TARGET_NR_mincore			(TARGET_NR_Linux +  26)
+#define TARGET_NR_madvise			(TARGET_NR_Linux +  27)
+#define TARGET_NR_shmget			(TARGET_NR_Linux +  28)
+#define TARGET_NR_shmat			(TARGET_NR_Linux +  29)
+#define TARGET_NR_shmctl			(TARGET_NR_Linux +  30)
+#define TARGET_NR_dup			(TARGET_NR_Linux +  31)
+#define TARGET_NR_dup2			(TARGET_NR_Linux +  32)
+#define TARGET_NR_pause			(TARGET_NR_Linux +  33)
+#define TARGET_NR_nanosleep			(TARGET_NR_Linux +  34)
+#define TARGET_NR_getitimer			(TARGET_NR_Linux +  35)
+#define TARGET_NR_setitimer			(TARGET_NR_Linux +  36)
+#define TARGET_NR_alarm			(TARGET_NR_Linux +  37)
+#define TARGET_NR_getpid			(TARGET_NR_Linux +  38)
+#define TARGET_NR_sendfile			(TARGET_NR_Linux +  39)
+#define TARGET_NR_socket			(TARGET_NR_Linux +  40)
+#define TARGET_NR_connect			(TARGET_NR_Linux +  41)
+#define TARGET_NR_accept			(TARGET_NR_Linux +  42)
+#define TARGET_NR_sendto			(TARGET_NR_Linux +  43)
+#define TARGET_NR_recvfrom			(TARGET_NR_Linux +  44)
+#define TARGET_NR_sendmsg			(TARGET_NR_Linux +  45)
+#define TARGET_NR_recvmsg			(TARGET_NR_Linux +  46)
+#define TARGET_NR_shutdown			(TARGET_NR_Linux +  47)
+#define TARGET_NR_bind			(TARGET_NR_Linux +  48)
+#define TARGET_NR_listen			(TARGET_NR_Linux +  49)
+#define TARGET_NR_getsockname		(TARGET_NR_Linux +  50)
+#define TARGET_NR_getpeername		(TARGET_NR_Linux +  51)
+#define TARGET_NR_socketpair			(TARGET_NR_Linux +  52)
+#define TARGET_NR_setsockopt			(TARGET_NR_Linux +  53)
+#define TARGET_NR_getsockopt			(TARGET_NR_Linux +  54)
+#define TARGET_NR_clone			(TARGET_NR_Linux +  55)
+#define TARGET_NR_fork			(TARGET_NR_Linux +  56)
+#define TARGET_NR_execve			(TARGET_NR_Linux +  57)
+#define TARGET_NR_exit			(TARGET_NR_Linux +  58)
+#define TARGET_NR_wait4			(TARGET_NR_Linux +  59)
+#define TARGET_NR_kill			(TARGET_NR_Linux +  60)
+#define TARGET_NR_uname			(TARGET_NR_Linux +  61)
+#define TARGET_NR_semget			(TARGET_NR_Linux +  62)
+#define TARGET_NR_semop			(TARGET_NR_Linux +  63)
+#define TARGET_NR_semctl			(TARGET_NR_Linux +  64)
+#define TARGET_NR_shmdt			(TARGET_NR_Linux +  65)
+#define TARGET_NR_msgget			(TARGET_NR_Linux +  66)
+#define TARGET_NR_msgsnd			(TARGET_NR_Linux +  67)
+#define TARGET_NR_msgrcv			(TARGET_NR_Linux +  68)
+#define TARGET_NR_msgctl			(TARGET_NR_Linux +  69)
+#define TARGET_NR_fcntl			(TARGET_NR_Linux +  70)
+#define TARGET_NR_flock			(TARGET_NR_Linux +  71)
+#define TARGET_NR_fsync			(TARGET_NR_Linux +  72)
+#define TARGET_NR_fdatasync			(TARGET_NR_Linux +  73)
+#define TARGET_NR_truncate			(TARGET_NR_Linux +  74)
+#define TARGET_NR_ftruncate			(TARGET_NR_Linux +  75)
+#define TARGET_NR_getdents			(TARGET_NR_Linux +  76)
+#define TARGET_NR_getcwd			(TARGET_NR_Linux +  77)
+#define TARGET_NR_chdir			(TARGET_NR_Linux +  78)
+#define TARGET_NR_fchdir			(TARGET_NR_Linux +  79)
+#define TARGET_NR_rename			(TARGET_NR_Linux +  80)
+#define TARGET_NR_mkdir			(TARGET_NR_Linux +  81)
+#define TARGET_NR_rmdir			(TARGET_NR_Linux +  82)
+#define TARGET_NR_creat			(TARGET_NR_Linux +  83)
+#define TARGET_NR_link			(TARGET_NR_Linux +  84)
+#define TARGET_NR_unlink			(TARGET_NR_Linux +  85)
+#define TARGET_NR_symlink			(TARGET_NR_Linux +  86)
+#define TARGET_NR_readlink			(TARGET_NR_Linux +  87)
+#define TARGET_NR_chmod			(TARGET_NR_Linux +  88)
+#define TARGET_NR_fchmod			(TARGET_NR_Linux +  89)
+#define TARGET_NR_chown			(TARGET_NR_Linux +  90)
+#define TARGET_NR_fchown			(TARGET_NR_Linux +  91)
+#define TARGET_NR_lchown			(TARGET_NR_Linux +  92)
+#define TARGET_NR_umask			(TARGET_NR_Linux +  93)
+#define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  94)
+#define TARGET_NR_getrlimit			(TARGET_NR_Linux +  95)
+#define TARGET_NR_getrusage			(TARGET_NR_Linux +  96)
+#define TARGET_NR_sysinfo			(TARGET_NR_Linux +  97)
+#define TARGET_NR_times			(TARGET_NR_Linux +  98)
+#define TARGET_NR_ptrace			(TARGET_NR_Linux +  99)
+#define TARGET_NR_getuid			(TARGET_NR_Linux + 100)
+#define TARGET_NR_syslog			(TARGET_NR_Linux + 101)
+#define TARGET_NR_getgid			(TARGET_NR_Linux + 102)
+#define TARGET_NR_setuid			(TARGET_NR_Linux + 103)
+#define TARGET_NR_setgid			(TARGET_NR_Linux + 104)
+#define TARGET_NR_geteuid			(TARGET_NR_Linux + 105)
+#define TARGET_NR_getegid			(TARGET_NR_Linux + 106)
+#define TARGET_NR_setpgid			(TARGET_NR_Linux + 107)
+#define TARGET_NR_getppid			(TARGET_NR_Linux + 108)
+#define TARGET_NR_getpgrp			(TARGET_NR_Linux + 109)
+#define TARGET_NR_setsid			(TARGET_NR_Linux + 110)
+#define TARGET_NR_setreuid			(TARGET_NR_Linux + 111)
+#define TARGET_NR_setregid			(TARGET_NR_Linux + 112)
+#define TARGET_NR_getgroups			(TARGET_NR_Linux + 113)
+#define TARGET_NR_setgroups			(TARGET_NR_Linux + 114)
+#define TARGET_NR_setresuid			(TARGET_NR_Linux + 115)
+#define TARGET_NR_getresuid			(TARGET_NR_Linux + 116)
+#define TARGET_NR_setresgid			(TARGET_NR_Linux + 117)
+#define TARGET_NR_getresgid			(TARGET_NR_Linux + 118)
+#define TARGET_NR_getpgid			(TARGET_NR_Linux + 119)
+#define TARGET_NR_setfsuid			(TARGET_NR_Linux + 120)
+#define TARGET_NR_setfsgid			(TARGET_NR_Linux + 121)
+#define TARGET_NR_getsid			(TARGET_NR_Linux + 122)
+#define TARGET_NR_capget			(TARGET_NR_Linux + 123)
+#define TARGET_NR_capset			(TARGET_NR_Linux + 124)
+#define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 125)
+#define TARGET_NR_rt_sigtimedwait		(TARGET_NR_Linux + 126)
+#define TARGET_NR_rt_sigqueueinfo		(TARGET_NR_Linux + 127)
+#define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 128)
+#define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 129)
+#define TARGET_NR_utime			(TARGET_NR_Linux + 130)
+#define TARGET_NR_mknod			(TARGET_NR_Linux + 131)
+#define TARGET_NR_personality		(TARGET_NR_Linux + 132)
+#define TARGET_NR_ustat			(TARGET_NR_Linux + 133)
+#define TARGET_NR_statfs			(TARGET_NR_Linux + 134)
+#define TARGET_NR_fstatfs			(TARGET_NR_Linux + 135)
+#define TARGET_NR_sysfs			(TARGET_NR_Linux + 136)
+#define TARGET_NR_getpriority		(TARGET_NR_Linux + 137)
+#define TARGET_NR_setpriority		(TARGET_NR_Linux + 138)
+#define TARGET_NR_sched_setparam		(TARGET_NR_Linux + 139)
+#define TARGET_NR_sched_getparam		(TARGET_NR_Linux + 140)
+#define TARGET_NR_sched_setscheduler		(TARGET_NR_Linux + 141)
+#define TARGET_NR_sched_getscheduler		(TARGET_NR_Linux + 142)
+#define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 143)
+#define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 144)
+#define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 145)
+#define TARGET_NR_mlock			(TARGET_NR_Linux + 146)
+#define TARGET_NR_munlock			(TARGET_NR_Linux + 147)
+#define TARGET_NR_mlockall			(TARGET_NR_Linux + 148)
+#define TARGET_NR_munlockall			(TARGET_NR_Linux + 149)
+#define TARGET_NR_vhangup			(TARGET_NR_Linux + 150)
+#define TARGET_NR_pivot_root			(TARGET_NR_Linux + 151)
+#define TARGET_NR__sysctl			(TARGET_NR_Linux + 152)
+#define TARGET_NR_prctl			(TARGET_NR_Linux + 153)
+#define TARGET_NR_adjtimex			(TARGET_NR_Linux + 154)
+#define TARGET_NR_setrlimit			(TARGET_NR_Linux + 155)
+#define TARGET_NR_chroot			(TARGET_NR_Linux + 156)
+#define TARGET_NR_sync			(TARGET_NR_Linux + 157)
+#define TARGET_NR_acct			(TARGET_NR_Linux + 158)
+#define TARGET_NR_settimeofday		(TARGET_NR_Linux + 159)
+#define TARGET_NR_mount			(TARGET_NR_Linux + 160)
+#define TARGET_NR_umount2			(TARGET_NR_Linux + 161)
+#define TARGET_NR_swapon			(TARGET_NR_Linux + 162)
+#define TARGET_NR_swapoff			(TARGET_NR_Linux + 163)
+#define TARGET_NR_reboot			(TARGET_NR_Linux + 164)
+#define TARGET_NR_sethostname		(TARGET_NR_Linux + 165)
+#define TARGET_NR_setdomainname		(TARGET_NR_Linux + 166)
+#define TARGET_NR_create_module		(TARGET_NR_Linux + 167)
+#define TARGET_NR_init_module		(TARGET_NR_Linux + 168)
+#define TARGET_NR_delete_module		(TARGET_NR_Linux + 169)
+#define TARGET_NR_get_kernel_syms		(TARGET_NR_Linux + 170)
+#define TARGET_NR_query_module		(TARGET_NR_Linux + 171)
+#define TARGET_NR_quotactl			(TARGET_NR_Linux + 172)
+#define TARGET_NR_nfsservctl			(TARGET_NR_Linux + 173)
+#define TARGET_NR_getpmsg			(TARGET_NR_Linux + 174)
+#define TARGET_NR_putpmsg			(TARGET_NR_Linux + 175)
+#define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 176)
+#define TARGET_NR_reserved177		(TARGET_NR_Linux + 177)
+#define TARGET_NR_gettid			(TARGET_NR_Linux + 178)
+#define TARGET_NR_readahead			(TARGET_NR_Linux + 179)
+#define TARGET_NR_setxattr			(TARGET_NR_Linux + 180)
+#define TARGET_NR_lsetxattr			(TARGET_NR_Linux + 181)
+#define TARGET_NR_fsetxattr			(TARGET_NR_Linux + 182)
+#define TARGET_NR_getxattr			(TARGET_NR_Linux + 183)
+#define TARGET_NR_lgetxattr			(TARGET_NR_Linux + 184)
+#define TARGET_NR_fgetxattr			(TARGET_NR_Linux + 185)
+#define TARGET_NR_listxattr			(TARGET_NR_Linux + 186)
+#define TARGET_NR_llistxattr			(TARGET_NR_Linux + 187)
+#define TARGET_NR_flistxattr			(TARGET_NR_Linux + 188)
+#define TARGET_NR_removexattr		(TARGET_NR_Linux + 189)
+#define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 190)
+#define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 191)
+#define TARGET_NR_tkill			(TARGET_NR_Linux + 192)
+#define TARGET_NR_reserved193		(TARGET_NR_Linux + 193)
+#define TARGET_NR_futex			(TARGET_NR_Linux + 194)
+#define TARGET_NR_sched_setaffinity		(TARGET_NR_Linux + 195)
+#define TARGET_NR_sched_getaffinity		(TARGET_NR_Linux + 196)
+#define TARGET_NR_cacheflush			(TARGET_NR_Linux + 197)
+#define TARGET_NR_cachectl			(TARGET_NR_Linux + 198)
+#define TARGET_NR_sysmips			(TARGET_NR_Linux + 199)
+#define TARGET_NR_io_setup			(TARGET_NR_Linux + 200)
+#define TARGET_NR_io_destroy			(TARGET_NR_Linux + 201)
+#define TARGET_NR_io_getevents		(TARGET_NR_Linux + 202)
+#define TARGET_NR_io_submit			(TARGET_NR_Linux + 203)
+#define TARGET_NR_io_cancel			(TARGET_NR_Linux + 204)
+#define TARGET_NR_exit_group			(TARGET_NR_Linux + 205)
+#define TARGET_NR_lookup_dcookie		(TARGET_NR_Linux + 206)
+#define TARGET_NR_epoll_create		(TARGET_NR_Linux + 207)
+#define TARGET_NR_epoll_ctl			(TARGET_NR_Linux + 208)
+#define TARGET_NR_epoll_wait			(TARGET_NR_Linux + 209)
+#define TARGET_NR_remap_file_pages		(TARGET_NR_Linux + 210)
+#define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 211)
+#define TARGET_NR_set_tid_address		(TARGET_NR_Linux + 212)
+#define TARGET_NR_restart_syscall		(TARGET_NR_Linux + 213)
+#define TARGET_NR_semtimedop			(TARGET_NR_Linux + 214)
+#define TARGET_NR_fadvise64			(TARGET_NR_Linux + 215)
+#define TARGET_NR_timer_create		(TARGET_NR_Linux + 216)
+#define TARGET_NR_timer_settime		(TARGET_NR_Linux + 217)
+#define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 218)
+#define TARGET_NR_timer_getoverrun		(TARGET_NR_Linux + 219)
+#define TARGET_NR_timer_delete		(TARGET_NR_Linux + 220)
+#define TARGET_NR_clock_settime		(TARGET_NR_Linux + 221)
+#define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 222)
+#define TARGET_NR_clock_getres		(TARGET_NR_Linux + 223)
+#define TARGET_NR_clock_nanosleep		(TARGET_NR_Linux + 224)
+#define TARGET_NR_tgkill			(TARGET_NR_Linux + 225)
+#define TARGET_NR_utimes			(TARGET_NR_Linux + 226)
+#define TARGET_NR_mbind			(TARGET_NR_Linux + 227)
+#define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 228)
+#define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 229)
+#define TARGET_NR_mq_open			(TARGET_NR_Linux + 230)
+#define TARGET_NR_mq_unlink			(TARGET_NR_Linux + 231)
+#define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 232)
+#define TARGET_NR_mq_timedreceive		(TARGET_NR_Linux + 233)
+#define TARGET_NR_mq_notify			(TARGET_NR_Linux + 234)
+#define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 235)
+#define TARGET_NR_vserver			(TARGET_NR_Linux + 236)
+#define TARGET_NR_waitid			(TARGET_NR_Linux + 237)
+/* #define TARGET_NR_sys_setaltroot		(TARGET_NR_Linux + 238) */
+#define TARGET_NR_add_key			(TARGET_NR_Linux + 239)
+#define TARGET_NR_request_key		(TARGET_NR_Linux + 240)
+#define TARGET_NR_keyctl			(TARGET_NR_Linux + 241)
+#define TARGET_NR_set_thread_area		(TARGET_NR_Linux + 242)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 243)
+#define TARGET_NR_inotify_add_watch		(TARGET_NR_Linux + 244)
+#define TARGET_NR_inotify_rm_watch		(TARGET_NR_Linux + 245)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 246)
+#define TARGET_NR_openat			(TARGET_NR_Linux + 247)
+#define TARGET_NR_mkdirat			(TARGET_NR_Linux + 248)
+#define TARGET_NR_mknodat			(TARGET_NR_Linux + 249)
+#define TARGET_NR_fchownat			(TARGET_NR_Linux + 250)
+#define TARGET_NR_futimesat			(TARGET_NR_Linux + 251)
+#define TARGET_NR_newfstatat			(TARGET_NR_Linux + 252)
+#define TARGET_NR_unlinkat			(TARGET_NR_Linux + 253)
+#define TARGET_NR_renameat			(TARGET_NR_Linux + 254)
+#define TARGET_NR_linkat			(TARGET_NR_Linux + 255)
+#define TARGET_NR_symlinkat			(TARGET_NR_Linux + 256)
+#define TARGET_NR_readlinkat			(TARGET_NR_Linux + 257)
+#define TARGET_NR_fchmodat			(TARGET_NR_Linux + 258)
+#define TARGET_NR_faccessat			(TARGET_NR_Linux + 259)
+#define TARGET_NR_pselect6			(TARGET_NR_Linux + 260)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 261)
+#define TARGET_NR_unshare			(TARGET_NR_Linux + 262)
+#define TARGET_NR_splice			(TARGET_NR_Linux + 263)
+#define TARGET_NR_sync_file_range		(TARGET_NR_Linux + 264)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 265)
+#define TARGET_NR_vmsplice			(TARGET_NR_Linux + 266)
+#define TARGET_NR_move_pages			(TARGET_NR_Linux + 267)
+#define TARGET_NR_set_robust_list		(TARGET_NR_Linux + 268)
+#define TARGET_NR_get_robust_list		(TARGET_NR_Linux + 269)
+#define TARGET_NR_kexec_load			(TARGET_NR_Linux + 270)
+#define TARGET_NR_getcpu			(TARGET_NR_Linux + 271)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 272)
+#define TARGET_NR_ioprio_set			(TARGET_NR_Linux + 273)
+#define TARGET_NR_ioprio_get			(TARGET_NR_Linux + 274)
+#define TARGET_NR_utimensat			(TARGET_NR_Linux + 275)
+#define TARGET_NR_signalfd			(TARGET_NR_Linux + 276)
+#define TARGET_NR_timerfd			(TARGET_NR_Linux + 277)
+#define TARGET_NR_eventfd			(TARGET_NR_Linux + 278)
+#define TARGET_NR_fallocate			(TARGET_NR_Linux + 279)
+#define TARGET_NR_timerfd_create		(TARGET_NR_Linux + 280)
+#define TARGET_NR_timerfd_gettime		(TARGET_NR_Linux + 281)
+#define TARGET_NR_timerfd_settime		(TARGET_NR_Linux + 282)
+#define TARGET_NR_signalfd4			(TARGET_NR_Linux + 283)
+#define TARGET_NR_eventfd2			(TARGET_NR_Linux + 284)
+#define TARGET_NR_epoll_create1		(TARGET_NR_Linux + 285)
+#define TARGET_NR_dup3				(TARGET_NR_Linux + 286)
+#define TARGET_NR_pipe2			(TARGET_NR_Linux + 287)
+#define TARGET_NR_inotify_init1		(TARGET_NR_Linux + 288)
+#define TARGET_NR_preadv                        (TARGET_NR_Linux + 289)
+#define TARGET_NR_pwritev                       (TARGET_NR_Linux + 290)
+#define TARGET_NR_rt_tgsigqueueinfo             (TARGET_NR_Linux + 291)
+#define TARGET_NR_perf_event_open               (TARGET_NR_Linux + 292)
+#define TARGET_NR_accept4                       (TARGET_NR_Linux + 293)
+#define TARGET_NR_recvmmsg                      (TARGET_NR_Linux + 294)
+#define TARGET_NR_fanotify_init                 (TARGET_NR_Linux + 295)
+#define TARGET_NR_fanotify_mark                 (TARGET_NR_Linux + 296)
+#define TARGET_NR_prlimit64                     (TARGET_NR_Linux + 297)
+#define TARGET_NR_name_to_handle_at             (TARGET_NR_Linux + 298)
+#define TARGET_NR_open_by_handle_at             (TARGET_NR_Linux + 299)
+#define TARGET_NR_clock_adjtime                 (TARGET_NR_Linux + 300)
+#define TARGET_NR_syncfs                        (TARGET_NR_Linux + 301)
diff --git a/qemu-0.15.x/linux-user/mips64/target_signal.h b/qemu-0.15.x/linux-user/mips64/target_signal.h
new file mode 100644
index 0000000..6e1dc8b
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips64/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_long ss_sp;
+	abi_ulong ss_size;
+	abi_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/mips64/termbits.h b/qemu-0.15.x/linux-user/mips64/termbits.h
new file mode 100644
index 0000000..d3a6cf8
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mips64/termbits.h
@@ -0,0 +1,245 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 23
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_IEXTEN  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VMIN	4
+#define TARGET_VTIME	5
+#define TARGET_VEOL2	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+/* VDSUSP not supported */
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
+
+/* ioctls */
+
+#define TARGET_TCGETA		0x5401
+#define TARGET_TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TARGET_TCSETAW		0x5403
+#define TARGET_TCSETAF		0x5404
+
+#define TARGET_TCSBRK		0x5405
+#define TARGET_TCXONC		0x5406
+#define TARGET_TCFLSH		0x5407
+
+#define TARGET_TCGETS		0x540d
+#define TARGET_TCSETS		0x540e
+#define TARGET_TCSETSW		0x540f
+#define TARGET_TCSETSF		0x5410
+
+#define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
+#define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
+#define TARGET_TIOCOUTQ	0x7472		/* output queue size */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
+#define TARGET_TIOCMGET	0x741d		/* get all modem bits */
+#define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
+#define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
+#define TARGET_TIOCMSET	0x741a		/* set all modem bits */
+#define TARGET_TIOCPKT		0x5470		/* pty: set/clear packet mode */
+#define	 TARGET_TIOCPKT_DATA		0x00	/* data packet */
+#define	 TARGET_TIOCPKT_FLUSHREAD	0x01	/* flush packet */
+#define	 TARGET_TIOCPKT_FLUSHWRITE	0x02	/* flush packet */
+#define	 TARGET_TIOCPKT_STOP		0x04	/* stop output */
+#define	 TARGET_TIOCPKT_START		0x08	/* start output */
+#define	 TARGET_TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+#define	 TARGET_TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
+/* #define  TIOCPKT_IOCTL		0x40	state change of pty driver */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)	/* set window size */
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)	/* get window size */
+#define TARGET_TIOCNOTTY	0x5471		/* void tty association */
+#define TARGET_TIOCSETD	0x7401
+#define TARGET_TIOCGETD	0x7400
+
+#define TARGET_FIOCLEX		0x6601
+#define TARGET_FIONCLEX	0x6602
+#define TARGET_FIOASYNC	0x667d
+#define TARGET_FIONBIO		0x667e
+#define TARGET_FIOQSIZE	0x667f
+
+#define TARGET_TIOCGLTC	0x7474			/* get special local chars */
+#define TARGET_TIOCSLTC	0x7475			/* set special local chars */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)	/* set pgrp of tty */
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)	/* get pgrp of tty */
+#define TARGET_TIOCCONS	TARGET_IOW('t', 120, int)	/* become virtual console */
+
+#define TARGET_FIONREAD	0x467f
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+#define TARGET_TIOCGETP        0x7408
+#define TARGET_TIOCSETP        0x7409
+#define TARGET_TIOCSETN        0x740a			/* TIOCSETP wo flush */
+
+/* #define TARGET_TIOCSETA	TARGET_IOW('t', 20, struct termios) set termios struct */
+/* #define TARGET_TIOCSETAW	TARGET_IOW('t', 21, struct termios) drain output, set */
+/* #define TARGET_TIOCSETAF	TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
+/* #define TARGET_TIOCGETD	TARGET_IOR('t', 26, int)	get line discipline */
+/* #define TARGET_TIOCSETD	TARGET_IOW('t', 27, int)	set line discipline */
+						/* 127-124 compat */
+
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x7416  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+/* I hope the range from 0x5480 on is free ... */
+#define TARGET_TIOCSCTTY	0x5480		/* become controlling tty */
+#define TARGET_TIOCGSOFTCAR	0x5481
+#define TARGET_TIOCSSOFTCAR	0x5482
+#define TARGET_TIOCLINUX	0x5483
+#define TARGET_TIOCGSERIAL	0x5484
+#define TARGET_TIOCSSERIAL	0x5485
+#define TARGET_TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSERCONFIG	0x5488
+#define TARGET_TIOCSERGWILD	0x5489
+#define TARGET_TIOCSERSWILD	0x548a
+#define TARGET_TIOCGLCKTRMIOS	0x548b
+#define TARGET_TIOCSLCKTRMIOS	0x548c
+#define TARGET_TIOCSERGSTRUCT	0x548d /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x548e /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
+#define TARGET_TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x5493 /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x5494 /* Set Hayes ESP configuration */
diff --git a/qemu-0.15.x/linux-user/mipsn32/syscall.h b/qemu-0.15.x/linux-user/mipsn32/syscall.h
new file mode 100644
index 0000000..4ec506c
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mipsn32/syscall.h
@@ -0,0 +1,221 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+	/* Saved main processor registers. */
+	target_ulong regs[32];
+
+	/* Saved special registers. */
+	target_ulong cp0_status;
+	target_ulong lo;
+	target_ulong hi;
+	target_ulong cp0_badvaddr;
+	target_ulong cp0_cause;
+	target_ulong cp0_epc;
+};
+
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
+#define UNAME_MACHINE "mips64"
diff --git a/qemu-0.15.x/linux-user/mipsn32/syscall_nr.h b/qemu-0.15.x/linux-user/mipsn32/syscall_nr.h
new file mode 100644
index 0000000..4e1aca3
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mipsn32/syscall_nr.h
@@ -0,0 +1,311 @@
+/*
+ * Linux N32 syscalls are in the range from 6000 to 6999.
+ */
+#define TARGET_NR_Linux			6000
+#define TARGET_NR_read			(TARGET_NR_Linux +   0)
+#define TARGET_NR_write			(TARGET_NR_Linux +   1)
+#define TARGET_NR_open			(TARGET_NR_Linux +   2)
+#define TARGET_NR_close			(TARGET_NR_Linux +   3)
+#define TARGET_NR_stat			(TARGET_NR_Linux +   4)
+#define TARGET_NR_fstat			(TARGET_NR_Linux +   5)
+#define TARGET_NR_lstat			(TARGET_NR_Linux +   6)
+#define TARGET_NR_poll			(TARGET_NR_Linux +   7)
+#define TARGET_NR_lseek			(TARGET_NR_Linux +   8)
+#define TARGET_NR_mmap			(TARGET_NR_Linux +   9)
+#define TARGET_NR_mprotect			(TARGET_NR_Linux +  10)
+#define TARGET_NR_munmap			(TARGET_NR_Linux +  11)
+#define TARGET_NR_brk			(TARGET_NR_Linux +  12)
+#define TARGET_NR_rt_sigaction		(TARGET_NR_Linux +  13)
+#define TARGET_NR_rt_sigprocmask		(TARGET_NR_Linux +  14)
+#define TARGET_NR_ioctl			(TARGET_NR_Linux +  15)
+#define TARGET_NR_pread64			(TARGET_NR_Linux +  16)
+#define TARGET_NR_pwrite64			(TARGET_NR_Linux +  17)
+#define TARGET_NR_readv			(TARGET_NR_Linux +  18)
+#define TARGET_NR_writev			(TARGET_NR_Linux +  19)
+#define TARGET_NR_access			(TARGET_NR_Linux +  20)
+#define TARGET_NR_pipe			(TARGET_NR_Linux +  21)
+#define TARGET_NR__newselect			(TARGET_NR_Linux +  22)
+#define TARGET_NR_sched_yield		(TARGET_NR_Linux +  23)
+#define TARGET_NR_mremap			(TARGET_NR_Linux +  24)
+#define TARGET_NR_msync			(TARGET_NR_Linux +  25)
+#define TARGET_NR_mincore			(TARGET_NR_Linux +  26)
+#define TARGET_NR_madvise			(TARGET_NR_Linux +  27)
+#define TARGET_NR_shmget			(TARGET_NR_Linux +  28)
+#define TARGET_NR_shmat			(TARGET_NR_Linux +  29)
+#define TARGET_NR_shmctl			(TARGET_NR_Linux +  30)
+#define TARGET_NR_dup			(TARGET_NR_Linux +  31)
+#define TARGET_NR_dup2			(TARGET_NR_Linux +  32)
+#define TARGET_NR_pause			(TARGET_NR_Linux +  33)
+#define TARGET_NR_nanosleep			(TARGET_NR_Linux +  34)
+#define TARGET_NR_getitimer			(TARGET_NR_Linux +  35)
+#define TARGET_NR_setitimer			(TARGET_NR_Linux +  36)
+#define TARGET_NR_alarm			(TARGET_NR_Linux +  37)
+#define TARGET_NR_getpid			(TARGET_NR_Linux +  38)
+#define TARGET_NR_sendfile			(TARGET_NR_Linux +  39)
+#define TARGET_NR_socket			(TARGET_NR_Linux +  40)
+#define TARGET_NR_connect			(TARGET_NR_Linux +  41)
+#define TARGET_NR_accept			(TARGET_NR_Linux +  42)
+#define TARGET_NR_sendto			(TARGET_NR_Linux +  43)
+#define TARGET_NR_recvfrom			(TARGET_NR_Linux +  44)
+#define TARGET_NR_sendmsg			(TARGET_NR_Linux +  45)
+#define TARGET_NR_recvmsg			(TARGET_NR_Linux +  46)
+#define TARGET_NR_shutdown			(TARGET_NR_Linux +  47)
+#define TARGET_NR_bind			(TARGET_NR_Linux +  48)
+#define TARGET_NR_listen			(TARGET_NR_Linux +  49)
+#define TARGET_NR_getsockname		(TARGET_NR_Linux +  50)
+#define TARGET_NR_getpeername		(TARGET_NR_Linux +  51)
+#define TARGET_NR_socketpair			(TARGET_NR_Linux +  52)
+#define TARGET_NR_setsockopt			(TARGET_NR_Linux +  53)
+#define TARGET_NR_getsockopt			(TARGET_NR_Linux +  54)
+#define TARGET_NR_clone			(TARGET_NR_Linux +  55)
+#define TARGET_NR_fork			(TARGET_NR_Linux +  56)
+#define TARGET_NR_execve			(TARGET_NR_Linux +  57)
+#define TARGET_NR_exit			(TARGET_NR_Linux +  58)
+#define TARGET_NR_wait4			(TARGET_NR_Linux +  59)
+#define TARGET_NR_kill			(TARGET_NR_Linux +  60)
+#define TARGET_NR_uname			(TARGET_NR_Linux +  61)
+#define TARGET_NR_semget			(TARGET_NR_Linux +  62)
+#define TARGET_NR_semop			(TARGET_NR_Linux +  63)
+#define TARGET_NR_semctl			(TARGET_NR_Linux +  64)
+#define TARGET_NR_shmdt			(TARGET_NR_Linux +  65)
+#define TARGET_NR_msgget			(TARGET_NR_Linux +  66)
+#define TARGET_NR_msgsnd			(TARGET_NR_Linux +  67)
+#define TARGET_NR_msgrcv			(TARGET_NR_Linux +  68)
+#define TARGET_NR_msgctl			(TARGET_NR_Linux +  69)
+#define TARGET_NR_fcntl			(TARGET_NR_Linux +  70)
+#define TARGET_NR_flock			(TARGET_NR_Linux +  71)
+#define TARGET_NR_fsync			(TARGET_NR_Linux +  72)
+#define TARGET_NR_fdatasync			(TARGET_NR_Linux +  73)
+#define TARGET_NR_truncate			(TARGET_NR_Linux +  74)
+#define TARGET_NR_ftruncate			(TARGET_NR_Linux +  75)
+#define TARGET_NR_getdents			(TARGET_NR_Linux +  76)
+#define TARGET_NR_getcwd			(TARGET_NR_Linux +  77)
+#define TARGET_NR_chdir			(TARGET_NR_Linux +  78)
+#define TARGET_NR_fchdir			(TARGET_NR_Linux +  79)
+#define TARGET_NR_rename			(TARGET_NR_Linux +  80)
+#define TARGET_NR_mkdir			(TARGET_NR_Linux +  81)
+#define TARGET_NR_rmdir			(TARGET_NR_Linux +  82)
+#define TARGET_NR_creat			(TARGET_NR_Linux +  83)
+#define TARGET_NR_link			(TARGET_NR_Linux +  84)
+#define TARGET_NR_unlink			(TARGET_NR_Linux +  85)
+#define TARGET_NR_symlink			(TARGET_NR_Linux +  86)
+#define TARGET_NR_readlink			(TARGET_NR_Linux +  87)
+#define TARGET_NR_chmod			(TARGET_NR_Linux +  88)
+#define TARGET_NR_fchmod			(TARGET_NR_Linux +  89)
+#define TARGET_NR_chown			(TARGET_NR_Linux +  90)
+#define TARGET_NR_fchown			(TARGET_NR_Linux +  91)
+#define TARGET_NR_lchown			(TARGET_NR_Linux +  92)
+#define TARGET_NR_umask			(TARGET_NR_Linux +  93)
+#define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  94)
+#define TARGET_NR_getrlimit			(TARGET_NR_Linux +  95)
+#define TARGET_NR_getrusage			(TARGET_NR_Linux +  96)
+#define TARGET_NR_sysinfo			(TARGET_NR_Linux +  97)
+#define TARGET_NR_times			(TARGET_NR_Linux +  98)
+#define TARGET_NR_ptrace			(TARGET_NR_Linux +  99)
+#define TARGET_NR_getuid			(TARGET_NR_Linux + 100)
+#define TARGET_NR_syslog			(TARGET_NR_Linux + 101)
+#define TARGET_NR_getgid			(TARGET_NR_Linux + 102)
+#define TARGET_NR_setuid			(TARGET_NR_Linux + 103)
+#define TARGET_NR_setgid			(TARGET_NR_Linux + 104)
+#define TARGET_NR_geteuid			(TARGET_NR_Linux + 105)
+#define TARGET_NR_getegid			(TARGET_NR_Linux + 106)
+#define TARGET_NR_setpgid			(TARGET_NR_Linux + 107)
+#define TARGET_NR_getppid			(TARGET_NR_Linux + 108)
+#define TARGET_NR_getpgrp			(TARGET_NR_Linux + 109)
+#define TARGET_NR_setsid			(TARGET_NR_Linux + 110)
+#define TARGET_NR_setreuid			(TARGET_NR_Linux + 111)
+#define TARGET_NR_setregid			(TARGET_NR_Linux + 112)
+#define TARGET_NR_getgroups			(TARGET_NR_Linux + 113)
+#define TARGET_NR_setgroups			(TARGET_NR_Linux + 114)
+#define TARGET_NR_setresuid			(TARGET_NR_Linux + 115)
+#define TARGET_NR_getresuid			(TARGET_NR_Linux + 116)
+#define TARGET_NR_setresgid			(TARGET_NR_Linux + 117)
+#define TARGET_NR_getresgid			(TARGET_NR_Linux + 118)
+#define TARGET_NR_getpgid			(TARGET_NR_Linux + 119)
+#define TARGET_NR_setfsuid			(TARGET_NR_Linux + 120)
+#define TARGET_NR_setfsgid			(TARGET_NR_Linux + 121)
+#define TARGET_NR_getsid			(TARGET_NR_Linux + 122)
+#define TARGET_NR_capget			(TARGET_NR_Linux + 123)
+#define TARGET_NR_capset			(TARGET_NR_Linux + 124)
+#define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 125)
+#define TARGET_NR_rt_sigtimedwait		(TARGET_NR_Linux + 126)
+#define TARGET_NR_rt_sigqueueinfo		(TARGET_NR_Linux + 127)
+#define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 128)
+#define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 129)
+#define TARGET_NR_utime			(TARGET_NR_Linux + 130)
+#define TARGET_NR_mknod			(TARGET_NR_Linux + 131)
+#define TARGET_NR_personality		(TARGET_NR_Linux + 132)
+#define TARGET_NR_ustat			(TARGET_NR_Linux + 133)
+#define TARGET_NR_statfs			(TARGET_NR_Linux + 134)
+#define TARGET_NR_fstatfs			(TARGET_NR_Linux + 135)
+#define TARGET_NR_sysfs			(TARGET_NR_Linux + 136)
+#define TARGET_NR_getpriority		(TARGET_NR_Linux + 137)
+#define TARGET_NR_setpriority		(TARGET_NR_Linux + 138)
+#define TARGET_NR_sched_setparam		(TARGET_NR_Linux + 139)
+#define TARGET_NR_sched_getparam		(TARGET_NR_Linux + 140)
+#define TARGET_NR_sched_setscheduler		(TARGET_NR_Linux + 141)
+#define TARGET_NR_sched_getscheduler		(TARGET_NR_Linux + 142)
+#define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 143)
+#define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 144)
+#define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 145)
+#define TARGET_NR_mlock			(TARGET_NR_Linux + 146)
+#define TARGET_NR_munlock			(TARGET_NR_Linux + 147)
+#define TARGET_NR_mlockall			(TARGET_NR_Linux + 148)
+#define TARGET_NR_munlockall			(TARGET_NR_Linux + 149)
+#define TARGET_NR_vhangup			(TARGET_NR_Linux + 150)
+#define TARGET_NR_pivot_root			(TARGET_NR_Linux + 151)
+#define TARGET_NR__sysctl			(TARGET_NR_Linux + 152)
+#define TARGET_NR_prctl			(TARGET_NR_Linux + 153)
+#define TARGET_NR_adjtimex			(TARGET_NR_Linux + 154)
+#define TARGET_NR_setrlimit			(TARGET_NR_Linux + 155)
+#define TARGET_NR_chroot			(TARGET_NR_Linux + 156)
+#define TARGET_NR_sync			(TARGET_NR_Linux + 157)
+#define TARGET_NR_acct			(TARGET_NR_Linux + 158)
+#define TARGET_NR_settimeofday		(TARGET_NR_Linux + 159)
+#define TARGET_NR_mount			(TARGET_NR_Linux + 160)
+#define TARGET_NR_umount2			(TARGET_NR_Linux + 161)
+#define TARGET_NR_swapon			(TARGET_NR_Linux + 162)
+#define TARGET_NR_swapoff			(TARGET_NR_Linux + 163)
+#define TARGET_NR_reboot			(TARGET_NR_Linux + 164)
+#define TARGET_NR_sethostname		(TARGET_NR_Linux + 165)
+#define TARGET_NR_setdomainname		(TARGET_NR_Linux + 166)
+#define TARGET_NR_create_module		(TARGET_NR_Linux + 167)
+#define TARGET_NR_init_module		(TARGET_NR_Linux + 168)
+#define TARGET_NR_delete_module		(TARGET_NR_Linux + 169)
+#define TARGET_NR_get_kernel_syms		(TARGET_NR_Linux + 170)
+#define TARGET_NR_query_module		(TARGET_NR_Linux + 171)
+#define TARGET_NR_quotactl			(TARGET_NR_Linux + 172)
+#define TARGET_NR_nfsservctl			(TARGET_NR_Linux + 173)
+#define TARGET_NR_getpmsg			(TARGET_NR_Linux + 174)
+#define TARGET_NR_putpmsg			(TARGET_NR_Linux + 175)
+#define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 176)
+#define TARGET_NR_reserved177		(TARGET_NR_Linux + 177)
+#define TARGET_NR_gettid			(TARGET_NR_Linux + 178)
+#define TARGET_NR_readahead			(TARGET_NR_Linux + 179)
+#define TARGET_NR_setxattr			(TARGET_NR_Linux + 180)
+#define TARGET_NR_lsetxattr			(TARGET_NR_Linux + 181)
+#define TARGET_NR_fsetxattr			(TARGET_NR_Linux + 182)
+#define TARGET_NR_getxattr			(TARGET_NR_Linux + 183)
+#define TARGET_NR_lgetxattr			(TARGET_NR_Linux + 184)
+#define TARGET_NR_fgetxattr			(TARGET_NR_Linux + 185)
+#define TARGET_NR_listxattr			(TARGET_NR_Linux + 186)
+#define TARGET_NR_llistxattr			(TARGET_NR_Linux + 187)
+#define TARGET_NR_flistxattr			(TARGET_NR_Linux + 188)
+#define TARGET_NR_removexattr		(TARGET_NR_Linux + 189)
+#define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 190)
+#define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 191)
+#define TARGET_NR_tkill			(TARGET_NR_Linux + 192)
+#define TARGET_NR_reserved193		(TARGET_NR_Linux + 193)
+#define TARGET_NR_futex			(TARGET_NR_Linux + 194)
+#define TARGET_NR_sched_setaffinity		(TARGET_NR_Linux + 195)
+#define TARGET_NR_sched_getaffinity		(TARGET_NR_Linux + 196)
+#define TARGET_NR_cacheflush			(TARGET_NR_Linux + 197)
+#define TARGET_NR_cachectl			(TARGET_NR_Linux + 198)
+#define TARGET_NR_sysmips			(TARGET_NR_Linux + 199)
+#define TARGET_NR_io_setup			(TARGET_NR_Linux + 200)
+#define TARGET_NR_io_destroy			(TARGET_NR_Linux + 201)
+#define TARGET_NR_io_getevents		(TARGET_NR_Linux + 202)
+#define TARGET_NR_io_submit			(TARGET_NR_Linux + 203)
+#define TARGET_NR_io_cancel			(TARGET_NR_Linux + 204)
+#define TARGET_NR_exit_group			(TARGET_NR_Linux + 205)
+#define TARGET_NR_lookup_dcookie		(TARGET_NR_Linux + 206)
+#define TARGET_NR_epoll_create		(TARGET_NR_Linux + 207)
+#define TARGET_NR_epoll_ctl			(TARGET_NR_Linux + 208)
+#define TARGET_NR_epoll_wait			(TARGET_NR_Linux + 209)
+#define TARGET_NR_remap_file_pages		(TARGET_NR_Linux + 210)
+#define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 211)
+#define TARGET_NR_fcntl64			(TARGET_NR_Linux + 212)
+#define TARGET_NR_set_tid_address		(TARGET_NR_Linux + 213)
+#define TARGET_NR_restart_syscall		(TARGET_NR_Linux + 214)
+#define TARGET_NR_semtimedop			(TARGET_NR_Linux + 215)
+#define TARGET_NR_fadvise64			(TARGET_NR_Linux + 216)
+#define TARGET_NR_statfs64			(TARGET_NR_Linux + 217)
+#define TARGET_NR_fstatfs64			(TARGET_NR_Linux + 218)
+#define TARGET_NR_sendfile64			(TARGET_NR_Linux + 219)
+#define TARGET_NR_timer_create		(TARGET_NR_Linux + 220)
+#define TARGET_NR_timer_settime		(TARGET_NR_Linux + 221)
+#define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 222)
+#define TARGET_NR_timer_getoverrun		(TARGET_NR_Linux + 223)
+#define TARGET_NR_timer_delete		(TARGET_NR_Linux + 224)
+#define TARGET_NR_clock_settime		(TARGET_NR_Linux + 225)
+#define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 226)
+#define TARGET_NR_clock_getres		(TARGET_NR_Linux + 227)
+#define TARGET_NR_clock_nanosleep		(TARGET_NR_Linux + 228)
+#define TARGET_NR_tgkill			(TARGET_NR_Linux + 229)
+#define TARGET_NR_utimes			(TARGET_NR_Linux + 230)
+#define TARGET_NR_mbind			(TARGET_NR_Linux + 231)
+#define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 232)
+#define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 233)
+#define TARGET_NR_mq_open			(TARGET_NR_Linux + 234)
+#define TARGET_NR_mq_unlink			(TARGET_NR_Linux + 235)
+#define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 236)
+#define TARGET_NR_mq_timedreceive		(TARGET_NR_Linux + 237)
+#define TARGET_NR_mq_notify			(TARGET_NR_Linux + 238)
+#define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 239)
+#define TARGET_NR_vserver			(TARGET_NR_Linux + 240)
+#define TARGET_NR_waitid			(TARGET_NR_Linux + 241)
+/* #define TARGET_NR_sys_setaltroot		(TARGET_NR_Linux + 242) */
+#define TARGET_NR_add_key			(TARGET_NR_Linux + 243)
+#define TARGET_NR_request_key		(TARGET_NR_Linux + 244)
+#define TARGET_NR_keyctl			(TARGET_NR_Linux + 245)
+#define TARGET_NR_set_thread_area		(TARGET_NR_Linux + 246)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 247)
+#define TARGET_NR_inotify_add_watch		(TARGET_NR_Linux + 248)
+#define TARGET_NR_inotify_rm_watch		(TARGET_NR_Linux + 249)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 250)
+#define TARGET_NR_openat			(TARGET_NR_Linux + 251)
+#define TARGET_NR_mkdirat			(TARGET_NR_Linux + 252)
+#define TARGET_NR_mknodat			(TARGET_NR_Linux + 253)
+#define TARGET_NR_fchownat			(TARGET_NR_Linux + 254)
+#define TARGET_NR_futimesat			(TARGET_NR_Linux + 255)
+#define TARGET_NR_newfstatat			(TARGET_NR_Linux + 256)
+#define TARGET_NR_unlinkat			(TARGET_NR_Linux + 257)
+#define TARGET_NR_renameat			(TARGET_NR_Linux + 258)
+#define TARGET_NR_linkat			(TARGET_NR_Linux + 259)
+#define TARGET_NR_symlinkat			(TARGET_NR_Linux + 260)
+#define TARGET_NR_readlinkat			(TARGET_NR_Linux + 261)
+#define TARGET_NR_fchmodat			(TARGET_NR_Linux + 262)
+#define TARGET_NR_faccessat			(TARGET_NR_Linux + 263)
+#define TARGET_NR_pselect6			(TARGET_NR_Linux + 264)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 265)
+#define TARGET_NR_unshare			(TARGET_NR_Linux + 266)
+#define TARGET_NR_splice			(TARGET_NR_Linux + 267)
+#define TARGET_NR_sync_file_range		(TARGET_NR_Linux + 268)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 269)
+#define TARGET_NR_vmsplice			(TARGET_NR_Linux + 270)
+#define TARGET_NR_move_pages			(TARGET_NR_Linux + 271)
+#define TARGET_NR_set_robust_list		(TARGET_NR_Linux + 272)
+#define TARGET_NR_get_robust_list		(TARGET_NR_Linux + 273)
+#define TARGET_NR_kexec_load			(TARGET_NR_Linux + 274)
+#define TARGET_NR_getcpu			(TARGET_NR_Linux + 275)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 276)
+#define TARGET_NR_ioprio_set			(TARGET_NR_Linux + 277)
+#define TARGET_NR_ioprio_get			(TARGET_NR_Linux + 278)
+#define TARGET_NR_utimensat			(TARGET_NR_Linux + 279)
+#define TARGET_NR_signalfd			(TARGET_NR_Linux + 280)
+#define TARGET_NR_timerfd			(TARGET_NR_Linux + 281)
+#define TARGET_NR_eventfd			(TARGET_NR_Linux + 282)
+#define TARGET_NR_fallocate			(TARGET_NR_Linux + 283)
+#define TARGET_NR_timerfd_create		(TARGET_NR_Linux + 284)
+#define TARGET_NR_timerfd_gettime		(TARGET_NR_Linux + 285)
+#define TARGET_NR_timerfd_settime		(TARGET_NR_Linux + 286)
+#define TARGET_NR_signalfd4			(TARGET_NR_Linux + 287)
+#define TARGET_NR_eventfd2			(TARGET_NR_Linux + 288)
+#define TARGET_NR_epoll_create1		(TARGET_NR_Linux + 289)
+#define TARGET_NR_dup3				(TARGET_NR_Linux + 290)
+#define TARGET_NR_pipe2			(TARGET_NR_Linux + 291)
+#define TARGET_NR_inotify_init1		(TARGET_NR_Linux + 292)
+#define TARGET_NR_preadv                        (TARGET_NR_Linux + 293)
+#define TARGET_NR_pwritev                       (TARGET_NR_Linux + 294)
+#define TARGET_NR_rt_tgsigqueueinfo             (TARGET_NR_Linux + 295)
+#define TARGET_NR_perf_event_open               (TARGET_NR_Linux + 296)
+#define TARGET_NR_accept4                       (TARGET_NR_Linux + 297)
+#define TARGET_NR_recvmmsg                      (TARGET_NR_Linux + 298)
+#define TARGET_NR_getdents64                    (TARGET_NR_Linux + 299)
+#define TARGET_NR_fanotify_init                 (TARGET_NR_Linux + 300)
+#define TARGET_NR_fanotify_mark                 (TARGET_NR_Linux + 301)
+#define TARGET_NR_prlimit64                     (TARGET_NR_Linux + 302)
+#define TARGET_NR_name_to_handle_at             (TARGET_NR_Linux + 303)
+#define TARGET_NR_open_by_handle_at             (TARGET_NR_Linux + 304)
+#define TARGET_NR_clock_adjtime                 (TARGET_NR_Linux + 305)
+#define TARGET_NR_syncfs                        (TARGET_NR_Linux + 306)
diff --git a/qemu-0.15.x/linux-user/mipsn32/target_signal.h b/qemu-0.15.x/linux-user/mipsn32/target_signal.h
new file mode 100644
index 0000000..ff20d9e
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mipsn32/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	int32_t ss_sp;
+	uint32_t ss_size;
+	int32_t ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->active_tc.gpr[29];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/mipsn32/termbits.h b/qemu-0.15.x/linux-user/mipsn32/termbits.h
new file mode 100644
index 0000000..d3a6cf8
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mipsn32/termbits.h
@@ -0,0 +1,245 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 23
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_IEXTEN  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VMIN	4
+#define TARGET_VTIME	5
+#define TARGET_VEOL2	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+/* VDSUSP not supported */
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
+
+/* ioctls */
+
+#define TARGET_TCGETA		0x5401
+#define TARGET_TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TARGET_TCSETAW		0x5403
+#define TARGET_TCSETAF		0x5404
+
+#define TARGET_TCSBRK		0x5405
+#define TARGET_TCXONC		0x5406
+#define TARGET_TCFLSH		0x5407
+
+#define TARGET_TCGETS		0x540d
+#define TARGET_TCSETS		0x540e
+#define TARGET_TCSETSW		0x540f
+#define TARGET_TCSETSF		0x5410
+
+#define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
+#define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
+#define TARGET_TIOCOUTQ	0x7472		/* output queue size */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
+#define TARGET_TIOCMGET	0x741d		/* get all modem bits */
+#define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
+#define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
+#define TARGET_TIOCMSET	0x741a		/* set all modem bits */
+#define TARGET_TIOCPKT		0x5470		/* pty: set/clear packet mode */
+#define	 TARGET_TIOCPKT_DATA		0x00	/* data packet */
+#define	 TARGET_TIOCPKT_FLUSHREAD	0x01	/* flush packet */
+#define	 TARGET_TIOCPKT_FLUSHWRITE	0x02	/* flush packet */
+#define	 TARGET_TIOCPKT_STOP		0x04	/* stop output */
+#define	 TARGET_TIOCPKT_START		0x08	/* start output */
+#define	 TARGET_TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+#define	 TARGET_TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
+/* #define  TIOCPKT_IOCTL		0x40	state change of pty driver */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)	/* set window size */
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)	/* get window size */
+#define TARGET_TIOCNOTTY	0x5471		/* void tty association */
+#define TARGET_TIOCSETD	0x7401
+#define TARGET_TIOCGETD	0x7400
+
+#define TARGET_FIOCLEX		0x6601
+#define TARGET_FIONCLEX	0x6602
+#define TARGET_FIOASYNC	0x667d
+#define TARGET_FIONBIO		0x667e
+#define TARGET_FIOQSIZE	0x667f
+
+#define TARGET_TIOCGLTC	0x7474			/* get special local chars */
+#define TARGET_TIOCSLTC	0x7475			/* set special local chars */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)	/* set pgrp of tty */
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)	/* get pgrp of tty */
+#define TARGET_TIOCCONS	TARGET_IOW('t', 120, int)	/* become virtual console */
+
+#define TARGET_FIONREAD	0x467f
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+#define TARGET_TIOCGETP        0x7408
+#define TARGET_TIOCSETP        0x7409
+#define TARGET_TIOCSETN        0x740a			/* TIOCSETP wo flush */
+
+/* #define TARGET_TIOCSETA	TARGET_IOW('t', 20, struct termios) set termios struct */
+/* #define TARGET_TIOCSETAW	TARGET_IOW('t', 21, struct termios) drain output, set */
+/* #define TARGET_TIOCSETAF	TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
+/* #define TARGET_TIOCGETD	TARGET_IOR('t', 26, int)	get line discipline */
+/* #define TARGET_TIOCSETD	TARGET_IOW('t', 27, int)	set line discipline */
+						/* 127-124 compat */
+
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x7416  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+/* I hope the range from 0x5480 on is free ... */
+#define TARGET_TIOCSCTTY	0x5480		/* become controlling tty */
+#define TARGET_TIOCGSOFTCAR	0x5481
+#define TARGET_TIOCSSOFTCAR	0x5482
+#define TARGET_TIOCLINUX	0x5483
+#define TARGET_TIOCGSERIAL	0x5484
+#define TARGET_TIOCSSERIAL	0x5485
+#define TARGET_TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSERCONFIG	0x5488
+#define TARGET_TIOCSERGWILD	0x5489
+#define TARGET_TIOCSERSWILD	0x548a
+#define TARGET_TIOCGLCKTRMIOS	0x548b
+#define TARGET_TIOCSLCKTRMIOS	0x548c
+#define TARGET_TIOCSERGSTRUCT	0x548d /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x548e /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
+#define TARGET_TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x5493 /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x5494 /* Set Hayes ESP configuration */
diff --git a/qemu-0.15.x/linux-user/mmap.c b/qemu-0.15.x/linux-user/mmap.c
new file mode 100644
index 0000000..994c02b
--- /dev/null
+++ b/qemu-0.15.x/linux-user/mmap.c
@@ -0,0 +1,763 @@
+/*
+ *  mmap support for qemu
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <linux/mman.h>
+#include <linux/unistd.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+//#define DEBUG_MMAP
+
+#if defined(CONFIG_USE_NPTL)
+static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
+static __thread int mmap_lock_count;
+
+void mmap_lock(void)
+{
+    if (mmap_lock_count++ == 0) {
+        pthread_mutex_lock(&mmap_mutex);
+    }
+}
+
+void mmap_unlock(void)
+{
+    if (--mmap_lock_count == 0) {
+        pthread_mutex_unlock(&mmap_mutex);
+    }
+}
+
+/* Grab lock to make sure things are in a consistent state after fork().  */
+void mmap_fork_start(void)
+{
+    if (mmap_lock_count)
+        abort();
+    pthread_mutex_lock(&mmap_mutex);
+}
+
+void mmap_fork_end(int child)
+{
+    if (child)
+        pthread_mutex_init(&mmap_mutex, NULL);
+    else
+        pthread_mutex_unlock(&mmap_mutex);
+}
+#else
+/* We aren't threadsafe to start with, so no need to worry about locking.  */
+void mmap_lock(void)
+{
+}
+
+void mmap_unlock(void)
+{
+}
+#endif
+
+/* NOTE: all the constants are the HOST ones, but addresses are target. */
+int target_mprotect(abi_ulong start, abi_ulong len, int prot)
+{
+    abi_ulong end, host_start, host_end, addr;
+    int prot1, ret;
+
+#ifdef DEBUG_MMAP
+    printf("mprotect: start=0x" TARGET_ABI_FMT_lx
+           "len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len,
+           prot & PROT_READ ? 'r' : '-',
+           prot & PROT_WRITE ? 'w' : '-',
+           prot & PROT_EXEC ? 'x' : '-');
+#endif
+
+    if ((start & ~TARGET_PAGE_MASK) != 0)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
+    if (len == 0)
+        return 0;
+
+    mmap_lock();
+    host_start = start & qemu_host_page_mask;
+    host_end = HOST_PAGE_ALIGN(end);
+    if (start > host_start) {
+        /* handle host page containing start */
+        prot1 = prot;
+        for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        if (host_end == host_start + qemu_host_page_size) {
+            for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+                prot1 |= page_get_flags(addr);
+            }
+            end = host_end;
+        }
+        ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
+        if (ret != 0)
+            goto error;
+        host_start += qemu_host_page_size;
+    }
+    if (end < host_end) {
+        prot1 = prot;
+        for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(addr);
+        }
+        ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
+                       prot1 & PAGE_BITS);
+        if (ret != 0)
+            goto error;
+        host_end -= qemu_host_page_size;
+    }
+
+    /* handle the pages in the middle */
+    if (host_start < host_end) {
+        ret = mprotect(g2h(host_start), host_end - host_start, prot);
+        if (ret != 0)
+            goto error;
+    }
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+    mmap_unlock();
+    return 0;
+error:
+    mmap_unlock();
+    return ret;
+}
+
+/* map an incomplete host page */
+static int mmap_frag(abi_ulong real_start,
+                     abi_ulong start, abi_ulong end,
+                     int prot, int flags, int fd, abi_ulong offset)
+{
+    abi_ulong real_end, addr;
+    void *host_start;
+    int prot1, prot_new;
+
+    real_end = real_start + qemu_host_page_size;
+    host_start = g2h(real_start);
+
+    /* get the protection of the target pages outside the mapping */
+    prot1 = 0;
+    for(addr = real_start; addr < real_end; addr++) {
+        if (addr < start || addr >= end)
+            prot1 |= page_get_flags(addr);
+    }
+
+    if (prot1 == 0) {
+        /* no page was there, so we allocate one */
+        void *p = mmap(host_start, qemu_host_page_size, prot,
+                       flags | MAP_ANONYMOUS, -1, 0);
+        if (p == MAP_FAILED)
+            return -1;
+        prot1 = prot;
+    }
+    prot1 &= PAGE_BITS;
+
+    prot_new = prot | prot1;
+    if (!(flags & MAP_ANONYMOUS)) {
+        /* msync() won't work here, so we return an error if write is
+           possible while it is a shared mapping */
+        if ((flags & MAP_TYPE) == MAP_SHARED &&
+            (prot & PROT_WRITE))
+            return -1;
+
+        /* adjust protection to be able to read */
+        if (!(prot1 & PROT_WRITE))
+            mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+
+        /* read the corresponding file data */
+        if (pread(fd, g2h(start), end - start, offset) == -1)
+            return -1;
+
+        /* put final protection */
+        if (prot_new != (prot1 | PROT_WRITE))
+            mprotect(host_start, qemu_host_page_size, prot_new);
+    } else {
+        /* just update the protection */
+        if (prot_new != prot1) {
+            mprotect(host_start, qemu_host_page_size, prot_new);
+        }
+    }
+    return 0;
+}
+
+#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
+# define TASK_UNMAPPED_BASE  (1ul << 38)
+#elif defined(__CYGWIN__)
+/* Cygwin doesn't have a whole lot of address space.  */
+# define TASK_UNMAPPED_BASE  0x18000000
+#else
+# define TASK_UNMAPPED_BASE  0x40000000
+#endif
+static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
+
+unsigned long last_brk;
+
+#ifdef CONFIG_USE_GUEST_BASE
+/* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
+   of guest address space.  */
+static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
+{
+    abi_ulong addr;
+    abi_ulong last_addr;
+    int prot;
+    int looped = 0;
+
+    if (size > RESERVED_VA) {
+        return (abi_ulong)-1;
+    }
+
+    last_addr = start;
+    for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) {
+        if (last_addr + size >= RESERVED_VA
+            || (abi_ulong)(last_addr + size) < last_addr) {
+            if (looped) {
+                return (abi_ulong)-1;
+            }
+            last_addr = qemu_host_page_size;
+            addr = 0;
+            looped = 1;
+            continue;
+        }
+        prot = page_get_flags(addr);
+        if (prot) {
+            last_addr = addr + qemu_host_page_size;
+        }
+    }
+    mmap_next_start = addr;
+    return last_addr;
+}
+#endif
+
+/*
+ * Find and reserve a free memory area of size 'size'. The search
+ * starts at 'start'.
+ * It must be called with mmap_lock() held.
+ * Return -1 if error.
+ */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+{
+    void *ptr, *prev;
+    abi_ulong addr;
+    int wrapped, repeat;
+
+    /* If 'start' == 0, then a default start address is used. */
+    if (start == 0) {
+        start = mmap_next_start;
+    } else {
+        start &= qemu_host_page_mask;
+    }
+
+    size = HOST_PAGE_ALIGN(size);
+
+#ifdef CONFIG_USE_GUEST_BASE
+    if (RESERVED_VA) {
+        return mmap_find_vma_reserved(start, size);
+    }
+#endif
+
+    addr = start;
+    wrapped = repeat = 0;
+    prev = 0;
+
+    for (;; prev = ptr) {
+        /*
+         * Reserve needed memory area to avoid a race.
+         * It should be discarded using:
+         *  - mmap() with MAP_FIXED flag
+         *  - mremap() with MREMAP_FIXED flag
+         *  - shmat() with SHM_REMAP flag
+         */
+        ptr = mmap(g2h(addr), size, PROT_NONE,
+                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+
+        /* ENOMEM, if host address space has no memory */
+        if (ptr == MAP_FAILED) {
+            return (abi_ulong)-1;
+        }
+
+        /* Count the number of sequential returns of the same address.
+           This is used to modify the search algorithm below.  */
+        repeat = (ptr == prev ? repeat + 1 : 0);
+
+        if (h2g_valid(ptr + size - 1)) {
+            addr = h2g(ptr);
+
+            if ((addr & ~TARGET_PAGE_MASK) == 0) {
+                /* Success.  */
+                if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
+                    mmap_next_start = addr + size;
+                }
+                return addr;
+            }
+
+            /* The address is not properly aligned for the target.  */
+            switch (repeat) {
+            case 0:
+                /* Assume the result that the kernel gave us is the
+                   first with enough free space, so start again at the
+                   next higher target page.  */
+                addr = TARGET_PAGE_ALIGN(addr);
+                break;
+            case 1:
+                /* Sometimes the kernel decides to perform the allocation
+                   at the top end of memory instead.  */
+                addr &= TARGET_PAGE_MASK;
+                break;
+            case 2:
+                /* Start over at low memory.  */
+                addr = 0;
+                break;
+            default:
+                /* Fail.  This unaligned block must the last.  */
+                addr = -1;
+                break;
+            }
+        } else {
+            /* Since the result the kernel gave didn't fit, start
+               again at low memory.  If any repetition, fail.  */
+            addr = (repeat ? -1 : 0);
+        }
+
+        /* Unmap and try again.  */
+        munmap(ptr, size);
+
+        /* ENOMEM if we checked the whole of the target address space.  */
+        if (addr == (abi_ulong)-1) {
+            return (abi_ulong)-1;
+        } else if (addr == 0) {
+            if (wrapped) {
+                return (abi_ulong)-1;
+            }
+            wrapped = 1;
+            /* Don't actually use 0 when wrapping, instead indicate
+               that we'd truly like an allocation in low memory.  */
+            addr = (mmap_min_addr > TARGET_PAGE_SIZE
+                     ? TARGET_PAGE_ALIGN(mmap_min_addr)
+                     : TARGET_PAGE_SIZE);
+        } else if (wrapped && addr >= start) {
+            return (abi_ulong)-1;
+        }
+    }
+}
+
+/* NOTE: all the constants are the HOST ones */
+abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
+                     int flags, int fd, abi_ulong offset)
+{
+    abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
+    unsigned long host_start;
+
+    mmap_lock();
+#ifdef DEBUG_MMAP
+    {
+        printf("mmap: start=0x" TARGET_ABI_FMT_lx
+               " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=",
+               start, len,
+               prot & PROT_READ ? 'r' : '-',
+               prot & PROT_WRITE ? 'w' : '-',
+               prot & PROT_EXEC ? 'x' : '-');
+        if (flags & MAP_FIXED)
+            printf("MAP_FIXED ");
+        if (flags & MAP_ANONYMOUS)
+            printf("MAP_ANON ");
+        switch(flags & MAP_TYPE) {
+        case MAP_PRIVATE:
+            printf("MAP_PRIVATE ");
+            break;
+        case MAP_SHARED:
+            printf("MAP_SHARED ");
+            break;
+        default:
+            printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
+            break;
+        }
+        printf("fd=%d offset=" TARGET_ABI_FMT_lx "\n", fd, offset);
+    }
+#endif
+
+    if (offset & ~TARGET_PAGE_MASK) {
+        errno = EINVAL;
+        goto fail;
+    }
+
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        goto the_end;
+    real_start = start & qemu_host_page_mask;
+
+    /* When mapping files into a memory area larger than the file, accesses
+       to pages beyond the file size will cause a SIGBUS. 
+
+       For example, if mmaping a file of 100 bytes on a host with 4K pages
+       emulating a target with 8K pages, the target expects to be able to
+       access the first 8K. But the host will trap us on any access beyond
+       4K.  
+
+       When emulating a target with a larger page-size than the hosts, we
+       may need to truncate file maps at EOF and add extra anonymous pages
+       up to the targets page boundary.  */
+
+    if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
+        && !(flags & MAP_ANONYMOUS)) {
+       struct stat sb;
+
+       if (fstat (fd, &sb) == -1)
+           goto fail;
+
+       /* Are we trying to create a map beyond EOF?.  */
+       if (offset + len > sb.st_size) {
+           /* If so, truncate the file map at eof aligned with 
+              the hosts real pagesize. Additional anonymous maps
+              will be created beyond EOF.  */
+           len = (sb.st_size - offset);
+           len += qemu_real_host_page_size - 1;
+           len &= ~(qemu_real_host_page_size - 1);
+       }
+    }
+
+    if (!(flags & MAP_FIXED)) {
+        abi_ulong mmap_start;
+        void *p;
+        host_offset = offset & qemu_host_page_mask;
+        host_len = len + offset - host_offset;
+        host_len = HOST_PAGE_ALIGN(host_len);
+        mmap_start = mmap_find_vma(real_start, host_len);
+        if (mmap_start == (abi_ulong)-1) {
+            errno = ENOMEM;
+            goto fail;
+        }
+        /* Note: we prefer to control the mapping address. It is
+           especially important if qemu_host_page_size >
+           qemu_real_host_page_size */
+        p = mmap(g2h(mmap_start),
+                 host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+        if (p == MAP_FAILED)
+            goto fail;
+        /* update start so that it points to the file position at 'offset' */
+        host_start = (unsigned long)p;
+        if (!(flags & MAP_ANONYMOUS)) {
+            p = mmap(g2h(mmap_start), len, prot, 
+                     flags | MAP_FIXED, fd, host_offset);
+            host_start += offset - host_offset;
+        }
+        start = h2g(host_start);
+    } else {
+        if (start & ~TARGET_PAGE_MASK) {
+            errno = EINVAL;
+            goto fail;
+        }
+        end = start + len;
+        real_end = HOST_PAGE_ALIGN(end);
+
+	/*
+	 * Test if requested memory area fits target address space
+	 * It can fail only on 64-bit host with 32-bit target.
+	 * On any other target/host host mmap() handles this error correctly.
+	 */
+        if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
+            errno = EINVAL;
+            goto fail;
+        }
+
+        /* worst case: we cannot map the file because the offset is not
+           aligned, so we read it */
+        if (!(flags & MAP_ANONYMOUS) &&
+            (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
+            /* msync() won't work here, so we return an error if write is
+               possible while it is a shared mapping */
+            if ((flags & MAP_TYPE) == MAP_SHARED &&
+                (prot & PROT_WRITE)) {
+                errno = EINVAL;
+                goto fail;
+            }
+            retaddr = target_mmap(start, len, prot | PROT_WRITE,
+                                  MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+                                  -1, 0);
+            if (retaddr == -1)
+                goto fail;
+            if (pread(fd, g2h(start), len, offset) == -1)
+                goto fail;
+            if (!(prot & PROT_WRITE)) {
+                ret = target_mprotect(start, len, prot);
+                if (ret != 0) {
+                    start = ret;
+                    goto the_end;
+                }
+            }
+            goto the_end;
+        }
+        
+        /* handle the start of the mapping */
+        if (start > real_start) {
+            if (real_end == real_start + qemu_host_page_size) {
+                /* one single host page */
+                ret = mmap_frag(real_start, start, end,
+                                prot, flags, fd, offset);
+                if (ret == -1)
+                    goto fail;
+                goto the_end1;
+            }
+            ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
+                            prot, flags, fd, offset);
+            if (ret == -1)
+                goto fail;
+            real_start += qemu_host_page_size;
+        }
+        /* handle the end of the mapping */
+        if (end < real_end) {
+            ret = mmap_frag(real_end - qemu_host_page_size,
+                            real_end - qemu_host_page_size, real_end,
+                            prot, flags, fd,
+                            offset + real_end - qemu_host_page_size - start);
+            if (ret == -1)
+                goto fail;
+            real_end -= qemu_host_page_size;
+        }
+
+        /* map the middle (easier) */
+        if (real_start < real_end) {
+            void *p;
+            unsigned long offset1;
+            if (flags & MAP_ANONYMOUS)
+                offset1 = 0;
+            else
+                offset1 = offset + real_start - start;
+            p = mmap(g2h(real_start), real_end - real_start,
+                     prot, flags, fd, offset1);
+            if (p == MAP_FAILED)
+                goto fail;
+        }
+    }
+ the_end1:
+    page_set_flags(start, start + len, prot | PAGE_VALID);
+ the_end:
+#ifdef DEBUG_MMAP
+    printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
+    page_dump(stdout);
+    printf("\n");
+#endif
+    mmap_unlock();
+    return start;
+fail:
+    mmap_unlock();
+    return -1;
+}
+
+static void mmap_reserve(abi_ulong start, abi_ulong size)
+{
+    abi_ulong real_start;
+    abi_ulong real_end;
+    abi_ulong addr;
+    abi_ulong end;
+    int prot;
+
+    real_start = start & qemu_host_page_mask;
+    real_end = HOST_PAGE_ALIGN(start + size);
+    end = start + size;
+    if (start > real_start) {
+        /* handle host page containing start */
+        prot = 0;
+        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (real_end == real_start + qemu_host_page_size) {
+            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+                prot |= page_get_flags(addr);
+            }
+            end = real_end;
+        }
+        if (prot != 0)
+            real_start += qemu_host_page_size;
+    }
+    if (end < real_end) {
+        prot = 0;
+        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (prot != 0)
+            real_end -= qemu_host_page_size;
+    }
+    if (real_start != real_end) {
+        mmap(g2h(real_start), real_end - real_start, PROT_NONE,
+                 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
+                 -1, 0);
+    }
+}
+
+int target_munmap(abi_ulong start, abi_ulong len)
+{
+    abi_ulong end, real_start, real_end, addr;
+    int prot, ret;
+
+#ifdef DEBUG_MMAP
+    printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x"
+           TARGET_ABI_FMT_lx "\n",
+           start, len);
+#endif
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    if (len == 0)
+        return -EINVAL;
+    mmap_lock();
+    end = start + len;
+    real_start = start & qemu_host_page_mask;
+    real_end = HOST_PAGE_ALIGN(end);
+
+    if (start > real_start) {
+        /* handle host page containing start */
+        prot = 0;
+        for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (real_end == real_start + qemu_host_page_size) {
+            for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+                prot |= page_get_flags(addr);
+            }
+            end = real_end;
+        }
+        if (prot != 0)
+            real_start += qemu_host_page_size;
+    }
+    if (end < real_end) {
+        prot = 0;
+        for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
+            prot |= page_get_flags(addr);
+        }
+        if (prot != 0)
+            real_end -= qemu_host_page_size;
+    }
+
+    ret = 0;
+    /* unmap what we can */
+    if (real_start < real_end) {
+        if (RESERVED_VA) {
+            mmap_reserve(real_start, real_end - real_start);
+        } else {
+            ret = munmap(g2h(real_start), real_end - real_start);
+        }
+    }
+
+    if (ret == 0)
+        page_set_flags(start, start + len, 0);
+    mmap_unlock();
+    return ret;
+}
+
+abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
+                       abi_ulong new_size, unsigned long flags,
+                       abi_ulong new_addr)
+{
+    int prot;
+    void *host_addr;
+
+    mmap_lock();
+
+    if (flags & MREMAP_FIXED) {
+        host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
+                                     old_size, new_size,
+                                     flags,
+                                     g2h(new_addr));
+
+        if (RESERVED_VA && host_addr != MAP_FAILED) {
+            /* If new and old addresses overlap then the above mremap will
+               already have failed with EINVAL.  */
+            mmap_reserve(old_addr, old_size);
+        }
+    } else if (flags & MREMAP_MAYMOVE) {
+        abi_ulong mmap_start;
+
+        mmap_start = mmap_find_vma(0, new_size);
+
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            host_addr = MAP_FAILED;
+        } else {
+            host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
+                                         old_size, new_size,
+                                         flags | MREMAP_FIXED,
+                                         g2h(mmap_start));
+            if ( RESERVED_VA ) {
+                mmap_reserve(old_addr, old_size);
+            }
+        }
+    } else {
+        int prot = 0;
+        if (RESERVED_VA && old_size < new_size) {
+            abi_ulong addr;
+            for (addr = old_addr + old_size;
+                 addr < old_addr + new_size;
+                 addr++) {
+                prot |= page_get_flags(addr);
+            }
+        }
+        if (prot == 0) {
+            host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
+            if (host_addr != MAP_FAILED && RESERVED_VA && old_size > new_size) {
+                mmap_reserve(old_addr + old_size, new_size - old_size);
+            }
+        } else {
+            errno = ENOMEM;
+            host_addr = MAP_FAILED;
+        }
+        /* Check if address fits target address space */
+        if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
+            /* Revert mremap() changes */
+            host_addr = mremap(g2h(old_addr), new_size, old_size, flags);
+            errno = ENOMEM;
+            host_addr = MAP_FAILED;
+        }
+    }
+
+    if (host_addr == MAP_FAILED) {
+        new_addr = -1;
+    } else {
+        new_addr = h2g(host_addr);
+        prot = page_get_flags(old_addr);
+        page_set_flags(old_addr, old_addr + old_size, 0);
+        page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
+    }
+    mmap_unlock();
+    return new_addr;
+}
+
+int target_msync(abi_ulong start, abi_ulong len, int flags)
+{
+    abi_ulong end;
+
+    if (start & ~TARGET_PAGE_MASK)
+        return -EINVAL;
+    len = TARGET_PAGE_ALIGN(len);
+    end = start + len;
+    if (end < start)
+        return -EINVAL;
+    if (end == start)
+        return 0;
+
+    start &= qemu_host_page_mask;
+    return msync(g2h(start), end - start, flags);
+}
diff --git a/qemu-0.15.x/linux-user/ppc/syscall.h b/qemu-0.15.x/linux-user/ppc/syscall.h
new file mode 100644
index 0000000..481047b
--- /dev/null
+++ b/qemu-0.15.x/linux-user/ppc/syscall.h
@@ -0,0 +1,64 @@
+/*
+ *  PPC emulation for qemu: syscall definitions.
+ *
+ *  Copyright (c) 2003 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX: ABSOLUTELY BUGGY:
+ * for now, this is quite just a cut-and-paste from i386 target...
+ */
+
+/* default linux values for the selectors */
+#define __USER_DS	(1)
+
+struct target_pt_regs {
+	abi_ulong gpr[32];
+	abi_ulong nip;
+	abi_ulong msr;
+	abi_ulong orig_gpr3;	/* Used for restarting system calls */
+	abi_ulong ctr;
+	abi_ulong link;
+	abi_ulong xer;
+	abi_ulong ccr;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+        abi_ulong softe;
+#else
+	abi_ulong mq;		/* 601 only (not used at present) */
+#endif
+					/* Used on APUS to hold IPL value. */
+	abi_ulong trap;		/* Reason for being here */
+	abi_ulong dar;		/* Fault registers */
+	abi_ulong dsisr;
+	abi_ulong result; 		/* Result of a system call */
+};
+
+/* ioctls */
+struct target_revectored_struct {
+	abi_ulong __map[8];			/* 256 bits */
+};
+
+/* Nasty hack: define a fake errno value for use by sigreturn.  */
+#define TARGET_QEMU_ESIGRETURN 255
+
+/*
+ * flags masks
+ */
+
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+#define UNAME_MACHINE "ppc64"
+#else
+#define UNAME_MACHINE "ppc"
+#endif
diff --git a/qemu-0.15.x/linux-user/ppc/syscall_nr.h b/qemu-0.15.x/linux-user/ppc/syscall_nr.h
new file mode 100644
index 0000000..0673b7d
--- /dev/null
+++ b/qemu-0.15.x/linux-user/ppc/syscall_nr.h
@@ -0,0 +1,364 @@
+/*
+ * This file contains the system call numbers.
+ */
+#define TARGET_NR_restart_syscall          0
+#define TARGET_NR_exit                     1
+#define TARGET_NR_fork                     2
+#define TARGET_NR_read                     3
+#define TARGET_NR_write                    4
+#define TARGET_NR_open                     5
+#define TARGET_NR_close                    6
+#define TARGET_NR_waitpid                  7
+#define TARGET_NR_creat                    8
+#define TARGET_NR_link                     9
+#define TARGET_NR_unlink                  10
+#define TARGET_NR_execve                  11
+#define TARGET_NR_chdir                   12
+#define TARGET_NR_time                    13
+#define TARGET_NR_mknod                   14
+#define TARGET_NR_chmod                   15
+#define TARGET_NR_lchown                  16
+#define TARGET_NR_break                   17
+#define TARGET_NR_oldstat                 18
+#define TARGET_NR_lseek                   19
+#define TARGET_NR_getpid                  20
+#define TARGET_NR_mount                   21
+#define TARGET_NR_umount                  22
+#define TARGET_NR_setuid                  23
+#define TARGET_NR_getuid                  24
+#define TARGET_NR_stime                   25
+#define TARGET_NR_ptrace                  26
+#define TARGET_NR_alarm                   27
+#define TARGET_NR_oldfstat                28
+#define TARGET_NR_pause                   29
+#define TARGET_NR_utime                   30
+#define TARGET_NR_stty                    31
+#define TARGET_NR_gtty                    32
+#define TARGET_NR_access                  33
+#define TARGET_NR_nice                    34
+#define TARGET_NR_ftime                   35
+#define TARGET_NR_sync                    36
+#define TARGET_NR_kill                    37
+#define TARGET_NR_rename                  38
+#define TARGET_NR_mkdir                   39
+#define TARGET_NR_rmdir                   40
+#define TARGET_NR_dup                     41
+#define TARGET_NR_pipe                    42
+#define TARGET_NR_times                   43
+#define TARGET_NR_prof                    44
+#define TARGET_NR_brk                     45
+#define TARGET_NR_setgid                  46
+#define TARGET_NR_getgid                  47
+#define TARGET_NR_signal                  48
+#define TARGET_NR_geteuid                 49
+#define TARGET_NR_getegid                 50
+#define TARGET_NR_acct                    51
+#define TARGET_NR_umount2                 52
+#define TARGET_NR_lock                    53
+#define TARGET_NR_ioctl                   54
+#define TARGET_NR_fcntl                   55
+#define TARGET_NR_mpx                     56
+#define TARGET_NR_setpgid                 57
+#define TARGET_NR_ulimit                  58
+#define TARGET_NR_oldolduname             59
+#define TARGET_NR_umask                   60
+#define TARGET_NR_chroot                  61
+#define TARGET_NR_ustat                   62
+#define TARGET_NR_dup2                    63
+#define TARGET_NR_getppid                 64
+#define TARGET_NR_getpgrp                 65
+#define TARGET_NR_setsid                  66
+#define TARGET_NR_sigaction               67
+#define TARGET_NR_sgetmask                68
+#define TARGET_NR_ssetmask                69
+#define TARGET_NR_setreuid                70
+#define TARGET_NR_setregid                71
+#define TARGET_NR_sigsuspend              72
+#define TARGET_NR_sigpending              73
+#define TARGET_NR_sethostname             74
+#define TARGET_NR_setrlimit               75
+#define TARGET_NR_getrlimit               76
+#define TARGET_NR_getrusage               77
+#define TARGET_NR_gettimeofday            78
+#define TARGET_NR_settimeofday            79
+#define TARGET_NR_getgroups               80
+#define TARGET_NR_setgroups               81
+#define TARGET_NR_select                  82
+#define TARGET_NR_symlink                 83
+#define TARGET_NR_oldlstat                84
+#define TARGET_NR_readlink                85
+#define TARGET_NR_uselib                  86
+#define TARGET_NR_swapon                  87
+#define TARGET_NR_reboot                  88
+#define TARGET_NR_readdir                 89
+#define TARGET_NR_mmap                    90
+#define TARGET_NR_munmap                  91
+#define TARGET_NR_truncate                92
+#define TARGET_NR_ftruncate               93
+#define TARGET_NR_fchmod                  94
+#define TARGET_NR_fchown                  95
+#define TARGET_NR_getpriority             96
+#define TARGET_NR_setpriority             97
+#define TARGET_NR_profil                  98
+#define TARGET_NR_statfs                  99
+#define TARGET_NR_fstatfs                100
+#define TARGET_NR_ioperm                 101
+#define TARGET_NR_socketcall             102
+#define TARGET_NR_syslog                 103
+#define TARGET_NR_setitimer              104
+#define TARGET_NR_getitimer              105
+#define TARGET_NR_stat                   106
+#define TARGET_NR_lstat                  107
+#define TARGET_NR_fstat                  108
+#define TARGET_NR_olduname               109
+#define TARGET_NR_iopl                   110
+#define TARGET_NR_vhangup                111
+#define TARGET_NR_idle                   112
+#define TARGET_NR_vm86                   113
+#define TARGET_NR_wait4                  114
+#define TARGET_NR_swapoff                115
+#define TARGET_NR_sysinfo                116
+#define TARGET_NR_ipc                    117
+#define TARGET_NR_fsync                  118
+#define TARGET_NR_sigreturn              119
+#define TARGET_NR_clone                  120
+#define TARGET_NR_setdomainname          121
+#define TARGET_NR_uname                  122
+#define TARGET_NR_modify_ldt             123
+#define TARGET_NR_adjtimex               124
+#define TARGET_NR_mprotect               125
+#define TARGET_NR_sigprocmask            126
+#define TARGET_NR_create_module          127
+#define TARGET_NR_init_module            128
+#define TARGET_NR_delete_module          129
+#define TARGET_NR_get_kernel_syms        130
+#define TARGET_NR_quotactl               131
+#define TARGET_NR_getpgid                132
+#define TARGET_NR_fchdir                 133
+#define TARGET_NR_bdflush                134
+#define TARGET_NR_sysfs                  135
+#define TARGET_NR_personality            136
+#define TARGET_NR_afs_syscall            137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid               138
+#define TARGET_NR_setfsgid               139
+#define TARGET_NR__llseek                140
+#define TARGET_NR_getdents               141
+#define TARGET_NR__newselect             142
+#define TARGET_NR_flock                  143
+#define TARGET_NR_msync                  144
+#define TARGET_NR_readv                  145
+#define TARGET_NR_writev                 146
+#define TARGET_NR_getsid                 147
+#define TARGET_NR_fdatasync              148
+#define TARGET_NR__sysctl                149
+#define TARGET_NR_mlock                  150
+#define TARGET_NR_munlock                151
+#define TARGET_NR_mlockall               152
+#define TARGET_NR_munlockall             153
+#define TARGET_NR_sched_setparam         154
+#define TARGET_NR_sched_getparam         155
+#define TARGET_NR_sched_setscheduler     156
+#define TARGET_NR_sched_getscheduler     157
+#define TARGET_NR_sched_yield            158
+#define TARGET_NR_sched_get_priority_max 159
+#define TARGET_NR_sched_get_priority_min 160
+#define TARGET_NR_sched_rr_get_interval  161
+#define TARGET_NR_nanosleep              162
+#define TARGET_NR_mremap                 163
+#define TARGET_NR_setresuid32            164
+#define TARGET_NR_getresuid32            165
+#define TARGET_NR_query_module           166
+#define TARGET_NR_poll                   167
+#define TARGET_NR_nfsservctl             168
+#define TARGET_NR_setresgid32            169
+#define TARGET_NR_getresgid32            170
+#define TARGET_NR_prctl                  171
+#define TARGET_NR_rt_sigreturn           172
+#define TARGET_NR_rt_sigaction           173
+#define TARGET_NR_rt_sigprocmask         174
+#define TARGET_NR_rt_sigpending          175
+#define TARGET_NR_rt_sigtimedwait        176
+#define TARGET_NR_rt_sigqueueinfo        177
+#define TARGET_NR_rt_sigsuspend          178
+#define TARGET_NR_pread64                179
+#define TARGET_NR_pwrite64               180
+#define TARGET_NR_chown                  181
+#define TARGET_NR_getcwd                 182
+#define TARGET_NR_capget                 183
+#define TARGET_NR_capset                 184
+#define TARGET_NR_sigaltstack            185
+#define TARGET_NR_sendfile               186
+#define TARGET_NR_getpmsg                187     /* some people actually want streams */
+#define TARGET_NR_putpmsg                188     /* some people actually want streams */
+#define TARGET_NR_vfork                  189
+#define TARGET_NR_ugetrlimit             190     /* SuS compliant getrlimit */
+#define TARGET_NR_readahead              191
+#if !defined(TARGET_PPC64) || defined(TARGET_ABI32)
+#define TARGET_NR_mmap2                  192
+#define TARGET_NR_truncate64             193
+#define TARGET_NR_ftruncate64            194
+#define TARGET_NR_stat64                 195
+#define TARGET_NR_lstat64                196
+#define TARGET_NR_fstat64                197
+#endif
+#define TARGET_NR_pciconfig_read         198
+#define TARGET_NR_pciconfig_write        199
+#define TARGET_NR_pciconfig_iobase       200
+#define TARGET_NR_multiplexer            201
+#define TARGET_NR_getdents64             202
+#define TARGET_NR_pivot_root             203
+#if !defined(TARGET_PPC64) || defined(TARGET_ABI32)
+#define TARGET_NR_fcntl64                204
+#endif
+#define TARGET_NR_madvise                205
+#define TARGET_NR_mincore                206
+#define TARGET_NR_gettid                 207
+#define TARGET_NR_tkill                  208
+#define TARGET_NR_setxattr               209
+#define TARGET_NR_lsetxattr              210
+#define TARGET_NR_fsetxattr              211
+#define TARGET_NR_getxattr               212
+#define TARGET_NR_lgetxattr              213
+#define TARGET_NR_fgetxattr              214
+#define TARGET_NR_listxattr              215
+#define TARGET_NR_llistxattr             216
+#define TARGET_NR_flistxattr             217
+#define TARGET_NR_removexattr            218
+#define TARGET_NR_lremovexattr           219
+#define TARGET_NR_fremovexattr           220
+#define TARGET_NR_futex                  221
+#define TARGET_NR_sched_setaffinity      222
+#define TARGET_NR_sched_getaffinity      223
+/* 224 currently unused */
+#define TARGET_NR_tuxcall                225
+#if !defined(TARGET_PPC64) || defined(TARGET_ABI32)
+#define TARGET_NR_sendfile64             226
+#endif
+#define TARGET_NR_io_setup               227
+#define TARGET_NR_io_destroy             228
+#define TARGET_NR_io_getevents           229
+#define TARGET_NR_io_submit              230
+#define TARGET_NR_io_cancel              231
+#define TARGET_NR_set_tid_address        232
+#define TARGET_NR_fadvise64              233
+#define TARGET_NR_exit_group             234
+#define TARGET_NR_lookup_dcookie         235
+#define TARGET_NR_epoll_create           236
+#define TARGET_NR_epoll_ctl              237
+#define TARGET_NR_epoll_wait             238
+#define TARGET_NR_remap_file_pages       239
+#define TARGET_NR_timer_create           240
+#define TARGET_NR_timer_settime          241
+#define TARGET_NR_timer_gettime          242
+#define TARGET_NR_timer_getoverrun       243
+#define TARGET_NR_timer_delete           244
+#define TARGET_NR_clock_settime          245
+#define TARGET_NR_clock_gettime          246
+#define TARGET_NR_clock_getres           247
+#define TARGET_NR_clock_nanosleep        248
+#define TARGET_NR_swapcontext            249
+#define TARGET_NR_tgkill                 250
+#define TARGET_NR_utimes                 251
+#define TARGET_NR_statfs64               252
+#define TARGET_NR_fstatfs64              253
+#if !defined(TARGET_PPC64) || defined(TARGET_ABI32)
+#define TARGET_NR_fadvise64_64           254
+#endif
+#define TARGET_NR_rtas		255
+#define TARGET_NR_sys_debug_setcontext 256
+/* Number 257 is reserved for vserver */
+#define TARGET_NR_migrate_pages	258
+#define TARGET_NR_mbind		259
+#define TARGET_NR_get_mempolicy	260
+#define TARGET_NR_set_mempolicy	261
+#define TARGET_NR_mq_open		262
+#define TARGET_NR_mq_unlink		263
+#define TARGET_NR_mq_timedsend	264
+#define TARGET_NR_mq_timedreceive	265
+#define TARGET_NR_mq_notify		266
+#define TARGET_NR_mq_getsetattr	267
+#define TARGET_NR_kexec_load		268
+#define TARGET_NR_add_key		269
+#define TARGET_NR_request_key	270
+#define TARGET_NR_keyctl		271
+#define TARGET_NR_waitid		272
+#define TARGET_NR_ioprio_set		273
+#define TARGET_NR_ioprio_get		274
+#define TARGET_NR_inotify_init	275
+#define TARGET_NR_inotify_add_watch	276
+#define TARGET_NR_inotify_rm_watch	277
+#define TARGET_NR_spu_run		278
+#define TARGET_NR_spu_create		279
+#define TARGET_NR_pselect6		280
+#define TARGET_NR_ppoll		281
+#define TARGET_NR_unshare		282
+#define TARGET_NR_splice		283
+#define TARGET_NR_tee		284
+#define TARGET_NR_vmsplice		285
+#define TARGET_NR_openat		286
+#define TARGET_NR_mkdirat		287
+#define TARGET_NR_mknodat		288
+#define TARGET_NR_fchownat		289
+#define TARGET_NR_futimesat		290
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+#define TARGET_NR_newfstatat		291
+#else
+#define TARGET_NR_fstatat64		291
+#endif
+#define TARGET_NR_unlinkat		292
+#define TARGET_NR_renameat		293
+#define TARGET_NR_linkat		294
+#define TARGET_NR_symlinkat		295
+#define TARGET_NR_readlinkat		296
+#define TARGET_NR_fchmodat		297
+#define TARGET_NR_faccessat		298
+#define TARGET_NR_get_robust_list	299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_move_pages		301
+#define TARGET_NR_getcpu		302
+#define TARGET_NR_epoll_pwait	303
+#define TARGET_NR_utimensat		304
+#define TARGET_NR_signalfd		305
+#define TARGET_NR_timerfd		306
+#define TARGET_NR_eventfd		307
+#define TARGET_NR_sync_file_range2	308
+#define TARGET_NR_fallocate		309
+#define TARGET_NR_subpage_prot		310
+#define TARGET_NR_timerfd_settime	311
+#define TARGET_NR_timerfd_gettime	312
+#define TARGET_NR_signalfd4		313
+#define TARGET_NR_eventfd2		314
+#define TARGET_NR_epoll_create1	315
+#define TARGET_NR_dup3			316
+#define TARGET_NR_pipe2		317
+#define TARGET_NR_inotify_init1	318
+#define TARGET_NR_perf_event_open       319
+#define TARGET_NR_preadv                320
+#define TARGET_NR_pwritev               321
+#define TARGET_NR_rt_tgsigqueueinfo     322
+#define TARGET_NR_fanotify_init         323
+#define TARGET_NR_fanotify_mark         324
+#define TARGET_NR_prlimit64             325
+#define TARGET_NR_socket                326
+#define TARGET_NR_bind                  327
+#define TARGET_NR_connect               328
+#define TARGET_NR_listen                329
+#define TARGET_NR_accept                330
+#define TARGET_NR_getsockname           331
+#define TARGET_NR_getpeername           332
+#define TARGET_NR_socketpair            333
+#define TARGET_NR_send                  334
+#define TARGET_NR_sendto                335
+#define TARGET_NR_recv                  336
+#define TARGET_NR_recvfrom              337
+#define TARGET_NR_shutdown              338
+#define TARGET_NR_setsockopt            339
+#define TARGET_NR_getsockopt            340
+#define TARGET_NR_sendmsg               341
+#define TARGET_NR_recvmsg               342
+#define TARGET_NR_recvmmsg              343
+#define TARGET_NR_accept4               344
+#define TARGET_NR_name_to_handle_at     345
+#define TARGET_NR_open_by_handle_at     346
+#define TARGET_NR_clock_adjtime         347
+#define TARGET_NR_syncfs                348
diff --git a/qemu-0.15.x/linux-user/ppc/target_signal.h b/qemu-0.15.x/linux-user/ppc/target_signal.h
new file mode 100644
index 0000000..a93b5cf
--- /dev/null
+++ b/qemu-0.15.x/linux-user/ppc/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	int ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state)
+{
+    return state->gpr[1];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/ppc/termbits.h b/qemu-0.15.x/linux-user/ppc/termbits.h
new file mode 100644
index 0000000..73e7151
--- /dev/null
+++ b/qemu-0.15.x/linux-user/ppc/termbits.h
@@ -0,0 +1,236 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+    unsigned char c_line;                    /* line discipline */
+    unsigned int c_ispeed;		/* input speed */
+    unsigned int c_ospeed;		/* output speed */
+};
+
+/* c_cc character offsets */
+#define TARGET_VINTR 	0
+#define TARGET_VQUIT 	1
+#define TARGET_VERASE 	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VMIN	5
+#define TARGET_VEOL	6
+#define TARGET_VTIME	7
+#define TARGET_VEOL2	8
+#define TARGET_VSWTC	9
+
+#define TARGET_VWERASE 	10
+#define TARGET_VREPRINT	11
+#define TARGET_VSUSP 		12
+#define TARGET_VSTART		13
+#define TARGET_VSTOP		14
+#define TARGET_VLNEXT		15
+#define TARGET_VDISCARD	16
+
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IXON	0001000
+#define TARGET_IXOFF	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IUCLC	0010000
+#define TARGET_IMAXBEL	0020000
+#define	TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_ONLCR	0000002
+#define TARGET_OLCUC	0000004
+
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+
+#define TARGET_OFILL	00000100
+#define TARGET_OFDEL	00000200
+#define TARGET_NLDLY	00001400
+#define   TARGET_NL0	00000000
+#define   TARGET_NL1	00000400
+#define   TARGET_NL2	00001000
+#define   TARGET_NL3	00001400
+#define TARGET_TABDLY	00006000
+#define   TARGET_TAB0	00000000
+#define   TARGET_TAB1	00002000
+#define   TARGET_TAB2	00004000
+#define   TARGET_TAB3	00006000
+#define   TARGET_XTABS	00006000	/* required by POSIX to == TAB3 */
+#define TARGET_CRDLY	00030000
+#define   TARGET_CR0	00000000
+#define   TARGET_CR1	00010000
+#define   TARGET_CR2	00020000
+#define   TARGET_CR3	00030000
+#define TARGET_FFDLY	00040000
+#define   TARGET_FF0	00000000
+#define   TARGET_FF1	00040000
+#define TARGET_BSDLY	00100000
+#define   TARGET_BS0	00000000
+#define   TARGET_BS1	00100000
+#define TARGET_VTDLY	00200000
+#define   TARGET_VT0	00000000
+#define   TARGET_VT1	00200000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0000377
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define  TARGET_B57600   00020
+#define  TARGET_B115200  00021
+#define  TARGET_B230400  00022
+#define  TARGET_B460800  00023
+#define  TARGET_B500000  00024
+#define  TARGET_B576000  00025
+#define  TARGET_B921600  00026
+#define TARGET_B1000000  00027
+#define TARGET_B1152000  00030
+#define TARGET_B1500000  00031
+#define TARGET_B2000000  00032
+#define TARGET_B2500000  00033
+#define TARGET_B3000000  00034
+#define TARGET_B3500000  00035
+#define TARGET_B4000000  00036
+
+#define TARGET_CSIZE	00001400
+#define   TARGET_CS5	00000000
+#define   TARGET_CS6	00000400
+#define   TARGET_CS7	00001000
+#define   TARGET_CS8	00001400
+
+#define TARGET_CSTOPB	00002000
+#define TARGET_CREAD	00004000
+#define TARGET_PARENB	00010000
+#define TARGET_PARODD	00020000
+#define TARGET_HUPCL	00040000
+
+#define TARGET_CLOCAL	00100000
+#define TARGET_CMSPAR	010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	020000000000		/* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000080
+#define TARGET_ICANON	0x00000100
+#define TARGET_XCASE	0x00004000
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000002
+#define TARGET_ECHOK	0x00000004
+#define TARGET_ECHONL	0x00000010
+#define TARGET_NOFLSH	0x80000000
+#define TARGET_TOSTOP	0x00400000
+#define TARGET_ECHOCTL	0x00000040
+#define TARGET_ECHOPRT	0x00000020
+#define TARGET_ECHOKE	0x00000001
+#define TARGET_FLUSHO	0x00800000
+#define TARGET_PENDIN	0x20000000
+#define TARGET_IEXTEN	0x00000400
+
+/* ioctls */
+
+#define TARGET_FIOCLEX		TARGET_IO('f', 1)
+#define TARGET_FIONCLEX	        TARGET_IO('f', 2)
+#define TARGET_FIOASYNC	        TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO		TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD	        TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+//#define TARGET_FIOQSIZE	        TARGET_IOR('f', 128, loff_t)
+
+#define TARGET_TCGETS		TARGET_IOR('t', 19, struct target_termios)
+#define TARGET_TCSETS		TARGET_IOW('t', 20, struct target_termios)
+#define TARGET_TCSETSW		TARGET_IOW('t', 21, struct target_termios)
+#define TARGET_TCSETSF		TARGET_IOW('t', 22, struct target_termios)
+
+#define TARGET_TCGETA		TARGET_IOR('t', 23, struct target_termio)
+#define TARGET_TCSETA		TARGET_IOW('t', 24, struct target_termio)
+#define TARGET_TCSETAW		TARGET_IOW('t', 25, struct target_termio)
+#define TARGET_TCSETAF		TARGET_IOW('t', 28, struct target_termio)
+
+#define TARGET_TCSBRK		TARGET_IO('t', 29)
+#define TARGET_TCXONC		TARGET_IO('t', 30)
+#define TARGET_TCFLSH		TARGET_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct target_winsize)
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct target_winsize)
+#define	TARGET_TIOCSTART	TARGET_IO('t', 110)		/* start output, like ^Q */
+#define	TARGET_TIOCSTOP	TARGET_IO('t', 111)		/* stop output, like ^S */
+#define TARGET_TIOCOUTQ        TARGET_IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCGLTC	TARGET_IOR('t', 116, struct target_ltchars)
+#define TARGET_TIOCSLTC	TARGET_IOW('t', 117, struct target_ltchars)
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
diff --git a/qemu-0.15.x/linux-user/qemu-types.h b/qemu-0.15.x/linux-user/qemu-types.h
new file mode 100644
index 0000000..1adda9f
--- /dev/null
+++ b/qemu-0.15.x/linux-user/qemu-types.h
@@ -0,0 +1,24 @@
+#ifndef QEMU_TYPES_H
+#define QEMU_TYPES_H
+#include "cpu.h"
+
+#ifdef TARGET_ABI32
+typedef uint32_t abi_ulong;
+typedef int32_t abi_long;
+#define TARGET_ABI_FMT_lx "%08x"
+#define TARGET_ABI_FMT_ld "%d"
+#define TARGET_ABI_FMT_lu "%u"
+#define TARGET_ABI_BITS 32
+#else
+typedef target_ulong abi_ulong;
+typedef target_long abi_long;
+#define TARGET_ABI_FMT_lx TARGET_FMT_lx
+#define TARGET_ABI_FMT_ld TARGET_FMT_ld
+#define TARGET_ABI_FMT_lu TARGET_FMT_lu
+#define TARGET_ABI_BITS TARGET_LONG_BITS
+/* for consistency, define ABI32 too */
+#if TARGET_ABI_BITS == 32
+#define TARGET_ABI32 1
+#endif
+#endif
+#endif
diff --git a/qemu-0.15.x/linux-user/qemu.h b/qemu-0.15.x/linux-user/qemu.h
new file mode 100644
index 0000000..627c8b3
--- /dev/null
+++ b/qemu-0.15.x/linux-user/qemu.h
@@ -0,0 +1,451 @@
+#ifndef QEMU_H
+#define QEMU_H
+
+#include <signal.h>
+#include <string.h>
+
+#include "cpu.h"
+
+#undef DEBUG_REMAP
+#ifdef DEBUG_REMAP
+#include <stdlib.h>
+#endif /* DEBUG_REMAP */
+
+#include "qemu-types.h"
+
+#include "thunk.h"
+#include "syscall_defs.h"
+#include "syscall.h"
+#include "target_signal.h"
+#include "gdbstub.h"
+#include "qemu-queue.h"
+
+#if defined(CONFIG_USE_NPTL)
+#define THREAD __thread
+#else
+#define THREAD
+#endif
+
+/* This struct is used to hold certain information about the image.
+ * Basically, it replicates in user space what would be certain
+ * task_struct fields in the kernel
+ */
+struct image_info {
+        abi_ulong       load_bias;
+        abi_ulong       load_addr;
+        abi_ulong       start_code;
+        abi_ulong       end_code;
+        abi_ulong       start_data;
+        abi_ulong       end_data;
+        abi_ulong       start_brk;
+        abi_ulong       brk;
+        abi_ulong       start_mmap;
+        abi_ulong       mmap;
+        abi_ulong       rss;
+        abi_ulong       start_stack;
+        abi_ulong       stack_limit;
+        abi_ulong       entry;
+        abi_ulong       code_offset;
+        abi_ulong       data_offset;
+        abi_ulong       saved_auxv;
+        abi_ulong       arg_start;
+        abi_ulong       arg_end;
+	int		personality;
+#ifdef CONFIG_USE_FDPIC
+        abi_ulong       loadmap_addr;
+        uint16_t        nsegs;
+        void           *loadsegs;
+        abi_ulong       pt_dynamic_addr;
+        struct image_info *other_info;
+#endif
+};
+
+#ifdef TARGET_I386
+/* Information about the current linux thread */
+struct vm86_saved_state {
+    uint32_t eax; /* return code */
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t ebp;
+    uint32_t esp;
+    uint32_t eflags;
+    uint32_t eip;
+    uint16_t cs, ss, ds, es, fs, gs;
+};
+#endif
+
+#ifdef TARGET_ARM
+/* FPU emulator */
+#include "nwfpe/fpa11.h"
+#endif
+
+#define MAX_SIGQUEUE_SIZE 1024
+
+struct sigqueue {
+    struct sigqueue *next;
+    target_siginfo_t info;
+};
+
+struct emulated_sigtable {
+    int pending; /* true if signal is pending */
+    struct sigqueue *first;
+    struct sigqueue info; /* in order to always have memory for the
+                             first signal, we put it here */
+};
+
+/* NOTE: we force a big alignment so that the stack stored after is
+   aligned too */
+typedef struct TaskState {
+    pid_t ts_tid;     /* tid (or pid) of this task */
+#ifdef TARGET_ARM
+    /* FPA state */
+    FPA11 fpa;
+    int swi_errno;
+#endif
+#ifdef TARGET_UNICORE32
+    int swi_errno;
+#endif
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+    abi_ulong target_v86;
+    struct vm86_saved_state vm86_saved_regs;
+    struct target_vm86plus_struct vm86plus;
+    uint32_t v86flags;
+    uint32_t v86mask;
+#endif
+#ifdef CONFIG_USE_NPTL
+    abi_ulong child_tidptr;
+#endif
+#ifdef TARGET_M68K
+    int sim_syscalls;
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+    /* Extra fields for semihosted binaries.  */
+    uint32_t stack_base;
+    uint32_t heap_base;
+    uint32_t heap_limit;
+#endif
+    int used; /* non zero if used */
+    struct image_info *info;
+    struct linux_binprm *bprm;
+
+    struct emulated_sigtable sigtab[TARGET_NSIG];
+    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct sigqueue *first_free; /* first free siginfo queue entry */
+    int signal_pending; /* non zero if a signal may be pending */
+} __attribute__((aligned(16))) TaskState;
+
+extern char *exec_path;
+void init_task_state(TaskState *ts);
+void task_settid(TaskState *);
+void stop_all_tasks(void);
+extern const char *qemu_uname_release;
+extern unsigned long mmap_min_addr;
+
+/* ??? See if we can avoid exposing so much of the loader internals.  */
+/*
+ * MAX_ARG_PAGES defines the number of pages allocated for arguments
+ * and envelope for the new program. 32 should suffice, this gives
+ * a maximum env+arg of 128kB w/4KB pages!
+ */
+#define MAX_ARG_PAGES 33
+
+/* Read a good amount of data initially, to hopefully get all the
+   program headers loaded.  */
+#define BPRM_BUF_SIZE  1024
+
+/*
+ * This structure is used to hold the arguments that are
+ * used when loading binaries.
+ */
+struct linux_binprm {
+        char buf[BPRM_BUF_SIZE] __attribute__((aligned));
+        void *page[MAX_ARG_PAGES];
+        abi_ulong p;
+	int fd;
+        int e_uid, e_gid;
+        int argc, envc;
+        char **argv;
+        char **envp;
+        char * filename;        /* Name of binary */
+        int (*core_dump)(int, const CPUState *); /* coredump routine */
+};
+
+void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
+abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
+                              abi_ulong stringp, int push_ptr);
+int loader_exec(const char * filename, char ** argv, char ** envp,
+             struct target_pt_regs * regs, struct image_info *infop,
+             struct linux_binprm *);
+
+int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
+                    struct image_info * info);
+
+abi_long memcpy_to_target(abi_ulong dest, const void *src,
+                          unsigned long len);
+void target_set_brk(abi_ulong new_brk);
+abi_long do_brk(abi_ulong new_brk);
+void syscall_init(void);
+abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
+                    abi_long arg2, abi_long arg3, abi_long arg4,
+                    abi_long arg5, abi_long arg6, abi_long arg7,
+                    abi_long arg8);
+void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+extern THREAD CPUState *thread_env;
+void cpu_loop(CPUState *env);
+char *target_strerror(int err);
+int get_osversion(void);
+void fork_start(void);
+void fork_end(int child);
+
+#include "qemu-log.h"
+
+/* strace.c */
+void print_syscall(int num,
+                   abi_long arg1, abi_long arg2, abi_long arg3,
+                   abi_long arg4, abi_long arg5, abi_long arg6);
+void print_syscall_ret(int num, abi_long arg1);
+extern int do_strace;
+
+/* signal.c */
+void process_pending_signals(CPUState *cpu_env);
+void signal_init(void);
+int queue_signal(CPUState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+long do_sigreturn(CPUState *env);
+long do_rt_sigreturn(CPUState *env);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+
+#ifdef TARGET_I386
+/* vm86.c */
+void save_v86_state(CPUX86State *env);
+void handle_vm86_trap(CPUX86State *env, int trapno);
+void handle_vm86_fault(CPUX86State *env);
+int do_vm86(CPUX86State *env, long subfunction, abi_ulong v86_addr);
+#elif defined(TARGET_SPARC64)
+void sparc64_set_context(CPUSPARCState *env);
+void sparc64_get_context(CPUSPARCState *env);
+#endif
+
+/* mmap.c */
+int target_mprotect(abi_ulong start, abi_ulong len, int prot);
+abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
+                     int flags, int fd, abi_ulong offset);
+int target_munmap(abi_ulong start, abi_ulong len);
+abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
+                       abi_ulong new_size, unsigned long flags,
+                       abi_ulong new_addr);
+int target_msync(abi_ulong start, abi_ulong len, int flags);
+extern unsigned long last_brk;
+void mmap_lock(void);
+void mmap_unlock(void);
+abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
+void cpu_list_lock(void);
+void cpu_list_unlock(void);
+#if defined(CONFIG_USE_NPTL)
+void mmap_fork_start(void);
+void mmap_fork_end(int child);
+#endif
+
+/* main.c */
+extern unsigned long guest_stack_size;
+
+/* user access */
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1 /* implies read access */
+
+static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
+{
+    return page_check_range((target_ulong)addr, size,
+                            (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
+}
+
+/* NOTE __get_user and __put_user use host pointers and don't check access. */
+/* These are usually used to access struct data members once the
+ * struct has been locked - usually with lock_user_struct().
+ */
+#define __put_user(x, hptr)\
+({\
+    switch(sizeof(*hptr)) {\
+    case 1:\
+        *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\
+        break;\
+    case 2:\
+        *(uint16_t *)(hptr) = tswap16((uint16_t)(typeof(*hptr))(x));\
+        break;\
+    case 4:\
+        *(uint32_t *)(hptr) = tswap32((uint32_t)(typeof(*hptr))(x));\
+        break;\
+    case 8:\
+        *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\
+        break;\
+    default:\
+        abort();\
+    }\
+    0;\
+})
+
+#define __get_user(x, hptr) \
+({\
+    switch(sizeof(*hptr)) {\
+    case 1:\
+        x = (typeof(*hptr))*(uint8_t *)(hptr);\
+        break;\
+    case 2:\
+        x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\
+        break;\
+    case 4:\
+        x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\
+        break;\
+    case 8:\
+        x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\
+        break;\
+    default:\
+        /* avoid warning */\
+        x = 0;\
+        abort();\
+    }\
+    0;\
+})
+
+/* put_user()/get_user() take a guest address and check access */
+/* These are usually used to access an atomic data type, such as an int,
+ * that has been passed by address.  These internally perform locking
+ * and unlocking on the data type.
+ */
+#define put_user(x, gaddr, target_type)					\
+({									\
+    abi_ulong __gaddr = (gaddr);					\
+    target_type *__hptr;						\
+    abi_long __ret;							\
+    if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \
+        __ret = __put_user((x), __hptr);				\
+        unlock_user(__hptr, __gaddr, sizeof(target_type));		\
+    } else								\
+        __ret = -TARGET_EFAULT;						\
+    __ret;								\
+})
+
+#define get_user(x, gaddr, target_type)					\
+({									\
+    abi_ulong __gaddr = (gaddr);					\
+    target_type *__hptr;						\
+    abi_long __ret;							\
+    if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \
+        __ret = __get_user((x), __hptr);				\
+        unlock_user(__hptr, __gaddr, 0);				\
+    } else {								\
+        /* avoid warning */						\
+        (x) = 0;							\
+        __ret = -TARGET_EFAULT;						\
+    }									\
+    __ret;								\
+})
+
+#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong)
+#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long)
+#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t)
+#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t)
+#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t)
+#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t)
+#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t)
+#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t)
+#define put_user_u8(x, gaddr)  put_user((x), (gaddr), uint8_t)
+#define put_user_s8(x, gaddr)  put_user((x), (gaddr), int8_t)
+
+#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong)
+#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long)
+#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t)
+#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t)
+#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t)
+#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t)
+#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t)
+#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t)
+#define get_user_u8(x, gaddr)  get_user((x), (gaddr), uint8_t)
+#define get_user_s8(x, gaddr)  get_user((x), (gaddr), int8_t)
+
+/* copy_from_user() and copy_to_user() are usually used to copy data
+ * buffers between the target and host.  These internally perform
+ * locking/unlocking of the memory.
+ */
+abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
+abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
+
+/* Functions for accessing guest memory.  The tget and tput functions
+   read/write single values, byteswapping as necessary.  The lock_user
+   gets a pointer to a contiguous area of guest memory, but does not perform
+   and byteswapping.  lock_user may return either a pointer to the guest
+   memory, or a temporary buffer.  */
+
+/* Lock an area of guest memory into the host.  If copy is true then the
+   host area will have the same contents as the guest.  */
+static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
+{
+    if (!access_ok(type, guest_addr, len))
+        return NULL;
+#ifdef DEBUG_REMAP
+    {
+        void *addr;
+        addr = malloc(len);
+        if (copy)
+            memcpy(addr, g2h(guest_addr), len);
+        else
+            memset(addr, 0, len);
+        return addr;
+    }
+#else
+    return g2h(guest_addr);
+#endif
+}
+
+/* Unlock an area of guest memory.  The first LEN bytes must be
+   flushed back to guest memory. host_ptr = NULL is explicitly
+   allowed and does nothing. */
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
+                               long len)
+{
+
+#ifdef DEBUG_REMAP
+    if (!host_ptr)
+        return;
+    if (host_ptr == g2h(guest_addr))
+        return;
+    if (len > 0)
+        memcpy(g2h(guest_addr), host_ptr, len);
+    free(host_ptr);
+#endif
+}
+
+/* Return the length of a string in target memory or -TARGET_EFAULT if
+   access error. */
+abi_long target_strlen(abi_ulong gaddr);
+
+/* Like lock_user but for null terminated strings.  */
+static inline void *lock_user_string(abi_ulong guest_addr)
+{
+    abi_long len;
+    len = target_strlen(guest_addr);
+    if (len < 0)
+        return NULL;
+    return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
+}
+
+/* Helper macros for locking/ulocking a target struct.  */
+#define lock_user_struct(type, host_ptr, guest_addr, copy)	\
+    (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
+#define unlock_user_struct(host_ptr, guest_addr, copy)		\
+    unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
+
+#if defined(CONFIG_USE_NPTL)
+#include <pthread.h>
+#endif
+
+#endif /* QEMU_H */
diff --git a/qemu-0.15.x/linux-user/s390x/syscall.h b/qemu-0.15.x/linux-user/s390x/syscall.h
new file mode 100644
index 0000000..c2ea151
--- /dev/null
+++ b/qemu-0.15.x/linux-user/s390x/syscall.h
@@ -0,0 +1,23 @@
+/* this typedef defines how a Program Status Word looks like */
+typedef struct {
+    abi_ulong mask;
+    abi_ulong addr;
+} __attribute__ ((aligned(8))) target_psw_t;
+
+/*
+ * The pt_regs struct defines the way the registers are stored on
+ * the stack during a system call.
+ */
+
+#define TARGET_NUM_GPRS        16
+
+struct target_pt_regs {
+    abi_ulong args[1];
+    target_psw_t psw;
+    abi_ulong gprs[TARGET_NUM_GPRS];
+    abi_ulong orig_gpr2;
+    unsigned short ilc;
+    unsigned short trap;
+};
+
+#define UNAME_MACHINE "s390x"
diff --git a/qemu-0.15.x/linux-user/s390x/syscall_nr.h b/qemu-0.15.x/linux-user/s390x/syscall_nr.h
new file mode 100644
index 0000000..d4529ac
--- /dev/null
+++ b/qemu-0.15.x/linux-user/s390x/syscall_nr.h
@@ -0,0 +1,358 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_exit                 1
+#define TARGET_NR_fork                 2
+#define TARGET_NR_read                 3
+#define TARGET_NR_write                4
+#define TARGET_NR_open                 5
+#define TARGET_NR_close                6
+#define TARGET_NR_restart_syscall	  7
+#define TARGET_NR_creat                8
+#define TARGET_NR_link                 9
+#define TARGET_NR_unlink              10
+#define TARGET_NR_execve              11
+#define TARGET_NR_chdir               12
+#define TARGET_NR_mknod               14
+#define TARGET_NR_chmod               15
+#define TARGET_NR_lseek               19
+#define TARGET_NR_getpid              20
+#define TARGET_NR_mount               21
+#define TARGET_NR_umount              22
+#define TARGET_NR_ptrace              26
+#define TARGET_NR_alarm               27
+#define TARGET_NR_pause               29
+#define TARGET_NR_utime               30
+#define TARGET_NR_access              33
+#define TARGET_NR_nice                34
+#define TARGET_NR_sync                36
+#define TARGET_NR_kill                37
+#define TARGET_NR_rename              38
+#define TARGET_NR_mkdir               39
+#define TARGET_NR_rmdir               40
+#define TARGET_NR_dup                 41
+#define TARGET_NR_pipe                42
+#define TARGET_NR_times               43
+#define TARGET_NR_brk                 45
+#define TARGET_NR_signal              48
+#define TARGET_NR_acct                51
+#define TARGET_NR_umount2             52
+#define TARGET_NR_ioctl               54
+#define TARGET_NR_fcntl               55
+#define TARGET_NR_setpgid             57
+#define TARGET_NR_umask               60
+#define TARGET_NR_chroot              61
+#define TARGET_NR_ustat               62
+#define TARGET_NR_dup2                63
+#define TARGET_NR_getppid             64
+#define TARGET_NR_getpgrp             65
+#define TARGET_NR_setsid              66
+#define TARGET_NR_sigaction           67
+#define TARGET_NR_sigsuspend          72
+#define TARGET_NR_sigpending          73
+#define TARGET_NR_sethostname         74
+#define TARGET_NR_setrlimit           75
+#define TARGET_NR_getrusage           77
+#define TARGET_NR_gettimeofday        78
+#define TARGET_NR_settimeofday        79
+#define TARGET_NR_symlink             83
+#define TARGET_NR_readlink            85
+#define TARGET_NR_uselib              86
+#define TARGET_NR_swapon              87
+#define TARGET_NR_reboot              88
+#define TARGET_NR_readdir             89
+#define TARGET_NR_mmap                90
+#define TARGET_NR_munmap              91
+#define TARGET_NR_truncate            92
+#define TARGET_NR_ftruncate           93
+#define TARGET_NR_fchmod              94
+#define TARGET_NR_getpriority         96
+#define TARGET_NR_setpriority         97
+#define TARGET_NR_statfs              99
+#define TARGET_NR_fstatfs            100
+#define TARGET_NR_socketcall         102
+#define TARGET_NR_syslog             103
+#define TARGET_NR_setitimer          104
+#define TARGET_NR_getitimer          105
+#define TARGET_NR_stat               106
+#define TARGET_NR_lstat              107
+#define TARGET_NR_fstat              108
+#define TARGET_NR_lookup_dcookie     110
+#define TARGET_NR_vhangup            111
+#define TARGET_NR_idle               112
+#define TARGET_NR_wait4              114
+#define TARGET_NR_swapoff            115
+#define TARGET_NR_sysinfo            116
+#define TARGET_NR_ipc                117
+#define TARGET_NR_fsync              118
+#define TARGET_NR_sigreturn          119
+#define TARGET_NR_clone              120
+#define TARGET_NR_setdomainname      121
+#define TARGET_NR_uname              122
+#define TARGET_NR_adjtimex           124
+#define TARGET_NR_mprotect           125
+#define TARGET_NR_sigprocmask        126
+#define TARGET_NR_create_module      127
+#define TARGET_NR_init_module        128
+#define TARGET_NR_delete_module      129
+#define TARGET_NR_get_kernel_syms    130
+#define TARGET_NR_quotactl           131
+#define TARGET_NR_getpgid            132
+#define TARGET_NR_fchdir             133
+#define TARGET_NR_bdflush            134
+#define TARGET_NR_sysfs              135
+#define TARGET_NR_personality        136
+#define TARGET_NR_afs_syscall        137 /* Syscall for Andrew File System */
+#define TARGET_NR_getdents           141
+#define TARGET_NR_flock              143
+#define TARGET_NR_msync              144
+#define TARGET_NR_readv              145
+#define TARGET_NR_writev             146
+#define TARGET_NR_getsid             147
+#define TARGET_NR_fdatasync          148
+#define TARGET_NR__sysctl            149
+#define TARGET_NR_mlock              150
+#define TARGET_NR_munlock            151
+#define TARGET_NR_mlockall           152
+#define TARGET_NR_munlockall         153
+#define TARGET_NR_sched_setparam             154
+#define TARGET_NR_sched_getparam             155
+#define TARGET_NR_sched_setscheduler         156
+#define TARGET_NR_sched_getscheduler         157
+#define TARGET_NR_sched_yield                158
+#define TARGET_NR_sched_get_priority_max     159
+#define TARGET_NR_sched_get_priority_min     160
+#define TARGET_NR_sched_rr_get_interval      161
+#define TARGET_NR_nanosleep          162
+#define TARGET_NR_mremap             163
+#define TARGET_NR_query_module       167
+#define TARGET_NR_poll               168
+#define TARGET_NR_nfsservctl         169
+#define TARGET_NR_prctl              172
+#define TARGET_NR_rt_sigreturn       173
+#define TARGET_NR_rt_sigaction       174
+#define TARGET_NR_rt_sigprocmask     175
+#define TARGET_NR_rt_sigpending      176
+#define TARGET_NR_rt_sigtimedwait    177
+#define TARGET_NR_rt_sigqueueinfo    178
+#define TARGET_NR_rt_sigsuspend      179
+#define TARGET_NR_pread64            180
+#define TARGET_NR_pwrite64           181
+#define TARGET_NR_getcwd             183
+#define TARGET_NR_capget             184
+#define TARGET_NR_capset             185
+#define TARGET_NR_sigaltstack        186
+#define TARGET_NR_sendfile           187
+#define TARGET_NR_getpmsg		188
+#define TARGET_NR_putpmsg		189
+#define TARGET_NR_vfork		190
+#define TARGET_NR_pivot_root         217
+#define TARGET_NR_mincore            218
+#define TARGET_NR_madvise            219
+#define TARGET_NR_getdents64		220
+#define TARGET_NR_readahead		222
+#define TARGET_NR_setxattr		224
+#define TARGET_NR_lsetxattr		225
+#define TARGET_NR_fsetxattr		226
+#define TARGET_NR_getxattr		227
+#define TARGET_NR_lgetxattr		228
+#define TARGET_NR_fgetxattr		229
+#define TARGET_NR_listxattr		230
+#define TARGET_NR_llistxattr		231
+#define TARGET_NR_flistxattr		232
+#define TARGET_NR_removexattr	233
+#define TARGET_NR_lremovexattr	234
+#define TARGET_NR_fremovexattr	235
+#define TARGET_NR_gettid		236
+#define TARGET_NR_tkill		237
+#define TARGET_NR_futex		238
+#define TARGET_NR_sched_setaffinity	239
+#define TARGET_NR_sched_getaffinity	240
+#define TARGET_NR_tgkill		241
+/* Number 242 is reserved for tux */
+#define TARGET_NR_io_setup		243
+#define TARGET_NR_io_destroy		244
+#define TARGET_NR_io_getevents	245
+#define TARGET_NR_io_submit		246
+#define TARGET_NR_io_cancel		247
+#define TARGET_NR_exit_group		248
+#define TARGET_NR_epoll_create	249
+#define TARGET_NR_epoll_ctl		250
+#define TARGET_NR_epoll_wait		251
+#define TARGET_NR_set_tid_address	252
+#define TARGET_NR_fadvise64		253
+#define TARGET_NR_timer_create	254
+#define TARGET_NR_timer_settime	(TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime	(TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete	(TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime	(TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
+/* Number 263 is reserved for vserver */
+#define TARGET_NR_statfs64		265
+#define TARGET_NR_fstatfs64		266
+#define TARGET_NR_remap_file_pages	267
+/* Number 268 is reserved for new sys_mbind */
+/* Number 269 is reserved for new sys_get_mempolicy */
+/* Number 270 is reserved for new sys_set_mempolicy */
+#define TARGET_NR_mq_open		271
+#define TARGET_NR_mq_unlink		272
+#define TARGET_NR_mq_timedsend	273
+#define TARGET_NR_mq_timedreceive	274
+#define TARGET_NR_mq_notify		275
+#define TARGET_NR_mq_getsetattr	276
+#define TARGET_NR_kexec_load		277
+#define TARGET_NR_add_key		278
+#define TARGET_NR_request_key	279
+#define TARGET_NR_keyctl		280
+#define TARGET_NR_waitid		281
+#define TARGET_NR_ioprio_set		282
+#define TARGET_NR_ioprio_get		283
+#define TARGET_NR_inotify_init	284
+#define TARGET_NR_inotify_add_watch	285
+#define TARGET_NR_inotify_rm_watch	286
+/* Number 287 is reserved for new sys_migrate_pages */
+#define TARGET_NR_openat		288
+#define TARGET_NR_mkdirat		289
+#define TARGET_NR_mknodat		290
+#define TARGET_NR_fchownat		291
+#define TARGET_NR_futimesat		292
+#define TARGET_NR_unlinkat		294
+#define TARGET_NR_renameat		295
+#define TARGET_NR_linkat		296
+#define TARGET_NR_symlinkat		297
+#define TARGET_NR_readlinkat		298
+#define TARGET_NR_fchmodat		299
+#define TARGET_NR_faccessat		300
+#define TARGET_NR_pselect6		301
+#define TARGET_NR_ppoll		302
+#define TARGET_NR_unshare		303
+#define TARGET_NR_set_robust_list	304
+#define TARGET_NR_get_robust_list	305
+#define TARGET_NR_splice		306
+#define TARGET_NR_sync_file_range	307
+#define TARGET_NR_tee		308
+#define TARGET_NR_vmsplice		309
+/* Number 310 is reserved for new sys_move_pages */
+#define TARGET_NR_getcpu		311
+#define TARGET_NR_epoll_pwait	312
+#define TARGET_NR_utimes		313
+#define TARGET_NR_fallocate		314
+#define TARGET_NR_utimensat		315
+#define TARGET_NR_signalfd		316
+#define TARGET_NR_timerfd		317
+#define TARGET_NR_eventfd		318
+#define TARGET_NR_timerfd_create	319
+#define TARGET_NR_timerfd_settime	320
+#define TARGET_NR_timerfd_gettime	321
+#define TARGET_NR_signalfd4		322
+#define TARGET_NR_eventfd2		323
+#define TARGET_NR_inotify_init1	324
+#define TARGET_NR_pipe2		325
+#define TARGET_NR_dup3		326
+#define TARGET_NR_epoll_create1	327
+#define TARGET_NR_preadv                328
+#define TARGET_NR_pwritev               329
+#define TARGET_NR_rt_tgsigqueueinfo     330
+#define TARGET_NR_perf_event_open       331
+#define TARGET_NR_fanotify_init         332
+#define TARGET_NR_fanotify_mark         333
+#define TARGET_NR_prlimit64             334
+#define TARGET_NR_name_to_handle_at     335
+#define TARGET_NR_open_by_handle_at     336
+#define TARGET_NR_clock_adjtime         337
+#define TARGET_NR_syncfs                338
+
+/*
+ * There are some system calls that are not present on 64 bit, some
+ * have a different name although they do the same (e.g. TARGET_NR_chown32
+ * is TARGET_NR_chown on 64 bit).
+ */
+#ifndef TARGET_S390X
+
+#define TARGET_NR_time		 13
+#define TARGET_NR_lchown		 16
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getuid		 24
+#define TARGET_NR_stime		 25
+#define TARGET_NR_setgid		 46
+#define TARGET_NR_getgid		 47
+#define TARGET_NR_geteuid		 49
+#define TARGET_NR_getegid		 50
+#define TARGET_NR_setreuid		 70
+#define TARGET_NR_setregid		 71
+#define TARGET_NR_getrlimit		 76
+#define TARGET_NR_getgroups		 80
+#define TARGET_NR_setgroups		 81
+#define TARGET_NR_fchown		 95
+#define TARGET_NR_ioperm		101
+#define TARGET_NR_setfsuid		138
+#define TARGET_NR_setfsgid		139
+#define TARGET_NR__llseek		140
+#define TARGET_NR__newselect 	142
+#define TARGET_NR_setresuid		164
+#define TARGET_NR_getresuid		165
+#define TARGET_NR_setresgid		170
+#define TARGET_NR_getresgid		171
+#define TARGET_NR_chown		182
+#define TARGET_NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define TARGET_NR_mmap2		192
+#define TARGET_NR_truncate64		193
+#define TARGET_NR_ftruncate64	194
+#define TARGET_NR_stat64		195
+#define TARGET_NR_lstat64		196
+#define TARGET_NR_fstat64		197
+#define TARGET_NR_lchown32		198
+#define TARGET_NR_getuid32		199
+#define TARGET_NR_getgid32		200
+#define TARGET_NR_geteuid32		201
+#define TARGET_NR_getegid32		202
+#define TARGET_NR_setreuid32		203
+#define TARGET_NR_setregid32		204
+#define TARGET_NR_getgroups32	205
+#define TARGET_NR_setgroups32	206
+#define TARGET_NR_fchown32		207
+#define TARGET_NR_setresuid32	208
+#define TARGET_NR_getresuid32	209
+#define TARGET_NR_setresgid32	210
+#define TARGET_NR_getresgid32	211
+#define TARGET_NR_chown32		212
+#define TARGET_NR_setuid32		213
+#define TARGET_NR_setgid32		214
+#define TARGET_NR_setfsuid32		215
+#define TARGET_NR_setfsgid32		216
+#define TARGET_NR_fcntl64		221
+#define TARGET_NR_sendfile64		223
+#define TARGET_NR_fadvise64_64	264
+#define TARGET_NR_fstatat64		293
+
+#else
+
+#define TARGET_NR_select		142
+#define TARGET_NR_getrlimit		191	/* SuS compliant getrlimit */
+#define TARGET_NR_lchown  		198
+#define TARGET_NR_getuid  		199
+#define TARGET_NR_getgid  		200
+#define TARGET_NR_geteuid  		201
+#define TARGET_NR_getegid  		202
+#define TARGET_NR_setreuid  		203
+#define TARGET_NR_setregid  		204
+#define TARGET_NR_getgroups  	205
+#define TARGET_NR_setgroups  	206
+#define TARGET_NR_fchown  		207
+#define TARGET_NR_setresuid  	208
+#define TARGET_NR_getresuid  	209
+#define TARGET_NR_setresgid  	210
+#define TARGET_NR_getresgid  	211
+#define TARGET_NR_chown  		212
+#define TARGET_NR_setuid  		213
+#define TARGET_NR_setgid  		214
+#define TARGET_NR_setfsuid  		215
+#define TARGET_NR_setfsgid  		216
+#define TARGET_NR_newfstatat		293
+
+#endif
+
diff --git a/qemu-0.15.x/linux-user/s390x/target_signal.h b/qemu-0.15.x/linux-user/s390x/target_signal.h
new file mode 100644
index 0000000..b4816b0
--- /dev/null
+++ b/qemu-0.15.x/linux-user/s390x/target_signal.h
@@ -0,0 +1,26 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+typedef struct target_sigaltstack {
+    abi_ulong ss_sp;
+    int ss_flags;
+    abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK      1
+#define TARGET_SS_DISABLE      2
+
+#define TARGET_MINSIGSTKSZ     2048
+#define TARGET_SIGSTKSZ        8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state)
+{
+   return state->regs[15];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/s390x/termbits.h b/qemu-0.15.x/linux-user/s390x/termbits.h
new file mode 100644
index 0000000..2a78a05
--- /dev/null
+++ b/qemu-0.15.x/linux-user/s390x/termbits.h
@@ -0,0 +1,283 @@
+/*
+ *  include/asm-s390/termbits.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/termbits.h"
+ */
+
+#define TARGET_NCCS 19
+struct target_termios {
+    unsigned int c_iflag;		/* input mode flags */
+    unsigned int c_oflag;		/* output mode flags */
+    unsigned int c_cflag;		/* control mode flags */
+    unsigned int c_lflag;		/* local mode flags */
+    unsigned char c_line;			/* line discipline */
+    unsigned char c_cc[TARGET_NCCS];		/* control characters */
+};
+
+struct target_termios2 {
+    unsigned int c_iflag;		/* input mode flags */
+    unsigned int c_oflag;		/* output mode flags */
+    unsigned int c_cflag;		/* control mode flags */
+    unsigned int c_lflag;		/* local mode flags */
+    unsigned char c_line;			/* line discipline */
+    unsigned char c_cc[TARGET_NCCS];		/* control characters */
+    unsigned int c_ispeed;		/* input speed */
+    unsigned int c_ospeed;		/* output speed */
+};
+
+struct target_ktermios {
+    unsigned int c_iflag;		/* input mode flags */
+    unsigned int c_oflag;		/* output mode flags */
+    unsigned int c_cflag;		/* control mode flags */
+    unsigned int c_lflag;		/* local mode flags */
+    unsigned char c_line;			/* line discipline */
+    unsigned char c_cc[TARGET_NCCS];		/* control characters */
+    unsigned int c_ispeed;		/* input speed */
+    unsigned int c_ospeed;		/* output speed */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IUCLC	0001000
+#define TARGET_IXON	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IXOFF	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_OLCUC	0000002
+#define TARGET_ONLCR	0000004
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+#define TARGET_OFILL	0000100
+#define TARGET_OFDEL	0000200
+#define TARGET_NLDLY	0000400
+#define TARGET_NL0	0000000
+#define TARGET_NL1	0000400
+#define TARGET_CRDLY	0003000
+#define TARGET_CR0	0000000
+#define TARGET_CR1	0001000
+#define TARGET_CR2	0002000
+#define TARGET_CR3	0003000
+#define TARGET_TABDLY	0014000
+#define TARGET_TAB0	0000000
+#define TARGET_TAB1	0004000
+#define TARGET_TAB2	0010000
+#define TARGET_TAB3	0014000
+#define TARGET_XTABS	0014000
+#define TARGET_BSDLY	0020000
+#define TARGET_BS0	0000000
+#define TARGET_BS1	0020000
+#define TARGET_VTDLY	0040000
+#define TARGET_VT0	0000000
+#define TARGET_VT1	0040000
+#define TARGET_FFDLY	0100000
+#define TARGET_FF0	0000000
+#define TARGET_FF1	0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0010017
+#define TARGET_B0	0000000		/* hang up */
+#define TARGET_B50	0000001
+#define TARGET_B75	0000002
+#define TARGET_B110	0000003
+#define TARGET_B134	0000004
+#define TARGET_B150	0000005
+#define TARGET_B200	0000006
+#define TARGET_B300	0000007
+#define TARGET_B600	0000010
+#define TARGET_B1200	0000011
+#define TARGET_B1800	0000012
+#define TARGET_B2400	0000013
+#define TARGET_B4800	0000014
+#define TARGET_B9600	0000015
+#define TARGET_B19200	0000016
+#define TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE	0000060
+#define TARGET_CS5	0000000
+#define TARGET_CS6	0000020
+#define TARGET_CS7	0000040
+#define TARGET_CS8	0000060
+#define TARGET_CSTOPB	0000100
+#define TARGET_CREAD	0000200
+#define TARGET_PARENB	0000400
+#define TARGET_PARODD	0001000
+#define TARGET_HUPCL	0002000
+#define TARGET_CLOCAL	0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_BOTHER  0010000
+#define TARGET_B57600  0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_B500000 0010005
+#define TARGET_B576000 0010006
+#define TARGET_B921600 0010007
+#define TARGET_B1000000 0010010
+#define TARGET_B1152000 0010011
+#define TARGET_B1500000 0010012
+#define TARGET_B2000000 0010013
+#define TARGET_B2500000 0010014
+#define TARGET_B3000000 0010015
+#define TARGET_B3500000 0010016
+#define TARGET_B4000000 0010017
+#define TARGET_CIBAUD	  002003600000	/* input baud rate */
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+#define TARGET_IBSHIFT	  16		/* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0000001
+#define TARGET_ICANON	0000002
+#define TARGET_XCASE	0000004
+#define TARGET_ECHO	0000010
+#define TARGET_ECHOE	0000020
+#define TARGET_ECHOK	0000040
+#define TARGET_ECHONL	0000100
+#define TARGET_NOFLSH	0000200
+#define TARGET_TOSTOP	0000400
+#define TARGET_ECHOCTL	0001000
+#define TARGET_ECHOPRT	0002000
+#define TARGET_ECHOKE	0004000
+#define TARGET_FLUSHO	0010000
+#define TARGET_PENDIN	0040000
+#define TARGET_IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TARGET_TCOOFF		0
+#define	TARGET_TCOON		1
+#define	TARGET_TCIOFF		2
+#define	TARGET_TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TARGET_TCIFLUSH	0
+#define	TARGET_TCOFLUSH	1
+#define	TARGET_TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TARGET_TCSANOW		0
+#define	TARGET_TCSADRAIN	1
+#define	TARGET_TCSAFLUSH	2
+
+/*
+ *  include/asm-s390/ioctls.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ioctls.h"
+ */
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TARGET_TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TARGET_TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TARGET_TCSETSF2	_IOW('T',0x2D, struct termios2)
+#define TARGET_TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TARGET_TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_FIOQSIZE	0x545E
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
diff --git a/qemu-0.15.x/linux-user/sh4/syscall.h b/qemu-0.15.x/linux-user/sh4/syscall.h
new file mode 100644
index 0000000..014bf58
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sh4/syscall.h
@@ -0,0 +1,12 @@
+struct target_pt_regs {
+        unsigned long regs[16];
+        unsigned long pc;
+        unsigned long pr;
+        unsigned long sr;
+        unsigned long gbr;
+        unsigned long mach;
+        unsigned long macl;
+        long tra;
+};
+
+#define UNAME_MACHINE "sh4"
diff --git a/qemu-0.15.x/linux-user/sh4/syscall_nr.h b/qemu-0.15.x/linux-user/sh4/syscall_nr.h
new file mode 100644
index 0000000..365db58
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sh4/syscall_nr.h
@@ -0,0 +1,368 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_restart_syscall	  0
+#define TARGET_NR_exit		  1
+#define TARGET_NR_fork		  2
+#define TARGET_NR_read		  3
+#define TARGET_NR_write		  4
+#define TARGET_NR_open		  5
+#define TARGET_NR_close		  6
+#define TARGET_NR_waitpid		  7
+#define TARGET_NR_creat		  8
+#define TARGET_NR_link		  9
+#define TARGET_NR_unlink		 10
+#define TARGET_NR_execve		 11
+#define TARGET_NR_chdir		 12
+#define TARGET_NR_time		 13
+#define TARGET_NR_mknod		 14
+#define TARGET_NR_chmod		 15
+#define TARGET_NR_lchown		 16
+#define TARGET_NR_break		 17
+#define TARGET_NR_oldstat		 18
+#define TARGET_NR_lseek		 19
+#define TARGET_NR_getpid		 20
+#define TARGET_NR_mount		 21
+#define TARGET_NR_umount		 22
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getuid		 24
+#define TARGET_NR_stime		 25
+#define TARGET_NR_ptrace		 26
+#define TARGET_NR_alarm		 27
+#define TARGET_NR_oldfstat		 28
+#define TARGET_NR_pause		 29
+#define TARGET_NR_utime		 30
+#define TARGET_NR_stty		 31
+#define TARGET_NR_gtty		 32
+#define TARGET_NR_access		 33
+#define TARGET_NR_nice		 34
+#define TARGET_NR_ftime		 35
+#define TARGET_NR_sync		 36
+#define TARGET_NR_kill		 37
+#define TARGET_NR_rename		 38
+#define TARGET_NR_mkdir		 39
+#define TARGET_NR_rmdir		 40
+#define TARGET_NR_dup		 41
+#define TARGET_NR_pipe		 42
+#define TARGET_NR_times		 43
+#define TARGET_NR_prof		 44
+#define TARGET_NR_brk		 45
+#define TARGET_NR_setgid		 46
+#define TARGET_NR_getgid		 47
+#define TARGET_NR_signal		 48
+#define TARGET_NR_geteuid		 49
+#define TARGET_NR_getegid		 50
+#define TARGET_NR_acct		 51
+#define TARGET_NR_umount2		 52
+#define TARGET_NR_lock		 53
+#define TARGET_NR_ioctl		 54
+#define TARGET_NR_fcntl		 55
+#define TARGET_NR_mpx		 56
+#define TARGET_NR_setpgid		 57
+#define TARGET_NR_ulimit		 58
+#define TARGET_NR_oldolduname	 59
+#define TARGET_NR_umask		 60
+#define TARGET_NR_chroot		 61
+#define TARGET_NR_ustat		 62
+#define TARGET_NR_dup2		 63
+#define TARGET_NR_getppid		 64
+#define TARGET_NR_getpgrp		 65
+#define TARGET_NR_setsid		 66
+#define TARGET_NR_sigaction		 67
+#define TARGET_NR_sgetmask		 68
+#define TARGET_NR_ssetmask		 69
+#define TARGET_NR_setreuid		 70
+#define TARGET_NR_setregid		 71
+#define TARGET_NR_sigsuspend		 72
+#define TARGET_NR_sigpending		 73
+#define TARGET_NR_sethostname	 74
+#define TARGET_NR_setrlimit		 75
+#define TARGET_NR_getrlimit	 	 76	/* Back compatible 2Gig limited rlimit */
+#define TARGET_NR_getrusage		 77
+#define TARGET_NR_gettimeofday	 78
+#define TARGET_NR_settimeofday	 79
+#define TARGET_NR_getgroups		 80
+#define TARGET_NR_setgroups		 81
+#define TARGET_NR_select		 82
+#define TARGET_NR_symlink		 83
+#define TARGET_NR_oldlstat		 84
+#define TARGET_NR_readlink		 85
+#define TARGET_NR_uselib		 86
+#define TARGET_NR_swapon		 87
+#define TARGET_NR_reboot		 88
+#define TARGET_NR_readdir		 89
+#define TARGET_NR_mmap		 90
+#define TARGET_NR_munmap		 91
+#define TARGET_NR_truncate		 92
+#define TARGET_NR_ftruncate		 93
+#define TARGET_NR_fchmod		 94
+#define TARGET_NR_fchown		 95
+#define TARGET_NR_getpriority	 96
+#define TARGET_NR_setpriority	 97
+#define TARGET_NR_profil		 98
+#define TARGET_NR_statfs		 99
+#define TARGET_NR_fstatfs		100
+#define TARGET_NR_ioperm		101
+#define TARGET_NR_socketcall		102
+#define TARGET_NR_syslog		103
+#define TARGET_NR_setitimer		104
+#define TARGET_NR_getitimer		105
+#define TARGET_NR_stat		106
+#define TARGET_NR_lstat		107
+#define TARGET_NR_fstat		108
+#define TARGET_NR_olduname		109
+#define TARGET_NR_iopl		110
+#define TARGET_NR_vhangup		111
+#define TARGET_NR_idle		112
+#define TARGET_NR_vm86old		113
+#define TARGET_NR_wait4		114
+#define TARGET_NR_swapoff		115
+#define TARGET_NR_sysinfo		116
+#define TARGET_NR_ipc		117
+#define TARGET_NR_fsync		118
+#define TARGET_NR_sigreturn		119
+#define TARGET_NR_clone		120
+#define TARGET_NR_setdomainname	121
+#define TARGET_NR_uname		122
+#define TARGET_NR_cacheflush		123
+#define TARGET_NR_adjtimex		124
+#define TARGET_NR_mprotect		125
+#define TARGET_NR_sigprocmask	126
+#define TARGET_NR_create_module	127
+#define TARGET_NR_init_module	128
+#define TARGET_NR_delete_module	129
+#define TARGET_NR_get_kernel_syms	130
+#define TARGET_NR_quotactl		131
+#define TARGET_NR_getpgid		132
+#define TARGET_NR_fchdir		133
+#define TARGET_NR_bdflush		134
+#define TARGET_NR_sysfs		135
+#define TARGET_NR_personality	136
+#define TARGET_NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid		138
+#define TARGET_NR_setfsgid		139
+#define TARGET_NR__llseek		140
+#define TARGET_NR_getdents		141
+#define TARGET_NR__newselect		142
+#define TARGET_NR_flock		143
+#define TARGET_NR_msync		144
+#define TARGET_NR_readv		145
+#define TARGET_NR_writev		146
+#define TARGET_NR_getsid		147
+#define TARGET_NR_fdatasync		148
+#define TARGET_NR__sysctl		149
+#define TARGET_NR_mlock		150
+#define TARGET_NR_munlock		151
+#define TARGET_NR_mlockall		152
+#define TARGET_NR_munlockall		153
+#define TARGET_NR_sched_setparam		154
+#define TARGET_NR_sched_getparam		155
+#define TARGET_NR_sched_setscheduler		156
+#define TARGET_NR_sched_getscheduler		157
+#define TARGET_NR_sched_yield		158
+#define TARGET_NR_sched_get_priority_max	159
+#define TARGET_NR_sched_get_priority_min	160
+#define TARGET_NR_sched_rr_get_interval	161
+#define TARGET_NR_nanosleep		162
+#define TARGET_NR_mremap		163
+#define TARGET_NR_setresuid		164
+#define TARGET_NR_getresuid		165
+#define TARGET_NR_vm86		166
+#define TARGET_NR_query_module	167
+#define TARGET_NR_poll		168
+#define TARGET_NR_nfsservctl		169
+#define TARGET_NR_setresgid		170
+#define TARGET_NR_getresgid		171
+#define TARGET_NR_prctl              172
+#define TARGET_NR_rt_sigreturn	173
+#define TARGET_NR_rt_sigaction	174
+#define TARGET_NR_rt_sigprocmask	175
+#define TARGET_NR_rt_sigpending	176
+#define TARGET_NR_rt_sigtimedwait	177
+#define TARGET_NR_rt_sigqueueinfo	178
+#define TARGET_NR_rt_sigsuspend	179
+#define TARGET_NR_pread64		180
+#define TARGET_NR_pwrite64		181
+#define TARGET_NR_chown		182
+#define TARGET_NR_getcwd		183
+#define TARGET_NR_capget		184
+#define TARGET_NR_capset		185
+#define TARGET_NR_sigaltstack	186
+#define TARGET_NR_sendfile		187
+#define TARGET_NR_streams1		188	/* some people actually want it */
+#define TARGET_NR_streams2		189	/* some people actually want it */
+#define TARGET_NR_vfork		190
+#define TARGET_NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define TARGET_NR_mmap2		192
+#define TARGET_NR_truncate64		193
+#define TARGET_NR_ftruncate64	194
+#define TARGET_NR_stat64		195
+#define TARGET_NR_lstat64		196
+#define TARGET_NR_fstat64		197
+#define TARGET_NR_lchown32		198
+#define TARGET_NR_getuid32		199
+#define TARGET_NR_getgid32		200
+#define TARGET_NR_geteuid32		201
+#define TARGET_NR_getegid32		202
+#define TARGET_NR_setreuid32		203
+#define TARGET_NR_setregid32		204
+#define TARGET_NR_getgroups32	205
+#define TARGET_NR_setgroups32	206
+#define TARGET_NR_fchown32		207
+#define TARGET_NR_setresuid32	208
+#define TARGET_NR_getresuid32	209
+#define TARGET_NR_setresgid32	210
+#define TARGET_NR_getresgid32	211
+#define TARGET_NR_chown32		212
+#define TARGET_NR_setuid32		213
+#define TARGET_NR_setgid32		214
+#define TARGET_NR_setfsuid32		215
+#define TARGET_NR_setfsgid32		216
+#define TARGET_NR_pivot_root		217
+#define TARGET_NR_mincore		218
+#define TARGET_NR_madvise		219
+#define TARGET_NR_getdents64		220
+#define TARGET_NR_fcntl64		221
+/* 223 is unused */
+#define TARGET_NR_gettid		224
+#define TARGET_NR_readahead		225
+#define TARGET_NR_setxattr		226
+#define TARGET_NR_lsetxattr		227
+#define TARGET_NR_fsetxattr		228
+#define TARGET_NR_getxattr		229
+#define TARGET_NR_lgetxattr		230
+#define TARGET_NR_fgetxattr		231
+#define TARGET_NR_listxattr		232
+#define TARGET_NR_llistxattr		233
+#define TARGET_NR_flistxattr		234
+#define TARGET_NR_removexattr	235
+#define TARGET_NR_lremovexattr	236
+#define TARGET_NR_fremovexattr	237
+#define TARGET_NR_tkill		238
+#define TARGET_NR_sendfile64		239
+#define TARGET_NR_futex		240
+#define TARGET_NR_sched_setaffinity	241
+#define TARGET_NR_sched_getaffinity	242
+#define TARGET_NR_set_thread_area	243
+#define TARGET_NR_get_thread_area	244
+#define TARGET_NR_io_setup		245
+#define TARGET_NR_io_destroy		246
+#define TARGET_NR_io_getevents	247
+#define TARGET_NR_io_submit		248
+#define TARGET_NR_io_cancel		249
+#define TARGET_NR_fadvise64		250
+
+#define TARGET_NR_exit_group		252
+#define TARGET_NR_lookup_dcookie	253
+#define TARGET_NR_epoll_create	254
+#define TARGET_NR_epoll_ctl		255
+#define TARGET_NR_epoll_wait		256
+#define TARGET_NR_remap_file_pages	257
+#define TARGET_NR_set_tid_address	258
+#define TARGET_NR_timer_create	259
+#define TARGET_NR_timer_settime	(TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime	(TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete	(TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime	(TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
+#define TARGET_NR_statfs64		268
+#define TARGET_NR_fstatfs64		269
+#define TARGET_NR_tgkill		270
+#define TARGET_NR_utimes		271
+#define TARGET_NR_fadvise64_64	272
+#define TARGET_NR_vserver		273
+#define TARGET_NR_mbind              274
+#define TARGET_NR_get_mempolicy      275
+#define TARGET_NR_set_mempolicy      276
+#define TARGET_NR_mq_open            277
+#define TARGET_NR_mq_unlink          (TARGET_NR_mq_open+1)
+#define TARGET_NR_mq_timedsend       (TARGET_NR_mq_open+2)
+#define TARGET_NR_mq_timedreceive    (TARGET_NR_mq_open+3)
+#define TARGET_NR_mq_notify          (TARGET_NR_mq_open+4)
+#define TARGET_NR_mq_getsetattr      (TARGET_NR_mq_open+5)
+#define TARGET_NR_sys_kexec_load	283
+#define TARGET_NR_waitid		284
+#define TARGET_NR_add_key		285
+#define TARGET_NR_request_key	286
+#define TARGET_NR_keyctl		287
+#define TARGET_NR_ioprio_set		288
+#define TARGET_NR_ioprio_get		289
+#define TARGET_NR_inotify_init	290
+#define TARGET_NR_inotify_add_watch	291
+#define TARGET_NR_inotify_rm_watch	292
+/* 293 is unused */
+#define TARGET_NR_migrate_pages	294
+#define TARGET_NR_openat		295
+#define TARGET_NR_mkdirat		296
+#define TARGET_NR_mknodat		297
+#define TARGET_NR_fchownat		298
+#define TARGET_NR_futimesat		299
+#define TARGET_NR_fstatat64		300
+#define TARGET_NR_unlinkat		301
+#define TARGET_NR_renameat		302
+#define TARGET_NR_linkat		303
+#define TARGET_NR_symlinkat		304
+#define TARGET_NR_readlinkat		305
+#define TARGET_NR_fchmodat		306
+#define TARGET_NR_faccessat		307
+#define TARGET_NR_pselect6		308
+#define TARGET_NR_ppoll		309
+#define TARGET_NR_unshare		310
+#define TARGET_NR_set_robust_list	311
+#define TARGET_NR_get_robust_list	312
+#define TARGET_NR_splice		313
+#define TARGET_NR_sync_file_range	314
+#define TARGET_NR_tee		315
+#define TARGET_NR_vmsplice		316
+#define TARGET_NR_move_pages		317
+#define TARGET_NR_getcpu		318
+#define TARGET_NR_epoll_pwait	319
+#define TARGET_NR_utimensat		320
+#define TARGET_NR_signalfd		321
+#define TARGET_NR_timerfd		322
+#define TARGET_NR_eventfd		323
+#define TARGET_NR_fallocate		324
+#define TARGET_NR_timerfd_settime	325
+#define TARGET_NR_timerfd_gettime	326
+#define TARGET_NR_signalfd4		327
+#define TARGET_NR_eventfd2		328
+#define TARGET_NR_epoll_create1	329
+#define TARGET_NR_dup3			330
+#define TARGET_NR_pipe2		331
+#define TARGET_NR_inotify_init1	332
+#define TARGET_NR_preadv                333
+#define TARGET_NR_pwritev               334
+#define TARGET_NR_rt_tgsigqueueinfo     335
+#define TARGET_NR_perf_event_open       336
+#define TARGET_NR_fanotify_init         337
+#define TARGET_NR_fanotify_mark         338
+#define TARGET_NR_prlimit64             339
+
+/* Non-multiplexed socket family */
+#define TARGET_NR_socket                340
+#define TARGET_NR_bind                  341
+#define TARGET_NR_connect               342
+#define TARGET_NR_listen                343
+#define TARGET_NR_accept                344
+#define TARGET_NR_getsockname           345
+#define TARGET_NR_getpeername           346
+#define TARGET_NR_socketpair            347
+#define TARGET_NR_send                  348
+#define TARGET_NR_sendto                349
+#define TARGET_NR_recv                  350
+#define TARGET_NR_recvfrom              351
+#define TARGET_NR_shutdown              352
+#define TARGET_NR_setsockopt            353
+#define TARGET_NR_getsockopt            354
+#define TARGET_NR_sendmsg               355
+#define TARGET_NR_recvmsg               356
+#define TARGET_NR_recvmmsg              357
+#define TARGET_NR_accept4               358
+#define TARGET_NR_name_to_handle_at     359
+#define TARGET_NR_open_by_handle_at     360
+#define TARGET_NR_clock_adjtime         361
+#define TARGET_NR_syncfs                362
diff --git a/qemu-0.15.x/linux-user/sh4/target_signal.h b/qemu-0.15.x/linux-user/sh4/target_signal.h
new file mode 100644
index 0000000..e148da0
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sh4/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
+{
+    return state->gregs[15];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/sh4/termbits.h b/qemu-0.15.x/linux-user/sh4/termbits.h
new file mode 100644
index 0000000..2ff774f
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sh4/termbits.h
@@ -0,0 +1,274 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+	unsigned int c_iflag;			/* input mode flags */
+	unsigned int c_oflag;			/* output mode flags */
+	unsigned int c_cflag;			/* control mode flags */
+	unsigned int c_lflag;			/* local mode flags */
+	unsigned char c_line;			/* line discipline */
+	unsigned char c_cc[TARGET_NCCS];	/* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IUCLC	0001000
+#define TARGET_IXON	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IXOFF	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_OLCUC	0000002
+#define TARGET_ONLCR	0000004
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+#define TARGET_OFILL	0000100
+#define TARGET_OFDEL	0000200
+#define TARGET_NLDLY	0000400
+#define TARGET_NL0	0000000
+#define TARGET_NL1	0000400
+#define TARGET_CRDLY	0003000
+#define TARGET_CR0	0000000
+#define TARGET_CR1	0001000
+#define TARGET_CR2	0002000
+#define TARGET_CR3	0003000
+#define TARGET_TABDLY	0014000
+#define TARGET_TAB0	0000000
+#define TARGET_TAB1	0004000
+#define TARGET_TAB2	0010000
+#define TARGET_TAB3	0014000
+#define TARGET_XTABS	0014000
+#define TARGET_BSDLY	0020000
+#define TARGET_BS0	0000000
+#define TARGET_BS1	0020000
+#define TARGET_VTDLY	0040000
+#define TARGET_VT0	0000000
+#define TARGET_VT1	0040000
+#define TARGET_FFDLY	0100000
+#define TARGET_FF0	0000000
+#define TARGET_FF1	0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0010017
+#define TARGET_B0	0000000		/* hang up */
+#define TARGET_B50	0000001
+#define TARGET_B75	0000002
+#define TARGET_B110	0000003
+#define TARGET_B134	0000004
+#define TARGET_B150	0000005
+#define TARGET_B200	0000006
+#define TARGET_B300	0000007
+#define TARGET_B600	0000010
+#define TARGET_B1200	0000011
+#define TARGET_B1800	0000012
+#define TARGET_B2400	0000013
+#define TARGET_B4800	0000014
+#define TARGET_B9600	0000015
+#define TARGET_B19200	0000016
+#define TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE	0000060
+#define TARGET_CS5	0000000
+#define TARGET_CS6	0000020
+#define TARGET_CS7	0000040
+#define TARGET_CS8	0000060
+#define TARGET_CSTOPB	0000100
+#define TARGET_CREAD	0000200
+#define TARGET_PARENB	0000400
+#define TARGET_PARODD	0001000
+#define TARGET_HUPCL	0002000
+#define TARGET_CLOCAL	0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_B57600 0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_B500000 0010005
+#define TARGET_B576000 0010006
+#define TARGET_B921600 0010007
+#define TARGET_B1000000 0010010
+#define TARGET_B1152000 0010011
+#define TARGET_B1500000 0010012
+#define TARGET_B2000000 0010013
+#define TARGET_B2500000 0010014
+#define TARGET_B3000000 0010015
+#define TARGET_B3500000 0010016
+#define TARGET_B4000000 0010017
+#define TARGET_CIBAUD	  002003600000	/* input baud rate (not used) */
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0000001
+#define TARGET_ICANON	0000002
+#define TARGET_XCASE	0000004
+#define TARGET_ECHO	0000010
+#define TARGET_ECHOE	0000020
+#define TARGET_ECHOK	0000040
+#define TARGET_ECHONL	0000100
+#define TARGET_NOFLSH	0000200
+#define TARGET_TOSTOP	0000400
+#define TARGET_ECHOCTL	0001000
+#define TARGET_ECHOPRT	0002000
+#define TARGET_ECHOKE	0004000
+#define TARGET_FLUSHO	0010000
+#define TARGET_PENDIN	0040000
+#define TARGET_IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define TARGET_TCOOFF		0
+#define TARGET_TCOON		1
+#define TARGET_TCIOFF		2
+#define TARGET_TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define TARGET_TCIFLUSH	0
+#define TARGET_TCOFLUSH	1
+#define TARGET_TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define TARGET_TCSANOW		0
+#define TARGET_TCSADRAIN	1
+#define TARGET_TARGET_TCSAFLUSH	2
+
+/* ioctl */
+#define TARGET_FIOCLEX         TARGET_IO('f', 1)
+#define TARGET_FIONCLEX        TARGET_IO('f', 2)
+#define TARGET_FIOASYNC        TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO         TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD        TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ         TARGET_FIONREAD
+#define TARGET_FIOQSIZE        TARGET_IOR('f', 128, loff_t)
+#define TARGET_TCGETS          0x5401
+#define TARGET_TCSETS          0x5402
+#define TARGET_TCSETSW         0x5403
+#define TARGET_TCSETSF         0x5404
+#define TARGET_TCGETA          TARGET_IOR('t', 23, struct termio)
+#define TARGET_TIOCSWINSZ      TARGET_IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ      TARGET_IOR('t', 104, struct winsize)
+#define TARGET_TIOCSTART       TARGET_IO('t', 110)           /* start output, like ^Q */
+#define TARGET_TIOCSTOP        TARGET_IO('t', 111)           /* stop output, like ^S */
+#define TARGET_TIOCOUTQ        TARGET_IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCSPGRP       TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP       TARGET_IOR('t', 119, int)
+
+#define TARGET_TCSETA          TARGET_IOW('t', 24, struct termio)
+#define TARGET_TCSETAW         TARGET_IOW('t', 25, struct termio)
+#define TARGET_TCSETAF         TARGET_IOW('t', 28, struct termio)
+#define TARGET_TCSBRK          TARGET_IO('t', 29)
+#define TARGET_TCXONC          TARGET_IO('t', 30)
+#define TARGET_TCFLSH          TARGET_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ      TARGET_IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ      TARGET_IOR('t', 104, struct winsize)
+#define TARGET_TIOCSTART       TARGET_IO('t', 110)           /* start output, like ^Q */
+#define TARGET_TIOCSTOP        TARGET_IO('t', 111)           /* stop output, like ^S */
+#define TARGET_TIOCOUTQ        TARGET_IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCSPGRP       TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP       TARGET_IOR('t', 119, int)
+#define TARGET_TIOCEXCL        TARGET_IO('T', 12) /* 0x540C */
+#define TARGET_TIOCNXCL        TARGET_IO('T', 13) /* 0x540D */
+#define TARGET_TIOCSCTTY       TARGET_IO('T', 14) /* 0x540E */
+
+#define TARGET_TIOCSTI         TARGET_IOW('T', 18, char) /* 0x5412 */
+#define TARGET_TIOCMGET        TARGET_IOR('T', 21, unsigned int) /* 0x5415 */
+#define TARGET_TIOCMBIS        TARGET_IOW('T', 22, unsigned int) /* 0x5416 */
+#define TARGET_TIOCMBIC        TARGET_IOW('T', 23, unsigned int) /* 0x5417 */
+#define TARGET_TIOCMSET        TARGET_IOW('T', 24, unsigned int) /* 0x5418 */
+#define TARGET_TIOCM_LE       0x001
+#define TARGET_TIOCM_DTR      0x002
+#define TARGET_TIOCM_RTS      0x004
+#define TARGET_TIOCM_ST       0x008
+#define TARGET_TIOCM_SR       0x010
+#define TARGET_TIOCM_CTS      0x020
+#define TARGET_TIOCM_CAR      0x040
+#define TARGET_TIOCM_RNG      0x080
+#define TARGET_TIOCM_DSR      0x100
+#define TARGET_TIOCM_CD       TARGET_TIOCM_CAR
+#define TARGET_TIOCM_RI       TARGET_TIOCM_RNG
+
+#define TARGET_TIOCGSOFTCAR    TARGET_IOR('T', 25, unsigned int) /* 0x5419 */
+#define TARGET_TIOCSSOFTCAR    TARGET_IOW('T', 26, unsigned int) /* 0x541A */
+#define TARGET_TIOCLINUX       TARGET_IOW('T', 28, char) /* 0x541C */
+#define TARGET_TIOCCONS        TARGET_IO('T', 29) /* 0x541D */
+#define TARGET_TIOCGSERIAL     TARGET_IOR('T', 30, int) /* 0x541E */
+#define TARGET_TIOCSSERIAL     TARGET_IOW('T', 31, int) /* 0x541F */
+#define TARGET_TIOCPKT         TARGET_IOW('T', 32, int) /* 0x5420 */
+#define TARGET_TIOCPKT_DATA            0
+#define TARGET_TIOCPKT_FLUSHREAD       1
+#define TARGET_TIOCPKT_FLUSHWRITE      2
+#define TARGET_TIOCPKT_STOP            4
+#define TARGET_TIOCPKT_START           8
+#define TARGET_TIOCPKT_NOSTOP         16
+#define TARGET_TIOCPKT_DOSTOP         32
+
+
+#define TARGET_TIOCNOTTY       TARGET_IO('T', 34) /* 0x5422 */
+#define TARGET_TIOCSETD        TARGET_IOW('T', 35, int) /* 0x5423 */
+#define TARGET_TIOCGETD        TARGET_IOR('T', 36, int) /* 0x5424 */
+#define TARGET_TCSBRKP         TARGET_IOW('T', 37, int) /* 0x5425 */ /* Needed for POSIX tcse
+ndbreak() */
+#define TARGET_TIOCSBRK        TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */
+#define TARGET_TIOCCBRK        TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */
+#define TARGET_TIOCGSID        TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session
+ID of FD */
+#define TARGET_TIOCGPTN        TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m
+ux device) */
+#define TARGET_TIOCSPTLCK      TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+
+#define TARGET_TIOCSERCONFIG   TARGET_IO('T', 83) /* 0x5453 */
+#define TARGET_TIOCSERGWILD    TARGET_IOR('T', 84,  int) /* 0x5454 */
+#define TARGET_TIOCSERSWILD    TARGET_IOW('T', 85,  int) /* 0x5455 */
+#define TARGET_TIOCGLCKTRMIOS  0x5456
+#define TARGET_TIOCSLCKTRMIOS  0x5457
+#define TARGET_TIOCSERGSTRUCT  TARGET_IOR('T', 88, int) /* 0x5458 */ /* For d
+ebugging only */
+#define TARGET_TIOCSERGETLSR   TARGET_IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line sta
+tus register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A
+*/ /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B
+*/ /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT      TARGET_IO('T', 92) /* 0x545C */       /* wait for a change on
+serial input line(s) */
+#define TARGET_TIOCGICOUNT     TARGET_IOR('T', 93, int) /* 0x545D */ /* read
+serial port inline interrupt counts */
diff --git a/qemu-0.15.x/linux-user/signal.c b/qemu-0.15.x/linux-user/signal.c
new file mode 100644
index 0000000..07ad07a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/signal.c
@@ -0,0 +1,5316 @@
+/*
+ *  Emulation of Linux signals
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/ucontext.h>
+#include <sys/resource.h>
+
+#include "qemu.h"
+#include "qemu-common.h"
+#include "target_signal.h"
+
+//#define DEBUG_SIGNAL
+
+static struct target_sigaltstack target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
+static struct target_sigaction sigact_table[TARGET_NSIG];
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+                                void *puc);
+
+static uint8_t host_to_target_signal_table[_NSIG] = {
+    [SIGHUP] = TARGET_SIGHUP,
+    [SIGINT] = TARGET_SIGINT,
+    [SIGQUIT] = TARGET_SIGQUIT,
+    [SIGILL] = TARGET_SIGILL,
+    [SIGTRAP] = TARGET_SIGTRAP,
+    [SIGABRT] = TARGET_SIGABRT,
+/*    [SIGIOT] = TARGET_SIGIOT,*/
+    [SIGBUS] = TARGET_SIGBUS,
+    [SIGFPE] = TARGET_SIGFPE,
+    [SIGKILL] = TARGET_SIGKILL,
+    [SIGUSR1] = TARGET_SIGUSR1,
+    [SIGSEGV] = TARGET_SIGSEGV,
+    [SIGUSR2] = TARGET_SIGUSR2,
+    [SIGPIPE] = TARGET_SIGPIPE,
+    [SIGALRM] = TARGET_SIGALRM,
+    [SIGTERM] = TARGET_SIGTERM,
+#ifdef SIGSTKFLT
+    [SIGSTKFLT] = TARGET_SIGSTKFLT,
+#endif
+    [SIGCHLD] = TARGET_SIGCHLD,
+    [SIGCONT] = TARGET_SIGCONT,
+    [SIGSTOP] = TARGET_SIGSTOP,
+    [SIGTSTP] = TARGET_SIGTSTP,
+    [SIGTTIN] = TARGET_SIGTTIN,
+    [SIGTTOU] = TARGET_SIGTTOU,
+    [SIGURG] = TARGET_SIGURG,
+    [SIGXCPU] = TARGET_SIGXCPU,
+    [SIGXFSZ] = TARGET_SIGXFSZ,
+    [SIGVTALRM] = TARGET_SIGVTALRM,
+    [SIGPROF] = TARGET_SIGPROF,
+    [SIGWINCH] = TARGET_SIGWINCH,
+    [SIGIO] = TARGET_SIGIO,
+    [SIGPWR] = TARGET_SIGPWR,
+    [SIGSYS] = TARGET_SIGSYS,
+    /* next signals stay the same */
+    /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+       host libpthread signals.  This assumes noone actually uses SIGRTMAX :-/
+       To fix this properly we need to do manual signal delivery multiplexed
+       over a single host signal.  */
+    [__SIGRTMIN] = __SIGRTMAX,
+    [__SIGRTMAX] = __SIGRTMIN,
+};
+static uint8_t target_to_host_signal_table[_NSIG];
+
+static inline int on_sig_stack(unsigned long sp)
+{
+    return (sp - target_sigaltstack_used.ss_sp
+            < target_sigaltstack_used.ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
+            : on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
+int host_to_target_signal(int sig)
+{
+    if (sig >= _NSIG)
+        return sig;
+    return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+    if (sig >= _NSIG)
+        return sig;
+    return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+    memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    set->sig[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+                                           const sigset_t *s)
+{
+    int i;
+    target_sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (sigismember(s, i)) {
+            target_sigaddset(d, host_to_target_signal(i));
+        }
+    }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+    target_sigset_t d1;
+    int i;
+
+    host_to_target_sigset_internal(&d1, s);
+    for(i = 0;i < TARGET_NSIG_WORDS; i++)
+        d->sig[i] = tswapl(d1.sig[i]);
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+                                           const target_sigset_t *s)
+{
+    int i;
+    sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (target_sigismember(s, i)) {
+            sigaddset(d, target_to_host_signal(i));
+        }
+     }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+    target_sigset_t s1;
+    int i;
+
+    for(i = 0;i < TARGET_NSIG_WORDS; i++)
+        s1.sig[i] = tswapl(s->sig[i]);
+    target_to_host_sigset_internal(d, &s1);
+}
+
+void host_to_target_old_sigset(abi_ulong *old_sigset,
+                               const sigset_t *sigset)
+{
+    target_sigset_t d;
+    host_to_target_sigset(&d, sigset);
+    *old_sigset = d.sig[0];
+}
+
+void target_to_host_old_sigset(sigset_t *sigset,
+                               const abi_ulong *old_sigset)
+{
+    target_sigset_t d;
+    int i;
+
+    d.sig[0] = *old_sigset;
+    for(i = 1;i < TARGET_NSIG_WORDS; i++)
+        d.sig[i] = 0;
+    target_to_host_sigset(sigset, &d);
+}
+
+/* siginfo conversion */
+
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+                                                 const siginfo_t *info)
+{
+    int sig;
+    sig = host_to_target_signal(info->si_signo);
+    tinfo->si_signo = sig;
+    tinfo->si_errno = 0;
+    tinfo->si_code = info->si_code;
+    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
+        sig == SIGBUS || sig == SIGTRAP) {
+        /* should never come here, but who knows. The information for
+           the target is irrelevant */
+        tinfo->_sifields._sigfault._addr = 0;
+    } else if (sig == SIGIO) {
+	tinfo->_sifields._sigpoll._fd = info->si_fd;
+    } else if (sig >= TARGET_SIGRTMIN) {
+        tinfo->_sifields._rt._pid = info->si_pid;
+        tinfo->_sifields._rt._uid = info->si_uid;
+        /* XXX: potential problem if 64 bit */
+        tinfo->_sifields._rt._sigval.sival_ptr =
+            (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+    }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo,
+                          const target_siginfo_t *info)
+{
+    int sig;
+    sig = info->si_signo;
+    tinfo->si_signo = tswap32(sig);
+    tinfo->si_errno = tswap32(info->si_errno);
+    tinfo->si_code = tswap32(info->si_code);
+    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
+        sig == SIGBUS || sig == SIGTRAP) {
+        tinfo->_sifields._sigfault._addr =
+            tswapl(info->_sifields._sigfault._addr);
+    } else if (sig == SIGIO) {
+	tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
+    } else if (sig >= TARGET_SIGRTMIN) {
+        tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
+        tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
+        tinfo->_sifields._rt._sigval.sival_ptr =
+            tswapl(info->_sifields._rt._sigval.sival_ptr);
+    }
+}
+
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+    host_to_target_siginfo_noswap(tinfo, info);
+    tswap_siginfo(tinfo, tinfo);
+}
+
+/* XXX: we support only POSIX RT signals are used. */
+/* XXX: find a solution for 64 bit (additional malloced data is needed) */
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
+{
+    info->si_signo = tswap32(tinfo->si_signo);
+    info->si_errno = tswap32(tinfo->si_errno);
+    info->si_code = tswap32(tinfo->si_code);
+    info->si_pid = tswap32(tinfo->_sifields._rt._pid);
+    info->si_uid = tswap32(tinfo->_sifields._rt._uid);
+    info->si_value.sival_ptr =
+            (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
+}
+
+static int fatal_signal (int sig)
+{
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+        /* Ignored by default.  */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+/* returns 1 if given signal should dump core if not handled */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return (1);
+    default:
+        return (0);
+    }
+}
+
+void signal_init(void)
+{
+    struct sigaction act;
+    struct sigaction oact;
+    int i, j;
+    int host_sig;
+
+    /* generate signal conversion tables */
+    for(i = 1; i < _NSIG; i++) {
+        if (host_to_target_signal_table[i] == 0)
+            host_to_target_signal_table[i] = i;
+    }
+    for(i = 1; i < _NSIG; i++) {
+        j = host_to_target_signal_table[i];
+        target_to_host_signal_table[j] = i;
+    }
+
+    /* set all host signal handlers. ALL signals are blocked during
+       the handlers to serialize them. */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO;
+    act.sa_sigaction = host_signal_handler;
+    for(i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /* If there's already a handler installed then something has
+           gone horribly wrong, so don't even try to handle that case.  */
+        /* Install some handlers for our own use.  We need at least
+           SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+           trap all signals because it affects syscall interrupt
+           behavior.  But do trap all default-fatal signals.  */
+        if (fatal_signal (i))
+            sigaction(host_sig, &act, NULL);
+    }
+}
+
+/* signal queue handling */
+
+static inline struct sigqueue *alloc_sigqueue(CPUState *env)
+{
+    TaskState *ts = env->opaque;
+    struct sigqueue *q = ts->first_free;
+    if (!q)
+        return NULL;
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
+{
+    TaskState *ts = env->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
+/* abort execution with signal */
+static void QEMU_NORETURN force_sig(int target_sig)
+{
+    TaskState *ts = (TaskState *)thread_env->opaque;
+    int host_sig, core_dumped = 0;
+    struct sigaction act;
+    host_sig = target_to_host_signal(target_sig);
+    gdb_signalled(thread_env, target_sig);
+
+    /* dump core if supported by target binary format */
+    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(target_sig, thread_env) == 0);
+    }
+    if (core_dumped) {
+        /* we already dumped the core of target process, we don't want
+         * a coredump of qemu itself */
+        struct rlimit nodump;
+        getrlimit(RLIMIT_CORE, &nodump);
+        nodump.rlim_cur=0;
+        setrlimit(RLIMIT_CORE, &nodump);
+        (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
+            target_sig, strsignal(host_sig), "core dumped" );
+    }
+
+    /* The proper exit code for dying from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive. */
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    /* For some reason raise(host_sig) doesn't send the signal when
+     * statically linked on x86-64. */
+    kill(getpid(), host_sig);
+
+    /* Make sure the signal isn't masked (just reuse the mask inside
+    of act) */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    abort();
+}
+
+/* queue a signal so that it will be send to the virtual CPU as soon
+   as possible */
+int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
+{
+    TaskState *ts = env->opaque;
+    struct emulated_sigtable *k;
+    struct sigqueue *q, **pq;
+    abi_ulong handler;
+    int queue;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "queue_signal: sig=%d\n",
+            sig);
+#endif
+    k = &ts->sigtab[sig - 1];
+    queue = gdb_queuesig ();
+    handler = sigact_table[sig - 1]._sa_handler;
+    if (!queue && handler == TARGET_SIG_DFL) {
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
+            kill(getpid(),SIGSTOP);
+            return 0;
+        } else
+        /* default handler : ignore some signal. The other are fatal */
+        if (sig != TARGET_SIGCHLD &&
+            sig != TARGET_SIGURG &&
+            sig != TARGET_SIGWINCH &&
+            sig != TARGET_SIGCONT) {
+            force_sig(sig);
+        } else {
+            return 0; /* indicate ignored */
+        }
+    } else if (!queue && handler == TARGET_SIG_IGN) {
+        /* ignore signal */
+        return 0;
+    } else if (!queue && handler == TARGET_SIG_ERR) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+        if (sig < TARGET_SIGRTMIN) {
+            /* if non real time signal, we queue exactly one signal */
+            if (!k->pending)
+                q = &k->info;
+            else
+                return 0;
+        } else {
+            if (!k->pending) {
+                /* first signal */
+                q = &k->info;
+            } else {
+                q = alloc_sigqueue(env);
+                if (!q)
+                    return -EAGAIN;
+                while (*pq != NULL)
+                    pq = &(*pq)->next;
+            }
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* signal that a new signal is pending */
+        ts->signal_pending = 1;
+        return 1; /* indicates that the signal was queued */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+                                void *puc)
+{
+    int sig;
+    target_siginfo_t tinfo;
+
+    /* the CPU emulator uses some host signals to detect exceptions,
+       we forward to it some signals */
+    if ((host_signum == SIGSEGV || host_signum == SIGBUS)
+        && info->si_code > 0) {
+        if (cpu_signal_handler(host_signum, info, puc))
+            return;
+    }
+
+    /* get target signal number */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > TARGET_NSIG)
+        return;
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    host_to_target_siginfo_noswap(&tinfo, info);
+    if (queue_signal(thread_env, sig, &tinfo) == 1) {
+        /* interrupt the virtual CPU as soon as possible */
+        cpu_exit(thread_env);
+    }
+}
+
+/* do_sigaltstack() returns target values and errnos. */
+/* compare linux/kernel/signal.c:do_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+    int ret;
+    struct target_sigaltstack oss;
+
+    /* XXX: test errors */
+    if(uoss_addr)
+    {
+        __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
+        __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
+        __put_user(sas_ss_flags(sp), &oss.ss_flags);
+    }
+
+    if(uss_addr)
+    {
+        struct target_sigaltstack *uss;
+        struct target_sigaltstack ss;
+
+	ret = -TARGET_EFAULT;
+        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
+	    || __get_user(ss.ss_sp, &uss->ss_sp)
+	    || __get_user(ss.ss_size, &uss->ss_size)
+	    || __get_user(ss.ss_flags, &uss->ss_flags))
+            goto out;
+        unlock_user_struct(uss, uss_addr, 0);
+
+	ret = -TARGET_EPERM;
+	if (on_sig_stack(sp))
+            goto out;
+
+	ret = -TARGET_EINVAL;
+	if (ss.ss_flags != TARGET_SS_DISABLE
+            && ss.ss_flags != TARGET_SS_ONSTACK
+            && ss.ss_flags != 0)
+            goto out;
+
+	if (ss.ss_flags == TARGET_SS_DISABLE) {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+	} else {
+            ret = -TARGET_ENOMEM;
+            if (ss.ss_size < MINSIGSTKSZ)
+                goto out;
+	}
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss_addr) {
+        ret = -TARGET_EFAULT;
+        if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
+            goto out;
+    }
+
+    ret = 0;
+out:
+    return ret;
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+                 struct target_sigaction *oact)
+{
+    struct target_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+    int ret = 0;
+
+    if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
+        return -EINVAL;
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
+            sig, act, oact);
+#endif
+    if (oact) {
+        oact->_sa_handler = tswapl(k->_sa_handler);
+        oact->sa_flags = tswapl(k->sa_flags);
+#if !defined(TARGET_MIPS)
+        oact->sa_restorer = tswapl(k->sa_restorer);
+#endif
+        oact->sa_mask = k->sa_mask;
+    }
+    if (act) {
+        /* FIXME: This is not threadsafe.  */
+        k->_sa_handler = tswapl(act->_sa_handler);
+        k->sa_flags = tswapl(act->sa_flags);
+#if !defined(TARGET_MIPS)
+        k->sa_restorer = tswapl(act->sa_restorer);
+#endif
+        k->sa_mask = act->sa_mask;
+
+        /* we update the host linux signal state */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+            sigfillset(&act1.sa_mask);
+            act1.sa_flags = SA_SIGINFO;
+            if (k->sa_flags & TARGET_SA_RESTART)
+                act1.sa_flags |= SA_RESTART;
+            /* NOTE: it is important to update the host kernel signal
+               ignore state to avoid getting unexpected interrupted
+               syscalls */
+            if (k->_sa_handler == TARGET_SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->_sa_handler == TARGET_SIG_DFL) {
+                if (fatal_signal (sig))
+                    act1.sa_sigaction = host_signal_handler;
+                else
+                    act1.sa_sigaction = (void *)SIG_DFL;
+            } else {
+                act1.sa_sigaction = host_signal_handler;
+            }
+            ret = sigaction(host_sig, &act1, NULL);
+        }
+    }
+    return ret;
+}
+
+static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
+                                       const target_siginfo_t *info)
+{
+    tswap_siginfo(tinfo, info);
+    return 0;
+}
+
+static inline int current_exec_domain_sig(int sig)
+{
+    return /* current->exec_domain && current->exec_domain->signal_invmap
+	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
+}
+
+#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
+
+/* from the Linux kernel */
+
+struct target_fpreg {
+	uint16_t significand[4];
+	uint16_t exponent;
+};
+
+struct target_fpxreg {
+	uint16_t significand[4];
+	uint16_t exponent;
+	uint16_t padding[3];
+};
+
+struct target_xmmreg {
+	abi_ulong element[4];
+};
+
+struct target_fpstate {
+	/* Regular FPU environment */
+        abi_ulong       cw;
+        abi_ulong       sw;
+        abi_ulong       tag;
+        abi_ulong       ipoff;
+        abi_ulong       cssel;
+        abi_ulong       dataoff;
+        abi_ulong       datasel;
+	struct target_fpreg	_st[8];
+	uint16_t	status;
+	uint16_t	magic;		/* 0xffff = regular FPU data only */
+
+	/* FXSR FPU environment */
+        abi_ulong       _fxsr_env[6];   /* FXSR FPU env is ignored */
+        abi_ulong       mxcsr;
+        abi_ulong       reserved;
+	struct target_fpxreg	_fxsr_st[8];	/* FXSR FPU reg data is ignored */
+	struct target_xmmreg	_xmm[8];
+        abi_ulong       padding[56];
+};
+
+#define X86_FXSR_MAGIC		0x0000
+
+struct target_sigcontext {
+	uint16_t gs, __gsh;
+	uint16_t fs, __fsh;
+	uint16_t es, __esh;
+	uint16_t ds, __dsh;
+        abi_ulong edi;
+        abi_ulong esi;
+        abi_ulong ebp;
+        abi_ulong esp;
+        abi_ulong ebx;
+        abi_ulong edx;
+        abi_ulong ecx;
+        abi_ulong eax;
+        abi_ulong trapno;
+        abi_ulong err;
+        abi_ulong eip;
+	uint16_t cs, __csh;
+        abi_ulong eflags;
+        abi_ulong esp_at_signal;
+	uint16_t ss, __ssh;
+        abi_ulong fpstate; /* pointer */
+        abi_ulong oldmask;
+        abi_ulong cr2;
+};
+
+struct target_ucontext {
+        abi_ulong         tuc_flags;
+        abi_ulong         tuc_link;
+	target_stack_t	  tuc_stack;
+	struct target_sigcontext tuc_mcontext;
+	target_sigset_t	  tuc_sigmask;	/* mask last for extensibility */
+};
+
+struct sigframe
+{
+    abi_ulong pretcode;
+    int sig;
+    struct target_sigcontext sc;
+    struct target_fpstate fpstate;
+    abi_ulong extramask[TARGET_NSIG_WORDS-1];
+    char retcode[8];
+};
+
+struct rt_sigframe
+{
+    abi_ulong pretcode;
+    int sig;
+    abi_ulong pinfo;
+    abi_ulong puc;
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    struct target_fpstate fpstate;
+    char retcode[8];
+};
+
+/*
+ * Set up a signal frame.
+ */
+
+/* XXX: save x87 state */
+static int
+setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
+		 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
+{
+	int err = 0;
+        uint16_t magic;
+
+	/* already locked in setup_frame() */
+	err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
+	err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
+	err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
+	err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
+	err |= __put_user(env->regs[R_EDI], &sc->edi);
+	err |= __put_user(env->regs[R_ESI], &sc->esi);
+	err |= __put_user(env->regs[R_EBP], &sc->ebp);
+	err |= __put_user(env->regs[R_ESP], &sc->esp);
+	err |= __put_user(env->regs[R_EBX], &sc->ebx);
+	err |= __put_user(env->regs[R_EDX], &sc->edx);
+	err |= __put_user(env->regs[R_ECX], &sc->ecx);
+	err |= __put_user(env->regs[R_EAX], &sc->eax);
+	err |= __put_user(env->exception_index, &sc->trapno);
+	err |= __put_user(env->error_code, &sc->err);
+	err |= __put_user(env->eip, &sc->eip);
+	err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
+	err |= __put_user(env->eflags, &sc->eflags);
+	err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
+	err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
+
+        cpu_x86_fsave(env, fpstate_addr, 1);
+        fpstate->status = fpstate->sw;
+        magic = 0xffff;
+        err |= __put_user(magic, &fpstate->magic);
+        err |= __put_user(fpstate_addr, &sc->fpstate);
+
+	/* non-iBCS2 extensions.. */
+	err |= __put_user(mask, &sc->oldmask);
+	err |= __put_user(env->cr[2], &sc->cr2);
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
+{
+	unsigned long esp;
+
+	/* Default to using normal stack */
+	esp = env->regs[R_ESP];
+	/* This is the X/Open sanctioned signal stack switching.  */
+        if (ka->sa_flags & TARGET_SA_ONSTACK) {
+            if (sas_ss_flags(esp) == 0)
+                esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+        }
+
+	/* This is the legacy signal stack switching. */
+	else
+        if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
+            !(ka->sa_flags & TARGET_SA_RESTORER) &&
+            ka->sa_restorer) {
+            esp = (unsigned long) ka->sa_restorer;
+	}
+        return (esp - frame_size) & -8ul;
+}
+
+/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUX86State *env)
+{
+	abi_ulong frame_addr;
+	struct sigframe *frame;
+	int i, err = 0;
+
+	frame_addr = get_sigframe(ka, env, sizeof(*frame));
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+		goto give_sigsegv;
+
+	err |= __put_user(current_exec_domain_sig(sig),
+		          &frame->sig);
+	if (err)
+		goto give_sigsegv;
+
+	setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
+                         frame_addr + offsetof(struct sigframe, fpstate));
+	if (err)
+		goto give_sigsegv;
+
+        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+            if (__put_user(set->sig[i], &frame->extramask[i - 1]))
+                goto give_sigsegv;
+        }
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa_flags & TARGET_SA_RESTORER) {
+		err |= __put_user(ka->sa_restorer, &frame->pretcode);
+	} else {
+                uint16_t val16;
+                abi_ulong retcode_addr;
+                retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
+		err |= __put_user(retcode_addr, &frame->pretcode);
+		/* This is popl %eax ; movl $,%eax ; int $0x80 */
+                val16 = 0xb858;
+		err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
+		err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
+                val16 = 0x80cd;
+		err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	env->regs[R_ESP] = frame_addr;
+	env->eip = ka->_sa_handler;
+
+        cpu_x86_load_seg(env, R_DS, __USER_DS);
+        cpu_x86_load_seg(env, R_ES, __USER_DS);
+        cpu_x86_load_seg(env, R_SS, __USER_DS);
+        cpu_x86_load_seg(env, R_CS, __USER_CS);
+	env->eflags &= ~TF_MASK;
+
+	unlock_user_struct(frame, frame_addr, 1);
+
+	return;
+
+give_sigsegv:
+	unlock_user_struct(frame, frame_addr, 1);
+	if (sig == TARGET_SIGSEGV)
+		ka->_sa_handler = TARGET_SIG_DFL;
+	force_sig(TARGET_SIGSEGV /* , current */);
+}
+
+/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUX86State *env)
+{
+        abi_ulong frame_addr, addr;
+	struct rt_sigframe *frame;
+	int i, err = 0;
+
+	frame_addr = get_sigframe(ka, env, sizeof(*frame));
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+		goto give_sigsegv;
+
+	err |= __put_user(current_exec_domain_sig(sig),
+			  &frame->sig);
+        addr = frame_addr + offsetof(struct rt_sigframe, info);
+	err |= __put_user(addr, &frame->pinfo);
+        addr = frame_addr + offsetof(struct rt_sigframe, uc);
+	err |= __put_user(addr, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.tuc_flags);
+	err |= __put_user(0, &frame->uc.tuc_link);
+	err |= __put_user(target_sigaltstack_used.ss_sp,
+			  &frame->uc.tuc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+			  &frame->uc.tuc_stack.ss_flags);
+	err |= __put_user(target_sigaltstack_used.ss_size,
+			  &frame->uc.tuc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
+			        env, set->sig[0], 
+                                frame_addr + offsetof(struct rt_sigframe, fpstate));
+        for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+            if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
+                goto give_sigsegv;
+        }
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa_flags & TARGET_SA_RESTORER) {
+		err |= __put_user(ka->sa_restorer, &frame->pretcode);
+	} else {
+                uint16_t val16;
+                addr = frame_addr + offsetof(struct rt_sigframe, retcode);
+		err |= __put_user(addr, &frame->pretcode);
+		/* This is movl $,%eax ; int $0x80 */
+                err |= __put_user(0xb8, (char *)(frame->retcode+0));
+		err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
+                val16 = 0x80cd;
+                err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	env->regs[R_ESP] = frame_addr;
+	env->eip = ka->_sa_handler;
+
+        cpu_x86_load_seg(env, R_DS, __USER_DS);
+        cpu_x86_load_seg(env, R_ES, __USER_DS);
+        cpu_x86_load_seg(env, R_SS, __USER_DS);
+        cpu_x86_load_seg(env, R_CS, __USER_CS);
+	env->eflags &= ~TF_MASK;
+
+	unlock_user_struct(frame, frame_addr, 1);
+
+	return;
+
+give_sigsegv:
+	unlock_user_struct(frame, frame_addr, 1);
+	if (sig == TARGET_SIGSEGV)
+		ka->_sa_handler = TARGET_SIG_DFL;
+	force_sig(TARGET_SIGSEGV /* , current */);
+}
+
+static int
+restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
+{
+	unsigned int err = 0;
+        abi_ulong fpstate_addr;
+        unsigned int tmpflags;
+
+        cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
+        cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
+        cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
+        cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
+
+        env->regs[R_EDI] = tswapl(sc->edi);
+        env->regs[R_ESI] = tswapl(sc->esi);
+        env->regs[R_EBP] = tswapl(sc->ebp);
+        env->regs[R_ESP] = tswapl(sc->esp);
+        env->regs[R_EBX] = tswapl(sc->ebx);
+        env->regs[R_EDX] = tswapl(sc->edx);
+        env->regs[R_ECX] = tswapl(sc->ecx);
+        env->eip = tswapl(sc->eip);
+
+        cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
+        cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
+
+        tmpflags = tswapl(sc->eflags);
+        env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+        //		regs->orig_eax = -1;		/* disable syscall checks */
+
+        fpstate_addr = tswapl(sc->fpstate);
+	if (fpstate_addr != 0) {
+                if (!access_ok(VERIFY_READ, fpstate_addr, 
+                               sizeof(struct target_fpstate)))
+                        goto badframe;
+                cpu_x86_frstor(env, fpstate_addr, 1);
+	}
+
+        *peax = tswapl(sc->eax);
+	return err;
+badframe:
+	return 1;
+}
+
+long do_sigreturn(CPUX86State *env)
+{
+    struct sigframe *frame;
+    abi_ulong frame_addr = env->regs[R_ESP] - 8;
+    target_sigset_t target_set;
+    sigset_t set;
+    int eax, i;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigreturn\n");
+#endif
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+        goto badframe;
+    /* set blocked signals */
+    if (__get_user(target_set.sig[0], &frame->sc.oldmask))
+        goto badframe;
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
+            goto badframe;
+    }
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    /* restore registers */
+    if (restore_sigcontext(env, &frame->sc, &eax))
+        goto badframe;
+    unlock_user_struct(frame, frame_addr, 0);
+    return eax;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUX86State *env)
+{
+        abi_ulong frame_addr;
+	struct rt_sigframe *frame;
+        sigset_t set;
+	int eax;
+
+        frame_addr = env->regs[R_ESP] - 4;
+        if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+                goto badframe;
+        target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+        sigprocmask(SIG_SETMASK, &set, NULL);
+
+	if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
+		goto badframe;
+
+	if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, 
+                           get_sp_from_cpustate(env)) == -EFAULT)
+		goto badframe;
+
+        unlock_user_struct(frame, frame_addr, 0);
+	return eax;
+
+badframe:
+        unlock_user_struct(frame, frame_addr, 0);
+        force_sig(TARGET_SIGSEGV);
+	return 0;
+}
+
+#elif defined(TARGET_ARM)
+
+struct target_sigcontext {
+	abi_ulong trap_no;
+	abi_ulong error_code;
+	abi_ulong oldmask;
+	abi_ulong arm_r0;
+	abi_ulong arm_r1;
+	abi_ulong arm_r2;
+	abi_ulong arm_r3;
+	abi_ulong arm_r4;
+	abi_ulong arm_r5;
+	abi_ulong arm_r6;
+	abi_ulong arm_r7;
+	abi_ulong arm_r8;
+	abi_ulong arm_r9;
+	abi_ulong arm_r10;
+	abi_ulong arm_fp;
+	abi_ulong arm_ip;
+	abi_ulong arm_sp;
+	abi_ulong arm_lr;
+	abi_ulong arm_pc;
+	abi_ulong arm_cpsr;
+	abi_ulong fault_address;
+};
+
+struct target_ucontext_v1 {
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t  tuc_sigmask;	/* mask last for extensibility */
+};
+
+struct target_ucontext_v2 {
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t  tuc_sigmask;	/* mask last for extensibility */
+    char __unused[128 - sizeof(target_sigset_t)];
+    abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
+};
+
+struct target_user_vfp {
+    uint64_t fpregs[32];
+    abi_ulong fpscr;
+};
+
+struct target_user_vfp_exc {
+    abi_ulong fpexc;
+    abi_ulong fpinst;
+    abi_ulong fpinst2;
+};
+
+struct target_vfp_sigframe {
+    abi_ulong magic;
+    abi_ulong size;
+    struct target_user_vfp ufp;
+    struct target_user_vfp_exc ufp_exc;
+} __attribute__((__aligned__(8)));
+
+struct target_iwmmxt_sigframe {
+    abi_ulong magic;
+    abi_ulong size;
+    uint64_t regs[16];
+    /* Note that not all the coprocessor control registers are stored here */
+    uint32_t wcssf;
+    uint32_t wcasf;
+    uint32_t wcgr0;
+    uint32_t wcgr1;
+    uint32_t wcgr2;
+    uint32_t wcgr3;
+} __attribute__((__aligned__(8)));
+
+#define TARGET_VFP_MAGIC 0x56465001
+#define TARGET_IWMMXT_MAGIC 0x12ef842a
+
+struct sigframe_v1
+{
+    struct target_sigcontext sc;
+    abi_ulong extramask[TARGET_NSIG_WORDS-1];
+    abi_ulong retcode;
+};
+
+struct sigframe_v2
+{
+    struct target_ucontext_v2 uc;
+    abi_ulong retcode;
+};
+
+struct rt_sigframe_v1
+{
+    abi_ulong pinfo;
+    abi_ulong puc;
+    struct target_siginfo info;
+    struct target_ucontext_v1 uc;
+    abi_ulong retcode;
+};
+
+struct rt_sigframe_v2
+{
+    struct target_siginfo info;
+    struct target_ucontext_v2 uc;
+    abi_ulong retcode;
+};
+
+#define TARGET_CONFIG_CPU_32 1
+
+/*
+ * For ARM syscalls, we encode the syscall number into the instruction.
+ */
+#define SWI_SYS_SIGRETURN	(0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
+#define SWI_SYS_RT_SIGRETURN	(0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
+
+/*
+ * For Thumb syscalls, we pass the syscall number via r7.  We therefore
+ * need two 16-bit instructions.
+ */
+#define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
+#define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
+
+static const abi_ulong retcodes[4] = {
+	SWI_SYS_SIGRETURN,	SWI_THUMB_SIGRETURN,
+	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
+};
+
+
+#define __get_user_error(x,p,e) __get_user(x, p)
+
+static inline int valid_user_regs(CPUState *regs)
+{
+    return 1;
+}
+
+static void
+setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
+		 CPUState *env, abi_ulong mask)
+{
+	__put_user(env->regs[0], &sc->arm_r0);
+	__put_user(env->regs[1], &sc->arm_r1);
+	__put_user(env->regs[2], &sc->arm_r2);
+	__put_user(env->regs[3], &sc->arm_r3);
+	__put_user(env->regs[4], &sc->arm_r4);
+	__put_user(env->regs[5], &sc->arm_r5);
+	__put_user(env->regs[6], &sc->arm_r6);
+	__put_user(env->regs[7], &sc->arm_r7);
+	__put_user(env->regs[8], &sc->arm_r8);
+	__put_user(env->regs[9], &sc->arm_r9);
+	__put_user(env->regs[10], &sc->arm_r10);
+	__put_user(env->regs[11], &sc->arm_fp);
+	__put_user(env->regs[12], &sc->arm_ip);
+	__put_user(env->regs[13], &sc->arm_sp);
+	__put_user(env->regs[14], &sc->arm_lr);
+	__put_user(env->regs[15], &sc->arm_pc);
+#ifdef TARGET_CONFIG_CPU_32
+	__put_user(cpsr_read(env), &sc->arm_cpsr);
+#endif
+
+	__put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
+	__put_user(/* current->thread.error_code */ 0, &sc->error_code);
+	__put_user(/* current->thread.address */ 0, &sc->fault_address);
+	__put_user(mask, &sc->oldmask);
+}
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
+{
+	unsigned long sp = regs->regs[13];
+
+	/*
+	 * This is the X/Open sanctioned signal stack switching.
+	 */
+	if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
+            sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+	/*
+	 * ATPCS B01 mandates 8-byte alignment
+	 */
+	return (sp - framesize) & ~7;
+}
+
+static int
+setup_return(CPUState *env, struct target_sigaction *ka,
+	     abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
+{
+	abi_ulong handler = ka->_sa_handler;
+	abi_ulong retcode;
+	int thumb = handler & 1;
+	uint32_t cpsr = cpsr_read(env);
+
+	cpsr &= ~CPSR_IT;
+	if (thumb) {
+		cpsr |= CPSR_T;
+	} else {
+		cpsr &= ~CPSR_T;
+	}
+
+	if (ka->sa_flags & TARGET_SA_RESTORER) {
+		retcode = ka->sa_restorer;
+	} else {
+		unsigned int idx = thumb;
+
+		if (ka->sa_flags & TARGET_SA_SIGINFO)
+			idx += 2;
+
+		if (__put_user(retcodes[idx], rc))
+			return 1;
+#if 0
+		flush_icache_range((abi_ulong)rc,
+				   (abi_ulong)(rc + 1));
+#endif
+		retcode = rc_addr + thumb;
+	}
+
+	env->regs[0] = usig;
+	env->regs[13] = frame_addr;
+	env->regs[14] = retcode;
+	env->regs[15] = handler & (thumb ? ~1 : ~3);
+	cpsr_write(env, cpsr, 0xffffffff);
+
+	return 0;
+}
+
+static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUState *env)
+{
+    int i;
+    struct target_vfp_sigframe *vfpframe;
+    vfpframe = (struct target_vfp_sigframe *)regspace;
+    __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
+    __put_user(sizeof(*vfpframe), &vfpframe->size);
+    for (i = 0; i < 32; i++) {
+        __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
+    }
+    __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
+    __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
+    __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
+    __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
+    return (abi_ulong*)(vfpframe+1);
+}
+
+static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace, CPUState *env)
+{
+    int i;
+    struct target_iwmmxt_sigframe *iwmmxtframe;
+    iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
+    __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
+    __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
+    for (i = 0; i < 16; i++) {
+        __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
+    }
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
+    __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
+    return (abi_ulong*)(iwmmxtframe+1);
+}
+
+static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
+                              target_sigset_t *set, CPUState *env)
+{
+    struct target_sigaltstack stack;
+    int i;
+    abi_ulong *regspace;
+
+    /* Clear all the bits of the ucontext we don't use.  */
+    memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
+
+    memset(&stack, 0, sizeof(stack));
+    __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
+    __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
+    __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
+    memcpy(&uc->tuc_stack, &stack, sizeof(stack));
+
+    setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
+    /* Save coprocessor signal frame.  */
+    regspace = uc->tuc_regspace;
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        regspace = setup_sigframe_v2_vfp(regspace, env);
+    }
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        regspace = setup_sigframe_v2_iwmmxt(regspace, env);
+    }
+
+    /* Write terminating magic word */
+    __put_user(0, regspace);
+
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
+    }
+}
+
+/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
+static void setup_frame_v1(int usig, struct target_sigaction *ka,
+			   target_sigset_t *set, CPUState *regs)
+{
+	struct sigframe_v1 *frame;
+	abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+	int i;
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+		return;
+
+	setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+            if (__put_user(set->sig[i], &frame->extramask[i - 1]))
+                goto end;
+	}
+
+        setup_return(regs, ka, &frame->retcode, frame_addr, usig,
+                     frame_addr + offsetof(struct sigframe_v1, retcode));
+
+end:
+	unlock_user_struct(frame, frame_addr, 1);
+}
+
+static void setup_frame_v2(int usig, struct target_sigaction *ka,
+			   target_sigset_t *set, CPUState *regs)
+{
+	struct sigframe_v2 *frame;
+	abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+		return;
+
+        setup_sigframe_v2(&frame->uc, set, regs);
+
+        setup_return(regs, ka, &frame->retcode, frame_addr, usig,
+                     frame_addr + offsetof(struct sigframe_v2, retcode));
+
+	unlock_user_struct(frame, frame_addr, 1);
+}
+
+static void setup_frame(int usig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *regs)
+{
+    if (get_osversion() >= 0x020612) {
+        setup_frame_v2(usig, ka, set, regs);
+    } else {
+        setup_frame_v1(usig, ka, set, regs);
+    }
+}
+
+/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
+static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
+                              target_siginfo_t *info,
+			      target_sigset_t *set, CPUState *env)
+{
+	struct rt_sigframe_v1 *frame;
+	abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
+	struct target_sigaltstack stack;
+	int i;
+        abi_ulong info_addr, uc_addr;
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+            return /* 1 */;
+
+        info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
+	__put_user(info_addr, &frame->pinfo);
+        uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
+	__put_user(uc_addr, &frame->puc);
+	copy_siginfo_to_user(&frame->info, info);
+
+	/* Clear all the bits of the ucontext we don't use.  */
+	memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
+
+        memset(&stack, 0, sizeof(stack));
+        __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
+        __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
+        __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
+        memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
+
+	setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
+        for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+            if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
+                goto end;
+        }
+
+        setup_return(env, ka, &frame->retcode, frame_addr, usig,
+                     frame_addr + offsetof(struct rt_sigframe_v1, retcode));
+
+        env->regs[1] = info_addr;
+        env->regs[2] = uc_addr;
+
+end:
+	unlock_user_struct(frame, frame_addr, 1);
+}
+
+static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
+                              target_siginfo_t *info,
+                              target_sigset_t *set, CPUState *env)
+{
+	struct rt_sigframe_v2 *frame;
+	abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
+        abi_ulong info_addr, uc_addr;
+
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+            return /* 1 */;
+
+        info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
+        uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
+	copy_siginfo_to_user(&frame->info, info);
+
+        setup_sigframe_v2(&frame->uc, set, env);
+
+        setup_return(env, ka, &frame->retcode, frame_addr, usig,
+                     frame_addr + offsetof(struct rt_sigframe_v2, retcode));
+
+        env->regs[1] = info_addr;
+        env->regs[2] = uc_addr;
+
+	unlock_user_struct(frame, frame_addr, 1);
+}
+
+static void setup_rt_frame(int usig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    if (get_osversion() >= 0x020612) {
+        setup_rt_frame_v2(usig, ka, info, set, env);
+    } else {
+        setup_rt_frame_v1(usig, ka, info, set, env);
+    }
+}
+
+static int
+restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
+{
+	int err = 0;
+        uint32_t cpsr;
+
+	__get_user_error(env->regs[0], &sc->arm_r0, err);
+	__get_user_error(env->regs[1], &sc->arm_r1, err);
+	__get_user_error(env->regs[2], &sc->arm_r2, err);
+	__get_user_error(env->regs[3], &sc->arm_r3, err);
+	__get_user_error(env->regs[4], &sc->arm_r4, err);
+	__get_user_error(env->regs[5], &sc->arm_r5, err);
+	__get_user_error(env->regs[6], &sc->arm_r6, err);
+	__get_user_error(env->regs[7], &sc->arm_r7, err);
+	__get_user_error(env->regs[8], &sc->arm_r8, err);
+	__get_user_error(env->regs[9], &sc->arm_r9, err);
+	__get_user_error(env->regs[10], &sc->arm_r10, err);
+	__get_user_error(env->regs[11], &sc->arm_fp, err);
+	__get_user_error(env->regs[12], &sc->arm_ip, err);
+	__get_user_error(env->regs[13], &sc->arm_sp, err);
+	__get_user_error(env->regs[14], &sc->arm_lr, err);
+	__get_user_error(env->regs[15], &sc->arm_pc, err);
+#ifdef TARGET_CONFIG_CPU_32
+	__get_user_error(cpsr, &sc->arm_cpsr, err);
+        cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
+#endif
+
+	err |= !valid_user_regs(env);
+
+	return err;
+}
+
+static long do_sigreturn_v1(CPUState *env)
+{
+        abi_ulong frame_addr;
+	struct sigframe_v1 *frame;
+	target_sigset_t set;
+        sigset_t host_set;
+        int i;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (env->regs[13] & 7)
+		goto badframe;
+
+        frame_addr = env->regs[13];
+	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+                goto badframe;
+
+	if (__get_user(set.sig[0], &frame->sc.oldmask))
+            goto badframe;
+        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+            if (__get_user(set.sig[i], &frame->extramask[i - 1]))
+                goto badframe;
+        }
+
+        target_to_host_sigset_internal(&host_set, &set);
+        sigprocmask(SIG_SETMASK, &host_set, NULL);
+
+	if (restore_sigcontext(env, &frame->sc))
+		goto badframe;
+
+#if 0
+	/* Send SIGTRAP if we're single-stepping */
+	if (ptrace_cancel_bpt(current))
+		send_sig(SIGTRAP, current, 1);
+#endif
+	unlock_user_struct(frame, frame_addr, 0);
+        return env->regs[0];
+
+badframe:
+	unlock_user_struct(frame, frame_addr, 0);
+        force_sig(TARGET_SIGSEGV /* , current */);
+	return 0;
+}
+
+static abi_ulong *restore_sigframe_v2_vfp(CPUState *env, abi_ulong *regspace)
+{
+    int i;
+    abi_ulong magic, sz;
+    uint32_t fpscr, fpexc;
+    struct target_vfp_sigframe *vfpframe;
+    vfpframe = (struct target_vfp_sigframe *)regspace;
+
+    __get_user(magic, &vfpframe->magic);
+    __get_user(sz, &vfpframe->size);
+    if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
+        return 0;
+    }
+    for (i = 0; i < 32; i++) {
+        __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
+    }
+    __get_user(fpscr, &vfpframe->ufp.fpscr);
+    vfp_set_fpscr(env, fpscr);
+    __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
+    /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
+     * and the exception flag is cleared
+     */
+    fpexc |= (1 << 30);
+    fpexc &= ~((1 << 31) | (1 << 28));
+    env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
+    __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
+    __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
+    return (abi_ulong*)(vfpframe + 1);
+}
+
+static abi_ulong *restore_sigframe_v2_iwmmxt(CPUState *env, abi_ulong *regspace)
+{
+    int i;
+    abi_ulong magic, sz;
+    struct target_iwmmxt_sigframe *iwmmxtframe;
+    iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
+
+    __get_user(magic, &iwmmxtframe->magic);
+    __get_user(sz, &iwmmxtframe->size);
+    if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
+        return 0;
+    }
+    for (i = 0; i < 16; i++) {
+        __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
+    }
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
+    __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
+    return (abi_ulong*)(iwmmxtframe + 1);
+}
+
+static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
+                                 struct target_ucontext_v2 *uc)
+{
+    sigset_t host_set;
+    abi_ulong *regspace;
+
+    target_to_host_sigset(&host_set, &uc->tuc_sigmask);
+    sigprocmask(SIG_SETMASK, &host_set, NULL);
+
+    if (restore_sigcontext(env, &uc->tuc_mcontext))
+        return 1;
+
+    /* Restore coprocessor signal frame */
+    regspace = uc->tuc_regspace;
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        regspace = restore_sigframe_v2_vfp(env, regspace);
+        if (!regspace) {
+            return 1;
+        }
+    }
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        regspace = restore_sigframe_v2_iwmmxt(env, regspace);
+        if (!regspace) {
+            return 1;
+        }
+    }
+
+    if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
+        return 1;
+
+#if 0
+    /* Send SIGTRAP if we're single-stepping */
+    if (ptrace_cancel_bpt(current))
+            send_sig(SIGTRAP, current, 1);
+#endif
+
+    return 0;
+}
+
+static long do_sigreturn_v2(CPUState *env)
+{
+        abi_ulong frame_addr;
+	struct sigframe_v2 *frame;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (env->regs[13] & 7)
+		goto badframe;
+
+        frame_addr = env->regs[13];
+	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+                goto badframe;
+
+        if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
+                goto badframe;
+
+	unlock_user_struct(frame, frame_addr, 0);
+	return env->regs[0];
+
+badframe:
+	unlock_user_struct(frame, frame_addr, 0);
+        force_sig(TARGET_SIGSEGV /* , current */);
+	return 0;
+}
+
+long do_sigreturn(CPUState *env)
+{
+    if (get_osversion() >= 0x020612) {
+        return do_sigreturn_v2(env);
+    } else {
+        return do_sigreturn_v1(env);
+    }
+}
+
+static long do_rt_sigreturn_v1(CPUState *env)
+{
+        abi_ulong frame_addr;
+	struct rt_sigframe_v1 *frame;
+        sigset_t host_set;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (env->regs[13] & 7)
+		goto badframe;
+
+        frame_addr = env->regs[13];
+	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+                goto badframe;
+
+        target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
+        sigprocmask(SIG_SETMASK, &host_set, NULL);
+
+	if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
+		goto badframe;
+
+	if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
+		goto badframe;
+
+#if 0
+	/* Send SIGTRAP if we're single-stepping */
+	if (ptrace_cancel_bpt(current))
+		send_sig(SIGTRAP, current, 1);
+#endif
+	unlock_user_struct(frame, frame_addr, 0);
+	return env->regs[0];
+
+badframe:
+	unlock_user_struct(frame, frame_addr, 0);
+        force_sig(TARGET_SIGSEGV /* , current */);
+	return 0;
+}
+
+static long do_rt_sigreturn_v2(CPUState *env)
+{
+        abi_ulong frame_addr;
+	struct rt_sigframe_v2 *frame;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (env->regs[13] & 7)
+		goto badframe;
+
+        frame_addr = env->regs[13];
+	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+                goto badframe;
+
+        if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
+                goto badframe;
+
+	unlock_user_struct(frame, frame_addr, 0);
+	return env->regs[0];
+
+badframe:
+	unlock_user_struct(frame, frame_addr, 0);
+        force_sig(TARGET_SIGSEGV /* , current */);
+	return 0;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    if (get_osversion() >= 0x020612) {
+        return do_rt_sigreturn_v2(env);
+    } else {
+        return do_rt_sigreturn_v1(env);
+    }
+}
+
+#elif defined(TARGET_SPARC)
+
+#define __SUNOS_MAXWIN   31
+
+/* This is what SunOS does, so shall I. */
+struct target_sigcontext {
+        abi_ulong sigc_onstack;      /* state to restore */
+
+        abi_ulong sigc_mask;         /* sigmask to restore */
+        abi_ulong sigc_sp;           /* stack pointer */
+        abi_ulong sigc_pc;           /* program counter */
+        abi_ulong sigc_npc;          /* next program counter */
+        abi_ulong sigc_psr;          /* for condition codes etc */
+        abi_ulong sigc_g1;           /* User uses these two registers */
+        abi_ulong sigc_o0;           /* within the trampoline code. */
+
+        /* Now comes information regarding the users window set
+         * at the time of the signal.
+         */
+        abi_ulong sigc_oswins;       /* outstanding windows */
+
+        /* stack ptrs for each regwin buf */
+        char *sigc_spbuf[__SUNOS_MAXWIN];
+
+        /* Windows to restore after signal */
+        struct {
+                abi_ulong locals[8];
+                abi_ulong ins[8];
+        } sigc_wbuf[__SUNOS_MAXWIN];
+};
+/* A Sparc stack frame */
+struct sparc_stackf {
+        abi_ulong locals[8];
+        abi_ulong ins[8];
+        /* It's simpler to treat fp and callers_pc as elements of ins[]
+         * since we never need to access them ourselves.
+         */
+        char *structptr;
+        abi_ulong xargs[6];
+        abi_ulong xxargs[1];
+};
+
+typedef struct {
+        struct {
+                abi_ulong psr;
+                abi_ulong pc;
+                abi_ulong npc;
+                abi_ulong y;
+                abi_ulong u_regs[16]; /* globals and ins */
+        }               si_regs;
+        int             si_mask;
+} __siginfo_t;
+
+typedef struct {
+        unsigned   long si_float_regs [32];
+        unsigned   long si_fsr;
+        unsigned   long si_fpqdepth;
+        struct {
+                unsigned long *insn_addr;
+                unsigned long insn;
+        } si_fpqueue [16];
+} qemu_siginfo_fpu_t;
+
+
+struct target_signal_frame {
+	struct sparc_stackf	ss;
+	__siginfo_t		info;
+	abi_ulong               fpu_save;
+	abi_ulong		insns[2] __attribute__ ((aligned (8)));
+	abi_ulong		extramask[TARGET_NSIG_WORDS - 1];
+	abi_ulong		extra_size; /* Should be 0 */
+	qemu_siginfo_fpu_t	fpu_state;
+};
+struct target_rt_signal_frame {
+	struct sparc_stackf	ss;
+	siginfo_t		info;
+	abi_ulong		regs[20];
+	sigset_t		mask;
+	abi_ulong               fpu_save;
+	unsigned int		insns[2];
+	stack_t			stack;
+	unsigned int		extra_size; /* Should be 0 */
+	qemu_siginfo_fpu_t	fpu_state;
+};
+
+#define UREG_O0        16
+#define UREG_O6        22
+#define UREG_I0        0
+#define UREG_I1        1
+#define UREG_I2        2
+#define UREG_I3        3
+#define UREG_I4        4
+#define UREG_I5        5
+#define UREG_I6        6
+#define UREG_I7        7
+#define UREG_L0	       8
+#define UREG_FP        UREG_I6
+#define UREG_SP        UREG_O6
+
+static inline abi_ulong get_sigframe(struct target_sigaction *sa, 
+                                     CPUState *env, unsigned long framesize)
+{
+	abi_ulong sp;
+
+	sp = env->regwptr[UREG_FP];
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (sa->sa_flags & TARGET_SA_ONSTACK) {
+            if (!on_sig_stack(sp)
+                && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
+                sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+	}
+	return sp - framesize;
+}
+
+static int
+setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
+{
+	int err = 0, i;
+
+	err |= __put_user(env->psr, &si->si_regs.psr);
+	err |= __put_user(env->pc, &si->si_regs.pc);
+	err |= __put_user(env->npc, &si->si_regs.npc);
+	err |= __put_user(env->y, &si->si_regs.y);
+	for (i=0; i < 8; i++) {
+		err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
+	}
+	for (i=0; i < 8; i++) {
+		err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
+	}
+	err |= __put_user(mask, &si->si_mask);
+	return err;
+}
+
+#if 0
+static int
+setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
+		 CPUState *env, unsigned long mask)
+{
+	int err = 0;
+
+	err |= __put_user(mask, &sc->sigc_mask);
+	err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
+	err |= __put_user(env->pc, &sc->sigc_pc);
+	err |= __put_user(env->npc, &sc->sigc_npc);
+	err |= __put_user(env->psr, &sc->sigc_psr);
+	err |= __put_user(env->gregs[1], &sc->sigc_g1);
+	err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
+
+	return err;
+}
+#endif
+#define NF_ALIGNEDSZ  (((sizeof(struct target_signal_frame) + 7) & (~7)))
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+        abi_ulong sf_addr;
+	struct target_signal_frame *sf;
+	int sigframe_size, err, i;
+
+	/* 1. Make sure everything is clean */
+	//synchronize_user_stack();
+
+        sigframe_size = NF_ALIGNEDSZ;
+	sf_addr = get_sigframe(ka, env, sigframe_size);
+
+        sf = lock_user(VERIFY_WRITE, sf_addr, 
+                       sizeof(struct target_signal_frame), 0);
+        if (!sf)
+		goto sigsegv;
+                
+	//fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
+#if 0
+	if (invalid_frame_pointer(sf, sigframe_size))
+		goto sigill_and_return;
+#endif
+	/* 2. Save the current process state */
+	err = setup___siginfo(&sf->info, env, set->sig[0]);
+	err |= __put_user(0, &sf->extra_size);
+
+	//err |= save_fpu_state(regs, &sf->fpu_state);
+	//err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+
+	err |= __put_user(set->sig[0], &sf->info.si_mask);
+	for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+		err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
+	}
+
+	for (i = 0; i < 8; i++) {
+	  	err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
+	}
+	for (i = 0; i < 8; i++) {
+	  	err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
+	}
+	if (err)
+		goto sigsegv;
+
+	/* 3. signal handler back-trampoline and parameters */
+	env->regwptr[UREG_FP] = sf_addr;
+	env->regwptr[UREG_I0] = sig;
+	env->regwptr[UREG_I1] = sf_addr + 
+                offsetof(struct target_signal_frame, info);
+	env->regwptr[UREG_I2] = sf_addr + 
+                offsetof(struct target_signal_frame, info);
+
+	/* 4. signal handler */
+	env->pc = ka->_sa_handler;
+	env->npc = (env->pc + 4);
+	/* 5. return to kernel instructions */
+	if (ka->sa_restorer)
+		env->regwptr[UREG_I7] = ka->sa_restorer;
+	else {
+                uint32_t val32;
+
+		env->regwptr[UREG_I7] = sf_addr + 
+                        offsetof(struct target_signal_frame, insns) - 2 * 4;
+
+		/* mov __NR_sigreturn, %g1 */
+                val32 = 0x821020d8;
+		err |= __put_user(val32, &sf->insns[0]);
+
+		/* t 0x10 */
+                val32 = 0x91d02010;
+		err |= __put_user(val32, &sf->insns[1]);
+		if (err)
+			goto sigsegv;
+
+		/* Flush instruction space. */
+		//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+                //		tb_flush(env);
+	}
+        unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
+	return;
+#if 0
+sigill_and_return:
+	force_sig(TARGET_SIGILL);
+#endif
+sigsegv:
+	//fprintf(stderr, "force_sig\n");
+        unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
+	force_sig(TARGET_SIGSEGV);
+}
+static inline int
+restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
+{
+        int err;
+#if 0
+#ifdef CONFIG_SMP
+        if (current->flags & PF_USEDFPU)
+                regs->psr &= ~PSR_EF;
+#else
+        if (current == last_task_used_math) {
+                last_task_used_math = 0;
+                regs->psr &= ~PSR_EF;
+        }
+#endif
+        current->used_math = 1;
+        current->flags &= ~PF_USEDFPU;
+#endif
+#if 0
+        if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+                return -EFAULT;
+#endif
+
+#if 0
+        /* XXX: incorrect */
+        err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
+	                             (sizeof(unsigned long) * 32));
+#endif
+        err |= __get_user(env->fsr, &fpu->si_fsr);
+#if 0
+        err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+        if (current->thread.fpqdepth != 0)
+                err |= __copy_from_user(&current->thread.fpqueue[0],
+                                        &fpu->si_fpqueue[0],
+                                        ((sizeof(unsigned long) +
+                                        (sizeof(unsigned long *)))*16));
+#endif
+        return err;
+}
+
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+        abi_ulong sf_addr;
+        struct target_signal_frame *sf;
+        uint32_t up_psr, pc, npc;
+        target_sigset_t set;
+        sigset_t host_set;
+        int err, i;
+
+        sf_addr = env->regwptr[UREG_FP];
+        if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
+                goto segv_and_exit;
+#if 0
+	fprintf(stderr, "sigreturn\n");
+	fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
+#endif
+	//cpu_dump_state(env, stderr, fprintf, 0);
+
+        /* 1. Make sure we are not getting garbage from the user */
+
+        if (sf_addr & 3)
+                goto segv_and_exit;
+
+        err = __get_user(pc,  &sf->info.si_regs.pc);
+        err |= __get_user(npc, &sf->info.si_regs.npc);
+
+        if ((pc | npc) & 3)
+                goto segv_and_exit;
+
+        /* 2. Restore the state */
+        err |= __get_user(up_psr, &sf->info.si_regs.psr);
+
+        /* User can only change condition codes and FPU enabling in %psr. */
+        env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
+                  | (env->psr & ~(PSR_ICC /* | PSR_EF */));
+
+	env->pc = pc;
+	env->npc = npc;
+        err |= __get_user(env->y, &sf->info.si_regs.y);
+	for (i=0; i < 8; i++) {
+		err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
+	}
+	for (i=0; i < 8; i++) {
+		err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
+	}
+
+        /* FIXME: implement FPU save/restore:
+         * __get_user(fpu_save, &sf->fpu_save);
+         * if (fpu_save)
+         *        err |= restore_fpu_state(env, fpu_save);
+         */
+
+        /* This is pretty much atomic, no amount locking would prevent
+         * the races which exist anyways.
+         */
+        err |= __get_user(set.sig[0], &sf->info.si_mask);
+        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+            err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
+        }
+
+        target_to_host_sigset_internal(&host_set, &set);
+        sigprocmask(SIG_SETMASK, &host_set, NULL);
+
+        if (err)
+                goto segv_and_exit;
+        unlock_user_struct(sf, sf_addr, 0);
+        return env->regwptr[0];
+
+segv_and_exit:
+        unlock_user_struct(sf, sf_addr, 0);
+	force_sig(TARGET_SIGSEGV);
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+#define MC_TSTATE 0
+#define MC_PC 1
+#define MC_NPC 2
+#define MC_Y 3
+#define MC_G1 4
+#define MC_G2 5
+#define MC_G3 6
+#define MC_G4 7
+#define MC_G5 8
+#define MC_G6 9
+#define MC_G7 10
+#define MC_O0 11
+#define MC_O1 12
+#define MC_O2 13
+#define MC_O3 14
+#define MC_O4 15
+#define MC_O5 16
+#define MC_O6 17
+#define MC_O7 18
+#define MC_NGREG 19
+
+typedef abi_ulong target_mc_greg_t;
+typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
+
+struct target_mc_fq {
+    abi_ulong *mcfq_addr;
+    uint32_t mcfq_insn;
+};
+
+struct target_mc_fpu {
+    union {
+        uint32_t sregs[32];
+        uint64_t dregs[32];
+        //uint128_t qregs[16];
+    } mcfpu_fregs;
+    abi_ulong mcfpu_fsr;
+    abi_ulong mcfpu_fprs;
+    abi_ulong mcfpu_gsr;
+    struct target_mc_fq *mcfpu_fq;
+    unsigned char mcfpu_qcnt;
+    unsigned char mcfpu_qentsz;
+    unsigned char mcfpu_enab;
+};
+typedef struct target_mc_fpu target_mc_fpu_t;
+
+typedef struct {
+    target_mc_gregset_t mc_gregs;
+    target_mc_greg_t mc_fp;
+    target_mc_greg_t mc_i7;
+    target_mc_fpu_t mc_fpregs;
+} target_mcontext_t;
+
+struct target_ucontext {
+    struct target_ucontext *tuc_link;
+    abi_ulong tuc_flags;
+    target_sigset_t tuc_sigmask;
+    target_mcontext_t tuc_mcontext;
+};
+
+/* A V9 register window */
+struct target_reg_window {
+    abi_ulong locals[8];
+    abi_ulong ins[8];
+};
+
+#define TARGET_STACK_BIAS 2047
+
+/* {set, get}context() needed for 64-bit SparcLinux userland. */
+void sparc64_set_context(CPUSPARCState *env)
+{
+    abi_ulong ucp_addr;
+    struct target_ucontext *ucp;
+    target_mc_gregset_t *grp;
+    abi_ulong pc, npc, tstate;
+    abi_ulong fp, i7, w_addr;
+    int err;
+    unsigned int i;
+
+    ucp_addr = env->regwptr[UREG_I0];
+    if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
+        goto do_sigsegv;
+    grp  = &ucp->tuc_mcontext.mc_gregs;
+    err  = __get_user(pc, &((*grp)[MC_PC]));
+    err |= __get_user(npc, &((*grp)[MC_NPC]));
+    if (err || ((pc | npc) & 3))
+        goto do_sigsegv;
+    if (env->regwptr[UREG_I1]) {
+        target_sigset_t target_set;
+        sigset_t set;
+
+        if (TARGET_NSIG_WORDS == 1) {
+            if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
+                goto do_sigsegv;
+        } else {
+            abi_ulong *src, *dst;
+            src = ucp->tuc_sigmask.sig;
+            dst = target_set.sig;
+            for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
+                 i++, dst++, src++)
+                err |= __get_user(*dst, src);
+            if (err)
+                goto do_sigsegv;
+        }
+        target_to_host_sigset_internal(&set, &target_set);
+        sigprocmask(SIG_SETMASK, &set, NULL);
+    }
+    env->pc = pc;
+    env->npc = npc;
+    err |= __get_user(env->y, &((*grp)[MC_Y]));
+    err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
+    env->asi = (tstate >> 24) & 0xff;
+    cpu_put_ccr(env, tstate >> 32);
+    cpu_put_cwp64(env, tstate & 0x1f);
+    err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
+    err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
+    err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
+    err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
+    err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
+    err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
+    err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
+    err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
+    err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
+    err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
+    err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
+    err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
+    err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
+    err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
+    err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
+
+    err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
+    err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
+
+    w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
+    if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), 
+                 abi_ulong) != 0)
+        goto do_sigsegv;
+    if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), 
+                 abi_ulong) != 0)
+        goto do_sigsegv;
+    /* FIXME this does not match how the kernel handles the FPU in
+     * its sparc64_set_context implementation. In particular the FPU
+     * is only restored if fenab is non-zero in:
+     *   __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+     */
+    err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
+    {
+        uint32_t *src, *dst;
+        src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        dst = env->fpr;
+        /* XXX: check that the CPU storage is the same as user context */
+        for (i = 0; i < 64; i++, dst++, src++)
+            err |= __get_user(*dst, src);
+    }
+    err |= __get_user(env->fsr,
+                      &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
+    err |= __get_user(env->gsr,
+                      &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
+    if (err)
+        goto do_sigsegv;
+    unlock_user_struct(ucp, ucp_addr, 0);
+    return;
+ do_sigsegv:
+    unlock_user_struct(ucp, ucp_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+}
+
+void sparc64_get_context(CPUSPARCState *env)
+{
+    abi_ulong ucp_addr;
+    struct target_ucontext *ucp;
+    target_mc_gregset_t *grp;
+    target_mcontext_t *mcp;
+    abi_ulong fp, i7, w_addr;
+    int err;
+    unsigned int i;
+    target_sigset_t target_set;
+    sigset_t set;
+
+    ucp_addr = env->regwptr[UREG_I0];
+    if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
+        goto do_sigsegv;
+    
+    mcp = &ucp->tuc_mcontext;
+    grp = &mcp->mc_gregs;
+
+    /* Skip over the trap instruction, first. */
+    env->pc = env->npc;
+    env->npc += 4;
+
+    err = 0;
+
+    sigprocmask(0, NULL, &set);
+    host_to_target_sigset_internal(&target_set, &set);
+    if (TARGET_NSIG_WORDS == 1) {
+        err |= __put_user(target_set.sig[0],
+                          (abi_ulong *)&ucp->tuc_sigmask);
+    } else {
+        abi_ulong *src, *dst;
+        src = target_set.sig;
+        dst = ucp->tuc_sigmask.sig;
+        for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
+             i++, dst++, src++)
+            err |= __put_user(*src, dst);
+        if (err)
+            goto do_sigsegv;
+    }
+
+    /* XXX: tstate must be saved properly */
+    //    err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
+    err |= __put_user(env->pc, &((*grp)[MC_PC]));
+    err |= __put_user(env->npc, &((*grp)[MC_NPC]));
+    err |= __put_user(env->y, &((*grp)[MC_Y]));
+    err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
+    err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
+    err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
+    err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
+    err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
+    err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
+    err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
+    err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
+    err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
+    err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
+    err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
+    err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
+    err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
+    err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
+    err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
+
+    w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
+    fp = i7 = 0;
+    if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), 
+                 abi_ulong) != 0)
+        goto do_sigsegv;
+    if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), 
+                 abi_ulong) != 0)
+        goto do_sigsegv;
+    err |= __put_user(fp, &(mcp->mc_fp));
+    err |= __put_user(i7, &(mcp->mc_i7));
+
+    {
+        uint32_t *src, *dst;
+        src = env->fpr;
+        dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        /* XXX: check that the CPU storage is the same as user context */
+        for (i = 0; i < 64; i++, dst++, src++)
+            err |= __put_user(*src, dst);
+    }
+    err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
+    err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
+    err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
+
+    if (err)
+        goto do_sigsegv;
+    unlock_user_struct(ucp, ucp_addr, 1);
+    return;
+ do_sigsegv:
+    unlock_user_struct(ucp, ucp_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+#endif
+#elif defined(TARGET_ABI_MIPSN64)
+
+# warning signal handling not implemented
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#elif defined(TARGET_ABI_MIPSN32)
+
+# warning signal handling not implemented
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#elif defined(TARGET_ABI_MIPSO32)
+
+struct target_sigcontext {
+    uint32_t   sc_regmask;     /* Unused */
+    uint32_t   sc_status;
+    uint64_t   sc_pc;
+    uint64_t   sc_regs[32];
+    uint64_t   sc_fpregs[32];
+    uint32_t   sc_ownedfp;     /* Unused */
+    uint32_t   sc_fpc_csr;
+    uint32_t   sc_fpc_eir;     /* Unused */
+    uint32_t   sc_used_math;
+    uint32_t   sc_dsp;         /* dsp status, was sc_ssflags */
+    uint32_t   pad0;
+    uint64_t   sc_mdhi;
+    uint64_t   sc_mdlo;
+    target_ulong   sc_hi1;         /* Was sc_cause */
+    target_ulong   sc_lo1;         /* Was sc_badvaddr */
+    target_ulong   sc_hi2;         /* Was sc_sigset[4] */
+    target_ulong   sc_lo2;
+    target_ulong   sc_hi3;
+    target_ulong   sc_lo3;
+};
+
+struct sigframe {
+    uint32_t sf_ass[4];			/* argument save space for o32 */
+    uint32_t sf_code[2];			/* signal trampoline */
+    struct target_sigcontext sf_sc;
+    target_sigset_t sf_mask;
+};
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    target_ulong tuc_link;
+    target_stack_t tuc_stack;
+    target_ulong pad0;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+    uint32_t rs_ass[4];               /* argument save space for o32 */
+    uint32_t rs_code[2];              /* signal trampoline */
+    struct target_siginfo rs_info;
+    struct target_ucontext rs_uc;
+};
+
+/* Install trampoline to jump back from signal handler */
+static inline int install_sigtramp(unsigned int *tramp,   unsigned int syscall)
+{
+    int err;
+
+    /*
+    * Set up the return code ...
+    *
+    *         li      v0, __NR__foo_sigreturn
+    *         syscall
+    */
+
+    err = __put_user(0x24020000 + syscall, tramp + 0);
+    err |= __put_user(0x0000000c          , tramp + 1);
+    /* flush_cache_sigtramp((unsigned long) tramp); */
+    return err;
+}
+
+static inline int
+setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
+{
+    int err = 0;
+
+    err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
+
+#define save_gp_reg(i) do {   						\
+        err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);	\
+    } while(0)
+    __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
+    save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
+    save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
+    save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
+    save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
+    save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
+    save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
+    save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
+    save_gp_reg(31);
+#undef save_gp_reg
+
+    err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+    err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+    /* Not used yet, but might be useful if we ever have DSP suppport */
+#if 0
+    if (cpu_has_dsp) {
+	err |= __put_user(mfhi1(), &sc->sc_hi1);
+	err |= __put_user(mflo1(), &sc->sc_lo1);
+	err |= __put_user(mfhi2(), &sc->sc_hi2);
+	err |= __put_user(mflo2(), &sc->sc_lo2);
+	err |= __put_user(mfhi3(), &sc->sc_hi3);
+	err |= __put_user(mflo3(), &sc->sc_lo3);
+	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
+    }
+    /* same with 64 bit */
+#ifdef CONFIG_64BIT
+    err |= __put_user(regs->hi, &sc->sc_hi[0]);
+    err |= __put_user(regs->lo, &sc->sc_lo[0]);
+    if (cpu_has_dsp) {
+	err |= __put_user(mfhi1(), &sc->sc_hi[1]);
+	err |= __put_user(mflo1(), &sc->sc_lo[1]);
+	err |= __put_user(mfhi2(), &sc->sc_hi[2]);
+	err |= __put_user(mflo2(), &sc->sc_lo[2]);
+	err |= __put_user(mfhi3(), &sc->sc_hi[3]);
+	err |= __put_user(mflo3(), &sc->sc_lo[3]);
+	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
+    }
+#endif
+#endif
+
+#if 0
+    err |= __put_user(!!used_math(), &sc->sc_used_math);
+
+    if (!used_math())
+	goto out;
+
+    /*
+    * Save FPU state to signal context.  Signal handler will "inherit"
+    * current FPU state.
+    */
+    preempt_disable();
+
+    if (!is_fpu_owner()) {
+	own_fpu();
+	restore_fp(current);
+    }
+    err |= save_fp_context(sc);
+
+    preempt_enable();
+    out:
+#endif
+    return err;
+}
+
+static inline int
+restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
+{
+    int err = 0;
+
+    err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
+
+    err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+    err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+#define restore_gp_reg(i) do {   							\
+        err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);		\
+    } while(0)
+    restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
+    restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
+    restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
+    restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
+    restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
+    restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
+    restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
+    restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
+    restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
+    restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
+    restore_gp_reg(31);
+#undef restore_gp_reg
+
+#if 0
+    if (cpu_has_dsp) {
+	err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
+	err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
+	err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
+	err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
+	err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
+	err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
+	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
+    }
+#ifdef CONFIG_64BIT
+    err |= __get_user(regs->hi, &sc->sc_hi[0]);
+    err |= __get_user(regs->lo, &sc->sc_lo[0]);
+    if (cpu_has_dsp) {
+	err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
+	err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
+	err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
+	err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
+	err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
+	err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
+	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
+    }
+#endif
+
+    err |= __get_user(used_math, &sc->sc_used_math);
+    conditional_used_math(used_math);
+
+    preempt_disable();
+
+    if (used_math()) {
+	/* restore fpu context if we have used it before */
+	own_fpu();
+	err |= restore_fp_context(sc);
+    } else {
+	/* signal handler may have used FPU.  Give it up. */
+	lose_fpu();
+    }
+
+    preempt_enable();
+#endif
+    return err;
+}
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
+{
+    unsigned long sp;
+
+    /* Default to using normal stack */
+    sp = regs->active_tc.gpr[29];
+
+    /*
+     * FPU emulator may have it's own trampoline active just
+     * above the user stack, 16-bytes before the next lowest
+     * 16 byte boundary.  Try to avoid trashing it.
+     */
+    sp -= 32;
+
+    /* This is the X/Open sanctioned signal stack switching.  */
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+
+    return (sp - frame_size) & ~7;
+}
+
+/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
+static void setup_frame(int sig, struct target_sigaction * ka,
+                        target_sigset_t *set, CPUState *regs)
+{
+    struct sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
+
+    if(setup_sigcontext(regs, &frame->sf_sc))
+	goto give_sigsegv;
+
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+	if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
+	    goto give_sigsegv;
+    }
+
+    /*
+    * Arguments to signal handler:
+    *
+    *   a0 = signal number
+    *   a1 = 0 (should be cause)
+    *   a2 = pointer to struct sigcontext
+    *
+    * $25 and PC point to the signal handler, $29 points to the
+    * struct sigframe.
+    */
+    regs->active_tc.gpr[ 4] = sig;
+    regs->active_tc.gpr[ 5] = 0;
+    regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
+    /* The original kernel code sets CP0_EPC to the handler
+    * since it returns to userland using eret
+    * we cannot do this here, and we must set PC directly */
+    regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV/*, current*/);
+    return;
+}
+
+long do_sigreturn(CPUState *regs)
+{
+    struct sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+    target_sigset_t target_set;
+    int i;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigreturn\n");
+#endif
+    frame_addr = regs->active_tc.gpr[29];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+   	if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
+	    goto badframe;
+    }
+
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->sf_sc))
+   	goto badframe;
+
+#if 0
+    /*
+     * Don't let your children do this ...
+     */
+    __asm__ __volatile__(
+   	"move\t$29, %0\n\t"
+   	"j\tsyscall_exit"
+   	:/* no outputs */
+   	:"r" (&regs));
+    /* Unreached */
+#endif
+
+    regs->active_tc.PC = regs->CP0_EPC;
+    /* I am not sure this is right, but it seems to work
+    * maybe a problem with nested signals ? */
+    regs->CP0_EPC = 0;
+    return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+    force_sig(TARGET_SIGSEGV/*, current*/);
+    return 0;
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
+
+    copy_siginfo_to_user(&frame->rs_info, info);
+
+    __put_user(0, &frame->rs_uc.tuc_flags);
+    __put_user(0, &frame->rs_uc.tuc_link);
+    __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
+    __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
+    __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+               &frame->rs_uc.tuc_stack.ss_flags);
+
+    setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
+    }
+
+    /*
+    * Arguments to signal handler:
+    *
+    *   a0 = signal number
+    *   a1 = pointer to struct siginfo
+    *   a2 = pointer to struct ucontext
+    *
+    * $25 and PC point to the signal handler, $29 points to the
+    * struct sigframe.
+    */
+    env->active_tc.gpr[ 4] = sig;
+    env->active_tc.gpr[ 5] = frame_addr
+                             + offsetof(struct target_rt_sigframe, rs_info);
+    env->active_tc.gpr[ 6] = frame_addr
+                             + offsetof(struct target_rt_sigframe, rs_uc);
+    env->active_tc.gpr[29] = frame_addr;
+    env->active_tc.gpr[31] = frame_addr
+                             + offsetof(struct target_rt_sigframe, rs_code);
+    /* The original kernel code sets CP0_EPC to the handler
+    * since it returns to userland using eret
+    * we cannot do this here, and we must set PC directly */
+    env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV/*, current*/);
+    return;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+    frame_addr = env->active_tc.gpr[29];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
+        goto badframe;
+
+    if (do_sigaltstack(frame_addr +
+		       offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
+		       0, get_sp_from_cpustate(env)) == -EFAULT)
+        goto badframe;
+
+    env->active_tc.PC = env->CP0_EPC;
+    /* I am not sure this is right, but it seems to work
+    * maybe a problem with nested signals ? */
+    env->CP0_EPC = 0;
+    return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+    force_sig(TARGET_SIGSEGV/*, current*/);
+    return 0;
+}
+
+#elif defined(TARGET_SH4)
+
+/*
+ * code and data structures from linux kernel:
+ * include/asm-sh/sigcontext.h
+ * arch/sh/kernel/signal.c
+ */
+
+struct target_sigcontext {
+    target_ulong  oldmask;
+
+    /* CPU registers */
+    target_ulong  sc_gregs[16];
+    target_ulong  sc_pc;
+    target_ulong  sc_pr;
+    target_ulong  sc_sr;
+    target_ulong  sc_gbr;
+    target_ulong  sc_mach;
+    target_ulong  sc_macl;
+
+    /* FPU registers */
+    target_ulong  sc_fpregs[16];
+    target_ulong  sc_xfpregs[16];
+    unsigned int sc_fpscr;
+    unsigned int sc_fpul;
+    unsigned int sc_ownedfp;
+};
+
+struct target_sigframe
+{
+    struct target_sigcontext sc;
+    target_ulong extramask[TARGET_NSIG_WORDS-1];
+    uint16_t retcode[3];
+};
+
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    struct target_ucontext *tuc_link;
+    target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t tuc_sigmask;	/* mask last for extensibility */
+};
+
+struct target_rt_sigframe
+{
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    uint16_t retcode[3];
+};
+
+
+#define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
+#define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+                         unsigned long sp, size_t frame_size)
+{
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+
+    return (sp - frame_size) & -8ul;
+}
+
+static int setup_sigcontext(struct target_sigcontext *sc,
+			    CPUState *regs, unsigned long mask)
+{
+    int err = 0;
+    int i;
+
+#define COPY(x)         err |= __put_user(regs->x, &sc->sc_##x)
+    COPY(gregs[0]); COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    for (i=0; i<16; i++) {
+        err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
+    }
+    err |= __put_user(regs->fpscr, &sc->sc_fpscr);
+    err |= __put_user(regs->fpul, &sc->sc_fpul);
+
+    /* non-iBCS2 extensions.. */
+    err |= __put_user(mask, &sc->oldmask);
+
+    return err;
+}
+
+static int restore_sigcontext(CPUState *regs, struct target_sigcontext *sc,
+                              target_ulong *r0_p)
+{
+    unsigned int err = 0;
+    int i;
+
+#define COPY(x)         err |= __get_user(regs->x, &sc->sc_##x)
+    COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    for (i=0; i<16; i++) {
+        err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
+    }
+    err |= __get_user(regs->fpscr, &sc->sc_fpscr);
+    err |= __get_user(regs->fpul, &sc->sc_fpul);
+
+    regs->tra = -1;         /* disable syscall checks */
+    err |= __get_user(*r0_p, &sc->sc_gregs[0]);
+    return err;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+    for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+        err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(2), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = 0;
+    regs->gregs[6] = (unsigned long) &frame->sc;
+    regs->pc = (unsigned long) ka->_sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= copy_siginfo_to_user(&frame->info, info);
+
+    /* Create the ucontext.  */
+    err |= __put_user(0, &frame->uc.tuc_flags);
+    err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
+    err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
+		      &frame->uc.tuc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(regs->gregs[15]),
+		      &frame->uc.tuc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+		      &frame->uc.tuc_stack.ss_size);
+    err |= setup_sigcontext(&frame->uc.tuc_mcontext,
+			    regs, set->sig[0]);
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(2), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = (unsigned long) &frame->info;
+    regs->gregs[6] = (unsigned long) &frame->uc;
+    regs->pc = (unsigned long) ka->_sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+long do_sigreturn(CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+    target_sigset_t target_set;
+    target_ulong r0;
+    int i;
+    int err = 0;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
+    }
+
+    if (err)
+        goto badframe;
+
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->sc, &r0))
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return r0;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+    target_ulong r0;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
+        goto badframe;
+
+    if (do_sigaltstack(frame_addr +
+		       offsetof(struct target_rt_sigframe, uc.tuc_stack),
+		       0, get_sp_from_cpustate(regs)) == -EFAULT)
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return r0;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+#elif defined(TARGET_MICROBLAZE)
+
+struct target_sigcontext {
+    struct target_pt_regs regs;  /* needs to be first */
+    uint32_t oldmask;
+};
+
+struct target_stack_t {
+    abi_ulong ss_sp;
+    int ss_flags;
+    unsigned int ss_size;
+};
+
+struct target_ucontext {
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    struct target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
+};
+
+/* Signal frames. */
+struct target_signal_frame {
+    struct target_ucontext uc;
+    uint32_t extramask[TARGET_NSIG_WORDS - 1];
+    uint32_t tramp[2];
+};
+
+struct rt_signal_frame {
+    struct siginfo info;
+    struct ucontext uc;
+    uint32_t tramp[2];
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
+{
+    __put_user(env->regs[0], &sc->regs.r0);
+    __put_user(env->regs[1], &sc->regs.r1);
+    __put_user(env->regs[2], &sc->regs.r2);
+    __put_user(env->regs[3], &sc->regs.r3);
+    __put_user(env->regs[4], &sc->regs.r4);
+    __put_user(env->regs[5], &sc->regs.r5);
+    __put_user(env->regs[6], &sc->regs.r6);
+    __put_user(env->regs[7], &sc->regs.r7);
+    __put_user(env->regs[8], &sc->regs.r8);
+    __put_user(env->regs[9], &sc->regs.r9);
+    __put_user(env->regs[10], &sc->regs.r10);
+    __put_user(env->regs[11], &sc->regs.r11);
+    __put_user(env->regs[12], &sc->regs.r12);
+    __put_user(env->regs[13], &sc->regs.r13);
+    __put_user(env->regs[14], &sc->regs.r14);
+    __put_user(env->regs[15], &sc->regs.r15);
+    __put_user(env->regs[16], &sc->regs.r16);
+    __put_user(env->regs[17], &sc->regs.r17);
+    __put_user(env->regs[18], &sc->regs.r18);
+    __put_user(env->regs[19], &sc->regs.r19);
+    __put_user(env->regs[20], &sc->regs.r20);
+    __put_user(env->regs[21], &sc->regs.r21);
+    __put_user(env->regs[22], &sc->regs.r22);
+    __put_user(env->regs[23], &sc->regs.r23);
+    __put_user(env->regs[24], &sc->regs.r24);
+    __put_user(env->regs[25], &sc->regs.r25);
+    __put_user(env->regs[26], &sc->regs.r26);
+    __put_user(env->regs[27], &sc->regs.r27);
+    __put_user(env->regs[28], &sc->regs.r28);
+    __put_user(env->regs[29], &sc->regs.r29);
+    __put_user(env->regs[30], &sc->regs.r30);
+    __put_user(env->regs[31], &sc->regs.r31);
+    __put_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
+{
+    __get_user(env->regs[0], &sc->regs.r0);
+    __get_user(env->regs[1], &sc->regs.r1);
+    __get_user(env->regs[2], &sc->regs.r2);
+    __get_user(env->regs[3], &sc->regs.r3);
+    __get_user(env->regs[4], &sc->regs.r4);
+    __get_user(env->regs[5], &sc->regs.r5);
+    __get_user(env->regs[6], &sc->regs.r6);
+    __get_user(env->regs[7], &sc->regs.r7);
+    __get_user(env->regs[8], &sc->regs.r8);
+    __get_user(env->regs[9], &sc->regs.r9);
+    __get_user(env->regs[10], &sc->regs.r10);
+    __get_user(env->regs[11], &sc->regs.r11);
+    __get_user(env->regs[12], &sc->regs.r12);
+    __get_user(env->regs[13], &sc->regs.r13);
+    __get_user(env->regs[14], &sc->regs.r14);
+    __get_user(env->regs[15], &sc->regs.r15);
+    __get_user(env->regs[16], &sc->regs.r16);
+    __get_user(env->regs[17], &sc->regs.r17);
+    __get_user(env->regs[18], &sc->regs.r18);
+    __get_user(env->regs[19], &sc->regs.r19);
+    __get_user(env->regs[20], &sc->regs.r20);
+    __get_user(env->regs[21], &sc->regs.r21);
+    __get_user(env->regs[22], &sc->regs.r22);
+    __get_user(env->regs[23], &sc->regs.r23);
+    __get_user(env->regs[24], &sc->regs.r24);
+    __get_user(env->regs[25], &sc->regs.r25);
+    __get_user(env->regs[26], &sc->regs.r26);
+    __get_user(env->regs[27], &sc->regs.r27);
+    __get_user(env->regs[28], &sc->regs.r28);
+    __get_user(env->regs[29], &sc->regs.r29);
+    __get_user(env->regs[30], &sc->regs.r30);
+    __get_user(env->regs[31], &sc->regs.r31);
+    __get_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+                              CPUState *env, int frame_size)
+{
+    abi_ulong sp = env->regs[1];
+
+    if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+
+    return ((sp - frame_size) & -8UL);
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    struct target_signal_frame *frame;
+    abi_ulong frame_addr;
+    int err = 0;
+    int i;
+
+    frame_addr = get_sigframe(ka, env, sizeof *frame);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+        goto badframe;
+
+    /* Save the mask.  */
+    err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
+    if (err)
+        goto badframe;
+
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->sig[i], &frame->extramask[i - 1]))
+            goto badframe;
+    }
+
+    setup_sigcontext(&frame->uc.tuc_mcontext, env);
+
+    /* Set up to return from userspace. If provided, use a stub
+       already in userspace. */
+    /* minus 8 is offset to cater for "rtsd r15,8" offset */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+        env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
+    } else {
+        uint32_t t;
+        /* Note, these encodings are _big endian_! */
+        /* addi r12, r0, __NR_sigreturn */
+        t = 0x31800000UL | TARGET_NR_sigreturn;
+        err |= __put_user(t, frame->tramp + 0);
+        /* brki r14, 0x8 */
+        t = 0xb9cc0008UL;
+        err |= __put_user(t, frame->tramp + 1);
+
+        /* Return from sighandler will jump to the tramp.
+           Negative 8 offset because return is rtsd r15, 8 */
+        env->regs[15] = ((unsigned long)frame->tramp) - 8;
+    }
+
+    if (err)
+        goto badframe;
+
+    /* Set up registers for signal handler */
+    env->regs[1] = (unsigned long) frame;
+    /* Signal handler args: */
+    env->regs[5] = sig; /* Arg 0: signum */
+    env->regs[6] = 0;
+    env->regs[7] = (unsigned long) &frame->uc; /* arg 1: sigcontext */
+
+    /* Offset of 4 to handle microblaze rtid r14, 0 */
+    env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+  badframe:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    struct target_signal_frame *frame;
+    abi_ulong frame_addr;
+    target_sigset_t target_set;
+    sigset_t set;
+    int i;
+
+    frame_addr = env->regs[R_SP];
+    /* Make sure the guest isn't playing games.  */
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+        goto badframe;
+
+    /* Restore blocked signals */
+    if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
+        goto badframe;
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
+            goto badframe;
+    }
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    restore_sigcontext(&frame->uc.tuc_mcontext, env);
+    /* We got here through a sigreturn syscall, our path back is via an
+       rtb insn so setup r14 for that.  */
+    env->regs[14] = env->sregs[SR_PC];
+ 
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->regs[10];
+  badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#elif defined(TARGET_CRIS)
+
+struct target_sigcontext {
+        struct target_pt_regs regs;  /* needs to be first */
+        uint32_t oldmask;
+        uint32_t usp;    /* usp before stacking this gunk on it */
+};
+
+/* Signal frames. */
+struct target_signal_frame {
+        struct target_sigcontext sc;
+        uint32_t extramask[TARGET_NSIG_WORDS - 1];
+        uint8_t retcode[8];       /* Trampoline code. */
+};
+
+struct rt_signal_frame {
+        struct siginfo *pinfo;
+        void *puc;
+        struct siginfo info;
+        struct ucontext uc;
+        uint8_t retcode[8];       /* Trampoline code. */
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
+{
+	__put_user(env->regs[0], &sc->regs.r0);
+	__put_user(env->regs[1], &sc->regs.r1);
+	__put_user(env->regs[2], &sc->regs.r2);
+	__put_user(env->regs[3], &sc->regs.r3);
+	__put_user(env->regs[4], &sc->regs.r4);
+	__put_user(env->regs[5], &sc->regs.r5);
+	__put_user(env->regs[6], &sc->regs.r6);
+	__put_user(env->regs[7], &sc->regs.r7);
+	__put_user(env->regs[8], &sc->regs.r8);
+	__put_user(env->regs[9], &sc->regs.r9);
+	__put_user(env->regs[10], &sc->regs.r10);
+	__put_user(env->regs[11], &sc->regs.r11);
+	__put_user(env->regs[12], &sc->regs.r12);
+	__put_user(env->regs[13], &sc->regs.r13);
+	__put_user(env->regs[14], &sc->usp);
+	__put_user(env->regs[15], &sc->regs.acr);
+	__put_user(env->pregs[PR_MOF], &sc->regs.mof);
+	__put_user(env->pregs[PR_SRP], &sc->regs.srp);
+	__put_user(env->pc, &sc->regs.erp);
+}
+
+static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
+{
+	__get_user(env->regs[0], &sc->regs.r0);
+	__get_user(env->regs[1], &sc->regs.r1);
+	__get_user(env->regs[2], &sc->regs.r2);
+	__get_user(env->regs[3], &sc->regs.r3);
+	__get_user(env->regs[4], &sc->regs.r4);
+	__get_user(env->regs[5], &sc->regs.r5);
+	__get_user(env->regs[6], &sc->regs.r6);
+	__get_user(env->regs[7], &sc->regs.r7);
+	__get_user(env->regs[8], &sc->regs.r8);
+	__get_user(env->regs[9], &sc->regs.r9);
+	__get_user(env->regs[10], &sc->regs.r10);
+	__get_user(env->regs[11], &sc->regs.r11);
+	__get_user(env->regs[12], &sc->regs.r12);
+	__get_user(env->regs[13], &sc->regs.r13);
+	__get_user(env->regs[14], &sc->usp);
+	__get_user(env->regs[15], &sc->regs.acr);
+	__get_user(env->pregs[PR_MOF], &sc->regs.mof);
+	__get_user(env->pregs[PR_SRP], &sc->regs.srp);
+	__get_user(env->pc, &sc->regs.erp);
+}
+
+static abi_ulong get_sigframe(CPUState *env, int framesize)
+{
+	abi_ulong sp;
+	/* Align the stack downwards to 4.  */
+	sp = (env->regs[R_SP] & ~3);
+	return sp - framesize;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+	struct target_signal_frame *frame;
+	abi_ulong frame_addr;
+	int err = 0;
+	int i;
+
+	frame_addr = get_sigframe(env, sizeof *frame);
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+		goto badframe;
+
+	/*
+	 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
+	 * use this trampoline anymore but it sets it up for GDB.
+	 * In QEMU, using the trampoline simplifies things a bit so we use it.
+	 *
+	 * This is movu.w __NR_sigreturn, r9; break 13;
+	 */
+	err |= __put_user(0x9c5f, frame->retcode+0);
+	err |= __put_user(TARGET_NR_sigreturn, 
+			  frame->retcode+2);
+	err |= __put_user(0xe93d, frame->retcode+4);
+
+	/* Save the mask.  */
+	err |= __put_user(set->sig[0], &frame->sc.oldmask);
+	if (err)
+		goto badframe;
+
+	for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+		if (__put_user(set->sig[i], &frame->extramask[i - 1]))
+			goto badframe;
+	}
+
+	setup_sigcontext(&frame->sc, env);
+
+	/* Move the stack and setup the arguments for the handler.  */
+	env->regs[R_SP] = (uint32_t) (unsigned long) frame;
+	env->regs[10] = sig;
+	env->pc = (unsigned long) ka->_sa_handler;
+	/* Link SRP so the guest returns through the trampoline.  */
+	env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
+
+	unlock_user_struct(frame, frame_addr, 1);
+	return;
+  badframe:
+	unlock_user_struct(frame, frame_addr, 1);
+	force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+	struct target_signal_frame *frame;
+	abi_ulong frame_addr;
+	target_sigset_t target_set;
+	sigset_t set;
+	int i;
+
+	frame_addr = env->regs[R_SP];
+	/* Make sure the guest isn't playing games.  */
+	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+		goto badframe;
+
+	/* Restore blocked signals */
+	if (__get_user(target_set.sig[0], &frame->sc.oldmask))
+		goto badframe;
+	for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+		if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
+			goto badframe;
+	}
+	target_to_host_sigset_internal(&set, &target_set);
+	sigprocmask(SIG_SETMASK, &set, NULL);
+
+	restore_sigcontext(&frame->sc, env);
+	unlock_user_struct(frame, frame_addr, 0);
+	return env->regs[10];
+  badframe:
+	unlock_user_struct(frame, frame_addr, 0);
+	force_sig(TARGET_SIGSEGV);
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#elif defined(TARGET_S390X)
+
+#define __NUM_GPRS 16
+#define __NUM_FPRS 16
+#define __NUM_ACRS 16
+
+#define S390_SYSCALL_SIZE   2
+#define __SIGNAL_FRAMESIZE      160 /* FIXME: 31-bit mode -> 96 */
+
+#define _SIGCONTEXT_NSIG        64
+#define _SIGCONTEXT_NSIG_BPW    64 /* FIXME: 31-bit mode -> 32 */
+#define _SIGCONTEXT_NSIG_WORDS  (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define _SIGMASK_COPY_SIZE    (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+#define PSW_ADDR_AMODE            0x0000000000000000UL /* 0x80000000UL for 31-bit */
+#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
+
+typedef struct {
+    target_psw_t psw;
+    target_ulong gprs[__NUM_GPRS];
+    unsigned int acrs[__NUM_ACRS];
+} target_s390_regs_common;
+
+typedef struct {
+    unsigned int fpc;
+    double   fprs[__NUM_FPRS];
+} target_s390_fp_regs;
+
+typedef struct {
+    target_s390_regs_common regs;
+    target_s390_fp_regs     fpregs;
+} target_sigregs;
+
+struct target_sigcontext {
+    target_ulong   oldmask[_SIGCONTEXT_NSIG_WORDS];
+    target_sigregs *sregs;
+};
+
+typedef struct {
+    uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+    struct target_sigcontext sc;
+    target_sigregs sregs;
+    int signo;
+    uint8_t retcode[S390_SYSCALL_SIZE];
+} sigframe;
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    struct target_ucontext *tuc_link;
+    target_stack_t tuc_stack;
+    target_sigregs tuc_mcontext;
+    target_sigset_t tuc_sigmask;   /* mask last for extensibility */
+};
+
+typedef struct {
+    uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+    uint8_t retcode[S390_SYSCALL_SIZE];
+    struct target_siginfo info;
+    struct target_ucontext uc;
+} rt_sigframe;
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUState *env, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Default to using normal stack */
+    sp = env->regs[15];
+
+    /* This is the X/Open sanctioned signal stack switching.  */
+    if (ka->sa_flags & TARGET_SA_ONSTACK) {
+        if (!sas_ss_flags(sp)) {
+            sp = target_sigaltstack_used.ss_sp +
+                 target_sigaltstack_used.ss_size;
+        }
+    }
+
+    /* This is the legacy signal stack switching. */
+    else if (/* FIXME !user_mode(regs) */ 0 &&
+             !(ka->sa_flags & TARGET_SA_RESTORER) &&
+             ka->sa_restorer) {
+        sp = (abi_ulong) ka->sa_restorer;
+    }
+
+    return (sp - frame_size) & -8ul;
+}
+
+static void save_sigregs(CPUState *env, target_sigregs *sregs)
+{
+    int i;
+    //save_access_regs(current->thread.acrs); FIXME
+
+    /* Copy a 'clean' PSW mask to the user to avoid leaking
+       information about whether PER is currently on.  */
+    __put_user(env->psw.mask, &sregs->regs.psw.mask);
+    __put_user(env->psw.addr, &sregs->regs.psw.addr);
+    for (i = 0; i < 16; i++) {
+        __put_user(env->regs[i], &sregs->regs.gprs[i]);
+    }
+    for (i = 0; i < 16; i++) {
+        __put_user(env->aregs[i], &sregs->regs.acrs[i]);
+    }
+    /*
+     * We have to store the fp registers to current->thread.fp_regs
+     * to merge them with the emulated registers.
+     */
+    //save_fp_regs(&current->thread.fp_regs); FIXME
+    for (i = 0; i < 16; i++) {
+        __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
+    }
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    sigframe *frame;
+    abi_ulong frame_addr;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+            goto give_sigsegv;
+    }
+
+    qemu_log("%s: 1\n", __FUNCTION__);
+    if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
+              goto give_sigsegv;
+    }
+
+    save_sigregs(env, &frame->sregs);
+
+    __put_user((abi_ulong)(unsigned long)&frame->sregs,
+               (abi_ulong *)&frame->sc.sregs);
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+            env->regs[14] = (unsigned long)
+                    ka->sa_restorer | PSW_ADDR_AMODE;
+    } else {
+            env->regs[14] = (unsigned long)
+                    frame->retcode | PSW_ADDR_AMODE;
+            if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
+                           (uint16_t *)(frame->retcode)))
+                    goto give_sigsegv;
+    }
+
+    /* Set up backchain. */
+    if (__put_user(env->regs[15], (abi_ulong *) frame)) {
+            goto give_sigsegv;
+    }
+
+    /* Set up registers for signal handler */
+    env->regs[15] = (target_ulong)(unsigned long) frame;
+    env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+    env->regs[2] = sig; //map_signal(sig);
+    env->regs[3] = (target_ulong)(unsigned long) &frame->sc;
+
+    /* We forgot to include these in the sigcontext.
+       To avoid breaking binary compatibility, they are passed as args. */
+    env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
+    env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
+
+    /* Place signal number on stack to allow backtrace from handler.  */
+    if (__put_user(env->regs[2], (int *) &frame->signo)) {
+            goto give_sigsegv;
+    }
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    qemu_log("%s: give_sigsegv\n", __FUNCTION__);
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+                           target_sigset_t *set, CPUState *env)
+{
+    int i;
+    rt_sigframe *frame;
+    abi_ulong frame_addr;
+
+    frame_addr = get_sigframe(ka, env, sizeof *frame);
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    qemu_log("%s: 1\n", __FUNCTION__);
+    if (copy_siginfo_to_user(&frame->info, info)) {
+        goto give_sigsegv;
+    }
+
+    /* Create the ucontext.  */
+    __put_user(0, &frame->uc.tuc_flags);
+    __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
+    __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
+    __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+                      &frame->uc.tuc_stack.ss_flags);
+    __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
+    save_sigregs(env, &frame->uc.tuc_mcontext);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user((abi_ulong)set->sig[i],
+        (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa_flags & TARGET_SA_RESTORER) {
+        env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
+    } else {
+        env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
+        if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
+                       (uint16_t *)(frame->retcode))) {
+            goto give_sigsegv;
+        }
+    }
+
+    /* Set up backchain. */
+    if (__put_user(env->regs[15], (abi_ulong *) frame)) {
+        goto give_sigsegv;
+    }
+
+    /* Set up registers for signal handler */
+    env->regs[15] = (target_ulong)(unsigned long) frame;
+    env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+    env->regs[2] = sig; //map_signal(sig);
+    env->regs[3] = (target_ulong)(unsigned long) &frame->info;
+    env->regs[4] = (target_ulong)(unsigned long) &frame->uc;
+    return;
+
+give_sigsegv:
+    qemu_log("%s: give_sigsegv\n", __FUNCTION__);
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static int
+restore_sigregs(CPUState *env, target_sigregs *sc)
+{
+    int err = 0;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
+    }
+
+    err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
+    qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
+             __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
+             (unsigned long long)env->psw.addr);
+    err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
+    /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
+
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
+    }
+    for (i = 0; i < 16; i++) {
+        err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
+    }
+
+    return err;
+}
+
+long do_sigreturn(CPUState *env)
+{
+    sigframe *frame;
+    abi_ulong frame_addr = env->regs[15];
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    target_sigset_t target_set;
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
+        goto badframe;
+    }
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+
+    if (restore_sigregs(env, &frame->sregs)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->regs[2];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    rt_sigframe *frame;
+    abi_ulong frame_addr = env->regs[15];
+    qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
+             (unsigned long long)frame_addr);
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+
+    sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
+
+    if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
+        goto badframe;
+    }
+
+    if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
+                       get_sp_from_cpustate(env)) == -EFAULT) {
+        goto badframe;
+    }
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->regs[2];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
+
+/* FIXME: Many of the structures are defined for both PPC and PPC64, but
+   the signal handling is different enough that we haven't implemented
+   support for PPC64 yet.  Hence the restriction above.
+
+   There are various #if'd blocks for code for TARGET_PPC64.  These
+   blocks should go away so that we can successfully run 32-bit and
+   64-bit binaries on a QEMU configured for PPC64.  */
+
+/* Size of dummy stack frame allocated when calling signal handler.
+   See arch/powerpc/include/asm/ptrace.h.  */
+#if defined(TARGET_PPC64)
+#define SIGNAL_FRAMESIZE 128
+#else
+#define SIGNAL_FRAMESIZE 64
+#endif
+
+/* See arch/powerpc/include/asm/sigcontext.h.  */
+struct target_sigcontext {
+    target_ulong _unused[4];
+    int32_t signal;
+#if defined(TARGET_PPC64)
+    int32_t pad0;
+#endif
+    target_ulong handler;
+    target_ulong oldmask;
+    target_ulong regs;      /* struct pt_regs __user * */
+    /* TODO: PPC64 includes extra bits here.  */
+};
+
+/* Indices for target_mcontext.mc_gregs, below.
+   See arch/powerpc/include/asm/ptrace.h for details.  */
+enum {
+    TARGET_PT_R0 = 0,
+    TARGET_PT_R1 = 1,
+    TARGET_PT_R2 = 2,
+    TARGET_PT_R3 = 3,
+    TARGET_PT_R4 = 4,
+    TARGET_PT_R5 = 5,
+    TARGET_PT_R6 = 6,
+    TARGET_PT_R7 = 7,
+    TARGET_PT_R8 = 8,
+    TARGET_PT_R9 = 9,
+    TARGET_PT_R10 = 10,
+    TARGET_PT_R11 = 11,
+    TARGET_PT_R12 = 12,
+    TARGET_PT_R13 = 13,
+    TARGET_PT_R14 = 14,
+    TARGET_PT_R15 = 15,
+    TARGET_PT_R16 = 16,
+    TARGET_PT_R17 = 17,
+    TARGET_PT_R18 = 18,
+    TARGET_PT_R19 = 19,
+    TARGET_PT_R20 = 20,
+    TARGET_PT_R21 = 21,
+    TARGET_PT_R22 = 22,
+    TARGET_PT_R23 = 23,
+    TARGET_PT_R24 = 24,
+    TARGET_PT_R25 = 25,
+    TARGET_PT_R26 = 26,
+    TARGET_PT_R27 = 27,
+    TARGET_PT_R28 = 28,
+    TARGET_PT_R29 = 29,
+    TARGET_PT_R30 = 30,
+    TARGET_PT_R31 = 31,
+    TARGET_PT_NIP = 32,
+    TARGET_PT_MSR = 33,
+    TARGET_PT_ORIG_R3 = 34,
+    TARGET_PT_CTR = 35,
+    TARGET_PT_LNK = 36,
+    TARGET_PT_XER = 37,
+    TARGET_PT_CCR = 38,
+    /* Yes, there are two registers with #39.  One is 64-bit only.  */
+    TARGET_PT_MQ = 39,
+    TARGET_PT_SOFTE = 39,
+    TARGET_PT_TRAP = 40,
+    TARGET_PT_DAR = 41,
+    TARGET_PT_DSISR = 42,
+    TARGET_PT_RESULT = 43,
+    TARGET_PT_REGS_COUNT = 44
+};
+
+/* See arch/powerpc/include/asm/ucontext.h.  Only used for 32-bit PPC;
+   on 64-bit PPC, sigcontext and mcontext are one and the same.  */
+struct target_mcontext {
+    target_ulong mc_gregs[48];
+    /* Includes fpscr.  */
+    uint64_t mc_fregs[33];
+    target_ulong mc_pad[2];
+    /* We need to handle Altivec and SPE at the same time, which no
+       kernel needs to do.  Fortunately, the kernel defines this bit to
+       be Altivec-register-large all the time, rather than trying to
+       twiddle it based on the specific platform.  */
+    union {
+        /* SPE vector registers.  One extra for SPEFSCR.  */
+        uint32_t spe[33];
+        /* Altivec vector registers.  The packing of VSCR and VRSAVE
+           varies depending on whether we're PPC64 or not: PPC64 splits
+           them apart; PPC32 stuffs them together.  */
+#if defined(TARGET_PPC64)
+#define QEMU_NVRREG 34
+#else
+#define QEMU_NVRREG 33
+#endif
+        ppc_avr_t altivec[QEMU_NVRREG];
+#undef QEMU_NVRREG
+    } mc_vregs __attribute__((__aligned__(16)));
+};
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    target_ulong tuc_link;    /* struct ucontext __user * */
+    struct target_sigaltstack tuc_stack;
+#if !defined(TARGET_PPC64)
+    int32_t tuc_pad[7];
+    target_ulong tuc_regs;    /* struct mcontext __user *
+                                points to uc_mcontext field */
+#endif
+    target_sigset_t tuc_sigmask;
+#if defined(TARGET_PPC64)
+    target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
+    struct target_sigcontext tuc_mcontext;
+#else
+    int32_t tuc_maskext[30];
+    int32_t tuc_pad2[3];
+    struct target_mcontext tuc_mcontext;
+#endif
+};
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+struct target_sigframe {
+    struct target_sigcontext sctx;
+    struct target_mcontext mctx;
+    int32_t abigap[56];
+};
+
+struct target_rt_sigframe {
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    int32_t abigap[56];
+};
+
+/* We use the mc_pad field for the signal return trampoline.  */
+#define tramp mc_pad
+
+/* See arch/powerpc/kernel/signal.c.  */
+static target_ulong get_sigframe(struct target_sigaction *ka,
+                                 CPUState *env,
+                                 int frame_size)
+{
+    target_ulong oldsp, newsp;
+
+    oldsp = env->gpr[1];
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
+        (sas_ss_flags(oldsp))) {
+        oldsp = (target_sigaltstack_used.ss_sp
+                 + target_sigaltstack_used.ss_size);
+    }
+
+    newsp = (oldsp - frame_size) & ~0xFUL;
+
+    return newsp;
+}
+
+static int save_user_regs(CPUState *env, struct target_mcontext *frame,
+                          int sigret)
+{
+    target_ulong msr = env->msr;
+    int i;
+    target_ulong ccr = 0;
+
+    /* In general, the kernel attempts to be intelligent about what it
+       needs to save for Altivec/FP/SPE registers.  We don't care that
+       much, so we just go ahead and save everything.  */
+
+    /* Save general registers.  */
+    for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+        if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
+            return 1;
+        }
+    }
+    if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
+        || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+    }
+    if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
+        return 1;
+
+    /* Save Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+            if (__put_user(avr->u64[0], &vreg->u64[0]) ||
+                __put_user(avr->u64[1], &vreg->u64[1])) {
+                return 1;
+            }
+        }
+        /* Set MSR_VR in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_VR;
+        if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
+                       &frame->mc_vregs.altivec[32].u32[3]))
+            return 1;
+    }
+
+    /* Save floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
+                return 1;
+            }
+        }
+        if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
+            return 1;
+    }
+
+    /* Save SPE registers.  The kernel only saves the high half.  */
+    if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+        for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+            if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#endif
+        /* Set MSR_SPE in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_SPE;
+        if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+            return 1;
+    }
+
+    /* Store MSR.  */
+    if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
+        return 1;
+
+    /* Set up the sigreturn trampoline: li r0,sigret; sc.  */
+    if (sigret) {
+        if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
+            __put_user(0x44000002UL, &frame->tramp[1])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int restore_user_regs(CPUState *env,
+                             struct target_mcontext *frame, int sig)
+{
+    target_ulong save_r2 = 0;
+    target_ulong msr;
+    target_ulong ccr;
+
+    int i;
+
+    if (!sig) {
+        save_r2 = env->gpr[2];
+    }
+
+    /* Restore general registers.  */
+    for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+        if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
+            return 1;
+        }
+    }
+    if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
+        || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+    if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
+        return 1;
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
+    }
+
+    if (!sig) {
+        env->gpr[2] = save_r2;
+    }
+    /* Restore MSR.  */
+    if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
+        return 1;
+
+    /* If doing signal return, restore the previous little-endian mode.  */
+    if (sig)
+        env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
+
+    /* Restore Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+            if (__get_user(avr->u64[0], &vreg->u64[0]) ||
+                __get_user(avr->u64[1], &vreg->u64[1])) {
+                return 1;
+            }
+        }
+        /* Set MSR_VEC in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        if (__get_user(env->spr[SPR_VRSAVE],
+                       (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
+            return 1;
+    }
+
+    /* Restore floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        uint64_t fpscr;
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
+                return 1;
+            }
+        }
+        if (__get_user(fpscr, &frame->mc_fregs[32]))
+            return 1;
+        env->fpscr = (uint32_t) fpscr;
+    }
+
+    /* Save SPE registers.  The kernel only saves the high half.  */
+    if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+        for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+            uint32_t hi;
+
+            if (__get_user(hi, &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+            env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#endif
+        if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+            return 1;
+    }
+
+    return 0;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+                        target_sigset_t *set, CPUState *env)
+{
+    struct target_sigframe *frame;
+    struct target_sigcontext *sc;
+    target_ulong frame_addr, newsp;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+        goto sigsegv;
+    sc = &frame->sctx;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= __put_user(h2g(ka->_sa_handler), &sc->handler);
+    err |= __put_user(set->sig[0], &sc->oldmask);
+#if defined(TARGET_PPC64)
+    err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
+#else
+    err |= __put_user(set->sig[1], &sc->_unused[3]);
+#endif
+    err |= __put_user(h2g(&frame->mctx), &sc->regs);
+    err |= __put_user(sig, &sc->signal);
+
+    /* Save user regs.  */
+    err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
+
+    /* The kernel checks for the presence of a VDSO here.  We don't
+       emulate a vdso, so use a sigreturn system call.  */
+    env->lr = (target_ulong) h2g(frame->mctx.tramp);
+
+    /* Turn off all fp exceptions.  */
+    env->fpscr = 0;
+
+    /* Create a stack frame for the caller of the handler.  */
+    newsp = frame_addr - SIGNAL_FRAMESIZE;
+    err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = signal;
+    env->gpr[4] = (target_ulong) h2g(sc);
+    env->nip = (target_ulong) ka->_sa_handler;
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~MSR_LE;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from setup_frame\n");
+    force_sig(TARGET_SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+                           target_sigset_t *set, CPUState *env)
+{
+    struct target_rt_sigframe *rt_sf;
+    struct target_mcontext *frame;
+    target_ulong rt_sf_addr, newsp = 0;
+    int i, err = 0;
+    int signal;
+
+    rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
+    if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
+        goto sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= copy_siginfo_to_user(&rt_sf->info, info);
+
+    err |= __put_user(0, &rt_sf->uc.tuc_flags);
+    err |= __put_user(0, &rt_sf->uc.tuc_link);
+    err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
+                      &rt_sf->uc.tuc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(env->gpr[1]),
+                      &rt_sf->uc.tuc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+                      &rt_sf->uc.tuc_stack.ss_size);
+    err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
+                      &rt_sf->uc.tuc_regs);
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
+    }
+
+    frame = &rt_sf->uc.tuc_mcontext;
+    err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
+
+    /* The kernel checks for the presence of a VDSO here.  We don't
+       emulate a vdso, so use a sigreturn system call.  */
+    env->lr = (target_ulong) h2g(frame->tramp);
+
+    /* Turn off all fp exceptions.  */
+    env->fpscr = 0;
+
+    /* Create a stack frame for the caller of the handler.  */
+    newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+    err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = (target_ulong) signal;
+    env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
+    env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
+    env->gpr[6] = (target_ulong) h2g(rt_sf);
+    env->nip = (target_ulong) ka->_sa_handler;
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~MSR_LE;
+
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from setup_rt_frame\n");
+    force_sig(TARGET_SIGSEGV);
+
+}
+
+long do_sigreturn(CPUState *env)
+{
+    struct target_sigcontext *sc = NULL;
+    struct target_mcontext *sr = NULL;
+    target_ulong sr_addr, sc_addr;
+    sigset_t blocked;
+    target_sigset_t set;
+
+    sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
+    if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
+        goto sigsegv;
+
+#if defined(TARGET_PPC64)
+    set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
+#else
+    if(__get_user(set.sig[0], &sc->oldmask) ||
+       __get_user(set.sig[1], &sc->_unused[3]))
+       goto sigsegv;
+#endif
+    target_to_host_sigset_internal(&blocked, &set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (__get_user(sr_addr, &sc->regs))
+        goto sigsegv;
+    if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
+        goto sigsegv;
+    if (restore_user_regs(env, sr, 1))
+        goto sigsegv;
+
+    unlock_user_struct(sr, sr_addr, 1);
+    unlock_user_struct(sc, sc_addr, 1);
+    return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+    unlock_user_struct(sr, sr_addr, 1);
+    unlock_user_struct(sc, sc_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from do_sigreturn\n");
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+static int do_setcontext(struct target_ucontext *ucp, CPUState *env, int sig)
+{
+    struct target_mcontext *mcp;
+    target_ulong mcp_addr;
+    sigset_t blocked;
+    target_sigset_t set;
+
+    if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
+                       sizeof (set)))
+        return 1;
+
+#if defined(TARGET_PPC64)
+    fprintf (stderr, "do_setcontext: not implemented\n");
+    return 0;
+#else
+    if (__get_user(mcp_addr, &ucp->tuc_regs))
+        return 1;
+
+    if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
+        return 1;
+
+    target_to_host_sigset_internal(&blocked, &set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+    if (restore_user_regs(env, mcp, sig))
+        goto sigsegv;
+
+    unlock_user_struct(mcp, mcp_addr, 1);
+    return 0;
+
+sigsegv:
+    unlock_user_struct(mcp, mcp_addr, 1);
+    return 1;
+#endif
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    struct target_rt_sigframe *rt_sf = NULL;
+    target_ulong rt_sf_addr;
+
+    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+    if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
+        goto sigsegv;
+
+    if (do_setcontext(&rt_sf->uc, env, 1))
+        goto sigsegv;
+
+    do_sigaltstack(rt_sf_addr
+                   + offsetof(struct target_rt_sigframe, uc.tuc_stack),
+                   0, env->gpr[1]);
+
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from do_rt_sigreturn\n");
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+#elif defined(TARGET_M68K)
+
+struct target_sigcontext {
+    abi_ulong  sc_mask;
+    abi_ulong  sc_usp;
+    abi_ulong  sc_d0;
+    abi_ulong  sc_d1;
+    abi_ulong  sc_a0;
+    abi_ulong  sc_a1;
+    unsigned short sc_sr;
+    abi_ulong  sc_pc;
+};
+
+struct target_sigframe
+{
+    abi_ulong pretcode;
+    int sig;
+    int code;
+    abi_ulong psc;
+    char retcode[8];
+    abi_ulong extramask[TARGET_NSIG_WORDS-1];
+    struct target_sigcontext sc;
+};
+ 
+typedef int target_greg_t;
+#define TARGET_NGREG 18
+typedef target_greg_t target_gregset_t[TARGET_NGREG];
+
+typedef struct target_fpregset {
+    int f_fpcntl[3];
+    int f_fpregs[8*3];
+} target_fpregset_t;
+
+struct target_mcontext {
+    int version;
+    target_gregset_t gregs;
+    target_fpregset_t fpregs;
+};
+
+#define TARGET_MCONTEXT_VERSION 2
+
+struct target_ucontext {
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    target_stack_t tuc_stack;
+    struct target_mcontext tuc_mcontext;
+    abi_long tuc_filler[80];
+    target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe
+{
+    abi_ulong pretcode;
+    int sig;
+    abi_ulong pinfo;
+    abi_ulong puc;
+    char retcode[8];
+    struct target_siginfo info;
+    struct target_ucontext uc;
+};
+
+static int
+setup_sigcontext(struct target_sigcontext *sc, CPUState *env, abi_ulong mask)
+{
+    int err = 0;
+
+    err |= __put_user(mask, &sc->sc_mask);
+    err |= __put_user(env->aregs[7], &sc->sc_usp);
+    err |= __put_user(env->dregs[0], &sc->sc_d0);
+    err |= __put_user(env->dregs[1], &sc->sc_d1);
+    err |= __put_user(env->aregs[0], &sc->sc_a0);
+    err |= __put_user(env->aregs[1], &sc->sc_a1);
+    err |= __put_user(env->sr, &sc->sc_sr);
+    err |= __put_user(env->pc, &sc->sc_pc);
+
+    return err;
+}
+
+static int
+restore_sigcontext(CPUState *env, struct target_sigcontext *sc, int *pd0)
+{
+    int err = 0;
+    int temp;
+
+    err |= __get_user(env->aregs[7], &sc->sc_usp);
+    err |= __get_user(env->dregs[1], &sc->sc_d1);
+    err |= __get_user(env->aregs[0], &sc->sc_a0);
+    err |= __get_user(env->aregs[1], &sc->sc_a1);
+    err |= __get_user(env->pc, &sc->sc_pc);
+    err |= __get_user(temp, &sc->sc_sr);
+    env->sr = (env->sr & 0xff00) | (temp & 0xff);
+
+    *pd0 = tswapl(sc->sc_d0);
+
+    return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
+{
+    unsigned long sp;
+
+    sp = regs->aregs[7];
+
+    /* This is the X/Open sanctioned signal stack switching.  */
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+
+    return ((sp - frame_size) & -8UL);
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    abi_ulong retcode_addr;
+    abi_ulong sc_addr;
+    int err = 0;
+    int i;
+
+    frame_addr = get_sigframe(ka, env, sizeof *frame);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    err |= __put_user(sig, &frame->sig);
+
+    sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
+    err |= __put_user(sc_addr, &frame->psc);
+
+    err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
+    if (err)
+	goto give_sigsegv;
+
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->sig[i], &frame->extramask[i - 1]))
+            goto give_sigsegv;
+    }
+
+    /* Set up to return from userspace.  */
+
+    retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
+    err |= __put_user(retcode_addr, &frame->pretcode);
+
+    /* moveq #,d0; trap #0 */
+
+    err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
+                      (long *)(frame->retcode));
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up to return from userspace */
+
+    env->aregs[7] = frame_addr;
+    env->pc = ka->_sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
+                                           CPUState *env)
+{
+    target_greg_t *gregs = uc->tuc_mcontext.gregs;
+    int err;
+
+    err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
+    err |= __put_user(env->dregs[0], &gregs[0]);
+    err |= __put_user(env->dregs[1], &gregs[1]);
+    err |= __put_user(env->dregs[2], &gregs[2]);
+    err |= __put_user(env->dregs[3], &gregs[3]);
+    err |= __put_user(env->dregs[4], &gregs[4]);
+    err |= __put_user(env->dregs[5], &gregs[5]);
+    err |= __put_user(env->dregs[6], &gregs[6]);
+    err |= __put_user(env->dregs[7], &gregs[7]);
+    err |= __put_user(env->aregs[0], &gregs[8]);
+    err |= __put_user(env->aregs[1], &gregs[9]);
+    err |= __put_user(env->aregs[2], &gregs[10]);
+    err |= __put_user(env->aregs[3], &gregs[11]);
+    err |= __put_user(env->aregs[4], &gregs[12]);
+    err |= __put_user(env->aregs[5], &gregs[13]);
+    err |= __put_user(env->aregs[6], &gregs[14]);
+    err |= __put_user(env->aregs[7], &gregs[15]);
+    err |= __put_user(env->pc, &gregs[16]);
+    err |= __put_user(env->sr, &gregs[17]);
+
+    return err;
+}
+ 
+static inline int target_rt_restore_ucontext(CPUState *env,
+                                             struct target_ucontext *uc,
+                                             int *pd0)
+{
+    int temp;
+    int err;
+    target_greg_t *gregs = uc->tuc_mcontext.gregs;
+    
+    err = __get_user(temp, &uc->tuc_mcontext.version);
+    if (temp != TARGET_MCONTEXT_VERSION)
+        goto badframe;
+
+    /* restore passed registers */
+    err |= __get_user(env->dregs[0], &gregs[0]);
+    err |= __get_user(env->dregs[1], &gregs[1]);
+    err |= __get_user(env->dregs[2], &gregs[2]);
+    err |= __get_user(env->dregs[3], &gregs[3]);
+    err |= __get_user(env->dregs[4], &gregs[4]);
+    err |= __get_user(env->dregs[5], &gregs[5]);
+    err |= __get_user(env->dregs[6], &gregs[6]);
+    err |= __get_user(env->dregs[7], &gregs[7]);
+    err |= __get_user(env->aregs[0], &gregs[8]);
+    err |= __get_user(env->aregs[1], &gregs[9]);
+    err |= __get_user(env->aregs[2], &gregs[10]);
+    err |= __get_user(env->aregs[3], &gregs[11]);
+    err |= __get_user(env->aregs[4], &gregs[12]);
+    err |= __get_user(env->aregs[5], &gregs[13]);
+    err |= __get_user(env->aregs[6], &gregs[14]);
+    err |= __get_user(env->aregs[7], &gregs[15]);
+    err |= __get_user(env->pc, &gregs[16]);
+    err |= __get_user(temp, &gregs[17]);
+    env->sr = (env->sr & 0xff00) | (temp & 0xff);
+
+    *pd0 = env->dregs[0];
+    return err;
+
+badframe:
+    return 1;
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    abi_ulong retcode_addr;
+    abi_ulong info_addr;
+    abi_ulong uc_addr;
+    int err = 0;
+    int i;
+
+    frame_addr = get_sigframe(ka, env, sizeof *frame);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    err |= __put_user(sig, &frame->sig);
+
+    info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
+    err |= __put_user(info_addr, &frame->pinfo);
+
+    uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
+    err |= __put_user(uc_addr, &frame->puc);
+
+    err |= copy_siginfo_to_user(&frame->info, info);
+
+    /* Create the ucontext */
+
+    err |= __put_user(0, &frame->uc.tuc_flags);
+    err |= __put_user(0, &frame->uc.tuc_link);
+    err |= __put_user(target_sigaltstack_used.ss_sp,
+                      &frame->uc.tuc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(env->aregs[7]),
+                      &frame->uc.tuc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+                      &frame->uc.tuc_stack.ss_size);
+    err |= target_rt_setup_ucontext(&frame->uc, env);
+
+    if (err)
+            goto give_sigsegv;
+
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
+            goto give_sigsegv;
+    }
+
+    /* Set up to return from userspace.  */
+
+    retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
+    err |= __put_user(retcode_addr, &frame->pretcode);
+
+    /* moveq #,d0; notb d0; trap #0 */
+
+    err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
+                      (long *)(frame->retcode + 0));
+    err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up to return from userspace */
+
+    env->aregs[7] = frame_addr;
+    env->pc = ka->_sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+long do_sigreturn(CPUState *env)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr = env->aregs[7] - 4;
+    target_sigset_t target_set;
+    sigset_t set;
+    int d0, i;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+        goto badframe;
+
+    /* set blocked signals */
+
+    if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
+        goto badframe;
+
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
+            goto badframe;
+    }
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    /* restore registers */
+
+    if (restore_sigcontext(env, &frame->sc, &d0))
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return d0;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr = env->aregs[7] - 4;
+    target_sigset_t target_set;
+    sigset_t set;
+    int d0;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+        goto badframe;
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    /* restore registers */
+
+    if (target_rt_restore_ucontext(env, &frame->uc, &d0))
+        goto badframe;
+
+    if (do_sigaltstack(frame_addr +
+                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
+                       0, get_sp_from_cpustate(env)) == -EFAULT)
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return d0;
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+#elif defined(TARGET_ALPHA)
+
+struct target_sigcontext {
+    abi_long sc_onstack;
+    abi_long sc_mask;
+    abi_long sc_pc;
+    abi_long sc_ps;
+    abi_long sc_regs[32];
+    abi_long sc_ownedfp;
+    abi_long sc_fpregs[32];
+    abi_ulong sc_fpcr;
+    abi_ulong sc_fp_control;
+    abi_ulong sc_reserved1;
+    abi_ulong sc_reserved2;
+    abi_ulong sc_ssize;
+    abi_ulong sc_sbase;
+    abi_ulong sc_traparg_a0;
+    abi_ulong sc_traparg_a1;
+    abi_ulong sc_traparg_a2;
+    abi_ulong sc_fp_trap_pc;
+    abi_ulong sc_fp_trigger_sum;
+    abi_ulong sc_fp_trigger_inst;
+};
+
+struct target_ucontext {
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    abi_ulong tuc_osf_sigmask;
+    target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t tuc_sigmask;
+};
+
+struct target_sigframe {
+    struct target_sigcontext sc;
+    unsigned int retcode[3];
+};
+
+struct target_rt_sigframe {
+    target_siginfo_t info;
+    struct target_ucontext uc;
+    unsigned int retcode[3];
+};
+
+#define INSN_MOV_R30_R16        0x47fe0410
+#define INSN_LDI_R0             0x201f0000
+#define INSN_CALLSYS            0x00000083
+
+static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env,
+                            abi_ulong frame_addr, target_sigset_t *set)
+{
+    int i, err = 0;
+
+    err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
+    err |= __put_user(set->sig[0], &sc->sc_mask);
+    err |= __put_user(env->pc, &sc->sc_pc);
+    err |= __put_user(8, &sc->sc_ps);
+
+    for (i = 0; i < 31; ++i) {
+        err |= __put_user(env->ir[i], &sc->sc_regs[i]);
+    }
+    err |= __put_user(0, &sc->sc_regs[31]);
+
+    for (i = 0; i < 31; ++i) {
+        err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
+    }
+    err |= __put_user(0, &sc->sc_fpregs[31]);
+    err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
+
+    err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
+    err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
+    err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
+
+    return err;
+}
+
+static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
+{
+    uint64_t fpcr;
+    int i, err = 0;
+
+    err |= __get_user(env->pc, &sc->sc_pc);
+
+    for (i = 0; i < 31; ++i) {
+        err |= __get_user(env->ir[i], &sc->sc_regs[i]);
+    }
+    for (i = 0; i < 31; ++i) {
+        err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
+    }
+
+    err |= __get_user(fpcr, &sc->sc_fpcr);
+    cpu_alpha_store_fpcr(env, fpcr);
+
+    return err;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *sa,
+                                     CPUState *env, unsigned long framesize)
+{
+    abi_ulong sp = env->ir[IR_SP];
+
+    /* This is the X/Open sanctioned signal stack switching.  */
+    if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+    return (sp - framesize) & -32;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+                        target_sigset_t *set, CPUState *env)
+{
+    abi_ulong frame_addr, r26;
+    struct target_sigframe *frame;
+    int err = 0;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
+
+    if (ka->sa_restorer) {
+        r26 = ka->sa_restorer;
+    } else {
+        err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
+        err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
+                          &frame->retcode[1]);
+        err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
+        /* imb() */
+        r26 = frame_addr;
+    }
+
+    unlock_user_struct(frame, frame_addr, 1);
+
+    if (err) {
+    give_sigsegv:
+        if (sig == TARGET_SIGSEGV) {
+            ka->_sa_handler = TARGET_SIG_DFL;
+        }
+        force_sig(TARGET_SIGSEGV);
+    }
+
+    env->ir[IR_RA] = r26;
+    env->ir[IR_PV] = env->pc = ka->_sa_handler;
+    env->ir[IR_A0] = sig;
+    env->ir[IR_A1] = 0;
+    env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
+    env->ir[IR_SP] = frame_addr;
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    abi_ulong frame_addr, r26;
+    struct target_rt_sigframe *frame;
+    int i, err = 0;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    err |= copy_siginfo_to_user(&frame->info, info);
+
+    err |= __put_user(0, &frame->uc.tuc_flags);
+    err |= __put_user(0, &frame->uc.tuc_link);
+    err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
+    err |= __put_user(target_sigaltstack_used.ss_sp,
+                      &frame->uc.tuc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
+                      &frame->uc.tuc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+                      &frame->uc.tuc_stack.ss_size);
+    err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
+    for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
+        err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+    }
+
+    if (ka->sa_restorer) {
+        r26 = ka->sa_restorer;
+    } else {
+        err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
+        err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
+                          &frame->retcode[1]);
+        err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
+        /* imb(); */
+        r26 = frame_addr;
+    }
+
+    if (err) {
+    give_sigsegv:
+       if (sig == TARGET_SIGSEGV) {
+            ka->_sa_handler = TARGET_SIG_DFL;
+        }
+        force_sig(TARGET_SIGSEGV);
+    }
+
+    env->ir[IR_RA] = r26;
+    env->ir[IR_PV] = env->pc = ka->_sa_handler;
+    env->ir[IR_A0] = sig;
+    env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
+    env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+    env->ir[IR_SP] = frame_addr;
+}
+
+long do_sigreturn(CPUState *env)
+{
+    struct target_sigcontext *sc;
+    abi_ulong sc_addr = env->ir[IR_A0];
+    target_sigset_t target_set;
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
+        goto badframe;
+    }
+
+    target_sigemptyset(&target_set);
+    if (__get_user(target_set.sig[0], &sc->sc_mask)) {
+        goto badframe;
+    }
+
+    target_to_host_sigset_internal(&set, &target_set);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    if (restore_sigcontext(env, sc)) {
+        goto badframe;
+    }
+    unlock_user_struct(sc, sc_addr, 0);
+    return env->ir[IR_V0];
+
+ badframe:
+    unlock_user_struct(sc, sc_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    abi_ulong frame_addr = env->ir[IR_A0];
+    struct target_rt_sigframe *frame;
+    sigset_t set;
+
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+    sigprocmask(SIG_SETMASK, &set, NULL);
+
+    if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
+        goto badframe;
+    }
+    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+                                             uc.tuc_stack),
+                       0, env->ir[IR_SP]) == -EFAULT) {
+        goto badframe;
+    }
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return env->ir[IR_V0];
+
+
+ badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+}
+
+#else
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif
+
+void process_pending_signals(CPUState *cpu_env)
+{
+    int sig;
+    abi_ulong handler;
+    sigset_t set, old_set;
+    target_sigset_t target_old_set;
+    struct emulated_sigtable *k;
+    struct target_sigaction *sa;
+    struct sigqueue *q;
+    TaskState *ts = cpu_env->opaque;
+
+    if (!ts->signal_pending)
+        return;
+
+    /* FIXME: This is not threadsafe.  */
+    k = ts->sigtab;
+    for(sig = 1; sig <= TARGET_NSIG; sig++) {
+        if (k->pending)
+            goto handle_signal;
+        k++;
+    }
+    /* if no signal is pending, just return */
+    ts->signal_pending = 0;
+    return;
+
+ handle_signal:
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+    /* dequeue signal */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first)
+        k->pending = 0;
+
+    sig = gdb_handlesig (cpu_env, sig);
+    if (!sig) {
+        sa = NULL;
+        handler = TARGET_SIG_IGN;
+    } else {
+        sa = &sigact_table[sig - 1];
+        handler = sa->_sa_handler;
+    }
+
+    if (handler == TARGET_SIG_DFL) {
+        /* default handler : ignore some signal. The other are job control or fatal */
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
+            kill(getpid(),SIGSTOP);
+        } else if (sig != TARGET_SIGCHLD &&
+                   sig != TARGET_SIGURG &&
+                   sig != TARGET_SIGWINCH &&
+                   sig != TARGET_SIGCONT) {
+            force_sig(sig);
+        }
+    } else if (handler == TARGET_SIG_IGN) {
+        /* ignore sig */
+    } else if (handler == TARGET_SIG_ERR) {
+        force_sig(sig);
+    } else {
+        /* compute the blocked signals during the handler execution */
+        target_to_host_sigset(&set, &sa->sa_mask);
+        /* SA_NODEFER indicates that the current signal should not be
+           blocked during the handler */
+        if (!(sa->sa_flags & TARGET_SA_NODEFER))
+            sigaddset(&set, target_to_host_signal(sig));
+
+        /* block signals in the handler using Linux */
+        sigprocmask(SIG_BLOCK, &set, &old_set);
+        /* save the previous blocked signal state to restore it at the
+           end of the signal execution (see do_sigreturn) */
+        host_to_target_sigset_internal(&target_old_set, &old_set);
+
+        /* if the CPU is in VM86 mode, we restore the 32 bit values */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+        {
+            CPUX86State *env = cpu_env;
+            if (env->eflags & VM_MASK)
+                save_v86_state(env);
+        }
+#endif
+        /* prepare the stack frame of the virtual CPU */
+        if (sa->sa_flags & TARGET_SA_SIGINFO)
+            setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
+        else
+            setup_frame(sig, sa, &target_old_set, cpu_env);
+	if (sa->sa_flags & TARGET_SA_RESETHAND)
+            sa->_sa_handler = TARGET_SIG_DFL;
+    }
+    if (q != &k->info)
+        free_sigqueue(cpu_env, q);
+}
diff --git a/qemu-0.15.x/linux-user/socket.h b/qemu-0.15.x/linux-user/socket.h
new file mode 100644
index 0000000..93d4782
--- /dev/null
+++ b/qemu-0.15.x/linux-user/socket.h
@@ -0,0 +1,147 @@
+
+#if defined(TARGET_MIPS)
+	// MIPS special values for constants
+
+	/*
+	 * For setsockopt(2)
+	 *
+	 * This defines are ABI conformant as far as Linux supports these ...
+	 */
+	#define TARGET_SOL_SOCKET      0xffff
+
+	#define TARGET_SO_DEBUG        0x0001  /* Record debugging information.  */
+	#define TARGET_SO_REUSEADDR    0x0004  /* Allow reuse of local addresses.  */
+	#define TARGET_SO_KEEPALIVE    0x0008  /* Keep connections alive and send
+					  SIGPIPE when they die.  */
+	#define TARGET_SO_DONTROUTE    0x0010  /* Don't do local routing.  */
+	#define TARGET_SO_BROADCAST    0x0020  /* Allow transmission of
+					  broadcast messages.  */
+	#define TARGET_SO_LINGER       0x0080  /* Block on close of a reliable
+					  socket to transmit pending data.  */
+	#define TARGET_SO_OOBINLINE 0x0100     /* Receive out-of-band data in-band.  */
+	#if 0
+	To add: #define TARGET_SO_REUSEPORT 0x0200     /* Allow local address and port reuse.  */
+	#endif
+
+	#define TARGET_SO_TYPE         0x1008  /* Compatible name for SO_STYLE.  */
+	#define TARGET_SO_STYLE        SO_TYPE /* Synonym */
+	#define TARGET_SO_ERROR        0x1007  /* get error status and clear */
+	#define TARGET_SO_SNDBUF       0x1001  /* Send buffer size. */
+	#define TARGET_SO_RCVBUF       0x1002  /* Receive buffer. */
+	#define TARGET_SO_SNDLOWAT     0x1003  /* send low-water mark */
+	#define TARGET_SO_RCVLOWAT     0x1004  /* receive low-water mark */
+	#define TARGET_SO_SNDTIMEO     0x1005  /* send timeout */
+	#define TARGET_SO_RCVTIMEO     0x1006  /* receive timeout */
+	#define TARGET_SO_ACCEPTCONN   0x1009
+
+	/* linux-specific, might as well be the same as on i386 */
+	#define TARGET_SO_NO_CHECK     11
+	#define TARGET_SO_PRIORITY     12
+	#define TARGET_SO_BSDCOMPAT    14
+
+	#define TARGET_SO_PASSCRED     17
+	#define TARGET_SO_PEERCRED     18
+
+	/* Security levels - as per NRL IPv6 - don't actually do anything */
+	#define TARGET_SO_SECURITY_AUTHENTICATION              22
+	#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT        23
+	#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK          24
+
+	#define TARGET_SO_BINDTODEVICE         25
+
+	/* Socket filtering */
+	#define TARGET_SO_ATTACH_FILTER        26
+	#define TARGET_SO_DETACH_FILTER        27
+
+	#define TARGET_SO_PEERNAME             28
+	#define TARGET_SO_TIMESTAMP            29
+	#define SCM_TIMESTAMP          SO_TIMESTAMP
+
+	#define TARGET_SO_PEERSEC              30
+	#define TARGET_SO_SNDBUFFORCE          31
+	#define TARGET_SO_RCVBUFFORCE          33
+
+	/** sock_type - Socket types
+	 *
+	 * Please notice that for binary compat reasons MIPS has to
+	 * override the enum sock_type in include/linux/net.h, so
+	 * we define ARCH_HAS_SOCKET_TYPES here.
+	 *
+	 * @SOCK_DGRAM - datagram (conn.less) socket
+	 * @SOCK_STREAM - stream (connection) socket
+	 * @SOCK_RAW - raw socket
+	 * @SOCK_RDM - reliably-delivered message
+	 * @SOCK_SEQPACKET - sequential packet socket
+	 * @SOCK_PACKET - linux specific way of getting packets at the dev level.
+	 *               For writing rarp and other similar things on the user level.
+	 */
+	enum sock_type {
+	       TARGET_SOCK_DGRAM       = 1,
+	       TARGET_SOCK_STREAM      = 2,
+	       TARGET_SOCK_RAW = 3,
+	       TARGET_SOCK_RDM = 4,
+	       TARGET_SOCK_SEQPACKET   = 5,
+	       TARGET_SOCK_DCCP        = 6,
+	       TARGET_SOCK_PACKET      = 10,
+	};
+
+	#define TARGET_SOCK_MAX (SOCK_PACKET + 1)
+
+#else
+
+	/* For setsockopt(2) */
+	#define TARGET_SOL_SOCKET      1
+
+	#define TARGET_SO_DEBUG        1
+	#define TARGET_SO_REUSEADDR    2
+	#define TARGET_SO_TYPE         3
+	#define TARGET_SO_ERROR        4
+	#define TARGET_SO_DONTROUTE    5
+	#define TARGET_SO_BROADCAST    6
+	#define TARGET_SO_SNDBUF       7
+	#define TARGET_SO_RCVBUF       8
+	#define TARGET_SO_SNDBUFFORCE  32
+	#define TARGET_SO_RCVBUFFORCE  33
+	#define TARGET_SO_KEEPALIVE    9
+	#define TARGET_SO_OOBINLINE    10
+	#define TARGET_SO_NO_CHECK     11
+	#define TARGET_SO_PRIORITY     12
+	#define TARGET_SO_LINGER       13
+	#define TARGET_SO_BSDCOMPAT    14
+	/* To add :#define TARGET_SO_REUSEPORT 15 */
+#if defined(TARGET_PPC)
+	#define TARGET_SO_RCVLOWAT     16
+	#define TARGET_SO_SNDLOWAT     17
+	#define TARGET_SO_RCVTIMEO     18
+	#define TARGET_SO_SNDTIMEO     19
+	#define TARGET_SO_PASSCRED     20
+	#define TARGET_SO_PEERCRED     21
+#else
+	#define TARGET_SO_PASSCRED     16
+	#define TARGET_SO_PEERCRED     17
+	#define TARGET_SO_RCVLOWAT     18
+	#define TARGET_SO_SNDLOWAT     19
+	#define TARGET_SO_RCVTIMEO     20
+	#define TARGET_SO_SNDTIMEO     21
+#endif
+
+	/* Security levels - as per NRL IPv6 - don't actually do anything */
+	#define TARGET_SO_SECURITY_AUTHENTICATION              22
+	#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT        23
+	#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK          24
+
+	#define TARGET_SO_BINDTODEVICE 25
+
+	/* Socket filtering */
+	#define TARGET_SO_ATTACH_FILTER        26
+	#define TARGET_SO_DETACH_FILTER        27
+
+	#define TARGET_SO_PEERNAME             28
+	#define TARGET_SO_TIMESTAMP            29
+	#define TARGET_SCM_TIMESTAMP           TARGET_SO_TIMESTAMP
+
+	#define TARGET_SO_ACCEPTCONN           30
+
+	#define TARGET_SO_PEERSEC              31
+
+#endif
diff --git a/qemu-0.15.x/linux-user/sparc/syscall.h b/qemu-0.15.x/linux-user/sparc/syscall.h
new file mode 100644
index 0000000..5a9bb7e
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc/syscall.h
@@ -0,0 +1,9 @@
+struct target_pt_regs {
+	abi_ulong psr;
+	abi_ulong pc;
+	abi_ulong npc;
+	abi_ulong y;
+	abi_ulong u_regs[16];
+};
+
+#define UNAME_MACHINE "sun4"
diff --git a/qemu-0.15.x/linux-user/sparc/syscall_nr.h b/qemu-0.15.x/linux-user/sparc/syscall_nr.h
new file mode 100644
index 0000000..be503f2
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc/syscall_nr.h
@@ -0,0 +1,299 @@
+#define TARGET_NR_exit                 1 /* Common                                      */
+#define TARGET_NR_fork                 2 /* Common                                      */
+#define TARGET_NR_read                 3 /* Common                                      */
+#define TARGET_NR_write                4 /* Common                                      */
+#define TARGET_NR_open                 5 /* Common                                      */
+#define TARGET_NR_close                6 /* Common                                      */
+#define TARGET_NR_wait4                7 /* Common                                      */
+#define TARGET_NR_creat                8 /* Common                                      */
+#define TARGET_NR_link                 9 /* Common                                      */
+#define TARGET_NR_unlink              10 /* Common                                      */
+#define TARGET_NR_execv               11 /* SunOS Specific                              */
+#define TARGET_NR_chdir               12 /* Common                                      */
+#define TARGET_NR_chown		 13 /* Common					   */
+#define TARGET_NR_mknod               14 /* Common                                      */
+#define TARGET_NR_chmod               15 /* Common                                      */
+#define TARGET_NR_lchown              16 /* Common                                      */
+#define TARGET_NR_brk                 17 /* Common                                      */
+#define TARGET_NR_perfctr             18 /* Performance counter operations              */
+#define TARGET_NR_lseek               19 /* Common                                      */
+#define TARGET_NR_getpid              20 /* Common                                      */
+#define TARGET_NR_capget		 21 /* Linux Specific				   */
+#define TARGET_NR_capset		 22 /* Linux Specific				   */
+#define TARGET_NR_setuid              23 /* Implemented via setreuid in SunOS           */
+#define TARGET_NR_getuid              24 /* Common                                      */
+#define TARGET_NR_ptrace              26 /* Common                                      */
+#define TARGET_NR_alarm               27 /* Implemented via setitimer in SunOS          */
+#define TARGET_NR_sigaltstack	 28 /* Common					   */
+#define TARGET_NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
+#define TARGET_NR_utime               30 /* Implemented via utimes() under SunOS        */
+#define TARGET_NR_lchown32            31 /* Linux sparc32 specific                      */
+#define TARGET_NR_fchown32            32 /* Linux sparc32 specific                      */
+#define TARGET_NR_access              33 /* Common                                      */
+#define TARGET_NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
+#define TARGET_NR_chown32             35 /* Linux sparc32 specific                      */
+#define TARGET_NR_sync                36 /* Common                                      */
+#define TARGET_NR_kill                37 /* Common                                      */
+#define TARGET_NR_stat                38 /* Common                                      */
+#define TARGET_NR_sendfile		 39 /* Linux Specific				   */
+#define TARGET_NR_lstat               40 /* Common                                      */
+#define TARGET_NR_dup                 41 /* Common                                      */
+#define TARGET_NR_pipe                42 /* Common                                      */
+#define TARGET_NR_times               43 /* Implemented via getrusage() in SunOS        */
+#define TARGET_NR_getuid32            44 /* Linux sparc32 specific                      */
+#define TARGET_NR_umount2             45 /* Linux Specific                              */
+#define TARGET_NR_setgid              46 /* Implemented via setregid() in SunOS         */
+#define TARGET_NR_getgid              47 /* Common                                      */
+#define TARGET_NR_signal              48 /* Implemented via sigvec() in SunOS           */
+#define TARGET_NR_geteuid             49 /* SunOS calls getuid()                        */
+#define TARGET_NR_getegid             50 /* SunOS calls getgid()                        */
+#define TARGET_NR_acct                51 /* Common                                      */
+#define TARGET_NR_getgid32            53 /* Linux sparc32 specific                      */
+#define TARGET_NR_ioctl               54 /* Common                                      */
+#define TARGET_NR_reboot              55 /* Common                                      */
+#define TARGET_NR_mmap2		 56 /* Linux sparc32 Specific			   */
+#define TARGET_NR_symlink             57 /* Common                                      */
+#define TARGET_NR_readlink            58 /* Common                                      */
+#define TARGET_NR_execve              59 /* Common                                      */
+#define TARGET_NR_umask               60 /* Common                                      */
+#define TARGET_NR_chroot              61 /* Common                                      */
+#define TARGET_NR_fstat               62 /* Common                                      */
+#define TARGET_NR_fstat64		 63 /* Linux sparc32 Specific			   */
+#define TARGET_NR_getpagesize         64 /* Common                                      */
+#define TARGET_NR_msync               65 /* Common in newer 1.3.x revs...               */
+#define TARGET_NR_vfork               66 /* Common                                      */
+#define TARGET_NR_pread               67 /* Linux Specific                              */
+#define TARGET_NR_pwrite              68 /* Linux Specific                              */
+#define TARGET_NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
+#define TARGET_NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
+#define TARGET_NR_mmap                71 /* Common                                      */
+#define TARGET_NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
+#define TARGET_NR_munmap              73 /* Common                                      */
+#define TARGET_NR_mprotect            74 /* Common                                      */
+#define TARGET_NR_madvise             75 /* Common                                      */
+#define TARGET_NR_vhangup             76 /* Common                                      */
+#define TARGET_NR_truncate64		 77 /* Linux sparc32 Specific			   */
+#define TARGET_NR_mincore             78 /* Common                                      */
+#define TARGET_NR_getgroups           79 /* Common                                      */
+#define TARGET_NR_setgroups           80 /* Common                                      */
+#define TARGET_NR_getpgrp             81 /* Common                                      */
+#define TARGET_NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
+#define TARGET_NR_setitimer           83 /* Common                                      */
+#define TARGET_NR_ftruncate64	 84 /* Linux sparc32 Specific			   */
+#define TARGET_NR_swapon              85 /* Common                                      */
+#define TARGET_NR_getitimer           86 /* Common                                      */
+#define TARGET_NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
+#define TARGET_NR_sethostname         88 /* Common                                      */
+#define TARGET_NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
+#define TARGET_NR_dup2                90 /* Common                                      */
+#define TARGET_NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
+#define TARGET_NR_fcntl               92 /* Common                                      */
+#define TARGET_NR_select              93 /* Common                                      */
+#define TARGET_NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
+#define TARGET_NR_fsync               95 /* Common                                      */
+#define TARGET_NR_setpriority         96 /* Common                                      */
+#define TARGET_NR_socket              97 /* Common                                      */
+#define TARGET_NR_connect             98 /* Common                                      */
+#define TARGET_NR_accept              99 /* Common                                      */
+#define TARGET_NR_getpriority        100 /* Common                                      */
+#define TARGET_NR_rt_sigreturn       101 /* Linux Specific                              */
+#define TARGET_NR_rt_sigaction       102 /* Linux Specific                              */
+#define TARGET_NR_rt_sigprocmask     103 /* Linux Specific                              */
+#define TARGET_NR_rt_sigpending      104 /* Linux Specific                              */
+#define TARGET_NR_rt_sigtimedwait    105 /* Linux Specific                              */
+#define TARGET_NR_rt_sigqueueinfo    106 /* Linux Specific                              */
+#define TARGET_NR_rt_sigsuspend      107 /* Linux Specific                              */
+#define TARGET_NR_setresuid32        108 /* Linux Specific, sigvec under SunOS	   */
+#define TARGET_NR_getresuid32        109 /* Linux Specific, sigblock under SunOS	   */
+#define TARGET_NR_setresgid32        110 /* Linux Specific, sigsetmask under SunOS	   */
+#define TARGET_NR_getresgid32        111 /* Linux Specific, sigpause under SunOS	   */
+#define TARGET_NR_setregid32         112 /* Linux sparc32, sigstack under SunOS         */
+#define TARGET_NR_recvmsg            113 /* Common                                      */
+#define TARGET_NR_sendmsg            114 /* Common                                      */
+#define TARGET_NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
+#define TARGET_NR_gettimeofday       116 /* Common                                      */
+#define TARGET_NR_getrusage          117 /* Common                                      */
+#define TARGET_NR_getsockopt         118 /* Common                                      */
+#define TARGET_NR_getcwd		119 /* Linux Specific				   */
+#define TARGET_NR_readv              120 /* Common                                      */
+#define TARGET_NR_writev             121 /* Common                                      */
+#define TARGET_NR_settimeofday       122 /* Common                                      */
+#define TARGET_NR_fchown             123 /* Common                                      */
+#define TARGET_NR_fchmod             124 /* Common                                      */
+#define TARGET_NR_recvfrom           125 /* Common                                      */
+#define TARGET_NR_setreuid           126 /* Common                                      */
+#define TARGET_NR_setregid           127 /* Common                                      */
+#define TARGET_NR_rename             128 /* Common                                      */
+#define TARGET_NR_truncate           129 /* Common                                      */
+#define TARGET_NR_ftruncate          130 /* Common                                      */
+#define TARGET_NR_flock              131 /* Common                                      */
+#define TARGET_NR_lstat64		132 /* Linux sparc32 Specific			   */
+#define TARGET_NR_sendto             133 /* Common                                      */
+#define TARGET_NR_shutdown           134 /* Common                                      */
+#define TARGET_NR_socketpair         135 /* Common                                      */
+#define TARGET_NR_mkdir              136 /* Common                                      */
+#define TARGET_NR_rmdir              137 /* Common                                      */
+#define TARGET_NR_utimes             138 /* SunOS Specific                              */
+#define TARGET_NR_stat64		139 /* Linux sparc32 Specific			   */
+#define TARGET_NR_getpeername        141 /* Common                                      */
+#define TARGET_NR_gettid             143 /* ENOSYS under SunOS                          */
+#define TARGET_NR_getrlimit          144 /* Common                                      */
+#define TARGET_NR_setrlimit          145 /* Common                                      */
+#define TARGET_NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
+#define TARGET_NR_prctl		147 /* ENOSYS under SunOS                          */
+#define TARGET_NR_pciconfig_read	148 /* ENOSYS under SunOS                          */
+#define TARGET_NR_pciconfig_write	149 /* ENOSYS under SunOS                          */
+#define TARGET_NR_getsockname        150 /* Common                                      */
+#define TARGET_NR_poll               153 /* Common                                      */
+#define TARGET_NR_getdents64		154 /* Linux specific				   */
+#define TARGET_NR_fcntl64		155 /* Linux sparc32 Specific                      */
+#define TARGET_NR_statfs             157 /* Common                                      */
+#define TARGET_NR_fstatfs            158 /* Common                                      */
+#define TARGET_NR_umount             159 /* Common                                      */
+#define TARGET_NR_getdomainname      162 /* SunOS Specific                              */
+#define TARGET_NR_setdomainname      163 /* Common                                      */
+#define TARGET_NR_quotactl           165 /* Common                                      */
+#define TARGET_NR_mount              167 /* Common                                      */
+#define TARGET_NR_ustat              168 /* Common                                      */
+#define TARGET_NR_getdents           174 /* Common                                      */
+#define TARGET_NR_setsid             175 /* Common                                      */
+#define TARGET_NR_fchdir             176 /* Common                                      */
+#define TARGET_NR_sigpending         183 /* Common                                      */
+#define TARGET_NR_query_module	184 /* Linux Specific				   */
+#define TARGET_NR_setpgid            185 /* Common                                      */
+#define TARGET_NR_tkill              187 /* SunOS: fpathconf                            */
+#define TARGET_NR_exit_group	     188 /* Linux specific, sysconf undef SunOS         */
+#define TARGET_NR_uname              189 /* Linux Specific                              */
+#define TARGET_NR_init_module        190 /* Linux Specific                              */
+#define TARGET_NR_personality        191 /* Linux Specific                              */
+#define TARGET_NR_getppid            197 /* Linux Specific                              */
+#define TARGET_NR_sigaction          198 /* Linux Specific                              */
+#define TARGET_NR_sgetmask           199 /* Linux Specific                              */
+#define TARGET_NR_ssetmask           200 /* Linux Specific                              */
+#define TARGET_NR_sigsuspend         201 /* Linux Specific                              */
+#define TARGET_NR_oldlstat           202 /* Linux Specific                              */
+#define TARGET_NR_uselib             203 /* Linux Specific                              */
+#define TARGET_NR_readdir            204 /* Linux Specific                              */
+#define TARGET_NR_readahead          205 /* Linux Specific                              */
+#define TARGET_NR_socketcall         206 /* Linux Specific                              */
+#define TARGET_NR_syslog             207 /* Linux Specific                              */
+#define TARGET_NR_waitpid            212 /* Linux Specific                              */
+#define TARGET_NR_swapoff            213 /* Linux Specific                              */
+#define TARGET_NR_sysinfo            214 /* Linux Specific                              */
+#define TARGET_NR_ipc                215 /* Linux Specific                              */
+#define TARGET_NR_sigreturn          216 /* Linux Specific                              */
+#define TARGET_NR_clone              217 /* Linux Specific                              */
+#define TARGET_NR_adjtimex           219 /* Linux Specific                              */
+#define TARGET_NR_sigprocmask        220 /* Linux Specific                              */
+#define TARGET_NR_create_module      221 /* Linux Specific                              */
+#define TARGET_NR_delete_module      222 /* Linux Specific                              */
+#define TARGET_NR_get_kernel_syms    223 /* Linux Specific                              */
+#define TARGET_NR_getpgid            224 /* Linux Specific                              */
+#define TARGET_NR_bdflush            225 /* Linux Specific                              */
+#define TARGET_NR_sysfs              226 /* Linux Specific                              */
+#define TARGET_NR_afs_syscall        227 /* Linux Specific                              */
+#define TARGET_NR_setfsuid           228 /* Linux Specific                              */
+#define TARGET_NR_setfsgid           229 /* Linux Specific                              */
+#define TARGET_NR__newselect         230 /* Linux Specific                              */
+#define TARGET_NR_time               231 /* Linux Specific                              */
+#define TARGET_NR_stime              233 /* Linux Specific                              */
+#define TARGET_NR__llseek            236 /* Linux Specific                              */
+#define TARGET_NR_mlock              237
+#define TARGET_NR_munlock            238
+#define TARGET_NR_mlockall           239
+#define TARGET_NR_munlockall         240
+#define TARGET_NR_sched_setparam     241
+#define TARGET_NR_sched_getparam     242
+#define TARGET_NR_sched_setscheduler 243
+#define TARGET_NR_sched_getscheduler 244
+#define TARGET_NR_sched_yield        245
+#define TARGET_NR_sched_get_priority_max 246
+#define TARGET_NR_sched_get_priority_min 247
+#define TARGET_NR_sched_rr_get_interval  248
+#define TARGET_NR_nanosleep          249
+#define TARGET_NR_mremap             250
+#define TARGET_NR__sysctl            251
+#define TARGET_NR_getsid             252
+#define TARGET_NR_fdatasync          253
+#define TARGET_NR_nfsservctl         254
+#define TARGET_NR_aplib              255
+#define TARGET_NR_clock_settime	256
+#define TARGET_NR_clock_gettime	257
+#define TARGET_NR_clock_getres	258
+#define TARGET_NR_clock_nanosleep	259
+#define TARGET_NR_sched_getaffinity	260
+#define TARGET_NR_sched_setaffinity	261
+#define TARGET_NR_timer_settime	262
+#define TARGET_NR_timer_gettime	263
+#define TARGET_NR_timer_getoverrun	264
+#define TARGET_NR_timer_delete	265
+#define TARGET_NR_timer_create	266
+/* #define TARGET_NR_vserver		267 Reserved for VSERVER */
+#define TARGET_NR_io_setup		268
+#define TARGET_NR_io_destroy		269
+#define TARGET_NR_io_submit		270
+#define TARGET_NR_io_cancel		271
+#define TARGET_NR_io_getevents	272
+#define TARGET_NR_mq_open		273
+#define TARGET_NR_mq_unlink		274
+#define TARGET_NR_mq_timedsend	275
+#define TARGET_NR_mq_timedreceive	276
+#define TARGET_NR_mq_notify		277
+#define TARGET_NR_mq_getsetattr	278
+#define TARGET_NR_waitid		279
+#define TARGET_NR_tee		280
+#define TARGET_NR_add_key		281
+#define TARGET_NR_request_key	282
+#define TARGET_NR_keyctl		283
+#define TARGET_NR_openat		284
+#define TARGET_NR_mkdirat		285
+#define TARGET_NR_mknodat		286
+#define TARGET_NR_fchownat		287
+#define TARGET_NR_futimesat		288
+#define TARGET_NR_fstatat64		289
+#define TARGET_NR_unlinkat		290
+#define TARGET_NR_renameat		291
+#define TARGET_NR_linkat		292
+#define TARGET_NR_symlinkat		293
+#define TARGET_NR_readlinkat		294
+#define TARGET_NR_fchmodat		295
+#define TARGET_NR_faccessat		296
+#define TARGET_NR_pselect6		297
+#define TARGET_NR_ppoll		298
+#define TARGET_NR_unshare		299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_get_robust_list	301
+#define TARGET_NR_migrate_pages	302
+#define TARGET_NR_mbind		303
+#define TARGET_NR_get_mempolicy	304
+#define TARGET_NR_set_mempolicy	305
+#define TARGET_NR_kexec_load		306
+#define TARGET_NR_move_pages		307
+#define TARGET_NR_getcpu		308
+#define TARGET_NR_epoll_pwait	309
+#define TARGET_NR_utimensat		310
+#define TARGET_NR_signalfd		311
+#define TARGET_NR_timerfd		312
+#define TARGET_NR_eventfd		313
+#define TARGET_NR_fallocate		314
+#define TARGET_NR_timerfd_settime	315
+#define TARGET_NR_timerfd_gettime	316
+#define TARGET_NR_signalfd4		317
+#define TARGET_NR_eventfd2		318
+#define TARGET_NR_epoll_create1	319
+#define TARGET_NR_dup3			320
+#define TARGET_NR_pipe2		321
+#define TARGET_NR_inotify_init1	322
+#define TARGET_NR_accept4		323
+#define TARGET_NR_preadv                324
+#define TARGET_NR_pwritev               325
+#define TARGET_NR_rt_tgsigqueueinfo     326
+#define TARGET_NR_perf_event_open       327
+#define TARGET_NR_recvmmsg              328
+#define TARGET_NR_fanotify_init         329
+#define TARGET_NR_fanotify_mark         330
+#define TARGET_NR_prlimit64             331
+#define TARGET_NR_name_to_handle_at     332
+#define TARGET_NR_open_by_handle_at     333
+#define TARGET_NR_clock_adjtime         334
+#define TARGET_NR_syncfs                335
diff --git a/qemu-0.15.x/linux-user/sparc/target_signal.h b/qemu-0.15.x/linux-user/sparc/target_signal.h
new file mode 100644
index 0000000..c7de300
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc/target_signal.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/sparc/termbits.h b/qemu-0.15.x/linux-user/sparc/termbits.h
new file mode 100644
index 0000000..691600d
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc/termbits.h
@@ -0,0 +1,279 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR    0
+#define TARGET_VQUIT    1
+#define TARGET_VERASE   2
+#define TARGET_VKILL    3
+#define TARGET_VEOF     4
+#define TARGET_VEOL     5
+#define TARGET_VEOL2    6
+#define TARGET_VSWTC    7
+#define TARGET_VSTART   8
+#define TARGET_VSTOP    9
+
+#define TARGET_VSUSP    10
+#define TARGET_VDSUSP   11  /* SunOS POSIX nicety I do believe... */
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE  14
+#define TARGET_VLNEXT   15
+
+/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
+ * shared with eof/eol
+ */
+#define TARGET_VMIN     TARGET_VEOF
+#define TARGET_VTIME    TARGET_VEOL
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0x00000001
+#define TARGET_BRKINT	0x00000002
+#define TARGET_IGNPAR	0x00000004
+#define TARGET_PARMRK	0x00000008
+#define TARGET_INPCK	0x00000010
+#define TARGET_ISTRIP	0x00000020
+#define TARGET_INLCR	0x00000040
+#define TARGET_IGNCR	0x00000080
+#define TARGET_ICRNL	0x00000100
+#define TARGET_IUCLC	0x00000200
+#define TARGET_IXON	0x00000400
+#define TARGET_IXANY	0x00000800
+#define TARGET_IXOFF	0x00001000
+#define TARGET_IMAXBEL	0x00002000
+#define TARGET_IUTF8	0x00004000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0x00000001
+#define TARGET_OLCUC	0x00000002
+#define TARGET_ONLCR	0x00000004
+#define TARGET_OCRNL	0x00000008
+#define TARGET_ONOCR	0x00000010
+#define TARGET_ONLRET	0x00000020
+#define TARGET_OFILL	0x00000040
+#define TARGET_OFDEL	0x00000080
+#define TARGET_NLDLY	0x00000100
+#define   TARGET_NL0	0x00000000
+#define   TARGET_NL1	0x00000100
+#define TARGET_CRDLY	0x00000600
+#define   TARGET_CR0	0x00000000
+#define   TARGET_CR1	0x00000200
+#define   TARGET_CR2	0x00000400
+#define   TARGET_CR3	0x00000600
+#define TARGET_TABDLY	0x00001800
+#define   TARGET_TAB0	0x00000000
+#define   TARGET_TAB1	0x00000800
+#define   TARGET_TAB2	0x00001000
+#define   TARGET_TAB3	0x00001800
+#define   TARGET_XTABS	0x00001800
+#define TARGET_BSDLY	0x00002000
+#define   TARGET_BS0	0x00000000
+#define   TARGET_BS1	0x00002000
+#define TARGET_VTDLY	0x00004000
+#define   TARGET_VT0	0x00000000
+#define   TARGET_VT1	0x00004000
+#define TARGET_FFDLY	0x00008000
+#define   TARGET_FF0	0x00000000
+#define   TARGET_FF1	0x00008000
+#define TARGET_PAGEOUT 0x00010000  /* SUNOS specific */
+#define TARGET_WRAP    0x00020000  /* SUNOS specific */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	  0x0000100f
+#define  TARGET_B0	  0x00000000   /* hang up */
+#define  TARGET_B50	  0x00000001
+#define  TARGET_B75	  0x00000002
+#define  TARGET_B110	  0x00000003
+#define  TARGET_B134	  0x00000004
+#define  TARGET_B150	  0x00000005
+#define  TARGET_B200	  0x00000006
+#define  TARGET_B300	  0x00000007
+#define  TARGET_B600	  0x00000008
+#define  TARGET_B1200	  0x00000009
+#define  TARGET_B1800	  0x0000000a
+#define  TARGET_B2400	  0x0000000b
+#define  TARGET_B4800	  0x0000000c
+#define  TARGET_B9600	  0x0000000d
+#define  TARGET_B19200	  0x0000000e
+#define  TARGET_B38400	  0x0000000f
+#define TARGET_EXTA      B19200
+#define TARGET_EXTB      B38400
+#define  TARGET_CSIZE    0x00000030
+#define   TARGET_CS5	  0x00000000
+#define   TARGET_CS6	  0x00000010
+#define   TARGET_CS7	  0x00000020
+#define   TARGET_CS8	  0x00000030
+#define TARGET_CSTOPB	  0x00000040
+#define TARGET_CREAD	  0x00000080
+#define TARGET_PARENB	  0x00000100
+#define TARGET_PARODD	  0x00000200
+#define TARGET_HUPCL	  0x00000400
+#define TARGET_CLOCAL	  0x00000800
+#define TARGET_CBAUDEX   0x00001000
+/* We'll never see these speeds with the Zilogs, but for completeness... */
+#define  TARGET_B57600   0x00001001
+#define  TARGET_B115200  0x00001002
+#define  TARGET_B230400  0x00001003
+#define  TARGET_B460800  0x00001004
+/* This is what we can do with the Zilogs. */
+#define  TARGET_B76800   0x00001005
+/* This is what we can do with the SAB82532. */
+#define  TARGET_B153600  0x00001006
+#define  TARGET_B307200  0x00001007
+#define  TARGET_B614400  0x00001008
+#define  TARGET_B921600  0x00001009
+/* And these are the rest... */
+#define  TARGET_B500000  0x0000100a
+#define  TARGET_B576000  0x0000100b
+#define TARGET_B1000000  0x0000100c
+#define TARGET_B1152000  0x0000100d
+#define TARGET_B1500000  0x0000100e
+#define TARGET_B2000000  0x0000100f
+/* These have totally bogus values and nobody uses them
+   so far. Later on we'd have to use say 0x10000x and
+   adjust CBAUD constant and drivers accordingly.
+#define B2500000  0x00001010
+#define B3000000  0x00001011
+#define B3500000  0x00001012
+#define B4000000  0x00001013  */
+#define TARGET_CIBAUD	  0x100f0000  /* input baud rate (not used) */
+#define TARGET_CMSPAR	  0x40000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  0x80000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000001
+#define TARGET_ICANON	0x00000002
+#define TARGET_XCASE	0x00000004
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000010
+#define TARGET_ECHOK	0x00000020
+#define TARGET_ECHONL	0x00000040
+#define TARGET_NOFLSH	0x00000080
+#define TARGET_TOSTOP	0x00000100
+#define TARGET_ECHOCTL	0x00000200
+#define TARGET_ECHOPRT	0x00000400
+#define TARGET_ECHOKE	0x00000800
+#define TARGET_DEFECHO  0x00001000  /* SUNOS thing, what is it? */
+#define TARGET_FLUSHO	0x00002000
+#define TARGET_PENDIN	0x00004000
+#define TARGET_IEXTEN	0x00008000
+
+/* ioctls */
+
+/* Big T */
+#define TARGET_TCGETA		TARGET_IOR('T', 1, struct target_termio)
+#define TARGET_TCSETA		TARGET_IOW('T', 2, struct target_termio)
+#define TARGET_TCSETAW		TARGET_IOW('T', 3, struct target_termio)
+#define TARGET_TCSETAF		TARGET_IOW('T', 4, struct target_termio)
+#define TARGET_TCSBRK		TARGET_IO('T', 5)
+#define TARGET_TCXONC		TARGET_IO('T', 6)
+#define TARGET_TCFLSH		TARGET_IO('T', 7)
+#define TARGET_TCGETS		TARGET_IOR('T', 8, struct target_termios)
+#define TARGET_TCSETS		TARGET_IOW('T', 9, struct target_termios)
+#define TARGET_TCSETSW		TARGET_IOW('T', 10, struct target_termios)
+#define TARGET_TCSETSF		TARGET_IOW('T', 11, struct target_termios)
+
+/* Note that all the ioctls that are not available in Linux have a
+ * double underscore on the front to: a) avoid some programs to
+ * thing we support some ioctls under Linux (autoconfiguration stuff)
+ */
+/* Little t */
+#define TARGET_TIOCGETD	TARGET_IOR('t', 0, int)
+#define TARGET_TIOCSETD	TARGET_IOW('t', 1, int)
+//#define __TIOCHPCL        _IO('t', 2) /* SunOS Specific */
+//#define __TIOCMODG        _IOR('t', 3, int) /* SunOS Specific */
+//#define __TIOCMODS        _IOW('t', 4, int) /* SunOS Specific */
+//#define __TIOCGETP        _IOR('t', 8, struct sgttyb) /* SunOS Specific */
+//#define __TIOCSETP        _IOW('t', 9, struct sgttyb) /* SunOS Specific */
+//#define __TIOCSETN        _IOW('t', 10, struct sgttyb) /* SunOS Specific */
+#define TARGET_TIOCEXCL	TARGET_IO('t', 13)
+#define TARGET_TIOCNXCL	TARGET_IO('t', 14)
+//#define __TIOCFLUSH       _IOW('t', 16, int) /* SunOS Specific */
+//#define __TIOCSETC        _IOW('t', 17, struct tchars) /* SunOS Specific */
+//#define __TIOCGETC        _IOR('t', 18, struct tchars) /* SunOS Specific */
+//#define __TIOCTCNTL       _IOW('t', 32, int) /* SunOS Specific */
+//#define __TIOCSIGNAL      _IOW('t', 33, int) /* SunOS Specific */
+//#define __TIOCSETX        _IOW('t', 34, int) /* SunOS Specific */
+//#define __TIOCGETX        _IOR('t', 35, int) /* SunOS Specific */
+#define TARGET_TIOCCONS	TARGET_IO('t', 36)
+//#define __TIOCSSIZE     _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
+//#define __TIOCGSIZE     _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
+#define TARGET_TIOCGSOFTCAR	TARGET_IOR('t', 100, int)
+#define TARGET_TIOCSSOFTCAR	TARGET_IOW('t', 101, int)
+//#define __TIOCUCNTL       _IOW('t', 102, int) /* SunOS Specific */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)
+//#define __TIOCREMOTE      _IOW('t', 105, int) /* SunOS Specific */
+#define TARGET_TIOCMGET	TARGET_IOR('t', 106, int)
+#define TARGET_TIOCMBIC	TARGET_IOW('t', 107, int)
+#define TARGET_TIOCMBIS	TARGET_IOW('t', 108, int)
+#define TARGET_TIOCMSET	TARGET_IOW('t', 109, int)
+#define TARGET_TIOCSTART       TARGET_IO('t', 110)
+#define TARGET_TIOCSTOP        TARGET_IO('t', 111)
+#define TARGET_TIOCPKT		TARGET_IOW('t', 112, int)
+#define TARGET_TIOCNOTTY	TARGET_IO('t', 113)
+#define TARGET_TIOCSTI		TARGET_IOW('t', 114, char)
+#define TARGET_TIOCOUTQ	TARGET_IOR('t', 115, int)
+//#define __TIOCGLTC        _IOR('t', 116, struct ltchars) /* SunOS Specific */
+//#define __TIOCSLTC        _IOW('t', 117, struct ltchars) /* SunOS Specific */
+/* 118 is the non-posix setpgrp tty ioctl */
+/* 119 is the non-posix getpgrp tty ioctl */
+//#define __TIOCCDTR        TARGET_IO('t', 120) /* SunOS Specific */
+//#define __TIOCSDTR        TARGET_IO('t', 121) /* SunOS Specific */
+#define TARGET_TIOCCBRK        TARGET_IO('t', 122)
+#define TARGET_TIOCSBRK        TARGET_IO('t', 123)
+//#define __TIOCLGET        TARGET_IOW('t', 124, int) /* SunOS Specific */
+//#define __TIOCLSET        TARGET_IOW('t', 125, int) /* SunOS Specific */
+//#define __TIOCLBIC        TARGET_IOW('t', 126, int) /* SunOS Specific */
+//#define __TIOCLBIS        TARGET_IOW('t', 127, int) /* SunOS Specific */
+//#define __TIOCISPACE      TARGET_IOR('t', 128, int) /* SunOS Specific */
+//#define __TIOCISIZE       TARGET_IOR('t', 129, int) /* SunOS Specific */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 130, int)
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 131, int)
+#define TARGET_TIOCSCTTY	TARGET_IO('t', 132)
+#define TARGET_TIOCGSID	TARGET_IOR('t', 133, int)
+/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
+#define TARGET_TIOCGPTN	TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
+
+/* Little f */
+#define TARGET_FIOCLEX		TARGET_IO('f', 1)
+#define TARGET_FIONCLEX	TARGET_IO('f', 2)
+#define TARGET_FIOASYNC	TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO		TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD	TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
+ * someday.  This is completely bogus, I know...
+ */
+//#define __TCGETSTAT       TARGET_IO('T', 200) /* Rutgers specific */
+//#define __TCSETSTAT       TARGET_IO('T', 201) /* Rutgers specific */
+
+/* Linux specific, no SunOS equivalent. */
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TCSBRKP		0x5425
+#define TARGET_TIOCTTYGSTRUCT	0x5426
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TARGET_TIOCMIWAIT	0x545C /* Wait input */
+#define TARGET_TIOCGICOUNT	0x545D /* Read serial port inline interrupt counts */
diff --git a/qemu-0.15.x/linux-user/sparc64/syscall.h b/qemu-0.15.x/linux-user/sparc64/syscall.h
new file mode 100644
index 0000000..81a816d
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc64/syscall.h
@@ -0,0 +1,10 @@
+struct target_pt_regs {
+	abi_ulong u_regs[16];
+	abi_ulong tstate;
+	abi_ulong pc;
+	abi_ulong npc;
+	abi_ulong y;
+	abi_ulong fprs;
+};
+
+#define UNAME_MACHINE "sun4u"
diff --git a/qemu-0.15.x/linux-user/sparc64/syscall_nr.h b/qemu-0.15.x/linux-user/sparc64/syscall_nr.h
new file mode 100644
index 0000000..70988b2
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc64/syscall_nr.h
@@ -0,0 +1,336 @@
+#define TARGET_NR_restart_syscall      0 /* Linux Specific				   */
+#define TARGET_NR_exit                 1 /* Common                                      */
+#define TARGET_NR_fork                 2 /* Common                                      */
+#define TARGET_NR_read                 3 /* Common                                      */
+#define TARGET_NR_write                4 /* Common                                      */
+#define TARGET_NR_open                 5 /* Common                                      */
+#define TARGET_NR_close                6 /* Common                                      */
+#define TARGET_NR_wait4                7 /* Common                                      */
+#define TARGET_NR_creat                8 /* Common                                      */
+#define TARGET_NR_link                 9 /* Common                                      */
+#define TARGET_NR_unlink              10 /* Common                                      */
+#define TARGET_NR_execv               11 /* SunOS Specific                              */
+#define TARGET_NR_chdir               12 /* Common                                      */
+#define TARGET_NR_chown		 13 /* Common					   */
+#define TARGET_NR_mknod               14 /* Common                                      */
+#define TARGET_NR_chmod               15 /* Common                                      */
+#define TARGET_NR_lchown              16 /* Common                                      */
+#define TARGET_NR_brk                 17 /* Common                                      */
+#define TARGET_NR_perfctr             18 /* Performance counter operations              */
+#define TARGET_NR_lseek               19 /* Common                                      */
+#define TARGET_NR_getpid              20 /* Common                                      */
+#define TARGET_NR_capget		 21 /* Linux Specific				   */
+#define TARGET_NR_capset		 22 /* Linux Specific				   */
+#define TARGET_NR_setuid              23 /* Implemented via setreuid in SunOS           */
+#define TARGET_NR_getuid              24 /* Common                                      */
+/* #define TARGET_NR_time alias	 25    ENOSYS under SunOS			   */
+#define TARGET_NR_ptrace              26 /* Common                                      */
+#define TARGET_NR_alarm               27 /* Implemented via setitimer in SunOS          */
+#define TARGET_NR_sigaltstack	 28 /* Common					   */
+#define TARGET_NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
+#define TARGET_NR_utime               30 /* Implemented via utimes() under SunOS        */
+#define TARGET_NR_lchown32            31 /* Linux sparc32 specific                      */
+#define TARGET_NR_fchown32            32 /* Linux sparc32 specific                      */
+#define TARGET_NR_access              33 /* Common                                      */
+#define TARGET_NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
+#define TARGET_NR_chown32             35 /*  Linux sparc32 specific                     */
+#define TARGET_NR_sync                36 /* Common                                      */
+#define TARGET_NR_kill                37 /* Common                                      */
+#define TARGET_NR_stat                38 /* Common                                      */
+#define TARGET_NR_sendfile		 39 /* Linux Specific				   */
+#define TARGET_NR_lstat               40 /* Common                                      */
+#define TARGET_NR_dup                 41 /* Common                                      */
+#define TARGET_NR_pipe                42 /* Common                                      */
+#define TARGET_NR_times               43 /* Implemented via getrusage() in SunOS        */
+#define TARGET_NR_getuid32            44 /* Linux sparc32 specific                      */
+#define TARGET_NR_umount2             45 /* Linux Specific                              */
+#define TARGET_NR_setgid              46 /* Implemented via setregid() in SunOS         */
+#define TARGET_NR_getgid              47 /* Common                                      */
+#define TARGET_NR_signal              48 /* Implemented via sigvec() in SunOS           */
+#define TARGET_NR_geteuid             49 /* SunOS calls getuid()                        */
+#define TARGET_NR_getegid             50 /* SunOS calls getgid()                        */
+#define TARGET_NR_acct                51 /* Common                                      */
+#define TARGET_NR_memory_ordering	 52 /* Linux Specific				   */
+#define TARGET_NR_getgid32            53 /* Linux sparc32 specific                      */
+#define TARGET_NR_ioctl               54 /* Common                                      */
+#define TARGET_NR_reboot              55 /* Common                                      */
+#define TARGET_NR_mmap2		      56 /* Linux sparc32 Specific                      */
+#define TARGET_NR_symlink             57 /* Common                                      */
+#define TARGET_NR_readlink            58 /* Common                                      */
+#define TARGET_NR_execve              59 /* Common                                      */
+#define TARGET_NR_umask               60 /* Common                                      */
+#define TARGET_NR_chroot              61 /* Common                                      */
+#define TARGET_NR_fstat               62 /* Common                                      */
+#define TARGET_NR_fstat64             63 /* Linux sparc32 Specific                      */
+#define TARGET_NR_getpagesize         64 /* Common                                      */
+#define TARGET_NR_msync               65 /* Common in newer 1.3.x revs...               */
+#define TARGET_NR_vfork               66 /* Common                                      */
+#define TARGET_NR_pread64             67 /* Linux Specific                              */
+#define TARGET_NR_pwrite64            68 /* Linux Specific                              */
+#define TARGET_NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
+#define TARGET_NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
+#define TARGET_NR_mmap                71 /* Common                                      */
+#define TARGET_NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
+#define TARGET_NR_munmap              73 /* Common                                      */
+#define TARGET_NR_mprotect            74 /* Common                                      */
+#define TARGET_NR_madvise             75 /* Common                                      */
+#define TARGET_NR_vhangup             76 /* Common                                      */
+#define TARGET_NR_truncate64          77 /* Linux sparc32 Specific			*/
+#define TARGET_NR_mincore             78 /* Common                                      */
+#define TARGET_NR_getgroups           79 /* Common                                      */
+#define TARGET_NR_setgroups           80 /* Common                                      */
+#define TARGET_NR_getpgrp             81 /* Common                                      */
+#define TARGET_NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
+#define TARGET_NR_setitimer           83 /* Common                                      */
+#define TARGET_NR_ftruncate64         84 /* Linux sparc32 Specific                      */
+#define TARGET_NR_swapon              85 /* Common                                      */
+#define TARGET_NR_getitimer           86 /* Common                                      */
+#define TARGET_NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
+#define TARGET_NR_sethostname         88 /* Common                                      */
+#define TARGET_NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
+#define TARGET_NR_dup2                90 /* Common                                      */
+#define TARGET_NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
+#define TARGET_NR_fcntl               92 /* Common                                      */
+#define TARGET_NR_select              93 /* Common                                      */
+#define TARGET_NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
+#define TARGET_NR_fsync               95 /* Common                                      */
+#define TARGET_NR_setpriority         96 /* Common                                      */
+#define TARGET_NR_socket              97 /* Common                                      */
+#define TARGET_NR_connect             98 /* Common                                      */
+#define TARGET_NR_accept              99 /* Common                                      */
+#define TARGET_NR_getpriority        100 /* Common                                      */
+#define TARGET_NR_rt_sigreturn       101 /* Linux Specific                              */
+#define TARGET_NR_rt_sigaction       102 /* Linux Specific                              */
+#define TARGET_NR_rt_sigprocmask     103 /* Linux Specific                              */
+#define TARGET_NR_rt_sigpending      104 /* Linux Specific                              */
+#define TARGET_NR_rt_sigtimedwait    105 /* Linux Specific                              */
+#define TARGET_NR_rt_sigqueueinfo    106 /* Linux Specific                              */
+#define TARGET_NR_rt_sigsuspend      107 /* Linux Specific                              */
+#define TARGET_NR_setresuid          108 /* Linux Specific, sigvec under SunOS	   */
+#define TARGET_NR_getresuid          109 /* Linux Specific, sigblock under SunOS	   */
+#define TARGET_NR_setresgid          110 /* Linux Specific, sigsetmask under SunOS	   */
+#define TARGET_NR_getresgid          111 /* Linux Specific, sigpause under SunOS	   */
+/* #define TARGET_NR_setregid32          75  Linux sparc32, sigstack under SunOS         */
+#define TARGET_NR_recvmsg            113 /* Common                                      */
+#define TARGET_NR_sendmsg            114 /* Common                                      */
+#define TARGET_NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
+#define TARGET_NR_gettimeofday       116 /* Common                                      */
+#define TARGET_NR_getrusage          117 /* Common                                      */
+#define TARGET_NR_getsockopt         118 /* Common                                      */
+#define TARGET_NR_getcwd		119 /* Linux Specific				   */
+#define TARGET_NR_readv              120 /* Common                                      */
+#define TARGET_NR_writev             121 /* Common                                      */
+#define TARGET_NR_settimeofday       122 /* Common                                      */
+#define TARGET_NR_fchown             123 /* Common                                      */
+#define TARGET_NR_fchmod             124 /* Common                                      */
+#define TARGET_NR_recvfrom           125 /* Common                                      */
+#define TARGET_NR_setreuid           126 /* Common                                      */
+#define TARGET_NR_setregid           127 /* Common                                      */
+#define TARGET_NR_rename             128 /* Common                                      */
+#define TARGET_NR_truncate           129 /* Common                                      */
+#define TARGET_NR_ftruncate          130 /* Common                                      */
+#define TARGET_NR_flock              131 /* Common                                      */
+#define TARGET_NR_lstat64	     132 /* Linux sparc32 Specific                      */
+#define TARGET_NR_sendto             133 /* Common                                      */
+#define TARGET_NR_shutdown           134 /* Common                                      */
+#define TARGET_NR_socketpair         135 /* Common                                      */
+#define TARGET_NR_mkdir              136 /* Common                                      */
+#define TARGET_NR_rmdir              137 /* Common                                      */
+#define TARGET_NR_utimes             138 /* SunOS Specific                              */
+#define TARGET_NR_stat64	     139 /* Linux sparc32 Specific			   */
+#define TARGET_NR_sendfile64         140 /* adjtime under SunOS                         */
+#define TARGET_NR_getpeername        141 /* Common                                      */
+#define TARGET_NR_futex              142 /* gethostid under SunOS                       */
+#define TARGET_NR_gettid             143 /* ENOSYS under SunOS                          */
+#define TARGET_NR_getrlimit		144 /* Common                                      */
+#define TARGET_NR_setrlimit          145 /* Common                                      */
+#define TARGET_NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
+#define TARGET_NR_prctl		147 /* ENOSYS under SunOS                          */
+#define TARGET_NR_pciconfig_read	148 /* ENOSYS under SunOS                          */
+#define TARGET_NR_pciconfig_write	149 /* ENOSYS under SunOS                          */
+#define TARGET_NR_getsockname        150 /* Common                                      */
+/* #define TARGET_NR_getmsg          151    SunOS Specific                              */
+/* #define TARGET_NR_putmsg          152    SunOS Specific                              */
+#define TARGET_NR_poll               153 /* Common                                      */
+#define TARGET_NR_getdents64		154 /* Linux specific				   */
+#define TARGET_NR_fcntl64            155 /* Linux sparc32 Specific                      */
+/* #define TARGET_NR_getdirentries   156    SunOS Specific                              */
+#define TARGET_NR_statfs             157 /* Common                                      */
+#define TARGET_NR_fstatfs            158 /* Common                                      */
+#define TARGET_NR_umount             159 /* Common                                      */
+#define TARGET_NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
+#define TARGET_NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
+#define TARGET_NR_getdomainname      162 /* SunOS Specific                              */
+#define TARGET_NR_setdomainname      163 /* Common                                      */
+#define TARGET_NR_utrap_install	164 /* SYSV ABI/v9 required			   */
+#define TARGET_NR_quotactl           165 /* Common                                      */
+#define TARGET_NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
+#define TARGET_NR_mount              167 /* Common                                      */
+#define TARGET_NR_ustat              168 /* Common                                      */
+#define TARGET_NR_setxattr           169 /* SunOS: semsys                               */
+#define TARGET_NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define TARGET_NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define TARGET_NR_getxattr           172 /* SunOS: auditsys                             */
+#define TARGET_NR_lgetxattr          173 /* SunOS: rfssys                               */
+#define TARGET_NR_getdents           174 /* Common                                      */
+#define TARGET_NR_setsid             175 /* Common                                      */
+#define TARGET_NR_fchdir             176 /* Common                                      */
+#define TARGET_NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define TARGET_NR_listxattr          178 /* SunOS: vpixsys                              */
+#define TARGET_NR_llistxattr         179 /* SunOS: aioread                              */
+#define TARGET_NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define TARGET_NR_removexattr        181 /* SunOS: aiowait                              */
+#define TARGET_NR_lremovexattr       182 /* SunOS: aiocancel                            */
+#define TARGET_NR_sigpending         183 /* Common                                      */
+#define TARGET_NR_query_module	184 /* Linux Specific				   */
+#define TARGET_NR_setpgid            185 /* Common                                      */
+#define TARGET_NR_fremovexattr       186 /* SunOS: pathconf                             */
+#define TARGET_NR_tkill              187 /* SunOS: fpathconf                            */
+#define TARGET_NR_exit_group		188 /* Linux specific, sysconf undef SunOS         */
+#define TARGET_NR_uname              189 /* Linux Specific                              */
+#define TARGET_NR_init_module        190 /* Linux Specific                              */
+#define TARGET_NR_personality        191 /* Linux Specific                              */
+#define TARGET_NR_remap_file_pages   192 /* Linux Specific                              */
+#define TARGET_NR_epoll_create       193 /* Linux Specific                              */
+#define TARGET_NR_epoll_ctl          194 /* Linux Specific                              */
+#define TARGET_NR_epoll_wait         195 /* Linux Specific                              */
+/* #define TARGET_NR_ulimit          196    Linux Specific                              */
+#define TARGET_NR_getppid            197 /* Linux Specific                              */
+#define TARGET_NR_sigaction          198 /* Linux Specific                              */
+#define TARGET_NR_sgetmask           199 /* Linux Specific                              */
+#define TARGET_NR_ssetmask           200 /* Linux Specific                              */
+#define TARGET_NR_sigsuspend         201 /* Linux Specific                              */
+#define TARGET_NR_oldlstat           202 /* Linux Specific                              */
+#define TARGET_NR_uselib             203 /* Linux Specific                              */
+#define TARGET_NR_readdir            204 /* Linux Specific                              */
+#define TARGET_NR_readahead          205 /* Linux Specific                              */
+#define TARGET_NR_socketcall         206 /* Linux Specific                              */
+#define TARGET_NR_syslog             207 /* Linux Specific                              */
+#define TARGET_NR_lookup_dcookie     208 /* Linux Specific                              */
+#define TARGET_NR_fadvise64          209 /* Linux Specific                              */
+#define TARGET_NR_fadvise64_64       210 /* Linux Specific                              */
+#define TARGET_NR_tgkill             211 /* Linux Specific                              */
+#define TARGET_NR_waitpid            212 /* Linux Specific                              */
+#define TARGET_NR_swapoff            213 /* Linux Specific                              */
+#define TARGET_NR_sysinfo            214 /* Linux Specific                              */
+#define TARGET_NR_ipc                215 /* Linux Specific                              */
+#define TARGET_NR_sigreturn          216 /* Linux Specific                              */
+#define TARGET_NR_clone              217 /* Linux Specific                              */
+/* #define TARGET_NR_modify_ldt      218    Linux Specific - i386 specific, unused      */
+#define TARGET_NR_adjtimex           219 /* Linux Specific                              */
+#define TARGET_NR_sigprocmask        220 /* Linux Specific                              */
+#define TARGET_NR_create_module      221 /* Linux Specific                              */
+#define TARGET_NR_delete_module      222 /* Linux Specific                              */
+#define TARGET_NR_get_kernel_syms    223 /* Linux Specific                              */
+#define TARGET_NR_getpgid            224 /* Linux Specific                              */
+#define TARGET_NR_bdflush            225 /* Linux Specific                              */
+#define TARGET_NR_sysfs              226 /* Linux Specific                              */
+#define TARGET_NR_afs_syscall        227 /* Linux Specific                              */
+#define TARGET_NR_setfsuid           228 /* Linux Specific                              */
+#define TARGET_NR_setfsgid           229 /* Linux Specific                              */
+#define TARGET_NR__newselect         230 /* Linux Specific                              */
+#define TARGET_NR_time               231 /* Linux sparc32                               */
+/* #define TARGET_NR_oldstat         232    Linux Specific                              */
+#define TARGET_NR_stime              233 /* Linux Specific                              */
+#define TARGET_NR_statfs64           234 /* Linux Specific                              */
+#define TARGET_NR_fstatfs64          235 /* Linux Specific                              */
+#define TARGET_NR__llseek            236 /* Linux Specific                              */
+#define TARGET_NR_mlock              237
+#define TARGET_NR_munlock            238
+#define TARGET_NR_mlockall           239
+#define TARGET_NR_munlockall         240
+#define TARGET_NR_sched_setparam     241
+#define TARGET_NR_sched_getparam     242
+#define TARGET_NR_sched_setscheduler 243
+#define TARGET_NR_sched_getscheduler 244
+#define TARGET_NR_sched_yield        245
+#define TARGET_NR_sched_get_priority_max 246
+#define TARGET_NR_sched_get_priority_min 247
+#define TARGET_NR_sched_rr_get_interval  248
+#define TARGET_NR_nanosleep          249
+#define TARGET_NR_mremap             250
+#define TARGET_NR__sysctl            251
+#define TARGET_NR_getsid             252
+#define TARGET_NR_fdatasync          253
+#define TARGET_NR_nfsservctl         254
+#define TARGET_NR_aplib              255
+#define TARGET_NR_clock_settime	256
+#define TARGET_NR_clock_gettime	257
+#define TARGET_NR_clock_getres	258
+#define TARGET_NR_clock_nanosleep	259
+#define TARGET_NR_sched_getaffinity	260
+#define TARGET_NR_sched_setaffinity	261
+#define TARGET_NR_timer_settime	262
+#define TARGET_NR_timer_gettime	263
+#define TARGET_NR_timer_getoverrun	264
+#define TARGET_NR_timer_delete	265
+#define TARGET_NR_timer_create	266
+/* #define TARGET_NR_vserver		267 Reserved for VSERVER */
+#define TARGET_NR_io_setup		268
+#define TARGET_NR_io_destroy		269
+#define TARGET_NR_io_submit		270
+#define TARGET_NR_io_cancel		271
+#define TARGET_NR_io_getevents	272
+#define TARGET_NR_mq_open		273
+#define TARGET_NR_mq_unlink		274
+#define TARGET_NR_mq_timedsend	275
+#define TARGET_NR_mq_timedreceive	276
+#define TARGET_NR_mq_notify		277
+#define TARGET_NR_mq_getsetattr	278
+#define TARGET_NR_waitid		279
+/*#define TARGET_NR_sys_setaltroot	280 available (was setaltroot) */
+#define TARGET_NR_add_key		281
+#define TARGET_NR_request_key	282
+#define TARGET_NR_keyctl		283
+#define TARGET_NR_openat		284
+#define TARGET_NR_mkdirat		285
+#define TARGET_NR_mknodat		286
+#define TARGET_NR_fchownat		287
+#define TARGET_NR_futimesat		288
+#define TARGET_NR_fstatat64		289
+#define TARGET_NR_unlinkat		290
+#define TARGET_NR_renameat		291
+#define TARGET_NR_linkat		292
+#define TARGET_NR_symlinkat		293
+#define TARGET_NR_readlinkat		294
+#define TARGET_NR_fchmodat		295
+#define TARGET_NR_faccessat		296
+#define TARGET_NR_pselect6		297
+#define TARGET_NR_ppoll		298
+#define TARGET_NR_unshare		299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_get_robust_list	301
+#define TARGET_NR_migrate_pages	302
+#define TARGET_NR_mbind		303
+#define TARGET_NR_get_mempolicy	304
+#define TARGET_NR_set_mempolicy	305
+#define TARGET_NR_kexec_load		306
+#define TARGET_NR_move_pages		307
+#define TARGET_NR_getcpu		308
+#define TARGET_NR_epoll_pwait	309
+#define TARGET_NR_utimensat		310
+#define TARGET_NR_signalfd		311
+#define TARGET_NR_timerfd		312
+#define TARGET_NR_eventfd		313
+#define TARGET_NR_fallocate		314
+#define TARGET_NR_timerfd_settime	315
+#define TARGET_NR_timerfd_gettime	316
+#define TARGET_NR_signalfd4		317
+#define TARGET_NR_eventfd2		318
+#define TARGET_NR_epoll_create1	319
+#define TARGET_NR_dup3			320
+#define TARGET_NR_pipe2		321
+#define TARGET_NR_inotify_init1	322
+#define TARGET_NR_accept4		323
+#define TARGET_NR_preadv                324
+#define TARGET_NR_pwritev               325
+#define TARGET_NR_rt_tgsigqueueinfo     326
+#define TARGET_NR_perf_event_open       327
+#define TARGET_NR_recvmmsg              328
+#define TARGET_NR_fanotify_init         329
+#define TARGET_NR_fanotify_mark         330
+#define TARGET_NR_prlimit64             331
+#define TARGET_NR_name_to_handle_at     332
+#define TARGET_NR_open_by_handle_at     333
+#define TARGET_NR_clock_adjtime         334
+#define TARGET_NR_syncfs                335
diff --git a/qemu-0.15.x/linux-user/sparc64/target_signal.h b/qemu-0.15.x/linux-user/sparc64/target_signal.h
new file mode 100644
index 0000000..c7de300
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc64/target_signal.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/sparc64/termbits.h b/qemu-0.15.x/linux-user/sparc64/termbits.h
new file mode 100644
index 0000000..691600d
--- /dev/null
+++ b/qemu-0.15.x/linux-user/sparc64/termbits.h
@@ -0,0 +1,279 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR    0
+#define TARGET_VQUIT    1
+#define TARGET_VERASE   2
+#define TARGET_VKILL    3
+#define TARGET_VEOF     4
+#define TARGET_VEOL     5
+#define TARGET_VEOL2    6
+#define TARGET_VSWTC    7
+#define TARGET_VSTART   8
+#define TARGET_VSTOP    9
+
+#define TARGET_VSUSP    10
+#define TARGET_VDSUSP   11  /* SunOS POSIX nicety I do believe... */
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE  14
+#define TARGET_VLNEXT   15
+
+/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
+ * shared with eof/eol
+ */
+#define TARGET_VMIN     TARGET_VEOF
+#define TARGET_VTIME    TARGET_VEOL
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0x00000001
+#define TARGET_BRKINT	0x00000002
+#define TARGET_IGNPAR	0x00000004
+#define TARGET_PARMRK	0x00000008
+#define TARGET_INPCK	0x00000010
+#define TARGET_ISTRIP	0x00000020
+#define TARGET_INLCR	0x00000040
+#define TARGET_IGNCR	0x00000080
+#define TARGET_ICRNL	0x00000100
+#define TARGET_IUCLC	0x00000200
+#define TARGET_IXON	0x00000400
+#define TARGET_IXANY	0x00000800
+#define TARGET_IXOFF	0x00001000
+#define TARGET_IMAXBEL	0x00002000
+#define TARGET_IUTF8	0x00004000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0x00000001
+#define TARGET_OLCUC	0x00000002
+#define TARGET_ONLCR	0x00000004
+#define TARGET_OCRNL	0x00000008
+#define TARGET_ONOCR	0x00000010
+#define TARGET_ONLRET	0x00000020
+#define TARGET_OFILL	0x00000040
+#define TARGET_OFDEL	0x00000080
+#define TARGET_NLDLY	0x00000100
+#define   TARGET_NL0	0x00000000
+#define   TARGET_NL1	0x00000100
+#define TARGET_CRDLY	0x00000600
+#define   TARGET_CR0	0x00000000
+#define   TARGET_CR1	0x00000200
+#define   TARGET_CR2	0x00000400
+#define   TARGET_CR3	0x00000600
+#define TARGET_TABDLY	0x00001800
+#define   TARGET_TAB0	0x00000000
+#define   TARGET_TAB1	0x00000800
+#define   TARGET_TAB2	0x00001000
+#define   TARGET_TAB3	0x00001800
+#define   TARGET_XTABS	0x00001800
+#define TARGET_BSDLY	0x00002000
+#define   TARGET_BS0	0x00000000
+#define   TARGET_BS1	0x00002000
+#define TARGET_VTDLY	0x00004000
+#define   TARGET_VT0	0x00000000
+#define   TARGET_VT1	0x00004000
+#define TARGET_FFDLY	0x00008000
+#define   TARGET_FF0	0x00000000
+#define   TARGET_FF1	0x00008000
+#define TARGET_PAGEOUT 0x00010000  /* SUNOS specific */
+#define TARGET_WRAP    0x00020000  /* SUNOS specific */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	  0x0000100f
+#define  TARGET_B0	  0x00000000   /* hang up */
+#define  TARGET_B50	  0x00000001
+#define  TARGET_B75	  0x00000002
+#define  TARGET_B110	  0x00000003
+#define  TARGET_B134	  0x00000004
+#define  TARGET_B150	  0x00000005
+#define  TARGET_B200	  0x00000006
+#define  TARGET_B300	  0x00000007
+#define  TARGET_B600	  0x00000008
+#define  TARGET_B1200	  0x00000009
+#define  TARGET_B1800	  0x0000000a
+#define  TARGET_B2400	  0x0000000b
+#define  TARGET_B4800	  0x0000000c
+#define  TARGET_B9600	  0x0000000d
+#define  TARGET_B19200	  0x0000000e
+#define  TARGET_B38400	  0x0000000f
+#define TARGET_EXTA      B19200
+#define TARGET_EXTB      B38400
+#define  TARGET_CSIZE    0x00000030
+#define   TARGET_CS5	  0x00000000
+#define   TARGET_CS6	  0x00000010
+#define   TARGET_CS7	  0x00000020
+#define   TARGET_CS8	  0x00000030
+#define TARGET_CSTOPB	  0x00000040
+#define TARGET_CREAD	  0x00000080
+#define TARGET_PARENB	  0x00000100
+#define TARGET_PARODD	  0x00000200
+#define TARGET_HUPCL	  0x00000400
+#define TARGET_CLOCAL	  0x00000800
+#define TARGET_CBAUDEX   0x00001000
+/* We'll never see these speeds with the Zilogs, but for completeness... */
+#define  TARGET_B57600   0x00001001
+#define  TARGET_B115200  0x00001002
+#define  TARGET_B230400  0x00001003
+#define  TARGET_B460800  0x00001004
+/* This is what we can do with the Zilogs. */
+#define  TARGET_B76800   0x00001005
+/* This is what we can do with the SAB82532. */
+#define  TARGET_B153600  0x00001006
+#define  TARGET_B307200  0x00001007
+#define  TARGET_B614400  0x00001008
+#define  TARGET_B921600  0x00001009
+/* And these are the rest... */
+#define  TARGET_B500000  0x0000100a
+#define  TARGET_B576000  0x0000100b
+#define TARGET_B1000000  0x0000100c
+#define TARGET_B1152000  0x0000100d
+#define TARGET_B1500000  0x0000100e
+#define TARGET_B2000000  0x0000100f
+/* These have totally bogus values and nobody uses them
+   so far. Later on we'd have to use say 0x10000x and
+   adjust CBAUD constant and drivers accordingly.
+#define B2500000  0x00001010
+#define B3000000  0x00001011
+#define B3500000  0x00001012
+#define B4000000  0x00001013  */
+#define TARGET_CIBAUD	  0x100f0000  /* input baud rate (not used) */
+#define TARGET_CMSPAR	  0x40000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  0x80000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000001
+#define TARGET_ICANON	0x00000002
+#define TARGET_XCASE	0x00000004
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000010
+#define TARGET_ECHOK	0x00000020
+#define TARGET_ECHONL	0x00000040
+#define TARGET_NOFLSH	0x00000080
+#define TARGET_TOSTOP	0x00000100
+#define TARGET_ECHOCTL	0x00000200
+#define TARGET_ECHOPRT	0x00000400
+#define TARGET_ECHOKE	0x00000800
+#define TARGET_DEFECHO  0x00001000  /* SUNOS thing, what is it? */
+#define TARGET_FLUSHO	0x00002000
+#define TARGET_PENDIN	0x00004000
+#define TARGET_IEXTEN	0x00008000
+
+/* ioctls */
+
+/* Big T */
+#define TARGET_TCGETA		TARGET_IOR('T', 1, struct target_termio)
+#define TARGET_TCSETA		TARGET_IOW('T', 2, struct target_termio)
+#define TARGET_TCSETAW		TARGET_IOW('T', 3, struct target_termio)
+#define TARGET_TCSETAF		TARGET_IOW('T', 4, struct target_termio)
+#define TARGET_TCSBRK		TARGET_IO('T', 5)
+#define TARGET_TCXONC		TARGET_IO('T', 6)
+#define TARGET_TCFLSH		TARGET_IO('T', 7)
+#define TARGET_TCGETS		TARGET_IOR('T', 8, struct target_termios)
+#define TARGET_TCSETS		TARGET_IOW('T', 9, struct target_termios)
+#define TARGET_TCSETSW		TARGET_IOW('T', 10, struct target_termios)
+#define TARGET_TCSETSF		TARGET_IOW('T', 11, struct target_termios)
+
+/* Note that all the ioctls that are not available in Linux have a
+ * double underscore on the front to: a) avoid some programs to
+ * thing we support some ioctls under Linux (autoconfiguration stuff)
+ */
+/* Little t */
+#define TARGET_TIOCGETD	TARGET_IOR('t', 0, int)
+#define TARGET_TIOCSETD	TARGET_IOW('t', 1, int)
+//#define __TIOCHPCL        _IO('t', 2) /* SunOS Specific */
+//#define __TIOCMODG        _IOR('t', 3, int) /* SunOS Specific */
+//#define __TIOCMODS        _IOW('t', 4, int) /* SunOS Specific */
+//#define __TIOCGETP        _IOR('t', 8, struct sgttyb) /* SunOS Specific */
+//#define __TIOCSETP        _IOW('t', 9, struct sgttyb) /* SunOS Specific */
+//#define __TIOCSETN        _IOW('t', 10, struct sgttyb) /* SunOS Specific */
+#define TARGET_TIOCEXCL	TARGET_IO('t', 13)
+#define TARGET_TIOCNXCL	TARGET_IO('t', 14)
+//#define __TIOCFLUSH       _IOW('t', 16, int) /* SunOS Specific */
+//#define __TIOCSETC        _IOW('t', 17, struct tchars) /* SunOS Specific */
+//#define __TIOCGETC        _IOR('t', 18, struct tchars) /* SunOS Specific */
+//#define __TIOCTCNTL       _IOW('t', 32, int) /* SunOS Specific */
+//#define __TIOCSIGNAL      _IOW('t', 33, int) /* SunOS Specific */
+//#define __TIOCSETX        _IOW('t', 34, int) /* SunOS Specific */
+//#define __TIOCGETX        _IOR('t', 35, int) /* SunOS Specific */
+#define TARGET_TIOCCONS	TARGET_IO('t', 36)
+//#define __TIOCSSIZE     _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
+//#define __TIOCGSIZE     _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
+#define TARGET_TIOCGSOFTCAR	TARGET_IOR('t', 100, int)
+#define TARGET_TIOCSSOFTCAR	TARGET_IOW('t', 101, int)
+//#define __TIOCUCNTL       _IOW('t', 102, int) /* SunOS Specific */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)
+//#define __TIOCREMOTE      _IOW('t', 105, int) /* SunOS Specific */
+#define TARGET_TIOCMGET	TARGET_IOR('t', 106, int)
+#define TARGET_TIOCMBIC	TARGET_IOW('t', 107, int)
+#define TARGET_TIOCMBIS	TARGET_IOW('t', 108, int)
+#define TARGET_TIOCMSET	TARGET_IOW('t', 109, int)
+#define TARGET_TIOCSTART       TARGET_IO('t', 110)
+#define TARGET_TIOCSTOP        TARGET_IO('t', 111)
+#define TARGET_TIOCPKT		TARGET_IOW('t', 112, int)
+#define TARGET_TIOCNOTTY	TARGET_IO('t', 113)
+#define TARGET_TIOCSTI		TARGET_IOW('t', 114, char)
+#define TARGET_TIOCOUTQ	TARGET_IOR('t', 115, int)
+//#define __TIOCGLTC        _IOR('t', 116, struct ltchars) /* SunOS Specific */
+//#define __TIOCSLTC        _IOW('t', 117, struct ltchars) /* SunOS Specific */
+/* 118 is the non-posix setpgrp tty ioctl */
+/* 119 is the non-posix getpgrp tty ioctl */
+//#define __TIOCCDTR        TARGET_IO('t', 120) /* SunOS Specific */
+//#define __TIOCSDTR        TARGET_IO('t', 121) /* SunOS Specific */
+#define TARGET_TIOCCBRK        TARGET_IO('t', 122)
+#define TARGET_TIOCSBRK        TARGET_IO('t', 123)
+//#define __TIOCLGET        TARGET_IOW('t', 124, int) /* SunOS Specific */
+//#define __TIOCLSET        TARGET_IOW('t', 125, int) /* SunOS Specific */
+//#define __TIOCLBIC        TARGET_IOW('t', 126, int) /* SunOS Specific */
+//#define __TIOCLBIS        TARGET_IOW('t', 127, int) /* SunOS Specific */
+//#define __TIOCISPACE      TARGET_IOR('t', 128, int) /* SunOS Specific */
+//#define __TIOCISIZE       TARGET_IOR('t', 129, int) /* SunOS Specific */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 130, int)
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 131, int)
+#define TARGET_TIOCSCTTY	TARGET_IO('t', 132)
+#define TARGET_TIOCGSID	TARGET_IOR('t', 133, int)
+/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
+#define TARGET_TIOCGPTN	TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
+
+/* Little f */
+#define TARGET_FIOCLEX		TARGET_IO('f', 1)
+#define TARGET_FIONCLEX	TARGET_IO('f', 2)
+#define TARGET_FIOASYNC	TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO		TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD	TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
+ * someday.  This is completely bogus, I know...
+ */
+//#define __TCGETSTAT       TARGET_IO('T', 200) /* Rutgers specific */
+//#define __TCSETSTAT       TARGET_IO('T', 201) /* Rutgers specific */
+
+/* Linux specific, no SunOS equivalent. */
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TCSBRKP		0x5425
+#define TARGET_TIOCTTYGSTRUCT	0x5426
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TARGET_TIOCMIWAIT	0x545C /* Wait input */
+#define TARGET_TIOCGICOUNT	0x545D /* Read serial port inline interrupt counts */
diff --git a/qemu-0.15.x/linux-user/strace.c b/qemu-0.15.x/linux-user/strace.c
new file mode 100644
index 0000000..fe9326a
--- /dev/null
+++ b/qemu-0.15.x/linux-user/strace.c
@@ -0,0 +1,1532 @@
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sched.h>
+#include "qemu.h"
+
+int do_strace=0;
+
+struct syscallname {
+    int nr;
+    const char *name;
+    const char *format;
+    void (*call)(const struct syscallname *,
+                 abi_long, abi_long, abi_long,
+                 abi_long, abi_long, abi_long);
+    void (*result)(const struct syscallname *, abi_long);
+};
+
+#ifdef __GNUC__
+/*
+ * It is possible that target doesn't have syscall that uses
+ * following flags but we don't want the compiler to warn
+ * us about them being unused.  Same applies to utility print
+ * functions.  It is ok to keep them while not used.
+ */
+#define UNUSED __attribute__ ((unused))
+#else
+#define UNUSED
+#endif
+
+/*
+ * Structure used to translate flag values into strings.  This is
+ * similar that is in the actual strace tool.
+ */
+struct flags {
+    abi_long    f_value;  /* flag */
+    const char  *f_string; /* stringified flag */
+};
+
+/* common flags for all architectures */
+#define FLAG_GENERIC(name) { name, #name }
+/* target specific flags (syscall_defs.h has TARGET_<flag>) */
+#define FLAG_TARGET(name)  { TARGET_ ## name, #name }
+/* end of flags array */
+#define FLAG_END           { 0, NULL }
+
+UNUSED static const char *get_comma(int);
+UNUSED static void print_pointer(abi_long, int);
+UNUSED static void print_flags(const struct flags *, abi_long, int);
+UNUSED static void print_at_dirfd(abi_long, int);
+UNUSED static void print_file_mode(abi_long, int);
+UNUSED static void print_open_flags(abi_long, int);
+UNUSED static void print_syscall_prologue(const struct syscallname *);
+UNUSED static void print_syscall_epilogue(const struct syscallname *);
+UNUSED static void print_string(abi_long, int);
+UNUSED static void print_raw_param(const char *, abi_long, int);
+UNUSED static void print_timeval(abi_ulong, int);
+UNUSED static void print_number(abi_long, int);
+UNUSED static void print_signal(abi_ulong, int);
+
+/*
+ * Utility functions
+ */
+static void
+print_ipc_cmd(int cmd)
+{
+#define output_cmd(val) \
+if( cmd == val ) { \
+    gemu_log(#val); \
+    return; \
+}
+
+    cmd &= 0xff;
+
+    /* General IPC commands */
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_SET );
+    output_cmd( IPC_STAT );
+    output_cmd( IPC_INFO );
+    /* msgctl() commands */
+    #ifdef __USER_MISC
+    output_cmd( MSG_STAT );
+    output_cmd( MSG_INFO );
+    #endif
+    /* shmctl() commands */
+    output_cmd( SHM_LOCK );
+    output_cmd( SHM_UNLOCK );
+    output_cmd( SHM_STAT );
+    output_cmd( SHM_INFO );
+    /* semctl() commands */
+    output_cmd( GETPID );
+    output_cmd( GETVAL );
+    output_cmd( GETALL );
+    output_cmd( GETNCNT );
+    output_cmd( GETZCNT );
+    output_cmd( SETVAL );
+    output_cmd( SETALL );
+    output_cmd( SEM_STAT );
+    output_cmd( SEM_INFO );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+    output_cmd( IPC_RMID );
+
+    /* Some value we don't recognize */
+    gemu_log("%d",cmd);
+}
+
+static void
+print_signal(abi_ulong arg, int last)
+{
+    const char *signal_name = NULL;
+    switch(arg) {
+    case TARGET_SIGHUP: signal_name = "SIGHUP"; break;
+    case TARGET_SIGINT: signal_name = "SIGINT"; break;
+    case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break;
+    case TARGET_SIGILL: signal_name = "SIGILL"; break;
+    case TARGET_SIGABRT: signal_name = "SIGABRT"; break;
+    case TARGET_SIGFPE: signal_name = "SIGFPE"; break;
+    case TARGET_SIGKILL: signal_name = "SIGKILL"; break;
+    case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break;
+    case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break;
+    case TARGET_SIGALRM: signal_name = "SIGALRM"; break;
+    case TARGET_SIGTERM: signal_name = "SIGTERM"; break;
+    case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break;
+    case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break;
+    case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break;
+    case TARGET_SIGCONT: signal_name = "SIGCONT"; break;
+    case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break;
+    case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break;
+    case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
+    }
+    if (signal_name == NULL) {
+        print_raw_param("%ld", arg, 1);
+        return;
+    }
+    gemu_log("%s%s", signal_name, get_comma(last));
+}
+
+#ifdef TARGET_NR__newselect
+static void
+print_fdset(int n, abi_ulong target_fds_addr)
+{
+    int i;
+
+    gemu_log("[");
+    if( target_fds_addr ) {
+        abi_long *target_fds;
+
+        target_fds = lock_user(VERIFY_READ,
+                               target_fds_addr,
+                               sizeof(*target_fds)*(n / TARGET_ABI_BITS + 1),
+                               1);
+
+        if (!target_fds)
+            return;
+
+        for (i=n; i>=0; i--) {
+            if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
+                gemu_log("%d,", i );
+            }
+        unlock_user(target_fds, target_fds_addr, 0);
+    }
+    gemu_log("]");
+}
+#endif
+
+/*
+ * Sysycall specific output functions
+ */
+
+/* select */
+#ifdef TARGET_NR__newselect
+static long newselect_arg1 = 0;
+static long newselect_arg2 = 0;
+static long newselect_arg3 = 0;
+static long newselect_arg4 = 0;
+static long newselect_arg5 = 0;
+
+static void
+print_newselect(const struct syscallname *name,
+                abi_long arg1, abi_long arg2, abi_long arg3,
+                abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    gemu_log("%s(" TARGET_ABI_FMT_ld ",", name->name, arg1);
+    print_fdset(arg1, arg2);
+    gemu_log(",");
+    print_fdset(arg1, arg3);
+    gemu_log(",");
+    print_fdset(arg1, arg4);
+    gemu_log(",");
+    print_timeval(arg5, 1);
+    gemu_log(")");
+
+    /* save for use in the return output function below */
+    newselect_arg1=arg1;
+    newselect_arg2=arg2;
+    newselect_arg3=arg3;
+    newselect_arg4=arg4;
+    newselect_arg5=arg5;
+}
+#endif
+
+#ifdef TARGET_NR_semctl
+static void
+print_semctl(const struct syscallname *name,
+             abi_long arg1, abi_long arg2, abi_long arg3,
+             abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2);
+    print_ipc_cmd(arg3);
+    gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
+}
+#endif
+
+static void
+print_execve(const struct syscallname *name,
+             abi_long arg1, abi_long arg2, abi_long arg3,
+             abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    abi_ulong arg_ptr_addr;
+    char *s;
+
+    if (!(s = lock_user_string(arg1)))
+        return;
+    gemu_log("%s(\"%s\",{", name->name, s);
+    unlock_user(s, arg1, 0);
+
+    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
+        abi_ulong *arg_ptr, arg_addr;
+
+	arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
+        if (!arg_ptr)
+            return;
+	arg_addr = tswapl(*arg_ptr);
+	unlock_user(arg_ptr, arg_ptr_addr, 0);
+        if (!arg_addr)
+            break;
+        if ((s = lock_user_string(arg_addr))) {
+            gemu_log("\"%s\",", s);
+            unlock_user(s, arg_addr, 0);
+        }
+    }
+
+    gemu_log("NULL})");
+}
+
+#ifdef TARGET_NR_ipc
+static void
+print_ipc(const struct syscallname *name,
+          abi_long arg1, abi_long arg2, abi_long arg3,
+          abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    switch(arg1) {
+    case IPCOP_semctl:
+        gemu_log("semctl(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", arg1, arg2);
+        print_ipc_cmd(arg3);
+        gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
+        break;
+    default:
+        gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")",
+                 name->name, arg1, arg2, arg3, arg4);
+    }
+}
+#endif
+
+/*
+ * Variants for the return value output function
+ */
+
+static void
+print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
+{
+if( ret == -1 ) {
+        gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
+    } else {
+        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
+    }
+}
+
+#if 0 /* currently unused */
+static void
+print_syscall_ret_raw(struct syscallname *name, abi_long ret)
+{
+        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
+}
+#endif
+
+#ifdef TARGET_NR__newselect
+static void
+print_syscall_ret_newselect(const struct syscallname *name, abi_long ret)
+{
+    gemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret);
+    print_fdset(newselect_arg1,newselect_arg2);
+    gemu_log(",");
+    print_fdset(newselect_arg1,newselect_arg3);
+    gemu_log(",");
+    print_fdset(newselect_arg1,newselect_arg4);
+    gemu_log(",");
+    print_timeval(newselect_arg5, 1);
+    gemu_log(")\n");
+}
+#endif
+
+UNUSED static struct flags access_flags[] = {
+    FLAG_GENERIC(F_OK),
+    FLAG_GENERIC(R_OK),
+    FLAG_GENERIC(W_OK),
+    FLAG_GENERIC(X_OK),
+    FLAG_END,
+};
+
+UNUSED static struct flags at_file_flags[] = {
+#ifdef AT_EACCESS
+    FLAG_GENERIC(AT_EACCESS),
+#endif
+#ifdef AT_SYMLINK_NOFOLLOW
+    FLAG_GENERIC(AT_SYMLINK_NOFOLLOW),
+#endif
+    FLAG_END,
+};
+
+UNUSED static struct flags unlinkat_flags[] = {
+#ifdef AT_REMOVEDIR
+    FLAG_GENERIC(AT_REMOVEDIR),
+#endif
+    FLAG_END,
+};
+
+UNUSED static struct flags mode_flags[] = {
+    FLAG_GENERIC(S_IFSOCK),
+    FLAG_GENERIC(S_IFLNK),
+    FLAG_GENERIC(S_IFREG),
+    FLAG_GENERIC(S_IFBLK),
+    FLAG_GENERIC(S_IFDIR),
+    FLAG_GENERIC(S_IFCHR),
+    FLAG_GENERIC(S_IFIFO),
+    FLAG_END,
+};
+
+UNUSED static struct flags open_access_flags[] = {
+    FLAG_TARGET(O_RDONLY),
+    FLAG_TARGET(O_WRONLY),
+    FLAG_TARGET(O_RDWR),
+    FLAG_END,
+};
+
+UNUSED static struct flags open_flags[] = {
+    FLAG_TARGET(O_APPEND),
+    FLAG_TARGET(O_CREAT),
+    FLAG_TARGET(O_DIRECTORY),
+    FLAG_TARGET(O_EXCL),
+    FLAG_TARGET(O_LARGEFILE),
+    FLAG_TARGET(O_NOCTTY),
+    FLAG_TARGET(O_NOFOLLOW),
+    FLAG_TARGET(O_NONBLOCK),      /* also O_NDELAY */
+    FLAG_TARGET(O_SYNC),
+    FLAG_TARGET(O_TRUNC),
+#ifdef O_DIRECT
+    FLAG_TARGET(O_DIRECT),
+#endif
+    FLAG_END,
+};
+
+UNUSED static struct flags mount_flags[] = {
+#ifdef MS_BIND
+    FLAG_GENERIC(MS_BIND),
+#endif
+#ifdef MS_DIRSYNC
+    FLAG_GENERIC(MS_DIRSYNC),
+#endif
+    FLAG_GENERIC(MS_MANDLOCK),
+#ifdef MS_MOVE
+    FLAG_GENERIC(MS_MOVE),
+#endif
+    FLAG_GENERIC(MS_NOATIME),
+    FLAG_GENERIC(MS_NODEV),
+    FLAG_GENERIC(MS_NODIRATIME),
+    FLAG_GENERIC(MS_NOEXEC),
+    FLAG_GENERIC(MS_NOSUID),
+    FLAG_GENERIC(MS_RDONLY),
+#ifdef MS_RELATIME
+    FLAG_GENERIC(MS_RELATIME),
+#endif
+    FLAG_GENERIC(MS_REMOUNT),
+    FLAG_GENERIC(MS_SYNCHRONOUS),
+    FLAG_END,
+};
+
+UNUSED static struct flags umount2_flags[] = {
+#ifdef MNT_FORCE
+    FLAG_GENERIC(MNT_FORCE),
+#endif
+#ifdef MNT_DETACH
+    FLAG_GENERIC(MNT_DETACH),
+#endif
+#ifdef MNT_EXPIRE
+    FLAG_GENERIC(MNT_EXPIRE),
+#endif
+    FLAG_END,
+};
+
+UNUSED static struct flags mmap_prot_flags[] = {
+    FLAG_GENERIC(PROT_NONE),
+    FLAG_GENERIC(PROT_EXEC),
+    FLAG_GENERIC(PROT_READ),
+    FLAG_GENERIC(PROT_WRITE),
+    FLAG_TARGET(PROT_SEM),
+    FLAG_GENERIC(PROT_GROWSDOWN),
+    FLAG_GENERIC(PROT_GROWSUP),
+    FLAG_END,
+};
+
+UNUSED static struct flags mmap_flags[] = {
+    FLAG_TARGET(MAP_SHARED),
+    FLAG_TARGET(MAP_PRIVATE),
+    FLAG_TARGET(MAP_ANONYMOUS),
+    FLAG_TARGET(MAP_DENYWRITE),
+    FLAG_TARGET(MAP_FIXED),
+    FLAG_TARGET(MAP_GROWSDOWN),
+    FLAG_TARGET(MAP_EXECUTABLE),
+#ifdef MAP_LOCKED
+    FLAG_TARGET(MAP_LOCKED),
+#endif
+#ifdef MAP_NONBLOCK
+    FLAG_TARGET(MAP_NONBLOCK),
+#endif
+    FLAG_TARGET(MAP_NORESERVE),
+#ifdef MAP_POPULATE
+    FLAG_TARGET(MAP_POPULATE),
+#endif
+#ifdef TARGET_MAP_UNINITIALIZED
+    FLAG_TARGET(MAP_UNINITIALIZED),
+#endif
+    FLAG_END,
+};
+
+UNUSED static struct flags fcntl_flags[] = {
+    FLAG_TARGET(F_DUPFD),
+    FLAG_TARGET(F_GETFD),
+    FLAG_TARGET(F_SETFD),
+    FLAG_TARGET(F_GETFL),
+    FLAG_TARGET(F_SETFL),
+    FLAG_TARGET(F_GETLK),
+    FLAG_TARGET(F_SETLK),
+    FLAG_TARGET(F_SETLKW),
+    FLAG_END,
+};
+
+UNUSED static struct flags clone_flags[] = {
+    FLAG_GENERIC(CLONE_VM),
+    FLAG_GENERIC(CLONE_FS),
+    FLAG_GENERIC(CLONE_FILES),
+    FLAG_GENERIC(CLONE_SIGHAND),
+    FLAG_GENERIC(CLONE_PTRACE),
+    FLAG_GENERIC(CLONE_VFORK),
+    FLAG_GENERIC(CLONE_PARENT),
+    FLAG_GENERIC(CLONE_THREAD),
+    FLAG_GENERIC(CLONE_NEWNS),
+    FLAG_GENERIC(CLONE_SYSVSEM),
+    FLAG_GENERIC(CLONE_SETTLS),
+    FLAG_GENERIC(CLONE_PARENT_SETTID),
+    FLAG_GENERIC(CLONE_CHILD_CLEARTID),
+    FLAG_GENERIC(CLONE_DETACHED),
+    FLAG_GENERIC(CLONE_UNTRACED),
+    FLAG_GENERIC(CLONE_CHILD_SETTID),
+#if defined(CLONE_NEWUTS)
+    FLAG_GENERIC(CLONE_NEWUTS),
+#endif
+#if defined(CLONE_NEWIPC)
+    FLAG_GENERIC(CLONE_NEWIPC),
+#endif
+#if defined(CLONE_NEWUSER)
+    FLAG_GENERIC(CLONE_NEWUSER),
+#endif
+#if defined(CLONE_NEWPID)
+    FLAG_GENERIC(CLONE_NEWPID),
+#endif
+#if defined(CLONE_NEWNET)
+    FLAG_GENERIC(CLONE_NEWNET),
+#endif
+#if defined(CLONE_IO)
+    FLAG_GENERIC(CLONE_IO),
+#endif
+    FLAG_END,
+};
+
+/*
+ * print_xxx utility functions.  These are used to print syscall
+ * parameters in certain format.  All of these have parameter
+ * named 'last'.  This parameter is used to add comma to output
+ * when last == 0.
+ */
+
+static const char *
+get_comma(int last)
+{
+    return ((last) ? "" : ",");
+}
+
+static void
+print_flags(const struct flags *f, abi_long flags, int last)
+{
+    const char *sep = "";
+    int n;
+
+    if ((flags == 0) && (f->f_value == 0)) {
+        gemu_log("%s%s", f->f_string, get_comma(last));
+        return;
+    }
+    for (n = 0; f->f_string != NULL; f++) {
+        if ((f->f_value != 0) && ((flags & f->f_value) == f->f_value)) {
+            gemu_log("%s%s", sep, f->f_string);
+            flags &= ~f->f_value;
+            sep = "|";
+            n++;
+        }
+    }
+
+    if (n > 0) {
+        /* print rest of the flags as numeric */
+        if (flags != 0) {
+            gemu_log("%s%#x%s", sep, (unsigned int)flags, get_comma(last));
+        } else {
+            gemu_log("%s", get_comma(last));
+        }
+    } else {
+        /* no string version of flags found, print them in hex then */
+        gemu_log("%#x%s", (unsigned int)flags, get_comma(last));
+    }
+}
+
+static void
+print_at_dirfd(abi_long dirfd, int last)
+{
+#ifdef AT_FDCWD
+    if (dirfd == AT_FDCWD) {
+        gemu_log("AT_FDCWD%s", get_comma(last));
+        return;
+    }
+#endif
+    gemu_log("%d%s", (int)dirfd, get_comma(last));
+}
+
+static void
+print_file_mode(abi_long mode, int last)
+{
+    const char *sep = "";
+    const struct flags *m;
+
+    for (m = &mode_flags[0]; m->f_string != NULL; m++) {
+        if ((m->f_value & mode) == m->f_value) {
+            gemu_log("%s%s", m->f_string, sep);
+            sep = "|";
+            mode &= ~m->f_value;
+            break;
+        }
+    }
+
+    mode &= ~S_IFMT;
+    /* print rest of the mode as octal */
+    if (mode != 0)
+        gemu_log("%s%#o", sep, (unsigned int)mode);
+
+    gemu_log("%s", get_comma(last));
+}
+
+static void
+print_open_flags(abi_long flags, int last)
+{
+    print_flags(open_access_flags, flags & TARGET_O_ACCMODE, 1);
+    flags &= ~TARGET_O_ACCMODE;
+    if (flags == 0) {
+        gemu_log("%s", get_comma(last));
+        return;
+    }
+    gemu_log("|");
+    print_flags(open_flags, flags, last);
+}
+
+static void
+print_syscall_prologue(const struct syscallname *sc)
+{
+    gemu_log("%s(", sc->name);
+}
+
+/*ARGSUSED*/
+static void
+print_syscall_epilogue(const struct syscallname *sc)
+{
+    (void)sc;
+    gemu_log(")");
+}
+
+static void
+print_string(abi_long addr, int last)
+{
+    char *s;
+
+    if ((s = lock_user_string(addr)) != NULL) {
+        gemu_log("\"%s\"%s", s, get_comma(last));
+        unlock_user(s, addr, 0);
+    } else {
+        /* can't get string out of it, so print it as pointer */
+        print_pointer(addr, last);
+    }
+}
+
+/*
+ * Prints out raw parameter using given format.  Caller needs
+ * to do byte swapping if needed.
+ */
+static void
+print_raw_param(const char *fmt, abi_long param, int last)
+{
+    char format[64];
+
+    (void) snprintf(format, sizeof (format), "%s%s", fmt, get_comma(last));
+    gemu_log(format, param);
+}
+
+static void
+print_pointer(abi_long p, int last)
+{
+    if (p == 0)
+        gemu_log("NULL%s", get_comma(last));
+    else
+        gemu_log("0x" TARGET_ABI_FMT_lx "%s", p, get_comma(last));
+}
+
+/*
+ * Reads 32-bit (int) number from guest address space from
+ * address 'addr' and prints it.
+ */
+static void
+print_number(abi_long addr, int last)
+{
+    if (addr == 0) {
+        gemu_log("NULL%s", get_comma(last));
+    } else {
+        int num;
+
+        get_user_s32(num, addr);
+        gemu_log("[%d]%s", num, get_comma(last));
+    }
+}
+
+static void
+print_timeval(abi_ulong tv_addr, int last)
+{
+    if( tv_addr ) {
+        struct target_timeval *tv;
+
+        tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1);
+        if (!tv)
+            return;
+        gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}%s",
+            tv->tv_sec, tv->tv_usec, get_comma(last));
+        unlock_user(tv, tv_addr, 0);
+    } else
+        gemu_log("NULL%s", get_comma(last));
+}
+
+#undef UNUSED
+
+#ifdef TARGET_NR_accept
+static void
+print_accept(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_pointer(arg1, 0);
+    print_number(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_access
+static void
+print_access(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_flags(access_flags, arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_brk
+static void
+print_brk(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_pointer(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_chdir
+static void
+print_chdir(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_chmod
+static void
+print_chmod(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_file_mode(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_clone
+static void
+print_clone(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+#if defined(TARGET_M68K)
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("newsp=0x" TARGET_ABI_FMT_lx, arg1, 1);
+#elif defined(TARGET_SH4) || defined(TARGET_ALPHA)
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#elif defined(TARGET_CRIS)
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg0, 0);
+    print_flags(clone_flags, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#else
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#endif
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_creat
+static void
+print_creat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_file_mode(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_execv
+static void
+print_execv(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_raw_param("0x" TARGET_ABI_FMT_lx, arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_faccessat
+static void
+print_faccessat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_flags(access_flags, arg2, 0);
+    print_flags(at_file_flags, arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_fchmodat
+static void
+print_fchmodat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_file_mode(arg2, 0);
+    print_flags(at_file_flags, arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_fchownat
+static void
+print_fchownat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_raw_param("%d", arg2, 0);
+    print_raw_param("%d", arg3, 0);
+    print_flags(at_file_flags, arg4, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#if defined(TARGET_NR_fcntl) || defined(TARGET_NR_fcntl64)
+static void
+print_fcntl(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_flags(fcntl_flags, arg1, 0);
+    /*
+     * TODO: check flags and print following argument only
+     *       when needed.
+     */
+    print_pointer(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#define print_fcntl64   print_fcntl
+#endif
+
+
+#ifdef TARGET_NR_futimesat
+static void
+print_futimesat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_timeval(arg2, 0);
+    print_timeval(arg2 + sizeof (struct target_timeval), 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_link
+static void
+print_link(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_string(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_linkat
+static void
+print_linkat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_at_dirfd(arg2, 0);
+    print_string(arg3, 0);
+    print_flags(at_file_flags, arg4, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR__llseek
+static void
+print__llseek(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    const char *whence = "UNKNOWN";
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_raw_param("%ld", arg1, 0);
+    print_raw_param("%ld", arg2, 0);
+    print_pointer(arg3, 0);
+    switch(arg4) {
+    case SEEK_SET: whence = "SEEK_SET"; break;
+    case SEEK_CUR: whence = "SEEK_CUR"; break;
+    case SEEK_END: whence = "SEEK_END"; break;
+    }
+    gemu_log("%s",whence);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \
+    defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64)
+static void
+print_stat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_pointer(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#define print_lstat     print_stat
+#define print_stat64	print_stat
+#define print_lstat64   print_stat
+#endif
+
+#if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
+static void
+print_fstat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_pointer(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#define print_fstat64     print_fstat
+#endif
+
+#ifdef TARGET_NR_mkdir
+static void
+print_mkdir(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_file_mode(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mkdirat
+static void
+print_mkdirat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_file_mode(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_rmdir
+static void
+print_rmdir(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_rt_sigaction
+static void
+print_rt_sigaction(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_signal(arg0, 0);
+    print_pointer(arg1, 0);
+    print_pointer(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_rt_sigprocmask
+static void
+print_rt_sigprocmask(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    const char *how = "UNKNOWN";
+    print_syscall_prologue(name);
+    switch(arg0) {
+    case TARGET_SIG_BLOCK: how = "SIG_BLOCK"; break;
+    case TARGET_SIG_UNBLOCK: how = "SIG_UNBLOCK"; break;
+    case TARGET_SIG_SETMASK: how = "SIG_SETMASK"; break;
+    }
+    gemu_log("%s,",how);
+    print_pointer(arg1, 0);
+    print_pointer(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mknod
+static void
+print_mknod(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    int hasdev = (arg1 & (S_IFCHR|S_IFBLK));
+
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_file_mode(arg1, (hasdev == 0));
+    if (hasdev) {
+        print_raw_param("makedev(%d", major(arg2), 0);
+        print_raw_param("%d)", minor(arg2), 1);
+    }
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mknodat
+static void
+print_mknodat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    int hasdev = (arg2 & (S_IFCHR|S_IFBLK));
+
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_file_mode(arg2, (hasdev == 0));
+    if (hasdev) {
+        print_raw_param("makedev(%d", major(arg3), 0);
+        print_raw_param("%d)", minor(arg3), 1);
+    }
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mq_open
+static void
+print_mq_open(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    int is_creat = (arg1 & TARGET_O_CREAT);
+
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_open_flags(arg1, (is_creat == 0));
+    if (is_creat) {
+        print_file_mode(arg2, 0);
+        print_pointer(arg3, 1);
+    }
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_open
+static void
+print_open(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    int is_creat = (arg1 & TARGET_O_CREAT);
+
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_open_flags(arg1, (is_creat == 0));
+    if (is_creat)
+        print_file_mode(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_openat
+static void
+print_openat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    int is_creat = (arg2 & TARGET_O_CREAT);
+
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_open_flags(arg2, (is_creat == 0));
+    if (is_creat)
+        print_file_mode(arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mq_unlink
+static void
+print_mq_unlink(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#if defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)
+static void
+print_fstatat64(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_pointer(arg2, 0);
+    print_flags(at_file_flags, arg3, 1);
+    print_syscall_epilogue(name);
+}
+#define print_newfstatat    print_fstatat64
+#endif
+
+#ifdef TARGET_NR_readlink
+static void
+print_readlink(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_pointer(arg1, 0);
+    print_raw_param("%u", arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_readlinkat
+static void
+print_readlinkat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_pointer(arg2, 0);
+    print_raw_param("%u", arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_rename
+static void
+print_rename(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_string(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_renameat
+static void
+print_renameat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_at_dirfd(arg2, 0);
+    print_string(arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_statfs
+static void
+print_statfs(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_pointer(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#define print_statfs64  print_statfs
+#endif
+
+#ifdef TARGET_NR_symlink
+static void
+print_symlink(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_string(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_symlinkat
+static void
+print_symlinkat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_at_dirfd(arg1, 0);
+    print_string(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_mount
+static void
+print_mount(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_string(arg1, 0);
+    print_string(arg2, 0);
+    print_flags(mount_flags, arg3, 0);
+    print_pointer(arg4, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_umount
+static void
+print_umount(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_umount2
+static void
+print_umount2(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_flags(umount2_flags, arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_unlink
+static void
+print_unlink(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_unlinkat
+static void
+print_unlinkat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_flags(unlinkat_flags, arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_utime
+static void
+print_utime(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_pointer(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_utimes
+static void
+print_utimes(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 0);
+    print_pointer(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_utimensat
+static void
+print_utimensat(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_at_dirfd(arg0, 0);
+    print_string(arg1, 0);
+    print_pointer(arg2, 0);
+    print_flags(at_file_flags, arg3, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2)
+static void
+print_mmap(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_pointer(arg0, 0);
+    print_raw_param("%d", arg1, 0);
+    print_flags(mmap_prot_flags, arg2, 0);
+    print_flags(mmap_flags, arg3, 0);
+    print_raw_param("%d", arg4, 0);
+    print_raw_param("%#x", arg5, 1);
+    print_syscall_epilogue(name);
+}
+#define print_mmap2     print_mmap
+#endif
+
+#ifdef TARGET_NR_mprotect
+static void
+print_mprotect(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_pointer(arg0, 0);
+    print_raw_param("%d", arg1, 0);
+    print_flags(mmap_prot_flags, arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_munmap
+static void
+print_munmap(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_pointer(arg0, 0);
+    print_raw_param("%d", arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_futex
+static void print_futex_op(abi_long tflag, int last)
+{
+#define print_op(val) \
+if( cmd == val ) { \
+    gemu_log(#val); \
+    return; \
+}
+
+    int cmd = (int)tflag;
+#ifdef FUTEX_PRIVATE_FLAG
+    if (cmd & FUTEX_PRIVATE_FLAG) {
+        gemu_log("FUTEX_PRIVATE_FLAG|");
+        cmd &= ~FUTEX_PRIVATE_FLAG;
+    }
+#endif
+    print_op(FUTEX_WAIT)
+    print_op(FUTEX_WAKE)
+    print_op(FUTEX_FD)
+    print_op(FUTEX_REQUEUE)
+    print_op(FUTEX_CMP_REQUEUE)
+    print_op(FUTEX_WAKE_OP)
+    print_op(FUTEX_LOCK_PI)
+    print_op(FUTEX_UNLOCK_PI)
+    print_op(FUTEX_TRYLOCK_PI)
+#ifdef FUTEX_WAIT_BITSET
+    print_op(FUTEX_WAIT_BITSET)
+#endif
+#ifdef FUTEX_WAKE_BITSET
+    print_op(FUTEX_WAKE_BITSET)
+#endif
+    /* unknown values */
+    gemu_log("%d",cmd);
+}
+
+static void
+print_futex(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_pointer(arg0, 0);
+    print_futex_op(arg1, 0);
+    print_raw_param(",%d", arg2, 0);
+    print_pointer(arg3, 0); /* struct timespec */
+    print_pointer(arg4, 0);
+    print_raw_param("%d", arg4, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_kill
+static void
+print_kill(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_signal(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+/*
+ * An array of all of the syscalls we know about
+ */
+
+static const struct syscallname scnames[] = {
+#include "strace.list"
+};
+
+static int nsyscalls = ARRAY_SIZE(scnames);
+
+/*
+ * The public interface to this module.
+ */
+void
+print_syscall(int num,
+              abi_long arg1, abi_long arg2, abi_long arg3,
+              abi_long arg4, abi_long arg5, abi_long arg6)
+{
+    int i;
+    const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")";
+
+    gemu_log("%d ", getpid() );
+
+    for(i=0;i<nsyscalls;i++)
+        if( scnames[i].nr == num ) {
+            if( scnames[i].call != NULL ) {
+                scnames[i].call(&scnames[i],arg1,arg2,arg3,arg4,arg5,arg6);
+            } else {
+                /* XXX: this format system is broken because it uses
+                   host types and host pointers for strings */
+                if( scnames[i].format != NULL )
+                    format = scnames[i].format;
+                gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6);
+            }
+            return;
+        }
+    gemu_log("Unknown syscall %d\n", num);
+}
+
+
+void
+print_syscall_ret(int num, abi_long ret)
+{
+    int i;
+
+    for(i=0;i<nsyscalls;i++)
+        if( scnames[i].nr == num ) {
+            if( scnames[i].result != NULL ) {
+                scnames[i].result(&scnames[i],ret);
+            } else {
+                if( ret < 0 ) {
+                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret));
+                } else {
+                    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
+                }
+            }
+            break;
+        }
+}
diff --git a/qemu-0.15.x/linux-user/strace.list b/qemu-0.15.x/linux-user/strace.list
new file mode 100644
index 0000000..a7eeaef
--- /dev/null
+++ b/qemu-0.15.x/linux-user/strace.list
@@ -0,0 +1,1529 @@
+/*
+ * Note that if you change format strings in these, check also
+ * that corresponding print functions are able to handle string
+ * locking correctly (see strace.c).
+ */
+#ifdef TARGET_NR_accept
+{ TARGET_NR_accept, "accept" , NULL, print_accept, NULL },
+#endif
+#ifdef TARGET_NR_access
+{ TARGET_NR_access, "access" , NULL, print_access, NULL },
+#endif
+#ifdef TARGET_NR_acct
+{ TARGET_NR_acct, "acct" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_add_key
+{ TARGET_NR_add_key, "add_key" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_adjtimex
+{ TARGET_NR_adjtimex, "adjtimex" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_afs_syscall
+{ TARGET_NR_afs_syscall, "afs_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_alarm
+{ TARGET_NR_alarm, "alarm" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_aplib
+{ TARGET_NR_aplib, "aplib" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_arch_prctl
+{ TARGET_NR_arch_prctl, "arch_prctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_arm_fadvise64_64
+{ TARGET_NR_arm_fadvise64_64, "arm_fadvise64_64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_bdflush
+{ TARGET_NR_bdflush, "bdflush" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_bind
+{ TARGET_NR_bind, "bind" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_break
+{ TARGET_NR_break, "break" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_brk
+{ TARGET_NR_brk, "brk" , NULL, print_brk, print_syscall_ret_addr },
+#endif
+#ifdef TARGET_NR_cachectl
+{ TARGET_NR_cachectl, "cachectl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_cacheflush
+{ TARGET_NR_cacheflush, "cacheflush" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_capget
+{ TARGET_NR_capget, "capget" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_capset
+{ TARGET_NR_capset, "capset" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_chdir
+{ TARGET_NR_chdir, "chdir" , NULL, print_chdir, NULL },
+#endif
+#ifdef TARGET_NR_chmod
+{ TARGET_NR_chmod, "chmod" , NULL, print_chmod, NULL },
+#endif
+#ifdef TARGET_NR_chown
+{ TARGET_NR_chown, "chown" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_chown32
+{ TARGET_NR_chown32, "chown32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_chroot
+{ TARGET_NR_chroot, "chroot" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_clock_getres
+{ TARGET_NR_clock_getres, "clock_getres" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_clock_gettime
+{ TARGET_NR_clock_gettime, "clock_gettime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_clock_nanosleep
+{ TARGET_NR_clock_nanosleep, "clock_nanosleep" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_clock_settime
+{ TARGET_NR_clock_settime, "clock_settime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_clone
+{ TARGET_NR_clone, "clone" , NULL, print_clone, NULL },
+#endif
+#ifdef TARGET_NR_close
+{ TARGET_NR_close, "close" , "%s(%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_connect
+{ TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_creat
+{ TARGET_NR_creat, "creat" , NULL, print_creat, NULL },
+#endif
+#ifdef TARGET_NR_create_module
+{ TARGET_NR_create_module, "create_module" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_delete_module
+{ TARGET_NR_delete_module, "delete_module" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_dipc
+{ TARGET_NR_dipc, "dipc" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_dup
+{ TARGET_NR_dup, "dup" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_dup2
+{ TARGET_NR_dup2, "dup2" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_epoll_create
+{ TARGET_NR_epoll_create, "epoll_create" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_epoll_ctl
+{ TARGET_NR_epoll_ctl, "epoll_ctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_epoll_ctl_old
+{ TARGET_NR_epoll_ctl_old, "epoll_ctl_old" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_epoll_wait
+{ TARGET_NR_epoll_wait, "epoll_wait" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_epoll_wait_old
+{ TARGET_NR_epoll_wait_old, "epoll_wait_old" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_execv
+{ TARGET_NR_execv, "execv" , NULL, print_execv, NULL },
+#endif
+#ifdef TARGET_NR_execve
+{ TARGET_NR_execve, "execve" , NULL, print_execve, NULL },
+#endif
+#ifdef TARGET_NR_exec_with_loader
+{ TARGET_NR_exec_with_loader, "exec_with_loader" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_exit
+{ TARGET_NR_exit, "exit" , "%s(%d)\n", NULL, NULL },
+#endif
+#ifdef TARGET_NR__exit
+{ TARGET_NR__exit, "_exit" , "%s(%d)\n", NULL, NULL },
+#endif
+#ifdef TARGET_NR_exit_group
+{ TARGET_NR_exit_group, "exit_group" , "%s(%d)\n", NULL, NULL },
+#endif
+#ifdef TARGET_NR_faccessat
+{ TARGET_NR_faccessat, "faccessat" , NULL, print_faccessat, NULL },
+#endif
+#ifdef TARGET_NR_fadvise64
+{ TARGET_NR_fadvise64, "fadvise64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fadvise64_64
+{ TARGET_NR_fadvise64_64, "fadvise64_64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fchdir
+{ TARGET_NR_fchdir, "fchdir" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fchmod
+{ TARGET_NR_fchmod, "fchmod" , "%s(%d,%#o)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fchmodat
+{ TARGET_NR_fchmodat, "fchmodat" , NULL, print_fchmodat, NULL },
+#endif
+#ifdef TARGET_NR_fchown
+{ TARGET_NR_fchown, "fchown" , "%s(%d,%d,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fchown32
+{ TARGET_NR_fchown32, "fchown32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fchownat
+{ TARGET_NR_fchownat, "fchownat" , NULL, print_fchownat, NULL },
+#endif
+#ifdef TARGET_NR_fcntl
+{ TARGET_NR_fcntl, "fcntl" , NULL, print_fcntl, NULL },
+#endif
+#ifdef TARGET_NR_fcntl64
+{ TARGET_NR_fcntl64, "fcntl64" , NULL, print_fcntl64, NULL },
+#endif
+#ifdef TARGET_NR_fdatasync
+{ TARGET_NR_fdatasync, "fdatasync" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fgetxattr
+{ TARGET_NR_fgetxattr, "fgetxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_flistxattr
+{ TARGET_NR_flistxattr, "flistxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_flock
+{ TARGET_NR_flock, "flock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fork
+{ TARGET_NR_fork, "fork" , "%s()", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fremovexattr
+{ TARGET_NR_fremovexattr, "fremovexattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fsetxattr
+{ TARGET_NR_fsetxattr, "fsetxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fstat
+{ TARGET_NR_fstat, "fstat" , NULL, print_fstat, NULL },
+#endif
+#ifdef TARGET_NR_fstat64
+{ TARGET_NR_fstat64, "fstat64" , NULL, print_fstat64, NULL },
+#endif
+#ifdef TARGET_NR_fstatfs
+{ TARGET_NR_fstatfs, "fstatfs" , "%s(%d,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fstatfs64
+{ TARGET_NR_fstatfs64, "fstatfs64" , "%s(%d,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fsync
+{ TARGET_NR_fsync, "fsync" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ftime
+{ TARGET_NR_ftime, "ftime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ftruncate
+{ TARGET_NR_ftruncate, "ftruncate" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ftruncate64
+{ TARGET_NR_ftruncate64, "ftruncate64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_futex
+{ TARGET_NR_futex, "futex" , NULL, print_futex, NULL },
+#endif
+#ifdef TARGET_NR_futimesat
+{ TARGET_NR_futimesat, "futimesat" , NULL, print_futimesat, NULL },
+#endif
+#ifdef TARGET_NR_getcwd
+{ TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_getdents
+{ TARGET_NR_getdents, "getdents" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getdents64
+{ TARGET_NR_getdents64, "getdents64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getdomainname
+{ TARGET_NR_getdomainname, "getdomainname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getdtablesize
+{ TARGET_NR_getdtablesize, "getdtablesize" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getegid
+{ TARGET_NR_getegid, "getegid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getegid32
+{ TARGET_NR_getegid32, "getegid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_geteuid
+{ TARGET_NR_geteuid, "geteuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_geteuid32
+{ TARGET_NR_geteuid32, "geteuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getgid
+{ TARGET_NR_getgid, "getgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getgid32
+{ TARGET_NR_getgid32, "getgid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getgroups
+{ TARGET_NR_getgroups, "getgroups" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getgroups32
+{ TARGET_NR_getgroups32, "getgroups32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_gethostname
+{ TARGET_NR_gethostname, "gethostname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getitimer
+{ TARGET_NR_getitimer, "getitimer" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_get_kernel_syms
+{ TARGET_NR_get_kernel_syms, "get_kernel_syms" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_get_mempolicy
+{ TARGET_NR_get_mempolicy, "get_mempolicy" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpagesize
+{ TARGET_NR_getpagesize, "getpagesize" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpeername
+{ TARGET_NR_getpeername, "getpeername" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpgid
+{ TARGET_NR_getpgid, "getpgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpgrp
+{ TARGET_NR_getpgrp, "getpgrp" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpid
+{ TARGET_NR_getpid, "getpid" , "%s()", NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpmsg
+{ TARGET_NR_getpmsg, "getpmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getppid
+{ TARGET_NR_getppid, "getppid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getpriority
+{ TARGET_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_getresgid
+{ TARGET_NR_getresgid, "getresgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getresgid32
+{ TARGET_NR_getresgid32, "getresgid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getresuid
+{ TARGET_NR_getresuid, "getresuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getresuid32
+{ TARGET_NR_getresuid32, "getresuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getrlimit
+{ TARGET_NR_getrlimit, "getrlimit" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_get_robust_list
+{ TARGET_NR_get_robust_list, "get_robust_list" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getrusage
+{ TARGET_NR_getrusage, "getrusage" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getsid
+{ TARGET_NR_getsid, "getsid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getsockname
+{ TARGET_NR_getsockname, "getsockname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getsockopt
+{ TARGET_NR_getsockopt, "getsockopt" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_get_thread_area
+{ TARGET_NR_get_thread_area, "get_thread_area" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_gettid
+{ TARGET_NR_gettid, "gettid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_gettimeofday
+{ TARGET_NR_gettimeofday, "gettimeofday" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getuid
+{ TARGET_NR_getuid, "getuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getuid32
+{ TARGET_NR_getuid32, "getuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getxattr
+{ TARGET_NR_getxattr, "getxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getxgid
+{ TARGET_NR_getxgid, "getxgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getxpid
+{ TARGET_NR_getxpid, "getxpid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_getxuid
+{ TARGET_NR_getxuid, "getxuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_gtty
+{ TARGET_NR_gtty, "gtty" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_idle
+{ TARGET_NR_idle, "idle" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_init_module
+{ TARGET_NR_init_module, "init_module" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_inotify_add_watch
+{ TARGET_NR_inotify_add_watch, "inotify_add_watch" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_inotify_init
+{ TARGET_NR_inotify_init, "inotify_init" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_inotify_rm_watch
+{ TARGET_NR_inotify_rm_watch, "inotify_rm_watch" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_io_cancel
+{ TARGET_NR_io_cancel, "io_cancel" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ioctl
+{ TARGET_NR_ioctl, "ioctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_io_destroy
+{ TARGET_NR_io_destroy, "io_destroy" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_io_getevents
+{ TARGET_NR_io_getevents, "io_getevents" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ioperm
+{ TARGET_NR_ioperm, "ioperm" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_iopl
+{ TARGET_NR_iopl, "iopl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ioprio_get
+{ TARGET_NR_ioprio_get, "ioprio_get" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ioprio_set
+{ TARGET_NR_ioprio_set, "ioprio_set" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_io_setup
+{ TARGET_NR_io_setup, "io_setup" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_io_submit
+{ TARGET_NR_io_submit, "io_submit" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ipc
+{ TARGET_NR_ipc, "ipc" , NULL, print_ipc, NULL },
+#endif
+#ifdef TARGET_NR_kexec_load
+{ TARGET_NR_kexec_load, "kexec_load" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_keyctl
+{ TARGET_NR_keyctl, "keyctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_kill
+{ TARGET_NR_kill, "kill", NULL, print_kill, NULL },
+#endif
+#ifdef TARGET_NR_lchown
+{ TARGET_NR_lchown, "lchown" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lchown32
+{ TARGET_NR_lchown32, "lchown32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lgetxattr
+{ TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_link
+{ TARGET_NR_link, "link" , NULL, print_link, NULL },
+#endif
+#ifdef TARGET_NR_linkat
+{ TARGET_NR_linkat, "linkat" , NULL, print_linkat, NULL },
+#endif
+#ifdef TARGET_NR_Linux
+{ TARGET_NR_Linux, "Linux" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_listen
+{ TARGET_NR_listen, "listen" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_listxattr
+{ TARGET_NR_listxattr, "listxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_llistxattr
+{ TARGET_NR_llistxattr, "llistxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR__llseek
+{ TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL },
+#endif
+#ifdef TARGET_NR_lock
+{ TARGET_NR_lock, "lock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lookup_dcookie
+{ TARGET_NR_lookup_dcookie, "lookup_dcookie" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lremovexattr
+{ TARGET_NR_lremovexattr, "lremovexattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lseek
+{ TARGET_NR_lseek, "lseek" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lsetxattr
+{ TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_lstat
+{ TARGET_NR_lstat, "lstat" , NULL, print_lstat, NULL },
+#endif
+#ifdef TARGET_NR_lstat64
+{ TARGET_NR_lstat64, "lstat64" , NULL, print_lstat64, NULL },
+#endif
+#ifdef TARGET_NR_madvise
+{ TARGET_NR_madvise, "madvise" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_madvise1
+{ TARGET_NR_madvise1, "madvise1" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mbind
+{ TARGET_NR_mbind, "mbind" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_memory_ordering
+{ TARGET_NR_memory_ordering, "memory_ordering" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_migrate_pages
+{ TARGET_NR_migrate_pages, "migrate_pages" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mincore
+{ TARGET_NR_mincore, "mincore" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mkdir
+{ TARGET_NR_mkdir, "mkdir" , NULL, print_mkdir, NULL },
+#endif
+#ifdef TARGET_NR_mkdirat
+{ TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL },
+#endif
+#ifdef TARGET_NR_rmdir
+{ TARGET_NR_rmdir, "rmdir" , NULL, print_rmdir, NULL },
+#endif
+#ifdef TARGET_NR_mknod
+{ TARGET_NR_mknod, "mknod" , NULL, print_mknod, NULL },
+#endif
+#ifdef TARGET_NR_mknodat
+{ TARGET_NR_mknodat, "mknodat" , NULL, print_mknodat, NULL },
+#endif
+#ifdef TARGET_NR_mlock
+{ TARGET_NR_mlock, "mlock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mlockall
+{ TARGET_NR_mlockall, "mlockall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mmap
+{ TARGET_NR_mmap, "mmap" , NULL, print_mmap, print_syscall_ret_addr },
+#endif
+#ifdef TARGET_NR_mmap2
+{ TARGET_NR_mmap2, "mmap2" , NULL, print_mmap2, print_syscall_ret_addr },
+#endif
+#ifdef TARGET_NR_modify_ldt
+{ TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mount
+{ TARGET_NR_mount, "mount" , NULL, print_mount, NULL },
+#endif
+#ifdef TARGET_NR_move_pages
+{ TARGET_NR_move_pages, "move_pages" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mprotect
+{ TARGET_NR_mprotect, "mprotect" , NULL, print_mprotect, NULL },
+#endif
+#ifdef TARGET_NR_mpx
+{ TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_mq_getsetattr
+{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_mq_notify
+{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_mq_open
+{ TARGET_NR_mq_open, "mq_open" , NULL, print_mq_open, NULL },
+#endif
+#ifdef TARGET_NR_mq_timedreceive
+{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_mq_timedsend
+{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_mq_unlink
+{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, print_mq_unlink, NULL },
+#endif
+#ifdef TARGET_NR_mremap
+{ TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_msgctl
+{ TARGET_NR_msgctl, "msgctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_msgget
+{ TARGET_NR_msgget, "msgget" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_msgrcv
+{ TARGET_NR_msgrcv, "msgrcv" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_msgsnd
+{ TARGET_NR_msgsnd, "msgsnd" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_msync
+{ TARGET_NR_msync, "msync" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_multiplexer
+{ TARGET_NR_multiplexer, "multiplexer" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_munlock
+{ TARGET_NR_munlock, "munlock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_munlockall
+{ TARGET_NR_munlockall, "munlockall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_munmap
+{ TARGET_NR_munmap, "munmap" , NULL, print_munmap, NULL },
+#endif
+#ifdef TARGET_NR_nanosleep
+{ TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_fstatat64
+{ TARGET_NR_fstatat64, "fstatat64" , NULL, print_fstatat64, NULL },
+#endif
+#ifdef TARGET_NR_newfstatat
+{ TARGET_NR_newfstatat, "newfstatat" , NULL, print_newfstatat, NULL },
+#endif
+#ifdef TARGET_NR__newselect
+{ TARGET_NR__newselect, "_newselect" , NULL, print_newselect, print_syscall_ret_newselect },
+#endif
+#ifdef TARGET_NR_nfsservctl
+{ TARGET_NR_nfsservctl, "nfsservctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_nice
+{ TARGET_NR_nice, "nice" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_old_adjtimex
+{ TARGET_NR_old_adjtimex, "old_adjtimex" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_oldfstat
+{ TARGET_NR_oldfstat, "oldfstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_oldlstat
+{ TARGET_NR_oldlstat, "oldlstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_oldolduname
+{ TARGET_NR_oldolduname, "oldolduname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_oldstat
+{ TARGET_NR_oldstat, "oldstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_oldumount
+{ TARGET_NR_oldumount, "oldumount" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_olduname
+{ TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_open
+{ TARGET_NR_open, "open" , NULL, print_open, NULL },
+#endif
+#ifdef TARGET_NR_openat
+{ TARGET_NR_openat, "openat" , NULL, print_openat, NULL },
+#endif
+#ifdef TARGET_NR_osf_adjtime
+{ TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_afs_syscall
+{ TARGET_NR_osf_afs_syscall, "osf_afs_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_alt_plock
+{ TARGET_NR_osf_alt_plock, "osf_alt_plock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_alt_setsid
+{ TARGET_NR_osf_alt_setsid, "osf_alt_setsid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_alt_sigpending
+{ TARGET_NR_osf_alt_sigpending, "osf_alt_sigpending" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_asynch_daemon
+{ TARGET_NR_osf_asynch_daemon, "osf_asynch_daemon" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_audcntl
+{ TARGET_NR_osf_audcntl, "osf_audcntl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_audgen
+{ TARGET_NR_osf_audgen, "osf_audgen" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_chflags
+{ TARGET_NR_osf_chflags, "osf_chflags" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_execve
+{ TARGET_NR_osf_execve, "osf_execve" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_exportfs
+{ TARGET_NR_osf_exportfs, "osf_exportfs" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_fchflags
+{ TARGET_NR_osf_fchflags, "osf_fchflags" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_fdatasync
+{ TARGET_NR_osf_fdatasync, "osf_fdatasync" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_fpathconf
+{ TARGET_NR_osf_fpathconf, "osf_fpathconf" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_fstatfs
+{ TARGET_NR_osf_fstatfs, "osf_fstatfs" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_fuser
+{ TARGET_NR_osf_fuser, "osf_fuser" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getaddressconf
+{ TARGET_NR_osf_getaddressconf, "osf_getaddressconf" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getdirentries
+{ TARGET_NR_osf_getdirentries, "osf_getdirentries" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getdomainname
+{ TARGET_NR_osf_getdomainname, "osf_getdomainname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getfh
+{ TARGET_NR_osf_getfh, "osf_getfh" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getfsstat
+{ TARGET_NR_osf_getfsstat, "osf_getfsstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_gethostid
+{ TARGET_NR_osf_gethostid, "osf_gethostid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getitimer
+{ TARGET_NR_osf_getitimer, "osf_getitimer" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getlogin
+{ TARGET_NR_osf_getlogin, "osf_getlogin" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getmnt
+{ TARGET_NR_osf_getmnt, "osf_getmnt" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getrusage
+{ TARGET_NR_osf_getrusage, "osf_getrusage" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_getsysinfo
+{ TARGET_NR_osf_getsysinfo, "osf_getsysinfo" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_gettimeofday
+{ TARGET_NR_osf_gettimeofday, "osf_gettimeofday" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_kloadcall
+{ TARGET_NR_osf_kloadcall, "osf_kloadcall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_kmodcall
+{ TARGET_NR_osf_kmodcall, "osf_kmodcall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_memcntl
+{ TARGET_NR_osf_memcntl, "osf_memcntl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_mincore
+{ TARGET_NR_osf_mincore, "osf_mincore" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_mount
+{ TARGET_NR_osf_mount, "osf_mount" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_mremap
+{ TARGET_NR_osf_mremap, "osf_mremap" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_msfs_syscall
+{ TARGET_NR_osf_msfs_syscall, "osf_msfs_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_msleep
+{ TARGET_NR_osf_msleep, "osf_msleep" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_mvalid
+{ TARGET_NR_osf_mvalid, "osf_mvalid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_mwakeup
+{ TARGET_NR_osf_mwakeup, "osf_mwakeup" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_naccept
+{ TARGET_NR_osf_naccept, "osf_naccept" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_nfssvc
+{ TARGET_NR_osf_nfssvc, "osf_nfssvc" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_ngetpeername
+{ TARGET_NR_osf_ngetpeername, "osf_ngetpeername" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_ngetsockname
+{ TARGET_NR_osf_ngetsockname, "osf_ngetsockname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_nrecvfrom
+{ TARGET_NR_osf_nrecvfrom, "osf_nrecvfrom" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_nrecvmsg
+{ TARGET_NR_osf_nrecvmsg, "osf_nrecvmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_nsendmsg
+{ TARGET_NR_osf_nsendmsg, "osf_nsendmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_ntp_adjtime
+{ TARGET_NR_osf_ntp_adjtime, "osf_ntp_adjtime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_ntp_gettime
+{ TARGET_NR_osf_ntp_gettime, "osf_ntp_gettime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_creat
+{ TARGET_NR_osf_old_creat, "osf_old_creat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_fstat
+{ TARGET_NR_osf_old_fstat, "osf_old_fstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_getpgrp
+{ TARGET_NR_osf_old_getpgrp, "osf_old_getpgrp" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_killpg
+{ TARGET_NR_osf_old_killpg, "osf_old_killpg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_lstat
+{ TARGET_NR_osf_old_lstat, "osf_old_lstat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_open
+{ TARGET_NR_osf_old_open, "osf_old_open" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_oldquota
+{ TARGET_NR_osf_oldquota, "osf_oldquota" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_sigaction
+{ TARGET_NR_osf_old_sigaction, "osf_old_sigaction" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_sigblock
+{ TARGET_NR_osf_old_sigblock, "osf_old_sigblock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_sigreturn
+{ TARGET_NR_osf_old_sigreturn, "osf_old_sigreturn" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_sigsetmask
+{ TARGET_NR_osf_old_sigsetmask, "osf_old_sigsetmask" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_sigvec
+{ TARGET_NR_osf_old_sigvec, "osf_old_sigvec" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_stat
+{ TARGET_NR_osf_old_stat, "osf_old_stat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_vadvise
+{ TARGET_NR_osf_old_vadvise, "osf_old_vadvise" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_vtrace
+{ TARGET_NR_osf_old_vtrace, "osf_old_vtrace" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_old_wait
+{ TARGET_NR_osf_old_wait, "osf_old_wait" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_pathconf
+{ TARGET_NR_osf_pathconf, "osf_pathconf" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_pid_block
+{ TARGET_NR_osf_pid_block, "osf_pid_block" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_pid_unblock
+{ TARGET_NR_osf_pid_unblock, "osf_pid_unblock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_plock
+{ TARGET_NR_osf_plock, "osf_plock" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_priocntlset
+{ TARGET_NR_osf_priocntlset, "osf_priocntlset" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_profil
+{ TARGET_NR_osf_profil, "osf_profil" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_proplist_syscall
+{ TARGET_NR_osf_proplist_syscall, "osf_proplist_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_reboot
+{ TARGET_NR_osf_reboot, "osf_reboot" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_revoke
+{ TARGET_NR_osf_revoke, "osf_revoke" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sbrk
+{ TARGET_NR_osf_sbrk, "osf_sbrk" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_security
+{ TARGET_NR_osf_security, "osf_security" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_select
+{ TARGET_NR_osf_select, "osf_select" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sethostid
+{ TARGET_NR_osf_sethostid, "osf_sethostid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_setitimer
+{ TARGET_NR_osf_setitimer, "osf_setitimer" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_setlogin
+{ TARGET_NR_osf_setlogin, "osf_setlogin" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_set_program_attributes
+{ TARGET_NR_osf_set_program_attributes, "osf_set_program_attributes" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_set_speculative
+{ TARGET_NR_osf_set_speculative, "osf_set_speculative" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_setsysinfo
+{ TARGET_NR_osf_setsysinfo, "osf_setsysinfo" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_settimeofday
+{ TARGET_NR_osf_settimeofday, "osf_settimeofday" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_shmat
+{ TARGET_NR_osf_shmat, "osf_shmat" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_signal
+{ TARGET_NR_osf_signal, "osf_signal" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sigprocmask
+{ TARGET_NR_osf_sigprocmask, "osf_sigprocmask" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sigsendset
+{ TARGET_NR_osf_sigsendset, "osf_sigsendset" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sigstack
+{ TARGET_NR_osf_sigstack, "osf_sigstack" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sigwaitprim
+{ TARGET_NR_osf_sigwaitprim, "osf_sigwaitprim" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sstk
+{ TARGET_NR_osf_sstk, "osf_sstk" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_statfs
+{ TARGET_NR_osf_statfs, "osf_statfs" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_subsys_info
+{ TARGET_NR_osf_subsys_info, "osf_subsys_info" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_swapctl
+{ TARGET_NR_osf_swapctl, "osf_swapctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_swapon
+{ TARGET_NR_osf_swapon, "osf_swapon" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_syscall
+{ TARGET_NR_osf_syscall, "osf_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_sysinfo
+{ TARGET_NR_osf_sysinfo, "osf_sysinfo" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_table
+{ TARGET_NR_osf_table, "osf_table" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_uadmin
+{ TARGET_NR_osf_uadmin, "osf_uadmin" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_usleep_thread
+{ TARGET_NR_osf_usleep_thread, "osf_usleep_thread" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_uswitch
+{ TARGET_NR_osf_uswitch, "osf_uswitch" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_utc_adjtime
+{ TARGET_NR_osf_utc_adjtime, "osf_utc_adjtime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_utc_gettime
+{ TARGET_NR_osf_utc_gettime, "osf_utc_gettime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_utimes
+{ TARGET_NR_osf_utimes, "osf_utimes" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_utsname
+{ TARGET_NR_osf_utsname, "osf_utsname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_wait4
+{ TARGET_NR_osf_wait4, "osf_wait4" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_osf_waitid
+{ TARGET_NR_osf_waitid, "osf_waitid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pause
+{ TARGET_NR_pause, "pause" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pciconfig_iobase
+{ TARGET_NR_pciconfig_iobase, "pciconfig_iobase" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pciconfig_read
+{ TARGET_NR_pciconfig_read, "pciconfig_read" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pciconfig_write
+{ TARGET_NR_pciconfig_write, "pciconfig_write" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_perfctr
+{ TARGET_NR_perfctr, "perfctr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_personality
+{ TARGET_NR_personality, "personality" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pipe
+{ TARGET_NR_pipe, "pipe" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pivot_root
+{ TARGET_NR_pivot_root, "pivot_root" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_poll
+{ TARGET_NR_poll, "poll" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ppoll
+{ TARGET_NR_ppoll, "ppoll" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_prctl
+{ TARGET_NR_prctl, "prctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pread
+{ TARGET_NR_pread, "pread" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pread64
+{ TARGET_NR_pread64, "pread64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_prof
+{ TARGET_NR_prof, "prof" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_profil
+{ TARGET_NR_profil, "profil" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pselect6
+{ TARGET_NR_pselect6, "pselect6" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ptrace
+{ TARGET_NR_ptrace, "ptrace" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_putpmsg
+{ TARGET_NR_putpmsg, "putpmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pwrite
+{ TARGET_NR_pwrite, "pwrite" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_pwrite64
+{ TARGET_NR_pwrite64, "pwrite64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_query_module
+{ TARGET_NR_query_module, "query_module" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_quotactl
+{ TARGET_NR_quotactl, "quotactl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_read
+{ TARGET_NR_read, "read" , "%s(%d,%#x,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_readahead
+{ TARGET_NR_readahead, "readahead" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_readdir
+{ TARGET_NR_readdir, "readdir" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_readlink
+{ TARGET_NR_readlink, "readlink" , NULL, print_readlink, NULL },
+#endif
+#ifdef TARGET_NR_readlinkat
+{ TARGET_NR_readlinkat, "readlinkat" , NULL, print_readlinkat, NULL },
+#endif
+#ifdef TARGET_NR_readv
+{ TARGET_NR_readv, "readv" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_reboot
+{ TARGET_NR_reboot, "reboot" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_recv
+{ TARGET_NR_recv, "recv" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_recvfrom
+{ TARGET_NR_recvfrom, "recvfrom" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_recvmsg
+{ TARGET_NR_recvmsg, "recvmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_remap_file_pages
+{ TARGET_NR_remap_file_pages, "remap_file_pages" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_removexattr
+{ TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rename
+{ TARGET_NR_rename, "rename" , NULL, print_rename, NULL },
+#endif
+#ifdef TARGET_NR_renameat
+{ TARGET_NR_renameat, "renameat" , NULL, print_renameat, NULL },
+#endif
+#ifdef TARGET_NR_request_key
+{ TARGET_NR_request_key, "request_key" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_reserved221
+{ TARGET_NR_reserved221, "reserved221" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_reserved82
+{ TARGET_NR_reserved82, "reserved82" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_restart_syscall
+{ TARGET_NR_restart_syscall, "restart_syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rmdir
+{ TARGET_NR_rmdir, "rmdir" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigaction
+{ TARGET_NR_rt_sigaction, "rt_sigaction" , NULL, print_rt_sigaction, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigpending
+{ TARGET_NR_rt_sigpending, "rt_sigpending" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigprocmask
+{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigqueueinfo
+{ TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigreturn
+{ TARGET_NR_rt_sigreturn, "rt_sigreturn" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigsuspend
+{ TARGET_NR_rt_sigsuspend, "rt_sigsuspend" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_rt_sigtimedwait
+{ TARGET_NR_rt_sigtimedwait, "rt_sigtimedwait" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_getaffinity
+{ TARGET_NR_sched_getaffinity, "sched_getaffinity" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_get_affinity
+{ TARGET_NR_sched_get_affinity, "sched_get_affinity" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_getparam
+{ TARGET_NR_sched_getparam, "sched_getparam" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_get_priority_max
+{ TARGET_NR_sched_get_priority_max, "sched_get_priority_max" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_get_priority_min
+{ TARGET_NR_sched_get_priority_min, "sched_get_priority_min" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_getscheduler
+{ TARGET_NR_sched_getscheduler, "sched_getscheduler" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_rr_get_interval
+{ TARGET_NR_sched_rr_get_interval, "sched_rr_get_interval" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_setaffinity
+{ TARGET_NR_sched_setaffinity, "sched_setaffinity" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_set_affinity
+{ TARGET_NR_sched_set_affinity, "sched_set_affinity" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_setparam
+{ TARGET_NR_sched_setparam, "sched_setparam" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_setscheduler
+{ TARGET_NR_sched_setscheduler, "sched_setscheduler" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sched_yield
+{ TARGET_NR_sched_yield, "sched_yield" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_security
+{ TARGET_NR_security, "security" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_select
+{ TARGET_NR_select, "select" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_semctl
+{ TARGET_NR_semctl, "semctl" , NULL, print_semctl, NULL },
+#endif
+#ifdef TARGET_NR_semget
+{ TARGET_NR_semget, "semget" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_semop
+{ TARGET_NR_semop, "semop" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_semtimedop
+{ TARGET_NR_semtimedop, "semtimedop" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_send
+{ TARGET_NR_send, "send" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sendfile
+{ TARGET_NR_sendfile, "sendfile" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sendfile64
+{ TARGET_NR_sendfile64, "sendfile64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sendmsg
+{ TARGET_NR_sendmsg, "sendmsg" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sendto
+{ TARGET_NR_sendto, "sendto" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setdomainname
+{ TARGET_NR_setdomainname, "setdomainname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setfsgid
+{ TARGET_NR_setfsgid, "setfsgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setfsgid32
+{ TARGET_NR_setfsgid32, "setfsgid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setfsuid
+{ TARGET_NR_setfsuid, "setfsuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setfsuid32
+{ TARGET_NR_setfsuid32, "setfsuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setgid
+{ TARGET_NR_setgid, "setgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setgid32
+{ TARGET_NR_setgid32, "setgid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setgroups
+{ TARGET_NR_setgroups, "setgroups" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setgroups32
+{ TARGET_NR_setgroups32, "setgroups32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sethae
+{ TARGET_NR_sethae, "sethae" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sethostname
+{ TARGET_NR_sethostname, "sethostname" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setitimer
+{ TARGET_NR_setitimer, "setitimer" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_set_mempolicy
+{ TARGET_NR_set_mempolicy, "set_mempolicy" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setpgid
+{ TARGET_NR_setpgid, "setpgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setpgrp
+{ TARGET_NR_setpgrp, "setpgrp" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setpriority
+{ TARGET_NR_setpriority, "setpriority" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setregid
+{ TARGET_NR_setregid, "setregid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setregid32
+{ TARGET_NR_setregid32, "setregid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setresgid
+{ TARGET_NR_setresgid, "setresgid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setresgid32
+{ TARGET_NR_setresgid32, "setresgid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setresuid
+{ TARGET_NR_setresuid, "setresuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setresuid32
+{ TARGET_NR_setresuid32, "setresuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setreuid
+{ TARGET_NR_setreuid, "setreuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setreuid32
+{ TARGET_NR_setreuid32, "setreuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setrlimit
+{ TARGET_NR_setrlimit, "setrlimit" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_set_robust_list
+{ TARGET_NR_set_robust_list, "set_robust_list" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setsid
+{ TARGET_NR_setsid, "setsid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setsockopt
+{ TARGET_NR_setsockopt, "setsockopt" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_set_thread_area
+{ TARGET_NR_set_thread_area, "set_thread_area" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_set_tid_address
+{ TARGET_NR_set_tid_address, "set_tid_address" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_settimeofday
+{ TARGET_NR_settimeofday, "settimeofday" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setuid
+{ TARGET_NR_setuid, "setuid" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setuid32
+{ TARGET_NR_setuid32, "setuid32" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_setxattr
+{ TARGET_NR_setxattr, "setxattr" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sgetmask
+{ TARGET_NR_sgetmask, "sgetmask" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_shmat
+{ TARGET_NR_shmat, "shmat" , NULL, NULL, print_syscall_ret_addr },
+#endif
+#ifdef TARGET_NR_shmctl
+{ TARGET_NR_shmctl, "shmctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_shmdt
+{ TARGET_NR_shmdt, "shmdt" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_shmget
+{ TARGET_NR_shmget, "shmget" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_shutdown
+{ TARGET_NR_shutdown, "shutdown" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigaction
+{ TARGET_NR_sigaction, "sigaction" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigaltstack
+{ TARGET_NR_sigaltstack, "sigaltstack" , "%s(%p,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_signal
+{ TARGET_NR_signal, "signal" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigpending
+{ TARGET_NR_sigpending, "sigpending" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigprocmask
+{ TARGET_NR_sigprocmask, "sigprocmask" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigreturn
+{ TARGET_NR_sigreturn, "sigreturn" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sigsuspend
+{ TARGET_NR_sigsuspend, "sigsuspend" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_socket
+{ TARGET_NR_socket, "socket" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_socketcall
+{ TARGET_NR_socketcall, "socketcall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_socketpair
+{ TARGET_NR_socketpair, "socketpair" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_splice
+{ TARGET_NR_splice, "splice" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ssetmask
+{ TARGET_NR_ssetmask, "ssetmask" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_stat
+{ TARGET_NR_stat, "stat" , NULL, print_stat, NULL },
+#endif
+#ifdef TARGET_NR_stat64
+{ TARGET_NR_stat64, "stat64" , NULL, print_stat64, NULL },
+#endif
+#ifdef TARGET_NR_statfs
+{ TARGET_NR_statfs, "statfs" , NULL, print_statfs, NULL },
+#endif
+#ifdef TARGET_NR_statfs64
+{ TARGET_NR_statfs64, "statfs64" , NULL, print_statfs64, NULL },
+#endif
+#ifdef TARGET_NR_stime
+{ TARGET_NR_stime, "stime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_streams1
+{ TARGET_NR_streams1, "streams1" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_streams2
+{ TARGET_NR_streams2, "streams2" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_stty
+{ TARGET_NR_stty, "stty" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_swapcontext
+{ TARGET_NR_swapcontext, "swapcontext" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_swapoff
+{ TARGET_NR_swapoff, "swapoff" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_swapon
+{ TARGET_NR_swapon, "swapon" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_symlink
+{ TARGET_NR_symlink, "symlink" , NULL, print_symlink, NULL },
+#endif
+#ifdef TARGET_NR_symlinkat
+{ TARGET_NR_symlinkat, "symlinkat", NULL, print_symlinkat, NULL },
+#endif
+#ifdef TARGET_NR_sync
+{ TARGET_NR_sync, "sync" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sync_file_range
+{ TARGET_NR_sync_file_range, "sync_file_range" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_syscall
+{ TARGET_NR_syscall, "syscall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR__sysctl
+{ TARGET_NR__sysctl, "_sysctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sys_epoll_create
+{ TARGET_NR_sys_epoll_create, "sys_epoll_create" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sys_epoll_ctl
+{ TARGET_NR_sys_epoll_ctl, "sys_epoll_ctl" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sys_epoll_wait
+{ TARGET_NR_sys_epoll_wait, "sys_epoll_wait" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sysfs
+{ TARGET_NR_sysfs, "sysfs" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sysinfo
+{ TARGET_NR_sysinfo, "sysinfo" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sys_kexec_load
+{ TARGET_NR_sys_kexec_load, "sys_kexec_load" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_syslog
+{ TARGET_NR_syslog, "syslog" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sysmips
+{ TARGET_NR_sysmips, "sysmips" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sys_setaltroot
+{ TARGET_NR_sys_setaltroot, "sys_setaltroot" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_tee
+{ TARGET_NR_tee, "tee" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_tgkill
+{ TARGET_NR_tgkill, "tgkill" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_time
+{ TARGET_NR_time, "time" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_timer_create
+{ TARGET_NR_timer_create, "timer_create" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_timer_delete
+{ TARGET_NR_timer_delete, "timer_delete" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_timer_getoverrun
+{ TARGET_NR_timer_getoverrun, "timer_getoverrun" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_timer_gettime
+{ TARGET_NR_timer_gettime, "timer_gettime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_timer_settime
+{ TARGET_NR_timer_settime, "timer_settime" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_times
+{ TARGET_NR_times, "times" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_tkill
+{ TARGET_NR_tkill, "tkill" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_truncate
+{ TARGET_NR_truncate, "truncate" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_truncate64
+{ TARGET_NR_truncate64, "truncate64" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_tuxcall
+{ TARGET_NR_tuxcall, "tuxcall" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ugetrlimit
+{ TARGET_NR_ugetrlimit, "ugetrlimit" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ulimit
+{ TARGET_NR_ulimit, "ulimit" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_umask
+{ TARGET_NR_umask, "umask" , "%s(%#o)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_umount
+{ TARGET_NR_umount, "umount" , NULL, print_umount, NULL },
+#endif
+#ifdef TARGET_NR_umount2
+{ TARGET_NR_umount2, "umount2" , NULL, print_umount2, NULL },
+#endif
+#ifdef TARGET_NR_uname
+{ TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_unlink
+{ TARGET_NR_unlink, "unlink" , NULL, print_unlink, NULL },
+#endif
+#ifdef TARGET_NR_unlinkat
+{ TARGET_NR_unlinkat, "unlinkat" , NULL, print_unlinkat, NULL },
+#endif
+#ifdef TARGET_NR_unshare
+{ TARGET_NR_unshare, "unshare" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused109
+{ TARGET_NR_unused109, "unused109" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused150
+{ TARGET_NR_unused150, "unused150" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused18
+{ TARGET_NR_unused18, "unused18" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused28
+{ TARGET_NR_unused28, "unused28" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused59
+{ TARGET_NR_unused59, "unused59" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_unused84
+{ TARGET_NR_unused84, "unused84" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_uselib
+{ TARGET_NR_uselib, "uselib" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_ustat
+{ TARGET_NR_ustat, "ustat" , "%s(%#x,%p)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_utime
+{ TARGET_NR_utime, "utime" , NULL, print_utime, NULL },
+#endif
+#ifdef TARGET_NR_utimes
+{ TARGET_NR_utimes, "utimes" , NULL, print_utimes, NULL },
+#endif
+#ifdef TARGET_NR_utrap_install
+{ TARGET_NR_utrap_install, "utrap_install" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vfork
+{ TARGET_NR_vfork, "vfork" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vhangup
+{ TARGET_NR_vhangup, "vhangup" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vm86
+{ TARGET_NR_vm86, "vm86" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vm86old
+{ TARGET_NR_vm86old, "vm86old" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vmsplice
+{ TARGET_NR_vmsplice, "vmsplice" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_vserver
+{ TARGET_NR_vserver, "vserver" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_wait4
+{ TARGET_NR_wait4, "wait4" , NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_waitid
+{ TARGET_NR_waitid, "waitid" , "%s(%#x,%d,%p,%#x)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_waitpid
+{ TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_write
+{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_writev
+{ TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_utimensat
+{ TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
+#endif
+#ifdef TARGET_NR_sync_file_range
+{ TARGET_NR_sync_file_range, "sync_file_range", NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sync_file_range2
+{ TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL },
+#endif
diff --git a/qemu-0.15.x/linux-user/syscall.c b/qemu-0.15.x/linux-user/syscall.c
new file mode 100644
index 0000000..73f9baa
--- /dev/null
+++ b/qemu-0.15.x/linux-user/syscall.c
@@ -0,0 +1,8109 @@
+/*
+ *  Linux syscalls
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define _ATFILE_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <elf.h>
+#include <endian.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/swap.h>
+#include <signal.h>
+#include <sched.h>
+#ifdef __ia64__
+int __clone2(int (*fn)(void *), void *child_stack_base,
+             size_t stack_size, int flags, void *arg, ...);
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <sys/times.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/statfs.h>
+#include <utime.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+//#include <sys/user.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <linux/wireless.h>
+#include <qemu-common.h>
+#ifdef TARGET_GPROF
+#include <sys/gmon.h>
+#endif
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+#ifdef CONFIG_EPOLL
+#include <sys/epoll.h>
+#endif
+
+#define termios host_termios
+#define winsize host_winsize
+#define termio host_termio
+#define sgttyb host_sgttyb /* same as target */
+#define tchars host_tchars /* same as target */
+#define ltchars host_ltchars /* same as target */
+
+#include <linux/termios.h>
+#include <linux/unistd.h>
+#include <linux/utsname.h>
+#include <linux/cdrom.h>
+#include <linux/hdreg.h>
+#include <linux/soundcard.h>
+#include <linux/kd.h>
+#include <linux/mtio.h>
+#include <linux/fs.h>
+#if defined(CONFIG_FIEMAP)
+#include <linux/fiemap.h>
+#endif
+#include <linux/fb.h>
+#include <linux/vt.h>
+#include "linux_loop.h"
+#include "cpu-uname.h"
+
+#include "qemu.h"
+#include "qemu-common.h"
+
+#if defined(CONFIG_USE_NPTL)
+#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
+    CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
+#else
+/* XXX: Hardcode the above values.  */
+#define CLONE_NPTL_FLAGS2 0
+#endif
+
+//#define DEBUG
+
+//#include <linux/msdos_fs.h>
+#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct linux_dirent [2])
+#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct linux_dirent [2])
+
+
+#undef _syscall0
+#undef _syscall1
+#undef _syscall2
+#undef _syscall3
+#undef _syscall4
+#undef _syscall5
+#undef _syscall6
+
+#define _syscall0(type,name)		\
+static type name (void)			\
+{					\
+	return syscall(__NR_##name);	\
+}
+
+#define _syscall1(type,name,type1,arg1)		\
+static type name (type1 arg1)			\
+{						\
+	return syscall(__NR_##name, arg1);	\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)	\
+static type name (type1 arg1,type2 arg2)		\
+{							\
+	return syscall(__NR_##name, arg1, arg2);	\
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)	\
+static type name (type1 arg1,type2 arg2,type3 arg3)		\
+{								\
+	return syscall(__NR_##name, arg1, arg2, arg3);		\
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)	\
+static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4)			\
+{										\
+	return syscall(__NR_##name, arg1, arg2, arg3, arg4);			\
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
+		  type5,arg5)							\
+static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)	\
+{										\
+	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5);		\
+}
+
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,	\
+		  type5,arg5,type6,arg6)					\
+static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
+                  type6 arg6)							\
+{										\
+	return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6);	\
+}
+
+
+#define __NR_sys_uname __NR_uname
+#define __NR_sys_faccessat __NR_faccessat
+#define __NR_sys_fchmodat __NR_fchmodat
+#define __NR_sys_fchownat __NR_fchownat
+#define __NR_sys_fstatat64 __NR_fstatat64
+#define __NR_sys_futimesat __NR_futimesat
+#define __NR_sys_getcwd1 __NR_getcwd
+#define __NR_sys_getdents __NR_getdents
+#define __NR_sys_getdents64 __NR_getdents64
+#define __NR_sys_getpriority __NR_getpriority
+#define __NR_sys_linkat __NR_linkat
+#define __NR_sys_mkdirat __NR_mkdirat
+#define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_newfstatat __NR_newfstatat
+#define __NR_sys_openat __NR_openat
+#define __NR_sys_readlinkat __NR_readlinkat
+#define __NR_sys_renameat __NR_renameat
+#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
+#define __NR_sys_symlinkat __NR_symlinkat
+#define __NR_sys_syslog __NR_syslog
+#define __NR_sys_tgkill __NR_tgkill
+#define __NR_sys_tkill __NR_tkill
+#define __NR_sys_unlinkat __NR_unlinkat
+#define __NR_sys_utimensat __NR_utimensat
+#define __NR_sys_futex __NR_futex
+#define __NR_sys_inotify_init __NR_inotify_init
+#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
+#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
+
+#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
+    defined(__s390x__)
+#define __NR__llseek __NR_lseek
+#endif
+
+#ifdef __NR_gettid
+_syscall0(int, gettid)
+#else
+/* This is a replacement for the host gettid() and must return a host
+   errno. */
+static int gettid(void) {
+    return -ENOSYS;
+}
+#endif
+_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
+_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
+#endif
+_syscall2(int, sys_getpriority, int, which, int, who);
+#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
+_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
+          loff_t *, res, uint, wh);
+#endif
+_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
+#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+#endif
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+_syscall2(int,sys_tkill,int,tid,int,sig)
+#endif
+#ifdef __NR_exit_group
+_syscall1(int,exit_group,int,error_code)
+#endif
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+_syscall1(int,set_tid_address,int *,tidptr)
+#endif
+#if defined(CONFIG_USE_NPTL)
+#if defined(TARGET_NR_futex) && defined(__NR_futex)
+_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
+          const struct timespec *,timeout,int *,uaddr2,int,val3)
+#endif
+#endif
+#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
+_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
+          unsigned long *, user_mask_ptr);
+#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
+_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
+          unsigned long *, user_mask_ptr);
+
+static bitmask_transtbl fcntl_flags_tbl[] = {
+  { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
+  { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
+  { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
+  { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
+  { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
+  { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
+  { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
+  { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
+  { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
+  { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
+  { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+  { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
+  { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+#if defined(O_DIRECT)
+  { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
+#endif
+  { 0, 0, 0, 0 }
+};
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+  do { \
+      /* __NEW_UTS_LEN doesn't include terminating null */ \
+      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+      (dest)[__NEW_UTS_LEN] = '\0'; \
+  } while (0)
+
+static int sys_uname(struct new_utsname *buf)
+{
+  struct utsname uts_buf;
+
+  if (uname(&uts_buf) < 0)
+      return (-1);
+
+  /*
+   * Just in case these have some differences, we
+   * translate utsname to new_utsname (which is the
+   * struct linux kernel uses).
+   */
+
+  memset(buf, 0, sizeof(*buf));
+  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+  return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int sys_getcwd1(char *buf, size_t size)
+{
+  if (getcwd(buf, size) == NULL) {
+      /* getcwd() sets errno */
+      return (-1);
+  }
+  return strlen(buf)+1;
+}
+
+#ifdef CONFIG_ATFILE
+/*
+ * Host system seems to have atfile syscall stubs available.  We
+ * now enable them one by one as specified by target syscall_nr.h.
+ */
+
+#ifdef TARGET_NR_faccessat
+static int sys_faccessat(int dirfd, const char *pathname, int mode)
+{
+  return (faccessat(dirfd, pathname, mode, 0));
+}
+#endif
+#ifdef TARGET_NR_fchmodat
+static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
+{
+  return (fchmodat(dirfd, pathname, mode, 0));
+}
+#endif
+#if defined(TARGET_NR_fchownat)
+static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+    gid_t group, int flags)
+{
+  return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+#ifdef __NR_fstatat64
+static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+    int flags)
+{
+  return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef __NR_newfstatat
+static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
+    int flags)
+{
+  return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef TARGET_NR_futimesat
+static int sys_futimesat(int dirfd, const char *pathname,
+    const struct timeval times[2])
+{
+  return (futimesat(dirfd, pathname, times));
+}
+#endif
+#ifdef TARGET_NR_linkat
+static int sys_linkat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath, int flags)
+{
+  return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+#ifdef TARGET_NR_mkdirat
+static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+  return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+#ifdef TARGET_NR_mknodat
+static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
+    dev_t dev)
+{
+  return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
+#ifdef TARGET_NR_openat
+static int sys_openat(int dirfd, const char *pathname, int flags, ...)
+{
+  /*
+   * open(2) has extra parameter 'mode' when called with
+   * flag O_CREAT.
+   */
+  if ((flags & O_CREAT) != 0) {
+      va_list ap;
+      mode_t mode;
+
+      /*
+       * Get the 'mode' parameter and translate it to
+       * host bits.
+       */
+      va_start(ap, flags);
+      mode = va_arg(ap, mode_t);
+      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
+      va_end(ap);
+
+      return (openat(dirfd, pathname, flags, mode));
+  }
+  return (openat(dirfd, pathname, flags));
+}
+#endif
+#ifdef TARGET_NR_readlinkat
+static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+  return (readlinkat(dirfd, pathname, buf, bufsiz));
+}
+#endif
+#ifdef TARGET_NR_renameat
+static int sys_renameat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath)
+{
+  return (renameat(olddirfd, oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_symlinkat
+static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+  return (symlinkat(oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_unlinkat
+static int sys_unlinkat(int dirfd, const char *pathname, int flags)
+{
+  return (unlinkat(dirfd, pathname, flags));
+}
+#endif
+#else /* !CONFIG_ATFILE */
+
+/*
+ * Try direct syscalls instead
+ */
+#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
+_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
+#endif
+#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
+_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
+#endif
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
+_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
+          uid_t,owner,gid_t,group,int,flags)
+#endif
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        defined(__NR_fstatat64)
+_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
+#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
+_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
+         const struct timeval *,times)
+#endif
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+        defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
+#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
+_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
+      int,newdirfd,const char *,newpath,int,flags)
+#endif
+#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
+_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
+#endif
+#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
+_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
+          mode_t,mode,dev_t,dev)
+#endif
+#if defined(TARGET_NR_openat) && defined(__NR_openat)
+_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
+#endif
+#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
+_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
+          char *,buf,size_t,bufsize)
+#endif
+#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
+_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
+#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
+_syscall3(int,sys_symlinkat,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
+#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
+_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
+#endif
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_UTIMENSAT
+static int sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
+{
+    if (pathname == NULL)
+        return futimens(dirfd, times);
+    else
+        return utimensat(dirfd, pathname, times, flags);
+}
+#else
+#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
+_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
+          const struct timespec *,tsp,int,flags)
+#endif
+#endif /* CONFIG_UTIMENSAT  */
+
+#ifdef CONFIG_INOTIFY
+#include <sys/inotify.h>
+
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
+static int sys_inotify_init(void)
+{
+  return (inotify_init());
+}
+#endif
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
+static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
+{
+  return (inotify_add_watch(fd, pathname, mask));
+}
+#endif
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
+static int sys_inotify_rm_watch(int fd, int32_t wd)
+{
+  return (inotify_rm_watch(fd, wd));
+}
+#endif
+#ifdef CONFIG_INOTIFY1
+#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
+static int sys_inotify_init1(int flags)
+{
+  return (inotify_init1(flags));
+}
+#endif
+#endif
+#else
+/* Userspace can usually survive runtime without inotify */
+#undef TARGET_NR_inotify_init
+#undef TARGET_NR_inotify_init1
+#undef TARGET_NR_inotify_add_watch
+#undef TARGET_NR_inotify_rm_watch
+#endif /* CONFIG_INOTIFY  */
+
+#if defined(TARGET_NR_ppoll)
+#ifndef __NR_ppoll
+# define __NR_ppoll -1
+#endif
+#define __NR_sys_ppoll __NR_ppoll
+_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
+          struct timespec *, timeout, const __sigset_t *, sigmask,
+          size_t, sigsetsize)
+#endif
+
+#if defined(TARGET_NR_pselect6)
+#ifndef __NR_pselect6
+# define __NR_pselect6 -1
+#endif
+#define __NR_sys_pselect6 __NR_pselect6
+_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
+          fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
+#endif
+
+#if defined(TARGET_NR_prlimit64)
+#ifndef __NR_prlimit64
+# define __NR_prlimit64 -1
+#endif
+#define __NR_sys_prlimit64 __NR_prlimit64
+/* The glibc rlimit structure may not be that used by the underlying syscall */
+struct host_rlimit64 {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+_syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
+          const struct host_rlimit64 *, new_limit,
+          struct host_rlimit64 *, old_limit)
+#endif
+
+extern int personality(int);
+extern int flock(int, int);
+extern int setfsuid(int);
+extern int setfsgid(int);
+extern int setgroups(int, gid_t *);
+
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
+#ifdef TARGET_ARM 
+static inline int regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
+}
+#elif defined(TARGET_MIPS)
+static inline int regpairs_aligned(void *cpu_env) { return 1; }
+#else
+static inline int regpairs_aligned(void *cpu_env) { return 0; }
+#endif
+
+#define ERRNO_TABLE_SIZE 1200
+
+/* target_to_host_errno_table[] is initialized from
+ * host_to_target_errno_table[] in syscall_init(). */
+static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
+};
+
+/*
+ * This list is the union of errno values overridden in asm-<arch>/errno.h
+ * minus the errnos that are not actually generic to all archs.
+ */
+static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
+    [EIDRM]		= TARGET_EIDRM,
+    [ECHRNG]		= TARGET_ECHRNG,
+    [EL2NSYNC]		= TARGET_EL2NSYNC,
+    [EL3HLT]		= TARGET_EL3HLT,
+    [EL3RST]		= TARGET_EL3RST,
+    [ELNRNG]		= TARGET_ELNRNG,
+    [EUNATCH]		= TARGET_EUNATCH,
+    [ENOCSI]		= TARGET_ENOCSI,
+    [EL2HLT]		= TARGET_EL2HLT,
+    [EDEADLK]		= TARGET_EDEADLK,
+    [ENOLCK]		= TARGET_ENOLCK,
+    [EBADE]		= TARGET_EBADE,
+    [EBADR]		= TARGET_EBADR,
+    [EXFULL]		= TARGET_EXFULL,
+    [ENOANO]		= TARGET_ENOANO,
+    [EBADRQC]		= TARGET_EBADRQC,
+    [EBADSLT]		= TARGET_EBADSLT,
+    [EBFONT]		= TARGET_EBFONT,
+    [ENOSTR]		= TARGET_ENOSTR,
+    [ENODATA]		= TARGET_ENODATA,
+    [ETIME]		= TARGET_ETIME,
+    [ENOSR]		= TARGET_ENOSR,
+    [ENONET]		= TARGET_ENONET,
+    [ENOPKG]		= TARGET_ENOPKG,
+    [EREMOTE]		= TARGET_EREMOTE,
+    [ENOLINK]		= TARGET_ENOLINK,
+    [EADV]		= TARGET_EADV,
+    [ESRMNT]		= TARGET_ESRMNT,
+    [ECOMM]		= TARGET_ECOMM,
+    [EPROTO]		= TARGET_EPROTO,
+    [EDOTDOT]		= TARGET_EDOTDOT,
+    [EMULTIHOP]		= TARGET_EMULTIHOP,
+    [EBADMSG]		= TARGET_EBADMSG,
+    [ENAMETOOLONG]	= TARGET_ENAMETOOLONG,
+    [EOVERFLOW]		= TARGET_EOVERFLOW,
+    [ENOTUNIQ]		= TARGET_ENOTUNIQ,
+    [EBADFD]		= TARGET_EBADFD,
+    [EREMCHG]		= TARGET_EREMCHG,
+    [ELIBACC]		= TARGET_ELIBACC,
+    [ELIBBAD]		= TARGET_ELIBBAD,
+    [ELIBSCN]		= TARGET_ELIBSCN,
+    [ELIBMAX]		= TARGET_ELIBMAX,
+    [ELIBEXEC]		= TARGET_ELIBEXEC,
+    [EILSEQ]		= TARGET_EILSEQ,
+    [ENOSYS]		= TARGET_ENOSYS,
+    [ELOOP]		= TARGET_ELOOP,
+    [ERESTART]		= TARGET_ERESTART,
+    [ESTRPIPE]		= TARGET_ESTRPIPE,
+    [ENOTEMPTY]		= TARGET_ENOTEMPTY,
+    [EUSERS]		= TARGET_EUSERS,
+    [ENOTSOCK]		= TARGET_ENOTSOCK,
+    [EDESTADDRREQ]	= TARGET_EDESTADDRREQ,
+    [EMSGSIZE]		= TARGET_EMSGSIZE,
+    [EPROTOTYPE]	= TARGET_EPROTOTYPE,
+    [ENOPROTOOPT]	= TARGET_ENOPROTOOPT,
+    [EPROTONOSUPPORT]	= TARGET_EPROTONOSUPPORT,
+    [ESOCKTNOSUPPORT]	= TARGET_ESOCKTNOSUPPORT,
+    [EOPNOTSUPP]	= TARGET_EOPNOTSUPP,
+    [EPFNOSUPPORT]	= TARGET_EPFNOSUPPORT,
+    [EAFNOSUPPORT]	= TARGET_EAFNOSUPPORT,
+    [EADDRINUSE]	= TARGET_EADDRINUSE,
+    [EADDRNOTAVAIL]	= TARGET_EADDRNOTAVAIL,
+    [ENETDOWN]		= TARGET_ENETDOWN,
+    [ENETUNREACH]	= TARGET_ENETUNREACH,
+    [ENETRESET]		= TARGET_ENETRESET,
+    [ECONNABORTED]	= TARGET_ECONNABORTED,
+    [ECONNRESET]	= TARGET_ECONNRESET,
+    [ENOBUFS]		= TARGET_ENOBUFS,
+    [EISCONN]		= TARGET_EISCONN,
+    [ENOTCONN]		= TARGET_ENOTCONN,
+    [EUCLEAN]		= TARGET_EUCLEAN,
+    [ENOTNAM]		= TARGET_ENOTNAM,
+    [ENAVAIL]		= TARGET_ENAVAIL,
+    [EISNAM]		= TARGET_EISNAM,
+    [EREMOTEIO]		= TARGET_EREMOTEIO,
+    [ESHUTDOWN]		= TARGET_ESHUTDOWN,
+    [ETOOMANYREFS]	= TARGET_ETOOMANYREFS,
+    [ETIMEDOUT]		= TARGET_ETIMEDOUT,
+    [ECONNREFUSED]	= TARGET_ECONNREFUSED,
+    [EHOSTDOWN]		= TARGET_EHOSTDOWN,
+    [EHOSTUNREACH]	= TARGET_EHOSTUNREACH,
+    [EALREADY]		= TARGET_EALREADY,
+    [EINPROGRESS]	= TARGET_EINPROGRESS,
+    [ESTALE]		= TARGET_ESTALE,
+    [ECANCELED]		= TARGET_ECANCELED,
+    [ENOMEDIUM]		= TARGET_ENOMEDIUM,
+    [EMEDIUMTYPE]	= TARGET_EMEDIUMTYPE,
+#ifdef ENOKEY
+    [ENOKEY]		= TARGET_ENOKEY,
+#endif
+#ifdef EKEYEXPIRED
+    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
+#endif
+#ifdef EKEYREVOKED
+    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
+#endif
+#ifdef EKEYREJECTED
+    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
+#endif
+#ifdef EOWNERDEAD
+    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
+#endif
+#ifdef ENOTRECOVERABLE
+    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
+#endif
+};
+
+static inline int host_to_target_errno(int err)
+{
+    if(host_to_target_errno_table[err])
+        return host_to_target_errno_table[err];
+    return err;
+}
+
+static inline int target_to_host_errno(int err)
+{
+    if (target_to_host_errno_table[err])
+        return target_to_host_errno_table[err];
+    return err;
+}
+
+static inline abi_long get_errno(abi_long ret)
+{
+    if (ret == -1)
+        return -host_to_target_errno(errno);
+    else
+        return ret;
+}
+
+static inline int is_error(abi_long ret)
+{
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
+}
+
+char *target_strerror(int err)
+{
+    return strerror(target_to_host_errno(err));
+}
+
+static abi_ulong target_brk;
+static abi_ulong target_original_brk;
+static abi_ulong brk_page;
+
+void target_set_brk(abi_ulong new_brk)
+{
+    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
+    brk_page = HOST_PAGE_ALIGN(target_brk);
+}
+
+//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
+#define DEBUGF_BRK(message, args...)
+
+/* do_brk() must return target values and target errnos. */
+abi_long do_brk(abi_ulong new_brk)
+{
+    abi_long mapped_addr;
+    int	new_alloc_size;
+
+    DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
+
+    if (!new_brk) {
+        DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
+        return target_brk;
+    }
+    if (new_brk < target_original_brk) {
+        DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
+        return target_brk;
+    }
+
+    /* If the new brk is less than the highest page reserved to the
+     * target heap allocation, set it and we're almost done...  */
+    if (new_brk <= brk_page) {
+        /* Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  */
+        if (new_brk > target_brk) {
+            memset(g2h(target_brk), 0, new_brk - target_brk);
+        }
+	target_brk = new_brk;
+        DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
+    	return target_brk;
+    }
+
+    /* We need to allocate more memory after the brk... Note that
+     * we don't use MAP_FIXED because that will map over the top of
+     * any existing mapping (like the one with the host libc or qemu
+     * itself); instead we treat "mapped but at wrong address" as
+     * a failure and unmap again.
+     */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                                        PROT_READ|PROT_WRITE,
+                                        MAP_ANON|MAP_PRIVATE, 0, 0));
+
+    if (mapped_addr == brk_page) {
+        target_brk = new_brk;
+        brk_page = HOST_PAGE_ALIGN(target_brk);
+        DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
+        return target_brk;
+    } else if (mapped_addr != -1) {
+        /* Mapped but at wrong address, meaning there wasn't actually
+         * enough space for this brk.
+         */
+        target_munmap(mapped_addr, new_alloc_size);
+        mapped_addr = -1;
+        DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
+    }
+    else {
+        DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
+    }
+
+#if defined(TARGET_ALPHA)
+    /* We (partially) emulate OSF/1 on Alpha, which requires we
+       return a proper errno, not an unchanged brk value.  */
+    return -TARGET_ENOMEM;
+#endif
+    /* For everything else, return the previous break. */
+    return target_brk;
+}
+
+static inline abi_long copy_from_user_fdset(fd_set *fds,
+                                            abi_ulong target_fds_addr,
+                                            int n)
+{
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_READ,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 1)))
+        return -TARGET_EFAULT;
+
+    FD_ZERO(fds);
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        /* grab the abi_ulong */
+        __get_user(b, &target_fds[i]);
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            /* check the bit inside the abi_ulong */
+            if ((b >> j) & 1)
+                FD_SET(k, fds);
+            k++;
+        }
+    }
+
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
+}
+
+static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+                                                 abi_ulong target_fds_addr,
+                                                 int n)
+{
+    if (target_fds_addr) {
+        if (copy_from_user_fdset(fds, target_fds_addr, n))
+            return -TARGET_EFAULT;
+        *fds_ptr = fds;
+    } else {
+        *fds_ptr = NULL;
+    }
+    return 0;
+}
+
+static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
+                                          const fd_set *fds,
+                                          int n)
+{
+    int i, nw, j, k;
+    abi_long v;
+    abi_ulong *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_WRITE,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 0)))
+        return -TARGET_EFAULT;
+
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        v = 0;
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            v |= ((FD_ISSET(k, fds) != 0) << j);
+            k++;
+        }
+        __put_user(v, &target_fds[i]);
+    }
+
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
+}
+
+#if defined(__alpha__)
+#define HOST_HZ 1024
+#else
+#define HOST_HZ 100
+#endif
+
+static inline abi_long host_to_target_clock_t(long ticks)
+{
+#if HOST_HZ == TARGET_HZ
+    return ticks;
+#else
+    return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
+#endif
+}
+
+static inline abi_long host_to_target_rusage(abi_ulong target_addr,
+                                             const struct rusage *rusage)
+{
+    struct target_rusage *target_rusage;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
+        return -TARGET_EFAULT;
+    target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
+    target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
+    target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
+    target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
+    target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
+    target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
+    target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
+    target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
+    target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
+    target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
+    target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
+    target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
+    target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
+    target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
+    target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
+    target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
+    target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
+    target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
+    unlock_user_struct(target_rusage, target_addr, 1);
+
+    return 0;
+}
+
+static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
+{
+    target_ulong target_rlim_swap;
+    rlim_t result;
+    
+    target_rlim_swap = tswapl(target_rlim);
+    if (target_rlim_swap == TARGET_RLIM_INFINITY || target_rlim_swap != (rlim_t)target_rlim_swap)
+        result = RLIM_INFINITY;
+    else
+        result = target_rlim_swap;
+    
+    return result;
+}
+
+static inline target_ulong host_to_target_rlim(rlim_t rlim)
+{
+    target_ulong target_rlim_swap;
+    target_ulong result;
+    
+    if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
+        target_rlim_swap = TARGET_RLIM_INFINITY;
+    else
+        target_rlim_swap = rlim;
+    result = tswapl(target_rlim_swap);
+    
+    return result;
+}
+
+static inline int target_to_host_resource(int code)
+{
+    switch (code) {
+    case TARGET_RLIMIT_AS:
+        return RLIMIT_AS;
+    case TARGET_RLIMIT_CORE:
+        return RLIMIT_CORE;
+    case TARGET_RLIMIT_CPU:
+        return RLIMIT_CPU;
+    case TARGET_RLIMIT_DATA:
+        return RLIMIT_DATA;
+    case TARGET_RLIMIT_FSIZE:
+        return RLIMIT_FSIZE;
+    case TARGET_RLIMIT_LOCKS:
+        return RLIMIT_LOCKS;
+    case TARGET_RLIMIT_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+    case TARGET_RLIMIT_MSGQUEUE:
+        return RLIMIT_MSGQUEUE;
+    case TARGET_RLIMIT_NICE:
+        return RLIMIT_NICE;
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+    case TARGET_RLIMIT_RTPRIO:
+        return RLIMIT_RTPRIO;
+    case TARGET_RLIMIT_SIGPENDING:
+        return RLIMIT_SIGPENDING;
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+    default:
+        return code;
+    }
+}
+
+static inline abi_long copy_from_user_timeval(struct timeval *tv,
+                                              abi_ulong target_tv_addr)
+{
+    struct target_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
+        return -TARGET_EFAULT;
+
+    __get_user(tv->tv_sec, &target_tv->tv_sec);
+    __get_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
+                                            const struct timeval *tv)
+{
+    struct target_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
+        return -TARGET_EFAULT;
+
+    __put_user(tv->tv_sec, &target_tv->tv_sec);
+    __put_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 1);
+
+    return 0;
+}
+
+#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
+#include <mqueue.h>
+
+static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
+                                              abi_ulong target_mq_attr_addr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_READ, target_mq_attr,
+                          target_mq_attr_addr, 1))
+        return -TARGET_EFAULT;
+
+    __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
+                                            const struct mq_attr *attr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
+                          target_mq_attr_addr, 0))
+        return -TARGET_EFAULT;
+
+    __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
+
+    return 0;
+}
+#endif
+
+#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
+/* do_select() must return target values and target errnos. */
+static abi_long do_select(int n,
+                          abi_ulong rfd_addr, abi_ulong wfd_addr,
+                          abi_ulong efd_addr, abi_ulong target_tv_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    struct timeval tv, *tv_ptr;
+    abi_long ret;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret) {
+        return ret;
+    }
+
+    if (target_tv_addr) {
+        if (copy_from_user_timeval(&tv, target_tv_addr))
+            return -TARGET_EFAULT;
+        tv_ptr = &tv;
+    } else {
+        tv_ptr = NULL;
+    }
+
+    ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
+
+    if (!is_error(ret)) {
+        if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+            return -TARGET_EFAULT;
+        if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+            return -TARGET_EFAULT;
+        if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+            return -TARGET_EFAULT;
+
+        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
+            return -TARGET_EFAULT;
+    }
+
+    return ret;
+}
+#endif
+
+static abi_long do_pipe2(int host_pipe[], int flags)
+{
+#ifdef CONFIG_PIPE2
+    return pipe2(host_pipe, flags);
+#else
+    return -ENOSYS;
+#endif
+}
+
+static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
+                        int flags, int is_pipe2)
+{
+    int host_pipe[2];
+    abi_long ret;
+    ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
+
+    if (is_error(ret))
+        return get_errno(ret);
+
+    /* Several targets have special calling conventions for the original
+       pipe syscall, but didn't replicate this into the pipe2 syscall.  */
+    if (!is_pipe2) {
+#if defined(TARGET_ALPHA)
+        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
+        return host_pipe[0];
+#elif defined(TARGET_MIPS)
+        ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
+        return host_pipe[0];
+#elif defined(TARGET_SH4)
+        ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
+        return host_pipe[0];
+#endif
+    }
+
+    if (put_user_s32(host_pipe[0], pipedes)
+        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
+        return -TARGET_EFAULT;
+    return get_errno(ret);
+}
+
+static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
+                                              abi_ulong target_addr,
+                                              socklen_t len)
+{
+    struct target_ip_mreqn *target_smreqn;
+
+    target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (!target_smreqn)
+        return -TARGET_EFAULT;
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn))
+        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
+                                               abi_ulong target_addr,
+                                               socklen_t len)
+{
+    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+    sa_family_t sa_family;
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (!target_saddr)
+        return -TARGET_EFAULT;
+
+    sa_family = tswap16(target_saddr->sa_family);
+
+    /* Oops. The caller might send a incomplete sun_path; sun_path
+     * must be terminated by \0 (see the manual page), but
+     * unfortunately it is quite common to specify sockaddr_un
+     * length as "strlen(x->sun_path)" while it should be
+     * "strlen(...) + 1". We'll fix that here if needed.
+     * Linux kernel has a similar feature.
+     */
+
+    if (sa_family == AF_UNIX) {
+        if (len < unix_maxlen && len > 0) {
+            char *cp = (char*)target_saddr;
+
+            if ( cp[len-1] && !cp[len] )
+                len++;
+        }
+        if (len > unix_maxlen)
+            len = unix_maxlen;
+    }
+
+    memcpy(addr, target_saddr, len);
+    addr->sa_family = sa_family;
+    unlock_user(target_saddr, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
+                                               struct sockaddr *addr,
+                                               socklen_t len)
+{
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (!target_saddr)
+        return -TARGET_EFAULT;
+    memcpy(target_saddr, addr, len);
+    target_saddr->sa_family = tswap16(addr->sa_family);
+    unlock_user(target_saddr, target_addr, len);
+
+    return 0;
+}
+
+/* ??? Should this also swap msgh->name?  */
+static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
+                                           struct target_msghdr *target_msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+    
+    msg_controllen = tswapl(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof (struct target_cmsghdr)) 
+        goto the_end;
+    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+    if (!target_cmsg)
+        return -TARGET_EFAULT;
+
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+
+        int len = tswapl(target_cmsg->cmsg_len)
+                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
+
+        space += CMSG_SPACE(len);
+        if (space > msgh->msg_controllen) {
+            space -= CMSG_SPACE(len);
+            gemu_log("Host cmsg overflow\n");
+            break;
+        }
+
+        cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+        cmsg->cmsg_len = CMSG_LEN(len);
+
+        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+            gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(data, target_data, len);
+        } else {
+            int *fd = (int *)data;
+            int *target_fd = (int *)target_data;
+            int i, numfds = len / sizeof(int);
+
+            for (i = 0; i < numfds; i++)
+                fd[i] = tswap32(target_fd[i]);
+        }
+
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, 0);
+ the_end:
+    msgh->msg_controllen = space;
+    return 0;
+}
+
+/* ??? Should this also swap msgh->name?  */
+static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
+                                           struct msghdr *msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    abi_long msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg;
+    socklen_t space = 0;
+
+    msg_controllen = tswapl(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof (struct target_cmsghdr)) 
+        goto the_end;
+    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
+    if (!target_cmsg)
+        return -TARGET_EFAULT;
+
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+
+        int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
+
+        space += TARGET_CMSG_SPACE(len);
+        if (space > msg_controllen) {
+            space -= TARGET_CMSG_SPACE(len);
+            gemu_log("Target cmsg overflow\n");
+            break;
+        }
+
+        target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+        target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
+
+        if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+            gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(target_data, data, len);
+        } else {
+            int *fd = (int *)data;
+            int *target_fd = (int *)target_data;
+            int i, numfds = len / sizeof(int);
+
+            for (i = 0; i < numfds; i++)
+                target_fd[i] = tswap32(fd[i]);
+        }
+
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+    }
+    unlock_user(target_cmsg, target_cmsg_addr, space);
+ the_end:
+    target_msgh->msg_controllen = tswapl(space);
+    return 0;
+}
+
+/* do_setsockopt() Must return target values and target errnos. */
+static abi_long do_setsockopt(int sockfd, int level, int optname,
+                              abi_ulong optval_addr, socklen_t optlen)
+{
+    abi_long ret;
+    int val;
+    struct ip_mreqn *ip_mreq;
+    struct ip_mreq_source *ip_mreq_source;
+
+    switch(level) {
+    case SOL_TCP:
+        /* TCP options all take an 'int' value.  */
+        if (optlen < sizeof(uint32_t))
+            return -TARGET_EINVAL;
+
+        if (get_user_u32(val, optval_addr))
+            return -TARGET_EFAULT;
+        ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+        break;
+    case SOL_IP:
+        switch(optname) {
+        case IP_TOS:
+        case IP_TTL:
+        case IP_HDRINCL:
+        case IP_ROUTER_ALERT:
+        case IP_RECVOPTS:
+        case IP_RETOPTS:
+        case IP_PKTINFO:
+        case IP_MTU_DISCOVER:
+        case IP_RECVERR:
+        case IP_RECVTOS:
+#ifdef IP_FREEBIND
+        case IP_FREEBIND:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+            val = 0;
+            if (optlen >= sizeof(uint32_t)) {
+                if (get_user_u32(val, optval_addr))
+                    return -TARGET_EFAULT;
+            } else if (optlen >= 1) {
+                if (get_user_u8(val, optval_addr))
+                    return -TARGET_EFAULT;
+            }
+            ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+            break;
+        case IP_ADD_MEMBERSHIP:
+        case IP_DROP_MEMBERSHIP:
+            if (optlen < sizeof (struct target_ip_mreq) ||
+                optlen > sizeof (struct target_ip_mreqn))
+                return -TARGET_EINVAL;
+
+            ip_mreq = (struct ip_mreqn *) alloca(optlen);
+            target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
+            break;
+
+        case IP_BLOCK_SOURCE:
+        case IP_UNBLOCK_SOURCE:
+        case IP_ADD_SOURCE_MEMBERSHIP:
+        case IP_DROP_SOURCE_MEMBERSHIP:
+            if (optlen != sizeof (struct target_ip_mreq_source))
+                return -TARGET_EINVAL;
+
+            ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
+            unlock_user (ip_mreq_source, optval_addr, 0);
+            break;
+
+        default:
+            goto unimplemented;
+        }
+        break;
+    case TARGET_SOL_SOCKET:
+        switch (optname) {
+            /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+		optname = SO_DEBUG;
+		break;
+        case TARGET_SO_REUSEADDR:
+		optname = SO_REUSEADDR;
+		break;
+        case TARGET_SO_TYPE:
+		optname = SO_TYPE;
+		break;
+        case TARGET_SO_ERROR:
+		optname = SO_ERROR;
+		break;
+        case TARGET_SO_DONTROUTE:
+		optname = SO_DONTROUTE;
+		break;
+        case TARGET_SO_BROADCAST:
+		optname = SO_BROADCAST;
+		break;
+        case TARGET_SO_SNDBUF:
+		optname = SO_SNDBUF;
+		break;
+        case TARGET_SO_RCVBUF:
+		optname = SO_RCVBUF;
+		break;
+        case TARGET_SO_KEEPALIVE:
+		optname = SO_KEEPALIVE;
+		break;
+        case TARGET_SO_OOBINLINE:
+		optname = SO_OOBINLINE;
+		break;
+        case TARGET_SO_NO_CHECK:
+		optname = SO_NO_CHECK;
+		break;
+        case TARGET_SO_PRIORITY:
+		optname = SO_PRIORITY;
+		break;
+#ifdef SO_BSDCOMPAT
+        case TARGET_SO_BSDCOMPAT:
+		optname = SO_BSDCOMPAT;
+		break;
+#endif
+        case TARGET_SO_PASSCRED:
+		optname = SO_PASSCRED;
+		break;
+        case TARGET_SO_TIMESTAMP:
+		optname = SO_TIMESTAMP;
+		break;
+        case TARGET_SO_RCVLOWAT:
+		optname = SO_RCVLOWAT;
+		break;
+        case TARGET_SO_RCVTIMEO:
+		optname = SO_RCVTIMEO;
+		break;
+        case TARGET_SO_SNDTIMEO:
+		optname = SO_SNDTIMEO;
+		break;
+            break;
+        default:
+            goto unimplemented;
+        }
+	if (optlen < sizeof(uint32_t))
+            return -TARGET_EINVAL;
+
+	if (get_user_u32(val, optval_addr))
+            return -TARGET_EFAULT;
+	ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
+        break;
+    default:
+    unimplemented:
+        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
+        ret = -TARGET_ENOPROTOOPT;
+    }
+    return ret;
+}
+
+/* do_getsockopt() Must return target values and target errnos. */
+static abi_long do_getsockopt(int sockfd, int level, int optname,
+                              abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int len, val;
+    socklen_t lv;
+
+    switch(level) {
+    case TARGET_SOL_SOCKET:
+        level = SOL_SOCKET;
+        switch (optname) {
+        /* These don't just return a single integer */
+        case TARGET_SO_LINGER:
+        case TARGET_SO_RCVTIMEO:
+        case TARGET_SO_SNDTIMEO:
+        case TARGET_SO_PEERCRED:
+        case TARGET_SO_PEERNAME:
+            goto unimplemented;
+        /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+            optname = SO_DEBUG;
+            goto int_case;
+        case TARGET_SO_REUSEADDR:
+            optname = SO_REUSEADDR;
+            goto int_case;
+        case TARGET_SO_TYPE:
+            optname = SO_TYPE;
+            goto int_case;
+        case TARGET_SO_ERROR:
+            optname = SO_ERROR;
+            goto int_case;
+        case TARGET_SO_DONTROUTE:
+            optname = SO_DONTROUTE;
+            goto int_case;
+        case TARGET_SO_BROADCAST:
+            optname = SO_BROADCAST;
+            goto int_case;
+        case TARGET_SO_SNDBUF:
+            optname = SO_SNDBUF;
+            goto int_case;
+        case TARGET_SO_RCVBUF:
+            optname = SO_RCVBUF;
+            goto int_case;
+        case TARGET_SO_KEEPALIVE:
+            optname = SO_KEEPALIVE;
+            goto int_case;
+        case TARGET_SO_OOBINLINE:
+            optname = SO_OOBINLINE;
+            goto int_case;
+        case TARGET_SO_NO_CHECK:
+            optname = SO_NO_CHECK;
+            goto int_case;
+        case TARGET_SO_PRIORITY:
+            optname = SO_PRIORITY;
+            goto int_case;
+#ifdef SO_BSDCOMPAT
+        case TARGET_SO_BSDCOMPAT:
+            optname = SO_BSDCOMPAT;
+            goto int_case;
+#endif
+        case TARGET_SO_PASSCRED:
+            optname = SO_PASSCRED;
+            goto int_case;
+        case TARGET_SO_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            goto int_case;
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            goto int_case;
+        default:
+            goto int_case;
+        }
+        break;
+    case SOL_TCP:
+        /* TCP options all take an 'int' value.  */
+    int_case:
+        if (get_user_u32(len, optlen))
+            return -TARGET_EFAULT;
+        if (len < 0)
+            return -TARGET_EINVAL;
+        lv = sizeof(lv);
+        ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+        if (ret < 0)
+            return ret;
+        if (len > lv)
+            len = lv;
+        if (len == 4) {
+            if (put_user_u32(val, optval_addr))
+                return -TARGET_EFAULT;
+        } else {
+            if (put_user_u8(val, optval_addr))
+                return -TARGET_EFAULT;
+        }
+        if (put_user_u32(len, optlen))
+            return -TARGET_EFAULT;
+        break;
+    case SOL_IP:
+        switch(optname) {
+        case IP_TOS:
+        case IP_TTL:
+        case IP_HDRINCL:
+        case IP_ROUTER_ALERT:
+        case IP_RECVOPTS:
+        case IP_RETOPTS:
+        case IP_PKTINFO:
+        case IP_MTU_DISCOVER:
+        case IP_RECVERR:
+        case IP_RECVTOS:
+#ifdef IP_FREEBIND
+        case IP_FREEBIND:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+            if (get_user_u32(len, optlen))
+                return -TARGET_EFAULT;
+            if (len < 0)
+                return -TARGET_EINVAL;
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+            if (ret < 0)
+                return ret;
+            if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen)
+                    || put_user_u8(val, optval_addr))
+                    return -TARGET_EFAULT;
+            } else {
+                if (len > sizeof(int))
+                    len = sizeof(int);
+                if (put_user_u32(len, optlen)
+                    || put_user_u32(val, optval_addr))
+                    return -TARGET_EFAULT;
+            }
+            break;
+        default:
+            ret = -TARGET_ENOPROTOOPT;
+            break;
+        }
+        break;
+    default:
+    unimplemented:
+        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+                 level, optname);
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+    }
+    return ret;
+}
+
+/* FIXME
+ * lock_iovec()/unlock_iovec() have a return code of 0 for success where
+ * other lock functions have a return code of 0 for failure.
+ */
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+                           int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        base = tswapl(target_vec[i].iov_base);
+        vec[i].iov_len = tswapl(target_vec[i].iov_len);
+        if (vec[i].iov_len != 0) {
+            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
+            /* Don't check lock_user return value. We must call writev even
+               if a element has invalid base address. */
+        } else {
+            /* zero length pointer is ignored */
+            vec[i].iov_base = NULL;
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+    return 0;
+}
+
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+                             int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        if (target_vec[i].iov_base) {
+            base = tswapl(target_vec[i].iov_base);
+            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+
+    return 0;
+}
+
+/* do_socket() Must return target values and target errnos. */
+static abi_long do_socket(int domain, int type, int protocol)
+{
+#if defined(TARGET_MIPS)
+    switch(type) {
+    case TARGET_SOCK_DGRAM:
+        type = SOCK_DGRAM;
+        break;
+    case TARGET_SOCK_STREAM:
+        type = SOCK_STREAM;
+        break;
+    case TARGET_SOCK_RAW:
+        type = SOCK_RAW;
+        break;
+    case TARGET_SOCK_RDM:
+        type = SOCK_RDM;
+        break;
+    case TARGET_SOCK_SEQPACKET:
+        type = SOCK_SEQPACKET;
+        break;
+    case TARGET_SOCK_PACKET:
+        type = SOCK_PACKET;
+        break;
+    }
+#endif
+    if (domain == PF_NETLINK)
+        return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
+    return get_errno(socket(domain, type, protocol));
+}
+
+/* do_bind() Must return target values and target errnos. */
+static abi_long do_bind(int sockfd, abi_ulong target_addr,
+                        socklen_t addrlen)
+{
+    void *addr;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen+1);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (ret)
+        return ret;
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* do_connect() Must return target values and target errnos. */
+static abi_long do_connect(int sockfd, abi_ulong target_addr,
+                           socklen_t addrlen)
+{
+    void *addr;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (ret)
+        return ret;
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* do_sendrecvmsg() Must return target values and target errnos. */
+static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
+                               int flags, int send)
+{
+    abi_long ret, len;
+    struct target_msghdr *msgp;
+    struct msghdr msg;
+    int count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    /* FIXME */
+    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
+                          msgp,
+                          target_msg,
+                          send ? 1 : 0))
+        return -TARGET_EFAULT;
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen);
+        ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
+                                msg.msg_namelen);
+        if (ret) {
+            unlock_user_struct(msgp, target_msg, send ? 0 : 1);
+            return ret;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
+    msg.msg_control = alloca(msg.msg_controllen);
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswapl(msgp->msg_iovlen);
+    vec = alloca(count * sizeof(struct iovec));
+    target_vec = tswapl(msgp->msg_iov);
+    lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    if (send) {
+        ret = target_to_host_cmsg(&msg, msgp);
+        if (ret == 0)
+            ret = get_errno(sendmsg(fd, &msg, flags));
+    } else {
+        ret = get_errno(recvmsg(fd, &msg, flags));
+        if (!is_error(ret)) {
+            len = ret;
+            ret = host_to_target_cmsg(msgp, &msg);
+            if (!is_error(ret))
+                ret = len;
+        }
+    }
+    unlock_iovec(vec, target_vec, count, !send);
+    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
+    return ret;
+}
+
+/* do_accept() Must return target values and target errnos. */
+static abi_long do_accept(int fd, abi_ulong target_addr,
+                          abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0)
+       return get_errno(accept(fd, NULL, NULL));
+
+    /* linux returns EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr))
+        return -TARGET_EINVAL;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+        return -TARGET_EINVAL;
+
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr))
+            ret = -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* do_getpeername() Must return target values and target errnos. */
+static abi_long do_getpeername(int fd, abi_ulong target_addr,
+                               abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr))
+        return -TARGET_EFAULT;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+        return -TARGET_EFAULT;
+
+    addr = alloca(addrlen);
+
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr))
+            ret = -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* do_getsockname() Must return target values and target errnos. */
+static abi_long do_getsockname(int fd, abi_ulong target_addr,
+                               abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr))
+        return -TARGET_EFAULT;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
+        return -TARGET_EFAULT;
+
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (put_user_u32(addrlen, target_addrlen_addr))
+            ret = -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* do_socketpair() Must return target values and target errnos. */
+static abi_long do_socketpair(int domain, int type, int protocol,
+                              abi_ulong target_tab_addr)
+{
+    int tab[2];
+    abi_long ret;
+
+    ret = get_errno(socketpair(domain, type, protocol, tab));
+    if (!is_error(ret)) {
+        if (put_user_s32(tab[0], target_tab_addr)
+            || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0])))
+            ret = -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* do_sendto() Must return target values and target errnos. */
+static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
+                          abi_ulong target_addr, socklen_t addrlen)
+{
+    void *addr;
+    void *host_msg;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    host_msg = lock_user(VERIFY_READ, msg, len, 1);
+    if (!host_msg)
+        return -TARGET_EFAULT;
+    if (target_addr) {
+        addr = alloca(addrlen);
+        ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+        if (ret) {
+            unlock_user(host_msg, msg, 0);
+            return ret;
+        }
+        ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen));
+    } else {
+        ret = get_errno(send(fd, host_msg, len, flags));
+    }
+    unlock_user(host_msg, msg, 0);
+    return ret;
+}
+
+/* do_recvfrom() Must return target values and target errnos. */
+static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
+                            abi_ulong target_addr,
+                            abi_ulong target_addrlen)
+{
+    socklen_t addrlen;
+    void *addr;
+    void *host_msg;
+    abi_long ret;
+
+    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
+    if (!host_msg)
+        return -TARGET_EFAULT;
+    if (target_addr) {
+        if (get_user_u32(addrlen, target_addrlen)) {
+            ret = -TARGET_EFAULT;
+            goto fail;
+        }
+        if ((int)addrlen < 0) {
+            ret = -TARGET_EINVAL;
+            goto fail;
+        }
+        addr = alloca(addrlen);
+        ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
+    } else {
+        addr = NULL; /* To keep compiler quiet.  */
+        ret = get_errno(qemu_recv(fd, host_msg, len, flags));
+    }
+    if (!is_error(ret)) {
+        if (target_addr) {
+            host_to_target_sockaddr(target_addr, addr, addrlen);
+            if (put_user_u32(addrlen, target_addrlen)) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+        }
+        unlock_user(host_msg, msg, len);
+    } else {
+fail:
+        unlock_user(host_msg, msg, 0);
+    }
+    return ret;
+}
+
+#ifdef TARGET_NR_socketcall
+/* do_socketcall() Must return target values and target errnos. */
+static abi_long do_socketcall(int num, abi_ulong vptr)
+{
+    abi_long ret;
+    const int n = sizeof(abi_ulong);
+
+    switch(num) {
+    case SOCKOP_socket:
+	{
+            abi_ulong domain, type, protocol;
+
+            if (get_user_ual(domain, vptr)
+                || get_user_ual(type, vptr + n)
+                || get_user_ual(protocol, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_socket(domain, type, protocol);
+	}
+        break;
+    case SOCKOP_bind:
+	{
+            abi_ulong sockfd;
+            abi_ulong target_addr;
+            socklen_t addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(target_addr, vptr + n)
+                || get_user_ual(addrlen, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_bind(sockfd, target_addr, addrlen);
+        }
+        break;
+    case SOCKOP_connect:
+        {
+            abi_ulong sockfd;
+            abi_ulong target_addr;
+            socklen_t addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(target_addr, vptr + n)
+                || get_user_ual(addrlen, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_connect(sockfd, target_addr, addrlen);
+        }
+        break;
+    case SOCKOP_listen:
+        {
+            abi_ulong sockfd, backlog;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(backlog, vptr + n))
+                return -TARGET_EFAULT;
+
+            ret = get_errno(listen(sockfd, backlog));
+        }
+        break;
+    case SOCKOP_accept:
+        {
+            abi_ulong sockfd;
+            abi_ulong target_addr, target_addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(target_addr, vptr + n)
+                || get_user_ual(target_addrlen, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_accept(sockfd, target_addr, target_addrlen);
+        }
+        break;
+    case SOCKOP_getsockname:
+        {
+            abi_ulong sockfd;
+            abi_ulong target_addr, target_addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(target_addr, vptr + n)
+                || get_user_ual(target_addrlen, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_getsockname(sockfd, target_addr, target_addrlen);
+        }
+        break;
+    case SOCKOP_getpeername:
+        {
+            abi_ulong sockfd;
+            abi_ulong target_addr, target_addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(target_addr, vptr + n)
+                || get_user_ual(target_addrlen, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_getpeername(sockfd, target_addr, target_addrlen);
+        }
+        break;
+    case SOCKOP_socketpair:
+        {
+            abi_ulong domain, type, protocol;
+            abi_ulong tab;
+
+            if (get_user_ual(domain, vptr)
+                || get_user_ual(type, vptr + n)
+                || get_user_ual(protocol, vptr + 2 * n)
+                || get_user_ual(tab, vptr + 3 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_socketpair(domain, type, protocol, tab);
+        }
+        break;
+    case SOCKOP_send:
+        {
+            abi_ulong sockfd;
+            abi_ulong msg;
+            size_t len;
+            abi_ulong flags;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(msg, vptr + n)
+                || get_user_ual(len, vptr + 2 * n)
+                || get_user_ual(flags, vptr + 3 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_sendto(sockfd, msg, len, flags, 0, 0);
+        }
+        break;
+    case SOCKOP_recv:
+        {
+            abi_ulong sockfd;
+            abi_ulong msg;
+            size_t len;
+            abi_ulong flags;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(msg, vptr + n)
+                || get_user_ual(len, vptr + 2 * n)
+                || get_user_ual(flags, vptr + 3 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_recvfrom(sockfd, msg, len, flags, 0, 0);
+        }
+        break;
+    case SOCKOP_sendto:
+        {
+            abi_ulong sockfd;
+            abi_ulong msg;
+            size_t len;
+            abi_ulong flags;
+            abi_ulong addr;
+            socklen_t addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(msg, vptr + n)
+                || get_user_ual(len, vptr + 2 * n)
+                || get_user_ual(flags, vptr + 3 * n)
+                || get_user_ual(addr, vptr + 4 * n)
+                || get_user_ual(addrlen, vptr + 5 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_sendto(sockfd, msg, len, flags, addr, addrlen);
+        }
+        break;
+    case SOCKOP_recvfrom:
+        {
+            abi_ulong sockfd;
+            abi_ulong msg;
+            size_t len;
+            abi_ulong flags;
+            abi_ulong addr;
+            socklen_t addrlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(msg, vptr + n)
+                || get_user_ual(len, vptr + 2 * n)
+                || get_user_ual(flags, vptr + 3 * n)
+                || get_user_ual(addr, vptr + 4 * n)
+                || get_user_ual(addrlen, vptr + 5 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen);
+        }
+        break;
+    case SOCKOP_shutdown:
+        {
+            abi_ulong sockfd, how;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(how, vptr + n))
+                return -TARGET_EFAULT;
+
+            ret = get_errno(shutdown(sockfd, how));
+        }
+        break;
+    case SOCKOP_sendmsg:
+    case SOCKOP_recvmsg:
+        {
+            abi_ulong fd;
+            abi_ulong target_msg;
+            abi_ulong flags;
+
+            if (get_user_ual(fd, vptr)
+                || get_user_ual(target_msg, vptr + n)
+                || get_user_ual(flags, vptr + 2 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_sendrecvmsg(fd, target_msg, flags,
+                                 (num == SOCKOP_sendmsg));
+        }
+        break;
+    case SOCKOP_setsockopt:
+        {
+            abi_ulong sockfd;
+            abi_ulong level;
+            abi_ulong optname;
+            abi_ulong optval;
+            socklen_t optlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(level, vptr + n)
+                || get_user_ual(optname, vptr + 2 * n)
+                || get_user_ual(optval, vptr + 3 * n)
+                || get_user_ual(optlen, vptr + 4 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_setsockopt(sockfd, level, optname, optval, optlen);
+        }
+        break;
+    case SOCKOP_getsockopt:
+        {
+            abi_ulong sockfd;
+            abi_ulong level;
+            abi_ulong optname;
+            abi_ulong optval;
+            socklen_t optlen;
+
+            if (get_user_ual(sockfd, vptr)
+                || get_user_ual(level, vptr + n)
+                || get_user_ual(optname, vptr + 2 * n)
+                || get_user_ual(optval, vptr + 3 * n)
+                || get_user_ual(optlen, vptr + 4 * n))
+                return -TARGET_EFAULT;
+
+            ret = do_getsockopt(sockfd, level, optname, optval, optlen);
+        }
+        break;
+    default:
+        gemu_log("Unsupported socketcall: %d\n", num);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+#endif
+
+#define N_SHM_REGIONS	32
+
+static struct shm_region {
+    abi_ulong	start;
+    abi_ulong	size;
+} shm_regions[N_SHM_REGIONS];
+
+struct target_ipc_perm
+{
+    abi_long __key;
+    abi_ulong uid;
+    abi_ulong gid;
+    abi_ulong cuid;
+    abi_ulong cgid;
+    unsigned short int mode;
+    unsigned short int __pad1;
+    unsigned short int __seq;
+    unsigned short int __pad2;
+    abi_ulong __unused1;
+    abi_ulong __unused2;
+};
+
+struct target_semid_ds
+{
+  struct target_ipc_perm sem_perm;
+  abi_ulong sem_otime;
+  abi_ulong __unused1;
+  abi_ulong sem_ctime;
+  abi_ulong __unused2;
+  abi_ulong sem_nsems;
+  abi_ulong __unused3;
+  abi_ulong __unused4;
+};
+
+static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+                                               abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    target_ip = &(target_sd->sem_perm);
+    host_ip->__key = tswapl(target_ip->__key);
+    host_ip->uid = tswapl(target_ip->uid);
+    host_ip->gid = tswapl(target_ip->gid);
+    host_ip->cuid = tswapl(target_ip->cuid);
+    host_ip->cgid = tswapl(target_ip->cgid);
+    host_ip->mode = tswapl(target_ip->mode);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+                                               struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    target_ip = &(target_sd->sem_perm);
+    target_ip->__key = tswapl(host_ip->__key);
+    target_ip->uid = tswapl(host_ip->uid);
+    target_ip->gid = tswapl(host_ip->gid);
+    target_ip->cuid = tswapl(host_ip->cuid);
+    target_ip->cgid = tswapl(host_ip->cgid);
+    target_ip->mode = tswapl(host_ip->mode);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+                                               abi_ulong target_addr)
+{
+    struct target_semid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+        return -TARGET_EFAULT;
+    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapl(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
+                                               struct semid_ds *host_sd)
+{
+    struct target_semid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+        return -TARGET_EFAULT;;
+    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapl(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                              struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
+union semun {
+	int val;
+	struct semid_ds *buf;
+	unsigned short *array;
+	struct seminfo *__buf;
+};
+
+union target_semun {
+	int val;
+	abi_ulong buf;
+	abi_ulong array;
+	abi_ulong __buf;
+};
+
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+                                               abi_ulong target_addr)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = malloc(nsems*sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems*sizeof(unsigned short), 1);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                               unsigned short **host_array)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems*sizeof(unsigned short), 0);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
+    }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+
+    return 0;
+}
+
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+                                 union target_semun target_su)
+{
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    struct seminfo seminfo;
+    abi_long ret = -TARGET_EINVAL;
+    abi_long err;
+    cmd &= 0xff;
+
+    switch( cmd ) {
+	case GETVAL:
+	case SETVAL:
+            arg.val = tswapl(target_su.val);
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            target_su.val = tswapl(arg.val);
+            break;
+	case GETALL:
+	case SETALL:
+            err = target_to_host_semarray(semid, &array, target_su.array);
+            if (err)
+                return err;
+            arg.array = array;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_semarray(semid, target_su.array, &array);
+            if (err)
+                return err;
+            break;
+	case IPC_STAT:
+	case IPC_SET:
+	case SEM_STAT:
+            err = target_to_host_semid_ds(&dsarg, target_su.buf);
+            if (err)
+                return err;
+            arg.buf = &dsarg;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_semid_ds(target_su.buf, &dsarg);
+            if (err)
+                return err;
+            break;
+	case IPC_INFO:
+	case SEM_INFO:
+            arg.__buf = &seminfo;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_seminfo(target_su.__buf, &seminfo);
+            if (err)
+                return err;
+            break;
+	case IPC_RMID:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+            ret = get_errno(semctl(semid, semnum, cmd, NULL));
+            break;
+    }
+
+    return ret;
+}
+
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                             abi_ulong target_addr,
+                                             unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops*sizeof(struct target_sembuf), 1);
+    if (!target_sembuf)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsops; i++) {
+        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+
+    unlock_user(target_sembuf, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+
+    if (target_to_host_sembuf(sops, ptr, nsops))
+        return -TARGET_EFAULT;
+
+    return semop(semid, sops, nsops);
+}
+
+struct target_msqid_ds
+{
+    struct target_ipc_perm msg_perm;
+    abi_ulong msg_stime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong msg_rtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong msg_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    abi_ulong __msg_cbytes;
+    abi_ulong msg_qnum;
+    abi_ulong msg_qbytes;
+    abi_ulong msg_lspid;
+    abi_ulong msg_lrpid;
+    abi_ulong __unused4;
+    abi_ulong __unused5;
+};
+
+static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+                                               abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
+        return -TARGET_EFAULT;
+    host_md->msg_stime = tswapl(target_md->msg_stime);
+    host_md->msg_rtime = tswapl(target_md->msg_rtime);
+    host_md->msg_ctime = tswapl(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapl(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapl(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+                                               struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
+        return -TARGET_EFAULT;
+    target_md->msg_stime = tswapl(host_md->msg_stime);
+    target_md->msg_rtime = tswapl(host_md->msg_rtime);
+    target_md->msg_ctime = tswapl(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapl(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapl(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 1);
+    return 0;
+}
+
+struct target_msginfo {
+    int msgpool;
+    int msgmap;
+    int msgmax;
+    int msgmnb;
+    int msgmni;
+    int msgssz;
+    int msgtql;
+    unsigned short int msgseg;
+};
+
+static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
+                                              struct msginfo *host_msginfo)
+{
+    struct target_msginfo *target_msginfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
+    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
+    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
+    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
+    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
+    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
+    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
+    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
+    unlock_user_struct(target_msginfo, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
+{
+    struct msqid_ds dsarg;
+    struct msginfo msginfo;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case MSG_STAT:
+        if (target_to_host_msqid_ds(&dsarg,ptr))
+            return -TARGET_EFAULT;
+        ret = get_errno(msgctl(msgid, cmd, &dsarg));
+        if (host_to_target_msqid_ds(ptr,&dsarg))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_RMID:
+        ret = get_errno(msgctl(msgid, cmd, NULL));
+        break;
+    case IPC_INFO:
+    case MSG_INFO:
+        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
+        if (host_to_target_msginfo(ptr, &msginfo))
+            return -TARGET_EFAULT;
+        break;
+    }
+
+    return ret;
+}
+
+struct target_msgbuf {
+    abi_long mtype;
+    char	mtext[1];
+};
+
+static inline abi_long do_msgsnd(int msqid, abi_long msgp,
+                                 unsigned int msgsz, int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct msgbuf *host_mb;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
+        return -TARGET_EFAULT;
+    host_mb = malloc(msgsz+sizeof(long));
+    host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
+    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+    free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
+static inline abi_long do_msgrcv(int msqid, abi_long msgp,
+                                 unsigned int msgsz, abi_long msgtyp,
+                                 int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    char *target_mtext;
+    struct msgbuf *host_mb;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
+        return -TARGET_EFAULT;
+
+    host_mb = malloc(msgsz+sizeof(long));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
+
+    if (ret > 0) {
+        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
+        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
+        if (!target_mtext) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+
+    target_mb->mtype = tswapl(host_mb->mtype);
+    free(host_mb);
+
+end:
+    if (target_mb)
+        unlock_user_struct(target_mb, msgp, 1);
+    return ret;
+}
+
+struct target_shmid_ds
+{
+    struct target_ipc_perm shm_perm;
+    abi_ulong shm_segsz;
+    abi_ulong shm_atime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong shm_dtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong shm_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    int shm_cpid;
+    int shm_lpid;
+    abi_ulong shm_nattch;
+    unsigned long int __unused4;
+    unsigned long int __unused5;
+};
+
+static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                               abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
+        return -TARGET_EFAULT;
+    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                               struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
+        return -TARGET_EFAULT;
+    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct  target_shminfo {
+    abi_ulong shmmax;
+    abi_ulong shmmin;
+    abi_ulong shmmni;
+    abi_ulong shmseg;
+    abi_ulong shmall;
+};
+
+static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
+                                              struct shminfo *host_shminfo)
+{
+    struct target_shminfo *target_shminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+    unlock_user_struct(target_shminfo, target_addr, 1);
+    return 0;
+}
+
+struct target_shm_info {
+    int used_ids;
+    abi_ulong shm_tot;
+    abi_ulong shm_rss;
+    abi_ulong shm_swp;
+    abi_ulong swap_attempts;
+    abi_ulong swap_successes;
+};
+
+static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
+                                               struct shm_info *host_shm_info)
+{
+    struct target_shm_info *target_shm_info;
+    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
+    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
+    unlock_user_struct(target_shm_info, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
+{
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch(cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SHM_STAT:
+        if (target_to_host_shmid_ds(&dsarg, buf))
+            return -TARGET_EFAULT;
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buf, &dsarg))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (host_to_target_shminfo(buf, &shminfo))
+            return -TARGET_EFAULT;
+        break;
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (host_to_target_shm_info(buf, &shm_info))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+    }
+
+    return ret;
+}
+
+static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_long raddr;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i,ret;
+
+    /* find out the length of the shared memory segment */
+    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
+    if (is_error(ret)) {
+        /* can't get length, bail out */
+        return ret;
+    }
+
+    mmap_lock();
+
+    if (shmaddr)
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+    else {
+        abi_ulong mmap_start;
+
+        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            host_raddr = (void *)-1;
+        } else
+            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
+    }
+
+    if (host_raddr == (void *)-1) {
+        mmap_unlock();
+        return get_errno((long)host_raddr);
+    }
+    raddr=h2g((unsigned long)host_raddr);
+
+    page_set_flags(raddr, raddr + shm_info.shm_segsz,
+                   PAGE_VALID | PAGE_READ |
+                   ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
+
+    for (i = 0; i < N_SHM_REGIONS; i++) {
+        if (shm_regions[i].start == 0) {
+            shm_regions[i].start = raddr;
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+
+}
+
+static inline abi_long do_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].start == shmaddr) {
+            shm_regions[i].start = 0;
+            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
+#ifdef TARGET_NR_ipc
+/* ??? This only works with linear mappings.  */
+/* do_ipc() must return target values and target errnos. */
+static abi_long do_ipc(unsigned int call, int first,
+                       int second, int third,
+                       abi_long ptr, abi_long fifth)
+{
+    int version;
+    abi_long ret = 0;
+
+    version = call >> 16;
+    call &= 0xffff;
+
+    switch (call) {
+    case IPCOP_semop:
+        ret = do_semop(first, ptr, second);
+        break;
+
+    case IPCOP_semget:
+        ret = get_errno(semget(first, second, third));
+        break;
+
+    case IPCOP_semctl:
+        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
+        break;
+
+    case IPCOP_msgget:
+        ret = get_errno(msgget(first, second));
+        break;
+
+    case IPCOP_msgsnd:
+        ret = do_msgsnd(first, ptr, second, third);
+        break;
+
+    case IPCOP_msgctl:
+        ret = do_msgctl(first, second, ptr);
+        break;
+
+    case IPCOP_msgrcv:
+        switch (version) {
+        case 0:
+            {
+                struct target_ipc_kludge {
+                    abi_long msgp;
+                    abi_long msgtyp;
+                } *tmp;
+
+                if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
+                    ret = -TARGET_EFAULT;
+                    break;
+                }
+
+                ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
+
+                unlock_user_struct(tmp, ptr, 0);
+                break;
+            }
+        default:
+            ret = do_msgrcv(first, ptr, second, fifth, third);
+        }
+        break;
+
+    case IPCOP_shmat:
+        switch (version) {
+        default:
+        {
+            abi_ulong raddr;
+            raddr = do_shmat(first, ptr, second);
+            if (is_error(raddr))
+                return get_errno(raddr);
+            if (put_user_ual(raddr, third))
+                return -TARGET_EFAULT;
+            break;
+        }
+        case 1:
+            ret = -TARGET_EINVAL;
+            break;
+        }
+	break;
+    case IPCOP_shmdt:
+        ret = do_shmdt(ptr);
+	break;
+
+    case IPCOP_shmget:
+	/* IPC_* flag values are the same on all linux platforms */
+	ret = get_errno(shmget(first, second, third));
+	break;
+
+	/* IPC_* and SHM_* command values are the same on all linux platforms */
+    case IPCOP_shmctl:
+        ret = do_shmctl(first, second, third);
+        break;
+    default:
+	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+	ret = -TARGET_ENOSYS;
+	break;
+    }
+    return ret;
+}
+#endif
+
+/* kernel structure types definitions */
+
+#define STRUCT(name, ...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "syscall_types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = {  __VA_ARGS__, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "syscall_types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+typedef struct IOCTLEntry IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
+                             int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
+    unsigned int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    do_ioctl_fn *do_ioctl;
+    const argtype arg_type[5];
+};
+
+#define IOC_R 0x0001
+#define IOC_W 0x0002
+#define IOC_RW (IOC_R | IOC_W)
+
+#define MAX_STRUCT_SIZE 4096
+
+#ifdef CONFIG_FIEMAP
+/* So fiemap access checks don't overflow on 32 bit systems.
+ * This is very slightly smaller than the limit imposed by
+ * the underlying kernel.
+ */
+#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
+                            / sizeof(struct fiemap_extent))
+
+static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                       int fd, abi_long cmd, abi_long arg)
+{
+    /* The parameter for this ioctl is a struct fiemap followed
+     * by an array of struct fiemap_extent whose size is set
+     * in fiemap->fm_extent_count. The array is filled in by the
+     * ioctl.
+     */
+    int target_size_in, target_size_out;
+    struct fiemap *fm;
+    const argtype *arg_type = ie->arg_type;
+    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
+    void *argptr, *p;
+    abi_long ret;
+    int i, extent_size = thunk_type_size(extent_arg_type, 0);
+    uint32_t outbufsz;
+    int free_fm = 0;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+    arg_type++;
+    target_size_in = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+    fm = (struct fiemap *)buf_temp;
+    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
+        return -TARGET_EINVAL;
+    }
+
+    outbufsz = sizeof (*fm) +
+        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
+
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /* We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        fm = malloc(outbufsz);
+        if (!fm) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(fm, buf_temp, sizeof(struct fiemap));
+        free_fm = 1;
+    }
+    ret = get_errno(ioctl(fd, ie->host_cmd, fm));
+    if (!is_error(ret)) {
+        target_size_out = target_size_in;
+        /* An extent_count of 0 means we were only counting the extents
+         * so there are no structs to copy
+         */
+        if (fm->fm_extent_count != 0) {
+            target_size_out += fm->fm_mapped_extents * extent_size;
+        }
+        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
+        if (!argptr) {
+            ret = -TARGET_EFAULT;
+        } else {
+            /* Convert the struct fiemap */
+            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
+            if (fm->fm_extent_count != 0) {
+                p = argptr + target_size_in;
+                /* ...and then all the struct fiemap_extents */
+                for (i = 0; i < fm->fm_mapped_extents; i++) {
+                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
+                                  THUNK_TARGET);
+                    p += extent_size;
+                }
+            }
+            unlock_user(argptr, arg, target_size_out);
+        }
+    }
+    if (free_fm) {
+        free(fm);
+    }
+    return ret;
+}
+#endif
+
+static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                int fd, abi_long cmd, abi_long arg)
+{
+    const argtype *arg_type = ie->arg_type;
+    int target_size;
+    void *argptr;
+    int ret;
+    struct ifconf *host_ifconf;
+    uint32_t outbufsz;
+    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
+    int target_ifreq_size;
+    int nb_ifreq;
+    int free_buf = 0;
+    int i;
+    int target_ifc_len;
+    abi_long target_ifc_buf;
+    int host_ifc_len;
+    char *host_ifc_buf;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+
+    arg_type++;
+    target_size = thunk_type_size(arg_type, 0);
+
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr)
+        return -TARGET_EFAULT;
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
+    target_ifc_len = host_ifconf->ifc_len;
+    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
+
+    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
+    nb_ifreq = target_ifc_len / target_ifreq_size;
+    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
+
+    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /* We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        host_ifconf = malloc(outbufsz);
+        if (!host_ifconf) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
+        free_buf = 1;
+    }
+    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
+
+    host_ifconf->ifc_len = host_ifc_len;
+    host_ifconf->ifc_buf = host_ifc_buf;
+
+    ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
+    if (!is_error(ret)) {
+	/* convert host ifc_len to target ifc_len */
+
+        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
+        target_ifc_len = nb_ifreq * target_ifreq_size;
+        host_ifconf->ifc_len = target_ifc_len;
+
+	/* restore target ifc_buf */
+
+        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
+
+	/* copy struct ifconf to target user */
+
+        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+        if (!argptr)
+            return -TARGET_EFAULT;
+        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
+        unlock_user(argptr, arg, target_size);
+
+	/* copy ifreq[] to target user */
+
+        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
+        for (i = 0; i < nb_ifreq ; i++) {
+            thunk_convert(argptr + i * target_ifreq_size,
+                          host_ifc_buf + i * sizeof(struct ifreq),
+                          ifreq_arg_type, THUNK_TARGET);
+        }
+        unlock_user(argptr, target_ifc_buf, target_ifc_len);
+    }
+
+    if (free_buf) {
+        free(host_ifconf);
+    }
+
+    return ret;
+}
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access, ...) \
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
+#include "ioctls.h"
+    { 0, 0, },
+};
+
+/* ??? Implement proper locking for ioctls.  */
+/* do_ioctl() Must return target values and target errnos. */
+static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
+{
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    abi_long ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    ie = ioctl_entries;
+    for(;;) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
+            return -TARGET_ENOSYS;
+        }
+        if (ie->target_cmd == cmd)
+            break;
+        ie++;
+    }
+    arg_type = ie->arg_type;
+#if defined(DEBUG)
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
+#endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
+    switch(arg_type[0]) {
+    case TYPE_NULL:
+        /* no argument */
+        ret = get_errno(ioctl(fd, ie->host_cmd));
+        break;
+    case TYPE_PTRVOID:
+    case TYPE_INT:
+        /* int argment */
+        ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+        break;
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch(ie->access) {
+        case IOC_R:
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr)
+                    return -TARGET_EFAULT;
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        case IOC_W:
+            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+            if (!argptr)
+                return -TARGET_EFAULT;
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+        default:
+        case IOC_RW:
+            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+            if (!argptr)
+                return -TARGET_EFAULT;
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr)
+                    return -TARGET_EFAULT;
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+                 (long)cmd, arg_type[0]);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+static const bitmask_transtbl iflag_tbl[] = {
+        { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
+        { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
+        { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
+        { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
+        { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
+        { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
+        { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
+        { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
+        { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
+        { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
+        { TARGET_IXON, TARGET_IXON, IXON, IXON },
+        { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
+        { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
+        { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
+        { 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl oflag_tbl[] = {
+	{ TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
+	{ TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
+	{ TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
+	{ TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
+	{ TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
+	{ TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
+	{ TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
+	{ TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
+	{ TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
+	{ TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
+	{ TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
+	{ TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
+	{ TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
+	{ TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
+	{ TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
+	{ TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
+	{ TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
+	{ TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
+	{ TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
+	{ TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
+	{ TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
+	{ TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
+	{ TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
+	{ TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
+	{ 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl cflag_tbl[] = {
+	{ TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
+	{ TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
+	{ TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
+	{ TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
+	{ TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
+	{ TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
+	{ TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
+	{ TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
+	{ TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
+	{ TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
+	{ TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
+	{ TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
+	{ TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
+	{ TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
+	{ TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
+	{ TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
+	{ TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
+	{ TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
+	{ TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
+	{ TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
+	{ TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
+	{ TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
+	{ TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
+	{ TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
+	{ TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
+	{ TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
+	{ TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
+	{ TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
+	{ TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
+	{ TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
+	{ TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
+	{ 0, 0, 0, 0 }
+};
+
+static const bitmask_transtbl lflag_tbl[] = {
+	{ TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
+	{ TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
+	{ TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
+	{ TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
+	{ TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
+	{ TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
+	{ TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
+	{ TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
+	{ TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
+	{ TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
+	{ TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
+	{ TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
+	{ TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
+	{ TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
+	{ TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
+	{ 0, 0, 0, 0 }
+};
+
+static void target_to_host_termios (void *dst, const void *src)
+{
+    struct host_termios *host = dst;
+    const struct target_termios *target = src;
+
+    host->c_iflag =
+        target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
+    host->c_oflag =
+        target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
+    host->c_cflag =
+        target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
+    host->c_lflag =
+        target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
+    host->c_line = target->c_line;
+
+    memset(host->c_cc, 0, sizeof(host->c_cc));
+    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
+    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
+    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
+    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
+    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
+    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
+    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
+    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
+    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
+    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
+    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
+    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
+    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
+    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
+    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
+    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
+    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
+}
+
+static void host_to_target_termios (void *dst, const void *src)
+{
+    struct target_termios *target = dst;
+    const struct host_termios *host = src;
+
+    target->c_iflag =
+        tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
+    target->c_oflag =
+        tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
+    target->c_cflag =
+        tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
+    target->c_lflag =
+        tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
+    target->c_line = host->c_line;
+
+    memset(target->c_cc, 0, sizeof(target->c_cc));
+    target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
+    target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
+    target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
+    target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
+    target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
+    target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
+    target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
+    target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
+    target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
+    target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
+    target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
+    target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
+    target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
+    target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
+    target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
+    target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
+    target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
+}
+
+static const StructEntry struct_termios_def = {
+    .convert = { host_to_target_termios, target_to_host_termios },
+    .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
+    .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
+};
+
+static bitmask_transtbl mmap_flags_tbl[] = {
+	{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
+	{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
+	{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
+	{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
+	{ TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
+	{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
+	{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
+	{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
+	{ 0, 0, 0, 0 }
+};
+
+#if defined(TARGET_I386)
+
+/* NOTE: there is really one LDT for all the threads */
+static uint8_t *ldt_table;
+
+static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
+{
+    int size;
+    void *p;
+
+    if (!ldt_table)
+        return 0;
+    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
+    if (size > bytecount)
+        size = bytecount;
+    p = lock_user(VERIFY_WRITE, ptr, size, 0);
+    if (!p)
+        return -TARGET_EFAULT;
+    /* ??? Should this by byteswapped?  */
+    memcpy(p, ldt_table, size);
+    unlock_user(p, ptr, size);
+    return size;
+}
+
+/* XXX: add locking support */
+static abi_long write_ldt(CPUX86State *env,
+                          abi_ulong ptr, unsigned long bytecount, int oldmode)
+{
+    struct target_modify_ldt_ldt_s ldt_info;
+    struct target_modify_ldt_ldt_s *target_ldt_info;
+    int seg_32bit, contents, read_exec_only, limit_in_pages;
+    int seg_not_present, useable, lm;
+    uint32_t *lp, entry_1, entry_2;
+
+    if (bytecount != sizeof(ldt_info))
+        return -TARGET_EINVAL;
+    if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
+        return -TARGET_EFAULT;
+    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
+    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.limit = tswap32(target_ldt_info->limit);
+    ldt_info.flags = tswap32(target_ldt_info->flags);
+    unlock_user_struct(target_ldt_info, ptr, 0);
+
+    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
+        return -TARGET_EINVAL;
+    seg_32bit = ldt_info.flags & 1;
+    contents = (ldt_info.flags >> 1) & 3;
+    read_exec_only = (ldt_info.flags >> 3) & 1;
+    limit_in_pages = (ldt_info.flags >> 4) & 1;
+    seg_not_present = (ldt_info.flags >> 5) & 1;
+    useable = (ldt_info.flags >> 6) & 1;
+#ifdef TARGET_ABI32
+    lm = 0;
+#else
+    lm = (ldt_info.flags >> 7) & 1;
+#endif
+    if (contents == 3) {
+        if (oldmode)
+            return -TARGET_EINVAL;
+        if (seg_not_present == 0)
+            return -TARGET_EINVAL;
+    }
+    /* allocate the LDT */
+    if (!ldt_table) {
+        env->ldt.base = target_mmap(0,
+                                    TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
+                                    PROT_READ|PROT_WRITE,
+                                    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+        if (env->ldt.base == -1)
+            return -TARGET_ENOMEM;
+        memset(g2h(env->ldt.base), 0,
+               TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
+        env->ldt.limit = 0xffff;
+        ldt_table = g2h(env->ldt.base);
+    }
+
+    /* NOTE: same code as Linux kernel */
+    /* Allow LDTs to be cleared by the user. */
+    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+        if (oldmode ||
+            (contents == 0		&&
+             read_exec_only == 1	&&
+             seg_32bit == 0		&&
+             limit_in_pages == 0	&&
+             seg_not_present == 1	&&
+             useable == 0 )) {
+            entry_1 = 0;
+            entry_2 = 0;
+            goto install;
+        }
+    }
+
+    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+        (ldt_info.limit & 0x0ffff);
+    entry_2 = (ldt_info.base_addr & 0xff000000) |
+        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+        (ldt_info.limit & 0xf0000) |
+        ((read_exec_only ^ 1) << 9) |
+        (contents << 10) |
+        ((seg_not_present ^ 1) << 15) |
+        (seg_32bit << 22) |
+        (limit_in_pages << 23) |
+        (lm << 21) |
+        0x7000;
+    if (!oldmode)
+        entry_2 |= (useable << 20);
+
+    /* Install the new entry ...  */
+install:
+    lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
+    lp[0] = tswap32(entry_1);
+    lp[1] = tswap32(entry_2);
+    return 0;
+}
+
+/* specific and weird i386 syscalls */
+static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
+                              unsigned long bytecount)
+{
+    abi_long ret;
+
+    switch (func) {
+    case 0:
+        ret = read_ldt(ptr, bytecount);
+        break;
+    case 1:
+        ret = write_ldt(env, ptr, bytecount, 1);
+        break;
+    case 0x11:
+        ret = write_ldt(env, ptr, bytecount, 0);
+        break;
+    default:
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
+
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
+{
+    uint64_t *gdt_table = g2h(env->gdt.base);
+    struct target_modify_ldt_ldt_s ldt_info;
+    struct target_modify_ldt_ldt_s *target_ldt_info;
+    int seg_32bit, contents, read_exec_only, limit_in_pages;
+    int seg_not_present, useable, lm;
+    uint32_t *lp, entry_1, entry_2;
+    int i;
+
+    lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
+    if (!target_ldt_info)
+        return -TARGET_EFAULT;
+    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
+    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.limit = tswap32(target_ldt_info->limit);
+    ldt_info.flags = tswap32(target_ldt_info->flags);
+    if (ldt_info.entry_number == -1) {
+        for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) {
+            if (gdt_table[i] == 0) {
+                ldt_info.entry_number = i;
+                target_ldt_info->entry_number = tswap32(i);
+                break;
+            }
+        }
+    }
+    unlock_user_struct(target_ldt_info, ptr, 1);
+
+    if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || 
+        ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
+           return -TARGET_EINVAL;
+    seg_32bit = ldt_info.flags & 1;
+    contents = (ldt_info.flags >> 1) & 3;
+    read_exec_only = (ldt_info.flags >> 3) & 1;
+    limit_in_pages = (ldt_info.flags >> 4) & 1;
+    seg_not_present = (ldt_info.flags >> 5) & 1;
+    useable = (ldt_info.flags >> 6) & 1;
+#ifdef TARGET_ABI32
+    lm = 0;
+#else
+    lm = (ldt_info.flags >> 7) & 1;
+#endif
+
+    if (contents == 3) {
+        if (seg_not_present == 0)
+            return -TARGET_EINVAL;
+    }
+
+    /* NOTE: same code as Linux kernel */
+    /* Allow LDTs to be cleared by the user. */
+    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+        if ((contents == 0             &&
+             read_exec_only == 1       &&
+             seg_32bit == 0            &&
+             limit_in_pages == 0       &&
+             seg_not_present == 1      &&
+             useable == 0 )) {
+            entry_1 = 0;
+            entry_2 = 0;
+            goto install;
+        }
+    }
+
+    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+        (ldt_info.limit & 0x0ffff);
+    entry_2 = (ldt_info.base_addr & 0xff000000) |
+        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+        (ldt_info.limit & 0xf0000) |
+        ((read_exec_only ^ 1) << 9) |
+        (contents << 10) |
+        ((seg_not_present ^ 1) << 15) |
+        (seg_32bit << 22) |
+        (limit_in_pages << 23) |
+        (useable << 20) |
+        (lm << 21) |
+        0x7000;
+
+    /* Install the new entry ...  */
+install:
+    lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
+    lp[0] = tswap32(entry_1);
+    lp[1] = tswap32(entry_2);
+    return 0;
+}
+
+static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
+{
+    struct target_modify_ldt_ldt_s *target_ldt_info;
+    uint64_t *gdt_table = g2h(env->gdt.base);
+    uint32_t base_addr, limit, flags;
+    int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
+    int seg_not_present, useable, lm;
+    uint32_t *lp, entry_1, entry_2;
+
+    lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
+    if (!target_ldt_info)
+        return -TARGET_EFAULT;
+    idx = tswap32(target_ldt_info->entry_number);
+    if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
+        idx > TARGET_GDT_ENTRY_TLS_MAX) {
+        unlock_user_struct(target_ldt_info, ptr, 1);
+        return -TARGET_EINVAL;
+    }
+    lp = (uint32_t *)(gdt_table + idx);
+    entry_1 = tswap32(lp[0]);
+    entry_2 = tswap32(lp[1]);
+    
+    read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
+    contents = (entry_2 >> 10) & 3;
+    seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
+    seg_32bit = (entry_2 >> 22) & 1;
+    limit_in_pages = (entry_2 >> 23) & 1;
+    useable = (entry_2 >> 20) & 1;
+#ifdef TARGET_ABI32
+    lm = 0;
+#else
+    lm = (entry_2 >> 21) & 1;
+#endif
+    flags = (seg_32bit << 0) | (contents << 1) |
+        (read_exec_only << 3) | (limit_in_pages << 4) |
+        (seg_not_present << 5) | (useable << 6) | (lm << 7);
+    limit = (entry_1 & 0xffff) | (entry_2  & 0xf0000);
+    base_addr = (entry_1 >> 16) | 
+        (entry_2 & 0xff000000) | 
+        ((entry_2 & 0xff) << 16);
+    target_ldt_info->base_addr = tswapl(base_addr);
+    target_ldt_info->limit = tswap32(limit);
+    target_ldt_info->flags = tswap32(flags);
+    unlock_user_struct(target_ldt_info, ptr, 1);
+    return 0;
+}
+#endif /* TARGET_I386 && TARGET_ABI32 */
+
+#ifndef TARGET_ABI32
+static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch(code) {
+    case TARGET_ARCH_SET_GS:
+    case TARGET_ARCH_SET_FS:
+        if (code == TARGET_ARCH_SET_GS)
+            idx = R_GS;
+        else
+            idx = R_FS;
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = addr;
+        break;
+    case TARGET_ARCH_GET_GS:
+    case TARGET_ARCH_GET_FS:
+        if (code == TARGET_ARCH_GET_GS)
+            idx = R_GS;
+        else
+            idx = R_FS;
+        val = env->segs[idx].base;
+        if (put_user(val, addr, abi_ulong))
+            ret = -TARGET_EFAULT;
+        break;
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+#endif
+
+#endif /* defined(TARGET_I386) */
+
+#define NEW_STACK_SIZE 0x40000
+
+#if defined(CONFIG_USE_NPTL)
+
+static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
+typedef struct {
+    CPUState *env;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_t thread;
+    uint32_t tid;
+    abi_ulong child_tidptr;
+    abi_ulong parent_tidptr;
+    sigset_t sigmask;
+} new_thread_info;
+
+static void *clone_func(void *arg)
+{
+    new_thread_info *info = arg;
+    CPUState *env;
+    TaskState *ts;
+
+    env = info->env;
+    thread_env = env;
+    ts = (TaskState *)thread_env->opaque;
+    info->tid = gettid();
+    env->host_tid = info->tid;
+    task_settid(ts);
+    if (info->child_tidptr)
+        put_user_u32(info->tid, info->child_tidptr);
+    if (info->parent_tidptr)
+        put_user_u32(info->tid, info->parent_tidptr);
+    /* Enable signals.  */
+    sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
+    /* Signal to the parent that we're ready.  */
+    pthread_mutex_lock(&info->mutex);
+    pthread_cond_broadcast(&info->cond);
+    pthread_mutex_unlock(&info->mutex);
+    /* Wait until the parent has finshed initializing the tls state.  */
+    pthread_mutex_lock(&clone_lock);
+    pthread_mutex_unlock(&clone_lock);
+    cpu_loop(env);
+    /* never exits */
+    return NULL;
+}
+#else
+
+static int clone_func(void *arg)
+{
+    CPUState *env = arg;
+    cpu_loop(env);
+    /* never exits */
+    return 0;
+}
+#endif
+
+/* do_fork() Must return host values and target errnos (unlike most
+   do_*() functions). */
+static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
+                   abi_ulong parent_tidptr, target_ulong newtls,
+                   abi_ulong child_tidptr)
+{
+    int ret;
+    TaskState *ts;
+    CPUState *new_env;
+#if defined(CONFIG_USE_NPTL)
+    unsigned int nptl_flags;
+    sigset_t sigmask;
+#else
+    uint8_t *new_stack;
+#endif
+
+    /* Emulate vfork() with fork() */
+    if (flags & CLONE_VFORK)
+        flags &= ~(CLONE_VFORK | CLONE_VM);
+
+    if (flags & CLONE_VM) {
+        TaskState *parent_ts = (TaskState *)env->opaque;
+#if defined(CONFIG_USE_NPTL)
+        new_thread_info info;
+        pthread_attr_t attr;
+#endif
+        ts = qemu_mallocz(sizeof(TaskState));
+        init_task_state(ts);
+        /* we create a new CPU instance. */
+        new_env = cpu_copy(env);
+#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
+        cpu_reset(new_env);
+#endif
+        /* Init regs that differ from the parent.  */
+        cpu_clone_regs(new_env, newsp);
+        new_env->opaque = ts;
+        ts->bprm = parent_ts->bprm;
+        ts->info = parent_ts->info;
+#if defined(CONFIG_USE_NPTL)
+        nptl_flags = flags;
+        flags &= ~CLONE_NPTL_FLAGS2;
+
+        if (nptl_flags & CLONE_CHILD_CLEARTID) {
+            ts->child_tidptr = child_tidptr;
+        }
+
+        if (nptl_flags & CLONE_SETTLS)
+            cpu_set_tls (new_env, newtls);
+
+        /* Grab a mutex so that thread setup appears atomic.  */
+        pthread_mutex_lock(&clone_lock);
+
+        memset(&info, 0, sizeof(info));
+        pthread_mutex_init(&info.mutex, NULL);
+        pthread_mutex_lock(&info.mutex);
+        pthread_cond_init(&info.cond, NULL);
+        info.env = new_env;
+        if (nptl_flags & CLONE_CHILD_SETTID)
+            info.child_tidptr = child_tidptr;
+        if (nptl_flags & CLONE_PARENT_SETTID)
+            info.parent_tidptr = parent_tidptr;
+
+        ret = pthread_attr_init(&attr);
+        ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+        /* It is not safe to deliver signals until the child has finished
+           initializing, so temporarily block all signals.  */
+        sigfillset(&sigmask);
+        sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
+
+        ret = pthread_create(&info.thread, &attr, clone_func, &info);
+        /* TODO: Free new CPU state if thread creation failed.  */
+
+        sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
+        pthread_attr_destroy(&attr);
+        if (ret == 0) {
+            /* Wait for the child to initialize.  */
+            pthread_cond_wait(&info.cond, &info.mutex);
+            ret = info.tid;
+            if (flags & CLONE_PARENT_SETTID)
+                put_user_u32(ret, parent_tidptr);
+        } else {
+            ret = -1;
+        }
+        pthread_mutex_unlock(&info.mutex);
+        pthread_cond_destroy(&info.cond);
+        pthread_mutex_destroy(&info.mutex);
+        pthread_mutex_unlock(&clone_lock);
+#else
+        if (flags & CLONE_NPTL_FLAGS2)
+            return -EINVAL;
+        /* This is probably going to die very quickly, but do it anyway.  */
+        new_stack = qemu_mallocz (NEW_STACK_SIZE);
+#ifdef __ia64__
+        ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
+#else
+	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+#endif
+#endif
+    } else {
+        /* if no CLONE_VM, we consider it is a fork */
+        if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
+            return -EINVAL;
+        fork_start();
+        ret = fork();
+        if (ret == 0) {
+            /* Child Process.  */
+            cpu_clone_regs(env, newsp);
+            fork_end(1);
+#if defined(CONFIG_USE_NPTL)
+            /* There is a race condition here.  The parent process could
+               theoretically read the TID in the child process before the child
+               tid is set.  This would require using either ptrace
+               (not implemented) or having *_tidptr to point at a shared memory
+               mapping.  We can't repeat the spinlock hack used above because
+               the child process gets its own copy of the lock.  */
+            if (flags & CLONE_CHILD_SETTID)
+                put_user_u32(gettid(), child_tidptr);
+            if (flags & CLONE_PARENT_SETTID)
+                put_user_u32(gettid(), parent_tidptr);
+            ts = (TaskState *)env->opaque;
+            if (flags & CLONE_SETTLS)
+                cpu_set_tls (env, newtls);
+            if (flags & CLONE_CHILD_CLEARTID)
+                ts->child_tidptr = child_tidptr;
+#endif
+        } else {
+            fork_end(0);
+        }
+    }
+    return ret;
+}
+
+/* warning : doesn't handle linux specific flags... */
+static int target_to_host_fcntl_cmd(int cmd)
+{
+    switch(cmd) {
+	case TARGET_F_DUPFD:
+	case TARGET_F_GETFD:
+	case TARGET_F_SETFD:
+	case TARGET_F_GETFL:
+	case TARGET_F_SETFL:
+            return cmd;
+        case TARGET_F_GETLK:
+	    return F_GETLK;
+	case TARGET_F_SETLK:
+	    return F_SETLK;
+	case TARGET_F_SETLKW:
+	    return F_SETLKW;
+	case TARGET_F_GETOWN:
+	    return F_GETOWN;
+	case TARGET_F_SETOWN:
+	    return F_SETOWN;
+	case TARGET_F_GETSIG:
+	    return F_GETSIG;
+	case TARGET_F_SETSIG:
+	    return F_SETSIG;
+#if TARGET_ABI_BITS == 32
+        case TARGET_F_GETLK64:
+	    return F_GETLK64;
+	case TARGET_F_SETLK64:
+	    return F_SETLK64;
+	case TARGET_F_SETLKW64:
+	    return F_SETLKW64;
+#endif
+        case TARGET_F_SETLEASE:
+            return F_SETLEASE;
+        case TARGET_F_GETLEASE:
+            return F_GETLEASE;
+#ifdef F_DUPFD_CLOEXEC
+        case TARGET_F_DUPFD_CLOEXEC:
+            return F_DUPFD_CLOEXEC;
+#endif
+        case TARGET_F_NOTIFY:
+            return F_NOTIFY;
+	default:
+            return -TARGET_EINVAL;
+    }
+    return -TARGET_EINVAL;
+}
+
+static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
+{
+    struct flock fl;
+    struct target_flock *target_fl;
+    struct flock64 fl64;
+    struct target_flock64 *target_fl64;
+    abi_long ret;
+    int host_cmd = target_to_host_fcntl_cmd(cmd);
+
+    if (host_cmd == -TARGET_EINVAL)
+	    return host_cmd;
+
+    switch(cmd) {
+    case TARGET_F_GETLK:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
+            return -TARGET_EFAULT;
+        fl.l_type = tswap16(target_fl->l_type);
+        fl.l_whence = tswap16(target_fl->l_whence);
+        fl.l_start = tswapl(target_fl->l_start);
+        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_pid = tswap32(target_fl->l_pid);
+        unlock_user_struct(target_fl, arg, 0);
+        ret = get_errno(fcntl(fd, host_cmd, &fl));
+        if (ret == 0) {
+            if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
+                return -TARGET_EFAULT;
+            target_fl->l_type = tswap16(fl.l_type);
+            target_fl->l_whence = tswap16(fl.l_whence);
+            target_fl->l_start = tswapl(fl.l_start);
+            target_fl->l_len = tswapl(fl.l_len);
+            target_fl->l_pid = tswap32(fl.l_pid);
+            unlock_user_struct(target_fl, arg, 1);
+        }
+        break;
+
+    case TARGET_F_SETLK:
+    case TARGET_F_SETLKW:
+        if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
+            return -TARGET_EFAULT;
+        fl.l_type = tswap16(target_fl->l_type);
+        fl.l_whence = tswap16(target_fl->l_whence);
+        fl.l_start = tswapl(target_fl->l_start);
+        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_pid = tswap32(target_fl->l_pid);
+        unlock_user_struct(target_fl, arg, 0);
+        ret = get_errno(fcntl(fd, host_cmd, &fl));
+        break;
+
+    case TARGET_F_GETLK64:
+        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
+            return -TARGET_EFAULT;
+        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
+        fl64.l_whence = tswap16(target_fl64->l_whence);
+        fl64.l_start = tswapl(target_fl64->l_start);
+        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_pid = tswap32(target_fl64->l_pid);
+        unlock_user_struct(target_fl64, arg, 0);
+        ret = get_errno(fcntl(fd, host_cmd, &fl64));
+        if (ret == 0) {
+            if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
+                return -TARGET_EFAULT;
+            target_fl64->l_type = tswap16(fl64.l_type) >> 1;
+            target_fl64->l_whence = tswap16(fl64.l_whence);
+            target_fl64->l_start = tswapl(fl64.l_start);
+            target_fl64->l_len = tswapl(fl64.l_len);
+            target_fl64->l_pid = tswap32(fl64.l_pid);
+            unlock_user_struct(target_fl64, arg, 1);
+        }
+        break;
+    case TARGET_F_SETLK64:
+    case TARGET_F_SETLKW64:
+        if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
+            return -TARGET_EFAULT;
+        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
+        fl64.l_whence = tswap16(target_fl64->l_whence);
+        fl64.l_start = tswapl(target_fl64->l_start);
+        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_pid = tswap32(target_fl64->l_pid);
+        unlock_user_struct(target_fl64, arg, 0);
+        ret = get_errno(fcntl(fd, host_cmd, &fl64));
+        break;
+
+    case TARGET_F_GETFL:
+        ret = get_errno(fcntl(fd, host_cmd, arg));
+        if (ret >= 0) {
+            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
+        }
+        break;
+
+    case TARGET_F_SETFL:
+        ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
+        break;
+
+    case TARGET_F_SETOWN:
+    case TARGET_F_GETOWN:
+    case TARGET_F_SETSIG:
+    case TARGET_F_GETSIG:
+    case TARGET_F_SETLEASE:
+    case TARGET_F_GETLEASE:
+        ret = get_errno(fcntl(fd, host_cmd, arg));
+        break;
+
+    default:
+        ret = get_errno(fcntl(fd, cmd, arg));
+        break;
+    }
+    return ret;
+}
+
+#ifdef USE_UID16
+
+static inline int high2lowuid(int uid)
+{
+    if (uid > 65535)
+        return 65534;
+    else
+        return uid;
+}
+
+static inline int high2lowgid(int gid)
+{
+    if (gid > 65535)
+        return 65534;
+    else
+        return gid;
+}
+
+static inline int low2highuid(int uid)
+{
+    if ((int16_t)uid == -1)
+        return -1;
+    else
+        return uid;
+}
+
+static inline int low2highgid(int gid)
+{
+    if ((int16_t)gid == -1)
+        return -1;
+    else
+        return gid;
+}
+static inline int tswapid(int id)
+{
+    return tswap16(id);
+}
+#else /* !USE_UID16 */
+static inline int high2lowuid(int uid)
+{
+    return uid;
+}
+static inline int high2lowgid(int gid)
+{
+    return gid;
+}
+static inline int low2highuid(int uid)
+{
+    return uid;
+}
+static inline int low2highgid(int gid)
+{
+    return gid;
+}
+static inline int tswapid(int id)
+{
+    return tswap32(id);
+}
+#endif /* USE_UID16 */
+
+void syscall_init(void)
+{
+    IOCTLEntry *ie;
+    const argtype *arg_type;
+    int size;
+    int i;
+
+#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
+#include "syscall_types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+    /* we patch the ioctl size if necessary. We rely on the fact that
+       no ioctl has all the bits at '1' in the size field */
+    ie = ioctl_entries;
+    while (ie->target_cmd != 0) {
+        if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
+            TARGET_IOC_SIZEMASK) {
+            arg_type = ie->arg_type;
+            if (arg_type[0] != TYPE_PTR) {
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
+                        ie->target_cmd);
+                exit(1);
+            }
+            arg_type++;
+            size = thunk_type_size(arg_type, 0);
+            ie->target_cmd = (ie->target_cmd &
+                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
+                (size << TARGET_IOC_SIZESHIFT);
+        }
+
+        /* Build target_to_host_errno_table[] table from
+         * host_to_target_errno_table[]. */
+        for (i=0; i < ERRNO_TABLE_SIZE; i++)
+                target_to_host_errno_table[host_to_target_errno_table[i]] = i;
+
+        /* automatic consistency check if same arch */
+#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
+    (defined(__x86_64__) && defined(TARGET_X86_64))
+        if (unlikely(ie->target_cmd != ie->host_cmd)) {
+            fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
+                    ie->name, ie->target_cmd, ie->host_cmd);
+        }
+#endif
+        ie++;
+    }
+}
+
+#if TARGET_ABI_BITS == 32
+static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS == 32 */
+static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+#ifdef TARGET_NR_truncate64
+static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
+                                         abi_long arg2,
+                                         abi_long arg3,
+                                         abi_long arg4)
+{
+    if (regpairs_aligned(cpu_env)) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
+}
+#endif
+
+#ifdef TARGET_NR_ftruncate64
+static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
+                                          abi_long arg2,
+                                          abi_long arg3,
+                                          abi_long arg4)
+{
+    if (regpairs_aligned(cpu_env)) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
+}
+#endif
+
+static inline abi_long target_to_host_timespec(struct timespec *host_ts,
+                                               abi_ulong target_addr)
+{
+    struct target_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
+        return -TARGET_EFAULT;
+    host_ts->tv_sec = tswapl(target_ts->tv_sec);
+    host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_timespec(abi_ulong target_addr,
+                                               struct timespec *host_ts)
+{
+    struct target_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
+        return -TARGET_EFAULT;
+    target_ts->tv_sec = tswapl(host_ts->tv_sec);
+    target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_addr, 1);
+    return 0;
+}
+
+#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
+static inline abi_long host_to_target_stat64(void *cpu_env,
+                                             abi_ulong target_addr,
+                                             struct stat *host_st)
+{
+#ifdef TARGET_ARM
+    if (((CPUARMState *)cpu_env)->eabi) {
+        struct target_eabi_stat64 *target_st;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
+            return -TARGET_EFAULT;
+        memset(target_st, 0, sizeof(struct target_eabi_stat64));
+        __put_user(host_st->st_dev, &target_st->st_dev);
+        __put_user(host_st->st_ino, &target_st->st_ino);
+#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
+        __put_user(host_st->st_ino, &target_st->__st_ino);
+#endif
+        __put_user(host_st->st_mode, &target_st->st_mode);
+        __put_user(host_st->st_nlink, &target_st->st_nlink);
+        __put_user(host_st->st_uid, &target_st->st_uid);
+        __put_user(host_st->st_gid, &target_st->st_gid);
+        __put_user(host_st->st_rdev, &target_st->st_rdev);
+        __put_user(host_st->st_size, &target_st->st_size);
+        __put_user(host_st->st_blksize, &target_st->st_blksize);
+        __put_user(host_st->st_blocks, &target_st->st_blocks);
+        __put_user(host_st->st_atime, &target_st->target_st_atime);
+        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
+        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
+        unlock_user_struct(target_st, target_addr, 1);
+    } else
+#endif
+    {
+#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA)
+        struct target_stat *target_st;
+#else
+        struct target_stat64 *target_st;
+#endif
+
+        if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
+            return -TARGET_EFAULT;
+        memset(target_st, 0, sizeof(*target_st));
+        __put_user(host_st->st_dev, &target_st->st_dev);
+        __put_user(host_st->st_ino, &target_st->st_ino);
+#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
+        __put_user(host_st->st_ino, &target_st->__st_ino);
+#endif
+        __put_user(host_st->st_mode, &target_st->st_mode);
+        __put_user(host_st->st_nlink, &target_st->st_nlink);
+        __put_user(host_st->st_uid, &target_st->st_uid);
+        __put_user(host_st->st_gid, &target_st->st_gid);
+        __put_user(host_st->st_rdev, &target_st->st_rdev);
+        /* XXX: better use of kernel struct */
+        __put_user(host_st->st_size, &target_st->st_size);
+        __put_user(host_st->st_blksize, &target_st->st_blksize);
+        __put_user(host_st->st_blocks, &target_st->st_blocks);
+        __put_user(host_st->st_atime, &target_st->target_st_atime);
+        __put_user(host_st->st_mtime, &target_st->target_st_mtime);
+        __put_user(host_st->st_ctime, &target_st->target_st_ctime);
+        unlock_user_struct(target_st, target_addr, 1);
+    }
+
+    return 0;
+}
+#endif
+
+#if defined(CONFIG_USE_NPTL)
+/* ??? Using host futex calls even when target atomic operations
+   are not really atomic probably breaks things.  However implementing
+   futexes locally would make futexes shared between multiple processes
+   tricky.  However they're probably useless because guest atomic
+   operations won't work either.  */
+static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
+                    target_ulong uaddr2, int val3)
+{
+    struct timespec ts, *pts;
+    int base_op;
+
+    /* ??? We assume FUTEX_* constants are the same on both host
+       and target.  */
+#ifdef FUTEX_CMD_MASK
+    base_op = op & FUTEX_CMD_MASK;
+#else
+    base_op = op;
+#endif
+    switch (base_op) {
+    case FUTEX_WAIT:
+        if (timeout) {
+            pts = &ts;
+            target_to_host_timespec(pts, timeout);
+        } else {
+            pts = NULL;
+        }
+        return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
+                         pts, NULL, 0));
+    case FUTEX_WAKE:
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+    case FUTEX_FD:
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+    case FUTEX_REQUEUE:
+    case FUTEX_CMP_REQUEUE:
+    case FUTEX_WAKE_OP:
+        /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
+           TIMEOUT parameter is interpreted as a uint32_t by the kernel.
+           But the prototype takes a `struct timespec *'; insert casts
+           to satisfy the compiler.  We do not need to tswap TIMEOUT
+           since it's not compared to guest memory.  */
+        pts = (struct timespec *)(uintptr_t) timeout;
+        return get_errno(sys_futex(g2h(uaddr), op, val, pts,
+                                   g2h(uaddr2),
+                                   (base_op == FUTEX_CMP_REQUEUE
+                                    ? tswap32(val3)
+                                    : val3)));
+    default:
+        return -TARGET_ENOSYS;
+    }
+}
+#endif
+
+/* Map host to target signal numbers for the wait family of syscalls.
+   Assume all other status bits are the same.  */
+static int host_to_target_waitstatus(int status)
+{
+    if (WIFSIGNALED(status)) {
+        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+    }
+    if (WIFSTOPPED(status)) {
+        return (host_to_target_signal(WSTOPSIG(status)) << 8)
+               | (status & 0xff);
+    }
+    return status;
+}
+
+int get_osversion(void)
+{
+    static int osversion;
+    struct new_utsname buf;
+    const char *s;
+    int i, n, tmp;
+    if (osversion)
+        return osversion;
+    if (qemu_uname_release && *qemu_uname_release) {
+        s = qemu_uname_release;
+    } else {
+        if (sys_uname(&buf))
+            return 0;
+        s = buf.release;
+    }
+    tmp = 0;
+    for (i = 0; i < 3; i++) {
+        n = 0;
+        while (*s >= '0' && *s <= '9') {
+            n *= 10;
+            n += *s - '0';
+            s++;
+        }
+        tmp = (tmp << 8) + n;
+        if (*s == '.')
+            s++;
+    }
+    osversion = tmp;
+    return osversion;
+}
+
+/* do_syscall() should always have a single exit point at the end so
+   that actions, such as logging of syscall results, can be performed.
+   All errnos that do_syscall() returns must be -TARGET_<errcode>. */
+abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
+                    abi_long arg2, abi_long arg3, abi_long arg4,
+                    abi_long arg5, abi_long arg6, abi_long arg7,
+                    abi_long arg8)
+{
+    abi_long ret;
+    struct stat st;
+    struct statfs stfs;
+    void *p;
+
+#ifdef DEBUG
+    gemu_log("syscall %d", num);
+#endif
+    if(do_strace)
+        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+
+    switch(num) {
+    case TARGET_NR_exit:
+#ifdef CONFIG_USE_NPTL
+      /* In old applications this may be used to implement _exit(2).
+         However in threaded applictions it is used for thread termination,
+         and _exit_group is used for application termination.
+         Do thread termination if we have more then one thread.  */
+      /* FIXME: This probably breaks if a signal arrives.  We should probably
+         be disabling signals.  */
+      if (first_cpu->next_cpu) {
+          TaskState *ts;
+          CPUState **lastp;
+          CPUState *p;
+
+          cpu_list_lock();
+          lastp = &first_cpu;
+          p = first_cpu;
+          while (p && p != (CPUState *)cpu_env) {
+              lastp = &p->next_cpu;
+              p = p->next_cpu;
+          }
+          /* If we didn't find the CPU for this thread then something is
+             horribly wrong.  */
+          if (!p)
+              abort();
+          /* Remove the CPU from the list.  */
+          *lastp = p->next_cpu;
+          cpu_list_unlock();
+          ts = ((CPUState *)cpu_env)->opaque;
+          if (ts->child_tidptr) {
+              put_user_u32(0, ts->child_tidptr);
+              sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+                        NULL, NULL, 0);
+          }
+          thread_env = NULL;
+          qemu_free(cpu_env);
+          qemu_free(ts);
+          pthread_exit(NULL);
+      }
+#endif
+#ifdef TARGET_GPROF
+        _mcleanup();
+#endif
+        gdb_exit(cpu_env, arg1);
+        _exit(arg1);
+        ret = 0; /* avoid warning */
+        break;
+    case TARGET_NR_read:
+        if (arg3 == 0)
+            ret = 0;
+        else {
+            if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+                goto efault;
+            ret = get_errno(read(arg1, p, arg3));
+            unlock_user(p, arg2, ret);
+        }
+        break;
+    case TARGET_NR_write:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(write(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+    case TARGET_NR_open:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(open(path(p),
+                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                             arg3));
+        unlock_user(p, arg1, 0);
+        break;
+#if defined(TARGET_NR_openat) && defined(__NR_openat)
+    case TARGET_NR_openat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_openat(arg1,
+                                   path(p),
+                                   target_to_host_bitmask(arg3, fcntl_flags_tbl),
+                                   arg4));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_close:
+        ret = get_errno(close(arg1));
+        break;
+    case TARGET_NR_brk:
+        ret = do_brk(arg1);
+        break;
+    case TARGET_NR_fork:
+        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
+        break;
+#ifdef TARGET_NR_waitpid
+    case TARGET_NR_waitpid:
+        {
+            int status;
+            ret = get_errno(waitpid(arg1, &status, arg3));
+            if (!is_error(ret) && arg2
+                && put_user_s32(host_to_target_waitstatus(status), arg2))
+                goto efault;
+        }
+        break;
+#endif
+#ifdef TARGET_NR_waitid
+    case TARGET_NR_waitid:
+        {
+            siginfo_t info;
+            info.si_pid = 0;
+            ret = get_errno(waitid(arg1, arg2, &info, arg4));
+            if (!is_error(ret) && arg3 && info.si_pid != 0) {
+                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
+                    goto efault;
+                host_to_target_siginfo(p, &info);
+                unlock_user(p, arg3, sizeof(target_siginfo_t));
+            }
+        }
+        break;
+#endif
+#ifdef TARGET_NR_creat /* not on alpha */
+    case TARGET_NR_creat:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(creat(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+    case TARGET_NR_link:
+        {
+            void * p2;
+            p = lock_user_string(arg1);
+            p2 = lock_user_string(arg2);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(link(p, p2));
+            unlock_user(p2, arg2, 0);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
+    case TARGET_NR_linkat:
+        {
+            void * p2 = NULL;
+            if (!arg2 || !arg4)
+                goto efault;
+            p  = lock_user_string(arg2);
+            p2 = lock_user_string(arg4);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
+            unlock_user(p, arg2, 0);
+            unlock_user(p2, arg4, 0);
+        }
+        break;
+#endif
+    case TARGET_NR_unlink:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(unlink(p));
+        unlock_user(p, arg1, 0);
+        break;
+#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
+    case TARGET_NR_unlinkat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_unlinkat(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_execve:
+        {
+            char **argp, **envp;
+            int argc, envc;
+            abi_ulong gp;
+            abi_ulong guest_argp;
+            abi_ulong guest_envp;
+            abi_ulong addr;
+            char **q;
+
+            argc = 0;
+            guest_argp = arg2;
+            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
+                if (get_user_ual(addr, gp))
+                    goto efault;
+                if (!addr)
+                    break;
+                argc++;
+            }
+            envc = 0;
+            guest_envp = arg3;
+            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
+                if (get_user_ual(addr, gp))
+                    goto efault;
+                if (!addr)
+                    break;
+                envc++;
+            }
+
+            argp = alloca((argc + 1) * sizeof(void *));
+            envp = alloca((envc + 1) * sizeof(void *));
+
+            for (gp = guest_argp, q = argp; gp;
+                  gp += sizeof(abi_ulong), q++) {
+                if (get_user_ual(addr, gp))
+                    goto execve_efault;
+                if (!addr)
+                    break;
+                if (!(*q = lock_user_string(addr)))
+                    goto execve_efault;
+            }
+            *q = NULL;
+
+            for (gp = guest_envp, q = envp; gp;
+                  gp += sizeof(abi_ulong), q++) {
+                if (get_user_ual(addr, gp))
+                    goto execve_efault;
+                if (!addr)
+                    break;
+                if (!(*q = lock_user_string(addr)))
+                    goto execve_efault;
+            }
+            *q = NULL;
+
+            if (!(p = lock_user_string(arg1)))
+                goto execve_efault;
+            ret = get_errno(execve(p, argp, envp));
+            unlock_user(p, arg1, 0);
+
+            goto execve_end;
+
+        execve_efault:
+            ret = -TARGET_EFAULT;
+
+        execve_end:
+            for (gp = guest_argp, q = argp; *q;
+                  gp += sizeof(abi_ulong), q++) {
+                if (get_user_ual(addr, gp)
+                    || !addr)
+                    break;
+                unlock_user(*q, addr, 0);
+            }
+            for (gp = guest_envp, q = envp; *q;
+                  gp += sizeof(abi_ulong), q++) {
+                if (get_user_ual(addr, gp)
+                    || !addr)
+                    break;
+                unlock_user(*q, addr, 0);
+            }
+        }
+        break;
+    case TARGET_NR_chdir:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(chdir(p));
+        unlock_user(p, arg1, 0);
+        break;
+#ifdef TARGET_NR_time
+    case TARGET_NR_time:
+        {
+            time_t host_time;
+            ret = get_errno(time(&host_time));
+            if (!is_error(ret)
+                && arg1
+                && put_user_sal(host_time, arg1))
+                goto efault;
+        }
+        break;
+#endif
+    case TARGET_NR_mknod:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(mknod(p, arg2, arg3));
+        unlock_user(p, arg1, 0);
+        break;
+#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
+    case TARGET_NR_mknodat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_chmod:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(chmod(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#ifdef TARGET_NR_break
+    case TARGET_NR_break:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_oldstat
+    case TARGET_NR_oldstat:
+        goto unimplemented;
+#endif
+    case TARGET_NR_lseek:
+        ret = get_errno(lseek(arg1, arg2, arg3));
+        break;
+#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
+    /* Alpha specific */
+    case TARGET_NR_getxpid:
+        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
+        ret = get_errno(getpid());
+        break;
+#endif
+#ifdef TARGET_NR_getpid
+    case TARGET_NR_getpid:
+        ret = get_errno(getpid());
+        break;
+#endif
+    case TARGET_NR_mount:
+		{
+			/* need to look at the data field */
+			void *p2, *p3;
+			p = lock_user_string(arg1);
+			p2 = lock_user_string(arg2);
+			p3 = lock_user_string(arg3);
+                        if (!p || !p2 || !p3)
+                            ret = -TARGET_EFAULT;
+                        else {
+                            /* FIXME - arg5 should be locked, but it isn't clear how to
+                             * do that since it's not guaranteed to be a NULL-terminated
+                             * string.
+                             */
+                            if ( ! arg5 )
+                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
+                            else
+                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
+                        }
+                        unlock_user(p, arg1, 0);
+                        unlock_user(p2, arg2, 0);
+                        unlock_user(p3, arg3, 0);
+			break;
+		}
+#ifdef TARGET_NR_umount
+    case TARGET_NR_umount:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(umount(p));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+#ifdef TARGET_NR_stime /* not on alpha */
+    case TARGET_NR_stime:
+        {
+            time_t host_time;
+            if (get_user_sal(host_time, arg1))
+                goto efault;
+            ret = get_errno(stime(&host_time));
+        }
+        break;
+#endif
+    case TARGET_NR_ptrace:
+        goto unimplemented;
+#ifdef TARGET_NR_alarm /* not on alpha */
+    case TARGET_NR_alarm:
+        ret = alarm(arg1);
+        break;
+#endif
+#ifdef TARGET_NR_oldfstat
+    case TARGET_NR_oldfstat:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_pause /* not on alpha */
+    case TARGET_NR_pause:
+        ret = get_errno(pause());
+        break;
+#endif
+#ifdef TARGET_NR_utime
+    case TARGET_NR_utime:
+        {
+            struct utimbuf tbuf, *host_tbuf;
+            struct target_utimbuf *target_tbuf;
+            if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
+                    goto efault;
+                tbuf.actime = tswapl(target_tbuf->actime);
+                tbuf.modtime = tswapl(target_tbuf->modtime);
+                unlock_user_struct(target_tbuf, arg2, 0);
+                host_tbuf = &tbuf;
+            } else {
+                host_tbuf = NULL;
+            }
+            if (!(p = lock_user_string(arg1)))
+                goto efault;
+            ret = get_errno(utime(p, host_tbuf));
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#endif
+    case TARGET_NR_utimes:
+        {
+            struct timeval *tvp, tv[2];
+            if (arg2) {
+                if (copy_from_user_timeval(&tv[0], arg2)
+                    || copy_from_user_timeval(&tv[1],
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
+                tvp = tv;
+            } else {
+                tvp = NULL;
+            }
+            if (!(p = lock_user_string(arg1)))
+                goto efault;
+            ret = get_errno(utimes(p, tvp));
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
+    case TARGET_NR_futimesat:
+        {
+            struct timeval *tvp, tv[2];
+            if (arg3) {
+                if (copy_from_user_timeval(&tv[0], arg3)
+                    || copy_from_user_timeval(&tv[1],
+                                              arg3 + sizeof(struct target_timeval)))
+                    goto efault;
+                tvp = tv;
+            } else {
+                tvp = NULL;
+            }
+            if (!(p = lock_user_string(arg2)))
+                goto efault;
+            ret = get_errno(sys_futimesat(arg1, path(p), tvp));
+            unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_stty
+    case TARGET_NR_stty:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_gtty
+    case TARGET_NR_gtty:
+        goto unimplemented;
+#endif
+    case TARGET_NR_access:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(access(path(p), arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
+    case TARGET_NR_faccessat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_faccessat(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+#ifdef TARGET_NR_nice /* not on alpha */
+    case TARGET_NR_nice:
+        ret = get_errno(nice(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_ftime
+    case TARGET_NR_ftime:
+        goto unimplemented;
+#endif
+    case TARGET_NR_sync:
+        sync();
+        ret = 0;
+        break;
+    case TARGET_NR_kill:
+        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
+        break;
+    case TARGET_NR_rename:
+        {
+            void *p2;
+            p = lock_user_string(arg1);
+            p2 = lock_user_string(arg2);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(rename(p, p2));
+            unlock_user(p2, arg2, 0);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
+    case TARGET_NR_renameat:
+        {
+            void *p2;
+            p  = lock_user_string(arg2);
+            p2 = lock_user_string(arg4);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
+            unlock_user(p2, arg4, 0);
+            unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
+    case TARGET_NR_mkdir:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(mkdir(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
+    case TARGET_NR_mkdirat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_mkdirat(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_rmdir:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(rmdir(p));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_dup:
+        ret = get_errno(dup(arg1));
+        break;
+    case TARGET_NR_pipe:
+        ret = do_pipe(cpu_env, arg1, 0, 0);
+        break;
+#ifdef TARGET_NR_pipe2
+    case TARGET_NR_pipe2:
+        ret = do_pipe(cpu_env, arg1, arg2, 1);
+        break;
+#endif
+    case TARGET_NR_times:
+        {
+            struct target_tms *tmsp;
+            struct tms tms;
+            ret = get_errno(times(&tms));
+            if (arg1) {
+                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
+                if (!tmsp)
+                    goto efault;
+                tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
+                tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
+                tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
+                tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
+            }
+            if (!is_error(ret))
+                ret = host_to_target_clock_t(ret);
+        }
+        break;
+#ifdef TARGET_NR_prof
+    case TARGET_NR_prof:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_signal
+    case TARGET_NR_signal:
+        goto unimplemented;
+#endif
+    case TARGET_NR_acct:
+        if (arg1 == 0) {
+            ret = get_errno(acct(NULL));
+        } else {
+            if (!(p = lock_user_string(arg1)))
+                goto efault;
+            ret = get_errno(acct(path(p)));
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#ifdef TARGET_NR_umount2 /* not on alpha */
+    case TARGET_NR_umount2:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(umount2(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+#ifdef TARGET_NR_lock
+    case TARGET_NR_lock:
+        goto unimplemented;
+#endif
+    case TARGET_NR_ioctl:
+        ret = do_ioctl(arg1, arg2, arg3);
+        break;
+    case TARGET_NR_fcntl:
+        ret = do_fcntl(arg1, arg2, arg3);
+        break;
+#ifdef TARGET_NR_mpx
+    case TARGET_NR_mpx:
+        goto unimplemented;
+#endif
+    case TARGET_NR_setpgid:
+        ret = get_errno(setpgid(arg1, arg2));
+        break;
+#ifdef TARGET_NR_ulimit
+    case TARGET_NR_ulimit:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_oldolduname
+    case TARGET_NR_oldolduname:
+        goto unimplemented;
+#endif
+    case TARGET_NR_umask:
+        ret = get_errno(umask(arg1));
+        break;
+    case TARGET_NR_chroot:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(chroot(p));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_ustat:
+        goto unimplemented;
+    case TARGET_NR_dup2:
+        ret = get_errno(dup2(arg1, arg2));
+        break;
+#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
+    case TARGET_NR_dup3:
+        ret = get_errno(dup3(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_getppid /* not on alpha */
+    case TARGET_NR_getppid:
+        ret = get_errno(getppid());
+        break;
+#endif
+    case TARGET_NR_getpgrp:
+        ret = get_errno(getpgrp());
+        break;
+    case TARGET_NR_setsid:
+        ret = get_errno(setsid());
+        break;
+#ifdef TARGET_NR_sigaction
+    case TARGET_NR_sigaction:
+        {
+#if defined(TARGET_ALPHA)
+            struct target_sigaction act, oact, *pact = 0;
+            struct target_old_sigaction *old_act;
+            if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
+                    goto efault;
+                act._sa_handler = old_act->_sa_handler;
+                target_siginitset(&act.sa_mask, old_act->sa_mask);
+                act.sa_flags = old_act->sa_flags;
+                act.sa_restorer = 0;
+                unlock_user_struct(old_act, arg2, 0);
+                pact = &act;
+            }
+            ret = get_errno(do_sigaction(arg1, pact, &oact));
+            if (!is_error(ret) && arg3) {
+                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
+                    goto efault;
+                old_act->_sa_handler = oact._sa_handler;
+                old_act->sa_mask = oact.sa_mask.sig[0];
+                old_act->sa_flags = oact.sa_flags;
+                unlock_user_struct(old_act, arg3, 1);
+            }
+#elif defined(TARGET_MIPS)
+	    struct target_sigaction act, oact, *pact, *old_act;
+
+	    if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
+                    goto efault;
+		act._sa_handler = old_act->_sa_handler;
+		target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
+		act.sa_flags = old_act->sa_flags;
+		unlock_user_struct(old_act, arg2, 0);
+		pact = &act;
+	    } else {
+		pact = NULL;
+	    }
+
+	    ret = get_errno(do_sigaction(arg1, pact, &oact));
+
+	    if (!is_error(ret) && arg3) {
+                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
+                    goto efault;
+		old_act->_sa_handler = oact._sa_handler;
+		old_act->sa_flags = oact.sa_flags;
+		old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
+		old_act->sa_mask.sig[1] = 0;
+		old_act->sa_mask.sig[2] = 0;
+		old_act->sa_mask.sig[3] = 0;
+		unlock_user_struct(old_act, arg3, 1);
+	    }
+#else
+            struct target_old_sigaction *old_act;
+            struct target_sigaction act, oact, *pact;
+            if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
+                    goto efault;
+                act._sa_handler = old_act->_sa_handler;
+                target_siginitset(&act.sa_mask, old_act->sa_mask);
+                act.sa_flags = old_act->sa_flags;
+                act.sa_restorer = old_act->sa_restorer;
+                unlock_user_struct(old_act, arg2, 0);
+                pact = &act;
+            } else {
+                pact = NULL;
+            }
+            ret = get_errno(do_sigaction(arg1, pact, &oact));
+            if (!is_error(ret) && arg3) {
+                if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
+                    goto efault;
+                old_act->_sa_handler = oact._sa_handler;
+                old_act->sa_mask = oact.sa_mask.sig[0];
+                old_act->sa_flags = oact.sa_flags;
+                old_act->sa_restorer = oact.sa_restorer;
+                unlock_user_struct(old_act, arg3, 1);
+            }
+#endif
+        }
+        break;
+#endif
+    case TARGET_NR_rt_sigaction:
+        {
+#if defined(TARGET_ALPHA)
+            struct target_sigaction act, oact, *pact = 0;
+            struct target_rt_sigaction *rt_act;
+            /* ??? arg4 == sizeof(sigset_t).  */
+            if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
+                    goto efault;
+                act._sa_handler = rt_act->_sa_handler;
+                act.sa_mask = rt_act->sa_mask;
+                act.sa_flags = rt_act->sa_flags;
+                act.sa_restorer = arg5;
+                unlock_user_struct(rt_act, arg2, 0);
+                pact = &act;
+            }
+            ret = get_errno(do_sigaction(arg1, pact, &oact));
+            if (!is_error(ret) && arg3) {
+                if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
+                    goto efault;
+                rt_act->_sa_handler = oact._sa_handler;
+                rt_act->sa_mask = oact.sa_mask;
+                rt_act->sa_flags = oact.sa_flags;
+                unlock_user_struct(rt_act, arg3, 1);
+            }
+#else
+            struct target_sigaction *act;
+            struct target_sigaction *oact;
+
+            if (arg2) {
+                if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
+                    goto efault;
+            } else
+                act = NULL;
+            if (arg3) {
+                if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
+                    ret = -TARGET_EFAULT;
+                    goto rt_sigaction_fail;
+                }
+            } else
+                oact = NULL;
+            ret = get_errno(do_sigaction(arg1, act, oact));
+	rt_sigaction_fail:
+            if (act)
+                unlock_user_struct(act, arg2, 0);
+            if (oact)
+                unlock_user_struct(oact, arg3, 1);
+#endif
+        }
+        break;
+#ifdef TARGET_NR_sgetmask /* not on alpha */
+    case TARGET_NR_sgetmask:
+        {
+            sigset_t cur_set;
+            abi_ulong target_set;
+            sigprocmask(0, NULL, &cur_set);
+            host_to_target_old_sigset(&target_set, &cur_set);
+            ret = target_set;
+        }
+        break;
+#endif
+#ifdef TARGET_NR_ssetmask /* not on alpha */
+    case TARGET_NR_ssetmask:
+        {
+            sigset_t set, oset, cur_set;
+            abi_ulong target_set = arg1;
+            sigprocmask(0, NULL, &cur_set);
+            target_to_host_old_sigset(&set, &target_set);
+            sigorset(&set, &set, &cur_set);
+            sigprocmask(SIG_SETMASK, &set, &oset);
+            host_to_target_old_sigset(&target_set, &oset);
+            ret = target_set;
+        }
+        break;
+#endif
+#ifdef TARGET_NR_sigprocmask
+    case TARGET_NR_sigprocmask:
+        {
+#if defined(TARGET_ALPHA)
+            sigset_t set, oldset;
+            abi_ulong mask;
+            int how;
+
+            switch (arg1) {
+            case TARGET_SIG_BLOCK:
+                how = SIG_BLOCK;
+                break;
+            case TARGET_SIG_UNBLOCK:
+                how = SIG_UNBLOCK;
+                break;
+            case TARGET_SIG_SETMASK:
+                how = SIG_SETMASK;
+                break;
+            default:
+                ret = -TARGET_EINVAL;
+                goto fail;
+            }
+            mask = arg2;
+            target_to_host_old_sigset(&set, &mask);
+
+            ret = get_errno(sigprocmask(how, &set, &oldset));
+
+            if (!is_error(ret)) {
+                host_to_target_old_sigset(&mask, &oldset);
+                ret = mask;
+                ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
+            }
+#else
+            sigset_t set, oldset, *set_ptr;
+            int how;
+
+            if (arg2) {
+                switch (arg1) {
+                case TARGET_SIG_BLOCK:
+                    how = SIG_BLOCK;
+                    break;
+                case TARGET_SIG_UNBLOCK:
+                    how = SIG_UNBLOCK;
+                    break;
+                case TARGET_SIG_SETMASK:
+                    how = SIG_SETMASK;
+                    break;
+                default:
+                    ret = -TARGET_EINVAL;
+                    goto fail;
+                }
+                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
+                    goto efault;
+                target_to_host_old_sigset(&set, p);
+                unlock_user(p, arg2, 0);
+                set_ptr = &set;
+            } else {
+                how = 0;
+                set_ptr = NULL;
+            }
+            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+            if (!is_error(ret) && arg3) {
+                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
+                    goto efault;
+                host_to_target_old_sigset(p, &oldset);
+                unlock_user(p, arg3, sizeof(target_sigset_t));
+            }
+#endif
+        }
+        break;
+#endif
+    case TARGET_NR_rt_sigprocmask:
+        {
+            int how = arg1;
+            sigset_t set, oldset, *set_ptr;
+
+            if (arg2) {
+                switch(how) {
+                case TARGET_SIG_BLOCK:
+                    how = SIG_BLOCK;
+                    break;
+                case TARGET_SIG_UNBLOCK:
+                    how = SIG_UNBLOCK;
+                    break;
+                case TARGET_SIG_SETMASK:
+                    how = SIG_SETMASK;
+                    break;
+                default:
+                    ret = -TARGET_EINVAL;
+                    goto fail;
+                }
+                if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
+                    goto efault;
+                target_to_host_sigset(&set, p);
+                unlock_user(p, arg2, 0);
+                set_ptr = &set;
+            } else {
+                how = 0;
+                set_ptr = NULL;
+            }
+            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+            if (!is_error(ret) && arg3) {
+                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
+                    goto efault;
+                host_to_target_sigset(p, &oldset);
+                unlock_user(p, arg3, sizeof(target_sigset_t));
+            }
+        }
+        break;
+#ifdef TARGET_NR_sigpending
+    case TARGET_NR_sigpending:
+        {
+            sigset_t set;
+            ret = get_errno(sigpending(&set));
+            if (!is_error(ret)) {
+                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
+                    goto efault;
+                host_to_target_old_sigset(p, &set);
+                unlock_user(p, arg1, sizeof(target_sigset_t));
+            }
+        }
+        break;
+#endif
+    case TARGET_NR_rt_sigpending:
+        {
+            sigset_t set;
+            ret = get_errno(sigpending(&set));
+            if (!is_error(ret)) {
+                if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
+                    goto efault;
+                host_to_target_sigset(p, &set);
+                unlock_user(p, arg1, sizeof(target_sigset_t));
+            }
+        }
+        break;
+#ifdef TARGET_NR_sigsuspend
+    case TARGET_NR_sigsuspend:
+        {
+            sigset_t set;
+#if defined(TARGET_ALPHA)
+            abi_ulong mask = arg1;
+            target_to_host_old_sigset(&set, &mask);
+#else
+            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
+                goto efault;
+            target_to_host_old_sigset(&set, p);
+            unlock_user(p, arg1, 0);
+#endif
+            ret = get_errno(sigsuspend(&set));
+        }
+        break;
+#endif
+    case TARGET_NR_rt_sigsuspend:
+        {
+            sigset_t set;
+            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
+                goto efault;
+            target_to_host_sigset(&set, p);
+            unlock_user(p, arg1, 0);
+            ret = get_errno(sigsuspend(&set));
+        }
+        break;
+    case TARGET_NR_rt_sigtimedwait:
+        {
+            sigset_t set;
+            struct timespec uts, *puts;
+            siginfo_t uinfo;
+
+            if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
+                goto efault;
+            target_to_host_sigset(&set, p);
+            unlock_user(p, arg1, 0);
+            if (arg3) {
+                puts = &uts;
+                target_to_host_timespec(puts, arg3);
+            } else {
+                puts = NULL;
+            }
+            ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+            if (!is_error(ret) && arg2) {
+                if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
+                    goto efault;
+                host_to_target_siginfo(p, &uinfo);
+                unlock_user(p, arg2, sizeof(target_siginfo_t));
+            }
+        }
+        break;
+    case TARGET_NR_rt_sigqueueinfo:
+        {
+            siginfo_t uinfo;
+            if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
+                goto efault;
+            target_to_host_siginfo(&uinfo, p);
+            unlock_user(p, arg1, 0);
+            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
+        }
+        break;
+#ifdef TARGET_NR_sigreturn
+    case TARGET_NR_sigreturn:
+        /* NOTE: ret is eax, so not transcoding must be done */
+        ret = do_sigreturn(cpu_env);
+        break;
+#endif
+    case TARGET_NR_rt_sigreturn:
+        /* NOTE: ret is eax, so not transcoding must be done */
+        ret = do_rt_sigreturn(cpu_env);
+        break;
+    case TARGET_NR_sethostname:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(sethostname(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_setrlimit:
+        {
+            int resource = target_to_host_resource(arg1);
+            struct target_rlimit *target_rlim;
+            struct rlimit rlim;
+            if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
+                goto efault;
+            rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
+            rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
+            unlock_user_struct(target_rlim, arg2, 0);
+            ret = get_errno(setrlimit(resource, &rlim));
+        }
+        break;
+    case TARGET_NR_getrlimit:
+        {
+            int resource = target_to_host_resource(arg1);
+            struct target_rlimit *target_rlim;
+            struct rlimit rlim;
+
+            ret = get_errno(getrlimit(resource, &rlim));
+            if (!is_error(ret)) {
+                if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
+                    goto efault;
+                target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+                target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+                unlock_user_struct(target_rlim, arg2, 1);
+            }
+        }
+        break;
+    case TARGET_NR_getrusage:
+        {
+            struct rusage rusage;
+            ret = get_errno(getrusage(arg1, &rusage));
+            if (!is_error(ret)) {
+                host_to_target_rusage(arg2, &rusage);
+            }
+        }
+        break;
+    case TARGET_NR_gettimeofday:
+        {
+            struct timeval tv;
+            ret = get_errno(gettimeofday(&tv, NULL));
+            if (!is_error(ret)) {
+                if (copy_to_user_timeval(arg1, &tv))
+                    goto efault;
+            }
+        }
+        break;
+    case TARGET_NR_settimeofday:
+        {
+            struct timeval tv;
+            if (copy_from_user_timeval(&tv, arg1))
+                goto efault;
+            ret = get_errno(settimeofday(&tv, NULL));
+        }
+        break;
+#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390)
+    case TARGET_NR_select:
+        {
+            struct target_sel_arg_struct *sel;
+            abi_ulong inp, outp, exp, tvp;
+            long nsel;
+
+            if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
+                goto efault;
+            nsel = tswapl(sel->n);
+            inp = tswapl(sel->inp);
+            outp = tswapl(sel->outp);
+            exp = tswapl(sel->exp);
+            tvp = tswapl(sel->tvp);
+            unlock_user_struct(sel, arg1, 0);
+            ret = do_select(nsel, inp, outp, exp, tvp);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_pselect6
+    case TARGET_NR_pselect6:
+        {
+            abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
+            fd_set rfds, wfds, efds;
+            fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+            struct timespec ts, *ts_ptr;
+
+            /*
+             * The 6th arg is actually two args smashed together,
+             * so we cannot use the C library.
+             */
+            sigset_t set;
+            struct {
+                sigset_t *set;
+                size_t size;
+            } sig, *sig_ptr;
+
+            abi_ulong arg_sigset, arg_sigsize, *arg7;
+            target_sigset_t *target_sigset;
+
+            n = arg1;
+            rfd_addr = arg2;
+            wfd_addr = arg3;
+            efd_addr = arg4;
+            ts_addr = arg5;
+
+            ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+            ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+            ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+            if (ret) {
+                goto fail;
+            }
+
+            /*
+             * This takes a timespec, and not a timeval, so we cannot
+             * use the do_select() helper ...
+             */
+            if (ts_addr) {
+                if (target_to_host_timespec(&ts, ts_addr)) {
+                    goto efault;
+                }
+                ts_ptr = &ts;
+            } else {
+                ts_ptr = NULL;
+            }
+
+            /* Extract the two packed args for the sigset */
+            if (arg6) {
+                sig_ptr = &sig;
+                sig.size = _NSIG / 8;
+
+                arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
+                if (!arg7) {
+                    goto efault;
+                }
+                arg_sigset = tswapl(arg7[0]);
+                arg_sigsize = tswapl(arg7[1]);
+                unlock_user(arg7, arg6, 0);
+
+                if (arg_sigset) {
+                    sig.set = &set;
+                    if (arg_sigsize != sizeof(*target_sigset)) {
+                        /* Like the kernel, we enforce correct size sigsets */
+                        ret = -TARGET_EINVAL;
+                        goto fail;
+                    }
+                    target_sigset = lock_user(VERIFY_READ, arg_sigset,
+                                              sizeof(*target_sigset), 1);
+                    if (!target_sigset) {
+                        goto efault;
+                    }
+                    target_to_host_sigset(&set, target_sigset);
+                    unlock_user(target_sigset, arg_sigset, 0);
+                } else {
+                    sig.set = NULL;
+                }
+            } else {
+                sig_ptr = NULL;
+            }
+
+            ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
+                                         ts_ptr, sig_ptr));
+
+            if (!is_error(ret)) {
+                if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+                    goto efault;
+                if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+                    goto efault;
+                if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+                    goto efault;
+
+                if (ts_addr && host_to_target_timespec(ts_addr, &ts))
+                    goto efault;
+            }
+        }
+        break;
+#endif
+    case TARGET_NR_symlink:
+        {
+            void *p2;
+            p = lock_user_string(arg1);
+            p2 = lock_user_string(arg2);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(symlink(p, p2));
+            unlock_user(p2, arg2, 0);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
+    case TARGET_NR_symlinkat:
+        {
+            void *p2;
+            p  = lock_user_string(arg1);
+            p2 = lock_user_string(arg3);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(sys_symlinkat(p, arg2, p2));
+            unlock_user(p2, arg3, 0);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_oldlstat
+    case TARGET_NR_oldlstat:
+        goto unimplemented;
+#endif
+    case TARGET_NR_readlink:
+        {
+            void *p2, *temp;
+            p = lock_user_string(arg1);
+            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+            if (!p || !p2)
+                ret = -TARGET_EFAULT;
+            else {
+                if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
+                    char real[PATH_MAX];
+                    temp = realpath(exec_path,real);
+                    ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
+                    snprintf((char *)p2, arg3, "%s", real);
+                    }
+                else
+                    ret = get_errno(readlink(path(p), p2, arg3));
+            }
+            unlock_user(p2, arg2, ret);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
+    case TARGET_NR_readlinkat:
+        {
+            void *p2;
+            p  = lock_user_string(arg2);
+            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+            if (!p || !p2)
+        	ret = -TARGET_EFAULT;
+            else
+                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
+            unlock_user(p2, arg3, ret);
+            unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_uselib
+    case TARGET_NR_uselib:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_swapon
+    case TARGET_NR_swapon:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(swapon(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+    case TARGET_NR_reboot:
+        goto unimplemented;
+#ifdef TARGET_NR_readdir
+    case TARGET_NR_readdir:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_mmap
+    case TARGET_NR_mmap:
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || \
+    defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
+    || defined(TARGET_S390X)
+        {
+            abi_ulong *v;
+            abi_ulong v1, v2, v3, v4, v5, v6;
+            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
+                goto efault;
+            v1 = tswapl(v[0]);
+            v2 = tswapl(v[1]);
+            v3 = tswapl(v[2]);
+            v4 = tswapl(v[3]);
+            v5 = tswapl(v[4]);
+            v6 = tswapl(v[5]);
+            unlock_user(v, arg1, 0);
+            ret = get_errno(target_mmap(v1, v2, v3,
+                                        target_to_host_bitmask(v4, mmap_flags_tbl),
+                                        v5, v6));
+        }
+#else
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
+                                    arg5,
+                                    arg6));
+#endif
+        break;
+#endif
+#ifdef TARGET_NR_mmap2
+    case TARGET_NR_mmap2:
+#ifndef MMAP_SHIFT
+#define MMAP_SHIFT 12
+#endif
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
+                                    arg5,
+                                    arg6 << MMAP_SHIFT));
+        break;
+#endif
+    case TARGET_NR_munmap:
+        ret = get_errno(target_munmap(arg1, arg2));
+        break;
+    case TARGET_NR_mprotect:
+        {
+            TaskState *ts = ((CPUState *)cpu_env)->opaque;
+            /* Special hack to detect libc making the stack executable.  */
+            if ((arg3 & PROT_GROWSDOWN)
+                && arg1 >= ts->info->stack_limit
+                && arg1 <= ts->info->start_stack) {
+                arg3 &= ~PROT_GROWSDOWN;
+                arg2 = arg2 + arg1 - ts->info->stack_limit;
+                arg1 = ts->info->stack_limit;
+            }
+        }
+        ret = get_errno(target_mprotect(arg1, arg2, arg3));
+        break;
+#ifdef TARGET_NR_mremap
+    case TARGET_NR_mremap:
+        ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
+        break;
+#endif
+        /* ??? msync/mlock/munlock are broken for softmmu.  */
+#ifdef TARGET_NR_msync
+    case TARGET_NR_msync:
+        ret = get_errno(msync(g2h(arg1), arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_mlock
+    case TARGET_NR_mlock:
+        ret = get_errno(mlock(g2h(arg1), arg2));
+        break;
+#endif
+#ifdef TARGET_NR_munlock
+    case TARGET_NR_munlock:
+        ret = get_errno(munlock(g2h(arg1), arg2));
+        break;
+#endif
+#ifdef TARGET_NR_mlockall
+    case TARGET_NR_mlockall:
+        ret = get_errno(mlockall(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_munlockall
+    case TARGET_NR_munlockall:
+        ret = get_errno(munlockall());
+        break;
+#endif
+    case TARGET_NR_truncate:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(truncate(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_ftruncate:
+        ret = get_errno(ftruncate(arg1, arg2));
+        break;
+    case TARGET_NR_fchmod:
+        ret = get_errno(fchmod(arg1, arg2));
+        break;
+#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
+    case TARGET_NR_fchmodat:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_fchmodat(arg1, p, arg3));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_getpriority:
+        /* libc does special remapping of the return value of
+         * sys_getpriority() so it's just easiest to call
+         * sys_getpriority() directly rather than through libc. */
+        ret = get_errno(sys_getpriority(arg1, arg2));
+        break;
+    case TARGET_NR_setpriority:
+        ret = get_errno(setpriority(arg1, arg2, arg3));
+        break;
+#ifdef TARGET_NR_profil
+    case TARGET_NR_profil:
+        goto unimplemented;
+#endif
+    case TARGET_NR_statfs:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(statfs(path(p), &stfs));
+        unlock_user(p, arg1, 0);
+    convert_statfs:
+        if (!is_error(ret)) {
+            struct target_statfs *target_stfs;
+
+            if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
+                goto efault;
+            __put_user(stfs.f_type, &target_stfs->f_type);
+            __put_user(stfs.f_bsize, &target_stfs->f_bsize);
+            __put_user(stfs.f_blocks, &target_stfs->f_blocks);
+            __put_user(stfs.f_bfree, &target_stfs->f_bfree);
+            __put_user(stfs.f_bavail, &target_stfs->f_bavail);
+            __put_user(stfs.f_files, &target_stfs->f_files);
+            __put_user(stfs.f_ffree, &target_stfs->f_ffree);
+            __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
+            __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
+            __put_user(stfs.f_namelen, &target_stfs->f_namelen);
+            unlock_user_struct(target_stfs, arg2, 1);
+        }
+        break;
+    case TARGET_NR_fstatfs:
+        ret = get_errno(fstatfs(arg1, &stfs));
+        goto convert_statfs;
+#ifdef TARGET_NR_statfs64
+    case TARGET_NR_statfs64:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(statfs(path(p), &stfs));
+        unlock_user(p, arg1, 0);
+    convert_statfs64:
+        if (!is_error(ret)) {
+            struct target_statfs64 *target_stfs;
+
+            if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
+                goto efault;
+            __put_user(stfs.f_type, &target_stfs->f_type);
+            __put_user(stfs.f_bsize, &target_stfs->f_bsize);
+            __put_user(stfs.f_blocks, &target_stfs->f_blocks);
+            __put_user(stfs.f_bfree, &target_stfs->f_bfree);
+            __put_user(stfs.f_bavail, &target_stfs->f_bavail);
+            __put_user(stfs.f_files, &target_stfs->f_files);
+            __put_user(stfs.f_ffree, &target_stfs->f_ffree);
+            __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
+            __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
+            __put_user(stfs.f_namelen, &target_stfs->f_namelen);
+            unlock_user_struct(target_stfs, arg3, 1);
+        }
+        break;
+    case TARGET_NR_fstatfs64:
+        ret = get_errno(fstatfs(arg1, &stfs));
+        goto convert_statfs64;
+#endif
+#ifdef TARGET_NR_ioperm
+    case TARGET_NR_ioperm:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_socketcall
+    case TARGET_NR_socketcall:
+        ret = do_socketcall(arg1, arg2);
+        break;
+#endif
+#ifdef TARGET_NR_accept
+    case TARGET_NR_accept:
+        ret = do_accept(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_bind
+    case TARGET_NR_bind:
+        ret = do_bind(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_connect
+    case TARGET_NR_connect:
+        ret = do_connect(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_getpeername
+    case TARGET_NR_getpeername:
+        ret = do_getpeername(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_getsockname
+    case TARGET_NR_getsockname:
+        ret = do_getsockname(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_getsockopt
+    case TARGET_NR_getsockopt:
+        ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+#endif
+#ifdef TARGET_NR_listen
+    case TARGET_NR_listen:
+        ret = get_errno(listen(arg1, arg2));
+        break;
+#endif
+#ifdef TARGET_NR_recv
+    case TARGET_NR_recv:
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
+        break;
+#endif
+#ifdef TARGET_NR_recvfrom
+    case TARGET_NR_recvfrom:
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+#endif
+#ifdef TARGET_NR_recvmsg
+    case TARGET_NR_recvmsg:
+        ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
+        break;
+#endif
+#ifdef TARGET_NR_send
+    case TARGET_NR_send:
+        ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
+        break;
+#endif
+#ifdef TARGET_NR_sendmsg
+    case TARGET_NR_sendmsg:
+        ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
+        break;
+#endif
+#ifdef TARGET_NR_sendto
+    case TARGET_NR_sendto:
+        ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+#endif
+#ifdef TARGET_NR_shutdown
+    case TARGET_NR_shutdown:
+        ret = get_errno(shutdown(arg1, arg2));
+        break;
+#endif
+#ifdef TARGET_NR_socket
+    case TARGET_NR_socket:
+        ret = do_socket(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_socketpair
+    case TARGET_NR_socketpair:
+        ret = do_socketpair(arg1, arg2, arg3, arg4);
+        break;
+#endif
+#ifdef TARGET_NR_setsockopt
+    case TARGET_NR_setsockopt:
+        ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
+        break;
+#endif
+
+    case TARGET_NR_syslog:
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
+        unlock_user(p, arg2, 0);
+        break;
+
+    case TARGET_NR_setitimer:
+        {
+            struct itimerval value, ovalue, *pvalue;
+
+            if (arg2) {
+                pvalue = &value;
+                if (copy_from_user_timeval(&pvalue->it_interval, arg2)
+                    || copy_from_user_timeval(&pvalue->it_value,
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
+            } else {
+                pvalue = NULL;
+            }
+            ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+            if (!is_error(ret) && arg3) {
+                if (copy_to_user_timeval(arg3,
+                                         &ovalue.it_interval)
+                    || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
+                                            &ovalue.it_value))
+                    goto efault;
+            }
+        }
+        break;
+    case TARGET_NR_getitimer:
+        {
+            struct itimerval value;
+
+            ret = get_errno(getitimer(arg1, &value));
+            if (!is_error(ret) && arg2) {
+                if (copy_to_user_timeval(arg2,
+                                         &value.it_interval)
+                    || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
+                                            &value.it_value))
+                    goto efault;
+            }
+        }
+        break;
+    case TARGET_NR_stat:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(stat(path(p), &st));
+        unlock_user(p, arg1, 0);
+        goto do_stat;
+    case TARGET_NR_lstat:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(lstat(path(p), &st));
+        unlock_user(p, arg1, 0);
+        goto do_stat;
+    case TARGET_NR_fstat:
+        {
+            ret = get_errno(fstat(arg1, &st));
+        do_stat:
+            if (!is_error(ret)) {
+                struct target_stat *target_st;
+
+                if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
+                    goto efault;
+                memset(target_st, 0, sizeof(*target_st));
+                __put_user(st.st_dev, &target_st->st_dev);
+                __put_user(st.st_ino, &target_st->st_ino);
+                __put_user(st.st_mode, &target_st->st_mode);
+                __put_user(st.st_uid, &target_st->st_uid);
+                __put_user(st.st_gid, &target_st->st_gid);
+                __put_user(st.st_nlink, &target_st->st_nlink);
+                __put_user(st.st_rdev, &target_st->st_rdev);
+                __put_user(st.st_size, &target_st->st_size);
+                __put_user(st.st_blksize, &target_st->st_blksize);
+                __put_user(st.st_blocks, &target_st->st_blocks);
+                __put_user(st.st_atime, &target_st->target_st_atime);
+                __put_user(st.st_mtime, &target_st->target_st_mtime);
+                __put_user(st.st_ctime, &target_st->target_st_ctime);
+                unlock_user_struct(target_st, arg2, 1);
+            }
+        }
+        break;
+#ifdef TARGET_NR_olduname
+    case TARGET_NR_olduname:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_iopl
+    case TARGET_NR_iopl:
+        goto unimplemented;
+#endif
+    case TARGET_NR_vhangup:
+        ret = get_errno(vhangup());
+        break;
+#ifdef TARGET_NR_idle
+    case TARGET_NR_idle:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_syscall
+    case TARGET_NR_syscall:
+        ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
+                         arg6, arg7, arg8, 0);
+        break;
+#endif
+    case TARGET_NR_wait4:
+        {
+            int status;
+            abi_long status_ptr = arg2;
+            struct rusage rusage, *rusage_ptr;
+            abi_ulong target_rusage = arg4;
+            if (target_rusage)
+                rusage_ptr = &rusage;
+            else
+                rusage_ptr = NULL;
+            ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
+            if (!is_error(ret)) {
+                if (status_ptr) {
+                    status = host_to_target_waitstatus(status);
+                    if (put_user_s32(status, status_ptr))
+                        goto efault;
+                }
+                if (target_rusage)
+                    host_to_target_rusage(target_rusage, &rusage);
+            }
+        }
+        break;
+#ifdef TARGET_NR_swapoff
+    case TARGET_NR_swapoff:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(swapoff(p));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+    case TARGET_NR_sysinfo:
+        {
+            struct target_sysinfo *target_value;
+            struct sysinfo value;
+            ret = get_errno(sysinfo(&value));
+            if (!is_error(ret) && arg1)
+            {
+                if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
+                    goto efault;
+                __put_user(value.uptime, &target_value->uptime);
+                __put_user(value.loads[0], &target_value->loads[0]);
+                __put_user(value.loads[1], &target_value->loads[1]);
+                __put_user(value.loads[2], &target_value->loads[2]);
+                __put_user(value.totalram, &target_value->totalram);
+                __put_user(value.freeram, &target_value->freeram);
+                __put_user(value.sharedram, &target_value->sharedram);
+                __put_user(value.bufferram, &target_value->bufferram);
+                __put_user(value.totalswap, &target_value->totalswap);
+                __put_user(value.freeswap, &target_value->freeswap);
+                __put_user(value.procs, &target_value->procs);
+                __put_user(value.totalhigh, &target_value->totalhigh);
+                __put_user(value.freehigh, &target_value->freehigh);
+                __put_user(value.mem_unit, &target_value->mem_unit);
+                unlock_user_struct(target_value, arg1, 1);
+            }
+        }
+        break;
+#ifdef TARGET_NR_ipc
+    case TARGET_NR_ipc:
+	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
+	break;
+#endif
+#ifdef TARGET_NR_semget
+    case TARGET_NR_semget:
+        ret = get_errno(semget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semop
+    case TARGET_NR_semop:
+        ret = get_errno(do_semop(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semctl
+    case TARGET_NR_semctl:
+        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+        break;
+#endif
+#ifdef TARGET_NR_msgctl
+    case TARGET_NR_msgctl:
+        ret = do_msgctl(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_msgget
+    case TARGET_NR_msgget:
+        ret = get_errno(msgget(arg1, arg2));
+        break;
+#endif
+#ifdef TARGET_NR_msgrcv
+    case TARGET_NR_msgrcv:
+        ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
+        break;
+#endif
+#ifdef TARGET_NR_msgsnd
+    case TARGET_NR_msgsnd:
+        ret = do_msgsnd(arg1, arg2, arg3, arg4);
+        break;
+#endif
+#ifdef TARGET_NR_shmget
+    case TARGET_NR_shmget:
+        ret = get_errno(shmget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_shmctl
+    case TARGET_NR_shmctl:
+        ret = do_shmctl(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmat
+    case TARGET_NR_shmat:
+        ret = do_shmat(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmdt
+    case TARGET_NR_shmdt:
+        ret = do_shmdt(arg1);
+        break;
+#endif
+    case TARGET_NR_fsync:
+        ret = get_errno(fsync(arg1));
+        break;
+    case TARGET_NR_clone:
+#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
+        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
+#elif defined(TARGET_CRIS)
+        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
+#elif defined(TARGET_S390X)
+        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
+#else
+        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
+#endif
+        break;
+#ifdef __NR_exit_group
+        /* new thread calls */
+    case TARGET_NR_exit_group:
+#ifdef TARGET_GPROF
+        _mcleanup();
+#endif
+        gdb_exit(cpu_env, arg1);
+        ret = get_errno(exit_group(arg1));
+        break;
+#endif
+    case TARGET_NR_setdomainname:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(setdomainname(p, arg2));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_uname:
+        /* no need to transcode because we use the linux syscall */
+        {
+            struct new_utsname * buf;
+
+            if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
+                goto efault;
+            ret = get_errno(sys_uname(buf));
+            if (!is_error(ret)) {
+                /* Overrite the native machine name with whatever is being
+                   emulated. */
+                strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
+                /* Allow the user to override the reported release.  */
+                if (qemu_uname_release && *qemu_uname_release)
+                  strcpy (buf->release, qemu_uname_release);
+            }
+            unlock_user_struct(buf, arg1, 1);
+        }
+        break;
+#ifdef TARGET_I386
+    case TARGET_NR_modify_ldt:
+        ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
+        break;
+#if !defined(TARGET_X86_64)
+    case TARGET_NR_vm86old:
+        goto unimplemented;
+    case TARGET_NR_vm86:
+        ret = do_vm86(cpu_env, arg1, arg2);
+        break;
+#endif
+#endif
+    case TARGET_NR_adjtimex:
+        goto unimplemented;
+#ifdef TARGET_NR_create_module
+    case TARGET_NR_create_module:
+#endif
+    case TARGET_NR_init_module:
+    case TARGET_NR_delete_module:
+#ifdef TARGET_NR_get_kernel_syms
+    case TARGET_NR_get_kernel_syms:
+#endif
+        goto unimplemented;
+    case TARGET_NR_quotactl:
+        goto unimplemented;
+    case TARGET_NR_getpgid:
+        ret = get_errno(getpgid(arg1));
+        break;
+    case TARGET_NR_fchdir:
+        ret = get_errno(fchdir(arg1));
+        break;
+#ifdef TARGET_NR_bdflush /* not on x86_64 */
+    case TARGET_NR_bdflush:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_sysfs
+    case TARGET_NR_sysfs:
+        goto unimplemented;
+#endif
+    case TARGET_NR_personality:
+        ret = get_errno(personality(arg1));
+        break;
+#ifdef TARGET_NR_afs_syscall
+    case TARGET_NR_afs_syscall:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR__llseek /* Not on alpha */
+    case TARGET_NR__llseek:
+        {
+            int64_t res;
+#if !defined(__NR_llseek)
+            res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
+            if (res == -1) {
+                ret = get_errno(res);
+            } else {
+                ret = 0;
+            }
+#else
+            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
+#endif
+            if ((ret == 0) && put_user_s64(res, arg4)) {
+                goto efault;
+            }
+        }
+        break;
+#endif
+    case TARGET_NR_getdents:
+#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
+        {
+            struct target_dirent *target_dirp;
+            struct linux_dirent *dirp;
+            abi_long count = arg3;
+
+	    dirp = malloc(count);
+	    if (!dirp) {
+                ret = -TARGET_ENOMEM;
+                goto fail;
+            }
+
+            ret = get_errno(sys_getdents(arg1, dirp, count));
+            if (!is_error(ret)) {
+                struct linux_dirent *de;
+		struct target_dirent *tde;
+                int len = ret;
+                int reclen, treclen;
+		int count1, tnamelen;
+
+		count1 = 0;
+                de = dirp;
+                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
+                    goto efault;
+		tde = target_dirp;
+                while (len > 0) {
+                    reclen = de->d_reclen;
+		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
+                    tde->d_reclen = tswap16(treclen);
+                    tde->d_ino = tswapl(de->d_ino);
+                    tde->d_off = tswapl(de->d_off);
+		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
+		    if (tnamelen > 256)
+                        tnamelen = 256;
+                    /* XXX: may not be correct */
+                    pstrcpy(tde->d_name, tnamelen, de->d_name);
+                    de = (struct linux_dirent *)((char *)de + reclen);
+                    len -= reclen;
+                    tde = (struct target_dirent *)((char *)tde + treclen);
+		    count1 += treclen;
+                }
+		ret = count1;
+                unlock_user(target_dirp, arg2, ret);
+            }
+	    free(dirp);
+        }
+#else
+        {
+            struct linux_dirent *dirp;
+            abi_long count = arg3;
+
+            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
+                goto efault;
+            ret = get_errno(sys_getdents(arg1, dirp, count));
+            if (!is_error(ret)) {
+                struct linux_dirent *de;
+                int len = ret;
+                int reclen;
+                de = dirp;
+                while (len > 0) {
+                    reclen = de->d_reclen;
+                    if (reclen > len)
+                        break;
+                    de->d_reclen = tswap16(reclen);
+                    tswapls(&de->d_ino);
+                    tswapls(&de->d_off);
+                    de = (struct linux_dirent *)((char *)de + reclen);
+                    len -= reclen;
+                }
+            }
+            unlock_user(dirp, arg2, ret);
+        }
+#endif
+        break;
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
+    case TARGET_NR_getdents64:
+        {
+            struct linux_dirent64 *dirp;
+            abi_long count = arg3;
+            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
+                goto efault;
+            ret = get_errno(sys_getdents64(arg1, dirp, count));
+            if (!is_error(ret)) {
+                struct linux_dirent64 *de;
+                int len = ret;
+                int reclen;
+                de = dirp;
+                while (len > 0) {
+                    reclen = de->d_reclen;
+                    if (reclen > len)
+                        break;
+                    de->d_reclen = tswap16(reclen);
+                    tswap64s((uint64_t *)&de->d_ino);
+                    tswap64s((uint64_t *)&de->d_off);
+                    de = (struct linux_dirent64 *)((char *)de + reclen);
+                    len -= reclen;
+                }
+            }
+            unlock_user(dirp, arg2, ret);
+        }
+        break;
+#endif /* TARGET_NR_getdents64 */
+#if defined(TARGET_NR__newselect) || defined(TARGET_S390X)
+#ifdef TARGET_S390X
+    case TARGET_NR_select:
+#else
+    case TARGET_NR__newselect:
+#endif
+        ret = do_select(arg1, arg2, arg3, arg4, arg5);
+        break;
+#endif
+#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
+# ifdef TARGET_NR_poll
+    case TARGET_NR_poll:
+# endif
+# ifdef TARGET_NR_ppoll
+    case TARGET_NR_ppoll:
+# endif
+        {
+            struct target_pollfd *target_pfd;
+            unsigned int nfds = arg2;
+            int timeout = arg3;
+            struct pollfd *pfd;
+            unsigned int i;
+
+            target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
+            if (!target_pfd)
+                goto efault;
+
+            pfd = alloca(sizeof(struct pollfd) * nfds);
+            for(i = 0; i < nfds; i++) {
+                pfd[i].fd = tswap32(target_pfd[i].fd);
+                pfd[i].events = tswap16(target_pfd[i].events);
+            }
+
+# ifdef TARGET_NR_ppoll
+            if (num == TARGET_NR_ppoll) {
+                struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
+                target_sigset_t *target_set;
+                sigset_t _set, *set = &_set;
+
+                if (arg3) {
+                    if (target_to_host_timespec(timeout_ts, arg3)) {
+                        unlock_user(target_pfd, arg1, 0);
+                        goto efault;
+                    }
+                } else {
+                    timeout_ts = NULL;
+                }
+
+                if (arg4) {
+                    target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
+                    if (!target_set) {
+                        unlock_user(target_pfd, arg1, 0);
+                        goto efault;
+                    }
+                    target_to_host_sigset(set, target_set);
+                } else {
+                    set = NULL;
+                }
+
+                ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
+
+                if (!is_error(ret) && arg3) {
+                    host_to_target_timespec(arg3, timeout_ts);
+                }
+                if (arg4) {
+                    unlock_user(target_set, arg4, 0);
+                }
+            } else
+# endif
+                ret = get_errno(poll(pfd, nfds, timeout));
+
+            if (!is_error(ret)) {
+                for(i = 0; i < nfds; i++) {
+                    target_pfd[i].revents = tswap16(pfd[i].revents);
+                }
+            }
+            unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+        }
+        break;
+#endif
+    case TARGET_NR_flock:
+        /* NOTE: the flock constant seems to be the same for every
+           Linux platform */
+        ret = get_errno(flock(arg1, arg2));
+        break;
+    case TARGET_NR_readv:
+        {
+            int count = arg3;
+            struct iovec *vec;
+
+            vec = alloca(count * sizeof(struct iovec));
+            if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
+                goto efault;
+            ret = get_errno(readv(arg1, vec, count));
+            unlock_iovec(vec, arg2, count, 1);
+        }
+        break;
+    case TARGET_NR_writev:
+        {
+            int count = arg3;
+            struct iovec *vec;
+
+            vec = alloca(count * sizeof(struct iovec));
+            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+                goto efault;
+            ret = get_errno(writev(arg1, vec, count));
+            unlock_iovec(vec, arg2, count, 0);
+        }
+        break;
+    case TARGET_NR_getsid:
+        ret = get_errno(getsid(arg1));
+        break;
+#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
+    case TARGET_NR_fdatasync:
+        ret = get_errno(fdatasync(arg1));
+        break;
+#endif
+    case TARGET_NR__sysctl:
+        /* We don't implement this, but ENOTDIR is always a safe
+           return value. */
+        ret = -TARGET_ENOTDIR;
+        break;
+    case TARGET_NR_sched_getaffinity:
+        {
+            unsigned int mask_size;
+            unsigned long *mask;
+
+            /*
+             * sched_getaffinity needs multiples of ulong, so need to take
+             * care of mismatches between target ulong and host ulong sizes.
+             */
+            if (arg2 & (sizeof(abi_ulong) - 1)) {
+                ret = -TARGET_EINVAL;
+                break;
+            }
+            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
+
+            mask = alloca(mask_size);
+            ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
+
+            if (!is_error(ret)) {
+                if (copy_to_user(arg3, mask, ret)) {
+                    goto efault;
+                }
+            }
+        }
+        break;
+    case TARGET_NR_sched_setaffinity:
+        {
+            unsigned int mask_size;
+            unsigned long *mask;
+
+            /*
+             * sched_setaffinity needs multiples of ulong, so need to take
+             * care of mismatches between target ulong and host ulong sizes.
+             */
+            if (arg2 & (sizeof(abi_ulong) - 1)) {
+                ret = -TARGET_EINVAL;
+                break;
+            }
+            mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
+
+            mask = alloca(mask_size);
+            if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
+                goto efault;
+            }
+            memcpy(mask, p, arg2);
+            unlock_user_struct(p, arg2, 0);
+
+            ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
+        }
+        break;
+    case TARGET_NR_sched_setparam:
+        {
+            struct sched_param *target_schp;
+            struct sched_param schp;
+
+            if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
+                goto efault;
+            schp.sched_priority = tswap32(target_schp->sched_priority);
+            unlock_user_struct(target_schp, arg2, 0);
+            ret = get_errno(sched_setparam(arg1, &schp));
+        }
+        break;
+    case TARGET_NR_sched_getparam:
+        {
+            struct sched_param *target_schp;
+            struct sched_param schp;
+            ret = get_errno(sched_getparam(arg1, &schp));
+            if (!is_error(ret)) {
+                if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
+                    goto efault;
+                target_schp->sched_priority = tswap32(schp.sched_priority);
+                unlock_user_struct(target_schp, arg2, 1);
+            }
+        }
+        break;
+    case TARGET_NR_sched_setscheduler:
+        {
+            struct sched_param *target_schp;
+            struct sched_param schp;
+            if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
+                goto efault;
+            schp.sched_priority = tswap32(target_schp->sched_priority);
+            unlock_user_struct(target_schp, arg3, 0);
+            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
+        }
+        break;
+    case TARGET_NR_sched_getscheduler:
+        ret = get_errno(sched_getscheduler(arg1));
+        break;
+    case TARGET_NR_sched_yield:
+        ret = get_errno(sched_yield());
+        break;
+    case TARGET_NR_sched_get_priority_max:
+        ret = get_errno(sched_get_priority_max(arg1));
+        break;
+    case TARGET_NR_sched_get_priority_min:
+        ret = get_errno(sched_get_priority_min(arg1));
+        break;
+    case TARGET_NR_sched_rr_get_interval:
+        {
+            struct timespec ts;
+            ret = get_errno(sched_rr_get_interval(arg1, &ts));
+            if (!is_error(ret)) {
+                host_to_target_timespec(arg2, &ts);
+            }
+        }
+        break;
+    case TARGET_NR_nanosleep:
+        {
+            struct timespec req, rem;
+            target_to_host_timespec(&req, arg1);
+            ret = get_errno(nanosleep(&req, &rem));
+            if (is_error(ret) && arg2) {
+                host_to_target_timespec(arg2, &rem);
+            }
+        }
+        break;
+#ifdef TARGET_NR_query_module
+    case TARGET_NR_query_module:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_nfsservctl
+    case TARGET_NR_nfsservctl:
+        goto unimplemented;
+#endif
+    case TARGET_NR_prctl:
+        switch (arg1)
+            {
+            case PR_GET_PDEATHSIG:
+                {
+                    int deathsig;
+                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+                    if (!is_error(ret) && arg2
+                        && put_user_ual(deathsig, arg2))
+                        goto efault;
+                }
+                break;
+            default:
+                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+                break;
+            }
+        break;
+#ifdef TARGET_NR_arch_prctl
+    case TARGET_NR_arch_prctl:
+#if defined(TARGET_I386) && !defined(TARGET_ABI32)
+        ret = do_arch_prctl(cpu_env, arg1, arg2);
+        break;
+#else
+        goto unimplemented;
+#endif
+#endif
+#ifdef TARGET_NR_pread
+    case TARGET_NR_pread:
+        if (regpairs_aligned(cpu_env))
+            arg4 = arg5;
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(pread(arg1, p, arg3, arg4));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_NR_pwrite:
+        if (regpairs_aligned(cpu_env))
+            arg4 = arg5;
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(pwrite(arg1, p, arg3, arg4));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+#ifdef TARGET_NR_pread64
+    case TARGET_NR_pread64:
+        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+            goto efault;
+        ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
+        unlock_user(p, arg2, ret);
+        break;
+    case TARGET_NR_pwrite64:
+        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+            goto efault;
+        ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+    case TARGET_NR_getcwd:
+        if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
+            goto efault;
+        ret = get_errno(sys_getcwd1(p, arg2));
+        unlock_user(p, arg1, ret);
+        break;
+    case TARGET_NR_capget:
+        goto unimplemented;
+    case TARGET_NR_capset:
+        goto unimplemented;
+    case TARGET_NR_sigaltstack:
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
+    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
+    defined(TARGET_M68K) || defined(TARGET_S390X)
+        ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env));
+        break;
+#else
+        goto unimplemented;
+#endif
+    case TARGET_NR_sendfile:
+        goto unimplemented;
+#ifdef TARGET_NR_getpmsg
+    case TARGET_NR_getpmsg:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_putpmsg
+    case TARGET_NR_putpmsg:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_vfork
+    case TARGET_NR_vfork:
+        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
+                        0, 0, 0, 0));
+        break;
+#endif
+#ifdef TARGET_NR_ugetrlimit
+    case TARGET_NR_ugetrlimit:
+    {
+	struct rlimit rlim;
+	int resource = target_to_host_resource(arg1);
+	ret = get_errno(getrlimit(resource, &rlim));
+	if (!is_error(ret)) {
+	    struct target_rlimit *target_rlim;
+            if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
+                goto efault;
+	    target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+	    target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+            unlock_user_struct(target_rlim, arg2, 1);
+	}
+	break;
+    }
+#endif
+#ifdef TARGET_NR_truncate64
+    case TARGET_NR_truncate64:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+	ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
+        unlock_user(p, arg1, 0);
+	break;
+#endif
+#ifdef TARGET_NR_ftruncate64
+    case TARGET_NR_ftruncate64:
+	ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
+	break;
+#endif
+#ifdef TARGET_NR_stat64
+    case TARGET_NR_stat64:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(stat(path(p), &st));
+        unlock_user(p, arg1, 0);
+        if (!is_error(ret))
+            ret = host_to_target_stat64(cpu_env, arg2, &st);
+        break;
+#endif
+#ifdef TARGET_NR_lstat64
+    case TARGET_NR_lstat64:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(lstat(path(p), &st));
+        unlock_user(p, arg1, 0);
+        if (!is_error(ret))
+            ret = host_to_target_stat64(cpu_env, arg2, &st);
+        break;
+#endif
+#ifdef TARGET_NR_fstat64
+    case TARGET_NR_fstat64:
+        ret = get_errno(fstat(arg1, &st));
+        if (!is_error(ret))
+            ret = host_to_target_stat64(cpu_env, arg2, &st);
+        break;
+#endif
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
+#ifdef TARGET_NR_fstatat64
+    case TARGET_NR_fstatat64:
+#endif
+#ifdef TARGET_NR_newfstatat
+    case TARGET_NR_newfstatat:
+#endif
+        if (!(p = lock_user_string(arg2)))
+            goto efault;
+#ifdef __NR_fstatat64
+        ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
+#else
+        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
+#endif
+        if (!is_error(ret))
+            ret = host_to_target_stat64(cpu_env, arg3, &st);
+        break;
+#endif
+    case TARGET_NR_lchown:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
+        unlock_user(p, arg1, 0);
+        break;
+#ifdef TARGET_NR_getuid
+    case TARGET_NR_getuid:
+        ret = get_errno(high2lowuid(getuid()));
+        break;
+#endif
+#ifdef TARGET_NR_getgid
+    case TARGET_NR_getgid:
+        ret = get_errno(high2lowgid(getgid()));
+        break;
+#endif
+#ifdef TARGET_NR_geteuid
+    case TARGET_NR_geteuid:
+        ret = get_errno(high2lowuid(geteuid()));
+        break;
+#endif
+#ifdef TARGET_NR_getegid
+    case TARGET_NR_getegid:
+        ret = get_errno(high2lowgid(getegid()));
+        break;
+#endif
+    case TARGET_NR_setreuid:
+        ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
+        break;
+    case TARGET_NR_setregid:
+        ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
+        break;
+    case TARGET_NR_getgroups:
+        {
+            int gidsetsize = arg1;
+            target_id *target_grouplist;
+            gid_t *grouplist;
+            int i;
+
+            grouplist = alloca(gidsetsize * sizeof(gid_t));
+            ret = get_errno(getgroups(gidsetsize, grouplist));
+            if (gidsetsize == 0)
+                break;
+            if (!is_error(ret)) {
+                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
+                if (!target_grouplist)
+                    goto efault;
+                for(i = 0;i < ret; i++)
+                    target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
+                unlock_user(target_grouplist, arg2, gidsetsize * 2);
+            }
+        }
+        break;
+    case TARGET_NR_setgroups:
+        {
+            int gidsetsize = arg1;
+            target_id *target_grouplist;
+            gid_t *grouplist;
+            int i;
+
+            grouplist = alloca(gidsetsize * sizeof(gid_t));
+            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+            if (!target_grouplist) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+            for(i = 0;i < gidsetsize; i++)
+                grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
+            unlock_user(target_grouplist, arg2, 0);
+            ret = get_errno(setgroups(gidsetsize, grouplist));
+        }
+        break;
+    case TARGET_NR_fchown:
+        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
+        break;
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
+    case TARGET_NR_fchownat:
+        if (!(p = lock_user_string(arg2))) 
+            goto efault;
+        ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+#ifdef TARGET_NR_setresuid
+    case TARGET_NR_setresuid:
+        ret = get_errno(setresuid(low2highuid(arg1),
+                                  low2highuid(arg2),
+                                  low2highuid(arg3)));
+        break;
+#endif
+#ifdef TARGET_NR_getresuid
+    case TARGET_NR_getresuid:
+        {
+            uid_t ruid, euid, suid;
+            ret = get_errno(getresuid(&ruid, &euid, &suid));
+            if (!is_error(ret)) {
+                if (put_user_u16(high2lowuid(ruid), arg1)
+                    || put_user_u16(high2lowuid(euid), arg2)
+                    || put_user_u16(high2lowuid(suid), arg3))
+                    goto efault;
+            }
+        }
+        break;
+#endif
+#ifdef TARGET_NR_getresgid
+    case TARGET_NR_setresgid:
+        ret = get_errno(setresgid(low2highgid(arg1),
+                                  low2highgid(arg2),
+                                  low2highgid(arg3)));
+        break;
+#endif
+#ifdef TARGET_NR_getresgid
+    case TARGET_NR_getresgid:
+        {
+            gid_t rgid, egid, sgid;
+            ret = get_errno(getresgid(&rgid, &egid, &sgid));
+            if (!is_error(ret)) {
+                if (put_user_u16(high2lowgid(rgid), arg1)
+                    || put_user_u16(high2lowgid(egid), arg2)
+                    || put_user_u16(high2lowgid(sgid), arg3))
+                    goto efault;
+            }
+        }
+        break;
+#endif
+    case TARGET_NR_chown:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
+        unlock_user(p, arg1, 0);
+        break;
+    case TARGET_NR_setuid:
+        ret = get_errno(setuid(low2highuid(arg1)));
+        break;
+    case TARGET_NR_setgid:
+        ret = get_errno(setgid(low2highgid(arg1)));
+        break;
+    case TARGET_NR_setfsuid:
+        ret = get_errno(setfsuid(arg1));
+        break;
+    case TARGET_NR_setfsgid:
+        ret = get_errno(setfsgid(arg1));
+        break;
+
+#ifdef TARGET_NR_lchown32
+    case TARGET_NR_lchown32:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(lchown(p, arg2, arg3));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+#ifdef TARGET_NR_getuid32
+    case TARGET_NR_getuid32:
+        ret = get_errno(getuid());
+        break;
+#endif
+
+#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
+   /* Alpha specific */
+    case TARGET_NR_getxuid:
+         {
+            uid_t euid;
+            euid=geteuid();
+            ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
+         }
+        ret = get_errno(getuid());
+        break;
+#endif
+#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
+   /* Alpha specific */
+    case TARGET_NR_getxgid:
+         {
+            uid_t egid;
+            egid=getegid();
+            ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
+         }
+        ret = get_errno(getgid());
+        break;
+#endif
+#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
+    /* Alpha specific */
+    case TARGET_NR_osf_getsysinfo:
+        ret = -TARGET_EOPNOTSUPP;
+        switch (arg1) {
+          case TARGET_GSI_IEEE_FP_CONTROL:
+            {
+                uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
+
+                /* Copied from linux ieee_fpcr_to_swcr.  */
+                swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
+                swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
+                swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
+                                        | SWCR_TRAP_ENABLE_DZE
+                                        | SWCR_TRAP_ENABLE_OVF);
+                swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
+                                        | SWCR_TRAP_ENABLE_INE);
+                swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
+                swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
+
+                if (put_user_u64 (swcr, arg2))
+                        goto efault;
+                ret = 0;
+            }
+            break;
+
+          /* case GSI_IEEE_STATE_AT_SIGNAL:
+             -- Not implemented in linux kernel.
+             case GSI_UACPROC:
+             -- Retrieves current unaligned access state; not much used.
+             case GSI_PROC_TYPE:
+             -- Retrieves implver information; surely not used.
+             case GSI_GET_HWRPB:
+             -- Grabs a copy of the HWRPB; surely not used.
+          */
+        }
+        break;
+#endif
+#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
+    /* Alpha specific */
+    case TARGET_NR_osf_setsysinfo:
+        ret = -TARGET_EOPNOTSUPP;
+        switch (arg1) {
+          case TARGET_SSI_IEEE_FP_CONTROL:
+          case TARGET_SSI_IEEE_RAISE_EXCEPTION:
+            {
+                uint64_t swcr, fpcr, orig_fpcr;
+
+                if (get_user_u64 (swcr, arg2))
+                    goto efault;
+                orig_fpcr = cpu_alpha_load_fpcr (cpu_env);
+                fpcr = orig_fpcr & FPCR_DYN_MASK;
+
+                /* Copied from linux ieee_swcr_to_fpcr.  */
+                fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
+                fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
+                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
+                                  | SWCR_TRAP_ENABLE_DZE
+                                  | SWCR_TRAP_ENABLE_OVF)) << 48;
+                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
+                                  | SWCR_TRAP_ENABLE_INE)) << 57;
+                fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
+                fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
+
+                cpu_alpha_store_fpcr (cpu_env, fpcr);
+                ret = 0;
+
+                if (arg1 == TARGET_SSI_IEEE_RAISE_EXCEPTION) {
+                    /* Old exceptions are not signaled.  */
+                    fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
+
+                    /* If any exceptions set by this call, and are unmasked,
+                       send a signal.  */
+                    /* ??? FIXME */
+                }
+            }
+            break;
+
+          /* case SSI_NVPAIRS:
+             -- Used with SSIN_UACPROC to enable unaligned accesses.
+             case SSI_IEEE_STATE_AT_SIGNAL:
+             case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
+             -- Not implemented in linux kernel
+          */
+        }
+        break;
+#endif
+#ifdef TARGET_NR_osf_sigprocmask
+    /* Alpha specific.  */
+    case TARGET_NR_osf_sigprocmask:
+        {
+            abi_ulong mask;
+            int how;
+            sigset_t set, oldset;
+
+            switch(arg1) {
+            case TARGET_SIG_BLOCK:
+                how = SIG_BLOCK;
+                break;
+            case TARGET_SIG_UNBLOCK:
+                how = SIG_UNBLOCK;
+                break;
+            case TARGET_SIG_SETMASK:
+                how = SIG_SETMASK;
+                break;
+            default:
+                ret = -TARGET_EINVAL;
+                goto fail;
+            }
+            mask = arg2;
+            target_to_host_old_sigset(&set, &mask);
+            sigprocmask(how, &set, &oldset);
+            host_to_target_old_sigset(&mask, &oldset);
+            ret = mask;
+        }
+        break;
+#endif
+
+#ifdef TARGET_NR_getgid32
+    case TARGET_NR_getgid32:
+        ret = get_errno(getgid());
+        break;
+#endif
+#ifdef TARGET_NR_geteuid32
+    case TARGET_NR_geteuid32:
+        ret = get_errno(geteuid());
+        break;
+#endif
+#ifdef TARGET_NR_getegid32
+    case TARGET_NR_getegid32:
+        ret = get_errno(getegid());
+        break;
+#endif
+#ifdef TARGET_NR_setreuid32
+    case TARGET_NR_setreuid32:
+        ret = get_errno(setreuid(arg1, arg2));
+        break;
+#endif
+#ifdef TARGET_NR_setregid32
+    case TARGET_NR_setregid32:
+        ret = get_errno(setregid(arg1, arg2));
+        break;
+#endif
+#ifdef TARGET_NR_getgroups32
+    case TARGET_NR_getgroups32:
+        {
+            int gidsetsize = arg1;
+            uint32_t *target_grouplist;
+            gid_t *grouplist;
+            int i;
+
+            grouplist = alloca(gidsetsize * sizeof(gid_t));
+            ret = get_errno(getgroups(gidsetsize, grouplist));
+            if (gidsetsize == 0)
+                break;
+            if (!is_error(ret)) {
+                target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
+                if (!target_grouplist) {
+                    ret = -TARGET_EFAULT;
+                    goto fail;
+                }
+                for(i = 0;i < ret; i++)
+                    target_grouplist[i] = tswap32(grouplist[i]);
+                unlock_user(target_grouplist, arg2, gidsetsize * 4);
+            }
+        }
+        break;
+#endif
+#ifdef TARGET_NR_setgroups32
+    case TARGET_NR_setgroups32:
+        {
+            int gidsetsize = arg1;
+            uint32_t *target_grouplist;
+            gid_t *grouplist;
+            int i;
+
+            grouplist = alloca(gidsetsize * sizeof(gid_t));
+            target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
+            if (!target_grouplist) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+            for(i = 0;i < gidsetsize; i++)
+                grouplist[i] = tswap32(target_grouplist[i]);
+            unlock_user(target_grouplist, arg2, 0);
+            ret = get_errno(setgroups(gidsetsize, grouplist));
+        }
+        break;
+#endif
+#ifdef TARGET_NR_fchown32
+    case TARGET_NR_fchown32:
+        ret = get_errno(fchown(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_setresuid32
+    case TARGET_NR_setresuid32:
+        ret = get_errno(setresuid(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_getresuid32
+    case TARGET_NR_getresuid32:
+        {
+            uid_t ruid, euid, suid;
+            ret = get_errno(getresuid(&ruid, &euid, &suid));
+            if (!is_error(ret)) {
+                if (put_user_u32(ruid, arg1)
+                    || put_user_u32(euid, arg2)
+                    || put_user_u32(suid, arg3))
+                    goto efault;
+            }
+        }
+        break;
+#endif
+#ifdef TARGET_NR_setresgid32
+    case TARGET_NR_setresgid32:
+        ret = get_errno(setresgid(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_getresgid32
+    case TARGET_NR_getresgid32:
+        {
+            gid_t rgid, egid, sgid;
+            ret = get_errno(getresgid(&rgid, &egid, &sgid));
+            if (!is_error(ret)) {
+                if (put_user_u32(rgid, arg1)
+                    || put_user_u32(egid, arg2)
+                    || put_user_u32(sgid, arg3))
+                    goto efault;
+            }
+        }
+        break;
+#endif
+#ifdef TARGET_NR_chown32
+    case TARGET_NR_chown32:
+        if (!(p = lock_user_string(arg1)))
+            goto efault;
+        ret = get_errno(chown(p, arg2, arg3));
+        unlock_user(p, arg1, 0);
+        break;
+#endif
+#ifdef TARGET_NR_setuid32
+    case TARGET_NR_setuid32:
+        ret = get_errno(setuid(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_setgid32
+    case TARGET_NR_setgid32:
+        ret = get_errno(setgid(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_setfsuid32
+    case TARGET_NR_setfsuid32:
+        ret = get_errno(setfsuid(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_setfsgid32
+    case TARGET_NR_setfsgid32:
+        ret = get_errno(setfsgid(arg1));
+        break;
+#endif
+
+    case TARGET_NR_pivot_root:
+        goto unimplemented;
+#ifdef TARGET_NR_mincore
+    case TARGET_NR_mincore:
+        {
+            void *a;
+            ret = -TARGET_EFAULT;
+            if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
+                goto efault;
+            if (!(p = lock_user_string(arg3)))
+                goto mincore_fail;
+            ret = get_errno(mincore(a, arg2, p));
+            unlock_user(p, arg3, ret);
+            mincore_fail:
+            unlock_user(a, arg1, 0);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_arm_fadvise64_64
+    case TARGET_NR_arm_fadvise64_64:
+	{
+		/*
+		 * arm_fadvise64_64 looks like fadvise64_64 but
+		 * with different argument order
+		 */
+		abi_long temp;
+		temp = arg3;
+		arg3 = arg4;
+		arg4 = temp;
+	}
+#endif
+#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64) || defined(TARGET_NR_fadvise64)
+#ifdef TARGET_NR_fadvise64_64
+    case TARGET_NR_fadvise64_64:
+#endif
+#ifdef TARGET_NR_fadvise64
+    case TARGET_NR_fadvise64:
+#endif
+#ifdef TARGET_S390X
+        switch (arg4) {
+        case 4: arg4 = POSIX_FADV_NOREUSE + 1; break; /* make sure it's an invalid value */
+        case 5: arg4 = POSIX_FADV_NOREUSE + 2; break; /* ditto */
+        case 6: arg4 = POSIX_FADV_DONTNEED; break;
+        case 7: arg4 = POSIX_FADV_NOREUSE; break;
+        default: break;
+        }
+#endif
+        ret = -posix_fadvise(arg1, arg2, arg3, arg4);
+	break;
+#endif
+#ifdef TARGET_NR_madvise
+    case TARGET_NR_madvise:
+        /* A straight passthrough may not be safe because qemu sometimes
+           turns private flie-backed mappings into anonymous mappings.
+           This will break MADV_DONTNEED.
+           This is a hint, so ignoring and returning success is ok.  */
+        ret = get_errno(0);
+        break;
+#endif
+#if TARGET_ABI_BITS == 32
+    case TARGET_NR_fcntl64:
+    {
+	int cmd;
+	struct flock64 fl;
+	struct target_flock64 *target_fl;
+#ifdef TARGET_ARM
+	struct target_eabi_flock64 *target_efl;
+#endif
+
+	cmd = target_to_host_fcntl_cmd(arg2);
+	if (cmd == -TARGET_EINVAL)
+		return cmd;
+
+        switch(arg2) {
+        case TARGET_F_GETLK64:
+#ifdef TARGET_ARM
+            if (((CPUARMState *)cpu_env)->eabi) {
+                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
+                    goto efault;
+                fl.l_type = tswap16(target_efl->l_type);
+                fl.l_whence = tswap16(target_efl->l_whence);
+                fl.l_start = tswap64(target_efl->l_start);
+                fl.l_len = tswap64(target_efl->l_len);
+                fl.l_pid = tswap32(target_efl->l_pid);
+                unlock_user_struct(target_efl, arg3, 0);
+            } else
+#endif
+            {
+                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
+                    goto efault;
+                fl.l_type = tswap16(target_fl->l_type);
+                fl.l_whence = tswap16(target_fl->l_whence);
+                fl.l_start = tswap64(target_fl->l_start);
+                fl.l_len = tswap64(target_fl->l_len);
+                fl.l_pid = tswap32(target_fl->l_pid);
+                unlock_user_struct(target_fl, arg3, 0);
+            }
+            ret = get_errno(fcntl(arg1, cmd, &fl));
+	    if (ret == 0) {
+#ifdef TARGET_ARM
+                if (((CPUARMState *)cpu_env)->eabi) {
+                    if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) 
+                        goto efault;
+                    target_efl->l_type = tswap16(fl.l_type);
+                    target_efl->l_whence = tswap16(fl.l_whence);
+                    target_efl->l_start = tswap64(fl.l_start);
+                    target_efl->l_len = tswap64(fl.l_len);
+                    target_efl->l_pid = tswap32(fl.l_pid);
+                    unlock_user_struct(target_efl, arg3, 1);
+                } else
+#endif
+                {
+                    if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) 
+                        goto efault;
+                    target_fl->l_type = tswap16(fl.l_type);
+                    target_fl->l_whence = tswap16(fl.l_whence);
+                    target_fl->l_start = tswap64(fl.l_start);
+                    target_fl->l_len = tswap64(fl.l_len);
+                    target_fl->l_pid = tswap32(fl.l_pid);
+                    unlock_user_struct(target_fl, arg3, 1);
+                }
+	    }
+	    break;
+
+        case TARGET_F_SETLK64:
+        case TARGET_F_SETLKW64:
+#ifdef TARGET_ARM
+            if (((CPUARMState *)cpu_env)->eabi) {
+                if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) 
+                    goto efault;
+                fl.l_type = tswap16(target_efl->l_type);
+                fl.l_whence = tswap16(target_efl->l_whence);
+                fl.l_start = tswap64(target_efl->l_start);
+                fl.l_len = tswap64(target_efl->l_len);
+                fl.l_pid = tswap32(target_efl->l_pid);
+                unlock_user_struct(target_efl, arg3, 0);
+            } else
+#endif
+            {
+                if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) 
+                    goto efault;
+                fl.l_type = tswap16(target_fl->l_type);
+                fl.l_whence = tswap16(target_fl->l_whence);
+                fl.l_start = tswap64(target_fl->l_start);
+                fl.l_len = tswap64(target_fl->l_len);
+                fl.l_pid = tswap32(target_fl->l_pid);
+                unlock_user_struct(target_fl, arg3, 0);
+            }
+            ret = get_errno(fcntl(arg1, cmd, &fl));
+	    break;
+        default:
+            ret = do_fcntl(arg1, arg2, arg3);
+            break;
+        }
+	break;
+    }
+#endif
+#ifdef TARGET_NR_cacheflush
+    case TARGET_NR_cacheflush:
+        /* self-modifying code is handled automatically, so nothing needed */
+        ret = 0;
+        break;
+#endif
+#ifdef TARGET_NR_security
+    case TARGET_NR_security:
+        goto unimplemented;
+#endif
+#ifdef TARGET_NR_getpagesize
+    case TARGET_NR_getpagesize:
+        ret = TARGET_PAGE_SIZE;
+        break;
+#endif
+    case TARGET_NR_gettid:
+        ret = get_errno(gettid());
+        break;
+#ifdef TARGET_NR_readahead
+    case TARGET_NR_readahead:
+#if TARGET_ABI_BITS == 32
+        if (regpairs_aligned(cpu_env)) {
+            arg2 = arg3;
+            arg3 = arg4;
+            arg4 = arg5;
+        }
+        ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
+#else
+        ret = get_errno(readahead(arg1, arg2, arg3));
+#endif
+        break;
+#endif
+#ifdef TARGET_NR_setxattr
+    case TARGET_NR_setxattr:
+    case TARGET_NR_lsetxattr:
+    case TARGET_NR_fsetxattr:
+    case TARGET_NR_getxattr:
+    case TARGET_NR_lgetxattr:
+    case TARGET_NR_fgetxattr:
+    case TARGET_NR_listxattr:
+    case TARGET_NR_llistxattr:
+    case TARGET_NR_flistxattr:
+    case TARGET_NR_removexattr:
+    case TARGET_NR_lremovexattr:
+    case TARGET_NR_fremovexattr:
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+#endif
+#ifdef TARGET_NR_set_thread_area
+    case TARGET_NR_set_thread_area:
+#if defined(TARGET_MIPS)
+      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+      ret = 0;
+      break;
+#elif defined(TARGET_CRIS)
+      if (arg1 & 0xff)
+          ret = -TARGET_EINVAL;
+      else {
+          ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
+          ret = 0;
+      }
+      break;
+#elif defined(TARGET_I386) && defined(TARGET_ABI32)
+      ret = do_set_thread_area(cpu_env, arg1);
+      break;
+#else
+      goto unimplemented_nowarn;
+#endif
+#endif
+#ifdef TARGET_NR_get_thread_area
+    case TARGET_NR_get_thread_area:
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+        ret = do_get_thread_area(cpu_env, arg1);
+#else
+        goto unimplemented_nowarn;
+#endif
+#endif
+#ifdef TARGET_NR_getdomainname
+    case TARGET_NR_getdomainname:
+        goto unimplemented_nowarn;
+#endif
+
+#ifdef TARGET_NR_clock_gettime
+    case TARGET_NR_clock_gettime:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_gettime(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+#ifdef TARGET_NR_clock_getres
+    case TARGET_NR_clock_getres:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_getres(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+#ifdef TARGET_NR_clock_nanosleep
+    case TARGET_NR_clock_nanosleep:
+    {
+        struct timespec ts;
+        target_to_host_timespec(&ts, arg3);
+        ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
+        if (arg4)
+            host_to_target_timespec(arg4, &ts);
+        break;
+    }
+#endif
+
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+    case TARGET_NR_set_tid_address:
+        ret = get_errno(set_tid_address((int *)g2h(arg1)));
+        break;
+#endif
+
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+    case TARGET_NR_tkill:
+        ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
+        break;
+#endif
+
+#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
+    case TARGET_NR_tgkill:
+	ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
+                        target_to_host_signal(arg3)));
+	break;
+#endif
+
+#ifdef TARGET_NR_set_robust_list
+    case TARGET_NR_set_robust_list:
+	goto unimplemented_nowarn;
+#endif
+
+#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
+    case TARGET_NR_utimensat:
+        {
+            struct timespec *tsp, ts[2];
+            if (!arg3) {
+                tsp = NULL;
+            } else {
+                target_to_host_timespec(ts, arg3);
+                target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+                tsp = ts;
+            }
+            if (!arg2)
+                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
+            else {
+                if (!(p = lock_user_string(arg2))) {
+                    ret = -TARGET_EFAULT;
+                    goto fail;
+                }
+                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
+                unlock_user(p, arg2, 0);
+            }
+        }
+	break;
+#endif
+#if defined(CONFIG_USE_NPTL)
+    case TARGET_NR_futex:
+        ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+#endif
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
+    case TARGET_NR_inotify_init:
+        ret = get_errno(sys_inotify_init());
+        break;
+#endif
+#ifdef CONFIG_INOTIFY1
+#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
+    case TARGET_NR_inotify_init1:
+        ret = get_errno(sys_inotify_init1(arg1));
+        break;
+#endif
+#endif
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
+    case TARGET_NR_inotify_add_watch:
+        p = lock_user_string(arg2);
+        ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
+        unlock_user(p, arg2, 0);
+        break;
+#endif
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
+    case TARGET_NR_inotify_rm_watch:
+        ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
+        break;
+#endif
+
+#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
+    case TARGET_NR_mq_open:
+        {
+            struct mq_attr posix_mq_attr;
+
+            p = lock_user_string(arg1 - 1);
+            if (arg4 != 0)
+                copy_from_user_mq_attr (&posix_mq_attr, arg4);
+            ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
+            unlock_user (p, arg1, 0);
+        }
+        break;
+
+    case TARGET_NR_mq_unlink:
+        p = lock_user_string(arg1 - 1);
+        ret = get_errno(mq_unlink(p));
+        unlock_user (p, arg1, 0);
+        break;
+
+    case TARGET_NR_mq_timedsend:
+        {
+            struct timespec ts;
+
+            p = lock_user (VERIFY_READ, arg2, arg3, 1);
+            if (arg5 != 0) {
+                target_to_host_timespec(&ts, arg5);
+                ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
+                host_to_target_timespec(arg5, &ts);
+            }
+            else
+                ret = get_errno(mq_send(arg1, p, arg3, arg4));
+            unlock_user (p, arg2, arg3);
+        }
+        break;
+
+    case TARGET_NR_mq_timedreceive:
+        {
+            struct timespec ts;
+            unsigned int prio;
+
+            p = lock_user (VERIFY_READ, arg2, arg3, 1);
+            if (arg5 != 0) {
+                target_to_host_timespec(&ts, arg5);
+                ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
+                host_to_target_timespec(arg5, &ts);
+            }
+            else
+                ret = get_errno(mq_receive(arg1, p, arg3, &prio));
+            unlock_user (p, arg2, arg3);
+            if (arg4 != 0)
+                put_user_u32(prio, arg4);
+        }
+        break;
+
+    /* Not implemented for now... */
+/*     case TARGET_NR_mq_notify: */
+/*         break; */
+
+    case TARGET_NR_mq_getsetattr:
+        {
+            struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
+            ret = 0;
+            if (arg3 != 0) {
+                ret = mq_getattr(arg1, &posix_mq_attr_out);
+                copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
+            }
+            if (arg2 != 0) {
+                copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
+                ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
+            }
+
+        }
+        break;
+#endif
+
+#ifdef CONFIG_SPLICE
+#ifdef TARGET_NR_tee
+    case TARGET_NR_tee:
+        {
+            ret = get_errno(tee(arg1,arg2,arg3,arg4));
+        }
+        break;
+#endif
+#ifdef TARGET_NR_splice
+    case TARGET_NR_splice:
+        {
+            loff_t loff_in, loff_out;
+            loff_t *ploff_in = NULL, *ploff_out = NULL;
+            if(arg2) {
+                get_user_u64(loff_in, arg2);
+                ploff_in = &loff_in;
+            }
+            if(arg4) {
+                get_user_u64(loff_out, arg2);
+                ploff_out = &loff_out;
+            }
+            ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
+        }
+        break;
+#endif
+#ifdef TARGET_NR_vmsplice
+	case TARGET_NR_vmsplice:
+        {
+            int count = arg3;
+            struct iovec *vec;
+
+            vec = alloca(count * sizeof(struct iovec));
+            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+                goto efault;
+            ret = get_errno(vmsplice(arg1, vec, count, arg4));
+            unlock_iovec(vec, arg2, count, 0);
+        }
+        break;
+#endif
+#endif /* CONFIG_SPLICE */
+#ifdef CONFIG_EVENTFD
+#if defined(TARGET_NR_eventfd)
+    case TARGET_NR_eventfd:
+        ret = get_errno(eventfd(arg1, 0));
+        break;
+#endif
+#if defined(TARGET_NR_eventfd2)
+    case TARGET_NR_eventfd2:
+        ret = get_errno(eventfd(arg1, arg2));
+        break;
+#endif
+#endif /* CONFIG_EVENTFD  */
+#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
+    case TARGET_NR_fallocate:
+        ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
+        break;
+#endif
+#if defined(CONFIG_SYNC_FILE_RANGE)
+#if defined(TARGET_NR_sync_file_range)
+    case TARGET_NR_sync_file_range:
+#if TARGET_ABI_BITS == 32
+#if defined(TARGET_MIPS)
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
+                                        target_offset64(arg5, arg6), arg7));
+#else
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
+                                        target_offset64(arg4, arg5), arg6));
+#endif /* !TARGET_MIPS */
+#else
+        ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
+#endif
+        break;
+#endif
+#if defined(TARGET_NR_sync_file_range2)
+    case TARGET_NR_sync_file_range2:
+        /* This is like sync_file_range but the arguments are reordered */
+#if TARGET_ABI_BITS == 32
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
+                                        target_offset64(arg5, arg6), arg2));
+#else
+        ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
+#endif
+        break;
+#endif
+#endif
+#if defined(CONFIG_EPOLL)
+#if defined(TARGET_NR_epoll_create)
+    case TARGET_NR_epoll_create:
+        ret = get_errno(epoll_create(arg1));
+        break;
+#endif
+#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
+    case TARGET_NR_epoll_create1:
+        ret = get_errno(epoll_create1(arg1));
+        break;
+#endif
+#if defined(TARGET_NR_epoll_ctl)
+    case TARGET_NR_epoll_ctl:
+    {
+        struct epoll_event ep;
+        struct epoll_event *epp = 0;
+        if (arg4) {
+            struct target_epoll_event *target_ep;
+            if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
+                goto efault;
+            }
+            ep.events = tswap32(target_ep->events);
+            /* The epoll_data_t union is just opaque data to the kernel,
+             * so we transfer all 64 bits across and need not worry what
+             * actual data type it is.
+             */
+            ep.data.u64 = tswap64(target_ep->data.u64);
+            unlock_user_struct(target_ep, arg4, 0);
+            epp = &ep;
+        }
+        ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
+        break;
+    }
+#endif
+
+#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
+#define IMPLEMENT_EPOLL_PWAIT
+#endif
+#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
+#if defined(TARGET_NR_epoll_wait)
+    case TARGET_NR_epoll_wait:
+#endif
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+    case TARGET_NR_epoll_pwait:
+#endif
+    {
+        struct target_epoll_event *target_ep;
+        struct epoll_event *ep;
+        int epfd = arg1;
+        int maxevents = arg3;
+        int timeout = arg4;
+
+        target_ep = lock_user(VERIFY_WRITE, arg2,
+                              maxevents * sizeof(struct target_epoll_event), 1);
+        if (!target_ep) {
+            goto efault;
+        }
+
+        ep = alloca(maxevents * sizeof(struct epoll_event));
+
+        switch (num) {
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+        case TARGET_NR_epoll_pwait:
+        {
+            target_sigset_t *target_set;
+            sigset_t _set, *set = &_set;
+
+            if (arg5) {
+                target_set = lock_user(VERIFY_READ, arg5,
+                                       sizeof(target_sigset_t), 1);
+                if (!target_set) {
+                    unlock_user(target_ep, arg2, 0);
+                    goto efault;
+                }
+                target_to_host_sigset(set, target_set);
+                unlock_user(target_set, arg5, 0);
+            } else {
+                set = NULL;
+            }
+
+            ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
+            break;
+        }
+#endif
+#if defined(TARGET_NR_epoll_wait)
+        case TARGET_NR_epoll_wait:
+            ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
+            break;
+#endif
+        default:
+            ret = -TARGET_ENOSYS;
+        }
+        if (!is_error(ret)) {
+            int i;
+            for (i = 0; i < ret; i++) {
+                target_ep[i].events = tswap32(ep[i].events);
+                target_ep[i].data.u64 = tswap64(ep[i].data.u64);
+            }
+        }
+        unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
+        break;
+    }
+#endif
+#endif
+#ifdef TARGET_NR_prlimit64
+    case TARGET_NR_prlimit64:
+    {
+        /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */
+        struct target_rlimit64 *target_rnew, *target_rold;
+        struct host_rlimit64 rnew, rold, *rnewp = 0;
+        if (arg3) {
+            if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
+                goto efault;
+            }
+            rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
+            rnew.rlim_max = tswap64(target_rnew->rlim_max);
+            unlock_user_struct(target_rnew, arg3, 0);
+            rnewp = &rnew;
+        }
+
+        ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0));
+        if (!is_error(ret) && arg4) {
+            if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
+                goto efault;
+            }
+            target_rold->rlim_cur = tswap64(rold.rlim_cur);
+            target_rold->rlim_max = tswap64(rold.rlim_max);
+            unlock_user_struct(target_rold, arg4, 1);
+        }
+        break;
+    }
+#endif
+    default:
+    unimplemented:
+        gemu_log("qemu: Unsupported syscall: %d\n", num);
+#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
+    unimplemented_nowarn:
+#endif
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+fail:
+#ifdef DEBUG
+    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
+#endif
+    if(do_strace)
+        print_syscall_ret(num, ret);
+    return ret;
+efault:
+    ret = -TARGET_EFAULT;
+    goto fail;
+}
diff --git a/qemu-0.15.x/linux-user/syscall_defs.h b/qemu-0.15.x/linux-user/syscall_defs.h
new file mode 100644
index 0000000..a117407
--- /dev/null
+++ b/qemu-0.15.x/linux-user/syscall_defs.h
@@ -0,0 +1,2333 @@
+/* common syscall defines for all architectures */
+
+/* Note: although the syscall numbers change between architectures,
+   most of them stay the same, so we handle it by puting ifdefs if
+   necessary */
+
+#include "syscall_nr.h"
+
+#define SOCKOP_socket           1
+#define SOCKOP_bind             2
+#define SOCKOP_connect          3
+#define SOCKOP_listen           4
+#define SOCKOP_accept           5
+#define SOCKOP_getsockname      6
+#define SOCKOP_getpeername      7
+#define SOCKOP_socketpair       8
+#define SOCKOP_send             9
+#define SOCKOP_recv             10
+#define SOCKOP_sendto           11
+#define SOCKOP_recvfrom         12
+#define SOCKOP_shutdown         13
+#define SOCKOP_setsockopt       14
+#define SOCKOP_getsockopt       15
+#define SOCKOP_sendmsg          16
+#define SOCKOP_recvmsg          17
+
+#define IPCOP_semop		1
+#define IPCOP_semget		2
+#define IPCOP_semctl		3
+#define IPCOP_semtimedop	4
+#define IPCOP_msgsnd		11
+#define IPCOP_msgrcv		12
+#define IPCOP_msgget		13
+#define IPCOP_msgctl		14
+#define IPCOP_shmat		21
+#define IPCOP_shmdt		22
+#define IPCOP_shmget		23
+#define IPCOP_shmctl		24
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The i386 ioctl numbering scheme doesn't really enforce
+ * a type field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define TARGET_IOC_NRBITS	8
+#define TARGET_IOC_TYPEBITS	8
+
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
+    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
+    /* 16 bit uid wrappers emulation */
+#define USE_UID16
+#define target_id uint16_t
+#else
+#define target_id uint32_t
+#endif
+
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
+    || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \
+    || defined(TARGET_S390X)
+
+#define TARGET_IOC_SIZEBITS	14
+#define TARGET_IOC_DIRBITS	2
+
+#define TARGET_IOC_NONE	  0U
+#define TARGET_IOC_WRITE  1U
+#define TARGET_IOC_READ	  2U
+
+#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
+      defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \
+      defined(TARGET_MIPS)
+
+#define TARGET_IOC_SIZEBITS	13
+#define TARGET_IOC_DIRBITS	3
+
+#define TARGET_IOC_NONE	  1U
+#define TARGET_IOC_READ	  2U
+#define TARGET_IOC_WRITE  4U
+
+#else
+#error unsupported CPU
+#endif
+
+#define TARGET_IOC_NRMASK	((1 << TARGET_IOC_NRBITS)-1)
+#define TARGET_IOC_TYPEMASK	((1 << TARGET_IOC_TYPEBITS)-1)
+#define TARGET_IOC_SIZEMASK	((1 << TARGET_IOC_SIZEBITS)-1)
+#define TARGET_IOC_DIRMASK	((1 << TARGET_IOC_DIRBITS)-1)
+
+#define TARGET_IOC_NRSHIFT	0
+#define TARGET_IOC_TYPESHIFT	(TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
+#define TARGET_IOC_SIZESHIFT	(TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
+#define TARGET_IOC_DIRSHIFT	(TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
+
+#define TARGET_IOC(dir,type,nr,size) \
+	(((dir)  << TARGET_IOC_DIRSHIFT) | \
+	 ((type) << TARGET_IOC_TYPESHIFT) | \
+	 ((nr)   << TARGET_IOC_NRSHIFT) | \
+	 ((size) << TARGET_IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define TARGET_IO(type,nr)		TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
+#define TARGET_IOR(type,nr,size)	TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
+#define TARGET_IOW(type,nr,size)	TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
+#define TARGET_IOWR(type,nr,size)	TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* the size is automatically computed for these defines */
+#define TARGET_IORU(type,nr)	TARGET_IOC(TARGET_IOC_READ,(type),(nr),TARGET_IOC_SIZEMASK)
+#define TARGET_IOWU(type,nr)	TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
+#define TARGET_IOWRU(type,nr)	TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
+
+struct target_sockaddr {
+    uint16_t sa_family;
+    uint8_t sa_data[14];
+};
+
+struct target_in_addr {
+    uint32_t s_addr; /* big endian */
+};
+
+struct target_ip_mreq {
+    struct target_in_addr imr_multiaddr;
+    struct target_in_addr imr_address;
+};
+
+struct target_ip_mreqn {
+    struct target_in_addr imr_multiaddr;
+    struct target_in_addr imr_address;
+    abi_long imr_ifindex;
+};
+
+struct target_ip_mreq_source {
+    /* big endian */
+    uint32_t imr_multiaddr;
+    uint32_t imr_interface;
+    uint32_t imr_sourceaddr;
+};
+
+struct target_timeval {
+    abi_long tv_sec;
+    abi_long tv_usec;
+};
+
+struct target_timespec {
+    abi_long tv_sec;
+    abi_long tv_nsec;
+};
+
+struct target_itimerval {
+    struct target_timeval it_interval;
+    struct target_timeval it_value;
+};
+
+typedef abi_long target_clock_t;
+
+#define TARGET_HZ 100
+
+struct target_tms {
+    target_clock_t tms_utime;
+    target_clock_t tms_stime;
+    target_clock_t tms_cutime;
+    target_clock_t tms_cstime;
+};
+
+struct target_utimbuf {
+    abi_long actime;
+    abi_long modtime;
+};
+
+struct target_sel_arg_struct {
+    abi_long n;
+    abi_long inp, outp, exp;
+    abi_long tvp;
+};
+
+struct target_iovec {
+    abi_long iov_base;   /* Starting address */
+    abi_long iov_len;   /* Number of bytes */
+};
+
+struct target_msghdr {
+    abi_long	 msg_name;	 /* Socket name			*/
+    int		 msg_namelen;	 /* Length of name		*/
+    abi_long	 msg_iov;	 /* Data blocks			*/
+    abi_long	 msg_iovlen;	 /* Number of blocks		*/
+    abi_long     msg_control;	 /* Per protocol magic (eg BSD file descriptor passing) */
+    abi_long	 msg_controllen; /* Length of cmsg list */
+    unsigned int msg_flags;
+};
+
+struct target_cmsghdr {
+    abi_long     cmsg_len;
+    int          cmsg_level;
+    int          cmsg_type;
+};
+
+#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
+#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \
+                               & (size_t) ~(sizeof (abi_long) - 1))
+#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
+                               + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
+#define TARGET_CMSG_LEN(len)   (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
+
+static __inline__ struct target_cmsghdr *
+__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
+{
+  struct target_cmsghdr *__ptr;
+
+  __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg
+                                    + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
+  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapl(__mhdr->msg_control))
+      > tswapl(__mhdr->msg_controllen))
+    /* No more entries.  */
+    return (struct target_cmsghdr *)0;
+  return __cmsg;
+}
+
+
+struct  target_rusage {
+        struct target_timeval ru_utime;        /* user time used */
+        struct target_timeval ru_stime;        /* system time used */
+        abi_long    ru_maxrss;                 /* maximum resident set size */
+        abi_long    ru_ixrss;                  /* integral shared memory size */
+        abi_long    ru_idrss;                  /* integral unshared data size */
+        abi_long    ru_isrss;                  /* integral unshared stack size */
+        abi_long    ru_minflt;                 /* page reclaims */
+        abi_long    ru_majflt;                 /* page faults */
+        abi_long    ru_nswap;                  /* swaps */
+        abi_long    ru_inblock;                /* block input operations */
+        abi_long    ru_oublock;                /* block output operations */
+        abi_long    ru_msgsnd;                 /* messages sent */
+        abi_long    ru_msgrcv;                 /* messages received */
+        abi_long    ru_nsignals;               /* signals received */
+        abi_long    ru_nvcsw;                  /* voluntary context switches */
+        abi_long    ru_nivcsw;                 /* involuntary " */
+};
+
+typedef struct {
+        int     val[2];
+} kernel_fsid_t;
+
+struct kernel_statfs {
+	int f_type;
+	int f_bsize;
+	int f_blocks;
+	int f_bfree;
+	int f_bavail;
+	int f_files;
+	int f_ffree;
+        kernel_fsid_t f_fsid;
+	int f_namelen;
+	int f_spare[6];
+};
+
+struct target_dirent {
+	abi_long	d_ino;
+	abi_long	d_off;
+	unsigned short	d_reclen;
+	char		d_name[256]; /* We must not include limits.h! */
+};
+
+struct target_dirent64 {
+	uint64_t	d_ino;
+	int64_t		d_off;
+	unsigned short	d_reclen;
+	unsigned char	d_type;
+	char		d_name[256];
+};
+
+
+/* mostly generic signal stuff */
+#define TARGET_SIG_DFL	((abi_long)0)	/* default signal handling */
+#define TARGET_SIG_IGN	((abi_long)1)	/* ignore signal */
+#define TARGET_SIG_ERR	((abi_long)-1)	/* error return from signal */
+
+#ifdef TARGET_MIPS
+#define TARGET_NSIG	   128
+#else
+#define TARGET_NSIG	   64
+#endif
+#define TARGET_NSIG_BPW	   TARGET_ABI_BITS
+#define TARGET_NSIG_WORDS  (TARGET_NSIG / TARGET_NSIG_BPW)
+
+typedef struct {
+    abi_ulong sig[TARGET_NSIG_WORDS];
+} target_sigset_t;
+
+#ifdef BSWAP_NEEDED
+static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
+{
+    int i;
+    for(i = 0;i < TARGET_NSIG_WORDS; i++)
+        d->sig[i] = tswapl(s->sig[i]);
+}
+#else
+static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
+{
+    *d = *s;
+}
+#endif
+
+static inline void target_siginitset(target_sigset_t *d, abi_ulong set)
+{
+    int i;
+    d->sig[0] = set;
+    for(i = 1;i < TARGET_NSIG_WORDS; i++)
+        d->sig[i] = 0;
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+void host_to_target_old_sigset(abi_ulong *old_sigset,
+                               const sigset_t *sigset);
+void target_to_host_old_sigset(sigset_t *sigset,
+                               const abi_ulong *old_sigset);
+struct target_sigaction;
+int do_sigaction(int sig, const struct target_sigaction *act,
+                 struct target_sigaction *oact);
+
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
+    || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \
+    || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \
+    || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) \
+    || defined(TARGET_S390X)
+
+#if defined(TARGET_SPARC)
+#define TARGET_SA_NOCLDSTOP    8u
+#define TARGET_SA_NOCLDWAIT    0x100u
+#define TARGET_SA_SIGINFO      0x200u
+#define TARGET_SA_ONSTACK      1u
+#define TARGET_SA_RESTART      2u
+#define TARGET_SA_NODEFER      0x20u
+#define TARGET_SA_RESETHAND    4u
+#elif defined(TARGET_MIPS)
+#define TARGET_SA_NOCLDSTOP	0x00000001
+#define TARGET_SA_NOCLDWAIT	0x00010000
+#define TARGET_SA_SIGINFO	0x00000008
+#define TARGET_SA_ONSTACK	0x08000000
+#define TARGET_SA_NODEFER	0x40000000
+#define TARGET_SA_RESTART	0x10000000
+#define TARGET_SA_RESETHAND	0x80000000
+#if !defined(TARGET_ABI_MIPSN32) && !defined(TARGET_ABI_MIPSN64)
+#define TARGET_SA_RESTORER	0x04000000	/* Only for O32 */
+#endif
+#elif defined(TARGET_ALPHA)
+#define TARGET_SA_ONSTACK	0x00000001
+#define TARGET_SA_RESTART	0x00000002
+#define TARGET_SA_NOCLDSTOP	0x00000004
+#define TARGET_SA_NODEFER	0x00000008
+#define TARGET_SA_RESETHAND	0x00000010
+#define TARGET_SA_NOCLDWAIT	0x00000020 /* not supported yet */
+#define TARGET_SA_SIGINFO	0x00000040
+#else
+#define TARGET_SA_NOCLDSTOP	0x00000001
+#define TARGET_SA_NOCLDWAIT	0x00000002 /* not supported yet */
+#define TARGET_SA_SIGINFO	0x00000004
+#define TARGET_SA_ONSTACK	0x08000000
+#define TARGET_SA_RESTART	0x10000000
+#define TARGET_SA_NODEFER	0x40000000
+#define TARGET_SA_RESETHAND	0x80000000
+#define TARGET_SA_RESTORER	0x04000000
+#endif
+
+#if defined(TARGET_SPARC)
+
+#define TARGET_SIGHUP		 1
+#define TARGET_SIGINT		 2
+#define TARGET_SIGQUIT		 3
+#define TARGET_SIGILL		 4
+#define TARGET_SIGTRAP		 5
+#define TARGET_SIGABRT		 6
+#define TARGET_SIGIOT		 6
+#define TARGET_SIGSTKFLT	 7 /* actually EMT */
+#define TARGET_SIGFPE		 8
+#define TARGET_SIGKILL		 9
+#define TARGET_SIGBUS		10
+#define TARGET_SIGSEGV		11
+#define TARGET_SIGSYS		12
+#define TARGET_SIGPIPE		13
+#define TARGET_SIGALRM		14
+#define TARGET_SIGTERM		15
+#define TARGET_SIGURG		16
+#define TARGET_SIGSTOP		17
+#define TARGET_SIGTSTP		18
+#define TARGET_SIGCONT		19
+#define TARGET_SIGCHLD		20
+#define TARGET_SIGTTIN		21
+#define TARGET_SIGTTOU		22
+#define TARGET_SIGIO		23
+#define TARGET_SIGXCPU		24
+#define TARGET_SIGXFSZ		25
+#define TARGET_SIGVTALRM	26
+#define TARGET_SIGPROF		27
+#define TARGET_SIGWINCH	        28
+#define TARGET_SIGPWR		29
+#define TARGET_SIGUSR1		30
+#define TARGET_SIGUSR2		31
+#define TARGET_SIGRTMIN         32
+
+#define TARGET_SIG_BLOCK          0x01 /* for blocking signals */
+#define TARGET_SIG_UNBLOCK        0x02 /* for unblocking signals */
+#define TARGET_SIG_SETMASK        0x04 /* for setting the signal mask */
+
+#elif defined(TARGET_MIPS)
+
+#define TARGET_SIGHUP		 1	/* Hangup (POSIX).  */
+#define TARGET_SIGINT		 2	/* Interrupt (ANSI).  */
+#define TARGET_SIGQUIT		 3	/* Quit (POSIX).  */
+#define TARGET_SIGILL		 4	/* Illegal instruction (ANSI).  */
+#define TARGET_SIGTRAP		 5	/* Trace trap (POSIX).  */
+#define TARGET_SIGIOT		 6	/* IOT trap (4.2 BSD).  */
+#define TARGET_SIGABRT		 TARGET_SIGIOT	/* Abort (ANSI).  */
+#define TARGET_SIGEMT		 7
+#define TARGET_SIGSTKFLT	 7 /* XXX: incorrect */
+#define TARGET_SIGFPE		 8	/* Floating-point exception (ANSI).  */
+#define TARGET_SIGKILL		 9	/* Kill, unblockable (POSIX).  */
+#define TARGET_SIGBUS		10	/* BUS error (4.2 BSD).  */
+#define TARGET_SIGSEGV		11	/* Segmentation violation (ANSI).  */
+#define TARGET_SIGSYS		12
+#define TARGET_SIGPIPE		13	/* Broken pipe (POSIX).  */
+#define TARGET_SIGALRM		14	/* Alarm clock (POSIX).  */
+#define TARGET_SIGTERM		15	/* Termination (ANSI).  */
+#define TARGET_SIGUSR1		16	/* User-defined signal 1 (POSIX).  */
+#define TARGET_SIGUSR2		17	/* User-defined signal 2 (POSIX).  */
+#define TARGET_SIGCHLD		18	/* Child status has changed (POSIX).  */
+#define TARGET_SIGCLD		TARGET_SIGCHLD	/* Same as TARGET_SIGCHLD (System V).  */
+#define TARGET_SIGPWR		19	/* Power failure restart (System V).  */
+#define TARGET_SIGWINCH	20	/* Window size change (4.3 BSD, Sun).  */
+#define TARGET_SIGURG		21	/* Urgent condition on socket (4.2 BSD).  */
+#define TARGET_SIGIO		22	/* I/O now possible (4.2 BSD).  */
+#define TARGET_SIGPOLL		TARGET_SIGIO	/* Pollable event occurred (System V).  */
+#define TARGET_SIGSTOP		23	/* Stop, unblockable (POSIX).  */
+#define TARGET_SIGTSTP		24	/* Keyboard stop (POSIX).  */
+#define TARGET_SIGCONT		25	/* Continue (POSIX).  */
+#define TARGET_SIGTTIN		26	/* Background read from tty (POSIX).  */
+#define TARGET_SIGTTOU		27	/* Background write to tty (POSIX).  */
+#define TARGET_SIGVTALRM	28	/* Virtual alarm clock (4.2 BSD).  */
+#define TARGET_SIGPROF		29	/* Profiling alarm clock (4.2 BSD).  */
+#define TARGET_SIGXCPU		30	/* CPU limit exceeded (4.2 BSD).  */
+#define TARGET_SIGXFSZ		31	/* File size limit exceeded (4.2 BSD).  */
+#define TARGET_SIGRTMIN         32
+
+#define TARGET_SIG_BLOCK	1	/* for blocking signals */
+#define TARGET_SIG_UNBLOCK	2	/* for unblocking signals */
+#define TARGET_SIG_SETMASK	3	/* for setting the signal mask */
+
+#else
+
+#define TARGET_SIGHUP		 1
+#define TARGET_SIGINT		 2
+#define TARGET_SIGQUIT		 3
+#define TARGET_SIGILL		 4
+#define TARGET_SIGTRAP		 5
+#define TARGET_SIGABRT		 6
+#define TARGET_SIGIOT		 6
+#define TARGET_SIGBUS		 7
+#define TARGET_SIGFPE		 8
+#define TARGET_SIGKILL		 9
+#define TARGET_SIGUSR1		10
+#define TARGET_SIGSEGV		11
+#define TARGET_SIGUSR2		12
+#define TARGET_SIGPIPE		13
+#define TARGET_SIGALRM		14
+#define TARGET_SIGTERM		15
+#define TARGET_SIGSTKFLT	16
+#define TARGET_SIGCHLD		17
+#define TARGET_SIGCONT		18
+#define TARGET_SIGSTOP		19
+#define TARGET_SIGTSTP		20
+#define TARGET_SIGTTIN		21
+#define TARGET_SIGTTOU		22
+#define TARGET_SIGURG		23
+#define TARGET_SIGXCPU		24
+#define TARGET_SIGXFSZ		25
+#define TARGET_SIGVTALRM	26
+#define TARGET_SIGPROF		27
+#define TARGET_SIGWINCH	        28
+#define TARGET_SIGIO		29
+#define TARGET_SIGPWR		30
+#define TARGET_SIGSYS		31
+#define TARGET_SIGRTMIN         32
+
+#define TARGET_SIG_BLOCK          0    /* for blocking signals */
+#define TARGET_SIG_UNBLOCK        1    /* for unblocking signals */
+#define TARGET_SIG_SETMASK        2    /* for setting the signal mask */
+
+#endif
+
+#if defined(TARGET_ALPHA)
+struct target_old_sigaction {
+    abi_ulong _sa_handler;
+    abi_ulong sa_mask;
+    abi_ulong sa_flags;
+};
+
+struct target_rt_sigaction {
+    abi_ulong _sa_handler;
+    abi_ulong sa_flags;
+    target_sigset_t sa_mask;
+};
+
+/* This is the struct used inside the kernel.  The ka_restorer
+   field comes from the 5th argument to sys_rt_sigaction.  */
+struct target_sigaction {
+    abi_ulong _sa_handler;
+    abi_ulong sa_flags;
+    target_sigset_t sa_mask;
+    abi_ulong sa_restorer;
+};
+#elif defined(TARGET_MIPS)
+struct target_sigaction {
+	uint32_t	sa_flags;
+#if defined(TARGET_ABI_MIPSN32)
+	uint32_t	_sa_handler;
+#else
+	abi_ulong	_sa_handler;
+#endif
+	target_sigset_t	sa_mask;
+};
+#else
+struct target_old_sigaction {
+        abi_ulong _sa_handler;
+        abi_ulong sa_mask;
+        abi_ulong sa_flags;
+        abi_ulong sa_restorer;
+};
+
+struct target_sigaction {
+        abi_ulong _sa_handler;
+        abi_ulong sa_flags;
+        abi_ulong sa_restorer;
+        target_sigset_t sa_mask;
+};
+#endif
+
+typedef union target_sigval {
+	int sival_int;
+        abi_ulong sival_ptr;
+} target_sigval_t;
+#if 0
+#if defined (TARGET_SPARC)
+typedef struct {
+	struct {
+		abi_ulong psr;
+		abi_ulong pc;
+		abi_ulong npc;
+		abi_ulong y;
+		abi_ulong u_regs[16]; /* globals and ins */
+	}		si_regs;
+	int		si_mask;
+} __siginfo_t;
+
+typedef struct {
+	unsigned   long si_float_regs [32];
+	unsigned   long si_fsr;
+	unsigned   long si_fpqdepth;
+	struct {
+		unsigned long *insn_addr;
+		unsigned long insn;
+	} si_fpqueue [16];
+} __siginfo_fpu_t;
+#endif
+#endif
+
+#define TARGET_SI_MAX_SIZE	128
+#define TARGET_SI_PAD_SIZE	((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct target_siginfo {
+#ifdef TARGET_MIPS
+	int si_signo;
+	int si_code;
+	int si_errno;
+#else
+	int si_signo;
+	int si_errno;
+	int si_code;
+#endif
+
+	union {
+		int _pad[TARGET_SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			target_sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			int _status;		/* exit code */
+			target_clock_t _utime;
+                        target_clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			abi_ulong _addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} target_siginfo_t;
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define TARGET_SI_USER		0	/* sent by kill, sigsend, raise */
+#define TARGET_SI_KERNEL	0x80	/* sent by the kernel from somewhere */
+#define TARGET_SI_QUEUE	-1		/* sent by sigqueue */
+#define TARGET_SI_TIMER -2              /* sent by timer expiration */
+#define TARGET_SI_MESGQ	-3		/* sent by real time mesq state change */
+#define TARGET_SI_ASYNCIO	-4	/* sent by AIO completion */
+#define TARGET_SI_SIGIO	-5		/* sent by queued SIGIO */
+
+/*
+ * SIGILL si_codes
+ */
+#define TARGET_ILL_ILLOPC	(1)	/* illegal opcode */
+#define TARGET_ILL_ILLOPN	(2)	/* illegal operand */
+#define TARGET_ILL_ILLADR	(3)	/* illegal addressing mode */
+#define TARGET_ILL_ILLTRP	(4)	/* illegal trap */
+#define TARGET_ILL_PRVOPC	(5)	/* privileged opcode */
+#define TARGET_ILL_PRVREG	(6)	/* privileged register */
+#define TARGET_ILL_COPROC	(7)	/* coprocessor error */
+#define TARGET_ILL_BADSTK	(8)	/* internal stack error */
+
+/*
+ * SIGFPE si_codes
+ */
+#define TARGET_FPE_INTDIV      (1)  /* integer divide by zero */
+#define TARGET_FPE_INTOVF      (2)  /* integer overflow */
+#define TARGET_FPE_FLTDIV      (3)  /* floating point divide by zero */
+#define TARGET_FPE_FLTOVF      (4)  /* floating point overflow */
+#define TARGET_FPE_FLTUND      (5)  /* floating point underflow */
+#define TARGET_FPE_FLTRES      (6)  /* floating point inexact result */
+#define TARGET_FPE_FLTINV      (7)  /* floating point invalid operation */
+#define TARGET_FPE_FLTSUB      (8)  /* subscript out of range */
+#define TARGET_NSIGFPE         8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define TARGET_SEGV_MAPERR     (1)  /* address not mapped to object */
+#define TARGET_SEGV_ACCERR     (2)  /* invalid permissions for mapped object */
+
+/*
+ * SIGBUS si_codes
+ */
+#define TARGET_BUS_ADRALN       (1)	/* invalid address alignment */
+#define TARGET_BUS_ADRERR       (2)	/* non-existant physical address */
+#define TARGET_BUS_OBJERR       (3)	/* object specific hardware error */
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TARGET_TRAP_BRKPT	(1)	/* process breakpoint */
+#define TARGET_TRAP_TRACE	(2)	/* process trace trap */
+
+#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
+
+struct target_rlimit {
+        abi_ulong   rlim_cur;
+        abi_ulong   rlim_max;
+};
+
+#if defined(TARGET_ALPHA)
+#define TARGET_RLIM_INFINITY	0x7fffffffffffffffull
+#elif defined(TARGET_MIPS) || defined(TARGET_SPARC)
+#define TARGET_RLIM_INFINITY	0x7fffffffUL
+#else
+#define TARGET_RLIM_INFINITY	((target_ulong)~0UL)
+#endif
+
+#if defined(TARGET_MIPS)
+#define TARGET_RLIMIT_CPU		0
+#define TARGET_RLIMIT_FSIZE		1
+#define TARGET_RLIMIT_DATA		2
+#define TARGET_RLIMIT_STACK		3
+#define TARGET_RLIMIT_CORE		4
+#define TARGET_RLIMIT_RSS		7
+#define TARGET_RLIMIT_NPROC		8
+#define TARGET_RLIMIT_NOFILE		5
+#define TARGET_RLIMIT_MEMLOCK		9
+#define TARGET_RLIMIT_AS		6
+#define TARGET_RLIMIT_LOCKS		10
+#define TARGET_RLIMIT_SIGPENDING	11
+#define TARGET_RLIMIT_MSGQUEUE		12
+#define TARGET_RLIMIT_NICE		13
+#define TARGET_RLIMIT_RTPRIO		14
+#else
+#define TARGET_RLIMIT_CPU		0
+#define TARGET_RLIMIT_FSIZE		1
+#define TARGET_RLIMIT_DATA		2
+#define TARGET_RLIMIT_STACK		3
+#define TARGET_RLIMIT_CORE		4
+#define TARGET_RLIMIT_RSS		5
+#define TARGET_RLIMIT_NPROC		6
+#define TARGET_RLIMIT_NOFILE		7
+#define TARGET_RLIMIT_MEMLOCK		8
+#define TARGET_RLIMIT_AS		9
+#define TARGET_RLIMIT_LOCKS		10
+#define TARGET_RLIMIT_SIGPENDING	11
+#define TARGET_RLIMIT_MSGQUEUE		12
+#define TARGET_RLIMIT_NICE		13
+#define TARGET_RLIMIT_RTPRIO		14
+#endif
+
+struct target_pollfd {
+    int fd;           /* file descriptor */
+    short events;     /* requested events */
+    short revents;    /* returned events */
+};
+
+/* virtual terminal ioctls */
+#define TARGET_KIOCSOUND       0x4B2F	/* start sound generation (0 for off) */
+#define TARGET_KDMKTONE	       0x4B30	/* generate tone */
+#define TARGET_KDGKBTYPE       0x4b33
+#define TARGET_KDSETMODE       0x4b3a
+#define TARGET_KDGKBMODE       0x4b44
+#define TARGET_KDSKBMODE       0x4b45
+#define TARGET_KDGKBENT	       0x4B46	/* gets one entry in translation table */
+#define TARGET_KDGKBSENT       0x4B48	/* gets one function key string entry */
+#define TARGET_KDGKBLED        0x4B64	/* get led flags (not lights) */
+#define TARGET_KDSKBLED        0x4B65	/* set led flags (not lights) */
+#define TARGET_KDGETLED        0x4B31	/* return current led state */
+#define TARGET_KDSETLED        0x4B32	/* set led state [lights, not flags] */
+
+#define TARGET_SIOCATMARK      0x8905
+
+/* Networking ioctls */
+#define TARGET_SIOCADDRT       0x890B          /* add routing table entry */
+#define TARGET_SIOCDELRT       0x890C          /* delete routing table entry */
+#define TARGET_SIOCGIFNAME     0x8910          /* get iface name               */
+#define TARGET_SIOCSIFLINK     0x8911          /* set iface channel            */
+#define TARGET_SIOCGIFCONF     0x8912          /* get iface list               */
+#define TARGET_SIOCGIFFLAGS    0x8913          /* get flags                    */
+#define TARGET_SIOCSIFFLAGS    0x8914          /* set flags                    */
+#define TARGET_SIOCGIFADDR     0x8915          /* get PA address               */
+#define TARGET_SIOCSIFADDR     0x8916          /* set PA address               */
+#define TARGET_SIOCGIFDSTADDR  0x8917          /* get remote PA address        */
+#define TARGET_SIOCSIFDSTADDR  0x8918          /* set remote PA address        */
+#define TARGET_SIOCGIFBRDADDR  0x8919          /* get broadcast PA address     */
+#define TARGET_SIOCSIFBRDADDR  0x891a          /* set broadcast PA address     */
+#define TARGET_SIOCGIFNETMASK  0x891b          /* get network PA mask          */
+#define TARGET_SIOCSIFNETMASK  0x891c          /* set network PA mask          */
+#define TARGET_SIOCGIFMETRIC   0x891d          /* get metric                   */
+#define TARGET_SIOCSIFMETRIC   0x891e          /* set metric                   */
+#define TARGET_SIOCGIFMEM      0x891f          /* get memory address (BSD)     */
+#define TARGET_SIOCSIFMEM      0x8920          /* set memory address (BSD)     */
+#define TARGET_SIOCGIFMTU      0x8921          /* get MTU size                 */
+#define TARGET_SIOCSIFMTU      0x8922          /* set MTU size                 */
+#define TARGET_SIOCSIFHWADDR   0x8924          /* set hardware address (NI)    */
+#define TARGET_SIOCGIFENCAP    0x8925          /* get/set slip encapsulation   */
+#define TARGET_SIOCSIFENCAP    0x8926
+#define TARGET_SIOCGIFHWADDR   0x8927          /* Get hardware address         */
+#define TARGET_SIOCGIFSLAVE    0x8929          /* Driver slaving support       */
+#define TARGET_SIOCSIFSLAVE    0x8930
+#define TARGET_SIOCADDMULTI    0x8931          /* Multicast address lists      */
+#define TARGET_SIOCDELMULTI    0x8932
+
+/* Bridging control calls */
+#define TARGET_SIOCGIFBR       0x8940          /* Bridging support             */
+#define TARGET_SIOCSIFBR       0x8941          /* Set bridging options         */
+
+#define TARGET_SIOCGIFTXQLEN   0x8942          /* Get the tx queue length      */
+#define TARGET_SIOCSIFTXQLEN   0x8943          /* Set the tx queue length      */
+
+/* ARP cache control calls. */
+#define TARGET_OLD_SIOCDARP    0x8950          /* old delete ARP table entry   */
+#define TARGET_OLD_SIOCGARP    0x8951          /* old get ARP table entry      */
+#define TARGET_OLD_SIOCSARP    0x8952          /* old set ARP table entry      */
+#define TARGET_SIOCDARP        0x8953          /* delete ARP table entry       */
+#define TARGET_SIOCGARP        0x8954          /* get ARP table entry          */
+#define TARGET_SIOCSARP        0x8955          /* set ARP table entry          */
+
+/* RARP cache control calls. */
+#define TARGET_SIOCDRARP       0x8960          /* delete RARP table entry      */
+#define TARGET_SIOCGRARP       0x8961          /* get RARP table entry         */
+#define TARGET_SIOCSRARP       0x8962          /* set RARP table entry         */
+
+/* Driver configuration calls */
+#define TARGET_SIOCGIFMAP      0x8970          /* Get device parameters        */
+#define TARGET_SIOCSIFMAP      0x8971          /* Set device parameters        */
+
+/* DLCI configuration calls */
+#define TARGET_SIOCADDDLCI     0x8980          /* Create new DLCI device       */
+#define TARGET_SIOCDELDLCI     0x8981          /* Delete DLCI device           */
+
+/* From <linux/wireless.h> */
+
+#define TARGET_SIOCGIWNAME     0x8B01          /* get name == wireless protocol */
+
+/* From <linux/fs.h> */
+
+#define TARGET_BLKROSET   TARGET_IO(0x12,93) /* set device read-only (0 = read-write) */
+#define TARGET_BLKROGET   TARGET_IO(0x12,94) /* get read-only status (0 = read_write) */
+#define TARGET_BLKRRPART  TARGET_IO(0x12,95) /* re-read partition table */
+#define TARGET_BLKGETSIZE TARGET_IO(0x12,96) /* return device size /512 (long *arg) */
+#define TARGET_BLKFLSBUF  TARGET_IO(0x12,97) /* flush buffer cache */
+#define TARGET_BLKRASET   TARGET_IO(0x12,98) /* Set read ahead for block device */
+#define TARGET_BLKRAGET   TARGET_IO(0x12,99) /* get current read ahead setting */
+#define TARGET_BLKFRASET  TARGET_IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
+#define TARGET_BLKFRAGET  TARGET_IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
+#define TARGET_BLKSECTSET TARGET_IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
+#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
+#define TARGET_BLKSSZGET  TARGET_IO(0x12,104)/* get block device sector size */
+/* A jump here: 108-111 have been used for various private purposes. */
+#define TARGET_BLKBSZGET  TARGET_IOR(0x12,112,sizeof(int))
+#define TARGET_BLKBSZSET  TARGET_IOW(0x12,113,sizeof(int))
+#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
+#define TARGET_FIBMAP     TARGET_IO(0x00,1)  /* bmap access */
+#define TARGET_FIGETBSZ   TARGET_IO(0x00,2)  /* get the block size used for bmap */
+#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
+
+/* cdrom commands */
+#define TARGET_CDROMPAUSE		0x5301 /* Pause Audio Operation */
+#define TARGET_CDROMRESUME		0x5302 /* Resume paused Audio Operation */
+#define TARGET_CDROMPLAYMSF		0x5303 /* Play Audio MSF (struct cdrom_msf) */
+#define TARGET_CDROMPLAYTRKIND		0x5304 /* Play Audio Track/index
+                                           (struct cdrom_ti) */
+#define TARGET_CDROMREADTOCHDR		0x5305 /* Read TOC header
+                                           (struct cdrom_tochdr) */
+#define TARGET_CDROMREADTOCENTRY	0x5306 /* Read TOC entry
+                                           (struct cdrom_tocentry) */
+#define TARGET_CDROMSTOP		0x5307 /* Stop the cdrom drive */
+#define TARGET_CDROMSTART		0x5308 /* Start the cdrom drive */
+#define TARGET_CDROMEJECT		0x5309 /* Ejects the cdrom media */
+#define TARGET_CDROMVOLCTRL		0x530a /* Control output volume
+                                           (struct cdrom_volctrl) */
+#define TARGET_CDROMSUBCHNL		0x530b /* Read subchannel data
+                                           (struct cdrom_subchnl) */
+#define TARGET_CDROMREADMODE2		0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes)
+                                           (struct cdrom_read) */
+#define TARGET_CDROMREADMODE1		0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes)
+                                           (struct cdrom_read) */
+#define TARGET_CDROMREADAUDIO		0x530e /* (struct cdrom_read_audio) */
+#define TARGET_CDROMEJECT_SW		0x530f /* enable(1)/disable(0) auto-ejecting */
+#define TARGET_CDROMMULTISESSION	0x5310 /* Obtain the start-of-last-session
+                                           address of multi session disks
+                                           (struct cdrom_multisession) */
+#define TARGET_CDROM_GET_MCN		0x5311 /* Obtain the "Universal Product Code"
+                                           if available (struct cdrom_mcn) */
+#define TARGET_CDROM_GET_UPC		TARGET_CDROM_GET_MCN  /* This one is depricated,
+                                          but here anyway for compatability */
+#define TARGET_CDROMRESET		0x5312 /* hard-reset the drive */
+#define TARGET_CDROMVOLREAD		0x5313 /* Get the drive's volume setting
+                                          (struct cdrom_volctrl) */
+#define TARGET_CDROMREADRAW		0x5314	/* read data in raw mode (2352 Bytes)
+                                           (struct cdrom_read) */
+/*
+ * These ioctls are used only used in aztcd.c and optcd.c
+ */
+#define TARGET_CDROMREADCOOKED		0x5315	/* read data in cooked mode */
+#define TARGET_CDROMSEEK		0x5316  /* seek msf address */
+
+/*
+ * This ioctl is only used by the scsi-cd driver.
+   It is for playing audio in logical block addressing mode.
+ */
+#define TARGET_CDROMPLAYBLK		0x5317	/* (struct cdrom_blk) */
+
+/*
+ * These ioctls are only used in optcd.c
+ */
+#define TARGET_CDROMREADALL		0x5318	/* read all 2646 bytes */
+
+/*
+ * These ioctls are (now) only in ide-cd.c for controlling
+ * drive spindown time.  They should be implemented in the
+ * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10,
+ * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE...
+ *  -Erik
+ */
+#define TARGET_CDROMGETSPINDOWN        0x531d
+#define TARGET_CDROMSETSPINDOWN        0x531e
+
+/*
+ * These ioctls are implemented through the uniform CD-ROM driver
+ * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM
+ * drivers are eventually ported to the uniform CD-ROM driver interface.
+ */
+#define TARGET_CDROMCLOSETRAY		0x5319	/* pendant of CDROMEJECT */
+#define TARGET_CDROM_SET_OPTIONS	0x5320  /* Set behavior options */
+#define TARGET_CDROM_CLEAR_OPTIONS	0x5321  /* Clear behavior options */
+#define TARGET_CDROM_SELECT_SPEED	0x5322  /* Set the CD-ROM speed */
+#define TARGET_CDROM_SELECT_DISC	0x5323  /* Select disc (for juke-boxes) */
+#define TARGET_CDROM_MEDIA_CHANGED	0x5325  /* Check is media changed  */
+#define TARGET_CDROM_DRIVE_STATUS	0x5326  /* Get tray position, etc. */
+#define TARGET_CDROM_DISC_STATUS	0x5327  /* Get disc type, etc. */
+#define TARGET_CDROM_CHANGER_NSLOTS    0x5328  /* Get number of slots */
+#define TARGET_CDROM_LOCKDOOR		0x5329  /* lock or unlock door */
+#define TARGET_CDROM_DEBUG		0x5330	/* Turn debug messages on/off */
+#define TARGET_CDROM_GET_CAPABILITY	0x5331	/* get capabilities */
+
+/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386.
+ * Future CDROM ioctls should be kept below 0x537F
+ */
+
+/* This ioctl is only used by sbpcd at the moment */
+#define TARGET_CDROMAUDIOBUFSIZ        0x5382	/* set the audio buffer size */
+					/* conflict with SCSI_IOCTL_GET_IDLUN */
+
+/* DVD-ROM Specific ioctls */
+#define TARGET_DVD_READ_STRUCT		0x5390  /* Read structure */
+#define TARGET_DVD_WRITE_STRUCT	0x5391  /* Write structure */
+#define TARGET_DVD_AUTH		0x5392  /* Authentication */
+
+#define TARGET_CDROM_SEND_PACKET	0x5393	/* send a packet to the drive */
+#define TARGET_CDROM_NEXT_WRITABLE	0x5394	/* get next writable block */
+#define TARGET_CDROM_LAST_WRITTEN	0x5395	/* get last block written on disc */
+
+/* HD commands */
+
+/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
+#define TARGET_HDIO_GETGEO            0x0301  /* get device geometry */
+#define TARGET_HDIO_GET_UNMASKINTR    0x0302  /* get current unmask setting */
+#define TARGET_HDIO_GET_MULTCOUNT     0x0304  /* get current IDE blockmode setting */
+#define TARGET_HDIO_GET_KEEPSETTINGS  0x0308  /* get keep-settings-on-reset flag */
+#define TARGET_HDIO_GET_32BIT         0x0309  /* get current io_32bit setting */
+#define TARGET_HDIO_GET_NOWERR        0x030a  /* get ignore-write-error flag */
+#define TARGET_HDIO_GET_DMA           0x030b  /* get use-dma flag */
+#define TARGET_HDIO_GET_IDENTITY      0x030d  /* get IDE identification info */
+#define TARGET_HDIO_DRIVE_CMD         0x031f  /* execute a special drive command */
+
+/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
+#define TARGET_HDIO_SET_MULTCOUNT     0x0321  /* change IDE blockmode */
+#define TARGET_HDIO_SET_UNMASKINTR    0x0322  /* permit other irqs during I/O */
+#define TARGET_HDIO_SET_KEEPSETTINGS  0x0323  /* keep ioctl settings on reset */
+#define TARGET_HDIO_SET_32BIT         0x0324  /* change io_32bit flags */
+#define TARGET_HDIO_SET_NOWERR        0x0325  /* change ignore-write-error flag */
+#define TARGET_HDIO_SET_DMA           0x0326  /* change use-dma flag */
+#define TARGET_HDIO_SET_PIO_MODE      0x0327  /* reconfig interface to new speed */
+
+/* loop ioctls */
+#define TARGET_LOOP_SET_FD            0x4C00
+#define TARGET_LOOP_CLR_FD            0x4C01
+#define TARGET_LOOP_SET_STATUS        0x4C02
+#define TARGET_LOOP_GET_STATUS        0x4C03
+#define TARGET_LOOP_SET_STATUS64      0x4C04
+#define TARGET_LOOP_GET_STATUS64      0x4C05
+#define TARGET_LOOP_CHANGE_FD         0x4C06
+
+/* fb ioctls */
+#define TARGET_FBIOGET_VSCREENINFO    0x4600
+#define TARGET_FBIOPUT_VSCREENINFO    0x4601
+#define TARGET_FBIOGET_FSCREENINFO    0x4602
+#define TARGET_FBIOGETCMAP            0x4604
+#define TARGET_FBIOPUTCMAP            0x4605
+#define TARGET_FBIOPAN_DISPLAY        0x4606
+#define TARGET_FBIOGET_CON2FBMAP      0x460F
+#define TARGET_FBIOPUT_CON2FBMAP      0x4610
+
+/* vt ioctls */
+#define TARGET_VT_OPENQRY             0x5600
+#define TARGET_VT_GETSTATE            0x5603
+#define TARGET_VT_ACTIVATE            0x5606
+#define TARGET_VT_WAITACTIVE          0x5607
+#define TARGET_VT_LOCKSWITCH          0x560b
+#define TARGET_VT_UNLOCKSWITCH        0x560c
+#define TARGET_VT_GETMODE             0x5601
+#define TARGET_VT_SETMODE             0x5602
+#define TARGET_VT_RELDISP             0x5605
+#define TARGET_VT_DISALLOCATE         0x5608
+
+/* from asm/termbits.h */
+
+#define TARGET_NCC 8
+struct target_termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[TARGET_NCC];	/* control characters */
+};
+
+struct target_winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#include "termbits.h"
+
+#if defined(TARGET_MIPS)
+#define TARGET_PROT_SEM         0x10
+#else
+#define TARGET_PROT_SEM         0x08
+#endif
+
+/* Common */
+#define TARGET_MAP_SHARED	0x01		/* Share changes */
+#define TARGET_MAP_PRIVATE	0x02		/* Changes are private */
+#define TARGET_MAP_TYPE		0x0f		/* Mask for type of mapping */
+
+/* Target specific */
+#if defined(TARGET_MIPS)
+#define TARGET_MAP_FIXED	0x10		/* Interpret addr exactly */
+#define TARGET_MAP_ANONYMOUS	0x0800		/* don't use a file */
+#define TARGET_MAP_GROWSDOWN	0x1000		/* stack-like segment */
+#define TARGET_MAP_DENYWRITE	0x2000		/* ETXTBSY */
+#define TARGET_MAP_EXECUTABLE	0x4000		/* mark it as an executable */
+#define TARGET_MAP_LOCKED	0x8000		/* pages are locked */
+#define TARGET_MAP_NORESERVE	0x0400		/* don't check for reservations */
+#define TARGET_MAP_POPULATE	0x10000		/* populate (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x20000		/* do not block on IO */
+#elif defined(TARGET_PPC)
+#define TARGET_MAP_FIXED	0x10		/* Interpret addr exactly */
+#define TARGET_MAP_ANONYMOUS	0x20		/* don't use a file */
+#define TARGET_MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define TARGET_MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define TARGET_MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define TARGET_MAP_LOCKED	0x0080		/* pages are locked */
+#define TARGET_MAP_NORESERVE	0x0040		/* don't check for reservations */
+#define TARGET_MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x10000		/* do not block on IO */
+#elif defined(TARGET_ALPHA)
+#define TARGET_MAP_ANONYMOUS	0x10		/* don't use a file */
+#define TARGET_MAP_FIXED	0x100		/* Interpret addr exactly */
+#define TARGET_MAP_GROWSDOWN	0x01000		/* stack-like segment */
+#define TARGET_MAP_DENYWRITE	0x02000		/* ETXTBSY */
+#define TARGET_MAP_EXECUTABLE	0x04000		/* mark it as an executable */
+#define TARGET_MAP_LOCKED	0x08000		/* lock the mapping */
+#define TARGET_MAP_NORESERVE	0x10000		/* no check for reservations */
+#define TARGET_MAP_POPULATE	0x20000		/* pop (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x40000		/* do not block on IO */
+#else
+#define TARGET_MAP_FIXED	0x10		/* Interpret addr exactly */
+#define TARGET_MAP_ANONYMOUS	0x20		/* don't use a file */
+#define TARGET_MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define TARGET_MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define TARGET_MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define TARGET_MAP_LOCKED	0x2000		/* pages are locked */
+#define TARGET_MAP_NORESERVE	0x4000		/* don't check for reservations */
+#define TARGET_MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x10000		/* do not block on IO */
+#define TARGET_MAP_UNINITIALIZED 0x4000000	/* for anonymous mmap, memory could be uninitialized */
+#endif
+
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \
+    || defined(TARGET_CRIS) || defined(TARGET_UNICORE32)
+struct target_stat {
+	unsigned short st_dev;
+	unsigned short __pad1;
+	abi_ulong st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned short __pad2;
+	abi_ulong  st_size;
+	abi_ulong  st_blksize;
+	abi_ulong  st_blocks;
+	abi_ulong  target_st_atime;
+	abi_ulong  __unused1;
+	abi_ulong  target_st_mtime;
+	abi_ulong  __unused2;
+	abi_ulong  target_st_ctime;
+	abi_ulong  __unused3;
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct target_stat64 {
+	unsigned short	st_dev;
+	unsigned char	__pad0[10];
+
+#define TARGET_STAT64_HAS_BROKEN_ST_INO	1
+	abi_ulong	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	abi_ulong	st_uid;
+	abi_ulong	st_gid;
+
+	unsigned short	st_rdev;
+	unsigned char	__pad3[10];
+
+	long long	st_size;
+	abi_ulong	st_blksize;
+
+	abi_ulong	st_blocks;	/* Number 512-byte blocks allocated. */
+	abi_ulong	__pad4;		/* future possible st_blocks high bits */
+
+	abi_ulong	target_st_atime;
+	abi_ulong	__pad5;
+
+	abi_ulong	target_st_mtime;
+	abi_ulong	__pad6;
+
+	abi_ulong	target_st_ctime;
+	abi_ulong	__pad7;		/* will be high 32 bits of ctime someday */
+
+	unsigned long long	st_ino;
+} __attribute__((packed));
+
+#ifdef TARGET_ARM
+struct target_eabi_stat64 {
+        unsigned long long st_dev;
+        unsigned int    __pad1;
+        abi_ulong    __st_ino;
+        unsigned int    st_mode;
+        unsigned int    st_nlink;
+
+        abi_ulong    st_uid;
+        abi_ulong    st_gid;
+
+        unsigned long long st_rdev;
+        unsigned int    __pad2[2];
+
+        long long       st_size;
+        abi_ulong    st_blksize;
+        unsigned int    __pad3;
+        unsigned long long st_blocks;
+
+        abi_ulong    target_st_atime;
+        abi_ulong    target_st_atime_nsec;
+
+        abi_ulong    target_st_mtime;
+        abi_ulong    target_st_mtime_nsec;
+
+        abi_ulong    target_st_ctime;
+        abi_ulong    target_st_ctime_nsec;
+
+        unsigned long long st_ino;
+} __attribute__ ((packed));
+#endif
+
+#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+struct target_stat {
+	unsigned int	st_dev;
+	abi_ulong	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	st_rdev;
+	abi_long	st_size;
+	abi_long	target_st_atime;
+	abi_long	target_st_mtime;
+	abi_long	target_st_ctime;
+	abi_long	st_blksize;
+	abi_long	st_blocks;
+	abi_ulong	__unused4[2];
+};
+
+struct target_stat64 {
+	unsigned char	__pad0[6];
+	unsigned short	st_dev;
+
+	uint64_t	st_ino;
+	uint64_t	st_nlink;
+
+	unsigned int	st_mode;
+
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+
+	unsigned char	__pad2[6];
+	unsigned short	st_rdev;
+
+        int64_t		st_size;
+	int64_t		st_blksize;
+
+	unsigned char	__pad4[4];
+	unsigned int	st_blocks;
+
+	abi_ulong	target_st_atime;
+	abi_ulong	__unused1;
+
+	abi_ulong	target_st_mtime;
+	abi_ulong	__unused2;
+
+	abi_ulong	target_st_ctime;
+	abi_ulong	__unused3;
+
+	abi_ulong	__unused4[3];
+};
+
+#elif defined(TARGET_SPARC)
+
+struct target_stat {
+	unsigned short	st_dev;
+	abi_ulong	st_ino;
+	unsigned short	st_mode;
+	short		st_nlink;
+	unsigned short	st_uid;
+	unsigned short	st_gid;
+	unsigned short	st_rdev;
+	abi_long	st_size;
+	abi_long	target_st_atime;
+	abi_ulong	__unused1;
+	abi_long	target_st_mtime;
+	abi_ulong	__unused2;
+	abi_long	target_st_ctime;
+	abi_ulong	__unused3;
+	abi_long	st_blksize;
+	abi_long	st_blocks;
+	abi_ulong	__unused4[2];
+};
+
+struct target_stat64 {
+	unsigned char	__pad0[6];
+	unsigned short	st_dev;
+
+	uint64_t st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+
+	unsigned char	__pad2[6];
+	unsigned short	st_rdev;
+
+	unsigned char	__pad3[8];
+
+        int64_t	st_size;
+	unsigned int	st_blksize;
+
+	unsigned char	__pad4[8];
+	unsigned int	st_blocks;
+
+	unsigned int	target_st_atime;
+	unsigned int	__unused1;
+
+	unsigned int	target_st_mtime;
+	unsigned int	__unused2;
+
+	unsigned int	target_st_ctime;
+	unsigned int	__unused3;
+
+	unsigned int	__unused4;
+	unsigned int	__unused5;
+};
+
+#elif defined(TARGET_PPC)
+
+struct target_stat {
+	abi_ulong st_dev;
+	abi_ulong st_ino;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+	abi_ulong st_nlink;
+	unsigned int st_mode;
+#else
+	unsigned int st_mode;
+	unsigned short st_nlink;
+#endif
+	unsigned int st_uid;
+	unsigned int st_gid;
+	abi_ulong  st_rdev;
+	abi_ulong  st_size;
+	abi_ulong  st_blksize;
+	abi_ulong  st_blocks;
+	abi_ulong  target_st_atime;
+	abi_ulong  target_st_atime_nsec;
+	abi_ulong  target_st_mtime;
+	abi_ulong  target_st_mtime_nsec;
+	abi_ulong  target_st_ctime;
+	abi_ulong  target_st_ctime_nsec;
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+	abi_ulong  __unused6;
+#endif
+};
+
+struct __attribute__((__packed__)) target_stat64 {
+	unsigned long long st_dev;
+        unsigned long long st_ino;
+	unsigned int st_mode;
+	unsigned int st_nlink;
+	unsigned int st_uid;
+	unsigned int st_gid;
+	unsigned long long st_rdev;
+	unsigned long long __pad0;
+	long long      st_size;
+	int	       st_blksize;
+	unsigned int   __pad1;
+	long long      st_blocks;	/* Number 512-byte blocks allocated. */
+	int	       target_st_atime;
+        unsigned int   target_st_atime_nsec;
+	int	       target_st_mtime;
+        unsigned int   target_st_mtime_nsec;
+	int            target_st_ctime;
+        unsigned int   target_st_ctime_nsec;
+        unsigned int   __unused4;
+        unsigned int   __unused5;
+};
+
+#elif defined(TARGET_MICROBLAZE)
+
+struct target_stat {
+	abi_ulong st_dev;
+	abi_ulong st_ino;
+	unsigned int st_mode;
+	unsigned short st_nlink;
+	unsigned int st_uid;
+	unsigned int st_gid;
+	abi_ulong  st_rdev;
+	abi_ulong  st_size;
+	abi_ulong  st_blksize;
+	abi_ulong  st_blocks;
+	abi_ulong  target_st_atime;
+	abi_ulong  target_st_atime_nsec;
+	abi_ulong  target_st_mtime;
+	abi_ulong  target_st_mtime_nsec;
+	abi_ulong  target_st_ctime;
+	abi_ulong  target_st_ctime_nsec;
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+/* FIXME: Microblaze no-mmu user-space has a difference stat64 layout...  */
+struct __attribute__((__packed__)) target_stat64 {
+	uint64_t st_dev;
+#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
+	uint32_t pad0;
+	uint32_t __st_ino;
+
+	uint32_t st_mode;
+	uint32_t st_nlink;
+	uint32_t st_uid;
+	uint32_t st_gid;
+	uint64_t st_rdev;
+	uint64_t __pad1;
+
+	int64_t  st_size;
+	int32_t  st_blksize;
+	uint32_t __pad2;
+	int64_t st_blocks;	/* Number 512-byte blocks allocated. */
+
+	int	       target_st_atime;
+	unsigned int   target_st_atime_nsec;
+	int	       target_st_mtime;
+	unsigned int   target_st_mtime_nsec;
+	int            target_st_ctime;
+	unsigned int   target_st_ctime_nsec;
+	uint64_t st_ino;
+};
+
+#elif defined(TARGET_M68K)
+
+struct target_stat {
+	unsigned short st_dev;
+	unsigned short __pad1;
+	abi_ulong st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned short __pad2;
+	abi_ulong  st_size;
+	abi_ulong  st_blksize;
+	abi_ulong  st_blocks;
+	abi_ulong  target_st_atime;
+	abi_ulong  __unused1;
+	abi_ulong  target_st_mtime;
+	abi_ulong  __unused2;
+	abi_ulong  target_st_ctime;
+	abi_ulong  __unused3;
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct target_stat64 {
+	unsigned long long	st_dev;
+	unsigned char	__pad1[2];
+
+#define TARGET_STAT64_HAS_BROKEN_ST_INO	1
+	abi_ulong	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	abi_ulong	st_uid;
+	abi_ulong	st_gid;
+
+	unsigned long long	st_rdev;
+	unsigned char	__pad3[2];
+
+	long long	st_size;
+	abi_ulong	st_blksize;
+
+	abi_ulong	__pad4;		/* future possible st_blocks high bits */
+	abi_ulong	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	abi_ulong	target_st_atime;
+	abi_ulong	target_st_atime_nsec;
+
+	abi_ulong	target_st_mtime;
+	abi_ulong	target_st_mtime_nsec;
+
+	abi_ulong	target_st_ctime;
+	abi_ulong	target_st_ctime_nsec;
+
+	unsigned long long	st_ino;
+} __attribute__((packed));
+
+#elif defined(TARGET_ABI_MIPSN64)
+
+/* The memory layout is the same as of struct stat64 of the 32-bit kernel.  */
+struct target_stat {
+	unsigned int		st_dev;
+	unsigned int		st_pad0[3]; /* Reserved for st_dev expansion */
+
+	abi_ulong		st_ino;
+
+	unsigned int		st_mode;
+	unsigned int		st_nlink;
+
+	int			st_uid;
+	int			st_gid;
+
+	unsigned int		st_rdev;
+	unsigned int		st_pad1[3]; /* Reserved for st_rdev expansion */
+
+	abi_ulong		st_size;
+
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	unsigned int		target_st_atime;
+	unsigned int		target_st_atime_nsec;
+
+	unsigned int		target_st_mtime;
+	unsigned int		target_st_mtime_nsec;
+
+	unsigned int		target_st_ctime;
+	unsigned int		target_st_ctime_nsec;
+
+	unsigned int		st_blksize;
+	unsigned int		st_pad2;
+
+	abi_ulong		st_blocks;
+};
+
+#elif defined(TARGET_ABI_MIPSN32)
+
+struct target_stat {
+	unsigned	st_dev;
+	int		st_pad1[3];		/* Reserved for network id */
+	unsigned int	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	int		st_uid;
+	int		st_gid;
+	unsigned 	st_rdev;
+	unsigned int	st_pad2[2];
+	unsigned int	st_size;
+	unsigned int	st_pad3;
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	unsigned int		target_st_atime;
+	unsigned int		target_st_atime_nsec;
+	unsigned int		target_st_mtime;
+	unsigned int		target_st_mtime_nsec;
+	unsigned int		target_st_ctime;
+	unsigned int		target_st_ctime_nsec;
+	unsigned int		st_blksize;
+	unsigned int		st_blocks;
+	unsigned int		st_pad4[14];
+};
+
+/*
+ * This matches struct stat64 in glibc2.1, hence the absolutely insane
+ * amounts of padding around dev_t's.  The memory layout is the same as of
+ * struct stat of the 64-bit kernel.
+ */
+
+struct target_stat64 {
+	unsigned int	st_dev;
+	unsigned int	st_pad0[3];	/* Reserved for st_dev expansion  */
+
+	target_ulong	st_ino;
+
+        unsigned int	st_mode;
+        unsigned int	st_nlink;
+
+	int		st_uid;
+	int		st_gid;
+
+	unsigned int	st_rdev;
+	unsigned int	st_pad1[3];	/* Reserved for st_rdev expansion  */
+
+	int		st_size;
+
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	int		target_st_atime;
+	unsigned int	target_st_atime_nsec;	/* Reserved for st_atime expansion  */
+
+	int		target_st_mtime;
+	unsigned int	target_st_mtime_nsec;	/* Reserved for st_mtime expansion  */
+
+	int		target_st_ctime;
+	unsigned int	target_st_ctime_nsec;	/* Reserved for st_ctime expansion  */
+
+	unsigned int	st_blksize;
+	unsigned int	st_pad2;
+
+	int		st_blocks;
+};
+
+#elif defined(TARGET_ABI_MIPSO32)
+
+struct target_stat {
+	unsigned	st_dev;
+	abi_long	st_pad1[3];		/* Reserved for network id */
+	abi_ulong	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	int		st_uid;
+	int		st_gid;
+	unsigned 	st_rdev;
+	abi_long	st_pad2[2];
+	abi_long	st_size;
+	abi_long	st_pad3;
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	abi_long		target_st_atime;
+	abi_long		target_st_atime_nsec;
+	abi_long		target_st_mtime;
+	abi_long		target_st_mtime_nsec;
+	abi_long		target_st_ctime;
+	abi_long		target_st_ctime_nsec;
+	abi_long		st_blksize;
+	abi_long		st_blocks;
+	abi_long		st_pad4[14];
+};
+
+/*
+ * This matches struct stat64 in glibc2.1, hence the absolutely insane
+ * amounts of padding around dev_t's.  The memory layout is the same as of
+ * struct stat of the 64-bit kernel.
+ */
+
+struct target_stat64 {
+	abi_ulong	st_dev;
+	abi_ulong	st_pad0[3];	/* Reserved for st_dev expansion  */
+
+	uint64_t	st_ino;
+
+        unsigned int	st_mode;
+        unsigned int	st_nlink;
+
+	int		st_uid;
+	int		st_gid;
+
+	abi_ulong	st_rdev;
+	abi_ulong	st_pad1[3];	/* Reserved for st_rdev expansion  */
+
+	int64_t 	st_size;
+
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	abi_long	target_st_atime;
+	abi_ulong	target_st_atime_nsec;	/* Reserved for st_atime expansion  */
+
+	abi_long	target_st_mtime;
+	abi_ulong	target_st_mtime_nsec;	/* Reserved for st_mtime expansion  */
+
+	abi_long	target_st_ctime;
+	abi_ulong	target_st_ctime_nsec;	/* Reserved for st_ctime expansion  */
+
+	abi_ulong	st_blksize;
+	abi_ulong	st_pad2;
+
+	int64_t  	st_blocks;
+};
+
+#elif defined(TARGET_ALPHA)
+
+struct target_stat {
+       unsigned int    st_dev;
+       unsigned int    st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_rdev;
+       abi_long     st_size;
+       abi_ulong    target_st_atime;
+       abi_ulong    target_st_mtime;
+       abi_ulong    target_st_ctime;
+       unsigned int    st_blksize;
+       unsigned int    st_blocks;
+       unsigned int    st_flags;
+       unsigned int    st_gen;
+};
+
+struct target_stat64 {
+       abi_ulong    st_dev;
+       abi_ulong    st_ino;
+       abi_ulong    st_rdev;
+       abi_long     st_size;
+       abi_ulong    st_blocks;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_blksize;
+       unsigned int    st_nlink;
+       unsigned int    __pad0;
+
+       abi_ulong    target_st_atime;
+       abi_ulong    target_st_atime_nsec;
+       abi_ulong    target_st_mtime;
+       abi_ulong    target_st_mtime_nsec;
+       abi_ulong    target_st_ctime;
+       abi_ulong    target_st_ctime_nsec;
+       abi_long     __unused[3];
+};
+
+#elif defined(TARGET_SH4)
+
+struct target_stat {
+	abi_ulong  st_dev;
+	abi_ulong  st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	abi_ulong  st_rdev;
+	abi_ulong  st_size;
+	abi_ulong  st_blksize;
+	abi_ulong  st_blocks;
+	abi_ulong  target_st_atime;
+	abi_ulong  target_st_atime_nsec;
+	abi_ulong  target_st_mtime;
+	abi_ulong  target_st_mtime_nsec;
+	abi_ulong  target_st_ctime;
+	abi_ulong  target_st_ctime_nsec;
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct __attribute__((__packed__)) target_stat64 {
+	unsigned long long	st_dev;
+	unsigned char	__pad0[4];
+
+#define TARGET_STAT64_HAS_BROKEN_ST_INO	1
+	abi_ulong	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	abi_ulong	st_uid;
+	abi_ulong	st_gid;
+
+	unsigned long long	st_rdev;
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	abi_ulong	st_blksize;
+
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	abi_ulong	target_st_atime;
+	abi_ulong	target_st_atime_nsec;
+
+	abi_ulong	target_st_mtime;
+	abi_ulong	target_st_mtime_nsec;
+
+	abi_ulong	target_st_ctime;
+	abi_ulong	target_st_ctime_nsec;
+
+	unsigned long long	st_ino;
+};
+
+#elif defined(TARGET_I386) && !defined(TARGET_ABI32)
+struct target_stat {
+	abi_ulong	st_dev;
+	abi_ulong	st_ino;
+	abi_ulong	st_nlink;
+
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad0;
+	abi_ulong	st_rdev;
+	abi_long	st_size;
+	abi_long	st_blksize;
+    	abi_long	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	abi_ulong	target_st_atime;
+	abi_ulong 	target_st_atime_nsec; 
+	abi_ulong	target_st_mtime;
+	abi_ulong	target_st_mtime_nsec;
+	abi_ulong	target_st_ctime;
+	abi_ulong       target_st_ctime_nsec;
+
+  	abi_long	__unused[3];
+};
+#elif defined(TARGET_S390X)
+struct target_stat {
+    abi_ulong  st_dev;
+    abi_ulong  st_ino;
+    abi_ulong  st_nlink;
+    unsigned int   st_mode;
+    unsigned int   st_uid;
+    unsigned int   st_gid;
+    unsigned int   __pad1;
+    abi_ulong  st_rdev;
+    abi_ulong  st_size;
+    abi_ulong  target_st_atime;
+    abi_ulong  target_st_atime_nsec;
+    abi_ulong  target_st_mtime;
+    abi_ulong  target_st_mtime_nsec;
+    abi_ulong  target_st_ctime;
+    abi_ulong  target_st_ctime_nsec;
+    abi_ulong  st_blksize;
+    abi_long       st_blocks;
+    abi_ulong  __unused[3];
+};
+#else
+#error unsupported CPU
+#endif
+
+typedef struct {
+        int     val[2];
+} target_fsid_t;
+
+#ifdef TARGET_MIPS
+#ifdef TARGET_ABI_MIPSN32
+struct target_statfs {
+	int32_t			f_type;
+	int32_t			f_bsize;
+	int32_t			f_frsize;	/* Fragment size - unsupported */
+	int32_t			f_blocks;
+	int32_t			f_bfree;
+	int32_t			f_files;
+	int32_t			f_ffree;
+	int32_t			f_bavail;
+
+	/* Linux specials */
+	target_fsid_t		f_fsid;
+	int32_t			f_namelen;
+	int32_t			f_spare[6];
+};
+#else
+struct target_statfs {
+	abi_long		f_type;
+	abi_long		f_bsize;
+	abi_long		f_frsize;	/* Fragment size - unsupported */
+	abi_long		f_blocks;
+	abi_long		f_bfree;
+	abi_long		f_files;
+	abi_long		f_ffree;
+	abi_long		f_bavail;
+
+	/* Linux specials */
+	target_fsid_t		f_fsid;
+	abi_long		f_namelen;
+	abi_long		f_spare[6];
+};
+#endif
+
+struct target_statfs64 {
+	uint32_t	f_type;
+	uint32_t	f_bsize;
+	uint32_t	f_frsize;	/* Fragment size - unsupported */
+	uint32_t	__pad;
+	uint64_t	f_blocks;
+	uint64_t	f_bfree;
+	uint64_t	f_files;
+	uint64_t	f_ffree;
+	uint64_t	f_bavail;
+	target_fsid_t	f_fsid;
+	uint32_t	f_namelen;
+	uint32_t	f_spare[6];
+};
+#elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \
+       defined(TARGET_SPARC64)) && !defined(TARGET_ABI32)
+struct target_statfs {
+	abi_long f_type;
+	abi_long f_bsize;
+	abi_long f_blocks;
+	abi_long f_bfree;
+	abi_long f_bavail;
+	abi_long f_files;
+	abi_long f_ffree;
+	target_fsid_t f_fsid;
+	abi_long f_namelen;
+	abi_long f_frsize;
+	abi_long f_spare[5];
+};
+
+struct target_statfs64 {
+	abi_long f_type;
+	abi_long f_bsize;
+	abi_long f_blocks;
+	abi_long f_bfree;
+	abi_long f_bavail;
+	abi_long f_files;
+	abi_long f_ffree;
+	target_fsid_t f_fsid;
+	abi_long f_namelen;
+	abi_long f_frsize;
+	abi_long f_spare[5];
+};
+#elif defined(TARGET_S390X)
+struct target_statfs {
+    int32_t  f_type;
+    int32_t  f_bsize;
+    abi_long f_blocks;
+    abi_long f_bfree;
+    abi_long f_bavail;
+    abi_long f_files;
+    abi_long f_ffree;
+    kernel_fsid_t f_fsid;
+    int32_t  f_namelen;
+    int32_t  f_frsize;
+    int32_t  f_spare[5];
+};
+
+struct target_statfs64 {
+    int32_t  f_type;
+    int32_t  f_bsize;
+    abi_long f_blocks;
+    abi_long f_bfree;
+    abi_long f_bavail;
+    abi_long f_files;
+    abi_long f_ffree;
+    kernel_fsid_t f_fsid;
+    int32_t  f_namelen;
+    int32_t  f_frsize;
+    int32_t  f_spare[5];
+};
+#else
+struct target_statfs {
+	uint32_t f_type;
+	uint32_t f_bsize;
+	uint32_t f_blocks;
+	uint32_t f_bfree;
+	uint32_t f_bavail;
+	uint32_t f_files;
+	uint32_t f_ffree;
+	target_fsid_t f_fsid;
+	uint32_t f_namelen;
+	uint32_t f_frsize;
+	uint32_t f_spare[5];
+};
+
+struct target_statfs64 {
+	uint32_t f_type;
+	uint32_t f_bsize;
+	uint64_t f_blocks;
+	uint64_t f_bfree;
+	uint64_t f_bavail;
+	uint64_t f_files;
+	uint64_t f_ffree;
+	target_fsid_t f_fsid;
+        uint32_t f_namelen;
+	uint32_t f_frsize;
+	uint32_t f_spare[5];
+};
+#endif
+
+
+#define TARGET_F_DUPFD         0       /* dup */
+#define TARGET_F_GETFD         1       /* get close_on_exec */
+#define TARGET_F_SETFD         2       /* set/clear close_on_exec */
+#define TARGET_F_GETFL         3       /* get file->f_flags */
+#define TARGET_F_SETFL         4       /* set file->f_flags */
+
+#if defined(TARGET_ALPHA)
+#define TARGET_F_GETLK         7
+#define TARGET_F_SETLK         8
+#define TARGET_F_SETLKW        9
+#define TARGET_F_SETOWN        5       /*  for sockets. */
+#define TARGET_F_GETOWN        6       /*  for sockets. */
+#elif defined(TARGET_MIPS)
+#define TARGET_F_GETLK         14
+#define TARGET_F_SETLK         6
+#define TARGET_F_SETLKW        7
+#define TARGET_F_SETOWN        24       /*  for sockets. */
+#define TARGET_F_GETOWN        25       /*  for sockets. */
+#else
+#define TARGET_F_GETLK         5
+#define TARGET_F_SETLK         6
+#define TARGET_F_SETLKW        7
+#define TARGET_F_SETOWN        8       /*  for sockets. */
+#define TARGET_F_GETOWN        9       /*  for sockets. */
+#endif
+
+#define TARGET_F_SETSIG        10      /*  for sockets. */
+#define TARGET_F_GETSIG        11      /*  for sockets. */
+
+#if defined(TARGET_MIPS)
+#define TARGET_F_GETLK64       33      /*  using 'struct flock64' */
+#define TARGET_F_SETLK64       34
+#define TARGET_F_SETLKW64      35
+#else
+#define TARGET_F_GETLK64       12      /*  using 'struct flock64' */
+#define TARGET_F_SETLK64       13
+#define TARGET_F_SETLKW64      14
+#endif
+
+#define TARGET_F_LINUX_SPECIFIC_BASE 1024
+#define TARGET_F_SETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 0)
+#define TARGET_F_GETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 1)
+#define TARGET_F_DUPFD_CLOEXEC (TARGET_F_LINUX_SPECIFIC_BASE + 6)
+#define TARGET_F_NOTIFY  (TARGET_F_LINUX_SPECIFIC_BASE+2)
+
+#if defined (TARGET_ARM)
+#define TARGET_O_ACCMODE          0003
+#define TARGET_O_RDONLY             00
+#define TARGET_O_WRONLY             01
+#define TARGET_O_RDWR               02
+#define TARGET_O_CREAT            0100 /* not fcntl */
+#define TARGET_O_EXCL             0200 /* not fcntl */
+#define TARGET_O_NOCTTY           0400 /* not fcntl */
+#define TARGET_O_TRUNC           01000 /* not fcntl */
+#define TARGET_O_APPEND          02000
+#define TARGET_O_NONBLOCK        04000
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
+#define TARGET_O_SYNC           010000
+#define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECTORY      040000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0100000 /* don't follow links */
+#define TARGET_O_DIRECT        0200000 /* direct disk access hint */
+#define TARGET_O_LARGEFILE     0400000
+#elif defined (TARGET_PPC)
+#define TARGET_O_ACCMODE          0003
+#define TARGET_O_RDONLY             00
+#define TARGET_O_WRONLY             01
+#define TARGET_O_RDWR               02
+#define TARGET_O_CREAT            0100 /* not fcntl */
+#define TARGET_O_EXCL             0200 /* not fcntl */
+#define TARGET_O_NOCTTY           0400 /* not fcntl */
+#define TARGET_O_TRUNC           01000 /* not fcntl */
+#define TARGET_O_APPEND          02000
+#define TARGET_O_NONBLOCK        04000
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
+#define TARGET_O_SYNC           010000
+#define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECTORY      040000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0100000 /* don't follow links */
+#define TARGET_O_LARGEFILE     0200000
+#define TARGET_O_DIRECT        0400000 /* direct disk access hint */
+#elif defined (TARGET_MICROBLAZE)
+#define TARGET_O_ACCMODE          0003
+#define TARGET_O_RDONLY             00
+#define TARGET_O_WRONLY             01
+#define TARGET_O_RDWR               02
+#define TARGET_O_CREAT            0100 /* not fcntl */
+#define TARGET_O_EXCL             0200 /* not fcntl */
+#define TARGET_O_NOCTTY           0400 /* not fcntl */
+#define TARGET_O_TRUNC           01000 /* not fcntl */
+#define TARGET_O_APPEND          02000
+#define TARGET_O_NONBLOCK        04000
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
+#define TARGET_O_SYNC           010000
+#define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECTORY      040000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0100000 /* don't follow links */
+#define TARGET_O_LARGEFILE     0200000
+#define TARGET_O_DIRECT        0400000 /* direct disk access hint */
+#elif defined (TARGET_SPARC)
+#define TARGET_O_RDONLY        0x0000
+#define TARGET_O_WRONLY        0x0001
+#define TARGET_O_RDWR          0x0002
+#define TARGET_O_ACCMODE       0x0003
+#define TARGET_O_APPEND        0x0008
+#define TARGET_FASYNC          0x0040  /* fcntl, for BSD compatibility */
+#define TARGET_O_CREAT         0x0200  /* not fcntl */
+#define TARGET_O_TRUNC         0x0400  /* not fcntl */
+#define TARGET_O_EXCL          0x0800  /* not fcntl */
+#define TARGET_O_SYNC          0x2000
+#define TARGET_O_NONBLOCK      0x4000
+#define TARGET_O_NDELAY        (0x0004 | TARGET_O_NONBLOCK)
+#define TARGET_O_NOCTTY        0x8000  /* not fcntl */
+#define TARGET_O_DIRECTORY     0x10000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0x20000 /* don't follow links */
+#define TARGET_O_LARGEFILE     0x40000
+#define TARGET_O_DIRECT        0x100000 /* direct disk access hint */
+#elif defined(TARGET_MIPS)
+#define TARGET_O_ACCMODE	0x0003
+#define TARGET_O_RDONLY	0x0000
+#define TARGET_O_WRONLY	0x0001
+#define TARGET_O_RDWR		0x0002
+#define TARGET_O_APPEND	0x0008
+#define TARGET_O_SYNC		0x0010
+#define TARGET_O_NONBLOCK	0x0080
+#define TARGET_O_CREAT         0x0100	/* not fcntl */
+#define TARGET_O_TRUNC		0x0200	/* not fcntl */
+#define TARGET_O_EXCL		0x0400	/* not fcntl */
+#define TARGET_O_NOCTTY	0x0800	/* not fcntl */
+#define TARGET_FASYNC		0x1000	/* fcntl, for BSD compatibility */
+#define TARGET_O_LARGEFILE	0x2000	/* allow large file opens */
+#define TARGET_O_DIRECT	0x8000	/* direct disk access hint */
+#define TARGET_O_DIRECTORY	0x10000	/* must be a directory */
+#define TARGET_O_NOFOLLOW	0x20000	/* don't follow links */
+#define TARGET_O_NOATIME	0x40000
+#define TARGET_O_NDELAY	TARGET_O_NONBLOCK
+#elif defined(TARGET_ALPHA)
+#define TARGET_O_ACCMODE	0x0003
+#define TARGET_O_RDONLY	0x0000
+#define TARGET_O_WRONLY	0x0001
+#define TARGET_O_RDWR		0x0002
+#define TARGET_O_APPEND	0x0008
+#define TARGET_O_SYNC		0x4000
+#define TARGET_O_NONBLOCK	0x0004
+#define TARGET_O_CREAT         0x0200	/* not fcntl */
+#define TARGET_O_TRUNC		0x0400	/* not fcntl */
+#define TARGET_O_EXCL		0x0800	/* not fcntl */
+#define TARGET_O_NOCTTY	0x1000	/* not fcntl */
+#define TARGET_FASYNC		0x2000	/* fcntl, for BSD compatibility */
+#define TARGET_O_LARGEFILE	0x0000	/* not necessary, always 64-bit */
+#define TARGET_O_DIRECT	0x80000	/* direct disk access hint */
+#define TARGET_O_DIRECTORY	0x8000	/* must be a directory */
+#define TARGET_O_NOFOLLOW	0x10000	/* don't follow links */
+#define TARGET_O_NOATIME	0x100000
+#define TARGET_O_NDELAY	TARGET_O_NONBLOCK
+#else
+#define TARGET_O_ACCMODE          0003
+#define TARGET_O_RDONLY             00
+#define TARGET_O_WRONLY             01
+#define TARGET_O_RDWR               02
+#define TARGET_O_CREAT            0100 /* not fcntl */
+#define TARGET_O_EXCL             0200 /* not fcntl */
+#define TARGET_O_NOCTTY           0400 /* not fcntl */
+#define TARGET_O_TRUNC           01000 /* not fcntl */
+#define TARGET_O_APPEND          02000
+#define TARGET_O_NONBLOCK        04000
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
+#define TARGET_O_SYNC           010000
+#define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECT         040000 /* direct disk access hint */
+#define TARGET_O_LARGEFILE     0100000
+#define TARGET_O_DIRECTORY     0200000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0400000 /* don't follow links */
+#endif
+
+struct target_flock {
+	short l_type;
+	short l_whence;
+	abi_ulong l_start;
+	abi_ulong l_len;
+	int l_pid;
+};
+
+struct target_flock64 {
+	short  l_type;
+	short  l_whence;
+#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined (TARGET_MICROBLAZE)
+        int __pad;
+#endif
+	unsigned long long l_start;
+	unsigned long long l_len;
+	int  l_pid;
+}__attribute__((packed));
+
+#ifdef TARGET_ARM
+struct target_eabi_flock64 {
+	short  l_type;
+	short  l_whence;
+        int __pad;
+	unsigned long long l_start;
+	unsigned long long l_len;
+	int  l_pid;
+}__attribute__((packed));
+#endif
+
+/* soundcard defines */
+/* XXX: convert them all to arch indepedent entries */
+#define TARGET_SNDCTL_COPR_HALT           TARGET_IOWR('C',  7, int);
+#define TARGET_SNDCTL_COPR_LOAD           0xcfb04301
+#define TARGET_SNDCTL_COPR_RCODE          0xc0144303
+#define TARGET_SNDCTL_COPR_RCVMSG         0x8fa44309
+#define TARGET_SNDCTL_COPR_RDATA          0xc0144302
+#define TARGET_SNDCTL_COPR_RESET          0x00004300
+#define TARGET_SNDCTL_COPR_RUN            0xc0144306
+#define TARGET_SNDCTL_COPR_SENDMSG        0xcfa44308
+#define TARGET_SNDCTL_COPR_WCODE          0x40144305
+#define TARGET_SNDCTL_COPR_WDATA          0x40144304
+#define TARGET_SNDCTL_DSP_RESET           TARGET_IO('P', 0)
+#define TARGET_SNDCTL_DSP_SYNC            TARGET_IO('P', 1)
+#define TARGET_SNDCTL_DSP_SPEED           TARGET_IOWR('P', 2, int)
+#define TARGET_SNDCTL_DSP_STEREO          TARGET_IOWR('P', 3, int)
+#define TARGET_SNDCTL_DSP_GETBLKSIZE      TARGET_IOWR('P', 4, int)
+#define TARGET_SNDCTL_DSP_SETFMT          TARGET_IOWR('P', 5, int)
+#define TARGET_SNDCTL_DSP_CHANNELS        TARGET_IOWR('P', 6, int)
+#define TARGET_SOUND_PCM_WRITE_FILTER     TARGET_IOWR('P', 7, int)
+#define TARGET_SNDCTL_DSP_POST            TARGET_IO('P', 8)
+#define TARGET_SNDCTL_DSP_SUBDIVIDE       TARGET_IOWR('P', 9, int)
+#define TARGET_SNDCTL_DSP_SETFRAGMENT     TARGET_IOWR('P',10, int)
+#define TARGET_SNDCTL_DSP_GETFMTS         TARGET_IOR('P', 11, int)
+#define TARGET_SNDCTL_DSP_GETOSPACE       TARGET_IORU('P',12)
+#define TARGET_SNDCTL_DSP_GETISPACE       TARGET_IORU('P',13)
+#define TARGET_SNDCTL_DSP_GETCAPS         TARGET_IOR('P', 15, int)
+#define TARGET_SNDCTL_DSP_GETTRIGGER      TARGET_IOR('P',16, int)
+#define TARGET_SNDCTL_DSP_GETIPTR         TARGET_IORU('P',17)
+#define TARGET_SNDCTL_DSP_GETOPTR         TARGET_IORU('P',18)
+#define TARGET_SNDCTL_DSP_MAPINBUF        0x80085013
+#define TARGET_SNDCTL_DSP_MAPOUTBUF       0x80085014
+#define TARGET_SNDCTL_DSP_NONBLOCK        0x0000500e
+#define TARGET_SNDCTL_DSP_SAMPLESIZE      0xc0045005
+#define TARGET_SNDCTL_DSP_SETDUPLEX       0x00005016
+#define TARGET_SNDCTL_DSP_SETSYNCRO       0x00005015
+#define TARGET_SNDCTL_DSP_SETTRIGGER      0x40045010
+#define TARGET_SNDCTL_FM_4OP_ENABLE       0x4004510f
+#define TARGET_SNDCTL_FM_LOAD_INSTR       0x40285107
+#define TARGET_SNDCTL_MIDI_INFO           0xc074510c
+#define TARGET_SNDCTL_MIDI_MPUCMD         0xc0216d02
+#define TARGET_SNDCTL_MIDI_MPUMODE        0xc0046d01
+#define TARGET_SNDCTL_MIDI_PRETIME        0xc0046d00
+#define TARGET_SNDCTL_PMGR_ACCESS         0xcfb85110
+#define TARGET_SNDCTL_PMGR_IFACE          0xcfb85001
+#define TARGET_SNDCTL_SEQ_CTRLRATE        0xc0045103
+#define TARGET_SNDCTL_SEQ_GETINCOUNT      0x80045105
+#define TARGET_SNDCTL_SEQ_GETOUTCOUNT     0x80045104
+#define TARGET_SNDCTL_SEQ_NRMIDIS         0x8004510b
+#define TARGET_SNDCTL_SEQ_NRSYNTHS        0x8004510a
+#define TARGET_SNDCTL_SEQ_OUTOFBAND       0x40085112
+#define TARGET_SNDCTL_SEQ_PANIC           0x00005111
+#define TARGET_SNDCTL_SEQ_PERCMODE        0x40045106
+#define TARGET_SNDCTL_SEQ_RESET           0x00005100
+#define TARGET_SNDCTL_SEQ_RESETSAMPLES    0x40045109
+#define TARGET_SNDCTL_SEQ_SYNC            0x00005101
+#define TARGET_SNDCTL_SEQ_TESTMIDI        0x40045108
+#define TARGET_SNDCTL_SEQ_THRESHOLD       0x4004510d
+#define TARGET_SNDCTL_SEQ_TRESHOLD        0x4004510d
+#define TARGET_SNDCTL_SYNTH_INFO          0xc08c5102
+#define TARGET_SNDCTL_SYNTH_MEMAVL        0xc004510e
+#define TARGET_SNDCTL_TMR_CONTINUE        0x00005404
+#define TARGET_SNDCTL_TMR_METRONOME       0x40045407
+#define TARGET_SNDCTL_TMR_SELECT          0x40045408
+#define TARGET_SNDCTL_TMR_SOURCE          0xc0045406
+#define TARGET_SNDCTL_TMR_START           0x00005402
+#define TARGET_SNDCTL_TMR_STOP            0x00005403
+#define TARGET_SNDCTL_TMR_TEMPO           0xc0045405
+#define TARGET_SNDCTL_TMR_TIMEBASE        0xc0045401
+#define TARGET_SOUND_PCM_READ_RATE        0x80045002
+#define TARGET_SOUND_PCM_READ_CHANNELS    0x80045006
+#define TARGET_SOUND_PCM_READ_BITS        0x80045005
+#define TARGET_SOUND_PCM_READ_FILTER      0x80045007
+#define TARGET_SOUND_MIXER_INFO           TARGET_IOR ('M', 101, mixer_info)
+#define TARGET_SOUND_MIXER_ACCESS         0xc0804d66
+#define TARGET_SOUND_MIXER_PRIVATE1       TARGET_IOWR('M', 111, int)
+#define TARGET_SOUND_MIXER_PRIVATE2       TARGET_IOWR('M', 112, int)
+#define TARGET_SOUND_MIXER_PRIVATE3       TARGET_IOWR('M', 113, int)
+#define TARGET_SOUND_MIXER_PRIVATE4       TARGET_IOWR('M', 114, int)
+#define TARGET_SOUND_MIXER_PRIVATE5       TARGET_IOWR('M', 115, int)
+
+#define TARGET_MIXER_READ(dev)	TARGET_IOR('M', dev, int)
+
+#define TARGET_SOUND_MIXER_READ_VOLUME		TARGET_MIXER_READ(SOUND_MIXER_VOLUME)
+#define TARGET_SOUND_MIXER_READ_BASS		TARGET_MIXER_READ(SOUND_MIXER_BASS)
+#define TARGET_SOUND_MIXER_READ_TREBLE		TARGET_MIXER_READ(SOUND_MIXER_TREBLE)
+#define TARGET_SOUND_MIXER_READ_SYNTH		TARGET_MIXER_READ(SOUND_MIXER_SYNTH)
+#define TARGET_SOUND_MIXER_READ_PCM		TARGET_MIXER_READ(SOUND_MIXER_PCM)
+#define TARGET_SOUND_MIXER_READ_SPEAKER	        TARGET_MIXER_READ(SOUND_MIXER_SPEAKER)
+#define TARGET_SOUND_MIXER_READ_LINE		TARGET_MIXER_READ(SOUND_MIXER_LINE)
+#define TARGET_SOUND_MIXER_READ_MIC		TARGET_MIXER_READ(SOUND_MIXER_MIC)
+#define TARGET_SOUND_MIXER_READ_CD		TARGET_MIXER_READ(SOUND_MIXER_CD)
+#define TARGET_SOUND_MIXER_READ_IMIX		TARGET_MIXER_READ(SOUND_MIXER_IMIX)
+#define TARGET_SOUND_MIXER_READ_ALTPCM		TARGET_MIXER_READ(SOUND_MIXER_ALTPCM)
+#define TARGET_SOUND_MIXER_READ_RECLEV		TARGET_MIXER_READ(SOUND_MIXER_RECLEV)
+#define TARGET_SOUND_MIXER_READ_IGAIN		TARGET_MIXER_READ(SOUND_MIXER_IGAIN)
+#define TARGET_SOUND_MIXER_READ_OGAIN		TARGET_MIXER_READ(SOUND_MIXER_OGAIN)
+#define TARGET_SOUND_MIXER_READ_LINE1		TARGET_MIXER_READ(SOUND_MIXER_LINE1)
+#define TARGET_SOUND_MIXER_READ_LINE2		TARGET_MIXER_READ(SOUND_MIXER_LINE2)
+#define TARGET_SOUND_MIXER_READ_LINE3		TARGET_MIXER_READ(SOUND_MIXER_LINE3)
+
+/* Obsolete macros */
+#define TARGET_SOUND_MIXER_READ_MUTE		TARGET_MIXER_READ(SOUND_MIXER_MUTE)
+#define TARGET_SOUND_MIXER_READ_ENHANCE	        TARGET_MIXER_READ(SOUND_MIXER_ENHANCE)
+#define TARGET_SOUND_MIXER_READ_LOUD		TARGET_MIXER_READ(SOUND_MIXER_LOUD)
+
+#define TARGET_SOUND_MIXER_READ_RECSRC		TARGET_MIXER_READ(SOUND_MIXER_RECSRC)
+#define TARGET_SOUND_MIXER_READ_DEVMASK	        TARGET_MIXER_READ(SOUND_MIXER_DEVMASK)
+#define TARGET_SOUND_MIXER_READ_RECMASK	        TARGET_MIXER_READ(SOUND_MIXER_RECMASK)
+#define TARGET_SOUND_MIXER_READ_STEREODEVS	TARGET_MIXER_READ(SOUND_MIXER_STEREODEVS)
+#define TARGET_SOUND_MIXER_READ_CAPS		TARGET_MIXER_READ(SOUND_MIXER_CAPS)
+
+#define TARGET_MIXER_WRITE(dev)		TARGET_IOWR('M', dev, int)
+
+#define TARGET_SOUND_MIXER_WRITE_VOLUME	TARGET_MIXER_WRITE(SOUND_MIXER_VOLUME)
+#define TARGET_SOUND_MIXER_WRITE_BASS		TARGET_MIXER_WRITE(SOUND_MIXER_BASS)
+#define TARGET_SOUND_MIXER_WRITE_TREBLE	TARGET_MIXER_WRITE(SOUND_MIXER_TREBLE)
+#define TARGET_SOUND_MIXER_WRITE_SYNTH		TARGET_MIXER_WRITE(SOUND_MIXER_SYNTH)
+#define TARGET_SOUND_MIXER_WRITE_PCM		TARGET_MIXER_WRITE(SOUND_MIXER_PCM)
+#define TARGET_SOUND_MIXER_WRITE_SPEAKER	TARGET_MIXER_WRITE(SOUND_MIXER_SPEAKER)
+#define TARGET_SOUND_MIXER_WRITE_LINE		TARGET_MIXER_WRITE(SOUND_MIXER_LINE)
+#define TARGET_SOUND_MIXER_WRITE_MIC		TARGET_MIXER_WRITE(SOUND_MIXER_MIC)
+#define TARGET_SOUND_MIXER_WRITE_CD		TARGET_MIXER_WRITE(SOUND_MIXER_CD)
+#define TARGET_SOUND_MIXER_WRITE_IMIX		TARGET_MIXER_WRITE(SOUND_MIXER_IMIX)
+#define TARGET_SOUND_MIXER_WRITE_ALTPCM	TARGET_MIXER_WRITE(SOUND_MIXER_ALTPCM)
+#define TARGET_SOUND_MIXER_WRITE_RECLEV	TARGET_MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define TARGET_SOUND_MIXER_WRITE_IGAIN		TARGET_MIXER_WRITE(SOUND_MIXER_IGAIN)
+#define TARGET_SOUND_MIXER_WRITE_OGAIN		TARGET_MIXER_WRITE(SOUND_MIXER_OGAIN)
+#define TARGET_SOUND_MIXER_WRITE_LINE1		TARGET_MIXER_WRITE(SOUND_MIXER_LINE1)
+#define TARGET_SOUND_MIXER_WRITE_LINE2		TARGET_MIXER_WRITE(SOUND_MIXER_LINE2)
+#define TARGET_SOUND_MIXER_WRITE_LINE3		TARGET_MIXER_WRITE(SOUND_MIXER_LINE3)
+
+/* Obsolete macros */
+#define TARGET_SOUND_MIXER_WRITE_MUTE		TARGET_MIXER_WRITE(SOUND_MIXER_MUTE)
+#define TARGET_SOUND_MIXER_WRITE_ENHANCE	TARGET_MIXER_WRITE(SOUND_MIXER_ENHANCE)
+#define TARGET_SOUND_MIXER_WRITE_LOUD		TARGET_MIXER_WRITE(SOUND_MIXER_LOUD)
+
+#define TARGET_SOUND_MIXER_WRITE_RECSRC	TARGET_MIXER_WRITE(SOUND_MIXER_RECSRC)
+
+/* vfat ioctls */
+#define TARGET_VFAT_IOCTL_READDIR_BOTH    TARGET_IORU('r', 1)
+#define TARGET_VFAT_IOCTL_READDIR_SHORT   TARGET_IORU('r', 2)
+
+#define TARGET_MTIOCTOP        TARGET_IOW('m', 1, struct mtop)
+#define TARGET_MTIOCGET        TARGET_IOR('m', 2, struct mtget)
+#define TARGET_MTIOCPOS        TARGET_IOR('m', 3, struct mtpos)
+
+struct target_sysinfo {
+    abi_long uptime;                /* Seconds since boot */
+    abi_ulong loads[3];             /* 1, 5, and 15 minute load averages */
+    abi_ulong totalram;             /* Total usable main memory size */
+    abi_ulong freeram;              /* Available memory size */
+    abi_ulong sharedram;            /* Amount of shared memory */
+    abi_ulong bufferram;            /* Memory used by buffers */
+    abi_ulong totalswap;            /* Total swap space size */
+    abi_ulong freeswap;             /* swap space still available */
+    unsigned short procs;           /* Number of current processes */
+    unsigned short pad;             /* explicit padding for m68k */
+    abi_ulong totalhigh;            /* Total high memory size */
+    abi_ulong freehigh;             /* Available high memory size */
+    unsigned int mem_unit;          /* Memory unit size in bytes */
+    char _f[20-2*sizeof(abi_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
+};
+
+struct linux_dirent {
+    long            d_ino;
+    unsigned long   d_off;
+    unsigned short  d_reclen;
+    char            d_name[256]; /* We must not include limits.h! */
+};
+
+struct linux_dirent64 {
+    uint64_t        d_ino;
+    int64_t         d_off;
+    unsigned short  d_reclen;
+    unsigned char   d_type;
+    char            d_name[256];
+};
+
+struct target_mq_attr {
+    abi_long mq_flags;
+    abi_long mq_maxmsg;
+    abi_long mq_msgsize;
+    abi_long mq_curmsgs;
+};
+
+#include "socket.h"
+
+#include "errno_defs.h"
+
+#define FUTEX_WAIT              0
+#define FUTEX_WAKE              1
+#define FUTEX_FD                2
+#define FUTEX_REQUEUE           3
+#define FUTEX_CMP_REQUEUE       4
+#define FUTEX_WAKE_OP           5
+#define FUTEX_LOCK_PI           6
+#define FUTEX_UNLOCK_PI         7
+#define FUTEX_TRYLOCK_PI        8
+#define FUTEX_WAIT_BITSET       9
+#define FUTEX_WAKE_BITSET       10
+
+#define FUTEX_PRIVATE_FLAG      128
+#define FUTEX_CLOCK_REALTIME    256
+#define FUTEX_CMD_MASK          ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+
+#ifdef CONFIG_EPOLL
+typedef union target_epoll_data {
+    abi_ulong ptr;
+    abi_ulong fd;
+    uint32_t u32;
+    uint64_t u64;
+} target_epoll_data_t;
+
+struct target_epoll_event {
+    uint32_t events;
+    target_epoll_data_t data;
+};
+#endif
+struct target_rlimit64 {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
diff --git a/qemu-0.15.x/linux-user/syscall_types.h b/qemu-0.15.x/linux-user/syscall_types.h
new file mode 100644
index 0000000..c370125
--- /dev/null
+++ b/qemu-0.15.x/linux-user/syscall_types.h
@@ -0,0 +1,203 @@
+STRUCT_SPECIAL(termios)
+
+STRUCT(winsize,
+       TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
+
+STRUCT(serial_multiport_struct,
+       TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR,
+       TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT,
+       MK_ARRAY(TYPE_INT, 32))
+
+STRUCT(serial_icounter_struct,
+       TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_INT, 16))
+
+STRUCT(sockaddr,
+       TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14))
+
+STRUCT(rtentry,
+       TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr),
+       TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID,
+       TYPE_ULONG, TYPE_ULONG, TYPE_SHORT)
+
+STRUCT(ifmap,
+       TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR,
+       /* Spare 3 bytes */
+       TYPE_CHAR, TYPE_CHAR, TYPE_CHAR)
+
+/* The *_ifreq_list arrays deal with the fact that struct ifreq has unions */
+
+STRUCT(sockaddr_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr))
+
+STRUCT(short_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT)
+
+STRUCT(int_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT)
+
+STRUCT(ifmap_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_ifmap))
+
+STRUCT(char_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ),
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ))
+
+STRUCT(ptr_ifreq,
+       MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID)
+
+STRUCT(ifconf,
+       TYPE_INT, TYPE_PTRVOID)
+
+STRUCT(arpreq,
+       MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr),
+       MK_ARRAY(TYPE_CHAR, 16))
+
+STRUCT(arpreq_old,
+       MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr))
+
+STRUCT(cdrom_read_audio,
+       TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_PTRVOID,
+       TYPE_NULL)
+
+STRUCT(hd_geometry,
+       TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
+
+STRUCT(dirent,
+       TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
+
+STRUCT(kbentry,
+       TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
+
+STRUCT(kbsentry,
+       TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 512))
+
+STRUCT(audio_buf_info,
+       TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
+
+STRUCT(count_info,
+       TYPE_INT, TYPE_INT, TYPE_INT)
+
+STRUCT(mixer_info,
+       MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
+
+/* loop device ioctls */
+STRUCT(loop_info,
+       TYPE_INT,                 /* lo_number */
+       TYPE_SHORT,               /* lo_device */
+       TYPE_ULONG,               /* lo_inode */
+       TYPE_SHORT,               /* lo_rdevice */
+       TYPE_INT,                 /* lo_offset */
+       TYPE_INT,                 /* lo_encrypt_type */
+       TYPE_INT,                 /* lo_encrypt_key_size */
+       TYPE_INT,                 /* lo_flags */
+       MK_ARRAY(TYPE_CHAR, 64),  /* lo_name */
+       MK_ARRAY(TYPE_CHAR, 32),  /* lo_encrypt_key */
+       MK_ARRAY(TYPE_ULONG, 2),  /* lo_init */
+       MK_ARRAY(TYPE_CHAR, 4))   /* reserved */
+
+STRUCT(loop_info64,
+       TYPE_ULONGLONG,           /* lo_device */
+       TYPE_ULONGLONG,           /* lo_inode */
+       TYPE_ULONGLONG,           /* lo_rdevice */
+       TYPE_ULONGLONG,           /* lo_offset */
+       TYPE_ULONG,               /* lo_number */
+       TYPE_ULONG,               /* lo_encrypt_type */
+       TYPE_ULONG,               /* lo_encrypt_key_size */
+       TYPE_ULONG,               /* lo_flags */
+       MK_ARRAY(TYPE_CHAR, 64),  /* lo_name */
+       MK_ARRAY(TYPE_CHAR, 64),  /* lo_crypt_name */
+       MK_ARRAY(TYPE_CHAR, 32),  /* lo_encrypt_key */
+       MK_ARRAY(TYPE_ULONGLONG, 2))  /* lo_init */
+
+/* mag tape ioctls */
+STRUCT(mtop, TYPE_SHORT, TYPE_INT)
+STRUCT(mtget, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG, TYPE_LONG,
+       TYPE_INT, TYPE_INT)
+STRUCT(mtpos, TYPE_LONG)
+
+STRUCT(fb_fix_screeninfo,
+       MK_ARRAY(TYPE_CHAR, 16), /* id */
+       TYPE_ULONG, /* smem_start */
+       TYPE_INT, /* smem_len */
+       TYPE_INT, /* type */
+       TYPE_INT, /* type_aux */
+       TYPE_INT, /* visual */
+       TYPE_SHORT, /* xpanstep */
+       TYPE_SHORT, /* ypanstep */
+       TYPE_SHORT, /* ywrapstep */
+       TYPE_INT, /* line_length */
+       TYPE_ULONG, /* mmio_start */
+       TYPE_INT, /* mmio_len */
+       TYPE_INT, /* accel */
+       MK_ARRAY(TYPE_CHAR, 3)) /* reserved */
+
+STRUCT(fb_var_screeninfo,
+       TYPE_INT, /* xres */
+       TYPE_INT, /* yres */
+       TYPE_INT, /* xres_virtual */
+       TYPE_INT, /* yres_virtual */
+       TYPE_INT, /* xoffset */
+       TYPE_INT, /* yoffset */
+       TYPE_INT, /* bits_per_pixel */
+       TYPE_INT, /* grayscale */
+       MK_ARRAY(TYPE_INT, 3), /* red */
+       MK_ARRAY(TYPE_INT, 3), /* green */
+       MK_ARRAY(TYPE_INT, 3), /* blue */
+       MK_ARRAY(TYPE_INT, 3), /* transp */
+       TYPE_INT, /* nonstd */
+       TYPE_INT, /* activate */
+       TYPE_INT, /* height */
+       TYPE_INT, /* width */
+       TYPE_INT, /* accel_flags */
+       TYPE_INT, /* pixclock */
+       TYPE_INT, /* left_margin */
+       TYPE_INT, /* right_margin */
+       TYPE_INT, /* upper_margin */
+       TYPE_INT, /* lower_margin */
+       TYPE_INT, /* hsync_len */
+       TYPE_INT, /* vsync_len */
+       TYPE_INT, /* sync */
+       TYPE_INT, /* vmode */
+       TYPE_INT, /* rotate */
+       MK_ARRAY(TYPE_INT, 5)) /* reserved */
+
+STRUCT(fb_cmap,
+       TYPE_INT, /* start  */
+       TYPE_INT, /* len    */
+       TYPE_PTRVOID, /* red    */
+       TYPE_PTRVOID, /* green  */
+       TYPE_PTRVOID, /* blue   */
+       TYPE_PTRVOID) /* transp */
+
+STRUCT(fb_con2fbmap,
+       TYPE_INT, /* console     */
+       TYPE_INT) /* framebuffer */
+
+
+STRUCT(vt_stat,
+       TYPE_SHORT, /* v_active */
+       TYPE_SHORT, /* v_signal */
+       TYPE_SHORT) /* v_state */
+
+STRUCT(vt_mode,
+       TYPE_CHAR,  /* mode   */
+       TYPE_CHAR,  /* waitv  */
+       TYPE_SHORT, /* relsig */
+       TYPE_SHORT, /* acqsig */
+       TYPE_SHORT) /* frsig  */
+
+STRUCT(fiemap_extent,
+       TYPE_ULONGLONG, /* fe_logical */
+       TYPE_ULONGLONG, /* fe_physical */
+       TYPE_ULONGLONG, /* fe_length */
+       MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */
+       TYPE_INT, /* fe_flags */
+       MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */
+
+STRUCT(fiemap,
+       TYPE_ULONGLONG, /* fm_start */
+       TYPE_ULONGLONG, /* fm_length */
+       TYPE_INT, /* fm_flags */
+       TYPE_INT, /* fm_mapped_extents */
+       TYPE_INT, /* fm_extent_count */
+       TYPE_INT) /* fm_reserved */
diff --git a/qemu-0.15.x/linux-user/target_flat.h b/qemu-0.15.x/linux-user/target_flat.h
new file mode 100644
index 0000000..0ba6bdd
--- /dev/null
+++ b/qemu-0.15.x/linux-user/target_flat.h
@@ -0,0 +1,10 @@
+/* If your arch needs to do custom stuff, create your own target_flat.h
+ * header file in linux-user/<your arch>/
+ */
+#define flat_argvp_envp_on_stack()                           1
+#define flat_reloc_valid(reloc, size)                        ((reloc) <= (size))
+#define flat_old_ram_flag(flag)                              (flag)
+#define flat_get_relocate_addr(relval)                       (relval)
+#define flat_get_addr_from_rp(rp, relval, flags, persistent) (rp)
+#define flat_set_persistent(relval, persistent)              (*persistent)
+#define flat_put_addr_at_rp(rp, addr, relval)                put_user_ual(addr, rp)
diff --git a/qemu-0.15.x/linux-user/uaccess.c b/qemu-0.15.x/linux-user/uaccess.c
new file mode 100644
index 0000000..a4d108c
--- /dev/null
+++ b/qemu-0.15.x/linux-user/uaccess.c
@@ -0,0 +1,65 @@
+/* User memory access */
+#include <stdio.h>
+#include <string.h>
+
+#include "qemu.h"
+
+/* copy_from_user() and copy_to_user() are usually used to copy data
+ * buffers between the target and host.  These internally perform
+ * locking/unlocking of the memory.
+ */
+abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
+{
+    abi_long ret = 0;
+    void *ghptr;
+
+    if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
+        memcpy(hptr, ghptr, len);
+        unlock_user(ghptr, gaddr, 0);
+    } else
+        ret = -TARGET_EFAULT;
+
+    return ret;
+}
+
+
+abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
+{
+    abi_long ret = 0;
+    void *ghptr;
+
+    if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
+        memcpy(ghptr, hptr, len);
+	unlock_user(ghptr, gaddr, len);
+    } else
+        ret = -TARGET_EFAULT;
+
+    return ret;
+}
+
+/* Return the length of a string in target memory or -TARGET_EFAULT if
+   access error  */
+abi_long target_strlen(abi_ulong guest_addr1)
+{
+    uint8_t *ptr;
+    abi_ulong guest_addr;
+    int max_len, len;
+
+    guest_addr = guest_addr1;
+    for(;;) {
+        max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK);
+        ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
+        if (!ptr)
+            return -TARGET_EFAULT;
+        len = qemu_strnlen((const char *)ptr, max_len);
+        unlock_user(ptr, guest_addr, 0);
+        guest_addr += len;
+        /* we don't allow wrapping or integer overflow */
+        if (guest_addr == 0 || 
+            (guest_addr - guest_addr1) > 0x7fffffff)
+            return -TARGET_EFAULT;
+        if (len != max_len)
+            break;
+    }
+    return guest_addr - guest_addr1;
+}
diff --git a/qemu-0.15.x/linux-user/unicore32/syscall.h b/qemu-0.15.x/linux-user/unicore32/syscall.h
new file mode 100644
index 0000000..010cdd8
--- /dev/null
+++ b/qemu-0.15.x/linux-user/unicore32/syscall.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __UC32_SYSCALL_H__
+#define __UC32_SYSCALL_H__
+struct target_pt_regs {
+    abi_ulong uregs[34];
+};
+
+#define UC32_REG_pc             uregs[31]
+#define UC32_REG_lr             uregs[30]
+#define UC32_REG_sp             uregs[29]
+#define UC32_REG_ip             uregs[28]
+#define UC32_REG_fp             uregs[27]
+#define UC32_REG_26             uregs[26]
+#define UC32_REG_25             uregs[25]
+#define UC32_REG_24             uregs[24]
+#define UC32_REG_23             uregs[23]
+#define UC32_REG_22             uregs[22]
+#define UC32_REG_21             uregs[21]
+#define UC32_REG_20             uregs[20]
+#define UC32_REG_19             uregs[19]
+#define UC32_REG_18             uregs[18]
+#define UC32_REG_17             uregs[17]
+#define UC32_REG_16             uregs[16]
+#define UC32_REG_15             uregs[15]
+#define UC32_REG_14             uregs[14]
+#define UC32_REG_13             uregs[13]
+#define UC32_REG_12             uregs[12]
+#define UC32_REG_11             uregs[11]
+#define UC32_REG_10             uregs[10]
+#define UC32_REG_09             uregs[9]
+#define UC32_REG_08             uregs[8]
+#define UC32_REG_07             uregs[7]
+#define UC32_REG_06             uregs[6]
+#define UC32_REG_05             uregs[5]
+#define UC32_REG_04             uregs[4]
+#define UC32_REG_03             uregs[3]
+#define UC32_REG_02             uregs[2]
+#define UC32_REG_01             uregs[1]
+#define UC32_REG_00             uregs[0]
+#define UC32_REG_asr            uregs[32]
+#define UC32_REG_ORIG_00        uregs[33]
+
+#define UC32_SYSCALL_BASE               0x900000
+#define UC32_SYSCALL_ARCH_BASE          0xf0000
+#define UC32_SYSCALL_NR_set_tls         (UC32_SYSCALL_ARCH_BASE + 5)
+
+#define UNAME_MACHINE "UniCore-II"
+
+#endif /* __UC32_SYSCALL_H__ */
diff --git a/qemu-0.15.x/linux-user/unicore32/syscall_nr.h b/qemu-0.15.x/linux-user/unicore32/syscall_nr.h
new file mode 100644
index 0000000..9c72d84
--- /dev/null
+++ b/qemu-0.15.x/linux-user/unicore32/syscall_nr.h
@@ -0,0 +1,371 @@
+/*
+ * This file contains the system call numbers for UniCore32 oldabi.
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#define TARGET_NR_restart_syscall               0
+#define TARGET_NR_exit                          1
+#define TARGET_NR_fork                          2
+#define TARGET_NR_read                          3
+#define TARGET_NR_write                         4
+#define TARGET_NR_open                          5
+#define TARGET_NR_close                         6
+#define TARGET_NR_waitpid                       7
+#define TARGET_NR_creat                         8
+#define TARGET_NR_link                          9
+#define TARGET_NR_unlink                        10
+#define TARGET_NR_execve                        11
+#define TARGET_NR_chdir                         12
+#define TARGET_NR_time                          13
+#define TARGET_NR_mknod                         14
+#define TARGET_NR_chmod                         15
+#define TARGET_NR_lchown                        16
+#define TARGET_NR_break                         17
+                                                /* 18 */
+#define TARGET_NR_lseek                         19
+#define TARGET_NR_getpid                        20
+#define TARGET_NR_mount                         21
+#define TARGET_NR_umount                        22
+#define TARGET_NR_setuid                        23
+#define TARGET_NR_getuid                        24
+#define TARGET_NR_stime                         25
+#define TARGET_NR_ptrace                        26
+#define TARGET_NR_alarm                         27
+                                                /* 28 */
+#define TARGET_NR_pause                         29
+#define TARGET_NR_utime                         30
+#define TARGET_NR_stty                          31
+#define TARGET_NR_gtty                          32
+#define TARGET_NR_access                        33
+#define TARGET_NR_nice                          34
+#define TARGET_NR_ftime                         35
+#define TARGET_NR_sync                          36
+#define TARGET_NR_kill                          37
+#define TARGET_NR_rename                        38
+#define TARGET_NR_mkdir                         39
+#define TARGET_NR_rmdir                         40
+#define TARGET_NR_dup                           41
+#define TARGET_NR_pipe                          42
+#define TARGET_NR_times                         43
+#define TARGET_NR_prof                          44
+#define TARGET_NR_brk                           45
+#define TARGET_NR_setgid                        46
+#define TARGET_NR_getgid                        47
+#define TARGET_NR_signal                        48
+#define TARGET_NR_geteuid                       49
+#define TARGET_NR_getegid                       50
+#define TARGET_NR_acct                          51
+#define TARGET_NR_umount2                       52
+#define TARGET_NR_lock                          53
+#define TARGET_NR_ioctl                         54
+#define TARGET_NR_fcntl                         55
+#define TARGET_NR_mpx                           56
+#define TARGET_NR_setpgid                       57
+#define TARGET_NR_ulimit                        58
+                                                /* 59 */
+#define TARGET_NR_umask                         60
+#define TARGET_NR_chroot                        61
+#define TARGET_NR_ustat                         62
+#define TARGET_NR_dup2                          63
+#define TARGET_NR_getppid                       64
+#define TARGET_NR_getpgrp                       65
+#define TARGET_NR_setsid                        66
+#define TARGET_NR_sigaction                     67
+#define TARGET_NR_sgetmask                      68
+#define TARGET_NR_ssetmask                      69
+#define TARGET_NR_setreuid                      70
+#define TARGET_NR_setregid                      71
+#define TARGET_NR_sigsuspend                    72
+#define TARGET_NR_sigpending                    73
+#define TARGET_NR_sethostname                   74
+#define TARGET_NR_setrlimit                     75
+#define TARGET_NR_getrlimit                     76
+#define TARGET_NR_getrusage                     77
+#define TARGET_NR_gettimeofday                  78
+#define TARGET_NR_settimeofday                  79
+#define TARGET_NR_getgroups                     80
+#define TARGET_NR_setgroups                     81
+#define TARGET_NR_select                        82
+#define TARGET_NR_symlink                       83
+                                                /* 84 */
+#define TARGET_NR_readlink                      85
+#define TARGET_NR_uselib                        86
+#define TARGET_NR_swapon                        87
+#define TARGET_NR_reboot                        88
+#define TARGET_NR_readdir                       89
+#define TARGET_NR_mmap                          90
+#define TARGET_NR_munmap                        91
+#define TARGET_NR_truncate                      92
+#define TARGET_NR_ftruncate                     93
+#define TARGET_NR_fchmod                        94
+#define TARGET_NR_fchown                        95
+#define TARGET_NR_getpriority                   96
+#define TARGET_NR_setpriority                   97
+#define TARGET_NR_profil                        98
+#define TARGET_NR_statfs                        99
+#define TARGET_NR_fstatfs                       100
+#define TARGET_NR_ioperm                        101
+#define TARGET_NR_socketcall                    102
+#define TARGET_NR_syslog                        103
+#define TARGET_NR_setitimer                     104
+#define TARGET_NR_getitimer                     105
+#define TARGET_NR_stat                          106
+#define TARGET_NR_lstat                         107
+#define TARGET_NR_fstat                         108
+                                                /* 109 */
+                                                /* 110 */
+#define TARGET_NR_vhangup                       111
+#define TARGET_NR_idle                          112
+#define TARGET_NR_syscall                       113
+#define TARGET_NR_wait4                         114
+#define TARGET_NR_swapoff                       115
+#define TARGET_NR_sysinfo                       116
+#define TARGET_NR_ipc                           117
+#define TARGET_NR_fsync                         118
+#define TARGET_NR_sigreturn                     119
+#define TARGET_NR_clone                         120
+#define TARGET_NR_setdomainname                 121
+#define TARGET_NR_uname                         122
+#define TARGET_NR_modify_ldt                    123
+#define TARGET_NR_adjtimex                      124
+#define TARGET_NR_mprotect                      125
+#define TARGET_NR_sigprocmask                   126
+#define TARGET_NR_create_module                 127
+#define TARGET_NR_init_module                   128
+#define TARGET_NR_delete_module                 129
+#define TARGET_NR_get_kernel_syms               130
+#define TARGET_NR_quotactl                      131
+#define TARGET_NR_getpgid                       132
+#define TARGET_NR_fchdir                        133
+#define TARGET_NR_bdflush                       134
+#define TARGET_NR_sysfs                         135
+#define TARGET_NR_personality                   136
+#define TARGET_NR_afs_syscall                   137
+#define TARGET_NR_setfsuid                      138
+#define TARGET_NR_setfsgid                      139
+#define TARGET_NR__llseek                       140
+#define TARGET_NR_getdents                      141
+#define TARGET_NR__newselect                    142
+#define TARGET_NR_flock                         143
+#define TARGET_NR_msync                         144
+#define TARGET_NR_readv                         145
+#define TARGET_NR_writev                        146
+#define TARGET_NR_getsid                        147
+#define TARGET_NR_fdatasync                     148
+#define TARGET_NR__sysctl                       149
+#define TARGET_NR_mlock                         150
+#define TARGET_NR_munlock                       151
+#define TARGET_NR_mlockall                      152
+#define TARGET_NR_munlockall                    153
+#define TARGET_NR_sched_setparam                154
+#define TARGET_NR_sched_getparam                155
+#define TARGET_NR_sched_setscheduler            156
+#define TARGET_NR_sched_getscheduler            157
+#define TARGET_NR_sched_yield                   158
+#define TARGET_NR_sched_get_priority_max        159
+#define TARGET_NR_sched_get_priority_min        160
+#define TARGET_NR_sched_rr_get_interval         161
+#define TARGET_NR_nanosleep                     162
+#define TARGET_NR_mremap                        163
+#define TARGET_NR_setresuid                     164
+#define TARGET_NR_getresuid                     165
+#define TARGET_NR_vm86                          166
+#define TARGET_NR_query_module                  167
+#define TARGET_NR_poll                          168
+#define TARGET_NR_nfsservctl                    169
+#define TARGET_NR_setresgid                     170
+#define TARGET_NR_getresgid                     171
+#define TARGET_NR_prctl                         172
+#define TARGET_NR_rt_sigreturn                  173
+#define TARGET_NR_rt_sigaction                  174
+#define TARGET_NR_rt_sigprocmask                175
+#define TARGET_NR_rt_sigpending                 176
+#define TARGET_NR_rt_sigtimedwait               177
+#define TARGET_NR_rt_sigqueueinfo               178
+#define TARGET_NR_rt_sigsuspend                 179
+#define TARGET_NR_pread                         180
+#define TARGET_NR_pwrite                        181
+#define TARGET_NR_chown                         182
+#define TARGET_NR_getcwd                        183
+#define TARGET_NR_capget                        184
+#define TARGET_NR_capset                        185
+#define TARGET_NR_sigaltstack                   186
+#define TARGET_NR_sendfile                      187
+                                                /* 188 */
+                                                /* 189 */
+#define TARGET_NR_vfork                         190
+#define TARGET_NR_ugetrlimit                    191
+#define TARGET_NR_mmap2                         192
+#define TARGET_NR_truncate64                    193
+#define TARGET_NR_ftruncate64                   194
+#define TARGET_NR_stat64                        195
+#define TARGET_NR_lstat64                       196
+#define TARGET_NR_fstat64                       197
+#define TARGET_NR_lchown32                      198
+#define TARGET_NR_getuid32                      199
+#define TARGET_NR_getgid32                      200
+#define TARGET_NR_geteuid32                     201
+#define TARGET_NR_getegid32                     202
+#define TARGET_NR_setreuid32                    203
+#define TARGET_NR_setregid32                    204
+#define TARGET_NR_getgroups32                   205
+#define TARGET_NR_setgroups32                   206
+#define TARGET_NR_fchown32                      207
+#define TARGET_NR_setresuid32                   208
+#define TARGET_NR_getresuid32                   209
+#define TARGET_NR_setresgid32                   210
+#define TARGET_NR_getresgid32                   211
+#define TARGET_NR_chown32                       212
+#define TARGET_NR_setuid32                      213
+#define TARGET_NR_setgid32                      214
+#define TARGET_NR_setfsuid32                    215
+#define TARGET_NR_setfsgid32                    216
+#define TARGET_NR_getdents64                    217
+#define TARGET_NR_pivot_root                    218
+#define TARGET_NR_mincore                       219
+#define TARGET_NR_madvise                       220
+#define TARGET_NR_fcntl64                       221
+                                                /* 222 */
+                                                /* 223 */
+#define TARGET_NR_gettid                        224
+#define TARGET_NR_readahead                     225
+#define TARGET_NR_setxattr                      226
+#define TARGET_NR_lsetxattr                     227
+#define TARGET_NR_fsetxattr                     228
+#define TARGET_NR_getxattr                      229
+#define TARGET_NR_lgetxattr                     230
+#define TARGET_NR_fgetxattr                     231
+#define TARGET_NR_listxattr                     232
+#define TARGET_NR_llistxattr                    233
+#define TARGET_NR_flistxattr                    234
+#define TARGET_NR_removexattr                   235
+#define TARGET_NR_lremovexattr                  236
+#define TARGET_NR_fremovexattr                  237
+#define TARGET_NR_tkill                         238
+#define TARGET_NR_sendfile64                    239
+#define TARGET_NR_futex                         240
+#define TARGET_NR_sched_setaffinity             241
+#define TARGET_NR_sched_getaffinity             242
+#define TARGET_NR_io_setup                      243
+#define TARGET_NR_io_destroy                    244
+#define TARGET_NR_io_getevents                  245
+#define TARGET_NR_io_submit                     246
+#define TARGET_NR_io_cancel                     247
+#define TARGET_NR_exit_group                    248
+#define TARGET_NR_lookup_dcookie                249
+#define TARGET_NR_epoll_create                  250
+#define TARGET_NR_epoll_ctl                     251
+#define TARGET_NR_epoll_wait                    252
+#define TARGET_NR_remap_file_pages              253
+                                                /* 254 */
+                                                /* 255 */
+                                                /* 256 */
+#define TARGET_NR_set_tid_address               256
+#define TARGET_NR_timer_create                  257
+#define TARGET_NR_timer_settime                 258
+#define TARGET_NR_timer_gettime                 259
+#define TARGET_NR_timer_getoverrun              260
+#define TARGET_NR_timer_delete                  261
+#define TARGET_NR_clock_settime                 262
+#define TARGET_NR_clock_gettime                 263
+#define TARGET_NR_clock_getres                  264
+#define TARGET_NR_clock_nanosleep               265
+#define TARGET_NR_statfs64                      266
+#define TARGET_NR_fstatfs64                     267
+#define TARGET_NR_tgkill                        268
+#define TARGET_NR_utimes                        269
+#define TARGET_NR_fadvise64_64                  270
+#define TARGET_NR_pciconfig_iobase              271
+#define TARGET_NR_pciconfig_read                272
+#define TARGET_NR_pciconfig_write               273
+#define TARGET_NR_mq_open                       274
+#define TARGET_NR_mq_unlink                     275
+#define TARGET_NR_mq_timedsend                  276
+#define TARGET_NR_mq_timedreceive               277
+#define TARGET_NR_mq_notify                     278
+#define TARGET_NR_mq_getsetattr                 279
+#define TARGET_NR_waitid                        280
+#define TARGET_NR_socket                        281
+#define TARGET_NR_bind                          282
+#define TARGET_NR_connect                       283
+#define TARGET_NR_listen                        284
+#define TARGET_NR_accept                        285
+#define TARGET_NR_getsockname                   286
+#define TARGET_NR_getpeername                   287
+#define TARGET_NR_socketpair                    288
+#define TARGET_NR_send                          289
+#define TARGET_NR_sendto                        290
+#define TARGET_NR_recv                          291
+#define TARGET_NR_recvfrom                      292
+#define TARGET_NR_shutdown                      293
+#define TARGET_NR_setsockopt                    294
+#define TARGET_NR_getsockopt                    295
+#define TARGET_NR_sendmsg                       296
+#define TARGET_NR_recvmsg                       297
+#define TARGET_NR_semop                         298
+#define TARGET_NR_semget                        299
+#define TARGET_NR_semctl                        300
+#define TARGET_NR_msgsnd                        301
+#define TARGET_NR_msgrcv                        302
+#define TARGET_NR_msgget                        303
+#define TARGET_NR_msgctl                        304
+#define TARGET_NR_shmat                         305
+#define TARGET_NR_shmdt                         306
+#define TARGET_NR_shmget                        307
+#define TARGET_NR_shmctl                        308
+#define TARGET_NR_add_key                       309
+#define TARGET_NR_request_key                   310
+#define TARGET_NR_keyctl                        311
+#define TARGET_NR_semtimedop                    312
+#define TARGET_NR_vserver                       313
+#define TARGET_NR_ioprio_set                    314
+#define TARGET_NR_ioprio_get                    315
+#define TARGET_NR_inotify_init                  316
+#define TARGET_NR_inotify_add_watch             317
+#define TARGET_NR_inotify_rm_watch              318
+#define TARGET_NR_mbind                         319
+#define TARGET_NR_get_mempolicy                 320
+#define TARGET_NR_set_mempolicy                 321
+#define TARGET_NR_openat                        322
+#define TARGET_NR_mkdirat                       323
+#define TARGET_NR_mknodat                       324
+#define TARGET_NR_fchownat                      325
+#define TARGET_NR_futimesat                     326
+#define TARGET_NR_fstatat64                     327
+#define TARGET_NR_unlinkat                      328
+#define TARGET_NR_renameat                      329
+#define TARGET_NR_linkat                        330
+#define TARGET_NR_symlinkat                     331
+#define TARGET_NR_readlinkat                    332
+#define TARGET_NR_fchmodat                      333
+#define TARGET_NR_faccessat                     334
+                                                /* 335 */
+                                                /* 336 */
+#define TARGET_NR_unshare                       337
+#define TARGET_NR_set_robust_list               338
+#define TARGET_NR_get_robust_list               339
+#define TARGET_NR_splice                        340
+#define TARGET_NR_sync_file_range2              341
+#define TARGET_NR_tee                           342
+#define TARGET_NR_vmsplice                      343
+#define TARGET_NR_move_pages                    344
+#define TARGET_NR_getcpu                        345
+                                                /* 346 */
+#define TARGET_NR_kexec_load                    347
+#define TARGET_NR_utimensat                     348
+#define TARGET_NR_signalfd                      349
+#define TARGET_NR_timerfd                       350
+#define TARGET_NR_eventfd                       351
+#define TARGET_NR_fallocate                     352
+#define TARGET_NR_timerfd_settime               353
+#define TARGET_NR_timerfd_gettime               354
+#define TARGET_NR_signalfd4                     355
+#define TARGET_NR_eventfd2                      356
+#define TARGET_NR_epoll_create1                 357
+#define TARGET_NR_dup3                          358
+#define TARGET_NR_pipe2                         359
+#define TARGET_NR_inotify_init1                 360
diff --git a/qemu-0.15.x/linux-user/unicore32/target_signal.h b/qemu-0.15.x/linux-user/unicore32/target_signal.h
new file mode 100644
index 0000000..8b255c4
--- /dev/null
+++ b/qemu-0.15.x/linux-user/unicore32/target_signal.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_ulong ss_sp;
+    abi_ulong ss_flags;
+    abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK               1
+#define TARGET_SS_DISABLE               2
+
+#define get_sp_from_cpustate(cpustate)  (cpustate->regs[29])
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/unicore32/termbits.h b/qemu-0.15.x/linux-user/unicore32/termbits.h
new file mode 100644
index 0000000..a5fcd64
--- /dev/null
+++ b/qemu-0.15.x/linux-user/unicore32/termbits.h
@@ -0,0 +1,2 @@
+/* NOTE: exactly the same as i386 */
+#include "../i386/termbits.h"
diff --git a/qemu-0.15.x/linux-user/vm86.c b/qemu-0.15.x/linux-user/vm86.c
new file mode 100644
index 0000000..0b2439d
--- /dev/null
+++ b/qemu-0.15.x/linux-user/vm86.c
@@ -0,0 +1,481 @@
+/*
+ *  vm86 linux syscall support
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "qemu.h"
+
+//#define DEBUG_VM86
+
+#ifdef DEBUG_VM86
+#  define LOG_VM86(...) qemu_log(__VA_ARGS__);
+#else
+#  define LOG_VM86(...) do { } while (0)
+#endif
+
+
+#define set_flags(X,new,mask) \
+((X) = ((X) & ~(mask)) | ((new) & (mask)))
+
+#define SAFE_MASK	(0xDD5)
+#define RETURN_MASK	(0xDFF)
+
+static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
+{
+    return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
+}
+
+static inline void vm_putw(uint32_t segptr, unsigned int reg16, unsigned int val)
+{
+    stw(segptr + (reg16 & 0xffff), val);
+}
+
+static inline void vm_putl(uint32_t segptr, unsigned int reg16, unsigned int val)
+{
+    stl(segptr + (reg16 & 0xffff), val);
+}
+
+static inline unsigned int vm_getb(uint32_t segptr, unsigned int reg16)
+{
+    return ldub(segptr + (reg16 & 0xffff));
+}
+
+static inline unsigned int vm_getw(uint32_t segptr, unsigned int reg16)
+{
+    return lduw(segptr + (reg16 & 0xffff));
+}
+
+static inline unsigned int vm_getl(uint32_t segptr, unsigned int reg16)
+{
+    return ldl(segptr + (reg16 & 0xffff));
+}
+
+void save_v86_state(CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+    struct target_vm86plus_struct * target_v86;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
+        /* FIXME - should return an error */
+        return;
+    /* put the VM86 registers in the userspace register structure */
+    target_v86->regs.eax = tswap32(env->regs[R_EAX]);
+    target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
+    target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
+    target_v86->regs.edx = tswap32(env->regs[R_EDX]);
+    target_v86->regs.esi = tswap32(env->regs[R_ESI]);
+    target_v86->regs.edi = tswap32(env->regs[R_EDI]);
+    target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
+    target_v86->regs.esp = tswap32(env->regs[R_ESP]);
+    target_v86->regs.eip = tswap32(env->eip);
+    target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
+    target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
+    target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
+    target_v86->regs.es = tswap16(env->segs[R_ES].selector);
+    target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
+    target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
+    set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
+    target_v86->regs.eflags = tswap32(env->eflags);
+    unlock_user_struct(target_v86, ts->target_v86, 1);
+    LOG_VM86("save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
+             env->eflags, env->segs[R_CS].selector, env->eip);
+
+    /* restore 32 bit registers */
+    env->regs[R_EAX] = ts->vm86_saved_regs.eax;
+    env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
+    env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
+    env->regs[R_EDX] = ts->vm86_saved_regs.edx;
+    env->regs[R_ESI] = ts->vm86_saved_regs.esi;
+    env->regs[R_EDI] = ts->vm86_saved_regs.edi;
+    env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
+    env->regs[R_ESP] = ts->vm86_saved_regs.esp;
+    env->eflags = ts->vm86_saved_regs.eflags;
+    env->eip = ts->vm86_saved_regs.eip;
+
+    cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
+    cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
+    cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
+    cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
+    cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
+    cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
+}
+
+/* return from vm86 mode to 32 bit. The vm86() syscall will return
+   'retval' */
+static inline void return_to_32bit(CPUX86State *env, int retval)
+{
+    LOG_VM86("return_to_32bit: ret=0x%x\n", retval);
+    save_v86_state(env);
+    env->regs[R_EAX] = retval;
+}
+
+static inline int set_IF(CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+
+    ts->v86flags |= VIF_MASK;
+    if (ts->v86flags & VIP_MASK) {
+        return_to_32bit(env, TARGET_VM86_STI);
+        return 1;
+    }
+    return 0;
+}
+
+static inline void clear_IF(CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+
+    ts->v86flags &= ~VIF_MASK;
+}
+
+static inline void clear_TF(CPUX86State *env)
+{
+    env->eflags &= ~TF_MASK;
+}
+
+static inline void clear_AC(CPUX86State *env)
+{
+    env->eflags &= ~AC_MASK;
+}
+
+static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+
+    set_flags(ts->v86flags, eflags, ts->v86mask);
+    set_flags(env->eflags, eflags, SAFE_MASK);
+    if (eflags & IF_MASK)
+        return set_IF(env);
+    else
+        clear_IF(env);
+    return 0;
+}
+
+static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+
+    set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
+    set_flags(env->eflags, flags, SAFE_MASK);
+    if (flags & IF_MASK)
+        return set_IF(env);
+    else
+        clear_IF(env);
+    return 0;
+}
+
+static inline unsigned int get_vflags(CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+    unsigned int flags;
+
+    flags = env->eflags & RETURN_MASK;
+    if (ts->v86flags & VIF_MASK)
+        flags |= IF_MASK;
+    flags |= IOPL_MASK;
+    return flags | (ts->v86flags & ts->v86mask);
+}
+
+#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
+
+/* handle VM86 interrupt (NOTE: the CPU core currently does not
+   support TSS interrupt revectoring, so this code is always executed) */
+static void do_int(CPUX86State *env, int intno)
+{
+    TaskState *ts = env->opaque;
+    uint32_t int_addr, segoffs, ssp;
+    unsigned int sp;
+
+    if (env->segs[R_CS].selector == TARGET_BIOSSEG)
+        goto cannot_handle;
+    if (is_revectored(intno, &ts->vm86plus.int_revectored))
+        goto cannot_handle;
+    if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
+                                       &ts->vm86plus.int21_revectored))
+        goto cannot_handle;
+    int_addr = (intno << 2);
+    segoffs = ldl(int_addr);
+    if ((segoffs >> 16) == TARGET_BIOSSEG)
+        goto cannot_handle;
+    LOG_VM86("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
+             intno, segoffs >> 16, segoffs & 0xffff);
+    /* save old state */
+    ssp = env->segs[R_SS].selector << 4;
+    sp = env->regs[R_ESP] & 0xffff;
+    vm_putw(ssp, sp - 2, get_vflags(env));
+    vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
+    vm_putw(ssp, sp - 6, env->eip);
+    ADD16(env->regs[R_ESP], -6);
+    /* goto interrupt handler */
+    env->eip = segoffs & 0xffff;
+    cpu_x86_load_seg(env, R_CS, segoffs >> 16);
+    clear_TF(env);
+    clear_IF(env);
+    clear_AC(env);
+    return;
+ cannot_handle:
+    LOG_VM86("VM86: return to 32 bits int 0x%x\n", intno);
+    return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
+}
+
+void handle_vm86_trap(CPUX86State *env, int trapno)
+{
+    if (trapno == 1 || trapno == 3) {
+        return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
+    } else {
+        do_int(env, trapno);
+    }
+}
+
+#define CHECK_IF_IN_TRAP() \
+      if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
+          (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
+		newflags |= TF_MASK
+
+#define VM86_FAULT_RETURN \
+        if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
+            (ts->v86flags & (IF_MASK | VIF_MASK))) \
+            return_to_32bit(env, TARGET_VM86_PICRETURN); \
+        return
+
+void handle_vm86_fault(CPUX86State *env)
+{
+    TaskState *ts = env->opaque;
+    uint32_t csp, ssp;
+    unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
+    int data32, pref_done;
+
+    csp = env->segs[R_CS].selector << 4;
+    ip = env->eip & 0xffff;
+
+    ssp = env->segs[R_SS].selector << 4;
+    sp = env->regs[R_ESP] & 0xffff;
+
+    LOG_VM86("VM86 exception %04x:%08x\n",
+             env->segs[R_CS].selector, env->eip);
+
+    data32 = 0;
+    pref_done = 0;
+    do {
+        opcode = vm_getb(csp, ip);
+        ADD16(ip, 1);
+        switch (opcode) {
+        case 0x66:      /* 32-bit data */     data32=1; break;
+        case 0x67:      /* 32-bit address */  break;
+        case 0x2e:      /* CS */              break;
+        case 0x3e:      /* DS */              break;
+        case 0x26:      /* ES */              break;
+        case 0x36:      /* SS */              break;
+        case 0x65:      /* GS */              break;
+        case 0x64:      /* FS */              break;
+        case 0xf2:      /* repnz */	      break;
+        case 0xf3:      /* rep */             break;
+        default: pref_done = 1;
+        }
+    } while (!pref_done);
+
+    /* VM86 mode */
+    switch(opcode) {
+    case 0x9c: /* pushf */
+        if (data32) {
+            vm_putl(ssp, sp - 4, get_vflags(env));
+            ADD16(env->regs[R_ESP], -4);
+        } else {
+            vm_putw(ssp, sp - 2, get_vflags(env));
+            ADD16(env->regs[R_ESP], -2);
+        }
+        env->eip = ip;
+        VM86_FAULT_RETURN;
+
+    case 0x9d: /* popf */
+        if (data32) {
+            newflags = vm_getl(ssp, sp);
+            ADD16(env->regs[R_ESP], 4);
+        } else {
+            newflags = vm_getw(ssp, sp);
+            ADD16(env->regs[R_ESP], 2);
+        }
+        env->eip = ip;
+        CHECK_IF_IN_TRAP();
+        if (data32) {
+            if (set_vflags_long(newflags, env))
+                return;
+        } else {
+            if (set_vflags_short(newflags, env))
+                return;
+        }
+        VM86_FAULT_RETURN;
+
+    case 0xcd: /* int */
+        intno = vm_getb(csp, ip);
+        ADD16(ip, 1);
+        env->eip = ip;
+        if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
+            if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
+                  (intno &7)) & 1) {
+                return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
+                return;
+            }
+        }
+        do_int(env, intno);
+        break;
+
+    case 0xcf: /* iret */
+        if (data32) {
+            newip = vm_getl(ssp, sp) & 0xffff;
+            newcs = vm_getl(ssp, sp + 4) & 0xffff;
+            newflags = vm_getl(ssp, sp + 8);
+            ADD16(env->regs[R_ESP], 12);
+        } else {
+            newip = vm_getw(ssp, sp);
+            newcs = vm_getw(ssp, sp + 2);
+            newflags = vm_getw(ssp, sp + 4);
+            ADD16(env->regs[R_ESP], 6);
+        }
+        env->eip = newip;
+        cpu_x86_load_seg(env, R_CS, newcs);
+        CHECK_IF_IN_TRAP();
+        if (data32) {
+            if (set_vflags_long(newflags, env))
+                return;
+        } else {
+            if (set_vflags_short(newflags, env))
+                return;
+        }
+        VM86_FAULT_RETURN;
+
+    case 0xfa: /* cli */
+        env->eip = ip;
+        clear_IF(env);
+        VM86_FAULT_RETURN;
+
+    case 0xfb: /* sti */
+        env->eip = ip;
+        if (set_IF(env))
+            return;
+        VM86_FAULT_RETURN;
+
+    default:
+        /* real VM86 GPF exception */
+        return_to_32bit(env, TARGET_VM86_UNKNOWN);
+        break;
+    }
+}
+
+int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
+{
+    TaskState *ts = env->opaque;
+    struct target_vm86plus_struct * target_v86;
+    int ret;
+
+    switch (subfunction) {
+    case TARGET_VM86_REQUEST_IRQ:
+    case TARGET_VM86_FREE_IRQ:
+    case TARGET_VM86_GET_IRQ_BITS:
+    case TARGET_VM86_GET_AND_RESET_IRQ:
+        gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
+        ret = -TARGET_EINVAL;
+        goto out;
+    case TARGET_VM86_PLUS_INSTALL_CHECK:
+        /* NOTE: on old vm86 stuff this will return the error
+           from verify_area(), because the subfunction is
+           interpreted as (invalid) address to vm86_struct.
+           So the installation check works.
+            */
+        ret = 0;
+        goto out;
+    }
+
+    /* save current CPU regs */
+    ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
+    ts->vm86_saved_regs.ebx = env->regs[R_EBX];
+    ts->vm86_saved_regs.ecx = env->regs[R_ECX];
+    ts->vm86_saved_regs.edx = env->regs[R_EDX];
+    ts->vm86_saved_regs.esi = env->regs[R_ESI];
+    ts->vm86_saved_regs.edi = env->regs[R_EDI];
+    ts->vm86_saved_regs.ebp = env->regs[R_EBP];
+    ts->vm86_saved_regs.esp = env->regs[R_ESP];
+    ts->vm86_saved_regs.eflags = env->eflags;
+    ts->vm86_saved_regs.eip  = env->eip;
+    ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
+    ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
+    ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
+    ts->vm86_saved_regs.es = env->segs[R_ES].selector;
+    ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
+    ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
+
+    ts->target_v86 = vm86_addr;
+    if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1))
+        return -TARGET_EFAULT;
+    /* build vm86 CPU state */
+    ts->v86flags = tswap32(target_v86->regs.eflags);
+    env->eflags = (env->eflags & ~SAFE_MASK) |
+        (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
+
+    ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
+    switch (ts->vm86plus.cpu_type) {
+    case TARGET_CPU_286:
+        ts->v86mask = 0;
+        break;
+    case TARGET_CPU_386:
+        ts->v86mask = NT_MASK | IOPL_MASK;
+        break;
+    case TARGET_CPU_486:
+        ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+        break;
+    default:
+        ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+        break;
+    }
+
+    env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
+    env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
+    env->regs[R_EDX] = tswap32(target_v86->regs.edx);
+    env->regs[R_ESI] = tswap32(target_v86->regs.esi);
+    env->regs[R_EDI] = tswap32(target_v86->regs.edi);
+    env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
+    env->regs[R_ESP] = tswap32(target_v86->regs.esp);
+    env->eip = tswap32(target_v86->regs.eip);
+    cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
+    cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
+    cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
+    cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
+    cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
+    cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
+    ret = tswap32(target_v86->regs.eax); /* eax will be restored at
+                                            the end of the syscall */
+    memcpy(&ts->vm86plus.int_revectored,
+           &target_v86->int_revectored, 32);
+    memcpy(&ts->vm86plus.int21_revectored,
+           &target_v86->int21_revectored, 32);
+    ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
+    memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
+           target_v86->vm86plus.vm86dbg_intxxtab, 32);
+    unlock_user_struct(target_v86, vm86_addr, 0);
+
+    LOG_VM86("do_vm86: cs:ip=%04x:%04x\n",
+             env->segs[R_CS].selector, env->eip);
+    /* now the virtual CPU is ready for vm86 execution ! */
+ out:
+    return ret;
+}
diff --git a/qemu-0.15.x/linux-user/x86_64/syscall.h b/qemu-0.15.x/linux-user/x86_64/syscall.h
new file mode 100644
index 0000000..2a8d696
--- /dev/null
+++ b/qemu-0.15.x/linux-user/x86_64/syscall.h
@@ -0,0 +1,98 @@
+#define __USER_CS	(0x33)
+#define __USER_DS	(0x2B)
+
+struct target_pt_regs {
+	abi_ulong r15;
+	abi_ulong r14;
+	abi_ulong r13;
+	abi_ulong r12;
+	abi_ulong rbp;
+	abi_ulong rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ 	abi_ulong r11;
+	abi_ulong r10;
+	abi_ulong r9;
+	abi_ulong r8;
+	abi_ulong rax;
+	abi_ulong rcx;
+	abi_ulong rdx;
+	abi_ulong rsi;
+	abi_ulong rdi;
+	abi_ulong orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+	abi_ulong rip;
+	abi_ulong cs;
+	abi_ulong eflags;
+	abi_ulong rsp;
+	abi_ulong ss;
+/* top of stack page */
+};
+
+/* Maximum number of LDT entries supported. */
+#define TARGET_LDT_ENTRIES	8192
+/* The size of each LDT entry. */
+#define TARGET_LDT_ENTRY_SIZE	8
+
+#define TARGET_GDT_ENTRIES 16
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 12
+#define TARGET_GDT_ENTRY_TLS_MAX 14
+
+#if 0 // Redefine this
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+        abi_ulong     base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+	unsigned int  lm:1;
+};
+#else
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+        abi_ulong     base_addr;
+	unsigned int  limit;
+        unsigned int flags;
+};
+#endif
+
+struct target_ipc64_perm
+{
+	int		key;
+	uint32_t	uid;
+	uint32_t	gid;
+	uint32_t	cuid;
+	uint32_t	cgid;
+	unsigned short		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	abi_ulong		__unused1;
+	abi_ulong		__unused2;
+};
+
+struct target_msqid64_ds {
+	struct target_ipc64_perm msg_perm;
+	unsigned int msg_stime;	/* last msgsnd time */
+	unsigned int msg_rtime;	/* last msgrcv time */
+	unsigned int msg_ctime;	/* last change time */
+	abi_ulong  msg_cbytes;	/* current number of bytes on queue */
+	abi_ulong  msg_qnum;	/* number of messages in queue */
+	abi_ulong  msg_qbytes;	/* max number of bytes on queue */
+	unsigned int msg_lspid;	/* pid of last msgsnd */
+	unsigned int msg_lrpid;	/* last receive pid */
+	abi_ulong  __unused4;
+	abi_ulong  __unused5;
+};
+
+#define UNAME_MACHINE "x86_64"
+
+#define TARGET_ARCH_SET_GS 0x1001
+#define TARGET_ARCH_SET_FS 0x1002
+#define TARGET_ARCH_GET_FS 0x1003
+#define TARGET_ARCH_GET_GS 0x1004
diff --git a/qemu-0.15.x/linux-user/x86_64/syscall_nr.h b/qemu-0.15.x/linux-user/x86_64/syscall_nr.h
new file mode 100644
index 0000000..947e961
--- /dev/null
+++ b/qemu-0.15.x/linux-user/x86_64/syscall_nr.h
@@ -0,0 +1,307 @@
+#define TARGET_NR_read                                0
+#define TARGET_NR_write                               1
+#define TARGET_NR_open                                2
+#define TARGET_NR_close                               3
+#define TARGET_NR_stat                                4
+#define TARGET_NR_fstat                               5
+#define TARGET_NR_lstat                               6
+#define TARGET_NR_poll                                7
+#define TARGET_NR_lseek                               8
+#define TARGET_NR_mmap                                9
+#define TARGET_NR_mprotect                           10
+#define TARGET_NR_munmap                             11
+#define TARGET_NR_brk                                12
+#define TARGET_NR_rt_sigaction                       13
+#define TARGET_NR_rt_sigprocmask                     14
+#define TARGET_NR_rt_sigreturn                       15
+#define TARGET_NR_ioctl                              16
+#define TARGET_NR_pread64                            17
+#define TARGET_NR_pwrite64                           18
+#define TARGET_NR_readv                              19
+#define TARGET_NR_writev                             20
+#define TARGET_NR_access                             21
+#define TARGET_NR_pipe                               22
+#define TARGET_NR_select                             23
+#define TARGET_NR_sched_yield                        24
+#define TARGET_NR_mremap                             25
+#define TARGET_NR_msync                              26
+#define TARGET_NR_mincore                            27
+#define TARGET_NR_madvise                            28
+#define TARGET_NR_shmget                             29
+#define TARGET_NR_shmat                              30
+#define TARGET_NR_shmctl                             31
+#define TARGET_NR_dup                                32
+#define TARGET_NR_dup2                               33
+#define TARGET_NR_pause                              34
+#define TARGET_NR_nanosleep                          35
+#define TARGET_NR_getitimer                          36
+#define TARGET_NR_alarm                              37
+#define TARGET_NR_setitimer                          38
+#define TARGET_NR_getpid                             39
+#define TARGET_NR_sendfile                           40
+#define TARGET_NR_socket                             41
+#define TARGET_NR_connect                            42
+#define TARGET_NR_accept                             43
+#define TARGET_NR_sendto                             44
+#define TARGET_NR_recvfrom                           45
+#define TARGET_NR_sendmsg                            46
+#define TARGET_NR_recvmsg                            47
+#define TARGET_NR_shutdown                           48
+#define TARGET_NR_bind                               49
+#define TARGET_NR_listen                             50
+#define TARGET_NR_getsockname                        51
+#define TARGET_NR_getpeername                        52
+#define TARGET_NR_socketpair                         53
+#define TARGET_NR_setsockopt                         54
+#define TARGET_NR_getsockopt                         55
+#define TARGET_NR_clone                              56
+#define TARGET_NR_fork                               57
+#define TARGET_NR_vfork                              58
+#define TARGET_NR_execve                             59
+#define TARGET_NR_exit                               60
+#define TARGET_NR_wait4                              61
+#define TARGET_NR_kill                               62
+#define TARGET_NR_uname                              63
+#define TARGET_NR_semget                             64
+#define TARGET_NR_semop                              65
+#define TARGET_NR_semctl                             66
+#define TARGET_NR_shmdt                              67
+#define TARGET_NR_msgget                             68
+#define TARGET_NR_msgsnd                             69
+#define TARGET_NR_msgrcv                             70
+#define TARGET_NR_msgctl                             71
+#define TARGET_NR_fcntl                              72
+#define TARGET_NR_flock                              73
+#define TARGET_NR_fsync                              74
+#define TARGET_NR_fdatasync                          75
+#define TARGET_NR_truncate                           76
+#define TARGET_NR_ftruncate                          77
+#define TARGET_NR_getdents                           78
+#define TARGET_NR_getcwd                             79
+#define TARGET_NR_chdir                              80
+#define TARGET_NR_fchdir                             81
+#define TARGET_NR_rename                             82
+#define TARGET_NR_mkdir                              83
+#define TARGET_NR_rmdir                              84
+#define TARGET_NR_creat                              85
+#define TARGET_NR_link                               86
+#define TARGET_NR_unlink                             87
+#define TARGET_NR_symlink                            88
+#define TARGET_NR_readlink                           89
+#define TARGET_NR_chmod                              90
+#define TARGET_NR_fchmod                             91
+#define TARGET_NR_chown                              92
+#define TARGET_NR_fchown                             93
+#define TARGET_NR_lchown                             94
+#define TARGET_NR_umask                              95
+#define TARGET_NR_gettimeofday                       96
+#define TARGET_NR_getrlimit                          97
+#define TARGET_NR_getrusage                          98
+#define TARGET_NR_sysinfo                            99
+#define TARGET_NR_times                             100
+#define TARGET_NR_ptrace                            101
+#define TARGET_NR_getuid                            102
+#define TARGET_NR_syslog                            103
+#define TARGET_NR_getgid                            104
+#define TARGET_NR_setuid                            105
+#define TARGET_NR_setgid                            106
+#define TARGET_NR_geteuid                           107
+#define TARGET_NR_getegid                           108
+#define TARGET_NR_setpgid                           109
+#define TARGET_NR_getppid                           110
+#define TARGET_NR_getpgrp                           111
+#define TARGET_NR_setsid                            112
+#define TARGET_NR_setreuid                          113
+#define TARGET_NR_setregid                          114
+#define TARGET_NR_getgroups                         115
+#define TARGET_NR_setgroups                         116
+#define TARGET_NR_setresuid                         117
+#define TARGET_NR_getresuid                         118
+#define TARGET_NR_setresgid                         119
+#define TARGET_NR_getresgid                         120
+#define TARGET_NR_getpgid                           121
+#define TARGET_NR_setfsuid                          122
+#define TARGET_NR_setfsgid                          123
+#define TARGET_NR_getsid                            124
+#define TARGET_NR_capget                            125
+#define TARGET_NR_capset                            126
+#define TARGET_NR_rt_sigpending                     127
+#define TARGET_NR_rt_sigtimedwait                   128
+#define TARGET_NR_rt_sigqueueinfo                   129
+#define TARGET_NR_rt_sigsuspend                     130
+#define TARGET_NR_sigaltstack                       131
+#define TARGET_NR_utime                             132
+#define TARGET_NR_mknod                             133
+#define TARGET_NR_uselib                            134
+#define TARGET_NR_personality                       135
+#define TARGET_NR_ustat                             136
+#define TARGET_NR_statfs                            137
+#define TARGET_NR_fstatfs                           138
+#define TARGET_NR_sysfs                             139
+#define TARGET_NR_getpriority                       140
+#define TARGET_NR_setpriority                       141
+#define TARGET_NR_sched_setparam                    142
+#define TARGET_NR_sched_getparam                    143
+#define TARGET_NR_sched_setscheduler                144
+#define TARGET_NR_sched_getscheduler                145
+#define TARGET_NR_sched_get_priority_max            146
+#define TARGET_NR_sched_get_priority_min            147
+#define TARGET_NR_sched_rr_get_interval             148
+#define TARGET_NR_mlock                             149
+#define TARGET_NR_munlock                           150
+#define TARGET_NR_mlockall                          151
+#define TARGET_NR_munlockall                        152
+#define TARGET_NR_vhangup                           153
+#define TARGET_NR_modify_ldt                        154
+#define TARGET_NR_pivot_root                        155
+#define TARGET_NR__sysctl                           156
+#define TARGET_NR_prctl                             157
+#define TARGET_NR_arch_prctl                        158
+#define TARGET_NR_adjtimex                          159
+#define TARGET_NR_setrlimit                         160
+#define TARGET_NR_chroot                            161
+#define TARGET_NR_sync                              162
+#define TARGET_NR_acct                              163
+#define TARGET_NR_settimeofday                      164
+#define TARGET_NR_mount                             165
+#define TARGET_NR_umount2                           166
+#define TARGET_NR_swapon                            167
+#define TARGET_NR_swapoff                           168
+#define TARGET_NR_reboot                            169
+#define TARGET_NR_sethostname                       170
+#define TARGET_NR_setdomainname                     171
+#define TARGET_NR_iopl                              172
+#define TARGET_NR_ioperm                            173
+#define TARGET_NR_create_module                     174
+#define TARGET_NR_init_module                       175
+#define TARGET_NR_delete_module                     176
+#define TARGET_NR_get_kernel_syms                   177
+#define TARGET_NR_query_module                      178
+#define TARGET_NR_quotactl                          179
+#define TARGET_NR_nfsservctl                        180
+#define TARGET_NR_getpmsg                           181	/* reserved for LiS/STREAMS */
+#define TARGET_NR_putpmsg                           182	/* reserved for LiS/STREAMS */
+#define TARGET_NR_afs_syscall                       183	/* reserved for AFS */
+#define TARGET_NR_tuxcall      		184 /* reserved for tux */
+#define TARGET_NR_security			185
+#define TARGET_NR_gettid		186
+#define TARGET_NR_readahead		187
+#define TARGET_NR_setxattr		188
+#define TARGET_NR_lsetxattr		189
+#define TARGET_NR_fsetxattr		190
+#define TARGET_NR_getxattr		191
+#define TARGET_NR_lgetxattr		192
+#define TARGET_NR_fgetxattr		193
+#define TARGET_NR_listxattr		194
+#define TARGET_NR_llistxattr		195
+#define TARGET_NR_flistxattr		196
+#define TARGET_NR_removexattr	197
+#define TARGET_NR_lremovexattr	198
+#define TARGET_NR_fremovexattr	199
+#define TARGET_NR_tkill	200
+#define TARGET_NR_time      201
+#define TARGET_NR_futex     202
+#define TARGET_NR_sched_setaffinity    203
+#define TARGET_NR_sched_getaffinity     204
+#define TARGET_NR_set_thread_area	205
+#define TARGET_NR_io_setup	206
+#define TARGET_NR_io_destroy	207
+#define TARGET_NR_io_getevents	208
+#define TARGET_NR_io_submit	209
+#define TARGET_NR_io_cancel	210
+#define TARGET_NR_get_thread_area	211
+#define TARGET_NR_lookup_dcookie	212
+#define TARGET_NR_epoll_create	213
+#define TARGET_NR_epoll_ctl_old	214
+#define TARGET_NR_epoll_wait_old	215
+#define TARGET_NR_remap_file_pages	216
+#define TARGET_NR_getdents64	217
+#define TARGET_NR_set_tid_address	218
+#define TARGET_NR_restart_syscall	219
+#define TARGET_NR_semtimedop		220
+#define TARGET_NR_fadvise64		221
+#define TARGET_NR_timer_create		222
+#define TARGET_NR_timer_settime		223
+#define TARGET_NR_timer_gettime		224
+#define TARGET_NR_timer_getoverrun		225
+#define TARGET_NR_timer_delete	226
+#define TARGET_NR_clock_settime	227
+#define TARGET_NR_clock_gettime	228
+#define TARGET_NR_clock_getres	229
+#define TARGET_NR_clock_nanosleep	230
+#define TARGET_NR_exit_group		231
+#define TARGET_NR_epoll_wait		232
+#define TARGET_NR_epoll_ctl		233
+#define TARGET_NR_tgkill		234
+#define TARGET_NR_utimes		235
+#define TARGET_NR_vserver		236
+#define TARGET_NR_mbind 		237
+#define TARGET_NR_set_mempolicy 	238
+#define TARGET_NR_get_mempolicy 	239
+#define TARGET_NR_mq_open 		240
+#define TARGET_NR_mq_unlink 		241
+#define TARGET_NR_mq_timedsend 	242
+#define TARGET_NR_mq_timedreceive	243
+#define TARGET_NR_mq_notify 		244
+#define TARGET_NR_mq_getsetattr 	245
+#define TARGET_NR_kexec_load 	246
+#define TARGET_NR_waitid		247
+#define TARGET_NR_add_key		248
+#define TARGET_NR_request_key	249
+#define TARGET_NR_keyctl		250
+#define TARGET_NR_ioprio_set		251
+#define TARGET_NR_ioprio_get		252
+#define TARGET_NR_inotify_init	253
+#define TARGET_NR_inotify_add_watch	254
+#define TARGET_NR_inotify_rm_watch	255
+#define TARGET_NR_migrate_pages	256
+#define TARGET_NR_openat		257
+#define TARGET_NR_mkdirat		258
+#define TARGET_NR_mknodat		259
+#define TARGET_NR_fchownat		260
+#define TARGET_NR_futimesat		261
+#define TARGET_NR_newfstatat		262
+#define TARGET_NR_unlinkat		263
+#define TARGET_NR_renameat		264
+#define TARGET_NR_linkat		265
+#define TARGET_NR_symlinkat		266
+#define TARGET_NR_readlinkat		267
+#define TARGET_NR_fchmodat		268
+#define TARGET_NR_faccessat		269
+#define TARGET_NR_pselect6		270
+#define TARGET_NR_ppoll		271
+#define TARGET_NR_unshare		272
+#define TARGET_NR_set_robust_list	273
+#define TARGET_NR_get_robust_list	274
+#define TARGET_NR_splice		275
+#define TARGET_NR_tee		276
+#define TARGET_NR_sync_file_range	277
+#define TARGET_NR_vmsplice		278
+#define TARGET_NR_move_pages		279
+#define TARGET_NR_utimensat		280
+#define TARGET_NR_epoll_pwait	281
+#define TARGET_NR_signalfd		282
+#define TARGET_NR_timerfd		283
+#define TARGET_NR_eventfd		284
+#define TARGET_NR_fallocate		285
+#define TARGET_NR_timerfd_settime	286
+#define TARGET_NR_timerfd_gettime	287
+#define TARGET_NR_accept4		288
+#define TARGET_NR_signalfd4		289
+#define TARGET_NR_eventfd2		290
+#define TARGET_NR_epoll_create1	291
+#define TARGET_NR_dup3			292
+#define TARGET_NR_pipe2		293
+#define TARGET_NR_inotify_init1	294
+#define TARGET_NR_preadv                295
+#define TARGET_NR_pwritev               296
+#define TARGET_NR_rt_tgsigqueueinfo     297
+#define TARGET_NR_perf_event_open       298
+#define TARGET_NR_recvmmsg              299
+#define TARGET_NR_fanotify_init         300
+#define TARGET_NR_fanotify_mark         301
+#define TARGET_NR_prlimit64             302
+#define TARGET_NR_name_to_handle_at     303
+#define TARGET_NR_open_by_handle_at     304
+#define TARGET_NR_clock_adjtime         305
+#define TARGET_NR_syncfs                306
diff --git a/qemu-0.15.x/linux-user/x86_64/target_signal.h b/qemu-0.15.x/linux-user/x86_64/target_signal.h
new file mode 100644
index 0000000..9baf7fb
--- /dev/null
+++ b/qemu-0.15.x/linux-user/x86_64/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	abi_ulong ss_sp;
+	abi_long ss_flags;
+	abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/qemu-0.15.x/linux-user/x86_64/termbits.h b/qemu-0.15.x/linux-user/x86_64/termbits.h
new file mode 100644
index 0000000..1c3445c
--- /dev/null
+++ b/qemu-0.15.x/linux-user/x86_64/termbits.h
@@ -0,0 +1,247 @@
+#define TARGET_NCCS 19
+
+typedef unsigned char	target_cc_t;
+typedef unsigned int	target_speed_t;
+typedef unsigned int	target_tcflag_t;
+struct target_termios {
+	target_tcflag_t c_iflag;		/* input mode flags */
+	target_tcflag_t c_oflag;		/* output mode flags */
+	target_tcflag_t c_cflag;		/* control mode flags */
+	target_tcflag_t c_lflag;		/* local mode flags */
+	target_cc_t c_line;			/* line discipline */
+	target_cc_t c_cc[TARGET_NCCS];		/* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IUCLC	0001000
+#define TARGET_IXON	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IXOFF	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_OLCUC	0000002
+#define TARGET_ONLCR	0000004
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+#define TARGET_OFILL	0000100
+#define TARGET_OFDEL	0000200
+#define TARGET_NLDLY	0000400
+#define   TARGET_NL0	0000000
+#define   TARGET_NL1	0000400
+#define TARGET_CRDLY	0003000
+#define   TARGET_CR0	0000000
+#define   TARGET_CR1	0001000
+#define   TARGET_CR2	0002000
+#define   TARGET_CR3	0003000
+#define TARGET_TABDLY	0014000
+#define   TARGET_TAB0	0000000
+#define   TARGET_TAB1	0004000
+#define   TARGET_TAB2	0010000
+#define   TARGET_TAB3	0014000
+#define   TARGET_XTABS	0014000
+#define TARGET_BSDLY	0020000
+#define   TARGET_BS0	0000000
+#define   TARGET_BS1	0020000
+#define TARGET_VTDLY	0040000
+#define   TARGET_VT0	0000000
+#define   TARGET_VT1	0040000
+#define TARGET_FFDLY	0100000
+#define   TARGET_FF0	0000000
+#define   TARGET_FF1	0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0010017
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE	0000060
+#define   TARGET_CS5	0000000
+#define   TARGET_CS6	0000020
+#define   TARGET_CS7	0000040
+#define   TARGET_CS8	0000060
+#define TARGET_CSTOPB	0000100
+#define TARGET_CREAD	0000200
+#define TARGET_PARENB	0000400
+#define TARGET_PARODD	0001000
+#define TARGET_HUPCL	0002000
+#define TARGET_CLOCAL	0004000
+#define TARGET_CBAUDEX 0010000
+#define	   TARGET_BOTHER 0010000		/* non standard rate */
+#define    TARGET_B57600 0010001
+#define   TARGET_B115200 0010002
+#define   TARGET_B230400 0010003
+#define   TARGET_B460800 0010004
+#define   TARGET_B500000 0010005
+#define   TARGET_B576000 0010006
+#define   TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD	  002003600000	/* input baud rate */
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+#define TARGET_IBSHIFT	  8		/* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0000001
+#define TARGET_ICANON	0000002
+#define TARGET_XCASE	0000004
+#define TARGET_ECHO	0000010
+#define TARGET_ECHOE	0000020
+#define TARGET_ECHOK	0000040
+#define TARGET_ECHONL	0000100
+#define TARGET_NOFLSH	0000200
+#define TARGET_TOSTOP	0000400
+#define TARGET_ECHOCTL	0001000
+#define TARGET_ECHOPRT	0002000
+#define TARGET_ECHOKE	0004000
+#define TARGET_FLUSHO	0010000
+#define TARGET_PENDIN	0040000
+#define TARGET_IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TARGET_TCOOFF		0
+#define	TARGET_TCOON		1
+#define	TARGET_TCIOFF		2
+#define	TARGET_TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TARGET_TCIFLUSH	0
+#define	TARGET_TCOFLUSH	1
+#define	TARGET_TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TARGET_TCSANOW		0
+#define	TARGET_TCSADRAIN	1
+#define	TARGET_TCSAFLUSH	2
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TARGET_TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TARGET_TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TARGET_TCSETSF2	_IOW('T',0x2D, struct termios2)
+#define TARGET_TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TARGET_FIOQSIZE       0x5460
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/qemu-0.15.x/m68k-dis.c b/qemu-0.15.x/m68k-dis.c
new file mode 100644
index 0000000..04f837a
--- /dev/null
+++ b/qemu-0.15.x/m68k-dis.c
@@ -0,0 +1,5051 @@
+/* This file is composed of several different files from the upstream
+   sourceware.org CVS.  Original file boundaries marked with **** */
+
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "dis-asm.h"
+
+/* **** floatformat.h from sourceware.org CVS 2005-08-14.  */
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+   Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#if !defined (FLOATFORMAT_H)
+#define FLOATFORMAT_H 1
+
+/*#include "ansidecl.h" */
+
+/* A floatformat consists of a sign bit, an exponent and a mantissa.  Once the
+   bytes are concatenated according to the byteorder flag, then each of those
+   fields is contiguous.  We number the bits with 0 being the most significant
+   (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field
+   contains with the *_start and *_len fields.  */
+
+/* What is the order of the bytes. */
+
+enum floatformat_byteorders {
+
+  /* Standard little endian byte order.
+     EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */
+
+  floatformat_little,
+
+  /* Standard big endian byte order.
+     EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */
+
+  floatformat_big,
+
+  /* Little endian byte order but big endian word order.
+     EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */
+
+  floatformat_littlebyte_bigword
+
+};
+
+enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no };
+
+struct floatformat
+{
+  enum floatformat_byteorders byteorder;
+  unsigned int totalsize;	/* Total size of number in bits */
+
+  /* Sign bit is always one bit long.  1 means negative, 0 means positive.  */
+  unsigned int sign_start;
+
+  unsigned int exp_start;
+  unsigned int exp_len;
+  /* Bias added to a "true" exponent to form the biased exponent.  It
+     is intentionally signed as, otherwize, -exp_bias can turn into a
+     very large number (e.g., given the exp_bias of 0x3fff and a 64
+     bit long, the equation (long)(1 - exp_bias) evaluates to
+     4294950914) instead of -16382).  */
+  int exp_bias;
+  /* Exponent value which indicates NaN.  This is the actual value stored in
+     the float, not adjusted by the exp_bias.  This usually consists of all
+     one bits.  */
+  unsigned int exp_nan;
+
+  unsigned int man_start;
+  unsigned int man_len;
+
+  /* Is the integer bit explicit or implicit?  */
+  enum floatformat_intbit intbit;
+
+  /* Internal name for debugging. */
+  const char *name;
+
+  /* Validator method.  */
+  int (*is_valid) (const struct floatformat *fmt, const char *from);
+};
+
+/* floatformats for IEEE single and double, big and little endian.  */
+
+extern const struct floatformat floatformat_ieee_single_big;
+extern const struct floatformat floatformat_ieee_single_little;
+extern const struct floatformat floatformat_ieee_double_big;
+extern const struct floatformat floatformat_ieee_double_little;
+
+/* floatformat for ARM IEEE double, little endian bytes and big endian words */
+
+extern const struct floatformat floatformat_ieee_double_littlebyte_bigword;
+
+/* floatformats for various extendeds.  */
+
+extern const struct floatformat floatformat_i387_ext;
+extern const struct floatformat floatformat_m68881_ext;
+extern const struct floatformat floatformat_i960_ext;
+extern const struct floatformat floatformat_m88110_ext;
+extern const struct floatformat floatformat_m88110_harris_ext;
+extern const struct floatformat floatformat_arm_ext_big;
+extern const struct floatformat floatformat_arm_ext_littlebyte_bigword;
+/* IA-64 Floating Point register spilt into memory.  */
+extern const struct floatformat floatformat_ia64_spill_big;
+extern const struct floatformat floatformat_ia64_spill_little;
+extern const struct floatformat floatformat_ia64_quad_big;
+extern const struct floatformat floatformat_ia64_quad_little;
+
+/* Convert from FMT to a double.
+   FROM is the address of the extended float.
+   Store the double in *TO.  */
+
+extern void
+floatformat_to_double (const struct floatformat *, const char *, double *);
+
+/* The converse: convert the double *FROM to FMT
+   and store where TO points.  */
+
+extern void
+floatformat_from_double (const struct floatformat *, const double *, char *);
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT.  */
+
+extern int
+floatformat_is_valid (const struct floatformat *fmt, const char *from);
+
+#endif	/* defined (FLOATFORMAT_H) */
+/* **** End of floatformat.h */
+/* **** m68k-dis.h from sourceware.org CVS 2005-08-14.  */
+/* Opcode table header for m680[01234]0/m6888[12]/m68851.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001,
+   2003, 2004 Free Software Foundation, Inc.
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   1, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+/* These are used as bit flags for the arch field in the m68k_opcode
+   structure.  */
+#define	_m68k_undef  0
+#define	m68000   0x001
+#define	m68008   m68000 /* Synonym for -m68000.  otherwise unused.  */
+#define	m68010   0x002
+#define	m68020   0x004
+#define	m68030   0x008
+#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences;
+			   gas will deal with the few differences.  */
+#define	m68040   0x010
+/* There is no 68050.  */
+#define m68060   0x020
+#define	m68881   0x040
+#define	m68882   m68881 /* Synonym for -m68881.  otherwise unused.  */
+#define	m68851   0x080
+#define cpu32	 0x100		/* e.g., 68332 */
+
+#define mcfmac   0x200		/* ColdFire MAC. */
+#define mcfemac  0x400		/* ColdFire EMAC. */
+#define cfloat   0x800		/* ColdFire FPU.  */
+#define mcfhwdiv 0x1000		/* ColdFire hardware divide.  */
+
+#define mcfisa_a 0x2000		/* ColdFire ISA_A.  */
+#define mcfisa_aa 0x4000	/* ColdFire ISA_A+.  */
+#define mcfisa_b 0x8000		/* ColdFire ISA_B.  */
+#define mcfusp   0x10000	/* ColdFire USP instructions.  */
+
+#define mcf5200  0x20000
+#define mcf5206e 0x40000
+#define mcf521x  0x80000
+#define mcf5249  0x100000
+#define mcf528x  0x200000
+#define mcf5307  0x400000
+#define mcf5407  0x800000
+#define mcf5470  0x1000000
+#define mcf5480  0x2000000
+
+ /* Handy aliases.  */
+#define	m68040up   (m68040 | m68060)
+#define	m68030up   (m68030 | m68040up)
+#define	m68020up   (m68020 | m68030up)
+#define	m68010up   (m68010 | cpu32 | m68020up)
+#define	m68000up   (m68000 | m68010up)
+
+#define	mfloat  (m68881 | m68882 | m68040 | m68060)
+#define	mmmu    (m68851 | m68030 | m68040 | m68060)
+
+/* The structure used to hold information for an opcode.  */
+
+struct m68k_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+  /* The pseudo-size of the instruction(in bytes).  Used to determine
+     number of bytes necessary to disassemble the instruction.  */
+  unsigned int size;
+  /* The opcode itself.  */
+  unsigned long opcode;
+  /* The mask used by the disassembler.  */
+  unsigned long match;
+  /* The arguments.  */
+  const char *args;
+  /* The architectures which support this opcode.  */
+  unsigned int arch;
+};
+
+/* The structure used to hold information for an opcode alias.  */
+
+struct m68k_opcode_alias
+{
+  /* The alias name.  */
+  const char *alias;
+  /* The instruction for which this is an alias.  */
+  const char *primary;
+};
+
+/* We store four bytes of opcode for all opcodes because that is the
+   most any of them need.  The actual length of an instruction is
+   always at least 2 bytes, and is as much longer as necessary to hold
+   the operands it has.
+
+   The match field is a mask saying which bits must match particular
+   opcode in order for an instruction to be an instance of that
+   opcode.
+
+   The args field is a string containing two characters for each
+   operand of the instruction.  The first specifies the kind of
+   operand; the second, the place it is stored.  */
+
+/* Kinds of operands:
+   Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+-
+
+   D  data register only.  Stored as 3 bits.
+   A  address register only.  Stored as 3 bits.
+   a  address register indirect only.  Stored as 3 bits.
+   R  either kind of register.  Stored as 4 bits.
+   r  either kind of register indirect only.  Stored as 4 bits.
+      At the moment, used only for cas2 instruction.
+   F  floating point coprocessor register only.   Stored as 3 bits.
+   O  an offset (or width): immediate data 0-31 or data register.
+      Stored as 6 bits in special format for BF... insns.
+   +  autoincrement only.  Stored as 3 bits (number of the address register).
+   -  autodecrement only.  Stored as 3 bits (number of the address register).
+   Q  quick immediate data.  Stored as 3 bits.
+      This matches an immediate operand only when value is in range 1 .. 8.
+   M  moveq immediate data.  Stored as 8 bits.
+      This matches an immediate operand only when value is in range -128..127
+   T  trap vector immediate data.  Stored as 4 bits.
+
+   k  K-factor for fmove.p instruction.   Stored as a 7-bit constant or
+      a three bit register offset, depending on the field type.
+
+   #  immediate data.  Stored in special places (b, w or l)
+      which say how many bits to store.
+   ^  immediate data for floating point instructions.   Special places
+      are offset by 2 bytes from '#'...
+   B  pc-relative address, converted to an offset
+      that is treated as immediate data.
+   d  displacement and register.  Stores the register as 3 bits
+      and stores the displacement in the entire second word.
+
+   C  the CCR.  No need to store it; this is just for filtering validity.
+   S  the SR.  No need to store, just as with CCR.
+   U  the USP.  No need to store, just as with CCR.
+   E  the MAC ACC.  No need to store, just as with CCR.
+   e  the EMAC ACC[0123].
+   G  the MAC/EMAC MACSR.  No need to store, just as with CCR.
+   g  the EMAC ACCEXT{01,23}.
+   H  the MASK.  No need to store, just as with CCR.
+   i  the MAC/EMAC scale factor.
+
+   I  Coprocessor ID.   Not printed if 1.   The Coprocessor ID is always
+      extracted from the 'd' field of word one, which means that an extended
+      coprocessor opcode can be skipped using the 'i' place, if needed.
+
+   s  System Control register for the floating point coprocessor.
+
+   J  Misc register for movec instruction, stored in 'j' format.
+	Possible values:
+	0x000	SFC	Source Function Code reg	[60, 40, 30, 20, 10]
+	0x001	DFC	Data Function Code reg		[60, 40, 30, 20, 10]
+	0x002   CACR    Cache Control Register          [60, 40, 30, 20, mcf]
+	0x003	TC	MMU Translation Control		[60, 40]
+	0x004	ITT0	Instruction Transparent
+				Translation reg 0	[60, 40]
+	0x005	ITT1	Instruction Transparent
+				Translation reg 1	[60, 40]
+	0x006	DTT0	Data Transparent
+				Translation reg 0	[60, 40]
+	0x007	DTT1	Data Transparent
+				Translation reg 1	[60, 40]
+	0x008	BUSCR	Bus Control Register		[60]
+	0x800	USP	User Stack Pointer		[60, 40, 30, 20, 10]
+        0x801   VBR     Vector Base reg                 [60, 40, 30, 20, 10, mcf]
+	0x802	CAAR	Cache Address Register		[        30, 20]
+	0x803	MSP	Master Stack Pointer		[    40, 30, 20]
+	0x804	ISP	Interrupt Stack Pointer		[    40, 30, 20]
+	0x805	MMUSR	MMU Status reg			[    40]
+	0x806	URP	User Root Pointer		[60, 40]
+	0x807	SRP	Supervisor Root Pointer		[60, 40]
+	0x808	PCR	Processor Configuration reg	[60]
+	0xC00	ROMBAR	ROM Base Address Register	[520X]
+	0xC04	RAMBAR0	RAM Base Address Register 0	[520X]
+	0xC05	RAMBAR1	RAM Base Address Register 0	[520X]
+	0xC0F	MBAR0	RAM Base Address Register 0	[520X]
+        0xC04   FLASHBAR FLASH Base Address Register    [mcf528x]
+        0xC05   RAMBAR  Static RAM Base Address Register [mcf528x]
+
+    L  Register list of the type d0-d7/a0-a7 etc.
+       (New!  Improved!  Can also hold fp0-fp7, as well!)
+       The assembler tries to see if the registers match the insn by
+       looking at where the insn wants them stored.
+
+    l  Register list like L, but with all the bits reversed.
+       Used for going the other way. . .
+
+    c  cache identifier which may be "nc" for no cache, "ic"
+       for instruction cache, "dc" for data cache, or "bc"
+       for both caches.  Used in cinv and cpush.  Always
+       stored in position "d".
+
+    u  Any register, with ``upper'' or ``lower'' specification.  Used
+       in the mac instructions with size word.
+
+ The remainder are all stored as 6 bits using an address mode and a
+ register number; they differ in which addressing modes they match.
+
+   *  all					(modes 0-6,7.0-4)
+   ~  alterable memory				(modes 2-6,7.0,7.1)
+   						(not 0,1,7.2-4)
+   %  alterable					(modes 0-6,7.0,7.1)
+						(not 7.2-4)
+   ;  data					(modes 0,2-6,7.0-4)
+						(not 1)
+   @  data, but not immediate			(modes 0,2-6,7.0-3)
+						(not 1,7.4)
+   !  control					(modes 2,5,6,7.0-3)
+						(not 0,1,3,4,7.4)
+   &  alterable control				(modes 2,5,6,7.0,7.1)
+						(not 0,1,3,4,7.2-4)
+   $  alterable data				(modes 0,2-6,7.0,7.1)
+						(not 1,7.2-4)
+   ?  alterable control, or data register	(modes 0,2,5,6,7.0,7.1)
+						(not 1,3,4,7.2-4)
+   /  control, or data register			(modes 0,2,5,6,7.0-3)
+						(not 1,3,4,7.4)
+   >  *save operands				(modes 2,4,5,6,7.0,7.1)
+						(not 0,1,3,7.2-4)
+   <  *restore operands				(modes 2,3,5,6,7.0-3)
+						(not 0,1,4,7.4)
+
+   coldfire move operands:
+   m  						(modes 0-4)
+   n						(modes 5,7.2)
+   o						(modes 6,7.0,7.1,7.3,7.4)
+   p						(modes 0-5)
+
+   coldfire bset/bclr/btst/mulsl/mulul operands:
+   q						(modes 0,2-5)
+   v						(modes 0,2-5,7.0,7.1)
+   b                                            (modes 0,2-5,7.2)
+   w                                            (modes 2-5,7.2)
+   y						(modes 2,5)
+   z						(modes 2,5,7.2)
+   x  mov3q immediate operand.
+   4						(modes 2,3,4,5)
+  */
+
+/* For the 68851:  */
+/* I didn't use much imagination in choosing the
+   following codes, so many of them aren't very
+   mnemonic. -rab
+
+   0  32 bit pmmu register
+	Possible values:
+	000	TC	Translation Control Register (68030, 68851)
+
+   1  16 bit pmmu register
+	111	AC	Access Control (68851)
+
+   2  8 bit pmmu register
+	100	CAL	Current Access Level (68851)
+	101	VAL	Validate Access Level (68851)
+	110	SCC	Stack Change Control (68851)
+
+   3  68030-only pmmu registers (32 bit)
+	010	TT0	Transparent Translation reg 0
+			(aka Access Control reg 0 -- AC0 -- on 68ec030)
+	011	TT1	Transparent Translation reg 1
+			(aka Access Control reg 1 -- AC1 -- on 68ec030)
+
+   W  wide pmmu registers
+	Possible values:
+	001	DRP	Dma Root Pointer (68851)
+	010	SRP	Supervisor Root Pointer (68030, 68851)
+	011	CRP	Cpu Root Pointer (68030, 68851)
+
+   f	function code register (68030, 68851)
+	0	SFC
+	1	DFC
+
+   V	VAL register only (68851)
+
+   X	BADx, BACx (16 bit)
+	100	BAD	Breakpoint Acknowledge Data (68851)
+	101	BAC	Breakpoint Acknowledge Control (68851)
+
+   Y	PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030)
+   Z	PCSR (68851)
+
+   |	memory 		(modes 2-6, 7.*)
+
+   t  address test level (68030 only)
+      Stored as 3 bits, range 0-7.
+      Also used for breakpoint instruction now.
+
+*/
+
+/* Places to put an operand, for non-general operands:
+   Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/
+
+   s  source, low bits of first word.
+   d  dest, shifted 9 in first word
+   1  second word, shifted 12
+   2  second word, shifted 6
+   3  second word, shifted 0
+   4  third word, shifted 12
+   5  third word, shifted 6
+   6  third word, shifted 0
+   7  second word, shifted 7
+   8  second word, shifted 10
+   9  second word, shifted 5
+   D  store in both place 1 and place 3; for divul and divsl.
+   B  first word, low byte, for branch displacements
+   W  second word (entire), for branch displacements
+   L  second and third words (entire), for branch displacements
+      (also overloaded for move16)
+   b  second word, low byte
+   w  second word (entire) [variable word/long branch offset for dbra]
+   W  second word (entire) (must be signed 16 bit value)
+   l  second and third word (entire)
+   g  variable branch offset for bra and similar instructions.
+      The place to store depends on the magnitude of offset.
+   t  store in both place 7 and place 8; for floating point operations
+   c  branch offset for cpBcc operations.
+      The place to store is word two if bit six of word one is zero,
+      and words two and three if bit six of word one is one.
+   i  Increment by two, to skip over coprocessor extended operands.   Only
+      works with the 'I' format.
+   k  Dynamic K-factor field.   Bits 6-4 of word 2, used as a register number.
+      Also used for dynamic fmovem instruction.
+   C  floating point coprocessor constant - 7 bits.  Also used for static
+      K-factors...
+   j  Movec register #, stored in 12 low bits of second word.
+   m  For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word
+      and remaining 3 bits of register shifted 9 bits in first word.
+      Indicate upper/lower in 1 bit shifted 7 bits in second word.
+      Use with `R' or `u' format.
+   n  `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split
+      with MSB shifted 6 bits in first word and remaining 3 bits of
+      register shifted 9 bits in first word.  No upper/lower
+      indication is done.)  Use with `R' or `u' format.
+   o  For M[S]ACw; 4 bits shifted 12 in second word (like `1').
+      Indicate upper/lower in 1 bit shifted 7 bits in second word.
+      Use with `R' or `u' format.
+   M  For M[S]ACw; 4 bits in low bits of first word.  Indicate
+      upper/lower in 1 bit shifted 6 bits in second word.  Use with
+      `R' or `u' format.
+   N  For M[S]ACw; 4 bits in low bits of second word.  Indicate
+      upper/lower in 1 bit shifted 6 bits in second word.  Use with
+      `R' or `u' format.
+   h  shift indicator (scale factor), 1 bit shifted 10 in second word
+
+ Places to put operand, for general operands:
+   d  destination, shifted 6 bits in first word
+   b  source, at low bit of first word, and immediate uses one byte
+   w  source, at low bit of first word, and immediate uses two bytes
+   l  source, at low bit of first word, and immediate uses four bytes
+   s  source, at low bit of first word.
+      Used sometimes in contexts where immediate is not allowed anyway.
+   f  single precision float, low bit of 1st word, immediate uses 4 bytes
+   F  double precision float, low bit of 1st word, immediate uses 8 bytes
+   x  extended precision float, low bit of 1st word, immediate uses 12 bytes
+   p  packed float, low bit of 1st word, immediate uses 12 bytes
+   G  EMAC accumulator, load  (bit 4 2nd word, !bit8 first word)
+   H  EMAC accumulator, non load  (bit 4 2nd word, bit 8 first word)
+   F  EMAC ACCx
+   f  EMAC ACCy
+   I  MAC/EMAC scale factor
+   /  Like 's', but set 2nd word, bit 5 if trailing_ampersand set
+   ]  first word, bit 10
+*/
+
+extern const struct m68k_opcode m68k_opcodes[];
+extern const struct m68k_opcode_alias m68k_opcode_aliases[];
+
+extern const int m68k_numopcodes, m68k_numaliases;
+
+/* **** End of m68k-opcode.h */
+/* **** m68k-dis.c from sourceware.org CVS 2005-08-14.  */
+/* Print Motorola 68k instructions.
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* Local function prototypes.  */
+
+static const char * const fpcr_names[] =
+{
+  "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
+  "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
+};
+
+static const char *const reg_names[] =
+{
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
+  "%ps", "%pc"
+};
+
+/* Name of register halves for MAC/EMAC.
+   Separate from reg_names since 'spu', 'fpl' look weird.  */
+static const char *const reg_half_names[] =
+{
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
+  "%ps", "%pc"
+};
+
+/* Sign-extend an (unsigned char).  */
+#if __STDC__ == 1
+#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch))
+#else
+#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128)
+#endif
+
+/* Get a 1 byte signed integer.  */
+#define NEXTBYTE(p)  (p += 2, fetch_data(info, p), COERCE_SIGNED_CHAR(p[-1]))
+
+/* Get a 2 byte signed integer.  */
+#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
+#define NEXTWORD(p)  \
+  (p += 2, fetch_data(info, p), \
+   COERCE16 ((p[-2] << 8) + p[-1]))
+
+/* Get a 4 byte signed integer.  */
+#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
+#define NEXTLONG(p)  \
+  (p += 4, fetch_data(info, p), \
+   (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
+
+/* Get a 4 byte unsigned integer.  */
+#define NEXTULONG(p)  \
+  (p += 4, fetch_data(info, p), \
+   (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
+
+/* Get a single precision float.  */
+#define NEXTSINGLE(val, p) \
+  (p += 4, fetch_data(info, p), \
+   floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
+
+/* Get a double precision float.  */
+#define NEXTDOUBLE(val, p) \
+  (p += 8, fetch_data(info, p), \
+   floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
+
+/* Get an extended precision float.  */
+#define NEXTEXTEND(val, p) \
+  (p += 12, fetch_data(info, p), \
+   floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
+
+/* Need a function to convert from packed to double
+   precision.   Actually, it's easier to print a
+   packed number than a double anyway, so maybe
+   there should be a special case to handle this... */
+#define NEXTPACKED(p) \
+  (p += 12, fetch_data(info, p), 0.0)
+
+/* Maximum length of an instruction.  */
+#define MAXLEN 22
+
+#include <setjmp.h>
+
+struct private
+{
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAXLEN];
+  bfd_vma insn_start;
+  jmp_buf bailout;
+};
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
+   on error.  */
+static int
+fetch_data2(struct disassemble_info *info, bfd_byte *addr)
+{
+  int status;
+  struct private *priv = (struct private *)info->private_data;
+  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+  status = (*info->read_memory_func) (start,
+				      priv->max_fetched,
+				      addr - priv->max_fetched,
+				      info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, start, info);
+      longjmp (priv->bailout, 1);
+    }
+  else
+    priv->max_fetched = addr;
+  return 1;
+}
+
+static int
+fetch_data(struct disassemble_info *info, bfd_byte *addr)
+{
+    if (addr <= ((struct private *) (info->private_data))->max_fetched) {
+        return 1;
+    } else {
+        return fetch_data2(info, addr);
+    }
+}
+
+/* This function is used to print to the bit-bucket.  */
+static int
+dummy_printer (FILE *file ATTRIBUTE_UNUSED,
+	       const char *format ATTRIBUTE_UNUSED,
+	       ...)
+{
+  return 0;
+}
+
+static void
+dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED,
+		     struct disassemble_info *info ATTRIBUTE_UNUSED)
+{
+}
+
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+   CODE is a "place to put an argument", or 'x' for a destination
+   that is a general address (mode and register).
+   BUFFER contains the instruction.  */
+
+static int
+fetch_arg (unsigned char *buffer,
+	   int code,
+	   int bits,
+	   disassemble_info *info)
+{
+  int val = 0;
+
+  switch (code)
+    {
+    case '/': /* MAC/EMAC mask bit.  */
+      val = buffer[3] >> 5;
+      break;
+
+    case 'G': /* EMAC ACC load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
+      break;
+
+    case 'H': /* EMAC ACC !load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
+      break;
+
+    case ']': /* EMAC ACCEXT bit.  */
+      val = buffer[0] >> 2;
+      break;
+
+    case 'I': /* MAC/EMAC scale factor.  */
+      val = buffer[2] >> 1;
+      break;
+
+    case 'F': /* EMAC ACCx.  */
+      val = buffer[0] >> 1;
+      break;
+
+    case 'f':
+      val = buffer[1];
+      break;
+
+    case 's':
+      val = buffer[1];
+      break;
+
+    case 'd':			/* Destination, for register or quick.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 9;
+      break;
+
+    case 'x':			/* Destination, for general arg.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 6;
+      break;
+
+    case 'k':
+      fetch_data(info, buffer + 3);
+      val = (buffer[3] >> 4);
+      break;
+
+    case 'C':
+      fetch_data(info, buffer + 3);
+      val = buffer[3];
+      break;
+
+    case '1':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 12;
+      break;
+
+    case '2':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 6;
+      break;
+
+    case '3':
+    case 'j':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      break;
+
+    case '4':
+      fetch_data(info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 12;
+      break;
+
+    case '5':
+      fetch_data(info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 6;
+      break;
+
+    case '6':
+      fetch_data(info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      break;
+
+    case '7':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 7;
+      break;
+
+    case '8':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 10;
+      break;
+
+    case '9':
+      fetch_data(info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 5;
+      break;
+
+    case 'e':
+      val = (buffer[1] >> 6);
+      break;
+
+    case 'm':
+      val = (buffer[1] & 0x40 ? 0x8 : 0)
+	| ((buffer[0] >> 1) & 0x7)
+	| (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
+
+    case 'n':
+      val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
+      break;
+
+    case 'o':
+      val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
+
+    case 'M':
+      val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
+
+    case 'N':
+      val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
+
+    case 'h':
+      val = buffer[2] >> 2;
+      break;
+
+    default:
+      abort ();
+    }
+
+  switch (bits)
+    {
+    case 1:
+      return val & 1;
+    case 2:
+      return val & 3;
+    case 3:
+      return val & 7;
+    case 4:
+      return val & 017;
+    case 5:
+      return val & 037;
+    case 6:
+      return val & 077;
+    case 7:
+      return val & 0177;
+    case 8:
+      return val & 0377;
+    case 12:
+      return val & 07777;
+    default:
+      abort ();
+    }
+}
+
+/* Check if an EA is valid for a particular code.  This is required
+   for the EMAC instructions since the type of source address determines
+   if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
+   is a non-load EMAC instruction and the bits mean register Ry.
+   A similar case exists for the movem instructions where the register
+   mask is interpreted differently for different EAs.  */
+
+static bfd_boolean
+m68k_valid_ea (char code, int val)
+{
+  int mode, mask;
+#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
+  (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
+   | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
+
+  switch (code)
+    {
+    case '*':
+      mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
+      break;
+    case '~':
+      mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case '%':
+      mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case ';':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
+      break;
+    case '@':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
+      break;
+    case '!':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '&':
+      mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
+      break;
+    case '$':
+      mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case '?':
+      mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
+      break;
+    case '/':
+      mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '|':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '>':
+      mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
+      break;
+    case '<':
+      mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
+      break;
+    case 'm':
+      mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
+      break;
+    case 'n':
+      mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
+      break;
+    case 'o':
+      mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
+      break;
+    case 'p':
+      mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'q':
+      mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'v':
+      mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
+      break;
+    case 'b':
+      mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'w':
+      mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'y':
+      mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
+      break;
+    case 'z':
+      mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
+      break;
+    case '4':
+      mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
+      break;
+    default:
+      abort ();
+    }
+#undef M
+
+  mode = (val >> 3) & 7;
+  if (mode == 7)
+    mode += val & 7;
+  return (mask & (1 << mode)) != 0;
+}
+
+/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
+   REGNO = -1 for pc, -2 for none (suppressed).  */
+
+static void
+print_base (int regno, bfd_vma disp, disassemble_info *info)
+{
+  if (regno == -1)
+    {
+      (*info->fprintf_func) (info->stream, "%%pc@(");
+      (*info->print_address_func) (disp, info);
+    }
+  else
+    {
+      char buf[50];
+
+      if (regno == -2)
+	(*info->fprintf_func) (info->stream, "@(");
+      else if (regno == -3)
+	(*info->fprintf_func) (info->stream, "%%zpc@(");
+      else
+	(*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
+
+      sprintf_vma (buf, disp);
+      (*info->fprintf_func) (info->stream, "%s", buf);
+    }
+}
+
+/* Print an indexed argument.  The base register is BASEREG (-1 for pc).
+   P points to extension word, in buffer.
+   ADDR is the nominal core address of that extension word.  */
+
+static unsigned char *
+print_indexed (int basereg,
+	       unsigned char *p,
+	       bfd_vma addr,
+	       disassemble_info *info)
+{
+  int word;
+  static const char *const scales[] = { "", ":2", ":4", ":8" };
+  bfd_vma base_disp;
+  bfd_vma outer_disp;
+  char buf[40];
+  char vmabuf[50];
+
+  word = NEXTWORD (p);
+
+  /* Generate the text for the index register.
+     Where this will be output is not yet determined.  */
+  sprintf (buf, "%s:%c%s",
+	   reg_names[(word >> 12) & 0xf],
+	   (word & 0x800) ? 'l' : 'w',
+	   scales[(word >> 9) & 3]);
+
+  /* Handle the 68000 style of indexing.  */
+
+  if ((word & 0x100) == 0)
+    {
+      base_disp = word & 0xff;
+      if ((base_disp & 0x80) != 0)
+	base_disp -= 0x100;
+      if (basereg == -1)
+	base_disp += addr;
+      print_base (basereg, base_disp, info);
+      (*info->fprintf_func) (info->stream, ",%s)", buf);
+      return p;
+    }
+
+  /* Handle the generalized kind.  */
+  /* First, compute the displacement to add to the base register.  */
+  if (word & 0200)
+    {
+      if (basereg == -1)
+	basereg = -3;
+      else
+	basereg = -2;
+    }
+  if (word & 0100)
+    buf[0] = '\0';
+  base_disp = 0;
+  switch ((word >> 4) & 3)
+    {
+    case 2:
+      base_disp = NEXTWORD (p);
+      break;
+    case 3:
+      base_disp = NEXTLONG (p);
+    }
+  if (basereg == -1)
+    base_disp += addr;
+
+  /* Handle single-level case (not indirect).  */
+  if ((word & 7) == 0)
+    {
+      print_base (basereg, base_disp, info);
+      if (buf[0] != '\0')
+	(*info->fprintf_func) (info->stream, ",%s", buf);
+      (*info->fprintf_func) (info->stream, ")");
+      return p;
+    }
+
+  /* Two level.  Compute displacement to add after indirection.  */
+  outer_disp = 0;
+  switch (word & 3)
+    {
+    case 2:
+      outer_disp = NEXTWORD (p);
+      break;
+    case 3:
+      outer_disp = NEXTLONG (p);
+    }
+
+  print_base (basereg, base_disp, info);
+  if ((word & 4) == 0 && buf[0] != '\0')
+    {
+      (*info->fprintf_func) (info->stream, ",%s", buf);
+      buf[0] = '\0';
+    }
+  sprintf_vma (vmabuf, outer_disp);
+  (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
+  if (buf[0] != '\0')
+    (*info->fprintf_func) (info->stream, ",%s", buf);
+  (*info->fprintf_func) (info->stream, ")");
+
+  return p;
+}
+
+/* Returns number of bytes "eaten" by the operand, or
+   return -1 if an invalid operand was found, or -2 if
+   an opcode tabe error was found.
+   ADDR is the pc for this arg to be relative to.  */
+
+static int
+print_insn_arg (const char *d,
+		unsigned char *buffer,
+		unsigned char *p0,
+		bfd_vma addr,
+		disassemble_info *info)
+{
+  int val = 0;
+  int place = d[1];
+  unsigned char *p = p0;
+  int regno;
+  const char *regname;
+  unsigned char *p1;
+  double flval;
+  int flt_p;
+  bfd_signed_vma disp;
+  unsigned int uval;
+
+  switch (*d)
+    {
+    case 'c':		/* Cache identifier.  */
+      {
+        static const char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
+        val = fetch_arg (buffer, place, 2, info);
+        (*info->fprintf_func) (info->stream, "%s", cacheFieldName[val]);
+        break;
+      }
+
+    case 'a':		/* Address register indirect only. Cf. case '+'.  */
+      {
+        (*info->fprintf_func)
+	  (info->stream,
+	   "%s@",
+	   reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+        break;
+      }
+
+    case '_':		/* 32-bit absolute address for move16.  */
+      {
+        uval = NEXTULONG (p);
+	(*info->print_address_func) (uval, info);
+        break;
+      }
+
+    case 'C':
+      (*info->fprintf_func) (info->stream, "%%ccr");
+      break;
+
+    case 'S':
+      (*info->fprintf_func) (info->stream, "%%sr");
+      break;
+
+    case 'U':
+      (*info->fprintf_func) (info->stream, "%%usp");
+      break;
+
+    case 'E':
+      (*info->fprintf_func) (info->stream, "%%acc");
+      break;
+
+    case 'G':
+      (*info->fprintf_func) (info->stream, "%%macsr");
+      break;
+
+    case 'H':
+      (*info->fprintf_func) (info->stream, "%%mask");
+      break;
+
+    case 'J':
+      {
+	/* FIXME: There's a problem here, different m68k processors call the
+	   same address different names. This table can't get it right
+	   because it doesn't know which processor it's disassembling for.  */
+	static const struct { const char *name; int value; } names[]
+	  = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
+	     {"%tc",  0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
+             {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
+	     {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
+	     {"%msp", 0x803}, {"%isp", 0x804},
+	     {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these.  */
+
+	     /* Should we be calling this psr like we do in case 'Y'?  */
+	     {"%mmusr",0x805},
+
+             {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}};
+
+	val = fetch_arg (buffer, place, 12, info);
+	for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+	  if (names[regno].value == val)
+	    {
+	      (*info->fprintf_func) (info->stream, "%s", names[regno].name);
+	      break;
+	    }
+	if (regno < 0)
+	  (*info->fprintf_func) (info->stream, "%d", val);
+      }
+      break;
+
+    case 'Q':
+      val = fetch_arg (buffer, place, 3, info);
+      /* 0 means 8, except for the bkpt instruction... */
+      if (val == 0 && d[1] != 's')
+	val = 8;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'x':
+      val = fetch_arg (buffer, place, 3, info);
+      /* 0 means -1.  */
+      if (val == 0)
+	val = -1;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'M':
+      if (place == 'h')
+	{
+	  static const char *const scalefactor_name[] = { "<<", ">>" };
+	  val = fetch_arg (buffer, place, 1, info);
+	  (*info->fprintf_func) (info->stream, "%s", scalefactor_name[val]);
+	}
+      else
+	{
+	  val = fetch_arg (buffer, place, 8, info);
+	  if (val & 0x80)
+	    val = val - 0x100;
+	  (*info->fprintf_func) (info->stream, "#%d", val);
+	}
+      break;
+
+    case 'T':
+      val = fetch_arg (buffer, place, 4, info);
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'D':
+      (*info->fprintf_func) (info->stream, "%s",
+			     reg_names[fetch_arg (buffer, place, 3, info)]);
+      break;
+
+    case 'A':
+      (*info->fprintf_func)
+	(info->stream, "%s",
+	 reg_names[fetch_arg (buffer, place, 3, info) + 010]);
+      break;
+
+    case 'R':
+      (*info->fprintf_func)
+	(info->stream, "%s",
+	 reg_names[fetch_arg (buffer, place, 4, info)]);
+      break;
+
+    case 'r':
+      regno = fetch_arg (buffer, place, 4, info);
+      if (regno > 7)
+	(*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
+      else
+	(*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]);
+      break;
+
+    case 'F':
+      (*info->fprintf_func)
+	(info->stream, "%%fp%d",
+	 fetch_arg (buffer, place, 3, info));
+      break;
+
+    case 'O':
+      val = fetch_arg (buffer, place, 6, info);
+      if (val & 0x20)
+	(*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
+      else
+	(*info->fprintf_func) (info->stream, "%d", val);
+      break;
+
+    case '+':
+      (*info->fprintf_func)
+	(info->stream, "%s at +",
+	 reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      break;
+
+    case '-':
+      (*info->fprintf_func)
+	(info->stream, "%s at -",
+	 reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      break;
+
+    case 'k':
+      if (place == 'k')
+	(*info->fprintf_func)
+	  (info->stream, "{%s}",
+	   reg_names[fetch_arg (buffer, place, 3, info)]);
+      else if (place == 'C')
+	{
+	  val = fetch_arg (buffer, place, 7, info);
+	  if (val > 63)		/* This is a signed constant.  */
+	    val -= 128;
+	  (*info->fprintf_func) (info->stream, "{#%d}", val);
+	}
+      else
+	return -2;
+      break;
+
+    case '#':
+    case '^':
+      p1 = buffer + (*d == '#' ? 2 : 4);
+      if (place == 's')
+	val = fetch_arg (buffer, place, 4, info);
+      else if (place == 'C')
+	val = fetch_arg (buffer, place, 7, info);
+      else if (place == '8')
+	val = fetch_arg (buffer, place, 3, info);
+      else if (place == '3')
+	val = fetch_arg (buffer, place, 8, info);
+      else if (place == 'b')
+	val = NEXTBYTE (p1);
+      else if (place == 'w' || place == 'W')
+	val = NEXTWORD (p1);
+      else if (place == 'l')
+	val = NEXTLONG (p1);
+      else
+	return -2;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'B':
+      if (place == 'b')
+	disp = NEXTBYTE (p);
+      else if (place == 'B')
+	disp = COERCE_SIGNED_CHAR (buffer[1]);
+      else if (place == 'w' || place == 'W')
+	disp = NEXTWORD (p);
+      else if (place == 'l' || place == 'L' || place == 'C')
+	disp = NEXTLONG (p);
+      else if (place == 'g')
+	{
+	  disp = NEXTBYTE (buffer);
+	  if (disp == 0)
+	    disp = NEXTWORD (p);
+	  else if (disp == -1)
+	    disp = NEXTLONG (p);
+	}
+      else if (place == 'c')
+	{
+	  if (buffer[1] & 0x40)		/* If bit six is one, long offset.  */
+	    disp = NEXTLONG (p);
+	  else
+	    disp = NEXTWORD (p);
+	}
+      else
+	return -2;
+
+      (*info->print_address_func) (addr + disp, info);
+      break;
+
+    case 'd':
+      val = NEXTWORD (p);
+      (*info->fprintf_func)
+	(info->stream, "%s@(%d)",
+	 reg_names[fetch_arg (buffer, place, 3, info) + 8], val);
+      break;
+
+    case 's':
+      (*info->fprintf_func) (info->stream, "%s",
+			     fpcr_names[fetch_arg (buffer, place, 3, info)]);
+      break;
+
+    case 'e':
+      val = fetch_arg(buffer, place, 2, info);
+      (*info->fprintf_func) (info->stream, "%%acc%d", val);
+      break;
+
+    case 'g':
+      val = fetch_arg(buffer, place, 1, info);
+      (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
+      break;
+
+    case 'i':
+      val = fetch_arg(buffer, place, 2, info);
+      if (val == 1)
+	(*info->fprintf_func) (info->stream, "<<");
+      else if (val == 3)
+	(*info->fprintf_func) (info->stream, ">>");
+      else
+	return -1;
+      break;
+
+    case 'I':
+      /* Get coprocessor ID... */
+      val = fetch_arg (buffer, 'd', 3, info);
+
+      if (val != 1)				/* Unusual coprocessor ID?  */
+	(*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
+      break;
+
+    case '4':
+    case '*':
+    case '~':
+    case '%':
+    case ';':
+    case '@':
+    case '!':
+    case '$':
+    case '?':
+    case '/':
+    case '&':
+    case '|':
+    case '<':
+    case '>':
+    case 'm':
+    case 'n':
+    case 'o':
+    case 'p':
+    case 'q':
+    case 'v':
+    case 'b':
+    case 'w':
+    case 'y':
+    case 'z':
+      if (place == 'd')
+	{
+	  val = fetch_arg (buffer, 'x', 6, info);
+	  val = ((val & 7) << 3) + ((val >> 3) & 7);
+	}
+      else
+	val = fetch_arg (buffer, 's', 6, info);
+
+      /* If the <ea> is invalid for *d, then reject this match.  */
+      if (!m68k_valid_ea (*d, val))
+	return -1;
+
+      /* Get register number assuming address register.  */
+      regno = (val & 7) + 8;
+      regname = reg_names[regno];
+      switch (val >> 3)
+	{
+	case 0:
+	  (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
+	  break;
+
+	case 1:
+	  (*info->fprintf_func) (info->stream, "%s", regname);
+	  break;
+
+	case 2:
+	  (*info->fprintf_func) (info->stream, "%s@", regname);
+	  break;
+
+	case 3:
+	  (*info->fprintf_func) (info->stream, "%s at +", regname);
+	  break;
+
+	case 4:
+	  (*info->fprintf_func) (info->stream, "%s at -", regname);
+	  break;
+
+	case 5:
+	  val = NEXTWORD (p);
+	  (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
+	  break;
+
+	case 6:
+	  p = print_indexed (regno, p, addr, info);
+	  break;
+
+	case 7:
+	  switch (val & 7)
+	    {
+	    case 0:
+	      val = NEXTWORD (p);
+	      (*info->print_address_func) (val, info);
+	      break;
+
+	    case 1:
+	      uval = NEXTULONG (p);
+	      (*info->print_address_func) (uval, info);
+	      break;
+
+	    case 2:
+	      val = NEXTWORD (p);
+	      (*info->fprintf_func) (info->stream, "%%pc@(");
+	      (*info->print_address_func) (addr + val, info);
+	      (*info->fprintf_func) (info->stream, ")");
+	      break;
+
+	    case 3:
+	      p = print_indexed (-1, p, addr, info);
+	      break;
+
+	    case 4:
+	      flt_p = 1;	/* Assume it's a float... */
+	      switch (place)
+	      {
+		case 'b':
+		  val = NEXTBYTE (p);
+		  flt_p = 0;
+		  break;
+
+		case 'w':
+		  val = NEXTWORD (p);
+		  flt_p = 0;
+		  break;
+
+		case 'l':
+		  val = NEXTLONG (p);
+		  flt_p = 0;
+		  break;
+
+		case 'f':
+		  NEXTSINGLE (flval, p);
+		  break;
+
+		case 'F':
+		  NEXTDOUBLE (flval, p);
+		  break;
+
+		case 'x':
+		  NEXTEXTEND (flval, p);
+		  break;
+
+		case 'p':
+		  flval = NEXTPACKED (p);
+		  break;
+
+		default:
+		  return -1;
+	      }
+	      if (flt_p)	/* Print a float? */
+		(*info->fprintf_func) (info->stream, "#%g", flval);
+	      else
+		(*info->fprintf_func) (info->stream, "#%d", val);
+	      break;
+
+	    default:
+	      return -1;
+	    }
+	}
+
+      /* If place is '/', then this is the case of the mask bit for
+	 mac/emac loads. Now that the arg has been printed, grab the
+	 mask bit and if set, add a '&' to the arg.  */
+      if (place == '/')
+	{
+	  val = fetch_arg (buffer, place, 1, info);
+	  if (val)
+	    info->fprintf_func (info->stream, "&");
+	}
+      break;
+
+    case 'L':
+    case 'l':
+	if (place == 'w')
+	  {
+	    char doneany;
+	    p1 = buffer + 2;
+	    val = NEXTWORD (p1);
+	    /* Move the pointer ahead if this point is farther ahead
+	       than the last.  */
+	    p = p1 > p ? p1 : p;
+	    if (val == 0)
+	      {
+		(*info->fprintf_func) (info->stream, "#0");
+		break;
+	      }
+	    if (*d == 'l')
+	      {
+		int newval = 0;
+
+		for (regno = 0; regno < 16; ++regno)
+		  if (val & (0x8000 >> regno))
+		    newval |= 1 << regno;
+		val = newval;
+	      }
+	    val &= 0xffff;
+	    doneany = 0;
+	    for (regno = 0; regno < 16; ++regno)
+	      if (val & (1 << regno))
+		{
+		  int first_regno;
+
+		  if (doneany)
+		    (*info->fprintf_func) (info->stream, "/");
+		  doneany = 1;
+		  (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
+		  first_regno = regno;
+		  while (val & (1 << (regno + 1)))
+		    ++regno;
+		  if (regno > first_regno)
+		    (*info->fprintf_func) (info->stream, "-%s",
+					   reg_names[regno]);
+		}
+	  }
+	else if (place == '3')
+	  {
+	    /* `fmovem' insn.  */
+	    char doneany;
+	    val = fetch_arg (buffer, place, 8, info);
+	    if (val == 0)
+	      {
+		(*info->fprintf_func) (info->stream, "#0");
+		break;
+	      }
+	    if (*d == 'l')
+	      {
+		int newval = 0;
+
+		for (regno = 0; regno < 8; ++regno)
+		  if (val & (0x80 >> regno))
+		    newval |= 1 << regno;
+		val = newval;
+	      }
+	    val &= 0xff;
+	    doneany = 0;
+	    for (regno = 0; regno < 8; ++regno)
+	      if (val & (1 << regno))
+		{
+		  int first_regno;
+		  if (doneany)
+		    (*info->fprintf_func) (info->stream, "/");
+		  doneany = 1;
+		  (*info->fprintf_func) (info->stream, "%%fp%d", regno);
+		  first_regno = regno;
+		  while (val & (1 << (regno + 1)))
+		    ++regno;
+		  if (regno > first_regno)
+		    (*info->fprintf_func) (info->stream, "-%%fp%d", regno);
+		}
+	  }
+	else if (place == '8')
+	  {
+	    /* fmoveml for FP status registers.  */
+	    (*info->fprintf_func) (info->stream, "%s",
+				   fpcr_names[fetch_arg (buffer, place, 3,
+							 info)]);
+	  }
+	else
+	  return -2;
+      break;
+
+    case 'X':
+      place = '8';
+    case 'Y':
+    case 'Z':
+    case 'W':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+      {
+	int val = fetch_arg (buffer, place, 5, info);
+        const char *name = 0;
+
+	switch (val)
+	  {
+	  case 2: name = "%tt0"; break;
+	  case 3: name = "%tt1"; break;
+	  case 0x10: name = "%tc"; break;
+	  case 0x11: name = "%drp"; break;
+	  case 0x12: name = "%srp"; break;
+	  case 0x13: name = "%crp"; break;
+	  case 0x14: name = "%cal"; break;
+	  case 0x15: name = "%val"; break;
+	  case 0x16: name = "%scc"; break;
+	  case 0x17: name = "%ac"; break;
+ 	  case 0x18: name = "%psr"; break;
+	  case 0x19: name = "%pcsr"; break;
+	  case 0x1c:
+	  case 0x1d:
+	    {
+	      int break_reg = ((buffer[3] >> 2) & 7);
+
+	      (*info->fprintf_func)
+		(info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d",
+		 break_reg);
+	    }
+	    break;
+	  default:
+	    (*info->fprintf_func) (info->stream, "<mmu register %d>", val);
+	  }
+	if (name)
+	  (*info->fprintf_func) (info->stream, "%s", name);
+      }
+      break;
+
+    case 'f':
+      {
+	int fc = fetch_arg (buffer, place, 5, info);
+
+	if (fc == 1)
+	  (*info->fprintf_func) (info->stream, "%%dfc");
+	else if (fc == 0)
+	  (*info->fprintf_func) (info->stream, "%%sfc");
+	else
+	  /* xgettext:c-format */
+	  (*info->fprintf_func) (info->stream, _("<function code %d>"), fc);
+      }
+      break;
+
+    case 'V':
+      (*info->fprintf_func) (info->stream, "%%val");
+      break;
+
+    case 't':
+      {
+	int level = fetch_arg (buffer, place, 3, info);
+
+	(*info->fprintf_func) (info->stream, "%d", level);
+      }
+      break;
+
+    case 'u':
+      {
+	short is_upper = 0;
+	int reg = fetch_arg (buffer, place, 5, info);
+
+	if (reg & 0x10)
+	  {
+	    is_upper = 1;
+	    reg &= 0xf;
+	  }
+	(*info->fprintf_func) (info->stream, "%s%s",
+			       reg_half_names[reg],
+			       is_upper ? "u" : "l");
+      }
+      break;
+
+    default:
+      return -2;
+    }
+
+  return p - p0;
+}
+
+/* Try to match the current instruction to best and if so, return the
+   number of bytes consumed from the instruction stream, else zero.  */
+
+static int
+match_insn_m68k (bfd_vma memaddr,
+		 disassemble_info * info,
+		 const struct m68k_opcode * best,
+		 struct private * priv)
+{
+  unsigned char *save_p;
+  unsigned char *p;
+  const char *d;
+
+  bfd_byte *buffer = priv->the_buffer;
+  fprintf_function save_printer = info->fprintf_func;
+  void (* save_print_address) (bfd_vma, struct disassemble_info *)
+    = info->print_address_func;
+
+  /* Point at first word of argument data,
+     and at descriptor for first argument.  */
+  p = buffer + 2;
+
+  /* Figure out how long the fixed-size portion of the instruction is.
+     The only place this is stored in the opcode table is
+     in the arguments--look for arguments which specify fields in the 2nd
+     or 3rd words of the instruction.  */
+  for (d = best->args; *d; d += 2)
+    {
+      /* I don't think it is necessary to be checking d[0] here;
+	 I suspect all this could be moved to the case statement below.  */
+      if (d[0] == '#')
+	{
+	  if (d[1] == 'l' && p - buffer < 6)
+	    p = buffer + 6;
+	  else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
+	    p = buffer + 4;
+	}
+
+      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+	p = buffer + 4;
+
+      switch (d[1])
+	{
+	case '1':
+	case '2':
+	case '3':
+	case '7':
+	case '8':
+	case '9':
+	case 'i':
+	  if (p - buffer < 4)
+	    p = buffer + 4;
+	  break;
+	case '4':
+	case '5':
+	case '6':
+	  if (p - buffer < 6)
+	    p = buffer + 6;
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  /* pflusha is an exceptions.  It takes no arguments but is two words
+     long.  Recognize it by looking at the lower 16 bits of the mask.  */
+  if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
+    p = buffer + 4;
+
+  /* lpstop is another exception.  It takes a one word argument but is
+     three words long.  */
+  if (p - buffer < 6
+      && (best->match & 0xffff) == 0xffff
+      && best->args[0] == '#'
+      && best->args[1] == 'w')
+    {
+      /* Copy the one word argument into the usual location for a one
+	 word argument, to simplify printing it.  We can get away with
+	 this because we know exactly what the second word is, and we
+	 aren't going to print anything based on it.  */
+      p = buffer + 6;
+      fetch_data(info, p);
+      buffer[2] = buffer[4];
+      buffer[3] = buffer[5];
+    }
+
+  fetch_data(info, p);
+
+  d = best->args;
+
+  save_p = p;
+  info->print_address_func = dummy_print_address;
+  info->fprintf_func = dummy_printer;
+
+  /* We scan the operands twice.  The first time we don't print anything,
+     but look for errors.  */
+  for (; *d; d += 2)
+    {
+      int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+
+      if (eaten >= 0)
+	p += eaten;
+      else if (eaten == -1)
+	{
+	  info->fprintf_func = save_printer;
+	  info->print_address_func = save_print_address;
+	  return 0;
+	}
+      else
+	{
+	  info->fprintf_func (info->stream,
+			      /* xgettext:c-format */
+			      _("<internal error in opcode table: %s %s>\n"),
+			      best->name,  best->args);
+	  info->fprintf_func = save_printer;
+	  info->print_address_func = save_print_address;
+	  return 2;
+	}
+    }
+
+  p = save_p;
+  info->fprintf_func = save_printer;
+  info->print_address_func = save_print_address;
+
+  d = best->args;
+
+  info->fprintf_func (info->stream, "%s", best->name);
+
+  if (*d)
+    info->fprintf_func (info->stream, " ");
+
+  while (*d)
+    {
+      p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+      d += 2;
+
+      if (*d && *(d - 2) != 'I' && *d != 'k')
+	info->fprintf_func (info->stream, ",");
+    }
+
+  return p - buffer;
+}
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
+{
+  int i;
+  const char *d;
+  unsigned int arch_mask;
+  struct private priv;
+  bfd_byte *buffer = priv.the_buffer;
+  int major_opcode;
+  static int numopcodes[16];
+  static const struct m68k_opcode **opcodes[16];
+  int val;
+
+  if (!opcodes[0])
+    {
+      /* Speed up the matching by sorting the opcode
+	 table on the upper four bits of the opcode.  */
+      const struct m68k_opcode **opc_pointer[16];
+
+      /* First count how many opcodes are in each of the sixteen buckets.  */
+      for (i = 0; i < m68k_numopcodes; i++)
+	numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
+
+      /* Then create a sorted table of pointers
+	 that point into the unsorted table.  */
+      opc_pointer[0] = malloc (sizeof (struct m68k_opcode *)
+                               * m68k_numopcodes);
+      opcodes[0] = opc_pointer[0];
+
+      for (i = 1; i < 16; i++)
+	{
+	  opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
+	  opcodes[i] = opc_pointer[i];
+	}
+
+      for (i = 0; i < m68k_numopcodes; i++)
+	*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
+    }
+
+  info->private_data = (PTR) &priv;
+  /* Tell objdump to use two bytes per chunk
+     and six bytes per line for displaying raw data.  */
+  info->bytes_per_chunk = 2;
+  info->bytes_per_line = 6;
+  info->display_endian = BFD_ENDIAN_BIG;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = memaddr;
+
+  if (setjmp (priv.bailout) != 0)
+    /* Error return.  */
+    return -1;
+
+  switch (info->mach)
+    {
+    default:
+    case 0:
+      arch_mask = (unsigned int) -1;
+      break;
+    case bfd_mach_m68000:
+      arch_mask = m68000|m68881|m68851;
+      break;
+    case bfd_mach_m68008:
+      arch_mask = m68008|m68881|m68851;
+      break;
+    case bfd_mach_m68010:
+      arch_mask = m68010|m68881|m68851;
+      break;
+    case bfd_mach_m68020:
+      arch_mask = m68020|m68881|m68851;
+      break;
+    case bfd_mach_m68030:
+      arch_mask = m68030|m68881|m68851;
+      break;
+    case bfd_mach_m68040:
+      arch_mask = m68040|m68881|m68851;
+      break;
+    case bfd_mach_m68060:
+      arch_mask = m68060|m68881|m68851;
+      break;
+    case bfd_mach_mcf5200:
+      arch_mask = mcfisa_a;
+      break;
+    case bfd_mach_mcf521x:
+    case bfd_mach_mcf528x:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac;
+      break;
+    case bfd_mach_mcf5206e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5249:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfemac;
+      break;
+    case bfd_mach_mcf5307:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5407:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac;
+      break;
+    case bfd_mach_mcf547x:
+    case bfd_mach_mcf548x:
+    case bfd_mach_mcfv4e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac;
+      break;
+    }
+
+  fetch_data(info, buffer + 2);
+  major_opcode = (buffer[0] >> 4) & 15;
+
+  for (i = 0; i < numopcodes[major_opcode]; i++)
+    {
+      const struct m68k_opcode *opc = opcodes[major_opcode][i];
+      unsigned long opcode = opc->opcode;
+      unsigned long match = opc->match;
+
+      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+	  && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+	  /* Only fetch the next two bytes if we need to.  */
+	  && (((0xffff & match) == 0)
+	      ||
+              (fetch_data(info, buffer + 4)
+	       && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+	       && ((0xff & buffer[3] & match) == (0xff & opcode)))
+	      )
+	  && (opc->arch & arch_mask) != 0)
+	{
+	  /* Don't use for printout the variants of divul and divsl
+	     that have the same register number in two places.
+	     The more general variants will match instead.  */
+	  for (d = opc->args; *d; d += 2)
+	    if (d[1] == 'D')
+	      break;
+
+	  /* Don't use for printout the variants of most floating
+	     point coprocessor instructions which use the same
+	     register number in two places, as above.  */
+	  if (*d == '\0')
+	    for (d = opc->args; *d; d += 2)
+	      if (d[1] == 't')
+		break;
+
+	  /* Don't match fmovel with more than one register;
+	     wait for fmoveml.  */
+	  if (*d == '\0')
+	    {
+	      for (d = opc->args; *d; d += 2)
+		{
+		  if (d[0] == 's' && d[1] == '8')
+		    {
+		      val = fetch_arg (buffer, d[1], 3, info);
+		      if ((val & (val - 1)) != 0)
+			break;
+		    }
+		}
+	    }
+
+	  if (*d == '\0')
+	    if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
+	      return val;
+	}
+    }
+
+  /* Handle undefined instructions.  */
+  info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
+  return 2;
+}
+/* **** End of m68k-dis.c */
+/* **** m68k-opc.h from sourceware.org CVS 2005-08-14.  */
+/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   1, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+#define one(x) ((unsigned int) (x) << 16)
+#define two(x, y) (((unsigned int) (x) << 16) + (y))
+
+/* The assembler requires that all instances of the same mnemonic must
+   be consecutive.  If they aren't, the assembler will bomb at
+   runtime.  */
+
+const struct m68k_opcode m68k_opcodes[] =
+{
+{"abcd", 2,	one(0140400),	one(0170770), "DsDd", m68000up },
+{"abcd", 2,	one(0140410),	one(0170770), "-s-d", m68000up },
+
+{"addaw", 2,	one(0150300),	one(0170700), "*wAd", m68000up },
+{"addal", 2,	one(0150700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+
+{"addib", 4,	one(0003000),	one(0177700), "#b$s", m68000up },
+{"addiw", 4,	one(0003100),	one(0177700), "#w$s", m68000up },
+{"addil", 6,	one(0003200),	one(0177700), "#l$s", m68000up },
+{"addil", 6,	one(0003200),	one(0177700), "#lDs", mcfisa_a },
+
+{"addqb", 2,	one(0050000),	one(0170700), "Qd$b", m68000up },
+{"addqw", 2,	one(0050100),	one(0170700), "Qd%w", m68000up },
+{"addql", 2,	one(0050200),	one(0170700), "Qd%l", m68000up | mcfisa_a },
+
+/* The add opcode can generate the adda, addi, and addq instructions.  */
+{"addb", 2,	one(0050000),	one(0170700), "Qd$b", m68000up },
+{"addb", 4,	one(0003000),	one(0177700), "#b$s", m68000up },
+{"addb", 2,	one(0150000),	one(0170700), ";bDd", m68000up },
+{"addb", 2,	one(0150400),	one(0170700), "Dd~b", m68000up },
+{"addw", 2,	one(0050100),	one(0170700), "Qd%w", m68000up },
+{"addw", 2,	one(0150300),	one(0170700), "*wAd", m68000up },
+{"addw", 4,	one(0003100),	one(0177700), "#w$s", m68000up },
+{"addw", 2,	one(0150100),	one(0170700), "*wDd", m68000up },
+{"addw", 2,	one(0150500),	one(0170700), "Dd~w", m68000up },
+{"addl", 2,	one(0050200),	one(0170700), "Qd%l", m68000up | mcfisa_a },
+{"addl", 6,	one(0003200),	one(0177700), "#l$s", m68000up },
+{"addl", 6,	one(0003200),	one(0177700), "#lDs", mcfisa_a },
+{"addl", 2,	one(0150700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+{"addl", 2,	one(0150200),	one(0170700), "*lDd", m68000up | mcfisa_a },
+{"addl", 2,	one(0150600),	one(0170700), "Dd~l", m68000up | mcfisa_a },
+
+{"addxb", 2,	one(0150400),	one(0170770), "DsDd", m68000up },
+{"addxb", 2,	one(0150410),	one(0170770), "-s-d", m68000up },
+{"addxw", 2,	one(0150500),	one(0170770), "DsDd", m68000up },
+{"addxw", 2,	one(0150510),	one(0170770), "-s-d", m68000up },
+{"addxl", 2,	one(0150600),	one(0170770), "DsDd", m68000up | mcfisa_a },
+{"addxl", 2,	one(0150610),	one(0170770), "-s-d", m68000up },
+
+{"andib", 4,	one(0001000),	one(0177700), "#b$s", m68000up },
+{"andib", 4,	one(0001074),	one(0177777), "#bCs", m68000up },
+{"andiw", 4,	one(0001100),	one(0177700), "#w$s", m68000up },
+{"andiw", 4,	one(0001174),	one(0177777), "#wSs", m68000up },
+{"andil", 6,	one(0001200),	one(0177700), "#l$s", m68000up },
+{"andil", 6,	one(0001200),	one(0177700), "#lDs", mcfisa_a },
+{"andi", 4,	one(0001100),	one(0177700), "#w$s", m68000up },
+{"andi", 4,	one(0001074),	one(0177777), "#bCs", m68000up },
+{"andi", 4,	one(0001174),	one(0177777), "#wSs", m68000up },
+
+/* The and opcode can generate the andi instruction.  */
+{"andb", 4,	one(0001000),	one(0177700), "#b$s", m68000up },
+{"andb", 4,	one(0001074),	one(0177777), "#bCs", m68000up },
+{"andb", 2,	one(0140000),	one(0170700), ";bDd", m68000up },
+{"andb", 2,	one(0140400),	one(0170700), "Dd~b", m68000up },
+{"andw", 4,	one(0001100),	one(0177700), "#w$s", m68000up },
+{"andw", 4,	one(0001174),	one(0177777), "#wSs", m68000up },
+{"andw", 2,	one(0140100),	one(0170700), ";wDd", m68000up },
+{"andw", 2,	one(0140500),	one(0170700), "Dd~w", m68000up },
+{"andl", 6,	one(0001200),	one(0177700), "#l$s", m68000up },
+{"andl", 6,	one(0001200),	one(0177700), "#lDs", mcfisa_a },
+{"andl", 2,	one(0140200),	one(0170700), ";lDd", m68000up | mcfisa_a },
+{"andl", 2,	one(0140600),	one(0170700), "Dd~l", m68000up | mcfisa_a },
+{"and", 4,	one(0001100),	one(0177700), "#w$w", m68000up },
+{"and", 4,	one(0001074),	one(0177777), "#bCs", m68000up },
+{"and", 4,	one(0001174),	one(0177777), "#wSs", m68000up },
+{"and", 2,	one(0140100),	one(0170700), ";wDd", m68000up },
+{"and", 2,	one(0140500),	one(0170700), "Dd~w", m68000up },
+
+{"aslb", 2,	one(0160400),	one(0170770), "QdDs", m68000up },
+{"aslb", 2,	one(0160440),	one(0170770), "DdDs", m68000up },
+{"aslw", 2,	one(0160500),	one(0170770), "QdDs", m68000up },
+{"aslw", 2,	one(0160540),	one(0170770), "DdDs", m68000up },
+{"aslw", 2,	one(0160700),	one(0177700), "~s",   m68000up },
+{"asll", 2,	one(0160600),	one(0170770), "QdDs", m68000up | mcfisa_a },
+{"asll", 2,	one(0160640),	one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"asrb", 2,	one(0160000),	one(0170770), "QdDs", m68000up },
+{"asrb", 2,	one(0160040),	one(0170770), "DdDs", m68000up },
+{"asrw", 2,	one(0160100),	one(0170770), "QdDs", m68000up },
+{"asrw", 2,	one(0160140),	one(0170770), "DdDs", m68000up },
+{"asrw", 2,	one(0160300),	one(0177700), "~s",   m68000up },
+{"asrl", 2,	one(0160200),	one(0170770), "QdDs", m68000up | mcfisa_a },
+{"asrl", 2,	one(0160240),	one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"bhiw", 2,	one(0061000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"blsw", 2,	one(0061400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bccw", 2,	one(0062000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bcsw", 2,	one(0062400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bnew", 2,	one(0063000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"beqw", 2,	one(0063400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bvcw", 2,	one(0064000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bvsw", 2,	one(0064400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bplw", 2,	one(0065000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bmiw", 2,	one(0065400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bgew", 2,	one(0066000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bltw", 2,	one(0066400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bgtw", 2,	one(0067000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"blew", 2,	one(0067400),	one(0177777), "BW", m68000up | mcfisa_a },
+
+{"bhil", 2,	one(0061377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"blsl", 2,	one(0061777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bccl", 2,	one(0062377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bcsl", 2,	one(0062777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bnel", 2,	one(0063377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"beql", 2,	one(0063777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bvcl", 2,	one(0064377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bvsl", 2,	one(0064777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bpll", 2,	one(0065377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bmil", 2,	one(0065777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bgel", 2,	one(0066377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bltl", 2,	one(0066777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bgtl", 2,	one(0067377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"blel", 2,	one(0067777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+
+{"bhis", 2,	one(0061000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"blss", 2,	one(0061400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bccs", 2,	one(0062000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bcss", 2,	one(0062400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bnes", 2,	one(0063000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"beqs", 2,	one(0063400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bvcs", 2,	one(0064000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bvss", 2,	one(0064400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bpls", 2,	one(0065000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bmis", 2,	one(0065400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bges", 2,	one(0066000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"blts", 2,	one(0066400),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bgts", 2,	one(0067000),	one(0177400), "BB", m68000up | mcfisa_a },
+{"bles", 2,	one(0067400),	one(0177400), "BB", m68000up | mcfisa_a },
+
+{"jhi", 2,	one(0061000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jls", 2,	one(0061400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jcc", 2,	one(0062000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jcs", 2,	one(0062400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jne", 2,	one(0063000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jeq", 2,	one(0063400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jvc", 2,	one(0064000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jvs", 2,	one(0064400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jpl", 2,	one(0065000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jmi", 2,	one(0065400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jge", 2,	one(0066000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jlt", 2,	one(0066400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jgt", 2,	one(0067000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jle", 2,	one(0067400),	one(0177400), "Bg", m68000up | mcfisa_a },
+
+{"bchg", 2,	one(0000500),	one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bchg", 4,	one(0004100),	one(0177700), "#b$s", m68000up },
+{"bchg", 4,	one(0004100),	one(0177700), "#bqs", mcfisa_a },
+
+{"bclr", 2,	one(0000600),	one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bclr", 4,	one(0004200),	one(0177700), "#b$s", m68000up },
+{"bclr", 4,	one(0004200),	one(0177700), "#bqs", mcfisa_a },
+
+{"bfchg", 4,	two(0165300, 0), two(0177700, 0170000),	"?sO2O3",   m68020up },
+{"bfclr", 4,	two(0166300, 0), two(0177700, 0170000),	"?sO2O3",   m68020up },
+{"bfexts", 4,	two(0165700, 0), two(0177700, 0100000),	"/sO2O3D1", m68020up },
+{"bfextu", 4,	two(0164700, 0), two(0177700, 0100000),	"/sO2O3D1", m68020up },
+{"bfffo", 4,	two(0166700, 0), two(0177700, 0100000),	"/sO2O3D1", m68020up },
+{"bfins", 4,	two(0167700, 0), two(0177700, 0100000),	"D1?sO2O3", m68020up },
+{"bfset", 4,	two(0167300, 0), two(0177700, 0170000),	"?sO2O3",   m68020up },
+{"bftst", 4,	two(0164300, 0), two(0177700, 0170000),	"/sO2O3",   m68020up },
+
+{"bgnd", 2,	one(0045372),	one(0177777), "", cpu32 },
+
+{"bitrev", 2,	one(0000300),	one(0177770), "Ds", mcfisa_aa},
+
+{"bkpt", 2,	one(0044110),	one(0177770), "ts", m68010up },
+
+{"braw", 2,	one(0060000),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bral", 2,	one(0060377),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bras", 2,	one(0060000),	one(0177400), "BB", m68000up | mcfisa_a },
+
+{"bset", 2,	one(0000700),	one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bset", 2,	one(0000700),	one(0170700), "Ddvs", mcfisa_a },
+{"bset", 4,	one(0004300),	one(0177700), "#b$s", m68000up },
+{"bset", 4,	one(0004300),	one(0177700), "#bqs", mcfisa_a },
+
+{"bsrw", 2,	one(0060400),	one(0177777), "BW", m68000up | mcfisa_a },
+{"bsrl", 2,	one(0060777),	one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bsrs", 2,	one(0060400),	one(0177400), "BB", m68000up | mcfisa_a },
+
+{"btst", 2,	one(0000400),	one(0170700), "Dd;b", m68000up | mcfisa_a },
+{"btst", 4,	one(0004000),	one(0177700), "#b at s", m68000up },
+{"btst", 4,	one(0004000),	one(0177700), "#bqs", mcfisa_a },
+
+{"byterev", 2,	one(0001300),	one(0177770), "Ds", mcfisa_aa},
+
+{"callm", 4,	one(0003300),	one(0177700), "#b!s", m68020 },
+
+{"cas2w", 6,    two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
+{"cas2w", 6,    two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
+{"cas2l", 6,    two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
+{"cas2l", 6,    two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
+
+{"casb", 4,	two(0005300, 0), two(0177700, 0177070),	"D3D2~s", m68020up },
+{"casw", 4,	two(0006300, 0), two(0177700, 0177070),	"D3D2~s", m68020up },
+{"casl", 4,	two(0007300, 0), two(0177700, 0177070),	"D3D2~s", m68020up },
+
+{"chk2b", 4, 	two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"chk2w", 4, 	two(0001300,0004000),	two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"chk2l", 4, 	two(0002300,0004000),	two(0177700,07777), "!sR1", m68020up | cpu32 },
+
+{"chkl", 2,	one(0040400),		one(0170700), ";lDd", m68000up },
+{"chkw", 2,	one(0040600),		one(0170700), ";wDd", m68000up },
+
+#define SCOPE_LINE (0x1 << 3)
+#define SCOPE_PAGE (0x2 << 3)
+#define SCOPE_ALL  (0x3 << 3)
+
+{"cinva", 2,	one(0xf400|SCOPE_ALL),  one(0xff38), "ce",   m68040up },
+{"cinvl", 2,	one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up },
+{"cinvp", 2,	one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
+
+{"cpusha", 2,	one(0xf420|SCOPE_ALL),  one(0xff38), "ce",   m68040up },
+{"cpushl", 2,	one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a },
+{"cpushp", 2,	one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
+
+#undef SCOPE_LINE
+#undef SCOPE_PAGE
+#undef SCOPE_ALL
+
+{"clrb", 2,	one(0041000),	one(0177700), "$s", m68000up | mcfisa_a },
+{"clrw", 2,	one(0041100),	one(0177700), "$s", m68000up | mcfisa_a },
+{"clrl", 2,	one(0041200),	one(0177700), "$s", m68000up | mcfisa_a },
+
+{"cmp2b", 4,	two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"cmp2w", 4,	two(0001300,0),	two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"cmp2l", 4,	two(0002300,0),	two(0177700,07777), "!sR1", m68020up | cpu32 },
+
+{"cmpaw", 2,	one(0130300),	one(0170700), "*wAd", m68000up },
+{"cmpal", 2,	one(0130700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+
+{"cmpib", 4,	one(0006000),	one(0177700), "#b at s", m68000up },
+{"cmpib", 4,	one(0006000),	one(0177700), "#bDs", mcfisa_b },
+{"cmpiw", 4,	one(0006100),	one(0177700), "#w at s", m68000up },
+{"cmpiw", 4,	one(0006100),	one(0177700), "#wDs", mcfisa_b },
+{"cmpil", 6,	one(0006200),	one(0177700), "#l at s", m68000up },
+{"cmpil", 6,	one(0006200),	one(0177700), "#lDs", mcfisa_a },
+
+{"cmpmb", 2,	one(0130410),	one(0170770), "+s+d", m68000up },
+{"cmpmw", 2,	one(0130510),	one(0170770), "+s+d", m68000up },
+{"cmpml", 2,	one(0130610),	one(0170770), "+s+d", m68000up },
+
+/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions.  */
+{"cmpb", 4,	one(0006000),	one(0177700), "#b at s", m68000up },
+{"cmpb", 4,	one(0006000),	one(0177700), "#bDs", mcfisa_b },
+{"cmpb", 2,	one(0130410),	one(0170770), "+s+d", m68000up },
+{"cmpb", 2,	one(0130000),	one(0170700), ";bDd", m68000up },
+{"cmpb", 2,	one(0130000),	one(0170700), "*bDd", mcfisa_b },
+{"cmpw", 2,	one(0130300),	one(0170700), "*wAd", m68000up },
+{"cmpw", 4,	one(0006100),	one(0177700), "#w at s", m68000up },
+{"cmpw", 4,	one(0006100),	one(0177700), "#wDs", mcfisa_b },
+{"cmpw", 2,	one(0130510),	one(0170770), "+s+d", m68000up },
+{"cmpw", 2,	one(0130100),	one(0170700), "*wDd", m68000up | mcfisa_b },
+{"cmpl", 2,	one(0130700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+{"cmpl", 6,	one(0006200),	one(0177700), "#l at s", m68000up },
+{"cmpl", 6,	one(0006200),	one(0177700), "#lDs", mcfisa_a },
+{"cmpl", 2,	one(0130610),	one(0170770), "+s+d", m68000up },
+{"cmpl", 2,	one(0130200),	one(0170700), "*lDd", m68000up | mcfisa_a },
+
+{"dbcc", 2,	one(0052310),	one(0177770), "DsBw", m68000up },
+{"dbcs", 2,	one(0052710),	one(0177770), "DsBw", m68000up },
+{"dbeq", 2,	one(0053710),	one(0177770), "DsBw", m68000up },
+{"dbf", 2,	one(0050710),	one(0177770), "DsBw", m68000up },
+{"dbge", 2,	one(0056310),	one(0177770), "DsBw", m68000up },
+{"dbgt", 2,	one(0057310),	one(0177770), "DsBw", m68000up },
+{"dbhi", 2,	one(0051310),	one(0177770), "DsBw", m68000up },
+{"dble", 2,	one(0057710),	one(0177770), "DsBw", m68000up },
+{"dbls", 2,	one(0051710),	one(0177770), "DsBw", m68000up },
+{"dblt", 2,	one(0056710),	one(0177770), "DsBw", m68000up },
+{"dbmi", 2,	one(0055710),	one(0177770), "DsBw", m68000up },
+{"dbne", 2,	one(0053310),	one(0177770), "DsBw", m68000up },
+{"dbpl", 2,	one(0055310),	one(0177770), "DsBw", m68000up },
+{"dbt", 2,	one(0050310),	one(0177770), "DsBw", m68000up },
+{"dbvc", 2,	one(0054310),	one(0177770), "DsBw", m68000up },
+{"dbvs", 2,	one(0054710),	one(0177770), "DsBw", m68000up },
+
+{"divsw", 2,	one(0100700),	one(0170700), ";wDd", m68000up | mcfhwdiv },
+
+{"divsl", 4, 	two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
+{"divsl", 4, 	two(0046100,0004000),two(0177700,0107770),";lDD",   m68020up|cpu32 },
+{"divsl", 4, 	two(0046100,0004000),two(0177700,0107770),"qsDD",   mcfhwdiv },
+
+{"divsll", 4, 	two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
+{"divsll", 4, 	two(0046100,0004000),two(0177700,0107770),";lDD",  m68020up|cpu32 },
+
+{"divuw", 2,	one(0100300),		one(0170700), ";wDd", m68000up | mcfhwdiv },
+
+{"divul", 4,	two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
+{"divul", 4,	two(0046100,0000000),two(0177700,0107770),";lDD",   m68020up|cpu32 },
+{"divul", 4,	two(0046100,0000000),two(0177700,0107770),"qsDD",   mcfhwdiv },
+
+{"divull", 4,	two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
+{"divull", 4,	two(0046100,0000000),two(0177700,0107770),";lDD",  m68020up|cpu32 },
+
+{"eorib", 4,	one(0005000),	one(0177700), "#b$s", m68000up },
+{"eorib", 4,	one(0005074),	one(0177777), "#bCs", m68000up },
+{"eoriw", 4,	one(0005100),	one(0177700), "#w$s", m68000up },
+{"eoriw", 4,	one(0005174),	one(0177777), "#wSs", m68000up },
+{"eoril", 6,	one(0005200),	one(0177700), "#l$s", m68000up },
+{"eoril", 6,	one(0005200),	one(0177700), "#lDs", mcfisa_a },
+{"eori", 4,	one(0005074),	one(0177777), "#bCs", m68000up },
+{"eori", 4,	one(0005174),	one(0177777), "#wSs", m68000up },
+{"eori", 4,	one(0005100),	one(0177700), "#w$s", m68000up },
+
+/* The eor opcode can generate the eori instruction.  */
+{"eorb", 4,	one(0005000),	one(0177700), "#b$s", m68000up },
+{"eorb", 4,	one(0005074),	one(0177777), "#bCs", m68000up },
+{"eorb", 2,	one(0130400),	one(0170700), "Dd$s", m68000up },
+{"eorw", 4,	one(0005100),	one(0177700), "#w$s", m68000up },
+{"eorw", 4,	one(0005174),	one(0177777), "#wSs", m68000up },
+{"eorw", 2,	one(0130500),	one(0170700), "Dd$s", m68000up },
+{"eorl", 6,	one(0005200),	one(0177700), "#l$s", m68000up },
+{"eorl", 6,	one(0005200),	one(0177700), "#lDs", mcfisa_a },
+{"eorl", 2,	one(0130600),	one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"eor", 4,	one(0005074),	one(0177777), "#bCs", m68000up },
+{"eor", 4,	one(0005174),	one(0177777), "#wSs", m68000up },
+{"eor", 4,	one(0005100),	one(0177700), "#w$s", m68000up },
+{"eor", 2,	one(0130500),	one(0170700), "Dd$s", m68000up },
+
+{"exg", 2,	one(0140500),	one(0170770), "DdDs", m68000up },
+{"exg", 2,	one(0140510),	one(0170770), "AdAs", m68000up },
+{"exg", 2,	one(0140610),	one(0170770), "DdAs", m68000up },
+{"exg", 2,	one(0140610),	one(0170770), "AsDd", m68000up },
+
+{"extw", 2,	one(0044200),	one(0177770), "Ds", m68000up|mcfisa_a },
+{"extl", 2,	one(0044300),	one(0177770), "Ds", m68000up|mcfisa_a },
+{"extbl", 2,	one(0044700),	one(0177770), "Ds", m68020up|cpu32|mcfisa_a },
+
+{"ff1", 2,   	one(0002300), one(0177770), "Ds", mcfisa_aa},
+
+/* float stuff starts here */
+
+{"fabsb", 4,	two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fabsb", 4,	two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsd", 4,	two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fabsd", 4,	two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fabsd", 4,	two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fabsd", 4,	two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fabsl", 4,	two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fabsl", 4,	two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsp", 4,	two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fabss", 4,	two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat },
+{"fabss", 4,	two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fabsw", 4,	two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fabsw", 4,	two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsx", 4,	two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fabsx", 4,	two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fabsx", 4,	two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsabsb", 4,	two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsabsb", 4,	two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsd", 4,	two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsabsd", 4,	two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fsabsd", 4,	two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsabsd", 4,	two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsabsl", 4,	two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsabsl", 4,	two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsp", 4,	two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsabss", 4,	two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabss", 4,	two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsabsw", 4,	two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsabsw", 4,	two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsx", 4,	two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsabsx", 4,	two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsabsx", 4,	two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdabsb", 4,	two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsb", 4,	two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up},
+{"fdabsd", 4,	two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdabsd", 4,	two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fdabsd", 4,	two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdabsd", 4,	two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up},
+{"fdabsl", 4,	two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsl", 4,	two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up},
+{"fdabsp", 4,	two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up},
+{"fdabss", 4,	two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabss", 4,	two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up},
+{"fdabsw", 4,	two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsw", 4,	two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up},
+{"fdabsx", 4,	two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up},
+{"fdabsx", 4,	two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up},
+{"fdabsx", 4,	two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt",   m68040up},
+
+{"facosb", 4,	two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"facosd", 4,	two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"facosl", 4,	two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"facosp", 4,	two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"facoss", 4,	two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"facosw", 4,	two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"facosx", 4,	two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"facosx", 4,	two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"facosx", 4,	two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"faddb", 4,	two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"faddb", 4,	two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddd", 4,	two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"faddd", 4,	two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"faddd", 4,	two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"faddd", 4,	two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"faddl", 4,	two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"faddl", 4,	two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddp", 4,	two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fadds", 4,	two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fadds", 4,	two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddw", 4,	two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"faddw", 4,	two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddx", 4,	two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"faddx", 4,	two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsaddb", 4,	two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsaddb", 4,	two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddd", 4,	two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsaddd", 4,	two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsaddd", 4,	two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsaddl", 4,	two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsaddl", 4,	two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddp", 4,	two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsadds", 4,	two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsadds", 4,	two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddw", 4,	two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsaddw", 4,	two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddx", 4,	two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsaddx", 4,	two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fdaddb", 4,	two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddb", 4,	two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdaddd", 4,	two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdaddd", 4,	two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddd", 4,	two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdaddl", 4,	two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdaddl", 4,	two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdaddp", 4,	two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdadds", 4,	two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdadds", 4,	two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddw", 4,	two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddw", 4,	two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdaddx", 4,	two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdaddx", 4,	two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fasinb", 4,	two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fasind", 4,	two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fasinl", 4,	two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fasinp", 4,	two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fasins", 4,	two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fasinw", 4,	two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fasinx", 4,	two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fasinx", 4,	two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fasinx", 4,	two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fatanb", 4,	two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatand", 4,	two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanl", 4,	two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanp", 4,	two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatans", 4,	two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanw", 4,	two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanx", 4,	two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanx", 4,	two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanx", 4,	two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fatanhb", 4,	two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatanhd", 4,	two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanhl", 4,	two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanhp", 4,	two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatanhs", 4,	two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanhw", 4,	two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanhx", 4,	two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanhx", 4,	two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanhx", 4,	two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fbeq", 2,	one(0xF081),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbf", 2,	one(0xF080),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbge", 2,	one(0xF093),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgl", 2,	one(0xF096),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgle", 2,	one(0xF097),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgt", 2,	one(0xF092),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fble", 2,	one(0xF095),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fblt", 2,	one(0xF094),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbne", 2,	one(0xF08E),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnge", 2,	one(0xF09C),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngl", 2,	one(0xF099),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngle", 2,	one(0xF098),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngt", 2,	one(0xF09D),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnle", 2,	one(0xF09A),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnlt", 2,	one(0xF09B),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fboge", 2,	one(0xF083),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbogl", 2,	one(0xF086),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbogt", 2,	one(0xF082),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbole", 2,	one(0xF085),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbolt", 2,	one(0xF084),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbor", 2,	one(0xF087),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbseq", 2,	one(0xF091),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbsf", 2,	one(0xF090),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbsne", 2,	one(0xF09E),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbst", 2,	one(0xF09F),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbt", 2,	one(0xF08F),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbueq", 2,	one(0xF089),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbuge", 2,	one(0xF08B),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbugt", 2,	one(0xF08A),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbule", 2,	one(0xF08D),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbult", 2,	one(0xF08C),		one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbun", 2,	one(0xF088),		one(0xF1FF), "IdBW", mfloat | cfloat },
+
+{"fbeql", 2,	one(0xF0C1),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbfl", 2,	one(0xF0C0),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgel", 2,	one(0xF0D3),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgll", 2,	one(0xF0D6),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbglel", 2,	one(0xF0D7),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgtl", 2,	one(0xF0D2),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fblel", 2,	one(0xF0D5),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbltl", 2,	one(0xF0D4),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnel", 2,	one(0xF0CE),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngel", 2,	one(0xF0DC),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngll", 2,	one(0xF0D9),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnglel", 2,	one(0xF0D8),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngtl", 2,	one(0xF0DD),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnlel", 2,	one(0xF0DA),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnltl", 2,	one(0xF0DB),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogel", 2,	one(0xF0C3),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogll", 2,	one(0xF0C6),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogtl", 2,	one(0xF0C2),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbolel", 2,	one(0xF0C5),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fboltl", 2,	one(0xF0C4),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fborl", 2,	one(0xF0C7),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbseql", 2,	one(0xF0D1),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbsfl", 2,	one(0xF0D0),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbsnel", 2,	one(0xF0DE),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbstl", 2,	one(0xF0DF),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbtl", 2,	one(0xF0CF),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbueql", 2,	one(0xF0C9),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbugel", 2,	one(0xF0CB),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbugtl", 2,	one(0xF0CA),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbulel", 2,	one(0xF0CD),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbultl", 2,	one(0xF0CC),		one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbunl", 2,	one(0xF0C8),		one(0xF1FF), "IdBC", mfloat | cfloat },
+
+{"fjeq", 2,	one(0xF081),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjf", 2,	one(0xF080),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjge", 2,	one(0xF093),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgl", 2,	one(0xF096),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgle", 2,	one(0xF097),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgt", 2,	one(0xF092),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjle", 2,	one(0xF095),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjlt", 2,	one(0xF094),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjne", 2,	one(0xF08E),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnge", 2,	one(0xF09C),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngl", 2,	one(0xF099),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngle", 2,	one(0xF098),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngt", 2,	one(0xF09D),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnle", 2,	one(0xF09A),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnlt", 2,	one(0xF09B),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjoge", 2,	one(0xF083),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjogl", 2,	one(0xF086),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjogt", 2,	one(0xF082),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjole", 2,	one(0xF085),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjolt", 2,	one(0xF084),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjor", 2,	one(0xF087),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjseq", 2,	one(0xF091),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjsf", 2,	one(0xF090),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjsne", 2,	one(0xF09E),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjst", 2,	one(0xF09F),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjt", 2,	one(0xF08F),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjueq", 2,	one(0xF089),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjuge", 2,	one(0xF08B),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjugt", 2,	one(0xF08A),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjule", 2,	one(0xF08D),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjult", 2,	one(0xF08C),		one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjun", 2,	one(0xF088),		one(0xF1BF), "IdBc", mfloat | cfloat },
+
+{"fcmpb", 4,	two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpb", 4,	two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcmpd", 4,	two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcmpd", 4,	two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fcmpd", 4,	two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fcmpl", 4,	two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcmpl", 4,	two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpp", 4,	two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcmps", 4,	two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcmps", 4,	two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpw", 4,	two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcmpw", 4,	two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpx", 4,	two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcmpx", 4,	two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fcosb", 4,	two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcosd", 4,	two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcosl", 4,	two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcosp", 4,	two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoss", 4,	two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcosw", 4,	two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcosx", 4,	two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcosx", 4,	two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcosx", 4,	two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fcoshb", 4,	two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcoshd", 4,	two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcoshl", 4,	two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcoshp", 4,	two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoshs", 4,	two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcoshw", 4,	two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcoshx", 4,	two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcoshx", 4,	two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcoshx", 4,	two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fdbeq", 4,	two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbf", 4,	two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbge", 4,	two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgl", 4,	two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgle", 4,	two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgt", 4,	two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdble", 4,	two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdblt", 4,	two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbne", 4,	two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnge", 4,	two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngl", 4,	two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngle", 4,	two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngt", 4,	two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnle", 4,	two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnlt", 4,	two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdboge", 4,	two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogl", 4,	two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogt", 4,	two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbole", 4,	two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbolt", 4,	two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbor", 4,	two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbseq", 4,	two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsf", 4,	two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsne", 4,	two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbst", 4,	two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbt", 4,	two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbueq", 4,	two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbuge", 4,	two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbugt", 4,	two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbule", 4,	two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbult", 4,	two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbun", 4,	two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+
+{"fdivb", 4,	two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fdivb", 4,	two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivd", 4,	two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdivd", 4,	two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fdivd", 4,	two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdivl", 4,	two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fdivl", 4,	two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivp", 4,	two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fdivs", 4,	two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fdivs", 4,	two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivw", 4,	two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fdivw", 4,	two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivx", 4,	two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fdivx", 4,	two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsdivb", 4,	two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsdivb", 4,	two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivd", 4,	two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsdivd", 4,	two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsdivd", 4,	two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsdivl", 4,	two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsdivl", 4,	two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivp", 4,	two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsdivs", 4,	two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsdivs", 4,	two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivw", 4,	two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsdivw", 4,	two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivx", 4,	two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsdivx", 4,	two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fddivb", 4,	two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fddivb", 4,	two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivd", 4,	two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fddivd", 4,	two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fddivd", 4,	two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fddivl", 4,	two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fddivl", 4,	two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivp", 4,	two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fddivs", 4,	two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fddivs", 4,	two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivw", 4,	two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fddivw", 4,	two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivx", 4,	two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fddivx", 4,	two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fetoxb", 4,	two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxd", 4,	two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxl", 4,	two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxp", 4,	two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxs", 4,	two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxw", 4,	two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxx", 4,	two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxx", 4,	two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxx", 4,	two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fetoxm1b", 4,	two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxm1d", 4,	two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxm1l", 4,	two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxm1p", 4,	two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxm1s", 4,	two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxm1w", 4,	two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxm1x", 4,	two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxm1x", 4,	two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxm1x", 4,	two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fgetexpb", 4,	two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetexpd", 4,	two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetexpl", 4,	two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetexpp", 4,	two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetexps", 4,	two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetexpw", 4,	two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetexpx", 4,	two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetexpx", 4,	two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetexpx", 4,	two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fgetmanb", 4,	two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetmand", 4,	two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetmanl", 4,	two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetmanp", 4,	two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetmans", 4,	two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetmanw", 4,	two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetmanx", 4,	two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetmanx", 4,	two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetmanx", 4,	two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fintb", 4,	two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintb", 4,	two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintd", 4,	two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fintd", 4,	two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fintd", 4,	two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintd", 4,	two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fintl", 4,	two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintl", 4,	two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintp", 4,	two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fints", 4,	two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fints", 4,	two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintw", 4,	two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintw", 4,	two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintx", 4,	two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintx", 4,	two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintx", 4,	two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fintrzb", 4,	two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintrzb", 4,	two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzd", 4,	two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fintrzd", 4,	two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fintrzd", 4,	two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintrzd", 4,	two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fintrzl", 4,	two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintrzl", 4,	two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzp", 4,	two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fintrzs", 4,	two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fintrzs", 4,	two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzw", 4,	two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintrzw", 4,	two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzx", 4,	two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintrzx", 4,	two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintrzx", 4,	two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flog10b", 4,	two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog10d", 4,	two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog10l", 4,	two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog10p", 4,	two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog10s", 4,	two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog10w", 4,	two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog10x", 4,	two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog10x", 4,	two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog10x", 4,	two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flog2b", 4,	two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog2d", 4,	two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog2l", 4,	two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog2p", 4,	two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog2s", 4,	two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog2w", 4,	two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog2x", 4,	two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog2x", 4,	two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog2x", 4,	two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flognb", 4,	two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognd", 4,	two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognl", 4,	two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp", 4,	two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flogns", 4,	two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognw", 4,	two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognx", 4,	two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognx", 4,	two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognx", 4,	two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flognp1b", 4,	two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognp1d", 4,	two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognp1l", 4,	two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp1p", 4,	two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flognp1s", 4,	two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognp1w", 4,	two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognp1x", 4,	two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognp1x", 4,	two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognp1x", 4,	two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fmodb", 4,	two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmodd", 4,	two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmodl", 4,	two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmodp", 4,	two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmods", 4,	two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmodw", 4,	two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmodx", 4,	two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmodx", 4,	two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fmoveb", 4,	two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmoveb", 4,	two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
+{"fmoveb", 4,	two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmoveb", 4,	two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat },
+{"fmoved", 4,	two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmoved", 4,	two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat },
+{"fmoved", 4,	two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fmoved", 4,	two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fmoved", 4,	two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
+{"fmovel", 4,	two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmovel", 4,	two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat },
+/* FIXME: the next two variants should not permit moving an address
+   register to anything but the floating point instruction register.  */
+{"fmovel", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmovel", 4,	two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat },
+{"fmovel", 4,	two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmovel", 4,	two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
+  /* Move the FP control registers.  */
+{"fmovel", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat },
+{"fmovel", 4,	two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat },
+{"fmovep", 4,	two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmovep", 4,	two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat },
+{"fmovep", 4,	two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat },
+{"fmoves", 4,	two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmoves", 4,	two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat },
+{"fmoves", 4,	two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmoves", 4,	two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fmovew", 4,	two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmovew", 4,	two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat },
+{"fmovew", 4,	two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmovew", 4,	two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fmovex", 4,	two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat },
+{"fmovex", 4,	two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fmovex", 4,	two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat },
+
+{"fsmoveb", 4,	two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsmoveb", 4,	two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmoveb", 4,	two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmoved", 4,	two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsmoved", 4,	two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsmoved", 4,	two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsmoved", 4,	two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
+{"fsmovel", 4,	two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsmovel", 4,	two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmovel", 4,	two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmoves", 4,	two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsmoves", 4,	two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmoves", 4,	two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmovew", 4,	two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsmovew", 4,	two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmovew", 4,	two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmovex", 4,	two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsmovex", 4,	two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsmovep", 4,	two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+
+{"fdmoveb", 4,	two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdmoveb", 4,	two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmoveb", 4,	two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmoved", 4,	two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdmoved", 4,	two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdmoved", 4,	two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdmoved", 4,	two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovel", 4,	two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdmovel", 4,	two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmovel", 4,	two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmoves", 4,	two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdmoves", 4,	two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmoves", 4,	two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovew", 4,	two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdmovew", 4,	two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmovew", 4,	two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovex", 4,	two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdmovex", 4,	two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdmovep", 4,	two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+
+{"fmovecrx", 4,	two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat },
+
+{"fmovemd", 4,	two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat },
+{"fmovemd", 4,	two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
+{"fmovemd", 4,	two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
+{"fmovemd", 4,	two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat },
+
+{"fmovemx", 4,	two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
+{"fmovemx", 4,	two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
+{"fmovemx", 4,	two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
+{"fmovemx", 4,	two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
+{"fmovemx", 4,	two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
+{"fmovemx", 4,	two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
+{"fmovemx", 4,	two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
+{"fmovemx", 4,	two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
+{"fmovemx", 4,	two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
+{"fmovemx", 4,	two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
+{"fmovemx", 4,	two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
+{"fmovemx", 4,	two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
+
+{"fmoveml", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmoveml", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
+/* FIXME: In the next instruction, we should only permit %dn if the
+   target is a single register.  We should only permit %an if the
+   target is a single %fpiar.  */
+{"fmoveml", 4,	two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat },
+
+{"fmovem", 4,	two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat },
+{"fmovem", 4,	two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
+{"fmovem", 4,	two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
+{"fmovem", 4,	two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat },
+
+{"fmovem", 4,	two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
+{"fmovem", 4,	two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
+{"fmovem", 4,	two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
+{"fmovem", 4,	two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
+{"fmovem", 4,	two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
+{"fmovem", 4,	two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
+{"fmovem", 4,	two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
+{"fmovem", 4,	two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
+{"fmovem", 4,	two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
+{"fmovem", 4,	two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
+{"fmovem", 4,	two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
+{"fmovem", 4,	two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
+{"fmovem", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmovem", 4,	two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat },
+{"fmovem", 4,	two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
+{"fmovem", 4,	two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat },
+
+{"fmulb", 4,	two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmulb", 4,	two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmuld", 4,	two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fmuld", 4,	two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmuld", 4,	two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fmull", 4,	two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmull", 4,	two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulp", 4,	two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmuls", 4,	two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmuls", 4,	two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulw", 4,	two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmulw", 4,	two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulx", 4,	two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmulx", 4,	two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsmulb", 4,	two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsmulb", 4,	two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmuld", 4,	two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsmuld", 4,	two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsmuld", 4,	two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsmull", 4,	two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsmull", 4,	two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulp", 4,	two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsmuls", 4,	two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsmuls", 4,	two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulw", 4,	two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsmulw", 4,	two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulx", 4,	two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsmulx", 4,	two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fdmulb", 4,	two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdmulb", 4,	two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmuld", 4,	two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdmuld", 4,	two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdmuld", 4,	two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdmull", 4,	two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdmull", 4,	two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulp", 4,	two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdmuls", 4,	two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdmuls", 4,	two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulw", 4,	two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdmulw", 4,	two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulx", 4,	two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdmulx", 4,	two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fnegb", 4,	two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fnegb", 4,	two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegd", 4,	two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fnegd", 4,	two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fnegd", 4,	two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fnegd", 4,	two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fnegl", 4,	two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fnegl", 4,	two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegp", 4,	two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fnegs", 4,	two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fnegs", 4,	two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegw", 4,	two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fnegw", 4,	two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegx", 4,	two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fnegx", 4,	two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fnegx", 4,	two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsnegb", 4,	two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsnegb", 4,	two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegd", 4,	two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsnegd", 4,	two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fsnegd", 4,	two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsnegd", 4,	two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsnegl", 4,	two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsnegl", 4,	two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegp", 4,	two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsnegs", 4,	two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsnegs", 4,	two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegw", 4,	two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsnegw", 4,	two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegx", 4,	two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsnegx", 4,	two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsnegx", 4,	two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdnegb", 4,	two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdnegb", 4,	two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegd", 4,	two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdnegd", 4,	two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fdnegd", 4,	two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdnegd", 4,	two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdnegl", 4,	two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdnegl", 4,	two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegp", 4,	two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdnegs", 4,	two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdnegs", 4,	two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegw", 4,	two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdnegw", 4,	two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegx", 4,	two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdnegx", 4,	two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdnegx", 4,	two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fnop", 4,	two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat },
+
+{"fremb", 4,	two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fremd", 4,	two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"freml", 4,	two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fremp", 4,	two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"frems", 4,	two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fremw", 4,	two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fremx", 4,	two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fremx", 4,	two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"frestore", 2,	one(0xF140),		one(0xF1C0), "Id<s", mfloat },
+{"frestore", 2,	one(0xF140),		one(0xF1C0), "Idys", cfloat },
+
+{"fsave", 2,	one(0xF100),		one(0xF1C0), "Id>s", mfloat },
+{"fsave", 2,	one(0xF100),		one(0xF1C0), "Idzs", cfloat },
+
+{"fscaleb", 4,	two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fscaled", 4,	two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fscalel", 4,	two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fscalep", 4,	two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fscales", 4,	two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fscalew", 4,	two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fscalex", 4,	two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fscalex", 4,	two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+/* $ is necessary to prevent the assembler from using PC-relative.
+   If @ were used, "label: fseq label" could produce "ftrapeq", 2,
+   because "label" became "pc at label".  */
+{"fseq", 4,	two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsf", 4,	two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsge", 4,	two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgl", 4,	two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgle", 4,	two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgt", 4,	two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsle", 4,	two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fslt", 4,	two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsne", 4,	two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnge", 4,	two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngl", 4,	two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngle", 4,	two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngt", 4,	two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnle", 4,	two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnlt", 4,	two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsoge", 4,	two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogl", 4,	two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogt", 4,	two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsole", 4,	two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsolt", 4,	two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsor", 4,	two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsseq", 4,	two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssf", 4,	two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssne", 4,	two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsst", 4,	two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fst", 4,	two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsueq", 4,	two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsuge", 4,	two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsugt", 4,	two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsule", 4,	two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsult", 4,	two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsun", 4,	two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+
+{"fsgldivb", 4,	two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsgldivd", 4,	two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsgldivl", 4,	two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsgldivp", 4,	two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsgldivs", 4,	two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsgldivw", 4,	two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsgldivx", 4,	two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsgldivx", 4,	two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsgldivx", 4,	two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsglmulb", 4,	two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsglmuld", 4,	two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsglmull", 4,	two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsglmulp", 4,	two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsglmuls", 4,	two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsglmulw", 4,	two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsglmulx", 4,	two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsglmulx", 4,	two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsglmulx", 4,	two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsinb", 4,	two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsind", 4,	two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinl", 4,	two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinp", 4,	two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsins", 4,	two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinw", 4,	two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinx", 4,	two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinx", 4,	two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinx", 4,	two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsincosb", 4,	two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat },
+{"fsincosd", 4,	two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat },
+{"fsincosl", 4,	two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat },
+{"fsincosp", 4,	two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat },
+{"fsincoss", 4,	two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat },
+{"fsincosw", 4,	two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat },
+{"fsincosx", 4,	two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat },
+{"fsincosx", 4,	two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat },
+
+{"fsinhb", 4,	two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsinhd", 4,	two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinhl", 4,	two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinhp", 4,	two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsinhs", 4,	two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinhw", 4,	two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinhx", 4,	two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinhx", 4,	two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinhx", 4,	two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsqrtb", 4,	two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsqrtb", 4,	two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtd", 4,	two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsqrtd", 4,	two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fsqrtd", 4,	two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsqrtd", 4,	two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsqrtl", 4,	two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsqrtl", 4,	two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtp", 4,	two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsqrts", 4,	two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsqrts", 4,	two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtw", 4,	two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsqrtw", 4,	two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtx", 4,	two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsqrtx", 4,	two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsqrtx", 4,	two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fssqrtb", 4,	two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fssqrtb", 4,	two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtd", 4,	two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fssqrtd", 4,	two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fssqrtd", 4,	two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fssqrtd", 4,	two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fssqrtl", 4,	two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fssqrtl", 4,	two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtp", 4,	two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fssqrts", 4,	two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fssqrts", 4,	two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtw", 4,	two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fssqrtw", 4,	two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtx", 4,	two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fssqrtx", 4,	two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fssqrtx", 4,	two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdsqrtb", 4,	two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdsqrtb", 4,	two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtd", 4,	two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdsqrtd", 4,	two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fdsqrtd", 4,	two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdsqrtl", 4,	two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdsqrtl", 4,	two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtp", 4,	two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdsqrts", 4,	two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdsqrts", 4,	two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtw", 4,	two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdsqrtw", 4,	two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtx", 4,	two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdsqrtx", 4,	two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdsqrtx", 4,	two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fsubb", 4,	two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsubb", 4,	two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubd", 4,	two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsubd", 4,	two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsubd", 4,	two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsubl", 4,	two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsubl", 4,	two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubp", 4,	two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsubs", 4,	two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsubs", 4,	two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubw", 4,	two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsubw", 4,	two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubx", 4,	two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsubx", 4,	two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsubx", 4,	two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fssubb", 4,	two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubb", 4,	two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fssubd", 4,	two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fssubd", 4,	two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fssubd", 4,	two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fssubl", 4,	two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fssubl", 4,	two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubp", 4,	two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fssubs", 4,	two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fssubs", 4,	two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubw", 4,	two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fssubw", 4,	two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubx", 4,	two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fssubx", 4,	two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fssubx", 4,	two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdsubb", 4,	two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubb", 4,	two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdsubd", 4,	two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdsubd", 4,	two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdsubd", 4,	two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdsubl", 4,	two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubl", 4,	two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdsubp", 4,	two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdsubs", 4,	two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubs", 4,	two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdsubw", 4,	two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubw", 4,	two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdsubx", 4,	two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdsubx", 4,	two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdsubx", 4,	two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"ftanb", 4,	two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftand", 4,	two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanl", 4,	two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanp", 4,	two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftans", 4,	two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanw", 4,	two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanx", 4,	two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanx", 4,	two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanx", 4,	two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftanhb", 4,	two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftanhd", 4,	two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanhl", 4,	two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanhp", 4,	two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftanhs", 4,	two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanhw", 4,	two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanhx", 4,	two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanhx", 4,	two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanhx", 4,	two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftentoxb", 4,	two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftentoxd", 4,	two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftentoxl", 4,	two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftentoxp", 4,	two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftentoxs", 4,	two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftentoxw", 4,	two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftentoxx", 4,	two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftentoxx", 4,	two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftentoxx", 4,	two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftrapeq", 4,	two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapf", 4,	two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapge", 4,	two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgl", 4,	two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgle", 4,	two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgt", 4,	two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraple", 4,	two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraplt", 4,	two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapne", 4,	two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnge", 4,	two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngl", 4,	two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngt", 4,	two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnle", 4,	two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnlt", 4,	two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapoge", 4,	two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogl", 4,	two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogt", 4,	two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapole", 4,	two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapolt", 4,	two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapor", 4,	two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapseq", 4,	two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsf", 4,	two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsne", 4,	two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapst", 4,	two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapt", 4,	two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapueq", 4,	two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapuge", 4,	two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapugt", 4,	two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapule", 4,	two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapult", 4,	two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapun", 4,	two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+
+{"ftrapeqw", 4,	two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapfw", 4,	two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgew", 4,	two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglw", 4,	two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgtw", 4,	two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraplew", 4,	two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapltw", 4,	two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnew", 4,	two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraporw", 4,	two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsfw", 4,	two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapstw", 4,	two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraptw", 4,	two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapunw", 4,	two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+
+{"ftrapeql", 4,	two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapfl", 4,	two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgel", 4,	two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgll", 4,	two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgtl", 4,	two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraplel", 4,	two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapltl", 4,	two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnel", 4,	two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraporl", 4,	two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsfl", 4,	two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapstl", 4,	two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraptl", 4,	two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapunl", 4,	two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+
+{"ftstb", 4,	two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat },
+{"ftstb", 4,	two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstd", 4,	two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat },
+{"ftstd", 4,	two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat },
+{"ftstd", 4,	two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstl", 4,	two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat },
+{"ftstl", 4,	two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstp", 4,	two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat },
+{"ftsts", 4,	two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat },
+{"ftsts", 4,	two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstw", 4,	two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat },
+{"ftstw", 4,	two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstx", 4,	two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat },
+{"ftstx", 4,	two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat },
+
+{"ftwotoxb", 4,	two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftwotoxd", 4,	two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftwotoxl", 4,	two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftwotoxp", 4,	two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftwotoxs", 4,	two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftwotoxw", 4,	two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftwotoxx", 4,	two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftwotoxx", 4,	two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftwotoxx", 4,	two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"halt", 2,	one(0045310),	one(0177777), "",     m68060 | mcfisa_a },
+
+{"illegal", 2,	one(0045374),	one(0177777), "",     m68000up | mcfisa_a },
+{"intouch", 2,	one(0xf428),	one(0xfff8), "As",    mcfisa_b },
+
+{"jmp", 2,	one(0047300),	one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jra", 2,	one(0060000),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jra", 2,	one(0047300),	one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jsr", 2,	one(0047200),	one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jbsr", 2,	one(0060400),	one(0177400), "Bg", m68000up | mcfisa_a },
+{"jbsr", 2,	one(0047200),	one(0177700), "!s", m68000up | mcfisa_a },
+
+{"lea", 2,	one(0040700),	one(0170700), "!sAd", m68000up | mcfisa_a },
+
+{"lpstop", 6,	two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 },
+
+{"linkw", 4,	one(0047120),	one(0177770), "As#w", m68000up | mcfisa_a },
+{"linkl", 6,	one(0044010),	one(0177770), "As#l", m68020up | cpu32 },
+{"link", 4,	one(0047120),	one(0177770), "As#W", m68000up | mcfisa_a },
+{"link", 6,	one(0044010),	one(0177770), "As#l", m68020up | cpu32 },
+
+{"lslb", 2,	one(0160410),	one(0170770), "QdDs", m68000up },
+{"lslb", 2,	one(0160450),	one(0170770), "DdDs", m68000up },
+{"lslw", 2,	one(0160510),	one(0170770), "QdDs", m68000up },
+{"lslw", 2,	one(0160550),	one(0170770), "DdDs", m68000up },
+{"lslw", 2,	one(0161700),	one(0177700), "~s",   m68000up },
+{"lsll", 2,	one(0160610),	one(0170770), "QdDs", m68000up | mcfisa_a },
+{"lsll", 2,	one(0160650),	one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"lsrb", 2,	one(0160010),	one(0170770), "QdDs", m68000up },
+{"lsrb", 2,	one(0160050),	one(0170770), "DdDs", m68000up },
+{"lsrw", 2,	one(0160110),	one(0170770), "QdDs", m68000up },
+{"lsrw", 2,	one(0160150),	one(0170770), "DdDs", m68000up },
+{"lsrw", 2,	one(0161300),	one(0177700), "~s",   m68000up },
+{"lsrl", 2,	one(0160210),	one(0170770), "QdDs", m68000up | mcfisa_a },
+{"lsrl", 2,	one(0160250),	one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"macw", 4,  	two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
+{"macw", 4,  	two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
+{"macw", 4,  	two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
+{"macw", 4,  	two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac },
+
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX.  */
+{"macw", 4,  	two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX.  */
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,<ea>,accX.  */
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX.  */
+{"macw", 4,  	two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX.  */
+{"macw", 4,  	two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX.  */
+
+{"macl", 4,  	two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
+{"macl", 4,  	two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
+{"macl", 4,  	two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
+{"macl", 4,  	two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac },
+
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
+{"macl", 4,  	two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
+{"macl", 4,  	two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
+{"macl", 4,  	two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
+
+/* NOTE: The mcf5200 family programmer's reference manual does not
+   indicate the byte form of the movea instruction is invalid (as it
+   is on 68000 family cpus).  However, experiments on the 5202 yeild
+   unexpected results.  The value is copied, but it is not sign extended
+   (as is done with movea.w) and the top three bytes in the address
+   register are not disturbed.  I don't know if this is the intended
+   behavior --- it could be a hole in instruction decoding (Motorola
+   decided not to trap all invalid instructions for performance reasons)
+   --- but I suspect that it is not.
+
+   I reported this to Motorola ISD Technical Communications Support,
+   which replied that other coldfire assemblers reject movea.b.  For
+   this reason I've decided to not allow moveab.
+
+	jtc at cygnus.com - 97/01/24.  */
+
+{"moveal", 2,	one(0020100),	one(0170700), "*lAd", m68000up | mcfisa_a },
+{"moveaw", 2,	one(0030100),	one(0170700), "*wAd", m68000up | mcfisa_a },
+
+{"movclrl", 2,	one(0xA1C0),	one(0xf9f0), "eFRs", mcfemac },
+
+{"movec", 4,	one(0047173),	one(0177777), "R1Jj", m68010up | mcfisa_a },
+{"movec", 4,	one(0047173),	one(0177777), "R1#j", m68010up | mcfisa_a },
+{"movec", 4,	one(0047172),	one(0177777), "JjR1", m68010up },
+{"movec", 4,	one(0047172),	one(0177777), "#jR1", m68010up },
+
+{"movemw", 4,	one(0044200),	one(0177700), "Lw&s", m68000up },
+{"movemw", 4,	one(0044240),	one(0177770), "lw-s", m68000up },
+{"movemw", 4,	one(0044200),	one(0177700), "#w>s", m68000up },
+{"movemw", 4,	one(0046200),	one(0177700), "<sLw", m68000up },
+{"movemw", 4,	one(0046200),	one(0177700), "<s#w", m68000up },
+{"moveml", 4,	one(0044300),	one(0177700), "Lw&s", m68000up },
+{"moveml", 4,	one(0044340),	one(0177770), "lw-s", m68000up },
+{"moveml", 4,	one(0044300),	one(0177700), "#w>s", m68000up },
+{"moveml", 4,	one(0046300),	one(0177700), "<sLw", m68000up },
+{"moveml", 4,	one(0046300),	one(0177700), "<s#w", m68000up },
+/* FIXME: need specifier for mode 2 and 5 to simplify below insn patterns.  */
+{"moveml", 4,	one(0044320),	one(0177770), "Lwas", mcfisa_a },
+{"moveml", 4,	one(0044320),	one(0177770), "#was", mcfisa_a },
+{"moveml", 4,	one(0044350),	one(0177770), "Lwds", mcfisa_a },
+{"moveml", 4,	one(0044350),	one(0177770), "#wds", mcfisa_a },
+{"moveml", 4,	one(0046320),	one(0177770), "asLw", mcfisa_a },
+{"moveml", 4,	one(0046320),	one(0177770), "as#w", mcfisa_a },
+{"moveml", 4,	one(0046350),	one(0177770), "dsLw", mcfisa_a },
+{"moveml", 4,	one(0046350),	one(0177770), "ds#w", mcfisa_a },
+
+{"movepw", 2,	one(0000410),	one(0170770), "dsDd", m68000up },
+{"movepw", 2,	one(0000610),	one(0170770), "Ddds", m68000up },
+{"movepl", 2,	one(0000510),	one(0170770), "dsDd", m68000up },
+{"movepl", 2,	one(0000710),	one(0170770), "Ddds", m68000up },
+
+{"moveq", 2,	one(0070000),	one(0170400), "MsDd", m68000up | mcfisa_a },
+{"moveq", 2,	one(0070000),	one(0170400), "#BDd", m68000up | mcfisa_a },
+
+/* The move opcode can generate the movea and moveq instructions.  */
+{"moveb", 2,	one(0010000),	one(0170000), ";b$d", m68000up },
+{"moveb", 2,	one(0010000),	one(0170070), "Ds$d", mcfisa_a },
+{"moveb", 2,	one(0010020),	one(0170070), "as$d", mcfisa_a },
+{"moveb", 2,	one(0010030),	one(0170070), "+s$d", mcfisa_a },
+{"moveb", 2,	one(0010040),	one(0170070), "-s$d", mcfisa_a },
+{"moveb", 2,	one(0010000),	one(0170000), "nsqd", mcfisa_a },
+{"moveb", 2,	one(0010000),	one(0170700), "obDd", mcfisa_a },
+{"moveb", 2,	one(0010200),	one(0170700), "obad", mcfisa_a },
+{"moveb", 2,	one(0010300),	one(0170700), "ob+d", mcfisa_a },
+{"moveb", 2,	one(0010400),	one(0170700), "ob-d", mcfisa_a },
+{"moveb", 2,	one(0010000),	one(0170000), "obnd", mcfisa_b },
+
+{"movew", 2,	one(0030000),	one(0170000), "*w%d", m68000up },
+{"movew", 2,	one(0030000),	one(0170000), "ms%d", mcfisa_a },
+{"movew", 2,	one(0030000),	one(0170000), "nspd", mcfisa_a },
+{"movew", 2,	one(0030000),	one(0170000), "owmd", mcfisa_a },
+{"movew", 2,	one(0030000),	one(0170000), "ownd", mcfisa_b },
+{"movew", 2,	one(0040300),	one(0177700), "Ss$s", m68000up },
+{"movew", 2,	one(0040300),	one(0177770), "SsDs", mcfisa_a },
+{"movew", 2,	one(0041300),	one(0177700), "Cs$s", m68010up },
+{"movew", 2,	one(0041300),	one(0177770), "CsDs", mcfisa_a },
+{"movew", 2,	one(0042300),	one(0177700), ";wCd", m68000up },
+{"movew", 2,	one(0042300),	one(0177700), "DsCd", mcfisa_a },
+{"movew", 4,	one(0042374),	one(0177777), "#wCd", mcfisa_a },
+{"movew", 2,	one(0043300),	one(0177700), ";wSd", m68000up },
+{"movew", 2,	one(0043300),	one(0177700), "DsSd", mcfisa_a },
+{"movew", 4,	one(0043374),	one(0177777), "#wSd", mcfisa_a },
+
+{"movel", 2,	one(0070000),	one(0170400), "MsDd", m68000up | mcfisa_a },
+{"movel", 2,	one(0020000),	one(0170000), "*l%d", m68000up },
+{"movel", 2,	one(0020000),	one(0170000), "ms%d", mcfisa_a },
+{"movel", 2,	one(0020000),	one(0170000), "nspd", mcfisa_a },
+{"movel", 2,	one(0020000),	one(0170000), "olmd", mcfisa_a },
+{"movel", 2,	one(0020000),	one(0170000), "olnd", mcfisa_b },
+{"movel", 2,	one(0047140),	one(0177770), "AsUd", m68000up | mcfusp },
+{"movel", 2,	one(0047150),	one(0177770), "UdAs", m68000up | mcfusp },
+{"movel", 2,	one(0120600),	one(0177760), "EsRs", mcfmac },
+{"movel", 2,	one(0120400),	one(0177760), "RsEs", mcfmac },
+{"movel", 6,	one(0120474),	one(0177777), "#lEs", mcfmac },
+{"movel", 2,	one(0124600),	one(0177760), "GsRs", mcfmac },
+{"movel", 2,	one(0124400),	one(0177760), "RsGs", mcfmac },
+{"movel", 6,	one(0124474),	one(0177777), "#lGs", mcfmac },
+{"movel", 2,	one(0126600),	one(0177760), "HsRs", mcfmac },
+{"movel", 2,	one(0126400),	one(0177760), "RsHs", mcfmac },
+{"movel", 6,	one(0126474),	one(0177777), "#lHs", mcfmac },
+{"movel", 2,	one(0124700),	one(0177777), "GsCs", mcfmac },
+
+{"movel", 2,	one(0xa180),	one(0xf9f0), "eFRs", mcfemac }, /* ACCx,Rx.  */
+{"movel", 2,	one(0xab80),	one(0xfbf0), "g]Rs", mcfemac }, /* ACCEXTx,Rx.  */
+{"movel", 2,	one(0xa980),	one(0xfff0), "G-Rs", mcfemac }, /* macsr,Rx.  */
+{"movel", 2,	one(0xad80),	one(0xfff0), "H-Rs", mcfemac }, /* mask,Rx.  */
+{"movel", 2,	one(0xa110),	one(0xf9fc), "efeF", mcfemac }, /* ACCy,ACCx.  */
+{"movel", 2,	one(0xa9c0),	one(0xffff), "G-C-", mcfemac }, /* macsr,ccr.  */
+{"movel", 2,	one(0xa100),	one(0xf9f0), "RseF", mcfemac }, /* Rx,ACCx.  */
+{"movel", 6,	one(0xa13c),	one(0xf9ff), "#leF", mcfemac }, /* #,ACCx.  */
+{"movel", 2,	one(0xab00),	one(0xfbc0), "Rsg]", mcfemac }, /* Rx,ACCEXTx.  */
+{"movel", 6,	one(0xab3c),	one(0xfbff), "#lg]", mcfemac }, /* #,ACCEXTx.  */
+{"movel", 2,	one(0xa900),	one(0xffc0), "RsG-", mcfemac }, /* Rx,macsr.  */
+{"movel", 6,	one(0xa93c),	one(0xffff), "#lG-", mcfemac }, /* #,macsr.  */
+{"movel", 2,	one(0xad00),	one(0xffc0), "RsH-", mcfemac }, /* Rx,mask.  */
+{"movel", 6,	one(0xad3c),	one(0xffff), "#lH-", mcfemac }, /* #,mask.  */
+
+{"move", 2,	one(0030000),	one(0170000), "*w%d", m68000up },
+{"move", 2,	one(0030000),	one(0170000), "ms%d", mcfisa_a },
+{"move", 2,	one(0030000),	one(0170000), "nspd", mcfisa_a },
+{"move", 2,	one(0030000),	one(0170000), "owmd", mcfisa_a },
+{"move", 2,	one(0030000),	one(0170000), "ownd", mcfisa_b },
+{"move", 2,	one(0040300),	one(0177700), "Ss$s", m68000up },
+{"move", 2,	one(0040300),	one(0177770), "SsDs", mcfisa_a },
+{"move", 2,	one(0041300),	one(0177700), "Cs$s", m68010up },
+{"move", 2,	one(0041300),	one(0177770), "CsDs", mcfisa_a },
+{"move", 2,	one(0042300),	one(0177700), ";wCd", m68000up },
+{"move", 2,	one(0042300),	one(0177700), "DsCd", mcfisa_a },
+{"move", 4,	one(0042374),	one(0177777), "#wCd", mcfisa_a },
+{"move", 2,	one(0043300),	one(0177700), ";wSd", m68000up },
+{"move", 2,	one(0043300),	one(0177700), "DsSd", mcfisa_a },
+{"move", 4,	one(0043374),	one(0177777), "#wSd", mcfisa_a },
+
+{"move", 2,	one(0047140),	one(0177770), "AsUd", m68000up },
+{"move", 2,	one(0047150),	one(0177770), "UdAs", m68000up },
+
+{"mov3ql", 2,	one(0120500),	one(0170700), "xd%s", mcfisa_b },
+{"mvsb", 2,	one(0070400),	one(0170700), "*bDd", mcfisa_b },
+{"mvsw", 2,	one(0070500),	one(0170700), "*wDd", mcfisa_b },
+{"mvzb", 2,	one(0070600),	one(0170700), "*bDd", mcfisa_b },
+{"mvzw", 2,	one(0070700),	one(0170700), "*wDd", mcfisa_b },
+
+{"movesb", 4,	two(0007000, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesb", 4,	two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movesw", 4,	two(0007100, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesw", 4,	two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movesl", 4,	two(0007200, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesl", 4,	two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up },
+
+{"move16", 4,	two(0xf620, 0x8000), two(0xfff8, 0x8fff), "+s+1", m68040up },
+{"move16", 2,	one(0xf600),		one(0xfff8), "+s_L", m68040up },
+{"move16", 2,	one(0xf608),		one(0xfff8), "_L+s", m68040up },
+{"move16", 2,	one(0xf610),		one(0xfff8), "as_L", m68040up },
+{"move16", 2,	one(0xf618),		one(0xfff8), "_Las", m68040up },
+
+{"msacw", 4,  	two(0xa080, 0x0100), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
+{"msacw", 4,  	two(0xa080, 0x0300), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
+{"msacw", 4,  	two(0xa080, 0x0100), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
+{"msacw", 4,  	two(0xa000, 0x0300), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf1b0, 0x0f00), "uMum", mcfmac },
+
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf100, 0x0900), "uMumiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX.  */
+{"msacw", 4,  	two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX.  */
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,<ea>,accX.  */
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX.  */
+{"msacw", 4,  	two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX.  */
+{"msacw", 4,  	two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX.  */
+
+{"msacl", 4,  	two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
+{"msacl", 4,  	two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
+{"msacl", 4,  	two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
+{"msacl", 4,  	two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac },
+
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
+{"msacl", 4,  	two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
+{"msacl", 4,  	two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
+{"msacl", 4,  	two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
+
+{"mulsw", 2,	one(0140700),		one(0170700), ";wDd", m68000up|mcfisa_a },
+{"mulsl", 4,	two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
+{"mulsl", 4,	two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a },
+{"mulsl", 4,	two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
+
+{"muluw", 2,	one(0140300),		one(0170700), ";wDd", m68000up|mcfisa_a },
+{"mulul", 4,	two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
+{"mulul", 4,	two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a },
+{"mulul", 4,	two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
+
+{"nbcd", 2,	one(0044000),	one(0177700), "$s", m68000up },
+
+{"negb", 2,	one(0042000),	one(0177700), "$s", m68000up },
+{"negw", 2,	one(0042100),	one(0177700), "$s", m68000up },
+{"negl", 2,	one(0042200),	one(0177700), "$s", m68000up },
+{"negl", 2,	one(0042200),	one(0177700), "Ds", mcfisa_a},
+
+{"negxb", 2,	one(0040000),	one(0177700), "$s", m68000up },
+{"negxw", 2,	one(0040100),	one(0177700), "$s", m68000up },
+{"negxl", 2,	one(0040200),	one(0177700), "$s", m68000up },
+{"negxl", 2,	one(0040200),	one(0177700), "Ds", mcfisa_a},
+
+{"nop", 2,	one(0047161),	one(0177777), "", m68000up | mcfisa_a},
+
+{"notb", 2,	one(0043000),	one(0177700), "$s", m68000up },
+{"notw", 2,	one(0043100),	one(0177700), "$s", m68000up },
+{"notl", 2,	one(0043200),	one(0177700), "$s", m68000up },
+{"notl", 2,	one(0043200),	one(0177700), "Ds", mcfisa_a},
+
+{"orib", 4,	one(0000000),	one(0177700), "#b$s", m68000up },
+{"orib", 4,	one(0000074),	one(0177777), "#bCs", m68000up },
+{"oriw", 4,	one(0000100),	one(0177700), "#w$s", m68000up },
+{"oriw", 4,	one(0000174),	one(0177777), "#wSs", m68000up },
+{"oril", 6,	one(0000200),	one(0177700), "#l$s", m68000up },
+{"oril", 6,	one(0000200),	one(0177700), "#lDs", mcfisa_a },
+{"ori", 4,	one(0000074),	one(0177777), "#bCs", m68000up },
+{"ori", 4,	one(0000100),	one(0177700), "#w$s", m68000up },
+{"ori", 4,	one(0000174),	one(0177777), "#wSs", m68000up },
+
+/* The or opcode can generate the ori instruction.  */
+{"orb", 4,	one(0000000),	one(0177700), "#b$s", m68000up },
+{"orb", 4,	one(0000074),	one(0177777), "#bCs", m68000up },
+{"orb", 2,	one(0100000),	one(0170700), ";bDd", m68000up },
+{"orb", 2,	one(0100400),	one(0170700), "Dd~s", m68000up },
+{"orw", 4,	one(0000100),	one(0177700), "#w$s", m68000up },
+{"orw", 4,	one(0000174),	one(0177777), "#wSs", m68000up },
+{"orw", 2,	one(0100100),	one(0170700), ";wDd", m68000up },
+{"orw", 2,	one(0100500),	one(0170700), "Dd~s", m68000up },
+{"orl", 6,	one(0000200),	one(0177700), "#l$s", m68000up },
+{"orl", 6,	one(0000200),	one(0177700), "#lDs", mcfisa_a },
+{"orl", 2,	one(0100200),	one(0170700), ";lDd", m68000up | mcfisa_a },
+{"orl", 2,	one(0100600),	one(0170700), "Dd~s", m68000up | mcfisa_a },
+{"or", 4,	one(0000074),	one(0177777), "#bCs", m68000up },
+{"or", 4,	one(0000100),	one(0177700), "#w$s", m68000up },
+{"or", 4,	one(0000174),	one(0177777), "#wSs", m68000up },
+{"or", 2,	one(0100100),	one(0170700), ";wDd", m68000up },
+{"or", 2,	one(0100500),	one(0170700), "Dd~s", m68000up },
+
+{"pack", 4,	one(0100500),	one(0170770), "DsDd#w", m68020up },
+{"pack", 4,	one(0100510),	one(0170770), "-s-d#w", m68020up },
+
+{"pbac", 2,	one(0xf087),	one(0xffbf), "Bc", m68851 },
+{"pbacw", 2,	one(0xf087),	one(0xffff), "BW", m68851 },
+{"pbas", 2,	one(0xf086),	one(0xffbf), "Bc", m68851 },
+{"pbasw", 2,	one(0xf086),	one(0xffff), "BW", m68851 },
+{"pbbc", 2,	one(0xf081),	one(0xffbf), "Bc", m68851 },
+{"pbbcw", 2,	one(0xf081),	one(0xffff), "BW", m68851 },
+{"pbbs", 2,	one(0xf080),	one(0xffbf), "Bc", m68851 },
+{"pbbsw", 2,	one(0xf080),	one(0xffff), "BW", m68851 },
+{"pbcc", 2,	one(0xf08f),	one(0xffbf), "Bc", m68851 },
+{"pbccw", 2,	one(0xf08f),	one(0xffff), "BW", m68851 },
+{"pbcs", 2,	one(0xf08e),	one(0xffbf), "Bc", m68851 },
+{"pbcsw", 2,	one(0xf08e),	one(0xffff), "BW", m68851 },
+{"pbgc", 2,	one(0xf08d),	one(0xffbf), "Bc", m68851 },
+{"pbgcw", 2,	one(0xf08d),	one(0xffff), "BW", m68851 },
+{"pbgs", 2,	one(0xf08c),	one(0xffbf), "Bc", m68851 },
+{"pbgsw", 2,	one(0xf08c),	one(0xffff), "BW", m68851 },
+{"pbic", 2,	one(0xf08b),	one(0xffbf), "Bc", m68851 },
+{"pbicw", 2,	one(0xf08b),	one(0xffff), "BW", m68851 },
+{"pbis", 2,	one(0xf08a),	one(0xffbf), "Bc", m68851 },
+{"pbisw", 2,	one(0xf08a),	one(0xffff), "BW", m68851 },
+{"pblc", 2,	one(0xf083),	one(0xffbf), "Bc", m68851 },
+{"pblcw", 2,	one(0xf083),	one(0xffff), "BW", m68851 },
+{"pbls", 2,	one(0xf082),	one(0xffbf), "Bc", m68851 },
+{"pblsw", 2,	one(0xf082),	one(0xffff), "BW", m68851 },
+{"pbsc", 2,	one(0xf085),	one(0xffbf), "Bc", m68851 },
+{"pbscw", 2,	one(0xf085),	one(0xffff), "BW", m68851 },
+{"pbss", 2,	one(0xf084),	one(0xffbf), "Bc", m68851 },
+{"pbssw", 2,	one(0xf084),	one(0xffff), "BW", m68851 },
+{"pbwc", 2,	one(0xf089),	one(0xffbf), "Bc", m68851 },
+{"pbwcw", 2,	one(0xf089),	one(0xffff), "BW", m68851 },
+{"pbws", 2,	one(0xf088),	one(0xffbf), "Bc", m68851 },
+{"pbwsw", 2,	one(0xf088),	one(0xffff), "BW", m68851 },
+
+{"pdbac", 4,	two(0xf048, 0x0007),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbas", 4,	two(0xf048, 0x0006),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbc", 4,	two(0xf048, 0x0001),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbs", 4,	two(0xf048, 0x0000),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcc", 4,	two(0xf048, 0x000f),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcs", 4,	two(0xf048, 0x000e),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgc", 4,	two(0xf048, 0x000d),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgs", 4,	two(0xf048, 0x000c),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbic", 4,	two(0xf048, 0x000b),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbis", 4,	two(0xf048, 0x000a),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdblc", 4,	two(0xf048, 0x0003),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbls", 4,	two(0xf048, 0x0002),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbsc", 4,	two(0xf048, 0x0005),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbss", 4,	two(0xf048, 0x0004),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbwc", 4,	two(0xf048, 0x0009),	two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbws", 4,	two(0xf048, 0x0008),	two(0xfff8, 0xffff), "DsBw", m68851 },
+
+{"pea", 2,	one(0044100),		one(0177700), "!s", m68000up|mcfisa_a },
+
+{"pflusha", 2,	one(0xf518),		one(0xfff8), "", m68040up },
+{"pflusha", 4,	two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 },
+
+{"pflush", 4,   two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 },
+{"pflush", 2,	one(0xf508),		one(0xfff8), "as", m68040up },
+{"pflush", 2,	one(0xf508),		one(0xfff8), "As", m68040up },
+
+{"pflushan", 2,	one(0xf510),		one(0xfff8), "", m68040up },
+{"pflushn", 2,	one(0xf500),		one(0xfff8), "as", m68040up },
+{"pflushn", 2,	one(0xf500),		one(0xfff8), "As", m68040up },
+
+{"pflushr", 4,	two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 },
+
+{"pflushs", 4,	two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 },
+{"pflushs", 4,	two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 },
+{"pflushs", 4,	two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 },
+{"pflushs", 4,	two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 },
+{"pflushs", 4,	two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 },
+{"pflushs", 4,	two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 },
+
+{"ploadr", 4,   two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
+{"ploadr", 4,   two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
+{"ploadr", 4,   two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
+
+{"plpar", 2,	one(0xf5c8),		one(0xfff8), "as", m68060 },
+{"plpaw", 2,	one(0xf588),		one(0xfff8), "as", m68060 },
+
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 },
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 },
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 },
+{"pmove", 4,    two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 },
+{"pmove", 4,    two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 },
+{"pmove", 4,    two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 },
+{"pmove", 4,    two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 },
+
+{"pmovefd", 4,	two(0xf000, 0x4100),	two(0xffc0, 0xe3ff), "*l08", m68030 },
+{"pmovefd", 4,	two(0xf000, 0x4100),	two(0xffc0, 0xe3ff), "|sW8", m68030 },
+{"pmovefd", 4,	two(0xf000, 0x0900),	two(0xffc0, 0xfbff), "*l38", m68030 },
+
+{"prestore", 2,	one(0xf140),		one(0xffc0), "<s", m68851 },
+
+{"psave", 2,	one(0xf100),		one(0xffc0), ">s", m68851 },
+
+{"psac", 4,	two(0xf040, 0x0007),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psas", 4,	two(0xf040, 0x0006),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psbc", 4,	two(0xf040, 0x0001),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psbs", 4,	two(0xf040, 0x0000),	two(0xffc0, 0xffff), "$s", m68851 },
+{"pscc", 4,	two(0xf040, 0x000f),	two(0xffc0, 0xffff), "$s", m68851 },
+{"pscs", 4,	two(0xf040, 0x000e),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psgc", 4,	two(0xf040, 0x000d),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psgs", 4,	two(0xf040, 0x000c),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psic", 4,	two(0xf040, 0x000b),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psis", 4,	two(0xf040, 0x000a),	two(0xffc0, 0xffff), "$s", m68851 },
+{"pslc", 4,	two(0xf040, 0x0003),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psls", 4,	two(0xf040, 0x0002),	two(0xffc0, 0xffff), "$s", m68851 },
+{"pssc", 4,	two(0xf040, 0x0005),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psss", 4,	two(0xf040, 0x0004),	two(0xffc0, 0xffff), "$s", m68851 },
+{"pswc", 4,	two(0xf040, 0x0009),	two(0xffc0, 0xffff), "$s", m68851 },
+{"psws", 4,	two(0xf040, 0x0008),	two(0xffc0, 0xffff), "$s", m68851 },
+
+{"ptestr", 4, 	two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 },
+{"ptestr", 4, 	two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
+{"ptestr", 4, 	two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
+{"ptestr", 4, 	two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
+{"ptestr", 4, 	two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
+{"ptestr", 4, 	two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
+{"ptestr", 2,	one(0xf568),		one(0xfff8), "as", m68040 },
+
+{"ptestw", 4, 	two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 },
+{"ptestw", 4, 	two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
+{"ptestw", 4, 	two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
+{"ptestw", 4, 	two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
+{"ptestw", 4, 	two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
+{"ptestw", 4, 	two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
+{"ptestw", 2,	one(0xf548),		one(0xfff8), "as", m68040 },
+
+{"ptrapacw", 6,	two(0xf07a, 0x0007),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapacl", 6,	two(0xf07b, 0x0007),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapac", 4,	two(0xf07c, 0x0007),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapasw", 6,	two(0xf07a, 0x0006),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapasl", 6,	two(0xf07b, 0x0006),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapas", 4,	two(0xf07c, 0x0006),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapbcw", 6,	two(0xf07a, 0x0001),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbcl", 6,	two(0xf07b, 0x0001),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbc", 4,	two(0xf07c, 0x0001),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapbsw", 6,	two(0xf07a, 0x0000),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbsl", 6,	two(0xf07b, 0x0000),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbs", 4,	two(0xf07c, 0x0000),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapccw", 6,	two(0xf07a, 0x000f),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapccl", 6,	two(0xf07b, 0x000f),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcc", 4,	two(0xf07c, 0x000f),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapcsw", 6,	two(0xf07a, 0x000e),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapcsl", 6,	two(0xf07b, 0x000e),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcs", 4,	two(0xf07c, 0x000e),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapgcw", 6,	two(0xf07a, 0x000d),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgcl", 6,	two(0xf07b, 0x000d),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgc", 4,	two(0xf07c, 0x000d),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapgsw", 6,	two(0xf07a, 0x000c),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgsl", 6,	two(0xf07b, 0x000c),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgs", 4,	two(0xf07c, 0x000c),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapicw", 6,	two(0xf07a, 0x000b),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapicl", 6,	two(0xf07b, 0x000b),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapic", 4,	two(0xf07c, 0x000b),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapisw", 6,	two(0xf07a, 0x000a),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapisl", 6,	two(0xf07b, 0x000a),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapis", 4,	two(0xf07c, 0x000a),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptraplcw", 6,	two(0xf07a, 0x0003),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplcl", 6,	two(0xf07b, 0x0003),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptraplc", 4,	two(0xf07c, 0x0003),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptraplsw", 6,	two(0xf07a, 0x0002),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplsl", 6,	two(0xf07b, 0x0002),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapls", 4,	two(0xf07c, 0x0002),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapscw", 6,	two(0xf07a, 0x0005),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapscl", 6,	two(0xf07b, 0x0005),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapsc", 4,	two(0xf07c, 0x0005),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapssw", 6,	two(0xf07a, 0x0004),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapssl", 6,	two(0xf07b, 0x0004),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapss", 4,	two(0xf07c, 0x0004),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapwcw", 6,	two(0xf07a, 0x0009),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwcl", 6,	two(0xf07b, 0x0009),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapwc", 4,	two(0xf07c, 0x0009),	two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapwsw", 6,	two(0xf07a, 0x0008),	two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwsl", 6,	two(0xf07b, 0x0008),	two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapws", 4,	two(0xf07c, 0x0008),	two(0xffff, 0xffff), "",   m68851 },
+
+{"pulse", 2,	one(0045314),		one(0177777), "", m68060 | mcfisa_a },
+
+{"pvalid", 4,	two(0xf000, 0x2800),	two(0xffc0, 0xffff), "Vs&s", m68851 },
+{"pvalid", 4,	two(0xf000, 0x2c00),	two(0xffc0, 0xfff8), "A3&s", m68851 },
+
+  /* FIXME: don't allow Dw==Dx. */
+{"remsl", 4,    two(0x4c40, 0x0800),    two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
+{"remul", 4,    two(0x4c40, 0x0000),    two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
+
+{"reset", 2,	one(0047160),		one(0177777), "", m68000up },
+
+{"rolb", 2,	one(0160430),		one(0170770), "QdDs", m68000up },
+{"rolb", 2,	one(0160470),		one(0170770), "DdDs", m68000up },
+{"rolw", 2,	one(0160530),		one(0170770), "QdDs", m68000up },
+{"rolw", 2,	one(0160570),		one(0170770), "DdDs", m68000up },
+{"rolw", 2,	one(0163700),		one(0177700), "~s",   m68000up },
+{"roll", 2,	one(0160630),		one(0170770), "QdDs", m68000up },
+{"roll", 2,	one(0160670),		one(0170770), "DdDs", m68000up },
+
+{"rorb", 2,	one(0160030),		one(0170770), "QdDs", m68000up },
+{"rorb", 2,	one(0160070),		one(0170770), "DdDs", m68000up },
+{"rorw", 2,	one(0160130),		one(0170770), "QdDs", m68000up },
+{"rorw", 2,	one(0160170),		one(0170770), "DdDs", m68000up },
+{"rorw", 2,	one(0163300),		one(0177700), "~s",   m68000up },
+{"rorl", 2,	one(0160230),		one(0170770), "QdDs", m68000up },
+{"rorl", 2,	one(0160270),		one(0170770), "DdDs", m68000up },
+
+{"roxlb", 2,	one(0160420),		one(0170770), "QdDs", m68000up },
+{"roxlb", 2,	one(0160460),		one(0170770), "DdDs", m68000up },
+{"roxlw", 2,	one(0160520),		one(0170770), "QdDs", m68000up },
+{"roxlw", 2,	one(0160560),		one(0170770), "DdDs", m68000up },
+{"roxlw", 2,	one(0162700),		one(0177700), "~s",   m68000up },
+{"roxll", 2,	one(0160620),		one(0170770), "QdDs", m68000up },
+{"roxll", 2,	one(0160660),		one(0170770), "DdDs", m68000up },
+
+{"roxrb", 2,	one(0160020),		one(0170770), "QdDs", m68000up },
+{"roxrb", 2,	one(0160060),		one(0170770), "DdDs", m68000up },
+{"roxrw", 2,	one(0160120),		one(0170770), "QdDs", m68000up },
+{"roxrw", 2,	one(0160160),		one(0170770), "DdDs", m68000up },
+{"roxrw", 2,	one(0162300),		one(0177700), "~s",   m68000up },
+{"roxrl", 2,	one(0160220),		one(0170770), "QdDs", m68000up },
+{"roxrl", 2,	one(0160260),		one(0170770), "DdDs", m68000up },
+
+{"rtd", 4,	one(0047164),		one(0177777), "#w", m68010up },
+
+{"rte", 2,	one(0047163),		one(0177777), "",   m68000up | mcfisa_a },
+
+{"rtm", 2,	one(0003300),		one(0177760), "Rs", m68020 },
+
+{"rtr", 2,	one(0047167),		one(0177777), "",   m68000up },
+
+{"rts", 2,	one(0047165),		one(0177777), "",   m68000up | mcfisa_a },
+
+{"satsl", 2,	one(0046200),		one(0177770), "Ds", mcfisa_b },
+
+{"sbcd", 2,	one(0100400),		one(0170770), "DsDd", m68000up },
+{"sbcd", 2,	one(0100410),		one(0170770), "-s-d", m68000up },
+
+{"scc", 2,	one(0052300),	one(0177700), "$s", m68000up },
+{"scc", 2,	one(0052300),	one(0177700), "Ds", mcfisa_a },
+{"scs", 2,	one(0052700),	one(0177700), "$s", m68000up },
+{"scs", 2,	one(0052700),	one(0177700), "Ds", mcfisa_a },
+{"seq", 2,	one(0053700),	one(0177700), "$s", m68000up },
+{"seq", 2,	one(0053700),	one(0177700), "Ds", mcfisa_a },
+{"sf", 2,	one(0050700),	one(0177700), "$s", m68000up },
+{"sf", 2,	one(0050700),	one(0177700), "Ds", mcfisa_a },
+{"sge", 2,	one(0056300),	one(0177700), "$s", m68000up },
+{"sge", 2,	one(0056300),	one(0177700), "Ds", mcfisa_a },
+{"sgt", 2,	one(0057300),	one(0177700), "$s", m68000up },
+{"sgt", 2,	one(0057300),	one(0177700), "Ds", mcfisa_a },
+{"shi", 2,	one(0051300),	one(0177700), "$s", m68000up },
+{"shi", 2,	one(0051300),	one(0177700), "Ds", mcfisa_a },
+{"sle", 2,	one(0057700),	one(0177700), "$s", m68000up },
+{"sle", 2,	one(0057700),	one(0177700), "Ds", mcfisa_a },
+{"sls", 2,	one(0051700),	one(0177700), "$s", m68000up },
+{"sls", 2,	one(0051700),	one(0177700), "Ds", mcfisa_a },
+{"slt", 2,	one(0056700),	one(0177700), "$s", m68000up },
+{"slt", 2,	one(0056700),	one(0177700), "Ds", mcfisa_a },
+{"smi", 2,	one(0055700),	one(0177700), "$s", m68000up },
+{"smi", 2,	one(0055700),	one(0177700), "Ds", mcfisa_a },
+{"sne", 2,	one(0053300),	one(0177700), "$s", m68000up },
+{"sne", 2,	one(0053300),	one(0177700), "Ds", mcfisa_a },
+{"spl", 2,	one(0055300),	one(0177700), "$s", m68000up },
+{"spl", 2,	one(0055300),	one(0177700), "Ds", mcfisa_a },
+{"st", 2,	one(0050300),	one(0177700), "$s", m68000up },
+{"st", 2,	one(0050300),	one(0177700), "Ds", mcfisa_a },
+{"svc", 2,	one(0054300),	one(0177700), "$s", m68000up },
+{"svc", 2,	one(0054300),	one(0177700), "Ds", mcfisa_a },
+{"svs", 2,	one(0054700),	one(0177700), "$s", m68000up },
+{"svs", 2,	one(0054700),	one(0177700), "Ds", mcfisa_a },
+
+{"stop", 4,	one(0047162),	one(0177777), "#w", m68000up | mcfisa_a },
+
+{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa},
+
+{"subal", 2,	one(0110700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+{"subaw", 2,	one(0110300),	one(0170700), "*wAd", m68000up },
+
+{"subib", 4,	one(0002000),	one(0177700), "#b$s", m68000up },
+{"subiw", 4,	one(0002100),	one(0177700), "#w$s", m68000up },
+{"subil", 6,	one(0002200),	one(0177700), "#l$s", m68000up },
+{"subil", 6,	one(0002200),	one(0177700), "#lDs", mcfisa_a },
+
+{"subqb", 2,	one(0050400),	one(0170700), "Qd%s", m68000up },
+{"subqw", 2,	one(0050500),	one(0170700), "Qd%s", m68000up },
+{"subql", 2,	one(0050600),	one(0170700), "Qd%s", m68000up | mcfisa_a },
+
+/* The sub opcode can generate the suba, subi, and subq instructions.  */
+{"subb", 2,	one(0050400),	one(0170700), "Qd%s", m68000up },
+{"subb", 4,	one(0002000),	one(0177700), "#b$s", m68000up },
+{"subb", 2,	one(0110000),	one(0170700), ";bDd", m68000up },
+{"subb", 2,	one(0110400),	one(0170700), "Dd~s", m68000up },
+{"subw", 2,	one(0050500),	one(0170700), "Qd%s", m68000up },
+{"subw", 4,	one(0002100),	one(0177700), "#w$s", m68000up },
+{"subw", 2,	one(0110300),	one(0170700), "*wAd", m68000up },
+{"subw", 2,	one(0110100),	one(0170700), "*wDd", m68000up },
+{"subw", 2,	one(0110500),	one(0170700), "Dd~s", m68000up },
+{"subl", 2,	one(0050600),	one(0170700), "Qd%s", m68000up | mcfisa_a },
+{"subl", 6,	one(0002200),	one(0177700), "#l$s", m68000up },
+{"subl", 6,	one(0002200),	one(0177700), "#lDs", mcfisa_a },
+{"subl", 2,	one(0110700),	one(0170700), "*lAd", m68000up | mcfisa_a },
+{"subl", 2,	one(0110200),	one(0170700), "*lDd", m68000up | mcfisa_a },
+{"subl", 2,	one(0110600),	one(0170700), "Dd~s", m68000up | mcfisa_a },
+
+{"subxb", 2,	one(0110400),	one(0170770), "DsDd", m68000up },
+{"subxb", 2,	one(0110410),	one(0170770), "-s-d", m68000up },
+{"subxw", 2,	one(0110500),	one(0170770), "DsDd", m68000up },
+{"subxw", 2,	one(0110510),	one(0170770), "-s-d", m68000up },
+{"subxl", 2,	one(0110600),	one(0170770), "DsDd", m68000up | mcfisa_a },
+{"subxl", 2,	one(0110610),	one(0170770), "-s-d", m68000up },
+
+{"swap", 2,	one(0044100),	one(0177770), "Ds", m68000up | mcfisa_a },
+
+/* swbeg and swbegl are magic constants used on sysV68.  The compiler
+   generates them before a switch table.  They tell the debugger and
+   disassembler that a switch table follows.  The parameter is the
+   number of elements in the table.  swbeg means that the entries in
+   the table are word (2 byte) sized, and swbegl means that the
+   entries in the table are longword (4 byte) sized.  */
+{"swbeg", 4,	one(0045374),	one(0177777), "#w",   m68000up | mcfisa_a },
+{"swbegl", 6,	one(0045375),	one(0177777), "#l",   m68000up | mcfisa_a },
+
+{"tas", 2,	one(0045300),	one(0177700), "$s", m68000up | mcfisa_b},
+
+#define TBL1(name,insn_size,signed,round,size)					\
+  {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400),	\
+     two(0177700,0107777), "!sD1", cpu32 },				\
+  {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)),		\
+     two(0177770,0107770), "DsD3D1", cpu32 }
+#define TBL(name1, name2, name3, s, r) \
+  TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2)
+TBL("tblsb", "tblsw", "tblsl", 2, 1),
+TBL("tblsnb", "tblsnw", "tblsnl", 2, 0),
+TBL("tblub", "tbluw", "tblul", 0, 1),
+TBL("tblunb", "tblunw", "tblunl", 0, 0),
+
+{"trap", 2,	one(0047100),	one(0177760), "Ts", m68000up | mcfisa_a },
+
+{"trapcc", 2,	one(0052374),	one(0177777), "", m68020up | cpu32 },
+{"trapcs", 2,	one(0052774),	one(0177777), "", m68020up | cpu32 },
+{"trapeq", 2,	one(0053774),	one(0177777), "", m68020up | cpu32 },
+{"trapf", 2,	one(0050774),	one(0177777), "", m68020up | cpu32 | mcfisa_a },
+{"trapge", 2,	one(0056374),	one(0177777), "", m68020up | cpu32 },
+{"trapgt", 2,	one(0057374),	one(0177777), "", m68020up | cpu32 },
+{"traphi", 2,	one(0051374),	one(0177777), "", m68020up | cpu32 },
+{"traple", 2,	one(0057774),	one(0177777), "", m68020up | cpu32 },
+{"trapls", 2,	one(0051774),	one(0177777), "", m68020up | cpu32 },
+{"traplt", 2,	one(0056774),	one(0177777), "", m68020up | cpu32 },
+{"trapmi", 2,	one(0055774),	one(0177777), "", m68020up | cpu32 },
+{"trapne", 2,	one(0053374),	one(0177777), "", m68020up | cpu32 },
+{"trappl", 2,	one(0055374),	one(0177777), "", m68020up | cpu32 },
+{"trapt", 2,	one(0050374),	one(0177777), "", m68020up | cpu32 },
+{"trapvc", 2,	one(0054374),	one(0177777), "", m68020up | cpu32 },
+{"trapvs", 2,	one(0054774),	one(0177777), "", m68020up | cpu32 },
+
+{"trapccw", 4,	one(0052372),	one(0177777), "#w", m68020up|cpu32 },
+{"trapcsw", 4,	one(0052772),	one(0177777), "#w", m68020up|cpu32 },
+{"trapeqw", 4,	one(0053772),	one(0177777), "#w", m68020up|cpu32 },
+{"trapfw", 4,	one(0050772),	one(0177777), "#w", m68020up|cpu32|mcfisa_a},
+{"trapgew", 4,	one(0056372),	one(0177777), "#w", m68020up|cpu32 },
+{"trapgtw", 4,	one(0057372),	one(0177777), "#w", m68020up|cpu32 },
+{"traphiw", 4,	one(0051372),	one(0177777), "#w", m68020up|cpu32 },
+{"traplew", 4,	one(0057772),	one(0177777), "#w", m68020up|cpu32 },
+{"traplsw", 4,	one(0051772),	one(0177777), "#w", m68020up|cpu32 },
+{"trapltw", 4,	one(0056772),	one(0177777), "#w", m68020up|cpu32 },
+{"trapmiw", 4,	one(0055772),	one(0177777), "#w", m68020up|cpu32 },
+{"trapnew", 4,	one(0053372),	one(0177777), "#w", m68020up|cpu32 },
+{"trapplw", 4,	one(0055372),	one(0177777), "#w", m68020up|cpu32 },
+{"traptw", 4,	one(0050372),	one(0177777), "#w", m68020up|cpu32 },
+{"trapvcw", 4,	one(0054372),	one(0177777), "#w", m68020up|cpu32 },
+{"trapvsw", 4,	one(0054772),	one(0177777), "#w", m68020up|cpu32 },
+
+{"trapccl", 6,	one(0052373),	one(0177777), "#l", m68020up|cpu32 },
+{"trapcsl", 6,	one(0052773),	one(0177777), "#l", m68020up|cpu32 },
+{"trapeql", 6,	one(0053773),	one(0177777), "#l", m68020up|cpu32 },
+{"trapfl", 6,	one(0050773),	one(0177777), "#l", m68020up|cpu32|mcfisa_a},
+{"trapgel", 6,	one(0056373),	one(0177777), "#l", m68020up|cpu32 },
+{"trapgtl", 6,	one(0057373),	one(0177777), "#l", m68020up|cpu32 },
+{"traphil", 6,	one(0051373),	one(0177777), "#l", m68020up|cpu32 },
+{"traplel", 6,	one(0057773),	one(0177777), "#l", m68020up|cpu32 },
+{"traplsl", 6,	one(0051773),	one(0177777), "#l", m68020up|cpu32 },
+{"trapltl", 6,	one(0056773),	one(0177777), "#l", m68020up|cpu32 },
+{"trapmil", 6,	one(0055773),	one(0177777), "#l", m68020up|cpu32 },
+{"trapnel", 6,	one(0053373),	one(0177777), "#l", m68020up|cpu32 },
+{"trappll", 6,	one(0055373),	one(0177777), "#l", m68020up|cpu32 },
+{"traptl", 6,	one(0050373),	one(0177777), "#l", m68020up|cpu32 },
+{"trapvcl", 6,	one(0054373),	one(0177777), "#l", m68020up|cpu32 },
+{"trapvsl", 6,	one(0054773),	one(0177777), "#l", m68020up|cpu32 },
+
+{"trapv", 2,	one(0047166),	one(0177777), "", m68000up },
+
+{"tstb", 2,	one(0045000),	one(0177700), ";b", m68020up|cpu32|mcfisa_a },
+{"tstb", 2,	one(0045000),	one(0177700), "$b", m68000up },
+{"tstw", 2,	one(0045100),	one(0177700), "*w", m68020up|cpu32|mcfisa_a },
+{"tstw", 2,	one(0045100),	one(0177700), "$w", m68000up },
+{"tstl", 2,	one(0045200),	one(0177700), "*l", m68020up|cpu32|mcfisa_a },
+{"tstl", 2,	one(0045200),	one(0177700), "$l", m68000up },
+
+{"unlk", 2,	one(0047130),	one(0177770), "As", m68000up | mcfisa_a },
+
+{"unpk", 4,	one(0100600),	one(0170770), "DsDd#w", m68020up },
+{"unpk", 4,	one(0100610),	one(0170770), "-s-d#w", m68020up },
+
+{"wddatab", 2,	one(0175400),   one(0177700), "~s", mcfisa_a },
+{"wddataw", 2,	one(0175500),   one(0177700), "~s", mcfisa_a },
+{"wddatal", 2,	one(0175600),   one(0177700), "~s", mcfisa_a },
+
+{"wdebug", 4,	two(0175720, 03),	two(0177770, 0xffff), "as", mcfisa_a },
+{"wdebug", 4,	two(0175750, 03),	two(0177770, 0xffff), "ds", mcfisa_a },
+};
+
+const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0];
+
+/* These aliases used to be in the above table, each one duplicating
+   all of the entries for its primary exactly.  This table was
+   constructed by mechanical processing of the opcode table, with a
+   small number of tweaks done by hand.  There are probably a lot more
+   aliases above that could be moved down here, except for very minor
+   differences.  */
+
+const struct m68k_opcode_alias m68k_opcode_aliases[] =
+{
+  { "add",	"addw", },
+  { "adda",	"addaw", },
+  { "addi",	"addiw", },
+  { "addq",	"addqw", },
+  { "addx",	"addxw", },
+  { "asl",	"aslw", },
+  { "asr",	"asrw", },
+  { "bhi",	"bhiw", },
+  { "bls",	"blsw", },
+  { "bcc",	"bccw", },
+  { "bcs",	"bcsw", },
+  { "bne",	"bnew", },
+  { "beq",	"beqw", },
+  { "bvc",	"bvcw", },
+  { "bvs",	"bvsw", },
+  { "bpl",	"bplw", },
+  { "bmi",	"bmiw", },
+  { "bge",	"bgew", },
+  { "blt",	"bltw", },
+  { "bgt",	"bgtw", },
+  { "ble",	"blew", },
+  { "bra",	"braw", },
+  { "bsr",	"bsrw", },
+  { "bhib",	"bhis", },
+  { "blsb",	"blss", },
+  { "bccb",	"bccs", },
+  { "bcsb",	"bcss", },
+  { "bneb",	"bnes", },
+  { "beqb",	"beqs", },
+  { "bvcb",	"bvcs", },
+  { "bvsb",	"bvss", },
+  { "bplb",	"bpls", },
+  { "bmib",	"bmis", },
+  { "bgeb",	"bges", },
+  { "bltb",	"blts", },
+  { "bgtb",	"bgts", },
+  { "bleb",	"bles", },
+  { "brab",	"bras", },
+  { "bsrb",	"bsrs", },
+  { "bhs",	"bccw" },
+  { "bhss",	"bccs" },
+  { "bhsb",	"bccs" },
+  { "bhsw",	"bccw" },
+  { "bhsl",	"bccl" },
+  { "blo",	"bcsw" },
+  { "blos",	"bcss" },
+  { "blob",	"bcss" },
+  { "blow",	"bcsw" },
+  { "blol",	"bcsl" },
+  { "br",	"braw", },
+  { "brs",	"bras", },
+  { "brb",	"bras", },
+  { "brw",	"braw", },
+  { "brl",	"bral", },
+  { "jfnlt",	"bcc", },	/* Apparently a sun alias.  */
+  { "jfngt",	"ble", },	/* Apparently a sun alias.  */
+  { "jfeq",	"beqs", },	/* Apparently a sun alias.  */
+  { "bchgb",	"bchg", },
+  { "bchgl",	"bchg", },
+  { "bclrb",	"bclr", },
+  { "bclrl",	"bclr", },
+  { "bsetb",	"bset", },
+  { "bsetl",	"bset", },
+  { "btstb",	"btst", },
+  { "btstl",	"btst", },
+  { "cas2",	"cas2w", },
+  { "cas",	"casw", },
+  { "chk2",	"chk2w", },
+  { "chk",	"chkw", },
+  { "clr",	"clrw", },
+  { "cmp2",	"cmp2w", },
+  { "cmpa",	"cmpaw", },
+  { "cmpi",	"cmpiw", },
+  { "cmpm",	"cmpmw", },
+  { "cmp",	"cmpw", },
+  { "dbccw",	"dbcc", },
+  { "dbcsw",	"dbcs", },
+  { "dbeqw",	"dbeq", },
+  { "dbfw",	"dbf", },
+  { "dbgew",	"dbge", },
+  { "dbgtw",	"dbgt", },
+  { "dbhiw",	"dbhi", },
+  { "dblew",	"dble", },
+  { "dblsw",	"dbls", },
+  { "dbltw",	"dblt", },
+  { "dbmiw",	"dbmi", },
+  { "dbnew",	"dbne", },
+  { "dbplw",	"dbpl", },
+  { "dbtw",	"dbt", },
+  { "dbvcw",	"dbvc", },
+  { "dbvsw",	"dbvs", },
+  { "dbhs",	"dbcc", },
+  { "dbhsw",	"dbcc", },
+  { "dbra",	"dbf", },
+  { "dbraw",	"dbf", },
+  { "tdivsl",	"divsl", },
+  { "divs",	"divsw", },
+  { "divu",	"divuw", },
+  { "ext",	"extw", },
+  { "extbw",	"extw", },
+  { "extwl",	"extl", },
+  { "fbneq",	"fbne", },
+  { "fbsneq",	"fbsne", },
+  { "fdbneq",	"fdbne", },
+  { "fdbsneq",	"fdbsne", },
+  { "fmovecr",	"fmovecrx", },
+  { "fmovm",	"fmovem", },
+  { "fsneq",	"fsne", },
+  { "fssneq",	"fssne", },
+  { "ftrapneq",	"ftrapne", },
+  { "ftrapsneq", "ftrapsne", },
+  { "fjneq",	"fjne", },
+  { "fjsneq",	"fjsne", },
+  { "jmpl",	"jmp", },
+  { "jmps",	"jmp", },
+  { "jsrl",	"jsr", },
+  { "jsrs",	"jsr", },
+  { "leal",	"lea", },
+  { "lsl",	"lslw", },
+  { "lsr",	"lsrw", },
+  { "mac",	"macw" },
+  { "movea",	"moveaw", },
+  { "movem",	"movemw", },
+  { "movml",	"moveml", },
+  { "movmw",	"movemw", },
+  { "movm",	"movemw", },
+  { "movep",	"movepw", },
+  { "movpw",	"movepw", },
+  { "moves",	"movesw" },
+  { "muls",	"mulsw", },
+  { "mulu",	"muluw", },
+  { "msac",	"msacw" },
+  { "nbcdb",	"nbcd" },
+  { "neg",	"negw", },
+  { "negx",	"negxw", },
+  { "not",	"notw", },
+  { "peal",	"pea", },
+  { "rol",	"rolw", },
+  { "ror",	"rorw", },
+  { "roxl",	"roxlw", },
+  { "roxr",	"roxrw", },
+  { "sats",	"satsl", },
+  { "sbcdb",	"sbcd", },
+  { "sccb",	"scc", },
+  { "scsb",	"scs", },
+  { "seqb",	"seq", },
+  { "sfb",	"sf", },
+  { "sgeb",	"sge", },
+  { "sgtb",	"sgt", },
+  { "shib",	"shi", },
+  { "sleb",	"sle", },
+  { "slsb",	"sls", },
+  { "sltb",	"slt", },
+  { "smib",	"smi", },
+  { "sneb",	"sne", },
+  { "splb",	"spl", },
+  { "stb",	"st", },
+  { "svcb",	"svc", },
+  { "svsb",	"svs", },
+  { "sfge",	"sge", },
+  { "sfgt",	"sgt", },
+  { "sfle",	"sle", },
+  { "sflt",	"slt", },
+  { "sfneq",	"sne", },
+  { "suba",	"subaw", },
+  { "subi",	"subiw", },
+  { "subq",	"subqw", },
+  { "sub",	"subw", },
+  { "subx",	"subxw", },
+  { "swapw",	"swap", },
+  { "tasb",	"tas", },
+  { "tpcc",	"trapcc", },
+  { "tcc",	"trapcc", },
+  { "tst",	"tstw", },
+  { "jbra",	"jra", },
+  { "jbhi",	"jhi", },
+  { "jbls",	"jls", },
+  { "jbcc",	"jcc", },
+  { "jbcs",	"jcs", },
+  { "jbne",	"jne", },
+  { "jbeq",	"jeq", },
+  { "jbvc",	"jvc", },
+  { "jbvs",	"jvs", },
+  { "jbpl",	"jpl", },
+  { "jbmi",	"jmi", },
+  { "jbge",	"jge", },
+  { "jblt",	"jlt", },
+  { "jbgt",	"jgt", },
+  { "jble",	"jle", },
+  { "movql",	"moveq", },
+  { "moveql",	"moveq", },
+  { "movl",	"movel", },
+  { "movq",	"moveq", },
+  { "moval",	"moveal", },
+  { "movaw",	"moveaw", },
+  { "movb",	"moveb", },
+  { "movc",	"movec", },
+  { "movecl",	"movec", },
+  { "movpl",	"movepl", },
+  { "movw",	"movew", },
+  { "movsb",	"movesb", },
+  { "movsl",	"movesl", },
+  { "movsw",	"movesw", },
+  { "mov3q",	"mov3ql", },
+
+  { "tdivul",	"divul", },	/* For m68k-svr4.  */
+  { "fmovb",	"fmoveb", },
+  { "fsmovb",	"fsmoveb", },
+  { "fdmovb",	"fdmoveb", },
+  { "fmovd",	"fmoved", },
+  { "fsmovd",	"fsmoved", },
+  { "fmovl",	"fmovel", },
+  { "fsmovl",	"fsmovel", },
+  { "fdmovl",	"fdmovel", },
+  { "fmovp",	"fmovep", },
+  { "fsmovp",	"fsmovep", },
+  { "fdmovp",	"fdmovep", },
+  { "fmovs",	"fmoves", },
+  { "fsmovs",	"fsmoves", },
+  { "fdmovs",	"fdmoves", },
+  { "fmovw",	"fmovew", },
+  { "fsmovw",	"fsmovew", },
+  { "fdmovw",	"fdmovew", },
+  { "fmovx",	"fmovex", },
+  { "fsmovx",	"fsmovex", },
+  { "fdmovx",	"fdmovex", },
+  { "fmovcr",	"fmovecr", },
+  { "fmovcrx",	"fmovecrx", },
+  { "ftestb",	"ftstb", },
+  { "ftestd",	"ftstd", },
+  { "ftestl",	"ftstl", },
+  { "ftestp",	"ftstp", },
+  { "ftests",	"ftsts", },
+  { "ftestw",	"ftstw", },
+  { "ftestx",	"ftstx", },
+
+  { "bitrevl",  "bitrev", },
+  { "byterevl", "byterev", },
+  { "ff1l",     "ff1", },
+
+};
+
+const int m68k_numaliases =
+  sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0];
+/* **** End of m68k-opc.c */
+/* **** floatformat.c from sourceware.org CVS 2005-08-14.  */
+/* IEEE floating point support routines, for GDB, the GNU Debugger.
+   Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* This is needed to pick up the NAN macro on some systems.  */
+//#define _GNU_SOURCE
+
+#ifndef INFINITY
+#ifdef HUGE_VAL
+#define INFINITY HUGE_VAL
+#else
+#define INFINITY (1.0 / 0.0)
+#endif
+#endif
+
+#ifndef NAN
+#define NAN (0.0 / 0.0)
+#endif
+
+static unsigned long get_field (const unsigned char *,
+                                enum floatformat_byteorders,
+                                unsigned int,
+                                unsigned int,
+                                unsigned int);
+static int floatformat_always_valid (const struct floatformat *fmt,
+                                     const char *from);
+
+static int
+floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
+                          const char *from ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
+   going to bother with trying to muck around with whether it is defined in
+   a system header, what we do if not, etc.  */
+#define FLOATFORMAT_CHAR_BIT 8
+
+/* floatformats for IEEE single and double, big and little endian.  */
+const struct floatformat floatformat_ieee_single_big =
+{
+  floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
+  floatformat_intbit_no,
+  "floatformat_ieee_single_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_single_little =
+{
+  floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
+  floatformat_intbit_no,
+  "floatformat_ieee_single_little",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_double_big =
+{
+  floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_double_little =
+{
+  floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_little",
+  floatformat_always_valid
+};
+
+/* floatformat for IEEE double, little endian byte order, with big endian word
+   ordering, as on the ARM.  */
+
+const struct floatformat floatformat_ieee_double_littlebyte_bigword =
+{
+  floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_littlebyte_bigword",
+  floatformat_always_valid
+};
+
+static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from);
+
+static int
+floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from)
+{
+  /* In the i387 double-extended format, if the exponent is all ones,
+     then the integer bit must be set.  If the exponent is neither 0
+     nor ~0, the intbit must also be set.  Only if the exponent is
+     zero can it be zero, and then it must be zero.  */
+  unsigned long exponent, int_bit;
+  const unsigned char *ufrom = (const unsigned char *) from;
+
+  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+			fmt->exp_start, fmt->exp_len);
+  int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+		       fmt->man_start, 1);
+
+  if ((exponent == 0) != (int_bit == 0))
+    return 0;
+  else
+    return 1;
+}
+
+const struct floatformat floatformat_i387_ext =
+{
+  floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
+  floatformat_intbit_yes,
+  "floatformat_i387_ext",
+  floatformat_i387_ext_is_valid
+};
+const struct floatformat floatformat_m68881_ext =
+{
+  /* Note that the bits from 16 to 31 are unused.  */
+  floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_m68881_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_i960_ext =
+{
+  /* Note that the bits from 0 to 15 are unused.  */
+  floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_i960_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_m88110_ext =
+{
+  floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
+  floatformat_intbit_yes,
+  "floatformat_m88110_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_m88110_harris_ext =
+{
+  /* Harris uses raw format 128 bytes long, but the number is just an ieee
+     double, and the last 64 bits are wasted. */
+  floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_m88110_ext_harris",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_arm_ext_big =
+{
+  /* Bits 1 to 16 are unused.  */
+  floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_arm_ext_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_arm_ext_littlebyte_bigword =
+{
+  /* Bits 1 to 16 are unused.  */
+  floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_arm_ext_littlebyte_bigword",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_spill_big =
+{
+  floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
+  floatformat_intbit_yes,
+  "floatformat_ia64_spill_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_spill_little =
+{
+  floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
+  floatformat_intbit_yes,
+  "floatformat_ia64_spill_little",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_quad_big =
+{
+  floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
+  floatformat_intbit_no,
+  "floatformat_ia64_quad_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_quad_little =
+{
+  floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
+  floatformat_intbit_no,
+  "floatformat_ia64_quad_little",
+  floatformat_always_valid
+};
+
+/* Extract a field which starts at START and is LEN bits long.  DATA and
+   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
+static unsigned long
+get_field (const unsigned char *data, enum floatformat_byteorders order,
+           unsigned int total_len, unsigned int start, unsigned int len)
+{
+  unsigned long result;
+  unsigned int cur_byte;
+  int cur_bitshift;
+
+  /* Start at the least significant part of the field.  */
+  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
+  cur_bitshift =
+    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+  result = *(data + cur_byte) >> (-cur_bitshift);
+  cur_bitshift += FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    ++cur_byte;
+  else
+    --cur_byte;
+
+  /* Move towards the most significant part of the field.  */
+  while ((unsigned int) cur_bitshift < len)
+    {
+      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
+	/* This is the last byte; zero out the bits which are not part of
+	   this field.  */
+	result |=
+	  (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
+	    << cur_bitshift;
+      else
+	result |= *(data + cur_byte) << cur_bitshift;
+      cur_bitshift += FLOATFORMAT_CHAR_BIT;
+      if (order == floatformat_little)
+	++cur_byte;
+      else
+	--cur_byte;
+    }
+  return result;
+}
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* Convert from FMT to a double.
+   FROM is the address of the extended float.
+   Store the double in *TO.  */
+
+void
+floatformat_to_double (const struct floatformat *fmt,
+                       const char *from, double *to)
+{
+  const unsigned char *ufrom = (const unsigned char *)from;
+  double dto;
+  long exponent;
+  unsigned long mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  int special_exponent;		/* It's a NaN, denorm or zero */
+
+  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+			fmt->exp_start, fmt->exp_len);
+
+  /* If the exponent indicates a NaN, we don't have information to
+     decide what to do.  So we handle it like IEEE, except that we
+     don't try to preserve the type of NaN.  FIXME.  */
+  if ((unsigned long) exponent == fmt->exp_nan)
+    {
+      int nan;
+
+      mant_off = fmt->man_start;
+      mant_bits_left = fmt->man_len;
+      nan = 0;
+      while (mant_bits_left > 0)
+	{
+	  mant_bits = min (mant_bits_left, 32);
+
+	  if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
+			 mant_off, mant_bits) != 0)
+	    {
+	      /* This is a NaN.  */
+	      nan = 1;
+	      break;
+	    }
+
+	  mant_off += mant_bits;
+	  mant_bits_left -= mant_bits;
+	}
+
+      /* On certain systems (such as GNU/Linux), the use of the
+	 INFINITY macro below may generate a warning that can not be
+	 silenced due to a bug in GCC (PR preprocessor/11931).  The
+	 preprocessor fails to recognise the __extension__ keyword in
+	 conjunction with the GNU/C99 extension for hexadecimal
+	 floating point constants and will issue a warning when
+	 compiling with -pedantic.  */
+      if (nan)
+	dto = NAN;
+      else
+	dto = INFINITY;
+
+      if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+	dto = -dto;
+
+      *to = dto;
+
+      return;
+    }
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  dto = 0.0;
+
+  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
+
+  /* Don't bias zero's, denorms or NaNs.  */
+  if (!special_exponent)
+    exponent -= fmt->exp_bias;
+
+  /* Build the result algebraically.  Might go infinite, underflow, etc;
+     who cares. */
+
+  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
+     increment the exponent by one to account for the integer bit.  */
+
+  if (!special_exponent)
+    {
+      if (fmt->intbit == floatformat_intbit_no)
+	dto = ldexp (1.0, exponent);
+      else
+	exponent++;
+    }
+
+  while (mant_bits_left > 0)
+    {
+      mant_bits = min (mant_bits_left, 32);
+
+      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+			 mant_off, mant_bits);
+
+      /* Handle denormalized numbers.  FIXME: What should we do for
+	 non-IEEE formats?  */
+      if (exponent == 0 && mant != 0)
+	dto += ldexp ((double)mant,
+		      (- fmt->exp_bias
+		       - mant_bits
+		       - (mant_off - fmt->man_start)
+		       + 1));
+      else
+	dto += ldexp ((double)mant, exponent - mant_bits);
+      if (exponent != 0)
+	exponent -= mant_bits;
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+
+  /* Negate it if negative.  */
+  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+    dto = -dto;
+  *to = dto;
+}
+
+static void put_field (unsigned char *, enum floatformat_byteorders,
+                       unsigned int,
+                       unsigned int,
+                       unsigned int,
+                       unsigned long);
+
+/* Set a field which starts at START and is LEN bits long.  DATA and
+   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
+static void
+put_field (unsigned char *data, enum floatformat_byteorders order,
+           unsigned int total_len, unsigned int start, unsigned int len,
+           unsigned long stuff_to_put)
+{
+  unsigned int cur_byte;
+  int cur_bitshift;
+
+  /* Start at the least significant part of the field.  */
+  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
+  cur_bitshift =
+    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+  *(data + cur_byte) &=
+    ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
+  *(data + cur_byte) |=
+    (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
+  cur_bitshift += FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    ++cur_byte;
+  else
+    --cur_byte;
+
+  /* Move towards the most significant part of the field.  */
+  while ((unsigned int) cur_bitshift < len)
+    {
+      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
+	{
+	  /* This is the last byte.  */
+	  *(data + cur_byte) &=
+	    ~((1 << (len - cur_bitshift)) - 1);
+	  *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
+	}
+      else
+	*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
+			      & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
+      cur_bitshift += FLOATFORMAT_CHAR_BIT;
+      if (order == floatformat_little)
+	++cur_byte;
+      else
+	--cur_byte;
+    }
+}
+
+/* The converse: convert the double *FROM to an extended float
+   and store where TO points.  Neither FROM nor TO have any alignment
+   restrictions.  */
+
+void
+floatformat_from_double (const struct floatformat *fmt,
+                         const double *from, char *to)
+{
+  double dfrom;
+  int exponent;
+  double mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  unsigned char *uto = (unsigned char *)to;
+
+  dfrom = *from;
+  memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
+
+  /* If negative, set the sign bit.  */
+  if (dfrom < 0)
+    {
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+      dfrom = -dfrom;
+    }
+
+  if (dfrom == 0)
+    {
+      /* 0.0.  */
+      return;
+    }
+
+  if (dfrom != dfrom)
+    {
+      /* NaN.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+		 fmt->exp_len, fmt->exp_nan);
+      /* Be sure it's not infinity, but NaN value is irrelevant.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+		 32, 1);
+      return;
+    }
+
+  if (dfrom + dfrom == dfrom)
+    {
+      /* This can only happen for an infinite value (or zero, which we
+	 already handled above).  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+		 fmt->exp_len, fmt->exp_nan);
+      return;
+    }
+
+  mant = frexp (dfrom, &exponent);
+  if (exponent + fmt->exp_bias - 1 > 0)
+    put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+	       fmt->exp_len, exponent + fmt->exp_bias - 1);
+  else
+    {
+      /* Handle a denormalized number.  FIXME: What should we do for
+	 non-IEEE formats?  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+		 fmt->exp_len, 0);
+      mant = ldexp (mant, exponent + fmt->exp_bias - 1);
+    }
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  while (mant_bits_left > 0)
+    {
+      unsigned long mant_long;
+      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
+
+      mant *= 4294967296.0;
+      mant_long = (unsigned long)mant;
+      mant -= mant_long;
+
+      /* If the integer bit is implicit, and we are not creating a
+	 denormalized number, then we need to discard it.  */
+      if ((unsigned int) mant_bits_left == fmt->man_len
+	  && fmt->intbit == floatformat_intbit_no
+	  && exponent + fmt->exp_bias - 1 > 0)
+	{
+	  mant_long &= 0x7fffffff;
+	  mant_bits -= 1;
+	}
+      else if (mant_bits < 32)
+	{
+	  /* The bits we want are in the most significant MANT_BITS bits of
+	     mant_long.  Move them to the least significant.  */
+	  mant_long >>= 32 - mant_bits;
+	}
+
+      put_field (uto, fmt->byteorder, fmt->totalsize,
+		 mant_off, mant_bits, mant_long);
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+}
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT.  */
+
+int
+floatformat_is_valid (const struct floatformat *fmt, const char *from)
+{
+  return fmt->is_valid (fmt, from);
+}
+
+
+#ifdef IEEE_DEBUG
+
+/* This is to be run on a host which uses IEEE floating point.  */
+
+void
+ieee_test (double n)
+{
+  double result;
+
+  floatformat_to_double (&floatformat_ieee_double_little, (char *) &n,
+			 &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
+    printf ("Differ(to): %.20g -> %.20g\n", n, result);
+
+  floatformat_from_double (&floatformat_ieee_double_little, &n,
+			   (char *) &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
+    printf ("Differ(from): %.20g -> %.20g\n", n, result);
+
+#if 0
+  {
+    char exten[16];
+
+    floatformat_from_double (&floatformat_m68881_ext, &n, exten);
+    floatformat_to_double (&floatformat_m68881_ext, exten, &result);
+    if (n != result)
+      printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
+  }
+#endif
+
+#if IEEE_DEBUG > 1
+  /* This is to be run on a host which uses 68881 format.  */
+  {
+    long double ex = *(long double *)exten;
+    if (ex != n)
+      printf ("Differ(from vs. extended): %.20g\n", n);
+  }
+#endif
+}
+
+int
+main (void)
+{
+  ieee_test (0.0);
+  ieee_test (0.5);
+  ieee_test (256.0);
+  ieee_test (0.12345);
+  ieee_test (234235.78907234);
+  ieee_test (-512.0);
+  ieee_test (-0.004321);
+  ieee_test (1.2E-70);
+  ieee_test (1.2E-316);
+  ieee_test (4.9406564584124654E-324);
+  ieee_test (- 4.9406564584124654E-324);
+  ieee_test (- 0.0);
+  ieee_test (- INFINITY);
+  ieee_test (- NAN);
+  ieee_test (INFINITY);
+  ieee_test (NAN);
+  return 0;
+}
+#endif
+/* **** End of floatformat.c  */
diff --git a/qemu-0.15.x/m68k-semi.c b/qemu-0.15.x/m68k-semi.c
new file mode 100644
index 0000000..7fde10e
--- /dev/null
+++ b/qemu-0.15.x/m68k-semi.c
@@ -0,0 +1,408 @@
+/*
+ *  m68k/ColdFire Semihosting syscall interface
+ *
+ *  Copyright (c) 2005-2007 CodeSourcery.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "cpu.h"
+#if defined(CONFIG_USER_ONLY)
+#include "qemu.h"
+#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
+#else
+#include "qemu-common.h"
+#include "gdbstub.h"
+#include "softmmu-semi.h"
+#endif
+#include "sysemu.h"
+
+#define HOSTED_EXIT  0
+#define HOSTED_INIT_SIM 1
+#define HOSTED_OPEN 2
+#define HOSTED_CLOSE 3
+#define HOSTED_READ 4
+#define HOSTED_WRITE 5
+#define HOSTED_LSEEK 6
+#define HOSTED_RENAME 7
+#define HOSTED_UNLINK 8
+#define HOSTED_STAT 9
+#define HOSTED_FSTAT 10
+#define HOSTED_GETTIMEOFDAY 11
+#define HOSTED_ISATTY 12
+#define HOSTED_SYSTEM 13
+
+typedef uint32_t gdb_mode_t;
+typedef uint32_t gdb_time_t;
+
+struct m68k_gdb_stat {
+  uint32_t    gdb_st_dev;     /* device */
+  uint32_t    gdb_st_ino;     /* inode */
+  gdb_mode_t  gdb_st_mode;    /* protection */
+  uint32_t    gdb_st_nlink;   /* number of hard links */
+  uint32_t    gdb_st_uid;     /* user ID of owner */
+  uint32_t    gdb_st_gid;     /* group ID of owner */
+  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
+  uint64_t    gdb_st_size;    /* total size, in bytes */
+  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
+  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
+  gdb_time_t  gdb_st_atime;   /* time of last access */
+  gdb_time_t  gdb_st_mtime;   /* time of last modification */
+  gdb_time_t  gdb_st_ctime;   /* time of last change */
+} __attribute__((packed));
+
+struct gdb_timeval {
+  gdb_time_t tv_sec;  /* second */
+  uint64_t tv_usec;   /* microsecond */
+} __attribute__((packed));
+
+#define GDB_O_RDONLY   0x0
+#define GDB_O_WRONLY   0x1
+#define GDB_O_RDWR     0x2
+#define GDB_O_APPEND   0x8
+#define GDB_O_CREAT  0x200
+#define GDB_O_TRUNC  0x400
+#define GDB_O_EXCL   0x800
+
+static int translate_openflags(int flags)
+{
+    int hf;
+
+    if (flags & GDB_O_WRONLY)
+        hf = O_WRONLY;
+    else if (flags & GDB_O_RDWR)
+        hf = O_RDWR;
+    else
+        hf = O_RDONLY;
+
+    if (flags & GDB_O_APPEND) hf |= O_APPEND;
+    if (flags & GDB_O_CREAT) hf |= O_CREAT;
+    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
+    if (flags & GDB_O_EXCL) hf |= O_EXCL;
+
+    return hf;
+}
+
+static void translate_stat(CPUState *env, target_ulong addr, struct stat *s)
+{
+    struct m68k_gdb_stat *p;
+
+    if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0)))
+        /* FIXME - should this return an error code? */
+        return;
+    p->gdb_st_dev = cpu_to_be32(s->st_dev);
+    p->gdb_st_ino = cpu_to_be32(s->st_ino);
+    p->gdb_st_mode = cpu_to_be32(s->st_mode);
+    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
+    p->gdb_st_uid = cpu_to_be32(s->st_uid);
+    p->gdb_st_gid = cpu_to_be32(s->st_gid);
+    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
+    p->gdb_st_size = cpu_to_be64(s->st_size);
+#ifdef _WIN32
+    /* Windows stat is missing some fields.  */
+    p->gdb_st_blksize = 0;
+    p->gdb_st_blocks = 0;
+#else
+    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
+    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
+#endif
+    p->gdb_st_atime = cpu_to_be32(s->st_atime);
+    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
+    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
+    unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
+}
+
+static int m68k_semi_is_fseek;
+
+static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    target_ulong args;
+
+    args = env->dregs[1];
+    if (m68k_semi_is_fseek) {
+        /* FIXME: We've already lost the high bits of the fseek
+           return value.  */
+        /* FIXME - handle put_user() failure */
+        put_user_u32(0, args);
+        args += 4;
+        m68k_semi_is_fseek = 0;
+    }
+    /* FIXME - handle put_user() failure */
+    put_user_u32(ret, args);
+    put_user_u32(errno, args + 4);
+}
+
+#define ARG(n)					\
+({						\
+    target_ulong __arg;				\
+    /* FIXME - handle get_user() failure */	\
+    get_user_ual(__arg, args + (n) * 4);	\
+    __arg;					\
+})
+#define PARG(x) ((unsigned long)ARG(x))
+void do_m68k_semihosting(CPUM68KState *env, int nr)
+{
+    uint32_t args;
+    void *p;
+    void *q;
+    uint32_t len;
+    uint32_t result;
+
+    args = env->dregs[1];
+    switch (nr) {
+    case HOSTED_EXIT:
+        gdb_exit(env, env->dregs[0]);
+        exit(env->dregs[0]);
+    case HOSTED_OPEN:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1),
+                           ARG(2), ARG(3));
+            return;
+        } else {
+            if (!(p = lock_user_string(ARG(0)))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = open(p, translate_openflags(ARG(2)), ARG(3));
+                unlock_user(p, ARG(0), 0);
+            }
+        }
+        break;
+    case HOSTED_CLOSE:
+        {
+            /* Ignore attempts to close stdin/out/err.  */
+            int fd = ARG(0);
+            if (fd > 2) {
+                if (use_gdb_syscalls()) {
+                    gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0));
+                    return;
+                } else {
+                    result = close(fd);
+                }
+            } else {
+                result = 0;
+            }
+            break;
+        }
+    case HOSTED_READ:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
+                           ARG(0), ARG(1), len);
+            return;
+        } else {
+            if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = read(ARG(0), p, len);
+                unlock_user(p, ARG(1), len);
+            }
+        }
+        break;
+    case HOSTED_WRITE:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
+                           ARG(0), ARG(1), len);
+            return;
+        } else {
+            if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = write(ARG(0), p, len);
+                unlock_user(p, ARG(0), 0);
+            }
+        }
+        break;
+    case HOSTED_LSEEK:
+        {
+            uint64_t off;
+            off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
+            if (use_gdb_syscalls()) {
+                m68k_semi_is_fseek = 1;
+                gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
+                               ARG(0), off, ARG(3));
+            } else {
+                off = lseek(ARG(0), off, ARG(3));
+                /* FIXME - handle put_user() failure */
+                put_user_u32(off >> 32, args);
+                put_user_u32(off, args + 4);
+                put_user_u32(errno, args + 8);
+            }
+            return;
+        }
+    case HOSTED_RENAME:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "rename,%s,%s",
+                           ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
+            return;
+        } else {
+            p = lock_user_string(ARG(0));
+            q = lock_user_string(ARG(2));
+            if (!p || !q) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = rename(p, q);
+            }
+            unlock_user(p, ARG(0), 0);
+            unlock_user(q, ARG(2), 0);
+        }
+        break;
+    case HOSTED_UNLINK:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "unlink,%s",
+                           ARG(0), (int)ARG(1));
+            return;
+        } else {
+            if (!(p = lock_user_string(ARG(0)))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = unlink(p);
+                unlock_user(p, ARG(0), 0);
+            }
+        }
+        break;
+    case HOSTED_STAT:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
+                           ARG(0), (int)ARG(1), ARG(2));
+            return;
+        } else {
+            struct stat s;
+            if (!(p = lock_user_string(ARG(0)))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = stat(p, &s);
+                unlock_user(p, ARG(0), 0);
+            }
+            if (result == 0) {
+                translate_stat(env, ARG(2), &s);
+            }
+        }
+        break;
+    case HOSTED_FSTAT:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
+                           ARG(0), ARG(1));
+            return;
+        } else {
+            struct stat s;
+            result = fstat(ARG(0), &s);
+            if (result == 0) {
+                translate_stat(env, ARG(1), &s);
+            }
+        }
+        break;
+    case HOSTED_GETTIMEOFDAY:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
+                           ARG(0), ARG(1));
+            return;
+        } else {
+            qemu_timeval tv;
+            struct gdb_timeval *p;
+            result = qemu_gettimeofday(&tv);
+            if (result != 0) {
+                if (!(p = lock_user(VERIFY_WRITE,
+                                    ARG(0), sizeof(struct gdb_timeval), 0))) {
+                    /* FIXME - check error code? */
+                    result = -1;
+                } else {
+                    p->tv_sec = cpu_to_be32(tv.tv_sec);
+                    p->tv_usec = cpu_to_be64(tv.tv_usec);
+                    unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
+                }
+            }
+        }
+        break;
+    case HOSTED_ISATTY:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0));
+            return;
+        } else {
+            result = isatty(ARG(0));
+        }
+        break;
+    case HOSTED_SYSTEM:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "system,%s",
+                           ARG(0), (int)ARG(1));
+            return;
+        } else {
+            if (!(p = lock_user_string(ARG(0)))) {
+                /* FIXME - check error code? */
+                result = -1;
+            } else {
+                result = system(p);
+                unlock_user(p, ARG(0), 0);
+            }
+        }
+        break;
+    case HOSTED_INIT_SIM:
+#if defined(CONFIG_USER_ONLY)
+        {
+        TaskState *ts = env->opaque;
+        /* Allocate the heap using sbrk.  */
+        if (!ts->heap_limit) {
+            abi_ulong ret;
+            uint32_t size;
+            uint32_t base;
+
+            base = do_brk(0);
+            size = SEMIHOSTING_HEAP_SIZE;
+            /* Try a big heap, and reduce the size if that fails.  */
+            for (;;) {
+                ret = do_brk(base + size);
+                if (ret >= (base + size)) {
+                    break;
+                }
+                size >>= 1;
+            }
+            ts->heap_limit = base + size;
+        }
+        /* This call may happen before we have writable memory, so return
+           values directly in registers.  */
+        env->dregs[1] = ts->heap_limit;
+        env->aregs[7] = ts->stack_base;
+        }
+#else
+        /* FIXME: This is wrong for boards where RAM does not start at
+           address zero.  */
+        env->dregs[1] = ram_size;
+        env->aregs[7] = ram_size;
+#endif
+        return;
+    default:
+        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
+        result = 0;
+    }
+    /* FIXME - handle put_user() failure */
+    put_user_u32(result, args);
+    put_user_u32(errno, args + 4);
+}
diff --git a/qemu-0.15.x/m68k.ld b/qemu-0.15.x/m68k.ld
new file mode 100644
index 0000000..0e3d9de
--- /dev/null
+++ b/qemu-0.15.x/m68k.ld
@@ -0,0 +1,175 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
+	      "elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+/* __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.dyn        :
+    {
+      *(.rel.init)
+      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+      *(.rel.fini)
+      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+      *(.rel.ctors)
+      *(.rel.dtors)
+      *(.rel.got)
+      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+    }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x4e754e75
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x4e754e75
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x4e754e75
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x2000) + (. & (0x2000 - 1));
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/qemu-0.15.x/microblaze-dis.c b/qemu-0.15.x/microblaze-dis.c
new file mode 100644
index 0000000..16c312f
--- /dev/null
+++ b/qemu-0.15.x/microblaze-dis.c
@@ -0,0 +1,1100 @@
+/* Disassemble Xilinx microblaze instructions.
+   Copyright (C) 1993, 1999, 2000 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc.  All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc.  The name of the Company may not be used to endorse 
+ * or promote products derived from this software without specific prior 
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *	Xilinx, Inc.
+ */
+
+
+#include <stdio.h>
+#define STATIC_TABLE
+#define DEFINE_TABLE
+
+#define TRUE   1
+#define FALSE  0
+
+#ifndef MICROBLAZE_OPC
+#define MICROBLAZE_OPC
+/* Assembler instructions for Xilinx's microblaze processor
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+   
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc.  All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc.  The name of the Company may not be used to endorse 
+ * or promote products derived from this software without specific prior 
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *	Xilinx, Inc.
+ */
+
+
+#ifndef MICROBLAZE_OPCM
+#define MICROBLAZE_OPCM
+
+/*
+ * Copyright (c) 2001 Xilinx, Inc.  All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Xilinx, Inc.  The name of the Company may not be used to endorse 
+ * or promote products derived from this software without specific prior 
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *	Xilinx, Inc.
+ * $Header:
+ */
+
+enum microblaze_instr {
+   add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu,
+   addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul, mulh, mulhu, mulhsu,
+   idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
+   ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor,
+   andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, wdcclear, wdcflush, mts, mfs, br, brd,
+   brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt,
+   bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni,
+   imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid,
+   brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti,
+   bgtid, bgei, bgeid, lbu, lhu, lw, lwx, sb, sh, sw, swx, lbui, lhui, lwi,
+   sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv, 
+   fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, flt, fint, fsqrt, 
+   tget, tcget, tnget, tncget, tput, tcput, tnput, tncput,
+   eget, ecget, neget, necget, eput, ecput, neput, necput,
+   teget, tecget, tneget, tnecget, teput, tecput, tneput, tnecput,
+   aget, caget, naget, ncaget, aput, caput, naput, ncaput,
+   taget, tcaget, tnaget, tncaget, taput, tcaput, tnaput, tncaput,
+   eaget, ecaget, neaget, necaget, eaput, ecaput, neaput, necaput,
+   teaget, tecaget, tneaget, tnecaget, teaput, tecaput, tneaput, tnecaput,
+   getd, tgetd, cgetd, tcgetd, ngetd, tngetd, ncgetd, tncgetd,
+   putd, tputd, cputd, tcputd, nputd, tnputd, ncputd, tncputd,
+   egetd, tegetd, ecgetd, tecgetd, negetd, tnegetd, necgetd, tnecgetd,
+   eputd, teputd, ecputd, tecputd, neputd, tneputd, necputd, tnecputd,
+   agetd, tagetd, cagetd, tcagetd, nagetd, tnagetd, ncagetd, tncagetd,
+   aputd, taputd, caputd, tcaputd, naputd, tnaputd, ncaputd, tncaputd,
+   eagetd, teagetd, ecagetd, tecagetd, neagetd, tneagetd, necagetd, tnecagetd,
+   eaputd, teaputd, ecaputd, tecaputd, neaputd, tneaputd, necaputd, tnecaputd,
+   invalid_inst } ;
+
+enum microblaze_instr_type {
+   arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst,
+   return_inst, immediate_inst, special_inst, memory_load_inst,
+   memory_store_inst, barrel_shift_inst, anyware_inst };
+
+#define INST_WORD_SIZE 4
+
+/* gen purpose regs go from 0 to 31 */
+/* mask is reg num - max_reg_num, ie reg_num - 32 in this case */
+
+#define REG_PC_MASK 0x8000
+#define REG_MSR_MASK 0x8001
+#define REG_EAR_MASK 0x8003
+#define REG_ESR_MASK 0x8005
+#define REG_FSR_MASK 0x8007
+#define REG_BTR_MASK 0x800b
+#define REG_EDR_MASK 0x800d
+#define REG_PVR_MASK 0xa000
+
+#define REG_PID_MASK   0x9000
+#define REG_ZPR_MASK   0x9001
+#define REG_TLBX_MASK  0x9002
+#define REG_TLBLO_MASK 0x9003
+#define REG_TLBHI_MASK 0x9004
+#define REG_TLBSX_MASK 0x9005
+
+#define MIN_REGNUM 0
+#define MAX_REGNUM 31
+
+#define MIN_PVR_REGNUM 0
+#define MAX_PVR_REGNUM 15
+
+#define REG_PC  32 /* PC */
+#define REG_MSR 33 /* machine status reg */
+#define REG_EAR 35 /* Exception reg */
+#define REG_ESR 37 /* Exception reg */
+#define REG_FSR 39 /* FPU Status reg */
+#define REG_BTR 43 /* Branch Target reg */
+#define REG_EDR 45 /* Exception reg */
+#define REG_PVR 40960 /* Program Verification reg */
+
+#define REG_PID   36864 /* MMU: Process ID reg       */
+#define REG_ZPR   36865 /* MMU: Zone Protect reg     */
+#define REG_TLBX  36866 /* MMU: TLB Index reg        */
+#define REG_TLBLO 36867 /* MMU: TLB Low reg          */
+#define REG_TLBHI 36868 /* MMU: TLB High reg         */
+#define REG_TLBSX 36869 /* MMU: TLB Search Index reg */
+
+/* alternate names for gen purpose regs */
+#define REG_SP  1 /* stack pointer */
+#define REG_ROSDP 2 /* read-only small data pointer */
+#define REG_RWSDP 13 /* read-write small data pointer */
+
+/* Assembler Register - Used in Delay Slot Optimization */
+#define REG_AS    18
+#define REG_ZERO  0
+ 
+#define RD_LOW  21 /* low bit for RD */
+#define RA_LOW  16 /* low bit for RA */
+#define RB_LOW  11 /* low bit for RB */
+#define IMM_LOW  0 /* low bit for immediate */
+
+#define RD_MASK 0x03E00000
+#define RA_MASK 0x001F0000
+#define RB_MASK 0x0000F800
+#define IMM_MASK 0x0000FFFF
+
+// imm mask for barrel shifts
+#define IMM5_MASK 0x0000001F
+
+
+// FSL imm mask for get, put instructions
+#define  RFSL_MASK 0x000000F
+
+// imm mask for msrset, msrclr instructions
+#define  IMM15_MASK 0x00007FFF
+
+#endif /* MICROBLAZE-OPCM */
+
+#define INST_TYPE_RD_R1_R2 0
+#define INST_TYPE_RD_R1_IMM 1
+#define INST_TYPE_RD_R1_UNSIGNED_IMM 2
+#define INST_TYPE_RD_R1 3
+#define INST_TYPE_RD_R2 4
+#define INST_TYPE_RD_IMM 5
+#define INST_TYPE_R2 6
+#define INST_TYPE_R1_R2 7
+#define INST_TYPE_R1_IMM 8
+#define INST_TYPE_IMM 9
+#define INST_TYPE_SPECIAL_R1 10
+#define INST_TYPE_RD_SPECIAL 11
+#define INST_TYPE_R1 12
+  // new instn type for barrel shift imms
+#define INST_TYPE_RD_R1_IMM5  13
+#define INST_TYPE_RD_RFSL    14
+#define INST_TYPE_R1_RFSL    15
+
+  // new insn type for insn cache
+#define INST_TYPE_RD_R1_SPECIAL 16
+
+// new insn type for msrclr, msrset insns.
+#define INST_TYPE_RD_IMM15    17
+
+// new insn type for tuqula rd - addik rd, r0, 42
+#define INST_TYPE_RD    18
+
+// new insn type for t*put
+#define INST_TYPE_RFSL  19
+
+#define INST_TYPE_NONE 25
+
+
+
+#define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/
+#define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/
+
+#define IMMVAL_MASK_NON_SPECIAL 0x0000
+#define IMMVAL_MASK_MTS 0x4000
+#define IMMVAL_MASK_MFS 0x0000
+
+#define OPCODE_MASK_H   0xFC000000 /* High 6 bits only */
+#define OPCODE_MASK_H1  0xFFE00000 /* High 11 bits */
+#define OPCODE_MASK_H2  0xFC1F0000 /* High 6 and bits 20-16 */
+#define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */
+#define OPCODE_MASK_H4  0xFC0007FF /* High 6 and low 11 bits */
+#define OPCODE_MASK_H13S 0xFFE0EFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */
+#define OPCODE_MASK_H23S 0xFC1FC000 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */
+#define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */
+#define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */
+#define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */
+#define OPCODE_MASK_H124  0xFFFF07FF /* High 16, and low 11 bits */
+#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */
+#define OPCODE_MASK_H3  0xFC000600 /* High 6 bits and bits 21, 22 */  
+#define OPCODE_MASK_H32 0xFC00FC00 /* High 6 bits and bit 16-21 */
+#define OPCODE_MASK_H34B   0xFC0000FF /* High 6 bits and low 8 bits */
+#define OPCODE_MASK_H34C   0xFC0007E0 /* High 6 bits and bits 21-26 */
+
+// New Mask for msrset, msrclr insns.
+#define OPCODE_MASK_H23N  0xFC1F8000 /* High 6 and bits 11 - 16 */
+
+#define DELAY_SLOT 1
+#define NO_DELAY_SLOT 0
+
+#define MAX_OPCODES 280
+
+struct op_code_struct {
+  const char *name;
+  short inst_type; /* registers and immediate values involved */
+  short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */
+  short delay_slots; /* info about delay slots needed after this instr. */
+  short immval_mask;
+  unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */ 
+  unsigned long opcode_mask; /* which bits define the opcode */
+  enum microblaze_instr instr;
+  enum microblaze_instr_type instr_type;
+  /* more info about output format here */
+} opcodes[MAX_OPCODES] = 
+
+{ 
+  {"add",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst },
+  {"rsub",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst },
+  {"addc",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst },
+  {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst },
+  {"addk",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst },
+  {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst },
+  {"cmp",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst },
+  {"cmpu",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst },
+  {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst },
+  {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst },
+  {"addi",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst },
+  {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst },
+  {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst },
+  {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst },
+  {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst },
+  {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst },
+  {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst },
+  {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst },
+  {"mul",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst },
+  {"mulh",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000001, OPCODE_MASK_H4, mulh, mult_inst },
+  {"mulhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000003, OPCODE_MASK_H4, mulhu, mult_inst },
+  {"mulhsu",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000002, OPCODE_MASK_H4, mulhsu, mult_inst },
+  {"idiv",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst },
+  {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst },
+  {"bsll",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst },
+  {"bsra",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst },
+  {"bsrl",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst },
+  {"get",   INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst },
+  {"put",   INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst },
+  {"nget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst },
+  {"nput",  INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst },
+  {"cget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst },
+  {"cput",  INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst },
+  {"ncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst },
+  {"ncput", INST_TYPE_R1_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst },
+  {"muli",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst },
+  {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst },
+  {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst },
+  {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst },
+  {"or",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst },
+  {"and",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst },
+  {"xor",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst },
+  {"andn",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst },
+  {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst },
+  {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst },
+  {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst },
+  {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst },
+  {"sra",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst },
+  {"src",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst },
+  {"srl",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst },
+  {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst },
+  {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst },
+  {"wic",   INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst },
+  {"wdc",   INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst },
+  {"wdc.clear", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000066, OPCODE_MASK_H34B, wdcclear, special_inst },
+  {"wdc.flush", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000074, OPCODE_MASK_H34B, wdcflush, special_inst },
+  {"mts",   INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst },
+  {"mfs",   INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst },
+  {"br",    INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst },
+  {"brd",   INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst },
+  {"brld",  INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst },
+  {"bra",   INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst },
+  {"brad",  INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst },
+  {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst },
+  {"brk",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst },
+  {"beq",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst },
+  {"beqd",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst },
+  {"bne",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst },
+  {"bned",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst },
+  {"blt",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst },
+  {"bltd",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst },
+  {"ble",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst },
+  {"bled",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst },
+  {"bgt",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst },
+  {"bgtd",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst },
+  {"bge",   INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst },
+  {"bged",  INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst },
+  {"ori",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst },
+  {"andi",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst },
+  {"xori",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst },
+  {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst },
+  {"imm",   INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst },
+  {"rtsd",  INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst },
+  {"rtid",  INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst },
+  {"rtbd",  INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst },
+  {"rted",  INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst },
+  {"bri",   INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst },
+  {"brid",  INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst },
+  {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst },
+  {"brai",  INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst },
+  {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst },
+  {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst },
+  {"brki",  INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst },
+  {"beqi",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst },
+  {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst },
+  {"bnei",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst },
+  {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst },
+  {"blti",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst },
+  {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst },
+  {"blei",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst },
+  {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst },
+  {"bgti",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst },
+  {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst },
+  {"bgei",  INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst },
+  {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst },
+  {"lbu",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst },
+  {"lhu",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst },
+  {"lw",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst },
+  {"lwx",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000400, OPCODE_MASK_H4, lwx, memory_load_inst },
+  {"sb",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst },
+  {"sh",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst },
+  {"sw",    INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst },
+  {"swx",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000400, OPCODE_MASK_H4, swx, memory_store_inst },
+  {"lbui",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst },
+  {"lhui",  INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst },
+  {"lwi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst },
+  {"sbi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst },
+  {"shi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst },
+  {"swi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst },
+  {"nop",   INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */
+  {"la",    INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */
+  {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */
+  {"not",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */
+  {"neg",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */
+  {"rtb",   INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */
+  {"sub",   INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */
+  {"lmi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst },
+  {"smi",   INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst },
+  {"msrset",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst },
+  {"msrclr",INST_TYPE_RD_IMM15, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst },
+  {"fadd",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst },
+  {"frsub",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst },
+  {"fmul",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst },
+  {"fdiv",  INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst },
+  {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst },
+  {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst },
+  {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst },
+  {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst },
+  {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst },
+  {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst },
+  {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst },
+  {"flt",   INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000280, OPCODE_MASK_H4, flt,   arithmetic_inst },
+  {"fint",  INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000300, OPCODE_MASK_H4, fint,  arithmetic_inst },
+  {"fsqrt", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000380, OPCODE_MASK_H4, fsqrt, arithmetic_inst },
+  {"tget",   INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001000, OPCODE_MASK_H32, tget,   anyware_inst },
+  {"tcget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003000, OPCODE_MASK_H32, tcget,  anyware_inst },
+  {"tnget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005000, OPCODE_MASK_H32, tnget,  anyware_inst },
+  {"tncget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007000, OPCODE_MASK_H32, tncget, anyware_inst },
+  {"tput",   INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009000, OPCODE_MASK_H32, tput,   anyware_inst },
+  {"tcput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B000, OPCODE_MASK_H32, tcput,  anyware_inst },
+  {"tnput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D000, OPCODE_MASK_H32, tnput,  anyware_inst },
+  {"tncput", INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F000, OPCODE_MASK_H32, tncput, anyware_inst },
+ 
+  {"eget",   INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000400, OPCODE_MASK_H32, eget,   anyware_inst },
+  {"ecget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002400, OPCODE_MASK_H32, ecget,  anyware_inst },
+  {"neget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004400, OPCODE_MASK_H32, neget,  anyware_inst },
+  {"necget", INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006400, OPCODE_MASK_H32, necget, anyware_inst },
+  {"eput",   INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008400, OPCODE_MASK_H32, eput,   anyware_inst },
+  {"ecput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A400, OPCODE_MASK_H32, ecput,  anyware_inst },
+  {"neput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C400, OPCODE_MASK_H32, neput,  anyware_inst },
+  {"necput", INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E400, OPCODE_MASK_H32, necput, anyware_inst },
+ 
+  {"teget",   INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001400, OPCODE_MASK_H32, teget,   anyware_inst },
+  {"tecget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003400, OPCODE_MASK_H32, tecget,  anyware_inst },
+  {"tneget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005400, OPCODE_MASK_H32, tneget,  anyware_inst },
+  {"tnecget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007400, OPCODE_MASK_H32, tnecget, anyware_inst },
+  {"teput",   INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009400, OPCODE_MASK_H32, teput,   anyware_inst },
+  {"tecput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B400, OPCODE_MASK_H32, tecput,  anyware_inst },
+  {"tneput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D400, OPCODE_MASK_H32, tneput,  anyware_inst },
+  {"tnecput", INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F400, OPCODE_MASK_H32, tnecput, anyware_inst },
+ 
+  {"aget",   INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000800, OPCODE_MASK_H32, aget,   anyware_inst },
+  {"caget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002800, OPCODE_MASK_H32, caget,  anyware_inst },
+  {"naget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004800, OPCODE_MASK_H32, naget,  anyware_inst },
+  {"ncaget", INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006800, OPCODE_MASK_H32, ncaget, anyware_inst },
+  {"aput",   INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008800, OPCODE_MASK_H32, aput,   anyware_inst },
+  {"caput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A800, OPCODE_MASK_H32, caput,  anyware_inst },
+  {"naput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C800, OPCODE_MASK_H32, naput,  anyware_inst },
+  {"ncaput", INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E800, OPCODE_MASK_H32, ncaput, anyware_inst },
+ 
+  {"taget",   INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001800, OPCODE_MASK_H32, taget,   anyware_inst },
+  {"tcaget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003800, OPCODE_MASK_H32, tcaget,  anyware_inst },
+  {"tnaget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005800, OPCODE_MASK_H32, tnaget,  anyware_inst },
+  {"tncaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007800, OPCODE_MASK_H32, tncaget, anyware_inst },
+  {"taput",   INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009800, OPCODE_MASK_H32, taput,   anyware_inst },
+  {"tcaput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00B800, OPCODE_MASK_H32, tcaput,  anyware_inst },
+  {"tnaput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00D800, OPCODE_MASK_H32, tnaput,  anyware_inst },
+  {"tncaput", INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00F800, OPCODE_MASK_H32, tncaput, anyware_inst },
+ 
+  {"eaget",   INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000C00, OPCODE_MASK_H32, eget,   anyware_inst },
+  {"ecaget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002C00, OPCODE_MASK_H32, ecget,  anyware_inst },
+  {"neaget",  INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004C00, OPCODE_MASK_H32, neget,  anyware_inst },
+  {"necaget", INST_TYPE_RD_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006C00, OPCODE_MASK_H32, necget, anyware_inst },
+  {"eaput",   INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008C00, OPCODE_MASK_H32, eput,   anyware_inst },
+  {"ecaput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00AC00, OPCODE_MASK_H32, ecput,  anyware_inst },
+  {"neaput",  INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00CC00, OPCODE_MASK_H32, neput,  anyware_inst },
+  {"necaput", INST_TYPE_R1_RFSL,  INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00EC00, OPCODE_MASK_H32, necput, anyware_inst },
+ 
+  {"teaget",   INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C001C00, OPCODE_MASK_H32, teaget,   anyware_inst },
+  {"tecaget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C003C00, OPCODE_MASK_H32, tecaget,  anyware_inst },
+  {"tneaget",  INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C005C00, OPCODE_MASK_H32, tneaget,  anyware_inst },
+  {"tnecaget", INST_TYPE_RD_RFSL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C007C00, OPCODE_MASK_H32, tnecaget, anyware_inst },
+  {"teaput",   INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C009C00, OPCODE_MASK_H32, teaput,   anyware_inst },
+  {"tecaput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00BC00, OPCODE_MASK_H32, tecaput,  anyware_inst },
+  {"tneaput",  INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00DC00, OPCODE_MASK_H32, tneaput,  anyware_inst },
+  {"tnecaput", INST_TYPE_RFSL,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00FC00, OPCODE_MASK_H32, tnecaput, anyware_inst },
+ 
+  {"getd",    INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000000, OPCODE_MASK_H34C, getd,    anyware_inst },
+  {"tgetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000080, OPCODE_MASK_H34C, tgetd,   anyware_inst },
+  {"cgetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000100, OPCODE_MASK_H34C, cgetd,   anyware_inst },
+  {"tcgetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000180, OPCODE_MASK_H34C, tcgetd,  anyware_inst },
+  {"ngetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000200, OPCODE_MASK_H34C, ngetd,   anyware_inst },
+  {"tngetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000280, OPCODE_MASK_H34C, tngetd,  anyware_inst },
+  {"ncgetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000300, OPCODE_MASK_H34C, ncgetd,  anyware_inst },
+  {"tncgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000380, OPCODE_MASK_H34C, tncgetd, anyware_inst },
+  {"putd",    INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000400, OPCODE_MASK_H34C, putd,    anyware_inst },
+  {"tputd",   INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000480, OPCODE_MASK_H34C, tputd,   anyware_inst },
+  {"cputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000500, OPCODE_MASK_H34C, cputd,   anyware_inst },
+  {"tcputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000580, OPCODE_MASK_H34C, tcputd,  anyware_inst },
+  {"nputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000600, OPCODE_MASK_H34C, nputd,   anyware_inst },
+  {"tnputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000680, OPCODE_MASK_H34C, tnputd,  anyware_inst },
+  {"ncputd",  INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000700, OPCODE_MASK_H34C, ncputd,  anyware_inst },
+  {"tncputd", INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000780, OPCODE_MASK_H34C, tncputd, anyware_inst },
+ 
+  {"egetd",    INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000020, OPCODE_MASK_H34C, egetd,    anyware_inst },
+  {"tegetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000A0, OPCODE_MASK_H34C, tegetd,   anyware_inst },
+  {"ecgetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000120, OPCODE_MASK_H34C, ecgetd,   anyware_inst },
+  {"tecgetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001A0, OPCODE_MASK_H34C, tecgetd,  anyware_inst },
+  {"negetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000220, OPCODE_MASK_H34C, negetd,   anyware_inst },
+  {"tnegetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002A0, OPCODE_MASK_H34C, tnegetd,  anyware_inst },
+  {"necgetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000320, OPCODE_MASK_H34C, necgetd,  anyware_inst },
+  {"tnecgetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003A0, OPCODE_MASK_H34C, tnecgetd, anyware_inst },
+  {"eputd",    INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000420, OPCODE_MASK_H34C, eputd,    anyware_inst },
+  {"teputd",   INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004A0, OPCODE_MASK_H34C, teputd,   anyware_inst },
+  {"ecputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000520, OPCODE_MASK_H34C, ecputd,   anyware_inst },
+  {"tecputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005A0, OPCODE_MASK_H34C, tecputd,  anyware_inst },
+  {"neputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000620, OPCODE_MASK_H34C, neputd,   anyware_inst },
+  {"tneputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006A0, OPCODE_MASK_H34C, tneputd,  anyware_inst },
+  {"necputd",  INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000720, OPCODE_MASK_H34C, necputd,  anyware_inst },
+  {"tnecputd", INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007A0, OPCODE_MASK_H34C, tnecputd, anyware_inst },
+ 
+  {"agetd",    INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000040, OPCODE_MASK_H34C, agetd,    anyware_inst },
+  {"tagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000C0, OPCODE_MASK_H34C, tagetd,   anyware_inst },
+  {"cagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000140, OPCODE_MASK_H34C, cagetd,   anyware_inst },
+  {"tcagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001C0, OPCODE_MASK_H34C, tcagetd,  anyware_inst },
+  {"nagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000240, OPCODE_MASK_H34C, nagetd,   anyware_inst },
+  {"tnagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002C0, OPCODE_MASK_H34C, tnagetd,  anyware_inst },
+  {"ncagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000340, OPCODE_MASK_H34C, ncagetd,  anyware_inst },
+  {"tncagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003C0, OPCODE_MASK_H34C, tncagetd, anyware_inst },
+  {"aputd",    INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000440, OPCODE_MASK_H34C, aputd,    anyware_inst },
+  {"taputd",   INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004C0, OPCODE_MASK_H34C, taputd,   anyware_inst },
+  {"caputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000540, OPCODE_MASK_H34C, caputd,   anyware_inst },
+  {"tcaputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005C0, OPCODE_MASK_H34C, tcaputd,  anyware_inst },
+  {"naputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000640, OPCODE_MASK_H34C, naputd,   anyware_inst },
+  {"tnaputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006C0, OPCODE_MASK_H34C, tnaputd,  anyware_inst },
+  {"ncaputd",  INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000740, OPCODE_MASK_H34C, ncaputd,  anyware_inst },
+  {"tncaputd", INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007C0, OPCODE_MASK_H34C, tncaputd, anyware_inst },
+ 
+  {"eagetd",    INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000060, OPCODE_MASK_H34C, eagetd,    anyware_inst },
+  {"teagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0000E0, OPCODE_MASK_H34C, teagetd,   anyware_inst },
+  {"ecagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000160, OPCODE_MASK_H34C, ecagetd,   anyware_inst },
+  {"tecagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0001E0, OPCODE_MASK_H34C, tecagetd,  anyware_inst },
+  {"neagetd",   INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000260, OPCODE_MASK_H34C, neagetd,   anyware_inst },
+  {"tneagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0002E0, OPCODE_MASK_H34C, tneagetd,  anyware_inst },
+  {"necagetd",  INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000360, OPCODE_MASK_H34C, necagetd,  anyware_inst },
+  {"tnecagetd", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0003E0, OPCODE_MASK_H34C, tnecagetd, anyware_inst },
+  {"eaputd",    INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000460, OPCODE_MASK_H34C, eaputd,    anyware_inst },
+  {"teaputd",   INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0004E0, OPCODE_MASK_H34C, teaputd,   anyware_inst },
+  {"ecaputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000560, OPCODE_MASK_H34C, ecaputd,   anyware_inst },
+  {"tecaputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0005E0, OPCODE_MASK_H34C, tecaputd,  anyware_inst },
+  {"neaputd",   INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000660, OPCODE_MASK_H34C, neaputd,   anyware_inst },
+  {"tneaputd",  INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0006E0, OPCODE_MASK_H34C, tneaputd,  anyware_inst },
+  {"necaputd",  INST_TYPE_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C000760, OPCODE_MASK_H34C, necaputd,  anyware_inst },
+  {"tnecaputd", INST_TYPE_R2,    INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x4C0007E0, OPCODE_MASK_H34C, tnecaputd, anyware_inst },
+  {"", 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+/* prefix for register names */
+char register_prefix[] = "r";
+char special_register_prefix[] = "spr";
+char fsl_register_prefix[] = "rfsl";
+char pvr_register_prefix[] = "rpvr";
+
+
+/* #defines for valid immediate range */
+#define MIN_IMM  ((int) 0x80000000)
+#define MAX_IMM  ((int) 0x7fffffff)
+
+#define MIN_IMM15 ((int) 0x0000)
+#define MAX_IMM15 ((int) 0x7fff)
+
+#endif /* MICROBLAZE_OPC */
+
+#include "dis-asm.h"
+#include <strings.h>
+
+#define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW)
+#define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW)
+#define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW)
+#define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
+#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
+
+/* Local function prototypes. */
+
+static char * get_field (long instr, long mask, unsigned short low);
+static char * get_field_imm (long instr);
+static char * get_field_imm5 (long instr);
+static char * get_field_rfsl (long instr);
+static char * get_field_imm15 (long instr);
+#if 0
+static char * get_field_unsigned_imm (long instr);
+#endif
+char * get_field_special (long instr, struct op_code_struct * op);
+unsigned long read_insn_microblaze (bfd_vma memaddr, 
+		      struct disassemble_info *info,
+		      struct op_code_struct **opr);
+enum microblaze_instr get_insn_microblaze (long inst,
+  		     bfd_boolean *isunsignedimm,
+  		     enum microblaze_instr_type *insn_type,
+  		     short *delay_slots);
+short get_delay_slots_microblaze (long inst);
+enum microblaze_instr microblaze_decode_insn (long insn,
+		        int *rd, 
+			int *ra, 
+			int *rb, 
+			int *imm);
+unsigned long
+microblaze_get_target_address (long inst,
+			       bfd_boolean immfound,
+			       int immval,
+			       long pcval,
+			       long r1val,
+			       long r2val,
+			       bfd_boolean *targetvalid,
+			       bfd_boolean *unconditionalbranch);
+
+static char *
+get_field (long instr, long mask, unsigned short low)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
+  return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm (long instr)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
+  return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm5 (long instr)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
+  return(strdup(tmpstr));
+}
+
+static char *
+get_field_rfsl (long instr)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & RFSL_MASK) >> IMM_LOW));
+  return(strdup(tmpstr));
+}
+
+static char *
+get_field_imm15 (long instr)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
+  return(strdup(tmpstr));
+}
+
+#if 0
+static char *
+get_field_unsigned_imm (long instr)
+{
+  char tmpstr[25];
+  sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW));
+  return(strdup(tmpstr));
+}
+#endif
+
+/*
+  char *
+  get_field_special (instr) 
+  long instr;
+  {
+  char tmpstr[25];
+  
+  sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr");
+  
+  return(strdup(tmpstr));
+  }
+*/
+
+char *
+get_field_special (long instr, struct op_code_struct * op)
+{
+   char tmpstr[25];
+   char spr[6];
+
+   switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) {
+
+   case REG_MSR_MASK :
+      strcpy(spr, "msr");
+      break;
+   case REG_PC_MASK :
+      strcpy(spr, "pc");
+      break;
+   case REG_EAR_MASK :
+      strcpy(spr, "ear");
+      break;
+   case REG_ESR_MASK :
+      strcpy(spr, "esr");
+      break;
+   case REG_FSR_MASK :
+      strcpy(spr, "fsr");
+      break;
+   case REG_BTR_MASK :
+      strcpy(spr, "btr");
+      break;      
+   case REG_EDR_MASK :
+      strcpy(spr, "edr");
+      break;
+   case REG_PID_MASK :
+      strcpy(spr, "pid");
+      break;
+   case REG_ZPR_MASK :
+      strcpy(spr, "zpr");
+      break;
+   case REG_TLBX_MASK :
+      strcpy(spr, "tlbx");
+      break;
+   case REG_TLBLO_MASK :
+      strcpy(spr, "tlblo");
+      break;
+   case REG_TLBHI_MASK :
+      strcpy(spr, "tlbhi");
+      break;
+   case REG_TLBSX_MASK :
+      strcpy(spr, "tlbsx");
+      break;
+   default :
+     {
+       if ( ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000) == REG_PVR_MASK) {
+	 sprintf(tmpstr, "%spvr%d", register_prefix, (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ^ REG_PVR_MASK);
+	 return(strdup(tmpstr));
+       } else {
+	 strcpy(spr, "pc");
+       }
+     }
+     break;
+   }
+   
+   sprintf(tmpstr, "%s%s", register_prefix, spr);
+   return(strdup(tmpstr));
+}
+
+unsigned long
+read_insn_microblaze (bfd_vma memaddr, 
+		      struct disassemble_info *info,
+		      struct op_code_struct **opr)
+{
+  unsigned char       ibytes[4];
+  int                 status;
+  struct op_code_struct * op;
+  unsigned long inst;
+
+  status = info->read_memory_func (memaddr, ibytes, 4, info);
+
+  if (status != 0) 
+    {
+      info->memory_error_func (status, memaddr, info);
+      return 0;
+    }
+
+  if (info->endian == BFD_ENDIAN_BIG)
+    inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
+  else if (info->endian == BFD_ENDIAN_LITTLE)
+    inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
+  else
+    abort ();
+
+  /* Just a linear search of the table.  */
+  for (op = opcodes; op->name != 0; op ++)
+    if (op->bit_sequence == (inst & op->opcode_mask))
+      break;
+
+  *opr = op;
+  return inst;
+}
+
+
+int 
+print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
+{
+  fprintf_function    fprintf_func = info->fprintf_func;
+  void *              stream = info->stream;
+  unsigned long       inst, prev_inst;
+  struct op_code_struct * op, *pop;
+  int                 immval = 0;
+  bfd_boolean         immfound = FALSE;
+  static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */
+  static int     prev_insn_vma = -1;  /*init the prev insn vma */
+  int            curr_insn_vma = info->buffer_vma;
+
+  info->bytes_per_chunk = 4;
+
+  inst = read_insn_microblaze (memaddr, info, &op);
+  if (inst == 0) {
+    return -1;
+  }
+  
+  if (prev_insn_vma == curr_insn_vma) {
+  if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) {
+    prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
+    if (prev_inst == 0)
+      return -1;
+    if (pop->instr == imm) {
+      immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000;
+      immfound = TRUE;
+    }
+    else {
+      immval = 0;
+      immfound = FALSE;
+    }
+  }
+  }
+  /* make curr insn as prev insn */
+  prev_insn_addr = memaddr;
+  prev_insn_vma = curr_insn_vma;
+
+  if (op->name == 0) {
+    fprintf_func (stream, ".short 0x%04lx", inst);
+  }
+  else
+    {
+      fprintf_func (stream, "%s", op->name);
+      
+      switch (op->inst_type)
+	{
+  case INST_TYPE_RD_R1_R2:
+     fprintf_func(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst));
+     break;
+        case INST_TYPE_RD_R1_IMM:
+	  fprintf_func(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst));
+	  if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) {
+	    if (immfound)
+	      immval |= (get_int_field_imm(inst) & 0x0000ffff);
+	    else {
+	      immval = get_int_field_imm(inst);
+	      if (immval & 0x8000)
+		immval |= 0xFFFF0000;
+	    }
+	    if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+	      fprintf_func (stream, "\t// ");
+	      info->print_address_func (immval, info);
+	    }
+	  }
+	  break;
+	case INST_TYPE_RD_R1_IMM5:
+	  fprintf_func(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst));
+	  break;
+	case INST_TYPE_RD_RFSL:
+	  fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_rfsl(inst));
+	  break;
+	case INST_TYPE_R1_RFSL:
+	  fprintf_func(stream, "\t%s, %s", get_field_r1(inst), get_field_rfsl(inst));
+	  break;
+	case INST_TYPE_RD_SPECIAL:
+	  fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op));
+	  break;
+	case INST_TYPE_SPECIAL_R1:
+	  fprintf_func(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst));
+	  break;
+	case INST_TYPE_RD_R1:
+	  fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst));
+	  break;
+	case INST_TYPE_R1_R2:
+	  fprintf_func(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst));
+	  break;
+	case INST_TYPE_R1_IMM:
+	  fprintf_func(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst));
+	  /* The non-pc relative instructions are returns, which shouldn't 
+	     have a label printed */
+	  if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) {
+	    if (immfound)
+	      immval |= (get_int_field_imm(inst) & 0x0000ffff);
+	    else {
+	      immval = get_int_field_imm(inst);
+	      if (immval & 0x8000)
+		immval |= 0xFFFF0000;
+	    }
+	    immval += memaddr;
+	    if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+	      fprintf_func (stream, "\t// ");
+	      info->print_address_func (immval, info);
+	    } else {
+	      fprintf_func (stream, "\t\t// ");
+	      fprintf_func (stream, "%x", immval);
+	    }
+	  }
+	  break;
+        case INST_TYPE_RD_IMM:
+	  fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst));
+	  if (info->print_address_func && info->symbol_at_address_func) {
+	    if (immfound)
+	      immval |= (get_int_field_imm(inst) & 0x0000ffff);
+	    else {
+	      immval = get_int_field_imm(inst);
+	      if (immval & 0x8000)
+		immval |= 0xFFFF0000;
+	    }
+	    if (op->inst_offset_type == INST_PC_OFFSET)
+	      immval += (int) memaddr;
+	    if (info->symbol_at_address_func(immval, info)) {
+	      fprintf_func (stream, "\t// ");
+	      info->print_address_func (immval, info);
+	    } 
+	  }
+	  break;
+        case INST_TYPE_IMM:
+	  fprintf_func(stream, "\t%s", get_field_imm(inst));
+	  if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) {
+	    if (immfound)
+	      immval |= (get_int_field_imm(inst) & 0x0000ffff);
+	    else {
+	      immval = get_int_field_imm(inst);
+	      if (immval & 0x8000)
+		immval |= 0xFFFF0000;
+	    }
+	    if (op->inst_offset_type == INST_PC_OFFSET)
+	      immval += (int) memaddr;
+	    if (immval > 0 && info->symbol_at_address_func(immval, info)) {
+	      fprintf_func (stream, "\t// ");
+	      info->print_address_func (immval, info);
+	    } else if (op->inst_offset_type == INST_PC_OFFSET) {
+	      fprintf_func (stream, "\t\t// ");
+	      fprintf_func (stream, "%x", immval);
+	    }
+	  }
+	  break;
+        case INST_TYPE_RD_R2:
+	  fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
+	  break;
+  case INST_TYPE_R2:
+     fprintf_func(stream, "\t%s", get_field_r2(inst));
+     break;
+  case INST_TYPE_R1:
+     fprintf_func(stream, "\t%s", get_field_r1(inst));
+     break;
+  case INST_TYPE_RD_R1_SPECIAL:
+     fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst));
+     break;
+  case INST_TYPE_RD_IMM15:
+     fprintf_func(stream, "\t%s, %s", get_field_rd(inst), get_field_imm15(inst));
+     break;
+     /* For tuqula instruction */
+  case INST_TYPE_RD:
+     fprintf_func(stream, "\t%s", get_field_rd(inst));
+     break;
+  case INST_TYPE_RFSL:
+     fprintf_func(stream, "\t%s", get_field_rfsl(inst));
+     break;
+  default:
+	  /* if the disassembler lags the instruction set */
+	  fprintf_func (stream, "\tundecoded operands, inst is 0x%04lx", inst);
+	  break;
+	}
+    }
+  
+  /* Say how many bytes we consumed? */
+  return 4;
+}
+
+enum microblaze_instr
+get_insn_microblaze (long inst,
+  		     bfd_boolean *isunsignedimm,
+  		     enum microblaze_instr_type *insn_type,
+  		     short *delay_slots)
+{
+  struct op_code_struct * op;
+  *isunsignedimm = FALSE;
+
+  /* Just a linear search of the table.  */
+  for (op = opcodes; op->name != 0; op ++)
+    if (op->bit_sequence == (inst & op->opcode_mask))
+      break;
+
+  if (op->name == 0)
+    return invalid_inst;
+  else {
+    *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
+    *insn_type = op->instr_type;
+    *delay_slots = op->delay_slots;
+    return op->instr;
+  }
+}
+
+short
+get_delay_slots_microblaze (long inst)
+{
+  bfd_boolean isunsignedimm;
+  enum microblaze_instr_type insn_type;
+  enum microblaze_instr op;
+  short delay_slots;
+
+  op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots);
+  if (op == invalid_inst)
+    return 0;
+  else 
+    return delay_slots;
+}
+
+enum microblaze_instr
+microblaze_decode_insn (long insn,
+		        int *rd, 
+			int *ra, 
+			int *rb, 
+			int *imm)
+{
+  enum microblaze_instr op;
+  bfd_boolean t1;
+  enum microblaze_instr_type t2;
+  short t3;
+
+  op = get_insn_microblaze(insn, &t1, &t2, &t3);
+  *rd = (insn & RD_MASK) >> RD_LOW;
+  *ra = (insn & RA_MASK) >> RA_LOW;
+  *rb = (insn & RB_MASK) >> RB_LOW;
+  t3 = (insn & IMM_MASK) >> IMM_LOW;
+  *imm = (int) t3;
+  return (op);
+}
+
+unsigned long
+microblaze_get_target_address (long inst,
+			       bfd_boolean immfound,
+			       int immval,
+			       long pcval,
+			       long r1val,
+			       long r2val,
+			       bfd_boolean *targetvalid,
+			       bfd_boolean *unconditionalbranch)
+{
+  struct op_code_struct * op;
+  long targetaddr = 0;
+
+  *unconditionalbranch = FALSE;
+  /* Just a linear search of the table.  */
+  for (op = opcodes; op->name != 0; op ++)
+    if (op->bit_sequence == (inst & op->opcode_mask))
+      break;
+
+  if (op->name == 0) {
+    *targetvalid = FALSE;
+  } else if (op->instr_type == branch_inst) {
+    switch (op->inst_type) {
+    case INST_TYPE_R2:
+      *unconditionalbranch = TRUE;
+      /* fallthru */
+    case INST_TYPE_RD_R2:
+    case INST_TYPE_R1_R2:
+      targetaddr = r2val;
+      *targetvalid = TRUE;
+      if (op->inst_offset_type == INST_PC_OFFSET)
+	targetaddr += pcval;
+      break;
+    case INST_TYPE_IMM:
+      *unconditionalbranch = TRUE;
+      /* fallthru */
+    case INST_TYPE_RD_IMM:
+    case INST_TYPE_R1_IMM:
+      if (immfound) {
+	targetaddr = (immval << 16) & 0xffff0000;
+	targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
+      } else {
+	targetaddr = get_int_field_imm(inst);
+	if (targetaddr & 0x8000)
+	  targetaddr |= 0xFFFF0000;
+      }
+      if (op->inst_offset_type == INST_PC_OFFSET)
+	targetaddr += pcval;
+      *targetvalid = TRUE;
+      break;
+    default:
+      *targetvalid = FALSE;
+      break;
+    }
+  } else if (op->instr_type == return_inst) {
+      if (immfound) {
+	targetaddr = (immval << 16) & 0xffff0000;
+	targetaddr |= (get_int_field_imm(inst) & 0x0000ffff);
+      } else {
+	targetaddr = get_int_field_imm(inst);
+	if (targetaddr & 0x8000)
+	  targetaddr |= 0xFFFF0000;
+      }
+      targetaddr += r1val;
+      *targetvalid = TRUE;
+  } else {
+    *targetvalid = FALSE;
+  }
+  return targetaddr;
+}
diff --git a/qemu-0.15.x/migration-exec.c b/qemu-0.15.x/migration-exec.c
new file mode 100644
index 0000000..4b7aad8
--- /dev/null
+++ b/qemu-0.15.x/migration-exec.c
@@ -0,0 +1,144 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Dell MessageOne 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Charles Duffy     <charles_duffy at messageone.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+#include "block.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
+//#define DEBUG_MIGRATION_EXEC
+
+#ifdef DEBUG_MIGRATION_EXEC
+#define DPRINTF(fmt, ...) \
+    do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int file_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int file_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int exec_close(FdMigrationState *s)
+{
+    int ret = 0;
+    DPRINTF("exec_close\n");
+    if (s->opaque) {
+        ret = qemu_fclose(s->opaque);
+        s->opaque = NULL;
+        s->fd = -1;
+        if (ret != -1 &&
+            WIFEXITED(ret)
+            && WEXITSTATUS(ret) == 0) {
+            ret = 0;
+        } else {
+            ret = -1;
+        }
+    }
+    return ret;
+}
+
+MigrationState *exec_start_outgoing_migration(Monitor *mon,
+                                              const char *command,
+					      int64_t bandwidth_limit,
+					      int detach,
+					      int blk,
+					      int inc)
+{
+    FdMigrationState *s;
+    FILE *f;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    f = popen(command, "w");
+    if (f == NULL) {
+        DPRINTF("Unable to popen exec target\n");
+        goto err_after_alloc;
+    }
+
+    s->fd = fileno(f);
+    if (s->fd == -1) {
+        DPRINTF("Unable to retrieve file descriptor for popen'd handle\n");
+        goto err_after_open;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    s->opaque = qemu_popen(f, "w");
+
+    s->close = exec_close;
+    s->get_error = file_errno;
+    s->write = file_write;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->mig_state.blk = blk;
+    s->mig_state.shared = inc;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    migrate_fd_connect(s);
+    return &s->mig_state;
+
+err_after_open:
+    pclose(f);
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void exec_accept_incoming_migration(void *opaque)
+{
+    QEMUFile *f = opaque;
+
+    process_incoming_migration(f);
+    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    qemu_fclose(f);
+}
+
+int exec_start_incoming_migration(const char *command)
+{
+    QEMUFile *f;
+
+    DPRINTF("Attempting to start an incoming migration\n");
+    f = qemu_popen_cmd(command, "r");
+    if(f == NULL) {
+        DPRINTF("Unable to apply qemu wrapper to popen file\n");
+        return -errno;
+    }
+
+    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL,
+			 exec_accept_incoming_migration, NULL, f);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/migration-fd.c b/qemu-0.15.x/migration-fd.c
new file mode 100644
index 0000000..66d51c1
--- /dev/null
+++ b/qemu-0.15.x/migration-fd.c
@@ -0,0 +1,129 @@
+/*
+ * QEMU live migration via generic fd
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "monitor.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION_FD
+
+#ifdef DEBUG_MIGRATION_FD
+#define DPRINTF(fmt, ...) \
+    do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int fd_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int fd_close(FdMigrationState *s)
+{
+    DPRINTF("fd_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach,
+					    int blk,
+					    int inc)
+{
+    FdMigrationState *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->fd = monitor_get_fd(mon, fdname);
+    if (s->fd == -1) {
+        DPRINTF("fd_migration: invalid file descriptor identifier\n");
+        goto err_after_alloc;
+    }
+
+    if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
+        DPRINTF("Unable to set nonblocking mode on file descriptor\n");
+        goto err_after_open;
+    }
+
+    s->get_error = fd_errno;
+    s->write = fd_write;
+    s->close = fd_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->mig_state.blk = blk;
+    s->mig_state.shared = inc;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    migrate_fd_connect(s);
+    return &s->mig_state;
+
+err_after_open:
+    close(s->fd);
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void fd_accept_incoming_migration(void *opaque)
+{
+    QEMUFile *f = opaque;
+
+    process_incoming_migration(f);
+    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    qemu_fclose(f);
+}
+
+int fd_start_incoming_migration(const char *infd)
+{
+    int fd;
+    QEMUFile *f;
+
+    DPRINTF("Attempting to start an incoming migration via fd\n");
+
+    fd = strtol(infd, NULL, 0);
+    f = qemu_fdopen(fd, "rb");
+    if(f == NULL) {
+        DPRINTF("Unable to apply qemu wrapper to file descriptor\n");
+        return -errno;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/migration-tcp.c b/qemu-0.15.x/migration-tcp.c
new file mode 100644
index 0000000..d3d80c9
--- /dev/null
+++ b/qemu-0.15.x/migration-tcp.c
@@ -0,0 +1,203 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_TCP
+
+#ifdef DEBUG_MIGRATION_TCP
+#define DPRINTF(fmt, ...) \
+    do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int socket_errno(FdMigrationState *s)
+{
+    return socket_error();
+}
+
+static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return send(s->fd, buf, size, 0);
+}
+
+static int tcp_close(FdMigrationState *s)
+{
+    DPRINTF("tcp_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+
+static void tcp_wait_for_connect(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int val, ret;
+    socklen_t valsize = sizeof(val);
+
+    DPRINTF("connect completed\n");
+    do {
+        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret < 0) {
+        migrate_fd_error(s);
+        return;
+    }
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (val == 0)
+        migrate_fd_connect(s);
+    else {
+        DPRINTF("error connecting %d\n", val);
+        migrate_fd_error(s);
+    }
+}
+
+MigrationState *tcp_start_outgoing_migration(Monitor *mon,
+                                             const char *host_port,
+                                             int64_t bandwidth_limit,
+                                             int detach,
+					     int blk,
+					     int inc)
+{
+    struct sockaddr_in addr;
+    FdMigrationState *s;
+    int ret;
+
+    if (parse_host_port(&addr, host_port) < 0)
+        return NULL;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->get_error = socket_errno;
+    s->write = socket_write;
+    s->close = tcp_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->mig_state.blk = blk;
+    s->mig_state.shared = inc;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
+    if (s->fd == -1) {
+        qemu_free(s);
+        return NULL;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    do {
+        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
+        if (ret == -1)
+            ret = -(s->get_error(s));
+
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+    } while (ret == -EINTR);
+
+    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+        DPRINTF("connect failed\n");
+        migrate_fd_error(s);
+    } else if (ret >= 0)
+        migrate_fd_connect(s);
+
+    return &s->mig_state;
+}
+
+static void tcp_accept_incoming_migration(void *opaque)
+{
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
+    int s = (intptr_t)opaque;
+    QEMUFile *f;
+    int c;
+
+    do {
+        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
+    } while (c == -1 && socket_error() == EINTR);
+
+    DPRINTF("accepted migration\n");
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        goto out2;
+    }
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    process_incoming_migration(f);
+    qemu_fclose(f);
+out:
+    close(c);
+out2:
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    close(s);
+}
+
+int tcp_start_incoming_migration(const char *host_port)
+{
+    struct sockaddr_in addr;
+    int val;
+    int s;
+
+    if (parse_host_port(&addr, host_port) < 0) {
+        fprintf(stderr, "invalid host/port combination: %s\n", host_port);
+        return -EINVAL;
+    }
+
+    s = qemu_socket(PF_INET, SOCK_STREAM, 0);
+    if (s == -1)
+        return -socket_error();
+
+    val = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+        goto err;
+
+    if (listen(s, 1) == -1)
+        goto err;
+
+    qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
+                         (void *)(intptr_t)s);
+
+    return 0;
+
+err:
+    close(s);
+    return -socket_error();
+}
diff --git a/qemu-0.15.x/migration-unix.c b/qemu-0.15.x/migration-unix.c
new file mode 100644
index 0000000..c8625c7
--- /dev/null
+++ b/qemu-0.15.x/migration-unix.c
@@ -0,0 +1,214 @@
+/*
+ * QEMU live migration via Unix Domain Sockets
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_UNIX
+
+#ifdef DEBUG_MIGRATION_UNIX
+#define DPRINTF(fmt, ...) \
+    do { printf("migration-unix: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int unix_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int unix_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int unix_close(FdMigrationState *s)
+{
+    DPRINTF("unix_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+static void unix_wait_for_connect(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int val, ret;
+    socklen_t valsize = sizeof(val);
+
+    DPRINTF("connect completed\n");
+    do {
+        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret < 0) {
+        migrate_fd_error(s);
+        return;
+    }
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (val == 0)
+        migrate_fd_connect(s);
+    else {
+        DPRINTF("error connecting %d\n", val);
+        migrate_fd_error(s);
+    }
+}
+
+MigrationState *unix_start_outgoing_migration(Monitor *mon,
+                                              const char *path,
+					      int64_t bandwidth_limit,
+					      int detach,
+					      int blk,
+					      int inc)
+{
+    FdMigrationState *s;
+    struct sockaddr_un addr;
+    int ret;
+
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->get_error = unix_errno;
+    s->write = unix_write;
+    s->close = unix_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->mig_state.blk = blk;
+    s->mig_state.shared = inc;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s->fd < 0) {
+        DPRINTF("Unable to open socket");
+        goto err_after_alloc;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    do {
+        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
+        if (ret == -1)
+	    ret = -(s->get_error(s));
+
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+	    qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+    } while (ret == -EINTR);
+
+    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+        DPRINTF("connect failed\n");
+        goto err_after_open;
+    }
+
+    if (!detach) {
+        migrate_fd_monitor_suspend(s, mon);
+    }
+
+    if (ret >= 0)
+        migrate_fd_connect(s);
+
+    return &s->mig_state;
+
+err_after_open:
+    close(s->fd);
+
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void unix_accept_incoming_migration(void *opaque)
+{
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+    int s = (intptr_t)opaque;
+    QEMUFile *f;
+    int c;
+
+    do {
+        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
+    } while (c == -1 && socket_error() == EINTR);
+
+    DPRINTF("accepted migration\n");
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        return;
+    }
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    process_incoming_migration(f);
+    qemu_fclose(f);
+out:
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    close(s);
+    close(c);
+}
+
+int unix_start_incoming_migration(const char *path)
+{
+    struct sockaddr_un un;
+    int sock;
+
+    DPRINTF("Attempting to start an incoming migration\n");
+
+    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
+        return -EINVAL;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+
+    unlink(un.sun_path);
+    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+    if (listen(sock, 1) < 0) {
+        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+
+    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
+			 (void *)(intptr_t)sock);
+
+    return 0;
+
+err:
+    close(sock);
+
+    return -EINVAL;
+}
diff --git a/qemu-0.15.x/migration.c b/qemu-0.15.x/migration.c
new file mode 100644
index 0000000..2a15b98
--- /dev/null
+++ b/qemu-0.15.x/migration.c
@@ -0,0 +1,482 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "migration.h"
+#include "monitor.h"
+#include "buffered_file.h"
+#include "sysemu.h"
+#include "block.h"
+#include "qemu_socket.h"
+#include "block-migration.h"
+#include "qemu-objects.h"
+
+//#define DEBUG_MIGRATION
+
+#ifdef DEBUG_MIGRATION
+#define DPRINTF(fmt, ...) \
+    do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* Migration speed throttling */
+static int64_t max_throttle = (32 << 20);
+
+static MigrationState *current_migration;
+
+static NotifierList migration_state_notifiers =
+    NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
+
+int qemu_start_incoming_migration(const char *uri)
+{
+    const char *p;
+    int ret;
+
+    if (strstart(uri, "tcp:", &p))
+        ret = tcp_start_incoming_migration(p);
+#if !defined(WIN32)
+    else if (strstart(uri, "exec:", &p))
+        ret =  exec_start_incoming_migration(p);
+    else if (strstart(uri, "unix:", &p))
+        ret = unix_start_incoming_migration(p);
+    else if (strstart(uri, "fd:", &p))
+        ret = fd_start_incoming_migration(p);
+#endif
+    else {
+        fprintf(stderr, "unknown migration protocol: %s\n", uri);
+        ret = -EPROTONOSUPPORT;
+    }
+    return ret;
+}
+
+void process_incoming_migration(QEMUFile *f)
+{
+    if (qemu_loadvm_state(f) < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        exit(0);
+    }
+    qemu_announce_self();
+    DPRINTF("successfully loaded vm state\n");
+
+    incoming_expected = false;
+
+    if (autostart)
+        vm_start();
+}
+
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    MigrationState *s = NULL;
+    const char *p;
+    int detach = qdict_get_try_bool(qdict, "detach", 0);
+    int blk = qdict_get_try_bool(qdict, "blk", 0);
+    int inc = qdict_get_try_bool(qdict, "inc", 0);
+    const char *uri = qdict_get_str(qdict, "uri");
+
+    if (current_migration &&
+        current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
+        monitor_printf(mon, "migration already in progress\n");
+        return -1;
+    }
+
+    if (qemu_savevm_state_blocked(mon)) {
+        return -1;
+    }
+
+    if (strstart(uri, "tcp:", &p)) {
+        s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
+                                         blk, inc);
+#if !defined(WIN32)
+    } else if (strstart(uri, "exec:", &p)) {
+        s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
+                                          blk, inc);
+    } else if (strstart(uri, "unix:", &p)) {
+        s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
+                                          blk, inc);
+    } else if (strstart(uri, "fd:", &p)) {
+        s = fd_start_outgoing_migration(mon, p, max_throttle, detach, 
+                                        blk, inc);
+#endif
+    } else {
+        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+        return -1;
+    }
+
+    if (s == NULL) {
+        monitor_printf(mon, "migration failed\n");
+        return -1;
+    }
+
+    if (current_migration) {
+        current_migration->release(current_migration);
+    }
+
+    current_migration = s;
+    notifier_list_notify(&migration_state_notifiers, NULL);
+    return 0;
+}
+
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    MigrationState *s = current_migration;
+
+    if (s)
+        s->cancel(s);
+
+    return 0;
+}
+
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int64_t d;
+    FdMigrationState *s;
+
+    d = qdict_get_int(qdict, "value");
+    if (d < 0) {
+        d = 0;
+    }
+    max_throttle = d;
+
+    s = migrate_to_fms(current_migration);
+    if (s && s->file) {
+        qemu_file_set_rate_limit(s->file, max_throttle);
+    }
+
+    return 0;
+}
+
+/* amount of nanoseconds we are willing to wait for migration to be down.
+ * the choice of nanoseconds is because it is the maximum resolution that
+ * get_clock() can achieve. It is an internal measure. All user-visible
+ * units must be in seconds */
+static uint64_t max_downtime = 30000000;
+
+uint64_t migrate_max_downtime(void)
+{
+    return max_downtime;
+}
+
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+                            QObject **ret_data)
+{
+    double d;
+
+    d = qdict_get_double(qdict, "value") * 1e9;
+    d = MAX(0, MIN(UINT64_MAX, d));
+    max_downtime = (uint64_t)d;
+
+    return 0;
+}
+
+static void migrate_print_status(Monitor *mon, const char *name,
+                                 const QDict *status_dict)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(qdict_get(status_dict, name));
+
+    monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
+                        qdict_get_int(qdict, "transferred") >> 10);
+    monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
+                        qdict_get_int(qdict, "remaining") >> 10);
+    monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
+                        qdict_get_int(qdict, "total") >> 10);
+}
+
+void do_info_migrate_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+
+    monitor_printf(mon, "Migration status: %s\n",
+                   qdict_get_str(qdict, "status"));
+
+    if (qdict_haskey(qdict, "ram")) {
+        migrate_print_status(mon, "ram", qdict);
+    }
+
+    if (qdict_haskey(qdict, "disk")) {
+        migrate_print_status(mon, "disk", qdict);
+    }
+}
+
+static void migrate_put_status(QDict *qdict, const char *name,
+                               uint64_t trans, uint64_t rem, uint64_t total)
+{
+    QObject *obj;
+
+    obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
+                               "'remaining': %" PRId64 ", "
+                               "'total': %" PRId64 " }", trans, rem, total);
+    qdict_put_obj(qdict, name, obj);
+}
+
+void do_info_migrate(Monitor *mon, QObject **ret_data)
+{
+    QDict *qdict;
+    MigrationState *s = current_migration;
+
+    if (s) {
+        switch (s->get_status(s)) {
+        case MIG_STATE_ACTIVE:
+            qdict = qdict_new();
+            qdict_put(qdict, "status", qstring_from_str("active"));
+
+            migrate_put_status(qdict, "ram", ram_bytes_transferred(),
+                               ram_bytes_remaining(), ram_bytes_total());
+
+            if (blk_mig_active()) {
+                migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
+                                   blk_mig_bytes_remaining(),
+                                   blk_mig_bytes_total());
+            }
+
+            *ret_data = QOBJECT(qdict);
+            break;
+        case MIG_STATE_COMPLETED:
+            *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
+            break;
+        case MIG_STATE_ERROR:
+            *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
+            break;
+        case MIG_STATE_CANCELLED:
+            *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
+            break;
+        }
+    }
+}
+
+/* shared migration helpers */
+
+void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
+{
+    s->mon = mon;
+    if (monitor_suspend(mon) == 0) {
+        DPRINTF("suspending monitor\n");
+    } else {
+        monitor_printf(mon, "terminal does not allow synchronous "
+                       "migration, continuing detached\n");
+    }
+}
+
+void migrate_fd_error(FdMigrationState *s)
+{
+    DPRINTF("setting error state\n");
+    s->state = MIG_STATE_ERROR;
+    notifier_list_notify(&migration_state_notifiers, NULL);
+    migrate_fd_cleanup(s);
+}
+
+int migrate_fd_cleanup(FdMigrationState *s)
+{
+    int ret = 0;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (s->file) {
+        DPRINTF("closing file\n");
+        if (qemu_fclose(s->file) != 0) {
+            ret = -1;
+        }
+        s->file = NULL;
+    }
+
+    if (s->fd != -1)
+        close(s->fd);
+
+    /* Don't resume monitor until we've flushed all of the buffers */
+    if (s->mon) {
+        monitor_resume(s->mon);
+    }
+
+    s->fd = -1;
+
+    return ret;
+}
+
+void migrate_fd_put_notify(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_file_put_notify(s->file);
+}
+
+ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
+{
+    FdMigrationState *s = opaque;
+    ssize_t ret;
+
+    do {
+        ret = s->write(s, data, size);
+    } while (ret == -1 && ((s->get_error(s)) == EINTR));
+
+    if (ret == -1)
+        ret = -(s->get_error(s));
+
+    if (ret == -EAGAIN) {
+        qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
+    } else if (ret < 0) {
+        if (s->mon) {
+            monitor_resume(s->mon);
+        }
+        s->state = MIG_STATE_ERROR;
+        notifier_list_notify(&migration_state_notifiers, NULL);
+    }
+
+    return ret;
+}
+
+void migrate_fd_connect(FdMigrationState *s)
+{
+    int ret;
+
+    s->file = qemu_fopen_ops_buffered(s,
+                                      s->bandwidth_limit,
+                                      migrate_fd_put_buffer,
+                                      migrate_fd_put_ready,
+                                      migrate_fd_wait_for_unfreeze,
+                                      migrate_fd_close);
+
+    DPRINTF("beginning savevm\n");
+    ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk,
+                                  s->mig_state.shared);
+    if (ret < 0) {
+        DPRINTF("failed, %d\n", ret);
+        migrate_fd_error(s);
+        return;
+    }
+    
+    migrate_fd_put_ready(s);
+}
+
+void migrate_fd_put_ready(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    if (s->state != MIG_STATE_ACTIVE) {
+        DPRINTF("put_ready returning because of non-active state\n");
+        return;
+    }
+
+    DPRINTF("iterate\n");
+    if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
+        int state;
+        int old_vm_running = vm_running;
+
+        DPRINTF("done iterating\n");
+        vm_stop(VMSTOP_MIGRATE);
+
+        if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
+            if (old_vm_running) {
+                vm_start();
+            }
+            state = MIG_STATE_ERROR;
+        } else {
+            state = MIG_STATE_COMPLETED;
+        }
+        if (migrate_fd_cleanup(s) < 0) {
+            if (old_vm_running) {
+                vm_start();
+            }
+            state = MIG_STATE_ERROR;
+        }
+        s->state = state;
+        notifier_list_notify(&migration_state_notifiers, NULL);
+    }
+}
+
+int migrate_fd_get_status(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+    return s->state;
+}
+
+void migrate_fd_cancel(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+
+    if (s->state != MIG_STATE_ACTIVE)
+        return;
+
+    DPRINTF("cancelling migration\n");
+
+    s->state = MIG_STATE_CANCELLED;
+    notifier_list_notify(&migration_state_notifiers, NULL);
+    qemu_savevm_state_cancel(s->mon, s->file);
+
+    migrate_fd_cleanup(s);
+}
+
+void migrate_fd_release(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+
+    DPRINTF("releasing state\n");
+   
+    if (s->state == MIG_STATE_ACTIVE) {
+        s->state = MIG_STATE_CANCELLED;
+        notifier_list_notify(&migration_state_notifiers, NULL);
+        migrate_fd_cleanup(s);
+    }
+    qemu_free(s);
+}
+
+void migrate_fd_wait_for_unfreeze(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int ret;
+
+    DPRINTF("wait for unfreeze\n");
+    if (s->state != MIG_STATE_ACTIVE)
+        return;
+
+    do {
+        fd_set wfds;
+
+        FD_ZERO(&wfds);
+        FD_SET(s->fd, &wfds);
+
+        ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+}
+
+int migrate_fd_close(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    return s->close(s);
+}
+
+void add_migration_state_change_notifier(Notifier *notify)
+{
+    notifier_list_add(&migration_state_notifiers, notify);
+}
+
+void remove_migration_state_change_notifier(Notifier *notify)
+{
+    notifier_list_remove(&migration_state_notifiers, notify);
+}
+
+int get_migration_state(void)
+{
+    if (current_migration) {
+        return migrate_fd_get_status(current_migration);
+    } else {
+        return MIG_STATE_ERROR;
+    }
+}
diff --git a/qemu-0.15.x/migration.h b/qemu-0.15.x/migration.h
new file mode 100644
index 0000000..050c56c
--- /dev/null
+++ b/qemu-0.15.x/migration.h
@@ -0,0 +1,151 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_MIGRATION_H
+#define QEMU_MIGRATION_H
+
+#include "qdict.h"
+#include "qemu-common.h"
+#include "notify.h"
+
+#define MIG_STATE_ERROR		-1
+#define MIG_STATE_COMPLETED	0
+#define MIG_STATE_CANCELLED	1
+#define MIG_STATE_ACTIVE	2
+
+typedef struct MigrationState MigrationState;
+
+struct MigrationState
+{
+    /* FIXME: add more accessors to print migration info */
+    void (*cancel)(MigrationState *s);
+    int (*get_status)(MigrationState *s);
+    void (*release)(MigrationState *s);
+    int blk;
+    int shared;
+};
+
+typedef struct FdMigrationState FdMigrationState;
+
+struct FdMigrationState
+{
+    MigrationState mig_state;
+    int64_t bandwidth_limit;
+    QEMUFile *file;
+    int fd;
+    Monitor *mon;
+    int state;
+    int (*get_error)(struct FdMigrationState*);
+    int (*close)(struct FdMigrationState*);
+    int (*write)(struct FdMigrationState*, const void *, size_t);
+    void *opaque;
+};
+
+void process_incoming_migration(QEMUFile *f);
+
+int qemu_start_incoming_migration(const char *uri);
+
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+uint64_t migrate_max_downtime(void);
+
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+                            QObject **ret_data);
+
+void do_info_migrate_print(Monitor *mon, const QObject *data);
+
+void do_info_migrate(Monitor *mon, QObject **ret_data);
+
+int exec_start_incoming_migration(const char *host_port);
+
+MigrationState *exec_start_outgoing_migration(Monitor *mon,
+                                              const char *host_port,
+					      int64_t bandwidth_limit,
+					      int detach,
+					      int blk,
+					      int inc);
+
+int tcp_start_incoming_migration(const char *host_port);
+
+MigrationState *tcp_start_outgoing_migration(Monitor *mon,
+                                             const char *host_port,
+					     int64_t bandwidth_limit,
+					     int detach,
+					     int blk,
+					     int inc);
+
+int unix_start_incoming_migration(const char *path);
+
+MigrationState *unix_start_outgoing_migration(Monitor *mon,
+                                              const char *path,
+					      int64_t bandwidth_limit,
+					      int detach,
+					      int blk,
+					      int inc);
+
+int fd_start_incoming_migration(const char *path);
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach,
+					    int blk,
+					    int inc);
+
+void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon);
+
+void migrate_fd_error(FdMigrationState *s);
+
+int migrate_fd_cleanup(FdMigrationState *s);
+
+void migrate_fd_put_notify(void *opaque);
+
+ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
+
+void migrate_fd_connect(FdMigrationState *s);
+
+void migrate_fd_put_ready(void *opaque);
+
+int migrate_fd_get_status(MigrationState *mig_state);
+
+void migrate_fd_cancel(MigrationState *mig_state);
+
+void migrate_fd_release(MigrationState *mig_state);
+
+void migrate_fd_wait_for_unfreeze(void *opaque);
+
+int migrate_fd_close(void *opaque);
+
+static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
+{
+    return container_of(mig_state, FdMigrationState, mig_state);
+}
+
+void add_migration_state_change_notifier(Notifier *notify);
+void remove_migration_state_change_notifier(Notifier *notify);
+int get_migration_state(void);
+
+uint64_t ram_bytes_remaining(void);
+uint64_t ram_bytes_transferred(void);
+uint64_t ram_bytes_total(void);
+
+int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
+int ram_load(QEMUFile *f, void *opaque, int version_id);
+
+extern int incoming_expected;
+
+#endif
diff --git a/qemu-0.15.x/mips-dis.c b/qemu-0.15.x/mips-dis.c
new file mode 100644
index 0000000..4d8e85b
--- /dev/null
+++ b/qemu-0.15.x/mips-dis.c
@@ -0,0 +1,4873 @@
+/* Print mips instructions for GDB, the GNU debugger, or for objdump.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
+   Contributed by Nobuyuki Hikichi(hikichi at sra.co.jp).
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include "dis-asm.h"
+
+/* mips.h.  Mips opcode list for GDB, the GNU debugger.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
+   Contributed by Ralph Campbell and OSF
+   Commented and modified by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+will be useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this file; see the file COPYING.  If not,
+see <http://www.gnu.org/licenses/>.  */
+
+/* These are bit masks and shift counts to use to access the various
+   fields of an instruction.  To retrieve the X field of an
+   instruction, use the expression
+	(i >> OP_SH_X) & OP_MASK_X
+   To set the same field (to j), use
+	i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X)
+
+   Make sure you use fields that are appropriate for the instruction,
+   of course.
+
+   The 'i' format uses OP, RS, RT and IMMEDIATE.
+
+   The 'j' format uses OP and TARGET.
+
+   The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT.
+
+   The 'b' format uses OP, RS, RT and DELTA.
+
+   The floating point 'i' format uses OP, RS, RT and IMMEDIATE.
+
+   The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT.
+
+   A breakpoint instruction uses OP, CODE and SPEC (10 bits of the
+   breakpoint instruction are not defined; Kane says the breakpoint
+   code field in BREAK is 20 bits; yet MIPS assemblers and debuggers
+   only use ten bits).  An optional two-operand form of break/sdbbp
+   allows the lower ten bits to be set too, and MIPS32 and later
+   architectures allow 20 bits to be set with a signal operand
+   (using CODE20).
+
+   The syscall instruction uses CODE20.
+
+   The general coprocessor instructions use COPZ.  */
+
+#define OP_MASK_OP		0x3f
+#define OP_SH_OP		26
+#define OP_MASK_RS		0x1f
+#define OP_SH_RS		21
+#define OP_MASK_FR		0x1f
+#define OP_SH_FR		21
+#define OP_MASK_FMT		0x1f
+#define OP_SH_FMT		21
+#define OP_MASK_BCC		0x7
+#define OP_SH_BCC		18
+#define OP_MASK_CODE		0x3ff
+#define OP_SH_CODE		16
+#define OP_MASK_CODE2		0x3ff
+#define OP_SH_CODE2		6
+#define OP_MASK_RT		0x1f
+#define OP_SH_RT		16
+#define OP_MASK_FT		0x1f
+#define OP_SH_FT		16
+#define OP_MASK_CACHE		0x1f
+#define OP_SH_CACHE		16
+#define OP_MASK_RD		0x1f
+#define OP_SH_RD		11
+#define OP_MASK_FS		0x1f
+#define OP_SH_FS		11
+#define OP_MASK_PREFX		0x1f
+#define OP_SH_PREFX		11
+#define OP_MASK_CCC		0x7
+#define OP_SH_CCC		8
+#define OP_MASK_CODE20		0xfffff /* 20 bit syscall/breakpoint code.  */
+#define OP_SH_CODE20		6
+#define OP_MASK_SHAMT		0x1f
+#define OP_SH_SHAMT		6
+#define OP_MASK_FD		0x1f
+#define OP_SH_FD		6
+#define OP_MASK_TARGET		0x3ffffff
+#define OP_SH_TARGET		0
+#define OP_MASK_COPZ		0x1ffffff
+#define OP_SH_COPZ		0
+#define OP_MASK_IMMEDIATE	0xffff
+#define OP_SH_IMMEDIATE		0
+#define OP_MASK_DELTA		0xffff
+#define OP_SH_DELTA		0
+#define OP_MASK_FUNCT		0x3f
+#define OP_SH_FUNCT		0
+#define OP_MASK_SPEC		0x3f
+#define OP_SH_SPEC		0
+#define OP_SH_LOCC              8       /* FP condition code.  */
+#define OP_SH_HICC              18      /* FP condition code.  */
+#define OP_MASK_CC              0x7
+#define OP_SH_COP1NORM          25      /* Normal COP1 encoding.  */
+#define OP_MASK_COP1NORM        0x1     /* a single bit.  */
+#define OP_SH_COP1SPEC          21      /* COP1 encodings.  */
+#define OP_MASK_COP1SPEC        0xf
+#define OP_MASK_COP1SCLR        0x4
+#define OP_MASK_COP1CMP         0x3
+#define OP_SH_COP1CMP           4
+#define OP_SH_FORMAT            21      /* FP short format field.  */
+#define OP_MASK_FORMAT          0x7
+#define OP_SH_TRUE              16
+#define OP_MASK_TRUE            0x1
+#define OP_SH_GE                17
+#define OP_MASK_GE              0x01
+#define OP_SH_UNSIGNED          16
+#define OP_MASK_UNSIGNED        0x1
+#define OP_SH_HINT              16
+#define OP_MASK_HINT            0x1f
+#define OP_SH_MMI               0       /* Multimedia (parallel) op.  */
+#define OP_MASK_MMI             0x3f
+#define OP_SH_MMISUB            6
+#define OP_MASK_MMISUB          0x1f
+#define OP_MASK_PERFREG		0x1f	/* Performance monitoring.  */
+#define OP_SH_PERFREG		1
+#define OP_SH_SEL		0	/* Coprocessor select field.  */
+#define OP_MASK_SEL		0x7	/* The sel field of mfcZ and mtcZ.  */
+#define OP_SH_CODE19		6       /* 19 bit wait code.  */
+#define OP_MASK_CODE19		0x7ffff
+#define OP_SH_ALN		21
+#define OP_MASK_ALN		0x7
+#define OP_SH_VSEL		21
+#define OP_MASK_VSEL		0x1f
+#define OP_MASK_VECBYTE		0x7	/* Selector field is really 4 bits,
+					   but 0x8-0xf don't select bytes.  */
+#define OP_SH_VECBYTE		22
+#define OP_MASK_VECALIGN	0x7	/* Vector byte-align (alni.ob) op.  */
+#define OP_SH_VECALIGN		21
+#define OP_MASK_INSMSB		0x1f	/* "ins" MSB.  */
+#define OP_SH_INSMSB		11
+#define OP_MASK_EXTMSBD		0x1f	/* "ext" MSBD.  */
+#define OP_SH_EXTMSBD		11
+
+#define	OP_OP_COP0		0x10
+#define	OP_OP_COP1		0x11
+#define	OP_OP_COP2		0x12
+#define	OP_OP_COP3		0x13
+#define	OP_OP_LWC1		0x31
+#define	OP_OP_LWC2		0x32
+#define	OP_OP_LWC3		0x33	/* a.k.a. pref */
+#define	OP_OP_LDC1		0x35
+#define	OP_OP_LDC2		0x36
+#define	OP_OP_LDC3		0x37	/* a.k.a. ld */
+#define	OP_OP_SWC1		0x39
+#define	OP_OP_SWC2		0x3a
+#define	OP_OP_SWC3		0x3b
+#define	OP_OP_SDC1		0x3d
+#define	OP_OP_SDC2		0x3e
+#define	OP_OP_SDC3		0x3f	/* a.k.a. sd */
+
+/* MIPS DSP ASE */
+#define OP_SH_DSPACC		11
+#define OP_MASK_DSPACC  	0x3
+#define OP_SH_DSPACC_S  	21
+#define OP_MASK_DSPACC_S	0x3
+#define OP_SH_DSPSFT		20
+#define OP_MASK_DSPSFT  	0x3f
+#define OP_SH_DSPSFT_7  	19
+#define OP_MASK_DSPSFT_7	0x7f
+#define OP_SH_SA3		21
+#define OP_MASK_SA3		0x7
+#define OP_SH_SA4		21
+#define OP_MASK_SA4		0xf
+#define OP_SH_IMM8		16
+#define OP_MASK_IMM8		0xff
+#define OP_SH_IMM10		16
+#define OP_MASK_IMM10		0x3ff
+#define OP_SH_WRDSP		11
+#define OP_MASK_WRDSP		0x3f
+#define OP_SH_RDDSP		16
+#define OP_MASK_RDDSP		0x3f
+#define OP_SH_BP		11
+#define OP_MASK_BP		0x3
+
+/* MIPS MT ASE */
+#define OP_SH_MT_U		5
+#define OP_MASK_MT_U		0x1
+#define OP_SH_MT_H		4
+#define OP_MASK_MT_H		0x1
+#define OP_SH_MTACC_T		18
+#define OP_MASK_MTACC_T		0x3
+#define OP_SH_MTACC_D		13
+#define OP_MASK_MTACC_D		0x3
+
+#define	OP_OP_COP0		0x10
+#define	OP_OP_COP1		0x11
+#define	OP_OP_COP2		0x12
+#define	OP_OP_COP3		0x13
+#define	OP_OP_LWC1		0x31
+#define	OP_OP_LWC2		0x32
+#define	OP_OP_LWC3		0x33	/* a.k.a. pref */
+#define	OP_OP_LDC1		0x35
+#define	OP_OP_LDC2		0x36
+#define	OP_OP_LDC3		0x37	/* a.k.a. ld */
+#define	OP_OP_SWC1		0x39
+#define	OP_OP_SWC2		0x3a
+#define	OP_OP_SWC3		0x3b
+#define	OP_OP_SDC1		0x3d
+#define	OP_OP_SDC2		0x3e
+#define	OP_OP_SDC3		0x3f	/* a.k.a. sd */
+
+/* Values in the 'VSEL' field.  */
+#define MDMX_FMTSEL_IMM_QH	0x1d
+#define MDMX_FMTSEL_IMM_OB	0x1e
+#define MDMX_FMTSEL_VEC_QH	0x15
+#define MDMX_FMTSEL_VEC_OB	0x16
+
+/* UDI */
+#define OP_SH_UDI1		6
+#define OP_MASK_UDI1		0x1f
+#define OP_SH_UDI2		6
+#define OP_MASK_UDI2		0x3ff
+#define OP_SH_UDI3		6
+#define OP_MASK_UDI3		0x7fff
+#define OP_SH_UDI4		6
+#define OP_MASK_UDI4		0xfffff
+/* This structure holds information for a particular instruction.  */
+
+struct mips_opcode
+{
+  /* The name of the instruction.  */
+  const char *name;
+  /* A string describing the arguments for this instruction.  */
+  const char *args;
+  /* The basic opcode for the instruction.  When assembling, this
+     opcode is modified by the arguments to produce the actual opcode
+     that is used.  If pinfo is INSN_MACRO, then this is 0.  */
+  unsigned long match;
+  /* If pinfo is not INSN_MACRO, then this is a bit mask for the
+     relevant portions of the opcode when disassembling.  If the
+     actual opcode anded with the match field equals the opcode field,
+     then we have found the correct instruction.  If pinfo is
+     INSN_MACRO, then this field is the macro identifier.  */
+  unsigned long mask;
+  /* For a macro, this is INSN_MACRO.  Otherwise, it is a collection
+     of bits describing the instruction, notably any relevant hazard
+     information.  */
+  unsigned long pinfo;
+  /* A collection of additional bits describing the instruction. */
+  unsigned long pinfo2;
+  /* A collection of bits describing the instruction sets of which this
+     instruction or macro is a member. */
+  unsigned long membership;
+};
+
+/* These are the characters which may appear in the args field of an
+   instruction.  They appear in the order in which the fields appear
+   when the instruction is used.  Commas and parentheses in the args
+   string are ignored when assembling, and written into the output
+   when disassembling.
+
+   Each of these characters corresponds to a mask field defined above.
+
+   "<" 5 bit shift amount (OP_*_SHAMT)
+   ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT)
+   "a" 26 bit target address (OP_*_TARGET)
+   "b" 5 bit base register (OP_*_RS)
+   "c" 10 bit breakpoint code (OP_*_CODE)
+   "d" 5 bit destination register specifier (OP_*_RD)
+   "h" 5 bit prefx hint (OP_*_PREFX)
+   "i" 16 bit unsigned immediate (OP_*_IMMEDIATE)
+   "j" 16 bit signed immediate (OP_*_DELTA)
+   "k" 5 bit cache opcode in target register position (OP_*_CACHE)
+       Also used for immediate operands in vr5400 vector insns.
+   "o" 16 bit signed offset (OP_*_DELTA)
+   "p" 16 bit PC relative branch target address (OP_*_DELTA)
+   "q" 10 bit extra breakpoint code (OP_*_CODE2)
+   "r" 5 bit same register used as both source and target (OP_*_RS)
+   "s" 5 bit source register specifier (OP_*_RS)
+   "t" 5 bit target register (OP_*_RT)
+   "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE)
+   "v" 5 bit same register used as both source and destination (OP_*_RS)
+   "w" 5 bit same register used as both target and destination (OP_*_RT)
+   "U" 5 bit same destination register in both OP_*_RD and OP_*_RT
+       (used by clo and clz)
+   "C" 25 bit coprocessor function code (OP_*_COPZ)
+   "B" 20 bit syscall/breakpoint function code (OP_*_CODE20)
+   "J" 19 bit wait function code (OP_*_CODE19)
+   "x" accept and ignore register name
+   "z" must be zero register
+   "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD)
+   "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes
+        LSB (OP_*_SHAMT).
+	Enforces: 0 <= pos < 32.
+   "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB).
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+   "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD).
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 0 < (pos+size) <= 32.
+	(Also used by "dext" w/ different limits, but limits for
+	that are checked by the M_DEXT macro.)
+   "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT).
+	Enforces: 32 <= pos < 64.
+   "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB).
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD).
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+   "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD).
+	Requires that "+A" or "+E" occur first to set position.
+	Enforces: 32 < (pos+size) <= 64.
+
+   Floating point instructions:
+   "D" 5 bit destination register (OP_*_FD)
+   "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up)
+   "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up)
+   "S" 5 bit fs source 1 register (OP_*_FS)
+   "T" 5 bit ft source 2 register (OP_*_FT)
+   "R" 5 bit fr source 3 register (OP_*_FR)
+   "V" 5 bit same register used as floating source and destination (OP_*_FS)
+   "W" 5 bit same register used as floating target and destination (OP_*_FT)
+
+   Coprocessor instructions:
+   "E" 5 bit target register (OP_*_RT)
+   "G" 5 bit destination register (OP_*_RD)
+   "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL)
+   "P" 5 bit performance-monitor register (OP_*_PERFREG)
+   "e" 5 bit vector register byte specifier (OP_*_VECBYTE)
+   "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN)
+   see also "k" above
+   "+D" Combined destination register ("G") and sel ("H") for CP0 ops,
+	for pretty-printing in disassembly only.
+
+   Macro instructions:
+   "A" General 32 bit expression
+   "I" 32 bit immediate (value placed in imm_expr).
+   "+I" 32 bit immediate (value placed in imm2_expr).
+   "F" 64 bit floating point constant in .rdata
+   "L" 64 bit floating point constant in .lit8
+   "f" 32 bit floating point constant
+   "l" 32 bit floating point constant in .lit4
+
+   MDMX instruction operands (note that while these use the FP register
+   fields, they accept both $fN and $vN names for the registers):
+   "O"	MDMX alignment offset (OP_*_ALN)
+   "Q"	MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT)
+   "X"	MDMX destination register (OP_*_FD)
+   "Y"	MDMX source register (OP_*_FS)
+   "Z"	MDMX source register (OP_*_FT)
+
+   DSP ASE usage:
+   "2" 2 bit unsigned immediate for byte align (OP_*_BP)
+   "3" 3 bit unsigned immediate (OP_*_SA3)
+   "4" 4 bit unsigned immediate (OP_*_SA4)
+   "5" 8 bit unsigned immediate (OP_*_IMM8)
+   "6" 5 bit unsigned immediate (OP_*_RS)
+   "7" 2 bit dsp accumulator register (OP_*_DSPACC)
+   "8" 6 bit unsigned immediate (OP_*_WRDSP)
+   "9" 2 bit dsp accumulator register (OP_*_DSPACC_S)
+   "0" 6 bit signed immediate (OP_*_DSPSFT)
+   ":" 7 bit signed immediate (OP_*_DSPSFT_7)
+   "'" 6 bit unsigned immediate (OP_*_RDDSP)
+   "@" 10 bit signed immediate (OP_*_IMM10)
+
+   MT ASE usage:
+   "!" 1 bit usermode flag (OP_*_MT_U)
+   "$" 1 bit load high flag (OP_*_MT_H)
+   "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T)
+   "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D)
+   "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD)
+   "+t" 5 bit coprocessor 0 destination register (OP_*_RT)
+   "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only
+
+   UDI immediates:
+   "+1" UDI immediate bits 6-10
+   "+2" UDI immediate bits 6-15
+   "+3" UDI immediate bits 6-20
+   "+4" UDI immediate bits 6-25
+
+   Other:
+   "()" parens surrounding optional value
+   ","  separates operands
+   "[]" brackets around index for vector-op scalar operand specifier (vr5400)
+   "+"  Start of extension sequence.
+
+   Characters used so far, for quick reference when adding more:
+   "234567890"
+   "%[]<>(),+:'@!$*&"
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+   "abcdefghijklopqrstuvwxz"
+
+   Extension character sequences used so far ("+" followed by the
+   following), for quick reference when adding more:
+   "1234"
+   "ABCDEFGHIT"
+   "t"
+*/
+
+/* These are the bits which may be set in the pinfo field of an
+   instructions, if it is not equal to INSN_MACRO.  */
+
+/* Modifies the general purpose register in OP_*_RD.  */
+#define INSN_WRITE_GPR_D            0x00000001
+/* Modifies the general purpose register in OP_*_RT.  */
+#define INSN_WRITE_GPR_T            0x00000002
+/* Modifies general purpose register 31.  */
+#define INSN_WRITE_GPR_31           0x00000004
+/* Modifies the floating point register in OP_*_FD.  */
+#define INSN_WRITE_FPR_D            0x00000008
+/* Modifies the floating point register in OP_*_FS.  */
+#define INSN_WRITE_FPR_S            0x00000010
+/* Modifies the floating point register in OP_*_FT.  */
+#define INSN_WRITE_FPR_T            0x00000020
+/* Reads the general purpose register in OP_*_RS.  */
+#define INSN_READ_GPR_S             0x00000040
+/* Reads the general purpose register in OP_*_RT.  */
+#define INSN_READ_GPR_T             0x00000080
+/* Reads the floating point register in OP_*_FS.  */
+#define INSN_READ_FPR_S             0x00000100
+/* Reads the floating point register in OP_*_FT.  */
+#define INSN_READ_FPR_T             0x00000200
+/* Reads the floating point register in OP_*_FR.  */
+#define INSN_READ_FPR_R		    0x00000400
+/* Modifies coprocessor condition code.  */
+#define INSN_WRITE_COND_CODE        0x00000800
+/* Reads coprocessor condition code.  */
+#define INSN_READ_COND_CODE         0x00001000
+/* TLB operation.  */
+#define INSN_TLB                    0x00002000
+/* Reads coprocessor register other than floating point register.  */
+#define INSN_COP                    0x00004000
+/* Instruction loads value from memory, requiring delay.  */
+#define INSN_LOAD_MEMORY_DELAY      0x00008000
+/* Instruction loads value from coprocessor, requiring delay.  */
+#define INSN_LOAD_COPROC_DELAY	    0x00010000
+/* Instruction has unconditional branch delay slot.  */
+#define INSN_UNCOND_BRANCH_DELAY    0x00020000
+/* Instruction has conditional branch delay slot.  */
+#define INSN_COND_BRANCH_DELAY      0x00040000
+/* Conditional branch likely: if branch not taken, insn nullified.  */
+#define INSN_COND_BRANCH_LIKELY	    0x00080000
+/* Moves to coprocessor register, requiring delay.  */
+#define INSN_COPROC_MOVE_DELAY      0x00100000
+/* Loads coprocessor register from memory, requiring delay.  */
+#define INSN_COPROC_MEMORY_DELAY    0x00200000
+/* Reads the HI register.  */
+#define INSN_READ_HI		    0x00400000
+/* Reads the LO register.  */
+#define INSN_READ_LO		    0x00800000
+/* Modifies the HI register.  */
+#define INSN_WRITE_HI		    0x01000000
+/* Modifies the LO register.  */
+#define INSN_WRITE_LO		    0x02000000
+/* Takes a trap (easier to keep out of delay slot).  */
+#define INSN_TRAP                   0x04000000
+/* Instruction stores value into memory.  */
+#define INSN_STORE_MEMORY	    0x08000000
+/* Instruction uses single precision floating point.  */
+#define FP_S			    0x10000000
+/* Instruction uses double precision floating point.  */
+#define FP_D			    0x20000000
+/* Instruction is part of the tx39's integer multiply family.    */
+#define INSN_MULT                   0x40000000
+/* Instruction synchronize shared memory.  */
+#define INSN_SYNC		    0x80000000
+
+/* These are the bits which may be set in the pinfo2 field of an
+   instruction. */
+
+/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */
+#define	INSN2_ALIAS		    0x00000001
+/* Instruction reads MDMX accumulator. */
+#define INSN2_READ_MDMX_ACC	    0x00000002
+/* Instruction writes MDMX accumulator. */
+#define INSN2_WRITE_MDMX_ACC	    0x00000004
+
+/* Instruction is actually a macro.  It should be ignored by the
+   disassembler, and requires special treatment by the assembler.  */
+#define INSN_MACRO                  0xffffffff
+
+/* Masks used to mark instructions to indicate which MIPS ISA level
+   they were introduced in.  ISAs, as defined below, are logical
+   ORs of these bits, indicating that they support the instructions
+   defined at the given level.  */
+
+#define INSN_ISA_MASK		  0x00000fff
+#define INSN_ISA1                 0x00000001
+#define INSN_ISA2                 0x00000002
+#define INSN_ISA3                 0x00000004
+#define INSN_ISA4                 0x00000008
+#define INSN_ISA5                 0x00000010
+#define INSN_ISA32                0x00000020
+#define INSN_ISA64                0x00000040
+#define INSN_ISA32R2              0x00000080
+#define INSN_ISA64R2              0x00000100
+
+/* Masks used for MIPS-defined ASEs.  */
+#define INSN_ASE_MASK		  0x0000f000
+
+/* DSP ASE */
+#define INSN_DSP                  0x00001000
+#define INSN_DSP64                0x00002000
+/* MIPS 16 ASE */
+#define INSN_MIPS16               0x00004000
+/* MIPS-3D ASE */
+#define INSN_MIPS3D               0x00008000
+
+/* Chip specific instructions.  These are bitmasks.  */
+
+/* MIPS R4650 instruction.  */
+#define INSN_4650                 0x00010000
+/* LSI R4010 instruction.  */
+#define INSN_4010                 0x00020000
+/* NEC VR4100 instruction.  */
+#define INSN_4100                 0x00040000
+/* Toshiba R3900 instruction.  */
+#define INSN_3900                 0x00080000
+/* MIPS R10000 instruction.  */
+#define INSN_10000                0x00100000
+/* Broadcom SB-1 instruction.  */
+#define INSN_SB1                  0x00200000
+/* NEC VR4111/VR4181 instruction.  */
+#define INSN_4111                 0x00400000
+/* NEC VR4120 instruction.  */
+#define INSN_4120                 0x00800000
+/* NEC VR5400 instruction.  */
+#define INSN_5400		  0x01000000
+/* NEC VR5500 instruction.  */
+#define INSN_5500		  0x02000000
+
+/* MDMX ASE */
+#define INSN_MDMX                 0x04000000
+/* MT ASE */
+#define INSN_MT                   0x08000000
+/* SmartMIPS ASE  */
+#define INSN_SMARTMIPS            0x10000000
+/* DSP R2 ASE  */
+#define INSN_DSPR2                0x20000000
+
+/* ST Microelectronics Loongson 2E.  */
+#define INSN_LOONGSON_2E          0x40000000
+/* ST Microelectronics Loongson 2F.  */
+#define INSN_LOONGSON_2F          0x80000000
+
+/* MIPS ISA defines, use instead of hardcoding ISA level.  */
+
+#define       ISA_UNKNOWN     0               /* Gas internal use.  */
+#define       ISA_MIPS1       (INSN_ISA1)
+#define       ISA_MIPS2       (ISA_MIPS1 | INSN_ISA2)
+#define       ISA_MIPS3       (ISA_MIPS2 | INSN_ISA3)
+#define       ISA_MIPS4       (ISA_MIPS3 | INSN_ISA4)
+#define       ISA_MIPS5       (ISA_MIPS4 | INSN_ISA5)
+
+#define       ISA_MIPS32      (ISA_MIPS2 | INSN_ISA32)
+#define       ISA_MIPS64      (ISA_MIPS5 | INSN_ISA32 | INSN_ISA64)
+
+#define       ISA_MIPS32R2    (ISA_MIPS32 | INSN_ISA32R2)
+#define       ISA_MIPS64R2    (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2)
+
+
+/* CPU defines, use instead of hardcoding processor number. Keep this
+   in sync with bfd/archures.c in order for machine selection to work.  */
+#define CPU_UNKNOWN	0               /* Gas internal use.  */
+#define CPU_R3000	3000
+#define CPU_R3900	3900
+#define CPU_R4000	4000
+#define CPU_R4010	4010
+#define CPU_VR4100	4100
+#define CPU_R4111	4111
+#define CPU_VR4120	4120
+#define CPU_R4300	4300
+#define CPU_R4400	4400
+#define CPU_R4600	4600
+#define CPU_R4650	4650
+#define CPU_R5000	5000
+#define CPU_VR5400	5400
+#define CPU_VR5500	5500
+#define CPU_R6000	6000
+#define CPU_RM7000	7000
+#define CPU_R8000	8000
+#define CPU_R10000	10000
+#define CPU_R12000	12000
+#define CPU_MIPS16	16
+#define CPU_MIPS32	32
+#define CPU_MIPS32R2	33
+#define CPU_MIPS5       5
+#define CPU_MIPS64      64
+#define CPU_MIPS64R2	65
+#define CPU_SB1         12310201        /* octal 'SB', 01.  */
+
+/* Test for membership in an ISA including chip specific ISAs.  INSN
+   is pointer to an element of the opcode table; ISA is the specified
+   ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to
+   test, or zero if no CPU specific ISA test is desired.  */
+
+#if 0
+#define OPCODE_IS_MEMBER(insn, isa, cpu)				\
+    (((insn)->membership & isa) != 0					\
+     || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0)	\
+     || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0)	\
+     || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0)	\
+     || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0)	\
+     || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0)	\
+     || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0)	\
+     || ((cpu == CPU_R10000 || cpu == CPU_R12000)			\
+	 && ((insn)->membership & INSN_10000) != 0)			\
+     || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0)	\
+     || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0)	\
+     || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0)	\
+     || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0)	\
+     || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0)	\
+     || 0)	/* Please keep this term for easier source merging.  */
+#else
+#define OPCODE_IS_MEMBER(insn, isa, cpu)                               \
+    (1 != 0)
+#endif
+
+/* This is a list of macro expanded instructions.
+
+   _I appended means immediate
+   _A appended means address
+   _AB appended means address with base register
+   _D appended means 64 bit floating point constant
+   _S appended means 32 bit floating point constant.  */
+
+enum
+{
+  M_ABS,
+  M_ADD_I,
+  M_ADDU_I,
+  M_AND_I,
+  M_BALIGN,
+  M_BEQ,
+  M_BEQ_I,
+  M_BEQL_I,
+  M_BGE,
+  M_BGEL,
+  M_BGE_I,
+  M_BGEL_I,
+  M_BGEU,
+  M_BGEUL,
+  M_BGEU_I,
+  M_BGEUL_I,
+  M_BGT,
+  M_BGTL,
+  M_BGT_I,
+  M_BGTL_I,
+  M_BGTU,
+  M_BGTUL,
+  M_BGTU_I,
+  M_BGTUL_I,
+  M_BLE,
+  M_BLEL,
+  M_BLE_I,
+  M_BLEL_I,
+  M_BLEU,
+  M_BLEUL,
+  M_BLEU_I,
+  M_BLEUL_I,
+  M_BLT,
+  M_BLTL,
+  M_BLT_I,
+  M_BLTL_I,
+  M_BLTU,
+  M_BLTUL,
+  M_BLTU_I,
+  M_BLTUL_I,
+  M_BNE,
+  M_BNE_I,
+  M_BNEL_I,
+  M_CACHE_AB,
+  M_DABS,
+  M_DADD_I,
+  M_DADDU_I,
+  M_DDIV_3,
+  M_DDIV_3I,
+  M_DDIVU_3,
+  M_DDIVU_3I,
+  M_DEXT,
+  M_DINS,
+  M_DIV_3,
+  M_DIV_3I,
+  M_DIVU_3,
+  M_DIVU_3I,
+  M_DLA_AB,
+  M_DLCA_AB,
+  M_DLI,
+  M_DMUL,
+  M_DMUL_I,
+  M_DMULO,
+  M_DMULO_I,
+  M_DMULOU,
+  M_DMULOU_I,
+  M_DREM_3,
+  M_DREM_3I,
+  M_DREMU_3,
+  M_DREMU_3I,
+  M_DSUB_I,
+  M_DSUBU_I,
+  M_DSUBU_I_2,
+  M_J_A,
+  M_JAL_1,
+  M_JAL_2,
+  M_JAL_A,
+  M_L_DOB,
+  M_L_DAB,
+  M_LA_AB,
+  M_LB_A,
+  M_LB_AB,
+  M_LBU_A,
+  M_LBU_AB,
+  M_LCA_AB,
+  M_LD_A,
+  M_LD_OB,
+  M_LD_AB,
+  M_LDC1_AB,
+  M_LDC2_AB,
+  M_LDC3_AB,
+  M_LDL_AB,
+  M_LDR_AB,
+  M_LH_A,
+  M_LH_AB,
+  M_LHU_A,
+  M_LHU_AB,
+  M_LI,
+  M_LI_D,
+  M_LI_DD,
+  M_LI_S,
+  M_LI_SS,
+  M_LL_AB,
+  M_LLD_AB,
+  M_LS_A,
+  M_LW_A,
+  M_LW_AB,
+  M_LWC0_A,
+  M_LWC0_AB,
+  M_LWC1_A,
+  M_LWC1_AB,
+  M_LWC2_A,
+  M_LWC2_AB,
+  M_LWC3_A,
+  M_LWC3_AB,
+  M_LWL_A,
+  M_LWL_AB,
+  M_LWR_A,
+  M_LWR_AB,
+  M_LWU_AB,
+  M_MOVE,
+  M_MUL,
+  M_MUL_I,
+  M_MULO,
+  M_MULO_I,
+  M_MULOU,
+  M_MULOU_I,
+  M_NOR_I,
+  M_OR_I,
+  M_REM_3,
+  M_REM_3I,
+  M_REMU_3,
+  M_REMU_3I,
+  M_DROL,
+  M_ROL,
+  M_DROL_I,
+  M_ROL_I,
+  M_DROR,
+  M_ROR,
+  M_DROR_I,
+  M_ROR_I,
+  M_S_DA,
+  M_S_DOB,
+  M_S_DAB,
+  M_S_S,
+  M_SC_AB,
+  M_SCD_AB,
+  M_SD_A,
+  M_SD_OB,
+  M_SD_AB,
+  M_SDC1_AB,
+  M_SDC2_AB,
+  M_SDC3_AB,
+  M_SDL_AB,
+  M_SDR_AB,
+  M_SEQ,
+  M_SEQ_I,
+  M_SGE,
+  M_SGE_I,
+  M_SGEU,
+  M_SGEU_I,
+  M_SGT,
+  M_SGT_I,
+  M_SGTU,
+  M_SGTU_I,
+  M_SLE,
+  M_SLE_I,
+  M_SLEU,
+  M_SLEU_I,
+  M_SLT_I,
+  M_SLTU_I,
+  M_SNE,
+  M_SNE_I,
+  M_SB_A,
+  M_SB_AB,
+  M_SH_A,
+  M_SH_AB,
+  M_SW_A,
+  M_SW_AB,
+  M_SWC0_A,
+  M_SWC0_AB,
+  M_SWC1_A,
+  M_SWC1_AB,
+  M_SWC2_A,
+  M_SWC2_AB,
+  M_SWC3_A,
+  M_SWC3_AB,
+  M_SWL_A,
+  M_SWL_AB,
+  M_SWR_A,
+  M_SWR_AB,
+  M_SUB_I,
+  M_SUBU_I,
+  M_SUBU_I_2,
+  M_TEQ_I,
+  M_TGE_I,
+  M_TGEU_I,
+  M_TLT_I,
+  M_TLTU_I,
+  M_TNE_I,
+  M_TRUNCWD,
+  M_TRUNCWS,
+  M_ULD,
+  M_ULD_A,
+  M_ULH,
+  M_ULH_A,
+  M_ULHU,
+  M_ULHU_A,
+  M_ULW,
+  M_ULW_A,
+  M_USH,
+  M_USH_A,
+  M_USW,
+  M_USW_A,
+  M_USD,
+  M_USD_A,
+  M_XOR_I,
+  M_COP0,
+  M_COP1,
+  M_COP2,
+  M_COP3,
+  M_NUM_MACROS
+};
+
+
+/* The order of overloaded instructions matters.  Label arguments and
+   register arguments look the same. Instructions that can have either
+   for arguments must apear in the correct order in this table for the
+   assembler to pick the right one. In other words, entries with
+   immediate operands must apear after the same instruction with
+   registers.
+
+   Many instructions are short hand for other instructions (i.e., The
+   jal <register> instruction is short for jalr <register>).  */
+
+extern const struct mips_opcode mips_builtin_opcodes[];
+extern const int bfd_mips_num_builtin_opcodes;
+extern struct mips_opcode *mips_opcodes;
+extern int bfd_mips_num_opcodes;
+#define NUMOPCODES bfd_mips_num_opcodes
+
+
+/* The rest of this file adds definitions for the mips16 TinyRISC
+   processor.  */
+
+/* These are the bitmasks and shift counts used for the different
+   fields in the instruction formats.  Other than OP, no masks are
+   provided for the fixed portions of an instruction, since they are
+   not needed.
+
+   The I format uses IMM11.
+
+   The RI format uses RX and IMM8.
+
+   The RR format uses RX, and RY.
+
+   The RRI format uses RX, RY, and IMM5.
+
+   The RRR format uses RX, RY, and RZ.
+
+   The RRI_A format uses RX, RY, and IMM4.
+
+   The SHIFT format uses RX, RY, and SHAMT.
+
+   The I8 format uses IMM8.
+
+   The I8_MOVR32 format uses RY and REGR32.
+
+   The IR_MOV32R format uses REG32R and MOV32Z.
+
+   The I64 format uses IMM8.
+
+   The RI64 format uses RY and IMM5.
+   */
+
+#define MIPS16OP_MASK_OP	0x1f
+#define MIPS16OP_SH_OP		11
+#define MIPS16OP_MASK_IMM11	0x7ff
+#define MIPS16OP_SH_IMM11	0
+#define MIPS16OP_MASK_RX	0x7
+#define MIPS16OP_SH_RX		8
+#define MIPS16OP_MASK_IMM8	0xff
+#define MIPS16OP_SH_IMM8	0
+#define MIPS16OP_MASK_RY	0x7
+#define MIPS16OP_SH_RY		5
+#define MIPS16OP_MASK_IMM5	0x1f
+#define MIPS16OP_SH_IMM5	0
+#define MIPS16OP_MASK_RZ	0x7
+#define MIPS16OP_SH_RZ		2
+#define MIPS16OP_MASK_IMM4	0xf
+#define MIPS16OP_SH_IMM4	0
+#define MIPS16OP_MASK_REGR32	0x1f
+#define MIPS16OP_SH_REGR32	0
+#define MIPS16OP_MASK_REG32R	0x1f
+#define MIPS16OP_SH_REG32R	3
+#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18))
+#define MIPS16OP_MASK_MOVE32Z	0x7
+#define MIPS16OP_SH_MOVE32Z	0
+#define MIPS16OP_MASK_IMM6	0x3f
+#define MIPS16OP_SH_IMM6	5
+
+/* These are the characters which may appears in the args field of an
+   instruction.  They appear in the order in which the fields appear
+   when the instruction is used.  Commas and parentheses in the args
+   string are ignored when assembling, and written into the output
+   when disassembling.
+
+   "y" 3 bit register (MIPS16OP_*_RY)
+   "x" 3 bit register (MIPS16OP_*_RX)
+   "z" 3 bit register (MIPS16OP_*_RZ)
+   "Z" 3 bit register (MIPS16OP_*_MOVE32Z)
+   "v" 3 bit same register as source and destination (MIPS16OP_*_RX)
+   "w" 3 bit same register as source and destination (MIPS16OP_*_RY)
+   "0" zero register ($0)
+   "S" stack pointer ($sp or $29)
+   "P" program counter
+   "R" return address register ($ra or $31)
+   "X" 5 bit MIPS register (MIPS16OP_*_REGR32)
+   "Y" 5 bit MIPS register (MIPS16OP_*_REG32R)
+   "6" 6 bit unsigned break code (MIPS16OP_*_IMM6)
+   "a" 26 bit jump address
+   "e" 11 bit extension value
+   "l" register list for entry instruction
+   "L" register list for exit instruction
+
+   The remaining codes may be extended.  Except as otherwise noted,
+   the full extended operand is a 16 bit signed value.
+   "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned)
+   ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned)
+   "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned)
+   "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned)
+   "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed)
+   "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5)
+   "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5)
+   "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5)
+   "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5)
+   "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5)
+   "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8)
+   "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8)
+   "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8)
+   "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned)
+   "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8)
+   "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8)
+   "p" 8 bit conditional branch address (MIPS16OP_*_IMM8)
+   "q" 11 bit branch address (MIPS16OP_*_IMM11)
+   "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8)
+   "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5)
+   "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5)
+   */
+
+/* Save/restore encoding for the args field when all 4 registers are
+   either saved as arguments or saved/restored as statics.  */
+#define MIPS16_ALL_ARGS    0xe
+#define MIPS16_ALL_STATICS 0xb
+
+/* For the mips16, we use the same opcode table format and a few of
+   the same flags.  However, most of the flags are different.  */
+
+/* Modifies the register in MIPS16OP_*_RX.  */
+#define MIPS16_INSN_WRITE_X		    0x00000001
+/* Modifies the register in MIPS16OP_*_RY.  */
+#define MIPS16_INSN_WRITE_Y		    0x00000002
+/* Modifies the register in MIPS16OP_*_RZ.  */
+#define MIPS16_INSN_WRITE_Z		    0x00000004
+/* Modifies the T ($24) register.  */
+#define MIPS16_INSN_WRITE_T		    0x00000008
+/* Modifies the SP ($29) register.  */
+#define MIPS16_INSN_WRITE_SP		    0x00000010
+/* Modifies the RA ($31) register.  */
+#define MIPS16_INSN_WRITE_31		    0x00000020
+/* Modifies the general purpose register in MIPS16OP_*_REG32R.  */
+#define MIPS16_INSN_WRITE_GPR_Y		    0x00000040
+/* Reads the register in MIPS16OP_*_RX.  */
+#define MIPS16_INSN_READ_X		    0x00000080
+/* Reads the register in MIPS16OP_*_RY.  */
+#define MIPS16_INSN_READ_Y		    0x00000100
+/* Reads the register in MIPS16OP_*_MOVE32Z.  */
+#define MIPS16_INSN_READ_Z		    0x00000200
+/* Reads the T ($24) register.  */
+#define MIPS16_INSN_READ_T		    0x00000400
+/* Reads the SP ($29) register.  */
+#define MIPS16_INSN_READ_SP		    0x00000800
+/* Reads the RA ($31) register.  */
+#define MIPS16_INSN_READ_31		    0x00001000
+/* Reads the program counter.  */
+#define MIPS16_INSN_READ_PC		    0x00002000
+/* Reads the general purpose register in MIPS16OP_*_REGR32.  */
+#define MIPS16_INSN_READ_GPR_X		    0x00004000
+/* Is a branch insn. */
+#define MIPS16_INSN_BRANCH                  0x00010000
+
+/* The following flags have the same value for the mips16 opcode
+   table:
+   INSN_UNCOND_BRANCH_DELAY
+   INSN_COND_BRANCH_DELAY
+   INSN_COND_BRANCH_LIKELY (never used)
+   INSN_READ_HI
+   INSN_READ_LO
+   INSN_WRITE_HI
+   INSN_WRITE_LO
+   INSN_TRAP
+   INSN_ISA3
+   */
+
+extern const struct mips_opcode mips16_opcodes[];
+extern const int bfd_mips16_num_opcodes;
+
+/* Short hand so the lines aren't too long.  */
+
+#define LDD     INSN_LOAD_MEMORY_DELAY
+#define LCD	INSN_LOAD_COPROC_DELAY
+#define UBD     INSN_UNCOND_BRANCH_DELAY
+#define CBD	INSN_COND_BRANCH_DELAY
+#define COD     INSN_COPROC_MOVE_DELAY
+#define CLD	INSN_COPROC_MEMORY_DELAY
+#define CBL	INSN_COND_BRANCH_LIKELY
+#define TRAP	INSN_TRAP
+#define SM	INSN_STORE_MEMORY
+
+#define WR_d    INSN_WRITE_GPR_D
+#define WR_t    INSN_WRITE_GPR_T
+#define WR_31   INSN_WRITE_GPR_31
+#define WR_D    INSN_WRITE_FPR_D
+#define WR_T	INSN_WRITE_FPR_T
+#define WR_S	INSN_WRITE_FPR_S
+#define RD_s    INSN_READ_GPR_S
+#define RD_b    INSN_READ_GPR_S
+#define RD_t    INSN_READ_GPR_T
+#define RD_S    INSN_READ_FPR_S
+#define RD_T    INSN_READ_FPR_T
+#define RD_R	INSN_READ_FPR_R
+#define WR_CC	INSN_WRITE_COND_CODE
+#define RD_CC	INSN_READ_COND_CODE
+#define RD_C0   INSN_COP
+#define RD_C1	INSN_COP
+#define RD_C2   INSN_COP
+#define RD_C3   INSN_COP
+#define WR_C0   INSN_COP
+#define WR_C1	INSN_COP
+#define WR_C2   INSN_COP
+#define WR_C3   INSN_COP
+
+#define WR_HI	INSN_WRITE_HI
+#define RD_HI	INSN_READ_HI
+#define MOD_HI  WR_HI|RD_HI
+
+#define WR_LO	INSN_WRITE_LO
+#define RD_LO	INSN_READ_LO
+#define MOD_LO  WR_LO|RD_LO
+
+#define WR_HILO WR_HI|WR_LO
+#define RD_HILO RD_HI|RD_LO
+#define MOD_HILO WR_HILO|RD_HILO
+
+#define IS_M    INSN_MULT
+
+#define WR_MACC INSN2_WRITE_MDMX_ACC
+#define RD_MACC INSN2_READ_MDMX_ACC
+
+#define I1	INSN_ISA1
+#define I2	INSN_ISA2
+#define I3	INSN_ISA3
+#define I4	INSN_ISA4
+#define I5	INSN_ISA5
+#define I32	INSN_ISA32
+#define I64     INSN_ISA64
+#define I33	INSN_ISA32R2
+#define I65	INSN_ISA64R2
+
+/* MIPS64 MIPS-3D ASE support.  */
+#define I16     INSN_MIPS16
+
+/* MIPS32 SmartMIPS ASE support.  */
+#define SMT	INSN_SMARTMIPS
+
+/* MIPS64 MIPS-3D ASE support.  */
+#define M3D     INSN_MIPS3D
+
+/* MIPS64 MDMX ASE support.  */
+#define MX      INSN_MDMX
+
+#define IL2E	(INSN_LOONGSON_2E)
+#define IL2F	(INSN_LOONGSON_2F)
+
+#define P3	INSN_4650
+#define L1	INSN_4010
+#define V1	(INSN_4100 | INSN_4111 | INSN_4120)
+#define T3      INSN_3900
+#define M1	INSN_10000
+#define SB1     INSN_SB1
+#define N411	INSN_4111
+#define N412	INSN_4120
+#define N5	(INSN_5400 | INSN_5500)
+#define N54	INSN_5400
+#define N55	INSN_5500
+
+#define G1      (T3             \
+                 )
+
+#define G2      (T3             \
+                 )
+
+#define G3      (I4             \
+                 )
+
+/* MIPS DSP ASE support.
+   NOTE:
+   1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3).  $ac0 is the pair
+   of original HI and LO.  $ac1, $ac2 and $ac3 are new registers, and have
+   the same structure as $ac0 (HI + LO).  For DSP instructions that write or
+   read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a
+   (RD_HILO) attributes, such that HILO dependencies are maintained
+   conservatively.
+
+   2. For some mul. instructions that use integer registers as destinations
+   but destroy HI+LO as side-effect, we add WR_HILO to their attributes.
+
+   3. MIPS DSP ASE includes a new DSP control register, which has 6 fields
+   (ccond, outflag, EFI, c, scount, pos).  Many DSP instructions read or write
+   certain fields of the DSP control register.  For simplicity, we decide not
+   to track dependencies of these fields.
+   However, "bposge32" is a branch instruction that depends on the "pos"
+   field.  In order to make sure that GAS does not reorder DSP instructions
+   that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP)
+   attribute to those instructions that write the "pos" field.  */
+
+#define WR_a	WR_HILO	/* Write dsp accumulators (reuse WR_HILO)  */
+#define RD_a	RD_HILO	/* Read dsp accumulators (reuse RD_HILO)  */
+#define MOD_a	WR_a|RD_a
+#define DSP_VOLA	INSN_TRAP
+#define D32	INSN_DSP
+#define D33	INSN_DSPR2
+#define D64	INSN_DSP64
+
+/* MIPS MT ASE support.  */
+#define MT32	INSN_MT
+
+/* The order of overloaded instructions matters.  Label arguments and
+   register arguments look the same. Instructions that can have either
+   for arguments must apear in the correct order in this table for the
+   assembler to pick the right one. In other words, entries with
+   immediate operands must apear after the same instruction with
+   registers.
+
+   Because of the lookup algorithm used, entries with the same opcode
+   name must be contiguous.
+
+   Many instructions are short hand for other instructions (i.e., The
+   jal <register> instruction is short for jalr <register>).  */
+
+const struct mips_opcode mips_builtin_opcodes[] =
+{
+/* These instructions appear first so that the disassembler will find
+   them first.  The assemblers uses a hash table based on the
+   instruction name anyhow.  */
+/* name,    args,	match,	    mask,	pinfo,          	membership */
+{"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
+{"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
+{"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
+{"ssnop",   "",         0x00000040, 0xffffffff, 0,              	INSN2_ALIAS,	I32|N55	}, /* sll */
+{"ehb",     "",         0x000000c0, 0xffffffff, 0,              	INSN2_ALIAS,	I33	}, /* sll */
+{"li",      "t,j",      0x24000000, 0xffe00000, WR_t,			INSN2_ALIAS,	I1	}, /* addiu */
+{"li",	    "t,i",	0x34000000, 0xffe00000, WR_t,			INSN2_ALIAS,	I1	}, /* ori */
+{"li",      "t,I",	0,    (int) M_LI,	INSN_MACRO,		0,		I1	},
+{"move",    "d,s",	0,    (int) M_MOVE,	INSN_MACRO,		0,		I1	},
+{"move",    "d,s",	0x0000002d, 0xfc1f07ff, WR_d|RD_s,		INSN2_ALIAS,	I3	},/* daddu */
+{"move",    "d,s",	0x00000021, 0xfc1f07ff, WR_d|RD_s,		INSN2_ALIAS,	I1	},/* addu */
+{"move",    "d,s",	0x00000025, 0xfc1f07ff,	WR_d|RD_s,		INSN2_ALIAS,	I1	},/* or */
+{"b",       "p",	0x10000000, 0xffff0000,	UBD,			INSN2_ALIAS,	I1	},/* beq 0,0 */
+{"b",       "p",	0x04010000, 0xffff0000,	UBD,			INSN2_ALIAS,	I1	},/* bgez 0 */
+{"bal",     "p",	0x04110000, 0xffff0000,	UBD|WR_31,		INSN2_ALIAS,	I1	},/* bgezal 0*/
+
+{"abs",     "d,v",	0,    (int) M_ABS,	INSN_MACRO,		0,		I1	},
+{"abs.s",   "D,V",	0x46000005, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"abs.d",   "D,V",	0x46200005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"abs.ps",  "D,V",	0x46c00005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"add",     "d,v,t",	0x00000020, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"add",     "t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,		I1	},
+{"add.s",   "D,V,T",	0x46000000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"add.d",   "D,V,T",	0x46200000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"add.ob",  "X,Y,Q",	0x7800000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"add.ob",  "D,S,T",	0x4ac0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ob",  "D,S,T[e]",	0x4800000b, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ob",  "D,S,k",	0x4bc0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ps",  "D,V,T",	0x46c00000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"add.qh",  "X,Y,Q",	0x7820000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"adda.ob", "Y,Q",	0x78000037, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"adda.qh", "Y,Q",	0x78200037, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"addi",    "t,r,j",	0x20000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"addiu",   "t,r,j",	0x24000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"addl.ob", "Y,Q",	0x78000437, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"addl.qh", "Y,Q",	0x78200437, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"addr.ps", "D,S,T",	0x46c00018, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"addu",    "d,v,t",	0x00000021, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"addu",    "t,r,I",	0,    (int) M_ADDU_I,	INSN_MACRO,		0,		I1	},
+{"alni.ob", "X,Y,Z,O",	0x78000018, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"alni.ob", "D,S,T,%",	0x48000018, 0xff00003f,	WR_D|RD_S|RD_T, 	0,		N54	},
+{"alni.qh", "X,Y,Z,O",	0x7800001a, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"alnv.ps", "D,V,T,s",	0x4c00001e, 0xfc00003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"alnv.ob", "X,Y,Z,s",	0x78000019, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, 0,		MX|SB1	},
+{"alnv.qh", "X,Y,Z,s",	0x7800001b, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, 0,		MX	},
+{"and",     "d,v,t",	0x00000024, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"and",     "t,r,I",	0,    (int) M_AND_I,	INSN_MACRO,		0,		I1	},
+{"and.ob",  "X,Y,Q",	0x7800000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"and.ob",  "D,S,T",	0x4ac0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.ob",  "D,S,T[e]",	0x4800000c, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.ob",  "D,S,k",	0x4bc0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.qh",  "X,Y,Q",	0x7820000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"andi",    "t,r,i",	0x30000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+/* b is at the top of the table.  */
+/* bal is at the top of the table.  */
+/* bc0[tf]l? are at the bottom of the table.  */
+{"bc1any2f", "N,p",	0x45200000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any2t", "N,p",	0x45210000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any4f", "N,p",	0x45400000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any4t", "N,p",	0x45410000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1f",    "p",	0x45000000, 0xffff0000,	CBD|RD_CC|FP_S,		0,		I1	},
+{"bc1f",    "N,p",      0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1fl",   "p",	0x45020000, 0xffff0000,	CBL|RD_CC|FP_S,		0,		I2|T3	},
+{"bc1fl",   "N,p",      0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1t",    "p",	0x45010000, 0xffff0000,	CBD|RD_CC|FP_S,		0,		I1	},
+{"bc1t",    "N,p",      0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1tl",   "p",	0x45030000, 0xffff0000,	CBL|RD_CC|FP_S,		0,		I2|T3	},
+{"bc1tl",   "N,p",      0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 	0,		I4|I32	},
+/* bc2* are at the bottom of the table.  */
+/* bc3* are at the bottom of the table.  */
+{"beqz",    "s,p",	0x10000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"beqzl",   "s,p",	0x50000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"beq",     "s,t,p",	0x10000000, 0xfc000000,	CBD|RD_s|RD_t,		0,		I1	},
+{"beq",     "s,I,p",	0,    (int) M_BEQ_I,	INSN_MACRO,		0,		I1	},
+{"beql",    "s,t,p",	0x50000000, 0xfc000000,	CBL|RD_s|RD_t,		0,		I2|T3	},
+{"beql",    "s,I,p",	0,    (int) M_BEQL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bge",     "s,t,p",	0,    (int) M_BGE,	INSN_MACRO,		0,		I1	},
+{"bge",     "s,I,p",	0,    (int) M_BGE_I,	INSN_MACRO,		0,		I1	},
+{"bgel",    "s,t,p",	0,    (int) M_BGEL,	INSN_MACRO,		0,		I2|T3	},
+{"bgel",    "s,I,p",	0,    (int) M_BGEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgeu",    "s,t,p",	0,    (int) M_BGEU,	INSN_MACRO,		0,		I1	},
+{"bgeu",    "s,I,p",	0,    (int) M_BGEU_I,	INSN_MACRO,		0,		I1	},
+{"bgeul",   "s,t,p",	0,    (int) M_BGEUL,	INSN_MACRO,		0,		I2|T3	},
+{"bgeul",   "s,I,p",	0,    (int) M_BGEUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgez",    "s,p",	0x04010000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bgezl",   "s,p",	0x04030000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bgezal",  "s,p",	0x04110000, 0xfc1f0000,	CBD|RD_s|WR_31,		0,		I1	},
+{"bgezall", "s,p",	0x04130000, 0xfc1f0000,	CBL|RD_s|WR_31,		0,		I2|T3	},
+{"bgt",     "s,t,p",	0,    (int) M_BGT,	INSN_MACRO,		0,		I1	},
+{"bgt",     "s,I,p",	0,    (int) M_BGT_I,	INSN_MACRO,		0,		I1	},
+{"bgtl",    "s,t,p",	0,    (int) M_BGTL,	INSN_MACRO,		0,		I2|T3	},
+{"bgtl",    "s,I,p",	0,    (int) M_BGTL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgtu",    "s,t,p",	0,    (int) M_BGTU,	INSN_MACRO,		0,		I1	},
+{"bgtu",    "s,I,p",	0,    (int) M_BGTU_I,	INSN_MACRO,		0,		I1	},
+{"bgtul",   "s,t,p",	0,    (int) M_BGTUL,	INSN_MACRO,		0,		I2|T3	},
+{"bgtul",   "s,I,p",	0,    (int) M_BGTUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgtz",    "s,p",	0x1c000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bgtzl",   "s,p",	0x5c000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"ble",     "s,t,p",	0,    (int) M_BLE,	INSN_MACRO,		0,		I1	},
+{"ble",     "s,I,p",	0,    (int) M_BLE_I,	INSN_MACRO,		0,		I1	},
+{"blel",    "s,t,p",	0,    (int) M_BLEL,	INSN_MACRO,		0,		I2|T3	},
+{"blel",    "s,I,p",	0,    (int) M_BLEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bleu",    "s,t,p",	0,    (int) M_BLEU,	INSN_MACRO,		0,		I1	},
+{"bleu",    "s,I,p",	0,    (int) M_BLEU_I,	INSN_MACRO,		0,		I1	},
+{"bleul",   "s,t,p",	0,    (int) M_BLEUL,	INSN_MACRO,		0,		I2|T3	},
+{"bleul",   "s,I,p",	0,    (int) M_BLEUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"blez",    "s,p",	0x18000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"blezl",   "s,p",	0x58000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"blt",     "s,t,p",	0,    (int) M_BLT,	INSN_MACRO,		0,		I1	},
+{"blt",     "s,I,p",	0,    (int) M_BLT_I,	INSN_MACRO,		0,		I1	},
+{"bltl",    "s,t,p",	0,    (int) M_BLTL,	INSN_MACRO,		0,		I2|T3	},
+{"bltl",    "s,I,p",	0,    (int) M_BLTL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bltu",    "s,t,p",	0,    (int) M_BLTU,	INSN_MACRO,		0,		I1	},
+{"bltu",    "s,I,p",	0,    (int) M_BLTU_I,	INSN_MACRO,		0,		I1	},
+{"bltul",   "s,t,p",	0,    (int) M_BLTUL,	INSN_MACRO,		0,		I2|T3	},
+{"bltul",   "s,I,p",	0,    (int) M_BLTUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bltz",    "s,p",	0x04000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bltzl",   "s,p",	0x04020000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bltzal",  "s,p",	0x04100000, 0xfc1f0000,	CBD|RD_s|WR_31,		0,		I1	},
+{"bltzall", "s,p",	0x04120000, 0xfc1f0000,	CBL|RD_s|WR_31,		0,		I2|T3	},
+{"bnez",    "s,p",	0x14000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bnezl",   "s,p",	0x54000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bne",     "s,t,p",	0x14000000, 0xfc000000,	CBD|RD_s|RD_t,		0,		I1	},
+{"bne",     "s,I,p",	0,    (int) M_BNE_I,	INSN_MACRO,		0,		I1	},
+{"bnel",    "s,t,p",	0x54000000, 0xfc000000,	CBL|RD_s|RD_t, 		0,		I2|T3	},
+{"bnel",    "s,I,p",	0,    (int) M_BNEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"break",   "",		0x0000000d, 0xffffffff,	TRAP,			0,		I1	},
+{"break",   "c",	0x0000000d, 0xfc00ffff,	TRAP,			0,		I1	},
+{"break",   "c,q",	0x0000000d, 0xfc00003f,	TRAP,			0,		I1	},
+{"c.f.d",   "S,T",	0x46200030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.f.d",   "M,S,T",    0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.f.s",   "S,T",      0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.f.s",   "M,S,T",    0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.f.ps",  "S,T",	0x46c00030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.f.ps",  "M,S,T",	0x46c00030, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.un.d",  "S,T",	0x46200031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.un.d",  "M,S,T",    0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.un.s",  "S,T",      0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.un.s",  "M,S,T",    0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.un.ps", "S,T",	0x46c00031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.un.ps", "M,S,T",	0x46c00031, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.d",  "S,T",	0x46200032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.eq.d",  "M,S,T",    0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.eq.s",  "S,T",      0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.eq.s",  "M,S,T",    0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.eq.ob", "Y,Q",	0x78000001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.eq.ob", "S,T",	0x4ac00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ob", "S,T[e]",	0x48000001, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ob", "S,k",	0x4bc00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ps", "S,T",	0x46c00032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.ps", "M,S,T",	0x46c00032, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.qh", "Y,Q",	0x78200001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.ueq.d", "S,T",	0x46200033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ueq.d", "M,S,T",    0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ueq.s", "S,T",      0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ueq.s", "M,S,T",    0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ueq.ps","S,T",	0x46c00033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ueq.ps","M,S,T",	0x46c00033, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.olt.d", "S,T",      0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   0,		I1      },
+{"c.olt.d", "M,S,T",    0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.olt.s", "S,T",	0x46000034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.olt.s", "M,S,T",    0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.olt.ps","S,T",	0x46c00034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.olt.ps","M,S,T",	0x46c00034, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ult.d", "S,T",	0x46200035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ult.d", "M,S,T",    0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ult.s", "S,T",      0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ult.s", "M,S,T",    0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ult.ps","S,T",	0x46c00035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ult.ps","M,S,T",	0x46c00035, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ole.d", "S,T",      0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   0,		I1      },
+{"c.ole.d", "M,S,T",    0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ole.s", "S,T",      0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ole.s", "M,S,T",    0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ole.ps","S,T",	0x46c00036, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ole.ps","M,S,T",	0x46c00036, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ule.d", "S,T",	0x46200037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ule.d", "M,S,T",    0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ule.s", "S,T",      0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ule.s", "M,S,T",    0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ule.ps","S,T",	0x46c00037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ule.ps","M,S,T",	0x46c00037, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.sf.d",  "S,T",	0x46200038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.sf.d",  "M,S,T",    0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.sf.s",  "S,T",      0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.sf.s",  "M,S,T",    0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.sf.ps", "S,T",	0x46c00038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.sf.ps", "M,S,T",	0x46c00038, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngle.d","S,T",	0x46200039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngle.d","M,S,T",    0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngle.s","S,T",      0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngle.s","M,S,T",    0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngle.ps","S,T",	0x46c00039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngle.ps","M,S,T",	0x46c00039, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.seq.d", "S,T",	0x4620003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.seq.d", "M,S,T",    0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.seq.s", "S,T",      0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.seq.s", "M,S,T",    0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.seq.ps","S,T",	0x46c0003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.seq.ps","M,S,T",	0x46c0003a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngl.d", "S,T",	0x4620003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngl.d", "M,S,T",    0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngl.s", "S,T",      0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngl.s", "M,S,T",    0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngl.ps","S,T",	0x46c0003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngl.ps","M,S,T",	0x46c0003b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.d",  "S,T",	0x4620003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.lt.d",  "M,S,T",    0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.lt.s",  "S,T",	0x4600003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.lt.s",  "M,S,T",    0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.lt.ob", "Y,Q",	0x78000004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.lt.ob", "S,T",	0x4ac00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ob", "S,T[e]",	0x48000004, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ob", "S,k",	0x4bc00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ps", "S,T",	0x46c0003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.ps", "M,S,T",	0x46c0003c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.qh", "Y,Q",	0x78200004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.nge.d", "S,T",	0x4620003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.nge.d", "M,S,T",    0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.nge.s", "S,T",      0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.nge.s", "M,S,T",    0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.nge.ps","S,T",	0x46c0003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.nge.ps","M,S,T",	0x46c0003d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.d",  "S,T",	0x4620003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.le.d",  "M,S,T",    0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.le.s",  "S,T",	0x4600003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.le.s",  "M,S,T",    0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.le.ob", "Y,Q",	0x78000005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.le.ob", "S,T",	0x4ac00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ob", "S,T[e]",	0x48000005, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ob", "S,k",	0x4bc00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ps", "S,T",	0x46c0003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.ps", "M,S,T",	0x46c0003e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.qh", "Y,Q",	0x78200005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.ngt.d", "S,T",	0x4620003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngt.d", "M,S,T",    0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngt.s", "S,T",      0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngt.s", "M,S,T",    0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngt.ps","S,T",	0x46c0003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngt.ps","M,S,T",	0x46c0003f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"cabs.eq.d",  "M,S,T",	0x46200072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.eq.ps", "M,S,T",	0x46c00072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.eq.s",  "M,S,T",	0x46000072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.f.d",   "M,S,T",	0x46200070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.f.ps",  "M,S,T",	0x46c00070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.f.s",   "M,S,T",	0x46000070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.le.d",  "M,S,T",	0x4620007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.le.ps", "M,S,T",	0x46c0007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.le.s",  "M,S,T",	0x4600007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.lt.d",  "M,S,T",	0x4620007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.lt.ps", "M,S,T",	0x46c0007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.lt.s",  "M,S,T",	0x4600007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.nge.d", "M,S,T",	0x4620007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.nge.ps","M,S,T",	0x46c0007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.nge.s", "M,S,T",	0x4600007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngl.d", "M,S,T",	0x4620007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngl.ps","M,S,T",	0x46c0007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngl.s", "M,S,T",	0x4600007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngle.d","M,S,T",	0x46200079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngle.s","M,S,T",	0x46000079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngt.d", "M,S,T",	0x4620007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngt.ps","M,S,T",	0x46c0007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngt.s", "M,S,T",	0x4600007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ole.d", "M,S,T",	0x46200076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ole.ps","M,S,T",	0x46c00076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ole.s", "M,S,T",	0x46000076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.olt.d", "M,S,T",	0x46200074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.olt.ps","M,S,T",	0x46c00074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.olt.s", "M,S,T",	0x46000074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.seq.d", "M,S,T",	0x4620007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.seq.ps","M,S,T",	0x46c0007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.seq.s", "M,S,T",	0x4600007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.sf.d",  "M,S,T",	0x46200078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.sf.ps", "M,S,T",	0x46c00078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.sf.s",  "M,S,T",	0x46000078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ueq.d", "M,S,T",	0x46200073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ueq.ps","M,S,T",	0x46c00073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ueq.s", "M,S,T",	0x46000073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ule.d", "M,S,T",	0x46200077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ule.ps","M,S,T",	0x46c00077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ule.s", "M,S,T",	0x46000077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ult.d", "M,S,T",	0x46200075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ult.ps","M,S,T",	0x46c00075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ult.s", "M,S,T",	0x46000075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.un.d",  "M,S,T",	0x46200071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.un.ps", "M,S,T",	0x46c00071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.un.s",  "M,S,T",	0x46000071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+/* CW4010 instructions which are aliases for the cache instruction.  */
+{"flushi",  "",		0xbc010000, 0xffffffff, 0,			0,		L1	},
+{"flushd",  "",		0xbc020000, 0xffffffff, 0, 			0,		L1	},
+{"flushid", "",		0xbc030000, 0xffffffff, 0, 			0,		L1	},
+{"wb", 	    "o(b)",	0xbc040000, 0xfc1f0000, SM|RD_b,		0,		L1	},
+{"cache",   "k,o(b)",   0xbc000000, 0xfc000000, RD_b,           	0,		I3|I32|T3},
+{"cache",   "k,A(b)",	0,    (int) M_CACHE_AB, INSN_MACRO,		0,		I3|I32|T3},
+{"ceil.l.d", "D,S",	0x4620000a, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"ceil.l.s", "D,S",	0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"ceil.w.d", "D,S",	0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"ceil.w.s", "D,S",	0x4600000e, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"cfc0",    "t,G",	0x40400000, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		I1	},
+{"cfc1",    "t,G",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	0,		I1	},
+{"cfc1",    "t,S",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	0,		I1	},
+/* cfc2 is at the bottom of the table.  */
+/* cfc3 is at the bottom of the table.  */
+{"cftc1",   "d,E",	0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0,		MT32	},
+{"cftc1",   "d,T",	0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0,		MT32	},
+{"cftc2",   "d,E",	0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"clo",     "U,s",      0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 	0,		I32|N55 },
+{"clz",     "U,s",      0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 	0,		I32|N55 },
+{"ctc0",    "t,G",	0x40c00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"ctc1",    "t,G",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	0,		I1	},
+{"ctc1",    "t,S",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	0,		I1	},
+/* ctc2 is at the bottom of the table.  */
+/* ctc3 is at the bottom of the table.  */
+{"cttc1",   "t,g",	0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0,		MT32	},
+{"cttc1",   "t,S",	0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0,		MT32	},
+{"cttc2",   "t,g",	0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC,	0,		MT32	},
+{"cvt.d.l", "D,S",	0x46a00021, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"cvt.d.s", "D,S",	0x46000021, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.d.w", "D,S",	0x46800021, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.l.d", "D,S",	0x46200025, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"cvt.l.s", "D,S",	0x46000025, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"cvt.s.l", "D,S",	0x46a00020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"cvt.s.d", "D,S",	0x46200020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.s.w", "D,S",	0x46800020, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"cvt.s.pl","D,S",	0x46c00028, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I5|I33	},
+{"cvt.s.pu","D,S",	0x46c00020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I5|I33	},
+{"cvt.w.d", "D,S",	0x46200024, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.w.s", "D,S",	0x46000024, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"cvt.ps.pw", "D,S",	0x46800026, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		M3D	},
+{"cvt.ps.s","D,V,T",	0x46000026, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S|FP_D, 0,		I5|I33	},
+{"cvt.pw.ps", "D,S",	0x46c00024, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		M3D	},
+{"dabs",    "d,v",	0,    (int) M_DABS,	INSN_MACRO,		0,		I3	},
+{"dadd",    "d,v,t",	0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		I3	},
+{"dadd",    "t,r,I",	0,    (int) M_DADD_I,	INSN_MACRO,		0,		I3	},
+{"daddi",   "t,r,j",	0x60000000, 0xfc000000, WR_t|RD_s,		0,		I3	},
+{"daddiu",  "t,r,j",	0x64000000, 0xfc000000, WR_t|RD_s,		0,		I3	},
+{"daddu",   "d,v,t",	0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		I3	},
+{"daddu",   "t,r,I",	0,    (int) M_DADDU_I,	INSN_MACRO,		0,		I3	},
+{"dbreak",  "",		0x7000003f, 0xffffffff,	0,			0,		N5	},
+{"dclo",    "U,s",      0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 	0,		I64|N55 },
+{"dclz",    "U,s",      0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 	0,		I64|N55 },
+/* dctr and dctw are used on the r5000.  */
+{"dctr",    "o(b)",	0xbc050000, 0xfc1f0000, RD_b,			0,		I3	},
+{"dctw",    "o(b)",	0xbc090000, 0xfc1f0000, RD_b,			0,		I3	},
+{"deret",   "",         0x4200001f, 0xffffffff, 0, 			0,		I32|G2	},
+{"dext",    "t,r,I,+I",	0,    (int) M_DEXT,	INSN_MACRO,		0,		I65	},
+{"dext",    "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dextm",   "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dextu",   "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+/* For ddiv, see the comments about div.  */
+{"ddiv",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"ddiv",    "d,v,t",	0,    (int) M_DDIV_3,	INSN_MACRO,		0,		I3	},
+{"ddiv",    "d,v,I",	0,    (int) M_DDIV_3I,	INSN_MACRO,		0,		I3	},
+/* For ddivu, see the comments about div.  */
+{"ddivu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"ddivu",   "d,v,t",	0,    (int) M_DDIVU_3,	INSN_MACRO,		0,		I3	},
+{"ddivu",   "d,v,I",	0,    (int) M_DDIVU_3I,	INSN_MACRO,		0,		I3	},
+{"di",      "",		0x41606000, 0xffffffff,	WR_t|WR_C0,		0,		I33	},
+{"di",      "t",	0x41606000, 0xffe0ffff,	WR_t|WR_C0,		0,		I33	},
+{"dins",    "t,r,I,+I",	0,    (int) M_DINS,	INSN_MACRO,		0,		I65	},
+{"dins",    "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dinsm",   "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dinsu",   "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+/* The MIPS assembler treats the div opcode with two operands as
+   though the first operand appeared twice (the first operand is both
+   a source and a destination).  To get the div machine instruction,
+   you must use an explicit destination of $0.  */
+{"div",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"div",     "z,t",      0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"div",     "d,v,t",	0,    (int) M_DIV_3,	INSN_MACRO,		0,		I1	},
+{"div",     "d,v,I",	0,    (int) M_DIV_3I,	INSN_MACRO,		0,		I1	},
+{"div.d",   "D,V,T",	0x46200003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"div.s",   "D,V,T",	0x46000003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"div.ps",  "D,V,T",	0x46c00003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
+/* For divu, see the comments about div.  */
+{"divu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"divu",    "z,t",      0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"divu",    "d,v,t",	0,    (int) M_DIVU_3,	INSN_MACRO,		0,		I1	},
+{"divu",    "d,v,I",	0,    (int) M_DIVU_3I,	INSN_MACRO,		0,		I1	},
+{"dla",     "t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		0,		I3	},
+{"dlca",    "t,A(b)",	0,    (int) M_DLCA_AB,	INSN_MACRO,		0,		I3	},
+{"dli",     "t,j",      0x24000000, 0xffe00000, WR_t,			0,		I3	}, /* addiu */
+{"dli",	    "t,i",	0x34000000, 0xffe00000, WR_t,			0,		I3	}, /* ori */
+{"dli",     "t,I",	0,    (int) M_DLI,	INSN_MACRO,		0,		I3	},
+{"dmacc",   "d,s,t",	0x00000029, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchi", "d,s,t",	0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchis", "d,s,t",	0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchiu", "d,s,t",	0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchius", "d,s,t",	0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccs",  "d,s,t",	0x00000429, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccu",  "d,s,t",	0x00000069, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccus", "d,s,t",	0x00000469, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmadd16", "s,t",      0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO,       0,		N411    },
+{"dmfc0",   "t,G",	0x40200000, 0xffe007ff, LCD|WR_t|RD_C0,		0,		I3	},
+{"dmfc0",   "t,+D",     0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I64     },
+{"dmfc0",   "t,G,H",    0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I64     },
+{"dmt",     "",		0x41600bc1, 0xffffffff, TRAP,			0,		MT32	},
+{"dmt",     "t",	0x41600bc1, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"dmtc0",   "t,G",	0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC,	0,		I3	},
+{"dmtc0",   "t,+D",     0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I64     },
+{"dmtc0",   "t,G,H",    0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I64     },
+{"dmfc1",   "t,S",	0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D,	0,		I3	},
+{"dmfc1",   "t,G",      0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D,     0,		I3      },
+{"dmtc1",   "t,S",	0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D,	0,		I3	},
+{"dmtc1",   "t,G",      0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D,     0,		I3      },
+/* dmfc2 is at the bottom of the table.  */
+/* dmtc2 is at the bottom of the table.  */
+/* dmfc3 is at the bottom of the table.  */
+/* dmtc3 is at the bottom of the table.  */
+{"dmul",    "d,v,t",	0,    (int) M_DMUL,	INSN_MACRO,		0,		I3	},
+{"dmul",    "d,v,I",	0,    (int) M_DMUL_I,	INSN_MACRO,		0,		I3	},
+{"dmulo",   "d,v,t",	0,    (int) M_DMULO,	INSN_MACRO,		0,		I3	},
+{"dmulo",   "d,v,I",	0,    (int) M_DMULO_I,	INSN_MACRO,		0,		I3	},
+{"dmulou",  "d,v,t",	0,    (int) M_DMULOU,	INSN_MACRO,		0,		I3	},
+{"dmulou",  "d,v,I",	0,    (int) M_DMULOU_I,	INSN_MACRO,		0,		I3	},
+{"dmult",   "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3	},
+{"dmultu",  "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3	},
+{"dneg",    "d,w",	0x0000002e, 0xffe007ff,	WR_d|RD_t,		0,		I3	}, /* dsub 0 */
+{"dnegu",   "d,w",	0x0000002f, 0xffe007ff,	WR_d|RD_t,		0,		I3	}, /* dsubu 0*/
+{"drem",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"drem",    "d,v,t",	3,    (int) M_DREM_3,	INSN_MACRO,		0,		I3	},
+{"drem",    "d,v,I",	3,    (int) M_DREM_3I,	INSN_MACRO,		0,		I3	},
+{"dremu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"dremu",   "d,v,t",	3,    (int) M_DREMU_3,	INSN_MACRO,		0,		I3	},
+{"dremu",   "d,v,I",	3,    (int) M_DREMU_3I,	INSN_MACRO,		0,		I3	},
+{"dret",    "",		0x7000003e, 0xffffffff,	0,			0,		N5	},
+{"drol",    "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		0,		I3	},
+{"drol",    "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,w,<",	0x0020003a, 0xffe0003f,	WR_d|RD_t,		0,		N5|I65	},
+{"drorv",   "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		N5|I65	},
+{"dror32",  "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		0,		N5|I65	},
+{"drotl",   "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		0,		I65	},
+{"drotl",   "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		0,		I65	},
+{"drotr",   "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		0,		I65	},
+{"drotr",   "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		0,		I65	},
+{"drotrv",  "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		I65	},
+{"drotr32", "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		0,		I65	},
+{"dsbh",    "d,w",	0x7c0000a4, 0xffe007ff,	WR_d|RD_t,		0,		I65	},
+{"dshd",    "d,w",	0x7c000164, 0xffe007ff,	WR_d|RD_t,		0,		I65	},
+{"dsllv",   "d,t,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsll32",  "d,w,<",	0x0000003c, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsll",    "d,w,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsllv */
+{"dsll",    "d,w,>",	0x0000003c, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsll32 */
+{"dsll",    "d,w,<",	0x00000038, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsrav",   "d,t,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsra32",  "d,w,<",	0x0000003f, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsra",    "d,w,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsrav */
+{"dsra",    "d,w,>",	0x0000003f, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsra32 */
+{"dsra",    "d,w,<",	0x0000003b, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsrlv",   "d,t,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsrl32",  "d,w,<",	0x0000003e, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsrl",    "d,w,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsrlv */
+{"dsrl",    "d,w,>",	0x0000003e, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsrl32 */
+{"dsrl",    "d,w,<",	0x0000003a, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsub",    "d,v,t",	0x0000002e, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I3	},
+{"dsub",    "d,v,I",	0,    (int) M_DSUB_I,	INSN_MACRO,		0,		I3	},
+{"dsubu",   "d,v,t",	0x0000002f, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I3	},
+{"dsubu",   "d,v,I",	0,    (int) M_DSUBU_I,	INSN_MACRO,		0,		I3	},
+{"dvpe",    "",		0x41600001, 0xffffffff, TRAP,			0,		MT32	},
+{"dvpe",    "t",	0x41600001, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"ei",      "",		0x41606020, 0xffffffff,	WR_t|WR_C0,		0,		I33	},
+{"ei",      "t",	0x41606020, 0xffe0ffff,	WR_t|WR_C0,		0,		I33	},
+{"emt",     "",		0x41600be1, 0xffffffff, TRAP,			0,		MT32	},
+{"emt",     "t",	0x41600be1, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"eret",    "",         0x42000018, 0xffffffff, 0,      		0,		I3|I32	},
+{"evpe",    "",		0x41600021, 0xffffffff, TRAP,			0,		MT32	},
+{"evpe",    "t",	0x41600021, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"ext",     "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s,    		0,		I33	},
+{"floor.l.d", "D,S",	0x4620000b, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"floor.l.s", "D,S",	0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"floor.w.d", "D,S",	0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"floor.w.s", "D,S",	0x4600000f, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"hibernate","",        0x42000023, 0xffffffff,	0, 			0,		V1	},
+{"ins",     "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		0,		I33	},
+{"jr",      "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	},
+/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with
+   the same hazard barrier effect.  */
+{"jr.hb",   "s",	0x00000408, 0xfc1fffff,	UBD|RD_s,		0,		I32	},
+{"j",       "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	}, /* jr */
+/* SVR4 PIC code requires special handling for j, so it must be a
+   macro.  */
+{"j",	    "a",	0,     (int) M_J_A,	INSN_MACRO,		0,		I1	},
+/* This form of j is used by the disassembler and internally by the
+   assembler, but will never match user input (because the line above
+   will match first).  */
+{"j",       "a",	0x08000000, 0xfc000000,	UBD,			0,		I1	},
+{"jalr",    "s",	0x0000f809, 0xfc1fffff,	UBD|RD_s|WR_d,		0,		I1	},
+{"jalr",    "d,s",	0x00000009, 0xfc1f07ff,	UBD|RD_s|WR_d,		0,		I1	},
+/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr
+   with the same hazard barrier effect.  */
+{"jalr.hb", "s",	0x0000fc09, 0xfc1fffff,	UBD|RD_s|WR_d,		0,		I32	},
+{"jalr.hb", "d,s",	0x00000409, 0xfc1f07ff,	UBD|RD_s|WR_d,		0,		I32	},
+/* SVR4 PIC code requires special handling for jal, so it must be a
+   macro.  */
+{"jal",     "d,s",	0,     (int) M_JAL_2,	INSN_MACRO,		0,		I1	},
+{"jal",     "s",	0,     (int) M_JAL_1,	INSN_MACRO,		0,		I1	},
+{"jal",     "a",	0,     (int) M_JAL_A,	INSN_MACRO,		0,		I1	},
+/* This form of jal is used by the disassembler and internally by the
+   assembler, but will never match user input (because the line above
+   will match first).  */
+{"jal",     "a",	0x0c000000, 0xfc000000,	UBD|WR_31,		0,		I1	},
+{"jalx",    "a",	0x74000000, 0xfc000000, UBD|WR_31,		0,		I16     },
+{"la",      "t,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		0,		I1	},
+{"lb",      "t,o(b)",	0x80000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lb",      "t,A(b)",	0,    (int) M_LB_AB,	INSN_MACRO,		0,		I1	},
+{"lbu",     "t,o(b)",	0x90000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lbu",     "t,A(b)",	0,    (int) M_LBU_AB,	INSN_MACRO,		0,		I1	},
+{"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		0,		I1	},
+{"ld",	    "t,o(b)",   0xdc000000, 0xfc000000, WR_t|RD_b,		0,		I3	},
+{"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		0,		I1	},
+{"ld",      "t,A(b)",	0,    (int) M_LD_AB,	INSN_MACRO,		0,		I1	},
+{"ldc1",    "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	},
+{"ldc1",    "E,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	},
+{"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		0,		I2	},
+{"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		0,		I2	},
+{"l.d",     "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	}, /* ldc1 */
+{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		0,		I1	},
+{"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		0,		I1	},
+{"ldc2",    "E,o(b)",	0xd8000000, 0xfc000000, CLD|RD_b|WR_CC,		0,		I2	},
+{"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		0,		I2	},
+{"ldc3",    "E,o(b)",	0xdc000000, 0xfc000000, CLD|RD_b|WR_CC,		0,		I2	},
+{"ldc3",    "E,A(b)",	0,    (int) M_LDC3_AB,	INSN_MACRO,		0,		I2	},
+{"ldl",	    "t,o(b)",	0x68000000, 0xfc000000, LDD|WR_t|RD_b,		0,		I3	},
+{"ldl",	    "t,A(b)",	0,    (int) M_LDL_AB,	INSN_MACRO,		0,		I3	},
+{"ldr",	    "t,o(b)",	0x6c000000, 0xfc000000, LDD|WR_t|RD_b,		0,		I3	},
+{"ldr",     "t,A(b)",	0,    (int) M_LDR_AB,	INSN_MACRO,		0,		I3	},
+{"ldxc1",   "D,t(b)",	0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I4|I33	},
+{"lh",      "t,o(b)",	0x84000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lh",      "t,A(b)",	0,    (int) M_LH_AB,	INSN_MACRO,		0,		I1	},
+{"lhu",     "t,o(b)",	0x94000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lhu",     "t,A(b)",	0,    (int) M_LHU_AB,	INSN_MACRO,		0,		I1	},
+/* li is at the start of the table.  */
+{"li.d",    "t,F",	0,    (int) M_LI_D,	INSN_MACRO,		0,		I1	},
+{"li.d",    "T,L",	0,    (int) M_LI_DD,	INSN_MACRO,		0,		I1	},
+{"li.s",    "t,f",	0,    (int) M_LI_S,	INSN_MACRO,		0,		I1	},
+{"li.s",    "T,l",	0,    (int) M_LI_SS,	INSN_MACRO,		0,		I1	},
+{"ll",	    "t,o(b)",	0xc0000000, 0xfc000000, LDD|RD_b|WR_t,		0,		I2	},
+{"ll",	    "t,A(b)",	0,    (int) M_LL_AB,	INSN_MACRO,		0,		I2	},
+{"lld",	    "t,o(b)",	0xd0000000, 0xfc000000, LDD|RD_b|WR_t,		0,		I3	},
+{"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		0,		I3	},
+{"lui",     "t,u",	0x3c000000, 0xffe00000,	WR_t,			0,		I1	},
+{"luxc1",   "D,t(b)",	0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I5|I33|N55},
+{"lw",      "t,o(b)",	0x8c000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lw",      "t,A(b)",	0,    (int) M_LW_AB,	INSN_MACRO,		0,		I1	},
+{"lwc0",    "E,o(b)",	0xc0000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc0",    "E,A(b)",	0,    (int) M_LWC0_AB,	INSN_MACRO,		0,		I1	},
+{"lwc1",    "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	},
+{"lwc1",    "E,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	},
+{"lwc1",    "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"lwc1",    "E,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"l.s",     "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	}, /* lwc1 */
+{"l.s",     "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"lwc2",    "E,o(b)",	0xc8000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc2",    "E,A(b)",	0,    (int) M_LWC2_AB,	INSN_MACRO,		0,		I1	},
+{"lwc3",    "E,o(b)",	0xcc000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc3",    "E,A(b)",	0,    (int) M_LWC3_AB,	INSN_MACRO,		0,		I1	},
+{"lwl",     "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lwl",     "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I1	},
+{"lcache",  "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I2	}, /* same */
+{"lcache",  "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I2	}, /* as lwl */
+{"lwr",     "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lwr",     "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I1	},
+{"flush",   "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I2	}, /* same */
+{"flush",   "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I2	}, /* as lwr */
+{"fork",    "d,s,t",	0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t,	0,		MT32	},
+{"lwu",     "t,o(b)",	0x9c000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I3	},
+{"lwu",     "t,A(b)",	0,    (int) M_LWU_AB,	INSN_MACRO,		0,		I3	},
+{"lwxc1",   "D,t(b)",	0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I4|I33	},
+{"lwxs",    "d,t(b)",	0x70000088, 0xfc0007ff,	LDD|RD_b|RD_t|WR_d,	0,		SMT	},
+{"macc",    "d,s,t",	0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macc",    "d,s,t",	0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"maccs",   "d,s,t",	0x00000428, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchi",  "d,s,t",	0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchi",  "d,s,t",	0x00000358, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"macchis", "d,s,t",	0x00000628, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchiu", "d,s,t",	0x00000268, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchiu", "d,s,t",	0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"macchius","d,s,t",	0x00000668, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"maccu",   "d,s,t",	0x00000068, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"maccu",   "d,s,t",	0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"maccus",  "d,s,t",	0x00000468, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"mad",     "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		P3      },
+{"madu",    "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		P3      },
+{"madd.d",  "D,R,S,T",	0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    0,		I4|I33	},
+{"madd.s",  "D,R,S,T",	0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S,    0,		I4|I33	},
+{"madd.ps", "D,R,S,T",	0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    0,		I5|I33	},
+{"madd",    "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,           0,		L1	},
+{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          0,		I32|N55	},
+{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      0,		G1	},
+{"madd",    "7,s,t",	0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t,             0,         D33	},
+{"madd",    "d,s,t",    0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"maddp",   "s,t",      0x70000441, 0xfc00ffff,	RD_s|RD_t|MOD_HILO,	     0,		SMT	},
+{"maddu",   "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,           0,		L1	},
+{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          0,		I32|N55	},
+{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      0,		G1	},
+{"maddu",   "7,s,t",	0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t,             0,         D33	},
+{"maddu",   "d,s,t",    0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"madd16",  "s,t",      0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO,	0,		N411    },
+{"max.ob",  "X,Y,Q",	0x78000007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"max.ob",  "D,S,T",	0x4ac00007, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.ob",  "D,S,T[e]",	0x48000007, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.ob",  "D,S,k",	0x4bc00007, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.qh",  "X,Y,Q",	0x78200007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mfpc",    "t,P",	0x4000c801, 0xffe0ffc1,	LCD|WR_t|RD_C0,		0,		M1|N5	},
+{"mfps",    "t,P",	0x4000c800, 0xffe0ffc1,	LCD|WR_t|RD_C0,		0,		M1|N5	},
+{"mftacx",  "d",	0x41020021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftacx",  "d,*",	0x41020021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftc0",   "d,+t",	0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc0",   "d,+T",	0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc0",   "d,E,H",	0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc1",   "d,T",	0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0,		MT32	},
+{"mftc1",   "d,E",	0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0,		MT32	},
+{"mftc2",   "d,E",	0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"mftdsp",  "d",	0x41100021, 0xffff07ff, TRAP|WR_d,		0,		MT32	},
+{"mftgpr",  "d,t",	0x41000020, 0xffe007ff, TRAP|WR_d|RD_t,		0,		MT32	},
+{"mfthc1",  "d,T",	0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0,		MT32	},
+{"mfthc1",  "d,E",	0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0,		MT32	},
+{"mfthc2",  "d,E",	0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"mfthi",   "d",	0x41010021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mfthi",   "d,*",	0x41010021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftlo",   "d",	0x41000021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftlo",   "d,*",	0x41000021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftr",    "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d,		0,		MT32	},
+{"mfc0",    "t,G",	0x40000000, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		I1	},
+{"mfc0",    "t,+D",     0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I32     },
+{"mfc0",    "t,G,H",    0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I32     },
+{"mfc1",    "t,S",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	0,		I1	},
+{"mfc1",    "t,G",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	0,		I1	},
+{"mfhc1",   "t,S",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_D,	0,		I33	},
+{"mfhc1",   "t,G",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_D,	0,		I33	},
+/* mfc2 is at the bottom of the table.  */
+/* mfhc2 is at the bottom of the table.  */
+/* mfc3 is at the bottom of the table.  */
+{"mfdr",    "t,G",	0x7000003d, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		N5      },
+{"mfhi",    "d",	0x00000010, 0xffff07ff,	WR_d|RD_HI,		0,		I1	},
+{"mfhi",    "d,9",	0x00000010, 0xff9f07ff, WR_d|RD_HI,		0,		D32	},
+{"mflo",    "d",	0x00000012, 0xffff07ff,	WR_d|RD_LO,		0,		I1	},
+{"mflo",    "d,9",	0x00000012, 0xff9f07ff, WR_d|RD_LO,		0,		D32	},
+{"mflhxu",  "d",	0x00000052, 0xffff07ff,	WR_d|MOD_HILO,		0,		SMT	},
+{"min.ob",  "X,Y,Q",	0x78000006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"min.ob",  "D,S,T",	0x4ac00006, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.ob",  "D,S,T[e]",	0x48000006, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.ob",  "D,S,k",	0x4bc00006, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.qh",  "X,Y,Q",	0x78200006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mov.d",   "D,S",	0x46200006, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"mov.s",   "D,S",	0x46000006, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"mov.ps",  "D,S",	0x46c00006, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"movf",    "d,s,N",    0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0,		I4|I32  },
+{"movf.d",  "D,S,N",    0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		I4|I32	},
+{"movf.l",  "D,S,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		MX|SB1	},
+{"movf.l",  "X,Y,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		MX|SB1	},
+{"movf.s",  "D,S,N",    0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   0,		I4|I32	},
+{"movf.ps", "D,S,N",	0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		I5|I33	},
+{"movn",    "d,v,t",    0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 	0,		I4|I32	},
+{"ffc",     "d,v",	0x0000000b, 0xfc1f07ff,	WR_d|RD_s,		0,		L1	},
+{"movn.d",  "D,S,t",    0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I4|I32	},
+{"movn.l",  "D,S,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movn.l",  "X,Y,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movn.s",  "D,S,t",    0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    0,		I4|I32	},
+{"movn.ps", "D,S,t",    0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I5|I33	},
+{"movt",    "d,s,N",    0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0,		I4|I32	},
+{"movt.d",  "D,S,N",    0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		I4|I32	},
+{"movt.l",  "D,S,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		MX|SB1	},
+{"movt.l",  "X,Y,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		MX|SB1	},
+{"movt.s",  "D,S,N",    0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   0,		I4|I32	},
+{"movt.ps", "D,S,N",	0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		I5|I33	},
+{"movz",    "d,v,t",    0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 	0,		I4|I32	},
+{"ffs",     "d,v",	0x0000000a, 0xfc1f07ff,	WR_d|RD_s,		0,		L1	},
+{"movz.d",  "D,S,t",    0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I4|I32	},
+{"movz.l",  "D,S,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movz.l",  "X,Y,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movz.s",  "D,S,t",    0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    0,		I4|I32	},
+{"movz.ps", "D,S,t",    0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I5|I33	},
+{"msac",    "d,s,t",	0x000001d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msacu",   "d,s,t",	0x000001d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msachi",  "d,s,t",	0x000003d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msachiu", "d,s,t",	0x000003d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+/* move is at the top of the table.  */
+{"msgn.qh", "X,Y,Q",	0x78200000, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"msub.d",  "D,R,S,T",	0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"msub.s",  "D,R,S,T",	0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"msub.ps", "D,R,S,T",	0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
+{"msub",    "s,t",      0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,	0,		L1    	},
+{"msub",    "s,t",      0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		I32|N55 },
+{"msub",    "7,s,t",	0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"msubu",   "s,t",      0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,	0,		L1	},
+{"msubu",   "s,t",      0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		I32|N55	},
+{"msubu",   "7,s,t",	0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"mtpc",    "t,P",	0x4080c801, 0xffe0ffc1,	COD|RD_t|WR_C0,		0,		M1|N5	},
+{"mtps",    "t,P",	0x4080c800, 0xffe0ffc1,	COD|RD_t|WR_C0,		0,		M1|N5	},
+{"mtc0",    "t,G",	0x40800000, 0xffe007ff,	COD|RD_t|WR_C0|WR_CC,	0,		I1	},
+{"mtc0",    "t,+D",     0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I32     },
+{"mtc0",    "t,G,H",    0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I32     },
+{"mtc1",    "t,S",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	0,		I1	},
+{"mtc1",    "t,G",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	0,		I1	},
+{"mthc1",   "t,S",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_D,	0,		I33	},
+{"mthc1",   "t,G",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_D,	0,		I33	},
+/* mtc2 is at the bottom of the table.  */
+/* mthc2 is at the bottom of the table.  */
+/* mtc3 is at the bottom of the table.  */
+{"mtdr",    "t,G",	0x7080003d, 0xffe007ff,	COD|RD_t|WR_C0,		0,		N5	},
+{"mthi",    "s",	0x00000011, 0xfc1fffff,	RD_s|WR_HI,		0,		I1	},
+{"mthi",    "s,7",	0x00000011, 0xfc1fe7ff, RD_s|WR_HI,		0,		D32	},
+{"mtlo",    "s",	0x00000013, 0xfc1fffff,	RD_s|WR_LO,		0,		I1	},
+{"mtlo",    "s,7",	0x00000013, 0xfc1fe7ff, RD_s|WR_LO,		0,		D32	},
+{"mtlhx",   "s",	0x00000053, 0xfc1fffff,	RD_s|MOD_HILO,		0,		SMT	},
+{"mttc0",   "t,G",	0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc0",   "t,+D",	0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc0",   "t,G,H",	0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc1",   "t,S",	0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0,		MT32	},
+{"mttc1",   "t,G",	0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0,		MT32	},
+{"mttc2",   "t,g",	0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0,		MT32	},
+{"mttacx",  "t",	0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttacx",  "t,&",	0x41801021, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttdsp",  "t",	0x41808021, 0xffe0ffff, TRAP|RD_t,		0,		MT32	},
+{"mttgpr",  "t,d",	0x41800020, 0xffe007ff, TRAP|WR_d|RD_t,		0,		MT32	},
+{"mtthc1",  "t,S",	0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0,		MT32	},
+{"mtthc1",  "t,G",	0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0,		MT32	},
+{"mtthc2",  "t,g",	0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0,		MT32	},
+{"mtthi",   "t",	0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mtthi",   "t,&",	0x41800821, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttlo",   "t",	0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttlo",   "t,&",	0x41800021, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttr",    "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t,		0,		MT32	},
+{"mul.d",   "D,V,T",	0x46200002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"mul.s",   "D,V,T",	0x46000002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"mul.ob",  "X,Y,Q",	0x78000030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"mul.ob",  "D,S,T",	0x4ac00030, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ob",  "D,S,T[e]",	0x48000030, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ob",  "D,S,k",	0x4bc00030, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ps",  "D,V,T",	0x46c00002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"mul.qh",  "X,Y,Q",	0x78200030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mul",     "d,v,t",    0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		I32|P3|N55},
+{"mul",     "d,s,t",	0x00000058, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N54	},
+{"mul",     "d,v,t",	0,    (int) M_MUL,	INSN_MACRO,		0,		I1	},
+{"mul",     "d,v,I",	0,    (int) M_MUL_I,	INSN_MACRO,		0,		I1	},
+{"mula.ob", "Y,Q",	0x78000033, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"mula.ob", "S,T",	0x4ac00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.ob", "S,T[e]",	0x48000033, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.ob", "S,k",	0x4bc00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.qh", "Y,Q",	0x78200033, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulhi",   "d,s,t",	0x00000258, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulhiu",  "d,s,t",	0x00000259, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mull.ob", "Y,Q",	0x78000433, 0xfc2007ff,	RD_S|RD_T|FP_D, 	WR_MACC,	MX|SB1	},
+{"mull.ob", "S,T",	0x4ac00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.ob", "S,T[e]",	0x48000433, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.ob", "S,k",	0x4bc00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.qh", "Y,Q",	0x78200433, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulo",    "d,v,t",	0,    (int) M_MULO,	INSN_MACRO,		0,		I1	},
+{"mulo",    "d,v,I",	0,    (int) M_MULO_I,	INSN_MACRO,		0,		I1	},
+{"mulou",   "d,v,t",	0,    (int) M_MULOU,	INSN_MACRO,		0,		I1	},
+{"mulou",   "d,v,I",	0,    (int) M_MULOU_I,	INSN_MACRO,		0,		I1	},
+{"mulr.ps", "D,S,T",	0x46c0001a, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"muls",    "d,s,t",	0x000000d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulsu",   "d,s,t",	0x000000d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulshi",  "d,s,t",	0x000002d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulshiu", "d,s,t",	0x000002d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"muls.ob", "Y,Q",	0x78000032, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"muls.ob", "S,T",	0x4ac00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.ob", "S,T[e]",	0x48000032, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.ob", "S,k",	0x4bc00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.qh", "Y,Q",	0x78200032, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulsl.ob", "Y,Q",	0x78000432, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"mulsl.ob", "S,T",	0x4ac00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.ob", "S,T[e]",	0x48000432, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.ob", "S,k",	0x4bc00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.qh", "Y,Q",	0x78200432, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mult",    "s,t",      0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0,		I1	},
+{"mult",    "7,s,t",	0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t,         0,              D33	},
+{"mult",    "d,s,t",    0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"multp",   "s,t",	0x00000459, 0xfc00ffff,	RD_s|RD_t|MOD_HILO,	0,		SMT	},
+{"multu",   "s,t",      0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0,		I1	},
+{"multu",   "7,s,t",	0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t,         0,              D33	},
+{"multu",   "d,s,t",    0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"mulu",    "d,s,t",	0x00000059, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"neg",     "d,w",	0x00000022, 0xffe007ff,	WR_d|RD_t,		0,		I1	}, /* sub 0 */
+{"negu",    "d,w",	0x00000023, 0xffe007ff,	WR_d|RD_t,		0,		I1	}, /* subu 0 */
+{"neg.d",   "D,V",	0x46200007, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"neg.s",   "D,V",	0x46000007, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"neg.ps",  "D,V",	0x46c00007, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"nmadd.d", "D,R,S,T",	0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"nmadd.s", "D,R,S,T",	0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"nmadd.ps","D,R,S,T",	0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
+{"nmsub.d", "D,R,S,T",	0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"nmsub.s", "D,R,S,T",	0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"nmsub.ps","D,R,S,T",	0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
+/* nop is at the start of the table.  */
+{"nor",     "d,v,t",	0x00000027, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"nor",     "t,r,I",	0,    (int) M_NOR_I,	INSN_MACRO,		0,		I1	},
+{"nor.ob",  "X,Y,Q",	0x7800000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"nor.ob",  "D,S,T",	0x4ac0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.ob",  "D,S,T[e]",	0x4800000f, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.ob",  "D,S,k",	0x4bc0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.qh",  "X,Y,Q",	0x7820000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"not",     "d,v",	0x00000027, 0xfc1f07ff,	WR_d|RD_s|RD_t,		0,		I1	},/*nor d,s,0*/
+{"or",      "d,v,t",	0x00000025, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"or",      "t,r,I",	0,    (int) M_OR_I,	INSN_MACRO,		0,		I1	},
+{"or.ob",   "X,Y,Q",	0x7800000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"or.ob",   "D,S,T",	0x4ac0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.ob",   "D,S,T[e]",	0x4800000e, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.ob",   "D,S,k",	0x4bc0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.qh",   "X,Y,Q",	0x7820000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"ori",     "t,r,i",	0x34000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
+{"pabsdiffc.ob", "Y,Q",	0x78000035, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	SB1	},
+{"pavg.ob", "X,Y,Q",	0x78000008, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
+{"pickf.ob", "X,Y,Q",	0x78000002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"pickf.ob", "D,S,T",	0x4ac00002, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.ob", "D,S,k",	0x4bc00002, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.qh", "X,Y,Q",	0x78200002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"pickt.ob", "X,Y,Q",	0x78000003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"pickt.ob", "D,S,T",	0x4ac00003, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.ob", "D,S,k",	0x4bc00003, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.qh", "X,Y,Q",	0x78200003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"pll.ps",  "D,V,T",	0x46c0002c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"plu.ps",  "D,V,T",	0x46c0002d, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+  /* pref and prefx are at the start of the table.  */
+{"pul.ps",  "D,V,T",	0x46c0002e, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"puu.ps",  "D,V,T",	0x46c0002f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"pperm",   "s,t",	0x70000481, 0xfc00ffff,	MOD_HILO|RD_s|RD_t,	0,		SMT	},
+{"rach.ob", "X",	0x7a00003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"rach.ob", "D",	0x4a00003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"rach.qh", "X",	0x7a20003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"racl.ob", "X",	0x7800003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"racl.ob", "D",	0x4800003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"racl.qh", "X",	0x7820003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"racm.ob", "X",	0x7900003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"racm.ob", "D",	0x4900003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"racm.qh", "X",	0x7920003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"recip.d", "D,S",	0x46200015, 0xffff003f, WR_D|RD_S|FP_D,		0,		I4|I33	},
+{"recip.ps","D,S",	0x46c00015, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"recip.s", "D,S",	0x46000015, 0xffff003f, WR_D|RD_S|FP_S,		0,		I4|I33	},
+{"recip1.d",  "D,S",	0x4620001d, 0xffff003f,	WR_D|RD_S|FP_D,		0,		M3D	},
+{"recip1.ps", "D,S",	0x46c0001d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"recip1.s",  "D,S",	0x4600001d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"recip2.d",  "D,S,T",	0x4620001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"recip2.ps", "D,S,T",	0x46c0001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"recip2.s",  "D,S,T",	0x4600001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rem",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1	},
+{"rem",     "d,v,t",	0,    (int) M_REM_3,	INSN_MACRO,		0,		I1	},
+{"rem",     "d,v,I",	0,    (int) M_REM_3I,	INSN_MACRO,		0,		I1	},
+{"remu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1	},
+{"remu",    "d,v,t",	0,    (int) M_REMU_3,	INSN_MACRO,		0,		I1	},
+{"remu",    "d,v,I",	0,    (int) M_REMU_3I,	INSN_MACRO,		0,		I1	},
+{"rdhwr",   "t,K",	0x7c00003b, 0xffe007ff, WR_t,			0,		I33	},
+{"rdpgpr",  "d,w",	0x41400000, 0xffe007ff, WR_d,			0,		I33	},
+{"rfe",     "",		0x42000010, 0xffffffff,	0,			0,		I1|T3	},
+{"rnas.qh", "X,Q",	0x78200025, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rnau.ob", "X,Q",	0x78000021, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rnau.qh", "X,Q",	0x78200021, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rnes.qh", "X,Q",	0x78200026, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rneu.ob", "X,Q",	0x78000022, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rneu.qh", "X,Q",	0x78200022, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rol",     "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		0,		I1	},
+{"rol",     "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		0,		I1	},
+{"ror",     "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		0,		I1	},
+{"ror",     "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		0,		I1	},
+{"ror",	    "d,w,<",	0x00200002, 0xffe0003f,	WR_d|RD_t,		0,		N5|I33|SMT },
+{"rorv",    "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		N5|I33|SMT },
+{"rotl",    "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		0,		I33|SMT	},
+{"rotl",    "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		0,		I33|SMT	},
+{"rotr",    "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		0,		I33|SMT	},
+{"rotr",    "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		0,		I33|SMT	},
+{"rotrv",   "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		I33|SMT	},
+{"round.l.d", "D,S",	0x46200008, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"round.l.s", "D,S",	0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"round.w.d", "D,S",	0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"round.w.s", "D,S",	0x4600000c, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"rsqrt.d", "D,S",	0x46200016, 0xffff003f, WR_D|RD_S|FP_D,		0,		I4|I33	},
+{"rsqrt.ps","D,S",	0x46c00016, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"rsqrt.s", "D,S",	0x46000016, 0xffff003f, WR_D|RD_S|FP_S,		0,		I4|I33	},
+{"rsqrt1.d",  "D,S",	0x4620001e, 0xffff003f,	WR_D|RD_S|FP_D,		0,		M3D	},
+{"rsqrt1.ps", "D,S",	0x46c0001e, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"rsqrt1.s",  "D,S",	0x4600001e, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"rsqrt2.d",  "D,S,T",	0x4620001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"rsqrt2.ps", "D,S,T",	0x46c0001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rsqrt2.s",  "D,S,T",	0x4600001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rzs.qh",  "X,Q",	0x78200024, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rzu.ob",  "X,Q",	0x78000020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rzu.ob",  "D,k",	0x4bc00020, 0xffe0f83f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"rzu.qh",  "X,Q",	0x78200020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"sb",      "t,o(b)",	0xa0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sb",      "t,A(b)",	0,    (int) M_SB_AB,	INSN_MACRO,		0,		I1	},
+{"sc",	    "t,o(b)",	0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	0,		I2	},
+{"sc",	    "t,A(b)",	0,    (int) M_SC_AB,	INSN_MACRO,		0,		I2	},
+{"scd",	    "t,o(b)",	0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	0,		I3	},
+{"scd",	    "t,A(b)",	0,    (int) M_SCD_AB,	INSN_MACRO,		0,		I3	},
+{"sd",	    "t,o(b)",	0xfc000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sd",      "t,o(b)",	0,    (int) M_SD_OB,	INSN_MACRO,		0,		I1	},
+{"sd",      "t,A(b)",	0,    (int) M_SD_AB,	INSN_MACRO,		0,		I1	},
+{"sdbbp",   "",		0x0000000e, 0xffffffff,	TRAP,           	0,		G2	},
+{"sdbbp",   "c",	0x0000000e, 0xfc00ffff,	TRAP,			0,		G2	},
+{"sdbbp",   "c,q",	0x0000000e, 0xfc00003f,	TRAP,			0,		G2	},
+{"sdbbp",   "",         0x7000003f, 0xffffffff, TRAP,           	0,		I32     },
+{"sdbbp",   "B",        0x7000003f, 0xfc00003f, TRAP,           	0,		I32     },
+{"sdc1",    "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"sdc1",    "E,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"sdc1",    "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		0,		I2	},
+{"sdc1",    "E,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		0,		I2	},
+{"sdc2",    "E,o(b)",	0xf8000000, 0xfc000000, SM|RD_C2|RD_b,		0,		I2	},
+{"sdc2",    "E,A(b)",	0,    (int) M_SDC2_AB,	INSN_MACRO,		0,		I2	},
+{"sdc3",    "E,o(b)",	0xfc000000, 0xfc000000, SM|RD_C3|RD_b,		0,		I2	},
+{"sdc3",    "E,A(b)",	0,    (int) M_SDC3_AB,	INSN_MACRO,		0,		I2	},
+{"s.d",     "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		0,		I1	},
+{"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		0,		I1	},
+{"sdl",     "t,o(b)",	0xb0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		0,		I3	},
+{"sdr",     "t,o(b)",	0xb4000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sdr",     "t,A(b)",	0,    (int) M_SDR_AB,	INSN_MACRO,		0,		I3	},
+{"sdxc1",   "S,t(b)",   0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D,	0,		I4|I33	},
+{"seb",     "d,w",	0x7c000420, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"seh",     "d,w",	0x7c000620, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"selsl",   "d,v,t",	0x00000005, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		L1	},
+{"selsr",   "d,v,t",	0x00000001, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		L1	},
+{"seq",     "d,v,t",	0,    (int) M_SEQ,	INSN_MACRO,		0,		I1	},
+{"seq",     "d,v,I",	0,    (int) M_SEQ_I,	INSN_MACRO,		0,		I1	},
+{"sge",     "d,v,t",	0,    (int) M_SGE,	INSN_MACRO,		0,		I1	},
+{"sge",     "d,v,I",	0,    (int) M_SGE_I,	INSN_MACRO,		0,		I1	},
+{"sgeu",    "d,v,t",	0,    (int) M_SGEU,	INSN_MACRO,		0,		I1	},
+{"sgeu",    "d,v,I",	0,    (int) M_SGEU_I,	INSN_MACRO,		0,		I1	},
+{"sgt",     "d,v,t",	0,    (int) M_SGT,	INSN_MACRO,		0,		I1	},
+{"sgt",     "d,v,I",	0,    (int) M_SGT_I,	INSN_MACRO,		0,		I1	},
+{"sgtu",    "d,v,t",	0,    (int) M_SGTU,	INSN_MACRO,		0,		I1	},
+{"sgtu",    "d,v,I",	0,    (int) M_SGTU_I,	INSN_MACRO,		0,		I1	},
+{"sh",      "t,o(b)",	0xa4000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sh",      "t,A(b)",	0,    (int) M_SH_AB,	INSN_MACRO,		0,		I1	},
+{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sle",     "d,v,t",	0,    (int) M_SLE,	INSN_MACRO,		0,		I1	},
+{"sle",     "d,v,I",	0,    (int) M_SLE_I,	INSN_MACRO,		0,		I1	},
+{"sleu",    "d,v,t",	0,    (int) M_SLEU,	INSN_MACRO,		0,		I1	},
+{"sleu",    "d,v,I",	0,    (int) M_SLEU_I,	INSN_MACRO,		0,		I1	},
+{"sllv",    "d,t,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"sll",     "d,w,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* sllv */
+{"sll",     "d,w,<",	0x00000000, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"sll.ob",  "X,Y,Q",	0x78000010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sll.ob",  "D,S,T[e]",	0x48000010, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sll.ob",  "D,S,k",	0x4bc00010, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sll.qh",  "X,Y,Q",	0x78200010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"slt",     "d,v,t",	0x0000002a, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"slt",     "d,v,I",	0,    (int) M_SLT_I,	INSN_MACRO,		0,		I1	},
+{"slti",    "t,r,j",	0x28000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"sltiu",   "t,r,j",	0x2c000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"sltu",    "d,v,t",	0x0000002b, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"sltu",    "d,v,I",	0,    (int) M_SLTU_I,	INSN_MACRO,		0,		I1	},
+{"sne",     "d,v,t",	0,    (int) M_SNE,	INSN_MACRO,		0,		I1	},
+{"sne",     "d,v,I",	0,    (int) M_SNE_I,	INSN_MACRO,		0,		I1	},
+{"sqrt.d",  "D,S",	0x46200004, 0xffff003f, WR_D|RD_S|FP_D,		0,		I2	},
+{"sqrt.s",  "D,S",	0x46000004, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"sqrt.ps", "D,S",	0x46c00004, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"srav",    "d,t,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"sra",     "d,w,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* srav */
+{"sra",     "d,w,<",	0x00000003, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"sra.qh",  "X,Y,Q",	0x78200013, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"srlv",    "d,t,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"srl",     "d,w,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* srlv */
+{"srl",     "d,w,<",	0x00000002, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"srl.ob",  "X,Y,Q",	0x78000012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"srl.ob",  "D,S,T[e]",	0x48000012, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"srl.ob",  "D,S,k",	0x4bc00012, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"srl.qh",  "X,Y,Q",	0x78200012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+/* ssnop is at the start of the table.  */
+{"standby", "",         0x42000021, 0xffffffff,	0,			0,		V1	},
+{"sub",     "d,v,t",	0x00000022, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"sub",     "d,v,I",	0,    (int) M_SUB_I,	INSN_MACRO,		0,		I1	},
+{"sub.d",   "D,V,T",	0x46200001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"sub.s",   "D,V,T",	0x46000001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"sub.ob",  "X,Y,Q",	0x7800000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sub.ob",  "D,S,T",	0x4ac0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ob",  "D,S,T[e]",	0x4800000a, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ob",  "D,S,k",	0x4bc0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ps",  "D,V,T",	0x46c00001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"sub.qh",  "X,Y,Q",	0x7820000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"suba.ob", "Y,Q",	0x78000036, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"suba.qh", "Y,Q",	0x78200036, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"subl.ob", "Y,Q",	0x78000436, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"subl.qh", "Y,Q",	0x78200436, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"subu",    "d,v,t",	0x00000023, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"subu",    "d,v,I",	0,    (int) M_SUBU_I,	INSN_MACRO,		0,		I1	},
+{"suspend", "",         0x42000022, 0xffffffff,	0,			0,		V1	},
+{"suxc1",   "S,t(b)",   0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	0,		I5|I33|N55},
+{"sw",      "t,o(b)",	0xac000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sw",      "t,A(b)",	0,    (int) M_SW_AB,	INSN_MACRO,		0,		I1	},
+{"swc0",    "E,o(b)",	0xe0000000, 0xfc000000,	SM|RD_C0|RD_b,		0,		I1	},
+{"swc0",    "E,A(b)",	0,    (int) M_SWC0_AB,	INSN_MACRO,		0,		I1	},
+{"swc1",    "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	},
+{"swc1",    "E,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	},
+{"swc1",    "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"swc1",    "E,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"s.s",     "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	}, /* swc1 */
+{"s.s",     "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"swc2",    "E,o(b)",	0xe8000000, 0xfc000000,	SM|RD_C2|RD_b,		0,		I1	},
+{"swc2",    "E,A(b)",	0,    (int) M_SWC2_AB,	INSN_MACRO,		0,		I1	},
+{"swc3",    "E,o(b)",	0xec000000, 0xfc000000,	SM|RD_C3|RD_b,		0,		I1	},
+{"swc3",    "E,A(b)",	0,    (int) M_SWC3_AB,	INSN_MACRO,		0,		I1	},
+{"swl",     "t,o(b)",	0xa8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"swl",     "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I1	},
+{"scache",  "t,o(b)",	0xa8000000, 0xfc000000,	RD_t|RD_b,		0,		I2	}, /* same */
+{"scache",  "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I2	}, /* as swl */
+{"swr",     "t,o(b)",	0xb8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"swr",     "t,A(b)",	0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I1	},
+{"invalidate", "t,o(b)",0xb8000000, 0xfc000000,	RD_t|RD_b,		0,		I2	}, /* same */
+{"invalidate", "t,A(b)",0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I2	}, /* as swr */
+{"swxc1",   "S,t(b)",   0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S,	0,		I4|I33	},
+{"sync",    "",		0x0000000f, 0xffffffff,	INSN_SYNC,		0,		I2|G1	},
+{"sync.p",  "",		0x0000040f, 0xffffffff,	INSN_SYNC,		0,		I2	},
+{"sync.l",  "",		0x0000000f, 0xffffffff,	INSN_SYNC,		0,		I2	},
+{"synci",   "o(b)",	0x041f0000, 0xfc1f0000,	SM|RD_b,		0,		I33	},
+{"syscall", "",		0x0000000c, 0xffffffff,	TRAP,			0,		I1	},
+{"syscall", "B",	0x0000000c, 0xfc00003f,	TRAP,			0,		I1	},
+{"teqi",    "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"teq",	    "s,t",	0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"teq",	    "s,t,q",	0x00000034, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"teq",     "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* teqi */
+{"teq",     "s,I",	0,    (int) M_TEQ_I,	INSN_MACRO,		0,		I2	},
+{"tgei",    "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tge",	    "s,t",	0x00000030, 0xfc00ffff,	RD_s|RD_t|TRAP,		0,		I2	},
+{"tge",	    "s,t,q",	0x00000030, 0xfc00003f,	RD_s|RD_t|TRAP,		0,		I2	},
+{"tge",     "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tgei */
+{"tge",	    "s,I",	0,    (int) M_TGE_I,    INSN_MACRO,		0,		I2	},
+{"tgeiu",   "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tgeu",    "s,t",	0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tgeu",    "s,t,q",	0x00000031, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tgeu",    "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tgeiu */
+{"tgeu",    "s,I",	0,    (int) M_TGEU_I,	INSN_MACRO,		0,		I2	},
+{"tlbp",    "",         0x42000008, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbr",    "",         0x42000001, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbwi",   "",         0x42000002, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbwr",   "",         0x42000006, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlti",    "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		0,		I2	},
+{"tlt",     "s,t",	0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tlt",     "s,t,q",	0x00000032, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tlt",     "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		0,		I2	}, /* tlti */
+{"tlt",     "s,I",	0,    (int) M_TLT_I,	INSN_MACRO,		0,		I2	},
+{"tltiu",   "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tltu",    "s,t",	0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tltu",    "s,t,q",	0x00000033, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tltu",    "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tltiu */
+{"tltu",    "s,I",	0,    (int) M_TLTU_I,	INSN_MACRO,		0,		I2	},
+{"tnei",    "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tne",     "s,t",	0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tne",     "s,t,q",	0x00000036, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tne",     "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tnei */
+{"tne",     "s,I",	0,    (int) M_TNE_I,	INSN_MACRO,		0,		I2	},
+{"trunc.l.d", "D,S",	0x46200009, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"trunc.l.s", "D,S",	0x46000009, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"trunc.w.d", "D,S",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"trunc.w.d", "D,S,x",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"trunc.w.d", "D,S,t",	0,    (int) M_TRUNCWD,	INSN_MACRO,		0,		I1	},
+{"trunc.w.s", "D,S",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2	},
+{"trunc.w.s", "D,S,x",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2	},
+{"trunc.w.s", "D,S,t",	0,    (int) M_TRUNCWS,	INSN_MACRO,		0,		I1	},
+{"uld",     "t,o(b)",	0,    (int) M_ULD,	INSN_MACRO,		0,		I3	},
+{"uld",     "t,A(b)",	0,    (int) M_ULD_A,	INSN_MACRO,		0,		I3	},
+{"ulh",     "t,o(b)",	0,    (int) M_ULH,	INSN_MACRO,		0,		I1	},
+{"ulh",     "t,A(b)",	0,    (int) M_ULH_A,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,o(b)",	0,    (int) M_ULHU,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_A,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,o(b)",	0,    (int) M_ULW,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,A(b)",	0,    (int) M_ULW_A,	INSN_MACRO,		0,		I1	},
+{"usd",     "t,o(b)",	0,    (int) M_USD,	INSN_MACRO,		0,		I3	},
+{"usd",     "t,A(b)",	0,    (int) M_USD_A,	INSN_MACRO,		0,		I3	},
+{"ush",     "t,o(b)",	0,    (int) M_USH,	INSN_MACRO,		0,		I1	},
+{"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		0,		I1	},
+{"wach.ob", "Y",	0x7a00003e, 0xffff07ff,	RD_S|FP_D,		WR_MACC,	MX|SB1	},
+{"wach.ob", "S",	0x4a00003e, 0xffff07ff,	RD_S,			0,		N54	},
+{"wach.qh", "Y",	0x7a20003e, 0xffff07ff,	RD_S|FP_D,		WR_MACC,	MX	},
+{"wacl.ob", "Y,Z",	0x7800003e, 0xffe007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"wacl.ob", "S,T",	0x4800003e, 0xffe007ff,	RD_S|RD_T,		0,		N54	},
+{"wacl.qh", "Y,Z",	0x7820003e, 0xffe007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"wait",    "",         0x42000020, 0xffffffff, TRAP,   		0,		I3|I32	},
+{"wait",    "J",        0x42000020, 0xfe00003f, TRAP,   		0,		I32|N55	},
+{"waiti",   "",		0x42000020, 0xffffffff,	TRAP,			0,		L1	},
+{"wrpgpr",  "d,w",	0x41c00000, 0xffe007ff, RD_t,			0,		I33	},
+{"wsbh",    "d,w",	0x7c0000a0, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"xor",     "d,v,t",	0x00000026, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"xor",     "t,r,I",	0,    (int) M_XOR_I,	INSN_MACRO,		0,		I1	},
+{"xor.ob",  "X,Y,Q",	0x7800000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"xor.ob",  "D,S,T",	0x4ac0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.ob",  "D,S,T[e]",	0x4800000d, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.ob",  "D,S,k",	0x4bc0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.qh",  "X,Y,Q",	0x7820000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"xori",    "t,r,i",	0x38000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"yield",   "s",	0x7c000009, 0xfc1fffff, TRAP|RD_s,		0,		MT32	},
+{"yield",   "d,s",	0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s,		0,		MT32	},
+
+/* User Defined Instruction.  */
+{"udi0",     "s,t,d,+1",0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "s,t,+2",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "s,+3",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "+4",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,t,d,+1",0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,t,+2",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,+3",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "+4",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,t,d,+1",0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,t,+2",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,+3",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "+4",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,t,d,+1",0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,t,+2",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,+3",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "+4",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,t,d,+1",0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,t,+2",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,+3",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "+4",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,t,d,+1",0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,t,+2",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,+3",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "+4",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,t,d,+1",0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,t,+2",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,+3",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "+4",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,t,d,+1",0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,t,+2",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,+3",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "+4",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,t,d,+1",0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,t,+2",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,+3",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "+4",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "s,t,d,+1",0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",      "s,t,+2",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "s,+3",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "+4",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,t,d,+1",0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,t,+2",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,+3",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "+4",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,t,d,+1",0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,t,+2",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,+3",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "+4",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,t,d,+1",0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,t,+2",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,+3",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "+4",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,t,d,+1",0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,t,+2",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,+3",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "+4",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,t,d,+1",0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,t,+2",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,+3",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "+4",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,t,d,+1",0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,t,+2",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,+3",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "+4",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+
+/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format
+   instructions so they are here for the latters to take precedence.  */
+{"bc2f",    "p",	0x49000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc2f",    "N,p",	0x49000000, 0xffe30000,	CBD|RD_CC,		0,		I32	},
+{"bc2fl",   "p",	0x49020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc2fl",   "N,p",	0x49020000, 0xffe30000,	CBL|RD_CC,		0,		I32	},
+{"bc2t",    "p",	0x49010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc2t",    "N,p",	0x49010000, 0xffe30000,	CBD|RD_CC,		0,		I32	},
+{"bc2tl",   "p",	0x49030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc2tl",   "N,p",	0x49030000, 0xffe30000,	CBL|RD_CC,		0,		I32	},
+{"cfc2",    "t,G",	0x48400000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I1	},
+{"ctc2",    "t,G",	0x48c00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"dmfc2",   "t,G",	0x48200000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I3	},
+{"dmfc2",   "t,G,H",	0x48200000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I64	},
+{"dmtc2",   "t,G",	0x48a00000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I3	},
+{"dmtc2",   "t,G,H",	0x48a00000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I64	},
+{"mfc2",    "t,G",	0x48000000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I1	},
+{"mfc2",    "t,G,H",	0x48000000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I32	},
+{"mfhc2",   "t,G",	0x48600000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mfhc2",   "t,G,H",	0x48600000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mfhc2",   "t,i",	0x48600000, 0xffe00000,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mtc2",    "t,G",	0x48800000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I1	},
+{"mtc2",    "t,G,H",	0x48800000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I32	},
+{"mthc2",   "t,G",	0x48e00000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+{"mthc2",   "t,G,H",	0x48e00000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+{"mthc2",   "t,i",	0x48e00000, 0xffe00000,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+
+/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X
+   instructions, so they are here for the latters to take precedence.  */
+{"bc3f",    "p",	0x4d000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc3fl",   "p",	0x4d020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc3t",    "p",	0x4d010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc3tl",   "p",	0x4d030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"cfc3",    "t,G",	0x4c400000, 0xffe007ff,	LCD|WR_t|RD_C3,		0,		I1	},
+{"ctc3",    "t,G",	0x4cc00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"dmfc3",   "t,G",	0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 	0,		I3	},
+{"dmtc3",   "t,G",	0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC,	0,		I3	},
+{"mfc3",    "t,G",	0x4c000000, 0xffe007ff,	LCD|WR_t|RD_C3,		0,		I1	},
+{"mfc3",    "t,G,H",    0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 	0,		I32     },
+{"mtc3",    "t,G",	0x4c800000, 0xffe007ff,	COD|RD_t|WR_C3|WR_CC,	0,		I1	},
+{"mtc3",    "t,G,H",    0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC,   0,		I32     },
+
+/* No hazard protection on coprocessor instructions--they shouldn't
+   change the state of the processor and if they do it's up to the
+   user to put in nops as necessary.  These are at the end so that the
+   disassembler recognizes more specific versions first.  */
+{"c0",      "C",	0x42000000, 0xfe000000,	0,			0,		I1	},
+{"c1",      "C",	0x46000000, 0xfe000000,	0,			0,		I1	},
+{"c2",      "C",	0x4a000000, 0xfe000000,	0,			0,		I1	},
+{"c3",      "C",	0x4e000000, 0xfe000000,	0,			0,		I1	},
+{"cop0",     "C",	0,    (int) M_COP0,	INSN_MACRO,		0,		I1	},
+{"cop1",     "C",	0,    (int) M_COP1,	INSN_MACRO,		0,		I1	},
+{"cop2",     "C",	0,    (int) M_COP2,	INSN_MACRO,		0,		I1	},
+{"cop3",     "C",	0,    (int) M_COP3,	INSN_MACRO,		0,		I1	},
+  /* Conflicts with the 4650's "mul" instruction.  Nobody's using the
+     4010 any more, so move this insn out of the way.  If the object
+     format gave us more info, we could do this right.  */
+{"addciu",  "t,r,j",	0x70000000, 0xfc000000,	WR_t|RD_s,		0,		L1	},
+/* MIPS DSP ASE */
+{"absq_s.ph", "d,t",	0x7c000252, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"absq_s.pw", "d,t",	0x7c000456, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"absq_s.qh", "d,t",	0x7c000256, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"absq_s.w", "d,t",	0x7c000452, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"addq.ph", "d,s,t",	0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addq.pw", "d,s,t",	0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq.qh", "d,s,t",	0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.ph", "d,s,t",	0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addq_s.pw", "d,s,t",	0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.qh", "d,s,t",	0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.w", "d,s,t",	0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addsc",   "d,s,t",	0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addu.ob", "d,s,t",	0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addu.qb", "d,s,t",	0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addu_s.ob", "d,s,t",	0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addu_s.qb", "d,s,t",	0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addwc",   "d,s,t",	0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"bitrev",  "d,t",	0x7c0006d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"bposge32", "p",	0x041c0000, 0xffff0000, CBD,			0,		D32	},
+{"bposge64", "p",	0x041d0000, 0xffff0000, CBD,			0,		D64	},
+{"cmp.eq.ph", "s,t",	0x7c000211, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.eq.pw", "s,t",	0x7c000415, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.eq.qh", "s,t",	0x7c000215, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmp.le.ph", "s,t",	0x7c000291, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.le.pw", "s,t",	0x7c000495, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.le.qh", "s,t",	0x7c000295, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.lt.ph", "s,t",	0x7c000251, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.lt.pw", "s,t",	0x7c000455, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.lt.qh", "s,t",	0x7c000255, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.eq.ob", "s,t",	0x7c000015, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.eq.qb", "s,t",	0x7c000011, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmpu.le.ob", "s,t",	0x7c000095, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.le.qb", "s,t",	0x7c000091, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmpu.lt.ob", "s,t",	0x7c000055, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.lt.qb", "s,t",	0x7c000051, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"dextpdp", "t,7,6",	0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA,	0,		D64	},
+{"dextpdpv", "t,7,s",	0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0,		D64	},
+{"dextp",   "t,7,6",	0x7c0000bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextpv",  "t,7,s",	0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextr.l", "t,7,6",	0x7c00043c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_r.l", "t,7,6",	0x7c00053c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_rs.l", "t,7,6",	0x7c0005bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_rs.w", "t,7,6",	0x7c0001bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_r.w", "t,7,6",	0x7c00013c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_s.h", "t,7,6",	0x7c0003bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextrv.l", "t,7,s",	0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_r.l", "t,7,s",	0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s,	0,		D64	},
+{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s,	0,		D64	},
+{"dextrv_r.w", "t,7,s",	0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_s.h", "t,7,s",	0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv.w", "t,7,s",	0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextr.w", "t,7,6",	0x7c00003c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dinsv",   "t,s",	0x7c00000d, 0xfc00ffff, WR_t|RD_s,		0,		D64	},
+{"dmadd",   "7,s,t",	0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmaddu",  "7,s,t",	0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmsub",   "7,s,t",	0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmsubu",  "7,s,t",	0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmthlip", "s,7",	0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA,	0,		D64	},
+{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.obl", "7,s,t",	0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.obr", "7,s,t",	0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.qbl", "7,s,t",	0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpau.h.qbr", "7,s,t",	0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.obl", "7,s,t",	0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.obr", "7,s,t",	0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.qbl", "7,s,t",	0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsu.h.qbr", "7,s,t",	0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dshilo",  "7,:",	0x7c0006bc, 0xfc07e7ff, MOD_a,			0,		D64	},
+{"dshilov", "7,s",	0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s,		0,		D64	},
+{"extpdp",  "t,7,6",	0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA,	0,		D32	},
+{"extpdpv", "t,7,s",	0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0,		D32	},
+{"extp",    "t,7,6",	0x7c0000b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extpv",   "t,7,s",	0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extr_rs.w", "t,7,6",	0x7c0001b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extr_r.w", "t,7,6",	0x7c000138, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extr_s.h", "t,7,6",	0x7c0003b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extrv_rs.w", "t,7,s",	0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv_r.w", "t,7,s",	0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv_s.h", "t,7,s",	0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv.w", "t,7,s",	0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extr.w",  "t,7,6",	0x7c000038, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"insv",    "t,s",	0x7c00000c, 0xfc00ffff, WR_t|RD_s,		0,		D32	},
+{"lbux",    "d,t(b)",	0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"ldx",     "d,t(b)",	0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D64	},
+{"lhx",     "d,t(b)",	0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"lwx",     "d,t(b)",	0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"modsub",  "d,s,t",	0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"mthlip",  "s,7",	0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA,	0,		D32	},
+{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"mulq_rs.ph", "d,s,t",	0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO,	0,		D32	},
+{"mulq_rs.qh", "d,s,t",	0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO,	0,		D64	},
+{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"packrl.ph", "d,s,t",	0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"packrl.pw", "d,s,t",	0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.ob", "d,s,t",	0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.ph", "d,s,t",	0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"pick.pw", "d,s,t",	0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.qb", "d,s,t",	0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"pick.qh", "d,s,t",	0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.w.phl", "d,t",	0x7c000312, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceq.w.phr", "d,t",	0x7c000352, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"raddu.l.ob", "d,s",	0x7c000514, 0xfc1f07ff, WR_d|RD_s,		0,		D64	},
+{"raddu.w.qb", "d,s",	0x7c000510, 0xfc1f07ff, WR_d|RD_s,		0,		D32	},
+{"rddsp",   "d",	0x7fff04b8, 0xffff07ff, WR_d,			0,		D32	},
+{"rddsp",   "d,'",	0x7c0004b8, 0xffc007ff, WR_d,			0,		D32	},
+{"repl.ob", "d,5",	0x7c000096, 0xff0007ff, WR_d,			0,		D64	},
+{"repl.ph", "d,@",	0x7c000292, 0xfc0007ff, WR_d,			0,		D32	},
+{"repl.pw", "d,@",	0x7c000496, 0xfc0007ff, WR_d,			0,		D64	},
+{"repl.qb", "d,5",	0x7c000092, 0xff0007ff, WR_d,			0,		D32	},
+{"repl.qh", "d,@",	0x7c000296, 0xfc0007ff, WR_d,			0,		D64	},
+{"replv.ob", "d,t",	0x7c0000d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"replv.ph", "d,t",	0x7c0002d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"replv.pw", "d,t",	0x7c0004d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"replv.qb", "d,t",	0x7c0000d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"replv.qh", "d,t",	0x7c0002d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"shilo",   "7,0",	0x7c0006b8, 0xfc0fe7ff, MOD_a,			0,		D32	},
+{"shilov",  "7,s",	0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s,		0,		D32	},
+{"shll.ob", "d,t,3",	0x7c000017, 0xff0007ff, WR_d|RD_t,		0,		D64	},
+{"shll.ph", "d,t,4",	0x7c000213, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shll.pw", "d,t,6",	0x7c000417, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shll.qb", "d,t,3",	0x7c000013, 0xff0007ff, WR_d|RD_t,		0,		D32	},
+{"shll.qh", "d,t,4",	0x7c000217, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.ph", "d,t,4",	0x7c000313, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shll_s.pw", "d,t,6",	0x7c000517, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.qh", "d,t,4",	0x7c000317, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.w", "d,t,6",	0x7c000513, 0xfc0007ff, WR_d|RD_t,		0,		D32	},
+{"shllv.ob", "d,t,s",	0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv.ph", "d,t,s",	0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv.pw", "d,t,s",	0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv.qb", "d,t,s",	0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv.qh", "d,t,s",	0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.ph", "d,t,s",	0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv_s.pw", "d,t,s",	0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.qh", "d,t,s",	0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.w", "d,t,s",	0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shra.ph", "d,t,4",	0x7c000253, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shra.pw", "d,t,6",	0x7c000457, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shra.qh", "d,t,4",	0x7c000257, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.ph", "d,t,4",	0x7c000353, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shra_r.pw", "d,t,6",	0x7c000557, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.qh", "d,t,4",	0x7c000357, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.w", "d,t,6",	0x7c000553, 0xfc0007ff, WR_d|RD_t,		0,		D32	},
+{"shrav.ph", "d,t,s",	0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrav.pw", "d,t,s",	0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav.qh", "d,t,s",	0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.ph", "d,t,s",	0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrav_r.pw", "d,t,s",	0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.qh", "d,t,s",	0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.w", "d,t,s",	0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrl.ob", "d,t,3",	0x7c000057, 0xff0007ff, WR_d|RD_t,		0,		D64	},
+{"shrl.qb", "d,t,3",	0x7c000053, 0xff0007ff, WR_d|RD_t,		0,		D32	},
+{"shrlv.ob", "d,t,s",	0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrlv.qb", "d,t,s",	0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq.ph", "d,s,t",	0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq.pw", "d,s,t",	0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq.qh", "d,s,t",	0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.ph", "d,s,t",	0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq_s.pw", "d,s,t",	0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.qh", "d,s,t",	0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.w", "d,s,t",	0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subu.ob", "d,s,t",	0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subu.qb", "d,s,t",	0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subu_s.ob", "d,s,t",	0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subu_s.qb", "d,s,t",	0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"wrdsp",   "s",	0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA,		0,		D32	},
+{"wrdsp",   "s,8",	0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA,		0,		D32	},
+/* MIPS DSP ASE Rev2 */
+{"absq_s.qb", "d,t",	0x7c000052, 0xffe007ff, WR_d|RD_t,              0,              D33	},
+{"addu.ph", "d,s,t",	0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"addu_s.ph", "d,s,t",	0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"adduh.qb", "d,s,t",	0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"adduh_r.qb", "d,s,t",	0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"append",  "t,s,h",	0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"balign",  "t,s,I",	0,    (int) M_BALIGN,	INSN_MACRO,             0,              D33	},
+{"balign",  "t,s,2",	0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"dpa.w.ph", "7,s,t",	0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"dps.w.ph", "7,s,t",	0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"mul.ph",  "d,s,t",	0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mul_s.ph", "d,s,t",	0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_rs.w", "d,s,t",	0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_s.ph", "d,s,t",	0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_s.w", "d,s,t",	0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulsa.w.ph", "7,s,t",	0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t,        0,              D33	},
+{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s,     0,              D33	},
+{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s,   0,              D33	},
+{"prepend", "t,s,h",	0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"shra.qb", "d,t,3",	0x7c000113, 0xff0007ff, WR_d|RD_t,              0,              D33	},
+{"shra_r.qb", "d,t,3",	0x7c000153, 0xff0007ff, WR_d|RD_t,              0,              D33	},
+{"shrav.qb", "d,t,s",	0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"shrav_r.qb", "d,t,s",	0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"shrl.ph", "d,t,4",	0x7c000653, 0xfe0007ff, WR_d|RD_t,              0,              D33	},
+{"shrlv.ph", "d,t,s",	0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subu.ph", "d,s,t",	0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subu_s.ph", "d,s,t",	0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subuh.qb", "d,s,t",	0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subuh_r.qb", "d,s,t",	0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"addqh.ph", "d,s,t",	0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh_r.ph", "d,s,t",	0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh.w", "d,s,t",	0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh_r.w", "d,s,t",	0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh.ph", "d,s,t",	0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh_r.ph", "d,s,t",	0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh.w", "d,s,t",	0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh_r.w", "d,s,t",	0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"dpax.w.ph", "7,s,t",	0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsx.w.ph", "7,s,t",	0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+/* Move bc0* after mftr and mttr to avoid opcode collision.  */
+{"bc0f",    "p",	0x41000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc0fl",   "p",	0x41020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc0t",    "p",	0x41010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc0tl",   "p",	0x41030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+/* ST Microelectronics Loongson-2E and -2F.  */
+{"mult.g",	"d,s,t",	0x7c000018,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"mult.g",	"d,s,t",	0x70000010,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"multu.g",	"d,s,t",	0x7c000019,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"multu.g",	"d,s,t",	0x70000012,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"dmult.g",	"d,s,t",	0x7c00001c,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"dmult.g",	"d,s,t",	0x70000011,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"dmultu.g",	"d,s,t",	0x7c00001d,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"dmultu.g",	"d,s,t",	0x70000013,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"div.g",	"d,s,t",	0x7c00001a,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"div.g",	"d,s,t",	0x70000014,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"divu.g",	"d,s,t",	0x7c00001b,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"divu.g",	"d,s,t",	0x70000016,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"ddiv.g",	"d,s,t",	0x7c00001e,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"ddiv.g",	"d,s,t",	0x70000015,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"ddivu.g",	"d,s,t",	0x7c00001f,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"ddivu.g",	"d,s,t",	0x70000017,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"mod.g",	"d,s,t",	0x7c000022,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"mod.g",	"d,s,t",	0x7000001c,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"modu.g",	"d,s,t",	0x7c000023,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"modu.g",	"d,s,t",	0x7000001e,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"dmod.g",	"d,s,t",	0x7c000026,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"dmod.g",	"d,s,t",	0x7000001d,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+{"dmodu.g",	"d,s,t",	0x7c000027,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2E	},
+{"dmodu.g",	"d,s,t",	0x7000001f,	0xfc0007ff,	RD_s|RD_t|WR_d,	0,	IL2F	},
+};
+
+#define MIPS_NUM_OPCODES \
+	((sizeof mips_builtin_opcodes) / (sizeof (mips_builtin_opcodes[0])))
+const int bfd_mips_num_builtin_opcodes = MIPS_NUM_OPCODES;
+
+/* const removed from the following to allow for dynamic extensions to the
+ * built-in instruction set. */
+struct mips_opcode *mips_opcodes =
+  (struct mips_opcode *) mips_builtin_opcodes;
+int bfd_mips_num_opcodes = MIPS_NUM_OPCODES;
+#undef MIPS_NUM_OPCODES
+
+/* Mips instructions are at maximum this many bytes long.  */
+#define INSNLEN 4
+
+
+/* FIXME: These should be shared with gdb somehow.  */
+
+struct mips_cp0sel_name
+{
+  unsigned int cp0reg;
+  unsigned int sel;
+  const char * const name;
+};
+
+/* The mips16 registers.  */
+static const unsigned int mips16_to_32_reg_map[] =
+{
+  16, 17, 2, 3, 4, 5, 6, 7
+};
+
+#define mips16_reg_names(rn)	mips_gpr_names[mips16_to_32_reg_map[rn]]
+
+
+static const char * const mips_gpr_names_numeric[32] =
+{
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const mips_gpr_names_oldabi[32] =
+{
+  "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
+  "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
+  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
+};
+
+static const char * const mips_gpr_names_newabi[32] =
+{
+  "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
+  "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
+  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
+};
+
+static const char * const mips_fpr_names_numeric[32] =
+{
+  "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
+  "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
+};
+
+static const char * const mips_fpr_names_32[32] =
+{
+  "fv0",  "fv0f", "fv1",  "fv1f", "ft0",  "ft0f", "ft1",  "ft1f",
+  "ft2",  "ft2f", "ft3",  "ft3f", "fa0",  "fa0f", "fa1",  "fa1f",
+  "ft4",  "ft4f", "ft5",  "ft5f", "fs0",  "fs0f", "fs1",  "fs1f",
+  "fs2",  "fs2f", "fs3",  "fs3f", "fs4",  "fs4f", "fs5",  "fs5f"
+};
+
+static const char * const mips_fpr_names_n32[32] =
+{
+  "fv0",  "ft14", "fv1",  "ft15", "ft0",  "ft1",  "ft2",  "ft3",
+  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
+  "fa4",  "fa5",  "fa6",  "fa7",  "fs0",  "ft8",  "fs1",  "ft9",
+  "fs2",  "ft10", "fs3",  "ft11", "fs4",  "ft12", "fs5",  "ft13"
+};
+
+static const char * const mips_fpr_names_64[32] =
+{
+  "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
+  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
+  "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
+  "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
+};
+
+static const char * const mips_cp0_names_numeric[32] =
+{
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const mips_cp0_names_mips3264[32] =
+{
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "c0_debug",
+  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
+  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
+};
+
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
+{
+  {  4, 1, "c0_contextconfig"	},
+  {  0, 1, "c0_mvpcontrol"	},
+  {  0, 2, "c0_mvpconf0"	},
+  {  0, 3, "c0_mvpconf1"	},
+  {  1, 1, "c0_vpecontrol"	},
+  {  1, 2, "c0_vpeconf0"	},
+  {  1, 3, "c0_vpeconf1"	},
+  {  1, 4, "c0_yqmask"		},
+  {  1, 5, "c0_vpeschedule"	},
+  {  1, 6, "c0_vpeschefback"	},
+  {  2, 1, "c0_tcstatus"	},
+  {  2, 2, "c0_tcbind"		},
+  {  2, 3, "c0_tcrestart"	},
+  {  2, 4, "c0_tchalt"		},
+  {  2, 5, "c0_tccontext"	},
+  {  2, 6, "c0_tcschedule"	},
+  {  2, 7, "c0_tcschefback"	},
+  {  5, 1, "c0_pagegrain"	},
+  {  6, 1, "c0_srsconf0"	},
+  {  6, 2, "c0_srsconf1"	},
+  {  6, 3, "c0_srsconf2"	},
+  {  6, 4, "c0_srsconf3"	},
+  {  6, 5, "c0_srsconf4"	},
+  { 12, 1, "c0_intctl"		},
+  { 12, 2, "c0_srsctl"		},
+  { 12, 3, "c0_srsmap"		},
+  { 15, 1, "c0_ebase"		},
+  { 16, 1, "c0_config1"		},
+  { 16, 2, "c0_config2"		},
+  { 16, 3, "c0_config3"		},
+  { 18, 1, "c0_watchlo,1"	},
+  { 18, 2, "c0_watchlo,2"	},
+  { 18, 3, "c0_watchlo,3"	},
+  { 18, 4, "c0_watchlo,4"	},
+  { 18, 5, "c0_watchlo,5"	},
+  { 18, 6, "c0_watchlo,6"	},
+  { 18, 7, "c0_watchlo,7"	},
+  { 19, 1, "c0_watchhi,1"	},
+  { 19, 2, "c0_watchhi,2"	},
+  { 19, 3, "c0_watchhi,3"	},
+  { 19, 4, "c0_watchhi,4"	},
+  { 19, 5, "c0_watchhi,5"	},
+  { 19, 6, "c0_watchhi,6"	},
+  { 19, 7, "c0_watchhi,7"	},
+  { 23, 1, "c0_tracecontrol"	},
+  { 23, 2, "c0_tracecontrol2"	},
+  { 23, 3, "c0_usertracedata"	},
+  { 23, 4, "c0_tracebpc"	},
+  { 25, 1, "c0_perfcnt,1"	},
+  { 25, 2, "c0_perfcnt,2"	},
+  { 25, 3, "c0_perfcnt,3"	},
+  { 25, 4, "c0_perfcnt,4"	},
+  { 25, 5, "c0_perfcnt,5"	},
+  { 25, 6, "c0_perfcnt,6"	},
+  { 25, 7, "c0_perfcnt,7"	},
+  { 27, 1, "c0_cacheerr,1"	},
+  { 27, 2, "c0_cacheerr,2"	},
+  { 27, 3, "c0_cacheerr,3"	},
+  { 28, 1, "c0_datalo"		},
+  { 28, 2, "c0_taglo1"		},
+  { 28, 3, "c0_datalo1"		},
+  { 28, 4, "c0_taglo2"		},
+  { 28, 5, "c0_datalo2"		},
+  { 28, 6, "c0_taglo3"		},
+  { 28, 7, "c0_datalo3"		},
+  { 29, 1, "c0_datahi"		},
+  { 29, 2, "c0_taghi1"		},
+  { 29, 3, "c0_datahi1"		},
+  { 29, 4, "c0_taghi2"		},
+  { 29, 5, "c0_datahi2"		},
+  { 29, 6, "c0_taghi3"		},
+  { 29, 7, "c0_datahi3"		},
+};
+
+static const char * const mips_cp0_names_mips3264r2[32] =
+{
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "c0_debug",
+  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
+  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
+};
+
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
+{
+  {  4, 1, "c0_contextconfig"	},
+  {  5, 1, "c0_pagegrain"	},
+  { 12, 1, "c0_intctl"		},
+  { 12, 2, "c0_srsctl"		},
+  { 12, 3, "c0_srsmap"		},
+  { 15, 1, "c0_ebase"		},
+  { 16, 1, "c0_config1"		},
+  { 16, 2, "c0_config2"		},
+  { 16, 3, "c0_config3"		},
+  { 18, 1, "c0_watchlo,1"	},
+  { 18, 2, "c0_watchlo,2"	},
+  { 18, 3, "c0_watchlo,3"	},
+  { 18, 4, "c0_watchlo,4"	},
+  { 18, 5, "c0_watchlo,5"	},
+  { 18, 6, "c0_watchlo,6"	},
+  { 18, 7, "c0_watchlo,7"	},
+  { 19, 1, "c0_watchhi,1"	},
+  { 19, 2, "c0_watchhi,2"	},
+  { 19, 3, "c0_watchhi,3"	},
+  { 19, 4, "c0_watchhi,4"	},
+  { 19, 5, "c0_watchhi,5"	},
+  { 19, 6, "c0_watchhi,6"	},
+  { 19, 7, "c0_watchhi,7"	},
+  { 23, 1, "c0_tracecontrol"	},
+  { 23, 2, "c0_tracecontrol2"	},
+  { 23, 3, "c0_usertracedata"	},
+  { 23, 4, "c0_tracebpc"	},
+  { 25, 1, "c0_perfcnt,1"	},
+  { 25, 2, "c0_perfcnt,2"	},
+  { 25, 3, "c0_perfcnt,3"	},
+  { 25, 4, "c0_perfcnt,4"	},
+  { 25, 5, "c0_perfcnt,5"	},
+  { 25, 6, "c0_perfcnt,6"	},
+  { 25, 7, "c0_perfcnt,7"	},
+  { 27, 1, "c0_cacheerr,1"	},
+  { 27, 2, "c0_cacheerr,2"	},
+  { 27, 3, "c0_cacheerr,3"	},
+  { 28, 1, "c0_datalo"		},
+  { 28, 2, "c0_taglo1"		},
+  { 28, 3, "c0_datalo1"		},
+  { 28, 4, "c0_taglo2"		},
+  { 28, 5, "c0_datalo2"		},
+  { 28, 6, "c0_taglo3"		},
+  { 28, 7, "c0_datalo3"		},
+  { 29, 1, "c0_datahi"		},
+  { 29, 2, "c0_taghi1"		},
+  { 29, 3, "c0_datahi1"		},
+  { 29, 4, "c0_taghi2"		},
+  { 29, 5, "c0_datahi2"		},
+  { 29, 6, "c0_taghi3"		},
+  { 29, 7, "c0_datahi3"		},
+};
+
+/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods.  */
+static const char * const mips_cp0_names_sb1[32] =
+{
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "c0_debug",
+  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr_i",
+  "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
+};
+
+static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
+{
+  { 16, 1, "c0_config1"		},
+  { 18, 1, "c0_watchlo,1"	},
+  { 19, 1, "c0_watchhi,1"	},
+  { 22, 0, "c0_perftrace"	},
+  { 23, 3, "c0_edebug"		},
+  { 25, 1, "c0_perfcnt,1"	},
+  { 25, 2, "c0_perfcnt,2"	},
+  { 25, 3, "c0_perfcnt,3"	},
+  { 25, 4, "c0_perfcnt,4"	},
+  { 25, 5, "c0_perfcnt,5"	},
+  { 25, 6, "c0_perfcnt,6"	},
+  { 25, 7, "c0_perfcnt,7"	},
+  { 26, 1, "c0_buserr_pa"	},
+  { 27, 1, "c0_cacheerr_d"	},
+  { 27, 3, "c0_cacheerr_d_pa"	},
+  { 28, 1, "c0_datalo_i"	},
+  { 28, 2, "c0_taglo_d"		},
+  { 28, 3, "c0_datalo_d"	},
+  { 29, 1, "c0_datahi_i"	},
+  { 29, 2, "c0_taghi_d"		},
+  { 29, 3, "c0_datahi_d"	},
+};
+
+static const char * const mips_hwr_names_numeric[32] =
+{
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const mips_hwr_names_mips3264r2[32] =
+{
+  "hwr_cpunum",   "hwr_synci_step", "hwr_cc",     "hwr_ccres",
+  "$4",          "$5",            "$6",           "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+struct mips_abi_choice
+{
+  const char *name;
+  const char * const *gpr_names;
+  const char * const *fpr_names;
+};
+
+static struct mips_abi_choice mips_abi_choices[] =
+{
+  { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
+  { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
+  { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
+  { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
+};
+
+struct mips_arch_choice
+{
+  const char *name;
+  int bfd_mach_valid;
+  unsigned long bfd_mach;
+  int processor;
+  int isa;
+  const char * const *cp0_names;
+  const struct mips_cp0sel_name *cp0sel_names;
+  unsigned int cp0sel_names_len;
+  const char * const *hwr_names;
+};
+
+#define bfd_mach_mips3000              3000
+#define bfd_mach_mips3900              3900
+#define bfd_mach_mips4000              4000
+#define bfd_mach_mips4010              4010
+#define bfd_mach_mips4100              4100
+#define bfd_mach_mips4111              4111
+#define bfd_mach_mips4120              4120
+#define bfd_mach_mips4300              4300
+#define bfd_mach_mips4400              4400
+#define bfd_mach_mips4600              4600
+#define bfd_mach_mips4650              4650
+#define bfd_mach_mips5000              5000
+#define bfd_mach_mips5400              5400
+#define bfd_mach_mips5500              5500
+#define bfd_mach_mips6000              6000
+#define bfd_mach_mips7000              7000
+#define bfd_mach_mips8000              8000
+#define bfd_mach_mips9000              9000
+#define bfd_mach_mips10000             10000
+#define bfd_mach_mips12000             12000
+#define bfd_mach_mips16                16
+#define bfd_mach_mips5                 5
+#define bfd_mach_mips_sb1              12310201 /* octal 'SB', 01 */
+#define bfd_mach_mipsisa32             32
+#define bfd_mach_mipsisa32r2           33
+#define bfd_mach_mipsisa64             64
+#define bfd_mach_mipsisa64r2           65
+
+static const struct mips_arch_choice mips_arch_choices[] =
+{
+  { "numeric",	0, 0, 0, 0,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+
+  { "r3000",	1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r3900",	1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4000",	1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4010",	1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "vr4100",	1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "vr4111",	1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "vr4120",	1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4300",	1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4400",	1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4600",	1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r4650",	1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r5000",	1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "vr5400",	1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "vr5500",	1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r6000",	1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "rm7000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "rm9000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r8000",	1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r10000",	1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r12000",	1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "mips5",	1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+
+  /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
+     Note that MIPS-3D and MDMX are not applicable to MIPS32.  (See
+     _MIPS32 Architecture For Programmers Volume I: Introduction to the
+     MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
+     page 1.  */
+  { "mips32",	1, bfd_mach_mipsisa32, CPU_MIPS32,
+    ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS,
+    mips_cp0_names_mips3264,
+    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
+    mips_hwr_names_numeric },
+
+  { "mips32r2",	1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
+    (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
+     | INSN_MIPS3D | INSN_MT),
+    mips_cp0_names_mips3264r2,
+    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+    mips_hwr_names_mips3264r2 },
+
+  /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs.  */
+  { "mips64",	1, bfd_mach_mipsisa64, CPU_MIPS64,
+    ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
+    mips_cp0_names_mips3264,
+    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
+    mips_hwr_names_numeric },
+
+  { "mips64r2",	1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
+    (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2
+     | INSN_DSP64 | INSN_MT | INSN_MDMX),
+    mips_cp0_names_mips3264r2,
+    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+    mips_hwr_names_mips3264r2 },
+
+  { "sb1",	1, bfd_mach_mips_sb1, CPU_SB1,
+    ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
+    mips_cp0_names_sb1,
+    mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
+    mips_hwr_names_numeric },
+
+  /* This entry, mips16, is here only for ISA/processor selection; do
+     not print its name.  */
+  { "",		1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+};
+
+/* ISA and processor type to disassemble for, and register names to use.
+   set_default_mips_dis_options and parse_mips_dis_options fill in these
+   values.  */
+static int mips_processor;
+static int mips_isa;
+static const char * const *mips_gpr_names;
+static const char * const *mips_fpr_names;
+static const char * const *mips_cp0_names;
+static const struct mips_cp0sel_name *mips_cp0sel_names;
+static int mips_cp0sel_names_len;
+static const char * const *mips_hwr_names;
+
+/* Other options */
+static int no_aliases;	/* If set disassemble as most general inst.  */
+
+static const struct mips_abi_choice *
+choose_abi_by_name (const char *name, unsigned int namelen)
+{
+  const struct mips_abi_choice *c;
+  unsigned int i;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
+    if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
+	&& strlen (mips_abi_choices[i].name) == namelen)
+      c = &mips_abi_choices[i];
+
+  return c;
+}
+
+static const struct mips_arch_choice *
+choose_arch_by_name (const char *name, unsigned int namelen)
+{
+  const struct mips_arch_choice *c = NULL;
+  unsigned int i;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
+    if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
+	&& strlen (mips_arch_choices[i].name) == namelen)
+      c = &mips_arch_choices[i];
+
+  return c;
+}
+
+static const struct mips_arch_choice *
+choose_arch_by_number (unsigned long mach)
+{
+  static unsigned long hint_bfd_mach;
+  static const struct mips_arch_choice *hint_arch_choice;
+  const struct mips_arch_choice *c;
+  unsigned int i;
+
+  /* We optimize this because even if the user specifies no
+     flags, this will be done for every instruction!  */
+  if (hint_bfd_mach == mach
+      && hint_arch_choice != NULL
+      && hint_arch_choice->bfd_mach == hint_bfd_mach)
+    return hint_arch_choice;
+
+  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
+    {
+      if (mips_arch_choices[i].bfd_mach_valid
+	  && mips_arch_choices[i].bfd_mach == mach)
+	{
+	  c = &mips_arch_choices[i];
+	  hint_bfd_mach = mach;
+	  hint_arch_choice = c;
+	}
+    }
+  return c;
+}
+
+static void
+set_default_mips_dis_options (struct disassemble_info *info)
+{
+  const struct mips_arch_choice *chosen_arch;
+
+  /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
+     and numeric FPR, CP0 register, and HWR names.  */
+  mips_isa = ISA_MIPS3;
+  mips_processor =  CPU_R3000;
+  mips_gpr_names = mips_gpr_names_oldabi;
+  mips_fpr_names = mips_fpr_names_numeric;
+  mips_cp0_names = mips_cp0_names_numeric;
+  mips_cp0sel_names = NULL;
+  mips_cp0sel_names_len = 0;
+  mips_hwr_names = mips_hwr_names_numeric;
+  no_aliases = 0;
+
+  /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
+#if 0
+  if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
+    {
+      Elf_Internal_Ehdr *header;
+
+      header = elf_elfheader (info->section->owner);
+      if (is_newabi (header))
+	mips_gpr_names = mips_gpr_names_newabi;
+    }
+#endif
+
+  /* Set ISA, architecture, and cp0 register names as best we can.  */
+#if !defined(SYMTAB_AVAILABLE) && 0
+  /* This is running out on a target machine, not in a host tool.
+     FIXME: Where does mips_target_info come from?  */
+  target_processor = mips_target_info.processor;
+  mips_isa = mips_target_info.isa;
+#else
+  chosen_arch = choose_arch_by_number (info->mach);
+  if (chosen_arch != NULL)
+    {
+      mips_processor = chosen_arch->processor;
+      mips_isa = chosen_arch->isa;
+      mips_cp0_names = chosen_arch->cp0_names;
+      mips_cp0sel_names = chosen_arch->cp0sel_names;
+      mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+      mips_hwr_names = chosen_arch->hwr_names;
+    }
+#endif
+}
+
+static void
+parse_mips_dis_option (const char *option, unsigned int len)
+{
+  unsigned int i, optionlen, vallen;
+  const char *val;
+  const struct mips_abi_choice *chosen_abi;
+  const struct mips_arch_choice *chosen_arch;
+
+  /* Look for the = that delimits the end of the option name.  */
+  for (i = 0; i < len; i++)
+    {
+      if (option[i] == '=')
+	break;
+    }
+  if (i == 0)		/* Invalid option: no name before '='.  */
+    return;
+  if (i == len)		/* Invalid option: no '='.  */
+    return;
+  if (i == (len - 1))	/* Invalid option: no value after '='.  */
+    return;
+
+  optionlen = i;
+  val = option + (optionlen + 1);
+  vallen = len - (optionlen + 1);
+
+  if (strncmp("gpr-names", option, optionlen) == 0
+      && strlen("gpr-names") == optionlen)
+    {
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	mips_gpr_names = chosen_abi->gpr_names;
+      return;
+    }
+
+  if (strncmp("fpr-names", option, optionlen) == 0
+      && strlen("fpr-names") == optionlen)
+    {
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	mips_fpr_names = chosen_abi->fpr_names;
+      return;
+    }
+
+  if (strncmp("cp0-names", option, optionlen) == 0
+      && strlen("cp0-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	{
+	  mips_cp0_names = chosen_arch->cp0_names;
+	  mips_cp0sel_names = chosen_arch->cp0sel_names;
+	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+	}
+      return;
+    }
+
+  if (strncmp("hwr-names", option, optionlen) == 0
+      && strlen("hwr-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	mips_hwr_names = chosen_arch->hwr_names;
+      return;
+    }
+
+  if (strncmp("reg-names", option, optionlen) == 0
+      && strlen("reg-names") == optionlen)
+    {
+      /* We check both ABI and ARCH here unconditionally, so
+	 that "numeric" will do the desirable thing: select
+	 numeric register names for all registers.  Other than
+	 that, a given name probably won't match both.  */
+      chosen_abi = choose_abi_by_name (val, vallen);
+      if (chosen_abi != NULL)
+	{
+	  mips_gpr_names = chosen_abi->gpr_names;
+	  mips_fpr_names = chosen_abi->fpr_names;
+	}
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+	{
+	  mips_cp0_names = chosen_arch->cp0_names;
+	  mips_cp0sel_names = chosen_arch->cp0sel_names;
+	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+	  mips_hwr_names = chosen_arch->hwr_names;
+	}
+      return;
+    }
+
+  /* Invalid option.  */
+}
+
+static void
+parse_mips_dis_options (const char *options)
+{
+  const char *option_end;
+
+  if (options == NULL)
+    return;
+
+  while (*options != '\0')
+    {
+      /* Skip empty options.  */
+      if (*options == ',')
+	{
+	  options++;
+	  continue;
+	}
+
+      /* We know that *options is neither NUL or a comma.  */
+      option_end = options + 1;
+      while (*option_end != ',' && *option_end != '\0')
+	option_end++;
+
+      parse_mips_dis_option (options, option_end - options);
+
+      /* Go on to the next one.  If option_end points to a comma, it
+	 will be skipped above.  */
+      options = option_end;
+    }
+}
+
+static const struct mips_cp0sel_name *
+lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names,
+			 unsigned int len,
+			 unsigned int cp0reg,
+			 unsigned int sel)
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+    if (names[i].cp0reg == cp0reg && names[i].sel == sel)
+      return &names[i];
+  return NULL;
+}
+
+/* Print insn arguments for 32/64-bit code.  */
+
+static void
+print_insn_args (const char *d,
+		 register unsigned long int l,
+		 bfd_vma pc,
+		 struct disassemble_info *info,
+		 const struct mips_opcode *opp)
+{
+  int op, delta;
+  unsigned int lsb, msb, msbd;
+
+  lsb = 0;
+
+  for (; *d != '\0'; d++)
+    {
+      switch (*d)
+	{
+	case ',':
+	case '(':
+	case ')':
+	case '[':
+	case ']':
+	  (*info->fprintf_func) (info->stream, "%c", *d);
+	  break;
+
+	case '+':
+	  /* Extension character; switch for second char.  */
+	  d++;
+	  switch (*d)
+	    {
+	    case '\0':
+	      /* xgettext:c-format */
+	      (*info->fprintf_func) (info->stream,
+				     _("# internal error, incomplete extension sequence (+)"));
+	      return;
+
+	    case 'A':
+	      lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
+	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
+	      break;
+
+	    case 'B':
+	      msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
+	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
+	      break;
+
+	    case '1':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI1) & OP_MASK_UDI1);
+	      break;
+
+	    case '2':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI2) & OP_MASK_UDI2);
+	      break;
+
+	    case '3':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI3) & OP_MASK_UDI3);
+	      break;
+
+	    case '4':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI4) & OP_MASK_UDI4);
+	      break;
+
+	    case 'C':
+	    case 'H':
+	      msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
+	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
+	      break;
+
+	    case 'D':
+	      {
+		const struct mips_cp0sel_name *n;
+		unsigned int cp0reg, sel;
+
+		cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
+		sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
+
+		/* CP0 register including 'sel' code for mtcN (et al.), to be
+		   printed textually if known.  If not known, print both
+		   CP0 register name and sel numerically since CP0 register
+		   with sel 0 may have a name unrelated to register being
+		   printed.  */
+		n = lookup_mips_cp0sel_name(mips_cp0sel_names,
+					    mips_cp0sel_names_len, cp0reg, sel);
+		if (n != NULL)
+		  (*info->fprintf_func) (info->stream, "%s", n->name);
+		else
+		  (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
+		break;
+	      }
+
+	    case 'E':
+	      lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
+	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
+	      break;
+
+	    case 'F':
+	      msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
+	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
+	      break;
+
+	    case 'G':
+	      msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
+	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
+	      break;
+
+	    case 't': /* Coprocessor 0 reg name */
+	      (*info->fprintf_func) (info->stream, "%s",
+				     mips_cp0_names[(l >> OP_SH_RT) &
+						     OP_MASK_RT]);
+	      break;
+
+	    case 'T': /* Coprocessor 0 reg name */
+	      {
+		const struct mips_cp0sel_name *n;
+		unsigned int cp0reg, sel;
+
+		cp0reg = (l >> OP_SH_RT) & OP_MASK_RT;
+		sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
+
+		/* CP0 register including 'sel' code for mftc0, to be
+		   printed textually if known.  If not known, print both
+		   CP0 register name and sel numerically since CP0 register
+		   with sel 0 may have a name unrelated to register being
+		   printed.  */
+		n = lookup_mips_cp0sel_name(mips_cp0sel_names,
+					    mips_cp0sel_names_len, cp0reg, sel);
+		if (n != NULL)
+		  (*info->fprintf_func) (info->stream, "%s", n->name);
+		else
+		  (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
+		break;
+	      }
+
+	    default:
+	      /* xgettext:c-format */
+	      (*info->fprintf_func) (info->stream,
+				     _("# internal error, undefined extension sequence (+%c)"),
+				     *d);
+	      return;
+	    }
+	  break;
+
+	case '2':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_BP) & OP_MASK_BP);
+	  break;
+
+	case '3':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_SA3) & OP_MASK_SA3);
+	  break;
+
+	case '4':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_SA4) & OP_MASK_SA4);
+	  break;
+
+	case '5':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_IMM8) & OP_MASK_IMM8);
+	  break;
+
+	case '6':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_RS) & OP_MASK_RS);
+	  break;
+
+	case '7':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_DSPACC) & OP_MASK_DSPACC);
+	  break;
+
+	case '8':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_WRDSP) & OP_MASK_WRDSP);
+	  break;
+
+	case '9':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S);
+	  break;
+
+	case '0': /* dsp 6-bit signed immediate in bit 20 */
+	  delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT);
+	  if (delta & 0x20) /* test sign bit */
+	    delta |= ~OP_MASK_DSPSFT;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case ':': /* dsp 7-bit signed immediate in bit 19 */
+	  delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7);
+	  if (delta & 0x40) /* test sign bit */
+	    delta |= ~OP_MASK_DSPSFT_7;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case '\'':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_RDDSP) & OP_MASK_RDDSP);
+	  break;
+
+	case '@': /* dsp 10-bit signed immediate in bit 16 */
+	  delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
+	  if (delta & 0x200) /* test sign bit */
+	    delta |= ~OP_MASK_IMM10;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case '!':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_MT_U) & OP_MASK_MT_U);
+	  break;
+
+	case '$':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_MT_H) & OP_MASK_MT_H);
+	  break;
+
+	case '*':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T);
+	  break;
+
+	case '&':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D);
+	  break;
+
+	case 'g':
+	  /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2.  */
+	  (*info->fprintf_func) (info->stream, "$%ld",
+				 (l >> OP_SH_RD) & OP_MASK_RD);
+	  break;
+
+	case 's':
+	case 'b':
+	case 'r':
+	case 'v':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
+	  break;
+
+	case 't':
+	case 'w':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+	  break;
+
+	case 'i':
+	case 'u':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
+	  break;
+
+	case 'j': /* Same as i, but sign-extended.  */
+	case 'o':
+	  delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+	  if (delta & 0x8000)
+	    delta |= ~0xffff;
+	  (*info->fprintf_func) (info->stream, "%d",
+				 delta);
+	  break;
+
+	case 'h':
+	  (*info->fprintf_func) (info->stream, "0x%x",
+				 (unsigned int) ((l >> OP_SH_PREFX)
+						 & OP_MASK_PREFX));
+	  break;
+
+	case 'k':
+	  (*info->fprintf_func) (info->stream, "0x%x",
+				 (unsigned int) ((l >> OP_SH_CACHE)
+						 & OP_MASK_CACHE));
+	  break;
+
+	case 'a':
+	  info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
+			  | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
+	  /* For gdb disassembler, force odd address on jalx.  */
+	  if (info->flavour == bfd_target_unknown_flavour
+	      && strcmp (opp->name, "jalx") == 0)
+	    info->target |= 1;
+	  (*info->print_address_func) (info->target, info);
+	  break;
+
+	case 'p':
+	  /* Sign extend the displacement.  */
+	  delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+	  if (delta & 0x8000)
+	    delta |= ~0xffff;
+	  info->target = (delta << 2) + pc + INSNLEN;
+	  (*info->print_address_func) (info->target, info);
+	  break;
+
+	case 'd':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+	  break;
+
+	case 'U':
+	  {
+	    /* First check for both rd and rt being equal.  */
+	    unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
+	    if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
+	      (*info->fprintf_func) (info->stream, "%s",
+				     mips_gpr_names[reg]);
+	    else
+	      {
+		/* If one is zero use the other.  */
+		if (reg == 0)
+		  (*info->fprintf_func) (info->stream, "%s",
+					 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+		else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
+		  (*info->fprintf_func) (info->stream, "%s",
+					 mips_gpr_names[reg]);
+		else /* Bogus, result depends on processor.  */
+		  (*info->fprintf_func) (info->stream, "%s or %s",
+					 mips_gpr_names[reg],
+					 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+	      }
+	  }
+	  break;
+
+	case 'z':
+	  (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
+	  break;
+
+	case '<':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
+	  break;
+
+	case 'c':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_CODE) & OP_MASK_CODE);
+	  break;
+
+	case 'q':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
+	  break;
+
+	case 'C':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
+	  break;
+
+	case 'B':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+
+				 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
+	  break;
+
+	case 'J':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
+	  break;
+
+	case 'S':
+	case 'V':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
+	  break;
+
+	case 'T':
+	case 'W':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
+	  break;
+
+	case 'D':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
+	  break;
+
+	case 'R':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
+	  break;
+
+	case 'E':
+	  /* Coprocessor register for lwcN instructions, et al.
+
+	     Note that there is no load/store cp0 instructions, and
+	     that FPU (cp1) instructions disassemble this field using
+	     'T' format.  Therefore, until we gain understanding of
+	     cp2 register names, we can simply print the register
+	     numbers.  */
+	  (*info->fprintf_func) (info->stream, "$%ld",
+				 (l >> OP_SH_RT) & OP_MASK_RT);
+	  break;
+
+	case 'G':
+	  /* Coprocessor register for mtcN instructions, et al.  Note
+	     that FPU (cp1) instructions disassemble this field using
+	     'S' format.  Therefore, we only need to worry about cp0,
+	     cp2, and cp3.  */
+	  op = (l >> OP_SH_OP) & OP_MASK_OP;
+	  if (op == OP_OP_COP0)
+	    (*info->fprintf_func) (info->stream, "%s",
+				   mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+	  else
+	    (*info->fprintf_func) (info->stream, "$%ld",
+				   (l >> OP_SH_RD) & OP_MASK_RD);
+	  break;
+
+	case 'K':
+	  (*info->fprintf_func) (info->stream, "%s",
+				 mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+	  break;
+
+	case 'N':
+	  (*info->fprintf_func) (info->stream,
+				 ((opp->pinfo & (FP_D | FP_S)) != 0
+				  ? "$fcc%ld" : "$cc%ld"),
+				 (l >> OP_SH_BCC) & OP_MASK_BCC);
+	  break;
+
+	case 'M':
+	  (*info->fprintf_func) (info->stream, "$fcc%ld",
+				 (l >> OP_SH_CCC) & OP_MASK_CCC);
+	  break;
+
+	case 'P':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
+	  break;
+
+	case 'e':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
+	  break;
+
+	case '%':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
+	  break;
+
+	case 'H':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_SEL) & OP_MASK_SEL);
+	  break;
+
+	case 'O':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_ALN) & OP_MASK_ALN);
+	  break;
+
+	case 'Q':
+	  {
+	    unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
+
+	    if ((vsel & 0x10) == 0)
+	      {
+		int fmt;
+
+		vsel &= 0x0f;
+		for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
+		  if ((vsel & 1) == 0)
+		    break;
+		(*info->fprintf_func) (info->stream, "$v%ld[%d]",
+				       (l >> OP_SH_FT) & OP_MASK_FT,
+				       vsel >> 1);
+	      }
+	    else if ((vsel & 0x08) == 0)
+	      {
+		(*info->fprintf_func) (info->stream, "$v%ld",
+				       (l >> OP_SH_FT) & OP_MASK_FT);
+	      }
+	    else
+	      {
+		(*info->fprintf_func) (info->stream, "0x%lx",
+				       (l >> OP_SH_FT) & OP_MASK_FT);
+	      }
+	  }
+	  break;
+
+	case 'X':
+	  (*info->fprintf_func) (info->stream, "$v%ld",
+				 (l >> OP_SH_FD) & OP_MASK_FD);
+	  break;
+
+	case 'Y':
+	  (*info->fprintf_func) (info->stream, "$v%ld",
+				 (l >> OP_SH_FS) & OP_MASK_FS);
+	  break;
+
+	case 'Z':
+	  (*info->fprintf_func) (info->stream, "$v%ld",
+				 (l >> OP_SH_FT) & OP_MASK_FT);
+	  break;
+
+	default:
+	  /* xgettext:c-format */
+	  (*info->fprintf_func) (info->stream,
+				 _("# internal error, undefined modifier(%c)"),
+				 *d);
+	  return;
+	}
+    }
+}
+
+/* Check if the object uses NewABI conventions.  */
+#if 0
+static int
+is_newabi (header)
+     Elf_Internal_Ehdr *header;
+{
+  /* There are no old-style ABIs which use 64-bit ELF.  */
+  if (header->e_ident[EI_CLASS] == ELFCLASS64)
+    return 1;
+
+  /* If a 32-bit ELF file, n32 is a new-style ABI.  */
+  if ((header->e_flags & EF_MIPS_ABI2) != 0)
+    return 1;
+
+  return 0;
+}
+#endif
+
+/* Print the mips instruction at address MEMADDR in debugged memory,
+   on using INFO.  Returns length of the instruction, in bytes, which is
+   always INSNLEN.  BIGENDIAN must be 1 if this is big-endian code, 0 if
+   this is little-endian code.  */
+
+static int
+print_insn_mips (bfd_vma memaddr,
+		 unsigned long int word,
+		 struct disassemble_info *info)
+{
+  const struct mips_opcode *op;
+  static bfd_boolean init = 0;
+  static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
+
+  /* Build a hash table to shorten the search time.  */
+  if (! init)
+    {
+      unsigned int i;
+
+      for (i = 0; i <= OP_MASK_OP; i++)
+	{
+	  for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
+	    {
+	      if (op->pinfo == INSN_MACRO
+		  || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
+		continue;
+	      if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
+		{
+		  mips_hash[i] = op;
+		  break;
+		}
+	    }
+	}
+
+      init = 1;
+    }
+
+  info->bytes_per_chunk = INSNLEN;
+  info->display_endian = info->endian;
+  info->insn_info_valid = 1;
+  info->branch_delay_insns = 0;
+  info->data_size = 0;
+  info->insn_type = dis_nonbranch;
+  info->target = 0;
+  info->target2 = 0;
+
+  op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
+  if (op != NULL)
+    {
+      for (; op < &mips_opcodes[NUMOPCODES]; op++)
+	{
+	  if (op->pinfo != INSN_MACRO
+	      && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	      && (word & op->mask) == op->match)
+	    {
+	      const char *d;
+
+	      /* We always allow to disassemble the jalx instruction.  */
+	      if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
+		  && strcmp (op->name, "jalx"))
+		continue;
+
+	      /* Figure out instruction type and branch delay information.  */
+	      if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
+	        {
+		  if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
+		    info->insn_type = dis_jsr;
+		  else
+		    info->insn_type = dis_branch;
+		  info->branch_delay_insns = 1;
+		}
+	      else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
+				     | INSN_COND_BRANCH_LIKELY)) != 0)
+		{
+		  if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
+		    info->insn_type = dis_condjsr;
+		  else
+		    info->insn_type = dis_condbranch;
+		  info->branch_delay_insns = 1;
+		}
+	      else if ((op->pinfo & (INSN_STORE_MEMORY
+				     | INSN_LOAD_MEMORY_DELAY)) != 0)
+		info->insn_type = dis_dref;
+
+	      (*info->fprintf_func) (info->stream, "%s", op->name);
+
+	      d = op->args;
+	      if (d != NULL && *d != '\0')
+		{
+		  (*info->fprintf_func) (info->stream, "\t");
+		  print_insn_args (d, word, memaddr, info, op);
+		}
+
+	      return INSNLEN;
+	    }
+	}
+    }
+
+  /* Handle undefined instructions.  */
+  info->insn_type = dis_noninsn;
+  (*info->fprintf_func) (info->stream, "0x%lx", word);
+  return INSNLEN;
+}
+
+/* In an environment where we do not know the symbol type of the
+   instruction we are forced to assume that the low order bit of the
+   instructions' address may mark it as a mips16 instruction.  If we
+   are single stepping, or the pc is within the disassembled function,
+   this works.  Otherwise, we need a clue.  Sometimes.  */
+
+static int
+_print_insn_mips (bfd_vma memaddr,
+		  struct disassemble_info *info,
+		  enum bfd_endian endianness)
+{
+  bfd_byte buffer[INSNLEN];
+  int status;
+
+  set_default_mips_dis_options (info);
+  parse_mips_dis_options (info->disassembler_options);
+
+#if 0
+#if 1
+  /* FIXME: If odd address, this is CLEARLY a mips 16 instruction.  */
+  /* Only a few tools will work this way.  */
+  if (memaddr & 0x01)
+    return print_insn_mips16 (memaddr, info);
+#endif
+
+#if SYMTAB_AVAILABLE
+  if (info->mach == bfd_mach_mips16
+      || (info->flavour == bfd_target_elf_flavour
+	  && info->symbols != NULL
+	  && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
+	      == STO_MIPS16)))
+    return print_insn_mips16 (memaddr, info);
+#endif
+#endif
+
+  status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
+  if (status == 0)
+    {
+      unsigned long insn;
+
+      if (endianness == BFD_ENDIAN_BIG)
+	insn = (unsigned long) bfd_getb32 (buffer);
+      else
+	insn = (unsigned long) bfd_getl32 (buffer);
+
+      return print_insn_mips (memaddr, insn, info);
+    }
+  else
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+}
+
+int
+print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info)
+{
+  return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
+}
+
+int
+print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
+{
+  return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
+}
+
+/* Disassemble mips16 instructions.  */
+#if 0
+static int
+print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int status;
+  bfd_byte buffer[2];
+  int length;
+  int insn;
+  bfd_boolean use_extend;
+  int extend = 0;
+  const struct mips_opcode *op, *opend;
+
+  info->bytes_per_chunk = 2;
+  info->display_endian = info->endian;
+  info->insn_info_valid = 1;
+  info->branch_delay_insns = 0;
+  info->data_size = 0;
+  info->insn_type = dis_nonbranch;
+  info->target = 0;
+  info->target2 = 0;
+
+  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  length = 2;
+
+  if (info->endian == BFD_ENDIAN_BIG)
+    insn = bfd_getb16 (buffer);
+  else
+    insn = bfd_getl16 (buffer);
+
+  /* Handle the extend opcode specially.  */
+  use_extend = FALSE;
+  if ((insn & 0xf800) == 0xf000)
+    {
+      use_extend = TRUE;
+      extend = insn & 0x7ff;
+
+      memaddr += 2;
+
+      status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+      if (status != 0)
+	{
+	  (*info->fprintf_func) (info->stream, "extend 0x%x",
+				 (unsigned int) extend);
+	  (*info->memory_error_func) (status, memaddr, info);
+	  return -1;
+	}
+
+      if (info->endian == BFD_ENDIAN_BIG)
+	insn = bfd_getb16 (buffer);
+      else
+	insn = bfd_getl16 (buffer);
+
+      /* Check for an extend opcode followed by an extend opcode.  */
+      if ((insn & 0xf800) == 0xf000)
+	{
+	  (*info->fprintf_func) (info->stream, "extend 0x%x",
+				 (unsigned int) extend);
+	  info->insn_type = dis_noninsn;
+	  return length;
+	}
+
+      length += 2;
+    }
+
+  /* FIXME: Should probably use a hash table on the major opcode here.  */
+
+  opend = mips16_opcodes + bfd_mips16_num_opcodes;
+  for (op = mips16_opcodes; op < opend; op++)
+    {
+      if (op->pinfo != INSN_MACRO
+	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	  && (insn & op->mask) == op->match)
+	{
+	  const char *s;
+
+	  if (strchr (op->args, 'a') != NULL)
+	    {
+	      if (use_extend)
+		{
+		  (*info->fprintf_func) (info->stream, "extend 0x%x",
+					 (unsigned int) extend);
+		  info->insn_type = dis_noninsn;
+		  return length - 2;
+		}
+
+	      use_extend = FALSE;
+
+	      memaddr += 2;
+
+	      status = (*info->read_memory_func) (memaddr, buffer, 2,
+						  info);
+	      if (status == 0)
+		{
+		  use_extend = TRUE;
+		  if (info->endian == BFD_ENDIAN_BIG)
+		    extend = bfd_getb16 (buffer);
+		  else
+		    extend = bfd_getl16 (buffer);
+		  length += 2;
+		}
+	    }
+
+	  (*info->fprintf_func) (info->stream, "%s", op->name);
+	  if (op->args[0] != '\0')
+	    (*info->fprintf_func) (info->stream, "\t");
+
+	  for (s = op->args; *s != '\0'; s++)
+	    {
+	      if (*s == ','
+		  && s[1] == 'w'
+		  && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
+		      == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
+		{
+		  /* Skip the register and the comma.  */
+		  ++s;
+		  continue;
+		}
+	      if (*s == ','
+		  && s[1] == 'v'
+		  && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
+		      == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
+		{
+		  /* Skip the register and the comma.  */
+		  ++s;
+		  continue;
+		}
+	      print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
+				     info);
+	    }
+
+	  if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
+	    {
+	      info->branch_delay_insns = 1;
+	      if (info->insn_type != dis_jsr)
+		info->insn_type = dis_branch;
+	    }
+
+	  return length;
+	}
+    }
+
+  if (use_extend)
+    (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
+  (*info->fprintf_func) (info->stream, "0x%x", insn);
+  info->insn_type = dis_noninsn;
+
+  return length;
+}
+
+/* Disassemble an operand for a mips16 instruction.  */
+
+static void
+print_mips16_insn_arg (char type,
+		       const struct mips_opcode *op,
+		       int l,
+		       bfd_boolean use_extend,
+		       int extend,
+		       bfd_vma memaddr,
+		       struct disassemble_info *info)
+{
+  switch (type)
+    {
+    case ',':
+    case '(':
+    case ')':
+      (*info->fprintf_func) (info->stream, "%c", type);
+      break;
+
+    case 'y':
+    case 'w':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips16_reg_names(((l >> MIPS16OP_SH_RY)
+					       & MIPS16OP_MASK_RY)));
+      break;
+
+    case 'x':
+    case 'v':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips16_reg_names(((l >> MIPS16OP_SH_RX)
+					       & MIPS16OP_MASK_RX)));
+      break;
+
+    case 'z':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips16_reg_names(((l >> MIPS16OP_SH_RZ)
+					       & MIPS16OP_MASK_RZ)));
+      break;
+
+    case 'Z':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z)
+					       & MIPS16OP_MASK_MOVE32Z)));
+      break;
+
+    case '0':
+      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
+      break;
+
+    case 'S':
+      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
+      break;
+
+    case 'P':
+      (*info->fprintf_func) (info->stream, "$pc");
+      break;
+
+    case 'R':
+      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
+      break;
+
+    case 'X':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
+					    & MIPS16OP_MASK_REGR32)]);
+      break;
+
+    case 'Y':
+      (*info->fprintf_func) (info->stream, "%s",
+			     mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
+      break;
+
+    case '<':
+    case '>':
+    case '[':
+    case ']':
+    case '4':
+    case '5':
+    case 'H':
+    case 'W':
+    case 'D':
+    case 'j':
+    case '6':
+    case '8':
+    case 'V':
+    case 'C':
+    case 'U':
+    case 'k':
+    case 'K':
+    case 'p':
+    case 'q':
+    case 'A':
+    case 'B':
+    case 'E':
+      {
+	int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
+
+	shift = 0;
+	signedp = 0;
+	extbits = 16;
+	pcrel = 0;
+	extu = 0;
+	branch = 0;
+	switch (type)
+	  {
+	  case '<':
+	    nbits = 3;
+	    immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
+	    extbits = 5;
+	    extu = 1;
+	    break;
+	  case '>':
+	    nbits = 3;
+	    immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
+	    extbits = 5;
+	    extu = 1;
+	    break;
+	  case '[':
+	    nbits = 3;
+	    immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
+	    extbits = 6;
+	    extu = 1;
+	    break;
+	  case ']':
+	    nbits = 3;
+	    immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
+	    extbits = 6;
+	    extu = 1;
+	    break;
+	  case '4':
+	    nbits = 4;
+	    immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
+	    signedp = 1;
+	    extbits = 15;
+	    break;
+	  case '5':
+	    nbits = 5;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    info->insn_type = dis_dref;
+	    info->data_size = 1;
+	    break;
+	  case 'H':
+	    nbits = 5;
+	    shift = 1;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    info->insn_type = dis_dref;
+	    info->data_size = 2;
+	    break;
+	  case 'W':
+	    nbits = 5;
+	    shift = 2;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
+		&& (op->pinfo & MIPS16_INSN_READ_SP) == 0)
+	      {
+		info->insn_type = dis_dref;
+		info->data_size = 4;
+	      }
+	    break;
+	  case 'D':
+	    nbits = 5;
+	    shift = 3;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    info->insn_type = dis_dref;
+	    info->data_size = 8;
+	    break;
+	  case 'j':
+	    nbits = 5;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    signedp = 1;
+	    break;
+	  case '6':
+	    nbits = 6;
+	    immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
+	    break;
+	  case '8':
+	    nbits = 8;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    break;
+	  case 'V':
+	    nbits = 8;
+	    shift = 2;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    /* FIXME: This might be lw, or it might be addiu to $sp or
+               $pc.  We assume it's load.  */
+	    info->insn_type = dis_dref;
+	    info->data_size = 4;
+	    break;
+	  case 'C':
+	    nbits = 8;
+	    shift = 3;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    info->insn_type = dis_dref;
+	    info->data_size = 8;
+	    break;
+	  case 'U':
+	    nbits = 8;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    extu = 1;
+	    break;
+	  case 'k':
+	    nbits = 8;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    signedp = 1;
+	    break;
+	  case 'K':
+	    nbits = 8;
+	    shift = 3;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    signedp = 1;
+	    break;
+	  case 'p':
+	    nbits = 8;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    signedp = 1;
+	    pcrel = 1;
+	    branch = 1;
+	    info->insn_type = dis_condbranch;
+	    break;
+	  case 'q':
+	    nbits = 11;
+	    immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
+	    signedp = 1;
+	    pcrel = 1;
+	    branch = 1;
+	    info->insn_type = dis_branch;
+	    break;
+	  case 'A':
+	    nbits = 8;
+	    shift = 2;
+	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
+	    pcrel = 1;
+	    /* FIXME: This can be lw or la.  We assume it is lw.  */
+	    info->insn_type = dis_dref;
+	    info->data_size = 4;
+	    break;
+	  case 'B':
+	    nbits = 5;
+	    shift = 3;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    pcrel = 1;
+	    info->insn_type = dis_dref;
+	    info->data_size = 8;
+	    break;
+	  case 'E':
+	    nbits = 5;
+	    shift = 2;
+	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
+	    pcrel = 1;
+	    break;
+	  default:
+	    abort ();
+	  }
+
+	if (! use_extend)
+	  {
+	    if (signedp && immed >= (1 << (nbits - 1)))
+	      immed -= 1 << nbits;
+	    immed <<= shift;
+	    if ((type == '<' || type == '>' || type == '[' || type == ']')
+		&& immed == 0)
+	      immed = 8;
+	  }
+	else
+	  {
+	    if (extbits == 16)
+	      immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
+	    else if (extbits == 15)
+	      immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
+	    else
+	      immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
+	    immed &= (1 << extbits) - 1;
+	    if (! extu && immed >= (1 << (extbits - 1)))
+	      immed -= 1 << extbits;
+	  }
+
+	if (! pcrel)
+	  (*info->fprintf_func) (info->stream, "%d", immed);
+	else
+	  {
+	    bfd_vma baseaddr;
+
+	    if (branch)
+	      {
+		immed *= 2;
+		baseaddr = memaddr + 2;
+	      }
+	    else if (use_extend)
+	      baseaddr = memaddr - 2;
+	    else
+	      {
+		int status;
+		bfd_byte buffer[2];
+
+		baseaddr = memaddr;
+
+		/* If this instruction is in the delay slot of a jr
+                   instruction, the base address is the address of the
+                   jr instruction.  If it is in the delay slot of jalr
+                   instruction, the base address is the address of the
+                   jalr instruction.  This test is unreliable: we have
+                   no way of knowing whether the previous word is
+                   instruction or data.  */
+		status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
+						    info);
+		if (status == 0
+		    && (((info->endian == BFD_ENDIAN_BIG
+			  ? bfd_getb16 (buffer)
+			  : bfd_getl16 (buffer))
+			 & 0xf800) == 0x1800))
+		  baseaddr = memaddr - 4;
+		else
+		  {
+		    status = (*info->read_memory_func) (memaddr - 2, buffer,
+							2, info);
+		    if (status == 0
+			&& (((info->endian == BFD_ENDIAN_BIG
+			      ? bfd_getb16 (buffer)
+			      : bfd_getl16 (buffer))
+			     & 0xf81f) == 0xe800))
+		      baseaddr = memaddr - 2;
+		  }
+	      }
+	    info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
+	    if (pcrel && branch
+		&& info->flavour == bfd_target_unknown_flavour)
+	      /* For gdb disassembler, maintain odd address.  */
+	      info->target |= 1;
+	    (*info->print_address_func) (info->target, info);
+	  }
+      }
+      break;
+
+    case 'a':
+      {
+	int jalx = l & 0x400;
+
+	if (! use_extend)
+	  extend = 0;
+	l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+	if (!jalx && info->flavour == bfd_target_unknown_flavour)
+	  /* For gdb disassembler, maintain odd address.  */
+	  l |= 1;
+      }
+      info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
+      (*info->print_address_func) (info->target, info);
+      info->insn_type = dis_jsr;
+      info->branch_delay_insns = 1;
+      break;
+
+    case 'l':
+    case 'L':
+      {
+	int need_comma, amask, smask;
+
+	need_comma = 0;
+
+	l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
+
+	amask = (l >> 3) & 7;
+
+	if (amask > 0 && amask < 5)
+	  {
+	    (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+	    if (amask > 1)
+	      (*info->fprintf_func) (info->stream, "-%s",
+				     mips_gpr_names[amask + 3]);
+	    need_comma = 1;
+	  }
+
+	smask = (l >> 1) & 3;
+	if (smask == 3)
+	  {
+	    (*info->fprintf_func) (info->stream, "%s??",
+				   need_comma ? "," : "");
+	    need_comma = 1;
+	  }
+	else if (smask > 0)
+	  {
+	    (*info->fprintf_func) (info->stream, "%s%s",
+				   need_comma ? "," : "",
+				   mips_gpr_names[16]);
+	    if (smask > 1)
+	      (*info->fprintf_func) (info->stream, "-%s",
+				     mips_gpr_names[smask + 15]);
+	    need_comma = 1;
+	  }
+
+	if (l & 1)
+	  {
+	    (*info->fprintf_func) (info->stream, "%s%s",
+				   need_comma ? "," : "",
+				   mips_gpr_names[31]);
+	    need_comma = 1;
+	  }
+
+	if (amask == 5 || amask == 6)
+	  {
+	    (*info->fprintf_func) (info->stream, "%s$f0",
+				   need_comma ? "," : "");
+	    if (amask == 6)
+	      (*info->fprintf_func) (info->stream, "-$f1");
+	  }
+      }
+      break;
+
+    case 'm':
+    case 'M':
+      /* MIPS16e save/restore.  */
+      {
+      int need_comma = 0;
+      int amask, args, statics;
+      int nsreg, smask;
+      int framesz;
+      int i, j;
+
+      l = l & 0x7f;
+      if (use_extend)
+        l |= extend << 16;
+
+      amask = (l >> 16) & 0xf;
+      if (amask == MIPS16_ALL_ARGS)
+        {
+          args = 4;
+          statics = 0;
+        }
+      else if (amask == MIPS16_ALL_STATICS)
+        {
+          args = 0;
+          statics = 4;
+        }
+      else
+        {
+          args = amask >> 2;
+          statics = amask & 3;
+        }
+
+      if (args > 0) {
+          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+          if (args > 1)
+            (*info->fprintf_func) (info->stream, "-%s",
+                                   mips_gpr_names[4 + args - 1]);
+          need_comma = 1;
+      }
+
+      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
+      if (framesz == 0 && !use_extend)
+        framesz = 128;
+
+      (*info->fprintf_func) (info->stream, "%s%d",
+                             need_comma ? "," : "",
+                             framesz);
+
+      if (l & 0x40)                   /* $ra */
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
+
+      nsreg = (l >> 24) & 0x7;
+      smask = 0;
+      if (l & 0x20)                   /* $s0 */
+        smask |= 1 << 0;
+      if (l & 0x10)                   /* $s1 */
+        smask |= 1 << 1;
+      if (nsreg > 0)                  /* $s2-$s8 */
+        smask |= ((1 << nsreg) - 1) << 2;
+
+      /* Find first set static reg bit.  */
+      for (i = 0; i < 9; i++)
+        {
+          if (smask & (1 << i))
+            {
+              (*info->fprintf_func) (info->stream, ",%s",
+                                     mips_gpr_names[i == 8 ? 30 : (16 + i)]);
+              /* Skip over string of set bits.  */
+              for (j = i; smask & (2 << j); j++)
+                continue;
+              if (j > i)
+                (*info->fprintf_func) (info->stream, "-%s",
+                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+              i = j + 1;
+            }
+        }
+
+      /* Statics $ax - $a3.  */
+      if (statics == 1)
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+      else if (statics > 0)
+        (*info->fprintf_func) (info->stream, ",%s-%s",
+                               mips_gpr_names[7 - statics + 1],
+                               mips_gpr_names[7]);
+      }
+      break;
+
+    default:
+      /* xgettext:c-format */
+      (*info->fprintf_func)
+	(info->stream,
+	 _("# internal disassembler error, unrecognised modifier (%c)"),
+	 type);
+      abort ();
+    }
+}
+
+void
+print_mips_disassembler_options (FILE *stream)
+{
+  unsigned int i;
+
+  fprintf (stream, _("\n\
+The following MIPS specific disassembler options are supported for use\n\
+with the -M switch (multiple options should be separated by commas):\n"));
+
+  fprintf (stream, _("\n\
+  gpr-names=ABI            Print GPR names according to  specified ABI.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  fpr-names=ABI            Print FPR names according to specified ABI.\n\
+                           Default: numeric.\n"));
+
+  fprintf (stream, _("\n\
+  cp0-names=ARCH           Print CP0 register names according to\n\
+                           specified architecture.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  hwr-names=ARCH           Print HWR names according to specified \n\
+			   architecture.\n\
+                           Default: based on binary being disassembled.\n"));
+
+  fprintf (stream, _("\n\
+  reg-names=ABI            Print GPR and FPR names according to\n\
+                           specified ABI.\n"));
+
+  fprintf (stream, _("\n\
+  reg-names=ARCH           Print CP0 register and HWR names according to\n\
+                           specified architecture.\n"));
+
+  fprintf (stream, _("\n\
+  For the options above, the following values are supported for \"ABI\":\n\
+   "));
+  for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
+    fprintf (stream, " %s", mips_abi_choices[i].name);
+  fprintf (stream, _("\n"));
+
+  fprintf (stream, _("\n\
+  For the options above, The following values are supported for \"ARCH\":\n\
+   "));
+  for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
+    if (*mips_arch_choices[i].name != '\0')
+      fprintf (stream, " %s", mips_arch_choices[i].name);
+  fprintf (stream, _("\n"));
+
+  fprintf (stream, _("\n"));
+}
+#endif
diff --git a/qemu-0.15.x/mips.ld b/qemu-0.15.x/mips.ld
new file mode 100644
index 0000000..7b610ce
--- /dev/null
+++ b/qemu-0.15.x/mips.ld
@@ -0,0 +1,222 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips",
+             "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .reginfo        : { *(.reginfo) }
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x47ff041f
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    _ftext = . ;
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.mips16.fn.*) *(.mips16.call.*)
+  } =0x47ff041f
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x47ff041f
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
+  /* Exception handling  */
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    _fdata = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  . = .;
+  _gp = ALIGN(16) + 0x7ff0;
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  .lit8           : { *(.lit8) }
+  .lit4           : { *(.lit4) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  _fbss = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/qemu-0.15.x/module.c b/qemu-0.15.x/module.c
new file mode 100644
index 0000000..e77d569
--- /dev/null
+++ b/qemu-0.15.x/module.c
@@ -0,0 +1,80 @@
+/*
+ * QEMU Module Infrastructure
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "module.h"
+
+typedef struct ModuleEntry
+{
+    module_init_type type;
+    void (*init)(void);
+    QTAILQ_ENTRY(ModuleEntry) node;
+} ModuleEntry;
+
+typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
+
+static ModuleTypeList init_type_list[MODULE_INIT_MAX];
+
+static void init_types(void)
+{
+    static int inited;
+    int i;
+
+    if (inited) {
+        return;
+    }
+
+    for (i = 0; i < MODULE_INIT_MAX; i++) {
+        QTAILQ_INIT(&init_type_list[i]);
+    }
+
+    inited = 1;
+}
+
+
+static ModuleTypeList *find_type(module_init_type type)
+{
+    ModuleTypeList *l;
+
+    init_types();
+
+    l = &init_type_list[type];
+
+    return l;
+}
+
+void register_module_init(void (*fn)(void), module_init_type type)
+{
+    ModuleEntry *e;
+    ModuleTypeList *l;
+
+    e = qemu_mallocz(sizeof(*e));
+    e->init = fn;
+
+    l = find_type(type);
+
+    QTAILQ_INSERT_TAIL(l, e, node);
+}
+
+void module_call_init(module_init_type type)
+{
+    ModuleTypeList *l;
+    ModuleEntry *e;
+
+    l = find_type(type);
+
+    QTAILQ_FOREACH(e, l, node) {
+        e->init();
+    }
+}
diff --git a/qemu-0.15.x/module.h b/qemu-0.15.x/module.h
new file mode 100644
index 0000000..ef66730
--- /dev/null
+++ b/qemu-0.15.x/module.h
@@ -0,0 +1,40 @@
+/*
+ * QEMU Module Infrastructure
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_MODULE_H
+#define QEMU_MODULE_H
+
+/* This should not be used directly.  Use block_init etc. instead.  */
+#define module_init(function, type)                                         \
+static void __attribute__((constructor)) do_qemu_init_ ## function(void) {  \
+    register_module_init(function, type);                                   \
+}
+
+typedef enum {
+    MODULE_INIT_BLOCK,
+    MODULE_INIT_DEVICE,
+    MODULE_INIT_MACHINE,
+    MODULE_INIT_QAPI,
+    MODULE_INIT_MAX
+} module_init_type;
+
+#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
+#define device_init(function) module_init(function, MODULE_INIT_DEVICE)
+#define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
+#define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
+
+void register_module_init(void (*fn)(void), module_init_type type);
+
+void module_call_init(module_init_type type);
+
+#endif
diff --git a/qemu-0.15.x/monitor.c b/qemu-0.15.x/monitor.c
new file mode 100644
index 0000000..fee572c
--- /dev/null
+++ b/qemu-0.15.x/monitor.c
@@ -0,0 +1,5333 @@
+/*
+ * 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 <dirent.h>
+#include "hw/hw.h"
+#include "hw/qdev.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "hw/watchdog.h"
+#include "hw/loader.h"
+#include "gdbstub.h"
+#include "net.h"
+#include "net/slirp.h"
+#include "qemu-char.h"
+#include "ui/qemu-spice.h"
+#include "sysemu.h"
+#include "monitor.h"
+#include "readline.h"
+#include "console.h"
+#include "blockdev.h"
+#include "audio/audio.h"
+#include "disas.h"
+#include "balloon.h"
+#include "qemu-timer.h"
+#include "migration.h"
+#include "kvm.h"
+#include "acl.h"
+#include "qint.h"
+#include "qfloat.h"
+#include "qlist.h"
+#include "qbool.h"
+#include "qstring.h"
+#include "qjson.h"
+#include "json-streamer.h"
+#include "json-parser.h"
+#include "osdep.h"
+#include "cpu.h"
+#ifdef CONFIG_SIMPLE_TRACE
+#include "trace.h"
+#endif
+#include "ui/qemu-spice.h"
+
+//#define DEBUG
+//#define DEBUG_COMPLETION
+
+/*
+ * Supported types:
+ *
+ * 'F'          filename
+ * 'B'          block device name
+ * 's'          string (accept optional quote)
+ * 'O'          option string of the form NAME=VALUE,...
+ *              parsed according to QemuOptsList given by its name
+ *              Example: 'device:O' uses qemu_device_opts.
+ *              Restriction: only lists with empty desc are supported
+ *              TODO lift the restriction
+ * 'i'          32 bit integer
+ * 'l'          target long (32 or 64 bit)
+ * 'M'          just like 'l', except in user mode the value is
+ *              multiplied by 2^20 (think Mebibyte)
+ * 'o'          octets (aka bytes)
+ *              user mode accepts an optional T, t, G, g, M, m, K, k
+ *              suffix, which multiplies the value by 2^40 for
+ *              suffixes T and t, 2^30 for suffixes G and g, 2^20 for
+ *              M and m, 2^10 for K and k
+ * 'T'          double
+ *              user mode accepts an optional ms, us, ns suffix,
+ *              which divides the value by 1e3, 1e6, 1e9, respectively
+ * '/'          optional gdb-like print format (like "/10x")
+ *
+ * '?'          optional type (for all types, except '/')
+ * '.'          other form of optional type (for 'i' and 'l')
+ * 'b'          boolean
+ *              user mode accepts "on" or "off"
+ * '-'          optional parameter (eg. '-f')
+ *
+ */
+
+typedef struct MonitorCompletionData MonitorCompletionData;
+struct MonitorCompletionData {
+    Monitor *mon;
+    void (*user_print)(Monitor *mon, const QObject *data);
+};
+
+typedef struct mon_cmd_t {
+    const char *name;
+    const char *args_type;
+    const char *params;
+    const char *help;
+    void (*user_print)(Monitor *mon, const QObject *data);
+    union {
+        void (*info)(Monitor *mon);
+        void (*info_new)(Monitor *mon, QObject **ret_data);
+        int  (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
+        void (*cmd)(Monitor *mon, const QDict *qdict);
+        int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+        int  (*cmd_async)(Monitor *mon, const QDict *params,
+                          MonitorCompletion *cb, void *opaque);
+    } mhandler;
+    int flags;
+} mon_cmd_t;
+
+/* file descriptors passed via SCM_RIGHTS */
+typedef struct mon_fd_t mon_fd_t;
+struct mon_fd_t {
+    char *name;
+    int fd;
+    QLIST_ENTRY(mon_fd_t) next;
+};
+
+typedef struct MonitorControl {
+    QObject *id;
+    JSONMessageParser parser;
+    int command_mode;
+} MonitorControl;
+
+struct Monitor {
+    CharDriverState *chr;
+    int mux_out;
+    int reset_seen;
+    int flags;
+    int suspend_cnt;
+    uint8_t outbuf[1024];
+    int outbuf_index;
+    ReadLineState *rs;
+    MonitorControl *mc;
+    CPUState *mon_cpu;
+    BlockDriverCompletionFunc *password_completion_cb;
+    void *password_opaque;
+#ifdef CONFIG_DEBUG_MONITOR
+    int print_calls_nr;
+#endif
+    QError *error;
+    QLIST_HEAD(,mon_fd_t) fds;
+    QLIST_ENTRY(Monitor) entry;
+};
+
+#ifdef CONFIG_DEBUG_MONITOR
+#define MON_DEBUG(fmt, ...) do {    \
+    fprintf(stderr, "Monitor: ");       \
+    fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+static inline void mon_print_count_inc(Monitor *mon)
+{
+    mon->print_calls_nr++;
+}
+
+static inline void mon_print_count_init(Monitor *mon)
+{
+    mon->print_calls_nr = 0;
+}
+
+static inline int mon_print_count_get(const Monitor *mon)
+{
+    return mon->print_calls_nr;
+}
+
+#else /* !CONFIG_DEBUG_MONITOR */
+#define MON_DEBUG(fmt, ...) do { } while (0)
+static inline void mon_print_count_inc(Monitor *mon) { }
+static inline void mon_print_count_init(Monitor *mon) { }
+static inline int mon_print_count_get(const Monitor *mon) { return 0; }
+#endif /* CONFIG_DEBUG_MONITOR */
+
+/* QMP checker flags */
+#define QMP_ACCEPT_UNKNOWNS 1
+
+static QLIST_HEAD(mon_list, Monitor) mon_list;
+
+static const mon_cmd_t mon_cmds[];
+static const mon_cmd_t info_cmds[];
+
+static const mon_cmd_t qmp_cmds[];
+static const mon_cmd_t qmp_query_cmds[];
+
+Monitor *cur_mon;
+Monitor *default_mon;
+
+static void monitor_command_cb(Monitor *mon, const char *cmdline,
+                               void *opaque);
+
+static inline int qmp_cmd_mode(const Monitor *mon)
+{
+    return (mon->mc ? mon->mc->command_mode : 0);
+}
+
+/* Return true if in control mode, false otherwise */
+static inline int monitor_ctrl_mode(const Monitor *mon)
+{
+    return (mon->flags & MONITOR_USE_CONTROL);
+}
+
+/* Return non-zero iff we have a current monitor, and it is in QMP mode.  */
+int monitor_cur_is_qmp(void)
+{
+    return cur_mon && monitor_ctrl_mode(cur_mon);
+}
+
+static void monitor_read_command(Monitor *mon, int show_prompt)
+{
+    if (!mon->rs)
+        return;
+
+    readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
+    if (show_prompt)
+        readline_show_prompt(mon->rs);
+}
+
+static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+                                 void *opaque)
+{
+    if (monitor_ctrl_mode(mon)) {
+        qerror_report(QERR_MISSING_PARAMETER, "password");
+        return -EINVAL;
+    } else if (mon->rs) {
+        readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
+        /* prompt is printed on return from the command handler */
+        return 0;
+    } else {
+        monitor_printf(mon, "terminal does not support password prompting\n");
+        return -ENOTTY;
+    }
+}
+
+void monitor_flush(Monitor *mon)
+{
+    if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
+        qemu_chr_write(mon->chr, mon->outbuf, mon->outbuf_index);
+        mon->outbuf_index = 0;
+    }
+}
+
+/* flush at every end of line or if the buffer is full */
+static void monitor_puts(Monitor *mon, const char *str)
+{
+    char c;
+
+    for(;;) {
+        c = *str++;
+        if (c == '\0')
+            break;
+        if (c == '\n')
+            mon->outbuf[mon->outbuf_index++] = '\r';
+        mon->outbuf[mon->outbuf_index++] = c;
+        if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1)
+            || c == '\n')
+            monitor_flush(mon);
+    }
+}
+
+void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
+{
+    char buf[4096];
+
+    if (!mon)
+        return;
+
+    mon_print_count_inc(mon);
+
+    if (monitor_ctrl_mode(mon)) {
+        return;
+    }
+
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    monitor_puts(mon, buf);
+}
+
+void monitor_printf(Monitor *mon, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    monitor_vprintf(mon, fmt, ap);
+    va_end(ap);
+}
+
+void monitor_print_filename(Monitor *mon, const char *filename)
+{
+    int i;
+
+    for (i = 0; filename[i]; i++) {
+        switch (filename[i]) {
+        case ' ':
+        case '"':
+        case '\\':
+            monitor_printf(mon, "\\%c", filename[i]);
+            break;
+        case '\t':
+            monitor_printf(mon, "\\t");
+            break;
+        case '\r':
+            monitor_printf(mon, "\\r");
+            break;
+        case '\n':
+            monitor_printf(mon, "\\n");
+            break;
+        default:
+            monitor_printf(mon, "%c", filename[i]);
+            break;
+        }
+    }
+}
+
+static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream,
+                                              const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    monitor_vprintf((Monitor *)stream, fmt, ap);
+    va_end(ap);
+    return 0;
+}
+
+static void monitor_user_noop(Monitor *mon, const QObject *data) { }
+
+static inline int handler_is_qobject(const mon_cmd_t *cmd)
+{
+    return cmd->user_print != NULL;
+}
+
+static inline bool handler_is_async(const mon_cmd_t *cmd)
+{
+    return cmd->flags & MONITOR_CMD_ASYNC;
+}
+
+static inline int monitor_has_error(const Monitor *mon)
+{
+    return mon->error != NULL;
+}
+
+static void monitor_json_emitter(Monitor *mon, const QObject *data)
+{
+    QString *json;
+
+    json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) :
+                                             qobject_to_json(data);
+    assert(json != NULL);
+
+    qstring_append_chr(json, '\n');
+    monitor_puts(mon, qstring_get_str(json));
+
+    QDECREF(json);
+}
+
+static void monitor_protocol_emitter(Monitor *mon, QObject *data)
+{
+    QDict *qmp;
+
+    qmp = qdict_new();
+
+    if (!monitor_has_error(mon)) {
+        /* success response */
+        if (data) {
+            qobject_incref(data);
+            qdict_put_obj(qmp, "return", data);
+        } else {
+            /* return an empty QDict by default */
+            qdict_put(qmp, "return", qdict_new());
+        }
+    } else {
+        /* error response */
+        qdict_put(mon->error->error, "desc", qerror_human(mon->error));
+        qdict_put(qmp, "error", mon->error->error);
+        QINCREF(mon->error->error);
+        QDECREF(mon->error);
+        mon->error = NULL;
+    }
+
+    if (mon->mc->id) {
+        qdict_put_obj(qmp, "id", mon->mc->id);
+        mon->mc->id = NULL;
+    }
+
+    monitor_json_emitter(mon, QOBJECT(qmp));
+    QDECREF(qmp);
+}
+
+static void timestamp_put(QDict *qdict)
+{
+    int err;
+    QObject *obj;
+    qemu_timeval tv;
+
+    err = qemu_gettimeofday(&tv);
+    if (err < 0)
+        return;
+
+    obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
+                                "'microseconds': %" PRId64 " }",
+                                (int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
+    qdict_put_obj(qdict, "timestamp", obj);
+}
+
+/**
+ * monitor_protocol_event(): Generate a Monitor event
+ *
+ * Event-specific data can be emitted through the (optional) 'data' parameter.
+ */
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+    QDict *qmp;
+    const char *event_name;
+    Monitor *mon;
+
+    assert(event < QEVENT_MAX);
+
+    switch (event) {
+        case QEVENT_SHUTDOWN:
+            event_name = "SHUTDOWN";
+            break;
+        case QEVENT_RESET:
+            event_name = "RESET";
+            break;
+        case QEVENT_POWERDOWN:
+            event_name = "POWERDOWN";
+            break;
+        case QEVENT_STOP:
+            event_name = "STOP";
+            break;
+        case QEVENT_RESUME:
+            event_name = "RESUME";
+            break;
+        case QEVENT_VNC_CONNECTED:
+            event_name = "VNC_CONNECTED";
+            break;
+        case QEVENT_VNC_INITIALIZED:
+            event_name = "VNC_INITIALIZED";
+            break;
+        case QEVENT_VNC_DISCONNECTED:
+            event_name = "VNC_DISCONNECTED";
+            break;
+        case QEVENT_BLOCK_IO_ERROR:
+            event_name = "BLOCK_IO_ERROR";
+            break;
+        case QEVENT_RTC_CHANGE:
+            event_name = "RTC_CHANGE";
+            break;
+        case QEVENT_WATCHDOG:
+            event_name = "WATCHDOG";
+            break;
+        case QEVENT_SPICE_CONNECTED:
+            event_name = "SPICE_CONNECTED";
+            break;
+        case QEVENT_SPICE_INITIALIZED:
+            event_name = "SPICE_INITIALIZED";
+            break;
+        case QEVENT_SPICE_DISCONNECTED:
+            event_name = "SPICE_DISCONNECTED";
+            break;
+        default:
+            abort();
+            break;
+    }
+
+    qmp = qdict_new();
+    timestamp_put(qmp);
+    qdict_put(qmp, "event", qstring_from_str(event_name));
+    if (data) {
+        qobject_incref(data);
+        qdict_put_obj(qmp, "data", data);
+    }
+
+    QLIST_FOREACH(mon, &mon_list, entry) {
+        if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
+            monitor_json_emitter(mon, QOBJECT(qmp));
+        }
+    }
+    QDECREF(qmp);
+}
+
+static int do_qmp_capabilities(Monitor *mon, const QDict *params,
+                               QObject **ret_data)
+{
+    /* Will setup QMP capabilities in the future */
+    if (monitor_ctrl_mode(mon)) {
+        mon->mc->command_mode = 1;
+    }
+
+    return 0;
+}
+
+static int mon_set_cpu(int cpu_index);
+static void handle_user_command(Monitor *mon, const char *cmdline);
+
+static int do_hmp_passthrough(Monitor *mon, const QDict *params,
+                              QObject **ret_data)
+{
+    int ret = 0;
+    Monitor *old_mon, hmp;
+    CharDriverState mchar;
+
+    memset(&hmp, 0, sizeof(hmp));
+    qemu_chr_init_mem(&mchar);
+    hmp.chr = &mchar;
+
+    old_mon = cur_mon;
+    cur_mon = &hmp;
+
+    if (qdict_haskey(params, "cpu-index")) {
+        ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+        if (ret < 0) {
+            cur_mon = old_mon;
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
+            goto out;
+        }
+    }
+
+    handle_user_command(&hmp, qdict_get_str(params, "command-line"));
+    cur_mon = old_mon;
+
+    if (qemu_chr_mem_osize(hmp.chr) > 0) {
+        *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr));
+    }
+
+out:
+    qemu_chr_close_mem(hmp.chr);
+    return ret;
+}
+
+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_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
+                          const char *prefix, const char *name)
+{
+    const mon_cmd_t *cmd;
+
+    for(cmd = cmds; cmd->name != NULL; cmd++) {
+        if (!name || !strcmp(name, cmd->name))
+            monitor_printf(mon, "%s%s %s -- %s\n", prefix, cmd->name,
+                           cmd->params, cmd->help);
+    }
+}
+
+static void help_cmd(Monitor *mon, const char *name)
+{
+    if (name && !strcmp(name, "info")) {
+        help_cmd_dump(mon, info_cmds, "info ", NULL);
+    } else {
+        help_cmd_dump(mon, mon_cmds, "", name);
+        if (name && !strcmp(name, "log")) {
+            const CPULogItem *item;
+            monitor_printf(mon, "Log items (comma separated):\n");
+            monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                monitor_printf(mon, "%-10s %s\n", item->name, item->help);
+            }
+        }
+    }
+}
+
+static void do_help_cmd(Monitor *mon, const QDict *qdict)
+{
+    help_cmd(mon, qdict_get_try_str(qdict, "name"));
+}
+
+#ifdef CONFIG_SIMPLE_TRACE
+static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
+{
+    const char *tp_name = qdict_get_str(qdict, "name");
+    bool new_state = qdict_get_bool(qdict, "option");
+    int ret = st_change_trace_event_state(tp_name, new_state);
+
+    if (!ret) {
+        monitor_printf(mon, "unknown event name \"%s\"\n", tp_name);
+    }
+}
+
+static void do_trace_file(Monitor *mon, const QDict *qdict)
+{
+    const char *op = qdict_get_try_str(qdict, "op");
+    const char *arg = qdict_get_try_str(qdict, "arg");
+
+    if (!op) {
+        st_print_trace_file_status((FILE *)mon, &monitor_fprintf);
+    } else if (!strcmp(op, "on")) {
+        st_set_trace_file_enabled(true);
+    } else if (!strcmp(op, "off")) {
+        st_set_trace_file_enabled(false);
+    } else if (!strcmp(op, "flush")) {
+        st_flush_trace_buffer();
+    } else if (!strcmp(op, "set")) {
+        if (arg) {
+            st_set_trace_file(arg);
+        }
+    } else {
+        monitor_printf(mon, "unexpected argument \"%s\"\n", op);
+        help_cmd(mon, "trace-file");
+    }
+}
+#endif
+
+static void user_monitor_complete(void *opaque, QObject *ret_data)
+{
+    MonitorCompletionData *data = (MonitorCompletionData *)opaque; 
+
+    if (ret_data) {
+        data->user_print(data->mon, ret_data);
+    }
+    monitor_resume(data->mon);
+    qemu_free(data);
+}
+
+static void qmp_monitor_complete(void *opaque, QObject *ret_data)
+{
+    monitor_protocol_emitter(opaque, ret_data);
+}
+
+static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
+                                 const QDict *params)
+{
+    return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
+}
+
+static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
+{
+    cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
+}
+
+static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
+                                   const QDict *params)
+{
+    int ret;
+
+    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
+    cb_data->mon = mon;
+    cb_data->user_print = cmd->user_print;
+    monitor_suspend(mon);
+    ret = cmd->mhandler.cmd_async(mon, params,
+                                  user_monitor_complete, cb_data);
+    if (ret < 0) {
+        monitor_resume(mon);
+        qemu_free(cb_data);
+    }
+}
+
+static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
+{
+    int ret;
+
+    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
+    cb_data->mon = mon;
+    cb_data->user_print = cmd->user_print;
+    monitor_suspend(mon);
+    ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
+    if (ret < 0) {
+        monitor_resume(mon);
+        qemu_free(cb_data);
+    }
+}
+
+static void do_info(Monitor *mon, const QDict *qdict)
+{
+    const mon_cmd_t *cmd;
+    const char *item = qdict_get_try_str(qdict, "item");
+
+    if (!item) {
+        goto help;
+    }
+
+    for (cmd = info_cmds; cmd->name != NULL; cmd++) {
+        if (compare_cmd(item, cmd->name))
+            break;
+    }
+
+    if (cmd->name == NULL) {
+        goto help;
+    }
+
+    if (handler_is_async(cmd)) {
+        user_async_info_handler(mon, cmd);
+    } else if (handler_is_qobject(cmd)) {
+        QObject *info_data = NULL;
+
+        cmd->mhandler.info_new(mon, &info_data);
+        if (info_data) {
+            cmd->user_print(mon, info_data);
+            qobject_decref(info_data);
+        }
+    } else {
+        cmd->mhandler.info(mon);
+    }
+
+    return;
+
+help:
+    help_cmd(mon, "info");
+}
+
+static void do_info_version_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+    QDict *qemu;
+
+    qdict = qobject_to_qdict(data);
+    qemu = qdict_get_qdict(qdict, "qemu");
+
+    monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
+                  qdict_get_int(qemu, "major"),
+                  qdict_get_int(qemu, "minor"),
+                  qdict_get_int(qemu, "micro"),
+                  qdict_get_str(qdict, "package"));
+}
+
+static void do_info_version(Monitor *mon, QObject **ret_data)
+{
+    const char *version = QEMU_VERSION;
+    int major = 0, minor = 0, micro = 0;
+    char *tmp;
+
+    major = strtol(version, &tmp, 10);
+    tmp++;
+    minor = strtol(tmp, &tmp, 10);
+    tmp++;
+    micro = strtol(tmp, &tmp, 10);
+
+    *ret_data = qobject_from_jsonf("{ 'qemu': { 'major': %d, 'minor': %d, \
+        'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION);
+}
+
+static void do_info_name_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+    if (qdict_size(qdict) == 0) {
+        return;
+    }
+
+    monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name"));
+}
+
+static void do_info_name(Monitor *mon, QObject **ret_data)
+{
+    *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) :
+                            qobject_from_jsonf("{}");
+}
+
+static QObject *get_cmd_dict(const char *name)
+{
+    const char *p;
+
+    /* Remove '|' from some commands */
+    p = strchr(name, '|');
+    if (p) {
+        p++;
+    } else {
+        p = name;
+    }
+
+    return qobject_from_jsonf("{ 'name': %s }", p);
+}
+
+static void do_info_commands(Monitor *mon, QObject **ret_data)
+{
+    QList *cmd_list;
+    const mon_cmd_t *cmd;
+
+    cmd_list = qlist_new();
+
+    for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
+        qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
+    }
+
+    for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
+        char buf[128];
+        snprintf(buf, sizeof(buf), "query-%s", cmd->name);
+        qlist_append_obj(cmd_list, get_cmd_dict(buf));
+    }
+
+    *ret_data = QOBJECT(cmd_list);
+}
+
+static void do_info_uuid_print(Monitor *mon, const QObject *data)
+{
+    monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
+}
+
+static void do_info_uuid(Monitor *mon, QObject **ret_data)
+{
+    char uuid[64];
+
+    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
+                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
+                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
+                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
+                   qemu_uuid[14], qemu_uuid[15]);
+    *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid);
+}
+
+/* get the current CPU defined by the user */
+static int mon_set_cpu(int cpu_index)
+{
+    CPUState *env;
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index == cpu_index) {
+            cur_mon->mon_cpu = env;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static CPUState *mon_get_cpu(void)
+{
+    if (!cur_mon->mon_cpu) {
+        mon_set_cpu(0);
+    }
+    cpu_synchronize_state(cur_mon->mon_cpu);
+    return cur_mon->mon_cpu;
+}
+
+static void do_info_registers(Monitor *mon)
+{
+    CPUState *env;
+    env = mon_get_cpu();
+#ifdef TARGET_I386
+    cpu_dump_state(env, (FILE *)mon, monitor_fprintf,
+                   X86_DUMP_FPU);
+#else
+    cpu_dump_state(env, (FILE *)mon, monitor_fprintf,
+                   0);
+#endif
+}
+
+static void print_cpu_iter(QObject *obj, void *opaque)
+{
+    QDict *cpu;
+    int active = ' ';
+    Monitor *mon = opaque;
+
+    assert(qobject_type(obj) == QTYPE_QDICT);
+    cpu = qobject_to_qdict(obj);
+
+    if (qdict_get_bool(cpu, "current")) {
+        active = '*';
+    }
+
+    monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
+
+#if defined(TARGET_I386)
+    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
+                   (target_ulong) qdict_get_int(cpu, "pc"));
+#elif defined(TARGET_PPC)
+    monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
+                   (target_long) qdict_get_int(cpu, "nip"));
+#elif defined(TARGET_SPARC)
+    monitor_printf(mon, "pc=0x " TARGET_FMT_lx,
+                   (target_long) qdict_get_int(cpu, "pc"));
+    monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
+                   (target_long) qdict_get_int(cpu, "npc"));
+#elif defined(TARGET_MIPS)
+    monitor_printf(mon, "PC=0x" TARGET_FMT_lx,
+                   (target_long) qdict_get_int(cpu, "PC"));
+#endif
+
+    if (qdict_get_bool(cpu, "halted")) {
+        monitor_printf(mon, " (halted)");
+    }
+
+    monitor_printf(mon, " thread_id=%" PRId64 " ",
+                   qdict_get_int(cpu, "thread_id"));
+
+    monitor_printf(mon, "\n");
+}
+
+static void monitor_print_cpus(Monitor *mon, const QObject *data)
+{
+    QList *cpu_list;
+
+    assert(qobject_type(data) == QTYPE_QLIST);
+    cpu_list = qobject_to_qlist(data);
+    qlist_iter(cpu_list, print_cpu_iter, mon);
+}
+
+static void do_info_cpus(Monitor *mon, QObject **ret_data)
+{
+    CPUState *env;
+    QList *cpu_list;
+
+    cpu_list = qlist_new();
+
+    /* just to set the default cpu if not already done */
+    mon_get_cpu();
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        QDict *cpu;
+        QObject *obj;
+
+        cpu_synchronize_state(env);
+
+        obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
+                                 env->cpu_index, env == mon->mon_cpu,
+                                 env->halted);
+
+        cpu = qobject_to_qdict(obj);
+
+#if defined(TARGET_I386)
+        qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
+#elif defined(TARGET_PPC)
+        qdict_put(cpu, "nip", qint_from_int(env->nip));
+#elif defined(TARGET_SPARC)
+        qdict_put(cpu, "pc", qint_from_int(env->pc));
+        qdict_put(cpu, "npc", qint_from_int(env->npc));
+#elif defined(TARGET_MIPS)
+        qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
+#endif
+        qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
+
+        qlist_append(cpu_list, cpu);
+    }
+
+    *ret_data = QOBJECT(cpu_list);
+}
+
+static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int index = qdict_get_int(qdict, "index");
+    if (mon_set_cpu(index) < 0) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
+                      "a CPU number");
+        return -1;
+    }
+    return 0;
+}
+
+static void do_info_jit(Monitor *mon)
+{
+    dump_exec_info((FILE *)mon, monitor_fprintf);
+}
+
+static void do_info_history(Monitor *mon)
+{
+    int i;
+    const char *str;
+
+    if (!mon->rs)
+        return;
+    i = 0;
+    for(;;) {
+        str = readline_get_history(mon->rs, i);
+        if (!str)
+            break;
+        monitor_printf(mon, "%d: '%s'\n", i, str);
+        i++;
+    }
+}
+
+#if defined(TARGET_PPC)
+/* XXX: not implemented in other targets */
+static void do_info_cpu_stats(Monitor *mon)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+    cpu_dump_statistics(env, (FILE *)mon, &monitor_fprintf, 0);
+}
+#endif
+
+#if defined(CONFIG_SIMPLE_TRACE)
+static void do_info_trace(Monitor *mon)
+{
+    st_print_trace((FILE *)mon, &monitor_fprintf);
+}
+
+static void do_info_trace_events(Monitor *mon)
+{
+    st_print_trace_events((FILE *)mon, &monitor_fprintf);
+}
+#endif
+
+/**
+ * do_quit(): Quit QEMU execution
+ */
+static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    monitor_suspend(mon);
+    no_shutdown = 0;
+    qemu_system_shutdown_request();
+
+    return 0;
+}
+
+#ifdef CONFIG_VNC
+static int change_vnc_password(const char *password)
+{
+    if (!password || !password[0]) {
+        if (vnc_display_disable_login(NULL)) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (vnc_display_password(NULL, password) < 0) {
+        qerror_report(QERR_SET_PASSWD_FAILED);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void change_vnc_password_cb(Monitor *mon, const char *password,
+                                   void *opaque)
+{
+    change_vnc_password(password);
+    monitor_read_command(mon, 1);
+}
+
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
+{
+    if (strcmp(target, "passwd") == 0 ||
+        strcmp(target, "password") == 0) {
+        if (arg) {
+            char password[9];
+            strncpy(password, arg, sizeof(password));
+            password[sizeof(password) - 1] = '\0';
+            return change_vnc_password(password);
+        } else {
+            return monitor_read_password(mon, change_vnc_password_cb, NULL);
+        }
+    } else {
+        if (vnc_display_open(NULL, target) < 0) {
+            qerror_report(QERR_VNC_SERVER_FAILED, target);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+#else
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
+{
+    qerror_report(QERR_FEATURE_DISABLED, "vnc");
+    return -ENODEV;
+}
+#endif
+
+/**
+ * do_change(): Change a removable medium, or VNC configuration
+ */
+static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *target = qdict_get_str(qdict, "target");
+    const char *arg = qdict_get_try_str(qdict, "arg");
+    int ret;
+
+    if (strcmp(device, "vnc") == 0) {
+        ret = do_change_vnc(mon, target, arg);
+    } else {
+        ret = do_change_block(mon, device, target, arg);
+    }
+
+    return ret;
+}
+
+static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *password  = qdict_get_str(qdict, "password");
+    const char *connected = qdict_get_try_str(qdict, "connected");
+    int disconnect_if_connected = 0;
+    int fail_if_connected = 0;
+    int rc;
+
+    if (connected) {
+        if (strcmp(connected, "fail") == 0) {
+            fail_if_connected = 1;
+        } else if (strcmp(connected, "disconnect") == 0) {
+            disconnect_if_connected = 1;
+        } else if (strcmp(connected, "keep") == 0) {
+            /* nothing */
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER, "connected");
+            return -1;
+        }
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+        rc = qemu_spice_set_passwd(password, fail_if_connected,
+                                   disconnect_if_connected);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        if (fail_if_connected || disconnect_if_connected) {
+            /* vnc supports "connected=keep" only */
+            qerror_report(QERR_INVALID_PARAMETER, "connected");
+            return -1;
+        }
+        /* Note that setting an empty password will not disable login through
+         * this interface. */
+        return vnc_display_password(NULL, password);
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *whenstr = qdict_get_str(qdict, "time");
+    time_t when;
+    int rc;
+
+    if (strcmp(whenstr, "now") == 0) {
+        when = 0;
+    } else if (strcmp(whenstr, "never") == 0) {
+        when = TIME_MAX;
+    } else if (whenstr[0] == '+') {
+        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+    } else {
+        when = strtoull(whenstr, NULL, 10);
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+        rc = qemu_spice_set_pw_expire(when);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        return vnc_display_pw_expire(NULL, when);
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *fdname = qdict_get_str(qdict, "fdname");
+    CharDriverState *s;
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+	qerror_report(QERR_ADD_CLIENT_FAILED);
+	return -1;
+#ifdef CONFIG_VNC
+    } else if (strcmp(protocol, "vnc") == 0) {
+	int fd = monitor_get_fd(mon, fdname);
+        int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
+	vnc_display_add_client(NULL, fd, skipauth);
+	return 0;
+#endif
+    } else if ((s = qemu_chr_find(protocol)) != NULL) {
+	int fd = monitor_get_fd(mon, fdname);
+	if (qemu_chr_add_client(s, fd) < 0) {
+	    qerror_report(QERR_ADD_CLIENT_FAILED);
+	    return -1;
+	}
+	return 0;
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol = qdict_get_str(qdict, "protocol");
+    const char *hostname = qdict_get_str(qdict, "hostname");
+    const char *subject  = qdict_get_try_str(qdict, "cert-subject");
+    int port             = qdict_get_try_int(qdict, "port", -1);
+    int tls_port         = qdict_get_try_int(qdict, "tls-port", -1);
+    int ret;
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+
+        ret = qemu_spice_migrate_info(hostname, port, tls_port, subject);
+        if (ret != 0) {
+            qerror_report(QERR_UNDEFINED_ERROR);
+            return -1;
+        }
+        return 0;
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
+    return 0;
+}
+
+static void do_logfile(Monitor *mon, const QDict *qdict)
+{
+    cpu_set_log_filename(qdict_get_str(qdict, "filename"));
+}
+
+static void do_log(Monitor *mon, const QDict *qdict)
+{
+    int mask;
+    const char *items = qdict_get_str(qdict, "items");
+
+    if (!strcmp(items, "none")) {
+        mask = 0;
+    } else {
+        mask = cpu_str_to_log_mask(items);
+        if (!mask) {
+            help_cmd(mon, "log");
+            return;
+        }
+    }
+    cpu_set_log(mask);
+}
+
+static void do_singlestep(Monitor *mon, const QDict *qdict)
+{
+    const char *option = qdict_get_try_str(qdict, "option");
+    if (!option || !strcmp(option, "on")) {
+        singlestep = 1;
+    } else if (!strcmp(option, "off")) {
+        singlestep = 0;
+    } else {
+        monitor_printf(mon, "unexpected option %s\n", option);
+    }
+}
+
+/**
+ * do_stop(): Stop VM execution
+ */
+static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    vm_stop(VMSTOP_USER);
+    return 0;
+}
+
+static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
+
+struct bdrv_iterate_context {
+    Monitor *mon;
+    int err;
+};
+
+/**
+ * do_cont(): Resume emulation.
+ */
+static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    struct bdrv_iterate_context context = { mon, 0 };
+
+    if (incoming_expected) {
+        qerror_report(QERR_MIGRATION_EXPECTED);
+        return -1;
+    }
+    bdrv_iterate(encrypted_bdrv_it, &context);
+    /* only resume the vm if all keys are set and valid */
+    if (!context.err) {
+        vm_start();
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+static void bdrv_key_cb(void *opaque, int err)
+{
+    Monitor *mon = opaque;
+
+    /* another key was set successfully, retry to continue */
+    if (!err)
+        do_cont(mon, NULL, NULL);
+}
+
+static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
+{
+    struct bdrv_iterate_context *context = opaque;
+
+    if (!context->err && bdrv_key_required(bs)) {
+        context->err = -EBUSY;
+        monitor_read_bdrv_key_start(context->mon, bs, bdrv_key_cb,
+                                    context->mon);
+    }
+}
+
+static void do_gdbserver(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_try_str(qdict, "device");
+    if (!device)
+        device = "tcp::" DEFAULT_GDBSTUB_PORT;
+    if (gdbserver_start(device) < 0) {
+        monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
+                       device);
+    } else if (strcmp(device, "none") == 0) {
+        monitor_printf(mon, "Disabled gdbserver\n");
+    } else {
+        monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
+                       device);
+    }
+}
+
+static void do_watchdog_action(Monitor *mon, const QDict *qdict)
+{
+    const char *action = qdict_get_str(qdict, "action");
+    if (select_watchdog_action(action) == -1) {
+        monitor_printf(mon, "Unknown watchdog action '%s'\n", action);
+    }
+}
+
+static void monitor_printc(Monitor *mon, int c)
+{
+    monitor_printf(mon, "'");
+    switch(c) {
+    case '\'':
+        monitor_printf(mon, "\\'");
+        break;
+    case '\\':
+        monitor_printf(mon, "\\\\");
+        break;
+    case '\n':
+        monitor_printf(mon, "\\n");
+        break;
+    case '\r':
+        monitor_printf(mon, "\\r");
+        break;
+    default:
+        if (c >= 32 && c <= 126) {
+            monitor_printf(mon, "%c", c);
+        } else {
+            monitor_printf(mon, "\\x%02x", c);
+        }
+        break;
+    }
+    monitor_printf(mon, "'");
+}
+
+static void memory_dump(Monitor *mon, int count, int format, int wsize,
+                        target_phys_addr_t addr, int is_physical)
+{
+    CPUState *env;
+    int l, line_size, i, max_digits, len;
+    uint8_t buf[16];
+    uint64_t v;
+
+    if (format == 'i') {
+        int flags;
+        flags = 0;
+        env = mon_get_cpu();
+#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(mon, env, addr, count, is_physical, flags);
+        return;
+    }
+
+    len = wsize * count;
+    if (wsize == 1)
+        line_size = 8;
+    else
+        line_size = 16;
+    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)
+            monitor_printf(mon, TARGET_FMT_plx ":", addr);
+        else
+            monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr);
+        l = len;
+        if (l > line_size)
+            l = line_size;
+        if (is_physical) {
+            cpu_physical_memory_read(addr, buf, l);
+        } else {
+            env = mon_get_cpu();
+            if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) {
+                monitor_printf(mon, " Cannot access memory\n");
+                break;
+            }
+        }
+        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;
+            }
+            monitor_printf(mon, " ");
+            switch(format) {
+            case 'o':
+                monitor_printf(mon, "%#*" PRIo64, max_digits, v);
+                break;
+            case 'x':
+                monitor_printf(mon, "0x%0*" PRIx64, max_digits, v);
+                break;
+            case 'u':
+                monitor_printf(mon, "%*" PRIu64, max_digits, v);
+                break;
+            case 'd':
+                monitor_printf(mon, "%*" PRId64, max_digits, v);
+                break;
+            case 'c':
+                monitor_printc(mon, v);
+                break;
+            }
+            i += wsize;
+        }
+        monitor_printf(mon, "\n");
+        addr += l;
+        len -= l;
+    }
+}
+
+static void do_memory_dump(Monitor *mon, const QDict *qdict)
+{
+    int count = qdict_get_int(qdict, "count");
+    int format = qdict_get_int(qdict, "format");
+    int size = qdict_get_int(qdict, "size");
+    target_long addr = qdict_get_int(qdict, "addr");
+
+    memory_dump(mon, count, format, size, addr, 0);
+}
+
+static void do_physical_memory_dump(Monitor *mon, const QDict *qdict)
+{
+    int count = qdict_get_int(qdict, "count");
+    int format = qdict_get_int(qdict, "format");
+    int size = qdict_get_int(qdict, "size");
+    target_phys_addr_t addr = qdict_get_int(qdict, "addr");
+
+    memory_dump(mon, count, format, size, addr, 1);
+}
+
+static void do_print(Monitor *mon, const QDict *qdict)
+{
+    int format = qdict_get_int(qdict, "format");
+    target_phys_addr_t val = qdict_get_int(qdict, "val");
+
+#if TARGET_PHYS_ADDR_BITS == 32
+    switch(format) {
+    case 'o':
+        monitor_printf(mon, "%#o", val);
+        break;
+    case 'x':
+        monitor_printf(mon, "%#x", val);
+        break;
+    case 'u':
+        monitor_printf(mon, "%u", val);
+        break;
+    default:
+    case 'd':
+        monitor_printf(mon, "%d", val);
+        break;
+    case 'c':
+        monitor_printc(mon, val);
+        break;
+    }
+#else
+    switch(format) {
+    case 'o':
+        monitor_printf(mon, "%#" PRIo64, val);
+        break;
+    case 'x':
+        monitor_printf(mon, "%#" PRIx64, val);
+        break;
+    case 'u':
+        monitor_printf(mon, "%" PRIu64, val);
+        break;
+    default:
+    case 'd':
+        monitor_printf(mon, "%" PRId64, val);
+        break;
+    case 'c':
+        monitor_printc(mon, val);
+        break;
+    }
+#endif
+    monitor_printf(mon, "\n");
+}
+
+static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    FILE *f;
+    uint32_t size = qdict_get_int(qdict, "size");
+    const char *filename = qdict_get_str(qdict, "filename");
+    target_long addr = qdict_get_int(qdict, "val");
+    uint32_t l;
+    CPUState *env;
+    uint8_t buf[1024];
+    int ret = -1;
+
+    env = mon_get_cpu();
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        return -1;
+    }
+    while (size != 0) {
+        l = sizeof(buf);
+        if (l > size)
+            l = size;
+        cpu_memory_rw_debug(env, addr, buf, l, 0);
+        if (fwrite(buf, 1, l, f) != l) {
+            monitor_printf(mon, "fwrite() error in do_memory_save\n");
+            goto exit;
+        }
+        addr += l;
+        size -= l;
+    }
+
+    ret = 0;
+
+exit:
+    fclose(f);
+    return ret;
+}
+
+static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
+                                    QObject **ret_data)
+{
+    FILE *f;
+    uint32_t l;
+    uint8_t buf[1024];
+    uint32_t size = qdict_get_int(qdict, "size");
+    const char *filename = qdict_get_str(qdict, "filename");
+    target_phys_addr_t addr = qdict_get_int(qdict, "val");
+    int ret = -1;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        return -1;
+    }
+    while (size != 0) {
+        l = sizeof(buf);
+        if (l > size)
+            l = size;
+        cpu_physical_memory_read(addr, buf, l);
+        if (fwrite(buf, 1, l, f) != l) {
+            monitor_printf(mon, "fwrite() error in do_physical_memory_save\n");
+            goto exit;
+        }
+        fflush(f);
+        addr += l;
+        size -= l;
+    }
+
+    ret = 0;
+
+exit:
+    fclose(f);
+    return ret;
+}
+
+static void do_sum(Monitor *mon, const QDict *qdict)
+{
+    uint32_t addr;
+    uint16_t sum;
+    uint32_t start = qdict_get_int(qdict, "start");
+    uint32_t size = qdict_get_int(qdict, "size");
+
+    sum = 0;
+    for(addr = start; addr < (start + size); addr++) {
+        uint8_t val = ldub_phys(addr);
+        /* BSD sum algorithm ('sum' Unix command) */
+        sum = (sum >> 1) | (sum << 15);
+        sum += val;
+    }
+    monitor_printf(mon, "%05d\n", sum);
+}
+
+typedef struct {
+    int keycode;
+    const char *name;
+} KeyDef;
+
+static const KeyDef key_defs[] = {
+    { 0x2a, "shift" },
+    { 0x36, "shift_r" },
+
+    { 0x38, "alt" },
+    { 0xb8, "alt_r" },
+    { 0x64, "altgr" },
+    { 0xe4, "altgr_r" },
+    { 0x1d, "ctrl" },
+    { 0x9d, "ctrl_r" },
+
+    { 0xdd, "menu" },
+
+    { 0x01, "esc" },
+
+    { 0x02, "1" },
+    { 0x03, "2" },
+    { 0x04, "3" },
+    { 0x05, "4" },
+    { 0x06, "5" },
+    { 0x07, "6" },
+    { 0x08, "7" },
+    { 0x09, "8" },
+    { 0x0a, "9" },
+    { 0x0b, "0" },
+    { 0x0c, "minus" },
+    { 0x0d, "equal" },
+    { 0x0e, "backspace" },
+
+    { 0x0f, "tab" },
+    { 0x10, "q" },
+    { 0x11, "w" },
+    { 0x12, "e" },
+    { 0x13, "r" },
+    { 0x14, "t" },
+    { 0x15, "y" },
+    { 0x16, "u" },
+    { 0x17, "i" },
+    { 0x18, "o" },
+    { 0x19, "p" },
+    { 0x1a, "bracket_left" },
+    { 0x1b, "bracket_right" },
+    { 0x1c, "ret" },
+
+    { 0x1e, "a" },
+    { 0x1f, "s" },
+    { 0x20, "d" },
+    { 0x21, "f" },
+    { 0x22, "g" },
+    { 0x23, "h" },
+    { 0x24, "j" },
+    { 0x25, "k" },
+    { 0x26, "l" },
+    { 0x27, "semicolon" },
+    { 0x28, "apostrophe" },
+    { 0x29, "grave_accent" },
+
+    { 0x2b, "backslash" },
+    { 0x2c, "z" },
+    { 0x2d, "x" },
+    { 0x2e, "c" },
+    { 0x2f, "v" },
+    { 0x30, "b" },
+    { 0x31, "n" },
+    { 0x32, "m" },
+    { 0x33, "comma" },
+    { 0x34, "dot" },
+    { 0x35, "slash" },
+
+    { 0x37, "asterisk" },
+
+    { 0x39, "spc" },
+    { 0x3a, "caps_lock" },
+    { 0x3b, "f1" },
+    { 0x3c, "f2" },
+    { 0x3d, "f3" },
+    { 0x3e, "f4" },
+    { 0x3f, "f5" },
+    { 0x40, "f6" },
+    { 0x41, "f7" },
+    { 0x42, "f8" },
+    { 0x43, "f9" },
+    { 0x44, "f10" },
+    { 0x45, "num_lock" },
+    { 0x46, "scroll_lock" },
+
+    { 0xb5, "kp_divide" },
+    { 0x37, "kp_multiply" },
+    { 0x4a, "kp_subtract" },
+    { 0x4e, "kp_add" },
+    { 0x9c, "kp_enter" },
+    { 0x53, "kp_decimal" },
+    { 0x54, "sysrq" },
+
+    { 0x52, "kp_0" },
+    { 0x4f, "kp_1" },
+    { 0x50, "kp_2" },
+    { 0x51, "kp_3" },
+    { 0x4b, "kp_4" },
+    { 0x4c, "kp_5" },
+    { 0x4d, "kp_6" },
+    { 0x47, "kp_7" },
+    { 0x48, "kp_8" },
+    { 0x49, "kp_9" },
+
+    { 0x56, "<" },
+
+    { 0x57, "f11" },
+    { 0x58, "f12" },
+
+    { 0xb7, "print" },
+
+    { 0xc7, "home" },
+    { 0xc9, "pgup" },
+    { 0xd1, "pgdn" },
+    { 0xcf, "end" },
+
+    { 0xcb, "left" },
+    { 0xc8, "up" },
+    { 0xd0, "down" },
+    { 0xcd, "right" },
+
+    { 0xd2, "insert" },
+    { 0xd3, "delete" },
+#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
+    { 0xf0, "stop" },
+    { 0xf1, "again" },
+    { 0xf2, "props" },
+    { 0xf3, "undo" },
+    { 0xf4, "front" },
+    { 0xf5, "copy" },
+    { 0xf6, "open" },
+    { 0xf7, "paste" },
+    { 0xf8, "find" },
+    { 0xf9, "cut" },
+    { 0xfa, "lf" },
+    { 0xfb, "help" },
+    { 0xfc, "meta_l" },
+    { 0xfd, "meta_r" },
+    { 0xfe, "compose" },
+#endif
+    { 0, NULL },
+};
+
+static int get_keycode(const char *key)
+{
+    const KeyDef *p;
+    char *endp;
+    int ret;
+
+    for(p = key_defs; p->name != NULL; p++) {
+        if (!strcmp(key, p->name))
+            return p->keycode;
+    }
+    if (strstart(key, "0x", NULL)) {
+        ret = strtoul(key, &endp, 0);
+        if (*endp == '\0' && ret >= 0x01 && ret <= 0xff)
+            return ret;
+    }
+    return -1;
+}
+
+#define MAX_KEYCODES 16
+static uint8_t keycodes[MAX_KEYCODES];
+static int nb_pending_keycodes;
+static QEMUTimer *key_timer;
+
+static void release_keys(void *opaque)
+{
+    int keycode;
+
+    while (nb_pending_keycodes > 0) {
+        nb_pending_keycodes--;
+        keycode = keycodes[nb_pending_keycodes];
+        if (keycode & 0x80)
+            kbd_put_keycode(0xe0);
+        kbd_put_keycode(keycode | 0x80);
+    }
+}
+
+static void do_sendkey(Monitor *mon, const QDict *qdict)
+{
+    char keyname_buf[16];
+    char *separator;
+    int keyname_len, keycode, i;
+    const char *string = qdict_get_str(qdict, "string");
+    int has_hold_time = qdict_haskey(qdict, "hold_time");
+    int hold_time = qdict_get_try_int(qdict, "hold_time", -1);
+
+    if (nb_pending_keycodes > 0) {
+        qemu_del_timer(key_timer);
+        release_keys(NULL);
+    }
+    if (!has_hold_time)
+        hold_time = 100;
+    i = 0;
+    while (1) {
+        separator = strchr(string, '-');
+        keyname_len = separator ? separator - string : strlen(string);
+        if (keyname_len > 0) {
+            pstrcpy(keyname_buf, sizeof(keyname_buf), string);
+            if (keyname_len > sizeof(keyname_buf) - 1) {
+                monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf);
+                return;
+            }
+            if (i == MAX_KEYCODES) {
+                monitor_printf(mon, "too many keys\n");
+                return;
+            }
+            keyname_buf[keyname_len] = 0;
+            keycode = get_keycode(keyname_buf);
+            if (keycode < 0) {
+                monitor_printf(mon, "unknown key: '%s'\n", keyname_buf);
+                return;
+            }
+            keycodes[i++] = keycode;
+        }
+        if (!separator)
+            break;
+        string = separator + 1;
+    }
+    nb_pending_keycodes = i;
+    /* key down events */
+    for (i = 0; i < nb_pending_keycodes; i++) {
+        keycode = keycodes[i];
+        if (keycode & 0x80)
+            kbd_put_keycode(0xe0);
+        kbd_put_keycode(keycode & 0x7f);
+    }
+    /* delayed key up events */
+    qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
+                   muldiv64(get_ticks_per_sec(), hold_time, 1000));
+}
+
+static int mouse_button_state;
+
+static void do_mouse_move(Monitor *mon, const QDict *qdict)
+{
+    int dx, dy, dz;
+    const char *dx_str = qdict_get_str(qdict, "dx_str");
+    const char *dy_str = qdict_get_str(qdict, "dy_str");
+    const char *dz_str = qdict_get_try_str(qdict, "dz_str");
+    dx = strtol(dx_str, NULL, 0);
+    dy = strtol(dy_str, NULL, 0);
+    dz = 0;
+    if (dz_str)
+        dz = strtol(dz_str, NULL, 0);
+    kbd_mouse_event(dx, dy, dz, mouse_button_state);
+}
+
+static void do_mouse_button(Monitor *mon, const QDict *qdict)
+{
+    int button_state = qdict_get_int(qdict, "button_state");
+    mouse_button_state = button_state;
+    kbd_mouse_event(0, 0, 0, mouse_button_state);
+}
+
+static void do_ioport_read(Monitor *mon, const QDict *qdict)
+{
+    int size = qdict_get_int(qdict, "size");
+    int addr = qdict_get_int(qdict, "addr");
+    int has_index = qdict_haskey(qdict, "index");
+    uint32_t val;
+    int suffix;
+
+    if (has_index) {
+        int index = qdict_get_int(qdict, "index");
+        cpu_outb(addr & IOPORTS_MASK, 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;
+    }
+    monitor_printf(mon, "port%c[0x%04x] = %#0*x\n",
+                   suffix, addr, size * 2, val);
+}
+
+static void do_ioport_write(Monitor *mon, const QDict *qdict)
+{
+    int size = qdict_get_int(qdict, "size");
+    int addr = qdict_get_int(qdict, "addr");
+    int val = qdict_get_int(qdict, "val");
+
+    addr &= IOPORTS_MASK;
+
+    switch (size) {
+    default:
+    case 1:
+        cpu_outb(addr, val);
+        break;
+    case 2:
+        cpu_outw(addr, val);
+        break;
+    case 4:
+        cpu_outl(addr, val);
+        break;
+    }
+}
+
+static void do_boot_set(Monitor *mon, const QDict *qdict)
+{
+    int res;
+    const char *bootdevice = qdict_get_str(qdict, "bootdevice");
+
+    res = qemu_boot_set(bootdevice);
+    if (res == 0) {
+        monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
+    } else if (res > 0) {
+        monitor_printf(mon, "setting boot device list failed\n");
+    } else {
+        monitor_printf(mon, "no function defined to set boot device list for "
+                       "this architecture\n");
+    }
+}
+
+/**
+ * do_system_reset(): Issue a machine reset
+ */
+static int do_system_reset(Monitor *mon, const QDict *qdict,
+                           QObject **ret_data)
+{
+    qemu_system_reset_request();
+    return 0;
+}
+
+/**
+ * do_system_powerdown(): Issue a machine powerdown
+ */
+static int do_system_powerdown(Monitor *mon, const QDict *qdict,
+                               QObject **ret_data)
+{
+    qemu_system_powerdown_request();
+    return 0;
+}
+
+#if defined(TARGET_I386)
+static void print_pte(Monitor *mon, target_phys_addr_t addr,
+                      target_phys_addr_t pte,
+                      target_phys_addr_t mask)
+{
+#ifdef TARGET_X86_64
+    if (addr & (1ULL << 47)) {
+        addr |= -1LL << 48;
+    }
+#endif
+    monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx
+                   " %c%c%c%c%c%c%c%c%c\n",
+                   addr,
+                   pte & mask,
+                   pte & PG_NX_MASK ? 'X' : '-',
+                   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_32(Monitor *mon, CPUState *env)
+{
+    int l1, l2;
+    uint32_t pgd, pde, pte;
+
+    pgd = env->cr[3] & ~0xfff;
+    for(l1 = 0; l1 < 1024; l1++) {
+        cpu_physical_memory_read(pgd + l1 * 4, &pde, 4);
+        pde = le32_to_cpu(pde);
+        if (pde & PG_PRESENT_MASK) {
+            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+                /* 4M pages */
+                print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1));
+            } else {
+                for(l2 = 0; l2 < 1024; l2++) {
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4);
+                    pte = le32_to_cpu(pte);
+                    if (pte & PG_PRESENT_MASK) {
+                        print_pte(mon, (l1 << 22) + (l2 << 12),
+                                  pte & ~PG_PSE_MASK,
+                                  ~0xfff);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void tlb_info_pae32(Monitor *mon, CPUState *env)
+{
+    int l1, l2, l3;
+    uint64_t pdpe, pde, pte;
+    uint64_t pdp_addr, pd_addr, pt_addr;
+
+    pdp_addr = env->cr[3] & ~0x1f;
+    for (l1 = 0; l1 < 4; l1++) {
+        cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8);
+        pdpe = le64_to_cpu(pdpe);
+        if (pdpe & PG_PRESENT_MASK) {
+            pd_addr = pdpe & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8);
+                pde = le64_to_cpu(pde);
+                if (pde & PG_PRESENT_MASK) {
+                    if (pde & PG_PSE_MASK) {
+                        /* 2M pages with PAE, CR4.PSE is ignored */
+                        print_pte(mon, (l1 << 30 ) + (l2 << 21), pde,
+                                  ~((target_phys_addr_t)(1 << 20) - 1));
+                    } else {
+                        pt_addr = pde & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8);
+                            pte = le64_to_cpu(pte);
+                            if (pte & PG_PRESENT_MASK) {
+                                print_pte(mon, (l1 << 30 ) + (l2 << 21)
+                                          + (l3 << 12),
+                                          pte & ~PG_PSE_MASK,
+                                          ~(target_phys_addr_t)0xfff);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+#ifdef TARGET_X86_64
+static void tlb_info_64(Monitor *mon, CPUState *env)
+{
+    uint64_t l1, l2, l3, l4;
+    uint64_t pml4e, pdpe, pde, pte;
+    uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr;
+
+    pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
+    for (l1 = 0; l1 < 512; l1++) {
+        cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8);
+        pml4e = le64_to_cpu(pml4e);
+        if (pml4e & PG_PRESENT_MASK) {
+            pdp_addr = pml4e & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8);
+                pdpe = le64_to_cpu(pdpe);
+                if (pdpe & PG_PRESENT_MASK) {
+                    if (pdpe & PG_PSE_MASK) {
+                        /* 1G pages, CR4.PSE is ignored */
+                        print_pte(mon, (l1 << 39) + (l2 << 30), pdpe,
+                                  0x3ffffc0000000ULL);
+                    } else {
+                        pd_addr = pdpe & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8);
+                            pde = le64_to_cpu(pde);
+                            if (pde & PG_PRESENT_MASK) {
+                                if (pde & PG_PSE_MASK) {
+                                    /* 2M pages, CR4.PSE is ignored */
+                                    print_pte(mon, (l1 << 39) + (l2 << 30) +
+                                              (l3 << 21), pde,
+                                              0x3ffffffe00000ULL);
+                                } else {
+                                    pt_addr = pde & 0x3fffffffff000ULL;
+                                    for (l4 = 0; l4 < 512; l4++) {
+                                        cpu_physical_memory_read(pt_addr
+                                                                 + l4 * 8,
+                                                                 &pte, 8);
+                                        pte = le64_to_cpu(pte);
+                                        if (pte & PG_PRESENT_MASK) {
+                                            print_pte(mon, (l1 << 39) +
+                                                      (l2 << 30) +
+                                                      (l3 << 21) + (l4 << 12),
+                                                      pte & ~PG_PSE_MASK,
+                                                      0x3fffffffff000ULL);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        monitor_printf(mon, "PG disabled\n");
+        return;
+    }
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            tlb_info_64(mon, env);
+        } else
+#endif
+        {
+            tlb_info_pae32(mon, env);
+        }
+    } else {
+        tlb_info_32(mon, env);
+    }
+}
+
+static void mem_print(Monitor *mon, target_phys_addr_t *pstart,
+                      int *plast_prot,
+                      target_phys_addr_t end, int prot)
+{
+    int prot1;
+    prot1 = *plast_prot;
+    if (prot != prot1) {
+        if (*pstart != -1) {
+            monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " "
+                           TARGET_FMT_plx " %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_32(Monitor *mon, CPUState *env)
+{
+    int l1, l2, prot, last_prot;
+    uint32_t pgd, pde, pte;
+    target_phys_addr_t start, end;
+
+    pgd = env->cr[3] & ~0xfff;
+    last_prot = 0;
+    start = -1;
+    for(l1 = 0; l1 < 1024; l1++) {
+        cpu_physical_memory_read(pgd + l1 * 4, &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(mon, &start, &last_prot, end, prot);
+            } else {
+                for(l2 = 0; l2 < 1024; l2++) {
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &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(mon, &start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(mon, &start, &last_prot, end, prot);
+        }
+    }
+}
+
+static void mem_info_pae32(Monitor *mon, CPUState *env)
+{
+    int l1, l2, l3, prot, last_prot;
+    uint64_t pdpe, pde, pte;
+    uint64_t pdp_addr, pd_addr, pt_addr;
+    target_phys_addr_t start, end;
+
+    pdp_addr = env->cr[3] & ~0x1f;
+    last_prot = 0;
+    start = -1;
+    for (l1 = 0; l1 < 4; l1++) {
+        cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8);
+        pdpe = le64_to_cpu(pdpe);
+        end = l1 << 30;
+        if (pdpe & PG_PRESENT_MASK) {
+            pd_addr = pdpe & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8);
+                pde = le64_to_cpu(pde);
+                end = (l1 << 30) + (l2 << 21);
+                if (pde & PG_PRESENT_MASK) {
+                    if (pde & PG_PSE_MASK) {
+                        prot = pde & (PG_USER_MASK | PG_RW_MASK |
+                                      PG_PRESENT_MASK);
+                        mem_print(mon, &start, &last_prot, end, prot);
+                    } else {
+                        pt_addr = pde & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8);
+                            pte = le64_to_cpu(pte);
+                            end = (l1 << 30) + (l2 << 21) + (l3 << 12);
+                            if (pte & PG_PRESENT_MASK) {
+                                prot = pte & (PG_USER_MASK | PG_RW_MASK |
+                                              PG_PRESENT_MASK);
+                            } else {
+                                prot = 0;
+                            }
+                            mem_print(mon, &start, &last_prot, end, prot);
+                        }
+                    }
+                } else {
+                    prot = 0;
+                    mem_print(mon, &start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(mon, &start, &last_prot, end, prot);
+        }
+    }
+}
+
+
+#ifdef TARGET_X86_64
+static void mem_info_64(Monitor *mon, CPUState *env)
+{
+    int prot, last_prot;
+    uint64_t l1, l2, l3, l4;
+    uint64_t pml4e, pdpe, pde, pte;
+    uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr, start, end;
+
+    pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
+    last_prot = 0;
+    start = -1;
+    for (l1 = 0; l1 < 512; l1++) {
+        cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8);
+        pml4e = le64_to_cpu(pml4e);
+        end = l1 << 39;
+        if (pml4e & PG_PRESENT_MASK) {
+            pdp_addr = pml4e & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8);
+                pdpe = le64_to_cpu(pdpe);
+                end = (l1 << 39) + (l2 << 30);
+                if (pdpe & PG_PRESENT_MASK) {
+                    if (pdpe & PG_PSE_MASK) {
+                        prot = pdpe & (PG_USER_MASK | PG_RW_MASK |
+                                       PG_PRESENT_MASK);
+                        mem_print(mon, &start, &last_prot, end, prot);
+                    } else {
+                        pd_addr = pdpe & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8);
+                            pde = le64_to_cpu(pde);
+                            end = (l1 << 39) + (l2 << 30) + (l3 << 21);
+                            if (pde & PG_PRESENT_MASK) {
+                                if (pde & PG_PSE_MASK) {
+                                    prot = pde & (PG_USER_MASK | PG_RW_MASK |
+                                                  PG_PRESENT_MASK);
+                                    mem_print(mon, &start, &last_prot, end, prot);
+                                } else {
+                                    pt_addr = pde & 0x3fffffffff000ULL;
+                                    for (l4 = 0; l4 < 512; l4++) {
+                                        cpu_physical_memory_read(pt_addr
+                                                                 + l4 * 8,
+                                                                 &pte, 8);
+                                        pte = le64_to_cpu(pte);
+                                        end = (l1 << 39) + (l2 << 30) +
+                                            (l3 << 21) + (l4 << 12);
+                                        if (pte & PG_PRESENT_MASK) {
+                                            prot = pte & (PG_USER_MASK | PG_RW_MASK |
+                                                          PG_PRESENT_MASK);
+                                        } else {
+                                            prot = 0;
+                                        }
+                                        mem_print(mon, &start, &last_prot, end, prot);
+                                    }
+                                }
+                            } else {
+                                prot = 0;
+                                mem_print(mon, &start, &last_prot, end, prot);
+                            }
+                        }
+                    }
+                } else {
+                    prot = 0;
+                    mem_print(mon, &start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(mon, &start, &last_prot, end, prot);
+        }
+    }
+}
+#endif
+
+static void mem_info(Monitor *mon)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        monitor_printf(mon, "PG disabled\n");
+        return;
+    }
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            mem_info_64(mon, env);
+        } else
+#endif
+        {
+            mem_info_pae32(mon, env);
+        }
+    } else {
+        mem_info_32(mon, env);
+    }
+}
+#endif
+
+#if defined(TARGET_SH4)
+
+static void print_tlb(Monitor *mon, int idx, tlb_t *tlb)
+{
+    monitor_printf(mon, " tlb%i:\t"
+                   "asid=%hhu vpn=%x\tppn=%x\tsz=%hhu size=%u\t"
+                   "v=%hhu shared=%hhu cached=%hhu prot=%hhu "
+                   "dirty=%hhu writethrough=%hhu\n",
+                   idx,
+                   tlb->asid, tlb->vpn, tlb->ppn, tlb->sz, tlb->size,
+                   tlb->v, tlb->sh, tlb->c, tlb->pr,
+                   tlb->d, tlb->wt);
+}
+
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env = mon_get_cpu();
+    int i;
+
+    monitor_printf (mon, "ITLB:\n");
+    for (i = 0 ; i < ITLB_SIZE ; i++)
+        print_tlb (mon, i, &env->itlb[i]);
+    monitor_printf (mon, "UTLB:\n");
+    for (i = 0 ; i < UTLB_SIZE ; i++)
+        print_tlb (mon, i, &env->utlb[i]);
+}
+
+#endif
+
+#if defined(TARGET_SPARC)
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env1 = mon_get_cpu();
+
+    dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
+}
+#endif
+
+static void do_info_kvm_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+
+    monitor_printf(mon, "kvm support: ");
+    if (qdict_get_bool(qdict, "present")) {
+        monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ?
+                                    "enabled" : "disabled");
+    } else {
+        monitor_printf(mon, "not compiled\n");
+    }
+}
+
+static void do_info_kvm(Monitor *mon, QObject **ret_data)
+{
+#ifdef CONFIG_KVM
+    *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }",
+                                   kvm_enabled());
+#else
+    *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }");
+#endif
+}
+
+static void do_info_numa(Monitor *mon)
+{
+    int i;
+    CPUState *env;
+
+    monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
+    for (i = 0; i < nb_numa_nodes; i++) {
+        monitor_printf(mon, "node %d cpus:", i);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (env->numa_node == i) {
+                monitor_printf(mon, " %d", env->cpu_index);
+            }
+        }
+        monitor_printf(mon, "\n");
+        monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
+            node_mem[i] >> 20);
+    }
+}
+
+#ifdef CONFIG_PROFILER
+
+int64_t qemu_time;
+int64_t dev_time;
+
+static void do_info_profile(Monitor *mon)
+{
+    int64_t total;
+    total = qemu_time;
+    if (total == 0)
+        total = 1;
+    monitor_printf(mon, "async time  %" PRId64 " (%0.3f)\n",
+                   dev_time, dev_time / (double)get_ticks_per_sec());
+    monitor_printf(mon, "qemu time   %" PRId64 " (%0.3f)\n",
+                   qemu_time, qemu_time / (double)get_ticks_per_sec());
+    qemu_time = 0;
+    dev_time = 0;
+}
+#else
+static void do_info_profile(Monitor *mon)
+{
+    monitor_printf(mon, "Internal profiler not compiled\n");
+}
+#endif
+
+/* Capture support */
+static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
+
+static void do_info_capture(Monitor *mon)
+{
+    int i;
+    CaptureState *s;
+
+    for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
+        monitor_printf(mon, "[%d]: ", i);
+        s->ops.info (s->opaque);
+    }
+}
+
+#ifdef HAS_AUDIO
+static void do_stop_capture(Monitor *mon, const QDict *qdict)
+{
+    int i;
+    int n = qdict_get_int(qdict, "n");
+    CaptureState *s;
+
+    for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
+        if (i == n) {
+            s->ops.destroy (s->opaque);
+            QLIST_REMOVE (s, entries);
+            qemu_free (s);
+            return;
+        }
+    }
+}
+
+static void do_wav_capture(Monitor *mon, const QDict *qdict)
+{
+    const char *path = qdict_get_str(qdict, "path");
+    int has_freq = qdict_haskey(qdict, "freq");
+    int freq = qdict_get_try_int(qdict, "freq", -1);
+    int has_bits = qdict_haskey(qdict, "bits");
+    int bits = qdict_get_try_int(qdict, "bits", -1);
+    int has_channels = qdict_haskey(qdict, "nchannels");
+    int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
+    CaptureState *s;
+
+    s = qemu_mallocz (sizeof (*s));
+
+    freq = has_freq ? freq : 44100;
+    bits = has_bits ? bits : 16;
+    nchannels = has_channels ? nchannels : 2;
+
+    if (wav_start_capture (s, path, freq, bits, nchannels)) {
+        monitor_printf(mon, "Failed to add wave capture\n");
+        qemu_free (s);
+        return;
+    }
+    QLIST_INSERT_HEAD (&capture_head, s, entries);
+}
+#endif
+
+#if defined(TARGET_I386)
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_interrupt(env, CPU_INTERRUPT_NMI);
+    }
+
+    return 0;
+}
+#else
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    qerror_report(QERR_UNSUPPORTED);
+    return -1;
+}
+#endif
+
+static void do_info_status_print(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+
+    monitor_printf(mon, "VM status: ");
+    if (qdict_get_bool(qdict, "running")) {
+        monitor_printf(mon, "running");
+        if (qdict_get_bool(qdict, "singlestep")) {
+            monitor_printf(mon, " (single step mode)");
+        }
+    } else {
+        monitor_printf(mon, "paused");
+    }
+
+    monitor_printf(mon, "\n");
+}
+
+static void do_info_status(Monitor *mon, QObject **ret_data)
+{
+    *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
+                                    vm_running, singlestep);
+}
+
+static qemu_acl *find_acl(Monitor *mon, const char *name)
+{
+    qemu_acl *acl = qemu_acl_find(name);
+
+    if (!acl) {
+        monitor_printf(mon, "acl: unknown list '%s'\n", name);
+    }
+    return acl;
+}
+
+static void do_acl_show(Monitor *mon, const QDict *qdict)
+{
+    const char *aclname = qdict_get_str(qdict, "aclname");
+    qemu_acl *acl = find_acl(mon, aclname);
+    qemu_acl_entry *entry;
+    int i = 0;
+
+    if (acl) {
+        monitor_printf(mon, "policy: %s\n",
+                       acl->defaultDeny ? "deny" : "allow");
+        QTAILQ_FOREACH(entry, &acl->entries, next) {
+            i++;
+            monitor_printf(mon, "%d: %s %s\n", i,
+                           entry->deny ? "deny" : "allow", entry->match);
+        }
+    }
+}
+
+static void do_acl_reset(Monitor *mon, const QDict *qdict)
+{
+    const char *aclname = qdict_get_str(qdict, "aclname");
+    qemu_acl *acl = find_acl(mon, aclname);
+
+    if (acl) {
+        qemu_acl_reset(acl);
+        monitor_printf(mon, "acl: removed all rules\n");
+    }
+}
+
+static void do_acl_policy(Monitor *mon, const QDict *qdict)
+{
+    const char *aclname = qdict_get_str(qdict, "aclname");
+    const char *policy = qdict_get_str(qdict, "policy");
+    qemu_acl *acl = find_acl(mon, aclname);
+
+    if (acl) {
+        if (strcmp(policy, "allow") == 0) {
+            acl->defaultDeny = 0;
+            monitor_printf(mon, "acl: policy set to 'allow'\n");
+        } else if (strcmp(policy, "deny") == 0) {
+            acl->defaultDeny = 1;
+            monitor_printf(mon, "acl: policy set to 'deny'\n");
+        } else {
+            monitor_printf(mon, "acl: unknown policy '%s', "
+                           "expected 'deny' or 'allow'\n", policy);
+        }
+    }
+}
+
+static void do_acl_add(Monitor *mon, const QDict *qdict)
+{
+    const char *aclname = qdict_get_str(qdict, "aclname");
+    const char *match = qdict_get_str(qdict, "match");
+    const char *policy = qdict_get_str(qdict, "policy");
+    int has_index = qdict_haskey(qdict, "index");
+    int index = qdict_get_try_int(qdict, "index", -1);
+    qemu_acl *acl = find_acl(mon, aclname);
+    int deny, ret;
+
+    if (acl) {
+        if (strcmp(policy, "allow") == 0) {
+            deny = 0;
+        } else if (strcmp(policy, "deny") == 0) {
+            deny = 1;
+        } else {
+            monitor_printf(mon, "acl: unknown policy '%s', "
+                           "expected 'deny' or 'allow'\n", policy);
+            return;
+        }
+        if (has_index)
+            ret = qemu_acl_insert(acl, deny, match, index);
+        else
+            ret = qemu_acl_append(acl, deny, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: unable to add acl entry\n");
+        else
+            monitor_printf(mon, "acl: added rule at position %d\n", ret);
+    }
+}
+
+static void do_acl_remove(Monitor *mon, const QDict *qdict)
+{
+    const char *aclname = qdict_get_str(qdict, "aclname");
+    const char *match = qdict_get_str(qdict, "match");
+    qemu_acl *acl = find_acl(mon, aclname);
+    int ret;
+
+    if (acl) {
+        ret = qemu_acl_remove(acl, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: no matching acl entry\n");
+        else
+            monitor_printf(mon, "acl: removed rule at position %d\n", ret);
+    }
+}
+
+#if defined(TARGET_I386)
+static void do_inject_mce(Monitor *mon, const QDict *qdict)
+{
+    CPUState *cenv;
+    int cpu_index = qdict_get_int(qdict, "cpu_index");
+    int bank = qdict_get_int(qdict, "bank");
+    uint64_t status = qdict_get_int(qdict, "status");
+    uint64_t mcg_status = qdict_get_int(qdict, "mcg_status");
+    uint64_t addr = qdict_get_int(qdict, "addr");
+    uint64_t misc = qdict_get_int(qdict, "misc");
+    int flags = MCE_INJECT_UNCOND_AO;
+
+    if (qdict_get_try_bool(qdict, "broadcast", 0)) {
+        flags |= MCE_INJECT_BROADCAST;
+    }
+    for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+        if (cenv->cpu_index == cpu_index) {
+            cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
+                               flags);
+            break;
+        }
+    }
+}
+#endif
+
+static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *fdname = qdict_get_str(qdict, "fdname");
+    mon_fd_t *monfd;
+    int fd;
+
+    fd = qemu_chr_get_msgfd(mon->chr);
+    if (fd == -1) {
+        qerror_report(QERR_FD_NOT_SUPPLIED);
+        return -1;
+    }
+
+    if (qemu_isdigit(fdname[0])) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "fdname",
+                      "a name not starting with a digit");
+        return -1;
+    }
+
+    QLIST_FOREACH(monfd, &mon->fds, next) {
+        if (strcmp(monfd->name, fdname) != 0) {
+            continue;
+        }
+
+        close(monfd->fd);
+        monfd->fd = fd;
+        return 0;
+    }
+
+    monfd = qemu_mallocz(sizeof(mon_fd_t));
+    monfd->name = qemu_strdup(fdname);
+    monfd->fd = fd;
+
+    QLIST_INSERT_HEAD(&mon->fds, monfd, next);
+    return 0;
+}
+
+static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *fdname = qdict_get_str(qdict, "fdname");
+    mon_fd_t *monfd;
+
+    QLIST_FOREACH(monfd, &mon->fds, next) {
+        if (strcmp(monfd->name, fdname) != 0) {
+            continue;
+        }
+
+        QLIST_REMOVE(monfd, next);
+        close(monfd->fd);
+        qemu_free(monfd->name);
+        qemu_free(monfd);
+        return 0;
+    }
+
+    qerror_report(QERR_FD_NOT_FOUND, fdname);
+    return -1;
+}
+
+static void do_loadvm(Monitor *mon, const QDict *qdict)
+{
+    int saved_vm_running  = vm_running;
+    const char *name = qdict_get_str(qdict, "name");
+
+    vm_stop(VMSTOP_LOADVM);
+
+    if (load_vmstate(name) == 0 && saved_vm_running) {
+        vm_start();
+    }
+}
+
+int monitor_get_fd(Monitor *mon, const char *fdname)
+{
+    mon_fd_t *monfd;
+
+    QLIST_FOREACH(monfd, &mon->fds, next) {
+        int fd;
+
+        if (strcmp(monfd->name, fdname) != 0) {
+            continue;
+        }
+
+        fd = monfd->fd;
+
+        /* caller takes ownership of fd */
+        QLIST_REMOVE(monfd, next);
+        qemu_free(monfd->name);
+        qemu_free(monfd);
+
+        return fd;
+    }
+
+    return -1;
+}
+
+static const mon_cmd_t mon_cmds[] = {
+#include "hmp-commands.h"
+    { NULL, NULL, },
+};
+
+/* Please update hmp-commands.hx when adding or changing commands */
+static const mon_cmd_t info_cmds[] = {
+    {
+        .name       = "version",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the version of QEMU",
+        .user_print = do_info_version_print,
+        .mhandler.info_new = do_info_version,
+    },
+    {
+        .name       = "network",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the network state",
+        .mhandler.info = do_info_network,
+    },
+    {
+        .name       = "chardev",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the character devices",
+        .user_print = qemu_chr_info_print,
+        .mhandler.info_new = qemu_chr_info,
+    },
+    {
+        .name       = "block",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the block devices",
+        .user_print = bdrv_info_print,
+        .mhandler.info_new = bdrv_info,
+    },
+    {
+        .name       = "blockstats",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show block device statistics",
+        .user_print = bdrv_stats_print,
+        .mhandler.info_new = bdrv_info_stats,
+    },
+    {
+        .name       = "registers",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the cpu registers",
+        .mhandler.info = do_info_registers,
+    },
+    {
+        .name       = "cpus",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show infos for each CPU",
+        .user_print = monitor_print_cpus,
+        .mhandler.info_new = do_info_cpus,
+    },
+    {
+        .name       = "history",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the command line history",
+        .mhandler.info = do_info_history,
+    },
+    {
+        .name       = "irq",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the interrupts statistics (if available)",
+        .mhandler.info = irq_info,
+    },
+    {
+        .name       = "pic",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show i8259 (PIC) state",
+        .mhandler.info = pic_info,
+    },
+    {
+        .name       = "pci",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show PCI info",
+        .user_print = do_pci_info_print,
+        .mhandler.info_new = do_pci_info,
+    },
+#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC)
+    {
+        .name       = "tlb",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show virtual to physical memory mappings",
+        .mhandler.info = tlb_info,
+    },
+#endif
+#if defined(TARGET_I386)
+    {
+        .name       = "mem",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the active virtual memory mappings",
+        .mhandler.info = mem_info,
+    },
+#endif
+    {
+        .name       = "jit",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show dynamic compiler info",
+        .mhandler.info = do_info_jit,
+    },
+    {
+        .name       = "kvm",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show KVM information",
+        .user_print = do_info_kvm_print,
+        .mhandler.info_new = do_info_kvm,
+    },
+    {
+        .name       = "numa",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show NUMA information",
+        .mhandler.info = do_info_numa,
+    },
+    {
+        .name       = "usb",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show guest USB devices",
+        .mhandler.info = usb_info,
+    },
+    {
+        .name       = "usbhost",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show host USB devices",
+        .mhandler.info = usb_host_info,
+    },
+    {
+        .name       = "profile",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show profiling information",
+        .mhandler.info = do_info_profile,
+    },
+    {
+        .name       = "capture",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show capture information",
+        .mhandler.info = do_info_capture,
+    },
+    {
+        .name       = "snapshots",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the currently saved VM snapshots",
+        .mhandler.info = do_info_snapshots,
+    },
+    {
+        .name       = "status",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM status (running|paused)",
+        .user_print = do_info_status_print,
+        .mhandler.info_new = do_info_status,
+    },
+    {
+        .name       = "pcmcia",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show guest PCMCIA status",
+        .mhandler.info = pcmcia_info,
+    },
+    {
+        .name       = "mice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show which guest mouse is receiving events",
+        .user_print = do_info_mice_print,
+        .mhandler.info_new = do_info_mice,
+    },
+    {
+        .name       = "vnc",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the vnc server status",
+        .user_print = do_info_vnc_print,
+        .mhandler.info_new = do_info_vnc,
+    },
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "spice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the spice server status",
+        .user_print = do_info_spice_print,
+        .mhandler.info_new = do_info_spice,
+    },
+#endif
+    {
+        .name       = "name",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM name",
+        .user_print = do_info_name_print,
+        .mhandler.info_new = do_info_name,
+    },
+    {
+        .name       = "uuid",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM UUID",
+        .user_print = do_info_uuid_print,
+        .mhandler.info_new = do_info_uuid,
+    },
+#if defined(TARGET_PPC)
+    {
+        .name       = "cpustats",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show CPU statistics",
+        .mhandler.info = do_info_cpu_stats,
+    },
+#endif
+#if defined(CONFIG_SLIRP)
+    {
+        .name       = "usernet",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show user network stack connection states",
+        .mhandler.info = do_info_usernet,
+    },
+#endif
+    {
+        .name       = "migrate",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show migration status",
+        .user_print = do_info_migrate_print,
+        .mhandler.info_new = do_info_migrate,
+    },
+    {
+        .name       = "balloon",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show balloon information",
+        .user_print = monitor_print_balloon,
+        .mhandler.info_async = do_info_balloon,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+    {
+        .name       = "qtree",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show device tree",
+        .mhandler.info = do_info_qtree,
+    },
+    {
+        .name       = "qdm",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show qdev device model list",
+        .mhandler.info = do_info_qdm,
+    },
+    {
+        .name       = "roms",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show roms",
+        .mhandler.info = do_info_roms,
+    },
+#if defined(CONFIG_SIMPLE_TRACE)
+    {
+        .name       = "trace",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show current contents of trace buffer",
+        .mhandler.info = do_info_trace,
+    },
+    {
+        .name       = "trace-events",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show available trace-events & their state",
+        .mhandler.info = do_info_trace_events,
+    },
+#endif
+    {
+        .name       = NULL,
+    },
+};
+
+static const mon_cmd_t qmp_cmds[] = {
+#include "qmp-commands.h"
+    { /* NULL */ },
+};
+
+static const mon_cmd_t qmp_query_cmds[] = {
+    {
+        .name       = "version",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the version of QEMU",
+        .user_print = do_info_version_print,
+        .mhandler.info_new = do_info_version,
+    },
+    {
+        .name       = "commands",
+        .args_type  = "",
+        .params     = "",
+        .help       = "list QMP available commands",
+        .user_print = monitor_user_noop,
+        .mhandler.info_new = do_info_commands,
+    },
+    {
+        .name       = "chardev",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the character devices",
+        .user_print = qemu_chr_info_print,
+        .mhandler.info_new = qemu_chr_info,
+    },
+    {
+        .name       = "block",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the block devices",
+        .user_print = bdrv_info_print,
+        .mhandler.info_new = bdrv_info,
+    },
+    {
+        .name       = "blockstats",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show block device statistics",
+        .user_print = bdrv_stats_print,
+        .mhandler.info_new = bdrv_info_stats,
+    },
+    {
+        .name       = "cpus",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show infos for each CPU",
+        .user_print = monitor_print_cpus,
+        .mhandler.info_new = do_info_cpus,
+    },
+    {
+        .name       = "pci",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show PCI info",
+        .user_print = do_pci_info_print,
+        .mhandler.info_new = do_pci_info,
+    },
+    {
+        .name       = "kvm",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show KVM information",
+        .user_print = do_info_kvm_print,
+        .mhandler.info_new = do_info_kvm,
+    },
+    {
+        .name       = "status",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM status (running|paused)",
+        .user_print = do_info_status_print,
+        .mhandler.info_new = do_info_status,
+    },
+    {
+        .name       = "mice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show which guest mouse is receiving events",
+        .user_print = do_info_mice_print,
+        .mhandler.info_new = do_info_mice,
+    },
+    {
+        .name       = "vnc",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the vnc server status",
+        .user_print = do_info_vnc_print,
+        .mhandler.info_new = do_info_vnc,
+    },
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "spice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the spice server status",
+        .user_print = do_info_spice_print,
+        .mhandler.info_new = do_info_spice,
+    },
+#endif
+    {
+        .name       = "name",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM name",
+        .user_print = do_info_name_print,
+        .mhandler.info_new = do_info_name,
+    },
+    {
+        .name       = "uuid",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the current VM UUID",
+        .user_print = do_info_uuid_print,
+        .mhandler.info_new = do_info_uuid,
+    },
+    {
+        .name       = "migrate",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show migration status",
+        .user_print = do_info_migrate_print,
+        .mhandler.info_new = do_info_migrate,
+    },
+    {
+        .name       = "balloon",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show balloon information",
+        .user_print = monitor_print_balloon,
+        .mhandler.info_async = do_info_balloon,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+    { /* 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)(const struct MonitorDef *md, int val);
+    int type;
+} MonitorDef;
+
+#if defined(TARGET_I386)
+static target_long monitor_get_pc (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return env->eip + env->segs[R_CS].base;
+}
+#endif
+
+#if defined(TARGET_PPC)
+static target_long monitor_get_ccr (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    unsigned int u;
+    int i;
+
+    u = 0;
+    for (i = 0; i < 8; i++)
+        u |= env->crf[i] << (32 - (4 * i));
+
+    return u;
+}
+
+static target_long monitor_get_msr (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return env->msr;
+}
+
+static target_long monitor_get_xer (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return env->xer;
+}
+
+static target_long monitor_get_decr (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return cpu_ppc_load_decr(env);
+}
+
+static target_long monitor_get_tbu (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return cpu_ppc_load_tbu(env);
+}
+
+static target_long monitor_get_tbl (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return cpu_ppc_load_tbl(env);
+}
+#endif
+
+#if defined(TARGET_SPARC)
+#ifndef TARGET_SPARC64
+static target_long monitor_get_psr (const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+
+    return cpu_get_psr(env);
+}
+#endif
+
+static target_long monitor_get_reg(const struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    return env->regwptr[val];
+}
+#endif
+
+static const 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, spr[SPR_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... */
+    { "pvr", offsetof(CPUState, spr[SPR_PVR]) },
+
+    { "srr0", offsetof(CPUState, spr[SPR_SRR0]) },
+    { "srr1", offsetof(CPUState, spr[SPR_SRR1]) },
+    { "sprg0", offsetof(CPUState, spr[SPR_SPRG0]) },
+    { "sprg1", offsetof(CPUState, spr[SPR_SPRG1]) },
+    { "sprg2", offsetof(CPUState, spr[SPR_SPRG2]) },
+    { "sprg3", offsetof(CPUState, spr[SPR_SPRG3]) },
+    { "sprg4", offsetof(CPUState, spr[SPR_SPRG4]) },
+    { "sprg5", offsetof(CPUState, spr[SPR_SPRG5]) },
+    { "sprg6", offsetof(CPUState, spr[SPR_SPRG6]) },
+    { "sprg7", offsetof(CPUState, spr[SPR_SPRG7]) },
+    { "pid", offsetof(CPUState, spr[SPR_BOOKE_PID]) },
+    { "csrr0", offsetof(CPUState, spr[SPR_BOOKE_CSRR0]) },
+    { "csrr1", offsetof(CPUState, spr[SPR_BOOKE_CSRR1]) },
+    { "esr", offsetof(CPUState, spr[SPR_BOOKE_ESR]) },
+    { "dear", offsetof(CPUState, spr[SPR_BOOKE_DEAR]) },
+    { "mcsr", offsetof(CPUState, spr[SPR_BOOKE_MCSR]) },
+    { "tsr", offsetof(CPUState, spr[SPR_BOOKE_TSR]) },
+    { "tcr", offsetof(CPUState, spr[SPR_BOOKE_TCR]) },
+    { "vrsave", offsetof(CPUState, spr[SPR_VRSAVE]) },
+    { "pir", offsetof(CPUState, spr[SPR_BOOKE_PIR]) },
+    { "mcsrr0", offsetof(CPUState, spr[SPR_BOOKE_MCSRR0]) },
+    { "mcsrr1", offsetof(CPUState, spr[SPR_BOOKE_MCSRR1]) },
+    { "decar", offsetof(CPUState, spr[SPR_BOOKE_DECAR]) },
+    { "ivpr", offsetof(CPUState, spr[SPR_BOOKE_IVPR]) },
+    { "epcr", offsetof(CPUState, spr[SPR_BOOKE_EPCR]) },
+    { "sprg8", offsetof(CPUState, spr[SPR_BOOKE_SPRG8]) },
+    { "ivor0", offsetof(CPUState, spr[SPR_BOOKE_IVOR0]) },
+    { "ivor1", offsetof(CPUState, spr[SPR_BOOKE_IVOR1]) },
+    { "ivor2", offsetof(CPUState, spr[SPR_BOOKE_IVOR2]) },
+    { "ivor3", offsetof(CPUState, spr[SPR_BOOKE_IVOR3]) },
+    { "ivor4", offsetof(CPUState, spr[SPR_BOOKE_IVOR4]) },
+    { "ivor5", offsetof(CPUState, spr[SPR_BOOKE_IVOR5]) },
+    { "ivor6", offsetof(CPUState, spr[SPR_BOOKE_IVOR6]) },
+    { "ivor7", offsetof(CPUState, spr[SPR_BOOKE_IVOR7]) },
+    { "ivor8", offsetof(CPUState, spr[SPR_BOOKE_IVOR8]) },
+    { "ivor9", offsetof(CPUState, spr[SPR_BOOKE_IVOR9]) },
+    { "ivor10", offsetof(CPUState, spr[SPR_BOOKE_IVOR10]) },
+    { "ivor11", offsetof(CPUState, spr[SPR_BOOKE_IVOR11]) },
+    { "ivor12", offsetof(CPUState, spr[SPR_BOOKE_IVOR12]) },
+    { "ivor13", offsetof(CPUState, spr[SPR_BOOKE_IVOR13]) },
+    { "ivor14", offsetof(CPUState, spr[SPR_BOOKE_IVOR14]) },
+    { "ivor15", offsetof(CPUState, spr[SPR_BOOKE_IVOR15]) },
+    { "ivor32", offsetof(CPUState, spr[SPR_BOOKE_IVOR32]) },
+    { "ivor33", offsetof(CPUState, spr[SPR_BOOKE_IVOR33]) },
+    { "ivor34", offsetof(CPUState, spr[SPR_BOOKE_IVOR34]) },
+    { "ivor35", offsetof(CPUState, spr[SPR_BOOKE_IVOR35]) },
+    { "ivor36", offsetof(CPUState, spr[SPR_BOOKE_IVOR36]) },
+    { "ivor37", offsetof(CPUState, spr[SPR_BOOKE_IVOR37]) },
+    { "mas0", offsetof(CPUState, spr[SPR_BOOKE_MAS0]) },
+    { "mas1", offsetof(CPUState, spr[SPR_BOOKE_MAS1]) },
+    { "mas2", offsetof(CPUState, spr[SPR_BOOKE_MAS2]) },
+    { "mas3", offsetof(CPUState, spr[SPR_BOOKE_MAS3]) },
+    { "mas4", offsetof(CPUState, spr[SPR_BOOKE_MAS4]) },
+    { "mas6", offsetof(CPUState, spr[SPR_BOOKE_MAS6]) },
+    { "mas7", offsetof(CPUState, spr[SPR_BOOKE_MAS7]) },
+    { "mmucfg", offsetof(CPUState, spr[SPR_MMUCFG]) },
+    { "tlb0cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB0CFG]) },
+    { "tlb1cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB1CFG]) },
+    { "epr", offsetof(CPUState, spr[SPR_BOOKE_EPR]) },
+    { "eplc", offsetof(CPUState, spr[SPR_BOOKE_EPLC]) },
+    { "epsc", offsetof(CPUState, spr[SPR_BOOKE_EPSC]) },
+    { "svr", offsetof(CPUState, spr[SPR_E500_SVR]) },
+    { "mcar", offsetof(CPUState, spr[SPR_Exxx_MCAR]) },
+    { "pid1", offsetof(CPUState, spr[SPR_BOOKE_PID1]) },
+    { "pid2", offsetof(CPUState, spr[SPR_BOOKE_PID2]) },
+    { "hid0", offsetof(CPUState, spr[SPR_HID0]) },
+
+#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(Monitor *mon, const char *msg)
+{
+    monitor_printf(mon, "%s\n", msg);
+    longjmp(expr_env, 1);
+}
+
+/* return 0 if OK, -1 if not found */
+static int get_monitor_def(target_long *pval, const char *name)
+{
+    const MonitorDef *md;
+    void *ptr;
+
+    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 {
+                CPUState *env = mon_get_cpu();
+                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;
+                }
+            }
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static void next(void)
+{
+    if (*pch != '\0') {
+        pch++;
+        while (qemu_isspace(*pch))
+            pch++;
+    }
+}
+
+static int64_t expr_sum(Monitor *mon);
+
+static int64_t expr_unary(Monitor *mon)
+{
+    int64_t n;
+    char *p;
+    int ret;
+
+    switch(*pch) {
+    case '+':
+        next();
+        n = expr_unary(mon);
+        break;
+    case '-':
+        next();
+        n = -expr_unary(mon);
+        break;
+    case '~':
+        next();
+        n = ~expr_unary(mon);
+        break;
+    case '(':
+        next();
+        n = expr_sum(mon);
+        if (*pch != ')') {
+            expr_error(mon, "')' expected");
+        }
+        next();
+        break;
+    case '\'':
+        pch++;
+        if (*pch == '\0')
+            expr_error(mon, "character constant expected");
+        n = *pch;
+        pch++;
+        if (*pch != '\'')
+            expr_error(mon, "missing terminating \' character");
+        next();
+        break;
+    case '$':
+        {
+            char buf[128], *q;
+            target_long reg=0;
+
+            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 (qemu_isspace(*pch))
+                pch++;
+            *q = 0;
+            ret = get_monitor_def(&reg, buf);
+            if (ret < 0)
+                expr_error(mon, "unknown register");
+            n = reg;
+        }
+        break;
+    case '\0':
+        expr_error(mon, "unexpected end of expression");
+        n = 0;
+        break;
+    default:
+#if TARGET_PHYS_ADDR_BITS > 32
+        n = strtoull(pch, &p, 0);
+#else
+        n = strtoul(pch, &p, 0);
+#endif
+        if (pch == p) {
+            expr_error(mon, "invalid char in expression");
+        }
+        pch = p;
+        while (qemu_isspace(*pch))
+            pch++;
+        break;
+    }
+    return n;
+}
+
+
+static int64_t expr_prod(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_unary(mon);
+    for(;;) {
+        op = *pch;
+        if (op != '*' && op != '/' && op != '%')
+            break;
+        next();
+        val2 = expr_unary(mon);
+        switch(op) {
+        default:
+        case '*':
+            val *= val2;
+            break;
+        case '/':
+        case '%':
+            if (val2 == 0)
+                expr_error(mon, "division by zero");
+            if (op == '/')
+                val /= val2;
+            else
+                val %= val2;
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_logic(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_prod(mon);
+    for(;;) {
+        op = *pch;
+        if (op != '&' && op != '|' && op != '^')
+            break;
+        next();
+        val2 = expr_prod(mon);
+        switch(op) {
+        default:
+        case '&':
+            val &= val2;
+            break;
+        case '|':
+            val |= val2;
+            break;
+        case '^':
+            val ^= val2;
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_sum(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_logic(mon);
+    for(;;) {
+        op = *pch;
+        if (op != '+' && op != '-')
+            break;
+        next();
+        val2 = expr_logic(mon);
+        if (op == '+')
+            val += val2;
+        else
+            val -= val2;
+    }
+    return val;
+}
+
+static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
+{
+    pch = *pp;
+    if (setjmp(expr_env)) {
+        *pp = pch;
+        return -1;
+    }
+    while (qemu_isspace(*pch))
+        pch++;
+    *pval = expr_sum(mon);
+    *pp = pch;
+    return 0;
+}
+
+static int get_double(Monitor *mon, double *pval, const char **pp)
+{
+    const char *p = *pp;
+    char *tailp;
+    double d;
+
+    d = strtod(p, &tailp);
+    if (tailp == p) {
+        monitor_printf(mon, "Number expected\n");
+        return -1;
+    }
+    if (d != d || d - d != 0) {
+        /* NaN or infinity */
+        monitor_printf(mon, "Bad number\n");
+        return -1;
+    }
+    *pval = d;
+    *pp = tailp;
+    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 (qemu_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' && !qemu_isspace(*p)) {
+            if ((q - buf) < buf_size - 1) {
+                *q++ = *p;
+            }
+            p++;
+        }
+    }
+    *q = '\0';
+    *pp = p;
+    return 0;
+}
+
+/*
+ * Store the command-name in cmdname, and return a pointer to
+ * the remaining of the command string.
+ */
+static const char *get_command_name(const char *cmdline,
+                                    char *cmdname, size_t nlen)
+{
+    size_t len;
+    const char *p, *pstart;
+
+    p = cmdline;
+    while (qemu_isspace(*p))
+        p++;
+    if (*p == '\0')
+        return NULL;
+    pstart = p;
+    while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
+        p++;
+    len = p - pstart;
+    if (len > nlen - 1)
+        len = nlen - 1;
+    memcpy(cmdname, pstart, len);
+    cmdname[len] = '\0';
+    return p;
+}
+
+/**
+ * Read key of 'type' into 'key' and return the current
+ * 'type' pointer.
+ */
+static char *key_get_info(const char *type, char **key)
+{
+    size_t len;
+    char *p, *str;
+
+    if (*type == ',')
+        type++;
+
+    p = strchr(type, ':');
+    if (!p) {
+        *key = NULL;
+        return NULL;
+    }
+    len = p - type;
+
+    str = qemu_malloc(len + 1);
+    memcpy(str, type, len);
+    str[len] = '\0';
+
+    *key = str;
+    return ++p;
+}
+
+static int default_fmt_format = 'x';
+static int default_fmt_size = 4;
+
+#define MAX_ARGS 16
+
+static int is_valid_option(const char *c, const char *typestr)
+{
+    char option[3];
+  
+    option[0] = '-';
+    option[1] = *c;
+    option[2] = '\0';
+  
+    typestr = strstr(typestr, option);
+    return (typestr != NULL);
+}
+
+static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
+                                              const char *cmdname)
+{
+    const mon_cmd_t *cmd;
+
+    for (cmd = disp_table; cmd->name != NULL; cmd++) {
+        if (compare_cmd(cmdname, cmd->name)) {
+            return cmd;
+        }
+    }
+
+    return NULL;
+}
+
+static const mon_cmd_t *monitor_find_command(const char *cmdname)
+{
+    return search_dispatch_table(mon_cmds, cmdname);
+}
+
+static const mon_cmd_t *qmp_find_query_cmd(const char *info_item)
+{
+    return search_dispatch_table(qmp_query_cmds, info_item);
+}
+
+static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
+{
+    return search_dispatch_table(qmp_cmds, cmdname);
+}
+
+static const mon_cmd_t *monitor_parse_command(Monitor *mon,
+                                              const char *cmdline,
+                                              QDict *qdict)
+{
+    const char *p, *typestr;
+    int c;
+    const mon_cmd_t *cmd;
+    char cmdname[256];
+    char buf[1024];
+    char *key;
+
+#ifdef DEBUG
+    monitor_printf(mon, "command='%s'\n", cmdline);
+#endif
+
+    /* extract the command name */
+    p = get_command_name(cmdline, cmdname, sizeof(cmdname));
+    if (!p)
+        return NULL;
+
+    cmd = monitor_find_command(cmdname);
+    if (!cmd) {
+        monitor_printf(mon, "unknown command: '%s'\n", cmdname);
+        return NULL;
+    }
+
+    /* parse the parameters */
+    typestr = cmd->args_type;
+    for(;;) {
+        typestr = key_get_info(typestr, &key);
+        if (!typestr)
+            break;
+        c = *typestr;
+        typestr++;
+        switch(c) {
+        case 'F':
+        case 'B':
+        case 's':
+            {
+                int ret;
+
+                while (qemu_isspace(*p))
+                    p++;
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        /* no optional string: NULL argument */
+                        break;
+                    }
+                }
+                ret = get_str(buf, sizeof(buf), &p);
+                if (ret < 0) {
+                    switch(c) {
+                    case 'F':
+                        monitor_printf(mon, "%s: filename expected\n",
+                                       cmdname);
+                        break;
+                    case 'B':
+                        monitor_printf(mon, "%s: block device name expected\n",
+                                       cmdname);
+                        break;
+                    default:
+                        monitor_printf(mon, "%s: string expected\n", cmdname);
+                        break;
+                    }
+                    goto fail;
+                }
+                qdict_put(qdict, key, qstring_from_str(buf));
+            }
+            break;
+        case 'O':
+            {
+                QemuOptsList *opts_list;
+                QemuOpts *opts;
+
+                opts_list = qemu_find_opts(key);
+                if (!opts_list || opts_list->desc->name) {
+                    goto bad_type;
+                }
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                if (!*p)
+                    break;
+                if (get_str(buf, sizeof(buf), &p) < 0) {
+                    goto fail;
+                }
+                opts = qemu_opts_parse(opts_list, buf, 1);
+                if (!opts) {
+                    goto fail;
+                }
+                qemu_opts_to_qdict(opts, qdict);
+                qemu_opts_del(opts);
+            }
+            break;
+        case '/':
+            {
+                int count, format, size;
+
+                while (qemu_isspace(*p))
+                    p++;
+                if (*p == '/') {
+                    /* format found */
+                    p++;
+                    count = 1;
+                    if (qemu_isdigit(*p)) {
+                        count = 0;
+                        while (qemu_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' && !qemu_isspace(*p)) {
+                        monitor_printf(mon, "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;
+                    }
+                }
+                qdict_put(qdict, "count", qint_from_int(count));
+                qdict_put(qdict, "format", qint_from_int(format));
+                qdict_put(qdict, "size", qint_from_int(size));
+            }
+            break;
+        case 'i':
+        case 'l':
+        case 'M':
+            {
+                int64_t val;
+
+                while (qemu_isspace(*p))
+                    p++;
+                if (*typestr == '?' || *typestr == '.') {
+                    if (*typestr == '?') {
+                        if (*p == '\0') {
+                            typestr++;
+                            break;
+                        }
+                    } else {
+                        if (*p == '.') {
+                            p++;
+                            while (qemu_isspace(*p))
+                                p++;
+                        } else {
+                            typestr++;
+                            break;
+                        }
+                    }
+                    typestr++;
+                }
+                if (get_expr(mon, &val, &p))
+                    goto fail;
+                /* Check if 'i' is greater than 32-bit */
+                if ((c == 'i') && ((val >> 32) & 0xffffffff)) {
+                    monitor_printf(mon, "\'%s\' has failed: ", cmdname);
+                    monitor_printf(mon, "integer is for 32-bit values\n");
+                    goto fail;
+                } else if (c == 'M') {
+                    val <<= 20;
+                }
+                qdict_put(qdict, key, qint_from_int(val));
+            }
+            break;
+        case 'o':
+            {
+                int64_t val;
+                char *end;
+
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        break;
+                    }
+                }
+                val = strtosz(p, &end);
+                if (val < 0) {
+                    monitor_printf(mon, "invalid size\n");
+                    goto fail;
+                }
+                qdict_put(qdict, key, qint_from_int(val));
+                p = end;
+            }
+            break;
+        case 'T':
+            {
+                double val;
+
+                while (qemu_isspace(*p))
+                    p++;
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        break;
+                    }
+                }
+                if (get_double(mon, &val, &p) < 0) {
+                    goto fail;
+                }
+                if (p[0] && p[1] == 's') {
+                    switch (*p) {
+                    case 'm':
+                        val /= 1e3; p += 2; break;
+                    case 'u':
+                        val /= 1e6; p += 2; break;
+                    case 'n':
+                        val /= 1e9; p += 2; break;
+                    }
+                }
+                if (*p && !qemu_isspace(*p)) {
+                    monitor_printf(mon, "Unknown unit suffix\n");
+                    goto fail;
+                }
+                qdict_put(qdict, key, qfloat_from_double(val));
+            }
+            break;
+        case 'b':
+            {
+                const char *beg;
+                int val;
+
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                beg = p;
+                while (qemu_isgraph(*p)) {
+                    p++;
+                }
+                if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
+                    val = 1;
+                } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
+                    val = 0;
+                } else {
+                    monitor_printf(mon, "Expected 'on' or 'off'\n");
+                    goto fail;
+                }
+                qdict_put(qdict, key, qbool_from_int(val));
+            }
+            break;
+        case '-':
+            {
+                const char *tmp = p;
+                int skip_key = 0;
+                /* option */
+
+                c = *typestr++;
+                if (c == '\0')
+                    goto bad_type;
+                while (qemu_isspace(*p))
+                    p++;
+                if (*p == '-') {
+                    p++;
+                    if(c != *p) {
+                        if(!is_valid_option(p, typestr)) {
+                  
+                            monitor_printf(mon, "%s: unsupported option -%c\n",
+                                           cmdname, *p);
+                            goto fail;
+                        } else {
+                            skip_key = 1;
+                        }
+                    }
+                    if(skip_key) {
+                        p = tmp;
+                    } else {
+                        /* has option */
+                        p++;
+                        qdict_put(qdict, key, qbool_from_int(1));
+                    }
+                }
+            }
+            break;
+        default:
+        bad_type:
+            monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
+            goto fail;
+        }
+        qemu_free(key);
+        key = NULL;
+    }
+    /* check that all arguments were parsed */
+    while (qemu_isspace(*p))
+        p++;
+    if (*p != '\0') {
+        monitor_printf(mon, "%s: extraneous characters at the end of line\n",
+                       cmdname);
+        goto fail;
+    }
+
+    return cmd;
+
+fail:
+    qemu_free(key);
+    return NULL;
+}
+
+void monitor_set_error(Monitor *mon, QError *qerror)
+{
+    /* report only the first error */
+    if (!mon->error) {
+        mon->error = qerror;
+    } else {
+        MON_DEBUG("Additional error report at %s:%d\n",
+                  qerror->file, qerror->linenr);
+        QDECREF(qerror);
+    }
+}
+
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+    if (ret && !monitor_has_error(mon)) {
+        /*
+         * If it returns failure, it must have passed on error.
+         *
+         * Action: Report an internal error to the client if in QMP.
+         */
+        qerror_report(QERR_UNDEFINED_ERROR);
+        MON_DEBUG("command '%s' returned failure but did not pass an error\n",
+                  cmd->name);
+    }
+
+#ifdef CONFIG_DEBUG_MONITOR
+    if (!ret && monitor_has_error(mon)) {
+        /*
+         * If it returns success, it must not have passed an error.
+         *
+         * Action: Report the passed error to the client.
+         */
+        MON_DEBUG("command '%s' returned success but passed an error\n",
+                  cmd->name);
+    }
+
+    if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
+        /*
+         * Handlers should not call Monitor print functions.
+         *
+         * Action: Ignore them in QMP.
+         *
+         * (XXX: we don't check any 'info' or 'query' command here
+         * because the user print function _is_ called by do_info(), hence
+         * we will trigger this check. This problem will go away when we
+         * make 'query' commands real and kill do_info())
+         */
+        MON_DEBUG("command '%s' called print functions %d time(s)\n",
+                  cmd->name, mon_print_count_get(mon));
+    }
+#endif
+}
+
+static void handle_user_command(Monitor *mon, const char *cmdline)
+{
+    QDict *qdict;
+    const mon_cmd_t *cmd;
+
+    qdict = qdict_new();
+
+    cmd = monitor_parse_command(mon, cmdline, qdict);
+    if (!cmd)
+        goto out;
+
+    if (handler_is_async(cmd)) {
+        user_async_cmd_handler(mon, cmd, qdict);
+    } else if (handler_is_qobject(cmd)) {
+        QObject *data = NULL;
+
+        /* XXX: ignores the error code */
+        cmd->mhandler.cmd_new(mon, qdict, &data);
+        assert(!monitor_has_error(mon));
+        if (data) {
+            cmd->user_print(mon, data);
+            qobject_decref(data);
+        }
+    } else {
+        cmd->mhandler.cmd(mon, qdict);
+    }
+
+out:
+    QDECREF(qdict);
+}
+
+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))) {
+            readline_add_completion(cur_mon->rs, cmd);
+        }
+        if (*p == '\0')
+            break;
+        p++;
+    }
+}
+
+static void file_completion(const char *input)
+{
+    DIR *ffs;
+    struct dirent *d;
+    char path[1024];
+    char file[1024], file_prefix[1024];
+    int input_path_len;
+    const char *p;
+
+    p = strrchr(input, '/');
+    if (!p) {
+        input_path_len = 0;
+        pstrcpy(file_prefix, sizeof(file_prefix), input);
+        pstrcpy(path, sizeof(path), ".");
+    } else {
+        input_path_len = p - input + 1;
+        memcpy(path, input, input_path_len);
+        if (input_path_len > sizeof(path) - 1)
+            input_path_len = sizeof(path) - 1;
+        path[input_path_len] = '\0';
+        pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
+    }
+#ifdef DEBUG_COMPLETION
+    monitor_printf(cur_mon, "input='%s' path='%s' prefix='%s'\n",
+                   input, path, file_prefix);
+#endif
+    ffs = opendir(path);
+    if (!ffs)
+        return;
+    for(;;) {
+        struct stat sb;
+        d = readdir(ffs);
+        if (!d)
+            break;
+
+        if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
+            continue;
+        }
+
+        if (strstart(d->d_name, file_prefix, NULL)) {
+            memcpy(file, input, input_path_len);
+            if (input_path_len < sizeof(file))
+                pstrcpy(file + input_path_len, sizeof(file) - input_path_len,
+                        d->d_name);
+            /* stat the file to find out if it's a directory.
+             * In that case add a slash to speed up typing long paths
+             */
+            stat(file, &sb);
+            if(S_ISDIR(sb.st_mode))
+                pstrcat(file, sizeof(file), "/");
+            readline_add_completion(cur_mon->rs, file);
+        }
+    }
+    closedir(ffs);
+}
+
+static void block_completion_it(void *opaque, BlockDriverState *bs)
+{
+    const char *name = bdrv_get_device_name(bs);
+    const char *input = opaque;
+
+    if (input[0] == '\0' ||
+        !strncmp(name, (char *)input, strlen(input))) {
+        readline_add_completion(cur_mon->rs, 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 (qemu_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;
+}
+
+static const char *next_arg_type(const char *typestr)
+{
+    const char *p = strchr(typestr, ':');
+    return (p != NULL ? ++p : typestr);
+}
+
+static void monitor_find_completion(const char *cmdline)
+{
+    const char *cmdname;
+    char *args[MAX_ARGS];
+    int nb_args, i, len;
+    const char *ptype, *str;
+    const mon_cmd_t *cmd;
+    const KeyDef *key;
+
+    parse_cmdline(cmdline, &nb_args, args);
+#ifdef DEBUG_COMPLETION
+    for(i = 0; i < nb_args; i++) {
+        monitor_printf(cur_mon, "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 && qemu_isspace(cmdline[len - 1])) {
+        if (nb_args >= MAX_ARGS) {
+            goto cleanup;
+        }
+        args[nb_args++] = qemu_strdup("");
+    }
+    if (nb_args <= 1) {
+        /* command completion */
+        if (nb_args == 0)
+            cmdname = "";
+        else
+            cmdname = args[0];
+        readline_set_completion_index(cur_mon->rs, strlen(cmdname));
+        for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
+            cmd_completion(cmdname, cmd->name);
+        }
+    } else {
+        /* find the command */
+        for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
+            if (compare_cmd(args[0], cmd->name)) {
+                break;
+            }
+        }
+        if (!cmd->name) {
+            goto cleanup;
+        }
+
+        ptype = next_arg_type(cmd->args_type);
+        for(i = 0; i < nb_args - 2; i++) {
+            if (*ptype != '\0') {
+                ptype = next_arg_type(ptype);
+                while (*ptype == '?')
+                    ptype = next_arg_type(ptype);
+            }
+        }
+        str = args[nb_args - 1];
+        if (*ptype == '-' && ptype[1] != '\0') {
+            ptype = next_arg_type(ptype);
+        }
+        switch(*ptype) {
+        case 'F':
+            /* file completion */
+            readline_set_completion_index(cur_mon->rs, strlen(str));
+            file_completion(str);
+            break;
+        case 'B':
+            /* block device name completion */
+            readline_set_completion_index(cur_mon->rs, strlen(str));
+            bdrv_iterate(block_completion_it, (void *)str);
+            break;
+        case 's':
+            /* XXX: more generic ? */
+            if (!strcmp(cmd->name, "info")) {
+                readline_set_completion_index(cur_mon->rs, strlen(str));
+                for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+                    cmd_completion(str, cmd->name);
+                }
+            } else if (!strcmp(cmd->name, "sendkey")) {
+                char *sep = strrchr(str, '-');
+                if (sep)
+                    str = sep + 1;
+                readline_set_completion_index(cur_mon->rs, strlen(str));
+                for(key = key_defs; key->name != NULL; key++) {
+                    cmd_completion(str, key->name);
+                }
+            } else if (!strcmp(cmd->name, "help|?")) {
+                readline_set_completion_index(cur_mon->rs, strlen(str));
+                for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
+                    cmd_completion(str, cmd->name);
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+cleanup:
+    for (i = 0; i < nb_args; i++) {
+        qemu_free(args[i]);
+    }
+}
+
+static int monitor_can_read(void *opaque)
+{
+    Monitor *mon = opaque;
+
+    return (mon->suspend_cnt == 0) ? 1 : 0;
+}
+
+static int invalid_qmp_mode(const Monitor *mon, const char *cmd_name)
+{
+    int is_cap = compare_cmd(cmd_name, "qmp_capabilities");
+    return (qmp_cmd_mode(mon) ? is_cap : !is_cap);
+}
+
+/*
+ * Argument validation rules:
+ *
+ * 1. The argument must exist in cmd_args qdict
+ * 2. The argument type must be the expected one
+ *
+ * Special case: If the argument doesn't exist in cmd_args and
+ *               the QMP_ACCEPT_UNKNOWNS flag is set, then the
+ *               checking is skipped for it.
+ */
+static int check_client_args_type(const QDict *client_args,
+                                  const QDict *cmd_args, int flags)
+{
+    const QDictEntry *ent;
+
+    for (ent = qdict_first(client_args); ent;ent = qdict_next(client_args,ent)){
+        QObject *obj;
+        QString *arg_type;
+        const QObject *client_arg = qdict_entry_value(ent);
+        const char *client_arg_name = qdict_entry_key(ent);
+
+        obj = qdict_get(cmd_args, client_arg_name);
+        if (!obj) {
+            if (flags & QMP_ACCEPT_UNKNOWNS) {
+                /* handler accepts unknowns */
+                continue;
+            }
+            /* client arg doesn't exist */
+            qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
+            return -1;
+        }
+
+        arg_type = qobject_to_qstring(obj);
+        assert(arg_type != NULL);
+
+        /* check if argument's type is correct */
+        switch (qstring_get_str(arg_type)[0]) {
+        case 'F':
+        case 'B':
+        case 's':
+            if (qobject_type(client_arg) != QTYPE_QSTRING) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "string");
+                return -1;
+            }
+        break;
+        case 'i':
+        case 'l':
+        case 'M':
+        case 'o':
+            if (qobject_type(client_arg) != QTYPE_QINT) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "int");
+                return -1; 
+            }
+            break;
+        case 'T':
+            if (qobject_type(client_arg) != QTYPE_QINT &&
+                qobject_type(client_arg) != QTYPE_QFLOAT) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "number");
+               return -1; 
+            }
+            break;
+        case 'b':
+        case '-':
+            if (qobject_type(client_arg) != QTYPE_QBOOL) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "bool");
+               return -1; 
+            }
+            break;
+        case 'O':
+            assert(flags & QMP_ACCEPT_UNKNOWNS);
+            break;
+        case '/':
+        case '.':
+            /*
+             * These types are not supported by QMP and thus are not
+             * handled here. Fall through.
+             */
+        default:
+            abort();
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * - Check if the client has passed all mandatory args
+ * - Set special flags for argument validation
+ */
+static int check_mandatory_args(const QDict *cmd_args,
+                                const QDict *client_args, int *flags)
+{
+    const QDictEntry *ent;
+
+    for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent)) {
+        const char *cmd_arg_name = qdict_entry_key(ent);
+        QString *type = qobject_to_qstring(qdict_entry_value(ent));
+        assert(type != NULL);
+
+        if (qstring_get_str(type)[0] == 'O') {
+            assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
+            *flags |= QMP_ACCEPT_UNKNOWNS;
+        } else if (qstring_get_str(type)[0] != '-' &&
+                   qstring_get_str(type)[1] != '?' &&
+                   !qdict_haskey(client_args, cmd_arg_name)) {
+            qerror_report(QERR_MISSING_PARAMETER, cmd_arg_name);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static QDict *qdict_from_args_type(const char *args_type)
+{
+    int i;
+    QDict *qdict;
+    QString *key, *type, *cur_qs;
+
+    assert(args_type != NULL);
+
+    qdict = qdict_new();
+
+    if (args_type == NULL || args_type[0] == '\0') {
+        /* no args, empty qdict */
+        goto out;
+    }
+
+    key = qstring_new();
+    type = qstring_new();
+
+    cur_qs = key;
+
+    for (i = 0;; i++) {
+        switch (args_type[i]) {
+            case ',':
+            case '\0':
+                qdict_put(qdict, qstring_get_str(key), type);
+                QDECREF(key);
+                if (args_type[i] == '\0') {
+                    goto out;
+                }
+                type = qstring_new(); /* qdict has ref */
+                cur_qs = key = qstring_new();
+                break;
+            case ':':
+                cur_qs = type;
+                break;
+            default:
+                qstring_append_chr(cur_qs, args_type[i]);
+                break;
+        }
+    }
+
+out:
+    return qdict;
+}
+
+/*
+ * Client argument checking rules:
+ *
+ * 1. Client must provide all mandatory arguments
+ * 2. Each argument provided by the client must be expected
+ * 3. Each argument provided by the client must have the type expected
+ *    by the command
+ */
+static int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args)
+{
+    int flags, err;
+    QDict *cmd_args;
+
+    cmd_args = qdict_from_args_type(cmd->args_type);
+
+    flags = 0;
+    err = check_mandatory_args(cmd_args, client_args, &flags);
+    if (err) {
+        goto out;
+    }
+
+    err = check_client_args_type(client_args, cmd_args, flags);
+
+out:
+    QDECREF(cmd_args);
+    return err;
+}
+
+/*
+ * Input object checking rules
+ *
+ * 1. Input object must be a dict
+ * 2. The "execute" key must exist
+ * 3. The "execute" key must be a string
+ * 4. If the "arguments" key exists, it must be a dict
+ * 5. If the "id" key exists, it can be anything (ie. json-value)
+ * 6. Any argument not listed above is considered invalid
+ */
+static QDict *qmp_check_input_obj(QObject *input_obj)
+{
+    const QDictEntry *ent;
+    int has_exec_key = 0;
+    QDict *input_dict;
+
+    if (qobject_type(input_obj) != QTYPE_QDICT) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
+        return NULL;
+    }
+
+    input_dict = qobject_to_qdict(input_obj);
+
+    for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
+        const char *arg_name = qdict_entry_key(ent);
+        const QObject *arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
+                              "string");
+                return NULL;
+            }
+            has_exec_key = 1;
+        } else if (!strcmp(arg_name, "arguments")) {
+            if (qobject_type(arg_obj) != QTYPE_QDICT) {
+                qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments",
+                              "object");
+                return NULL;
+            }
+        } else if (!strcmp(arg_name, "id")) {
+            /* FIXME: check duplicated IDs for async commands */
+        } else {
+            qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    return input_dict;
+}
+
+static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
+{
+    QObject *ret_data = NULL;
+
+    if (handler_is_async(cmd)) {
+        qmp_async_info_handler(mon, cmd);
+        if (monitor_has_error(mon)) {
+            monitor_protocol_emitter(mon, NULL);
+        }
+    } else {
+        cmd->mhandler.info_new(mon, &ret_data);
+        monitor_protocol_emitter(mon, ret_data);
+        qobject_decref(ret_data);
+    }
+}
+
+static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
+                         const QDict *params)
+{
+    int ret;
+    QObject *data = NULL;
+
+    mon_print_count_init(mon);
+
+    ret = cmd->mhandler.cmd_new(mon, params, &data);
+    handler_audit(mon, cmd, ret);
+    monitor_protocol_emitter(mon, data);
+    qobject_decref(data);
+}
+
+static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
+{
+    int err;
+    QObject *obj;
+    QDict *input, *args;
+    const mon_cmd_t *cmd;
+    Monitor *mon = cur_mon;
+    const char *cmd_name, *query_cmd;
+
+    query_cmd = NULL;
+    args = input = NULL;
+
+    obj = json_parser_parse(tokens, NULL);
+    if (!obj) {
+        // FIXME: should be triggered in json_parser_parse()
+        qerror_report(QERR_JSON_PARSING);
+        goto err_out;
+    }
+
+    input = qmp_check_input_obj(obj);
+    if (!input) {
+        qobject_decref(obj);
+        goto err_out;
+    }
+
+    mon->mc->id = qdict_get(input, "id");
+    qobject_incref(mon->mc->id);
+
+    cmd_name = qdict_get_str(input, "execute");
+    if (invalid_qmp_mode(mon, cmd_name)) {
+        qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
+        goto err_out;
+    }
+
+    if (strstart(cmd_name, "query-", &query_cmd)) {
+        cmd = qmp_find_query_cmd(query_cmd);
+    } else {
+        cmd = qmp_find_cmd(cmd_name);
+    }
+
+    if (!cmd) {
+        qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
+        goto err_out;
+    }
+
+    obj = qdict_get(input, "arguments");
+    if (!obj) {
+        args = qdict_new();
+    } else {
+        args = qobject_to_qdict(obj);
+        QINCREF(args);
+    }
+
+    err = qmp_check_client_args(cmd, args);
+    if (err < 0) {
+        goto err_out;
+    }
+
+    if (query_cmd) {
+        qmp_call_query_cmd(mon, cmd);
+    } else if (handler_is_async(cmd)) {
+        err = qmp_async_cmd_handler(mon, cmd, args);
+        if (err) {
+            /* emit the error response */
+            goto err_out;
+        }
+    } else {
+        qmp_call_cmd(mon, cmd, args);
+    }
+
+    goto out;
+
+err_out:
+    monitor_protocol_emitter(mon, NULL);
+out:
+    QDECREF(input);
+    QDECREF(args);
+}
+
+/**
+ * monitor_control_read(): Read and handle QMP input
+ */
+static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
+{
+    Monitor *old_mon = cur_mon;
+
+    cur_mon = opaque;
+
+    json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
+
+    cur_mon = old_mon;
+}
+
+static void monitor_read(void *opaque, const uint8_t *buf, int size)
+{
+    Monitor *old_mon = cur_mon;
+    int i;
+
+    cur_mon = opaque;
+
+    if (cur_mon->rs) {
+        for (i = 0; i < size; i++)
+            readline_handle_byte(cur_mon->rs, buf[i]);
+    } else {
+        if (size == 0 || buf[size - 1] != 0)
+            monitor_printf(cur_mon, "corrupted command\n");
+        else
+            handle_user_command(cur_mon, (char *)buf);
+    }
+
+    cur_mon = old_mon;
+}
+
+static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
+{
+    monitor_suspend(mon);
+    handle_user_command(mon, cmdline);
+    monitor_resume(mon);
+}
+
+int monitor_suspend(Monitor *mon)
+{
+    if (!mon->rs)
+        return -ENOTTY;
+    mon->suspend_cnt++;
+    return 0;
+}
+
+void monitor_resume(Monitor *mon)
+{
+    if (!mon->rs)
+        return;
+    if (--mon->suspend_cnt == 0)
+        readline_show_prompt(mon->rs);
+}
+
+static QObject *get_qmp_greeting(void)
+{
+    QObject *ver;
+
+    do_info_version(NULL, &ver);
+    return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
+}
+
+/**
+ * monitor_control_event(): Print QMP gretting
+ */
+static void monitor_control_event(void *opaque, int event)
+{
+    QObject *data;
+    Monitor *mon = opaque;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        mon->mc->command_mode = 0;
+        json_message_parser_init(&mon->mc->parser, handle_qmp_command);
+        data = get_qmp_greeting();
+        monitor_json_emitter(mon, data);
+        qobject_decref(data);
+        break;
+    case CHR_EVENT_CLOSED:
+        json_message_parser_destroy(&mon->mc->parser);
+        break;
+    }
+}
+
+static void monitor_event(void *opaque, int event)
+{
+    Monitor *mon = opaque;
+
+    switch (event) {
+    case CHR_EVENT_MUX_IN:
+        mon->mux_out = 0;
+        if (mon->reset_seen) {
+            readline_restart(mon->rs);
+            monitor_resume(mon);
+            monitor_flush(mon);
+        } else {
+            mon->suspend_cnt = 0;
+        }
+        break;
+
+    case CHR_EVENT_MUX_OUT:
+        if (mon->reset_seen) {
+            if (mon->suspend_cnt == 0) {
+                monitor_printf(mon, "\n");
+            }
+            monitor_flush(mon);
+            monitor_suspend(mon);
+        } else {
+            mon->suspend_cnt++;
+        }
+        mon->mux_out = 1;
+        break;
+
+    case CHR_EVENT_OPENED:
+        monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
+                       "information\n", QEMU_VERSION);
+        if (!mon->mux_out) {
+            readline_show_prompt(mon->rs);
+        }
+        mon->reset_seen = 1;
+        break;
+    }
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
+
+void monitor_init(CharDriverState *chr, int flags)
+{
+    static int is_first_init = 1;
+    Monitor *mon;
+
+    if (is_first_init) {
+        key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
+        is_first_init = 0;
+    }
+
+    mon = qemu_mallocz(sizeof(*mon));
+
+    mon->chr = chr;
+    mon->flags = flags;
+    if (flags & MONITOR_USE_READLINE) {
+        mon->rs = readline_init(mon, monitor_find_completion);
+        monitor_read_command(mon, 0);
+    }
+
+    if (monitor_ctrl_mode(mon)) {
+        mon->mc = qemu_mallocz(sizeof(MonitorControl));
+        /* Control mode requires special handlers */
+        qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
+                              monitor_control_event, mon);
+        qemu_chr_set_echo(chr, true);
+    } else {
+        qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
+                              monitor_event, mon);
+    }
+
+    QLIST_INSERT_HEAD(&mon_list, mon, entry);
+    if (!default_mon || (flags & MONITOR_IS_DEFAULT))
+        default_mon = mon;
+}
+
+static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
+{
+    BlockDriverState *bs = opaque;
+    int ret = 0;
+
+    if (bdrv_set_key(bs, password) != 0) {
+        monitor_printf(mon, "invalid password\n");
+        ret = -EPERM;
+    }
+    if (mon->password_completion_cb)
+        mon->password_completion_cb(mon->password_opaque, ret);
+
+    monitor_read_command(mon, 1);
+}
+
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                BlockDriverCompletionFunc *completion_cb,
+                                void *opaque)
+{
+    int err;
+
+    if (!bdrv_key_required(bs)) {
+        if (completion_cb)
+            completion_cb(opaque, 0);
+        return 0;
+    }
+
+    if (monitor_ctrl_mode(mon)) {
+        qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+        return -1;
+    }
+
+    monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
+                   bdrv_get_encrypted_filename(bs));
+
+    mon->password_completion_cb = completion_cb;
+    mon->password_opaque = opaque;
+
+    err = monitor_read_password(mon, bdrv_password_cb, bs);
+
+    if (err && completion_cb)
+        completion_cb(opaque, err);
+
+    return err;
+}
diff --git a/qemu-0.15.x/monitor.h b/qemu-0.15.x/monitor.h
new file mode 100644
index 0000000..4f2d328
--- /dev/null
+++ b/qemu-0.15.x/monitor.h
@@ -0,0 +1,65 @@
+#ifndef MONITOR_H
+#define MONITOR_H
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "qerror.h"
+#include "qdict.h"
+#include "block.h"
+
+extern Monitor *cur_mon;
+extern Monitor *default_mon;
+
+/* flags for monitor_init */
+#define MONITOR_IS_DEFAULT    0x01
+#define MONITOR_USE_READLINE  0x02
+#define MONITOR_USE_CONTROL   0x04
+#define MONITOR_USE_PRETTY    0x08
+
+/* flags for monitor commands */
+#define MONITOR_CMD_ASYNC       0x0001
+
+/* QMP events */
+typedef enum MonitorEvent {
+    QEVENT_SHUTDOWN,
+    QEVENT_RESET,
+    QEVENT_POWERDOWN,
+    QEVENT_STOP,
+    QEVENT_RESUME,
+    QEVENT_VNC_CONNECTED,
+    QEVENT_VNC_INITIALIZED,
+    QEVENT_VNC_DISCONNECTED,
+    QEVENT_BLOCK_IO_ERROR,
+    QEVENT_RTC_CHANGE,
+    QEVENT_WATCHDOG,
+    QEVENT_SPICE_CONNECTED,
+    QEVENT_SPICE_INITIALIZED,
+    QEVENT_SPICE_DISCONNECTED,
+    QEVENT_MAX,
+} MonitorEvent;
+
+int monitor_cur_is_qmp(void);
+
+void monitor_protocol_event(MonitorEvent event, QObject *data);
+void monitor_init(CharDriverState *chr, int flags);
+
+int monitor_suspend(Monitor *mon);
+void monitor_resume(Monitor *mon);
+
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                BlockDriverCompletionFunc *completion_cb,
+                                void *opaque);
+
+int monitor_get_fd(Monitor *mon, const char *fdname);
+
+void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
+    GCC_FMT_ATTR(2, 0);
+void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void monitor_print_filename(Monitor *mon, const char *filename);
+void monitor_flush(Monitor *mon);
+
+typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
+
+void monitor_set_error(Monitor *mon, QError *qerror);
+
+#endif /* !MONITOR_H */
diff --git a/qemu-0.15.x/nbd.c b/qemu-0.15.x/nbd.c
new file mode 100644
index 0000000..e7a585d
--- /dev/null
+++ b/qemu-0.15.x/nbd.c
@@ -0,0 +1,666 @@
+/*
+ *  Copyright (C) 2005  Anthony Liguori <anthony at codemonkey.ws>
+ *
+ *  Network Block Device
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nbd.h"
+
+#include <errno.h>
+#include <string.h>
+#ifndef _WIN32
+#include <sys/ioctl.h>
+#endif
+#if defined(__sun__) || defined(__HAIKU__)
+#include <sys/ioccom.h>
+#endif
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "qemu_socket.h"
+
+//#define DEBUG_NBD
+
+#ifdef DEBUG_NBD
+#define TRACE(msg, ...) do { \
+    LOG(msg, ## __VA_ARGS__); \
+} while(0)
+#else
+#define TRACE(msg, ...) \
+    do { } while (0)
+#endif
+
+#define LOG(msg, ...) do { \
+    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
+            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+} while(0)
+
+/* This is all part of the "official" NBD API */
+
+#define NBD_REPLY_SIZE          (4 + 4 + 8)
+#define NBD_REQUEST_MAGIC       0x25609513
+#define NBD_REPLY_MAGIC         0x67446698
+
+#define NBD_SET_SOCK            _IO(0xab, 0)
+#define NBD_SET_BLKSIZE         _IO(0xab, 1)
+#define NBD_SET_SIZE            _IO(0xab, 2)
+#define NBD_DO_IT               _IO(0xab, 3)
+#define NBD_CLEAR_SOCK          _IO(0xab, 4)
+#define NBD_CLEAR_QUE           _IO(0xab, 5)
+#define NBD_PRINT_DEBUG         _IO(0xab, 6)
+#define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
+#define NBD_DISCONNECT          _IO(0xab, 8)
+
+#define NBD_OPT_EXPORT_NAME     (1 << 0)
+
+/* That's all folks */
+
+#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
+#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
+
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+{
+    size_t offset = 0;
+
+    while (offset < size) {
+        ssize_t len;
+
+        if (do_read) {
+            len = qemu_recv(fd, buffer + offset, size - offset, 0);
+        } else {
+            len = send(fd, buffer + offset, size - offset, 0);
+        }
+
+        if (len == -1)
+            errno = socket_error();
+
+        /* recoverable error */
+        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
+            continue;
+        }
+
+        /* eof */
+        if (len == 0) {
+            break;
+        }
+
+        /* unrecoverable error */
+        if (len == -1) {
+            return 0;
+        }
+
+        offset += len;
+    }
+
+    return offset;
+}
+
+static void combine_addr(char *buf, size_t len, const char* address,
+                         uint16_t port)
+{
+    /* If the address-part contains a colon, it's an IPv6 IP so needs [] */
+    if (strstr(address, ":")) {
+        snprintf(buf, len, "[%s]:%u", address, port);
+    } else {
+        snprintf(buf, len, "%s:%u", address, port);
+    }
+}
+
+int tcp_socket_outgoing(const char *address, uint16_t port)
+{
+    char address_and_port[128];
+    combine_addr(address_and_port, 128, address, port);
+    return tcp_socket_outgoing_spec(address_and_port);
+}
+
+int tcp_socket_outgoing_spec(const char *address_and_port)
+{
+    return inet_connect(address_and_port, SOCK_STREAM);
+}
+
+int tcp_socket_incoming(const char *address, uint16_t port)
+{
+    char address_and_port[128];
+    combine_addr(address_and_port, 128, address, port);
+    return tcp_socket_incoming_spec(address_and_port);
+}
+
+int tcp_socket_incoming_spec(const char *address_and_port)
+{
+    char *ostr  = NULL;
+    int olen = 0;
+    return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
+}
+
+int unix_socket_incoming(const char *path)
+{
+    char *ostr = NULL;
+    int olen = 0;
+
+    return unix_listen(path, ostr, olen);
+}
+
+int unix_socket_outgoing(const char *path)
+{
+    return unix_connect(path);
+}
+
+/* Basic flow
+
+   Server         Client
+
+   Negotiate
+                  Request
+   Response
+                  Request
+   Response
+                  ...
+   ...
+                  Request (type == 2)
+*/
+
+int nbd_negotiate(int csock, off_t size)
+{
+    char buf[8 + 8 + 8 + 128];
+
+    /* Negotiate
+        [ 0 ..   7]   passwd   ("NBDMAGIC")
+        [ 8 ..  15]   magic    (0x00420281861253)
+        [16 ..  23]   size
+        [24 .. 151]   reserved (0)
+     */
+
+    TRACE("Beginning negotiation.");
+    memcpy(buf, "NBDMAGIC", 8);
+    cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
+    cpu_to_be64w((uint64_t*)(buf + 16), size);
+    memset(buf + 24, 0, 128);
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("write failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Negotation succeeded.");
+
+    return 0;
+}
+
+int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+                          off_t *size, size_t *blocksize)
+{
+    char buf[256];
+    uint64_t magic, s;
+    uint16_t tmp;
+
+    TRACE("Receiving negotation.");
+
+    if (read_sync(csock, buf, 8) != 8) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    buf[8] = '\0';
+    if (strlen(buf) == 0) {
+        LOG("server connection closed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Magic is %c%c%c%c%c%c%c%c",
+          qemu_isprint(buf[0]) ? buf[0] : '.',
+          qemu_isprint(buf[1]) ? buf[1] : '.',
+          qemu_isprint(buf[2]) ? buf[2] : '.',
+          qemu_isprint(buf[3]) ? buf[3] : '.',
+          qemu_isprint(buf[4]) ? buf[4] : '.',
+          qemu_isprint(buf[5]) ? buf[5] : '.',
+          qemu_isprint(buf[6]) ? buf[6] : '.',
+          qemu_isprint(buf[7]) ? buf[7] : '.');
+
+    if (memcmp(buf, "NBDMAGIC", 8) != 0) {
+        LOG("Invalid magic received");
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+    magic = be64_to_cpu(magic);
+    TRACE("Magic is 0x%" PRIx64, magic);
+
+    if (name) {
+        uint32_t reserved = 0;
+        uint32_t opt;
+        uint32_t namesize;
+
+        TRACE("Checking magic (opts_magic)");
+        if (magic != 0x49484156454F5054LL) {
+            LOG("Bad magic received");
+            errno = EINVAL;
+            return -1;
+        }
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("flags read failed");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags = be16_to_cpu(tmp) << 16;
+        /* reserved for future use */
+        if (write_sync(csock, &reserved, sizeof(reserved)) !=
+            sizeof(reserved)) {
+            LOG("write failed (reserved)");
+            errno = EINVAL;
+            return -1;
+        }
+        /* write the export name */
+        magic = cpu_to_be64(magic);
+        if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+            LOG("write failed (magic)");
+            errno = EINVAL;
+            return -1;
+        }
+        opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
+        if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+            LOG("write failed (opt)");
+            errno = EINVAL;
+            return -1;
+        }
+        namesize = cpu_to_be32(strlen(name));
+        if (write_sync(csock, &namesize, sizeof(namesize)) !=
+            sizeof(namesize)) {
+            LOG("write failed (namesize)");
+            errno = EINVAL;
+            return -1;
+        }
+        if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+            LOG("write failed (name)");
+            errno = EINVAL;
+            return -1;
+        }
+    } else {
+        TRACE("Checking magic (cli_magic)");
+
+        if (magic != 0x00420281861253LL) {
+            LOG("Bad magic received");
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+    *size = be64_to_cpu(s);
+    *blocksize = 1024;
+    TRACE("Size is %" PRIu64, *size);
+
+    if (!name) {
+        if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+            LOG("read failed (flags)");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags = be32_to_cpup(flags);
+    } else {
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("read failed (tmp)");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags |= be32_to_cpu(tmp);
+    }
+    if (read_sync(csock, &buf, 124) != 124) {
+        LOG("read failed (buf)");
+        errno = EINVAL;
+        return -1;
+    }
+        return 0;
+}
+
+#ifndef _WIN32
+int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+{
+    TRACE("Setting block size to %lu", (unsigned long)blocksize);
+
+    if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+        int serrno = errno;
+        LOG("Failed setting NBD block size");
+        errno = serrno;
+        return -1;
+    }
+
+        TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
+
+    if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+        int serrno = errno;
+        LOG("Failed setting size (in blocks)");
+        errno = serrno;
+        return -1;
+    }
+
+    TRACE("Clearing NBD socket");
+
+    if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
+        int serrno = errno;
+        LOG("Failed clearing NBD socket");
+        errno = serrno;
+        return -1;
+    }
+
+    TRACE("Setting NBD socket");
+
+    if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+        int serrno = errno;
+        LOG("Failed to set NBD socket");
+        errno = serrno;
+        return -1;
+    }
+
+    TRACE("Negotiation ended");
+
+    return 0;
+}
+
+int nbd_disconnect(int fd)
+{
+    ioctl(fd, NBD_CLEAR_QUE);
+    ioctl(fd, NBD_DISCONNECT);
+    ioctl(fd, NBD_CLEAR_SOCK);
+    return 0;
+}
+
+int nbd_client(int fd)
+{
+    int ret;
+    int serrno;
+
+    TRACE("Doing NBD loop");
+
+    ret = ioctl(fd, NBD_DO_IT);
+    serrno = errno;
+
+    TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
+
+    TRACE("Clearing NBD queue");
+    ioctl(fd, NBD_CLEAR_QUE);
+
+    TRACE("Clearing NBD socket");
+    ioctl(fd, NBD_CLEAR_SOCK);
+
+    errno = serrno;
+    return ret;
+}
+#else
+int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int nbd_disconnect(int fd)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int nbd_client(int fd)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+#endif
+
+int nbd_send_request(int csock, struct nbd_request *request)
+{
+    uint8_t buf[4 + 4 + 8 + 8 + 4];
+
+    cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
+    cpu_to_be32w((uint32_t*)(buf + 4), request->type);
+    cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
+    cpu_to_be64w((uint64_t*)(buf + 16), request->from);
+    cpu_to_be32w((uint32_t*)(buf + 24), request->len);
+
+    TRACE("Sending request to client: "
+          "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
+          request->from, request->len, request->handle, request->type);
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("writing to socket failed");
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+static int nbd_receive_request(int csock, struct nbd_request *request)
+{
+    uint8_t buf[4 + 4 + 8 + 8 + 4];
+    uint32_t magic;
+
+    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Request
+       [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
+       [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
+       [ 8 .. 15]   handle
+       [16 .. 23]   from
+       [24 .. 27]   len
+     */
+
+    magic = be32_to_cpup((uint32_t*)buf);
+    request->type  = be32_to_cpup((uint32_t*)(buf + 4));
+    request->handle = be64_to_cpup((uint64_t*)(buf + 8));
+    request->from  = be64_to_cpup((uint64_t*)(buf + 16));
+    request->len   = be32_to_cpup((uint32_t*)(buf + 24));
+
+    TRACE("Got request: "
+          "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
+          magic, request->type, request->from, request->len);
+
+    if (magic != NBD_REQUEST_MAGIC) {
+        LOG("invalid magic (got 0x%x)", magic);
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+int nbd_receive_reply(int csock, struct nbd_reply *reply)
+{
+    uint8_t buf[NBD_REPLY_SIZE];
+    uint32_t magic;
+
+    memset(buf, 0xAA, sizeof(buf));
+
+    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Reply
+       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+       [ 4 ..  7]    error   (0 == no error)
+       [ 7 .. 15]    handle
+     */
+
+    magic = be32_to_cpup((uint32_t*)buf);
+    reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
+    reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
+
+    TRACE("Got reply: "
+          "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
+          magic, reply->error, reply->handle);
+
+    if (magic != NBD_REPLY_MAGIC) {
+        LOG("invalid magic (got 0x%x)", magic);
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+static int nbd_send_reply(int csock, struct nbd_reply *reply)
+{
+    uint8_t buf[4 + 4 + 8];
+
+    /* Reply
+       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+       [ 4 ..  7]    error   (0 == no error)
+       [ 7 .. 15]    handle
+     */
+    cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
+    cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
+    cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
+
+    TRACE("Sending response to client");
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("writing to socket failed");
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
+             off_t *offset, bool readonly, uint8_t *data, int data_size)
+{
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    TRACE("Reading request.");
+
+    if (nbd_receive_request(csock, &request) == -1)
+        return -1;
+
+    if (request.len + NBD_REPLY_SIZE > data_size) {
+        LOG("len (%u) is larger than max len (%u)",
+            request.len + NBD_REPLY_SIZE, data_size);
+        errno = EINVAL;
+        return -1;
+    }
+
+    if ((request.from + request.len) < request.from) {
+        LOG("integer overflow detected! "
+            "you're probably being attacked");
+        errno = EINVAL;
+        return -1;
+    }
+
+    if ((request.from + request.len) > size) {
+            LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
+            ", Offset: %" PRIu64 "\n",
+                    request.from, request.len, (uint64_t)size, dev_offset);
+        LOG("requested operation past EOF--bad client?");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Decoding type");
+
+    reply.handle = request.handle;
+    reply.error = 0;
+
+    switch (request.type) {
+    case NBD_CMD_READ:
+        TRACE("Request type is READ");
+
+        if (bdrv_read(bs, (request.from + dev_offset) / 512,
+                  data + NBD_REPLY_SIZE,
+                  request.len / 512) == -1) {
+            LOG("reading from file failed");
+            errno = EINVAL;
+            return -1;
+        }
+        *offset += request.len;
+
+        TRACE("Read %u byte(s)", request.len);
+
+        /* Reply
+           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+           [ 4 ..  7]    error   (0 == no error)
+           [ 7 .. 15]    handle
+         */
+
+        cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
+        cpu_to_be32w((uint32_t*)(data + 4), reply.error);
+        cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
+
+        TRACE("Sending data to client");
+
+        if (write_sync(csock, data,
+                   request.len + NBD_REPLY_SIZE) !=
+                   request.len + NBD_REPLY_SIZE) {
+            LOG("writing to socket failed");
+            errno = EINVAL;
+            return -1;
+        }
+        break;
+    case NBD_CMD_WRITE:
+        TRACE("Request type is WRITE");
+
+        TRACE("Reading %u byte(s)", request.len);
+
+        if (read_sync(csock, data, request.len) != request.len) {
+            LOG("reading from socket failed");
+            errno = EINVAL;
+            return -1;
+        }
+
+        if (readonly) {
+            TRACE("Server is read-only, return error");
+            reply.error = 1;
+        } else {
+            TRACE("Writing to device");
+
+            if (bdrv_write(bs, (request.from + dev_offset) / 512,
+                       data, request.len / 512) == -1) {
+                LOG("writing to file failed");
+                errno = EINVAL;
+                return -1;
+            }
+
+            *offset += request.len;
+        }
+
+        if (nbd_send_reply(csock, &reply) == -1)
+            return -1;
+        break;
+    case NBD_CMD_DISC:
+        TRACE("Request type is DISCONNECT");
+        errno = 0;
+        return 1;
+    default:
+        LOG("invalid request type (%u) received", request.type);
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Request/Reply complete");
+
+    return 0;
+}
diff --git a/qemu-0.15.x/nbd.h b/qemu-0.15.x/nbd.h
new file mode 100644
index 0000000..b38d0d0
--- /dev/null
+++ b/qemu-0.15.x/nbd.h
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (C) 2005  Anthony Liguori <anthony at codemonkey.ws>
+ *
+ *  Network Block Device
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NBD_H
+#define NBD_H
+
+#include <sys/types.h>
+
+#include <qemu-common.h>
+
+#include "block_int.h"
+
+struct nbd_request {
+    uint32_t magic;
+    uint32_t type;
+    uint64_t handle;
+    uint64_t from;
+    uint32_t len;
+} __attribute__ ((__packed__));
+
+struct nbd_reply {
+    uint32_t magic;
+    uint32_t error;
+    uint64_t handle;
+} __attribute__ ((__packed__));
+
+enum {
+    NBD_CMD_READ = 0,
+    NBD_CMD_WRITE = 1,
+    NBD_CMD_DISC = 2
+};
+
+#define NBD_DEFAULT_PORT	10809
+
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+int tcp_socket_outgoing(const char *address, uint16_t port);
+int tcp_socket_incoming(const char *address, uint16_t port);
+int tcp_socket_outgoing_spec(const char *address_and_port);
+int tcp_socket_incoming_spec(const char *address_and_port);
+int unix_socket_outgoing(const char *path);
+int unix_socket_incoming(const char *path);
+
+int nbd_negotiate(int csock, off_t size);
+int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+                          off_t *size, size_t *blocksize);
+int nbd_init(int fd, int csock, off_t size, size_t blocksize);
+int nbd_send_request(int csock, struct nbd_request *request);
+int nbd_receive_reply(int csock, struct nbd_reply *reply);
+int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
+             off_t *offset, bool readonly, uint8_t *data, int data_size);
+int nbd_client(int fd);
+int nbd_disconnect(int fd);
+
+#endif
diff --git a/qemu-0.15.x/net.c b/qemu-0.15.x/net.c
new file mode 100644
index 0000000..31c2338
--- /dev/null
+++ b/qemu-0.15.x/net.c
@@ -0,0 +1,1433 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net.h"
+
+#include "config-host.h"
+
+#include "net/tap.h"
+#include "net/socket.h"
+#include "net/dump.h"
+#include "net/slirp.h"
+#include "net/vde.h"
+#include "net/util.h"
+#include "monitor.h"
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "hw/qdev.h"
+#include "iov.h"
+
+static QTAILQ_HEAD(, VLANState) vlans;
+static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
+
+int default_net = 1;
+
+/***********************************************************/
+/* network device redirectors */
+
+#if defined(DEBUG_NET)
+static void hex_dump(FILE *f, const uint8_t *buf, int size)
+{
+    int len, i, j, c;
+
+    for(i=0;i<size;i+=16) {
+        len = size - i;
+        if (len > 16)
+            len = 16;
+        fprintf(f, "%08x ", i);
+        for(j=0;j<16;j++) {
+            if (j < len)
+                fprintf(f, " %02x", buf[i+j]);
+            else
+                fprintf(f, "   ");
+        }
+        fprintf(f, " ");
+        for(j=0;j<len;j++) {
+            c = buf[i+j];
+            if (c < ' ' || c > '~')
+                c = '.';
+            fprintf(f, "%c", c);
+        }
+        fprintf(f, "\n");
+    }
+}
+#endif
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+{
+    const char *p, *p1;
+    int len;
+    p = *pp;
+    p1 = strchr(p, sep);
+    if (!p1)
+        return -1;
+    len = p1 - p;
+    p1++;
+    if (buf_size > 0) {
+        if (len > buf_size - 1)
+            len = buf_size - 1;
+        memcpy(buf, p, len);
+        buf[len] = '\0';
+    }
+    *pp = p1;
+    return 0;
+}
+
+int parse_host_port(struct sockaddr_in *saddr, const char *str)
+{
+    char buf[512];
+    struct hostent *he;
+    const char *p, *r;
+    int port;
+
+    p = str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+        return -1;
+    saddr->sin_family = AF_INET;
+    if (buf[0] == '\0') {
+        saddr->sin_addr.s_addr = 0;
+    } else {
+        if (qemu_isdigit(buf[0])) {
+            if (!inet_aton(buf, &saddr->sin_addr))
+                return -1;
+        } else {
+            if ((he = gethostbyname(buf)) == NULL)
+                return - 1;
+            saddr->sin_addr = *(struct in_addr *)he->h_addr;
+        }
+    }
+    port = strtol(p, (char **)&r, 0);
+    if (r == p)
+        return -1;
+    saddr->sin_port = htons(port);
+    return 0;
+}
+
+void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6])
+{
+    snprintf(vc->info_str, sizeof(vc->info_str),
+             "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             vc->model,
+             macaddr[0], macaddr[1], macaddr[2],
+             macaddr[3], macaddr[4], macaddr[5]);
+}
+
+void qemu_macaddr_default_if_unset(MACAddr *macaddr)
+{
+    static int index = 0;
+    static const MACAddr zero = { .a = { 0,0,0,0,0,0 } };
+
+    if (memcmp(macaddr, &zero, sizeof(zero)) != 0)
+        return;
+    macaddr->a[0] = 0x52;
+    macaddr->a[1] = 0x54;
+    macaddr->a[2] = 0x00;
+    macaddr->a[3] = 0x12;
+    macaddr->a[4] = 0x34;
+    macaddr->a[5] = 0x56 + index++;
+}
+
+static char *assign_name(VLANClientState *vc1, const char *model)
+{
+    VLANState *vlan;
+    char buf[256];
+    int id = 0;
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        VLANClientState *vc;
+
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            if (vc != vc1 && strcmp(vc->model, model) == 0) {
+                id++;
+            }
+        }
+    }
+
+    snprintf(buf, sizeof(buf), "%s.%d", model, id);
+
+    return qemu_strdup(buf);
+}
+
+static ssize_t qemu_deliver_packet(VLANClientState *sender,
+                                   unsigned flags,
+                                   const uint8_t *data,
+                                   size_t size,
+                                   void *opaque);
+static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
+                                       unsigned flags,
+                                       const struct iovec *iov,
+                                       int iovcnt,
+                                       void *opaque);
+
+VLANClientState *qemu_new_net_client(NetClientInfo *info,
+                                     VLANState *vlan,
+                                     VLANClientState *peer,
+                                     const char *model,
+                                     const char *name)
+{
+    VLANClientState *vc;
+
+    assert(info->size >= sizeof(VLANClientState));
+
+    vc = qemu_mallocz(info->size);
+
+    vc->info = info;
+    vc->model = qemu_strdup(model);
+    if (name) {
+        vc->name = qemu_strdup(name);
+    } else {
+        vc->name = assign_name(vc, model);
+    }
+
+    if (vlan) {
+        assert(!peer);
+        vc->vlan = vlan;
+        QTAILQ_INSERT_TAIL(&vc->vlan->clients, vc, next);
+    } else {
+        if (peer) {
+            assert(!peer->peer);
+            vc->peer = peer;
+            peer->peer = vc;
+        }
+        QTAILQ_INSERT_TAIL(&non_vlan_clients, vc, next);
+
+        vc->send_queue = qemu_new_net_queue(qemu_deliver_packet,
+                                            qemu_deliver_packet_iov,
+                                            vc);
+    }
+
+    return vc;
+}
+
+NICState *qemu_new_nic(NetClientInfo *info,
+                       NICConf *conf,
+                       const char *model,
+                       const char *name,
+                       void *opaque)
+{
+    VLANClientState *nc;
+    NICState *nic;
+
+    assert(info->type == NET_CLIENT_TYPE_NIC);
+    assert(info->size >= sizeof(NICState));
+
+    nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name);
+
+    nic = DO_UPCAST(NICState, nc, nc);
+    nic->conf = conf;
+    nic->opaque = opaque;
+
+    return nic;
+}
+
+static void qemu_cleanup_vlan_client(VLANClientState *vc)
+{
+    if (vc->vlan) {
+        QTAILQ_REMOVE(&vc->vlan->clients, vc, next);
+    } else {
+        QTAILQ_REMOVE(&non_vlan_clients, vc, next);
+    }
+
+    if (vc->info->cleanup) {
+        vc->info->cleanup(vc);
+    }
+}
+
+static void qemu_free_vlan_client(VLANClientState *vc)
+{
+    if (!vc->vlan) {
+        if (vc->send_queue) {
+            qemu_del_net_queue(vc->send_queue);
+        }
+        if (vc->peer) {
+            vc->peer->peer = NULL;
+        }
+    }
+    qemu_free(vc->name);
+    qemu_free(vc->model);
+    qemu_free(vc);
+}
+
+void qemu_del_vlan_client(VLANClientState *vc)
+{
+    /* If there is a peer NIC, delete and cleanup client, but do not free. */
+    if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) {
+        NICState *nic = DO_UPCAST(NICState, nc, vc->peer);
+        if (nic->peer_deleted) {
+            return;
+        }
+        nic->peer_deleted = true;
+        /* Let NIC know peer is gone. */
+        vc->peer->link_down = true;
+        if (vc->peer->info->link_status_changed) {
+            vc->peer->info->link_status_changed(vc->peer);
+        }
+        qemu_cleanup_vlan_client(vc);
+        return;
+    }
+
+    /* If this is a peer NIC and peer has already been deleted, free it now. */
+    if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) {
+        NICState *nic = DO_UPCAST(NICState, nc, vc);
+        if (nic->peer_deleted) {
+            qemu_free_vlan_client(vc->peer);
+        }
+    }
+
+    qemu_cleanup_vlan_client(vc);
+    qemu_free_vlan_client(vc);
+}
+
+VLANClientState *
+qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
+                              const char *client_str)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+
+    vlan = qemu_find_vlan(vlan_id, 0);
+    if (!vlan) {
+        monitor_printf(mon, "unknown VLAN %d\n", vlan_id);
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(vc, &vlan->clients, next) {
+        if (!strcmp(vc->name, client_str)) {
+            break;
+        }
+    }
+    if (!vc) {
+        monitor_printf(mon, "can't find device %s on VLAN %d\n",
+                       client_str, vlan_id);
+    }
+
+    return vc;
+}
+
+void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
+{
+    VLANClientState *nc;
+    VLANState *vlan;
+
+    QTAILQ_FOREACH(nc, &non_vlan_clients, next) {
+        if (nc->info->type == NET_CLIENT_TYPE_NIC) {
+            func(DO_UPCAST(NICState, nc, nc), opaque);
+        }
+    }
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        QTAILQ_FOREACH(nc, &vlan->clients, next) {
+            if (nc->info->type == NET_CLIENT_TYPE_NIC) {
+                func(DO_UPCAST(NICState, nc, nc), opaque);
+            }
+        }
+    }
+}
+
+int qemu_can_send_packet(VLANClientState *sender)
+{
+    VLANState *vlan = sender->vlan;
+    VLANClientState *vc;
+
+    if (sender->peer) {
+        if (sender->peer->receive_disabled) {
+            return 0;
+        } else if (sender->peer->info->can_receive &&
+                   !sender->peer->info->can_receive(sender->peer)) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if (!sender->vlan) {
+        return 1;
+    }
+
+    QTAILQ_FOREACH(vc, &vlan->clients, next) {
+        if (vc == sender) {
+            continue;
+        }
+
+        /* no can_receive() handler, they can always receive */
+        if (vc->info->can_receive && !vc->info->can_receive(vc)) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static ssize_t qemu_deliver_packet(VLANClientState *sender,
+                                   unsigned flags,
+                                   const uint8_t *data,
+                                   size_t size,
+                                   void *opaque)
+{
+    VLANClientState *vc = opaque;
+    ssize_t ret;
+
+    if (vc->link_down) {
+        return size;
+    }
+
+    if (vc->receive_disabled) {
+        return 0;
+    }
+
+    if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) {
+        ret = vc->info->receive_raw(vc, data, size);
+    } else {
+        ret = vc->info->receive(vc, data, size);
+    }
+
+    if (ret == 0) {
+        vc->receive_disabled = 1;
+    };
+
+    return ret;
+}
+
+static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
+                                        unsigned flags,
+                                        const uint8_t *buf,
+                                        size_t size,
+                                        void *opaque)
+{
+    VLANState *vlan = opaque;
+    VLANClientState *vc;
+    ssize_t ret = -1;
+
+    QTAILQ_FOREACH(vc, &vlan->clients, next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = size;
+            continue;
+        }
+
+        if (vc->receive_disabled) {
+            ret = 0;
+            continue;
+        }
+
+        if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) {
+            len = vc->info->receive_raw(vc, buf, size);
+        } else {
+            len = vc->info->receive(vc, buf, size);
+        }
+
+        if (len == 0) {
+            vc->receive_disabled = 1;
+        }
+
+        ret = (ret >= 0) ? ret : len;
+
+    }
+
+    return ret;
+}
+
+void qemu_purge_queued_packets(VLANClientState *vc)
+{
+    NetQueue *queue;
+
+    if (!vc->peer && !vc->vlan) {
+        return;
+    }
+
+    if (vc->peer) {
+        queue = vc->peer->send_queue;
+    } else {
+        queue = vc->vlan->send_queue;
+    }
+
+    qemu_net_queue_purge(queue, vc);
+}
+
+void qemu_flush_queued_packets(VLANClientState *vc)
+{
+    NetQueue *queue;
+
+    vc->receive_disabled = 0;
+
+    if (vc->vlan) {
+        queue = vc->vlan->send_queue;
+    } else {
+        queue = vc->send_queue;
+    }
+
+    qemu_net_queue_flush(queue);
+}
+
+static ssize_t qemu_send_packet_async_with_flags(VLANClientState *sender,
+                                                 unsigned flags,
+                                                 const uint8_t *buf, int size,
+                                                 NetPacketSent *sent_cb)
+{
+    NetQueue *queue;
+
+#ifdef DEBUG_NET
+    printf("qemu_send_packet_async:\n");
+    hex_dump(stdout, buf, size);
+#endif
+
+    if (sender->link_down || (!sender->peer && !sender->vlan)) {
+        return size;
+    }
+
+    if (sender->peer) {
+        queue = sender->peer->send_queue;
+    } else {
+        queue = sender->vlan->send_queue;
+    }
+
+    return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
+}
+
+ssize_t qemu_send_packet_async(VLANClientState *sender,
+                               const uint8_t *buf, int size,
+                               NetPacketSent *sent_cb)
+{
+    return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE,
+                                             buf, size, sent_cb);
+}
+
+void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    qemu_send_packet_async(vc, buf, size, NULL);
+}
+
+ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    return qemu_send_packet_async_with_flags(vc, QEMU_NET_PACKET_FLAG_RAW,
+                                             buf, size, NULL);
+}
+
+static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    uint8_t buffer[4096];
+    size_t offset;
+
+    offset = iov_to_buf(iov, iovcnt, buffer, 0, sizeof(buffer));
+
+    return vc->info->receive(vc, buffer, offset);
+}
+
+static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
+                                       unsigned flags,
+                                       const struct iovec *iov,
+                                       int iovcnt,
+                                       void *opaque)
+{
+    VLANClientState *vc = opaque;
+
+    if (vc->link_down) {
+        return iov_size(iov, iovcnt);
+    }
+
+    if (vc->info->receive_iov) {
+        return vc->info->receive_iov(vc, iov, iovcnt);
+    } else {
+        return vc_sendv_compat(vc, iov, iovcnt);
+    }
+}
+
+static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState *sender,
+                                            unsigned flags,
+                                            const struct iovec *iov,
+                                            int iovcnt,
+                                            void *opaque)
+{
+    VLANState *vlan = opaque;
+    VLANClientState *vc;
+    ssize_t ret = -1;
+
+    QTAILQ_FOREACH(vc, &vlan->clients, next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = iov_size(iov, iovcnt);
+            continue;
+        }
+
+        assert(!(flags & QEMU_NET_PACKET_FLAG_RAW));
+
+        if (vc->info->receive_iov) {
+            len = vc->info->receive_iov(vc, iov, iovcnt);
+        } else {
+            len = vc_sendv_compat(vc, iov, iovcnt);
+        }
+
+        ret = (ret >= 0) ? ret : len;
+    }
+
+    return ret;
+}
+
+ssize_t qemu_sendv_packet_async(VLANClientState *sender,
+                                const struct iovec *iov, int iovcnt,
+                                NetPacketSent *sent_cb)
+{
+    NetQueue *queue;
+
+    if (sender->link_down || (!sender->peer && !sender->vlan)) {
+        return iov_size(iov, iovcnt);
+    }
+
+    if (sender->peer) {
+        queue = sender->peer->send_queue;
+    } else {
+        queue = sender->vlan->send_queue;
+    }
+
+    return qemu_net_queue_send_iov(queue, sender,
+                                   QEMU_NET_PACKET_FLAG_NONE,
+                                   iov, iovcnt, sent_cb);
+}
+
+ssize_t
+qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt)
+{
+    return qemu_sendv_packet_async(vc, iov, iovcnt, NULL);
+}
+
+/* find or alloc a new VLAN */
+VLANState *qemu_find_vlan(int id, int allocate)
+{
+    VLANState *vlan;
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        if (vlan->id == id) {
+            return vlan;
+        }
+    }
+
+    if (!allocate) {
+        return NULL;
+    }
+
+    vlan = qemu_mallocz(sizeof(VLANState));
+    vlan->id = id;
+    QTAILQ_INIT(&vlan->clients);
+
+    vlan->send_queue = qemu_new_net_queue(qemu_vlan_deliver_packet,
+                                          qemu_vlan_deliver_packet_iov,
+                                          vlan);
+
+    QTAILQ_INSERT_TAIL(&vlans, vlan, next);
+
+    return vlan;
+}
+
+VLANClientState *qemu_find_netdev(const char *id)
+{
+    VLANClientState *vc;
+
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!strcmp(vc->name, id)) {
+            return vc;
+        }
+    }
+
+    return NULL;
+}
+
+static int nic_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_NICS; index++)
+        if (!nd_table[index].used)
+            return index;
+    return -1;
+}
+
+int qemu_show_nic_models(const char *arg, const char *const *models)
+{
+    int i;
+
+    if (!arg || strcmp(arg, "?"))
+        return 0;
+
+    fprintf(stderr, "qemu: Supported NIC models: ");
+    for (i = 0 ; models[i]; i++)
+        fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
+    return 1;
+}
+
+void qemu_check_nic_model(NICInfo *nd, const char *model)
+{
+    const char *models[2];
+
+    models[0] = model;
+    models[1] = NULL;
+
+    if (qemu_show_nic_models(nd->model, models))
+        exit(0);
+    if (qemu_find_nic_model(nd, models, model) < 0)
+        exit(1);
+}
+
+int qemu_find_nic_model(NICInfo *nd, const char * const *models,
+                        const char *default_model)
+{
+    int i;
+
+    if (!nd->model)
+        nd->model = qemu_strdup(default_model);
+
+    for (i = 0 ; models[i]; i++) {
+        if (strcmp(nd->model, models[i]) == 0)
+            return i;
+    }
+
+    error_report("Unsupported NIC model: %s", nd->model);
+    return -1;
+}
+
+int net_handle_fd_param(Monitor *mon, const char *param)
+{
+    int fd;
+
+    if (!qemu_isdigit(param[0]) && mon) {
+
+        fd = monitor_get_fd(mon, param);
+        if (fd == -1) {
+            error_report("No file descriptor named %s found", param);
+            return -1;
+        }
+    } else {
+        char *endptr = NULL;
+
+        fd = strtol(param, &endptr, 10);
+        if (*endptr || (fd == 0 && param == endptr)) {
+            return -1;
+        }
+    }
+
+    return fd;
+}
+
+static int net_init_nic(QemuOpts *opts,
+                        Monitor *mon,
+                        const char *name,
+                        VLANState *vlan)
+{
+    int idx;
+    NICInfo *nd;
+    const char *netdev;
+
+    idx = nic_get_free_idx();
+    if (idx == -1 || nb_nics >= MAX_NICS) {
+        error_report("Too Many NICs");
+        return -1;
+    }
+
+    nd = &nd_table[idx];
+
+    memset(nd, 0, sizeof(*nd));
+
+    if ((netdev = qemu_opt_get(opts, "netdev"))) {
+        nd->netdev = qemu_find_netdev(netdev);
+        if (!nd->netdev) {
+            error_report("netdev '%s' not found", netdev);
+            return -1;
+        }
+    } else {
+        assert(vlan);
+        nd->vlan = vlan;
+    }
+    if (name) {
+        nd->name = qemu_strdup(name);
+    }
+    if (qemu_opt_get(opts, "model")) {
+        nd->model = qemu_strdup(qemu_opt_get(opts, "model"));
+    }
+    if (qemu_opt_get(opts, "addr")) {
+        nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
+    }
+
+    if (qemu_opt_get(opts, "macaddr") &&
+        net_parse_macaddr(nd->macaddr.a, qemu_opt_get(opts, "macaddr")) < 0) {
+        error_report("invalid syntax for ethernet address");
+        return -1;
+    }
+    qemu_macaddr_default_if_unset(&nd->macaddr);
+
+    nd->nvectors = qemu_opt_get_number(opts, "vectors",
+                                       DEV_NVECTORS_UNSPECIFIED);
+    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
+        (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) {
+        error_report("invalid # of vectors: %d", nd->nvectors);
+        return -1;
+    }
+
+    nd->used = 1;
+    nb_nics++;
+
+    return idx;
+}
+
+#define NET_COMMON_PARAMS_DESC                     \
+    {                                              \
+        .name = "type",                            \
+        .type = QEMU_OPT_STRING,                   \
+        .help = "net client type (nic, tap etc.)", \
+     }, {                                          \
+        .name = "vlan",                            \
+        .type = QEMU_OPT_NUMBER,                   \
+        .help = "vlan number",                     \
+     }, {                                          \
+        .name = "name",                            \
+        .type = QEMU_OPT_STRING,                   \
+        .help = "identifier for monitor commands", \
+     }
+
+typedef int (*net_client_init_func)(QemuOpts *opts,
+                                    Monitor *mon,
+                                    const char *name,
+                                    VLANState *vlan);
+
+/* magic number, but compiler will warn if too small */
+#define NET_MAX_DESC 20
+
+static const struct {
+    const char *type;
+    net_client_init_func init;
+    QemuOptDesc desc[NET_MAX_DESC];
+} net_client_types[NET_CLIENT_TYPE_MAX] = {
+    [NET_CLIENT_TYPE_NONE] = {
+        .type = "none",
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            { /* end of list */ }
+        },
+    },
+    [NET_CLIENT_TYPE_NIC] = {
+        .type = "nic",
+        .init = net_init_nic,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "netdev",
+                .type = QEMU_OPT_STRING,
+                .help = "id of -netdev to connect to",
+            },
+            {
+                .name = "macaddr",
+                .type = QEMU_OPT_STRING,
+                .help = "MAC address",
+            }, {
+                .name = "model",
+                .type = QEMU_OPT_STRING,
+                .help = "device model (e1000, rtl8139, virtio etc.)",
+            }, {
+                .name = "addr",
+                .type = QEMU_OPT_STRING,
+                .help = "PCI device address",
+            }, {
+                .name = "vectors",
+                .type = QEMU_OPT_NUMBER,
+                .help = "number of MSI-x vectors, 0 to disable MSI-X",
+            },
+            { /* end of list */ }
+        },
+    },
+#ifdef CONFIG_SLIRP
+    [NET_CLIENT_TYPE_USER] = {
+        .type = "user",
+        .init = net_init_slirp,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "hostname",
+                .type = QEMU_OPT_STRING,
+                .help = "client hostname reported by the builtin DHCP server",
+            }, {
+                .name = "restrict",
+                .type = QEMU_OPT_STRING,
+                .help = "isolate the guest from the host (y|yes|n|no)",
+            }, {
+                .name = "ip",
+                .type = QEMU_OPT_STRING,
+                .help = "legacy parameter, use net= instead",
+            }, {
+                .name = "net",
+                .type = QEMU_OPT_STRING,
+                .help = "IP address and optional netmask",
+            }, {
+                .name = "host",
+                .type = QEMU_OPT_STRING,
+                .help = "guest-visible address of the host",
+            }, {
+                .name = "tftp",
+                .type = QEMU_OPT_STRING,
+                .help = "root directory of the built-in TFTP server",
+            }, {
+                .name = "bootfile",
+                .type = QEMU_OPT_STRING,
+                .help = "BOOTP filename, for use with tftp=",
+            }, {
+                .name = "dhcpstart",
+                .type = QEMU_OPT_STRING,
+                .help = "the first of the 16 IPs the built-in DHCP server can assign",
+            }, {
+                .name = "dns",
+                .type = QEMU_OPT_STRING,
+                .help = "guest-visible address of the virtual nameserver",
+            }, {
+                .name = "smb",
+                .type = QEMU_OPT_STRING,
+                .help = "root directory of the built-in SMB server",
+            }, {
+                .name = "smbserver",
+                .type = QEMU_OPT_STRING,
+                .help = "IP address of the built-in SMB server",
+            }, {
+                .name = "hostfwd",
+                .type = QEMU_OPT_STRING,
+                .help = "guest port number to forward incoming TCP or UDP connections",
+            }, {
+                .name = "guestfwd",
+                .type = QEMU_OPT_STRING,
+                .help = "IP address and port to forward guest TCP connections",
+            },
+            { /* end of list */ }
+        },
+    },
+#endif
+    [NET_CLIENT_TYPE_TAP] = {
+        .type = "tap",
+        .init = net_init_tap,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "ifname",
+                .type = QEMU_OPT_STRING,
+                .help = "interface name",
+            },
+#ifndef _WIN32
+            {
+                .name = "fd",
+                .type = QEMU_OPT_STRING,
+                .help = "file descriptor of an already opened tap",
+            }, {
+                .name = "script",
+                .type = QEMU_OPT_STRING,
+                .help = "script to initialize the interface",
+            }, {
+                .name = "downscript",
+                .type = QEMU_OPT_STRING,
+                .help = "script to shut down the interface",
+            }, {
+                .name = "sndbuf",
+                .type = QEMU_OPT_SIZE,
+                .help = "send buffer limit"
+            }, {
+                .name = "vnet_hdr",
+                .type = QEMU_OPT_BOOL,
+                .help = "enable the IFF_VNET_HDR flag on the tap interface"
+            }, {
+                .name = "vhost",
+                .type = QEMU_OPT_BOOL,
+                .help = "enable vhost-net network accelerator",
+            }, {
+                .name = "vhostfd",
+                .type = QEMU_OPT_STRING,
+                .help = "file descriptor of an already opened vhost net device",
+            }, {
+                .name = "vhostforce",
+                .type = QEMU_OPT_BOOL,
+                .help = "force vhost on for non-MSIX virtio guests",
+        },
+#endif /* _WIN32 */
+            { /* end of list */ }
+        },
+    },
+    [NET_CLIENT_TYPE_SOCKET] = {
+        .type = "socket",
+        .init = net_init_socket,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "fd",
+                .type = QEMU_OPT_STRING,
+                .help = "file descriptor of an already opened socket",
+            }, {
+                .name = "listen",
+                .type = QEMU_OPT_STRING,
+                .help = "port number, and optional hostname, to listen on",
+            }, {
+                .name = "connect",
+                .type = QEMU_OPT_STRING,
+                .help = "port number, and optional hostname, to connect to",
+            }, {
+                .name = "mcast",
+                .type = QEMU_OPT_STRING,
+                .help = "UDP multicast address and port number",
+            }, {
+                .name = "localaddr",
+                .type = QEMU_OPT_STRING,
+                .help = "source address for multicast packets",
+            },
+            { /* end of list */ }
+        },
+    },
+#ifdef CONFIG_VDE
+    [NET_CLIENT_TYPE_VDE] = {
+        .type = "vde",
+        .init = net_init_vde,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "sock",
+                .type = QEMU_OPT_STRING,
+                .help = "socket path",
+            }, {
+                .name = "port",
+                .type = QEMU_OPT_NUMBER,
+                .help = "port number",
+            }, {
+                .name = "group",
+                .type = QEMU_OPT_STRING,
+                .help = "group owner of socket",
+            }, {
+                .name = "mode",
+                .type = QEMU_OPT_NUMBER,
+                .help = "permissions for socket",
+            },
+            { /* end of list */ }
+        },
+    },
+#endif
+    [NET_CLIENT_TYPE_DUMP] = {
+        .type = "dump",
+        .init = net_init_dump,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "len",
+                .type = QEMU_OPT_SIZE,
+                .help = "per-packet size limit (64k default)",
+            }, {
+                .name = "file",
+                .type = QEMU_OPT_STRING,
+                .help = "dump file path (default is qemu-vlan0.pcap)",
+            },
+            { /* end of list */ }
+        },
+    },
+};
+
+int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
+{
+    const char *name;
+    const char *type;
+    int i;
+
+    type = qemu_opt_get(opts, "type");
+    if (!type) {
+        qerror_report(QERR_MISSING_PARAMETER, "type");
+        return -1;
+    }
+
+    if (is_netdev) {
+        if (strcmp(type, "tap") != 0 &&
+#ifdef CONFIG_SLIRP
+            strcmp(type, "user") != 0 &&
+#endif
+#ifdef CONFIG_VDE
+            strcmp(type, "vde") != 0 &&
+#endif
+            strcmp(type, "socket") != 0) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                          "a netdev backend type");
+            return -1;
+        }
+
+        if (qemu_opt_get(opts, "vlan")) {
+            qerror_report(QERR_INVALID_PARAMETER, "vlan");
+            return -1;
+        }
+        if (qemu_opt_get(opts, "name")) {
+            qerror_report(QERR_INVALID_PARAMETER, "name");
+            return -1;
+        }
+        if (!qemu_opts_id(opts)) {
+            qerror_report(QERR_MISSING_PARAMETER, "id");
+            return -1;
+        }
+    }
+
+    name = qemu_opts_id(opts);
+    if (!name) {
+        name = qemu_opt_get(opts, "name");
+    }
+
+    for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) {
+        if (net_client_types[i].type != NULL &&
+            !strcmp(net_client_types[i].type, type)) {
+            VLANState *vlan = NULL;
+            int ret;
+
+            if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) {
+                return -1;
+            }
+
+            /* Do not add to a vlan if it's a -netdev or a nic with a
+             * netdev= parameter. */
+            if (!(is_netdev ||
+                  (strcmp(type, "nic") == 0 && qemu_opt_get(opts, "netdev")))) {
+                vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1);
+            }
+
+            ret = 0;
+            if (net_client_types[i].init) {
+                ret = net_client_types[i].init(opts, mon, name, vlan);
+                if (ret < 0) {
+                    /* TODO push error reporting into init() methods */
+                    qerror_report(QERR_DEVICE_INIT_FAILED, type);
+                    return -1;
+                }
+            }
+            return ret;
+        }
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                  "a network client type");
+    return -1;
+}
+
+static int net_host_check_device(const char *device)
+{
+    int i;
+    const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_SLIRP
+                                       ,"user"
+#endif
+#ifdef CONFIG_VDE
+                                       ,"vde"
+#endif
+    };
+    for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
+        if (!strncmp(valid_param_list[i], device,
+                     strlen(valid_param_list[i])))
+            return 1;
+    }
+
+    return 0;
+}
+
+void net_host_device_add(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *opts_str = qdict_get_try_str(qdict, "opts");
+    QemuOpts *opts;
+
+    if (!net_host_check_device(device)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+
+    opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
+    if (!opts) {
+        return;
+    }
+
+    qemu_opt_set(opts, "type", device);
+
+    if (net_client_init(mon, opts, 0) < 0) {
+        monitor_printf(mon, "adding host network device %s failed\n", device);
+    }
+}
+
+void net_host_device_remove(Monitor *mon, const QDict *qdict)
+{
+    VLANClientState *vc;
+    int vlan_id = qdict_get_int(qdict, "vlan_id");
+    const char *device = qdict_get_str(qdict, "device");
+
+    vc = qemu_find_vlan_client_by_name(mon, vlan_id, device);
+    if (!vc) {
+        return;
+    }
+    if (!net_host_check_device(vc->model)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+    qemu_del_vlan_client(vc);
+}
+
+int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    QemuOpts *opts;
+    int res;
+
+    opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict);
+    if (!opts) {
+        return -1;
+    }
+
+    res = net_client_init(mon, opts, 1);
+    if (res < 0) {
+        qemu_opts_del(opts);
+    }
+
+    return res;
+}
+
+int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    VLANClientState *vc;
+
+    vc = qemu_find_netdev(id);
+    if (!vc || vc->info->type == NET_CLIENT_TYPE_NIC) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        return -1;
+    }
+    qemu_del_vlan_client(vc);
+    qemu_opts_del(qemu_opts_find(qemu_find_opts("netdev"), id));
+    return 0;
+}
+
+static void print_net_client(Monitor *mon, VLANClientState *vc)
+{
+    monitor_printf(mon, "%s: type=%s,%s\n", vc->name,
+                   net_client_types[vc->info->type].type, vc->info_str);
+}
+
+void do_info_network(Monitor *mon)
+{
+    VLANState *vlan;
+    VLANClientState *vc, *peer;
+    net_client_type type;
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
+
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            monitor_printf(mon, "  ");
+            print_net_client(mon, vc);
+        }
+    }
+    monitor_printf(mon, "Devices not on any VLAN:\n");
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        peer = vc->peer;
+        type = vc->info->type;
+        if (!peer || type == NET_CLIENT_TYPE_NIC) {
+            monitor_printf(mon, "  ");
+            print_net_client(mon, vc);
+        } /* else it's a netdev connected to a NIC, printed with the NIC */
+        if (peer && type == NET_CLIENT_TYPE_NIC) {
+            monitor_printf(mon, "   \\ ");
+            print_net_client(mon, peer);
+        }
+    }
+}
+
+int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    VLANState *vlan;
+    VLANClientState *vc = NULL;
+    const char *name = qdict_get_str(qdict, "name");
+    int up = qdict_get_bool(qdict, "up");
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            if (strcmp(vc->name, name) == 0) {
+                goto done;
+            }
+        }
+    }
+    vc = qemu_find_netdev(name);
+done:
+
+    if (!vc) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, name);
+        return -1;
+    }
+
+    vc->link_down = !up;
+
+    if (vc->info->link_status_changed) {
+        vc->info->link_status_changed(vc);
+    }
+
+    /* Notify peer. Don't update peer link status: this makes it possible to
+     * disconnect from host network without notifying the guest.
+     * FIXME: is disconnected link status change operation useful?
+     *
+     * Current behaviour is compatible with qemu vlans where there could be
+     * multiple clients that can still communicate with each other in
+     * disconnected mode. For now maintain this compatibility. */
+    if (vc->peer && vc->peer->info->link_status_changed) {
+        vc->peer->info->link_status_changed(vc->peer);
+    }
+    return 0;
+}
+
+void net_cleanup(void)
+{
+    VLANState *vlan;
+    VLANClientState *vc, *next_vc;
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        QTAILQ_FOREACH_SAFE(vc, &vlan->clients, next, next_vc) {
+            qemu_del_vlan_client(vc);
+        }
+    }
+
+    QTAILQ_FOREACH_SAFE(vc, &non_vlan_clients, next, next_vc) {
+        qemu_del_vlan_client(vc);
+    }
+}
+
+void net_check_clients(void)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+    int i;
+
+    /* Don't warn about the default network setup that you get if
+     * no command line -net or -netdev options are specified. There
+     * are two cases that we would otherwise complain about:
+     * (1) board doesn't support a NIC but the implicit "-net nic"
+     * requested one
+     * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic"
+     * sets up a nic that isn't connected to anything.
+     */
+    if (default_net) {
+        return;
+    }
+
+    QTAILQ_FOREACH(vlan, &vlans, next) {
+        int has_nic = 0, has_host_dev = 0;
+
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            switch (vc->info->type) {
+            case NET_CLIENT_TYPE_NIC:
+                has_nic = 1;
+                break;
+            case NET_CLIENT_TYPE_USER:
+            case NET_CLIENT_TYPE_TAP:
+            case NET_CLIENT_TYPE_SOCKET:
+            case NET_CLIENT_TYPE_VDE:
+                has_host_dev = 1;
+                break;
+            default: ;
+            }
+        }
+        if (has_host_dev && !has_nic)
+            fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
+        if (has_nic && !has_host_dev)
+            fprintf(stderr,
+                    "Warning: vlan %d is not connected to host network\n",
+                    vlan->id);
+    }
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!vc->peer) {
+            fprintf(stderr, "Warning: %s %s has no peer\n",
+                    vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
+                    vc->name);
+        }
+    }
+
+    /* Check that all NICs requested via -net nic actually got created.
+     * NICs created via -device don't need to be checked here because
+     * they are always instantiated.
+     */
+    for (i = 0; i < MAX_NICS; i++) {
+        NICInfo *nd = &nd_table[i];
+        if (nd->used && !nd->instantiated) {
+            fprintf(stderr, "Warning: requested NIC (%s, model %s) "
+                    "was not created (not supported by this machine?)\n",
+                    nd->name ? nd->name : "anonymous",
+                    nd->model ? nd->model : "unspecified");
+        }
+    }
+}
+
+static int net_init_client(QemuOpts *opts, void *dummy)
+{
+    if (net_client_init(NULL, opts, 0) < 0)
+        return -1;
+    return 0;
+}
+
+static int net_init_netdev(QemuOpts *opts, void *dummy)
+{
+    return net_client_init(NULL, opts, 1);
+}
+
+int net_init_clients(void)
+{
+    QemuOptsList *net = qemu_find_opts("net");
+
+    if (default_net) {
+        /* if no clients, we use a default config */
+        qemu_opts_set(net, NULL, "type", "nic");
+#ifdef CONFIG_SLIRP
+        qemu_opts_set(net, NULL, "type", "user");
+#endif
+    }
+
+    QTAILQ_INIT(&vlans);
+    QTAILQ_INIT(&non_vlan_clients);
+
+    if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
+        return -1;
+
+    if (qemu_opts_foreach(net, net_init_client, NULL, 1) == -1) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int net_client_parse(QemuOptsList *opts_list, const char *optarg)
+{
+#if defined(CONFIG_SLIRP)
+    int ret;
+    if (net_slirp_parse_legacy(opts_list, optarg, &ret)) {
+        return ret;
+    }
+#endif
+
+    if (!qemu_opts_parse(opts_list, optarg, 1)) {
+        return -1;
+    }
+
+    default_net = 0;
+    return 0;
+}
diff --git a/qemu-0.15.x/net.h b/qemu-0.15.x/net.h
new file mode 100644
index 0000000..9f633f8
--- /dev/null
+++ b/qemu-0.15.x/net.h
@@ -0,0 +1,182 @@
+#ifndef QEMU_NET_H
+#define QEMU_NET_H
+
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qdict.h"
+#include "qemu-option.h"
+#include "net/queue.h"
+
+struct MACAddr {
+    uint8_t a[6];
+};
+
+/* qdev nic properties */
+
+typedef struct NICConf {
+    MACAddr macaddr;
+    VLANState *vlan;
+    VLANClientState *peer;
+    int32_t bootindex;
+} NICConf;
+
+#define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
+    DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
+    DEFINE_PROP_VLAN("vlan",     _state, _conf.vlan),                   \
+    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer),                   \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1)
+
+/* VLANs support */
+
+typedef enum {
+    NET_CLIENT_TYPE_NONE,
+    NET_CLIENT_TYPE_NIC,
+    NET_CLIENT_TYPE_USER,
+    NET_CLIENT_TYPE_TAP,
+    NET_CLIENT_TYPE_SOCKET,
+    NET_CLIENT_TYPE_VDE,
+    NET_CLIENT_TYPE_DUMP,
+
+    NET_CLIENT_TYPE_MAX
+} net_client_type;
+
+typedef void (NetPoll)(VLANClientState *, bool enable);
+typedef int (NetCanReceive)(VLANClientState *);
+typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
+typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
+typedef void (NetCleanup) (VLANClientState *);
+typedef void (LinkStatusChanged)(VLANClientState *);
+
+typedef struct NetClientInfo {
+    net_client_type type;
+    size_t size;
+    NetReceive *receive;
+    NetReceive *receive_raw;
+    NetReceiveIOV *receive_iov;
+    NetCanReceive *can_receive;
+    NetCleanup *cleanup;
+    LinkStatusChanged *link_status_changed;
+    NetPoll *poll;
+} NetClientInfo;
+
+struct VLANClientState {
+    NetClientInfo *info;
+    int link_down;
+    QTAILQ_ENTRY(VLANClientState) next;
+    struct VLANState *vlan;
+    VLANClientState *peer;
+    NetQueue *send_queue;
+    char *model;
+    char *name;
+    char info_str[256];
+    unsigned receive_disabled : 1;
+};
+
+typedef struct NICState {
+    VLANClientState nc;
+    NICConf *conf;
+    void *opaque;
+    bool peer_deleted;
+} NICState;
+
+struct VLANState {
+    int id;
+    QTAILQ_HEAD(, VLANClientState) clients;
+    QTAILQ_ENTRY(VLANState) next;
+    NetQueue *send_queue;
+};
+
+VLANState *qemu_find_vlan(int id, int allocate);
+VLANClientState *qemu_find_netdev(const char *id);
+VLANClientState *qemu_new_net_client(NetClientInfo *info,
+                                     VLANState *vlan,
+                                     VLANClientState *peer,
+                                     const char *model,
+                                     const char *name);
+NICState *qemu_new_nic(NetClientInfo *info,
+                       NICConf *conf,
+                       const char *model,
+                       const char *name,
+                       void *opaque);
+void qemu_del_vlan_client(VLANClientState *vc);
+VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
+                                               const char *client_str);
+typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
+void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
+int qemu_can_send_packet(VLANClientState *vc);
+ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
+                          int iovcnt);
+ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
+                                int iovcnt, NetPacketSent *sent_cb);
+void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
+                               int size, NetPacketSent *sent_cb);
+void qemu_purge_queued_packets(VLANClientState *vc);
+void qemu_flush_queued_packets(VLANClientState *vc);
+void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]);
+void qemu_macaddr_default_if_unset(MACAddr *macaddr);
+int qemu_show_nic_models(const char *arg, const char *const *models);
+void qemu_check_nic_model(NICInfo *nd, const char *model);
+int qemu_find_nic_model(NICInfo *nd, const char * const *models,
+                        const char *default_model);
+
+void do_info_network(Monitor *mon);
+int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+/* NIC info */
+
+#define MAX_NICS 8
+
+struct NICInfo {
+    MACAddr macaddr;
+    char *model;
+    char *name;
+    char *devaddr;
+    VLANState *vlan;
+    VLANClientState *netdev;
+    int used;         /* is this slot in nd_table[] being used? */
+    int instantiated; /* does this NICInfo correspond to an instantiated NIC? */
+    int nvectors;
+};
+
+extern int nb_nics;
+extern NICInfo nd_table[MAX_NICS];
+extern int default_net;
+
+/* BT HCI info */
+
+struct HCIInfo {
+    int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr);
+    void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void *opaque;
+    void (*evt_recv)(void *opaque, const uint8_t *data, int len);
+    void (*acl_recv)(void *opaque, const uint8_t *data, int len);
+};
+
+struct HCIInfo *qemu_next_hci(void);
+
+/* from net.c */
+extern const char *legacy_tftp_prefix;
+extern const char *legacy_bootp_filename;
+
+int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
+int net_client_parse(QemuOptsList *opts_list, const char *str);
+int net_init_clients(void);
+void net_check_clients(void);
+void net_cleanup(void);
+void net_host_device_add(Monitor *mon, const QDict *qdict);
+void net_host_device_remove(Monitor *mon, const QDict *qdict);
+int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+
+void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
+
+int net_handle_fd_param(Monitor *mon, const char *param);
+
+#endif
diff --git a/qemu-0.15.x/net/checksum.c b/qemu-0.15.x/net/checksum.c
new file mode 100644
index 0000000..4046932
--- /dev/null
+++ b/qemu-0.15.x/net/checksum.c
@@ -0,0 +1,85 @@
+/*
+ *  IP checksumming functions.
+ *  (c) 2008 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/checksum.h"
+
+#define PROTO_TCP  6
+#define PROTO_UDP 17
+
+uint32_t net_checksum_add(int len, uint8_t *buf)
+{
+    uint32_t sum = 0;
+    int i;
+
+    for (i = 0; i < len; i++) {
+	if (i & 1)
+	    sum += (uint32_t)buf[i];
+	else
+	    sum += (uint32_t)buf[i] << 8;
+    }
+    return sum;
+}
+
+uint16_t net_checksum_finish(uint32_t sum)
+{
+    while (sum>>16)
+	sum = (sum & 0xFFFF)+(sum >> 16);
+    return ~sum;
+}
+
+uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
+                             uint8_t *addrs, uint8_t *buf)
+{
+    uint32_t sum = 0;
+
+    sum += net_checksum_add(length, buf);         // payload
+    sum += net_checksum_add(8, addrs);            // src + dst address
+    sum += proto + length;                        // protocol & length
+    return net_checksum_finish(sum);
+}
+
+void net_checksum_calculate(uint8_t *data, int length)
+{
+    int hlen, plen, proto, csum_offset;
+    uint16_t csum;
+
+    if ((data[14] & 0xf0) != 0x40)
+	return; /* not IPv4 */
+    hlen  = (data[14] & 0x0f) * 4;
+    plen  = (data[16] << 8 | data[17]) - hlen;
+    proto = data[23];
+
+    switch (proto) {
+    case PROTO_TCP:
+	csum_offset = 16;
+	break;
+    case PROTO_UDP:
+	csum_offset = 6;
+	break;
+    default:
+	return;
+    }
+
+    if (plen < csum_offset+2)
+	return;
+
+    data[14+hlen+csum_offset]   = 0;
+    data[14+hlen+csum_offset+1] = 0;
+    csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
+    data[14+hlen+csum_offset]   = csum >> 8;
+    data[14+hlen+csum_offset+1] = csum & 0xff;
+}
diff --git a/qemu-0.15.x/net/checksum.h b/qemu-0.15.x/net/checksum.h
new file mode 100644
index 0000000..1f05298
--- /dev/null
+++ b/qemu-0.15.x/net/checksum.h
@@ -0,0 +1,29 @@
+/*
+ *  IP checksumming functions.
+ *  (c) 2008 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_NET_CHECKSUM_H
+#define QEMU_NET_CHECKSUM_H
+
+#include <stdint.h>
+
+uint32_t net_checksum_add(int len, uint8_t *buf);
+uint16_t net_checksum_finish(uint32_t sum);
+uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
+                             uint8_t *addrs, uint8_t *buf);
+void net_checksum_calculate(uint8_t *data, int length);
+
+#endif /* QEMU_NET_CHECKSUM_H */
diff --git a/qemu-0.15.x/net/dump.c b/qemu-0.15.x/net/dump.c
new file mode 100644
index 0000000..0d0cbb2
--- /dev/null
+++ b/qemu-0.15.x/net/dump.c
@@ -0,0 +1,159 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "dump.h"
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "qemu-log.h"
+#include "qemu-timer.h"
+
+typedef struct DumpState {
+    VLANClientState nc;
+    int fd;
+    int pcap_caplen;
+} DumpState;
+
+#define PCAP_MAGIC 0xa1b2c3d4
+
+struct pcap_file_hdr {
+    uint32_t magic;
+    uint16_t version_major;
+    uint16_t version_minor;
+    int32_t thiszone;
+    uint32_t sigfigs;
+    uint32_t snaplen;
+    uint32_t linktype;
+};
+
+struct pcap_sf_pkthdr {
+    struct {
+        int32_t tv_sec;
+        int32_t tv_usec;
+    } ts;
+    uint32_t caplen;
+    uint32_t len;
+};
+
+static ssize_t dump_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    DumpState *s = DO_UPCAST(DumpState, nc, nc);
+    struct pcap_sf_pkthdr hdr;
+    int64_t ts;
+    int caplen;
+
+    /* Early return in case of previous error. */
+    if (s->fd < 0) {
+        return size;
+    }
+
+    ts = muldiv64(qemu_get_clock_ns(vm_clock), 1000000, get_ticks_per_sec());
+    caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
+
+    hdr.ts.tv_sec = ts / 1000000;
+    hdr.ts.tv_usec = ts % 1000000;
+    hdr.caplen = caplen;
+    hdr.len = size;
+    if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+        write(s->fd, buf, caplen) != caplen) {
+        qemu_log("-net dump write error - stop dump\n");
+        close(s->fd);
+        s->fd = -1;
+    }
+
+    return size;
+}
+
+static void dump_cleanup(VLANClientState *nc)
+{
+    DumpState *s = DO_UPCAST(DumpState, nc, nc);
+
+    close(s->fd);
+}
+
+static NetClientInfo net_dump_info = {
+    .type = NET_CLIENT_TYPE_DUMP,
+    .size = sizeof(DumpState),
+    .receive = dump_receive,
+    .cleanup = dump_cleanup,
+};
+
+static int net_dump_init(VLANState *vlan, const char *device,
+                         const char *name, const char *filename, int len)
+{
+    struct pcap_file_hdr hdr;
+    VLANClientState *nc;
+    DumpState *s;
+    int fd;
+
+    fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644);
+    if (fd < 0) {
+        error_report("-net dump: can't open %s", filename);
+        return -1;
+    }
+
+    hdr.magic = PCAP_MAGIC;
+    hdr.version_major = 2;
+    hdr.version_minor = 4;
+    hdr.thiszone = 0;
+    hdr.sigfigs = 0;
+    hdr.snaplen = len;
+    hdr.linktype = 1;
+
+    if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
+        error_report("-net dump write error: %s", strerror(errno));
+        close(fd);
+        return -1;
+    }
+
+    nc = qemu_new_net_client(&net_dump_info, vlan, NULL, device, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str),
+             "dump to %s (len=%d)", filename, len);
+
+    s = DO_UPCAST(DumpState, nc, nc);
+
+    s->fd = fd;
+    s->pcap_caplen = len;
+
+    return 0;
+}
+
+int net_init_dump(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
+{
+    int len;
+    const char *file;
+    char def_file[128];
+
+    assert(vlan);
+
+    file = qemu_opt_get(opts, "file");
+    if (!file) {
+        snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", vlan->id);
+        file = def_file;
+    }
+
+    len = qemu_opt_get_size(opts, "len", 65536);
+
+    return net_dump_init(vlan, "dump", name, file, len);
+}
diff --git a/qemu-0.15.x/net/dump.h b/qemu-0.15.x/net/dump.h
new file mode 100644
index 0000000..fdc91ad
--- /dev/null
+++ b/qemu-0.15.x/net/dump.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 QEMU_NET_DUMP_H
+#define QEMU_NET_DUMP_H
+
+#include "net.h"
+#include "qemu-common.h"
+
+int net_init_dump(QemuOpts *opts, Monitor *mon,
+                  const char *name, VLANState *vlan);
+
+#endif /* QEMU_NET_DUMP_H */
diff --git a/qemu-0.15.x/net/queue.c b/qemu-0.15.x/net/queue.c
new file mode 100644
index 0000000..2ea6cd0
--- /dev/null
+++ b/qemu-0.15.x/net/queue.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * 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 "net/queue.h"
+#include "qemu-queue.h"
+
+/* The delivery handler may only return zero if it will call
+ * qemu_net_queue_flush() when it determines that it is once again able
+ * to deliver packets. It must also call qemu_net_queue_purge() in its
+ * cleanup path.
+ *
+ * If a sent callback is provided to send(), the caller must handle a
+ * zero return from the delivery handler by not sending any more packets
+ * until we have invoked the callback. Only in that case will we queue
+ * the packet.
+ *
+ * If a sent callback isn't provided, we just drop the packet to avoid
+ * unbounded queueing.
+ */
+
+struct NetPacket {
+    QTAILQ_ENTRY(NetPacket) entry;
+    VLANClientState *sender;
+    unsigned flags;
+    int size;
+    NetPacketSent *sent_cb;
+    uint8_t data[0];
+};
+
+struct NetQueue {
+    NetPacketDeliver *deliver;
+    NetPacketDeliverIOV *deliver_iov;
+    void *opaque;
+
+    QTAILQ_HEAD(packets, NetPacket) packets;
+
+    unsigned delivering : 1;
+};
+
+NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
+                             NetPacketDeliverIOV *deliver_iov,
+                             void *opaque)
+{
+    NetQueue *queue;
+
+    queue = qemu_mallocz(sizeof(NetQueue));
+
+    queue->deliver = deliver;
+    queue->deliver_iov = deliver_iov;
+    queue->opaque = opaque;
+
+    QTAILQ_INIT(&queue->packets);
+
+    queue->delivering = 0;
+
+    return queue;
+}
+
+void qemu_del_net_queue(NetQueue *queue)
+{
+    NetPacket *packet, *next;
+
+    QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
+        QTAILQ_REMOVE(&queue->packets, packet, entry);
+        qemu_free(packet);
+    }
+
+    qemu_free(queue);
+}
+
+static ssize_t qemu_net_queue_append(NetQueue *queue,
+                                     VLANClientState *sender,
+                                     unsigned flags,
+                                     const uint8_t *buf,
+                                     size_t size,
+                                     NetPacketSent *sent_cb)
+{
+    NetPacket *packet;
+
+    packet = qemu_malloc(sizeof(NetPacket) + size);
+    packet->sender = sender;
+    packet->flags = flags;
+    packet->size = size;
+    packet->sent_cb = sent_cb;
+    memcpy(packet->data, buf, size);
+
+    QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
+
+    return size;
+}
+
+static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
+                                         VLANClientState *sender,
+                                         unsigned flags,
+                                         const struct iovec *iov,
+                                         int iovcnt,
+                                         NetPacketSent *sent_cb)
+{
+    NetPacket *packet;
+    size_t max_len = 0;
+    int i;
+
+    for (i = 0; i < iovcnt; i++) {
+        max_len += iov[i].iov_len;
+    }
+
+    packet = qemu_malloc(sizeof(NetPacket) + max_len);
+    packet->sender = sender;
+    packet->sent_cb = sent_cb;
+    packet->flags = flags;
+    packet->size = 0;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len = iov[i].iov_len;
+
+        memcpy(packet->data + packet->size, iov[i].iov_base, len);
+        packet->size += len;
+    }
+
+    QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
+
+    return packet->size;
+}
+
+static ssize_t qemu_net_queue_deliver(NetQueue *queue,
+                                      VLANClientState *sender,
+                                      unsigned flags,
+                                      const uint8_t *data,
+                                      size_t size)
+{
+    ssize_t ret = -1;
+
+    queue->delivering = 1;
+    ret = queue->deliver(sender, flags, data, size, queue->opaque);
+    queue->delivering = 0;
+
+    return ret;
+}
+
+static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
+                                          VLANClientState *sender,
+                                          unsigned flags,
+                                          const struct iovec *iov,
+                                          int iovcnt)
+{
+    ssize_t ret = -1;
+
+    queue->delivering = 1;
+    ret = queue->deliver_iov(sender, flags, iov, iovcnt, queue->opaque);
+    queue->delivering = 0;
+
+    return ret;
+}
+
+ssize_t qemu_net_queue_send(NetQueue *queue,
+                            VLANClientState *sender,
+                            unsigned flags,
+                            const uint8_t *data,
+                            size_t size,
+                            NetPacketSent *sent_cb)
+{
+    ssize_t ret;
+
+    if (queue->delivering) {
+        return qemu_net_queue_append(queue, sender, flags, data, size, NULL);
+    }
+
+    ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
+    if (ret == 0) {
+        qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
+        return 0;
+    }
+
+    qemu_net_queue_flush(queue);
+
+    return ret;
+}
+
+ssize_t qemu_net_queue_send_iov(NetQueue *queue,
+                                VLANClientState *sender,
+                                unsigned flags,
+                                const struct iovec *iov,
+                                int iovcnt,
+                                NetPacketSent *sent_cb)
+{
+    ssize_t ret;
+
+    if (queue->delivering) {
+        return qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, NULL);
+    }
+
+    ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
+    if (ret == 0) {
+        qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
+        return 0;
+    }
+
+    qemu_net_queue_flush(queue);
+
+    return ret;
+}
+
+void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from)
+{
+    NetPacket *packet, *next;
+
+    QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
+        if (packet->sender == from) {
+            QTAILQ_REMOVE(&queue->packets, packet, entry);
+            qemu_free(packet);
+        }
+    }
+}
+
+void qemu_net_queue_flush(NetQueue *queue)
+{
+    while (!QTAILQ_EMPTY(&queue->packets)) {
+        NetPacket *packet;
+        int ret;
+
+        packet = QTAILQ_FIRST(&queue->packets);
+        QTAILQ_REMOVE(&queue->packets, packet, entry);
+
+        ret = qemu_net_queue_deliver(queue,
+                                     packet->sender,
+                                     packet->flags,
+                                     packet->data,
+                                     packet->size);
+        if (ret == 0) {
+            QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
+            break;
+        }
+
+        if (packet->sent_cb) {
+            packet->sent_cb(packet->sender, ret);
+        }
+
+        qemu_free(packet);
+    }
+}
diff --git a/qemu-0.15.x/net/queue.h b/qemu-0.15.x/net/queue.h
new file mode 100644
index 0000000..a31958e
--- /dev/null
+++ b/qemu-0.15.x/net/queue.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * 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 QEMU_NET_QUEUE_H
+#define QEMU_NET_QUEUE_H
+
+#include "qemu-common.h"
+
+typedef struct NetPacket NetPacket;
+typedef struct NetQueue NetQueue;
+
+typedef void (NetPacketSent) (VLANClientState *sender, ssize_t ret);
+
+typedef ssize_t (NetPacketDeliver) (VLANClientState *sender,
+                                    unsigned flags,
+                                    const uint8_t *buf,
+                                    size_t size,
+                                    void *opaque);
+
+typedef ssize_t (NetPacketDeliverIOV) (VLANClientState *sender,
+                                       unsigned flags,
+                                       const struct iovec *iov,
+                                       int iovcnt,
+                                       void *opaque);
+
+#define QEMU_NET_PACKET_FLAG_NONE  0
+#define QEMU_NET_PACKET_FLAG_RAW  (1<<0)
+
+NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
+                             NetPacketDeliverIOV *deliver_iov,
+                             void *opaque);
+void qemu_del_net_queue(NetQueue *queue);
+
+ssize_t qemu_net_queue_send(NetQueue *queue,
+                            VLANClientState *sender,
+                            unsigned flags,
+                            const uint8_t *data,
+                            size_t size,
+                            NetPacketSent *sent_cb);
+
+ssize_t qemu_net_queue_send_iov(NetQueue *queue,
+                                VLANClientState *sender,
+                                unsigned flags,
+                                const struct iovec *iov,
+                                int iovcnt,
+                                NetPacketSent *sent_cb);
+
+void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from);
+void qemu_net_queue_flush(NetQueue *queue);
+
+#endif /* QEMU_NET_QUEUE_H */
diff --git a/qemu-0.15.x/net/slirp.c b/qemu-0.15.x/net/slirp.c
new file mode 100644
index 0000000..8199d00
--- /dev/null
+++ b/qemu-0.15.x/net/slirp.c
@@ -0,0 +1,779 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/slirp.h"
+
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <sys/wait.h>
+#endif
+#include "net.h"
+#include "monitor.h"
+#include "qemu_socket.h"
+#include "slirp/libslirp.h"
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+{
+    const char *p, *p1;
+    int len;
+    p = *pp;
+    p1 = strchr(p, sep);
+    if (!p1)
+        return -1;
+    len = p1 - p;
+    p1++;
+    if (buf_size > 0) {
+        if (len > buf_size - 1)
+            len = buf_size - 1;
+        memcpy(buf, p, len);
+        buf[len] = '\0';
+    }
+    *pp = p1;
+    return 0;
+}
+
+/* slirp network adapter */
+
+#define SLIRP_CFG_HOSTFWD 1
+#define SLIRP_CFG_LEGACY  2
+
+struct slirp_config_str {
+    struct slirp_config_str *next;
+    int flags;
+    char str[1024];
+    int legacy_format;
+};
+
+typedef struct SlirpState {
+    VLANClientState nc;
+    QTAILQ_ENTRY(SlirpState) entry;
+    Slirp *slirp;
+#ifndef _WIN32
+    char smb_dir[128];
+#endif
+} SlirpState;
+
+static struct slirp_config_str *slirp_configs;
+const char *legacy_tftp_prefix;
+const char *legacy_bootp_filename;
+static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
+    QTAILQ_HEAD_INITIALIZER(slirp_stacks);
+
+static int slirp_hostfwd(SlirpState *s, const char *redir_str,
+                         int legacy_format);
+static int slirp_guestfwd(SlirpState *s, const char *config_str,
+                          int legacy_format);
+
+#ifndef _WIN32
+static const char *legacy_smb_export;
+
+static int slirp_smb(SlirpState *s, const char *exported_dir,
+                     struct in_addr vserver_addr);
+static void slirp_smb_cleanup(SlirpState *s);
+#else
+static inline void slirp_smb_cleanup(SlirpState *s) { }
+#endif
+
+int slirp_can_output(void *opaque)
+{
+    SlirpState *s = opaque;
+
+    return qemu_can_send_packet(&s->nc);
+}
+
+void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
+{
+    SlirpState *s = opaque;
+
+    qemu_send_packet(&s->nc, pkt, pkt_len);
+}
+
+static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
+
+    slirp_input(s->slirp, buf, size);
+
+    return size;
+}
+
+static void net_slirp_cleanup(VLANClientState *nc)
+{
+    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
+
+    slirp_cleanup(s->slirp);
+    slirp_smb_cleanup(s);
+    QTAILQ_REMOVE(&slirp_stacks, s, entry);
+}
+
+static NetClientInfo net_slirp_info = {
+    .type = NET_CLIENT_TYPE_USER,
+    .size = sizeof(SlirpState),
+    .receive = net_slirp_receive,
+    .cleanup = net_slirp_cleanup,
+};
+
+static int net_slirp_init(VLANState *vlan, const char *model,
+                          const char *name, int restricted,
+                          const char *vnetwork, const char *vhost,
+                          const char *vhostname, const char *tftp_export,
+                          const char *bootfile, const char *vdhcp_start,
+                          const char *vnameserver, const char *smb_export,
+                          const char *vsmbserver)
+{
+    /* default settings according to historic slirp */
+    struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
+    struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
+    struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
+    struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
+    struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
+#ifndef _WIN32
+    struct in_addr smbsrv = { .s_addr = 0 };
+#endif
+    VLANClientState *nc;
+    SlirpState *s;
+    char buf[20];
+    uint32_t addr;
+    int shift;
+    char *end;
+    struct slirp_config_str *config;
+
+    if (!tftp_export) {
+        tftp_export = legacy_tftp_prefix;
+    }
+    if (!bootfile) {
+        bootfile = legacy_bootp_filename;
+    }
+
+    if (vnetwork) {
+        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
+            if (!inet_aton(vnetwork, &net)) {
+                return -1;
+            }
+            addr = ntohl(net.s_addr);
+            if (!(addr & 0x80000000)) {
+                mask.s_addr = htonl(0xff000000); /* class A */
+            } else if ((addr & 0xfff00000) == 0xac100000) {
+                mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
+            } else if ((addr & 0xc0000000) == 0x80000000) {
+                mask.s_addr = htonl(0xffff0000); /* class B */
+            } else if ((addr & 0xffff0000) == 0xc0a80000) {
+                mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
+            } else if ((addr & 0xffff0000) == 0xc6120000) {
+                mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
+            } else if ((addr & 0xe0000000) == 0xe0000000) {
+                mask.s_addr = htonl(0xffffff00); /* class C */
+            } else {
+                mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
+            }
+        } else {
+            if (!inet_aton(buf, &net)) {
+                return -1;
+            }
+            shift = strtol(vnetwork, &end, 10);
+            if (*end != '\0') {
+                if (!inet_aton(vnetwork, &mask)) {
+                    return -1;
+                }
+            } else if (shift < 4 || shift > 32) {
+                return -1;
+            } else {
+                mask.s_addr = htonl(0xffffffff << (32 - shift));
+            }
+        }
+        net.s_addr &= mask.s_addr;
+        host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
+        dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
+        dns.s_addr  = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
+    }
+
+    if (vhost && !inet_aton(vhost, &host)) {
+        return -1;
+    }
+    if ((host.s_addr & mask.s_addr) != net.s_addr) {
+        return -1;
+    }
+
+    if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
+        return -1;
+    }
+    if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
+        dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
+        return -1;
+    }
+
+    if (vnameserver && !inet_aton(vnameserver, &dns)) {
+        return -1;
+    }
+    if ((dns.s_addr & mask.s_addr) != net.s_addr ||
+        dns.s_addr == host.s_addr) {
+        return -1;
+    }
+
+#ifndef _WIN32
+    if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
+        return -1;
+    }
+#endif
+
+    nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str),
+             "net=%s,restrict=%s", inet_ntoa(net),
+             restricted ? "on" : "off");
+
+    s = DO_UPCAST(SlirpState, nc, nc);
+
+    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
+                          tftp_export, bootfile, dhcp, dns, s);
+    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
+
+    for (config = slirp_configs; config; config = config->next) {
+        if (config->flags & SLIRP_CFG_HOSTFWD) {
+            if (slirp_hostfwd(s, config->str,
+                              config->flags & SLIRP_CFG_LEGACY) < 0)
+                goto error;
+        } else {
+            if (slirp_guestfwd(s, config->str,
+                               config->flags & SLIRP_CFG_LEGACY) < 0)
+                goto error;
+        }
+    }
+#ifndef _WIN32
+    if (!smb_export) {
+        smb_export = legacy_smb_export;
+    }
+    if (smb_export) {
+        if (slirp_smb(s, smb_export, smbsrv) < 0)
+            goto error;
+    }
+#endif
+
+    return 0;
+
+error:
+    qemu_del_vlan_client(nc);
+    return -1;
+}
+
+static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
+                                const char *stack)
+{
+
+    if (vlan) {
+        VLANClientState *nc;
+        nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack);
+        if (!nc) {
+            return NULL;
+        }
+        if (strcmp(nc->model, "user")) {
+            monitor_printf(mon, "invalid device specified\n");
+            return NULL;
+        }
+        return DO_UPCAST(SlirpState, nc, nc);
+    } else {
+        if (QTAILQ_EMPTY(&slirp_stacks)) {
+            monitor_printf(mon, "user mode network stack not in use\n");
+            return NULL;
+        }
+        return QTAILQ_FIRST(&slirp_stacks);
+    }
+}
+
+void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+    struct in_addr host_addr = { .s_addr = INADDR_ANY };
+    int host_port;
+    char buf[256] = "";
+    const char *src_str, *p;
+    SlirpState *s;
+    int is_udp = 0;
+    int err;
+    const char *arg1 = qdict_get_str(qdict, "arg1");
+    const char *arg2 = qdict_get_try_str(qdict, "arg2");
+    const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+    if (arg2) {
+        s = slirp_lookup(mon, arg1, arg2);
+        src_str = arg3;
+    } else {
+        s = slirp_lookup(mon, NULL, NULL);
+        src_str = arg1;
+    }
+    if (!s) {
+        return;
+    }
+
+    if (!src_str || !src_str[0])
+        goto fail_syntax;
+
+    p = src_str;
+    get_str_sep(buf, sizeof(buf), &p, ':');
+
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+        goto fail_syntax;
+    }
+
+    host_port = atoi(p);
+
+    err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
+                               host_addr, host_port);
+
+    monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
+                   err ? "removed" : "not found");
+    return;
+
+ fail_syntax:
+    monitor_printf(mon, "invalid format\n");
+}
+
+static int slirp_hostfwd(SlirpState *s, const char *redir_str,
+                         int legacy_format)
+{
+    struct in_addr host_addr = { .s_addr = INADDR_ANY };
+    struct in_addr guest_addr = { .s_addr = 0 };
+    int host_port, guest_port;
+    const char *p;
+    char buf[256];
+    int is_udp;
+    char *end;
+
+    p = redir_str;
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    if (!legacy_format) {
+        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+            goto fail_syntax;
+        }
+        if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+            goto fail_syntax;
+        }
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
+        goto fail_syntax;
+    }
+    host_port = strtol(buf, &end, 0);
+    if (*end != '\0' || host_port < 1 || host_port > 65535) {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
+        goto fail_syntax;
+    }
+
+    guest_port = strtol(p, &end, 0);
+    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
+        goto fail_syntax;
+    }
+
+    if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
+                          guest_port) < 0) {
+        error_report("could not set up host forwarding rule '%s'",
+                     redir_str);
+        return -1;
+    }
+    return 0;
+
+ fail_syntax:
+    error_report("invalid host forwarding rule '%s'", redir_str);
+    return -1;
+}
+
+void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
+{
+    const char *redir_str;
+    SlirpState *s;
+    const char *arg1 = qdict_get_str(qdict, "arg1");
+    const char *arg2 = qdict_get_try_str(qdict, "arg2");
+    const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+    if (arg2) {
+        s = slirp_lookup(mon, arg1, arg2);
+        redir_str = arg3;
+    } else {
+        s = slirp_lookup(mon, NULL, NULL);
+        redir_str = arg1;
+    }
+    if (s) {
+        slirp_hostfwd(s, redir_str, 0);
+    }
+
+}
+
+int net_slirp_redir(const char *redir_str)
+{
+    struct slirp_config_str *config;
+
+    if (QTAILQ_EMPTY(&slirp_stacks)) {
+        config = qemu_malloc(sizeof(*config));
+        pstrcpy(config->str, sizeof(config->str), redir_str);
+        config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
+        config->next = slirp_configs;
+        slirp_configs = config;
+        return 0;
+    }
+
+    return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
+}
+
+#ifndef _WIN32
+
+/* automatic user mode samba server configuration */
+static void slirp_smb_cleanup(SlirpState *s)
+{
+    char cmd[128];
+    int ret;
+
+    if (s->smb_dir[0] != '\0') {
+        snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
+        ret = system(cmd);
+        if (ret == -1 || !WIFEXITED(ret)) {
+            error_report("'%s' failed.", cmd);
+        } else if (WEXITSTATUS(ret)) {
+            error_report("'%s' failed. Error code: %d",
+                         cmd, WEXITSTATUS(ret));
+        }
+        s->smb_dir[0] = '\0';
+    }
+}
+
+static int slirp_smb(SlirpState* s, const char *exported_dir,
+                     struct in_addr vserver_addr)
+{
+    static int instance;
+    char smb_conf[128];
+    char smb_cmdline[128];
+    FILE *f;
+
+    snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
+             (long)getpid(), instance++);
+    if (mkdir(s->smb_dir, 0700) < 0) {
+        error_report("could not create samba server dir '%s'", s->smb_dir);
+        return -1;
+    }
+    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
+
+    f = fopen(smb_conf, "w");
+    if (!f) {
+        slirp_smb_cleanup(s);
+        error_report("could not create samba server configuration file '%s'",
+                     smb_conf);
+        return -1;
+    }
+    fprintf(f,
+            "[global]\n"
+            "private dir=%s\n"
+            "smb ports=0\n"
+            "socket address=127.0.0.1\n"
+            "pid directory=%s\n"
+            "lock directory=%s\n"
+            "log file=%s/log.smbd\n"
+            "smb passwd file=%s/smbpasswd\n"
+            "security = share\n"
+            "[qemu]\n"
+            "path=%s\n"
+            "read only=no\n"
+            "guest ok=yes\n",
+            s->smb_dir,
+            s->smb_dir,
+            s->smb_dir,
+            s->smb_dir,
+            s->smb_dir,
+            exported_dir
+            );
+    fclose(f);
+
+    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
+             CONFIG_SMBD_COMMAND, smb_conf);
+
+    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
+        slirp_smb_cleanup(s);
+        error_report("conflicting/invalid smbserver address");
+        return -1;
+    }
+    return 0;
+}
+
+/* automatic user mode samba server configuration (legacy interface) */
+int net_slirp_smb(const char *exported_dir)
+{
+    struct in_addr vserver_addr = { .s_addr = 0 };
+
+    if (legacy_smb_export) {
+        fprintf(stderr, "-smb given twice\n");
+        return -1;
+    }
+    legacy_smb_export = exported_dir;
+    if (!QTAILQ_EMPTY(&slirp_stacks)) {
+        return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
+                         vserver_addr);
+    }
+    return 0;
+}
+
+#endif /* !defined(_WIN32) */
+
+struct GuestFwd {
+    CharDriverState *hd;
+    struct in_addr server;
+    int port;
+    Slirp *slirp;
+};
+
+static int guestfwd_can_read(void *opaque)
+{
+    struct GuestFwd *fwd = opaque;
+    return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
+}
+
+static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
+{
+    struct GuestFwd *fwd = opaque;
+    slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
+}
+
+static int slirp_guestfwd(SlirpState *s, const char *config_str,
+                          int legacy_format)
+{
+    struct in_addr server = { .s_addr = 0 };
+    struct GuestFwd *fwd;
+    const char *p;
+    char buf[128];
+    char *end;
+    int port;
+
+    p = config_str;
+    if (legacy_format) {
+        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+            goto fail_syntax;
+        }
+    } else {
+        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+            goto fail_syntax;
+        }
+        if (strcmp(buf, "tcp") && buf[0] != '\0') {
+            goto fail_syntax;
+        }
+        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+            goto fail_syntax;
+        }
+        if (buf[0] != '\0' && !inet_aton(buf, &server)) {
+            goto fail_syntax;
+        }
+        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+            goto fail_syntax;
+        }
+    }
+    port = strtol(buf, &end, 10);
+    if (*end != '\0' || port < 1 || port > 65535) {
+        goto fail_syntax;
+    }
+
+    fwd = qemu_malloc(sizeof(struct GuestFwd));
+    snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
+    fwd->hd = qemu_chr_open(buf, p, NULL);
+    if (!fwd->hd) {
+        error_report("could not open guest forwarding device '%s'", buf);
+        qemu_free(fwd);
+        return -1;
+    }
+
+    if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
+        error_report("conflicting/invalid host:port in guest forwarding "
+                     "rule '%s'", config_str);
+        qemu_free(fwd);
+        return -1;
+    }
+    fwd->server = server;
+    fwd->port = port;
+    fwd->slirp = s->slirp;
+
+    qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
+                          NULL, fwd);
+    return 0;
+
+ fail_syntax:
+    error_report("invalid guest forwarding rule '%s'", config_str);
+    return -1;
+}
+
+void do_info_usernet(Monitor *mon)
+{
+    SlirpState *s;
+
+    QTAILQ_FOREACH(s, &slirp_stacks, entry) {
+        monitor_printf(mon, "VLAN %d (%s):\n",
+                       s->nc.vlan ? s->nc.vlan->id : -1,
+                       s->nc.name);
+        slirp_connection_info(s->slirp, mon);
+    }
+}
+
+static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
+{
+    struct slirp_config_str *config;
+
+    if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
+        return 0;
+    }
+
+    config = qemu_mallocz(sizeof(*config));
+
+    pstrcpy(config->str, sizeof(config->str), value);
+
+    if (!strcmp(name, "hostfwd")) {
+        config->flags = SLIRP_CFG_HOSTFWD;
+    }
+
+    config->next = slirp_configs;
+    slirp_configs = config;
+
+    return 0;
+}
+
+int net_init_slirp(QemuOpts *opts,
+                   Monitor *mon,
+                   const char *name,
+                   VLANState *vlan)
+{
+    struct slirp_config_str *config;
+    const char *vhost;
+    const char *vhostname;
+    const char *vdhcp_start;
+    const char *vnamesrv;
+    const char *tftp_export;
+    const char *bootfile;
+    const char *smb_export;
+    const char *vsmbsrv;
+    const char *restrict_opt;
+    char *vnet = NULL;
+    int restricted = 0;
+    int ret;
+
+    vhost       = qemu_opt_get(opts, "host");
+    vhostname   = qemu_opt_get(opts, "hostname");
+    vdhcp_start = qemu_opt_get(opts, "dhcpstart");
+    vnamesrv    = qemu_opt_get(opts, "dns");
+    tftp_export = qemu_opt_get(opts, "tftp");
+    bootfile    = qemu_opt_get(opts, "bootfile");
+    smb_export  = qemu_opt_get(opts, "smb");
+    vsmbsrv     = qemu_opt_get(opts, "smbserver");
+
+    restrict_opt = qemu_opt_get(opts, "restrict");
+    if (restrict_opt) {
+        if (!strcmp(restrict_opt, "on") ||
+            !strcmp(restrict_opt, "yes") || !strcmp(restrict_opt, "y")) {
+            restricted = 1;
+        } else if (strcmp(restrict_opt, "off") &&
+            strcmp(restrict_opt, "no") && strcmp(restrict_opt, "n")) {
+            error_report("invalid option: 'restrict=%s'", restrict_opt);
+            return -1;
+        }
+    }
+
+    if (qemu_opt_get(opts, "ip")) {
+        const char *ip = qemu_opt_get(opts, "ip");
+        int l = strlen(ip) + strlen("/24") + 1;
+
+        vnet = qemu_malloc(l);
+
+        /* emulate legacy ip= parameter */
+        pstrcpy(vnet, l, ip);
+        pstrcat(vnet, l, "/24");
+    }
+
+    if (qemu_opt_get(opts, "net")) {
+        if (vnet) {
+            qemu_free(vnet);
+        }
+        vnet = qemu_strdup(qemu_opt_get(opts, "net"));
+    }
+
+    qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
+
+    ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
+                         vhostname, tftp_export, bootfile, vdhcp_start,
+                         vnamesrv, smb_export, vsmbsrv);
+
+    while (slirp_configs) {
+        config = slirp_configs;
+        slirp_configs = config->next;
+        qemu_free(config);
+    }
+
+    qemu_free(vnet);
+
+    return ret;
+}
+
+int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
+{
+    if (strcmp(opts_list->name, "net") != 0 ||
+        strncmp(optarg, "channel,", strlen("channel,")) != 0) {
+        return 0;
+    }
+
+    /* handle legacy -net channel,port:chr */
+    optarg += strlen("channel,");
+
+    if (QTAILQ_EMPTY(&slirp_stacks)) {
+        struct slirp_config_str *config;
+
+        config = qemu_malloc(sizeof(*config));
+        pstrcpy(config->str, sizeof(config->str), optarg);
+        config->flags = SLIRP_CFG_LEGACY;
+        config->next = slirp_configs;
+        slirp_configs = config;
+        *ret = 0;
+    } else {
+        *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
+    }
+
+    return 1;
+}
+
diff --git a/qemu-0.15.x/net/slirp.h b/qemu-0.15.x/net/slirp.h
new file mode 100644
index 0000000..c17de8e
--- /dev/null
+++ b/qemu-0.15.x/net/slirp.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 QEMU_NET_SLIRP_H
+#define QEMU_NET_SLIRP_H
+
+#include "qemu-common.h"
+#include "qdict.h"
+#include "qemu-option.h"
+
+#ifdef CONFIG_SLIRP
+
+int net_init_slirp(QemuOpts *opts,
+                   Monitor *mon,
+                   const char *name,
+                   VLANState *vlan);
+
+void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict);
+void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict);
+
+int net_slirp_redir(const char *redir_str);
+
+int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret);
+
+int net_slirp_smb(const char *exported_dir);
+
+void do_info_usernet(Monitor *mon);
+
+#endif
+
+#endif /* QEMU_NET_SLIRP_H */
diff --git a/qemu-0.15.x/net/socket.c b/qemu-0.15.x/net/socket.c
new file mode 100644
index 0000000..5cd0b9a
--- /dev/null
+++ b/qemu-0.15.x/net/socket.c
@@ -0,0 +1,606 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/socket.h"
+
+#include "config-host.h"
+
+#include "net.h"
+#include "qemu-char.h"
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "qemu-option.h"
+#include "qemu_socket.h"
+
+typedef struct NetSocketState {
+    VLANClientState nc;
+    int fd;
+    int state; /* 0 = getting length, 1 = getting data */
+    unsigned int index;
+    unsigned int packet_len;
+    uint8_t buf[4096];
+    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+} NetSocketState;
+
+typedef struct NetSocketListenState {
+    VLANState *vlan;
+    char *model;
+    char *name;
+    int fd;
+} NetSocketListenState;
+
+/* XXX: we consider we can send the whole packet without blocking */
+static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
+    uint32_t len;
+    len = htonl(size);
+
+    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
+    return send_all(s->fd, buf, size);
+}
+
+static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
+
+    return sendto(s->fd, (const void *)buf, size, 0,
+                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+}
+
+static void net_socket_send(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size, err;
+    unsigned l;
+    uint8_t buf1[4096];
+    const uint8_t *buf;
+
+    size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
+    if (size < 0) {
+        err = socket_error();
+        if (err != EWOULDBLOCK)
+            goto eoc;
+    } else if (size == 0) {
+        /* end of connection */
+    eoc:
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        return;
+    }
+    buf = buf1;
+    while (size > 0) {
+        /* reassemble a packet from the network */
+        switch(s->state) {
+        case 0:
+            l = 4 - s->index;
+            if (l > size)
+                l = size;
+            memcpy(s->buf + s->index, buf, l);
+            buf += l;
+            size -= l;
+            s->index += l;
+            if (s->index == 4) {
+                /* got length */
+                s->packet_len = ntohl(*(uint32_t *)s->buf);
+                s->index = 0;
+                s->state = 1;
+            }
+            break;
+        case 1:
+            l = s->packet_len - s->index;
+            if (l > size)
+                l = size;
+            if (s->index + l <= sizeof(s->buf)) {
+                memcpy(s->buf + s->index, buf, l);
+            } else {
+                fprintf(stderr, "serious error: oversized packet received,"
+                    "connection terminated.\n");
+                s->state = 0;
+                goto eoc;
+            }
+
+            s->index += l;
+            buf += l;
+            size -= l;
+            if (s->index >= s->packet_len) {
+                qemu_send_packet(&s->nc, s->buf, s->packet_len);
+                s->index = 0;
+                s->state = 0;
+            }
+            break;
+        }
+    }
+}
+
+static void net_socket_send_dgram(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size;
+
+    size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
+    if (size < 0)
+        return;
+    if (size == 0) {
+        /* end of connection */
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        return;
+    }
+    qemu_send_packet(&s->nc, s->buf, size);
+}
+
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
+{
+    struct ip_mreq imr;
+    int fd;
+    int val, ret;
+#ifdef __OpenBSD__
+    unsigned char loop;
+#else
+    int loop;
+#endif
+
+    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
+	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+		inet_ntoa(mcastaddr->sin_addr),
+                (int)ntohl(mcastaddr->sin_addr.s_addr));
+	return -1;
+
+    }
+    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        return -1;
+    }
+
+    val = 1;
+    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+                   (const char *)&val, sizeof(val));
+    if (ret < 0) {
+	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+	goto fail;
+    }
+
+    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+    if (ret < 0) {
+        perror("bind");
+        goto fail;
+    }
+
+    /* Add host to multicast group */
+    imr.imr_multiaddr = mcastaddr->sin_addr;
+    if (localaddr) {
+        imr.imr_interface = *localaddr;
+    } else {
+        imr.imr_interface.s_addr = htonl(INADDR_ANY);
+    }
+
+    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                     (const char *)&imr, sizeof(struct ip_mreq));
+    if (ret < 0) {
+	perror("setsockopt(IP_ADD_MEMBERSHIP)");
+	goto fail;
+    }
+
+    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+    loop = 1;
+    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+                   (const char *)&loop, sizeof(loop));
+    if (ret < 0) {
+	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+	goto fail;
+    }
+
+    /* If a bind address is given, only send packets from that address */
+    if (localaddr != NULL) {
+        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+                         (const char *)localaddr, sizeof(*localaddr));
+        if (ret < 0) {
+            perror("setsockopt(IP_MULTICAST_IF)");
+            goto fail;
+        }
+    }
+
+    socket_set_nonblock(fd);
+    return fd;
+fail:
+    if (fd >= 0)
+        closesocket(fd);
+    return -1;
+}
+
+static void net_socket_cleanup(VLANClientState *nc)
+{
+    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
+    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+    close(s->fd);
+}
+
+static NetClientInfo net_dgram_socket_info = {
+    .type = NET_CLIENT_TYPE_SOCKET,
+    .size = sizeof(NetSocketState),
+    .receive = net_socket_receive_dgram,
+    .cleanup = net_socket_cleanup,
+};
+
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
+                                                const char *model,
+                                                const char *name,
+                                                int fd, int is_connected)
+{
+    struct sockaddr_in saddr;
+    int newfd;
+    socklen_t saddr_len;
+    VLANClientState *nc;
+    NetSocketState *s;
+
+    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
+     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+     * by ONLY ONE process: we must "clone" this dgram socket --jjo
+     */
+
+    if (is_connected) {
+	if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+	    /* must be bound */
+	    if (saddr.sin_addr.s_addr==0) {
+		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+			fd);
+		return NULL;
+	    }
+	    /* clone dgram socket */
+	    newfd = net_socket_mcast_create(&saddr, NULL);
+	    if (newfd < 0) {
+		/* error already reported by net_socket_mcast_create() */
+		close(fd);
+		return NULL;
+	    }
+	    /* clone newfd to fd, close newfd */
+	    dup2(newfd, fd);
+	    close(newfd);
+
+	} else {
+	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+		    fd, strerror(errno));
+	    return NULL;
+	}
+    }
+
+    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str),
+	    "socket: fd=%d (%s mcast=%s:%d)",
+	    fd, is_connected ? "cloned" : "",
+	    inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+
+    s = DO_UPCAST(NetSocketState, nc, nc);
+
+    s->fd = fd;
+
+    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+
+    /* mcast: save bound address as dst */
+    if (is_connected) s->dgram_dst=saddr;
+
+    return s;
+}
+
+static void net_socket_connect(void *opaque)
+{
+    NetSocketState *s = opaque;
+    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
+}
+
+static NetClientInfo net_socket_info = {
+    .type = NET_CLIENT_TYPE_SOCKET,
+    .size = sizeof(NetSocketState),
+    .receive = net_socket_receive,
+    .cleanup = net_socket_cleanup,
+};
+
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
+                                                 const char *model,
+                                                 const char *name,
+                                                 int fd, int is_connected)
+{
+    VLANClientState *nc;
+    NetSocketState *s;
+
+    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
+
+    s = DO_UPCAST(NetSocketState, nc, nc);
+
+    s->fd = fd;
+
+    if (is_connected) {
+        net_socket_connect(s);
+    } else {
+        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
+    }
+    return s;
+}
+
+static NetSocketState *net_socket_fd_init(VLANState *vlan,
+                                          const char *model, const char *name,
+                                          int fd, int is_connected)
+{
+    int so_type = -1, optlen=sizeof(so_type);
+
+    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
+        (socklen_t *)&optlen)< 0) {
+	fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
+	return NULL;
+    }
+    switch(so_type) {
+    case SOCK_DGRAM:
+        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
+    case SOCK_STREAM:
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    default:
+        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    }
+    return NULL;
+}
+
+static void net_socket_accept(void *opaque)
+{
+    NetSocketListenState *s = opaque;
+    NetSocketState *s1;
+    struct sockaddr_in saddr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+        len = sizeof(saddr);
+        fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
+        if (fd < 0 && errno != EINTR) {
+            return;
+        } else if (fd >= 0) {
+            break;
+        }
+    }
+    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
+    if (!s1) {
+        closesocket(fd);
+    } else {
+        snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
+                 "socket: connection from %s:%d",
+                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    }
+}
+
+static int net_socket_listen_init(VLANState *vlan,
+                                  const char *model,
+                                  const char *name,
+                                  const char *host_str)
+{
+    NetSocketListenState *s;
+    int fd, val, ret;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    s = qemu_mallocz(sizeof(NetSocketListenState));
+
+    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    /* allow fast reuse */
+    val = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+
+    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+    if (ret < 0) {
+        perror("bind");
+        return -1;
+    }
+    ret = listen(fd, 0);
+    if (ret < 0) {
+        perror("listen");
+        return -1;
+    }
+    s->vlan = vlan;
+    s->model = qemu_strdup(model);
+    s->name = name ? qemu_strdup(name) : NULL;
+    s->fd = fd;
+    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
+    return 0;
+}
+
+static int net_socket_connect_init(VLANState *vlan,
+                                   const char *model,
+                                   const char *name,
+                                   const char *host_str)
+{
+    NetSocketState *s;
+    int fd, connected, ret, err;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    connected = 0;
+    for(;;) {
+        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+        if (ret < 0) {
+            err = socket_error();
+            if (err == EINTR || err == EWOULDBLOCK) {
+            } else if (err == EINPROGRESS) {
+                break;
+#ifdef _WIN32
+            } else if (err == WSAEALREADY || err == WSAEINVAL) {
+                break;
+#endif
+            } else {
+                perror("connect");
+                closesocket(fd);
+                return -1;
+            }
+        } else {
+            connected = 1;
+            break;
+        }
+    }
+    s = net_socket_fd_init(vlan, model, name, fd, connected);
+    if (!s)
+        return -1;
+    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+             "socket: connect to %s:%d",
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+}
+
+static int net_socket_mcast_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 const char *host_str,
+                                 const char *localaddr_str)
+{
+    NetSocketState *s;
+    int fd;
+    struct sockaddr_in saddr;
+    struct in_addr localaddr, *param_localaddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    if (localaddr_str != NULL) {
+        if (inet_aton(localaddr_str, &localaddr) == 0)
+            return -1;
+        param_localaddr = &localaddr;
+    } else {
+        param_localaddr = NULL;
+    }
+
+    fd = net_socket_mcast_create(&saddr, param_localaddr);
+    if (fd < 0)
+	return -1;
+
+    s = net_socket_fd_init(vlan, model, name, fd, 0);
+    if (!s)
+        return -1;
+
+    s->dgram_dst = saddr;
+
+    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+             "socket: mcast=%s:%d",
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+
+}
+
+int net_init_socket(QemuOpts *opts,
+                    Monitor *mon,
+                    const char *name,
+                    VLANState *vlan)
+{
+    if (qemu_opt_get(opts, "fd")) {
+        int fd;
+
+        if (qemu_opt_get(opts, "listen") ||
+            qemu_opt_get(opts, "connect") ||
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=");
+            return -1;
+        }
+
+        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
+        if (fd == -1) {
+            return -1;
+        }
+
+        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
+            close(fd);
+            return -1;
+        }
+    } else if (qemu_opt_get(opts, "listen")) {
+        const char *listen;
+
+        if (qemu_opt_get(opts, "fd") ||
+            qemu_opt_get(opts, "connect") ||
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=");
+            return -1;
+        }
+
+        listen = qemu_opt_get(opts, "listen");
+
+        if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
+            return -1;
+        }
+    } else if (qemu_opt_get(opts, "connect")) {
+        const char *connect;
+
+        if (qemu_opt_get(opts, "fd") ||
+            qemu_opt_get(opts, "listen") ||
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=");
+            return -1;
+        }
+
+        connect = qemu_opt_get(opts, "connect");
+
+        if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
+            return -1;
+        }
+    } else if (qemu_opt_get(opts, "mcast")) {
+        const char *mcast, *localaddr;
+
+        if (qemu_opt_get(opts, "fd") ||
+            qemu_opt_get(opts, "connect") ||
+            qemu_opt_get(opts, "listen")) {
+            error_report("fd=, connect= and listen= is invalid with mcast=");
+            return -1;
+        }
+
+        mcast = qemu_opt_get(opts, "mcast");
+        localaddr = qemu_opt_get(opts, "localaddr");
+
+        if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
+            return -1;
+        }
+    } else {
+        error_report("-socket requires fd=, listen=, connect= or mcast=");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/net/socket.h b/qemu-0.15.x/net/socket.h
new file mode 100644
index 0000000..ea46f02
--- /dev/null
+++ b/qemu-0.15.x/net/socket.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 QEMU_NET_SOCKET_H
+#define QEMU_NET_SOCKET_H
+
+#include "net.h"
+#include "qemu-common.h"
+
+int net_init_socket(QemuOpts *opts, Monitor *mon,
+                    const char *name, VLANState *vlan);
+
+#endif /* QEMU_NET_SOCKET_H */
diff --git a/qemu-0.15.x/net/tap-aix.c b/qemu-0.15.x/net/tap-aix.c
new file mode 100644
index 0000000..e19aaba
--- /dev/null
+++ b/qemu-0.15.x/net/tap-aix.c
@@ -0,0 +1,61 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/tap.h"
+#include <stdio.h>
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
+{
+    fprintf(stderr, "no tap on AIX\n");
+    return -1;
+}
+
+int tap_set_sndbuf(int fd, QemuOpts *opts)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr(int fd)
+{
+    return 0;
+}
+
+int tap_probe_has_ufo(int fd)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    return 0;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+}
+
+void tap_fd_set_offload(int fd, int csum, int tso4,
+                        int tso6, int ecn, int ufo)
+{
+}
diff --git a/qemu-0.15.x/net/tap-bsd.c b/qemu-0.15.x/net/tap-bsd.c
new file mode 100644
index 0000000..2f3efde
--- /dev/null
+++ b/qemu-0.15.x/net/tap-bsd.c
@@ -0,0 +1,131 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/tap.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "qemu-error.h"
+
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
+{
+    int fd;
+    char *dev;
+    struct stat s;
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+    /* if no ifname is given, always start the search from tap0/tun0. */
+    int i;
+    char dname[100];
+
+    for (i = 0; i < 10; i++) {
+        if (*ifname) {
+            snprintf(dname, sizeof dname, "/dev/%s", ifname);
+        } else {
+#if defined(__OpenBSD__)
+            snprintf(dname, sizeof dname, "/dev/tun%d", i);
+#else
+            snprintf(dname, sizeof dname, "/dev/tap%d", i);
+#endif
+        }
+        TFR(fd = open(dname, O_RDWR));
+        if (fd >= 0) {
+            break;
+        }
+        else if (errno == ENXIO || errno == ENOENT) {
+            break;
+        }
+        if (*ifname) {
+            break;
+        }
+    }
+    if (fd < 0) {
+        error_report("warning: could not open %s (%s): no virtual network emulation",
+                   dname, strerror(errno));
+        return -1;
+    }
+#else
+    TFR(fd = open("/dev/tap", O_RDWR));
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        return -1;
+    }
+#endif
+
+    fstat(fd, &s);
+    dev = devname(s.st_rdev, S_IFCHR);
+    pstrcpy(ifname, ifname_size, dev);
+
+    if (*vnet_hdr) {
+        /* BSD doesn't have IFF_VNET_HDR */
+        *vnet_hdr = 0;
+
+        if (vnet_hdr_required && !*vnet_hdr) {
+            error_report("vnet_hdr=1 requested, but no kernel "
+                         "support for IFF_VNET_HDR available");
+            close(fd);
+            return -1;
+        }
+    }
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+
+int tap_set_sndbuf(int fd, QemuOpts *opts)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr(int fd)
+{
+    return 0;
+}
+
+int tap_probe_has_ufo(int fd)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    return 0;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+}
+
+void tap_fd_set_offload(int fd, int csum, int tso4,
+                        int tso6, int ecn, int ufo)
+{
+}
diff --git a/qemu-0.15.x/net/tap-haiku.c b/qemu-0.15.x/net/tap-haiku.c
new file mode 100644
index 0000000..91dda8e
--- /dev/null
+++ b/qemu-0.15.x/net/tap-haiku.c
@@ -0,0 +1,61 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/tap.h"
+#include <stdio.h>
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
+{
+    fprintf(stderr, "no tap on Haiku\n");
+    return -1;
+}
+
+int tap_set_sndbuf(int fd, QemuOpts *opts)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr(int fd)
+{
+    return 0;
+}
+
+int tap_probe_has_ufo(int fd)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    return 0;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+}
+
+void tap_fd_set_offload(int fd, int csum, int tso4,
+                        int tso6, int ecn, int ufo)
+{
+}
diff --git a/qemu-0.15.x/net/tap-linux.c b/qemu-0.15.x/net/tap-linux.c
new file mode 100644
index 0000000..ff8cad0
--- /dev/null
+++ b/qemu-0.15.x/net/tap-linux.c
@@ -0,0 +1,195 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * 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 "net/tap.h"
+#include "net/tap-linux.h"
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "sysemu.h"
+#include "qemu-common.h"
+#include "qemu-error.h"
+
+#define PATH_NET_TUN "/dev/net/tun"
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
+{
+    struct ifreq ifr;
+    int fd, ret;
+
+    TFR(fd = open(PATH_NET_TUN, O_RDWR));
+    if (fd < 0) {
+        error_report("could not open %s: %m", PATH_NET_TUN);
+        return -1;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+    if (*vnet_hdr) {
+        unsigned int features;
+
+        if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
+            features & IFF_VNET_HDR) {
+            *vnet_hdr = 1;
+            ifr.ifr_flags |= IFF_VNET_HDR;
+        } else {
+            *vnet_hdr = 0;
+        }
+
+        if (vnet_hdr_required && !*vnet_hdr) {
+            error_report("vnet_hdr=1 requested, but no kernel "
+                         "support for IFF_VNET_HDR available");
+            close(fd);
+            return -1;
+        }
+    }
+
+    if (ifname[0] != '\0')
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+    else
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+    if (ret != 0) {
+        error_report("could not configure %s (%s): %m", PATH_NET_TUN, ifr.ifr_name);
+        close(fd);
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+
+/* sndbuf implements a kind of flow control for tap.
+ * Unfortunately when it's enabled, and packets are sent
+ * to other guests on the same host, the receiver
+ * can lock up the transmitter indefinitely.
+ *
+ * To avoid packet loss, sndbuf should be set to a value lower than the tx
+ * queue capacity of any destination network interface.
+ * Ethernet NICs generally have txqueuelen=1000, so 1Mb is
+ * a good value, given a 1500 byte MTU.
+ */
+#define TAP_DEFAULT_SNDBUF 0
+
+int tap_set_sndbuf(int fd, QemuOpts *opts)
+{
+    int sndbuf;
+
+    sndbuf = qemu_opt_get_size(opts, "sndbuf", TAP_DEFAULT_SNDBUF);
+    if (!sndbuf) {
+        sndbuf = INT_MAX;
+    }
+
+    if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && qemu_opt_get(opts, "sndbuf")) {
+        error_report("TUNSETSNDBUF ioctl failed: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+int tap_probe_vnet_hdr(int fd)
+{
+    struct ifreq ifr;
+
+    if (ioctl(fd, TUNGETIFF, &ifr) != 0) {
+        error_report("TUNGETIFF ioctl() failed: %s", strerror(errno));
+        return 0;
+    }
+
+    return ifr.ifr_flags & IFF_VNET_HDR;
+}
+
+int tap_probe_has_ufo(int fd)
+{
+    unsigned offload;
+
+    offload = TUN_F_CSUM | TUN_F_UFO;
+
+    if (ioctl(fd, TUNSETOFFLOAD, offload) < 0)
+        return 0;
+
+    return 1;
+}
+
+/* Verify that we can assign given length */
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    int orig;
+    if (ioctl(fd, TUNGETVNETHDRSZ, &orig) == -1) {
+        return 0;
+    }
+    if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) {
+        return 0;
+    }
+    /* Restore original length: we can't handle failure. */
+    if (ioctl(fd, TUNSETVNETHDRSZ, &orig) == -1) {
+        fprintf(stderr, "TUNGETVNETHDRSZ ioctl() failed: %s. Exiting.\n",
+                strerror(errno));
+        assert(0);
+        return -errno;
+    }
+    return 1;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+    if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) {
+        fprintf(stderr, "TUNSETVNETHDRSZ ioctl() failed: %s. Exiting.\n",
+                strerror(errno));
+        assert(0);
+    }
+}
+
+void tap_fd_set_offload(int fd, int csum, int tso4,
+                        int tso6, int ecn, int ufo)
+{
+    unsigned int offload = 0;
+
+    /* Check if our kernel supports TUNSETOFFLOAD */
+    if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) {
+        return;
+    }
+
+    if (csum) {
+        offload |= TUN_F_CSUM;
+        if (tso4)
+            offload |= TUN_F_TSO4;
+        if (tso6)
+            offload |= TUN_F_TSO6;
+        if ((tso4 || tso6) && ecn)
+            offload |= TUN_F_TSO_ECN;
+        if (ufo)
+            offload |= TUN_F_UFO;
+    }
+
+    if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+        offload &= ~TUN_F_UFO;
+        if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+            fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
+                    strerror(errno));
+        }
+    }
+}
diff --git a/qemu-0.15.x/net/tap-linux.h b/qemu-0.15.x/net/tap-linux.h
new file mode 100644
index 0000000..659e981
--- /dev/null
+++ b/qemu-0.15.x/net/tap-linux.h
@@ -0,0 +1,63 @@
+/*
+ *  Universal TUN/TAP device driver.
+ *  Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk at yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef QEMU_TAP_H
+#define QEMU_TAP_H
+
+#include <stdint.h>
+#ifdef __linux__
+
+#include <linux/ioctl.h>
+
+/* Ioctl defines */
+#define TUNSETIFF     _IOW('T', 202, int)
+#define TUNGETFEATURES _IOR('T', 207, unsigned int)
+#define TUNSETOFFLOAD  _IOW('T', 208, unsigned int)
+#define TUNGETIFF      _IOR('T', 210, unsigned int)
+#define TUNSETSNDBUF   _IOW('T', 212, int)
+#define TUNGETVNETHDRSZ _IOR('T', 215, int)
+#define TUNSETVNETHDRSZ _IOW('T', 216, int)
+
+#endif
+
+/* TUNSETIFF ifr flags */
+#define IFF_TAP		0x0002
+#define IFF_NO_PI	0x1000
+#define IFF_VNET_HDR	0x4000
+
+/* Features for GSO (TUNSETOFFLOAD). */
+#define TUN_F_CSUM	0x01	/* You can hand me unchecksummed packets. */
+#define TUN_F_TSO4	0x02	/* I can handle TSO for IPv4 packets */
+#define TUN_F_TSO6	0x04	/* I can handle TSO for IPv6 packets */
+#define TUN_F_TSO_ECN	0x08	/* I can handle TSO with ECN bits. */
+#define TUN_F_UFO	0x10	/* I can handle UFO packets */
+
+struct virtio_net_hdr
+{
+    uint8_t flags;
+    uint8_t gso_type;
+    uint16_t hdr_len;
+    uint16_t gso_size;
+    uint16_t csum_start;
+    uint16_t csum_offset;
+};
+
+struct virtio_net_hdr_mrg_rxbuf
+{
+    struct virtio_net_hdr hdr;
+    uint16_t num_buffers;   /* Number of merged rx buffers */
+};
+
+#endif /* QEMU_TAP_H */
diff --git a/qemu-0.15.x/net/tap-solaris.c b/qemu-0.15.x/net/tap-solaris.c
new file mode 100644
index 0000000..c216d28
--- /dev/null
+++ b/qemu-0.15.x/net/tap-solaris.c
@@ -0,0 +1,227 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/tap.h"
+#include "sysemu.h"
+
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#include "qemu-error.h"
+
+ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    struct strbuf sbuf;
+    int f = 0;
+
+    sbuf.maxlen = maxlen;
+    sbuf.buf = (char *)buf;
+
+    return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
+}
+
+#define TUNNEWPPA       (('T'<<16) | 0x0001)
+/*
+ * Allocate TAP device, returns opened fd.
+ * Stores dev name in the first arg(must be large enough).
+ */
+static int tap_alloc(char *dev, size_t dev_size)
+{
+    int tap_fd, if_fd, ppa = -1;
+    static int ip_fd = 0;
+    char *ptr;
+
+    static int arp_fd = 0;
+    int ip_muxid, arp_muxid;
+    struct strioctl  strioc_if, strioc_ppa;
+    int link_type = I_PLINK;;
+    struct lifreq ifr;
+    char actual_name[32] = "";
+
+    memset(&ifr, 0x0, sizeof(ifr));
+
+    if( *dev ){
+       ptr = dev;
+       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
+       ppa = atoi(ptr);
+    }
+
+    /* Check if IP device was opened */
+    if( ip_fd )
+       close(ip_fd);
+
+    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+    if (ip_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+       return -1;
+    }
+
+    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+    if (tap_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap");
+       return -1;
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    strioc_ppa.ic_cmd = TUNNEWPPA;
+    strioc_ppa.ic_timout = 0;
+    strioc_ppa.ic_len = sizeof(ppa);
+    strioc_ppa.ic_dp = (char *)&ppa;
+    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+       syslog (LOG_ERR, "Can't assign new interface");
+
+    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+    if (if_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap (2)");
+       return -1;
+    }
+    if(ioctl(if_fd, I_PUSH, "ip") < 0){
+       syslog(LOG_ERR, "Can't push IP module");
+       return -1;
+    }
+
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+	syslog(LOG_ERR, "Can't get flags\n");
+
+    snprintf (actual_name, 32, "tap%d", ppa);
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+
+    ifr.lifr_ppa = ppa;
+    /* Assign ppa according to the unit number returned by tun device */
+
+    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+        syslog (LOG_ERR, "Can't set PPA %d", ppa);
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+        syslog (LOG_ERR, "Can't get flags\n");
+    /* Push arp module to if_fd */
+    if (ioctl (if_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (2)");
+
+    /* Push arp module to ip_fd */
+    if (ioctl (ip_fd, I_POP, NULL) < 0)
+        syslog (LOG_ERR, "I_POP failed\n");
+    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (3)\n");
+    /* Open arp_fd */
+    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+    if (arp_fd < 0)
+       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+
+    /* Set ifname to arp */
+    strioc_if.ic_cmd = SIOCSLIFNAME;
+    strioc_if.ic_timout = 0;
+    strioc_if.ic_len = sizeof(ifr);
+    strioc_if.ic_dp = (char *)𝔦
+    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+        syslog (LOG_ERR, "Can't set ifname to arp\n");
+    }
+
+    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+       syslog(LOG_ERR, "Can't link TAP device to IP");
+       return -1;
+    }
+
+    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+        syslog (LOG_ERR, "Can't link TAP device to ARP");
+
+    close (if_fd);
+
+    memset(&ifr, 0x0, sizeof(ifr));
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+    ifr.lifr_ip_muxid  = ip_muxid;
+    ifr.lifr_arp_muxid = arp_muxid;
+
+    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+    {
+      ioctl (ip_fd, I_PUNLINK , arp_muxid);
+      ioctl (ip_fd, I_PUNLINK, ip_muxid);
+      syslog (LOG_ERR, "Can't set multiplexor id");
+    }
+
+    snprintf(dev, dev_size, "tap%d", ppa);
+    return tap_fd;
+}
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
+{
+    char  dev[10]="";
+    int fd;
+    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
+       fprintf(stderr, "Cannot allocate TAP device\n");
+       return -1;
+    }
+    pstrcpy(ifname, ifname_size, dev);
+    if (*vnet_hdr) {
+        /* Solaris doesn't have IFF_VNET_HDR */
+        *vnet_hdr = 0;
+
+        if (vnet_hdr_required && !*vnet_hdr) {
+            error_report("vnet_hdr=1 requested, but no kernel "
+                         "support for IFF_VNET_HDR available");
+            close(fd);
+            return -1;
+        }
+    }
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+
+int tap_set_sndbuf(int fd, QemuOpts *opts)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr(int fd)
+{
+    return 0;
+}
+
+int tap_probe_has_ufo(int fd)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    return 0;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+}
+
+void tap_fd_set_offload(int fd, int csum, int tso4,
+                        int tso6, int ecn, int ufo)
+{
+}
diff --git a/qemu-0.15.x/net/tap-win32.c b/qemu-0.15.x/net/tap-win32.c
new file mode 100644
index 0000000..596132e
--- /dev/null
+++ b/qemu-0.15.x/net/tap-win32.c
@@ -0,0 +1,751 @@
+/*
+ *  TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ *               on Windows.  Originally derived from the CIPE-Win32
+ *               project by Damion K. Wilson, with extensive modifications by
+ *               James Yonan.
+ *
+ *  All source code which derives from the CIPE-Win32 project is
+ *  Copyright (C) Damion K. Wilson, 2003, and is released under the
+ *  GPL version 2 (see below).
+ *
+ *  All other source code is Copyright (C) James Yonan, 2003-2004,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/tap.h"
+
+#include "qemu-common.h"
+#include "net.h"
+#include "sysemu.h"
+#include "qemu-error.h"
+#include <stdio.h>
+#include <windows.h>
+#include <winioctl.h>
+
+//=============
+// TAP IOCTLs
+//=============
+
+#define TAP_CONTROL_CODE(request,method) \
+  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
+
+#define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
+#define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)
+
+//=================
+// Registry keys
+//=================
+
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+//======================
+// Filesystem prefixes
+//======================
+
+#define USERMODEDEVICEDIR "\\\\.\\Global\\"
+#define TAPSUFFIX         ".tap"
+
+
+//======================
+// Compile time configuration
+//======================
+
+//#define DEBUG_TAP_WIN32
+
+#define TUN_ASYNCHRONOUS_WRITES 1
+
+#define TUN_BUFFER_SIZE 1560
+#define TUN_MAX_BUFFER_COUNT 32
+
+/*
+ * The data member "buffer" must be the first element in the tun_buffer
+ * structure. See the function, tap_win32_free_buffer.
+ */
+typedef struct tun_buffer_s {
+    unsigned char buffer [TUN_BUFFER_SIZE];
+    unsigned long read_size;
+    struct tun_buffer_s* next;
+} tun_buffer_t;
+
+typedef struct tap_win32_overlapped {
+    HANDLE handle;
+    HANDLE read_event;
+    HANDLE write_event;
+    HANDLE output_queue_semaphore;
+    HANDLE free_list_semaphore;
+    HANDLE tap_semaphore;
+    CRITICAL_SECTION output_queue_cs;
+    CRITICAL_SECTION free_list_cs;
+    OVERLAPPED read_overlapped;
+    OVERLAPPED write_overlapped;
+    tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT];
+    tun_buffer_t* free_list;
+    tun_buffer_t* output_queue_front;
+    tun_buffer_t* output_queue_back;
+} tap_win32_overlapped_t;
+
+static tap_win32_overlapped_t tap_overlapped;
+
+static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
+{
+    tun_buffer_t* buffer = NULL;
+    WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
+    EnterCriticalSection(&overlapped->free_list_cs);
+    buffer = overlapped->free_list;
+//    assert(buffer != NULL);
+    overlapped->free_list = buffer->next;
+    LeaveCriticalSection(&overlapped->free_list_cs);
+    buffer->next = NULL;
+    return buffer;
+}
+
+static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
+{
+    EnterCriticalSection(&overlapped->free_list_cs);
+    buffer->next = overlapped->free_list;
+    overlapped->free_list = buffer;
+    LeaveCriticalSection(&overlapped->free_list_cs);
+    ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
+}
+
+static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
+{
+    tun_buffer_t* buffer = NULL;
+    DWORD result, timeout = block ? INFINITE : 0L;
+
+    // Non-blocking call
+    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
+
+    switch (result)
+    {
+        // The semaphore object was signaled.
+        case WAIT_OBJECT_0:
+            EnterCriticalSection(&overlapped->output_queue_cs);
+
+            buffer = overlapped->output_queue_front;
+            overlapped->output_queue_front = buffer->next;
+
+            if(overlapped->output_queue_front == NULL) {
+                overlapped->output_queue_back = NULL;
+            }
+
+            LeaveCriticalSection(&overlapped->output_queue_cs);
+            break;
+
+        // Semaphore was nonsignaled, so a time-out occurred.
+        case WAIT_TIMEOUT:
+            // Cannot open another window.
+            break;
+    }
+
+    return buffer;
+}
+
+static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
+{
+    return get_buffer_from_output_queue(overlapped, 0);
+}
+
+static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
+{
+    EnterCriticalSection(&overlapped->output_queue_cs);
+
+    if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) {
+        overlapped->output_queue_front = overlapped->output_queue_back = buffer;
+    } else {
+        buffer->next = NULL;
+        overlapped->output_queue_back->next = buffer;
+        overlapped->output_queue_back = buffer;
+    }
+
+    LeaveCriticalSection(&overlapped->output_queue_cs);
+
+    ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
+}
+
+
+static int is_tap_win32_dev(const char *guid)
+{
+    HKEY netcard_key;
+    LONG status;
+    DWORD len;
+    int i = 0;
+
+    status = RegOpenKeyEx(
+        HKEY_LOCAL_MACHINE,
+        ADAPTER_KEY,
+        0,
+        KEY_READ,
+        &netcard_key);
+
+    if (status != ERROR_SUCCESS) {
+        return FALSE;
+    }
+
+    for (;;) {
+        char enum_name[256];
+        char unit_string[256];
+        HKEY unit_key;
+        char component_id_string[] = "ComponentId";
+        char component_id[256];
+        char net_cfg_instance_id_string[] = "NetCfgInstanceId";
+        char net_cfg_instance_id[256];
+        DWORD data_type;
+
+        len = sizeof (enum_name);
+        status = RegEnumKeyEx(
+            netcard_key,
+            i,
+            enum_name,
+            &len,
+            NULL,
+            NULL,
+            NULL,
+            NULL);
+
+        if (status == ERROR_NO_MORE_ITEMS)
+            break;
+        else if (status != ERROR_SUCCESS) {
+            return FALSE;
+        }
+
+        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
+                  ADAPTER_KEY, enum_name);
+
+        status = RegOpenKeyEx(
+            HKEY_LOCAL_MACHINE,
+            unit_string,
+            0,
+            KEY_READ,
+            &unit_key);
+
+        if (status != ERROR_SUCCESS) {
+            return FALSE;
+        } else {
+            len = sizeof (component_id);
+            status = RegQueryValueEx(
+                unit_key,
+                component_id_string,
+                NULL,
+                &data_type,
+                (LPBYTE)component_id,
+                &len);
+
+            if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
+                len = sizeof (net_cfg_instance_id);
+                status = RegQueryValueEx(
+                    unit_key,
+                    net_cfg_instance_id_string,
+                    NULL,
+                    &data_type,
+                    (LPBYTE)net_cfg_instance_id,
+                    &len);
+
+                if (status == ERROR_SUCCESS && data_type == REG_SZ) {
+                    if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/
+                        !strcmp (net_cfg_instance_id, guid)) {
+                        RegCloseKey (unit_key);
+                        RegCloseKey (netcard_key);
+                        return TRUE;
+                    }
+                }
+            }
+            RegCloseKey (unit_key);
+        }
+        ++i;
+    }
+
+    RegCloseKey (netcard_key);
+    return FALSE;
+}
+
+static int get_device_guid(
+    char *name,
+    int name_size,
+    char *actual_name,
+    int actual_name_size)
+{
+    LONG status;
+    HKEY control_net_key;
+    DWORD len;
+    int i = 0;
+    int stop = 0;
+
+    status = RegOpenKeyEx(
+        HKEY_LOCAL_MACHINE,
+        NETWORK_CONNECTIONS_KEY,
+        0,
+        KEY_READ,
+        &control_net_key);
+
+    if (status != ERROR_SUCCESS) {
+        return -1;
+    }
+
+    while (!stop)
+    {
+        char enum_name[256];
+        char connection_string[256];
+        HKEY connection_key;
+        char name_data[256];
+        DWORD name_type;
+        const char name_string[] = "Name";
+
+        len = sizeof (enum_name);
+        status = RegEnumKeyEx(
+            control_net_key,
+            i,
+            enum_name,
+            &len,
+            NULL,
+            NULL,
+            NULL,
+            NULL);
+
+        if (status == ERROR_NO_MORE_ITEMS)
+            break;
+        else if (status != ERROR_SUCCESS) {
+            return -1;
+        }
+
+        snprintf(connection_string,
+             sizeof(connection_string),
+             "%s\\%s\\Connection",
+             NETWORK_CONNECTIONS_KEY, enum_name);
+
+        status = RegOpenKeyEx(
+            HKEY_LOCAL_MACHINE,
+            connection_string,
+            0,
+            KEY_READ,
+            &connection_key);
+
+        if (status == ERROR_SUCCESS) {
+            len = sizeof (name_data);
+            status = RegQueryValueEx(
+                connection_key,
+                name_string,
+                NULL,
+                &name_type,
+                (LPBYTE)name_data,
+                &len);
+
+            if (status != ERROR_SUCCESS || name_type != REG_SZ) {
+                    return -1;
+            }
+            else {
+                if (is_tap_win32_dev(enum_name)) {
+                    snprintf(name, name_size, "%s", enum_name);
+                    if (actual_name) {
+                        if (strcmp(actual_name, "") != 0) {
+                            if (strcmp(name_data, actual_name) != 0) {
+                                RegCloseKey (connection_key);
+                                ++i;
+                                continue;
+                            }
+                        }
+                        else {
+                            snprintf(actual_name, actual_name_size, "%s", name_data);
+                        }
+                    }
+                    stop = 1;
+                }
+            }
+
+            RegCloseKey (connection_key);
+        }
+        ++i;
+    }
+
+    RegCloseKey (control_net_key);
+
+    if (stop == 0)
+        return -1;
+
+    return 0;
+}
+
+static int tap_win32_set_status(HANDLE handle, int status)
+{
+    unsigned long len = 0;
+
+    return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
+                &status, sizeof (status),
+                &status, sizeof (status), &len, NULL);
+}
+
+static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
+{
+    overlapped->handle = handle;
+
+    overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    overlapped->read_overlapped.Offset = 0;
+    overlapped->read_overlapped.OffsetHigh = 0;
+    overlapped->read_overlapped.hEvent = overlapped->read_event;
+
+    overlapped->write_overlapped.Offset = 0;
+    overlapped->write_overlapped.OffsetHigh = 0;
+    overlapped->write_overlapped.hEvent = overlapped->write_event;
+
+    InitializeCriticalSection(&overlapped->output_queue_cs);
+    InitializeCriticalSection(&overlapped->free_list_cs);
+
+    overlapped->output_queue_semaphore = CreateSemaphore(
+        NULL,   // default security attributes
+        0,   // initial count
+        TUN_MAX_BUFFER_COUNT,   // maximum count
+        NULL);  // unnamed semaphore
+
+    if(!overlapped->output_queue_semaphore)  {
+        fprintf(stderr, "error creating output queue semaphore!\n");
+    }
+
+    overlapped->free_list_semaphore = CreateSemaphore(
+        NULL,   // default security attributes
+        TUN_MAX_BUFFER_COUNT,   // initial count
+        TUN_MAX_BUFFER_COUNT,   // maximum count
+        NULL);  // unnamed semaphore
+
+    if(!overlapped->free_list_semaphore)  {
+        fprintf(stderr, "error creating free list semaphore!\n");
+    }
+
+    overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
+
+    {
+        unsigned index;
+        for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) {
+            tun_buffer_t* element = &overlapped->buffers[index];
+            element->next = overlapped->free_list;
+            overlapped->free_list = element;
+        }
+    }
+    /* To count buffers, initially no-signal. */
+    overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
+    if(!overlapped->tap_semaphore)
+        fprintf(stderr, "error creating tap_semaphore.\n");
+}
+
+static int tap_win32_write(tap_win32_overlapped_t *overlapped,
+                           const void *buffer, unsigned long size)
+{
+    unsigned long write_size;
+    BOOL result;
+    DWORD error;
+
+    result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
+                                  &write_size, FALSE);
+
+    if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
+        WaitForSingleObject(overlapped->write_event, INFINITE);
+
+    result = WriteFile(overlapped->handle, buffer, size,
+                       &write_size, &overlapped->write_overlapped);
+
+    if (!result) {
+        switch (error = GetLastError())
+        {
+        case ERROR_IO_PENDING:
+#ifndef TUN_ASYNCHRONOUS_WRITES
+            WaitForSingleObject(overlapped->write_event, INFINITE);
+#endif
+            break;
+        default:
+            return -1;
+        }
+    }
+
+    return write_size;
+}
+
+static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
+{
+    tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
+    unsigned long read_size;
+    BOOL result;
+    DWORD dwError;
+    tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
+
+
+    for (;;) {
+        result = ReadFile(overlapped->handle,
+                          buffer->buffer,
+                          sizeof(buffer->buffer),
+                          &read_size,
+                          &overlapped->read_overlapped);
+        if (!result) {
+            dwError = GetLastError();
+            if (dwError == ERROR_IO_PENDING) {
+                WaitForSingleObject(overlapped->read_event, INFINITE);
+                result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
+                                              &read_size, FALSE);
+                if (!result) {
+#ifdef DEBUG_TAP_WIN32
+                    LPVOID lpBuffer;
+                    dwError = GetLastError();
+                    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                                   NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                                   (LPTSTR) & lpBuffer, 0, NULL );
+                    fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer);
+                    LocalFree( lpBuffer );
+#endif
+                }
+            } else {
+#ifdef DEBUG_TAP_WIN32
+                LPVOID lpBuffer;
+                FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                               NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                               (LPTSTR) & lpBuffer, 0, NULL );
+                fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer);
+                LocalFree( lpBuffer );
+#endif
+            }
+        }
+
+        if(read_size > 0) {
+            buffer->read_size = read_size;
+            put_buffer_on_output_queue(overlapped, buffer);
+            ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
+            buffer = get_buffer_from_free_list(overlapped);
+        }
+    }
+
+    return 0;
+}
+
+static int tap_win32_read(tap_win32_overlapped_t *overlapped,
+                          uint8_t **pbuf, int max_size)
+{
+    int size = 0;
+
+    tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
+
+    if(buffer != NULL) {
+        *pbuf = buffer->buffer;
+        size = (int)buffer->read_size;
+        if(size > max_size) {
+            size = max_size;
+        }
+    }
+
+    return size;
+}
+
+static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
+                                  uint8_t *pbuf)
+{
+    tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
+    put_buffer_on_free_list(overlapped, buffer);
+}
+
+static int tap_win32_open(tap_win32_overlapped_t **phandle,
+                          const char *prefered_name)
+{
+    char device_path[256];
+    char device_guid[0x100];
+    int rc;
+    HANDLE handle;
+    BOOL bret;
+    char name_buffer[0x100] = {0, };
+    struct {
+        unsigned long major;
+        unsigned long minor;
+        unsigned long debug;
+    } version;
+    DWORD version_len;
+    DWORD idThread;
+
+    if (prefered_name != NULL)
+        snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);
+
+    rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
+    if (rc)
+        return -1;
+
+    snprintf (device_path, sizeof(device_path), "%s%s%s",
+              USERMODEDEVICEDIR,
+              device_guid,
+              TAPSUFFIX);
+
+    handle = CreateFile (
+        device_path,
+        GENERIC_READ | GENERIC_WRITE,
+        0,
+        0,
+        OPEN_EXISTING,
+        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
+        0 );
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+
+    bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
+                           &version, sizeof (version),
+                           &version, sizeof (version), &version_len, NULL);
+
+    if (bret == FALSE) {
+        CloseHandle(handle);
+        return -1;
+    }
+
+    if (!tap_win32_set_status(handle, TRUE)) {
+        return -1;
+    }
+
+    tap_win32_overlapped_init(&tap_overlapped, handle);
+
+    *phandle = &tap_overlapped;
+
+    CreateThread(NULL, 0, tap_win32_thread_entry,
+                 (LPVOID)&tap_overlapped, 0, &idThread);
+    return 0;
+}
+
+/********************************************/
+
+ typedef struct TAPState {
+     VLANClientState nc;
+     tap_win32_overlapped_t *handle;
+ } TAPState;
+
+static void tap_cleanup(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
+
+    /* FIXME: need to kill thread and close file handle:
+       tap_win32_close(s);
+    */
+}
+
+static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    return tap_win32_write(s->handle, buf, size);
+}
+
+static void tap_win32_send(void *opaque)
+{
+    TAPState *s = opaque;
+    uint8_t *buf;
+    int max_size = 4096;
+    int size;
+
+    size = tap_win32_read(s->handle, &buf, max_size);
+    if (size > 0) {
+        qemu_send_packet(&s->nc, buf, size);
+        tap_win32_free_buffer(s->handle, buf);
+    }
+}
+
+static NetClientInfo net_tap_win32_info = {
+    .type = NET_CLIENT_TYPE_TAP,
+    .size = sizeof(TAPState),
+    .receive = tap_receive,
+    .cleanup = tap_cleanup,
+};
+
+static int tap_win32_init(VLANState *vlan, const char *model,
+                          const char *name, const char *ifname)
+{
+    VLANClientState *nc;
+    TAPState *s;
+    tap_win32_overlapped_t *handle;
+
+    if (tap_win32_open(&handle, ifname) < 0) {
+        printf("tap: Could not open '%s'\n", ifname);
+        return -1;
+    }
+
+    nc = qemu_new_net_client(&net_tap_win32_info, vlan, NULL, model, name);
+
+    s = DO_UPCAST(TAPState, nc, nc);
+
+    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+             "tap: ifname=%s", ifname);
+
+    s->handle = handle;
+
+    qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
+
+    return 0;
+}
+
+int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
+{
+    const char *ifname;
+
+    ifname = qemu_opt_get(opts, "ifname");
+
+    if (!ifname) {
+        error_report("tap: no interface name");
+        return -1;
+    }
+
+    if (tap_win32_init(vlan, "tap", name, ifname) == -1) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int tap_has_ufo(VLANClientState *vc)
+{
+    return 0;
+}
+
+int tap_has_vnet_hdr(VLANClientState *vc)
+{
+    return 0;
+}
+
+int tap_probe_vnet_hdr_len(int fd, int len)
+{
+    return 0;
+}
+
+void tap_fd_set_vnet_hdr_len(int fd, int len)
+{
+}
+
+void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
+{
+}
+
+void tap_set_offload(VLANClientState *vc, int csum, int tso4,
+                     int tso6, int ecn, int ufo)
+{
+}
+
+struct vhost_net *tap_get_vhost_net(VLANClientState *nc)
+{
+    return NULL;
+}
diff --git a/qemu-0.15.x/net/tap.c b/qemu-0.15.x/net/tap.c
new file mode 100644
index 0000000..1f26dc9
--- /dev/null
+++ b/qemu-0.15.x/net/tap.c
@@ -0,0 +1,524 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * 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 "net/tap.h"
+
+#include "config-host.h"
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "net.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "qemu-common.h"
+#include "qemu-error.h"
+
+#include "net/tap-linux.h"
+
+#include "hw/vhost_net.h"
+
+/* Maximum GSO packet size (64k) plus plenty of room for
+ * the ethernet and virtio_net headers
+ */
+#define TAP_BUFSIZE (4096 + 65536)
+
+typedef struct TAPState {
+    VLANClientState nc;
+    int fd;
+    char down_script[1024];
+    char down_script_arg[128];
+    uint8_t buf[TAP_BUFSIZE];
+    unsigned int read_poll : 1;
+    unsigned int write_poll : 1;
+    unsigned int using_vnet_hdr : 1;
+    unsigned int has_ufo: 1;
+    VHostNetState *vhost_net;
+    unsigned host_vnet_hdr_len;
+} TAPState;
+
+static int launch_script(const char *setup_script, const char *ifname, int fd);
+
+static int tap_can_send(void *opaque);
+static void tap_send(void *opaque);
+static void tap_writable(void *opaque);
+
+static void tap_update_fd_handler(TAPState *s)
+{
+    qemu_set_fd_handler2(s->fd,
+                         s->read_poll  ? tap_can_send : NULL,
+                         s->read_poll  ? tap_send     : NULL,
+                         s->write_poll ? tap_writable : NULL,
+                         s);
+}
+
+static void tap_read_poll(TAPState *s, int enable)
+{
+    s->read_poll = !!enable;
+    tap_update_fd_handler(s);
+}
+
+static void tap_write_poll(TAPState *s, int enable)
+{
+    s->write_poll = !!enable;
+    tap_update_fd_handler(s);
+}
+
+static void tap_writable(void *opaque)
+{
+    TAPState *s = opaque;
+
+    tap_write_poll(s, 0);
+
+    qemu_flush_queued_packets(&s->nc);
+}
+
+static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt)
+{
+    ssize_t len;
+
+    do {
+        len = writev(s->fd, iov, iovcnt);
+    } while (len == -1 && errno == EINTR);
+
+    if (len == -1 && errno == EAGAIN) {
+        tap_write_poll(s, 1);
+        return 0;
+    }
+
+    return len;
+}
+
+static ssize_t tap_receive_iov(VLANClientState *nc, const struct iovec *iov,
+                               int iovcnt)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    const struct iovec *iovp = iov;
+    struct iovec iov_copy[iovcnt + 1];
+    struct virtio_net_hdr_mrg_rxbuf hdr = { };
+
+    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
+        iov_copy[0].iov_base = &hdr;
+        iov_copy[0].iov_len =  s->host_vnet_hdr_len;
+        memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
+        iovp = iov_copy;
+        iovcnt++;
+    }
+
+    return tap_write_packet(s, iovp, iovcnt);
+}
+
+static ssize_t tap_receive_raw(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    struct iovec iov[2];
+    int iovcnt = 0;
+    struct virtio_net_hdr_mrg_rxbuf hdr = { };
+
+    if (s->host_vnet_hdr_len) {
+        iov[iovcnt].iov_base = &hdr;
+        iov[iovcnt].iov_len  = s->host_vnet_hdr_len;
+        iovcnt++;
+    }
+
+    iov[iovcnt].iov_base = (char *)buf;
+    iov[iovcnt].iov_len  = size;
+    iovcnt++;
+
+    return tap_write_packet(s, iov, iovcnt);
+}
+
+static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    struct iovec iov[1];
+
+    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
+        return tap_receive_raw(nc, buf, size);
+    }
+
+    iov[0].iov_base = (char *)buf;
+    iov[0].iov_len  = size;
+
+    return tap_write_packet(s, iov, 1);
+}
+
+static int tap_can_send(void *opaque)
+{
+    TAPState *s = opaque;
+
+    return qemu_can_send_packet(&s->nc);
+}
+
+#ifndef __sun__
+ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    return read(tapfd, buf, maxlen);
+}
+#endif
+
+static void tap_send_completed(VLANClientState *nc, ssize_t len)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    tap_read_poll(s, 1);
+}
+
+static void tap_send(void *opaque)
+{
+    TAPState *s = opaque;
+    int size;
+
+    do {
+        uint8_t *buf = s->buf;
+
+        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
+        if (size <= 0) {
+            break;
+        }
+
+        if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
+            buf  += s->host_vnet_hdr_len;
+            size -= s->host_vnet_hdr_len;
+        }
+
+        size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
+        if (size == 0) {
+            tap_read_poll(s, 0);
+        }
+    } while (size > 0 && qemu_can_send_packet(&s->nc));
+}
+
+int tap_has_ufo(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+
+    return s->has_ufo;
+}
+
+int tap_has_vnet_hdr(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+
+    return !!s->host_vnet_hdr_len;
+}
+
+int tap_has_vnet_hdr_len(VLANClientState *nc, int len)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+
+    return tap_probe_vnet_hdr_len(s->fd, len);
+}
+
+void tap_set_vnet_hdr_len(VLANClientState *nc, int len)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+    assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
+           len == sizeof(struct virtio_net_hdr));
+
+    tap_fd_set_vnet_hdr_len(s->fd, len);
+    s->host_vnet_hdr_len = len;
+}
+
+void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    using_vnet_hdr = using_vnet_hdr != 0;
+
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+    assert(!!s->host_vnet_hdr_len == using_vnet_hdr);
+
+    s->using_vnet_hdr = using_vnet_hdr;
+}
+
+void tap_set_offload(VLANClientState *nc, int csum, int tso4,
+                     int tso6, int ecn, int ufo)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    if (s->fd < 0) {
+        return;
+    }
+
+    tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
+}
+
+static void tap_cleanup(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+    if (s->vhost_net) {
+        vhost_net_cleanup(s->vhost_net);
+        s->vhost_net = NULL;
+    }
+
+    qemu_purge_queued_packets(nc);
+
+    if (s->down_script[0])
+        launch_script(s->down_script, s->down_script_arg, s->fd);
+
+    tap_read_poll(s, 0);
+    tap_write_poll(s, 0);
+    close(s->fd);
+    s->fd = -1;
+}
+
+static void tap_poll(VLANClientState *nc, bool enable)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    tap_read_poll(s, enable);
+    tap_write_poll(s, enable);
+}
+
+int tap_get_fd(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+    return s->fd;
+}
+
+/* fd support */
+
+static NetClientInfo net_tap_info = {
+    .type = NET_CLIENT_TYPE_TAP,
+    .size = sizeof(TAPState),
+    .receive = tap_receive,
+    .receive_raw = tap_receive_raw,
+    .receive_iov = tap_receive_iov,
+    .poll = tap_poll,
+    .cleanup = tap_cleanup,
+};
+
+static TAPState *net_tap_fd_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 int fd,
+                                 int vnet_hdr)
+{
+    VLANClientState *nc;
+    TAPState *s;
+
+    nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name);
+
+    s = DO_UPCAST(TAPState, nc, nc);
+
+    s->fd = fd;
+    s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
+    s->using_vnet_hdr = 0;
+    s->has_ufo = tap_probe_has_ufo(s->fd);
+    tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
+    tap_read_poll(s, 1);
+    s->vhost_net = NULL;
+    return s;
+}
+
+static int launch_script(const char *setup_script, const char *ifname, int fd)
+{
+    sigset_t oldmask, mask;
+    int pid, status;
+    char *args[3];
+    char **parg;
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
+    sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+    /* try to launch network script */
+    pid = fork();
+    if (pid == 0) {
+        int open_max = sysconf(_SC_OPEN_MAX), i;
+
+        for (i = 0; i < open_max; i++) {
+            if (i != STDIN_FILENO &&
+                i != STDOUT_FILENO &&
+                i != STDERR_FILENO &&
+                i != fd) {
+                close(i);
+            }
+        }
+        parg = args;
+        *parg++ = (char *)setup_script;
+        *parg++ = (char *)ifname;
+        *parg = NULL;
+        execv(setup_script, args);
+        _exit(1);
+    } else if (pid > 0) {
+        while (waitpid(pid, &status, 0) != pid) {
+            /* loop */
+        }
+        sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return 0;
+        }
+    }
+    fprintf(stderr, "%s: could not launch network script\n", setup_script);
+    return -1;
+}
+
+static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
+{
+    int fd, vnet_hdr_required;
+    char ifname[128] = {0,};
+    const char *setup_script;
+
+    if (qemu_opt_get(opts, "ifname")) {
+        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
+    }
+
+    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
+    if (qemu_opt_get(opts, "vnet_hdr")) {
+        vnet_hdr_required = *vnet_hdr;
+    } else {
+        vnet_hdr_required = 0;
+    }
+
+    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
+    if (fd < 0) {
+        return -1;
+    }
+
+    setup_script = qemu_opt_get(opts, "script");
+    if (setup_script &&
+        setup_script[0] != '\0' &&
+        strcmp(setup_script, "no") != 0 &&
+        launch_script(setup_script, ifname, fd)) {
+        close(fd);
+        return -1;
+    }
+
+    qemu_opt_set(opts, "ifname", ifname);
+
+    return fd;
+}
+
+int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
+{
+    TAPState *s;
+    int fd, vnet_hdr = 0;
+
+    if (qemu_opt_get(opts, "fd")) {
+        if (qemu_opt_get(opts, "ifname") ||
+            qemu_opt_get(opts, "script") ||
+            qemu_opt_get(opts, "downscript") ||
+            qemu_opt_get(opts, "vnet_hdr")) {
+            error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=");
+            return -1;
+        }
+
+        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
+        if (fd == -1) {
+            return -1;
+        }
+
+        fcntl(fd, F_SETFL, O_NONBLOCK);
+
+        vnet_hdr = tap_probe_vnet_hdr(fd);
+    } else {
+        if (!qemu_opt_get(opts, "script")) {
+            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
+        }
+
+        if (!qemu_opt_get(opts, "downscript")) {
+            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
+        }
+
+        fd = net_tap_init(opts, &vnet_hdr);
+        if (fd == -1) {
+            return -1;
+        }
+    }
+
+    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
+    if (!s) {
+        close(fd);
+        return -1;
+    }
+
+    if (tap_set_sndbuf(s->fd, opts) < 0) {
+        return -1;
+    }
+
+    if (qemu_opt_get(opts, "fd")) {
+        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
+    } else {
+        const char *ifname, *script, *downscript;
+
+        ifname     = qemu_opt_get(opts, "ifname");
+        script     = qemu_opt_get(opts, "script");
+        downscript = qemu_opt_get(opts, "downscript");
+
+        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+                 "ifname=%s,script=%s,downscript=%s",
+                 ifname, script, downscript);
+
+        if (strcmp(downscript, "no") != 0) {
+            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
+            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+        }
+    }
+
+    if (qemu_opt_get_bool(opts, "vhost", !!qemu_opt_get(opts, "vhostfd") ||
+                          qemu_opt_get_bool(opts, "vhostforce", false))) {
+        int vhostfd, r;
+        bool force = qemu_opt_get_bool(opts, "vhostforce", false);
+        if (qemu_opt_get(opts, "vhostfd")) {
+            r = net_handle_fd_param(mon, qemu_opt_get(opts, "vhostfd"));
+            if (r == -1) {
+                return -1;
+            }
+            vhostfd = r;
+        } else {
+            vhostfd = -1;
+        }
+        s->vhost_net = vhost_net_init(&s->nc, vhostfd, force);
+        if (!s->vhost_net) {
+            error_report("vhost-net requested but could not be initialized");
+            return -1;
+        }
+    } else if (qemu_opt_get(opts, "vhostfd")) {
+        error_report("vhostfd= is not valid without vhost");
+        return -1;
+    }
+
+    return 0;
+}
+
+VHostNetState *tap_get_vhost_net(VLANClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
+    return s->vhost_net;
+}
diff --git a/qemu-0.15.x/net/tap.h b/qemu-0.15.x/net/tap.h
new file mode 100644
index 0000000..e44bd2b
--- /dev/null
+++ b/qemu-0.15.x/net/tap.h
@@ -0,0 +1,60 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * 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 QEMU_NET_TAP_H
+#define QEMU_NET_TAP_H
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+
+int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan);
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required);
+
+ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen);
+
+int tap_has_ufo(VLANClientState *vc);
+int tap_has_vnet_hdr(VLANClientState *vc);
+int tap_has_vnet_hdr_len(VLANClientState *vc, int len);
+void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr);
+void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn, int ufo);
+void tap_set_vnet_hdr_len(VLANClientState *vc, int len);
+
+int tap_set_sndbuf(int fd, QemuOpts *opts);
+int tap_probe_vnet_hdr(int fd);
+int tap_probe_vnet_hdr_len(int fd, int len);
+int tap_probe_has_ufo(int fd);
+void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
+void tap_fd_set_vnet_hdr_len(int fd, int len);
+
+int tap_get_fd(VLANClientState *vc);
+
+struct vhost_net;
+struct vhost_net *tap_get_vhost_net(VLANClientState *vc);
+
+#endif /* QEMU_NET_TAP_H */
diff --git a/qemu-0.15.x/net/util.c b/qemu-0.15.x/net/util.c
new file mode 100644
index 0000000..1e9afbc
--- /dev/null
+++ b/qemu-0.15.x/net/util.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/util.h"
+#include <errno.h>
+#include <stdlib.h>
+
+int net_parse_macaddr(uint8_t *macaddr, const char *p)
+{
+    int i;
+    char *last_char;
+    long int offset;
+
+    errno = 0;
+    offset = strtol(p, &last_char, 0);
+    if (errno == 0 && *last_char == '\0' &&
+        offset >= 0 && offset <= 0xFFFFFF) {
+        macaddr[3] = (offset & 0xFF0000) >> 16;
+        macaddr[4] = (offset & 0xFF00) >> 8;
+        macaddr[5] = offset & 0xFF;
+        return 0;
+    }
+
+    for (i = 0; i < 6; i++) {
+        macaddr[i] = strtol(p, (char **)&p, 16);
+        if (i == 5) {
+            if (*p != '\0') {
+                return -1;
+            }
+        } else {
+            if (*p != ':' && *p != '-') {
+                return -1;
+            }
+            p++;
+        }
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/net/util.h b/qemu-0.15.x/net/util.h
new file mode 100644
index 0000000..10c7da9
--- /dev/null
+++ b/qemu-0.15.x/net/util.h
@@ -0,0 +1,32 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 QEMU_NET_UTIL_H
+#define QEMU_NET_UTIL_H
+
+#include <stdint.h>
+
+int net_parse_macaddr(uint8_t *macaddr, const char *p);
+
+#endif /* QEMU_NET_UTIL_H */
diff --git a/qemu-0.15.x/net/vde.c b/qemu-0.15.x/net/vde.c
new file mode 100644
index 0000000..ac48ab2
--- /dev/null
+++ b/qemu-0.15.x/net/vde.c
@@ -0,0 +1,130 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "net/vde.h"
+
+#include "config-host.h"
+
+#include <libvdeplug.h>
+
+#include "net.h"
+#include "qemu-char.h"
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+typedef struct VDEState {
+    VLANClientState nc;
+    VDECONN *vde;
+} VDEState;
+
+static void vde_to_qemu(void *opaque)
+{
+    VDEState *s = opaque;
+    uint8_t buf[4096];
+    int size;
+
+    size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
+    if (size > 0) {
+        qemu_send_packet(&s->nc, buf, size);
+    }
+}
+
+static ssize_t vde_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    VDEState *s = DO_UPCAST(VDEState, nc, nc);
+    ssize_t ret;
+
+    do {
+      ret = vde_send(s->vde, (const char *)buf, size, 0);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static void vde_cleanup(VLANClientState *nc)
+{
+    VDEState *s = DO_UPCAST(VDEState, nc, nc);
+    qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL);
+    vde_close(s->vde);
+}
+
+static NetClientInfo net_vde_info = {
+    .type = NET_CLIENT_TYPE_VDE,
+    .size = sizeof(VDEState),
+    .receive = vde_receive,
+    .cleanup = vde_cleanup,
+};
+
+static int net_vde_init(VLANState *vlan, const char *model,
+                        const char *name, const char *sock,
+                        int port, const char *group, int mode)
+{
+    VLANClientState *nc;
+    VDEState *s;
+    VDECONN *vde;
+    char *init_group = (char *)group;
+    char *init_sock = (char *)sock;
+
+    struct vde_open_args args = {
+        .port = port,
+        .group = init_group,
+        .mode = mode,
+    };
+
+    vde = vde_open(init_sock, (char *)"QEMU", &args);
+    if (!vde){
+        return -1;
+    }
+
+    nc = qemu_new_net_client(&net_vde_info, vlan, NULL, model, name);
+
+    snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d",
+             sock, vde_datafd(vde));
+
+    s = DO_UPCAST(VDEState, nc, nc);
+
+    s->vde = vde;
+
+    qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+
+    return 0;
+}
+
+int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
+{
+    const char *sock;
+    const char *group;
+    int port, mode;
+
+    sock  = qemu_opt_get(opts, "sock");
+    group = qemu_opt_get(opts, "group");
+
+    port = qemu_opt_get_number(opts, "port", 0);
+    mode = qemu_opt_get_number(opts, "mode", 0700);
+
+    if (net_vde_init(vlan, "vde", name, sock, port, group, mode) == -1) {
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/net/vde.h b/qemu-0.15.x/net/vde.h
new file mode 100644
index 0000000..3e6ca3e
--- /dev/null
+++ b/qemu-0.15.x/net/vde.h
@@ -0,0 +1,36 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 QEMU_NET_VDE_H
+#define QEMU_NET_VDE_H
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+#ifdef CONFIG_VDE
+
+int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan);
+
+#endif /* CONFIG_VDE */
+
+#endif /* QEMU_NET_VDE_H */
diff --git a/qemu-0.15.x/notify.c b/qemu-0.15.x/notify.c
new file mode 100644
index 0000000..a6bac1f
--- /dev/null
+++ b/qemu-0.15.x/notify.c
@@ -0,0 +1,39 @@
+/*
+ * Notifier lists
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "notify.h"
+
+void notifier_list_init(NotifierList *list)
+{
+    QTAILQ_INIT(&list->notifiers);
+}
+
+void notifier_list_add(NotifierList *list, Notifier *notifier)
+{
+    QTAILQ_INSERT_HEAD(&list->notifiers, notifier, node);
+}
+
+void notifier_list_remove(NotifierList *list, Notifier *notifier)
+{
+    QTAILQ_REMOVE(&list->notifiers, notifier, node);
+}
+
+void notifier_list_notify(NotifierList *list, void *data)
+{
+    Notifier *notifier, *next;
+
+    QTAILQ_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
+        notifier->notify(notifier, data);
+    }
+}
diff --git a/qemu-0.15.x/notify.h b/qemu-0.15.x/notify.h
new file mode 100644
index 0000000..54fc57c
--- /dev/null
+++ b/qemu-0.15.x/notify.h
@@ -0,0 +1,43 @@
+/*
+ * Notifier lists
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_NOTIFY_H
+#define QEMU_NOTIFY_H
+
+#include "qemu-queue.h"
+
+typedef struct Notifier Notifier;
+
+struct Notifier
+{
+    void (*notify)(Notifier *notifier, void *data);
+    QTAILQ_ENTRY(Notifier) node;
+};
+
+typedef struct NotifierList
+{
+    QTAILQ_HEAD(, Notifier) notifiers;
+} NotifierList;
+
+#define NOTIFIER_LIST_INITIALIZER(head) \
+    { QTAILQ_HEAD_INITIALIZER((head).notifiers) }
+
+void notifier_list_init(NotifierList *list);
+
+void notifier_list_add(NotifierList *list, Notifier *notifier);
+
+void notifier_list_remove(NotifierList *list, Notifier *notifier);
+
+void notifier_list_notify(NotifierList *list, void *data);
+
+#endif
diff --git a/qemu-0.15.x/os-posix.c b/qemu-0.15.x/os-posix.c
new file mode 100644
index 0000000..6f8d488
--- /dev/null
+++ b/qemu-0.15.x/os-posix.c
@@ -0,0 +1,392 @@
+/*
+ * os-posix.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+/*needed for MAP_POPULATE before including qemu-options.h */
+#include <sys/mman.h>
+#include <pwd.h>
+#include <grp.h>
+#include <libgen.h>
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+#include "sysemu.h"
+#include "net/slirp.h"
+#include "qemu-options.h"
+
+#ifdef CONFIG_LINUX
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+static struct passwd *user_pwd;
+static const char *chroot_dir;
+static int daemonize;
+static int fds[2];
+
+void os_setup_early_signal_handling(void)
+{
+    struct sigaction act;
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &act, NULL);
+}
+
+static void termsig_handler(int signal, siginfo_t *info, void *c)
+{
+    qemu_system_killed(info->si_signo, info->si_pid);
+}
+
+void os_setup_signal_handling(void)
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = termsig_handler;
+    act.sa_flags = SA_SIGINFO;
+    sigaction(SIGINT,  &act, NULL);
+    sigaction(SIGHUP,  &act, NULL);
+    sigaction(SIGTERM, &act, NULL);
+}
+
+/* Find a likely location for support files using the location of the binary.
+   For installed binaries this will be "$bindir/../share/qemu".  When
+   running from the build tree this will be "$bindir/../pc-bios".  */
+#define SHARE_SUFFIX "/share/qemu"
+#define BUILD_SUFFIX "/pc-bios"
+char *os_find_datadir(const char *argv0)
+{
+    char *dir;
+    char *p = NULL;
+    char *res;
+    char buf[PATH_MAX];
+    size_t max_len;
+
+#if defined(__linux__)
+    {
+        int len;
+        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#elif defined(__FreeBSD__)
+    {
+        static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+        size_t len = sizeof(buf) - 1;
+
+        *buf = '\0';
+        if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
+            *buf) {
+            buf[sizeof(buf) - 1] = '\0';
+            p = buf;
+        }
+    }
+#endif
+    /* If we don't have any way of figuring out the actual executable
+       location then try argv[0].  */
+    if (!p) {
+        p = realpath(argv0, buf);
+        if (!p) {
+            return NULL;
+        }
+    }
+    dir = dirname(p);
+    dir = dirname(dir);
+
+    max_len = strlen(dir) +
+        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+    res = qemu_mallocz(max_len);
+    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+    if (access(res, R_OK)) {
+        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+        if (access(res, R_OK)) {
+            qemu_free(res);
+            res = NULL;
+        }
+    }
+
+    return res;
+}
+#undef SHARE_SUFFIX
+#undef BUILD_SUFFIX
+
+void os_set_proc_name(const char *s)
+{
+#if defined(PR_SET_NAME)
+    char name[16];
+    if (!s)
+        return;
+    name[sizeof(name) - 1] = 0;
+    strncpy(name, s, sizeof(name));
+    /* Could rewrite argv[0] too, but that's a bit more complicated.
+       This simple way is enough for `top'. */
+    if (prctl(PR_SET_NAME, name)) {
+        perror("unable to change process name");
+        exit(1);
+    }
+#else
+    fprintf(stderr, "Change of process name not supported by your OS\n");
+    exit(1);
+#endif
+}
+
+/*
+ * Parse OS specific command line options.
+ * return 0 if option handled, -1 otherwise
+ */
+void os_parse_cmd_args(int index, const char *optarg)
+{
+    switch (index) {
+#ifdef CONFIG_SLIRP
+    case QEMU_OPTION_smb:
+        if (net_slirp_smb(optarg) < 0)
+            exit(1);
+        break;
+#endif
+    case QEMU_OPTION_runas:
+        user_pwd = getpwnam(optarg);
+        if (!user_pwd) {
+            fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
+            exit(1);
+        }
+        break;
+    case QEMU_OPTION_chroot:
+        chroot_dir = optarg;
+        break;
+    case QEMU_OPTION_daemonize:
+        daemonize = 1;
+        break;
+    }
+    return;
+}
+
+static void change_process_uid(void)
+{
+    if (user_pwd) {
+        if (setgid(user_pwd->pw_gid) < 0) {
+            fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
+            exit(1);
+        }
+        if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
+            fprintf(stderr, "Failed to initgroups(\"%s\", %d)\n",
+                    user_pwd->pw_name, user_pwd->pw_gid);
+            exit(1);
+        }
+        if (setuid(user_pwd->pw_uid) < 0) {
+            fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
+            exit(1);
+        }
+        if (setuid(0) != -1) {
+            fprintf(stderr, "Dropping privileges failed\n");
+            exit(1);
+        }
+    }
+}
+
+static void change_root(void)
+{
+    if (chroot_dir) {
+        if (chroot(chroot_dir) < 0) {
+            fprintf(stderr, "chroot failed\n");
+            exit(1);
+        }
+        if (chdir("/")) {
+            perror("not able to chdir to /");
+            exit(1);
+        }
+    }
+
+}
+
+void os_daemonize(void)
+{
+    if (daemonize) {
+	pid_t pid;
+
+	if (pipe(fds) == -1)
+	    exit(1);
+
+	pid = fork();
+	if (pid > 0) {
+	    uint8_t status;
+	    ssize_t len;
+
+	    close(fds[1]);
+
+	again:
+            len = read(fds[0], &status, 1);
+            if (len == -1 && (errno == EINTR))
+                goto again;
+
+            if (len != 1)
+                exit(1);
+            else if (status == 1) {
+                fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
+                exit(1);
+            } else
+                exit(0);
+	} else if (pid < 0)
+            exit(1);
+
+	close(fds[0]);
+	qemu_set_cloexec(fds[1]);
+
+	setsid();
+
+	pid = fork();
+	if (pid > 0)
+	    exit(0);
+	else if (pid < 0)
+	    exit(1);
+
+	umask(027);
+
+        signal(SIGTSTP, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+        signal(SIGTTIN, SIG_IGN);
+    }
+}
+
+void os_setup_post(void)
+{
+    int fd = 0;
+
+    if (daemonize) {
+	uint8_t status = 0;
+	ssize_t len;
+
+    again1:
+	len = write(fds[1], &status, 1);
+	if (len == -1 && (errno == EINTR))
+	    goto again1;
+
+	if (len != 1)
+	    exit(1);
+
+        if (chdir("/")) {
+            perror("not able to chdir to /");
+            exit(1);
+        }
+	TFR(fd = qemu_open("/dev/null", O_RDWR));
+	if (fd == -1)
+	    exit(1);
+    }
+
+    change_root();
+    change_process_uid();
+
+    if (daemonize) {
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+
+        close(fd);
+    }
+}
+
+void os_pidfile_error(void)
+{
+    if (daemonize) {
+        uint8_t status = 1;
+        if (write(fds[1], &status, 1) != 1) {
+            perror("daemonize. Writing to pipe\n");
+        }
+    } else
+        fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+}
+
+void os_set_line_buffering(void)
+{
+    setvbuf(stdout, NULL, _IOLBF, 0);
+}
+
+/*
+ * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
+ */
+int qemu_eventfd(int fds[2])
+{
+#ifdef CONFIG_EVENTFD
+    int ret;
+
+    ret = eventfd(0, 0);
+    if (ret >= 0) {
+        fds[0] = ret;
+        qemu_set_cloexec(ret);
+        if ((fds[1] = dup(ret)) == -1) {
+            close(ret);
+            return -1;
+        }
+        qemu_set_cloexec(fds[1]);
+        return 0;
+    }
+
+    if (errno != ENOSYS) {
+        return -1;
+    }
+#endif
+
+    return qemu_pipe(fds);
+}
+
+int qemu_create_pidfile(const char *filename)
+{
+    char buffer[128];
+    int len;
+    int fd;
+
+    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
+    if (fd == -1) {
+        return -1;
+    }
+    if (lockf(fd, F_TLOCK, 0) == -1) {
+        return -1;
+    }
+    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
+    if (write(fd, buffer, len) != len) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int qemu_get_thread_id(void)
+{
+#if defined (__linux__)
+    return syscall(SYS_gettid);
+#else
+    return getpid();
+#endif
+}
diff --git a/qemu-0.15.x/os-win32.c b/qemu-0.15.x/os-win32.c
new file mode 100644
index 0000000..b6652af
--- /dev/null
+++ b/qemu-0.15.x/os-win32.c
@@ -0,0 +1,273 @@
+/*
+ * os-win32.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * 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 <windows.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include "config-host.h"
+#include "sysemu.h"
+#include "qemu-options.h"
+
+/***********************************************************/
+/* Functions missing in mingw */
+
+int setenv(const char *name, const char *value, int overwrite)
+{
+    int result = 0;
+    if (overwrite || !getenv(name)) {
+        size_t length = strlen(name) + strlen(value) + 2;
+        char *string = qemu_malloc(length);
+        snprintf(string, length, "%s=%s", name, value);
+        result = putenv(string);
+    }
+    return result;
+}
+
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+    PollingFunc *func;
+    void *opaque;
+    struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    pe = qemu_mallocz(sizeof(PollingEntry));
+    pe->func = func;
+    pe->opaque = opaque;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+    *ppe = pe;
+    return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+        pe = *ppe;
+        if (pe->func == func && pe->opaque == opaque) {
+            *ppe = pe->next;
+            qemu_free(pe);
+            break;
+        }
+    }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+    int num;
+    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    WaitObjects *w = &wait_objects;
+
+    if (w->num >= MAXIMUM_WAIT_OBJECTS)
+        return -1;
+    w->events[w->num] = handle;
+    w->func[w->num] = func;
+    w->opaque[w->num] = opaque;
+    w->num++;
+    return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    int i, found;
+    WaitObjects *w = &wait_objects;
+
+    found = 0;
+    for (i = 0; i < w->num; i++) {
+        if (w->events[i] == handle)
+            found = 1;
+        if (found) {
+            w->events[i] = w->events[i + 1];
+            w->func[i] = w->func[i + 1];
+            w->opaque[i] = w->opaque[i + 1];
+        }
+    }
+    if (found)
+        w->num--;
+}
+
+void os_host_main_loop_wait(int *timeout)
+{
+    int ret, ret2, i;
+    PollingEntry *pe;
+
+    /* XXX: need to suppress polling by better using win32 events */
+    ret = 0;
+    for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
+        ret |= pe->func(pe->opaque);
+    }
+    if (ret == 0) {
+        int err;
+        WaitObjects *w = &wait_objects;
+
+        qemu_mutex_unlock_iothread();
+        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+        qemu_mutex_lock_iothread();
+        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+            if (w->func[ret - WAIT_OBJECT_0])
+                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+            /* Check for additional signaled events */
+            for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+                /* Check if event is signaled */
+                ret2 = WaitForSingleObject(w->events[i], 0);
+                if(ret2 == WAIT_OBJECT_0) {
+                    if (w->func[i])
+                        w->func[i](w->opaque[i]);
+                } else if (ret2 == WAIT_TIMEOUT) {
+                } else {
+                    err = GetLastError();
+                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+                }
+            }
+        } else if (ret == WAIT_TIMEOUT) {
+        } else {
+            err = GetLastError();
+            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+        }
+    }
+
+    *timeout = 0;
+}
+
+static BOOL WINAPI qemu_ctrl_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+
+void os_setup_early_signal_handling(void)
+{
+    /* Note: cpu_interrupt() is currently not SMP safe, so we force
+       QEMU to run on a single CPU */
+    HANDLE h;
+    DWORD_PTR mask, smask;
+    int i;
+
+    SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+
+    h = GetCurrentProcess();
+    if (GetProcessAffinityMask(h, &mask, &smask)) {
+        for(i = 0; i < 32; i++) {
+            if (mask & (1 << i))
+                break;
+        }
+        if (i != 32) {
+            mask = 1 << i;
+            SetProcessAffinityMask(h, mask);
+        }
+    }
+}
+
+/* Look for support files in the same directory as the executable.  */
+char *os_find_datadir(const char *argv0)
+{
+    char *p;
+    char buf[MAX_PATH];
+    DWORD len;
+
+    len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
+    if (len == 0) {
+        return NULL;
+    }
+
+    buf[len] = 0;
+    p = buf + len - 1;
+    while (p != buf && *p != '\\')
+        p--;
+    *p = 0;
+    if (access(buf, R_OK) == 0) {
+        return qemu_strdup(buf);
+    }
+    return NULL;
+}
+
+void os_set_line_buffering(void)
+{
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+}
+
+/*
+ * Parse OS specific command line options.
+ * return 0 if option handled, -1 otherwise
+ */
+void os_parse_cmd_args(int index, const char *optarg)
+{
+    return;
+}
+
+void os_pidfile_error(void)
+{
+    fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+}
+
+int qemu_create_pidfile(const char *filename)
+{
+    char buffer[128];
+    int len;
+    HANDLE file;
+    OVERLAPPED overlap;
+    BOOL ret;
+    memset(&overlap, 0, sizeof(overlap));
+
+    file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+		      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if (file == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
+    ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
+		      &overlap, NULL);
+    if (ret == 0) {
+        return -1;
+    }
+    return 0;
+}
+
+int qemu_get_thread_id(void)
+{
+    return GetCurrentThreadId();
+}
diff --git a/qemu-0.15.x/osdep.c b/qemu-0.15.x/osdep.c
new file mode 100644
index 0000000..56e6963
--- /dev/null
+++ b/qemu-0.15.x/osdep.c
@@ -0,0 +1,168 @@
+/*
+ * QEMU low level functions
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+
+#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
+#include <sys/mman.h>
+#endif
+
+#ifdef CONFIG_SOLARIS
+#include <sys/types.h>
+#include <sys/statvfs.h>
+/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
+   discussion about Solaris header problems */
+extern int madvise(caddr_t, size_t, int);
+#endif
+
+#include "qemu-common.h"
+#include "trace.h"
+#include "qemu_socket.h"
+
+int qemu_madvise(void *addr, size_t len, int advice)
+{
+    if (advice == QEMU_MADV_INVALID) {
+        errno = EINVAL;
+        return -1;
+    }
+#if defined(CONFIG_MADVISE)
+    return madvise(addr, len, advice);
+#elif defined(CONFIG_POSIX_MADVISE)
+    return posix_madvise(addr, len, advice);
+#else
+    errno = EINVAL;
+    return -1;
+#endif
+}
+
+
+/*
+ * Opens a file with FD_CLOEXEC set
+ */
+int qemu_open(const char *name, int flags, ...)
+{
+    int ret;
+    int mode = 0;
+
+    if (flags & O_CREAT) {
+        va_list ap;
+
+        va_start(ap, flags);
+        mode = va_arg(ap, int);
+        va_end(ap);
+    }
+
+#ifdef O_CLOEXEC
+    ret = open(name, flags | O_CLOEXEC, mode);
+#else
+    ret = open(name, flags, mode);
+    if (ret >= 0) {
+        qemu_set_cloexec(ret);
+    }
+#endif
+
+    return ret;
+}
+
+/*
+ * A variant of write(2) which handles partial write.
+ *
+ * Return the number of bytes transferred.
+ * Set errno if fewer than `count' bytes are written.
+ *
+ * This function don't work with non-blocking fd's.
+ * Any of the possibilities with non-bloking fd's is bad:
+ *   - return a short write (then name is wrong)
+ *   - busy wait adding (errno == EAGAIN) to the loop
+ */
+ssize_t qemu_write_full(int fd, const void *buf, size_t count)
+{
+    ssize_t ret = 0;
+    ssize_t total = 0;
+
+    while (count) {
+        ret = write(fd, buf, count);
+        if (ret < 0) {
+            if (errno == EINTR)
+                continue;
+            break;
+        }
+
+        count -= ret;
+        buf += ret;
+        total += ret;
+    }
+
+    return total;
+}
+
+/*
+ * Opens a socket with FD_CLOEXEC set
+ */
+int qemu_socket(int domain, int type, int protocol)
+{
+    int ret;
+
+#ifdef SOCK_CLOEXEC
+    ret = socket(domain, type | SOCK_CLOEXEC, protocol);
+    if (ret != -1 || errno != EINVAL) {
+        return ret;
+    }
+#endif
+    ret = socket(domain, type, protocol);
+    if (ret >= 0) {
+        qemu_set_cloexec(ret);
+    }
+
+    return ret;
+}
+
+/*
+ * Accept a connection and set FD_CLOEXEC
+ */
+int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+    int ret;
+
+#ifdef CONFIG_ACCEPT4
+    ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
+    if (ret != -1 || errno != ENOSYS) {
+        return ret;
+    }
+#endif
+    ret = accept(s, addr, addrlen);
+    if (ret >= 0) {
+        qemu_set_cloexec(ret);
+    }
+
+    return ret;
+}
diff --git a/qemu-0.15.x/osdep.h b/qemu-0.15.x/osdep.h
new file mode 100644
index 0000000..a817017
--- /dev/null
+++ b/qemu-0.15.x/osdep.h
@@ -0,0 +1,157 @@
+#ifndef QEMU_OSDEP_H
+#define QEMU_OSDEP_H
+
+#include <stdarg.h>
+#include <stddef.h>
+#ifdef __OpenBSD__
+#include <sys/types.h>
+#include <sys/signal.h>
+#endif
+
+#include <sys/time.h>
+
+#ifndef glue
+#define xglue(x, y) x ## y
+#define glue(x, y) xglue(x, y)
+#define stringify(s)	tostring(s)
+#define tostring(s)	#s
+#endif
+
+#ifndef likely
+#if __GNUC__ < 3
+#define __builtin_expect(x, n) (x)
+#endif
+
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+
+#ifdef CONFIG_NEED_OFFSETOF
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
+#endif
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
+        (type *) ((char *) __mptr - offsetof(type, member));})
+#endif
+
+/* Convert from a base type to a parent type, with compile time checking.  */
+#ifdef __GNUC__
+#define DO_UPCAST(type, field, dev) ( __extension__ ( { \
+    char __attribute__((unused)) offset_must_be_zero[ \
+        -offsetof(type, field)]; \
+    container_of(dev, type, field);}))
+#else
+#define DO_UPCAST(type, field, dev) container_of(dev, type, field)
+#endif
+
+#define typeof_field(type, field) typeof(((type *)0)->field)
+#define type_check(t1,t2) ((t1*)0 - (t2*)0)
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef always_inline
+#if !((__GNUC__ < 3) || defined(__APPLE__))
+#ifdef __OPTIMIZE__
+#define inline __attribute__ (( always_inline )) __inline__
+#endif
+#endif
+#else
+#define inline always_inline
+#endif
+
+#ifdef __i386__
+#define REGPARM __attribute((regparm(3)))
+#else
+#define REGPARM
+#endif
+
+#define qemu_printf printf
+
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+# define QEMU_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define QEMU_GNUC_PREREQ(maj, min) 0
+#endif
+
+int qemu_daemon(int nochdir, int noclose);
+void *qemu_memalign(size_t alignment, size_t size);
+void *qemu_vmalloc(size_t size);
+void qemu_vfree(void *ptr);
+
+#define QEMU_MADV_INVALID -1
+
+#if defined(CONFIG_MADVISE)
+
+#define QEMU_MADV_WILLNEED  MADV_WILLNEED
+#define QEMU_MADV_DONTNEED  MADV_DONTNEED
+#ifdef MADV_DONTFORK
+#define QEMU_MADV_DONTFORK  MADV_DONTFORK
+#else
+#define QEMU_MADV_DONTFORK  QEMU_MADV_INVALID
+#endif
+#ifdef MADV_MERGEABLE
+#define QEMU_MADV_MERGEABLE MADV_MERGEABLE
+#else
+#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
+#endif
+
+#elif defined(CONFIG_POSIX_MADVISE)
+
+#define QEMU_MADV_WILLNEED  POSIX_MADV_WILLNEED
+#define QEMU_MADV_DONTNEED  POSIX_MADV_DONTNEED
+#define QEMU_MADV_DONTFORK  QEMU_MADV_INVALID
+#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
+
+#else /* no-op */
+
+#define QEMU_MADV_WILLNEED  QEMU_MADV_INVALID
+#define QEMU_MADV_DONTNEED  QEMU_MADV_INVALID
+#define QEMU_MADV_DONTFORK  QEMU_MADV_INVALID
+#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
+
+#endif
+
+int qemu_madvise(void *addr, size_t len, int advice);
+
+#if defined(__HAIKU__) && defined(__i386__)
+#define FMT_pid "%ld"
+#else
+#define FMT_pid "%d"
+#endif
+
+int qemu_create_pidfile(const char *filename);
+int qemu_get_thread_id(void);
+
+#ifdef _WIN32
+static inline void qemu_timersub(const struct timeval *val1,
+                                 const struct timeval *val2,
+                                 struct timeval *res)
+{
+    res->tv_sec = val1->tv_sec - val2->tv_sec;
+    if (val1->tv_usec < val2->tv_usec) {
+        res->tv_sec--;
+        res->tv_usec = val1->tv_usec - val2->tv_usec + 1000 * 1000;
+    } else {
+        res->tv_usec = val1->tv_usec - val2->tv_usec;
+    }
+}
+#else
+#define qemu_timersub timersub
+#endif
+
+#endif
diff --git a/qemu-0.15.x/oslib-posix.c b/qemu-0.15.x/oslib-posix.c
new file mode 100644
index 0000000..3a18e86
--- /dev/null
+++ b/qemu-0.15.x/oslib-posix.c
@@ -0,0 +1,173 @@
+/*
+ * os-posix-lib.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * QEMU library functions on POSIX which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * 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.
+ */
+
+/* The following block of code temporarily renames the daemon() function so the
+   compiler does not see the warning associated with it in stdlib.h on OSX */
+#ifdef __APPLE__
+#define daemon qemu_fake_daemon_function
+#include <stdlib.h>
+#undef daemon
+extern int daemon(int, int);
+#endif
+
+#include "config-host.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu_socket.h"
+
+
+
+int qemu_daemon(int nochdir, int noclose)
+{
+    return daemon(nochdir, noclose);
+}
+
+void *qemu_oom_check(void *ptr)
+{
+    if (ptr == NULL) {
+        fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
+        abort();
+    }
+    return ptr;
+}
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+    void *ptr;
+#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
+    int ret;
+    ret = posix_memalign(&ptr, alignment, size);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to allocate %zu B: %s\n",
+                size, strerror(ret));
+        abort();
+    }
+#elif defined(CONFIG_BSD)
+    ptr = qemu_oom_check(valloc(size));
+#else
+    ptr = qemu_oom_check(memalign(alignment, size));
+#endif
+    trace_qemu_memalign(alignment, size, ptr);
+    return ptr;
+}
+
+/* alloc shared memory pages */
+void *qemu_vmalloc(size_t size)
+{
+    return qemu_memalign(getpagesize(), size);
+}
+
+void qemu_vfree(void *ptr)
+{
+    trace_qemu_vfree(ptr);
+    free(ptr);
+}
+
+void socket_set_nonblock(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, f | O_NONBLOCK);
+}
+
+void qemu_set_cloexec(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFD);
+    fcntl(fd, F_SETFD, f | FD_CLOEXEC);
+}
+
+/*
+ * Creates a pipe with FD_CLOEXEC set on both file descriptors
+ */
+int qemu_pipe(int pipefd[2])
+{
+    int ret;
+
+#ifdef CONFIG_PIPE2
+    ret = pipe2(pipefd, O_CLOEXEC);
+    if (ret != -1 || errno != ENOSYS) {
+        return ret;
+    }
+#endif
+    ret = pipe(pipefd);
+    if (ret == 0) {
+        qemu_set_cloexec(pipefd[0]);
+        qemu_set_cloexec(pipefd[1]);
+    }
+
+    return ret;
+}
+
+int qemu_utimensat(int dirfd, const char *path, const struct timespec *times,
+                   int flags)
+{
+    struct timeval tv[2], tv_now;
+    struct stat st;
+    int i;
+#ifdef CONFIG_UTIMENSAT
+    int ret;
+
+    ret = utimensat(dirfd, path, times, flags);
+    if (ret != -1 || errno != ENOSYS) {
+        return ret;
+    }
+#endif
+    /* Fallback: use utimes() instead of utimensat() */
+
+    /* happy if special cases */
+    if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) {
+        return 0;
+    }
+    if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) {
+        return utimes(path, NULL);
+    }
+
+    /* prepare for hard cases */
+    if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
+        gettimeofday(&tv_now, NULL);
+    }
+    if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
+        stat(path, &st);
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (times[i].tv_nsec == UTIME_NOW) {
+            tv[i].tv_sec = tv_now.tv_sec;
+            tv[i].tv_usec = tv_now.tv_usec;
+        } else if (times[i].tv_nsec == UTIME_OMIT) {
+            tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
+            tv[i].tv_usec = 0;
+        } else {
+            tv[i].tv_sec = times[i].tv_sec;
+            tv[i].tv_usec = times[i].tv_nsec / 1000;
+        }
+    }
+
+    return utimes(path, &tv[0]);
+}
diff --git a/qemu-0.15.x/oslib-win32.c b/qemu-0.15.x/oslib-win32.c
new file mode 100644
index 0000000..5f0759f
--- /dev/null
+++ b/qemu-0.15.x/oslib-win32.c
@@ -0,0 +1,114 @@
+/*
+ * os-win32.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * QEMU library functions for win32 which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * 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 <windows.h>
+#include "config-host.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu_socket.h"
+
+void *qemu_oom_check(void *ptr)
+{
+    if (ptr == NULL) {
+        fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
+        abort();
+    }
+    return ptr;
+}
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+    void *ptr;
+
+    if (!size) {
+        abort();
+    }
+    ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+    trace_qemu_memalign(alignment, size, ptr);
+    return ptr;
+}
+
+void *qemu_vmalloc(size_t size)
+{
+    void *ptr;
+
+    /* FIXME: this is not exactly optimal solution since VirtualAlloc
+       has 64Kb granularity, but at least it guarantees us that the
+       memory is page aligned. */
+    if (!size) {
+        abort();
+    }
+    ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+    trace_qemu_vmalloc(size, ptr);
+    return ptr;
+}
+
+void qemu_vfree(void *ptr)
+{
+    trace_qemu_vfree(ptr);
+    VirtualFree(ptr, 0, MEM_RELEASE);
+}
+
+void socket_set_nonblock(int fd)
+{
+    unsigned long opt = 1;
+    ioctlsocket(fd, FIONBIO, &opt);
+}
+
+int inet_aton(const char *cp, struct in_addr *ia)
+{
+    uint32_t addr = inet_addr(cp);
+    if (addr == 0xffffffff) {
+	return 0;
+    }
+    ia->s_addr = addr;
+    return 1;
+}
+
+void qemu_set_cloexec(int fd)
+{
+}
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
+#define _W32_FT_OFFSET (116444736000000000ULL)
+
+int qemu_gettimeofday(qemu_timeval *tp)
+{
+  union {
+    unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
+    FILETIME ft;
+  }  _now;
+
+  if(tp) {
+      GetSystemTimeAsFileTime (&_now.ft);
+      tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
+      tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
+  }
+  /* Always return 0 as per Open Group Base Specifications Issue 6.
+     Do not set errno on error.  */
+  return 0;
+}
diff --git a/qemu-0.15.x/path.c b/qemu-0.15.x/path.c
new file mode 100644
index 0000000..ef3f277
--- /dev/null
+++ b/qemu-0.15.x/path.c
@@ -0,0 +1,181 @@
+/* Code to mangle pathnames into those matching a given prefix.
+   eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
+
+   The assumption is that this area does not change.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "qemu-common.h"
+
+struct pathelem
+{
+    /* Name of this, eg. lib */
+    char *name;
+    /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
+    char *pathname;
+    struct pathelem *parent;
+    /* Children */
+    unsigned int num_entries;
+    struct pathelem *entries[0];
+};
+
+static struct pathelem *base;
+
+/* First N chars of S1 match S2, and S2 is N chars long. */
+static int strneq(const char *s1, unsigned int n, const char *s2)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; i++)
+        if (s1[i] != s2[i])
+            return 0;
+    return s2[i] == 0;
+}
+
+static struct pathelem *add_entry(struct pathelem *root, const char *name,
+                                  unsigned char type);
+
+static struct pathelem *new_entry(const char *root,
+                                  struct pathelem *parent,
+                                  const char *name)
+{
+    struct pathelem *new = malloc(sizeof(*new));
+    new->name = strdup(name);
+    if (asprintf(&new->pathname, "%s/%s", root, name) == -1) {
+        printf("Cannot allocate memory\n");
+        exit(1);
+    }
+    new->num_entries = 0;
+    return new;
+}
+
+#define streq(a,b) (strcmp((a), (b)) == 0)
+
+/* Not all systems provide this feature */
+#if defined(DT_DIR) && defined(DT_UNKNOWN)
+# define dirent_type(dirent) ((dirent)->d_type)
+# define is_dir_maybe(type)  ((type) == DT_DIR || (type) == DT_UNKNOWN)
+#else
+# define dirent_type(dirent) (1)
+# define is_dir_maybe(type)  (type)
+#endif
+
+static struct pathelem *add_dir_maybe(struct pathelem *path)
+{
+    DIR *dir;
+
+    if ((dir = opendir(path->pathname)) != NULL) {
+        struct dirent *dirent;
+
+        while ((dirent = readdir(dir)) != NULL) {
+            if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
+                path = add_entry(path, dirent->d_name, dirent_type(dirent));
+            }
+        }
+        closedir(dir);
+    }
+    return path;
+}
+
+static struct pathelem *add_entry(struct pathelem *root, const char *name,
+                                  unsigned char type)
+{
+    struct pathelem **e;
+
+    root->num_entries++;
+
+    root = realloc(root, sizeof(*root)
+                   + sizeof(root->entries[0])*root->num_entries);
+    e = &root->entries[root->num_entries-1];
+
+    *e = new_entry(root->pathname, root, name);
+    if (is_dir_maybe(type)) {
+        *e = add_dir_maybe(*e);
+    }
+
+    return root;
+}
+
+/* This needs to be done after tree is stabilized (ie. no more reallocs!). */
+static void set_parents(struct pathelem *child, struct pathelem *parent)
+{
+    unsigned int i;
+
+    child->parent = parent;
+    for (i = 0; i < child->num_entries; i++)
+        set_parents(child->entries[i], child);
+}
+
+/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
+static const char *
+follow_path(const struct pathelem *cursor, const char *name)
+{
+    unsigned int i, namelen;
+
+    name += strspn(name, "/");
+    namelen = strcspn(name, "/");
+
+    if (namelen == 0)
+        return cursor->pathname;
+
+    if (strneq(name, namelen, ".."))
+        return follow_path(cursor->parent, name + namelen);
+
+    if (strneq(name, namelen, "."))
+        return follow_path(cursor, name + namelen);
+
+    for (i = 0; i < cursor->num_entries; i++)
+        if (strneq(name, namelen, cursor->entries[i]->name))
+            return follow_path(cursor->entries[i], name + namelen);
+
+    /* Not found */
+    return NULL;
+}
+
+void init_paths(const char *prefix)
+{
+    char pref_buf[PATH_MAX];
+
+    if (prefix[0] == '\0' ||
+        !strcmp(prefix, "/"))
+        return;
+
+    if (prefix[0] != '/') {
+        char *cwd = getcwd(NULL, 0);
+        size_t pref_buf_len = sizeof(pref_buf);
+
+        if (!cwd)
+            abort();
+        pstrcpy(pref_buf, sizeof(pref_buf), cwd);
+        pstrcat(pref_buf, pref_buf_len, "/");
+        pstrcat(pref_buf, pref_buf_len, prefix);
+        free(cwd);
+    } else
+        pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
+
+    base = new_entry("", NULL, pref_buf);
+    base = add_dir_maybe(base);
+    if (base->num_entries == 0) {
+        free (base);
+        base = NULL;
+    } else {
+        set_parents(base, base);
+    }
+}
+
+/* Look for path in emulation dir, otherwise return name. */
+const char *path(const char *name)
+{
+    /* Only do absolute paths: quick and dirty, but should mostly be OK.
+       Could do relative by tracking cwd. */
+    if (!base || !name || name[0] != '/')
+        return name;
+
+    return follow_path(base, name) ?: name;
+}
diff --git a/qemu-0.15.x/pc-bios/Makefile b/qemu-0.15.x/pc-bios/Makefile
new file mode 100644
index 0000000..315288d
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/Makefile
@@ -0,0 +1,19 @@
+#
+# NOTE: only compilable with x86 cross compile tools
+#
+include ../config-host.mak
+
+DEFINES=
+
+TARGETS=
+
+all: $(TARGETS)
+
+%.o: %.S
+	$(CC) $(DEFINES) -c -o $@ $<
+
+%.dtb: %.dts
+	dtc -I dts -O dtb -o $@ $<
+
+clean:
+	rm -f $(TARGETS) *.o *~
diff --git a/qemu-0.15.x/pc-bios/README b/qemu-0.15.x/pc-bios/README
new file mode 100644
index 0000000..f74b246
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/README
@@ -0,0 +1,34 @@
+- SeaBIOS (bios.bin) is the successor of pc bios.
+  See http://www.seabios.org/ for more information.
+
+- The VGA BIOS and the Cirrus VGA BIOS come from the LGPL VGA bios
+  project (http://www.nongnu.org/vgabios/).
+
+- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
+  available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
+
+- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
+  firmware implementation. The goal is to implement a 100% IEEE
+  1275-1994 (referred to as Open Firmware) compliant firmware.
+  The included image for PowerPC (for 32 and 64 bit PPC CPUs)
+  is built from OpenBIOS SVN revision 1044 and Sparc32 and Sparc64
+  images are built from OpenBIOS SVN revision 1045.
+
+- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
+  implementation for certain IBM POWER hardware.  The sources are at
+  https://github.com/dgibson/SLOF, and the image currently in qemu is
+  built from git tag qemu-slof-20110323.
+
+- The PXE roms come from the iPXE project. Built with BANNER_TIME 0.
+  Sources available at http://ipxe.org.  Vendor:Device ID -> ROM mapping:
+
+	8086:100e -> pxe-e1000.rom
+	8086:1209 -> pxe-eepro100.rom
+	1050:0940 -> pxe-ne2k_pci.rom
+	1022:2000 -> pxe-pcnet.rom
+	10ec:8139 -> pxe-rtl8139.rom
+	1af4:1000 -> pxe-virtio.rom
+
+- The S390 zipl loader is an addition to the official IBM s390-tools
+  package. That fork is maintained in its own git repository at:
+  git://repo.or.cz/s390-tools.git
diff --git a/qemu-0.15.x/pc-bios/bamboo.dtb b/qemu-0.15.x/pc-bios/bamboo.dtb
new file mode 100644
index 0000000..c78e254
Binary files /dev/null and b/qemu-0.15.x/pc-bios/bamboo.dtb differ
diff --git a/qemu-0.15.x/pc-bios/bamboo.dts b/qemu-0.15.x/pc-bios/bamboo.dts
new file mode 100644
index 0000000..655442c
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/bamboo.dts
@@ -0,0 +1,234 @@
+/*
+ * Device Tree Source for AMCC Bamboo
+ *
+ * Copyright (c) 2006, 2007 IBM Corp.
+ * Josh Boyer <jwboyer at linux.vnet.ibm.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	model = "amcc,bamboo";
+	compatible = "amcc,bamboo";
+	dcr-parent = <&/cpus/cpu at 0>;
+
+	aliases {
+		serial0 = &UART0;
+		serial1 = &UART1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			model = "PowerPC,440EP";
+			reg = <0>;
+			clock-frequency = <1fca0550>;
+			timebase-frequency = <017d7840>;
+			i-cache-line-size = <20>;
+			d-cache-line-size = <20>;
+			i-cache-size = <8000>;
+			d-cache-size = <8000>;
+			dcr-controller;
+			dcr-access-method = "native";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0 9000000>;
+	};
+
+	UIC0: interrupt-controller0 {
+		compatible = "ibm,uic-440ep","ibm,uic";
+		interrupt-controller;
+		cell-index = <0>;
+		dcr-reg = <0c0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+	};
+/*
+	UIC1: interrupt-controller1 {
+		compatible = "ibm,uic-440ep","ibm,uic";
+		interrupt-controller;
+		cell-index = <1>;
+		dcr-reg = <0d0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <1e 4 1f 4>;
+		interrupt-parent = <&UIC0>;
+	};
+*/
+
+	SDR0: sdr {
+		compatible = "ibm,sdr-440ep";
+		dcr-reg = <00e 002>;
+	};
+
+	CPR0: cpr {
+		compatible = "ibm,cpr-440ep";
+		dcr-reg = <00c 002>;
+	};
+
+	plb {
+		compatible = "ibm,plb-440ep", "ibm,plb-440gp", "ibm,plb4";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges;
+		clock-frequency = <07f28154>;
+
+		SDRAM0: sdram {
+			compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
+			dcr-reg = <010 2>;
+		};
+
+		DMA0: dma {
+			compatible = "ibm,dma-440ep", "ibm,dma-440gp";
+			dcr-reg = <100 027>;
+		};
+
+		POB0: opb {
+			compatible = "ibm,opb-440ep", "ibm,opb-440gp", "ibm,opb";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			/* Bamboo is oddball in the 44x world and doesn't use the ERPN
+			 * bits.
+			 */
+			ranges = <00000000 0 00000000 80000000
+			          80000000 0 80000000 80000000>;
+			/* interrupt-parent = <&UIC1>; */
+			interrupts = <7 4>;
+			clock-frequency = <03f940aa>;
+
+			EBC0: ebc {
+				compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
+				dcr-reg = <012 2>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				clock-frequency = <03f940aa>;
+				interrupts = <5 1>;
+			/* interrupt-parent = <&UIC1>; */
+			};
+
+			UART0: serial at ef600300 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <ef600300 8>;
+				virtual-reg = <ef600300>;
+				clock-frequency = <00a8c000>;
+				current-speed = <1c200>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0 4>;
+			};
+
+			UART1: serial at ef600400 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <ef600400 8>;
+				virtual-reg = <ef600400>;
+				clock-frequency = <00a8c000>;
+				current-speed = <0>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <1 4>;
+			};
+/*
+			UART2: serial at ef600500 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <ef600500 8>;
+				virtual-reg = <ef600500>;
+				clock-frequency = <0>;
+				current-speed = <0>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <3 4>;
+			};
+
+			UART3: serial at ef600600 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <ef600600 8>;
+				virtual-reg = <ef600600>;
+				clock-frequency = <0>;
+				current-speed = <0>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <4 4>;
+			};
+
+*/
+			IIC0: i2c at ef600700 {
+				device_type = "i2c";
+				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
+				reg = <ef600700 14>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <2 4>;
+			};
+
+			IIC1: i2c at ef600800 {
+				device_type = "i2c";
+				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
+				reg = <ef600800 14>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <7 4>;
+			};
+
+			ZMII0: emac-zmii at ef600d00 {
+				device_type = "zmii-interface";
+				compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
+				reg = <ef600d00 c>;
+			};
+
+		};
+
+		PCI0: pci at ec000000 {
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
+			primary;
+			reg = <0 eec00000 8     /* Config space access */
+			       0 eed00000 4     /* IACK */
+			       0 eed00000 4     /* Special cycle */
+			       0 ef400000 40>;  /* Internal registers */
+
+			/* Outbound ranges, one memory and one IO,
+			 * later cannot be changed. Chip supports a second
+			 * IO range but we don't use it for now
+			 */
+			ranges = <02000000 0 a0000000 0 a0000000 0 20000000
+				  01000000 0 00000000 0 e8000000 0 00010000>;
+
+			/* Inbound 2GB range starting at 0 */
+			dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+			/* Bamboo has all 4 IRQ pins tied together per slot */
+			interrupt-map-mask = <f800 0 0 0>;
+			interrupt-map = <
+				/* IDSEL 1 */
+				0800 0 0 0 &UIC0 1c 8
+
+				/* IDSEL 2 */
+				1000 0 0 0 &UIC0 1b 8
+
+				/* IDSEL 3 */
+				1800 0 0 0 &UIC0 1a 8
+
+				/* IDSEL 4 */
+				2000 0 0 0 &UIC0 19 8
+			>;
+		};
+
+	};
+
+	chosen {
+		linux,stdout-path = "/plb/opb/serial at ef600300";
+	};
+};
diff --git a/qemu-0.15.x/pc-bios/bios.bin b/qemu-0.15.x/pc-bios/bios.bin
new file mode 100644
index 0000000..bdb4831
Binary files /dev/null and b/qemu-0.15.x/pc-bios/bios.bin differ
diff --git a/qemu-0.15.x/pc-bios/keymaps/ar b/qemu-0.15.x/pc-bios/keymaps/ar
new file mode 100644
index 0000000..c430c03
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/ar
@@ -0,0 +1,98 @@
+# generated from XKB map ar
+include common
+map 0x401
+exclam 0x02 shift
+at 0x03 shift
+numbersign 0x04 shift
+dollar 0x05 shift
+percent 0x06 shift
+asciicircum 0x07 shift
+ampersand 0x08 shift
+asterisk 0x09 shift
+parenleft 0x0a shift
+parenright 0x0b shift
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+Arabic_dad 0x10 altgr
+Arabic_fatha 0x10 shift altgr
+Arabic_sad 0x11 altgr
+Arabic_fathatan 0x11 shift altgr
+Arabic_theh 0x12 altgr
+Arabic_damma 0x12 shift altgr
+Arabic_qaf 0x13 altgr
+Arabic_dammatan 0x13 shift altgr
+Arabic_feh 0x14 altgr
+UFEF9 0x14 shift altgr
+Arabic_ghain 0x15 altgr
+Arabic_hamzaunderalef 0x15 shift altgr
+Arabic_ain 0x16 altgr
+grave 0x16 shift altgr
+Arabic_ha 0x17 altgr
+division 0x17 shift altgr
+Arabic_khah 0x18 altgr
+multiply 0x18 shift altgr
+Arabic_hah 0x19 altgr
+Arabic_semicolon 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+Arabic_jeem 0x1a altgr
+bracketright 0x1b
+braceright 0x1b shift
+Arabic_dal 0x1b altgr
+Arabic_sheen 0x1e altgr
+backslash 0x1e shift altgr
+Arabic_seen 0x1f altgr
+Arabic_yeh 0x20 altgr
+bracketleft 0x20 shift altgr
+Arabic_beh 0x21 altgr
+bracketright 0x21 shift altgr
+Arabic_lam 0x22 altgr
+UFEF7 0x22 shift altgr
+Arabic_alef 0x23 altgr
+Arabic_hamzaonalef 0x23 shift altgr
+Arabic_teh 0x24 altgr
+Arabic_tatweel 0x24 shift altgr
+Arabic_noon 0x25 altgr
+Arabic_comma 0x25 shift altgr
+Arabic_meem 0x26 altgr
+slash 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+Arabic_kaf 0x27 altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+Arabic_tah 0x28 altgr
+grave 0x29
+asciitilde 0x29 shift
+Arabic_thal 0x29 altgr
+Arabic_shadda 0x29 shift altgr
+backslash 0x2b
+bar 0x2b shift
+less 0x2b altgr
+greater 0x2b shift altgr
+Arabic_hamzaonyeh 0x2c altgr
+asciitilde 0x2c shift altgr
+Arabic_hamza 0x2d altgr
+Arabic_sukun 0x2d shift altgr
+Arabic_hamzaonwaw 0x2e altgr
+Arabic_kasra 0x2e shift altgr
+Arabic_ra 0x2f altgr
+Arabic_kasratan 0x2f shift altgr
+UFEFB 0x30 altgr
+UFEF5 0x30 shift altgr
+Arabic_alefmaksura 0x31 altgr
+Arabic_maddaonalef 0x31 shift altgr
+Arabic_tehmarbuta 0x32 altgr
+apostrophe 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+Arabic_waw 0x33 altgr
+period 0x34
+greater 0x34 shift
+Arabic_zain 0x34 altgr
+slash 0x35
+question 0x35 shift
+Arabic_zah 0x35 altgr
+Arabic_question_mark 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/bepo b/qemu-0.15.x/pc-bios/keymaps/bepo
new file mode 100644
index 0000000..d40041a
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/bepo
@@ -0,0 +1,333 @@
+include common
+
+# Bépo : Improved ergonomic french keymap using Dvorak method.
+# Built by community on 'Dvorak Fr / Bépo' :
+# see http://www.clavier-dvorak.org/wiki/ to join and help.
+#
+# Bépo layout (1.0rc2 version) for a pc105 keyboard (french) :
+# ┌────┐
+# │ S A│   S = Shift,  A = AltGr + Shift
+# │ s a│   s = normal, a = AltGr
+# └────┘
+#
+# ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┲━━━━━━━━━┓
+# │ # ¶ │ 1 „ │ 2 “ │ 3 ” │ 4 ≤ │ 5 ≥ │ 6   │ 7 ¬ │ 8 ¼ │ 9 ½ │ 0 ¾ │ ° ′ │ ` ″ ┃ ⌫ Retour┃
+# │ $ – │ " — │ « < │ » > │ ( [ │ ) ] │ @ ^ │ + ± │ - − │ / ÷ │ * × │ = ≠ │ % ‰ ┃  arrière┃
+# ┢━━━━━┷━┱───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┺━┳━━━━━━━┫
+# ┃       ┃ B ¦ │ É ˝ │ P § │ O Œ │ È ` │ !   │ V   │ D Ð │ L   │ J IJ │ Z Ə │ W   ┃Entrée ┃
+# ┃Tab ↹  ┃ b | │ é ˊ │ p & │ o œ │ è ` │ ˆ ¡ │ v ˇ │ d ð │ l / │ j ij │ z ə │ w ̆ ┃   ⏎   ┃
+# ┣━━━━━━━┻┱────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┺┓      ┃
+# ┃        ┃ A Æ │ U Ù │ I ˙ │ E ¤ │ ; ̛ │ C ſ │ T Þ │ S ẞ │ R ™ │ N   │ M º │ Ç , ┃      ┃
+# ┃Maj ⇬   ┃ a æ │ u ù │ i ̈ │ e € │ , ’ │ c © │ t þ │ s ß │ r ® │ n ˜ │ m ¯ │ ç ¸ ┃      ┃
+# ┣━━━━━━━┳┹────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┲┷━━━━━┻━━━━━━┫
+# ┃       ┃ Ê   │ À   │ Y ‘ │ X ’ │ : · │ K   │ ? ̉ │ Q ̣ │ G   │ H ‡ │ F ª ┃             ┃
+# ┃Shift ⇧┃ ê / │ à \ │ y { │ x } │ . … │ k ~ │ ' ¿ │ q ˚ │ g µ │ h † │ f ˛ ┃Shift ⇧      ┃
+# ┣━━━━━━━╋━━━━━┷━┳━━━┷━━━┱─┴─────┴─────┴─────┴─────┴─────┴───┲━┷━━━━━╈━━━━━┻━┳━━━━━━━┳━━━┛
+# ┃       ┃       ┃       ┃ Espace inséc.   Espace inséc. fin ┃       ┃       ┃       ┃
+# ┃Ctrl   ┃Meta   ┃Alt    ┃ ␣ (Espace)      _               ␣ ┃AltGr ⇮┃Menu   ┃Ctrl   ┃
+# ┗━━━━━━━┻━━━━━━━┻━━━━━━━┹───────────────────────────────────┺━━━━━━━┻━━━━━━━┻━━━━━━━┛
+
+
+# First row
+## keycode  41 = dollar numbersign       U+2013  U+00b6
+dollar        0x29
+numbersign    0x29  shift
+U2013         0x29        altgr
+U00b6         0x29  shift altgr
+
+## keycode   2 = +quotedbl +one          U+2014  U+201e
+quotedbl      0x2
+one           0x2  shift
+U2014         0x2        altgr
+U201e         0x2  shift altgr
+
+## keycode   3 = +guillemotleft  +two     less    U+201c
+guillemotleft  0x3
+two           0x3  shift
+less          0x3        altgr
+U201c         0x3  shift altgr
+
+## keycode   4 = +guillemotright +three  greater U+201d
+guillemotright  0x4
+three         0x4  shift
+greater       0x4        altgr
+U201d         0x4  shift altgr
+
+## keycode   5 = +parenleft +four        bracketleft  U+2264
+parenleft     0x5
+four          0x5  shift
+bracketleft   0x5        altgr
+U2264         0x5  shift altgr
+
+## keycode   6 = +parenright +five       bracketright  U+2265
+parenright    0x6
+five          0x6  shift
+bracketright  0x6        altgr
+U2265         0x6  shift altgr
+
+## keycode   7 = +at       +six          asciicircum
+at            0x7
+six           0x7  shift
+asciicircum   0x7        altgr
+
+## keycode   8 = +plus     +seven        U+00b1  U+00ac
+plus          0x8
+seven         0x8  shift
+U00b1         0x8        altgr
+U00ac         0x8  shift altgr
+
+## keycode   9 = +minus    +eight        U+2212  U+00bc
+minus         0x9
+eight         0x9  shift
+U2212         0x9        altgr
+U00bc         0x9  shift altgr
+
+## keycode  10 = +slash    +nine         U+00f7  U+00bd
+slash         0xa
+nine          0xa  shift
+U00f7         0xa        altgr
+U00bd         0xa  shift altgr
+
+## keycode  11 = +asterisk +zero         U+00d7  U+00be
+asterisk      0xb
+zero          0xb  shift
+U00d7         0xb        altgr
+U00be         0xb  shift altgr
+
+## keycode  12 = equal     U+00b0        U+2260  U+2032
+equal         0xc
+U00b0         0xc  shift
+U2260         0xc        altgr
+U2032         0xc  shift altgr
+
+## keycode  13 = percent   grave         U+2030  U+2033
+percent       0xd
+grave         0xd  shift
+U2030         0xd        altgr
+U2033         0xd  shift altgr
+
+
+# Second row
+
+# simplified letter definitions notation :
+## keycode 16 = b
+b             0x10  addupper
+## keycode 18 = p
+p             0x12  addupper
+## keycode 19 = o
+o             0x13  addupper
+## keycode 22 = v
+v             0x16  addupper
+## keycode 23 = d
+d             0x17  addupper
+## keycode 24 = l
+l             0x18  addupper
+## keycode 25 = j
+j             0x19  addupper
+## keycode 26 = z
+z             0x1a  addupper
+## keycode 27 = w
+w             0x1b  addupper
+
+# then, add specific definitions
+##                    AltGr keycode  16 = bar
+bar           0x10        altgr
+##              Shift AltGr keycode  16 = brokenbar
+brokenbar     0x10  shift altgr
+
+## keycode 17 = +eacute +Eacute dead_acute
+eacute        0x11
+Eacute        0x11  shift
+dead_acute    0x11        altgr
+
+##                    AltGr keycode  18 = ampersand
+ampersand     0x12        altgr
+##              Shift AltGr keycode  18 = U+00a7
+U00a7         0x12  shift altgr
+
+##                    AltGr keycode  19 = +U+0153
+U+0153        0x13        altgr
+##              Shift AltGr keycode  19 = +U+0152
+U+0152        0x13  shift altgr
+
+## keycode 20 = +egrave +Egrave dead_grave grave # no Meta !
+egrave        0x14
+Egrave        0x14  shift
+dead_grave    0x14        altgr
+
+## keycode 21 = dead_circumflex exclam exclamdown
+dead_circumflex  0x15
+exclam        0x15  shift
+exclamdown    0x15        altgr
+
+##                    AltGr keycode  22 = dead_caron
+dead_caron    0x16        altgr
+
+##                    AltGr keycode  23 = eth
+eth           0x17        altgr
+##              Shift AltGr keycode  23 = ETH
+ETH           0x17  shift altgr
+
+##                    AltGr keycode  25 = +U+0133
+U+0133        0x19        altgr
+##              Shift AltGr keycode  25 = +U+0132
+U+0132        0x19  shift altgr
+
+##                    AltGr keycode  26 = +U+0259
+U+0259        0x1a        altgr
+##              Shift AltGr keycode  26 = +U+018f
+U+018f        0x1a  shift altgr
+
+
+
+# Third row
+
+# simplified letter definitions notation :
+## keycode 30 = a
+a             0x1e  addupper
+## keycode 31 = u
+u             0x1f  addupper
+## keycode 32 = i
+i             0x20  addupper
+## keycode 33 = e
+e             0x21  addupper
+## keycode 35 = c
+c             0x23  addupper
+## keycode 36 = t
+t             0x24  addupper
+## keycode 37 = s
+s             0x25  addupper
+## keycode 38 = r
+r             0x26  addupper
+## keycode 39 = n
+n             0x27  addupper
+## keycode 40 = m
+m             0x28  addupper
+
+# then, add specific definitions
+##                    AltGr keycode  30 = +ae
+ae            0x1e        altgr
+##              Shift AltGr keycode  30 = +AE
+AE            0x1e  shift altgr
+
+##                    AltGr keycode  31 = +ugrave
+ugrave        0x1f        altgr
+##              Shift AltGr keycode  31 = +Ugrave
+Ugrave        0x1f  shift altgr
+
+##                    AltGr keycode  32 = dead_diaeresis
+dead_diaeresis  0x20        altgr
+
+
+##                    AltGr keycode  33 = U+20ac
+U20ac         0x21        altgr
+
+## keycode 34 = comma semicolon U+2019 +U+031b
+comma         0x22
+semicolon     0x22  shift
+U2019         0x22        altgr
+U+031b        0x22  shift altgr
+
+##                    AltGr keycode  35 = copyright
+copyright     0x23        altgr
+##              Shift AltGr keycode  35 = U+017f
+U017f         0x23  shift altgr
+
+##                    AltGr keycode  36 = +thorn
+thorn         0x24        altgr
+##              Shift AltGr keycode  36 = +THORN
+THORN         0x24  shift altgr
+
+##                    AltGr keycode  37 = +ssharp
+ssharp        0x25        altgr
+##              Shift AltGr keycode  37 = U+1e9e
+U1e9e         0x25  shift altgr
+
+##                    AltGr keycode  38 = registered
+registered    0x26        altgr
+##              Shift AltGr keycode  38 = U+2122
+U2122         0x26  shift altgr
+
+##                    AltGr keycode  39 = dead_tilde
+dead_tilde    0x27        altgr
+
+##              Shift AltGr keycode  40 = masculine
+masculine     0x28  shift altgr
+
+## keycode 43 = +ccedilla +Ccedilla dead_cedilla
+ccedilla      0x2b
+Ccedilla      0x2b  shift
+dead_cedilla  0x2b        altgr
+
+
+# Fourth row
+
+# simplified letter definitions notation :
+## keycode 45 = y
+y             0x2d  addupper
+## keycode 46 = x
+x             0x2e  addupper
+## keycode 48 = k
+k             0x30  addupper
+## keycode 50 = q
+q             0x32  addupper
+## keycode 51 = g
+g             0x33  addupper
+## keycode 52 = h
+h             0x34  addupper
+## keycode 53 = f
+f             0x35  addupper
+
+# then, add specific definitions
+## keycode 86 = +ecircumflex +Ecircumflex slash slash
+ecircumflex   0x56
+Ecircumflex   0x56  shift
+
+## keycode 44 = +agrave +Agrave backslash
+agrave        0x2c
+Agrave        0x2c  shift
+backslash     0x2c        altgr
+
+##                    AltGr keycode  45 = braceleft
+braceleft     0x2d        altgr
+##              Shift AltGr keycode  45 = U+2018
+U2018         0x2d  shift altgr
+
+##                    AltGr keycode  46 = braceright
+braceright    0x2e        altgr
+
+## keycode 47 = period colon U+2026 periodcentered
+period        0x2f
+colon         0x2f  shift
+U2026         0x2f        altgr
+periodcentered  0x2f  shift altgr
+
+##                    AltGr keycode  48 = asciitilde
+asciitilde    0x30        altgr
+##              Shift AltGr keycode  48 = U+2328
+U2328         0x30  shift altgr
+
+## keycode 49 = apostrophe question questiondown +U+0309
+apostrophe    0x31
+question      0x31  shift
+questiondown  0x31        altgr
+U+0309        0x31  shift altgr
+
+##                    AltGr keycode  51 = mu
+mu            0x33        altgr
+
+##                    AltGr keycode  52 = U+2020
+U2020         0x34        altgr
+##              Shift AltGr keycode  52 = U+2021
+U2021         0x34  shift altgr
+
+##              Shift AltGr keycode  53 = ordfeminine
+ordfeminine   0x35  shift altgr
+
+
+
+## keycode 57 = space nobreakspace underscore U+202f
+space         0x39
+nobreakspace  0x39  shift
+underscore    0x39        altgr
+U202f         0x39  shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/common b/qemu-0.15.x/pc-bios/keymaps/common
new file mode 100644
index 0000000..adc56c7
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/common
@@ -0,0 +1,157 @@
+include modifiers
+
+#
+# Top row
+#
+1 0x2
+2 0x3
+3 0x4
+4 0x5
+5 0x6
+6 0x7
+7 0x8
+8 0x9
+9 0xa
+0 0xb
+BackSpace 0xe
+
+#
+# QWERTY first row
+#
+Tab 0xf localstate
+ISO_Left_Tab 0xf shift
+q 0x10 addupper
+w 0x11 addupper
+e 0x12 addupper
+r 0x13 addupper
+t 0x14 addupper
+y 0x15 addupper
+u 0x16 addupper
+i 0x17 addupper
+o 0x18 addupper
+p 0x19 addupper
+
+#
+# QWERTY second row
+#
+a 0x1e addupper
+s 0x1f addupper
+d 0x20 addupper
+f 0x21 addupper
+g 0x22 addupper
+h 0x23 addupper
+j 0x24 addupper
+k 0x25 addupper
+l 0x26 addupper
+Return 0x1c localstate
+
+#
+# QWERTY third row
+#
+z 0x2c addupper
+x 0x2d addupper
+c 0x2e addupper
+v 0x2f addupper
+b 0x30 addupper
+n 0x31 addupper
+m 0x32 addupper
+
+space 0x39 localstate
+
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+brokenbar 0x56 shift altgr
+
+#
+# Esc and Function keys
+#
+Escape 0x1 localstate
+F1 0x3b localstate
+F2 0x3c localstate
+F3 0x3d localstate
+F4 0x3e localstate
+F5 0x3f localstate
+F6 0x40 localstate
+F7 0x41 localstate
+F8 0x42 localstate
+F9 0x43 localstate
+F10 0x44 localstate
+F11 0x57 localstate
+F12 0x58 localstate
+
+# Printscreen, Scrollock and Pause
+# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
+# but (0xe0, 0x37) seems to work.
+Print 0xb7 localstate
+Sys_Req 0xb7 localstate
+Execute 0xb7 localstate
+Scroll_Lock 0x46
+
+#
+# Insert - PgDown
+#
+Insert 0xd2 localstate
+Delete 0xd3 localstate
+Home 0xc7 localstate
+End 0xcf localstate
+Page_Up 0xc9 localstate
+Page_Down 0xd1 localstate
+
+#
+# Arrow keys
+#
+Left 0xcb localstate
+Up 0xc8 localstate
+Down 0xd0 localstate
+Right 0xcd localstate
+
+#
+# Numpad
+#
+Num_Lock 0x45
+KP_Divide 0xb5
+KP_Multiply 0x37
+KP_Subtract 0x4a
+KP_Add 0x4e
+KP_Enter 0x9c
+
+KP_Decimal 0x53 numlock
+KP_Separator 0x53 numlock
+KP_Delete 0x53
+
+KP_0 0x52 numlock
+KP_Insert 0x52
+
+KP_1 0x4f numlock
+KP_End 0x4f
+
+KP_2 0x50 numlock
+KP_Down 0x50
+
+KP_3 0x51 numlock
+KP_Next 0x51
+
+KP_4 0x4b numlock
+KP_Left 0x4b
+
+KP_5 0x4c numlock
+KP_Begin 0x4c
+
+KP_6 0x4d numlock
+KP_Right 0x4d
+
+KP_7 0x47 numlock
+KP_Home 0x47
+
+KP_8 0x48 numlock
+KP_Up 0x48
+
+KP_9 0x49 numlock
+KP_Prior 0x49
+
+Caps_Lock 0x3a
+#
+# Inhibited keys
+#
+Multi_key 0x0 inhibit
diff --git a/qemu-0.15.x/pc-bios/keymaps/da b/qemu-0.15.x/pc-bios/keymaps/da
new file mode 100644
index 0000000..3884dcf
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/da
@@ -0,0 +1,120 @@
+# generated from XKB map dk
+include common
+map 0x406
+exclam 0x02 shift
+exclamdown 0x02 altgr
+onesuperior 0x02 shift altgr
+quotedbl 0x03 shift
+at 0x03 altgr
+twosuperior 0x03 shift altgr
+numbersign 0x04 shift
+sterling 0x04 altgr
+threesuperior 0x04 shift altgr
+currency 0x05 shift
+dollar 0x05 altgr
+onequarter 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+cent 0x06 shift altgr
+ampersand 0x07 shift
+yen 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+division 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+guillemotleft 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+guillemotright 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+plus 0x0c
+question 0x0c shift
+plusminus 0x0c altgr
+questiondown 0x0c shift altgr
+dead_acute 0x0d
+dead_grave 0x0d shift
+bar 0x0d altgr
+brokenbar 0x0d shift altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+registered 0x13 altgr
+thorn 0x14 altgr
+THORN 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oe 0x18 altgr
+OE 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+aring 0x1a
+Aring 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+dead_diaeresis 0x1b
+dead_circumflex 0x1b shift
+dead_tilde 0x1b altgr
+dead_caron 0x1b shift altgr
+ordfeminine 0x1e altgr
+masculine 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+ae 0x27
+AE 0x27 shift
+oslash 0x28
+Ooblique 0x28 shift
+dead_caron 0x28 shift altgr
+onehalf 0x29
+section 0x29 shift
+threequarters 0x29 altgr
+paragraph 0x29 shift altgr
+apostrophe 0x2b
+asterisk 0x2b shift
+dead_doubleacute 0x2b altgr
+multiply 0x2b shift altgr
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+copyright 0x2e altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+dead_cedilla 0x33 altgr
+dead_ogonek 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+dead_abovedot 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+hyphen 0x35 altgr
+macron 0x35 shift altgr
+nobreakspace 0x39 altgr
+less 0x56
+greater 0x56 shift
+backslash 0x56 altgr
+notsign 0x56 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/de b/qemu-0.15.x/pc-bios/keymaps/de
new file mode 100644
index 0000000..ed929c7
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/de
@@ -0,0 +1,114 @@
+# generated from XKB map de
+include common
+map 0x407
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+section 0x04 shift
+threesuperior 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+currency 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+ssharp 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+acute 0x0d
+dead_acute 0x0d
+grave 0x0d shift
+dead_grave 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+z 0x15 addupper
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+udiaeresis 0x1a
+Udiaeresis 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+plus 0x1b
+asterisk 0x1b shift
+asciitilde 0x1b altgr
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+odiaeresis 0x27
+Odiaeresis 0x27 shift
+dead_doubleacute 0x27 altgr
+adiaeresis 0x28
+Adiaeresis 0x28 shift
+dead_caron 0x28 shift altgr
+asciicircum 0x29
+dead_circumflex 0x29
+degree 0x29 shift
+notsign 0x29 altgr
+numbersign 0x2b
+apostrophe 0x2b shift
+dead_breve 0x2b shift altgr
+y 0x2c addupper
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/de-ch b/qemu-0.15.x/pc-bios/keymaps/de-ch
new file mode 100644
index 0000000..852f8b8
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/de-ch
@@ -0,0 +1,169 @@
+# rdesktop Swiss-German (de-ch) keymap file
+# 2003-06-03 by noldi at tristar.ch
+#
+include common
+map 0x00000807
+#
+# Scan Code 1
+section 0x29
+degree 0x29 shift
+notsign 0x29 altgr inhibit
+#
+# Scan Code 2
+plus 0x2 shift
+brokenbar 0x02 altgr
+#
+# Scan Code 3
+quotedbl 0x03 shift
+at 0x03 altgr
+#
+# Scan Code 4
+asterisk 0x04 shift
+numbersign 0x04 altgr
+#
+# Scan Code 5
+ccedilla 0x05 shift
+onequarter 0x05 altgr inhibit
+#
+# Scan Code 6
+percent 0x06 shift
+onehalf 0x06 altgr inhibit
+#
+# Scan Code 7
+ampersand 0x07 shift
+notsign 0x07 altgr
+#
+# Scan Code 8
+slash 0x08 shift
+bar 0x08 altgr
+#
+# Scan Code 9
+parenleft 0x09 shift
+cent 0x09 altgr
+#
+# Scan Code 10
+parenright 0x0a shift
+#
+# Scan Code 11
+equal 0x0b shift
+braceright 0x0b altgr inhibit
+#
+# Scan Code 12
+apostrophe 0x0c
+question 0x0c shift
+dead_acute 0x0c altgr
+#
+# Scan Code 13
+dead_circumflex 0x0d
+dead_grave 0x0d shift
+dead_tilde 0x0d altgr
+#
+# Scan Code 19
+EuroSign 0x12 altgr
+#
+# Scan Code 22
+z 0x15 addupper
+#
+# Scan Code 27
+udiaeresis 0x1a
+egrave 0x1a shift
+bracketleft 0x1a altgr
+#
+# Scan Code 28
+dead_diaeresis 0x1b
+exclam 0x1b shift
+bracketright 0x1b altgr
+#
+# Scan Code 40
+odiaeresis 0x27
+eacute 0x27 shift
+#
+# Scan Code 41
+adiaeresis 0x28
+agrave 0x28 shift
+braceleft 0x28 altgr
+#
+# Scan Code 42 (only on international keyboards)
+dollar 0x2b
+sterling 0x2b shift
+braceright 0x2b altgr
+#
+# Scan Code 45 (only on international keyboards)
+backslash 0x56 altgr
+#
+# Scan Code 46
+y 0x2c addupper
+#
+# Scan Code 53
+comma 0x33
+semicolon 0x33 shift
+#
+# Scan Code 54
+period 0x34
+colon 0x34 shift
+#
+# Scan Code 55
+minus 0x35
+underscore 0x35 shift
+#
+# Suppress Windows unsupported AltGr keys
+#
+# Scan Code 17
+paragraph 0x10 altgr inhibit
+#
+# Scan Code 21
+tslash 0x14 altgr inhibit
+#
+# Scan Code 22
+leftarrow 0x15 altgr inhibit
+#
+# Scan Code 23
+downarrow 0x16 altgr inhibit
+#
+# Scan Code 24
+rightarrow 0x17 altgr inhibit
+#
+# Scan Code 25
+oslash 0x18 altgr inhibit
+#
+# Scan Code 26
+thorn 0x19 altgr inhibit
+#
+# Scan Code 31
+ae 0x1e altgr inhibit
+#
+# Scan Code 32
+ssharp 0x1f altgr inhibit
+#
+# Scan Code 33
+eth 0x20 altgr inhibit
+#
+# Scan Code 34
+dstroke 0x21 altgr inhibit
+#
+# Scan Code 35
+eng 0x22 altgr inhibit
+#
+# Scan Code 36
+hstroke 0x23 altgr inhibit
+#
+# Scan Code 38
+kra 0x25 altgr inhibit
+#
+# Scan Code 39
+lstroke 0x26 altgr inhibit
+#
+# Scan Code 46
+guillemotleft 0x2c altgr inhibit
+#
+# Scan Code 47
+guillemotright 0x2d altgr inhibit
+#
+# Scan Code 49
+leftdoublequotemark 0x2f altgr inhibit
+#
+# Scan Code 50
+rightdoublequotemark 0x30 altgr inhibit
+#
+# Scan Code 52
+mu 0x32 altgr inhibit
diff --git a/qemu-0.15.x/pc-bios/keymaps/en-gb b/qemu-0.15.x/pc-bios/keymaps/en-gb
new file mode 100644
index 0000000..b45f06c
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/en-gb
@@ -0,0 +1,119 @@
+# generated from XKB map gb
+include common
+map 0x809
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+sterling 0x04 shift
+threesuperior 0x04 altgr
+dollar 0x05 shift
+EuroSign 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+asciicircum 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+ampersand 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+asterisk 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenleft 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+parenright 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+minus 0x0c
+underscore 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+equal 0x0d
+plus 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+apostrophe 0x28
+at 0x28 shift
+dead_circumflex 0x28 altgr
+dead_caron 0x28 shift altgr
+grave 0x29
+notsign 0x29 shift
+bar 0x29 altgr
+numbersign 0x2b
+asciitilde 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+guillemotleft 0x2c altgr
+less 0x2c shift altgr
+guillemotright 0x2d altgr
+greater 0x2d shift altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
+backslash 0x56
+bar 0x56 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/en-us b/qemu-0.15.x/pc-bios/keymaps/en-us
new file mode 100644
index 0000000..f5784bb
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/en-us
@@ -0,0 +1,35 @@
+# generated from XKB map us
+include common
+map 0x409
+exclam 0x02 shift
+at 0x03 shift
+numbersign 0x04 shift
+dollar 0x05 shift
+percent 0x06 shift
+asciicircum 0x07 shift
+ampersand 0x08 shift
+asterisk 0x09 shift
+parenleft 0x0a shift
+parenright 0x0b shift
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+bracketleft 0x1a
+braceleft 0x1a shift
+bracketright 0x1b
+braceright 0x1b shift
+semicolon 0x27
+colon 0x27 shift
+apostrophe 0x28
+quotedbl 0x28 shift
+grave 0x29
+asciitilde 0x29 shift
+backslash 0x2b
+bar 0x2b shift
+comma 0x33
+less 0x33 shift
+period 0x34
+greater 0x34 shift
+slash 0x35
+question 0x35 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/es b/qemu-0.15.x/pc-bios/keymaps/es
new file mode 100644
index 0000000..0c29eec
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/es
@@ -0,0 +1,105 @@
+# generated from XKB map es
+include common
+map 0x40a
+exclam 0x02 shift
+bar 0x02 altgr
+quotedbl 0x03 shift
+at 0x03 altgr
+oneeighth 0x03 shift altgr
+periodcentered 0x04 shift
+numbersign 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+asciitilde 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+notsign 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+trademark 0x09 shift altgr
+parenright 0x0a shift
+plusminus 0x0a shift altgr
+equal 0x0b shift
+degree 0x0b shift altgr
+apostrophe 0x0c
+question 0x0c shift
+exclamdown 0x0d
+questiondown 0x0d shift
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+dead_grave 0x1a
+dead_circumflex 0x1a shift
+bracketleft 0x1a altgr
+dead_abovering 0x1a shift altgr
+plus 0x1b
+asterisk 0x1b shift
+bracketright 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+ntilde 0x27
+Ntilde 0x27 shift
+dead_doubleacute 0x27 shift altgr
+dead_acute 0x28
+dead_diaeresis 0x28 shift
+braceleft 0x28 altgr
+masculine 0x29
+ordfeminine 0x29 shift
+backslash 0x29 altgr
+ccedilla 0x2b
+Ccedilla 0x2b shift
+braceright 0x2b altgr
+dead_breve 0x2b shift altgr
+guillemotleft 0x2c altgr
+less 0x56
+greater 0x56 shift
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/et b/qemu-0.15.x/pc-bios/keymaps/et
new file mode 100644
index 0000000..85541a3
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/et
@@ -0,0 +1,85 @@
+map 0x00000425
+include common
+
+#
+# Top row
+#
+dead_caron 0x29
+dead_tilde 0x29 shift
+
+# 1
+exclam 0x2 shift
+
+# 2
+quotedbl 0x3 shift
+at 0x3 altgr
+
+# 3
+numbersign 0x4 shift
+sterling 0x4 altgr
+# 4
+currency 0x5 shift
+dollar 0x5 altgr
+# 5
+percent 0x6 shift
+# 6
+ampersand 0x7 shift
+# 7
+slash 0x8 shift
+braceleft 0x8 altgr
+# 8
+parenleft 0x9 shift
+bracketleft 0x9 altgr
+# 9
+parenright 0xa shift
+bracketright 0xa altgr
+# 0
+equal 0xb shift
+braceright 0xb altgr
+
+plus 0xc
+question 0xc shift
+backslash 0xc altgr
+
+acute 0xd
+dead_acute 0xd
+grave 0xd shift
+dead_grave 0xd shift
+
+#
+# QWERTY first row
+#
+EuroSign 0x12 altgr
+udiaeresis 0x1a
+Udiaeresis 0x1a shift
+otilde 0x1b
+Otilde 0x1b shift
+section 0x1b altgr
+
+#
+# QWERTY second row
+#
+scaron 0x1f altgr
+Scaron 0x1f altgr shift
+odiaeresis 0x27
+Odiaeresis 0x27 shift
+adiaeresis 0x28
+Adiaeresis 0x28 shift
+asciicircum 0x28 altgr
+apostrophe 0x2b
+asterisk 0x2b shift
+onehalf 0x2b altgr
+#
+# QWERTY third row
+#
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+zcaron 0x2c altgr
+Zcaron 0x2c altgr shift
+comma 0x33
+semicolon 0x33 shift
+period 0x34
+colon 0x34 shift
+minus 0x35
+underscore 0x35 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/fi b/qemu-0.15.x/pc-bios/keymaps/fi
new file mode 100644
index 0000000..2a4e0f0
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fi
@@ -0,0 +1,124 @@
+# generated from XKB map se_FI
+include common
+map 0x40b
+exclam 0x02 shift
+exclamdown 0x02 altgr
+onesuperior 0x02 shift altgr
+quotedbl 0x03 shift
+at 0x03 altgr
+twosuperior 0x03 shift altgr
+numbersign 0x04 shift
+sterling 0x04 altgr
+threesuperior 0x04 shift altgr
+currency 0x05 shift
+dollar 0x05 altgr
+onequarter 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+cent 0x06 shift altgr
+ampersand 0x07 shift
+yen 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+division 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+guillemotleft 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+guillemotright 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+plus 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+dead_acute 0x0d
+dead_grave 0x0d shift
+plusminus 0x0d altgr
+notsign 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+registered 0x13 altgr
+thorn 0x14 altgr
+THORN 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oe 0x18 altgr
+OE 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+aring 0x1a
+Aring 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+dead_diaeresis 0x1b
+dead_circumflex 0x1b shift
+dead_tilde 0x1b altgr
+dead_caron 0x1b shift altgr
+ordfeminine 0x1e altgr
+masculine 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+ampersand 0x25 shift altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+odiaeresis 0x27
+Odiaeresis 0x27 shift
+oslash 0x27 altgr
+Ooblique 0x27 shift altgr
+adiaeresis 0x28
+Adiaeresis 0x28 shift
+ae 0x28 altgr
+AE 0x28 shift altgr
+section 0x29
+onehalf 0x29 shift
+paragraph 0x29 altgr
+threequarters 0x29 shift altgr
+apostrophe 0x2b
+asterisk 0x2b shift
+acute 0x2b altgr
+multiply 0x2b shift altgr
+guillemotleft 0x2c altgr
+less 0x2c shift altgr
+guillemotright 0x2d altgr
+greater 0x2d shift altgr
+copyright 0x2e altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+apostrophe 0x30 shift altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+dead_cedilla 0x33 altgr
+dead_ogonek 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+dead_abovedot 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+hyphen 0x35 altgr
+macron 0x35 shift altgr
+nobreakspace 0x39 altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/fo b/qemu-0.15.x/pc-bios/keymaps/fo
new file mode 100644
index 0000000..c00d9d4
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fo
@@ -0,0 +1,76 @@
+map 0x438
+include common
+
+#
+# Top row
+#
+onehalf 0x29
+section 0x29 shift
+
+# 1
+exclam 0x2 shift
+
+# 2
+quotedbl 0x3 shift
+at 0x3 altgr
+
+# 3
+numbersign 0x4 shift
+sterling 0x4 altgr
+# 4
+currency 0x5 shift
+dollar 0x5 altgr
+# 5
+percent 0x6 shift
+# 6
+ampersand 0x7 shift
+# 7
+slash 0x8 shift
+braceleft 0x8 altgr
+# 8
+parenleft 0x9 shift
+bracketleft 0x9 altgr
+# 9
+parenright 0xa shift
+bracketright 0xa altgr
+# 0
+equal 0xb shift
+braceright 0xb altgr
+
+plus 0xc
+question 0xc shift
+plusminus 0xc altgr
+
+bar 0xd altgr
+dead_acute 0xd
+
+#
+# QWERTY first row
+#
+EuroSign 0x12 altgr
+aring 0x1a
+Aring 0x1a shift
+eth 0x1b addupper
+asciitilde 0x1b altgr
+
+#
+# QWERTY second row
+#
+ae 0x27 addupper
+oslash 0x28
+Ooblique 0x28 shift
+apostrophe 0x2b
+asterisk 0x2b shift
+
+#
+# QWERTY third row
+#
+less 0x56
+greater 0x56 shift
+backslash 0x56 altgr
+comma 0x33
+semicolon 0x33 shift
+period 0x34
+colon 0x34 shift
+minus 0x35
+underscore 0x35 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/fr b/qemu-0.15.x/pc-bios/keymaps/fr
new file mode 100644
index 0000000..ba5a176
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fr
@@ -0,0 +1,181 @@
+include common
+map 0x40c
+#
+# Top row
+#
+twosuperior 0x29
+notsign 0x29 altgr
+
+ampersand 0x02
+1 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+
+eacute 0x03
+2 0x03 shift
+asciitilde 0x03 altgr
+oneeighth 0x03 shift altgr
+
+quotedbl 0x04
+3 0x04 shift
+numbersign 0x04 altgr
+
+apostrophe 0x05
+4 0x05 shift
+braceleft 0x05 altgr
+
+parenleft 0x06
+5 0x06 shift
+bracketleft 0x06 altgr
+threeeighths 0x06 shift altgr
+
+minus 0x07
+6 0x07 shift
+bar 0x07 altgr
+fiveeighths 0x07 shift altgr
+
+egrave 0x08
+7 0x08 shift
+grave 0x08 altgr
+seveneighths 0x08 shift altgr
+
+underscore 0x09
+8 0x09 shift
+backslash 0x09 altgr
+trademark 0x09 shift altgr
+
+ccedilla 0x0a
+9 0x0a shift
+asciicircum 0x0a altgr
+plusminus 0x0a shift altgr
+
+agrave 0x0b
+0 0x0b shift
+at 0x0b altgr
+
+parenright 0x0c
+degree 0x0c shift
+bracketright 0x0c altgr
+questiondown 0x0c shift altgr
+
+equal 0x0d
+plus 0x0d shift
+braceright 0x0d altgr
+dead_ogonek 0x0d shift altgr
+
+#
+# AZERTY first row
+#
+
+a 0x10 addupper
+ae 0x10 altgr
+AE 0x10 shift altgr
+
+z 0x11 addupper
+guillemotleft 0x11 altgr
+
+EuroSign 0x12 altgr
+
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+
+dead_circumflex 0x1a
+dead_diaeresis 0x1a shift
+dead_abovering 0x1a shift altgr
+
+dollar 0x1b
+sterling 0x1b shift
+currency 0x1b altgr
+dead_macron 0x1b shift altgr
+
+#
+# AZERTY second row
+#
+q 0x1e addupper
+Greek_OMEGA 0x1e shift altgr
+
+ssharp 0x1f altgr
+
+eth 0x20 altgr
+ETH 0x20 shift altgr
+
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+
+eng 0x22 altgr
+ENG 0x22 shift altgr
+
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+
+kra 0x25 altgr
+
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+
+m 0x27 addupper
+masculine 0x27 shift altgr
+
+ugrave 0x28
+percent 0x28 shift
+dead_caron 0x28 shift altgr
+
+asterisk 0x2b
+mu 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+
+#
+# AZERTY third row
+#
+less 0x56
+greater 0x56 shift
+
+w 0x2c addupper
+
+guillemotright 0x2d altgr
+
+cent 0x2e altgr
+copyright 0x2e shift altgr
+
+leftdoublequotemark 0x2f altgr
+
+rightdoublequotemark 0x30 altgr
+
+comma 0x32
+question 0x32 shift
+dead_acute 0x32 altgr
+dead_doubleacute 0x32 shift altgr
+
+semicolon 0x33
+period 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+
+colon 0x34
+slash 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+
+exclam 0x35
+section 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/fr-be b/qemu-0.15.x/pc-bios/keymaps/fr-be
new file mode 100644
index 0000000..62f7128
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fr-be
@@ -0,0 +1,134 @@
+# generated from XKB map be
+include common
+map 0x80c
+ampersand 0x02
+1 0x02 shift
+bar 0x02 altgr
+exclamdown 0x02 shift altgr
+eacute 0x03
+2 0x03 shift
+at 0x03 altgr
+oneeighth 0x03 shift altgr
+quotedbl 0x04
+3 0x04 shift
+numbersign 0x04 altgr
+sterling 0x04 shift altgr
+apostrophe 0x05
+4 0x05 shift
+onequarter 0x05 altgr
+dollar 0x05 shift altgr
+parenleft 0x06
+5 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+section 0x07
+6 0x07 shift
+asciicircum 0x07 altgr
+fiveeighths 0x07 shift altgr
+egrave 0x08
+7 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+exclam 0x09
+8 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+ccedilla 0x0a
+9 0x0a shift
+braceleft 0x0a altgr
+plusminus 0x0a shift altgr
+agrave 0x0b
+0 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+parenright 0x0c
+degree 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+minus 0x0d
+underscore 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+a 0x10 addupper
+Greek_OMEGA 0x10 shift altgr
+z 0x11 addupper
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+dead_circumflex 0x1a
+dead_diaeresis 0x1a shift
+bracketleft 0x1a altgr
+dead_abovering 0x1a shift altgr
+dollar 0x1b
+asterisk 0x1b shift
+bracketright 0x1b altgr
+dead_macron 0x1b shift altgr
+q 0x1e addupper
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+m 0x27 addupper
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+ugrave 0x28
+percent 0x28 shift
+dead_acute 0x28 altgr
+dead_caron 0x28 shift altgr
+twosuperior 0x29
+threesuperior 0x29 shift
+notsign 0x29 altgr
+mu 0x2b
+sterling 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+w 0x2c addupper
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+comma 0x32
+question 0x32 shift
+dead_cedilla 0x32 altgr
+masculine 0x32 shift altgr
+semicolon 0x33
+period 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+colon 0x34
+slash 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+equal 0x35
+plus 0x35 shift
+dead_tilde 0x35 altgr
+dead_abovedot 0x35 shift altgr
+backslash 0x56 altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/fr-ca b/qemu-0.15.x/pc-bios/keymaps/fr-ca
new file mode 100644
index 0000000..b645208
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fr-ca
@@ -0,0 +1,50 @@
+# Canadian French
+# By Simon Germain
+include common
+map 0xc0c
+
+backslash 0x29 altgr
+plusminus 0x2 altgr
+at 0x3 altgr
+sterling 0x4 altgr
+cent 0x5 altgr
+currency 0x6 altgr
+notsign 0x7 altgr
+bar 0x29 shift
+twosuperior 0x9 altgr
+threesuperior 0xa altgr
+onequarter 0xb altgr
+onehalf 0xc altgr
+threequarters 0xd altgr
+section 0x18 altgr
+paragraph 0x19 altgr
+bracketleft 0x1a altgr
+bracketright 0x1b altgr
+asciitilde 0x27 altgr
+braceleft 0x28 altgr
+braceright 0x2b altgr
+less 0x2b
+greater 0x2b shift
+guillemotleft 0x56
+guillemotright 0x56 shift
+degree 0x56 altgr
+mu 0x32 altgr
+eacute 0x35
+dead_acute 0x35 altgr
+dead_grave 0x28
+dead_circumflex 0x1a
+dead_circumflex 0x1a shift
+dead_cedilla 0x1b
+dead_diaeresis 0x1b shift
+exclam 0x2 shift
+quotedbl 0x3 shift
+slash 0x4 shift
+dollar 0x5 shift
+percent 0x6 shift
+question 0x7 shift
+ampersand 0x8 shift
+asterisk 0x9 shift
+parenleft 0xa shift
+parenright 0xb shift
+underscore 0xc shift
+plus 0xd shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/fr-ch b/qemu-0.15.x/pc-bios/keymaps/fr-ch
new file mode 100644
index 0000000..4620d20
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/fr-ch
@@ -0,0 +1,114 @@
+# generated from XKB map fr_CH
+include common
+map 0x100c
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+section 0x04 shift
+threesuperior 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+currency 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+ssharp 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+acute 0x0d
+dead_acute 0x0d
+grave 0x0d shift
+dead_grave 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+z 0x15 addupper
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+udiaeresis 0x1a
+Udiaeresis 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+plus 0x1b
+asterisk 0x1b shift
+asciitilde 0x1b altgr
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+odiaeresis 0x27
+Odiaeresis 0x27 shift
+dead_doubleacute 0x27 altgr
+adiaeresis 0x28
+Adiaeresis 0x28 shift
+dead_caron 0x28 shift altgr
+asciicircum 0x29
+dead_circumflex 0x29
+degree 0x29 shift
+notsign 0x29 altgr
+numbersign 0x2b
+apostrophe 0x2b shift
+dead_breve 0x2b shift altgr
+y 0x2c addupper
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/hr b/qemu-0.15.x/pc-bios/keymaps/hr
new file mode 100644
index 0000000..613aa69
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/hr
@@ -0,0 +1,125 @@
+# generated from XKB map hr
+include common
+map 0x41a
+exclam 0x02 shift
+asciitilde 0x02 altgr
+dead_tilde 0x02 shift altgr
+quotedbl 0x03 shift
+dead_caron 0x03 altgr
+caron 0x03 shift altgr
+numbersign 0x04 shift
+asciicircum 0x04 altgr
+dead_circumflex 0x04 shift altgr
+dollar 0x05 shift
+dead_breve 0x05 altgr
+breve 0x05 shift altgr
+percent 0x06 shift
+degree 0x06 altgr
+dead_abovering 0x06 shift altgr
+ampersand 0x07 shift
+dead_ogonek 0x07 altgr
+ogonek 0x07 shift altgr
+slash 0x08 shift
+grave 0x08 altgr
+dead_grave 0x08 shift altgr
+parenleft 0x09 shift
+dead_abovedot 0x09 altgr
+abovedot 0x09 shift altgr
+parenright 0x0a shift
+dead_acute 0x0a altgr
+apostrophe 0x0a shift altgr
+equal 0x0b shift
+dead_doubleacute 0x0b altgr
+doubleacute 0x0b shift altgr
+apostrophe 0x0c
+question 0x0c shift
+dead_diaeresis 0x0c altgr
+diaeresis 0x0c shift altgr
+plus 0x0d
+asterisk 0x0d shift
+dead_cedilla 0x0d altgr
+cedilla 0x0d shift altgr
+backslash 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+bar 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+z 0x15 addupper
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+scaron 0x1a
+Scaron 0x1a shift
+division 0x1a altgr
+dead_abovering 0x1a shift altgr
+dstroke 0x1b
+Dstroke 0x1b shift
+multiply 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+bracketleft 0x21 altgr
+ordfeminine 0x21 shift altgr
+bracketright 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+lstroke 0x25 altgr
+ampersand 0x25 shift altgr
+Lstroke 0x26 altgr
+ccaron 0x27
+Ccaron 0x27 shift
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+cacute 0x28
+Cacute 0x28 shift
+ssharp 0x28 altgr
+dead_caron 0x28 shift altgr
+dead_cedilla 0x29
+dead_diaeresis 0x29 shift
+notsign 0x29 altgr
+zcaron 0x2b
+Zcaron 0x2b shift
+currency 0x2b altgr
+dead_breve 0x2b shift altgr
+y 0x2c addupper
+guillemotleft 0x2c altgr
+less 0x2c shift altgr
+guillemotright 0x2d altgr
+greater 0x2d shift altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+at 0x2f altgr
+grave 0x2f shift altgr
+braceleft 0x30 altgr
+apostrophe 0x30 shift altgr
+braceright 0x31 altgr
+section 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/hu b/qemu-0.15.x/pc-bios/keymaps/hu
new file mode 100644
index 0000000..8aba444
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/hu
@@ -0,0 +1,115 @@
+# Hungarian keyboard layout (QWERTZ)
+# Created by: The NeverGone <never at delfin.klte.hu>
+
+include common
+map 0x40e
+
+
+# AltGr keys:
+notsign 0x29 altgr
+asciitilde 0x02 altgr
+caron 0x03 altgr
+asciicircum 0x04 altgr
+breve 0x05 altgr
+degree 0x06 altgr
+ogonek 0x07 altgr
+grave 0x08 altgr
+abovedot 0x09 altgr
+acute 0x0a altgr
+doubleacute 0x0b altgr
+diaeresis 0x0c altgr
+cedilla 0x0d altgr
+backslash 0x10 altgr
+bar 0x11 altgr
+EuroSign 0x12 altgr
+Iacute 0x17 altgr
+division 0x1a altgr
+multiply 0x1b altgr
+dstroke 0x1f altgr
+Dstroke 0x20 altgr
+bracketleft 0x21 altgr
+bracketright 0x22 altgr
+iacute 0x24 altgr
+lstroke 0x25 altgr
+Lstroke 0x26 altgr
+dollar 0x27 altgr
+ssharp 0x28 altgr
+currency 0x2b altgr
+less 0x56 altgr
+greater 0x2c altgr
+numbersign 0x2d altgr
+ampersand 0x2e altgr
+at 0x2f altgr
+braceleft 0x30 altgr
+braceright 0x31 altgr
+semicolon 0x33 altgr
+asterisk 0x35 altgr
+
+
+# Shift keys:
+section 0x29 shift
+apostrophe 0x02 shift
+quotedbl 0x03 shift
+plus 0x04 shift
+exclam 0x05 shift
+percent 0x06 shift
+slash 0x07 shift
+equal 0x08 shift
+parenleft 0x09 shift
+parenright 0x0a shift
+Odiaeresis 0x0b shift
+Udiaeresis 0x0c shift
+Oacute 0x0d shift
+Z 0x15 shift
+Odoubleacute 0x1a shift
+Uacute 0x1b shift
+Eacute 0x27 shift
+Aacute 0x28 shift
+Udoubleacute 0x2b shift
+Y 0x2c shift
+question 0x33 shift
+colon 0x34 shift
+underscore 0x35 shift
+F13 0x3b shift
+F14 0x3c shift
+F15 0x3d shift
+F16 0x3e shift
+F17 0x3f shift
+F18 0x40 shift
+F19 0x41 shift
+F20 0x42 shift
+F21 0x43 shift
+F22 0x44 shift
+F23 0x57 shift
+F24 0x58 shift
+
+
+# Ctrl keys:
+F25 0x3b ctrl
+F26 0x3c ctrl
+F27 0x3d ctrl
+F28 0x3e ctrl
+F29 0x3f ctrl
+F30 0x40 ctrl
+F31 0x41 ctrl
+F32 0x42 ctrl
+F33 0x43 ctrl
+F34 0x44 ctrl
+F35 0x57 ctrl
+#NoSymbol 0x58 ctrl
+
+
+0 0x29
+odiaeresis 0x0b
+udiaeresis 0x0c
+oacute 0x0d
+z 0x15
+odoubleacute 0x1a
+uacute 0x1b
+eacute 0x27
+aacute 0x28
+udoubleacute 0x2b
+y 0x2c
+comma 0x33
+period 0x34
+minus 0x35
diff --git a/qemu-0.15.x/pc-bios/keymaps/is b/qemu-0.15.x/pc-bios/keymaps/is
new file mode 100644
index 0000000..21dc1fd
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/is
@@ -0,0 +1,139 @@
+# 2004-03-16 Halldór Guðmundsson and Morten Lange
+# Keyboard definition file for the Icelandic keyboard
+# to be used in rdesktop 1.3.x ( See rdesktop.org)
+# generated from XKB map de, and changed manually
+# Location for example /usr/local/share/rdesktop/keymaps/is
+include common
+map 0x40f
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+#section 0x04 shift
+numbersign 0x04 shift
+threesuperior 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+currency 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+#ssharp 0x0c
+odiaeresis 0x0c
+#question 0x0c shift
+Odiaeresis 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+#acute 0x0d
+minus  0x0d
+#dead_acute 0x0d
+#grave 0x0d shift
+#dead_grave 0x0d shift
+underscore 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+#z 0x15 addupper
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+#thorn 0x19 altgr
+#THORN 0x19 shift altgr
+#udiaeresis 0x1a
+#Udiaeresis 0x1a shift
+#dead_diaeresis 0x1a altgr
+#dead_abovering 0x1a shift altgr
+eth 0x1a
+ETH 0x1a shift
+apostrophe 0x1b
+question 0x1b shift
+#plus 0x1b
+#asterisk 0x1b shift
+asciitilde 0x1b altgr
+#grave 0x1b altgr
+#dead_tilde 0x1b altgr
+#dead_macron 0x1b shift altgr
+#ae 0x1e altgr
+#AE 0x1e shift altgr
+#eth 0x20 altgr
+#eth 0x20
+#ETH 0x20 shift altgr
+#ETH 0x20 shift
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+#adiaeresis 0x27
+#Adiaeresis 0x27 shift
+ae 0x27
+AE 0x27 shift
+dead_doubleacute 0x27 altgr
+#adiaeresis 0x28
+#Adiaeresis 0x28 shift
+#dead_caron 0x28 shift altgr
+#asciicircum 0x29
+acute  0x28
+dead_acute 0x28
+#dead_circumflex 0x29
+#degree 0x29 shift
+#notsign 0x29 altgr
+plus 0x2b
+asterisk 0x2b shift
+grave 0x2b altgr
+#numbersign 0x2b
+#apostrophe 0x2b shift
+#dead_breve 0x2b shift altgr
+#y 0x2c addupper
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+#minus 0x35
+#underscore 0x35 shift
+thorn 0x35
+THORN 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/it b/qemu-0.15.x/pc-bios/keymaps/it
new file mode 100644
index 0000000..00ca73a
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/it
@@ -0,0 +1,115 @@
+# generated from XKB map it
+include common
+map 0x410
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+sterling 0x04 shift
+threesuperior 0x04 altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+trademark 0x09 shift altgr
+parenright 0x0a shift
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+apostrophe 0x0c
+question 0x0c shift
+grave 0x0c altgr
+questiondown 0x0c shift altgr
+igrave 0x0d
+asciicircum 0x0d shift
+asciitilde 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+egrave 0x1a
+eacute 0x1a shift
+bracketleft 0x1a altgr
+dead_abovering 0x1a shift altgr
+plus 0x1b
+asterisk 0x1b shift
+bracketright 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+ograve 0x27
+ccedilla 0x27 shift
+at 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+agrave 0x28
+degree 0x28 shift
+numbersign 0x28 altgr
+backslash 0x29
+bar 0x29 shift
+notsign 0x29 altgr
+ugrave 0x2b
+section 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/ja b/qemu-0.15.x/pc-bios/keymaps/ja
new file mode 100644
index 0000000..9d90a78
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/ja
@@ -0,0 +1,109 @@
+# generated from XKB map jp106
+include common
+map 0x411
+exclam 0x02 shift
+kana_NU 0x02 altgr
+quotedbl 0x03 shift
+kana_FU 0x03 altgr
+numbersign 0x04 shift
+kana_A 0x04 altgr
+kana_a 0x04 shift altgr
+dollar 0x05 shift
+kana_U 0x05 altgr
+kana_u 0x05 shift altgr
+percent 0x06 shift
+kana_E 0x06 altgr
+kana_e 0x06 shift altgr
+ampersand 0x07 shift
+kana_O 0x07 altgr
+kana_o 0x07 shift altgr
+apostrophe 0x08 shift
+kana_YA 0x08 altgr
+kana_ya 0x08 shift altgr
+parenleft 0x09 shift
+kana_YU 0x09 altgr
+kana_yu 0x09 shift altgr
+parenright 0x0a shift
+kana_YO 0x0a altgr
+kana_yo 0x0a shift altgr
+asciitilde 0x0b shift
+kana_WA 0x0b altgr
+kana_WO 0x0b shift altgr
+minus 0x0c
+equal 0x0c shift
+kana_HO 0x0c altgr
+asciicircum 0x0d
+asciitilde 0x0d shift
+kana_HE 0x0d altgr
+kana_TA 0x10 altgr
+kana_TE 0x11 altgr
+kana_I 0x12 altgr
+kana_i 0x12 shift altgr
+kana_SU 0x13 altgr
+kana_KA 0x14 altgr
+kana_N 0x15 altgr
+kana_NA 0x16 altgr
+kana_NI 0x17 altgr
+kana_RA 0x18 altgr
+kana_SE 0x19 altgr
+at 0x1a
+grave 0x1a shift
+voicedsound 0x1a altgr
+bracketleft 0x1b
+braceleft 0x1b shift
+semivoicedsound 0x1b altgr
+kana_openingbracket 0x1b shift altgr
+kana_CHI 0x1e altgr
+kana_TO 0x1f altgr
+kana_SHI 0x20 altgr
+kana_HA 0x21 altgr
+kana_KI 0x22 altgr
+kana_KU 0x23 altgr
+kana_MA 0x24 altgr
+kana_NO 0x25 altgr
+kana_RI 0x26 altgr
+semicolon 0x27
+plus 0x27 shift
+kana_RE 0x27 altgr
+colon 0x28
+asterisk 0x28 shift
+kana_KE 0x28 altgr
+Zenkaku_Hankaku 0x29
+bracketright 0x2b
+braceright 0x2b shift
+kana_MU 0x2b altgr
+kana_closingbracket 0x2b shift altgr
+kana_TSU 0x2c altgr
+kana_tsu 0x2c shift altgr
+kana_SA 0x2d altgr
+kana_SO 0x2e altgr
+kana_HI 0x2f altgr
+kana_KO 0x30 altgr
+kana_MI 0x31 altgr
+kana_MO 0x32 altgr
+comma 0x33
+less 0x33 shift
+kana_NE 0x33 altgr
+kana_comma 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+kana_RU 0x34 altgr
+kana_fullstop 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+kana_ME 0x35 altgr
+kana_conjunctive 0x35 shift altgr
+Eisu_toggle 0x3a shift
+Execute 0x54 shift
+Kanji 0x70
+backslash 0x73
+yen 0x7d
+bar 0x7d shift
+underscore 0x73 shift
+Henkan_Mode 0x79
+Katakana_Real 0x70
+Katakana 0x70
+Muhenkan 0x7b
+Henkan_Mode_Real 0x79
+Henkan_Mode_Ultra 0x79
+backslash_ja 0x73
diff --git a/qemu-0.15.x/pc-bios/keymaps/lt b/qemu-0.15.x/pc-bios/keymaps/lt
new file mode 100644
index 0000000..3d9d619
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/lt
@@ -0,0 +1,57 @@
+# generated from XKB map lt
+include common
+map 0x427
+exclam 0x02 shift
+aogonek 0x02 altgr
+Aogonek 0x02 shift altgr
+at 0x03 shift
+ccaron 0x03 altgr
+Ccaron 0x03 shift altgr
+numbersign 0x04 shift
+eogonek 0x04 altgr
+Eogonek 0x04 shift altgr
+dollar 0x05 shift
+eabovedot 0x05 altgr
+Eabovedot 0x05 shift altgr
+percent 0x06 shift
+iogonek 0x06 altgr
+Iogonek 0x06 shift altgr
+asciicircum 0x07 shift
+scaron 0x07 altgr
+Scaron 0x07 shift altgr
+ampersand 0x08 shift
+uogonek 0x08 altgr
+Uogonek 0x08 shift altgr
+asterisk 0x09 shift
+umacron 0x09 altgr
+Umacron 0x09 shift altgr
+parenleft 0x0a shift
+doublelowquotemark 0x0a altgr
+parenright 0x0b shift
+leftdoublequotemark 0x0b altgr
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+zcaron 0x0d altgr
+Zcaron 0x0d shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+bracketright 0x1b
+braceright 0x1b shift
+semicolon 0x27
+colon 0x27 shift
+apostrophe 0x28
+quotedbl 0x28 shift
+grave 0x29
+asciitilde 0x29 shift
+backslash 0x2b
+bar 0x2b shift
+comma 0x33
+less 0x33 shift
+period 0x34
+greater 0x34 shift
+slash 0x35
+question 0x35 shift
+endash 0x56
+EuroSign 0x56 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/lv b/qemu-0.15.x/pc-bios/keymaps/lv
new file mode 100644
index 0000000..1d91727
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/lv
@@ -0,0 +1,128 @@
+# generated from XKB map lv
+include common
+map 0x426
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+at 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+numbersign 0x04 shift
+threesuperior 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+EuroSign 0x05 altgr
+cent 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+asciicircum 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+ampersand 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+asterisk 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenleft 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+parenright 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+minus 0x0c
+underscore 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+equal 0x0d
+plus 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+emacron 0x12 altgr
+Emacron 0x12 shift altgr
+rcedilla 0x13 altgr
+Rcedilla 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+umacron 0x16 altgr
+Umacron 0x16 shift altgr
+imacron 0x17 altgr
+Imacron 0x17 shift altgr
+omacron 0x18 altgr
+Omacron 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ISO_Next_Group 0x1c shift
+amacron 0x1e altgr
+Amacron 0x1e shift altgr
+scaron 0x1f altgr
+Scaron 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+gcedilla 0x22 altgr
+Gcedilla 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kcedilla 0x25 altgr
+Kcedilla 0x25 shift altgr
+lcedilla 0x26 altgr
+Lcedilla 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+leftdoublequotemark 0x28 altgr
+doublelowquotemark 0x28 shift altgr
+grave 0x29
+asciitilde 0x29 shift
+notsign 0x29 altgr
+backslash 0x2b
+bar 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+zcaron 0x2c altgr
+Zcaron 0x2c shift altgr
+guillemotright 0x2d altgr
+greater 0x2d shift altgr
+ccaron 0x2e altgr
+Ccaron 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+apostrophe 0x30 shift altgr
+ncedilla 0x31 altgr
+Ncedilla 0x31 shift altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
+nobreakspace 0x39 altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/mk b/qemu-0.15.x/pc-bios/keymaps/mk
new file mode 100644
index 0000000..18c1504
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/mk
@@ -0,0 +1,101 @@
+# generated from XKB map mk
+include common
+map 0x42f
+exclam 0x02 shift
+at 0x03 shift
+doublelowquotemark 0x03 shift altgr
+numbersign 0x04 shift
+leftdoublequotemark 0x04 shift altgr
+dollar 0x05 shift
+percent 0x06 shift
+asciicircum 0x07 shift
+ampersand 0x08 shift
+asterisk 0x09 shift
+parenleft 0x0a shift
+parenright 0x0b shift
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+Cyrillic_lje 0x10 altgr
+Cyrillic_LJE 0x10 shift altgr
+Cyrillic_nje 0x11 altgr
+Cyrillic_NJE 0x11 shift altgr
+Cyrillic_ie 0x12 altgr
+Cyrillic_IE 0x12 shift altgr
+Cyrillic_er 0x13 altgr
+Cyrillic_ER 0x13 shift altgr
+Cyrillic_te 0x14 altgr
+Cyrillic_TE 0x14 shift altgr
+Macedonia_dse 0x15 altgr
+Macedonia_DSE 0x15 shift altgr
+Cyrillic_u 0x16 altgr
+Cyrillic_U 0x16 shift altgr
+Cyrillic_i 0x17 altgr
+Cyrillic_I 0x17 shift altgr
+Cyrillic_o 0x18 altgr
+Cyrillic_O 0x18 shift altgr
+Cyrillic_pe 0x19 altgr
+Cyrillic_PE 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+Cyrillic_sha 0x1a altgr
+Cyrillic_SHA 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+Macedonia_gje 0x1b altgr
+Macedonia_GJE 0x1b shift altgr
+Cyrillic_a 0x1e altgr
+Cyrillic_A 0x1e shift altgr
+Cyrillic_es 0x1f altgr
+Cyrillic_ES 0x1f shift altgr
+Cyrillic_de 0x20 altgr
+Cyrillic_DE 0x20 shift altgr
+Cyrillic_ef 0x21 altgr
+Cyrillic_EF 0x21 shift altgr
+Cyrillic_ghe 0x22 altgr
+Cyrillic_GHE 0x22 shift altgr
+Cyrillic_ha 0x23 altgr
+Cyrillic_HA 0x23 shift altgr
+Cyrillic_je 0x24 altgr
+Cyrillic_JE 0x24 shift altgr
+Cyrillic_ka 0x25 altgr
+Cyrillic_KA 0x25 shift altgr
+Cyrillic_el 0x26 altgr
+Cyrillic_EL 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+Cyrillic_che 0x27 altgr
+Cyrillic_CHE 0x27 shift altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+Macedonia_kje 0x28 altgr
+Macedonia_KJE 0x28 shift altgr
+grave 0x29
+asciitilde 0x29 shift
+backslash 0x2b
+bar 0x2b shift
+Cyrillic_zhe 0x2b altgr
+Cyrillic_ZHE 0x2b shift altgr
+Cyrillic_ze 0x2c altgr
+Cyrillic_ZE 0x2c shift altgr
+Cyrillic_dzhe 0x2d altgr
+Cyrillic_DZHE 0x2d shift altgr
+Cyrillic_tse 0x2e altgr
+Cyrillic_TSE 0x2e shift altgr
+Cyrillic_ve 0x2f altgr
+Cyrillic_VE 0x2f shift altgr
+Cyrillic_be 0x30 altgr
+Cyrillic_BE 0x30 shift altgr
+Cyrillic_en 0x31 altgr
+Cyrillic_EN 0x31 shift altgr
+Cyrillic_em 0x32 altgr
+Cyrillic_EM 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+semicolon 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+colon 0x34 shift altgr
+slash 0x35
+question 0x35 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/modifiers b/qemu-0.15.x/pc-bios/keymaps/modifiers
new file mode 100644
index 0000000..d73b7a6
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/modifiers
@@ -0,0 +1,18 @@
+Shift_R 0x36
+Shift_L 0x2a
+
+Alt_R 0xb8
+Mode_switch 0xb8
+ISO_Level3_Shift 0xb8
+Alt_L 0x38
+
+Control_R 0x9d
+Control_L 0x1d
+
+# Translate Super to Windows keys.
+# This is hardcoded. See documentation for details.
+Super_R 0xdc
+Super_L 0xdb
+
+# Translate Menu to the Windows Application key.
+Menu 0xdd
diff --git a/qemu-0.15.x/pc-bios/keymaps/nl b/qemu-0.15.x/pc-bios/keymaps/nl
new file mode 100644
index 0000000..b4892f9
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/nl
@@ -0,0 +1,59 @@
+# Dutch (Netherlands)
+include common
+map 0x413
+
+exclam 0x02 shift
+onesuperior 0x02 altgr
+quotebl 0x03 shift
+twosuperior 0x03 altgr
+numbersign 0x04 shift
+threesuperior 0x04 altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+underscore 0x08 shift
+sterling 0x08 altgr
+parenleft 0x09 shift
+braceleft 0x09 altgr
+parenright 0x0a shift
+braceright 0x0a altgr
+apostrophe 0x0b shift
+slash 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+degree 0x0d
+dead_tilde 0x0d shift
+dead_cedilla 0x0d altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+dead_diaeresis 0x1a
+dead_circumflex 0x1a shift
+asterisk 0x1b
+bar 0x1b shift
+ssharp 0x1f altgr
+plus 0x27
+plusminus 0x27 shift
+dead_acute 0x28
+dead_grave 0x28 shift
+at 0x29
+section 0x29 shift
+notsign 0x29 altgr
+less 0x2b
+greater 0x2b shift
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+copyright 0x2e altgr
+mu 0x32 altgr
+comma 0x33
+semicolon 0x33 shift
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+hyphen 0x35
+equal 0x35 shift
+bracketright 0x56
+bracketleft 0x56 shift
+brokenbar 0x56 altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/nl-be b/qemu-0.15.x/pc-bios/keymaps/nl-be
new file mode 100644
index 0000000..34fc881
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/nl-be
@@ -0,0 +1,3 @@
+# Dutch (Belgium)
+map 0x813
+include common
diff --git a/qemu-0.15.x/pc-bios/keymaps/no b/qemu-0.15.x/pc-bios/keymaps/no
new file mode 100644
index 0000000..40a6479
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/no
@@ -0,0 +1,119 @@
+# generated from XKB map no
+include common
+map 0x414
+exclam 0x02 shift
+exclamdown 0x02 altgr
+onesuperior 0x02 shift altgr
+quotedbl 0x03 shift
+at 0x03 altgr
+twosuperior 0x03 shift altgr
+numbersign 0x04 shift
+sterling 0x04 altgr
+threesuperior 0x04 shift altgr
+currency 0x05 shift
+dollar 0x05 altgr
+onequarter 0x05 shift altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+cent 0x06 shift altgr
+ampersand 0x07 shift
+yen 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+division 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+guillemotleft 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+guillemotright 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+plus 0x0c
+question 0x0c shift
+plusminus 0x0c altgr
+questiondown 0x0c shift altgr
+backslash 0x0d
+dead_grave 0x0d shift
+dead_acute 0x0d altgr
+notsign 0x0d shift altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+registered 0x13 altgr
+thorn 0x14 altgr
+THORN 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oe 0x18 altgr
+OE 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+aring 0x1a
+Aring 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+dead_diaeresis 0x1b
+dead_circumflex 0x1b shift
+asciicircum 0x01b shift
+dead_tilde 0x1b altgr
+asciitilde 0x1b altgr
+dead_caron 0x1b shift altgr
+ordfeminine 0x1e altgr
+masculine 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+oslash 0x27
+Ooblique 0x27 shift
+dead_doubleacute 0x27 shift altgr
+ae 0x28
+AE 0x28 shift
+dead_caron 0x28 shift altgr
+bar 0x29
+section 0x29 shift
+brokenbar 0x29 altgr
+paragraph 0x29 shift altgr
+apostrophe 0x2b
+asterisk 0x2b shift
+multiply 0x2b shift altgr
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+copyright 0x2e altgr
+leftdoublequotemark 0x2f altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+dead_cedilla 0x33 altgr
+dead_ogonek 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+dead_abovedot 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+hyphen 0x35 altgr
+macron 0x35 shift altgr
+nobreakspace 0x39 altgr
+onehalf 0x56 altgr
+threequarters 0x56 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/pl b/qemu-0.15.x/pc-bios/keymaps/pl
new file mode 100644
index 0000000..09c600d
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/pl
@@ -0,0 +1,122 @@
+# generated from XKB map pl
+include common
+map 0x415
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+at 0x03 shift
+twosuperior 0x03 altgr
+oneeighth 0x03 shift altgr
+numbersign 0x04 shift
+threesuperior 0x04 altgr
+sterling 0x04 shift altgr
+dollar 0x05 shift
+onequarter 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+asciicircum 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+ampersand 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+asterisk 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenleft 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+parenright 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+minus 0x0c
+underscore 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+equal 0x0d
+plus 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+eogonek 0x12 altgr
+Eogonek 0x12 shift altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+EuroSign 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oacute 0x18 altgr
+Oacute 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+aogonek 0x1e altgr
+Aogonek 0x1e shift altgr
+sacute 0x1f altgr
+Sacute 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+dead_circumflex 0x28 altgr
+dead_caron 0x28 shift altgr
+grave 0x29
+asciitilde 0x29 shift
+notsign 0x29 altgr
+backslash 0x2b
+bar 0x2b shift
+dead_grave 0x2b altgr
+dead_breve 0x2b shift altgr
+zabovedot 0x2c altgr
+Zabovedot 0x2c shift altgr
+zacute 0x2d altgr
+Zacute 0x2d shift altgr
+cacute 0x2e altgr
+Cacute 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+nacute 0x31 altgr
+Nacute 0x31 shift altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/pt b/qemu-0.15.x/pc-bios/keymaps/pt
new file mode 100644
index 0000000..c6941f6
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/pt
@@ -0,0 +1,113 @@
+# generated from XKB map pt
+include common
+map 0x816
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+quotedbl 0x03 shift
+at 0x03 altgr
+oneeighth 0x03 shift altgr
+numbersign 0x04 shift
+sterling 0x04 altgr
+dollar 0x05 shift
+section 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+threequarters 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+apostrophe 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+guillemotleft 0x0d
+guillemotright 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+cent 0x12 shift altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+plus 0x1a
+asterisk 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+dead_acute 0x1b
+dead_grave 0x1b shift
+dead_tilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+ccedilla 0x27
+Ccedilla 0x27 shift
+dead_doubleacute 0x27 shift altgr
+masculine 0x28
+ordfeminine 0x28 shift
+dead_circumflex 0x28 altgr
+dead_caron 0x28 shift altgr
+backslash 0x29
+bar 0x29 shift
+notsign 0x29 altgr
+dead_tilde 0x2b
+dead_circumflex 0x2b shift
+dead_breve 0x2b shift altgr
+less 0x56
+greater 0x56 shift
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+mu 0x32 altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+multiply 0x33 shift altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+division 0x34 shift altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/pt-br b/qemu-0.15.x/pc-bios/keymaps/pt-br
new file mode 100644
index 0000000..54bafc5
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/pt-br
@@ -0,0 +1,69 @@
+# generated from XKB map br
+include common
+map 0x416
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+at 0x03 shift
+twosuperior 0x03 altgr
+onehalf 0x03 shift altgr
+numbersign 0x04 shift
+threesuperior 0x04 altgr
+threequarters 0x04 shift altgr
+dollar 0x05 shift
+sterling 0x05 altgr
+onequarter 0x05 shift altgr
+percent 0x06 shift
+cent 0x06 altgr
+dead_diaeresis 0x07 shift
+notsign 0x07 altgr
+diaeresis 0x07 shift altgr
+ampersand 0x08 shift
+braceleft 0x08 altgr
+asterisk 0x09 shift
+bracketleft 0x09 altgr
+parenleft 0x0a shift
+bracketright 0x0a altgr
+parenright 0x0b shift
+braceright 0x0b altgr
+minus 0x0c
+underscore 0x0c shift
+backslash 0x0c altgr
+equal 0x0d
+plus 0x0d shift
+section 0x0d altgr
+EuroSign 0x12 altgr
+registered 0x13 altgr
+dead_acute 0x1a
+dead_grave 0x1a shift
+acute 0x1a altgr
+grave 0x1a shift altgr
+bracketleft 0x1b
+braceleft 0x1b shift
+ordfeminine 0x1b altgr
+ccedilla 0x27
+Ccedilla 0x27 shift
+dead_tilde 0x28
+dead_circumflex 0x28 shift
+asciitilde 0x28 altgr
+asciicircum 0x28 shift altgr
+apostrophe 0x29
+quotedbl 0x29 shift
+bracketright 0x2b
+braceright 0x2b shift
+masculine 0x2b altgr
+copyright 0x2e altgr
+mu 0x32 altgr
+comma 0x33
+less 0x33 shift
+period 0x34
+greater 0x34 shift
+semicolon 0x35
+colon 0x35 shift
+comma 0x53 numlock
+backslash 0x56
+bar 0x56 shift
+slash 0x73
+question 0x73 shift
+degree 0x73 altgr
+KP_Decimal 0x34
diff --git a/qemu-0.15.x/pc-bios/keymaps/ru b/qemu-0.15.x/pc-bios/keymaps/ru
new file mode 100644
index 0000000..b3e7d24
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/ru
@@ -0,0 +1,109 @@
+# generated from XKB map ru
+include common
+map 0x419
+exclam 0x02 shift
+at 0x03 shift
+quotedbl 0x03 shift altgr
+numbersign 0x04 shift
+dollar 0x05 shift
+asterisk 0x05 shift altgr
+percent 0x06 shift
+colon 0x06 shift altgr
+asciicircum 0x07 shift
+comma 0x07 shift altgr
+ampersand 0x08 shift
+period 0x08 shift altgr
+asterisk 0x09 shift
+semicolon 0x09 shift altgr
+parenleft 0x0a shift
+parenright 0x0b shift
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+Cyrillic_shorti 0x10 altgr
+Cyrillic_SHORTI 0x10 shift altgr
+Cyrillic_tse 0x11 altgr
+Cyrillic_TSE 0x11 shift altgr
+Cyrillic_u 0x12 altgr
+Cyrillic_U 0x12 shift altgr
+Cyrillic_ka 0x13 altgr
+Cyrillic_KA 0x13 shift altgr
+Cyrillic_ie 0x14 altgr
+Cyrillic_IE 0x14 shift altgr
+Cyrillic_en 0x15 altgr
+Cyrillic_EN 0x15 shift altgr
+Cyrillic_ghe 0x16 altgr
+Cyrillic_GHE 0x16 shift altgr
+Cyrillic_sha 0x17 altgr
+Cyrillic_SHA 0x17 shift altgr
+Cyrillic_shcha 0x18 altgr
+Cyrillic_SHCHA 0x18 shift altgr
+Cyrillic_ze 0x19 altgr
+Cyrillic_ZE 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+Cyrillic_ha 0x1a altgr
+Cyrillic_HA 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+Cyrillic_hardsign 0x1b altgr
+Cyrillic_HARDSIGN 0x1b shift altgr
+Cyrillic_ef 0x1e altgr
+Cyrillic_EF 0x1e shift altgr
+Cyrillic_yeru 0x1f altgr
+Cyrillic_YERU 0x1f shift altgr
+Cyrillic_ve 0x20 altgr
+Cyrillic_VE 0x20 shift altgr
+Cyrillic_a 0x21 altgr
+Cyrillic_A 0x21 shift altgr
+Cyrillic_pe 0x22 altgr
+Cyrillic_PE 0x22 shift altgr
+Cyrillic_er 0x23 altgr
+Cyrillic_ER 0x23 shift altgr
+Cyrillic_o 0x24 altgr
+Cyrillic_O 0x24 shift altgr
+Cyrillic_el 0x25 altgr
+Cyrillic_EL 0x25 shift altgr
+Cyrillic_de 0x26 altgr
+Cyrillic_DE 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+Cyrillic_zhe 0x27 altgr
+Cyrillic_ZHE 0x27 shift altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+Cyrillic_e 0x28 altgr
+Cyrillic_E 0x28 shift altgr
+grave 0x29
+asciitilde 0x29 shift
+Cyrillic_io 0x29 altgr
+Cyrillic_IO 0x29 shift altgr
+backslash 0x2b
+bar 0x2b shift
+Cyrillic_ya 0x2c altgr
+Cyrillic_YA 0x2c shift altgr
+Cyrillic_che 0x2d altgr
+Cyrillic_CHE 0x2d shift altgr
+Cyrillic_es 0x2e altgr
+Cyrillic_ES 0x2e shift altgr
+Cyrillic_em 0x2f altgr
+Cyrillic_EM 0x2f shift altgr
+Cyrillic_i 0x30 altgr
+Cyrillic_I 0x30 shift altgr
+Cyrillic_te 0x31 altgr
+Cyrillic_TE 0x31 shift altgr
+Cyrillic_softsign 0x32 altgr
+Cyrillic_SOFTSIGN 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+Cyrillic_be 0x33 altgr
+Cyrillic_BE 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+Cyrillic_yu 0x34 altgr
+Cyrillic_YU 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+slash 0x56 altgr
+bar 0x56 shift altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/sl b/qemu-0.15.x/pc-bios/keymaps/sl
new file mode 100644
index 0000000..56835a9
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/sl
@@ -0,0 +1,110 @@
+# generated from XKB map sl
+include common
+map 0x424
+exclam 0x02 shift
+asciitilde 0x02 altgr
+dead_tilde 0x02 shift altgr
+quotedbl 0x03 shift
+dead_caron 0x03 altgr
+caron 0x03 shift altgr
+numbersign 0x04 shift
+asciicircum 0x04 altgr
+dead_circumflex 0x04 shift altgr
+dollar 0x05 shift
+dead_breve 0x05 altgr
+breve 0x05 shift altgr
+percent 0x06 shift
+degree 0x06 altgr
+dead_abovering 0x06 shift altgr
+ampersand 0x07 shift
+dead_ogonek 0x07 altgr
+ogonek 0x07 shift altgr
+slash 0x08 shift
+grave 0x08 altgr
+dead_grave 0x08 shift altgr
+parenleft 0x09 shift
+dead_abovedot 0x09 altgr
+abovedot 0x09 shift altgr
+parenright 0x0a shift
+dead_acute 0x0a altgr
+equal 0x0b shift
+dead_doubleacute 0x0b altgr
+doubleacute 0x0b shift altgr
+apostrophe 0x0c
+question 0x0c shift
+dead_diaeresis 0x0c altgr
+diaeresis 0x0c shift altgr
+plus 0x0d
+asterisk 0x0d shift
+dead_cedilla 0x0d altgr
+cedilla 0x0d shift altgr
+backslash 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+bar 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+z 0x15 addupper
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+rightarrow 0x17 altgr
+idotless 0x17 shift altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+scaron 0x1a
+Scaron 0x1a shift
+division 0x1a altgr
+dstroke 0x1b
+Dstroke 0x1b shift
+multiply 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+bracketleft 0x21 altgr
+ordfeminine 0x21 shift altgr
+bracketright 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+lstroke 0x25 altgr
+Lstroke 0x26 altgr
+ccaron 0x27
+Ccaron 0x27 shift
+cacute 0x28
+Cacute 0x28 shift
+ssharp 0x28 altgr
+dead_cedilla 0x29
+notsign 0x29 altgr
+zcaron 0x2b
+Zcaron 0x2b shift
+currency 0x2b altgr
+y 0x2c addupper
+guillemotleft 0x2c altgr
+guillemotright 0x2d altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+at 0x2f altgr
+braceleft 0x30 altgr
+braceright 0x31 altgr
+section 0x32 altgr
+masculine 0x32 shift altgr
+comma 0x33
+semicolon 0x33 shift
+horizconnector 0x33 altgr
+period 0x34
+colon 0x34 shift
+periodcentered 0x34 altgr
+minus 0x35
+underscore 0x35 shift
+dead_belowdot 0x35 altgr
diff --git a/qemu-0.15.x/pc-bios/keymaps/sv b/qemu-0.15.x/pc-bios/keymaps/sv
new file mode 100644
index 0000000..5d9080e
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/sv
@@ -0,0 +1,81 @@
+map 0x0000041d
+include common
+
+#
+# Top row
+#
+section 0x29
+onehalf 0x29 shift
+
+# 1
+exclam 0x2 shift
+
+# 2
+quotedbl 0x3 shift
+at 0x3 altgr
+
+# 3
+numbersign 0x4 shift
+sterling 0x4 altgr
+# 4
+currency 0x5 shift
+dollar 0x5 altgr
+# 5
+percent 0x6 shift
+# 6
+ampersand 0x7 shift
+# 7
+slash 0x8 shift
+braceleft 0x8 altgr
+# 8
+parenleft 0x9 shift
+bracketleft 0x9 altgr
+# 9
+parenright 0xa shift
+bracketright 0xa altgr
+# 0
+equal 0xb shift
+braceright 0xb altgr
+
+plus 0xc
+question 0xc shift
+backslash 0xc altgr
+
+acute 0xd
+dead_acute 0xd
+grave 0xd shift
+dead_grave 0xd shift
+
+#
+# QWERTY first row
+#
+EuroSign 0x12 altgr
+aring 0x1a
+Aring 0x1a shift
+dead_diaeresis 0x1b
+dead_circumflex 0x1b shift
+dead_tilde 0x1b altgr
+
+#
+# QWERTY second row
+#
+odiaeresis 0x27
+Odiaeresis 0x27 shift
+adiaeresis 0x28
+Adiaeresis 0x28 shift
+apostrophe 0x2b
+asterisk 0x2b shift
+
+#
+# QWERTY third row
+#
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+mu 0x32 altgr
+comma 0x33
+semicolon 0x33 shift
+period 0x34
+colon 0x34 shift
+minus 0x35
+underscore 0x35 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/th b/qemu-0.15.x/pc-bios/keymaps/th
new file mode 100644
index 0000000..b65b6da
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/th
@@ -0,0 +1,131 @@
+# generated from XKB map th
+include common
+map 0x41e
+exclam 0x02 shift
+Thai_lakkhangyao 0x02 altgr
+plus 0x02 shift altgr
+at 0x03 shift
+slash 0x03 altgr
+Thai_leknung 0x03 shift altgr
+numbersign 0x04 shift
+minus 0x04 altgr
+Thai_leksong 0x04 shift altgr
+dollar 0x05 shift
+Thai_phosamphao 0x05 altgr
+Thai_leksam 0x05 shift altgr
+percent 0x06 shift
+Thai_thothung 0x06 altgr
+Thai_leksi 0x06 shift altgr
+asciicircum 0x07 shift
+Thai_sarau 0x07 altgr
+Thai_sarauu 0x07 shift altgr
+ampersand 0x08 shift
+Thai_saraue 0x08 altgr
+Thai_baht 0x08 shift altgr
+asterisk 0x09 shift
+Thai_khokhwai 0x09 altgr
+Thai_lekha 0x09 shift altgr
+parenleft 0x0a shift
+Thai_totao 0x0a altgr
+Thai_lekhok 0x0a shift altgr
+parenright 0x0b shift
+Thai_chochan 0x0b altgr
+Thai_lekchet 0x0b shift altgr
+minus 0x0c
+underscore 0x0c shift
+Thai_khokhai 0x0c altgr
+Thai_lekpaet 0x0c shift altgr
+equal 0x0d
+plus 0x0d shift
+Thai_chochang 0x0d altgr
+Thai_lekkao 0x0d shift altgr
+Thai_maiyamok 0x10 altgr
+Thai_leksun 0x10 shift altgr
+Thai_saraaimaimalai 0x11 altgr
+quotedbl 0x11 shift altgr
+Thai_saraam 0x12 altgr
+Thai_dochada 0x12 shift altgr
+Thai_phophan 0x13 altgr
+Thai_thonangmontho 0x13 shift altgr
+Thai_saraa 0x14 altgr
+Thai_thothong 0x14 shift altgr
+Thai_maihanakat 0x15 altgr
+Thai_nikhahit 0x15 shift altgr
+Thai_saraii 0x16 altgr
+Thai_maitri 0x16 shift altgr
+Thai_rorua 0x17 altgr
+Thai_nonen 0x17 shift altgr
+Thai_nonu 0x18 altgr
+Thai_paiyannoi 0x18 shift altgr
+Thai_yoyak 0x19 altgr
+Thai_yoying 0x19 shift altgr
+bracketleft 0x1a
+braceleft 0x1a shift
+Thai_bobaimai 0x1a altgr
+Thai_thothan 0x1a shift altgr
+bracketright 0x1b
+braceright 0x1b shift
+Thai_loling 0x1b altgr
+comma 0x1b shift altgr
+Thai_fofan 0x1e altgr
+Thai_ru 0x1e shift altgr
+Thai_hohip 0x1f altgr
+Thai_khorakhang 0x1f shift altgr
+Thai_kokai 0x20 altgr
+Thai_topatak 0x20 shift altgr
+Thai_dodek 0x21 altgr
+Thai_sarao 0x21 shift altgr
+Thai_sarae 0x22 altgr
+Thai_chochoe 0x22 shift altgr
+Thai_maitho 0x23 altgr
+Thai_maitaikhu 0x23 shift altgr
+Thai_maiek 0x24 altgr
+Thai_maichattawa 0x24 shift altgr
+Thai_saraaa 0x25 altgr
+Thai_sorusi 0x25 shift altgr
+Thai_sosua 0x26 altgr
+Thai_sosala 0x26 shift altgr
+semicolon 0x27
+colon 0x27 shift
+Thai_wowaen 0x27 altgr
+Thai_soso 0x27 shift altgr
+apostrophe 0x28
+quotedbl 0x28 shift
+Thai_ngongu 0x28 altgr
+period 0x28 shift altgr
+grave 0x29
+asciitilde 0x29 shift
+underscore 0x29 altgr
+percent 0x29 shift altgr
+ISO_First_Group 0x2a shift
+backslash 0x2b
+bar 0x2b shift
+Thai_khokhuat 0x2b altgr
+Thai_khokhon 0x2b shift altgr
+Thai_phophung 0x2c altgr
+parenleft 0x2c shift altgr
+Thai_popla 0x2d altgr
+parenright 0x2d shift altgr
+Thai_saraae 0x2e altgr
+Thai_choching 0x2e shift altgr
+Thai_oang 0x2f altgr
+Thai_honokhuk 0x2f shift altgr
+Thai_sarai 0x30 altgr
+Thai_phinthu 0x30 shift altgr
+Thai_sarauee 0x31 altgr
+Thai_thanthakhat 0x31 shift altgr
+Thai_thothahan 0x32 altgr
+question 0x32 shift altgr
+comma 0x33
+less 0x33 shift
+Thai_moma 0x33 altgr
+Thai_thophuthao 0x33 shift altgr
+period 0x34
+greater 0x34 shift
+Thai_saraaimaimuan 0x34 altgr
+Thai_lochula 0x34 shift altgr
+slash 0x35
+question 0x35 shift
+Thai_fofa 0x35 altgr
+Thai_lu 0x35 shift altgr
+ISO_Last_Group 0x36 shift
diff --git a/qemu-0.15.x/pc-bios/keymaps/tr b/qemu-0.15.x/pc-bios/keymaps/tr
new file mode 100644
index 0000000..5650e1e
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/keymaps/tr
@@ -0,0 +1,123 @@
+# generated from XKB map tr
+include common
+map 0x41f
+exclam 0x02 shift
+onesuperior 0x02 altgr
+exclamdown 0x02 shift altgr
+apostrophe 0x03 shift
+at 0x03 altgr
+oneeighth 0x03 shift altgr
+dead_circumflex 0x04 shift
+numbersign 0x04 altgr
+sterling 0x04 shift altgr
+plus 0x05 shift
+dollar 0x05 altgr
+percent 0x06 shift
+onehalf 0x06 altgr
+threeeighths 0x06 shift altgr
+ampersand 0x07 shift
+asciicircum 0x07 altgr
+fiveeighths 0x07 shift altgr
+slash 0x08 shift
+braceleft 0x08 altgr
+seveneighths 0x08 shift altgr
+parenleft 0x09 shift
+bracketleft 0x09 altgr
+trademark 0x09 shift altgr
+parenright 0x0a shift
+bracketright 0x0a altgr
+plusminus 0x0a shift altgr
+equal 0x0b shift
+braceright 0x0b altgr
+degree 0x0b shift altgr
+asterisk 0x0c
+question 0x0c shift
+backslash 0x0c altgr
+questiondown 0x0c shift altgr
+minus 0x0d
+underscore 0x0d shift
+dead_cedilla 0x0d altgr
+dead_ogonek 0x0d shift altgr
+at 0x10 altgr
+Greek_OMEGA 0x10 shift altgr
+lstroke 0x11 altgr
+Lstroke 0x11 shift altgr
+EuroSign 0x12 altgr
+paragraph 0x13 altgr
+registered 0x13 shift altgr
+tslash 0x14 altgr
+Tslash 0x14 shift altgr
+leftarrow 0x15 altgr
+yen 0x15 shift altgr
+downarrow 0x16 altgr
+uparrow 0x16 shift altgr
+idotless 0x17
+I 0x17 shift
+rightarrow 0x17 altgr
+oslash 0x18 altgr
+Ooblique 0x18 shift altgr
+thorn 0x19 altgr
+THORN 0x19 shift altgr
+gbreve 0x1a
+Gbreve 0x1a shift
+dead_diaeresis 0x1a altgr
+dead_abovering 0x1a shift altgr
+udiaeresis 0x1b
+Udiaeresis 0x1b shift
+asciitilde 0x1b altgr
+dead_macron 0x1b shift altgr
+ae 0x1e altgr
+AE 0x1e shift altgr
+ssharp 0x1f altgr
+section 0x1f shift altgr
+eth 0x20 altgr
+ETH 0x20 shift altgr
+dstroke 0x21 altgr
+ordfeminine 0x21 shift altgr
+eng 0x22 altgr
+ENG 0x22 shift altgr
+hstroke 0x23 altgr
+Hstroke 0x23 shift altgr
+kra 0x25 altgr
+ampersand 0x25 shift altgr
+lstroke 0x26 altgr
+Lstroke 0x26 shift altgr
+scedilla 0x27
+Scedilla 0x27 shift
+dead_acute 0x27 altgr
+dead_doubleacute 0x27 shift altgr
+i 0x28
+Iabovedot 0x28 shift
+dead_circumflex 0x28 altgr
+dead_caron 0x28 shift altgr
+backslash 0x29
+quotedbl 0x29 shift
+asciitilde 0x29 altgr
+comma 0x2b
+semicolon 0x2b shift
+bar 0x2b altgr
+dead_breve 0x2b shift altgr
+guillemotleft 0x2c altgr
+less 0x2c shift altgr
+guillemotright 0x2d altgr
+greater 0x2d shift altgr
+cent 0x2e altgr
+copyright 0x2e shift altgr
+leftdoublequotemark 0x2f altgr
+grave 0x2f shift altgr
+rightdoublequotemark 0x30 altgr
+apostrophe 0x30 shift altgr
+mu 0x32 altgr
+masculine 0x32 shift altgr
+odiaeresis 0x33
+Odiaeresis 0x33 shift
+less 0x33 altgr
+multiply 0x33 shift altgr
+ccedilla 0x34
+Ccedilla 0x34 shift
+greater 0x34 altgr
+division 0x34 shift altgr
+period 0x35
+colon 0x35 shift
+dead_belowdot 0x35 altgr
+dead_abovedot 0x35 shift altgr
diff --git a/qemu-0.15.x/pc-bios/linuxboot.bin b/qemu-0.15.x/pc-bios/linuxboot.bin
new file mode 100644
index 0000000..e7c3669
Binary files /dev/null and b/qemu-0.15.x/pc-bios/linuxboot.bin differ
diff --git a/qemu-0.15.x/pc-bios/mpc8544ds.dtb b/qemu-0.15.x/pc-bios/mpc8544ds.dtb
new file mode 100644
index 0000000..ae318b1
Binary files /dev/null and b/qemu-0.15.x/pc-bios/mpc8544ds.dtb differ
diff --git a/qemu-0.15.x/pc-bios/mpc8544ds.dts b/qemu-0.15.x/pc-bios/mpc8544ds.dts
new file mode 100644
index 0000000..a88b47c
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/mpc8544ds.dts
@@ -0,0 +1,131 @@
+/*
+ * MPC8544 DS Device Tree Source
+ *
+ * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+	model = "MPC8544DS";
+	compatible = "MPC8544DS", "MPC85xxDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		serial0 = &serial0;
+		serial1 = &serial1;
+		pci0 = &pci0;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8544 at 0 {
+			device_type = "cpu";
+			reg = <0x0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <0x8000>;		// L1, 32K
+			i-cache-size = <0x8000>;		// L1, 32K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x0>;	// Filled by U-Boot
+	};
+
+	soc8544 at e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+
+		ranges = <0x0 0xe0000000 0x100000>;
+		reg = <0xe0000000 0x1000>;	// CCSRBAR 1M
+		bus-frequency = <0>;		// Filled out by uboot.
+
+		serial0: serial at 4500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <42 2>;
+			interrupt-parent = <&mpic>;
+		};
+
+		serial1: serial at 4600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <42 2>;
+			interrupt-parent = <&mpic>;
+		};
+
+		mpic: pic at 40000 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+		};
+
+                global-utilities at e0000 {        //global utilities block
+                        compatible = "fsl,mpc8544-guts";
+                        reg = <0xe0000 0x1000>;
+                        fsl,has-rstcr;
+                };
+	};
+
+	pci0: pci at e0008000 {
+		cell-index = <0>;
+		compatible = "fsl,mpc8540-pci";
+		device_type = "pci";
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+
+			/* IDSEL 0x11 J17 Slot 1 */
+			0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8800 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x12 J16 Slot 2 */
+
+			0x9000 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9000 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9000 0x0 0x0 0x3 &mpic 0x2 0x1
+			0x9000 0x0 0x0 0x4 &mpic 0x1 0x1>;
+
+		interrupt-parent = <&mpic>;
+		interrupts = <24 2>;
+		bus-range = <0 255>;
+		ranges = <0x2000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x0 0xe1000000 0x0 0x10000>;
+		clock-frequency = <66666666>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xe0008000 0x1000>;
+	};
+
+	chosen {
+		linux,stdout-path = "/soc8544 at e0000000/serial at 4500";
+	};
+
+	hypervisor {
+	};
+};
diff --git a/qemu-0.15.x/pc-bios/multiboot.bin b/qemu-0.15.x/pc-bios/multiboot.bin
new file mode 100644
index 0000000..f74a6e1
Binary files /dev/null and b/qemu-0.15.x/pc-bios/multiboot.bin differ
diff --git a/qemu-0.15.x/pc-bios/ohw.diff b/qemu-0.15.x/pc-bios/ohw.diff
new file mode 100644
index 0000000..4fb5422
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/ohw.diff
@@ -0,0 +1,1843 @@
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bios.h OpenHackWare-release-0.4/src/bios.h
+--- OpenHackWare-release-0.4.org/src/bios.h	2005-04-06 23:20:22.000000000 +0200
++++ OpenHackWare-release-0.4/src/bios.h	2005-07-07 01:10:20.000000000 +0200
+@@ -64,6 +64,7 @@
+     ARCH_CHRP,
+     ARCH_MAC99,
+     ARCH_POP,
++    ARCH_HEATHROW,
+ };
+ 
+ /* Hardware definition(s) */
+@@ -174,6 +175,7 @@
+ int bd_ioctl (bloc_device_t *bd, int func, void *args);
+ uint32_t bd_seclen (bloc_device_t *bd);
+ void bd_close (bloc_device_t *bd);
++void bd_reset_all(void);
+ uint32_t bd_seclen (bloc_device_t *bd);
+ uint32_t bd_maxbloc (bloc_device_t *bd);
+ void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum,
+@@ -183,12 +185,12 @@
+ part_t *bd_probe (int boot_device);
+ bloc_device_t *bd_get (int device);
+ void bd_put (bloc_device_t *bd);
+-void bd_set_boot_part (bloc_device_t *bd, part_t *partition);
++void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum);
+ part_t **_bd_parts (bloc_device_t *bd);
+ 
+ void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
+                           uint32_t io_base2, uint32_t io_base3,
+-                          void *OF_private);
++                          void *OF_private0, void *OF_private1);
+ void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1,
+                             void *OF_private);
+ 
+@@ -399,17 +401,23 @@
+                               uint16_t min_grant, uint16_t max_latency);
+ void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses);
+ void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
+-                             uint32_t *regions, uint32_t *sizes);
++                             uint32_t *regions, uint32_t *sizes,
++                             int irq_line);
+ void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
+                             void *private_data);
++void OF_finalize_pci_ide (void *dev, 
++                          uint32_t io_base0, uint32_t io_base1,
++                          uint32_t io_base2, uint32_t io_base3);
+ int OF_register_bus (const unsigned char *name, uint32_t address,
+                      const unsigned char *type);
+ int OF_register_serial (const unsigned char *bus, const unsigned char *name,
+                         uint32_t io_base, int irq);
+ int OF_register_stdio (const unsigned char *dev_in,
+                        const unsigned char *dev_out);
+-void OF_vga_register (const unsigned char *name, uint32_t address,
+-                      int width, int height, int depth);
++void OF_vga_register (const unsigned char *name, unused uint32_t address,
++                      int width, int height, int depth,
++                      unsigned long vga_bios_addr, 
++                      unsigned long vga_bios_size);
+ void *OF_blockdev_register (void *parent, void *private,
+                             const unsigned char *type,
+                             const unsigned char *name, int devnum,
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bloc.c OpenHackWare-release-0.4/src/bloc.c
+--- OpenHackWare-release-0.4.org/src/bloc.c	2005-04-06 23:21:00.000000000 +0200
++++ OpenHackWare-release-0.4/src/bloc.c	2005-07-08 00:28:26.000000000 +0200
+@@ -55,6 +55,7 @@
+     /* Partitions */
+     part_t *parts, *bparts;
+     part_t *boot_part;
++    int bpartnum;
+     /* Chain */
+     bloc_device_t *next;
+ };
+@@ -66,6 +67,7 @@
+ 
+ static int ide_initialize (bloc_device_t *bd, int device);
+ static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum);
++static int ide_reset (bloc_device_t *bd);
+ 
+ static int mem_initialize (bloc_device_t *bd, int device);
+ static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+@@ -212,6 +214,17 @@
+ {
+ }
+ 
++void bd_reset_all(void)
++{
++    bloc_device_t *bd;
++    for (bd = bd_list; bd != NULL; bd = bd->next) {
++        if (bd->init == &ide_initialize) {
++            /* reset IDE drive because Darwin wants all IDE devices to be reset */
++            ide_reset(bd);
++        }
++    }
++}
++
+ uint32_t bd_seclen (bloc_device_t *bd)
+ {
+     return bd->seclen;
+@@ -223,10 +236,12 @@
+ }
+ 
+ /* XXX: to be suppressed */
+-void bd_set_boot_part (bloc_device_t *bd, part_t *partition)
++void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum)
+ {
++    dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum);
+     if (bd->boot_part == NULL) {
+         bd->boot_part = partition;
++        bd->bpartnum = partnum;
+     }
+ }
+ 
+@@ -240,6 +255,13 @@
+     return &bd->bparts;
+ }
+ 
++void bd_set_boot_device (bloc_device_t *bd)
++{
++#if defined (USE_OPENFIRMWARE)
++    OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot");
++#endif
++}
++
+ part_t *bd_probe (int boot_device)
+ {
+     char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', };
+@@ -272,9 +294,7 @@
+         tmp = part_probe(bd, force_raw);
+         if (boot_device == bd->device) {
+             boot_part = tmp;
+-#if defined (USE_OPENFIRMWARE)
+-            OF_blockdev_set_boot_device(bd->OF_private, 2, "\\\\ofwboot");
+-#endif
++            bd_set_boot_device(bd);
+         }
+     }
+ 
+@@ -717,34 +737,29 @@
+ /* IDE PCI access for pc */
+ static uint8_t ide_pci_port_read (bloc_device_t *bd, int port)
+ {
+-    eieio();
+-
+-    return *(uint8_t *)(bd->io_base + port);
++    uint8_t value;
++    value = inb(bd->io_base + port);
++    return value;
+ }
+ 
+ static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value)
+ {
+-    *(uint8_t *)(bd->io_base + port) = value;
+-    eieio();
++    outb(bd->io_base + port, value);
+ }
+ 
+ static uint32_t ide_pci_data_readl (bloc_device_t *bd)
+ {
+-    eieio();
+-
+-    return *((uint32_t *)bd->io_base);
++    return inl(bd->io_base);
+ }
+ 
+ static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val)
+ {
+-    *(uint32_t *)(bd->io_base) = val;
+-    eieio();
++    outl(bd->io_base, val);
+ }
+ 
+ static void ide_pci_control_write (bloc_device_t *bd, uint32_t val)
+ {
+-    *((uint8_t *)bd->tmp) = val;
+-    eieio();
++    outb(bd->tmp + 2, val);
+ }
+ 
+ static ide_ops_t ide_pci_pc_ops = {
+@@ -761,7 +776,7 @@
+ 
+ void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
+                           uint32_t io_base2, uint32_t io_base3,
+-                          unused void *OF_private)
++                          void *OF_private0, void *OF_private1)
+ {
+     if (ide_pci_ops == NULL) {
+         ide_pci_ops = malloc(sizeof(ide_ops_t));
+@@ -770,19 +785,19 @@
+         memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t));
+     }
+     if ((io_base0 != 0 || io_base1 != 0) &&
+-        ide_pci_ops->base[0] == 0 && ide_pci_ops->base[1] == 0) {
++        ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) {
+         ide_pci_ops->base[0] = io_base0;
+-        ide_pci_ops->base[1] = io_base1;
++        ide_pci_ops->base[2] = io_base1;
+ #ifdef USE_OPENFIRMWARE
+-        ide_pci_ops->OF_private[0] = OF_private;
++        ide_pci_ops->OF_private[0] = OF_private0;
+ #endif
+     }
+     if ((io_base2 != 0 || io_base3 != 0) &&
+-        ide_pci_ops->base[2] == 0 && ide_pci_ops->base[3] == 0) {
+-        ide_pci_ops->base[2] = io_base2;
++        ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) {
++        ide_pci_ops->base[1] = io_base2;
+         ide_pci_ops->base[3] = io_base3;
+ #ifdef USE_OPENFIRMWARE
+-        ide_pci_ops->OF_private[1] = OF_private;
++        ide_pci_ops->OF_private[1] = OF_private1;
+ #endif
+     }
+ }
+@@ -935,6 +950,8 @@
+ }
+ 
+ static void atapi_pad_req (void *buffer, int len);
++static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
++                            int maxlen);
+ static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+ 
+ static int ide_initialize (bloc_device_t *bd, int device)
+@@ -1035,9 +1052,7 @@
+         DPRINTF("INQUIRY\n");
+         len = spc_inquiry_req(&atapi_buffer, 36);
+         atapi_pad_req(&atapi_buffer, len);
+-        ide_port_write(bd, 0x07, 0xA0);
+-        for (i = 0; i < 3; i++)
+-            ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
++        atapi_make_req(bd, atapi_buffer, 36);
+         status = ide_port_read(bd, 0x07);
+         if (status != 0x48) {
+             ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status);
+@@ -1053,9 +1068,7 @@
+         DPRINTF("READ_CAPACITY\n");
+         len = mmc_read_capacity_req(&atapi_buffer);
+         atapi_pad_req(&atapi_buffer, len);
+-        ide_port_write(bd, 0x07, 0xA0);
+-        for (i = 0; i < 3; i++)
+-            ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
++        atapi_make_req(bd, atapi_buffer, 8);
+         status = ide_port_read(bd, 0x07);
+         if (status != 0x48) {
+             ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status);
+@@ -1105,6 +1118,22 @@
+     memset(p + len, 0, 12 - len);
+ }
+ 
++static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
++                            int maxlen)
++{
++    int i;
++    /* select drive */
++    if (bd->drv == 0)
++        ide_port_write(bd, 0x06, 0x40);
++    else
++        ide_port_write(bd, 0x06, 0x50);
++    ide_port_write(bd, 0x04, maxlen & 0xff);
++    ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff);
++    ide_port_write(bd, 0x07, 0xA0);
++    for (i = 0; i < 3; i++)
++        ide_data_writel(bd, ldswap32(&buffer[i]));
++}
++
+ static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum)
+ {
+     uint32_t atapi_buffer[4];
+@@ -1112,16 +1141,9 @@
+     uint32_t status, value;
+     int i, len;
+ 
+-    /* select drive */
+-    if (bd->drv == 0)
+-        ide_port_write(bd, 0x06, 0x40);
+-    else
+-        ide_port_write(bd, 0x06, 0x50);
+     len = mmc_read12_req(atapi_buffer, secnum, 1);
+     atapi_pad_req(&atapi_buffer, len);
+-    ide_port_write(bd, 0x07, 0xA0);
+-    for (i = 0; i < 3; i++)
+-        ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
++    atapi_make_req(bd, atapi_buffer, bd->seclen);
+     status = ide_port_read(bd, 0x07);
+     if (status != 0x48) {
+         ERROR("ATAPI READ12 : status %0x != 0x48\n", status);
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/apple.c OpenHackWare-release-0.4/src/libpart/apple.c
+--- OpenHackWare-release-0.4.org/src/libpart/apple.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/libpart/apple.c	2005-07-03 16:17:41.000000000 +0200
+@@ -199,14 +199,18 @@
+         if (len == 0) {
+             /* Place holder. Skip it */
+             DPRINTF("%s placeholder part\t%d\n", __func__, i);
++            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
++            part_register(bd, part, name, i);
+         } else if (strncmp("Apple_Void", type, 32) == 0) {
+             /* Void partition. Skip it */
+             DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type);
++            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
++            part_register(bd, part, name, i);
+         } else if (strncmp("Apple_Free", type, 32) == 0) {
+             /* Free space. Skip it */
+             DPRINTF("%s Free part (%d)\n", __func__, i);
+             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
+-            part_register(bd, part, name);
++            part_register(bd, part, name, i);
+         } else if (strncmp("Apple_partition_map", type, 32) == 0 ||
+                    strncmp("Apple_Partition_Map", type, 32) == 0
+ #if 0 // Is this really used or is it just a mistake ?
+@@ -226,7 +230,7 @@
+                  */
+             }
+             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
+-            part_register(bd, part, name);
++            part_register(bd, part, name, i);
+         } else if (strncmp("Apple_Driver", type, 32) == 0 ||
+                    strncmp("Apple_Driver43", type, 32) == 0 ||
+                    strncmp("Apple_Driver43_CD", type, 32) == 0 ||
+@@ -236,8 +240,12 @@
+                    strncmp("Apple_Driver_IOKit", type, 32) == 0) {
+             /* Drivers. don't care for now */
+             DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type);
++            part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER;
++            part_register(bd, part, name, i);
+         } else if (strncmp("Apple_Patches", type, 32) == 0) {
+             /* Patches: don't care for now */
++            part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH;
++            part_register(bd, part, name, i);
+             DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type);
+         } else if (strncmp("Apple_HFS", type, 32) == 0 ||
+                    strncmp("Apple_MFS", type, 32) == 0 ||
+@@ -256,9 +264,8 @@
+             count = partmap->bloc_cnt * HFS_BLOCSIZE;
+             if (partmap->boot_size == 0 || partmap->boot_load == 0) {
+                 printf("Not a bootable partition %d %d (%p %p)\n",
+-                       partmap->boot_size, partmap->boot_load,boot_part, part);
+-                if (boot_part == NULL)
+-                    boot_part = part;
++                       partmap->boot_size, partmap->boot_load,
++                       boot_part, part);
+                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS;
+             } else {
+                 part->boot_start.bloc = partmap->boot_start;
+@@ -278,8 +285,8 @@
+                 boot_part = part;
+                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT;
+             }
+-            printf("Partition: %d %s st %0x size %0x",
+-                    i, name, partmap->start_bloc, partmap->bloc_cnt);
++            printf("Partition: %d '%s' '%s' st %0x size %0x",
++                    i, name, type, partmap->start_bloc, partmap->bloc_cnt);
+ #ifndef DEBUG
+             printf("\n");
+ #endif
+@@ -290,11 +297,13 @@
+                     part->boot_load, part->boot_entry);
+             DPRINTF("                           load %0x entry %0x %0x\n",
+                     partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE);
+-            part_register(bd, part, name);
++            part_register(bd, part, name, i);
+         } else {
+             memcpy(tmp, type, 32);
+             tmp[32] = '\0';
+             ERROR("Unknown partition type [%s]\n", tmp);
++            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
++            part_register(bd, part, name, i);
+         }
+     }
+  error:
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/core.c OpenHackWare-release-0.4/src/libpart/core.c
+--- OpenHackWare-release-0.4.org/src/libpart/core.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/libpart/core.c	2005-07-03 16:17:41.000000000 +0200
+@@ -126,7 +126,7 @@
+ }
+ 
+ int part_register (bloc_device_t *bd, part_t *partition,
+-                   const unsigned char *name)
++                   const unsigned char *name, int partnum)
+ {
+     part_t **cur;
+ 
+@@ -134,6 +134,7 @@
+     partition->bd = bd;
+     partition->next = NULL;
+     partition->name = strdup(name);
++    partition->partnum = partnum;
+     for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next)
+         continue;
+     *cur = partition;
+@@ -141,29 +142,15 @@
+     return 0;
+ }
+ 
+-static inline int set_boot_part (bloc_device_t *bd, int partnum)
+-{
+-    part_t *cur;
+-
+-    cur = part_get(bd, partnum);
+-    if (cur == NULL)
+-        return -1;
+-    bd_set_boot_part(bd, cur);
+-
+-    return 0;
+-}
+-
+ part_t *part_get (bloc_device_t *bd, int partnum)
+ {
+     part_t **listp, *cur;
+-    int i;
+ 
+     listp = _bd_parts(bd);
+-    cur = *listp;
+-    for (i = 0; i != partnum; i++) {
+-        if (cur == NULL)
++    
++    for (cur = *listp; cur != NULL; cur = cur->next) {
++        if (cur->partnum == partnum)
+             break;
+-        cur = cur->next;
+     }
+     
+     return cur;
+@@ -192,17 +179,20 @@
+     part_set_blocsize(bd, part, 512);
+     part->bd = bd;
+     part->flags = PART_TYPE_RAW | PART_FLAG_BOOT;
+-    part_register(bd, part, "Raw");
++    part_register(bd, part, "Raw", 0);
+ 
+     return part;
+ }
+ 
++bloc_device_t *part_get_bd (part_t *part)
++{
++    return part->bd;
++}
++
+ part_t *part_probe (bloc_device_t *bd, int set_raw)
+ {
+-    part_t *part0, *boot_part, **cur;
++    part_t *part0 = NULL, *boot_part, **cur;
+ 
+-    /* Register the 0 partition: raw partition containing the whole disk */
+-    part0 = part_get_raw(bd);
+     /* Try to find a valid boot partition */
+     boot_part = Apple_probe_partitions(bd);
+     if (boot_part == NULL) {
+@@ -210,10 +200,13 @@
+         if (boot_part == NULL && arch == ARCH_PREP)
+             boot_part = PREP_find_partition(bd);
+         if (boot_part == NULL && set_raw != 0) {
+-            boot_part = part0;
+-            set_boot_part(bd, 0);
++            dprintf("Use bloc device as raw partition\n");
+         }
+     }
++    if (_bd_parts(bd) == NULL) {
++        /* Register the 0 partition: raw partition containing the whole disk */
++        part0 = part_get_raw(bd);
++    }
+     /* Probe filesystem on each found partition */
+     for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) {
+         const unsigned char *map, *type;
+@@ -248,23 +241,28 @@
+             type = "unknown";
+             break;
+         }
+-        DPRINTF("Probe filesystem on %s %s partition '%s' %s\n",
++        dprintf("Probe filesystem on %s %s partition '%s' %s %p\n",
+                 type, map, (*cur)->name,
+-                ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "");
++                ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "", *cur);
+         if (((*cur)->flags) & PART_FLAG_FS) {
+             if (((*cur)->flags) & PART_FLAG_BOOT)
+                 (*cur)->fs = fs_probe(*cur, 1);
+             else
+                 (*cur)->fs = fs_probe(*cur, 0);
++        } else if (((*cur)->flags) & PART_TYPE_RAW) {
++            (*cur)->fs = fs_probe(*cur, 2);
+         } else {
+             (*cur)->fs = fs_probe(*cur, 2);
+         }
+-        if (((*cur)->flags) & PART_FLAG_BOOT) {
+-            bd_set_boot_part(bd, *cur);
+             fs_get_bootfile((*cur)->fs);
++        if (((*cur)->flags) & PART_FLAG_BOOT) {
++            dprintf("Partition is bootable (%d)\n", (*cur)->partnum);
++            bd_set_boot_part(bd, *cur, (*cur)->partnum);
++            if (boot_part == NULL)
++                boot_part = *cur;
+         }
+     }
+-    DPRINTF("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs,
++    dprintf("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs,
+             part_fs(boot_part), part0);
+ 
+     return boot_part;
+@@ -279,6 +277,7 @@
+     part->boot_size.offset = 0;
+     part->boot_load = 0;
+     part->boot_entry = 0;
++    part->flags |= PART_FLAG_BOOT;
+ 
+     return 0;
+ }
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/isofs.c OpenHackWare-release-0.4/src/libpart/isofs.c
+--- OpenHackWare-release-0.4.org/src/libpart/isofs.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/libpart/isofs.c	2005-07-03 16:17:41.000000000 +0200
+@@ -242,7 +242,7 @@
+                    part->boot_start.bloc, part->boot_size.bloc,
+                    part->boot_load, part->boot_entry);
+             part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT;
+-            part_register(bd, part, name);
++            part_register(bd, part, name, i + 1);
+             fs_raw_set_bootfile(part, part->boot_start.bloc,
+                                 part->boot_start.offset,
+                                 part->boot_size.bloc,
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/libpart.h OpenHackWare-release-0.4/src/libpart/libpart.h
+--- OpenHackWare-release-0.4.org/src/libpart/libpart.h	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/libpart/libpart.h	2005-07-03 16:17:41.000000000 +0200
+@@ -30,6 +30,7 @@
+ 
+ struct part_t {
+     bloc_device_t *bd;
++    int partnum;
+     uint32_t start;      /* Partition first bloc             */
+     uint32_t size;       /* Partition size, in blocs         */
+     uint32_t spb;
+@@ -54,7 +55,7 @@
+ };
+ 
+ int part_register (bloc_device_t *bd, part_t *partition,
+-                   const unsigned char *name);
++                   const unsigned char *name, int partnum);
+ void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize);
+ void part_private_set (part_t *part, void *private);
+ void *part_private_get (part_t *part);
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/prep.c OpenHackWare-release-0.4/src/libpart/prep.c
+--- OpenHackWare-release-0.4.org/src/libpart/prep.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/libpart/prep.c	2005-07-03 16:17:41.000000000 +0200
+@@ -164,7 +164,7 @@
+             part->boot_load = 0;
+             part->boot_entry = boot_offset - part->bloc_size;
+             part->flags = PART_TYPE_PREP | PART_FLAG_BOOT;
+-            part_register(bd, part, "PREP boot");
++            part_register(bd, part, "PREP boot", i);
+             fs_raw_set_bootfile(part, part->boot_start.bloc,
+                                 part->boot_start.offset,
+                                 part->boot_size.bloc,
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/main.c OpenHackWare-release-0.4/src/main.c
+--- OpenHackWare-release-0.4.org/src/main.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/main.c	2005-06-07 23:48:39.000000000 +0200
+@@ -364,20 +364,24 @@
+     void *load_base, *load_entry, *last_alloc, *load_end;
+     uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size;
+     uint32_t boot_base, boot_nb;
+-    int boot_device;
++    int boot_device, i;
++    static const uint32_t isa_base_tab[3] = {
++        0x80000000, /* PREP */
++        0xFE000000, /* Grackle (Heathrow) */
++        0xF2000000, /* UniNorth (Mac99)  */
++    };
+ 
+     /* Retrieve NVRAM configuration */
+- nvram_retry:
++    for(i = 0; i < 3; i++) {
++        isa_io_base = isa_base_tab[i];
+     nvram = NVRAM_get_config(&memsize, &boot_device,
+                              &boot_image, &boot_image_size,
+                              &cmdline, &cmdline_size,
+                              &ramdisk, &ramdisk_size);
+-    if (nvram == NULL) {
+-        /* Retry with another isa_io_base */
+-        if (isa_io_base == 0x80000000) {
+-            isa_io_base = 0xF2000000;
+-            goto nvram_retry;
++        if (nvram)
++            break;
+         }
++    if (i == 3) {
+         ERROR("Unable to load configuration from NVRAM. Aborting...\n");
+         return -1;
+     }
+@@ -402,7 +406,7 @@
+         cpu_name = CPU_get_name(pvr);
+         OF_register_cpu(cpu_name, 0, pvr,
+                         200 * 1000 * 1000, 200 * 1000 * 1000,
+-                        100 * 1000 * 1000, 10 * 1000 * 1000,
++                        100 * 1000 * 1000, 100 * 1000 * 1000,
+                         0x0092);
+     }
+     OF_register_memory(memsize, 512 * 1024 /* TOFIX */);
+@@ -433,9 +437,12 @@
+     vga_puts(copyright);
+     vga_puts("\n");
+ 
++#if 0
+     /* QEMU is quite incoherent: d is cdrom, not second drive */
++    /* XXX: should probe CD-ROM position */
+     if (boot_device == 'd')
+         boot_device = 'e';
++#endif
+     /* Open boot device */
+     boot_part = bd_probe(boot_device);
+     if (boot_device == 'm') {
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/nvram.c OpenHackWare-release-0.4/src/nvram.c
+--- OpenHackWare-release-0.4.org/src/nvram.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/nvram.c	2005-06-04 23:44:03.000000000 +0200
+@@ -334,6 +334,7 @@
+         ret = NVRAM_chrp_format(nvram);
+         break;
+     case ARCH_MAC99:
++    case ARCH_HEATHROW: /* XXX: may be incorrect */
+         ret = NVRAM_mac99_format(nvram);
+         break;
+     case ARCH_POP:
+@@ -409,13 +410,12 @@
+         arch = ARCH_MAC99;
+     } else if (strcmp(sign, "POP") == 0) {
+         arch = ARCH_POP;
++    } else if (strcmp(sign, "HEATHROW") == 0) {
++        arch = ARCH_HEATHROW;
+     } else {
+         ERROR("Unknown PPC architecture: '%s'\n", sign);
+         return NULL;
+     }
+-    /* HACK */
+-    if (arch == ARCH_CHRP)
+-        arch = ARCH_MAC99;
+     lword = NVRAM_get_lword(nvram, 0x30);
+     *RAM_size = lword;
+     byte = NVRAM_get_byte(nvram, 0x34);
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/of.c OpenHackWare-release-0.4/src/of.c
+--- OpenHackWare-release-0.4.org/src/of.c	2005-04-06 23:17:26.000000000 +0200
++++ OpenHackWare-release-0.4/src/of.c	2005-07-07 23:30:08.000000000 +0200
+@@ -489,7 +489,7 @@
+         ERROR("%s can't alloc new node '%s' name\n", __func__, name);
+         return NULL;
+     }
+-    new->prop_address = OF_prop_int_new(env, new, "address", address);
++    new->prop_address = OF_prop_int_new(env, new, "unit-address", address);
+     if (new->prop_address == NULL) {
+         free(new->prop_name->value);
+         free(new->prop_name);
+@@ -1017,6 +1017,33 @@
+                            string, strlen(string) + 1);
+ }
+ 
++/* convert '\1' char to '\0' */
++static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node,
++                                       const unsigned char *name,
++                                       const unsigned char *string)
++{
++    int len, i;
++    OF_prop_t *ret;
++    unsigned char *str;
++
++    if (strchr(string, '\1') == NULL) {
++        return OF_prop_string_new(env, node, name, string);
++    } else {
++        len = strlen(string) + 1;
++        str = malloc(len);
++        if (!str)
++            return NULL;
++        memcpy(str, string, len);
++        for(i = 0; i < len; i++)
++            if (str[i] == '\1')
++                str[i] = '\0';
++        ret = OF_property_new(env, node, name,
++                              str, len);
++        free(str);
++        return ret;
++    }
++}
++
+ __attribute__ (( section (".OpenFirmware") ))
+ static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
+                                    const unsigned char *name, uint32_t value)
+@@ -1421,15 +1448,12 @@
+ __attribute__ (( section (".OpenFirmware") ))
+ int OF_init (void)
+ {
+-    const unsigned char compat_str[] =
+ #if 0
+         "PowerMac3,1\0MacRISC\0Power Macintosh\0";
+         "PowerMac1,2\0MacRISC\0Power Macintosh\0";
+         "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
+         "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0";
+         "AAPL,Gossamer\0MacRISC\0Power Macintosh\0";
+-#else
+-        "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
+ #endif
+     OF_env_t *OF_env;
+     OF_node_t *als, *opt, *chs, *pks;
+@@ -1455,15 +1479,21 @@
+         return -1;
+     }
+     OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom");
+-#if 0
+-    OF_prop_string_new(OF_env, OF_node_root,
+-                       "model", "PPC Open Hack'Ware " BIOS_VERSION);
+-#else
++    if (arch == ARCH_HEATHROW) {
++        const unsigned char compat_str[] =
++            "PowerMac1,1\0MacRISC\0Power Macintosh";
++        OF_property_new(OF_env, OF_node_root, "compatible",
++                        compat_str, sizeof(compat_str));
+     OF_prop_string_new(OF_env, OF_node_root,
+-                       "model", compat_str);
+-#endif
++                           "model", "Power Macintosh");
++    } else {
++        const unsigned char compat_str[] =
++            "PowerMac3,1\0MacRISC\0Power Macintosh";
+     OF_property_new(OF_env, OF_node_root, "compatible",
+                     compat_str, sizeof(compat_str));
++        OF_prop_string_new(OF_env, OF_node_root,
++                           "model", "PowerMac3,1");
++    }
+ #if 0
+     OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright);
+ #else
+@@ -1561,14 +1591,15 @@
+         range.size = 0x00800000;
+         OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t));
+         OF_prop_int_new(OF_env, rom, "#address-cells", 1);
++
+         /* "/rom/boot-rom at fff00000" node */
+-        brom = OF_node_new(OF_env, OF_node_root, "boot-rom", 0xfff00000);
++        brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000);
+         if (brom == NULL) {
+             ERROR("Cannot create 'boot-rom'\n");
+             return -1;
+         }
+         regs.address = 0xFFF00000;
+-        regs.size = 0x00010000;
++        regs.size = 0x00100000;
+         OF_property_new(OF_env, brom, "reg", &regs, sizeof(OF_regprop_t));
+         OF_prop_string_new(OF_env, brom, "write-characteristic", "flash");
+         OF_prop_string_new(OF_env, brom, "BootROM-build-date",
+@@ -1577,7 +1608,7 @@
+         OF_prop_string_new(OF_env, brom, "copyright", copyright);
+         OF_prop_string_new(OF_env, brom, "model", BIOS_str);
+         OF_prop_int_new(OF_env, brom, "result", 0);
+-#if 0
++#if 1
+         {
+             /* Hack taken 'as-is' from PearPC */
+             unsigned char info[] = {
+@@ -1596,7 +1627,9 @@
+         OF_node_put(OF_env, brom);
+         OF_node_put(OF_env, rom);
+     }
++#if 0
+     /* From here, hardcoded hacks to get a Mac-like machine */
++    /* XXX: Core99 does not seem to like this NVRAM tree */
+     /* "/nvram at fff04000" node */
+     {
+         OF_regprop_t regs;
+@@ -1617,6 +1650,7 @@
+         OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr));
+         OF_node_put(OF_env, nvr);
+     }
++#endif
+     /* "/pseudo-hid" : hid emulation as Apple does */
+     {
+         OF_node_t *hid;
+@@ -1663,7 +1697,27 @@
+         }
+         OF_node_put(OF_env, hid);
+     }
++    if (arch == ARCH_MAC99) {
++        OF_node_t *unin;
++        OF_regprop_t regs;
+ 
++        unin = OF_node_new(OF_env, OF_node_root,
++                           "uni-n", 0xf8000000);
++        if (unin == NULL) {
++            ERROR("Cannot create 'uni-n'\n");
++            return -1;
++        }
++        OF_prop_string_new(OF_env, unin, "device-type", "memory-controller");
++        OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth");
++        OF_prop_string_new(OF_env, unin, "compatible", "uni-north");
++        regs.address = 0xf8000000;
++        regs.size = 0x01000000;
++        OF_property_new(OF_env, unin, "reg", &regs, sizeof(regs));
++        OF_prop_int_new(OF_env, unin, "#address-cells", 1);
++        OF_prop_int_new(OF_env, unin, "#size-cells", 1);
++        OF_prop_int_new(OF_env, unin, "device-rev", 3);
++        OF_node_put(OF_env, unin);
++    }
+     
+ #if 1 /* This is mandatory for claim to work
+        * but I don't know where it should really be (in cpu ?)
+@@ -1693,7 +1747,9 @@
+ 
+     /* "/options/boot-args" node */
+     {
+-        const unsigned char *args = "-v rootdev cdrom";
++        //        const unsigned char *args = "-v rootdev cdrom";
++        //const unsigned char *args = "-v io=0xffffffff";
++        const unsigned char *args = "-v";
+         /* Ask MacOS X to print debug messages */
+         //        OF_prop_string_new(OF_env, chs, "machargs", args);
+         //        OF_prop_string_new(OF_env, opt, "boot-command", args);
+@@ -2013,17 +2069,17 @@
+     OF_prop_int_new(OF_env, node, "min-grant", min_grant);
+     OF_prop_int_new(OF_env, node, "max-latency", max_latency);
+     if (dev->type != NULL)
+-        OF_prop_string_new(OF_env, node, "device_type", dev->type);
++        OF_prop_string_new1(OF_env, node, "device_type", dev->type);
+     if (dev->compat != NULL)
+-        OF_prop_string_new(OF_env, node, "compatible", dev->compat);
++        OF_prop_string_new1(OF_env, node, "compatible", dev->compat);
+     if (dev->model != NULL)
+-        OF_prop_string_new(OF_env, node, "model", dev->model);
++        OF_prop_string_new1(OF_env, node, "model", dev->model);
+     if (dev->acells != 0)
+         OF_prop_int_new(OF_env, node, "#address-cells", dev->acells);
+     if (dev->scells != 0)
+-        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->acells);
++        OF_prop_int_new(OF_env, node, "#size-cells", dev->scells);
+     if (dev->icells != 0)
+-        OF_prop_int_new(OF_env, node, "#size-cells", dev->acells);
++        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells);
+     dprintf("Done %p %p\n", parent, node);
+     
+     return node;
+@@ -2040,8 +2096,9 @@
+     OF_env_t *OF_env;
+     pci_range_t ranges[3];
+     OF_regprop_t regs[1];
+-    OF_node_t *pci_host;
++    OF_node_t *pci_host, *als;
+     int nranges;
++    unsigned char buffer[OF_NAMELEN_MAX];
+ 
+     OF_env = OF_env_main;
+     dprintf("register PCI host '%s' '%s' '%s' '%s'\n",
+@@ -2052,6 +2109,17 @@
+         ERROR("Cannot create pci host\n");
+         return NULL;
+     }
++    
++    als = OF_node_get(OF_env, "aliases");
++    if (als == NULL) {
++        ERROR("Cannot get 'aliases'\n");
++        return NULL;
++    }
++    sprintf(buffer, "/%s", dev->name);
++    OF_prop_string_set(OF_env, als, "pci", buffer);
++    OF_node_put(OF_env, als);
++    
++
+     regs[0].address = cfg_base;
+     regs[0].size = cfg_len;
+     OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t));
+@@ -2136,6 +2204,11 @@
+     return pci_dev;
+ }
+ 
++/* XXX: suppress that, used for interrupt map init */
++OF_node_t *pci_host_node;
++uint32_t pci_host_interrupt_map[7 * 32];
++int pci_host_interrupt_map_len = 0;
++
+ void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses)
+ {
+     OF_env_t *OF_env;
+@@ -2145,10 +2218,12 @@
+     regs[0].address = first_bus;
+     regs[0].size = nb_busses;
+     OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t));
++    pci_host_node = dev;
+ }
+ 
+ void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
+-                             uint32_t *regions, uint32_t *sizes)
++                             uint32_t *regions, uint32_t *sizes,
++                             int irq_line)
+ {
+     OF_env_t *OF_env;
+     pci_reg_prop_t pregs[6], rregs[6];
+@@ -2156,6 +2231,7 @@
+     int i, j, k;
+ 
+     OF_env = OF_env_main;
++    /* XXX: only useful for VGA card in fact */
+     if (regions[0] != 0x00000000)
+         OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F);
+     for (i = 0, j = 0, k = 0; i < 6; i++) {
+@@ -2222,7 +2298,22 @@
+     } else {
+         OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0);
+     }
+-#if 0
++    if (irq_line >= 0) {
++        int i;
++        OF_prop_int_new(OF_env, dev, "interrupts", 1);
++        i = pci_host_interrupt_map_len;
++        pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800;
++        pci_host_interrupt_map[i++] = 0;
++        pci_host_interrupt_map[i++] = 0;
++        pci_host_interrupt_map[i++] = 0;
++        pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */
++        pci_host_interrupt_map[i++] = irq_line;
++        if (arch != ARCH_HEATHROW) {
++            pci_host_interrupt_map[i++] = 1;
++        }
++        pci_host_interrupt_map_len = i;
++    }
++#if 1
+     {
+         OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name;
+ 
+@@ -2390,6 +2481,54 @@
+     return 0;
+ }
+ 
++static void keylargo_ata(OF_node_t *mio, uint32_t base_address,
++                         uint32_t base, int irq1, int irq2, 
++                         uint16_t pic_phandle)
++{
++    OF_env_t *OF_env = OF_env_main;
++    OF_node_t *ata;
++    OF_regprop_t regs[2];
++
++    ata = OF_node_new(OF_env, mio, "ata-4", base);
++    if (ata == NULL) {
++        ERROR("Cannot create 'ata-4'\n");
++        return;
++    }
++    OF_prop_string_new(OF_env, ata, "device_type", "ata");
++#if 1
++    OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata");
++    OF_prop_string_new(OF_env, ata, "model", "ata-4");
++    OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor");
++#else
++    OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
++    OF_prop_string_new(OF_env, ata, "model", "ata-4");
++#endif
++    OF_prop_int_new(OF_env, ata, "#address-cells", 1);
++    OF_prop_int_new(OF_env, ata, "#size-cells", 0);
++    regs[0].address = base;
++    regs[0].size = 0x00001000;
++#if 0 // HACK: Don't set up DMA registers
++    regs[1].address = 0x00008A00;
++    regs[1].size = 0x00001000;
++    OF_property_new(OF_env, ata, "reg",
++                    regs, 2 * sizeof(OF_regprop_t));
++#else
++    OF_property_new(OF_env, ata, "reg",
++                    regs, sizeof(OF_regprop_t));
++#endif
++    OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
++    regs[0].address = irq1;
++    regs[0].size = 0x00000001;
++    regs[1].address = irq2;
++    regs[1].size = 0x00000000;
++    OF_property_new(OF_env, ata, "interrupts",
++                    regs, 2 * sizeof(OF_regprop_t));
++    if (base == 0x1f000)
++        ide_pci_pmac_register(base_address + base, 0x00000000, ata);
++    else
++        ide_pci_pmac_register(0x00000000, base_address + base, ata);
++}
++
+ void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
+                             void *private_data)
+ {
+@@ -2398,6 +2537,8 @@
+     pci_reg_prop_t pregs[2];
+     OF_node_t *mio, *chs, *als;
+     uint16_t pic_phandle;
++    int rec_len;
++    OF_prop_t *mio_reg;
+ 
+     OF_DPRINTF("mac-io: %p\n", dev);
+     OF_env = OF_env_main;
+@@ -2416,10 +2557,14 @@
+     mio = dev;
+     mio->private_data = private_data;
+     pregs[0].addr.hi = 0x00000000;
+-    pregs[0].addr.mid = 0x82013810;
++    pregs[0].addr.mid = 0x00000000;
+     pregs[0].addr.lo = 0x00000000;
+     pregs[0].size_hi = base_address;
+     pregs[0].size_lo = size;
++    mio_reg = OF_property_get(OF_env, mio, "reg");
++    if (mio_reg && mio_reg->vlen >= 5 * 4) {
++        pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi;
++    }
+     OF_property_new(OF_env, mio, "ranges",
+                     &pregs, sizeof(pci_reg_prop_t));
+ #if 0
+@@ -2431,8 +2576,32 @@
+     OF_property_new(OF_env, mio, "assigned-addresses",
+                     &pregs, sizeof(pci_reg_prop_t));
+ #endif
++
++    if (arch == ARCH_HEATHROW) {
++        /* Heathrow PIC */
++        OF_regprop_t regs;
++        OF_node_t *mpic;
++        const char compat_str[] = "heathrow\0mac-risc";
++
++        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10);
++        if (mpic == NULL) {
++            ERROR("Cannot create 'mpic'\n");
++            goto out;
++        }
++        OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller");
++        OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str));
++        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1);
++        regs.address = 0x10;
++        regs.size = 0x20;
++        OF_property_new(OF_env, mpic, "reg",
++                        &regs, sizeof(regs));
++        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0);
++        pic_phandle = OF_pack_handle(OF_env, mpic);
++        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
++        OF_node_put(OF_env, mpic);
++        rec_len = 6;
++    } else {
+     /* OpenPIC */
+-    {
+         OF_regprop_t regs[4];
+         OF_node_t *mpic;
+         mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000);
+@@ -2455,8 +2624,37 @@
+         pic_phandle = OF_pack_handle(OF_env, mpic);
+         OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
+         OF_node_put(OF_env, mpic);
++        rec_len = 7;
+     }
+-#if 1
++
++    /* patch pci host table */
++    /* XXX: do it after the PCI init */
++    {
++        int i;
++        uint32_t tab[4];
++
++        for(i = 0; i < pci_host_interrupt_map_len; i += rec_len)
++            pci_host_interrupt_map[i + 4] = pic_phandle;
++#if 0
++        dprintf("interrupt-map:\n");
++        for(i = 0; i < pci_host_interrupt_map_len; i++) {
++            dprintf(" %08x", pci_host_interrupt_map[i]);
++            if ((i % rec_len) == (rec_len - 1))
++                dprintf("\n");
++        }
++        dprintf("\n");
++#endif
++        OF_property_new(OF_env, pci_host_node, "interrupt-map", 
++                        pci_host_interrupt_map, 
++                        pci_host_interrupt_map_len * sizeof(uint32_t));
++        tab[0] = 0xf800;
++        tab[1] = 0;
++        tab[2] = 0;
++        tab[3] = 0;
++        OF_property_new(OF_env, pci_host_node, "interrupt-map-mask", 
++                        tab, 4 * sizeof(uint32_t));
++    }
++#if 0
+     /* escc is usefull to get MacOS X debug messages */
+     {
+         OF_regprop_t regs[8];
+@@ -2645,85 +2843,12 @@
+         OF_node_put(OF_env, scc);
+     }
+ #endif
+-    /* IDE controller */
+-    {
+-        OF_node_t *ata;
+-        OF_regprop_t regs[2];
+-        ata = OF_node_new(OF_env, mio, "ata-4", 0x1f000);
+-        if (ata == NULL) {
+-            ERROR("Cannot create 'ata-4'\n");
+-            goto out;
+-        }
+-        OF_prop_string_new(OF_env, ata, "device_type", "ata");
+-#if 1
+-        OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
+-        OF_prop_string_new(OF_env, ata, "model", "ata-4");
+-#else
+-        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+-        OF_prop_string_new(OF_env, ata, "model", "ata-4");
+-#endif
+-        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+-        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+-        regs[0].address = 0x0001F000;
+-        regs[0].size = 0x00001000;
+-#if 0 // HACK: Don't set up DMA registers
+-        regs[1].address = 0x00008A00;
+-        regs[1].size = 0x00001000;
+-        OF_property_new(OF_env, ata, "reg",
+-                        regs, 2 * sizeof(OF_regprop_t));
+-#else
+-        OF_property_new(OF_env, ata, "reg",
+-                        regs, sizeof(OF_regprop_t));
+-#endif
+-        OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
+-        regs[0].address = 0x00000013;
+-        regs[0].size = 0x00000001;
+-        regs[1].address = 0x0000000B;
+-        regs[1].size = 0x00000000;
+-        OF_property_new(OF_env, ata, "interrupts",
+-                        regs, 2 * sizeof(OF_regprop_t));
+-        ide_pci_pmac_register(base_address + 0x1f000, 0x00000000, ata);
+-
+-    }
+-    {
+-        OF_node_t *ata;
+-        OF_regprop_t regs[2];
+-        ata = OF_node_new(OF_env, mio, "ata-4", 0x20000);
+-        if (ata == NULL) {
+-            ERROR("Cannot create 'ata-4'\n");
+-            goto out;
+-        }
+-        OF_prop_string_new(OF_env, ata, "device_type", "ata");
+-#if 1
+-        OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
+-        OF_prop_string_new(OF_env, ata, "model", "ata-4");
+-#else
+-        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+-        OF_prop_string_new(OF_env, ata, "model", "ata-4");
+-#endif
+-        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+-        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+-        regs[0].address = 0x00020000;
+-        regs[0].size = 0x00001000;
+-#if 0 // HACK: Don't set up DMA registers
+-        regs[1].address = 0x00008A00;
+-        regs[1].size = 0x00001000;
+-        OF_property_new(OF_env, ata, "reg",
+-                        regs, 2 * sizeof(OF_regprop_t));
+-#else
+-        OF_property_new(OF_env, ata, "reg",
+-                        regs, sizeof(OF_regprop_t));
+-#endif
+-        OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
+-        regs[0].address = 0x00000014;
+-        regs[0].size = 0x00000001;
+-        regs[1].address = 0x0000000B;
+-        regs[1].size = 0x00000000;
+-        OF_property_new(OF_env, ata, "interrupts",
+-                        regs, 2 * sizeof(OF_regprop_t));
+-        ide_pci_pmac_register(0x00000000, base_address + 0x20000, ata);
+-
++    /* Keylargo IDE controller: need some work (DMA problem ?) */
++    if (arch == ARCH_MAC99) {
++        keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle);
++        keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle);
+     }
++#if 0
+     /* Timer */
+     {
+         OF_node_t *tmr;
+@@ -2746,10 +2871,11 @@
+                         regs, sizeof(OF_regprop_t));
+         OF_node_put(OF_env, tmr);
+     }
++#endif
+     /* VIA-PMU */
+     {
+         /* Controls adb, RTC and power-mgt (forget it !) */
+-        OF_node_t *via, *adb, *rtc;
++        OF_node_t *via, *adb;
+         OF_regprop_t regs[1];
+ #if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD !
+       // (but needed has Qemu doesn't emulate via-pmu).
+@@ -2773,14 +2899,21 @@
+         regs[0].size = 0x00002000;
+         OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t));
+         OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle);
++        if (arch == ARCH_HEATHROW) {
++            OF_prop_int_new(OF_env, via, "interrupts", 0x12);
++        } else {
+         regs[0].address = 0x00000019;
+         regs[0].size = 0x00000001;
+         OF_property_new(OF_env, via, "interrupts",
+                         regs, sizeof(OF_regprop_t));
++        }
++        /* force usage of OF bus speeds */
++        OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1);
+ #if 0
+         OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C);
+ #endif
+-#if 1
++        {
++            OF_node_t *kbd, *mouse;
+         /* ADB pseudo-device */
+         adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE);
+         if (adb == NULL) {
+@@ -2797,9 +2930,26 @@
+         OF_prop_int_new(OF_env, adb, "#size-cells", 0);
+         OF_pack_get_path(OF_env, tmp, 512, adb);
+         OF_prop_string_new(OF_env, als, "adb", tmp);
+-        /* XXX: add "keyboard at 2" and "mouse at 3" */
+-        OF_node_put(OF_env, adb);
+-#endif
++
++            kbd = OF_node_new(OF_env, adb, "keyboard", 2);
++            if (kbd == NULL) {
++                ERROR("Cannot create 'kbd'\n");
++                goto out;
++            }
++            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
++            OF_prop_int_new(OF_env, kbd, "reg", 2);
++
++            mouse = OF_node_new(OF_env, adb, "mouse", 3);
++            if (mouse == NULL) {
++                ERROR("Cannot create 'mouse'\n");
++                goto out;
++            }
++            OF_prop_string_new(OF_env, mouse, "device_type", "mouse");
++            OF_prop_int_new(OF_env, mouse, "reg", 3);
++            OF_prop_int_new(OF_env, mouse, "#buttons", 3);
++        }
++        {
++            OF_node_t *rtc;
+         
+         rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE);
+         if (rtc == NULL) {
+@@ -2813,14 +2963,68 @@
+         OF_prop_string_new(OF_env, rtc, "compatible", "rtc");
+ #endif
+         OF_node_put(OF_env, rtc);
+-        OF_node_put(OF_env, via);
+     }
++        //        OF_node_put(OF_env, via);
++    }
++    {
++        OF_node_t *pmgt;
++        pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE);
++        OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt");
++        OF_prop_string_new(OF_env, pmgt, "compatible", "cuda");
++        OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led");
++        OF_node_put(OF_env, pmgt);
++    }
++
++    if (arch == ARCH_HEATHROW) {
++        /* NVRAM */
++        OF_node_t *nvr;
++        OF_regprop_t regs;
++        nvr = OF_node_new(OF_env, mio, "nvram", 0x60000);
++        OF_prop_string_new(OF_env, nvr, "device_type", "nvram");
++        regs.address = 0x60000;
++        regs.size = 0x00020000;
++        OF_property_new(OF_env, nvr, "reg", &regs, sizeof(regs));
++        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000);
++        OF_node_put(OF_env, nvr);
++    }
++
+  out:
+     //    OF_node_put(OF_env, mio);
+     OF_node_put(OF_env, chs);
+     OF_node_put(OF_env, als);
+ }
+ 
++void OF_finalize_pci_ide (void *dev, 
++                          uint32_t io_base0, uint32_t io_base1,
++                          uint32_t io_base2, uint32_t io_base3)
++{
++    OF_env_t *OF_env = OF_env_main;
++    OF_node_t *pci_ata = dev;
++    OF_node_t *ata, *atas[2];
++    int i;
++
++    OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1);
++    OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0);
++
++    /* XXX: Darwin handles only one device */
++    for(i = 0; i < 1; i++) {
++        ata = OF_node_new(OF_env, pci_ata, "ata-4", i);
++        if (ata == NULL) {
++            ERROR("Cannot create 'ata-4'\n");
++            return;
++        }
++        OF_prop_string_new(OF_env, ata, "device_type", "ata");
++        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
++        OF_prop_string_new(OF_env, ata, "model", "ata-4");
++        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
++        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
++        OF_prop_int_new(OF_env, ata, "reg", i);
++        atas[i] = ata;
++    }
++    ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3,
++                        atas[0], atas[1]);
++}
++
+ /*****************************************************************************/
+ /* Fake package */
+ static void OF_method_fake (OF_env_t *OF_env)
+@@ -2862,11 +3066,11 @@
+     /* As we get a 1:1 mapping, do nothing */
+     ihandle = popd(OF_env);
+     args = (void *)popd(OF_env);
+-    address = popd(OF_env);
+-    virt = popd(OF_env);
+-    size = popd(OF_env);
+     popd(OF_env);
+-    OF_DPRINTF("Translate address %0x %0x %0x %0x\n", ihandle, address,
++    size = popd(OF_env);
++    virt = popd(OF_env);
++    address = popd(OF_env);
++    OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address,
+                virt, size);
+     pushd(OF_env, 0);
+ }
+@@ -3270,7 +3474,7 @@
+     OF_prop_string_new(OF_env, dsk, "device_type", "block");
+     OF_prop_string_new(OF_env, dsk, "category", type);
+     OF_prop_int_new(OF_env, dsk, "device_id", devnum);
+-    OF_prop_int_new(OF_env, dsk, "reg", 0);
++    OF_prop_int_new(OF_env, dsk, "reg", devnum);
+     OF_method_new(OF_env, dsk, "open", &OF_blockdev_open);
+     OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek);
+     OF_method_new(OF_env, dsk, "read", &OF_blockdev_read);
+@@ -3432,7 +3636,8 @@
+ }
+ 
+ void OF_vga_register (const unsigned char *name, unused uint32_t address,
+-                      int width, int height, int depth)
++                      int width, int height, int depth,
++                      unsigned long vga_bios_addr, unsigned long vga_bios_size)
+ {
+     OF_env_t *OF_env;
+     unsigned char tmp[OF_NAMELEN_MAX];
+@@ -3504,6 +3709,18 @@
+     OF_prop_string_new(OF_env, als, "display", tmp);
+     OF_node_put(OF_env, als);
+     /* XXX: may also need read-rectangle */
++
++    if (vga_bios_size >= 8) {
++        const uint8_t *p;
++        int size;
++        /* check the QEMU VGA BIOS header */
++        p = (const uint8_t *)vga_bios_addr;
++        if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') {
++            size = *(uint32_t *)(p + 4);
++            OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC", 
++                            p + 8, size);
++        }
++    }
+  out:
+     OF_node_put(OF_env, disp);
+ }
+@@ -4451,7 +4668,10 @@
+         break;
+     case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */
+         /* Create "memory-map" pseudo device */
+-        popd(OF_env);
++        {
++            OF_node_t *map;
++            uint32_t phandle;
++
+         /* Find "/packages" */
+         chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen");
+         if (chs == NULL) {
+@@ -4459,10 +4679,6 @@
+             ERROR("Cannot get '/chosen'\n");
+             break;
+         }
+-        {
+-#if 1
+-            OF_node_t *map;
+-            uint32_t phandle;
+             map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE);
+             if (map == NULL) {
+                 pushd(OF_env, -1);
+@@ -4473,11 +4689,8 @@
+             OF_node_put(OF_env, map);
+             OF_node_put(OF_env, chs);
+             pushd(OF_env, phandle);
+-        }
+-#else
+-        pushd(OF_env, 0);
+-#endif
+         pushd(OF_env, 0);
++        }
+         break;
+     case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */
+         /* Return screen ihandle */
+@@ -4540,9 +4753,10 @@
+     case 0x4ad41f2d:
+         /* Yaboot: wait 10 ms: sure ! */
+         break;
++
+     default:
+         /* ERROR */
+-        printf("Script:\n%s\n", FString);
++        printf("Script: len=%d\n%s\n", (int)strlen(FString), FString);
+         printf("Call %0x NOT IMPLEMENTED !\n", crc);
+         bug();
+         break;
+@@ -4581,6 +4795,7 @@
+ {
+     OF_CHECK_NBARGS(OF_env, 0);
+     /* Should free all OF resources */
++    bd_reset_all();
+ #if defined (DEBUG_BIOS)
+     {
+         uint16_t loglevel = 0x02 | 0x10 | 0x80;
+diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/pci.c OpenHackWare-release-0.4/src/pci.c
+--- OpenHackWare-release-0.4.org/src/pci.c	2005-03-31 09:23:33.000000000 +0200
++++ OpenHackWare-release-0.4/src/pci.c	2005-07-07 23:27:37.000000000 +0200
+@@ -99,8 +99,8 @@
+     uint16_t min_grant;
+     uint16_t max_latency;
+     uint8_t  irq_line;
+-    uint32_t regions[6];
+-    uint32_t sizes[6];
++    uint32_t regions[7]; /* the region 6 is the PCI ROM */
++    uint32_t sizes[7];
+     pci_device_t *next;
+ };
+ 
+@@ -158,6 +158,7 @@
+ 
+ /* IRQ numbers assigned to PCI IRQs */
+ static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 };
++static uint8_t heathrow_pci_irqs[4] = { 0x15, 0x16, 0x17, 0x18 };
+ static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 };
+ 
+ /* PREP PCI host */
+@@ -399,6 +400,79 @@
+     &uninorth_config_readl, &uninorth_config_writel,
+ };
+ 
++/* Grackle PCI host */
++
++static uint32_t grackle_cfg_address (pci_bridge_t *bridge,
++                                     uint8_t bus, uint8_t devfn,
++                                     uint8_t offset)
++{
++    uint32_t addr;
++    addr = 0x80000000 | (bus << 16) | (devfn << 8) | (offset & 0xfc);
++    stswap32((uint32_t *)bridge->cfg_addr, addr);
++    return bridge->cfg_data + (offset & 3);
++}
++
++static uint8_t grackle_config_readb (pci_bridge_t *bridge,
++                                      uint8_t bus, uint8_t devfn,
++                                      uint8_t offset)
++{
++    uint32_t addr;
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    return *((uint8_t *)addr);
++}
++
++static void grackle_config_writeb (pci_bridge_t *bridge,
++                                    uint8_t bus, uint8_t devfn,
++                                    uint8_t offset, uint8_t val)
++{
++    uint32_t addr;
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    *((uint8_t *)addr) = val;
++}
++
++static uint16_t grackle_config_readw (pci_bridge_t *bridge,
++                                       uint8_t bus, uint8_t devfn,
++                                       uint8_t offset)
++{
++    uint32_t addr;
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    return ldswap16((uint16_t *)addr);
++}
++
++static void grackle_config_writew (pci_bridge_t *bridge,
++                                    uint8_t bus, uint8_t devfn,
++                                    uint8_t offset, uint16_t val)
++{
++    uint32_t addr;
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    stswap16((uint16_t *)addr, val);
++}
++
++static uint32_t grackle_config_readl (pci_bridge_t *bridge,
++                                       uint8_t bus, uint8_t devfn,
++                                       uint8_t offset)
++{
++    uint32_t addr;
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    return ldswap32((uint32_t *)addr);
++}
++
++static void grackle_config_writel (pci_bridge_t *bridge,
++                                    uint8_t bus, uint8_t devfn,
++                                    uint8_t offset, uint32_t val)
++{
++    uint32_t addr;
++
++    addr = grackle_cfg_address(bridge, bus, devfn, offset);
++    stswap32((uint32_t *)addr, val);
++}
++
++static pci_ops_t grackle_pci_ops = {
++    &grackle_config_readb, &grackle_config_writeb,
++    &grackle_config_readw, &grackle_config_writew,
++    &grackle_config_readl, &grackle_config_writel,
++};
++
+ static inline uint8_t pci_config_readb (pci_bridge_t *bridge,
+                                         uint8_t bus, uint8_t devfn,
+                                         uint8_t offset)
+@@ -466,12 +540,22 @@
+     },
+ };
+ 
++static int ide_config_cb2 (pci_device_t *device)
++{
++    OF_finalize_pci_ide(device->common.OF_private,
++                        device->regions[0] & ~0x0000000F,
++                        device->regions[1] & ~0x0000000F,
++                        device->regions[2] & ~0x0000000F,
++                        device->regions[3] & ~0x0000000F);
++    return 0;
++}
++
+ static pci_dev_t ide_devices[] = {
+     {
+-        0x8086, 0x0100,
+-        NULL, "Qemu IDE", "Qemu IDE",    "ide",
++        0x1095, 0x0646, /* CMD646 IDE controller */
++        "pci-ide", "pci-ata", NULL, NULL,
+         0, 0, 0,
+-        NULL, NULL,
++        ide_config_cb2, NULL,
+     },
+     {
+         0xFFFF, 0xFFFF,
+@@ -481,7 +565,9 @@
+     },
+ };
+ 
+-static int ide_config_cb (pci_device_t *device)
++#if 0
++/* should base it on PCI ID, not on arch */
++static int ide_config_cb (unused pci_device_t *device)
+ {
+     printf("Register IDE controller\n");
+     switch (arch) {
+@@ -491,14 +577,8 @@
+                               device->common.OF_private);
+         break;
+     default:
+-        ide_pci_pc_register(device->regions[0] & ~0x0000000F,
+-                            device->regions[1] & ~0x0000000F,
+-                            device->regions[2] & ~0x0000000F,
+-                            device->regions[3] & ~0x0000000F,
+-                            device->common.OF_private);
+         break;
+     }
+-
+     return 0;
+ }
+ 
+@@ -512,16 +592,12 @@
+                               device->common.OF_private);
+         break;
+     default:
+-        ide_pci_pc_register(device->regions[0] & ~0x0000000F,
+-                            device->regions[1] & ~0x0000000F,
+-                            device->regions[2] & ~0x0000000F,
+-                            device->regions[3] & ~0x0000000F,
+-                            device->common.OF_private);
+         break;
+     }
+ 
+     return 0;
+ }
++#endif
+ 
+ static pci_subclass_t mass_subclass[] = {
+     {
+@@ -530,7 +606,7 @@
+     },
+     {
+         0x01, "IDE controller",             "ide", ide_devices, NULL,
+-        &ide_config_cb, NULL,
++        NULL, NULL,
+     },
+     {
+         0x02, "Floppy disk controller",     NULL,  NULL, NULL,
+@@ -546,7 +622,7 @@
+     },
+     {
+         0x05, "ATA controller",             "ata", NULL, NULL,
+-        &ata_config_cb, NULL,
++        NULL, NULL,
+     },
+     {
+         0x80, "misc mass-storage controller", NULL, NULL, NULL,
+@@ -646,7 +722,9 @@
+         /* VGA 640x480x16 */
+         OF_vga_register(device->common.device->name,
+                         device->regions[0] & ~0x0000000F,
+-                        vga_width, vga_height, vga_depth);
++                        vga_width, vga_height, vga_depth,
++                        device->regions[6] & ~0x0000000F,
++                        device->sizes[6]);
+     }
+     vga_console_register();
+ 
+@@ -750,6 +828,13 @@
+     NULL, &PREP_pci_ops,
+ };
+ 
++pci_dev_t grackle_fake_bridge = {
++    0xFFFF, 0xFFFF,
++    "pci", "pci-bridge", "DEC,21154", "DEC,21154.pci-bridge",
++    -1, -1, -1,
++    NULL, &grackle_pci_ops,
++};
++
+ static pci_dev_t hbrg_devices[] = {
+     {
+         0x106B, 0x0020, NULL,
+@@ -758,8 +843,8 @@
+         NULL, &uninorth_agp_fake_bridge,
+     },
+     {
+-        0x106B, 0x001F,
+-        NULL, "pci", "AAPL,UniNorth", "uni-north",
++        0x106B, 0x001F, NULL, 
++        "pci", "AAPL,UniNorth", "uni-north",
+         3, 2, 1,
+         NULL, &uninorth_fake_bridge,
+     },
+@@ -770,10 +855,10 @@
+         NULL, &uninorth_fake_bridge,
+     },
+     {
+-        0x1011, 0x0026, NULL,
+-        "pci-bridge", NULL, NULL,
++        0x1057, 0x0002, "pci",
++        "pci", "MOT,MPC106", "grackle",
+         3, 2, 1,
+-        NULL, &PREP_pci_ops,
++        NULL, &grackle_fake_bridge,
+     },
+     {
+         0x1057, 0x4801, NULL,
+@@ -1443,7 +1528,14 @@
+ }
+ 
+ static const pci_dev_t misc_pci[] = {
+-    /* Apple Mac-io controller */
++    /* Paddington Mac I/O */
++    { 
++        0x106B, 0x0017,
++        "mac-io", "mac-io", "AAPL,343S1211", "paddington\1heathrow",
++        1, 1, 1,
++        &macio_config_cb, NULL,
++    },
++    /* KeyLargo Mac I/O */
+     { 
+         0x106B, 0x0022,
+         "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo",
+@@ -1599,7 +1691,7 @@
+                                       uint8_t min_grant, uint8_t max_latency,
+                                       int irq_line)
+ {
+-    uint32_t cmd;
++    uint32_t cmd, addr;
+     int i;
+ 
+     device->min_grant = min_grant;
+@@ -1611,22 +1703,28 @@
+         printf("MAP PCI device %d:%d to IRQ %d\n",
+                device->bus, device->devfn, irq_line);
+     }
+-    for (i = 0; i < 6; i++) {
++    for (i = 0; i < 7; i++) {
+         if ((device->regions[i] & ~0xF) != 0x00000000 &&
+             (device->regions[i] & ~0xF) != 0xFFFFFFF0) {
+             printf("Map PCI device %d:%d %d to %0x %0x (%s)\n",
+                    device->bus, device->devfn, i,
+                    device->regions[i], device->sizes[i],
+-                   device->regions[i] & 0x00000001 ? "I/O" : "memory");
++                   (device->regions[i] & 0x00000001) && i != 6 ? "I/O" : 
++                    "memory");
++            if (i != 6) {
+             cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04);
+             if (device->regions[i] & 0x00000001)
+                 cmd |= 0x00000001;
+             else
+                 cmd |= 0x00000002;
+             pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd);
++            }
++            if (i == 6)
++                addr = 0x30; /* PCI ROM */
++            else
++                addr = 0x10 + (i * sizeof(uint32_t));
+             pci_config_writel(bridge, device->bus, device->devfn,
+-                              0x10 + (i * sizeof(uint32_t)),
+-                              device->regions[i]);
++                              addr, device->regions[i]);
+         }
+     }
+ }
+@@ -1900,7 +1998,7 @@
+         goto out;
+     }
+     ret = (pci_u_t *)newd;
+-    max_areas = 6;
++    max_areas = 7;
+     /* register PCI device in OF tree */
+     if (bridge->dev.common.type == PCI_FAKE_BRIDGE) {
+         newd->common.OF_private =
+@@ -1927,6 +2025,9 @@
+             /* Handle 64 bits memory mapping */
+             continue;
+         }
++        if (i == 6)
++            addr = 0x30; /* PCI ROM */
++        else
+         addr = 0x10 + (i * sizeof(uint32_t));
+         /* Get region size
+          * Note: we assume it's always a power of 2
+@@ -1935,7 +2036,7 @@
+         smask = pci_config_readl(bridge, bus, devfn, addr);
+         if (smask == 0x00000000 || smask == 0xFFFFFFFF)
+             continue;
+-        if (smask & 0x00000001) {
++        if ((smask & 0x00000001) != 0 && i != 6) {
+             /* I/O space */
+             base = io_base;
+             /* Align to a minimum of 256 bytes (arbitrary) */
+@@ -1947,6 +2048,8 @@
+             /* Align to a minimum of 64 kB (arbitrary) */
+             min_align = 1 << 16;
+             amask = 0x0000000F;
++            if (i == 6)
++                smask |= 1; /* PCI ROM enable */
+         }
+         omask = smask & amask;
+         smask &= ~amask;
+@@ -1980,7 +2083,10 @@
+     if (irq_pin > 0) {
+         /* assign the IRQ */
+         irq_pin = ((devfn >> 3) + irq_pin - 1) & 3;
+-        if (arch == ARCH_PREP) {
++        /* XXX: should base it on the PCI bridge type, not the arch */
++        switch(arch) {
++        case ARCH_PREP:
++            {
+             int elcr_port, val;
+             irq_line = prep_pci_irqs[irq_pin];
+             /* set the IRQ to level-sensitive */
+@@ -1988,14 +2094,22 @@
+             val = inb(elcr_port);
+             val |= 1 << (irq_line & 7);
+             outb(elcr_port, val);
+-        } else {
++            }
++            break;
++        case ARCH_MAC99:
+             irq_line = pmac_pci_irqs[irq_pin];
++            break;
++        case ARCH_HEATHROW:
++            irq_line = heathrow_pci_irqs[irq_pin];
++            break;
++        default:
++            break;
+         }
+     }
+  update_device:
+     pci_update_device(bridge, newd, min_grant, max_latency, irq_line);
+     OF_finalize_pci_device(newd->common.OF_private, bus, devfn,
+-                           newd->regions, newd->sizes);
++                           newd->regions, newd->sizes, irq_line);
+     /* Call special inits if needed */
+     if (dev->config_cb != NULL)
+         (*dev->config_cb)(newd);
+@@ -2049,6 +2163,32 @@
+     case ARCH_CHRP:
+         /* TODO */
+         break;
++    case ARCH_HEATHROW:
++        dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
++        if (dev == NULL)
++            return -1;
++        fake_host = pci_add_host(hostp, dev,
++                                 (0x06 << 24) | (0x00 << 16) | (0xFF << 8));
++        if (fake_host == NULL)
++            return -1;
++        fake_host->dev.common.type = PCI_FAKE_HOST;
++        dev = &grackle_fake_bridge;
++        if (dev == NULL)
++            goto free_fake_host;
++        fake_bridge = pci_add_bridge(fake_host, 0, 0, dev,
++                                     (0x06 << 24) | (0x04 << 16) | (0xFF << 8),
++                                     cfg_base, cfg_len,
++                                     cfg_base + 0x7ec00000,
++                                     cfg_base + 0x7ee00000,
++                                     mem_base, mem_len,
++                                     io_base, io_len,
++                                     rbase, rlen,
++                                     0,
++                                     &grackle_pci_ops);
++        if (fake_bridge == NULL)
++            goto free_fake_host;
++        fake_bridge->dev.common.type = PCI_FAKE_BRIDGE;
++        break;
+     case ARCH_MAC99:
+         dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
+         if (dev == NULL)
+@@ -2167,6 +2307,30 @@
+     case ARCH_CHRP:
+         /* TODO */
+         break;
++    case ARCH_HEATHROW:
++        cfg_base = 0x80000000;
++        cfg_len  = 0x7f000000;
++        mem_base = 0x80000000;
++        mem_len  = 0x01000000;
++        io_base  = 0xfe000000;
++        io_len   = 0x00800000;
++#if 1
++        rbase    = 0xfd000000;
++        rlen     = 0x01000000;
++#else
++        rbase    = 0x00000000;
++        rlen     = 0x01000000;
++#endif
++        if (pci_check_host(&pci_main, cfg_base, cfg_len,
++                           mem_base, mem_len, io_base, io_len, rbase, rlen,
++                           0x1057, 0x0002) == 0) {
++            isa_io_base = io_base;
++            busnum++;
++        }
++        for (curh = pci_main; curh->next != NULL; curh = curh->next)
++            continue;
++        pci_check_devices(curh);
++        break;
+     case ARCH_MAC99:
+         /* We are supposed to have 3 host bridges:
+          * - the uninorth AGP bridge at 0xF0000000
diff --git a/qemu-0.15.x/pc-bios/openbios-ppc b/qemu-0.15.x/pc-bios/openbios-ppc
new file mode 100644
index 0000000..6525a91
Binary files /dev/null and b/qemu-0.15.x/pc-bios/openbios-ppc differ
diff --git a/qemu-0.15.x/pc-bios/openbios-sparc32 b/qemu-0.15.x/pc-bios/openbios-sparc32
new file mode 100644
index 0000000..ea9cc32
Binary files /dev/null and b/qemu-0.15.x/pc-bios/openbios-sparc32 differ
diff --git a/qemu-0.15.x/pc-bios/openbios-sparc64 b/qemu-0.15.x/pc-bios/openbios-sparc64
new file mode 100644
index 0000000..7e746b4
Binary files /dev/null and b/qemu-0.15.x/pc-bios/openbios-sparc64 differ
diff --git a/qemu-0.15.x/pc-bios/optionrom/Makefile b/qemu-0.15.x/pc-bios/optionrom/Makefile
new file mode 100644
index 0000000..51da288
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/optionrom/Makefile
@@ -0,0 +1,29 @@
+all: build-all
+# Dummy command so that make thinks it has done something
+	@true
+
+include ../../config-host.mak
+include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/pc-bios/optionrom)
+
+.PHONY : all clean build-all
+
+CFLAGS := -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
+CFLAGS += -I$(SRC_PATH)
+CFLAGS += $(call cc-option, $(CFLAGS), -fno-stack-protector)
+QEMU_CFLAGS = $(CFLAGS)
+
+build-all: multiboot.bin linuxboot.bin
+
+%.img: %.o
+	$(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<,"  Building $(TARGET_DIR)$@")
+
+%.raw: %.img
+	$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"  Building $(TARGET_DIR)$@")
+
+%.bin: %.raw
+	$(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/signrom.sh $< $@,"  Signing $(TARGET_DIR)$@")
+
+clean:
+	rm -f *.o *.d *.raw *.img *.bin *~
diff --git a/qemu-0.15.x/pc-bios/optionrom/linuxboot.S b/qemu-0.15.x/pc-bios/optionrom/linuxboot.S
new file mode 100644
index 0000000..748c831
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/optionrom/linuxboot.S
@@ -0,0 +1,139 @@
+/*
+ * Linux Boot Option ROM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright Novell Inc, 2009
+ *   Authors: Alexander Graf <agraf at suse.de>
+ *
+ * Based on code in hw/pc.c.
+ */
+
+#include "optionrom.h"
+
+#define BOOT_ROM_PRODUCT "Linux loader"
+
+BOOT_ROM_START
+
+run_linuxboot:
+
+	cli
+	cld
+
+	jmp		copy_kernel
+boot_kernel:
+
+	read_fw		FW_CFG_SETUP_ADDR
+
+	mov		%eax, %ebx
+	shr		$4, %ebx
+
+	/* All segments contain real_addr */
+	mov		%bx, %ds
+	mov		%bx, %es
+	mov		%bx, %fs
+	mov		%bx, %gs
+	mov		%bx, %ss
+
+	/* CX = CS we want to jump to */
+	add		$0x20, %bx
+	mov		%bx, %cx
+
+	/* SP = cmdline_addr-real_addr-16 */
+	read_fw		FW_CFG_CMDLINE_ADDR
+	mov		%eax, %ebx
+	read_fw		FW_CFG_SETUP_ADDR
+	sub		%eax, %ebx
+	sub		$16, %ebx
+	mov		%ebx, %esp
+
+	/* Build indirect lret descriptor */
+	pushw		%cx		/* CS */
+	xor		%ax, %ax
+	pushw		%ax		/* IP = 0 */
+
+	/* Clear registers */
+	xor		%eax, %eax
+	xor		%ebx, %ebx
+	xor		%ecx, %ecx
+	xor		%edx, %edx
+	xor		%edi, %edi
+	xor		%ebp, %ebp
+
+	/* Jump to Linux */
+	lret
+
+
+copy_kernel:
+
+	/* We need to load the kernel into memory we can't access in 16 bit
+	   mode, so let's get into 32 bit mode, write the kernel and jump
+	   back again. */
+
+	/* Reserve space on the stack for our GDT descriptor. */
+	mov		%esp, %ebp
+	sub		$16, %esp
+
+	/* Now create the GDT descriptor */
+	movw		$((3 * 8) - 1), -16(%bp)
+	mov		%cs, %eax
+	movzwl		%ax, %eax
+	shl		$4, %eax
+	addl		$gdt, %eax
+	movl		%eax, -14(%bp)
+
+	/* And load the GDT */
+	data32 lgdt	-16(%bp)
+	mov		%ebp, %esp
+
+	/* Get us to protected mode now */
+	mov		$1, %eax
+	mov		%eax, %cr0
+
+	/* So we can set ES to a 32-bit segment */
+	mov		$0x10, %eax
+	mov		%eax, %es
+
+	/* We're now running in 16-bit CS, but 32-bit ES! */
+
+	/* Load kernel and initrd */
+	read_fw_blob_addr32(FW_CFG_KERNEL)
+	read_fw_blob_addr32(FW_CFG_INITRD)
+	read_fw_blob_addr32(FW_CFG_CMDLINE)
+	read_fw_blob_addr32(FW_CFG_SETUP)
+
+	/* And now jump into Linux! */
+	mov		$0, %eax
+	mov		%eax, %cr0
+
+	/* ES = CS */
+	mov		%cs, %ax
+	mov		%ax, %es
+
+	jmp		boot_kernel
+
+/* Variables */
+
+.align 4, 0
+gdt:
+	/* 0x00 */
+.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+	/* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
+
+	/* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
+
+BOOT_ROM_END
diff --git a/qemu-0.15.x/pc-bios/optionrom/multiboot.S b/qemu-0.15.x/pc-bios/optionrom/multiboot.S
new file mode 100644
index 0000000..cc5ca1b
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/optionrom/multiboot.S
@@ -0,0 +1,186 @@
+/*
+ * Multiboot Option ROM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright Novell Inc, 2009
+ *   Authors: Alexander Graf <agraf at suse.de>
+ */
+
+#include "optionrom.h"
+
+#define BOOT_ROM_PRODUCT "multiboot loader"
+
+#define MULTIBOOT_MAGIC		0x2badb002
+
+#define GS_PROT_JUMP		0
+#define GS_GDT_DESC		6
+
+
+BOOT_ROM_START
+
+run_multiboot:
+
+	cli
+	cld
+
+	mov		%cs, %eax
+	shl		$0x4, %eax
+
+	/* set up a long jump descriptor that is PC relative */
+
+	/* move stack memory to %gs */
+	mov		%ss, %ecx
+	shl		$0x4, %ecx
+	mov		%esp, %ebx
+	add		%ebx, %ecx
+	sub		$0x20, %ecx
+	sub		$0x30, %esp
+	shr		$0x4, %ecx
+	mov		%cx, %gs
+
+	/* now push the indirect jump decriptor there */
+	mov		(prot_jump), %ebx
+	add		%eax, %ebx
+	movl		%ebx, %gs:GS_PROT_JUMP
+	mov		$8, %bx
+	movw		%bx, %gs:GS_PROT_JUMP + 4
+
+	/* fix the gdt descriptor to be PC relative */
+	movw		(gdt_desc), %bx
+	movw		%bx, %gs:GS_GDT_DESC
+	movl		(gdt_desc+2), %ebx
+	add		%eax, %ebx
+	movl		%ebx, %gs:GS_GDT_DESC + 2
+
+	xor		%eax, %eax
+	mov		%eax, %es
+
+	/* Read the bootinfo struct into RAM */
+	read_fw_blob(FW_CFG_INITRD)
+
+	/* FS = bootinfo_struct */
+	read_fw		FW_CFG_INITRD_ADDR
+	shr		$4, %eax
+	mov		%ax, %fs
+
+	/* ES = mmap_addr */
+	mov 		%fs:48, %eax
+	shr		$4, %eax
+	mov		%ax, %es
+
+	/* Initialize multiboot mmap structs using int 0x15(e820) */
+	xor		%ebx, %ebx
+	/* mmap start after first size */
+	movl		$4, %edi
+
+mmap_loop:
+	/* entry size (mmap struct) & max buffer size (int15) */
+	movl		$20, %ecx
+	/* store entry size */
+	/* old as(1) doesn't like this insn so emit the bytes instead:
+	movl		%ecx, %es:-4(%edi)
+	*/
+	.dc.b		0x26,0x67,0x66,0x89,0x4f,0xfc
+	/* e820 */
+	movl		$0x0000e820, %eax
+	/* 'SMAP' magic */
+	movl		$0x534d4150, %edx
+	int		$0x15
+
+mmap_check_entry:
+	/* last entry? then we're done */
+	jb		mmap_done
+	and		%bx, %bx
+	jz		mmap_done
+	/* valid entry, so let's loop on */
+
+mmap_store_entry:
+	/* %ax = entry_number * 24 */
+	mov		$24, %ax
+	mul		%bx
+	mov		%ax, %di
+	movw		%di, %fs:0x2c
+	/* %di = 4 + (entry_number * 24) */
+	add		$4, %di
+	jmp		mmap_loop
+
+mmap_done:
+real_to_prot:
+	/* Load the GDT before going into protected mode */
+lgdt:
+	data32 lgdt	%gs:GS_GDT_DESC
+
+	/* get us to protected mode now */
+	movl		$1, %eax
+	movl		%eax, %cr0
+
+	/* the LJMP sets CS for us and gets us to 32-bit */
+ljmp:
+	data32 ljmp	*%gs:GS_PROT_JUMP
+
+prot_mode:
+.code32
+
+	/* initialize all other segments */
+	movl		$0x10, %eax
+	movl		%eax, %ss
+	movl		%eax, %ds
+	movl		%eax, %es
+	movl		%eax, %fs
+	movl		%eax, %gs
+
+	/* Read the kernel and modules into RAM */
+	read_fw_blob(FW_CFG_KERNEL)
+
+	/* Jump off to the kernel */
+	read_fw		FW_CFG_KERNEL_ENTRY
+	mov		%eax, %ecx
+
+	/* EBX contains a pointer to the bootinfo struct */
+	read_fw		FW_CFG_INITRD_ADDR
+	movl		%eax, %ebx
+
+	/* EAX has to contain the magic */
+	movl		$MULTIBOOT_MAGIC, %eax
+ljmp2:
+	jmp		*%ecx
+
+/* Variables */
+.align 4, 0
+prot_jump:	.long prot_mode
+		.short 8
+
+.align 4, 0
+gdt:
+	/* 0x00 */
+.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+	/* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
+
+	/* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
+
+	/* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
+
+	/* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
+.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
+
+gdt_desc:
+.short	(5 * 8) - 1
+.long	gdt
+
+BOOT_ROM_END
diff --git a/qemu-0.15.x/pc-bios/optionrom/optionrom.h b/qemu-0.15.x/pc-bios/optionrom/optionrom.h
new file mode 100644
index 0000000..aa783de
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/optionrom/optionrom.h
@@ -0,0 +1,136 @@
+/*
+ * Common Option ROM Functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright Novell Inc, 2009
+ *   Authors: Alexander Graf <agraf at suse.de>
+ */
+
+
+#define NO_QEMU_PROTOS
+#include "../../hw/fw_cfg.h"
+
+#define BIOS_CFG_IOPORT_CFG	0x510
+#define BIOS_CFG_IOPORT_DATA	0x511
+
+/* Break the translation block flow so -d cpu shows us values */
+#define DEBUG_HERE \
+	jmp		1f;				\
+	1:
+	
+/*
+ * Read a variable from the fw_cfg device.
+ * Clobbers:	%edx
+ * Out:		%eax
+ */
+.macro read_fw VAR
+	mov		$\VAR, %ax
+	mov		$BIOS_CFG_IOPORT_CFG, %dx
+	outw		%ax, (%dx)
+	mov		$BIOS_CFG_IOPORT_DATA, %dx
+	inb		(%dx), %al
+	shl		$8, %eax
+	inb		(%dx), %al
+	shl		$8, %eax
+	inb		(%dx), %al
+	shl		$8, %eax
+	inb		(%dx), %al
+	bswap		%eax
+.endm
+
+#define read_fw_blob_pre(var)				\
+	read_fw		var ## _ADDR;			\
+	mov		%eax, %edi;			\
+	read_fw		var ## _SIZE;			\
+	mov		%eax, %ecx;			\
+	mov		$var ## _DATA, %ax;		\
+	mov		$BIOS_CFG_IOPORT_CFG, %edx;	\
+	outw		%ax, (%dx);			\
+	mov		$BIOS_CFG_IOPORT_DATA, %dx;	\
+	cld
+
+/*
+ * Read a blob from the fw_cfg device.
+ * Requires _ADDR, _SIZE and _DATA values for the parameter.
+ *
+ * Clobbers:	%eax, %edx, %es, %ecx, %edi
+ */
+#define read_fw_blob(var)				\
+	read_fw_blob_pre(var);				\
+	/* old as(1) doesn't like this insn so emit the bytes instead: \
+	rep insb	(%dx), %es:(%edi);		\
+	*/						\
+	.dc.b		0xf3,0x6c
+
+/*
+ * Read a blob from the fw_cfg device in forced addr32 mode.
+ * Requires _ADDR, _SIZE and _DATA values for the parameter.
+ *
+ * Clobbers:	%eax, %edx, %es, %ecx, %edi
+ */
+#define read_fw_blob_addr32(var)				\
+	read_fw_blob_pre(var);				\
+	/* old as(1) doesn't like this insn so emit the bytes instead: \
+	addr32 rep insb	(%dx), %es:(%edi);		\
+	*/						\
+	.dc.b		0x67,0xf3,0x6c
+
+#define OPTION_ROM_START					\
+    .code16;						\
+    .text;						\
+	.global 	_start;				\
+    _start:;						\
+	.short		0xaa55;				\
+	.byte		(_end - _start) / 512;
+
+#define BOOT_ROM_START					\
+	OPTION_ROM_START				\
+	lret;						\
+	.org 		0x18;				\
+	.short		0;				\
+	.short		_pnph;				\
+    _pnph:						\
+	.ascii		"$PnP";				\
+	.byte		0x01;				\
+	.byte		( _pnph_len / 16 );		\
+	.short		0x0000;				\
+	.byte		0x00;				\
+	.byte		0x00;				\
+	.long		0x00000000;			\
+	.short		_manufacturer;			\
+	.short		_product;			\
+	.long		0x00000000;			\
+	.short		0x0000;				\
+	.short		0x0000;				\
+	.short		_bev;				\
+	.short		0x0000;				\
+	.short		0x0000;				\
+	.equ		_pnph_len, . - _pnph;		\
+    _bev:;						\
+	/* DS = CS */					\
+	movw		%cs, %ax;			\
+	movw		%ax, %ds;
+
+#define OPTION_ROM_END					\
+    .align 512, 0;					\
+    _end:
+
+#define BOOT_ROM_END					\
+    _manufacturer:;					\
+	.asciz "QEMU";					\
+    _product:;						\
+	.asciz BOOT_ROM_PRODUCT;			\
+	OPTION_ROM_END
+
diff --git a/qemu-0.15.x/pc-bios/petalogix-ml605.dtb b/qemu-0.15.x/pc-bios/petalogix-ml605.dtb
new file mode 100644
index 0000000..fbbd45f
Binary files /dev/null and b/qemu-0.15.x/pc-bios/petalogix-ml605.dtb differ
diff --git a/qemu-0.15.x/pc-bios/petalogix-s3adsp1800.dtb b/qemu-0.15.x/pc-bios/petalogix-s3adsp1800.dtb
new file mode 100644
index 0000000..93c5973
Binary files /dev/null and b/qemu-0.15.x/pc-bios/petalogix-s3adsp1800.dtb differ
diff --git a/qemu-0.15.x/pc-bios/ppc_rom.bin b/qemu-0.15.x/pc-bios/ppc_rom.bin
new file mode 100644
index 0000000..0ad0282
Binary files /dev/null and b/qemu-0.15.x/pc-bios/ppc_rom.bin differ
diff --git a/qemu-0.15.x/pc-bios/pxe-e1000.rom b/qemu-0.15.x/pc-bios/pxe-e1000.rom
new file mode 100644
index 0000000..2e5f8b2
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-e1000.rom differ
diff --git a/qemu-0.15.x/pc-bios/pxe-eepro100.rom b/qemu-0.15.x/pc-bios/pxe-eepro100.rom
new file mode 100644
index 0000000..d292e8f
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-eepro100.rom differ
diff --git a/qemu-0.15.x/pc-bios/pxe-ne2k_pci.rom b/qemu-0.15.x/pc-bios/pxe-ne2k_pci.rom
new file mode 100644
index 0000000..62010cb
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-ne2k_pci.rom differ
diff --git a/qemu-0.15.x/pc-bios/pxe-pcnet.rom b/qemu-0.15.x/pc-bios/pxe-pcnet.rom
new file mode 100644
index 0000000..512d6d4
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-pcnet.rom differ
diff --git a/qemu-0.15.x/pc-bios/pxe-rtl8139.rom b/qemu-0.15.x/pc-bios/pxe-rtl8139.rom
new file mode 100644
index 0000000..67c77fb
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-rtl8139.rom differ
diff --git a/qemu-0.15.x/pc-bios/pxe-virtio.rom b/qemu-0.15.x/pc-bios/pxe-virtio.rom
new file mode 100644
index 0000000..b1ec909
Binary files /dev/null and b/qemu-0.15.x/pc-bios/pxe-virtio.rom differ
diff --git a/qemu-0.15.x/pc-bios/s390-zipl.rom b/qemu-0.15.x/pc-bios/s390-zipl.rom
new file mode 100644
index 0000000..3115128
Binary files /dev/null and b/qemu-0.15.x/pc-bios/s390-zipl.rom differ
diff --git a/qemu-0.15.x/pc-bios/slof.bin b/qemu-0.15.x/pc-bios/slof.bin
new file mode 100644
index 0000000..22c4c7f
Binary files /dev/null and b/qemu-0.15.x/pc-bios/slof.bin differ
diff --git a/qemu-0.15.x/pc-bios/spapr-rtas.bin b/qemu-0.15.x/pc-bios/spapr-rtas.bin
new file mode 100644
index 0000000..fc24c8e
Binary files /dev/null and b/qemu-0.15.x/pc-bios/spapr-rtas.bin differ
diff --git a/qemu-0.15.x/pc-bios/spapr-rtas/Makefile b/qemu-0.15.x/pc-bios/spapr-rtas/Makefile
new file mode 100644
index 0000000..dc8b23e
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/spapr-rtas/Makefile
@@ -0,0 +1,24 @@
+all: build-all
+# Dummy command so that make thinks it has done something
+	@true
+
+include ../../config-host.mak
+include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas)
+
+.PHONY : all clean build-all
+
+#CFLAGS += -I$(SRC_PATH)
+#QEMU_CFLAGS = $(CFLAGS)
+
+build-all: spapr-rtas.bin
+
+%.img: %.o
+	$(call quiet-command,$(CC) -nostdlib -o $@ $<,"  Building $(TARGET_DIR)$@")
+
+%.bin: %.img
+	$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"  Building $(TARGET_DIR)$@")
+
+clean:
+	rm -f *.o *.d *.img *.bin *~
diff --git a/qemu-0.15.x/pc-bios/spapr-rtas/spapr-rtas.S b/qemu-0.15.x/pc-bios/spapr-rtas/spapr-rtas.S
new file mode 100644
index 0000000..903bec2
--- /dev/null
+++ b/qemu-0.15.x/pc-bios/spapr-rtas/spapr-rtas.S
@@ -0,0 +1,37 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Trivial in-partition RTAS implementation, based on a hypercall
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+
+.globl	_start
+_start:
+	mr	4,3
+	lis	3,KVMPPC_H_RTAS at h
+	ori	3,3,KVMPPC_H_RTAS at l
+	sc	1
+	blr
diff --git a/qemu-0.15.x/pc-bios/vgabios-cirrus.bin b/qemu-0.15.x/pc-bios/vgabios-cirrus.bin
new file mode 100644
index 0000000..424dd0c
Binary files /dev/null and b/qemu-0.15.x/pc-bios/vgabios-cirrus.bin differ
diff --git a/qemu-0.15.x/pc-bios/vgabios-qxl.bin b/qemu-0.15.x/pc-bios/vgabios-qxl.bin
new file mode 100644
index 0000000..3156c6e
Binary files /dev/null and b/qemu-0.15.x/pc-bios/vgabios-qxl.bin differ
diff --git a/qemu-0.15.x/pc-bios/vgabios-stdvga.bin b/qemu-0.15.x/pc-bios/vgabios-stdvga.bin
new file mode 100644
index 0000000..5123c5f
Binary files /dev/null and b/qemu-0.15.x/pc-bios/vgabios-stdvga.bin differ
diff --git a/qemu-0.15.x/pc-bios/vgabios-vmware.bin b/qemu-0.15.x/pc-bios/vgabios-vmware.bin
new file mode 100644
index 0000000..5e8c06b
Binary files /dev/null and b/qemu-0.15.x/pc-bios/vgabios-vmware.bin differ
diff --git a/qemu-0.15.x/pc-bios/vgabios.bin b/qemu-0.15.x/pc-bios/vgabios.bin
new file mode 100644
index 0000000..892a2b5
Binary files /dev/null and b/qemu-0.15.x/pc-bios/vgabios.bin differ
diff --git a/qemu-0.15.x/pci-ids.txt b/qemu-0.15.x/pci-ids.txt
new file mode 100644
index 0000000..73125a8
--- /dev/null
+++ b/qemu-0.15.x/pci-ids.txt
@@ -0,0 +1,31 @@
+
+PCI IDs for qemu
+================
+
+Red Hat, Inc. donates a part of its device ID range to qemu, to be used for
+virtual devices.  The vendor ID is 1af4 (formerly Qumranet ID).
+
+The 1000 -> 10ff device ID range is used for VirtIO devices.
+
+The 1100 device ID is used as PCI Subsystem ID for existing hardware
+devices emulated by qemu.
+
+All other device IDs are reserved.
+
+
+VirtIO Device IDs
+-----------------
+
+1af4:1000  network device
+1af4:1001  block device
+1af4:1002  balloon device
+1af4:1003  console device
+
+1af4:1004  Reserved.
+   to      Contact Gerd Hoffmann <kraxel at redhat.com> to get a
+1af4:10ef  device ID assigned for your new virtio device.
+
+1af4:10f0  Available for experimental usage without registration.  Must get
+   to      official ID when the code leaves the test lab (i.e. when seeking
+1af4:10ff  upstream merge or shipping a distro/product) to avoid conflicts.
+
diff --git a/qemu-0.15.x/pflib.c b/qemu-0.15.x/pflib.c
new file mode 100644
index 0000000..1154d0c
--- /dev/null
+++ b/qemu-0.15.x/pflib.c
@@ -0,0 +1,213 @@
+/*
+ * PixelFormat conversion library.
+ *
+ * Author: Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "console.h"
+#include "pflib.h"
+
+typedef struct QemuPixel QemuPixel;
+
+typedef void (*pf_convert)(QemuPfConv *conv,
+                           void *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_from)(PixelFormat *pf,
+                                QemuPixel *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_to)(PixelFormat *pf,
+                              void *dst, QemuPixel *src, uint32_t cnt);
+
+struct QemuPfConv {
+    pf_convert        convert;
+    PixelFormat       src;
+    PixelFormat       dst;
+
+    /* for copy_generic() */
+    pf_convert_from   conv_from;
+    pf_convert_to     conv_to;
+    QemuPixel         *conv_buf;
+    uint32_t          conv_cnt;
+};
+
+struct QemuPixel {
+    uint8_t red;
+    uint8_t green;
+    uint8_t blue;
+    uint8_t alpha;
+};
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> QemuPixel conversions                                    */
+
+static void conv_16_to_pixel(PixelFormat *pf,
+                             QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint16_t *src16 = src;
+
+    while (cnt > 0) {
+        dst->red   = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+        dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+        dst->blue  = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+        dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+        dst++, src16++, cnt--;
+    }
+}
+
+/* assumes pf->{r,g,b,a}bits == 8 */
+static void conv_32_to_pixel_fast(PixelFormat *pf,
+                                  QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint32_t *src32 = src;
+
+    while (cnt > 0) {
+        dst->red   = (*src32 & pf->rmask) >> pf->rshift;
+        dst->green = (*src32 & pf->gmask) >> pf->gshift;
+        dst->blue  = (*src32 & pf->bmask) >> pf->bshift;
+        dst->alpha = (*src32 & pf->amask) >> pf->ashift;
+        dst++, src32++, cnt--;
+    }
+}
+
+static void conv_32_to_pixel_generic(PixelFormat *pf,
+                                     QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint32_t *src32 = src;
+
+    while (cnt > 0) {
+        if (pf->rbits < 8) {
+            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+        } else {
+            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
+        }
+        if (pf->gbits < 8) {
+            dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+        } else {
+            dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
+        }
+        if (pf->bbits < 8) {
+            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+        } else {
+            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
+        }
+        if (pf->abits < 8) {
+            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+        } else {
+            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
+        }
+        dst++, src32++, cnt--;
+    }
+}
+
+/* ----------------------------------------------------------------------- */
+/* QemuPixel -> PixelFormat conversions                                    */
+
+static void conv_pixel_to_16(PixelFormat *pf,
+                             void *dst, QemuPixel *src, uint32_t cnt)
+{
+    uint16_t *dst16 = dst;
+
+    while (cnt > 0) {
+        *dst16  = ((uint16_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
+        *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+        *dst16 |= ((uint16_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
+        *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+        dst16++, src++, cnt--;
+    }
+}
+
+static void conv_pixel_to_32(PixelFormat *pf,
+                             void *dst, QemuPixel *src, uint32_t cnt)
+{
+    uint32_t *dst32 = dst;
+
+    while (cnt > 0) {
+        *dst32  = ((uint32_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
+        *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+        *dst32 |= ((uint32_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
+        *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+        dst32++, src++, cnt--;
+    }
+}
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> PixelFormat conversions                                  */
+
+static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    uint32_t bytes = cnt * conv->src.bytes_per_pixel;
+    memcpy(dst, src, bytes);
+}
+
+static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    if (conv->conv_cnt < cnt) {
+        conv->conv_cnt = cnt;
+        conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
+    }
+    conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
+    conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
+}
+
+/* ----------------------------------------------------------------------- */
+/* public interface                                                        */
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
+{
+    QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv));
+
+    conv->src = *src;
+    conv->dst = *dst;
+
+    if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
+        /* formats identical, can simply copy */
+        conv->convert = convert_copy;
+    } else {
+        /* generic two-step conversion: src -> QemuPixel -> dst  */
+        switch (conv->src.bytes_per_pixel) {
+        case 2:
+            conv->conv_from = conv_16_to_pixel;
+            break;
+        case 4:
+            if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
+                conv->conv_from = conv_32_to_pixel_fast;
+            } else {
+                conv->conv_from = conv_32_to_pixel_generic;
+            }
+            break;
+        default:
+            goto err;
+        }
+        switch (conv->dst.bytes_per_pixel) {
+        case 2:
+            conv->conv_to = conv_pixel_to_16;
+            break;
+        case 4:
+            conv->conv_to = conv_pixel_to_32;
+            break;
+        default:
+            goto err;
+        }
+        conv->convert = convert_generic;
+    }
+    return conv;
+
+err:
+    qemu_free(conv);
+    return NULL;
+}
+
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    conv->convert(conv, dst, src, cnt);
+}
+
+void qemu_pf_conv_put(QemuPfConv *conv)
+{
+    if (conv) {
+        qemu_free(conv->conv_buf);
+        qemu_free(conv);
+    }
+}
diff --git a/qemu-0.15.x/pflib.h b/qemu-0.15.x/pflib.h
new file mode 100644
index 0000000..b70c313
--- /dev/null
+++ b/qemu-0.15.x/pflib.h
@@ -0,0 +1,20 @@
+#ifndef __QEMU_PFLIB_H
+#define __QEMU_PFLIB_H
+
+/*
+ * PixelFormat conversion library.
+ *
+ * Author: Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+typedef struct QemuPfConv QemuPfConv;
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src);
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt);
+void qemu_pf_conv_put(QemuPfConv *conv);
+
+#endif
diff --git a/qemu-0.15.x/poison.h b/qemu-0.15.x/poison.h
new file mode 100644
index 0000000..5354e77
--- /dev/null
+++ b/qemu-0.15.x/poison.h
@@ -0,0 +1,63 @@
+/* Poison identifiers that should not be used when building
+   target independent device code.  */
+
+#ifndef HW_POISON_H
+#define HW_POISON_H
+#ifdef __GNUC__
+
+#pragma GCC poison TARGET_I386
+#pragma GCC poison TARGET_X86_64
+#pragma GCC poison TARGET_ALPHA
+#pragma GCC poison TARGET_ARM
+#pragma GCC poison TARGET_CRIS
+#pragma GCC poison TARGET_LM32
+#pragma GCC poison TARGET_M68K
+#pragma GCC poison TARGET_MIPS
+#pragma GCC poison TARGET_MIPS64
+#pragma GCC poison TARGET_PPC
+#pragma GCC poison TARGET_PPCEMB
+#pragma GCC poison TARGET_PPC64
+#pragma GCC poison TARGET_ABI32
+#pragma GCC poison TARGET_SH4
+#pragma GCC poison TARGET_SPARC
+#pragma GCC poison TARGET_SPARC64
+
+#pragma GCC poison TARGET_WORDS_BIGENDIAN
+#pragma GCC poison BSWAP_NEEDED
+
+#pragma GCC poison TARGET_LONG_BITS
+#pragma GCC poison TARGET_FMT_lx
+#pragma GCC poison TARGET_FMT_ld
+
+#pragma GCC poison TARGET_PAGE_SIZE
+#pragma GCC poison TARGET_PAGE_MASK
+#pragma GCC poison TARGET_PAGE_BITS
+#pragma GCC poison TARGET_PAGE_ALIGN
+
+#pragma GCC poison CPUState
+#pragma GCC poison env
+
+#pragma GCC poison lduw_phys
+#pragma GCC poison ldl_phys
+#pragma GCC poison ldq_phys
+#pragma GCC poison stl_phys_notdirty
+#pragma GCC poison stq_phys_notdirty
+#pragma GCC poison stw_phys
+#pragma GCC poison stl_phys
+#pragma GCC poison stq_phys
+
+#pragma GCC poison CPU_INTERRUPT_HARD
+#pragma GCC poison CPU_INTERRUPT_EXITTB
+#pragma GCC poison CPU_INTERRUPT_HALT
+#pragma GCC poison CPU_INTERRUPT_DEBUG
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_0
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_1
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_2
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_3
+#pragma GCC poison CPU_INTERRUPT_TGT_EXT_4
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_0
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_1
+#pragma GCC poison CPU_INTERRUPT_TGT_INT_2
+
+#endif
+#endif
diff --git a/qemu-0.15.x/posix-aio-compat.c b/qemu-0.15.x/posix-aio-compat.c
new file mode 100644
index 0000000..c4116e3
--- /dev/null
+++ b/qemu-0.15.x/posix-aio-compat.c
@@ -0,0 +1,663 @@
+/*
+ * QEMU posix-aio emulation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "qemu-queue.h"
+#include "osdep.h"
+#include "sysemu.h"
+#include "qemu-common.h"
+#include "trace.h"
+#include "block_int.h"
+
+#include "block/raw-posix-aio.h"
+
+
+struct qemu_paiocb {
+    BlockDriverAIOCB common;
+    int aio_fildes;
+    union {
+        struct iovec *aio_iov;
+        void *aio_ioctl_buf;
+    };
+    int aio_niov;
+    size_t aio_nbytes;
+#define aio_ioctl_cmd   aio_nbytes /* for QEMU_AIO_IOCTL */
+    int ev_signo;
+    off_t aio_offset;
+
+    QTAILQ_ENTRY(qemu_paiocb) node;
+    int aio_type;
+    ssize_t ret;
+    int active;
+    struct qemu_paiocb *next;
+
+    int async_context_id;
+};
+
+typedef struct PosixAioState {
+    int rfd, wfd;
+    struct qemu_paiocb *first_aio;
+} PosixAioState;
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_t thread_id;
+static pthread_attr_t attr;
+static int max_threads = 64;
+static int cur_threads = 0;
+static int idle_threads = 0;
+static QTAILQ_HEAD(, qemu_paiocb) request_list;
+
+#ifdef CONFIG_PREADV
+static int preadv_present = 1;
+#else
+static int preadv_present = 0;
+#endif
+
+static void die2(int err, const char *what)
+{
+    fprintf(stderr, "%s failed: %s\n", what, strerror(err));
+    abort();
+}
+
+static void die(const char *what)
+{
+    die2(errno, what);
+}
+
+static void mutex_lock(pthread_mutex_t *mutex)
+{
+    int ret = pthread_mutex_lock(mutex);
+    if (ret) die2(ret, "pthread_mutex_lock");
+}
+
+static void mutex_unlock(pthread_mutex_t *mutex)
+{
+    int ret = pthread_mutex_unlock(mutex);
+    if (ret) die2(ret, "pthread_mutex_unlock");
+}
+
+static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+                           struct timespec *ts)
+{
+    int ret = pthread_cond_timedwait(cond, mutex, ts);
+    if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait");
+    return ret;
+}
+
+static void cond_signal(pthread_cond_t *cond)
+{
+    int ret = pthread_cond_signal(cond);
+    if (ret) die2(ret, "pthread_cond_signal");
+}
+
+static void thread_create(pthread_t *thread, pthread_attr_t *attr,
+                          void *(*start_routine)(void*), void *arg)
+{
+    int ret = pthread_create(thread, attr, start_routine, arg);
+    if (ret) die2(ret, "pthread_create");
+}
+
+static ssize_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
+{
+    int ret;
+
+    ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
+    if (ret == -1)
+        return -errno;
+
+    /*
+     * This looks weird, but the aio code only consideres a request
+     * successful if it has written the number full number of bytes.
+     *
+     * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
+     * so in fact we return the ioctl command here to make posix_aio_read()
+     * happy..
+     */
+    return aiocb->aio_nbytes;
+}
+
+static ssize_t handle_aiocb_flush(struct qemu_paiocb *aiocb)
+{
+    int ret;
+
+    ret = qemu_fdatasync(aiocb->aio_fildes);
+    if (ret == -1)
+        return -errno;
+    return 0;
+}
+
+#ifdef CONFIG_PREADV
+
+static ssize_t
+qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+    return preadv(fd, iov, nr_iov, offset);
+}
+
+static ssize_t
+qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+    return pwritev(fd, iov, nr_iov, offset);
+}
+
+#else
+
+static ssize_t
+qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+    return -ENOSYS;
+}
+
+static ssize_t
+qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
+{
+    return -ENOSYS;
+}
+
+#endif
+
+static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
+{
+    size_t offset = 0;
+    ssize_t len;
+
+    do {
+        if (aiocb->aio_type & QEMU_AIO_WRITE)
+            len = qemu_pwritev(aiocb->aio_fildes,
+                               aiocb->aio_iov,
+                               aiocb->aio_niov,
+                               aiocb->aio_offset + offset);
+         else
+            len = qemu_preadv(aiocb->aio_fildes,
+                              aiocb->aio_iov,
+                              aiocb->aio_niov,
+                              aiocb->aio_offset + offset);
+    } while (len == -1 && errno == EINTR);
+
+    if (len == -1)
+        return -errno;
+    return len;
+}
+
+static ssize_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
+{
+    ssize_t offset = 0;
+    ssize_t len;
+
+    while (offset < aiocb->aio_nbytes) {
+         if (aiocb->aio_type & QEMU_AIO_WRITE)
+             len = pwrite(aiocb->aio_fildes,
+                          (const char *)buf + offset,
+                          aiocb->aio_nbytes - offset,
+                          aiocb->aio_offset + offset);
+         else
+             len = pread(aiocb->aio_fildes,
+                         buf + offset,
+                         aiocb->aio_nbytes - offset,
+                         aiocb->aio_offset + offset);
+
+         if (len == -1 && errno == EINTR)
+             continue;
+         else if (len == -1) {
+             offset = -errno;
+             break;
+         } else if (len == 0)
+             break;
+
+         offset += len;
+    }
+
+    return offset;
+}
+
+static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
+{
+    ssize_t nbytes;
+    char *buf;
+
+    if (!(aiocb->aio_type & QEMU_AIO_MISALIGNED)) {
+        /*
+         * If there is just a single buffer, and it is properly aligned
+         * we can just use plain pread/pwrite without any problems.
+         */
+        if (aiocb->aio_niov == 1)
+             return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
+
+        /*
+         * We have more than one iovec, and all are properly aligned.
+         *
+         * Try preadv/pwritev first and fall back to linearizing the
+         * buffer if it's not supported.
+         */
+        if (preadv_present) {
+            nbytes = handle_aiocb_rw_vector(aiocb);
+            if (nbytes == aiocb->aio_nbytes)
+                return nbytes;
+            if (nbytes < 0 && nbytes != -ENOSYS)
+                return nbytes;
+            preadv_present = 0;
+        }
+
+        /*
+         * XXX(hch): short read/write.  no easy way to handle the reminder
+         * using these interfaces.  For now retry using plain
+         * pread/pwrite?
+         */
+    }
+
+    /*
+     * Ok, we have to do it the hard way, copy all segments into
+     * a single aligned buffer.
+     */
+    buf = qemu_blockalign(aiocb->common.bs, aiocb->aio_nbytes);
+    if (aiocb->aio_type & QEMU_AIO_WRITE) {
+        char *p = buf;
+        int i;
+
+        for (i = 0; i < aiocb->aio_niov; ++i) {
+            memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
+            p += aiocb->aio_iov[i].iov_len;
+        }
+    }
+
+    nbytes = handle_aiocb_rw_linear(aiocb, buf);
+    if (!(aiocb->aio_type & QEMU_AIO_WRITE)) {
+        char *p = buf;
+        size_t count = aiocb->aio_nbytes, copy;
+        int i;
+
+        for (i = 0; i < aiocb->aio_niov && count; ++i) {
+            copy = count;
+            if (copy > aiocb->aio_iov[i].iov_len)
+                copy = aiocb->aio_iov[i].iov_len;
+            memcpy(aiocb->aio_iov[i].iov_base, p, copy);
+            p     += copy;
+            count -= copy;
+        }
+    }
+    qemu_vfree(buf);
+
+    return nbytes;
+}
+
+static void *aio_thread(void *unused)
+{
+    pid_t pid;
+
+    pid = getpid();
+
+    while (1) {
+        struct qemu_paiocb *aiocb;
+        ssize_t ret = 0;
+        qemu_timeval tv;
+        struct timespec ts;
+
+        qemu_gettimeofday(&tv);
+        ts.tv_sec = tv.tv_sec + 10;
+        ts.tv_nsec = 0;
+
+        mutex_lock(&lock);
+
+        while (QTAILQ_EMPTY(&request_list) &&
+               !(ret == ETIMEDOUT)) {
+            idle_threads++;
+            ret = cond_timedwait(&cond, &lock, &ts);
+            idle_threads--;
+        }
+
+        if (QTAILQ_EMPTY(&request_list))
+            break;
+
+        aiocb = QTAILQ_FIRST(&request_list);
+        QTAILQ_REMOVE(&request_list, aiocb, node);
+        aiocb->active = 1;
+        mutex_unlock(&lock);
+
+        switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
+        case QEMU_AIO_READ:
+        case QEMU_AIO_WRITE:
+            ret = handle_aiocb_rw(aiocb);
+            break;
+        case QEMU_AIO_FLUSH:
+            ret = handle_aiocb_flush(aiocb);
+            break;
+        case QEMU_AIO_IOCTL:
+            ret = handle_aiocb_ioctl(aiocb);
+            break;
+        default:
+            fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+            ret = -EINVAL;
+            break;
+        }
+
+        mutex_lock(&lock);
+        aiocb->ret = ret;
+        mutex_unlock(&lock);
+
+        if (kill(pid, aiocb->ev_signo)) die("kill failed");
+    }
+
+    cur_threads--;
+    mutex_unlock(&lock);
+
+    return NULL;
+}
+
+static void spawn_thread(void)
+{
+    sigset_t set, oldset;
+
+    cur_threads++;
+
+    /* block all signals */
+    if (sigfillset(&set)) die("sigfillset");
+    if (sigprocmask(SIG_SETMASK, &set, &oldset)) die("sigprocmask");
+
+    thread_create(&thread_id, &attr, aio_thread, NULL);
+
+    if (sigprocmask(SIG_SETMASK, &oldset, NULL)) die("sigprocmask restore");
+}
+
+static void qemu_paio_submit(struct qemu_paiocb *aiocb)
+{
+    aiocb->ret = -EINPROGRESS;
+    aiocb->active = 0;
+    mutex_lock(&lock);
+    if (idle_threads == 0 && cur_threads < max_threads)
+        spawn_thread();
+    QTAILQ_INSERT_TAIL(&request_list, aiocb, node);
+    mutex_unlock(&lock);
+    cond_signal(&cond);
+}
+
+static ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
+{
+    ssize_t ret;
+
+    mutex_lock(&lock);
+    ret = aiocb->ret;
+    mutex_unlock(&lock);
+
+    return ret;
+}
+
+static int qemu_paio_error(struct qemu_paiocb *aiocb)
+{
+    ssize_t ret = qemu_paio_return(aiocb);
+
+    if (ret < 0)
+        ret = -ret;
+    else
+        ret = 0;
+
+    return ret;
+}
+
+static int posix_aio_process_queue(void *opaque)
+{
+    PosixAioState *s = opaque;
+    struct qemu_paiocb *acb, **pacb;
+    int ret;
+    int result = 0;
+    int async_context_id = get_async_context_id();
+
+    for(;;) {
+        pacb = &s->first_aio;
+        for(;;) {
+            acb = *pacb;
+            if (!acb)
+                return result;
+
+            /* we're only interested in requests in the right context */
+            if (acb->async_context_id != async_context_id) {
+                pacb = &acb->next;
+                continue;
+            }
+
+            ret = qemu_paio_error(acb);
+            if (ret == ECANCELED) {
+                /* remove the request */
+                *pacb = acb->next;
+                qemu_aio_release(acb);
+                result = 1;
+            } else if (ret != EINPROGRESS) {
+                /* end of aio */
+                if (ret == 0) {
+                    ret = qemu_paio_return(acb);
+                    if (ret == acb->aio_nbytes)
+                        ret = 0;
+                    else
+                        ret = -EINVAL;
+                } else {
+                    ret = -ret;
+                }
+
+                trace_paio_complete(acb, acb->common.opaque, ret);
+
+                /* remove the request */
+                *pacb = acb->next;
+                /* call the callback */
+                acb->common.cb(acb->common.opaque, ret);
+                qemu_aio_release(acb);
+                result = 1;
+                break;
+            } else {
+                pacb = &acb->next;
+            }
+        }
+    }
+
+    return result;
+}
+
+static void posix_aio_read(void *opaque)
+{
+    PosixAioState *s = opaque;
+    ssize_t len;
+
+    /* read all bytes from signal pipe */
+    for (;;) {
+        char bytes[16];
+
+        len = read(s->rfd, bytes, sizeof(bytes));
+        if (len == -1 && errno == EINTR)
+            continue; /* try again */
+        if (len == sizeof(bytes))
+            continue; /* more to read */
+        break;
+    }
+
+    posix_aio_process_queue(s);
+}
+
+static int posix_aio_flush(void *opaque)
+{
+    PosixAioState *s = opaque;
+    return !!s->first_aio;
+}
+
+static PosixAioState *posix_aio_state;
+
+static void aio_signal_handler(int signum)
+{
+    if (posix_aio_state) {
+        char byte = 0;
+        ssize_t ret;
+
+        ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
+        if (ret < 0 && errno != EAGAIN)
+            die("write()");
+    }
+
+    qemu_service_io();
+}
+
+static void paio_remove(struct qemu_paiocb *acb)
+{
+    struct qemu_paiocb **pacb;
+
+    /* remove the callback from the queue */
+    pacb = &posix_aio_state->first_aio;
+    for(;;) {
+        if (*pacb == NULL) {
+            fprintf(stderr, "paio_remove: aio request not found!\n");
+            break;
+        } else if (*pacb == acb) {
+            *pacb = acb->next;
+            qemu_aio_release(acb);
+            break;
+        }
+        pacb = &(*pacb)->next;
+    }
+}
+
+static void paio_cancel(BlockDriverAIOCB *blockacb)
+{
+    struct qemu_paiocb *acb = (struct qemu_paiocb *)blockacb;
+    int active = 0;
+
+    trace_paio_cancel(acb, acb->common.opaque);
+
+    mutex_lock(&lock);
+    if (!acb->active) {
+        QTAILQ_REMOVE(&request_list, acb, node);
+        acb->ret = -ECANCELED;
+    } else if (acb->ret == -EINPROGRESS) {
+        active = 1;
+    }
+    mutex_unlock(&lock);
+
+    if (active) {
+        /* fail safe: if the aio could not be canceled, we wait for
+           it */
+        while (qemu_paio_error(acb) == EINPROGRESS)
+            ;
+    }
+
+    paio_remove(acb);
+}
+
+static AIOPool raw_aio_pool = {
+    .aiocb_size         = sizeof(struct qemu_paiocb),
+    .cancel             = paio_cancel,
+};
+
+BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type)
+{
+    struct qemu_paiocb *acb;
+
+    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->aio_type = type;
+    acb->aio_fildes = fd;
+    acb->ev_signo = SIGUSR2;
+    acb->async_context_id = get_async_context_id();
+
+    if (qiov) {
+        acb->aio_iov = qiov->iov;
+        acb->aio_niov = qiov->niov;
+    }
+    acb->aio_nbytes = nb_sectors * 512;
+    acb->aio_offset = sector_num * 512;
+
+    acb->next = posix_aio_state->first_aio;
+    posix_aio_state->first_aio = acb;
+
+    trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
+    qemu_paio_submit(acb);
+    return &acb->common;
+}
+
+BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    struct qemu_paiocb *acb;
+
+    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->aio_type = QEMU_AIO_IOCTL;
+    acb->aio_fildes = fd;
+    acb->ev_signo = SIGUSR2;
+    acb->async_context_id = get_async_context_id();
+    acb->aio_offset = 0;
+    acb->aio_ioctl_buf = buf;
+    acb->aio_ioctl_cmd = req;
+
+    acb->next = posix_aio_state->first_aio;
+    posix_aio_state->first_aio = acb;
+
+    qemu_paio_submit(acb);
+    return &acb->common;
+}
+
+int paio_init(void)
+{
+    struct sigaction act;
+    PosixAioState *s;
+    int fds[2];
+    int ret;
+
+    if (posix_aio_state)
+        return 0;
+
+    s = qemu_malloc(sizeof(PosixAioState));
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
+    act.sa_handler = aio_signal_handler;
+    sigaction(SIGUSR2, &act, NULL);
+
+    s->first_aio = NULL;
+    if (qemu_pipe(fds) == -1) {
+        fprintf(stderr, "failed to create pipe\n");
+        return -1;
+    }
+
+    s->rfd = fds[0];
+    s->wfd = fds[1];
+
+    fcntl(s->rfd, F_SETFL, O_NONBLOCK);
+    fcntl(s->wfd, F_SETFL, O_NONBLOCK);
+
+    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
+        posix_aio_process_queue, s);
+
+    ret = pthread_attr_init(&attr);
+    if (ret)
+        die2(ret, "pthread_attr_init");
+
+    ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    if (ret)
+        die2(ret, "pthread_attr_setdetachstate");
+
+    QTAILQ_INIT(&request_list);
+
+    posix_aio_state = s;
+    return 0;
+}
diff --git a/qemu-0.15.x/ppc-dis.c b/qemu-0.15.x/ppc-dis.c
new file mode 100644
index 0000000..ffdbec1
--- /dev/null
+++ b/qemu-0.15.x/ppc-dis.c
@@ -0,0 +1,5412 @@
+/* ppc-dis.c -- Disassemble PowerPC instructions
+   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+will be useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this file; see the file COPYING.  If not,
+see <http://www.gnu.org/licenses/>.  */
+#include "dis-asm.h"
+#define BFD_DEFAULT_TARGET_SIZE 64
+
+/* ppc.h -- Header file for PowerPC opcode table
+   Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2007 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+will be useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this file; see the file COPYING.  If not,
+see <http://www.gnu.org/licenses/>.  */
+
+/* The opcode table is an array of struct powerpc_opcode.  */
+
+struct powerpc_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+
+  /* The opcode itself.  Those bits which will be filled in with
+     operands are zeroes.  */
+  unsigned long opcode;
+
+  /* The opcode mask.  This is used by the disassembler.  This is a
+     mask containing ones indicating those bits which must match the
+     opcode field, and zeroes indicating those bits which need not
+     match (and are presumably filled in by operands).  */
+  unsigned long mask;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The defined values
+     are listed below.  */
+  unsigned long flags;
+
+  /* An array of operand codes.  Each code is an index into the
+     operand table.  They appear in the order which the operands must
+     appear in assembly code, and are terminated by a zero.  */
+  unsigned char operands[8];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct powerpc_opcode powerpc_opcodes[];
+extern const int powerpc_num_opcodes;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* Opcode is defined for the PowerPC architecture.  */
+#define PPC_OPCODE_PPC			 1
+
+/* Opcode is defined for the POWER (RS/6000) architecture.  */
+#define PPC_OPCODE_POWER		 2
+
+/* Opcode is defined for the POWER2 (Rios 2) architecture.  */
+#define PPC_OPCODE_POWER2		 4
+
+/* Opcode is only defined on 32 bit architectures.  */
+#define PPC_OPCODE_32			 8
+
+/* Opcode is only defined on 64 bit architectures.  */
+#define PPC_OPCODE_64		      0x10
+
+/* Opcode is supported by the Motorola PowerPC 601 processor.  The 601
+   is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions,
+   but it also supports many additional POWER instructions.  */
+#define PPC_OPCODE_601		      0x20
+
+/* Opcode is supported in both the Power and PowerPC architectures
+   (ie, compiler's -mcpu=common or assembler's -mcom).  */
+#define PPC_OPCODE_COMMON	      0x40
+
+/* Opcode is supported for any Power or PowerPC platform (this is
+   for the assembler's -many option, and it eliminates duplicates).  */
+#define PPC_OPCODE_ANY		      0x80
+
+/* Opcode is supported as part of the 64-bit bridge.  */
+#define PPC_OPCODE_64_BRIDGE	     0x100
+
+/* Opcode is supported by Altivec Vector Unit */
+#define PPC_OPCODE_ALTIVEC	     0x200
+
+/* Opcode is supported by PowerPC 403 processor.  */
+#define PPC_OPCODE_403		     0x400
+
+/* Opcode is supported by PowerPC BookE processor.  */
+#define PPC_OPCODE_BOOKE	     0x800
+
+/* Opcode is only supported by 64-bit PowerPC BookE processor.  */
+#define PPC_OPCODE_BOOKE64	    0x1000
+
+/* Opcode is supported by PowerPC 440 processor.  */
+#define PPC_OPCODE_440		    0x2000
+
+/* Opcode is only supported by Power4 architecture.  */
+#define PPC_OPCODE_POWER4	    0x4000
+
+/* Opcode isn't supported by Power4 architecture.  */
+#define PPC_OPCODE_NOPOWER4	    0x8000
+
+/* Opcode is only supported by POWERPC Classic architecture.  */
+#define PPC_OPCODE_CLASSIC	   0x10000
+
+/* Opcode is only supported by e500x2 Core.  */
+#define PPC_OPCODE_SPE		   0x20000
+
+/* Opcode is supported by e500x2 Integer select APU.  */
+#define PPC_OPCODE_ISEL		   0x40000
+
+/* Opcode is an e500 SPE floating point instruction.  */
+#define PPC_OPCODE_EFS		   0x80000
+
+/* Opcode is supported by branch locking APU.  */
+#define PPC_OPCODE_BRLOCK	  0x100000
+
+/* Opcode is supported by performance monitor APU.  */
+#define PPC_OPCODE_PMR		  0x200000
+
+/* Opcode is supported by cache locking APU.  */
+#define PPC_OPCODE_CACHELCK	  0x400000
+
+/* Opcode is supported by machine check APU.  */
+#define PPC_OPCODE_RFMCI	  0x800000
+
+/* Opcode is only supported by Power5 architecture.  */
+#define PPC_OPCODE_POWER5	 0x1000000
+
+/* Opcode is supported by PowerPC e300 family.  */
+#define PPC_OPCODE_E300          0x2000000
+
+/* Opcode is only supported by Power6 architecture.  */
+#define PPC_OPCODE_POWER6	 0x4000000
+
+/* Opcode is only supported by PowerPC Cell family.  */
+#define PPC_OPCODE_CELL		 0x8000000
+
+/* A macro to extract the major opcode from an instruction.  */
+#define PPC_OP(i) (((i) >> 26) & 0x3f)
+
+/* The operands table is an array of struct powerpc_operand.  */
+
+struct powerpc_operand
+{
+  /* A bitmask of bits in the operand.  */
+  unsigned int bitm;
+
+  /* How far the operand is left shifted in the instruction.
+     -1 to indicate that BITM and SHIFT cannot be used to determine
+     where the operand goes in the insn.  */
+  int shift;
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+	 i |= (op & o->bitm) << o->shift;
+     (i is the instruction which we are filling in, o is a pointer to
+     this structure, and op is the operand value).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will return the new value
+     of the instruction.  If the ERRMSG argument is not NULL, then if
+     the operand value is illegal, *ERRMSG will be set to a warning
+     string (the operand will be inserted in any case).  If the
+     operand value is legal, *ERRMSG will be unchanged (most operands
+     can accept any value).  */
+  unsigned long (*insert)
+    (unsigned long instruction, long op, int dialect, const char **errmsg);
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+	 op = (i >> o->shift) & o->bitm;
+	 if ((o->flags & PPC_OPERAND_SIGNED) != 0)
+	   sign_extend (op);
+     (i is the instruction, o is a pointer to this structure, and op
+     is the result).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.  */
+  long (*extract) (unsigned long instruction, int dialect, int *invalid);
+
+  /* One bit syntax flags.  */
+  unsigned long flags;
+};
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+extern const struct powerpc_operand powerpc_operands[];
+extern const unsigned int num_powerpc_operands;
+
+/* Values defined for the flags field of a struct powerpc_operand.  */
+
+/* This operand takes signed values.  */
+#define PPC_OPERAND_SIGNED (0x1)
+
+/* This operand takes signed values, but also accepts a full positive
+   range of values when running in 32 bit mode.  That is, if bits is
+   16, it takes any value from -0x8000 to 0xffff.  In 64 bit mode,
+   this flag is ignored.  */
+#define PPC_OPERAND_SIGNOPT (0x2)
+
+/* This operand does not actually exist in the assembler input.  This
+   is used to support extended mnemonics such as mr, for which two
+   operands fields are identical.  The assembler should call the
+   insert function with any op value.  The disassembler should call
+   the extract function, ignore the return value, and check the value
+   placed in the valid argument.  */
+#define PPC_OPERAND_FAKE (0x4)
+
+/* The next operand should be wrapped in parentheses rather than
+   separated from this one by a comma.  This is used for the load and
+   store instructions which want their operands to look like
+       reg,displacement(reg)
+   */
+#define PPC_OPERAND_PARENS (0x8)
+
+/* This operand may use the symbolic names for the CR fields, which
+   are
+       lt  0	gt  1	eq  2	so  3	un  3
+       cr0 0	cr1 1	cr2 2	cr3 3
+       cr4 4	cr5 5	cr6 6	cr7 7
+   These may be combined arithmetically, as in cr2*4+gt.  These are
+   only supported on the PowerPC, not the POWER.  */
+#define PPC_OPERAND_CR (0x10)
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define PPC_OPERAND_GPR (0x20)
+
+/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0.  */
+#define PPC_OPERAND_GPR_0 (0x40)
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'.  */
+#define PPC_OPERAND_FPR (0x80)
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_RELATIVE (0x100)
+
+/* This operand is an absolute branch address.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_ABSOLUTE (0x200)
+
+/* This operand is optional, and is zero if omitted.  This is used for
+   example, in the optional BF field in the comparison instructions.  The
+   assembler must count the number of operands remaining on the line,
+   and the number of operands remaining for the opcode, and decide
+   whether this operand is present or not.  The disassembler should
+   print this operand out only if it is not zero.  */
+#define PPC_OPERAND_OPTIONAL (0x400)
+
+/* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
+   is omitted, then for the next operand use this operand value plus
+   1, ignoring the next operand field for the opcode.  This wretched
+   hack is needed because the Power rotate instructions can take
+   either 4 or 5 operands.  The disassembler should print this operand
+   out regardless of the PPC_OPERAND_OPTIONAL field.  */
+#define PPC_OPERAND_NEXT (0x800)
+
+/* This operand should be regarded as a negative number for the
+   purposes of overflow checking (i.e., the normal most negative
+   number is disallowed and one more than the normal most positive
+   number is allowed).  This flag will only be set for a signed
+   operand.  */
+#define PPC_OPERAND_NEGATIVE (0x1000)
+
+/* This operand names a vector unit register.  The disassembler
+   prints these with a leading 'v'.  */
+#define PPC_OPERAND_VR (0x2000)
+
+/* This operand is for the DS field in a DS form instruction.  */
+#define PPC_OPERAND_DS (0x4000)
+
+/* This operand is for the DQ field in a DQ form instruction.  */
+#define PPC_OPERAND_DQ (0x8000)
+
+/* Valid range of operand is 0..n rather than 0..n-1.  */
+#define PPC_OPERAND_PLUS1 (0x10000)
+
+/* The POWER and PowerPC assemblers use a few macros.  We keep them
+   with the operands table for simplicity.  The macro table is an
+   array of struct powerpc_macro.  */
+
+struct powerpc_macro
+{
+  /* The macro name.  */
+  const char *name;
+
+  /* The number of operands the macro takes.  */
+  unsigned int operands;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The values are the
+     same as those for the struct powerpc_opcode flags field.  */
+  unsigned long flags;
+
+  /* A format string to turn the macro into a normal instruction.
+     Each %N in the string is replaced with operand number N (zero
+     based).  */
+  const char *format;
+};
+
+extern const struct powerpc_macro powerpc_macros[];
+extern const int powerpc_num_macros;
+
+/* ppc-opc.c -- PowerPC opcode list
+   Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   2, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.
+   If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file holds the PowerPC opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+
+/* Local insertion and extraction functions.  */
+
+static unsigned long insert_bat (unsigned long, long, int, const char **);
+static long extract_bat (unsigned long, int, int *);
+static unsigned long insert_bba (unsigned long, long, int, const char **);
+static long extract_bba (unsigned long, int, int *);
+static unsigned long insert_bdm (unsigned long, long, int, const char **);
+static long extract_bdm (unsigned long, int, int *);
+static unsigned long insert_bdp (unsigned long, long, int, const char **);
+static long extract_bdp (unsigned long, int, int *);
+static unsigned long insert_bo (unsigned long, long, int, const char **);
+static long extract_bo (unsigned long, int, int *);
+static unsigned long insert_boe (unsigned long, long, int, const char **);
+static long extract_boe (unsigned long, int, int *);
+static unsigned long insert_fxm (unsigned long, long, int, const char **);
+static long extract_fxm (unsigned long, int, int *);
+static unsigned long insert_mbe (unsigned long, long, int, const char **);
+static long extract_mbe (unsigned long, int, int *);
+static unsigned long insert_mb6 (unsigned long, long, int, const char **);
+static long extract_mb6 (unsigned long, int, int *);
+static long extract_nb (unsigned long, int, int *);
+static unsigned long insert_nsi (unsigned long, long, int, const char **);
+static long extract_nsi (unsigned long, int, int *);
+static unsigned long insert_ral (unsigned long, long, int, const char **);
+static unsigned long insert_ram (unsigned long, long, int, const char **);
+static unsigned long insert_raq (unsigned long, long, int, const char **);
+static unsigned long insert_ras (unsigned long, long, int, const char **);
+static unsigned long insert_rbs (unsigned long, long, int, const char **);
+static long extract_rbs (unsigned long, int, int *);
+static unsigned long insert_sh6 (unsigned long, long, int, const char **);
+static long extract_sh6 (unsigned long, int, int *);
+static unsigned long insert_spr (unsigned long, long, int, const char **);
+static long extract_spr (unsigned long, int, int *);
+static unsigned long insert_sprg (unsigned long, long, int, const char **);
+static long extract_sprg (unsigned long, int, int *);
+static unsigned long insert_tbr (unsigned long, long, int, const char **);
+static long extract_tbr (unsigned long, int, int *);
+
+/* The operands table.
+
+   The fields are bitm, shift, insert, extract, flags.
+
+   We used to put parens around the various additions, like the one
+   for BA just below.  However, that caused trouble with feeble
+   compilers with a limit on depth of a parenthesized expression, like
+   (reportedly) the compiler in Microsoft Developer Studio 5.  So we
+   omit the parens, since the macros are never used in a context where
+   the addition will be ambiguous.  */
+
+const struct powerpc_operand powerpc_operands[] =
+{
+  /* The zero index is used to indicate the end of the list of
+     operands.  */
+#define UNUSED 0
+  { 0, 0, NULL, NULL, 0 },
+
+  /* The BA field in an XL form instruction.  */
+#define BA UNUSED + 1
+  /* The BI field in a B form or XL form instruction.  */
+#define BI BA
+#define BI_MASK (0x1f << 16)
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The BA field in an XL form instruction when it must be the same
+     as the BT field in the same instruction.  */
+#define BAT BA + 1
+  { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
+
+  /* The BB field in an XL form instruction.  */
+#define BB BAT + 1
+#define BB_MASK (0x1f << 11)
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The BB field in an XL form instruction when it must be the same
+     as the BA field in the same instruction.  */
+#define BBA BB + 1
+  { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
+
+  /* The BD field in a B form instruction.  The lower two bits are
+     forced to zero.  */
+#define BD BBA + 1
+  { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when absolute addressing is
+     used.  */
+#define BDA BD + 1
+  { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDM BDA + 1
+  { 0xfffc, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used
+     and absolute address is used.  */
+#define BDMA BDM + 1
+  { 0xfffc, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDP BDMA + 1
+  { 0xfffc, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used
+     and absolute addressing is used.  */
+#define BDPA BDP + 1
+  { 0xfffc, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BF BDPA + 1
+  /* The CRFD field in an X form instruction.  */
+#define CRFD BF
+  { 0x7, 23, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BFF BF + 1
+  { 0x7, 23, NULL, NULL, 0 },
+
+  /* An optional BF field.  This is used for comparison instructions,
+     in which an omitted BF field is taken as zero.  */
+#define OBF BFF + 1
+  { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The BFA field in an X or XL form instruction.  */
+#define BFA OBF + 1
+  { 0x7, 18, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The BO field in a B form instruction.  Certain values are
+     illegal.  */
+#define BO BFA + 1
+#define BO_MASK (0x1f << 21)
+  { 0x1f, 21, insert_bo, extract_bo, 0 },
+
+  /* The BO field in a B form instruction when the + or - modifier is
+     used.  This is like the BO field, but it must be even.  */
+#define BOE BO + 1
+  { 0x1e, 21, insert_boe, extract_boe, 0 },
+
+#define BH BOE + 1
+  { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The BT field in an X or XL form instruction.  */
+#define BT BH + 1
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The condition register number portion of the BI field in a B form
+     or XL form instruction.  This is used for the extended
+     conditional branch mnemonics, which set the lower two bits of the
+     BI field.  This field is optional.  */
+#define CR BT + 1
+  { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The CRB field in an X form instruction.  */
+#define CRB CR + 1
+  /* The MB field in an M form instruction.  */
+#define MB CRB
+#define MB_MASK (0x1f << 6)
+  { 0x1f, 6, NULL, NULL, 0 },
+
+  /* The CRFS field in an X form instruction.  */
+#define CRFS CRB + 1
+  { 0x7, 0, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The CT field in an X form instruction.  */
+#define CT CRFS + 1
+  /* The MO field in an mbar instruction.  */
+#define MO CT
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The D field in a D form instruction.  This is a displacement off
+     a register, and implies that the next operand is a register in
+     parentheses.  */
+#define D CT + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DE field in a DE form instruction.  This is like D, but is 12
+     bits only.  */
+#define DE D + 1
+  { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DES field in a DES form instruction.  This is like DS, but is 14
+     bits only (12 stored.)  */
+#define DES DE + 1
+  { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DQ field in a DQ form instruction.  This is like D, but the
+     lower four bits are forced to zero. */
+#define DQ DES + 1
+  { 0xfff0, 0, NULL, NULL,
+    PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ },
+
+  /* The DS field in a DS form instruction.  This is like D, but the
+     lower two bits are forced to zero.  */
+#undef DS
+#define DS DQ + 1
+  { 0xfffc, 0, NULL, NULL,
+    PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
+
+  /* The E field in a wrteei instruction.  */
+#define E DS + 1
+  { 0x1, 15, NULL, NULL, 0 },
+
+  /* The FL1 field in a POWER SC form instruction.  */
+#define FL1 E + 1
+  /* The U field in an X form instruction.  */
+#define U FL1
+  { 0xf, 12, NULL, NULL, 0 },
+
+  /* The FL2 field in a POWER SC form instruction.  */
+#define FL2 FL1 + 1
+  { 0x7, 2, NULL, NULL, 0 },
+
+  /* The FLM field in an XFL form instruction.  */
+#define FLM FL2 + 1
+  { 0xff, 17, NULL, NULL, 0 },
+
+  /* The FRA field in an X or A form instruction.  */
+#define FRA FLM + 1
+#define FRA_MASK (0x1f << 16)
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR },
+
+  /* The FRB field in an X or A form instruction.  */
+#define FRB FRA + 1
+#define FRB_MASK (0x1f << 11)
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR },
+
+  /* The FRC field in an A form instruction.  */
+#define FRC FRB + 1
+#define FRC_MASK (0x1f << 6)
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR },
+
+  /* The FRS field in an X form instruction or the FRT field in a D, X
+     or A form instruction.  */
+#define FRS FRC + 1
+#define FRT FRS
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR },
+
+  /* The FXM field in an XFX instruction.  */
+#define FXM FRS + 1
+  { 0xff, 12, insert_fxm, extract_fxm, 0 },
+
+  /* Power4 version for mfcr.  */
+#define FXM4 FXM + 1
+  { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL },
+
+  /* The L field in a D or X form instruction.  */
+#define L FXM4 + 1
+  { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The LEV field in a POWER SVC form instruction.  */
+#define SVC_LEV L + 1
+  { 0x7f, 5, NULL, NULL, 0 },
+
+  /* The LEV field in an SC form instruction.  */
+#define LEV SVC_LEV + 1
+  { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The LI field in an I form instruction.  The lower two bits are
+     forced to zero.  */
+#define LI LEV + 1
+  { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The LI field in an I form instruction when used as an absolute
+     address.  */
+#define LIA LI + 1
+  { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The LS field in an X (sync) form instruction.  */
+#define LS LIA + 1
+  { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The ME field in an M form instruction.  */
+#define ME LS + 1
+#define ME_MASK (0x1f << 1)
+  { 0x1f, 1, NULL, NULL, 0 },
+
+  /* The MB and ME fields in an M form instruction expressed a single
+     operand which is a bitmask indicating which bits to select.  This
+     is a two operand form using PPC_OPERAND_NEXT.  See the
+     description in opcode/ppc.h for what this means.  */
+#define MBE ME + 1
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { -1, 0, insert_mbe, extract_mbe, 0 },
+
+  /* The MB or ME field in an MD or MDS form instruction.  The high
+     bit is wrapped to the low end.  */
+#define MB6 MBE + 2
+#define ME6 MB6
+#define MB6_MASK (0x3f << 5)
+  { 0x3f, 5, insert_mb6, extract_mb6, 0 },
+
+  /* The NB field in an X form instruction.  The value 32 is stored as
+     0.  */
+#define NB MB6 + 1
+  { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 },
+
+  /* The NSI field in a D form instruction.  This is the same as the
+     SI field, only negated.  */
+#define NSI NB + 1
+  { 0xffff, 0, insert_nsi, extract_nsi,
+      PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
+
+  /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction.  */
+#define RA NSI + 1
+#define RA_MASK (0x1f << 16)
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR },
+
+  /* As above, but 0 in the RA field means zero, not r0.  */
+#define RA0 RA + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field in the DQ form lq instruction, which has special
+     value restrictions.  */
+#define RAQ RA0 + 1
+  { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field in a D or X form instruction which is an updating
+     load, which means that the RA field may not be zero and may not
+     equal the RT field.  */
+#define RAL RAQ + 1
+  { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field in an lmw instruction, which has special value
+     restrictions.  */
+#define RAM RAL + 1
+  { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field in a D or X form instruction which is an updating
+     store or an updating floating point load, which means that the RA
+     field may not be zero.  */
+#define RAS RAM + 1
+  { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field of the tlbwe instruction, which is optional.  */
+#define RAOPT RAS + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL },
+
+  /* The RB field in an X, XO, M, or MDS form instruction.  */
+#define RB RAOPT + 1
+#define RB_MASK (0x1f << 11)
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR },
+
+  /* The RB field in an X form instruction when it must be the same as
+     the RS field in the instruction.  This is used for extended
+     mnemonics like mr.  */
+#define RBS RB + 1
+  { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
+
+  /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
+     instruction or the RT field in a D, DS, X, XFX or XO form
+     instruction.  */
+#define RS RBS + 1
+#define RT RS
+#define RT_MASK (0x1f << 21)
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR },
+
+  /* The RS and RT fields of the DS form stq instruction, which have
+     special value restrictions.  */
+#define RSQ RS + 1
+#define RTQ RSQ
+  { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RS field of the tlbwe instruction, which is optional.  */
+#define RSO RSQ + 1
+#define RTO RSO
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL },
+
+  /* The SH field in an X or M form instruction.  */
+#define SH RSO + 1
+#define SH_MASK (0x1f << 11)
+  /* The other UIMM field in a EVX form instruction.  */
+#define EVUIMM SH
+  { 0x1f, 11, NULL, NULL, 0 },
+
+  /* The SH field in an MD form instruction.  This is split.  */
+#define SH6 SH + 1
+#define SH6_MASK ((0x1f << 11) | (1 << 1))
+  { 0x3f, -1, insert_sh6, extract_sh6, 0 },
+
+  /* The SH field of the tlbwe instruction, which is optional.  */
+#define SHO SH6 + 1
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The SI field in a D form instruction.  */
+#define SI SHO + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED },
+
+  /* The SI field in a D form instruction when we accept a wide range
+     of positive values.  */
+#define SISIGNOPT SI + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+
+  /* The SPR field in an XFX form instruction.  This is flipped--the
+     lower 5 bits are stored in the upper 5 and vice- versa.  */
+#define SPR SISIGNOPT + 1
+#define PMR SPR
+#define SPR_MASK (0x3ff << 11)
+  { 0x3ff, 11, insert_spr, extract_spr, 0 },
+
+  /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
+#define SPRBAT SPR + 1
+#define SPRBAT_MASK (0x3 << 17)
+  { 0x3, 17, NULL, NULL, 0 },
+
+  /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
+#define SPRG SPRBAT + 1
+  { 0x1f, 16, insert_sprg, extract_sprg, 0 },
+
+  /* The SR field in an X form instruction.  */
+#define SR SPRG + 1
+  { 0xf, 16, NULL, NULL, 0 },
+
+  /* The STRM field in an X AltiVec form instruction.  */
+#define STRM SR + 1
+  { 0x3, 21, NULL, NULL, 0 },
+
+  /* The SV field in a POWER SC form instruction.  */
+#define SV STRM + 1
+  { 0x3fff, 2, NULL, NULL, 0 },
+
+  /* The TBR field in an XFX form instruction.  This is like the SPR
+     field, but it is optional.  */
+#define TBR SV + 1
+  { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
+
+  /* The TO field in a D or X form instruction.  */
+#define TO TBR + 1
+#define TO_MASK (0x1f << 21)
+  { 0x1f, 21, NULL, NULL, 0 },
+
+  /* The UI field in a D form instruction.  */
+#define UI TO + 1
+  { 0xffff, 0, NULL, NULL, 0 },
+
+  /* The VA field in a VA, VX or VXR form instruction.  */
+#define VA UI + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VB field in a VA, VX or VXR form instruction.  */
+#define VB VA + 1
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VC field in a VA form instruction.  */
+#define VC VB + 1
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VD or VS field in a VA, VX, VXR or X form instruction.  */
+#define VD VC + 1
+#define VS VD
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The SIMM field in a VX form instruction.  */
+#define SIMM VD + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED},
+
+  /* The UIMM field in a VX form instruction, and TE in Z form.  */
+#define UIMM SIMM + 1
+#define TE UIMM
+  { 0x1f, 16, NULL, NULL, 0 },
+
+  /* The SHB field in a VA form instruction.  */
+#define SHB UIMM + 1
+  { 0xf, 6, NULL, NULL, 0 },
+
+  /* The other UIMM field in a half word EVX form instruction.  */
+#define EVUIMM_2 SHB + 1
+  { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The other UIMM field in a word EVX form instruction.  */
+#define EVUIMM_4 EVUIMM_2 + 1
+  { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The other UIMM field in a double EVX form instruction.  */
+#define EVUIMM_8 EVUIMM_4 + 1
+  { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The WS field.  */
+#define WS EVUIMM_8 + 1
+  { 0x7, 11, NULL, NULL, 0 },
+
+  /* The L field in an mtmsrd or A form instruction or W in an X form.  */
+#define A_L WS + 1
+#define W A_L
+  { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+#define RMC A_L + 1
+  { 0x3, 9, NULL, NULL, 0 },
+
+#define R RMC + 1
+  { 0x1, 16, NULL, NULL, 0 },
+
+#define SP R + 1
+  { 0x3, 19, NULL, NULL, 0 },
+
+#define S SP + 1
+  { 0x1, 20, NULL, NULL, 0 },
+
+  /* SH field starting at bit position 16.  */
+#define SH16 S + 1
+  /* The DCM and DGM fields in a Z form instruction.  */
+#define DCM SH16
+#define DGM DCM
+  { 0x3f, 10, NULL, NULL, 0 },
+
+  /* The EH field in larx instruction.  */
+#define EH SH16 + 1
+  { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The L field in an mtfsf or XFL form instruction.  */
+#define XFL_L EH + 1
+  { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL},
+};
+
+const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
+					   / sizeof (powerpc_operands[0]));
+
+/* The functions used to insert and extract complicated operands.  */
+
+/* The BA field in an XL form instruction when it must be the same as
+   the BT field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BT field into the BA field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+static unsigned long
+insert_bat (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static long
+extract_bat (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BB field in an XL form instruction when it must be the same as
+   the BA field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BA field into the BB field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+static unsigned long
+insert_bba (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (((insn >> 16) & 0x1f) << 11);
+}
+
+static long
+extract_bba (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BD field in a B form instruction when the - modifier is used.
+   This modifier means that the branch is not expected to be taken.
+   For chips built to versions of the architecture prior to version 2
+   (ie. not Power4 compatible), we set the y bit of the BO field to 1
+   if the offset is negative.  When extracting, we require that the y
+   bit be 1 and that the offset be positive, since if the y bit is 0
+   we just want to print the normal form of the instruction.
+   Power4 compatible targets use two bits, "a", and "t", instead of
+   the "y" bit.  "at" == 00 => no hint, "at" == 01 => unpredictable,
+   "at" == 10 => not taken, "at" == 11 => taken.  The "t" bit is 00001
+   in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000
+   for branch on CTR.  We only handle the taken/not-taken hint here.
+   Note that we don't relax the conditions tested here when
+   disassembling with -Many because insns using extract_bdm and
+   extract_bdp always occur in pairs.  One or the other will always
+   be valid.  */
+
+static unsigned long
+insert_bdm (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if ((value & 0x8000) != 0)
+	insn |= 1 << 21;
+    }
+  else
+    {
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+	insn |= 0x02 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+	insn |= 0x08 << 21;
+    }
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdm (unsigned long insn,
+	     int dialect,
+	     int *invalid)
+{
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0))
+	*invalid = 1;
+    }
+  else
+    {
+      if ((insn & (0x17 << 21)) != (0x06 << 21)
+	  && (insn & (0x1d << 21)) != (0x18 << 21))
+	*invalid = 1;
+    }
+
+  return ((insn & 0xfffc) ^ 0x8000) - 0x8000;
+}
+
+/* The BD field in a B form instruction when the + modifier is used.
+   This is like BDM, above, except that the branch is expected to be
+   taken.  */
+
+static unsigned long
+insert_bdp (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if ((value & 0x8000) == 0)
+	insn |= 1 << 21;
+    }
+  else
+    {
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+	insn |= 0x03 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+	insn |= 0x09 << 21;
+    }
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdp (unsigned long insn,
+	     int dialect,
+	     int *invalid)
+{
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0))
+	*invalid = 1;
+    }
+  else
+    {
+      if ((insn & (0x17 << 21)) != (0x07 << 21)
+	  && (insn & (0x1d << 21)) != (0x19 << 21))
+	*invalid = 1;
+    }
+
+  return ((insn & 0xfffc) ^ 0x8000) - 0x8000;
+}
+
+/* Check for legal values of a BO field.  */
+
+static int
+valid_bo (long value, int dialect, int extract)
+{
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      int valid;
+      /* Certain encodings have bits that are required to be zero.
+	 These are (z must be zero, y may be anything):
+	     001zy
+	     011zy
+	     1z00y
+	     1z01y
+	     1z1zz
+      */
+      switch (value & 0x14)
+	{
+	default:
+	case 0:
+	  valid = 1;
+	  break;
+	case 0x4:
+	  valid = (value & 0x2) == 0;
+	  break;
+	case 0x10:
+	  valid = (value & 0x8) == 0;
+	  break;
+	case 0x14:
+	  valid = value == 0x14;
+	  break;
+	}
+      /* When disassembling with -Many, accept power4 encodings too.  */
+      if (valid
+	  || (dialect & PPC_OPCODE_ANY) == 0
+	  || !extract)
+	return valid;
+    }
+
+  /* Certain encodings have bits that are required to be zero.
+     These are (z must be zero, a & t may be anything):
+	 0000z
+	 0001z
+	 0100z
+	 0101z
+	 001at
+	 011at
+	 1a00t
+	 1a01t
+	 1z1zz
+  */
+  if ((value & 0x14) == 0)
+    return (value & 0x1) == 0;
+  else if ((value & 0x14) == 0x14)
+    return value == 0x14;
+  else
+    return 1;
+}
+
+/* The BO field in a B form instruction.  Warn about attempts to set
+   the field to an illegal value.  */
+
+static unsigned long
+insert_bo (unsigned long insn,
+	   long value,
+	   int dialect,
+	   const char **errmsg)
+{
+  if (!valid_bo (value, dialect, 0))
+    *errmsg = _("invalid conditional option");
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_bo (unsigned long insn,
+	    int dialect,
+	    int *invalid)
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (!valid_bo (value, dialect, 1))
+    *invalid = 1;
+  return value;
+}
+
+/* The BO field in a B form instruction when the + or - modifier is
+   used.  This is like the BO field, but it must be even.  When
+   extracting it, we force it to be even.  */
+
+static unsigned long
+insert_boe (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg)
+{
+  if (!valid_bo (value, dialect, 0))
+    *errmsg = _("invalid conditional option");
+  else if ((value & 1) != 0)
+    *errmsg = _("attempt to set y bit when using + or - modifier");
+
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_boe (unsigned long insn,
+	     int dialect,
+	     int *invalid)
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (!valid_bo (value, dialect, 1))
+    *invalid = 1;
+  return value & 0x1e;
+}
+
+/* FXM mask in mfcr and mtcrf instructions.  */
+
+static unsigned long
+insert_fxm (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg)
+{
+  /* If we're handling the mfocrf and mtocrf insns ensure that exactly
+     one bit of the mask field is set.  */
+  if ((insn & (1 << 20)) != 0)
+    {
+      if (value == 0 || (value & -value) != value)
+	{
+	  *errmsg = _("invalid mask field");
+	  value = 0;
+	}
+    }
+
+  /* If the optional field on mfcr is missing that means we want to use
+     the old form of the instruction that moves the whole cr.  In that
+     case we'll have VALUE zero.  There doesn't seem to be a way to
+     distinguish this from the case where someone writes mfcr %r3,0.  */
+  else if (value == 0)
+    ;
+
+  /* If only one bit of the FXM field is set, we can use the new form
+     of the instruction, which is faster.  Unlike the Power4 branch hint
+     encoding, this is not backward compatible.  Do not generate the
+     new form unless -mpower4 has been given, or -many and the two
+     operand form of mfcr was used.  */
+  else if ((value & -value) == value
+	   && ((dialect & PPC_OPCODE_POWER4) != 0
+	       || ((dialect & PPC_OPCODE_ANY) != 0
+		   && (insn & (0x3ff << 1)) == 19 << 1)))
+    insn |= 1 << 20;
+
+  /* Any other value on mfcr is an error.  */
+  else if ((insn & (0x3ff << 1)) == 19 << 1)
+    {
+      *errmsg = _("ignoring invalid mfcr mask");
+      value = 0;
+    }
+
+  return insn | ((value & 0xff) << 12);
+}
+
+static long
+extract_fxm (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  long mask = (insn >> 12) & 0xff;
+
+  /* Is this a Power4 insn?  */
+  if ((insn & (1 << 20)) != 0)
+    {
+      /* Exactly one bit of MASK should be set.  */
+      if (mask == 0 || (mask & -mask) != mask)
+	*invalid = 1;
+    }
+
+  /* Check that non-power4 form of mfcr has a zero MASK.  */
+  else if ((insn & (0x3ff << 1)) == 19 << 1)
+    {
+      if (mask != 0)
+	*invalid = 1;
+    }
+
+  return mask;
+}
+
+/* The MB and ME fields in an M form instruction expressed as a single
+   operand which is itself a bitmask.  The extraction function always
+   marks it as invalid, since we never want to recognize an
+   instruction which uses a field of this type.  */
+
+static unsigned long
+insert_mbe (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  unsigned long uval, mask;
+  int mb, me, mx, count, last;
+
+  uval = value;
+
+  if (uval == 0)
+    {
+      *errmsg = _("illegal bitmask");
+      return insn;
+    }
+
+  mb = 0;
+  me = 32;
+  if ((uval & 1) != 0)
+    last = 1;
+  else
+    last = 0;
+  count = 0;
+
+  /* mb: location of last 0->1 transition */
+  /* me: location of last 1->0 transition */
+  /* count: # transitions */
+
+  for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1)
+    {
+      if ((uval & mask) && !last)
+	{
+	  ++count;
+	  mb = mx;
+	  last = 1;
+	}
+      else if (!(uval & mask) && last)
+	{
+	  ++count;
+	  me = mx;
+	  last = 0;
+	}
+    }
+  if (me == 0)
+    me = 32;
+
+  if (count != 2 && (count != 0 || ! last))
+    *errmsg = _("illegal bitmask");
+
+  return insn | (mb << 6) | ((me - 1) << 1);
+}
+
+static long
+extract_mbe (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  long ret;
+  int mb, me;
+  int i;
+
+  *invalid = 1;
+
+  mb = (insn >> 6) & 0x1f;
+  me = (insn >> 1) & 0x1f;
+  if (mb < me + 1)
+    {
+      ret = 0;
+      for (i = mb; i <= me; i++)
+	ret |= 1L << (31 - i);
+    }
+  else if (mb == me + 1)
+    ret = ~0;
+  else /* (mb > me + 1) */
+    {
+      ret = ~0;
+      for (i = me + 1; i < mb; i++)
+	ret &= ~(1L << (31 - i));
+    }
+  return ret;
+}
+
+/* The MB or ME field in an MD or MDS form instruction.  The high bit
+   is wrapped to the low end.  */
+
+static unsigned long
+insert_mb6 (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | ((value & 0x1f) << 6) | (value & 0x20);
+}
+
+static long
+extract_mb6 (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
+{
+  return ((insn >> 6) & 0x1f) | (insn & 0x20);
+}
+
+/* The NB field in an X form instruction.  The value 32 is stored as
+   0.  */
+
+static long
+extract_nb (unsigned long insn,
+	    int dialect ATTRIBUTE_UNUSED,
+	    int *invalid ATTRIBUTE_UNUSED)
+{
+  long ret;
+
+  ret = (insn >> 11) & 0x1f;
+  if (ret == 0)
+    ret = 32;
+  return ret;
+}
+
+/* The NSI field in a D form instruction.  This is the same as the SI
+   field, only negated.  The extraction function always marks it as
+   invalid, since we never want to recognize an instruction which uses
+   a field of this type.  */
+
+static unsigned long
+insert_nsi (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (-value & 0xffff);
+}
+
+static long
+extract_nsi (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  *invalid = 1;
+  return -(((insn & 0xffff) ^ 0x8000) - 0x8000);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   load, which means that the RA field may not be zero and may not
+   equal the RT field.  */
+
+static unsigned long
+insert_ral (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  if (value == 0
+      || (unsigned long) value == ((insn >> 21) & 0x1f))
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in an lmw instruction, which has special value
+   restrictions.  */
+
+static unsigned long
+insert_ram (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  if ((unsigned long) value >= ((insn >> 21) & 0x1f))
+    *errmsg = _("index register in load range");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in the DQ form lq instruction, which has special
+   value restrictions.  */
+
+static unsigned long
+insert_raq (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  long rtvalue = (insn & RT_MASK) >> 21;
+
+  if (value == rtvalue)
+    *errmsg = _("source and target register operands must be different");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   store or an updating floating point load, which means that the RA
+   field may not be zero.  */
+
+static unsigned long
+insert_ras (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  if (value == 0)
+    *errmsg = _("invalid register operand when updating");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RB field in an X form instruction when it must be the same as
+   the RS field in the instruction.  This is used for extended
+   mnemonics like mr.  This operand is marked FAKE.  The insertion
+   function just copies the BT field into the BA field, and the
+   extraction function just checks that the fields are the same.  */
+
+static unsigned long
+insert_rbs (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | (((insn >> 21) & 0x1f) << 11);
+}
+
+static long
+extract_rbs (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
+{
+  if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The SH field in an MD form instruction.  This is split.  */
+
+static unsigned long
+insert_sh6 (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
+}
+
+static long
+extract_sh6 (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
+{
+  return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
+}
+
+/* The SPR field in an XFX form instruction.  This is flipped--the
+   lower 5 bits are stored in the upper 5 and vice- versa.  */
+
+static unsigned long
+insert_spr (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_spr (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
+{
+  return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+}
+
+/* Some dialects have 8 SPRG registers instead of the standard 4.  */
+
+static unsigned long
+insert_sprg (unsigned long insn,
+	     long value,
+	     int dialect,
+	     const char **errmsg)
+{
+  /* This check uses PPC_OPCODE_403 because PPC405 is later defined
+     as a synonym.  If ever a 405 specific dialect is added this
+     check should use that instead.  */
+  if (value > 7
+      || (value > 3
+	  && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0))
+    *errmsg = _("invalid sprg number");
+
+  /* If this is mfsprg4..7 then use spr 260..263 which can be read in
+     user mode.  Anything else must use spr 272..279.  */
+  if (value <= 3 || (insn & 0x100) != 0)
+    value |= 0x10;
+
+  return insn | ((value & 0x17) << 16);
+}
+
+static long
+extract_sprg (unsigned long insn,
+	      int dialect,
+	      int *invalid)
+{
+  unsigned long val = (insn >> 16) & 0x1f;
+
+  /* mfsprg can use 260..263 and 272..279.  mtsprg only uses spr 272..279
+     If not BOOKE or 405, then both use only 272..275.  */
+  if (val <= 3
+      || (val < 0x10 && (insn & 0x100) != 0)
+      || (val - 0x10 > 3
+	  && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0))
+    *invalid = 1;
+  return val & 7;
+}
+
+/* The TBR field in an XFX instruction.  This is just like SPR, but it
+   is optional.  When TBR is omitted, it must be inserted as 268 (the
+   magic number of the TB register).  These functions treat 0
+   (indicating an omitted optional operand) as 268.  This means that
+   ``mftb 4,0'' is not handled correctly.  This does not matter very
+   much, since the architecture manual does not define mftb as
+   accepting any values other than 268 or 269.  */
+
+#define TB (268)
+
+static unsigned long
+insert_tbr (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  if (value == 0)
+    value = TB;
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_tbr (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
+{
+  long ret;
+
+  ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+  if (ret == TB)
+    ret = 0;
+  return ret;
+}
+
+/* Macros used to form opcodes.  */
+
+/* The main opcode.  */
+#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26)
+#define OP_MASK OP (0x3f)
+
+/* The main opcode combined with a trap code in the TO field of a D
+   form instruction.  Used for extended mnemonics for the trap
+   instructions.  */
+#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define OPTO_MASK (OP_MASK | TO_MASK)
+
+/* The main opcode combined with a comparison size bit in the L field
+   of a D form or X form instruction.  Used for extended mnemonics for
+   the comparison instructions.  */
+#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21))
+#define OPL_MASK OPL (0x3f,1)
+
+/* An A form instruction.  */
+#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1))
+#define A_MASK A (0x3f, 0x1f, 1)
+
+/* An A_MASK with the FRB field fixed.  */
+#define AFRB_MASK (A_MASK | FRB_MASK)
+
+/* An A_MASK with the FRC field fixed.  */
+#define AFRC_MASK (A_MASK | FRC_MASK)
+
+/* An A_MASK with the FRA and FRC fields fixed.  */
+#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
+
+/* An AFRAFRC_MASK, but with L bit clear.  */
+#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16))
+
+/* A B form instruction.  */
+#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1))
+#define B_MASK B (0x3f, 1, 1)
+
+/* A B form instruction setting the BO field.  */
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
+
+/* A BBO_MASK with the y bit of the BO field removed.  This permits
+   matching a conditional branch regardless of the setting of the y
+   bit.  Similarly for the 'at' bits used for power4 branch hints.  */
+#define Y_MASK   (((unsigned long) 1) << 21)
+#define AT1_MASK (((unsigned long) 3) << 21)
+#define AT2_MASK (((unsigned long) 9) << 21)
+#define BBOY_MASK  (BBO_MASK &~ Y_MASK)
+#define BBOAT_MASK (BBO_MASK &~ AT1_MASK)
+
+/* A B form instruction setting the BO field and the condition bits of
+   the BI field.  */
+#define BBOCB(op, bo, cb, aa, lk) \
+  (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16))
+#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
+
+/* A BBOCB_MASK with the y bit of the BO field removed.  */
+#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK)
+#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK)
+
+/* A BBOYCB_MASK in which the BI field is fixed.  */
+#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
+
+/* An Context form instruction.  */
+#define CTX(op, xop)   (OP (op) | (((unsigned long)(xop)) & 0x7))
+#define CTX_MASK CTX(0x3f, 0x7)
+
+/* An User Context form instruction.  */
+#define UCTX(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define UCTX_MASK UCTX(0x3f, 0x1f)
+
+/* The main opcode mask with the RA field clear.  */
+#define DRA_MASK (OP_MASK | RA_MASK)
+
+/* A DS form instruction.  */
+#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
+#define DS_MASK DSO (0x3f, 3)
+
+/* A DE form instruction.  */
+#define DEO(op, xop) (OP (op) | ((xop) & 0xf))
+#define DE_MASK DEO (0x3e, 0xf)
+
+/* An EVSEL form instruction.  */
+#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3)
+#define EVSEL_MASK EVSEL(0x3f, 0xff)
+
+/* An M form instruction.  */
+#define M(op, rc) (OP (op) | ((rc) & 1))
+#define M_MASK M (0x3f, 1)
+
+/* An M form instruction with the ME field specified.  */
+#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1))
+
+/* An M_MASK with the MB and ME fields fixed.  */
+#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
+
+/* An M_MASK with the SH and ME fields fixed.  */
+#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
+
+/* An MD form instruction.  */
+#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1))
+#define MD_MASK MD (0x3f, 0x7, 1)
+
+/* An MD_MASK with the MB field fixed.  */
+#define MDMB_MASK (MD_MASK | MB6_MASK)
+
+/* An MD_MASK with the SH field fixed.  */
+#define MDSH_MASK (MD_MASK | SH6_MASK)
+
+/* An MDS form instruction.  */
+#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1))
+#define MDS_MASK MDS (0x3f, 0xf, 1)
+
+/* An MDS_MASK with the MB field fixed.  */
+#define MDSMB_MASK (MDS_MASK | MB6_MASK)
+
+/* An SC form instruction.  */
+#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
+
+/* An VX form instruction.  */
+#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
+
+/* The mask for an VX form instruction.  */
+#define VX_MASK	VX(0x3f, 0x7ff)
+
+/* An VA form instruction.  */
+#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
+
+/* The mask for an VA form instruction.  */
+#define VXA_MASK VXA(0x3f, 0x3f)
+
+/* An VXR form instruction.  */
+#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
+
+/* The mask for a VXR form instruction.  */
+#define VXR_MASK VXR(0x3f, 0x3ff, 1)
+
+/* An X form instruction.  */
+#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* A Z form instruction.  */
+#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1))
+
+/* An X form instruction with the RC bit specified.  */
+#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
+
+/* A Z form instruction with the RC bit specified.  */
+#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1))
+
+/* The mask for an X form instruction.  */
+#define X_MASK XRC (0x3f, 0x3ff, 1)
+
+/* The mask for a Z form instruction.  */
+#define Z_MASK ZRC (0x3f, 0x1ff, 1)
+#define Z2_MASK ZRC (0x3f, 0xff, 1)
+
+/* An X_MASK with the RA field fixed.  */
+#define XRA_MASK (X_MASK | RA_MASK)
+
+/* An XRA_MASK with the W field clear.  */
+#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16))
+
+/* An X_MASK with the RB field fixed.  */
+#define XRB_MASK (X_MASK | RB_MASK)
+
+/* An X_MASK with the RT field fixed.  */
+#define XRT_MASK (X_MASK | RT_MASK)
+
+/* An XRT_MASK mask with the L bits clear.  */
+#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21))
+
+/* An X_MASK with the RA and RB fields fixed.  */
+#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+
+/* An XRARB_MASK, but with the L bit clear.  */
+#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16))
+
+/* An X_MASK with the RT and RA fields fixed.  */
+#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
+
+/* An XRTRA_MASK, but with L bit clear.  */
+#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21))
+
+/* An X form instruction with the L bit specified.  */
+#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21))
+
+/* The mask for an X form comparison instruction.  */
+#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22))
+
+/* The mask for an X form comparison instruction with the L field
+   fixed.  */
+#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21))
+
+/* An X form trap instruction with the TO field specified.  */
+#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define XTO_MASK (X_MASK | TO_MASK)
+
+/* An X form tlb instruction with the SH field specified.  */
+#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11))
+#define XTLB_MASK (X_MASK | SH_MASK)
+
+/* An X form sync instruction.  */
+#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21))
+
+/* An X form sync instruction with everything filled in except the LS field.  */
+#define XSYNC_MASK (0xff9fffff)
+
+/* An X_MASK, but with the EH bit clear.  */
+#define XEH_MASK (X_MASK & ~((unsigned long )1))
+
+/* An X form AltiVec dss instruction.  */
+#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25))
+#define XDSS_MASK XDSS(0x3f, 0x3ff, 1)
+
+/* An XFL form instruction.  */
+#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
+#define XFL_MASK XFL (0x3f, 0x3ff, 1)
+
+/* An X form isel instruction.  */
+#define XISEL(op, xop)  (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
+#define XISEL_MASK      XISEL(0x3f, 0x1f)
+
+/* An XL form instruction with the LK field set to 0.  */
+#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* An XL form instruction which uses the LK field.  */
+#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
+
+/* The mask for an XL form instruction.  */
+#define XL_MASK XLLK (0x3f, 0x3ff, 1)
+
+/* An XL form instruction which explicitly sets the BO field.  */
+#define XLO(op, bo, xop, lk) \
+  (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define XLO_MASK (XL_MASK | BO_MASK)
+
+/* An XL form instruction which explicitly sets the y bit of the BO
+   field.  */
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21))
+#define XLYLK_MASK (XL_MASK | Y_MASK)
+
+/* An XL form instruction which sets the BO field and the condition
+   bits of the BI field.  */
+#define XLOCB(op, bo, cb, xop, lk) \
+  (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16))
+#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
+
+/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed.  */
+#define XLBB_MASK (XL_MASK | BB_MASK)
+#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
+#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
+
+/* A mask for branch instructions using the BH field.  */
+#define XLBH_MASK (XL_MASK | (0x1c << 11))
+
+/* An XL_MASK with the BO and BB fields fixed.  */
+#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
+
+/* An XL_MASK with the BO, BI and BB fields fixed.  */
+#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
+
+/* An XO form instruction.  */
+#define XO(op, xop, oe, rc) \
+  (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1))
+#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
+
+/* An XO_MASK with the RB field fixed.  */
+#define XORB_MASK (XO_MASK | RB_MASK)
+
+/* An XS form instruction.  */
+#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1))
+#define XS_MASK XS (0x3f, 0x1ff, 1)
+
+/* A mask for the FXM version of an XFX form instruction.  */
+#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20))
+
+/* An XFX form instruction with the FXM field filled in.  */
+#define XFXM(op, xop, fxm, p4) \
+  (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \
+   | ((unsigned long)(p4) << 20))
+
+/* An XFX form instruction with the SPR field filled in.  */
+#define XSPR(op, xop, spr) \
+  (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6))
+#define XSPR_MASK (X_MASK | SPR_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRBAT field.  */
+#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRG field.  */
+#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16))
+
+/* An X form instruction with everything filled in except the E field.  */
+#define XE_MASK (0xffff7fff)
+
+/* An X form user context instruction.  */
+#define XUC(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define XUC_MASK      XUC(0x3f, 0x1f)
+
+/* The BO encodings used in extended conditional branch mnemonics.  */
+#define BODNZF	(0x0)
+#define BODNZFP	(0x1)
+#define BODZF	(0x2)
+#define BODZFP	(0x3)
+#define BODNZT	(0x8)
+#define BODNZTP	(0x9)
+#define BODZT	(0xa)
+#define BODZTP	(0xb)
+
+#define BOF	(0x4)
+#define BOFP	(0x5)
+#define BOFM4	(0x6)
+#define BOFP4	(0x7)
+#define BOT	(0xc)
+#define BOTP	(0xd)
+#define BOTM4	(0xe)
+#define BOTP4	(0xf)
+
+#define BODNZ	(0x10)
+#define BODNZP	(0x11)
+#define BODZ	(0x12)
+#define BODZP	(0x13)
+#define BODNZM4 (0x18)
+#define BODNZP4 (0x19)
+#define BODZM4	(0x1a)
+#define BODZP4	(0x1b)
+
+#define BOU	(0x14)
+
+/* The BI condition bit encodings used in extended conditional branch
+   mnemonics.  */
+#define CBLT	(0)
+#define CBGT	(1)
+#define CBEQ	(2)
+#define CBSO	(3)
+
+/* The TO encodings used in extended trap mnemonics.  */
+#define TOLGT	(0x1)
+#define TOLLT	(0x2)
+#define TOEQ	(0x4)
+#define TOLGE	(0x5)
+#define TOLNL	(0x5)
+#define TOLLE	(0x6)
+#define TOLNG	(0x6)
+#define TOGT	(0x8)
+#define TOGE	(0xc)
+#define TONL	(0xc)
+#define TOLT	(0x10)
+#define TOLE	(0x14)
+#define TONG	(0x14)
+#define TONE	(0x18)
+#define TOU	(0x1f)
+
+/* Smaller names for the flags so each entry in the opcodes table will
+   fit on a single line.  */
+#undef	PPC
+#define PPC     PPC_OPCODE_PPC
+#define PPCCOM	PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM
+#define POWER4	PPC_OPCODE_POWER4
+#define POWER5	PPC_OPCODE_POWER5
+#define POWER6	PPC_OPCODE_POWER6
+#define CELL	PPC_OPCODE_CELL
+#define PPC32   PPC_OPCODE_32 | PPC_OPCODE_PPC
+#define PPC64   PPC_OPCODE_64 | PPC_OPCODE_PPC
+#define PPC403	PPC_OPCODE_403
+#define PPC405	PPC403
+#define PPC440	PPC_OPCODE_440
+#define PPC750	PPC
+#define PPC860	PPC
+#define PPCVEC	PPC_OPCODE_ALTIVEC
+#define	POWER   PPC_OPCODE_POWER
+#define	POWER2	PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define PPCPWR2	PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define	POWER32	PPC_OPCODE_POWER | PPC_OPCODE_32
+#define	COM     PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define	COM32   PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32
+#define	M601    PPC_OPCODE_POWER | PPC_OPCODE_601
+#define PWRCOM	PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON
+#define	MFDEC1	PPC_OPCODE_POWER
+#define	MFDEC2	PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE
+#define BOOKE	PPC_OPCODE_BOOKE
+#define BOOKE64	PPC_OPCODE_BOOKE64
+#define CLASSIC	PPC_OPCODE_CLASSIC
+#define PPCE300 PPC_OPCODE_E300
+#define PPCSPE	PPC_OPCODE_SPE
+#define PPCISEL	PPC_OPCODE_ISEL
+#define PPCEFS	PPC_OPCODE_EFS
+#define PPCBRLK	PPC_OPCODE_BRLOCK
+#define PPCPMR	PPC_OPCODE_PMR
+#define PPCCHLK	PPC_OPCODE_CACHELCK
+#define PPCCHLK64	PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64
+#define PPCRFMCI	PPC_OPCODE_RFMCI
+
+/* The opcode table.
+
+   The format of the opcode table is:
+
+   NAME	     OPCODE	MASK		FLAGS		{ OPERANDS }
+
+   NAME is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   FLAGS are flags indicated what processors support the instruction.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches, so this table is sorted to put more
+   specific instructions before more general instructions.  It is also
+   sorted by major opcode.  */
+
+const struct powerpc_opcode powerpc_opcodes[] = {
+{ "attn",    X(0,256), X_MASK,		POWER4,		{ 0 } },
+{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnli",   OPTO(2,TONL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdngi",   OPTO(2,TONG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnei",   OPTO(2,TONE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdi",     OP(2),	OP_MASK,	PPC64,		{ TO, RA, SI } },
+
+{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllti",  OPTO(3,TOLLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllti",   OPTO(3,TOLLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllei",  OPTO(3,TOLLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllei",   OPTO(3,TOLLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgti",   OPTO(3,TOGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgti",    OPTO(3,TOGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgei",   OPTO(3,TOGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgei",    OPTO(3,TOGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnli",   OPTO(3,TONL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnli",    OPTO(3,TONL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlti",   OPTO(3,TOLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlti",    OPTO(3,TOLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlei",   OPTO(3,TOLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlei",    OPTO(3,TOLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twngi",   OPTO(3,TONG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tngi",    OPTO(3,TONG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnei",   OPTO(3,TONE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnei",    OPTO(3,TONE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twi",     OP(3),	OP_MASK,	PPCCOM,		{ TO, RA, SI } },
+{ "ti",      OP(3),	OP_MASK,	PWRCOM,		{ TO, RA, SI } },
+
+{ "macchw",	XO(4,172,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchw.",	XO(4,172,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwo",	XO(4,172,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwo.",	XO(4,172,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchws",	XO(4,236,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchws.",	XO(4,236,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwso",	XO(4,236,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwso.",	XO(4,236,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsu",	XO(4,204,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsu.",	XO(4,204,0,1), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsuo",	XO(4,204,1,0), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsuo.",	XO(4,204,1,1), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwu",	XO(4,140,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwu.",	XO(4,140,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwuo",	XO(4,140,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwuo.",	XO(4,140,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhw",	XO(4,44,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhw.",	XO(4,44,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwo",	XO(4,44,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwo.",	XO(4,44,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhws",	XO(4,108,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhws.",	XO(4,108,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwso",	XO(4,108,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwso.",	XO(4,108,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsu",	XO(4,76,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsu.",	XO(4,76,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsuo",	XO(4,76,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsuo.",	XO(4,76,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwu",	XO(4,12,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwu.",	XO(4,12,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwuo",	XO(4,12,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwuo.",	XO(4,12,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhw",	XO(4,428,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhw.",	XO(4,428,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwo",	XO(4,428,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwo.",	XO(4,428,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhws",	XO(4,492,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhws.",	XO(4,492,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwso",	XO(4,492,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwso.",	XO(4,492,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsu",	XO(4,460,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsu.",	XO(4,460,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsuo",	XO(4,460,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsuo.",	XO(4,460,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwu",	XO(4,396,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwu.",	XO(4,396,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwuo",	XO(4,396,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwuo.",	XO(4,396,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchw",	XRC(4,168,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchw.",	XRC(4,168,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchwu",	XRC(4,136,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchwu.",	XRC(4,136,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhw",	XRC(4,40,0),   X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhw.",	XRC(4,40,1),   X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhwu",	XRC(4,8,0),    X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhwu.",	XRC(4,8,1),    X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhw",	XRC(4,424,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhw.",	XRC(4,424,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhwu",	XRC(4,392,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhwu.",	XRC(4,392,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchw",	XO(4,174,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchw.",	XO(4,174,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwo",	XO(4,174,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwo.",	XO(4,174,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchws",	XO(4,238,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchws.",	XO(4,238,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwso",	XO(4,238,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwso.",	XO(4,238,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhw",	XO(4,46,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhw.",	XO(4,46,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwo",	XO(4,46,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwo.",	XO(4,46,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhws",	XO(4,110,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhws.",	XO(4,110,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwso",	XO(4,110,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwso.",	XO(4,110,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhw",	XO(4,430,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhw.",	XO(4,430,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwo",	XO(4,430,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwo.",	XO(4,430,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhws",	XO(4,494,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhws.",	XO(4,494,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwso",	XO(4,494,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwso.",	XO(4,494,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mfvscr",  VX(4, 1540), VX_MASK,	PPCVEC,		{ VD } },
+{ "mtvscr",  VX(4, 1604), VX_MASK,	PPCVEC,		{ VB } },
+
+  /* Double-precision opcodes.  */
+  /* Some of these conflict with AltiVec, so move them before, since
+     PPCVEC includes the PPC_OPCODE_PPC set.  */
+{ "efscfd",   VX(4, 719), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdabs",   VX(4, 740), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdnabs",  VX(4, 741), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdneg",   VX(4, 742), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdadd",   VX(4, 736), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdsub",   VX(4, 737), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdmul",   VX(4, 744), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efddiv",   VX(4, 745), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdcmpgt", VX(4, 748), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcmplt", VX(4, 749), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcmpeq", VX(4, 750), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtstgt", VX(4, 764), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtstlt", VX(4, 765), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtsteq", VX(4, 766), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcfsi",  VX(4, 753), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfsid", VX(4, 739), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfui",  VX(4, 752), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfuid", VX(4, 738), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfsf",  VX(4, 755), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfuf",  VX(4, 754), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsi",  VX(4, 757), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsidz",VX(4, 747), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsiz", VX(4, 762), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctui",  VX(4, 756), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuidz",VX(4, 746), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuiz", VX(4, 760), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsf",  VX(4, 759), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuf",  VX(4, 758), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfs",   VX(4, 751), VX_MASK,	PPCEFS,		{ RS, RB } },
+  /* End of double-precision opcodes.  */
+
+{ "vaddcuw", VX(4,  384), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddfp",  VX(4,   10), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsbs", VX(4,  768), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddshs", VX(4,  832), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsws", VX(4,  896), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubm", VX(4,    0), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubs", VX(4,  512), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhm", VX(4,   64), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhs", VX(4,  576), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduwm", VX(4,  128), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduws", VX(4,  640), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vand",    VX(4, 1028), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vandc",   VX(4, 1092), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsb",  VX(4, 1282), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsh",  VX(4, 1346), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsw",  VX(4, 1410), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgub",  VX(4, 1026), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguh",  VX(4, 1090), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguw",  VX(4, 1154), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vcfsx",   VX(4,  842), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcfux",   VX(4,  778), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcmpbfp",   VXR(4, 966, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpbfp.",  VXR(4, 966, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp",  VXR(4, 198, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb",  VXR(4,   6, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb.", VXR(4,   6, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh",  VXR(4,  70, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh.", VXR(4,  70, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw",  VXR(4, 134, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp",  VXR(4, 454, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp",  VXR(4, 710, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb",  VXR(4, 774, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh",  VXR(4, 838, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw",  VXR(4, 902, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub",  VXR(4, 518, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh",  VXR(4, 582, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw",  VXR(4, 646, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vctsxs",    VX(4,  970), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vctuxs",    VX(4,  906), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vexptefp",  VX(4,  394), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vlogefp",   VX(4,  458), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vmaddfp",   VXA(4,  46), VXA_MASK,	PPCVEC,		{ VD, VA, VC, VB } },
+{ "vmaxfp",    VX(4, 1034), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsb",    VX(4,  258), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsh",    VX(4,  322), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsw",    VX(4,  386), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxub",    VX(4,    2), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuh",    VX(4,   66), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuw",    VX(4,  130), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmhaddshs", VXA(4,  32), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmhraddshs", VXA(4, 33), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vminfp",    VX(4, 1098), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsb",    VX(4,  770), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsh",    VX(4,  834), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsw",    VX(4,  898), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminub",    VX(4,  514), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuh",    VX(4,  578), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuw",    VX(4,  642), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmladduhm", VXA(4,  34), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmrghb",    VX(4,   12), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrghh",    VX(4,   76), VX_MASK,    PPCVEC,		{ VD, VA, VB } },
+{ "vmrghw",    VX(4,  140), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglb",    VX(4,  268), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglh",    VX(4,  332), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglw",    VX(4,  396), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmsummbm",  VXA(4,  37), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshm",  VXA(4,  40), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshs",  VXA(4,  41), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumubm",  VXA(4,  36), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhm",  VXA(4,  38), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhs",  VXA(4,  39), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmulesb",   VX(4,  776), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulesh",   VX(4,  840), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleub",   VX(4,  520), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleuh",   VX(4,  584), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosb",   VX(4,  264), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosh",   VX(4,  328), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuloub",   VX(4,    8), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulouh",   VX(4,   72), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vnmsubfp",  VXA(4,  47), VXA_MASK,	PPCVEC,		{ VD, VA, VC, VB } },
+{ "vnor",      VX(4, 1284), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vor",       VX(4, 1156), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vperm",     VXA(4,  43), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vpkpx",     VX(4,  782), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshss",   VX(4,  398), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshus",   VX(4,  270), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswss",   VX(4,  462), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswus",   VX(4,  334), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhum",   VX(4,   14), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhus",   VX(4,  142), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwum",   VX(4,   78), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwus",   VX(4,  206), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrefp",     VX(4,  266), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfim",     VX(4,  714), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfin",     VX(4,  522), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfip",     VX(4,  650), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfiz",     VX(4,  586), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrlb",      VX(4,    4), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlh",      VX(4,   68), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlw",      VX(4,  132), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrsqrtefp", VX(4,  330), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vsel",      VXA(4,  42), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vsl",       VX(4,  452), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslb",      VX(4,  260), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsldoi",    VXA(4,  44), VXA_MASK,	PPCVEC,		{ VD, VA, VB, SHB } },
+{ "vslh",      VX(4,  324), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslo",      VX(4, 1036), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslw",      VX(4,  388), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vspltb",    VX(4,  524), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsplth",    VX(4,  588), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vspltisb",  VX(4,  780), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltish",  VX(4,  844), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltisw",  VX(4,  908), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltw",    VX(4,  652), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsr",       VX(4,  708), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrab",     VX(4,  772), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrah",     VX(4,  836), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsraw",     VX(4,  900), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrb",      VX(4,  516), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrh",      VX(4,  580), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsro",      VX(4, 1100), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrw",      VX(4,  644), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubcuw",   VX(4, 1408), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubfp",    VX(4,   74), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsbs",   VX(4, 1792), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubshs",   VX(4, 1856), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsws",   VX(4, 1920), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububm",   VX(4, 1024), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububs",   VX(4, 1536), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhm",   VX(4, 1088), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhs",   VX(4, 1600), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuwm",   VX(4, 1152), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuws",   VX(4, 1664), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsumsws",   VX(4, 1928), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum2sws",  VX(4, 1672), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4sbs",  VX(4, 1800), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4shs",  VX(4, 1608), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4ubs",  VX(4, 1544), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vupkhpx",   VX(4,  846), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsb",   VX(4,  526), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsh",   VX(4,  590), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklpx",   VX(4,  974), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsb",   VX(4,  654), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsh",   VX(4,  718), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vxor",      VX(4, 1220), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+
+{ "evaddw",    VX(4, 512), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evaddiw",   VX(4, 514), VX_MASK,	PPCSPE,		{ RS, RB, UIMM } },
+{ "evsubfw",   VX(4, 516), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsubw",    VX(4, 516), VX_MASK,	PPCSPE,		{ RS, RB, RA } },
+{ "evsubifw",  VX(4, 518), VX_MASK,	PPCSPE,		{ RS, UIMM, RB } },
+{ "evsubiw",   VX(4, 518), VX_MASK,	PPCSPE,		{ RS, RB, UIMM } },
+{ "evabs",     VX(4, 520), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evneg",     VX(4, 521), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evextsb",   VX(4, 522), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evextsh",   VX(4, 523), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evrndw",    VX(4, 524), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evcntlzw",  VX(4, 525), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evcntlsw",  VX(4, 526), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "brinc",     VX(4, 527), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evand",     VX(4, 529), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evandc",    VX(4, 530), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmr",      VX(4, 535), VX_MASK,	PPCSPE,		{ RS, RA, BBA } },
+{ "evor",      VX(4, 535), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evorc",     VX(4, 539), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evxor",     VX(4, 534), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "eveqv",     VX(4, 537), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evnand",    VX(4, 542), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evnot",     VX(4, 536), VX_MASK,	PPCSPE,		{ RS, RA, BBA } },
+{ "evnor",     VX(4, 536), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evrlw",     VX(4, 552), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evrlwi",    VX(4, 554), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evslw",     VX(4, 548), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evslwi",    VX(4, 550), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsrws",    VX(4, 545), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsrwu",    VX(4, 544), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsrwis",   VX(4, 547), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsrwiu",   VX(4, 546), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsplati",  VX(4, 553), VX_MASK,	PPCSPE,		{ RS, SIMM } },
+{ "evsplatfi", VX(4, 555), VX_MASK,	PPCSPE,		{ RS, SIMM } },
+{ "evmergehi", VX(4, 556), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergelo", VX(4, 557), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergehilo",VX(4,558), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergelohi",VX(4,559), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evcmpgts",  VX(4, 561), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpgtu",  VX(4, 560), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmplts",  VX(4, 563), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpltu",  VX(4, 562), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpeq",   VX(4, 564), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evsel",     EVSEL(4,79),EVSEL_MASK,	PPCSPE,		{ RS, RA, RB, CRFS } },
+
+{ "evldd",     VX(4, 769), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evlddx",    VX(4, 768), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evldw",     VX(4, 771), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evldwx",    VX(4, 770), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evldh",     VX(4, 773), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evldhx",    VX(4, 772), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhe",    VX(4, 785), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhex",   VX(4, 784), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhou",   VX(4, 789), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhoux",  VX(4, 788), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhos",   VX(4, 791), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhosx",  VX(4, 790), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwwsplat",VX(4, 793), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwwsplatx",VX(4, 792), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhsplat",VX(4, 797), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhsplatx",VX(4, 796), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhesplat",VX(4, 777), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhesplatx",VX(4, 776), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhousplat",VX(4, 781), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhousplatx",VX(4, 780), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhossplat",VX(4, 783), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhossplatx",VX(4, 782), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evstdd",    VX(4, 801), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstddx",   VX(4, 800), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstdw",    VX(4, 803), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstdwx",   VX(4, 802), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstdh",    VX(4, 805), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstdhx",   VX(4, 804), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwwe",   VX(4, 825), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwwex",  VX(4, 824), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwwo",   VX(4, 829), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwwox",  VX(4, 828), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwhe",   VX(4, 817), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwhex",  VX(4, 816), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwho",   VX(4, 821), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwhox",  VX(4, 820), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evfsabs",   VX(4, 644), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsnabs",  VX(4, 645), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsneg",   VX(4, 646), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsadd",   VX(4, 640), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfssub",   VX(4, 641), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfsmul",   VX(4, 648), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfsdiv",   VX(4, 649), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfscmpgt", VX(4, 652), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscmplt", VX(4, 653), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscmpeq", VX(4, 654), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststgt", VX(4, 668), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststlt", VX(4, 669), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststeq", VX(4, 670), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscfui",  VX(4, 656), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctuiz", VX(4, 664), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfsi",  VX(4, 657), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfuf",  VX(4, 658), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfsf",  VX(4, 659), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctui",  VX(4, 660), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsi",  VX(4, 661), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsiz", VX(4, 666), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctuf",  VX(4, 662), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsf",  VX(4, 663), VX_MASK,	PPCSPE,		{ RS, RB } },
+
+{ "efsabs",   VX(4, 708), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsnabs",  VX(4, 709), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsneg",   VX(4, 710), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsadd",   VX(4, 704), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efssub",   VX(4, 705), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efsmul",   VX(4, 712), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efsdiv",   VX(4, 713), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efscmpgt", VX(4, 716), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscmplt", VX(4, 717), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscmpeq", VX(4, 718), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststgt", VX(4, 732), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststlt", VX(4, 733), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststeq", VX(4, 734), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscfui",  VX(4, 720), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctuiz", VX(4, 728), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfsi",  VX(4, 721), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfuf",  VX(4, 722), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfsf",  VX(4, 723), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctui",  VX(4, 724), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsi",  VX(4, 725), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsiz", VX(4, 730), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctuf",  VX(4, 726), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsf",  VX(4, 727), VX_MASK,	PPCEFS,		{ RS, RB } },
+
+{ "evmhossf",  VX(4, 1031), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossfa", VX(4, 1063), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmf",  VX(4, 1039), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfa", VX(4, 1071), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmi",  VX(4, 1037), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmia", VX(4, 1069), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumi",  VX(4, 1036), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumia", VX(4, 1068), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessf",  VX(4, 1027), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfa", VX(4, 1059), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmf",  VX(4, 1035), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfa", VX(4, 1067), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmi",  VX(4, 1033), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmia", VX(4, 1065), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumi",  VX(4, 1032), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumia", VX(4, 1064), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhossfaaw",VX(4, 1287), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossiaaw",VX(4, 1285), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfaaw",VX(4, 1295), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmiaaw",VX(4, 1293), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhousiaaw",VX(4, 1284), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumiaaw",VX(4, 1292), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfaaw",VX(4, 1283), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessiaaw",VX(4, 1281), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfaaw",VX(4, 1291), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmiaaw",VX(4, 1289), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheusiaaw",VX(4, 1280), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumiaaw",VX(4, 1288), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhossfanw",VX(4, 1415), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossianw",VX(4, 1413), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfanw",VX(4, 1423), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmianw",VX(4, 1421), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhousianw",VX(4, 1412), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumianw",VX(4, 1420), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfanw",VX(4, 1411), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessianw",VX(4, 1409), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfanw",VX(4, 1419), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmianw",VX(4, 1417), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheusianw",VX(4, 1408), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumianw",VX(4, 1416), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhogsmfaa",VX(4, 1327), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogsmiaa",VX(4, 1325), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogumiaa",VX(4, 1324), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmfaa",VX(4, 1323), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmiaa",VX(4, 1321), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegumiaa",VX(4, 1320), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhogsmfan",VX(4, 1455), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogsmian",VX(4, 1453), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogumian",VX(4, 1452), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmfan",VX(4, 1451), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmian",VX(4, 1449), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegumian",VX(4, 1448), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwhssf",  VX(4, 1095), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhssfa", VX(4, 1127), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmf",  VX(4, 1103), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmfa", VX(4, 1135), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmi",  VX(4, 1101), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmia", VX(4, 1133), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhumi",  VX(4, 1100), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhumia", VX(4, 1132), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlumi",  VX(4, 1096), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumia", VX(4, 1128), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlssiaaw",VX(4, 1345), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlsmiaaw",VX(4, 1353), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlusiaaw",VX(4, 1344), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumiaaw",VX(4, 1352), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlssianw",VX(4, 1473), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlsmianw",VX(4, 1481), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlusianw",VX(4, 1472), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumianw",VX(4, 1480), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssf",   VX(4, 1107), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwssfa",  VX(4, 1139), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmf",   VX(4, 1115), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfa",  VX(4, 1147), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmi",   VX(4, 1113), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmia",  VX(4, 1145), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumi",   VX(4, 1112), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumia",  VX(4, 1144), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssfaa", VX(4, 1363), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfaa", VX(4, 1371), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmiaa", VX(4, 1369), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumiaa", VX(4, 1368), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssfan", VX(4, 1491), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfan", VX(4, 1499), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmian", VX(4, 1497), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumian", VX(4, 1496), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evaddssiaaw",VX(4, 1217), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddsmiaaw",VX(4, 1225), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddusiaaw",VX(4, 1216), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddumiaaw",VX(4, 1224), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evsubfssiaaw",VX(4, 1219), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfsmiaaw",VX(4, 1227), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfusiaaw",VX(4, 1218), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfumiaaw",VX(4, 1226), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evmra",    VX(4, 1220), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evdivws",  VX(4, 1222), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evdivwu",  VX(4, 1223), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "mulli",   OP(7),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "muli",    OP(7),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "subfic",  OP(8),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "sfi",     OP(8),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "dozi",    OP(9),	OP_MASK,	M601,		{ RT, RA, SI } },
+
+{ "bce",     B(9,0,0),	B_MASK,		BOOKE64,	{ BO, BI, BD } },
+{ "bcel",    B(9,0,1),	B_MASK,		BOOKE64,	{ BO, BI, BD } },
+{ "bcea",    B(9,1,0),	B_MASK,		BOOKE64,	{ BO, BI, BDA } },
+{ "bcela",   B(9,1,1),	B_MASK,		BOOKE64,	{ BO, BI, BDA } },
+
+{ "cmplwi",  OPL(10,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, UI } },
+{ "cmpldi",  OPL(10,1), OPL_MASK,	PPC64,		{ OBF, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PPC,		{ BF, L, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PWRCOM,		{ BF, RA, UI } },
+
+{ "cmpwi",   OPL(11,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, SI } },
+{ "cmpdi",   OPL(11,1),	OPL_MASK,	PPC64,		{ OBF, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PPC,		{ BF, L, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PWRCOM,		{ BF, RA, SI } },
+
+{ "addic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai",	     OP(12),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+
+{ "addic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai.",     OP(13),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
+
+{ "li",	     OP(14),	DRA_MASK,	PPCCOM,		{ RT, SI } },
+{ "lil",     OP(14),	DRA_MASK,	PWRCOM,		{ RT, SI } },
+{ "addi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA0, SI } },
+{ "cal",     OP(14),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
+{ "subi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA0, NSI } },
+{ "la",	     OP(14),	OP_MASK,	PPCCOM,		{ RT, D, RA0 } },
+
+{ "lis",     OP(15),	DRA_MASK,	PPCCOM,		{ RT, SISIGNOPT } },
+{ "liu",     OP(15),	DRA_MASK,	PWRCOM,		{ RT, SISIGNOPT } },
+{ "addis",   OP(15),	OP_MASK,	PPCCOM,		{ RT,RA0,SISIGNOPT } },
+{ "cau",     OP(15),	OP_MASK,	PWRCOM,		{ RT,RA0,SISIGNOPT } },
+{ "subis",   OP(15),	OP_MASK,	PPCCOM,		{ RT, RA0, NSI } },
+
+{ "bdnz-",   BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnz+",   BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnz",    BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BD } },
+{ "bdn",     BBO(16,BODNZ,0,0),      BBOATBI_MASK, PWRCOM,	{ BD } },
+{ "bdnzl-",  BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnzl+",  BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnzl",   BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BD } },
+{ "bdnl",    BBO(16,BODNZ,0,1),      BBOATBI_MASK, PWRCOM,	{ BD } },
+{ "bdnza-",  BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnza+",  BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnza",   BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDA } },
+{ "bdna",    BBO(16,BODNZ,1,0),      BBOATBI_MASK, PWRCOM,	{ BDA } },
+{ "bdnzla-", BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnzla+", BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnzla",  BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDA } },
+{ "bdnla",   BBO(16,BODNZ,1,1),      BBOATBI_MASK, PWRCOM,	{ BDA } },
+{ "bdz-",    BBO(16,BODZ,0,0),       BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdz+",    BBO(16,BODZ,0,0),       BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdz",     BBO(16,BODZ,0,0),       BBOATBI_MASK, COM,		{ BD } },
+{ "bdzl-",   BBO(16,BODZ,0,1),       BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdzl+",   BBO(16,BODZ,0,1),       BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdzl",    BBO(16,BODZ,0,1),       BBOATBI_MASK, COM,		{ BD } },
+{ "bdza-",   BBO(16,BODZ,1,0),       BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdza+",   BBO(16,BODZ,1,0),       BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdza",    BBO(16,BODZ,1,0),       BBOATBI_MASK, COM,		{ BDA } },
+{ "bdzla-",  BBO(16,BODZ,1,1),       BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdzla+",  BBO(16,BODZ,1,1),       BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdzla",   BBO(16,BODZ,1,1),       BBOATBI_MASK, COM,		{ BDA } },
+{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bt-",     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bt+",     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bt",	     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbt",     BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "btl-",    BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "btl+",    BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "btl",     BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbtl",    BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bta-",    BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bta+",    BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bta",     BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbta",    BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "btla-",   BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "btla+",   BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "btla",    BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbtla",   BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bf-",     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bf+",     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bf",	     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbf",     BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bfl-",    BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bfl+",    BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bfl",     BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbfl",    BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bfa-",    BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfa+",    BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfa",     BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfa",    BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bfla-",   BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfla+",   BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfla",    BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfla",   BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bc-",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bc+",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bc",	     B(16,0,0),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bcl-",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bcl+",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bcl",     B(16,0,1),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bca-",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bca+",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bca",     B(16,1,0),	B_MASK,		COM,		{ BO, BI, BDA } },
+{ "bcla-",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bcla+",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bcla",    B(16,1,1),	B_MASK,		COM,		{ BO, BI, BDA } },
+
+{ "sc",      SC(17,1,0), SC_MASK,	PPC,		{ LEV } },
+{ "svc",     SC(17,0,0), SC_MASK,	POWER,		{ SVC_LEV, FL1, FL2 } },
+{ "svcl",    SC(17,0,1), SC_MASK,	POWER,		{ SVC_LEV, FL1, FL2 } },
+{ "svca",    SC(17,1,0), SC_MASK,	PWRCOM,		{ SV } },
+{ "svcla",   SC(17,1,1), SC_MASK,	POWER,		{ SV } },
+
+{ "b",	     B(18,0,0),	B_MASK,		COM,		{ LI } },
+{ "bl",      B(18,0,1),	B_MASK,		COM,		{ LI } },
+{ "ba",      B(18,1,0),	B_MASK,		COM,		{ LIA } },
+{ "bla",     B(18,1,1),	B_MASK,		COM,		{ LIA } },
+
+{ "mcrf",    XL(19,0),	XLBB_MASK|(3 << 21)|(3 << 16), COM,	{ BF, BFA } },
+
+{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlr-",  XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlr-",  XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlr-",  XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolr-",  XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlr-",  XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelr-",  XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllr-",  XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelr-",  XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelr+",  XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglr-",  XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelr-",  XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslr-",  XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulr-",  XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlr-",   XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlr+",   XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlrl-",  XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflr-",   XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflr+",   XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflrl-",  XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclr",    XLLK(19,16,0), XLBH_MASK,	PPCCOM,		{ BO, BI, BH } },
+{ "bclrl",   XLLK(19,16,1), XLBH_MASK,	PPCCOM,		{ BO, BI, BH } },
+{ "bcr",     XLLK(19,16,0), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+{ "bcrl",    XLLK(19,16,1), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+{ "bclre",   XLLK(19,17,0), XLBB_MASK,	BOOKE64,	{ BO, BI } },
+{ "bclrel",  XLLK(19,17,1), XLBB_MASK,	BOOKE64,	{ BO, BI } },
+
+{ "rfid",    XL(19,18),	0xffffffff,	PPC64,		{ 0 } },
+
+{ "crnot",   XL(19,33), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "crnor",   XL(19,33),	XL_MASK,	COM,		{ BT, BA, BB } },
+{ "rfmci",    X(19,38), 0xffffffff,	PPCRFMCI,	{ 0 } },
+
+{ "rfi",     XL(19,50),	0xffffffff,	COM,		{ 0 } },
+{ "rfci",    XL(19,51),	0xffffffff,	PPC403 | BOOKE,	{ 0 } },
+
+{ "rfsvc",   XL(19,82),	0xffffffff,	POWER,		{ 0 } },
+
+{ "crandc",  XL(19,129), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "isync",   XL(19,150), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "ics",     XL(19,150), 0xffffffff,	PWRCOM,		{ 0 } },
+
+{ "crclr",   XL(19,193), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "crxor",   XL(19,193), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crnand",  XL(19,225), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "crand",   XL(19,257), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "hrfid",   XL(19,274), 0xffffffff,	POWER5 | CELL,	{ 0 } },
+
+{ "crset",   XL(19,289), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "creqv",   XL(19,289), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "doze",    XL(19,402), 0xffffffff,	POWER6,		{ 0 } },
+
+{ "crorc",   XL(19,417), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "nap",     XL(19,434), 0xffffffff,	POWER6,		{ 0 } },
+
+{ "crmove",  XL(19,449), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "cror",    XL(19,449), XL_MASK,	COM,		{ BT, BA, BB } },
+
+{ "sleep",   XL(19,466), 0xffffffff,	POWER6,		{ 0 } },
+{ "rvwinkle", XL(19,498), 0xffffffff,	POWER6,		{ 0 } },
+
+{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bltctr",  XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctr-", XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctrl", XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "btctr",   XLO(19,BOT,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctr-",  XLO(19,BOT,528,0),  XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctr-",  XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctr+",  XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "btctrl",  XLO(19,BOT,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctrl-", XLO(19,BOT,528,1),  XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctr",   XLO(19,BOF,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctr-",  XLO(19,BOF,528,0),  XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctr-",  XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctr+",  XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctrl",  XLO(19,BOF,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctrl-", XLO(19,BOF,528,1),  XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bcctr-",  XLYLK(19,528,0,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctr+",  XLYLK(19,528,1,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl-", XLYLK(19,528,0,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl+", XLYLK(19,528,1,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctr",   XLLK(19,528,0),     XLBH_MASK,   PPCCOM,	{ BO, BI, BH } },
+{ "bcctrl",  XLLK(19,528,1),     XLBH_MASK,   PPCCOM,	{ BO, BI, BH } },
+{ "bcc",     XLLK(19,528,0),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+{ "bccl",    XLLK(19,528,1),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+{ "bcctre",  XLLK(19,529,0),     XLBB_MASK,   BOOKE64,	{ BO, BI } },
+{ "bcctrel", XLLK(19,529,1),     XLBB_MASK,   BOOKE64,	{ BO, BI } },
+
+{ "rlwimi",  M(20,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi",   M(20,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlwimi.", M(20,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi.",  M(20,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rotlwi",  MME(21,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "clrlwi",  MME(21,31,0), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm",  M(21,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm",   M(21,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rotlwi.", MME(21,31,1), MMBME_MASK,	PPCCOM,		{ RA,RS,SH } },
+{ "clrlwi.", MME(21,31,1), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm.", M(21,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm.",  M(21,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlmi",    M(22,0),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
+{ "rlmi.",   M(22,1),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
+
+{ "be",	     B(22,0,0),	B_MASK,		BOOKE64,	{ LI } },
+{ "bel",     B(22,0,1),	B_MASK,		BOOKE64,	{ LI } },
+{ "bea",     B(22,1,0),	B_MASK,		BOOKE64,	{ LIA } },
+{ "bela",    B(22,1,1),	B_MASK,		BOOKE64,	{ LIA } },
+
+{ "rotlw",   MME(23,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm",   M(23,0),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm",    M(23,0),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rotlw.",  MME(23,31,1), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm.",  M(23,1),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm.",   M(23,1),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
+
+{ "nop",     OP(24),	0xffffffff,	PPCCOM,		{ 0 } },
+{ "ori",     OP(24),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oril",    OP(24),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "oris",    OP(25),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oriu",    OP(25),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "xori",    OP(26),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoril",   OP(26),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "xoris",   OP(27),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoriu",   OP(27),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "andi.",   OP(28),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andil.",  OP(28),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "andis.",  OP(29),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andiu.",  OP(29),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
+
+{ "rotldi",  MD(30,0,0), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi",  MD(30,0,0), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl",  MD(30,0,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rotldi.", MD(30,0,1), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi.", MD(30,0,1), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl.", MD(30,0,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rldicr",  MD(30,1,0), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+{ "rldicr.", MD(30,1,1), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+
+{ "rldic",   MD(30,2,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldic.",  MD(30,2,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rldimi",  MD(30,3,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldimi.", MD(30,3,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rotld",   MDS(30,8,0), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl",   MDS(30,8,0), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+{ "rotld.",  MDS(30,8,1), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl.",  MDS(30,8,1), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+
+{ "rldcr",   MDS(30,9,0), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+{ "rldcr.",  MDS(30,9,1), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+
+{ "cmpw",    XOPL(31,0,0), XCMPL_MASK, PPCCOM,		{ OBF, RA, RB } },
+{ "cmpd",    XOPL(31,0,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
+{ "cmp",     X(31,0),	XCMP_MASK,	PPC,		{ BF, L, RA, RB } },
+{ "cmp",     X(31,0),	XCMPL_MASK,	PWRCOM,		{ BF, RA, RB } },
+
+{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "tweq",    XTO(31,4,TOEQ), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "teq",     XTO(31,4,TOEQ), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twgt",    XTO(31,4,TOGT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tgt",     XTO(31,4,TOGT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twge",    XTO(31,4,TOGE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tge",     XTO(31,4,TOGE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twnl",    XTO(31,4,TONL), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tnl",     XTO(31,4,TONL), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlt",    XTO(31,4,TOLT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tlt",     XTO(31,4,TOLT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twle",    XTO(31,4,TOLE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tle",     XTO(31,4,TOLE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twng",    XTO(31,4,TONG), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tng",     XTO(31,4,TONG), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twne",    XTO(31,4,TONE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tne",     XTO(31,4,TONE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "trap",    XTO(31,4,TOU), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "tw",      X(31,4),	X_MASK,		PPCCOM,		{ TO, RA, RB } },
+{ "t",       X(31,4),	X_MASK,		PWRCOM,		{ TO, RA, RB } },
+
+{ "subfc",   XO(31,8,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf",      XO(31,8,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subc",    XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfc.",  XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf.",     XO(31,8,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subc.",   XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RB, RA } },
+{ "subfco",  XO(31,8,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo",     XO(31,8,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subco",   XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfco.", XO(31,8,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo.",    XO(31,8,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subco.",  XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "mulhdu",  XO(31,9,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulhdu.", XO(31,9,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addc",    XO(31,10,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a",       XO(31,10,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addc.",   XO(31,10,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a.",      XO(31,10,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco",   XO(31,10,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao",      XO(31,10,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco.",  XO(31,10,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao.",     XO(31,10,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "mulhwu",  XO(31,11,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhwu.", XO(31,11,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "isellt",  X(31,15),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "iselgt",  X(31,47),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "iseleq",  X(31,79),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "isel",    XISEL(31,15),  XISEL_MASK,	PPCISEL,	{ RT, RA, RB, CRB } },
+
+{ "mfocrf",  XFXM(31,19,0,1), XFXFXM_MASK, COM,		{ RT, FXM } },
+{ "mfcr",    X(31,19),	XRARB_MASK,	NOPOWER4 | COM,	{ RT } },
+{ "mfcr",    X(31,19),	XFXFXM_MASK,	POWER4,		{ RT, FXM4 } },
+
+{ "lwarx",   X(31,20),	XEH_MASK,	PPC,		{ RT, RA0, RB, EH } },
+
+{ "ldx",     X(31,21),	X_MASK,		PPC64,		{ RT, RA0, RB } },
+
+{ "icbt",    X(31,22),	X_MASK,		BOOKE|PPCE300,	{ CT, RA, RB } },
+{ "icbt",    X(31,262),	XRT_MASK,	PPC403,		{ RA, RB } },
+
+{ "lwzx",    X(31,23),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lx",      X(31,23),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "slw",     XRC(31,24,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl",      XRC(31,24,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "slw.",    XRC(31,24,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl.",     XRC(31,24,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "cntlzw",  XRC(31,26,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz",   XRC(31,26,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "cntlzw.", XRC(31,26,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz.",  XRC(31,26,1), XRB_MASK, 	PWRCOM,		{ RA, RS } },
+
+{ "sld",     XRC(31,27,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "sld.",    XRC(31,27,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "and",     XRC(31,28,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "and.",    XRC(31,28,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "maskg",   XRC(31,29,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskg.",  XRC(31,29,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "icbte",   X(31,30),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "lwzxe",   X(31,31),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "cmplw",   XOPL(31,32,0), XCMPL_MASK, PPCCOM,	{ OBF, RA, RB } },
+{ "cmpld",   XOPL(31,32,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
+{ "cmpl",    X(31,32),	XCMP_MASK,	 PPC,		{ BF, L, RA, RB } },
+{ "cmpl",    X(31,32),	XCMPL_MASK,	 PWRCOM,	{ BF, RA, RB } },
+
+{ "subf",    XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub",     XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subf.",   XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub.",    XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo",   XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo",    XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo.",  XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo.",   XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "ldux",    X(31,53),	X_MASK,		PPC64,		{ RT, RAL, RB } },
+
+{ "dcbst",   X(31,54),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lwzux",   X(31,55),	X_MASK,		PPCCOM,		{ RT, RAL, RB } },
+{ "lux",     X(31,55),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "dcbste",  X(31,62),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "lwzuxe",  X(31,63),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
+
+{ "cntlzd",  XRC(31,58,0), XRB_MASK,	PPC64,		{ RA, RS } },
+{ "cntlzd.", XRC(31,58,1), XRB_MASK,	PPC64,		{ RA, RS } },
+
+{ "andc",    XRC(31,60,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "andc.",   XRC(31,60,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdgt",    XTO(31,68,TOGT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdge",    XTO(31,68,TOGE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdnl",    XTO(31,68,TONL), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlt",    XTO(31,68,TOLT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdle",    XTO(31,68,TOLE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdng",    XTO(31,68,TONG), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdne",    XTO(31,68,TONE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "td",	     X(31,68),	X_MASK,		 PPC64,		{ TO, RA, RB } },
+
+{ "mulhd",   XO(31,73,0,0), XO_MASK,	 PPC64,		{ RT, RA, RB } },
+{ "mulhd.",  XO(31,73,0,1), XO_MASK,	 PPC64,		{ RT, RA, RB } },
+
+{ "mulhw",   XO(31,75,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhw.",  XO(31,75,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "dlmzb",   XRC(31,78,0),  X_MASK,	PPC403|PPC440,	{ RA, RS, RB } },
+{ "dlmzb.",  XRC(31,78,1),  X_MASK,	PPC403|PPC440,	{ RA, RS, RB } },
+
+{ "mtsrd",   X(31,82),	XRB_MASK|(1<<20), PPC64,	{ SR, RS } },
+
+{ "mfmsr",   X(31,83),	XRARB_MASK,	COM,		{ RT } },
+
+{ "ldarx",   X(31,84),	XEH_MASK,	PPC64,		{ RT, RA0, RB, EH } },
+
+{ "dcbfl",   XOPL(31,86,1), XRT_MASK,	POWER5,		{ RA, RB } },
+{ "dcbf",    X(31,86),	XLRT_MASK,	PPC,		{ RA, RB, L } },
+
+{ "lbzx",    X(31,87),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "dcbfe",   X(31,94),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "lbzxe",   X(31,95),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "neg",     XO(31,104,0,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "neg.",    XO(31,104,0,1), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego",    XO(31,104,1,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego.",   XO(31,104,1,1), XORB_MASK,	COM,		{ RT, RA } },
+
+{ "mul",     XO(31,107,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mul.",    XO(31,107,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo",    XO(31,107,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo.",   XO(31,107,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "mtsrdin", X(31,114),	XRA_MASK,	PPC64,		{ RS, RB } },
+
+{ "clf",     X(31,118), XTO_MASK,	POWER,		{ RA, RB } },
+
+{ "lbzux",   X(31,119),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "popcntb", X(31,122), XRB_MASK,	POWER5,		{ RA, RS } },
+
+{ "not",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "not.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "lwarxe",  X(31,126),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "lbzuxe",  X(31,127),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
+
+{ "wrtee",   X(31,131),	XRARB_MASK,	PPC403 | BOOKE,	{ RS } },
+
+{ "dcbtstls",X(31,134),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "subfe",   XO(31,136,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe",     XO(31,136,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfe.",  XO(31,136,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe.",    XO(31,136,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo",  XO(31,136,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo",    XO(31,136,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo.", XO(31,136,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo.",   XO(31,136,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "adde",    XO(31,138,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae",      XO(31,138,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "adde.",   XO(31,138,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae.",     XO(31,138,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo",   XO(31,138,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo",     XO(31,138,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo.",  XO(31,138,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo.",    XO(31,138,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "dcbtstlse",X(31,142),X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "mtocrf",  XFXM(31,144,0,1), XFXFXM_MASK, COM,	{ FXM, RS } },
+{ "mtcr",    XFXM(31,144,0xff,0), XRARB_MASK, COM,	{ RS }},
+{ "mtcrf",   X(31,144),	XFXFXM_MASK,	COM,		{ FXM, RS } },
+
+{ "mtmsr",   X(31,146),	XRARB_MASK,	COM,		{ RS } },
+
+{ "stdx",    X(31,149), X_MASK,		PPC64,		{ RS, RA0, RB } },
+
+{ "stwcx.",  XRC(31,150,1), X_MASK,	PPC,		{ RS, RA0, RB } },
+
+{ "stwx",    X(31,151), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stx",     X(31,151), X_MASK,		PWRCOM,		{ RS, RA, RB } },
+
+{ "stwcxe.", XRC(31,158,1), X_MASK,	BOOKE64,	{ RS, RA0, RB } },
+
+{ "stwxe",   X(31,159), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "slq",     XRC(31,152,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "slq.",    XRC(31,152,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sle",     XRC(31,153,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sle.",    XRC(31,153,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "prtyw",   X(31,154),	XRB_MASK,	POWER6,		{ RA, RS } },
+
+{ "wrteei",  X(31,163),	XE_MASK,	PPC403 | BOOKE,	{ E } },
+
+{ "dcbtls",  X(31,166),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+{ "dcbtlse", X(31,174),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "mtmsrd",  X(31,178),	XRLARB_MASK,	PPC64,		{ RS, A_L } },
+
+{ "stdux",   X(31,181),	X_MASK,		PPC64,		{ RS, RAS, RB } },
+
+{ "stwux",   X(31,183),	X_MASK,		PPCCOM,		{ RS, RAS, RB } },
+{ "stux",    X(31,183),	X_MASK,		PWRCOM,		{ RS, RA0, RB } },
+
+{ "sliq",    XRC(31,184,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sliq.",   XRC(31,184,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "prtyd",   X(31,186),	XRB_MASK,	POWER6,		{ RA, RS } },
+
+{ "stwuxe",  X(31,191),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "subfze",  XO(31,200,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze",    XO(31,200,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze.",   XO(31,200,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo",   XO(31,200,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "addze",   XO(31,202,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze",     XO(31,202,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addze.",  XO(31,202,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze.",    XO(31,202,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo",    XO(31,202,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo.",   XO(31,202,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mtsr",    X(31,210),	XRB_MASK|(1<<20), COM32,	{ SR, RS } },
+
+{ "stdcx.",  XRC(31,214,1), X_MASK,	PPC64,		{ RS, RA0, RB } },
+
+{ "stbx",    X(31,215),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "sllq",    XRC(31,216,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sllq.",   XRC(31,216,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sleq",    XRC(31,217,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sleq.",   XRC(31,217,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stbxe",   X(31,223),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "icblc",   X(31,230),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "subfme",  XO(31,232,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme",    XO(31,232,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme.",   XO(31,232,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo",   XO(31,232,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mulld",   XO(31,233,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulld.",  XO(31,233,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo",  XO(31,233,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo.", XO(31,233,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addme",   XO(31,234,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame",     XO(31,234,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addme.",  XO(31,234,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame.",    XO(31,234,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo",    XO(31,234,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo.",   XO(31,234,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mullw",   XO(31,235,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls",    XO(31,235,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullw.",  XO(31,235,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls.",   XO(31,235,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo",  XO(31,235,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso",   XO(31,235,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo.", XO(31,235,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso.",  XO(31,235,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "icblce",  X(31,238),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+{ "mtsrin",  X(31,242),	XRA_MASK,	PPC32,		{ RS, RB } },
+{ "mtsri",   X(31,242),	XRA_MASK,	POWER32,	{ RS, RB } },
+
+{ "dcbtst",  X(31,246),	X_MASK,	PPC,			{ CT, RA, RB } },
+
+{ "stbux",   X(31,247),	X_MASK,		COM,		{ RS, RAS, RB } },
+
+{ "slliq",   XRC(31,248,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "slliq.",  XRC(31,248,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "dcbtste", X(31,253),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "stbuxe",  X(31,255),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "mfdcrx",  X(31,259),	X_MASK,		BOOKE,		{ RS, RA } },
+
+{ "doz",     XO(31,264,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "doz.",    XO(31,264,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo",    XO(31,264,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo.",   XO(31,264,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "add",     XO(31,266,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax",     XO(31,266,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "add.",    XO(31,266,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax.",    XO(31,266,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo",    XO(31,266,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo",    XO(31,266,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo.",   XO(31,266,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo.",   XO(31,266,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "tlbiel",  X(31,274), XRTLRA_MASK,	POWER4,		{ RB, L } },
+
+{ "mfapidi", X(31,275), X_MASK,		BOOKE,		{ RT, RA } },
+
+{ "lscbx",   XRC(31,277,0), X_MASK,	M601,		{ RT, RA, RB } },
+{ "lscbx.",  XRC(31,277,1), X_MASK,	M601,		{ RT, RA, RB } },
+
+{ "dcbt",    X(31,278),	X_MASK,		PPC,		{ CT, RA, RB } },
+
+{ "lhzx",    X(31,279),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "eqv",     XRC(31,284,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "eqv.",    XRC(31,284,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "dcbte",   X(31,286),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "lhzxe",   X(31,287),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "tlbie",   X(31,306),	XRTLRA_MASK,	PPC,		{ RB, L } },
+{ "tlbi",    X(31,306),	XRT_MASK,	POWER,		{ RA0, RB } },
+
+{ "eciwx",   X(31,310), X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "lhzux",   X(31,311),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "xor",     XRC(31,316,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "xor.",    XRC(31,316,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "lhzuxe",  X(31,319),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
+
+{ "mfexisr",  XSPR(31,323,64),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfexier",  XSPR(31,323,66),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr0",    XSPR(31,323,128), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr1",    XSPR(31,323,129), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr2",    XSPR(31,323,130), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr3",    XSPR(31,323,131), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr4",    XSPR(31,323,132), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr5",    XSPR(31,323,133), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr6",    XSPR(31,323,134), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr7",    XSPR(31,323,135), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbear",   XSPR(31,323,144), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbesr",   XSPR(31,323,145), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiocr",   XSPR(31,323,160), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasr",  XSPR(31,323,224), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdcr",    X(31,323),	X_MASK,	PPC403 | BOOKE,	{ RT, SPR } },
+
+{ "div",     XO(31,331,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "div.",    XO(31,331,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo",    XO(31,331,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo.",   XO(31,331,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "mfpmr",   X(31,334),	X_MASK,		PPCPMR,		{ RT, PMR }},
+
+{ "mfmq",       XSPR(31,339,0),    XSPR_MASK, M601,	{ RT } },
+{ "mfxer",      XSPR(31,339,1),    XSPR_MASK, COM,	{ RT } },
+{ "mfrtcu",     XSPR(31,339,4),    XSPR_MASK, COM,	{ RT } },
+{ "mfrtcl",     XSPR(31,339,5),    XSPR_MASK, COM,	{ RT } },
+{ "mfdec",      XSPR(31,339,6),    XSPR_MASK, MFDEC1,	{ RT } },
+{ "mfdec",      XSPR(31,339,22),   XSPR_MASK, MFDEC2,	{ RT } },
+{ "mflr",       XSPR(31,339,8),    XSPR_MASK, COM,	{ RT } },
+{ "mfctr",      XSPR(31,339,9),    XSPR_MASK, COM,	{ RT } },
+{ "mftid",      XSPR(31,339,17),   XSPR_MASK, POWER,	{ RT } },
+{ "mfdsisr",    XSPR(31,339,18),   XSPR_MASK, COM,	{ RT } },
+{ "mfdar",      XSPR(31,339,19),   XSPR_MASK, COM,	{ RT } },
+{ "mfsdr0",     XSPR(31,339,24),   XSPR_MASK, POWER,	{ RT } },
+{ "mfsdr1",     XSPR(31,339,25),   XSPR_MASK, COM,	{ RT } },
+{ "mfsrr0",     XSPR(31,339,26),   XSPR_MASK, COM,	{ RT } },
+{ "mfsrr1",     XSPR(31,339,27),   XSPR_MASK, COM,	{ RT } },
+{ "mfcfar",     XSPR(31,339,28),   XSPR_MASK, POWER6,	{ RT } },
+{ "mfpid",      XSPR(31,339,48),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfpid",      XSPR(31,339,945),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfcsrr0",    XSPR(31,339,58),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfcsrr1",    XSPR(31,339,59),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfdear",     XSPR(31,339,61),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfdear",     XSPR(31,339,981),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfesr",      XSPR(31,339,62),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfesr",      XSPR(31,339,980),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfivpr",     XSPR(31,339,63),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfcmpa",     XSPR(31,339,144),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpb",     XSPR(31,339,145),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpc",     XSPR(31,339,146),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpd",     XSPR(31,339,147),  XSPR_MASK, PPC860,	{ RT } },
+{ "mficr",      XSPR(31,339,148),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfder",      XSPR(31,339,149),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcounta",   XSPR(31,339,150),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcountb",   XSPR(31,339,151),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpe",     XSPR(31,339,152),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpf",     XSPR(31,339,153),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpg",     XSPR(31,339,154),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmph",     XSPR(31,339,155),  XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl1",   XSPR(31,339,156),  XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl2",   XSPR(31,339,157),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfictrl",    XSPR(31,339,158),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfbar",      XSPR(31,339,159),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfvrsave",   XSPR(31,339,256),  XSPR_MASK, PPCVEC,	{ RT } },
+{ "mfusprg0",   XSPR(31,339,256),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftb",       X(31,371),	   X_MASK,    CLASSIC,	{ RT, TBR } },
+{ "mftb",       XSPR(31,339,268),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftbl",      XSPR(31,371,268),  XSPR_MASK, CLASSIC,	{ RT } },
+{ "mftbl",      XSPR(31,339,268),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftbu",      XSPR(31,371,269),  XSPR_MASK, CLASSIC,	{ RT } },
+{ "mftbu",      XSPR(31,339,269),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfsprg",     XSPR(31,339,256),  XSPRG_MASK, PPC,	{ RT, SPRG } },
+{ "mfsprg0",    XSPR(31,339,272),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg1",    XSPR(31,339,273),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg2",    XSPR(31,339,274),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg3",    XSPR(31,339,275),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg4",    XSPR(31,339,260),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg5",    XSPR(31,339,261),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg6",    XSPR(31,339,262),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg7",    XSPR(31,339,263),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfasr",      XSPR(31,339,280),  XSPR_MASK, PPC64,	{ RT } },
+{ "mfear",      XSPR(31,339,282),  XSPR_MASK, PPC,	{ RT } },
+{ "mfpir",      XSPR(31,339,286),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfpvr",      XSPR(31,339,287),  XSPR_MASK, PPC,	{ RT } },
+{ "mfdbsr",     XSPR(31,339,304),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbsr",     XSPR(31,339,1008), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdbcr0",    XSPR(31,339,308),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbcr0",    XSPR(31,339,1010), XSPR_MASK, PPC405,	{ RT } },
+{ "mfdbcr1",    XSPR(31,339,309),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbcr1",    XSPR(31,339,957),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdbcr2",    XSPR(31,339,310),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac1",     XSPR(31,339,312),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac1",     XSPR(31,339,1012), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiac2",     XSPR(31,339,313),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac2",     XSPR(31,339,1013), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiac3",     XSPR(31,339,314),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac3",     XSPR(31,339,948),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfiac4",     XSPR(31,339,315),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac4",     XSPR(31,339,949),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdac1",     XSPR(31,339,316),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdac1",     XSPR(31,339,1014), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdac2",     XSPR(31,339,317),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdac2",     XSPR(31,339,1015), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdvc1",     XSPR(31,339,318),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdvc1",     XSPR(31,339,950),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdvc2",     XSPR(31,339,319),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdvc2",     XSPR(31,339,951),  XSPR_MASK, PPC405,	{ RT } },
+{ "mftsr",      XSPR(31,339,336),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftsr",      XSPR(31,339,984),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftcr",      XSPR(31,339,340),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftcr",      XSPR(31,339,986),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfivor0",    XSPR(31,339,400),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor1",    XSPR(31,339,401),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor2",    XSPR(31,339,402),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor3",    XSPR(31,339,403),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor4",    XSPR(31,339,404),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor5",    XSPR(31,339,405),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor6",    XSPR(31,339,406),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor7",    XSPR(31,339,407),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor8",    XSPR(31,339,408),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor9",    XSPR(31,339,409),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor10",   XSPR(31,339,410),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor11",   XSPR(31,339,411),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor12",   XSPR(31,339,412),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor13",   XSPR(31,339,413),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor14",   XSPR(31,339,414),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor15",   XSPR(31,339,415),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfspefscr",  XSPR(31,339,512),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfbbear",    XSPR(31,339,513),  XSPR_MASK, PPCBRLK,  { RT } },
+{ "mfbbtar",    XSPR(31,339,514),  XSPR_MASK, PPCBRLK,  { RT } },
+{ "mfivor32",   XSPR(31,339,528),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor33",   XSPR(31,339,529),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor34",   XSPR(31,339,530),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor35",   XSPR(31,339,531),  XSPR_MASK, PPCPMR,	{ RT } },
+{ "mfibatu",    XSPR(31,339,528),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfibatl",    XSPR(31,339,529),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatu",    XSPR(31,339,536),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatl",    XSPR(31,339,537),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfic_cst",   XSPR(31,339,560),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_adr",   XSPR(31,339,561),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_dat",   XSPR(31,339,562),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_cst",   XSPR(31,339,568),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_adr",   XSPR(31,339,569),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmcsrr0",   XSPR(31,339,570),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfdc_dat",   XSPR(31,339,570),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmcsrr1",   XSPR(31,339,571),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfmcsr",     XSPR(31,339,572),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfmcar",     XSPR(31,339,573),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfdpdr",     XSPR(31,339,630),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdpir",     XSPR(31,339,631),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfimmr",     XSPR(31,339,638),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ctr",   XSPR(31,339,784),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ap",    XSPR(31,339,786),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_epn",   XSPR(31,339,787),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_twc",   XSPR(31,339,789),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_rpn",   XSPR(31,339,790),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ctr",   XSPR(31,339,792),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_casid",  XSPR(31,339,793),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ap",    XSPR(31,339,794),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_epn",   XSPR(31,339,795),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twb",   XSPR(31,339,796),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twc",   XSPR(31,339,797),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_rpn",   XSPR(31,339,798),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_tw",     XSPR(31,339,799),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbcam", XSPR(31,339,816),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram0",XSPR(31,339,817),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram1",XSPR(31,339,818),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbcam", XSPR(31,339,824),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram0",XSPR(31,339,825),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram1",XSPR(31,339,826),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfummcr0",   XSPR(31,339,936),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc1",    XSPR(31,339,937),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc2",    XSPR(31,339,938),  XSPR_MASK, PPC750,   { RT } },
+{ "mfusia",     XSPR(31,339,939),  XSPR_MASK, PPC750,   { RT } },
+{ "mfummcr1",   XSPR(31,339,940),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc3",    XSPR(31,339,941),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc4",    XSPR(31,339,942),  XSPR_MASK, PPC750,   { RT } },
+{ "mfzpr",   	XSPR(31,339,944),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfccr0",  	XSPR(31,339,947),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr0",	XSPR(31,339,952),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfpmc1",	XSPR(31,339,953),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsgr",	XSPR(31,339,953),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfpmc2",	XSPR(31,339,954),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfdcwr", 	XSPR(31,339,954),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsia",	XSPR(31,339,955),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsler",	XSPR(31,339,955),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr1",	XSPR(31,339,956),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsu0r",	XSPR(31,339,956),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfpmc3",	XSPR(31,339,957),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfpmc4",	XSPR(31,339,958),  XSPR_MASK, PPC750,	{ RT } },
+{ "mficdbdr",   XSPR(31,339,979),  XSPR_MASK, PPC403,   { RT } },
+{ "mfevpr",     XSPR(31,339,982),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfcdbcr",    XSPR(31,339,983),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfpit",      XSPR(31,339,987),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftbhi",     XSPR(31,339,988),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftblo",     XSPR(31,339,989),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr2",     XSPR(31,339,990),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr3",     XSPR(31,339,991),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfl2cr",     XSPR(31,339,1017), XSPR_MASK, PPC750,   { RT } },
+{ "mfdccr",     XSPR(31,339,1018), XSPR_MASK, PPC403,	{ RT } },
+{ "mficcr",     XSPR(31,339,1019), XSPR_MASK, PPC403,	{ RT } },
+{ "mfictc",     XSPR(31,339,1019), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbl1",     XSPR(31,339,1020), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm1",    XSPR(31,339,1020), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbu1",     XSPR(31,339,1021), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm2",    XSPR(31,339,1021), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbl2",     XSPR(31,339,1022), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm3",    XSPR(31,339,1022), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbu2",     XSPR(31,339,1023), XSPR_MASK, PPC403,	{ RT } },
+{ "mfspr",      X(31,339),	   X_MASK,    COM,	{ RT, SPR } },
+
+{ "lwax",    X(31,341),	X_MASK,		PPC64,		{ RT, RA0, RB } },
+
+{ "dst",     XDSS(31,342,0), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+{ "dstt",    XDSS(31,342,1), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+
+{ "lhax",    X(31,343),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "lhaxe",   X(31,351),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "dstst",   XDSS(31,374,0), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+{ "dststt",  XDSS(31,374,1), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+
+{ "dccci",   X(31,454),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "abs",     XO(31,360,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abs.",    XO(31,360,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "abso",    XO(31,360,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abso.",   XO(31,360,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divs",    XO(31,363,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divs.",   XO(31,363,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso",   XO(31,363,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso.",  XO(31,363,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "tlbia",   X(31,370),	0xffffffff,	PPC,		{ 0 } },
+
+{ "lwaux",   X(31,373),	X_MASK,		PPC64,		{ RT, RAL, RB } },
+
+{ "lhaux",   X(31,375),	X_MASK,		COM,		{ RT, RAL, RB } },
+
+{ "lhauxe",  X(31,383),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
+
+{ "mtdcrx",  X(31,387),	X_MASK,		BOOKE,		{ RA, RS } },
+
+{ "dcblc",   X(31,390),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "subfe64", XO(31,392,0,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+{ "subfe64o",XO(31,392,1,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+
+{ "adde64",  XO(31,394,0,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+{ "adde64o", XO(31,394,1,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+
+{ "dcblce",  X(31,398),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "slbmte",  X(31,402), XRA_MASK,	PPC64,		{ RS, RB } },
+
+{ "sthx",    X(31,407),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "cmpb",    X(31,508),	X_MASK,		POWER6,		{ RA, RS, RB } },
+
+{ "lfqx",    X(31,791),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "lfdpx",   X(31,791),	X_MASK,		POWER6,		{ FRT, RA, RB } },
+
+{ "lfqux",   X(31,823),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "stfqx",   X(31,919),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "stfdpx",  X(31,919),	X_MASK,		POWER6,		{ FRS, RA, RB } },
+
+{ "stfqux",  X(31,951),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "orc",     XRC(31,412,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "orc.",    XRC(31,412,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "sradi",   XS(31,413,0), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "sradi.",  XS(31,413,1), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
+
+{ "sthxe",   X(31,415),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "slbie",   X(31,434),	XRTRA_MASK,	PPC64,		{ RB } },
+
+{ "ecowx",   X(31,438),	X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "sthux",   X(31,439),	X_MASK,		COM,		{ RS, RAS, RB } },
+
+{ "sthuxe",  X(31,447),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "cctpl",   0x7c210b78,    0xffffffff,	CELL,		{ 0 }},
+{ "cctpm",   0x7c421378,    0xffffffff,	CELL,		{ 0 }},
+{ "cctph",   0x7c631b78,    0xffffffff,	CELL,		{ 0 }},
+{ "db8cyc",  0x7f9ce378,    0xffffffff,	CELL,		{ 0 }},
+{ "db10cyc", 0x7fbdeb78,    0xffffffff,	CELL,		{ 0 }},
+{ "db12cyc", 0x7fdef378,    0xffffffff,	CELL,		{ 0 }},
+{ "db16cyc", 0x7ffffb78,    0xffffffff,	CELL,		{ 0 }},
+{ "mr",	     XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or",      XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "mr.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "mtexisr",  XSPR(31,451,64),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtexier",  XSPR(31,451,66),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr0",    XSPR(31,451,128), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr1",    XSPR(31,451,129), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr2",    XSPR(31,451,130), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr3",    XSPR(31,451,131), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr4",    XSPR(31,451,132), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr5",    XSPR(31,451,133), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr6",    XSPR(31,451,134), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr7",    XSPR(31,451,135), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbear",   XSPR(31,451,144), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbesr",   XSPR(31,451,145), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiocr",   XSPR(31,451,160), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasr",  XSPR(31,451,224), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdcr",    X(31,451),	X_MASK,	PPC403 | BOOKE,	{ SPR, RS } },
+
+{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+
+{ "divdu",   XO(31,457,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdu.",  XO(31,457,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo",  XO(31,457,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo.", XO(31,457,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+
+{ "divwu",   XO(31,459,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwu.",  XO(31,459,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo",  XO(31,459,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo.", XO(31,459,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mtmq",      XSPR(31,467,0),    XSPR_MASK, M601,	{ RS } },
+{ "mtxer",     XSPR(31,467,1),    XSPR_MASK, COM,	{ RS } },
+{ "mtlr",      XSPR(31,467,8),    XSPR_MASK, COM,	{ RS } },
+{ "mtctr",     XSPR(31,467,9),    XSPR_MASK, COM,	{ RS } },
+{ "mttid",     XSPR(31,467,17),   XSPR_MASK, POWER,	{ RS } },
+{ "mtdsisr",   XSPR(31,467,18),   XSPR_MASK, COM,	{ RS } },
+{ "mtdar",     XSPR(31,467,19),   XSPR_MASK, COM,	{ RS } },
+{ "mtrtcu",    XSPR(31,467,20),   XSPR_MASK, COM,	{ RS } },
+{ "mtrtcl",    XSPR(31,467,21),   XSPR_MASK, COM,	{ RS } },
+{ "mtdec",     XSPR(31,467,22),   XSPR_MASK, COM,	{ RS } },
+{ "mtsdr0",    XSPR(31,467,24),   XSPR_MASK, POWER,	{ RS } },
+{ "mtsdr1",    XSPR(31,467,25),   XSPR_MASK, COM,	{ RS } },
+{ "mtsrr0",    XSPR(31,467,26),   XSPR_MASK, COM,	{ RS } },
+{ "mtsrr1",    XSPR(31,467,27),   XSPR_MASK, COM,	{ RS } },
+{ "mtcfar",    XSPR(31,467,28),   XSPR_MASK, POWER6,	{ RS } },
+{ "mtpid",     XSPR(31,467,48),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtpid",     XSPR(31,467,945),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtdecar",   XSPR(31,467,54),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcsrr0",   XSPR(31,467,58),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcsrr1",   XSPR(31,467,59),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtdear",    XSPR(31,467,61),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtdear",    XSPR(31,467,981),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtesr",     XSPR(31,467,62),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtesr",     XSPR(31,467,980),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtivpr",    XSPR(31,467,63),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcmpa",    XSPR(31,467,144),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpb",    XSPR(31,467,145),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpc",    XSPR(31,467,146),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpd",    XSPR(31,467,147),  XSPR_MASK, PPC860,	{ RS } },
+{ "mticr",     XSPR(31,467,148),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtder",     XSPR(31,467,149),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcounta",  XSPR(31,467,150),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcountb",  XSPR(31,467,151),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpe",    XSPR(31,467,152),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpf",    XSPR(31,467,153),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpg",    XSPR(31,467,154),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmph",    XSPR(31,467,155),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtlctrl1",  XSPR(31,467,156),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtlctrl2",  XSPR(31,467,157),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtictrl",   XSPR(31,467,158),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtbar",     XSPR(31,467,159),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtvrsave",  XSPR(31,467,256),  XSPR_MASK, PPCVEC,	{ RS } },
+{ "mtusprg0",  XSPR(31,467,256),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtsprg",    XSPR(31,467,256),  XSPRG_MASK,PPC,	{ SPRG, RS } },
+{ "mtsprg0",   XSPR(31,467,272),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg1",   XSPR(31,467,273),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg2",   XSPR(31,467,274),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg3",   XSPR(31,467,275),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg4",   XSPR(31,467,276),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg5",   XSPR(31,467,277),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg6",   XSPR(31,467,278),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg7",   XSPR(31,467,279),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtasr",     XSPR(31,467,280),  XSPR_MASK, PPC64,	{ RS } },
+{ "mtear",     XSPR(31,467,282),  XSPR_MASK, PPC,	{ RS } },
+{ "mttbl",     XSPR(31,467,284),  XSPR_MASK, PPC,	{ RS } },
+{ "mttbu",     XSPR(31,467,285),  XSPR_MASK, PPC,	{ RS } },
+{ "mtdbsr",    XSPR(31,467,304),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbsr",    XSPR(31,467,1008), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdbcr0",   XSPR(31,467,308),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbcr0",   XSPR(31,467,1010), XSPR_MASK, PPC405,	{ RS } },
+{ "mtdbcr1",   XSPR(31,467,309),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbcr1",   XSPR(31,467,957),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdbcr2",   XSPR(31,467,310),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac1",    XSPR(31,467,312),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac1",    XSPR(31,467,1012), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiac2",    XSPR(31,467,313),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac2",    XSPR(31,467,1013), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiac3",    XSPR(31,467,314),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac3",    XSPR(31,467,948),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtiac4",    XSPR(31,467,315),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac4",    XSPR(31,467,949),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdac1",    XSPR(31,467,316),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdac1",    XSPR(31,467,1014), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdac2",    XSPR(31,467,317),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdac2",    XSPR(31,467,1015), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdvc1",    XSPR(31,467,318),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdvc1",    XSPR(31,467,950),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdvc2",    XSPR(31,467,319),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdvc2",    XSPR(31,467,951),  XSPR_MASK, PPC405,	{ RS } },
+{ "mttsr",     XSPR(31,467,336),  XSPR_MASK, BOOKE,     { RS } },
+{ "mttsr",     XSPR(31,467,984),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttcr",     XSPR(31,467,340),  XSPR_MASK, BOOKE,     { RS } },
+{ "mttcr",     XSPR(31,467,986),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtivor0",   XSPR(31,467,400),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor1",   XSPR(31,467,401),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor2",   XSPR(31,467,402),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor3",   XSPR(31,467,403),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor4",   XSPR(31,467,404),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor5",   XSPR(31,467,405),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor6",   XSPR(31,467,406),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor7",   XSPR(31,467,407),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor8",   XSPR(31,467,408),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor9",   XSPR(31,467,409),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor10",  XSPR(31,467,410),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor11",  XSPR(31,467,411),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor12",  XSPR(31,467,412),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor13",  XSPR(31,467,413),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor14",  XSPR(31,467,414),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor15",  XSPR(31,467,415),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtspefscr",  XSPR(31,467,512),  XSPR_MASK, PPCSPE,   { RS } },
+{ "mtbbear",   XSPR(31,467,513),  XSPR_MASK, PPCBRLK,   { RS } },
+{ "mtbbtar",   XSPR(31,467,514),  XSPR_MASK, PPCBRLK,  { RS } },
+{ "mtivor32",  XSPR(31,467,528),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor33",  XSPR(31,467,529),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor34",  XSPR(31,467,530),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor35",  XSPR(31,467,531),  XSPR_MASK, PPCPMR,	{ RS } },
+{ "mtibatu",   XSPR(31,467,528),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtibatl",   XSPR(31,467,529),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatu",   XSPR(31,467,536),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatl",   XSPR(31,467,537),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtmcsrr0",  XSPR(31,467,570),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtmcsrr1",  XSPR(31,467,571),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtmcsr",    XSPR(31,467,572),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtummcr0",  XSPR(31,467,936),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc1",   XSPR(31,467,937),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc2",   XSPR(31,467,938),  XSPR_MASK, PPC750,    { RS } },
+{ "mtusia",    XSPR(31,467,939),  XSPR_MASK, PPC750,    { RS } },
+{ "mtummcr1",  XSPR(31,467,940),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc3",   XSPR(31,467,941),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc4",   XSPR(31,467,942),  XSPR_MASK, PPC750,    { RS } },
+{ "mtzpr",     XSPR(31,467,944),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtccr0",    XSPR(31,467,947),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtmmcr0",   XSPR(31,467,952),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsgr",     XSPR(31,467,953),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpmc1",    XSPR(31,467,953),  XSPR_MASK, PPC750,    { RS } },
+{ "mtdcwr",    XSPR(31,467,954),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpmc2",    XSPR(31,467,954),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsler",    XSPR(31,467,955),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtsia",     XSPR(31,467,955),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsu0r",    XSPR(31,467,956),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtmmcr1",   XSPR(31,467,956),  XSPR_MASK, PPC750,    { RS } },
+{ "mtpmc3",    XSPR(31,467,957),  XSPR_MASK, PPC750,    { RS } },
+{ "mtpmc4",    XSPR(31,467,958),  XSPR_MASK, PPC750,    { RS } },
+{ "mticdbdr",  XSPR(31,467,979),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtevpr",    XSPR(31,467,982),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtcdbcr",   XSPR(31,467,983),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpit",     XSPR(31,467,987),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttbhi",    XSPR(31,467,988),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttblo",    XSPR(31,467,989),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtsrr2",    XSPR(31,467,990),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtsrr3",    XSPR(31,467,991),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtl2cr",    XSPR(31,467,1017), XSPR_MASK, PPC750,    { RS } },
+{ "mtdccr",    XSPR(31,467,1018), XSPR_MASK, PPC403,	{ RS } },
+{ "mticcr",    XSPR(31,467,1019), XSPR_MASK, PPC403,	{ RS } },
+{ "mtictc",    XSPR(31,467,1019), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbl1",    XSPR(31,467,1020), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm1",   XSPR(31,467,1020), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbu1",    XSPR(31,467,1021), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm2",   XSPR(31,467,1021), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbl2",    XSPR(31,467,1022), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm3",   XSPR(31,467,1022), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbu2",    XSPR(31,467,1023), XSPR_MASK, PPC403,	{ RS } },
+{ "mtspr",     X(31,467),	  X_MASK,    COM,	{ SPR, RS } },
+
+{ "dcbi",    X(31,470),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "nand",    XRC(31,476,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "nand.",   XRC(31,476,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "dcbie",   X(31,478),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "dcread",  X(31,486),	X_MASK,		PPC403|PPC440,	{ RT, RA, RB }},
+
+{ "mtpmr",   X(31,462),	X_MASK,		PPCPMR,		{ PMR, RS }},
+
+{ "icbtls",  X(31,486),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "nabs",    XO(31,488,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "nabs.",   XO(31,488,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "nabso",   XO(31,488,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "nabso.",  XO(31,488,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divd",    XO(31,489,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divd.",   XO(31,489,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo",   XO(31,489,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo.",  XO(31,489,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+
+{ "divw",    XO(31,491,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divw.",   XO(31,491,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo",   XO(31,491,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo.",  XO(31,491,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "icbtlse", X(31,494),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "slbia",   X(31,498),	0xffffffff,	PPC64,		{ 0 } },
+
+{ "cli",     X(31,502), XRB_MASK,	POWER,		{ RT, RA } },
+
+{ "stdcxe.", XRC(31,511,1), X_MASK,	BOOKE64,	{ RS, RA, RB } },
+
+{ "mcrxr",   X(31,512),	XRARB_MASK|(3<<21), COM,	{ BF } },
+
+{ "bblels",  X(31,518),	X_MASK,		PPCBRLK,	{ 0 }},
+{ "mcrxr64", X(31,544),	XRARB_MASK|(3<<21), BOOKE64,	{ BF } },
+
+{ "clcs",    X(31,531), XRB_MASK,	M601,		{ RT, RA } },
+
+{ "ldbrx",   X(31,532),	X_MASK,		CELL,		{ RT, RA0, RB } },
+
+{ "lswx",    X(31,533),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lsx",     X(31,533),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lwbrx",   X(31,534),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lbrx",    X(31,534),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lfsx",    X(31,535),	X_MASK,		COM,		{ FRT, RA0, RB } },
+
+{ "srw",     XRC(31,536,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr",      XRC(31,536,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "srw.",    XRC(31,536,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr.",     XRC(31,536,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "rrib",    XRC(31,537,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "rrib.",   XRC(31,537,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srd",     XRC(31,539,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srd.",    XRC(31,539,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "maskir",  XRC(31,541,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskir.", XRC(31,541,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "lwbrxe",  X(31,542),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "lfsxe",   X(31,543),	X_MASK,		BOOKE64,	{ FRT, RA0, RB } },
+
+{ "bbelr",   X(31,550),	X_MASK,		PPCBRLK,	{ 0 }},
+
+{ "tlbsync", X(31,566),	0xffffffff,	PPC,		{ 0 } },
+
+{ "lfsux",   X(31,567),	X_MASK,		COM,		{ FRT, RAS, RB } },
+
+{ "lfsuxe",  X(31,575),	X_MASK,		BOOKE64,	{ FRT, RAS, RB } },
+
+{ "mfsr",    X(31,595),	XRB_MASK|(1<<20), COM32,	{ RT, SR } },
+
+{ "lswi",    X(31,597),	X_MASK,		PPCCOM,		{ RT, RA0, NB } },
+{ "lsi",     X(31,597),	X_MASK,		PWRCOM,		{ RT, RA0, NB } },
+
+{ "lwsync",  XSYNC(31,598,1), 0xffffffff, PPC,		{ 0 } },
+{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64,	{ 0 } },
+{ "msync",   X(31,598), 0xffffffff,	BOOKE,		{ 0 } },
+{ "sync",    X(31,598), XSYNC_MASK,	PPCCOM,		{ LS } },
+{ "dcs",     X(31,598), 0xffffffff,	PWRCOM,		{ 0 } },
+
+{ "lfdx",    X(31,599), X_MASK,		COM,		{ FRT, RA0, RB } },
+
+{ "lfdxe",   X(31,607), X_MASK,		BOOKE64,	{ FRT, RA0, RB } },
+
+{ "mffgpr",  XRC(31,607,0), XRA_MASK,	POWER6,		{ FRT, RB } },
+
+{ "mfsri",   X(31,627), X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "dclst",   X(31,630), XRB_MASK,	PWRCOM,		{ RS, RA } },
+
+{ "lfdux",   X(31,631), X_MASK,		COM,		{ FRT, RAS, RB } },
+
+{ "lfduxe",  X(31,639), X_MASK,		BOOKE64,	{ FRT, RAS, RB } },
+
+{ "mfsrin",  X(31,659), XRA_MASK,	PPC32,		{ RT, RB } },
+
+{ "stdbrx",  X(31,660), X_MASK,		CELL,		{ RS, RA0, RB } },
+
+{ "stswx",   X(31,661), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stsx",    X(31,661), X_MASK,		PWRCOM,		{ RS, RA0, RB } },
+
+{ "stwbrx",  X(31,662), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stbrx",   X(31,662), X_MASK,		PWRCOM,		{ RS, RA0, RB } },
+
+{ "stfsx",   X(31,663), X_MASK,		COM,		{ FRS, RA0, RB } },
+
+{ "srq",     XRC(31,664,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srq.",    XRC(31,664,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sre",     XRC(31,665,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sre.",    XRC(31,665,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stwbrxe", X(31,670), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "stfsxe",  X(31,671), X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
+
+{ "stfsux",  X(31,695),	X_MASK,		COM,		{ FRS, RAS, RB } },
+
+{ "sriq",    XRC(31,696,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sriq.",   XRC(31,696,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "stfsuxe", X(31,703),	X_MASK,		BOOKE64,	{ FRS, RAS, RB } },
+
+{ "stswi",   X(31,725),	X_MASK,		PPCCOM,		{ RS, RA0, NB } },
+{ "stsi",    X(31,725),	X_MASK,		PWRCOM,		{ RS, RA0, NB } },
+
+{ "stfdx",   X(31,727),	X_MASK,		COM,		{ FRS, RA0, RB } },
+
+{ "srlq",    XRC(31,728,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srlq.",   XRC(31,728,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sreq",    XRC(31,729,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sreq.",   XRC(31,729,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stfdxe",  X(31,735),	X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
+
+{ "mftgpr",  XRC(31,735,0), XRA_MASK,	POWER6,		{ RT, FRB } },
+
+{ "dcba",    X(31,758),	XRT_MASK,	PPC405 | BOOKE,	{ RA, RB } },
+
+{ "stfdux",  X(31,759),	X_MASK,		COM,		{ FRS, RAS, RB } },
+
+{ "srliq",   XRC(31,760,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "srliq.",  XRC(31,760,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "dcbae",   X(31,766),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "stfduxe", X(31,767),	X_MASK,		BOOKE64,	{ FRS, RAS, RB } },
+
+{ "tlbivax", X(31,786),	XRT_MASK,	BOOKE,		{ RA, RB } },
+{ "tlbivaxe",X(31,787),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "lwzcix",  X(31,789),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "lhbrx",   X(31,790),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "sraw",    XRC(31,792,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra",     XRC(31,792,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "sraw.",   XRC(31,792,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra.",    XRC(31,792,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "srad",    XRC(31,794,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srad.",   XRC(31,794,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "lhbrxe",  X(31,798),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "ldxe",    X(31,799),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+{ "lduxe",   X(31,831),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "rac",     X(31,818),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lhzcix",  X(31,821),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "dss",     XDSS(31,822,0), XDSS_MASK,	PPCVEC,		{ STRM } },
+{ "dssall",  XDSS(31,822,1), XDSS_MASK,	PPCVEC,		{ 0 } },
+
+{ "srawi",   XRC(31,824,0), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai",    XRC(31,824,0), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+{ "srawi.",  XRC(31,824,1), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai.",   XRC(31,824,1), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+
+{ "slbmfev", X(31,851), XRA_MASK,	PPC64,		{ RT, RB } },
+
+{ "lbzcix",  X(31,853),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "mbar",    X(31,854),	X_MASK,		BOOKE,		{ MO } },
+{ "eieio",   X(31,854),	0xffffffff,	PPC,		{ 0 } },
+
+{ "lfiwax",  X(31,855),	X_MASK,		POWER6,		{ FRT, RA0, RB } },
+
+{ "ldcix",   X(31,885),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "tlbsx",   XRC(31,914,0), X_MASK, 	PPC403|BOOKE,	{ RTO, RA, RB } },
+{ "tlbsx.",  XRC(31,914,1), X_MASK, 	PPC403|BOOKE,	{ RTO, RA, RB } },
+{ "tlbsxe",  XRC(31,915,0), X_MASK,	BOOKE64,	{ RTO, RA, RB } },
+{ "tlbsxe.", XRC(31,915,1), X_MASK,	BOOKE64,	{ RTO, RA, RB } },
+
+{ "slbmfee", X(31,915), XRA_MASK,	PPC64,		{ RT, RB } },
+
+{ "stwcix",  X(31,917),	X_MASK,		POWER6,		{ RS, RA0, RB } },
+
+{ "sthbrx",  X(31,918),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "sraq",    XRC(31,920,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sraq.",   XRC(31,920,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srea",    XRC(31,921,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srea.",   XRC(31,921,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "extsh",   XRC(31,922,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts",    XRC(31,922,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "extsh.",  XRC(31,922,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts.",   XRC(31,922,1), XRB_MASK,	PWRCOM,		{ RA, RS } },
+
+{ "sthbrxe", X(31,926),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "stdxe",   X(31,927), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "tlbrehi", XTLB(31,946,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbrelo", XTLB(31,946,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbre",   X(31,946),	X_MASK,		PPC403|BOOKE,	{ RSO, RAOPT, SHO } },
+
+{ "sthcix",  X(31,949),	X_MASK,		POWER6,		{ RS, RA0, RB } },
+
+{ "sraiq",   XRC(31,952,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sraiq.",  XRC(31,952,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "extsb",   XRC(31,954,0), XRB_MASK,	PPC,		{ RA, RS} },
+{ "extsb.",  XRC(31,954,1), XRB_MASK,	PPC,		{ RA, RS} },
+
+{ "stduxe",  X(31,959),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "iccci",   X(31,966),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "tlbwehi", XTLB(31,978,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwelo", XTLB(31,978,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwe",   X(31,978),	X_MASK,		PPC403|BOOKE,	{ RSO, RAOPT, SHO } },
+{ "tlbld",   X(31,978),	XRTRA_MASK,	PPC,		{ RB } },
+
+{ "stbcix",  X(31,981),	X_MASK,		POWER6,		{ RS, RA0, RB } },
+
+{ "icbi",    X(31,982),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "stfiwx",  X(31,983),	X_MASK,		PPC,		{ FRS, RA0, RB } },
+
+{ "extsw",   XRC(31,986,0), XRB_MASK,	PPC64 | BOOKE64,{ RA, RS } },
+{ "extsw.",  XRC(31,986,1), XRB_MASK,	PPC64,		{ RA, RS } },
+
+{ "icread",  X(31,998),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "icbie",   X(31,990),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+{ "stfiwxe", X(31,991),	X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
+
+{ "tlbli",   X(31,1010), XRTRA_MASK,	PPC,		{ RB } },
+
+{ "stdcix",  X(31,1013), X_MASK,	POWER6,		{ RS, RA0, RB } },
+
+{ "dcbzl",   XOPL(31,1014,1), XRT_MASK,POWER4,            { RA, RB } },
+{ "dcbz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+{ "dclz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "dcbze",   X(31,1022), XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "lvebx",   X(31,   7), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvehx",   X(31,  39), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvewx",   X(31,  71), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsl",    X(31,   6), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsr",    X(31,  38), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvx",     X(31, 103), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvxl",    X(31, 359), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "stvebx",  X(31, 135), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvehx",  X(31, 167), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvewx",  X(31, 199), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvx",    X(31, 231), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvxl",   X(31, 487), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+
+/* New load/store left/right index vector instructions that are in the Cell only.  */
+{ "lvlx",    X(31, 519), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvlxl",   X(31, 775), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvrx",    X(31, 551), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvrxl",   X(31, 807), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "stvlx",   X(31, 647), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvlxl",  X(31, 903), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvrx",   X(31, 679), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvrxl",  X(31, 935), X_MASK,	CELL,		{ VS, RA0, RB } },
+
+{ "lwz",     OP(32),	OP_MASK,	PPCCOM,		{ RT, D, RA0 } },
+{ "l",	     OP(32),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
+
+{ "lwzu",    OP(33),	OP_MASK,	PPCCOM,		{ RT, D, RAL } },
+{ "lu",      OP(33),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
+
+{ "lbz",     OP(34),	OP_MASK,	COM,		{ RT, D, RA0 } },
+
+{ "lbzu",    OP(35),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "stw",     OP(36),	OP_MASK,	PPCCOM,		{ RS, D, RA0 } },
+{ "st",      OP(36),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
+
+{ "stwu",    OP(37),	OP_MASK,	PPCCOM,		{ RS, D, RAS } },
+{ "stu",     OP(37),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
+
+{ "stb",     OP(38),	OP_MASK,	COM,		{ RS, D, RA0 } },
+
+{ "stbu",    OP(39),	OP_MASK,	COM,		{ RS, D, RAS } },
+
+{ "lhz",     OP(40),	OP_MASK,	COM,		{ RT, D, RA0 } },
+
+{ "lhzu",    OP(41),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "lha",     OP(42),	OP_MASK,	COM,		{ RT, D, RA0 } },
+
+{ "lhau",    OP(43),	OP_MASK,	COM,		{ RT, D, RAL } },
+
+{ "sth",     OP(44),	OP_MASK,	COM,		{ RS, D, RA0 } },
+
+{ "sthu",    OP(45),	OP_MASK,	COM,		{ RS, D, RAS } },
+
+{ "lmw",     OP(46),	OP_MASK,	PPCCOM,		{ RT, D, RAM } },
+{ "lm",      OP(46),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
+
+{ "stmw",    OP(47),	OP_MASK,	PPCCOM,		{ RS, D, RA0 } },
+{ "stm",     OP(47),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
+
+{ "lfs",     OP(48),	OP_MASK,	COM,		{ FRT, D, RA0 } },
+
+{ "lfsu",    OP(49),	OP_MASK,	COM,		{ FRT, D, RAS } },
+
+{ "lfd",     OP(50),	OP_MASK,	COM,		{ FRT, D, RA0 } },
+
+{ "lfdu",    OP(51),	OP_MASK,	COM,		{ FRT, D, RAS } },
+
+{ "stfs",    OP(52),	OP_MASK,	COM,		{ FRS, D, RA0 } },
+
+{ "stfsu",   OP(53),	OP_MASK,	COM,		{ FRS, D, RAS } },
+
+{ "stfd",    OP(54),	OP_MASK,	COM,		{ FRS, D, RA0 } },
+
+{ "stfdu",   OP(55),	OP_MASK,	COM,		{ FRS, D, RAS } },
+
+{ "lq",      OP(56),	OP_MASK,	POWER4,		{ RTQ, DQ, RAQ } },
+
+{ "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA0 } },
+
+{ "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA0 } },
+
+{ "lfdp",    OP(57),	OP_MASK,	POWER6,		{ FRT, D, RA0 } },
+
+{ "lbze",    DEO(58,0), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lbzue",   DEO(58,1), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lhze",    DEO(58,2), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lhzue",   DEO(58,3), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lhae",    DEO(58,4), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lhaue",   DEO(58,5), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lwze",    DEO(58,6), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lwzue",   DEO(58,7), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "stbe",    DEO(58,8), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "stbue",   DEO(58,9), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+{ "sthe",    DEO(58,10), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "sthue",   DEO(58,11), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+{ "stwe",    DEO(58,14), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "stwue",   DEO(58,15), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+
+{ "ld",      DSO(58,0),	DS_MASK,	PPC64,		{ RT, DS, RA0 } },
+
+{ "ldu",     DSO(58,1), DS_MASK,	PPC64,		{ RT, DS, RAL } },
+
+{ "lwa",     DSO(58,2), DS_MASK,	PPC64,		{ RT, DS, RA0 } },
+
+{ "dadd",    XRC(59,2,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dadd.",   XRC(59,2,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dqua",    ZRC(59,3,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "dqua.",   ZRC(59,3,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "fdivs",   A(59,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fdivs.",  A(59,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsubs",   A(59,20,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fsubs.",  A(59,20,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fadds",   A(59,21,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fadds.",  A(59,21,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsqrts",  A(59,22,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fsqrts.", A(59,22,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fres",    A(59,24,0), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+{ "fres.",   A(59,24,1), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+
+{ "fmuls",   A(59,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+{ "fmuls.",  A(59,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+
+{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5,		{ FRT, FRB, A_L } },
+{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5,		{ FRT, FRB, A_L } },
+
+{ "fmsubs",  A(59,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmsubs.", A(59,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadds",  A(59,29,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmadds.", A(59,29,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsubs", A(59,30,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsubs.",A(59,30,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadds", A(59,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadds.",A(59,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "dmul",    XRC(59,34,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dmul.",   XRC(59,34,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "drrnd",   ZRC(59,35,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "drrnd.",  ZRC(59,35,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "dscli",   ZRC(59,66,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscli.",  ZRC(59,66,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "dquai",   ZRC(59,67,0), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+{ "dquai.",  ZRC(59,67,1), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+
+{ "dscri",   ZRC(59,98,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscri.",  ZRC(59,98,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "drintx",  ZRC(59,99,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintx.", ZRC(59,99,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dcmpo",   X(59,130),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstex",  X(59,162),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+{ "dtstdc",  Z(59,194),	   Z_MASK,	POWER6,		{ BF,  FRA, DCM } },
+{ "dtstdg",  Z(59,226),	   Z_MASK,	POWER6,		{ BF,  FRA, DGM } },
+
+{ "drintn",  ZRC(59,227,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintn.", ZRC(59,227,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dctdp",   XRC(59,258,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctdp.",  XRC(59,258,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dctfix",  XRC(59,290,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctfix.", XRC(59,290,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "ddedpd",  XRC(59,322,0), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+{ "ddedpd.", XRC(59,322,1), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+
+{ "dxex",    XRC(59,354,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dxex.",   XRC(59,354,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dsub",    XRC(59,514,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dsub.",   XRC(59,514,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "ddiv",    XRC(59,546,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "ddiv.",   XRC(59,546,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dcmpu",   X(59,642),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstsf",  X(59,674),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "drsp",    XRC(59,770,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "drsp.",   XRC(59,770,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dcffix",  XRC(59,802,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dcffix.", XRC(59,802,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "denbcd",  XRC(59,834,0), X_MASK,	POWER6,		{ S, FRT, FRB } },
+{ "denbcd.", XRC(59,834,1), X_MASK,	POWER6,		{ S, FRT, FRB } },
+
+{ "diex",    XRC(59,866,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "diex.",   XRC(59,866,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "stfq",    OP(60),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "stfqu",   OP(61),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "stfdp",   OP(61),	OP_MASK,	POWER6,		{ FRT, D, RA0 } },
+
+{ "lde",     DEO(62,0), DE_MASK,	BOOKE64,	{ RT, DES, RA0 } },
+{ "ldue",    DEO(62,1), DE_MASK,	BOOKE64,	{ RT, DES, RA0 } },
+{ "lfse",    DEO(62,4), DE_MASK,	BOOKE64,	{ FRT, DES, RA0 } },
+{ "lfsue",   DEO(62,5), DE_MASK,	BOOKE64,	{ FRT, DES, RAS } },
+{ "lfde",    DEO(62,6), DE_MASK,	BOOKE64,	{ FRT, DES, RA0 } },
+{ "lfdue",   DEO(62,7), DE_MASK,	BOOKE64,	{ FRT, DES, RAS } },
+{ "stde",    DEO(62,8), DE_MASK,	BOOKE64,	{ RS, DES, RA0 } },
+{ "stdue",   DEO(62,9), DE_MASK,	BOOKE64,	{ RS, DES, RAS } },
+{ "stfse",   DEO(62,12), DE_MASK,	BOOKE64,	{ FRS, DES, RA0 } },
+{ "stfsue",  DEO(62,13), DE_MASK,	BOOKE64,	{ FRS, DES, RAS } },
+{ "stfde",   DEO(62,14), DE_MASK,	BOOKE64,	{ FRS, DES, RA0 } },
+{ "stfdue",  DEO(62,15), DE_MASK,	BOOKE64,	{ FRS, DES, RAS } },
+
+{ "std",     DSO(62,0),	DS_MASK,	PPC64,		{ RS, DS, RA0 } },
+
+{ "stdu",    DSO(62,1),	DS_MASK,	PPC64,		{ RS, DS, RAS } },
+
+{ "stq",     DSO(62,2),	DS_MASK,	POWER4,		{ RSQ, DS, RA0 } },
+
+{ "fcmpu",   X(63,0),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
+
+{ "daddq",   XRC(63,2,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "daddq.",  XRC(63,2,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dquaq",   ZRC(63,3,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "dquaq.",  ZRC(63,3,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "fcpsgn",  XRC(63,8,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "fcpsgn.", XRC(63,8,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "frsp",    XRC(63,12,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "frsp.",   XRC(63,12,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "fctiw",   XRC(63,14,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcir",    XRC(63,14,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiw.",  XRC(63,14,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcir.",   XRC(63,14,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fctiwz",  XRC(63,15,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcirz",   XRC(63,15,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiwz.", XRC(63,15,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
+{ "fcirz.",  XRC(63,15,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fdiv",    A(63,18,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd",      A(63,18,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fdiv.",   A(63,18,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd.",     A(63,18,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fsub",    A(63,20,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs",      A(63,20,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fsub.",   A(63,20,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs.",     A(63,20,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fadd",    A(63,21,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa",      A(63,21,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fadd.",   A(63,21,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa.",     A(63,21,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+
+{ "fsqrt",   A(63,22,0), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
+{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
+
+{ "fsel",    A(63,23,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fsel.",   A(63,23,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fre",     A(63,24,0), AFRALFRC_MASK,	POWER5,		{ FRT, FRB, A_L } },
+{ "fre.",    A(63,24,1), AFRALFRC_MASK,	POWER5,		{ FRT, FRB, A_L } },
+
+{ "fmul",    A(63,25,0), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm",      A(63,25,0), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
+{ "fmul.",   A(63,25,1), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm.",     A(63,25,1), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
+
+{ "frsqrte", A(63,26,0), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+{ "frsqrte.",A(63,26,1), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+
+{ "fmsub",   A(63,28,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms",     A(63,28,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmsub.",  A(63,28,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms.",    A(63,28,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadd",   A(63,29,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma",     A(63,29,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmadd.",  A(63,29,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma.",    A(63,29,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsub",  A(63,30,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms",    A(63,30,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsub.", A(63,30,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms.",   A(63,30,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadd",  A(63,31,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma",    A(63,31,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadd.", A(63,31,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma.",   A(63,31,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+
+{ "fcmpo",   X(63,32),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
+
+{ "dmulq",   XRC(63,34,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dmulq.",  XRC(63,34,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "drrndq",  ZRC(63,35,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "drrndq.", ZRC(63,35,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "mtfsb1",  XRC(63,38,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb1.", XRC(63,38,1), XRARB_MASK,	COM,		{ BT } },
+
+{ "fneg",    XRC(63,40,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fneg.",   XRC(63,40,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "mcrfs",   X(63,64),	XRB_MASK|(3<<21)|(3<<16), COM,	{ BF, BFA } },
+
+{ "dscliq",  ZRC(63,66,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscliq.", ZRC(63,66,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "dquaiq",  ZRC(63,67,0), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+{ "dquaiq.", ZRC(63,67,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "mtfsb0",  XRC(63,70,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb0.", XRC(63,70,1), XRARB_MASK,	COM,		{ BT } },
+
+{ "fmr",     XRC(63,72,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fmr.",    XRC(63,72,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "dscriq",  ZRC(63,98,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscriq.", ZRC(63,98,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "drintxq", ZRC(63,99,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintxq.",ZRC(63,99,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dcmpoq",  X(63,130),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "mtfsfi",  XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
+{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
+
+{ "fnabs",   XRC(63,136,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fnabs.",  XRC(63,136,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "dtstexq", X(63,162),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+{ "dtstdcq", Z(63,194),	    Z_MASK,	POWER6,		{ BF,  FRA, DCM } },
+{ "dtstdgq", Z(63,226),	    Z_MASK,	POWER6,		{ BF,  FRA, DGM } },
+
+{ "drintnq", ZRC(63,227,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintnq.",ZRC(63,227,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dctqpq",  XRC(63,258,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctqpq.", XRC(63,258,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "fabs",    XRC(63,264,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fabs.",   XRC(63,264,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "dctfixq", XRC(63,290,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctfixq.",XRC(63,290,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "ddedpdq", XRC(63,322,0), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+{ "ddedpdq.",XRC(63,322,1), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+
+{ "dxexq",   XRC(63,354,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dxexq.",  XRC(63,354,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "frin",    XRC(63,392,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frin.",   XRC(63,392,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "friz",    XRC(63,424,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "friz.",   XRC(63,424,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frip",    XRC(63,456,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frip.",   XRC(63,456,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frim",    XRC(63,488,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frim.",   XRC(63,488,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+
+{ "dsubq",   XRC(63,514,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dsubq.",  XRC(63,514,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "ddivq",   XRC(63,546,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "ddivq.",  XRC(63,546,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "mffs",    XRC(63,583,0), XRARB_MASK,	COM,		{ FRT } },
+{ "mffs.",   XRC(63,583,1), XRARB_MASK,	COM,		{ FRT } },
+
+{ "dcmpuq",  X(63,642),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstsfq", X(63,674),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, W } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, W } },
+
+{ "drdpq",   XRC(63,770,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "drdpq.",  XRC(63,770,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dcffixq", XRC(63,802,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dcffixq.",XRC(63,802,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "fctid",   XRC(63,814,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctid.",  XRC(63,814,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "fctidz",  XRC(63,815,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctidz.", XRC(63,815,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "denbcdq", XRC(63,834,0), X_MASK,	POWER6,		{ S, FRT, FRB } },
+{ "denbcdq.",XRC(63,834,1), X_MASK,	POWER6,		{ S, FRT, FRB } },
+
+{ "fcfid",   XRC(63,846,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fcfid.",  XRC(63,846,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "diexq",   XRC(63,866,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "diexq.",  XRC(63,866,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+};
+
+const int powerpc_num_opcodes =
+  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+
+/* The macro table.  This is only used by the assembler.  */
+
+/* The expressions of the form (-x ! 31) & (x | 31) have the value 0
+   when x=0; 32-x when x is between 1 and 31; are negative if x is
+   negative; and are 32 or more otherwise.  This is what you want
+   when, for instance, you are emulating a right shift by a
+   rotate-left-and-mask, because the underlying instructions support
+   shifts of size 0 but not shifts of size 32.  By comparison, when
+   extracting x bits from some word you want to use just 32-x, because
+   the underlying instructions don't support extracting 0 bits but do
+   support extracting the whole word (32 bits in this case).  */
+
+const struct powerpc_macro powerpc_macros[] = {
+{ "extldi",  4,   PPC64,	"rldicr %0,%1,%3,(%2)-1" },
+{ "extldi.", 4,   PPC64,	"rldicr. %0,%1,%3,(%2)-1" },
+{ "extrdi",  4,   PPC64,	"rldicl %0,%1,(%2)+(%3),64-(%2)" },
+{ "extrdi.", 4,   PPC64,	"rldicl. %0,%1,(%2)+(%3),64-(%2)" },
+{ "insrdi",  4,   PPC64,	"rldimi %0,%1,64-((%2)+(%3)),%3" },
+{ "insrdi.", 4,   PPC64,	"rldimi. %0,%1,64-((%2)+(%3)),%3" },
+{ "rotrdi",  3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "rotrdi.", 3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "sldi",    3,   PPC64,	"rldicr %0,%1,%2,63-(%2)" },
+{ "sldi.",   3,   PPC64,	"rldicr. %0,%1,%2,63-(%2)" },
+{ "srdi",    3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "srdi.",   3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "clrrdi",  3,   PPC64,	"rldicr %0,%1,0,63-(%2)" },
+{ "clrrdi.", 3,   PPC64,	"rldicr. %0,%1,0,63-(%2)" },
+{ "clrlsldi",4,   PPC64,	"rldic %0,%1,%3,(%2)-(%3)" },
+{ "clrlsldi.",4,  PPC64,	"rldic. %0,%1,%3,(%2)-(%3)" },
+
+{ "extlwi",  4,   PPCCOM,	"rlwinm %0,%1,%3,0,(%2)-1" },
+{ "extlwi.", 4,   PPCCOM,	"rlwinm. %0,%1,%3,0,(%2)-1" },
+{ "extrwi",  4,   PPCCOM,	"rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" },
+{ "extrwi.", 4,   PPCCOM,	"rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" },
+{ "inslwi",  4,   PPCCOM,	"rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" },
+{ "inslwi.", 4,   PPCCOM,	"rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"},
+{ "insrwi",  4,   PPCCOM,	"rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
+{ "insrwi.", 4,   PPCCOM,	"rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
+{ "rotrwi",  3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "rotrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "slwi",    3,   PPCCOM,	"rlwinm %0,%1,%2,0,31-(%2)" },
+{ "sli",     3,   PWRCOM,	"rlinm %0,%1,%2,0,31-(%2)" },
+{ "slwi.",   3,   PPCCOM,	"rlwinm. %0,%1,%2,0,31-(%2)" },
+{ "sli.",    3,   PWRCOM,	"rlinm. %0,%1,%2,0,31-(%2)" },
+{ "srwi",    3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri",     3,   PWRCOM,	"rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "srwi.",   3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri.",    3,   PWRCOM,	"rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "clrrwi",  3,   PPCCOM,	"rlwinm %0,%1,0,0,31-(%2)" },
+{ "clrrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,0,0,31-(%2)" },
+{ "clrlslwi",4,   PPCCOM,	"rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
+{ "clrlslwi.",4,  PPCCOM,	"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
+};
+
+const int powerpc_num_macros =
+  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
+
+
+/* This file provides several disassembler functions, all of which use
+   the disassembler interface defined in dis-asm.h.  Several functions
+   are provided because this file handles disassembly for the PowerPC
+   in both big and little endian mode and also for the POWER (RS/6000)
+   chip.  */
+
+static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
+
+/* Determine which set of machines to disassemble for.  PPC403/601 or
+   BookE.  For convenience, also disassemble instructions supported
+   by the AltiVec vector unit.  */
+
+static int
+powerpc_dialect (struct disassemble_info *info)
+{
+  int dialect = PPC_OPCODE_PPC;
+
+  if (BFD_DEFAULT_TARGET_SIZE == 64)
+    dialect |= PPC_OPCODE_64;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "booke") != NULL)
+    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
+  else if ((info->mach == bfd_mach_ppc_e500)
+	   || (info->disassembler_options
+	       && strstr (info->disassembler_options, "e500") != NULL))
+    dialect |= (PPC_OPCODE_BOOKE
+		| PPC_OPCODE_SPE | PPC_OPCODE_ISEL
+		| PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
+		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+		| PPC_OPCODE_RFMCI);
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "efs") != NULL)
+    dialect |= PPC_OPCODE_EFS;
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "e300") != NULL)
+    dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON;
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "440") != NULL)
+    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32
+      | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI;
+  else
+    dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
+		| PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power4") != NULL)
+    dialect |= PPC_OPCODE_POWER4;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power5") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "cell") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power6") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "any") != NULL)
+    dialect |= PPC_OPCODE_ANY;
+
+  if (info->disassembler_options)
+    {
+      if (strstr (info->disassembler_options, "32") != NULL)
+	dialect &= ~PPC_OPCODE_64;
+      else if (strstr (info->disassembler_options, "64") != NULL)
+	dialect |= PPC_OPCODE_64;
+    }
+
+  info->private_data = (char *) 0 + dialect;
+  return dialect;
+}
+
+/* Qemu default */
+int
+print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 1, dialect);
+}
+
+/* Print a big endian PowerPC instruction.  */
+
+int
+print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 1, dialect);
+}
+
+/* Print a little endian PowerPC instruction.  */
+
+int
+print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 0, dialect);
+}
+
+/* Print a POWER (RS/6000) instruction.  */
+
+int
+print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
+}
+
+/* Extract the operand value from the PowerPC or POWER instruction.  */
+
+static long
+operand_value_powerpc (const struct powerpc_operand *operand,
+		       unsigned long insn, int dialect)
+{
+  long value;
+  int invalid;
+  /* Extract the value from the instruction.  */
+  if (operand->extract)
+    value = (*operand->extract) (insn, dialect, &invalid);
+  else
+    {
+      value = (insn >> operand->shift) & operand->bitm;
+      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+	{
+	  /* BITM is always some number of zeros followed by some
+	     number of ones, followed by some numer of zeros.  */
+	  unsigned long top = operand->bitm;
+	  /* top & -top gives the rightmost 1 bit, so this
+	     fills in any trailing zeros.  */
+	  top |= (top & -top) - 1;
+	  top &= ~(top >> 1);
+	  value = (value ^ top) - top;
+	}
+    }
+
+  return value;
+}
+
+/* Determine whether the optional operand(s) should be printed.  */
+
+static int
+skip_optional_operands (const unsigned char *opindex,
+			unsigned long insn, int dialect)
+{
+  const struct powerpc_operand *operand;
+
+  for (; *opindex != 0; opindex++)
+    {
+      operand = &powerpc_operands[*opindex];
+      if ((operand->flags & PPC_OPERAND_NEXT) != 0
+	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+	      && operand_value_powerpc (operand, insn, dialect) != 0))
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Print a PowerPC or POWER instruction.  */
+
+static int
+print_insn_powerpc (bfd_vma memaddr,
+		    struct disassemble_info *info,
+		    int bigendian,
+		    int dialect)
+{
+  bfd_byte buffer[4];
+  int status;
+  unsigned long insn;
+  const struct powerpc_opcode *opcode;
+  const struct powerpc_opcode *opcode_end;
+  unsigned long op;
+
+  if (dialect == 0)
+    dialect = powerpc_dialect (info);
+
+  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  if (bigendian)
+    insn = bfd_getb32 (buffer);
+  else
+    insn = bfd_getl32 (buffer);
+
+  /* Get the major opcode of the instruction.  */
+  op = PPC_OP (insn);
+
+  /* Find the first match in the opcode table.  We could speed this up
+     a bit by doing a binary search on the major opcode.  */
+  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+ again:
+  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
+    {
+      unsigned long table_op;
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+      int need_comma;
+      int need_paren;
+      int skip_optional;
+
+      table_op = PPC_OP (opcode->opcode);
+      if (op < table_op)
+	break;
+      if (op > table_op)
+	continue;
+
+      if ((insn & opcode->mask) != opcode->opcode
+	  || (opcode->flags & dialect) == 0)
+	continue;
+
+      /* Make two passes over the operands.  First see if any of them
+	 have extraction functions, and, if they do, make sure the
+	 instruction is valid.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  operand = powerpc_operands + *opindex;
+	  if (operand->extract)
+	    (*operand->extract) (insn, dialect, &invalid);
+	}
+      if (invalid)
+	continue;
+
+      /* The instruction is valid.  */
+      if (opcode->operands[0] != 0)
+	(*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
+      else
+	(*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+      /* Now extract and print the operands.  */
+      need_comma = 0;
+      need_paren = 0;
+      skip_optional = -1;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  long value;
+
+	  operand = powerpc_operands + *opindex;
+
+	  /* Operands that are marked FAKE are simply ignored.  We
+	     already made sure that the extract function considered
+	     the instruction to be valid.  */
+	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
+	    continue;
+
+	  /* If all of the optional operands have the value zero,
+	     then don't print any of them.  */
+	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
+	    {
+	      if (skip_optional < 0)
+		skip_optional = skip_optional_operands (opindex, insn,
+							dialect);
+	      if (skip_optional)
+		continue;
+	    }
+
+	  value = operand_value_powerpc (operand, insn, dialect);
+
+	  if (need_comma)
+	    {
+	      (*info->fprintf_func) (info->stream, ",");
+	      need_comma = 0;
+	    }
+
+	  /* Print the operand as directed by the flags.  */
+	  if ((operand->flags & PPC_OPERAND_GPR) != 0
+	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
+	    (*info->fprintf_func) (info->stream, "r%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+	    (*info->fprintf_func) (info->stream, "f%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
+	    (*info->fprintf_func) (info->stream, "v%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
+	    (*info->print_address_func) (memaddr + value, info);
+	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
+	  else if ((operand->flags & PPC_OPERAND_CR) == 0
+		   || (dialect & PPC_OPCODE_PPC) == 0)
+	    (*info->fprintf_func) (info->stream, "%ld", value);
+	  else
+	    {
+	      if (operand->bitm == 7)
+		(*info->fprintf_func) (info->stream, "cr%ld", value);
+	      else
+		{
+		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
+		  int cr;
+		  int cc;
+
+		  cr = value >> 2;
+		  if (cr != 0)
+		    (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
+		  cc = value & 3;
+		  (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
+		}
+	    }
+
+	  if (need_paren)
+	    {
+	      (*info->fprintf_func) (info->stream, ")");
+	      need_paren = 0;
+	    }
+
+	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
+	    need_comma = 1;
+	  else
+	    {
+	      (*info->fprintf_func) (info->stream, "(");
+	      need_paren = 1;
+	    }
+	}
+
+      /* We have found and printed an instruction; return.  */
+      return 4;
+    }
+
+  if ((dialect & PPC_OPCODE_ANY) != 0)
+    {
+      dialect = ~PPC_OPCODE_ANY;
+      goto again;
+    }
+
+  /* We could not find a match.  */
+  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
+
+  return 4;
+}
diff --git a/qemu-0.15.x/ppc.ld b/qemu-0.15.x/ppc.ld
new file mode 100644
index 0000000..69aa3f2
--- /dev/null
+++ b/qemu-0.15.x/ppc.ld
@@ -0,0 +1,225 @@
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj at atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp) 	}
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .gnu.version   : { *(.gnu.version)	}
+  .gnu.version_d   : { *(.gnu.version_d)	}
+  .gnu.version_r   : { *(.gnu.version_r)	}
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rela.got1           : { *(.rela.got1) }
+  .rela.got2           : { *(.rela.got2) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.glink)
+  } =0x47ff041f
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x47ff041f
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    PROVIDE (_SDA2_BASE_ = 32768);
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
+  /* Exception handling  */
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .got1           : { *(.got1) }
+  .got2           : { *(.got2) }
+  .dynamic        : { *(.dynamic) }
+  .got            : SPECIAL { *(.got) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .plt            : SPECIAL { *(.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .got            : SPECIAL { *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    PROVIDE (_SDA_BASE_ = 32768);
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .);
+  }
+  .plt            : SPECIAL { *(.plt) }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+  /DISCARD/    : { *(.fixup) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/qemu-0.15.x/ppc64.ld b/qemu-0.15.x/ppc64.ld
new file mode 100644
index 0000000..0059ee5
--- /dev/null
+++ b/qemu-0.15.x/ppc64.ld
@@ -0,0 +1,218 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc",
+	      "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_start)
+/* __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.dyn        :
+    {
+      *(.rel.init)
+      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+      *(.rel.fini)
+      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+      *(.rel.data.rel.ro*)
+      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+      *(.rel.ctors)
+      *(.rel.dtors)
+      *(.rel.got)
+      *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+      *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+      *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+      *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+    }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.toc)
+      *(.rela.opd)
+      *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+      *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+      *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+      *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .rela.tocbss	  : { *(.rela.tocbss) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x60000000
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.sfpr .glink)
+  } =0x60000000
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x60000000
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+*(.gcc_except_table.*) } /* Adjust the address for the data segment.  We want to
+adjust up to +     the same address within the page on the next page up.  */
+  . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN
+(0x10000, 0x1000);   /* Exception handling  */
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { KEEP (*(.gcc_except_table))
+*(.gcc_except_table.*) }   /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(64 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { KEEP (*(.preinit_array)) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { KEEP (*(.init_array)) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { KEEP (*(.fini_array)) }
+  PROVIDE (__fini_array_end = .);
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+  .dynamic        : { *(.dynamic) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .toc1		 ALIGN(8) : { *(.toc1) }
+  .opd		 ALIGN(8) : { KEEP (*(.opd)) }
+  .got		ALIGN(8) : { *(.got .toc) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .tocbss	 ALIGN(8) : { *(.tocbss)}
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .);
+    PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .);
+    PROVIDE (___sbss_end = .);
+  }
+  .plt            : { *(.plt) }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(64 / 8);
+  }
+  . = ALIGN(64 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/qemu-0.15.x/qapi-schema-guest.json b/qemu-0.15.x/qapi-schema-guest.json
new file mode 100644
index 0000000..fde5971
--- /dev/null
+++ b/qemu-0.15.x/qapi-schema-guest.json
@@ -0,0 +1,217 @@
+# *-*- Mode: Python -*-*
+
+##
+# @guest-sync:
+#
+# Echo back a unique integer value
+#
+# This is used by clients talking to the guest agent over the
+# wire to ensure the stream is in sync and doesn't contain stale
+# data from previous client. All guest agent responses should be
+# ignored until the provided unique integer value is returned,
+# and it is up to the client to handle stale whole or
+# partially-delivered JSON text in such a way that this response
+# can be obtained.
+#
+# Such clients should also preceed this command
+# with a 0xFF byte to make such the guest agent flushes any
+# partially read JSON data from a previous session.
+#
+# @id: randomly generated 64-bit integer
+#
+# Returns: The unique integer id passed in by the client
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-sync'
+  'data':    { 'id': 'int' },
+  'returns': 'int' }
+
+##
+# @guest-ping:
+#
+# Ping the guest agent, a non-error return implies success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-ping' }
+
+##
+# @guest-info:
+#
+# Get some information about the guest agent.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestAgentInfo', 'data': {'version': 'str'} }
+{ 'command': 'guest-info',
+  'returns': 'GuestAgentInfo' }
+
+##
+# @guest-shutdown:
+#
+# Initiate guest-activated shutdown. Note: this is an asynchronous
+# shutdown request, with no guaruntee of successful shutdown. Errors
+# will be logged to guest's syslog.
+#
+# @mode: #optional "halt", "powerdown" (default), or "reboot"
+#
+# Returns: Nothing on success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } }
+
+##
+# @guest-file-open:
+#
+# Open a file in the guest and retrieve a file handle for it
+#
+# @filepath: Full path to the file in the guest to open.
+#
+# @mode: #optional open mode, as per fopen(), "r" is the default.
+#
+# Returns: Guest file handle on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-open',
+  'data':    { 'path': 'str', '*mode': 'str' },
+  'returns': 'int' }
+
+##
+# @guest-file-close:
+#
+# Close an open file in the guest
+#
+# @handle: filehandle returned by guest-file-open
+#
+# Returns: Nothing on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-close',
+  'data': { 'handle': 'int' } }
+
+##
+# @guest-file-read:
+#
+# Read from an open file in the guest. Data will be base64-encoded
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @count: #optional maximum number of bytes to read (default is 4KB)
+#
+# Returns: GuestFileRead on success. Note: count is number of bytes read
+#          *before* base64 encoding bytes read.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileRead',
+  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
+
+{ 'command': 'guest-file-read',
+  'data':    { 'handle': 'int', '*count': 'int' },
+  'returns': 'GuestFileRead' }
+
+##
+# @guest-file-write:
+#
+# Write to an open file in the guest.
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @buf-b64: base64-encoded string representing data to be written
+#
+# @count: #optional bytes to write (actual bytes, after base64-decode),
+#         default is all content in buf-b64 buffer after base64 decoding
+#
+# Returns: GuestFileWrite on success. Note: count is the number of bytes
+#          base64-decoded bytes written
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileWrite',
+  'data': { 'count': 'int', 'eof': 'bool' } }
+{ 'command': 'guest-file-write',
+  'data':    { 'handle': 'int', 'buf-b64': 'str', '*count': 'int' },
+  'returns': 'GuestFileWrite' }
+
+##
+# @guest-file-seek:
+#
+# Seek to a position in the file, as with fseek(), and return the
+# current file position afterward. Also encapsulates ftell()'s
+# functionality, just Set offset=0, whence=SEEK_CUR.
+#
+# @handle: filehandle returned by guest-file-open
+#
+# @offset: bytes to skip over in the file stream
+#
+# @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
+#
+# Returns: GuestFileSeek on success.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileSeek',
+  'data': { 'position': 'int', 'eof': 'bool' } }
+
+{ 'command': 'guest-file-seek',
+  'data':    { 'handle': 'int', 'offset': 'int', 'whence': 'int' },
+  'returns': 'GuestFileSeek' }
+
+##
+# @guest-file-flush:
+#
+# Write file changes bufferred in userspace to disk/kernel buffers
+#
+# @handle: filehandle returned by guest-file-open
+#
+# Returns: Nothing on success.
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-file-flush',
+  'data': { 'handle': 'int' } }
+
+##
+# @guest-fsfreeze-status:
+#
+# Get guest fsfreeze state. error state indicates failure to thaw 1 or more
+# previously frozen filesystems, or failure to open a previously cached
+# filesytem (filesystem unmounted/directory changes, etc).
+#
+# Returns: GuestFsfreezeStatus ("thawed", "frozen", etc., as defined below)
+#
+# Since: 0.15.0
+##
+{ 'enum': 'GuestFsfreezeStatus',
+  'data': [ 'thawed', 'frozen', 'error' ] }
+{ 'command': 'guest-fsfreeze-status',
+  'returns': 'GuestFsfreezeStatus' }
+
+##
+# @guest-fsfreeze-freeze:
+#
+# Sync and freeze all non-network guest filesystems
+#
+# Returns: Number of file systems frozen on success
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-fsfreeze-freeze',
+  'returns': 'int' }
+
+##
+# @guest-fsfreeze-thaw:
+#
+# Unfreeze frozen guest fileystems
+#
+# Returns: Number of file systems thawed
+#          If error, -1 (unknown error) or -errno
+#
+# Since: 0.15.0
+##
+{ 'command': 'guest-fsfreeze-thaw',
+  'returns': 'int' }
diff --git a/qemu-0.15.x/qapi-schema-test.json b/qemu-0.15.x/qapi-schema-test.json
new file mode 100644
index 0000000..3acedad
--- /dev/null
+++ b/qemu-0.15.x/qapi-schema-test.json
@@ -0,0 +1,22 @@
+# *-*- Mode: Python -*-*
+
+# for testing enums
+{ 'enum': 'EnumOne',
+  'data': [ 'value1', 'value2', 'value3' ] }
+{ 'type': 'NestedEnumsOne',
+  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# for testing nested structs
+{ 'type': 'UserDefOne',
+  'data': { 'integer': 'int', 'string': 'str' } }
+
+{ 'type': 'UserDefTwo',
+  'data': { 'string': 'str',
+            'dict': { 'string': 'str',
+                      'dict': { 'userdef': 'UserDefOne', 'string': 'str' },
+                      '*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' }
diff --git a/qemu-0.15.x/qapi/qapi-dealloc-visitor.c b/qemu-0.15.x/qapi/qapi-dealloc-visitor.c
new file mode 100644
index 0000000..8cde4dd
--- /dev/null
+++ b/qemu-0.15.x/qapi/qapi-dealloc-visitor.c
@@ -0,0 +1,147 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi-dealloc-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+    void *value;
+    QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisitor
+{
+    Visitor visitor;
+    QTAILQ_HEAD(, StackEntry) stack;
+};
+
+static QapiDeallocVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QapiDeallocVisitor, visitor);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
+{
+    StackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
+{
+    StackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    qemu_free(e);
+    return value;
+}
+
+static void qapi_dealloc_start_struct(Visitor *v, void **obj, const char *kind,
+                                      const char *name, size_t unused,
+                                      Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    void **obj = qapi_dealloc_pop(qov);
+    if (obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
+{
+}
+
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list,
+                                           Error **errp)
+{
+    GenericList *retval = *list;
+    qemu_free(retval->value);
+    *list = retval->next;
+    return retval;
+}
+
+static void qapi_dealloc_end_list(Visitor *v, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name,
+                                  Error **errp)
+{
+    if (obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name,
+                                  Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visitor *v, bool *obj, const char *name,
+                                   Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name,
+                                     Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[],
+                                   const char *kind, const char *name,
+                                   Error **errp)
+{
+}
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
+{
+    qemu_free(v);
+}
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
+{
+    QapiDeallocVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qapi_dealloc_start_struct;
+    v->visitor.end_struct = qapi_dealloc_end_struct;
+    v->visitor.start_list = qapi_dealloc_start_list;
+    v->visitor.next_list = qapi_dealloc_next_list;
+    v->visitor.end_list = qapi_dealloc_end_list;
+    v->visitor.type_enum = qapi_dealloc_type_enum;
+    v->visitor.type_int = qapi_dealloc_type_int;
+    v->visitor.type_bool = qapi_dealloc_type_bool;
+    v->visitor.type_str = qapi_dealloc_type_str;
+    v->visitor.type_number = qapi_dealloc_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qemu-0.15.x/qapi/qapi-dealloc-visitor.h b/qemu-0.15.x/qapi/qapi-dealloc-visitor.h
new file mode 100644
index 0000000..5842bc7
--- /dev/null
+++ b/qemu-0.15.x/qapi/qapi-dealloc-visitor.h
@@ -0,0 +1,26 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_DEALLOC_VISITOR_H
+#define QAPI_DEALLOC_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisitor QapiDeallocVisitor;
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
+
+#endif
diff --git a/qemu-0.15.x/qapi/qapi-types-core.h b/qemu-0.15.x/qapi/qapi-types-core.h
new file mode 100644
index 0000000..a79bc2b
--- /dev/null
+++ b/qemu-0.15.x/qapi/qapi-types-core.h
@@ -0,0 +1,20 @@
+/*
+ * Core Definitions for QAPI-generated Types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_TYPES_CORE_H
+#define QAPI_TYPES_CORE_H
+
+#include "qemu-common.h"
+#include "error.h"
+
+#endif
diff --git a/qemu-0.15.x/qapi/qapi-visit-core.c b/qemu-0.15.x/qapi/qapi-visit-core.c
new file mode 100644
index 0000000..ddef3ed
--- /dev/null
+++ b/qemu-0.15.x/qapi/qapi-visit-core.c
@@ -0,0 +1,118 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-visit-core.h"
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind,
+                        const char *name, Error **errp)
+{
+    if (!error_is_set(errp) && v->start_handle) {
+        v->start_handle(v, obj, kind, name, errp);
+    }
+}
+
+void visit_end_handle(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_handle) {
+        v->end_handle(v, errp);
+    }
+}
+
+void visit_start_struct(Visitor *v, void **obj, const char *kind,
+                        const char *name, size_t size, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_struct(v, obj, kind, name, size, errp);
+    }
+}
+
+void visit_end_struct(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_struct(v, errp);
+    }
+}
+
+void visit_start_list(Visitor *v, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_list(v, name, errp);
+    }
+}
+
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        return v->next_list(v, list, errp);
+    }
+
+    return 0;
+}
+
+void visit_end_list(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_list(v, errp);
+    }
+}
+
+void visit_start_optional(Visitor *v, bool *present, const char *name,
+                          Error **errp)
+{
+    if (!error_is_set(errp) && v->start_optional) {
+        v->start_optional(v, present, name, errp);
+    }
+}
+
+void visit_end_optional(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_optional) {
+        v->end_optional(v, errp);
+    }
+}
+
+void visit_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_enum(v, obj, strings, kind, name, errp);
+    }
+}
+
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_int(v, obj, name, errp);
+    }
+}
+
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_bool(v, obj, name, errp);
+    }
+}
+
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_str(v, obj, name, errp);
+    }
+}
+
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_number(v, obj, name, errp);
+    }
+}
diff --git a/qemu-0.15.x/qapi/qapi-visit-core.h b/qemu-0.15.x/qapi/qapi-visit-core.h
new file mode 100644
index 0000000..e850746
--- /dev/null
+++ b/qemu-0.15.x/qapi/qapi-visit-core.h
@@ -0,0 +1,76 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QAPI_VISITOR_CORE_H
+#define QAPI_VISITOR_CORE_H
+
+#include "qapi/qapi-types-core.h"
+#include <stdlib.h>
+
+typedef struct GenericList
+{
+    void *value;
+    struct GenericList *next;
+} GenericList;
+
+typedef struct Visitor Visitor;
+
+struct Visitor
+{
+    /* Must be set */
+    void (*start_struct)(Visitor *v, void **obj, const char *kind,
+                         const char *name, size_t size, Error **errp);
+    void (*end_struct)(Visitor *v, Error **errp);
+
+    void (*start_list)(Visitor *v, const char *name, Error **errp);
+    GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
+    void (*end_list)(Visitor *v, Error **errp);
+
+    void (*type_enum)(Visitor *v, int *obj, const char *strings[],
+                      const char *kind, const char *name, Error **errp);
+
+    void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
+    void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
+    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
+    void (*type_number)(Visitor *v, double *obj, const char *name,
+                        Error **errp);
+
+    /* May be NULL */
+    void (*start_optional)(Visitor *v, bool *present, const char *name,
+                           Error **errp);
+    void (*end_optional)(Visitor *v, Error **errp);
+
+    void (*start_handle)(Visitor *v, void **obj, const char *kind,
+                         const char *name, Error **errp);
+    void (*end_handle)(Visitor *v, Error **errp);
+};
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind,
+                        const char *name, Error **errp);
+void visit_end_handle(Visitor *v, Error **errp);
+void visit_start_struct(Visitor *v, void **obj, const char *kind,
+                        const char *name, size_t size, Error **errp);
+void visit_end_struct(Visitor *v, Error **errp);
+void visit_start_list(Visitor *v, const char *name, Error **errp);
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
+void visit_end_list(Visitor *v, Error **errp);
+void visit_start_optional(Visitor *v, bool *present, const char *name,
+                          Error **errp);
+void visit_end_optional(Visitor *v, Error **errp);
+void visit_type_enum(Visitor *v, int *obj, const char *strings[],
+                     const char *kind, const char *name, Error **errp);
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+
+#endif
diff --git a/qemu-0.15.x/qapi/qmp-core.h b/qemu-0.15.x/qapi/qmp-core.h
new file mode 100644
index 0000000..f1c26e4
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-core.h
@@ -0,0 +1,41 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_CORE_H
+#define QMP_CORE_H
+
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+
+typedef enum QmpCommandType
+{
+    QCT_NORMAL,
+} QmpCommandType;
+
+typedef struct QmpCommand
+{
+    const char *name;
+    QmpCommandType type;
+    QmpCommandFunc *fn;
+    QTAILQ_ENTRY(QmpCommand) node;
+} QmpCommand;
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn);
+QmpCommand *qmp_find_command(const char *name);
+QObject *qmp_dispatch(QObject *request);
+
+#endif
+
diff --git a/qemu-0.15.x/qapi/qmp-dispatch.c b/qemu-0.15.x/qapi/qmp-dispatch.c
new file mode 100644
index 0000000..5584693
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-dispatch.c
@@ -0,0 +1,124 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+#include "error.h"
+#include "error_int.h"
+#include "qerror.h"
+
+static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
+{
+    const QDictEntry *ent;
+    const char *arg_name;
+    const QObject *arg_obj;
+    bool has_exec_key = false;
+    QDict *dict = NULL;
+
+    if (qobject_type(request) != QTYPE_QDICT) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT,
+                  "request is not a dictionary");
+        return NULL;
+    }
+
+    dict = qobject_to_qdict(request);
+
+    for (ent = qdict_first(dict); ent;
+         ent = qdict_next(dict, ent)) {
+        arg_name = qdict_entry_key(ent);
+        arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                error_set(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
+                          "string");
+                return NULL;
+            }
+            has_exec_key = true;
+        } else if (strcmp(arg_name, "arguments")) {
+            error_set(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    return dict;
+}
+
+static QObject *do_qmp_dispatch(QObject *request, Error **errp)
+{
+    const char *command;
+    QDict *args, *dict;
+    QmpCommand *cmd;
+    QObject *ret = NULL;
+
+
+    dict = qmp_dispatch_check_obj(request, errp);
+    if (!dict || error_is_set(errp)) {
+        return NULL;
+    }
+
+    command = qdict_get_str(dict, "execute");
+    cmd = qmp_find_command(command);
+    if (cmd == NULL) {
+        error_set(errp, QERR_COMMAND_NOT_FOUND, command);
+        return NULL;
+    }
+
+    if (!qdict_haskey(dict, "arguments")) {
+        args = qdict_new();
+    } else {
+        args = qdict_get_qdict(dict, "arguments");
+        QINCREF(args);
+    }
+
+    switch (cmd->type) {
+    case QCT_NORMAL:
+        cmd->fn(args, &ret, errp);
+        if (!error_is_set(errp) && ret == NULL) {
+            ret = QOBJECT(qdict_new());
+        }
+        break;
+    }
+
+    QDECREF(args);
+
+    return ret;
+}
+
+QObject *qmp_dispatch(QObject *request)
+{
+    Error *err = NULL;
+    QObject *ret;
+    QDict *rsp;
+
+    ret = do_qmp_dispatch(request, &err);
+
+    rsp = qdict_new();
+    if (err) {
+        qdict_put_obj(rsp, "error", error_get_qobject(err));
+        error_free(err);
+    } else if (ret) {
+        qdict_put_obj(rsp, "return", ret);
+    } else {
+        QDECREF(rsp);
+        return NULL;
+    }
+
+    return QOBJECT(rsp);
+}
diff --git a/qemu-0.15.x/qapi/qmp-input-visitor.c b/qemu-0.15.x/qapi/qmp-input-visitor.c
new file mode 100644
index 0000000..6a1adc9
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-input-visitor.c
@@ -0,0 +1,301 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-input-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+    const QObject *obj;
+    const  QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisitor
+{
+    Visitor visitor;
+    QObject *obj;
+    StackObject stack[QIV_STACK_SIZE];
+    int nb_stack;
+};
+
+static QmpInputVisitor *to_qiv(Visitor *v)
+{
+    return container_of(v, QmpInputVisitor, visitor);
+}
+
+static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
+                                           const char *name)
+{
+    const QObject *qobj;
+
+    if (qiv->nb_stack == 0) {
+        qobj = qiv->obj;
+    } else {
+        qobj = qiv->stack[qiv->nb_stack - 1].obj;
+    }
+
+    if (name && qobject_type(qobj) == QTYPE_QDICT) {
+        return qdict_get(qobject_to_qdict(qobj), name);
+    } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
+    }
+
+    return qobj;
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+{
+    qiv->stack[qiv->nb_stack].obj = obj;
+    if (qobject_type(obj) == QTYPE_QLIST) {
+        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
+    }
+    qiv->nb_stack++;
+
+    if (qiv->nb_stack >= QIV_STACK_SIZE) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
+{
+    qiv->nb_stack--;
+    if (qiv->nb_stack < 0) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
+                                   const char *name, size_t size, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "QDict");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (obj) {
+        *obj = qemu_mallocz(size);
+    }
+}
+
+static void qmp_input_end_struct(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "list");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+}
+
+static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
+                                        Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    GenericList *entry;
+    StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+
+    if (so->entry == NULL) {
+        return NULL;
+    }
+
+    entry = qemu_mallocz(sizeof(*entry));
+    if (*list) {
+        so->entry = qlist_next(so->entry);
+        if (so->entry == NULL) {
+            qemu_free(entry);
+            return NULL;
+        }
+        (*list)->next = entry;
+    }
+    *list = entry;
+
+
+    return entry;
+}
+
+static void qmp_input_end_list(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
+                               Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "integer");
+        return;
+    }
+
+    *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
+                                Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "boolean");
+        return;
+    }
+
+    *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
+                               Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "string");
+        return;
+    }
+
+    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
+                                  Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+                  "double");
+        return;
+    }
+
+    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
+                                const char *kind, const char *name,
+                                Error **errp)
+{
+    int64_t value = 0;
+    char *enum_str;
+
+    assert(strings);
+
+    qmp_input_type_str(v, &enum_str, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    while (strings[value] != NULL) {
+        if (strcmp(strings[value], enum_str) == 0) {
+            break;
+        }
+        value++;
+    }
+
+    if (strings[value] == NULL) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        return;
+    }
+
+    *obj = value;
+}
+
+static void qmp_input_start_optional(Visitor *v, bool *present,
+                                     const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj) {
+        *present = false;
+        return;
+    }
+
+    *present = true;
+}
+
+static void qmp_input_end_optional(Visitor *v, Error **errp)
+{
+}
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_input_visitor_cleanup(QmpInputVisitor *v)
+{
+    qobject_decref(v->obj);
+    qemu_free(v);
+}
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
+{
+    QmpInputVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qmp_input_start_struct;
+    v->visitor.end_struct = qmp_input_end_struct;
+    v->visitor.start_list = qmp_input_start_list;
+    v->visitor.next_list = qmp_input_next_list;
+    v->visitor.end_list = qmp_input_end_list;
+    v->visitor.type_enum = qmp_input_type_enum;
+    v->visitor.type_int = qmp_input_type_int;
+    v->visitor.type_bool = qmp_input_type_bool;
+    v->visitor.type_str = qmp_input_type_str;
+    v->visitor.type_number = qmp_input_type_number;
+    v->visitor.start_optional = qmp_input_start_optional;
+    v->visitor.end_optional = qmp_input_end_optional;
+
+    v->obj = obj;
+    qobject_incref(v->obj);
+
+    return v;
+}
diff --git a/qemu-0.15.x/qapi/qmp-input-visitor.h b/qemu-0.15.x/qapi/qmp-input-visitor.h
new file mode 100644
index 0000000..3f798f0
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-input-visitor.h
@@ -0,0 +1,27 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_INPUT_VISITOR_H
+#define QMP_INPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisitor QmpInputVisitor;
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
+void qmp_input_visitor_cleanup(QmpInputVisitor *v);
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
+
+#endif
diff --git a/qemu-0.15.x/qapi/qmp-output-visitor.c b/qemu-0.15.x/qapi/qmp-output-visitor.c
new file mode 100644
index 0000000..c398cac
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-output-visitor.c
@@ -0,0 +1,239 @@
+/*
+ * Core Definitions for QAPI/QMP Command Registry
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-output-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+typedef struct QStackEntry
+{
+    QObject *value;
+    QTAILQ_ENTRY(QStackEntry) node;
+} QStackEntry;
+
+typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
+
+struct QmpOutputVisitor
+{
+    Visitor visitor;
+    QStack stack;
+};
+
+#define qmp_output_add(qov, name, value) \
+    qmp_output_add_obj(qov, name, QOBJECT(value))
+#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
+
+static QmpOutputVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QmpOutputVisitor, visitor);
+}
+
+static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
+{
+    QStackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    qemu_free(e);
+    return value;
+}
+
+static QObject *qmp_output_first(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+    return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
+                               QObject *value)
+{
+    QObject *cur;
+
+    if (QTAILQ_EMPTY(&qov->stack)) {
+        qmp_output_push_obj(qov, value);
+        return;
+    }
+
+    cur = qmp_output_last(qov);
+
+    switch (qobject_type(cur)) {
+    case QTYPE_QDICT:
+        qdict_put_obj(qobject_to_qdict(cur), name, value);
+        break;
+    case QTYPE_QLIST:
+        qlist_append_obj(qobject_to_qlist(cur), value);
+        break;
+    default:
+        qobject_decref(qmp_output_pop(qov));
+        qmp_output_push_obj(qov, value);
+        break;
+    }
+}
+
+static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
+                                    const char *name, size_t unused,
+                                    Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QDict *dict = qdict_new();
+
+    qmp_output_add(qov, name, dict);
+    qmp_output_push(qov, dict);
+}
+
+static void qmp_output_end_struct(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QList *list = qlist_new();
+
+    qmp_output_add(qov, name, list);
+    qmp_output_push(qov, list);
+}
+
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **list,
+                                         Error **errp)
+{
+    GenericList *retval = *list;
+    *list = retval->next;
+    return retval;
+}
+
+static void qmp_output_end_list(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
+                                Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
+                                 Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
+                                Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    if (*obj) {
+        qmp_output_add(qov, name, qstring_from_str(*obj));
+    } else {
+        qmp_output_add(qov, name, qstring_from_str(""));
+    }
+}
+
+static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
+                                   Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[],
+                                 const char *kind, const char *name,
+                                 Error **errp)
+{
+    int i = 0;
+    int value = *obj;
+    char *enum_str;
+
+    assert(strings);
+    while (strings[i++] != NULL);
+    if (value >= i - 1) {
+        error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        return;
+    }
+
+    enum_str = (char *)strings[value];
+    qmp_output_type_str(v, &enum_str, name, errp);
+}
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
+{
+    QObject *obj = qmp_output_first(qov);
+    if (obj) {
+        qobject_incref(obj);
+    }
+    return obj;
+}
+
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
+{
+    QStackEntry *e, *tmp;
+
+    QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
+        QTAILQ_REMOVE(&v->stack, e, node);
+        if (e->value) {
+            qobject_decref(e->value);
+        }
+        qemu_free(e);
+    }
+
+    qemu_free(v);
+}
+
+QmpOutputVisitor *qmp_output_visitor_new(void)
+{
+    QmpOutputVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qmp_output_start_struct;
+    v->visitor.end_struct = qmp_output_end_struct;
+    v->visitor.start_list = qmp_output_start_list;
+    v->visitor.next_list = qmp_output_next_list;
+    v->visitor.end_list = qmp_output_end_list;
+    v->visitor.type_enum = qmp_output_type_enum;
+    v->visitor.type_int = qmp_output_type_int;
+    v->visitor.type_bool = qmp_output_type_bool;
+    v->visitor.type_str = qmp_output_type_str;
+    v->visitor.type_number = qmp_output_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qemu-0.15.x/qapi/qmp-output-visitor.h b/qemu-0.15.x/qapi/qmp-output-visitor.h
new file mode 100644
index 0000000..4a649c2
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-output-visitor.h
@@ -0,0 +1,28 @@
+/*
+ * Output Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_OUTPUT_VISITOR_H
+#define QMP_OUTPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisitor QmpOutputVisitor;
+
+QmpOutputVisitor *qmp_output_visitor_new(void);
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
+
+#endif
diff --git a/qemu-0.15.x/qapi/qmp-registry.c b/qemu-0.15.x/qapi/qmp-registry.c
new file mode 100644
index 0000000..3fe8866
--- /dev/null
+++ b/qemu-0.15.x/qapi/qmp-registry.c
@@ -0,0 +1,40 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Michael Roth      <mdroth at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qmp-core.h"
+
+static QTAILQ_HEAD(, QmpCommand) qmp_commands =
+    QTAILQ_HEAD_INITIALIZER(qmp_commands);
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn)
+{
+    QmpCommand *cmd = qemu_mallocz(sizeof(*cmd));
+
+    cmd->name = name;
+    cmd->type = QCT_NORMAL;
+    cmd->fn = fn;
+    QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
+}
+
+QmpCommand *qmp_find_command(const char *name)
+{
+    QmpCommand *i;
+
+    QTAILQ_FOREACH(i, &qmp_commands, node) {
+        if (strcmp(i->name, name) == 0) {
+            return i;
+        }
+    }
+    return NULL;
+}
diff --git a/qemu-0.15.x/qbool.c b/qemu-0.15.x/qbool.c
new file mode 100644
index 0000000..ad4873f
--- /dev/null
+++ b/qemu-0.15.x/qbool.c
@@ -0,0 +1,68 @@
+/*
+ * QBool Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qbool.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static void qbool_destroy_obj(QObject *obj);
+
+static const QType qbool_type = {
+    .code = QTYPE_QBOOL,
+    .destroy = qbool_destroy_obj,
+};
+
+/**
+ * qbool_from_int(): Create a new QBool from an int
+ *
+ * Return strong reference.
+ */
+QBool *qbool_from_int(int value)
+{
+    QBool *qb;
+
+    qb = qemu_malloc(sizeof(*qb));
+    qb->value = value;
+    QOBJECT_INIT(qb, &qbool_type);
+
+    return qb;
+}
+
+/**
+ * qbool_get_int(): Get the stored int
+ */
+int qbool_get_int(const QBool *qb)
+{
+    return qb->value;
+}
+
+/**
+ * qobject_to_qbool(): Convert a QObject into a QBool
+ */
+QBool *qobject_to_qbool(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QBOOL)
+        return NULL;
+
+    return container_of(obj, QBool, base);
+}
+
+/**
+ * qbool_destroy_obj(): Free all memory allocated by a
+ * QBool object
+ */
+static void qbool_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    qemu_free(qobject_to_qbool(obj));
+}
diff --git a/qemu-0.15.x/qbool.h b/qemu-0.15.x/qbool.h
new file mode 100644
index 0000000..fe66fcd
--- /dev/null
+++ b/qemu-0.15.x/qbool.h
@@ -0,0 +1,29 @@
+/*
+ * QBool Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QBOOL_H
+#define QBOOL_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QBool {
+    QObject_HEAD;
+    int value;
+} QBool;
+
+QBool *qbool_from_int(int value);
+int qbool_get_int(const QBool *qb);
+QBool *qobject_to_qbool(const QObject *obj);
+
+#endif /* QBOOL_H */
diff --git a/qemu-0.15.x/qdict-test-data.txt b/qemu-0.15.x/qdict-test-data.txt
new file mode 100644
index 0000000..122fda4
--- /dev/null
+++ b/qemu-0.15.x/qdict-test-data.txt
@@ -0,0 +1,4999 @@
+00-INDEX: 333
+07: 4096
+1040.bin.ihex: 92633
+11d.c: 17874
+11d.h: 2386
+1200.bin.ihex: 14717
+12160.bin.ihex: 77829
+1232ea962bbaf0e909365f4964f6cceb2ba8ce: 298
+1280.bin.ihex: 88220
+15562512ca6cf14c1b8f08e09d5907118deaf0: 297
+17: 4096
+1d: 4096
+1.Intro: 14968
+21142.c: 8591
+21285.c: 11721
+2860_main_dev.c: 33854
+2860_rtmp_init.c: 26170
+2870_main_dev.c: 39352
+2870_rtmp_init.c: 51247
+2.Process: 22356
+300vtbl.h: 43771
+310vtbl.h: 59655
+3270.ChangeLog: 1889
+3270.txt: 10964
+3550.bin.ihex: 13916
+3780i.c: 21485
+3780i.h: 14180
+38C0800.bin.ihex: 14772
+38C1600.bin.ihex: 17504
+3C359.bin.ihex: 69044
+3c359.c: 60161
+3c359.h: 7264
+3c359.txt: 2463
+3c501.c: 23869
+3c501.h: 2623
+3c503.c: 22491
+3c503.h: 3880
+3c505.c: 48605
+3c505.h: 6535
+3c505.txt: 1831
+3c507.c: 28758
+3c509.c: 42879
+3c509.txt: 9006
+3c515.c: 49671
+3c523.c: 39251
+3c523.h: 11169
+3c527.c: 43065
+3c527.h: 1482
+3c574_cs.c: 35859
+3c589_cs.c: 30110
+3c59x.c: 103272
+3CCFEM556.cis.ihex: 469
+3com: 4096
+3CXEM556.cis.ihex: 463
+3.Early-stage: 9993
+3w-9xxx.c: 77318
+3w-9xxx.h: 26357
+3w-xxxx.c: 85227
+3w-xxxx.h: 16846
+40x: 4096
+40x_mmu.c: 4082
+42: 4096
+44x: 4096
+44x.c: 3615
+44x_emulate.c: 4512
+44x.h: 448
+44x_mmu.c: 2966
+44x_tlb.c: 13997
+44x_tlb.h: 2465
+4.Coding: 20212
+4level-fixup.h: 1028
+4xx: 4096
+4xx.c: 16297
+4xx.h: 1174
+512x: 4096
+5206: 4096
+5206e: 4096
+520x: 4096
+523x: 4096
+5249: 4096
+5272: 4096
+527x: 4096
+528x: 4096
+52xx: 4096
+5307: 4096
+532x: 4096
+53c700.c: 71188
+53c700_d.h_shipped: 28887
+53c700.h: 16652
+53c700.scr: 10894
+53c700.txt: 5042
+5407: 4096
+57xx_iscsi_constants.h: 7004
+57xx_iscsi_hsi.h: 36895
+5d: 4096
+5.Posting: 15211
+66b00c9dc3e1e071bde0ebfeadc40bbc1e8316: 298
+68328: 4096
+68328fb.c: 13570
+68328serial.c: 35841
+68328serial.h: 6237
+68360: 4096
+68360serial.c: 76262
+68EZ328: 4096
+68VZ328: 4096
+6c5e45fe4f1c83df9429b7c2668b41446baac2: 297
+6.Followthrough: 11745
+6pack.c: 24715
+6pack.txt: 7940
+6xx-suspend.S: 1086
+712_defconfig: 25531
+7206: 4096
+73: 4096
+7343: 4096
+770x: 4096
+7721: 4096
+7722: 4096
+7724: 4096
+7751: 4096
+7780: 4096
+7990.c: 22036
+7990.h: 10421
+7.AdvancedTopics: 9648
+7c: 4096
+7segled.c: 2698
+802: 4096
+80211core: 4096
+80211hdr.h: 12326
+80211mgr.c: 28179
+80211mgr.h: 23006
+8021q: 4096
+8139cp.c: 56138
+8139too.c: 71384
+8250_accent.c: 1071
+8250_acorn.c: 3194
+8250_boca.c: 1301
+8250.c: 83003
+8250_early.c: 6636
+8250_exar_st16c554.c: 1191
+8250_fourport.c: 1216
+8250_gsc.c: 3620
+8250.h: 2432
+8250_hp300.c: 7797
+8250_hub6.c: 1224
+8250_mca.c: 1375
+8250_pci.c: 93521
+8250_pci.h: 999
+8250-platform.c: 1091
+8250_pnp.c: 14783
+8253.h: 10999
+8253pit.h: 48
+8255.c: 10692
+8255.h: 1805
+82571.c: 48377
+82596.c: 41209
+82xx: 4096
+8390.c: 2094
+8390.h: 9629
+8390p.c: 2248
+83xx: 4096
+83xx-512x-pci.txt: 1323
+85xx: 4096
+86xx: 4096
+87: 4096
+8b: 4096
+8.Conclusion: 3137
+8xx: 4096
+8xx_immap.h: 14089
+8xxx_gpio.txt: 1343
+941a7798a5169ee0dd69a9e8d5c40ceb702023: 298
+9600.bin.ihex: 14715
+9p: 4096
+9p.h: 13443
+9p.txt: 5113
+a100u2w.c: 36919
+a100u2w.h: 16936
+a2065.c: 20730
+a2065.h: 5135
+a2091.c: 6445
+a2091.h: 1712
+a20.c: 3548
+a20r.c: 5261
+a3000.c: 6528
+a3000.h: 1807
+a3d.c: 11335
+a4000t.c: 3579
+a500_defconfig: 31440
+a800.c: 5950
+aachba.c: 84424
+aaci.c: 27297
+aaci.h: 7022
+aacraid: 4096
+aacraid.h: 53671
+aacraid.txt: 6849
+aaec2000.h: 8936
+aaed2000.c: 2298
+aaed2000.h: 1354
+aaed2000_kbd.c: 5059
+aarp.c: 25379
+ab3100-core.c: 22600
+ab3100.h: 3510
+abdac.c: 15469
+ABI: 4096
+abi.h: 782
+abituguru: 3731
+abituguru3: 2493
+abituguru3.c: 41974
+abituguru.c: 53440
+abituguru-datasheet: 12294
+abi.txt: 1413
+ABI.txt: 1413
+ablkcipher.c: 9484
+abort-ev4.S: 882
+abort-ev4t.S: 913
+abort-ev5tj.S: 987
+abort-ev5t.S: 912
+abort-ev6.S: 1320
+abort-ev7.S: 774
+abort-lv4t.S: 6546
+abort-macro.S: 1144
+abort-nommu.S: 462
+abs_addr.h: 1800
+abspath.c: 2808
+abs.S: 238
+abyss.c: 11197
+abyss.h: 1550
+ac3200.c: 11838
+ac97: 4096
+ac97_bus.c: 1681
+ac97.c: 4489
+ac97c.c: 26095
+ac97c.h: 2045
+ac97_codec.c: 36925
+ac97_codec.h: 15115
+ac97.h: 507
+ac97_id.h: 2422
+ac97_local.h: 1689
+ac97_patch.c: 128568
+ac97_patch.h: 4386
+ac97_pcm.c: 21244
+ac97_proc.c: 18243
+acadia_defconfig: 23272
+acadia.dts: 5188
+ac.c: 9202
+accel.c: 8625
+accel.h: 5627
+access.c: 10521
+accessibility: 4096
+access_ok.h: 1305
+accommon.h: 2825
+acconfig.h: 7688
+accounting: 4096
+acct.c: 17700
+acct.h: 5949
+acdebug.h: 6836
+acdispat.h: 10988
+acecad.c: 7982
+acenic: 4096
+acenic.c: 88166
+acenic.h: 16029
+acenv.h: 11821
+acerhdf.c: 14909
+acer-wmi.c: 30530
+acer-wmi.txt: 6480
+acevents.h: 6692
+acexcep.h: 12764
+acgcc.h: 2843
+acglobal.h: 14485
+achware.h: 4355
+acinterp.h: 16329
+ackvec.c: 12985
+ackvec.h: 3426
+acl7225b.c: 3794
+acl.c: 5321
+acl.h: 1548
+aclinux.h: 5049
+aclocal.h: 34614
+acmacros.h: 22966
+acm.txt: 4974
+acnames.h: 3482
+acnamesp.h: 10211
+acobject.h: 16573
+acopcode.h: 22365
+acorn.c: 12206
+acornfb.c: 35783
+acornfb.h: 4809
+acorn.h: 623
+acornscsi.c: 87770
+acornscsi.h: 9694
+acornscsi-io.S: 3320
+acoutput.h: 10925
+acparser.h: 7436
+acpi: 4096
+acpi_bus.h: 11195
+acpi.c: 6529
+acpica: 12288
+acpi-cpufreq.c: 21588
+acpi_drivers.h: 5322
+acpi-ext.c: 2774
+acpi-ext.h: 590
+acpi.h: 4768
+acpi_memhotplug.c: 14832
+acpi_numa.h: 471
+acpiosxf.h: 7880
+acpi_pcihp.c: 14898
+acpiphp_core.c: 10949
+acpiphp_glue.c: 44065
+acpiphp.h: 6325
+acpiphp_ibm.c: 14740
+acpi_pm.c: 6723
+acpi_pmtmr.h: 672
+acpi-processor.c: 1893
+acpixf.h: 12045
+acpredef.h: 18909
+acquirewdt.c: 8920
+acresrc.h: 11064
+acrestyp.h: 11267
+acs5k_defconfig: 28786
+acs5k_tiny_defconfig: 21413
+acstruct.h: 7738
+act2000: 4096
+act2000.h: 6271
+act2000_isa.c: 11978
+act2000_isa.h: 7615
+act200l-sir.c: 7142
+actables.h: 3945
+act_api.c: 23712
+act_api.h: 4195
+actbl1.h: 35761
+actbl.h: 15492
+act_gact.c: 5493
+action.c: 40
+action.h: 40
+act_ipt.c: 7564
+actisys-sir.c: 7692
+active_mm.txt: 3805
+act_mirred.c: 6285
+act_nat.c: 7265
+act_pedit.c: 6148
+act_police.c: 9833
+act_simple.c: 5238
+act_skbedit.c: 5510
+actypes.h: 34263
+acutils.h: 16898
+acx.c: 16590
+acx.h: 33552
+ad1816a: 4096
+ad1816a.c: 8825
+ad1816a.h: 5363
+ad1816a_lib.c: 30656
+ad1843.c: 16402
+ad1843.h: 1516
+ad1848: 4096
+ad1848.c: 75959
+ad1848.h: 982
+ad1848_mixer.h: 10957
+ad1889.c: 27048
+ad1889.h: 8073
+ad1980.c: 8427
+ad1980.h: 468
+ad73311.c: 2765
+ad73311.h: 2404
+ad7414.c: 7164
+ad7418.c: 8304
+ad7877.c: 20856
+ad7877.h: 796
+ad7879.c: 19019
+ad7879.h: 1004
+adaptec: 4096
+adapter.h: 400
+adb.c: 19706
+adb.h: 2770
+adbhid.c: 35627
+adb-iop.c: 6325
+adb_iop.h: 1081
+adc.c: 8573
+adc.h: 886
+ADC-LH7-Touchscreen: 2187
+adcxx.c: 8256
+adder875.c: 3142
+adder875_defconfig: 21956
+adder875-redboot.dts: 4102
+adder875-uboot.dts: 4072
+addi_amcc_S5920.c: 7563
+addi_amcc_S5920.h: 1016
+addi_amcc_s5933.h: 13296
+addi_apci_035.c: 128
+addi_apci_1032.c: 63
+addi_apci_1500.c: 63
+addi_apci_1516.c: 63
+addi_apci_1564.c: 63
+addi_apci_16xx.c: 63
+addi_apci_1710.c: 63
+addi_apci_2016.c: 63
+addi_apci_2032.c: 63
+addi_apci_2200.c: 63
+addi_apci_3001.c: 63
+addi_apci_3120.c: 63
+addi_apci_3200.c: 63
+addi_apci_3300.c: 63
+addi_apci_3501.c: 63
+addi_apci_3xxx.c: 63
+addi_apci_all.c: 468
+addi_common.c: 57084
+addi_common.h: 15536
+addi-data: 4096
+addi_eeprom.c: 35657
+addinitrd.c: 3837
+addnote.c: 5117
+addon_cpuid_features.c: 3269
+addRamDisk.c: 9120
+addr.c: 13176
+addrconf.c: 112491
+addrconf_core.c: 2484
+addrconf.h: 7261
+address.c: 10451
+addr.h: 615
+addrlabel.c: 14012
+addr-map.c: 3725
+addr-map.h: 1054
+addrs.h: 14810
+addrspace.h: 4233
+adfs: 4096
+adfs_fs.h: 1337
+adfs.h: 5064
+adfs.txt: 1816
+adi.c: 14310
+adlib.c: 3006
+adl_pci6208.c: 11803
+adl_pci7296.c: 4671
+adl_pci7432.c: 5617
+adl_pci8164.c: 9991
+adl_pci9111.c: 38266
+adl_pci9118.c: 69079
+adm1021: 4184
+adm1021.c: 14057
+adm1025: 2364
+adm1025.c: 19865
+adm1026: 4578
+adm1026.c: 60096
+adm1029.c: 13774
+adm1031: 1193
+adm1031.c: 31209
+adm8211.c: 56115
+adm8211.h: 18093
+adm9240: 6804
+adm9240.c: 24112
+adma.c: 5497
+adma.h: 13803
+adq12b.c: 12147
+ads7828: 1146
+ads7828.c: 8084
+ads7846.c: 31008
+ads7846.h: 1844
+ADSBitsy: 1396
+adssphere.c: 1810
+adt7462: 2515
+adt7462.c: 60645
+adt7470: 2759
+adt7470.c: 42397
+adt7473: 2757
+adt7473.c: 35779
+adt7475: 2578
+adt7475.c: 35318
+adummy.c: 3035
+adutux.c: 25427
+adv7170.c: 9645
+adv7175.c: 10457
+adv7343.c: 12608
+adv7343.h: 730
+adv7343_regs.h: 5764
+advansys: 4096
+advansys.c: 382572
+advansys.txt: 9492
+advantechwdt.c: 8222
+adv_pci1710.c: 46220
+adv_pci1723.c: 12975
+adv_pci_dio.c: 34130
+ae7400074d449189d41fceb6d6f871490d7842: 298
+aead.c: 12873
+aead.h: 2027
+aec62xx.c: 9392
+aedsp16.c: 36369
+ael1002.c: 41054
+aer: 4096
+aerdrv_acpi.c: 1347
+aerdrv.c: 8935
+aerdrv_core.c: 22958
+aerdrv_errprint.c: 5915
+aerdrv.h: 3468
+aer.h: 773
+aer_inject.c: 10715
+aes.c: 11973
+aes_ccm.c: 3589
+aes_ccm.h: 810
+aes_ccmp.c: 14024
+aes_ccmp.h: 1469
+aes_cmac.c: 2737
+aes_cmac.h: 587
+aes_generic.c: 63316
+aes_glue.c: 1691
+aes.h: 279
+aes-i586-asm_32.S: 10637
+aesni-intel_asm.S: 21991
+aesni-intel_glue.c: 19525
+aes_s390.c: 13814
+aes-x86_64-asm_64.S: 4820
+af802154.h: 1271
+af9005.c: 28215
+af9005-fe.c: 36514
+af9005.h: 120579
+af9005-remote.c: 4403
+af9005-script.h: 5193
+af9013.c: 38083
+af9013.h: 3095
+af9013_priv.h: 21508
+af9015.c: 43153
+af9015.h: 28439
+af_ax25.c: 45160
+af_bluetooth.c: 10089
+af_can.c: 23294
+af_can.h: 4053
+af_decnet.c: 54945
+afeb9260_defconfig: 29783
+af_econet.c: 25853
+affs: 4096
+affs.h: 10590
+affs_hardblocks.h: 1481
+affs.txt: 8188
+af_ieee802154.c: 8683
+af_ieee802154.h: 1620
+af_inet6.c: 29847
+af_inet.c: 40041
+af_ipx.c: 50967
+af_irda.c: 67827
+af_irda.h: 2964
+af_iucv.c: 41285
+af_iucv.h: 2495
+af_key.c: 102229
+af_llc.c: 29863
+af_netlink.c: 46590
+af_netrom.c: 33634
+af_packet.c: 55964
+af_phonet.c: 10845
+af_rds.c: 14309
+af_rose.c: 39337
+af_rxrpc.c: 20908
+af_rxrpc.h: 2017
+afs: 4096
+afs.c: 6434
+afs_cm.h: 1213
+afs_fs.h: 2342
+afs.h: 6110
+afs.txt: 7976
+afs_vl.h: 3680
+af_unix.c: 53673
+af_unix.h: 1891
+af_x25.c: 38538
+agent.c: 6214
+agent.h: 2106
+agg-rx.c: 10061
+agg-tx.c: 19983
+agnx: 4096
+agnx.h: 4414
+agp: 4096
+agp_backend.h: 909
+agpgart.h: 6567
+agp.h: 11594
+ah4.c: 7802
+ah6.c: 13438
+aha152x.c: 100462
+aha152x_core.c: 61
+aha152x.h: 10175
+aha152x_stub.c: 7843
+aha152x.txt: 6540
+aha1542.c: 50376
+aha1542.h: 4776
+aha1740.c: 19608
+aha1740.h: 4954
+ahash.c: 5607
+ahb.c: 4740
+ah.c: 3493
+ahci.c: 82058
+ah.h: 894
+aic7770.c: 9851
+aic7770_osm.c: 4437
+aic79xx_core.c: 299904
+aic79xx.h: 46803
+aic79xx_inline.h: 5997
+aic79xx_osm.c: 79947
+aic79xx_osm.h: 21300
+aic79xx_osm_pci.c: 10626
+aic79xx_pci.c: 27694
+aic79xx_pci.h: 3106
+aic79xx_proc.c: 10559
+aic79xx.reg: 73912
+aic79xx_reg.h_shipped: 71718
+aic79xx_reg_print.c_shipped: 19691
+aic79xx.seq: 72735
+aic79xx_seq.h_shipped: 29327
+aic79xx.txt: 24091
+aic7xxx: 4096
+aic7xxx_93cx6.c: 9761
+aic7xxx_93cx6.h: 3670
+aic7xxx_core.c: 216583
+aic7xxx.h: 42160
+aic7xxx_inline.h: 3774
+aic7xxx_old: 4096
+aic7xxx_old.c: 366880
+aic7xxx_old.txt: 24500
+aic7xxx_osm.c: 73118
+aic7xxx_osm.h: 21353
+aic7xxx_osm_pci.c: 12355
+aic7xxx_pci.c: 61842
+aic7xxx_pci.h: 5296
+aic7xxx_proc.c: 10950
+aic7xxx.reg: 38137
+aic7xxx_reg.h: 15305
+aic7xxx_reg.h_shipped: 23099
+aic7xxx_reg_print.c_shipped: 10818
+aic7xxx.seq: 70499
+aic7xxx_seq.c: 20747
+aic7xxx_seq.h_shipped: 32908
+aic7xxx.txt: 19701
+aic94xx: 4096
+aic94xx_dev.c: 11236
+aic94xx_dump.c: 36929
+aic94xx_dump.h: 1451
+aic94xx.h: 3007
+aic94xx_hwi.c: 38875
+aic94xx_hwi.h: 10646
+aic94xx_init.c: 28607
+aic94xx_reg.c: 10895
+aic94xx_reg_def.h: 74147
+aic94xx_reg.h: 10470
+aic94xx_sas.h: 22044
+aic94xx_scb.c: 27220
+aic94xx_sds.c: 37304
+aic94xx_sds.h: 4644
+aic94xx_seq.c: 47415
+aic94xx_seq.h: 2011
+aic94xx_task.c: 17414
+aic94xx_tmf.c: 20129
+aica.c: 18912
+aica.h: 2322
+aicasm: 4096
+aicasm.c: 20235
+aicasm_gram.y: 41937
+aicasm.h: 3213
+aicasm_insformat.h: 5394
+aicasm_macro_gram.y: 4072
+aicasm_macro_scan.l: 4166
+aicasm_scan.l: 15538
+aicasm_symbol.c: 16089
+aicasm_symbol.h: 4889
+aiclib.c: 1599
+aiclib.h: 6327
+aio_abi.h: 3060
+aio_aio12_8.c: 5597
+aio.c: 9345
+aio.h: 530
+aio_iiro_16.c: 4521
+aiptek.c: 63719
+aircable.c: 16905
+airo.c: 224549
+airo_cs.c: 16214
+airo.h: 272
+aironet.c: 38
+aironet.h: 31
+airport.c: 6741
+airq.c: 3567
+airq.h: 530
+ak4104.c: 8783
+ak4104.h: 143
+ak4114.c: 18943
+ak4114.h: 10191
+ak4117.c: 16871
+ak4117.h: 9193
+ak4396.h: 1065
+ak4531_codec.c: 17543
+ak4531_codec.h: 3161
+ak4535.c: 18361
+ak4535.h: 1042
+ak4xxx-adda.c: 25308
+ak4xxx-adda.h: 3333
+ak4xxx.c: 5039
+aki3068net: 4096
+alauda.c: 34485
+alaw_main.csp.ihex: 3714
+alchemy: 4096
+alchemy-flash.c: 4191
+algapi.c: 16668
+algapi.h: 8721
+algboss.c: 6296
+algos: 4096
+ali14xx.c: 6564
+ali5451: 4096
+ali5451.c: 59400
+ali-agp.c: 10369
+alias.c: 1447
+aliasing-test.c: 6103
+aliasing.txt: 8753
+alias.txt: 1181
+align.c: 24429
+alignment.c: 23757
+align.S: 11650
+ali-ircc.c: 57570
+ali-ircc.h: 7748
+alim1535_wdt.c: 10224
+alim15x3.c: 14978
+alim7101_wdt.c: 11048
+allocator.c: 10151
+alloc.c: 10261
+alloc.h: 9219
+allocpercpu.c: 4150
+alpaca.h: 1209
+alpha: 4096
+alpha-agp.c: 5476
+alpha_ksyms.c: 2696
+alphatrack.c: 23326
+alphatrack.h: 2005
+alps.c: 15813
+alps.h: 1047
+ALS: 3770
+als100.c: 9384
+als300.c: 23789
+als4000.c: 32136
+alsa: 4096
+alsa.c: 2430
+ALSA-Configuration.txt: 75006
+alsa-driver-api.tmpl: 3216
+alsa.h: 370
+alternative-asm.h: 289
+alternative.c: 14237
+alternative.h: 5895
+altpciechdma: 4096
+altpciechdma.c: 37598
+am200epd.c: 9652
+am200epdkit_defconfig: 26949
+am300epd.c: 6564
+am79c961a.c: 18502
+am79c961a.h: 3109
+am9513.h: 1940
+amba: 4096
+amba-clcd.c: 12494
+ambakmi.c: 4554
+amba-pl010.c: 19490
+amba-pl011.c: 21509
+amba-pl022.c: 53346
+ambassador.c: 68387
+ambassador.h: 16192
+amcc: 4096
+amcc_s5933_58.h: 14263
+amcc_s5933.h: 6603
+amd5536udc.c: 86854
+amd5536udc.h: 17276
+amd64-agp.c: 20128
+amd64_edac.c: 98492
+amd64_edac_dbg.c: 5401
+amd64_edac_err_types.c: 3628
+amd64_edac.h: 19221
+amd64_edac_inj.c: 4304
+amd74xx.c: 10198
+amd76x_edac.c: 9371
+amd76xrom.c: 9404
+amd7930.c: 31102
+amd7930_fn.c: 23626
+amd7930_fn.h: 1162
+amd8111e.c: 53690
+amd8111_edac.c: 16756
+amd8111_edac.h: 4244
+amd8111e.h: 21006
+amd8131_edac.c: 10985
+amd8131_edac.h: 3772
+amd_bus.c: 13843
+amd.c: 3180
+amd_iommu.c: 52618
+amd_iommu.h: 1421
+amd_iommu_init.c: 34814
+amd_iommu_types.h: 13377
+amd-k7-agp.c: 15673
+amd-powernow.txt: 1673
+amd-rng.c: 3458
+amifb.c: 103212
+amifd.h: 1995
+amifdreg.h: 2674
+amiflop.c: 46962
+amiga: 4096
+amiga.c: 3445
+amiga_defconfig: 28613
+amigaffs.c: 11549
+amigaffs.h: 2927
+amiga.h: 116
+amigahw.h: 11232
+amigaints.h: 3583
+amigaone: 4096
+amigaone_defconfig: 40433
+amigaone.dts: 4189
+amigayle.h: 3135
+amiints.c: 6489
+amijoy.c: 4591
+amijoy.txt: 7701
+amikbd.c: 6468
+amimouse.c: 3296
+amipcmcia.h: 2568
+amiserial.c: 54254
+amisound.c: 2828
+amix86.c: 23331
+amlcode.h: 18976
+aml_nfw.c: 5630
+amlresrc.h: 9975
+amon.h: 141
+amp.c: 2736
+amp.h: 1594
+amplc_dio200.c: 38731
+amplc_pc236.c: 16962
+amplc_pc263.c: 11680
+amplc_pci224.c: 44174
+amplc_pci230.c: 92910
+ams: 4096
+ams-core.c: 6046
+ams-delta.c: 5974
+ams_delta_defconfig: 28481
+amsdu.c: 5428
+ams.h: 1354
+ams-i2c.c: 6365
+ams-input.c: 3542
+amso1100: 4096
+ams-pmu.c: 4469
+analog.c: 20366
+anchor.h: 3882
+anchors.txt: 2625
+android: 4096
+ani.c: 23441
+ani.h: 4062
+anode.c: 14491
+anomaly.h: 11228
+anon_inodes.c: 5477
+anon_inodes.h: 312
+ansi_cprng.c: 10011
+ansidecl.h: 4393
+ans-lcd.c: 3847
+ans-lcd.h: 206
+anubis.c: 28484
+anubis-cpld.h: 652
+anubis-irq.h: 596
+anubis-map.h: 1219
+anycast.c: 11884
+anysee.c: 15434
+anysee.h: 14174
+aoa: 4096
+aoa-gpio.h: 2434
+aoa.h: 3816
+aoe: 4096
+aoeblk.c: 7321
+aoechr.c: 6092
+aoecmd.c: 23023
+aoedev.c: 5392
+aoe.h: 4748
+aoemain.c: 2032
+aoenet.c: 3237
+aoe.txt: 4600
+aops.c: 49318
+aops.h: 4017
+a.out-core.h: 2444
+a.out.h: 2438
+ap325rxa_defconfig: 31462
+apanel.c: 8043
+apb.h: 1043
+ap_bus.c: 45317
+ap_bus.h: 6091
+apc.c: 4412
+apc.h: 1682
+APCI1710_82x54.c: 55614
+APCI1710_82x54.h: 2408
+APCI1710_Chrono.c: 75530
+APCI1710_Chrono.h: 2397
+APCI1710_Dig_io.c: 35243
+APCI1710_Dig_io.h: 1437
+APCI1710_INCCPT.c: 206966
+APCI1710_INCCPT.h: 10615
+APCI1710_Inp_cpt.c: 32511
+APCI1710_Inp_cpt.h: 1414
+APCI1710_Pwm.c: 110859
+APCI1710_Pwm.h: 2722
+APCI1710_Ssi.c: 30348
+APCI1710_Ssi.h: 1343
+APCI1710_Tor.c: 70692
+APCI1710_Tor.h: 1684
+APCI1710_Ttl.c: 35072
+APCI1710_Ttl.h: 1338
+apdbg.c: 12729
+aperture_64.c: 13850
+ap.h: 26
+apic: 4096
+api.c: 4766
+apic.c: 56323
+apicdef.h: 10790
+apic_flat_64.c: 9680
+apic.h: 48
+apicnum.h: 229
+API.html: 738
+api-intro.txt: 6569
+apm_32.c: 71310
+apm-acpi.txt: 1541
+apm_bios.h: 5647
+apm.c: 1961
+apm_emu.c: 3225
+apm-emulation.c: 17959
+apm-emulation.h: 1575
+apm.h: 1722
+apm_power.c: 10334
+apm-power.c: 2659
+apne.c: 17115
+apollo: 4096
+apollo_defconfig: 25574
+apollodma.h: 9409
+apollohw.h: 2876
+appldata: 4096
+appldata_base.c: 16414
+appldata.h: 2269
+appldata_mem.c: 4196
+appldata_net_sum.c: 4240
+appldata_os.c: 6134
+appledisplay.c: 9793
+applesmc.c: 46139
+appletalk: 4096
+appletouch.c: 25051
+appletouch.txt: 3199
+applicom.c: 24465
+applicom.h: 2558
+applying-patches.txt: 19961
+applypatch-msg.sample: 452
+aq100x.c: 8974
+ar7: 4096
+ar7_defconfig: 29419
+ar7.h: 4432
+ar7part.c: 4186
+ar7_wdt.c: 8576
+ar9170: 4096
+ar9170.h: 7335
+ar-accept.c: 12406
+ar-ack.c: 33274
+arbiter.c: 11549
+arbiter.h: 607
+arc: 4096
+arc4.c: 2066
+ar-call.c: 21724
+arc_con.c: 973
+arcdevice.h: 12708
+arcfb.c: 16908
+arcfb.h: 150
+arch: 4096
+arch_checks.c: 3045
+arches_defconfig: 19397
+arches.dts: 7694
+arch.h: 1650
+arch-kev7a400.c: 2933
+arch-lpd7a40x.c: 10208
+archparam.h: 246
+archsetjmp.h: 363
+arch-v10: 4096
+arch-v32: 4096
+arcmsr: 4096
+arcmsr_attr.c: 12953
+arcmsr.h: 22540
+arcmsr_hba.c: 68471
+arcmsr_spec.txt: 22891
+arcnet: 4096
+arcnet.c: 30476
+arcnet-hardware.txt: 112635
+arcnet.txt: 23983
+arcofi.c: 3664
+arcofi.h: 721
+ar-connection.c: 23383
+ar-connevent.c: 9295
+arc-rawmode.c: 5274
+arc-rimi.c: 10949
+ar-error.c: 5949
+argv_split.c: 1893
+ariadne.c: 24224
+ariadne.h: 15566
+ar-input.c: 20380
+ar-internal.h: 28881
+ark3116.c: 12365
+ar-key.c: 8236
+arkfb.c: 31427
+arkfb.txt: 2024
+arlan.h: 16773
+arlan-main.c: 51969
+arlan-proc.c: 30009
+ar-local.c: 7670
+arm: 4096
+armadillo5x0.c: 7149
+ARM-gcc.h: 4503
+armksyms.c: 4758
+arm_timer.h: 576
+ar-output.c: 18343
+arp.c: 35296
+ar-peer.c: 7599
+arp.h: 1028
+ar-proc.c: 5159
+arptable_filter.c: 3496
+arp_tables.c: 47085
+arp_tables.h: 8551
+arpt_mangle.c: 2391
+arpt_mangle.h: 547
+array.c: 13244
+arrayRCU.txt: 4475
+ar-recvmsg.c: 11003
+ar-security.c: 5588
+ar-skbuff.c: 3506
+arthur.c: 2275
+artpec_3_defconfig: 13781
+ar-transport.c: 7196
+arv.c: 22235
+arxescsi.c: 9967
+asb100: 2093
+asb100.c: 29220
+asb2303_defconfig: 13559
+asciidoc.conf: 2238
+asequencer.h: 24733
+ashiftrt.S: 3468
+ashldi3.c: 1516
+__ashldi3.S: 1340
+ashldi3.S: 1594
+ashlsi3.S: 3814
+ashrdi3.c: 1578
+__ashrdi3.S: 1359
+ashrdi3.S: 1594
+ashrsi3.S: 3765
+ashxdi3.S: 5014
+asic3.c: 23429
+asic3.h: 11966
+asids-debugfs.c: 1875
+asi.h: 13855
+asiliantfb.c: 17057
+as-iosched.c: 39676
+as-iosched.txt: 8697
+asix.c: 39119
+as-layout.h: 1666
+asl.c: 9101
+asm: 4096
+asm-compat.h: 1951
+asm-generic: 4096
+asm.h: 9481
+asmmacro-32.h: 4815
+asmmacro-64.h: 3961
+asmmacro.h: 2767
+asm-offsets_32.c: 5194
+asm-offsets_64.c: 3637
+asm-offsets.c: 4611
+asmregs.h: 3115
+asn1.c: 15700
+asoundef.h: 14263
+asound_fm.h: 4313
+asound.h: 39901
+asp8347_defconfig: 35011
+asp834x.c: 2108
+asp834x-redboot.dts: 6941
+asp.c: 3631
+aspenite.c: 2671
+asp.h: 608
+aspm.c: 25790
+Assabet: 9201
+assabet.c: 11283
+assabet_defconfig: 17595
+assabet.h: 4477
+assembler.h: 2834
+assembly.h: 12972
+assoc.c: 36
+assoc.h: 408
+association.h: 4661
+associola.c: 43957
+ast.c: 3630
+ast.h: 878
+asus_acpi.c: 39676
+asus_atk0110.c: 24097
+asuscom.c: 11573
+asus-laptop.c: 36214
+asus_oled: 4096
+asus_oled.c: 18945
+async.c: 11128
+asyncdata.c: 15045
+async.h: 973
+async_memcpy.c: 3227
+async_memset.c: 2994
+async-thread.c: 13350
+async-thread.h: 3400
+async_tx: 4096
+async-tx-api.txt: 8950
+async_tx.c: 8062
+async_tx.h: 5062
+async_xor.c: 9790
+at1700.c: 25461
+at24.c: 17172
+at24.h: 1084
+at25.c: 10286
+at32ap700x.c: 54284
+at32ap700x.h: 9017
+at32ap700x_wdt.c: 10216
+at32psif.c: 8545
+at73c213.c: 28442
+at73c213.h: 3187
+at76c50x-usb.c: 69577
+at76c50x-usb.h: 11556
+at76_usb: 4096
+at76_usb.c: 159931
+at76_usb.h: 18785
+at91_adc.h: 2447
+at91_aic.h: 2578
+at91cap9adk_defconfig: 28118
+at91cap9.c: 9260
+at91cap9_ddrsdr.h: 4803
+at91cap9_devices.c: 32852
+at91cap9.h: 5120
+at91cap9_matrix.h: 8438
+at91_cf.c: 10319
+at91_dbgu.h: 2878
+at91_ether.c: 37656
+at91_ether.h: 3116
+at91_ide.c: 10538
+at91_mci.c: 31894
+at91_mci.h: 5220
+at91_pio.h: 2085
+at91_pit.h: 1189
+at91_pmc.h: 6822
+at91rm9200.c: 8544
+at91rm9200_devices.c: 32118
+at91rm9200dk_defconfig: 19334
+at91rm9200ek_defconfig: 19319
+at91rm9200_emac.h: 6334
+at91rm9200.h: 4634
+at91rm9200_mc.h: 7552
+at91rm9200_time.c: 6137
+at91rm9200_wdt.c: 6655
+at91_rstc.h: 1684
+at91_rtc.h: 3381
+at91_rtt.h: 1335
+at91sam9260.c: 9719
+at91sam9260_devices.c: 28830
+at91sam9260ek_defconfig: 23675
+at91sam9260.h: 5601
+at91sam9260_matrix.h: 4360
+at91sam9261.c: 7811
+at91sam9261_devices.c: 27547
+at91sam9261ek_defconfig: 27131
+at91sam9261.h: 3985
+at91sam9261_matrix.h: 3171
+at91sam9263.c: 8693
+at91sam9263_devices.c: 36564
+at91sam9263ek_defconfig: 27888
+at91sam9263.h: 5088
+at91sam9263_matrix.h: 7531
+at91sam926x_time.c: 4812
+at91sam9g20ek_defconfig: 26082
+at91sam9rl.c: 8144
+at91sam9rl_devices.c: 28643
+at91sam9rlek_defconfig: 21184
+at91sam9rl.h: 4332
+at91sam9rl_matrix.h: 5086
+at91sam9_sdramc.h: 3914
+at91sam9_smc.h: 3570
+at91sam9_wdt.c: 7764
+at91_shdwc.h: 1497
+at91_spi.h: 3738
+at91_ssc.h: 4846
+at91_st.h: 1983
+at91_tc.h: 6897
+at91_twi.h: 3075
+at91_udc.c: 48229
+at91_udc.h: 6283
+at91_wdt.h: 1464
+at91x40.c: 1914
+at91x40.h: 2025
+at91x40_time.c: 2547
+at93c.c: 2613
+at93c.h: 292
+ata: 12288
+ata.c: 4208
+ata_defs_asm.h: 8736
+ata_defs.h: 6434
+atafb.c: 91174
+atafb.h: 1708
+atafb_iplan2p2.c: 6818
+atafb_iplan2p4.c: 7301
+atafb_iplan2p8.c: 8377
+atafb_mfb.c: 2554
+atafb_utils.h: 11235
+atafd.h: 261
+atafdreg.h: 2704
+ataflop.c: 52286
+ata_generic.c: 6543
+atags.c: 1588
+atags.h: 132
+ata.h: 787
+ataints.c: 14727
+atakbd.c: 6402
+atakeyb.c: 15982
+atalk.h: 5240
+atalk_proc.c: 7290
+ata_piix.c: 45848
+ata_platform.h: 910
+atari: 4096
+atari.c: 3911
+atari_defconfig: 26788
+atari.h: 1077
+atarihw.h: 20620
+atariints.h: 5520
+atari_joystick.h: 418
+atarikbd.txt: 26109
+atarikb.h: 1514
+atarilance.c: 34168
+atarimouse.c: 3865
+atari_NCR5380.c: 92608
+atari_scsi.c: 35928
+atari_scsi.h: 5820
+atari_stdma.h: 458
+atari_stram.h: 429
+atasound.c: 2705
+ateb9200_defconfig: 26557
+aten2011.c: 65277
+aten.c: 3343
+ath: 4096
+ath5k: 4096
+ath5k.h: 45994
+ath9k: 4096
+ath9k.h: 20541
+ath9k_platform.h: 1116
+athr_common.h: 4056
+ati-agp.c: 14653
+ati_ids.h: 8172
+atiixp.c: 5592
+atiixp_modem.c: 36739
+ati_pcigart.c: 5516
+ati_remote2.c: 23391
+ati_remote.c: 27913
+atkbd.c: 40410
+atl1c: 4096
+atl1.c: 101403
+atl1c_ethtool.c: 9188
+atl1c.h: 20395
+atl1c_hw.c: 13975
+atl1c_hw.h: 31069
+atl1c_main.c: 77505
+atl1e: 4096
+atl1e_ethtool.c: 11679
+atl1e.h: 17562
+atl1e_hw.c: 16680
+atl1e_hw.h: 38581
+atl1e_main.c: 71172
+atl1e_param.c: 7245
+atl1.h: 24023
+atl2.c: 82456
+atl2.h: 16349
+atlas_btns.c: 4752
+atlx: 4096
+atlx.c: 7198
+atlx.h: 18176
+atm: 4096
+atmapi.h: 889
+atmarp.h: 1233
+atmbr2684.h: 3208
+atmclip.h: 513
+atmdev.h: 16681
+atmel: 4096
+atmel-abdac.h: 626
+atmel-ac97c.h: 1409
+atmel.c: 132756
+atmel_cs.c: 17914
+atmel.h: 1533
+atmel_lcdc.h: 7265
+atmel_lcdfb.c: 31305
+atmel-mci.c: 43139
+atmel-mci.h: 1269
+atmel-mci-regs.h: 6476
+atmel_nand.c: 15137
+atmel_nand_ecc.h: 1412
+atmel_pci.c: 2533
+atmel-pcm.c: 14083
+atmel-pcm.h: 2987
+atmel_pdc.h: 1410
+atmel-pwm-bl.c: 6152
+atmel-pwm-bl.h: 1550
+atmel_pwm.c: 9359
+atmel_pwm.h: 2724
+atmel_read_eeprom.c: 3671
+atmel_read_eeprom.h: 2413
+atmel_serial.c: 40894
+atmel_serial.h: 6087
+atmel_spi.c: 23923
+atmel_spi.h: 4446
+atmel-ssc.c: 3605
+atmel_ssc_dai.c: 20632
+atmel_ssc_dai.h: 3265
+atmel-ssc.h: 9369
+atmel_tc.h: 11075
+atmel_tclib.c: 3626
+atmel_tsadcc.c: 10816
+atmel_usba_udc.c: 50940
+atmel_usba_udc.h: 10031
+atmel-wm97xx.c: 11848
+atm_eni.h: 585
+atm.h: 7995
+atm_he.h: 343
+atm_idt77105.h: 892
+atmioc.h: 1583
+atmlec.h: 2561
+atm_misc.c: 2638
+atmmpc.h: 4163
+atm_nicstar.h: 1215
+atmppp.h: 576
+atmsap.h: 4907
+atmsar11.HEX: 19191
+atm_suni.h: 253
+atmsvc.h: 1790
+atm_sysfs.c: 3945
+atmtcp.c: 11650
+atm_tcp.h: 1768
+atm.txt: 426
+atm_zatm.h: 1606
+atngw100: 4096
+atngw100_defconfig: 28242
+atngw100_evklcd100_defconfig: 29353
+atngw100_evklcd101_defconfig: 29353
+atngw100_mrmt_defconfig: 33751
+atombios_crtc.c: 23254
+atombios.h: 221852
+atom-bits.h: 1882
+atom.c: 29689
+atom.h: 4494
+atomic32.c: 2859
+atomic_32.h: 11086
+atomic_32.S: 2663
+atomic64.c: 3863
+atomic_64.h: 10903
+atomic64.h: 1840
+atomic64-ops.S: 4827
+atomic_64.S: 2925
+atomic-grb.h: 4642
+atomic.h: 7333
+atomic-irq.h: 1375
+atomic-llsc.h: 2813
+atomic-long.h: 5244
+atomic_mm.h: 4061
+atomic_no.h: 3556
+atomic-ops.S: 5339
+atomic_ops.txt: 19503
+atomic-ops.txt: 4632
+atomic.S: 15917
+atom-names.h: 4758
+atom-types.h: 1430
+atp870u.c: 86512
+atp870u.h: 1487
+atp.c: 29816
+atp.h: 8737
+atstk1000: 4096
+atstk1000.h: 535
+atstk1002.c: 8012
+atstk1002_defconfig: 30107
+atstk1003.c: 3765
+atstk1003_defconfig: 25774
+atstk1004.c: 3756
+atstk1004_defconfig: 15379
+atstk1006_defconfig: 32583
+attach.c: 9647
+attr.c: 2666
+attrib.c: 91896
+attrib.h: 4321
+attribute_container.c: 12242
+attribute_container.h: 2530
+atxp1.c: 9417
+aty: 4096
+aty128fb.c: 67277
+aty128fb.txt: 2119
+aty128.h: 13554
+atyfb_base.c: 111634
+atyfb.h: 8973
+au0828: 4096
+au0828-cards.c: 9773
+au0828-cards.h: 1060
+au0828-core.c: 7629
+au0828-dvb.c: 11151
+au0828.h: 7385
+au0828-i2c.c: 9287
+au0828-reg.h: 2134
+au0828-video.c: 41940
+au1000_db1x00.c: 7294
+au1000_dma.h: 11212
+au1000_eth.c: 33708
+au1000_eth.h: 3012
+au1000_generic.c: 14674
+au1000_generic.h: 4280
+au1000.h: 53188
+au1000_ircc.h: 3758
+au1000_pb1x00.c: 9234
+au1000_xxs1500.c: 4378
+au1100fb.c: 20752
+au1100fb.h: 14620
+au1100_mmc.h: 5888
+au1200fb.c: 52491
+au1200fb.h: 18704
+au1550_ac97.c: 51655
+au1550nd.c: 14821
+au1550_spi.c: 26531
+au1550_spi.h: 433
+au1k_ir.c: 20249
+au1x: 4096
+au1x00.c: 19173
+au1xmmc.c: 28453
+au1xxx_dbdma.h: 13134
+au1xxx.h: 1723
+au1xxx-ide.c: 15369
+au1xxx_ide.h: 6491
+AU1xxx_IDE.README: 4039
+au1xxx_psc.h: 15895
+au6610.c: 6091
+au6610.h: 1286
+au8522_decoder.c: 27416
+au8522_dig.c: 21506
+au8522.h: 2387
+au8522_priv.h: 17128
+au8810.c: 379
+au8810.h: 7007
+au8820.c: 331
+au8820.h: 6479
+au8830.c: 404
+au8830.h: 8629
+au88x0: 4096
+au88x0_a3d.c: 25257
+au88x0_a3ddata.c: 2908
+au88x0_a3d.h: 4336
+au88x0.c: 10316
+au88x0_core.c: 78891
+au88x0_eq.c: 23045
+au88x0_eqdata.c: 3952
+au88x0_eq.h: 1287
+au88x0_game.c: 3655
+au88x0.h: 8929
+au88x0_mixer.c: 773
+au88x0_mpu401.c: 3619
+au88x0_pcm.c: 15858
+au88x0_synth.c: 11076
+au88x0_wt.h: 2347
+au88x0_xtalk.c: 23426
+au88x0_xtalk.h: 2304
+Audigy-mixer.txt: 13956
+audio.c: 7519
+AudioExcelDSP16: 3886
+audio.h: 525
+Audiophile-Usb.txt: 17915
+audit_64.c: 1870
+audit.c: 1888
+audit_change_attr.h: 320
+audit_dir_write.h: 238
+auditfilter.c: 34110
+audit.h: 394
+audit_read.h: 127
+auditsc.c: 67706
+audit_signal.h: 36
+audit_tree.c: 22256
+audit_watch.c: 14765
+audit_write.h: 255
+aureon.c: 64017
+aureon.h: 2419
+autcpu12.c: 5831
+autcpu12.h: 2590
+autcpu12-nvram.c: 3124
+auth.c: 35
+authenc.c: 13429
+authenc.h: 609
+auth_generic.c: 4800
+auth_gss: 4096
+auth_gss.c: 40950
+auth_gss.h: 2256
+auth.h: 540
+auth_null.c: 2607
+authorization.txt: 2640
+authors: 38
+AUTHORS: 38
+auth_rsp.c: 39
+auth_unix.c: 5607
+auto_dev-ioctl.h: 5186
+autofs: 4096
+autofs4: 4096
+auto_fs4.h: 4095
+autofs4-mount-control.txt: 17706
+auto_fs.h: 2467
+autofs_i.h: 7355
+autoload.c: 967
+autoload.sh: 339
+automount-support.txt: 4694
+autoprobe.c: 4772
+auxdisplay: 4096
+auxio_32.c: 3721
+auxio_32.h: 2622
+auxio_64.c: 3214
+auxio_64.h: 3266
+auxio.h: 176
+aux_reg.h: 646
+auxvec.h: 60
+av7110: 4096
+av7110_av.c: 40033
+av7110_av.h: 1214
+av7110.c: 82729
+av7110_ca.c: 9180
+av7110_ca.h: 441
+av7110.h: 7155
+av7110_hw.c: 31995
+av7110_hw.h: 12512
+av7110_ipack.c: 7991
+av7110_ipack.h: 402
+av7110_ir.c: 11196
+av7110_v4l.c: 27884
+avc.c: 24534
+avc.h: 3102
+avc_ss.h: 617
+avermedia.txt: 13922
+avila.h: 917
+avila-pci.c: 1817
+avila-setup.c: 4610
+av_inherit.h: 1693
+avm: 4096
+avm_a1.c: 8303
+avma1_cs.c: 9468
+avm_a1p.c: 7146
+avmcard.h: 13933
+avm_cs.c: 9107
+avm_pci.c: 23187
+av_permissions.h: 53693
+av_perm_to_string.h: 10893
+avr32: 4096
+__avr32_asr64.S: 560
+avr32_ksyms.c: 1843
+__avr32_lsl64.S: 559
+__avr32_lsr64.S: 559
+avtab.c: 12842
+avtab.h: 2874
+aw2: 4096
+aw2-alsa.c: 22536
+aw2-saa7146.c: 12816
+aw2-saa7146.h: 3650
+aw2-tsl.c: 4092
+awacs.c: 32895
+awacs.h: 8192
+ax25: 4096
+ax25_addr.c: 6217
+ax25_dev.c: 4867
+ax25_ds_in.c: 7261
+ax25_ds_subr.c: 5218
+ax25_ds_timer.c: 5960
+ax25.h: 2752
+ax25_iface.c: 5067
+ax25_in.c: 10789
+ax25_ip.c: 5405
+ax25_out.c: 8933
+ax25_route.c: 11432
+ax25_std_in.c: 11343
+ax25_std_subr.c: 2329
+ax25_std_timer.c: 4335
+ax25_subr.c: 7113
+ax25_timer.c: 5261
+ax25.txt: 610
+ax25_uid.c: 5032
+ax88796.c: 25354
+ax88796.h: 751
+axisflashmap.c: 11854
+axisflashmap.h: 1932
+axnet_cs.c: 55656
+axon_msi.c: 11768
+axonram.c: 9510
+azt2320.c: 9995
+azt3328.c: 74771
+azt3328.h: 16466
+b128ops.h: 2471
+b180_defconfig: 30806
+b1.c: 20917
+b1dma.c: 24682
+b1isa.c: 6013
+b1lli.h: 1654
+b1pci.c: 10903
+b1pcmcia.c: 5718
+b1pcmcia.h: 666
+b2: 4096
+b2c2: 4096
+b3dfg: 4096
+b3dfg.c: 29136
+b43: 4096
+b43.h: 34564
+b43legacy: 4096
+b43legacy.h: 26792
+b43_pci_bridge.c: 1563
+b44.c: 58926
+b44.h: 17577
+ba_action.c: 43
+baboon.c: 2869
+backchannel_rqst.c: 9002
+backend-api.txt: 23417
+backend.c: 8969
+background.c: 4246
+backing-dev.c: 7753
+backing-dev.h: 7625
+backing_ops.c: 11152
+backlight: 4096
+backlight.c: 8488
+backlight.h: 1076
+backoff.h: 514
+backtrace.c: 2048
+backtrace.S: 3769
+backtracetest.c: 2135
+badge4.c: 7278
+badge4_defconfig: 25237
+badge4.h: 2530
+bad_inode.c: 8103
+bad_memory.txt: 1113
+balance: 5103
+balloc.c: 28466
+balloon.c: 15823
+bamboo.c: 1219
+bamboo_defconfig: 23088
+bamboo.dts: 7833
+barrier.h: 751
+barrier.txt: 10841
+base: 4096
+baseband.c: 69836
+baseband.h: 5142
+base.c: 17017
+base.h: 5692
+base.S: 2976
+bas-gigaset.c: 70245
+basic: 4096
+basic-pm-debugging.txt: 10323
+basic_profiling.txt: 1707
+basler: 4096
+bast-cpld.h: 1556
+bast-ide.c: 2522
+bast-irq.c: 3575
+bast-irq.h: 842
+bast-map.h: 5001
+bast-pmu.h: 1140
+battery.c: 26147
+baycom_epp.c: 34930
+baycom.h: 820
+baycom_par.c: 16899
+baycom_ser_fdx.c: 21220
+baycom_ser_hdx.c: 21005
+baycom.txt: 7038
+bbc_envctrl.c: 15825
+bbc.h: 9957
+bbc_i2c.c: 9865
+bbc_i2c.h: 1987
+bbm.h: 4408
+bcache.h: 1450
+bcast.c: 21337
+bcast.h: 5594
+bcd.c: 257
+bcd.h: 195
+bcm1480: 4096
+bcm1480_int.h: 18356
+bcm1480_l2c.h: 8696
+bcm1480_mc.h: 51843
+bcm1480_regs.h: 42338
+bcm1480_scd.h: 15457
+bcm203x.c: 7066
+bcm3510.c: 21894
+bcm3510.h: 1667
+bcm3510_priv.h: 9194
+bcm47xx: 4096
+bcm47xx_defconfig: 44162
+bcm47xx.h: 914
+bcm47xx_wdt.c: 6278
+bcm5974.c: 22743
+bcm5974.txt: 2275
+bcm.c: 39855
+bcm.h: 2057
+bcom_ata_task.c: 1873
+bcom_fec_rx_task.c: 2688
+bcom_fec_tx_task.c: 3548
+bcom_gen_bd_rx_task.c: 1901
+bcom_gen_bd_tx_task.c: 2118
+bc_svc.c: 2387
+bcu.c: 5507
+bc_xprt.h: 1873
+bdx.bin.ihex: 117765
+beacon.c: 16577
+bearer.c: 17977
+bearer.h: 6277
+beat.c: 5680
+beat.h: 1477
+beat_htab.c: 12023
+beat_hvCall.S: 4654
+beat_interrupt.c: 7398
+beat_interrupt.h: 1147
+beat_iommu.c: 3142
+beat_smp.c: 2934
+beat_spu_priv1.c: 5295
+beat_syscall.h: 9338
+beat_udbg.c: 2419
+beat_wrapper.h: 7284
+be_byteshift.h: 1424
+be_cmds.c: 28134
+be_cmds.h: 21092
+beep.c: 7937
+be_ethtool.c: 10213
+befs: 4096
+befs_fs_types.h: 5040
+befs.h: 3265
+befs.txt: 3636
+be.h: 9794
+be_hw.h: 6736
+belkin_sa.c: 17581
+belkin_sa.h: 5114
+be_main.c: 53536
+be_memmove.h: 770
+Benchmark.h: 14912
+benet: 4096
+berry_charge.c: 5094
+bestcomm: 4096
+bestcomm.c: 13444
+bestcomm.h: 5696
+bestcomm_priv.h: 10178
+be_struct.h: 749
+BF518F-EZBRD_defconfig: 30487
+bf518.h: 3233
+BF526-EZBRD_defconfig: 37925
+BF527-EZKIT_defconfig: 39344
+bf527.h: 3368
+BF533-EZKIT_defconfig: 27699
+bf533.h: 3987
+BF533-STAMP_defconfig: 31991
+bf537.h: 3679
+BF537-STAMP_defconfig: 33322
+BF538-EZKIT_defconfig: 31824
+bf538.h: 3110
+BF548-EZKIT_defconfig: 41918
+bf548.h: 3408
+bf54x-keys.c: 10383
+bf54x_keys.h: 373
+bf54x-lq043fb.c: 19521
+bf54x-lq043.h: 486
+BF561-EZKIT_defconfig: 27483
+bf561.h: 5899
+bf5xx-ac97.c: 10719
+bf5xx-ac97.h: 1698
+bf5xx-ac97-pcm.c: 13449
+bf5xx-ac97-pcm.h: 595
+bf5xx-ad1980.c: 3043
+bf5xx-ad73311.c: 6491
+bf5xx-i2s.c: 8397
+bf5xx-i2s.h: 321
+bf5xx-i2s-pcm.c: 7810
+bf5xx-i2s-pcm.h: 591
+bf5xx_nand.c: 19911
+bf5xx-sport.c: 26015
+bf5xx-sport.h: 5191
+bf5xx-ssm2602.c: 4846
+bfin_5xx.c: 37574
+bfin5xx_spi.h: 3282
+bfin-async-flash.c: 5961
+bfin_cf_pcmcia.c: 8045
+bfind.c: 4484
+bfin_dma_5xx.c: 13838
+bfin-global.h: 3579
+bfin_gpio.c: 31670
+bfin-gpio-notes.txt: 2459
+bfin_jtag_comm.c: 9699
+bfin_ksyms.c: 3302
+bfin_mac.c: 29136
+bfin_mac.h: 1654
+bfin_oprofile.c: 303
+bfin-otp.c: 4874
+bfin_sdh.h: 273
+bfin_serial_5xx.h: 5124
+bfin_simple_timer.h: 446
+bfin_sir.c: 18943
+bfin_sir.h: 5300
+bfin_sport.h: 3839
+bfin_sport_uart.c: 16463
+bfin_sport_uart.h: 3726
+bfin-t350mcqb-fb.c: 16570
+bfin_wdt.c: 11813
+bfrom.h: 3443
+bfs: 4096
+bfs_fs.h: 1830
+bfs.h: 1424
+bfs.txt: 2118
+bfusb.c: 17036
+bif_core_defs_asm.h: 15240
+bif_core_defs.h: 9672
+bif_dma_defs_asm.h: 22539
+bif_dma_defs.h: 14998
+bif_slave_defs_asm.h: 11664
+bif_slave_defs.h: 8256
+big_endian.h: 3729
+big-endian.S: 304
+BIG.FAT.WARNING: 234
+bigsmp_32.c: 6414
+bigsur_defconfig: 32018
+bigsur.h: 1540
+bin2c.c: 702
+bin2hex.c: 755
+bin.c: 11164
+bind_addr.c: 13678
+bind.c: 7327
+bindec.S: 28113
+binder.c: 105864
+binder.h: 9073
+bind.h: 1305
+binding.txt: 3687
+binfmt_aout.c: 13156
+binfmt_elf32.c: 3565
+binfmt_elf.c: 55465
+binfmt_elf_fdpic.c: 48887
+binfmt_elfn32.c: 3368
+binfmt_elfo32.c: 4508
+binfmt_em86.c: 2848
+binfmt_flat.c: 27410
+binfmt_loader.c: 1116
+binfmt_misc.c: 15436
+binfmt_misc.txt: 6108
+binfmt_script.c: 2829
+binfmts.h: 4146
+binfmt_som.c: 7567
+binoffset.c: 4039
+binstr.S: 4302
+bio.c: 39950
+biodoc.txt: 55452
+bio.h: 20583
+bio-integrity.c: 21385
+bios32.c: 17673
+bios.c: 2953
+bioscall.S: 1566
+bioscalls.c: 13235
+bios_ebda.h: 794
+bios.h: 3282
+bios_uv.c: 4629
+bitblit.c: 10909
+bitext.c: 2979
+bitext.h: 613
+bitfield.h: 19835
+bitmap.c: 45202
+bitmap.h: 10515
+bit_operations.h: 5627
+bitops: 4096
+bitops_32.h: 2988
+bitops_64.h: 2428
+bitops.c: 1091
+bitops-grb.h: 6325
+bitops.h: 3153
+bitops-llsc.h: 2819
+bitops_mm.h: 11048
+bitops_no.h: 8097
+bitops-op32.h: 3832
+bitops.S: 2667
+bitrev.c: 2157
+bitrev.h: 270
+bits.h: 2634
+bitsperlong.h: 37
+bit_spinlock.h: 2210
+bitstream.bin.ihex: 33395
+bitstream.HEX: 192281
+bkm_a4t.c: 9149
+bkm_a8.c: 11765
+bkm_ax.h: 4575
+blackfin: 4096
+blackfin.c: 7552
+blackfin.h: 1089
+blackfin_sram.h: 1207
+blacklist.c: 8658
+blacklist.h: 108
+blackstamp.c: 9838
+BlackStamp_defconfig: 27434
+blinken.h: 617
+blizzard.c: 41338
+blizzard.h: 249
+blk-barrier.c: 9923
+blkcipher.c: 19013
+blk-core.c: 65533
+blkdev.h: 38233
+blk-exec.c: 2683
+blk.h: 4565
+blkif.h: 3398
+blk-integrity.c: 10137
+blk-ioc.c: 4083
+blk-map.c: 8314
+blk-merge.c: 9996
+blkpg.h: 1569
+blk-settings.c: 21842
+blk-softirq.c: 4192
+blk-sysfs.c: 12022
+blk-tag.c: 10090
+blk-timeout.c: 5850
+blktrace_api.h: 7347
+blktrace.c: 40749
+blktrans.h: 1935
+bloat-o-meter: 1711
+block: 4096
+block2mtd.c: 10757
+block.c: 15974
+blockcheck.c: 16817
+blockcheck.h: 3928
+blockdev: 4096
+block_dev.c: 37737
+blockgroup_lock.h: 1164
+block.h: 12870
+blockops.S: 2573
+block_validity.c: 6187
+blowfish.c: 17890
+bluecard_cs.c: 21854
+bluetooth: 4096
+bluetooth.h: 4823
+bmac.c: 42545
+bmac.h: 8220
+bmap.c: 17082
+bmap.h: 8896
+bmap_union.h: 1274
+bnep: 4096
+bnep.h: 4313
+bnode.c: 15448
+bnx2: 4096
+bnx2.c: 204472
+bnx2_fw.h: 2909
+bnx2.h: 328128
+bnx2i: 4096
+bnx2i.h: 23900
+bnx2i_hwi.c: 73780
+bnx2i_init.c: 11868
+bnx2i_iscsi.c: 56395
+bnx2i_sysfs.c: 3632
+bnx2-mips-06-4.6.16.fw.ihex: 255140
+bnx2-mips-09-4.6.17.fw.ihex: 255536
+bnx2-rv2p-06-4.6.16.fw.ihex: 19256
+bnx2-rv2p-09-4.6.15.fw.ihex: 21444
+bnx2x_dump.h: 28960
+bnx2x-e1-4.8.53.0.fw.ihex: 455912
+bnx2x-e1h-4.8.53.0.fw.ihex: 529144
+bnx2x_fw_defs.h: 15968
+bnx2x_fw_file_hdr.h: 1226
+bnx2x.h: 36495
+bnx2x_hsi.h: 87970
+bnx2x_init.h: 12172
+bnx2x_init_ops.h: 12435
+bnx2x_link.c: 162411
+bnx2x_link.h: 6119
+bnx2x_main.c: 321334
+bnx2x_reg.h: 308654
+board-1arm.c: 2699
+board-2430sdp.c: 5365
+board-3430sdp.c: 12788
+board-4430sdp.c: 2343
+board-a9m9750dev.c: 3624
+board-a9m9750dev.h: 478
+board-acs5k.c: 5495
+board-afeb-9260v1.c: 5234
+board-ams-delta.c: 6109
+board-ams-delta.h: 3023
+board-ap325rxa.c: 13583
+board-apollon.c: 8566
+board-armadillo5x0.h: 564
+board.c: 3934
+board-cam60.c: 4681
+board-cap9adk.c: 9718
+board-carmeva.c: 4435
+board-csb337.c: 6265
+board-csb637.c: 3642
+board-dk.c: 5862
+board-dm355-evm.c: 7541
+board-dm355-leopard.c: 7584
+board-dm644x-evm.c: 17303
+board-dm646x-evm.c: 5912
+board-dsm320.c: 2919
+board-eb01.c: 1385
+board-eb9200.c: 3461
+board-eb.h: 3843
+board-ecbat91.c: 4404
+board-edosk7760.c: 4611
+board-ek.c: 5054
+boardergo.c: 16200
+boardergo.h: 4069
+board-espt.c: 2426
+board-fsample.c: 8474
+board-generic.c: 1918
+board.h: 3611
+board-h2.c: 10497
+board-h2.h: 1585
+board-h2-mmc.c: 1862
+board-h3.c: 9698
+board-h3.h: 1550
+board-h3-mmc.c: 1668
+board-h4.c: 9524
+board-halibut.c: 2112
+board-innovator.c: 10872
+board-jscc9p9360.c: 457
+board-jscc9p9360.h: 390
+board-kafa.c: 2778
+board-kb9202.c: 3738
+board-ldp.c: 9161
+board-magicpanelr2.c: 11382
+board-micrel.c: 1450
+board-mx21ads.h: 1998
+board-mx27ads.h: 10858
+board-mx27lite.h: 544
+board-mx27pdk.h: 541
+board-mx31ads.h: 3850
+board-mx31lilly.h: 1430
+board-mx31lite.h: 508
+board-mx31moboard.h: 1408
+board-mx31pdk.h: 2120
+board-mx35pdk.h: 1062
+board-neocore926.c: 9196
+board-nokia770.c: 9780
+board-omap3beagle.c: 10647
+board-omap3evm.c: 7649
+board-omap3pandora.c: 10350
+board-osk.c: 15556
+board-overo.c: 11768
+board-palmte.c: 9495
+board-palmtt.c: 7148
+board-palmz71.c: 8139
+board-pb1176.h: 3534
+board-pb11mp.h: 3933
+board-pba8.h: 3279
+board-pbx.h: 4735
+board-pcm037.h: 1039
+board-pcm038.h: 1428
+board-pcm043.h: 1039
+board-perseus2.c: 7106
+board-picotux200.c: 4544
+board-polaris.c: 3273
+board-qil-a9260.c: 6417
+board-qong.h: 590
+board-rut1xx.c: 2111
+board-rx51.c: 2237
+board-rx51-peripherals.c: 9630
+boards: 4096
+board-sam9260ek.c: 8166
+board-sam9261ek.c: 14425
+board-sam9263ek.c: 10154
+board-sam9g20ek.c: 7036
+board-sam9-l9260.c: 5065
+board-sam9rlek.c: 5294
+boards.c: 9634
+board-se7619.c: 368
+board_setup.c: 991
+board-sffsdr.c: 5298
+boards.h: 874
+board-sh7785lcr.c: 8051
+board-shmin.c: 715
+board-sx1.c: 10319
+board-sx1.h: 1472
+board-sx1-mmc.c: 1614
+board.txt: 1400
+board-urquell.c: 4834
+board-usb-a9260.c: 5382
+board-usb-a9263.c: 5692
+board-voiceblue.c: 6718
+board-voiceblue.h: 552
+board-yl-9200.c: 19259
+board-zoom2.c: 2568
+board-zoom-debugboard.c: 3833
+bond_3ad.c: 81880
+bond_3ad.h: 9440
+bond_alb.c: 45790
+bond_alb.h: 4802
+bonding: 4096
+bonding.h: 10602
+bonding.txt: 98243
+bond_ipv6.c: 5432
+bond_main.c: 137243
+bond_sysfs.c: 42050
+bonito64.h: 16247
+bonito-irq.c: 2465
+booke.c: 16034
+booke_emulate.c: 6991
+booke.h: 2429
+booke_interrupts.S: 11644
+booke_wdt.c: 4745
+boot: 4096
+boot2.H16: 14566
+boot.c: 8143
+bootcode.bin.ihex: 604
+boot-elf: 4096
+bootflag.c: 1698
+bootgraph.pl: 5753
+boot.h: 1195
+boot.H16: 14980
+boot_head.S: 4023
+bootinfo.h: 3250
+Booting: 4704
+booting.txt: 5755
+booting-without-of.txt: 61721
+boot.ld: 812
+boot.lds.S: 927
+bootloader.c: 3823
+bootloader.lds: 501
+bootlogo.h: 236895
+bootlogo.pl: 165
+bootmem.c: 19242
+bootmem.h: 4841
+boot-options.txt: 12803
+bootp: 4096
+bootparam.h: 1530
+bootp.c: 5689
+bootp.lds: 695
+bootpz.c: 13415
+boot-redboot: 4096
+Boot.S: 2820
+bootstd.h: 4709
+bootstr_32.c: 1207
+bootstr_64.c: 1055
+bootstrap.asm: 2924
+bootstrap.bin.ihex: 1080
+bootstrap.S: 4829
+boot.txt: 35058
+bootwrapper.txt: 7768
+bootx.h: 5211
+bootx_init.c: 16762
+bottom_half.h: 224
+bounce.c: 6616
+bounds.c: 526
+bpa10x.c: 10967
+bpck6.c: 6457
+bpck.c: 9505
+bpqether.c: 14923
+bpqether.h: 952
+bq24022.c: 4006
+bq24022.h: 728
+bq27x00_battery.c: 8343
+br2684.c: 20774
+braille: 4096
+braille_console.c: 8194
+braille-console.txt: 1458
+branch.c: 5609
+branches: 4096
+branch.h: 794
+br.c: 2297
+brcmphy.h: 277
+brd.c: 13994
+br_device.c: 4305
+break.h: 1512
+break.S: 20777
+brec.c: 13153
+br_fdb.c: 10129
+br_forward.c: 3296
+brg.txt: 450
+bridge: 4096
+bridge.h: 29862
+bridge-regs.h: 1121
+bridge.txt: 382
+br_if.c: 9454
+br_input.c: 4146
+br_ioctl.c: 9353
+briq_panel.c: 5383
+brl_emu.c: 5592
+br_netfilter.c: 28764
+br_netlink.c: 4931
+br_notify.c: 2202
+broadcom.c: 17870
+broadsheetfb.c: 13698
+broadsheetfb.h: 1727
+br_private.h: 7906
+br_private_stp.h: 1654
+br_stp_bpdu.c: 5251
+br_stp.c: 11134
+br_stp_if.c: 7340
+br_stp_timer.c: 4651
+br_sysfs_br.c: 12447
+br_sysfs_if.c: 6540
+Brutus: 1927
+bsbe1.h: 3346
+bsd_comp.c: 29587
+bsg.c: 23964
+bsg.h: 3096
+bsr.c: 8971
+bsru6.h: 3855
+bssdb.c: 59681
+bssdb.h: 9978
+bt3c_cs.c: 16786
+bt431.h: 5854
+bt455.h: 2096
+bt819.c: 14549
+bt819.h: 1082
+bt848.h: 11788
+bt856.c: 7085
+bt866.c: 6222
+bt878.c: 16114
+bt878.h: 4113
+bt87x.c: 30530
+Bt87x.txt: 2597
+bt8xx: 4096
+bt8xxgpio.c: 8476
+bt8xxgpio.txt: 4402
+bt8xx.txt: 3940
+btaudio: 3104
+btcx-risc.c: 6470
+btcx-risc.h: 863
+bte.c: 12913
+bte_error.c: 7665
+bte.h: 7765
+btext.c: 38463
+btext.h: 858
+btfixup.c: 10268
+btfixup.h: 7304
+btfixupprep.c: 11589
+btnode.c: 8474
+btnode.h: 2067
+btree.c: 8032
+btree.h: 5488
+btrfs: 4096
+btrfs_inode.h: 4339
+btrfs.txt: 2918
+btsdio.c: 8446
+bttv: 4096
+bttv-audio-hook.c: 9617
+bttv-audio-hook.h: 1126
+bttv-cards.c: 151213
+bttv-driver.c: 121604
+bttv-gpio.c: 4858
+bttv.h: 14877
+bttv-i2c.c: 10677
+bttv-if.c: 2894
+bttv-input.c: 10597
+bttvp.h: 14108
+bttv-risc.c: 25965
+bttv-vbi.c: 12835
+btuart_cs.c: 15857
+btusb.c: 24625
+buddha.c: 5673
+budget-av.c: 45832
+budget.c: 23026
+budget-ci.c: 46442
+budget-core.c: 17319
+budget.h: 3030
+budget-patch.c: 20598
+buffer.c: 3308
+buffer-format.txt: 4606
+buffer_head.h: 11463
+buffer_head_io.c: 10961
+buffer_head_io.h: 2416
+buffer_icap.c: 10726
+buffer_icap.h: 2297
+buffer_sync.c: 13744
+buffer_sync.h: 432
+bug.c: 423
+bugfix.S: 14062
+bug.h: 400
+BUG-HUNTING: 8326
+BUGS: 235
+bugs_64.c: 778
+bugs.c: 1893
+bugs.h: 451
+BUGS-parport: 319
+build.c: 39439
+builddeb: 5872
+buildtar: 2659
+builtin-annotate.c: 29512
+builtin.h: 1035
+builtin-help.c: 11520
+builtin-list.c: 408
+builtin-record.c: 14786
+builtin-report.c: 35243
+builtin-stat.c: 13788
+builtin-top.c: 17061
+bunzip2.h: 258
+burgundy.c: 25045
+burgundy.h: 4105
+bus.c: 8958
+busctl-regs.h: 2071
+bus.h: 950
+BusLogic.c: 151498
+BusLogic.h: 40976
+BusLogic.txt: 26440
+bus-osm.c: 4125
+busses: 4096
+bust_spinlocks.c: 636
+bus.txt: 4536
+bus_watcher.c: 7864
+butterfly: 2990
+button.c: 12060
+buttons.c: 1516
+bvme6000: 4096
+bvme6000_defconfig: 24611
+bvme6000hw.h: 3490
+bvme6000_scsi.c: 3343
+bw2.c: 9440
+bw-qcam.c: 25715
+bw-qcam.h: 2049
+byteorder: 4096
+byteorder.h: 277
+bzero.S: 3581
+c101.c: 11218
+c16e9e8bb74f14f4504305957e4346e7fc46ea: 296
+c2_ae.c: 9166
+c2_ae.h: 3338
+c2_alloc.c: 4106
+c2.c: 33727
+c2_cm.c: 9984
+c2_cq.c: 10526
+c2.h: 13957
+c2_intr.c: 5630
+c2k.c: 3705
+c2k_defconfig: 48649
+c2k.dts: 8777
+c2_mm.c: 8862
+c2_mq.c: 4622
+c2_mq.h: 3238
+c2p_core.h: 2688
+c2_pd.c: 3012
+c2p.h: 631
+c2p_iplan2.c: 3576
+c2port: 4096
+c2port-duramar2150.c: 3241
+c2port.h: 1788
+c2port.txt: 2848
+c2p_planar.c: 3697
+c2_provider.c: 21747
+c2_provider.h: 4101
+c2_qp.c: 25022
+c2_rnic.c: 16782
+c2_status.h: 5103
+c2_user.h: 2415
+c2_vq.c: 7741
+c2_vq.h: 2530
+c2_wr.h: 35475
+c3000_defconfig: 37418
+c4.c: 33871
+c67x00: 4096
+c67x00-drv.c: 6069
+c67x00.h: 9392
+c67x00-hcd.c: 10012
+c67x00-hcd.h: 4298
+c67x00-ll-hpi.c: 12221
+c67x00-sched.c: 30459
+c6xdigio.c: 13668
+ca0106: 4096
+ca0106.h: 37992
+ca0106_main.c: 59396
+ca0106_mixer.c: 27767
+ca0106_proc.c: 14457
+cacheasm.h: 3274
+cache.c: 10301
+cache-c.c: 733
+cachectl.h: 752
+cache-debugfs.c: 3861
+cache-fa.S: 5726
+cachefeatures.txt: 1538
+cache-feroceon-l2.c: 8394
+cache-feroceon-l2.h: 358
+cachefiles: 4096
+cachefiles.txt: 17132
+cacheflush_32.h: 3544
+cacheflush_64.h: 2543
+cacheflush.h: 7154
+cacheflush_mm.h: 4194
+cache-flush-mn10300.S: 5528
+cacheflush_no.h: 2672
+cacheflush.S: 1897
+cache.h: 4660
+cacheinfo.c: 20221
+cacheinfo.h: 240
+cacheinit.c: 1960
+cache-l2x0.c: 3064
+cache-l2x0.h: 1931
+cache-lock.txt: 1222
+cache-mn10300.S: 6477
+cacheops.h: 2183
+cache-page.c: 1964
+cache.S: 2858
+cache-sh2a.c: 3241
+cache-sh2.c: 2044
+cache-sh3.c: 2486
+cache-sh4.c: 20825
+cache-sh5.c: 27270
+cache-sh7705.c: 5050
+cachetlb.txt: 16265
+cachetype.h: 1643
+cache-v3.S: 3174
+cache-v4.S: 3364
+cache-v4wb.S: 5731
+cache-v4wt.S: 4411
+cache-v6.S: 6450
+cache-v7.S: 7015
+cache-xsc3l2.c: 5806
+caching: 4096
+cafe_ccic: 2424
+cafe_ccic.c: 53700
+cafe_ccic-regs.h: 6845
+cafe_nand.c: 25500
+cagg.c: 110445
+cagg.h: 15067
+ca.h: 3022
+caiaq: 4096
+caleb.c: 3138
+caleb.h: 636
+calgary.h: 2452
+calib.c: 28905
+calib.h: 3835
+calibrate.c: 5121
+callback.c: 9965
+callback.h: 2994
+callback_proc.c: 6012
+callbacks.c: 7878
+callbacks.h: 1495
+callback_srm.S: 2840
+callbacks.txt: 4860
+callback_xdr.c: 18050
+callc.c: 48919
+callchain.c: 3746
+callchain.h: 711
+call_hpt.h: 3078
+calling.h: 5596
+call_o32.S: 2534
+call_pci.h: 7934
+call_sm.h: 1270
+calls.S: 10619
+cam60_defconfig: 28038
+camellia.c: 35950
+camera.h: 1504
+cam.h: 4590
+ca_midi.c: 8689
+ca_midi.h: 2024
+can: 4096
+can.h: 3326
+can.txt: 35254
+canyonlands_defconfig: 25711
+canyonlands.dts: 14369
+capability.c: 8203
+capability.h: 17864
+capability.txt: 618
+capcella_defconfig: 18424
+capcella.h: 1486
+capi: 4096
+capi20.h: 29357
+capi.c: 33038
+capicmd.h: 4663
+capidrv.c: 64650
+capidrv.h: 4862
+capidtmf.c: 26932
+capidtmf.h: 3726
+capifs.c: 5266
+capifs.h: 360
+capifunc.c: 31377
+capifunc.h: 903
+capi.h: 10360
+capilib.c: 4606
+capilli.h: 3567
+capimain.c: 3336
+capiutil.c: 30023
+capiutil.h: 14649
+capmode.c: 8041
+caps.c: 5160
+capture.c: 9562
+capture.h: 702
+card: 4096
+cardbus.c: 6323
+card.c: 10228
+card.h: 4366
+CARDLIST.au0828: 527
+CARDLIST.bttv: 9061
+CARDLIST.cx23885: 1693
+CARDLIST.cx88: 5876
+CARDLIST.em28xx: 4880
+CARDLIST.ivtv: 1163
+CARDLIST.saa7134: 9829
+CARDLIST.tuner: 2995
+CARDLIST.usbvision: 4940
+Cards: 26708
+cards.txt: 4752
+cardtype.h: 39894
+carmel.h: 1969
+carmeva_defconfig: 13180
+carminefb.c: 22690
+carminefb.h: 2251
+carminefb_regs.h: 6940
+carta_random.S: 1032
+casio-e55: 4096
+cassini.bin.ihex: 6246
+cassini.c: 145494
+cassini.h: 125724
+cast5.c: 34939
+cast6.c: 22021
+catalog.c: 10749
+catas.c: 4281
+catc.c: 24085
+cats-hw.c: 2052
+cats-pci.c: 1313
+cavium-octeon: 4096
+cavium-octeon_defconfig: 22786
+cayman_defconfig: 31979
+cb710: 4096
+cb710.h: 6584
+cb710-mmc.c: 22406
+cb710-mmc.h: 3337
+cbaf.c: 20405
+cbc.c: 7621
+cb_das16_cs.c: 25977
+cbe_cpufreq.c: 4980
+cbe_cpufreq.h: 578
+cbe_cpufreq_pervasive.c: 2924
+cbe_cpufreq_pmi.c: 3695
+cbe_powerbutton.c: 3019
+cbe_regs.c: 6692
+cbe_thermal.c: 10724
+cb_pcidas64.c: 122559
+cb_pcidas.c: 54058
+cb_pcidda.c: 24298
+cb_pcidio.c: 9309
+cb_pcimdas.c: 14161
+cb_pcimdda.c: 15282
+cchips: 4096
+ccid2.c: 21699
+ccid2.h: 2480
+ccid3.c: 29348
+ccid3.h: 6401
+ccid.c: 5450
+ccid.h: 7568
+ccids: 4096
+ccio-dma.c: 48900
+ccio-rm-dma.c: 5203
+cciss.c: 121676
+cciss_cmd.h: 8834
+cciss.h: 7343
+cciss_ioctl.h: 6805
+cciss_scsi.c: 49769
+cciss_scsi.h: 3184
+cciss.txt: 6396
+ccm.c: 22059
+ccmd.c: 47173
+ccwdev.h: 6880
+ccwgroup.c: 16375
+ccwgroup.h: 2479
+cd1400.h: 7059
+cd1865.h: 13309
+cd32.txt: 535
+cda2df87ba4ecc7988be7a45d01645e11c9f4c: 307
+cdb89712.c: 5870
+cdc2.c: 6912
+cdc-acm.c: 43081
+cdc-acm.h: 3737
+cdc_eem.c: 9394
+cdc_ether.c: 17432
+cdc.h: 7100
+cdc_subset.c: 10970
+cdc-wdm.c: 19634
+cdefBF512.h: 1386
+cdefBF514.h: 5819
+cdefBF516.h: 16666
+cdefBF518.h: 16668
+cdefBF51x_base.h: 71524
+cdefBF522.h: 1386
+cdefBF525.h: 26762
+cdefBF527.h: 37609
+cdefBF52x_base.h: 71524
+cdefBF532.h: 48301
+cdefBF534.h: 124785
+cdefBF537.h: 13187
+cdefBF538.h: 148152
+cdefBF539.h: 16826
+cdefBF542.h: 35078
+cdefBF544.h: 59758
+cdefBF547.h: 48769
+cdefBF548.h: 98262
+cdefBF549.h: 115636
+cdefBF54x_base.h: 169306
+cdefBF561.h: 117485
+cdef_LPBlackfin.h: 20055
+cdev.c: 25135
+cdev.h: 677
+cdk.h: 12770
+cdrom: 4096
+cdrom.c: 99243
+cdrom.h: 36224
+cdrom-standard.tex: 51371
+cdrom.txt: 19223
+cds.txt: 21022
+ce6230.c: 8126
+ce6230.h: 2306
+ceiva.c: 7563
+cell: 4096
+cell.c: 9326
+cell_defconfig: 37867
+celleb_defconfig: 32091
+celleb_pci.c: 12369
+celleb_pci.h: 1402
+celleb_scc_epci.c: 10052
+celleb_scc.h: 7871
+celleb_scc_pciex.c: 15023
+celleb_scc_sio.c: 2600
+celleb_scc_uhc.c: 2518
+celleb_setup.c: 6097
+cell_edac.c: 7394
+cell-pmu.h: 4133
+cell-regs.h: 9211
+centaur.c: 5432
+central.c: 6181
+CERF: 1215
+cerf.c: 3449
+cerfcube_defconfig: 17978
+cerf.h: 810
+cerr-sb1.c: 16742
+cevt-bcm1480.c: 4444
+cevt-ds1287.c: 2833
+cevt-gt641xx.c: 3662
+cevt-r4k.c: 5115
+cevt-r4k.h: 1421
+cevt-sb1250.c: 4380
+cevt-smtc.c: 8920
+cevt-txx9.c: 5694
+cex-gen.S: 1009
+cex-oct.S: 1574
+cex-sb1.S: 4707
+cfag12864b: 3173
+cfag12864b.c: 8350
+cfag12864b-example.c: 5897
+cfag12864bfb.c: 4656
+cfag12864b.h: 2147
+cfbcopyarea.c: 11312
+cfbfillrect.c: 8940
+cfbimgblt.c: 8396
+cfe: 4096
+cfe_api.c: 11219
+cfe_api.h: 3833
+cfe_api_int.h: 4031
+cfe.c: 8423
+cfe_console.c: 1737
+cfe_error.h: 2197
+cfg80211.c: 10563
+cfg80211.h: 1079
+cfg.c: 35379
+cfg.h: 155
+cfi_cmdset_0001.c: 73671
+cfi_cmdset_0002.c: 53117
+cfi_cmdset_0020.c: 38615
+cfi_endian.h: 1238
+cfi_flagadm.c: 3947
+cfi.h: 13714
+cfi_probe.c: 11670
+cfi_util.c: 5934
+cfm.c: 16482
+cfq-iosched.c: 65456
+cfunc.c: 33674
+cfunc.h: 23021
+cg14.c: 15044
+cg3.c: 11707
+cg6.c: 22284
+cgroup.c: 95997
+cgroup_debug.c: 2057
+cgroup_freezer.c: 9146
+cgroup.h: 15604
+cgroups: 4096
+cgroupstats.h: 2155
+cgroupstats.txt: 1307
+cgroups.txt: 21831
+cgroup_subsys.h: 697
+ch341.c: 15479
+ch9.h: 24667
+chafsr.h: 9671
+chainiv.c: 8763
+changebit.S: 617
+ChangeLog: 18049
+CHANGELOG: 18049
+ChangeLog.1992-1997: 59954
+ChangeLog.arcmsr: 6754
+ChangeLog.history: 25741
+ChangeLog.ide-cd.1994-2004: 15586
+ChangeLog.ide-floppy.1996-2002: 4068
+ChangeLog.ide-tape.1995-2002: 16249
+ChangeLog.ips: 5304
+ChangeLog.lpfc: 89671
+ChangeLog.megaraid: 23975
+ChangeLog.megaraid_sas: 12624
+ChangeLog.ncr53c8xx: 22786
+ChangeLog.sym53c8xx: 29464
+ChangeLog.sym53c8xx_2: 6011
+Changes: 4725
+CHANGES: 4725
+chan_kern.c: 13142
+chan_kern.h: 1587
+chan_user.c: 7101
+chan_user.h: 1710
+char: 4096
+char_dev.c: 13712
+chb.c: 5975
+ch.c: 24601
+check-all.sh: 434
+check.c: 3835
+check-gas: 277
+check-gas-asm.S: 37
+check.h: 551
+checkincludes.pl: 529
+checkkconfigsymbols.sh: 1851
+checklist.c: 8211
+checklist.txt: 14315
+check-lxdialog.sh: 1653
+check-model.c: 47
+checkpatch.pl: 70566
+checkpoint.c: 21921
+checks.c: 15663
+check-segrel.lds: 203
+check-segrel.S: 45
+check-serialize.S: 41
+check.sh: 214
+check_signature.c: 599
+checkstack.pl: 5332
+checksum_32.h: 4895
+checksum_32.S: 4739
+checksum_64.h: 5349
+checksum_64.S: 6192
+checksum.c: 4610
+checksumcopy.S: 2455
+checksum.h: 6169
+checksum_mm.h: 3391
+checksum_no.h: 3074
+checksum.S: 9073
+checksyscalls.sh: 5661
+check-text-align.S: 69
+checkversion.pl: 1867
+chelsio: 4096
+cherrs.S: 15233
+chio.h: 5287
+chip.c: 15518
+chip.h: 5099
+chipram.c: 3350
+chipreg.c: 2405
+chips: 4096
+chipsfb.c: 12752
+chlist.h: 30
+chmc.c: 20666
+chmctrl.h: 8057
+chp.c: 17406
+chp.h: 1489
+chpid.h: 1040
+chrp: 4096
+chrp32_defconfig: 40160
+chrp.h: 308
+chsc.c: 22534
+chsc.h: 2470
+chsc_sch.c: 19838
+chsc_sch.h: 179
+chunk.c: 8172
+ci13xxx_udc.c: 69484
+ci13xxx_udc.h: 6227
+cia.c: 4343
+cicada.c: 3994
+cic.c: 14355
+cifs: 4096
+cif.S: 1000
+cifsacl.c: 21375
+cifsacl.h: 2405
+cifs_debug.c: 21856
+cifs_debug.h: 2329
+cifs_dfs_ref.c: 9982
+cifsencrypt.c: 12795
+cifsencrypt.h: 1256
+cifsfs.c: 31585
+cifsfs.h: 4854
+cifs_fs_sb.h: 2432
+cifsglob.h: 23265
+cifspdu.h: 81322
+cifsproto.h: 16968
+cifssmb.c: 173618
+cifs_spnego.c: 4357
+cifs_spnego.h: 1628
+cifs.txt: 2406
+cifs_unicode.c: 7190
+cifs_unicode.h: 8878
+cifs_uniupr.h: 12874
+cimax2.c: 11227
+cimax2.h: 1921
+cinergyT2-core.c: 6717
+cinergyT2-fe.c: 8456
+cinergyT2.h: 3001
+cinit.c: 59044
+cio: 4096
+cio.c: 27748
+cio_debug.h: 849
+cio.h: 4879
+cipher.c: 7783
+cipso_ipv4.c: 64343
+cipso_ipv4.h: 7616
+cipso_ipv4.txt: 2252
+circ_buf.h: 1000
+cirrusfb.c: 77607
+cirrusfb.txt: 1934
+cirrus.h: 8939
+cis: 4096
+ciscode.h: 3364
+cisreg.h: 2804
+cistpl.c: 38770
+cistpl.h: 14596
+ci.txt: 6753
+ck804xrom.c: 10948
+class: 4096
+class.c: 12662
+class_to_string.h: 1508
+class.txt: 4758
+claw.c: 115821
+claw.h: 14619
+clcd.c: 5668
+clcd.h: 6601
+cleanfile: 3492
+cleanpatch: 5132
+cleanup.c: 28008
+clearbit.S: 613
+clear_page_64.S: 969
+clear_page.S: 401
+clear_user.S: 2687
+clep7312.c: 1478
+client.c: 45575
+client.h: 7071
+clinkage.h: 27
+clip.c: 24997
+clk.c: 774
+clkdev.c: 3488
+clkdev.h: 122
+clkgen_defs_asm.h: 7393
+clkgen_defs.h: 5421
+clk.h: 4465
+clk_interface.h: 683
+clksupport.h: 844
+clk.txt: 1173
+clnt.c: 42336
+clnt.h: 5095
+clntlock.c: 6865
+clntproc.c: 21263
+clock24xx.c: 22943
+clock24xx.h: 82888
+clock34xx.c: 31225
+clock34xx.h: 84973
+clock-7x01a.c: 4770
+clock.c: 6387
+clockchips.h: 4535
+clock-cpg.c: 5839
+clock-dclk.c: 4423
+clockdomain.c: 16366
+clockdomain.h: 3231
+clockdomains.h: 9108
+clockevents.c: 6244
+clock_getres.S: 1020
+clock_gettime.S: 2948
+clock.h: 1320
+clock_imx21.c: 23302
+clock_imx27.c: 22042
+clock-imx35.c: 13016
+clocking.txt: 1582
+clocks.c: 2153
+clocks.h: 2092
+clock-sh3.c: 2204
+clock-sh4-202.c: 3818
+clock-sh4.c: 1967
+clock-sh5.c: 1848
+clock-sh7201.c: 1982
+clock-sh7203.c: 1936
+clock-sh7206.c: 1931
+clock-sh7343.c: 6574
+clock-sh7366.c: 6500
+clock-sh7619.c: 1741
+clock-sh7705.c: 2140
+clock-sh7706.c: 2055
+clock-sh7709.c: 2302
+clock-sh7710.c: 1874
+clock-sh7712.c: 1592
+clock-sh7722.c: 5683
+clock-sh7723.c: 7223
+clock-sh7724.c: 7654
+clock-sh7763.c: 2503
+clock-sh7770.c: 1749
+clock-sh7780.c: 2630
+clock-sh7785.c: 3792
+clock-sh7786.c: 3252
+clock-shx3.c: 2959
+clocks-init.c: 2524
+clocksource: 4096
+clocksource.c: 16881
+clocksource.h: 11531
+clock.txt: 2443
+clone.c: 1295
+clps7111.h: 5605
+clps711x.c: 13340
+clps711xfb.c: 10751
+cls_api.c: 14078
+cls_basic.c: 6522
+cls_cgroup.c: 6506
+cls_flow.c: 15621
+cls_fw.c: 8499
+cls_route.c: 12482
+cls_rsvp6.c: 768
+cls_rsvp.c: 761
+cls_rsvp.h: 14927
+cls_tcindex.c: 11961
+cls_u32.c: 16562
+cluster: 4096
+cluster.c: 14916
+cluster.h: 3649
+clut_vga16.ppm: 230
+cm109.c: 24186
+cm4000_cs.c: 50839
+cm4000_cs.h: 1822
+cm4040_cs.c: 17240
+cm4040_cs.h: 1435
+cm5200_defconfig: 30374
+cm5200.dts: 5770
+cm9780.h: 1648
+cma.c: 76031
+cmap_xfbdev.txt: 1927
+cm_bf527.c: 24357
+CM-BF527_defconfig: 33449
+cm_bf533.c: 10441
+CM-BF533_defconfig: 17784
+cm_bf537.c: 15825
+CM-BF537E_defconfig: 22519
+CM-BF537U_defconfig: 18739
+cm_bf548.c: 20079
+CM-BF548_defconfig: 31514
+cm_bf561.c: 11463
+CM-BF561_defconfig: 19376
+cmb.h: 2128
+cm.c: 108467
+cmd640.c: 22942
+cmd64x.c: 13588
+cmdblk.h: 1843
+cmd.c: 12040
+cmd.h: 3292
+cmdline.c: 774
+cmdlinepart.c: 9405
+cmdpkt.h: 4387
+cmdresp.c: 16004
+cmf.c: 34004
+cm.h: 3735
+CMI8330: 3229
+cmi8330.c: 22466
+cmipci.c: 104710
+CMIPCI.txt: 9357
+cmmap.c: 75502
+cmm.c: 74564
+cmm_data_2860.c: 34802
+cmm_data_2870.c: 28944
+cmm_data.c: 42
+cmm_info.c: 42
+cmm_sanity.c: 44
+cm_msgs.h: 21469
+cmmsta.c: 182636
+cmm_sync.c: 42
+cmm_wpa.c: 41
+cmode.S: 4744
+cmpdi2.c: 435
+cmp.h: 486
+cmpxchg_32.h: 9438
+cmpxchg_64.h: 4582
+cmpxchg.c: 1500
+cmpxchg-grb.h: 2053
+cmpxchg.h: 3173
+cmpxchg-irq.h: 796
+cmpxchg-llsc.h: 1420
+cmpxchg-local.h: 1369
+cm-regbits-24xx.h: 14321
+cm-regbits-34xx.h: 26454
+cm_sbs.c: 3007
+cmservice.c: 13501
+cmtdef.h: 23113
+cmt.h: 1786
+cmtp: 4096
+cmtp.h: 3099
+cmu.c: 5791
+cm-x255.c: 5295
+cm-x270.c: 7295
+cmx270_nand.c: 6063
+cm-x2xx.c: 11698
+cm_x2xx_defconfig: 48725
+cm-x2xx-pci.c: 5404
+cm-x2xx-pci.h: 460
+cm-x300.c: 11712
+cm_x300_defconfig: 39363
+cn_cifs.h: 1323
+cnic.c: 66079
+cnic_defs.h: 16086
+cnic.h: 7097
+cnic_if.h: 7270
+cnode.c: 4219
+cn_proc.c: 7019
+cn_proc.h: 3206
+cn_queue.c: 6122
+cnt32_to_63.h: 3193
+cn_test.c: 4483
+cnv_float.h: 13001
+coalesced_mmio.c: 3435
+coalesced_mmio.h: 652
+cobalt: 4096
+cobalt_btns.c: 4645
+cobalt_defconfig: 29161
+cobalt.h: 614
+cobalt_lcdfb.c: 7871
+cobra.c: 6747
+c-octeon.c: 7206
+coda: 4096
+coda_cache.h: 673
+coda_fs_i.h: 1700
+coda.h: 17708
+coda_int.h: 434
+coda_linux.c: 5125
+coda_linux.h: 2883
+coda_psdev.h: 3200
+coda.txt: 49725
+code16gcc.h: 388
+codecs: 12288
+codec.txt: 5826
+code-patching.c: 12715
+code-patching.h: 1744
+CodingStyle: 29820
+coff.h: 12413
+coh901327_wdt.c: 14160
+coid.c: 75657
+coldfire: 4096
+coldfire.h: 1492
+colibri.h: 1059
+colibri-pxa270.c: 3375
+colibri_pxa270_defconfig: 42182
+colibri-pxa300.c: 4795
+colibri_pxa300_defconfig: 27217
+colibri-pxa320.c: 4735
+colibri-pxa3xx.c: 3817
+collate.c: 3675
+collate.h: 1705
+collie.c: 7329
+collie_defconfig: 18902
+collie.h: 3779
+color.c: 4817
+color.h: 1187
+com20020.c: 10296
+com20020_cs.c: 10301
+com20020.h: 3624
+com20020-isa.c: 5185
+com20020-pci.c: 5701
+com90io.c: 11118
+com90xx.c: 18469
+comedi: 4096
+comedi_bond.c: 17048
+comedi_compat32.c: 17423
+comedi_compat32.h: 1861
+comedidev.h: 16882
+comedi_fc.c: 3317
+comedi_fc.h: 2462
+comedi_fops.c: 60764
+comedi_fops.h: 191
+comedi.h: 29999
+comedi_ksyms.c: 2407
+comedilib.h: 7998
+comedi_parport.c: 9181
+comedi_pci.h: 1605
+comedi_test.c: 14760
+command.c: 8449
+command.h: 8829
+command-list.txt: 288
+commands.c: 25775
+commands.h: 11936
+comm.c: 4950
+commctrl.c: 23882
+comminit.c: 13072
+commit.c: 32855
+commit-msg.sample: 894
+common: 4096
+common.c: 25712
+commoncap.c: 27617
+common_defconfig: 11971
+common.h: 12299
+CommonIO: 4651
+common.lds.S: 2212
+common-offsets.h: 1451
+common-pci.c: 12979
+common_perm_to_string.h: 1100
+common-smdk.c: 4474
+common-smdk.h: 451
+commproc.c: 8070
+commproc.h: 25607
+commsup.c: 51665
+CompactFlash: 1735
+compal-laptop.c: 8886
+comparator.h: 5271
+compartmentalisation.txt: 1944
+compat_audit.c: 664
+compat_binfmt_elf.c: 3496
+compat.c: 2196
+compat_exec_domain.c: 741
+compat.h: 369
+compatibility-list.txt: 1345
+compat_ioctl.c: 7581
+compat_ioctl.h: 4449
+compat_linux.c: 21127
+compat_linux.h: 7320
+compatmac.h: 332
+compat_mq.c: 4132
+compat_ptrace.h: 2572
+compat_rt_sigframe.h: 1846
+compat_signal.c: 17351
+compat_signal.h: 57
+compat-signal.h: 2664
+compat_ucontext.h: 552
+compat_wrapper.S: 48644
+compiler-gcc3.h: 823
+compiler-gcc4.h: 1407
+compiler-gcc.h: 3118
+compiler.h: 4524
+compiler-intel.h: 746
+completion.h: 3226
+composite.c: 30121
+composite.h: 14982
+compr.c: 10363
+compress.c: 1839
+compressed: 4096
+compress.h: 974
+compression.c: 18461
+compression.h: 1742
+compr.h: 3025
+compr_lzo.c: 2312
+compr_rtime.c: 2867
+compr_rubin.c: 8932
+compr_zlib.c: 5850
+computone.txt: 17570
+comstats.h: 3120
+con3215.c: 30319
+con3270.c: 15947
+concap.h: 3778
+concat.h: 454
+conditional.c: 11225
+conditional.h: 617
+conex.c: 32880
+conf.c: 11969
+confdata.c: 19322
+config: 2695
+config3270.sh: 2009
+config.c: 24033
+config.c.in: 496
+config_defs_asm.h: 5405
+config_defs.h: 4370
+configfs: 4096
+configfs_example_explicit.c: 12619
+configfs_example_macros.c: 11555
+configfs.h: 8837
+configfs_internal.h: 5080
+configfs.txt: 21464
+config.h: 1142
+config.mk: 7917
+config-osm.c: 2170
+config_roms.c: 4579
+config_roms.h: 588
+configs: 4096
+configs.c: 2818
+configuring.txt: 4139
+cong.c: 12223
+conmakehash.c: 6121
+connect.c: 38
+connection.c: 13263
+connector: 4096
+connector.c: 11327
+connector.h: 4405
+connector.txt: 6503
+conntrack.h: 810
+consistent.c: 3927
+console: 4096
+console_32.c: 2071
+console_64.c: 1575
+console.c: 7199
+console.h: 2080
+consolemap.c: 22885
+consolemap.h: 1029
+console_struct.h: 5109
+console.txt: 5814
+constants.c: 49479
+constants.h: 2939
+const.h: 596
+constraint.h: 2093
+consumer.h: 8894
+consumer.txt: 6869
+container.c: 7095
+container.h: 198
+contec_pci_dio.c: 5763
+context.c: 1678
+context.h: 3703
+context.S: 6412
+contig.c: 7791
+contregs.h: 3351
+CONTRIBUTORS: 495
+contributors.txt: 3035
+control.c: 43620
+control_compat.c: 11584
+controlfb.c: 27775
+controlfb.h: 4696
+control.h: 9928
+ControlNames.txt: 2085
+control_w.h: 1820
+cookie.c: 13149
+coprocessor.h: 5194
+coprocessor.S: 7277
+coproc.h: 362
+cops.c: 29453
+cops_ffdrv.h: 21384
+cops.h: 1400
+cops_ltdrv.h: 9491
+cops.txt: 2768
+copy_32.S: 9822
+copy.c: 2883
+copy_from_user.S: 1986
+COPYING: 18693
+COPYING.LIB: 25265
+copy_in_user.S: 1659
+copy_page_64.S: 2337
+copypage_64.S: 2011
+copypage-fa.c: 2349
+copypage-feroceon.c: 3145
+copy_page_mck.S: 5871
+copy_page.S: 532
+copypage-v3.c: 2110
+copypage-v4mc.c: 3649
+copypage-v4wb.c: 2820
+copypage-v4wt.c: 2403
+copypage-v6.c: 3822
+copypage-xsc3.c: 2840
+copypage-xscale.c: 3881
+copy.S: 1321
+copy_template.S: 5586
+copy_to_user.S: 2016
+copy_user_64.S: 5420
+copyuser_64.S: 9936
+copy_user_memcpy.S: 5245
+copy_user_nocache_64.S: 2468
+copy_user.S: 2573
+core: 4096
+core_apecs.c: 10176
+core_apecs.h: 17281
+coreb.c: 1844
+core.c: 24656
+core-card.c: 15330
+core-cdev.c: 37224
+core_cia.c: 33365
+core_cia.h: 15760
+core-device.c: 32375
+coredump.c: 5613
+core.h: 5921
+core_irongate.c: 10486
+core_irongate.h: 6754
+core-iso.c: 8971
+core_lca.c: 14096
+core_lca.h: 11596
+core_locking.txt: 4081
+core_marvel.c: 25082
+core_marvel.h: 9350
+core_mcpcia.c: 16238
+core_mcpcia.h: 11691
+core_polaris.c: 4523
+core_polaris.h: 2948
+core_priv.h: 1817
+core_t2.c: 16416
+core_t2.h: 20353
+coretemp: 1672
+coretemp.c: 11947
+core_titan.c: 20020
+core_titan.h: 11455
+core-topology.c: 15332
+core-transaction.c: 27218
+core_tsunami.c: 13148
+core_tsunami.h: 8469
+core.txt: 804
+core_wildfire.c: 17607
+core_wildfire.h: 8616
+corgi.c: 9471
+corgi_defconfig: 47365
+corgi.h: 4831
+corgikbd.c: 12406
+corgi_lcd.c: 16845
+corgi_lcd.h: 421
+corgi_pm.c: 7155
+corgi_ssp.c: 7384
+corgi_ts.c: 9648
+cosa.c: 59334
+cosa.h: 4349
+country.h: 4726
+cow.h: 1883
+cow_sys.h: 692
+cow_user.c: 12166
+coyote.h: 949
+coyote-pci.c: 1459
+coyote-setup.c: 3158
+cp1emu.c: 28793
+cp210x.c: 24866
+cp437.uni: 4426
+cp6.c: 1398
+cpc925_edac.c: 30540
+cpc.h: 16904
+cpci_hotplug_core.c: 17267
+cpci_hotplug.h: 3193
+cpci_hotplug_pci.c: 7823
+cpcihp_generic.c: 6519
+cpcihp_zt5550.c: 8619
+cpcihp_zt5550.h: 2730
+cpc_int.h: 2284
+cpcmd.c: 3087
+cpcmd.h: 1259
+cpc-usb: 4096
+cpc-usb_drv.c: 28935
+cpcusb.h: 2856
+cpfile.c: 24964
+cpfile.h: 1680
+cphy.h: 6427
+cpia2: 4096
+cpia2_core.c: 77737
+cpia2dev.h: 1919
+cpia2.h: 13192
+cpia2_overview.txt: 2357
+cpia2_registers.h: 17890
+cpia2_usb.c: 25426
+cpia2_v4l.c: 50779
+cpia.c: 114212
+cpia.h: 11791
+cpia_pp.c: 22139
+cpia_usb.c: 16084
+cp_intc.c: 3984
+cp_intc.h: 2302
+cpl5_cmd.h: 12577
+cplb.h: 4597
+cplbinfo.c: 3920
+cplbinit.c: 3353
+cplbinit.h: 2491
+cplbmgr.c: 9975
+cplb-mpu: 4096
+cplb-nompu: 4096
+cpm: 4096
+cpm1.c: 19027
+cpm1.h: 23000
+cpm2.c: 8657
+cpm2.h: 51335
+cpm2_pic.c: 7028
+cpm2_pic.h: 177
+cpmac.c: 35475
+cpm_common.c: 8715
+cpm.h: 3601
+cpm_qe: 4096
+cpm-serial.c: 5276
+cpm.txt: 2279
+cpm_uart: 4096
+cpm_uart_core.c: 34184
+cpm_uart_cpm1.c: 4062
+cpm_uart_cpm1.h: 630
+cpm_uart_cpm2.c: 4728
+cpm_uart_cpm2.h: 692
+cpm_uart.h: 3846
+cppi_dma.c: 44672
+cppi_dma.h: 3257
+cpqarray.c: 48267
+cpqarray.h: 3023
+cpqarray.txt: 2224
+cpqphp_core.c: 37277
+cpqphp_ctrl.c: 77860
+cpqphp.h: 22122
+cpqphp_nvram.c: 13820
+cpqphp_nvram.h: 1534
+cpqphp_pci.c: 39788
+cpqphp_sysfs.c: 5682
+cprecomp.h: 1072
+cpsmgr.c: 18525
+cpu: 4096
+cpu5wdt.c: 6940
+cpuacct.txt: 1941
+cpu_buffer.c: 11402
+cpu_buffer.h: 2876
+cpu-bugs64.c: 7627
+cpu.c: 5945
+cpucheck.c: 6054
+cpu-common: 4096
+cpudata_32.h: 574
+cpudata_64.h: 1041
+cpudata.h: 184
+cpu_debug.c: 17937
+cpu_debug.h: 3759
+cpu-drivers.txt: 7387
+cpufeature.h: 13827
+cpu-feature-overrides.h: 1176
+cpu-features.h: 7307
+cpu_features.txt: 2681
+cpufreq: 4096
+cpu-freq: 4096
+cpufreq_32.c: 18804
+cpufreq_64.c: 20116
+cpufreq.c: 49742
+cpufreq_conservative.c: 18026
+cpu-freq.h: 2392
+cpufreq.h: 12164
+cpufreq-nforce2.c: 9537
+cpufreq-nforce2.txt: 597
+cpufreq_ondemand.c: 19342
+cpufreq_performance.c: 1553
+cpufreq_powersave.c: 1625
+cpufreq-pxa2xx.c: 14833
+cpufreq-pxa3xx.c: 6493
+cpufreq_spudemand.c: 4449
+cpufreq_stats.c: 9729
+cpufreq-stats.txt: 5021
+cpufreq_userspace.c: 6109
+cpu.h: 1297
+cpu-h7201.c: 1510
+cpu-h7202.c: 5243
+cpu_hotplug.c: 2052
+cpu-hotplug-spec: 1155
+cpu-hotplug.txt: 14935
+cpuid.c: 5549
+cpuid.h: 617
+cpuidle: 4096
+cpuidle.c: 8664
+cpuidle.h: 1058
+cpu_imx27.c: 1739
+cpuinfo.c: 2141
+cpu-info.h: 2924
+cpuinfo.h: 2135
+cpuinfo-pvr-full.c: 2822
+cpuinfo-static.c: 4940
+cpu-irqs.h: 2654
+cpu-load.txt: 3110
+cpumap.c: 10894
+cpumap.h: 320
+cpumask.c: 4643
+cpumask.h: 381
+cpu-multi32.h: 1743
+cpu-omap.c: 4053
+cpu-probe.c: 23180
+cpu-regs.h: 14601
+cpu-sa1100.c: 7866
+cpu-sa1110.c: 9518
+cpuset.c: 72697
+cpuset.h: 4740
+cpusets.txt: 36191
+cpu_setup_44x.S: 1639
+cpu_setup_6xx.S: 11167
+cpu_setup_fsl_booke.S: 1766
+cpu_setup_pa6t.S: 1218
+cpu_setup_ppc970.S: 3704
+cpu-sh2: 4096
+cpu-sh2a: 4096
+cpu-sh3: 4096
+cpu-sh4: 4096
+cpu-sh5: 4096
+cpu-single.h: 1429
+cputable.c: 57765
+cputable.h: 19753
+cputhreads.h: 1572
+cputime.h: 118
+cputopology.txt: 3013
+cputype.h: 840
+cpu_vect.h: 1321
+cp_vers.h: 933
+cpwd.c: 16512
+cq.c: 20469
+c-qcam.c: 19812
+CQcam.txt: 7069
+cq_desc.h: 2507
+cq_enet_desc.h: 6342
+cq_exch_desc.h: 5837
+cq.h: 4130
+c-r3k.c: 8056
+c-r4k.c: 37720
+cramfs: 4096
+cramfs_fs.h: 2930
+cramfs_fs_sb.h: 343
+cramfs.txt: 2599
+crash.c: 9898
+crash_dump_32.c: 2149
+crash_dump_64.c: 1417
+crash_dump.c: 3851
+crash_dump.h: 2002
+cr_bllcd.c: 7402
+crc16.c: 2838
+crc16.h: 622
+crc32.c: 15299
+crc32c.c: 8200
+crc32c.h: 254
+crc32c-intel.c: 4975
+crc32defs.h: 1072
+crc32.h: 880
+crc32hash.c: 654
+crc7.c: 2329
+crc7.h: 272
+crc-ccitt.c: 3052
+crc-ccitt.h: 330
+crc.h: 880
+crc-itu-t.c: 2892
+crc-itu-t.h: 615
+crc-t10dif.c: 2965
+crc-t10dif.h: 140
+cred.c: 14888
+credentials.txt: 20932
+cred.h: 10905
+cred-internals.h: 559
+CREDITS: 603
+crime.c: 2833
+crime.h: 5271
+cris: 4096
+cris_defs_asm.h: 3805
+crisksyms.c: 472
+cris_supp_reg.h: 198
+crisv10.c: 129158
+crisv10.h: 4289
+crm_regs.h: 1700
+cr_pll.c: 4842
+crt0_ram.S: 2152
+crt0_rom.S: 3157
+crt0.S: 1979
+crtsavres.S: 6123
+crunch-bits.S: 8521
+crunch.c: 2001
+crw.c: 4007
+crw.h: 2025
+cryptd.c: 16974
+cryptd.h: 650
+crypto: 4096
+crypto4xx_alg.c: 8383
+crypto4xx_core.c: 34847
+crypto4xx_core.h: 5634
+crypto4xx_reg_def.h: 7646
+crypto4xx_sa.c: 2984
+crypto4xx_sa.h: 5742
+crypto.c: 16089
+crypto_compat.h: 2294
+cryptocop.c: 111134
+cryptocop.h: 7614
+crypto_des.h: 516
+crypto.h: 35141
+cryptohash.h: 264
+cryptoloop.c: 5005
+crypto_null.c: 5051
+crypto_wq.c: 896
+crypto_wq.h: 122
+crypt_s390.h: 10190
+cs4231.c: 6021
+cs4231-regs.h: 8547
+cs4236.c: 22848
+cs4236_lib.c: 35470
+cs423x: 4096
+cs4270.c: 26832
+cs4270.h: 804
+cs4281.c: 66411
+cs4362a.h: 2039
+cs4398.h: 1968
+cs461x.txt: 2184
+cs46xx: 4096
+cs46xx.c: 5301
+cs46xx_dsp_scb_types.h: 28137
+cs46xx_dsp_spos.h: 6198
+cs46xx_dsp_task_types.h: 7293
+cs46xx.h: 73681
+cs46xx_image.h: 155782
+cs46xx_lib.c: 107227
+cs46xx_lib.h: 8586
+cs5345.c: 5839
+cs5345.h: 1210
+cs53l32a.c: 5932
+cs53l32a.h: 1196
+cs5520.c: 4777
+cs5530.c: 8332
+cs5535audio: 4096
+cs5535audio.c: 10538
+cs5535audio.h: 4162
+cs5535audio_olpc.c: 4595
+cs5535audio_pcm.c: 13419
+cs5535audio_pm.c: 4043
+cs5535.c: 6298
+cs5535_gpio.c: 6000
+cs5536.c: 7861
+cs553x_nand.c: 10268
+cs8403.h: 8833
+cs8420.h: 1681
+cs8427.c: 18610
+cs8427.h: 10572
+cs89712.h: 1848
+cs89x0.c: 59868
+cs89x0.h: 16242
+cs89x0.txt: 25508
+csb337_defconfig: 28177
+csb637_defconfig: 29026
+csb701.c: 1321
+csb726.c: 7527
+csb726.h: 658
+cs.c: 21706
+cscanmgr.c: 14014
+cs.h: 6099
+cs_internal.h: 7245
+csr1212.c: 38810
+csr1212.h: 14571
+csr.c: 26430
+csrc-bcm1480.c: 1705
+csrc-ioasic.c: 1796
+csrc-octeon.c: 1473
+csrc-r4k.c: 885
+csrc-sb1250.c: 2176
+csr.h: 2690
+css.c: 26134
+css.h: 4460
+cstate.c: 4904
+cs_types.h: 934
+csum-copy_64.S: 4160
+csum_copy_from_user.S: 439
+csum_copy.S: 7018
+csum_copy_to_user.S: 431
+csumcpfruser.S: 1663
+csum_ipv6_magic.S: 2885
+csumipv6.S: 696
+csum-partial_64.c: 3530
+csum_partial_copy.c: 8909
+csum_partial_copy_generic.S: 1729
+csumpartialcopygeneric.S: 6850
+csumpartialcopy.S: 1151
+csumpartialcopyuser.S: 2378
+csum_partial.S: 16737
+csumpartial.S: 3126
+csum-wrappers_64.c: 3926
+ct20k1reg.h: 20603
+ct20k2reg.h: 3088
+ct82c710.c: 6778
+ctamixer.c: 10033
+ctamixer.h: 2795
+ctatc.c: 42227
+ctatc.h: 5058
+ctcm_dbug.c: 1932
+ctcm_dbug.h: 3316
+ctcm_fsms.c: 75291
+ctcm_fsms.h: 8271
+ctcm_main.c: 45768
+ctcm_main.h: 6938
+ctcm_mpc.c: 59919
+ctcm_mpc.h: 5324
+ctcm_sysfs.c: 5171
+ctdaio.c: 17904
+ctdaio.h: 3291
+cthardware.c: 1688
+cthardware.h: 7286
+cthw20k1.c: 49680
+cthw20k1.h: 598
+cthw20k2.c: 49114
+cthw20k2.h: 598
+ctimap.c: 2516
+ctimap.h: 1167
+ctkip.c: 17399
+ctl_unnumbered.txt: 962
+ctmixer.c: 28786
+ctmixer.h: 1691
+ctpcm.c: 11244
+ctpcm.h: 612
+ctr.c: 11026
+ctree.c: 111552
+ctree.h: 75158
+ctresource.c: 5825
+ctresource.h: 2267
+ctr.h: 524
+ctrlchar.c: 1752
+ctrlchar.h: 484
+cts.c: 10045
+ctsrc.c: 19870
+ctsrc.h: 4527
+cttimer.c: 11342
+cttimer.h: 686
+ctvmem.c: 5666
+ctvmem.h: 1787
+c-tx39.c: 10852
+ctxfi: 4096
+ctxrx.c: 147975
+ctype.c: 1041
+ctype.h: 1399
+cu3088.c: 3577
+cu3088.h: 848
+cuboot-52xx.c: 1660
+cuboot-824x.c: 1224
+cuboot-83xx.c: 1525
+cuboot-85xx.c: 1673
+cuboot-85xx-cpm2.c: 1764
+cuboot-8xx.c: 1149
+cuboot-acadia.c: 4964
+cuboot-amigaone.c: 868
+cuboot-bamboo.c: 689
+cuboot.c: 944
+cuboot-c2k.c: 4884
+cuboot-ebony.c: 782
+cuboot.h: 365
+cuboot-katmai.c: 1294
+cuboot-mpc7448hpc2.c: 1279
+cuboot-pq2.c: 7138
+cuboot-rainier.c: 1453
+cuboot-sam440ep.c: 1254
+cuboot-sequoia.c: 1453
+cuboot-taishan.c: 1361
+cuboot-warp.c: 916
+cuboot-yosemite.c: 1095
+cuda.h: 978
+cumana_1.c: 7960
+cumana_2.c: 14690
+current.h: 677
+cuse.c: 14893
+cvisionppc.h: 1577
+cvmx-address.h: 8499
+cvmx-asm.h: 4526
+cvmx-asxx-defs.h: 14223
+cvmx-bootinfo.h: 9081
+cvmx-bootmem.c: 20524
+cvmx-bootmem.h: 12982
+cvmx-ciu-defs.h: 39090
+cvmx-cmd-queue.c: 9400
+cvmx-cmd-queue.h: 18993
+cvmx-config.h: 6486
+cvmx-dbg-defs.h: 2123
+cvmx-fau.h: 19011
+cvmx-fpa.c: 4975
+cvmx-fpa-defs.h: 11938
+cvmx-fpa.h: 8284
+cvmx-gmxx-defs.h: 79305
+cvmx-gpio-defs.h: 6346
+cvmx.h: 14240
+cvmx-helper-board.c: 21950
+cvmx-helper-board.h: 6656
+cvmx-helper.c: 32770
+cvmx-helper-errata.c: 2592
+cvmx-helper-errata.h: 1277
+cvmx-helper-fpa.c: 7545
+cvmx-helper-fpa.h: 2360
+cvmx-helper.h: 7482
+cvmx-helper-jtag.c: 4203
+cvmx-helper-jtag.h: 1530
+cvmx-helper-loop.c: 2679
+cvmx-helper-loop.h: 1901
+cvmx-helper-npi.c: 3413
+cvmx-helper-npi.h: 1897
+cvmx-helper-rgmii.c: 17448
+cvmx-helper-rgmii.h: 3560
+cvmx-helper-sgmii.c: 17037
+cvmx-helper-sgmii.h: 3417
+cvmx-helper-spi.c: 6088
+cvmx-helper-spi.h: 2785
+cvmx-helper-util.c: 12555
+cvmx-helper-util.h: 6164
+cvmx-helper-xaui.c: 11997
+cvmx-helper-xaui.h: 3409
+cvmx-interrupt-decodes.c: 13959
+cvmx-interrupt-rsl.c: 3787
+cvmx-iob-defs.h: 16589
+cvmx-ipd-defs.h: 27302
+cvmx-ipd.h: 10763
+cvmx-l2c.c: 19669
+cvmx-l2c-defs.h: 23395
+cvmx-l2c.h: 10068
+cvmx-l2d-defs.h: 9721
+cvmx-l2t-defs.h: 3720
+cvmx-led-defs.h: 6731
+cvmx-mdio.h: 13085
+cvmx-mio-defs.h: 54538
+cvmx-npei-defs.h: 61528
+cvmx-npi-defs.h: 46348
+cvmx-packet.h: 1964
+cvmx-pci-defs.h: 40401
+cvmx-pcieep-defs.h: 32743
+cvmx-pciercx-defs.h: 36139
+cvmx-pcsx-defs.h: 11497
+cvmx-pcsxx-defs.h: 9562
+cvmx-pescx-defs.h: 11439
+cvmx-pexp-defs.h: 9365
+cvmx-pip-defs.h: 34993
+cvmx-pip.h: 16579
+cvmx-pko.c: 14987
+cvmx-pko-defs.h: 31966
+cvmx-pko.h: 18946
+cvmx-pow-defs.h: 19069
+cvmx-pow.h: 59817
+cvmx-scratch.h: 3875
+cvmx-smix-defs.h: 5173
+cvmx-spi.c: 22343
+cvmx-spi.h: 9516
+cvmx-spinlock.h: 6516
+cvmx-spxx-defs.h: 9687
+cvmx-srxx-defs.h: 3849
+cvmx-stxx-defs.h: 8491
+cvmx-sysinfo.c: 3570
+cvmx-sysinfo.h: 4893
+cvmx-wqe.h: 11943
+cwc4630.h: 15478
+cwcasync.h: 7969
+cwcbinhack.h: 1566
+cwcdma.asp: 4526
+cwcdma.h: 2174
+cwcsnoop.h: 1513
+cwep.c: 9662
+cwm.c: 3787
+cwm.h: 2421
+cx18: 4096
+cx18-audio.c: 2589
+cx18-audio.h: 905
+cx18-av-audio.c: 14932
+cx18-av-core.c: 41048
+cx18-av-core.h: 13381
+cx18-av-firmware.c: 7225
+cx18-av-vbi.c: 9043
+cx18-cards.c: 16165
+cx18-cards.h: 4838
+cx18-controls.c: 9435
+cx18-controls.h: 1257
+cx18-driver.c: 35409
+cx18-driver.h: 23311
+cx18-dvb.c: 9950
+cx18-dvb.h: 946
+cx18-fileops.c: 21082
+cx18-fileops.h: 1421
+cx18-firmware.c: 14987
+cx18-firmware.h: 1001
+cx18-gpio.c: 9268
+cx18-gpio.h: 1226
+cx18-i2c.c: 8776
+cx18-i2c.h: 1083
+cx18-io.c: 2807
+cx18-ioctl.c: 27533
+cx18-ioctl.h: 1423
+cx18-io.h: 4951
+cx18-irq.c: 2319
+cx18-irq.h: 1417
+cx18-mailbox.c: 21623
+cx18-mailbox.h: 3643
+cx18-queue.c: 6955
+cx18-queue.h: 2294
+cx18-scb.c: 5787
+cx18-scb.h: 7441
+cx18-streams.c: 21499
+cx18-streams.h: 1889
+cx18.txt: 811
+cx18-vbi.c: 7419
+cx18-vbi.h: 1031
+cx18-version.h: 1319
+cx18-video.c: 1080
+cx18-video.h: 875
+cx22700.c: 11029
+cx22700.h: 1488
+cx22702.c: 14516
+cx22702.h: 1673
+cx231xx: 4096
+cx231xx-audio.c: 14952
+cx231xx-avcore.c: 77231
+cx231xx-cards.c: 23257
+cx231xx-conf-reg.h: 25445
+cx231xx-core.c: 30779
+cx231xx-dvb.c: 13339
+cx231xx.h: 22018
+cx231xx-i2c.c: 12912
+cx231xx-input.c: 6423
+cx231xx-pcb-cfg.c: 20991
+cx231xx-pcb-cfg.h: 6456
+cx231xx-reg.h: 67462
+cx231xx-vbi.c: 17757
+cx231xx-vbi.h: 2261
+cx231xx-video.c: 58825
+cx23418.h: 17951
+cx2341x: 4096
+cx2341x.c: 38287
+cx2341x.h: 7383
+cx23885: 4096
+cx23885-417.c: 48981
+cx23885-cards.c: 25645
+cx23885-core.c: 54422
+cx23885-dvb.c: 26635
+cx23885.h: 16143
+cx23885-i2c.c: 9910
+cx23885-reg.h: 12999
+cx23885-vbi.c: 6762
+cx23885-video.c: 40258
+cx24110.c: 20853
+cx24110.h: 1810
+cx24113.c: 14661
+cx24113.h: 1673
+cx24116.c: 40768
+cx24116.h: 1706
+cx24123.c: 30243
+cx24123.h: 1979
+cx25840: 4096
+cx25840-audio.c: 11073
+cx25840-core.c: 45706
+cx25840-core.h: 3605
+cx25840-firmware.c: 3889
+cx25840.h: 3250
+cx25840-vbi.c: 7108
+cx88: 4096
+cx88-alsa.c: 23036
+cx88-blackbird.c: 39031
+cx88-cards.c: 89130
+cx88-core.c: 31343
+cx88-dsp.c: 8787
+cx88-dvb.c: 39095
+cx88.h: 22857
+cx88-i2c.c: 5568
+cx88-input.c: 14002
+cx88-mpeg.c: 24270
+cx88-reg.h: 34334
+cx88-tvaudio.c: 28674
+cx88-vbi.c: 6438
+cx88-video.c: 56637
+cx88-vp3054-i2c.c: 4322
+cx88-vp3054-i2c.h: 1559
+cxacru.c: 37008
+cxacru.txt: 2325
+cxgb2.c: 38481
+cxgb3: 4096
+cxgb3_ctl_defs.h: 5067
+cxgb3_defs.h: 3489
+cxgb3i: 4096
+cxgb3i_ddp.c: 20593
+cxgb3i_ddp.h: 8254
+cxgb3i.h: 4401
+cxgb3i_init.c: 3040
+cxgb3i_iscsi.c: 27545
+cxgb3_ioctl.h: 3847
+cxgb3i_offload.c: 50331
+cxgb3i_offload.h: 7277
+cxgb3i_pdu.c: 12368
+cxgb3i_pdu.h: 1710
+cxgb3i.txt: 3295
+cxgb3_main.c: 84313
+cxgb3_offload.c: 37599
+cxgb3_offload.h: 6272
+cxgb.txt: 13829
+cxio_dbg.c: 5114
+cxio_hal.c: 38094
+cxio_hal.h: 7482
+cxio_resource.c: 9188
+cxio_resource.h: 3116
+cxio_wr.h: 20826
+cxusb.c: 48202
+cxusb.h: 724
+cy82c693.c: 10524
+cyber2000fb.c: 43356
+cyber2000fb.h: 16008
+cyberjack.c: 14547
+cyclades.c: 158213
+cyclades.h: 24974
+cyclomx.h: 2544
+cyclone.c: 3125
+cyclone.h: 403
+cycx_cfm.h: 2926
+cycx_drv.c: 15649
+cycx_drv.h: 2183
+cycx_main.c: 9413
+cycx_x25.c: 45814
+cycx_x25.h: 3727
+cylinder.c: 5848
+cypress_atacb.c: 8391
+cypress_cy7c63.c: 7689
+cypress.h: 2856
+cypress_m8.c: 47071
+cypress_m8.h: 2367
+cyrix.c: 5962
+cytherm.c: 11260
+d101m_ucode.bin.ihex: 1675
+d101s_ucode.bin.ihex: 1675
+d102e_ucode.bin.ihex: 1675
+da9030_battery.c: 16256
+da9034-ts.c: 9057
+da903x_bl.c: 4988
+da903x.c: 13455
+da903x.h: 7048
+dabusb: 4096
+dabusb.c: 22084
+dabusb.h: 1873
+DAC960.c: 265715
+DAC960.h: 151800
+daca.c: 7036
+dac.h: 752
+dadapter.c: 14853
+dadapter.h: 1070
+daemon.c: 16879
+daemon.h: 8435
+daemon_kern.c: 2419
+daemon_user.c: 4368
+daisy.c: 12538
+DAI.txt: 2270
+dapm.txt: 10267
+daqboard2000.c: 25750
+darla20.c: 2889
+darla20_dsp.c: 3479
+darla24.c: 3153
+darla24_dsp.c: 3845
+dart.h: 2235
+dart_iommu.c: 10816
+das08.c: 26325
+das08_cs.c: 14893
+das08.h: 2561
+das16.c: 44853
+das16m1.c: 21006
+das1800.c: 48894
+das6402.c: 8510
+das800.c: 24454
+DASD: 3388
+dasd_3990_erp.c: 68376
+dasd_alias.c: 26580
+dasd.c: 72767
+dasd_devmap.c: 29631
+dasd_diag.c: 17829
+dasd_diag.h: 2628
+dasd_eckd.c: 95322
+dasd_eckd.h: 11295
+dasd_eer.c: 20468
+dasd_erp.c: 4866
+dasd_fba.c: 17801
+dasd_fba.h: 1816
+dasd_genhd.c: 4783
+dasd.h: 11124
+dasd_int.h: 21917
+dasd_ioctl.c: 11160
+dasd_proc.c: 9802
+data.c: 2497
+datafab.c: 20690
+datagram.c: 4449
+data-integrity.txt: 13815
+datalink.h: 482
+datapage.S: 2018
+datarate.c: 12551
+datarate.h: 2494
+datastream.c: 15931
+datastream.h: 514
+dat.c: 11476
+dat.h: 2048
+davicom.c: 4985
+davinci: 4096
+davinci_all_defconfig: 43899
+davinci.c: 13768
+davinci_emac.c: 84968
+davinci-evm.c: 6719
+davinci.h: 3430
+davinci-i2s.c: 17146
+davinci-i2s.h: 495
+davinci_nand.c: 23119
+davinci-pcm.c: 10560
+davinci-pcm.h: 783
+davinci-sffsdr.c: 4374
+davinci_wdt.c: 6690
+db1000_defconfig: 23355
+db1100_defconfig: 23611
+db1200_defconfig: 25180
+db1200.h: 6115
+db1500_defconfig: 30453
+db1550_defconfig: 26655
+db1x00: 4096
+db1x00.h: 5353
+db78x00-bp-setup.c: 2591
+db88f5281-setup.c: 9805
+db88f6281-bp-setup.c: 2227
+db9.c: 21255
+dbdma2.c: 10987
+dbdma.c: 29134
+dbdma.h: 3834
+dbell.c: 1075
+dbell.h: 1308
+dbg.c: 7231
+dbg_current.S: 402
+dbg.h: 144
+dbg_io.c: 5088
+dbg_stackcheck.S: 427
+dbg_stackkill.S: 575
+dbl_float.h: 36770
+dbox2-flash.c: 2719
+dbri.c: 80387
+dbus_contexts: 195
+dc21285.c: 5936
+dc21285-timer.c: 1332
+dc232b: 4096
+dc395x.c: 145696
+dc395x.h: 25842
+dc395x.txt: 3337
+dca: 4096
+dcache.c: 60424
+dcache.h: 2009
+dca-core.c: 6864
+dca.h: 2530
+dca-sysfs.c: 2700
+dcb: 4096
+dcbnl.c: 29597
+dcbnl.h: 11558
+dccp: 4096
+dccp.h: 15873
+dccp.txt: 7484
+dcdbas.c: 16163
+dcdbas.h: 2821
+dcdbas.txt: 3709
+dcookies.c: 6936
+dcookies.h: 1289
+dcore.c: 21748
+dcr.c: 6132
+dcr-generic.h: 1621
+dcr.h: 6308
+dcr-low.S: 983
+dcr-mmio.h: 1838
+dcr-native.h: 4500
+dcr-regs.h: 5140
+dcssblk.c: 27372
+dcu.h: 1481
+dd.c: 9413
+ddp.c: 49018
+ddr2_defs_asm.h: 11790
+ddr2_defs.h: 9835
+ddr.h: 4564
+de2104x.c: 54503
+de4x5.c: 169230
+de4x5.h: 49229
+de4x5.txt: 8677
+de600.c: 13275
+de600.h: 5588
+de620.c: 26654
+de620.h: 4970
+deadline-iosched.c: 11700
+deadline-iosched.txt: 2841
+debug-8250.S: 719
+debug.c: 7221
+debug-cmd.h: 1653
+debug-devices.c: 1975
+debugfs: 4096
+debug_fs.c: 16621
+debugfs.c: 6192
+debugfs.h: 2563
+debugfs_key.c: 9097
+debugfs_key.h: 1348
+debugfs-kmemtrace: 2769
+debugfs_netdev.c: 14895
+debugfs_netdev.h: 739
+debugfs-pktcdvd: 448
+debugfs_sta.c: 7063
+debugfs_sta.h: 427
+debugfs.txt: 7128
+debugging: 1594
+Debugging390.txt: 97243
+debugging-modules.txt: 954
+debugging-via-ohci1394.txt: 7635
+debug.h: 1195
+Debug.h: 1195
+debug_if.h: 3572
+debug-leds.c: 7120
+debug-levels.h: 1482
+debuglib.c: 4523
+debuglib.h: 11740
+debug_locks.c: 1127
+debug_locks.h: 1663
+debug-macro.S: 619
+debugobjects.c: 24352
+debugobjects.h: 2960
+debugobjects.tmpl: 14144
+debug-pagealloc.c: 2607
+debug-pl01x.S: 693
+debugport.c: 12453
+debugreg.h: 2904
+debug.S: 2650
+debug-stub.c: 6089
+debugtraps.S: 1210
+debug.txt: 5755
+dec: 4096
+dec21285.h: 5572
+dec_and_lock.c: 809
+decbin.S: 15728
+declance.c: 35842
+decl.h: 2409
+decnet: 4096
+decnet.txt: 10805
+decodecode: 1702
+decode_exc.c: 11585
+decode_rs.c: 6959
+decompress: 4096
+decompress_bunzip2.c: 23556
+decompress.c: 1126
+decompress_inflate.c: 3544
+decompress_unlzma.c: 15528
+decompress_v10.lds: 342
+decompress_v32.lds: 337
+decstation_defconfig: 17956
+dectypes.h: 427
+default_defconfig: 39014
+defBF512.h: 1271
+defBF514.h: 13406
+defBF516.h: 46402
+defBF518.h: 48358
+defBF51x_base.h: 113540
+defBF522.h: 1271
+defBF525.h: 44639
+defBF527.h: 77635
+defBF52x_base.h: 116393
+defBF532.h: 74150
+defBF534.h: 189790
+defBF537.h: 35002
+defBF539.h: 212777
+defBF542.h: 58060
+defBF544.h: 57371
+defBF547.h: 78333
+defBF548.h: 117603
+defBF549.h: 180941
+defBF54x_base.h: 251535
+defBF561.h: 109277
+defconfig: 20414
+deferred_io.txt: 3031
+defines.h: 5063
+define_trace.h: 1988
+defkeymap.c: 6243
+defkeymap.c_shipped: 11007
+defkeymap.map: 12183
+deflate.c: 5615
+deflate_syms.c: 377
+def_LPBlackfin.h: 29239
+defpalo.conf: 789
+defs.h: 12522
+deftree.c: 40510
+defutil.h: 11891
+defxx.c: 116343
+defxx.h: 54496
+delay_32.h: 882
+delay_64.h: 378
+delay-accounting.txt: 3837
+delayacct.c: 5038
+delayacct.h: 4108
+delay.c: 581
+delayed-ref.c: 24860
+delayed-ref.h: 6619
+delay.h: 1166
+delay_mm.h: 1362
+delay_no.h: 2314
+delay.S: 1279
+delay.txt: 694
+delegation.c: 14100
+delegation.h: 2261
+delkin_cb.c: 4687
+dell-laptop.c: 9519
+dell_rbu.c: 19420
+dell_rbu.txt: 4973
+dell-wmi.c: 6724
+delta.c: 23513
+delta.h: 5823
+demo_main.c: 29367
+demux.h: 8791
+denormal.c: 3335
+dentry.c: 2934
+dentry-locking.txt: 8359
+depca.c: 61475
+depca.h: 6823
+depca.txt: 1245
+desc.c: 19546
+desc_defs.h: 2385
+desc.h: 20526
+des_check_key.c: 4011
+descore-readme.txt: 17200
+description: 73
+des_generic.c: 36210
+des.h: 403
+design_notes.txt: 4626
+design.txt: 17558
+des_s390.c: 17966
+dev-audio.c: 1656
+devboards: 4096
+dev.c: 16990
+devconnect.c: 33409
+devdma.c: 2008
+devdma.h: 271
+development-process: 4096
+dev-fb.c: 1681
+devfs: 459
+dev.h: 9111
+dev-hsmmc1.c: 1647
+dev-hsmmc.c: 1640
+dev-i2c0.c: 1622
+dev-i2c1.c: 1587
+device.c: 3904
+device_cfg.h: 2924
+device_cgroup.c: 12005
+device_cgroup.h: 380
+device-drivers.tmpl: 13872
+device_fsm.c: 34071
+device.h: 31245
+device_handler: 4096
+device_id.c: 8750
+device_id.h: 9158
+device-init.c: 23541
+deviceiobook.tmpl: 11288
+device_main.c: 128828
+device-mapper: 4096
+device-mapper.h: 10956
+device_ops.c: 22502
+device_pgid.c: 16031
+devices: 4096
+devices.c: 19482
+devices.h: 918
+devices-rsk7203.c: 2587
+device_status.c: 12596
+devices.txt: 118144
+devicetable.txt: 1298
+device.txt: 6393
+devinet.c: 40642
+dev-interface: 8905
+devio.c: 45517
+dev-ioctl.c: 18582
+devmap.c: 1464
+dev_mcast.c: 5650
+devops_32.c: 1879
+devops_64.c: 1006
+devpts: 4096
+devpts_fs.h: 1454
+devpts.txt: 5085
+devres.c: 16191
+devres.txt: 7761
+devs.c: 9766
+devs.h: 1960
+dev-sysfs.c: 3852
+dev_table.c: 5563
+dev_table.h: 10908
+devtree.c: 8324
+dev-uart.c: 3521
+dev-usb.c: 1134
+dev-usb-hsotg.c: 992
+dfadd.c: 15801
+dfcmp.c: 5306
+dfdiv.c: 12636
+dfifo.h: 2160
+dfmpy.c: 11736
+dfrem.c: 8997
+dfs.c: 37
+dfs.h: 27
+dfsqrt.c: 5530
+dfsub.c: 15897
+dfu: 4096
+dfu.c: 6025
+dgram.c: 8393
+diag.c: 1739
+diag.h: 1050
+dialog.h: 6696
+dib0070.c: 13441
+dib0070.h: 1691
+dib0700_core.c: 11979
+dib0700_devices.c: 54526
+dib0700.h: 2680
+dib07x0.h: 266
+dib3000.h: 1813
+dib3000mb.c: 23970
+dib3000mb_priv.h: 16232
+dib3000mc.c: 26706
+dib3000mc.h: 2337
+dib7000m.c: 40754
+dib7000m.h: 2102
+dib7000p.c: 40757
+dib7000p.h: 2849
+dibusb-common.c: 12123
+dibusb.h: 3337
+dibusb-mb.c: 14485
+dibusb-mc.c: 5124
+dibx000_common.c: 4156
+dibx000_common.h: 2896
+di.c: 31214
+di_dbg.h: 1102
+diddfunc.c: 2703
+di_defs.h: 8217
+did_vers.h: 933
+diffconfig: 3642
+dig: 4096
+digest.c: 2574
+digi1.h: 3665
+digi_acceleport.c: 58641
+digiepca.txt: 3789
+digiFep1.h: 1928
+digiPCI.h: 1382
+digitv.c: 9329
+digitv.h: 1457
+digsy_mtc.dts: 5933
+di.h: 4386
+dilnetpc.c: 13589
+dino.c: 31503
+dio: 4096
+dio.c: 8573
+dio-driver.c: 3552
+dio.h: 11200
+dio-sysfs.c: 2250
+dir.c: 25683
+direct.c: 6527
+direct.h: 1640
+direct-io.c: 35225
+directory.c: 7736
+directory-locking: 5153
+dirent.h: 177
+dir_f.c: 10085
+dir_f.h: 1267
+dir_fplus.c: 4598
+dir_fplus.h: 1014
+dir.h: 1246
+dirhash.c: 6496
+dir-item.c: 11583
+disable-tsc-ctxt-sw-stress-test.c: 1724
+disable-tsc-on-off-stress-test.c: 1717
+disable-tsc-test.c: 2121
+dis-asm.h: 895
+disassemble.c: 19044
+disassemble.h: 1766
+dis.c: 41703
+discontig.c: 1271
+discover.c: 9895
+discover.h: 2378
+discovery.c: 12785
+discovery.h: 3572
+disk-io.c: 67604
+disk-io.h: 4751
+diskonchip.c: 50636
+disk-shock-protection.txt: 6881
+dispc.c: 37465
+dispc.h: 1183
+display: 4096
+display7seg.c: 6503
+display7seg.h: 1882
+display.c: 1573
+display_gx1.c: 6318
+display_gx1.h: 4598
+display_gx.c: 4945
+display.h: 2117
+display-sysfs.c: 6099
+diu.txt: 470
+div64.c: 3889
+div64-generic.c: 283
+div64.h: 371
+div64.S: 3866
+diva.c: 34488
+divacapi.h: 50994
+diva_didd.c: 3571
+diva_dma.c: 2843
+diva_dma.h: 1993
+diva.h: 1010
+divamnt.c: 5616
+diva_pci.h: 631
+divasfunc.c: 5512
+divasi.c: 12379
+divasmain.c: 21787
+divasproc.c: 10764
+divasync.h: 20126
+divdi3.S: 6280
+divert: 4096
+divert_init.c: 2399
+divert_procfs.c: 8581
+divide.S: 4293
+divsi3.S: 6392
+div_small.S: 1546
+div_Xsig.S: 10096
+dl2k.c: 48901
+dl2k.h: 14949
+dl2k.txt: 9387
+dlci.c: 11723
+DLINK.txt: 7386
+dlm: 4096
+dlmapi.h: 9492
+dlmast.c: 13019
+dlmcommon.h: 29686
+dlmconstants.h: 5013
+dlmconvert.c: 15590
+dlmconvert.h: 1218
+dlmdebug.c: 28761
+dlmdebug.h: 2109
+dlm_device.h: 2536
+dlmdomain.c: 49292
+dlmdomain.h: 1165
+dlmfs.c: 15242
+dlmfs.txt: 4319
+dlmfsver.c: 1211
+dlmfsver.h: 997
+dlmglue.c: 110475
+dlmglue.h: 5587
+dlm.h: 5602
+dlm_internal.h: 16633
+dlmlock.c: 19997
+dlmmaster.c: 96511
+dlm_netlink.h: 1064
+dlm_plock.h: 1135
+dlmrecovery.c: 85132
+dlmthread.c: 21013
+dlmunlock.c: 19250
+dlmver.c: 1203
+dlmver.h: 991
+dm1105: 4096
+dm1105.c: 22399
+dm355.c: 17263
+dm355evm_keys.c: 8928
+dm355evm_msp.c: 10717
+dm355evm_msp.h: 2879
+dm355.h: 586
+dm644x.c: 14946
+dm644x.h: 1316
+dm646x.c: 15438
+dm646x.h: 757
+dm9000.c: 34291
+dm9000.h: 4167
+dm9000.txt: 5137
+dm9601.c: 15941
+dma: 4096
+dma-alloc.c: 4571
+dma-api.c: 9315
+DMA-API.txt: 28886
+DMA-attributes.txt: 1376
+dma-attrs.h: 1758
+dmabounce.c: 14340
+dmabrg.c: 5279
+dmabrg.h: 497
+dmabuf.c: 35686
+dma.c: 6328
+dmac.c: 4805
+dmac.h: 11517
+dma-coherence.h: 1492
+dma-coherent.c: 3667
+dma-coherent.h: 891
+dmacopy.c: 909
+dma-core.h: 639
+dmactl-regs.h: 4663
+dma-debug.c: 31988
+dma-debug.h: 4915
+dma-default.c: 8575
+dma_defs_asm.h: 14594
+dma_defs.h: 14110
+dmaengine.c: 28040
+dmaengine.h: 15831
+dmaengine.txt: 42
+dma-g2.c: 4776
+dma.h: 2547
+dma-iommu.c: 3128
+dma-isa.c: 5163
+DMA-ISA-LPC.txt: 5333
+dma_lib.c: 16254
+dma-m2p.c: 9922
+dma-mapping-broken.h: 2488
+dma-mapping.c: 5434
+dma-mapping-common.h: 5646
+dma-mapping.h: 4368
+DMA-mapping.txt: 27929
+dma_mm.h: 455
+dma-mx1-mx2.c: 23615
+dma-mx1-mx2.h: 2711
+dma_no.h: 16955
+dma-noncoherent.c: 10156
+dma-octeon.c: 10532
+dma-plat.h: 2025
+dmapool.c: 13226
+dmapool.h: 923
+dma-pvr2.c: 2423
+dmar.c: 31385
+dma_remapping.h: 988
+dmar.h: 6143
+dmascc.c: 37724
+dma-sh4a.h: 2469
+dma-sh7760.c: 10216
+dma-sh.c: 7913
+dma-sh.h: 2862
+dmasound: 4096
+dmasound_atari.c: 42606
+dmasound_core.c: 44456
+dmasound.h: 8131
+dmasound_paula.c: 19160
+dmasound_q40.c: 14354
+dma-swiotlb.c: 4748
+dma-sysfs.c: 4348
+dmatest.c: 15129
+dma_timer.c: 2282
+dma.txt: 6352
+DMA.txt: 6352
+dma_v.h: 1177
+dm-bio-record.h: 1629
+dm.c: 60780
+dm-crypt.c: 32243
+dm-crypt.txt: 1485
+dm-delay.c: 8567
+dm-dirty-log.h: 3944
+dme1737: 11748
+dme1737.c: 74868
+dmesg.c: 1657
+dm-exception-store.c: 6745
+dm-exception-store.h: 4659
+dmfe.c: 60351
+dmfe.txt: 2168
+dm.h: 3933
+dmi.h: 411
+dmi-id.c: 6586
+dm-io.c: 11366
+dm-ioctl.c: 33212
+dm-ioctl.h: 9109
+dm-io.h: 2051
+dm-io.txt: 3298
+dmi_scan.c: 15130
+dm-kcopyd.c: 14244
+dm-kcopyd.h: 1335
+dm-linear.c: 3614
+dm-log.c: 19367
+dm-log.txt: 2397
+dm-log-userspace-base.c: 16497
+dm-log-userspace.h: 12944
+dm-log-userspace-transfer.c: 6936
+dm-log-userspace-transfer.h: 452
+dmm32at.c: 30666
+dm-mpath.c: 37626
+dm-mpath.h: 415
+dm-path-selector.c: 2473
+dm-path-selector.h: 2533
+dm-queue-length.c: 5495
+dm-queue-length.txt: 1218
+dm-raid1.c: 32159
+dm-region-hash.c: 18043
+dm-region-hash.h: 3217
+dm-round-robin.c: 4673
+dm-service-time.c: 8360
+dm-service-time.txt: 3243
+dm-snap.c: 33940
+dm-snap-persistent.c: 17550
+dm-snap-transient.c: 3687
+dm-stripe.c: 8013
+dm-sysfs.c: 2204
+dm-table.c: 27836
+dm-target.c: 2600
+dmtimer.c: 22824
+dmtimer.h: 3450
+dm-uevent.c: 5482
+dm-uevent.h: 1678
+dm-uevent.txt: 2650
+dmv182.c: 3833
+dmx3191d.c: 4547
+dmxdev.c: 28366
+dmxdev.h: 2409
+dmx.h: 3848
+dm-zero.c: 1495
+dn_dev.c: 33824
+dn_dev.h: 5493
+dnet.c: 25715
+dnet.h: 7221
+dnfb.c: 8139
+dn_fib.c: 18396
+dn_fib.h: 4894
+dn.h: 4527
+dn_ints.c: 1049
+dn_neigh.c: 15875
+dn_neigh.h: 824
+dn_nsp.h: 6229
+dn_nsp_in.c: 21566
+dn_nsp_out.c: 17942
+dnode.c: 30235
+dnotify: 4096
+dnotify.c: 12385
+dnotify.h: 978
+dnotify.txt: 3565
+dn_route.c: 44768
+dn_route.h: 4165
+dn_rtmsg.c: 3778
+dn_rules.c: 5755
+dns323-setup.c: 10831
+dns_resolve.c: 3678
+dns_resolve.h: 1294
+dn_table.c: 20482
+dn_timer.c: 3167
+do_balan.c: 58466
+doc2000.c: 32664
+doc2000.h: 5486
+doc2001.c: 25107
+doc2001plus.c: 31825
+DocBook: 4096
+docecc.c: 15968
+dock.c: 31358
+docprobe.c: 10340
+docproc.c: 11716
+do_csum.S: 2991
+Documentation: 4096
+do_func.S: 13813
+domain.c: 29471
+domain.h: 2107
+do_mounts.c: 9465
+do_mounts.h: 1396
+do_mounts_initrd.c: 3256
+do_mounts_md.c: 8071
+do_mounts_rd.c: 8166
+donauboe.c: 48207
+donauboe.h: 14213
+dontdiff: 1964
+doorbell.c: 2900
+doorbell.h: 2894
+dot11d.c: 5434
+dot11d.h: 2916
+dot_command.c: 4062
+dot_command.h: 2259
+dot.gdbinit: 5372
+dot.gdbinit_200MHz_16MB: 5763
+dot.gdbinit_300MHz_32MB: 5763
+dot.gdbinit_400MHz_32MB: 5764
+dot.gdbinit.nommu: 3891
+dot.gdbinit.smp: 8938
+dot.gdbinit.vdec2: 5442
+do_timer.h: 349
+double_cpdo.c: 4122
+doublefault_32.c: 1732
+double.h: 6303
+down2.H16: 33610
+down3.bin.ihex: 35892
+down.H16: 36678
+dp_add.c: 4700
+dpc.c: 58689
+dpc.h: 1771
+dp_cmp.c: 1842
+dpcsup.c: 9553
+dp_div.c: 4369
+dp_fint.c: 1932
+dp_flong.c: 1912
+dp_frexp.c: 1450
+dp_fsp.c: 1879
+dp_logb.c: 1446
+dpmc.c: 3024
+dpmc.h: 1247
+dpmc_modes.S: 14539
+dp_modf.c: 2064
+dp_mul.c: 4812
+dp_scalb.c: 1508
+dp_simple.c: 2057
+dp_sqrt.c: 4372
+dp_sub.c: 4977
+dpt: 4096
+dpt_i2o.c: 96500
+dpti.h: 11787
+dpti_i2o.h: 13449
+dpti_ioctl.h: 5365
+dp_tint.c: 3021
+dpti.txt: 3614
+dp_tlong.c: 3061
+dptsig.h: 14986
+dqblk_qtree.h: 2108
+dqblk_v1.h: 342
+dqblk_v2.h: 367
+dqblk_xfs.h: 6607
+dqueue.c: 2180
+dqueue.h: 1007
+dquot.c: 72530
+draft-ietf-cipso-ipsecurity-01.txt: 28638
+dram_init.S: 3913
+draw_functrace.py: 3560
+dreamcast_defconfig: 25856
+driver: 11995
+driver.c: 54722
+driver-changes.txt: 4022
+driver_chipcommon.c: 13262
+driver_chipcommon_pmu.c: 17510
+driver_extif.c: 3829
+driver_gige.c: 7415
+driver.h: 4405
+driver_mipscore.c: 6999
+driver-model: 4096
+driver-model.txt: 10127
+driver-ops.h: 5035
+driver_pcicore.c: 16619
+drivers: 4096
+drivers.c: 22567
+drivers-testing.txt: 2173
+driver.txt: 8049
+drm: 4096
+drm_agpsupport.c: 13149
+drm_auth.c: 5698
+drm_bufs.c: 44350
+drm_cache.c: 2119
+drm_context.c: 11821
+drm_core.h: 1468
+drm_crtc.c: 63999
+drm_crtc.h: 25347
+drm_crtc_helper.c: 29207
+drm_crtc_helper.h: 4951
+drm_debugfs.c: 6275
+drm_dma.c: 4147
+drm_drawable.c: 5166
+drm_drv.c: 16709
+drm_edid.c: 24730
+drm_edid.h: 5722
+drm_fops.c: 14460
+drm_gem.c: 14905
+drm.h: 23018
+drm_hashtab.c: 5440
+drm_hashtab.h: 2589
+drm_info.c: 9606
+drm_ioc32.c: 33632
+drm_ioctl.c: 9402
+drm_irq.c: 17068
+drm_lock.c: 11107
+drm_memory.c: 5012
+drm_memory.h: 1936
+drm_mm.c: 9213
+drm_mm.h: 3301
+drm_mode.h: 6855
+drm_modes.c: 14802
+drm_os_linux.h: 4047
+drm_pci.c: 3839
+drm_pciids.h: 40171
+drmP.h: 49714
+drm_proc.c: 6339
+drm_sarea.h: 2655
+drm_scatter.c: 5431
+drm_sman.c: 8782
+drm_sman.h: 5975
+drm_stub.c: 13017
+drm_sysfs.c: 13561
+drm_vm.c: 18670
+drop_caches.c: 1684
+drop_monitor.c: 8677
+drp-avail.c: 8822
+drp.c: 24684
+drp-ie.c: 9743
+drv.c: 22503
+drvfbi.c: 12647
+drx397xD.c: 30335
+drx397xD_fw.h: 1525
+drx397xD.h: 3015
+ds1286.h: 1223
+ds1287.h: 1019
+ds1302.c: 7604
+ds1305.h: 1068
+ds1603.c: 3162
+ds1603.h: 566
+ds1620.c: 8486
+ds1621: 2670
+ds1621.c: 9932
+ds1682.c: 7160
+ds17287rtc.h: 2676
+ds1_ctrl.fw.ihex: 33804
+ds1_dsp.fw.ihex: 364
+ds1e_ctrl.fw.ihex: 33804
+ds1wm.c: 11691
+ds1wm.h: 114
+ds2482: 743
+ds2482.c: 14041
+ds2490: 3576
+ds2490.c: 24260
+ds2760_battery.c: 13485
+dsa: 4096
+dsa.c: 9418
+dsa.h: 1617
+dsa_priv.h: 4060
+dsbr100.c: 17605
+ds.c: 38706
+dsc.c: 1195
+dscc4.c: 55052
+dsdt-override.txt: 247
+dsemul.c: 4501
+dsfield.c: 19154
+dsfield.h: 1127
+ds.h: 8003
+dsinit.c: 6745
+dsmethod.c: 19169
+dsmg600.h: 1216
+dsmg600-pci.c: 1898
+dsmg600-setup.c: 7030
+dsmthdat.c: 21585
+dsobject.c: 23900
+dsopcode.c: 39305
+dsp56k: 4096
+dsp56k.c: 12404
+dsp56k.h: 1269
+dsp_audio.c: 11056
+dsp_biquad.h: 1622
+dsp_blowfish.c: 23738
+dspbootcode.bin.ihex: 36048
+dsp_cmx.c: 52826
+dsp_common.h: 1309
+dsp_core.c: 33551
+dsp_defs.h: 12149
+dspdids.h: 2695
+dsp_dtmf.c: 7570
+dsp_ecdis.h: 3527
+dsp.h: 7893
+dsp_hwec.c: 3049
+dsp_hwec.h: 242
+dsp_pipeline.c: 8348
+dsp_spos.c: 55617
+dsp_spos.h: 7631
+dsp_spos_scb_lib.c: 49424
+dsp_tones.c: 17264
+dsp_tst.h: 1486
+dsrv4bri.h: 1644
+dsrv_bri.h: 1178
+dsrv_pri.h: 1247
+ds_selftest.c: 9393
+ds_selftest.h: 363
+dst: 4096
+dst.c: 49967
+dst_ca.c: 21634
+dst_ca.h: 1591
+dst_common.h: 4277
+dst.h: 14556
+dst_priv.h: 598
+dstr.c: 5143
+dsutils.c: 25450
+dswexec.c: 19731
+dswload.c: 31066
+dswscope.c: 6750
+dswstate.c: 21428
+dt019x.c: 9062
+dt2801.c: 15251
+dt2811.c: 14680
+dt2814.c: 8589
+dt2815.c: 7337
+dt2817.c: 4517
+dt282x.c: 35248
+dt3000.c: 23494
+dt9812.c: 28480
+dtc: 4096
+dt.c: 16907
+dtc2278.c: 3867
+dtc3x80.txt: 1952
+dtc.c: 13348
+dtc.h: 2644
+dtc-lexer.l: 6979
+dtc-lexer.lex.c_shipped: 57920
+dtc-parser.tab.c_shipped: 55472
+dtc-parser.tab.h_shipped: 3233
+dtc-parser.y: 6540
+dtc-src: 4096
+dtl1_cs.c: 14325
+dtlb_miss.S: 747
+dtlb_prot.S: 1267
+dtl.c: 6493
+dtlk.c: 16644
+dtlk.h: 3768
+dts: 4096
+dts-bindings: 4096
+dtt200u.c: 9848
+dtt200u-fe.c: 5300
+dtt200u.h: 1606
+dtv5100.c: 5845
+dtv5100.h: 1534
+dum.h: 7581
+dummy.c: 3850
+dummycon.c: 1805
+dummy_hcd.c: 50629
+dump_pagetables.c: 8879
+dumprequest.c: 3343
+dumprequest.h: 2117
+dumpstack_32.c: 3323
+dumpstack_64.c: 7276
+dump_stack.c: 290
+dumpstack.c: 8067
+dumpstack.h: 1003
+dump_tlb.c: 2643
+dv1394: 390
+dv1394.c: 74226
+dv1394.h: 10409
+dv1394-private.h: 17471
+dvb: 4096
+dvb-bt8xx.c: 28096
+dvb-bt8xx.h: 1816
+dvb_ca_en50221.c: 45737
+dvb_ca_en50221.h: 4082
+dvb-core: 4096
+dvb_demux.c: 30507
+dvb_demux.h: 3579
+dvbdev.c: 11761
+dvbdev.h: 4065
+dvb_dummy_fe.c: 7049
+dvb_dummy_fe.h: 1698
+dvb_filter.c: 12922
+dvb_filter.h: 6064
+dvb_frontend.c: 54720
+dvb_frontend.h: 11618
+dvb_math.c: 5423
+dvb_math.h: 1974
+dvb_net.c: 42892
+dvb_net.h: 1379
+dvb-pll.c: 17175
+dvb-pll.h: 1617
+dvb_ringbuffer.c: 7188
+dvb_ringbuffer.h: 6340
+dvb-ttusb-budget.c: 44105
+dvb-usb: 12288
+dvb-usb-common.h: 2150
+dvb-usb-dvb.c: 5850
+dvb-usb-firmware.c: 3956
+dvb-usb.h: 12194
+dvb-usb-i2c.c: 1061
+dvb-usb-ids.h: 11042
+dvb-usb-init.c: 8477
+dvb-usb-remote.c: 5519
+dvb-usb-urb.c: 2585
+dvi.c: 18260
+dvi.h: 2461
+dvma.c: 1265
+dvma.h: 9864
+dvo_ch7017.c: 14698
+dvo_ch7xxx.c: 9179
+dvo.h: 4860
+dvo_ivch.c: 10628
+dvo_sil164.c: 7534
+dvo_tfp410.c: 8848
+dw2102.c: 27129
+dw2102.h: 240
+dwarf2.h: 2393
+dw_dmac.c: 37849
+dw_dmac.h: 3078
+dw_dmac_regs.h: 6137
+dynamic_debug.c: 18386
+dynamic_debug.h: 2666
+dynamic-debug-howto.txt: 8633
+dyn.lds.S: 5092
+dz.c: 23133
+dz.h: 5439
+e00154b8e949bf4b89ac198aef9a247532ac2d: 297
+e100: 4096
+e1000: 4096
+e1000_82575.c: 42179
+e1000_82575.h: 8176
+e1000_defines.h: 28796
+e1000e: 4096
+e1000_ethtool.c: 56605
diff --git a/qemu-0.15.x/qdict.c b/qemu-0.15.x/qdict.c
new file mode 100644
index 0000000..dee0fb4
--- /dev/null
+++ b/qemu-0.15.x/qdict.c
@@ -0,0 +1,456 @@
+/*
+ * QDict Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qint.h"
+#include "qfloat.h"
+#include "qdict.h"
+#include "qbool.h"
+#include "qstring.h"
+#include "qobject.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+
+static void qdict_destroy_obj(QObject *obj);
+
+static const QType qdict_type = {
+    .code = QTYPE_QDICT,
+    .destroy = qdict_destroy_obj,
+};
+
+/**
+ * qdict_new(): Create a new QDict
+ *
+ * Return strong reference.
+ */
+QDict *qdict_new(void)
+{
+    QDict *qdict;
+
+    qdict = qemu_mallocz(sizeof(*qdict));
+    QOBJECT_INIT(qdict, &qdict_type);
+
+    return qdict;
+}
+
+/**
+ * qobject_to_qdict(): Convert a QObject into a QDict
+ */
+QDict *qobject_to_qdict(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QDICT)
+        return NULL;
+
+    return container_of(obj, QDict, base);
+}
+
+/**
+ * tdb_hash(): based on the hash agorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+    unsigned value;	/* Used to compute the hash value.  */
+    unsigned   i;	/* Used to cycle through random values. */
+
+    /* Set the initial value from the key size. */
+    for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+        value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
+
+    return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value)
+{
+    QDictEntry *entry;
+
+    entry = qemu_mallocz(sizeof(*entry));
+    entry->key = qemu_strdup(key);
+    entry->value = value;
+
+    return entry;
+}
+
+/**
+ * qdict_entry_value(): Return qdict entry value
+ *
+ * Return weak reference.
+ */
+QObject *qdict_entry_value(const QDictEntry *entry)
+{
+    return entry->value;
+}
+
+/**
+ * qdict_entry_key(): Return qdict entry key
+ *
+ * Return a *pointer* to the string, it has to be duplicated before being
+ * stored.
+ */
+const char *qdict_entry_key(const QDictEntry *entry)
+{
+    return entry->key;
+}
+
+/**
+ * qdict_find(): List lookup function
+ */
+static QDictEntry *qdict_find(const QDict *qdict,
+                              const char *key, unsigned int bucket)
+{
+    QDictEntry *entry;
+
+    QLIST_FOREACH(entry, &qdict->table[bucket], next)
+        if (!strcmp(entry->key, key))
+            return entry;
+
+    return NULL;
+}
+
+/**
+ * qdict_put_obj(): Put a new QObject into the dictionary
+ *
+ * Insert the pair 'key:value' into 'qdict', if 'key' already exists
+ * its 'value' will be replaced.
+ *
+ * This is done by freeing the reference to the stored QObject and
+ * storing the new one in the same entry.
+ *
+ * NOTE: ownership of 'value' is transferred to the QDict
+ */
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
+{
+    unsigned int bucket;
+    QDictEntry *entry;
+
+    bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
+    entry = qdict_find(qdict, key, bucket);
+    if (entry) {
+        /* replace key's value */
+        qobject_decref(entry->value);
+        entry->value = value;
+    } else {
+        /* allocate a new entry */
+        entry = alloc_entry(key, value);
+        QLIST_INSERT_HEAD(&qdict->table[bucket], entry, next);
+        qdict->size++;
+    }
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return a weak reference to the QObject associated with 'key' if
+ * 'key' is present in the dictionary, NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+    QDictEntry *entry;
+
+    entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
+    return (entry == NULL ? NULL : entry->value);
+}
+
+/**
+ * qdict_haskey(): Check if 'key' exists
+ *
+ * Return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_haskey(const QDict *qdict, const char *key)
+{
+    unsigned int bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
+    return (qdict_find(qdict, key, bucket) == NULL ? 0 : 1);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+    return qdict->size;
+}
+
+/**
+ * qdict_get_obj(): Get a QObject of a specific type
+ */
+static QObject *qdict_get_obj(const QDict *qdict, const char *key,
+                              qtype_code type)
+{
+    QObject *obj;
+
+    obj = qdict_get(qdict, key);
+    assert(obj != NULL);
+    assert(qobject_type(obj) == type);
+
+    return obj;
+}
+
+/**
+ * qdict_get_double(): Get an number mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QFloat or QInt object.
+ *
+ * Return number mapped by 'key'.
+ */
+double qdict_get_double(const QDict *qdict, const char *key)
+{
+    QObject *obj = qdict_get(qdict, key);
+
+    assert(obj);
+    switch (qobject_type(obj)) {
+    case QTYPE_QFLOAT:
+        return qfloat_get_double(qobject_to_qfloat(obj));
+    case QTYPE_QINT:
+        return qint_get_int(qobject_to_qint(obj));
+    default:
+        abort();
+    }
+}
+
+/**
+ * qdict_get_int(): Get an integer mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ *
+ * Return integer mapped by 'key'.
+ */
+int64_t qdict_get_int(const QDict *qdict, const char *key)
+{
+    QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+    return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_bool(): Get a bool mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QBool object.
+ *
+ * Return bool mapped by 'key'.
+ */
+int qdict_get_bool(const QDict *qdict, const char *key)
+{
+    QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL);
+    return qbool_get_int(qobject_to_qbool(obj));
+}
+
+/**
+ * qdict_get_qlist(): Get the QList mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QList object.
+ *
+ * Return QList mapped by 'key'.
+ */
+QList *qdict_get_qlist(const QDict *qdict, const char *key)
+{
+    return qobject_to_qlist(qdict_get_obj(qdict, key, QTYPE_QLIST));
+}
+
+/**
+ * qdict_get_qdict(): Get the QDict mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QDict object.
+ *
+ * Return QDict mapped by 'key'.
+ */
+QDict *qdict_get_qdict(const QDict *qdict, const char *key)
+{
+    return qobject_to_qdict(qdict_get_obj(qdict, key, QTYPE_QDICT));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QString object.
+ *
+ * Return pointer to the string mapped by 'key'.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+    QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING);
+    return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_get_try_int(): Try to get integer mapped by 'key'
+ *
+ * Return integer mapped by 'key', if it is not present in
+ * the dictionary or if the stored object is not of QInt type
+ * 'def_value' will be returned.
+ */
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+                          int64_t def_value)
+{
+    QObject *obj;
+
+    obj = qdict_get(qdict, key);
+    if (!obj || qobject_type(obj) != QTYPE_QINT)
+        return def_value;
+
+    return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_try_bool(): Try to get a bool mapped by 'key'
+ *
+ * Return bool mapped by 'key', if it is not present in the
+ * dictionary or if the stored object is not of QBool type
+ * 'def_value' will be returned.
+ */
+int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value)
+{
+    QObject *obj;
+
+    obj = qdict_get(qdict, key);
+    if (!obj || qobject_type(obj) != QTYPE_QBOOL)
+        return def_value;
+
+    return qbool_get_int(qobject_to_qbool(obj));
+}
+
+/**
+ * qdict_get_try_str(): Try to get a pointer to the stored string
+ * mapped by 'key'
+ *
+ * Return a pointer to the string mapped by 'key', if it is not present
+ * in the dictionary or if the stored object is not of QString type
+ * NULL will be returned.
+ */
+const char *qdict_get_try_str(const QDict *qdict, const char *key)
+{
+    QObject *obj;
+
+    obj = qdict_get(qdict, key);
+    if (!obj || qobject_type(obj) != QTYPE_QSTRING)
+        return NULL;
+
+    return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_iter(): Iterate over all the dictionary's stored values.
+ *
+ * This function allows the user to provide an iterator, which will be
+ * called for each stored value in the dictionary.
+ */
+void qdict_iter(const QDict *qdict,
+                void (*iter)(const char *key, QObject *obj, void *opaque),
+                void *opaque)
+{
+    int i;
+    QDictEntry *entry;
+
+    for (i = 0; i < QDICT_BUCKET_MAX; i++) {
+        QLIST_FOREACH(entry, &qdict->table[i], next)
+            iter(entry->key, entry->value, opaque);
+    }
+}
+
+static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket)
+{
+    int i;
+
+    for (i = first_bucket; i < QDICT_BUCKET_MAX; i++) {
+        if (!QLIST_EMPTY(&qdict->table[i])) {
+            return QLIST_FIRST(&qdict->table[i]);
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * qdict_first(): Return first qdict entry for iteration.
+ */
+const QDictEntry *qdict_first(const QDict *qdict)
+{
+    return qdict_next_entry(qdict, 0);
+}
+
+/**
+ * qdict_next(): Return next qdict entry in an iteration.
+ */
+const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry)
+{
+    QDictEntry *ret;
+
+    ret = QLIST_NEXT(entry, next);
+    if (!ret) {
+        unsigned int bucket = tdb_hash(entry->key) % QDICT_BUCKET_MAX;
+        ret = qdict_next_entry(qdict, bucket + 1);
+    }
+
+    return ret;
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+    assert(e != NULL);
+    assert(e->key != NULL);
+    assert(e->value != NULL);
+
+    qobject_decref(e->value);
+    qemu_free(e->key);
+    qemu_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+    QDictEntry *entry;
+
+    entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
+    if (entry) {
+        QLIST_REMOVE(entry, next);
+        qentry_destroy(entry);
+        qdict->size--;
+    }
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+static void qdict_destroy_obj(QObject *obj)
+{
+    int i;
+    QDict *qdict;
+
+    assert(obj != NULL);
+    qdict = qobject_to_qdict(obj);
+
+    for (i = 0; i < QDICT_BUCKET_MAX; i++) {
+        QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
+        while (entry) {
+            QDictEntry *tmp = QLIST_NEXT(entry, next);
+            QLIST_REMOVE(entry, next);
+            qentry_destroy(entry);
+            entry = tmp;
+        }
+    }
+
+    qemu_free(qdict);
+}
diff --git a/qemu-0.15.x/qdict.h b/qemu-0.15.x/qdict.h
new file mode 100644
index 0000000..929d8d2
--- /dev/null
+++ b/qemu-0.15.x/qdict.h
@@ -0,0 +1,67 @@
+/*
+ * QDict Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QDICT_H
+#define QDICT_H
+
+#include "qobject.h"
+#include "qlist.h"
+#include "qemu-queue.h"
+#include <stdint.h>
+
+#define QDICT_BUCKET_MAX 512
+
+typedef struct QDictEntry {
+    char *key;
+    QObject *value;
+    QLIST_ENTRY(QDictEntry) next;
+} QDictEntry;
+
+typedef struct QDict {
+    QObject_HEAD;
+    size_t size;
+    QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX];
+} QDict;
+
+/* Object API */
+QDict *qdict_new(void);
+const char *qdict_entry_key(const QDictEntry *entry);
+QObject *qdict_entry_value(const QDictEntry *entry);
+size_t qdict_size(const QDict *qdict);
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value);
+void qdict_del(QDict *qdict, const char *key);
+int qdict_haskey(const QDict *qdict, const char *key);
+QObject *qdict_get(const QDict *qdict, const char *key);
+QDict *qobject_to_qdict(const QObject *obj);
+void qdict_iter(const QDict *qdict,
+                void (*iter)(const char *key, QObject *obj, void *opaque),
+                void *opaque);
+const QDictEntry *qdict_first(const QDict *qdict);
+const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry);
+
+/* Helper to qdict_put_obj(), accepts any object */
+#define qdict_put(qdict, key, obj) \
+        qdict_put_obj(qdict, key, QOBJECT(obj))
+
+/* High level helpers */
+double qdict_get_double(const QDict *qdict, const char *key);
+int64_t qdict_get_int(const QDict *qdict, const char *key);
+int qdict_get_bool(const QDict *qdict, const char *key);
+QList *qdict_get_qlist(const QDict *qdict, const char *key);
+QDict *qdict_get_qdict(const QDict *qdict, const char *key);
+const char *qdict_get_str(const QDict *qdict, const char *key);
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+                          int64_t def_value);
+int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value);
+const char *qdict_get_try_str(const QDict *qdict, const char *key);
+
+#endif /* QDICT_H */
diff --git a/qemu-0.15.x/qemu-aio.h b/qemu-0.15.x/qemu-aio.h
new file mode 100644
index 0000000..3bdd749
--- /dev/null
+++ b/qemu-0.15.x/qemu-aio.h
@@ -0,0 +1,59 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_AIO_H
+#define QEMU_AIO_H
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+
+/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
+typedef int (AioFlushHandler)(void *opaque);
+
+/* Runs all currently allowed AIO callbacks of completed requests in the
+ * respective AIO backend. Returns 0 if no requests was handled, non-zero
+ * if at least one queued request was handled. */
+typedef int (AioProcessQueue)(void *opaque);
+
+/* Flush any pending AIO operation. This function will block until all
+ * outstanding AIO operations have been completed or cancelled. */
+void qemu_aio_flush(void);
+
+/* Wait for a single AIO completion to occur.  This function will wait
+ * until a single AIO event has completed and it will ensure something
+ * has moved before returning. This can issue new pending aio as
+ * result of executing I/O completion or bh callbacks. */
+void qemu_aio_wait(void);
+
+/*
+ * Runs all currently allowed AIO callbacks of completed requests. Returns 0
+ * if no requests were handled, non-zero if at least one request was
+ * processed.
+ */
+int qemu_aio_process_queue(void);
+
+/* Register a file descriptor and associated callbacks.  Behaves very similarly
+ * to qemu_set_fd_handler2.  Unlike qemu_set_fd_handler2, these callbacks will
+ * be invoked when using either qemu_aio_wait() or qemu_aio_flush().
+ *
+ * Code that invokes AIO completion functions should rely on this function
+ * instead of qemu_set_fd_handler[2].
+ */
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            AioProcessQueue *io_process_queue,
+                            void *opaque);
+
+#endif
diff --git a/qemu-0.15.x/qemu-barrier.h b/qemu-0.15.x/qemu-barrier.h
new file mode 100644
index 0000000..b77fce2
--- /dev/null
+++ b/qemu-0.15.x/qemu-barrier.h
@@ -0,0 +1,10 @@
+#ifndef __QEMU_BARRIER_H
+#define __QEMU_BARRIER_H 1
+
+/* FIXME: arch dependant, x86 version */
+#define smp_wmb()   asm volatile("" ::: "memory")
+
+/* Compiler barrier */
+#define barrier()   asm volatile("" ::: "memory")
+
+#endif
diff --git a/qemu-0.15.x/qemu-char.c b/qemu-0.15.x/qemu-char.c
new file mode 100644
index 0000000..8e8cf31
--- /dev/null
+++ b/qemu-0.15.x/qemu-char.c
@@ -0,0 +1,2700 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "qemu-common.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "hw/usb.h"
+#include "hw/baum.h"
+#include "hw/msmouse.h"
+#include "qemu-objects.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef CONFIG_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <libutil.h>
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#if defined(__GLIBC__)
+#include <pty.h>
+#endif
+#elif defined(__DragonFly__)
+#include <libutil.h>
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
+#else
+#include <util.h>
+#endif
+#else
+#ifdef __linux__
+#include <pty.h>
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#include "qemu_socket.h"
+#include "ui/qemu-spice.h"
+
+#define READ_BUF_LEN 4096
+
+/***********************************************************/
+/* character device */
+
+static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+    QTAILQ_HEAD_INITIALIZER(chardevs);
+
+static void qemu_chr_event(CharDriverState *s, int event)
+{
+    /* Keep track if the char device is open */
+    switch (event) {
+        case CHR_EVENT_OPENED:
+            s->opened = 1;
+            break;
+        case CHR_EVENT_CLOSED:
+            s->opened = 0;
+            break;
+    }
+
+    if (!s->chr_event)
+        return;
+    s->chr_event(s->handler_opaque, event);
+}
+
+static void qemu_chr_generic_open_bh(void *opaque)
+{
+    CharDriverState *s = opaque;
+    qemu_chr_event(s, CHR_EVENT_OPENED);
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+}
+
+void qemu_chr_generic_open(CharDriverState *s)
+{
+    if (s->bh == NULL) {
+	s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
+	qemu_bh_schedule(s->bh);
+    }
+}
+
+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);
+}
+
+int qemu_chr_get_msgfd(CharDriverState *s)
+{
+    return s->get_msgfd ? s->get_msgfd(s) : -1;
+}
+
+int qemu_chr_add_client(CharDriverState *s, int fd)
+{
+    return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
+}
+
+void qemu_chr_accept_input(CharDriverState *s)
+{
+    if (s->chr_accept_input)
+        s->chr_accept_input(s);
+}
+
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+{
+    char buf[READ_BUF_LEN];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    qemu_chr_write(s, (uint8_t *)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,
+                           IOCanReadHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque)
+{
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        /* chr driver being released. */
+        ++s->avail_connections;
+    }
+    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);
+
+    /* We're connecting to an already opened device, so let's make sure we
+       also get the open event */
+    if (s->opened) {
+        qemu_chr_generic_open(s);
+    }
+}
+
+static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    return len;
+}
+
+static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+
+    *_chr= chr;
+    return 0;
+}
+
+/* MUX driver for serial I/O splitting */
+#define MAX_MUX 4
+#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
+#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
+typedef struct {
+    IOCanReadHandler *chr_can_read[MAX_MUX];
+    IOReadHandler *chr_read[MAX_MUX];
+    IOEventHandler *chr_event[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    CharDriverState *drv;
+    int focus;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+    /* Intermediate input buffer allows to catch escape sequences even if the
+       currently active device is not accepting any input - but only until it
+       is full as well. */
+    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+    int prod[MAX_MUX];
+    int cons[MAX_MUX];
+    int timestamps;
+    int linestart;
+    int64_t timestamps_start;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MuxDriver *d = chr->opaque;
+    int ret;
+    if (!d->timestamps) {
+        ret = d->drv->chr_write(d->drv, buf, len);
+    } else {
+        int i;
+
+        ret = 0;
+        for (i = 0; i < len; i++) {
+            if (d->linestart) {
+                char buf1[64];
+                int64_t ti;
+                int secs;
+
+                ti = qemu_get_clock_ms(rt_clock);
+                if (d->timestamps_start == -1)
+                    d->timestamps_start = ti;
+                ti -= d->timestamps_start;
+                secs = ti / 1000;
+                snprintf(buf1, sizeof(buf1),
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)(ti % 1000));
+                d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+                d->linestart = 0;
+            }
+            ret += d->drv->chr_write(d->drv, buf+i, 1);
+            if (buf[i] == '\n') {
+                d->linestart = 1;
+            }
+        }
+    }
+    return ret;
+}
+
+static const char * const mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% t    toggle console timestamps\n\r"
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+int term_escape_char = 0x01; /* ctrl-a is used for escape */
+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) {
+        snprintf(cbuf, sizeof(cbuf), "\n\r");
+        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
+    } else {
+        snprintf(cbuf, sizeof(cbuf),
+                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
+                 term_escape_char);
+    }
+    chr->chr_write(chr, (uint8_t *)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, (uint8_t *)ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
+        }
+    }
+}
+
+static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+{
+    if (d->chr_event[mux_nr])
+        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
+        switch(ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            {
+                 const char *term =  "QEMU: Terminated\n\r";
+                 chr->chr_write(chr,(uint8_t *)term,strlen(term));
+                 exit(0);
+                 break;
+            }
+        case 's':
+            bdrv_commit_all();
+            break;
+        case 'b':
+            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            /* Switch to the next registered device */
+            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+            d->focus++;
+            if (d->focus >= d->mux_cnt)
+                d->focus = 0;
+            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+            break;
+        case 't':
+            d->timestamps = !d->timestamps;
+            d->timestamps_start = -1;
+            d->linestart = 0;
+            break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static void mux_chr_accept_input(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+    int m = d->focus;
+
+    while (d->prod[m] != d->cons[m] &&
+           d->chr_can_read[m] &&
+           d->chr_can_read[m](d->ext_opaque[m])) {
+        d->chr_read[m](d->ext_opaque[m],
+                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
+    }
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = d->focus;
+
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
+        return 1;
+    if (d->chr_can_read[m])
+        return d->chr_can_read[m](d->ext_opaque[m]);
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = d->focus;
+    int i;
+
+    mux_chr_accept_input (opaque);
+
+    for(i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i])) {
+            if (d->prod[m] == d->cons[m] &&
+                d->chr_can_read[m] &&
+                d->chr_can_read[m](d->ext_opaque[m]))
+                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+            else
+                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
+        }
+}
+
+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++)
+        mux_chr_send_event(d, i, event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "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;
+    /* Fix up the real driver with mux routines */
+    if (d->mux_cnt == 0) {
+        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+                              mux_chr_event, chr);
+    }
+    if (d->focus != -1) {
+        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+    }
+    d->focus = d->mux_cnt;
+    d->mux_cnt++;
+    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+}
+
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
+    CharDriverState *chr;
+    MuxDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    d = qemu_mallocz(sizeof(MuxDriver));
+
+    chr->opaque = d;
+    d->drv = drv;
+    d->focus = -1;
+    chr->chr_write = mux_chr_write;
+    chr->chr_update_read_handler = mux_chr_update_read_handler;
+    chr->chr_accept_input = mux_chr_accept_input;
+    /* Frontend guest-open / -close notification is not support with muxes */
+    chr->chr_guest_open = NULL;
+    chr->chr_guest_close = NULL;
+
+    /* Muxes are always open on creation */
+    qemu_chr_generic_open(chr);
+
+    return chr;
+}
+
+
+#ifdef _WIN32
+int send_all(int fd, const void *buf, int len1)
+{
+    int ret, len;
+
+    len = len1;
+    while (len > 0) {
+        ret = send(fd, buf, len, 0);
+        if (ret < 0) {
+            errno = WSAGetLastError();
+            if (errno != WSAEWOULDBLOCK) {
+                return -1;
+            }
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+
+#else
+
+int send_all(int fd, const void *_buf, int len1)
+{
+    int ret, len;
+    const uint8_t *buf = _buf;
+
+    len = len1;
+    while (len > 0) {
+        ret = write(fd, buf, len);
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN)
+                return -1;
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+#endif /* !_WIN32 */
+
+#ifndef _WIN32
+
+typedef struct {
+    int fd_in, fd_out;
+    int max_size;
+} FDCharDriver;
+
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
+
+static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    FDCharDriver *s = chr->opaque;
+    return send_all(s->fd_out, buf, len);
+}
+
+static int fd_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void fd_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[READ_BUF_LEN];
+
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    if (len == 0)
+        return;
+    size = read(s->fd_in, buf, len);
+    if (size == 0) {
+        /* FD has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        return;
+    }
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void fd_chr_update_read_handler(CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+                                 fd_chr_read, NULL, chr);
+        }
+    }
+}
+
+static void fd_chr_close(struct CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        }
+    }
+
+    qemu_free(s);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+/* open a character device to a unix fd */
+static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
+{
+    CharDriverState *chr;
+    FDCharDriver *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(FDCharDriver));
+    s->fd_in = fd_in;
+    s->fd_out = fd_out;
+    chr->opaque = s;
+    chr->chr_write = fd_chr_write;
+    chr->chr_update_read_handler = fd_chr_update_read_handler;
+    chr->chr_close = fd_chr_close;
+
+    qemu_chr_generic_open(chr);
+
+    return chr;
+}
+
+static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr)
+{
+    int fd_out;
+
+    TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
+                      O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
+    if (fd_out < 0) {
+        return -errno;
+    }
+
+    *_chr = qemu_chr_open_fd(-1, fd_out);
+    return 0;
+}
+
+static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
+{
+    int fd_in, fd_out;
+    char filename_in[256], filename_out[256];
+    const char *filename = qemu_opt_get(opts, "path");
+
+    if (filename == NULL) {
+        fprintf(stderr, "chardev: pipe: no filename given\n");
+        return -EINVAL;
+    }
+
+    snprintf(filename_in, 256, "%s.in", filename);
+    snprintf(filename_out, 256, "%s.out", filename);
+    TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
+    TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
+    if (fd_in < 0 || fd_out < 0) {
+	if (fd_in >= 0)
+	    close(fd_in);
+	if (fd_out >= 0)
+	    close(fd_out);
+        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0) {
+            return -errno;
+        }
+    }
+
+    *_chr = qemu_chr_open_fd(fd_in, fd_out);
+    return 0;
+}
+
+
+/* for STDIO, we handle the case where several clients use it
+   (nographic mode) */
+
+#define TERM_FIFO_MAX_SIZE 1
+
+static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
+static int term_fifo_size;
+
+static int stdio_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+
+    /* try to flush the queue if needed */
+    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+        qemu_chr_read(chr, term_fifo, 1);
+        term_fifo_size = 0;
+    }
+    /* see if we can absorb more chars */
+    if (term_fifo_size == 0)
+        return 1;
+    else
+        return 0;
+}
+
+static void stdio_read(void *opaque)
+{
+    int size;
+    uint8_t buf[1];
+    CharDriverState *chr = opaque;
+
+    size = read(0, buf, 1);
+    if (size == 0) {
+        /* stdin has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+        return;
+    }
+    if (size > 0) {
+        if (qemu_chr_can_read(chr) > 0) {
+            qemu_chr_read(chr, buf, 1);
+        } else if (term_fifo_size == 0) {
+            term_fifo[term_fifo_size++] = buf[0];
+        }
+    }
+}
+
+/* init terminal so that we can grab keys */
+static struct termios oldtty;
+static int old_fd0_flags;
+static bool stdio_allow_signal;
+
+static void term_exit(void)
+{
+    tcsetattr (0, TCSANOW, &oldtty);
+    fcntl(0, F_SETFL, old_fd0_flags);
+}
+
+static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
+{
+    struct termios tty;
+
+    tty = oldtty;
+    if (!echo) {
+        tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+        tty.c_oflag |= OPOST;
+        tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+        tty.c_cflag &= ~(CSIZE|PARENB);
+        tty.c_cflag |= CS8;
+        tty.c_cc[VMIN] = 1;
+        tty.c_cc[VTIME] = 0;
+    }
+    /* if graphical mode, we allow Ctrl-C handling */
+    if (!stdio_allow_signal)
+        tty.c_lflag &= ~ISIG;
+
+    tcsetattr (0, TCSANOW, &tty);
+}
+
+static void qemu_chr_close_stdio(struct CharDriverState *chr)
+{
+    term_exit();
+    stdio_nb_clients--;
+    qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+    fd_chr_close(chr);
+}
+
+static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
+        return -EBUSY;
+    }
+
+    if (stdio_nb_clients == 0) {
+        old_fd0_flags = fcntl(0, F_GETFL);
+        tcgetattr (0, &oldtty);
+        fcntl(0, F_SETFL, O_NONBLOCK);
+        atexit(term_exit);
+    }
+
+    chr = qemu_chr_open_fd(0, 1);
+    chr->chr_close = qemu_chr_close_stdio;
+    chr->chr_set_echo = qemu_chr_set_echo_stdio;
+    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+    stdio_nb_clients++;
+    stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
+                                           display_type != DT_NOGRAPHIC);
+    qemu_chr_set_echo(chr, false);
+
+    *_chr = chr;
+    return 0;
+}
+
+#ifdef __sun__
+/* Once Solaris has openpty(), this is going to be removed. */
+static int openpty(int *amaster, int *aslave, char *name,
+                   struct termios *termp, struct winsize *winp)
+{
+        const char *slave;
+        int mfd = -1, sfd = -1;
+
+        *amaster = *aslave = -1;
+
+        mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+        if (mfd < 0)
+                goto err;
+
+        if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
+                goto err;
+
+        if ((slave = ptsname(mfd)) == NULL)
+                goto err;
+
+        if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
+                goto err;
+
+        if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
+            (termp != NULL && tcgetattr(sfd, termp) < 0))
+                goto err;
+
+        if (amaster)
+                *amaster = mfd;
+        if (aslave)
+                *aslave = sfd;
+        if (winp)
+                ioctl(sfd, TIOCSWINSZ, winp);
+
+        return 0;
+
+err:
+        if (sfd != -1)
+                close(sfd);
+        close(mfd);
+        return -1;
+}
+
+static void cfmakeraw (struct termios *termios_p)
+{
+        termios_p->c_iflag &=
+                ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+        termios_p->c_oflag &= ~OPOST;
+        termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+        termios_p->c_cflag &= ~(CSIZE|PARENB);
+        termios_p->c_cflag |= CS8;
+
+        termios_p->c_cc[VMIN] = 0;
+        termios_p->c_cc[VTIME] = 0;
+}
+#endif
+
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__GLIBC__)
+
+typedef struct {
+    int fd;
+    int connected;
+    int polling;
+    int read_bytes;
+    QEMUTimer *timer;
+} PtyCharDriver;
+
+static void pty_chr_update_read_handler(CharDriverState *chr);
+static void pty_chr_state(CharDriverState *chr, int connected);
+
+static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!s->connected) {
+        /* guest sends data, check for (re-)connect */
+        pty_chr_update_read_handler(chr);
+        return 0;
+    }
+    return send_all(s->fd, buf, len);
+}
+
+static int pty_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    s->read_bytes = qemu_chr_can_read(chr);
+    return s->read_bytes;
+}
+
+static void pty_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[READ_BUF_LEN];
+
+    len = sizeof(buf);
+    if (len > s->read_bytes)
+        len = s->read_bytes;
+    if (len == 0)
+        return;
+    size = read(s->fd, buf, len);
+    if ((size == -1 && errno == EIO) ||
+        (size == 0)) {
+        pty_chr_state(chr, 0);
+        return;
+    }
+    if (size > 0) {
+        pty_chr_state(chr, 1);
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void pty_chr_update_read_handler(CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+                         pty_chr_read, NULL, chr);
+    s->polling = 1;
+    /*
+     * Short timeout here: just need wait long enougth that qemu makes
+     * it through the poll loop once.  When reconnected we want a
+     * short timeout so we notice it almost instantly.  Otherwise
+     * read() gives us -EIO instantly, making pty_chr_state() reset the
+     * timeout to the normal (much longer) poll interval before the
+     * timer triggers.
+     */
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10);
+}
+
+static void pty_chr_state(CharDriverState *chr, int connected)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!connected) {
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+        s->connected = 0;
+        s->polling = 0;
+        /* (re-)connect poll interval for idle guests: once per second.
+         * We check more frequently in case the guests sends data to
+         * the virtual device linked to our pty. */
+        qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000);
+    } else {
+        if (!s->connected)
+            qemu_chr_generic_open(chr);
+        s->connected = 1;
+    }
+}
+
+static void pty_chr_timer(void *opaque)
+{
+    struct CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    if (s->connected)
+        return;
+    if (s->polling) {
+        /* If we arrive here without polling being cleared due
+         * read returning -EIO, then we are (re-)connected */
+        pty_chr_state(chr, 1);
+        return;
+    }
+
+    /* Next poll ... */
+    pty_chr_update_read_handler(chr);
+}
+
+static void pty_chr_close(struct CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_free(s);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+    PtyCharDriver *s;
+    struct termios tty;
+    int slave_fd, len;
+#if defined(__OpenBSD__) || defined(__DragonFly__)
+    char pty_name[PATH_MAX];
+#define q_ptsname(x) pty_name
+#else
+    char *pty_name = NULL;
+#define q_ptsname(x) ptsname(x)
+#endif
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(PtyCharDriver));
+
+    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+        return -errno;
+    }
+
+    /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
+    cfmakeraw(&tty);
+    tcsetattr(slave_fd, TCSAFLUSH, &tty);
+    close(slave_fd);
+
+    len = strlen(q_ptsname(s->fd)) + 5;
+    chr->filename = qemu_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
+    qemu_opt_set(opts, "path", q_ptsname(s->fd));
+    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+
+    chr->opaque = s;
+    chr->chr_write = pty_chr_write;
+    chr->chr_update_read_handler = pty_chr_update_read_handler;
+    chr->chr_close = pty_chr_close;
+
+    s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
+
+    *_chr = chr;
+    return 0;
+}
+
+static void tty_serial_init(int fd, int speed,
+                            int parity, int data_bits, int stop_bits)
+{
+    struct termios tty;
+    speed_t spd;
+
+#if 0
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr (fd, &tty);
+
+#define check_speed(val) if (speed <= val) { spd = B##val; break; }
+    speed = speed * 10 / 11;
+    do {
+        check_speed(50);
+        check_speed(75);
+        check_speed(110);
+        check_speed(134);
+        check_speed(150);
+        check_speed(200);
+        check_speed(300);
+        check_speed(600);
+        check_speed(1200);
+        check_speed(1800);
+        check_speed(2400);
+        check_speed(4800);
+        check_speed(9600);
+        check_speed(19200);
+        check_speed(38400);
+        /* Non-Posix values follow. They may be unsupported on some systems. */
+        check_speed(57600);
+        check_speed(115200);
+#ifdef B230400
+        check_speed(230400);
+#endif
+#ifdef B460800
+        check_speed(460800);
+#endif
+#ifdef B500000
+        check_speed(500000);
+#endif
+#ifdef B576000
+        check_speed(576000);
+#endif
+#ifdef B921600
+        check_speed(921600);
+#endif
+#ifdef B1000000
+        check_speed(1000000);
+#endif
+#ifdef B1152000
+        check_speed(1152000);
+#endif
+#ifdef B1500000
+        check_speed(1500000);
+#endif
+#ifdef B2000000
+        check_speed(2000000);
+#endif
+#ifdef B2500000
+        check_speed(2500000);
+#endif
+#ifdef B3000000
+        check_speed(3000000);
+#endif
+#ifdef B3500000
+        check_speed(3500000);
+#endif
+#ifdef B4000000
+        check_speed(4000000);
+#endif
+        spd = B115200;
+    } while (0);
+
+    cfsetispeed(&tty, spd);
+    cfsetospeed(&tty, spd);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
+    switch(data_bits) {
+    default:
+    case 8:
+        tty.c_cflag |= CS8;
+        break;
+    case 7:
+        tty.c_cflag |= CS7;
+        break;
+    case 6:
+        tty.c_cflag |= CS6;
+        break;
+    case 5:
+        tty.c_cflag |= CS5;
+        break;
+    }
+    switch(parity) {
+    default:
+    case 'N':
+        break;
+    case 'E':
+        tty.c_cflag |= PARENB;
+        break;
+    case 'O':
+        tty.c_cflag |= PARENB | PARODD;
+        break;
+    }
+    if (stop_bits == 2)
+        tty.c_cflag |= CSTOPB;
+
+    tcsetattr (fd, TCSANOW, &tty);
+}
+
+static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    FDCharDriver *s = chr->opaque;
+
+    switch(cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        {
+            QEMUSerialSetParams *ssp = arg;
+            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable)
+                tcsendbreak(s->fd_in, 1);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        {
+            int sarg = 0;
+            int *targ = (int *)arg;
+            ioctl(s->fd_in, TIOCMGET, &sarg);
+            *targ = 0;
+            if (sarg & TIOCM_CTS)
+                *targ |= CHR_TIOCM_CTS;
+            if (sarg & TIOCM_CAR)
+                *targ |= CHR_TIOCM_CAR;
+            if (sarg & TIOCM_DSR)
+                *targ |= CHR_TIOCM_DSR;
+            if (sarg & TIOCM_RI)
+                *targ |= CHR_TIOCM_RI;
+            if (sarg & TIOCM_DTR)
+                *targ |= CHR_TIOCM_DTR;
+            if (sarg & TIOCM_RTS)
+                *targ |= CHR_TIOCM_RTS;
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        {
+            int sarg = *(int *)arg;
+            int targ = 0;
+            ioctl(s->fd_in, TIOCMGET, &targ);
+            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+            if (sarg & CHR_TIOCM_CTS)
+                targ |= TIOCM_CTS;
+            if (sarg & CHR_TIOCM_CAR)
+                targ |= TIOCM_CAR;
+            if (sarg & CHR_TIOCM_DSR)
+                targ |= TIOCM_DSR;
+            if (sarg & CHR_TIOCM_RI)
+                targ |= TIOCM_RI;
+            if (sarg & CHR_TIOCM_DTR)
+                targ |= TIOCM_DTR;
+            if (sarg & CHR_TIOCM_RTS)
+                targ |= TIOCM_RTS;
+            ioctl(s->fd_in, TIOCMSET, &targ);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void qemu_chr_close_tty(CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+    int fd = -1;
+
+    if (s) {
+        fd = s->fd_in;
+    }
+
+    fd_chr_close(chr);
+
+    if (fd >= 0) {
+        close(fd);
+    }
+}
+
+static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    CharDriverState *chr;
+    int fd;
+
+    TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
+    if (fd < 0) {
+        return -errno;
+    }
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+    chr = qemu_chr_open_fd(fd, fd);
+    chr->chr_ioctl = tty_serial_ioctl;
+    chr->chr_close = qemu_chr_close_tty;
+
+    *_chr = chr;
+    return 0;
+}
+#else  /* ! __linux__ && ! __sun__ */
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
+{
+    return -ENOTSUP;
+}
+#endif /* __linux__ || __sun__ */
+
+#if defined(__linux__)
+typedef struct {
+    int fd;
+    int mode;
+} ParallelCharDriver;
+
+static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+{
+    if (s->mode != mode) {
+	int m = mode;
+        if (ioctl(s->fd, PPSETMODE, &m) < 0)
+            return 0;
+	s->mode = mode;
+    }
+    return 1;
+}
+
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0)
+            return -ENOTSUP;
+	/* Linux gives only the lowest bits, and no way to know data
+	   direction! For better compatibility set the fixed upper
+	   bits. */
+        *(uint8_t *)arg = b | 0xc0;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_DATA_DIR:
+        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_EPP_READ_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_READ:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void pp_close(CharDriverState *chr)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_free(drv);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    CharDriverState *chr;
+    ParallelCharDriver *drv;
+    int fd;
+
+    TFR(fd = open(filename, O_RDWR));
+    if (fd < 0) {
+        return -errno;
+    }
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        close(fd);
+        return -errno;
+    }
+
+    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    drv->fd = fd;
+    drv->mode = IEEE1284_MODE_COMPAT;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    chr->chr_close = pp_close;
+    chr->opaque = drv;
+
+    qemu_chr_generic_open(chr);
+
+    *_chr = chr;
+    return 0;
+}
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)(intptr_t)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPIGDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPIGCTRL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISCTRL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    CharDriverState *chr;
+    int fd;
+
+    fd = qemu_open(filename, O_RDWR);
+    if (fd < 0) {
+        return -errno;
+    }
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->opaque = (void *)(intptr_t)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+
+    *_chr = chr;
+    return 0;
+}
+#endif
+
+#else /* _WIN32 */
+
+typedef struct {
+    int max_size;
+    HANDLE hcom, hrecv, hsend;
+    OVERLAPPED orecv, osend;
+    BOOL fpipe;
+    DWORD len;
+} WinCharState;
+
+#define NSENDBUF 2048
+#define NRECVBUF 2048
+#define MAXCONNECT 1
+#define NTIMEOUT 5000
+
+static int win_chr_poll(void *opaque);
+static int win_chr_pipe_poll(void *opaque);
+
+static void win_chr_close(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->hsend) {
+        CloseHandle(s->hsend);
+        s->hsend = NULL;
+    }
+    if (s->hrecv) {
+        CloseHandle(s->hrecv);
+        s->hrecv = NULL;
+    }
+    if (s->hcom) {
+        CloseHandle(s->hcom);
+        s->hcom = NULL;
+    }
+    if (s->fpipe)
+        qemu_del_polling_cb(win_chr_pipe_poll, chr);
+    else
+        qemu_del_polling_cb(win_chr_poll, chr);
+
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+static int win_chr_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    COMMCONFIG comcfg;
+    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+    COMSTAT comstat;
+    DWORD size;
+    DWORD err;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+        fprintf(stderr, "Failed SetupComm\n");
+        goto fail;
+    }
+
+    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+    size = sizeof(COMMCONFIG);
+    GetDefaultCommConfig(filename, &comcfg, &size);
+    comcfg.dcb.DCBlength = sizeof(DCB);
+    CommConfigDialog(filename, NULL, &comcfg);
+
+    if (!SetCommState(s->hcom, &comcfg.dcb)) {
+        fprintf(stderr, "Failed SetCommState\n");
+        goto fail;
+    }
+
+    if (!SetCommMask(s->hcom, EV_ERR)) {
+        fprintf(stderr, "Failed SetCommMask\n");
+        goto fail;
+    }
+
+    cto.ReadIntervalTimeout = MAXDWORD;
+    if (!SetCommTimeouts(s->hcom, &cto)) {
+        fprintf(stderr, "Failed SetCommTimeouts\n");
+        goto fail;
+    }
+
+    if (!ClearCommError(s->hcom, &err, &comstat)) {
+        fprintf(stderr, "Failed ClearCommError\n");
+        goto fail;
+    }
+    qemu_add_polling_cb(win_chr_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+{
+    WinCharState *s = chr->opaque;
+    DWORD len, ret, size, err;
+
+    len = len1;
+    ZeroMemory(&s->osend, sizeof(s->osend));
+    s->osend.hEvent = s->hsend;
+    while (len > 0) {
+        if (s->hsend)
+            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+        else
+            ret = WriteFile(s->hcom, buf, len, &size, NULL);
+        if (!ret) {
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                if (ret) {
+                    buf += size;
+                    len -= size;
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else {
+            buf += size;
+            len -= size;
+        }
+    }
+    return len1 - len;
+}
+
+static int win_chr_read_poll(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void win_chr_readfile(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+    int ret, err;
+    uint8_t buf[READ_BUF_LEN];
+    DWORD size;
+
+    ZeroMemory(&s->orecv, sizeof(s->orecv));
+    s->orecv.hEvent = s->hrecv;
+    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+        }
+    }
+
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void win_chr_read(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->len > s->max_size)
+        s->len = s->max_size;
+    if (s->len == 0)
+        return;
+
+    win_chr_readfile(chr);
+}
+
+static int win_chr_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    COMSTAT status;
+    DWORD comerr;
+
+    ClearCommError(s->hcom, &comerr, &status);
+    if (status.cbInQue > 0) {
+        s->len = status.cbInQue;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return -EIO;
+    }
+    qemu_chr_generic_open(chr);
+
+    *_chr = chr;
+    return 0;
+}
+
+static int win_chr_pipe_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    DWORD size;
+
+    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+    if (size > 0) {
+        s->len = size;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    OVERLAPPED ov;
+    int ret;
+    DWORD size;
+    char openname[256];
+
+    s->fpipe = TRUE;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
+    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                              PIPE_WAIT,
+                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    ZeroMemory(&ov, sizeof(ov));
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ret = ConnectNamedPipe(s->hcom, &ov);
+    if (ret) {
+        fprintf(stderr, "Failed ConnectNamedPipe\n");
+        goto fail;
+    }
+
+    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+    if (!ret) {
+        fprintf(stderr, "Failed GetOverlappedResult\n");
+        if (ov.hEvent) {
+            CloseHandle(ov.hEvent);
+            ov.hEvent = NULL;
+        }
+        goto fail;
+    }
+
+    if (ov.hEvent) {
+        CloseHandle(ov.hEvent);
+        ov.hEvent = NULL;
+    }
+    qemu_add_polling_cb(win_chr_pipe_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+
+static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_pipe_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return -EIO;
+    }
+    qemu_chr_generic_open(chr);
+
+    *_chr = chr;
+    return 0;
+}
+
+static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    s->hcom = fd_out;
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    qemu_chr_generic_open(chr);
+    *pchr = chr;
+    return 0;
+}
+
+static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **chr)
+{
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr);
+}
+
+static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
+{
+    const char *file_out = qemu_opt_get(opts, "path");
+    HANDLE fd_out;
+
+    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (fd_out == INVALID_HANDLE_VALUE) {
+        return -EIO;
+    }
+
+    return qemu_chr_open_win_file(fd_out, _chr);
+}
+#endif /* !_WIN32 */
+
+/***********************************************************/
+/* UDP Net console */
+
+typedef struct {
+    int fd;
+    uint8_t buf[READ_BUF_LEN];
+    int bufcnt;
+    int bufptr;
+    int max_size;
+} NetCharDriver;
+
+static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    NetCharDriver *s = chr->opaque;
+
+    return send(s->fd, (const void *)buf, len, 0);
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+
+    /* If there were any stray characters in the queue process them
+     * first
+     */
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+    return s->max_size;
+}
+
+static void udp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    if (s->max_size == 0)
+        return;
+    s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
+    s->bufptr = s->bufcnt;
+    if (s->bufcnt <= 0)
+        return;
+
+    s->bufptr = 0;
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+}
+
+static void udp_chr_update_read_handler(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+
+    if (s->fd >= 0) {
+        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
+                             udp_chr_read, NULL, chr);
+    }
+}
+
+static void udp_chr_close(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    qemu_free(s);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr = NULL;
+    NetCharDriver *s = NULL;
+    int fd = -1;
+    int ret;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(NetCharDriver));
+
+    fd = inet_dgram_opts(opts);
+    if (fd < 0) {
+        fprintf(stderr, "inet_dgram_opts failed\n");
+        ret = -errno;
+        goto return_err;
+    }
+
+    s->fd = fd;
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    chr->opaque = s;
+    chr->chr_write = udp_chr_write;
+    chr->chr_update_read_handler = udp_chr_update_read_handler;
+    chr->chr_close = udp_chr_close;
+
+    *_chr = chr;
+    return 0;
+
+return_err:
+    qemu_free(chr);
+    qemu_free(s);
+    if (fd >= 0) {
+        closesocket(fd);
+    }
+    return ret;
+}
+
+/***********************************************************/
+/* TCP Net console */
+
+typedef struct {
+    int fd, listen_fd;
+    int connected;
+    int max_size;
+    int do_telnetopt;
+    int do_nodelay;
+    int is_unix;
+    int msgfd;
+} TCPCharDriver;
+
+static void tcp_chr_accept(void *opaque);
+
+static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->connected) {
+        return send_all(s->fd, buf, len);
+    } else {
+        /* XXX: indicate an error ? */
+        return len;
+    }
+}
+
+static int tcp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    if (!s->connected)
+        return 0;
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+                                      TCPCharDriver *s,
+                                      uint8_t *buf, int *size)
+{
+    /* Handle any telnet client's basic IAC options to satisfy char by
+     * char mode with no echo.  All IAC options will be removed from
+     * the buf and the do_telnetopt variable will be used to track the
+     * state of the width of the IAC information.
+     *
+     * IAC commands come in sets of 3 bytes with the exception of the
+     * "IAC BREAK" command and the double IAC.
+     */
+
+    int i;
+    int j = 0;
+
+    for (i = 0; i < *size; i++) {
+        if (s->do_telnetopt > 1) {
+            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                /* Double IAC means send an IAC */
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+                s->do_telnetopt = 1;
+            } else {
+                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+                    /* Handle IAC break commands by sending a serial break */
+                    qemu_chr_event(chr, CHR_EVENT_BREAK);
+                    s->do_telnetopt++;
+                }
+                s->do_telnetopt++;
+            }
+            if (s->do_telnetopt >= 4) {
+                s->do_telnetopt = 1;
+            }
+        } else {
+            if ((unsigned char)buf[i] == IAC) {
+                s->do_telnetopt = 2;
+            } else {
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+            }
+        }
+    }
+    *size = j;
+}
+
+static int tcp_get_msgfd(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+    int fd = s->msgfd;
+    s->msgfd = -1;
+    return fd;
+}
+
+#ifndef _WIN32
+static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
+{
+    TCPCharDriver *s = chr->opaque;
+    struct cmsghdr *cmsg;
+
+    for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+        int fd;
+
+        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+            cmsg->cmsg_level != SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS)
+            continue;
+
+        fd = *((int *)CMSG_DATA(cmsg));
+        if (fd < 0)
+            continue;
+
+        if (s->msgfd != -1)
+            close(s->msgfd);
+        s->msgfd = fd;
+    }
+}
+
+static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+{
+    TCPCharDriver *s = chr->opaque;
+    struct msghdr msg = { NULL, };
+    struct iovec iov[1];
+    union {
+        struct cmsghdr cmsg;
+        char control[CMSG_SPACE(sizeof(int))];
+    } msg_control;
+    ssize_t ret;
+
+    iov[0].iov_base = buf;
+    iov[0].iov_len = len;
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    ret = recvmsg(s->fd, &msg, 0);
+    if (ret > 0 && s->is_unix)
+        unix_process_msgfd(chr, &msg);
+
+    return ret;
+}
+#else
+static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+{
+    TCPCharDriver *s = chr->opaque;
+    return qemu_recv(s->fd, buf, len, 0);
+}
+#endif
+
+static void tcp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    uint8_t buf[READ_BUF_LEN];
+    int len, size;
+
+    if (!s->connected || s->max_size <= 0)
+        return;
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    size = tcp_chr_recv(chr, (void *)buf, len);
+    if (size == 0) {
+        /* connection closed */
+        s->connected = 0;
+        if (s->listen_fd >= 0) {
+            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        }
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        s->fd = -1;
+        qemu_chr_event(chr, CHR_EVENT_CLOSED);
+    } else if (size > 0) {
+        if (s->do_telnetopt)
+            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+        if (size > 0)
+            qemu_chr_read(chr, buf, size);
+    }
+}
+
+#ifndef _WIN32
+CharDriverState *qemu_chr_open_eventfd(int eventfd)
+{
+    return qemu_chr_open_fd(eventfd, eventfd);
+}
+#endif
+
+static void tcp_chr_connect(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+
+    s->connected = 1;
+    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+                         tcp_chr_read, NULL, chr);
+    qemu_chr_generic_open(chr);
+}
+
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+    char buf[3];
+    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    send(fd, (char *)buf, 3, 0);
+}
+
+static void socket_set_nodelay(int fd)
+{
+    int val = 1;
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+}
+
+static int tcp_chr_add_client(CharDriverState *chr, int fd)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd != -1)
+	return -1;
+
+    socket_set_nonblock(fd);
+    if (s->do_nodelay)
+        socket_set_nodelay(fd);
+    s->fd = fd;
+    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+    tcp_chr_connect(chr);
+
+    return 0;
+}
+
+static void tcp_chr_accept(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    struct sockaddr_in saddr;
+#ifndef _WIN32
+    struct sockaddr_un uaddr;
+#endif
+    struct sockaddr *addr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+#ifndef _WIN32
+	if (s->is_unix) {
+	    len = sizeof(uaddr);
+	    addr = (struct sockaddr *)&uaddr;
+	} else
+#endif
+	{
+	    len = sizeof(saddr);
+	    addr = (struct sockaddr *)&saddr;
+	}
+        fd = qemu_accept(s->listen_fd, addr, &len);
+        if (fd < 0 && errno != EINTR) {
+            return;
+        } else if (fd >= 0) {
+            if (s->do_telnetopt)
+                tcp_chr_telnet_init(fd);
+            break;
+        }
+    }
+    if (tcp_chr_add_client(chr, fd) < 0)
+	close(fd);
+}
+
+static void tcp_chr_close(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    if (s->listen_fd >= 0) {
+        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        closesocket(s->listen_fd);
+    }
+    qemu_free(s);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
+static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr = NULL;
+    TCPCharDriver *s = NULL;
+    int fd = -1;
+    int is_listen;
+    int is_waitconnect;
+    int do_nodelay;
+    int is_unix;
+    int is_telnet;
+    int ret;
+
+    is_listen      = qemu_opt_get_bool(opts, "server", 0);
+    is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
+    is_telnet      = qemu_opt_get_bool(opts, "telnet", 0);
+    do_nodelay     = !qemu_opt_get_bool(opts, "delay", 1);
+    is_unix        = qemu_opt_get(opts, "path") != NULL;
+    if (!is_listen)
+        is_waitconnect = 0;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(TCPCharDriver));
+
+    if (is_unix) {
+        if (is_listen) {
+            fd = unix_listen_opts(opts);
+        } else {
+            fd = unix_connect_opts(opts);
+        }
+    } else {
+        if (is_listen) {
+            fd = inet_listen_opts(opts, 0);
+        } else {
+            fd = inet_connect_opts(opts);
+        }
+    }
+    if (fd < 0) {
+        ret = -errno;
+        goto fail;
+    }
+
+    if (!is_waitconnect)
+        socket_set_nonblock(fd);
+
+    s->connected = 0;
+    s->fd = -1;
+    s->listen_fd = -1;
+    s->msgfd = -1;
+    s->is_unix = is_unix;
+    s->do_nodelay = do_nodelay && !is_unix;
+
+    chr->opaque = s;
+    chr->chr_write = tcp_chr_write;
+    chr->chr_close = tcp_chr_close;
+    chr->get_msgfd = tcp_get_msgfd;
+    chr->chr_add_client = tcp_chr_add_client;
+
+    if (is_listen) {
+        s->listen_fd = fd;
+        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        if (is_telnet)
+            s->do_telnetopt = 1;
+
+    } else {
+        s->connected = 1;
+        s->fd = fd;
+        socket_set_nodelay(fd);
+        tcp_chr_connect(chr);
+    }
+
+    /* for "info chardev" monitor command */
+    chr->filename = qemu_malloc(256);
+    if (is_unix) {
+        snprintf(chr->filename, 256, "unix:%s%s",
+                 qemu_opt_get(opts, "path"),
+                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+    } else if (is_telnet) {
+        snprintf(chr->filename, 256, "telnet:%s:%s%s",
+                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
+                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+    } else {
+        snprintf(chr->filename, 256, "tcp:%s:%s%s",
+                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
+                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+    }
+
+    if (is_listen && is_waitconnect) {
+        printf("QEMU waiting for connection on: %s\n",
+               chr->filename);
+        tcp_chr_accept(chr);
+        socket_set_nonblock(s->listen_fd);
+    }
+
+    *_chr = chr;
+    return 0;
+
+ fail:
+    if (fd >= 0)
+        closesocket(fd);
+    qemu_free(s);
+    qemu_free(chr);
+    return ret;
+}
+
+/***********************************************************/
+/* Memory chardev */
+typedef struct {
+    size_t outbuf_size;
+    size_t outbuf_capacity;
+    uint8_t *outbuf;
+} MemoryDriver;
+
+static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MemoryDriver *d = chr->opaque;
+
+    /* TODO: the QString implementation has the same code, we should
+     * introduce a generic way to do this in cutils.c */
+    if (d->outbuf_capacity < d->outbuf_size + len) {
+        /* grow outbuf */
+        d->outbuf_capacity += len;
+        d->outbuf_capacity *= 2;
+        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
+    }
+
+    memcpy(d->outbuf + d->outbuf_size, buf, len);
+    d->outbuf_size += len;
+
+    return len;
+}
+
+void qemu_chr_init_mem(CharDriverState *chr)
+{
+    MemoryDriver *d;
+
+    d = qemu_malloc(sizeof(*d));
+    d->outbuf_size = 0;
+    d->outbuf_capacity = 4096;
+    d->outbuf = qemu_mallocz(d->outbuf_capacity);
+
+    memset(chr, 0, sizeof(*chr));
+    chr->opaque = d;
+    chr->chr_write = mem_chr_write;
+}
+
+QString *qemu_chr_mem_to_qs(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
+}
+
+/* NOTE: this driver can not be closed with qemu_chr_close()! */
+void qemu_chr_close_mem(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+
+    qemu_free(d->outbuf);
+    qemu_free(chr->opaque);
+    chr->opaque = NULL;
+    chr->chr_write = NULL;
+}
+
+size_t qemu_chr_mem_osize(const CharDriverState *chr)
+{
+    const MemoryDriver *d = chr->opaque;
+    return d->outbuf_size;
+}
+
+QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
+{
+    char host[65], port[33], width[8], height[8];
+    int pos;
+    const char *p;
+    QemuOpts *opts;
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
+    if (NULL == opts)
+        return NULL;
+
+    if (strstart(filename, "mon:", &p)) {
+        filename = p;
+        qemu_opt_set(opts, "mux", "on");
+    }
+
+    if (strcmp(filename, "null")    == 0 ||
+        strcmp(filename, "pty")     == 0 ||
+        strcmp(filename, "msmouse") == 0 ||
+        strcmp(filename, "braille") == 0 ||
+        strcmp(filename, "stdio")   == 0) {
+        qemu_opt_set(opts, "backend", filename);
+        return opts;
+    }
+    if (strstart(filename, "vc", &p)) {
+        qemu_opt_set(opts, "backend", "vc");
+        if (*p == ':') {
+            if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) {
+                /* pixels */
+                qemu_opt_set(opts, "width", width);
+                qemu_opt_set(opts, "height", height);
+            } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) {
+                /* chars */
+                qemu_opt_set(opts, "cols", width);
+                qemu_opt_set(opts, "rows", height);
+            } else {
+                goto fail;
+            }
+        }
+        return opts;
+    }
+    if (strcmp(filename, "con:") == 0) {
+        qemu_opt_set(opts, "backend", "console");
+        return opts;
+    }
+    if (strstart(filename, "COM", NULL)) {
+        qemu_opt_set(opts, "backend", "serial");
+        qemu_opt_set(opts, "path", filename);
+        return opts;
+    }
+    if (strstart(filename, "file:", &p)) {
+        qemu_opt_set(opts, "backend", "file");
+        qemu_opt_set(opts, "path", p);
+        return opts;
+    }
+    if (strstart(filename, "pipe:", &p)) {
+        qemu_opt_set(opts, "backend", "pipe");
+        qemu_opt_set(opts, "path", p);
+        return opts;
+    }
+    if (strstart(filename, "tcp:", &p) ||
+        strstart(filename, "telnet:", &p)) {
+        if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
+            host[0] = 0;
+            if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
+                goto fail;
+        }
+        qemu_opt_set(opts, "backend", "socket");
+        qemu_opt_set(opts, "host", host);
+        qemu_opt_set(opts, "port", port);
+        if (p[pos] == ',') {
+            if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0)
+                goto fail;
+        }
+        if (strstart(filename, "telnet:", &p))
+            qemu_opt_set(opts, "telnet", "on");
+        return opts;
+    }
+    if (strstart(filename, "udp:", &p)) {
+        qemu_opt_set(opts, "backend", "udp");
+        if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
+            host[0] = 0;
+            if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
+                goto fail;
+            }
+        }
+        qemu_opt_set(opts, "host", host);
+        qemu_opt_set(opts, "port", port);
+        if (p[pos] == '@') {
+            p += pos + 1;
+            if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
+                host[0] = 0;
+                if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
+                    goto fail;
+                }
+            }
+            qemu_opt_set(opts, "localaddr", host);
+            qemu_opt_set(opts, "localport", port);
+        }
+        return opts;
+    }
+    if (strstart(filename, "unix:", &p)) {
+        qemu_opt_set(opts, "backend", "socket");
+        if (qemu_opts_do_parse(opts, p, "path") != 0)
+            goto fail;
+        return opts;
+    }
+    if (strstart(filename, "/dev/parport", NULL) ||
+        strstart(filename, "/dev/ppi", NULL)) {
+        qemu_opt_set(opts, "backend", "parport");
+        qemu_opt_set(opts, "path", filename);
+        return opts;
+    }
+    if (strstart(filename, "/dev/", NULL)) {
+        qemu_opt_set(opts, "backend", "tty");
+        qemu_opt_set(opts, "path", filename);
+        return opts;
+    }
+
+fail:
+    qemu_opts_del(opts);
+    return NULL;
+}
+
+static const struct {
+    const char *name;
+    int (*open)(QemuOpts *opts, CharDriverState **chr);
+} backend_table[] = {
+    { .name = "null",      .open = qemu_chr_open_null },
+    { .name = "socket",    .open = qemu_chr_open_socket },
+    { .name = "udp",       .open = qemu_chr_open_udp },
+    { .name = "msmouse",   .open = qemu_chr_open_msmouse },
+    { .name = "vc",        .open = text_console_init },
+#ifdef _WIN32
+    { .name = "file",      .open = qemu_chr_open_win_file_out },
+    { .name = "pipe",      .open = qemu_chr_open_win_pipe },
+    { .name = "console",   .open = qemu_chr_open_win_con },
+    { .name = "serial",    .open = qemu_chr_open_win },
+#else
+    { .name = "file",      .open = qemu_chr_open_file_out },
+    { .name = "pipe",      .open = qemu_chr_open_pipe },
+    { .name = "pty",       .open = qemu_chr_open_pty },
+    { .name = "stdio",     .open = qemu_chr_open_stdio },
+#endif
+#ifdef CONFIG_BRLAPI
+    { .name = "braille",   .open = chr_baum_init },
+#endif
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__FreeBSD_kernel__)
+    { .name = "tty",       .open = qemu_chr_open_tty },
+#endif
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \
+    || defined(__FreeBSD_kernel__)
+    { .name = "parport",   .open = qemu_chr_open_pp },
+#endif
+#ifdef CONFIG_SPICE
+    { .name = "spicevmc",     .open = qemu_chr_open_spice },
+#endif
+};
+
+CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+                                    void (*init)(struct CharDriverState *s))
+{
+    CharDriverState *chr;
+    int i;
+    int ret;
+
+    if (qemu_opts_id(opts) == NULL) {
+        fprintf(stderr, "chardev: no id specified\n");
+        return NULL;
+    }
+
+    if (qemu_opt_get(opts, "backend") == NULL) {
+        fprintf(stderr, "chardev: \"%s\" missing backend\n",
+                qemu_opts_id(opts));
+        return NULL;
+    }
+    for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
+        if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
+            break;
+    }
+    if (i == ARRAY_SIZE(backend_table)) {
+        fprintf(stderr, "chardev: backend \"%s\" not found\n",
+                qemu_opt_get(opts, "backend"));
+        return NULL;
+    }
+
+    ret = backend_table[i].open(opts, &chr);
+    if (ret < 0) {
+        fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n",
+                qemu_opt_get(opts, "backend"), strerror(-ret));
+        return NULL;
+    }
+
+    if (!chr->filename)
+        chr->filename = qemu_strdup(qemu_opt_get(opts, "backend"));
+    chr->init = init;
+    QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+
+    if (qemu_opt_get_bool(opts, "mux", 0)) {
+        CharDriverState *base = chr;
+        int len = strlen(qemu_opts_id(opts)) + 6;
+        base->label = qemu_malloc(len);
+        snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
+        chr = qemu_chr_open_mux(base);
+        chr->filename = base->filename;
+        chr->avail_connections = MAX_MUX;
+        QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+    } else {
+        chr->avail_connections = 1;
+    }
+    chr->label = qemu_strdup(qemu_opts_id(opts));
+    return chr;
+}
+
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+{
+    const char *p;
+    CharDriverState *chr;
+    QemuOpts *opts;
+
+    if (strstart(filename, "chardev:", &p)) {
+        return qemu_chr_find(p);
+    }
+
+    opts = qemu_chr_parse_compat(label, filename);
+    if (!opts)
+        return NULL;
+
+    chr = qemu_chr_open_opts(opts, init);
+    if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
+        monitor_init(chr, MONITOR_USE_READLINE);
+    }
+    qemu_opts_del(opts);
+    return chr;
+}
+
+void qemu_chr_set_echo(struct CharDriverState *chr, bool echo)
+{
+    if (chr->chr_set_echo) {
+        chr->chr_set_echo(chr, echo);
+    }
+}
+
+void qemu_chr_guest_open(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_open) {
+        chr->chr_guest_open(chr);
+    }
+}
+
+void qemu_chr_guest_close(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_close) {
+        chr->chr_guest_close(chr);
+    }
+}
+
+void qemu_chr_close(CharDriverState *chr)
+{
+    QTAILQ_REMOVE(&chardevs, chr, next);
+    if (chr->chr_close)
+        chr->chr_close(chr);
+    qemu_free(chr->filename);
+    qemu_free(chr->label);
+    qemu_free(chr);
+}
+
+static void qemu_chr_qlist_iter(QObject *obj, void *opaque)
+{
+    QDict *chr_dict;
+    Monitor *mon = opaque;
+
+    chr_dict = qobject_to_qdict(obj);
+    monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"),
+                                         qdict_get_str(chr_dict, "filename"));
+}
+
+void qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
+{
+    qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
+}
+
+void qemu_chr_info(Monitor *mon, QObject **ret_data)
+{
+    QList *chr_list;
+    CharDriverState *chr;
+
+    chr_list = qlist_new();
+
+    QTAILQ_FOREACH(chr, &chardevs, next) {
+        QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }",
+                                          chr->label, chr->filename);
+        qlist_append_obj(chr_list, obj);
+    }
+
+    *ret_data = QOBJECT(chr_list);
+}
+
+CharDriverState *qemu_chr_find(const char *name)
+{
+    CharDriverState *chr;
+
+    QTAILQ_FOREACH(chr, &chardevs, next) {
+        if (strcmp(chr->label, name) != 0)
+            continue;
+        return chr;
+    }
+    return NULL;
+}
diff --git a/qemu-0.15.x/qemu-char.h b/qemu-0.15.x/qemu-char.h
new file mode 100644
index 0000000..f361c6d
--- /dev/null
+++ b/qemu-0.15.x/qemu-char.h
@@ -0,0 +1,130 @@
+#ifndef QEMU_CHAR_H
+#define QEMU_CHAR_H
+
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "qobject.h"
+#include "qstring.h"
+
+/* 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_OPENED  2 /* new connection established */
+#define CHR_EVENT_MUX_IN  3 /* mux-focus was set to this terminal */
+#define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */
+#define CHR_EVENT_CLOSED  5 /* connection closed */
+
+
+#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
+#define CHR_IOCTL_PP_DATA_DIR        12
+
+#define CHR_IOCTL_SERIAL_SET_TIOCM   13
+#define CHR_IOCTL_SERIAL_GET_TIOCM   14
+
+#define CHR_TIOCM_CTS	0x020
+#define CHR_TIOCM_CAR	0x040
+#define CHR_TIOCM_DSR	0x100
+#define CHR_TIOCM_RI	0x080
+#define CHR_TIOCM_DTR	0x002
+#define CHR_TIOCM_RTS	0x004
+
+typedef void IOEventHandler(void *opaque, int event);
+
+struct CharDriverState {
+    void (*init)(struct CharDriverState *s);
+    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);
+    int (*get_msgfd)(struct CharDriverState *s);
+    int (*chr_add_client)(struct CharDriverState *chr, int fd);
+    IOEventHandler *chr_event;
+    IOCanReadHandler *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 (*chr_accept_input)(struct CharDriverState *chr);
+    void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
+    void (*chr_guest_open)(struct CharDriverState *chr);
+    void (*chr_guest_close)(struct CharDriverState *chr);
+    void *opaque;
+    QEMUBH *bh;
+    char *label;
+    char *filename;
+    int opened;
+    int avail_connections;
+    QTAILQ_ENTRY(CharDriverState) next;
+};
+
+QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
+CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+                                    void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
+void qemu_chr_set_echo(struct CharDriverState *chr, bool echo);
+void qemu_chr_guest_open(struct CharDriverState *chr);
+void qemu_chr_guest_close(struct CharDriverState *chr);
+void qemu_chr_close(CharDriverState *chr);
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+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,
+                           IOCanReadHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque);
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+void qemu_chr_generic_open(CharDriverState *s);
+int qemu_chr_can_read(CharDriverState *s);
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
+int qemu_chr_get_msgfd(CharDriverState *s);
+void qemu_chr_accept_input(CharDriverState *s);
+int qemu_chr_add_client(CharDriverState *s, int fd);
+void qemu_chr_info_print(Monitor *mon, const QObject *ret_data);
+void qemu_chr_info(Monitor *mon, QObject **ret_data);
+CharDriverState *qemu_chr_find(const char *name);
+
+/* add an eventfd to the qemu devices that are polled */
+CharDriverState *qemu_chr_open_eventfd(int eventfd);
+
+extern int term_escape_char;
+
+/* memory chardev */
+void qemu_chr_init_mem(CharDriverState *chr);
+void qemu_chr_close_mem(CharDriverState *chr);
+QString *qemu_chr_mem_to_qs(CharDriverState *chr);
+size_t qemu_chr_mem_osize(const CharDriverState *chr);
+
+/* async I/O support */
+
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque);
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque);
+#endif
diff --git a/qemu-0.15.x/qemu-common.h b/qemu-0.15.x/qemu-common.h
new file mode 100644
index 0000000..391fadd
--- /dev/null
+++ b/qemu-0.15.x/qemu-common.h
@@ -0,0 +1,376 @@
+/* Common header file that is included by all of qemu.  */
+#ifndef QEMU_COMMON_H
+#define QEMU_COMMON_H
+
+#include "compiler.h"
+#include "config-host.h"
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
+typedef struct QEMUTimer QEMUTimer;
+typedef struct QEMUFile QEMUFile;
+typedef struct QEMUBH QEMUBH;
+typedef struct DeviceState DeviceState;
+
+struct Monitor;
+typedef struct Monitor Monitor;
+
+/* we put basic includes here to avoid repeating them in device drivers */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <signal.h>
+
+#ifdef _WIN32
+#include "qemu-os-win32.h"
+#endif
+
+#ifdef CONFIG_POSIX
+#include "qemu-os-posix.h"
+#endif
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#ifndef ENOMEDIUM
+#define ENOMEDIUM ENODEV
+#endif
+#if !defined(ENOTSUP)
+#define ENOTSUP 4096
+#endif
+#ifndef TIME_MAX
+#define TIME_MAX LONG_MAX
+#endif
+
+#ifndef CONFIG_IOVEC
+#define CONFIG_IOVEC
+struct iovec {
+    void *iov_base;
+    size_t iov_len;
+};
+/*
+ * Use the same value as Linux for now.
+ */
+#define IOV_MAX		1024
+#else
+#include <sys/uio.h>
+#endif
+
+typedef int (*fprintf_function)(FILE *f, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+#ifdef _WIN32
+#define fsync _commit
+#define lseek _lseeki64
+int qemu_ftruncate64(int, int64_t);
+#define ftruncate qemu_ftruncate64
+
+static inline char *realpath(const char *path, char *resolved_path)
+{
+    _fullpath(resolved_path, path, _MAX_PATH);
+    return resolved_path;
+}
+#endif
+
+/* FIXME: Remove NEED_CPU_H.  */
+#ifndef NEED_CPU_H
+
+#include "osdep.h"
+#include "bswap.h"
+
+#else
+
+#include "cpu.h"
+
+#endif /* !defined(NEED_CPU_H) */
+
+/* main function, renamed */
+#if defined(CONFIG_COCOA)
+int qemu_main(int argc, char **argv, char **envp);
+#endif
+
+/* bottom halves */
+typedef void QEMUBHFunc(void *opaque);
+
+void async_context_push(void);
+void async_context_pop(void);
+int get_async_context_id(void);
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
+void qemu_bh_schedule(QEMUBH *bh);
+/* Bottom halfs that are scheduled from a bottom half handler are instantly
+ * invoked.  This can create an infinite loop if a bottom half handler
+ * schedules itself.  qemu_bh_schedule_idle() avoids this infinite loop by
+ * ensuring that the bottom half isn't executed until the next main loop
+ * iteration.
+ */
+void qemu_bh_schedule_idle(QEMUBH *bh);
+void qemu_bh_cancel(QEMUBH *bh);
+void qemu_bh_delete(QEMUBH *bh);
+int qemu_bh_poll(void);
+void qemu_bh_update_timeout(int *timeout);
+
+void qemu_get_timedate(struct tm *tm, int offset);
+int qemu_timedate_diff(struct tm *tm);
+
+/* cutils.c */
+void pstrcpy(char *buf, int buf_size, const char *str);
+char *pstrcat(char *buf, int buf_size, const char *s);
+int strstart(const char *str, const char *val, const char **ptr);
+int stristart(const char *str, const char *val, const char **ptr);
+int qemu_strnlen(const char *s, int max_len);
+time_t mktimegm(struct tm *tm);
+int qemu_fls(int i);
+int qemu_fdatasync(int fd);
+int fcntl_setfl(int fd, int flag);
+
+/*
+ * strtosz() suffixes used to specify the default treatment of an
+ * argument passed to strtosz() without an explicit suffix.
+ * These should be defined using upper case characters in the range
+ * A-Z, as strtosz() will use qemu_toupper() on the given argument
+ * prior to comparison.
+ */
+#define STRTOSZ_DEFSUFFIX_TB	'T'
+#define STRTOSZ_DEFSUFFIX_GB	'G'
+#define STRTOSZ_DEFSUFFIX_MB	'M'
+#define STRTOSZ_DEFSUFFIX_KB	'K'
+#define STRTOSZ_DEFSUFFIX_B	'B'
+int64_t strtosz(const char *nptr, char **end);
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
+
+/* path.c */
+void init_paths(const char *prefix);
+const char *path(const char *pathname);
+
+#define qemu_isalnum(c)		isalnum((unsigned char)(c))
+#define qemu_isalpha(c)		isalpha((unsigned char)(c))
+#define qemu_iscntrl(c)		iscntrl((unsigned char)(c))
+#define qemu_isdigit(c)		isdigit((unsigned char)(c))
+#define qemu_isgraph(c)		isgraph((unsigned char)(c))
+#define qemu_islower(c)		islower((unsigned char)(c))
+#define qemu_isprint(c)		isprint((unsigned char)(c))
+#define qemu_ispunct(c)		ispunct((unsigned char)(c))
+#define qemu_isspace(c)		isspace((unsigned char)(c))
+#define qemu_isupper(c)		isupper((unsigned char)(c))
+#define qemu_isxdigit(c)	isxdigit((unsigned char)(c))
+#define qemu_tolower(c)		tolower((unsigned char)(c))
+#define qemu_toupper(c)		toupper((unsigned char)(c))
+#define qemu_isascii(c)		isascii((unsigned char)(c))
+#define qemu_toascii(c)		toascii((unsigned char)(c))
+
+void *qemu_oom_check(void *ptr);
+void *qemu_malloc(size_t size);
+void *qemu_realloc(void *ptr, size_t size);
+void *qemu_mallocz(size_t size);
+void qemu_free(void *ptr);
+char *qemu_strdup(const char *str);
+char *qemu_strndup(const char *str, size_t size);
+
+void qemu_mutex_lock_iothread(void);
+void qemu_mutex_unlock_iothread(void);
+
+int qemu_open(const char *name, int flags, ...);
+ssize_t qemu_write_full(int fd, const void *buf, size_t count)
+    QEMU_WARN_UNUSED_RESULT;
+void qemu_set_cloexec(int fd);
+
+#ifndef _WIN32
+int qemu_add_child_watch(pid_t pid);
+int qemu_eventfd(int pipefd[2]);
+int qemu_pipe(int pipefd[2]);
+#endif
+
+#ifdef _WIN32
+#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags)
+#else
+#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags)
+#endif
+
+/* Error handling.  */
+
+void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
+/* IO callbacks.  */
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanReadHandler(void *opaque);
+typedef void IOHandler(void *opaque);
+
+void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
+void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+
+struct ParallelIOArg {
+    void *buffer;
+    int count;
+};
+
+typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size);
+
+/* A load of opaque types so that device init declarations don't have to
+   pull in all the real definitions.  */
+typedef struct NICInfo NICInfo;
+typedef struct HCIInfo HCIInfo;
+typedef struct AudioState AudioState;
+typedef struct BlockDriverState BlockDriverState;
+typedef struct DriveInfo DriveInfo;
+typedef struct DisplayState DisplayState;
+typedef struct DisplayChangeListener DisplayChangeListener;
+typedef struct DisplaySurface DisplaySurface;
+typedef struct DisplayAllocator DisplayAllocator;
+typedef struct PixelFormat PixelFormat;
+typedef struct TextConsole TextConsole;
+typedef TextConsole QEMUConsole;
+typedef struct CharDriverState CharDriverState;
+typedef struct MACAddr MACAddr;
+typedef struct VLANState VLANState;
+typedef struct VLANClientState VLANClientState;
+typedef struct i2c_bus i2c_bus;
+typedef struct i2c_slave i2c_slave;
+typedef struct SMBusDevice SMBusDevice;
+typedef struct PCIHostState PCIHostState;
+typedef struct PCIExpressHost PCIExpressHost;
+typedef struct PCIBus PCIBus;
+typedef struct PCIDevice PCIDevice;
+typedef struct PCIExpressDevice PCIExpressDevice;
+typedef struct PCIBridge PCIBridge;
+typedef struct PCIEAERMsg PCIEAERMsg;
+typedef struct PCIEAERLog PCIEAERLog;
+typedef struct PCIEAERErr PCIEAERErr;
+typedef struct PCIEPort PCIEPort;
+typedef struct PCIESlot PCIESlot;
+typedef struct SerialState SerialState;
+typedef struct IRQState *qemu_irq;
+typedef struct PCMCIACardState PCMCIACardState;
+typedef struct MouseTransformInfo MouseTransformInfo;
+typedef struct uWireSlave uWireSlave;
+typedef struct I2SCodec I2SCodec;
+typedef struct SSIBus SSIBus;
+typedef struct EventNotifier EventNotifier;
+typedef struct VirtIODevice VirtIODevice;
+
+typedef uint64_t pcibus_t;
+
+void cpu_exec_init_all(unsigned long tb_size);
+
+/* CPU save/load.  */
+void cpu_save(QEMUFile *f, void *opaque);
+int cpu_load(QEMUFile *f, void *opaque, int version_id);
+
+/* Force QEMU to stop what it's doing and service IO */
+void qemu_service_io(void);
+
+/* Force QEMU to process pending events */
+void qemu_notify_event(void);
+
+/* Unblock cpu */
+void qemu_cpu_kick(void *env);
+void qemu_cpu_kick_self(void);
+int qemu_cpu_is_self(void *env);
+bool all_cpu_threads_idle(void);
+
+/* work queue */
+struct qemu_work_item {
+    struct qemu_work_item *next;
+    void (*func)(void *data);
+    void *data;
+    int done;
+};
+
+#ifdef CONFIG_USER_ONLY
+#define qemu_init_vcpu(env) do { } while (0)
+#else
+void qemu_init_vcpu(void *env);
+#endif
+
+typedef struct QEMUIOVector {
+    struct iovec *iov;
+    int niov;
+    int nalloc;
+    size_t size;
+} QEMUIOVector;
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
+void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
+void qemu_iovec_copy(QEMUIOVector *dst, QEMUIOVector *src, uint64_t skip,
+    size_t size);
+void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size);
+void qemu_iovec_destroy(QEMUIOVector *qiov);
+void qemu_iovec_reset(QEMUIOVector *qiov);
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
+void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+                            size_t skip);
+
+void qemu_progress_init(int enabled, float min_skip);
+void qemu_progress_end(void);
+void qemu_progress_print(float delta, int max);
+
+#define QEMU_FILE_TYPE_BIOS   0
+#define QEMU_FILE_TYPE_KEYMAP 1
+char *qemu_find_file(int type, const char *name);
+
+/* OS specific functions */
+void os_setup_early_signal_handling(void);
+char *os_find_datadir(const char *argv0);
+void os_parse_cmd_args(int index, const char *optarg);
+void os_pidfile_error(void);
+
+/* Convert a byte between binary and BCD.  */
+static inline uint8_t to_bcd(uint8_t val)
+{
+    return ((val / 10) << 4) | (val % 10);
+}
+
+static inline uint8_t from_bcd(uint8_t val)
+{
+    return ((val >> 4) * 10) + (val & 0x0f);
+}
+
+/* compute with 96 bit intermediate result: (a*b)/c */
+static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+#ifdef HOST_WORDS_BIGENDIAN
+            uint32_t high, low;
+#else
+            uint32_t low, high;
+#endif
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
+
+#include "module.h"
+
+#endif
diff --git a/qemu-0.15.x/qemu-config.c b/qemu-0.15.x/qemu-config.c
new file mode 100644
index 0000000..b2ec40b
--- /dev/null
+++ b/qemu-0.15.x/qemu-config.c
@@ -0,0 +1,703 @@
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "hw/qdev.h"
+
+static QemuOptsList qemu_drive_opts = {
+    .name = "drive",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
+    .desc = {
+        {
+            .name = "bus",
+            .type = QEMU_OPT_NUMBER,
+            .help = "bus number",
+        },{
+            .name = "unit",
+            .type = QEMU_OPT_NUMBER,
+            .help = "unit number (i.e. lun for scsi)",
+        },{
+            .name = "if",
+            .type = QEMU_OPT_STRING,
+            .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
+        },{
+            .name = "index",
+            .type = QEMU_OPT_NUMBER,
+            .help = "index number",
+        },{
+            .name = "cyls",
+            .type = QEMU_OPT_NUMBER,
+            .help = "number of cylinders (ide disk geometry)",
+        },{
+            .name = "heads",
+            .type = QEMU_OPT_NUMBER,
+            .help = "number of heads (ide disk geometry)",
+        },{
+            .name = "secs",
+            .type = QEMU_OPT_NUMBER,
+            .help = "number of sectors (ide disk geometry)",
+        },{
+            .name = "trans",
+            .type = QEMU_OPT_STRING,
+            .help = "chs translation (auto, lba. none)",
+        },{
+            .name = "media",
+            .type = QEMU_OPT_STRING,
+            .help = "media type (disk, cdrom)",
+        },{
+            .name = "snapshot",
+            .type = QEMU_OPT_BOOL,
+            .help = "enable/disable snapshot mode",
+        },{
+            .name = "file",
+            .type = QEMU_OPT_STRING,
+            .help = "disk image",
+        },{
+            .name = "cache",
+            .type = QEMU_OPT_STRING,
+            .help = "host cache usage (none, writeback, writethrough, unsafe)",
+        },{
+            .name = "aio",
+            .type = QEMU_OPT_STRING,
+            .help = "host AIO implementation (threads, native)",
+        },{
+            .name = "format",
+            .type = QEMU_OPT_STRING,
+            .help = "disk format (raw, qcow2, ...)",
+        },{
+            .name = "serial",
+            .type = QEMU_OPT_STRING,
+            .help = "disk serial number",
+        },{
+            .name = "rerror",
+            .type = QEMU_OPT_STRING,
+            .help = "read error action",
+        },{
+            .name = "werror",
+            .type = QEMU_OPT_STRING,
+            .help = "write error action",
+        },{
+            .name = "addr",
+            .type = QEMU_OPT_STRING,
+            .help = "pci address (virtio only)",
+        },{
+            .name = "readonly",
+            .type = QEMU_OPT_BOOL,
+            .help = "open drive file as read-only",
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_chardev_opts = {
+    .name = "chardev",
+    .implied_opt_name = "backend",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
+    .desc = {
+        {
+            .name = "backend",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "host",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "port",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "localaddr",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "localport",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "to",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "ipv4",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "ipv6",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "wait",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "server",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "delay",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "telnet",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "width",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "height",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "cols",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "rows",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "mux",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "signal",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "name",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "debug",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+QemuOptsList qemu_fsdev_opts = {
+    .name = "fsdev",
+    .implied_opt_name = "fstype",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
+    .desc = {
+        {
+            .name = "fstype",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "security_model",
+            .type = QEMU_OPT_STRING,
+        },
+        { /*End of list */ }
+    },
+};
+
+QemuOptsList qemu_virtfs_opts = {
+    .name = "virtfs",
+    .implied_opt_name = "fstype",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
+    .desc = {
+        {
+            .name = "fstype",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "mount_tag",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "security_model",
+            .type = QEMU_OPT_STRING,
+        },
+
+        { /*End of list */ }
+    },
+};
+
+static QemuOptsList qemu_device_opts = {
+    .name = "device",
+    .implied_opt_name = "driver",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
+    .desc = {
+        /*
+         * no elements => accept any
+         * sanity checking will happen later
+         * when setting device properties
+         */
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_netdev_opts = {
+    .name = "netdev",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
+    .desc = {
+        /*
+         * no elements => accept any params
+         * validation will happen later
+         */
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_net_opts = {
+    .name = "net",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
+    .desc = {
+        /*
+         * no elements => accept any params
+         * validation will happen later
+         */
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_rtc_opts = {
+    .name = "rtc",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
+    .desc = {
+        {
+            .name = "base",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "clock",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "driftfix",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_global_opts = {
+    .name = "global",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
+    .desc = {
+        {
+            .name = "driver",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "property",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "value",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_mon_opts = {
+    .name = "mon",
+    .implied_opt_name = "chardev",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
+    .desc = {
+        {
+            .name = "mode",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "chardev",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "default",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "pretty",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end of list */ }
+    },
+};
+
+#ifdef CONFIG_SIMPLE_TRACE
+static QemuOptsList qemu_trace_opts = {
+    .name = "trace",
+    .implied_opt_name = "trace",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
+    .desc = {
+        {
+            .name = "file",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+#endif
+
+static QemuOptsList qemu_cpudef_opts = {
+    .name = "cpudef",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
+    .desc = {
+        {
+            .name = "name",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "level",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "vendor",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "family",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "model",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "stepping",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "feature_edx",      /* cpuid 0000_0001.edx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "xlevel",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "model_id",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "vendor_override",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+QemuOptsList qemu_spice_opts = {
+    .name = "spice",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
+    .desc = {
+        {
+            .name = "port",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "tls-port",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "addr",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "ipv4",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "ipv6",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "password",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "disable-ticketing",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "disable-copy-paste",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "sasl",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "x509-dir",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509-key-file",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509-key-password",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509-cert-file",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509-cacert-file",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509-dh-key-file",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "tls-ciphers",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "tls-channel",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "plaintext-channel",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "image-compression",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "jpeg-wan-compression",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "zlib-glz-wan-compression",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "streaming-video",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "agent-mouse",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "playback-compression",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end of list */ }
+    },
+};
+
+QemuOptsList qemu_option_rom_opts = {
+    .name = "option-rom",
+    .implied_opt_name = "romfile",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
+    .desc = {
+        {
+            .name = "bootindex",
+            .type = QEMU_OPT_NUMBER,
+        }, {
+            .name = "romfile",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList qemu_machine_opts = {
+    .name = "machine",
+    .implied_opt_name = "type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
+    .desc = {
+        {
+            .name = "type",
+            .type = QEMU_OPT_STRING,
+            .help = "emulated machine"
+        }, {
+            .name = "accel",
+            .type = QEMU_OPT_STRING,
+            .help = "accelerator list",
+        },
+        { /* End of list */ }
+    },
+};
+
+static QemuOptsList *vm_config_groups[32] = {
+    &qemu_drive_opts,
+    &qemu_chardev_opts,
+    &qemu_device_opts,
+    &qemu_netdev_opts,
+    &qemu_net_opts,
+    &qemu_rtc_opts,
+    &qemu_global_opts,
+    &qemu_mon_opts,
+    &qemu_cpudef_opts,
+#ifdef CONFIG_SIMPLE_TRACE
+    &qemu_trace_opts,
+#endif
+    &qemu_option_rom_opts,
+    &qemu_machine_opts,
+    NULL,
+};
+
+static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
+{
+    int i;
+
+    for (i = 0; lists[i] != NULL; i++) {
+        if (strcmp(lists[i]->name, group) == 0)
+            break;
+    }
+    if (lists[i] == NULL) {
+        error_report("there is no option group \"%s\"", group);
+    }
+    return lists[i];
+}
+
+QemuOptsList *qemu_find_opts(const char *group)
+{
+    return find_list(vm_config_groups, group);
+}
+
+void qemu_add_opts(QemuOptsList *list)
+{
+    int entries, i;
+
+    entries = ARRAY_SIZE(vm_config_groups);
+    entries--; /* keep list NULL terminated */
+    for (i = 0; i < entries; i++) {
+        if (vm_config_groups[i] == NULL) {
+            vm_config_groups[i] = list;
+            return;
+        }
+    }
+    fprintf(stderr, "ran out of space in vm_config_groups");
+    abort();
+}
+
+int qemu_set_option(const char *str)
+{
+    char group[64], id[64], arg[64];
+    QemuOptsList *list;
+    QemuOpts *opts;
+    int rc, offset;
+
+    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
+    if (rc < 3 || str[offset] != '=') {
+        error_report("can't parse: \"%s\"", str);
+        return -1;
+    }
+
+    list = qemu_find_opts(group);
+    if (list == NULL) {
+        return -1;
+    }
+
+    opts = qemu_opts_find(list, id);
+    if (!opts) {
+        error_report("there is no %s \"%s\" defined",
+                     list->name, id);
+        return -1;
+    }
+
+    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
+        return -1;
+    }
+    return 0;
+}
+
+int qemu_global_option(const char *str)
+{
+    char driver[64], property[64];
+    QemuOpts *opts;
+    int rc, offset;
+
+    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
+    if (rc < 2 || str[offset] != '=') {
+        error_report("can't parse: \"%s\"", str);
+        return -1;
+    }
+
+    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
+    qemu_opt_set(opts, "driver", driver);
+    qemu_opt_set(opts, "property", property);
+    qemu_opt_set(opts, "value", str+offset+1);
+    return 0;
+}
+
+struct ConfigWriteData {
+    QemuOptsList *list;
+    FILE *fp;
+};
+
+static int config_write_opt(const char *name, const char *value, void *opaque)
+{
+    struct ConfigWriteData *data = opaque;
+
+    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
+    return 0;
+}
+
+static int config_write_opts(QemuOpts *opts, void *opaque)
+{
+    struct ConfigWriteData *data = opaque;
+    const char *id = qemu_opts_id(opts);
+
+    if (id) {
+        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
+    } else {
+        fprintf(data->fp, "[%s]\n", data->list->name);
+    }
+    qemu_opt_foreach(opts, config_write_opt, data, 0);
+    fprintf(data->fp, "\n");
+    return 0;
+}
+
+void qemu_config_write(FILE *fp)
+{
+    struct ConfigWriteData data = { .fp = fp };
+    QemuOptsList **lists = vm_config_groups;
+    int i;
+
+    fprintf(fp, "# qemu config file\n\n");
+    for (i = 0; lists[i] != NULL; i++) {
+        data.list = lists[i];
+        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
+    }
+}
+
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
+{
+    char line[1024], group[64], id[64], arg[64], value[1024];
+    Location loc;
+    QemuOptsList *list = NULL;
+    QemuOpts *opts = NULL;
+    int res = -1, lno = 0;
+
+    loc_push_none(&loc);
+    while (fgets(line, sizeof(line), fp) != NULL) {
+        loc_set_file(fname, ++lno);
+        if (line[0] == '\n') {
+            /* skip empty lines */
+            continue;
+        }
+        if (line[0] == '#') {
+            /* comment */
+            continue;
+        }
+        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
+            /* group with id */
+            list = find_list(lists, group);
+            if (list == NULL)
+                goto out;
+            opts = qemu_opts_create(list, id, 1);
+            continue;
+        }
+        if (sscanf(line, "[%63[^]]]", group) == 1) {
+            /* group without id */
+            list = find_list(lists, group);
+            if (list == NULL)
+                goto out;
+            opts = qemu_opts_create(list, NULL, 0);
+            continue;
+        }
+        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
+            /* arg = value */
+            if (opts == NULL) {
+                error_report("no group defined");
+                goto out;
+            }
+            if (qemu_opt_set(opts, arg, value) != 0) {
+                goto out;
+            }
+            continue;
+        }
+        error_report("parse error");
+        goto out;
+    }
+    if (ferror(fp)) {
+        error_report("error reading file");
+        goto out;
+    }
+    res = 0;
+out:
+    loc_pop(&loc);
+    return res;
+}
+
+int qemu_read_config_file(const char *filename)
+{
+    FILE *f = fopen(filename, "r");
+    int ret;
+
+    if (f == NULL) {
+        return -errno;
+    }
+
+    ret = qemu_config_parse(f, vm_config_groups, filename);
+    fclose(f);
+
+    if (ret == 0) {
+        return 0;
+    } else {
+        return -EINVAL;
+    }
+}
diff --git a/qemu-0.15.x/qemu-config.h b/qemu-0.15.x/qemu-config.h
new file mode 100644
index 0000000..20d707f
--- /dev/null
+++ b/qemu-0.15.x/qemu-config.h
@@ -0,0 +1,19 @@
+#ifndef QEMU_CONFIG_H
+#define QEMU_CONFIG_H
+
+extern QemuOptsList qemu_fsdev_opts;
+extern QemuOptsList qemu_virtfs_opts;
+extern QemuOptsList qemu_spice_opts;
+
+QemuOptsList *qemu_find_opts(const char *group);
+void qemu_add_opts(QemuOptsList *list);
+int qemu_set_option(const char *str);
+int qemu_global_option(const char *str);
+void qemu_add_globals(void);
+
+void qemu_config_write(FILE *fp);
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
+
+int qemu_read_config_file(const char *filename);
+
+#endif /* QEMU_CONFIG_H */
diff --git a/qemu-0.15.x/qemu-doc.texi b/qemu-0.15.x/qemu-doc.texi
new file mode 100644
index 0000000..47e1991
--- /dev/null
+++ b/qemu-0.15.x/qemu-doc.texi
@@ -0,0 +1,2717 @@
+\input texinfo @c -*- texinfo -*-
+ at c %**start of header
+ at setfilename qemu-doc.info
+
+ at documentlanguage en
+ at documentencoding UTF-8
+
+ at settitle QEMU Emulator User Documentation
+ at exampleindent 0
+ at paragraphindent 0
+ at c %**end of header
+
+ at ifinfo
+ at direntry
+* QEMU: (qemu-doc).    The QEMU Emulator User Documentation.
+ at end direntry
+ at end ifinfo
+
+ at iftex
+ at titlepage
+ at sp 7
+ at center @titlefont{QEMU Emulator}
+ at sp 1
+ at center @titlefont{User Documentation}
+ at sp 3
+ at end titlepage
+ at end iftex
+
+ at ifnottex
+ at node Top
+ at top
+
+ at menu
+* Introduction::
+* Installation::
+* QEMU PC System emulator::
+* QEMU System emulator for non PC targets::
+* QEMU User space emulator::
+* compilation:: Compilation from the sources
+* License::
+* Index::
+ at end menu
+ at end ifnottex
+
+ at contents
+
+ at node Introduction
+ at chapter Introduction
+
+ at menu
+* intro_features:: Features
+ at end menu
+
+ at node intro_features
+ at section Features
+
+QEMU is a FAST! processor emulator using dynamic translation to
+achieve good emulation speed.
+
+QEMU has two operating modes:
+
+ at itemize
+ at cindex operating modes
+
+ at item
+ at cindex system emulation
+Full system emulation. In this mode, QEMU emulates a full system (for
+example a PC), including one or several processors and various
+peripherals. It can be used to launch different Operating Systems
+without rebooting the PC or to debug system code.
+
+ at item
+ at cindex user mode emulation
+User mode emulation. In this mode, QEMU can launch
+processes compiled for one CPU on another CPU. It can be used to
+launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
+to ease cross-compilation and cross-debugging.
+
+ at end itemize
+
+QEMU can run without an host kernel driver and yet gives acceptable
+performance.
+
+For system emulation, the following hardware targets are supported:
+ at itemize
+ at cindex emulated target systems
+ at cindex supported target systems
+ at item PC (x86 or x86_64 processor)
+ at item ISA PC (old style PC without PCI bus)
+ at item PREP (PowerPC processor)
+ at item G3 Beige PowerMac (PowerPC processor)
+ at item Mac99 PowerMac (PowerPC processor, in progress)
+ at item Sun4m/Sun4c/Sun4d (32-bit Sparc processor)
+ at item Sun4u/Sun4v (64-bit Sparc processor, in progress)
+ at item Malta board (32-bit and 64-bit MIPS processors)
+ at item MIPS Magnum (64-bit MIPS processor)
+ at item ARM Integrator/CP (ARM)
+ at item ARM Versatile baseboard (ARM)
+ at item ARM RealView Emulation/Platform baseboard (ARM)
+ at item Spitz, Akita, Borzoi, Terrier and Tosa PDAs (PXA270 processor)
+ at item Luminary Micro LM3S811EVB (ARM Cortex-M3)
+ at item Luminary Micro LM3S6965EVB (ARM Cortex-M3)
+ at item Freescale MCF5208EVB (ColdFire V2).
+ at item Arnewsh MCF5206 evaluation board (ColdFire V2).
+ at item Palm Tungsten|E PDA (OMAP310 processor)
+ at item N800 and N810 tablets (OMAP2420 processor)
+ at item MusicPal (MV88W8618 ARM processor)
+ at item Gumstix "Connex" and "Verdex" motherboards (PXA255/270).
+ at item Siemens SX1 smartphone (OMAP310 processor)
+ at item Syborg SVP base model (ARM Cortex-A8).
+ at item AXIS-Devboard88 (CRISv32 ETRAX-FS).
+ at item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze).
+ at end itemize
+
+ at cindex supported user mode targets
+For user emulation, x86 (32 and 64 bit), PowerPC (32 and 64 bit),
+ARM, MIPS (32 bit only), Sparc (32 and 64 bit),
+Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported.
+
+ at node Installation
+ at chapter Installation
+
+If you want to compile QEMU yourself, see @ref{compilation}.
+
+ at menu
+* install_linux::   Linux
+* install_windows:: Windows
+* install_mac::     Macintosh
+ at end menu
+
+ at node install_linux
+ at section Linux
+ at cindex installation (Linux)
+
+If a precompiled package is available for your distribution - you just
+have to install it. Otherwise, see @ref{compilation}.
+
+ at node install_windows
+ at section Windows
+ at cindex installation (Windows)
+
+Download the experimental binary installer at
+ at url{http://www.free.oszoo.org/@/download.html}.
+TODO (no longer available)
+
+ at node install_mac
+ at section Mac OS X
+
+Download the experimental binary installer at
+ at url{http://www.free.oszoo.org/@/download.html}.
+TODO (no longer available)
+
+ at node QEMU PC System emulator
+ at chapter QEMU PC System emulator
+ at cindex system emulation (PC)
+
+ at menu
+* pcsys_introduction:: Introduction
+* pcsys_quickstart::   Quick Start
+* sec_invocation::     Invocation
+* pcsys_keys::         Keys
+* pcsys_monitor::      QEMU Monitor
+* disk_images::        Disk Images
+* pcsys_network::      Network emulation
+* pcsys_other_devs::   Other Devices
+* direct_linux_boot::  Direct Linux Boot
+* pcsys_usb::          USB emulation
+* vnc_security::       VNC security
+* gdb_usage::          GDB usage
+* pcsys_os_specific::  Target OS specific information
+ at end menu
+
+ at node pcsys_introduction
+ at section Introduction
+
+ at c man begin DESCRIPTION
+
+The QEMU PC System emulator simulates the
+following peripherals:
+
+ at itemize @minus
+ at item
+i440FX host PCI bridge and PIIX3 PCI to ISA bridge
+ at item
+Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA
+extensions (hardware level, including all non standard modes).
+ at item
+PS/2 mouse and keyboard
+ at item
+2 PCI IDE interfaces with hard disk and CD-ROM support
+ at item
+Floppy disk
+ at item
+PCI and ISA network adapters
+ at item
+Serial ports
+ at item
+Creative SoundBlaster 16 sound card
+ at item
+ENSONIQ AudioPCI ES1370 sound card
+ at item
+Intel 82801AA AC97 Audio compatible sound card
+ at item
+Intel HD Audio Controller and HDA codec
+ at item
+Adlib (OPL2) - Yamaha YM3812 compatible chip
+ at item
+Gravis Ultrasound GF1 sound card
+ at item
+CS4231A compatible sound card
+ at item
+PCI UHCI USB controller and a virtual USB hub.
+ at end itemize
+
+SMP is supported with up to 255 CPUs.
+
+Note that adlib, gus and cs4231a are only available when QEMU was
+configured with --audio-card-list option containing the name(s) of
+required card(s).
+
+QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
+VGA BIOS.
+
+QEMU uses YM3812 emulation by Tatsuyuki Satoh.
+
+QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
+by Tibor "TS" Schütz.
+
+Not that, by default, GUS shares IRQ(7) with parallel ports and so
+qemu must be told to not have parallel ports to have working GUS
+
+ at example
+qemu dos.img -soundhw gus -parallel none
+ at end example
+
+Alternatively:
+ at example
+qemu dos.img -device gus,irq=5
+ at end example
+
+Or some other unclaimed IRQ.
+
+CS4231A is the chip used in Windows Sound System and GUSMAX products
+
+ at c man end
+
+ at node pcsys_quickstart
+ at section Quick Start
+ at cindex quick start
+
+Download and uncompress the linux image (@file{linux.img}) and type:
+
+ at example
+qemu linux.img
+ at end example
+
+Linux should boot and give you a prompt.
+
+ at node sec_invocation
+ at section Invocation
+
+ at example
+ at c man begin SYNOPSIS
+usage: qemu [options] [@var{disk_image}]
+ at c man end
+ at end example
+
+ at c man begin OPTIONS
+ at var{disk_image} is a raw hard disk image for IDE hard disk 0. Some
+targets do not need a disk image.
+
+ at include qemu-options.texi
+
+ at c man end
+
+ at node pcsys_keys
+ at section Keys
+
+ at c man begin OPTIONS
+
+During the graphical emulation, you can use special key combinations to change
+modes. The default key mappings are shown below, but if you use @code{-alt-grab}
+then the modifier is Ctrl-Alt-Shift (instead of Ctrl-Alt) and if you use
+ at code{-ctrl-grab} then the modifier is the right Ctrl key (instead of Ctrl-Alt):
+
+ at table @key
+ at item Ctrl-Alt-f
+ at kindex Ctrl-Alt-f
+Toggle full screen
+
+ at item Ctrl-Alt-u
+ at kindex Ctrl-Alt-u
+Restore the screen's un-scaled dimensions
+
+ at item Ctrl-Alt-n
+ at kindex Ctrl-Alt-n
+Switch to virtual console 'n'. Standard console mappings are:
+ at table @emph
+ at item 1
+Target system display
+ at item 2
+Monitor
+ at item 3
+Serial port
+ at end table
+
+ at item Ctrl-Alt
+ at kindex Ctrl-Alt
+Toggle mouse and keyboard grab.
+ at end table
+
+ at kindex Ctrl-Up
+ at kindex Ctrl-Down
+ at kindex Ctrl-PageUp
+ at kindex Ctrl-PageDown
+In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down},
+ at key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log.
+
+ at kindex Ctrl-a h
+During emulation, if you are using the @option{-nographic} option, use
+ at key{Ctrl-a h} to get terminal commands:
+
+ at table @key
+ at item Ctrl-a h
+ at kindex Ctrl-a h
+ at item Ctrl-a ?
+ at kindex Ctrl-a ?
+Print this help
+ at item Ctrl-a x
+ at kindex Ctrl-a x
+Exit emulator
+ at item Ctrl-a s
+ at kindex Ctrl-a s
+Save disk data back to file (if -snapshot)
+ at item Ctrl-a t
+ at kindex Ctrl-a t
+Toggle console timestamps
+ at item Ctrl-a b
+ at kindex Ctrl-a b
+Send break (magic sysrq in Linux)
+ at item Ctrl-a c
+ at kindex Ctrl-a c
+Switch between console and monitor
+ at item Ctrl-a Ctrl-a
+ at kindex Ctrl-a a
+Send Ctrl-a
+ at end table
+ at c man end
+
+ at ignore
+
+ at c man begin SEEALSO
+The HTML documentation of QEMU for more precise information and Linux
+user mode emulator invocation.
+ at c man end
+
+ at c man begin AUTHOR
+Fabrice Bellard
+ at c man end
+
+ at end ignore
+
+ at node pcsys_monitor
+ at section QEMU Monitor
+ at cindex QEMU monitor
+
+The QEMU monitor is used to give complex commands to the QEMU
+emulator. You can use it to:
+
+ at itemize @minus
+
+ at item
+Remove or insert removable media images
+(such as CD-ROM or floppies).
+
+ at item
+Freeze/unfreeze the Virtual Machine (VM) and save or restore its state
+from a disk file.
+
+ at item Inspect the VM state without an external debugger.
+
+ at end itemize
+
+ at subsection Commands
+
+The following commands are available:
+
+ at include qemu-monitor.texi
+
+ at subsection Integer expressions
+
+The monitor understands integers expressions for every integer
+argument. You can use register names to get the value of specifics
+CPU registers by prefixing them with @emph{$}.
+
+ at node disk_images
+ at section Disk Images
+
+Since version 0.6.1, QEMU supports many disk image formats, including
+growable disk images (their size increase as non empty sectors are
+written), compressed and encrypted disk images. Version 0.8.3 added
+the new qcow2 disk image format which is essential to support VM
+snapshots.
+
+ at menu
+* disk_images_quickstart::    Quick start for disk image creation
+* disk_images_snapshot_mode:: Snapshot mode
+* vm_snapshots::              VM snapshots
+* qemu_img_invocation::       qemu-img Invocation
+* qemu_nbd_invocation::       qemu-nbd Invocation
+* host_drives::               Using host drives
+* disk_images_fat_images::    Virtual FAT disk images
+* disk_images_nbd::           NBD access
+* disk_images_sheepdog::      Sheepdog disk images
+ at end menu
+
+ at node disk_images_quickstart
+ at subsection Quick start for disk image creation
+
+You can create a disk image with the command:
+ at example
+qemu-img create myimage.img mysize
+ at end example
+where @var{myimage.img} is the disk image filename and @var{mysize} is its
+size in kilobytes. You can add an @code{M} suffix to give the size in
+megabytes and a @code{G} suffix for gigabytes.
+
+See @ref{qemu_img_invocation} for more information.
+
+ at node disk_images_snapshot_mode
+ at subsection Snapshot mode
+
+If you use the option @option{-snapshot}, all disk images are
+considered as read only. When sectors in written, they are written in
+a temporary file created in @file{/tmp}. You can however force the
+write back to the raw disk images by using the @code{commit} monitor
+command (or @key{C-a s} in the serial console).
+
+ at node vm_snapshots
+ at subsection VM snapshots
+
+VM snapshots are snapshots of the complete virtual machine including
+CPU state, RAM, device state and the content of all the writable
+disks. In order to use VM snapshots, you must have at least one non
+removable and writable block device using the @code{qcow2} disk image
+format. Normally this device is the first virtual hard drive.
+
+Use the monitor command @code{savevm} to create a new VM snapshot or
+replace an existing one. A human readable name can be assigned to each
+snapshot in addition to its numerical ID.
+
+Use @code{loadvm} to restore a VM snapshot and @code{delvm} to remove
+a VM snapshot. @code{info snapshots} lists the available snapshots
+with their associated information:
+
+ at example
+(qemu) info snapshots
+Snapshot devices: hda
+Snapshot list (from hda):
+ID        TAG                 VM SIZE                DATE       VM CLOCK
+1         start                   41M 2006-08-06 12:38:02   00:00:14.954
+2                                 40M 2006-08-06 12:43:29   00:00:18.633
+3         msys                    40M 2006-08-06 12:44:04   00:00:23.514
+ at end example
+
+A VM snapshot is made of a VM state info (its size is shown in
+ at code{info snapshots}) and a snapshot of every writable disk image.
+The VM state info is stored in the first @code{qcow2} non removable
+and writable block device. The disk image snapshots are stored in
+every disk image. The size of a snapshot in a disk image is difficult
+to evaluate and is not shown by @code{info snapshots} because the
+associated disk sectors are shared among all the snapshots to save
+disk space (otherwise each snapshot would need a full copy of all the
+disk images).
+
+When using the (unrelated) @code{-snapshot} option
+(@ref{disk_images_snapshot_mode}), you can always make VM snapshots,
+but they are deleted as soon as you exit QEMU.
+
+VM snapshots currently have the following known limitations:
+ at itemize
+ at item
+They cannot cope with removable devices if they are removed or
+inserted after a snapshot is done.
+ at item
+A few device drivers still have incomplete snapshot support so their
+state is not saved or restored properly (in particular USB).
+ at end itemize
+
+ at node qemu_img_invocation
+ at subsection @code{qemu-img} Invocation
+
+ at include qemu-img.texi
+
+ at node qemu_nbd_invocation
+ at subsection @code{qemu-nbd} Invocation
+
+ at include qemu-nbd.texi
+
+ at node host_drives
+ at subsection Using host drives
+
+In addition to disk image files, QEMU can directly access host
+devices. We describe here the usage for QEMU version >= 0.8.3.
+
+ at subsubsection Linux
+
+On Linux, you can directly use the host device filename instead of a
+disk image filename provided you have enough privileges to access
+it. For example, use @file{/dev/cdrom} to access to the CDROM or
+ at file{/dev/fd0} for the floppy.
+
+ at table @code
+ at item CD
+You can specify a CDROM device even if no CDROM is loaded. QEMU has
+specific code to detect CDROM insertion or removal. CDROM ejection by
+the guest OS is supported. Currently only data CDs are supported.
+ at item Floppy
+You can specify a floppy device even if no floppy is loaded. Floppy
+removal is currently not detected accurately (if you change floppy
+without doing floppy access while the floppy is not loaded, the guest
+OS will think that the same floppy is loaded).
+ at item Hard disks
+Hard disks can be used. Normally you must specify the whole disk
+(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can
+see it as a partitioned disk. WARNING: unless you know what you do, it
+is better to only make READ-ONLY accesses to the hard disk otherwise
+you may corrupt your host data (use the @option{-snapshot} command
+line option or modify the device permissions accordingly).
+ at end table
+
+ at subsubsection Windows
+
+ at table @code
+ at item CD
+The preferred syntax is the drive letter (e.g. @file{d:}). The
+alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is
+supported as an alias to the first CDROM drive.
+
+Currently there is no specific code to handle removable media, so it
+is better to use the @code{change} or @code{eject} monitor commands to
+change or eject media.
+ at item Hard disks
+Hard disks can be used with the syntax: @file{\\.\PhysicalDrive at var{N}}
+where @var{N} is the drive number (0 is the first hard disk).
+
+WARNING: unless you know what you do, it is better to only make
+READ-ONLY accesses to the hard disk otherwise you may corrupt your
+host data (use the @option{-snapshot} command line so that the
+modifications are written in a temporary file).
+ at end table
+
+
+ at subsubsection Mac OS X
+
+ at file{/dev/cdrom} is an alias to the first CDROM.
+
+Currently there is no specific code to handle removable media, so it
+is better to use the @code{change} or @code{eject} monitor commands to
+change or eject media.
+
+ at node disk_images_fat_images
+ at subsection Virtual FAT disk images
+
+QEMU can automatically create a virtual FAT disk image from a
+directory tree. In order to use it, just type:
+
+ at example
+qemu linux.img -hdb fat:/my_directory
+ at end example
+
+Then you access access to all the files in the @file{/my_directory}
+directory without having to copy them in a disk image or to export
+them via SAMBA or NFS. The default access is @emph{read-only}.
+
+Floppies can be emulated with the @code{:floppy:} option:
+
+ at example
+qemu linux.img -fda fat:floppy:/my_directory
+ at end example
+
+A read/write support is available for testing (beta stage) with the
+ at code{:rw:} option:
+
+ at example
+qemu linux.img -fda fat:floppy:rw:/my_directory
+ at end example
+
+What you should @emph{never} do:
+ at itemize
+ at item use non-ASCII filenames ;
+ at item use "-snapshot" together with ":rw:" ;
+ at item expect it to work when loadvm'ing ;
+ at item write to the FAT directory on the host system while accessing it with the guest system.
+ at end itemize
+
+ at node disk_images_nbd
+ at subsection NBD access
+
+QEMU can access directly to block device exported using the Network Block Device
+protocol.
+
+ at example
+qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
+ at end example
+
+If the NBD server is located on the same host, you can use an unix socket instead
+of an inet socket:
+
+ at example
+qemu linux.img -hdb nbd:unix:/tmp/my_socket
+ at end example
+
+In this case, the block device must be exported using qemu-nbd:
+
+ at example
+qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
+ at end example
+
+The use of qemu-nbd allows to share a disk between several guests:
+ at example
+qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
+ at end example
+
+and then you can use it with two guests:
+ at example
+qemu linux1.img -hdb nbd:unix:/tmp/my_socket
+qemu linux2.img -hdb nbd:unix:/tmp/my_socket
+ at end example
+
+If the nbd-server uses named exports (since NBD 2.9.18), you must use the
+"exportname" option:
+ at example
+qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
+qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
+ at end example
+
+ at node disk_images_sheepdog
+ at subsection Sheepdog disk images
+
+Sheepdog is a distributed storage system for QEMU.  It provides highly
+available block level storage volumes that can be attached to
+QEMU-based virtual machines.
+
+You can create a Sheepdog disk image with the command:
+ at example
+qemu-img create sheepdog:@var{image} @var{size}
+ at end example
+where @var{image} is the Sheepdog image name and @var{size} is its
+size.
+
+To import the existing @var{filename} to Sheepdog, you can use a
+convert command.
+ at example
+qemu-img convert @var{filename} sheepdog:@var{image}
+ at end example
+
+You can boot from the Sheepdog disk image with the command:
+ at example
+qemu sheepdog:@var{image}
+ at end example
+
+You can also create a snapshot of the Sheepdog image like qcow2.
+ at example
+qemu-img snapshot -c @var{tag} sheepdog:@var{image}
+ at end example
+where @var{tag} is a tag name of the newly created snapshot.
+
+To boot from the Sheepdog snapshot, specify the tag name of the
+snapshot.
+ at example
+qemu sheepdog:@var{image}:@var{tag}
+ at end example
+
+You can create a cloned image from the existing snapshot.
+ at example
+qemu-img create -b sheepdog:@var{base}:@var{tag} sheepdog:@var{image}
+ at end example
+where @var{base} is a image name of the source snapshot and @var{tag}
+is its tag name.
+
+If the Sheepdog daemon doesn't run on the local host, you need to
+specify one of the Sheepdog servers to connect to.
+ at example
+qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size}
+qemu sheepdog:@var{hostname}:@var{port}:@var{image}
+ at end example
+
+ at node pcsys_network
+ at section Network emulation
+
+QEMU can simulate several network cards (PCI or ISA cards on the PC
+target) and can connect them to an arbitrary number of Virtual Local
+Area Networks (VLANs). Host TAP devices can be connected to any QEMU
+VLAN. VLAN can be connected between separate instances of QEMU to
+simulate large networks. For simpler usage, a non privileged user mode
+network stack can replace the TAP device to have a basic network
+connection.
+
+ at subsection VLANs
+
+QEMU simulates several VLANs. A VLAN can be symbolised as a virtual
+connection between several network devices. These devices can be for
+example QEMU virtual Ethernet cards or virtual Host ethernet devices
+(TAP devices).
+
+ at subsection Using TAP network interfaces
+
+This is the standard way to connect QEMU to a real network. QEMU adds
+a virtual network device on your host (called @code{tapN}), and you
+can then configure it as if it was a real ethernet card.
+
+ at subsubsection Linux host
+
+As an example, you can download the @file{linux-test-xxx.tar.gz}
+archive and copy the script @file{qemu-ifup} in @file{/etc} and
+configure properly @code{sudo} so that the command @code{ifconfig}
+contained in @file{qemu-ifup} can be executed as root. You must verify
+that your host kernel supports the TAP network interfaces: the
+device @file{/dev/net/tun} must be present.
+
+See @ref{sec_invocation} to have examples of command lines using the
+TAP network interfaces.
+
+ at subsubsection Windows host
+
+There is a virtual ethernet driver for Windows 2000/XP systems, called
+TAP-Win32. But it is not included in standard QEMU for Windows,
+so you will need to get it separately. It is part of OpenVPN package,
+so download OpenVPN from : @url{http://openvpn.net/}.
+
+ at subsection Using the user mode network stack
+
+By using the option @option{-net user} (default configuration if no
+ at option{-net} option is specified), QEMU uses a completely user mode
+network stack (you don't need root privilege to use the virtual
+network). The virtual network configuration is the following:
+
+ at example
+
+         QEMU VLAN      <------>  Firewall/DHCP server <-----> Internet
+                           |          (10.0.2.2)
+                           |
+                           ---->  DNS server (10.0.2.3)
+                           |
+                           ---->  SMB server (10.0.2.4)
+ at end example
+
+The QEMU VM behaves as if it was behind a firewall which blocks all
+incoming connections. You can use a DHCP client to automatically
+configure the network in the QEMU VM. The DHCP server assign addresses
+to the hosts starting from 10.0.2.15.
+
+In order to check that the user mode network is working, you can ping
+the address 10.0.2.2 and verify that you got an address in the range
+10.0.2.x from the QEMU virtual DHCP server.
+
+Note that @code{ping} is not supported reliably to the internet as it
+would require root privileges. It means you can only ping the local
+router (10.0.2.2).
+
+When using the built-in TFTP server, the router is also the TFTP
+server.
+
+When using the @option{-redir} option, TCP or UDP connections can be
+redirected from the host to the guest. It allows for example to
+redirect X11, telnet or SSH connections.
+
+ at subsection Connecting VLANs between QEMU instances
+
+Using the @option{-net socket} option, it is possible to make VLANs
+that span several QEMU instances. See @ref{sec_invocation} to have a
+basic example.
+
+ at node pcsys_other_devs
+ at section Other Devices
+
+ at subsection Inter-VM Shared Memory device
+
+With KVM enabled on a Linux host, a shared memory device is available.  Guests
+map a POSIX shared memory region into the guest as a PCI device that enables
+zero-copy communication to the application level of the guests.  The basic
+syntax is:
+
+ at example
+qemu -device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
+ at end example
+
+If desired, interrupts can be sent between guest VMs accessing the same shared
+memory region.  Interrupt support requires using a shared memory server and
+using a chardev socket to connect to it.  The code for the shared memory server
+is qemu.git/contrib/ivshmem-server.  An example syntax when using the shared
+memory server is:
+
+ at example
+qemu -device ivshmem,size=<size in format accepted by -m>[,chardev=<id>]
+                        [,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
+qemu -chardev socket,path=<path>,id=<id>
+ at end example
+
+When using the server, the guest will be assigned a VM ID (>=0) that allows guests
+using the same server to communicate via interrupts.  Guests can read their
+VM ID from a device register (see example code).  Since receiving the shared
+memory region from the server is asynchronous, there is a (small) chance the
+guest may boot before the shared memory is attached.  To allow an application
+to ensure shared memory is attached, the VM ID register will return -1 (an
+invalid VM ID) until the memory is attached.  Once the shared memory is
+attached, the VM ID will return the guest's valid VM ID.  With these semantics,
+the guest application can check to ensure the shared memory is attached to the
+guest before proceeding.
+
+The @option{role} argument can be set to either master or peer and will affect
+how the shared memory is migrated.  With @option{role=master}, the guest will
+copy the shared memory on migration to the destination host.  With
+ at option{role=peer}, the guest will not be able to migrate with the device attached.
+With the @option{peer} case, the device should be detached and then reattached
+after migration using the PCI hotplug support.
+
+ at node direct_linux_boot
+ at section Direct Linux Boot
+
+This section explains how to launch a Linux kernel inside QEMU without
+having to make a full bootable image. It is very useful for fast Linux
+kernel testing.
+
+The syntax is:
+ at example
+qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda"
+ at end example
+
+Use @option{-kernel} to provide the Linux kernel image and
+ at option{-append} to give the kernel command line arguments. The
+ at option{-initrd} option can be used to provide an INITRD image.
+
+When using the direct Linux boot, a disk image for the first hard disk
+ at file{hda} is required because its boot sector is used to launch the
+Linux kernel.
+
+If you do not need graphical output, you can disable it and redirect
+the virtual serial port and the QEMU monitor to the console with the
+ at option{-nographic} option. The typical command line is:
+ at example
+qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
+     -append "root=/dev/hda console=ttyS0" -nographic
+ at end example
+
+Use @key{Ctrl-a c} to switch between the serial console and the
+monitor (@pxref{pcsys_keys}).
+
+ at node pcsys_usb
+ at section USB emulation
+
+QEMU emulates a PCI UHCI USB controller. You can virtually plug
+virtual USB devices or real host USB devices (experimental, works only
+on Linux hosts).  Qemu will automatically create and connect virtual USB hubs
+as necessary to connect multiple USB devices.
+
+ at menu
+* usb_devices::
+* host_usb_devices::
+ at end menu
+ at node usb_devices
+ at subsection Connecting USB devices
+
+USB devices can be connected with the @option{-usbdevice} commandline option
+or the @code{usb_add} monitor command.  Available devices are:
+
+ at table @code
+ at item mouse
+Virtual Mouse.  This will override the PS/2 mouse emulation when activated.
+ at item tablet
+Pointer device that uses absolute coordinates (like a touchscreen).
+This means qemu is able to report the mouse position without having
+to grab the mouse.  Also overrides the PS/2 mouse emulation when activated.
+ at item disk:@var{file}
+Mass storage device based on @var{file} (@pxref{disk_images})
+ at item host:@var{bus.addr}
+Pass through the host device identified by @var{bus.addr}
+(Linux only)
+ at item host:@var{vendor_id:product_id}
+Pass through the host device identified by @var{vendor_id:product_id}
+(Linux only)
+ at item wacom-tablet
+Virtual Wacom PenPartner tablet.  This device is similar to the @code{tablet}
+above but it can be used with the tslib library because in addition to touch
+coordinates it reports touch pressure.
+ at item keyboard
+Standard USB keyboard.  Will override the PS/2 keyboard (if present).
+ at item serial:[vendorid=@var{vendor_id}][,product_id=@var{product_id}]:@var{dev}
+Serial converter. This emulates an FTDI FT232BM chip connected to host character
+device @var{dev}. The available character devices are the same as for the
+ at code{-serial} option. The @code{vendorid} and @code{productid} options can be
+used to override the default 0403:6001. For instance,
+ at example
+usb_add serial:productid=FA00:tcp:192.168.0.2:4444
+ at end example
+will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual
+serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00).
+ at item braille
+Braille device.  This will use BrlAPI to display the braille output on a real
+or fake device.
+ at item net:@var{options}
+Network adapter that supports CDC ethernet and RNDIS protocols.  @var{options}
+specifies NIC options as with @code{-net nic,}@var{options} (see description).
+For instance, user-mode networking can be used with
+ at example
+qemu [...OPTIONS...] -net user,vlan=0 -usbdevice net:vlan=0
+ at end example
+Currently this cannot be used in machines that support PCI NICs.
+ at item bt[:@var{hci-type}]
+Bluetooth dongle whose type is specified in the same format as with
+the @option{-bt hci} option, @pxref{bt-hcis,,allowed HCI types}.  If
+no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}.
+This USB device implements the USB Transport Layer of HCI.  Example
+usage:
+ at example
+qemu [...OPTIONS...] -usbdevice bt:hci,vlan=3 -bt device:keyboard,vlan=3
+ at end example
+ at end table
+
+ at node host_usb_devices
+ at subsection Using host USB devices on a Linux host
+
+WARNING: this is an experimental feature. QEMU will slow down when
+using it. USB devices requiring real time streaming (i.e. USB Video
+Cameras) are not supported yet.
+
+ at enumerate
+ at item If you use an early Linux 2.4 kernel, verify that no Linux driver
+is actually using the USB device. A simple way to do that is simply to
+disable the corresponding kernel module by renaming it from @file{mydriver.o}
+to @file{mydriver.o.disabled}.
+
+ at item Verify that @file{/proc/bus/usb} is working (most Linux distributions should enable it by default). You should see something like that:
+ at example
+ls /proc/bus/usb
+001  devices  drivers
+ at end example
+
+ at item Since only root can access to the USB devices directly, you can either launch QEMU as root or change the permissions of the USB devices you want to use. For testing, the following suffices:
+ at example
+chown -R myuid /proc/bus/usb
+ at end example
+
+ at item Launch QEMU and do in the monitor:
+ at example
+info usbhost
+  Device 1.2, speed 480 Mb/s
+    Class 00: USB device 1234:5678, USB DISK
+ at end example
+You should see the list of the devices you can use (Never try to use
+hubs, it won't work).
+
+ at item Add the device in QEMU by using:
+ at example
+usb_add host:1234:5678
+ at end example
+
+Normally the guest OS should report that a new USB device is
+plugged. You can use the option @option{-usbdevice} to do the same.
+
+ at item Now you can try to use the host USB device in QEMU.
+
+ at end enumerate
+
+When relaunching QEMU, you may have to unplug and plug again the USB
+device to make it work again (this is a bug).
+
+ at node vnc_security
+ at section VNC security
+
+The VNC server capability provides access to the graphical console
+of the guest VM across the network. This has a number of security
+considerations depending on the deployment scenarios.
+
+ at menu
+* vnc_sec_none::
+* vnc_sec_password::
+* vnc_sec_certificate::
+* vnc_sec_certificate_verify::
+* vnc_sec_certificate_pw::
+* vnc_sec_sasl::
+* vnc_sec_certificate_sasl::
+* vnc_generate_cert::
+* vnc_setup_sasl::
+ at end menu
+ at node vnc_sec_none
+ at subsection Without passwords
+
+The simplest VNC server setup does not include any form of authentication.
+For this setup it is recommended to restrict it to listen on a UNIX domain
+socket only. For example
+
+ at example
+qemu [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
+ at end example
+
+This ensures that only users on local box with read/write access to that
+path can access the VNC server. To securely access the VNC server from a
+remote machine, a combination of netcat+ssh can be used to provide a secure
+tunnel.
+
+ at node vnc_sec_password
+ at subsection With passwords
+
+The VNC protocol has limited support for password based authentication. Since
+the protocol limits passwords to 8 characters it should not be considered
+to provide high security. The password can be fairly easily brute-forced by
+a client making repeat connections. For this reason, a VNC server using password
+authentication should be restricted to only listen on the loopback interface
+or UNIX domain sockets. Password authentication is requested with the @code{password}
+option, and then once QEMU is running the password is set with the monitor. Until
+the monitor is used to set the password all clients will be rejected.
+
+ at example
+qemu [...OPTIONS...] -vnc :1,password -monitor stdio
+(qemu) change vnc password
+Password: ********
+(qemu)
+ at end example
+
+ at node vnc_sec_certificate
+ at subsection With x509 certificates
+
+The QEMU VNC server also implements the VeNCrypt extension allowing use of
+TLS for encryption of the session, and x509 certificates for authentication.
+The use of x509 certificates is strongly recommended, because TLS on its
+own is susceptible to man-in-the-middle attacks. Basic x509 certificate
+support provides a secure session, but no authentication. This allows any
+client to connect, and provides an encrypted session.
+
+ at example
+qemu [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio
+ at end example
+
+In the above example @code{/etc/pki/qemu} should contain at least three files,
+ at code{ca-cert.pem}, @code{server-cert.pem} and @code{server-key.pem}. Unprivileged
+users will want to use a private directory, for example @code{$HOME/.pki/qemu}.
+NB the @code{server-key.pem} file should be protected with file mode 0600 to
+only be readable by the user owning it.
+
+ at node vnc_sec_certificate_verify
+ at subsection With x509 certificates and client verification
+
+Certificates can also provide a means to authenticate the client connecting.
+The server will request that the client provide a certificate, which it will
+then validate against the CA certificate. This is a good choice if deploying
+in an environment with a private internal certificate authority.
+
+ at example
+qemu [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio
+ at end example
+
+
+ at node vnc_sec_certificate_pw
+ at subsection With x509 certificates, client verification and passwords
+
+Finally, the previous method can be combined with VNC password authentication
+to provide two layers of authentication for clients.
+
+ at example
+qemu [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio
+(qemu) change vnc password
+Password: ********
+(qemu)
+ at end example
+
+
+ at node vnc_sec_sasl
+ at subsection With SASL authentication
+
+The SASL authentication method is a VNC extension, that provides an
+easily extendable, pluggable authentication method. This allows for
+integration with a wide range of authentication mechanisms, such as
+PAM, GSSAPI/Kerberos, LDAP, SQL databases, one-time keys and more.
+The strength of the authentication depends on the exact mechanism
+configured. If the chosen mechanism also provides a SSF layer, then
+it will encrypt the datastream as well.
+
+Refer to the later docs on how to choose the exact SASL mechanism
+used for authentication, but assuming use of one supporting SSF,
+then QEMU can be launched with:
+
+ at example
+qemu [...OPTIONS...] -vnc :1,sasl -monitor stdio
+ at end example
+
+ at node vnc_sec_certificate_sasl
+ at subsection With x509 certificates and SASL authentication
+
+If the desired SASL authentication mechanism does not supported
+SSF layers, then it is strongly advised to run it in combination
+with TLS and x509 certificates. This provides securely encrypted
+data stream, avoiding risk of compromising of the security
+credentials. This can be enabled, by combining the 'sasl' option
+with the aforementioned TLS + x509 options:
+
+ at example
+qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio
+ at end example
+
+
+ at node vnc_generate_cert
+ at subsection Generating certificates for VNC
+
+The GNU TLS packages provides a command called @code{certtool} which can
+be used to generate certificates and keys in PEM format. At a minimum it
+is necessary to setup a certificate authority, and issue certificates to
+each server. If using certificates for authentication, then each client
+will also need to be issued a certificate. The recommendation is for the
+server to keep its certificates in either @code{/etc/pki/qemu} or for
+unprivileged users in @code{$HOME/.pki/qemu}.
+
+ at menu
+* vnc_generate_ca::
+* vnc_generate_server::
+* vnc_generate_client::
+ at end menu
+ at node vnc_generate_ca
+ at subsubsection Setup the Certificate Authority
+
+This step only needs to be performed once per organization / organizational
+unit. First the CA needs a private key. This key must be kept VERY secret
+and secure. If this key is compromised the entire trust chain of the certificates
+issued with it is lost.
+
+ at example
+# certtool --generate-privkey > ca-key.pem
+ at end example
+
+A CA needs to have a public certificate. For simplicity it can be a self-signed
+certificate, or one issue by a commercial certificate issuing authority. To
+generate a self-signed certificate requires one core piece of information, the
+name of the organization.
+
+ at example
+# cat > ca.info <<EOF
+cn = Name of your organization
+ca
+cert_signing_key
+EOF
+# certtool --generate-self-signed \
+           --load-privkey ca-key.pem
+           --template ca.info \
+           --outfile ca-cert.pem
+ at end example
+
+The @code{ca-cert.pem} file should be copied to all servers and clients wishing to utilize
+TLS support in the VNC server. The @code{ca-key.pem} must not be disclosed/copied at all.
+
+ at node vnc_generate_server
+ at subsubsection Issuing server certificates
+
+Each server (or host) needs to be issued with a key and certificate. When connecting
+the certificate is sent to the client which validates it against the CA certificate.
+The core piece of information for a server certificate is the hostname. This should
+be the fully qualified hostname that the client will connect with, since the client
+will typically also verify the hostname in the certificate. On the host holding the
+secure CA private key:
+
+ at example
+# cat > server.info <<EOF
+organization = Name  of your organization
+cn = server.foo.example.com
+tls_www_server
+encryption_key
+signing_key
+EOF
+# certtool --generate-privkey > server-key.pem
+# certtool --generate-certificate \
+           --load-ca-certificate ca-cert.pem \
+           --load-ca-privkey ca-key.pem \
+           --load-privkey server server-key.pem \
+           --template server.info \
+           --outfile server-cert.pem
+ at end example
+
+The @code{server-key.pem} and @code{server-cert.pem} files should now be securely copied
+to the server for which they were generated. The @code{server-key.pem} is security
+sensitive and should be kept protected with file mode 0600 to prevent disclosure.
+
+ at node vnc_generate_client
+ at subsubsection Issuing client certificates
+
+If the QEMU VNC server is to use the @code{x509verify} option to validate client
+certificates as its authentication mechanism, each client also needs to be issued
+a certificate. The client certificate contains enough metadata to uniquely identify
+the client, typically organization, state, city, building, etc. On the host holding
+the secure CA private key:
+
+ at example
+# cat > client.info <<EOF
+country = GB
+state = London
+locality = London
+organiazation = Name of your organization
+cn = client.foo.example.com
+tls_www_client
+encryption_key
+signing_key
+EOF
+# certtool --generate-privkey > client-key.pem
+# certtool --generate-certificate \
+           --load-ca-certificate ca-cert.pem \
+           --load-ca-privkey ca-key.pem \
+           --load-privkey client-key.pem \
+           --template client.info \
+           --outfile client-cert.pem
+ at end example
+
+The @code{client-key.pem} and @code{client-cert.pem} files should now be securely
+copied to the client for which they were generated.
+
+
+ at node vnc_setup_sasl
+
+ at subsection Configuring SASL mechanisms
+
+The following documentation assumes use of the Cyrus SASL implementation on a
+Linux host, but the principals should apply to any other SASL impl. When SASL
+is enabled, the mechanism configuration will be loaded from system default
+SASL service config /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+
+The default configuration might contain
+
+ at example
+mech_list: digest-md5
+sasldb_path: /etc/qemu/passwd.db
+ at end example
+
+This says to use the 'Digest MD5' mechanism, which is similar to the HTTP
+Digest-MD5 mechanism. The list of valid usernames & passwords is maintained
+in the /etc/qemu/passwd.db file, and can be updated using the saslpasswd2
+command. While this mechanism is easy to configure and use, it is not
+considered secure by modern standards, so only suitable for developers /
+ad-hoc testing.
+
+A more serious deployment might use Kerberos, which is done with the 'gssapi'
+mechanism
+
+ at example
+mech_list: gssapi
+keytab: /etc/qemu/krb5.tab
+ at end example
+
+For this to work the administrator of your KDC must generate a Kerberos
+principal for the server, with a name of  'qemu/somehost.example.com@@EXAMPLE.COM'
+replacing 'somehost.example.com' with the fully qualified host name of the
+machine running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm.
+
+Other configurations will be left as an exercise for the reader. It should
+be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data
+encryption. For all other mechanisms, VNC should always be configured to
+use TLS and x509 certificates to protect security credentials from snooping.
+
+ at node gdb_usage
+ at section GDB usage
+
+QEMU has a primitive support to work with gdb, so that you can do
+'Ctrl-C' while the virtual machine is running and inspect its state.
+
+In order to use gdb, launch qemu with the '-s' option. It will wait for a
+gdb connection:
+ at example
+> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
+       -append "root=/dev/hda"
+Connected to host network interface: tun0
+Waiting gdb connection on port 1234
+ at end example
+
+Then launch gdb on the 'vmlinux' executable:
+ at example
+> gdb vmlinux
+ at end example
+
+In gdb, connect to QEMU:
+ at example
+(gdb) target remote localhost:1234
+ at end example
+
+Then you can use gdb normally. For example, type 'c' to launch the kernel:
+ at example
+(gdb) c
+ at end example
+
+Here are some useful tips in order to use gdb on system code:
+
+ at enumerate
+ at item
+Use @code{info reg} to display all the CPU registers.
+ at item
+Use @code{x/10i $eip} to display the code at the PC position.
+ at item
+Use @code{set architecture i8086} to dump 16 bit code. Then use
+ at code{x/10i $cs*16+$eip} to dump the code at the PC position.
+ at end enumerate
+
+Advanced debugging options:
+
+The default single stepping behavior is step with the IRQs and timer service routines off.  It is set this way because when gdb executes a single step it expects to advance beyond the current instruction.  With the IRQs and and timer service routines on, a single step might jump into the one of the interrupt or exception vectors instead of executing the current instruction. This means you may hit the same breakpoint a number of times before executing the instruction gdb wants to have executed.  Because there are rare circumstances where you want to single step into an interrupt vector the behavior can be controlled from GDB.  There are three commands you can query and set the single step behavior:
+ at table @code
+ at item maintenance packet qqemu.sstepbits
+
+This will display the MASK bits used to control the single stepping IE:
+ at example
+(gdb) maintenance packet qqemu.sstepbits
+sending: "qqemu.sstepbits"
+received: "ENABLE=1,NOIRQ=2,NOTIMER=4"
+ at end example
+ at item maintenance packet qqemu.sstep
+
+This will display the current value of the mask used when single stepping IE:
+ at example
+(gdb) maintenance packet qqemu.sstep
+sending: "qqemu.sstep"
+received: "0x7"
+ at end example
+ at item maintenance packet Qqemu.sstep=HEX_VALUE
+
+This will change the single step mask, so if wanted to enable IRQs on the single step, but not timers, you would use:
+ at example
+(gdb) maintenance packet Qqemu.sstep=0x5
+sending: "qemu.sstep=0x5"
+received: "OK"
+ at end example
+ at end table
+
+ at node pcsys_os_specific
+ at section Target OS specific information
+
+ at subsection Linux
+
+To have access to SVGA graphic modes under X11, use the @code{vesa} or
+the @code{cirrus} X11 driver. For optimal performances, use 16 bit
+color depth in the guest and the host OS.
+
+When using a 2.6 guest Linux kernel, you should add the option
+ at code{clock=pit} on the kernel command line because the 2.6 Linux
+kernels make very strict real time clock checks by default that QEMU
+cannot simulate exactly.
+
+When using a 2.6 guest Linux kernel, verify that the 4G/4G patch is
+not activated because QEMU is slower with this patch. The QEMU
+Accelerator Module is also much slower in this case. Earlier Fedora
+Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporate this
+patch by default. Newer kernels don't have it.
+
+ at subsection Windows
+
+If you have a slow host, using Windows 95 is better as it gives the
+best speed. Windows 2000 is also a good choice.
+
+ at subsubsection SVGA graphic modes support
+
+QEMU emulates a Cirrus Logic GD5446 Video
+card. All Windows versions starting from Windows 95 should recognize
+and use this graphic card. For optimal performances, use 16 bit color
+depth in the guest and the host OS.
+
+If you are using Windows XP as guest OS and if you want to use high
+resolution modes which the Cirrus Logic BIOS does not support (i.e. >=
+1280x1024x16), then you should use the VESA VBE virtual graphic card
+(option @option{-std-vga}).
+
+ at subsubsection CPU usage reduction
+
+Windows 9x does not correctly use the CPU HLT
+instruction. The result is that it takes host CPU cycles even when
+idle. You can install the utility from
+ at url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this
+problem. Note that no such tool is needed for NT, 2000 or XP.
+
+ at subsubsection Windows 2000 disk full problem
+
+Windows 2000 has a bug which gives a disk full problem during its
+installation. When installing it, use the @option{-win2k-hack} QEMU
+option to enable a specific workaround. After Windows 2000 is
+installed, you no longer need this option (this option slows down the
+IDE transfers).
+
+ at subsubsection Windows 2000 shutdown
+
+Windows 2000 cannot automatically shutdown in QEMU although Windows 98
+can. It comes from the fact that Windows 2000 does not automatically
+use the APM driver provided by the BIOS.
+
+In order to correct that, do the following (thanks to Struan
+Bartlett): go to the Control Panel => Add/Remove Hardware & Next =>
+Add/Troubleshoot a device => Add a new device & Next => No, select the
+hardware from a list & Next => NT Apm/Legacy Support & Next => Next
+(again) a few times. Now the driver is installed and Windows 2000 now
+correctly instructs QEMU to shutdown at the appropriate moment.
+
+ at subsubsection Share a directory between Unix and Windows
+
+See @ref{sec_invocation} about the help of the option @option{-smb}.
+
+ at subsubsection Windows XP security problem
+
+Some releases of Windows XP install correctly but give a security
+error when booting:
+ at example
+A problem is preventing Windows from accurately checking the
+license for this computer. Error code: 0x800703e6.
+ at end example
+
+The workaround is to install a service pack for XP after a boot in safe
+mode. Then reboot, and the problem should go away. Since there is no
+network while in safe mode, its recommended to download the full
+installation of SP1 or SP2 and transfer that via an ISO or using the
+vvfat block device ("-hdb fat:directory_which_holds_the_SP").
+
+ at subsection MS-DOS and FreeDOS
+
+ at subsubsection CPU usage reduction
+
+DOS does not correctly use the CPU HLT instruction. The result is that
+it takes host CPU cycles even when idle. You can install the utility
+from @url{http://www.vmware.com/software/dosidle210.zip} to solve this
+problem.
+
+ at node QEMU System emulator for non PC targets
+ at chapter QEMU System emulator for non PC targets
+
+QEMU is a generic emulator and it emulates many non PC
+machines. Most of the options are similar to the PC emulator. The
+differences are mentioned in the following sections.
+
+ at menu
+* PowerPC System emulator::
+* Sparc32 System emulator::
+* Sparc64 System emulator::
+* MIPS System emulator::
+* ARM System emulator::
+* ColdFire System emulator::
+* Cris System emulator::
+* Microblaze System emulator::
+* SH4 System emulator::
+ at end menu
+
+ at node PowerPC System emulator
+ at section PowerPC System emulator
+ at cindex system emulation (PowerPC)
+
+Use the executable @file{qemu-system-ppc} to simulate a complete PREP
+or PowerMac PowerPC system.
+
+QEMU emulates the following PowerMac peripherals:
+
+ at itemize @minus
+ at item
+UniNorth or Grackle PCI Bridge
+ at item
+PCI VGA compatible card with VESA Bochs Extensions
+ at item
+2 PMAC IDE interfaces with hard disk and CD-ROM support
+ at item
+NE2000 PCI adapters
+ at item
+Non Volatile RAM
+ at item
+VIA-CUDA with ADB keyboard and mouse.
+ at end itemize
+
+QEMU emulates the following PREP peripherals:
+
+ at itemize @minus
+ at item
+PCI Bridge
+ at item
+PCI VGA compatible card with VESA Bochs Extensions
+ at item
+2 IDE interfaces with hard disk and CD-ROM support
+ at item
+Floppy disk
+ at item
+NE2000 network adapters
+ at item
+Serial port
+ at item
+PREP Non Volatile RAM
+ at item
+PC compatible keyboard and mouse.
+ at end itemize
+
+QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at
+ at url{http://perso.magic.fr/l_indien/OpenHackWare/index.htm}.
+
+Since version 0.9.1, QEMU uses OpenBIOS @url{http://www.openbios.org/}
+for the g3beige and mac99 PowerMac machines. OpenBIOS is a free (GPL
+v2) portable firmware implementation. The goal is to implement a 100%
+IEEE 1275-1994 (referred to as Open Firmware) compliant firmware.
+
+ at c man begin OPTIONS
+
+The following options are specific to the PowerPC emulation:
+
+ at table @option
+
+ at item -g @var{W}x at var{H}[x at var{DEPTH}]
+
+Set the initial VGA graphic mode. The default is 800x600x15.
+
+ at item -prom-env @var{string}
+
+Set OpenBIOS variables in NVRAM, for example:
+
+ at example
+qemu-system-ppc -prom-env 'auto-boot?=false' \
+ -prom-env 'boot-device=hd:2,\yaboot' \
+ -prom-env 'boot-args=conf=hd:2,\yaboot.conf'
+ at end example
+
+These variables are not used by Open Hack'Ware.
+
+ at end table
+
+ at c man end
+
+
+More information is available at
+ at url{http://perso.magic.fr/l_indien/qemu-ppc/}.
+
+ at node Sparc32 System emulator
+ at section Sparc32 System emulator
+ at cindex system emulation (Sparc32)
+
+Use the executable @file{qemu-system-sparc} to simulate the following
+Sun4m architecture machines:
+ at itemize @minus
+ at item
+SPARCstation 4
+ at item
+SPARCstation 5
+ at item
+SPARCstation 10
+ at item
+SPARCstation 20
+ at item
+SPARCserver 600MP
+ at item
+SPARCstation LX
+ at item
+SPARCstation Voyager
+ at item
+SPARCclassic
+ at item
+SPARCbook
+ at end itemize
+
+The emulation is somewhat complete. SMP up to 16 CPUs is supported,
+but Linux limits the number of usable CPUs to 4.
+
+It's also possible to simulate a SPARCstation 2 (sun4c architecture),
+SPARCserver 1000, or SPARCcenter 2000 (sun4d architecture), but these
+emulators are not usable yet.
+
+QEMU emulates the following sun4m/sun4c/sun4d peripherals:
+
+ at itemize @minus
+ at item
+IOMMU or IO-UNITs
+ at item
+TCX Frame buffer
+ at item
+Lance (Am7990) Ethernet
+ at item
+Non Volatile RAM M48T02/M48T08
+ at item
+Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard
+and power/reset logic
+ at item
+ESP SCSI controller with hard disk and CD-ROM support
+ at item
+Floppy drive (not on SS-600MP)
+ at item
+CS4231 sound device (only on SS-5, not working yet)
+ at end itemize
+
+The number of peripherals is fixed in the architecture.  Maximum
+memory size depends on the machine type, for SS-5 it is 256MB and for
+others 2047MB.
+
+Since version 0.8.2, QEMU uses OpenBIOS
+ at url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable
+firmware implementation. The goal is to implement a 100% IEEE
+1275-1994 (referred to as Open Firmware) compliant firmware.
+
+A sample Linux 2.6 series kernel and ram disk image are available on
+the QEMU web site. There are still issues with NetBSD and OpenBSD, but
+some kernel versions work. Please note that currently Solaris kernels
+don't work probably due to interface issues between OpenBIOS and
+Solaris.
+
+ at c man begin OPTIONS
+
+The following options are specific to the Sparc32 emulation:
+
+ at table @option
+
+ at item -g @var{W}x at var{H}x[x at var{DEPTH}]
+
+Set the initial TCX graphic mode. The default is 1024x768x8, currently
+the only other possible mode is 1024x768x24.
+
+ at item -prom-env @var{string}
+
+Set OpenBIOS variables in NVRAM, for example:
+
+ at example
+qemu-system-sparc -prom-env 'auto-boot?=false' \
+ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single'
+ at end example
+
+ at item -M [SS-4|SS-5|SS-10|SS-20|SS-600MP|LX|Voyager|SPARCClassic] [|SPARCbook|SS-2|SS-1000|SS-2000]
+
+Set the emulated machine type. Default is SS-5.
+
+ at end table
+
+ at c man end
+
+ at node Sparc64 System emulator
+ at section Sparc64 System emulator
+ at cindex system emulation (Sparc64)
+
+Use the executable @file{qemu-system-sparc64} to simulate a Sun4u
+(UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic
+Niagara (T1) machine. The emulator is not usable for anything yet, but
+it can launch some kernels.
+
+QEMU emulates the following peripherals:
+
+ at itemize @minus
+ at item
+UltraSparc IIi APB PCI Bridge
+ at item
+PCI VGA compatible card with VESA Bochs Extensions
+ at item
+PS/2 mouse and keyboard
+ at item
+Non Volatile RAM M48T59
+ at item
+PC-compatible serial ports
+ at item
+2 PCI IDE interfaces with hard disk and CD-ROM support
+ at item
+Floppy disk
+ at end itemize
+
+ at c man begin OPTIONS
+
+The following options are specific to the Sparc64 emulation:
+
+ at table @option
+
+ at item -prom-env @var{string}
+
+Set OpenBIOS variables in NVRAM, for example:
+
+ at example
+qemu-system-sparc64 -prom-env 'auto-boot?=false'
+ at end example
+
+ at item -M [sun4u|sun4v|Niagara]
+
+Set the emulated machine type. The default is sun4u.
+
+ at end table
+
+ at c man end
+
+ at node MIPS System emulator
+ at section MIPS System emulator
+ at cindex system emulation (MIPS)
+
+Four executables cover simulation of 32 and 64-bit MIPS systems in
+both endian options, @file{qemu-system-mips}, @file{qemu-system-mipsel}
+ at file{qemu-system-mips64} and @file{qemu-system-mips64el}.
+Five different machine types are emulated:
+
+ at itemize @minus
+ at item
+A generic ISA PC-like machine "mips"
+ at item
+The MIPS Malta prototype board "malta"
+ at item
+An ACER Pica "pica61". This machine needs the 64-bit emulator.
+ at item
+MIPS emulator pseudo board "mipssim"
+ at item
+A MIPS Magnum R4000 machine "magnum". This machine needs the 64-bit emulator.
+ at end itemize
+
+The generic emulation is supported by Debian 'Etch' and is able to
+install Debian into a virtual disk image. The following devices are
+emulated:
+
+ at itemize @minus
+ at item
+A range of MIPS CPUs, default is the 24Kf
+ at item
+PC style serial port
+ at item
+PC style IDE disk
+ at item
+NE2000 network card
+ at end itemize
+
+The Malta emulation supports the following devices:
+
+ at itemize @minus
+ at item
+Core board with MIPS 24Kf CPU and Galileo system controller
+ at item
+PIIX4 PCI/USB/SMbus controller
+ at item
+The Multi-I/O chip's serial device
+ at item
+PCI network cards (PCnet32 and others)
+ at item
+Malta FPGA serial device
+ at item
+Cirrus (default) or any other PCI VGA graphics card
+ at end itemize
+
+The ACER Pica emulation supports:
+
+ at itemize @minus
+ at item
+MIPS R4000 CPU
+ at item
+PC-style IRQ and DMA controllers
+ at item
+PC Keyboard
+ at item
+IDE controller
+ at end itemize
+
+The mipssim pseudo board emulation provides an environment similiar
+to what the proprietary MIPS emulator uses for running Linux.
+It supports:
+
+ at itemize @minus
+ at item
+A range of MIPS CPUs, default is the 24Kf
+ at item
+PC style serial port
+ at item
+MIPSnet network emulation
+ at end itemize
+
+The MIPS Magnum R4000 emulation supports:
+
+ at itemize @minus
+ at item
+MIPS R4000 CPU
+ at item
+PC-style IRQ controller
+ at item
+PC Keyboard
+ at item
+SCSI controller
+ at item
+G364 framebuffer
+ at end itemize
+
+
+ at node ARM System emulator
+ at section ARM System emulator
+ at cindex system emulation (ARM)
+
+Use the executable @file{qemu-system-arm} to simulate a ARM
+machine. The ARM Integrator/CP board is emulated with the following
+devices:
+
+ at itemize @minus
+ at item
+ARM926E, ARM1026E, ARM946E, ARM1136 or Cortex-A8 CPU
+ at item
+Two PL011 UARTs
+ at item
+SMC 91c111 Ethernet adapter
+ at item
+PL110 LCD controller
+ at item
+PL050 KMI with PS/2 keyboard and mouse.
+ at item
+PL181 MultiMedia Card Interface with SD card.
+ at end itemize
+
+The ARM Versatile baseboard is emulated with the following devices:
+
+ at itemize @minus
+ at item
+ARM926E, ARM1136 or Cortex-A8 CPU
+ at item
+PL190 Vectored Interrupt Controller
+ at item
+Four PL011 UARTs
+ at item
+SMC 91c111 Ethernet adapter
+ at item
+PL110 LCD controller
+ at item
+PL050 KMI with PS/2 keyboard and mouse.
+ at item
+PCI host bridge.  Note the emulated PCI bridge only provides access to
+PCI memory space.  It does not provide access to PCI IO space.
+This means some devices (eg. ne2k_pci NIC) are not usable, and others
+(eg. rtl8139 NIC) are only usable when the guest drivers use the memory
+mapped control registers.
+ at item
+PCI OHCI USB controller.
+ at item
+LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
+ at item
+PL181 MultiMedia Card Interface with SD card.
+ at end itemize
+
+Several variants of the ARM RealView baseboard are emulated,
+including the EB, PB-A8 and PBX-A9.  Due to interactions with the
+bootloader, only certain Linux kernel configurations work out
+of the box on these boards.
+
+Kernels for the PB-A8 board should have CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+enabled in the kernel, and expect 512M RAM.  Kernels for The PBX-A9 board
+should have CONFIG_SPARSEMEM enabled, CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+disabled and expect 1024M RAM.
+
+The following devices are emulated:
+
+ at itemize @minus
+ at item
+ARM926E, ARM1136, ARM11MPCore, Cortex-A8 or Cortex-A9 MPCore CPU
+ at item
+ARM AMBA Generic/Distributed Interrupt Controller
+ at item
+Four PL011 UARTs
+ at item
+SMC 91c111 or SMSC LAN9118 Ethernet adapter
+ at item
+PL110 LCD controller
+ at item
+PL050 KMI with PS/2 keyboard and mouse
+ at item
+PCI host bridge
+ at item
+PCI OHCI USB controller
+ at item
+LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices
+ at item
+PL181 MultiMedia Card Interface with SD card.
+ at end itemize
+
+The XScale-based clamshell PDA models ("Spitz", "Akita", "Borzoi"
+and "Terrier") emulation includes the following peripherals:
+
+ at itemize @minus
+ at item
+Intel PXA270 System-on-chip (ARM V5TE core)
+ at item
+NAND Flash memory
+ at item
+IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in "Akita"
+ at item
+On-chip OHCI USB controller
+ at item
+On-chip LCD controller
+ at item
+On-chip Real Time Clock
+ at item
+TI ADS7846 touchscreen controller on SSP bus
+ at item
+Maxim MAX1111 analog-digital converter on I at math{^2}C bus
+ at item
+GPIO-connected keyboard controller and LEDs
+ at item
+Secure Digital card connected to PXA MMC/SD host
+ at item
+Three on-chip UARTs
+ at item
+WM8750 audio CODEC on I at math{^2}C and I at math{^2}S busses
+ at end itemize
+
+The Palm Tungsten|E PDA (codename "Cheetah") emulation includes the
+following elements:
+
+ at itemize @minus
+ at item
+Texas Instruments OMAP310 System-on-chip (ARM 925T core)
+ at item
+ROM and RAM memories (ROM firmware image can be loaded with -option-rom)
+ at item
+On-chip LCD controller
+ at item
+On-chip Real Time Clock
+ at item
+TI TSC2102i touchscreen controller / analog-digital converter / Audio
+CODEC, connected through MicroWire and I at math{^2}S busses
+ at item
+GPIO-connected matrix keypad
+ at item
+Secure Digital card connected to OMAP MMC/SD host
+ at item
+Three on-chip UARTs
+ at end itemize
+
+Nokia N800 and N810 internet tablets (known also as RX-34 and RX-44 / 48)
+emulation supports the following elements:
+
+ at itemize @minus
+ at item
+Texas Instruments OMAP2420 System-on-chip (ARM 1136 core)
+ at item
+RAM and non-volatile OneNAND Flash memories
+ at item
+Display connected to EPSON remote framebuffer chip and OMAP on-chip
+display controller and a LS041y3 MIPI DBI-C controller
+ at item
+TI TSC2301 (in N800) and TI TSC2005 (in N810) touchscreen controllers
+driven through SPI bus
+ at item
+National Semiconductor LM8323-controlled qwerty keyboard driven
+through I at math{^2}C bus
+ at item
+Secure Digital card connected to OMAP MMC/SD host
+ at item
+Three OMAP on-chip UARTs and on-chip STI debugging console
+ at item
+A Bluetooth(R) transceiver and HCI connected to an UART
+ at item
+Mentor Graphics "Inventra" dual-role USB controller embedded in a TI
+TUSB6010 chip - only USB host mode is supported
+ at item
+TI TMP105 temperature sensor driven through I at math{^2}C bus
+ at item
+TI TWL92230C power management companion with an RTC on I at math{^2}C bus
+ at item
+Nokia RETU and TAHVO multi-purpose chips with an RTC, connected
+through CBUS
+ at end itemize
+
+The Luminary Micro Stellaris LM3S811EVB emulation includes the following
+devices:
+
+ at itemize @minus
+ at item
+Cortex-M3 CPU core.
+ at item
+64k Flash and 8k SRAM.
+ at item
+Timers, UARTs, ADC and I at math{^2}C interface.
+ at item
+OSRAM Pictiva 96x16 OLED with SSD0303 controller on I at math{^2}C bus.
+ at end itemize
+
+The Luminary Micro Stellaris LM3S6965EVB emulation includes the following
+devices:
+
+ at itemize @minus
+ at item
+Cortex-M3 CPU core.
+ at item
+256k Flash and 64k SRAM.
+ at item
+Timers, UARTs, ADC, I at math{^2}C and SSI interfaces.
+ at item
+OSRAM Pictiva 128x64 OLED with SSD0323 controller connected via SSI.
+ at end itemize
+
+The Freecom MusicPal internet radio emulation includes the following
+elements:
+
+ at itemize @minus
+ at item
+Marvell MV88W8618 ARM core.
+ at item
+32 MB RAM, 256 KB SRAM, 8 MB flash.
+ at item
+Up to 2 16550 UARTs
+ at item
+MV88W8xx8 Ethernet controller
+ at item
+MV88W8618 audio controller, WM8750 CODEC and mixer
+ at item
+128×64 display with brightness control
+ at item
+2 buttons, 2 navigation wheels with button function
+ at end itemize
+
+The Siemens SX1 models v1 and v2 (default) basic emulation.
+The emulation includes the following elements:
+
+ at itemize @minus
+ at item
+Texas Instruments OMAP310 System-on-chip (ARM 925T core)
+ at item
+ROM and RAM memories (ROM firmware image can be loaded with -pflash)
+V1
+1 Flash of 16MB and 1 Flash of 8MB
+V2
+1 Flash of 32MB
+ at item
+On-chip LCD controller
+ at item
+On-chip Real Time Clock
+ at item
+Secure Digital card connected to OMAP MMC/SD host
+ at item
+Three on-chip UARTs
+ at end itemize
+
+The "Syborg" Symbian Virtual Platform base model includes the following
+elements:
+
+ at itemize @minus
+ at item
+ARM Cortex-A8 CPU
+ at item
+Interrupt controller
+ at item
+Timer
+ at item
+Real Time Clock
+ at item
+Keyboard
+ at item
+Framebuffer
+ at item
+Touchscreen
+ at item
+UARTs
+ at end itemize
+
+A Linux 2.6 test image is available on the QEMU web site. More
+information is available in the QEMU mailing-list archive.
+
+ at c man begin OPTIONS
+
+The following options are specific to the ARM emulation:
+
+ at table @option
+
+ at item -semihosting
+Enable semihosting syscall emulation.
+
+On ARM this implements the "Angel" interface.
+
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
+
+ at end table
+
+ at node ColdFire System emulator
+ at section ColdFire System emulator
+ at cindex system emulation (ColdFire)
+ at cindex system emulation (M68K)
+
+Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine.
+The emulator is able to boot a uClinux kernel.
+
+The M5208EVB emulation includes the following devices:
+
+ at itemize @minus
+ at item
+MCF5208 ColdFire V2 Microprocessor (ISA A+ with EMAC).
+ at item
+Three Two on-chip UARTs.
+ at item
+Fast Ethernet Controller (FEC)
+ at end itemize
+
+The AN5206 emulation includes the following devices:
+
+ at itemize @minus
+ at item
+MCF5206 ColdFire V2 Microprocessor.
+ at item
+Two on-chip UARTs.
+ at end itemize
+
+ at c man begin OPTIONS
+
+The following options are specific to the ColdFire emulation:
+
+ at table @option
+
+ at item -semihosting
+Enable semihosting syscall emulation.
+
+On M68K this implements the "ColdFire GDB" interface used by libgloss.
+
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
+
+ at end table
+
+ at node Cris System emulator
+ at section Cris System emulator
+ at cindex system emulation (Cris)
+
+TODO
+
+ at node Microblaze System emulator
+ at section Microblaze System emulator
+ at cindex system emulation (Microblaze)
+
+TODO
+
+ at node SH4 System emulator
+ at section SH4 System emulator
+ at cindex system emulation (SH4)
+
+TODO
+
+ at node QEMU User space emulator
+ at chapter QEMU User space emulator
+
+ at menu
+* Supported Operating Systems ::
+* Linux User space emulator::
+* Mac OS X/Darwin User space emulator ::
+* BSD User space emulator ::
+ at end menu
+
+ at node Supported Operating Systems
+ at section Supported Operating Systems
+
+The following OS are supported in user space emulation:
+
+ at itemize @minus
+ at item
+Linux (referred as qemu-linux-user)
+ at item
+Mac OS X/Darwin (referred as qemu-darwin-user)
+ at item
+BSD (referred as qemu-bsd-user)
+ at end itemize
+
+ at node Linux User space emulator
+ at section Linux User space emulator
+
+ at menu
+* Quick Start::
+* Wine launch::
+* Command line options::
+* Other binaries::
+ at end menu
+
+ at node Quick Start
+ at subsection Quick Start
+
+In order to launch a Linux process, QEMU needs the process executable
+itself and all the target (x86) dynamic libraries used by it.
+
+ at itemize
+
+ at item On x86, you can just try to launch any process by using the native
+libraries:
+
+ at example
+qemu-i386 -L / /bin/ls
+ at end example
+
+ at code{-L /} tells that the x86 dynamic linker must be searched with a
+ at file{/} prefix.
+
+ at item Since QEMU is also a linux process, you can launch qemu with
+qemu (NOTE: you can only do that if you compiled QEMU from the sources):
+
+ at example
+qemu-i386 -L / qemu-i386 -L / /bin/ls
+ at end example
+
+ at item On non x86 CPUs, you need first to download at least an x86 glibc
+(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that
+ at code{LD_LIBRARY_PATH} is not set:
+
+ at example
+unset LD_LIBRARY_PATH
+ at end example
+
+Then you can launch the precompiled @file{ls} x86 executable:
+
+ at example
+qemu-i386 tests/i386/ls
+ at end example
+You can look at @file{scripts/qemu-binfmt-conf.sh} so that
+QEMU is automatically launched by the Linux kernel when you try to
+launch x86 executables. It requires the @code{binfmt_misc} module in the
+Linux kernel.
+
+ at item The x86 version of QEMU is also included. You can try weird things such as:
+ at example
+qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 \
+          /usr/local/qemu-i386/bin/ls-i386
+ at end example
+
+ at end itemize
+
+ at node Wine launch
+ at subsection Wine launch
+
+ at itemize
+
+ at item Ensure that you have a working QEMU with the x86 glibc
+distribution (see previous section). In order to verify it, you must be
+able to do:
+
+ at example
+qemu-i386 /usr/local/qemu-i386/bin/ls-i386
+ at end example
+
+ at item Download the binary x86 Wine install
+(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
+
+ at item Configure Wine on your account. Look at the provided script
+ at file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous
+ at code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
+
+ at item Then you can try the example @file{putty.exe}:
+
+ at example
+qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
+          /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
+ at end example
+
+ at end itemize
+
+ at node Command line options
+ at subsection Command line options
+
+ at example
+usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
+ at end example
+
+ at table @option
+ at item -h
+Print the help
+ at item -L path
+Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
+ at item -s size
+Set the x86 stack size in bytes (default=524288)
+ at item -cpu model
+Select CPU model (-cpu ? for list and additional feature selection)
+ at item -ignore-environment
+Start with an empty environment. Without this option,
+the initial environment is a copy of the caller's environment.
+ at item -E @var{var}=@var{value}
+Set environment @var{var} to @var{value}.
+ at item -U @var{var}
+Remove @var{var} from the environment.
+ at item -B offset
+Offset guest address by the specified number of bytes.  This is useful when
+the address region required by guest applications is reserved on the host.
+This option is currently only supported on some hosts.
+ at item -R size
+Pre-allocate a guest virtual address space of the given size (in bytes).
+"G", "M", and "k" suffixes may be used when specifying the size.
+ at end table
+
+Debug options:
+
+ at table @option
+ at item -d
+Activate log (logfile=/tmp/qemu.log)
+ at item -p pagesize
+Act as if the host page size was 'pagesize' bytes
+ at item -g port
+Wait gdb connection to port
+ at item -singlestep
+Run the emulation in single step mode.
+ at end table
+
+Environment variables:
+
+ at table @env
+ at item QEMU_STRACE
+Print system calls and arguments similar to the 'strace' program
+(NOTE: the actual 'strace' program will not work because the user
+space emulator hasn't implemented ptrace).  At the moment this is
+incomplete.  All system calls that don't have a specific argument
+format are printed with information for six arguments.  Many
+flag-style arguments don't have decoders and will show up as numbers.
+ at end table
+
+ at node Other binaries
+ at subsection Other binaries
+
+ at cindex user mode (Alpha)
+ at command{qemu-alpha} TODO.
+
+ at cindex user mode (ARM)
+ at command{qemu-armeb} TODO.
+
+ at cindex user mode (ARM)
+ at command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF
+binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
+configurations), and arm-uclinux bFLT format binaries.
+
+ at cindex user mode (ColdFire)
+ at cindex user mode (M68K)
+ at command{qemu-m68k} is capable of running semihosted binaries using the BDM
+(m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and
+coldfire uClinux bFLT format binaries.
+
+The binary format is detected automatically.
+
+ at cindex user mode (Cris)
+ at command{qemu-cris} TODO.
+
+ at cindex user mode (i386)
+ at command{qemu-i386} TODO.
+ at command{qemu-x86_64} TODO.
+
+ at cindex user mode (Microblaze)
+ at command{qemu-microblaze} TODO.
+
+ at cindex user mode (MIPS)
+ at command{qemu-mips} TODO.
+ at command{qemu-mipsel} TODO.
+
+ at cindex user mode (PowerPC)
+ at command{qemu-ppc64abi32} TODO.
+ at command{qemu-ppc64} TODO.
+ at command{qemu-ppc} TODO.
+
+ at cindex user mode (SH4)
+ at command{qemu-sh4eb} TODO.
+ at command{qemu-sh4} TODO.
+
+ at cindex user mode (SPARC)
+ at command{qemu-sparc} can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI).
+
+ at command{qemu-sparc32plus} can execute Sparc32 and SPARC32PLUS binaries
+(Sparc64 CPU, 32 bit ABI).
+
+ at command{qemu-sparc64} can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and
+SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI).
+
+ at node Mac OS X/Darwin User space emulator
+ at section Mac OS X/Darwin User space emulator
+
+ at menu
+* Mac OS X/Darwin Status::
+* Mac OS X/Darwin Quick Start::
+* Mac OS X/Darwin Command line options::
+ at end menu
+
+ at node Mac OS X/Darwin Status
+ at subsection Mac OS X/Darwin Status
+
+ at itemize @minus
+ at item
+target x86 on x86: Most apps (Cocoa and Carbon too) works. [1]
+ at item
+target PowerPC on x86: Not working as the ppc commpage can't be mapped (yet!)
+ at item
+target PowerPC on PowerPC: Most apps (Cocoa and Carbon too) works. [1]
+ at item
+target x86 on PowerPC: most utilities work. Cocoa and Carbon apps are not yet supported.
+ at end itemize
+
+[1] If you're host commpage can be executed by qemu.
+
+ at node Mac OS X/Darwin Quick Start
+ at subsection Quick Start
+
+In order to launch a Mac OS X/Darwin process, QEMU needs the process executable
+itself and all the target dynamic libraries used by it. If you don't have the FAT
+libraries (you're running Mac OS X/ppc) you'll need to obtain it from a Mac OS X
+CD or compile them by hand.
+
+ at itemize
+
+ at item On x86, you can just try to launch any process by using the native
+libraries:
+
+ at example
+qemu-i386 /bin/ls
+ at end example
+
+or to run the ppc version of the executable:
+
+ at example
+qemu-ppc /bin/ls
+ at end example
+
+ at item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker)
+are installed:
+
+ at example
+qemu-i386 -L /opt/x86_root/ /bin/ls
+ at end example
+
+ at code{-L /opt/x86_root/} tells that the dynamic linker (dyld) path is in
+ at file{/opt/x86_root/usr/bin/dyld}.
+
+ at end itemize
+
+ at node Mac OS X/Darwin Command line options
+ at subsection Command line options
+
+ at example
+usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
+ at end example
+
+ at table @option
+ at item -h
+Print the help
+ at item -L path
+Set the library root path (default=/)
+ at item -s size
+Set the stack size in bytes (default=524288)
+ at end table
+
+Debug options:
+
+ at table @option
+ at item -d
+Activate log (logfile=/tmp/qemu.log)
+ at item -p pagesize
+Act as if the host page size was 'pagesize' bytes
+ at item -singlestep
+Run the emulation in single step mode.
+ at end table
+
+ at node BSD User space emulator
+ at section BSD User space emulator
+
+ at menu
+* BSD Status::
+* BSD Quick Start::
+* BSD Command line options::
+ at end menu
+
+ at node BSD Status
+ at subsection BSD Status
+
+ at itemize @minus
+ at item
+target Sparc64 on Sparc64: Some trivial programs work.
+ at end itemize
+
+ at node BSD Quick Start
+ at subsection Quick Start
+
+In order to launch a BSD process, QEMU needs the process executable
+itself and all the target dynamic libraries used by it.
+
+ at itemize
+
+ at item On Sparc64, you can just try to launch any process by using the native
+libraries:
+
+ at example
+qemu-sparc64 /bin/ls
+ at end example
+
+ at end itemize
+
+ at node BSD Command line options
+ at subsection Command line options
+
+ at example
+usage: qemu-sparc64 [-h] [-d] [-L path] [-s size] [-bsd type] program [arguments...]
+ at end example
+
+ at table @option
+ at item -h
+Print the help
+ at item -L path
+Set the library root path (default=/)
+ at item -s size
+Set the stack size in bytes (default=524288)
+ at item -ignore-environment
+Start with an empty environment. Without this option,
+the initial environment is a copy of the caller's environment.
+ at item -E @var{var}=@var{value}
+Set environment @var{var} to @var{value}.
+ at item -U @var{var}
+Remove @var{var} from the environment.
+ at item -bsd type
+Set the type of the emulated BSD Operating system. Valid values are
+FreeBSD, NetBSD and OpenBSD (default).
+ at end table
+
+Debug options:
+
+ at table @option
+ at item -d
+Activate log (logfile=/tmp/qemu.log)
+ at item -p pagesize
+Act as if the host page size was 'pagesize' bytes
+ at item -singlestep
+Run the emulation in single step mode.
+ at end table
+
+ at node compilation
+ at chapter Compilation from the sources
+
+ at menu
+* Linux/Unix::
+* Windows::
+* Cross compilation for Windows with Linux::
+* Mac OS X::
+* Make targets::
+ at end menu
+
+ at node Linux/Unix
+ at section Linux/Unix
+
+ at subsection Compilation
+
+First you must decompress the sources:
+ at example
+cd /tmp
+tar zxvf qemu-x.y.z.tar.gz
+cd qemu-x.y.z
+ at end example
+
+Then you configure QEMU and build it (usually no options are needed):
+ at example
+./configure
+make
+ at end example
+
+Then type as root user:
+ at example
+make install
+ at end example
+to install QEMU in @file{/usr/local}.
+
+ at node Windows
+ at section Windows
+
+ at itemize
+ at item Install the current versions of MSYS and MinGW from
+ at url{http://www.mingw.org/}. You can find detailed installation
+instructions in the download section and the FAQ.
+
+ at item Download
+the MinGW development library of SDL 1.2.x
+(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
+ at url{http://www.libsdl.org}. Unpack it in a temporary place and
+edit the @file{sdl-config} script so that it gives the
+correct SDL directory when invoked.
+
+ at item Install the MinGW version of zlib and make sure
+ at file{zlib.h} and @file{libz.dll.a} are in
+MinGW's default header and linker search paths.
+
+ at item Extract the current version of QEMU.
+
+ at item Start the MSYS shell (file @file{msys.bat}).
+
+ at item Change to the QEMU directory. Launch @file{./configure} and
+ at file{make}.  If you have problems using SDL, verify that
+ at file{sdl-config} can be launched from the MSYS command line.
+
+ at item You can install QEMU in @file{Program Files/Qemu} by typing
+ at file{make install}. Don't forget to copy @file{SDL.dll} in
+ at file{Program Files/Qemu}.
+
+ at end itemize
+
+ at node Cross compilation for Windows with Linux
+ at section Cross compilation for Windows with Linux
+
+ at itemize
+ at item
+Install the MinGW cross compilation tools available at
+ at url{http://www.mingw.org/}.
+
+ at item Download
+the MinGW development library of SDL 1.2.x
+(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
+ at url{http://www.libsdl.org}. Unpack it in a temporary place and
+edit the @file{sdl-config} script so that it gives the
+correct SDL directory when invoked.  Set up the @code{PATH} environment
+variable so that @file{sdl-config} can be launched by
+the QEMU configuration script.
+
+ at item Install the MinGW version of zlib and make sure
+ at file{zlib.h} and @file{libz.dll.a} are in
+MinGW's default header and linker search paths.
+
+ at item
+Configure QEMU for Windows cross compilation:
+ at example
+PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i686-pc-mingw32-'
+ at end example
+The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and
+MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}.
+We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and
+use --cross-prefix to specify the name of the cross compiler.
+You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}.
+
+Under Fedora Linux, you can run:
+ at example
+yum -y install mingw32-gcc mingw32-SDL mingw32-zlib
+ at end example
+to get a suitable cross compilation environment.
+
+ at item You can install QEMU in the installation directory by typing
+ at code{make install}. Don't forget to copy @file{SDL.dll} and @file{zlib1.dll} into the
+installation directory.
+
+ at end itemize
+
+Wine can be used to launch the resulting qemu.exe compiled for Win32.
+
+ at node Mac OS X
+ at section Mac OS X
+
+The Mac OS X patches are not fully merged in QEMU, so you should look
+at the QEMU mailing list archive to have all the necessary
+information.
+
+ at node Make targets
+ at section Make targets
+
+ at table @code
+
+ at item make
+ at item make all
+Make everything which is typically needed.
+
+ at item install
+TODO
+
+ at item install-doc
+TODO
+
+ at item make clean
+Remove most files which were built during make.
+
+ at item make distclean
+Remove everything which was built during make.
+
+ at item make dvi
+ at item make html
+ at item make info
+ at item make pdf
+Create documentation in dvi, html, info or pdf format.
+
+ at item make cscope
+TODO
+
+ at item make defconfig
+(Re-)create some build configuration files.
+User made changes will be overwritten.
+
+ at item tar
+ at item tarbin
+TODO
+
+ at end table
+
+ at node License
+ at appendix License
+
+QEMU is a trademark of Fabrice Bellard.
+
+QEMU is released under the GNU General Public License (TODO: add link).
+Parts of QEMU have specific licenses, see file LICENSE.
+
+TODO (refer to file LICENSE, include it, include the GPL?)
+
+ at node Index
+ at appendix Index
+ at menu
+* Concept Index::
+* Function Index::
+* Keystroke Index::
+* Program Index::
+* Data Type Index::
+* Variable Index::
+ at end menu
+
+ at node Concept Index
+ at section Concept Index
+This is the main index. Should we combine all keywords in one index? TODO
+ at printindex cp
+
+ at node Function Index
+ at section Function Index
+This index could be used for command line options and monitor functions.
+ at printindex fn
+
+ at node Keystroke Index
+ at section Keystroke Index
+
+This is a list of all keystrokes which have a special function
+in system emulation.
+
+ at printindex ky
+
+ at node Program Index
+ at section Program Index
+ at printindex pg
+
+ at node Data Type Index
+ at section Data Type Index
+
+This index could be used for qdev device names and options.
+
+ at printindex tp
+
+ at node Variable Index
+ at section Variable Index
+ at printindex vr
+
+ at bye
diff --git a/qemu-0.15.x/qemu-error.c b/qemu-0.15.x/qemu-error.c
new file mode 100644
index 0000000..4b20d28
--- /dev/null
+++ b/qemu-0.15.x/qemu-error.c
@@ -0,0 +1,210 @@
+/*
+ * Error reporting
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <armbru at redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include "monitor.h"
+
+/*
+ * Print to current monitor if we have one, else to stderr.
+ * TODO should return int, so callers can calculate width, but that
+ * requires surgery to monitor_vprintf().  Left for another day.
+ */
+void error_vprintf(const char *fmt, va_list ap)
+{
+    if (cur_mon) {
+        monitor_vprintf(cur_mon, fmt, ap);
+    } else {
+        vfprintf(stderr, fmt, ap);
+    }
+}
+
+/*
+ * Print to current monitor if we have one, else to stderr.
+ * TODO just like error_vprintf()
+ */
+void error_printf(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    error_vprintf(fmt, ap);
+    va_end(ap);
+}
+
+void error_printf_unless_qmp(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (!monitor_cur_is_qmp()) {
+        va_start(ap, fmt);
+        error_vprintf(fmt, ap);
+        va_end(ap);
+    }
+}
+
+static Location std_loc = {
+    .kind = LOC_NONE
+};
+static Location *cur_loc = &std_loc;
+
+/*
+ * Push location saved in LOC onto the location stack, return it.
+ * The top of that stack is the current location.
+ * Needs a matching loc_pop().
+ */
+Location *loc_push_restore(Location *loc)
+{
+    assert(!loc->prev);
+    loc->prev = cur_loc;
+    cur_loc = loc;
+    return loc;
+}
+
+/*
+ * Initialize *LOC to "nowhere", push it onto the location stack.
+ * The top of that stack is the current location.
+ * Needs a matching loc_pop().
+ * Return LOC.
+ */
+Location *loc_push_none(Location *loc)
+{
+    loc->kind = LOC_NONE;
+    loc->prev = NULL;
+    return loc_push_restore(loc);
+}
+
+/*
+ * Pop the location stack.
+ * LOC must be the current location, i.e. the top of the stack.
+ */
+Location *loc_pop(Location *loc)
+{
+    assert(cur_loc == loc && loc->prev);
+    cur_loc = loc->prev;
+    loc->prev = NULL;
+    return loc;
+}
+
+/*
+ * Save the current location in LOC, return LOC.
+ */
+Location *loc_save(Location *loc)
+{
+    *loc = *cur_loc;
+    loc->prev = NULL;
+    return loc;
+}
+
+/*
+ * Change the current location to the one saved in LOC.
+ */
+void loc_restore(Location *loc)
+{
+    Location *prev = cur_loc->prev;
+    assert(!loc->prev);
+    *cur_loc = *loc;
+    cur_loc->prev = prev;
+}
+
+/*
+ * Change the current location to "nowhere in particular".
+ */
+void loc_set_none(void)
+{
+    cur_loc->kind = LOC_NONE;
+}
+
+/*
+ * Change the current location to argument ARGV[IDX..IDX+CNT-1].
+ */
+void loc_set_cmdline(char **argv, int idx, int cnt)
+{
+    cur_loc->kind = LOC_CMDLINE;
+    cur_loc->num = cnt;
+    cur_loc->ptr = argv + idx;
+}
+
+/*
+ * Change the current location to file FNAME, line LNO.
+ */
+void loc_set_file(const char *fname, int lno)
+{
+    assert (fname || cur_loc->kind == LOC_FILE);
+    cur_loc->kind = LOC_FILE;
+    cur_loc->num = lno;
+    if (fname) {
+        cur_loc->ptr = fname;
+    }
+}
+
+static const char *progname;
+
+/*
+ * Set the program name for error_print_loc().
+ */
+void error_set_progname(const char *argv0)
+{
+    const char *p = strrchr(argv0, '/');
+    progname = p ? p + 1 : argv0;
+}
+
+/*
+ * Print current location to current monitor if we have one, else to stderr.
+ */
+void error_print_loc(void)
+{
+    const char *sep = "";
+    int i;
+    const char *const *argp;
+
+    if (!cur_mon && progname) {
+        fprintf(stderr, "%s:", progname);
+        sep = " ";
+    }
+    switch (cur_loc->kind) {
+    case LOC_CMDLINE:
+        argp = cur_loc->ptr;
+        for (i = 0; i < cur_loc->num; i++) {
+            error_printf("%s%s", sep, argp[i]);
+            sep = " ";
+        }
+        error_printf(": ");
+        break;
+    case LOC_FILE:
+        error_printf("%s:", (const char *)cur_loc->ptr);
+        if (cur_loc->num) {
+            error_printf("%d:", cur_loc->num);
+        }
+        error_printf(" ");
+        break;
+    default:
+        error_printf("%s", sep);
+    }
+}
+
+/*
+ * Print an error message to current monitor if we have one, else to stderr.
+ * Format arguments like sprintf().  The result should not contain
+ * newlines.
+ * Prepend the current location and append a newline.
+ * It's wrong to call this in a QMP monitor.  Use qerror_report() there.
+ */
+void error_report(const char *fmt, ...)
+{
+    va_list ap;
+
+    error_print_loc();
+    va_start(ap, fmt);
+    error_vprintf(fmt, ap);
+    va_end(ap);
+    error_printf("\n");
+}
diff --git a/qemu-0.15.x/qemu-error.h b/qemu-0.15.x/qemu-error.h
new file mode 100644
index 0000000..4d5c537
--- /dev/null
+++ b/qemu-0.15.x/qemu-error.h
@@ -0,0 +1,40 @@
+/*
+ * Error reporting
+ *
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <armbru at redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_ERROR_H
+#define QEMU_ERROR_H
+
+typedef struct Location {
+    /* all members are private to qemu-error.c */
+    enum { LOC_NONE, LOC_CMDLINE, LOC_FILE } kind;
+    int num;
+    const void *ptr;
+    struct Location *prev;
+} Location;
+
+Location *loc_push_restore(Location *loc);
+Location *loc_push_none(Location *loc);
+Location *loc_pop(Location *loc);
+Location *loc_save(Location *loc);
+void loc_restore(Location *loc);
+void loc_set_none(void);
+void loc_set_cmdline(char **argv, int idx, int cnt);
+void loc_set_file(const char *fname, int lno);
+
+void error_vprintf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
+void error_printf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void error_printf_unless_qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void error_print_loc(void);
+void error_set_progname(const char *argv0);
+void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
+#endif
diff --git a/qemu-0.15.x/qemu-ga.c b/qemu-0.15.x/qemu-ga.c
new file mode 100644
index 0000000..869ee37
--- /dev/null
+++ b/qemu-0.15.x/qemu-ga.c
@@ -0,0 +1,637 @@
+/*
+ * QEMU Guest Agent
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Adam Litke        <aglitke at linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <getopt.h>
+#include <termios.h>
+#include <syslog.h>
+#include "qemu_socket.h"
+#include "json-streamer.h"
+#include "json-parser.h"
+#include "qint.h"
+#include "qjson.h"
+#include "qga/guest-agent-core.h"
+#include "module.h"
+#include "signal.h"
+#include "qerror.h"
+#include "error_int.h"
+
+#define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
+#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
+#define QGA_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
+#define QGA_TIMEOUT_DEFAULT 30*1000 /* ms */
+
+struct GAState {
+    JSONMessageParser parser;
+    GMainLoop *main_loop;
+    GIOChannel *conn_channel;
+    GIOChannel *listen_channel;
+    const char *path;
+    const char *method;
+    bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
+    GACommandState *command_state;
+    GLogLevelFlags log_level;
+    FILE *log_file;
+    bool logging_enabled;
+};
+
+static struct GAState *ga_state;
+
+static void quit_handler(int sig)
+{
+    g_debug("recieved signal num %d, quitting", sig);
+
+    if (g_main_loop_is_running(ga_state->main_loop)) {
+        g_main_loop_quit(ga_state->main_loop);
+    }
+}
+
+static void register_signal_handlers(void)
+{
+    struct sigaction sigact;
+    int ret;
+
+    memset(&sigact, 0, sizeof(struct sigaction));
+    sigact.sa_handler = quit_handler;
+
+    ret = sigaction(SIGINT, &sigact, NULL);
+    if (ret == -1) {
+        g_error("error configuring signal handler: %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    ret = sigaction(SIGTERM, &sigact, NULL);
+    if (ret == -1) {
+        g_error("error configuring signal handler: %s", strerror(errno));
+    }
+}
+
+static void usage(const char *cmd)
+{
+    printf(
+"Usage: %s -c <channel_opts>\n"
+"QEMU Guest Agent %s\n"
+"\n"
+"  -m, --method      transport method: one of unix-listen, virtio-serial, or\n"
+"                    isa-serial (virtio-serial is the default)\n"
+"  -p, --path        device/socket path (%s is the default for virtio-serial)\n"
+"  -l, --logfile     set logfile path, logs to stderr by default\n"
+"  -f, --pidfile     specify pidfile (default is %s)\n"
+"  -v, --verbose     log extra debugging information\n"
+"  -V, --version     print version information and exit\n"
+"  -d, --daemonize   become a daemon\n"
+"  -h, --help        display this help and exit\n"
+"\n"
+"Report bugs to <mdroth at linux.vnet.ibm.com>\n"
+    , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT);
+}
+
+static void conn_channel_close(GAState *s);
+
+static const char *ga_log_level_str(GLogLevelFlags level)
+{
+    switch (level & G_LOG_LEVEL_MASK) {
+        case G_LOG_LEVEL_ERROR:
+            return "error";
+        case G_LOG_LEVEL_CRITICAL:
+            return "critical";
+        case G_LOG_LEVEL_WARNING:
+            return "warning";
+        case G_LOG_LEVEL_MESSAGE:
+            return "message";
+        case G_LOG_LEVEL_INFO:
+            return "info";
+        case G_LOG_LEVEL_DEBUG:
+            return "debug";
+        default:
+            return "user";
+    }
+}
+
+bool ga_logging_enabled(GAState *s)
+{
+    return s->logging_enabled;
+}
+
+void ga_disable_logging(GAState *s)
+{
+    s->logging_enabled = false;
+}
+
+void ga_enable_logging(GAState *s)
+{
+    s->logging_enabled = true;
+}
+
+static void ga_log(const gchar *domain, GLogLevelFlags level,
+                   const gchar *msg, gpointer opaque)
+{
+    GAState *s = opaque;
+    GTimeVal time;
+    const char *level_str = ga_log_level_str(level);
+
+    if (!ga_logging_enabled(s)) {
+        return;
+    }
+
+    level &= G_LOG_LEVEL_MASK;
+    if (g_strcmp0(domain, "syslog") == 0) {
+        syslog(LOG_INFO, "%s: %s", level_str, msg);
+    } else if (level & s->log_level) {
+        g_get_current_time(&time);
+        fprintf(s->log_file,
+                "%lu.%lu: %s: %s\n", time.tv_sec, time.tv_usec, level_str, msg);
+        fflush(s->log_file);
+    }
+}
+
+static void become_daemon(const char *pidfile)
+{
+    pid_t pid, sid;
+    int pidfd;
+    char *pidstr = NULL;
+
+    pid = fork();
+    if (pid < 0) {
+        exit(EXIT_FAILURE);
+    }
+    if (pid > 0) {
+        exit(EXIT_SUCCESS);
+    }
+
+    pidfd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, S_IRUSR|S_IWUSR);
+    if (pidfd == -1) {
+        g_critical("Cannot create pid file, %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    if (asprintf(&pidstr, "%d", getpid()) == -1) {
+        g_critical("Cannot allocate memory");
+        goto fail;
+    }
+    if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
+        free(pidstr);
+        g_critical("Failed to write pid file");
+        goto fail;
+    }
+
+    umask(0);
+    sid = setsid();
+    if (sid < 0) {
+        goto fail;
+    }
+    if ((chdir("/")) < 0) {
+        goto fail;
+    }
+
+    close(STDIN_FILENO);
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+    free(pidstr);
+    return;
+
+fail:
+    unlink(pidfile);
+    g_critical("failed to daemonize");
+    exit(EXIT_FAILURE);
+}
+
+static int conn_channel_send_buf(GIOChannel *channel, const char *buf,
+                                 gsize count)
+{
+    GError *err = NULL;
+    gsize written = 0;
+    GIOStatus status;
+
+    while (count) {
+        status = g_io_channel_write_chars(channel, buf, count, &written, &err);
+        g_debug("sending data, count: %d", (int)count);
+        if (err != NULL) {
+            g_warning("error sending newline: %s", err->message);
+            return err->code;
+        }
+        if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
+            return -EPIPE;
+        }
+
+        if (status == G_IO_STATUS_NORMAL) {
+            count -= written;
+        }
+    }
+
+    return 0;
+}
+
+static int conn_channel_send_payload(GIOChannel *channel, QObject *payload)
+{
+    int ret = 0;
+    const char *buf;
+    QString *payload_qstr;
+    GError *err = NULL;
+
+    g_assert(payload && channel);
+
+    payload_qstr = qobject_to_json(payload);
+    if (!payload_qstr) {
+        return -EINVAL;
+    }
+
+    qstring_append_chr(payload_qstr, '\n');
+    buf = qstring_get_str(payload_qstr);
+    ret = conn_channel_send_buf(channel, buf, strlen(buf));
+    if (ret) {
+        goto out_free;
+    }
+
+    g_io_channel_flush(channel, &err);
+    if (err != NULL) {
+        g_warning("error flushing payload: %s", err->message);
+        ret = err->code;
+        goto out_free;
+    }
+
+out_free:
+    QDECREF(payload_qstr);
+    if (err) {
+        g_error_free(err);
+    }
+    return ret;
+}
+
+static void process_command(GAState *s, QDict *req)
+{
+    QObject *rsp = NULL;
+    int ret;
+
+    g_assert(req);
+    g_debug("processing command");
+    rsp = qmp_dispatch(QOBJECT(req));
+    if (rsp) {
+        ret = conn_channel_send_payload(s->conn_channel, rsp);
+        if (ret) {
+            g_warning("error sending payload: %s", strerror(ret));
+        }
+        qobject_decref(rsp);
+    } else {
+        g_warning("error getting response");
+    }
+}
+
+/* handle requests/control events coming in over the channel */
+static void process_event(JSONMessageParser *parser, QList *tokens)
+{
+    GAState *s = container_of(parser, GAState, parser);
+    QObject *obj;
+    QDict *qdict;
+    Error *err = NULL;
+    int ret;
+
+    g_assert(s && parser);
+
+    g_debug("process_event: called");
+    obj = json_parser_parse_err(tokens, NULL, &err);
+    if (err || !obj || qobject_type(obj) != QTYPE_QDICT) {
+        qobject_decref(obj);
+        qdict = qdict_new();
+        if (!err) {
+            g_warning("failed to parse event: unknown error");
+            error_set(&err, QERR_JSON_PARSING);
+        } else {
+            g_warning("failed to parse event: %s", error_get_pretty(err));
+        }
+        qdict_put_obj(qdict, "error", error_get_qobject(err));
+        error_free(err);
+    } else {
+        qdict = qobject_to_qdict(obj);
+    }
+
+    g_assert(qdict);
+
+    /* handle host->guest commands */
+    if (qdict_haskey(qdict, "execute")) {
+        process_command(s, qdict);
+    } else {
+        if (!qdict_haskey(qdict, "error")) {
+            QDECREF(qdict);
+            qdict = qdict_new();
+            g_warning("unrecognized payload format");
+            error_set(&err, QERR_UNSUPPORTED);
+            qdict_put_obj(qdict, "error", error_get_qobject(err));
+            error_free(err);
+        }
+        ret = conn_channel_send_payload(s->conn_channel, QOBJECT(qdict));
+        if (ret) {
+            g_warning("error sending payload: %s", strerror(ret));
+        }
+    }
+
+    QDECREF(qdict);
+}
+
+static gboolean conn_channel_read(GIOChannel *channel, GIOCondition condition,
+                                  gpointer data)
+{
+    GAState *s = data;
+    gchar buf[1024];
+    gsize count;
+    GError *err = NULL;
+    memset(buf, 0, 1024);
+    GIOStatus status = g_io_channel_read_chars(channel, buf, 1024,
+                                               &count, &err);
+    if (err != NULL) {
+        g_warning("error reading channel: %s", err->message);
+        conn_channel_close(s);
+        g_error_free(err);
+        return false;
+    }
+    switch (status) {
+    case G_IO_STATUS_ERROR:
+        g_warning("problem");
+        return false;
+    case G_IO_STATUS_NORMAL:
+        g_debug("read data, count: %d, data: %s", (int)count, buf);
+        json_message_parser_feed(&s->parser, (char *)buf, (int)count);
+    case G_IO_STATUS_AGAIN:
+        /* virtio causes us to spin here when no process is attached to
+         * host-side chardev. sleep a bit to mitigate this
+         */
+        if (s->virtio) {
+            usleep(100*1000);
+        }
+        return true;
+    case G_IO_STATUS_EOF:
+        g_debug("received EOF");
+        conn_channel_close(s);
+        if (s->virtio) {
+            return true;
+        }
+        return false;
+    default:
+        g_warning("unknown channel read status, closing");
+        conn_channel_close(s);
+        return false;
+    }
+    return true;
+}
+
+static int conn_channel_add(GAState *s, int fd)
+{
+    GIOChannel *conn_channel;
+    GError *err = NULL;
+
+    g_assert(s && !s->conn_channel);
+    conn_channel = g_io_channel_unix_new(fd);
+    g_assert(conn_channel);
+    g_io_channel_set_encoding(conn_channel, NULL, &err);
+    if (err != NULL) {
+        g_warning("error setting channel encoding to binary");
+        g_error_free(err);
+        return -1;
+    }
+    g_io_add_watch(conn_channel, G_IO_IN | G_IO_HUP,
+                   conn_channel_read, s);
+    s->conn_channel = conn_channel;
+    return 0;
+}
+
+static gboolean listen_channel_accept(GIOChannel *channel,
+                                      GIOCondition condition, gpointer data)
+{
+    GAState *s = data;
+    g_assert(channel != NULL);
+    int ret, conn_fd;
+    bool accepted = false;
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+
+    conn_fd = qemu_accept(g_io_channel_unix_get_fd(s->listen_channel),
+                             (struct sockaddr *)&addr, &addrlen);
+    if (conn_fd == -1) {
+        g_warning("error converting fd to gsocket: %s", strerror(errno));
+        goto out;
+    }
+    fcntl(conn_fd, F_SETFL, O_NONBLOCK);
+    ret = conn_channel_add(s, conn_fd);
+    if (ret) {
+        g_warning("error setting up connection");
+        goto out;
+    }
+    accepted = true;
+
+out:
+    /* only accept 1 connection at a time */
+    return !accepted;
+}
+
+/* start polling for readable events on listen fd, new==true
+ * indicates we should use the existing s->listen_channel
+ */
+static int listen_channel_add(GAState *s, int listen_fd, bool new)
+{
+    if (new) {
+        s->listen_channel = g_io_channel_unix_new(listen_fd);
+    }
+    g_io_add_watch(s->listen_channel, G_IO_IN,
+                   listen_channel_accept, s);
+    return 0;
+}
+
+/* cleanup state for closed connection/session, start accepting new
+ * connections if we're in listening mode
+ */
+static void conn_channel_close(GAState *s)
+{
+    if (strcmp(s->method, "unix-listen") == 0) {
+        g_io_channel_shutdown(s->conn_channel, true, NULL);
+        listen_channel_add(s, 0, false);
+    } else if (strcmp(s->method, "virtio-serial") == 0) {
+        /* we spin on EOF for virtio-serial, so back off a bit. also,
+         * dont close the connection in this case, it'll resume normal
+         * operation when another process connects to host chardev
+         */
+        usleep(100*1000);
+        goto out_noclose;
+    }
+    g_io_channel_unref(s->conn_channel);
+    s->conn_channel = NULL;
+out_noclose:
+    return;
+}
+
+static void init_guest_agent(GAState *s)
+{
+    struct termios tio;
+    int ret, fd;
+
+    if (s->method == NULL) {
+        /* try virtio-serial as our default */
+        s->method = "virtio-serial";
+    }
+
+    if (s->path == NULL) {
+        if (strcmp(s->method, "virtio-serial") != 0) {
+            g_critical("must specify a path for this channel");
+            exit(EXIT_FAILURE);
+        }
+        /* try the default path for the virtio-serial port */
+        s->path = QGA_VIRTIO_PATH_DEFAULT;
+    }
+
+    if (strcmp(s->method, "virtio-serial") == 0) {
+        s->virtio = true;
+        fd = qemu_open(s->path, O_RDWR | O_NONBLOCK | O_ASYNC);
+        if (fd == -1) {
+            g_critical("error opening channel: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        ret = conn_channel_add(s, fd);
+        if (ret) {
+            g_critical("error adding channel to main loop");
+            exit(EXIT_FAILURE);
+        }
+    } else if (strcmp(s->method, "isa-serial") == 0) {
+        fd = qemu_open(s->path, O_RDWR | O_NOCTTY);
+        if (fd == -1) {
+            g_critical("error opening channel: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        tcgetattr(fd, &tio);
+        /* set up serial port for non-canonical, dumb byte streaming */
+        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
+                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
+                         IMAXBEL);
+        tio.c_oflag = 0;
+        tio.c_lflag = 0;
+        tio.c_cflag |= QGA_BAUDRATE_DEFAULT;
+        /* 1 available byte min or reads will block (we'll set non-blocking
+         * elsewhere, else we have to deal with read()=0 instead)
+         */
+        tio.c_cc[VMIN] = 1;
+        tio.c_cc[VTIME] = 0;
+        /* flush everything waiting for read/xmit, it's garbage at this point */
+        tcflush(fd, TCIFLUSH);
+        tcsetattr(fd, TCSANOW, &tio);
+        ret = conn_channel_add(s, fd);
+        if (ret) {
+            g_error("error adding channel to main loop");
+        }
+    } else if (strcmp(s->method, "unix-listen") == 0) {
+        fd = unix_listen(s->path, NULL, strlen(s->path));
+        if (fd == -1) {
+            g_critical("error opening path: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        ret = listen_channel_add(s, fd, true);
+        if (ret) {
+            g_critical("error binding/listening to specified socket");
+            exit(EXIT_FAILURE);
+        }
+    } else {
+        g_critical("unsupported channel method/type: %s", s->method);
+        exit(EXIT_FAILURE);
+    }
+
+    json_message_parser_init(&s->parser, process_event);
+    s->main_loop = g_main_loop_new(NULL, false);
+}
+
+int main(int argc, char **argv)
+{
+    const char *sopt = "hVvdm:p:l:f:";
+    const char *method = NULL, *path = NULL, *pidfile = QGA_PIDFILE_DEFAULT;
+    const struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "logfile", 0, NULL, 'l' },
+        { "pidfile", 0, NULL, 'f' },
+        { "verbose", 0, NULL, 'v' },
+        { "method", 0, NULL, 'm' },
+        { "path", 0, NULL, 'p' },
+        { "daemonize", 0, NULL, 'd' },
+        { NULL, 0, NULL, 0 }
+    };
+    int opt_ind = 0, ch, daemonize = 0;
+    GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
+    FILE *log_file = stderr;
+    GAState *s;
+
+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+        switch (ch) {
+        case 'm':
+            method = optarg;
+            break;
+        case 'p':
+            path = optarg;
+            break;
+        case 'l':
+            log_file = fopen(optarg, "a");
+            if (!log_file) {
+                g_critical("unable to open specified log file: %s",
+                           strerror(errno));
+                return EXIT_FAILURE;
+            }
+            break;
+        case 'f':
+            pidfile = optarg;
+            break;
+        case 'v':
+            /* enable all log levels */
+            log_level = G_LOG_LEVEL_MASK;
+            break;
+        case 'V':
+            printf("QEMU Guest Agent %s\n", QGA_VERSION);
+            return 0;
+        case 'd':
+            daemonize = 1;
+            break;
+        case 'h':
+            usage(argv[0]);
+            return 0;
+        case '?':
+            g_print("Unknown option, try '%s --help' for more information.\n",
+                    argv[0]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (daemonize) {
+        g_debug("starting daemon");
+        become_daemon(pidfile);
+    }
+
+    s = qemu_mallocz(sizeof(GAState));
+    s->conn_channel = NULL;
+    s->path = path;
+    s->method = method;
+    s->log_file = log_file;
+    s->log_level = log_level;
+    g_log_set_default_handler(ga_log, s);
+    g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
+    s->logging_enabled = true;
+    s->command_state = ga_command_state_new();
+    ga_command_state_init(s, s->command_state);
+    ga_command_state_init_all(s->command_state);
+    ga_state = s;
+
+    module_call_init(MODULE_INIT_QAPI);
+    init_guest_agent(ga_state);
+    register_signal_handlers();
+
+    g_main_loop_run(ga_state->main_loop);
+
+    ga_command_state_cleanup_all(ga_state->command_state);
+    unlink(pidfile);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-img-cmds.hx b/qemu-0.15.x/qemu-img-cmds.hx
new file mode 100644
index 0000000..1299e83
--- /dev/null
+++ b/qemu-0.15.x/qemu-img-cmds.hx
@@ -0,0 +1,59 @@
+HXCOMM Use DEFHEADING() to define headings in both help text and texi
+HXCOMM Text between STEXI and ETEXI are copied to texi version and
+HXCOMM discarded from C version
+HXCOMM DEF(command, callback, arg_string) is used to construct
+HXCOMM command structures and help message.
+HXCOMM HXCOMM can be used for comments, discarded from both texi and C
+
+STEXI
+ at table @option
+ETEXI
+
+DEF("check", img_check,
+    "check [-f fmt] filename")
+STEXI
+ at item check [-f @var{fmt}] @var{filename}
+ETEXI
+
+DEF("create", img_create,
+    "create [-f fmt] [-o options] filename [size]")
+STEXI
+ at item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+ETEXI
+
+DEF("commit", img_commit,
+    "commit [-f fmt] [-t cache] filename")
+STEXI
+ at item commit [-f @var{fmt}] @var{filename}
+ETEXI
+
+DEF("convert", img_convert,
+    "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
+STEXI
+ at item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+ETEXI
+
+DEF("info", img_info,
+    "info [-f fmt] filename")
+STEXI
+ at item info [-f @var{fmt}] @var{filename}
+ETEXI
+
+DEF("snapshot", img_snapshot,
+    "snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+STEXI
+ at item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
+ETEXI
+
+DEF("rebase", img_rebase,
+    "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
+STEXI
+ at item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+ETEXI
+
+DEF("resize", img_resize,
+    "resize filename [+ | -]size")
+STEXI
+ at item resize @var{filename} [+ | -]@var{size}
+ at end table
+ETEXI
diff --git a/qemu-0.15.x/qemu-img.c b/qemu-0.15.x/qemu-img.c
new file mode 100644
index 0000000..b205e98
--- /dev/null
+++ b/qemu-0.15.x/qemu-img.c
@@ -0,0 +1,1623 @@
+/*
+ * QEMU disk image utility
+ *
+ * Copyright (c) 2003-2008 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 "qemu-common.h"
+#include "qemu-option.h"
+#include "qemu-error.h"
+#include "osdep.h"
+#include "sysemu.h"
+#include "block_int.h"
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+typedef struct img_cmd_t {
+    const char *name;
+    int (*handler)(int argc, char **argv);
+} img_cmd_t;
+
+/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
+#define BDRV_O_FLAGS BDRV_O_CACHE_WB
+#define BDRV_DEFAULT_CACHE "writeback"
+
+static void format_print(void *opaque, const char *name)
+{
+    printf(" %s", name);
+}
+
+/* Please keep in synch with qemu-img.texi */
+static void help(void)
+{
+    const char *help_msg =
+           "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
+           "usage: qemu-img command [command options]\n"
+           "QEMU disk image utility\n"
+           "\n"
+           "Command syntax:\n"
+#define DEF(option, callback, arg_string)        \
+           "  " arg_string "\n"
+#include "qemu-img-cmds.h"
+#undef DEF
+#undef GEN_DOCS
+           "\n"
+           "Command parameters:\n"
+           "  'filename' is a disk image filename\n"
+           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
+           "  'cache' is the cache mode used to write the output disk image, the valid\n"
+           "    options are: 'none', 'writeback' (default), 'writethrough' and 'unsafe'\n"
+           "  'size' is the disk image size in bytes. Optional suffixes\n"
+           "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
+           "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
+           "  'output_filename' is the destination disk image filename\n"
+           "  'output_fmt' is the destination format\n"
+           "  'options' is a comma separated list of format specific options in a\n"
+           "    name=value format. Use -o ? for an overview of the options supported by the\n"
+           "    used format\n"
+           "  '-c' indicates that target image must be compressed (qcow format only)\n"
+           "  '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
+           "       match exactly. The image doesn't need a working backing file before\n"
+           "       rebasing in this case (useful for renaming the backing file)\n"
+           "  '-h' with or without a command shows this help and lists the supported formats\n"
+           "  '-p' show progress of command (only certain commands)\n"
+           "\n"
+           "Parameters to snapshot subcommand:\n"
+           "  'snapshot' is the name of the snapshot to create, apply or delete\n"
+           "  '-a' applies a snapshot (revert disk to saved state)\n"
+           "  '-c' creates a snapshot\n"
+           "  '-d' deletes a snapshot\n"
+           "  '-l' lists all snapshots in the given image\n";
+
+    printf("%s\nSupported formats:", help_msg);
+    bdrv_iterate_format(format_print, NULL);
+    printf("\n");
+    exit(1);
+}
+
+#if defined(WIN32)
+/* XXX: put correct support for win32 */
+static int read_password(char *buf, int buf_size)
+{
+    int c, i;
+    printf("Password: ");
+    fflush(stdout);
+    i = 0;
+    for(;;) {
+        c = getchar();
+        if (c == '\n')
+            break;
+        if (i < (buf_size - 1))
+            buf[i++] = c;
+    }
+    buf[i] = '\0';
+    return 0;
+}
+
+#else
+
+#include <termios.h>
+
+static struct termios oldtty;
+
+static void term_exit(void)
+{
+    tcsetattr (0, TCSANOW, &oldtty);
+}
+
+static void term_init(void)
+{
+    struct termios tty;
+
+    tcgetattr (0, &tty);
+    oldtty = tty;
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+    tty.c_cflag &= ~(CSIZE|PARENB);
+    tty.c_cflag |= CS8;
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+
+    tcsetattr (0, TCSANOW, &tty);
+
+    atexit(term_exit);
+}
+
+static int read_password(char *buf, int buf_size)
+{
+    uint8_t ch;
+    int i, ret;
+
+    printf("password: ");
+    fflush(stdout);
+    term_init();
+    i = 0;
+    for(;;) {
+        ret = read(0, &ch, 1);
+        if (ret == -1) {
+            if (errno == EAGAIN || errno == EINTR) {
+                continue;
+            } else {
+                ret = -1;
+                break;
+            }
+        } else if (ret == 0) {
+            ret = -1;
+            break;
+        } else {
+            if (ch == '\r') {
+                ret = 0;
+                break;
+            }
+            if (i < (buf_size - 1))
+                buf[i++] = ch;
+        }
+    }
+    term_exit();
+    buf[i] = '\0';
+    printf("\n");
+    return ret;
+}
+#endif
+
+static int set_cache_flag(const char *mode, int *flags)
+{
+    *flags &= ~BDRV_O_CACHE_MASK;
+
+    if (!strcmp(mode, "none") || !strcmp(mode, "off")) {
+        *flags |= BDRV_O_CACHE_WB;
+        *flags |= BDRV_O_NOCACHE;
+    } else if (!strcmp(mode, "writeback")) {
+        *flags |= BDRV_O_CACHE_WB;
+    } else if (!strcmp(mode, "unsafe")) {
+        *flags |= BDRV_O_CACHE_WB;
+        *flags |= BDRV_O_NO_FLUSH;
+    } else if (!strcmp(mode, "writethrough")) {
+        /* this is the default */
+    } else {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int print_block_option_help(const char *filename, const char *fmt)
+{
+    BlockDriver *drv, *proto_drv;
+    QEMUOptionParameter *create_options = NULL;
+
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(fmt);
+    if (!drv) {
+        error_report("Unknown file format '%s'", fmt);
+        return 1;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        error_report("Unknown protocol '%s'", filename);
+        return 1;
+    }
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+    print_option_help(create_options);
+    free_option_parameters(create_options);
+    return 0;
+}
+
+static BlockDriverState *bdrv_new_open(const char *filename,
+                                       const char *fmt,
+                                       int flags)
+{
+    BlockDriverState *bs;
+    BlockDriver *drv;
+    char password[256];
+    int ret;
+
+    bs = bdrv_new("image");
+
+    if (fmt) {
+        drv = bdrv_find_format(fmt);
+        if (!drv) {
+            error_report("Unknown file format '%s'", fmt);
+            goto fail;
+        }
+    } else {
+        drv = NULL;
+    }
+
+    ret = bdrv_open(bs, filename, flags, drv);
+    if (ret < 0) {
+        error_report("Could not open '%s': %s", filename, strerror(-ret));
+        goto fail;
+    }
+
+    if (bdrv_is_encrypted(bs)) {
+        printf("Disk image '%s' is encrypted.\n", filename);
+        if (read_password(password, sizeof(password)) < 0) {
+            error_report("No password given");
+            goto fail;
+        }
+        if (bdrv_set_key(bs, password) < 0) {
+            error_report("invalid password");
+            goto fail;
+        }
+    }
+    return bs;
+fail:
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    return NULL;
+}
+
+static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
+                                 const char *base_filename,
+                                 const char *base_fmt)
+{
+    if (base_filename) {
+        if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
+            error_report("Backing file not supported for file format '%s'",
+                         fmt);
+            return -1;
+        }
+    }
+    if (base_fmt) {
+        if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+            error_report("Backing file format not supported for file "
+                         "format '%s'", fmt);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int img_create(int argc, char **argv)
+{
+    int c, ret = 0;
+    uint64_t img_size = -1;
+    const char *fmt = "raw";
+    const char *base_fmt = NULL;
+    const char *filename;
+    const char *base_filename = NULL;
+    char *options = NULL;
+
+    for(;;) {
+        c = getopt(argc, argv, "F:b:f:he6o:");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'F':
+            base_fmt = optarg;
+            break;
+        case 'b':
+            base_filename = optarg;
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        case 'e':
+            error_report("option -e is deprecated, please use \'-o "
+                  "encryption\' instead!");
+            return 1;
+        case '6':
+            error_report("option -6 is deprecated, please use \'-o "
+                  "compat6\' instead!");
+            return 1;
+        case 'o':
+            options = optarg;
+            break;
+        }
+    }
+
+    /* Get the filename */
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    /* Get image size, if specified */
+    if (optind < argc) {
+        int64_t sval;
+        sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B);
+        if (sval < 0) {
+            error_report("Invalid image size specified! You may use k, M, G or "
+                  "T suffixes for ");
+            error_report("kilobytes, megabytes, gigabytes and terabytes.");
+            ret = -1;
+            goto out;
+        }
+        img_size = (uint64_t)sval;
+    }
+
+    if (options && !strcmp(options, "?")) {
+        ret = print_block_option_help(filename, fmt);
+        goto out;
+    }
+
+    ret = bdrv_img_create(filename, fmt, base_filename, base_fmt,
+                          options, img_size, BDRV_O_FLAGS);
+out:
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * Checks an image for consistency. Exit codes:
+ *
+ * 0 - Check completed, image is good
+ * 1 - Check not completed because of internal errors
+ * 2 - Check completed, image is corrupted
+ * 3 - Check completed, image has leaked clusters, but is good otherwise
+ */
+static int img_check(int argc, char **argv)
+{
+    int c, ret;
+    const char *filename, *fmt;
+    BlockDriverState *bs;
+    BdrvCheckResult result;
+
+    fmt = NULL;
+    for(;;) {
+        c = getopt(argc, argv, "f:h");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);
+    if (!bs) {
+        return 1;
+    }
+    ret = bdrv_check(bs, &result);
+
+    if (ret == -ENOTSUP) {
+        error_report("This image format does not support checks");
+        bdrv_delete(bs);
+        return 1;
+    }
+
+    if (!(result.corruptions || result.leaks || result.check_errors)) {
+        printf("No errors were found on the image.\n");
+    } else {
+        if (result.corruptions) {
+            printf("\n%d errors were found on the image.\n"
+                "Data may be corrupted, or further writes to the image "
+                "may corrupt it.\n",
+                result.corruptions);
+        }
+
+        if (result.leaks) {
+            printf("\n%d leaked clusters were found on the image.\n"
+                "This means waste of disk space, but no harm to data.\n",
+                result.leaks);
+        }
+
+        if (result.check_errors) {
+            printf("\n%d internal errors have occurred during the check.\n",
+                result.check_errors);
+        }
+    }
+
+    bdrv_delete(bs);
+
+    if (ret < 0 || result.check_errors) {
+        printf("\nAn error has occurred during the check: %s\n"
+            "The check is not complete and may have missed error.\n",
+            strerror(-ret));
+        return 1;
+    }
+
+    if (result.corruptions) {
+        return 2;
+    } else if (result.leaks) {
+        return 3;
+    } else {
+        return 0;
+    }
+}
+
+static int img_commit(int argc, char **argv)
+{
+    int c, ret, flags;
+    const char *filename, *fmt, *cache;
+    BlockDriverState *bs;
+
+    fmt = NULL;
+    cache = BDRV_DEFAULT_CACHE;
+    for(;;) {
+        c = getopt(argc, argv, "f:ht:");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        case 't':
+            cache = optarg;
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    flags = BDRV_O_RDWR;
+    ret = set_cache_flag(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
+    bs = bdrv_new_open(filename, fmt, flags);
+    if (!bs) {
+        return 1;
+    }
+    ret = bdrv_commit(bs);
+    switch(ret) {
+    case 0:
+        printf("Image committed.\n");
+        break;
+    case -ENOENT:
+        error_report("No disk inserted");
+        break;
+    case -EACCES:
+        error_report("Image is read-only");
+        break;
+    case -ENOTSUP:
+        error_report("Image is already committed");
+        break;
+    default:
+        error_report("Error while committing image");
+        break;
+    }
+
+    bdrv_delete(bs);
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * Checks whether the sector is not a zero sector.
+ *
+ * Attention! The len must be a multiple of 4 * sizeof(long) due to
+ * restriction of optimizations in this function.
+ */
+static int is_not_zero(const uint8_t *sector, int len)
+{
+    /*
+     * Use long as the biggest available internal data type that fits into the
+     * CPU register and unroll the loop to smooth out the effect of memory
+     * latency.
+     */
+
+    int i;
+    long d0, d1, d2, d3;
+    const long * const data = (const long *) sector;
+
+    len /= sizeof(long);
+
+    for(i = 0; i < len; i += 4) {
+        d0 = data[i + 0];
+        d1 = data[i + 1];
+        d2 = data[i + 2];
+        d3 = data[i + 3];
+
+        if (d0 || d1 || d2 || d3) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Returns true iff the first sector pointed to by 'buf' contains at least
+ * a non-NUL byte.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the first one) that are known to be in the same allocated/unallocated state.
+ */
+static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
+{
+    int v, i;
+
+    if (n <= 0) {
+        *pnum = 0;
+        return 0;
+    }
+    v = is_not_zero(buf, 512);
+    for(i = 1; i < n; i++) {
+        buf += 512;
+        if (v != is_not_zero(buf, 512))
+            break;
+    }
+    *pnum = i;
+    return v;
+}
+
+/*
+ * Compares two buffers sector by sector. Returns 0 if the first sector of both
+ * buffers matches, non-zero otherwise.
+ *
+ * pnum is set to the number of sectors (including and immediately following
+ * the first one) that are known to have the same comparison result
+ */
+static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
+    int *pnum)
+{
+    int res, i;
+
+    if (n <= 0) {
+        *pnum = 0;
+        return 0;
+    }
+
+    res = !!memcmp(buf1, buf2, 512);
+    for(i = 1; i < n; i++) {
+        buf1 += 512;
+        buf2 += 512;
+
+        if (!!memcmp(buf1, buf2, 512) != res) {
+            break;
+        }
+    }
+
+    *pnum = i;
+    return res;
+}
+
+#define IO_BUF_SIZE (2 * 1024 * 1024)
+
+static int img_convert(int argc, char **argv)
+{
+    int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
+    int progress = 0, flags;
+    const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
+    BlockDriver *drv, *proto_drv;
+    BlockDriverState **bs = NULL, *out_bs = NULL;
+    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
+    uint64_t bs_sectors;
+    uint8_t * buf = NULL;
+    const uint8_t *buf1;
+    BlockDriverInfo bdi;
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *out_baseimg_param;
+    char *options = NULL;
+    const char *snapshot_name = NULL;
+    float local_progress;
+
+    fmt = NULL;
+    out_fmt = "raw";
+    cache = "unsafe";
+    out_baseimg = NULL;
+    compress = 0;
+    for(;;) {
+        c = getopt(argc, argv, "f:O:B:s:hce6o:pt:");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        case 'O':
+            out_fmt = optarg;
+            break;
+        case 'B':
+            out_baseimg = optarg;
+            break;
+        case 'c':
+            compress = 1;
+            break;
+        case 'e':
+            error_report("option -e is deprecated, please use \'-o "
+                  "encryption\' instead!");
+            return 1;
+        case '6':
+            error_report("option -6 is deprecated, please use \'-o "
+                  "compat6\' instead!");
+            return 1;
+        case 'o':
+            options = optarg;
+            break;
+        case 's':
+            snapshot_name = optarg;
+            break;
+        case 'p':
+            progress = 1;
+            break;
+        case 't':
+            cache = optarg;
+            break;
+        }
+    }
+
+    bs_n = argc - optind - 1;
+    if (bs_n < 1) {
+        help();
+    }
+
+    out_filename = argv[argc - 1];
+
+    if (options && !strcmp(options, "?")) {
+        ret = print_block_option_help(out_filename, out_fmt);
+        goto out;
+    }
+
+    if (bs_n > 1 && out_baseimg) {
+        error_report("-B makes no sense when concatenating multiple input "
+                     "images");
+        ret = -1;
+        goto out;
+    }
+        
+    qemu_progress_init(progress, 2.0);
+    qemu_progress_print(0, 100);
+
+    bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
+
+    total_sectors = 0;
+    for (bs_i = 0; bs_i < bs_n; bs_i++) {
+        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
+        if (!bs[bs_i]) {
+            error_report("Could not open '%s'", argv[optind + bs_i]);
+            ret = -1;
+            goto out;
+        }
+        bdrv_get_geometry(bs[bs_i], &bs_sectors);
+        total_sectors += bs_sectors;
+    }
+
+    if (snapshot_name != NULL) {
+        if (bs_n > 1) {
+            error_report("No support for concatenating multiple snapshot");
+            ret = -1;
+            goto out;
+        }
+        if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
+            error_report("Failed to load snapshot");
+            ret = -1;
+            goto out;
+        }
+    }
+
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(out_fmt);
+    if (!drv) {
+        error_report("Unknown file format '%s'", out_fmt);
+        ret = -1;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(out_filename);
+    if (!proto_drv) {
+        error_report("Unknown protocol '%s'", out_filename);
+        ret = -1;
+        goto out;
+    }
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+
+    if (options) {
+        param = parse_option_parameters(options, create_options, param);
+        if (param == NULL) {
+            error_report("Invalid options for file format '%s'.", out_fmt);
+            ret = -1;
+            goto out;
+        }
+    } else {
+        param = parse_option_parameters("", create_options, param);
+    }
+
+    set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
+    ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
+    if (ret < 0) {
+        goto out;
+    }
+
+    /* Get backing file name if -o backing_file was used */
+    out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    if (out_baseimg_param) {
+        out_baseimg = out_baseimg_param->value.s;
+    }
+
+    /* Check if compression is supported */
+    if (compress) {
+        QEMUOptionParameter *encryption =
+            get_option_parameter(param, BLOCK_OPT_ENCRYPT);
+
+        if (!drv->bdrv_write_compressed) {
+            error_report("Compression not supported for this file format");
+            ret = -1;
+            goto out;
+        }
+
+        if (encryption && encryption->value.n) {
+            error_report("Compression and encryption not supported at "
+                         "the same time");
+            ret = -1;
+            goto out;
+        }
+    }
+
+    /* Create the new image */
+    ret = bdrv_create(drv, out_filename, param);
+    if (ret < 0) {
+        if (ret == -ENOTSUP) {
+            error_report("Formatting not supported for file format '%s'",
+                         out_fmt);
+        } else if (ret == -EFBIG) {
+            error_report("The image size is too large for file format '%s'",
+                         out_fmt);
+        } else {
+            error_report("%s: error while converting %s: %s",
+                         out_filename, out_fmt, strerror(-ret));
+        }
+        goto out;
+    }
+
+    flags = BDRV_O_RDWR;
+    ret = set_cache_flag(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
+    out_bs = bdrv_new_open(out_filename, out_fmt, flags);
+    if (!out_bs) {
+        ret = -1;
+        goto out;
+    }
+
+    bs_i = 0;
+    bs_offset = 0;
+    bdrv_get_geometry(bs[0], &bs_sectors);
+    buf = qemu_malloc(IO_BUF_SIZE);
+
+    if (compress) {
+        ret = bdrv_get_info(out_bs, &bdi);
+        if (ret < 0) {
+            error_report("could not get block driver info");
+            goto out;
+        }
+        cluster_size = bdi.cluster_size;
+        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
+            error_report("invalid cluster size");
+            ret = -1;
+            goto out;
+        }
+        cluster_sectors = cluster_size >> 9;
+        sector_num = 0;
+
+        nb_sectors = total_sectors;
+        local_progress = (float)100 /
+            (nb_sectors / MIN(nb_sectors, cluster_sectors));
+
+        for(;;) {
+            int64_t bs_num;
+            int remainder;
+            uint8_t *buf2;
+
+            nb_sectors = total_sectors - sector_num;
+            if (nb_sectors <= 0)
+                break;
+            if (nb_sectors >= cluster_sectors)
+                n = cluster_sectors;
+            else
+                n = nb_sectors;
+
+            bs_num = sector_num - bs_offset;
+            assert (bs_num >= 0);
+            remainder = n;
+            buf2 = buf;
+            while (remainder > 0) {
+                int nlow;
+                while (bs_num == bs_sectors) {
+                    bs_i++;
+                    assert (bs_i < bs_n);
+                    bs_offset += bs_sectors;
+                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
+                    bs_num = 0;
+                    /* printf("changing part: sector_num=%" PRId64 ", "
+                       "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
+                       "\n", sector_num, bs_i, bs_offset, bs_sectors); */
+                }
+                assert (bs_num < bs_sectors);
+
+                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
+
+                ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
+                if (ret < 0) {
+                    error_report("error while reading");
+                    goto out;
+                }
+
+                buf2 += nlow * 512;
+                bs_num += nlow;
+
+                remainder -= nlow;
+            }
+            assert (remainder == 0);
+
+            if (n < cluster_sectors) {
+                memset(buf + n * 512, 0, cluster_size - n * 512);
+            }
+            if (is_not_zero(buf, cluster_size)) {
+                ret = bdrv_write_compressed(out_bs, sector_num, buf,
+                                            cluster_sectors);
+                if (ret != 0) {
+                    error_report("error while compressing sector %" PRId64,
+                          sector_num);
+                    goto out;
+                }
+            }
+            sector_num += n;
+            qemu_progress_print(local_progress, 100);
+        }
+        /* signal EOF to align */
+        bdrv_write_compressed(out_bs, 0, NULL, 0);
+    } else {
+        int has_zero_init = bdrv_has_zero_init(out_bs);
+
+        sector_num = 0; // total number of sectors converted so far
+        nb_sectors = total_sectors - sector_num;
+        local_progress = (float)100 /
+            (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
+
+        for(;;) {
+            nb_sectors = total_sectors - sector_num;
+            if (nb_sectors <= 0) {
+                break;
+            }
+            if (nb_sectors >= (IO_BUF_SIZE / 512)) {
+                n = (IO_BUF_SIZE / 512);
+            } else {
+                n = nb_sectors;
+            }
+
+            while (sector_num - bs_offset >= bs_sectors) {
+                bs_i ++;
+                assert (bs_i < bs_n);
+                bs_offset += bs_sectors;
+                bdrv_get_geometry(bs[bs_i], &bs_sectors);
+                /* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "
+                  "bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",
+                   sector_num, bs_i, bs_offset, bs_sectors); */
+            }
+
+            if (n > bs_offset + bs_sectors - sector_num) {
+                n = bs_offset + bs_sectors - sector_num;
+            }
+
+            if (has_zero_init) {
+                /* If the output image is being created as a copy on write image,
+                   assume that sectors which are unallocated in the input image
+                   are present in both the output's and input's base images (no
+                   need to copy them). */
+                if (out_baseimg) {
+                    if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
+                                           n, &n1)) {
+                        sector_num += n1;
+                        continue;
+                    }
+                    /* The next 'n1' sectors are allocated in the input image. Copy
+                       only those as they may be followed by unallocated sectors. */
+                    n = n1;
+                }
+            } else {
+                n1 = n;
+            }
+
+            ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
+            if (ret < 0) {
+                error_report("error while reading");
+                goto out;
+            }
+            /* NOTE: at the same time we convert, we do not write zero
+               sectors to have a chance to compress the image. Ideally, we
+               should add a specific call to have the info to go faster */
+            buf1 = buf;
+            while (n > 0) {
+                /* If the output image is being created as a copy on write image,
+                   copy all sectors even the ones containing only NUL bytes,
+                   because they may differ from the sectors in the base image.
+
+                   If the output is to a host device, we also write out
+                   sectors that are entirely 0, since whatever data was
+                   already there is garbage, not 0s. */
+                if (!has_zero_init || out_baseimg ||
+                    is_allocated_sectors(buf1, n, &n1)) {
+                    ret = bdrv_write(out_bs, sector_num, buf1, n1);
+                    if (ret < 0) {
+                        error_report("error while writing");
+                        goto out;
+                    }
+                }
+                sector_num += n1;
+                n -= n1;
+                buf1 += n1 * 512;
+            }
+            qemu_progress_print(local_progress, 100);
+        }
+    }
+out:
+    qemu_progress_end();
+    free_option_parameters(create_options);
+    free_option_parameters(param);
+    qemu_free(buf);
+    if (out_bs) {
+        bdrv_delete(out_bs);
+    }
+    if (bs) {
+        for (bs_i = 0; bs_i < bs_n; bs_i++) {
+            if (bs[bs_i]) {
+                bdrv_delete(bs[bs_i]);
+            }
+        }
+        qemu_free(bs);
+    }
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+
+static void dump_snapshots(BlockDriverState *bs)
+{
+    QEMUSnapshotInfo *sn_tab, *sn;
+    int nb_sns, i;
+    char buf[256];
+
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns <= 0)
+        return;
+    printf("Snapshot list:\n");
+    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+    for(i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+    }
+    qemu_free(sn_tab);
+}
+
+static int img_info(int argc, char **argv)
+{
+    int c;
+    const char *filename, *fmt;
+    BlockDriverState *bs;
+    char fmt_name[128], size_buf[128], dsize_buf[128];
+    uint64_t total_sectors;
+    int64_t allocated_size;
+    char backing_filename[1024];
+    char backing_filename2[1024];
+    BlockDriverInfo bdi;
+
+    fmt = NULL;
+    for(;;) {
+        c = getopt(argc, argv, "f:h");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
+    if (!bs) {
+        return 1;
+    }
+    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
+    bdrv_get_geometry(bs, &total_sectors);
+    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
+    allocated_size = bdrv_get_allocated_file_size(bs);
+    if (allocated_size < 0) {
+        snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
+    } else {
+        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
+                                allocated_size);
+    }
+    printf("image: %s\n"
+           "file format: %s\n"
+           "virtual size: %s (%" PRId64 " bytes)\n"
+           "disk size: %s\n",
+           filename, fmt_name, size_buf,
+           (total_sectors * 512),
+           dsize_buf);
+    if (bdrv_is_encrypted(bs)) {
+        printf("encrypted: yes\n");
+    }
+    if (bdrv_get_info(bs, &bdi) >= 0) {
+        if (bdi.cluster_size != 0) {
+            printf("cluster_size: %d\n", bdi.cluster_size);
+        }
+    }
+    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
+    if (backing_filename[0] != '\0') {
+        path_combine(backing_filename2, sizeof(backing_filename2),
+                     filename, backing_filename);
+        printf("backing file: %s (actual path: %s)\n",
+               backing_filename,
+               backing_filename2);
+    }
+    dump_snapshots(bs);
+    bdrv_delete(bs);
+    return 0;
+}
+
+#define SNAPSHOT_LIST   1
+#define SNAPSHOT_CREATE 2
+#define SNAPSHOT_APPLY  3
+#define SNAPSHOT_DELETE 4
+
+static int img_snapshot(int argc, char **argv)
+{
+    BlockDriverState *bs;
+    QEMUSnapshotInfo sn;
+    char *filename, *snapshot_name = NULL;
+    int c, ret = 0, bdrv_oflags;
+    int action = 0;
+    qemu_timeval tv;
+
+    bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
+    /* Parse commandline parameters */
+    for(;;) {
+        c = getopt(argc, argv, "la:c:d:h");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            return 0;
+        case 'l':
+            if (action) {
+                help();
+                return 0;
+            }
+            action = SNAPSHOT_LIST;
+            bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
+            break;
+        case 'a':
+            if (action) {
+                help();
+                return 0;
+            }
+            action = SNAPSHOT_APPLY;
+            snapshot_name = optarg;
+            break;
+        case 'c':
+            if (action) {
+                help();
+                return 0;
+            }
+            action = SNAPSHOT_CREATE;
+            snapshot_name = optarg;
+            break;
+        case 'd':
+            if (action) {
+                help();
+                return 0;
+            }
+            action = SNAPSHOT_DELETE;
+            snapshot_name = optarg;
+            break;
+        }
+    }
+
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    /* Open the image */
+    bs = bdrv_new_open(filename, NULL, bdrv_oflags);
+    if (!bs) {
+        return 1;
+    }
+
+    /* Perform the requested action */
+    switch(action) {
+    case SNAPSHOT_LIST:
+        dump_snapshots(bs);
+        break;
+
+    case SNAPSHOT_CREATE:
+        memset(&sn, 0, sizeof(sn));
+        pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
+
+        qemu_gettimeofday(&tv);
+        sn.date_sec = tv.tv_sec;
+        sn.date_nsec = tv.tv_usec * 1000;
+
+        ret = bdrv_snapshot_create(bs, &sn);
+        if (ret) {
+            error_report("Could not create snapshot '%s': %d (%s)",
+                snapshot_name, ret, strerror(-ret));
+        }
+        break;
+
+    case SNAPSHOT_APPLY:
+        ret = bdrv_snapshot_goto(bs, snapshot_name);
+        if (ret) {
+            error_report("Could not apply snapshot '%s': %d (%s)",
+                snapshot_name, ret, strerror(-ret));
+        }
+        break;
+
+    case SNAPSHOT_DELETE:
+        ret = bdrv_snapshot_delete(bs, snapshot_name);
+        if (ret) {
+            error_report("Could not delete snapshot '%s': %d (%s)",
+                snapshot_name, ret, strerror(-ret));
+        }
+        break;
+    }
+
+    /* Cleanup */
+    bdrv_delete(bs);
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+static int img_rebase(int argc, char **argv)
+{
+    BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
+    BlockDriver *old_backing_drv, *new_backing_drv;
+    char *filename;
+    const char *fmt, *cache, *out_basefmt, *out_baseimg;
+    int c, flags, ret;
+    int unsafe = 0;
+    int progress = 0;
+
+    /* Parse commandline parameters */
+    fmt = NULL;
+    cache = BDRV_DEFAULT_CACHE;
+    out_baseimg = NULL;
+    out_basefmt = NULL;
+    for(;;) {
+        c = getopt(argc, argv, "uhf:F:b:pt:");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            return 0;
+        case 'f':
+            fmt = optarg;
+            break;
+        case 'F':
+            out_basefmt = optarg;
+            break;
+        case 'b':
+            out_baseimg = optarg;
+            break;
+        case 'u':
+            unsafe = 1;
+            break;
+        case 'p':
+            progress = 1;
+            break;
+        case 't':
+            cache = optarg;
+            break;
+        }
+    }
+
+    if ((optind >= argc) || (!unsafe && !out_baseimg)) {
+        help();
+    }
+    filename = argv[optind++];
+
+    qemu_progress_init(progress, 2.0);
+    qemu_progress_print(0, 100);
+
+    flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
+    ret = set_cache_flag(cache, &flags);
+    if (ret < 0) {
+        error_report("Invalid cache option: %s", cache);
+        return -1;
+    }
+
+    /*
+     * Open the images.
+     *
+     * Ignore the old backing file for unsafe rebase in case we want to correct
+     * the reference to a renamed or moved backing file.
+     */
+    bs = bdrv_new_open(filename, fmt, flags);
+    if (!bs) {
+        return 1;
+    }
+
+    /* Find the right drivers for the backing files */
+    old_backing_drv = NULL;
+    new_backing_drv = NULL;
+
+    if (!unsafe && bs->backing_format[0] != '\0') {
+        old_backing_drv = bdrv_find_format(bs->backing_format);
+        if (old_backing_drv == NULL) {
+            error_report("Invalid format name: '%s'", bs->backing_format);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    if (out_basefmt != NULL) {
+        new_backing_drv = bdrv_find_format(out_basefmt);
+        if (new_backing_drv == NULL) {
+            error_report("Invalid format name: '%s'", out_basefmt);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    /* For safe rebasing we need to compare old and new backing file */
+    if (unsafe) {
+        /* Make the compiler happy */
+        bs_old_backing = NULL;
+        bs_new_backing = NULL;
+    } else {
+        char backing_name[1024];
+
+        bs_old_backing = bdrv_new("old_backing");
+        bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
+        ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,
+                        old_backing_drv);
+        if (ret) {
+            error_report("Could not open old backing file '%s'", backing_name);
+            goto out;
+        }
+
+        bs_new_backing = bdrv_new("new_backing");
+        ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,
+                        new_backing_drv);
+        if (ret) {
+            error_report("Could not open new backing file '%s'", out_baseimg);
+            goto out;
+        }
+    }
+
+    /*
+     * Check each unallocated cluster in the COW file. If it is unallocated,
+     * accesses go to the backing file. We must therefore compare this cluster
+     * in the old and new backing file, and if they differ we need to copy it
+     * from the old backing file into the COW file.
+     *
+     * If qemu-img crashes during this step, no harm is done. The content of
+     * the image is the same as the original one at any time.
+     */
+    if (!unsafe) {
+        uint64_t num_sectors;
+        uint64_t sector;
+        int n;
+        uint8_t * buf_old;
+        uint8_t * buf_new;
+        float local_progress;
+
+        buf_old = qemu_malloc(IO_BUF_SIZE);
+        buf_new = qemu_malloc(IO_BUF_SIZE);
+
+        bdrv_get_geometry(bs, &num_sectors);
+
+        local_progress = (float)100 /
+            (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
+        for (sector = 0; sector < num_sectors; sector += n) {
+
+            /* How many sectors can we handle with the next read? */
+            if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
+                n = (IO_BUF_SIZE / 512);
+            } else {
+                n = num_sectors - sector;
+            }
+
+            /* If the cluster is allocated, we don't need to take action */
+            ret = bdrv_is_allocated(bs, sector, n, &n);
+            if (ret) {
+                continue;
+            }
+
+            /* Read old and new backing file */
+            ret = bdrv_read(bs_old_backing, sector, buf_old, n);
+            if (ret < 0) {
+                error_report("error while reading from old backing file");
+                goto out;
+            }
+            ret = bdrv_read(bs_new_backing, sector, buf_new, n);
+            if (ret < 0) {
+                error_report("error while reading from new backing file");
+                goto out;
+            }
+
+            /* If they differ, we need to write to the COW file */
+            uint64_t written = 0;
+
+            while (written < n) {
+                int pnum;
+
+                if (compare_sectors(buf_old + written * 512,
+                    buf_new + written * 512, n - written, &pnum))
+                {
+                    ret = bdrv_write(bs, sector + written,
+                        buf_old + written * 512, pnum);
+                    if (ret < 0) {
+                        error_report("Error while writing to COW image: %s",
+                            strerror(-ret));
+                        goto out;
+                    }
+                }
+
+                written += pnum;
+            }
+            qemu_progress_print(local_progress, 100);
+        }
+
+        qemu_free(buf_old);
+        qemu_free(buf_new);
+    }
+
+    /*
+     * Change the backing file. All clusters that are different from the old
+     * backing file are overwritten in the COW file now, so the visible content
+     * doesn't change when we switch the backing file.
+     */
+    ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
+    if (ret == -ENOSPC) {
+        error_report("Could not change the backing file to '%s': No "
+                     "space left in the file header", out_baseimg);
+    } else if (ret < 0) {
+        error_report("Could not change the backing file to '%s': %s",
+            out_baseimg, strerror(-ret));
+    }
+
+    qemu_progress_print(100, 0);
+    /*
+     * TODO At this point it is possible to check if any clusters that are
+     * allocated in the COW file are the same in the backing file. If so, they
+     * could be dropped from the COW file. Don't do this before switching the
+     * backing file, in case of a crash this would lead to corruption.
+     */
+out:
+    qemu_progress_end();
+    /* Cleanup */
+    if (!unsafe) {
+        if (bs_old_backing != NULL) {
+            bdrv_delete(bs_old_backing);
+        }
+        if (bs_new_backing != NULL) {
+            bdrv_delete(bs_new_backing);
+        }
+    }
+
+    bdrv_delete(bs);
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+static int img_resize(int argc, char **argv)
+{
+    int c, ret, relative;
+    const char *filename, *fmt, *size;
+    int64_t n, total_size;
+    BlockDriverState *bs = NULL;
+    QEMUOptionParameter *param;
+    QEMUOptionParameter resize_options[] = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        { NULL }
+    };
+
+    /* Remove size from argv manually so that negative numbers are not treated
+     * as options by getopt. */
+    if (argc < 3) {
+        help();
+        return 1;
+    }
+
+    size = argv[--argc];
+
+    /* Parse getopt arguments */
+    fmt = NULL;
+    for(;;) {
+        c = getopt(argc, argv, "f:h");
+        if (c == -1) {
+            break;
+        }
+        switch(c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    /* Choose grow, shrink, or absolute resize mode */
+    switch (size[0]) {
+    case '+':
+        relative = 1;
+        size++;
+        break;
+    case '-':
+        relative = -1;
+        size++;
+        break;
+    default:
+        relative = 0;
+        break;
+    }
+
+    /* Parse size */
+    param = parse_option_parameters("", resize_options, NULL);
+    if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
+        /* Error message already printed when size parsing fails */
+        ret = -1;
+        goto out;
+    }
+    n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
+    free_option_parameters(param);
+
+    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
+    if (!bs) {
+        ret = -1;
+        goto out;
+    }
+
+    if (relative) {
+        total_size = bdrv_getlength(bs) + n * relative;
+    } else {
+        total_size = n;
+    }
+    if (total_size <= 0) {
+        error_report("New image size must be positive");
+        ret = -1;
+        goto out;
+    }
+
+    ret = bdrv_truncate(bs, total_size);
+    switch (ret) {
+    case 0:
+        printf("Image resized.\n");
+        break;
+    case -ENOTSUP:
+        error_report("This image format does not support resize");
+        break;
+    case -EACCES:
+        error_report("Image is read-only");
+        break;
+    default:
+        error_report("Error resizing image (%d)", -ret);
+        break;
+    }
+out:
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
+static const img_cmd_t img_cmds[] = {
+#define DEF(option, callback, arg_string)        \
+    { option, callback },
+#include "qemu-img-cmds.h"
+#undef DEF
+#undef GEN_DOCS
+    { NULL, NULL, },
+};
+
+int main(int argc, char **argv)
+{
+    const img_cmd_t *cmd;
+    const char *cmdname;
+
+    error_set_progname(argv[0]);
+
+    bdrv_init();
+    if (argc < 2)
+        help();
+    cmdname = argv[1];
+    argc--; argv++;
+
+    /* find the command */
+    for(cmd = img_cmds; cmd->name != NULL; cmd++) {
+        if (!strcmp(cmdname, cmd->name)) {
+            return cmd->handler(argc, argv);
+        }
+    }
+
+    /* not found */
+    help();
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-img.texi b/qemu-0.15.x/qemu-img.texi
new file mode 100644
index 0000000..495a1b6
--- /dev/null
+++ b/qemu-0.15.x/qemu-img.texi
@@ -0,0 +1,262 @@
+ at example
+ at c man begin SYNOPSIS
+usage: qemu-img command [command options]
+ at c man end
+ at end example
+
+ at c man begin OPTIONS
+
+The following commands are supported:
+
+ at include qemu-img-cmds.texi
+
+Command parameters:
+ at table @var
+ at item filename
+ is a disk image filename
+ at item fmt
+is the disk image format. It is guessed automatically in most cases. See below
+for a description of the supported disk formats.
+
+ at item size
+is the disk image size in bytes. Optional suffixes @code{k} or @code{K}
+(kilobyte, 1024) @code{M} (megabyte, 1024k) and @code{G} (gigabyte, 1024M)
+and T (terabyte, 1024G) are supported.  @code{b} is ignored.
+
+ at item output_filename
+is the destination disk image filename
+
+ at item output_fmt
+ is the destination format
+ at item options
+is a comma separated list of format specific options in a
+name=value format. Use @code{-o ?} for an overview of the options supported
+by the used format or see the format descriptions below for details.
+
+
+ at item -c
+indicates that target image must be compressed (qcow format only)
+ at item -h
+with or without a command shows help and lists the supported formats
+ at item -p
+display progress bar (convert and rebase commands only)
+ at end table
+
+Parameters to snapshot subcommand:
+
+ at table @option
+
+ at item snapshot
+is the name of the snapshot to create, apply or delete
+ at item -a
+applies a snapshot (revert disk to saved state)
+ at item -c
+creates a snapshot
+ at item -d
+deletes a snapshot
+ at item -l
+lists all snapshots in the given image
+ at end table
+
+Command description:
+
+ at table @option
+ at item check [-f @var{fmt}] @var{filename}
+
+Perform a consistency check on the disk image @var{filename}.
+
+Only the formats @code{qcow2}, @code{qed} and @code{vdi} support
+consistency checks.
+
+ at item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+
+Create the new disk image @var{filename} of size @var{size} and format
+ at var{fmt}. Depending on the file format, you can add one or more @var{options}
+that enable additional features of this format.
+
+If the option @var{backing_file} is specified, then the image will record
+only the differences from @var{backing_file}. No size needs to be specified in
+this case. @var{backing_file} will never be modified unless you use the
+ at code{commit} monitor command (or qemu-img commit).
+
+The size can also be specified using the @var{size} option with @code{-o},
+it doesn't need to be specified separately in this case.
+
+ at item commit [-f @var{fmt}] @var{filename}
+
+Commit the changes recorded in @var{filename} in its base image.
+
+ at item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+
+Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
+using format @var{output_fmt}. It can be optionally compressed (@code{-c}
+option) or use any format specific options like encryption (@code{-o} option).
+
+Only the formats @code{qcow} and @code{qcow2} support compression. The
+compression is read-only. It means that if a compressed sector is
+rewritten, then it is rewritten as uncompressed data.
+
+Image conversion is also useful to get smaller image when using a
+growable format such as @code{qcow} or @code{cow}: the empty sectors
+are detected and suppressed from the destination image.
+
+You can use the @var{backing_file} option to force the output image to be
+created as a copy on write image of the specified base image; the
+ at var{backing_file} should have the same content as the input's base image,
+however the path, image format, etc may differ.
+
+ at item info [-f @var{fmt}] @var{filename}
+
+Give information about the disk image @var{filename}. Use it in
+particular to know the size reserved on disk which can be different
+from the displayed size. If VM snapshots are stored in the disk image,
+they are displayed too.
+
+ at item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename}
+
+List, apply, create or delete snapshots in image @var{filename}.
+
+ at item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+
+Changes the backing file of an image. Only the formats @code{qcow2} and
+ at code{qed} support changing the backing file.
+
+The backing file is changed to @var{backing_file} and (if the image format of
+ at var{filename} supports this) the backing file format is changed to
+ at var{backing_fmt}.
+
+There are two different modes in which @code{rebase} can operate:
+ at table @option
+ at item Safe mode
+This is the default mode and performs a real rebase operation. The new backing
+file may differ from the old one and qemu-img rebase will take care of keeping
+the guest-visible content of @var{filename} unchanged.
+
+In order to achieve this, any clusters that differ between @var{backing_file}
+and the old backing file of @var{filename} are merged into @var{filename}
+before actually changing the backing file.
+
+Note that the safe mode is an expensive operation, comparable to converting
+an image. It only works if the old backing file still exists.
+
+ at item Unsafe mode
+qemu-img uses the unsafe mode if @code{-u} is specified. In this mode, only the
+backing file name and format of @var{filename} is changed without any checks
+on the file contents. The user must take care of specifying the correct new
+backing file, or the guest-visible content of the image will be corrupted.
+
+This mode is useful for renaming or moving the backing file to somewhere else.
+It can be used without an accessible old backing file, i.e. you can use it to
+fix an image whose backing file has already been moved/renamed.
+ at end table
+
+ at item resize @var{filename} [+ | -]@var{size}
+
+Change the disk image as if it had been created with @var{size}.
+
+Before using this command to shrink a disk image, you MUST use file system and
+partitioning tools inside the VM to reduce allocated file systems and partition
+sizes accordingly.  Failure to do so will result in data loss!
+
+After using this command to grow a disk image, you must use file system and
+partitioning tools inside the VM to actually begin using the new space on the
+device.
+ at end table
+
+Supported image file formats:
+
+ at table @option
+ at item raw
+
+Raw disk image format (default). This format has the advantage of
+being simple and easily exportable to all other emulators. If your
+file system supports @emph{holes} (for example in ext2 or ext3 on
+Linux or NTFS on Windows), then only the written sectors will reserve
+space. Use @code{qemu-img info} to know the real size used by the
+image or @code{ls -ls} on Unix/Linux.
+
+ at item qcow2
+QEMU image format, the most versatile format. Use it to have smaller
+images (useful if your filesystem does not supports holes, for example
+on Windows), optional AES encryption, zlib based compression and
+support of multiple VM snapshots.
+
+Supported options:
+ at table @code
+ at item backing_file
+File name of a base image (see @option{create} subcommand)
+ at item backing_fmt
+Image format of the base image
+ at item encryption
+If this option is set to @code{on}, the image is encrypted.
+
+Encryption uses the AES format which is very secure (128 bit keys). Use
+a long password (16 characters) to get maximum protection.
+
+ at item cluster_size
+Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster
+sizes can improve the image file size whereas larger cluster sizes generally
+provide better performance.
+
+ at item preallocation
+Preallocation mode (allowed values: off, metadata). An image with preallocated
+metadata is initially larger but can improve performance when the image needs
+to grow.
+
+ at end table
+
+
+ at item qcow
+Old QEMU image format. Left for compatibility.
+
+Supported options:
+ at table @code
+ at item backing_file
+File name of a base image (see @option{create} subcommand)
+ at item encryption
+If this option is set to @code{on}, the image is encrypted.
+ at end table
+
+ at item cow
+User Mode Linux Copy On Write image format. Used to be the only growable
+image format in QEMU. It is supported only for compatibility with
+previous versions. It does not work on win32.
+ at item vdi
+VirtualBox 1.1 compatible image format.
+ at item vmdk
+VMware 3 and 4 compatible image format.
+
+Supported options:
+ at table @code
+ at item backing_fmt
+Image format of the base image
+ at item compat6
+Create a VMDK version 6 image (instead of version 4)
+ at end table
+
+ at item vpc
+VirtualPC compatible image format (VHD).
+
+ at item cloop
+Linux Compressed Loop image, useful only to reuse directly compressed
+CD-ROM images present for example in the Knoppix CD-ROMs.
+ at end table
+
+
+ at c man end
+
+ at ignore
+
+ at setfilename qemu-img
+ at settitle QEMU disk image utility
+
+ at c man begin SEEALSO
+The HTML documentation of QEMU for more precise information and Linux
+user mode emulator invocation.
+ at c man end
+
+ at c man begin AUTHOR
+Fabrice Bellard
+ at c man end
+
+ at end ignore
diff --git a/qemu-0.15.x/qemu-io.c b/qemu-0.15.x/qemu-io.c
new file mode 100644
index 0000000..a553d0c
--- /dev/null
+++ b/qemu-0.15.x/qemu-io.c
@@ -0,0 +1,1840 @@
+/*
+ * Command line utility to exercise the QEMU I/O path.
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <libgen.h>
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "cmd.h"
+
+#define VERSION	"0.0.1"
+
+#define CMD_NOFILE_OK   0x01
+
+char *progname;
+static BlockDriverState *bs;
+
+static int misalign;
+
+/*
+ * Parse the pattern argument to various sub-commands.
+ *
+ * Because the pattern is used as an argument to memset it must evaluate
+ * to an unsigned integer that fits into a single byte.
+ */
+static int parse_pattern(const char *arg)
+{
+    char *endptr = NULL;
+    long pattern;
+
+    pattern = strtol(arg, &endptr, 0);
+    if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
+        printf("%s is not a valid pattern byte\n", arg);
+        return -1;
+    }
+
+    return pattern;
+}
+
+/*
+ * Memory allocation helpers.
+ *
+ * Make sure memory is aligned by default, or purposefully misaligned if
+ * that is specified on the command line.
+ */
+
+#define MISALIGN_OFFSET     16
+static void *qemu_io_alloc(size_t len, int pattern)
+{
+    void *buf;
+
+    if (misalign) {
+        len += MISALIGN_OFFSET;
+    }
+    buf = qemu_blockalign(bs, len);
+    memset(buf, pattern, len);
+    if (misalign) {
+        buf += MISALIGN_OFFSET;
+    }
+    return buf;
+}
+
+static void qemu_io_free(void *p)
+{
+    if (misalign) {
+        p -= MISALIGN_OFFSET;
+    }
+    qemu_vfree(p);
+}
+
+static void dump_buffer(const void *buffer, int64_t offset, int len)
+{
+    int i, j;
+    const uint8_t *p;
+
+    for (i = 0, p = buffer; i < len; i += 16) {
+        const uint8_t *s = p;
+
+        printf("%08" PRIx64 ":  ", offset + i);
+        for (j = 0; j < 16 && i + j < len; j++, p++) {
+            printf("%02x ", *p);
+        }
+        printf(" ");
+        for (j = 0; j < 16 && i + j < len; j++, s++) {
+            if (isalnum(*s)) {
+                printf("%c", *s);
+            } else {
+                printf(".");
+            }
+        }
+        printf("\n");
+    }
+}
+
+static void print_report(const char *op, struct timeval *t, int64_t offset,
+                         int count, int total, int cnt, int Cflag)
+{
+    char s1[64], s2[64], ts[64];
+
+    timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+    if (!Cflag) {
+        cvtstr((double)total, s1, sizeof(s1));
+        cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+        printf("%s %d/%d bytes at offset %" PRId64 "\n",
+               op, total, count, offset);
+        printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+               s1, cnt, ts, s2, tdiv((double)cnt, *t));
+    } else {/* bytes,ops,time,bytes/sec,ops/sec */
+        printf("%d,%d,%s,%.3f,%.3f\n",
+            total, cnt, ts,
+            tdiv((double)total, *t),
+            tdiv((double)cnt, *t));
+    }
+}
+
+/*
+ * Parse multiple length statements for vectored I/O, and construct an I/O
+ * vector matching it.
+ */
+static void *
+create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
+{
+    size_t *sizes = calloc(nr_iov, sizeof(size_t));
+    size_t count = 0;
+    void *buf = NULL;
+    void *p;
+    int i;
+
+    for (i = 0; i < nr_iov; i++) {
+        char *arg = argv[i];
+        int64_t len;
+
+        len = cvtnum(arg);
+        if (len < 0) {
+            printf("non-numeric length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        /* should be SIZE_T_MAX, but that doesn't exist */
+        if (len > INT_MAX) {
+            printf("too large length argument -- %s\n", arg);
+            goto fail;
+        }
+
+        if (len & 0x1ff) {
+            printf("length argument %" PRId64
+                   " is not sector aligned\n", len);
+            goto fail;
+        }
+
+        sizes[i] = len;
+        count += len;
+    }
+
+    qemu_iovec_init(qiov, nr_iov);
+
+    buf = p = qemu_io_alloc(count, pattern);
+
+    for (i = 0; i < nr_iov; i++) {
+        qemu_iovec_add(qiov, p, sizes[i]);
+        p += sizes[i];
+    }
+
+fail:
+    free(sizes);
+    return buf;
+}
+
+static int do_read(char *buf, int64_t offset, int count, int *total)
+{
+    int ret;
+
+    ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
+}
+
+static int do_write(char *buf, int64_t offset, int count, int *total)
+{
+    int ret;
+
+    ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    if (ret < 0) {
+        return ret;
+    }
+    *total = count;
+    return 1;
+}
+
+static int do_pread(char *buf, int64_t offset, int count, int *total)
+{
+    *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
+}
+
+static int do_pwrite(char *buf, int64_t offset, int count, int *total)
+{
+    *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
+}
+
+static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
+{
+    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
+}
+
+static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
+{
+    *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+    if (*total < 0) {
+        return *total;
+    }
+    return 1;
+}
+
+#define NOT_DONE 0x7fffffff
+static void aio_rw_done(void *opaque, int ret)
+{
+    *(int *)opaque = ret;
+}
+
+static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
+
+    acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+                         aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
+}
+
+static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+    BlockDriverAIOCB *acb;
+    int async_ret = NOT_DONE;
+
+    acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+                          aio_rw_done, &async_ret);
+    if (!acb) {
+        return -EIO;
+    }
+
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+
+    *total = qiov->size;
+    return async_ret < 0 ? async_ret : 1;
+}
+
+struct multiwrite_async_ret {
+    int num_done;
+    int error;
+};
+
+static void multiwrite_cb(void *opaque, int ret)
+{
+    struct multiwrite_async_ret *async_ret = opaque;
+
+    async_ret->num_done++;
+    if (ret < 0) {
+        async_ret->error = ret;
+    }
+}
+
+static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
+{
+    int i, ret;
+    struct multiwrite_async_ret async_ret = {
+        .num_done = 0,
+        .error = 0,
+    };
+
+    *total = 0;
+    for (i = 0; i < num_reqs; i++) {
+        reqs[i].cb = multiwrite_cb;
+        reqs[i].opaque = &async_ret;
+        *total += reqs[i].qiov->size;
+    }
+
+    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    while (async_ret.num_done < num_reqs) {
+        qemu_aio_wait();
+    }
+
+    return async_ret.error < 0 ? async_ret.error : 1;
+}
+
+static void read_help(void)
+{
+    printf(
+"\n"
+" reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" -b, -- read from the VM state rather than the virtual disk\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -l, -- length for pattern verification (only with -P)\n"
+" -p, -- use bdrv_pread to read the file\n"
+" -P, -- use a pattern to verify read data\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+" -s, -- start offset for pattern verification (only with -P)\n"
+" -v, -- dump buffer to standard output\n"
+"\n");
+}
+
+static int read_f(int argc, char **argv);
+
+static const cmdinfo_t read_cmd = {
+    .name       = "read",
+    .altname    = "r",
+    .cfunc      = read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = read_help,
+};
+
+static int read_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+    int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0, pattern_offset = 0, pattern_count = 0;
+
+    while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'l':
+            lflag = 1;
+            pattern_count = cvtnum(optarg);
+            if (pattern_count < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 's':
+            sflag = 1;
+            pattern_offset = cvtnum(optarg);
+            if (pattern_offset < 0) {
+                printf("non-numeric length argument -- %s\n", optarg);
+                return 0;
+            }
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&read_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&read_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    if (!Pflag && (lflag || sflag)) {
+        return command_usage(&read_cmd);
+    }
+
+    if (!lflag) {
+        pattern_count = count - pattern_offset;
+    }
+
+    if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
+        printf("pattern verfication range exceeds end of read data\n");
+        return 0;
+    }
+
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, 0xab);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pread(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_load_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_read(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("read failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(pattern_count);
+        memset(cmp_buf, pattern, pattern_count);
+        if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %d bytes\n",
+                   offset + pattern_offset, pattern_count);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, count);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, count, total, cnt, Cflag);
+
+out:
+    qemu_io_free(buf);
+
+    return 0;
+}
+
+static void readv_help(void)
+{
+    printf(
+"\n"
+" reads a range of bytes from the given offset into multiple buffers\n"
+"\n"
+" Example:\n"
+" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" Uses multiple iovec buffers if more than one byte range is specified.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -P, -- use a pattern to verify read data\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int readv_f(int argc, char **argv);
+
+static const cmdinfo_t readv_cmd = {
+    .name       = "readv",
+    .cfunc      = readv_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "reads a number of bytes at a specified offset",
+    .help       = readv_help,
+};
+
+static int readv_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0, vflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    QEMUIOVector qiov;
+    int pattern = 0;
+    int Pflag = 0;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'P':
+            Pflag = 1;
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'v':
+            vflag = 1;
+            break;
+        default:
+            return command_usage(&readv_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&readv_cmd);
+    }
+
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_readv(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("readv failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (Pflag) {
+        void *cmp_buf = malloc(qiov.size);
+        memset(cmp_buf, pattern, qiov.size);
+        if (memcmp(buf, cmp_buf, qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", offset, qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    if (vflag) {
+        dump_buffer(buf, offset, qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+
+out:
+    qemu_io_free(buf);
+    return 0;
+}
+
+static void write_help(void)
+{
+    printf(
+"\n"
+" writes a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -b, -- write to the VM state rather than the virtual disk\n"
+" -p, -- use bdrv_pwrite to write the file\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int write_f(int argc, char **argv);
+
+static const cmdinfo_t write_cmd = {
+    .name       = "write",
+    .altname    = "w",
+    .cfunc      = write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-abCpq] [-P pattern ] off len",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = write_help,
+};
+
+static int write_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    int count;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int pattern = 0xcd;
+
+    while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
+        switch (c) {
+        case 'b':
+            bflag = 1;
+            break;
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'p':
+            pflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&write_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&write_cmd);
+    }
+
+    if (bflag && pflag) {
+        printf("-b and -p cannot be specified at the same time\n");
+        return 0;
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    if (!pflag) {
+        if (offset & 0x1ff) {
+            printf("offset %" PRId64 " is not sector aligned\n",
+                   offset);
+            return 0;
+        }
+
+        if (count & 0x1ff) {
+            printf("count %d is not sector aligned\n",
+                   count);
+            return 0;
+        }
+    }
+
+    buf = qemu_io_alloc(count, pattern);
+
+    gettimeofday(&t1, NULL);
+    if (pflag) {
+        cnt = do_pwrite(buf, offset, count, &total);
+    } else if (bflag) {
+        cnt = do_save_vmstate(buf, offset, count, &total);
+    } else {
+        cnt = do_write(buf, offset, count, &total);
+    }
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("write failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+
+out:
+    qemu_io_free(buf);
+
+    return 0;
+}
+
+static void
+writev_help(void)
+{
+    printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int writev_f(int argc, char **argv);
+
+static const cmdinfo_t writev_cmd = {
+    .name       = "writev",
+    .cfunc      = writev_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "writes a number of bytes at a specified offset",
+    .help       = writev_help,
+};
+
+static int writev_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char *buf;
+    int64_t offset;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int pattern = 0xcd;
+    QEMUIOVector qiov;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+    optind++;
+
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_writev(&qiov, offset, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("writev failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+out:
+    qemu_io_free(buf);
+    return 0;
+}
+
+static void multiwrite_help(void)
+{
+    printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers,\n"
+" in a batch of requests that may be merged by qemu\n"
+"\n"
+" Example:\n"
+" 'multiwrite 512 1k 1k ; 4k 1k' \n"
+"  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
+" by one for each request contained in the multiwrite command.\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int multiwrite_f(int argc, char **argv);
+
+static const cmdinfo_t multiwrite_cmd = {
+    .name       = "multiwrite",
+    .cfunc      = multiwrite_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
+    .oneline    = "issues multiple write requests at once",
+    .help       = multiwrite_help,
+};
+
+static int multiwrite_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, cnt;
+    char **buf;
+    int64_t offset, first_offset = 0;
+    /* Some compilers get confused and warn if this is not initialized.  */
+    int total = 0;
+    int nr_iov;
+    int nr_reqs;
+    int pattern = 0xcd;
+    QEMUIOVector *qiovs;
+    int i;
+    BlockRequest *reqs;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            return command_usage(&writev_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        return command_usage(&writev_cmd);
+    }
+
+    nr_reqs = 1;
+    for (i = optind; i < argc; i++) {
+        if (!strcmp(argv[i], ";")) {
+            nr_reqs++;
+        }
+    }
+
+    reqs = qemu_malloc(nr_reqs * sizeof(*reqs));
+    buf = qemu_malloc(nr_reqs * sizeof(*buf));
+    qiovs = qemu_malloc(nr_reqs * sizeof(*qiovs));
+
+    for (i = 0; i < nr_reqs; i++) {
+        int j;
+
+        /* Read the offset of the request */
+        offset = cvtnum(argv[optind]);
+        if (offset < 0) {
+            printf("non-numeric offset argument -- %s\n", argv[optind]);
+            return 0;
+        }
+        optind++;
+
+        if (offset & 0x1ff) {
+            printf("offset %lld is not sector aligned\n",
+                   (long long)offset);
+            return 0;
+        }
+
+        if (i == 0) {
+            first_offset = offset;
+        }
+
+        /* Read lengths for qiov entries */
+        for (j = optind; j < argc; j++) {
+            if (!strcmp(argv[j], ";")) {
+                break;
+            }
+        }
+
+        nr_iov = j - optind;
+
+        /* Build request */
+        reqs[i].qiov = &qiovs[i];
+        buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern);
+        reqs[i].sector = offset >> 9;
+        reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
+
+        optind = j + 1;
+
+        offset += reqs[i].qiov->size;
+        pattern++;
+    }
+
+    gettimeofday(&t1, NULL);
+    cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
+    gettimeofday(&t2, NULL);
+
+    if (cnt < 0) {
+        printf("aio_multiwrite failed: %s\n", strerror(-cnt));
+        goto out;
+    }
+
+    if (qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, t1);
+    print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
+out:
+    for (i = 0; i < nr_reqs; i++) {
+        qemu_io_free(buf[i]);
+        qemu_iovec_destroy(&qiovs[i]);
+    }
+    qemu_free(buf);
+    qemu_free(reqs);
+    qemu_free(qiovs);
+    return 0;
+}
+
+struct aio_ctx {
+    QEMUIOVector qiov;
+    int64_t offset;
+    char *buf;
+    int qflag;
+    int vflag;
+    int Cflag;
+    int Pflag;
+    int pattern;
+    struct timeval t1;
+};
+
+static void aio_write_done(void *opaque, int ret)
+{
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
+
+    gettimeofday(&t2, NULL);
+
+
+    if (ret < 0) {
+        printf("aio_write failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
+out:
+    qemu_io_free(ctx->buf);
+    free(ctx);
+}
+
+static void aio_read_done(void *opaque, int ret)
+{
+    struct aio_ctx *ctx = opaque;
+    struct timeval t2;
+
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("readv failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    if (ctx->Pflag) {
+        void *cmp_buf = malloc(ctx->qiov.size);
+
+        memset(cmp_buf, ctx->pattern, ctx->qiov.size);
+        if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
+            printf("Pattern verification failed at offset %"
+                   PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
+        }
+        free(cmp_buf);
+    }
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    if (ctx->vflag) {
+        dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("read", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
+out:
+    qemu_io_free(ctx->buf);
+    free(ctx);
+}
+
+static void aio_read_help(void)
+{
+    printf(
+"\n"
+" asynchronously reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" The read is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -P, -- use a pattern to verify read data\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int aio_read_f(int argc, char **argv);
+
+static const cmdinfo_t aio_read_cmd = {
+    .name       = "aio_read",
+    .cfunc      = aio_read_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cqv] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously reads a number of bytes",
+    .help       = aio_read_help,
+};
+
+static int aio_read_f(int argc, char **argv)
+{
+    int nr_iov, c;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'P':
+            ctx->Pflag = 1;
+            ctx->pattern = parse_pattern(optarg);
+            if (ctx->pattern < 0) {
+                free(ctx);
+                return 0;
+            }
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'v':
+            ctx->vflag = 1;
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_read_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_read_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
+                         ctx->qiov.size >> 9, aio_read_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static void aio_write_help(void)
+{
+    printf(
+"\n"
+" asynchronously writes a range of bytes from the given offset source\n"
+" from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" The write is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int aio_write_f(int argc, char **argv);
+
+static const cmdinfo_t aio_write_cmd = {
+    .name       = "aio_write",
+    .cfunc      = aio_write_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] [-P pattern ] off len [len..]",
+    .oneline    = "asynchronously writes a number of bytes",
+    .help       = aio_write_help,
+};
+
+static int aio_write_f(int argc, char **argv)
+{
+    int nr_iov, c;
+    int pattern = 0xcd;
+    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    BlockDriverAIOCB *acb;
+
+    while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = 1;
+            break;
+        case 'q':
+            ctx->qflag = 1;
+            break;
+        case 'P':
+            pattern = parse_pattern(optarg);
+            if (pattern < 0) {
+                return 0;
+            }
+            break;
+        default:
+            free(ctx);
+            return command_usage(&aio_write_cmd);
+        }
+    }
+
+    if (optind > argc - 2) {
+        free(ctx);
+        return command_usage(&aio_write_cmd);
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        free(ctx);
+        return 0;
+    }
+    optind++;
+
+    if (ctx->offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               ctx->offset);
+        free(ctx);
+        return 0;
+    }
+
+    nr_iov = argc - optind;
+    ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
+
+    gettimeofday(&ctx->t1, NULL);
+    acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
+                          ctx->qiov.size >> 9, aio_write_done, ctx);
+    if (!acb) {
+        free(ctx->buf);
+        free(ctx);
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static int aio_flush_f(int argc, char **argv)
+{
+    qemu_aio_flush();
+    return 0;
+}
+
+static const cmdinfo_t aio_flush_cmd = {
+    .name       = "aio_flush",
+    .cfunc      = aio_flush_f,
+    .oneline    = "completes all outstanding aio requests"
+};
+
+static int flush_f(int argc, char **argv)
+{
+    bdrv_flush(bs);
+    return 0;
+}
+
+static const cmdinfo_t flush_cmd = {
+    .name       = "flush",
+    .altname    = "f",
+    .cfunc      = flush_f,
+    .oneline    = "flush all in-core file state to disk",
+};
+
+static int truncate_f(int argc, char **argv)
+{
+    int64_t offset;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset < 0) {
+        printf("non-numeric truncate argument -- %s\n", argv[1]);
+        return 0;
+    }
+
+    ret = bdrv_truncate(bs, offset);
+    if (ret < 0) {
+        printf("truncate: %s\n", strerror(-ret));
+        return 0;
+    }
+
+    return 0;
+}
+
+static const cmdinfo_t truncate_cmd = {
+    .name       = "truncate",
+    .altname    = "t",
+    .cfunc      = truncate_f,
+    .argmin     = 1,
+    .argmax     = 1,
+    .args       = "off",
+    .oneline    = "truncates the current file at the given offset",
+};
+
+static int length_f(int argc, char **argv)
+{
+    int64_t size;
+    char s1[64];
+
+    size = bdrv_getlength(bs);
+    if (size < 0) {
+        printf("getlength: %s\n", strerror(-size));
+        return 0;
+    }
+
+    cvtstr(size, s1, sizeof(s1));
+    printf("%s\n", s1);
+    return 0;
+}
+
+
+static const cmdinfo_t length_cmd = {
+    .name   = "length",
+    .altname    = "l",
+    .cfunc      = length_f,
+    .oneline    = "gets the length of the current file",
+};
+
+
+static int info_f(int argc, char **argv)
+{
+    BlockDriverInfo bdi;
+    char s1[64], s2[64];
+    int ret;
+
+    if (bs->drv && bs->drv->format_name) {
+        printf("format name: %s\n", bs->drv->format_name);
+    }
+    if (bs->drv && bs->drv->protocol_name) {
+        printf("format name: %s\n", bs->drv->protocol_name);
+    }
+
+    ret = bdrv_get_info(bs, &bdi);
+    if (ret) {
+        return 0;
+    }
+
+    cvtstr(bdi.cluster_size, s1, sizeof(s1));
+    cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+
+    printf("cluster size: %s\n", s1);
+    printf("vm state offset: %s\n", s2);
+
+    return 0;
+}
+
+
+
+static const cmdinfo_t info_cmd = {
+    .name       = "info",
+    .altname    = "i",
+    .cfunc      = info_f,
+    .oneline    = "prints information about the current file",
+};
+
+static void discard_help(void)
+{
+    printf(
+"\n"
+" discards a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
+"\n"
+" Discards a segment of the currently open file.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int discard_f(int argc, char **argv);
+
+static const cmdinfo_t discard_cmd = {
+    .name       = "discard",
+    .altname    = "d",
+    .cfunc      = discard_f,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] off len",
+    .oneline    = "discards a number of bytes at a specified offset",
+    .help       = discard_help,
+};
+
+static int discard_f(int argc, char **argv)
+{
+    struct timeval t1, t2;
+    int Cflag = 0, qflag = 0;
+    int c, ret;
+    int64_t offset;
+    int count;
+
+    while ((c = getopt(argc, argv, "Cq")) != EOF) {
+        switch (c) {
+        case 'C':
+            Cflag = 1;
+            break;
+        case 'q':
+            qflag = 1;
+            break;
+        default:
+            return command_usage(&discard_cmd);
+        }
+    }
+
+    if (optind != argc - 2) {
+        return command_usage(&discard_cmd);
+    }
+
+    offset = cvtnum(argv[optind]);
+    if (offset < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    optind++;
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        printf("non-numeric length argument -- %s\n", argv[optind]);
+        return 0;
+    }
+
+    gettimeofday(&t1, NULL);
+    ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
+                       count >> BDRV_SECTOR_BITS);
+    gettimeofday(&t2, NULL);
+
+    if (ret < 0) {
+        printf("discard failed: %s\n", strerror(-ret));
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    if (!qflag) {
+        t2 = tsub(t2, t1);
+        print_report("discard", &t2, offset, count, count, 1, Cflag);
+    }
+
+out:
+    return 0;
+}
+
+static int alloc_f(int argc, char **argv)
+{
+    int64_t offset;
+    int nb_sectors, remaining;
+    char s1[64];
+    int num, sum_alloc;
+    int ret;
+
+    offset = cvtnum(argv[1]);
+    if (offset & 0x1ff) {
+        printf("offset %" PRId64 " is not sector aligned\n",
+               offset);
+        return 0;
+    }
+
+    if (argc == 3) {
+        nb_sectors = cvtnum(argv[2]);
+    } else {
+        nb_sectors = 1;
+    }
+
+    remaining = nb_sectors;
+    sum_alloc = 0;
+    while (remaining) {
+        ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+        remaining -= num;
+        if (ret) {
+            sum_alloc += num;
+        }
+    }
+
+    cvtstr(offset, s1, sizeof(s1));
+
+    printf("%d/%d sectors allocated at offset %s\n",
+           sum_alloc, nb_sectors, s1);
+    return 0;
+}
+
+static const cmdinfo_t alloc_cmd = {
+    .name       = "alloc",
+    .altname    = "a",
+    .argmin     = 1,
+    .argmax     = 2,
+    .cfunc      = alloc_f,
+    .args       = "off [sectors]",
+    .oneline    = "checks if a sector is present in the file",
+};
+
+static int map_f(int argc, char **argv)
+{
+    int64_t offset;
+    int64_t nb_sectors;
+    char s1[64];
+    int num, num_checked;
+    int ret;
+    const char *retstr;
+
+    offset = 0;
+    nb_sectors = bs->total_sectors;
+
+    do {
+        num_checked = MIN(nb_sectors, INT_MAX);
+        ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+        retstr = ret ? "    allocated" : "not allocated";
+        cvtstr(offset << 9ULL, s1, sizeof(s1));
+        printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
+               offset << 9ULL, num, num_checked, retstr, s1, ret);
+
+        offset += num;
+        nb_sectors -= num;
+    } while (offset < bs->total_sectors);
+
+    return 0;
+}
+
+static const cmdinfo_t map_cmd = {
+       .name           = "map",
+       .argmin         = 0,
+       .argmax         = 0,
+       .cfunc          = map_f,
+       .args           = "",
+       .oneline        = "prints the allocated areas of a file",
+};
+
+
+static int close_f(int argc, char **argv)
+{
+    bdrv_close(bs);
+    bs = NULL;
+    return 0;
+}
+
+static const cmdinfo_t close_cmd = {
+    .name       = "close",
+    .altname    = "c",
+    .cfunc      = close_f,
+    .oneline    = "close the current open file",
+};
+
+static int openfile(char *name, int flags, int growable)
+{
+    if (bs) {
+        fprintf(stderr, "file open already, try 'help close'\n");
+        return 1;
+    }
+
+    if (growable) {
+        if (bdrv_file_open(&bs, name, flags)) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            return 1;
+        }
+    } else {
+        bs = bdrv_new("hda");
+
+        if (bdrv_open(bs, name, flags, NULL) < 0) {
+            fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            bs = NULL;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void open_help(void)
+{
+    printf(
+"\n"
+" opens a new file in the requested mode\n"
+"\n"
+" Example:\n"
+" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
+"\n"
+" Opens a file for subsequent use by all of the other qemu-io commands.\n"
+" -r, -- open file read-only\n"
+" -s, -- use snapshot file\n"
+" -n, -- disable host cache\n"
+" -g, -- allow file to grow (only applies to protocols)"
+"\n");
+}
+
+static int open_f(int argc, char **argv);
+
+static const cmdinfo_t open_cmd = {
+    .name       = "open",
+    .altname    = "o",
+    .cfunc      = open_f,
+    .argmin     = 1,
+    .argmax     = -1,
+    .flags      = CMD_NOFILE_OK,
+    .args       = "[-Crsn] [path]",
+    .oneline    = "open the file specified by path",
+    .help       = open_help,
+};
+
+static int open_f(int argc, char **argv)
+{
+    int flags = 0;
+    int readonly = 0;
+    int growable = 0;
+    int c;
+
+    while ((c = getopt(argc, argv, "snrg")) != EOF) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        default:
+            return command_usage(&open_cmd);
+        }
+    }
+
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
+
+    if (optind != argc - 1) {
+        return command_usage(&open_cmd);
+    }
+
+    return openfile(argv[optind], flags, growable);
+}
+
+static int init_args_command(int index)
+{
+    /* only one device allowed so far */
+    if (index >= 1) {
+        return 0;
+    }
+    return ++index;
+}
+
+static int init_check_command(const cmdinfo_t *ct)
+{
+    if (ct->flags & CMD_FLAG_GLOBAL) {
+        return 1;
+    }
+    if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+        fprintf(stderr, "no file open, try 'help open'\n");
+        return 0;
+    }
+    return 1;
+}
+
+static void usage(const char *name)
+{
+    printf(
+"Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
+"QEMU Disk exerciser\n"
+"\n"
+"  -c, --cmd            command to execute\n"
+"  -r, --read-only      export read-only\n"
+"  -s, --snapshot       use snapshot file\n"
+"  -n, --nocache        disable host cache\n"
+"  -g, --growable       allow file to grow (only applies to protocols)\n"
+"  -m, --misalign       misalign allocations for O_DIRECT\n"
+"  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
+"  -h, --help           display this help and exit\n"
+"  -V, --version        output version information and exit\n"
+"\n",
+    name);
+}
+
+
+int main(int argc, char **argv)
+{
+    int readonly = 0;
+    int growable = 0;
+    const char *sopt = "hVc:rsnmgk";
+    const struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "offset", 1, NULL, 'o' },
+        { "cmd", 1, NULL, 'c' },
+        { "read-only", 0, NULL, 'r' },
+        { "snapshot", 0, NULL, 's' },
+        { "nocache", 0, NULL, 'n' },
+        { "misalign", 0, NULL, 'm' },
+        { "growable", 0, NULL, 'g' },
+        { "native-aio", 0, NULL, 'k' },
+        { NULL, 0, NULL, 0 }
+    };
+    int c;
+    int opt_index = 0;
+    int flags = 0;
+
+    progname = basename(argv[0]);
+
+    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
+        switch (c) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'c':
+            add_user_command(optarg);
+            break;
+        case 'r':
+            readonly = 1;
+            break;
+        case 'm':
+            misalign = 1;
+            break;
+        case 'g':
+            growable = 1;
+            break;
+        case 'k':
+            flags |= BDRV_O_NATIVE_AIO;
+            break;
+        case 'V':
+            printf("%s version %s\n", progname, VERSION);
+            exit(0);
+        case 'h':
+            usage(progname);
+            exit(0);
+        default:
+            usage(progname);
+            exit(1);
+        }
+    }
+
+    if ((argc - optind) > 1) {
+        usage(progname);
+        exit(1);
+    }
+
+    bdrv_init();
+
+    /* initialize commands */
+    quit_init();
+    help_init();
+    add_command(&open_cmd);
+    add_command(&close_cmd);
+    add_command(&read_cmd);
+    add_command(&readv_cmd);
+    add_command(&write_cmd);
+    add_command(&writev_cmd);
+    add_command(&multiwrite_cmd);
+    add_command(&aio_read_cmd);
+    add_command(&aio_write_cmd);
+    add_command(&aio_flush_cmd);
+    add_command(&flush_cmd);
+    add_command(&truncate_cmd);
+    add_command(&length_cmd);
+    add_command(&info_cmd);
+    add_command(&discard_cmd);
+    add_command(&alloc_cmd);
+    add_command(&map_cmd);
+
+    add_args_command(init_args_command);
+    add_check_command(init_check_command);
+
+    /* open the device */
+    if (!readonly) {
+        flags |= BDRV_O_RDWR;
+    }
+
+    if ((argc - optind) == 1) {
+        openfile(argv[optind], flags, growable);
+    }
+    command_loop();
+
+    /*
+     * Make sure all outstanding requests get flushed the program exits.
+     */
+    qemu_aio_flush();
+
+    if (bs) {
+        bdrv_close(bs);
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-lock.h b/qemu-0.15.x/qemu-lock.h
new file mode 100644
index 0000000..a72edda
--- /dev/null
+++ b/qemu-0.15.x/qemu-lock.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+/* configure guarantees us that we have pthreads on any host except
+ * mingw32, which doesn't support any of the user-only targets.
+ * So we can simply assume we have pthread mutexes here.
+ */
+#if defined(CONFIG_USER_ONLY)
+
+#include <pthread.h>
+#define spin_lock pthread_mutex_lock
+#define spin_unlock pthread_mutex_unlock
+#define spinlock_t pthread_mutex_t
+#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
+
+#else
+
+/* Empty implementations, on the theory that system mode emulation
+ * is single-threaded. This means that these functions should only
+ * be used from code run in the TCG cpu thread, and cannot protect
+ * data structures which might also be accessed from the IO thread
+ * or from signal handlers.
+ */
+typedef int spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
+
+static inline void spin_lock(spinlock_t *lock)
+{
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+}
+
+#endif
diff --git a/qemu-0.15.x/qemu-log.h b/qemu-0.15.x/qemu-log.h
new file mode 100644
index 0000000..fccfb11
--- /dev/null
+++ b/qemu-0.15.x/qemu-log.h
@@ -0,0 +1,93 @@
+#ifndef QEMU_LOG_H
+#define QEMU_LOG_H
+
+/* The deprecated global variables: */
+extern FILE *logfile;
+extern int loglevel;
+
+
+/* 
+ * The new API:
+ *
+ */
+
+/* Log settings checking macros: */
+
+/* Returns true if qemu_log() will really write somewhere
+ */
+#define qemu_log_enabled() (logfile != NULL)
+
+/* Returns true if a bit is set in the current loglevel mask
+ */
+#define qemu_loglevel_mask(b) ((loglevel & (b)) != 0)
+
+
+/* Logging functions: */
+
+/* main logging function
+ */
+#define qemu_log(...) do {                 \
+        if (logfile)                       \
+            fprintf(logfile, ## __VA_ARGS__); \
+    } while (0)
+
+/* vfprintf-like logging function
+ */
+#define qemu_log_vprintf(fmt, va) do {     \
+        if (logfile)                       \
+            vfprintf(logfile, fmt, va);    \
+    } while (0)
+
+/* log only if a bit is set on the current loglevel mask
+ */
+#define qemu_log_mask(b, ...) do {         \
+        if (loglevel & (b))                \
+            fprintf(logfile, ## __VA_ARGS__); \
+    } while (0)
+
+
+
+
+/* Special cases: */
+
+/* cpu_dump_state() logging functions: */
+#define log_cpu_state(env, f) cpu_dump_state((env), logfile, fprintf, (f));
+#define log_cpu_state_mask(b, env, f) do {           \
+      if (loglevel & (b)) log_cpu_state((env), (f)); \
+  } while (0)
+
+/* disas() and target_disas() to logfile: */
+#define log_target_disas(start, len, flags) \
+        target_disas(logfile, (start), (len), (flags))
+#define log_disas(start, len) \
+        disas(logfile, (start), (len))
+
+/* page_dump() output to the log file: */
+#define log_page_dump() page_dump(logfile)
+
+
+
+/* Maintenance: */
+
+/* fflush() the log file */
+#define qemu_log_flush() fflush(logfile)
+
+/* Close the log file */
+#define qemu_log_close() do { \
+        fclose(logfile);      \
+        logfile = NULL;       \
+    } while (0)
+
+/* Set up a new log file */
+#define qemu_log_set_file(f) do { \
+        logfile = (f);            \
+    } while (0)
+
+/* Set up a new log file, only if none is set */
+#define qemu_log_try_set_file(f) do { \
+        if (!logfile)                 \
+            logfile = (f);            \
+    } while (0)
+
+
+#endif
diff --git a/qemu-0.15.x/qemu-malloc.c b/qemu-0.15.x/qemu-malloc.c
new file mode 100644
index 0000000..b9b3851
--- /dev/null
+++ b/qemu-0.15.x/qemu-malloc.c
@@ -0,0 +1,98 @@
+/*
+ * malloc-like functions for system 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 "qemu-common.h"
+#include "trace.h"
+#include <stdlib.h>
+
+void qemu_free(void *ptr)
+{
+    trace_qemu_free(ptr);
+    free(ptr);
+}
+
+static int allow_zero_malloc(void)
+{
+#if defined(CONFIG_ZERO_MALLOC)
+    return 1;
+#else
+    return 0;
+#endif
+}
+
+void *qemu_malloc(size_t size)
+{
+    void *ptr;
+    if (!size && !allow_zero_malloc()) {
+        abort();
+    }
+    ptr = qemu_oom_check(malloc(size ? size : 1));
+    trace_qemu_malloc(size, ptr);
+    return ptr;
+}
+
+void *qemu_realloc(void *ptr, size_t size)
+{
+    void *newptr;
+    if (!size && !allow_zero_malloc()) {
+        abort();
+    }
+    newptr = qemu_oom_check(realloc(ptr, size ? size : 1));
+    trace_qemu_realloc(ptr, size, newptr);
+    return newptr;
+}
+
+void *qemu_mallocz(size_t size)
+{
+    void *ptr;
+    if (!size && !allow_zero_malloc()) {
+        abort();
+    }
+    ptr = qemu_oom_check(calloc(1, size ? size : 1));
+    trace_qemu_malloc(size, ptr);
+    return ptr;
+}
+
+char *qemu_strdup(const char *str)
+{
+    char *ptr;
+    size_t len = strlen(str);
+    ptr = qemu_malloc(len + 1);
+    memcpy(ptr, str, len + 1);
+    return ptr;
+}
+
+char *qemu_strndup(const char *str, size_t size)
+{
+    const char *end = memchr(str, 0, size);
+    char *new;
+
+    if (end) {
+        size = end - str;
+    }
+
+    new = qemu_malloc(size + 1);
+    new[size] = 0;
+
+    return memcpy(new, str, size);
+}
diff --git a/qemu-0.15.x/qemu-nbd.c b/qemu-0.15.x/qemu-nbd.c
new file mode 100644
index 0000000..d91c02c
--- /dev/null
+++ b/qemu-0.15.x/qemu-nbd.c
@@ -0,0 +1,499 @@
+/*
+ *  Copyright (C) 2005  Anthony Liguori <anthony at codemonkey.ws>
+ *
+ *  Network Block Device
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <qemu-common.h>
+#include "block_int.h"
+#include "nbd.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <libgen.h>
+
+#define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
+
+#define NBD_BUFFER_SIZE (1024*1024)
+
+static int verbose;
+
+static void usage(const char *name)
+{
+    printf(
+"Usage: %s [OPTIONS] FILE\n"
+"QEMU Disk Network Block Device Server\n"
+"\n"
+"  -p, --port=PORT      port to listen on (default `%d')\n"
+"  -o, --offset=OFFSET  offset into the image\n"
+"  -b, --bind=IFACE     interface to bind to (default `0.0.0.0')\n"
+"  -k, --socket=PATH    path to the unix socket\n"
+"                       (default '"SOCKET_PATH"')\n"
+"  -r, --read-only      export read-only\n"
+"  -P, --partition=NUM  only expose partition NUM\n"
+"  -s, --snapshot       use snapshot file\n"
+"  -n, --nocache        disable host cache\n"
+"  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
+"  -d, --disconnect     disconnect the specified device\n"
+"  -e, --shared=NUM     device can be shared by NUM clients (default '1')\n"
+"  -t, --persistent     don't exit on the last connection\n"
+"  -v, --verbose        display extra debugging information\n"
+"  -h, --help           display this help and exit\n"
+"  -V, --version        output version information and exit\n"
+"\n"
+"Report bugs to <anthony at codemonkey.ws>\n"
+    , name, NBD_DEFAULT_PORT, "DEVICE");
+}
+
+static void version(const char *name)
+{
+    printf(
+"%s version 0.0.1\n"
+"Written by Anthony Liguori.\n"
+"\n"
+"Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>.\n"
+"This is free software; see the source for copying conditions.  There is NO\n"
+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+    , name);
+}
+
+struct partition_record
+{
+    uint8_t bootable;
+    uint8_t start_head;
+    uint32_t start_cylinder;
+    uint8_t start_sector;
+    uint8_t system;
+    uint8_t end_head;
+    uint8_t end_cylinder;
+    uint8_t end_sector;
+    uint32_t start_sector_abs;
+    uint32_t nb_sectors_abs;
+};
+
+static void read_partition(uint8_t *p, struct partition_record *r)
+{
+    r->bootable = p[0];
+    r->start_head = p[1];
+    r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300);
+    r->start_sector = p[2] & 0x3f;
+    r->system = p[4];
+    r->end_head = p[5];
+    r->end_cylinder = p[7] | ((p[6] << 2) & 0x300);
+    r->end_sector = p[6] & 0x3f;
+    r->start_sector_abs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24;
+    r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24;
+}
+
+static int find_partition(BlockDriverState *bs, int partition,
+                          off_t *offset, off_t *size)
+{
+    struct partition_record mbr[4];
+    uint8_t data[512];
+    int i;
+    int ext_partnum = 4;
+    int ret;
+
+    if ((ret = bdrv_read(bs, 0, data, 1)) < 0) {
+        errno = -ret;
+        err(EXIT_FAILURE, "error while reading");
+    }
+
+    if (data[510] != 0x55 || data[511] != 0xaa) {
+        errno = -EINVAL;
+        return -1;
+    }
+
+    for (i = 0; i < 4; i++) {
+        read_partition(&data[446 + 16 * i], &mbr[i]);
+
+        if (!mbr[i].nb_sectors_abs)
+            continue;
+
+        if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
+            struct partition_record ext[4];
+            uint8_t data1[512];
+            int j;
+
+            if ((ret = bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) < 0) {
+                errno = -ret;
+                err(EXIT_FAILURE, "error while reading");
+            }
+
+            for (j = 0; j < 4; j++) {
+                read_partition(&data1[446 + 16 * j], &ext[j]);
+                if (!ext[j].nb_sectors_abs)
+                    continue;
+
+                if ((ext_partnum + j + 1) == partition) {
+                    *offset = (uint64_t)ext[j].start_sector_abs << 9;
+                    *size = (uint64_t)ext[j].nb_sectors_abs << 9;
+                    return 0;
+                }
+            }
+            ext_partnum += 4;
+        } else if ((i + 1) == partition) {
+            *offset = (uint64_t)mbr[i].start_sector_abs << 9;
+            *size = (uint64_t)mbr[i].nb_sectors_abs << 9;
+            return 0;
+        }
+    }
+
+    errno = -ENOENT;
+    return -1;
+}
+
+static void show_parts(const char *device)
+{
+    if (fork() == 0) {
+        int nbd;
+
+        /* linux just needs an open() to trigger
+         * the partition table update
+         * but remember to load the module with max_part != 0 :
+         *     modprobe nbd max_part=63
+         */
+        nbd = open(device, O_RDWR);
+        if (nbd != -1)
+              close(nbd);
+        exit(0);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    BlockDriverState *bs;
+    off_t dev_offset = 0;
+    off_t offset = 0;
+    bool readonly = false;
+    bool disconnect = false;
+    const char *bindto = "0.0.0.0";
+    int port = NBD_DEFAULT_PORT;
+    struct sockaddr_in addr;
+    socklen_t addr_len = sizeof(addr);
+    off_t fd_size;
+    char *device = NULL;
+    char *socket = NULL;
+    char sockpath[128];
+    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
+    struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "bind", 1, NULL, 'b' },
+        { "port", 1, NULL, 'p' },
+        { "socket", 1, NULL, 'k' },
+        { "offset", 1, NULL, 'o' },
+        { "read-only", 0, NULL, 'r' },
+        { "partition", 1, NULL, 'P' },
+        { "connect", 1, NULL, 'c' },
+        { "disconnect", 0, NULL, 'd' },
+        { "snapshot", 0, NULL, 's' },
+        { "nocache", 0, NULL, 'n' },
+        { "shared", 1, NULL, 'e' },
+        { "persistent", 0, NULL, 't' },
+        { "verbose", 0, NULL, 'v' },
+        { NULL, 0, NULL, 0 }
+    };
+    int ch;
+    int opt_ind = 0;
+    int li;
+    char *end;
+    int flags = BDRV_O_RDWR;
+    int partition = -1;
+    int ret;
+    int shared = 1;
+    uint8_t *data;
+    fd_set fds;
+    int *sharing_fds;
+    int fd;
+    int i;
+    int nb_fds = 0;
+    int max_fd;
+    int persistent = 0;
+    uint32_t nbdflags;
+
+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+        switch (ch) {
+        case 's':
+            flags |= BDRV_O_SNAPSHOT;
+            break;
+        case 'n':
+            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+            break;
+        case 'b':
+            bindto = optarg;
+            break;
+        case 'p':
+            li = strtol(optarg, &end, 0);
+            if (*end) {
+                errx(EXIT_FAILURE, "Invalid port `%s'", optarg);
+            }
+            if (li < 1 || li > 65535) {
+                errx(EXIT_FAILURE, "Port out of range `%s'", optarg);
+            }
+            port = (uint16_t)li;
+            break;
+        case 'o':
+                dev_offset = strtoll (optarg, &end, 0);
+            if (*end) {
+                errx(EXIT_FAILURE, "Invalid offset `%s'", optarg);
+            }
+            if (dev_offset < 0) {
+                errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg);
+            }
+            break;
+        case 'r':
+            readonly = true;
+            flags &= ~BDRV_O_RDWR;
+            break;
+        case 'P':
+            partition = strtol(optarg, &end, 0);
+            if (*end)
+                errx(EXIT_FAILURE, "Invalid partition `%s'", optarg);
+            if (partition < 1 || partition > 8)
+                errx(EXIT_FAILURE, "Invalid partition %d", partition);
+            break;
+        case 'k':
+            socket = optarg;
+            if (socket[0] != '/')
+                errx(EXIT_FAILURE, "socket path must be absolute\n");
+            break;
+        case 'd':
+            disconnect = true;
+            break;
+        case 'c':
+            device = optarg;
+            break;
+        case 'e':
+            shared = strtol(optarg, &end, 0);
+            if (*end) {
+                errx(EXIT_FAILURE, "Invalid shared device number '%s'", optarg);
+            }
+            if (shared < 1) {
+                errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
+            }
+            break;
+	case 't':
+	    persistent = 1;
+	    break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'V':
+            version(argv[0]);
+            exit(0);
+            break;
+        case 'h':
+            usage(argv[0]);
+            exit(0);
+            break;
+        case '?':
+            errx(EXIT_FAILURE, "Try `%s --help' for more information.",
+                 argv[0]);
+        }
+    }
+
+    if ((argc - optind) != 1) {
+        errx(EXIT_FAILURE, "Invalid number of argument.\n"
+             "Try `%s --help' for more information.",
+             argv[0]);
+    }
+
+    if (disconnect) {
+        fd = open(argv[optind], O_RDWR);
+        if (fd == -1)
+            err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
+
+        nbd_disconnect(fd);
+
+        close(fd);
+
+        printf("%s disconnected\n", argv[optind]);
+
+	return 0;
+    }
+
+    bdrv_init();
+
+    bs = bdrv_new("hda");
+
+    if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {
+        errno = -ret;
+        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
+    }
+
+    fd_size = bs->total_sectors * 512;
+
+    if (partition != -1 &&
+        find_partition(bs, partition, &dev_offset, &fd_size))
+        err(EXIT_FAILURE, "Could not find partition %d", partition);
+
+    if (device) {
+        pid_t pid;
+        int sock;
+
+        /* want to fail before daemonizing */
+        if (access(device, R_OK|W_OK) == -1) {
+            err(EXIT_FAILURE, "Could not access '%s'", device);
+        }
+
+        if (!verbose) {
+            /* detach client and server */
+            if (qemu_daemon(0, 0) == -1) {
+                err(EXIT_FAILURE, "Failed to daemonize");
+            }
+        }
+
+        if (socket == NULL) {
+            snprintf(sockpath, sizeof(sockpath), SOCKET_PATH,
+                     basename(device));
+            socket = sockpath;
+        }
+
+        pid = fork();
+        if (pid < 0)
+            return 1;
+        if (pid != 0) {
+            off_t size;
+            size_t blocksize;
+
+            ret = 0;
+            bdrv_close(bs);
+
+            do {
+                sock = unix_socket_outgoing(socket);
+                if (sock == -1) {
+                    if (errno != ENOENT && errno != ECONNREFUSED) {
+                        ret = 1;
+                        goto out;
+                    }
+                    sleep(1);	/* wait children */
+                }
+            } while (sock == -1);
+
+            fd = open(device, O_RDWR);
+            if (fd == -1) {
+                ret = 1;
+                goto out;
+            }
+
+            ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
+					&size, &blocksize);
+            if (ret == -1) {
+                ret = 1;
+                goto out;
+            }
+
+            ret = nbd_init(fd, sock, size, blocksize);
+            if (ret == -1) {
+                ret = 1;
+                goto out;
+            }
+
+            printf("NBD device %s is now connected to file %s\n",
+                    device, argv[optind]);
+
+	    /* update partition table */
+
+            show_parts(device);
+
+            ret = nbd_client(fd);
+            if (ret) {
+                ret = 1;
+            }
+            close(fd);
+ out:
+            kill(pid, SIGTERM);
+            unlink(socket);
+
+            return ret;
+        }
+        /* children */
+    }
+
+    sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
+
+    if (socket) {
+        sharing_fds[0] = unix_socket_incoming(socket);
+    } else {
+        sharing_fds[0] = tcp_socket_incoming(bindto, port);
+    }
+
+    if (sharing_fds[0] == -1)
+        return 1;
+    max_fd = sharing_fds[0];
+    nb_fds++;
+
+    data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
+    if (data == NULL)
+        errx(EXIT_FAILURE, "Cannot allocate data buffer");
+
+    do {
+
+        FD_ZERO(&fds);
+        for (i = 0; i < nb_fds; i++)
+            FD_SET(sharing_fds[i], &fds);
+
+        ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
+        if (ret == -1)
+            break;
+
+        if (FD_ISSET(sharing_fds[0], &fds))
+            ret--;
+        for (i = 1; i < nb_fds && ret; i++) {
+            if (FD_ISSET(sharing_fds[i], &fds)) {
+                if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
+                    &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
+                    close(sharing_fds[i]);
+                    nb_fds--;
+                    sharing_fds[i] = sharing_fds[nb_fds];
+                    i--;
+                }
+                ret--;
+            }
+        }
+        /* new connection ? */
+        if (FD_ISSET(sharing_fds[0], &fds)) {
+            if (nb_fds < shared + 1) {
+                sharing_fds[nb_fds] = accept(sharing_fds[0],
+                                             (struct sockaddr *)&addr,
+                                             &addr_len);
+                if (sharing_fds[nb_fds] != -1 &&
+                    nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {
+                        if (sharing_fds[nb_fds] > max_fd)
+                            max_fd = sharing_fds[nb_fds];
+                        nb_fds++;
+                }
+            }
+        }
+    } while (persistent || nb_fds > 1);
+    qemu_vfree(data);
+
+    close(sharing_fds[0]);
+    bdrv_close(bs);
+    qemu_free(sharing_fds);
+    if (socket)
+        unlink(socket);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-nbd.texi b/qemu-0.15.x/qemu-nbd.texi
new file mode 100644
index 0000000..44996cc
--- /dev/null
+++ b/qemu-0.15.x/qemu-nbd.texi
@@ -0,0 +1,66 @@
+ at example
+ at c man begin SYNOPSIS
+usage: qemu-nbd [OPTION]...  @var{filename}
+ at c man end
+ at end example
+
+ at c man begin DESCRIPTION
+
+Export Qemu disk image using NBD protocol.
+
+ at c man end
+
+ at c man begin OPTIONS
+ at table @option
+ at item @var{filename}
+ is a disk image filename
+ at item -p, --port=@var{port}
+  port to listen on (default @samp{1024})
+ at item -o, --offset=@var{offset}
+  offset into the image
+ at item -b, --bind=@var{iface}
+  interface to bind to (default @samp{0.0.0.0})
+ at item -k, --socket=@var{path}
+  Use a unix socket with path @var{path}
+ at item -r, --read-only
+  export read-only
+ at item -P, --partition=@var{num}
+  only expose partition @var{num}
+ at item -s, --snapshot
+  use snapshot file
+ at item -n, --nocache
+  disable host cache
+ at item -c, --connect=@var{dev}
+  connect @var{filename} to NBD device @var{dev}
+ at item -d, --disconnect
+  disconnect the specified device
+ at item -e, --shared=@var{num}
+  device can be shared by @var{num} clients (default @samp{1})
+ at item -t, --persistent
+  don't exit on the last connection
+ at item -v, --verbose
+  display extra debugging information
+ at item -h, --help
+  display this help and exit
+ at item -V, --version
+  output version information and exit
+ at end table
+
+ at c man end
+
+ at ignore
+
+ at setfilename qemu-nbd
+ at settitle QEMU Disk Network Block Device Server
+
+ at c man begin AUTHOR
+Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ at c man end
+
+ at c man begin SEEALSO
+qemu-img(1)
+ at c man end
+
+ at end ignore
diff --git a/qemu-0.15.x/qemu-objects.h b/qemu-0.15.x/qemu-objects.h
new file mode 100644
index 0000000..c53fbaa
--- /dev/null
+++ b/qemu-0.15.x/qemu-objects.h
@@ -0,0 +1,25 @@
+/*
+ * Include all QEMU objects.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QEMU_OBJECTS_H
+#define QEMU_OBJECTS_H
+
+#include "qobject.h"
+#include "qint.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "qstring.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qjson.h"
+
+#endif /* QEMU_OBJECTS_H */
diff --git a/qemu-0.15.x/qemu-option.c b/qemu-0.15.x/qemu-option.c
new file mode 100644
index 0000000..65db542
--- /dev/null
+++ b/qemu-0.15.x/qemu-option.c
@@ -0,0 +1,977 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf at redhat.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "qemu-objects.h"
+#include "qemu-option.h"
+#include "qerror.h"
+
+/*
+ * Extracts the name of an option from the parameter string (p points at the
+ * first byte of the option name)
+ *
+ * The option name is delimited by delim (usually , or =) or the string end
+ * and is copied into buf. If the option name is longer than buf_size, it is
+ * truncated. buf is always zero terminated.
+ *
+ * The return value is the position of the delimiter/zero byte after the option
+ * name in p.
+ */
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0' && *p != delim) {
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+/*
+ * Extracts the value of an option from the parameter string p (p points at the
+ * first byte of the option value)
+ *
+ * This function is comparable to get_opt_name with the difference that the
+ * delimiter is fixed to be comma which starts a new option. To specify an
+ * option value that contains commas, double each comma.
+ */
+const char *get_opt_value(char *buf, int buf_size, const char *p)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0') {
+        if (*p == ',') {
+            if (*(p + 1) != ',')
+                break;
+            p++;
+        }
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+int get_next_param_value(char *buf, int buf_size,
+                         const char *tag, const char **pstr)
+{
+    const char *p;
+    char option[128];
+
+    p = *pstr;
+    for(;;) {
+        p = get_opt_name(option, sizeof(option), p, '=');
+        if (*p != '=')
+            break;
+        p++;
+        if (!strcmp(tag, option)) {
+            *pstr = get_opt_value(buf, buf_size, p);
+            if (**pstr == ',') {
+                (*pstr)++;
+            }
+            return strlen(buf);
+        } else {
+            p = get_opt_value(NULL, 0, p);
+        }
+        if (*p != ',')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str)
+{
+    return get_next_param_value(buf, buf_size, tag, &str);
+}
+
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str)
+{
+    const char *p;
+    int i;
+
+    p = str;
+    while (*p != '\0') {
+        p = get_opt_name(buf, buf_size, p, '=');
+        if (*p != '=') {
+            return -1;
+        }
+        p++;
+        for (i = 0; params[i] != NULL; i++) {
+            if (!strcmp(params[i], buf)) {
+                break;
+            }
+        }
+        if (params[i] == NULL) {
+            return -1;
+        }
+        p = get_opt_value(NULL, 0, p);
+        if (*p != ',') {
+            break;
+        }
+        p++;
+    }
+    return 0;
+}
+
+/*
+ * Searches an option list for an option with the given name
+ */
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name)
+{
+    while (list && list->name) {
+        if (!strcmp(list->name, name)) {
+            return list;
+        }
+        list++;
+    }
+
+    return NULL;
+}
+
+static int parse_option_bool(const char *name, const char *value, int *ret)
+{
+    if (value != NULL) {
+        if (!strcmp(value, "on")) {
+            *ret = 1;
+        } else if (!strcmp(value, "off")) {
+            *ret = 0;
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'");
+            return -1;
+        }
+    } else {
+        *ret = 1;
+    }
+    return 0;
+}
+
+static int parse_option_number(const char *name, const char *value, uint64_t *ret)
+{
+    char *postfix;
+    uint64_t number;
+
+    if (value != NULL) {
+        number = strtoull(value, &postfix, 0);
+        if (*postfix != '\0') {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
+            return -1;
+        }
+        *ret = number;
+    } else {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
+        return -1;
+    }
+    return 0;
+}
+
+static int parse_option_size(const char *name, const char *value, uint64_t *ret)
+{
+    char *postfix;
+    double sizef;
+
+    if (value != NULL) {
+        sizef = strtod(value, &postfix);
+        switch (*postfix) {
+        case 'T':
+            sizef *= 1024;
+        case 'G':
+            sizef *= 1024;
+        case 'M':
+            sizef *= 1024;
+        case 'K':
+        case 'k':
+            sizef *= 1024;
+        case 'b':
+        case '\0':
+            *ret = (uint64_t) sizef;
+            break;
+        default:
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
+            error_printf_unless_qmp("You may use k, M, G or T suffixes for "
+                    "kilobytes, megabytes, gigabytes and terabytes.\n");
+            return -1;
+        }
+    } else {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Sets the value of a parameter in a given option list. The parsing of the
+ * value depends on the type of option:
+ *
+ * OPT_FLAG (uses value.n):
+ *      If no value is given, the flag is set to 1.
+ *      Otherwise the value must be "on" (set to 1) or "off" (set to 0)
+ *
+ * OPT_STRING (uses value.s):
+ *      value is strdup()ed and assigned as option value
+ *
+ * OPT_SIZE (uses value.n):
+ *      The value is converted to an integer. Suffixes for kilobytes etc. are
+ *      allowed (powers of 1024).
+ *
+ * Returns 0 on succes, -1 in error cases
+ */
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value)
+{
+    int flag;
+
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+        if (parse_option_bool(name, value, &flag) == -1)
+            return -1;
+        list->value.n = flag;
+        break;
+
+    case OPT_STRING:
+        if (value != NULL) {
+            list->value.s = qemu_strdup(value);
+        } else {
+            fprintf(stderr, "Option '%s' needs a parameter\n", name);
+            return -1;
+        }
+        break;
+
+    case OPT_SIZE:
+        if (parse_option_size(name, value, &list->value.n) == -1)
+            return -1;
+        break;
+
+    default:
+        fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Sets the given parameter to an integer instead of a string.
+ * This function cannot be used to set string options.
+ *
+ * Returns 0 on success, -1 in error cases
+ */
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value)
+{
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+    case OPT_NUMBER:
+    case OPT_SIZE:
+        list->value.n = value;
+        break;
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Frees a option list. If it contains strings, the strings are freed as well.
+ */
+void free_option_parameters(QEMUOptionParameter *list)
+{
+    QEMUOptionParameter *cur = list;
+
+    while (cur && cur->name) {
+        if (cur->type == OPT_STRING) {
+            qemu_free(cur->value.s);
+        }
+        cur++;
+    }
+
+    qemu_free(list);
+}
+
+/*
+ * Count valid options in list
+ */
+static size_t count_option_parameters(QEMUOptionParameter *list)
+{
+    size_t num_options = 0;
+
+    while (list && list->name) {
+        num_options++;
+        list++;
+    }
+
+    return num_options;
+}
+
+/*
+ * Append an option list (list) to an option list (dest).
+ *
+ * If dest is NULL, a new copy of list is created.
+ *
+ * Returns a pointer to the first element of dest (or the newly allocated copy)
+ */
+QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
+    QEMUOptionParameter *list)
+{
+    size_t num_options, num_dest_options;
+
+    num_options = count_option_parameters(dest);
+    num_dest_options = num_options;
+
+    num_options += count_option_parameters(list);
+
+    dest = qemu_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
+    dest[num_dest_options].name = NULL;
+
+    while (list && list->name) {
+        if (get_option_parameter(dest, list->name) == NULL) {
+            dest[num_dest_options++] = *list;
+            dest[num_dest_options].name = NULL;
+        }
+        list++;
+    }
+
+    return dest;
+}
+
+/*
+ * Parses a parameter string (param) into an option list (dest).
+ *
+ * list is the template option list. If dest is NULL, a new copy of list is
+ * created. If list is NULL, this function fails.
+ *
+ * A parameter string consists of one or more parameters, separated by commas.
+ * Each parameter consists of its name and possibly of a value. In the latter
+ * case, the value is delimited by an = character. To specify a value which
+ * contains commas, double each comma so it won't be recognized as the end of
+ * the parameter.
+ *
+ * For more details of the parsing see above.
+ *
+ * Returns a pointer to the first element of dest (or the newly allocated copy)
+ * or NULL in error cases
+ */
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest)
+{
+    QEMUOptionParameter *allocated = NULL;
+    char name[256];
+    char value[256];
+    char *param_delim, *value_delim;
+    char next_delim;
+
+    if (list == NULL) {
+        return NULL;
+    }
+
+    if (dest == NULL) {
+        dest = allocated = append_option_parameters(NULL, list);
+    }
+
+    while (*param) {
+
+        // Find parameter name and value in the string
+        param_delim = strchr(param, ',');
+        value_delim = strchr(param, '=');
+
+        if (value_delim && (value_delim < param_delim || !param_delim)) {
+            next_delim = '=';
+        } else {
+            next_delim = ',';
+            value_delim = NULL;
+        }
+
+        param = get_opt_name(name, sizeof(name), param, next_delim);
+        if (value_delim) {
+            param = get_opt_value(value, sizeof(value), param + 1);
+        }
+        if (*param != '\0') {
+            param++;
+        }
+
+        // Set the parameter
+        if (set_option_parameter(dest, name, value_delim ? value : NULL)) {
+            goto fail;
+        }
+    }
+
+    return dest;
+
+fail:
+    // Only free the list if it was newly allocated
+    free_option_parameters(allocated);
+    return NULL;
+}
+
+/*
+ * Prints all options of a list that have a value to stdout
+ */
+void print_option_parameters(QEMUOptionParameter *list)
+{
+    while (list && list->name) {
+        switch (list->type) {
+            case OPT_STRING:
+                 if (list->value.s != NULL) {
+                     printf("%s='%s' ", list->name, list->value.s);
+                 }
+                break;
+            case OPT_FLAG:
+                printf("%s=%s ", list->name, list->value.n ? "on" : "off");
+                break;
+            case OPT_SIZE:
+            case OPT_NUMBER:
+                printf("%s=%" PRId64 " ", list->name, list->value.n);
+                break;
+            default:
+                printf("%s=(unkown type) ", list->name);
+                break;
+        }
+        list++;
+    }
+}
+
+/*
+ * Prints an overview of all available options
+ */
+void print_option_help(QEMUOptionParameter *list)
+{
+    printf("Supported options:\n");
+    while (list && list->name) {
+        printf("%-16s %s\n", list->name,
+            list->help ? list->help : "No description available");
+        list++;
+    }
+}
+
+/* ------------------------------------------------------------------ */
+
+struct QemuOpt {
+    const char   *name;
+    const char   *str;
+
+    const QemuOptDesc *desc;
+    union {
+        int      boolean;
+        uint64_t uint;
+    } value;
+
+    QemuOpts     *opts;
+    QTAILQ_ENTRY(QemuOpt) next;
+};
+
+struct QemuOpts {
+    char *id;
+    QemuOptsList *list;
+    Location loc;
+    QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
+    QTAILQ_ENTRY(QemuOpts) next;
+};
+
+static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
+{
+    QemuOpt *opt;
+
+    QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
+        if (strcmp(opt->name, name) != 0)
+            continue;
+        return opt;
+    }
+    return NULL;
+}
+
+const char *qemu_opt_get(QemuOpts *opts, const char *name)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+    return opt ? opt->str : NULL;
+}
+
+int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
+    return opt->value.boolean;
+}
+
+uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
+    return opt->value.uint;
+}
+
+uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
+    return opt->value.uint;
+}
+
+static int qemu_opt_parse(QemuOpt *opt)
+{
+    if (opt->desc == NULL)
+        return 0;
+    switch (opt->desc->type) {
+    case QEMU_OPT_STRING:
+        /* nothing */
+        return 0;
+    case QEMU_OPT_BOOL:
+        return parse_option_bool(opt->name, opt->str, &opt->value.boolean);
+    case QEMU_OPT_NUMBER:
+        return parse_option_number(opt->name, opt->str, &opt->value.uint);
+    case QEMU_OPT_SIZE:
+        return parse_option_size(opt->name, opt->str, &opt->value.uint);
+    default:
+        abort();
+    }
+}
+
+static void qemu_opt_del(QemuOpt *opt)
+{
+    QTAILQ_REMOVE(&opt->opts->head, opt, next);
+    qemu_free((/* !const */ char*)opt->name);
+    qemu_free((/* !const */ char*)opt->str);
+    qemu_free(opt);
+}
+
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+    QemuOpt *opt;
+    const QemuOptDesc *desc = opts->list->desc;
+    int i;
+
+    for (i = 0; desc[i].name != NULL; i++) {
+        if (strcmp(desc[i].name, name) == 0) {
+            break;
+        }
+    }
+    if (desc[i].name == NULL) {
+        if (i == 0) {
+            /* empty list -> allow any */;
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER, name);
+            return -1;
+        }
+    }
+
+    opt = qemu_mallocz(sizeof(*opt));
+    opt->name = qemu_strdup(name);
+    opt->opts = opts;
+    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+    if (desc[i].name != NULL) {
+        opt->desc = desc+i;
+    }
+    if (value) {
+        opt->str = qemu_strdup(value);
+    }
+    if (qemu_opt_parse(opt) < 0) {
+        qemu_opt_del(opt);
+        return -1;
+    }
+    return 0;
+}
+
+int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
+                     int abort_on_failure)
+{
+    QemuOpt *opt;
+    int rc = 0;
+
+    QTAILQ_FOREACH(opt, &opts->head, next) {
+        rc = func(opt->name, opt->str, opaque);
+        if (abort_on_failure  &&  rc != 0)
+            break;
+    }
+    return rc;
+}
+
+QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
+{
+    QemuOpts *opts;
+
+    QTAILQ_FOREACH(opts, &list->head, next) {
+        if (!opts->id) {
+            continue;
+        }
+        if (strcmp(opts->id, id) != 0) {
+            continue;
+        }
+        return opts;
+    }
+    return NULL;
+}
+
+static int id_wellformed(const char *id)
+{
+    int i;
+
+    if (!qemu_isalpha(id[0])) {
+        return 0;
+    }
+    for (i = 1; id[i]; i++) {
+        if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists)
+{
+    QemuOpts *opts = NULL;
+
+    if (id) {
+        if (!id_wellformed(id)) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+            error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");
+            return NULL;
+        }
+        opts = qemu_opts_find(list, id);
+        if (opts != NULL) {
+            if (fail_if_exists) {
+                qerror_report(QERR_DUPLICATE_ID, id, list->name);
+                return NULL;
+            } else {
+                return opts;
+            }
+        }
+    }
+    opts = qemu_mallocz(sizeof(*opts));
+    if (id) {
+        opts->id = qemu_strdup(id);
+    }
+    opts->list = list;
+    loc_save(&opts->loc);
+    QTAILQ_INIT(&opts->head);
+    QTAILQ_INSERT_TAIL(&list->head, opts, next);
+    return opts;
+}
+
+void qemu_opts_reset(QemuOptsList *list)
+{
+    QemuOpts *opts, *next_opts;
+
+    QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
+        qemu_opts_del(opts);
+    }
+}
+
+void qemu_opts_loc_restore(QemuOpts *opts)
+{
+    loc_restore(&opts->loc);
+}
+
+int qemu_opts_set(QemuOptsList *list, const char *id,
+                  const char *name, const char *value)
+{
+    QemuOpts *opts;
+
+    opts = qemu_opts_create(list, id, 1);
+    if (opts == NULL) {
+        return -1;
+    }
+    return qemu_opt_set(opts, name, value);
+}
+
+const char *qemu_opts_id(QemuOpts *opts)
+{
+    return opts->id;
+}
+
+void qemu_opts_del(QemuOpts *opts)
+{
+    QemuOpt *opt;
+
+    for (;;) {
+        opt = QTAILQ_FIRST(&opts->head);
+        if (opt == NULL)
+            break;
+        qemu_opt_del(opt);
+    }
+    QTAILQ_REMOVE(&opts->list->head, opts, next);
+    qemu_free(opts->id);
+    qemu_free(opts);
+}
+
+int qemu_opts_print(QemuOpts *opts, void *dummy)
+{
+    QemuOpt *opt;
+
+    fprintf(stderr, "%s: %s:", opts->list->name,
+            opts->id ? opts->id : "<noid>");
+    QTAILQ_FOREACH(opt, &opts->head, next) {
+        fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
+
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+{
+    char option[128], value[1024];
+    const char *p,*pe,*pc;
+
+    for (p = params; *p != '\0'; p++) {
+        pe = strchr(p, '=');
+        pc = strchr(p, ',');
+        if (!pe || (pc && pc < pe)) {
+            /* found "foo,more" */
+            if (p == params && firstname) {
+                /* implicitly named first option */
+                pstrcpy(option, sizeof(option), firstname);
+                p = get_opt_value(value, sizeof(value), p);
+            } else {
+                /* option without value, probably a flag */
+                p = get_opt_name(option, sizeof(option), p, ',');
+                if (strncmp(option, "no", 2) == 0) {
+                    memmove(option, option+2, strlen(option+2)+1);
+                    pstrcpy(value, sizeof(value), "off");
+                } else {
+                    pstrcpy(value, sizeof(value), "on");
+                }
+            }
+        } else {
+            /* found "foo=bar,more" */
+            p = get_opt_name(option, sizeof(option), p, '=');
+            if (*p != '=') {
+                break;
+            }
+            p++;
+            p = get_opt_value(value, sizeof(value), p);
+        }
+        if (strcmp(option, "id") != 0) {
+            /* store and parse */
+            if (qemu_opt_set(opts, option, value) == -1) {
+                return -1;
+            }
+        }
+        if (*p != ',') {
+            break;
+        }
+    }
+    return 0;
+}
+
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
+                          int permit_abbrev)
+{
+    const char *firstname;
+    char value[1024], *id = NULL;
+    const char *p;
+    QemuOpts *opts;
+
+    assert(!permit_abbrev || list->implied_opt_name);
+    firstname = permit_abbrev ? list->implied_opt_name : NULL;
+
+    if (strncmp(params, "id=", 3) == 0) {
+        get_opt_value(value, sizeof(value), params+3);
+        id = value;
+    } else if ((p = strstr(params, ",id=")) != NULL) {
+        get_opt_value(value, sizeof(value), p+4);
+        id = value;
+    }
+    opts = qemu_opts_create(list, id, 1);
+    if (opts == NULL)
+        return NULL;
+
+    if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+        qemu_opts_del(opts);
+        return NULL;
+    }
+
+    return opts;
+}
+
+static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
+{
+    char buf[32];
+    const char *value;
+    int n;
+
+    if (!strcmp(key, "id")) {
+        return;
+    }
+
+    switch (qobject_type(obj)) {
+    case QTYPE_QSTRING:
+        value = qstring_get_str(qobject_to_qstring(obj));
+        break;
+    case QTYPE_QINT:
+        n = snprintf(buf, sizeof(buf), "%" PRId64,
+                     qint_get_int(qobject_to_qint(obj)));
+        assert(n < sizeof(buf));
+        value = buf;
+        break;
+    case QTYPE_QFLOAT:
+        n = snprintf(buf, sizeof(buf), "%.17g",
+                     qfloat_get_double(qobject_to_qfloat(obj)));
+        assert(n < sizeof(buf));
+        value = buf;
+        break;
+    case QTYPE_QBOOL:
+        pstrcpy(buf, sizeof(buf),
+                qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off");
+        value = buf;
+        break;
+    default:
+        return;
+    }
+    qemu_opt_set(opaque, key, value);
+}
+
+/*
+ * Create QemuOpts from a QDict.
+ * Use value of key "id" as ID if it exists and is a QString.
+ * Only QStrings, QInts, QFloats and QBools are copied.  Entries with
+ * other types are silently ignored.
+ */
+QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict)
+{
+    QemuOpts *opts;
+
+    opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1);
+    if (opts == NULL)
+        return NULL;
+
+    qdict_iter(qdict, qemu_opts_from_qdict_1, opts);
+    return opts;
+}
+
+/*
+ * Convert from QemuOpts to QDict.
+ * The QDict values are of type QString.
+ * TODO We'll want to use types appropriate for opt->desc->type, but
+ * this is enough for now.
+ */
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
+{
+    QemuOpt *opt;
+    QObject *val;
+
+    if (!qdict) {
+        qdict = qdict_new();
+    }
+    if (opts->id) {
+        qdict_put(qdict, "id", qstring_from_str(opts->id));
+    }
+    QTAILQ_FOREACH(opt, &opts->head, next) {
+        val = QOBJECT(qstring_from_str(opt->str));
+        qdict_put_obj(qdict, opt->name, val);
+    }
+    return qdict;
+}
+
+/* Validate parsed opts against descriptions where no
+ * descriptions were provided in the QemuOptsList.
+ */
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
+{
+    QemuOpt *opt;
+
+    assert(opts->list->desc[0].name == NULL);
+
+    QTAILQ_FOREACH(opt, &opts->head, next) {
+        int i;
+
+        for (i = 0; desc[i].name != NULL; i++) {
+            if (strcmp(desc[i].name, opt->name) == 0) {
+                break;
+            }
+        }
+        if (desc[i].name == NULL) {
+            qerror_report(QERR_INVALID_PARAMETER, opt->name);
+            return -1;
+        }
+
+        opt->desc = &desc[i];
+
+        if (qemu_opt_parse(opt) < 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
+                      int abort_on_failure)
+{
+    Location loc;
+    QemuOpts *opts;
+    int rc = 0;
+
+    loc_push_none(&loc);
+    QTAILQ_FOREACH(opts, &list->head, next) {
+        loc_restore(&opts->loc);
+        rc |= func(opts, opaque);
+        if (abort_on_failure  &&  rc != 0)
+            break;
+    }
+    loc_pop(&loc);
+    return rc;
+}
diff --git a/qemu-0.15.x/qemu-option.h b/qemu-0.15.x/qemu-option.h
new file mode 100644
index 0000000..b515813
--- /dev/null
+++ b/qemu-0.15.x/qemu-option.h
@@ -0,0 +1,135 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf at redhat.com>
+ *
+ * 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 QEMU_OPTIONS_H
+#define QEMU_OPTIONS_H
+
+#include <stdint.h>
+#include "qemu-queue.h"
+#include "qdict.h"
+
+enum QEMUOptionParType {
+    OPT_FLAG,
+    OPT_NUMBER,
+    OPT_SIZE,
+    OPT_STRING,
+};
+
+typedef struct QEMUOptionParameter {
+    const char *name;
+    enum QEMUOptionParType type;
+    union {
+        uint64_t n;
+        char* s;
+    } value;
+    const char *help;
+} QEMUOptionParameter;
+
+
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
+const char *get_opt_value(char *buf, int buf_size, const char *p);
+int get_next_param_value(char *buf, int buf_size,
+                         const char *tag, const char **pstr);
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str);
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str);
+
+
+/*
+ * The following functions take a parameter list as input. This is a pointer to
+ * the first element of a QEMUOptionParameter array which is terminated by an
+ * entry with entry->name == NULL.
+ */
+
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name);
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value);
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value);
+QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
+    QEMUOptionParameter *list);
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest);
+void free_option_parameters(QEMUOptionParameter *list);
+void print_option_parameters(QEMUOptionParameter *list);
+void print_option_help(QEMUOptionParameter *list);
+
+/* ------------------------------------------------------------------ */
+
+typedef struct QemuOpt QemuOpt;
+typedef struct QemuOpts QemuOpts;
+typedef struct QemuOptsList QemuOptsList;
+
+enum QemuOptType {
+    QEMU_OPT_STRING = 0,  /* no parsing (use string as-is)                        */
+    QEMU_OPT_BOOL,        /* on/off                                               */
+    QEMU_OPT_NUMBER,      /* simple number                                        */
+    QEMU_OPT_SIZE,        /* size, accepts (K)ilo, (M)ega, (G)iga, (T)era postfix */
+};
+
+typedef struct QemuOptDesc {
+    const char *name;
+    enum QemuOptType type;
+    const char *help;
+} QemuOptDesc;
+
+struct QemuOptsList {
+    const char *name;
+    const char *implied_opt_name;
+    QTAILQ_HEAD(, QemuOpts) head;
+    QemuOptDesc desc[];
+};
+
+const char *qemu_opt_get(QemuOpts *opts, const char *name);
+int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
+uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval);
+uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
+typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque);
+int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
+                     int abort_on_failure);
+
+QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id);
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists);
+void qemu_opts_reset(QemuOptsList *list);
+void qemu_opts_loc_restore(QemuOpts *opts);
+int qemu_opts_set(QemuOptsList *list, const char *id,
+                  const char *name, const char *value);
+const char *qemu_opts_id(QemuOpts *opts);
+void qemu_opts_del(QemuOpts *opts);
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev);
+QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict);
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
+
+typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);
+int qemu_opts_print(QemuOpts *opts, void *dummy);
+int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
+                      int abort_on_failure);
+
+#endif
diff --git a/qemu-0.15.x/qemu-options.h b/qemu-0.15.x/qemu-options.h
new file mode 100644
index 0000000..c96f994
--- /dev/null
+++ b/qemu-0.15.x/qemu-options.h
@@ -0,0 +1,41 @@
+/*
+ * qemu-options.h
+ *
+ * Defines needed for command line argument processing.
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen at redhat.com>
+ *
+ * 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 _QEMU_OPTIONS_H_
+#define _QEMU_OPTIONS_H_
+
+enum {
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask)     \
+    opt_enum,
+#define DEFHEADING(text)
+#include "qemu-options.def"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+};
+
+#endif
diff --git a/qemu-0.15.x/qemu-options.hx b/qemu-0.15.x/qemu-options.hx
new file mode 100644
index 0000000..6238075
--- /dev/null
+++ b/qemu-0.15.x/qemu-options.hx
@@ -0,0 +1,2433 @@
+HXCOMM Use DEFHEADING() to define headings in both help text and texi
+HXCOMM Text between STEXI and ETEXI are copied to texi version and
+HXCOMM discarded from C version
+HXCOMM DEF(option, HAS_ARG/0, opt_enum, opt_help, arch_mask) is used to
+HXCOMM construct option structures, enums and help message for specified
+HXCOMM architectures.
+HXCOMM HXCOMM can be used for comments, discarded from both texi and C
+
+DEFHEADING(Standard options:)
+STEXI
+ at table @option
+ETEXI
+
+DEF("help", 0, QEMU_OPTION_h,
+    "-h or -help     display this help and exit\n", QEMU_ARCH_ALL)
+STEXI
+ at item -h
+ at findex -h
+Display help and exit
+ETEXI
+
+DEF("version", 0, QEMU_OPTION_version,
+    "-version        display version information and exit\n", QEMU_ARCH_ALL)
+STEXI
+ at item -version
+ at findex -version
+Display version information and exit
+ETEXI
+
+DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
+    "-machine [type=]name[,prop[=value][,...]]\n"
+    "                selects emulated machine (-machine ? for list)\n"
+    "                property accel=accel1[:accel2[:...]] selects accelerator\n"
+    "                supported accelerators are kvm, xen, tcg (default: tcg)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -machine [type=]@var{name}[,prop=@var{value}[,...]]
+ at findex -machine
+Select the emulated machine by @var{name}. Use @code{-machine ?} to list
+available machines. Supported machine properties are:
+ at table @option
+ at item accel=@var{accels1}[:@var{accels2}[:...]]
+This is used to enable an accelerator. Depending on the target architecture,
+kvm, xen, or tcg can be available. By default, tcg is used. If there is more
+than one accelerator specified, the next one is used if the previous one fails
+to initialize.
+ at end table
+ETEXI
+
+HXCOMM Deprecated by -machine
+DEF("M", HAS_ARG, QEMU_OPTION_M, "", QEMU_ARCH_ALL)
+
+DEF("cpu", HAS_ARG, QEMU_OPTION_cpu,
+    "-cpu cpu        select CPU (-cpu ? for list)\n", QEMU_ARCH_ALL)
+STEXI
+ at item -cpu @var{model}
+ at findex -cpu
+Select CPU model (-cpu ? for list and additional feature selection)
+ETEXI
+
+DEF("smp", HAS_ARG, QEMU_OPTION_smp,
+    "-smp n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]\n"
+    "                set the number of CPUs to 'n' [default=1]\n"
+    "                maxcpus= maximum number of total cpus, including\n"
+    "                offline CPUs for hotplug, etc\n"
+    "                cores= number of CPU cores on one socket\n"
+    "                threads= number of threads on one CPU core\n"
+    "                sockets= number of discrete sockets in the system\n",
+        QEMU_ARCH_ALL)
+STEXI
+ at item -smp @var{n}[,cores=@var{cores}][,threads=@var{threads}][,sockets=@var{sockets}][,maxcpus=@var{maxcpus}]
+ at findex -smp
+Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
+CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs
+to 4.
+For the PC target, the number of @var{cores} per socket, the number
+of @var{threads} per cores and the total number of @var{sockets} can be
+specified. Missing values will be computed. If any on the three values is
+given, the total number of CPUs @var{n} can be omitted. @var{maxcpus}
+specifies the maximum number of hotpluggable CPUs.
+ETEXI
+
+DEF("numa", HAS_ARG, QEMU_OPTION_numa,
+    "-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node]\n", QEMU_ARCH_ALL)
+STEXI
+ at item -numa @var{opts}
+ at findex -numa
+Simulate a multi node NUMA system. If mem and cpus are omitted, resources
+are split equally.
+ETEXI
+
+DEF("fda", HAS_ARG, QEMU_OPTION_fda,
+    "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL)
+DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL)
+STEXI
+ at item -fda @var{file}
+ at item -fdb @var{file}
+ at findex -fda
+ at findex -fdb
+Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
+use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}).
+ETEXI
+
+DEF("hda", HAS_ARG, QEMU_OPTION_hda,
+    "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n", QEMU_ARCH_ALL)
+DEF("hdb", HAS_ARG, QEMU_OPTION_hdb, "", QEMU_ARCH_ALL)
+DEF("hdc", HAS_ARG, QEMU_OPTION_hdc,
+    "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n", QEMU_ARCH_ALL)
+DEF("hdd", HAS_ARG, QEMU_OPTION_hdd, "", QEMU_ARCH_ALL)
+STEXI
+ at item -hda @var{file}
+ at item -hdb @var{file}
+ at item -hdc @var{file}
+ at item -hdd @var{file}
+ at findex -hda
+ at findex -hdb
+ at findex -hdc
+ at findex -hdd
+Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
+ETEXI
+
+DEF("cdrom", HAS_ARG, QEMU_OPTION_cdrom,
+    "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 master)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -cdrom @var{file}
+ at findex -cdrom
+Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
+ at option{-cdrom} at the same time). You can use the host CD-ROM by
+using @file{/dev/cdrom} as filename (@pxref{host_drives}).
+ETEXI
+
+DEF("drive", HAS_ARG, QEMU_OPTION_drive,
+    "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
+    "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
+    "       [,cache=writethrough|writeback|none|unsafe][,format=f]\n"
+    "       [,serial=s][,addr=A][,id=name][,aio=threads|native]\n"
+    "       [,readonly=on|off]\n"
+    "                use 'file' as a drive image\n", QEMU_ARCH_ALL)
+STEXI
+ at item -drive @var{option}[, at var{option}[, at var{option}[,...]]]
+ at findex -drive
+
+Define a new drive. Valid options are:
+
+ at table @option
+ at item file=@var{file}
+This option defines which disk image (@pxref{disk_images}) to use with
+this drive. If the filename contains comma, you must double it
+(for instance, "file=my,,file" to use file "my,file").
+ at item if=@var{interface}
+This option defines on which type on interface the drive is connected.
+Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
+ at item bus=@var{bus},unit=@var{unit}
+These options define where is connected the drive by defining the bus number and
+the unit id.
+ at item index=@var{index}
+This option defines where is connected the drive by using an index in the list
+of available connectors of a given interface type.
+ at item media=@var{media}
+This option defines the type of the media: disk or cdrom.
+ at item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
+These options have the same definition as they have in @option{-hdachs}.
+ at item snapshot=@var{snapshot}
+ at var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}).
+ at item cache=@var{cache}
+ at var{cache} is "none", "writeback", "unsafe", or "writethrough" and controls how the host cache is used to access block data.
+ at item aio=@var{aio}
+ at var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO.
+ at item format=@var{format}
+Specify which disk @var{format} will be used rather than detecting
+the format.  Can be used to specifiy format=raw to avoid interpreting
+an untrusted format header.
+ at item serial=@var{serial}
+This option specifies the serial number to assign to the device.
+ at item addr=@var{addr}
+Specify the controller's PCI address (if=virtio only).
+ at item werror=@var{action},rerror=@var{action}
+Specify which @var{action} to take on write and read errors. Valid actions are:
+"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
+"report" (report the error to the guest), "enospc" (pause QEMU only if the
+host disk is full; report the error to the guest otherwise).
+The default setting is @option{werror=enospc} and @option{rerror=report}.
+ at item readonly
+Open drive @option{file} as read-only. Guest write attempts will fail.
+ at end table
+
+By default, writethrough caching is used for all block device.  This means that
+the host page cache will be used to read and write data but write notification
+will be sent to the guest only when the data has been reported as written by
+the storage subsystem.
+
+Writeback caching will report data writes as completed as soon as the data is
+present in the host page cache.  This is safe as long as you trust your host.
+If your host crashes or loses power, then the guest may experience data
+corruption.
+
+The host page cache can be avoided entirely with @option{cache=none}.  This will
+attempt to do disk IO directly to the guests memory.  QEMU may still perform
+an internal copy of the data.
+
+Some block drivers perform badly with @option{cache=writethrough}, most notably,
+qcow2.  If performance is more important than correctness,
+ at option{cache=writeback} should be used with qcow2.
+
+In case you don't care about data integrity over host failures, use
+cache=unsafe. This option tells qemu that it never needs to write any data
+to the disk but can instead keeps things in cache. If anything goes wrong,
+like your host losing power, the disk storage getting disconnected accidently,
+etc. you're image will most probably be rendered unusable.   When using
+the @option{-snapshot} option, unsafe caching is always used.
+
+Instead of @option{-cdrom} you can use:
+ at example
+qemu -drive file=file,index=2,media=cdrom
+ at end example
+
+Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can
+use:
+ at example
+qemu -drive file=file,index=0,media=disk
+qemu -drive file=file,index=1,media=disk
+qemu -drive file=file,index=2,media=disk
+qemu -drive file=file,index=3,media=disk
+ at end example
+
+You can connect a CDROM to the slave of ide0:
+ at example
+qemu -drive file=file,if=ide,index=1,media=cdrom
+ at end example
+
+If you don't specify the "file=" argument, you define an empty drive:
+ at example
+qemu -drive if=ide,index=1,media=cdrom
+ at end example
+
+You can connect a SCSI disk with unit ID 6 on the bus #0:
+ at example
+qemu -drive file=file,if=scsi,bus=0,unit=6
+ at end example
+
+Instead of @option{-fda}, @option{-fdb}, you can use:
+ at example
+qemu -drive file=file,index=0,if=floppy
+qemu -drive file=file,index=1,if=floppy
+ at end example
+
+By default, @var{interface} is "ide" and @var{index} is automatically
+incremented:
+ at example
+qemu -drive file=a -drive file=b"
+ at end example
+is interpreted like:
+ at example
+qemu -hda a -hdb b
+ at end example
+ETEXI
+
+DEF("set", HAS_ARG, QEMU_OPTION_set,
+    "-set group.id.arg=value\n"
+    "                set <arg> parameter for item <id> of type <group>\n"
+    "                i.e. -set drive.$id.file=/path/to/image\n", QEMU_ARCH_ALL)
+STEXI
+ at item -set
+ at findex -set
+TODO
+ETEXI
+
+DEF("global", HAS_ARG, QEMU_OPTION_global,
+    "-global driver.property=value\n"
+    "                set a global default for a driver property\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -global
+ at findex -global
+TODO
+ETEXI
+
+DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock,
+    "-mtdblock file  use 'file' as on-board Flash memory image\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -mtdblock @var{file}
+ at findex -mtdblock
+Use @var{file} as on-board Flash memory image.
+ETEXI
+
+DEF("sd", HAS_ARG, QEMU_OPTION_sd,
+    "-sd file        use 'file' as SecureDigital card image\n", QEMU_ARCH_ALL)
+STEXI
+ at item -sd @var{file}
+ at findex -sd
+Use @var{file} as SecureDigital card image.
+ETEXI
+
+DEF("pflash", HAS_ARG, QEMU_OPTION_pflash,
+    "-pflash file    use 'file' as a parallel flash image\n", QEMU_ARCH_ALL)
+STEXI
+ at item -pflash @var{file}
+ at findex -pflash
+Use @var{file} as a parallel flash image.
+ETEXI
+
+DEF("boot", HAS_ARG, QEMU_OPTION_boot,
+    "-boot [order=drives][,once=drives][,menu=on|off]\n"
+    "                'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off]
+ at findex -boot
+Specify boot order @var{drives} as a string of drive letters. Valid
+drive letters depend on the target achitecture. The x86 PC uses: a, b
+(floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot
+from network adapter 1-4), hard disk boot is the default. To apply a
+particular boot order only on the first startup, specify it via
+ at option{once}.
+
+Interactive boot menus/prompts can be enabled via @option{menu=on} as far
+as firmware/BIOS supports them. The default is non-interactive boot.
+
+ at example
+# try to boot from network first, then from hard disk
+qemu -boot order=nc
+# boot from CD-ROM first, switch back to default order after reboot
+qemu -boot once=d
+ at end example
+
+Note: The legacy format '-boot @var{drives}' is still supported but its
+use is discouraged as it may be removed from future versions.
+ETEXI
+
+DEF("snapshot", 0, QEMU_OPTION_snapshot,
+    "-snapshot       write to temporary files instead of disk image files\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -snapshot
+ at findex -snapshot
+Write to temporary files instead of disk image files. In this case,
+the raw disk image you use is not written back. You can however force
+the write back by pressing @key{C-a s} (@pxref{disk_images}).
+ETEXI
+
+DEF("m", HAS_ARG, QEMU_OPTION_m,
+    "-m megs         set virtual RAM size to megs MB [default="
+    stringify(DEFAULT_RAM_SIZE) "]\n", QEMU_ARCH_ALL)
+STEXI
+ at item -m @var{megs}
+ at findex -m
+Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB.  Optionally,
+a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
+gigabytes respectively.
+ETEXI
+
+DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
+    "-mem-path FILE  provide backing storage for guest RAM\n", QEMU_ARCH_ALL)
+STEXI
+ at item -mem-path @var{path}
+Allocate guest RAM from a temporarily created file in @var{path}.
+ETEXI
+
+#ifdef MAP_POPULATE
+DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc,
+    "-mem-prealloc   preallocate guest memory (use with -mem-path)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -mem-prealloc
+Preallocate memory when using -mem-path.
+ETEXI
+#endif
+
+DEF("k", HAS_ARG, QEMU_OPTION_k,
+    "-k language     use keyboard layout (for example 'fr' for French)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -k @var{language}
+ at findex -k
+Use keyboard layout @var{language} (for example @code{fr} for
+French). This option is only needed where it is not easy to get raw PC
+keycodes (e.g. on Macs, with some X11 servers or with a VNC
+display). You don't normally need to use it on PC/Linux or PC/Windows
+hosts.
+
+The available layouts are:
+ at example
+ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
+da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
+de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
+ at end example
+
+The default is @code{en-us}.
+ETEXI
+
+
+DEF("audio-help", 0, QEMU_OPTION_audio_help,
+    "-audio-help     print list of audio drivers and their options\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -audio-help
+ at findex -audio-help
+Will show the audio subsystem help: list of drivers, tunable
+parameters.
+ETEXI
+
+DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw,
+    "-soundhw c1,... enable audio support\n"
+    "                and only specified sound cards (comma separated list)\n"
+    "                use -soundhw ? to get the list of supported cards\n"
+    "                use -soundhw all to enable all of them\n", QEMU_ARCH_ALL)
+STEXI
+ at item -soundhw @var{card1}[, at var{card2},...] or -soundhw all
+ at findex -soundhw
+Enable audio and selected sound hardware. Use ? to print all
+available sound hardware.
+
+ at example
+qemu -soundhw sb16,adlib disk.img
+qemu -soundhw es1370 disk.img
+qemu -soundhw ac97 disk.img
+qemu -soundhw hda disk.img
+qemu -soundhw all disk.img
+qemu -soundhw ?
+ at end example
+
+Note that Linux's i810_audio OSS kernel (for AC97) module might
+require manually specifying clocking.
+
+ at example
+modprobe i810_audio clocking=48000
+ at end example
+ETEXI
+
+STEXI
+ at end table
+ETEXI
+
+DEF("usb", 0, QEMU_OPTION_usb,
+    "-usb            enable the USB driver (will be the default soon)\n",
+    QEMU_ARCH_ALL)
+STEXI
+USB options:
+ at table @option
+
+ at item -usb
+ at findex -usb
+Enable the USB driver (will be the default soon)
+ETEXI
+
+DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice,
+    "-usbdevice name add the host or guest USB device 'name'\n",
+    QEMU_ARCH_ALL)
+STEXI
+
+ at item -usbdevice @var{devname}
+ at findex -usbdevice
+Add the USB device @var{devname}. @xref{usb_devices}.
+
+ at table @option
+
+ at item mouse
+Virtual Mouse. This will override the PS/2 mouse emulation when activated.
+
+ at item tablet
+Pointer device that uses absolute coordinates (like a touchscreen). This
+means qemu is able to report the mouse position without having to grab the
+mouse. Also overrides the PS/2 mouse emulation when activated.
+
+ at item disk:[format=@var{format}]:@var{file}
+Mass storage device based on file. The optional @var{format} argument
+will be used rather than detecting the format. Can be used to specifiy
+ at code{format=raw} to avoid interpreting an untrusted format header.
+
+ at item host:@var{bus}. at var{addr}
+Pass through the host device identified by @var{bus}. at var{addr} (Linux only).
+
+ at item host:@var{vendor_id}:@var{product_id}
+Pass through the host device identified by @var{vendor_id}:@var{product_id}
+(Linux only).
+
+ at item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev}
+Serial converter to host character device @var{dev}, see @code{-serial} for the
+available devices.
+
+ at item braille
+Braille device.  This will use BrlAPI to display the braille output on a real
+or fake device.
+
+ at item net:@var{options}
+Network adapter that supports CDC ethernet and RNDIS protocols.
+
+ at end table
+ETEXI
+
+DEF("device", HAS_ARG, QEMU_OPTION_device,
+    "-device driver[,prop[=value][,...]]\n"
+    "                add device (based on driver)\n"
+    "                prop=value,... sets driver properties\n"
+    "                use -device ? to print all possible drivers\n"
+    "                use -device driver,? to print all possible properties\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -device @var{driver}[, at var{prop}[=@var{value}][,...]]
+ at findex -device
+Add device @var{driver}.  @var{prop}=@var{value} sets driver
+properties.  Valid properties depend on the driver.  To get help on
+possible drivers and properties, use @code{-device ?} and
+ at code{-device @var{driver},?}.
+ETEXI
+
+DEFHEADING(File system options:)
+
+DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
+    "-fsdev local,id=id,path=path,security_model=[mapped|passthrough|none]\n",
+    QEMU_ARCH_ALL)
+
+STEXI
+
+The general form of a File system device option is:
+ at table @option
+
+ at item -fsdev @var{fstype} ,id=@var{id} [, at var{options}]
+ at findex -fsdev
+Fstype is one of:
+ at option{local},
+The specific Fstype will determine the applicable options.
+
+Options to each backend are described below.
+
+ at item -fsdev local ,id=@var{id} ,path=@var{path} ,security_model=@var{security_model}
+
+Create a file-system-"device" for local-filesystem.
+
+ at option{local} is only available on Linux.
+
+ at option{path} specifies the path to be exported. @option{path} is required.
+
+ at option{security_model} specifies the security model to be followed.
+ at option{security_model} is required.
+
+ at end table
+ETEXI
+
+DEFHEADING(Virtual File system pass-through options:)
+
+DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
+    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n",
+    QEMU_ARCH_ALL)
+
+STEXI
+
+The general form of a Virtual File system pass-through option is:
+ at table @option
+
+ at item -virtfs @var{fstype} [, at var{options}]
+ at findex -virtfs
+Fstype is one of:
+ at option{local},
+The specific Fstype will determine the applicable options.
+
+Options to each backend are described below.
+
+ at item -virtfs local ,path=@var{path} ,mount_tag=@var{mount_tag} ,security_model=@var{security_model}
+
+Create a Virtual file-system-pass through for local-filesystem.
+
+ at option{local} is only available on Linux.
+
+ at option{path} specifies the path to be exported. @option{path} is required.
+
+ at option{security_model} specifies the security model to be followed.
+ at option{security_model} is required.
+
+
+ at option{mount_tag} specifies the tag with which the exported file is mounted.
+ at option{mount_tag} is required.
+
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEF("name", HAS_ARG, QEMU_OPTION_name,
+    "-name string1[,process=string2]\n"
+    "                set the name of the guest\n"
+    "                string1 sets the window title and string2 the process name (on Linux)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -name @var{name}
+ at findex -name
+Sets the @var{name} of the guest.
+This name will be displayed in the SDL window caption.
+The @var{name} will also be used for the VNC server.
+Also optionally set the top visible process name in Linux.
+ETEXI
+
+DEF("uuid", HAS_ARG, QEMU_OPTION_uuid,
+    "-uuid %08x-%04x-%04x-%04x-%012x\n"
+    "                specify machine UUID\n", QEMU_ARCH_ALL)
+STEXI
+ at item -uuid @var{uuid}
+ at findex -uuid
+Set system UUID.
+ETEXI
+
+STEXI
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Display options:)
+
+STEXI
+ at table @option
+ETEXI
+
+DEF("display", HAS_ARG, QEMU_OPTION_display,
+    "-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off]\n"
+    "            [,window_close=on|off]|curses|none|\n"
+    "            vnc=<display>[,<optargs>]\n"
+    "                select display type\n", QEMU_ARCH_ALL)
+STEXI
+ at item -display @var{type}
+ at findex -display
+Select type of display to use. This option is a replacement for the
+old style -sdl/-curses/... options. Valid values for @var{type} are
+ at table @option
+ at item sdl
+Display video output via SDL (usually in a separate graphics
+window; see the SDL documentation for other possibilities).
+ at item curses
+Display video output via curses. For graphics device models which
+support a text mode, QEMU can display this output using a
+curses/ncurses interface. Nothing is displayed when the graphics
+device is in graphical mode or if the graphics device does not support
+a text mode. Generally only the VGA device models support text mode.
+ at item none
+Do not display video output. The guest will still see an emulated
+graphics card, but its output will not be displayed to the QEMU
+user. This option differs from the -nographic option in that it
+only affects what is done with video output; -nographic also changes
+the destination of the serial and parallel port data.
+ at item vnc
+Start a VNC server on display <arg>
+ at end table
+ETEXI
+
+DEF("nographic", 0, QEMU_OPTION_nographic,
+    "-nographic      disable graphical output and redirect serial I/Os to console\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -nographic
+ at findex -nographic
+Normally, QEMU uses SDL to display the VGA output. With this option,
+you can totally disable graphical output so that QEMU is a simple
+command line application. The emulated serial port is redirected on
+the console. Therefore, you can still use QEMU to debug a Linux kernel
+with a serial console.
+ETEXI
+
+DEF("curses", 0, QEMU_OPTION_curses,
+    "-curses         use a curses/ncurses interface instead of SDL\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -curses
+ at findex curses
+Normally, QEMU uses SDL to display the VGA output.  With this option,
+QEMU can display the VGA output when in text mode using a
+curses/ncurses interface.  Nothing is displayed in graphical mode.
+ETEXI
+
+DEF("no-frame", 0, QEMU_OPTION_no_frame,
+    "-no-frame       open SDL window without a frame and window decorations\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -no-frame
+ at findex -no-frame
+Do not use decorations for SDL windows and start them using the whole
+available screen space. This makes the using QEMU in a dedicated desktop
+workspace more convenient.
+ETEXI
+
+DEF("alt-grab", 0, QEMU_OPTION_alt_grab,
+    "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -alt-grab
+ at findex -alt-grab
+Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). Note that this also
+affects the special keys (for fullscreen, monitor-mode switching, etc).
+ETEXI
+
+DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab,
+    "-ctrl-grab      use Right-Ctrl to grab mouse (instead of Ctrl-Alt)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -ctrl-grab
+ at findex -ctrl-grab
+Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). Note that this also
+affects the special keys (for fullscreen, monitor-mode switching, etc).
+ETEXI
+
+DEF("no-quit", 0, QEMU_OPTION_no_quit,
+    "-no-quit        disable SDL window close capability\n", QEMU_ARCH_ALL)
+STEXI
+ at item -no-quit
+ at findex -no-quit
+Disable SDL window close capability.
+ETEXI
+
+DEF("sdl", 0, QEMU_OPTION_sdl,
+    "-sdl            enable SDL\n", QEMU_ARCH_ALL)
+STEXI
+ at item -sdl
+ at findex -sdl
+Enable SDL.
+ETEXI
+
+DEF("spice", HAS_ARG, QEMU_OPTION_spice,
+    "-spice <args>   enable spice\n", QEMU_ARCH_ALL)
+STEXI
+ at item -spice @var{option}[, at var{option}[,...]]
+ at findex -spice
+Enable the spice remote desktop protocol. Valid options are
+
+ at table @option
+
+ at item port=<nr>
+Set the TCP port spice is listening on for plaintext channels.
+
+ at item addr=<addr>
+Set the IP address spice is listening on.  Default is any address.
+
+ at item ipv4
+ at item ipv6
+Force using the specified IP version.
+
+ at item password=<secret>
+Set the password you need to authenticate.
+
+ at item sasl
+Require that the client use SASL to authenticate with the spice.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials.
+
+ at item disable-ticketing
+Allow client connects without authentication.
+
+ at item disable-copy-paste
+Disable copy paste between the client and the guest.
+
+ at item tls-port=<nr>
+Set the TCP port spice is listening on for encrypted channels.
+
+ at item x509-dir=<dir>
+Set the x509 file directory. Expects same filenames as -vnc $display,x509=$dir
+
+ at item x509-key-file=<file>
+ at item x509-key-password=<file>
+ at item x509-cert-file=<file>
+ at item x509-cacert-file=<file>
+ at item x509-dh-key-file=<file>
+The x509 file names can also be configured individually.
+
+ at item tls-ciphers=<list>
+Specify which ciphers to use.
+
+ at item tls-channel=[main|display|inputs|record|playback|tunnel]
+ at item plaintext-channel=[main|display|inputs|record|playback|tunnel]
+Force specific channel to be used with or without TLS encryption.  The
+options can be specified multiple times to configure multiple
+channels.  The special name "default" can be used to set the default
+mode.  For channels which are not explicitly forced into one mode the
+spice client is allowed to pick tls/plaintext as he pleases.
+
+ at item image-compression=[auto_glz|auto_lz|quic|glz|lz|off]
+Configure image compression (lossless).
+Default is auto_glz.
+
+ at item jpeg-wan-compression=[auto|never|always]
+ at item zlib-glz-wan-compression=[auto|never|always]
+Configure wan image compression (lossy for slow links).
+Default is auto.
+
+ at item streaming-video=[off|all|filter]
+Configure video stream detection.  Default is filter.
+
+ at item agent-mouse=[on|off]
+Enable/disable passing mouse events via vdagent.  Default is on.
+
+ at item playback-compression=[on|off]
+Enable/disable audio stream compression (using celt 0.5.1).  Default is on.
+
+ at end table
+ETEXI
+
+DEF("portrait", 0, QEMU_OPTION_portrait,
+    "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -portrait
+ at findex -portrait
+Rotate graphical output 90 deg left (only PXA LCD).
+ETEXI
+
+DEF("rotate", HAS_ARG, QEMU_OPTION_rotate,
+    "-rotate <deg>   rotate graphical output some deg left (only PXA LCD)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -rotate
+ at findex -rotate
+Rotate graphical output some deg left (only PXA LCD).
+ETEXI
+
+DEF("vga", HAS_ARG, QEMU_OPTION_vga,
+    "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
+    "                select video card type\n", QEMU_ARCH_ALL)
+STEXI
+ at item -vga @var{type}
+ at findex -vga
+Select type of VGA card to emulate. Valid values for @var{type} are
+ at table @option
+ at item cirrus
+Cirrus Logic GD5446 Video card. All Windows versions starting from
+Windows 95 should recognize and use this graphic card. For optimal
+performances, use 16 bit color depth in the guest and the host OS.
+(This one is the default)
+ at item std
+Standard VGA card with Bochs VBE extensions.  If your guest OS
+supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want
+to use high resolution modes (>= 1280x1024x16) then you should use
+this option.
+ at item vmware
+VMWare SVGA-II compatible adapter. Use it if you have sufficiently
+recent XFree86/XOrg server or Windows guest with a driver for this
+card.
+ at item qxl
+QXL paravirtual graphic card.  It is VGA compatible (including VESA
+2.0 VBE support).  Works best with qxl guest drivers installed though.
+Recommended choice when using the spice protocol.
+ at item none
+Disable VGA card.
+ at end table
+ETEXI
+
+DEF("full-screen", 0, QEMU_OPTION_full_screen,
+    "-full-screen    start in full screen\n", QEMU_ARCH_ALL)
+STEXI
+ at item -full-screen
+ at findex -full-screen
+Start in full screen.
+ETEXI
+
+DEF("g", 1, QEMU_OPTION_g ,
+    "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n",
+    QEMU_ARCH_PPC | QEMU_ARCH_SPARC)
+STEXI
+ at item -g @var{width}x at var{height}[x at var{depth}]
+ at findex -g
+Set the initial graphical resolution and depth (PPC, SPARC only).
+ETEXI
+
+DEF("vnc", HAS_ARG, QEMU_OPTION_vnc ,
+    "-vnc display    start a VNC server on display\n", QEMU_ARCH_ALL)
+STEXI
+ at item -vnc @var{display}[, at var{option}[, at var{option}[,...]]]
+ at findex -vnc
+Normally, QEMU uses SDL to display the VGA output.  With this option,
+you can have QEMU listen on VNC display @var{display} and redirect the VGA
+display over the VNC session.  It is very useful to enable the usb
+tablet device when using this option (option @option{-usbdevice
+tablet}). When using the VNC display, you must use the @option{-k}
+parameter to set the keyboard layout if you are not using en-us. Valid
+syntax for the @var{display} is
+
+ at table @option
+
+ at item @var{host}:@var{d}
+
+TCP connections will only be allowed from @var{host} on display @var{d}.
+By convention the TCP port is 5900+ at var{d}. Optionally, @var{host} can
+be omitted in which case the server will accept connections from any host.
+
+ at item unix:@var{path}
+
+Connections will be allowed over UNIX domain sockets where @var{path} is the
+location of a unix socket to listen for connections on.
+
+ at item none
+
+VNC is initialized but not started. The monitor @code{change} command
+can be used to later start the VNC server.
+
+ at end table
+
+Following the @var{display} value there may be one or more @var{option} flags
+separated by commas. Valid options are
+
+ at table @option
+
+ at item reverse
+
+Connect to a listening VNC client via a ``reverse'' connection. The
+client is specified by the @var{display}. For reverse network
+connections (@var{host}:@var{d}, at code{reverse}), the @var{d} argument
+is a TCP port number, not a display number.
+
+ at item password
+
+Require that password based authentication is used for client connections.
+The password must be set separately using the @code{change} command in the
+ at ref{pcsys_monitor}
+
+ at item tls
+
+Require that client use TLS when communicating with the VNC server. This
+uses anonymous TLS credentials so is susceptible to a man-in-the-middle
+attack. It is recommended that this option be combined with either the
+ at option{x509} or @option{x509verify} options.
+
+ at item x509=@var{/path/to/certificate/dir}
+
+Valid if @option{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client. It is recommended that a password be set on the VNC server
+to provide authentication of the client when this is used. The path following
+this option specifies where the x509 certificates are to be loaded from.
+See the @ref{vnc_security} section for details on generating certificates.
+
+ at item x509verify=@var{/path/to/certificate/dir}
+
+Valid if @option{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client, and request that the client send its own x509 certificate.
+The server will validate the client's certificate against the CA certificate,
+and reject clients when validation fails. If the certificate authority is
+trusted, this is a sufficient authentication mechanism. You may still wish
+to set a password on the VNC server as a second authentication layer. The
+path following this option specifies where the x509 certificates are to
+be loaded from. See the @ref{vnc_security} section for details on generating
+certificates.
+
+ at item sasl
+
+Require that the client use SASL to authenticate with the VNC server.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials. See the @ref{vnc_security} section for details on using
+SASL authentication.
+
+ at item acl
+
+Turn on access control lists for checking of the x509 client certificate
+and SASL party. For x509 certs, the ACL check is made against the
+certificate's distinguished name. This is something that looks like
+ at code{C=GB,O=ACME,L=Boston,CN=bob}. For SASL party, the ACL check is
+made against the username, which depending on the SASL plugin, may
+include a realm component, eg @code{bob} or @code{bob@@EXAMPLE.COM}.
+When the @option{acl} flag is set, the initial access list will be
+empty, with a @code{deny} policy. Thus no one will be allowed to
+use the VNC server until the ACLs have been loaded. This can be
+achieved using the @code{acl} monitor command.
+
+ at item lossy
+
+Enable lossy compression methods (gradient, JPEG, ...). If this
+option is set, VNC client may receive lossy framebuffer updates
+depending on its encoding settings. Enabling this option can save
+a lot of bandwidth at the expense of quality.
+
+ at item non-adaptive
+
+Disable adaptive encodings. Adaptive encodings are enabled by default.
+An adaptive encoding will try to detect frequently updated screen regions,
+and send updates in these regions using a lossy encoding (like JPEG).
+This can be really helpful to save bandwidth when playing videos. Disabling
+adaptive encodings allows to restore the original static behavior of encodings
+like Tight.
+
+ at end table
+ETEXI
+
+STEXI
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(i386 target only:)
+STEXI
+ at table @option
+ETEXI
+
+DEF("win2k-hack", 0, QEMU_OPTION_win2k_hack,
+    "-win2k-hack     use it when installing Windows 2000 to avoid a disk full bug\n",
+    QEMU_ARCH_I386)
+STEXI
+ at item -win2k-hack
+ at findex -win2k-hack
+Use it when installing Windows 2000 to avoid a disk full bug. After
+Windows 2000 is installed, you no longer need this option (this option
+slows down the IDE transfers).
+ETEXI
+
+HXCOMM Deprecated by -rtc
+DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, "", QEMU_ARCH_I386)
+
+DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk,
+    "-no-fd-bootchk  disable boot signature checking for floppy disks\n",
+    QEMU_ARCH_I386)
+STEXI
+ at item -no-fd-bootchk
+ at findex -no-fd-bootchk
+Disable boot signature checking for floppy disks in Bochs BIOS. It may
+be needed to boot from old floppy disks.
+TODO: check reference to Bochs BIOS.
+ETEXI
+
+DEF("no-acpi", 0, QEMU_OPTION_no_acpi,
+           "-no-acpi        disable ACPI\n", QEMU_ARCH_I386)
+STEXI
+ at item -no-acpi
+ at findex -no-acpi
+Disable ACPI (Advanced Configuration and Power Interface) support. Use
+it if your guest OS complains about ACPI problems (PC target machine
+only).
+ETEXI
+
+DEF("no-hpet", 0, QEMU_OPTION_no_hpet,
+    "-no-hpet        disable HPET\n", QEMU_ARCH_I386)
+STEXI
+ at item -no-hpet
+ at findex -no-hpet
+Disable HPET support.
+ETEXI
+
+DEF("balloon", HAS_ARG, QEMU_OPTION_balloon,
+    "-balloon none   disable balloon device\n"
+    "-balloon virtio[,addr=str]\n"
+    "                enable virtio balloon device (default)\n", QEMU_ARCH_ALL)
+STEXI
+ at item -balloon none
+ at findex -balloon
+Disable balloon device.
+ at item -balloon virtio[,addr=@var{addr}]
+Enable virtio balloon device (default), optionally with PCI address
+ at var{addr}.
+ETEXI
+
+DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable,
+    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
+    "                ACPI table description\n", QEMU_ARCH_I386)
+STEXI
+ at item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...]
+ at findex -acpitable
+Add ACPI table with specified header fields and context from specified files.
+ETEXI
+
+DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
+    "-smbios file=binary\n"
+    "                load SMBIOS entry from binary file\n"
+    "-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d]\n"
+    "                specify SMBIOS type 0 fields\n"
+    "-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]\n"
+    "              [,uuid=uuid][,sku=str][,family=str]\n"
+    "                specify SMBIOS type 1 fields\n", QEMU_ARCH_I386)
+STEXI
+ at item -smbios file=@var{binary}
+ at findex -smbios
+Load SMBIOS entry from binary file.
+
+ at item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}]
+ at findex -smbios
+Specify SMBIOS type 0 fields
+
+ at item -smbios type=1[,manufacturer=@var{str}][,product=@var{str}] [,version=@var{str}][,serial=@var{str}][,uuid=@var{uuid}][,sku=@var{str}] [,family=@var{str}]
+Specify SMBIOS type 1 fields
+ETEXI
+
+DEFHEADING()
+STEXI
+ at end table
+ETEXI
+
+DEFHEADING(Network options:)
+STEXI
+ at table @option
+ETEXI
+
+HXCOMM Legacy slirp options (now moved to -net user):
+#ifdef CONFIG_SLIRP
+DEF("tftp", HAS_ARG, QEMU_OPTION_tftp, "", QEMU_ARCH_ALL)
+DEF("bootp", HAS_ARG, QEMU_OPTION_bootp, "", QEMU_ARCH_ALL)
+DEF("redir", HAS_ARG, QEMU_OPTION_redir, "", QEMU_ARCH_ALL)
+#ifndef _WIN32
+DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
+#endif
+#endif
+
+DEF("net", HAS_ARG, QEMU_OPTION_net,
+    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
+    "                create a new Network Interface Card and connect it to VLAN 'n'\n"
+#ifdef CONFIG_SLIRP
+    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
+    "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
+    "         [,hostfwd=rule][,guestfwd=rule]"
+#ifndef _WIN32
+                                             "[,smb=dir[,smbserver=addr]]\n"
+#endif
+    "                connect the user mode network stack to VLAN 'n', configure its\n"
+    "                DHCP server and enabled optional services\n"
+#endif
+#ifdef _WIN32
+    "-net tap[,vlan=n][,name=str],ifname=name\n"
+    "                connect the host TAP network interface to VLAN 'n'\n"
+#else
+    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+    "                connect the host TAP network interface to VLAN 'n' and use the\n"
+    "                network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
+    "                and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+    "                use '[down]script=no' to disable script execution\n"
+    "                use 'fd=h' to connect to an already opened TAP interface\n"
+    "                use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
+    "                default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
+    "                use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag\n"
+    "                use vnet_hdr=on to make the lack of IFF_VNET_HDR support an error condition\n"
+    "                use vhost=on to enable experimental in kernel accelerator\n"
+    "                    (only has effect for virtio guests which use MSIX)\n"
+    "                use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
+    "                use 'vhostfd=h' to connect to an already opened vhost net device\n"
+#endif
+    "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
+    "                connect the vlan 'n' to another VLAN using a socket connection\n"
+    "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port[,localaddr=addr]]\n"
+    "                connect the vlan 'n' to multicast maddr and port\n"
+    "                use 'localaddr=addr' to specify the host address to send packets from\n"
+#ifdef CONFIG_VDE
+    "-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
+    "                connect the vlan 'n' to port 'n' of a vde switch running\n"
+    "                on host and listening for incoming connections on 'socketpath'.\n"
+    "                Use group 'groupname' and mode 'octalmode' to change default\n"
+    "                ownership and permissions for communication port.\n"
+#endif
+    "-net dump[,vlan=n][,file=f][,len=n]\n"
+    "                dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n"
+    "-net none       use it alone to have zero network devices. If no -net option\n"
+    "                is provided, the default is '-net nic -net user'\n", QEMU_ARCH_ALL)
+DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
+    "-netdev ["
+#ifdef CONFIG_SLIRP
+    "user|"
+#endif
+    "tap|"
+#ifdef CONFIG_VDE
+    "vde|"
+#endif
+    "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
+STEXI
+ at item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
+ at findex -net
+Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
+= 0 is the default). The NIC is an e1000 by default on the PC
+target. Optionally, the MAC address can be changed to @var{mac}, the
+device address set to @var{addr} (PCI cards only),
+and a @var{name} can be assigned for use in monitor commands.
+Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
+that the card should have; this option currently only affects virtio cards; set
+ at var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
+NIC is created.  Qemu can emulate several different models of network card.
+Valid values for @var{type} are
+ at code{virtio}, @code{i82551}, @code{i82557b}, @code{i82559er},
+ at code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139},
+ at code{e1000}, @code{smc91c111}, @code{lance} and @code{mcf_fec}.
+Not all devices are supported on all targets.  Use -net nic,model=?
+for a list of available devices for your target.
+
+ at item -net user[, at var{option}][, at var{option}][,...]
+Use the user mode network stack which requires no administrator
+privilege to run. Valid options are:
+
+ at table @option
+ at item vlan=@var{n}
+Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
+
+ at item name=@var{name}
+Assign symbolic name for use in monitor commands.
+
+ at item net=@var{addr}[/@var{mask}]
+Set IP network address the guest will see. Optionally specify the netmask,
+either in the form a.b.c.d or as number of valid top-most bits. Default is
+10.0.2.0/24.
+
+ at item host=@var{addr}
+Specify the guest-visible address of the host. Default is the 2nd IP in the
+guest network, i.e. x.x.x.2.
+
+ at item restrict=on|off
+If this option is enabled, the guest will be isolated, i.e. it will not be
+able to contact the host and no guest IP packets will be routed over the host
+to the outside. This option does not affect any explicitly set forwarding rules.
+
+ at item hostname=@var{name}
+Specifies the client hostname reported by the builtin DHCP server.
+
+ at item dhcpstart=@var{addr}
+Specify the first of the 16 IPs the built-in DHCP server can assign. Default
+is the 15th to 31st IP in the guest network, i.e. x.x.x.15 to x.x.x.31.
+
+ at item dns=@var{addr}
+Specify the guest-visible address of the virtual nameserver. The address must
+be different from the host address. Default is the 3rd IP in the guest network,
+i.e. x.x.x.3.
+
+ at item tftp=@var{dir}
+When using the user mode network stack, activate a built-in TFTP
+server. The files in @var{dir} will be exposed as the root of a TFTP server.
+The TFTP client on the guest must be configured in binary mode (use the command
+ at code{bin} of the Unix TFTP client).
+
+ at item bootfile=@var{file}
+When using the user mode network stack, broadcast @var{file} as the BOOTP
+filename. In conjunction with @option{tftp}, this can be used to network boot
+a guest from a local directory.
+
+Example (using pxelinux):
+ at example
+qemu -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
+ at end example
+
+ at item smb=@var{dir}[,smbserver=@var{addr}]
+When using the user mode network stack, activate a built-in SMB
+server so that Windows OSes can access to the host files in @file{@var{dir}}
+transparently. The IP address of the SMB server can be set to @var{addr}. By
+default the 4th IP in the guest network is used, i.e. x.x.x.4.
+
+In the guest Windows OS, the line:
+ at example
+10.0.2.4 smbserver
+ at end example
+must be added in the file @file{C:\WINDOWS\LMHOSTS} (for windows 9x/Me)
+or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000).
+
+Then @file{@var{dir}} can be accessed in @file{\\smbserver\qemu}.
+
+Note that a SAMBA server must be installed on the host OS.
+QEMU was tested successfully with smbd versions from Red Hat 9,
+Fedora Core 3 and OpenSUSE 11.x.
+
+ at item hostfwd=[tcp|udp]:[@var{hostaddr}]:@var{hostport}-[@var{guestaddr}]:@var{guestport}
+Redirect incoming TCP or UDP connections to the host port @var{hostport} to
+the guest IP address @var{guestaddr} on guest port @var{guestport}. If
+ at var{guestaddr} is not specified, its value is x.x.x.15 (default first address
+given by the built-in DHCP server). By specifying @var{hostaddr}, the rule can
+be bound to a specific host interface. If no connection type is set, TCP is
+used. This option can be given multiple times.
+
+For example, to redirect host X11 connection from screen 1 to guest
+screen 0, use the following:
+
+ at example
+# on the host
+qemu -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...]
+# this host xterm should open in the guest X11 server
+xterm -display :1
+ at end example
+
+To redirect telnet connections from host port 5555 to telnet port on
+the guest, use the following:
+
+ at example
+# on the host
+qemu -net user,hostfwd=tcp::5555-:23 [...]
+telnet localhost 5555
+ at end example
+
+Then when you use on the host @code{telnet localhost 5555}, you
+connect to the guest telnet server.
+
+ at item guestfwd=[tcp]:@var{server}:@var{port}- at var{dev}
+Forward guest TCP connections to the IP address @var{server} on port @var{port}
+to the character device @var{dev}. This option can be given multiple times.
+
+ at end table
+
+Note: Legacy stand-alone options -tftp, -bootp, -smb and -redir are still
+processed and applied to -net user. Mixing them with the new configuration
+syntax gives undefined results. Their use for new applications is discouraged
+as they will be removed from future versions.
+
+ at item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] [,script=@var{file}][,downscript=@var{dfile}]
+Connect the host TAP network interface @var{name} to VLAN @var{n}, use
+the network script @var{file} to configure it and the network script
+ at var{dfile} to deconfigure it. If @var{name} is not provided, the OS
+automatically provides one. @option{fd}=@var{h} can be used to specify
+the handle of an already opened host TAP interface. The default network
+configure script is @file{/etc/qemu-ifup} and the default network
+deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no}
+or @option{downscript=no} to disable script execution. Example:
+
+ at example
+qemu linux.img -net nic -net tap
+ at end example
+
+More complicated example (two NICs, each one connected to a TAP device)
+ at example
+qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
+               -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
+ at end example
+
+ at item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
+
+Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
+machine using a TCP socket connection. If @option{listen} is
+specified, QEMU waits for incoming connections on @var{port}
+(@var{host} is optional). @option{connect} is used to connect to
+another QEMU instance using the @option{listen} option. @option{fd}=@var{h}
+specifies an already opened TCP socket.
+
+Example:
+ at example
+# launch a first QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,listen=:1234
+# connect the VLAN 0 of this instance to the VLAN 0
+# of the first instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+               -net socket,connect=127.0.0.1:1234
+ at end example
+
+ at item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
+
+Create a VLAN @var{n} shared with another QEMU virtual
+machines using a UDP multicast socket, effectively making a bus for
+every QEMU with same multicast address @var{maddr} and @var{port}.
+NOTES:
+ at enumerate
+ at item
+Several QEMU can be running on different hosts and share same bus (assuming
+correct multicast setup for these hosts).
+ at item
+mcast support is compatible with User Mode Linux (argument @option{eth at var{N}=mcast}), see
+ at url{http://user-mode-linux.sf.net}.
+ at item
+Use @option{fd=h} to specify an already opened UDP multicast socket.
+ at end enumerate
+
+Example:
+ at example
+# launch one QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=230.0.0.1:1234
+# launch another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+               -net socket,mcast=230.0.0.1:1234
+# launch yet another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \
+               -net socket,mcast=230.0.0.1:1234
+ at end example
+
+Example (User Mode Linux compat.):
+ at example
+# launch QEMU instance (note mcast address selected
+# is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=239.192.168.1:1102
+# launch UML
+/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+ at end example
+
+Example (send packets from host's 1.2.3.4):
+ at example
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
+ at end example
+
+ at item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
+Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
+listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
+and MODE @var{octalmode} to change default ownership and permissions for
+communication port. This option is available only if QEMU has been compiled
+with vde support enabled.
+
+Example:
+ at example
+# launch vde switch
+vde_switch -F -sock /tmp/myswitch
+# launch QEMU instance
+qemu linux.img -net nic -net vde,sock=/tmp/myswitch
+ at end example
+
+ at item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
+Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
+At most @var{len} bytes (64k by default) per packet are stored. The file format is
+libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
+
+ at item -net none
+Indicate that no network devices should be configured. It is used to
+override the default configuration (@option{-net nic -net user}) which
+is activated if no @option{-net} options are provided.
+
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Character device options:)
+
+DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
+    "-chardev null,id=id[,mux=on|off]\n"
+    "-chardev socket,id=id[,host=host],port=host[,to=to][,ipv4][,ipv6][,nodelay]\n"
+    "         [,server][,nowait][,telnet][,mux=on|off] (tcp)\n"
+    "-chardev socket,id=id,path=path[,server][,nowait][,telnet],[mux=on|off] (unix)\n"
+    "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
+    "         [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n"
+    "-chardev msmouse,id=id[,mux=on|off]\n"
+    "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n"
+    "         [,mux=on|off]\n"
+    "-chardev file,id=id,path=path[,mux=on|off]\n"
+    "-chardev pipe,id=id,path=path[,mux=on|off]\n"
+#ifdef _WIN32
+    "-chardev console,id=id[,mux=on|off]\n"
+    "-chardev serial,id=id,path=path[,mux=on|off]\n"
+#else
+    "-chardev pty,id=id[,mux=on|off]\n"
+    "-chardev stdio,id=id[,mux=on|off][,signal=on|off]\n"
+#endif
+#ifdef CONFIG_BRLAPI
+    "-chardev braille,id=id[,mux=on|off]\n"
+#endif
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+        || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    "-chardev tty,id=id,path=path[,mux=on|off]\n"
+#endif
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    "-chardev parport,id=id,path=path[,mux=on|off]\n"
+#endif
+#if defined(CONFIG_SPICE)
+    "-chardev spicevmc,id=id,name=name[,debug=debug]\n"
+#endif
+    , QEMU_ARCH_ALL
+)
+
+STEXI
+
+The general form of a character device option is:
+ at table @option
+
+ at item -chardev @var{backend} ,id=@var{id} [,mux=on|off] [, at var{options}]
+ at findex -chardev
+Backend is one of:
+ at option{null},
+ at option{socket},
+ at option{udp},
+ at option{msmouse},
+ at option{vc},
+ at option{file},
+ at option{pipe},
+ at option{console},
+ at option{serial},
+ at option{pty},
+ at option{stdio},
+ at option{braille},
+ at option{tty},
+ at option{parport},
+ at option{spicevmc}.
+The specific backend will determine the applicable options.
+
+All devices must have an id, which can be any string up to 127 characters long.
+It is used to uniquely identify this device in other command line directives.
+
+A character device may be used in multiplexing mode by multiple front-ends.
+The key sequence of @key{Control-a} and @key{c} will rotate the input focus
+between attached front-ends. Specify @option{mux=on} to enable this mode.
+
+Options to each backend are described below.
+
+ at item -chardev null ,id=@var{id}
+A void device. This device will not emit any data, and will drop any data it
+receives. The null backend does not take any options.
+
+ at item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet]
+
+Create a two-way stream socket, which can be either a TCP or a unix socket. A
+unix socket will be created if @option{path} is specified. Behaviour is
+undefined if TCP options are specified for a unix socket.
+
+ at option{server} specifies that the socket shall be a listening socket.
+
+ at option{nowait} specifies that QEMU should not block waiting for a client to
+connect to a listening socket.
+
+ at option{telnet} specifies that traffic on the socket should interpret telnet
+escape sequences.
+
+TCP and unix socket options are given below:
+
+ at table @option
+
+ at item TCP options: port=@var{port} [,host=@var{host}] [,to=@var{to}] [,ipv4] [,ipv6] [,nodelay]
+
+ at option{host} for a listening socket specifies the local address to be bound.
+For a connecting socket species the remote host to connect to. @option{host} is
+optional for listening sockets. If not specified it defaults to @code{0.0.0.0}.
+
+ at option{port} for a listening socket specifies the local port to be bound. For a
+connecting socket specifies the port on the remote host to connect to.
+ at option{port} can be given as either a port number or a service name.
+ at option{port} is required.
+
+ at option{to} is only relevant to listening sockets. If it is specified, and
+ at option{port} cannot be bound, QEMU will attempt to bind to subsequent ports up
+to and including @option{to} until it succeeds. @option{to} must be specified
+as a port number.
+
+ at option{ipv4} and @option{ipv6} specify that either IPv4 or IPv6 must be used.
+If neither is specified the socket may use either protocol.
+
+ at option{nodelay} disables the Nagle algorithm.
+
+ at item unix options: path=@var{path}
+
+ at option{path} specifies the local path of the unix socket. @option{path} is
+required.
+
+ at end table
+
+ at item -chardev udp ,id=@var{id} [,host=@var{host}] ,port=@var{port} [,localaddr=@var{localaddr}] [,localport=@var{localport}] [,ipv4] [,ipv6]
+
+Sends all traffic from the guest to a remote host over UDP.
+
+ at option{host} specifies the remote host to connect to. If not specified it
+defaults to @code{localhost}.
+
+ at option{port} specifies the port on the remote host to connect to. @option{port}
+is required.
+
+ at option{localaddr} specifies the local address to bind to. If not specified it
+defaults to @code{0.0.0.0}.
+
+ at option{localport} specifies the local port to bind to. If not specified any
+available local port will be used.
+
+ at option{ipv4} and @option{ipv6} specify that either IPv4 or IPv6 must be used.
+If neither is specified the device may use either protocol.
+
+ at item -chardev msmouse ,id=@var{id}
+
+Forward QEMU's emulated msmouse events to the guest. @option{msmouse} does not
+take any options.
+
+ at item -chardev vc ,id=@var{id} [[,width=@var{width}] [,height=@var{height}]] [[,cols=@var{cols}] [,rows=@var{rows}]]
+
+Connect to a QEMU text console. @option{vc} may optionally be given a specific
+size.
+
+ at option{width} and @option{height} specify the width and height respectively of
+the console, in pixels.
+
+ at option{cols} and @option{rows} specify that the console be sized to fit a text
+console with the given dimensions.
+
+ at item -chardev file ,id=@var{id} ,path=@var{path}
+
+Log all traffic received from the guest to a file.
+
+ at option{path} specifies the path of the file to be opened. This file will be
+created if it does not already exist, and overwritten if it does. @option{path}
+is required.
+
+ at item -chardev pipe ,id=@var{id} ,path=@var{path}
+
+Create a two-way connection to the guest. The behaviour differs slightly between
+Windows hosts and other hosts:
+
+On Windows, a single duplex pipe will be created at
+ at file{\\.pipe\@option{path}}.
+
+On other hosts, 2 pipes will be created called @file{@option{path}.in} and
+ at file{@option{path}.out}. Data written to @file{@option{path}.in} will be
+received by the guest. Data written by the guest can be read from
+ at file{@option{path}.out}. QEMU will not create these fifos, and requires them to
+be present.
+
+ at option{path} forms part of the pipe path as described above. @option{path} is
+required.
+
+ at item -chardev console ,id=@var{id}
+
+Send traffic from the guest to QEMU's standard output. @option{console} does not
+take any options.
+
+ at option{console} is only available on Windows hosts.
+
+ at item -chardev serial ,id=@var{id} ,path=@option{path}
+
+Send traffic from the guest to a serial device on the host.
+
+ at option{serial} is
+only available on Windows hosts.
+
+ at option{path} specifies the name of the serial device to open.
+
+ at item -chardev pty ,id=@var{id}
+
+Create a new pseudo-terminal on the host and connect to it. @option{pty} does
+not take any options.
+
+ at option{pty} is not available on Windows hosts.
+
+ at item -chardev stdio ,id=@var{id} [,signal=on|off]
+Connect to standard input and standard output of the qemu process.
+
+ at option{signal} controls if signals are enabled on the terminal, that includes
+exiting QEMU with the key sequence @key{Control-c}. This option is enabled by
+default, use @option{signal=off} to disable it.
+
+ at option{stdio} is not available on Windows hosts.
+
+ at item -chardev braille ,id=@var{id}
+
+Connect to a local BrlAPI server. @option{braille} does not take any options.
+
+ at item -chardev tty ,id=@var{id} ,path=@var{path}
+
+Connect to a local tty device.
+
+ at option{tty} is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD and
+DragonFlyBSD hosts.
+
+ at option{path} specifies the path to the tty. @option{path} is required.
+
+ at item -chardev parport ,id=@var{id} ,path=@var{path}
+
+ at option{parport} is only available on Linux, FreeBSD and DragonFlyBSD hosts.
+
+Connect to a local parallel port.
+
+ at option{path} specifies the path to the parallel port device. @option{path} is
+required.
+
+#if defined(CONFIG_SPICE)
+ at item -chardev spicevmc ,id=@var{id} ,debug=@var{debug}, name=@var{name}
+
+ at option{debug} debug level for spicevmc
+
+ at option{name} name of spice channel to connect to
+
+Connect to a spice virtual machine channel, such as vdiport.
+#endif
+
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Bluetooth(R) options:)
+
+DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
+    "-bt hci,null    dumb bluetooth HCI - doesn't respond to commands\n" \
+    "-bt hci,host[:id]\n" \
+    "                use host's HCI with the given name\n" \
+    "-bt hci[,vlan=n]\n" \
+    "                emulate a standard HCI in virtual scatternet 'n'\n" \
+    "-bt vhci[,vlan=n]\n" \
+    "                add host computer to virtual scatternet 'n' using VHCI\n" \
+    "-bt device:dev[,vlan=n]\n" \
+    "                emulate a bluetooth device 'dev' in scatternet 'n'\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at table @option
+
+ at item -bt hci[...]
+ at findex -bt
+Defines the function of the corresponding Bluetooth HCI.  -bt options
+are matched with the HCIs present in the chosen machine type.  For
+example when emulating a machine with only one HCI built into it, only
+the first @code{-bt hci[...]} option is valid and defines the HCI's
+logic.  The Transport Layer is decided by the machine type.  Currently
+the machines @code{n800} and @code{n810} have one HCI and all other
+machines have none.
+
+ at anchor{bt-hcis}
+The following three types are recognized:
+
+ at table @option
+ at item -bt hci,null
+(default) The corresponding Bluetooth HCI assumes no internal logic
+and will not respond to any HCI commands or emit events.
+
+ at item -bt hci,host[:@var{id}]
+(@code{bluez} only) The corresponding HCI passes commands / events
+to / from the physical HCI identified by the name @var{id} (default:
+ at code{hci0}) on the computer running QEMU.  Only available on @code{bluez}
+capable systems like Linux.
+
+ at item -bt hci[,vlan=@var{n}]
+Add a virtual, standard HCI that will participate in the Bluetooth
+scatternet @var{n} (default @code{0}).  Similarly to @option{-net}
+VLANs, devices inside a bluetooth network @var{n} can only communicate
+with other devices in the same network (scatternet).
+ at end table
+
+ at item -bt vhci[,vlan=@var{n}]
+(Linux-host only) Create a HCI in scatternet @var{n} (default 0) attached
+to the host bluetooth stack instead of to the emulated target.  This
+allows the host and target machines to participate in a common scatternet
+and communicate.  Requires the Linux @code{vhci} driver installed.  Can
+be used as following:
+
+ at example
+qemu [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
+ at end example
+
+ at item -bt device:@var{dev}[,vlan=@var{n}]
+Emulate a bluetooth device @var{dev} and place it in network @var{n}
+(default @code{0}).  QEMU can only emulate one type of bluetooth devices
+currently:
+
+ at table @option
+ at item keyboard
+Virtual wireless keyboard implementing the HIDP bluetooth profile.
+ at end table
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Linux/Multiboot boot specific:)
+STEXI
+
+When using these options, you can use a given Linux or Multiboot
+kernel without installing it in the disk image. It can be useful
+for easier testing of various kernels.
+
+ at table @option
+ETEXI
+
+DEF("kernel", HAS_ARG, QEMU_OPTION_kernel, \
+    "-kernel bzImage use 'bzImage' as kernel image\n", QEMU_ARCH_ALL)
+STEXI
+ at item -kernel @var{bzImage}
+ at findex -kernel
+Use @var{bzImage} as kernel image. The kernel can be either a Linux kernel
+or in multiboot format.
+ETEXI
+
+DEF("append", HAS_ARG, QEMU_OPTION_append, \
+    "-append cmdline use 'cmdline' as kernel command line\n", QEMU_ARCH_ALL)
+STEXI
+ at item -append @var{cmdline}
+ at findex -append
+Use @var{cmdline} as kernel command line
+ETEXI
+
+DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
+           "-initrd file    use 'file' as initial ram disk\n", QEMU_ARCH_ALL)
+STEXI
+ at item -initrd @var{file}
+ at findex -initrd
+Use @var{file} as initial ram disk.
+
+ at item -initrd "@var{file1} arg=foo, at var{file2}"
+
+This syntax is only available with multiboot.
+
+Use @var{file1} and @var{file2} as modules and pass arg=foo as parameter to the
+first module.
+ETEXI
+
+STEXI
+ at end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Debug/Expert options:)
+
+STEXI
+ at table @option
+ETEXI
+
+DEF("serial", HAS_ARG, QEMU_OPTION_serial, \
+    "-serial dev     redirect the serial port to char device 'dev'\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -serial @var{dev}
+ at findex -serial
+Redirect the virtual serial port to host character device
+ at var{dev}. The default device is @code{vc} in graphical mode and
+ at code{stdio} in non graphical mode.
+
+This option can be used several times to simulate up to 4 serial
+ports.
+
+Use @code{-serial none} to disable all serial ports.
+
+Available character devices are:
+ at table @option
+ at item vc[:@var{W}x at var{H}]
+Virtual console. Optionally, a width and height can be given in pixel with
+ at example
+vc:800x600
+ at end example
+It is also possible to specify width or height in characters:
+ at example
+vc:80Cx24C
+ at end example
+ at item pty
+[Linux only] Pseudo TTY (a new PTY is automatically allocated)
+ at item none
+No device is allocated.
+ at item null
+void device
+ at item /dev/XXX
+[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
+parameters are set according to the emulated ones.
+ at item /dev/parport at var{N}
+[Linux only, parallel port only] Use host parallel port
+ at var{N}. Currently SPP and EPP parallel port features can be used.
+ at item file:@var{filename}
+Write output to @var{filename}. No character can be read.
+ at item stdio
+[Unix only] standard input/output
+ at item pipe:@var{filename}
+name pipe @var{filename}
+ at item COM at var{n}
+[Windows only] Use host serial port @var{n}
+ at item udp:[@var{remote_host}]:@var{remote_port}[@@[@var{src_ip}]:@var{src_port}]
+This implements UDP Net Console.
+When @var{remote_host} or @var{src_ip} are not specified
+they default to @code{0.0.0.0}.
+When not using a specified @var{src_port} a random port is automatically chosen.
+
+If you just want a simple readonly console you can use @code{netcat} or
+ at code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
+ at code{nc -u -l -p 4555}. Any time qemu writes something to that port it
+will appear in the netconsole session.
+
+If you plan to send characters back via netconsole or you want to stop
+and start qemu a lot of times, you should have qemu use the same
+source port each time by using something like @code{-serial
+udp::4555@@:4556} to qemu. Another approach is to use a patched
+version of netcat which can listen to a TCP port and send and receive
+characters via udp.  If you have a patched version of netcat which
+activates telnet remote echo and single char transfer, then you can
+use the following options to step up a netcat redirector to allow
+telnet on port 5555 to access the qemu port.
+ at table @code
+ at item Qemu Options:
+-serial udp::4555@@:4556
+ at item netcat options:
+-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
+ at item telnet options:
+localhost 5555
+ at end table
+
+ at item tcp:[@var{host}]:@var{port}[, at var{server}][,nowait][,nodelay]
+The TCP Net Console has two modes of operation.  It can send the serial
+I/O to a location or wait for a connection from a location.  By default
+the TCP Net Console is sent to @var{host} at the @var{port}.  If you use
+the @var{server} option QEMU will wait for a client socket application
+to connect to the port before continuing, unless the @code{nowait}
+option was specified.  The @code{nodelay} option disables the Nagle buffering
+algorithm.  If @var{host} is omitted, 0.0.0.0 is assumed. Only
+one TCP connection at a time is accepted. You can use @code{telnet} to
+connect to the corresponding character device.
+ at table @code
+ at item Example to send tcp console to 192.168.0.2 port 4444
+-serial tcp:192.168.0.2:4444
+ at item Example to listen and wait on port 4444 for connection
+-serial tcp::4444,server
+ at item Example to not wait and listen on ip 192.168.0.100 port 4444
+-serial tcp:192.168.0.100:4444,server,nowait
+ at end table
+
+ at item telnet:@var{host}:@var{port}[,server][,nowait][,nodelay]
+The telnet protocol is used instead of raw tcp sockets.  The options
+work the same as if you had specified @code{-serial tcp}.  The
+difference is that the port acts like a telnet server or client using
+telnet option negotiation.  This will also allow you to send the
+MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
+sequence.  Typically in unix telnet you do it with Control-] and then
+type "send break" followed by pressing the enter key.
+
+ at item unix:@var{path}[,server][,nowait]
+A unix domain socket is used instead of a tcp socket.  The option works the
+same as if you had specified @code{-serial tcp} except the unix domain socket
+ at var{path} is used for connections.
+
+ at item mon:@var{dev_string}
+This is a special option to allow the monitor to be multiplexed onto
+another serial port.  The monitor is accessed with key sequence of
+ at key{Control-a} and then pressing @key{c}. See monitor access
+ at ref{pcsys_keys} in the -nographic section for more keys.
+ at var{dev_string} should be any one of the serial devices specified
+above.  An example to multiplex the monitor onto a telnet server
+listening on port 4444 would be:
+ at table @code
+ at item -serial mon:telnet::4444,server,nowait
+ at end table
+
+ at item braille
+Braille device.  This will use BrlAPI to display the braille output on a real
+or fake device.
+
+ at item msmouse
+Three button serial mouse. Configure the guest to use Microsoft protocol.
+ at end table
+ETEXI
+
+DEF("parallel", HAS_ARG, QEMU_OPTION_parallel, \
+    "-parallel dev   redirect the parallel port to char device 'dev'\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -parallel @var{dev}
+ at findex -parallel
+Redirect the virtual parallel port to host device @var{dev} (same
+devices as the serial port). On Linux hosts, @file{/dev/parportN} can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+
+This option can be used several times to simulate up to 3 parallel
+ports.
+
+Use @code{-parallel none} to disable all parallel ports.
+ETEXI
+
+DEF("monitor", HAS_ARG, QEMU_OPTION_monitor, \
+    "-monitor dev    redirect the monitor to char device 'dev'\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -monitor @var{dev}
+ at findex -monitor
+Redirect the monitor to host device @var{dev} (same devices as the
+serial port).
+The default device is @code{vc} in graphical mode and @code{stdio} in
+non graphical mode.
+ETEXI
+DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \
+    "-qmp dev        like -monitor but opens in 'control' mode\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -qmp @var{dev}
+ at findex -qmp
+Like -monitor but opens in 'control' mode.
+ETEXI
+
+DEF("mon", HAS_ARG, QEMU_OPTION_mon, \
+    "-mon chardev=[name][,mode=readline|control][,default]\n", QEMU_ARCH_ALL)
+STEXI
+ at item -mon chardev=[name][,mode=readline|control][,default]
+ at findex -mon
+Setup monitor on chardev @var{name}.
+ETEXI
+
+DEF("debugcon", HAS_ARG, QEMU_OPTION_debugcon, \
+    "-debugcon dev   redirect the debug console to char device 'dev'\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -debugcon @var{dev}
+ at findex -debugcon
+Redirect the debug console to host device @var{dev} (same devices as the
+serial port).  The debug console is an I/O port which is typically port
+0xe9; writing to that I/O port sends output to this device.
+The default device is @code{vc} in graphical mode and @code{stdio} in
+non graphical mode.
+ETEXI
+
+DEF("pidfile", HAS_ARG, QEMU_OPTION_pidfile, \
+    "-pidfile file   write PID to 'file'\n", QEMU_ARCH_ALL)
+STEXI
+ at item -pidfile @var{file}
+ at findex -pidfile
+Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
+from a script.
+ETEXI
+
+DEF("singlestep", 0, QEMU_OPTION_singlestep, \
+    "-singlestep     always run in singlestep mode\n", QEMU_ARCH_ALL)
+STEXI
+ at item -singlestep
+ at findex -singlestep
+Run the emulation in single step mode.
+ETEXI
+
+DEF("S", 0, QEMU_OPTION_S, \
+    "-S              freeze CPU at startup (use 'c' to start execution)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -S
+ at findex -S
+Do not start CPU at startup (you must type 'c' in the monitor).
+ETEXI
+
+DEF("gdb", HAS_ARG, QEMU_OPTION_gdb, \
+    "-gdb dev        wait for gdb connection on 'dev'\n", QEMU_ARCH_ALL)
+STEXI
+ at item -gdb @var{dev}
+ at findex -gdb
+Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical
+connections will likely be TCP-based, but also UDP, pseudo TTY, or even
+stdio are reasonable use case. The latter is allowing to start qemu from
+within gdb and establish the connection via a pipe:
+ at example
+(gdb) target remote | exec qemu -gdb stdio ...
+ at end example
+ETEXI
+
+DEF("s", 0, QEMU_OPTION_s, \
+    "-s              shorthand for -gdb tcp::" DEFAULT_GDBSTUB_PORT "\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -s
+ at findex -s
+Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234
+(@pxref{gdb_usage}).
+ETEXI
+
+DEF("d", HAS_ARG, QEMU_OPTION_d, \
+    "-d item1,...    output log to /tmp/qemu.log (use -d ? for a list of log items)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -d
+ at findex -d
+Output log in /tmp/qemu.log
+ETEXI
+
+DEF("D", HAS_ARG, QEMU_OPTION_D, \
+    "-D logfile      output log to logfile (instead of the default /tmp/qemu.log)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -D
+ at findex -D
+Output log in logfile instead of /tmp/qemu.log
+ETEXI
+
+DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
+    "-hdachs c,h,s[,t]\n" \
+    "                force hard disk 0 physical geometry and the optional BIOS\n" \
+    "                translation (t=none or lba) (usually qemu can guess them)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -hdachs @var{c}, at var{h}, at var{s},[, at var{t}]
+ at findex -hdachs
+Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
+ at var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
+translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
+all those parameters. This option is useful for old MS-DOS disk
+images.
+ETEXI
+
+DEF("L", HAS_ARG, QEMU_OPTION_L, \
+    "-L path         set the directory for the BIOS, VGA BIOS and keymaps\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -L  @var{path}
+ at findex -L
+Set the directory for the BIOS, VGA BIOS and keymaps.
+ETEXI
+
+DEF("bios", HAS_ARG, QEMU_OPTION_bios, \
+    "-bios file      set the filename for the BIOS\n", QEMU_ARCH_ALL)
+STEXI
+ at item -bios @var{file}
+ at findex -bios
+Set the filename for the BIOS.
+ETEXI
+
+DEF("enable-kvm", 0, QEMU_OPTION_enable_kvm, \
+    "-enable-kvm     enable KVM full virtualization support\n", QEMU_ARCH_ALL)
+STEXI
+ at item -enable-kvm
+ at findex -enable-kvm
+Enable KVM full virtualization support. This option is only available
+if KVM support is enabled when compiling.
+ETEXI
+
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n", QEMU_ARCH_ALL)
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n",
+    QEMU_ARCH_ALL)
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -xen-domid @var{id}
+ at findex -xen-domid
+Specify xen guest domain @var{id} (XEN only).
+ at item -xen-create
+ at findex -xen-create
+Create domain using xen hypercalls, bypassing xend.
+Warning: should not be used when xend is in use (XEN only).
+ at item -xen-attach
+ at findex -xen-attach
+Attach to existing xen domain.
+xend will use this when starting qemu (XEN only).
+ETEXI
+
+DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
+    "-no-reboot      exit instead of rebooting\n", QEMU_ARCH_ALL)
+STEXI
+ at item -no-reboot
+ at findex -no-reboot
+Exit instead of rebooting.
+ETEXI
+
+DEF("no-shutdown", 0, QEMU_OPTION_no_shutdown, \
+    "-no-shutdown    stop before shutdown\n", QEMU_ARCH_ALL)
+STEXI
+ at item -no-shutdown
+ at findex -no-shutdown
+Don't exit QEMU on guest shutdown, but instead only stop the emulation.
+This allows for instance switching to monitor to commit changes to the
+disk image.
+ETEXI
+
+DEF("loadvm", HAS_ARG, QEMU_OPTION_loadvm, \
+    "-loadvm [tag|id]\n" \
+    "                start right away with a saved state (loadvm in monitor)\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -loadvm @var{file}
+ at findex -loadvm
+Start right away with a saved state (@code{loadvm} in monitor)
+ETEXI
+
+#ifndef _WIN32
+DEF("daemonize", 0, QEMU_OPTION_daemonize, \
+    "-daemonize      daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
+#endif
+STEXI
+ at item -daemonize
+ at findex -daemonize
+Daemonize the QEMU process after initialization.  QEMU will not detach from
+standard IO until it is ready to receive connections on any of its devices.
+This option is a useful way for external programs to launch QEMU without having
+to cope with initialization race conditions.
+ETEXI
+
+DEF("option-rom", HAS_ARG, QEMU_OPTION_option_rom, \
+    "-option-rom rom load a file, rom, into the option ROM space\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -option-rom @var{file}
+ at findex -option-rom
+Load the contents of @var{file} as an option ROM.
+This option is useful to load things like EtherBoot.
+ETEXI
+
+DEF("clock", HAS_ARG, QEMU_OPTION_clock, \
+    "-clock          force the use of the given methods for timer alarm.\n" \
+    "                To see what timers are available use -clock ?\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -clock @var{method}
+ at findex -clock
+Force the use of the given methods for timer alarm. To see what timers
+are available use -clock ?.
+ETEXI
+
+HXCOMM Options deprecated by -rtc
+DEF("localtime", 0, QEMU_OPTION_localtime, "", QEMU_ARCH_ALL)
+DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "", QEMU_ARCH_ALL)
+
+DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \
+    "-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew]\n" \
+    "                set the RTC base and clock, enable drift fix for clock ticks (x86 only)\n",
+    QEMU_ARCH_ALL)
+
+STEXI
+
+ at item -rtc [base=utc|localtime|@var{date}][,clock=host|vm][,driftfix=none|slew]
+ at findex -rtc
+Specify @option{base} as @code{utc} or @code{localtime} to let the RTC start at the current
+UTC or local time, respectively. @code{localtime} is required for correct date in
+MS-DOS or Windows. To start at a specific point in time, provide @var{date} in the
+format @code{2006-06-17T16:01:21} or @code{2006-06-17}. The default base is UTC.
+
+By default the RTC is driven by the host system time. This allows to use the
+RTC as accurate reference clock inside the guest, specifically if the host
+time is smoothly following an accurate external reference clock, e.g. via NTP.
+If you want to isolate the guest time from the host, even prevent it from
+progressing during suspension, you can set @option{clock} to @code{vm} instead.
+
+Enable @option{driftfix} (i386 targets only) if you experience time drift problems,
+specifically with Windows' ACPI HAL. This option will try to figure out how
+many timer interrupts were not processed by the Windows guest and will
+re-inject them.
+ETEXI
+
+DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
+    "-icount [N|auto]\n" \
+    "                enable virtual instruction counter with 2^N clock ticks per\n" \
+    "                instruction\n", QEMU_ARCH_ALL)
+STEXI
+ at item -icount [@var{N}|auto]
+ at findex -icount
+Enable virtual instruction counter.  The virtual cpu will execute one
+instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
+then the virtual cpu speed will be automatically adjusted to keep virtual
+time within a few seconds of real time.
+
+Note that while this option can give deterministic behavior, it does not
+provide cycle accurate emulation.  Modern CPUs contain superscalar out of
+order cores with complex cache hierarchies.  The number of instructions
+executed often has little or no correlation with actual performance.
+ETEXI
+
+DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
+    "-watchdog i6300esb|ib700\n" \
+    "                enable virtual hardware watchdog [default=none]\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -watchdog @var{model}
+ at findex -watchdog
+Create a virtual hardware watchdog device.  Once enabled (by a guest
+action), the watchdog must be periodically polled by an agent inside
+the guest or else the guest will be restarted.
+
+The @var{model} is the model of hardware watchdog to emulate.  Choices
+for model are: @code{ib700} (iBASE 700) which is a very simple ISA
+watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O
+controller hub) which is a much more featureful PCI-based dual-timer
+watchdog.  Choose a model for which your guest has drivers.
+
+Use @code{-watchdog ?} to list available hardware models.  Only one
+watchdog can be enabled for a guest.
+ETEXI
+
+DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \
+    "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n" \
+    "                action when watchdog fires [default=reset]\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -watchdog-action @var{action}
+
+The @var{action} controls what QEMU will do when the watchdog timer
+expires.
+The default is
+ at code{reset} (forcefully reset the guest).
+Other possible actions are:
+ at code{shutdown} (attempt to gracefully shutdown the guest),
+ at code{poweroff} (forcefully poweroff the guest),
+ at code{pause} (pause the guest),
+ at code{debug} (print a debug message and continue), or
+ at code{none} (do nothing).
+
+Note that the @code{shutdown} action requires that the guest responds
+to ACPI signals, which it may not be able to do in the sort of
+situations where the watchdog would have expired, and thus
+ at code{-watchdog-action shutdown} is not recommended for production use.
+
+Examples:
+
+ at table @code
+ at item -watchdog i6300esb -watchdog-action pause
+ at item -watchdog ib700
+ at end table
+ETEXI
+
+DEF("echr", HAS_ARG, QEMU_OPTION_echr, \
+    "-echr chr       set terminal escape character instead of ctrl-a\n",
+    QEMU_ARCH_ALL)
+STEXI
+
+ at item -echr @var{numeric_ascii_value}
+ at findex -echr
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing.  The default is @code{0x01} when using the
+ at code{-nographic} option.  @code{0x01} is equal to pressing
+ at code{Control-a}.  You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z.  For
+instance you could use the either of the following to change the escape
+character to Control-t.
+ at table @code
+ at item -echr 0x14
+ at item -echr 20
+ at end table
+ETEXI
+
+DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \
+    "-virtioconsole c\n" \
+    "                set virtio console\n", QEMU_ARCH_ALL)
+STEXI
+ at item -virtioconsole @var{c}
+ at findex -virtioconsole
+Set virtio console.
+
+This option is maintained for backward compatibility.
+
+Please use @code{-device virtconsole} for the new way of invocation.
+ETEXI
+
+DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \
+    "-show-cursor    show cursor\n", QEMU_ARCH_ALL)
+STEXI
+ at item -show-cursor
+ at findex -show-cursor
+Show cursor.
+ETEXI
+
+DEF("tb-size", HAS_ARG, QEMU_OPTION_tb_size, \
+    "-tb-size n      set TB size\n", QEMU_ARCH_ALL)
+STEXI
+ at item -tb-size @var{n}
+ at findex -tb-size
+Set TB size.
+ETEXI
+
+DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
+    "-incoming p     prepare for incoming migration, listen on port p\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -incoming @var{port}
+ at findex -incoming
+Prepare for incoming migration, listen on @var{port}.
+ETEXI
+
+DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \
+    "-nodefaults     don't create default devices\n", QEMU_ARCH_ALL)
+STEXI
+ at item -nodefaults
+ at findex -nodefaults
+Don't create default devices.
+ETEXI
+
+#ifndef _WIN32
+DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \
+    "-chroot dir     chroot to dir just before starting the VM\n",
+    QEMU_ARCH_ALL)
+#endif
+STEXI
+ at item -chroot @var{dir}
+ at findex -chroot
+Immediately before starting guest execution, chroot to the specified
+directory.  Especially useful in combination with -runas.
+ETEXI
+
+#ifndef _WIN32
+DEF("runas", HAS_ARG, QEMU_OPTION_runas, \
+    "-runas user     change to user id user just before starting the VM\n",
+    QEMU_ARCH_ALL)
+#endif
+STEXI
+ at item -runas @var{user}
+ at findex -runas
+Immediately before starting guest execution, drop root privileges, switching
+to the specified user.
+ETEXI
+
+DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
+    "-prom-env variable=value\n"
+    "                set OpenBIOS nvram variables\n",
+    QEMU_ARCH_PPC | QEMU_ARCH_SPARC)
+STEXI
+ at item -prom-env @var{variable}=@var{value}
+ at findex -prom-env
+Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
+ETEXI
+DEF("semihosting", 0, QEMU_OPTION_semihosting,
+    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K)
+STEXI
+ at item -semihosting
+ at findex -semihosting
+Semihosting mode (ARM, M68K only).
+ETEXI
+DEF("old-param", 0, QEMU_OPTION_old_param,
+    "-old-param      old param mode\n", QEMU_ARCH_ARM)
+STEXI
+ at item -old-param
+ at findex -old-param (ARM)
+Old param mode (ARM only).
+ETEXI
+
+DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig,
+    "-readconfig <file>\n", QEMU_ARCH_ALL)
+STEXI
+ at item -readconfig @var{file}
+ at findex -readconfig
+Read device configuration from @var{file}.
+ETEXI
+DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig,
+    "-writeconfig <file>\n"
+    "                read/write config file\n", QEMU_ARCH_ALL)
+STEXI
+ at item -writeconfig @var{file}
+ at findex -writeconfig
+Write device configuration to @var{file}.
+ETEXI
+DEF("nodefconfig", 0, QEMU_OPTION_nodefconfig,
+    "-nodefconfig\n"
+    "                do not load default config files at startup\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -nodefconfig
+ at findex -nodefconfig
+Normally QEMU loads a configuration file from @var{sysconfdir}/qemu.conf and
+ at var{sysconfdir}/target- at var{ARCH}.conf on startup.  The @code{-nodefconfig}
+option will prevent QEMU from loading these configuration files at startup.
+ETEXI
+#ifdef CONFIG_SIMPLE_TRACE
+DEF("trace", HAS_ARG, QEMU_OPTION_trace,
+    "-trace\n"
+    "                Specify a trace file to log traces to\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -trace
+ at findex -trace
+Specify a trace file to log output traces to.
+ETEXI
+#endif
+
+HXCOMM This is the last statement. Insert new options before this line!
+STEXI
+ at end table
+ETEXI
diff --git a/qemu-0.15.x/qemu-os-posix.h b/qemu-0.15.x/qemu-os-posix.h
new file mode 100644
index 0000000..81fd9ab
--- /dev/null
+++ b/qemu-0.15.x/qemu-os-posix.h
@@ -0,0 +1,54 @@
+/*
+ * posix specific declarations
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen at redhat.com>
+ *
+ * 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 QEMU_OS_POSIX_H
+#define QEMU_OS_POSIX_H
+
+static inline void os_host_main_loop_wait(int *timeout)
+{
+}
+
+void os_set_line_buffering(void);
+void os_set_proc_name(const char *s);
+void os_setup_signal_handling(void);
+void os_daemonize(void);
+void os_setup_post(void);
+
+typedef struct timeval qemu_timeval;
+#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
+
+#ifndef CONFIG_UTIMENSAT
+#ifndef UTIME_NOW
+# define UTIME_NOW     ((1l << 30) - 1l)
+#endif
+#ifndef UTIME_OMIT
+# define UTIME_OMIT    ((1l << 30) - 2l)
+#endif
+#endif
+typedef struct timespec qemu_timespec;
+int qemu_utimensat(int dirfd, const char *path, const qemu_timespec *times,
+    int flags);
+
+#endif
diff --git a/qemu-0.15.x/qemu-os-win32.h b/qemu-0.15.x/qemu-os-win32.h
new file mode 100644
index 0000000..8a069d7
--- /dev/null
+++ b/qemu-0.15.x/qemu-os-win32.h
@@ -0,0 +1,69 @@
+/*
+ * win32 specific declarations
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen at redhat.com>
+ *
+ * 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 QEMU_OS_WIN32_H
+#define QEMU_OS_WIN32_H
+
+#include <windows.h>
+#include <winsock2.h>
+
+/* Declaration of ffs() is missing in MinGW's strings.h. */
+int ffs(int i);
+
+/* Polling handling */
+
+/* return TRUE if no sleep should be done afterwards */
+typedef int PollingFunc(void *opaque);
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque);
+void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+
+void os_host_main_loop_wait(int *timeout);
+
+static inline void os_setup_signal_handling(void) {}
+static inline void os_daemonize(void) {}
+static inline void os_setup_post(void) {}
+void os_set_line_buffering(void);
+static inline void os_set_proc_name(const char *dummy) {}
+
+#if !defined(EPROTONOSUPPORT)
+# define EPROTONOSUPPORT EINVAL
+#endif
+
+int setenv(const char *name, const char *value, int overwrite);
+
+typedef struct {
+    long tv_sec;
+    long tv_usec;
+} qemu_timeval;
+int qemu_gettimeofday(qemu_timeval *tp);
+
+#endif
diff --git a/qemu-0.15.x/qemu-progress.c b/qemu-0.15.x/qemu-progress.c
new file mode 100644
index 0000000..5f1b8df
--- /dev/null
+++ b/qemu-0.15.x/qemu-progress.c
@@ -0,0 +1,150 @@
+/*
+ * QEMU progress printing utility functions
+ *
+ * Copyright (C) 2011 Jes Sorensen <Jes.Sorensen at redhat.com>
+ *
+ * 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 "qemu-common.h"
+#include "osdep.h"
+#include "sysemu.h"
+#include <stdio.h>
+
+struct progress_state {
+    float current;
+    float last_print;
+    float min_skip;
+    void (*print)(void);
+    void (*end)(void);
+};
+
+static struct progress_state state;
+static volatile sig_atomic_t print_pending;
+
+/*
+ * Simple progress print function.
+ * @percent relative percent of current operation
+ * @max percent of total operation
+ */
+static void progress_simple_print(void)
+{
+    printf("    (%3.2f/100%%)\r", state.current);
+    fflush(stdout);
+}
+
+static void progress_simple_end(void)
+{
+    printf("\n");
+}
+
+static void progress_simple_init(void)
+{
+    state.print = progress_simple_print;
+    state.end = progress_simple_end;
+}
+
+#ifdef CONFIG_POSIX
+static void sigusr_print(int signal)
+{
+    print_pending = 1;
+}
+#endif
+
+static void progress_dummy_print(void)
+{
+    if (print_pending) {
+        fprintf(stderr, "    (%3.2f/100%%)\n", state.current);
+        print_pending = 0;
+    }
+}
+
+static void progress_dummy_end(void)
+{
+}
+
+static void progress_dummy_init(void)
+{
+#ifdef CONFIG_POSIX
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    sigfillset(&action.sa_mask);
+    action.sa_handler = sigusr_print;
+    action.sa_flags = 0;
+    sigaction(SIGUSR1, &action, NULL);
+#endif
+
+    state.print = progress_dummy_print;
+    state.end = progress_dummy_end;
+}
+
+/*
+ * Initialize progress reporting.
+ * If @enabled is false, actual reporting is suppressed.  The user can
+ * still trigger a report by sending a SIGUSR1.
+ * Reports are also suppressed unless we've had at least @min_skip
+ * percent progress since the last report.
+ */
+void qemu_progress_init(int enabled, float min_skip)
+{
+    state.min_skip = min_skip;
+    if (enabled) {
+        progress_simple_init();
+    } else {
+        progress_dummy_init();
+    }
+}
+
+void qemu_progress_end(void)
+{
+    state.end();
+}
+
+/*
+ * Report progress.
+ * @delta is how much progress we made.
+ * If @max is zero, @delta is an absolut value of the total job done.
+ * Else, @delta is a progress delta since the last call, as a fraction
+ * of @max.  I.e. the delta is @delta * @max / 100. This allows
+ * relative accounting of functions which may be a different fraction of
+ * the full job, depending on the context they are called in. I.e.
+ * a function might be considered 40% of the full job if used from
+ * bdrv_img_create() but only 20% if called from img_convert().
+ */
+void qemu_progress_print(float delta, int max)
+{
+    float current;
+
+    if (max == 0) {
+        current = delta;
+    } else {
+        current = state.current + delta / 100 * max;
+    }
+    if (current > 100) {
+        current = 100;
+    }
+    state.current = current;
+
+    if (current > (state.last_print + state.min_skip) ||
+        (current == 100) || (current == 0)) {
+        state.last_print = state.current;
+        state.print();
+    }
+}
diff --git a/qemu-0.15.x/qemu-queue.h b/qemu-0.15.x/qemu-queue.h
new file mode 100644
index 0000000..1d07745
--- /dev/null
+++ b/qemu-0.15.x/qemu-queue.h
@@ -0,0 +1,449 @@
+/*      $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
+
+/*
+ * Qemu version: Copy from netbsd, removed debug code, removed some of
+ * the implementations.  Left in lists, simple queues, tail queues and
+ * circular queues.
+ */
+
+/*
+ * 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. 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.
+ *
+ *      @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef QEMU_SYS_QUEUE_H_
+#define QEMU_SYS_QUEUE_H_
+
+/*
+ * This file defines four types of data structures:
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define QLIST_HEAD(name, type)                                          \
+struct name {                                                           \
+        struct type *lh_first;  /* first element */                     \
+}
+
+#define QLIST_HEAD_INITIALIZER(head)                                    \
+        { NULL }
+
+#define QLIST_ENTRY(type)                                               \
+struct {                                                                \
+        struct type *le_next;   /* next element */                      \
+        struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List functions.
+ */
+#define QLIST_INIT(head) do {                                           \
+        (head)->lh_first = NULL;                                        \
+} while (/*CONSTCOND*/0)
+
+#define QLIST_INSERT_AFTER(listelm, elm, field) do {                    \
+        if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+                (listelm)->field.le_next->field.le_prev =               \
+                    &(elm)->field.le_next;                              \
+        (listelm)->field.le_next = (elm);                               \
+        (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (/*CONSTCOND*/0)
+
+#define QLIST_INSERT_BEFORE(listelm, elm, field) do {                   \
+        (elm)->field.le_prev = (listelm)->field.le_prev;                \
+        (elm)->field.le_next = (listelm);                               \
+        *(listelm)->field.le_prev = (elm);                              \
+        (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (/*CONSTCOND*/0)
+
+#define QLIST_INSERT_HEAD(head, elm, field) do {                        \
+        if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+                (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+        (head)->lh_first = (elm);                                       \
+        (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (/*CONSTCOND*/0)
+
+#define QLIST_REMOVE(elm, field) do {                                   \
+        if ((elm)->field.le_next != NULL)                               \
+                (elm)->field.le_next->field.le_prev =                   \
+                    (elm)->field.le_prev;                               \
+        *(elm)->field.le_prev = (elm)->field.le_next;                   \
+} while (/*CONSTCOND*/0)
+
+#define QLIST_FOREACH(var, head, field)                                 \
+        for ((var) = ((head)->lh_first);                                \
+                (var);                                                  \
+                (var) = ((var)->field.le_next))
+
+#define QLIST_FOREACH_SAFE(var, head, field, next_var)                  \
+        for ((var) = ((head)->lh_first);                                \
+                (var) && ((next_var) = ((var)->field.le_next), 1);      \
+                (var) = (next_var))
+
+/*
+ * List access methods.
+ */
+#define QLIST_EMPTY(head)                ((head)->lh_first == NULL)
+#define QLIST_FIRST(head)                ((head)->lh_first)
+#define QLIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+
+/*
+ * Simple queue definitions.
+ */
+#define QSIMPLEQ_HEAD(name, type)                                       \
+struct name {                                                           \
+    struct type *sqh_first;    /* first element */                      \
+    struct type **sqh_last;    /* addr of last next element */          \
+}
+
+#define QSIMPLEQ_HEAD_INITIALIZER(head)                                 \
+    { NULL, &(head).sqh_first }
+
+#define QSIMPLEQ_ENTRY(type)                                            \
+struct {                                                                \
+    struct type *sqe_next;    /* next element */                        \
+}
+
+/*
+ * Simple queue functions.
+ */
+#define QSIMPLEQ_INIT(head) do {                                        \
+    (head)->sqh_first = NULL;                                           \
+    (head)->sqh_last = &(head)->sqh_first;                              \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
+    if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)            \
+        (head)->sqh_last = &(elm)->field.sqe_next;                      \
+    (head)->sqh_first = (elm);                                          \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
+    (elm)->field.sqe_next = NULL;                                       \
+    *(head)->sqh_last = (elm);                                          \
+    (head)->sqh_last = &(elm)->field.sqe_next;                          \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+    if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)    \
+        (head)->sqh_last = &(elm)->field.sqe_next;                      \
+    (listelm)->field.sqe_next = (elm);                                  \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_REMOVE_HEAD(head, field) do {                          \
+    if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\
+        (head)->sqh_last = &(head)->sqh_first;                          \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_REMOVE(head, elm, type, field) do {                    \
+    if ((head)->sqh_first == (elm)) {                                   \
+        QSIMPLEQ_REMOVE_HEAD((head), field);                            \
+    } else {                                                            \
+        struct type *curelm = (head)->sqh_first;                        \
+        while (curelm->field.sqe_next != (elm))                         \
+            curelm = curelm->field.sqe_next;                            \
+        if ((curelm->field.sqe_next =                                   \
+            curelm->field.sqe_next->field.sqe_next) == NULL)            \
+                (head)->sqh_last = &(curelm)->field.sqe_next;           \
+    }                                                                   \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_FOREACH(var, head, field)                              \
+    for ((var) = ((head)->sqh_first);                                   \
+        (var);                                                          \
+        (var) = ((var)->field.sqe_next))
+
+#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next)                   \
+    for ((var) = ((head)->sqh_first);                                   \
+        (var) && ((next = ((var)->field.sqe_next)), 1);                 \
+        (var) = (next))
+
+#define QSIMPLEQ_CONCAT(head1, head2) do {                              \
+    if (!QSIMPLEQ_EMPTY((head2))) {                                     \
+        *(head1)->sqh_last = (head2)->sqh_first;                        \
+        (head1)->sqh_last = (head2)->sqh_last;                          \
+        QSIMPLEQ_INIT((head2));                                         \
+    }                                                                   \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_LAST(head, type, field)                                \
+    (QSIMPLEQ_EMPTY((head)) ?                                           \
+        NULL :                                                          \
+            ((struct type *)(void *)                                    \
+        ((char *)((head)->sqh_last) - offsetof(struct type, field))))
+
+/*
+ * Simple queue access methods.
+ */
+#define QSIMPLEQ_EMPTY(head)        ((head)->sqh_first == NULL)
+#define QSIMPLEQ_FIRST(head)        ((head)->sqh_first)
+#define QSIMPLEQ_NEXT(elm, field)   ((elm)->field.sqe_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define Q_TAILQ_HEAD(name, type, qual)                                  \
+struct name {                                                           \
+        qual type *tqh_first;           /* first element */             \
+        qual type *qual *tqh_last;      /* addr of last next element */ \
+}
+#define QTAILQ_HEAD(name, type)  Q_TAILQ_HEAD(name, struct type,)
+
+#define QTAILQ_HEAD_INITIALIZER(head)                                   \
+        { NULL, &(head).tqh_first }
+
+#define Q_TAILQ_ENTRY(type, qual)                                       \
+struct {                                                                \
+        qual type *tqe_next;            /* next element */              \
+        qual type *qual *tqe_prev;      /* address of previous next element */\
+}
+#define QTAILQ_ENTRY(type)       Q_TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define QTAILQ_INIT(head) do {                                          \
+        (head)->tqh_first = NULL;                                       \
+        (head)->tqh_last = &(head)->tqh_first;                          \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_HEAD(head, elm, field) do {                       \
+        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+                (head)->tqh_first->field.tqe_prev =                     \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (head)->tqh_first = (elm);                                      \
+        (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_TAIL(head, elm, field) do {                       \
+        (elm)->field.tqe_next = NULL;                                   \
+        (elm)->field.tqe_prev = (head)->tqh_last;                       \
+        *(head)->tqh_last = (elm);                                      \
+        (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (listelm)->field.tqe_next = (elm);                              \
+        (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do {                  \
+        (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+        (elm)->field.tqe_next = (listelm);                              \
+        *(listelm)->field.tqe_prev = (elm);                             \
+        (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_REMOVE(head, elm, field) do {                            \
+        if (((elm)->field.tqe_next) != NULL)                            \
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    (elm)->field.tqe_prev;                              \
+        else                                                            \
+                (head)->tqh_last = (elm)->field.tqe_prev;               \
+        *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_FOREACH(var, head, field)                                \
+        for ((var) = ((head)->tqh_first);                               \
+                (var);                                                  \
+                (var) = ((var)->field.tqe_next))
+
+#define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
+        for ((var) = ((head)->tqh_first);                               \
+                (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
+                (var) = (next_var))
+
+#define QTAILQ_FOREACH_REVERSE(var, head, headname, field)              \
+        for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));    \
+                (var);                                                  \
+                (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+/*
+ * Tail queue access methods.
+ */
+#define QTAILQ_EMPTY(head)               ((head)->tqh_first == NULL)
+#define QTAILQ_FIRST(head)               ((head)->tqh_first)
+#define QTAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+
+#define QTAILQ_LAST(head, headname) \
+        (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define QTAILQ_PREV(elm, headname, field) \
+        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define QCIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                           \
+        struct type *cqh_first;         /* first element */             \
+        struct type *cqh_last;          /* last element */              \
+}
+
+#define QCIRCLEQ_HEAD_INITIALIZER(head)                                 \
+        { (void *)&head, (void *)&head }
+
+#define QCIRCLEQ_ENTRY(type)                                            \
+struct {                                                                \
+        struct type *cqe_next;          /* next element */              \
+        struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define QCIRCLEQ_INIT(head) do {                                        \
+        (head)->cqh_first = (void *)(head);                             \
+        (head)->cqh_last = (void *)(head);                              \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+        (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+        (elm)->field.cqe_prev = (listelm);                              \
+        if ((listelm)->field.cqe_next == (void *)(head))                \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+        (listelm)->field.cqe_next = (elm);                              \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+        (elm)->field.cqe_next = (listelm);                              \
+        (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+        if ((listelm)->field.cqe_prev == (void *)(head))                \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+        (listelm)->field.cqe_prev = (elm);                              \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+        (elm)->field.cqe_next = (head)->cqh_first;                      \
+        (elm)->field.cqe_prev = (void *)(head);                         \
+        if ((head)->cqh_last == (void *)(head))                         \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (head)->cqh_first->field.cqe_prev = (elm);              \
+        (head)->cqh_first = (elm);                                      \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+        (elm)->field.cqe_next = (void *)(head);                         \
+        (elm)->field.cqe_prev = (head)->cqh_last;                       \
+        if ((head)->cqh_first == (void *)(head))                        \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (head)->cqh_last->field.cqe_next = (elm);               \
+        (head)->cqh_last = (elm);                                       \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_REMOVE(head, elm, field) do {                          \
+        if ((elm)->field.cqe_next == (void *)(head))                    \
+                (head)->cqh_last = (elm)->field.cqe_prev;               \
+        else                                                            \
+                (elm)->field.cqe_next->field.cqe_prev =                 \
+                    (elm)->field.cqe_prev;                              \
+        if ((elm)->field.cqe_prev == (void *)(head))                    \
+                (head)->cqh_first = (elm)->field.cqe_next;              \
+        else                                                            \
+                (elm)->field.cqe_prev->field.cqe_next =                 \
+                    (elm)->field.cqe_next;                              \
+} while (/*CONSTCOND*/0)
+
+#define QCIRCLEQ_FOREACH(var, head, field)                              \
+        for ((var) = ((head)->cqh_first);                               \
+                (var) != (const void *)(head);                          \
+                (var) = ((var)->field.cqe_next))
+
+#define QCIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
+        for ((var) = ((head)->cqh_last);                                \
+                (var) != (const void *)(head);                          \
+                (var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define QCIRCLEQ_EMPTY(head)             ((head)->cqh_first == (void *)(head))
+#define QCIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define QCIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define QCIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define QCIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+
+#define QCIRCLEQ_LOOP_NEXT(head, elm, field)                            \
+        (((elm)->field.cqe_next == (void *)(head))                      \
+            ? ((head)->cqh_first)                                       \
+            : (elm->field.cqe_next))
+#define QCIRCLEQ_LOOP_PREV(head, elm, field)                            \
+        (((elm)->field.cqe_prev == (void *)(head))                      \
+            ? ((head)->cqh_last)                                        \
+            : (elm->field.cqe_prev))
+
+#endif  /* !QEMU_SYS_QUEUE_H_ */
diff --git a/qemu-0.15.x/qemu-sockets.c b/qemu-0.15.x/qemu-sockets.c
new file mode 100644
index 0000000..eda1850
--- /dev/null
+++ b/qemu-0.15.x/qemu-sockets.c
@@ -0,0 +1,679 @@
+/*
+ *  inet and unix socket functions for qemu
+ *
+ *  (c) 2008 Gerd Hoffmann <kraxel at redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "qemu_socket.h"
+#include "qemu-common.h" /* for qemu_isdigit */
+
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+static int sockets_debug = 0;
+static const int on=1, off=0;
+
+/* used temporarely until all users are converted to QemuOpts */
+static QemuOptsList dummy_opts = {
+    .name = "dummy",
+    .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
+    .desc = {
+        {
+            .name = "path",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "host",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "port",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "to",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "ipv4",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "ipv6",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end if list */ }
+    },
+};
+
+static int inet_getport(struct addrinfo *e)
+{
+    struct sockaddr_in *i4;
+    struct sockaddr_in6 *i6;
+
+    switch (e->ai_family) {
+    case PF_INET6:
+        i6 = (void*)e->ai_addr;
+        return ntohs(i6->sin6_port);
+    case PF_INET:
+        i4 = (void*)e->ai_addr;
+        return ntohs(i4->sin_port);
+    default:
+        return 0;
+    }
+}
+
+static void inet_setport(struct addrinfo *e, int port)
+{
+    struct sockaddr_in *i4;
+    struct sockaddr_in6 *i6;
+
+    switch (e->ai_family) {
+    case PF_INET6:
+        i6 = (void*)e->ai_addr;
+        i6->sin6_port = htons(port);
+        break;
+    case PF_INET:
+        i4 = (void*)e->ai_addr;
+        i4->sin_port = htons(port);
+        break;
+    }
+}
+
+const char *inet_strfamily(int family)
+{
+    switch (family) {
+    case PF_INET6: return "ipv6";
+    case PF_INET:  return "ipv4";
+    case PF_UNIX:  return "unix";
+    }
+    return "unknown";
+}
+
+static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
+{
+    struct addrinfo *e;
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+
+    for (e = res; e != NULL; e = e->ai_next) {
+        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+                    uaddr,INET6_ADDRSTRLEN,uport,32,
+                    NI_NUMERICHOST | NI_NUMERICSERV);
+        fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
+                tag, inet_strfamily(e->ai_family), uaddr, uport);
+    }
+}
+
+int inet_listen_opts(QemuOpts *opts, int port_offset)
+{
+    struct addrinfo ai,*res,*e;
+    const char *addr;
+    char port[33];
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    int slisten,rc,to,try_next;
+
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+    ai.ai_family = PF_UNSPEC;
+    ai.ai_socktype = SOCK_STREAM;
+
+    if ((qemu_opt_get(opts, "host") == NULL) ||
+        (qemu_opt_get(opts, "port") == NULL)) {
+        fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
+        return -1;
+    }
+    pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
+    addr = qemu_opt_get(opts, "host");
+
+    to = qemu_opt_get_number(opts, "to", 0);
+    if (qemu_opt_get_bool(opts, "ipv4", 0))
+        ai.ai_family = PF_INET;
+    if (qemu_opt_get_bool(opts, "ipv6", 0))
+        ai.ai_family = PF_INET6;
+
+    /* lookup */
+    if (port_offset)
+        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
+    if (rc != 0) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+                gai_strerror(rc));
+        return -1;
+    }
+    if (sockets_debug)
+        inet_print_addrinfo(__FUNCTION__, res);
+
+    /* create socket + bind */
+    for (e = res; e != NULL; e = e->ai_next) {
+        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+		        uaddr,INET6_ADDRSTRLEN,uport,32,
+		        NI_NUMERICHOST | NI_NUMERICSERV);
+        slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
+        if (slisten < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family), strerror(errno));
+            continue;
+        }
+
+        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+#ifdef IPV6_V6ONLY
+        if (e->ai_family == PF_INET6) {
+            /* listen on both ipv4 and ipv6 */
+            setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
+                sizeof(off));
+        }
+#endif
+
+        for (;;) {
+            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
+                if (sockets_debug)
+                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family), uaddr, inet_getport(e));
+                goto listen;
+            }
+            try_next = to && (inet_getport(e) <= to + port_offset);
+            if (!try_next || sockets_debug)
+                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family), uaddr, inet_getport(e),
+                        strerror(errno));
+            if (try_next) {
+                inet_setport(e, inet_getport(e) + 1);
+                continue;
+            }
+            break;
+        }
+        closesocket(slisten);
+    }
+    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
+    freeaddrinfo(res);
+    return -1;
+
+listen:
+    if (listen(slisten,1) != 0) {
+        perror("listen");
+        closesocket(slisten);
+        freeaddrinfo(res);
+        return -1;
+    }
+    snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
+    qemu_opt_set(opts, "host", uaddr);
+    qemu_opt_set(opts, "port", uport);
+    qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
+    qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
+    freeaddrinfo(res);
+    return slisten;
+}
+
+int inet_connect_opts(QemuOpts *opts)
+{
+    struct addrinfo ai,*res,*e;
+    const char *addr;
+    const char *port;
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    int sock,rc;
+
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+    ai.ai_family = PF_UNSPEC;
+    ai.ai_socktype = SOCK_STREAM;
+
+    addr = qemu_opt_get(opts, "host");
+    port = qemu_opt_get(opts, "port");
+    if (addr == NULL || port == NULL) {
+        fprintf(stderr, "inet_connect: host and/or port not specified\n");
+        return -1;
+    }
+
+    if (qemu_opt_get_bool(opts, "ipv4", 0))
+        ai.ai_family = PF_INET;
+    if (qemu_opt_get_bool(opts, "ipv6", 0))
+        ai.ai_family = PF_INET6;
+
+    /* lookup */
+    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+                gai_strerror(rc));
+	return -1;
+    }
+    if (sockets_debug)
+        inet_print_addrinfo(__FUNCTION__, res);
+
+    for (e = res; e != NULL; e = e->ai_next) {
+        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+                            uaddr,INET6_ADDRSTRLEN,uport,32,
+                            NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
+            continue;
+        }
+        sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
+        if (sock < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+            inet_strfamily(e->ai_family), strerror(errno));
+            continue;
+        }
+        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+
+        /* connect to peer */
+        if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
+            if (sockets_debug || NULL == e->ai_next)
+                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family),
+                        e->ai_canonname, uaddr, uport, strerror(errno));
+            closesocket(sock);
+            continue;
+        }
+        if (sockets_debug)
+            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family),
+                    e->ai_canonname, uaddr, uport);
+        freeaddrinfo(res);
+        return sock;
+    }
+    freeaddrinfo(res);
+    return -1;
+}
+
+int inet_dgram_opts(QemuOpts *opts)
+{
+    struct addrinfo ai, *peer = NULL, *local = NULL;
+    const char *addr;
+    const char *port;
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    int sock = -1, rc;
+
+    /* lookup peer addr */
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+    ai.ai_family = PF_UNSPEC;
+    ai.ai_socktype = SOCK_DGRAM;
+
+    addr = qemu_opt_get(opts, "host");
+    port = qemu_opt_get(opts, "port");
+    if (addr == NULL || strlen(addr) == 0) {
+        addr = "localhost";
+    }
+    if (port == NULL || strlen(port) == 0) {
+        fprintf(stderr, "inet_dgram: port not specified\n");
+        return -1;
+    }
+
+    if (qemu_opt_get_bool(opts, "ipv4", 0))
+        ai.ai_family = PF_INET;
+    if (qemu_opt_get_bool(opts, "ipv6", 0))
+        ai.ai_family = PF_INET6;
+
+    if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+                gai_strerror(rc));
+	return -1;
+    }
+    if (sockets_debug) {
+        fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port);
+        inet_print_addrinfo(__FUNCTION__, peer);
+    }
+
+    /* lookup local addr */
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_PASSIVE;
+    ai.ai_family = peer->ai_family;
+    ai.ai_socktype = SOCK_DGRAM;
+
+    addr = qemu_opt_get(opts, "localaddr");
+    port = qemu_opt_get(opts, "localport");
+    if (addr == NULL || strlen(addr) == 0) {
+        addr = NULL;
+    }
+    if (!port || strlen(port) == 0)
+        port = "0";
+
+    if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+                gai_strerror(rc));
+        return -1;
+    }
+    if (sockets_debug) {
+        fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port);
+        inet_print_addrinfo(__FUNCTION__, local);
+    }
+
+    /* create socket */
+    sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
+    if (sock < 0) {
+        fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                inet_strfamily(peer->ai_family), strerror(errno));
+        goto err;
+    }
+    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+
+    /* bind socket */
+    if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen,
+                    uaddr,INET6_ADDRSTRLEN,uport,32,
+                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+        goto err;
+    }
+    if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
+        fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
+                inet_strfamily(local->ai_family), uaddr, inet_getport(local));
+        goto err;
+    }
+
+    /* connect to peer */
+    if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen,
+                    uaddr, INET6_ADDRSTRLEN, uport, 32,
+                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+        goto err;
+    }
+    if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
+        fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+                inet_strfamily(peer->ai_family),
+                peer->ai_canonname, uaddr, uport, strerror(errno));
+        goto err;
+    }
+
+    freeaddrinfo(local);
+    freeaddrinfo(peer);
+    return sock;
+
+err:
+    if (-1 != sock)
+        closesocket(sock);
+    if (local)
+        freeaddrinfo(local);
+    if (peer)
+        freeaddrinfo(peer);
+    return -1;
+}
+
+/* compatibility wrapper */
+static int inet_parse(QemuOpts *opts, const char *str)
+{
+    const char *optstr, *h;
+    char addr[64];
+    char port[33];
+    int pos;
+
+    /* parse address */
+    if (str[0] == ':') {
+        /* no host given */
+        addr[0] = '\0';
+        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
+            fprintf(stderr, "%s: portonly parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    } else if (str[0] == '[') {
+        /* IPv6 addr */
+        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        qemu_opt_set(opts, "ipv6", "on");
+    } else if (qemu_isdigit(str[0])) {
+        /* IPv4 addr */
+        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        qemu_opt_set(opts, "ipv4", "on");
+    } else {
+        /* hostname */
+        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: hostname parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    }
+    qemu_opt_set(opts, "host", addr);
+    qemu_opt_set(opts, "port", port);
+
+    /* parse options */
+    optstr = str + pos;
+    h = strstr(optstr, ",to=");
+    if (h)
+        qemu_opt_set(opts, "to", h+4);
+    if (strstr(optstr, ",ipv4"))
+        qemu_opt_set(opts, "ipv4", "on");
+    if (strstr(optstr, ",ipv6"))
+        qemu_opt_set(opts, "ipv6", "on");
+    return 0;
+}
+
+int inet_listen(const char *str, char *ostr, int olen,
+                int socktype, int port_offset)
+{
+    QemuOpts *opts;
+    char *optstr;
+    int sock = -1;
+
+    opts = qemu_opts_create(&dummy_opts, NULL, 0);
+    if (inet_parse(opts, str) == 0) {
+        sock = inet_listen_opts(opts, port_offset);
+        if (sock != -1 && ostr) {
+            optstr = strchr(str, ',');
+            if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+                snprintf(ostr, olen, "[%s]:%s%s",
+                         qemu_opt_get(opts, "host"),
+                         qemu_opt_get(opts, "port"),
+                         optstr ? optstr : "");
+            } else {
+                snprintf(ostr, olen, "%s:%s%s",
+                         qemu_opt_get(opts, "host"),
+                         qemu_opt_get(opts, "port"),
+                         optstr ? optstr : "");
+            }
+        }
+    }
+    qemu_opts_del(opts);
+    return sock;
+}
+
+int inet_connect(const char *str, int socktype)
+{
+    QemuOpts *opts;
+    int sock = -1;
+
+    opts = qemu_opts_create(&dummy_opts, NULL, 0);
+    if (inet_parse(opts, str) == 0)
+        sock = inet_connect_opts(opts);
+    qemu_opts_del(opts);
+    return sock;
+}
+
+#ifndef _WIN32
+
+int unix_listen_opts(QemuOpts *opts)
+{
+    struct sockaddr_un un;
+    const char *path = qemu_opt_get(opts, "path");
+    int sock, fd;
+
+    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        perror("socket(unix)");
+        return -1;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    if (path && strlen(path)) {
+        snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    } else {
+        char *tmpdir = getenv("TMPDIR");
+        snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
+                 tmpdir ? tmpdir : "/tmp");
+        /*
+         * This dummy fd usage silences the mktemp() unsecure warning.
+         * Using mkstemp() doesn't make things more secure here
+         * though.  bind() complains about existing files, so we have
+         * to unlink first and thus re-open the race window.  The
+         * worst case possible is bind() failing, i.e. a DoS attack.
+         */
+        fd = mkstemp(un.sun_path); close(fd);
+        qemu_opt_set(opts, "path", un.sun_path);
+    }
+
+    unlink(un.sun_path);
+    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+    if (listen(sock, 1) < 0) {
+        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+
+    if (sockets_debug)
+        fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
+    return sock;
+
+err:
+    closesocket(sock);
+    return -1;
+}
+
+int unix_connect_opts(QemuOpts *opts)
+{
+    struct sockaddr_un un;
+    const char *path = qemu_opt_get(opts, "path");
+    int sock;
+
+    if (NULL == path) {
+        fprintf(stderr, "unix connect: no path specified\n");
+        return -1;
+    }
+
+    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        perror("socket(unix)");
+        return -1;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
+	return -1;
+    }
+
+    if (sockets_debug)
+        fprintf(stderr, "connect(unix:%s): OK\n", path);
+    return sock;
+}
+
+/* compatibility wrapper */
+int unix_listen(const char *str, char *ostr, int olen)
+{
+    QemuOpts *opts;
+    char *path, *optstr;
+    int sock, len;
+
+    opts = qemu_opts_create(&dummy_opts, NULL, 0);
+
+    optstr = strchr(str, ',');
+    if (optstr) {
+        len = optstr - str;
+        if (len) {
+            path = qemu_malloc(len+1);
+            snprintf(path, len+1, "%.*s", len, str);
+            qemu_opt_set(opts, "path", path);
+            qemu_free(path);
+        }
+    } else {
+        qemu_opt_set(opts, "path", str);
+    }
+
+    sock = unix_listen_opts(opts);
+
+    if (sock != -1 && ostr)
+        snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
+    qemu_opts_del(opts);
+    return sock;
+}
+
+int unix_connect(const char *path)
+{
+    QemuOpts *opts;
+    int sock;
+
+    opts = qemu_opts_create(&dummy_opts, NULL, 0);
+    qemu_opt_set(opts, "path", path);
+    sock = unix_connect_opts(opts);
+    qemu_opts_del(opts);
+    return sock;
+}
+
+#else
+
+int unix_listen_opts(QemuOpts *opts)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
+    return -1;
+}
+
+int unix_connect_opts(QemuOpts *opts)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
+    return -1;
+}
+
+int unix_listen(const char *path, char *ostr, int olen)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif
+
+#ifdef _WIN32
+static void socket_cleanup(void)
+{
+    WSACleanup();
+}
+#endif
+
+int socket_init(void)
+{
+#ifdef _WIN32
+    WSADATA Data;
+    int ret, err;
+
+    ret = WSAStartup(MAKEWORD(2,2), &Data);
+    if (ret != 0) {
+        err = WSAGetLastError();
+        fprintf(stderr, "WSAStartup: %d\n", err);
+        return -1;
+    }
+    atexit(socket_cleanup);
+#endif
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-tech.texi b/qemu-0.15.x/qemu-tech.texi
new file mode 100644
index 0000000..138e3ce
--- /dev/null
+++ b/qemu-0.15.x/qemu-tech.texi
@@ -0,0 +1,697 @@
+\input texinfo @c -*- texinfo -*-
+ at c %**start of header
+ at setfilename qemu-tech.info
+
+ at documentlanguage en
+ at documentencoding UTF-8
+
+ at settitle QEMU Internals
+ at exampleindent 0
+ at paragraphindent 0
+ at c %**end of header
+
+ at ifinfo
+ at direntry
+* QEMU Internals: (qemu-tech).   The QEMU Emulator Internals.
+ at end direntry
+ at end ifinfo
+
+ at iftex
+ at titlepage
+ at sp 7
+ at center @titlefont{QEMU Internals}
+ at sp 3
+ at end titlepage
+ at end iftex
+
+ at ifnottex
+ at node Top
+ at top
+
+ at menu
+* Introduction::
+* QEMU Internals::
+* Regression Tests::
+* Index::
+ at end menu
+ at end ifnottex
+
+ at contents
+
+ at node Introduction
+ at chapter Introduction
+
+ at menu
+* intro_features::        Features
+* intro_x86_emulation::   x86 and x86-64 emulation
+* intro_arm_emulation::   ARM emulation
+* intro_mips_emulation::  MIPS emulation
+* intro_ppc_emulation::   PowerPC emulation
+* intro_sparc_emulation:: Sparc32 and Sparc64 emulation
+* intro_other_emulation:: Other CPU emulation
+ at end menu
+
+ at node intro_features
+ at section Features
+
+QEMU is a FAST! processor emulator using a portable dynamic
+translator.
+
+QEMU has two operating modes:
+
+ at itemize @minus
+
+ at item
+Full system emulation. In this mode (full platform virtualization),
+QEMU emulates a full system (usually a PC), including a processor and
+various peripherals. It can be used to launch several different
+Operating Systems at once without rebooting the host machine or to
+debug system code.
+
+ at item
+User mode emulation. In this mode (application level virtualization),
+QEMU can launch processes compiled for one CPU on another CPU, however
+the Operating Systems must match. This can be used for example to ease
+cross-compilation and cross-debugging.
+ at end itemize
+
+As QEMU requires no host kernel driver to run, it is very safe and
+easy to use.
+
+QEMU generic features:
+
+ at itemize
+
+ at item User space only or full system emulation.
+
+ at item Using dynamic translation to native code for reasonable speed.
+
+ at item
+Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM,
+HPPA, Sparc32 and Sparc64. Previous versions had some support for
+Alpha and S390 hosts, but TCG (see below) doesn't support those yet.
+
+ at item Self-modifying code support.
+
+ at item Precise exceptions support.
+
+ at item The virtual CPU is a library (@code{libqemu}) which can be used
+in other projects (look at @file{qemu/tests/qruncom.c} to have an
+example of user mode @code{libqemu} usage).
+
+ at item
+Floating point library supporting both full software emulation and
+native host FPU instructions.
+
+ at end itemize
+
+QEMU user mode emulation features:
+ at itemize
+ at item Generic Linux system call converter, including most ioctls.
+
+ at item clone() emulation using native CPU clone() to use Linux scheduler for threads.
+
+ at item Accurate signal handling by remapping host signals to target signals.
+ at end itemize
+
+Linux user emulator (Linux host only) can be used to launch the Wine
+Windows API emulator (@url{http://www.winehq.org}). A Darwin user
+emulator (Darwin hosts only) exists and a BSD user emulator for BSD
+hosts is under development. It would also be possible to develop a
+similar user emulator for Solaris.
+
+QEMU full system emulation features:
+ at itemize
+ at item
+QEMU uses a full software MMU for maximum portability.
+
+ at item
+QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators 
+execute some of the guest code natively, while
+continuing to emulate the rest of the machine.
+
+ at item
+Various hardware devices can be emulated and in some cases, host
+devices (e.g. serial and parallel ports, USB, drives) can be used
+transparently by the guest Operating System. Host device passthrough
+can be used for talking to external physical peripherals (e.g. a
+webcam, modem or tape drive).
+
+ at item
+Symmetric multiprocessing (SMP) even on a host with a single CPU. On a
+SMP host system, QEMU can use only one CPU fully due to difficulty in
+implementing atomic memory accesses efficiently.
+
+ at end itemize
+
+ at node intro_x86_emulation
+ at section x86 and x86-64 emulation
+
+QEMU x86 target features:
+
+ at itemize
+
+ at item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
+LDT/GDT and IDT are emulated. VM86 mode is also supported to run
+DOSEMU. There is some support for MMX/3DNow!, SSE, SSE2, SSE3, SSSE3,
+and SSE4 as well as x86-64 SVM.
+
+ at item Support of host page sizes bigger than 4KB in user mode emulation.
+
+ at item QEMU can emulate itself on x86.
+
+ at item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
+It can be used to test other x86 virtual CPUs.
+
+ at end itemize
+
+Current QEMU limitations:
+
+ at itemize
+
+ at item Limited x86-64 support.
+
+ at item IPC syscalls are missing.
+
+ at item The x86 segment limits and access rights are not tested at every
+memory access (yet). Hopefully, very few OSes seem to rely on that for
+normal use.
+
+ at end itemize
+
+ at node intro_arm_emulation
+ at section ARM emulation
+
+ at itemize
+
+ at item Full ARM 7 user emulation.
+
+ at item NWFPE FPU support included in user Linux emulation.
+
+ at item Can run most ARM Linux binaries.
+
+ at end itemize
+
+ at node intro_mips_emulation
+ at section MIPS emulation
+
+ at itemize
+
+ at item The system emulation allows full MIPS32/MIPS64 Release 2 emulation,
+including privileged instructions, FPU and MMU, in both little and big
+endian modes.
+
+ at item The Linux userland emulation can run many 32 bit MIPS Linux binaries.
+
+ at end itemize
+
+Current QEMU limitations:
+
+ at itemize
+
+ at item Self-modifying code is not always handled correctly.
+
+ at item 64 bit userland emulation is not implemented.
+
+ at item The system emulation is not complete enough to run real firmware.
+
+ at item The watchpoint debug facility is not implemented.
+
+ at end itemize
+
+ at node intro_ppc_emulation
+ at section PowerPC emulation
+
+ at itemize
+
+ at item Full PowerPC 32 bit emulation, including privileged instructions,
+FPU and MMU.
+
+ at item Can run most PowerPC Linux binaries.
+
+ at end itemize
+
+ at node intro_sparc_emulation
+ at section Sparc32 and Sparc64 emulation
+
+ at itemize
+
+ at item Full SPARC V8 emulation, including privileged
+instructions, FPU and MMU. SPARC V9 emulation includes most privileged
+and VIS instructions, FPU and I/D MMU. Alignment is fully enforced.
+
+ at item Can run most 32-bit SPARC Linux binaries, SPARC32PLUS Linux binaries and
+some 64-bit SPARC Linux binaries.
+
+ at end itemize
+
+Current QEMU limitations:
+
+ at itemize
+
+ at item IPC syscalls are missing.
+
+ at item Floating point exception support is buggy.
+
+ at item Atomic instructions are not correctly implemented.
+
+ at item There are still some problems with Sparc64 emulators.
+
+ at end itemize
+
+ at node intro_other_emulation
+ at section Other CPU emulation
+
+In addition to the above, QEMU supports emulation of other CPUs with
+varying levels of success. These are:
+
+ at itemize
+
+ at item
+Alpha
+ at item
+CRIS
+ at item
+M68k
+ at item
+SH4
+ at end itemize
+
+ at node QEMU Internals
+ at chapter QEMU Internals
+
+ at menu
+* QEMU compared to other emulators::
+* Portable dynamic translation::
+* Condition code optimisations::
+* CPU state optimisations::
+* Translation cache::
+* Direct block chaining::
+* Self-modifying code and translated code invalidation::
+* Exception support::
+* MMU emulation::
+* Device emulation::
+* Hardware interrupts::
+* User emulation specific details::
+* Bibliography::
+ at end menu
+
+ at node QEMU compared to other emulators
+ at section QEMU compared to other emulators
+
+Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
+bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC
+emulation while QEMU can emulate several processors.
+
+Like Valgrind [2], QEMU does user space emulation and dynamic
+translation. Valgrind is mainly a memory debugger while QEMU has no
+support for it (QEMU could be used to detect out of bound memory
+accesses as Valgrind, but it has no support to track uninitialised data
+as Valgrind does). The Valgrind dynamic translator generates better code
+than QEMU (in particular it does register allocation) but it is closely
+tied to an x86 host and target and has no support for precise exceptions
+and system emulation.
+
+EM86 [4] is the closest project to user space QEMU (and QEMU still uses
+some of its code, in particular the ELF file loader). EM86 was limited
+to an alpha host and used a proprietary and slow interpreter (the
+interpreter part of the FX!32 Digital Win32 code translator [5]).
+
+TWIN [6] is a Windows API emulator like Wine. It is less accurate than
+Wine but includes a protected mode x86 interpreter to launch x86 Windows
+executables. Such an approach has greater potential because most of the
+Windows API is executed natively but it is far more difficult to develop
+because all the data structures and function parameters exchanged
+between the API and the x86 code must be converted.
+
+User mode Linux [7] was the only solution before QEMU to launch a
+Linux kernel as a process while not needing any host kernel
+patches. However, user mode Linux requires heavy kernel patches while
+QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is
+slower.
+
+The Plex86 [8] PC virtualizer is done in the same spirit as the now
+obsolete qemu-fast system emulator. It requires a patched Linux kernel
+to work (you cannot launch the same kernel on your PC), but the
+patches are really small. As it is a PC virtualizer (no emulation is
+done except for some privileged instructions), it has the potential of
+being faster than QEMU. The downside is that a complicated (and
+potentially unsafe) host kernel patch is needed.
+
+The commercial PC Virtualizers (VMWare [9], VirtualPC [10], TwoOStwo
+[11]) are faster than QEMU, but they all need specific, proprietary
+and potentially unsafe host drivers. Moreover, they are unable to
+provide cycle exact simulation as an emulator can.
+
+VirtualBox [12], Xen [13] and KVM [14] are based on QEMU. QEMU-SystemC
+[15] uses QEMU to simulate a system where some hardware devices are
+developed in SystemC.
+
+ at node Portable dynamic translation
+ at section Portable dynamic translation
+
+QEMU is a dynamic translator. When it first encounters a piece of code,
+it converts it to the host instruction set. Usually dynamic translators
+are very complicated and highly CPU dependent. QEMU uses some tricks
+which make it relatively easily portable and simple while achieving good
+performances.
+
+After the release of version 0.9.1, QEMU switched to a new method of
+generating code, Tiny Code Generator or TCG. TCG relaxes the
+dependency on the exact version of the compiler used. The basic idea
+is to split every target instruction into a couple of RISC-like TCG
+ops (see @code{target-i386/translate.c}). Some optimizations can be
+performed at this stage, including liveness analysis and trivial
+constant expression evaluation. TCG ops are then implemented in the
+host CPU back end, also known as TCG target (see
+ at code{tcg/i386/tcg-target.c}). For more information, please take a
+look at @code{tcg/README}.
+
+ at node Condition code optimisations
+ at section Condition code optimisations
+
+Lazy evaluation of CPU condition codes (@code{EFLAGS} register on x86)
+is important for CPUs where every instruction sets the condition
+codes. It tends to be less important on conventional RISC systems
+where condition codes are only updated when explicitly requested. On
+Sparc64, costly update of both 32 and 64 bit condition codes can be
+avoided with lazy evaluation.
+
+Instead of computing the condition codes after each x86 instruction,
+QEMU just stores one operand (called @code{CC_SRC}), the result
+(called @code{CC_DST}) and the type of operation (called
+ at code{CC_OP}). When the condition codes are needed, the condition
+codes can be calculated using this information. In addition, an
+optimized calculation can be performed for some instruction types like
+conditional branches.
+
+ at code{CC_OP} is almost never explicitly set in the generated code
+because it is known at translation time.
+
+The lazy condition code evaluation is used on x86, m68k, cris and
+Sparc. ARM uses a simplified variant for the N and Z flags.
+
+ at node CPU state optimisations
+ at section CPU state optimisations
+
+The target CPUs have many internal states which change the way it
+evaluates instructions. In order to achieve a good speed, the
+translation phase considers that some state information of the virtual
+CPU cannot change in it. The state is recorded in the Translation
+Block (TB). If the state changes (e.g. privilege level), a new TB will
+be generated and the previous TB won't be used anymore until the state
+matches the state recorded in the previous TB. For example, if the SS,
+DS and ES segments have a zero base, then the translator does not even
+generate an addition for the segment base.
+
+[The FPU stack pointer register is not handled that way yet].
+
+ at node Translation cache
+ at section Translation cache
+
+A 16 MByte cache holds the most recently used translations. For
+simplicity, it is completely flushed when it is full. A translation unit
+contains just a single basic block (a block of x86 instructions
+terminated by a jump or by a virtual CPU state change which the
+translator cannot deduce statically).
+
+ at node Direct block chaining
+ at section Direct block chaining
+
+After each translated basic block is executed, QEMU uses the simulated
+Program Counter (PC) and other cpu state informations (such as the CS
+segment base value) to find the next basic block.
+
+In order to accelerate the most common cases where the new simulated PC
+is known, QEMU can patch a basic block so that it jumps directly to the
+next one.
+
+The most portable code uses an indirect jump. An indirect jump makes
+it easier to make the jump target modification atomic. On some host
+architectures (such as x86 or PowerPC), the @code{JUMP} opcode is
+directly patched so that the block chaining has no overhead.
+
+ at node Self-modifying code and translated code invalidation
+ at section Self-modifying code and translated code invalidation
+
+Self-modifying code is a special challenge in x86 emulation because no
+instruction cache invalidation is signaled by the application when code
+is modified.
+
+When translated code is generated for a basic block, the corresponding
+host page is write protected if it is not already read-only. Then, if
+a write access is done to the page, Linux raises a SEGV signal. QEMU
+then invalidates all the translated code in the page and enables write
+accesses to the page.
+
+Correct translated code invalidation is done efficiently by maintaining
+a linked list of every translated block contained in a given page. Other
+linked lists are also maintained to undo direct block chaining.
+
+On RISC targets, correctly written software uses memory barriers and
+cache flushes, so some of the protection above would not be
+necessary. However, QEMU still requires that the generated code always
+matches the target instructions in memory in order to handle
+exceptions correctly.
+
+ at node Exception support
+ at section Exception support
+
+longjmp() is used when an exception such as division by zero is
+encountered.
+
+The host SIGSEGV and SIGBUS signal handlers are used to get invalid
+memory accesses. The simulated program counter is found by
+retranslating the corresponding basic block and by looking where the
+host program counter was at the exception point.
+
+The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
+in some cases it is not computed because of condition code
+optimisations. It is not a big concern because the emulated code can
+still be restarted in any cases.
+
+ at node MMU emulation
+ at section MMU emulation
+
+For system emulation QEMU supports a soft MMU. In that mode, the MMU
+virtual to physical address translation is done at every memory
+access. QEMU uses an address translation cache to speed up the
+translation.
+
+In order to avoid flushing the translated code each time the MMU
+mappings change, QEMU uses a physically indexed translation cache. It
+means that each basic block is indexed with its physical address.
+
+When MMU mappings change, only the chaining of the basic blocks is
+reset (i.e. a basic block can no longer jump directly to another one).
+
+ at node Device emulation
+ at section Device emulation
+
+Systems emulated by QEMU are organized by boards. At initialization
+phase, each board instantiates a number of CPUs, devices, RAM and
+ROM. Each device in turn can assign I/O ports or memory areas (for
+MMIO) to its handlers. When the emulation starts, an access to the
+ports or MMIO memory areas assigned to the device causes the
+corresponding handler to be called.
+
+RAM and ROM are handled more optimally, only the offset to the host
+memory needs to be added to the guest address.
+
+The video RAM of VGA and other display cards is special: it can be
+read or written directly like RAM, but write accesses cause the memory
+to be marked with VGA_DIRTY flag as well.
+
+QEMU supports some device classes like serial and parallel ports, USB,
+drives and network devices, by providing APIs for easier connection to
+the generic, higher level implementations. The API hides the
+implementation details from the devices, like native device use or
+advanced block device formats like QCOW.
+
+Usually the devices implement a reset method and register support for
+saving and loading of the device state. The devices can also use
+timers, especially together with the use of bottom halves (BHs).
+
+ at node Hardware interrupts
+ at section Hardware interrupts
+
+In order to be faster, QEMU does not check at every basic block if an
+hardware interrupt is pending. Instead, the user must asynchronously
+call a specific function to tell that an interrupt is pending. This
+function resets the chaining of the currently executing basic
+block. It ensures that the execution will return soon in the main loop
+of the CPU emulator. Then the main loop can test if the interrupt is
+pending and handle it.
+
+ at node User emulation specific details
+ at section User emulation specific details
+
+ at subsection Linux system call translation
+
+QEMU includes a generic system call translator for Linux. It means that
+the parameters of the system calls can be converted to fix the
+endianness and 32/64 bit issues. The IOCTLs are converted with a generic
+type description system (see @file{ioctls.h} and @file{thunk.c}).
+
+QEMU supports host CPUs which have pages bigger than 4KB. It records all
+the mappings the process does and try to emulated the @code{mmap()}
+system calls in cases where the host @code{mmap()} call would fail
+because of bad page alignment.
+
+ at subsection Linux signals
+
+Normal and real-time signals are queued along with their information
+(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt
+request is done to the virtual CPU. When it is interrupted, one queued
+signal is handled by generating a stack frame in the virtual CPU as the
+Linux kernel does. The @code{sigreturn()} system call is emulated to return
+from the virtual signal handler.
+
+Some signals (such as SIGALRM) directly come from the host. Other
+signals are synthesized from the virtual CPU exceptions such as SIGFPE
+when a division by zero is done (see @code{main.c:cpu_loop()}).
+
+The blocked signal mask is still handled by the host Linux kernel so
+that most signal system calls can be redirected directly to the host
+Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system
+calls need to be fully emulated (see @file{signal.c}).
+
+ at subsection clone() system call and threads
+
+The Linux clone() system call is usually used to create a thread. QEMU
+uses the host clone() system call so that real host threads are created
+for each emulated thread. One virtual CPU instance is created for each
+thread.
+
+The virtual x86 CPU atomic operations are emulated with a global lock so
+that their semantic is preserved.
+
+Note that currently there are still some locking issues in QEMU. In
+particular, the translated cache flush is not protected yet against
+reentrancy.
+
+ at subsection Self-virtualization
+
+QEMU was conceived so that ultimately it can emulate itself. Although
+it is not very useful, it is an important test to show the power of the
+emulator.
+
+Achieving self-virtualization is not easy because there may be address
+space conflicts. QEMU user emulators solve this problem by being an
+executable ELF shared object as the ld-linux.so ELF interpreter. That
+way, it can be relocated at load time.
+
+ at node Bibliography
+ at section Bibliography
+
+ at table @asis
+
+ at item [1]
+ at url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing
+direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio
+Riccardi.
+
+ at item [2]
+ at url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source
+memory debugger for x86-GNU/Linux, by Julian Seward.
+
+ at item [3]
+ at url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project,
+by Kevin Lawton et al.
+
+ at item [4]
+ at url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86
+x86 emulator on Alpha-Linux.
+
+ at item [5]
+ at url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/@/full_papers/chernoff/chernoff.pdf},
+DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
+Chernoff and Ray Hookway.
+
+ at item [6]
+ at url{http://www.willows.com/}, Windows API library emulation from
+Willows Software.
+
+ at item [7]
+ at url{http://user-mode-linux.sourceforge.net/},
+The User-mode Linux Kernel.
+
+ at item [8]
+ at url{http://www.plex86.org/},
+The new Plex86 project.
+
+ at item [9]
+ at url{http://www.vmware.com/},
+The VMWare PC virtualizer.
+
+ at item [10]
+ at url{http://www.microsoft.com/windowsxp/virtualpc/},
+The VirtualPC PC virtualizer.
+
+ at item [11]
+ at url{http://www.twoostwo.org/},
+The TwoOStwo PC virtualizer.
+
+ at item [12]
+ at url{http://virtualbox.org/},
+The VirtualBox PC virtualizer.
+
+ at item [13]
+ at url{http://www.xen.org/},
+The Xen hypervisor.
+
+ at item [14]
+ at url{http://kvm.qumranet.com/kvmwiki/Front_Page},
+Kernel Based Virtual Machine (KVM).
+
+ at item [15]
+ at url{http://www.greensocs.com/projects/QEMUSystemC},
+QEMU-SystemC, a hardware co-simulator.
+
+ at end table
+
+ at node Regression Tests
+ at chapter Regression Tests
+
+In the directory @file{tests/}, various interesting testing programs
+are available. They are used for regression testing.
+
+ at menu
+* test-i386::
+* linux-test::
+* qruncom.c::
+ at end menu
+
+ at node test-i386
+ at section @file{test-i386}
+
+This program executes most of the 16 bit and 32 bit x86 instructions and
+generates a text output. It can be compared with the output obtained with
+a real CPU or another emulator. The target @code{make test} runs this
+program and a @code{diff} on the generated output.
+
+The Linux system call @code{modify_ldt()} is used to create x86 selectors
+to test some 16 bit addressing and 32 bit with segmentation cases.
+
+The Linux system call @code{vm86()} is used to test vm86 emulation.
+
+Various exceptions are raised to test most of the x86 user space
+exception reporting.
+
+ at node linux-test
+ at section @file{linux-test}
+
+This program tests various Linux system calls. It is used to verify
+that the system call parameters are correctly converted between target
+and host CPUs.
+
+ at node qruncom.c
+ at section @file{qruncom.c}
+
+Example of usage of @code{libqemu} to emulate a user mode i386 CPU.
+
+ at node Index
+ at chapter Index
+ at printindex cp
+
+ at bye
diff --git a/qemu-0.15.x/qemu-thread-posix.c b/qemu-0.15.x/qemu-thread-posix.c
new file mode 100644
index 0000000..2bd02ef
--- /dev/null
+++ b/qemu-0.15.x/qemu-thread-posix.c
@@ -0,0 +1,149 @@
+/*
+ * Wrappers around mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Author:
+ *  Marcelo Tosatti <mtosatti at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include "qemu-thread.h"
+
+static void error_exit(int err, const char *msg)
+{
+    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
+    exit(1);
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+    int err;
+    pthread_mutexattr_t mutexattr;
+
+    pthread_mutexattr_init(&mutexattr);
+    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
+    err = pthread_mutex_init(&mutex->lock, &mutexattr);
+    pthread_mutexattr_destroy(&mutexattr);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_mutex_destroy(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_destroy(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_lock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+    return pthread_mutex_trylock(&mutex->lock);
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_unlock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_init(&cond->cond, NULL);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_destroy(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_destroy(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_signal(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_broadcast(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_cond_wait(&cond->cond, &mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void*),
+                       void *arg)
+{
+    int err;
+
+    /* Leave signal handling to the iothread.  */
+    sigset_t set, oldset;
+
+    sigfillset(&set);
+    pthread_sigmask(SIG_SETMASK, &set, &oldset);
+    err = pthread_create(&thread->thread, NULL, start_routine, arg);
+    if (err)
+        error_exit(err, __func__);
+
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+}
+
+void qemu_thread_get_self(QemuThread *thread)
+{
+    thread->thread = pthread_self();
+}
+
+int qemu_thread_is_self(QemuThread *thread)
+{
+   return pthread_equal(pthread_self(), thread->thread);
+}
+
+void qemu_thread_exit(void *retval)
+{
+    pthread_exit(retval);
+}
diff --git a/qemu-0.15.x/qemu-thread-posix.h b/qemu-0.15.x/qemu-thread-posix.h
new file mode 100644
index 0000000..ee4618e
--- /dev/null
+++ b/qemu-0.15.x/qemu-thread-posix.h
@@ -0,0 +1,17 @@
+#ifndef __QEMU_THREAD_POSIX_H
+#define __QEMU_THREAD_POSIX_H 1
+#include "pthread.h"
+
+struct QemuMutex {
+    pthread_mutex_t lock;
+};
+
+struct QemuCond {
+    pthread_cond_t cond;
+};
+
+struct QemuThread {
+    pthread_t thread;
+};
+
+#endif
diff --git a/qemu-0.15.x/qemu-thread-win32.c b/qemu-0.15.x/qemu-thread-win32.c
new file mode 100644
index 0000000..2d2d5ab
--- /dev/null
+++ b/qemu-0.15.x/qemu-thread-win32.c
@@ -0,0 +1,281 @@
+/*
+ * Win32 implementation for mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Author:
+ *  Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "qemu-thread.h"
+#include <process.h>
+#include <assert.h>
+#include <limits.h>
+
+static void error_exit(int err, const char *msg)
+{
+    char *pstr;
+
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                  NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
+    fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
+    LocalFree(pstr);
+    exit(1);
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+    mutex->owner = 0;
+    InitializeCriticalSection(&mutex->lock);
+}
+
+void qemu_mutex_destroy(QemuMutex *mutex)
+{
+    assert(mutex->owner == 0);
+    DeleteCriticalSection(&mutex->lock);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+    EnterCriticalSection(&mutex->lock);
+
+    /* Win32 CRITICAL_SECTIONs are recursive.  Assert that we're not
+     * using them as such.
+     */
+    assert(mutex->owner == 0);
+    mutex->owner = GetCurrentThreadId();
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+    int owned;
+
+    owned = TryEnterCriticalSection(&mutex->lock);
+    if (owned) {
+        assert(mutex->owner == 0);
+        mutex->owner = GetCurrentThreadId();
+    }
+    return !owned;
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+    assert(mutex->owner == GetCurrentThreadId());
+    mutex->owner = 0;
+    LeaveCriticalSection(&mutex->lock);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+    memset(cond, 0, sizeof(*cond));
+
+    cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
+    if (!cond->sema) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->continue_event = CreateEvent(NULL,    /* security */
+                                       FALSE,   /* auto-reset */
+                                       FALSE,   /* not signaled */
+                                       NULL);   /* name */
+    if (!cond->continue_event) {
+        error_exit(GetLastError(), __func__);
+    }
+}
+
+void qemu_cond_destroy(QemuCond *cond)
+{
+    BOOL result;
+    result = CloseHandle(cond->continue_event);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->continue_event = 0;
+    result = CloseHandle(cond->sema);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+    cond->sema = 0;
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+    DWORD result;
+
+    /*
+     * Signal only when there are waiters.  cond->waiters is
+     * incremented by pthread_cond_wait under the external lock,
+     * so we are safe about that.
+     */
+    if (cond->waiters == 0) {
+        return;
+    }
+
+    /*
+     * Waiting threads decrement it outside the external lock, but
+     * only if another thread is executing pthread_cond_broadcast and
+     * has the mutex.  So, it also cannot be decremented concurrently
+     * with this particular access.
+     */
+    cond->target = cond->waiters - 1;
+    result = SignalObjectAndWait(cond->sema, cond->continue_event,
+                                 INFINITE, FALSE);
+    if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
+        error_exit(GetLastError(), __func__);
+    }
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+    BOOLEAN result;
+    /*
+     * As in pthread_cond_signal, access to cond->waiters and
+     * cond->target is locked via the external mutex.
+     */
+    if (cond->waiters == 0) {
+        return;
+    }
+
+    cond->target = 0;
+    result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
+    if (!result) {
+        error_exit(GetLastError(), __func__);
+    }
+
+    /*
+     * At this point all waiters continue. Each one takes its
+     * slice of the semaphore. Now it's our turn to wait: Since
+     * the external mutex is held, no thread can leave cond_wait,
+     * yet. For this reason, we can be sure that no thread gets
+     * a chance to eat *more* than one slice. OTOH, it means
+     * that the last waiter must send us a wake-up.
+     */
+    WaitForSingleObject(cond->continue_event, INFINITE);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+    /*
+     * This access is protected under the mutex.
+     */
+    cond->waiters++;
+
+    /*
+     * Unlock external mutex and wait for signal.
+     * NOTE: we've held mutex locked long enough to increment
+     * waiters count above, so there's no problem with
+     * leaving mutex unlocked before we wait on semaphore.
+     */
+    qemu_mutex_unlock(mutex);
+    WaitForSingleObject(cond->sema, INFINITE);
+
+    /* Now waiters must rendez-vous with the signaling thread and
+     * let it continue.  For cond_broadcast this has heavy contention
+     * and triggers thundering herd.  So goes life.
+     *
+     * Decrease waiters count.  The mutex is not taken, so we have
+     * to do this atomically.
+     *
+     * All waiters contend for the mutex at the end of this function
+     * until the signaling thread relinquishes it.  To ensure
+     * each waiter consumes exactly one slice of the semaphore,
+     * the signaling thread stops until it is told by the last
+     * waiter that it can go on.
+     */
+    if (InterlockedDecrement(&cond->waiters) == cond->target) {
+        SetEvent(cond->continue_event);
+    }
+
+    qemu_mutex_lock(mutex);
+}
+
+struct QemuThreadData {
+    QemuThread *thread;
+    void *(*start_routine)(void *);
+    void *arg;
+};
+
+static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES;
+
+static unsigned __stdcall win32_start_routine(void *arg)
+{
+    struct QemuThreadData data = *(struct QemuThreadData *) arg;
+    QemuThread *thread = data.thread;
+
+    free(arg);
+    TlsSetValue(qemu_thread_tls_index, thread);
+
+    /*
+     * Use DuplicateHandle instead of assigning thread->thread in the
+     * creating thread to avoid races.  It's simpler this way than with
+     * synchronization.
+     */
+    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+                    GetCurrentProcess(), &thread->thread,
+                    0, FALSE, DUPLICATE_SAME_ACCESS);
+
+    qemu_thread_exit(data.start_routine(data.arg));
+    abort();
+}
+
+void qemu_thread_exit(void *arg)
+{
+    QemuThread *thread = TlsGetValue(qemu_thread_tls_index);
+    thread->ret = arg;
+    CloseHandle(thread->thread);
+    thread->thread = NULL;
+    ExitThread(0);
+}
+
+static inline void qemu_thread_init(void)
+{
+    if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
+        qemu_thread_tls_index = TlsAlloc();
+        if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
+            error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__);
+        }
+    }
+}
+
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void *),
+                       void *arg)
+{
+    HANDLE hThread;
+
+    struct QemuThreadData *data;
+    qemu_thread_init();
+    data = qemu_malloc(sizeof *data);
+    data->thread = thread;
+    data->start_routine = start_routine;
+    data->arg = arg;
+
+    hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
+                                      data, 0, NULL);
+    if (!hThread) {
+        error_exit(GetLastError(), __func__);
+    }
+    CloseHandle(hThread);
+}
+
+void qemu_thread_get_self(QemuThread *thread)
+{
+    if (!thread->thread) {
+        /* In the main thread of the process.  Initialize the QemuThread
+           pointer in TLS, and use the dummy GetCurrentThread handle as
+           the identifier for qemu_thread_is_self.  */
+        qemu_thread_init();
+        TlsSetValue(qemu_thread_tls_index, thread);
+        thread->thread = GetCurrentThread();
+    }
+}
+
+int qemu_thread_is_self(QemuThread *thread)
+{
+    QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index);
+    return this_thread->thread == thread->thread;
+}
diff --git a/qemu-0.15.x/qemu-thread-win32.h b/qemu-0.15.x/qemu-thread-win32.h
new file mode 100644
index 0000000..878f86a
--- /dev/null
+++ b/qemu-0.15.x/qemu-thread-win32.h
@@ -0,0 +1,21 @@
+#ifndef __QEMU_THREAD_WIN32_H
+#define __QEMU_THREAD_WIN32_H 1
+#include "windows.h"
+
+struct QemuMutex {
+    CRITICAL_SECTION lock;
+    LONG owner;
+};
+
+struct QemuCond {
+    LONG waiters, target;
+    HANDLE sema;
+    HANDLE continue_event;
+};
+
+struct QemuThread {
+    HANDLE thread;
+    void *ret;
+};
+
+#endif
diff --git a/qemu-0.15.x/qemu-thread.h b/qemu-0.15.x/qemu-thread.h
new file mode 100644
index 0000000..0a73d50
--- /dev/null
+++ b/qemu-0.15.x/qemu-thread.h
@@ -0,0 +1,41 @@
+#ifndef __QEMU_THREAD_H
+#define __QEMU_THREAD_H 1
+
+#include <inttypes.h>
+
+typedef struct QemuMutex QemuMutex;
+typedef struct QemuCond QemuCond;
+typedef struct QemuThread QemuThread;
+
+#ifdef _WIN32
+#include "qemu-thread-win32.h"
+#else
+#include "qemu-thread-posix.h"
+#endif
+
+void qemu_mutex_init(QemuMutex *mutex);
+void qemu_mutex_destroy(QemuMutex *mutex);
+void qemu_mutex_lock(QemuMutex *mutex);
+int qemu_mutex_trylock(QemuMutex *mutex);
+void qemu_mutex_unlock(QemuMutex *mutex);
+
+void qemu_cond_init(QemuCond *cond);
+void qemu_cond_destroy(QemuCond *cond);
+
+/*
+ * IMPORTANT: The implementation does not guarantee that pthread_cond_signal
+ * and pthread_cond_broadcast can be called except while the same mutex is
+ * held as in the corresponding pthread_cond_wait calls!
+ */
+void qemu_cond_signal(QemuCond *cond);
+void qemu_cond_broadcast(QemuCond *cond);
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void*),
+                       void *arg);
+void qemu_thread_get_self(QemuThread *thread);
+int qemu_thread_is_self(QemuThread *thread);
+void qemu_thread_exit(void *retval);
+
+#endif
diff --git a/qemu-0.15.x/qemu-timer-common.c b/qemu-0.15.x/qemu-timer-common.c
new file mode 100644
index 0000000..755e300
--- /dev/null
+++ b/qemu-0.15.x/qemu-timer-common.c
@@ -0,0 +1,63 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "qemu-timer.h"
+
+/***********************************************************/
+/* real time host monotonic timer */
+
+#ifdef _WIN32
+
+int64_t clock_freq;
+
+static void __attribute__((constructor)) init_get_clock(void)
+{
+    LARGE_INTEGER freq;
+    int ret;
+    ret = QueryPerformanceFrequency(&freq);
+    if (ret == 0) {
+        fprintf(stderr, "Could not calibrate ticks\n");
+        exit(1);
+    }
+    clock_freq = freq.QuadPart;
+}
+
+#else
+
+int use_rt_clock;
+
+static void __attribute__((constructor)) init_get_clock(void)
+{
+    use_rt_clock = 0;
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
+    || defined(__OpenBSD__)
+    {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            use_rt_clock = 1;
+        }
+    }
+#endif
+}
+#endif
diff --git a/qemu-0.15.x/qemu-timer.c b/qemu-0.15.x/qemu-timer.c
new file mode 100644
index 0000000..30e8f12
--- /dev/null
+++ b/qemu-0.15.x/qemu-timer.c
@@ -0,0 +1,1218 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 "sysemu.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+
+#include "hw/hw.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
+#include "qemu-timer.h"
+
+/* Conversion factor from emulated instructions to virtual clock ticks.  */
+int icount_time_shift;
+/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
+#define MAX_ICOUNT_SHIFT 10
+/* Compensate for varying guest execution speed.  */
+int64_t qemu_icount_bias;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+
+/***********************************************************/
+/* guest cycle counter */
+
+typedef struct TimersState {
+    int64_t cpu_ticks_prev;
+    int64_t cpu_ticks_offset;
+    int64_t cpu_clock_offset;
+    int32_t cpu_ticks_enabled;
+    int64_t dummy;
+} TimersState;
+
+TimersState timers_state;
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+    if (use_icount) {
+        return cpu_get_icount();
+    }
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_ticks_offset;
+    } else {
+        int64_t ticks;
+        ticks = cpu_get_real_ticks();
+        if (timers_state.cpu_ticks_prev > ticks) {
+            /* Note: non increasing ticks may happen if the host uses
+               software suspend */
+            timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+        }
+        timers_state.cpu_ticks_prev = ticks;
+        return ticks + timers_state.cpu_ticks_offset;
+    }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+    int64_t ti;
+    if (!timers_state.cpu_ticks_enabled) {
+        return timers_state.cpu_clock_offset;
+    } else {
+        ti = get_clock();
+        return ti + timers_state.cpu_clock_offset;
+    }
+}
+
+#ifndef CONFIG_IOTHREAD
+static int64_t qemu_icount_delta(void)
+{
+    if (!use_icount) {
+        return 5000 * (int64_t) 1000000;
+    } else if (use_icount == 1) {
+        /* When not using an adaptive execution frequency
+           we tend to get badly out of sync with real time,
+           so just delay for a reasonable amount of time.  */
+        return 0;
+    } else {
+        return cpu_get_icount() - cpu_get_clock();
+    }
+}
+#endif
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+    if (!timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
+        timers_state.cpu_clock_offset -= get_clock();
+        timers_state.cpu_ticks_enabled = 1;
+    }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+   cpu_get_ticks() after that.  */
+void cpu_disable_ticks(void)
+{
+    if (timers_state.cpu_ticks_enabled) {
+        timers_state.cpu_ticks_offset = cpu_get_ticks();
+        timers_state.cpu_clock_offset = cpu_get_clock();
+        timers_state.cpu_ticks_enabled = 0;
+    }
+}
+
+/***********************************************************/
+/* timers */
+
+#define QEMU_CLOCK_REALTIME 0
+#define QEMU_CLOCK_VIRTUAL  1
+#define QEMU_CLOCK_HOST     2
+
+struct QEMUClock {
+    int type;
+    int enabled;
+
+    QEMUTimer *warp_timer;
+
+    NotifierList reset_notifiers;
+    int64_t last;
+};
+
+struct QEMUTimer {
+    QEMUClock *clock;
+    int64_t expire_time;	/* in nanoseconds */
+    int scale;
+    QEMUTimerCB *cb;
+    void *opaque;
+    struct QEMUTimer *next;
+};
+
+struct qemu_alarm_timer {
+    char const *name;
+    int (*start)(struct qemu_alarm_timer *t);
+    void (*stop)(struct qemu_alarm_timer *t);
+    void (*rearm)(struct qemu_alarm_timer *t);
+#if defined(__linux__)
+    int fd;
+    timer_t timer;
+#elif defined(_WIN32)
+    HANDLE timer;
+#endif
+    char expired;
+    char pending;
+};
+
+static struct qemu_alarm_timer *alarm_timer;
+
+static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
+{
+    return timer_head && (timer_head->expire_time <= current_time);
+}
+
+int qemu_alarm_pending(void)
+{
+    return alarm_timer->pending;
+}
+
+static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
+{
+    return !!t->rearm;
+}
+
+static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
+{
+    if (!alarm_has_dynticks(t))
+        return;
+
+    t->rearm(t);
+}
+
+/* TODO: MIN_TIMER_REARM_NS should be optimized */
+#define MIN_TIMER_REARM_NS 250000
+
+#ifdef _WIN32
+
+static int mm_start_timer(struct qemu_alarm_timer *t);
+static void mm_stop_timer(struct qemu_alarm_timer *t);
+static void mm_rearm_timer(struct qemu_alarm_timer *t);
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t);
+
+#else
+
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+static void unix_rearm_timer(struct qemu_alarm_timer *t);
+
+#ifdef __linux__
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t);
+static void dynticks_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+
+#endif /* __linux__ */
+
+#endif /* _WIN32 */
+
+/* Correlation between real and virtual time is always going to be
+   fairly approximate, so ignore small variation.
+   When the guest is idle real and virtual time will be aligned in
+   the IO wait loop.  */
+#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
+
+static void icount_adjust(void)
+{
+    int64_t cur_time;
+    int64_t cur_icount;
+    int64_t delta;
+    static int64_t last_delta;
+    /* If the VM is not running, then do nothing.  */
+    if (!vm_running)
+        return;
+
+    cur_time = cpu_get_clock();
+    cur_icount = qemu_get_clock_ns(vm_clock);
+    delta = cur_icount - cur_time;
+    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
+    if (delta > 0
+        && last_delta + ICOUNT_WOBBLE < delta * 2
+        && icount_time_shift > 0) {
+        /* The guest is getting too far ahead.  Slow time down.  */
+        icount_time_shift--;
+    }
+    if (delta < 0
+        && last_delta - ICOUNT_WOBBLE > delta * 2
+        && icount_time_shift < MAX_ICOUNT_SHIFT) {
+        /* The guest is getting too far behind.  Speed time up.  */
+        icount_time_shift++;
+    }
+    last_delta = delta;
+    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+}
+
+static void icount_adjust_rt(void * opaque)
+{
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_adjust();
+}
+
+static void icount_adjust_vm(void * opaque)
+{
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+    icount_adjust();
+}
+
+int64_t qemu_icount_round(int64_t count)
+{
+    return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
+}
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifndef _WIN32
+#ifdef __linux__
+    {"dynticks", dynticks_start_timer,
+     dynticks_stop_timer, dynticks_rearm_timer},
+#endif
+    {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer},
+#else
+    {"mmtimer", mm_start_timer, mm_stop_timer, NULL},
+    {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer},
+    {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer},
+    {"win32", win32_start_timer, win32_stop_timer, NULL},
+#endif
+    {NULL, }
+};
+
+static void show_available_alarms(void)
+{
+    int i;
+
+    printf("Available alarm timers, in order of precedence:\n");
+    for (i = 0; alarm_timers[i].name; i++)
+        printf("%s\n", alarm_timers[i].name);
+}
+
+void configure_alarms(char const *opt)
+{
+    int i;
+    int cur = 0;
+    int count = ARRAY_SIZE(alarm_timers) - 1;
+    char *arg;
+    char *name;
+    struct qemu_alarm_timer tmp;
+
+    if (!strcmp(opt, "?")) {
+        show_available_alarms();
+        exit(0);
+    }
+
+    arg = qemu_strdup(opt);
+
+    /* Reorder the array */
+    name = strtok(arg, ",");
+    while (name) {
+        for (i = 0; i < count && alarm_timers[i].name; i++) {
+            if (!strcmp(alarm_timers[i].name, name))
+                break;
+        }
+
+        if (i == count) {
+            fprintf(stderr, "Unknown clock %s\n", name);
+            goto next;
+        }
+
+        if (i < cur)
+            /* Ignore */
+            goto next;
+
+	/* Swap */
+        tmp = alarm_timers[i];
+        alarm_timers[i] = alarm_timers[cur];
+        alarm_timers[cur] = tmp;
+
+        cur++;
+next:
+        name = strtok(NULL, ",");
+    }
+
+    qemu_free(arg);
+
+    if (cur) {
+        /* Disable remaining timers */
+        for (i = cur; i < count; i++)
+            alarm_timers[i].name = NULL;
+    } else {
+        show_available_alarms();
+        exit(1);
+    }
+}
+
+#define QEMU_NUM_CLOCKS 3
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+QEMUClock *host_clock;
+
+static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
+
+static QEMUClock *qemu_new_clock(int type)
+{
+    QEMUClock *clock;
+
+    clock = qemu_mallocz(sizeof(QEMUClock));
+    clock->type = type;
+    clock->enabled = 1;
+    notifier_list_init(&clock->reset_notifiers);
+    /* required to detect & report backward jumps */
+    if (type == QEMU_CLOCK_HOST) {
+        clock->last = get_clock_realtime();
+    }
+    return clock;
+}
+
+void qemu_clock_enable(QEMUClock *clock, int enabled)
+{
+    clock->enabled = enabled;
+}
+
+static int64_t vm_clock_warp_start;
+
+static void icount_warp_rt(void *opaque)
+{
+    if (vm_clock_warp_start == -1) {
+        return;
+    }
+
+    if (vm_running) {
+        int64_t clock = qemu_get_clock_ns(rt_clock);
+        int64_t warp_delta = clock - vm_clock_warp_start;
+        if (use_icount == 1) {
+            qemu_icount_bias += warp_delta;
+        } else {
+            /*
+             * In adaptive mode, do not let the vm_clock run too
+             * far ahead of real time.
+             */
+            int64_t cur_time = cpu_get_clock();
+            int64_t cur_icount = qemu_get_clock_ns(vm_clock);
+            int64_t delta = cur_time - cur_icount;
+            qemu_icount_bias += MIN(warp_delta, delta);
+        }
+        if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
+                               qemu_get_clock_ns(vm_clock))) {
+            qemu_notify_event();
+        }
+    }
+    vm_clock_warp_start = -1;
+}
+
+void qemu_clock_warp(QEMUClock *clock)
+{
+    int64_t deadline;
+
+    if (!clock->warp_timer) {
+        return;
+    }
+
+    /*
+     * There are too many global variables to make the "warp" behavior
+     * applicable to other clocks.  But a clock argument removes the
+     * need for if statements all over the place.
+     */
+    assert(clock == vm_clock);
+
+    /*
+     * If the CPUs have been sleeping, advance the vm_clock timer now.  This
+     * ensures that the deadline for the timer is computed correctly below.
+     * This also makes sure that the insn counter is synchronized before the
+     * CPU starts running, in case the CPU is woken by an event other than
+     * the earliest vm_clock timer.
+     */
+    icount_warp_rt(NULL);
+    if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
+        qemu_del_timer(clock->warp_timer);
+        return;
+    }
+
+    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
+    deadline = qemu_next_icount_deadline();
+    if (deadline > 0) {
+        /*
+         * Ensure the vm_clock proceeds even when the virtual CPU goes to
+         * sleep.  Otherwise, the CPU might be waiting for a future timer
+         * interrupt to wake it up, but the interrupt never comes because
+         * the vCPU isn't running any insns and thus doesn't advance the
+         * vm_clock.
+         *
+         * An extreme solution for this problem would be to never let VCPUs
+         * sleep in icount mode if there is a pending vm_clock timer; rather
+         * time could just advance to the next vm_clock event.  Instead, we
+         * do stop VCPUs and only advance vm_clock after some "real" time,
+         * (related to the time left until the next event) has passed.  This
+         * rt_clock timer will do this.  This avoids that the warps are too
+         * visible externally---for example, you will not be sending network
+         * packets continously instead of every 100ms.
+         */
+        qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline);
+    } else {
+        qemu_notify_event();
+    }
+}
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque)
+{
+    QEMUTimer *ts;
+
+    ts = qemu_mallocz(sizeof(QEMUTimer));
+    ts->clock = clock;
+    ts->cb = cb;
+    ts->opaque = opaque;
+    ts->scale = scale;
+    return ts;
+}
+
+void qemu_free_timer(QEMUTimer *ts)
+{
+    qemu_free(ts);
+}
+
+/* stop a timer, but do not dealloc it */
+void qemu_del_timer(QEMUTimer *ts)
+{
+    QEMUTimer **pt, *t;
+
+    /* NOTE: this code must be signal safe because
+       qemu_timer_expired() can be called from a signal. */
+    pt = &active_timers[ts->clock->type];
+    for(;;) {
+        t = *pt;
+        if (!t)
+            break;
+        if (t == ts) {
+            *pt = t->next;
+            break;
+        }
+        pt = &t->next;
+    }
+}
+
+/* modify the current timer so that it will be fired when current_time
+   >= expire_time. The corresponding callback will be called. */
+static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
+{
+    QEMUTimer **pt, *t;
+
+    qemu_del_timer(ts);
+
+    /* add the timer in the sorted list */
+    /* NOTE: this code must be signal safe because
+       qemu_timer_expired() can be called from a signal. */
+    pt = &active_timers[ts->clock->type];
+    for(;;) {
+        t = *pt;
+        if (!qemu_timer_expired_ns(t, expire_time)) {
+            break;
+        }
+        pt = &t->next;
+    }
+    ts->expire_time = expire_time;
+    ts->next = *pt;
+    *pt = ts;
+
+    /* Rearm if necessary  */
+    if (pt == &active_timers[ts->clock->type]) {
+        if (!alarm_timer->pending) {
+            qemu_rearm_alarm_timer(alarm_timer);
+        }
+        /* Interrupt execution to force deadline recalculation.  */
+        qemu_clock_warp(ts->clock);
+        if (use_icount) {
+            qemu_notify_event();
+        }
+    }
+}
+
+/* modify the current timer so that it will be fired when current_time
+   >= expire_time. The corresponding callback will be called. */
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+{
+    qemu_mod_timer_ns(ts, expire_time * ts->scale);
+}
+
+int qemu_timer_pending(QEMUTimer *ts)
+{
+    QEMUTimer *t;
+    for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+        if (t == ts)
+            return 1;
+    }
+    return 0;
+}
+
+int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
+{
+    return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
+}
+
+static void qemu_run_timers(QEMUClock *clock)
+{
+    QEMUTimer **ptimer_head, *ts;
+    int64_t current_time;
+   
+    if (!clock->enabled)
+        return;
+
+    current_time = qemu_get_clock_ns(clock);
+    ptimer_head = &active_timers[clock->type];
+    for(;;) {
+        ts = *ptimer_head;
+        if (!qemu_timer_expired_ns(ts, current_time)) {
+            break;
+        }
+        /* remove timer from the list before calling the callback */
+        *ptimer_head = ts->next;
+        ts->next = NULL;
+
+        /* run the callback (the timer list can be modified) */
+        ts->cb(ts->opaque);
+    }
+}
+
+int64_t qemu_get_clock_ns(QEMUClock *clock)
+{
+    int64_t now, last;
+
+    switch(clock->type) {
+    case QEMU_CLOCK_REALTIME:
+        return get_clock();
+    default:
+    case QEMU_CLOCK_VIRTUAL:
+        if (use_icount) {
+            return cpu_get_icount();
+        } else {
+            return cpu_get_clock();
+        }
+    case QEMU_CLOCK_HOST:
+        now = get_clock_realtime();
+        last = clock->last;
+        clock->last = now;
+        if (now < last) {
+            notifier_list_notify(&clock->reset_notifiers, &now);
+        }
+        return now;
+    }
+}
+
+void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
+{
+    notifier_list_add(&clock->reset_notifiers, notifier);
+}
+
+void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
+{
+    notifier_list_remove(&clock->reset_notifiers, notifier);
+}
+
+void init_clocks(void)
+{
+    rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
+    vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
+    host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
+
+    rtc_clock = host_clock;
+}
+
+/* save a timer */
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    if (qemu_timer_pending(ts)) {
+        expire_time = ts->expire_time;
+    } else {
+        expire_time = -1;
+    }
+    qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_get_be64(f);
+    if (expire_time != -1) {
+        qemu_mod_timer_ns(ts, expire_time);
+    } else {
+        qemu_del_timer(ts);
+    }
+}
+
+static const VMStateDescription vmstate_timers = {
+    .name = "timer",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT64(cpu_ticks_offset, TimersState),
+        VMSTATE_INT64(dummy, TimersState),
+        VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void configure_icount(const char *option)
+{
+    vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+    if (!option)
+        return;
+
+#ifdef CONFIG_IOTHREAD
+    vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+#endif
+
+    if (strcmp(option, "auto") != 0) {
+        icount_time_shift = strtol(option, NULL, 0);
+        use_icount = 1;
+        return;
+    }
+
+    use_icount = 2;
+
+    /* 125MIPS seems a reasonable initial guess at the guest speed.
+       It will be corrected fairly quickly anyway.  */
+    icount_time_shift = 3;
+
+    /* Have both realtime and virtual time triggers for speed adjustment.
+       The realtime trigger catches emulated time passing too slowly,
+       the virtual time trigger catches emulated time passing too fast.
+       Realtime triggers occur even when idle, so use them less frequently
+       than VM triggers.  */
+    icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock_ms(rt_clock) + 1000);
+    icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+}
+
+void qemu_run_all_timers(void)
+{
+    alarm_timer->pending = 0;
+
+    /* rearm timer, if not periodic */
+    if (alarm_timer->expired) {
+        alarm_timer->expired = 0;
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
+
+    /* vm time timers */
+    if (vm_running) {
+        qemu_run_timers(vm_clock);
+    }
+
+    qemu_run_timers(rt_clock);
+    qemu_run_timers(host_clock);
+}
+
+static int64_t qemu_next_alarm_deadline(void);
+
+#ifdef _WIN32
+static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused)
+#else
+static void host_alarm_handler(int host_signum)
+#endif
+{
+    struct qemu_alarm_timer *t = alarm_timer;
+    if (!t)
+	return;
+
+#if 0
+#define DISP_FREQ 1000
+    {
+        static int64_t delta_min = INT64_MAX;
+        static int64_t delta_max, delta_cum, last_clock, delta, ti;
+        static int count;
+        ti = qemu_get_clock_ns(vm_clock);
+        if (last_clock != 0) {
+            delta = ti - last_clock;
+            if (delta < delta_min)
+                delta_min = delta;
+            if (delta > delta_max)
+                delta_max = delta;
+            delta_cum += delta;
+            if (++count == DISP_FREQ) {
+                printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
+                       muldiv64(delta_min, 1000000, get_ticks_per_sec()),
+                       muldiv64(delta_max, 1000000, get_ticks_per_sec()),
+                       muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()),
+                       (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ));
+                count = 0;
+                delta_min = INT64_MAX;
+                delta_max = 0;
+                delta_cum = 0;
+            }
+        }
+        last_clock = ti;
+    }
+#endif
+    if (alarm_has_dynticks(t) ||
+        qemu_next_alarm_deadline () <= 0) {
+        t->expired = alarm_has_dynticks(t);
+        t->pending = 1;
+        qemu_notify_event();
+    }
+}
+
+int64_t qemu_next_icount_deadline(void)
+{
+    /* To avoid problems with overflow limit this to 2^32.  */
+    int64_t delta = INT32_MAX;
+
+    assert(use_icount);
+    if (active_timers[QEMU_CLOCK_VIRTUAL]) {
+        delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
+                     qemu_get_clock_ns(vm_clock);
+    }
+
+    if (delta < 0)
+        delta = 0;
+
+    return delta;
+}
+
+static int64_t qemu_next_alarm_deadline(void)
+{
+    int64_t delta;
+    int64_t rtdelta;
+
+    if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
+        delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
+                     qemu_get_clock_ns(vm_clock);
+    } else {
+        delta = INT32_MAX;
+    }
+    if (active_timers[QEMU_CLOCK_HOST]) {
+        int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
+                 qemu_get_clock_ns(host_clock);
+        if (hdelta < delta)
+            delta = hdelta;
+    }
+    if (active_timers[QEMU_CLOCK_REALTIME]) {
+        rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
+                 qemu_get_clock_ns(rt_clock));
+        if (rtdelta < delta)
+            delta = rtdelta;
+    }
+
+    return delta;
+}
+
+#if defined(__linux__)
+
+#include "compatfd.h"
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigevent ev;
+    timer_t host_timer;
+    struct sigaction act;
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+
+    /* 
+     * Initialize ev struct to 0 to avoid valgrind complaining
+     * about uninitialized data in timer_create call
+     */
+    memset(&ev, 0, sizeof(ev));
+    ev.sigev_value.sival_int = 0;
+    ev.sigev_notify = SIGEV_SIGNAL;
+#ifdef SIGEV_THREAD_ID
+    if (qemu_signalfd_available()) {
+        ev.sigev_notify = SIGEV_THREAD_ID;
+        ev._sigev_un._tid = qemu_get_thread_id();
+    }
+#endif /* SIGEV_THREAD_ID */
+    ev.sigev_signo = SIGALRM;
+
+    if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
+        perror("timer_create");
+
+        /* disable dynticks */
+        fprintf(stderr, "Dynamic Ticks disabled\n");
+
+        return -1;
+    }
+
+    t->timer = host_timer;
+
+    return 0;
+}
+
+static void dynticks_stop_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = t->timer;
+
+    timer_delete(host_timer);
+}
+
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = t->timer;
+    struct itimerspec timeout;
+    int64_t nearest_delta_ns = INT64_MAX;
+    int64_t current_ns;
+
+    assert(alarm_has_dynticks(t));
+    if (!active_timers[QEMU_CLOCK_REALTIME] &&
+        !active_timers[QEMU_CLOCK_VIRTUAL] &&
+        !active_timers[QEMU_CLOCK_HOST])
+        return;
+
+    nearest_delta_ns = qemu_next_alarm_deadline();
+    if (nearest_delta_ns < MIN_TIMER_REARM_NS)
+        nearest_delta_ns = MIN_TIMER_REARM_NS;
+
+    /* check whether a timer is already running */
+    if (timer_gettime(host_timer, &timeout)) {
+        perror("gettime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+    current_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec;
+    if (current_ns && current_ns <= nearest_delta_ns)
+        return;
+
+    timeout.it_interval.tv_sec = 0;
+    timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+    timeout.it_value.tv_sec =  nearest_delta_ns / 1000000000;
+    timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000;
+    if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
+        perror("settime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+}
+
+#endif /* defined(__linux__) */
+
+#if !defined(_WIN32)
+
+static int unix_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigaction act;
+
+    /* timer signal */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+    return 0;
+}
+
+static void unix_rearm_timer(struct qemu_alarm_timer *t)
+{
+    struct itimerval itv;
+    int64_t nearest_delta_ns = INT64_MAX;
+    int err;
+
+    assert(alarm_has_dynticks(t));
+    if (!active_timers[QEMU_CLOCK_REALTIME] &&
+        !active_timers[QEMU_CLOCK_VIRTUAL] &&
+        !active_timers[QEMU_CLOCK_HOST])
+        return;
+
+    nearest_delta_ns = qemu_next_alarm_deadline();
+    if (nearest_delta_ns < MIN_TIMER_REARM_NS)
+        nearest_delta_ns = MIN_TIMER_REARM_NS;
+
+    itv.it_interval.tv_sec = 0;
+    itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */
+    itv.it_value.tv_sec =  nearest_delta_ns / 1000000000;
+    itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000;
+    err = setitimer(ITIMER_REAL, &itv, NULL);
+    if (err) {
+        perror("setitimer");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
+{
+    struct itimerval itv;
+
+    memset(&itv, 0, sizeof(itv));
+    setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+#endif /* !defined(_WIN32) */
+
+
+#ifdef _WIN32
+
+static MMRESULT mm_timer;
+static unsigned mm_period;
+
+static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
+                                      DWORD_PTR dwUser, DWORD_PTR dw1,
+                                      DWORD_PTR dw2)
+{
+    struct qemu_alarm_timer *t = alarm_timer;
+    if (!t) {
+        return;
+    }
+    if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) {
+        t->expired = alarm_has_dynticks(t);
+        t->pending = 1;
+        qemu_notify_event();
+    }
+}
+
+static int mm_start_timer(struct qemu_alarm_timer *t)
+{
+    TIMECAPS tc;
+    UINT flags;
+
+    memset(&tc, 0, sizeof(tc));
+    timeGetDevCaps(&tc, sizeof(tc));
+
+    mm_period = tc.wPeriodMin;
+    timeBeginPeriod(mm_period);
+
+    flags = TIME_CALLBACK_FUNCTION;
+    if (alarm_has_dynticks(t)) {
+        flags |= TIME_ONESHOT;
+    } else {
+        flags |= TIME_PERIODIC;
+    }
+
+    mm_timer = timeSetEvent(1,                  /* interval (ms) */
+                            mm_period,          /* resolution */
+                            mm_alarm_handler,   /* function */
+                            (DWORD_PTR)t,       /* parameter */
+                            flags);
+
+    if (!mm_timer) {
+        fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
+                GetLastError());
+        timeEndPeriod(mm_period);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void mm_stop_timer(struct qemu_alarm_timer *t)
+{
+    timeKillEvent(mm_timer);
+    timeEndPeriod(mm_period);
+}
+
+static void mm_rearm_timer(struct qemu_alarm_timer *t)
+{
+    int nearest_delta_ms;
+
+    assert(alarm_has_dynticks(t));
+    if (!active_timers[QEMU_CLOCK_REALTIME] &&
+        !active_timers[QEMU_CLOCK_VIRTUAL] &&
+        !active_timers[QEMU_CLOCK_HOST]) {
+        return;
+    }
+
+    timeKillEvent(mm_timer);
+
+    nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+    if (nearest_delta_ms < 1) {
+        nearest_delta_ms = 1;
+    }
+    mm_timer = timeSetEvent(nearest_delta_ms,
+                            mm_period,
+                            mm_alarm_handler,
+                            (DWORD_PTR)t,
+                            TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
+
+    if (!mm_timer) {
+        fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
+                GetLastError());
+
+        timeEndPeriod(mm_period);
+        exit(1);
+    }
+}
+
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+    HANDLE hTimer;
+    BOOLEAN success;
+
+    /* If you call ChangeTimerQueueTimer on a one-shot timer (its period
+       is zero) that has already expired, the timer is not updated.  Since
+       creating a new timer is relatively expensive, set a bogus one-hour
+       interval in the dynticks case.  */
+    success = CreateTimerQueueTimer(&hTimer,
+                          NULL,
+                          host_alarm_handler,
+                          t,
+                          1,
+                          alarm_has_dynticks(t) ? 3600000 : 1,
+                          WT_EXECUTEINTIMERTHREAD);
+
+    if (!success) {
+        fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
+                GetLastError());
+        return -1;
+    }
+
+    t->timer = hTimer;
+    return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+    HANDLE hTimer = t->timer;
+
+    if (hTimer) {
+        DeleteTimerQueueTimer(NULL, hTimer, NULL);
+    }
+}
+
+static void win32_rearm_timer(struct qemu_alarm_timer *t)
+{
+    HANDLE hTimer = t->timer;
+    int nearest_delta_ms;
+    BOOLEAN success;
+
+    assert(alarm_has_dynticks(t));
+    if (!active_timers[QEMU_CLOCK_REALTIME] &&
+        !active_timers[QEMU_CLOCK_VIRTUAL] &&
+        !active_timers[QEMU_CLOCK_HOST])
+        return;
+
+    nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+    if (nearest_delta_ms < 1) {
+        nearest_delta_ms = 1;
+    }
+    success = ChangeTimerQueueTimer(NULL,
+                                    hTimer,
+                                    nearest_delta_ms,
+                                    3600000);
+
+    if (!success) {
+        fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n",
+                GetLastError());
+        exit(-1);
+    }
+
+}
+
+#endif /* _WIN32 */
+
+static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)
+{
+    if (running)
+        qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
+}
+
+int init_timer_alarm(void)
+{
+    struct qemu_alarm_timer *t = NULL;
+    int i, err = -1;
+
+    for (i = 0; alarm_timers[i].name; i++) {
+        t = &alarm_timers[i];
+
+        err = t->start(t);
+        if (!err)
+            break;
+    }
+
+    if (err) {
+        err = -ENOENT;
+        goto fail;
+    }
+
+    /* first event is at time 0 */
+    t->pending = 1;
+    alarm_timer = t;
+    qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t);
+
+    return 0;
+
+fail:
+    return err;
+}
+
+void quit_timers(void)
+{
+    struct qemu_alarm_timer *t = alarm_timer;
+    alarm_timer = NULL;
+    t->stop(t);
+}
+
+int qemu_calculate_timeout(void)
+{
+#ifndef CONFIG_IOTHREAD
+    int timeout;
+
+    if (!vm_running)
+        timeout = 5000;
+    else {
+     /* XXX: use timeout computed from timers */
+        int64_t add;
+        int64_t delta;
+        /* Advance virtual time to the next event.  */
+	delta = qemu_icount_delta();
+        if (delta > 0) {
+            /* If virtual time is ahead of real time then just
+               wait for IO.  */
+            timeout = (delta + 999999) / 1000000;
+        } else {
+            /* Wait for either IO to occur or the next
+               timer event.  */
+            add = qemu_next_icount_deadline();
+            /* We advance the timer before checking for IO.
+               Limit the amount we advance so that early IO
+               activity won't get the guest too far ahead.  */
+            if (add > 10000000)
+                add = 10000000;
+            delta += add;
+            qemu_icount += qemu_icount_round (add);
+            timeout = delta / 1000000;
+            if (timeout < 0)
+                timeout = 0;
+        }
+    }
+
+    return timeout;
+#else /* CONFIG_IOTHREAD */
+    return 1000;
+#endif
+}
+
diff --git a/qemu-0.15.x/qemu-timer.h b/qemu-0.15.x/qemu-timer.h
new file mode 100644
index 0000000..0a43469
--- /dev/null
+++ b/qemu-0.15.x/qemu-timer.h
@@ -0,0 +1,341 @@
+#ifndef QEMU_TIMER_H
+#define QEMU_TIMER_H
+
+#include "qemu-common.h"
+#include "notify.h"
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+/* timers */
+
+#define SCALE_MS 1000000
+#define SCALE_US 1000
+#define SCALE_NS 1
+
+typedef struct QEMUClock QEMUClock;
+typedef void QEMUTimerCB(void *opaque);
+
+/* The real time clock should be used only for stuff which does not
+   change the virtual machine state, as it is run even if the virtual
+   machine is stopped. The real time clock has a frequency of 1000
+   Hz. */
+extern QEMUClock *rt_clock;
+
+/* The virtual clock is only run during the emulation. It is stopped
+   when the virtual machine is stopped. Virtual timers use a high
+   precision clock, usually cpu cycles (use ticks_per_sec). */
+extern QEMUClock *vm_clock;
+
+/* The host clock should be use for device models that emulate accurate
+   real time sources. It will continue to run when the virtual machine
+   is suspended, and it will reflect system time changes the host may
+   undergo (e.g. due to NTP). The host clock has the same precision as
+   the virtual clock. */
+extern QEMUClock *host_clock;
+
+int64_t qemu_get_clock_ns(QEMUClock *clock);
+void qemu_clock_enable(QEMUClock *clock, int enabled);
+void qemu_clock_warp(QEMUClock *clock);
+
+void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier);
+void qemu_unregister_clock_reset_notifier(QEMUClock *clock,
+                                          Notifier *notifier);
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque);
+void qemu_free_timer(QEMUTimer *ts);
+void qemu_del_timer(QEMUTimer *ts);
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
+int qemu_timer_pending(QEMUTimer *ts);
+int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
+
+void qemu_run_all_timers(void);
+int qemu_alarm_pending(void);
+int64_t qemu_next_icount_deadline(void);
+void configure_alarms(char const *opt);
+void configure_icount(const char *option);
+int qemu_calculate_timeout(void);
+void init_clocks(void);
+int init_timer_alarm(void);
+void quit_timers(void);
+
+int64_t cpu_get_ticks(void);
+void cpu_enable_ticks(void);
+void cpu_disable_ticks(void);
+
+static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb,
+                                           void *opaque)
+{
+    return qemu_new_timer(clock, SCALE_NS, cb, opaque);
+}
+
+static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb,
+                                           void *opaque)
+{
+    return qemu_new_timer(clock, SCALE_MS, cb, opaque);
+}
+
+static inline int64_t qemu_get_clock_ms(QEMUClock *clock)
+{
+    return qemu_get_clock_ns(clock) / SCALE_MS;
+}
+
+static inline int64_t get_ticks_per_sec(void)
+{
+    return 1000000000LL;
+}
+
+/* real time host monotonic timer */
+static inline int64_t get_clock_realtime(void)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+}
+
+/* Warning: don't insert tracepoints into these functions, they are
+   also used by simpletrace backend and tracepoints would cause
+   an infinite recursion! */
+#ifdef _WIN32
+extern int64_t clock_freq;
+
+static inline int64_t get_clock(void)
+{
+    LARGE_INTEGER ti;
+    QueryPerformanceCounter(&ti);
+    return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq);
+}
+
+#else
+
+extern int use_rt_clock;
+
+static inline int64_t get_clock(void)
+{
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+    if (use_rt_clock) {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    } else
+#endif
+    {
+        /* XXX: using gettimeofday leads to problems if the date
+           changes, so it should be avoided. */
+        return get_clock_realtime();
+    }
+}
+#endif
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
+
+/* ptimer.c */
+typedef struct ptimer_state ptimer_state;
+typedef void (*ptimer_cb)(void *opaque);
+
+ptimer_state *ptimer_init(QEMUBH *bh);
+void ptimer_set_period(ptimer_state *s, int64_t period);
+void ptimer_set_freq(ptimer_state *s, uint32_t freq);
+void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
+uint64_t ptimer_get_count(ptimer_state *s);
+void ptimer_set_count(ptimer_state *s, uint64_t count);
+void ptimer_run(ptimer_state *s, int oneshot);
+void ptimer_stop(ptimer_state *s);
+
+/* icount */
+int64_t qemu_icount_round(int64_t count);
+extern int64_t qemu_icount;
+extern int use_icount;
+extern int icount_time_shift;
+extern int64_t qemu_icount_bias;
+int64_t cpu_get_icount(void);
+
+/*******************************************/
+/* host CPU ticks (if available) */
+
+#if defined(_ARCH_PPC)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t retval;
+#ifdef _ARCH_PPC64
+    /* This reads timebase in one 64bit go and includes Cell workaround from:
+       http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
+    */
+    __asm__ __volatile__ ("mftb    %0\n\t"
+                          "cmpwi   %0,0\n\t"
+                          "beq-    $-8"
+                          : "=r" (retval));
+#else
+    /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */
+    unsigned long junk;
+    __asm__ __volatile__ ("mfspr   %1,269\n\t"  /* mftbu */
+                          "mfspr   %L0,268\n\t" /* mftb */
+                          "mfspr   %0,269\n\t"  /* mftbu */
+                          "cmpw    %0,%1\n\t"
+                          "bne     $-16"
+                          : "=r" (retval), "=r" (junk));
+#endif
+    return retval;
+}
+
+#elif defined(__i386__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t val;
+    asm volatile ("rdtsc" : "=A" (val));
+    return val;
+}
+
+#elif defined(__x86_64__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    uint32_t low,high;
+    int64_t val;
+    asm volatile("rdtsc" : "=a" (low), "=d" (high));
+    val = high;
+    val <<= 32;
+    val |= low;
+    return val;
+}
+
+#elif defined(__hppa__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int val;
+    asm volatile ("mfctl %%cr16, %0" : "=r"(val));
+    return val;
+}
+
+#elif defined(__ia64)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t val;
+    asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
+    return val;
+}
+
+#elif defined(__s390__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t val;
+    asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
+    return val;
+}
+
+#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
+
+static inline int64_t cpu_get_real_ticks (void)
+{
+#if defined(_LP64)
+    uint64_t        rval;
+    asm volatile("rd %%tick,%0" : "=r"(rval));
+    return rval;
+#else
+    union {
+        uint64_t i64;
+        struct {
+            uint32_t high;
+            uint32_t low;
+        }       i32;
+    } rval;
+    asm volatile("rd %%tick,%1; srlx %1,32,%0"
+                 : "=r"(rval.i32.high), "=r"(rval.i32.low));
+    return rval.i64;
+#endif
+}
+
+#elif defined(__mips__) && \
+    ((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__))
+/*
+ * binutils wants to use rdhwr only on mips32r2
+ * but as linux kernel emulate it, it's fine
+ * to use it.
+ *
+ */
+#define MIPS_RDHWR(rd, value) {                         \
+        __asm__ __volatile__ (".set   push\n\t"         \
+                              ".set mips32r2\n\t"       \
+                              "rdhwr  %0, "rd"\n\t"     \
+                              ".set   pop"              \
+                              : "=r" (value));          \
+    }
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    /* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */
+    uint32_t count;
+    static uint32_t cyc_per_count = 0;
+
+    if (!cyc_per_count) {
+        MIPS_RDHWR("$3", cyc_per_count);
+    }
+
+    MIPS_RDHWR("$2", count);
+    return (int64_t)(count * cyc_per_count);
+}
+
+#elif defined(__alpha__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    uint64_t cc;
+    uint32_t cur, ofs;
+
+    asm volatile("rpcc %0" : "=r"(cc));
+    cur = cc;
+    ofs = cc >> 32;
+    return cur - ofs;
+}
+
+#else
+/* The host CPU doesn't have an easily accessible cycle counter.
+   Just return a monotonically increasing value.  This will be
+   totally wrong, but hopefully better than nothing.  */
+static inline int64_t cpu_get_real_ticks (void)
+{
+    static int64_t ticks = 0;
+    return ticks++;
+}
+#endif
+
+#ifdef NEED_CPU_H
+/* Deterministic execution requires that IO only be performed on the last
+   instruction of a TB so that interrupts take effect immediately.  */
+static inline int can_do_io(CPUState *env)
+{
+    if (!use_icount)
+        return 1;
+
+    /* If not executing code then assume we are ok.  */
+    if (!env->current_tb)
+        return 1;
+
+    return env->can_do_io != 0;
+}
+#endif
+
+#ifdef CONFIG_PROFILER
+static inline int64_t profile_getclock(void)
+{
+    return cpu_get_real_ticks();
+}
+
+extern int64_t qemu_time, qemu_time_start;
+extern int64_t tlb_flush_time;
+extern int64_t dev_time;
+#endif
+
+#endif
diff --git a/qemu-0.15.x/qemu-tool.c b/qemu-0.15.x/qemu-tool.c
new file mode 100644
index 0000000..41e5c41
--- /dev/null
+++ b/qemu-0.15.x/qemu-tool.c
@@ -0,0 +1,98 @@
+/*
+ * Compatibility for qemu-img/qemu-nbd
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "monitor.h"
+#include "qemu-timer.h"
+#include "qemu-log.h"
+
+#include <sys/time.h>
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+FILE *logfile;
+
+struct QEMUBH
+{
+    QEMUBHFunc *cb;
+    void *opaque;
+};
+
+void qemu_service_io(void)
+{
+}
+
+Monitor *cur_mon;
+
+int monitor_cur_is_qmp(void)
+{
+    return 0;
+}
+
+void monitor_set_error(Monitor *mon, QError *qerror)
+{
+}
+
+void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
+{
+}
+
+void monitor_printf(Monitor *mon, const char *fmt, ...)
+{
+}
+
+void monitor_print_filename(Monitor *mon, const char *filename)
+{
+}
+
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+}
+
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    return 0;
+}
+
+void qemu_notify_event(void)
+{
+}
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
+                          QEMUTimerCB *cb, void *opaque)
+{
+    return qemu_malloc(1);
+}
+
+void qemu_free_timer(QEMUTimer *ts)
+{
+    qemu_free(ts);
+}
+
+void qemu_del_timer(QEMUTimer *ts)
+{
+}
+
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+{
+}
+
+int64_t qemu_get_clock_ns(QEMUClock *clock)
+{
+    return 0;
+}
diff --git a/qemu-0.15.x/qemu-x509.h b/qemu-0.15.x/qemu-x509.h
new file mode 100644
index 0000000..095aec1
--- /dev/null
+++ b/qemu-0.15.x/qemu-x509.h
@@ -0,0 +1,9 @@
+#ifndef QEMU_X509_H
+#define QEMU_X509_H
+
+#define X509_CA_CERT_FILE "ca-cert.pem"
+#define X509_CA_CRL_FILE "ca-crl.pem"
+#define X509_SERVER_KEY_FILE "server-key.pem"
+#define X509_SERVER_CERT_FILE "server-cert.pem"
+
+#endif /* QEMU_X509_H */
diff --git a/qemu-0.15.x/qemu.sasl b/qemu-0.15.x/qemu.sasl
new file mode 100644
index 0000000..cf19cf8
--- /dev/null
+++ b/qemu-0.15.x/qemu.sasl
@@ -0,0 +1,34 @@
+# If you want to use the non-TLS socket, then you *must* include
+# the GSSAPI or DIGEST-MD5 mechanisms, because they are the only
+# ones that can offer session encryption as well as authentication.
+#
+# If you're only using TLS, then you can turn on any mechanisms
+# you like for authentication, because TLS provides the encryption
+#
+# Default to a simple username+password mechanism
+# NB digest-md5 is no longer considered secure by current standards
+mech_list: digest-md5
+
+# Before you can use GSSAPI, you need a service principle on the
+# KDC server for libvirt, and that to be exported to the keytab
+# file listed below
+#mech_list: gssapi
+#
+# You can also list many mechanisms at once, then the user can choose
+# by adding  '?auth=sasl.gssapi' to their libvirt URI, eg
+#   qemu+tcp://hostname/system?auth=sasl.gssapi
+#mech_list: digest-md5 gssapi
+
+# Some older builds of MIT kerberos on Linux ignore this option &
+# instead need KRB5_KTNAME env var.
+# For modern Linux, and other OS, this should be sufficient
+keytab: /etc/qemu/krb5.tab
+
+# If using digest-md5 for username/passwds, then this is the file
+# containing the passwds. Use 'saslpasswd2 -a qemu [username]'
+# to add entries, and 'sasldblistusers2 -a qemu' to browse it
+sasldb_path: /etc/qemu/passwd.db
+
+
+auxprop_plugin: sasldb
+
diff --git a/qemu-0.15.x/qemu_socket.h b/qemu-0.15.x/qemu_socket.h
new file mode 100644
index 0000000..180e4db
--- /dev/null
+++ b/qemu-0.15.x/qemu_socket.h
@@ -0,0 +1,59 @@
+/* headers to use the BSD sockets */
+#ifndef QEMU_SOCKET_H
+#define QEMU_SOCKET_H
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#define socket_error() WSAGetLastError()
+#undef EINTR
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINTR       WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+
+int inet_aton(const char *cp, struct in_addr *ia);
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#define socket_error() errno
+#define closesocket(s) close(s)
+
+#endif /* !_WIN32 */
+
+#include "qemu-option.h"
+
+/* misc helpers */
+int qemu_socket(int domain, int type, int protocol);
+int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+void socket_set_nonblock(int fd);
+int send_all(int fd, const void *buf, int len1);
+
+/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
+int inet_listen_opts(QemuOpts *opts, int port_offset);
+int inet_listen(const char *str, char *ostr, int olen,
+                int socktype, int port_offset);
+int inet_connect_opts(QemuOpts *opts);
+int inet_connect(const char *str, int socktype);
+int inet_dgram_opts(QemuOpts *opts);
+const char *inet_strfamily(int family);
+
+int unix_listen_opts(QemuOpts *opts);
+int unix_listen(const char *path, char *ostr, int olen);
+int unix_connect_opts(QemuOpts *opts);
+int unix_connect(const char *path);
+
+/* Old, ipv4 only bits.  Don't use for new code. */
+int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int socket_init(void);
+
+#endif /* QEMU_SOCKET_H */
diff --git a/qemu-0.15.x/qerror.c b/qemu-0.15.x/qerror.c
new file mode 100644
index 0000000..69c1bc9
--- /dev/null
+++ b/qemu-0.15.x/qerror.c
@@ -0,0 +1,505 @@
+/*
+ * QError Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "monitor.h"
+#include "qjson.h"
+#include "qerror.h"
+#include "qemu-common.h"
+
+static void qerror_destroy_obj(QObject *obj);
+
+static const QType qerror_type = {
+    .code = QTYPE_QERROR,
+    .destroy = qerror_destroy_obj,
+};
+
+/**
+ * The 'desc' parameter is a printf-like string, the format of the format
+ * string is:
+ *
+ * %(KEY)
+ *
+ * Where KEY is a QDict key, which has to be passed to qerror_from_info().
+ *
+ * Example:
+ *
+ * "foo error on device: %(device) slot: %(slot_nr)"
+ *
+ * A single percent sign can be printed if followed by a second one,
+ * for example:
+ *
+ * "running out of foo: %(foo)%%"
+ *
+ * Please keep the entries in alphabetical order.
+ * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
+ * to check.
+ */
+static const QErrorStringTable qerror_table[] = {
+    {
+        .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
+        .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
+    },
+    {
+        .error_fmt = QERR_BUS_NOT_FOUND,
+        .desc      = "Bus '%(bus)' not found",
+    },
+    {
+        .error_fmt = QERR_BUS_NO_HOTPLUG,
+        .desc      = "Bus '%(bus)' does not support hotplugging",
+    },
+    {
+        .error_fmt = QERR_COMMAND_NOT_FOUND,
+        .desc      = "The command %(name) has not been found",
+    },
+    {
+        .error_fmt = QERR_DEVICE_ENCRYPTED,
+        .desc      = "Device '%(device)' is encrypted",
+    },
+    {
+        .error_fmt = QERR_DEVICE_INIT_FAILED,
+        .desc      = "Device '%(device)' could not be initialized",
+    },
+    {
+        .error_fmt = QERR_DEVICE_IN_USE,
+        .desc      = "Device '%(device)' is in use",
+    },
+    {
+        .error_fmt = QERR_DEVICE_LOCKED,
+        .desc      = "Device '%(device)' is locked",
+    },
+    {
+        .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
+        .desc      = "Device '%(device)' has multiple child busses",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NOT_ACTIVE,
+        .desc      = "Device '%(device)' has not been activated",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NOT_ENCRYPTED,
+        .desc      = "Device '%(device)' is not encrypted",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NOT_FOUND,
+        .desc      = "Device '%(device)' not found",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
+        .desc      = "Device '%(device)' is not removable",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NO_BUS,
+        .desc      = "Device '%(device)' has no child bus",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NO_HOTPLUG,
+        .desc      = "Device '%(device)' does not support hotplugging",
+    },
+    {
+        .error_fmt = QERR_DUPLICATE_ID,
+        .desc      = "Duplicate ID '%(id)' for %(object)",
+    },
+    {
+        .error_fmt = QERR_FD_NOT_FOUND,
+        .desc      = "File descriptor named '%(name)' not found",
+    },
+    {
+        .error_fmt = QERR_FD_NOT_SUPPLIED,
+        .desc      = "No file descriptor supplied via SCM_RIGHTS",
+    },
+    {
+        .error_fmt = QERR_INVALID_BLOCK_FORMAT,
+        .desc      = "Invalid block format '%(name)'",
+    },
+    {
+        .error_fmt = QERR_INVALID_PARAMETER,
+        .desc      = "Invalid parameter '%(name)'",
+    },
+    {
+        .error_fmt = QERR_INVALID_PARAMETER_TYPE,
+        .desc      = "Invalid parameter type, expected: %(expected)",
+    },
+    {
+        .error_fmt = QERR_INVALID_PARAMETER_VALUE,
+        .desc      = "Parameter '%(name)' expects %(expected)",
+    },
+    {
+        .error_fmt = QERR_INVALID_PASSWORD,
+        .desc      = "Password incorrect",
+    },
+    {
+        .error_fmt = QERR_JSON_PARSING,
+        .desc      = "Invalid JSON syntax",
+    },
+    {
+        .error_fmt = QERR_JSON_PARSE_ERROR,
+        .desc      = "JSON parse error, %(message)",
+
+    },
+    {
+        .error_fmt = QERR_KVM_MISSING_CAP,
+        .desc      = "Using KVM without %(capability), %(feature) unavailable",
+    },
+    {
+        .error_fmt = QERR_MIGRATION_EXPECTED,
+        .desc      = "An incoming migration is expected before this command can be executed",
+    },
+    {
+        .error_fmt = QERR_MISSING_PARAMETER,
+        .desc      = "Parameter '%(name)' is missing",
+    },
+    {
+        .error_fmt = QERR_NO_BUS_FOR_DEVICE,
+        .desc      = "No '%(bus)' bus found for device '%(device)'",
+    },
+    {
+        .error_fmt = QERR_OPEN_FILE_FAILED,
+        .desc      = "Could not open '%(filename)'",
+    },
+    {
+        .error_fmt = QERR_PROPERTY_NOT_FOUND,
+        .desc      = "Property '%(device).%(property)' not found",
+    },
+    {
+        .error_fmt = QERR_PROPERTY_VALUE_BAD,
+        .desc      = "Property '%(device).%(property)' doesn't take value '%(value)'",
+    },
+    {
+        .error_fmt = QERR_PROPERTY_VALUE_IN_USE,
+        .desc      = "Property '%(device).%(property)' can't take value '%(value)', it's in use",
+    },
+    {
+        .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND,
+        .desc      = "Property '%(device).%(property)' can't find value '%(value)'",
+    },
+    {
+        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
+        .desc      = "Expected '%(expected)' in QMP input",
+    },
+    {
+        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+        .desc      = "QMP input object member '%(member)' expects '%(expected)'",
+    },
+    {
+        .error_fmt = QERR_QMP_EXTRA_MEMBER,
+        .desc      = "QMP input object member '%(member)' is unexpected",
+    },
+    {
+        .error_fmt = QERR_SET_PASSWD_FAILED,
+        .desc      = "Could not set password",
+    },
+    {
+        .error_fmt = QERR_ADD_CLIENT_FAILED,
+        .desc      = "Could not add client",
+    },
+    {
+        .error_fmt = QERR_TOO_MANY_FILES,
+        .desc      = "Too many open files",
+    },
+    {
+        .error_fmt = QERR_UNDEFINED_ERROR,
+        .desc      = "An undefined error has ocurred",
+    },
+    {
+        .error_fmt = QERR_UNSUPPORTED,
+        .desc      = "this feature or command is not currently supported",
+    },
+    {
+        .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+        .desc      = "'%(device)' uses a %(format) feature which is not "
+                     "supported by this qemu version: %(feature)",
+    },
+    {
+        .error_fmt = QERR_VNC_SERVER_FAILED,
+        .desc      = "Could not start VNC server on %(target)",
+    },
+    {
+        .error_fmt = QERR_QGA_LOGGING_FAILED,
+        .desc      = "Guest agent failed to log non-optional log statement",
+    },
+    {
+        .error_fmt = QERR_QGA_COMMAND_FAILED,
+        .desc      = "Guest agent command failed, error was '%(message)'",
+    },
+    {}
+};
+
+/**
+ * qerror_new(): Create a new QError
+ *
+ * Return strong reference.
+ */
+QError *qerror_new(void)
+{
+    QError *qerr;
+
+    qerr = qemu_mallocz(sizeof(*qerr));
+    QOBJECT_INIT(qerr, &qerror_type);
+
+    return qerr;
+}
+
+static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
+                                            const char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
+    fprintf(stderr, "qerror: -> ");
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
+    abort();
+}
+
+static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
+                                               const char *fmt, va_list *va)
+{
+    QObject *obj;
+
+    obj = qobject_from_jsonv(fmt, va);
+    if (!obj) {
+        qerror_abort(qerr, "invalid format '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QDICT) {
+        qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
+    }
+
+    qerr->error = qobject_to_qdict(obj);
+
+    obj = qdict_get(qerr->error, "class");
+    if (!obj) {
+        qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QSTRING) {
+        qerror_abort(qerr, "'class' key value should be a QString");
+    }
+    
+    obj = qdict_get(qerr->error, "data");
+    if (!obj) {
+        qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QDICT) {
+        qerror_abort(qerr, "'data' key value should be a QDICT");
+    }
+}
+
+static void qerror_set_desc(QError *qerr, const char *fmt)
+{
+    int i;
+
+    // FIXME: inefficient loop
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+            qerr->entry = &qerror_table[i];
+            return;
+        }
+    }
+
+    qerror_abort(qerr, "error format '%s' not found", fmt);
+}
+
+/**
+ * qerror_from_info(): Create a new QError from error information
+ *
+ * The information consists of:
+ *
+ * - file   the file name of where the error occurred
+ * - linenr the line number of where the error occurred
+ * - func   the function name of where the error occurred
+ * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
+ *          'data'
+ * - va     va_list of all arguments specified by fmt
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_info(const char *file, int linenr, const char *func,
+                         const char *fmt, va_list *va)
+{
+    QError *qerr;
+
+    qerr = qerror_new();
+    loc_save(&qerr->loc);
+    qerr->linenr = linenr;
+    qerr->file = file;
+    qerr->func = func;
+
+    if (!fmt) {
+        qerror_abort(qerr, "QDict not specified");
+    }
+
+    qerror_set_data(qerr, fmt, va);
+    qerror_set_desc(qerr, fmt);
+
+    return qerr;
+}
+
+static void parse_error(const QErrorStringTable *entry, int c)
+{
+    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
+    abort();
+}
+
+static const char *append_field(QDict *error, QString *outstr,
+                                const QErrorStringTable *entry,
+                                const char *start)
+{
+    QObject *obj;
+    QDict *qdict;
+    QString *key_qs;
+    const char *end, *key;
+
+    if (*start != '%')
+        parse_error(entry, '%');
+    start++;
+    if (*start != '(')
+        parse_error(entry, '(');
+    start++;
+
+    end = strchr(start, ')');
+    if (!end)
+        parse_error(entry, ')');
+
+    key_qs = qstring_from_substr(start, 0, end - start - 1);
+    key = qstring_get_str(key_qs);
+
+    qdict = qobject_to_qdict(qdict_get(error, "data"));
+    obj = qdict_get(qdict, key);
+    if (!obj) {
+        abort();
+    }
+
+    switch (qobject_type(obj)) {
+        case QTYPE_QSTRING:
+            qstring_append(outstr, qdict_get_str(qdict, key));
+            break;
+        case QTYPE_QINT:
+            qstring_append_int(outstr, qdict_get_int(qdict, key));
+            break;
+        default:
+            abort();
+    }
+
+    QDECREF(key_qs);
+    return ++end;
+}
+
+static QString *qerror_format_desc(QDict *error,
+                                   const QErrorStringTable *entry)
+{
+    QString *qstring;
+    const char *p;
+
+    assert(entry != NULL);
+
+    qstring = qstring_new();
+
+    for (p = entry->desc; *p != '\0';) {
+        if (*p != '%') {
+            qstring_append_chr(qstring, *p++);
+        } else if (*(p + 1) == '%') {
+            qstring_append_chr(qstring, '%');
+            p += 2;
+        } else {
+            p = append_field(error, qstring, entry, p);
+        }
+    }
+
+    return qstring;
+}
+
+QString *qerror_format(const char *fmt, QDict *error)
+{
+    const QErrorStringTable *entry = NULL;
+    int i;
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+            entry = &qerror_table[i];
+            break;
+        }
+    }
+
+    return qerror_format_desc(error, entry);
+}
+
+/**
+ * qerror_human(): Format QError data into human-readable string.
+ */
+QString *qerror_human(const QError *qerror)
+{
+    return qerror_format_desc(qerror->error, qerror->entry);
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function will print the member 'desc' of the specified QError object,
+ * it uses error_report() for this, so that the output is routed to the right
+ * place (ie. stderr or Monitor's device).
+ */
+void qerror_print(QError *qerror)
+{
+    QString *qstring = qerror_human(qerror);
+    loc_push_restore(&qerror->loc);
+    error_report("%s", qstring_get_str(qstring));
+    loc_pop(&qerror->loc);
+    QDECREF(qstring);
+}
+
+void qerror_report_internal(const char *file, int linenr, const char *func,
+                            const char *fmt, ...)
+{
+    va_list va;
+    QError *qerror;
+
+    va_start(va, fmt);
+    qerror = qerror_from_info(file, linenr, func, fmt, &va);
+    va_end(va);
+
+    if (monitor_cur_is_qmp()) {
+        monitor_set_error(cur_mon, qerror);
+    } else {
+        qerror_print(qerror);
+        QDECREF(qerror);
+    }
+}
+
+/**
+ * qobject_to_qerror(): Convert a QObject into a QError
+ */
+QError *qobject_to_qerror(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QERROR) {
+        return NULL;
+    }
+
+    return container_of(obj, QError, base);
+}
+
+/**
+ * qerror_destroy_obj(): Free all memory allocated by a QError
+ */
+static void qerror_destroy_obj(QObject *obj)
+{
+    QError *qerr;
+
+    assert(obj != NULL);
+    qerr = qobject_to_qerror(obj);
+
+    QDECREF(qerr->error);
+    qemu_free(qerr);
+}
diff --git a/qemu-0.15.x/qerror.h b/qemu-0.15.x/qerror.h
new file mode 100644
index 0000000..8058456
--- /dev/null
+++ b/qemu-0.15.x/qerror.h
@@ -0,0 +1,196 @@
+/*
+ * QError Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QERROR_H
+#define QERROR_H
+
+#include "qdict.h"
+#include "qstring.h"
+#include "qemu-error.h"
+#include <stdarg.h>
+
+typedef struct QErrorStringTable {
+    const char *desc;
+    const char *error_fmt;
+} QErrorStringTable;
+
+typedef struct QError {
+    QObject_HEAD;
+    QDict *error;
+    Location loc;
+    int linenr;
+    const char *file;
+    const char *func;
+    const QErrorStringTable *entry;
+} QError;
+
+QError *qerror_new(void);
+QError *qerror_from_info(const char *file, int linenr, const char *func,
+                         const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0);
+QString *qerror_human(const QError *qerror);
+void qerror_print(QError *qerror);
+void qerror_report_internal(const char *file, int linenr, const char *func,
+                            const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+QString *qerror_format(const char *fmt, QDict *error);
+#define qerror_report(fmt, ...) \
+    qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
+QError *qobject_to_qerror(const QObject *obj);
+
+/*
+ * QError class list
+ * Please keep the definitions in alphabetical order.
+ * Use "grep '^#define QERR_' qerror.h | sort -c" to check.
+ */
+#define QERR_BAD_BUS_FOR_DEVICE \
+    "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+
+#define QERR_BUS_NOT_FOUND \
+    "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+
+#define QERR_BUS_NO_HOTPLUG \
+    "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+
+#define QERR_COMMAND_NOT_FOUND \
+    "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
+#define QERR_DEVICE_ENCRYPTED \
+    "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_INIT_FAILED \
+    "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_IN_USE \
+    "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_LOCKED \
+    "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_MULTIPLE_BUSSES \
+    "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NOT_ACTIVE \
+    "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NOT_ENCRYPTED \
+    "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NOT_FOUND \
+    "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NOT_REMOVABLE \
+    "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NO_BUS \
+    "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NO_HOTPLUG \
+    "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+
+#define QERR_DUPLICATE_ID \
+    "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+
+#define QERR_FD_NOT_FOUND \
+    "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+
+#define QERR_FD_NOT_SUPPLIED \
+    "{ 'class': 'FdNotSupplied', 'data': {} }"
+
+#define QERR_INVALID_BLOCK_FORMAT \
+    "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+
+#define QERR_INVALID_PARAMETER \
+    "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+
+#define QERR_INVALID_PARAMETER_TYPE \
+    "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+
+#define QERR_INVALID_PARAMETER_VALUE \
+    "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+
+#define QERR_INVALID_PASSWORD \
+    "{ 'class': 'InvalidPassword', 'data': {} }"
+
+#define QERR_JSON_PARSING \
+    "{ 'class': 'JSONParsing', 'data': {} }"
+
+#define QERR_JSON_PARSE_ERROR \
+    "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+
+#define QERR_BUFFER_OVERRUN \
+    "{ 'class': 'BufferOverrun', 'data': {} }"
+
+#define QERR_KVM_MISSING_CAP \
+    "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+
+#define QERR_MIGRATION_EXPECTED \
+    "{ 'class': 'MigrationExpected', 'data': {} }"
+
+#define QERR_MISSING_PARAMETER \
+    "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+
+#define QERR_NO_BUS_FOR_DEVICE \
+    "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+
+#define QERR_OPEN_FILE_FAILED \
+    "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+
+#define QERR_PROPERTY_NOT_FOUND \
+    "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+
+#define QERR_PROPERTY_VALUE_BAD \
+    "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+
+#define QERR_PROPERTY_VALUE_IN_USE \
+    "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+
+#define QERR_PROPERTY_VALUE_NOT_FOUND \
+    "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+
+#define QERR_QMP_BAD_INPUT_OBJECT \
+    "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+
+#define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
+    "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+
+#define QERR_QMP_EXTRA_MEMBER \
+    "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+
+#define QERR_SET_PASSWD_FAILED \
+    "{ 'class': 'SetPasswdFailed', 'data': {} }"
+
+#define QERR_ADD_CLIENT_FAILED \
+    "{ 'class': 'AddClientFailed', 'data': {} }"
+
+#define QERR_TOO_MANY_FILES \
+    "{ 'class': 'TooManyFiles', 'data': {} }"
+
+#define QERR_UNDEFINED_ERROR \
+    "{ 'class': 'UndefinedError', 'data': {} }"
+
+#define QERR_UNSUPPORTED \
+    "{ 'class': 'Unsupported', 'data': {} }"
+
+#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
+    "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+
+#define QERR_VNC_SERVER_FAILED \
+    "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
+
+#define QERR_FEATURE_DISABLED \
+    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
+#define QERR_QGA_LOGGING_FAILED \
+    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+
+#define QERR_QGA_COMMAND_FAILED \
+    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+
+#endif /* QERROR_H */
diff --git a/qemu-0.15.x/qfloat.c b/qemu-0.15.x/qfloat.c
new file mode 100644
index 0000000..f8c8a2e
--- /dev/null
+++ b/qemu-0.15.x/qfloat.c
@@ -0,0 +1,68 @@
+/*
+ * QFloat Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qfloat.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static void qfloat_destroy_obj(QObject *obj);
+
+static const QType qfloat_type = {
+    .code = QTYPE_QFLOAT,
+    .destroy = qfloat_destroy_obj,
+};
+
+/**
+ * qfloat_from_int(): Create a new QFloat from a float
+ *
+ * Return strong reference.
+ */
+QFloat *qfloat_from_double(double value)
+{
+    QFloat *qf;
+
+    qf = qemu_malloc(sizeof(*qf));
+    qf->value = value;
+    QOBJECT_INIT(qf, &qfloat_type);
+
+    return qf;
+}
+
+/**
+ * qfloat_get_double(): Get the stored float
+ */
+double qfloat_get_double(const QFloat *qf)
+{
+    return qf->value;
+}
+
+/**
+ * qobject_to_qfloat(): Convert a QObject into a QFloat
+ */
+QFloat *qobject_to_qfloat(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QFLOAT)
+        return NULL;
+
+    return container_of(obj, QFloat, base);
+}
+
+/**
+ * qfloat_destroy_obj(): Free all memory allocated by a
+ * QFloat object
+ */
+static void qfloat_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    qemu_free(qobject_to_qfloat(obj));
+}
diff --git a/qemu-0.15.x/qfloat.h b/qemu-0.15.x/qfloat.h
new file mode 100644
index 0000000..9d67876
--- /dev/null
+++ b/qemu-0.15.x/qfloat.h
@@ -0,0 +1,29 @@
+/*
+ * QFloat Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QFLOAT_H
+#define QFLOAT_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QFloat {
+    QObject_HEAD;
+    double value;
+} QFloat;
+
+QFloat *qfloat_from_double(double value);
+double qfloat_get_double(const QFloat *qi);
+QFloat *qobject_to_qfloat(const QObject *obj);
+
+#endif /* QFLOAT_H */
diff --git a/qemu-0.15.x/qga/guest-agent-command-state.c b/qemu-0.15.x/qga/guest-agent-command-state.c
new file mode 100644
index 0000000..bc6e0bd
--- /dev/null
+++ b/qemu-0.15.x/qga/guest-agent-command-state.c
@@ -0,0 +1,73 @@
+/*
+ * QEMU Guest Agent command state interfaces
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth      <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <glib.h>
+#include "qga/guest-agent-core.h"
+
+struct GACommandState {
+    GSList *groups;
+};
+
+typedef struct GACommandGroup {
+    void (*init)(void);
+    void (*cleanup)(void);
+} GACommandGroup;
+
+/* handle init/cleanup for stateful guest commands */
+
+void ga_command_state_add(GACommandState *cs,
+                          void (*init)(void),
+                          void (*cleanup)(void))
+{
+    GACommandGroup *cg = qemu_mallocz(sizeof(GACommandGroup));
+    cg->init = init;
+    cg->cleanup = cleanup;
+    cs->groups = g_slist_append(cs->groups, cg);
+}
+
+static void ga_command_group_init(gpointer opaque, gpointer unused)
+{
+    GACommandGroup *cg = opaque;
+
+    g_assert(cg);
+    if (cg->init) {
+        cg->init();
+    }
+}
+
+void ga_command_state_init_all(GACommandState *cs)
+{
+    g_assert(cs);
+    g_slist_foreach(cs->groups, ga_command_group_init, NULL);
+}
+
+static void ga_command_group_cleanup(gpointer opaque, gpointer unused)
+{
+    GACommandGroup *cg = opaque;
+
+    g_assert(cg);
+    if (cg->cleanup) {
+        cg->cleanup();
+    }
+}
+
+void ga_command_state_cleanup_all(GACommandState *cs)
+{
+    g_assert(cs);
+    g_slist_foreach(cs->groups, ga_command_group_cleanup, NULL);
+}
+
+GACommandState *ga_command_state_new(void)
+{
+    GACommandState *cs = qemu_mallocz(sizeof(GACommandState));
+    cs->groups = NULL;
+    return cs;
+}
diff --git a/qemu-0.15.x/qga/guest-agent-commands.c b/qemu-0.15.x/qga/guest-agent-commands.c
new file mode 100644
index 0000000..30c4068
--- /dev/null
+++ b/qemu-0.15.x/qga/guest-agent-commands.c
@@ -0,0 +1,561 @@
+/*
+ * QEMU Guest Agent commands
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth      <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#if defined(__linux__)
+#include <mntent.h>
+#include <linux/fs.h>
+
+#if defined(__linux__) && defined(FIFREEZE)
+#define CONFIG_FSFREEZE
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "qga/guest-agent-core.h"
+#include "qga-qmp-commands.h"
+#include "qerror.h"
+#include "qemu-queue.h"
+
+static GAState *ga_state;
+
+/* Note: in some situations, like with the fsfreeze, logging may be
+ * temporarilly disabled. if it is necessary that a command be able
+ * to log for accounting purposes, check ga_logging_enabled() beforehand,
+ * and use the QERR_QGA_LOGGING_DISABLED to generate an error
+ */
+static void slog(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    g_logv("syslog", G_LOG_LEVEL_INFO, fmt, ap);
+    va_end(ap);
+}
+
+int64_t qmp_guest_sync(int64_t id, Error **errp)
+{
+    return id;
+}
+
+void qmp_guest_ping(Error **err)
+{
+    slog("guest-ping called");
+}
+
+struct GuestAgentInfo *qmp_guest_info(Error **err)
+{
+    GuestAgentInfo *info = qemu_mallocz(sizeof(GuestAgentInfo));
+
+    info->version = g_strdup(QGA_VERSION);
+
+    return info;
+}
+
+void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
+{
+    int ret;
+    const char *shutdown_flag;
+
+    slog("guest-shutdown called, mode: %s", mode);
+    if (!has_mode || strcmp(mode, "powerdown") == 0) {
+        shutdown_flag = "-P";
+    } else if (strcmp(mode, "halt") == 0) {
+        shutdown_flag = "-H";
+    } else if (strcmp(mode, "reboot") == 0) {
+        shutdown_flag = "-r";
+    } else {
+        error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
+                  "halt|powerdown|reboot");
+        return;
+    }
+
+    ret = fork();
+    if (ret == 0) {
+        /* child, start the shutdown */
+        setsid();
+        fclose(stdin);
+        fclose(stdout);
+        fclose(stderr);
+
+        ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
+                    "hypervisor initiated shutdown", (char*)NULL);
+        if (ret) {
+            slog("guest-shutdown failed: %s", strerror(errno));
+        }
+        exit(!!ret);
+    } else if (ret < 0) {
+        error_set(err, QERR_UNDEFINED_ERROR);
+    }
+}
+
+typedef struct GuestFileHandle {
+    uint64_t id;
+    FILE *fh;
+    QTAILQ_ENTRY(GuestFileHandle) next;
+} GuestFileHandle;
+
+static struct {
+    QTAILQ_HEAD(, GuestFileHandle) filehandles;
+} guest_file_state;
+
+static void guest_file_handle_add(FILE *fh)
+{
+    GuestFileHandle *gfh;
+
+    gfh = qemu_mallocz(sizeof(GuestFileHandle));
+    gfh->id = fileno(fh);
+    gfh->fh = fh;
+    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
+}
+
+static GuestFileHandle *guest_file_handle_find(int64_t id)
+{
+    GuestFileHandle *gfh;
+
+    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
+    {
+        if (gfh->id == id) {
+            return gfh;
+        }
+    }
+
+    return NULL;
+}
+
+int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
+{
+    FILE *fh;
+    int fd;
+    int64_t ret = -1;
+
+    if (!has_mode) {
+        mode = "r";
+    }
+    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
+    fh = fopen(path, mode);
+    if (!fh) {
+        error_set(err, QERR_OPEN_FILE_FAILED, path);
+        return -1;
+    }
+
+    /* set fd non-blocking to avoid common use cases (like reading from a
+     * named pipe) from hanging the agent
+     */
+    fd = fileno(fh);
+    ret = fcntl(fd, F_GETFL);
+    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
+        fclose(fh);
+        return -1;
+    }
+
+    guest_file_handle_add(fh);
+    slog("guest-file-open, handle: %d", fd);
+    return fd;
+}
+
+void qmp_guest_file_close(int64_t handle, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    int ret;
+
+    slog("guest-file-close called, handle: %ld", handle);
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return;
+    }
+
+    ret = fclose(gfh->fh);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
+        return;
+    }
+
+    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
+    qemu_free(gfh);
+}
+
+struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
+                                          int64_t count, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    GuestFileRead *read_data = NULL;
+    guchar *buf;
+    FILE *fh;
+    size_t read_count;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    if (!has_count) {
+        count = QGA_READ_COUNT_DEFAULT;
+    } else if (count < 0) {
+        error_set(err, QERR_INVALID_PARAMETER, "count");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    buf = qemu_mallocz(count+1);
+    read_count = fread(buf, 1, count, fh);
+    if (ferror(fh)) {
+        slog("guest-file-read failed, handle: %ld", handle);
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
+    } else {
+        buf[read_count] = 0;
+        read_data = qemu_mallocz(sizeof(GuestFileRead));
+        read_data->count = read_count;
+        read_data->eof = feof(fh);
+        if (read_count) {
+            read_data->buf_b64 = g_base64_encode(buf, read_count);
+        }
+    }
+    qemu_free(buf);
+    clearerr(fh);
+
+    return read_data;
+}
+
+GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
+                                     bool has_count, int64_t count, Error **err)
+{
+    GuestFileWrite *write_data = NULL;
+    guchar *buf;
+    gsize buf_len;
+    int write_count;
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    FILE *fh;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    buf = g_base64_decode(buf_b64, &buf_len);
+
+    if (!has_count) {
+        count = buf_len;
+    } else if (count < 0 || count > buf_len) {
+        qemu_free(buf);
+        error_set(err, QERR_INVALID_PARAMETER, "count");
+        return NULL;
+    }
+
+    write_count = fwrite(buf, 1, count, fh);
+    if (ferror(fh)) {
+        slog("guest-file-write failed, handle: %ld", handle);
+        error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
+    } else {
+        write_data = qemu_mallocz(sizeof(GuestFileWrite));
+        write_data->count = write_count;
+        write_data->eof = feof(fh);
+    }
+    qemu_free(buf);
+    clearerr(fh);
+
+    return write_data;
+}
+
+struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
+                                          int64_t whence, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    GuestFileSeek *seek_data = NULL;
+    FILE *fh;
+    int ret;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return NULL;
+    }
+
+    fh = gfh->fh;
+    ret = fseek(fh, offset, whence);
+    if (ret == -1) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
+    } else {
+        seek_data = qemu_mallocz(sizeof(GuestFileRead));
+        seek_data->position = ftell(fh);
+        seek_data->eof = feof(fh);
+    }
+    clearerr(fh);
+
+    return seek_data;
+}
+
+void qmp_guest_file_flush(int64_t handle, Error **err)
+{
+    GuestFileHandle *gfh = guest_file_handle_find(handle);
+    FILE *fh;
+    int ret;
+
+    if (!gfh) {
+        error_set(err, QERR_FD_NOT_FOUND, "handle");
+        return;
+    }
+
+    fh = gfh->fh;
+    ret = fflush(fh);
+    if (ret == EOF) {
+        error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
+    }
+}
+
+static void guest_file_init(void)
+{
+    QTAILQ_INIT(&guest_file_state.filehandles);
+}
+
+#if defined(CONFIG_FSFREEZE)
+static void disable_logging(void)
+{
+    ga_disable_logging(ga_state);
+}
+
+static void enable_logging(void)
+{
+    ga_enable_logging(ga_state);
+}
+
+typedef struct GuestFsfreezeMount {
+    char *dirname;
+    char *devtype;
+    QTAILQ_ENTRY(GuestFsfreezeMount) next;
+} GuestFsfreezeMount;
+
+struct {
+    GuestFsfreezeStatus status;
+    QTAILQ_HEAD(, GuestFsfreezeMount) mount_list;
+} guest_fsfreeze_state;
+
+/*
+ * Walk the mount table and build a list of local file systems
+ */
+static int guest_fsfreeze_build_mount_list(void)
+{
+    struct mntent *ment;
+    GuestFsfreezeMount *mount, *temp;
+    char const *mtab = MOUNTED;
+    FILE *fp;
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next);
+        qemu_free(mount->dirname);
+        qemu_free(mount->devtype);
+        qemu_free(mount);
+    }
+
+    fp = setmntent(mtab, "r");
+    if (!fp) {
+        g_warning("fsfreeze: unable to read mtab");
+        return -1;
+    }
+
+    while ((ment = getmntent(fp))) {
+        /*
+         * An entry which device name doesn't start with a '/' is
+         * either a dummy file system or a network file system.
+         * Add special handling for smbfs and cifs as is done by
+         * coreutils as well.
+         */
+        if ((ment->mnt_fsname[0] != '/') ||
+            (strcmp(ment->mnt_type, "smbfs") == 0) ||
+            (strcmp(ment->mnt_type, "cifs") == 0)) {
+            continue;
+        }
+
+        mount = qemu_mallocz(sizeof(GuestFsfreezeMount));
+        mount->dirname = qemu_strdup(ment->mnt_dir);
+        mount->devtype = qemu_strdup(ment->mnt_type);
+
+        QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next);
+    }
+
+    endmntent(fp);
+
+    return 0;
+}
+
+/*
+ * Return status of freeze/thaw
+ */
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+    return guest_fsfreeze_state.status;
+}
+
+/*
+ * Walk list of mounted file systems in the guest, and freeze the ones which
+ * are real local file systems.
+ */
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+    int ret = 0, i = 0;
+    struct GuestFsfreezeMount *mount, *temp;
+    int fd;
+    char err_msg[512];
+
+    slog("guest-fsfreeze called");
+
+    if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
+        return 0;
+    }
+
+    ret = guest_fsfreeze_build_mount_list();
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* cannot risk guest agent blocking itself on a write in this state */
+    disable_logging();
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        fd = qemu_open(mount->dirname, O_RDONLY);
+        if (fd == -1) {
+            sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno));
+            error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+            goto error;
+        }
+
+        /* we try to cull filesytems we know won't work in advance, but other
+         * filesytems may not implement fsfreeze for less obvious reasons.
+         * these will report EOPNOTSUPP, so we simply ignore them. when
+         * thawing, these filesystems will return an EINVAL instead, due to
+         * not being in a frozen state. Other filesystem-specific
+         * errors may result in EINVAL, however, so the user should check the
+         * number * of filesystems returned here against those returned by the
+         * thaw operation to determine whether everything completed
+         * successfully
+         */
+        ret = ioctl(fd, FIFREEZE);
+        if (ret < 0 && errno != EOPNOTSUPP) {
+            sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno));
+            error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+            close(fd);
+            goto error;
+        }
+        close(fd);
+
+        i++;
+    }
+
+    guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
+    return i;
+
+error:
+    if (i > 0) {
+        qmp_guest_fsfreeze_thaw(NULL);
+    }
+    return 0;
+}
+
+/*
+ * Walk list of frozen file systems in the guest, and thaw them.
+ */
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+    int ret;
+    GuestFsfreezeMount *mount, *temp;
+    int fd, i = 0;
+    bool has_error = false;
+
+    QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
+        fd = qemu_open(mount->dirname, O_RDONLY);
+        if (fd == -1) {
+            has_error = true;
+            continue;
+        }
+        ret = ioctl(fd, FITHAW);
+        if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) {
+            has_error = true;
+            close(fd);
+            continue;
+        }
+        close(fd);
+        i++;
+    }
+
+    if (has_error) {
+        guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR;
+    } else {
+        guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
+    }
+    enable_logging();
+    return i;
+}
+
+static void guest_fsfreeze_init(void)
+{
+    guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
+    QTAILQ_INIT(&guest_fsfreeze_state.mount_list);
+}
+
+static void guest_fsfreeze_cleanup(void)
+{
+    int64_t ret;
+    Error *err = NULL;
+
+    if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
+        ret = qmp_guest_fsfreeze_thaw(&err);
+        if (ret < 0 || err) {
+            slog("failed to clean up frozen filesystems");
+        }
+    }
+}
+#else
+/*
+ * Return status of freeze/thaw
+ */
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+
+/*
+ * Walk list of mounted file systems in the guest, and freeze the ones which
+ * are real local file systems.
+ */
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+
+/*
+ * Walk list of frozen file systems in the guest, and thaw them.
+ */
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
+}
+#endif
+
+/* register init/cleanup routines for stateful command groups */
+void ga_command_state_init(GAState *s, GACommandState *cs)
+{
+    ga_state = s;
+#if defined(CONFIG_FSFREEZE)
+    ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
+#endif
+    ga_command_state_add(cs, guest_file_init, NULL);
+}
diff --git a/qemu-0.15.x/qga/guest-agent-core.h b/qemu-0.15.x/qga/guest-agent-core.h
new file mode 100644
index 0000000..e42b91d
--- /dev/null
+++ b/qemu-0.15.x/qga/guest-agent-core.h
@@ -0,0 +1,31 @@
+/*
+ * QEMU Guest Agent core declarations
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Adam Litke        <aglitke at linux.vnet.ibm.com>
+ *  Michael Roth      <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qapi/qmp-core.h"
+#include "qemu-common.h"
+
+#define QGA_VERSION "1.0"
+#define QGA_READ_COUNT_DEFAULT 4 << 10
+
+typedef struct GAState GAState;
+typedef struct GACommandState GACommandState;
+
+void ga_command_state_init(GAState *s, GACommandState *cs);
+void ga_command_state_add(GACommandState *cs,
+                          void (*init)(void),
+                          void (*cleanup)(void));
+void ga_command_state_init_all(GACommandState *cs);
+void ga_command_state_cleanup_all(GACommandState *cs);
+GACommandState *ga_command_state_new(void);
+bool ga_logging_enabled(GAState *s);
+void ga_disable_logging(GAState *s);
+void ga_enable_logging(GAState *s);
diff --git a/qemu-0.15.x/qint.c b/qemu-0.15.x/qint.c
new file mode 100644
index 0000000..fb3823a
--- /dev/null
+++ b/qemu-0.15.x/qint.c
@@ -0,0 +1,67 @@
+/*
+ * QInt Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qint.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static void qint_destroy_obj(QObject *obj);
+
+static const QType qint_type = {
+    .code = QTYPE_QINT,
+    .destroy = qint_destroy_obj,
+};
+
+/**
+ * qint_from_int(): Create a new QInt from an int64_t
+ *
+ * Return strong reference.
+ */
+QInt *qint_from_int(int64_t value)
+{
+    QInt *qi;
+
+    qi = qemu_malloc(sizeof(*qi));
+    qi->value = value;
+    QOBJECT_INIT(qi, &qint_type);
+
+    return qi;
+}
+
+/**
+ * qint_get_int(): Get the stored integer
+ */
+int64_t qint_get_int(const QInt *qi)
+{
+    return qi->value;
+}
+
+/**
+ * qobject_to_qint(): Convert a QObject into a QInt
+ */
+QInt *qobject_to_qint(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QINT)
+        return NULL;
+
+    return container_of(obj, QInt, base);
+}
+
+/**
+ * qint_destroy_obj(): Free all memory allocated by a
+ * QInt object
+ */
+static void qint_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    qemu_free(qobject_to_qint(obj));
+}
diff --git a/qemu-0.15.x/qint.h b/qemu-0.15.x/qint.h
new file mode 100644
index 0000000..6b1a15c
--- /dev/null
+++ b/qemu-0.15.x/qint.h
@@ -0,0 +1,28 @@
+/*
+ * QInt Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QINT_H
+#define QINT_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QInt {
+    QObject_HEAD;
+    int64_t value;
+} QInt;
+
+QInt *qint_from_int(int64_t value);
+int64_t qint_get_int(const QInt *qi);
+QInt *qobject_to_qint(const QObject *obj);
+
+#endif /* QINT_H */
diff --git a/qemu-0.15.x/qjson.c b/qemu-0.15.x/qjson.c
new file mode 100644
index 0000000..f9c8e77
--- /dev/null
+++ b/qemu-0.15.x/qjson.c
@@ -0,0 +1,294 @@
+/*
+ * QObject JSON integration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "json-lexer.h"
+#include "json-parser.h"
+#include "json-streamer.h"
+#include "qjson.h"
+#include "qint.h"
+#include "qlist.h"
+#include "qbool.h"
+#include "qfloat.h"
+#include "qdict.h"
+
+typedef struct JSONParsingState
+{
+    JSONMessageParser parser;
+    va_list *ap;
+    QObject *result;
+} JSONParsingState;
+
+static void parse_json(JSONMessageParser *parser, QList *tokens)
+{
+    JSONParsingState *s = container_of(parser, JSONParsingState, parser);
+    s->result = json_parser_parse(tokens, s->ap);
+}
+
+QObject *qobject_from_jsonv(const char *string, va_list *ap)
+{
+    JSONParsingState state = {};
+
+    state.ap = ap;
+
+    json_message_parser_init(&state.parser, parse_json);
+    json_message_parser_feed(&state.parser, string, strlen(string));
+    json_message_parser_flush(&state.parser);
+    json_message_parser_destroy(&state.parser);
+
+    return state.result;
+}
+
+QObject *qobject_from_json(const char *string)
+{
+    return qobject_from_jsonv(string, NULL);
+}
+
+/*
+ * IMPORTANT: This function aborts on error, thus it must not
+ * be used with untrusted arguments.
+ */
+QObject *qobject_from_jsonf(const char *string, ...)
+{
+    QObject *obj;
+    va_list ap;
+
+    va_start(ap, string);
+    obj = qobject_from_jsonv(string, &ap);
+    va_end(ap);
+
+    assert(obj != NULL);
+    return obj;
+}
+
+typedef struct ToJsonIterState
+{
+    int indent;
+    int pretty;
+    int count;
+    QString *str;
+} ToJsonIterState;
+
+static void to_json(const QObject *obj, QString *str, int pretty, int indent);
+
+static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
+{
+    ToJsonIterState *s = opaque;
+    QString *qkey;
+    int j;
+
+    if (s->count)
+        qstring_append(s->str, ", ");
+
+    if (s->pretty) {
+        qstring_append(s->str, "\n");
+        for (j = 0 ; j < s->indent ; j++)
+            qstring_append(s->str, "    ");
+    }
+
+    qkey = qstring_from_str(key);
+    to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
+    QDECREF(qkey);
+
+    qstring_append(s->str, ": ");
+    to_json(obj, s->str, s->pretty, s->indent);
+    s->count++;
+}
+
+static void to_json_list_iter(QObject *obj, void *opaque)
+{
+    ToJsonIterState *s = opaque;
+    int j;
+
+    if (s->count)
+        qstring_append(s->str, ", ");
+
+    if (s->pretty) {
+        qstring_append(s->str, "\n");
+        for (j = 0 ; j < s->indent ; j++)
+            qstring_append(s->str, "    ");
+    }
+
+    to_json(obj, s->str, s->pretty, s->indent);
+    s->count++;
+}
+
+static void to_json(const QObject *obj, QString *str, int pretty, int indent)
+{
+    switch (qobject_type(obj)) {
+    case QTYPE_QINT: {
+        QInt *val = qobject_to_qint(obj);
+        char buffer[1024];
+
+        snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val));
+        qstring_append(str, buffer);
+        break;
+    }
+    case QTYPE_QSTRING: {
+        QString *val = qobject_to_qstring(obj);
+        const char *ptr;
+
+        ptr = qstring_get_str(val);
+        qstring_append(str, "\"");
+        while (*ptr) {
+            if ((ptr[0] & 0xE0) == 0xE0 &&
+                (ptr[1] & 0x80) && (ptr[2] & 0x80)) {
+                uint16_t wchar;
+                char escape[7];
+
+                wchar  = (ptr[0] & 0x0F) << 12;
+                wchar |= (ptr[1] & 0x3F) << 6;
+                wchar |= (ptr[2] & 0x3F);
+                ptr += 2;
+
+                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
+                qstring_append(str, escape);
+            } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) {
+                uint16_t wchar;
+                char escape[7];
+
+                wchar  = (ptr[0] & 0x1F) << 6;
+                wchar |= (ptr[1] & 0x3F);
+                ptr++;
+
+                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
+                qstring_append(str, escape);
+            } else switch (ptr[0]) {
+                case '\"':
+                    qstring_append(str, "\\\"");
+                    break;
+                case '\\':
+                    qstring_append(str, "\\\\");
+                    break;
+                case '\b':
+                    qstring_append(str, "\\b");
+                    break;
+                case '\f':
+                    qstring_append(str, "\\f");
+                    break;
+                case '\n':
+                    qstring_append(str, "\\n");
+                    break;
+                case '\r':
+                    qstring_append(str, "\\r");
+                    break;
+                case '\t':
+                    qstring_append(str, "\\t");
+                    break;
+                default: {
+                    if (ptr[0] <= 0x1F) {
+                        char escape[7];
+                        snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]);
+                        qstring_append(str, escape);
+                    } else {
+                        char buf[2] = { ptr[0], 0 };
+                        qstring_append(str, buf);
+                    }
+                    break;
+                }
+                }
+            ptr++;
+        }
+        qstring_append(str, "\"");
+        break;
+    }
+    case QTYPE_QDICT: {
+        ToJsonIterState s;
+        QDict *val = qobject_to_qdict(obj);
+
+        s.count = 0;
+        s.str = str;
+        s.indent = indent + 1;
+        s.pretty = pretty;
+        qstring_append(str, "{");
+        qdict_iter(val, to_json_dict_iter, &s);
+        if (pretty) {
+            int j;
+            qstring_append(str, "\n");
+            for (j = 0 ; j < indent ; j++)
+                qstring_append(str, "    ");
+        }
+        qstring_append(str, "}");
+        break;
+    }
+    case QTYPE_QLIST: {
+        ToJsonIterState s;
+        QList *val = qobject_to_qlist(obj);
+
+        s.count = 0;
+        s.str = str;
+        s.indent = indent + 1;
+        s.pretty = pretty;
+        qstring_append(str, "[");
+        qlist_iter(val, (void *)to_json_list_iter, &s);
+        if (pretty) {
+            int j;
+            qstring_append(str, "\n");
+            for (j = 0 ; j < indent ; j++)
+                qstring_append(str, "    ");
+        }
+        qstring_append(str, "]");
+        break;
+    }
+    case QTYPE_QFLOAT: {
+        QFloat *val = qobject_to_qfloat(obj);
+        char buffer[1024];
+        int len;
+
+        len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
+        while (len > 0 && buffer[len - 1] == '0') {
+            len--;
+        }
+
+        if (len && buffer[len - 1] == '.') {
+            buffer[len - 1] = 0;
+        } else {
+            buffer[len] = 0;
+        }
+        
+        qstring_append(str, buffer);
+        break;
+    }
+    case QTYPE_QBOOL: {
+        QBool *val = qobject_to_qbool(obj);
+
+        if (qbool_get_int(val)) {
+            qstring_append(str, "true");
+        } else {
+            qstring_append(str, "false");
+        }
+        break;
+    }
+    case QTYPE_QERROR:
+        /* XXX: should QError be emitted? */
+    case QTYPE_NONE:
+        break;
+    }
+}
+
+QString *qobject_to_json(const QObject *obj)
+{
+    QString *str = qstring_new();
+
+    to_json(obj, str, 0, 0);
+
+    return str;
+}
+
+QString *qobject_to_json_pretty(const QObject *obj)
+{
+    QString *str = qstring_new();
+
+    to_json(obj, str, 1, 0);
+
+    return str;
+}
diff --git a/qemu-0.15.x/qjson.h b/qemu-0.15.x/qjson.h
new file mode 100644
index 0000000..65b10ea
--- /dev/null
+++ b/qemu-0.15.x/qjson.h
@@ -0,0 +1,28 @@
+/*
+ * QObject JSON integration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QJSON_H
+#define QJSON_H
+
+#include <stdarg.h>
+#include "qobject.h"
+#include "qstring.h"
+
+QObject *qobject_from_json(const char *string) GCC_FMT_ATTR(1, 0);
+QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2);
+QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0);
+
+QString *qobject_to_json(const QObject *obj);
+QString *qobject_to_json_pretty(const QObject *obj);
+
+#endif /* QJSON_H */
diff --git a/qemu-0.15.x/qlist.c b/qemu-0.15.x/qlist.c
new file mode 100644
index 0000000..5730fb8
--- /dev/null
+++ b/qemu-0.15.x/qlist.c
@@ -0,0 +1,157 @@
+/*
+ * QList Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qlist.h"
+#include "qobject.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+
+static void qlist_destroy_obj(QObject *obj);
+
+static const QType qlist_type = {
+    .code = QTYPE_QLIST,
+    .destroy = qlist_destroy_obj,
+};
+ 
+/**
+ * qlist_new(): Create a new QList
+ *
+ * Return strong reference.
+ */
+QList *qlist_new(void)
+{
+    QList *qlist;
+
+    qlist = qemu_malloc(sizeof(*qlist));
+    QTAILQ_INIT(&qlist->head);
+    QOBJECT_INIT(qlist, &qlist_type);
+
+    return qlist;
+}
+
+static void qlist_copy_elem(QObject *obj, void *opaque)
+{
+    QList *dst = opaque;
+
+    qobject_incref(obj);
+    qlist_append_obj(dst, obj);
+}
+
+QList *qlist_copy(QList *src)
+{
+    QList *dst = qlist_new();
+
+    qlist_iter(src, qlist_copy_elem, dst);
+
+    return dst;
+}
+
+/**
+ * qlist_append_obj(): Append an QObject into QList
+ *
+ * NOTE: ownership of 'value' is transferred to the QList
+ */
+void qlist_append_obj(QList *qlist, QObject *value)
+{
+    QListEntry *entry;
+
+    entry = qemu_malloc(sizeof(*entry));
+    entry->value = value;
+
+    QTAILQ_INSERT_TAIL(&qlist->head, entry, next);
+}
+
+/**
+ * qlist_iter(): Iterate over all the list's stored values.
+ *
+ * This function allows the user to provide an iterator, which will be
+ * called for each stored value in the list.
+ */
+void qlist_iter(const QList *qlist,
+                void (*iter)(QObject *obj, void *opaque), void *opaque)
+{
+    QListEntry *entry;
+
+    QTAILQ_FOREACH(entry, &qlist->head, next)
+        iter(entry->value, opaque);
+}
+
+QObject *qlist_pop(QList *qlist)
+{
+    QListEntry *entry;
+    QObject *ret;
+
+    if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+        return NULL;
+    }
+
+    entry = QTAILQ_FIRST(&qlist->head);
+    QTAILQ_REMOVE(&qlist->head, entry, next);
+
+    ret = entry->value;
+    qemu_free(entry);
+
+    return ret;
+}
+
+QObject *qlist_peek(QList *qlist)
+{
+    QListEntry *entry;
+    QObject *ret;
+
+    if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+        return NULL;
+    }
+
+    entry = QTAILQ_FIRST(&qlist->head);
+
+    ret = entry->value;
+
+    return ret;
+}
+
+int qlist_empty(const QList *qlist)
+{
+    return QTAILQ_EMPTY(&qlist->head);
+}
+
+/**
+ * qobject_to_qlist(): Convert a QObject into a QList
+ */
+QList *qobject_to_qlist(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QLIST) {
+        return NULL;
+    }
+
+    return container_of(obj, QList, base);
+}
+
+/**
+ * qlist_destroy_obj(): Free all the memory allocated by a QList
+ */
+static void qlist_destroy_obj(QObject *obj)
+{
+    QList *qlist;
+    QListEntry *entry, *next_entry;
+
+    assert(obj != NULL);
+    qlist = qobject_to_qlist(obj);
+
+    QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) {
+        QTAILQ_REMOVE(&qlist->head, entry, next);
+        qobject_decref(entry->value);
+        qemu_free(entry);
+    }
+
+    qemu_free(qlist);
+}
diff --git a/qemu-0.15.x/qlist.h b/qemu-0.15.x/qlist.h
new file mode 100644
index 0000000..d426bd4
--- /dev/null
+++ b/qemu-0.15.x/qlist.h
@@ -0,0 +1,64 @@
+/*
+ * QList Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QLIST_H
+#define QLIST_H
+
+#include "qobject.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-queue.h"
+
+typedef struct QListEntry {
+    QObject *value;
+    QTAILQ_ENTRY(QListEntry) next;
+} QListEntry;
+
+typedef struct QList {
+    QObject_HEAD;
+    QTAILQ_HEAD(,QListEntry) head;
+} QList;
+
+#define qlist_append(qlist, obj) \
+        qlist_append_obj(qlist, QOBJECT(obj))
+
+#define QLIST_FOREACH_ENTRY(qlist, var)             \
+        for ((var) = ((qlist)->head.tqh_first);     \
+            (var);                                  \
+            (var) = ((var)->next.tqe_next))
+
+static inline QObject *qlist_entry_obj(const QListEntry *entry)
+{
+    return entry->value;
+}
+
+QList *qlist_new(void);
+QList *qlist_copy(QList *src);
+void qlist_append_obj(QList *qlist, QObject *obj);
+void qlist_iter(const QList *qlist,
+                void (*iter)(QObject *obj, void *opaque), void *opaque);
+QObject *qlist_pop(QList *qlist);
+QObject *qlist_peek(QList *qlist);
+int qlist_empty(const QList *qlist);
+QList *qobject_to_qlist(const QObject *obj);
+
+static inline const QListEntry *qlist_first(const QList *qlist)
+{
+    return QTAILQ_FIRST(&qlist->head);
+}
+
+static inline const QListEntry *qlist_next(const QListEntry *entry)
+{
+    return QTAILQ_NEXT(entry, next);
+}
+
+#endif /* QLIST_H */
diff --git a/qemu-0.15.x/qmp-commands.hx b/qemu-0.15.x/qmp-commands.hx
new file mode 100644
index 0000000..54e313c
--- /dev/null
+++ b/qemu-0.15.x/qmp-commands.hx
@@ -0,0 +1,1868 @@
+HXCOMM QMP dispatch table and documentation
+HXCOMM Text between SQMP and EQMP is copied to the QMP documention file and
+HXCOMM does not show up in the other formats.
+
+SQMP
+                        QMP Supported Commands
+                        ----------------------
+
+This document describes all commands currently supported by QMP.
+
+Most of the time their usage is exactly the same as in the user Monitor, this
+means that any other document which also describe commands (the manpage,
+QEMU's manual, etc) can and should be consulted.
+
+QMP has two types of commands: regular and query commands. Regular commands
+usually change the Virtual Machine's state someway, while query commands just
+return information. The sections below are divided accordingly.
+
+It's important to observe that all communication examples are formatted in
+a reader-friendly way, so that they're easier to understand. However, in real
+protocol usage, they're emitted as a single line.
+
+Also, the following notation is used to denote data flow:
+
+-> data issued by the Client
+<- Server data response
+
+Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed
+information on the Server command and response formats.
+
+NOTE: This document is temporary and will be replaced soon.
+
+1. Stability Considerations
+===========================
+
+The current QMP command set (described in this file) may be useful for a
+number of use cases, however it's limited and several commands have bad
+defined semantics, specially with regard to command completion.
+
+These problems are going to be solved incrementally in the next QEMU releases
+and we're going to establish a deprecation policy for badly defined commands.
+
+If you're planning to adopt QMP, please observe the following:
+
+    1. The deprecation policy will take efect and be documented soon, please
+       check the documentation of each used command as soon as a new release of
+       QEMU is available
+
+    2. DO NOT rely on anything which is not explicit documented
+
+    3. Errors, in special, are not documented. Applications should NOT check
+       for specific errors classes or data (it's strongly recommended to only
+       check for the "error" key)
+
+2. Regular Commands
+===================
+
+Server's responses in the examples below are always a success response, please
+refer to the QMP specification for more details on error responses.
+
+EQMP
+
+    {
+        .name       = "quit",
+        .args_type  = "",
+        .params     = "",
+        .help       = "quit the emulator",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_quit,
+    },
+
+SQMP
+quit
+----
+
+Quit the emulator.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "quit" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "eject",
+        .args_type  = "force:-f,device:B",
+        .params     = "[-f] device",
+        .help       = "eject a removable medium (use -f to force it)",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_eject,
+    },
+
+SQMP
+eject
+-----
+
+Eject a removable medium.
+
+Arguments: 
+
+- force: force ejection (json-bool, optional)
+- device: device name (json-string)
+
+Example:
+
+-> { "execute": "eject", "arguments": { "device": "ide1-cd0" } }
+<- { "return": {} }
+
+Note: The "force" argument defaults to false.
+
+EQMP
+
+    {
+        .name       = "change",
+        .args_type  = "device:B,target:F,arg:s?",
+        .params     = "device filename [format]",
+        .help       = "change a removable medium, optional format",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_change,
+    },
+
+SQMP
+change
+------
+
+Change a removable medium or VNC configuration.
+
+Arguments:
+
+- "device": device name (json-string)
+- "target": filename or item (json-string)
+- "arg": additional argument (json-string, optional)
+
+Examples:
+
+1. Change a removable medium
+
+-> { "execute": "change",
+             "arguments": { "device": "ide1-cd0",
+                            "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } }
+<- { "return": {} }
+
+2. Change VNC password
+
+-> { "execute": "change",
+             "arguments": { "device": "vnc", "target": "password",
+                            "arg": "foobar1" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "screendump",
+        .args_type  = "filename:F",
+        .params     = "filename",
+        .help       = "save screen into PPM image 'filename'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_screen_dump,
+    },
+
+SQMP
+screendump
+----------
+
+Save screen into PPM image.
+
+Arguments:
+
+- "filename": file path (json-string)
+
+Example:
+
+-> { "execute": "screendump", "arguments": { "filename": "/tmp/image" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "stop",
+        .args_type  = "",
+        .params     = "",
+        .help       = "stop emulation",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_stop,
+    },
+
+SQMP
+stop
+----
+
+Stop the emulator.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "stop" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "cont",
+        .args_type  = "",
+        .params     = "",
+        .help       = "resume emulation",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_cont,
+    },
+
+SQMP
+cont
+----
+
+Resume emulation.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "cont" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "system_reset",
+        .args_type  = "",
+        .params     = "",
+        .help       = "reset the system",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_system_reset,
+    },
+
+SQMP
+system_reset
+------------
+
+Reset the system.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "system_reset" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "system_powerdown",
+        .args_type  = "",
+        .params     = "",
+        .help       = "send system power down event",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_system_powerdown,
+    },
+
+SQMP
+system_powerdown
+----------------
+
+Send system power down event.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "system_powerdown" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "device_add",
+        .args_type  = "device:O",
+        .params     = "driver[,prop=value][,...]",
+        .help       = "add device, like -device on the command line",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_device_add,
+    },
+
+SQMP
+device_add
+----------
+
+Add a device.
+
+Arguments:
+
+- "driver": the name of the new device's driver (json-string)
+- "bus": the device's parent bus (device tree path, json-string, optional)
+- "id": the device's ID, must be unique (json-string)
+- device properties
+
+Example:
+
+-> { "execute": "device_add", "arguments": { "driver": "e1000", "id": "net1" } }
+<- { "return": {} }
+
+Notes:
+
+(1) For detailed information about this command, please refer to the
+    'docs/qdev-device-use.txt' file.
+
+(2) It's possible to list device properties by running QEMU with the
+    "-device DEVICE,\?" command-line argument, where DEVICE is the device's name
+
+EQMP
+
+    {
+        .name       = "device_del",
+        .args_type  = "id:s",
+        .params     = "device",
+        .help       = "remove device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_device_del,
+    },
+
+SQMP
+device_del
+----------
+
+Remove a device.
+
+Arguments:
+
+- "id": the device's ID (json-string)
+
+Example:
+
+-> { "execute": "device_del", "arguments": { "id": "net1" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "cpu",
+        .args_type  = "index:i",
+        .params     = "index",
+        .help       = "set the default CPU",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_cpu_set,
+    },
+
+SQMP
+cpu
+---
+
+Set the default CPU.
+
+Arguments:
+
+- "index": the CPU's index (json-int)
+
+Example:
+
+-> { "execute": "cpu", "arguments": { "index": 0 } }
+<- { "return": {} }
+
+Note: CPUs' indexes are obtained with the 'query-cpus' command.
+
+EQMP
+
+    {
+        .name       = "memsave",
+        .args_type  = "val:l,size:i,filename:s",
+        .params     = "addr size file",
+        .help       = "save to disk virtual memory dump starting at 'addr' of size 'size'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_memory_save,
+    },
+
+SQMP
+memsave
+-------
+
+Save to disk virtual memory dump starting at 'val' of size 'size'.
+
+Arguments:
+
+- "val": the starting address (json-int)
+- "size": the memory size, in bytes (json-int)
+- "filename": file path (json-string)
+
+Example:
+
+-> { "execute": "memsave",
+             "arguments": { "val": 10,
+                            "size": 100,
+                            "filename": "/tmp/virtual-mem-dump" } }
+<- { "return": {} }
+
+Note: Depends on the current CPU.
+
+EQMP
+
+    {
+        .name       = "pmemsave",
+        .args_type  = "val:l,size:i,filename:s",
+        .params     = "addr size file",
+        .help       = "save to disk physical memory dump starting at 'addr' of size 'size'",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_physical_memory_save,
+    },
+
+SQMP
+pmemsave
+--------
+
+Save to disk physical memory dump starting at 'val' of size 'size'.
+
+Arguments:
+
+- "val": the starting address (json-int)
+- "size": the memory size, in bytes (json-int)
+- "filename": file path (json-string)
+
+Example:
+
+-> { "execute": "pmemsave",
+             "arguments": { "val": 10,
+                            "size": 100,
+                            "filename": "/tmp/physical-mem-dump" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "inject-nmi",
+        .args_type  = "",
+        .params     = "",
+        .help       = "",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_inject_nmi,
+    },
+
+SQMP
+inject-nmi
+----------
+
+Inject an NMI on guest's CPUs.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "inject-nmi" }
+<- { "return": {} }
+
+Note: inject-nmi is only supported for x86 guest currently, it will
+      returns "Unsupported" error for non-x86 guest.
+
+EQMP
+
+    {
+        .name       = "migrate",
+        .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
+        .params     = "[-d] [-b] [-i] uri",
+        .help       = "migrate to URI (using -d to not wait for completion)"
+		      "\n\t\t\t -b for migration without shared storage with"
+		      " full copy of disk\n\t\t\t -i for migration without "
+		      "shared storage with incremental copy of disk "
+		      "(base image shared between src and destination)",
+        .user_print = monitor_user_noop,	
+	.mhandler.cmd_new = do_migrate,
+    },
+
+SQMP
+migrate
+-------
+
+Migrate to URI.
+
+Arguments:
+
+- "blk": block migration, full disk copy (json-bool, optional)
+- "inc": incremental disk copy (json-bool, optional)
+- "uri": Destination URI (json-string)
+
+Example:
+
+-> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
+<- { "return": {} }
+
+Notes:
+
+(1) The 'query-migrate' command should be used to check migration's progress
+    and final result (this information is provided by the 'status' member)
+(2) All boolean arguments default to false
+(3) The user Monitor's "detach" argument is invalid in QMP and should not
+    be used
+
+EQMP
+
+    {
+        .name       = "migrate_cancel",
+        .args_type  = "",
+        .params     = "",
+        .help       = "cancel the current VM migration",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_cancel,
+    },
+
+SQMP
+migrate_cancel
+--------------
+
+Cancel the current migration.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "migrate_cancel" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "migrate_set_speed",
+        .args_type  = "value:o",
+        .params     = "value",
+        .help       = "set maximum speed (in bytes) for migrations",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_set_speed,
+    },
+
+SQMP
+migrate_set_speed
+-----------------
+
+Set maximum speed for migrations.
+
+Arguments:
+
+- "value": maximum speed, in bytes per second (json-int)
+
+Example:
+
+-> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "migrate_set_downtime",
+        .args_type  = "value:T",
+        .params     = "value",
+        .help       = "set maximum tolerated downtime (in seconds) for migrations",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_migrate_set_downtime,
+    },
+
+SQMP
+migrate_set_downtime
+--------------------
+
+Set maximum tolerated downtime (in seconds) for migrations.
+
+Arguments:
+
+- "value": maximum downtime (json-number)
+
+Example:
+
+-> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "client_migrate_info",
+        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+        .params     = "protocol hostname port tls-port cert-subject",
+        .help       = "send migration info to spice/vnc client",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = client_migrate_info,
+    },
+
+SQMP
+client_migrate_info
+------------------
+
+Set the spice/vnc connection info for the migration target.  The spice/vnc
+server will ask the spice/vnc client to automatically reconnect using the
+new parameters (if specified) once the vm migration finished successfully.
+
+Arguments:
+
+- "protocol":     protocol: "spice" or "vnc" (json-string)
+- "hostname":     migration target hostname (json-string)
+- "port":         spice/vnc tcp port for plaintext channels (json-int, optional)
+- "tls-port":     spice tcp port for tls-secured channels (json-int, optional)
+- "cert-subject": server certificate subject (json-string, optional)
+
+Example:
+
+-> { "execute": "client_migrate_info",
+     "arguments": { "protocol": "spice",
+                    "hostname": "virt42.lab.kraxel.org",
+                    "port": 1234 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "netdev_add",
+        .args_type  = "netdev:O",
+        .params     = "[user|tap|socket],id=str[,prop=value][,...]",
+        .help       = "add host network device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_netdev_add,
+    },
+
+SQMP
+netdev_add
+----------
+
+Add host network device.
+
+Arguments:
+
+- "type": the device type, "tap", "user", ... (json-string)
+- "id": the device's ID, must be unique (json-string)
+- device options
+
+Example:
+
+-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
+<- { "return": {} }
+
+Note: The supported device options are the same ones supported by the '-net'
+      command-line argument, which are listed in the '-help' output or QEMU's
+      manual
+
+EQMP
+
+    {
+        .name       = "netdev_del",
+        .args_type  = "id:s",
+        .params     = "id",
+        .help       = "remove host network device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_netdev_del,
+    },
+
+SQMP
+netdev_del
+----------
+
+Remove host network device.
+
+Arguments:
+
+- "id": the device's ID, must be unique (json-string)
+
+Example:
+
+-> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
+<- { "return": {} }
+
+
+EQMP
+
+    {
+        .name       = "block_resize",
+        .args_type  = "device:B,size:o",
+        .params     = "device size",
+        .help       = "resize a block image",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_resize,
+    },
+
+SQMP
+block_resize
+------------
+
+Resize a block image while a guest is running.
+
+Arguments:
+
+- "device": the device's ID, must be unique (json-string)
+- "size": new size
+
+Example:
+
+-> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "blockdev-snapshot-sync",
+        .args_type  = "device:B,snapshot-file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+SQMP
+blockdev-snapshot-sync
+----------------------
+
+Synchronous snapshot of a block device. snapshot-file specifies the
+target of the new image. If the file exists, or if it is a device, the
+snapshot will be created in the existing file/device. If does not
+exist, a new file will be created. format specifies the format of the
+snapshot image, default is qcow2.
+
+Arguments:
+
+- "device": device name to snapshot (json-string)
+- "snapshot-file": name of new image file (json-string)
+- "format": format of new image (json-string, optional)
+
+Example:
+
+-> { "execute": "blockdev-snapshot", "arguments": { "device": "ide-hd0",
+                                                    "snapshot-file":
+                                                    "/some/place/my-image",
+                                                    "format": "qcow2" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "balloon",
+        .args_type  = "value:M",
+        .params     = "target",
+        .help       = "request VM to change its memory allocation (in MB)",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_async = do_balloon,
+        .flags      = MONITOR_CMD_ASYNC,
+    },
+
+SQMP
+balloon
+-------
+
+Request VM to change its memory allocation (in bytes).
+
+Arguments:
+
+- "value": New memory allocation (json-int)
+
+Example:
+
+-> { "execute": "balloon", "arguments": { "value": 536870912 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "set_link",
+        .args_type  = "name:s,up:b",
+        .params     = "name on|off",
+        .help       = "change the link status of a network adapter",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_set_link,
+    },
+
+SQMP
+set_link
+--------
+
+Change the link status of a network adapter.
+
+Arguments:
+
+- "name": network device name (json-string)
+- "up": status is up (json-bool)
+
+Example:
+
+-> { "execute": "set_link", "arguments": { "name": "e1000.0", "up": false } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "getfd",
+        .args_type  = "fdname:s",
+        .params     = "getfd name",
+        .help       = "receive a file descriptor via SCM rights and assign it a name",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_getfd,
+    },
+
+SQMP
+getfd
+-----
+
+Receive a file descriptor via SCM rights and assign it a name.
+
+Arguments:
+
+- "fdname": file descriptor name (json-string)
+
+Example:
+
+-> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "closefd",
+        .args_type  = "fdname:s",
+        .params     = "closefd name",
+        .help       = "close a file descriptor previously passed via SCM rights",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_closefd,
+    },
+
+SQMP
+closefd
+-------
+
+Close a file descriptor previously passed via SCM rights.
+
+Arguments:
+
+- "fdname": file descriptor name (json-string)
+
+Example:
+
+-> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "block_passwd",
+        .args_type  = "device:B,password:s",
+        .params     = "block_passwd device password",
+        .help       = "set the password of encrypted block devices",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_set_passwd,
+    },
+
+SQMP
+block_passwd
+------------
+
+Set the password of encrypted block devices.
+
+Arguments:
+
+- "device": device name (json-string)
+- "password": password (json-string)
+
+Example:
+
+-> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
+                                               "password": "12345" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "set_password",
+        .args_type  = "protocol:s,password:s,connected:s?",
+        .params     = "protocol password action-if-connected",
+        .help       = "set spice/vnc password",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = set_password,
+    },
+
+SQMP
+set_password
+------------
+
+Set the password for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "password": password (json-string)
+- "connected": [ keep | disconnect | fail ] (josn-string, optional)
+
+Example:
+
+-> { "execute": "set_password", "arguments": { "protocol": "vnc",
+                                               "password": "secret" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "expire_password",
+        .args_type  = "protocol:s,time:s",
+        .params     = "protocol time",
+        .help       = "set spice/vnc password expire-time",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = expire_password,
+    },
+
+SQMP
+expire_password
+---------------
+
+Set the password expire time for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "time": [ now | never | +secs | secs ] (json-string)
+
+Example:
+
+-> { "execute": "expire_password", "arguments": { "protocol": "vnc",
+                                                  "time": "+60" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "add_client",
+        .args_type  = "protocol:s,fdname:s,skipauth:b?",
+        .params     = "protocol fdname skipauth",
+        .help       = "add a graphics client",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = add_graphics_client,
+    },
+
+SQMP
+add_client
+----------
+
+Add a graphics client
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "fdname": file descriptor name (json-string)
+
+Example:
+
+-> { "execute": "add_client", "arguments": { "protocol": "vnc",
+                                             "fdname": "myclient" } }
+<- { "return": {} }
+
+EQMP
+    {
+        .name       = "qmp_capabilities",
+        .args_type  = "",
+        .params     = "",
+        .help       = "enable QMP capabilities",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_qmp_capabilities,
+    },
+
+SQMP
+qmp_capabilities
+----------------
+
+Enable QMP capabilities.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "qmp_capabilities" }
+<- { "return": {} }
+
+Note: This command must be issued before issuing any other command.
+
+EQMP
+
+    {
+        .name       = "human-monitor-command",
+        .args_type  = "command-line:s,cpu-index:i?",
+        .params     = "",
+        .help       = "",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_hmp_passthrough,
+    },
+
+SQMP
+human-monitor-command
+---------------------
+
+Execute a Human Monitor command.
+
+Arguments: 
+
+- command-line: the command name and its arguments, just like the
+                Human Monitor's shell (json-string)
+- cpu-index: select the CPU number to be used by commands which access CPU
+             data, like 'info registers'. The Monitor selects CPU 0 if this
+             argument is not provided (json-int, optional)
+
+Example:
+
+-> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } }
+<- { "return": "kvm support: enabled\r\n" }
+
+Notes:
+
+(1) The Human Monitor is NOT an stable interface, this means that command
+    names, arguments and responses can change or be removed at ANY time.
+    Applications that rely on long term stability guarantees should NOT
+    use this command
+
+(2) Limitations:
+
+    o This command is stateless, this means that commands that depend
+      on state information (such as getfd) might not work
+
+    o Commands that prompt the user for data (eg. 'cont' when the block
+      device is encrypted) don't currently work
+
+3. Query Commands
+=================
+
+HXCOMM Each query command below is inside a SQMP/EQMP section, do NOT change
+HXCOMM this! We will possibly move query commands definitions inside those
+HXCOMM sections, just like regular commands.
+
+EQMP
+
+SQMP
+query-version
+-------------
+
+Show QEMU version.
+
+Return a json-object with the following information:
+
+- "qemu": A json-object containing three integer values:
+    - "major": QEMU's major version (json-int)
+    - "minor": QEMU's minor version (json-int)
+    - "micro": QEMU's micro version (json-int)
+- "package": package's version (json-string)
+
+Example:
+
+-> { "execute": "query-version" }
+<- {
+      "return":{
+         "qemu":{
+            "major":0,
+            "minor":11,
+            "micro":5
+         },
+         "package":""
+      }
+   }
+
+EQMP
+
+SQMP
+query-commands
+--------------
+
+List QMP available commands.
+
+Each command is represented by a json-object, the returned value is a json-array
+of all commands.
+
+Each json-object contain:
+
+- "name": command's name (json-string)
+
+Example:
+
+-> { "execute": "query-commands" }
+<- {
+      "return":[
+         {
+            "name":"query-balloon"
+         },
+         {
+            "name":"system_powerdown"
+         }
+      ]
+   }
+
+Note: This example has been shortened as the real response is too long.
+
+EQMP
+
+SQMP
+query-chardev
+-------------
+
+Each device is represented by a json-object. The returned value is a json-array
+of all devices.
+
+Each json-object contain the following:
+
+- "label": device's label (json-string)
+- "filename": device's file (json-string)
+
+Example:
+
+-> { "execute": "query-chardev" }
+<- {
+      "return":[
+         {
+            "label":"monitor",
+            "filename":"stdio"
+         },
+         {
+            "label":"serial0",
+            "filename":"vc"
+         }
+      ]
+   }
+
+EQMP
+
+SQMP
+query-block
+-----------
+
+Show the block devices.
+
+Each block device information is stored in a json-object and the returned value
+is a json-array of all devices.
+
+Each json-object contain the following:
+
+- "device": device name (json-string)
+- "type": device type (json-string)
+         - deprecated, retained for backward compatibility
+         - Possible values: "unknown"
+- "removable": true if the device is removable, false otherwise (json-bool)
+- "locked": true if the device is locked, false otherwise (json-bool)
+- "inserted": only present if the device is inserted, it is a json-object
+   containing the following:
+         - "file": device file name (json-string)
+         - "ro": true if read-only, false otherwise (json-bool)
+         - "drv": driver format name (json-string)
+             - Possible values: "blkdebug", "bochs", "cloop", "cow", "dmg",
+                                "file", "file", "ftp", "ftps", "host_cdrom",
+                                "host_device", "host_floppy", "http", "https",
+                                "nbd", "parallels", "qcow", "qcow2", "raw",
+                                "tftp", "vdi", "vmdk", "vpc", "vvfat"
+         - "backing_file": backing file name (json-string, optional)
+         - "encrypted": true if encrypted, false otherwise (json-bool)
+
+Example:
+
+-> { "execute": "query-block" }
+<- {
+      "return":[
+         {
+            "device":"ide0-hd0",
+            "locked":false,
+            "removable":false,
+            "inserted":{
+               "ro":false,
+               "drv":"qcow2",
+               "encrypted":false,
+               "file":"disks/test.img"
+            },
+            "type":"unknown"
+         },
+         {
+            "device":"ide1-cd0",
+            "locked":false,
+            "removable":true,
+            "type":"unknown"
+         },
+         {
+            "device":"floppy0",
+            "locked":false,
+            "removable":true,
+            "type":"unknown"
+         },
+         {
+            "device":"sd0",
+            "locked":false,
+            "removable":true,
+            "type":"unknown"
+         }
+      ]
+   }
+
+EQMP
+
+SQMP
+query-blockstats
+----------------
+
+Show block device statistics.
+
+Each device statistic information is stored in a json-object and the returned
+value is a json-array of all devices.
+
+Each json-object contain the following:
+
+- "device": device name (json-string)
+- "stats": A json-object with the statistics information, it contains:
+    - "rd_bytes": bytes read (json-int)
+    - "wr_bytes": bytes written (json-int)
+    - "rd_operations": read operations (json-int)
+    - "wr_operations": write operations (json-int)
+    - "wr_highest_offset": Highest offset of a sector written since the
+                           BlockDriverState has been opened (json-int)
+- "parent": Contains recursively the statistics of the underlying
+            protocol (e.g. the host file for a qcow2 image). If there is
+            no underlying protocol, this field is omitted
+            (json-object, optional)
+
+Example:
+
+-> { "execute": "query-blockstats" }
+<- {
+      "return":[
+         {
+            "device":"ide0-hd0",
+            "parent":{
+               "stats":{
+                  "wr_highest_offset":3686448128,
+                  "wr_bytes":9786368,
+                  "wr_operations":751,
+                  "rd_bytes":122567168,
+                  "rd_operations":36772
+               }
+            },
+            "stats":{
+               "wr_highest_offset":2821110784,
+               "wr_bytes":9786368,
+               "wr_operations":692,
+               "rd_bytes":122739200,
+               "rd_operations":36604
+            }
+         },
+         {
+            "device":"ide1-cd0",
+            "stats":{
+               "wr_highest_offset":0,
+               "wr_bytes":0,
+               "wr_operations":0,
+               "rd_bytes":0,
+               "rd_operations":0
+            }
+         },
+         {
+            "device":"floppy0",
+            "stats":{
+               "wr_highest_offset":0,
+               "wr_bytes":0,
+               "wr_operations":0,
+               "rd_bytes":0,
+               "rd_operations":0
+            }
+         },
+         {
+            "device":"sd0",
+            "stats":{
+               "wr_highest_offset":0,
+               "wr_bytes":0,
+               "wr_operations":0,
+               "rd_bytes":0,
+               "rd_operations":0
+            }
+         }
+      ]
+   }
+
+EQMP
+
+SQMP
+query-cpus
+----------
+
+Show CPU information.
+
+Return a json-array. Each CPU is represented by a json-object, which contains:
+
+- "CPU": CPU index (json-int)
+- "current": true if this is the current CPU, false otherwise (json-bool)
+- "halted": true if the cpu is halted, false otherwise (json-bool)
+- Current program counter. The key's name depends on the architecture:
+     "pc": i386/x86_64 (json-int)
+     "nip": PPC (json-int)
+     "pc" and "npc": sparc (json-int)
+     "PC": mips (json-int)
+- "thread_id": ID of the underlying host thread (json-int)
+
+Example:
+
+-> { "execute": "query-cpus" }
+<- {
+      "return":[
+         {
+            "CPU":0,
+            "current":true,
+            "halted":false,
+            "pc":3227107138
+            "thread_id":3134
+         },
+         {
+            "CPU":1,
+            "current":false,
+            "halted":true,
+            "pc":7108165
+            "thread_id":3135
+         }
+      ]
+   }
+
+EQMP
+
+SQMP
+query-pci
+---------
+
+PCI buses and devices information.
+
+The returned value is a json-array of all buses. Each bus is represented by
+a json-object, which has a key with a json-array of all PCI devices attached
+to it. Each device is represented by a json-object.
+
+The bus json-object contains the following:
+
+- "bus": bus number (json-int)
+- "devices": a json-array of json-objects, each json-object represents a
+             PCI device
+
+The PCI device json-object contains the following:
+
+- "bus": identical to the parent's bus number (json-int)
+- "slot": slot number (json-int)
+- "function": function number (json-int)
+- "class_info": a json-object containing:
+     - "desc": device class description (json-string, optional)
+     - "class": device class number (json-int)
+- "id": a json-object containing:
+     - "device": device ID (json-int)
+     - "vendor": vendor ID (json-int)
+- "irq": device's IRQ if assigned (json-int, optional)
+- "qdev_id": qdev id string (json-string)
+- "pci_bridge": It's a json-object, only present if this device is a
+                PCI bridge, contains:
+     - "bus": bus number (json-int)
+     - "secondary": secondary bus number (json-int)
+     - "subordinate": subordinate bus number (json-int)
+     - "io_range": I/O memory range information, a json-object with the
+                   following members:
+                 - "base": base address, in bytes (json-int)
+                 - "limit": limit address, in bytes (json-int)
+     - "memory_range": memory range information, a json-object with the
+                       following members:
+                 - "base": base address, in bytes (json-int)
+                 - "limit": limit address, in bytes (json-int)
+     - "prefetchable_range": Prefetchable memory range information, a
+                             json-object with the following members:
+                 - "base": base address, in bytes (json-int)
+                 - "limit": limit address, in bytes (json-int)
+     - "devices": a json-array of PCI devices if there's any attached, each
+                  each element is represented by a json-object, which contains
+                  the same members of the 'PCI device json-object' described
+                  above (optional)
+- "regions": a json-array of json-objects, each json-object represents a
+             memory region of this device
+
+The memory range json-object contains the following:
+
+- "base": base memory address (json-int)
+- "limit": limit value (json-int)
+
+The region json-object can be an I/O region or a memory region, an I/O region
+json-object contains the following:
+
+- "type": "io" (json-string, fixed)
+- "bar": BAR number (json-int)
+- "address": memory address (json-int)
+- "size": memory size (json-int)
+
+A memory region json-object contains the following:
+
+- "type": "memory" (json-string, fixed)
+- "bar": BAR number (json-int)
+- "address": memory address (json-int)
+- "size": memory size (json-int)
+- "mem_type_64": true or false (json-bool)
+- "prefetch": true or false (json-bool)
+
+Example:
+
+-> { "execute": "query-pci" }
+<- {
+      "return":[
+         {
+            "bus":0,
+            "devices":[
+               {
+                  "bus":0,
+                  "qdev_id":"",
+                  "slot":0,
+                  "class_info":{
+                     "class":1536,
+                     "desc":"Host bridge"
+                  },
+                  "id":{
+                     "device":32902,
+                     "vendor":4663
+                  },
+                  "function":0,
+                  "regions":[
+   
+                  ]
+               },
+               {
+                  "bus":0,
+                  "qdev_id":"",
+                  "slot":1,
+                  "class_info":{
+                     "class":1537,
+                     "desc":"ISA bridge"
+                  },
+                  "id":{
+                     "device":32902,
+                     "vendor":28672
+                  },
+                  "function":0,
+                  "regions":[
+   
+                  ]
+               },
+               {
+                  "bus":0,
+                  "qdev_id":"",
+                  "slot":1,
+                  "class_info":{
+                     "class":257,
+                     "desc":"IDE controller"
+                  },
+                  "id":{
+                     "device":32902,
+                     "vendor":28688
+                  },
+                  "function":1,
+                  "regions":[
+                     {
+                        "bar":4,
+                        "size":16,
+                        "address":49152,
+                        "type":"io"
+                     }
+                  ]
+               },
+               {
+                  "bus":0,
+                  "qdev_id":"",
+                  "slot":2,
+                  "class_info":{
+                     "class":768,
+                     "desc":"VGA controller"
+                  },
+                  "id":{
+                     "device":4115,
+                     "vendor":184
+                  },
+                  "function":0,
+                  "regions":[
+                     {
+                        "prefetch":true,
+                        "mem_type_64":false,
+                        "bar":0,
+                        "size":33554432,
+                        "address":4026531840,
+                        "type":"memory"
+                     },
+                     {
+                        "prefetch":false,
+                        "mem_type_64":false,
+                        "bar":1,
+                        "size":4096,
+                        "address":4060086272,
+                        "type":"memory"
+                     },
+                     {
+                        "prefetch":false,
+                        "mem_type_64":false,
+                        "bar":6,
+                        "size":65536,
+                        "address":-1,
+                        "type":"memory"
+                     }
+                  ]
+               },
+               {
+                  "bus":0,
+                  "qdev_id":"",
+                  "irq":11,
+                  "slot":4,
+                  "class_info":{
+                     "class":1280,
+                     "desc":"RAM controller"
+                  },
+                  "id":{
+                     "device":6900,
+                     "vendor":4098
+                  },
+                  "function":0,
+                  "regions":[
+                     {
+                        "bar":0,
+                        "size":32,
+                        "address":49280,
+                        "type":"io"
+                     }
+                  ]
+               }
+            ]
+         }
+      ]
+   }
+
+Note: This example has been shortened as the real response is too long.
+
+EQMP
+
+SQMP
+query-kvm
+---------
+
+Show KVM information.
+
+Return a json-object with the following information:
+
+- "enabled": true if KVM support is enabled, false otherwise (json-bool)
+- "present": true if QEMU has KVM support, false otherwise (json-bool)
+
+Example:
+
+-> { "execute": "query-kvm" }
+<- { "return": { "enabled": true, "present": true } }
+
+EQMP
+
+SQMP
+query-status
+------------
+
+Return a json-object with the following information:
+
+- "running": true if the VM is running, or false if it is paused (json-bool)
+- "singlestep": true if the VM is in single step mode,
+                false otherwise (json-bool)
+
+Example:
+
+-> { "execute": "query-status" }
+<- { "return": { "running": true, "singlestep": false } }
+
+EQMP
+
+SQMP
+query-mice
+----------
+
+Show VM mice information.
+
+Each mouse is represented by a json-object, the returned value is a json-array
+of all mice.
+
+The mouse json-object contains the following:
+
+- "name": mouse's name (json-string)
+- "index": mouse's index (json-int)
+- "current": true if this mouse is receiving events, false otherwise (json-bool)
+- "absolute": true if the mouse generates absolute input events (json-bool)
+
+Example:
+
+-> { "execute": "query-mice" }
+<- {
+      "return":[
+         {
+            "name":"QEMU Microsoft Mouse",
+            "index":0,
+            "current":false,
+            "absolute":false
+         },
+         {
+            "name":"QEMU PS/2 Mouse",
+            "index":1,
+            "current":true,
+            "absolute":true
+         }
+      ]
+   }
+
+EQMP
+
+SQMP
+query-vnc
+---------
+
+Show VNC server information.
+
+Return a json-object with server information. Connected clients are returned
+as a json-array of json-objects.
+
+The main json-object contains the following:
+
+- "enabled": true or false (json-bool)
+- "host": server's IP address (json-string)
+- "family": address family (json-string)
+         - Possible values: "ipv4", "ipv6", "unix", "unknown"
+- "service": server's port number (json-string)
+- "auth": authentication method (json-string)
+         - Possible values: "invalid", "none", "ra2", "ra2ne", "sasl", "tight",
+                            "tls", "ultra", "unknown", "vencrypt", "vencrypt",
+                            "vencrypt+plain", "vencrypt+tls+none",
+                            "vencrypt+tls+plain", "vencrypt+tls+sasl",
+                            "vencrypt+tls+vnc", "vencrypt+x509+none",
+                            "vencrypt+x509+plain", "vencrypt+x509+sasl",
+                            "vencrypt+x509+vnc", "vnc"
+- "clients": a json-array of all connected clients
+
+Clients are described by a json-object, each one contain the following:
+
+- "host": client's IP address (json-string)
+- "family": address family (json-string)
+         - Possible values: "ipv4", "ipv6", "unix", "unknown"
+- "service": client's port number (json-string)
+- "x509_dname": TLS dname (json-string, optional)
+- "sasl_username": SASL username (json-string, optional)
+
+Example:
+
+-> { "execute": "query-vnc" }
+<- {
+      "return":{
+         "enabled":true,
+         "host":"0.0.0.0",
+         "service":"50402",
+         "auth":"vnc",
+         "family":"ipv4",
+         "clients":[
+            {
+               "host":"127.0.0.1",
+               "service":"50401",
+               "family":"ipv4"
+            }
+         ]
+      }
+   }
+
+EQMP
+
+SQMP
+query-spice
+-----------
+
+Show SPICE server information.
+
+Return a json-object with server information. Connected clients are returned
+as a json-array of json-objects.
+
+The main json-object contains the following:
+
+- "enabled": true or false (json-bool)
+- "host": server's IP address (json-string)
+- "port": server's port number (json-int, optional)
+- "tls-port": server's port number (json-int, optional)
+- "auth": authentication method (json-string)
+         - Possible values: "none", "spice"
+- "channels": a json-array of all active channels clients
+
+Channels are described by a json-object, each one contain the following:
+
+- "host": client's IP address (json-string)
+- "family": address family (json-string)
+         - Possible values: "ipv4", "ipv6", "unix", "unknown"
+- "port": client's port number (json-string)
+- "connection-id": spice connection id.  All channels with the same id
+                   belong to the same spice session (json-int)
+- "channel-type": channel type.  "1" is the main control channel, filter for
+                  this one if you want track spice sessions only (json-int)
+- "channel-id": channel id.  Usually "0", might be different needed when
+                multiple channels of the same type exist, such as multiple
+                display channels in a multihead setup (json-int)
+- "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+-> { "execute": "query-spice" }
+<- {
+      "return": {
+         "enabled": true,
+         "auth": "spice",
+         "port": 5920,
+         "tls-port": 5921,
+         "host": "0.0.0.0",
+         "channels": [
+            {
+               "port": "54924",
+               "family": "ipv4",
+               "channel-type": 1,
+               "connection-id": 1804289383,
+               "host": "127.0.0.1",
+               "channel-id": 0,
+               "tls": true
+            },
+            {
+               "port": "36710",
+               "family": "ipv4",
+               "channel-type": 4,
+               "connection-id": 1804289383,
+               "host": "127.0.0.1",
+               "channel-id": 0,
+               "tls": false
+            },
+            [ ... more channels follow ... ]
+         ]
+      }
+   }
+
+EQMP
+
+SQMP
+query-name
+----------
+
+Show VM name.
+
+Return a json-object with the following information:
+
+- "name": VM's name (json-string, optional)
+
+Example:
+
+-> { "execute": "query-name" }
+<- { "return": { "name": "qemu-name" } }
+
+EQMP
+
+SQMP
+query-uuid
+----------
+
+Show VM UUID.
+
+Return a json-object with the following information:
+
+- "UUID": Universally Unique Identifier (json-string)
+
+Example:
+
+-> { "execute": "query-uuid" }
+<- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
+
+EQMP
+
+SQMP
+query-migrate
+-------------
+
+Migration status.
+
+Return a json-object. If migration is active there will be another json-object
+with RAM migration status and if block migration is active another one with
+block migration status.
+
+The main json-object contains the following:
+
+- "status": migration status (json-string)
+     - Possible values: "active", "completed", "failed", "cancelled"
+- "ram": only present if "status" is "active", it is a json-object with the
+  following RAM information (in bytes):
+         - "transferred": amount transferred (json-int)
+         - "remaining": amount remaining (json-int)
+         - "total": total (json-int)
+- "disk": only present if "status" is "active" and it is a block migration,
+  it is a json-object with the following disk information (in bytes):
+         - "transferred": amount transferred (json-int)
+         - "remaining": amount remaining (json-int)
+         - "total": total (json-int)
+
+Examples:
+
+1. Before the first migration
+
+-> { "execute": "query-migrate" }
+<- { "return": {} }
+
+2. Migration is done and has succeeded
+
+-> { "execute": "query-migrate" }
+<- { "return": { "status": "completed" } }
+
+3. Migration is done and has failed
+
+-> { "execute": "query-migrate" }
+<- { "return": { "status": "failed" } }
+
+4. Migration is being performed and is not a block migration:
+
+-> { "execute": "query-migrate" }
+<- {
+      "return":{
+         "status":"active",
+         "ram":{
+            "transferred":123,
+            "remaining":123,
+            "total":246
+         }
+      }
+   }
+
+5. Migration is being performed and is a block migration:
+
+-> { "execute": "query-migrate" }
+<- {
+      "return":{
+         "status":"active",
+         "ram":{
+            "total":1057024,
+            "remaining":1053304,
+            "transferred":3720
+         },
+         "disk":{
+            "total":20971520,
+            "remaining":20880384,
+            "transferred":91136
+         }
+      }
+   }
+
+EQMP
+
+SQMP
+query-balloon
+-------------
+
+Show balloon information.
+
+Make an asynchronous request for balloon info. When the request completes a
+json-object will be returned containing the following data:
+
+- "actual": current balloon value in bytes (json-int)
+- "mem_swapped_in": Amount of memory swapped in bytes (json-int, optional)
+- "mem_swapped_out": Amount of memory swapped out in bytes (json-int, optional)
+- "major_page_faults": Number of major faults (json-int, optional)
+- "minor_page_faults": Number of minor faults (json-int, optional)
+- "free_mem": Total amount of free and unused memory in
+              bytes (json-int, optional)
+- "total_mem": Total amount of available memory in bytes (json-int, optional)
+
+Example:
+
+-> { "execute": "query-balloon" }
+<- {
+      "return":{
+         "actual":1073741824,
+         "mem_swapped_in":0,
+         "mem_swapped_out":0,
+         "major_page_faults":142,
+         "minor_page_faults":239245,
+         "free_mem":1014185984,
+         "total_mem":1044668416
+      }
+   }
+
+EQMP
+
diff --git a/qemu-0.15.x/qobject.h b/qemu-0.15.x/qobject.h
new file mode 100644
index 0000000..d42386d
--- /dev/null
+++ b/qemu-0.15.x/qobject.h
@@ -0,0 +1,112 @@
+/*
+ * QEMU Object Model.
+ *
+ * Based on ideas by Avi Kivity <avi at redhat.com>
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ * QObject Reference Counts Terminology
+ * ------------------------------------
+ *
+ *  - Returning references: A function that returns an object may
+ *  return it as either a weak or a strong reference.  If the reference
+ *  is strong, you are responsible for calling QDECREF() on the reference
+ *  when you are done.
+ *
+ *  If the reference is weak, the owner of the reference may free it at
+ *  any time in the future.  Before storing the reference anywhere, you
+ *  should call QINCREF() to make the reference strong.
+ *
+ *  - Transferring ownership: when you transfer ownership of a reference
+ *  by calling a function, you are no longer responsible for calling
+ *  QDECREF() when the reference is no longer needed.  In other words,
+ *  when the function returns you must behave as if the reference to the
+ *  passed object was weak.
+ */
+#ifndef QOBJECT_H
+#define QOBJECT_H
+
+#include <stddef.h>
+#include <assert.h>
+
+typedef enum {
+    QTYPE_NONE,
+    QTYPE_QINT,
+    QTYPE_QSTRING,
+    QTYPE_QDICT,
+    QTYPE_QLIST,
+    QTYPE_QFLOAT,
+    QTYPE_QBOOL,
+    QTYPE_QERROR,
+} qtype_code;
+
+struct QObject;
+
+typedef struct QType {
+    qtype_code code;
+    void (*destroy)(struct QObject *);
+} QType;
+
+typedef struct QObject {
+    const QType *type;
+    size_t refcnt;
+} QObject;
+
+/* Objects definitions must include this */
+#define QObject_HEAD  \
+    QObject base
+
+/* Get the 'base' part of an object */
+#define QOBJECT(obj) (&(obj)->base)
+
+/* High-level interface for qobject_incref() */
+#define QINCREF(obj)      \
+    qobject_incref(QOBJECT(obj))
+
+/* High-level interface for qobject_decref() */
+#define QDECREF(obj)              \
+    qobject_decref(QOBJECT(obj))
+
+/* Initialize an object to default values */
+#define QOBJECT_INIT(obj, qtype_type)   \
+    obj->base.refcnt = 1;               \
+    obj->base.type   = qtype_type
+
+/**
+ * qobject_incref(): Increment QObject's reference count
+ */
+static inline void qobject_incref(QObject *obj)
+{
+    if (obj)
+        obj->refcnt++;
+}
+
+/**
+ * qobject_decref(): Decrement QObject's reference count, deallocate
+ * when it reaches zero
+ */
+static inline void qobject_decref(QObject *obj)
+{
+    if (obj && --obj->refcnt == 0) {
+        assert(obj->type != NULL);
+        assert(obj->type->destroy != NULL);
+        obj->type->destroy(obj);
+    }
+}
+
+/**
+ * qobject_type(): Return the QObject's type
+ */
+static inline qtype_code qobject_type(const QObject *obj)
+{
+    assert(obj->type != NULL);
+    return obj->type->code;
+}
+
+#endif /* QOBJECT_H */
diff --git a/qemu-0.15.x/qstring.c b/qemu-0.15.x/qstring.c
new file mode 100644
index 0000000..4e2ba08
--- /dev/null
+++ b/qemu-0.15.x/qstring.c
@@ -0,0 +1,141 @@
+/*
+ * QString Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qobject.h"
+#include "qstring.h"
+#include "qemu-common.h"
+
+static void qstring_destroy_obj(QObject *obj);
+
+static const QType qstring_type = {
+    .code = QTYPE_QSTRING,
+    .destroy = qstring_destroy_obj,
+};
+
+/**
+ * qstring_new(): Create a new empty QString
+ *
+ * Return strong reference.
+ */
+QString *qstring_new(void)
+{
+    return qstring_from_str("");
+}
+
+/**
+ * qstring_from_substr(): Create a new QString from a C string substring
+ *
+ * Return string reference
+ */
+QString *qstring_from_substr(const char *str, int start, int end)
+{
+    QString *qstring;
+
+    qstring = qemu_malloc(sizeof(*qstring));
+
+    qstring->length = end - start + 1;
+    qstring->capacity = qstring->length;
+
+    qstring->string = qemu_malloc(qstring->capacity + 1);
+    memcpy(qstring->string, str + start, qstring->length);
+    qstring->string[qstring->length] = 0;
+
+    QOBJECT_INIT(qstring, &qstring_type);
+
+    return qstring;
+}
+
+/**
+ * qstring_from_str(): Create a new QString from a regular C string
+ *
+ * Return strong reference.
+ */
+QString *qstring_from_str(const char *str)
+{
+    return qstring_from_substr(str, 0, strlen(str) - 1);
+}
+
+static void capacity_increase(QString *qstring, size_t len)
+{
+    if (qstring->capacity < (qstring->length + len)) {
+        qstring->capacity += len;
+        qstring->capacity *= 2; /* use exponential growth */
+
+        qstring->string = qemu_realloc(qstring->string, qstring->capacity + 1);
+    }
+}
+
+/* qstring_append(): Append a C string to a QString
+ */
+void qstring_append(QString *qstring, const char *str)
+{
+    size_t len = strlen(str);
+
+    capacity_increase(qstring, len);
+    memcpy(qstring->string + qstring->length, str, len);
+    qstring->length += len;
+    qstring->string[qstring->length] = 0;
+}
+
+void qstring_append_int(QString *qstring, int64_t value)
+{
+    char num[32];
+
+    snprintf(num, sizeof(num), "%" PRId64, value);
+    qstring_append(qstring, num);
+}
+
+/**
+ * qstring_append_chr(): Append a C char to a QString
+ */
+void qstring_append_chr(QString *qstring, int c)
+{
+    capacity_increase(qstring, 1);
+    qstring->string[qstring->length++] = c;
+    qstring->string[qstring->length] = 0;
+}
+
+/**
+ * qobject_to_qstring(): Convert a QObject to a QString
+ */
+QString *qobject_to_qstring(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QSTRING)
+        return NULL;
+
+    return container_of(obj, QString, base);
+}
+
+/**
+ * qstring_get_str(): Return a pointer to the stored string
+ *
+ * NOTE: Should be used with caution, if the object is deallocated
+ * this pointer becomes invalid.
+ */
+const char *qstring_get_str(const QString *qstring)
+{
+    return qstring->string;
+}
+
+/**
+ * qstring_destroy_obj(): Free all memory allocated by a QString
+ * object
+ */
+static void qstring_destroy_obj(QObject *obj)
+{
+    QString *qs;
+
+    assert(obj != NULL);
+    qs = qobject_to_qstring(obj);
+    qemu_free(qs->string);
+    qemu_free(qs);
+}
diff --git a/qemu-0.15.x/qstring.h b/qemu-0.15.x/qstring.h
new file mode 100644
index 0000000..84ccd96
--- /dev/null
+++ b/qemu-0.15.x/qstring.h
@@ -0,0 +1,35 @@
+/*
+ * QString Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QSTRING_H
+#define QSTRING_H
+
+#include <stdint.h>
+#include "qobject.h"
+
+typedef struct QString {
+    QObject_HEAD;
+    char *string;
+    size_t length;
+    size_t capacity;
+} QString;
+
+QString *qstring_new(void);
+QString *qstring_from_str(const char *str);
+QString *qstring_from_substr(const char *str, int start, int end);
+const char *qstring_get_str(const QString *qstring);
+void qstring_append_int(QString *qstring, int64_t value);
+void qstring_append(QString *qstring, const char *str);
+void qstring_append_chr(QString *qstring, int c);
+QString *qobject_to_qstring(const QObject *obj);
+
+#endif /* QSTRING_H */
diff --git a/qemu-0.15.x/range.h b/qemu-0.15.x/range.h
new file mode 100644
index 0000000..3502372
--- /dev/null
+++ b/qemu-0.15.x/range.h
@@ -0,0 +1,29 @@
+#ifndef QEMU_RANGE_H
+#define QEMU_RANGE_H
+
+/* Get last byte of a range from offset + length.
+ * Undefined for ranges that wrap around 0. */
+static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
+{
+    return offset + len - 1;
+}
+
+/* Check whether a given range covers a given byte. */
+static inline int range_covers_byte(uint64_t offset, uint64_t len,
+                                    uint64_t byte)
+{
+    return offset <= byte && byte <= range_get_last(offset, len);
+}
+
+/* Check whether 2 given ranges overlap.
+ * Undefined if ranges that wrap around 0. */
+static inline int ranges_overlap(uint64_t first1, uint64_t len1,
+                                 uint64_t first2, uint64_t len2)
+{
+    uint64_t last1 = range_get_last(first1, len1);
+    uint64_t last2 = range_get_last(first2, len2);
+
+    return !(last2 < first1 || last1 < first2);
+}
+
+#endif
diff --git a/qemu-0.15.x/readline.c b/qemu-0.15.x/readline.c
new file mode 100644
index 0000000..92f9cd1
--- /dev/null
+++ b/qemu-0.15.x/readline.c
@@ -0,0 +1,476 @@
+/*
+ * 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 "readline.h"
+#include "monitor.h"
+
+#define IS_NORM 0
+#define IS_ESC  1
+#define IS_CSI  2
+
+#undef printf
+#define printf do_not_use_printf
+
+void readline_show_prompt(ReadLineState *rs)
+{
+    monitor_printf(rs->mon, "%s", rs->prompt);
+    monitor_flush(rs->mon);
+    rs->last_cmd_buf_index = 0;
+    rs->last_cmd_buf_size = 0;
+    rs->esc_state = IS_NORM;
+}
+
+/* update the displayed command line */
+static void readline_update(ReadLineState *rs)
+{
+    int i, delta, len;
+
+    if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
+        memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
+        for(i = 0; i < rs->last_cmd_buf_index; i++) {
+            monitor_printf(rs->mon, "\033[D");
+        }
+        rs->cmd_buf[rs->cmd_buf_size] = '\0';
+        if (rs->read_password) {
+            len = strlen(rs->cmd_buf);
+            for(i = 0; i < len; i++)
+                monitor_printf(rs->mon, "*");
+        } else {
+            monitor_printf(rs->mon, "%s", rs->cmd_buf);
+        }
+        monitor_printf(rs->mon, "\033[K");
+        memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
+        rs->last_cmd_buf_size = rs->cmd_buf_size;
+        rs->last_cmd_buf_index = rs->cmd_buf_size;
+    }
+    if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
+        delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
+        if (delta > 0) {
+            for(i = 0;i < delta; i++) {
+                monitor_printf(rs->mon, "\033[C");
+            }
+        } else {
+            delta = -delta;
+            for(i = 0;i < delta; i++) {
+                monitor_printf(rs->mon, "\033[D");
+            }
+        }
+        rs->last_cmd_buf_index = rs->cmd_buf_index;
+    }
+    monitor_flush(rs->mon);
+}
+
+static void readline_insert_char(ReadLineState *rs, int ch)
+{
+    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf[rs->cmd_buf_index] = ch;
+        rs->cmd_buf_size++;
+        rs->cmd_buf_index++;
+    }
+}
+
+static void readline_backward_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index > 0) {
+        rs->cmd_buf_index--;
+    }
+}
+
+static void readline_forward_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        rs->cmd_buf_index++;
+    }
+}
+
+static void readline_delete_char(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf_size - rs->cmd_buf_index - 1);
+        rs->cmd_buf_size--;
+    }
+}
+
+static void readline_backspace(ReadLineState *rs)
+{
+    if (rs->cmd_buf_index > 0) {
+        readline_backward_char(rs);
+        readline_delete_char(rs);
+    }
+}
+
+static void readline_backword(ReadLineState *rs)
+{
+    int start;
+
+    if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
+        return;
+    }
+
+    start = rs->cmd_buf_index - 1;
+
+    /* find first word (backwards) */
+    while (start > 0) {
+        if (!qemu_isspace(rs->cmd_buf[start])) {
+            break;
+        }
+
+        --start;
+    }
+
+    /* find first space (backwards) */
+    while (start > 0) {
+        if (qemu_isspace(rs->cmd_buf[start])) {
+            ++start;
+            break;
+        }
+
+        --start;
+    }
+
+    /* remove word */
+    if (start < rs->cmd_buf_index) {
+        memmove(rs->cmd_buf + start,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf_size -= rs->cmd_buf_index - start;
+        rs->cmd_buf_index = start;
+    }
+}
+
+static void readline_bol(ReadLineState *rs)
+{
+    rs->cmd_buf_index = 0;
+}
+
+static void readline_eol(ReadLineState *rs)
+{
+    rs->cmd_buf_index = rs->cmd_buf_size;
+}
+
+static void readline_up_char(ReadLineState *rs)
+{
+    int idx;
+
+    if (rs->hist_entry == 0)
+	return;
+    if (rs->hist_entry == -1) {
+	/* Find latest entry */
+	for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	    if (rs->history[idx] == NULL)
+		break;
+	}
+	rs->hist_entry = idx;
+    }
+    rs->hist_entry--;
+    if (rs->hist_entry >= 0) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
+	rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
+    }
+}
+
+static void readline_down_char(ReadLineState *rs)
+{
+    if (rs->hist_entry == -1)
+        return;
+    if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
+        rs->history[++rs->hist_entry] != NULL) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
+    } else {
+        rs->cmd_buf[0] = 0;
+	rs->hist_entry = -1;
+    }
+    rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
+}
+
+static void readline_hist_add(ReadLineState *rs, const char *cmdline)
+{
+    char *hist_entry, *new_entry;
+    int idx;
+
+    if (cmdline[0] == '\0')
+	return;
+    new_entry = NULL;
+    if (rs->hist_entry != -1) {
+	/* We were editing an existing history entry: replace it */
+	hist_entry = rs->history[rs->hist_entry];
+	idx = rs->hist_entry;
+	if (strcmp(hist_entry, cmdline) == 0) {
+	    goto same_entry;
+	}
+    }
+    /* Search cmdline in history buffers */
+    for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	hist_entry = rs->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(&rs->history[idx], &rs->history[idx + 1],
+		    (READLINE_MAX_CMDS - idx + 1) * sizeof(char *));
+	    rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	    for (; idx < READLINE_MAX_CMDS; idx++) {
+		if (rs->history[idx] == NULL)
+		    break;
+	    }
+	    break;
+	}
+    }
+    if (idx == READLINE_MAX_CMDS) {
+	/* Need to get one free slot */
+	free(rs->history[0]);
+	memcpy(rs->history, &rs->history[1],
+	       (READLINE_MAX_CMDS - 1) * sizeof(char *));
+	rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	idx = READLINE_MAX_CMDS - 1;
+    }
+    if (new_entry == NULL)
+	new_entry = strdup(cmdline);
+    rs->history[idx] = new_entry;
+    rs->hist_entry = -1;
+}
+
+/* completion support */
+
+void readline_add_completion(ReadLineState *rs, const char *str)
+{
+    if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
+        rs->completions[rs->nb_completions++] = qemu_strdup(str);
+    }
+}
+
+void readline_set_completion_index(ReadLineState *rs, int index)
+{
+    rs->completion_index = index;
+}
+
+static void readline_completion(ReadLineState *rs)
+{
+    Monitor *mon = cur_mon;
+    int len, i, j, max_width, nb_cols, max_prefix;
+    char *cmdline;
+
+    rs->nb_completions = 0;
+
+    cmdline = qemu_malloc(rs->cmd_buf_index + 1);
+    memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
+    cmdline[rs->cmd_buf_index] = '\0';
+    rs->completion_finder(cmdline);
+    qemu_free(cmdline);
+
+    /* no completion found */
+    if (rs->nb_completions <= 0)
+        return;
+    if (rs->nb_completions == 1) {
+        len = strlen(rs->completions[0]);
+        for(i = rs->completion_index; i < len; i++) {
+            readline_insert_char(rs, rs->completions[0][i]);
+        }
+        /* extra space for next argument. XXX: make it more generic */
+        if (len > 0 && rs->completions[0][len - 1] != '/')
+            readline_insert_char(rs, ' ');
+    } else {
+        monitor_printf(mon, "\n");
+        max_width = 0;
+        max_prefix = 0;	
+        for(i = 0; i < rs->nb_completions; i++) {
+            len = strlen(rs->completions[i]);
+            if (i==0) {
+                max_prefix = len;
+            } else {
+                if (len < max_prefix)
+                    max_prefix = len;
+                for(j=0; j<max_prefix; j++) {
+                    if (rs->completions[i][j] != rs->completions[0][j])
+                        max_prefix = j;
+                }
+            }
+            if (len > max_width)
+                max_width = len;
+        }
+        if (max_prefix > 0) 
+            for(i = rs->completion_index; i < max_prefix; i++) {
+                readline_insert_char(rs, rs->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 < rs->nb_completions; i++) {
+            monitor_printf(rs->mon, "%-*s", max_width, rs->completions[i]);
+            if (++j == nb_cols || i == (rs->nb_completions - 1)) {
+                monitor_printf(rs->mon, "\n");
+                j = 0;
+            }
+        }
+        readline_show_prompt(rs);
+    }
+}
+
+/* return true if command handled */
+void readline_handle_byte(ReadLineState *rs, int ch)
+{
+    switch(rs->esc_state) {
+    case IS_NORM:
+        switch(ch) {
+        case 1:
+            readline_bol(rs);
+            break;
+        case 4:
+            readline_delete_char(rs);
+            break;
+        case 5:
+            readline_eol(rs);
+            break;
+        case 9:
+            readline_completion(rs);
+            break;
+        case 10:
+        case 13:
+            rs->cmd_buf[rs->cmd_buf_size] = '\0';
+            if (!rs->read_password)
+                readline_hist_add(rs, rs->cmd_buf);
+            monitor_printf(rs->mon, "\n");
+            rs->cmd_buf_index = 0;
+            rs->cmd_buf_size = 0;
+            rs->last_cmd_buf_index = 0;
+            rs->last_cmd_buf_size = 0;
+            rs->readline_func(rs->mon, rs->cmd_buf, rs->readline_opaque);
+            break;
+        case 23:
+            /* ^W */
+            readline_backword(rs);
+            break;
+        case 27:
+            rs->esc_state = IS_ESC;
+            break;
+        case 127:
+        case 8:
+            readline_backspace(rs);
+            break;
+	case 155:
+            rs->esc_state = IS_CSI;
+	    break;
+        default:
+            if (ch >= 32) {
+                readline_insert_char(rs, ch);
+            }
+            break;
+        }
+        break;
+    case IS_ESC:
+        if (ch == '[') {
+            rs->esc_state = IS_CSI;
+            rs->esc_param = 0;
+        } else {
+            rs->esc_state = IS_NORM;
+        }
+        break;
+    case IS_CSI:
+        switch(ch) {
+	case 'A':
+	case 'F':
+	    readline_up_char(rs);
+	    break;
+	case 'B':
+	case 'E':
+	    readline_down_char(rs);
+	    break;
+        case 'D':
+            readline_backward_char(rs);
+            break;
+        case 'C':
+            readline_forward_char(rs);
+            break;
+        case '0' ... '9':
+            rs->esc_param = rs->esc_param * 10 + (ch - '0');
+            goto the_end;
+        case '~':
+            switch(rs->esc_param) {
+            case 1:
+                readline_bol(rs);
+                break;
+            case 3:
+                readline_delete_char(rs);
+                break;
+            case 4:
+                readline_eol(rs);
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+        rs->esc_state = IS_NORM;
+    the_end:
+        break;
+    }
+    readline_update(rs);
+}
+
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
+                    ReadLineFunc *readline_func, void *opaque)
+{
+    pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
+    rs->readline_func = readline_func;
+    rs->readline_opaque = opaque;
+    rs->read_password = read_password;
+    readline_restart(rs);
+}
+
+void readline_restart(ReadLineState *rs)
+{
+    rs->cmd_buf_index = 0;
+    rs->cmd_buf_size = 0;
+}
+
+const char *readline_get_history(ReadLineState *rs, unsigned int index)
+{
+    if (index >= READLINE_MAX_CMDS)
+        return NULL;
+    return rs->history[index];
+}
+
+ReadLineState *readline_init(Monitor *mon,
+                             ReadLineCompletionFunc *completion_finder)
+{
+    ReadLineState *rs = qemu_mallocz(sizeof(*rs));
+
+    rs->hist_entry = -1;
+    rs->mon = mon;
+    rs->completion_finder = completion_finder;
+
+    return rs;
+}
diff --git a/qemu-0.15.x/readline.h b/qemu-0.15.x/readline.h
new file mode 100644
index 0000000..fc9806e
--- /dev/null
+++ b/qemu-0.15.x/readline.h
@@ -0,0 +1,55 @@
+#ifndef READLINE_H
+#define READLINE_H
+
+#include "qemu-common.h"
+
+#define READLINE_CMD_BUF_SIZE 4095
+#define READLINE_MAX_CMDS 64
+#define READLINE_MAX_COMPLETIONS 256
+
+typedef void ReadLineFunc(Monitor *mon, const char *str, void *opaque);
+typedef void ReadLineCompletionFunc(const char *cmdline);
+
+typedef struct ReadLineState {
+    char cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int cmd_buf_index;
+    int cmd_buf_size;
+
+    char last_cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int last_cmd_buf_index;
+    int last_cmd_buf_size;
+
+    int esc_state;
+    int esc_param;
+
+    char *history[READLINE_MAX_CMDS];
+    int hist_entry;
+
+    ReadLineCompletionFunc *completion_finder;
+    char *completions[READLINE_MAX_COMPLETIONS];
+    int nb_completions;
+    int completion_index;
+
+    ReadLineFunc *readline_func;
+    void *readline_opaque;
+    int read_password;
+    char prompt[256];
+    Monitor *mon;
+} ReadLineState;
+
+void readline_add_completion(ReadLineState *rs, const char *str);
+void readline_set_completion_index(ReadLineState *rs, int completion_index);
+
+const char *readline_get_history(ReadLineState *rs, unsigned int index);
+
+void readline_handle_byte(ReadLineState *rs, int ch);
+
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
+                    ReadLineFunc *readline_func, void *opaque);
+void readline_restart(ReadLineState *rs);
+void readline_show_prompt(ReadLineState *rs);
+
+ReadLineState *readline_init(Monitor *mon,
+                             ReadLineCompletionFunc *completion_finder);
+
+#endif /* !READLINE_H */
diff --git a/qemu-0.15.x/roms/SLOF/.gitignore b/qemu-0.15.x/roms/SLOF/.gitignore
new file mode 100644
index 0000000..861289b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/.gitignore
@@ -0,0 +1,6 @@
+*.o
+*.fsi
+*.a
+*.dep
+*.depend
+
diff --git a/qemu-0.15.x/roms/SLOF/INSTALL b/qemu-0.15.x/roms/SLOF/INSTALL
new file mode 100644
index 0000000..6fcdd31
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/INSTALL
@@ -0,0 +1,93 @@
+Slimline Open Firmware - SLOF
+
+Copyright (C) 2005, 2008 IBM Corporation
+
+
+BUILD
+===============================================================================
+
+ To build SLOF you need:
+  - Recent GNU tools, configured for powerpc64-linux
+    - GCC: 3.3.3 and newer are known to work
+    - Binutils: use a version as new as possible
+    - Subversion
+
+  - set the CROSS variable
+    - something like export CROSS="powerpc64-unknown-linux-gnu-"
+      when using a cross compiler
+    or
+    - export CROSS=""
+      when using a native compiler
+
+  - four more files to build a bootable image:
+    - libipmi.oco
+    - takeover.oco
+    - i2c_bmc.oco
+    - ipmi_oem.oco
+    these files are also provided through developerworks and have to be
+    also downloaded just like the SLOF source code
+
+  - starting with the SLOF release JX-1.6.0-0 it is necessary to
+    download a x86 emulator which is used to execute the BIOS
+    of VGA card; to download the x86 emulator following steps are
+    required:
+    - cd other-licence/x86emu/
+    - ./x86emu_download.sh # this downloads the x86 emulator sources
+    - cd -
+
+  - make js2x
+
+INSTALL
+===============================================================================
+
+ Detailed information about how to use SLOF on JS20 and JS21 can be found in
+ the document FlashingSLOF.pdf
+
+ The JS20 and JS21 blades both have 2 "flashsides". They have a 8MB flash part
+ which is divided into a 4MB "temporary" side and a 4MB "permanent" side.
+
+ The temporary side is the flashside used for the normal operation and the
+ permanent side is used as a backup if the temporary should ever fail.
+
+ Therefore it is important that the permanent flash side is not changed so
+ that if ever required the original firmware can be restored.
+
+ SLOF usually warns or in most cases does not easily allow to overwrite the
+ permanent side.
+
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !                                                           !
+ ! WITH THE FOLLOWING STEPS YOU MIGHT DESTROY YOUR FIRMWARE  !
+ ! IMAGE AND LOOSE YOUR WARRANTY !                           !
+ ! YOU MAY NEED TO CALL SERVICE, IF THE FIRMWARE IMAGE IS    !
+ ! DESTROYED !                                               !
+ !                                                           !
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+UNINSTALL
+===============================================================================
+
+ If you want to boot the original firmware again, you need to boot the blade 
+ from the management module. If auto-boot is enabled you have to press "s"
+ to reach the firmware prompt.
+ On the SLOF command line, type:
+
+  0 > other-firmware
+
+ and it should get you back to running the original firmware. To permanently 
+ get it back, after booting Linux from there, type
+
+  $ update_flash -r
+  $ halt
+ 
+ You will boot on the PERM side. To boot from the TEMP side again, you need to
+ restart the Blade System MGMT Processor.
+
+    Following steps are needed on
+        Management Module -> Blade Tasks -> Power/Restart
+        
+        Power Off Blade
+        Restart Blade System Mgmt Processor 
+        Power On Blade
diff --git a/qemu-0.15.x/roms/SLOF/LICENSE b/qemu-0.15.x/roms/SLOF/LICENSE
new file mode 100644
index 0000000..4830faf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/LICENSE
@@ -0,0 +1,8 @@
+Copyright (c) 2004, 2008 IBM Corporation
+All rights reserved.
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+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.
+Neither the name of IBM 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 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 THE COPYRIGHT OWNER 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.
diff --git a/qemu-0.15.x/roms/SLOF/Makefile b/qemu-0.15.x/roms/SLOF/Makefile
new file mode 100644
index 0000000..7567d13
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/Makefile
@@ -0,0 +1,133 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include make.rules
+
+STD_BOARDS = $(shell targets=""; \
+		for a in `echo board-*`; do \
+			if [ -e $$a/config ]; then \
+				targets="$$targets $$a"; \
+			else \
+				cd $$a; \
+				for b in `echo config* | sed -e s/config.//g`; do \
+					if [ "X$$b" != "Xsimics" ]; then \
+						if [ "X$$b" != "X`echo $$a|sed -e s/board-//g`" ]; then \
+							targets="$$targets $$a-$$b"; \
+						else \
+							targets="$$targets $$b"; \
+					fi fi \
+				done; \
+				cd ..; \
+			fi; \
+		done; \
+		echo $$targets | sed -e s/board-//g)
+
+all:
+	@if [ ! -f .target ]; then \
+		echo "Please specify a build target:"; \
+		echo "  $(STD_BOARDS)"; \
+		exit 1; \
+	fi
+	@make `cat .target`
+
+rom:
+	@echo "******* Build $(BOARD) System ********"
+	@echo $(BOARD) > .target
+	@make -C board-$(BOARD)
+	@$(RM) -f .crc_flash
+rw:
+	@echo "******* Build $(BOARD) system (RISCWatch boot) ********"
+	@echo $(BOARD) > .target
+	@make -C board-$(BOARD) l2b
+	@$(RM) -f .crc_flash
+
+$(STD_BOARDS):
+	@echo "******** Building $@ system ********"
+	@if [ -f .target ]; then \
+		if [ `cat .target` != $@ ]; then \
+			echo "Configuration changed - cleaning up first..."; \
+			make distclean; \
+			echo $@ > .target; \
+		fi; \
+	else \
+		echo $@ > .target; \
+	fi
+	@b=`echo $@ | grep "-"`; \
+	if [ -n "$$b" ]; then \
+		subboard=$${b##*-}; \
+		board=$${b%%-*}; \
+		make -C board-$$board SUBBOARD=$$subboard; \
+	else \
+		make -C board-$@; \
+	fi
+	@$(RM) .crc_flash
+
+test_all:
+	@for i in $(STD_BOARDS); do make distclean $$i; done
+
+driver:
+	@echo "******** Building $(BOARD) system ********"
+	@b=`echo $(BOARD) | grep "-"`; \
+	if [ -n "$$b" ]; then \
+		subboard=$${b##*-}; \
+		board=$${b%%-*}; \
+		DRIVER=1 make -C board-$$board SUBBOARD=$$subboard driver; \
+	else \
+		DRIVER=1 make -C board-$(BOARD) driver; \
+	fi
+	@$(RM) -f .crc_flash .boot_xdr.ffs
+
+cli:
+		make -C clients
+
+# Rules for making clean:
+clean_here:
+		rm -f boot_rom.bin .boot_rom.ffs boot_xdr.bin .boot_xdr.ffs
+		rm -f boot_l2-dd2.ad boot_l2b.bin .crc_flash
+
+
+clean:		clean_here
+		@if [ -e .target ]; then \
+			tar=`cat .target`; \
+			b=`echo $$tar | grep "-"`; \
+			if [ -n "$$b" ]; then \
+				subboard=$${b##*-}; \
+				board=$${b%%-*}; \
+				make -C board-$$board SUBBOARD=$$subboard clean; \
+			else \
+				pwd; \
+				make -C board-$$tar clean; \
+			fi \
+		fi
+
+distclean:	clean_here
+		@if [ -e .target ]; then \
+			tar=`cat .target`; \
+			b=`echo $$tar | grep "-"`; \
+			if [ -n "$$b" ]; then \
+				subboard=$${b##*-}; \
+				board=$${b%%-*}; \
+				make -C board-$$board SUBBOARD=$$subboard distclean; \
+			else \
+				make -C board-$$tar distclean; \
+			fi; \
+			rm -f .target; \
+		fi
+
+distclean_all:	clean_here
+		@for dir in board-* ; do \
+			$(MAKE) -C $$dir distclean || exit 1; \
+		done
+		rm -f .target
+
+cli-clean:
+		make -C clients clean
diff --git a/qemu-0.15.x/roms/SLOF/Makefile.gen b/qemu-0.15.x/roms/SLOF/Makefile.gen
new file mode 100644
index 0000000..3c5d116
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/Makefile.gen
@@ -0,0 +1,213 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+MAKEARG = BOARD=$(BOARD) PLATFORM=$(PLATFORM) FLAG=$(FLAG) TARG=$(TARG)
+
+BUILDS  = tools_build romfs_build
+
+include ../make.rules
+
+ifdef DRIVER
+RELEASE=$(shell cat ../VERSION)
+export DRIVER_NAME=$(shell cat ../VERSION | sed -e "s/-/./g" | awk -F . '{ printf("%s%02d%02d%1s%02s",$$1,$$2,$$3,$$4,$$5); }')
+else
+RELEASE="$(USER)@$(HOSTNAME)(private build)"
+export DRIVER_NAME=HEAD
+endif
+
+
+DRVDATE=$(shell date +%Y-%h%d)
+
+FLASH_SIZE_MB = `echo $$[ $(FLASH_SIZE)/1024/1024 ]`
+
+DTB_ROMFS_FLAG ?= 0
+DTB_ROMFS_ADDR ?= 0
+
+llfw_disassembly:
+		make -C $(LLFWBRDDIR) stage1.dis stage2.dis stageS.dis
+
+clients_build:
+		@echo " ====== Building clients ======"
+		make -C ../clients $(MAKEARG)
+
+other_licence_build:
+		make -C ../other-licence $(MAKEARG)
+
+tools_build:
+		make -C ../tools
+
+romfs_build:
+		make -C ../romfs/tools $(MAKEARG)
+
+../build_info.img:
+		@echo "$(CC)" > ../build_info.img
+		@$(CC) -v >> ../build_info.img 2>&1
+		@$(LD) -V >> ../build_info.img 2>&1
+
+../$(SUBBOARD).dtb:
+		@if [ -e dts/$(SUBBOARD).dts ]; then \
+			 dtc -q -I dts -O dtb dts/$(SUBBOARD).dts > $@; \
+		fi
+
+boot_rom.bin boot_xdr.bin: 	$(BUILDS) ../build_info.img ../$(SUBBOARD).dtb
+ifeq ($(DO_COMPRESS),1)
+
+		@echo " ====== Building packed $@ ======"
+			@if [ -e $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs ]; then \
+				cat $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs > ../.boot_rom.ffs; \
+				cat $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).pack.ffs > ../.boot_rom.pack.ffs; \
+			else \
+				cat $(ROMFSBRDDIR)/boot_rom.ffs > ../.boot_rom.ffs; \
+				cat $(ROMFSBRDDIR)/boot_rom.pack.ffs > ../.boot_rom.pack.ffs; \
+			fi
+			@if [ -e $(PCDBRDDIR)/pcdfiles.ffs ]; then \
+				cat $(PCDBRDDIR)/pcdfiles.ffs >> ../.boot_rom.ffs; \
+				cat $(PCDBRDDIR)/pcdfiles.ffs >> ../.boot_rom.pack.ffs; \
+			fi
+
+			@echo "romfs.pack      boot_rom.bin.pack.nv              0             0" >> ../.boot_rom.ffs
+
+			cat $(SLOFBRDDIR)/OF.ffs >> ../.boot_rom.pack.ffs 
+			@echo build_info.img  build_info.img 0 0 >> ../.boot_rom.pack.ffs
+			@if [ -e ../$(SUBBOARD).dtb ]; then \
+				echo dtb $(SUBBOARD).dtb $(DTB_ROMFS_FLAG) \
+						$(DTB_ROMFS_ADDR) >> ../.boot_rom.pack.ffs; \
+			fi;
+			cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) .boot_rom.pack.ffs boot_rom.bin.pack
+			cd .. && ./tools/pknova -q boot_rom.bin.pack boot_rom.bin.pack.nv;    	 
+			cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) .boot_rom.ffs $@ 
+			if [ "$@" = "boot_rom.bin" ]; then \
+				rm ../boot_rom.bin.pack; \
+				rm ../boot_rom.bin.pack.nv; \
+			fi;
+else 
+		@echo " ====== Building $@ ======"
+		        @if [ -e $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs ]; then \
+	 	               cat $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs > ../.boot_rom.ffs; \
+	           	else \
+	            	        cat $(ROMFSBRDDIR)/boot_rom.ffs > ../.boot_rom.ffs; \
+	            	fi
+	           	@if [ -e $(PCDBRDDIR)/pcdfiles.ffs ]; then \
+	             	        cat $(PCDBRDDIR)/pcdfiles.ffs >> ../.boot_rom.ffs; \
+	             	fi
+	             	cat $(SLOFBRDDIR)/OF.ffs >> ../.boot_rom.ffs
+	              	@echo build_info.img  build_info.img 0 0 >> ../.boot_rom.ffs
+	              	@if [ -e ../$(SUBBOARD).dtb ]; then \
+                	        echo dtb $(SUBBOARD).dtb $(DTB_ROMFS_FLAG) \
+                	                        $(DTB_ROMFS_ADDR) >> ../.boot_rom.ffs; \
+                	fi
+	              	@if [ -e slik.elf ]; then				\
+				echo "slik.elf available ...";			\
+                	        echo slik board-$(BOARD)/slik.elf 0 0 >>	\
+					../.boot_rom.ffs;			\
+                	fi
+	              	cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) .boot_rom.ffs $@
+endif
+		cd .. && if [ -f $@.gz ]; then rm -f $@.gz; gzip -9 $@ ; fi
+		rm -f ../.boot_rom.*ffs
+		rm -f ../$(SUBBOARD).dtb
+
+../boot_l2b.bin:	$(BUILDS) ../romfs/copyright.img ../$(SUBBOARD).dtb
+		@if [ -e $(ROMFSBRDDIR)/boot_l2.$(SUBBOARD).ffs ]; then \
+			cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) $(ROMFSBRDDIR)/boot_l2.$(SUBBOARD).ffs boot_l2b.bin; \
+		else \
+			cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) $(ROMFSBRDDIR)/boot_l2.ffs boot_l2b.bin; \
+		fi
+		@if [ -e ../$(SUBBOARD).dtb ]; then \
+			echo dtb $(SUBBOARD).dtb $(DTB_ROMFS_FLAG) \
+					$(DTB_ROMFS_ADDR) >> ../.boot_rom.ffs; \
+		fi
+		rm -f ../$(SUBBOARD).dtb
+
+boot_l2.ad boot_l2-dd2.ad: ../boot_l2b.bin
+		@cd ../tools && ./elf2l2 dd2 ../boot_l2b.bin 0 ../$@
+
+external_flasher: ../boot_rom.bin
+		../tools/make-flasher-image.sh $(FLASH_SIZE) ../boot_rom.bin \
+                        ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin
+
+driver_dirs:
+		@rm -rf ../driver-$(RELEASE)
+		@mkdir -p ../driver-$(RELEASE)/{rom,l2b,disassemblies}
+
+driver_prep:
+		@echo "Building driver "$(RELEASE)" for $(BOARD)"
+
+copy_disassemblies:	llfw_disassembly
+		cp $(LLFWBRDDIR)/stage1.dis  \
+			../driver-$(RELEASE)/disassemblies/$(RELEASE)-stage1.dis
+		cp $(LLFWBRDDIR)/stage2.dis  \
+			../driver-$(RELEASE)/disassemblies/$(RELEASE)-stage2.dis
+		cp $(LLFWBRDDIR)/stageS.dis  \
+			../driver-$(RELEASE)/disassemblies/$(RELEASE)-stageS.dis
+		cp $(LLFWBRDDIR)/meminit.dis  \
+			../driver-$(RELEASE)/disassemblies/$(RELEASE)-meminit.dis
+		@if [ -e ../clients/snk/client.dis ]; then cp ../clients/snk/client.dis \
+			../driver-$(RELEASE)/disassemblies/$(RELEASE)-client.dis; fi
+
+copy_driver:	copy_disassemblies external_flasher
+		mv ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin \
+			../driver-$(RELEASE)/rom/$(RELEASE)-boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin
+		mv ../boot_rom.bin \
+			../driver-$(RELEASE)/rom/$(RELEASE)-boot_rom.bin
+		if [ -e ../boot_l2-dd2.ad ]; then \
+			mv ../boot_l2-dd2.ad \
+			../driver-$(RELEASE)/l2b/; \
+		else \
+			mv ../boot_l2.ad \
+			../driver-$(RELEASE)/l2b/; fi
+		mv ../boot_xdr.bin \
+			../driver-$(RELEASE)/l2b/
+		cp ../VERSION ../driver-$(RELEASE)
+		cd ../driver-$(RELEASE) && md5sum rom/*.bin > md5sum.txt
+
+tar_gz:		copy_driver
+		@cp -a ../driver-$(RELEASE) ../driver-$(RELEASE)-$(DRVDATE)-devel
+		tar czf ../driver-$(RELEASE)-$(DRVDATE)-devel.tar.gz \
+			../driver-$(RELEASE)-$(DRVDATE)-devel > /dev/null 2>&1
+		@rm -rf ../driver-$(RELEASE)-$(DRVDATE)-devel
+		@rm -rf ../driver-$(RELEASE)/disassemblies
+		@mv ../driver-$(RELEASE) ../driver-$(RELEASE)-$(DRVDATE)
+		tar czf ../driver-$(RELEASE)-$(DRVDATE).tar.gz \
+			../driver-$(RELEASE)-$(DRVDATE) > /dev/null  2>&1
+		@rm -rf ../driver-$(RELEASE)-$(DRVDATE)
+
+clean_top:
+		@rm -f ../build_info.img
+		@rm -f ../.crc_flash
+		@rm -f ../$(SUBBOARD).dtb
+
+clean_gen:	clean_top
+		make -C ../romfs/tools BOARD=$(BOARD) clean
+		make -C ../tools clean
+		make -C ../other-licence clean
+		make -C ../clients clean
+		@for dir in $(COMMON_LIBS); do \
+			$(MAKE) -C ../lib/$$dir clean || exit 1; \
+		done
+
+distclean_gen:	clean_top
+		make -C ../romfs/tools BOARD=$(BOARD) distclean
+		make -C ../tools distclean
+		make -C ../other-licence distclean
+		make -C ../clients distclean
+		@for dir in $(COMMON_LIBS); do \
+			$(MAKE) -C ../lib/$$dir distclean || exit 1; \
+		done
+
+common-libs:
+		@echo " ====== Building common libraries ======"
+		$(MAKE) -C $(LIBCMNDIR) $(COMMON_LIBS)
+
+board-libs:
+		$(MAKE) -C lib $(MAKEARG)
diff --git a/qemu-0.15.x/roms/SLOF/README b/qemu-0.15.x/roms/SLOF/README
new file mode 100644
index 0000000..c4fc677
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/README
@@ -0,0 +1,153 @@
+Slimline Open Firmware - SLOF
+
+Copyright (C) 2004, 2008  IBM Corporation
+
+
+Index
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+1.0 Introduction to Open Firmware
+1.1 Build process
+2.0 Extension
+3.0 Limitations
+
+1.0 Introduction to Open Firmware
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The IEEE Standard 1275-1994 [1], Standard for Boot (Initialization Configuration)
+Firmware, Core Requirements and Practices, is the first non-proprietary open
+standard for boot firmware that is usable on different processors and buses.
+Firmware which complies with this standard (also known as Open Firmware)
+includes a processor-independent device interface that allows add-in devices
+to identify itself and to supply a single boot driver that can be used,
+unchanged, on any CPU.  In addition, Open Firmware includes a user interface
+with powerful scripting and debugging support and a client interface that
+allows an operating system and its loaders to use Open Firmware services
+during the configuration and initialization process.  Open Firmware stores
+information about the hardware in a tree structure called the
+``device tree''.  This device tree supports multiple interconnected system
+buses and offers a framework for ``plug and play''-type auto configuration
+across different buses.  It was designed to support a variety of different
+processor Instruction Set Architectures (ISAs) and buses.
+
+The full documentation of this Standard can be found in [1].
+
+
+1.1 Build process
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Open Firmware (OF) is based on the programming language Forth. 
+SLOF use Paflof as the Forth engine, which was developed by
+Segher Boessenkool.  Most parts of the Forth engine are implemented in 
+C, by using GNU extensions of ANSI C, (e.g. assigned goto, often misnamed "computed goto"),
+resulting in a very efficient yet still quite portable engine.  
+
+The basic Forth words, so-called primitives,  are implemented with 
+a set of C macros.  A set of .in and .code files are provided, which
+define the semantic of the Forth primitives.  A Perl script translates 
+these files into valid C code, which will be compiled into the Forth engine.
+The complete Forth system composes of the basic Forth primitives and
+a set of Forth words, which are compiled during the start of the Forth
+system.
+
+Example:
+Forth primitive 'dup'
+
+	dup ( a -- a a) \ Duplicate top of stack element
+
+
+prim.in:	
+	cod(DUP)
+
+prim.code:
+	PRIM(DUP) cell x = TOS; PUSH; TOS = x; MIRP
+
+Generated code:
+
+static cell xt_DUP[] = { { .a = xt_DOTICK }, { .c = "\000\003DUP" },
+	 { .a = &&code_DUP }, };
+
+code_DUP: { asm("#### " "DUP"); void *w = (cfa = (++ip)->a)->a;
+	 cell x = (*dp); dp++; (*dp) = x; goto *w; }
+
+Without going into detail, it can be seen, that the data stack is
+implemented in C as an array of cells, where dp is the pointer to the top of
+stack. 
+
+For the implementation of the Open Firmware, most of the
+code is added as Forth code and bound to the engine.  Also 
+the system vector for reset and all kinds of exceptions
+will be part of the image. Additionally a secondary boot-loader
+or any other client application can be bound to the code as payload, 
+e.g. diagnostics and test programs.
+
+The Open Firmware image will be put together by the build 
+process, with a loader at the start of the image. This loader
+is called by Low Level Firmware and loads at boot time the Open 
+Firmware to it's location in memory (see 1.3 Load process). Additionally 
+a secondary boot loader or any other client application can be bound
+to the code as payload.
+
+The Low Level Firmware (LLFW) is responsible for setting up the 
+system in an initial state. This task includes the setup of the 
+CPUs, the system memory and all the buses as well as the serial port
+itself.
+
+
+2.0 Extension
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+In the following paragraphs it will be shown how to add
+new primitive words (i.e., words implemented not by building
+pre-existing Forth words together, but instead implemented in
+C or assembler).  With this, it is possible to adapt SLOF to
+the specific needs of different hardware and architectures.
+
+
+To add primitives:
+   
+   For a new primitive, following steps have to be done:
+
+   + Definition of primitive name in <arch>.in
+     - cod(ABC) defines primitive ABC
+
+     You can also use the following in a .in file, see existing
+     code for how to use these:
+     - con(ABC) defines constant ABC   
+     - col(ABC) defines colon definition ABC
+     - dfr(ABC) defines defer definition ABC
+
+   + Definition of the primitives effects in <arch>.code
+     - PRIM(ABC) ... MIRP
+
+       The code for the primitive body is any C-code. With
+       the macros of prim.code the data and return stack of 
+       the Forth engine can be appropriately manipulated.
+
+
+3.0 Limitations of this package
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ On a JS20 the memory setup is very static and therefore there are
+ only very few combinations of memory DIMM placement actually work.
+
+ Known booting configurations:
+
+    * 4x 256 MB (filling all slots) -- only "0.5 GB" reported.
+    * 2x 1 GB, slots 3/4 -- only "0.5 GB" reported.
+
+ Known failing configurations
+
+    * 2x 256 MB, slots 3/4
+    * 2x 256 MB, slots 1/2
+
+ On a JS20 SLOF wil always report 0.5 GB even if there is much more memory
+ available.
+
+ On a JS21 all memory configurations should work.
+
+Documentation
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+[1] IEEE 1275-1994 Standard, Standard for Boot (Initialization Configuration)
+    Firmware: Core Requierements and Practices
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/Makefile b/qemu-0.15.x/roms/SLOF/board-js2x/Makefile
new file mode 100644
index 0000000..cf17f98
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/Makefile
@@ -0,0 +1,85 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+JS2X_TARGETS = tools_build romfs_build clients_build bcm57xx stage1
+
+SUBDIRS = slof rtas 
+COMMON_LIBS = libc libipmi libbootmsg libbases libnvram libelf
+
+all: $(JS2X_TARGETS) subdirs boot_rom.bin
+
+.PHONY : subdirs $(SUBDIRS) clean distclean
+
+include config
+include Makefile.dirs
+include $(TOPCMNDIR)/make.rules
+include $(TOPCMNDIR)/Makefile.gen
+
+subdirs: $(SUBDIRS)
+
+$(SUBDIRS): common-libs
+		@echo " ====== Building $@ ======"
+		$(MAKE) -C $@ $(MAKEARG)
+
+stage1:	common-libs
+		@echo " ====== Building llfw ======"
+		make -C llfw RELEASE=-DRELEASE=\"\\\"$(RELEASE)\\\"\"
+
+bcm57xx:
+		make -C ../other-licence/bcm
+
+clean_here:
+		rm -f ../slof/OF.ffs
+		rm -f ../boot_rom.bin
+
+clean:		clean_here clean_gen
+		@for dir in $(SUBDIRS); do \
+			$(MAKE) -C $$dir clean || exit 1; \
+		done
+		rm -f ../boot_rom.bin ../js2*.img 
+		make -C ../other-licence/bcm clean
+		@make -C llfw clean
+		@make -C $(TOPCMNDIR)/clients/takeover clean
+
+distclean:	clean_here distclean_gen
+		@for dir in $(SUBDIRS); do \
+			$(MAKE) -C $$dir distclean || exit 1; \
+		done
+		rm -f ../boot_rom.bin ../js2*.img 
+		make -C ../other-licence/bcm clean
+		make -C llfw clean
+		make -C $(TOPCMNDIR)/clients/takeover distclean
+
+takeover: all
+		$(MAKE) -C $(TOPCMNDIR)/clients/takeover
+
+.driver_dirs:
+		@rm -rf ../driver-$(RELEASE)
+		@mkdir -p ../driver-$(RELEASE)
+
+.tar_gz:	.driver_dirs takeover external_flasher
+		@mv ../boot_rom.bin \
+			../driver-$(RELEASE)/$(RELEASE)-js2x.bin
+		@mv ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin \
+			../driver-$(RELEASE)/$(RELEASE)-$(FLASH_SIZE_MB)MB-BigEndian.bin
+		@mv $(TOPCMNDIR)/clients/takeover/takeover.elf \
+			../driver-$(RELEASE)/$(RELEASE)-takeover.bin
+		@cp ../VERSION ../driver-$(RELEASE)
+		@cp changes.txt ../driver-$(RELEASE)
+		@cd ../driver-$(RELEASE) && md5sum * > md5sum.txt
+		@chmod 644 ../driver-$(RELEASE)/*
+		@mv ../driver-$(RELEASE) ../driver-$(RELEASE)-`date +%Y-%h%d`
+		@tar czf ../driver-$(RELEASE)-`date +%Y-%h%d`.tar.gz \
+			../driver-$(RELEASE)-`date +%Y-%h%d` > /dev/null  2>&1
+		@rm -rf ../driver-$(RELEASE)-`date +%Y-%h%d`
+
+driver:		driver_prep clean .tar_gz
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/Makefile.dirs b/qemu-0.15.x/roms/SLOF/board-js2x/Makefile.dirs
new file mode 100644
index 0000000..1493d3b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/Makefile.dirs
@@ -0,0 +1,41 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+#
+# This sub-Makefile contains the directory configuration variables.
+# It can be included from all board specific subdirectories.
+#
+
+# The board specific top directory:
+export TOPBRDDIR ?= $(shell while ! test -e Makefile.dirs ; do cd .. ; done ; pwd )
+
+# The board specific directories:
+export INCLBRDDIR ?= $(TOPBRDDIR)/include
+export LLFWBRDDIR ?= $(TOPBRDDIR)/llfw
+export RTASBRDDIR ?= $(TOPBRDDIR)/rtas
+export SLOFBRDDIR ?= $(TOPBRDDIR)/slof
+export ROMFSBRDDIR ?=  $(TOPBRDDIR)/romfs
+
+# The common top directory:
+export TOPCMNDIR ?= $(shell cd $(TOPBRDDIR)/.. && pwd)
+
+# The common directories:
+export INCLCMNDIR ?= $(TOPCMNDIR)/include
+export LLFWCMNDIR ?= $(TOPCMNDIR)/llfw
+export RTASCMNDIR ?= $(TOPCMNDIR)/rtas
+export SLOFCMNDIR ?= $(TOPCMNDIR)/slof
+export ROMFSCMNDIR ?=  $(TOPCMNDIR)/romfs
+
+export LIBCMNDIR ?= $(TOPCMNDIR)/lib
+
+export TOOLSDIR ?= $(TOPCMNDIR)/tools
+export CLIENTSDIR ?= $(TOPCMNDIR)/clients
+export OTHERLICENCEDIR ?= $(TOPCMNDIR)/other-licence
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/config b/qemu-0.15.x/roms/SLOF/board-js2x/config
new file mode 100644
index 0000000..3f6a6c8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/config
@@ -0,0 +1,7 @@
+BOARD=js2x
+TARG=ppc64
+export FLAG="-DBIOSEMU"
+export CPUARCH=ppc970
+export CPUARCHDEF=-DCPU_PPC970
+export SNK_BIOSEMU_APPS=1
+FLASH_SIZE=8388608
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/include/bmc.h b/qemu-0.15.x/roms/SLOF/board-js2x/include/bmc.h
new file mode 100644
index 0000000..39dff80
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/include/bmc.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __BMC_H
+#define __BMC_H
+
+void (*bmc_system_reboot) (void);
+void (*bmc_power_off) (void);
+
+short (*bmc_set_flashside) (short mode);
+short (*bmc_get_flashside) (void);
+int (*bmc_stop_bootwatchdog) (void);
+int (*bmc_set_bootwatchdog) (unsigned short);
+
+uint32_t(*bmc_read_vpd) (uint8_t * dst, uint32_t len, uint32_t offset);
+uint32_t(*bmc_write_vpd) (uint8_t * src, uint32_t len, uint32_t offset);
+
+uint32_t(*bmc_get_blade_descr) (uint8_t * dst, uint32_t maxlen, uint32_t * len);
+
+#endif				/* __BMC_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/include/hw.h b/qemu-0.15.x/roms/SLOF/board-js2x/include/hw.h
new file mode 100644
index 0000000..27117c3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/include/hw.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+uint16_t bswap16_load(uint64_t addr) ;
+uint32_t bswap32_load(uint64_t addr) ;
+
+void bswap16_store(uint64_t addr, uint16_t val) ;
+void bswap32_store(uint64_t addr, uint32_t val) ;
+
+uint8_t load8_ci(uint64_t addr) ;
+uint16_t load16_ci(uint64_t addr) ;
+uint32_t load32_ci(uint64_t addr) ;
+uint64_t load64_ci(uint64_t addr) ;
+
+void store8_ci(uint64_t  addr, uint8_t val) ;
+void store16_ci(uint64_t  addr, uint16_t val) ;
+void store32_ci(uint64_t  addr, uint32_t val) ;
+void store64_ci(uint64_t  addr, uint64_t val) ;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/include/nvramlog.h b/qemu-0.15.x/roms/SLOF/board-js2x/include/nvramlog.h
new file mode 100644
index 0000000..5d6c5d1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/include/nvramlog.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef NVRAMLOG_H
+	#define NVRAMLOG_H
+
+/* ----------------------------------------------------------------------------
+ *	NVRAM Log-Partition header design:
+ *
+ *	Partition Header
+ *	00h	- signature	( 1 byte)
+ *	01h	- checksum	( 1 byte)
+ *	02h	- length	( 2 byte) value = 1st_byte*256 + 2nd_byte
+ *	04h	- name		(12 byte)
+ *	space for partiton header = 16 byte
+ *
+ *	Log Header
+ *	10h	- offset	( 2 byte) from Partition Header to Data Section
+ *	12h	- flags		( 2 byte) control flags
+ *	14h	- pointer	( 4 byte) pointer to first free byte in Data Section
+ *					  relative to the beginning of the data section
+ *	18h	- zero		( 32 byte) reserved as stack for four  64 bit register
+ *	38h - reserved		(  8 byte) reserved for 64 bit CRC (not implemented yet)
+ *	space for header = 64 byte
+ *	Data Section
+ *	40h	- cyclic data
+ * -------------------------------------------------------------------------------- */
+
+	// initial values
+	#define LLFW_LOG_BE0_SIGNATURE		0x51			// signature for general firmware usage
+	#define LLFW_LOG_BE0_NAME_PREFIX	0x69626D2C		// first 4 bytes of name: "ibm,"
+	#define LLFW_LOG_BE0_NAME		0x435055306C6F6700	// remaining 8 bytes	: "CPU0log\0"
+	#define LLFW_LOG_BE0_LENGTH		0x2000			// Partition length in block of 16 bytes
+	#define LLFW_LOG_BE0_DATA_OFFSET	0x40			// offset in bytes between header and data
+	#define LLFW_LOG_BE0_FLAGS		0			// unused
+
+	#define LLFW_LOG_BE1_SIGNATURE		0x51			// signature for general firmware usage
+	#define LLFW_LOG_BE1_NAME_PREFIX	0x69626D2C		// first 4 bytes of name: "ibm,"
+	#define LLFW_LOG_BE1_NAME		0x435055316C6F6700	// remaining 8 bytes	: "CPU1log\0\0"
+	#define LLFW_LOG_BE1_LENGTH		0x500			// Partition length in block of 16 bytes
+	#define LLFW_LOG_BE1_DATA_OFFSET	0x40			// offset in bytes between header and data
+	#define LLFW_LOG_BE1_FLAGS		0x0			// unused
+
+	// positions of the initial values
+	#define LLFW_LOG_POS_CHECKSUM	0x01			// 1
+	#define LLFW_LOG_POS_LENGTH	0x02			// 2
+	#define LLFW_LOG_POS_NAME	0x04			// 4
+	#define LLFW_LOG_POS_DATA_OFFSET 0x10			// 16
+	#define LLFW_LOG_POS_FLAGS	0x12			// 18
+	#define LLFW_LOG_POS_POINTER	0x14			// 20
+
+	// NVRAM info
+	#define MAMBO_NVRAM_BASE	0x100000		// NVRAM Base for MAMBO
+	#define NVRAM_EMPTY_PATTERN	0x0000000000000000	// Pattern (64-bit) used to overwrite NVRAM
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/include/product.h b/qemu-0.15.x/roms/SLOF/board-js2x/include/product.h
new file mode 100644
index 0000000..55e9132
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/include/product.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _PRODUCT_H
+#define _PRODUCT_H
+
+/* This is also the name which is also put in the flash and should
+ * therefore not excedd the length of 32 bytes */
+#define PRODUCT_NAME "JS2XBlade"
+
+/* Generic identifier used in the flash */
+#define FLASHFS_MAGIC "magic123"
+
+/* Magic identifying the platform */
+#define FLASHFS_PLATFORM_MAGIC "JS2XBlade"
+
+/* also used in the flash */
+#define FLASHFS_PLATFORM_REVISION "1"
+
+#define BOOT_MESSAGE  "Press \"s\" to enter Open Firmware.\r\n\r\n\0"
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/include/southbridge.h b/qemu-0.15.x/roms/SLOF/board-js2x/include/southbridge.h
new file mode 100644
index 0000000..1edeb6d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/include/southbridge.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _SOUTHBRIDGE_H
+#define _SOUTHBRIDGE_H
+
+
+#define SB_FLASH_adr           (0xff000000)          // FLASH (EBC_CS0/Bank0)
+#define SB_NVRAM_adr           (0xff800000)          // NonVolatile mapping
+#define SB_NVRAM_FWONLY_adr    (0xff8FF000)          // NonVolatile mapping
+#define NVRAM_LENGTH           0x100000
+#define NVRAM_FWONLY_LENGTH    0x1000
+#define SB_MAILBOX_adr         0
+
+#define FLASH_LENGTH           0x400000
+
+#define SB_IPMI_KCS_adr        0xF4000CA8            // IPMI KCS
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Cboot.S b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Cboot.S
new file mode 100644
index 0000000..d22f3c9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Cboot.S
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+	.org 0
+
+	/* Boot Information, hardcoded to ColdReset */
+	.quad	1
+	/* start address */
+	.quad	0x100
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Makefile b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Makefile
new file mode 100644
index 0000000..41cdc35
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/Makefile
@@ -0,0 +1,61 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../../make.rules
+
+CPPFLAGS	= -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) \
+		  -I$(LIBCMNDIR)/libc/include
+CFLAGS		+= -fno-builtin $(CPPFLAGS) -O2  -msoft-float $(MAMBO)
+CFLAGS		+= $(BOOT) $(IOCONF) -Wa,-mregnames $(RELEASE) $(CPUARCHDEF) -Wall
+ASFLAGS         = $(BOOT) $(IOCONF) $(RELEASE)$(CPUARCHDEF)  -Wa,-mregnames
+LDFLAGS1	= -nostdlib -e__start -Tstage2.lds -N -Ttext=0x100
+
+
+STG1OBJ		 = startup.o boot_abort.o romfs.o hw.o io_generic.o board_io.o 
+STG1OBJ		 += stage2_head.o stage2.o comlib.o romfs_wrap.o nvramlog.o
+STG1OBJ		 += u4mem.o
+
+all: stage1.bin stageS.bin Cboot.o
+
+stage1.bin:	$(STG1OBJ) $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a
+		$(LD) $(LDFLAGS1) -o stage1.elf $^
+		$(OBJCOPY) -O binary stage1.elf $@
+
+stageS.bin:	stage_s.o
+		$(LD) -nostdlib -N -Tstage_s.lds -o stage_s.elf stage_s.o
+		$(OBJCOPY) -O binary stage_s.elf stageS.bin
+
+romfs.o:	../../llfw/romfs.S
+		$(CC) $(CFLAGS) -c ../../llfw/romfs.S
+
+boot_abort.o:	../../llfw/boot_abort.S
+		$(CC) $(CFLAGS) -c ../../llfw/boot_abort.S
+
+nvramlog.o:	../../llfw/nvramlog.S
+		$(CC) $(CFLAGS) -c ../../llfw/nvramlog.S
+
+include $(LLFWCMNDIR)/clib/Makefile.inc
+
+include $(LLFWCMNDIR)/io_generic/Makefile.inc
+
+romfs_wrap.o:	../../llfw/romfs_wrap.c
+		$(CC) $(CFLAGS) -c ../../llfw/romfs_wrap.c
+
+Cboot.o: Cboot.S
+		$(CC) $(CFLAGS) -c $^
+		$(OBJCOPY) -O binary Cboot.o Cboot.bin
+
+%.o: %.S
+		$(CC) $(CFLAGS) -c $^
+
+clean:
+		rm -f *.o *.bin *.elf
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/board_io.S b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/board_io.S
new file mode 100644
index 0000000..2f36588
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/board_io.S
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <macros.h>
+#include <cpu.h>
+
+	.text
+
+C_ENTRY(copy_from_flash)
+# size in GPR3 (multiple of 64), from GPR4, to GPR5
+	mflr 24 ; mtctr 3 ; addi 4,4,-64 ; addi 5,5,-64
+0:	SETCI(r0)
+	ldu 16,64(4) ; ld 17,8(4) ; ld 18,16(4) ; ld 19,24(4)
+	ld 20,32(4) ; ld 21,40(4) ; ld 22,48(4) ; ld 23,56(4)
+	CLRCI(r0)
+	stdu 16,64(5) ; std 17,8(5) ; std 18,16(5) ; std 19,24(5)
+	std 20,32(5) ; std 21,40(5) ; std 22,48(5) ; std 23,56(5)
+	sync ; icbi 0,2 ; bdnz 0b ; sync ; isync ; mtlr 24 ; blr
+
+/****************************************************************************
+ * prints one character to serial console
+ *
+ * Input:
+ * R3 - character
+ *
+ * Returns: -
+ *
+ * Modifies Registers:
+ * R3, R4, R5, R6, R7
+ ****************************************************************************/
+ENTRY(io_putchar)
+	mflr	r7
+
+	SETCI(r0)
+
+	# always use serial1
+	li 4,0x3f8 ; oris 4,4,0xf400
+
+	# print one char
+0:	lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio 
+
+	# also print char to serial2 if on a JS21
+	# read ID register: only if it is a PC87427 (JS21) also use serial2
+	addi 4,4,-0x3f8
+	li 5,0x20 ; stb 5,0x2e(4) ; lbz 5,0x2f(4) ; cmpdi 5,0xf2 ; bne 1f
+
+	addi 4,4,0x2f8
+0:	lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio 
+
+1:	CLRCI(r0)
+
+	mtlr	r7
+	blr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/hw.c b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/hw.c
new file mode 100644
index 0000000..e01b583
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/hw.c
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <stdint.h>
+#include <hw.h>
+
+uint16_t
+bswap16_load(uint64_t addr)
+{
+	unsigned int val;
+	set_ci();
+	asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr));
+	clr_ci();
+	return val;
+}
+
+uint32_t
+bswap32_load(uint64_t addr)
+{
+	unsigned int val;
+	set_ci();
+	asm volatile ("lwbrx %0, 0, %1":"=r" (val):"r"(addr));
+	clr_ci();
+	return val;
+}
+
+void
+bswap16_store(uint64_t addr, uint16_t val)
+{
+	set_ci();
+	asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr));
+	clr_ci();
+}
+
+void
+bswap32_store(uint64_t addr, uint32_t val)
+{
+	set_ci();
+	asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr));
+	clr_ci();
+}
+
+uint8_t
+load8_ci(uint64_t addr)
+{
+	uint8_t val;
+	set_ci();
+	val = *(uint8_t *) addr;
+	clr_ci();
+	return val;
+}
+
+uint16_t
+load16_ci(uint64_t addr)
+{
+	uint16_t val;
+	set_ci();
+	val = *(uint16_t *) addr;
+	clr_ci();
+	return val;
+}
+
+uint32_t
+load32_ci(uint64_t addr)
+{
+	uint32_t val;
+	set_ci();
+	val = *(uint32_t *) addr;
+	clr_ci();
+	return val;
+}
+
+uint64_t
+load64_ci(uint64_t addr)
+{
+	uint64_t val;
+	set_ci();
+	val = *(uint64_t *) addr;
+	clr_ci();
+	return val;
+}
+
+
+void
+store8_ci(uint64_t addr, uint8_t val)
+{
+	set_ci();
+	*(uint8_t *) addr = val;
+	clr_ci();
+}
+
+void
+store16_ci(uint64_t addr, uint16_t val)
+{
+	set_ci();
+	*(uint16_t *) addr = val;
+	clr_ci();
+}
+
+void
+store32_ci(uint64_t addr, uint32_t val)
+{
+	set_ci();
+	*(uint32_t *) addr = val;
+	clr_ci();
+}
+
+void
+store64_ci(uint64_t addr, uint64_t val)
+{
+	set_ci();
+	*(uint64_t *) addr = val;
+	clr_ci();
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.c b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.c
new file mode 100644
index 0000000..245d92e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.c
@@ -0,0 +1,284 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <xvect.h>
+#include <hw.h>
+#include <stdio.h>
+#include <romfs.h>
+#include "memmap.h"
+#include "stage2.h"
+#include <termctrl.h>
+#include "product.h"
+#include "calculatecrc.h"
+#include <cpu.h>
+#include <libelf.h>
+#include <string.h>
+
+uint64_t uart;
+uint64_t gVecNum;
+uint8_t u4Flag;
+
+uint64_t exception_stack_frame;
+
+typedef void (*pInterruptFunc_t) (void);
+
+pInterruptFunc_t vectorTable[0x2E << 1];
+
+void c_memInit(uint64_t r3, uint64_t r4);
+
+void proceedInterrupt();
+
+void
+exception_forward(void)
+{
+	uint64_t val;
+
+	if (*(uint64_t *) XVECT_M_HANDLER) {
+		proceedInterrupt();
+	}
+
+	printf("\r\n exception %llx ", gVecNum);
+	asm volatile ("mfsrr0	%0":"=r" (val):);
+	printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val);
+	asm volatile ("mfsrr1	%0":"=r" (val):);
+	printf(" SRR1 = %08llx%08llx ", val >> 32, val);
+
+	asm volatile ("mfsprg	%0,2":"=r" (val):);
+	printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val);
+	asm volatile ("mfsprg	%0,3":"=r" (val):);
+	printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val);
+	while (1);
+}
+
+void
+c_interrupt(uint64_t vecNum)
+{
+	gVecNum = vecNum;
+	if (vectorTable[vecNum >> 7]) {
+		vectorTable[vecNum >> 7] ();
+	} else {
+		exception_forward();
+	}
+}
+
+void
+set_exceptionVector(int num, void *func)
+{
+	vectorTable[num >> 7] = (pInterruptFunc_t) func;
+}
+
+static void
+io_init(void)
+{
+	// read ID register: only if it is a PC87427, enable serial2
+	store8_ci(0xf400002e, 0x20);
+	if (load8_ci(0xf400002f) != 0xf2) {
+		uart = 0xf40003f8;
+		u4Flag = 0;
+	} else {
+		uart = 0xf40002f8;
+		u4Flag = 1;
+	}
+}
+
+int
+io_getchar(char *ch)
+{
+	int retVal = 0;
+	if ((load8_ci(uart + 5) & 0x01)) {
+		*ch = load8_ci(uart);
+		retVal = 1;
+	}
+	return retVal;
+}
+
+uint64_t
+get_dec(void)
+{
+	return 0xdeadaffe;
+}
+
+void
+set_dec(uint64_t val)
+{
+}
+
+uint64_t
+tb_frequency(void)
+{
+	return 0;
+}
+
+void copy_from_flash(uint64_t cnt, uint64_t src, uint64_t dest);
+
+const uint32_t CrcTableHigh[16] = {
+	0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90,
+	0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7,
+	0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E,
+	0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09
+};
+const uint32_t CrcTableLow[16] = {
+	0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
+	0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
+	0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
+	0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
+};
+
+unsigned long
+check_flash_image(unsigned long rombase, unsigned long length,
+		  unsigned long start_crc)
+{
+
+	uint32_t AccumCRC = start_crc;
+	char val;
+	uint32_t Temp;
+	while (length-- > 0) {
+		val = load8_ci(rombase++);
+		Temp = ((AccumCRC >> 24) ^ val) & 0x000000ff;
+		AccumCRC <<= 8;
+		AccumCRC ^= CrcTableHigh[Temp / 16];
+		AccumCRC ^= CrcTableLow[Temp % 16];
+	}
+
+	return AccumCRC;
+}
+
+static void
+load_file(uint64_t destAddr, char *name, uint64_t maxSize, uint64_t romfs_base)
+{
+	uint64_t *src, *dest, cnt;
+	struct romfs_lookup_t fileInfo;
+	c_romfs_lookup(name, romfs_base, &fileInfo);
+	if (maxSize) {
+		cnt = maxSize / 8;
+	} else {
+		cnt = (fileInfo.size_data + 7) / 8;
+	}
+	dest = (uint64_t *) destAddr;
+	src = (uint64_t *) fileInfo.addr_data;
+	while (cnt--) {
+		store64_ci((uint64_t) dest, *src);
+		dest++;
+		src++;
+	}
+	flush_cache((void *) destAddr, fileInfo.size_data);
+}
+
+/***************************************************************************
+ * Function: early_c_entry
+ * Input   : start_addr
+ *
+ * Description:
+ **************************************************************************/
+void
+early_c_entry(uint64_t start_addr)
+{
+	struct romfs_lookup_t fileInfo;
+	uint32_t crc;
+	void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
+	uint64_t *boot_info;
+	exception_stack_frame = 0;
+	/* destination for the flash image; we copy it to RAM
+	 * because from flash it is much too slow
+	 * the flash is copied at 224MB - 4MB (max flash size)
+	 * at 224MB starts SLOF
+	 * at 256MB is the SLOF load-base */
+	uint64_t romfs_base = 0xe000000 - 0x400000;
+	// romfs header values
+	struct stH *header = (struct stH *) (start_addr + 0x28);
+	//since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory
+	uint64_t magic_val = 0;
+	uint64_t startVal = 0;
+	uint64_t flashlen = 0;
+	unsigned long ofw_addr;
+
+	io_init();
+
+	flashlen = load64_ci((uint64_t) (&header->flashlen));
+
+	//copy fh_magic to magic_val since, we cannot use it as a string from flash
+	magic_val = load64_ci((uint64_t) (header->magic));
+
+	printf(" Check ROM  = ");
+	if (strncmp((char *) &magic_val, FLASHFS_MAGIC, 8) == 0) {
+		// somehow, the first 8 bytes in flashfs are overwritten, if booting from drone...
+		// so if we find "IMG1" in the first 4 bytes, we skip the CRC check...
+		startVal = load64_ci((uint64_t) start_addr);
+		if (strncmp((char *) &startVal, "IMG1", 4) == 0) {
+			printf
+			    ("start from RAM detected, skipping CRC check!\r\n");
+			// for romfs accesses (c_romfs_lookup) to work, we must fix the first uint64_t to the value we expect...
+			store64_ci((uint64_t) start_addr, 0xd8);
+		} else {
+			//checking CRC in flash, we must use cache_inhibit
+			// since the crc is included as the last 32 bits in the image, the resulting crc should be 0
+			crc =
+			    check_flash_image((uint64_t) start_addr,
+					      load64_ci((uint64_t)
+							(&header->flashlen)),
+					      0);
+			if (crc == 0) {
+				printf("OK\r\n");
+			} else {
+				printf("failed!\r\n");
+				while (1);
+			}
+		}
+	} else {
+		printf
+		    ("failed (magic string is \"%.8s\" should be \"%.8s\")\r\n",
+		     (char *) &magic_val, FLASHFS_MAGIC);
+		while (1);
+	}
+
+	printf(" Press \"s\" to enter Open Firmware.\r\n\r\n");
+
+	if ((start_addr > 0xF0000000) && u4Flag)
+		u4memInit();
+
+	/* here we have real ram avail -> hopefully
+	 * copy flash to ram; size is in 64 byte blocks */
+	flashlen /= 64;
+	/* align it a bit */
+	flashlen += 7;
+	flashlen &= ~7;
+	copy_from_flash(flashlen, start_addr, romfs_base);
+	/* takeover sometimes fails if the image running on the system
+	 * has a different size; flushing the cache helps, because it is
+	 * the right thing to do anyway */
+	flush_cache((void *) romfs_base, flashlen * 64);
+
+	c_romfs_lookup("bootinfo", romfs_base, &fileInfo);
+	boot_info = (uint64_t *) fileInfo.addr_data;
+	boot_info[1] = start_addr;
+	load_file(0x100, "xvect", 0, romfs_base);
+	load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base);
+	c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
+	load_elf_file((void *) fileInfo.addr_data, &ofw_addr);
+	ofw_start =
+	    (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
+	    &ofw_addr;
+	// re-enable the cursor
+	printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON);
+	/* ePAPR 0.5
+	 * r3 = R3 Effective address of the device tree image. Note: this
+	 *      address must be 8-byte aligned in memory.
+	 * r4 = implementation dependent
+	 * r5 = 0
+	 * r6 = 0x65504150 -- ePAPR magic value-to distinguish from
+	 *      non-ePAPR-compliant firmware
+	 * r7 = implementation dependent
+	 */
+	ofw_start(0, romfs_base, 0, 0, 0);
+	// never return
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.h b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.h
new file mode 100644
index 0000000..9ce3c82
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __STAGE2_H
+#define __STAGE2_H
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+
+void u4memInit(void);
+
+#endif		/* __ASSEMBLER__ */
+#endif		/* __STAGE2_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.lds b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.lds
new file mode 100644
index 0000000..f91f065
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2.lds
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+
+/* set the entry point */
+ENTRY ( __start )
+
+SECTIONS {
+	.text : {
+		*(.text)
+	}
+
+	. = ALIGN(8);
+
+	.data : {
+		*(.data)
+		*(.rodata .rodata.*)
+		*(.got1)
+	        *(.sdata)
+	        *(.opd)
+	}
+
+	/* FIXME bss at end ??? */
+
+	. = ALIGN(8);
+	__bss_start = .;
+	.bss : {
+		*(.sbss) *(.scommon)
+		*(.dynbss)
+		*(.bss)
+	}
+
+	. = ALIGN(8);
+	__bss_end = .;
+	__bss_size = (__bss_end - __bss_start);
+
+	__toc_start = .;
+	.got       :
+	{
+		 *(.toc .got)
+	}
+	. = ALIGN(8);
+	__toc_end = .;                                                                         
+	__stack_end = . ;
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2_head.S b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2_head.S
new file mode 100644
index 0000000..5460bfe
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage2_head.S
@@ -0,0 +1,91 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "macros.h"
+#include "../../llfw/boot_abort.h"
+
+/*#################### defines #####################*/
+#define STACK_SIZE   0x4000
+
+/*#################### code ########################*/
+	.text
+	.globl .gluon_c_entry
+	.globl __toc_start
+	.globl __toc_end
+	.globl __stack_end
+	.globl __bss_start
+	.globl __bss_size
+	.globl __start
+
+ASM_ENTRY(__startC)
+	/* clear out bss section                */
+        LOAD64(r3, (__bss_start - 8))
+        LOAD64(r4, __bss_size)
+
+        /* divide __bss_size by 8 to get number */
+        /* of dwords to clear                   */
+        srwi.   r4, r4, 3
+        beq     bsscdone
+        li      r5, 0
+        mtctr   r4
+bssc:   stdu    r5, 8(r3)
+        bdnz    bssc
+bsscdone:
+	/* setup stack                          */
+	LOAD64(r1, __stack_end + STACK_SIZE)
+
+	/* save return address beside stack     */
+	addi	r3, r1, 128
+	mflr	r0
+	std	r0, 0(r3)
+	
+	/* setup toc                            */
+	bl	toc_init
+
+	/* ------------------------------------ */
+	/* jump to c-code                       */
+	/* r10 = cpu_init_slave address - r3    */
+	/* r11 = slave_setup address    - r4    */
+	/* ------------------------------------ */
+	mr	r3, r10
+	mr	r4, r11
+	bl	.early_c_entry
+
+	/* return to caller...                  */
+	LOAD64(r1, __stack_end + STACK_SIZE)
+	addi	r1, r1, 128
+	ld	r3, 0(r1)
+	mtlr	r3
+	blr
+
+	/* #################################### */
+	/* Basic Additional Functions           */
+	/* for extended lib functions see       */
+	/* external library                     */
+	/* #################################### */
+	.align 	2
+
+	/* ------------------------------------ */
+	/* updates toc in r2                    */
+	/* ------------------------------------ */
+ASM_ENTRY(toc_init)	
+	LOAD64(r2, __toc_start)
+	addi	r2,r2,0x4000
+	addi	r2,r2,0x4000
+	blr
+
+	/* ------------------------------------ */
+	/* stores arg#1 in r27 and stops        */
+	/* ------------------------------------ */
+ENTRY(do_panic)
+ENTRY(halt_sys)
+	BOOT_ABORT_R3HINT(ABORT_CANIO, ALTBOOT, msg_e_ierror);
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.S b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.S
new file mode 100644
index 0000000..202350f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.S
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+	.text
+	.org	0 /* after loading to mem this is at slaveloop_base */
+#	. = 0x3f00 loaded to this addr
+	.globl __stage_s_entry
+
+__stage_s_entry:
+	bl	$+4
+	mflr	r4
+	li	r3, 0xff
+	not 	r3, r3
+	and	r4, r4, r3
+	li 0,1 ; std 0,0xf8(4)
+	li 0,0 ; std 0,0xa0(4)
+slaveloop:
+	ori 28,28,0x100
+	lis 0,10
+	mtctr 0
+	bdnz $		# do some waiting, to prevent flooding the buses
+	lwz 0,0xa0(4)
+	cmpw 0,28
+	bne $-20	# wait for our flag
+
+	lwz 0,0x80(4)
+	lwz 3,0xc0(4)
+	mtctr 0
+	bctr		# jump to specified address, with specified GPR3
+
+#	.quad	0	
+#	.quad	0	
+
+
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.lds b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.lds
new file mode 100644
index 0000000..200c1b3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/stage_s.lds
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+
+ENTRY( __stage_s_entry )
+
+SECTIONS {
+  .text : {
+	*(.text)
+	  } 
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/startup.S b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/startup.S
new file mode 100644
index 0000000..1357d3f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/startup.S
@@ -0,0 +1,708 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+# SLOF for JS20/JS21 -- ROM boot code.
+# Initial entry point, copy code from flash to cache, memory setup.
+# Also sets up serial console and optimizes some settings.
+
+#include "termctrl.h"
+#include <product.h>
+#include <xvect.h>
+#include <cpu.h>
+#include <macros.h>
+#include <southbridge.h>
+
+	.text
+	.globl __start
+__start:
+	/* put rombase in sprg1 ***********************/
+
+	bl	postHeader
+	.long 0xDEADBEE0
+	.long 0x0       /* size */ 
+	.long 0x0       /* crc  */
+	.long relTag - __start
+postHeader:
+	mflr	r3
+	li	r4, 0x7fff
+	not	r4, r4
+	and	r3, r3, r4
+	mtsprg	1, r3      /* romfs base */
+	bl	_start
+
+	.org 0x150 - 0x100
+__startSlave:
+	bl setup_cpu
+	bl set_ci_bit
+#	b slaveWithNumber
+	b slave
+
+	.org 0x180 - 0x100
+__startMaster:
+	li 3,0
+	mtsprg	1, r3      /* romfs base */
+	bl setup_cpu
+	bl set_ci_bit
+	b master
+
+
+	/* FIXME: Also need 0280, 0380, 0f20, etc. */
+
+	.irp i, 0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x0400,0x0500,0x0600,0x0700, \
+		0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, \
+		0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
+		0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+		0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+		0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00
+	. = \i
+
+	/* enable this if you get exceptions before the console works    */
+	/* this will allow using the hardware debugger to see where      */
+	/* it traps, and with what register values etc.                  */
+	// b	$
+
+	mtsprg	0, r0
+	mfctr	r0
+	mtsprg  2,r0
+	mflr	r0
+// 10
+	mtsprg  3,r0
+	ld	r0, (\i + 0x160)(0)
+	mtctr	r0
+	li	r0, \i + 0x100
+// 20
+	bctr
+
+	. = \i + 0x60
+
+	.quad intHandler2C
+
+	.endr
+
+
+	. = XVECT_M_HANDLER - 0x100
+	.quad 0x00
+	. = XVECT_S_HANDLER - 0x100
+
+	.quad 0
+
+
+
+	.org 0x4000 - 0x100
+_start:
+	# optimize HID register settings
+	bl setup_cpu
+	bl set_ci_bit
+
+	# read semaphore, run as slave if not the first to do so
+	li 3,0 ; oris 3,3,0xf800 ; lwz 3,0x60(3) ; andi. 3,3,1 ; beq slave
+master:
+	# setup flash, serial
+	bl setup_sio
+
+	# early greet
+	li	r3, 10
+	bl	putc
+	li 3,13 ; bl putc ; li 3,10 ; bl putc ; li 3,'S' ; bl putc
+
+
+	#do we run from ram ?
+	mfsprg	r3, 1	/* rombase */
+	cmpdi	r3,0	/* rombase is 0 when running from RAM */
+
+	bne copy_to_cache
+
+	# wait a bit, start scripts are slow...  need to get all cores running!
+	lis 3,0x4000 ; mtctr 3 ; bdnz $
+
+	# copy 4MB from 0 to temp memory
+   lis 4,0x8 ; mtctr 4 ; lis 4,0x200  ; li 3,0 ; addi 4,4,-8 ; addi 3,3,-8
+0:	ldu 5,8(3) ; stdu 5,8(4) ; bdnz 0b
+
+	lis 4,0x200
+	mtsprg	1, r4
+
+	lis 4,0x1
+	lis 3,0x20 ; addi 3,3,0x200-8 ;
+	FLUSH_CACHE(r3, r4)
+
+	lis 4,0x200
+	addi 4,4,copy_to_cache at l
+	mtctr 4
+	bctr
+
+# make all data accesses cache-inhibited
+set_ci_bit:
+	SETCI(r0)
+	blr
+
+# make all data accesses cacheable
+clr_ci_bit:
+	CLRCI(r0)
+	blr
+
+# write a character to the serial port
+putc:
+# always write to serial1
+0:	lbz 0,5(13) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(13) ; eieio
+
+# read ID register: only if it is a PC87427 (JS21) also use serial2
+	li 4,0 ; oris 4,4,0xf400
+	li 5,0x20 ; stb 5,0x2e(4) ; lbz 5,0x2f(4); cmpdi 5,0xf2 ; bne 1f
+
+	addi 4,4,0x2f8
+0:	lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio
+
+1:	blr
+
+# transfer from running from flash to running from cache
+return_cacheable:
+	# find and set address to start running from cache, set msr value 
+	mflr 3 ; rldicl 3,3,0,44 
+jump_cacheable:
+	mtsrr0 3 ; 
+	mfmsr 3 ; ori 3,3,0x1000 ; mtsrr1 3 # enable MCE, as well
+
+	# set cacheable insn fetches, jump to cache
+	mfspr 3,HID1 ; rldicl 3,3,32,0 ; oris 3,3,0x0020 ; rldicl 3,3,32,0
+	sync ; mtspr HID1,3 ; mtspr HID1,3 ; rfid ; b .
+
+
+
+
+copy_to_cache:
+	# zero the whole cache
+	# also, invalidate the insn cache, to clear parity errors
+	# 128kB @ 0MB (boot code and vectors from 0x0 up to 0x20000)
+	li 4,0x400 ; mtctr 4 ; li 5,0x0 ; bl clr_ci_bit
+0:	dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b
+
+	# 0x2000 to 0x100000/0x80000 (smaller on 970/970FX)
+	li 4,0x1C00 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0xC00
+0:
+	mtctr 4 ; li 5,0x2000
+0:	dcbz 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b ; bl set_ci_bit
+
+	# find base address
+	bcl 20,31,$+4 ; mflr 31 ; rldicr 31,31,0,43
+
+	# copy 1kB from 0x4000
+	li 4,0x80 ; mtctr 4 ; 
+	li	5,0x3ff8
+	addi 3,31,0x3ff8
+0:	ldu 4,8(3) ; bl clr_ci_bit ; stdu 4,8(5) ; bl set_ci_bit ; bdnz 0b
+	# now start executing from cache -- insn cache is huge speed boost
+
+	bl return_cacheable
+
+	li 3,'L' ; bl putc
+
+	# copy 128kB of flash to cache
+	li 4,0x800 ; mtctr 4 ; li 5,0x200-64 ; addi 3,31,0x200-64 ; 
+0:	ldu 16,64(3) ; ld 17,8(3) ; ld 18,16(3) ; ld 19,24(3)
+	ld 20,32(3) ; ld 21,40(3) ; ld 22,48(3) ; ld 23,56(3)
+	bl clr_ci_bit
+	stdu 16,64(5) ; std 17,8(5) ; std 18,16(5) ; std 19,24(5)
+	std 20,32(5) ; std 21,40(5) ; std 22,48(5) ; std 23,56(5)
+	icbi 0,5 ; bl set_ci_bit ; bdnz 0b ; isync
+
+
+	li 3,'O' ; bl putc
+
+	lis 4,0x20
+	mfsprg	r3,1
+	cmpd r3,r4
+	beq 1f
+
+	// at 0xf8000000 we decide if it is u3 or u4
+	li 4,0 ; oris 4,4,0xf800 ; lwz 3,0(4) ; srdi 3,3,4 ; cmpdi 3,3 ; bne 0f
+	bl setup_mem_u3
+	bl setup_mem_size
+	b 1f
+0:
+
+1:
+	li 3,'F' ; bl putc
+
+	# setup nvram logging only when not running from RAM
+	mfsprg	r3, 1	/* rombase */
+	cmpdi	r3, 0	/* rombase is 0 when running from RAM */
+	beq	0f
+
+	// at 0xf8000000 we decide if it is u3 or u4
+	li	r4, 0
+	oris	r4, r4, 0xf800
+	lwz	r3, 0(r4)
+	srdi	r3, r3, 4
+	cmpdi	r3, 3	/* 3 means js20; no nvram logging on js20 */
+	beq	0f
+
+	bl	io_log_init
+0:
+
+	#bl print_mem
+
+	# data is cacheable by default from now on
+	bl clr_ci_bit
+
+
+	/* give live sign *****************************/
+	bl	0f
+	.ascii	TERM_CTRL_RESET
+	.ascii	TERM_CTRL_CRSOFF
+	.ascii  " **********************************************************************"
+	.ascii	"\r\n"
+	.ascii	TERM_CTRL_BRIGHT
+	.ascii	PRODUCT_NAME
+	.ascii  " Starting\r\n"
+	.ascii  TERM_CTRL_RESET
+	.ascii  " Build Date = ", __DATE__, " ", __TIME__
+	.ascii	"\r\n"
+	.ascii  " FW Version = " , RELEASE
+	.ascii	"\r\n\0"
+	.align	2
+0:	mflr	r3
+	bl	io_print
+
+	# go!
+	li	r3,__startC at l
+	mtctr	r3
+	mfsprg	r10, 1
+	bctrl
+
+relTag:
+	.ascii  RELEASE
+	.ascii	"\0"
+	.align	2
+
+slave:
+
+	# get cpu number
+	li 3,0 ; oris 3,3,0xf800 ; lwz 28,0x50(3)
+
+slaveWithNumber:
+	# create our slave loop address
+	sldi 3,28,24 ; oris 3,3,0x3000
+
+	# invalidate the insn cache, to clear parity errors
+	# clear the L2 cache as well, to get ECC right
+	li 4,0x2000 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0x1000
+0:	mtctr 4 ; mr 5,3 ; bl clr_ci_bit
+
+0:	dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b
+
+
+	# write a "b $" insn in there
+	lis 4,0x4800 ; stw 4,0(3)
+/*
+	mr 5,3
+
+	# jump there
+	bl set_ci_bit
+	li 13,0 ; oris 13,13,0xf400
+	# device address
+	addi 13,13,0x2f8
+	li 3,'O' ; add 3,3,28 ; bl putc
+	bl clr_ci_bit
+	mr 3,5
+*/
+	b jump_cacheable
+
+
+
+
+# allow the flash chip to be accessed faster
+# initialize the 16550-compatible uart on serial port 1 of the sio
+setup_sio:
+
+	# i/o base address
+	li 3,0 ; oris 3,3,0xf400
+
+	# i/o base address
+	li 3,0 ; oris 3,3,0xf400
+
+	# put x-bus in turbo mode
+	li 4,0xf1 ; stb 4,0x400(3) ; eieio
+
+
+	# select sio serial1
+	li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio
+
+	# set base address to 3f8
+	li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio
+
+	# enable device
+	li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio
+
+	# read ID register: only if it is a PC87427, enable serial2
+	li 4,0x20 ; stb 4,0x2e(3) ; eieio ; lbz 4,0x2f(3) ; cmpdi 4,0xf2 ; bne 0f
+
+	# select sio serial2
+	li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio
+
+	# set base address to 2f8
+	li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio
+
+	# enable device
+	li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio
+
+	# uart @0x2f8
+	addi 3,3,0x2f8
+
+	# disable interrupts, fifo off
+	li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio
+
+	# set serial speed
+	li 4,0x80 ; stb 4,3(3) ; eieio
+	li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio
+
+	# set 8-N-1, set RTS and DTR
+	li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio
+
+	eieio
+
+	addi 3,3,-0x2f8
+
+	# uart @0x3f8
+0:	addi 3,3,0x3f8
+
+	# disable interrupts, fifo off
+	li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio
+
+	# set serial speed
+	li 4,0x80 ; stb 4,3(3) ; eieio
+	li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio
+
+	# set 8-N-1, set RTS and DTR
+	li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio
+
+	eieio
+
+	# save UART base for putc routine
+0:	mr 13,3
+
+	blr
+
+
+
+
+# set the HID registers of the 970 for optimally executing from flash
+setup_cpu:
+
+	/* clear all the HV cruft */
+	li	r0, 0
+	sync
+	mtspr	HID4, r0
+	isync
+
+	/* enable dpm, disable attn insn, enable external mce
+	 * first, try external time base; if clock doesn't run, switch to
+	 * internal */
+	li	r0, 1			/* do the setup for external timebase */
+	rldicl	r0, r0, 44, 0		/* bit 19 has to be set */
+	oris	r0, r0, 0x8000		/* Enable external machine check */
+					/* interrupts (preferred state */
+					/* equals `1'). */
+	sync
+	mtspr	HID0, r0
+	isync
+
+	mftb	r3			/* read the timebase */
+	li	r1, 0x4000		/* wait long enough for the external */
+	mtctr	r1			/* timebase (14MHz) to tick a bit */
+	bdnz	$			/* 0x4000 seems to be enough (for now) */
+	mftb	r4			/* read the timebase a second time */
+	cmpld	r3, r4			/* see if it changed */
+	bne	0f
+	/* timebase did not change, do the setup for internal */
+	rldicl	r0, r0, 19, 1
+	rldicl	r0, r0, 45, 0
+	sync
+	mtspr	HID0, r0
+	isync
+
+0:
+	/* enable insn prefetch, speculative table walks */
+	mfspr	r0, HID1
+	rldicl	r0, r0, 20, 0
+	ori	r0, r0, 0x1002
+	mfsprg	r3, 1			/* read rombase */
+	cmpdi	r3, 0			/* check if running from ram */
+	bne	0f
+	/* running from ram */
+	/* Enable instruction fetch cacheability control */
+	ori	r0, r0, 0x200
+0:
+	rldicl	r0, r0, 44, 0
+	sync
+	mtspr	HID1, r0
+	isync
+
+	/* enable cache parity */
+	mfspr	r0, HID4
+	oris	r0, r0, 0xfff0
+	xoris	r0, r0, 0xfff0
+	sync
+	mtspr	HID4, r0
+	isync
+
+	/* exception offset at 0 */
+	li	r3, 0
+	mtspr	HIOR, r3
+
+	blr
+
+C_ENTRY(proceedInterrupt)
+
+	ld      r3,exception_stack_frame at got(r2)
+	ld	r1,0(r3)
+
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	ld	r14,0x138(r1);
+	mtsrr0	r14
+
+	ld	r14,0x140(r1);
+	mtsrr1	r14
+
+	ld	r14,0x148(r1);
+	mtcr	r14
+
+
+	ld 0,XVECT_M_HANDLER(0)
+	mtctr 0
+
+	ld	r0,0x30(r1); # restore vector number
+	ld	r1,0x38(r1);
+
+	bctr
+
+intHandler2C:
+	mtctr	r1 # save old stack pointer
+	lis	r1,0x4
+	stdu	r1, -0x160(r1)
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	std	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	std	r0,0x30(r1);  # save vector number
+
+	mfctr	r14
+	std	r14,0x38(r1); # save old r1
+
+	mfsrr0	r14
+	std	r14,0x138(r1);
+
+	mfsrr1	r14
+	std	r14,0x140(r1);
+
+	mfcr	r14
+	std	r14,0x148(r1);
+
+	mfxer	r14
+	std	r14,0x150(r1);
+
+	bl toc_init
+
+	ld      r3,exception_stack_frame at got(r2)
+	std     r1,0(r3)
+
+
+	mr 	r3,r0
+	bl .c_interrupt
+
+	ld	r14,0x138(r1);
+	mtsrr0	r14
+
+	ld	r14,0x140(r1);
+	mtsrr1	r14
+
+	ld	r14,0x148(r1);
+	mtcr	r14
+
+	ld	r14,0x150(r1);
+	mtxer	r14
+
+
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	ld	r1,0x38(r1);
+
+	mfsprg	r0,2
+	mtctr	r0
+	mfsprg	r0,3
+	mtlr	r0
+	mfsprg	r0,0
+	rfid
+
+/* Set exception handler for given exception vector.  
+	r3:	exception vector offset
+	r4:	exception handler
+*/
+	.globl .set_exception
+.set_exception:
+	.globl set_exception
+set_exception:
+    ld r4,0x0(r4)
+	.globl .set_exception_asm
+.set_exception_asm:
+	.globl set_exception_asm
+set_exception_asm:
+	std	r4, 0x60(r3)	# fixme diff 1f - 0b
+	blr
+
+
+setup_mem_u3:
+	li 4,0x2000 ; oris 4,4,0xf800
+
+	# MemTimingParam -- CAS lat 2.5 / 4 (read-to-read / read-to-write)
+	lis 3,0x49e1 ; ori 3,3,0xa000 ; stw 3,0x50(4)
+
+	# MRSRegCntl -- CAS lat 2.5
+	li 3,0x6a ; stw 3,0xf0(4)
+
+	# MemBusConfig -- 128 bit bus
+	lis 3,0x8500 ; stw 3,0x190(4)
+
+	# CKDelAdj -- clock delay 75
+	lis 3,0x12c3 ; ori 3,3,0x30cc ; stw 3,0x520(4)
+
+	# IOModeCntl -- no termination on differential and 3-state drivers
+	lis 3,0x0350 ; stw 3,0x530(4)
+
+	li 3,18 ; mtctr 3 ; addi 5,4,0x5f0
+0:	# DQSDelAdj -- read delay offset -10
+	lis 3,0x3d8f ; ori 3,3,0x6000 ; stwu 3,0x10(5)
+
+	# DQSDataDelAdj -- write delay offset -32, write data delay offset +15
+	lis 3,0x380e ; ori 3,3,0x003c ; stwu 3,0x10(5)
+	bdnz 0b
+
+	# MemProgCntl -- set all
+	lis 3,0xc000 ; stw 3,0xe0(4)
+
+	eieio
+
+	blr
+
+
+# read dimm SPDs, program memory size and type
+setup_mem_size:
+	mflr 14
+
+	li 15,0 ; oris 15,15,0xf800 ; li 17,0
+	li 3,0xa0 ; li 4,3 ; li 5,3 ; bl i2c_read
+	mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0
+0:	li 3,0xa2 ; li 4,3 ; li 5,3 ; bl i2c_read
+	cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f
+0:	li 16,0x1e00
+1:	#li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte
+	#mr 3,16 ; bl print_hex
+
+	#li 3,0x20 ; bl print_byte
+	sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00
+	stw 3,0x21c0(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x21e0(15)
+0:	#bl print_hex
+	sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3
+		# slw, not sld, so that empty/bad banks translate into size 0
+	stw 17,0x21d0(15) ; bl add17173 ; stw 17,0x21f0(15)
+	andi. 0,16,2 ; beq 0f ; bl add17173
+0:	#bl print_hex
+
+	li 3,0xa4 ; li 4,3 ; li 5,3 ; bl i2c_read
+	mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0
+0:	li 3,0xa6 ; li 4,3 ; li 5,3 ; bl i2c_read
+	cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f
+0:	li 16,0x1e00
+1:	#li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte
+	#mr 3,16 ; bl print_hex
+
+	#li 3,0x20 ; bl print_byte
+	sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00
+	stw 3,0x2200(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x2220(15)
+0:	#bl print_hex
+	sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3
+	stw 17,0x2210(15) ; bl add17173 ; stw 17,0x2230(15)
+	andi. 0,16,2 ; beq 0f ; bl add17173
+0:	#bl print_hex
+	#mr 3,17 ; bl print_hex
+	stw 17,0x2250(15) ; stw 17,0x2270(15)
+	stw 17,0x2290(15) ; stw 17,0x22b0(15)
+
+	mtlr 14
+	blr
+
+
+
+
+# print GPR3 as 8-digit hex.  uses GPR18,19
+print_hex:
+	mflr 18 ; mr 19,3 ; li 3,8 ; mtctr 3
+1:	rlwinm 3,19,4,28,31 ; sldi 19,19,4
+	cmpdi 3,0xa ; blt 0f ; addi 3,3,0x27
+0:	addi 3,3,0x30 ; bl putc
+	bdnz 1b ; mtlr 18 ; blr
+
+
+# i2c stuff uses GPR20..GPR24
+
+# terminate any i2c transaction, at any point during that transaction
+i2c_stop:
+0:	lwz 3,0x30(20) ; stw 3,0x30(20) ; andi. 3,3,4 ; beq 0b
+	mr 3,21 ; mr 4,22 ; mtlr 24 ; eieio ; blr
+
+# do a combined-mode read
+# in: GPR3 = addr, GPR4 = subaddr, GPR5 = len
+# out: GPR3 = error, GPR4 = result (right-aligned, msb)
+i2c_read:
+	mflr 24
+	li 20,0x1000 ; oris 20,20,0xf800	# uni-n i2c base
+	mr 21,3 ; mr 22,4 ; mr 23,5		# save params
+	li 4,0xc ; stw 4,0(20)			# set mode (combined)
+	ori 4,21,1 ; stw 4,0x50(20)		# set addr, read
+	stw 22,0x60(20)				# set subaddr
+	li 4,2 ; stw 4,0x10(20) ; eieio		# start address phase
+	li 21,1					# error
+	li 22,0					# result accumulator
+0:	lwz 3,0x30(20) ; andi. 3,3,2 ; beq 0b	# wait until sent
+	lwz 3,0x20(20) ; andi. 3,3,2 ; beq i2c_stop # check result
+	li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0
+0:	stw 4,0x10(20)				# AAK for next byte (or not)
+	li 4,2 ; stw 4,0x30(20) ; eieio		# ack address phase
+i2c_read_loop:
+	lwz 3,0x30(20) ; andi. 3,3,1 ; beq 1f	# if byte recv'd:
+	subi 23,23,1 ; sldi 22,22,8		# shift byte accum
+	lwz 3,0x70(20) ; rlwimi 22,3,0,24,31	# get byte
+	cmpdi 23,0 ; bne 0f ; li 21,0 ; b i2c_stop # all done
+0:	li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0
+0:      stw 4,0x10(20)				# AAK for next byte (or not)
+	li 4,1 ; stw 4,0x30(20) ; eieio		# ack data phase
+1:	lwz 3,0x30(20) ; andi. 3,3,4 ; beq i2c_read_loop
+	li 4,0 ; stw 4,0x10(20) ; eieio ; b i2c_stop # stop bit received
+
+add17173: # add GPR3 into GPR17; if passing 2GB (0x10000000), add another 2GB.
+	lis 0,0x1000 ; cmpld 17,0 ; add 17,17,3 ; bgtlr
+	cmpld 17,0 ; blelr ; add 17,17,0 ; blr
+
+io_log_init:
+	LOAD64(r3, SB_NVRAM_adr)
+	b checkinitLog
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/llfw/u4mem.c b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/u4mem.c
new file mode 100644
index 0000000..c3e6494
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/llfw/u4mem.c
@@ -0,0 +1,4062 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <stdint.h>
+#include <hw.h>
+#include <stdio.h>
+#include "stage2.h"
+#include <cpu.h>
+#include <string.h>
+
+/*
+ * compiler switches
+ *******************************************************************************
+ */
+#define U4_DEBUG
+#define U4_INFO
+//#define U4_SHOW_REGS
+
+int io_getchar(char *);
+
+/*
+ * version info
+ */
+static const uint32_t VER    = 2;
+static const uint32_t SUBVER = 1;
+
+/*
+ * local macros
+ *******************************************************************************
+ */
+// bit shifting in Motorola/IBM bit enumeration format (yaks...)
+#define IBIT( nr )		( (uint32_t) 0x80000000 >> (nr) )
+#define BIT( nr )		( (uint32_t) 0x1 << (nr) )
+
+/*
+ * macros to detect the current board layout
+ */
+#define IS_MAUI		( ( load8_ci( 0xf4000682 ) >> 4 ) == 0 )
+#define IS_BIMINI		( ( load8_ci( 0xf4000682 ) >> 4 ) == 1 )
+#define IS_KAUAI		( ( load8_ci( 0xf4000682 ) >> 4 ) == 2 )
+
+/*
+ * local constants
+ *******************************************************************************
+ */
+
+/*
+ * u4 base address
+ */
+#define U4_BASE_ADDR		((uint64_t) 0xf8000000 )
+#define u4reg( reg )		(U4_BASE_ADDR + (uint64_t) (reg))
+
+/*
+ * I2C registers
+ */
+#define I2C_MODE_R		u4reg(0x1000)
+#define I2C_CTRL_R		u4reg(0x1010)
+#define I2C_STAT_R		u4reg(0x1020)
+#define I2C_ISR_R		u4reg(0x1030)
+#define I2C_ADDR_R		u4reg(0x1050)
+#define I2C_SUBA_R		u4reg(0x1060)
+#define I2C_DATA_R		u4reg(0x1070)
+
+/*
+ * clock control registers & needed bits/masks
+ */
+#define ClkCntl_R		u4reg(0x0800)
+#define PLL2Cntl_R		u4reg(0x0860)
+
+/*
+ * clock control bits & masks
+ */
+#define CLK_DDR_CLK_MSK		(IBIT(11) | IBIT(12) | IBIT(13))
+
+/*
+ * memory controler registers
+ */
+#define RASTimer0_R		u4reg(0x2030)
+#define RASTimer1_R		u4reg(0x2040)
+#define CASTimer0_R		u4reg(0x2050)
+#define CASTimer1_R		u4reg(0x2060)
+#define MemRfshCntl_R		u4reg(0x2070)
+#define MemProgCntl_R		u4reg(0x20b0)
+#define Dm0Cnfg_R		u4reg(0x2200)
+#define Dm1Cnfg_R		u4reg(0x2210)
+#define Dm2Cnfg_R		u4reg(0x2220)
+#define Dm3Cnfg_R		u4reg(0x2230)
+#define MemWrQCnfg_R		u4reg(0x2270)
+#define MemArbWt_R		u4reg(0x2280)
+#define UsrCnfg_R		u4reg(0x2290)
+#define MemRdQCnfg_R		u4reg(0x22a0)
+#define MemQArb_R		u4reg(0x22b0)
+#define MemRWArb_R		u4reg(0x22c0)
+#define MemBusCnfg_R		u4reg(0x22d0)
+#define MemBusCnfg2_R		u4reg(0x22e0)
+#define ODTCntl_R        	u4reg(0x23a0)
+#define MemModeCntl_R		u4reg(0x2500)
+#define MemPhyModeCntl_R 	u4reg(0x2880)
+#define CKDelayL_R		u4reg(0x2890)
+#define CKDelayU_R		u4reg(0x28a0)
+#define IOPadCntl_R      	u4reg(0x29a0)
+#define ByteWrClkDelC0B00_R	u4reg(0x2800)
+#define ByteWrClkDelC0B01_R	u4reg(0x2810)
+#define ByteWrClkDelC0B02_R	u4reg(0x2820)
+#define ByteWrClkDelC0B03_R	u4reg(0x2830)
+#define ByteWrClkDelC0B04_R	u4reg(0x2900)
+#define ByteWrClkDelC0B05_R	u4reg(0x2910)
+#define ByteWrClkDelC0B06_R	u4reg(0x2920)
+#define ByteWrClkDelC0B07_R	u4reg(0x2930)
+#define ByteWrClkDelC0B16_R	u4reg(0x2980)
+#define ByteWrClkDelC0B08_R	u4reg(0x2a00)
+#define ByteWrClkDelC0B09_R	u4reg(0x2a10)
+#define ByteWrClkDelC0B10_R	u4reg(0x2a20)
+#define ByteWrClkDelC0B11_R	u4reg(0x2a30)
+#define ByteWrClkDelC0B12_R	u4reg(0x2b00)
+#define ByteWrClkDelC0B13_R	u4reg(0x2b10)
+#define ByteWrClkDelC0B14_R	u4reg(0x2b20)
+#define ByteWrClkDelC0B15_R	u4reg(0x2b30)
+#define ByteWrClkDelC0B17_R	u4reg(0x2b80)
+#define ReadStrobeDelC0B00_R	u4reg(0x2840)
+#define ReadStrobeDelC0B01_R	u4reg(0x2850)
+#define ReadStrobeDelC0B02_R	u4reg(0x2860)
+#define ReadStrobeDelC0B03_R	u4reg(0x2870)
+#define ReadStrobeDelC0B04_R	u4reg(0x2940)
+#define ReadStrobeDelC0B05_R	u4reg(0x2950)
+#define ReadStrobeDelC0B06_R	u4reg(0x2960)
+#define ReadStrobeDelC0B07_R	u4reg(0x2970)
+#define ReadStrobeDelC0B16_R	u4reg(0x2990)
+#define ReadStrobeDelC0B08_R	u4reg(0x2a40)
+#define ReadStrobeDelC0B09_R	u4reg(0x2a50)
+#define ReadStrobeDelC0B10_R	u4reg(0x2a60)
+#define ReadStrobeDelC0B11_R	u4reg(0x2a70)
+#define ReadStrobeDelC0B12_R	u4reg(0x2b40)
+#define ReadStrobeDelC0B13_R	u4reg(0x2b50)
+#define ReadStrobeDelC0B14_R	u4reg(0x2b60)
+#define ReadStrobeDelC0B15_R	u4reg(0x2b70)
+#define ReadStrobeDelC0B17_R	u4reg(0x2b90)
+#define MemInit00_R		u4reg(0x2100)
+#define MemInit01_R		u4reg(0x2110)
+#define MemInit02_R		u4reg(0x2120)
+#define MemInit03_R		u4reg(0x2130)
+#define MemInit04_R		u4reg(0x2140)
+#define MemInit05_R		u4reg(0x2150)
+#define MemInit06_R		u4reg(0x2160)
+#define MemInit07_R		u4reg(0x2170)
+#define MemInit08_R		u4reg(0x2180)
+#define MemInit09_R		u4reg(0x2190)
+#define MemInit10_R		u4reg(0x21a0)
+#define MemInit11_R		u4reg(0x21b0)
+#define MemInit12_R		u4reg(0x21c0)
+#define MemInit13_R		u4reg(0x21d0)
+#define MemInit14_R		u4reg(0x21e0)
+#define MemInit15_R		u4reg(0x21f0)
+#define CalConf0_R		u4reg(0x29b0)
+#define CalConf1_R		u4reg(0x29c0)
+#define MeasStatusC0_R		u4reg(0x28f0)
+#define MeasStatusC1_R		u4reg(0x29f0)
+#define MeasStatusC2_R		u4reg(0x2af0)
+#define MeasStatusC3_R		u4reg(0x2bf0)
+#define CalC0_R			u4reg(0x28e0)
+#define CalC1_R			u4reg(0x29e0)
+#define CalC2_R			u4reg(0x2ae0)
+#define CalC3_R			u4reg(0x2be0)
+#define RstLdEnVerniersC0_R	u4reg(0x28d0)
+#define RstLdEnVerniersC1_R	u4reg(0x29d0)
+#define RstLdEnVerniersC2_R	u4reg(0x2ad0)
+#define RstLdEnVerniersC3_R	u4reg(0x2bd0)
+#define ExtMuxVernier0_R	u4reg(0x28b0)
+#define ExtMuxVernier1_R	u4reg(0x28c0)
+#define OCDCalCmd_R		u4reg(0x2300)
+#define OCDCalCntl_R		u4reg(0x2310)
+#define MCCR_R      		u4reg(0x2440)
+#define MSRSR_R     		u4reg(0x2410)
+#define MSRER_R     		u4reg(0x2420)
+#define MSPR_R      		u4reg(0x2430)
+#define MSCR_R      		u4reg(0x2400)
+#define MEAR0_R			u4reg(0x2460)
+#define MEAR1_R			u4reg(0x2470)
+#define MESR_R			u4reg(0x2480)
+#define MRSRegCntl_R		u4reg(0x20c0)
+#define EMRSRegCntl_R		u4reg(0x20d0)
+#define APIMemRdCfg_R		u4reg(0x30090)
+#define APIExcp_R		u4reg(0x300a0)
+
+/*
+ * common return values
+ */
+#define RET_OK			 0
+#define RET_ERR			-1
+#define RET_ACERR_CE		-1
+#define RET_ACERR_UEWT		-2
+#define RET_ACERR_UE		-3
+
+/*
+ * 'DIMM slot populated' indicator
+ */
+#define SL_POP			1
+
+/*
+ * spd buffer size
+ */
+#define SPD_BUF_SIZE		0x40
+
+/*
+ * maximum number of DIMM banks & DIMM groups
+ */
+#define NUM_SLOTS		8
+#define NUM_BANKS		( NUM_SLOTS / 2 )
+#define MAX_DGROUPS		( NUM_SLOTS / 2 )
+#define SLOT_ADJ()		( ( IS_MAUI ) ? NUM_SLOTS / 4 : NUM_SLOTS / 2 )
+
+/*
+ * values needed for auto calibration
+ */
+#define MAX_DRANKS		NUM_SLOTS
+#define MAX_BLANE		18
+#define MAX_RMD			0xf
+
+/*
+ * maximum number of supported CAS latencies
+ */
+#define NUM_CL			3
+
+/*
+ * min/max supported CL values by U4
+ */
+#define U4_MIN_CL		3
+#define U4_MAX_CL		5
+
+/*
+ * DIMM constants
+ */
+#define DIMM_TYPE_MSK		BIT(0)
+#define DIMM_ORG_x4		BIT(0)
+#define DIMM_ORG_x8		BIT(1)
+#define DIMM_ORG_x16		BIT(2)
+#define DIMM_ORG_MIXx8x16	BIT(30)
+#define DIMM_ORG_UNKNOWN	0
+#define DIMM_WIDTH		72
+#define DIMM_BURSTLEN_4		BIT(2)
+
+/*
+ * L2 cache size
+ */
+#define L2_CACHE_SIZE		(uint32_t) 0x100000
+
+/*
+ * scrub types
+ */
+#define	IMMEDIATE_SCRUB			IBIT(0)
+#define	IMMEDIATE_SCRUB_WITH_FILL	( IBIT(0) | IBIT(1) )
+#define	BACKGROUND_SCRUB		( IBIT(1) | ( 0x29 << 16 ) )
+
+/*
+ * I2C starting slave addresses of the DIMM banks
+ */
+#define I2C_START		0x50
+
+/*
+ * Index to the speed dependend DIMM settings
+ */
+enum
+{
+	SPEED_IDX_400 = 0,
+	SPEED_IDX_533,
+	SPEED_IDX_667,
+	NUM_SPEED_IDX
+};
+
+/*
+ * number of read/write strobes of the U4
+ */
+#define NUM_STROBES 		18
+
+/*
+ * 2GB hole definition
+ */
+static const uint64_t _2GB = (uint64_t) 0x80000000;
+
+/*
+ * local types
+ *******************************************************************************
+ */
+/*
+ * DIMM definition
+ */
+typedef struct
+{
+	uint32_t m_pop_u32;		// set if bank is populated
+	uint32_t m_bank_u32;		// bank number
+	uint32_t m_clmsk_u32;		// mask of supported CAS latencies
+	uint32_t m_clcnt_u32;		// number of supporetd CAS latencies
+	uint32_t m_clval_pu32[NUM_CL];	// values of supporeted CAS latencies
+	uint32_t m_speed_pu32[NUM_CL];	// speed (Mhz) at CAS latency of same index
+	uint32_t m_size_u32;		// chip size in Mb
+	uint32_t m_rank_u32;		// # of ranks, total size = chip size*rank
+	uint32_t m_orgmsk_u32;		// data organisation (x4, x8, x16) (mask)
+	uint32_t m_orgval_u32;		// data organisation (value)
+	uint32_t m_width_u32;		// data width
+	uint32_t m_ecc_u32;             // set if ecc
+	uint32_t m_type_u32;		// rdimm or udimm
+	uint32_t m_burst_u32;		// supported burst lengths
+	uint32_t m_bankcnt_u32;		// number of banks
+
+	/*
+	 * the following timing values are all in 1/100ns
+	 */
+	uint32_t m_tCK_pu32[NUM_CL];
+	uint32_t m_tRAS_u32;
+	uint32_t m_tRTP_u32;
+	uint32_t m_tRP_u32;
+	uint32_t m_tWR_u32;
+	uint32_t m_tRRD_u32;
+	uint32_t m_tRC_u32;
+	uint32_t m_tRCD_u32;
+	uint32_t m_tWTR_u32;
+	uint32_t m_tREF_u32;
+	uint32_t m_tRFC_u32;
+}	dimm_t;
+
+/*
+ * DIMM group definition
+ */
+typedef struct
+{
+	uint32_t  m_size_u32;		// group size in MB
+	uint32_t  m_start_u32;		// in 128Mb granularity
+	uint32_t  m_end_u32;		// in 128Mb granularity
+	uint32_t  m_ss_u32;		// single sided/double sided
+	uint32_t  m_csmode_u32;		// selected CS mode for this group
+	uint32_t  m_add2g_u32;
+	uint32_t  m_sub2g_u32;
+	uint32_t  m_memmd_u32;		// selected mem mode for this group
+	uint32_t  m_dcnt_u32;		// number of DIMMs in group
+	dimm_t   *m_dptr[NUM_SLOTS];
+}	dgroup_t;
+
+/*
+ * auto calibration result structure
+ */
+typedef struct
+{
+	uint32_t m_MemBusCnfg_u32;
+	uint32_t m_MemBusCnfg2_u32;
+	uint32_t m_RstLdEnVerniers_pu32[4];
+}	auto_calib_t;
+
+/*
+ * ECC error structure
+ */
+typedef struct
+{
+	int32_t  m_err_i32;
+	uint32_t m_uecnt_u32;		// number of uncorrectable errors
+	uint32_t m_cecnt_u32;		// number of correctable errors
+	uint32_t m_rank_u32;		// erroneous rank
+	uint32_t m_col_u32;		// erroneous column
+	uint32_t m_row_u32;		// erroneous row
+	uint32_t m_bank_u32;		// erroneous bank
+}	eccerror_t;
+
+/*
+ * U4 register setup structure
+ */
+typedef struct
+{
+	/*
+	 * external MUX delays
+	 */
+	uint32_t RRMux;
+	uint32_t WRMux;
+	uint32_t WWMux;
+	uint32_t RWMux;
+
+	/*
+	 * default Wr/Rd Queue & Arbiter register settings
+	 */
+	uint32_t MemRdQCnfg;
+	uint32_t MemWrQCnfg;
+	uint32_t MemQArb;
+	uint32_t MemRWArb;
+
+	/*
+	 * misc fixed register values
+	 */
+	uint32_t ODTCntl;
+	uint32_t IOPadCntl;
+	uint32_t MemPhyModeCntl;
+	uint32_t OCDCalCntl;
+	uint32_t OCDCalCmd;
+	uint32_t CKDelayL;
+	uint32_t CKDelayU;
+	uint32_t MemBusCnfg;
+	uint32_t CAS1Dly0;
+	uint32_t CAS1Dly1;
+	uint32_t ByteWrClkDel[NUM_STROBES];
+	uint32_t ReadStrobeDel[NUM_STROBES];
+} reg_statics_t;
+
+/*
+ * local variables
+ *******************************************************************************
+ */
+static dimm_t	 m_dimm[NUM_SLOTS];
+static dimm_t	 m_gendimm;
+static uint32_t  m_dcnt_u32;
+static dimm_t   *m_dptr[NUM_SLOTS];
+static uint32_t  m_bankoff_u32;
+static uint32_t	 m_bankpop_u32[NUM_BANKS];
+static uint32_t  m_dclidx_u32;
+static uint32_t  m_dgrcnt_u32;
+static dgroup_t  m_dgroup[MAX_DGROUPS];
+static dgroup_t *m_dgrptr[MAX_DGROUPS];
+static uint64_t  m_memsize_u64;	// memsize in bytes
+
+/*
+ * local functions
+ *******************************************************************************
+ */
+static void
+progbar( void )
+{
+	static uint8_t  bar[] =
+			{ '|', '/', '-', '\\', 0 };
+	static uint32_t idx = 0;
+
+	printf( "\b%c", bar[idx] );
+
+	if( bar[++idx] == 0 ) {
+		idx = 0;
+	}
+
+}
+
+static void
+or32_ci( uint64_t r, uint32_t m )
+{
+	uint32_t v;
+
+	v  = load32_ci( r );
+	v |= m;
+	store32_ci( r, v );
+}
+
+static void
+and32_ci( uint64_t r, uint32_t m )
+{
+	uint32_t v;
+
+	v  = load32_ci( r );
+	v &= m;
+	store32_ci( r, v );
+}
+
+static void
+dly( uint64_t volatile f_wait_u64 ) \
+{
+	while( f_wait_u64 ) {
+		f_wait_u64--;
+	}
+}
+
+/*
+ * local i2c access functions
+ */
+static void
+i2c_term( void )
+{
+	uint32_t l_stat_u32;
+
+	/*
+	 * clear out all pending int's and wait
+	 * for the stop condition to occur
+	 */
+	do {
+		l_stat_u32 = load32_ci( I2C_ISR_R );
+		store32_ci( I2C_ISR_R, l_stat_u32 );
+	} while( ( l_stat_u32 & IBIT(29) ) == 0 );
+
+}
+
+static int32_t
+i2c_read( uint32_t f_addr_u32, uint32_t f_suba_u32, uint8_t *f_buf_pu08, uint32_t f_len_u32 )
+{
+	uint32_t  l_val_u32;
+	int32_t   l_ret_i32 = 1;
+
+	/*
+	 * parameter check
+	 */
+	if( ( f_addr_u32 > (uint32_t) 0x7f ) ||
+	    ( f_suba_u32 > (uint32_t) 0xff ) ||
+	    ( f_len_u32 == (uint32_t) 0x00 ) ) {
+		return RET_ERR;
+	}
+
+	/*
+	 * set I2C Interface to combined mode
+	 */
+	store32_ci( I2C_MODE_R, IBIT(28) | IBIT(29) );
+
+	/*
+	 * set address, subaddress & read mode
+	 */
+	store32_ci( I2C_ADDR_R, ( f_addr_u32 << 1 ) | (uint32_t) 0x1 );
+	store32_ci( I2C_SUBA_R, f_suba_u32 );
+
+	/*
+	 * start address transmission phase
+	 */
+	store32_ci( I2C_CTRL_R, IBIT(30) );
+
+	/*
+	 * wait for address transmission to finish
+	 */
+	do {
+		l_val_u32 = load32_ci( I2C_ISR_R );
+	} while( ( l_val_u32 & IBIT(30) ) == 0 );
+
+	/*
+	 * check for success
+	 */
+	if( ( load32_ci( I2C_STAT_R ) & IBIT(30) ) == 0 ) {
+		i2c_term();
+		return RET_ERR;
+	} else {
+		// send ack
+		store32_ci( I2C_CTRL_R, IBIT(31) );
+		// clear int
+		store32_ci( I2C_ISR_R, IBIT(30) );
+	}
+
+	/*
+	 * read data
+	 */
+	while( l_ret_i32 > 0 ) {
+		l_val_u32 = load32_ci( I2C_ISR_R );
+
+		if( ( l_val_u32 & IBIT(31) ) != 0 ) {
+			// data was received
+			*f_buf_pu08 = ( uint8_t ) load32_ci( I2C_DATA_R );
+
+			f_buf_pu08++;
+			f_len_u32--;
+
+			/*
+			 * continue when there is more data to read or
+			 * exit if not
+			 */
+			if( f_len_u32 != 0 ) {
+				// send ack
+				store32_ci( I2C_CTRL_R, IBIT(31) );
+				// clear int
+				store32_ci( I2C_ISR_R, IBIT(31) );
+			} else {
+				// send nack
+				store32_ci( I2C_CTRL_R, 0 );
+				// set exit flag
+				l_ret_i32 = RET_OK;
+			}
+
+		} else if( ( l_val_u32 & IBIT(29) ) != 0 ) {
+			// early stop condition
+			// set exit flag
+			l_ret_i32 = RET_ERR;
+		}
+
+	};
+
+	i2c_term();
+
+	return( l_ret_i32 );
+}
+
+static uint32_t
+i2c_get_slot( uint32_t i2c_addr )
+{
+	uint32_t slot;
+
+	slot = ( i2c_addr - I2C_START ) / 2;
+
+	if( ( i2c_addr & 0x1 ) != 0 ) {
+		slot += SLOT_ADJ();
+	}
+
+	return slot;
+}
+
+/*
+ * 'serial presence detect' interpretation functions
+ */
+static uint32_t
+ddr2_get_dimm_rank( uint8_t *f_spd_pu08 )
+{
+	static const int RANK_IDX = (int) 5;
+
+	return (uint32_t) ( f_spd_pu08[RANK_IDX] & 0x3 ) + 1;
+}
+
+static uint32_t
+ddr2_get_dimm_size( uint8_t *f_spd_pu08 )
+{
+	static const int SIZE_IDX   = (int) 31;
+	uint8_t          l_smsk_u08;
+	uint32_t         i;
+
+	l_smsk_u08 = ( f_spd_pu08[SIZE_IDX] << 3 ) |
+		     ( f_spd_pu08[SIZE_IDX] >> 5 );
+
+	for( i = 0; ( ( l_smsk_u08 & ( (uint8_t) 0x1 << i ) ) == 0 ) ; i++ );
+
+	return (uint32_t) 0x80 << i;
+}
+
+static uint32_t
+ddr2_get_dimm_type( uint8_t *f_spd_pu08 )
+{
+	static const int TYPE_IDX = (int) 20;
+
+	return (uint32_t) f_spd_pu08[TYPE_IDX] & DIMM_TYPE_MSK;
+}
+
+static uint32_t
+ddr2_get_dimm_org( uint8_t *f_spd_pu08, uint32_t /*out*/ *f_omsk_pu32 )
+{
+	static const int ORG_IDX   = (int) 13;
+	uint32_t         l_ret_u32 = (uint32_t) f_spd_pu08[ORG_IDX];
+
+	if( l_ret_u32 == 4 ) {
+		*f_omsk_pu32  = DIMM_ORG_x4;
+	} else if( l_ret_u32 == 8 ) {
+		*f_omsk_pu32  = DIMM_ORG_x8;
+		*f_omsk_pu32 |= DIMM_ORG_MIXx8x16;
+	} else if( l_ret_u32 == 16 ) {
+		*f_omsk_pu32  = DIMM_ORG_x16;
+		*f_omsk_pu32 |= DIMM_ORG_MIXx8x16;
+	} else {
+		*f_omsk_pu32  = DIMM_ORG_UNKNOWN;
+		 l_ret_u32    = (uint32_t) ~0;
+	}
+
+	return l_ret_u32;
+}
+
+static uint32_t
+ddr2_get_dimm_width( uint8_t *f_spd_pu08 )
+{
+	static const int WIDTH_IDX = (int) 6;
+
+	return (uint32_t) f_spd_pu08[WIDTH_IDX];
+}
+
+static uint32_t
+ddr2_get_dimm_ecc( uint8_t *f_spd_pu08 )
+{
+	static const int ECC_IDX = (int) 11;
+
+	return ( f_spd_pu08[ECC_IDX] & BIT(1) ) != 0;
+}
+
+static uint32_t
+ddr2_get_dimm_burstlen( uint8_t *f_spd_pu08 )
+{
+	static const int BURST_IDX = (int) 16;
+
+	return (uint32_t) f_spd_pu08[BURST_IDX];
+}
+
+static void
+ddr2_get_dimm_speed( dimm_t *f_dimm, uint8_t *f_spd_pu08 )
+{
+	static const int      SPEED_IDX[] = { 25, 23, 9 };
+	static const uint32_t NS[]        = { 25, 33, 66, 75 };
+	uint8_t               l_tmp_u08;
+	uint32_t	      l_dspeed_u32;
+	uint32_t	      idx = 0;
+	uint32_t	      i;
+
+	for( i = NUM_CL - f_dimm->m_clcnt_u32; i < NUM_CL; i++ ) {
+		l_tmp_u08     = f_spd_pu08[SPEED_IDX[i]];
+		l_dspeed_u32  = (uint32_t) ( l_tmp_u08 >> 4 ) * 100;
+		l_tmp_u08    &= (uint8_t) 0xf;
+
+		if( l_tmp_u08 >= (uint8_t) 10 ) {
+			l_dspeed_u32 += NS[l_tmp_u08 - 10];
+		} else {
+			l_dspeed_u32 += (uint32_t) l_tmp_u08 * 10;
+		}
+
+		f_dimm->m_tCK_pu32[idx]    = l_dspeed_u32;
+		f_dimm->m_speed_pu32[idx]  = (uint32_t) 2000000 / l_dspeed_u32;
+		f_dimm->m_speed_pu32[idx] += (uint32_t) 5;
+		f_dimm->m_speed_pu32[idx] /= (uint32_t) 10;
+		idx++;
+	}
+
+}
+
+static void
+ddr2_get_dimm_timings( dimm_t *f_dimm, uint8_t *f_spd_pu08 )
+{
+	static const uint32_t NS[]  = { 00, 25, 33, 50, 66, 75, 00, 00 };
+	static const uint32_t USMUL = (uint32_t) 390625;
+	static const int tREF_IDX   = (int) 12;
+	static const int tRP_IDX    = (int) 27;
+	static const int tRRD_IDX   = (int) 28;
+	static const int tRCD_IDX   = (int) 29;
+	static const int tRAS_IDX   = (int) 30;
+	static const int tWR_IDX    = (int) 36;
+	static const int tWTR_IDX   = (int) 37;
+	static const int tRTP_IDX   = (int) 38;
+	static const int tRC_IDX    = (int) 41;	// & 40
+	static const int tRFC_IDX   = (int) 42;	// & 40
+
+	uint32_t         l_tmp_u32;
+
+	f_dimm->m_tRP_u32  = (uint32_t) f_spd_pu08[tRP_IDX]  *  25;
+	f_dimm->m_tRRD_u32 = (uint32_t) f_spd_pu08[tRRD_IDX] *  25;
+	f_dimm->m_tRCD_u32 = (uint32_t) f_spd_pu08[tRCD_IDX] *  25;
+	f_dimm->m_tWR_u32  = (uint32_t) f_spd_pu08[tWR_IDX]  *  25;
+	f_dimm->m_tWTR_u32 = (uint32_t) f_spd_pu08[tWTR_IDX] *  25;
+	f_dimm->m_tRTP_u32 = (uint32_t) f_spd_pu08[tRTP_IDX] *  25;
+	f_dimm->m_tRAS_u32 = (uint32_t) f_spd_pu08[tRAS_IDX] * 100;
+
+	l_tmp_u32          = (uint32_t) ( f_spd_pu08[tRC_IDX - 1] >> 4 );
+	l_tmp_u32         &= (uint32_t) 0x7;
+	f_dimm->m_tRC_u32  = (uint32_t) f_spd_pu08[tRC_IDX] * 100 +
+			   		NS[l_tmp_u32];
+
+	l_tmp_u32	    = (uint32_t) f_spd_pu08[tRFC_IDX - 2];
+	l_tmp_u32          &= (uint32_t) 0xf;
+	f_dimm->m_tRFC_u32  = (uint32_t) 256 * ( l_tmp_u32 & (uint32_t) 0x1 );
+	f_dimm->m_tRFC_u32 += (uint32_t) f_spd_pu08[tRFC_IDX];
+	f_dimm->m_tRFC_u32 *= 100;
+	l_tmp_u32         >>= 1;
+	f_dimm->m_tRFC_u32 += NS[l_tmp_u32];
+
+	l_tmp_u32           = (uint32_t) f_spd_pu08[tREF_IDX];
+	l_tmp_u32          &= (uint32_t) 0x7f;
+
+	if( l_tmp_u32 == 0 ) {
+		l_tmp_u32 = (uint32_t) 2;
+	} else if( l_tmp_u32 <= (uint32_t) 2 ) {
+		l_tmp_u32--;
+	}
+
+	f_dimm->m_tREF_u32 = ( l_tmp_u32 + 1 ) * USMUL;
+}
+
+static uint32_t
+ddr2_get_banks( uint8_t *f_spd_pu08 )
+{
+	static const int BANK_IDX = (int) 17;
+
+	return (uint32_t) f_spd_pu08[BANK_IDX];
+}
+
+static uint32_t
+ddr2_get_cl_mask( uint8_t *f_spd_pu08 )
+{
+	static const int CL_IDX = (int) 18;
+
+	return (uint32_t) f_spd_pu08[CL_IDX];
+}
+
+static void
+ddr2_get_cl( dimm_t *f_dimm )
+{
+	uint32_t l_clcnt_u32 = 0;
+	uint32_t i;
+
+	for( i = 0; ( i < 8 ) && ( l_clcnt_u32 < NUM_CL ) ; i++ ) {
+
+		if( ( f_dimm->m_clmsk_u32 & ( (uint32_t) 0x1 << i ) ) != 0 ) {
+			f_dimm->m_clval_pu32[l_clcnt_u32] = i;
+			l_clcnt_u32++;
+		}
+
+	}
+
+	f_dimm->m_clcnt_u32 = l_clcnt_u32;
+}
+
+static uint32_t
+ddr2_cl2speed( dimm_t *f_dimm, uint32_t f_cl_u32, uint32_t *f_tCK_pu32 )
+{
+	uint32_t i;
+
+	for(i = 0; (i < NUM_CL) && (f_dimm->m_clval_pu32[i] != f_cl_u32); i++);
+
+	if( i == NUM_CL ) {
+		return (uint32_t) ~0;
+	}
+
+	*f_tCK_pu32 = f_dimm->m_tCK_pu32[i];
+
+	return f_dimm->m_speed_pu32[i];
+}
+
+static void
+ddr2_setupDIMM( dimm_t *f_dimm, uint32_t f_bank_u32, uint8_t *f_spd_pu08 )
+{
+	f_dimm->m_pop_u32     = SL_POP;
+	f_dimm->m_bank_u32    = f_bank_u32;
+	f_dimm->m_size_u32    = ddr2_get_dimm_size( f_spd_pu08 );
+	f_dimm->m_rank_u32    = ddr2_get_dimm_rank( f_spd_pu08 );
+	f_dimm->m_type_u32    = ddr2_get_dimm_type( f_spd_pu08 );
+	f_dimm->m_orgval_u32  = ddr2_get_dimm_org( f_spd_pu08, &f_dimm->m_orgmsk_u32 );
+	f_dimm->m_width_u32   = ddr2_get_dimm_width( f_spd_pu08 );
+	f_dimm->m_ecc_u32     = ddr2_get_dimm_ecc( f_spd_pu08 );
+	f_dimm->m_burst_u32   = ddr2_get_dimm_burstlen( f_spd_pu08 );
+	f_dimm->m_clmsk_u32   = ddr2_get_cl_mask( f_spd_pu08 );
+	f_dimm->m_bankcnt_u32 = ddr2_get_banks( f_spd_pu08 );
+
+	ddr2_get_cl( f_dimm );
+	ddr2_get_dimm_speed( f_dimm, f_spd_pu08 );
+	ddr2_get_dimm_timings( f_dimm, f_spd_pu08 );
+}
+
+static int32_t
+ddr2_checkSPD( uint8_t *f_spd_pu08 )
+{
+	uint8_t  crc = 0;
+	uint32_t i;
+
+	for( i = 0; i < SPD_BUF_SIZE - 1; i++ ) {
+		crc += f_spd_pu08[i];
+	}
+
+	if( crc != f_spd_pu08[i] ) {
+		return RET_ERR;
+	}
+
+	return RET_OK;
+}
+
+static int32_t
+ddr2_readSPDs( void )
+{
+	static const uint32_t MAX_SPD_FAIL = 3;
+	uint8_t  l_spdbuf_pu08[SPD_BUF_SIZE];
+	uint32_t l_bankfail_u32 = 0;
+	uint32_t l_spdfail_u32  = 0;
+	int32_t  l_i2c_i32      = RET_OK;
+	int32_t  l_spd_i32      = RET_OK;
+	int32_t  ret            = RET_OK;
+	uint32_t i;
+
+	/*
+	 * read spd's and detect populated slots
+	 */
+	for( i = 0; i < NUM_SLOTS; i++ ) {
+		/*
+		 * indicate slot as empty
+		 */
+		m_dimm[i].m_pop_u32 = 0;
+
+		/*
+		 * check whether bank is switched off
+		 */
+		if( ( m_bankoff_u32 & ( 0x1 << ( i / 2 ) ) ) != 0 ) {
+			continue;
+		}
+
+		/*
+		 * read SPD data
+		 */
+
+		/*
+		 * reset SPD fail counter
+		 */
+		l_spdfail_u32 = MAX_SPD_FAIL;
+		l_spd_i32     = RET_OK;
+
+		while( l_spdfail_u32 != 0 ) {
+			l_i2c_i32 = i2c_read( I2C_START + i, 0x0, l_spdbuf_pu08, SPD_BUF_SIZE );
+
+			if( l_i2c_i32 == RET_OK ) {
+				l_spd_i32 = ddr2_checkSPD( l_spdbuf_pu08 );
+
+				if( l_spd_i32 == RET_OK ) {
+					l_spdfail_u32 = 0;
+				} else {
+					l_spdfail_u32--;
+				}
+
+			} else {
+				l_spdfail_u32--;
+			}
+
+		}
+
+		if( l_spd_i32 != RET_OK ) {
+			#ifdef U4_INFO
+			printf( "\r\n  [ERROR -> SPD read failure in slot %u]",
+				i2c_get_slot( I2C_START + i ) );
+			#endif
+
+			l_bankfail_u32 |= ( 0x1 << ( i / 2 ) );
+			ret             = RET_ERR;
+		} else if( l_i2c_i32 == RET_OK ) {
+			/*
+			 * slot is populated
+			 */
+			ddr2_setupDIMM( &m_dimm[i], i / 2, l_spdbuf_pu08 );
+
+			m_dptr[m_dcnt_u32] = &m_dimm[i];
+			m_dcnt_u32++;
+		}
+
+	}
+
+	if( ret != RET_OK ) {
+		m_bankoff_u32 |= l_bankfail_u32;
+		#ifdef U4_INFO
+		printf( "\r\n" );
+		#endif
+	}
+
+	return ret;
+}
+
+static int32_t
+ddr2_setupDIMMcfg( void )
+{
+	uint32_t  l_tmp_u32;
+	uint32_t  l_tmp0_u32;
+	uint32_t  l_tmp1_u32;
+	uint32_t  i, j, e, b;
+
+	/*
+	 * check wether on board DIMM slot population is valid
+	 */
+	e = 0;
+	b = 0;
+	for( i = 0; i < NUM_SLOTS; i += 2 ) {
+
+		switch( m_dimm[i].m_pop_u32 + m_dimm[i+1].m_pop_u32 ) {
+			case 0: {
+				m_bankpop_u32[i/2] = 0;
+				break;
+			}
+
+			case 2 * SL_POP: {
+				m_bankpop_u32[i/2] = !0;
+				b++;
+				break;
+			}
+
+			default: {
+				#ifdef U4_DEBUG
+				printf( "\r\n  [ERROR -> only 1 DIMM installed in bank %u]", i/2 );
+				#endif
+				e++;
+			}
+
+		}
+
+	}
+
+	/*
+	 * return on error
+	 */
+	if( e != 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	if( b == 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n  [ERROR -> no (functional) memory installed]\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * check DIMM compatibility
+	 * configuration is 128 bit data/128 bit bus
+	 * -all DIMMs must be organized as x4
+	 * -all DIMMs must be 72 bit wide with ECC
+	 * -all DIMMs must be registered DIMMs (RDIMMs)
+	 * -paired DIMMs must have the same # of ranks, size & organization
+	 */
+
+	/*
+	 * check DIMM ranks & sizes
+	 */
+	e = 0;
+	for( i = 0; i < NUM_SLOTS; i += 2 ) {
+
+		if( (   m_bankpop_u32[i/2]   != 0	               ) &&
+		    ( ( m_dimm[i].m_rank_u32 != m_dimm[i+1].m_rank_u32 ) ||
+		      ( m_dimm[i].m_size_u32 != m_dimm[i+1].m_size_u32 ) ) ) {
+			#ifdef U4_DEBUG
+			printf( "\r\n  [ERROR -> installed DIMMs in bank %u have different ranks/sizes]", i/2 );
+			#endif
+			e++;
+		}
+
+	}
+
+	/*
+	 * return on error
+	 */
+	if( e != 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * check valid DIMM organisation (must be x4)
+	 */
+	e = 0;
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+
+		if( ( m_dptr[i]->m_orgmsk_u32 & DIMM_ORG_x4 ) == 0 ) {
+			#ifdef U4_DEBUG
+			printf( "\r\n  [ERROR -> wrong DIMM organisation in bank %u]",
+				m_dptr[i]->m_bank_u32 );
+			#endif
+			e++;
+		}
+
+	}
+
+	/*
+	 * return on error
+	 */
+	if( e != 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	e = (uint32_t) ~0;
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+		e &= m_dptr[i]->m_type_u32;
+	}
+
+	/*
+	 * return on error
+	 */
+	if( e == 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n  [ERROR -> installed DIMMs are of different type]\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * setup generic dimm
+	 */
+	m_gendimm.m_type_u32 = e;
+
+	/*
+	 * check valid width, ecc & burst length
+	 */
+	e = 0;
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+
+		if( m_dptr[i]->m_width_u32 != DIMM_WIDTH ) {
+			#ifdef U4_DEBUG
+			printf( "\r\n  [ERROR -> invalid DIMM width in bank %u]",
+				m_dptr[i]->m_bank_u32 );
+			#endif
+			e++;
+		}
+
+		if( m_dptr[i]->m_ecc_u32 == 0 ) {
+			#ifdef U4_DEBUG
+			printf( "\r\n  [ERROR -> DIMM(s) do not support ECC in bank %u]",
+				m_dptr[i]->m_bank_u32 );
+			#endif
+			e++;
+		}
+
+		if( ( m_dptr[i]->m_burst_u32 & DIMM_BURSTLEN_4 ) == 0 ) {
+			#ifdef U4_DEBUG
+			printf( "\r\n  [ERROR -> DIMM(s) have invalid burst length in bank %u]",
+				m_dptr[i]->m_bank_u32 );
+			#endif
+			e++;
+		}
+
+	}
+
+	/*
+	 * return on error
+	 */
+	if( e != 0 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * setup generic dimm
+	 */
+	m_gendimm.m_width_u32 = m_dptr[0]->m_width_u32;
+	m_gendimm.m_ecc_u32   = m_dptr[0]->m_ecc_u32;
+	m_gendimm.m_burst_u32 = m_dptr[0]->m_burst_u32;
+
+	/*
+	 * success
+	 */
+	m_gendimm.m_pop_u32 = SL_POP;
+
+	/*
+	 * setup timing parameters
+	 */
+
+	/*
+	 * find smallest common CL value
+	 */
+	l_tmp_u32 = (uint32_t) ~0;
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+		l_tmp_u32 &= m_dptr[i]->m_clmsk_u32;
+	}
+
+	m_gendimm.m_clmsk_u32 = l_tmp_u32;
+	ddr2_get_cl( &m_gendimm );
+
+	/*
+	 * find fastest common DIMM speed for all common CL values
+	 */
+	for( i = 0; i < m_gendimm.m_clcnt_u32; i++ ) {
+		m_gendimm.m_speed_pu32[i] = (uint32_t) ~0;
+
+		for( j = 0; j < m_dcnt_u32; j++ ) {
+			l_tmp0_u32 =
+			ddr2_cl2speed( m_dptr[j],
+				       m_gendimm.m_clval_pu32[i],
+				       &l_tmp1_u32 );
+
+			if( m_gendimm.m_speed_pu32[i] > l_tmp0_u32 ) {
+				m_gendimm.m_speed_pu32[i] = l_tmp0_u32;
+				m_gendimm.m_tCK_pu32[i]   = l_tmp1_u32;
+			}
+
+		}
+
+	}
+
+	/*
+	 * check wether cl values are supported by U4
+	 */
+	for( i = 0; i < m_gendimm.m_clcnt_u32; i++ ) {
+
+		if( ( m_gendimm.m_clval_pu32[i] >= U4_MIN_CL ) &&
+		    ( m_gendimm.m_clval_pu32[i] <= U4_MAX_CL ) ) {
+			break;
+		}
+
+	}
+
+	if( i == m_gendimm.m_clcnt_u32 ) {
+		#ifdef U4_DEBUG
+		printf( "\r\n  [ERROR -> DIMM's CL values not supported]\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * choose cl/speed values to use: prefer speed over CL
+	 * i holds smallest supported cl value of u4 already
+	 */
+	l_tmp_u32 = 0;
+	while( i < m_gendimm.m_clcnt_u32 ) {
+
+		if( l_tmp_u32 < m_gendimm.m_speed_pu32[i] ) {
+			l_tmp_u32    = m_gendimm.m_speed_pu32[i];
+			m_dclidx_u32 = i;
+		}
+
+		i++;
+	}
+
+	/*
+	 * choose largest number of banks
+	 */
+	m_gendimm.m_bankcnt_u32 = 0;
+
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+
+		if( m_gendimm.m_bankcnt_u32 < m_dptr[i]->m_bankcnt_u32 ) {
+			m_gendimm.m_bankcnt_u32 = m_dptr[i]->m_bankcnt_u32;
+		}
+
+	}
+
+	/*
+	 * setup fastest possible timing parameters for all DIMMs
+	 */
+	m_gendimm.m_tRP_u32  = 0;
+	m_gendimm.m_tRRD_u32 = 0;
+	m_gendimm.m_tRCD_u32 = 0;
+	m_gendimm.m_tWR_u32  = 0;
+	m_gendimm.m_tWTR_u32 = 0;
+	m_gendimm.m_tRTP_u32 = 0;
+	m_gendimm.m_tRAS_u32 = 0;
+	m_gendimm.m_tRC_u32  = 0;
+	m_gendimm.m_tRFC_u32 = 0;
+	m_gendimm.m_tREF_u32 = (uint32_t) ~0;
+
+	for( i = 0; i < m_dcnt_u32; i++ ) {
+
+		if( m_gendimm.m_tRP_u32  < m_dptr[i]->m_tRP_u32  ) {
+			m_gendimm.m_tRP_u32  = m_dptr[i]->m_tRP_u32;
+		}
+
+		if( m_gendimm.m_tRRD_u32 < m_dptr[i]->m_tRRD_u32 ) {
+			m_gendimm.m_tRRD_u32 = m_dptr[i]->m_tRRD_u32;
+		}
+
+		if( m_gendimm.m_tRCD_u32 < m_dptr[i]->m_tRCD_u32 ) {
+			m_gendimm.m_tRCD_u32 = m_dptr[i]->m_tRCD_u32;
+		}
+
+		if( m_gendimm.m_tWR_u32  < m_dptr[i]->m_tWR_u32  ) {
+			m_gendimm.m_tWR_u32  = m_dptr[i]->m_tWR_u32;
+		}
+
+		if( m_gendimm.m_tWTR_u32 < m_dptr[i]->m_tWTR_u32 ) {
+			m_gendimm.m_tWTR_u32 = m_dptr[i]->m_tWTR_u32;
+		}
+
+		if( m_gendimm.m_tRTP_u32 < m_dptr[i]->m_tRTP_u32 ) {
+			m_gendimm.m_tRTP_u32 = m_dptr[i]->m_tRTP_u32;
+		}
+
+		if( m_gendimm.m_tRAS_u32 < m_dptr[i]->m_tRAS_u32 ) {
+			m_gendimm.m_tRAS_u32 = m_dptr[i]->m_tRAS_u32;
+		}
+
+		if( m_gendimm.m_tRC_u32  < m_dptr[i]->m_tRC_u32  ) {
+			m_gendimm.m_tRC_u32  = m_dptr[i]->m_tRC_u32;
+		}
+
+		if( m_gendimm.m_tRFC_u32 < m_dptr[i]->m_tRFC_u32 ) {
+			m_gendimm.m_tRFC_u32 = m_dptr[i]->m_tRFC_u32;
+		}
+
+		if( m_gendimm.m_tREF_u32 > m_dptr[i]->m_tREF_u32 ) {
+			m_gendimm.m_tREF_u32 = m_dptr[i]->m_tREF_u32;
+		}
+
+	}
+
+	return RET_OK;
+}
+
+static void
+u4_group2dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -at least 2 slots are populated
+	 * -the 2 DIMMs are equal
+	 * -DIMMs are double sided (2 ranks)
+	 *
+	 * RESULT:
+	 * 1 group of 2 ranks (2 ranks/2 DIMMs)
+	 * -> CS mode 1 (one double sided DIMM pair)
+	 */
+	l_dgr->m_size_u32   = 2 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 0;
+	l_dgr->m_csmode_u32 = 1;
+	l_dgr->m_dcnt_u32   = 2;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+
+	m_dgrcnt_u32++;
+}
+
+static void
+u4_group2dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -at least 2 slots are populated
+	 * -the 2 DIMMs are equal
+	 * -DIMMs are single sided (1 rank)
+	 *
+	 * RESULT:
+	 * 1 group of 1 rank (1 rank/2 DIMMs)
+	 * -> CS mode 0 (one single sided DIMM pair)
+	 */
+	l_dgr->m_size_u32   = 2 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 1;
+	l_dgr->m_csmode_u32 = 0;
+	l_dgr->m_dcnt_u32   = 2;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+
+	m_dgrcnt_u32++;
+}
+
+static void
+u4_group4dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1,
+		  dimm_t *f_dimm2, dimm_t *f_dimm3 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -4 slots are populated
+	 * -all 4 DIMMs are equal
+	 * -DIMMs are double sided (2 ranks)
+	 *
+	 * RESULT:
+	 * 1 group of 4 ranks (2 ranks/2 DIMMs)
+	 * -> CS mode 2 (two double sided DIMM pairs)
+	 */
+	l_dgr->m_size_u32   = 4 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 0;
+	l_dgr->m_csmode_u32 = 2;
+	l_dgr->m_dcnt_u32   = 4;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+	l_dgr->m_dptr[2]    = f_dimm2;
+	l_dgr->m_dptr[3]    = f_dimm3;
+
+	m_dgrcnt_u32++;
+}
+
+static void
+u4_group4dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1,
+		  dimm_t *f_dimm2, dimm_t *f_dimm3 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -4 slots are populated
+	 * -all 4 DIMMs are equal
+	 * -DIMMs are single sided (1 rank)
+	 *
+	 * RESULT:
+	 * 1 group of 2 ranks (1 rank/2 DIMMs)
+	 * -> CS mode 1 (two single sided DIMM pairs)
+	 */
+	l_dgr->m_size_u32   = 4 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 1;
+	l_dgr->m_csmode_u32 = 1;
+	l_dgr->m_dcnt_u32   = 4;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+	l_dgr->m_dptr[2]    = f_dimm2;
+	l_dgr->m_dptr[3]    = f_dimm3;
+
+	m_dgrcnt_u32++;
+}
+
+static void
+u4_group8dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1,
+		  dimm_t *f_dimm2, dimm_t *f_dimm3,
+		  dimm_t *f_dimm4, dimm_t *f_dimm5,
+		  dimm_t *f_dimm6, dimm_t *f_dimm7 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -8 slots are populated
+	 * -all 8 DIMMs are equal
+	 * -DIMMs are double sided (2 ranks)
+	 *
+	 * RESULT:
+	 * 1 group of 8 ranks (2 ranks/2 DIMMs)
+	 * -> CS mode 3 (four double sided DIMM pairs)
+	 */
+	l_dgr->m_size_u32   = 8 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 0;
+	l_dgr->m_csmode_u32 = 3;
+	l_dgr->m_dcnt_u32   = 8;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+	l_dgr->m_dptr[2]    = f_dimm2;
+	l_dgr->m_dptr[3]    = f_dimm3;
+	l_dgr->m_dptr[4]    = f_dimm4;
+	l_dgr->m_dptr[5]    = f_dimm5;
+	l_dgr->m_dptr[6]    = f_dimm6;
+	l_dgr->m_dptr[7]    = f_dimm7;
+
+	m_dgrcnt_u32++;
+}
+
+static void
+u4_group8dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1,
+		  dimm_t *f_dimm2, dimm_t *f_dimm3,
+		  dimm_t *f_dimm4, dimm_t *f_dimm5,
+		  dimm_t *f_dimm6, dimm_t *f_dimm7 )
+{
+	dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32];
+
+	/*
+	 * known conditions at this point:
+	 * -8 slots are populated
+	 * -all 8 DIMMs are equal
+	 * -DIMMs are single sided (1 rank)
+	 *
+	 * RESULT:
+	 * 1 group of 4 ranks (1 rank/2 DIMMs)
+	 * -> CS mode 2 (four single sided DIMM pairs)
+	 */
+	l_dgr->m_size_u32   = 8 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 );
+	l_dgr->m_ss_u32     = 1;
+	l_dgr->m_csmode_u32 = 2;
+	l_dgr->m_dcnt_u32   = 8;
+	l_dgr->m_dptr[0]    = f_dimm0;
+	l_dgr->m_dptr[1]    = f_dimm1;
+	l_dgr->m_dptr[2]    = f_dimm2;
+	l_dgr->m_dptr[3]    = f_dimm3;
+	l_dgr->m_dptr[4]    = f_dimm4;
+	l_dgr->m_dptr[5]    = f_dimm5;
+	l_dgr->m_dptr[6]    = f_dimm6;
+	l_dgr->m_dptr[7]    = f_dimm7;
+
+	m_dgrcnt_u32++;
+}
+
+static int32_t
+u4_Dcmp( dimm_t *f_dimm0, dimm_t *f_dimm1 )
+{
+
+	if( ( f_dimm0->m_size_u32 == f_dimm1->m_size_u32 ) &&
+	    ( f_dimm0->m_rank_u32 == f_dimm1->m_rank_u32 ) ) {
+		return RET_OK;
+	}
+
+	return RET_ERR;
+}
+
+static void
+u4_group1banks( uint32_t *bidx )
+{
+	uint32_t didx = 2 * bidx[0];
+
+	/*
+	 * known conditions at this point:
+	 * -either DIMMs 0 & 4 or
+	 *	   DIMMs 1 & 5 or
+	 *	   DIMMs 2 & 6 or
+	 *	   DIMMs 3 & 7 are populated
+	 * -3 (bimini)/1 (maui) pair of slots is empty
+	 * -installed DIMMs are equal
+	 */
+
+	/*
+	 * double/single sided setup
+	 */
+	if( m_dimm[didx].m_rank_u32 == 1 ) {
+		u4_group2dimmsSS( &m_dimm[didx], &m_dimm[didx+1] );
+	} else {
+		u4_group2dimmsDS( &m_dimm[didx], &m_dimm[didx+1] );
+	}
+
+}
+
+static void
+u4_group2banks( uint32_t *bidx )
+{
+	uint32_t didx0 = 2 * bidx[0];
+	uint32_t didx1 = 2 * bidx[1];
+
+	/*
+	 * known conditions at this point:
+	 * -4 slots are populated
+	 */
+
+	/*
+	 * check wether DIMM banks may be grouped
+	 */
+	if( ( ( ( bidx[0] + bidx[1] ) & 0x1 )           != 0 ) &&
+	    ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx1] ) == 0 ) ) {
+		/*
+		 * double/single sided setup
+		 * NOTE: at this point all DIMMs have the same amount
+		 * of ranks, therefore only the # of ranks on DIMM 0 is checked
+		 */
+		if( m_dimm[didx0].m_rank_u32 == 1 ) {
+			u4_group4dimmsSS( &m_dimm[didx0], &m_dimm[didx0+1],
+					  &m_dimm[didx1], &m_dimm[didx1+1]);
+		} else {
+			u4_group4dimmsDS( &m_dimm[didx0], &m_dimm[didx0+1],
+					  &m_dimm[didx1], &m_dimm[didx1+1]);
+		}
+
+	} else {
+		u4_group1banks( &bidx[0] );
+		u4_group1banks( &bidx[1] );
+	}
+
+}
+
+static void
+u4_group3banks( uint32_t *bidx )
+{
+
+	if(        ( bidx[0] == 0 ) && ( bidx[1] == 1 ) ) {
+		u4_group2banks( &bidx[0] );
+		u4_group1banks( &bidx[2] );
+	} else if( ( bidx[1] == 2 ) && ( bidx[2] == 3 ) ) {
+		u4_group2banks( &bidx[1] );
+		u4_group1banks( &bidx[0] );
+	}
+
+}
+
+static void
+u4_group4banks( uint32_t *bidx )
+{
+	uint32_t didx0 = 2 * bidx[0];
+	uint32_t didx1 = 2 * bidx[1];
+	uint32_t didx2 = 2 * bidx[2];
+	uint32_t didx3 = 2 * bidx[3];
+
+	if( ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx1] ) == RET_OK ) &&
+	    ( u4_Dcmp( &m_dimm[didx2], &m_dimm[didx3] ) == RET_OK ) &&
+	    ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx2] ) == RET_OK ) ) {
+
+		if( m_dimm[didx0].m_rank_u32 == 1 ) {
+			u4_group8dimmsSS( &m_dimm[didx0], &m_dimm[didx0+1],
+					  &m_dimm[didx1], &m_dimm[didx1+1],
+					  &m_dimm[didx2], &m_dimm[didx2+1],
+					  &m_dimm[didx3], &m_dimm[didx3+1] );
+		} else {
+			u4_group8dimmsDS( &m_dimm[didx0], &m_dimm[didx0+1],
+					  &m_dimm[didx1], &m_dimm[didx1+1],
+					  &m_dimm[didx2], &m_dimm[didx2+1],
+					  &m_dimm[didx3], &m_dimm[didx3+1] );
+		}
+
+	} else {
+		u4_group2banks( &bidx[0] );
+		u4_group2banks( &bidx[2] );
+	}
+
+}
+
+static void
+u4_sortDIMMgroups( void )
+{
+	uint32_t i, j;
+
+	/*
+	 * setup global group pointers
+	 */
+	for( i = 0; i < m_dgrcnt_u32; i++ ) {
+		m_dgrptr[i] = &m_dgroup[i];
+	}
+
+	/*
+	 * use a simple bubble sort to sort groups by size (descending)
+	 */
+	for( i = 0; i < ( m_dgrcnt_u32 - 1 ); i++ ) {
+
+		for( j = i + 1; j < m_dgrcnt_u32; j++ ) {
+
+			if( m_dgrptr[i]->m_size_u32 < m_dgrptr[j]->m_size_u32 ) {
+				dgroup_t *l_sgr;
+
+				l_sgr       = m_dgrptr[i];
+				m_dgrptr[i] = m_dgrptr[j];
+				m_dgrptr[j] = l_sgr;
+			}
+
+		}
+
+	}
+
+}
+
+static void
+u4_calcDIMMcnfg( void )
+{
+	static const uint32_t _2GB  = (uint32_t) 0x00800;
+	static const uint32_t _4GB  = (uint32_t) 0x01000;
+	static const uint32_t _64GB = (uint32_t) 0x10000;
+	uint32_t l_start_u32        = (uint32_t) 0;
+	uint32_t l_end_u32          = (uint32_t) 0;
+	uint32_t l_add2g_u32        = (uint32_t) 1;
+	uint32_t l_sub2g_u32        = (uint32_t) 1;
+	uint32_t i;
+
+	/*
+	 * setup DIMM group parameters
+	 */
+	for( i = 0; i < m_dgrcnt_u32; i++ ) {
+		l_end_u32 = l_start_u32 + m_dgrptr[i]->m_size_u32;
+
+		if( m_dgrptr[i]->m_size_u32 > _2GB ) {
+
+			if( l_end_u32 < _64GB ) {
+				l_add2g_u32 = ( l_end_u32 >> 11 );
+			} else {
+				l_add2g_u32 = 1;
+			}
+
+			if( l_start_u32 == 0 ) {
+				l_sub2g_u32 = 1;
+			} else {
+				l_sub2g_u32 = ( l_start_u32 >> 11 );
+			}
+
+		} else if( l_add2g_u32 != 1 ) {
+			l_start_u32 += _2GB;
+			l_end_u32   += _2GB;
+			l_add2g_u32  = 1;
+			l_sub2g_u32  = 1;
+		}
+
+		/*
+		 * save values for the group
+		 */
+		m_dgrptr[i]->m_start_u32 = ( l_start_u32 >> 7 ); // = /128
+		m_dgrptr[i]->m_end_u32   = ( l_end_u32   >> 7 );
+		m_dgrptr[i]->m_add2g_u32 = l_add2g_u32;
+		m_dgrptr[i]->m_sub2g_u32 = l_sub2g_u32;
+
+		/*
+		 * continue with next group
+		 */
+		if( l_end_u32 != _2GB ) {
+			l_start_u32 = l_end_u32;
+		} else {
+			l_start_u32 = _4GB;
+		}
+
+	}
+
+}
+
+static int32_t
+u4_calcDIMMmemmode( void )
+{
+	static const uint32_t MAX_ORG  = (uint32_t) 0x10;
+	static const uint32_t MIN_BASE = (uint32_t) 0x80;
+	static const uint32_t MAX_MODE = (uint32_t) 0x10;
+	static const uint32_t MODE_ADD = (uint32_t) 0x04;
+	dimm_t   *l_dptr;
+	uint32_t  l_modeoffs_u32;
+	uint32_t  l_sizebase_u32;
+	int32_t	  ret = RET_OK;
+	uint32_t  i, j;
+
+	/*
+	 * loop through all DIMM groups and calculate memmode setting
+	 */
+	for( i = 0; i < m_dgrcnt_u32; i++ ) {
+		l_dptr = m_dgrptr[i]->m_dptr[0]; // all dimms in one group are equal!
+
+		l_modeoffs_u32  = MAX_ORG / l_dptr->m_orgval_u32;
+		l_modeoffs_u32 /= (uint32_t) 2;
+		l_sizebase_u32  = ( MIN_BASE << l_modeoffs_u32 );
+
+		j = 0;
+		while( ( l_sizebase_u32 != l_dptr->m_size_u32 ) &&
+		       ( j               < MAX_MODE           ) ) {
+			l_sizebase_u32 <<= 1;
+			j += (uint32_t) MODE_ADD;
+		}
+
+		// return on error
+		if( j >= MAX_MODE ) {
+			#ifdef U4_INFO
+			uint32_t b, k, l;
+			printf( "\r\n  [ERROR -> unsupported memory type in bank(s)" );
+
+			l = 0;
+			for( k = 0; k < m_dgrptr[i]->m_dcnt_u32; k++ ) {
+				b = m_dgrptr[i]->m_dptr[k]->m_bank_u32;
+
+				if( ( l & ( 1 << b ) ) == 0 ) {
+					printf( " %u", b );
+					l |= ( 1 << b );
+				}
+
+			}
+
+			printf( "]\r\n" );
+			#endif
+
+			ret = RET_ERR;
+		} else {
+			m_dgrptr[i]->m_memmd_u32 = l_modeoffs_u32 + j;
+		}
+
+	}
+
+	return ret;
+}
+
+static void
+u4_setupDIMMgroups( void )
+{
+	static const uint64_t _1MB = (uint64_t) 0x100000;
+	uint32_t l_bcnt_u32;
+	uint32_t l_bidx_u32[NUM_BANKS];
+	uint32_t i;
+
+	/*
+	 * calculate number of populated banks
+	 * IMPORTANT: array must be in ascending order!
+	 */
+	l_bcnt_u32 = 0;
+	for( i = 0; i < NUM_BANKS; i++ ) {
+
+		if( m_bankpop_u32[i] != 0 ) {
+			l_bidx_u32[l_bcnt_u32] = i;
+			l_bcnt_u32++;
+		}
+
+	}
+
+	switch( l_bcnt_u32 ) {
+		case 4: u4_group4banks( &l_bidx_u32[0] ); break;
+		case 3: u4_group3banks( &l_bidx_u32[0] ); break;
+		case 2: u4_group2banks( &l_bidx_u32[0] ); break;
+		case 1: u4_group1banks( &l_bidx_u32[0] ); break;
+	}
+
+	/*
+	 * sort DIMM groups by size (descending)
+	 */
+	u4_sortDIMMgroups();
+
+	/*
+	 * calculate overall memory size in bytes
+	 * (group size is in MB)
+	 */
+	m_memsize_u64 = 0;
+	for( i = 0; i < m_dgrcnt_u32; i++ ) {
+		m_memsize_u64 += (uint64_t) m_dgrptr[i]->m_size_u32 * _1MB;
+	}
+
+}
+
+static int32_t
+u4_setup_core_clock( void )
+{
+	static const uint32_t MCLK = (uint32_t) 266;
+	static const uint32_t CDIV = (uint32_t) 66;
+	static const uint32_t CMAX = (uint32_t) 7;
+	static const uint32_t MERR = (uint32_t) 10;
+	uint32_t volatile     l_cclk_u32;
+	uint32_t volatile     l_pll2_u32;
+	uint32_t              i, s;
+
+	#ifdef U4_INFO
+	printf( "  [core clock reset:          ]" );
+	#endif
+
+	/*
+	 * calculate speed value
+	 */
+	s  = m_gendimm.m_speed_pu32[m_dclidx_u32];
+	s -= MCLK;
+	s /= CDIV;
+
+	/*
+	 * insert new core clock value
+	 */
+	l_cclk_u32  = load32_ci( ClkCntl_R );
+	l_cclk_u32 &= ~CLK_DDR_CLK_MSK;
+	l_cclk_u32 |= ( s << 18 );
+
+
+	// return on error
+	if( s > CMAX ) {
+		#ifdef U4_INFO
+		printf( "\b\b\b\bERR\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * reset core clock
+	 */
+	store32_ci( ClkCntl_R, l_cclk_u32 );
+	dly( 0x1000000 );
+	or32_ci( PLL2Cntl_R, IBIT(0) );
+	dly( 0x1000000 );
+
+	/*
+	 * wait for reset to finish
+	 */
+	do {
+		l_pll2_u32 = load32_ci( PLL2Cntl_R );
+	} while( ( l_pll2_u32 & IBIT(0) ) != 0 );
+
+	/*
+	 * wait for stable PLL
+	 */
+	s = 0;
+	do {
+		l_pll2_u32  = ( load32_ci( PLL2Cntl_R ) & IBIT(2) );
+
+		for( i = 0; i < 4; i++ ) {
+			l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) );
+			l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) );
+			l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) );
+			dly( 0x10000 );
+		}
+
+	} while( ( l_pll2_u32 == 0 ) && ( s++ < MERR ) );
+
+	if( s >= MERR ) {
+		#ifdef U4_INFO
+		printf( "\b\b\b\bERR\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+	#endif
+
+	return RET_OK;
+}
+
+static void
+u4_auto_calib_init( void )
+{
+	static const uint32_t SEQ[] = {
+		0xb1000000, 0xd1000000, 0xd1000000, 0xd1000000,
+		0xd1000000, 0xd1000000, 0xd1000000, 0xd1000000,
+		0xd1000000, 0xd1000000, 0xd1000000, 0xd1000000,
+		0xd1000000, 0xd1000000, 0xd1000400, 0x00000000,
+	};
+
+	uint64_t i;
+	uint32_t j;
+
+	for( i = MemInit00_R, j = 0; i <= MemInit15_R; i += 0x10, j++ ) {
+		store32_ci( i, SEQ[j] );
+	}
+
+}
+
+#if 0
+static uint32_t
+u4_RSL_BLane( uint32_t f_Rank_u32, uint32_t f_BLane_u32 )
+{
+	static const uint32_t MemProgCntl_V = (uint32_t) 0x80000500;
+	static const uint32_t CalConf0_V    = (uint32_t) 0x0000aa10;
+	uint32_t l_MemProgCntl_u32;
+	uint32_t l_CalConf0_u32;
+	uint32_t l_MeasStat_u32;
+	uint32_t l_CalC_u32;
+	uint64_t MeasStat_R;
+	uint64_t CalC_R;
+	uint64_t VerC_R;
+	uint32_t shft;
+	uint32_t v;
+
+	if( f_BLane_u32 < 4 ) {
+		MeasStat_R   = MeasStatusC0_R;
+		CalC_R       = CalC0_R;
+		VerC_R       = RstLdEnVerniersC0_R;
+	} else if( f_BLane_u32  <  8 ) {
+		f_BLane_u32 -= 4;
+		MeasStat_R   = MeasStatusC1_R;
+		CalC_R       = CalC1_R;
+		VerC_R       = RstLdEnVerniersC1_R;
+	} else if( f_BLane_u32  < 12 ) {
+		f_BLane_u32 -= 8;
+		MeasStat_R   = MeasStatusC2_R;
+		CalC_R       = CalC2_R;
+		VerC_R       = RstLdEnVerniersC2_R;
+	} else if( f_BLane_u32 == 16 ) {
+		f_BLane_u32  = 4;
+		MeasStat_R   = MeasStatusC1_R;
+		CalC_R       = CalC1_R;
+		VerC_R       = RstLdEnVerniersC1_R;
+	} else if( f_BLane_u32 == 17 ) {
+		f_BLane_u32  = 4;
+		MeasStat_R   = MeasStatusC3_R;
+		CalC_R       = CalC3_R;
+		VerC_R       = RstLdEnVerniersC3_R;
+	} else {
+		f_BLane_u32 -= 12;
+		MeasStat_R   = MeasStatusC3_R;
+		CalC_R       = CalC3_R;
+		VerC_R       = RstLdEnVerniersC3_R;
+	}
+
+	shft = (uint32_t) 28 - ( f_BLane_u32 * 4 );
+
+	/*
+	 * start auto calibration logic & wait for completion
+	 */
+	or32_ci( MeasStat_R, IBIT(0) );
+
+	do {
+		l_MeasStat_u32 = load32_ci( MeasStat_R );
+	} while( ( l_MeasStat_u32 & IBIT(0) ) == 1 );
+
+	l_CalConf0_u32  = CalConf0_V;
+	store32_ci( CalConf0_R, l_CalConf0_u32 );
+
+	for( v = 0x000; v < (uint32_t) 0x100; v++ ) {
+		store32_ci( VerC_R, ( v << 24 ) | ( v << 16 ) );
+
+		l_MemProgCntl_u32  = MemProgCntl_V;
+		l_MemProgCntl_u32 |=
+			( (uint32_t) 0x00800000 >> f_Rank_u32 );
+		store32_ci( MemProgCntl_R, l_MemProgCntl_u32 );
+
+		do {
+			l_MemProgCntl_u32 = load32_ci( MemProgCntl_R );
+		} while( ( l_MemProgCntl_u32 & IBIT(1) ) == 0 );
+
+		l_CalC_u32 = ( ( load32_ci( CalC_R ) >> shft ) &
+			         (uint32_t) 0xf );
+
+		if( l_CalC_u32 != (uint32_t) 0xa ) {
+			v--;
+			break;
+		}
+
+	}
+
+	if( v == (uint32_t) 0x100 ) {
+		v = (uint32_t) ~1;
+	}
+
+	return v;
+}
+#endif
+
+static uint32_t
+u4_RMDF_BLane( uint32_t f_Rank_u32, uint32_t f_BLane_u32 )
+{
+	static const uint32_t MemProgCntl_V = (uint32_t) 0x80000f00;
+	static const uint32_t CalConf0_V    = (uint32_t) 0x0000ac10;
+	uint32_t l_MemProgCntl_u32;
+	uint32_t l_CalConf0_u32;
+	uint32_t l_MeasStat_u32;
+	uint32_t l_CalC_u32;
+	uint64_t MeasStat_R;
+	uint64_t CalC_R;
+	uint64_t VerC_R;
+	uint32_t shft;
+	uint32_t v;
+
+	if( f_BLane_u32 < 4 ) {
+		MeasStat_R   = MeasStatusC0_R;
+		CalC_R       = CalC0_R;
+		VerC_R       = RstLdEnVerniersC0_R;
+	} else if( f_BLane_u32  <  8 ) {
+		f_BLane_u32 -= 4;
+		MeasStat_R   = MeasStatusC1_R;
+		CalC_R       = CalC1_R;
+		VerC_R       = RstLdEnVerniersC1_R;
+	} else if( f_BLane_u32  < 12 ) {
+		f_BLane_u32 -= 8;
+		MeasStat_R   = MeasStatusC2_R;
+		CalC_R       = CalC2_R;
+		VerC_R       = RstLdEnVerniersC2_R;
+	} else if( f_BLane_u32 == 16 ) {
+		f_BLane_u32  = 4;
+		MeasStat_R   = MeasStatusC1_R;
+		CalC_R       = CalC1_R;
+		VerC_R       = RstLdEnVerniersC1_R;
+	} else if( f_BLane_u32 == 17 ) {
+		f_BLane_u32  = 4;
+		MeasStat_R   = MeasStatusC3_R;
+		CalC_R       = CalC3_R;
+		VerC_R       = RstLdEnVerniersC3_R;
+	} else {
+		f_BLane_u32 -= 12;
+		MeasStat_R   = MeasStatusC3_R;
+		CalC_R       = CalC3_R;
+		VerC_R       = RstLdEnVerniersC3_R;
+	}
+
+	shft = (uint32_t) 28 - ( f_BLane_u32 * 4 );
+
+	/*
+	 * start auto calibration logic & wait for completion
+	 */
+	or32_ci( MeasStat_R, IBIT(0) );
+
+	do {
+		l_MeasStat_u32 = load32_ci( MeasStat_R );
+	} while( ( l_MeasStat_u32 & IBIT(0) ) == 1 );
+
+	l_CalConf0_u32  = CalConf0_V;
+	l_CalConf0_u32 |= ( f_BLane_u32 << 5 );
+	store32_ci( CalConf0_R, l_CalConf0_u32 );
+
+	for( v = 0x000; v < (uint32_t) 0x100; v++ ) {
+		store32_ci( VerC_R, ( v << 24 ) | ( v << 16 ) );
+
+		l_MemProgCntl_u32  = MemProgCntl_V;
+		l_MemProgCntl_u32 |=
+			( (uint32_t) 0x00800000 >> f_Rank_u32 );
+		store32_ci( MemProgCntl_R, l_MemProgCntl_u32 );
+
+		do {
+			l_MemProgCntl_u32 = load32_ci( MemProgCntl_R );
+		} while( ( l_MemProgCntl_u32 & IBIT(1) ) == 0 );
+
+		l_CalC_u32 = ( ( load32_ci( CalC_R ) >> shft ) &
+			         (uint32_t) 0xf );
+
+		if( l_CalC_u32 != (uint32_t) 0xa ) {
+			v--;
+			break;
+		}
+
+	}
+
+	if( v == (uint32_t) 0x100 ) {
+		v = (uint32_t) ~1;
+	}
+
+	return v;
+}
+
+static int32_t
+u4_RMDF_Rank( uint32_t  f_Rank_u32,
+	      uint32_t *f_Buf_pu32 )
+{
+	int32_t  l_Err_pi32 = 0;
+	uint32_t b;
+
+	for( b = 0; ( b < MAX_BLANE ) && ( l_Err_pi32 == 0 ); b++ ) {
+		f_Buf_pu32[b] = u4_RMDF_BLane( f_Rank_u32, b );
+
+		if( f_Buf_pu32[b] == (uint32_t) ~0 ) {
+			f_Buf_pu32[b] = 0;
+			l_Err_pi32++;
+		} else if( f_Buf_pu32[b] == (uint32_t) ~1 ) {
+			f_Buf_pu32[b] = (uint32_t) 0xff;
+			l_Err_pi32++;
+		}
+
+	}
+
+	return l_Err_pi32;
+}
+
+static int32_t
+u4_auto_calib_MemBus( auto_calib_t *f_ac_pt )
+{
+	uint32_t RdMacDly, RdMacCnt;
+	uint32_t ResMuxDly, ResMuxCnt;
+	uint32_t RdPipeDly;
+	uint32_t l_Buf_pu32[MAX_DRANKS][MAX_BLANE];
+	uint32_t l_Rnk_pu32[MAX_DRANKS];
+	uint32_t l_Ver_u32;
+	int32_t  l_Err_i32;
+	uint32_t bidx;
+	uint32_t n, r, b;
+
+	/*
+	 * read starting delays out of the MemBus register
+	 */
+	RdMacDly  = ( load32_ci( MemBusCnfg_R ) >> 28 ) & 0xf;
+	ResMuxDly = ( load32_ci( MemBusCnfg_R ) >> 24 ) & 0xf;
+
+	/*
+	 * initialize ranks as not populated
+	 */
+	for( r = 0; r < MAX_DRANKS; r++ ) {
+		l_Rnk_pu32[r] = 0;
+	}
+
+	/*
+	 * run through every possible delays of
+	 * RdMacDly, ResMuxDly & RdPipeDly until
+	 * the first working configuration is found
+	 */
+	RdPipeDly = 0;
+	do {
+		and32_ci( MemBusCnfg2_R, ~0x3 );
+		or32_ci(  MemBusCnfg2_R, RdPipeDly );
+
+		RdMacCnt  =  RdMacDly;
+		ResMuxCnt =  ResMuxDly;
+
+		/*
+		 * RdMacDly >= ResMuxDly
+		 */
+		do {
+			and32_ci( MemBusCnfg_R, ( 1 << 24 ) - 1 );
+			or32_ci(  MemBusCnfg_R, ( RdMacCnt  << 28 ) |
+						( ResMuxCnt << 24 ) );
+			and32_ci( MemBusCnfg2_R, ( 1 << 28 ) - 1 );
+			or32_ci(  MemBusCnfg2_R, ( RdMacCnt << 28 ) );
+
+			/*
+			 * check the current value for every installed
+			 * DIMM on each side for every bytelane
+			 */
+			l_Err_i32 = 0;
+			for( n = 0;
+			     ( n < NUM_SLOTS ) &&
+			     ( l_Err_i32 == 0 );
+			     n += 2 ) {
+
+				if( m_dimm[n].m_pop_u32 ) {
+					/*
+					 * run through all 18 bytelanes of every rank
+					 */
+					for( r = n;
+					     ( r < n + m_dimm[n].m_rank_u32 ) &&
+					     ( l_Err_i32 == 0 );
+					     r++ ) {
+						l_Rnk_pu32[r] = 1;
+
+						l_Err_i32 =
+						u4_RMDF_Rank( r,
+							      &l_Buf_pu32[r][0] );
+					}
+
+				}
+
+			}
+
+			/*
+			 * decrementation before exit is wanted!
+			 */
+			RdMacCnt--;
+			ResMuxCnt--;
+		} while( ( ResMuxCnt  > 0 ) &&
+			 ( l_Err_i32 != 0 ) );
+
+		if( l_Err_i32 != 0 ) {
+			RdPipeDly++;
+		}
+
+	} while( ( RdPipeDly   < 4 ) &&
+		 ( l_Err_i32 != 0 ) );
+
+	/*
+	 * if l_Err_pi32 == 0 the auto calibration passed ok
+	 */
+	if( l_Err_i32 != 0 ) {
+		return RET_ERR;
+	}
+
+	/*
+	 * insert delay values into return struct
+	 */
+	and32_ci( MemBusCnfg_R, ( 1 << 24 ) - 1 );
+	or32_ci(  MemBusCnfg_R, ( RdMacCnt  << 28 ) |
+				( ResMuxCnt << 24 ) );
+	and32_ci( MemBusCnfg2_R, ( ( 1 << 28 ) - 1 ) & ~0x3 );
+	or32_ci(  MemBusCnfg2_R, ( RdMacCnt << 28 ) | RdPipeDly );
+
+	f_ac_pt->m_MemBusCnfg_u32  = load32_ci( MemBusCnfg_R );
+	f_ac_pt->m_MemBusCnfg2_u32 = load32_ci( MemBusCnfg2_R );
+
+	/*
+	 * calculate the average vernier setting for the
+	 * bytelanes which share one vernier
+	 */
+	for( b = 0; b < MAX_BLANE - 2; b += 2 ) {
+		n         = 0;
+		l_Ver_u32 = 0;
+
+		for( r = 0; r < MAX_DRANKS; r++ ) {
+			/*
+			 * calculation is done or populated ranks only
+			 */
+			if( l_Rnk_pu32[r] != 0 ) {
+				/*
+				 * calculate average value
+				 */
+				l_Ver_u32 += l_Buf_pu32[r][b];
+				l_Ver_u32 += l_Buf_pu32[r][b+1];
+				n         += 2;
+
+				if( b == 4 ) {
+					l_Ver_u32 += l_Buf_pu32[r][16];
+					n++;
+				} else if( b == 12 ) {
+					l_Ver_u32 += l_Buf_pu32[r][17];
+					n++;
+				}
+
+			}
+
+		}
+
+		/*
+		 * average the values
+		 */
+		l_Ver_u32 /= n;
+
+		/*
+		 * set appropiate vernier register for
+		 * the current bytelane
+		 */
+		bidx = ( b >> 2 );
+		if( ( b & (uint32_t) 0x3 ) == 0 ) {
+			l_Ver_u32 <<= 24;
+			f_ac_pt->m_RstLdEnVerniers_pu32[bidx]  = l_Ver_u32;
+		} else {
+			l_Ver_u32 <<= 16;
+			f_ac_pt->m_RstLdEnVerniers_pu32[bidx] |= l_Ver_u32;
+		}
+
+	}
+
+	return RET_OK;
+}
+
+static int32_t
+u4_auto_calib( auto_calib_t *f_ac_pt )
+{
+	uint32_t l_MemBusCnfg_S;
+	uint32_t l_MemBusCnfg2_S;
+	uint32_t l_RstLdEnVerniers_S[4];
+	int32_t  l_Ret_i32;
+
+	/*
+	 * save manipulated registers
+	 */
+	l_MemBusCnfg_S         = load32_ci( MemBusCnfg_R );
+	l_MemBusCnfg2_S        = load32_ci( MemBusCnfg2_R );
+	l_RstLdEnVerniers_S[0] = load32_ci( RstLdEnVerniersC0_R );
+	l_RstLdEnVerniers_S[1] = load32_ci( RstLdEnVerniersC1_R );
+	l_RstLdEnVerniers_S[2] = load32_ci( RstLdEnVerniersC2_R );
+	l_RstLdEnVerniers_S[3] = load32_ci( RstLdEnVerniersC3_R );
+
+	u4_auto_calib_init();
+	l_Ret_i32 = u4_auto_calib_MemBus( f_ac_pt );
+
+	/*
+	 * restore manipulated registers
+	 */
+	store32_ci( MemBusCnfg_R,  l_MemBusCnfg_S );
+	store32_ci( MemBusCnfg2_R, l_MemBusCnfg2_S );
+	store32_ci( RstLdEnVerniersC0_R, l_RstLdEnVerniers_S[0] );
+	store32_ci( RstLdEnVerniersC1_R, l_RstLdEnVerniers_S[1] );
+	store32_ci( RstLdEnVerniersC2_R, l_RstLdEnVerniers_S[2] );
+	store32_ci( RstLdEnVerniersC3_R, l_RstLdEnVerniers_S[3] );
+
+	return l_Ret_i32;
+}
+
+static int32_t
+u4_checkeccerr( eccerror_t *f_ecc_pt )
+{
+	uint32_t l_val_u32;
+	int32_t  ret = RET_OK;
+
+	l_val_u32   = load32_ci( MESR_R );
+	l_val_u32 >>= 29;
+
+	if( ( l_val_u32 & (uint32_t) 0x7 ) != 0 ) {
+
+		if(        ( l_val_u32 & (uint32_t) 0x4 ) != 0 ) {
+			/* UE */
+			ret = RET_ACERR_UE;
+		} else if( ( l_val_u32 & (uint32_t) 0x1 ) != 0 ) {
+			/* UEWT */
+			ret = RET_ACERR_UEWT;
+		} else {
+			/* CE */
+			ret = RET_ACERR_CE;
+		}
+
+	}
+
+	f_ecc_pt->m_err_i32   = ret;
+
+	l_val_u32             = load32_ci( MEAR1_R );
+	f_ecc_pt->m_uecnt_u32 = ( ( l_val_u32 >> 24 ) & (uint32_t) 0xff );
+	f_ecc_pt->m_cecnt_u32 = ( ( l_val_u32 >> 16 ) & (uint32_t) 0xff );
+
+	l_val_u32             = load32_ci( MEAR0_R );
+	f_ecc_pt->m_rank_u32  = ( ( l_val_u32 >> 29 ) & (uint32_t) 0x7 );
+	f_ecc_pt->m_col_u32   = ( ( l_val_u32 >> 18 ) & (uint32_t) 0x7ff );
+	f_ecc_pt->m_row_u32   = ( ( l_val_u32 >>  0 ) & (uint32_t) 0x7fff );
+	f_ecc_pt->m_bank_u32  = ( ( l_val_u32 >> 15 ) & (uint32_t) 0x7 );
+
+	return ret;
+}
+
+static uint32_t
+u4_CalcScrubEnd( void )
+{
+	uint64_t l_scrend_u64 = m_memsize_u64;
+
+	/*
+	 * check for memory hole at 2GB
+	 */
+	if( l_scrend_u64 > _2GB ) {
+		l_scrend_u64 += _2GB;
+	}
+
+	l_scrend_u64 -= 0x40;
+	l_scrend_u64 /= 0x10;
+
+	return( (uint32_t) l_scrend_u64 );
+}
+
+static int32_t
+u4_Scrub( uint32_t f_scrub_u32, uint32_t f_pattern_u32, eccerror_t *f_eccerr_pt )
+{
+	uint32_t i;
+	int32_t  ret;
+
+	/*
+	 * setup scrub parameters
+	 */
+	store32_ci( MSCR_R, 0 );			// stop scrub
+	store32_ci( MSRSR_R, 0x0 );			// set start
+	store32_ci( MSRER_R, u4_CalcScrubEnd() );	// set end
+	store32_ci( MSPR_R, f_pattern_u32 );		// set pattern
+
+	/*
+	 * clear out ECC error registers
+	 */
+	store32_ci( MEAR0_R, 0x0 );
+	store32_ci( MEAR1_R, 0x0 );
+	store32_ci( MESR_R, 0x0 );
+
+	/*
+	 * Setup Scrub Type
+	 */
+	store32_ci( MSCR_R, f_scrub_u32 );
+
+	if( f_scrub_u32 != BACKGROUND_SCRUB ) {
+		/*
+		 * wait for scrub to complete
+		 */
+		do {
+			progbar();
+			dly( 15000000 );
+			i = load32_ci( MSCR_R );
+		} while( ( i & f_scrub_u32 ) != 0 );
+
+		ret = u4_checkeccerr( f_eccerr_pt );
+	} else {
+		ret = RET_OK;
+	}
+
+	return ret;
+}
+
+static eccerror_t
+u4_InitialScrub( void )
+{
+	eccerror_t l_eccerr_st[2];
+	int32_t    l_err_i32[2] = { 0, 0 };
+
+	l_err_i32[0] = u4_Scrub( IMMEDIATE_SCRUB_WITH_FILL, 0x0, &l_eccerr_st[0] );
+
+	if( l_err_i32[0] >= -1 /*CE*/ ) {
+		l_err_i32[1] = u4_Scrub( IMMEDIATE_SCRUB, 0x0, &l_eccerr_st[1] );
+	}
+
+	if( l_err_i32[0] < l_err_i32[1] ) {
+		return l_eccerr_st[0];
+	} else {
+		return l_eccerr_st[1];
+	}
+
+}
+
+/*
+ * RND: calculates Timer cycles from the given frequency
+ *	devided by the clock frequency. Values are rounded
+ * 	up to the nearest integer value if the division is not even.
+ */
+#define RND( tXXX )	( ( ( tXXX ) + tCK - 1 ) / tCK )
+
+static void
+u4_MemInitSequence( uint32_t tRP, uint32_t tWR, uint32_t tRFC, uint32_t CL,
+		    uint32_t tCK, uint32_t TD )
+{
+	/*
+	 * DIMM init sequence
+	 */
+	static const uint32_t INI_SEQ[] = {
+		0xa0000400, 0x80020000, 0x80030000, 0x80010404,
+		0x8000100a, 0xa0000400, 0x90000000, 0x90000000,
+		0x8ff0100a, 0x80010784, 0x80010404, 0x00000000,
+		0x00000000, 0x00000000, 0x00000000, 0x00000000
+	};
+
+	uint32_t l_MemInit_u32;
+	uint64_t r;
+	uint32_t i;
+
+	for( r = MemInit00_R, i = 0; r <= MemInit15_R; r += 0x10, i++ ) {
+		l_MemInit_u32 = INI_SEQ[i];
+
+		switch( i ) {
+			case 0:
+			case 5: {
+				l_MemInit_u32 |= ( ( RND( tRP ) - TD )  << 20 );
+				break;
+			}
+			case 3: {
+				store32_ci( EMRSRegCntl_R, l_MemInit_u32 &
+							   (uint32_t) 0xffff );
+				break;
+			}
+			case 4: {
+				l_MemInit_u32 |= IBIT(23);
+			}
+			case 8: {
+				l_MemInit_u32 |= ( ( RND( tWR ) - 1 )  <<  9 );
+				l_MemInit_u32 |= ( CL                  <<  4 );
+
+				store32_ci( MRSRegCntl_R, l_MemInit_u32 &
+							  (uint32_t) 0xffff );
+				break;
+			}
+			case 6:
+			case 7: {
+				l_MemInit_u32 |= ( ( RND( tRFC ) - TD ) << 20 );
+				break;
+			}
+
+		}
+
+		store32_ci( r, l_MemInit_u32 );
+
+#ifdef U4_SHOW_REGS
+		printf( "\r\nMemInit%02d (0x%04X): 0x%08X", i, (uint16_t) r, l_MemInit_u32 );
+#endif
+	}
+#ifdef U4_SHOW_REGS
+	printf( "\r\n" );
+#endif
+	/*
+	 * Kick off memory init sequence & wait for completion
+	 */
+	store32_ci( MemProgCntl_R, IBIT(0) );
+
+	do {
+		i = load32_ci( MemProgCntl_R );
+	} while( ( i & IBIT(1) ) == 0 );
+
+}
+
+/*
+ * static DIMM configuartion settings
+ */
+static reg_statics_t reg_statics_maui[NUM_SPEED_IDX] = {
+	{	/* 400 Mhz */
+		.RRMux          = 1,
+		.WRMux          = 1,
+		.WWMux          = 1,
+		.RWMux          = 1,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x60000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x34000000,
+		.CKDelayU       = 0x34000000,
+
+		.MemBusCnfg     = 0x00000050                  |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 2 ) << 24 ) ),
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 533 Mhz */
+		.RRMux          = 1,
+		.WRMux          = 1,
+		.WWMux          = 1,
+		.RWMux          = 1,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x60000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x18000000,
+		.CKDelayU       = 0x18000000,
+
+		.MemBusCnfg     = 0x00002070	              |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 3 ) << 24 ) ),
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+
+			0x12000000, 0x12000000, 0x12000000 , 0x12000000,
+			0x12000000, 0x12000000, 0x12000000 , 0x12000000,
+			0x12000000, 0x12000000, 0x12000000 , 0x12000000,
+			0x12000000, 0x12000000, 0x12000000 , 0x12000000,
+			0x12000000, 0x12000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000 , 0x00000000,
+			0x00000000, 0x00000000, 0x00000000 , 0x00000000,
+			0x00000000, 0x00000000, 0x00000000 , 0x00000000,
+			0x00000000, 0x00000000, 0x00000000 , 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 667 Mhz */
+		.RRMux          = 1,
+		.WRMux          = 1,
+		.WWMux          = 1,
+		.RWMux          = 3,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x60000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x0a000000,
+		.CKDelayU       = 0x0a000000,
+
+		.MemBusCnfg     = 0x000040a0		      |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 3 ) << 24 ) ),
+
+		.CAS1Dly0       = 2,
+		.CAS1Dly1	= 2,
+
+		.ByteWrClkDel   = {
+
+			0x12000000, 0x12000000, 0x12000000, 0x12000000,
+			0x12000000, 0x12000000, 0x12000000, 0x12000000,
+			0x12000000, 0x12000000, 0x12000000, 0x12000000,
+			0x12000000, 0x12000000, 0x12000000, 0x12000000,
+			0x12000000, 0x12000000
+/*
+			0x31000000, 0x31000000, 0x31000000, 0x31000000,
+			0x31000000, 0x31000000, 0x31000000, 0x31000000,
+			0x31000000, 0x31000000, 0x31000000, 0x31000000,
+			0x31000000, 0x31000000, 0x31000000, 0x31000000,
+			0x31000000, 0x31000000
+*/
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	}
+};
+
+static reg_statics_t reg_statics_bimini[NUM_SPEED_IDX] = {
+	{	/* 400 Mhz */
+		.RRMux          = 2,
+		.WRMux          = 2,
+		.WWMux          = 2,
+		.RWMux          = 2,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x40000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x00000000,
+		.CKDelayU       = 0x28000000,
+
+		.MemBusCnfg     = 0x00552070                  |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 2 ) << 24 ) ),
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 533 Mhz */
+		.RRMux          = 3,
+		.WRMux          = 3,
+		.WWMux          = 3,
+		.RWMux          = 3,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x40000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x00000000,
+		.CKDelayU       = 0x20000000,
+
+		.MemBusCnfg     = 0x00644190		      |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 3 ) << 24 ) ),
+
+		.CAS1Dly0       = 2,
+		.CAS1Dly1	= 2,
+
+		.ByteWrClkDel   = {
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 667 Mhz */
+		.RRMux          = 3,
+		.WRMux          = 3,
+		.WWMux          = 3,
+		.RWMux          = 3,
+
+		.MemRdQCnfg     = 0x20020820,
+		.MemWrQCnfg     = 0x40041040,
+		.MemQArb        = 0x00000000,
+		.MemRWArb       = 0x30413cc0,
+
+		.ODTCntl        = 0x40000000,
+		.IOPadCntl      = 0x001a4000,
+		.MemPhyModeCntl = 0x00000000,
+		.OCDCalCntl     = 0x00000000,
+		.OCDCalCmd      = 0x00000000,
+
+		.CKDelayL       = 0x00000000,
+		.CKDelayU       = 0x00000000,
+
+		.MemBusCnfg     = 0x00666270		      |
+				  ( (   MAX_RMD       << 28 ) |
+				    ( ( MAX_RMD - 3 ) << 24 ) ),
+
+		.CAS1Dly0       = 2,
+		.CAS1Dly1	= 2,
+
+		.ByteWrClkDel   = {
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000, 0x14000000, 0x14000000,
+			0x14000000, 0x14000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	}
+};
+
+static reg_statics_t reg_statics_kauai[NUM_SPEED_IDX] = {
+	{	/* 400 Mhz */
+		.RRMux          = 0,
+		.WRMux          = 0,
+		.WWMux          = 0,
+		.RWMux          = 0,
+
+		.MemRdQCnfg     = 0,
+		.MemWrQCnfg     = 0,
+		.MemQArb        = 0,
+		.MemRWArb       = 0,
+
+		.ODTCntl        = 0,
+		.IOPadCntl      = 0,
+		.MemPhyModeCntl = 0,
+		.OCDCalCntl     = 0,
+		.OCDCalCmd      = 0,
+
+		.CKDelayL       = 0,
+		.CKDelayU       = 0,
+
+		.MemBusCnfg     = 0,
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 533 Mhz */
+		.RRMux          = 0,
+		.WRMux          = 0,
+		.WWMux          = 0,
+		.RWMux          = 0,
+
+		.MemRdQCnfg     = 0,
+		.MemWrQCnfg     = 0,
+		.MemQArb        = 0,
+		.MemRWArb       = 0,
+
+		.ODTCntl        = 0,
+		.IOPadCntl      = 0,
+		.MemPhyModeCntl = 0,
+		.OCDCalCntl     = 0,
+		.OCDCalCmd      = 0,
+
+		.CKDelayL       = 0,
+		.CKDelayU       = 0,
+
+		.MemBusCnfg     = 0,
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	},
+	{	/* 667 Mhz */
+		.RRMux          = 0,
+		.WRMux          = 0,
+		.WWMux          = 0,
+		.RWMux          = 0,
+
+		.MemRdQCnfg     = 0,
+		.MemWrQCnfg     = 0,
+		.MemQArb        = 0,
+		.MemRWArb       = 0,
+
+		.ODTCntl        = 0,
+		.IOPadCntl      = 0,
+		.MemPhyModeCntl = 0,
+		.OCDCalCntl     = 0,
+		.OCDCalCmd      = 0,
+
+		.CKDelayL       = 0,
+		.CKDelayU       = 0,
+
+		.MemBusCnfg     = 0,
+
+		.CAS1Dly0       = 0,
+		.CAS1Dly1	= 0,
+
+		.ByteWrClkDel   = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		},
+		.ReadStrobeDel  = {
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			0x00000000, 0x00000000
+		}
+
+	}
+};
+
+static int32_t
+u4_start( eccerror_t *f_ecc_pt )
+{
+	/*
+	 * maximum runs for auto calibration
+	 */
+	static const uint32_t MAX_ACERR	= (uint32_t) 5;
+
+	/*
+	 * fixed u4/DIMM timer/timing values for calculation
+	 */
+	static const uint32_t TD      = (uint32_t) 2;	// u4 delay cycles for loading a timer
+	static const uint32_t AL      = (uint32_t) 0; 	// additional latency (fix)
+	static const uint32_t BL      = (uint32_t) 4; 	// burst length (fix)
+
+	uint32_t	      SPEED   = m_gendimm.m_speed_pu32[m_dclidx_u32];
+	uint32_t              CL      = m_gendimm.m_clval_pu32[m_dclidx_u32];
+	uint32_t              RL      = AL + CL;
+	uint32_t              WL      = RL - 1;
+	uint32_t              tCK     = m_gendimm.m_tCK_pu32[m_dclidx_u32];
+	uint32_t 	      tRAS    = m_gendimm.m_tRAS_u32;
+	uint32_t 	      tRTP    = m_gendimm.m_tRTP_u32;
+	uint32_t 	      tRP     = m_gendimm.m_tRP_u32;
+	uint32_t 	      tWR     = m_gendimm.m_tWR_u32;
+	uint32_t 	      tRRD    = m_gendimm.m_tRRD_u32;
+	uint32_t 	      tRC     = m_gendimm.m_tRC_u32;
+	uint32_t 	      tRCD    = m_gendimm.m_tRCD_u32;
+	uint32_t 	      tWTR    = m_gendimm.m_tWTR_u32;
+	uint32_t	      tRFC    = m_gendimm.m_tRFC_u32;
+	uint32_t	      tREF    = m_gendimm.m_tREF_u32;
+
+	reg_statics_t *rst = 0;
+
+	uint32_t       l_RAS0_u32;
+	uint32_t       l_RAS1_u32;
+	uint32_t       l_CAS0_u32;
+	uint32_t       l_CAS1_u32;
+	uint32_t       l_MemRfshCntl_u32;
+	uint32_t       l_UsrCnfg_u32;
+	uint32_t       l_DmCnfg_u32;
+
+	uint32_t       l_MemArbWt_u32;
+	uint32_t       l_MemRWArb_u32;
+	uint32_t       l_MemBusCnfg_u32;
+
+	auto_calib_t   l_ac_st;
+	int32_t	       l_ac_i32;
+	uint32_t       l_acerr_i32;
+	uint32_t       sidx;
+	uint32_t       i, j, t0, t1;
+
+	/*
+	 * set index for different 400/533/667 Mhz setup
+	 */
+	switch( SPEED ) {
+		case 400:
+		case 533:
+		case 667: {
+			sidx  = SPEED;
+			sidx -= 400;
+			sidx /= 133;
+			break;
+		}
+
+		default: {
+			#ifdef U4_DEBUG2
+			printf( "\r\n-> DIMM speed of %03u not supported\r\n",
+				m_gendimm.m_speed_pu32[m_dclidx_u32]  );
+			#endif
+			return RET_ERR;
+		}
+
+	}
+
+	/*
+	 * setup pointer to the static register settings
+	 */
+	if( IS_MAUI ) {
+		rst = &reg_statics_maui[sidx];
+	} else if( IS_BIMINI ) {
+		rst = &reg_statics_bimini[sidx];
+	} else if( IS_KAUAI ) {
+		rst = &reg_statics_kauai[sidx];
+	}
+
+	/*
+	 * Switch off Fast Path by default for all DIMMs
+	 * running with more than 400Mhz
+	 */
+	if( SPEED == 400 ) {
+		or32_ci( APIMemRdCfg_R, IBIT(30) );
+		#ifdef U4_INFO
+		printf( "  [fastpath        :        ON]\r\n" );
+		#endif
+	} else {
+		and32_ci( APIMemRdCfg_R, ~IBIT(30) );
+		#ifdef U4_INFO
+		printf( "  [fastpath        :       OFF]\r\n" );
+		#endif
+	}
+
+
+	#ifdef U4_INFO
+	printf( "  [register setup  :          ]" );
+	#endif
+
+	/*
+	 * setup RAS/CAS timers2
+	 * NOTE: subtract TD from all values because of the delay
+	 * caused by reloading timers (see spec)
+	 */
+
+	/*
+	 * RAS Timer 0
+	 */
+	// TiAtP = RND(tRAS) -> RAS0[0:4]
+	l_RAS0_u32  = ( ( RND( tRAS )                           - TD ) << 27 );
+	// TiRtP = AL + BL/2 - 2 + RND(tRTP) -> RAS01[5:9]
+	l_RAS0_u32 |= ( ( AL + BL/2 - 2 + RND( tRTP )           - TD ) << 22 );
+	// TiWtP = WL + BL/2 + RND(tWR) -> RAS0[10:14]
+	l_RAS0_u32 |= ( ( WL + BL/2 + RND( tWR )                - TD ) << 17 );
+	// TiPtA = RND(tRP) -> RAS0[15:19]
+	l_RAS0_u32 |= ( ( RND( tRP )                            - TD ) << 12 );
+	// TiPAtA = RND(tRP) or
+	//          RND(tRP) + 1 for 8 bank devices -> RAS0[20:24]
+	if( m_gendimm.m_bankcnt_u32 <= 4 ) {
+		l_RAS0_u32 |= ( ( RND( tRP )                    - TD ) <<  7 );
+	} else {
+		l_RAS0_u32 |= ( ( RND( tRP ) + 1                - TD ) <<  7 );
+	}
+
+	/*
+	 * RAS Timer 1
+	 */
+	// TiRAPtA = AL + BL/2 - 2 + RND(tRTP + tRP) -> RAS1[0:4]
+	l_RAS1_u32  = ( ( AL + BL/2 - 2 + RND( tRTP + tRP )     - TD ) << 27 );
+	// TiWAPtA = CL + AL + BL/2 - 1 + RND(tWR + tRP) -> RAS1[5:9]
+	l_RAS1_u32 |= ( ( CL + AL + BL/2 - 1 + RND( tWR + tRP ) - TD ) << 22 );
+	// TiAtARk = tRRD -> RAS1[10:14]
+	l_RAS1_u32 |= ( ( RND( tRRD )                           - TD ) << 17 );
+	// TiAtABk = tRC -> RAS1[15:19]
+	l_RAS1_u32 |= ( ( RND( tRC )                            - TD ) << 12 );
+	// TiAtRW = tRCD -> RAS1[20:24]
+	l_RAS1_u32 |= ( ( RND( tRCD )                           - TD ) <<  7 );
+	// TiSAtARk Win = 4 * tRRD + 2 -> RAS1[25:29]
+	l_RAS1_u32 |= ( ( RND( 4 * tRRD ) + 2                   - TD ) <<  2 );
+
+	/*
+	 * CAS Timer 0
+	 */
+	// TiRtRRk = BL/2 -> CAS0[0:4]
+	l_CAS0_u32  = ( ( BL/2                                  - TD ) << 27 );
+	// TiRtRDm = BL/2 + 1 -> CAS0[5:9]
+	l_CAS0_u32 |= ( ( BL/2 + 1                              - TD ) << 22 );
+	// TiRtRSy = BL/2 + RRMux -> CAS0[10:14]
+	l_CAS0_u32 |= ( ( BL/2 + rst->RRMux                     - TD ) << 17 );
+	// TiWtRRk = CL - 1 + BL/2 + tWTR ->CAS0[15:19]
+	l_CAS0_u32 |= ( ( CL - 1 + BL/2 + RND( tWTR )           - TD ) << 12 );
+	// TiWtRDm = BL/2 + 1 -> CAS0[20:24]
+	l_CAS0_u32 |= ( ( BL/2 + 1                              - TD ) <<  7 );
+	// TiWtRSy = BL/2 + WRMux -> CAS0[25:29]
+	l_CAS0_u32 |= ( ( BL/2 + rst->WRMux                     - TD ) <<  2 );
+
+	/*
+	 * CAS Timer 1
+	 */
+	// TiWtWRk = BL/2 -> CAS1[0:4]
+	l_CAS1_u32  = ( ( BL/2                                  - TD ) << 27 );
+	// TiWtWDm = BL/2 + 1 -> CAS1[5:9]
+	l_CAS1_u32 |= ( ( BL/2 + 1                              - TD ) << 22 );
+	// TiWtWSy = BL/2 + WWMux -> CAS1[10:14]
+	l_CAS1_u32 |= ( ( BL/2 + rst->WWMux                     - TD ) << 17 );
+	// TiRtWRk = BL/2 + 2 -> CAS1[15:19]
+ 	l_CAS1_u32 |= ( ( BL/2 + 2            + rst->CAS1Dly0   - TD ) << 12 );
+	// TiRtWDm = BL/2 + 2 -> CAS1[20:24]
+	l_CAS1_u32 |= ( ( BL/2 + 2            + rst->CAS1Dly1   - TD ) <<  7 );
+	// TiRtWSy = BL/2 + RWMux + 1 -> CAS1[25:29]
+	l_CAS1_u32 |= ( ( BL/2 + rst->RWMux + 1                 - TD ) <<  2 );
+
+	store32_ci( RASTimer0_R, l_RAS0_u32 );
+	store32_ci( RASTimer1_R, l_RAS1_u32 );
+	store32_ci( CASTimer0_R, l_CAS0_u32 );
+	store32_ci( CASTimer1_R, l_CAS1_u32 );
+
+	/*
+	 * Mem Refresh Control register
+	 */
+	l_MemRfshCntl_u32  = ( ( ( tREF / tCK ) / 16 ) << 23 );
+	l_MemRfshCntl_u32 |= ( ( RND( tRFC )    - TD ) <<  8 );
+	store32_ci( MemRfshCntl_R, l_MemRfshCntl_u32 );
+
+	/*
+	 * setup DmXCnfg registers
+	 */
+	store32_ci( Dm0Cnfg_R, (uint32_t) 0x0 );
+	store32_ci( Dm1Cnfg_R, (uint32_t) 0x0 );
+	store32_ci( Dm2Cnfg_R, (uint32_t) 0x0 );
+	store32_ci( Dm3Cnfg_R, (uint32_t) 0x0 );
+
+	/*
+	 * create DmCnfg & UsrCnfg values out of group data
+	 */
+	l_UsrCnfg_u32 = 0;
+	for( i = 0; i < m_dgrcnt_u32; i++ ) {
+		l_DmCnfg_u32  = ( m_dgrptr[i]->m_add2g_u32 << 27 );
+		l_DmCnfg_u32 |= ( m_dgrptr[i]->m_sub2g_u32 << 19 );
+		l_DmCnfg_u32 |= ( m_dgrptr[i]->m_memmd_u32 << 12 );
+		l_DmCnfg_u32 |= ( m_dgrptr[i]->m_start_u32 <<  3 );
+		l_DmCnfg_u32 |= ( m_dgrptr[i]->m_ss_u32    <<  1 );
+		l_DmCnfg_u32 |= IBIT(31);	// enable bit
+
+		/*
+		 * write value into DmXCnfg registers
+		 */
+		for( j = 0; j < m_dgrptr[i]->m_dcnt_u32; j++ ) {
+			t0 = m_dgrptr[i]->m_dptr[j]->m_bank_u32;
+			t1 = Dm0Cnfg_R + 0x10 * t0;
+
+			if( load32_ci( t1 ) == 0 ) {
+				store32_ci( t1, l_DmCnfg_u32 );
+				l_UsrCnfg_u32 |=
+				( m_dgrptr[i]->m_csmode_u32 << ( 30 - 2 * t0 ) );
+			}
+
+		}
+
+	}
+
+	/*
+	 * setup UsrCnfg register
+	 *- cs mode is selected above
+	 *- Interleave on L2 cache line
+	 *- Usually closed page policy
+	 */
+	l_UsrCnfg_u32 |=  IBIT(8);	// interleave on L2 cache line
+	l_UsrCnfg_u32 &= ~IBIT(9);	// usually closed
+	l_UsrCnfg_u32 |=  IBIT(10);
+	store32_ci( UsrCnfg_R, l_UsrCnfg_u32 );
+
+	/*
+	 * Memory Arbiter Weight Register
+	 */
+	// CohWt  -> MemAWt[0:1]
+	l_MemArbWt_u32  = ( (uint32_t) 1 << 30 );
+	// NCohWt -> MemAWt[2:3]
+	l_MemArbWt_u32 |= ( (uint32_t) 1 << 28 );
+	// ScrbWt -> MemAWt[4:5]
+	l_MemArbWt_u32 |= ( (uint32_t) 0 << 26 );
+	store32_ci( MemArbWt_R, l_MemArbWt_u32 );
+
+	/*
+	 * misc fixed register setup
+	 */
+	store32_ci( ODTCntl_R,        rst->ODTCntl );
+	store32_ci( IOPadCntl_R,      rst->IOPadCntl );
+	store32_ci( MemPhyModeCntl_R, rst->MemPhyModeCntl );
+	store32_ci( OCDCalCntl_R,     rst->OCDCalCntl );
+	store32_ci( OCDCalCmd_R,      rst->OCDCalCmd );
+
+	/*
+	 * CK Delay registers
+	 */
+	store32_ci( CKDelayL_R, rst->CKDelayL );
+	store32_ci( CKDelayU_R, rst->CKDelayU );
+
+	/*
+	 * read/write strobe delays
+	 */
+	store32_ci( ByteWrClkDelC0B00_R, rst->ByteWrClkDel[ 0] );
+	store32_ci( ByteWrClkDelC0B01_R, rst->ByteWrClkDel[ 1] );
+	store32_ci( ByteWrClkDelC0B02_R, rst->ByteWrClkDel[ 2] );
+	store32_ci( ByteWrClkDelC0B03_R, rst->ByteWrClkDel[ 3] );
+	store32_ci( ByteWrClkDelC0B04_R, rst->ByteWrClkDel[ 4] );
+	store32_ci( ByteWrClkDelC0B05_R, rst->ByteWrClkDel[ 5] );
+	store32_ci( ByteWrClkDelC0B06_R, rst->ByteWrClkDel[ 6] );
+	store32_ci( ByteWrClkDelC0B07_R, rst->ByteWrClkDel[ 7] );
+	store32_ci( ByteWrClkDelC0B16_R, rst->ByteWrClkDel[16] );
+	store32_ci( ByteWrClkDelC0B08_R, rst->ByteWrClkDel[ 8] );
+	store32_ci( ByteWrClkDelC0B09_R, rst->ByteWrClkDel[ 9] );
+	store32_ci( ByteWrClkDelC0B10_R, rst->ByteWrClkDel[10] );
+	store32_ci( ByteWrClkDelC0B11_R, rst->ByteWrClkDel[11] );
+	store32_ci( ByteWrClkDelC0B12_R, rst->ByteWrClkDel[12] );
+	store32_ci( ByteWrClkDelC0B13_R, rst->ByteWrClkDel[13] );
+	store32_ci( ByteWrClkDelC0B14_R, rst->ByteWrClkDel[14] );
+	store32_ci( ByteWrClkDelC0B15_R, rst->ByteWrClkDel[15] );
+	store32_ci( ByteWrClkDelC0B17_R, rst->ByteWrClkDel[17] );
+	store32_ci( ReadStrobeDelC0B00_R, rst->ReadStrobeDel[ 0] );
+	store32_ci( ReadStrobeDelC0B01_R, rst->ReadStrobeDel[ 1] );
+	store32_ci( ReadStrobeDelC0B02_R, rst->ReadStrobeDel[ 2] );
+	store32_ci( ReadStrobeDelC0B03_R, rst->ReadStrobeDel[ 3] );
+	store32_ci( ReadStrobeDelC0B04_R, rst->ReadStrobeDel[ 4] );
+	store32_ci( ReadStrobeDelC0B05_R, rst->ReadStrobeDel[ 5] );
+	store32_ci( ReadStrobeDelC0B06_R, rst->ReadStrobeDel[ 6] );
+	store32_ci( ReadStrobeDelC0B07_R, rst->ReadStrobeDel[ 7] );
+	store32_ci( ReadStrobeDelC0B16_R, rst->ReadStrobeDel[16] );
+	store32_ci( ReadStrobeDelC0B08_R, rst->ReadStrobeDel[ 8] );
+	store32_ci( ReadStrobeDelC0B09_R, rst->ReadStrobeDel[ 9] );
+	store32_ci( ReadStrobeDelC0B10_R, rst->ReadStrobeDel[10] );
+	store32_ci( ReadStrobeDelC0B11_R, rst->ReadStrobeDel[11] );
+	store32_ci( ReadStrobeDelC0B12_R, rst->ReadStrobeDel[12] );
+	store32_ci( ReadStrobeDelC0B13_R, rst->ReadStrobeDel[13] );
+	store32_ci( ReadStrobeDelC0B14_R, rst->ReadStrobeDel[14] );
+	store32_ci( ReadStrobeDelC0B15_R, rst->ReadStrobeDel[15] );
+	store32_ci( ReadStrobeDelC0B17_R, rst->ReadStrobeDel[17] );
+
+	/*
+	 * Mem Bus Configuration
+	 * initial setup used in auto calibration
+	 * final values will be written after
+	 * auto calibration has finished
+	 */
+	l_MemBusCnfg_u32  = rst->MemBusCnfg;
+
+/*	values calculation has been dropped, static values are used instead
+	// WdbRqDly = 2 * (CL - 3) (registered DIMMs) -> MBC[16:19]
+	l_MemBusCnfg_u32 += ( ( 2 * ( CL - 3 ) ) << 12 );
+	// RdOEOnDly = 0 (typically)
+	l_MemBusCnfg_u32 += ( ( 0 )              <<  8 );
+	// RdOEOffDly = (2 * CL) - 4 -> MBC[24:27]
+	// NOTE: formula is not working, changed to:
+	// RdOEOffDly = (2 * CL) - 1
+	l_MemBusCnfg_u32 += ( ( ( 2 * CL ) - 1 ) <<  4 );
+*/
+
+	store32_ci( MemBusCnfg_R, l_MemBusCnfg_u32 );
+	store32_ci( MemBusCnfg2_R, rst->MemBusCnfg & (uint32_t) 0xf0000000 );
+
+	/*
+	 * reset verniers registers
+	 */
+	store32_ci( RstLdEnVerniersC0_R, 0x0 );
+	store32_ci( RstLdEnVerniersC1_R, 0x0 );
+	store32_ci( RstLdEnVerniersC2_R, 0x0 );
+	store32_ci( RstLdEnVerniersC3_R, 0x0 );
+	store32_ci( ExtMuxVernier0_R,    0x0 );
+	store32_ci( ExtMuxVernier1_R,    0x0 );
+
+	/*
+	 * Queue Configuration
+	 */
+	store32_ci( MemRdQCnfg_R, rst->MemRdQCnfg );
+	store32_ci( MemWrQCnfg_R, rst->MemWrQCnfg );
+	store32_ci( MemQArb_R,    rst->MemQArb );
+	store32_ci( MemRWArb_R,   rst->MemRWArb );
+
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+	#endif
+
+	/*
+	 * start up clocks & wait for pll2 to stabilize
+	 */
+	#ifdef U4_INFO
+	printf( "  [start DDR clock :          ]" );
+	#endif
+
+	store32_ci( MemModeCntl_R, IBIT(0) | IBIT(8) );
+	dly( 50000000 );
+
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+
+	#endif
+
+	/*
+	 * memory initialization sequence
+	 */
+	#ifdef U4_INFO
+	printf( "  [memory init     :          ]" );
+	#endif
+	u4_MemInitSequence( tRP, tWR, tRFC, CL, tCK, TD );
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+	#endif
+
+	/*
+	 * start ECC before auto calibration to enable ECC bytelane
+	 */
+	store32_ci( MCCR_R, IBIT(0) );
+	dly( 15000000 );
+
+	/*
+	 * start up auto calibration
+	 */
+	#ifdef U4_INFO
+	printf( "  [auto calibration:          ]\b" );
+	#endif
+
+	/*
+	 * start auto calibration
+	*/
+	l_acerr_i32 = 0;
+	do {
+		progbar();
+
+		l_ac_i32 = u4_auto_calib( &l_ac_st );
+
+		if( l_ac_i32 != 0 ) {
+			l_acerr_i32++;
+		}
+
+		dly( 15000000 );
+	} while( ( l_ac_i32    != 0             ) &&
+		 ( l_acerr_i32 <= MAX_ACERR     ) );
+
+	if( l_acerr_i32 > MAX_ACERR ) {
+		#ifdef U4_INFO
+		printf( "\b\b\bERR\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * insert auto calibration results
+	 */
+	store32_ci( MemBusCnfg_R,  	 l_ac_st.m_MemBusCnfg_u32 );
+	store32_ci( MemBusCnfg2_R, 	 l_ac_st.m_MemBusCnfg2_u32 );
+	store32_ci( RstLdEnVerniersC0_R, l_ac_st.m_RstLdEnVerniers_pu32[0] );
+	store32_ci( RstLdEnVerniersC1_R, l_ac_st.m_RstLdEnVerniers_pu32[1] );
+	store32_ci( RstLdEnVerniersC2_R, l_ac_st.m_RstLdEnVerniers_pu32[2] );
+	store32_ci( RstLdEnVerniersC3_R, l_ac_st.m_RstLdEnVerniers_pu32[3] );
+
+	/*
+	 * insert final timing value into MemRWArb
+	 */
+	l_MemRWArb_u32  = ( ( l_ac_st.m_MemBusCnfg_u32 >> 28 /*RdMacDel*/) + 1 );
+	l_MemRWArb_u32 *= 10;	// needed for rounding
+	l_MemRWArb_u32 /= 2;	// due to spec
+	l_MemRWArb_u32 += 9;	// round up
+	l_MemRWArb_u32 /= 10;	// value is rounded now
+	l_MemRWArb_u32  = l_MemRWArb_u32 + 6 - WL - TD;
+	l_MemRWArb_u32 |= rst->MemRWArb;
+	store32_ci( MemRWArb_R, l_MemRWArb_u32 );
+
+	progbar();
+	dly( 15000000 );
+
+	/*
+	 * do initial scrubbing
+	 */
+	*f_ecc_pt = u4_InitialScrub();
+
+	switch( f_ecc_pt->m_err_i32 ) {
+		case  RET_OK: {
+			#ifdef U4_INFO
+			printf( "\b\bOK\r\n" );
+			#endif
+			break;
+		}
+
+		case RET_ACERR_CE: {
+			#ifdef U4_INFO
+			printf( "\b\b\b\bWEAK][correctable errors during scrub (%u)]\r\n",
+				f_ecc_pt->m_cecnt_u32 );
+			#endif
+			break;
+		}
+
+		case RET_ACERR_UEWT:
+		case RET_ACERR_UE: {
+			#ifdef U4_INFO
+			printf( "\b\b\bERR][uncorrectable errors during scrub (%u)]\r\n",
+				f_ecc_pt->m_uecnt_u32 );
+			#endif
+			return RET_ACERR_UE;
+		}
+
+	}
+
+	/*
+	 * start continuous background scrub
+	 */
+	#ifdef U4_INFO
+	printf( "  [background scrub:          ]" );
+	#endif
+
+	u4_Scrub( BACKGROUND_SCRUB, 0, NULL );
+
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+	#endif
+
+	/*
+	 * finally clear API Exception register
+	 * (read to clear)
+	 */
+	load32_ci( APIExcp_R );
+
+	return RET_OK;
+}
+
+#undef RND
+
+void
+u4_memtest(uint8_t argCnt, char *pArgs[], uint64_t flags)
+
+{
+	#define TEND			99
+	#define TCHK			100
+	static const uint64_t _2GB   = (uint64_t) 0x80000000;
+	static const uint64_t _start = (uint64_t) 0x08000000;	// 128Mb
+	static const uint64_t _bsize = (uint64_t) 0x08000000;	// 128MB
+	static const uint64_t _line  = (uint64_t) 128;
+	static const uint64_t _256MB = (uint64_t) 0x10000000;
+
+	static const uint64_t PATTERN[] = {
+		0x9090909090909090, 0x0020002000200020,
+		0x0c0c0c0c0c0c0c0c, 0x8080808080808080,
+		0x1004010004001041, 0x0000000000000000
+	};
+
+     	uint64_t mend      = (uint64_t) 0x200000000;//m_memsize_u64;
+	uint64_t numblocks = ( mend - _start ) / _bsize;	// 128Mb blocks
+	uint64_t numlines  = _bsize / _line;
+	uint64_t tstate    = 0;
+	uint64_t tlast     = 0;
+	uint64_t pidx      = 0;
+	uint64_t rotr      = 0;
+	uint64_t rotl      = 0;
+	uint64_t block;
+	uint64_t line;
+	uint64_t addr;
+	uint64_t i;
+	uint64_t check = 0;
+	uint64_t dcnt;
+	uint64_t uerr = 0;
+	uint64_t cerr = 0;
+	uint64_t merr = 0;
+	char     c;
+
+	printf( "\n\nU4 memory test" );
+	printf( "\n--------------" );
+
+	/*
+	 * mask out UEC & CEC
+	 */
+	or32_ci( MCCR_R, IBIT(6) | IBIT(7) );
+
+	while( PATTERN[pidx] ) {
+
+		switch( tstate )
+		{
+		case 0: {
+			printf( "\npattern fill 0x%08X%08X: ", (uint32_t) (PATTERN[pidx] >> 32), (uint32_t) PATTERN[pidx] );
+
+			/*
+			 * first switch lines, then blocks. This way the CPU
+			 * is not able to cache data
+			 */
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						*( (uint64_t *) addr ) = PATTERN[pidx];
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+							printf( "*" );
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			check  = PATTERN[pidx];
+			tlast  = 0;
+			tstate = TCHK;
+		} 	break;
+
+		case 1: {
+			uint64_t one;
+
+			/*
+			 * new check pattern
+
+			 */
+			one     = ( ( check & 0x1 ) != 0 );
+			check >>= 1;
+			if( one ) {
+				check |= 0x8000000000000000;
+			}
+
+			printf( "\nrotate right 0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check );
+
+			/*
+			 * first switch lines, then blocks. This way the CPU
+			 * is not able to cache data
+			 */
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						*( (uint64_t *) addr ) >>= 1;
+
+						if( one ) {
+							*( (uint64_t *) addr ) |=
+								(uint64_t) 0x8000000000000000;
+						}
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+							printf( "*" );
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			tlast  = 1;
+			tstate = TCHK;
+		}	break;
+
+		case 2: {
+
+			if( rotr < 6 ) {
+				rotr++;
+				tstate = 1;
+			} else {
+				rotr   = 0;
+				tstate = 3;
+			}
+
+		}	break;
+
+		case 3: {
+			/*
+			 * new check pattern
+			 */
+			check ^= (uint64_t) ~0;
+
+			printf( "\ninverting    0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check );
+
+			/*
+			 * first switch lines, then blocks. This way the CPU
+			 * is not able to cache data
+			 */
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						*( (uint64_t *) addr ) ^= (uint64_t) ~0;
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+							printf( "*" );
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			tlast  = 3;
+			tstate = TCHK;
+		}	break;
+
+		case 4: {
+			uint64_t one;
+
+			/*
+			 * new check pattern
+			 */
+			one     = ( ( check & 0x8000000000000000 ) != 0 );
+			check <<= 1;
+			if( one ) {
+				check |= 0x1;
+			}
+
+			printf( "\nrotate left  0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check );
+
+			/*
+			 * first switch lines, then blocks. This way the CPU
+			 * is not able to cache data
+			 */
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						*( (uint64_t *) addr ) <<= 1;
+
+						if( one ) {
+							*( (uint64_t *) addr ) |=
+								(uint64_t) 0x1;
+						}
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+							printf( "*" );
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			tlast  = 4;
+			tstate = TCHK;
+		}	break;
+
+		case 5: {
+
+			if( rotl < 6 ) {
+				rotl++;
+				tstate = 4;
+			} else {
+				rotl   = 0;
+				tstate = 6;
+			}
+
+		}	break;
+
+		case 6: {
+			/*
+			 * new check pattern
+			 */
+			check *= ~check;
+			printf( "\nmultiply     0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check );
+
+			/*
+			 * first switch lines, then blocks. This way the CPU
+			 * is not able to cache data
+			 */
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						*( (uint64_t *) addr ) *= ~( *( (uint64_t *) addr ) );
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+							printf( "*" );
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			tlast  = TEND - 1;
+			tstate = TCHK;
+		}	break;
+
+		case TEND: {
+			pidx++;
+			tstate = 0;
+		}	break;
+
+		case TCHK: {
+			uint64_t err;
+			/*
+			 * check data
+			 */
+			printf( "\nchecking                       : " );
+
+			for( line = 0, dcnt = 0; line < numlines; line++ ) {
+
+				for( block = 0; block < numblocks; block++ ) {
+
+					for( i = 0; i < _line; i += 8 ) {
+						addr =  _start +
+							( block * _bsize ) +
+							( line * _line )   +
+							i;
+
+						if( addr >= _2GB ) {
+							addr += _2GB;
+						}
+
+						err = ( *( (uint64_t *) addr ) != check );
+
+						if( err ) {
+							merr++;
+						}
+
+						/*
+						 * print out a dot every 256Mb
+						 */
+						dcnt += 8;
+						if( dcnt == _256MB ) {
+							dcnt = 0;
+
+							if( err ) {
+								printf( "X" );
+							} else {
+								printf( "*" );
+							}
+
+							if( io_getchar( &c ) ) {
+								goto mtend;
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			err   = (uint64_t) load32_ci( MEAR1_R );
+			uerr += ( err >> 24 ) & (uint64_t) 0xff;
+			cerr += ( err >> 16 ) & (uint64_t) 0xff;
+
+			printf( " (UE: %02llX, CE: %02llX)", ( err >> 24 ) & (uint64_t) 0xff, ( err >> 16 ) & (uint64_t) 0xff );
+
+			tstate = tlast + 1;
+			tlast  = TCHK;
+		} 	break;
+
+		}
+
+	}
+
+mtend:
+	printf( "\n\nmemory test results" );
+	printf( "\n-------------------" );
+	printf( "\nuncorrectable errors: %u", (uint32_t) uerr );
+	printf( "\ncorrectable errors  : %u", (uint32_t) cerr );
+	printf( "\nread/write errors   : %u\n", (uint32_t) merr );
+
+	and32_ci( MCCR_R, ~( IBIT(6) | IBIT(7) ) );
+}
+
+void
+u4_dump(uint8_t argCnt, char *pArgs[], uint64_t flags)
+{
+	printf( "\r\n*** u4 register dump ***\r\n\n" );
+	printf( "register      (offset): value\r\n" );
+	printf( "----------------------------------\r\n" );
+	printf( "Clock Control (0x%04X): 0x%08X\r\n", (uint16_t) ClkCntl_R, load32_ci( ClkCntl_R ) );
+	printf( "PLL2 Control  (0x%04X): 0x%08X\r\n", (uint16_t) PLL2Cntl_R, load32_ci( PLL2Cntl_R ) );
+	printf( "MemModeCntl   (0x%04X): 0x%08X\r\n", (uint16_t) MemModeCntl_R, load32_ci( MemModeCntl_R ) );
+	printf( "RASTimer0     (0x%04X): 0x%08X\r\n", (uint16_t) RASTimer0_R, load32_ci( RASTimer0_R ) );
+	printf( "RASTimer1     (0x%04X): 0x%08X\r\n", (uint16_t) RASTimer1_R, load32_ci( RASTimer1_R ) );
+	printf( "CASTimer0     (0x%04X): 0x%08X\r\n", (uint16_t) CASTimer0_R, load32_ci( CASTimer0_R ) );
+	printf( "CASTimer1     (0x%04X): 0x%08X\r\n", (uint16_t) CASTimer1_R, load32_ci( CASTimer1_R ) );
+	printf( "MemRfshCntl   (0x%04X): 0x%08X\r\n", (uint16_t) MemRfshCntl_R, load32_ci( MemRfshCntl_R ) );
+	printf( "Dm0Cnfg       (0x%04X): 0x%08X\r\n", (uint16_t) Dm0Cnfg_R, load32_ci( Dm0Cnfg_R ) );
+	printf( "Dm1Cnfg       (0x%04X): 0x%08X\r\n", (uint16_t) Dm1Cnfg_R, load32_ci( Dm1Cnfg_R ) );
+	printf( "Dm2Cnfg       (0x%04X): 0x%08X\r\n", (uint16_t) Dm2Cnfg_R, load32_ci( Dm2Cnfg_R ) );
+	printf( "Dm3Cnfg       (0x%04X): 0x%08X\r\n", (uint16_t) Dm3Cnfg_R, load32_ci( Dm3Cnfg_R ) );
+	printf( "UsrCnfg       (0x%04X): 0x%08X\r\n", (uint16_t) UsrCnfg_R, load32_ci( UsrCnfg_R ) );
+	printf( "MemArbWt      (0x%04X): 0x%08X\r\n", (uint16_t) MemArbWt_R, load32_ci( MemArbWt_R ) );
+	printf( "ODTCntl       (0x%04X): 0x%08X\r\n", (uint16_t) ODTCntl_R, load32_ci( ODTCntl_R ) );
+	printf( "IOPadCntl     (0x%04X): 0x%08X\r\n", (uint16_t) IOPadCntl_R, load32_ci( IOPadCntl_R ) );
+	printf( "MemPhyMode    (0x%04X): 0x%08X\r\n", (uint16_t) MemPhyModeCntl_R, load32_ci( MemPhyModeCntl_R ) );
+	printf( "OCDCalCntl    (0x%04X): 0x%08X\r\n", (uint16_t) OCDCalCntl_R, load32_ci( OCDCalCntl_R ) );
+	printf( "OCDCalCmd     (0x%04X): 0x%08X\r\n", (uint16_t) OCDCalCmd_R, load32_ci( OCDCalCmd_R ) );
+	printf( "CKDelayL      (0x%04X): 0x%08X\r\n", (uint16_t) CKDelayL_R, load32_ci( CKDelayL_R ) );
+	printf( "CKDelayH      (0x%04X): 0x%08X\r\n", (uint16_t) CKDelayU_R, load32_ci( CKDelayU_R ) );
+	printf( "MemBusCnfg    (0x%04X): 0x%08X\r\n", (uint16_t) MemBusCnfg_R, load32_ci( MemBusCnfg_R ) );
+	printf( "MemBusCnfg2   (0x%04X): 0x%08X\r\n", (uint16_t) MemBusCnfg2_R, load32_ci( MemBusCnfg2_R ) );
+	printf( "MemRdQCnfg    (0x%04X): 0x%08X\r\n", (uint16_t) MemRdQCnfg_R, load32_ci( MemRdQCnfg_R ) );
+	printf( "MemWrQCnfg    (0x%04X): 0x%08X\r\n", (uint16_t) MemWrQCnfg_R, load32_ci( MemWrQCnfg_R ) );
+	printf( "MemQArb       (0x%04X): 0x%08X\r\n", (uint16_t) MemQArb_R, load32_ci( MemQArb_R ) );
+	printf( "MemRWArb      (0x%04X): 0x%08X\r\n", (uint16_t) MemRWArb_R, load32_ci( MemRWArb_R ) );
+	printf( "ByteWrClkDel  (0x%04X): 0x%08X\r\n", (uint16_t) ByteWrClkDelC0B00_R, load32_ci( ByteWrClkDelC0B00_R ) );
+	printf( "ReadStrobeDel (0x%04X): 0x%08X\r\n", (uint16_t) ReadStrobeDelC0B00_R, load32_ci( ReadStrobeDelC0B00_R ) );
+	printf( "RstLdEnVerC0  (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC0_R, load32_ci( RstLdEnVerniersC0_R ) );
+	printf( "RstLdEnVerC1  (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC1_R, load32_ci( RstLdEnVerniersC1_R ) );
+	printf( "RstLdEnVerC2  (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC2_R, load32_ci( RstLdEnVerniersC2_R ) );
+	printf( "RstLdEnVerC3  (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC3_R, load32_ci( RstLdEnVerniersC3_R ) );
+	printf( "APIMemRdCfg   (0x%04X): 0x%08X\r\n", (uint16_t) APIMemRdCfg_R, load32_ci( APIMemRdCfg_R ) );
+	printf( "scrub start   (0x%04X): 0x%08X\r\n", (uint16_t) MSRSR_R, load32_ci( MSRSR_R ) );
+	printf( "scrub end     (0x%04X): 0x%08X\r\n", (uint16_t) MSRER_R, load32_ci( MSRER_R ) );
+}
+
+int32_t
+u4_memBegin( eccerror_t *f_ecc_pt )
+{
+	int32_t i;
+
+	#ifdef U4_INFO
+	printf( "\r\n" );
+	printf( "U4 DDR2 memory controller setup V%u.%u\r\n",
+		VER, SUBVER );
+	printf( "------------------------------------\r\n" );
+	printf( "> detected board              : " );
+
+	if( IS_MAUI ) {
+		printf( "MAUI" );
+	} else if( IS_BIMINI ) {
+		printf( "BIMINI" );
+	} else if( IS_KAUAI ) {
+		printf( "KAUAI" );
+	} else {
+		printf( "unknown!" );
+		return RET_ERR;
+	}
+	#endif
+
+	do {
+		/*
+		 * initialize variables
+		 */
+		m_memsize_u64    = 0;
+		m_dcnt_u32       = 0;
+		m_dgrcnt_u32     = 0;
+		m_dclidx_u32     = 0;
+
+		for( i = 0; i < NUM_SLOTS; i++ ) {
+			m_dptr[i] = NULL;
+			memset( ( void * ) &m_dimm[i], 0, sizeof( dimm_t ) );
+		}
+
+		for( i = 0; i < MAX_DGROUPS; i++ ) {
+			m_dgrptr[i] = NULL;
+			memset( ( void * ) &m_dgroup[i], 0, sizeof( dimm_t ) );
+		}
+
+		/*
+		 * start configuration
+		 */
+		#ifdef U4_INFO
+		printf( "\r\n> detected DIMM configuration : " );
+		#endif
+
+		i = ddr2_readSPDs();
+
+		if( i != RET_OK ) {
+			#ifdef U4_INFO
+			printf( "\r\n-------------------------------------------------------------" );
+			printf( "\r\n  switching off memory bank(s) due to SPD integrity failure" );
+			printf( "\r\n-------------------------------------------------------------\r\n" );
+			#endif
+		}
+
+	} while( i != RET_OK );
+
+	/*
+	 * check DIMM configuration
+	 */
+	if( ddr2_setupDIMMcfg() != RET_OK ) {
+		#ifdef U4_INFO
+		printf( "> initialization failure.\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	/*
+	 * create DIMM groups
+	 */
+	u4_setupDIMMgroups();
+
+	/*
+	 * start configuration of u4
+	 */
+	u4_calcDIMMcnfg();
+
+	if( u4_calcDIMMmemmode() != RET_OK ) {
+		#ifdef U4_INFO
+		printf( "> initialization failure.\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	#ifdef U4_INFO
+	printf( "%uMb @ %uMhz, CL %u\r\n",
+		(uint32_t) ( m_memsize_u64 / 0x100000 ),
+		m_gendimm.m_speed_pu32[m_dclidx_u32],
+		m_gendimm.m_clval_pu32[m_dclidx_u32] );
+
+	printf( "> initializing memory         :\r\n" );
+	#endif
+
+	if( u4_setup_core_clock() != RET_OK ) {
+		#ifdef U4_INFO
+		printf( "> initialization failure.\r\n" );
+		#endif
+		return RET_ERR;
+	}
+
+	i = u4_start( f_ecc_pt );
+	if( i != RET_OK ) {
+		#ifdef U4_INFO
+		printf( "> initialization failure.\r\n" );
+		#endif
+		return i;
+	}
+
+	#ifdef U4_INFO
+	printf( "  [flush cache     :          ]" );
+	#endif
+
+	flush_cache( 0x0, L2_CACHE_SIZE );
+
+	#ifdef U4_INFO
+	printf( "\b\b\bOK\r\n" );
+	printf( "> initialization complete.\r\n" );
+	#endif
+
+#ifdef U4_SHOW_REGS
+	u4_dump(0,0,0);
+#endif
+
+	return RET_OK;
+}
+
+static int32_t scrubstarted = 0;
+
+void
+u4_scrubStart(uint8_t argCnt, char *pArgs[], uint64_t flags )
+{
+	scrubstarted = 1;
+
+	/*
+	 * setup scrub parameters
+	 */
+	store32_ci( MSCR_R, 0 );			// stop scrub
+	store32_ci( MSRSR_R, 0x0 );			// set start
+	store32_ci( MSRER_R, 0x1c );			// set end
+	store32_ci( MSPR_R, 0x0 );			// set pattern
+
+	/*
+	 * clear out ECC error registers
+	 */
+	store32_ci( MEAR0_R, 0x0 );
+	store32_ci( MEAR1_R, 0x0 );
+	store32_ci( MESR_R, 0x0 );
+
+	/*
+	 * Setup Scrub Type
+	 */
+	store32_ci( MSCR_R, IBIT(1) );
+	printf( "\r\nscrub started\r\n" );
+}
+
+void
+u4_scrubEnd(uint8_t argCnt, char *pArgs[], uint64_t flags )
+{
+	store32_ci( MSCR_R, 0 );			// stop scrub
+	scrubstarted = 0;
+	printf( "\r\nscrub stopped\r\n" );
+}
+
+void
+u4_memwr(uint8_t argCnt, char *pArgs[], uint64_t flags )
+{
+	uint32_t i;
+	uint32_t v = 0;
+
+	for( i = 0; i < 0x200; i += 4 ) {
+
+		if( ( i & 0xf ) == 0 ) {
+			v = ~v;
+		}
+
+		store32_ci( i, v );
+	}
+
+}
+
+void
+u4memInit()
+{
+	static uint32_t l_isInit_u32 = 0;
+	eccerror_t	l_ecc_t;
+	int32_t		ret;
+
+	/*
+	 * do not initialize memory more than once
+	 */
+	if( l_isInit_u32 ) {
+		#ifdef U4_INFO
+		printf( "\r\n\nmemory already initialized\r\n" );
+		#endif
+		return;
+	} else {
+		l_isInit_u32 = 1;
+	}
+
+	/*
+	 * enable all DIMM banks on first run
+	 */
+	m_bankoff_u32 = 0;
+
+	do {
+		ret = u4_memBegin( &l_ecc_t );
+
+		if( ret < RET_ERR ) {
+			uint32_t l_bank_u32 = l_ecc_t.m_rank_u32 / 2;
+			printf( "\r\n-----------------------------------------------------" );
+			printf( "\r\n  switching off memory bank %u due to memory failure", l_bank_u32 );
+			printf( "\r\n-----------------------------------------------------" );
+			m_bankoff_u32 |= ( 1 << l_bank_u32 );
+		}
+
+	} while( ret < RET_ERR );
+
+}
+
+void
+monitorDDR2( uint8_t argCnt, char *pArgs[], uint64_t flags )
+{
+	u4memInit();
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/romfs/boot_rom.ffs b/qemu-0.15.x/roms/SLOF/board-js2x/romfs/boot_rom.ffs
new file mode 100644
index 0000000..fc86bbf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/romfs/boot_rom.ffs
@@ -0,0 +1,23 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+# FFile-Name	Real Filename		Flags			ROM-Offset i/a
+#--------------|-----------------------|-----------------------|--------------
+header		romfs/header.img	0			0
+stage1          board-js2x/llfw/stage1.bin         1             0x100
+xvect		slof/xvect.bin		0			0
+ofw_main	board-js2x/slof/paflof		0			0
+stageS		board-js2x/llfw/stageS.bin	0			0
+bootinfo	board-js2x/llfw/Cboot.bin	0			0
+rtas		board-js2x/rtas/rtas.bin	0			0
+snk             clients/net-snk.client		0			0
+net_bcm         other-licence/bcm/net_bcm57xx.bin 0             0
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/Makefile b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/Makefile
new file mode 100644
index 0000000..70e506f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/Makefile
@@ -0,0 +1,89 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../Makefile.dirs
+
+include $(TOPBRDDIR)/config
+include $(TOPCMNDIR)/make.rules
+
+
+LDFLAGS		= -nostdlib
+CPPFLAGS	= -I. -I$(LIBCMNDIR)/libc/include -I$(LIBCMNDIR)/libipmi -I$(INCLBRDDIR) \
+		  -I$(INCLCMNDIR) -I$(RTASCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+ASFLAGS		= -Wa,-mregnames $(FLAG)
+CFLAGS		+= -Wall -Wextra -O2 -msoft-float -ffreestanding $(FLAG)
+
+# Board specific RTAS files:
+BOARD_SRC_ASM	=
+BOARD_SRC_C	= rtas_flash.c rtas_board.c rtas_pci.c  \
+		  rtas_out.c rtas_table.c 
+BOARD_SRCS	= $(BOARD_SRC_ASM) $(BOARD_SRC_C)
+BOARD_OBJ	= $(BOARD_SRC_ASM:%.S=%.o) $(BOARD_SRC_C:%.c=%.o) $(BOARD_OCO:%.oco=%.o)
+BOARD_OCO	= i2c_bmc.oco ipmi_oem.oco
+
+
+# Common RTAS files (from $(RTASCMNDIR) directory):
+RTAS_SRC_ASM	= rtas_entry.S rtas_common.S reloc.S
+RTAS_SRC_C	= rtas_call.c
+RTAS_SRCS	= $(RTAS_SRC_ASM) $(RTAS_SRC_C)
+RTAS_OBJ	= $(RTAS_SRC_ASM:%.S=%.o) $(RTAS_SRC_C:%.c=%.o)
+
+RTAS_FLASH_SRC  = block_lists.c
+RTAS_FLASH_OBJ  = $(RTAS_FLASH_SRC:%.c=$(RTASCMNDIR)/flash/%.o)
+
+# Additional object files:
+EXTRA_OBJ	= ../llfw/hw.o ../../lib/libc.a ../../lib/libipmi.a
+
+OBJS 		= $(RTAS_OBJ:%=$(RTASCMNDIR)/%) $(BOARD_OBJ) $(EXTRA_OBJ) \
+		  $(RTAS_FLASH_OBJ)
+
+
+all:	Makefile.dep rtas.bin
+
+rtas.bin: rtas 
+	$(OBJCOPY) -O binary $< $@
+
+rtas: $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o 
+	$(LD) $(LDFLAGS) -o $@ -T $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o
+
+reloc_table.o: $(TOOLSDIR)/gen_reloc_table $(OBJS)
+	$(TOOLSDIR)/create_reloc_table.sh --ld "$(ONLY_LD)" --ldflags "$(LDFLAGS)" \
+	  --lds "$(RTASCMNDIR)/rtas.lds" --objcopy "$(OBJCOPY)" $(OBJS)
+
+$(TOOLSDIR)/gen_reloc_table: $(TOOLSDIR)/gen_reloc_table.c
+	$(MAKE) -C $(TOOLSDIR) gen_reloc_table
+
+../../lib/libc.a:
+	make -C ../../lib
+
+clean:
+	make -C ../../lib clean
+	rm -f $(OBJS) reloc_table.o rtas rtas.bin
+
+distclean : clean
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(BOARD_SRCS) > Makefile.dep
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(RTAS_SRCS:%=$(RTASCMNDIR)/%) \
+	  | sed -e '/:/s,^,$(RTASCMNDIR)/,' >> Makefile.dep
+Makefile.dep:
+	$(MAKE) depend
+
+# Include dependency file if available:
+ifneq (,$(wildcard Makefile.dep))
+include Makefile.dep
+endif
+%.o: %.oco
+	cp -f $< $@
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.c b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.c
new file mode 100644
index 0000000..9b20566
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.c
@@ -0,0 +1,216 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <rtas.h>
+#include "rtas_board.h"
+#include <bmc.h>
+#include <rtas_i2c_bmc.h>
+#include <rtas_ipmi_bmc.h>
+#include "libipmi.h"
+#include <hw.h>
+
+void io_init(void);
+
+typedef struct {
+	uint64_t r3;
+	uint64_t addr;
+	volatile uint64_t id;
+} slave_t;
+
+volatile slave_t rtas_slave_interface;
+
+void
+rtas_slave_loop(volatile slave_t * pIface)
+{
+	uint64_t mask = pIface->id;
+	pIface->id = 0;
+	while (pIface->id != mask); {
+		int dly = 0x1000;
+		while (dly--);
+	}
+	pIface->id = 0;
+	asm("  mr 3,%0 ; mtctr %1 ; bctr "::"r"(pIface->r3), "r"(pIface->addr));
+
+}
+
+void
+rtas_fetch_slaves(rtas_args_t * pArgs)
+{
+	int retVal = 0;
+	int idx = 0;
+	uint32_t mask = pArgs->args[0] & 0xFFFFFFFE;
+	uint64_t *rtas_slave_loop_ptr = (uint64_t *)rtas_slave_loop;
+	while (mask) {
+		if (mask & 0x1) {
+			rtas_slave_interface.id = idx | 0x100;
+			*(int *) 0x3fc0 = (int)(unsigned long) &rtas_slave_interface;	// r3
+			*(int *) 0x3f80 = *rtas_slave_loop_ptr;		// addr
+			*(int *) 0x3fa0 = idx | 0x100;	// pid
+			while (rtas_slave_interface.id);
+		}
+		mask >>= 1;
+		idx++;
+	}
+	pArgs->args[pArgs->nargs] = retVal;
+}
+
+void
+rtas_start_cpu(rtas_args_t * pArgs)
+{
+	int retVal = 0;
+	int idx = pArgs->args[0];	// pid
+	rtas_slave_interface.r3 = pArgs->args[2];	// r3
+	rtas_slave_interface.addr = pArgs->args[1];	// addr
+	asm(" sync ");
+	rtas_slave_interface.id = idx | 0x100;	// pid
+	while (rtas_slave_interface.id);
+	pArgs->args[pArgs->nargs] = retVal;
+}
+
+void
+rtas_read_vpd(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] =
+	    bmc_read_vpd((uint8_t *) (uint64_t) pArgs->args[2], pArgs->args[1],
+			 pArgs->args[0]);
+}
+
+void
+rtas_write_vpd(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] =
+	    bmc_write_vpd((uint8_t *) (uint64_t) pArgs->args[2], pArgs->args[1],
+			  pArgs->args[0]);
+}
+
+void
+rtas_set_indicator(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = -1;
+}
+
+void
+rtas_event_scan(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = -1;
+}
+
+void
+rtas_stop_bootwatchdog(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = bmc_stop_bootwatchdog();
+}
+
+void
+rtas_set_bootwatchdog(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = bmc_set_bootwatchdog(pArgs->args[0]);
+}
+
+void
+rtas_set_flashside(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = bmc_set_flashside(pArgs->args[0]);
+}
+
+void
+rtas_get_flashside(rtas_args_t * pArgs)
+{
+	int retVal = bmc_get_flashside();
+	pArgs->args[pArgs->nargs] = retVal;
+}
+
+void
+rtas_flash_test(rtas_args_t * pArgs)
+{
+	pArgs->args[pArgs->nargs] = -1;
+}
+
+void
+rtas_system_reboot(rtas_args_t * pArgs)
+{
+	bmc_system_reboot();
+	pArgs->args[pArgs->nargs] = -1;
+}
+
+void
+rtas_power_off(rtas_args_t * pArgs)
+{
+	bmc_power_off();
+	pArgs->args[pArgs->nargs] = -1;
+}
+
+void
+rtas_get_blade_descr(rtas_args_t * pArgs)
+{
+	uint8_t *buffer = (uint8_t *) (uint64_t) pArgs->args[0];
+	uint32_t maxlen = pArgs->args[1];
+	uint32_t retlen = 0;
+	uint32_t retval = bmc_get_blade_descr(buffer, maxlen, &retlen);
+	pArgs->args[pArgs->nargs] = retlen;
+	pArgs->args[pArgs->nargs + 1] = retval;
+}
+
+// for JS20 cannot read blade descr
+uint32_t
+dummy_get_blade_descr(uint8_t *dst, uint32_t maxlen, uint32_t *len)
+{
+	// to not have a warning we need to do _something_ with *dst and maxlen...
+	*dst = *dst;
+	maxlen = maxlen;
+	*len = 0;
+	return -1;
+}
+
+/* read flashside from register */
+short
+reg_get_flashside(void)
+{
+	short retVal;
+	uint8_t val = load8_ci(0xf4003fe3);
+	if (val & 0x80) {
+		// temp
+		retVal = 1;
+	} else {
+		// perm
+		retVal = 0;
+	}
+	return retVal;
+}
+
+void
+rtas_init(void)
+{
+	io_init();
+	if (u4Flag) {
+		bmc_system_reboot = ipmi_system_reboot;
+		bmc_power_off = ipmi_power_off;
+		bmc_set_flashside = ipmi_set_flashside;
+		bmc_get_flashside = reg_get_flashside;
+		bmc_stop_bootwatchdog = ipmi_oem_stop_bootwatchdog;
+		bmc_set_bootwatchdog = ipmi_oem_set_bootwatchdog;
+		bmc_read_vpd = ipmi_oem_read_vpd;
+		bmc_write_vpd = ipmi_oem_write_vpd;
+		bmc_get_blade_descr = ipmi_oem_get_blade_descr;
+	} else {
+		bmc_system_reboot = i2c_system_reboot;
+		bmc_power_off = i2c_power_off;
+		bmc_set_flashside = i2c_set_flashside;
+		bmc_get_flashside = i2c_get_flashside;
+		bmc_stop_bootwatchdog = i2c_stop_bootwatchdog;
+		bmc_set_bootwatchdog = i2c_set_bootwatchdog;
+		bmc_read_vpd = i2c_read_vpd;
+		bmc_write_vpd = i2c_write_vpd;
+		bmc_get_blade_descr = dummy_get_blade_descr;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.h b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.h
new file mode 100644
index 0000000..06766e1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_board.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __RTAS_BOARD_H
+#define __RTAS_BOARD_H
+
+#include <stddef.h>
+
+extern volatile unsigned char u4Flag;
+
+void rtas_ibm_read_pci_config(rtas_args_t * pArgs);
+void rtas_ibm_write_pci_config(rtas_args_t * pArgs);
+void rtas_read_pci_config(rtas_args_t * pArgs);
+void rtas_write_pci_config(rtas_args_t * pArgs);
+void rtas_system_reboot(rtas_args_t * pArgs);
+void rtas_power_off(rtas_args_t * pArgs);
+void rtas_display_character(rtas_args_t * pArgs);
+void rtas_flash_test(rtas_args_t * pArgs);
+void rtas_ibm_update_flash_64_and_reboot(rtas_args_t * pArgs);
+void rtas_set_indicator(rtas_args_t * pArgs);
+void rtas_event_scan(rtas_args_t * pArgs);
+void rtas_ibm_manage_flash_image(rtas_args_t * pArgs);
+void rtas_ibm_validate_flash_image(rtas_args_t * pArgs);
+void rtas_update_flash(rtas_args_t * pArgs);
+void rtas_set_flashside(rtas_args_t * pArgs);
+void rtas_get_flashside(rtas_args_t * pArgs);
+void rtas_dump_flash(rtas_args_t * pArgs);
+void rtas_start_cpu(rtas_args_t * pArgs);
+void rtas_read_vpd(rtas_args_t * pArgs);
+void rtas_write_vpd(rtas_args_t * pArgs);
+void rtas_fetch_slaves(rtas_args_t * pArgs);
+void rtas_stop_bootwatchdog(rtas_args_t * pArgs);
+void rtas_get_blade_descr(rtas_args_t * pArgs);
+void rtas_set_bootwatchdog(rtas_args_t * pArgs);
+
+#endif				/* __RTAS_BOARD_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.c b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.c
new file mode 100644
index 0000000..82c1745
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.c
@@ -0,0 +1,614 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <hw.h>
+#include <rtas.h>
+#include "rtas_board.h"
+#include <bmc.h>
+#include "rtas_flash.h"
+#include <flash/block_lists.h>
+#include "product.h"
+#include "calculatecrc.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintf(_x ...) printf(_x)
+#else
+#define dprintf(_x ...)
+#endif
+
+static uint64_t size;
+static uint64_t flashOffset;
+
+unsigned short manage_flash_buffer[BUFSIZE];
+unsigned long check_flash_image(unsigned long rombase, unsigned long length,
+				unsigned long start_crc);
+
+#ifdef DEBUG
+static void
+dump_blocklist(uint64_t *bl, int version)
+{
+	uint64_t bl_size;
+	uint8_t *addr = (uint8_t *)bl;
+
+	if (version == 1) {
+		/* version 1 blocklist */
+		bl_size = *bl & 0x00FFFFFFFFFFFFFFUL;
+
+	} else {
+		bl_size = *bl;
+	}
+
+	printf("\n\rblocklist_dump %lx", bl_size);
+	while (bl_size) {
+		unsigned int tmpCnt = bl_size;
+		unsigned char x;
+		if (tmpCnt > 8)
+			tmpCnt = 8;
+		printf("\n\r%08x: ", addr);
+		/* print hex */
+		while (tmpCnt--) {
+			set_ci();
+			x = *addr++;
+			clr_ci();
+			printf("%02x ", x);
+		}
+		tmpCnt = bl_size;
+		if (tmpCnt > 8)
+			tmpCnt = 8;
+		bl_size -= tmpCnt;
+		/* reset addr ptr to print ascii */
+		addr = addr - tmpCnt;
+		/* print ascii */
+		while (tmpCnt--) {
+			set_ci();
+			x = *addr++;
+			clr_ci();
+			if ((x < 32) || (x >= 127)) {
+				/* non-printable char */
+				x = '.';
+			}
+			printf("%c", x);
+		}
+	}
+	printf("\r\n");
+}
+#endif
+
+void
+rtas_dump_flash(rtas_args_t *rtas_args)
+{
+	int retVal = 0;
+	unsigned int size = rtas_args->args[0];
+	unsigned int offset = rtas_args->args[1];
+	volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+	printf("\n\rflash_dump %x %x", size, offset);
+	flash += offset;
+	while (size) {
+		unsigned int tmpCnt = size;
+		unsigned char x;
+		if (tmpCnt > 16)
+			tmpCnt = 16;
+		printf("\n\r%p: ", flash);
+		/* print hex */
+		while (tmpCnt--) {
+			set_ci();
+			x = *flash++;
+			clr_ci();
+			printf("%02x ", x);
+		}
+		tmpCnt = size;
+		if (tmpCnt > 16)
+			tmpCnt = 16;
+		size -= tmpCnt;
+		/* reset flash ptr to print ascii */
+		flash = flash - tmpCnt;
+		/* print ascii */
+		while (tmpCnt--) {
+			set_ci();
+			x = *flash++;
+			clr_ci();
+			if ((x < 32) || (x >= 127)) {
+				/* non-printable char */
+				x = '.';
+			}
+			printf("%c", x);
+		}
+	}
+	printf("\r\n");
+	rtas_args->args[rtas_args->nargs] = retVal;
+}
+
+
+static void
+print_block(int i)
+{
+	int counter = 8;
+
+	while (counter--)
+		printf("\b");
+	printf("%08x", i);
+}
+
+
+
+/* To enter data mode after flash has been in programming mode
+ * a 0xFF has to be written */
+static void
+enter_data_mode(void)
+{
+	volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+	set_ci();
+	*flash = 0xFF;
+	eieio();
+	clr_ci();
+}
+
+
+static void
+erase_flash_block(unsigned long offset)
+{
+	volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+	flash += offset;
+	set_ci();
+	*flash = 0x20;
+	eieio();
+	*flash = 0xd0;
+	eieio();
+	while (!(*flash & 0x80)) ;
+	clr_ci();
+}
+
+
+void
+write_flash(unsigned long offset, unsigned char *data)
+{
+	int cnt = 32;
+	volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+	flash += (offset + flashOffset);
+	set_ci();
+	while (cnt) {
+		if (!((uint64_t)flash & 0x1F)) {
+			while (cnt) {
+				uint64_t tmpcnt = cnt;
+				if (tmpcnt > 0x20)
+					tmpcnt = 0x20;
+				do {
+					*flash = 0xE8;
+					eieio();
+				} while (!(*flash & 0x80));
+				cnt -= tmpcnt;
+				*flash = tmpcnt - 1;
+				while (tmpcnt--) {
+					*flash++ = *data++;
+				}
+				*flash = 0xD0;
+				eieio();
+				while (!(*flash & 0x80)) ;
+			}
+			break;
+		}
+		*flash = 0x40;
+		eieio();
+		*flash++ = *data++;
+		eieio();
+		while (!(*flash & 0x80)) ;
+		cnt--;
+	}
+	clr_ci();
+}
+
+void
+write_flash_page(unsigned long offset, unsigned short *data)
+{
+	int i = 0;
+
+	for (i = 0; i < BUFSIZE; i += 32, offset += 32) {
+		write_flash(offset, ((unsigned char *)data + i));
+	}
+}
+
+/*
+ * 0 reject temporary image
+ * 1 commit temporary image
+ * */
+static int
+copy_flash(short mode)
+{
+	volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+	uint64_t blockCnt;
+	uint64_t hash = 0;
+	short notmode = mode ^ 0x1;
+
+	if (bmc_set_flashside(notmode) != notmode) {
+		return -1;
+	}
+	printf("\r\nErasing Flash: 0x        ");
+
+	for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += FLASH_BLOCK_SIZE) {
+		print_block(blockCnt);
+		erase_flash_block(blockCnt);
+	}
+	enter_data_mode();
+	progress = FLASHSIZE / 38;
+	print_writing();
+
+	for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += BUFSIZE) {
+		uint64_t *srcPtr = (uint64_t *)(flash + blockCnt);
+		uint64_t *destPtr = (uint64_t *)((void*)manage_flash_buffer);
+		uint64_t cnt = BUFSIZE / 8;
+		if (bmc_set_flashside(mode) != mode) {
+			return -1;
+		}
+		enter_data_mode();
+		set_ci();
+		while (cnt--) {
+			*destPtr++ = *srcPtr++;
+		}
+		clr_ci();
+
+		if (bmc_set_flashside(notmode) != notmode) {
+			return -1;
+		}
+		write_flash_page(blockCnt,
+				 (unsigned short *)manage_flash_buffer);
+
+		/* progress output... */
+		print_progress();
+		if (blockCnt > hash * progress) {
+			print_hash();
+			hash++;
+		}
+	}
+	enter_data_mode();
+	if (bmc_set_flashside(mode) != mode) {
+		return -1;
+	}
+	printf("\b#\n");
+	return 0;
+}
+
+/*
+ * Function: ibm_manage_flash_image
+ *	Input:
+ *		r3:   rtas parm structure
+ *			token:  46
+ *			in:     1
+ *			out:    1
+ *			parm0:  0 reject temporary image
+ *				1 commit temporary image
+ *	Output:
+ *			parm1:  Status (hw -1, busy -2, parameter error -3
+ *					-9001 cannot overwrite the active firmware image)
+ *
+ */
+
+void
+rtas_ibm_manage_flash_image(rtas_args_t *rtas_args)
+{
+	int side;
+	int result = 0;
+	short mode = rtas_args->args[0];
+
+	if (mode < 0 || mode > 1) {
+		rtas_args->args[rtas_args->nargs] = -3;
+		return;
+	}
+	side = bmc_get_flashside();
+	if (side == 0) {
+		/* we are on the permanent side */
+		if (mode != 0) {
+			rtas_args->args[rtas_args->nargs] = -9001;
+			return;
+		}
+	} else if (side == 1) {
+		/* we are on the temporary side */
+		if (mode != 1) {
+			rtas_args->args[rtas_args->nargs] = -9001;
+			return;
+		}
+	} else {
+		rtas_args->args[rtas_args->nargs] = -1;
+		return;
+	}
+
+	result = copy_flash(mode);
+	bmc_set_flashside(mode);
+	enter_data_mode();
+	rtas_args->args[rtas_args->nargs] = 0;
+}
+
+/**
+ * check, if we find the FLASHFS_MAGIC token in bl
+ **/
+static uint8_t
+check_magic(uint64_t *bl, int version)
+{
+	struct stH *pHeader;
+
+	if (version == 1) {
+		/* version 1 blocklist */
+		/* if block list size <= 0x10, it is only block list header */
+		/* and address of block list extension, so look at the extension... */
+		while ((*bl & 0x00FFFFFFFFFFFFFFUL) <= 0x10)
+			bl = (uint64_t *)bl[1];
+
+		/* block list item 2 _should_ be the address of our flashfs image */
+		pHeader = (struct stH *)(bl[2] + 0x28);
+		/* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */
+		return strncmp(pHeader->magic, FLASHFS_MAGIC, 8);
+	} else {
+		/* block list item 1 _should_ be the address of our flashfs image */
+		pHeader = (struct stH *)(bl[1] + 0x28);
+		/* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */
+		return strncmp(pHeader->magic, FLASHFS_MAGIC, 8);
+	}
+}
+
+static void
+get_image_name(char *buffer, int maxsize)
+{
+	volatile struct stH *flash_header = (volatile struct stH *)(SB_FLASH_adr + 0x28);
+	/* since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory */
+	uint64_t magic_val = 0;
+	uint64_t addr;
+
+	/* copy fh_magic to magic_val since, we cannot use it as a string from flash */
+	magic_val = load64_ci((uint64_t)(flash_header->magic));
+	if (strncmp((char *)&magic_val, FLASHFS_MAGIC, 8)) {
+		/* magic does not match */
+		sprintf(buffer, "Unknown");
+		buffer[maxsize - 1] = '\0';
+		return;
+	}
+	addr = (uint64_t)flash_header->version;
+	while (--maxsize) {
+		*buffer = load8_ci(addr++);
+		if (!*buffer++)
+			return;
+	}
+	*buffer = '\0';
+}
+
+/**
+ * validate_flash_image
+ * this function checks if the flash will be updated with the given image
+ * @param args[0] - buffer with minimum 4K of the image to flash
+ * @param args[1] - size of the buffer
+ * @param args[2] - status:
+ *                           0    success
+ *                          -1    hw
+ *                          -2    busy
+ *                          -3    parameter error
+ * @param args[3] - update result token
+ */
+void
+rtas_ibm_validate_flash_image(rtas_args_t *rtas_args)
+{
+	dprintf("\nrtas_ibm_validate_flash_image\n");
+	unsigned long new_image = rtas_args->args[0];
+	char *ret_str = (char *)new_image;
+	struct stH *flash_header = (struct stH *)(new_image + 0x28);
+	char current_temp_version[16];
+	char current_perm_version[16];
+	char new_version[16];
+	int side = bmc_get_flashside();
+
+	/* fill args[0] with the current values which is needed
+	 * in an error case */
+
+	bmc_set_flashside(0);
+	get_image_name(current_perm_version, sizeof(current_perm_version));
+	bmc_set_flashside(1);
+	get_image_name(current_temp_version, sizeof(current_temp_version));
+	bmc_set_flashside(side);
+
+	/* check if the candidate image if valid for this platform */
+	if (strncmp(flash_header->magic, FLASHFS_MAGIC, 8)) {
+		/* magic does not match */
+		rtas_args->args[rtas_args->nargs] = 0;
+		/* No update done, the candidate image is
+		 * not valid for this platform */
+		rtas_args->args[rtas_args->nargs + 1] = 2;
+		sprintf(ret_str, "MI %s %s\xaMI %s %s",
+			current_temp_version, current_perm_version,
+			current_temp_version, current_perm_version);
+		return;
+	}
+
+	if (strncmp(flash_header->platform_name, (char *)sig_org, 32)) {
+		/* this image if for a different board */
+		rtas_args->args[rtas_args->nargs] = 0;
+		/* No update done, the candidate image is
+		 * not valid for this platform */
+		rtas_args->args[rtas_args->nargs + 1] = 2;
+		sprintf(ret_str, "MI %s %s\xaMI %s %s",
+			current_temp_version, current_perm_version,
+			current_temp_version, current_perm_version);
+		return;
+	}
+
+	/* check header crc */
+	if (check_flash_image(rtas_args->args[0], 0x88, 0)) {
+		/* header crc failed */
+		rtas_args->args[rtas_args->nargs] = 0;
+		/* No update done, the candidate image is
+		 * not valid for this platform */
+		rtas_args->args[rtas_args->nargs + 1] = 2;
+		sprintf(ret_str, "MI %s %s\xaMI %s %s",
+			current_temp_version, current_perm_version,
+			current_temp_version, current_perm_version);
+		return;
+	}
+	memcpy(new_version, flash_header->version, 16);
+	sprintf(ret_str, "MI %s %s\xaMI %s %s", current_temp_version,
+		current_perm_version, new_version, current_perm_version);
+	rtas_args->args[rtas_args->nargs] = 0;
+
+	if (strncmp(new_version, current_temp_version, 16) >= 0)
+		rtas_args->args[rtas_args->nargs + 1] = 0;
+	else
+		rtas_args->args[rtas_args->nargs + 1] = 6;
+}
+
+/*
+ * Function: ibm_update_flash_64
+ *	Input:
+ *		r3:   rtas parm structure
+ *			token:  7
+ *			in:     1
+ *			out:    1
+ *			parm0:  A real pointer to a block list
+ *	Output:
+ *			parm1:  Status (hw -1, bad image -3, programming failed -4)
+ *
+ *   Description: flash if addresses above 4GB have to be addressed
+ */
+void
+rtas_update_flash(rtas_args_t *rtas_args)
+{
+	void *bl = (void *)(uint64_t)rtas_args->args[0];
+	int version = get_block_list_version((unsigned char *)bl);
+	uint64_t erase_size;
+	unsigned int i;
+	int perm_check = 1;
+
+#ifdef DEBUG
+	dump_blocklist(bl, version);
+#endif
+
+	/* from SLOF we pass a second (unofficial) parameter, if this parameter is 1, we do not
+	 * check wether we are on permanent side. Needed for update-flash -c to work! */
+	if ((rtas_args->nargs > 1) && (rtas_args->args[1] == 1))
+		perm_check = 0;
+
+	/* check magic string */
+	printf("\r\nChecking magic string : ");
+	if (check_magic(bl, version) != 0) {
+		printf("failed!\n");
+		rtas_args->args[rtas_args->nargs] = -3; /* bad image */
+		return;
+	}
+	printf("succeeded!\n");
+
+	/* check platform */
+	printf("Checking platform : ");
+	if (check_platform(bl, 0x48, version) == -1) {
+		printf("failed!\n");
+		rtas_args->args[rtas_args->nargs] = -3; /* bad image */
+		return;
+	}
+	printf("succeeded!\n");
+
+	/* checkcrc */
+	printf("Checking CRC : ");
+	/* the actual CRC is included at the end of the flash image, thus the resulting CRC must be 0! */
+	if (image_check_crc(bl, version) != 0) {
+		printf("failed!\n");
+		rtas_args->args[1] = -3;        /* bad image */
+		return;
+	}
+	printf("succeeded!\n");
+
+	/* check if we are running on P
+	 * if so, let's switch to temp and flash temp */
+	if (bmc_get_flashside() == 0  && perm_check) {
+		printf("Set flashside: ");
+		bmc_set_flashside(1);
+		printf("Temp!\n");
+	}
+
+#ifdef DEBUG
+	rtas_args_t ra;
+	ra.args[0] = 0x100;     /* size; */
+	ra.args[1] = flashOffset;
+	ra.nargs = 2;
+
+	rtas_dump_flash(&ra);
+	printf("\n");
+#endif
+
+	size = get_size(bl, version);
+	erase_size = (size + (FLASH_BLOCK_SIZE - 1)) & ~(FLASH_BLOCK_SIZE - 1);
+	dprintf("Erasing: size: %#x, erase_size: %#x, FLASH_BLOCK_SIZE: %#x\n",
+		size, erase_size, FLASH_BLOCK_SIZE);
+
+	progress = size / 39;
+	printf("Erasing : 0x%08x", 0);
+	for (i = 0; i < erase_size; i += FLASH_BLOCK_SIZE) {
+		print_block(i);
+		erase_flash_block(i);
+	}
+
+	enter_data_mode();
+#ifdef DEBUG
+	rtas_dump_flash(&ra);
+	printf("\n");
+#endif
+	print_writing();
+	write_block_list(bl, version);
+	printf("\b#\n");
+	enter_data_mode();
+
+#ifdef DEBUG
+	rtas_dump_flash(&ra);
+	printf("\n");
+#endif
+
+	/* checkcrc */
+	printf("Recheck CRC : ");
+	if (check_flash_image(FLASH + flashOffset, size, 0) != 0) {
+		/* failed */
+		printf("failed!\n\r");
+		dprintf("flash_addr: %#x, flashOffset: %#x, size: %#x\n", FLASH,
+			flashOffset, size);
+		dprintf("crc: %#x\n",
+			check_flash_image(FLASH + flashOffset, size, 0));
+		rtas_args->args[rtas_args->nargs] = -4; /* programming failed */
+		return;
+	}
+	printf("succeeded!\n");
+	rtas_args->args[rtas_args->nargs] = 0;
+}
+
+/*
+ * Function: ibm_update_flash_64_and_reboot
+ *	Input:
+ *		r3:   rtas parm structure
+ *			token:  27
+ *			in:     1
+ *			out:    1
+ *			parm0:  A real pointer to a block list
+ *	Output:
+ *			parm1:  Status (hw -1, bad image -3, programming failed -4)
+ *				Currently -4 and -1 are not returned
+ *
+ *  Description: flash and reboot if addresses above 4GB have to be addressed
+ */
+void
+rtas_ibm_update_flash_64_and_reboot(rtas_args_t *rtas_args)
+{
+	rtas_update_flash(rtas_args);
+	dprintf("rc: %#d\n", rtas_args->args[rtas_args->nargs]);
+	if (rtas_args->args[rtas_args->nargs] == 0) {
+		rtas_system_reboot(rtas_args);
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.h b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.h
new file mode 100644
index 0000000..2f79435
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_flash.h
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <southbridge.h>
+
+#define FLASHSIZE FLASH_LENGTH
+#define FLASH SB_FLASH_adr
+#define BUFSIZE 4096
+#define FLASH_BLOCK_SIZE 0x20000
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h
new file mode 100644
index 0000000..e46de88
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __RTAS_I2C_BMC_H
+#define __RTAS_I2C_BMC_H
+
+#include <stddef.h>
+
+void i2c_system_reboot (void);
+void i2c_power_off (void);
+short i2c_set_flashside (short mode);
+short i2c_get_flashside (void);
+int i2c_stop_bootwatchdog (void);
+uint32_t i2c_read_vpd (uint8_t *dst, uint32_t len, uint32_t offset);
+uint32_t i2c_write_vpd (uint8_t *src, uint32_t len, uint32_t offset);
+int i2c_set_bootwatchdog(unsigned short seconds);
+
+#endif		/* __RTAS_I2C_BMC_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h
new file mode 100644
index 0000000..00532d4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __RTAS_IPMI_BMC_H
+#define __RTAS_IPMI_BMC_H
+
+#include <stddef.h>
+
+short ipmi_set_flashside (short mode);
+short ipmi_get_flashside (void);
+
+#endif		/* __RTAS_IPMI_BMC_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_out.c b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_out.c
new file mode 100644
index 0000000..ac2b25d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_out.c
@@ -0,0 +1,114 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <rtas.h>
+#include <hw.h>
+
+volatile unsigned char *uart;
+volatile unsigned char u4Flag;
+
+void
+io_init(void)
+{
+	// read ID register: only if it is a PC87427, enable serial2
+	store8_ci(0xf400002e, 0x20);
+	if (load8_ci(0xf400002f) != 0xf2) {
+		uart = (volatile unsigned char *) 0xf40003f8;
+		u4Flag = 0;
+	} else {
+		uart = (volatile unsigned char *) 0xf40002f8;
+		u4Flag = 1;
+	}
+}
+
+void
+display_char(char ch)
+{
+	volatile int i = 0;
+	volatile unsigned char *uart = (volatile unsigned char *) 0xf40002f8;
+	int cnt = 2;
+	while (cnt--) {
+		set_ci();
+		while (!(uart[5] & 0x20)) {
+			i++;
+		}
+		uart[0] = ch;
+		clr_ci();
+		uart += 0x100;
+	}
+}
+
+size_t
+write(int fd __attribute((unused)), const void *buf, size_t cnt)
+{
+	while (cnt--) {
+		display_char(*(char *) buf);
+		if (*(char *) buf++ == '\n')
+			display_char('\r');
+	}
+	return 0;
+}
+
+void *
+sbrk(int incr __attribute((unused)))
+{
+	return (void *) -1;
+}
+
+
+
+int
+rtas_display_character(rtas_args_t * pArgs)
+{
+	int retVal = 0;
+	display_char((char) pArgs->args[0]);
+	return retVal;
+}
+
+unsigned long
+check_flash_image(unsigned long rombase, unsigned long length,
+		  unsigned long start_crc)
+{
+	const uint32_t CrcTableHigh[16] = {
+		0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90,
+		0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7,
+		0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E,
+		0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09
+	};
+	const uint32_t CrcTableLow[16] = {
+		0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
+		0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
+		0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
+		0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
+	};
+
+	char *Buffer = (char *) rombase;
+	uint32_t AccumCRC = start_crc;
+	char val;
+	uint32_t Temp;
+	while (length-- > 0) {
+		set_ci();
+		val = *Buffer;
+		clr_ci();
+		Temp = ((AccumCRC >> 24) ^ val) & 0x000000ff;
+		AccumCRC <<= 8;
+		AccumCRC ^= CrcTableHigh[Temp / 16];
+		AccumCRC ^= CrcTableLow[Temp % 16];
+		++Buffer;
+	}
+	return AccumCRC;
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_pci.c b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_pci.c
new file mode 100644
index 0000000..610c326
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_pci.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <stdint.h>
+#include <rtas.h>
+#include <hw.h>
+
+int
+rtas_ibm_read_pci_config (rtas_args_t *rtas_args) {
+	int retVal = 0;
+	uint64_t addr = ((uint64_t) rtas_args->args[1]) << 32;  // high 32 bits of PHB UID
+	addr |= (rtas_args->args[2] & 0xFFFFFFFF); // low 32 bits of PHB UID
+	addr |= (rtas_args->args[0] & 0x00FFFFFF); // bus, devfn, offset
+	unsigned int size = rtas_args->args[3];
+
+	/* Check for bus != 0  on PCI/PCI-X (PHB UID = 0xf2000000) */
+	if (((addr & 0xf2000000) == 0xf2000000) && (addr & 0xff0000))
+		addr += 0x1000000;
+
+	if (size == 1)
+		rtas_args->args[5] = load8_ci(addr);
+	else if (size == 2)
+		rtas_args->args[5] = bswap16_load(addr);
+	else if (size == 4)
+		rtas_args->args[5] = bswap32_load(addr);
+	else
+		retVal = -3;  /* Bad arguments */
+
+	return retVal;
+}
+
+int
+rtas_ibm_write_pci_config (rtas_args_t *rtas_args) {
+	int retVal = 0;
+	uint64_t addr = ((uint64_t) rtas_args->args[1]) << 32;  // high 32 bits of PHB UID
+	addr |= (rtas_args->args[2] & 0xFFFFFFFF); // low 32 bits of PHB UID
+	addr |= (rtas_args->args[0] & 0x00FFFFFF); // bus, devfn, offset
+	unsigned int size = rtas_args->args[3];
+
+	addr |= 0xf2000000;
+
+	/* Check for bus != 0  on PCI/PCI-X (PHB UID = 0xf2000000) */
+	if (((addr & 0xf2000000) == 0xf2000000) && (addr & 0xff0000))
+		addr += 0x1000000;
+
+	if (size == 1)
+		store8_ci(addr, rtas_args->args[4]);
+	else if (size == 2)
+		bswap16_store(addr, rtas_args->args[4]);
+	else if (size == 4)
+		bswap32_store(addr, rtas_args->args[4]);
+	else
+		retVal = -3;  /* Bad arguments */
+
+	return retVal;
+}
+
+int
+rtas_read_pci_config (rtas_args_t *rtas_args) {
+	int retVal = 0;
+	unsigned long addr = rtas_args->args[0];
+	unsigned int size = rtas_args->args[1];
+	addr |= 0xf2000000;
+
+	/* Check for bus != 0 */
+	if (addr & 0xff0000)
+		addr += 0x1000000;
+
+	if (size == 1)
+		rtas_args->args[3] = load8_ci(addr);
+	else if (size == 2)
+		rtas_args->args[3] = bswap16_load(addr);
+	else if (size == 4)
+		rtas_args->args[3] = bswap32_load(addr);
+	else
+		retVal = -3;  /* Bad arguments */
+
+	return retVal;
+}
+
+int
+rtas_write_pci_config (rtas_args_t *rtas_args) {
+	int retVal = 0;
+	unsigned long addr = rtas_args->args[0];
+	unsigned int size = rtas_args->args[1];
+
+	addr |= 0xf2000000;
+
+	/* Check for bus != 0 */
+	if (addr & 0xff0000)
+		addr += 0x1000000;
+
+	if (size == 1)
+		store8_ci(addr, rtas_args->args[2]);
+	else if (size == 2)
+		bswap16_store(addr, rtas_args->args[2]);
+	else if (size == 4)
+		bswap32_store(addr, rtas_args->args[2]);
+	else
+		retVal = -3;  /* Bad arguments */
+
+	return retVal;
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_table.c b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_table.c
new file mode 100644
index 0000000..fed4032
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/rtas/rtas_table.c
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <rtas.h>
+#include "rtas_table.h"
+#include "rtas_board.h"
+
+const rtas_funcdescr_t rtas_func_tab[] = {
+	{"ibm,read-pci-config", rtas_ibm_read_pci_config, 0},
+	{"ibm,write-pci-config", rtas_ibm_write_pci_config, 0},
+	{"system-reboot", rtas_system_reboot, 0},
+	{"power-off", rtas_power_off, 0},
+	{"set-indicator", rtas_set_indicator, 0},
+	{"rtas-flash-test", rtas_flash_test, RTAS_TBLFLG_INTERNAL},
+	{"ibm,update-flash-64-and-reboot", rtas_ibm_update_flash_64_and_reboot, 0},
+	{"display-character", rtas_display_character, 0},
+	{"event-scan", rtas_event_scan, 0},
+	{"ibm,manage-flash-image", rtas_ibm_manage_flash_image, 0},
+	{"ibm,validate-flash-image", rtas_ibm_validate_flash_image, 0},
+	{"ibm,update-flash-64", rtas_update_flash, 0},
+	{"rtas-set-flashside", rtas_set_flashside, 0},
+	{"rtas-get-flashside", rtas_get_flashside, 0},
+	{"rtas-dump-flash", rtas_dump_flash, RTAS_TBLFLG_INTERNAL},
+	{"start-cpu", rtas_start_cpu, 0},
+	{"msg-read-vpd", rtas_read_vpd, RTAS_TBLFLG_INTERNAL},
+	{"msg-write-vpd", rtas_write_vpd, RTAS_TBLFLG_INTERNAL},
+	{"read-pci-config", rtas_read_pci_config, 0},
+	{"write-pci-config", rtas_write_pci_config, 0},
+	{"rtas-fetch-slaves", rtas_fetch_slaves, RTAS_TBLFLG_INTERNAL},
+	{"rtas-stop-bootwatchdog", rtas_stop_bootwatchdog, RTAS_TBLFLG_INTERNAL},
+	{"rtas-set-bootwatchdog", rtas_set_bootwatchdog, RTAS_TBLFLG_INTERNAL},
+	{"rtas-get-blade-descr", rtas_get_blade_descr, RTAS_TBLFLG_INTERNAL},
+};
+
+const int rtas_func_tab_size = sizeof(rtas_func_tab) / sizeof(rtas_func_tab[0]);
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/Makefile b/qemu-0.15.x/roms/SLOF/board-js2x/slof/Makefile
new file mode 100644
index 0000000..3d7882a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/Makefile
@@ -0,0 +1,110 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+include ../Makefile.dirs
+
+include $(TOPBRDDIR)/config
+include $(TOPCMNDIR)/make.rules
+
+
+all: Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin
+
+CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libnvram
+SLOF_LIBS = $(LIBCMNDIR)/libbootmsg.a $(LIBCMNDIR)/libnvram.a
+BOARD_SLOF_IN = \
+	$(LIBCMNDIR)/libbootmsg/bootmsg.in \
+	$(LIBCMNDIR)/libbases/libbases.in  \
+	$(LIBCMNDIR)/libnvram/libnvram.in
+BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)
+
+include $(SLOFCMNDIR)/Makefile.inc
+
+FPPINCLUDES = -I. -I$(SLOFCMNDIR)/fs -I$(SLOFCMNDIR)
+
+# FCode Evaluator files for the ROM fs:
+FCODE_FFS_FILES = \
+       $(SLOFCMNDIR)/fs/fcode/core.fs \
+       $(SLOFCMNDIR)/fs/fcode/evaluator.fs \
+       $(SLOFCMNDIR)/fs/fcode/big.fs \
+       $(SLOFCMNDIR)/fs/fcode/tokens.fs \
+       $(SLOFCMNDIR)/fs/fcode/1275.fs
+
+
+USB_FFS_FILES = \
+	$(SLOFCMNDIR)/fs/devices/pci-class_0c.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-ohci.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-hub.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-enumerate.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage-wrapper.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-keyboard.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-kbd-device-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-mouse.fs \
+	$(SLOFCMNDIR)/fs/scsi-support.fs
+
+
+
+# Files that should go into the ROM fs (and so have to be listed in OF.ffs):
+OF_FFS_FILES = \
+	$(SLOFBRDDIR)/u4-mem.fs \
+	$(SLOFBRDDIR)/attu.fs \
+	$(SLOFBRDDIR)/cpu.fs \
+	$(SLOFBRDDIR)/ioapic.fs \
+	$(SLOFBRDDIR)/pci-bridge_1022_7460.fs \
+	$(SLOFBRDDIR)/pci-device_1014_028c.fs \
+	$(SLOFBRDDIR)/pci-device_1014_02bd.fs \
+	$(SLOFBRDDIR)/pci-device_1022_7468.fs \
+	$(SLOFBRDDIR)/pci-device_1022_7469.fs \
+	$(SLOFBRDDIR)/pci-device_1022_7451.fs \
+	$(SLOFBRDDIR)/pci-class_03.fs \
+	$(SLOFBRDDIR)/vga-display.fs \
+	$(SLOFBRDDIR)/freq.fs \
+	$(SLOFBRDDIR)/pci-device_1002_515e.fs \
+	$(SLOFBRDDIR)/citrine.fs \
+	$(SLOFBRDDIR)/citrine-disk.fs \
+	$(SLOFBRDDIR)/sio.fs \
+	$(SLOFBRDDIR)/tpm.fs \
+	$(SLOFBRDDIR)/ipmi-kcs.fs \
+	$(SLOFCMNDIR)/fs/ide.fs \
+	$(SLOFCMNDIR)/fs/fbuffer.fs \
+	$(SLOFCMNDIR)/fs/generic-disk.fs \
+	$(SLOFCMNDIR)/fs/pci-device.fs \
+	$(SLOFCMNDIR)/fs/pci-bridge.fs \
+	$(SLOFCMNDIR)/fs/pci-properties.fs \
+	$(SLOFCMNDIR)/fs/pci-config-bridge.fs \
+	$(SLOFCMNDIR)/fs/update_flash.fs \
+	$(SLOFCMNDIR)/fs/xmodem.fs \
+	$(SLOFCMNDIR)/fs/devices/pci-device_10de_0141.fs \
+	$(SLOFCMNDIR)/fs/devices/pci-class_02.fs \
+	$(SLOFBRDDIR)/default-font.bin \
+	$(FCODE_FFS_FILES)
+
+# Uncomment the following line to enable the USB code:
+OF_FFS_FILES += $(USB_FFS_FILES)
+
+OF_FFS_FILES := $(OF_FFS_FILES:%.fs=%.fsi)
+
+OF.ffs: Makefile $(SLOFCMNDIR)/Makefile.inc $(OF_FFS_FILES)
+	$(MAKE) create_OF_ffs
+
+# Rules for cleaning up:
+.PHONY: clean_here clean distclean
+
+clean_here:
+	rm -f *.o OF.fsi OF.ffs
+
+clean: clean_here clean_slof
+
+distclean: clean_here distclean_slof
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/OF.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/OF.fs
new file mode 100644
index 0000000..894f43a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/OF.fs
@@ -0,0 +1,546 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ The master file.  Everything else is included into here.
+
+hex
+
+' ll-cr to cr
+
+\ as early as possible we want to know if it is js20, js21 or bimini
+\ u3 = js20; u4 = js21/bimini
+\ the difference if bimini or js21 will be done later depending if
+\ obsidian or citrine is found
+\ f8000000 is probably the place of the u3/u4 version
+f8000000 rl@ CONSTANT uni-n-version
+uni-n-version 4 rshift  dup 3 = CONSTANT u3?  4 = CONSTANT u4?
+\ if (f4000682 >> 4) == 1... it is a bimini...
+f4000682 rb@ 4 rshift 1 = CONSTANT bimini?
+
+\ to decide wether vga initialisation using bios emulation should be attempted,
+\ we need to know wether a vga-device was found during pci-scan.
+\ If it is found, this value will be set to the device's phandle
+0 value vga-device-node?
+
+\ planar-id reads back GPIO 29 30 31 and returns it as one value
+\ if planar-id >= 5 it should be GA2 else it is GA1 (JS20 only)
+defer planar-id  ( -- planar-id )
+
+: (planar-id)  ( -- planar-id)
+   \ default implementation of planar-id just returns 8
+   \ the highest possible planar id for JS20 is 7
+   8
+;
+
+' (planar-id) to planar-id
+
+#include "header.fs"
+
+\ I/O accesses.
+#include "io.fs"
+
+\ XXX: Enable first UART on JS20, scripts forget to do this.  Sigh.
+3 7 siocfg!  1 30 siocfg!
+
+#include "serial.fs"
+
+cr
+
+#include "base.fs"
+
+\ Little-endian accesses.  Also known as `wrong-endian'.
+#include <little-endian.fs>
+
+\ do not free-mem if address is not within the heap
+\ workaround for NVIDIA card
+: free-mem  (  addr len -- )
+   over heap-start heap-end within  IF
+      free-mem
+   ELSE
+      2drop
+   THEN
+;
+
+: #join  ( lo hi #bits -- x )  lshift or ;
+: #split ( x #bits -- lo hi )  2dup rshift dup >r swap lshift xor r> ;
+
+: blink ;
+
+: reset-dual-emit ;
+
+: console-clean-fifo ;
+
+: bootmsg-nvupdate ;
+
+: asm-cout 2drop drop ;
+
+#include "logging.fs"
+
+: log-string 2drop ;
+
+#include "bootmsg.fs"
+
+000 cp
+
+\ disable the nvram logging until we know if we are
+\ running from ram/takeover/js20 or in normal mode on js21
+: (nvramlog-write-byte)  drop ;
+' (nvramlog-write-byte) to nvramlog-write-byte
+
+#include "exception.fs"
+
+: mm-log-warning 2drop ;
+
+: write-mm-log ( data length type -- status )
+	3drop 0
+;
+
+080 cp
+
+#include "rtc.fs"
+
+100 cp
+
+\ Input line editing.
+#include "accept.fs"
+
+120 cp
+
+#include "dump.fs"
+
+cistack ciregs >r1 ! \ kernel wants a stack :-)
+
+#include "romfs.fs"
+
+140 cp
+#include "flash.fs"
+
+\ 1 temp; 0 perm; let's default to temp
+1 VALUE flashside?
+
+\ claim the memory used by copy of the flash
+flash-header  IF
+   romfs-base dup flash-image-size 0 claim drop
+THEN
+
+s" bootinfo" romfs-lookup drop c + l@ CONSTANT start-addr
+start-addr flash-addr <> CONSTANT takeover?
+
+takeover? u3? or 0=  IF
+   \ we want nvram logging to work
+   ['] .nvramlog-write-byte to nvramlog-write-byte
+THEN
+
+160 cp
+
+u4? IF f8002100 rl@ 0= ELSE false THEN  ?INCLUDE u4-mem.fs
+u3?  IF
+   planar-id 5 >=  IF
+      40000 to nvram-size
+   ELSE
+      \ change nvram-size to 8000 for GA1 blades
+      8000 to nvram-size
+   THEN
+THEN
+
+
+takeover?  IF
+   \ potentially comming from phype
+   u4?  IF
+      \ takeover on JS21 is using some nvram area
+      \ which might be available
+      \ on JS20 the nvram is too small and
+      \ we just overwrite the nvram
+      sec-nvram-base to nvram-base
+   THEN
+   sec-nvram-size to nvram-size
+   \ in takeover mode the nvram is probably not mapped
+   \ to the exact location where the nvram starts
+   \ doing a small check to see if we have a partition
+   \ starting with 70; this test is far from perfect but
+   \ takeover is not the most common mode of running slof
+   nvram-base rb@ 70 <>  IF  0 nvram-base rb!  THEN
+THEN
+
+200 cp
+
+#include <slof-logo.fs>
+#include <banner.fs>
+
+: .banner .slof-logo .banner ;
+
+\ Get the secondary CPUs into our own spinloop.
+f8000050 rl@ CONSTANT master-cpu
+\ cr .( The master cpu is #) master-cpu .
+
+VARIABLE cpu-mask
+: get-slave ( n -- online? )
+  0 3ff8 ! 18 lshift 30000000 or 48003f02 over l! icbi 10000 0 DO LOOP 3ff8 @ ;
+: mark-online ( n -- )  1 swap lshift cpu-mask @ or cpu-mask ! ;
+: get-slaves  40 0 DO i get-slave IF i mark-online THEN LOOP ;
+: cpu-report  ( -- )
+   cpu-mask @ 40 0  DO  dup 1 and  IF  ." #" i .  THEN  1 rshift  LOOP  drop
+;
+
+220 cp
+master-cpu mark-online get-slaves
+
+DEFER disable-watchdog ( -- )
+DEFER find-boot-sector ( -- )
+
+
+240 cp
+\ Timebase frequency, in Hz.
+\ -1 VALUE tb-frequency
+d# 14318378 VALUE tb-frequency   \ default value - needed for "ms" to work
+-1 VALUE cpu-frequency
+
+#include "helper.fs"
+260 cp
+
+#include <timebase.fs>
+
+280 cp
+
+\ rtas-config is not used
+0 CONSTANT rtas-config
+
+#include "rtas.fs"
+290 cp
+s" update_flash.fs" included
+2a0 cp
+cpu-mask @ rtas-fetch-cpus drop
+
+: of-start-cpu rtas-start-cpu ;
+
+' power-off to halt
+' rtas-system-reboot to reboot
+
+: other-firmware  rtas-get-flashside 0= IF 1 ELSE 0 THEN rtas-set-flashside reboot ;
+: disable-boot-watchdog rtas-stop-bootwatchdog drop ;
+' disable-boot-watchdog to disable-watchdog
+
+true value bmc?
+false value debug-boot?
+
+\ for JS21/Bimini try to detect BMC... if kcs (io @ca8) status is not ff...
+u4? IF ca8 4 + io-c@ ff = IF false to bmc? true to debug-boot? THEN THEN
+
+VARIABLE memnode
+
+\ Hook to help loading our secondary boot loader.
+DEFER disk-read ( lba cnt addr -- )
+0 VALUE disk-off
+
+create vpd-cb 24 allot
+create vpd-bootlist 4 allot
+2c0 cp
+#include "ipmi-vpd.fs"
+2e0 cp
+#include <quiesce.fs>
+300 cp
+#include <usb/usb-static.fs>
+320 cp
+#include <scsi-loader.fs>
+#include <root.fs>
+360 cp
+#include "tree.fs"
+
+: .system-information  ( -- )
+   s"                   " type cr
+   s" SYSTEM INFORMATION" type cr
+   s"  Processor  = " type s" cpu" get-chosen  IF
+      drop l@ >r pvr@ s" pvr>name" r> $call-method type
+      s"  @ " type cpu-frequency d# 1000000 /
+      decimal . hex s" MHz" type
+   THEN  cr s"  I/O Bridge = " type u3?  IF
+      s" U3"  ELSE  s" U4"  THEN type
+   f8000000 rl@ 4 rshift s"  (" type 1 0.r s" ." type
+   f8000000 rl@ f and 1 0.r s" )" type cr
+   s"  SMP Size   = " type cpu-mask @ cnt-bits 1 0.r
+   s"  (" type cpu-report 8 emit s" )" type
+   cr s"  Boot-Date  = " type .date cr
+   s"  Memory     = " type s" memory" get-chosen  IF
+      drop l@ s" mem-report" rot $call-method  THEN
+   cr s"  Board Type = " type u3?  IF
+      s" JS20(GA" type planar-id 5 >=  IF
+         s" 2)" ELSE s" 1)" THEN type
+   ELSE bimini?  IF  s" Bimini"  ELSE  s" JS21"  THEN  type  THEN
+   s"  (" type .vpd-machine-type [char] / emit
+   .vpd-machine-serial [char] / emit
+   .vpd-hw-revision 8 emit  s" )" type cr
+   s"  MFG Date   = " type .vpd-manufacturer-date cr
+   s"  Part No.   = " type .vpd-part-number cr
+   s"  FRU No.    = " type .vpd-fru-number cr
+   s"  FRU Serial = " type .vpd-cardprefix-serial .vpd-card-serial cr
+   s"  UUID       = " type .vpd-uuid cr
+   s"  Flashside  = " type rtas-get-flashside 0=  IF
+      ." 0 (permanent)"
+   ELSE
+      ." 1 (temporary)" THEN cr
+   s"  Version    = " type 
+   takeover?  IF
+      romfs-base 38 + a type
+   ELSE
+      slof-build-id here swap rmove 
+      here slof-build-id nip type cr
+      s"  Build Date = " type bdate2human type
+   THEN
+   cr cr
+;
+
+800 cp
+
+#include "nvram.fs"
+takeover? not u4? and  IF
+   \ if were are not in takeover mode the nvram should look
+   \ something like this:
+   \ type  size  name
+   \ ========================
+   \  51  20000  ibm,CPU0log
+   \  51   5000  ibm,CPU1log
+   \  70   1000  common
+   \  7f  da000  <free-space>
+   \ the partition with the type 51 should have been added
+   \ by LLFW... if it does not exist then something went
+   \ wrong and we just destroy the whole thing
+   51 get-nvram-partition IF  0 0 nvram-c!  ELSE  2drop  THEN
+THEN
+
+880 cp
+
+\ dmesg/dmesg2 not available if running in takeover/ram mode or on js20
+: dmesg  ( -- )  u3? takeover? or 0=  IF  dmesg  THEN ;
+: dmesg2  ( -- )  u3? takeover? or 0=  IF  dmesg2  THEN ;
+
+#include "envvar.fs"
+check-for-nvramrc
+
+8a0 cp
+\ The client interface.
+#include "client.fs"
+\ ELF binary file format.
+#include "elf.fs"
+#include <loaders.fs>
+
+: bios-exec ( arg len -- rc )
+   s" snk" romfs-lookup 0<> IF load-elf-file drop start-elf64
+   ELSE 2drop false THEN
+;
+
+\ check wether a VGA device was found during pci scan, if it was
+\ try to initialize it and create the needed device-nodes
+0 value biosemu-vmem
+100000 value biosemu-vmem-size
+0 value screen-info
+
+vga-device-node? 0<> use-biosemu? AND IF
+   s" VGA Device found: " type vga-device-node? node>path type s"  initializing..." type cr
+   \ claim virtual memory for biosemu of 1MB
+   biosemu-vmem-size 4 claim to biosemu-vmem
+   \ claim memory for screen-info struct (140 bytes)
+   d# 140 4 claim to screen-info
+   \ remember current-node (it might be node 0 so we cannot use get-node)
+   current-node @
+   \ change into vga device node
+   vga-device-node? set-node
+   \ run biosemu to initialize the vga card
+   \ s" Time before biosemu:" type .date cr
+   vga-device-node? node>path ( pathstr len )
+   s" biosemu " biosemu-vmem $cathex ( pathstr len paramstr len )
+   20 char-cat \ add a space ( pathstr len paramstr len )
+   biosemu-vmem-size $cathex \ add VMEM Size ( pathstr len paramstr len )
+   20 char-cat \ add a space ( pathstr len paramstr len )
+   2swap $cat ( paramstr+path len )
+   biosemu-debug 0<> IF
+      20 char-cat biosemu-debug $cathex \ add biosemu-debug as param
+      ( paramstr+path+biosemu-debug len )
+   THEN
+   bios-exec
+   \ s" Time after biosemu:" type .date cr
+   s" VGA initialization: detecting displays..." type cr
+   \ try to get info for two monitors
+   2 0 DO 
+      \ setup screen-info struct as input to get_vbe_info
+      s" DDC" 0 char-cat screen-info swap move \ null-terminated "DDC" as signature
+      d# 140 screen-info 4 + w! \ reserved size in bytes (see claim above)
+      i screen-info 6 + c! \ monitor number
+      \ 320 screen-info 7 + w! \ max. screen width (800)
+      500 screen-info 7 + w! \ max. screen width (1280)
+      \ following line would be the right thing to do, however environment seems not setup yet...
+      \ screen-#columns char-width * 500 min 280 max screen-info 7 + w! \ max. screen width, calculated from environment variable screen-#columns, but max. 1280, min. 640...
+      8 screen-info 9 + c! \ requested color depth (8bpp)
+      \ d# 16 screen-info 9 + c! \ requested color depth (16bpp)
+      \ execute get_vbe_info from load-base
+      \ s" Time before client exec:" type .date cr
+      \ since node>path overwrites strings created with s" 
+      \ we need to call it before assembling the parameter string
+      vga-device-node? node>path ( pathstr len )
+      s" get_vbe_info " biosemu-vmem $cathex ( pathstr len paramstr len )
+      20 char-cat \ add a space ( pathstr len paramstr len )
+      biosemu-vmem-size $cathex \ add VMEM Size ( pathstr len paramstr len )
+      20 char-cat \ add a space ( pathstr len paramstr len )
+      2swap $cat ( paramstr+path len )
+      20 char-cat
+      screen-info $cathex bios-exec
+      \ s" Time after client exec:" type .date cr
+      screen-info c@ 0<> IF
+        s"   display " type i . s" found..." type 
+        \ screen found
+        \ create device entry
+        get-node node>name \ get current nodes name (e.g. "vga") ( str len )
+        i \ put display-num on the stack ( str len displaynum )
+        new-device \ create new device
+           s" vga-display.fs" included
+        finish-device
+        s" created." type cr
+      THEN
+   LOOP
+   \ return to where we were before changing to vga device node
+   set-node
+   \ release the claimed memory
+   screen-info d# 140 release 
+   biosemu-vmem biosemu-vmem-size release
+
+   s" VGA initialization done." type cr
+THEN \ vga-device-node?
+
+: enable-framebuffer-output  ( -- )
+\ enable output on framebuffer
+   s" screen" find-alias ?dup  IF
+      \ we need to open/close the screen device once
+      \ before "ticking" display-emit to emit
+      open-dev close-node
+      s" display-emit" $find  IF 
+         to emit 
+      ELSE
+         2drop
+      THEN
+   THEN
+;
+
+enable-framebuffer-output
+
+8b0 cp
+
+\ do not let the usb scan overwrite the atapi cdrom alias
+pci-cdrom-num TO cdrom-alias-num
+usb-scan
+
+: create-aliases  ( -- )
+   s" net" s" net1" find-alias ?dup  IF  set-alias ELSE 2drop  THEN
+   s" disk" s" disk0" find-alias ?dup  IF  set-alias  ELSE  2drop  THEN
+   s" cdrom" s" cdrom0" find-alias ?dup  IF  set-alias  ELSE  2drop  THEN
+;
+
+create-aliases
+
+8ff cp
+
+.system-information
+
+: directserial
+u3? IF
+	s" /ht/isa/serial at 3f8" io
+ELSE
+	s" direct-serial?" evaluate IF s" /ht/isa/serial at 2f8" io ELSE s" /ht/isa/serial at 3f8" io THEN
+THEN
+;
+
+directserial
+  
+\ on bimini we want to automatically enable screen and keyboard, if they are detected...
+bimini? IF
+   key? IF
+      cr ."    input available on current console input device, not switching input / output." cr
+   ELSE
+      \ this enables the framebuffer as primary output device
+      s" screen" find-alias  IF  drop
+         s" screen" output
+         \ at this point serial output is theoretically disabled
+         ."    screen detected and set as default output device" cr
+      THEN
+      \ enable USB keyboard
+      s" keyboard" find-alias  IF  drop
+         s" keyboard" input
+         \ at this point serial input is disabled
+         ."    keyboard detected and set as default input device" cr cr cr
+         s"   Press 's' to enter Open Firmware." type cr
+         500 ms
+      THEN
+   THEN
+THEN
+
+: .flashside
+   cr ." The currently active flashside is: "
+   rtas-get-flashside 0= IF ." 0 (permanent)" ELSE
+   ." 1 (temporary)" THEN
+;
+
+bmc? IF  disable-watchdog  THEN
+
+: flashsave  ( "{filename}" -- rc )
+  (parse-line) dup 0> IF
+    s" netsave "             \ command
+    get-flash-base $cathex   \ Flash base addr
+    s"  400000 " $cat        \ Flash size (4MB)
+    2swap $cat               \ add parameters from (parse-line)
+    evaluate
+  ELSE
+    cr
+    ." Usage: flashsave [bootp|dhcp,]filename[,siaddr][,ciaddr][,giaddr][,bootp-retries][,tftp-retries][,use_ci]"
+    cr 2drop
+  THEN
+;
+
+#include <vpd-bootlist.fs>
+
+\ for the blades we read the bootlist from the VPD
+bimini? takeover? or 0=  IF  ['] vpd-boot-import to read-bootlist  THEN
+
+\ for the bimini, we try to boot from disk, if it exists, 
+\ only if "boot-device" is not set in the nvram
+: bimini-bootlist
+   \ check nvram
+   s" boot-device" evaluate swap drop ( boot-device-strlen )
+   0= IF
+      \ no boot-device set in NVRAM, check if disk is available and set it...
+      \ clear boot-device list
+      0 0 set-boot-device
+      s" disk" find-alias ?dup IF
+         \ alias found, use it as default
+         add-boot-device
+      THEN
+   THEN
+;
+
+bimini? IF ['] bimini-bootlist to read-bootlist THEN
+
+#include <start-up.fs>
+
+#include <boot.fs>
+
+cr .(   Welcome to Open Firmware)
+cr
+#include "copyright-oss.fs"
+cr
+
+\ this CATCH is to ensure the code bellow always executes:  boot may ABORT!
+' start-it CATCH drop
+
+#include <history.fs>
+nvram-history? [IF]
+." loading shell history .. "
+history-load
+." done" cr
+[THEN]
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/attu.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/attu.fs
new file mode 100644
index 0000000..cc12252
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/attu.fs
@@ -0,0 +1,101 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ U4 "Attu" PCIe root complex.
+
+\ See the PCI OF binding document.
+
+new-device
+
+s" pciex" device-name s" pci" device-type
+s" U4-pcie" compatible
+s" U4" encode-string s" model" property
+
+\ spare out 0xc0000000-0xefffffff for pcie
+f8070200 rl@ fffffff0 and f8070200 rl!
+\ enable io memory for pcie @ c0000000-efffffff
+70000003 f80903f0 rl!-le
+
+3 encode-int s" #address-cells" property
+2 encode-int s" #size-cells" property
+
+s" /mpic" find-node encode-int s" interrupt-parent" property
+\ XXX should have interrupt map, etc.  this works for now though.
+
+: decode-unit  2 hex-decode-unit  3 #join  8 lshift  0 0 rot F00000 + ;
+: encode-unit  nip nip  ff00 and 8 rshift  3 #split
+               over IF 2 ELSE nip 1 THEN hex-encode-unit ;
+
+f1000000 CONSTANT my-puid
+\ Configuration space accesses.
+: >config  f1000000 + ;
+: config-l!  >config rl!-le ;
+: config-l@  >config rl at -le ;
+: config-w!  >config rw!-le ;
+: config-w@  >config rw at -le ;
+: config-b!  >config rb! ;
+: config-b@  >config rb@ ;
+
+: config-dump ( addr size -- )  ['] config-l@ 4 (dump) ;
+
+\ 16MB of configuration space
+f1000000 encode-64 1000000 encode-64+ s" reg" property
+
+\ 4MB of I/O space.
+01000000 encode-int  00000000 encode-int+ 00000000 encode-int+ 
+00000000 encode-int+ f0000000 encode-int+ 
+00000000 encode-int+ 00400000 encode-int+
+
+\ 1.75GB of memory space @ c0000000.
+02000000 encode-int+ c0000000 encode-64+
+c0000000 encode-64+  30000000 encode-64+ s" ranges" property
+
+\ Host bridge, so full bus range.
+f0 encode-int ff encode-int+ s" bus-range" property
+
+: open  true ;
+: close ;
+
+\ : probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- )
+s" /mpic" find-node my-puid pci-irq-init drop
+
+00fff1f0 18 config-l!
+
+ff F0 f0000000 e8000000 e8000000 c0000000 100000000 f000
+my-puid probe-pci-host-bridge
+
+\ \ PCIe debug / fixup
+: find-pcie-cap  ( devfn -- offset | 0 )
+   >r 34  BEGIN  r@ + config-b@ dup ff <> over and  WHILE
+       dup r@ + config-b@ 10 =  IF
+          r> drop EXIT
+       THEN 1+
+   REPEAT r> 2drop 0
+;
+
+ : (set-ps) ( ps addr -- )
+   8 + >r 5 lshift r@ config-w@ ff1f and or r> config-w! ;
+ : set-ps ( ps -- )
+   log2 7 -
+   10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF
+   + 2dup (set-ps) THEN drop LOOP drop ;
+ 
+ : (set-rr) ( rr addr -- )
+   8 + >r c lshift r@ config-w@ 8fff and or r> config-w! ;
+ : set-rr ( rr -- )
+   log2 7 -
+   10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF
+   + 2dup (set-rr) THEN drop LOOP drop ;
+
+80 set-ps  80 set-rr  
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-disk.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-disk.fs
new file mode 100644
index 0000000..146e7ec
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-disk.fs
@@ -0,0 +1,79 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+( max-#blocks rsrc id -- )
+
+new-device   
+
+lwsplit swap wbsplit rot set-unit
+
+s" disk" device-name  s" block" device-type
+
+CONSTANT resource-id
+CONSTANT max-#blocks
+get-parent CONSTANT ppack
+
+
+: our-disk-read ( lba count addr -- )
+  >r >r >r resource-id r> r> r> s" do-read" ppack $call-static ;
+
+0 pci-alias-disk
+
+\ Requiered interface for deblocker
+
+200   CONSTANT block-size
+40000 CONSTANT max-transfer 
+
+: read-blocks ( addr block# #blocks -- #read )
+\   my-unit s" dev-read-blocks" $call-parent
+   \ check if the read is within max-#blocks
+   2dup + max-#blocks 1 + > IF 
+     \ 2drop drop 0 \ return 0 
+     \ returning 0 would be correct (maybe?) but it confuses the deblocker...
+     \ so i erase whatever would have been read and return the "expected" #read
+     dup >r 
+     swap drop \ drop block# (not needed)
+     block-size * erase \ erase at addr #blocks * block-size
+     r>   \ return #read 
+   ELSE
+     dup >r rot our-disk-read r>
+   THEN
+;    
+
+INSTANCE VARIABLE deblocker
+
+: open ( -- okay? )
+   0 0 s" deblocker" $open-package dup deblocker ! dup IF 
+      s" disk-label" find-package IF
+	 my-args rot interpose
+      THEN
+   THEN 0<> ;
+
+: close ( -- )
+   deblocker @ close-package ;
+
+: seek ( pos.lo pos.hi -- status )
+   2dup lxjoin max-#blocks 1 + block-size *  > IF 
+     \ illegal seek, return -1
+     2drop -1
+   ELSE
+     s" seek" deblocker @ $call-method
+   THEN
+;
+
+: read ( addr len -- actual )
+   s" read" deblocker @ $call-method ;
+
+
+finish-device
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-flash.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-flash.fs
new file mode 100644
index 0000000..5842b07
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine-flash.fs
@@ -0,0 +1,36 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ we do all flash accesses as 8-bit
+
+9f000000 CONSTANT citrine-flash-addr
+
+: >citrine-flash  citrine-flash-addr + ;
+: citrine-flash@  >citrine-flash rb@ ;
+: citrine-flash!  >citrine-flash rb! ;
+: wait-for-citrine-flash-ready  BEGIN 0 citrine-flash@ 80 and UNTIL ;
+: erase-citrine-flash-block ( offset -- )
+  cr dup 8 .r ."  Erasing..."
+  20 over citrine-flash! d0 swap citrine-flash! wait-for-citrine-flash-ready ;
+: write-citrine-flash ( data offset -- )
+  over ff = IF 2drop EXIT THEN
+  40 over citrine-flash! citrine-flash! wait-for-citrine-flash-ready ;
+: write-citrine-flash-block ( addr offset -- ) \ always writes 128kB!
+  ."  Writing..."
+  20000 0 DO over i + c@ over i + write-citrine-flash LOOP 2drop
+  ."  Done." ;
+: citrine-flash ( addr offset size -- )
+  BEGIN dup 0 > WHILE >r dup erase-citrine-flash-block
+  2dup write-citrine-flash-block >r 20000 + r> 20000 + r> 20000 - REPEAT
+  drop 2drop -1 0 citrine-flash! ;
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine.fs
new file mode 100644
index 0000000..ee26c9a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/citrine.fs
@@ -0,0 +1,242 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Citrine storage controller.
+2dup type
+
+device-name s" ide" device-type
+
+
+3 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+: decode-unit  3 hex-decode-unit ;
+: encode-unit  3 hex-encode-unit ;
+
+
+: >ioa  [ 10 config-l@ -10 and ] LITERAL + ;
+: ioa@  >ioa rl at -le ;
+: ioa!  >ioa rl!-le ;
+
+
+\ Clear request completion doorbell.
+2 228 ioa!
+
+\ status
+CREATE ioasa 200 allot  ioasa 200 erase \ can reduce to 8 later
+
+\ request/response queue
+CREATE rrq 100 allot  rrq 100 erase \ can be smaller
+
+\ data descriptor
+CREATE ioadl 8 allot
+
+\ control block
+CREATE ioarcb 80 allot  ioarcb 80 erase
+ioarcb dup l!
+60708090 ioarcb c + l! \ user handle
+ioadl ioarcb 2c + l! \ read ioadl
+ioasa ioarcb 34 + l!  200 ioarcb 38 + w!
+
+\ ioa config data (max. 16 devices)
+CREATE ioacfg 404 allot  ioacfg 404 erase
+CREATE setsupbuff  2c allot  setsupbuff 2c erase 2c setsupbuff w! 1 setsupbuff + 3 c!
+
+: wait-ready ( -- )
+	82800000 214 ioa!
+	80000000 BEGIN dup 224 ioa@ cr .s dup 8000000 and IF 
+		cr ." Unit check on SAS-Controller detected"
+		cr 42c ioa@ .
+		8 110 ioa!
+ 		BEGIN cr 0 config-l@ dup . ffffffff <> UNTIL
+\		ABORT" Unit check on SAS-Controller detected"
+	THEN
+	and
+	UNTIL drop 
+;
+
+\ wait-ready
+
+: wait-ioa ( int-mask -- )  BEGIN dup 224 ioa@ and UNTIL drop ;
+: init-ioa ( -- )  82800000 214 ioa!  80000000 wait-ioa ;
+: do-request ( -- )  ioasa 20 erase  ioarcb 404 ioa!
+                     2 wait-ioa 2 228 ioa! 
+;
+
+: setup-ioarcb ( rsrc type addr len -- )
+  tuck  49000000 or ioadl l!  ioadl 4 + l! \ setup ioadl
+  ioarcb 20 + l!  ioadl ioarcb 2c + l! 8 ioarcb 30 + l! \ set len, ioadl addr
+  ioarcb 3e + c!  ioarcb 8 + l! \ set type and resource
+  ioarcb 40 + 40 erase ;
+
+: setup-wrioarcb ( rsrc type addr len -- )
+  tuck  49000000 or ioadl l!  ioadl 4 + l! \ setup ioadl
+  ioarcb 1C + l!  ioadl ioarcb 24 + l! 8 ioarcb 28 + l! \ set len, ioadl addr
+  ioarcb 3e + c!  ioarcb 8 + l! \ set type and resource
+  ioarcb 40 + 40 erase ;
+
+: setup-idrrq ( rrq len -- )
+  c4 ioarcb 42 + c!  8 lshift ioarcb 48 + l!  ioarcb 44 + l! ;
+: do-idrrq ( -- )  -1 1 0 0 setup-ioarcb  rrq 100 setup-idrrq  do-request ;
+
+: setup-query ( len -- )  c5 ioarcb 42 + c!  8 lshift ioarcb 48 + l! ;
+: do-query ( -- )  -1 1 ioacfg 404 setup-ioarcb  404 setup-query  do-request ;
+
+: setup-startUnit ( -- )  1b ioarcb 42 + c! 3 ioarcb 46 + c! ;
+: do-startUnit ( hndl -- )  0 0 0 setup-ioarcb  setup-startUnit  do-request ;
+
+: setup-setsupported ( len -- ) 80 ioarcb 40 + c! fb ioarcb 42 + c! 8 lshift ioarcb 48 + l! ;
+: do-setsupported (  -- )  -1 1 setsupbuff 2c setup-wrioarcb  2c setup-setsupported  do-request ;
+
+\ ********************************
+\ read capacity
+\ ********************************
+CREATE cap 8 allot
+
+: setup-cap ( -- ) 25 ioarcb 42 + c!  cap 8 erase ;
+: do-cap ( rsrc addr -- )
+  >r 0 r> 8 setup-ioarcb  setup-cap  do-request ;
+
+: .id  ( id -- )  ." @" lwsplit 2 0.r ." ," wbsplit 2 0.r ." ," 2 0.r ;
+
+: .cap ( rsrc -- )
+  cap do-cap cap l@ cap 4 + l@ * d# 50000000 + d# 100000000 /
+  base @ >r decimal d# 10 /mod 4 .r ." ." 0 .r ." GB" r> base ! ;
+
+\ ********************************
+\ Test Unit Ready
+\ ********************************
+: setup-test-unit-ready ( -- )
+   00 ioarcb 42 + c!   \ SCSI cmd: Test-Unit-Ready
+;
+
+: do-test-unit-ready       ( rsrc -- )
+   0 0 0 setup-ioarcb      ( rsrc type addr len -- )
+   setup-test-unit-ready
+   do-request
+;
+
+\ ********************************
+\ Check devices
+\ ********************************
+: check-device  ( ioacfg-entry -- )
+   dup 2 + w@ 2001 and 0<>       \ generic or raid disk
+   IF                            \ is an IOA resource ?
+      dup 8 + l@                 ( ioacfg-entry rsrc )  \ get resource handle
+      8 0
+      DO                         ( ioacfg-entry rsrc )
+         dup do-test-unit-ready  ( ioacfg-entry rsrc )
+         ioasa l@ 0=             \ read returned status
+         IF
+            LEAVE
+         THEN
+      LOOP
+      drop                       ( ioacfg-entry )
+   THEN
+   drop  (  )
+;
+
+: check-devices   ( -- )
+   ioacfg 4 +     ( ioacfg-entry )  \ config block for 16 devices
+   ioacfg c@ 0    \ amount of detected devices
+   ?DO
+      dup
+      check-device   ( ioacfg-entry )
+      40 +
+   LOOP
+   drop
+;
+
+\ ********************************
+\ Show Devices
+\ ********************************
+: show-device  ( ioacfg-entry -- )
+   cr ."     " dup 2 + w@
+   dup 8000 and  IF  ." Controller         :"  THEN
+   dup 2000 and  IF  ."  Disk (RAID Member):"  THEN
+   dup 0002 and  IF  ."  Disk (Volume Set) :"  THEN
+   0001 and  IF  ."  Disk (Generic)    :"  THEN
+   space dup 4 + l@ ffffff and dup ffffff <>  IF
+      .id
+   ELSE  drop 9 spaces  THEN  space
+   dup 1c + 8 type space dup 24 + 10 type
+   dup 2 + w@ 8000 and 0=  IF
+      space dup 8 + l@ .cap 
+   THEN drop
+;
+
+: show-devices  ( -- )
+   ioacfg 4 + ioacfg c@ 0
+   ?DO dup show-device 40 + LOOP drop
+;
+
+: setup-read  ( lba len -- ) \ len is in blocks
+   28 ioarcb 42 + c!
+   swap ioarcb 44 + l!
+   8 lshift ioarcb 48 + l!
+;
+
+: do-read  ( hndl lba len addr -- )  \ len is in blocks
+   over >r rot >r swap 0 -rot 200 * ( 0 hndl addr len* ) 
+   setup-ioarcb r> r> ( lba len ) 
+   setup-read do-request 
+;
+
+: make-subnode  ( rsrc-type rsrc-handle id -- )
+   rot 2 and  IF  \ only device which are part of a RAID should be started
+      over do-startUnit  \ at least on citrine there are problems starting
+                         \ Generic SCSI devices
+   THEN  do-setsupported
+   dup ffffff <>  IF
+      \ we need max-#blocks for citrine-disk.fs
+                             ( rsrc id )
+      over cap do-cap cap l@ ( rsrc id max-#blocks )
+      swap rot swap ( max-#block rsrc id ) \ this is what citrine-disk.fs expects...
+      s" citrine-disk.fs" included
+   ELSE
+      2drop
+   THEN
+;
+
+: make-subnodes  ( -- )
+   ioacfg 4 + ioacfg c@ 0  ?DO  dup 2 + w@ dup  ( ioacfg rsrc-type rsrc-type )
+   A000  \ 8000 = Resource Subtype is IOA Focal Point.
+         \ 2000 = Device is a member of a data redundancy group (eg. RAID).
+         \ (1000 = Device is designated for use as a hot spare.
+         \         Unfortunately obsidian reports disk which are not part of
+         \         of a RAID also as hot space even if they are not.)
+         \ all these devices should not appeat in DT
+         \ SIS40 page 60
+   and 0=  IF
+      swap dup  ( rsrc-type ioacfg ioacfg )
+      8 + l@ over 4 + l@  ( rsrc-type ioacfg rsrc-handle rsrc-addr )
+      ffffff and 2swap swap 2swap  ( ioacfg rsrc-type rsrc-handle rsrc-addr )
+      make-subnode  ELSE  drop  THEN  40 +  LOOP  drop ;
+
+: do-it  ( -- )
+   init-ioa do-idrrq
+   do-query
+   check-devices
+   show-devices
+;
+
+: setup-shutdown ( -- )
+  f7 ioarcb 42 + c!  0 ioarcb 48 + l!  0 ioarcb 44 + l! ;
+: do-shutdown ( -- )  -1 1 0 0 setup-ioarcb  setup-shutdown  do-request ;
+
+: open  true ;
+: close ;
+
+: start ['] do-it CATCH IF cr ." Citrine disabled" ELSE make-subnodes THEN ;
+
+cr start cr cr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/copyright-oss.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/copyright-oss.fs
new file mode 100644
index 0000000..06f9a3a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/copyright-oss.fs
@@ -0,0 +1,16 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+cr .(   Copyright (c) char ) emit .(  2004, 2008 IBM Corporation All rights reserved.)
+cr .(   This program and the accompanying materials are made available)
+cr .(   under the terms of the BSD License available at)
+cr .(   http://www.opensource.org/licenses/bsd-license.php)
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/cpu.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/cpu.fs
new file mode 100644
index 0000000..bee07d1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/cpu.fs
@@ -0,0 +1,44 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ CPU node.  Pretty minimal...
+
+( cpu# -- )
+new-device  set-space
+
+: pvr>name  s" PowerPC," rot 10 rshift CASE
+            39 OF s" 970"   ENDOF
+            3c OF s" 970FX" ENDOF
+            44 OF 1 my-space 1 xor lshift cpu-mask @ and IF
+                  s" 970MP" ELSE s" 970GX" THEN ENDOF
+                  \ On GX CPUs, the sibling is missing, numbering is the same.
+       dup dup OF 0 <# # # # # [char] # hold #> ENDOF ENDCASE $cat ;
+
+pvr@ pvr>name device-name
+s" cpu" device-type
+
+my-space encode-int s" reg" property
+
+tb-frequency  encode-int s" timebase-frequency" property
+cpu-frequency encode-int s" clock-frequency" property
+
+ 8000 encode-int s" d-cache-size"      property
+   80 encode-int s" d-cache-line-size" property
+10000 encode-int s" i-cache-size"      property
+   80 encode-int s" i-cache-line-size" property
+
+: open  true ;
+: close ;
+
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/dart.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/dart.fs
new file mode 100644
index 0000000..8fdac83
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/dart.fs
@@ -0,0 +1,31 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ CPC9x5 DART.
+
+new-device
+
+s" dart" 2dup device-name device-type
+u3? IF s" u3-dart" compatible THEN
+u4? IF s" u4-dart" compatible THEN
+
+0 encode-int  f8033000 encode-int+
+0 encode-int+     7000 encode-int+ s" reg" property
+
+: open  true ;
+: close ;
+
+\ Now clear and disable the DART.
+20000000 f8033000 rl!
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/flash.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/flash.fs
new file mode 100644
index 0000000..9c72182
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/flash.fs
@@ -0,0 +1,43 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ we do all flash accesses as 8-bit
+
+ff000000 CONSTANT flash-addr
+
+: >flash  flash-addr + ;
+: flash@  >flash rb@ ;
+: flash!  >flash rb! ;
+: wait-for-flash-ready  BEGIN 0 flash@ 80 and UNTIL ;
+: erase-flash-block ( offset -- )
+  cr dup 8 .r ."  Erasing..."
+  20 over flash! d0 swap flash! wait-for-flash-ready ;
+: write-flash ( data offset -- )
+  40 over flash! flash! wait-for-flash-ready ;
+: write-flash-buffer ( addr offset -- )
+  e8 over flash!  wait-for-flash-ready  1f over flash!
+  20 0 DO over i + c@ over i + flash! LOOP
+  d0 over flash! wait-for-flash-ready 2drop ;
+: write-flash-block ( addr offset -- ) \ always writes 128kB!
+  ."  Writing..."
+  20000 0 DO over i + over i + write-flash-buffer 20 +LOOP 2drop
+  ."  Done." ;
+: flash ( addr offset size -- )
+  BEGIN dup 0 > WHILE >r dup erase-flash-block 2dup write-flash-block
+  >r 20000 + r> 20000 + r> 20000 - REPEAT drop 2drop -1 0 flash! ;
+
+: flash-it  load-base 0 e0000  flash ;
+: flash4    load-base 0 400000 flash ;
+
+\ for update-flash
+: flash-image-size  ( addr -- size )  30 + rx@  ;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/freq.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/freq.fs
new file mode 100644
index 0000000..9f1d36d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/freq.fs
@@ -0,0 +1,39 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Use the HPET to calculate various frequencies.
+
+\ Make HPET run.
+1 10 hpet!
+
+\ Set PMC1 to count CPU cycles.
+f00 mmcr0!
+
+d# 1000000000000000 4 hpet@ / CONSTANT hpet-freq
+
+: get-times  tbl@ pmc1@ f0 hpet@ ;
+
+\ Calculate the CPU and TB frequencies.
+: calibrate  get-times dup >r swap >r swap >r hpet-freq d# 100 / + >r
+             BEGIN get-times dup r@ < WHILE 3drop REPEAT r> drop
+             rot r> - ffffffff and \ TB
+             rot r> - ffffffff and \ CPU
+             rot r> - >r           \ HPET
+             hpet-freq * r@ / swap
+             hpet-freq * r> / ;
+
+: round-to  tuck 2/ + over / * ;
+calibrate TO tb-frequency d# 100000000 round-to TO cpu-frequency
+
+\ Stop HPET.
+0 10 hpet!
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/header.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/header.fs
new file mode 100644
index 0000000..7248a7e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/header.fs
@@ -0,0 +1,21 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+get-flash-base VALUE flash-addr
+
+get-nvram-base CONSTANT nvram-base
+get-nvram-size CONSTANT nvram-size
+ff8f9000 CONSTANT sec-nvram-base  \ save area from phype.... not really known
+2000 CONSTANT sec-nvram-size
+
+nvram-base 20000 + CONSTANT nvram-log-be1-base
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/helper.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/helper.fs
new file mode 100644
index 0000000..34d60da
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/helper.fs
@@ -0,0 +1,28 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: slof-build-id  ( -- str len )
+   flash-header 10 + a
+;
+
+: slof-revision s" 001" ;
+
+: read-version-and-date
+   flash-header 0= IF
+   s"  " encode-string
+   ELSE
+   flash-header 10 + 10
+   here swap rmove
+   here 10
+   s" , " $cat
+   bdate2human $cat encode-string THEN
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/ht.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ht.fs
new file mode 100644
index 0000000..e122a03
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ht.fs
@@ -0,0 +1,189 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Hypertransport.
+
+\ See the PCI OF binding document.
+
+new-device
+
+s" ht" 2dup device-name device-type
+s" u3-ht" compatible
+s" U3" encode-string s" model" property
+
+3 encode-int s" #address-cells" property
+2 encode-int s" #size-cells" property
+
+s" /mpic" find-node encode-int s" interrupt-parent" property
+
+4000 encode-int 0 encode-int+ 0 encode-int+
+1 encode-int+ s" /mpic" find-node encode-int+ 
+10 encode-int+ 0 encode-int+
+s" interrupt-map" property
+
+f800 encode-int 0 encode-int+ 0 encode-int+
+7 encode-int+ s" interrupt-map-mask" property
+
+: decode-unit  2 hex-decode-unit 3 lshift or
+               8 lshift 0 0 rot ;
+: encode-unit  nip nip ff00 and 8 rshift dup 7 and swap 3 rshift
+               over IF 2 ELSE nip 1 THEN hex-encode-unit ;
+
+f2000000 CONSTANT my-puid
+\ Configuration space accesses.
+: >config  dup ffff > IF 1000000 + THEN f2000000 + ;
+
+\ : config-l!  >config cr ." config-l! " 2dup . space . rl!-le ;
+\ : config-l@  >config cr ." config-l@ " dup . rl at -le space dup . ;
+\ : config-w!  >config cr ." config-w! " 2dup . space . rw!-le ;
+\ : config-w@  >config cr ." config-w@ " dup . rw at -le space dup . ;
+\ : config-b!  >config cr ." config-b! " 2dup . space . rb! ;
+\ : config-b@  >config cr ." config-b@ " dup . rb@ space dup . ;
+
+: config-l!  >config rl!-le ;
+: config-l@  >config rl at -le ;
+: config-w!  >config rw!-le ;
+: config-w@  >config rw at -le ;
+: config-b!  >config rb! ;
+: config-b@  >config rb@ ;
+
+: config-dump ( addr size -- )  ['] config-l@ 4 (dump) ;
+
+
+\ 16MB of configuration space, seperate for type 0 and type 1.
+00000000 encode-int  f2000000 encode-int+
+00000000 encode-int+ 02000000 encode-int+ s" reg" property
+
+\ 4MB of I/O space.
+01000000 encode-int  00000000 encode-int+ 00000000 encode-int+ 
+00000000 encode-int+ f4000000 encode-int+ 
+00000000 encode-int+ 00400000 encode-int+
+
+\ 1 GB of memory space @ 80000000
+02000000 encode-int+ 00000000 encode-int+ 80000000 encode-int+ 
+00000000 encode-int+ 80000000 encode-int+ 
+00000000 encode-int+ 40000000 encode-int+ s" ranges" property
+
+\ Host bridge, so full bus range.
+0 encode-int ff encode-int+ s" bus-range" property
+
+: enable-ht-apic-space 3c0300fe f8070200 rl! ;
+enable-ht-apic-space
+
+\ spare out 0xc0000000-0xefffffff for pcie
+f8070200 rl@ fffffff0 and f8070200 rl!
+\ enable io memory for pcie @ c0000000-efffffff
+70000003 f80903f0 rl!-le
+
+
+\ Workaround for "takeover" boot on JS20: the top 8131 is programmed to be
+\ device #1f, while it should be #01.
+u3? IF f800 config-l@ 74501022 = IF 41 f8c2 config-w! THEN THEN
+
+\ Assign BUIDs.
+
+: find-ht-primary
+  34 BEGIN config-b@ dup 0= ABORT" No HT capability block found!"
+  dup config-l@ e00000ff and 8 = IF 2 + EXIT THEN 1 + AGAIN ;
+
+: assign-buid ( this -- next )
+  find-ht-primary dup >r config-w@ 5 rshift 1f and over r> config-b! + ;
+
+: assign-buids ( -- )
+  1 BEGIN 0 config-l@ ffffffff <> WHILE assign-buid REPEAT drop ;
+
+assign-buids 
+
+: ldtstop  f8000840 rl@ 40000 or f8000840 rl! ;
+: delay 100000 0 DO LOOP ;
+: wait-for-done  BEGIN f8070110  rl@ 30 and UNTIL
+                 BEGIN 8b4 config-l@ 30 and UNTIL ;
+: ldtstop1  f8000840 rl@ dup 20000 or f8000840 rl! delay
+            f8000840 rl! wait-for-done ;
+: warm  400000 f8070300 rl! 0 f8070300 rl! ;
+
+: dumpht  cr f8070110 rl@ 8 0.r space 8b4 config-l@ 8 0.r
+       space f8070122 rb@ 2 0.r space 8bd config-b@ 2 0.r ; 
+
+: clearht  f8070110 dup rl@ swap rl!
+           f8070120 dup rl@ swap rl!
+           08b4 dup config-l@ swap config-l!
+           08bc dup config-l@ swap config-l! ;
+
+: setwidth  dup f8070110 rb! 8b7 config-b! ;
+: set8   00 setwidth ;
+: set16  11 setwidth ;
+
+: setfreq  dup f8070122 rb! 8bd config-b! ;
+: set200   0 setfreq ;
+: set300   1 setfreq ;
+: set400   2 setfreq ;
+: set500   3 setfreq ;
+: set600   4 setfreq ;
+: set800   5 setfreq ;
+: set1000  6 setfreq ;
+: set1200  7 setfreq ;
+: set1400  8 setfreq ;
+: set1600  9 setfreq ;
+
+: ht>freq  2 + dup 6 > IF 2* 6 - THEN d# 100 * ;
+\ XXX: looks only at the U3/U4 side for max. link speed and width.
+clearht f8070111 rb@ setwidth
+f8070120 rw@ 2log dup .(  Switching top HT bus to ) ht>freq 0 d# .r .( MHz...) cr
+setfreq u3? IF ldtstop THEN u4? IF ldtstop1 THEN
+
+: open  true ;
+: close ;
+
+\ : probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- )
+s" /mpic" find-node my-puid pci-irq-init drop
+1f 0 c0000000 b8000000 b8000000 80000000 100000000 10000
+my-puid probe-pci-host-bridge
+
+: msi
+  f80040f0 010854 config-l!   0 010858 config-l!
+      ffff 01085c config-w!  81 010852 config-b!
+;
+
+\ This works.  Needs cleaning up though; and we need to communicate the
+\ MSI address range to the client program.  (We keep the default range
+\ at fee00000 for now).
+: msi-on  7 1 DO 10000 i 800 * a0 + config-l! LOOP ;
+msi-on
+
+\ PCIe debug / fixup
+: find-pcie-cap  ( devfn -- offset | 0 )
+   >r 34  BEGIN  r@ + config-b@ dup ff <> over and  WHILE
+      dup r@ + config-b@ 10 = IF
+         r> drop EXIT 
+      THEN 1+
+   REPEAT r> 2drop 0
+;
+
+: (set-ps) ( ps addr -- )
+  8 + >r 5 lshift r@ config-w@ ff1f and or r> config-w! ;
+: set-ps ( ps -- )
+  log2 7 -
+  10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF
+  + 2dup (set-ps) THEN drop LOOP drop ;
+
+: (set-rr) ( rr addr -- )
+  8 + >r c lshift r@ config-w@ 8fff and or r> config-w! ;
+: set-rr ( rr -- )
+  log2 7 -
+  10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF
+  + 2dup (set-rr) THEN drop LOOP drop ;
+
+100 set-ps  200 set-rr  
+100 set-ps  200 set-rr  
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/i2c.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/i2c.fs
new file mode 100644
index 0000000..044bde9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/i2c.fs
@@ -0,0 +1,77 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+new-device
+
+s" i2c" 2dup device-name device-type
+s" u4-i2c" compatible
+
+0 encode-int  f8001000 encode-int+
+0 encode-int+     1000 encode-int+ s" reg" property
+
+: >i2c  f8001000 + ;
+: i2c@  >i2c rl@ ;
+: i2c!  >i2c rl! ;
+
+: .i2c  80 0 DO i i2c@ . 10 +LOOP ;
+
+\ 0 mode  1 ctrl  2 stat  3 isr  4 ier  5 addr  6 suba  7 data
+\ 8 rev  9 risetime  a bittime
+
+\ 0 mode: 08
+\ 1 ctrl: 8 = start  4 = stop  2 = xaddr  1 = aak
+\ 2 stat: 2 = lastaak  1 = busy
+\ 3 isr: 8 = istart  4 = istop  2 = iaddr  1 = idata
+\ 4 ier: --
+\ 5 addr: a1..a7
+\ 6 suba: offset
+\ 7 data: data
+
+: i2c-addr ( addr -- )  50 i2c!  2 10 i2c!  BEGIN 30 i2c@ 2 and UNTIL ;
+: i2c-subaddr ( suba -- )  60 i2c! ;
+: i2c-stop ( -- )  BEGIN 30 i2c@ dup 30 i2c! 4 and UNTIL ;
+: i2c-nak? ( -- failed? )  20 i2c@ 2 and 0= dup IF i2c-stop THEN ;
+: i2c-short? ( -- failed? )  30 i2c@ 4 and 0<> dup IF 0 10 i2c! i2c-stop THEN ;
+: i2c-aak-if-more ( n -- )  1 <> 1 and 10 i2c! ;
+
+: (read) ( buf len addr -- error? )
+  1 or i2c-addr  i2c-nak? IF 2drop true EXIT THEN
+  dup i2c-aak-if-more  2 30 i2c!
+  BEGIN
+  30 i2c@ 1 and IF
+    1- >r 70 i2c@ over c! char+ r>
+    dup 0= IF i2c-stop 2drop false EXIT THEN
+    dup i2c-aak-if-more 1 30 i2c! THEN
+  i2c-short? IF 2drop true EXIT THEN
+  AGAIN ;
+
+: i2c-read ( buf len addr -- error? )
+  4 0 i2c!  (read) ;
+: i2c-sub-read ( buf len addr suba -- error? )
+  c 0 i2c!  i2c-subaddr  (read) ;
+
+: i2c-write ( buf len addr -- error? )
+  4 0 i2c!  i2c-addr  i2c-nak? IF 2drop true EXIT THEN
+  over c@ 70 i2c!  2 30 i2c!
+  BEGIN
+  30 i2c@ 1 and IF
+    1- >r char+ r> i2c-nak? IF 2drop true EXIT THEN
+    dup 0= IF 4 10 i2c! i2c-stop nip EXIT THEN
+    over c@ 70 i2c!  1 30 i2c! THEN
+  i2c-short? IF 2drop true EXIT THEN
+  AGAIN ;
+
+: open  true ;
+: close ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/io.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/io.fs
new file mode 100644
index 0000000..f388984
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/io.fs
@@ -0,0 +1,26 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ I/O accesses.
+
+\ Legacy I/O accesses.
+: >io  f4000000 + ;
+
+: io-c!  >io rb! ;
+: io-c@  >io rb@ ;
+
+: io-w!  >io rw! ;
+: io-w@  >io rw@ ;
+
+\ Accessing the SIO config registers.
+: siocfg!  2e io-c! 2f io-c! ;
+: siocfg@  2e io-c! 2f io-c@ ;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/ioapic.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ioapic.fs
new file mode 100644
index 0000000..685d6df
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ioapic.fs
@@ -0,0 +1,36 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ ( ioapic-addr -- )
+\ IO-APIC setup.
+
+CONSTANT ioapic
+
+: ioapic@  ( offset -- x )  ioapic rb! ioapic 10 + rl at -le ;
+: ioapic!  ( x offset -- )  ioapic rb! ioapic 10 + rl!-le ;
+
+: init-ioapic  ( irq# -- )
+   1a000 or 1 ioapic@ 10 rshift 1+ 0  ?DO
+      0 i 2* 11 + ioapic! dup
+      \ move all ISA IRQs to 40 and higher,
+      \ as to not conflict with U3/U4 internal
+      \ IRQs. ISA IRQs are positive edge.
+      dup ff and 0c <  IF  a000 - 40 +  THEN
+      i 2* 10 + ioapic! 1+  LOOP  drop
+;
+
+: dump-ioapic  ( -- )
+   1 ioapic@ 10 rshift 1+
+   dup cr . ." irqs" 0  ?DO
+      cr i 2 0.r space i 2* 11 + ioapic@ 8 0.r
+      i 2* 10 + ioapic@ 8 0.r  LOOP
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-kcs.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-kcs.fs
new file mode 100644
index 0000000..cf9d5af
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-kcs.fs
@@ -0,0 +1,57 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ IPMI KCS interface to the BMC.
+
+new-device
+   ca8 1 set-unit
+
+   : open true ;
+   : close ;
+
+   create descr-buf 100 allot
+
+   : rtas-get-bmc-version ( -- adr len )
+      descr-buf 100 rtas-get-blade-descr   ( len status )
+      IF
+         drop 0 0
+      ELSE
+         descr-buf 9 + swap 11 -               ( adr len )
+      THEN
+   ;
+
+   ' rtas-get-bmc-version to bmc-version
+
+   s" system-controller" 2dup device-name device-type
+   \ s" IBM,BMC." get-build-name $cat encode-string s" model" property
+   \ s" IBM,BMC.12345" encode-string s" model" property
+   s" IBM,BMC." bmc-version $cat encode-string s" model" property
+   0 0 s" ranges" property
+
+   new-device
+
+      : open true ;
+      : close ;
+
+      s" ipmi" 2dup device-name device-type
+      s" ipmi-kcs" compatible
+
+      1 encode-int ca8 encode-int+ 1 encode-int+ s" reg" property
+      4 encode-int s" reg-spacing" property
+      s" IBM,BMC." bmc-version $cat encode-string s" model" property
+
+      s" ipmi"  get-node node>path set-alias
+
+   finish-device
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-vpd.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-vpd.fs
new file mode 100644
index 0000000..bfb3e50
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/ipmi-vpd.fs
@@ -0,0 +1,98 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: vpd-read-bootlist  ( -- )
+   837 4 vpd-bootlist rtas-read-vpd IF vpd-bootlist 4 erase THEN
+;
+
+: vpd-write-bootlist  ( offset len data -- )
+   837 4 vpd-bootlist rtas-write-vpd
+;
+
+: .vpd-machine-type
+	e 7 vpd-cb rtas-read-vpd drop
+	0 vpd-cb 7 + c!
+	vpd-cb zcount type
+;
+
+: .vpd-machine-serial
+	15 7 vpd-cb rtas-read-vpd drop
+	0 vpd-cb 7 + c!
+	vpd-cb zcount type
+;
+
+: .vpd-card-serial
+	54 6 vpd-cb rtas-read-vpd drop
+	0 vpd-cb 6 + c!
+	vpd-cb zcount type
+;
+: .vpd-cardprefix-serial
+	5a 6 vpd-cb rtas-read-vpd drop
+	0 vpd-cb 6 + c!
+	vpd-cb zcount type
+;
+
+: .vpd-hw-revision
+	65 1 vpd-cb rtas-read-vpd drop
+	vpd-cb c@ .
+;
+
+: .vpd-part-number
+	3c c vpd-cb rtas-read-vpd drop
+	vpd-cb c type
+;
+
+: .vpd-fru-number
+	48 c vpd-cb rtas-read-vpd drop
+	vpd-cb c type
+;
+
+: .vpd-manufacturer-date
+	6b 4 vpd-cb rtas-read-vpd drop
+	0 vpd-cb 4 + c!
+	vpd-cb zcount type
+;
+
+: .vpd-uuid
+	9f 10 vpd-cb rtas-read-vpd drop
+	10 0 do i vpd-cb + c@ 2 0.r loop
+;
+
+: vpd-read-model  ( -- addr len )
+   60 4 vpd-cb rtas-read-vpd drop vpd-cb 4 -leading s" ," $cat 
+   e 7 vpd-cb rtas-read-vpd drop vpd-cb 4 $cat s" -" $cat vpd-cb 4 + 3 $cat
+;
+
+: .vpd
+	." ===================== VPD =====================" 
+	cr ." Machine Type        : " .vpd-machine-type
+	cr ." Machine Serial No.  : " .vpd-machine-serial
+	cr ." Hardware Revision   : " .vpd-hw-revision	
+	cr ." Manuf. Date         : " .vpd-manufacturer-date
+	cr ." Part Number         : " .vpd-part-number
+	cr ." FRU Number          : " .vpd-fru-number
+	cr ." FRU Serial No.      : " .vpd-cardprefix-serial .vpd-card-serial
+	cr ." UUID                : " .vpd-uuid
+;
+
+: vpd-write-revision-and-build-id  ( -- )
+   406 24 vpd-cb rtas-read-vpd drop 0
+   vpd-cb 1a + zcount bdate2human drop a string=ci 0=
+   IF  bdate2human drop a vpd-cb 1a + zplace drop 1  THEN
+   vpd-cb zcount slof-revision string=ci 0=
+   IF  slof-revision vpd-cb zplace drop 1  THEN
+   vpd-cb 4 + zcount slof-build-id string=ci 0=
+   IF  slof-build-id vpd-cb 4 + rzplace drop 1  THEN
+   1 =  IF  406 24 vpd-cb rtas-write-vpd drop  THEN
+;
+
+vpd-write-revision-and-build-id
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/memory.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/memory.fs
new file mode 100644
index 0000000..b1b7aaa
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/memory.fs
@@ -0,0 +1,52 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ The /memory node.
+
+\ See 3.7.6.
+new-device
+
+s" memory" 2dup device-name device-type
+
+: mem-size-u3  20000000 ;
+: (mem-size-u4) ( # -- size )
+  4 lshift f8002200 + rl@ dup 1 and 0= IF drop 0 EXIT THEN
+  dup c000 and e rshift over 3000 and c rshift + 10000000 swap lshift
+  swap 2 and 0= IF 2* THEN ;
+: mem-size-u4  0 4 0 DO i (mem-size-u4) + LOOP ;
+: mem-size   u3? IF mem-size-u3 THEN  u4? IF mem-size-u4 THEN ;
+: mem-speed-u4  f8000800 rl@ 12 rshift 7 and 4 + d# 200 * 3 / ;
+: mem-speed-u3  f8000f60 rl@ c rshift f and d# 100 * 3 / ;
+: mem-speed  u3? IF mem-speed-u3 THEN  u4? IF mem-speed-u4 THEN ;
+
+
+: encode-our-reg
+  0 encode-int 0 encode-int+
+  mem-size dup >r 80000000 > IF
+  0 encode-int+ 80000000 encode-int+
+  1 encode-int+ 0 encode-int+ r> 80000000 - >r THEN
+  r@ 20 rshift encode-int+ r> ffffffff and encode-int+ ;
+encode-our-reg s" reg" property
+0  mem-size release	\ Make our memory available
+
+
+: mem-report
+  base @ decimal mem-size 1e rshift 0 .r
+  mem-size 3fffffff and IF ." .5" THEN ."  GB of RAM @ "
+  mem-speed . ." MHz" base ! ;
+
+get-node memnode !
+
+: open  true ;
+: close ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/mpic.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/mpic.fs
new file mode 100644
index 0000000..a952344
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/mpic.fs
@@ -0,0 +1,31 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+new-device
+
+s" mpic" device-name s" interrupt-controller" device-type
+s" open-pic" compatible
+0 0 s" interrupt-controller" property
+
+2 encode-int s" #interrupt-cells" property
+
+0 encode-int  f8040000 encode-int+
+0 encode-int+    30000 encode-int+ s" reg" property
+
+: enable-mpic  6 f80000e0 rl! ;
+enable-mpic
+
+: open  true ;
+: close ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-aliases.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-aliases.fs
new file mode 100644
index 0000000..f017e4a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-aliases.fs
@@ -0,0 +1,85 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Starting alias number for net devices after the onboard devices.
+2 VALUE pci-net-num
+\ Starting alias number for disks after the onboard devices.
+0 VALUE pci-disk-num
+\ Starting alias number for cdroms after the onboard devices.
+0 VALUE pci-cdrom-num
+
+\ define a new alias for this device
+: pci-set-alias ( str-addr str-len num -- )
+        $cathex strdup       \ create alias name
+        get-node node>path   \ get path string
+        set-alias            \ and set the alias
+;
+
+\ define a new net alias
+: unknown-enet ( -- pci-net-num )
+	pci-net-num dup 1+ TO pci-net-num
+;
+: pci-alias-net ( config-addr -- )
+	u3? IF
+		pci-device-vec c@ CASE 
+		2 OF pci-device-vec-len 1 >= IF  
+					pci-device-vec 1+ c@ CASE 
+						1 OF dup pci-addr2fn 1 >= IF 1 ELSE 0 THEN  ENDOF 
+						dup OF  unknown-enet ENDOF
+					ENDCASE
+				ELSE
+					unknown-enet
+				THEN
+			ENDOF
+			dup OF unknown-enet  ENDOF	
+		ENDCASE
+	ELSE
+		pci-device-vec c@ CASE 
+		2 OF pci-device-vec-len 1 >= IF  
+					pci-device-vec 1+ c@ CASE 
+						4 OF dup pci-addr2fn 1 >= IF 1 ELSE 0 THEN  ENDOF 
+						dup OF  unknown-enet ENDOF
+					ENDCASE
+				ELSE
+					unknown-enet
+				THEN
+			ENDOF
+			dup OF unknown-enet  ENDOF	
+		ENDCASE
+	THEN
+	swap drop                               \ forget the config address
+
+        s" net" rot pci-set-alias              \ create the alias
+;
+
+\ define a new disk alias
+: pci-alias-disk ( config-addr -- )
+        drop                                    \ forget the config address
+        pci-disk-num dup 1+ TO pci-disk-num     \ increase the pci-disk-num
+        s" disk" rot pci-set-alias              \ create the alias
+;
+\ define a new cdrom alias
+: pci-alias-cdrom ( config-addr -- )
+        drop                                    \ forget the config address
+        pci-cdrom-num dup 1+ TO pci-cdrom-num     \ increase the pci-cdrom-num
+        s" cdrom" rot pci-set-alias              \ create the alias
+;
+
+\ define the alias for the calling device
+: pci-alias ( config-addr -- )
+        dup pci-class@ 
+        10 rshift CASE
+                01 OF   pci-alias-disk ENDOF
+                02 OF   pci-alias-net  ENDOF
+               dup OF   drop           ENDOF
+        ENDCASE
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs
new file mode 100644
index 0000000..c28e0d2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs
@@ -0,0 +1,193 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ AMD 8111 I/O hub.
+
+\ See the documentation at http://www.amd.com ; the datasheet for this chip is
+\ document #24674.
+
+\ First, some master config.  Not all of this logically belongs to just
+\ one function, and certainly not to the LPC bridge; also, we'll
+\ initialize all functions in "downstream" order, and this code has to be
+\ run first.  So do it now.
+
+00 842 config-b! \ Disable 8237 & 8254 & 8259's.  We're not a PC.
+u3?  IF
+   80 847 config-b! \ Disable EHCI, as it is terminally broken.
+THEN
+03 848 config-b! \ Enable LPC, IDE; disable I2C, SMM, AC'97 functions.
+01 849 config-b! \ Enable USB, disable 100Mb enet.
+01 84b config-b! \ Enable IO-APIC.
+
+fec00000 s" ioapic.fs" included
+00 init-ioapic
+
+\ Program PNPIRQ[0,1,2] as IRQ #D,E,F; switch those GPIOs to low-active.
+  0b 848 config-b! \ enable devB:3
+7000 b58 config-l! \ map PMxx at pci i/o 7000
+  d1 b41 config-b! \ enable access to PMxx space
+
+\ on JS20 the planar id is encoded in GPIO 29, 30 and 31
+\ >=5 is GA2 else it is GA1
+: (planar-id) ( -- planar-id)
+   [ 70dd io-c@ 5 rshift 1 and ]  LITERAL
+   [ 70de io-c@ 5 rshift 2 and ]  LITERAL
+   [ 70df io-c@ 5 rshift 4 and ]  LITERAL
+   + + 7 xor
+;
+
+u3?  IF  [']  (planar-id) to planar-id  THEN
+
+8 70d3 io-c!  8 70d4 io-c!  8 70d5 io-c! \ set the pins to low-active
+ bimini? IF 5 70c4 io-c! THEN \ on bimini set gpio4 as output and high to power up USB
+ fec b44 config-w! \ set PNPIRQ pnpirq2 -> f , pnpirq1 -> e pnpirq0 -> c
+  51 b41 config-b! \ disable access to PMxx space
+  03 848 config-b! \ disable devB:3
+
+\ The function of the PCI controller BARs change depending on the mode the
+\ controller is in.
+\ And the default is legacy mode.  Gross.
+05 909 config-b! \ Enable native PCI mode.
+03 940 config-b! \ Enable both ports.
+
+\ Enable HPET on 8111, at address fe000000.
+fe000001 8a0 config-l!
+
+: >hpet  fe000000 + ;
+: hpet@  >hpet rl at -le ;
+: hpet!  >hpet rl!-le ;
+
+INCLUDE freq.fs
+
+\ Disable HPET.
+0 8a0 config-l!
+
+\ 8111 has only 16 bits of PCI I/O space.  Get the address in range.
+8000 next-pci-io !
+
+\ before disabling EHCI it needs to be reset
+
+\ first we are setting up the BAR0, so that we can talk to the
+\ memory mapped controller; not using the PCI scan because we just
+\ want a temporary setup
+
+: really-disable-broken-amd8111-ehci  ( -- )
+   \ this word only works on U4 systems (JS21/Bimini)
+   \ yeah, hardcoded!
+   f2000000 to puid
+   
+   \ the PCI scan would assign pci-next-mmio to that device
+   \ let's just take that address
+   pci-next-mmio @ 100000 #aligned 
+   \ pci-bus-number 10 lshift 210 or could be something like 70210
+   \ 7: pci-bus-number
+   \ 2: device function
+   \ 10: offset 10 (bar 0)
+   pci-bus-number 10 lshift 210 or rtas-config-l!
+
+   \ enable memory space
+   pci-bus-number 10 lshift 204 or dup rtas-config-l@ 2 or swap rtas-config-l!
+
+   pci-next-mmio @ 100000 #aligned ( base )
+
+   \ Sequence prescribed for resetting the EHCI contoller
+
+   \ If Run/Stop bit (ECAP30 bit 0) is 1
+   \   Set Run/Stop bit to 0
+   \   wait 2ms
+
+   dup 30 + rl@ 1 and 1 =  IF
+      dup 30 + rl@ 1 or
+      over 30 + rl!
+      2 ms
+   THEN
+
+   \ While HCHalted bit (ECAP34 bit 12) is 0  (still running, wait forever)
+   \   wait 2ms
+
+   BEGIN  dup 34 + rl@ 1000 and 0= 2 ms UNTIL
+
+   \ Set HCReset bit (ECAP30 bit 1)
+
+   dup 30 + 2 swap rl!
+
+   \ While HCReset bit is 1 (wait forever for reset to complete)
+   \   wait 2ms
+
+   BEGIN  dup 30 + rl@ 2 and 0= 2 ms UNTIL  drop
+
+   \ now it is really disabled
+
+   \ disable memory space access again
+   2100000 pci-bus-number 10 lshift 204 or rtas-config-l!
+
+   80 847 config-b! \ Disable EHCI, as it is terminally broken.
+;
+
+my-space pci-class-name type cr
+
+\ copied from pci-properties.fs and pci-scan.fs
+\ changed to disable the EHCI completely just before the scan
+\ and after mem/IO transactions have been enabled
+
+\ Setup the Base and Limits in the Bridge
+\ and scan the bus(es) beyond that Bridge
+: pci-bridge-probe-amd8111 ( addr -- )
+   dup pci-bridge-set-bases                        \ SetUp all Base Registers
+   pci-bus-number 1+ TO pci-bus-number             \ increase number of busses found
+   pci-device-vec-len 1+ TO pci-device-vec-len     \ increase the device-slot vector depth
+   dup                                             \ stack config-addr for pci-bus!
+   FF swap                                         \ Subordinate Bus Number ( for now to max to open all subbusses )
+   pci-bus-number swap                             \ Secondary   Bus Number ( the new busnumber )
+   dup pci-addr2bus swap                           \ Primary     Bus Number ( the current bus )
+   pci-bus!                                        \ and set them into the bridge
+   pci-enable                                      \ enable mem/IO transactions
+
+   \ at this point we can talk to the broken EHCI controller
+   really-disable-broken-amd8111-ehci
+
+   dup pci-bus-scnd@ func-pci-probe-bus            \ and probe the secondary bus
+   dup pci-bus-number swap pci-bus-subo!           \ set SubOrdinate Bus Number to current number of busses
+   pci-device-vec-len 1- TO pci-device-vec-len     \ decrease the device-slot vector depth
+   dup pci-bridge-set-limits                       \ SetUp all Limit Registers
+   drop                                            \ forget the config-addr
+;
+
+\ used to set up all unknown Bridges.
+\ If a Bridge has no special handling for setup
+\ the device file (pci-bridge_VENDOR_DEVICE.fs) can call
+\ this word to setup busses and scan beyond.
+: pci-bridge-generic-setup-amd8111 ( addr -- )
+   pci-device-slots >r             \ save the slot array on return stack
+   dup pci-common-props            \ set the common properties before scanning the bus
+   s" pci" device-type             \ the type is allways "pci"
+   dup pci-bridge-probe-amd8111    \ find all device connected to it
+   dup assign-all-bridge-bars      \ set up all memory access BARs
+   dup pci-set-irq-line            \ set the interrupt pin
+   dup pci-set-capabilities        \ set up the capabilities
+   pci-bridge-props                \ and generate all properties
+   r> TO pci-device-slots          \ and reset the slot array
+;
+
+: amd8111-bridge-setup
+    my-space
+    u3? takeover? or  IF
+       \ if it is js20 or we are coming from takeover
+       \ we just do the normal setup
+       pci-bridge-generic-setup
+    ELSE
+       pci-bridge-generic-setup-amd8111
+    THEN
+    s" pci" device-name
+;
+
+amd8111-bridge-setup
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-capabilities.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-capabilities.fs
new file mode 100644
index 0000000..a50714a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-capabilities.fs
@@ -0,0 +1,23 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ -----------------------------------------------------------------------------
+\ Set the msi address for a device
+: pci-set-msi ( cap-addr -- )
+        drop
+;
+
+\ Set up all known capabilities for this board to the plugged devices
+: pci-set-capabilities ( config-addr -- )
+        dup 05 pci-cap-find ?dup IF pci-set-msi THEN
+        drop
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-class_03.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-class_03.fs
new file mode 100644
index 0000000..05c8eb6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-class_03.fs
@@ -0,0 +1,55 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space pci-class-name type
+
+my-space pci-device-generic-setup
+
+my-space pci-class-name device-type
+
+\ add legacy I/O Ports / Memory regions to assigned-addresses
+\ see PCI Bus Binding Revision 2.1 Section 7.
+s" reg" get-my-property
+IF
+   \ "reg" does not exist, create new
+   encode-start
+ELSE
+   \ "reg" does exist, copy it 
+   encode-bytes
+THEN
+\ I/O Range 0x3B0-0x3BB
+my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space
+3b0 encode-64+ \ addr
+c encode-64+ \ size
+\ I/O Range 0x3C0-0x3DF
+my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space
+3c0 encode-64+ \ addr
+20 encode-64+ \ size
+\ the U4 does not support memory accesses to this region... so we dont put it into "reg"
+\ maybe with some clever hacking of the address map registers it will be possible to access
+\ these regions??
+\ Memory Range 0xA0000-0xBFFFF
+\ my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space
+\ a0000 encode-64+ \ addr
+\ 20000 encode-64+ \ size
+
+s" reg" property \ store "reg" property
+
+\ check wether we have already found a vga-device (vga-device-node? != 0) and if
+\ this device has Expansion ROM
+vga-device-node? 0= 30 config-l@ 0<> AND IF
+   \ remember this vga device's phandle
+   get-node to vga-device-node?
+THEN
+
+cr
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs
new file mode 100644
index 0000000..5cd692b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs
@@ -0,0 +1,504 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space pci-class-name type
+
+my-space assign-all-device-bars
+my-space pci-device-props
+my-space pci-set-irq-line
+
+7 4 config-w!
+
+\ Special notice from ATI:
+\ ATI TECHNOLOGIES INC. ("ATI") HAS NOT ASSISTED IN THE CREATION OF,
+\ AND DOES NOT ENDORSE THE USE OF, THIS SOFTWARE.  ATI WILL NOT BE
+\ RESPONSIBLE OR LIABLE FOR ANY ACTUAL OR ALLEGED DAMAGE OR LOSS
+\ CAUSED BY OR IN CONNECTION WITH THE USE OF, OR RELIANCE ON,
+\ THIS SOFTWARE.
+
+\  Description: This FCODE driver initializes the RN50 (ES1000) ATI
+\               adaptor.
+
+-1 value mem-addr
+-1 value regs-addr
+false value is_installed
+
+: >rn [ 18 config-l@ -10 and ] LITERAL + ;
+: rn! >rn rl!-le ;
+: rn@ >rn rl at -le ;
+: reg-rl@ rn@ ;
+: reg-rl! rn! ;
+: map-in        " map-in"       $call-parent ;
+: map-out       " map-out"      $call-parent ;
+: pc@ ( offset -- byte ) >rn rb@ ;
+: pc! ( byte offset -- ) >rn rb! ;
+
+0 value phys_low
+0 value phys_mid
+0 value phys_high
+0 value phys_len
+
+: MAP-CSR-BASE ( -- )
+  " assigned-addresses" get-my-property 0= if
+    begin dup 0> while  ( prop-addr len )
+     \ Get the phys-hi mid low and the low order 32 bits of the length
+
+      decode-phys to phys_high to phys_mid to phys_low decode-int drop decode-int to phys_len
+
+      phys_high H# FF and  \ See which BAR this refers to
+      case
+        h# 10 of phys_low phys_mid phys_high h# 1000000  map-in to mem-addr  endof
+        h# 18 of phys_low phys_mid phys_high    phys_len map-in to regs-addr endof
+      endcase
+    repeat
+    ( prop-addr 0 ) 2drop
+  then
+
+  ;
+
+: enable-card my-space 4 + dup config-b@ 3 or swap config-b! ;
+
+: EARLY-MAP ( -- )
+
+  " reg" get-my-property 0= if
+    begin dup 0> while  ( prop-addr len )
+
+   \ Get the phys-hi mid low and the low order 32 bits of the length
+
+      decode-phys to phys_high to phys_mid to phys_low decode-int drop decode-int to phys_len
+
+      phys_high H# FF and  \ See which BAR this refers to
+      case
+        h# 10 of phys_low phys_mid phys_high H# 1000000  map-in to mem-addr  endof
+        h# 18 of phys_low phys_mid phys_high h#    1000  map-in to regs-addr endof
+      endcase
+    repeat
+    ( prop-addr 0 ) 2drop
+  then
+  ;
+
+: EARLY-UNMAP ( -- )
+
+  mem-addr -1 <> if
+    mem-addr h# 1000000 map-out
+    -1 to mem-addr
+  then
+
+  regs-addr -1 <> if
+    regs-addr h# 1000   map-out
+    -1 to regs-addr
+  then
+
+  ;
+
+CREATE INIT1_ARRAY
+H# 0F8  ( CONFIG_MEMSIZE )  L,    H# 00000000 L, H# 01000000 L,
+H# 1C0  ( MPP_TB_CONFIG )   L,    H# 00FFFFFF L, H# 07000000 L,
+H# 030  ( BUS_CNTL      )   L,    H# 00000000 L, H# 5133A3B0 L,
+H# 0EC  ( RBBM_CNTL     )   L,    H# 00000000 L, h# 00004443 L,
+H# 1D0  ( DEBUG_CNTL    )   L,    H# FFFFFFFD L, H# 00000002 L,
+H# 050  ( CRTC_GEN_CNTL )   L,    H# 00000000 L, H# 04000000 L,
+H# 058  ( DAC_CNTL      )   L,    H# 00000000 L, H# FF604102 L,
+H# 168  ( PAD_CTLR_STRENGTH ) L,  H# FFFEFFFF L, H# 00001200 L,
+H# 178  ( MEM_REFRESH_CNTL  ) L,  H# 00000000 L, H# 88888888 L,
+H# 17C  ( MEM_READ_CNTL )   L,    H# 00000000 L, H# B7C20000 L,
+H# 188  ( MC_DEBUG      )   L,    H# FFFFFFFF L, H# 00000000 L,
+H# D00  ( DISP_MISC_CNTL)   L,    H# 00FFFFFF L, H# 5B000000 L,
+H# 88C  ( TV_DAC_CNTL   )   L,    H# F800FCEF L, H# 00490200 L,
+H# D04  ( DAC_MACRO_CNTL)   L,    H# 00000000 L, H# 00000905 L,
+H# 284  ( FP_GEN_CNTL   )   L,    H# FFFFFFFF L, H# 00000008 L,
+H# 030  ( BUS_CNTL      )   L,    H# FFFFFFEF L, H# 00000000 L,
+
+here  INIT1_ARRAY  - /L / CONSTANT INIT1_LENGTH
+
+
+CREATE INIT2_ARRAY
+
+H# 140  ( MEM_CNTL )           L, H#  00000000 L, H# 38001A01 L, 0 L,
+H# 158  ( MEM_SDRAM_MODE_REG ) L, H#  E0000000 L, H# 08320032 L, 0 L,
+H# 144  ( MEM_TIMING_CNTL    ) L, H#  00000000 L, H# 20123833 L, 0 L,
+H# 14C  ( MC_AGP_LOCATION    ) L, H#  00000000 L, H# 000FFFF0 L, 0 L,
+H# 148  ( MC_FB_LOCATION     ) L, H#  00000000 L, H# FFFF0000 L, 0 L,
+H# 154  ( MEM_INIT_LAT_TIMER ) L, H#  00000000 L, H# 34444444 L, 0 L,
+H# 18C  ( MC_CHP_IO_OE_CNTL  ) L, H#  00000000 L, H# 0A540002 L, 0 L,
+H# 910  ( FCP_CNTL           ) L, H#  00000000 L, H# 00000004 L, 0 L,
+H# 010  ( BIOS_0_SCRATCH     ) L, H#  FFFFFFFB L, H# 00000004 L, 0 L,
+H# D64  ( DISP_OUTPUT_CNTL   ) L, H#  FFFFFBFF L, H# 00000000 L, 0 L,
+H# 2A8  ( TMDS_PLL_CNTL      ) L, H#  00000000 L, H# 00000A1B L, 0 L,
+H# 800  ( TV_MASTER_CNTL     ) L, H#  BFFFFFFF L, H# 40000000 L, 0 L,
+H# D10  ( DISP_TEST_DBUG_CTL ) L, H#  EFFFFFFF L, H# 10000000 L, 0 L,
+H# 4DC  ( OV0_FLAG_CNTRL     ) L, H#  FFFFFEFF L, H# 00000100 L, 0 L,
+H# 034  ( BUS_CNTL1          ) L, H#  73FFFFFF L, H# 84000000 L, 0 L,
+H# 174  ( AGP_CNTL           ) L, H#  FFEFFF00 L, H# 001E0000 L, 0 L,
+H# 18C  ( MC_CHP_IO_OE_CNTL  ) L, H#  FFFFFFF9 L, H# 00000006 L, h# 000A L,
+H# 18C  ( MC_CHP_IO_OE_CNTL  ) L, H#  FFFFFFFB L, H# 00000000 L, H# 000A L,
+H# 18C  ( MC_CHP_IO_OE_CNTL  ) L, H#  FFFFFFFD L, H# 00000000 L, 0 L,
+
+here  INIT2_ARRAY  - /L / CONSTANT INIT2_LENGTH
+
+CREATE PLLINIT_ARRAY
+
+H# 0D   L, H# FFFFFFFF L, H# FFFF8000 L, 0 L,
+H# 12   L, H# FFFFFFFF L, H# 00350000 L, 0 L,
+H# 08   L, H# FFFFFFFF L, H# 00000000 L, 0 L,
+H# 2D   L, H# FFFFFFFF L, H# 00000000 L, 0 L,
+H# 1F   L, H# FFFFFFFF L, H# 0000000A L, 5 L,
+H# 03   L, H# FFFFFFFF L, H# 0000003C L, 0 L,
+H# 0A   L, H# FFFFFFFF L, H# 00252504 L, 0 L,
+H# 25   L, H# FFFFFFFF L, H# 00000005 L, 0 L,
+H# 0E   L, H# FFFFFFFF L, H# 04756400 L, 0 L,
+H# 0C   L, H# FFFFFFFF L, H# 04006401 L, 0 L,
+H# 02   L, H# FFFFFFFF L, H# 0000A703 L, 0 L,
+H# 0F   L, H# FFFFFFFF L, H# 0000051C L, 0 L,
+H# 10   L, H# FFFFFFFF L, H# 04000400 L, 5 L,
+H# 0E   L, H# FFFFFFFD L, H# 00000000 L, 5 L,
+H# 0E   L, H# FFFFFFFE L, H# 00000000 L, 5 L,
+H# 12   L, H# FFFFFFFF L, H# 00350012 L, 5 L,
+H# 0F   L, H# FFFFFFFE L, H# 00000000 L, 6 L,
+H# 10   L, H# FFFFFFFE L, H# 00000000 L, 5 L,
+H# 10   L, H# FFFEFFFF L, H# 00000000 L, 6 L,
+H# 0F   L, H# FFFFFFFD L, H# 00000000 L, 5 L,
+H# 10   L, H# FFFFFFFD L, H# 00000000 L, 5 L,
+H# 10   L, H# FFFDFFFF L, H# 00000000 L, d# 10 L,
+H# 0C   L, H# FFFFFFFE L, H# 00000000 L, 6 L,
+H# 0C   L, H# FFFFFFFD L, H# 00000000 L, 5 L,
+h# 0D   L, H# FFFFFFFF L, H# FFFF8007 L, 5 L,
+H# 08   L, H# FFFFFF3C L, H# 00000000 L, 0 L,
+H# 02   L, H# FFFFFFFF L, H# 00000003 L, 0 L,
+H# 04   L, H# FFFFFFFF L, H# 000381C0 L, 0 L,
+H# 05   L, H# FFFFFFFF L, H# 000381F7 L, 0 L,
+H# 06   L, H# FFFFFFFF L, H# 000381C0 L, 0 L,
+H# 07   L, H# FFFFFFFF L, H# 000381F7 L, 0 L,
+H# 02   L, H# FFFFFFFD L, H# 00000000 L, 6 L,
+H# 02   L, H# FFFFFFFE L, H# 00000000 L, 5 L,
+h# 08   L, H# FFFFFF3C L, H# 00000003 L, 5 L,
+H# 0B   L, H# FFFFFFFF L, H# 78000800 L, 0 L,
+H# 0B   L, H# FFFFFFFF L, H# 00004000 L, 0 L,
+h# 01   L, h# FFFFFFFF L, H# 00000010 L, 0 L,
+
+here  PLLINIT_ARRAY  - /L / CONSTANT PLLINIT_LENGTH
+
+CREATE MEMINIT_ARRAY
+h# 6FFF0000  L, H# 00004000 L, H# 6FFF0000 L, H# 80004000 L,
+h# 6FFF0000  L, H# 00000132 L, H# 6FFF0000 L, H# 80000132 L,
+h# 6FFF0000  L, H# 00000032 L, H# 6FFF0000 L, H# 80000032 L,
+h# 6FFF0000  L, H# 10000032 L,
+here MEMINIT_ARRAY - /L / CONSTANT MEMINIT_LENGTH
+: L at + ( addr -- value addr' )
+
+dup l@ swap la1+
+;
+
+0 VALUE _len
+
+: ENCODE-ARRAY  ( array len -- )
+   dup to _len 0  do  l at + swap encode-int rot  loop
+   drop _len 1 - 0  ?do  encode+  loop
+;
+
+: andorset  ( reg and or -- )
+   2 pick regs-addr + dup rn@
+   3 pick AND 2 pick OR swap rn! 3drop
+;
+
+: INIT1
+H# 0F8  ( CONFIG_MEMSIZE )      H# 00000000  H# 01000000 andorset \ Set 16Mb memory size
+H# 1C0  ( MPP_TB_CONFIG )       H# 00FFFFFF  H# 07000000 andorset
+H# 030  ( BUS_CNTL      )       H# 00000000  H# 5133A3B0 andorset
+H# 0EC  ( RBBM_CNTL     )       H# 00000000  h# 00004443 andorset
+H# 1D0  ( DEBUG_CNTL    )       H# FFFFFFFD  H# 00000002 andorset
+H# 050  ( CRTC_GEN_CNTL )       H# 00000000  H# 04000000 andorset
+H# 058  ( DAC_CNTL      )       H# 00000000  H# FF604102 andorset
+H# 168  ( PAD_CTLR_STRENGTH )   H# FFFEFFFF  H# 00001200 andorset
+H# 178  ( MEM_REFRESH_CNTL  )   H# 00000000  H# 88888888 andorset
+H# 17C  ( MEM_READ_CNTL )       H# 00000000  H# B7C20000 andorset
+H# 188  ( MC_DEBUG      )       H# FFFFFFFF  H# 00000000 andorset
+H# D00  ( DISP_MISC_CNTL)       H# 00FFFFFF  H# 5B000000 andorset
+H# 88C  ( TV_DAC_CNTL   )       H# F800FCEF  H# 00490200 andorset
+H# D04  ( DAC_MACRO_CNTL)       H# 00000000  H# 00000905 andorset
+H# 284  ( FP_GEN_CNTL   )       H# FFFFFFFF  H# 00000008 andorset
+H# 030  ( BUS_CNTL      )       H# FFFFFFEF  H# 00000000 andorset
+;
+
+
+: INIT2
+H# 140  ( MEM_CNTL )            H#  00000000  H# 38001A01 andorset
+H# 158  ( MEM_SDRAM_MODE_REG )  H#  E0000000  H# 08320032 andorset
+H# 144  ( MEM_TIMING_CNTL    )  H#  00000000  H# 20123833 andorset
+H# 14C  ( MC_AGP_LOCATION    )  H#  00000000  H# 000FFFF0 andorset
+H# 148  ( MC_FB_LOCATION     )  H#  00000000  H# FFFF0000 andorset
+H# 154  ( MEM_INIT_LAT_TIMER )  H#  00000000  H# 34444444 andorset
+H# 18C  ( MC_CHP_IO_OE_CNTL  )  H#  00000000  H# 0A540002 andorset
+H# 910  ( FCP_CNTL           )  H#  00000000  H# 00000004 andorset
+H# 010  ( BIOS_0_SCRATCH     )  H#  FFFFFFFB  H# 00000004 andorset
+H# D64  ( DISP_OUTPUT_CNTL   )  H#  FFFFFBFF  H# 00000000 andorset
+H# 2A8  ( TMDS_PLL_CNTL      )  H#  00000000  H# 00000A1B andorset
+H# 800  ( TV_MASTER_CNTL     )  H#  BFFFFFFF  H# 40000000 andorset
+H# D10  ( DISP_TEST_DEBUG_CTL ) H#  EFFFFFFF  H# 10000000 andorset
+H# 4DC  ( OV0_FLAG_CNTRL     )  H#  FFFFFEFF  H# 00000100 andorset
+H# 034  ( BUS_CNTL1          )  H#  73FFFFFF  H# 84000000 andorset
+H# 174  ( AGP_CNTL           )  H#  FFEFFF00  H# 001E0000 andorset
+H# 18C  ( MC_CHP_IO_OE_CNTL  )  H#  FFFFFFF9  H# 00000006 andorset h# 000A ms
+H# 18C  ( MC_CHP_IO_OE_CNTL  )  H#  FFFFFFFB  H# 00000000 andorset H# 000A ms
+H# 18C  ( MC_CHP_IO_OE_CNTL  )  H#  FFFFFFFD  H# 00000000 andorset
+;
+
+: CLK-CNTL-INDEX! 8 ( CLK_CNTL_INDEX ) reg-rl! ;
+
+: CLK-CNTL-INDEX@ 8 ( CLK_CNTL_INDEX ) reg-rl@ ;
+
+: PLLWRITEON  clk-cntl-index@ H# 80 ( PLL_WR_ENABLE ) or clk-cntl-index! ;
+
+: PLLWRITEOFF clk-cntl-index@ H# 80 ( PLL_WR_ENABLE ) not and clk-cntl-index! ; \ Remove PLL_WR_ENABLE
+
+: CLKDATA! h# 0c ( CLK_CNTL_DATA ) reg-rl! ;
+
+: CLKDATA@ h# 0c ( CLK_CNTL_DATA ) reg-rl@ ;
+
+: PLLINDEXSET clk-cntl-index@ h# FFFFFFC0 and or clk-cntl-index! ;
+
+: PLLSET swap pllindexset clkdata! ;
+
+: pllandorset  ( index and or -- )
+   2 pick pllindexset clkdata@
+   2 pick AND over OR clkdata! 3drop
+;
+
+: PLLINIT
+pllwriteon
+H# 0D   H# FFFF8000 pllset
+H# 12   H# 00350000 pllset
+H# 08   H# 00000000 pllset
+H# 2D   H# 00000000 pllset
+H# 1F   H# 0000000A pllset 5 ms
+
+H# 03   H# 0000003C pllset
+H# 0A   H# 00252504 pllset
+H# 25   H# 00000005 pllset
+H# 0E   H# 04756400 pllset
+H# 0C   H# 04006401 pllset
+H# 02   H# 0000A703 pllset
+H# 0F   H# 0000051C pllset
+H# 10   H# 04000400 pllset 5 ms
+
+H# 0E   H# FFFFFFFD 00 pllandorset 5 ms
+H# 0E   H# FFFFFFFE 00 pllandorset 5 ms
+H# 12   H# 00350012 pllset 5 ms
+H# 0F   H# FFFFFFFE 00 pllandorset 6 ms
+H# 10   H# FFFFFFFE 00 pllandorset 5 ms
+H# 10   H# FFFEFFFF 00 pllandorset 6 ms
+H# 0F   H# FFFFFFFD 00 pllandorset 5 ms
+H# 10   H# FFFFFFFD 00 pllandorset 5 ms
+H# 10   H# FFFDFFFF 00 pllandorset d# 10 ms
+H# 0C   H# FFFFFFFE 00 pllandorset 6 ms
+H# 0C   H# FFFFFFFD 00 pllandorset 5 ms
+h# 0D   h# FFFF8007      pllset 5 ms
+H# 08   H# FFFFFF3C 00   pllandorset
+H# 02   h# FFFFFFFF 03   pllandorset
+H# 04   H# 000381C0      pllset
+H# 05   H# 000381F7      pllset
+H# 06   H# 000381C0      pllset
+H# 07   H# 000381F7      pllset
+H# 02   H# FFFFFFFD 00   pllandorset 6 ms
+H# 02   h# FFFFFFFE 00   pllandorset 5 ms
+h# 08   H# FFFFFF3C 03   pllandorset 5 ms
+H# 0B   h# 78000800      pllset
+H# 0B   H# FFFFFFFF h# 4000 pllandorset
+h# 01   h# FFFFFFFF h# 0010 pllandorset
+
+pllwriteoff
+;
+
+: DYNCKE
+pllwriteon
+H# 14   H# FFFF3FFF H# 30 pllandorset
+H# 14   H# FF1FFFFF H# 00 pllandorset
+H# 01   h# FFFFFFFF h# 80 pllandorset
+H# 0D   H# 00000007       pllset 5 ms
+h# 2D   H# 0000F8C0       pllset
+h# 08   H# FFFFFFFF h# C0 pllandorset 5 ms
+pllwriteoff
+;
+
+: MEM-MODE@
+    h# 158 ( MEM_SDRAM_MODE_REG ) reg-rl@ ;
+
+: MEM-MODE!
+    h# 158 ( MEM_SDRAM_MODE_REG ) reg-rl! ;
+
+: MEM-STATUS@
+    H# 150 reg-rl@ ;
+
+: WAIT-MEM-CMPLT
+    h# 8000 0 do mem-status@ 3 and 3 = if leave then loop ;
+
+: INITMEM
+
+  mem-mode@ h# 6FFF0000 and h# 4000     or mem-mode!
+  mem-mode@ h# 6FFF0000 and h# 80004000 or mem-mode!
+  wait-mem-cmplt
+  mem-mode@ h# 6FFF0000 and h# 0132     or mem-mode!
+  mem-mode@ h# 6FFF0000 and h# 80000132 or mem-mode!
+  wait-mem-cmplt
+  mem-mode@ h# 6FFF0000 and h# 0032     or mem-mode!
+  mem-mode@ h# 6FFF0000 and h# 80000032 or mem-mode!
+  wait-mem-cmplt
+  mem-mode@ h# 6FFF0000 and h# 10000032 or mem-mode!
+;
+
+
+
+: CLR-REG ( reg -- )
+  0 swap  reg-rl!
+
+;
+: SET-PALETTE  ( -- )
+  h# 0 h# b0 pc!                \ Reset PALETTE_INDEX
+
+  d# 16 0 do
+    H# 000000 h# B4 reg-rl!     \ Write the PALETTE_DATA ( Auto increments)
+    H# aa0000 H# B4 reg-rl!
+    H# 00aa00 H# B4 reg-rl!
+    H# aa5500 H# B4 reg-rl!
+    H# 0000aa H# B4 reg-rl!
+    H# aa00aa H# B4 reg-rl!
+    H# 00aaaa H# B4 reg-rl!
+    H# aaaaaa H# B4 reg-rl!
+    H# 555555 H# B4 reg-rl!
+    H# ff5555 H# B4 reg-rl!
+    H# 55ff55 H# B4 reg-rl!
+    H# ffff55 H# B4 reg-rl!
+    H# 5555ff H# B4 reg-rl!
+    H# ff55ff H# B4 reg-rl!
+    H# 55ffff H# B4 reg-rl!
+    H# ffffff H# B4 reg-rl!
+  loop
+
+ ;
+
+0 VALUE _addr
+0 VALUE _color
+
+: DO-COLOR  ( color-addr addr color -- )
+   to _color to _addr 0 to _color
+   3 0  do  _addr i + c@ 2 i - 8 * << _color + to _color  loop
+   _color h# B4 reg-rl!
+;
+
+: SET-COLORS ( addr index #indicies -- )
+
+  swap h# B0 pc!
+  ( addr #indicies ) 0 ?do dup ( index ) i 3 * + DO-COLOR loop
+  ( addr ) drop ;
+
+: init-card
+
+  h# FF h# 58 3 + pc!   \
+  h# 59 pc@ h# FE and  h# 59 pc!   \
+  h# 50 reg-rl@ H# FEFFFFFF AND h# 02000200 or  \ Clear 24 set 25 and 8-11 to 2
+  h# 50 reg-rl!
+  h# 4F0063  h# 200 reg-rl!
+  H# 8C02A2  h# 204 reg-rl!
+  H# 1Df020C h# 208 reg-rl!
+  h# 8201EA  h# 20C reg-rl!
+  h# 50 reg-rl@ H# F8FFFFFF AND h# 03000000 or h# 50 reg-rl!
+  h# 50 h# 22C reg-rl!
+  set-palette
+
+  \ at this point for some reason mem-addr does not point
+  \ to the right address and therefore the following command
+  \ which should probably clean the frame buffer just
+  \ overwrites everything starting from 0 including the
+  \ exception vectors
+
+  \ mem-addr h# F0000 0 fill
+ ;
+
+: DO-INIT
+  early-map
+  enable-card
+  init1
+  pllinit
+  init2
+  initmem
+  init-card
+  h# 8020 h# 54 reg-rl!
+  early-unmap
+;
+
+d# 640 constant /scanline
+d# 480 constant #scanlines
+/scanline #scanlines * constant /fb
+
+" okay" encode-string " status" property
+
+: display-install ( -- )
+  is_installed not if
+    map-csr-base
+    enable-card
+    mem-addr to frame-buffer-adr
+    h# 8020 h# 54 reg-rl!
+    default-font set-font
+    /scanline #scanlines  d# 100 d# 40 fb8-install
+    true to is_installed
+  then
+;
+
+: display-remove  ( -- )  ;
+
+do-init                                                 \ Set up the card
+\ clear at least 640x480
+10 config-l@ 8 - F0000 0 rfill
+init1_array init1_length encode-array " ibm,init1" property
+init2_array init2_length encode-array " ibm,init2" property
+pllinit_array pllinit_length   encode-array " ibm,pllinit" property
+meminit_array meminit_length   encode-array " ibm,meminit" property
+0 0 encode-bytes " iso6429-1983-colors" property
+" display" encode-string " device_type" property
+/scanline  encode-int " width" property
+ #scanlines encode-int " height" property
+8 encode-int " depth" property
+/scanline  encode-int " linebytes" property
+
+' display-install is-install
+' display-remove is-remove
+
+: fill-rectangle ( index x y w h -- )
+  2swap -rot /scanline * + frame-buffer-adr + ( index w h fbadr )
+  swap 0 ?do ( index w fbadr )
+    3dup swap rot fill ( index w fbadr )
+    /scanline + ( index w fbadr' )
+  loop
+  3drop
+;
+: draw-rectangle ( addr x y w h -- )
+ 2swap -rot /scanline * + frame-buffer-adr + ( addr w h fbadr )
+ swap 0 ?do ( addr w fbadr )
+   3dup swap move ( addr w fbadr )
+    >r tuck + swap r> ( addr' w fbadr )
+    /scanline + ( addr' w fbadr' )
+  loop
+  3drop
+ ;
+ : read-rectangle ( addr x y w h -- )
+  2swap -rot /scanline * + frame-buffer-adr + ( addr w h fbadr )
+  swap 0 ?do ( addr w fbadr )
+    3dup -rot move ( addr w fbadr )
+    >r tuck + swap r> ( addr' w fbadr )
+    /scanline + ( addr' w fbadr' )
+  loop
+  3drop
+ ;
+
+: dimensions  ( -- width height )  /scanline #scanlines  ;
+
+."  ( rn50 )" cr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs
new file mode 100644
index 0000000..e83a4e0
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs
@@ -0,0 +1,25 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space assign-all-device-bars
+my-space pci-device-props
+my-space pci-set-irq-line
+
+\ set Memory Write and Invalidate Enable, SERR# Enable (see PCI 3.0 Spec Chapter 6.2.2 device control)
+
+7 4 config-w!
+
+
+\ Citrine storage controller.
+s" citrine"
+
+include citrine.fs
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs
new file mode 100644
index 0000000..1db6bda
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs
@@ -0,0 +1,23 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space assign-all-device-bars
+my-space pci-device-props
+my-space pci-set-irq-line
+
+\ set Memory Write and Invalidate Enable, SERR# Enable (see PCI 3.0 Spec Chapter 6.2.2 device control)
+7 4 config-w!
+
+\ Citrine storage controller.
+s" obsidian"
+
+include citrine.fs
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs
new file mode 100644
index 0000000..8c2c30b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs
@@ -0,0 +1,34 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ IO-APIC init
+
+s" io-apic" 2dup device-name device-type
+my-space pci-class-name type s"  ( 8131 IO-APIC )" type
+
+enable-io-access
+enable-mem-access
+pci-master-enable
+
+my-space b rshift  \ Get slot #.
+dup c lshift fec00000 or  \ Calculate base address.
+dup 48 config-l! 0 4c config-l!  \ Set base address.
+03 44 config-b!  \ Enable IO-APIC.
+
+s" ioapic.fs" included
+
+2 lshift 14 +  \ Calculate first IRQ #.
+init-ioapic  \ Set IRQs.
+
+my-space pci-device-props
+
+cr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs
new file mode 100644
index 0000000..4126ca2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs
@@ -0,0 +1,50 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space assign-all-device-bars
+my-space pci-device-props
+my-space pci-set-irq-line
+
+\ See the "ISA/EISA/ISA-PnP" OF binding document.
+
+.( isa)
+
+s" isa" 2dup device-name device-type
+\ We have to say it's ISA i.s.o. LPC, as otherwise Linux can't find
+\ the serial port for its console.  Linux uses the name instead of the
+\ device type (and it completely ignores any "compatible" property).
+
+2 encode-int s" #address-cells" property
+1 encode-int s" #size-cells" property
+
+\ We assume all ISA addresses to refer to I/O space.
+: decode-unit  1 hex-decode-unit 1 ;
+: encode-unit  drop 1 hex-encode-unit ;
+
+\ 32kB of ISA I/O space.
+1 encode-int my-space 01000000 + encode-64+ 0 encode-int+ 0 encode-int+
+8000 encode-int+ s" ranges" property
+
+: open  true ;
+: close ;
+
+\ There's a SIO chip on the LPC bus.
+INCLUDE sio.fs
+
+\ There's also an Atmel TPM chip on JS21
+\ removed on Bimini Pass 2 and therefore disabled on all Biminis
+u4? bimini? not and ?INCLUDE tpm.fs
+
+\ And finally there's the IPMI interface to the BMC.
+u4? ?INCLUDE ipmi-kcs.fs
+
+cr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs
new file mode 100644
index 0000000..fdae920
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs
@@ -0,0 +1,23 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space assign-all-device-bars
+my-space pci-device-props
+my-space pci-set-irq-line
+
+7 4 config-w!
+
+s" ide" type cr
+
+include ide.fs
+
+cr
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-interrupts.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-interrupts.fs
new file mode 100644
index 0000000..92851cd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/pci-interrupts.fs
@@ -0,0 +1,235 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ define function pointer as forward declaration for get-interrupt-line
+\ this is board wireing and southbridge dependent
+\ returns the wired interrupt line for this config addr
+\ ( config-addr -- irq-line )
+DEFER pci-get-irq-line
+
+\ define function pointer as forward declaration for get-interrupt-sense-type
+\ this is board wireing and southbridge dependent
+\ returns the wired interrupt sense type for this config addr
+\ 0 - Edge rising
+\ 1 - Level low
+\ 2 - Level high
+\ 3 - Edge falling
+\ ( config-addr -- irq-sense )
+DEFER pci-get-irq-sense
+
+
+\ *****************************************************************************
+\ Generic IRQ routines
+\ *****************************************************************************
+
+
+
+: unknown-slot ( -- 0 )
+\	cr pci-vec ABORT" Unknown slot "
+	0
+;
+\ 0c s" /ht/@1/@2"    PCI-X INTA & INTC Pnpirq0 -> irq12
+\ 0e s" /ht/@1/@2"    PCI-X INTB & INTD Pnpirq1 -> irq14
+\ 10 s" /ht/@8,1"     ATA         
+\ 0f s" /ht/@1/@1"    Obsidian     Pnpirq2 -> irq15
+\ 10 s" /ht/@7/@2"    Video / Exar Serial  PirqA
+\ 11 s" /ht/@2/@4"    Ethernet     PirqB
+\ 12 s" /ht/@2/@4,1"  Ethernet     PirqC
+\ 13 s" /ht/@7/@0"    USB          PirqD
+\ 13 s" /ht/@7/@0,1"  USB          PirqD
+\ 13 s" /ht/@7/@0,2"  USB          PirqD
+
+\ 14 s" /ht/@3/@0"    PCIe gpio28
+\ 15 s" /ht/@4/@0"    PCIe gpio29
+\ 16 s" /ht/@5/@0"    PCIe gpio30
+\ 17 s" /ht/@6/@0"    PCIe gpio31
+
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt pin for a device on ht u4
+: u4-get-irq-line ( config-addr -- irq-line )
+\	cr s" u4-get-irq-line " type
+	pci-device-vec c@ CASE 
+		1 OF pci-device-vec-len 1 >= IF  
+				pci-device-vec 1+ c@ CASE 
+					1 OF f ENDOF
+					2 OF dup pci-interrupt@ CASE
+							1 OF c ENDOF
+							3 OF e ENDOF
+							2 OF c ENDOF
+							4 OF e ENDOF
+						ENDCASE
+					ENDOF 
+					dup OF unknown-slot  ENDOF
+				ENDCASE
+			ELSE
+				unknown-slot
+			THEN
+		ENDOF
+		2 OF pci-device-vec-len 1 >= IF  
+				 pci-device-vec 1+ c@ CASE
+					4 OF dup pci-addr2fn 1 >= IF 12 ELSE 11 THEN  ENDOF 
+					dup OF unknown-slot  ENDOF
+				ENDCASE
+			ELSE
+				unknown-slot
+			THEN
+		ENDOF
+		3 OF 14 ENDOF
+		4 OF 15 ENDOF
+		5 OF 16 ENDOF
+		6 OF 17 ENDOF
+		7 OF pci-device-vec-len 1 >= IF  
+				pci-device-vec 1+ c@ CASE 
+					0 OF 13  ENDOF 
+					2 OF 10  ENDOF 
+					dup OF unknown-slot  ENDOF
+				ENDCASE
+			ELSE
+				unknown-slot
+			THEN
+		ENDOF
+		8 OF 10 ENDOF
+                dup OF unknown-slot  ENDOF	
+        ENDCASE
+	swap drop
+;
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt sense type for a device on ht u4
+: u4-get-irq-sense ( config-addr -- irq-sense )
+\	cr s" u4-get-irq-sense " type
+        u4-get-irq-line CASE 
+	0c OF 00 ENDOF
+	0e OF 00 ENDOF
+	dup OF 01  ENDOF
+        ENDCASE
+;
+
+\ 10 s" /ht/@4,1"    set-pci-interrupt \ ATA
+\ 13 s" /ht/@3/@0"   set-pci-interrupt \ USB
+\ 13 s" /ht/@3/@0,1" set-pci-interrupt \ USB
+\ 13 s" /ht/@3/@0,2" set-pci-interrupt \ USB
+\ 1c s" /ht/@2/@1"   set-pci-interrupt \ Ethernet
+\ 1d s" /ht/@2/@1,1" set-pci-interrupt \ Ethernet
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt pin for a device on ht u3
+: u3-get-irq-line ( config-addr -- irq-line )
+\	cr s" u3-get-irq-line " type
+	pci-device-vec c@ CASE 
+		2 OF pci-device-vec-len 1 >= IF  
+				pci-device-vec 1+ c@ CASE 
+					1 OF dup pci-addr2fn 1 >= IF 1d ELSE 1c THEN  ENDOF 
+					dup OF unknown-slot  ENDOF
+				ENDCASE
+			ELSE
+				unknown-slot
+			THEN
+		ENDOF
+		3 OF 13 ENDOF
+		4 OF 10 ENDOF
+                dup OF unknown-slot  ENDOF	
+        ENDCASE
+	swap drop
+;
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt sense type for a device on ht u3
+: u3-get-irq-sense ( config-addr -- irq-sense )
+\	cr s" u3-get-irq-sense " type
+        u3-get-irq-line CASE 
+	dup OF 01  ENDOF
+        ENDCASE
+;
+
+
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt pin for a device on attu
+: pcie-get-irq-line ( config-addr -- irq-line )
+\	cr s" pcie-get-irq-line " type
+	drop
+	3
+;
+
+
+\ -----------------------------------------------------------------------------
+\ Get the interrupt sense type for a device on attu
+: pcie-get-irq-sense ( config-addr -- irq-sense )
+\ 	cr s" pcie-get-irq-sense " type
+       drop
+        01
+;
+
+\ -----------------------------------------------------------------------------
+\ Set up the special routines for HT irq handling
+: ht-irq-init ( -- )
+\	cr s" ht-irq-init " type
+	u4? IF
+       		['] u4-get-irq-line TO pci-get-irq-line
+       		['] u4-get-irq-sense TO pci-get-irq-sense
+	ELSE
+        	['] u3-get-irq-line TO pci-get-irq-line
+	       	['] u3-get-irq-sense TO pci-get-irq-sense
+	THEN
+;
+
+\ -----------------------------------------------------------------------------
+\ Set up the special routines for PCI-e irq handling
+: pcie-irq-init ( -- )
+\	cr s" pcie-irq-init " type
+        ['] pcie-get-irq-sense TO pci-get-irq-sense
+        ['] pcie-get-irq-line TO pci-get-irq-line
+;
+
+\ -----------------------------------------------------------------------------
+\ Set up the special routines for irq handling
+0 VALUE mpic
+: pci-irq-init ( mpic puid -- mpic )
+        over TO mpic
+        18 rshift FF and
+        CASE
+                F1 OF pcie-irq-init ENDOF
+                F2 OF ht-irq-init ENDOF
+                dup OF ABORT" Wrong PUID! in pci-irq-init" ENDOF
+        ENDCASE
+;
+
+\ -----------------------------------------------------------------------------
+\ Set the interrupt pin for a device
+: pci-set-irq-line ( config-addr -- )
+\	cr pci-vec
+        dup pci-get-irq-line 
+\	." ->" dup .
+        swap pci-irq-line!
+;
+
+\ -----------------------------------------------------------------------------
+\ Add an irq entry for the device at config-addr into the irq map
+\ each entry consists of 7 integer values
+\ Structure of an entry:
+\             +----------+---+---+------------+--------------+---------+---------------+
+\  Number#    |    0     | 1 | 2 |     3      |      4       |    5    |      6        |
+\             +----------+---+---+------------+--------------+---------+---------------+
+\  meaning    |  config  |   |   |      int#  |  phandle     | intr nr | pos edge (0)  |
+\             |   addr   |   |   | (1=a, 2=b, |  intr contr  |         | act ll   (1)  |
+\             +----------+---+---+------------+--------------+---------+---------------+
+\  value      | pci slot | 0 | 0 |    1       |        mpic  |     7   |     0|1       |
+\             +----------+---+---+------------+--------------+---------+---------------+
+: pci-gen-irq-entry ( prop-addr prop-len config-addr -- prop-addr prop-len )
+        dup >r encode-int+ 0    encode-64+      \ config addr
+        r@ pci-interrupt@       encode-int+     \ interrupt type
+        mpic                    encode-int+     \ phandle to MPIC
+        r@ pci-irq-line@        encode-int+     \ interrupt number
+        r> pci-get-irq-sense    encode-int+     \ trigger type
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtas.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtas.fs
new file mode 100644
index 0000000..616184f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtas.fs
@@ -0,0 +1,242 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+#include <rtas/rtas-init.fs>
+#include <rtas/rtas-cpu.fs>
+#include <rtas/rtas-reboot.fs>
+#include <rtas/rtas-flash.fs>
+#include <rtas/rtas-vpd.fs>
+
+\ for update-flash
+: (get-flashside)  ( -- flashside )  rtas-get-flashside  ;
+
+' (get-flashside) to get-flashside
+
+\ remember the current flashside
+get-flashside to flashside? 
+
+\ for update-flash
+: (set-flashside)  ( flashside -- status )
+   dup rtas-set-flashside =  IF  0  ELSE  -1  THEN
+;
+
+' (set-flashside) to set-flashside
+
+: rtas-ibm-read-pci-config  ( size puid bus devfn off -- x )
+   [ s" ibm,read-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   4 rtas-cb rtas>nargs l!
+   2 rtas-cb rtas>nret l!
+   swap 8 lshift or swap 10 lshift or rtas-cb rtas>args0 l!
+   dup 20 rshift rtas-cb rtas>args1 l!
+   ffffffff and rtas-cb rtas>args2 l!
+   rtas-cb rtas>args3 l!
+   enter-rtas
+   rtas-cb rtas>args5 l@
+;
+
+: rtas-fetch-cpus  ( mask -- status )
+   [ s" rtas-fetch-slaves" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   1 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   0 rtas-cb rtas>args1 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
+
+: rtas-stop-bootwatchdog  ( -- status )
+   [ s" rtas-stop-bootwatchdog" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   0 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   enter-rtas
+   rtas-cb rtas>args0 l@
+;
+
+: rtas-set-bootwatchdog  ( seconds -- )
+   [ s" rtas-set-bootwatchdog" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   1 rtas-cb rtas>nargs l!
+   0 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+;
+
+' rtas-set-bootwatchdog to set-watchdog
+
+: rtas-dump-flash  ( offset cnt -- )
+   [ s" rtas-dump-flash" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   2 rtas-cb rtas>nargs l!
+   0 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   rtas-cb rtas>args1 l!
+   enter-rtas
+;
+
+\ load-base wird in slof/fs/base.fs gesetzt... nicht überschreiben
+\ 2000000 CONSTANT load-base
+create blist 50 allot
+blist 50 erase
+
+: build-blocklist_old
+   \ set version
+   1 blist c!
+   \ set length of block list
+   50 blist 7 + c!
+   \ no more block list
+   0000000000000000 blist 8 + !
+   \ first block
+   load-base 0 + blist 10 + !
+   80000 blist 18 + !
+   load-base 80000 + blist 20 + !
+   80000 blist 28 + !
+   load-base 100000 + blist 30 + !
+   80000 blist 38 + !
+   load-base 180000 + blist 40 + !
+   8006C blist 48 + !
+;
+
+80000 constant _block_size
+
+: build-blocklist
+   \ set length of block list
+   \ length of flashfs at load-base is at offset 30... get it...
+   load-base 30 + @
+   \ calculate the number of blocks we need
+   _block_size / 1 +
+   \ total number of blocks is 2 (for header and block_list extension + (number of blocks for flashfs * 2 (1 for address 1 for length))
+   2 * 2 + 8 * blist !
+   \ set version ( in first byte only )
+   1 blist c!
+   \ no more block list
+   0000000000000000 blist 8 + !
+   \ length of flashfs at load-base is at offset 30... get it...
+   load-base 30 + @
+   \ i define one block to be 64K, so calculate the number of blocks we need and loop over them
+   _block_size / 1 + 0 do
+      load-base _block_size i * +  \ which position of load-base to store
+      blist 10 +             \ at what offset of blist ( 0x8 + for header 0x8 + for extension )
+      i 10 * +               \ for each loop we have done 0x10 +
+      !                      \ store it
+      load-base 30 + @
+      _block_size i * -      \ remaining length
+      dup _block_size > 
+      IF                     \ is the remaining length > block size
+	drop _block_size     \ then store the block size as length
+      ELSE
+			     \ do nothing (store remaining length)
+      THEN
+      blist 10 +          \ store the length at
+      i 10 * +            \ correct blist offset 
+      8 +                 \ + 8 (we have stored address, now the length)
+      !                   \ store it
+   loop
+;
+
+
+
+: build-blocklist-v0_old
+   \ set version
+   0 blist c!
+   48 blist 7 + c!
+   \ first block
+   load-base 0 + blist 8 + !
+   80000 blist 10 + !
+   load-base 80000 + blist 18 + !
+   80000 blist 20 + !
+   load-base 100000 + blist 28 + !
+   80000 blist 30 + !
+   load-base 180000 + blist 38 + !
+   8006C blist 40 + !
+;
+
+: build-blocklist-v0
+   \ set length of block list
+   \ length of flashfs at load-base is at offset 30... get it...
+   load-base 30 + @
+   \ calculate the number of blocks we need
+   _block_size / 1 +
+   \ total number of blocks is 1 (for header + (number of blocks for flashfs * 2 (1 for address 1 for length))
+   2 * 1 + 8 * blist !
+   \ length of flashfs at load-base is at offset 30... get it...
+   load-base 30 + @
+   \ i define one block to be 64K, so calculate the number of blocks we need and loop over them
+   _block_size / 1 + 0 do
+      load-base _block_size i * +  \ which position of load-base to store
+      blist 8 +             \ at what offset of blist ( 0x8 + for header)
+      i 10 * +               \ for each loop we have done 0x10 +
+      !                      \ store it
+      load-base 30 + @
+      _block_size i * -      \ remaining length
+      dup _block_size > 
+      IF                     \ is the remaining length > block size
+	drop _block_size     \ then store the block size as length
+      ELSE
+			     \ do nothing (store remaining length)
+      THEN
+      blist 8 +          \ store the length at
+      i 10 * +            \ correct blist offset 
+      8 +                 \ + 8 (we have stored address, now the length)
+      !                   \ store it
+   loop
+;
+
+
+: yy
+   build-blocklist
+   blist rtas-ibm-update-flash-64-and-reboot
+;
+
+: yy0
+   build-blocklist-v0
+   blist rtas-ibm-update-flash-64-and-reboot
+;
+
+: rtas-ibm-update-flash-64  ( block-list -- status )
+   [ s" ibm,update-flash-64" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   2 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   \ special unofficial parameter: if this is set to 1, the rtas function will not check, wether
+   \ we are on the perm side... this is needed for "update-flash -c" to work...
+   1 rtas-cb rtas>args1 l!
+   enter-rtas
+   rtas-cb rtas>args2 l@
+;
+
+\ for update-flash
+: flash-write  ( image-address -- status)
+   load-base >r to load-base build-blocklist-v0
+   blist rtas-ibm-update-flash-64
+   r> to load-base 0=  IF  true  ELSE  false  THEN
+;
+
+: commit  1 rtas-ibm-manage-flash-image ;
+: reject  0 rtas-ibm-manage-flash-image ;
+
+: rtas-ibm-validate-flash-image  ( image-to-commit -- status )
+   [ s" ibm,validate-flash-image" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   2 rtas-cb rtas>nargs l!
+   2 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
+
+: rtas-get-blade-descr ( address size -- len status )
+   [ s" rtas-get-blade-descr" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   2 rtas-cb rtas>nargs l!
+   2 rtas-cb rtas>nret l!
+   rtas-cb rtas>args1 l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args2 l@
+   rtas-cb rtas>args3 l@
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtc.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtc.fs
new file mode 100644
index 0000000..861b3f9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/rtc.fs
@@ -0,0 +1,59 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ National Semiconductor SIO.
+\ See http://www.national.com/pf/PC/PC87417.html for the datasheet.
+\ PC87417.pdf
+\ moved the RTC initialisation from the device tree to a much earlier point
+\ so that the RTC can be accessed before device tree is generated
+
+\ Enable the RTC, set its address at 1070
+\ see PC87417.pdf page 39 (chapter 3.2.3)
+10 7 siocfg!
+1 30 siocfg!
+1070 wbsplit nip dup 60 siocfg! 62 siocfg!
+
+: rtc@  ( offset -- value )
+   1070 io-c! 1071 io-c@
+;
+
+: rtc!  ( value offset -- )
+   1070 io-c! 1071 io-c!
+;
+
+\ Set sane configuration; BCD mode is required by Linux.
+\ PC87417.pdf page 153 (chapter 8.3.13) - RTC Control Register A
+\ 20 - Divider Chain Control = Normal Operation
+20 0a rtc!
+\ PC87417.pdf page 155 (chapter 8.3.14) - RTC Control Register B
+\ 02 - 24-hour format enabled
+02 0b rtc!
+\ PC87417.pdf page 156 (chapter 8.3.15) - RTC Control Register C
+00 0c rtc!
+
+\ read from the rtc and do the bcd-to-bin conversion
+: rtc-bin@  ( offset -- value )
+   rtc@ bcd-to-bin
+;
+
+\ to be compatible with the cell boards we provide a .date word
+\ .date prints the current date and time on the firmware prompt
+: .date  ( -- )
+   0 rtc-bin@  ( seconds )
+   2 rtc-bin@
+   4 rtc-bin@
+   7 rtc-bin@
+   8 rtc-bin@  ( seconds minutes hours day month )
+   9 rtc-bin@ d# 1900 + dup d# 1970 <  IF  d# 100 +  THEN
+   decimal 4 0.r 2d emit 2 0.r 2d emit 2 0.r space
+   2 0.r 3a emit 2 0.r 3a emit 2 0.r hex
+;
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/serial.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/serial.fs
new file mode 100644
index 0000000..98b2f29
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/serial.fs
@@ -0,0 +1,48 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Serial console.  Enabled very early.
+\ remember last console used
+CREATE lastser 4 allot  0 lastser l!
+
+\ On JS21, use serial port 2.  Detect Maui by looking at the SIO version.
+20 siocfg@ f2 = IF 2f8 ELSE 3f8 THEN
+
+: >serial  LITERAL + ;
+: js21?	   -2f8 >serial 0= ;
+: serial!  js21? IF 2dup 2f8 + io-c! THEN 3f8 + io-c! ;
+: serial1@ 3f8 + io-c@ ;
+: serial2@ 2f8 + io-c@ ;
+
+: serial-init  0 1 serial!  0 2 serial!
+               80 3 serial! d# 115200 swap / 0 serial!  0 1 serial!
+               3 3 serial!  3 4 serial! ;
+: serial-emit  BEGIN 5 serial1@ 20 and UNTIL  
+ 	       js21? IF BEGIN 5 serial2@ 20 and UNTIL THEN 0 serial! ;
+: serial1-key? 5 serial1@ 1 and 0<> ;
+: serial2-key? 5 serial2@ 1 and 0<> ;
+: serial1-key  serial1-key? dup IF 0 serial1@ swap 0 lastser l! THEN ;
+: serial2-key  serial2-key? dup IF 0 serial2@ swap 1 lastser l! THEN ;
+: serial-key   BEGIN serial1-key dup IF ELSE js21? IF drop serial2-key THEN THEN UNTIL ;
+: serial-key?  serial1-key? js21? IF serial2-key? or THEN ;
+
+\ : serial-key   BEGIN 5 serial2@ 1 and UNTIL  0 serial2@ ;
+\ : serial-key?  5 serial2@  1 and 0<> ;
+
+d# 19200 serial-init
+' serial-emit to emit
+' serial-key  to key
+' serial-key? to key?
+
+( .( SLOF)
+\ .(  has started execution, serial console @ ) 0 >serial .
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/sio.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/sio.fs
new file mode 100644
index 0000000..554cf83
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/sio.fs
@@ -0,0 +1,85 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ National Semiconductor SIO.
+\ See http://www.national.com/pf/PC/PC87417.html for the datasheet.
+
+\ We use both serial ports, and the RTC.
+
+\ See 3.7.5.
+new-device   3f8 1 set-unit
+
+s" serial" 2dup device-name device-type
+
+\ Enable this UART.
+3 7 siocfg!  1 30 siocfg!
+
+\ 8 bytes of ISA I/O space
+my-unit encode-int rot encode-int+ 8 encode-int+ s" reg" property
+d# 19200 encode-int s" current-speed" property
+44 encode-int 0 encode-int+ s" interrupts" property
+
+: open  true ;
+: close ;
+: write ( adr len -- actual )  tuck type ;
+: read  ( adr len -- actual )  0= IF drop 0 EXIT THEN
+                               serial-key? 0= IF 0 swap c! -2 EXIT THEN
+                               serial-key swap c! 1 ;
+
+finish-device
+
+
+new-device   2f8 1 set-unit
+
+s" serial" 2dup device-name device-type
+
+\ Enable this UART.
+2 7 siocfg!  1 30 siocfg!
+
+\ 8 bytes of ISA I/O space
+my-unit encode-int rot encode-int+ 8 encode-int+ s" reg" property
+d# 19200 encode-int s" current-speed" property
+43 encode-int 0 encode-int+ s" interrupts" property
+
+: open  true ;
+: close ;
+: write ( adr len -- actual )  tuck type ;
+: read  ( adr len -- actual )  0= IF drop 0 EXIT THEN
+                               serial-key? 0= IF 0 swap c! -2 EXIT THEN
+                               serial-key swap c! 1 ;
+
+finish-device
+
+
+
+\ See the "Device Support Extensions" OF Recommended Practice document.
+new-device   1070 1 set-unit
+
+s" rtc" 2dup device-name device-type
+\ Following is for Linux, to recognize this RTC:
+s" pnpPNP,b00" compatible
+
+: rtc!  my-space io-c!  my-space 1+ io-c! ;
+: rtc@  my-space io-c!  my-space 1+ io-c@ ;
+
+\ 10 bytes of ISA I/O space, at 1070.
+my-unit encode-int rot encode-int+ 10 encode-int+ s" reg" property
+
+: open   true ;
+: close ;
+
+\ XXX: dummy methods.
+: get-time ( -- sec min hr day mth yr )  38 22 c 1 1 d# 1973 ;
+: set-time ( sec min hr day mth yr -- )  3drop 3drop ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/tpm.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/tpm.fs
new file mode 100644
index 0000000..69b9bc4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/tpm.fs
@@ -0,0 +1,63 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Atmel TPM.
+
+new-device   500 1 set-unit
+
+s" tpm" 2dup device-name device-type
+
+s" AT97SC3201" compatible
+
+\ 2 bytes of ISA I/O space
+my-unit encode-int rot encode-int+ 2 encode-int+ s" reg" property
+
+: >tpm  4e io-c! ;
+: tpm@  >tpm 4f io-c@ ;
+: tpm!  >tpm 4f io-c! ;
+
+: dump-tpm  11 0 DO cr i 2 .r space i tpm@ 2 0.r LOOP ;
+
+my-address wbsplit 9 tpm! 8 tpm! \ set base address
+0 a tpm! \ disable serint
+
+\ Now we need to execute TPM_Startup.
+CREATE startup-cmd
+0 c, c1 c,
+0 c, 0 c, 0 c, c c,
+0 c, 0 c, 0 c, 99 c, \ TPM_ORD_Startup
+0 c, 1 c, \ TCPA_ST_CLEAR
+
+: send ( addr len -- )  bounds ?DO i c@ 500 io-c! LOOP ;
+: wait-for-ready ( -- )  BEGIN 501 io-c@ 3 and 2 = UNTIL ;
+: recv-verbose  ( -- )
+   cr ." TPM result: "
+   500 io-c@ 2 0.r 500 io-c@ 2 0.r space
+   500 io-c@ 500 io-c@ 500 io-c@ 500 io-c@ 
+   bljoin lbflip 6 - dup 8 0.r space 0
+   ?DO  500 io-c@ .  LOOP
+;
+
+: recv ( -- )
+   500 io-c@ drop 500 io-c@ drop
+   500 io-c@ 500 io-c@ 500 io-c@ 500 io-c@
+   bljoin lbflip 6 - 0
+   ?DO  500 io-c@ drop  LOOP
+;
+
+startup-cmd c send  wait-for-ready  recv
+
+: open  true ;
+: close ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/tree.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/tree.fs
new file mode 100644
index 0000000..fe43955
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/tree.fs
@@ -0,0 +1,227 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+400 cp
+
+0 value puid
+
+: >conf-rtas ( config-addr  -- config-addr )
+   puid f2000000 >= IF dup ffff > IF 1000000 + THEN THEN puid +  ;
+
+: rtas-config-b@ ( config-addr -- value ) >conf-rtas rb@ ;
+: rtas-config-b! ( value config-addr -- ) >conf-rtas rb! ;
+: rtas-config-w@ ( config-addr -- value ) >conf-rtas rw at -le ;
+: rtas-config-w! ( value config-addr -- ) >conf-rtas rw!-le ;
+: rtas-config-l@ ( config-addr -- value ) >conf-rtas rl at -le ;
+: rtas-config-l! ( value config-addr -- ) >conf-rtas rl!-le ;
+
+440 cp
+
+#include "pci-scan.fs"
+
+480 cp
+
+\ The root of the device tree and some of its kids.
+
+s" /" find-device
+\ read model string from VPD
+vpd-read-model ( straddr strlen )
+\ if it is a bimini, we replace the "IBM," in the model string with "TSS,"
+bimini? IF
+   2dup drop 4 ( straddr strlen str 4 ) \ for string comparison: only first 4 bytes ("IBM,")
+   \ string comparison
+   s" IBM," str= IF
+      \ model starts with "IBM,", we replace it with "TSS,"
+      2dup drop s" TSS," ( straddr strlen straddr replacestr len )
+      rot swap ( straddr strlen replacestr straddr len ) \ correct order for move: src dest len
+      move ( straddr strlen ) \ now we have TSS, at beginning of str...
+   THEN
+THEN
+\ store the model string
+encode-string s" model" property
+
+2 encode-int s" #address-cells" property
+2 encode-int s" #size-cells" property
+
+\ XXX: what requires this?  Linux?
+0 encode-int  f8040000 encode-int+
+0 encode-int+ f8050000 encode-int+ s" platform-open-pic" property
+
+\ Yaboot is stupid.  Without this, it can't/won't find /etc/yaboot.conf.
+s" chrp SLOF based 970 blade" device-type
+
+\ add more information to the compatible property
+js21?  IF
+   bimini?  IF
+      s" IBM,Bimini"
+   ELSE
+      s" IBM,JS21"
+   THEN
+ELSE
+   s" IBM,JS20"
+THEN  encode-string
+\ To get linux-2.6.10 and later to work out-of-the-box.
+s" Momentum,Maple" encode-string encode+ s" compatible" property
+
+
+\ See 3.6.5, and the PowerPC OF binding document.
+new-device
+s" mmu" 2dup device-name device-type
+0 0 s" translations" property
+
+: open  true ;
+: close ;
+
+finish-device
+
+new-device flash-addr set-unit-64
+   s" flash" 2dup device-name device-type
+   0 encode-int flash-addr encode-int+
+   0 encode-int+ get-flash-size encode-int+ s" reg" property
+   get-flash-size encode-int s" #bytes" property
+   0 0 s" used-by-rtas" property
+   : open  true  ;
+   : close  ;
+finish-device
+
+4a0 cp
+
+new-device nvram-base set-unit-64
+   s" nvram" 2dup device-name device-type
+   nvram-size encode-int s" #bytes" property
+   0 encode-int nvram-base encode-int+
+   0 encode-int+ nvram-size encode-int+ s" reg" property
+   get-node node>path s" nvram" 2swap set-alias
+   : open  true  ;
+   : close  ;
+finish-device
+
+4c0 cp
+
+#include "memory.fs"
+
+500 cp
+
+#include "mpic.fs"
+
+580 cp
+
+#include "dart.fs"
+
+5a0 cp
+
+#include "i2c.fs"
+
+600 cp
+get-node device-end
+620 cp
+\ if it is js21/bimini the fbuffer code is included
+u4? ?include fbuffer.fs
+640 cp
+set-node
+
+690 cp
+
+#include "ht.fs"
+
+6a0 cp
+get-node device-end
+6a8 cp
+\ at this point the SAS controller has been detected and we know
+\ if it is bimini or js21
+\ if it is bimini the fcode evaluator is included
+bimini? ?include evaluator.fs
+6b0 cp
+set-node
+6b8 cp
+
+u4? ?include attu.fs
+6c0 cp
+
+\ See the PowerPC OF binding document.
+new-device
+s" cpus" device-name
+
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+: decode-unit  1 hex-decode-unit ;
+: encode-unit  1 hex-encode-unit ;
+
+cpu-mask @ 40 0 DO dup 1 and IF
+i s" cpu.fs" INCLUDED THEN u2/ LOOP drop
+
+: open  true ;
+: close ;
+
+finish-device
+
+master-cpu s" /cpus/@" rot (u.) $cat open-dev encode-int s" cpu" set-chosen
+s" /memory" open-dev encode-int s" memory" set-chosen
+
+6e0 cp
+
+new-device
+   s" rtas" device-name
+
+   rtas-size encode-int s" rtas-size" property
+   00000001 encode-int s" ibm,flash-block-version" property
+   00000001 encode-int s" rtas-event-scan-rate" property
+   rtas-create-token-properties
+   00000001 encode-int s" rtas-version" property
+
+: open  true ;
+: close ;
+
+: instantiate-rtas instantiate-rtas ;
+
+finish-device
+
+700 cp
+
+device-end
+
+\ Hack for AIX.
+s" /options" find-device
+   \ s" 33554432" encode-string s" load-base" property
+   s" 16384" encode-string s" load-base" property
+device-end
+
+\ See 3.5.
+s" /openprom" find-device
+   s" SLOF," slof-build-id here swap rmove here slof-build-id nip $cat encode-string s" model" property
+   0 0 s" relative-addressing" property
+   flashside? 1 = IF s" T" ELSE s" P" THEN
+   encode-string s" ibm,fw-bank" property
+   takeover? not  IF
+      0 set-flashside drop
+      read-version-and-date  s" ibm,fw-perm-bank" property
+      1 set-flashside drop
+      read-version-and-date  s" ibm,fw-temp-bank" property
+      flashside? set-flashside drop
+   THEN
+device-end
+
+s" /aliases" find-device
+   : open  true ;
+   : close ;
+device-end
+
+s" /mmu" open-dev encode-int s" mmu" set-chosen
+
+#include "available.fs"
+
+#include <term-io.fs>
+
+u3? IF s" /ht/isa/serial at 3f8" io
+  ELSE s" /ht/isa/serial at 2f8" io THEN
+
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/u4-mem.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/u4-mem.fs
new file mode 100644
index 0000000..0f8b1ee
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/u4-mem.fs
@@ -0,0 +1,313 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ U4 DDR2 memory controller.
+
+cr .( Setting up memory controller...)
+
+
+\ First, I2C access to the SPDs.
+
+: >i2c  f8001000 + ;
+: i2c@  >i2c rl@ ;
+: i2c!  >i2c rl! ;
+
+: .i2c  80 0 DO i i2c@ . 10 +LOOP ;
+
+: i2c-addr ( addr -- )  50 i2c!  2 10 i2c!  BEGIN 30 i2c@ 2 and UNTIL ;
+: i2c-addr-subaddr ( addr suba -- )  60 i2c! i2c-addr ;
+: i2c-stop ( -- )  BEGIN 30 i2c@ dup 30 i2c! 4 and UNTIL ;
+: i2c-nak? ( -- failed? )  20 i2c@ 2 and 0= dup IF i2c-stop THEN ;
+: i2c-short? ( -- failed? )  30 i2c@ 4 and 0<> dup IF 0 10 i2c! i2c-stop THEN ;
+: i2c-aak-if-more ( n -- )  1 <> 1 and 10 i2c! ;
+
+: i2c-sub-read ( buf len addr suba -- error? )
+  c 0 i2c!  >r 1 or r> i2c-addr-subaddr  i2c-nak? IF 2drop true EXIT THEN
+  dup i2c-aak-if-more  2 30 i2c!
+  BEGIN
+  30 i2c@ 1 and IF
+    1- >r 70 i2c@ over c! char+ r>
+    dup 0= IF i2c-stop 2drop false EXIT THEN
+    dup i2c-aak-if-more 1 30 i2c! THEN
+  i2c-short? IF 2drop true EXIT THEN
+  AGAIN ;
+
+
+\ What slots are filled with working memory (bitmask).
+
+f VALUE dimms-valid
+: dimm-invalid  1 swap lshift invert dimms-valid and to dimms-valid ;
+: dimm-invalid  dup dimm-invalid 2 xor dimm-invalid ; \ DIMMs are paired
+: dimm-valid?  1 swap lshift dimms-valid and ;
+: dimm(  +comp postpone 4 postpone 0 postpone DO
+               postpone i postpone dimm-valid? postpone IF ; immediate
+: )dimm  postpone THEN postpone LOOP -comp ; immediate
+
+
+\ The data from the SPDs.
+
+CREATE spds 100 allot
+: spd@ ( dimm# off -- value ) swap 40 * + spds + c@ ;
+
+CREATE addresses a0 c, a4 c, a2 c, a6 c,
+dimm( spds i 40 * + 40 addresses i + c@ 0 i2c-sub-read IF i dimm-invalid THEN )dimm
+
+
+\ Accessors.
+
+: spd>rows  3 spd@ ;
+: spd>cols  4 spd@ ;
+: spd>ranks 5 spd@ 7 and 1+ ;
+: spd>width d spd@ ;
+: spd>banks 11 spd@ ;
+: spd>cas   12 spd@ ; \ bit mask of allowable CAS latencies
+: spd>trp   1b spd@ ; \ in units of 0.25 ns
+: spd>trrd  1c spd@ ; \ in units of 0.25 ns
+: spd>trcd  1d spd@ ; \ in units of 0.25 ns
+: spd>tras  1e spd@ ; \ in units of 1 ns
+: spd>twr   24 spd@ ; \ in units of 0.25 ns
+: spd>twtr  25 spd@ ; \ in units of 0.25 ns
+: spd>trtp  26 spd@ ; \ in units of 0.25 ns
+: spd>trc   29 spd@ ; \ in units of 1 ns  XXX: should also look at byte 28
+: spd>trfc  2a spd@ ; \ in units of 1 ns  XXX: should also look at byte 28
+
+cr .( rows cols ranks width banks trp trrd trcd tras twr twtr trtp trc trfc)
+cr .( =====================================================================)
+decimal
+dimm( cr
+i spd>rows  4 .r  i spd>cols  5 .r  i spd>ranks 6 .r  i spd>width 6 .r
+i spd>banks 6 .r  i spd>trp   4 .r  i spd>trrd  5 .r  i spd>trcd  5 .r
+i spd>tras  5 .r  i spd>twr   4 .r  i spd>twtr  5 .r  i spd>trtp  5 .r
+i spd>trc   4 .r  i spd>trfc  5 .r
+)dimm
+hex
+
+ff dimm( i spd>cas and )dimm CONSTANT cl-supported
+: max-cl  -1 swap 8 0 DO dup 1 and IF nip i swap THEN u2/ LOOP drop ;
+cl-supported max-cl VALUE cl
+
+: tck>60*ns dup f and swap 4 rshift a * over + 6 * swap CASE
+            a OF 2d - ENDOF b OF 2e - ENDOF c OF 20 - ENDOF d OF 21 - ENDOF
+            ENDCASE ;
+: cl>tck  0 spd>cas max-cl swap -
+          CASE 0 OF 9 ENDOF 1 OF 17 ENDOF 2 OF 19 ENDOF
+          true ABORT" No supported CAS latency for this DIMM" ENDCASE
+          0 swap spd@ tck>60*ns ;
+
+: spd>min-tck  dup spd>cas max-cl cl -
+               CASE 0 OF 9 ENDOF 1 OF 17 ENDOF 2 OF 19 ENDOF
+               true ABORT" No supported CAS latency for this DIMM" ENDCASE
+               spd@ tck>60*ns ;
+: spd>max-tck  2b spd@ tck>60*ns ;
+
+: .tck  base @ >r decimal dup d# 60 / 0 .r [char] . emit
+        d# 60 mod d# 1000 * d# 60 / 3 0.r ." ns" r> base ! ;
+
+cr .( CAS latencies supported: )
+8 0 DO cl-supported 1 i lshift and IF i . THEN LOOP
+
+\ Find the lowest CL at the highest tCK.
+8 0 DO cl-supported 1 i lshift and IF cl cl>tck i cl>tck = IF
+       i to cl LEAVE THEN THEN LOOP
+
+.( -- using ) cl .
+
+
+0 dimm( i spd>min-tck max )dimm  CONSTANT tck
+dimm( i spd>max-tck tck < IF i dimm-invalid THEN )dimm
+cr .( tCK is ) tck .tck
+
+
+0 CONSTANT al
+cl al + CONSTANT rl
+rl 1- CONSTANT wl
+
+: //  dup >r 1- + r> / ; \ round up
+0 spd>tras d# 60 * tck // CONSTANT tras
+0 spd>trtp d# 15 * tck // CONSTANT trtp
+0 spd>twr  d# 15 * tck // CONSTANT twr
+0 spd>trp  d# 15 * tck // CONSTANT trp
+0 spd>trrd d# 15 * tck // CONSTANT trrd
+0 spd>trrd d# 60 * tck // CONSTANT 4*trrd
+0 spd>trcd d# 15 * tck // CONSTANT trcd
+0 spd>trc  d# 60 * tck // CONSTANT trc
+0 spd>twtr d# 15 * tck // CONSTANT twtr
+
+: spd>memmd
+  >r r@ spd>rows r@ spd>cols +
+  r@ spd>banks 2log + 4 * r> spd>width 2log 3 * + 6c - ;
+: dimm-group-size ( dimm# -- size )
+  >r r@ spd>rows r@ spd>cols + 1 swap lshift
+  r@ spd>banks * r> spd>ranks * 10 * ;
+VARIABLE start-address
+VARIABLE was-prev-big
+: assign-dimm-group ( dimm# -- config-value )
+  dup dimm-valid? 0= IF drop 0 EXIT THEN
+  \ MemMd, enable, single-sided or not
+  dup spd>memmd c lshift 1 or over spd>ranks 1 = IF 2 or THEN 
+cr ." ---> " dup .
+>r
+  dimm-group-size start-address @ 2dup + rot ( start end size )
+  80000000 > IF
+    dup 1000000000 < IF dup 4 rshift ELSE 08000000 THEN r> or >r \ Add2G
+    over 0<>        IF over c rshift ELSE 00080000 THEN r> or >r \ Sub2G
+    was-prev-big on
+  ELSE
+    was-prev-big @ IF 80000000 + swap 80000000 + swap THEN r> 08080000 or >r
+    was-prev-big off
+  THEN
+  swap 18 rshift r> or >r \ start address
+  dup 80000000 = IF drop 100000000 THEN start-address ! r> ;
+
+
+\ Now set the frequency in the memory controller
+d# 1800 tck / 4 - 12 lshift 33c or f8000800 rl!
+f8000860 rl@ 80000000 or f8000860 rl!  10000 0 DO LOOP
+
+: mc!  f8002000 + rl! ;
+: mc@  f8002000 + rl@ ;
+
+
+\ memory timing regs (state machine)
+
+tras 2-
+5 lshift al trtp + 2- or
+5 lshift wl twr + or
+5 lshift trp 2- or
+5 lshift trp 2- 0 spd>banks 8 = IF 1+ THEN or
+7 lshift 030 mc!
+
+al trtp + trp + 2-
+5 lshift cl al + twr + trp + 1- or
+5 lshift trrd 2- or
+5 lshift trc 2- or
+5 lshift trcd 2- or
+5 lshift 4*trrd or
+2 lshift 040 mc!
+
+0
+5 lshift 1 or
+5 lshift 1 or
+5 lshift cl 1- twtr + or
+5 lshift 1 or
+5 lshift 1 or
+2 lshift 050 mc!
+
+0
+5 lshift 1 or
+5 lshift 1 or
+5 lshift 2 or
+5 lshift 2 or
+5 lshift 2 or
+2 lshift 060 mc! \ XXX joerg has different setting
+
+cl 3 = IF 30801800 ( 30800d00 ) 070 mc! \ XXX memory refresh
+ELSE 41002000 070 mc! THEN
+
+\ memory size regs
+
+1 dimm-group-size 0 dimm-group-size > 1 0 rot IF swap THEN \ biggest first
+assign-dimm-group 200 mc!
+assign-dimm-group 210 mc!
+0 220 mc! 0 230 mc!
+
+
+
+
+
+\ arbiter tunables
+\ 40041040 270 mc!
+04041040 270 mc!
+50000000 280 mc!
+\ a0a00000 290 mc! \ a0000000 might be faster
+00000000 290 mc!
+\ 20020820 2a0 mc!
+04020822 2a0 mc!
+00000000 2b0 mc!
+\ 30413cc7 2c0 mc! \ have to calculate the low five bits
+30413dc5 2c0 mc!
+\ cl 3 = IF 76000050 2d0 mc!  70000000 2e0 mc! ELSE
+cl 3 = IF 75000050 2d0 mc!  70000000 2e0 mc! ELSE
+    b8002080 2d0 mc!  b0000000 2e0 mc! THEN
+\ Should test for something else really
+
+
+
+cl 3 = IF 00006000 890 mc!  00006000 8a0 mc! ELSE
+          00006500 890 mc!  00006500 8a0 mc! THEN
+
+cl 3 = IF 1e008a8a ELSE 31000000 THEN
+dup 800 mc! dup 810 mc! dup 820 mc! dup 830 mc!
+dup 900 mc! dup 910 mc! dup 920 mc! dup 930 mc! dup 980 mc!
+dup a00 mc! dup a10 mc! dup a20 mc! dup a30 mc!
+dup b00 mc! dup b10 mc! dup b20 mc! dup b30 mc!     b80 mc!
+
+\ 0 8d0 mc!  0 9d0 mc!  0 ad0 mc!  0 bd0 mc!
+61630000 8d0 mc!
+61630000 9d0 mc!
+52510000 ad0 mc!
+434e0000 bd0 mc!
+
+a0200400 100 mc!
+80020000 110 mc!
+80030000 120 mc!
+80010404 130 mc!
+cl 3 = IF
+8000153a 140 mc! ELSE
+8000174a 140 mc! THEN
+a0200400 150 mc!
+\ 92000000 160 mc!
+\ 92000000 170 mc!
+\ 91300000 160 mc!
+\ 91300000 170 mc!
+91800000 160 mc!
+91800000 170 mc!
+cl 3 = IF
+8ff0143a 180 mc! ELSE
+8ff0164a 180 mc! THEN
+80010784 190 mc!
+80010404 1a0 mc!
+0 1b0 mc!  0 1c0 mc!  0 1d0 mc!  0 1e0 mc!  0 1f0 mc!
+
+cl 3 = IF
+143a 0c0 mc! ELSE
+164a 0c0 mc! THEN
+0404 0d0 mc!
+
+\ after this point, setup is common for all speeds and sizes of dimms (sort of)
+
+60000000 3a0 mc!
+
+0 840 mc!  0 850 mc!  0 860 mc!  0 870 mc!
+0 940 mc!  0 950 mc!  0 960 mc!  0 970 mc!  0 990 mc!
+0 a40 mc!  0 a50 mc!  0 a60 mc!  0 a70 mc!
+0 b40 mc!  0 b50 mc!  0 b60 mc!  0 b70 mc!  0 b90 mc!
+
+0 880 mc!
+
+001a4000 9a0 mc!
+
+84800000 500 mc!
+
+10000 0 DO LOOP
+
+80000000 b0 mc!  BEGIN b0 mc@ 40000000 and UNTIL
+
+0 300 mc!  0 310 mc!
+
+80000000 440 mc!
+0 410 mc!  27fffffc 420 mc!
+fedcba98 430 mc!
+c0000000 400 mc!  BEGIN 400 mc@ c0000000 and 0= UNTIL
+
+cr .( mem done)
diff --git a/qemu-0.15.x/roms/SLOF/board-js2x/slof/vga-display.fs b/qemu-0.15.x/roms/SLOF/board-js2x/slof/vga-display.fs
new file mode 100644
index 0000000..0cc9bba
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-js2x/slof/vga-display.fs
@@ -0,0 +1,215 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ included by pci-class_03.fs
+
+( str len display_num ) \ name prefix
+
+false value is-installed?
+value display_num ( str len )
+
+s" ,Display-" $cat 41 display_num + char-cat \ add ", Display-A" or "-B" to name ( str len )
+encode-string s" name" property \ store as name property
+
+s" display" encode-string s" device_type" property \ add "device_type" propert
+
+\ screen-info is set by pci-class_03.fs contains output of get_vbe_info bios-snk call
+CASE screen-info c@ \ ( display-type )
+   0 OF s" NONE" ENDOF \ No display
+   1 OF s" Analog" ENDOF
+   2 OF s" Digital" ENDOF
+ENDCASE
+encode-string s" display-type" property 
+
+screen-info 8 + l@ value mem-adr
+screen-info 1 + w@ value width
+screen-info 3 + w@ value height
+
+screen-info c@ IF
+   \ if screen-info is not 0, we have some screen attached, add needed properties...
+   width encode-int s" width" property
+   height encode-int s" height" property
+   screen-info 5 + w@ encode-int s" linebytes" property
+   screen-info 7 + c@ encode-int s" depth" property
+   mem-adr encode-int s" address" property
+   \ the EDID property breaks the boot... so i leave it out for now, 
+   \ maybe encode-bytes does s.th. wrong???
+   \ screen-info c + 80 encode-bytes s" EDID" property
+   s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok...
+THEN
+
+\ words for installation/removal, needed by is-install/is-remove, see display.fs
+: display-remove ( -- ) 
+;
+: display-install ( -- ) 
+   is-installed? NOT IF 
+      mem-adr to frame-buffer-adr 
+      default-font 
+      set-font
+      width height width char-width / height char-height / ( width height #lines #cols )
+      fb8-install 
+      true to is-installed?
+   THEN
+;
+
+\ as of OF 8bit Graphics Recommendation, these shall be implemented:
+
+: draw-rectangle ( adr x y w h -- )
+   is-installed? IF
+      0 ?DO
+         4dup ( adr x y w adr x y w )
+         drop ( adr x y w adr x y )
+         i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) 
+         ( adr x y w adr offs ) 
+         frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 
+         1 pick 3 pick i * + swap 3 pick ( adr x y w adr adr_offs fb_adr w )
+         rmove \ copy line ( adr x y w adr )
+         drop ( adr x y w )
+      LOOP
+      4drop
+   ELSE
+      4drop drop
+   THEN
+;
+
+: fill-rectangle ( number x y w h -- )
+   is-installed? IF
+      0 ?DO
+         4dup ( number x y w number x y w )
+         drop ( number x y w number x y )
+         i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) 
+         ( number x y w number offs ) 
+         frame-buffer-adr + \ add to frame-buffer-adr ( number x y w number adr ) 
+         2 pick 2 pick ( number x y w number adr w number )
+         rfill \ draw line ( number x y w number )
+         drop ( number x y w )
+      LOOP
+      4drop
+   ELSE
+      4drop drop
+   THEN
+;
+
+: read-rectangle ( adr x y w h -- )
+   is-installed? IF
+      0 ?DO
+         4dup ( adr x y w adr x y w )
+         drop ( adr x y w adr x y )
+         i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) 
+         ( adr x y w adr offs ) 
+         frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 
+         1 pick 3 pick i * + 3 pick ( adr x y w adr fb_adr adr_offs w )
+         rmove \ copy line ( adr x y w adr )
+         drop ( adr x y w )
+      LOOP
+      4drop
+   ELSE
+      4drop drop
+   THEN
+;
+
+: color! ( r g b number -- ) 
+   \ 3c8 is RAMDAC write mode select palette entry register
+   \ 3c9 is RAMDAC write mode write palette entry register ( 3 consecutive writes set new entry )
+   vga-device-node? 3c8 translate-address ( r g b number address ) 
+   swap 1 pick ( r g b address number address )
+   rb! \ write palette entry number ( r g b address )
+   1 + \ select next register (3c9)
+   dup 4 pick swap rb! \ write red ( r g b address )
+   dup 3 pick swap rb! \ write green ( r g b address )
+   dup 2 pick swap rb! \ write blue ( r g b address )
+   4drop
+;
+
+: color@ ( number -- r g b ) 
+   \ 3c7 is RAMDAC read mode select palette entry register
+   \ 3c9 is RAMDAC read mode read palette entry register ( 3 consecutive reads read entry )
+   vga-device-node? 3c7 translate-address ( number address ) 
+   swap 1 pick ( address number address )
+   rb! \ write palette entry number ( address )
+   2 + >r \ select next register (3c9) ( R: address )
+   r@ rb@ \ read red ( r R: address )
+   r@ rb@ \ read green ( r g R: address )
+   r@ rb@ \ write blue ( r g b R: address )
+   r> drop ( r g b )
+;
+
+: set-colors ( adr number #numbers -- )
+   \ 3c8 is RAMDAC write mode select palette entry register
+   \ 3c9 is RAMDAC write mode write palette entry register ( 3 consecutive writes set new entry )
+   \ since after writing 3 entries, the palette entry is automagically incremented, 
+   \ we can just continue writing...
+   vga-device-node? 3c8 translate-address ( adr number #numbers ) 
+   dup 3 pick swap ( adr number #numbers address number address )
+   rb! \ write palette entry number ( adr number #numbers address )
+   1 + \ select next register (3c9)  
+   -rot swap drop ( adr address #numbers )
+   -rot swap rot  ( address adr #numbers )
+   0 ?DO
+      ( address adr )
+      dup rb@ \ read red value from adr ( address adr r )
+      2 pick rb! \ write to register ( address adr )
+      1 + \ next adr 
+      dup rb@ \ read green value from adr ( address adr g )
+      2 pick rb! \ write to register ( address adr )
+      1 + \ next adr 
+      dup rb@ \ read blue value from adr ( address adr r )
+      2 pick rb! \ write to register ( address adr )
+      1 + \ next adr 
+   LOOP
+   2drop
+;
+
+: get-colors ( adr number #numbers -- )
+   \ 3c7 is RAMDAC read mode select palette entry register
+   \ 3c9 is RAMDAC read mode read palette entry register ( 3 consecutive reads get entry )
+   \ since after reading 3 entries, the palette entry is automagically incremented, 
+   \ we can just continue reading...
+   vga-device-node? 3c7 translate-address ( adr number #numbers ) 
+   dup 3 pick swap ( adr number #numbers address number address )
+   rb! \ write palette entry number ( adr number #numbers address )
+   2 + \ select next register (3c9)  
+   -rot swap drop ( adr address #numbers )
+   -rot swap rot  ( address adr #numbers )
+   0 ?DO
+      ( address adr )
+      1 pick rb@ \ read red value from register ( address adr r )
+      1 pick rb! \ write to adr ( address adr )
+      1 + \ next adr 
+      1 pick rb@ \ read green value from register ( address adr g )
+      1 pick rb! \ write to adr ( address adr )
+      1 + \ next adr 
+      1 pick rb@ \ read blue value from register ( address adr b )
+      1 pick rb! \ write to adr ( address adr )
+      1 + \ next adr 
+   LOOP
+   2drop
+;
+
+: dimensions ( -- width height )
+width height
+;
+
+\ clear screen 
+mem-adr width height * 0 rfill
+
+\ call is-install and is-remove
+' display-install is-install
+
+' display-remove is-remove
+
+s" screen" find-alias 0= IF
+   \ no previous screen alias defined, define it...
+   s" screen" get-node node>path set-alias
+ELSE
+   drop
+THEN 
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/Makefile b/qemu-0.15.x/roms/SLOF/board-qemu/Makefile
new file mode 100644
index 0000000..b67ee24
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/Makefile
@@ -0,0 +1,76 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+BOARD_TARGETS = tools_build romfs_build clients_build net_veth stage1
+
+SUBDIRS = slof 
+COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall
+
+all: $(BOARD_TARGETS) subdirs boot_rom.bin
+
+.PHONY : subdirs $(SUBDIRS) clean distclean
+
+include config
+include Makefile.dirs
+include $(TOPCMNDIR)/make.rules
+include $(TOPCMNDIR)/Makefile.gen
+
+subdirs: $(SUBDIRS)
+
+$(SUBDIRS): common-libs
+		@echo " ====== Building $@ ======"
+		$(MAKE) -C $@ $(MAKEARG)
+
+stage1:	common-libs
+		@echo " ====== Building llfw ======"
+		make -C llfw RELEASE=-DRELEASE=\"\\\"$(RELEASE)\\\"\"
+
+net_veth: common-libs
+		@echo " ====== Building veth ======"
+		make -C veth
+
+clean_here:
+		rm -f ../slof/OF.ffs
+		rm -f ../boot_rom.bin
+
+clean:		clean_here clean_gen
+		@for dir in $(SUBDIRS); do \
+			$(MAKE) -C $$dir clean || exit 1; \
+		done
+		rm -f ../boot_rom.bin 
+		@make -C llfw clean
+		make -C veth clean
+
+distclean:	clean_here distclean_gen
+		@for dir in $(SUBDIRS); do \
+			$(MAKE) -C $$dir distclean || exit 1; \
+		done
+		rm -f ../boot_rom.bin 
+		make -C llfw clean
+		make -C veth distclean
+
+.driver_dirs:
+		@rm -rf ../driver-$(RELEASE)
+		@mkdir -p ../driver-$(RELEASE)
+
+.tar_gz:	.driver_dirs
+		@mv ../boot_rom.bin ../driver-$(RELEASE)/$(RELEASE)-slof.bin
+		@cp ../VERSION ../driver-$(RELEASE)
+		@cp changes.txt ../driver-$(RELEASE)
+		@cd ../driver-$(RELEASE) && md5sum * > md5sum.txt
+		@chmod 644 ../driver-$(RELEASE)/*
+		@mv ../driver-$(RELEASE) ../driver-$(RELEASE)-`date +%Y-%h%d`
+		@tar czf ../driver-$(RELEASE)-`date +%Y-%h%d`.tar.gz \
+			../driver-$(RELEASE)-`date +%Y-%h%d` > /dev/null  2>&1
+		@rm -rf ../driver-$(RELEASE)-`date +%Y-%h%d`
+
+driver:		driver_prep clean .tar_gz
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/Makefile.dirs b/qemu-0.15.x/roms/SLOF/board-qemu/Makefile.dirs
new file mode 100644
index 0000000..1493d3b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/Makefile.dirs
@@ -0,0 +1,41 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+#
+# This sub-Makefile contains the directory configuration variables.
+# It can be included from all board specific subdirectories.
+#
+
+# The board specific top directory:
+export TOPBRDDIR ?= $(shell while ! test -e Makefile.dirs ; do cd .. ; done ; pwd )
+
+# The board specific directories:
+export INCLBRDDIR ?= $(TOPBRDDIR)/include
+export LLFWBRDDIR ?= $(TOPBRDDIR)/llfw
+export RTASBRDDIR ?= $(TOPBRDDIR)/rtas
+export SLOFBRDDIR ?= $(TOPBRDDIR)/slof
+export ROMFSBRDDIR ?=  $(TOPBRDDIR)/romfs
+
+# The common top directory:
+export TOPCMNDIR ?= $(shell cd $(TOPBRDDIR)/.. && pwd)
+
+# The common directories:
+export INCLCMNDIR ?= $(TOPCMNDIR)/include
+export LLFWCMNDIR ?= $(TOPCMNDIR)/llfw
+export RTASCMNDIR ?= $(TOPCMNDIR)/rtas
+export SLOFCMNDIR ?= $(TOPCMNDIR)/slof
+export ROMFSCMNDIR ?=  $(TOPCMNDIR)/romfs
+
+export LIBCMNDIR ?= $(TOPCMNDIR)/lib
+
+export TOOLSDIR ?= $(TOPCMNDIR)/tools
+export CLIENTSDIR ?= $(TOPCMNDIR)/clients
+export OTHERLICENCEDIR ?= $(TOPCMNDIR)/other-licence
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/config b/qemu-0.15.x/roms/SLOF/board-qemu/config
new file mode 100644
index 0000000..63976a0
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/config
@@ -0,0 +1,7 @@
+BOARD=qemu
+TARG=ppc64
+export FLAG="-DDISABLE_NVRAM"
+export CPUARCH=ppcp7
+export CPUARCHDEF=-DCPU_PPCP7
+#export SNK_BIOSEMU_APPS=1
+FLASH_SIZE=8388608
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/include/hw.h b/qemu-0.15.x/roms/SLOF/board-qemu/include/hw.h
new file mode 100644
index 0000000..27117c3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/include/hw.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+uint16_t bswap16_load(uint64_t addr) ;
+uint32_t bswap32_load(uint64_t addr) ;
+
+void bswap16_store(uint64_t addr, uint16_t val) ;
+void bswap32_store(uint64_t addr, uint32_t val) ;
+
+uint8_t load8_ci(uint64_t addr) ;
+uint16_t load16_ci(uint64_t addr) ;
+uint32_t load32_ci(uint64_t addr) ;
+uint64_t load64_ci(uint64_t addr) ;
+
+void store8_ci(uint64_t  addr, uint8_t val) ;
+void store16_ci(uint64_t  addr, uint16_t val) ;
+void store32_ci(uint64_t  addr, uint32_t val) ;
+void store64_ci(uint64_t  addr, uint64_t val) ;
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/include/nvramlog.h b/qemu-0.15.x/roms/SLOF/board-qemu/include/nvramlog.h
new file mode 100644
index 0000000..fef7661
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/include/nvramlog.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef NVRAMLOG_H
+	#define NVRAMLOG_H
+
+/* ----------------------------------------------------------------------------
+ *	NVRAM Log-Partition header design:
+ *
+ *	Partition Header
+ *	00h	- signature	( 1 byte)
+ *	01h	- checksum	( 1 byte)
+ *	02h	- length	( 2 byte) value = 1st_byte*256 + 2nd_byte
+ *	04h	- name		(12 byte)
+ *	space for partiton header = 16 byte
+ *
+ *	Log Header
+ *	10h	- offset	( 2 byte) from Partition Header to Data Section
+ *	12h	- flags		( 2 byte) control flags
+ *	14h	- pointer	( 4 byte) pointer to first free byte in Data Section
+ *					  relative to the beginning of the data section
+ *	18h	- zero		( 32 byte) reserved as stack for four  64 bit register
+ *	38h - reserved		(  8 byte) reserved for 64 bit CRC (not implemented yet)
+ *	space for header = 64 byte
+ *	Data Section
+ *	40h	- cyclic data
+ * -------------------------------------------------------------------------------- */
+
+	// initial values
+	#define LLFW_LOG_BE0_SIGNATURE		0x51			// signature for general firmware usage
+	#define LLFW_LOG_BE0_NAME_PREFIX	0x69626D2C		// first 4 bytes of name: "ibm,"
+	#define LLFW_LOG_BE0_NAME		0x435055306C6F6700	// remaining 8 bytes	: "CPU0log\0"
+	#define LLFW_LOG_BE0_LENGTH		0x2000			// Partition length in block of 16 bytes
+	#define LLFW_LOG_BE0_DATA_OFFSET	0x40			// offset in bytes between header and data
+	#define LLFW_LOG_BE0_FLAGS		0			// unused
+
+	#define LLFW_LOG_BE1_SIGNATURE		0x51			// signature for general firmware usage
+	#define LLFW_LOG_BE1_NAME_PREFIX	0x69626D2C		// first 4 bytes of name: "ibm,"
+	#define LLFW_LOG_BE1_NAME		0x435055316C6F6700	// remaining 8 bytes	: "CPU1log\0\0"
+	#define LLFW_LOG_BE1_LENGTH		0x500			// Partition length in block of 16 bytes
+	#define LLFW_LOG_BE1_DATA_OFFSET	0x40			// offset in bytes between header and data
+	#define LLFW_LOG_BE1_FLAGS		0x0			// unused
+
+	// positions of the initial values
+	#define LLFW_LOG_POS_CHECKSUM	0x01			// 1
+	#define LLFW_LOG_POS_LENGTH	0x02			// 2
+	#define LLFW_LOG_POS_NAME	0x04			// 4
+	#define LLFW_LOG_POS_DATA_OFFSET 0x10			// 16
+	#define LLFW_LOG_POS_FLAGS	0x12			// 18
+	#define LLFW_LOG_POS_POINTER	0x14			// 20
+
+	// NVRAM info
+	#define MAMBO_NVRAM_BASE	0x100000		// NVRAM Base for MAMBO
+	#define NVRAM_EMPTY_PATTERN	0x0000000000000000	// Pattern (64-bit) used to overwrite NVRAM
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/include/product.h b/qemu-0.15.x/roms/SLOF/board-qemu/include/product.h
new file mode 100644
index 0000000..819d6ed
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/include/product.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _PRODUCT_H
+#define _PRODUCT_H
+
+/* This is also the name which is also put in the flash and should
+ * therefore not excedd the length of 32 bytes */
+#define PRODUCT_NAME "QEMU"
+
+/* Generic identifier used in the flash */
+#define FLASHFS_MAGIC "magic123"
+
+/* Magic identifying the platform */
+#define FLASHFS_PLATFORM_MAGIC "qemu0"
+
+/* also used in the flash */
+#define FLASHFS_PLATFORM_REVISION "1"
+
+#define BOOT_MESSAGE  "Press \"s\" to enter Open Firmware.\r\n\r\n\0"
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/include/southbridge.h b/qemu-0.15.x/roms/SLOF/board-qemu/include/southbridge.h
new file mode 100644
index 0000000..3ca4e04
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/include/southbridge.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* Not used */
+#define SB_NVRAM_adr 	0
+#define SB_FLASH_adr 	0
+#define NVRAM_LENGTH	0x10000
+#define FLASH_LENGTH 	0
+#define SB_MAILBOX_adr	0
+
+#define SECONDARY_CPUS_STOPPED
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Cboot.S b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Cboot.S
new file mode 100644
index 0000000..d22f3c9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Cboot.S
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+	.org 0
+
+	/* Boot Information, hardcoded to ColdReset */
+	.quad	1
+	/* start address */
+	.quad	0x100
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Makefile b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Makefile
new file mode 100644
index 0000000..f124a3b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/Makefile
@@ -0,0 +1,56 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../../make.rules
+
+CPPFLAGS	= -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) \
+		  -I$(LIBCMNDIR)/libc/include
+CFLAGS		+= -fno-builtin $(CPPFLAGS) -O2  -msoft-float $(MAMBO)
+CFLAGS		+= $(BOOT) $(IOCONF) -Wa,-mregnames $(RELEASE) $(CPUARCHDEF) -Wall
+ASFLAGS         = $(BOOT) $(IOCONF) $(RELEASE)$(CPUARCHDEF)  -Wa,-mregnames
+LDFLAGS1	= -nostdlib -e__start -Tstage2.lds -N -Ttext=0x100
+
+
+STG1OBJ		 = startup.o boot_abort.o romfs.o io_generic.o board_io.o 
+STG1OBJ		 += stage2_head.o stage2.o comlib.o romfs_wrap.o nvramlog.o
+
+all: stage1.bin Cboot.o
+
+stage1.bin:	$(STG1OBJ) $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a
+		$(LD) $(LDFLAGS1) -o stage1.elf $^
+		$(OBJCOPY) -O binary stage1.elf $@
+
+romfs.o:	../../llfw/romfs.S
+		$(CC) $(CFLAGS) -c ../../llfw/romfs.S
+
+boot_abort.o:	../../llfw/boot_abort.S
+		$(CC) $(CFLAGS) -c ../../llfw/boot_abort.S
+
+nvramlog.o:	../../llfw/nvramlog.S
+		$(CC) $(CFLAGS) -c ../../llfw/nvramlog.S
+
+include $(LLFWCMNDIR)/clib/Makefile.inc
+
+include $(LLFWCMNDIR)/io_generic/Makefile.inc
+
+romfs_wrap.o:	../../llfw/romfs_wrap.c
+		$(CC) $(CFLAGS) -c ../../llfw/romfs_wrap.c
+
+Cboot.o: Cboot.S
+		$(CC) $(CFLAGS) -c $^
+		$(OBJCOPY) -O binary Cboot.o Cboot.bin
+
+%.o: %.S
+		$(CC) $(CFLAGS) -c $^
+
+clean:
+		rm -f *.o *.bin *.elf
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/board_io.S b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/board_io.S
new file mode 100644
index 0000000..7d572ab
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/board_io.S
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <macros.h>
+#include <cpu.h>
+
+	.text
+
+/****************************************************************************
+ * prints one character to serial console
+ *
+ * Input:
+ * R3 - character
+ *
+ * Returns: -
+ *
+ * Modifies Registers:
+ * R3, R4, R5, R6, R7
+ ****************************************************************************/
+ENTRY(io_putchar)
+	sldi	r6,r3,(24+32)
+	li	r3,0x58
+	li	r4,0
+	li	r5,1
+	.long 0x44000022
+	blr
+	
+ENTRY(io_getchar)
+	mr	r10,r3
+	li	r3,0x54
+	li	r4,0
+	.long 0x44000022
+	mr.	r3,r4
+	beq	1f
+	srdi	r3,r5,(24+32)
+	stb	r3,0(r10)
+1:	blr
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.c b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.c
new file mode 100644
index 0000000..59b0296
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.c
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <xvect.h>
+#include <hw.h>
+#include <stdio.h>
+#include <romfs.h>
+#include "memmap.h"
+#include "stage2.h"
+#include <termctrl.h>
+#include "product.h"
+#include "calculatecrc.h"
+#include <cpu.h>
+#include <libelf.h>
+#include <string.h>
+
+#define DEBUG(fmt...)
+//#define DEBUG(fmt...) printf(fmt)
+
+uint64_t gVecNum;
+
+uint64_t exception_stack_frame;
+
+typedef void (*pInterruptFunc_t) (void);
+
+pInterruptFunc_t vectorTable[0x2E << 1];
+
+void c_memInit(uint64_t r3, uint64_t r4);
+
+void proceedInterrupt();
+
+void exception_forward(void)
+{
+	uint64_t val;
+
+	if (*(uint64_t *) XVECT_M_HANDLER) {
+		proceedInterrupt();
+	}
+
+	printf("\r\n exception %llx ", gVecNum);
+	asm volatile ("mfsrr0	%0":"=r" (val):);
+	printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val);
+	asm volatile ("mfsrr1	%0":"=r" (val):);
+	printf(" SRR1 = %08llx%08llx ", val >> 32, val);
+
+	asm volatile ("mfsprg	%0,2":"=r" (val):);
+	printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val);
+	asm volatile ("mfsprg	%0,3":"=r" (val):);
+	printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val);
+	while (1);
+}
+
+void c_interrupt(uint64_t vecNum)
+{
+	gVecNum = vecNum;
+	if (vectorTable[vecNum >> 7]) {
+		vectorTable[vecNum >> 7] ();
+	} else {
+		exception_forward();
+	}
+}
+
+void set_exceptionVector(int num, void *func)
+{
+	vectorTable[num >> 7] = (pInterruptFunc_t) func;
+}
+
+uint64_t get_dec(void)
+{
+	return 0xdeadaffe;
+}
+
+void set_dec(uint64_t val)
+{
+}
+
+uint64_t tb_frequency(void)
+{
+	return 0;
+}
+
+static void load_file(uint64_t destAddr, char *name, uint64_t maxSize,
+		      uint64_t romfs_base)
+{
+	uint64_t *src, *dest, cnt;
+	struct romfs_lookup_t fileInfo;
+	int rc;
+
+	rc = c_romfs_lookup(name, romfs_base, &fileInfo);
+	if (rc) {
+		printf("Cannot find romfs file %s\n", name);
+		return;
+	}
+	DEBUG("Found romfs file %s\n", name);
+	if (maxSize) {
+		cnt = maxSize;
+	} else {
+		cnt = fileInfo.size_data;
+	}
+	memcpy((void *)destAddr, (void *)fileInfo.addr_data, cnt);
+	dest = (uint64_t *) destAddr;
+	src = (uint64_t *) fileInfo.addr_data;
+	flush_cache((void *) destAddr, fileInfo.size_data);
+}
+
+/***************************************************************************
+ * Function: early_c_entry
+ * Input   : start_addr
+ *
+ * Description:
+ **************************************************************************/
+void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
+{
+	struct romfs_lookup_t fileInfo;
+	void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
+	uint64_t *boot_info;
+	uint64_t romfs_base;
+	// romfs header values
+	struct stH *header = (struct stH *) (start_addr + 0x28);
+	uint64_t flashlen = 0;
+	unsigned long ofw_addr[2];
+	int rc;
+
+	flashlen = header->flashlen;
+
+	romfs_base = 0x10000000 - 0x400000;
+	if (romfs_base)
+		memcpy((char *)romfs_base, 0, 0x400000);
+
+	exception_stack_frame = 0;
+
+	printf(" Press \"s\" to enter Open Firmware.\r\n\r\n");
+
+	DEBUG("  [c_romfs_lookup at %p]\n", c_romfs_lookup);
+	rc = c_romfs_lookup("bootinfo", romfs_base, &fileInfo);
+	if (rc)
+		printf("  !!! roomfs lookup(bootinfo) = %d\n", rc);
+	boot_info = (uint64_t *) fileInfo.addr_data;
+	boot_info[1] = start_addr;
+	load_file(0x100, "xvect", 0, romfs_base);
+	rc = c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
+	if (rc)
+		printf("  !!! roomfs lookup(bootinfo) = %d\n", rc);
+
+	DEBUG("  [ofw_main addr hdr  0x%lx]\n", fileInfo.addr_header);
+	DEBUG("  [ofw_main addr data 0x%lx]\n", fileInfo.addr_data);
+	DEBUG("  [ofw_main size data 0x%lx]\n", fileInfo.size_data);
+	DEBUG("  [ofw_main flags     0x%lx]\n", fileInfo.flags);
+	DEBUG("  [hdr: 0x%08lx 0x%08lx]\n  [     0x%08lx 0x%08lx]\n",
+	       ((uint64_t *)fileInfo.addr_header)[0],	
+	       ((uint64_t *)fileInfo.addr_header)[1],
+	       ((uint64_t *)fileInfo.addr_header)[2],
+	       ((uint64_t *)fileInfo.addr_header)[3]);
+	rc = load_elf_file((void *)fileInfo.addr_data, ofw_addr);
+	DEBUG("  [load_elf_file returned %d]\n", rc);
+	ofw_start =
+	    (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
+	    &ofw_addr;
+	// re-enable the cursor
+	printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON);
+	DEBUG("  [ofw_start=%p ofw_addr=0x%lx]\n", ofw_start, ofw_addr[0]);
+	ofw_addr[1] = ofw_addr[0];
+	/* ePAPR 0.5
+	 * r3 = R3 Effective address of the device tree image. Note: this
+	 *      address must be 8-byte aligned in memory.
+	 * r4 = implementation dependent
+	 * r5 = 0
+	 * r6 = 0x65504150 -- ePAPR magic value-to distinguish from
+	 *      non-ePAPR-compliant firmware
+	 * r7 = implementation dependent
+	 */
+	asm volatile("isync; sync;" : : : "memory");
+	ofw_start(fdt_addr, romfs_base, 0, 0, 0);
+	asm volatile("isync; sync;" : : : "memory");
+	// never return
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.h b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.h
new file mode 100644
index 0000000..9ce3c82
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __STAGE2_H
+#define __STAGE2_H
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+
+void u4memInit(void);
+
+#endif		/* __ASSEMBLER__ */
+#endif		/* __STAGE2_H */
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.lds b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.lds
new file mode 100644
index 0000000..4012ea5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2.lds
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+
+/* set the entry point */
+ENTRY ( __start )
+
+SECTIONS {
+	.text : {
+		*(.text)
+	}
+
+	. = ALIGN(8);
+
+	.data : {
+		*(.data)
+		*(.rodata .rodata.*)
+		*(.got1)
+		*(.sdata)
+		*(.opd)
+	}
+
+	/* FIXME bss at end ??? */
+
+	. = ALIGN(8);
+	__bss_start = .;
+	.bss : {
+		*(.sbss) *(.scommon)
+		*(.dynbss)
+		*(.bss)
+	}
+
+	. = ALIGN(8);
+	__bss_end = .;
+	__bss_size = (__bss_end - __bss_start);
+
+	__toc_start = .;
+	.got :
+	{
+		 *(.toc .got)
+	}
+	. = ALIGN(8);
+	__toc_end = .;
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2_head.S b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2_head.S
new file mode 100644
index 0000000..c56b117
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/stage2_head.S
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "macros.h"
+#include "../../llfw/boot_abort.h"
+
+/*#################### defines #####################*/
+#define STACK_SIZE   0x4000
+
+/*#################### code ########################*/
+	.text
+	.globl .gluon_c_entry
+	.globl __toc_start
+	.globl __toc_end
+	.globl __bss_start
+	.globl __bss_size
+	.globl __start
+
+ASM_ENTRY(__startC)
+	/* clear out bss section                */
+	LOAD64(r3, (__bss_start - 8))
+	LOAD64(r4, __bss_size)
+
+	/* divide __bss_size by 8 to get number */
+	/* of dwords to clear                   */
+	srwi.	r4, r4, 3
+	beq	bsscdone
+	li	r5, 0
+	mtctr	r4
+bssc:	stdu	r5, 8(r3)
+	bdnz	bssc
+bsscdone:
+	/* setup stack                          */
+	LOAD64(r1, __stack_end + STACK_SIZE)
+
+	/* save return address beside stack     */
+	addi	r3, r1, 128
+	mflr	r0
+	std	r0, 0(r3)
+
+	/* setup toc                            */
+	bl	toc_init
+
+	/* ------------------------------------ */
+	/* jump to c-code                       */
+	/* r31 = fdt                    - r5    */
+	/* ------------------------------------ */
+	li	r3, r0
+	mr	r4, r31
+	bl	.early_c_entry
+
+	/* return to caller...                  */
+	LOAD64(r1, __stack_end + STACK_SIZE)
+	addi	r1, r1, 128
+	ld	r3, 0(r1)
+	mtlr	r3
+	blr
+
+	/* #################################### */
+	/* Basic Additional Functions           */
+	/* for extended lib functions see       */
+	/* external library                     */
+	/* #################################### */
+	.align 	2
+
+	/* ------------------------------------ */
+	/* updates toc in r2                    */
+	/* ------------------------------------ */
+ASM_ENTRY(toc_init)
+	LOAD64(r2, __toc_start)
+	addi	r2,r2,0x4000
+	addi	r2,r2,0x4000
+	blr
+
+	/* ------------------------------------ */
+	/* stores arg#1 in r27 and stops        */
+	/* ------------------------------------ */
+ENTRY(do_panic)
+ENTRY(halt_sys)
+	BOOT_ABORT_R3HINT(ABORT_CANIO, ALTBOOT, msg_e_ierror);
+
+	.section ".bss"
+	.balign STACK_SIZE
+__stack_end:
+	.space STACK_SIZE
+	.text
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/llfw/startup.S b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/startup.S
new file mode 100644
index 0000000..5882164
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/llfw/startup.S
@@ -0,0 +1,258 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* SLOF for QEMU -- boot code.
+ * Initial entry point
+ */
+
+#include "termctrl.h"
+#include <product.h>
+#include <xvect.h>
+#include <cpu.h>
+#include <macros.h>
+
+	/* qemu entry:
+	 *
+	 * __start loaded at 0x100
+	 *
+	 * CPU 0 starts at 0 with GPR3 pointing to the flat devtree
+	 *
+	 * All other CPUs are held in stopped state by qemu and are
+	 * started via RTAS
+	 */
+	.text
+	.globl __start
+__start:
+	b	_start
+	.long 0xDEADBEE0
+	.long 0x0       /* size */ 
+	.long 0x0       /* crc  */
+	.long relTag - __start
+
+	/* Some exception vectors
+	 *	
+	 * FIXME: Also need 0280, 0380, 0f20, etc.
+	 */
+
+	.irp i, 0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x0400,0x0500, \
+	        0x0600,0x0700,0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00, \
+	        0x0e00,0x0f00,0x1000,0x1100,0x1200,0x1300,0x1400,0x1500, \
+	        0x1600,0x1700, \
+		0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+		0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+		0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00
+	. = \i
+
+	/* enable this if you get exceptions before the console works    */
+	/* this will allow using the hardware debugger to see where      */
+	/* it traps, and with what register values etc.                  */
+	// b	$
+
+	mtsprg	0,r0
+	mfctr	r0
+	mtsprg  2,r0
+	mflr	r0
+// 10
+	mtsprg  3,r0
+	ld	r0, (\i + 0x160)(0)
+	mtctr	r0
+	li	r0, \i + 0x100
+// 20
+	bctr
+
+	. = \i + 0x60
+	.quad	intHandler2C
+	.endr
+
+	. = XVECT_M_HANDLER - 0x100
+	.quad	0x00
+	.text
+
+	/* Here's the startup code for the master CPU */
+	.org 0x4000 - 0x100
+_start:
+	/* Save device-tree pointer */
+	mr	r31,r3
+
+	/* Switch to 64-bit mode with 64-bit exceptions */
+#define MSR_SF_LG	63              /* Enable 64 bit mode */
+#define MSR_ISF_LG	61              /* Interrupt 64b mode valid on 630 */
+#define __MASK(X)	(1<<(X))
+#define MSR_SF		__MASK(MSR_SF_LG)	/* Enable 64 bit mode */
+#define MSR_ISF		__MASK(MSR_ISF_LG)	/* Interrupt 64b mode */
+	mfmsr	r11			/* grab the current MSR */
+	li	r12,(MSR_SF | MSR_ISF)@highest
+	sldi	r12,r12,48
+	or	r11,r11,r12
+	mtmsrd	r11
+	isync
+
+	/* Early greet */
+	li	r3,10
+	bl	putc
+	li	r3,13
+	bl	putc
+	li	r3,10
+	bl	putc
+	li	r3,'S'
+	bl	putc
+
+	li	r3,'L'
+	bl	putc
+	li	r3,'O'
+	bl	putc
+	li	r3,'F'
+	bl	putc
+
+	/* give live sign *****************************/
+	bl	0f
+	.ascii	TERM_CTRL_RESET
+	.ascii	TERM_CTRL_CRSOFF
+	.ascii  " **********************************************************************"
+	.ascii	"\r\n"
+	.ascii	TERM_CTRL_BRIGHT
+	.ascii	PRODUCT_NAME
+	.ascii  " Starting\r\n"
+	.ascii  TERM_CTRL_RESET
+	.ascii  " Build Date = ", __DATE__, " ", __TIME__
+	.ascii	"\r\n"
+	.ascii  " FW Version = " , RELEASE
+	.ascii	"\r\n\0"
+	.align	2
+0:	mflr	r3
+	bl	io_print
+
+	/* go! */
+	li	r3,__startC at l
+	mtctr	r3
+	bctrl
+	
+	/* write a character to the HV console */
+putc:	sldi	r6,r3,(24+32)
+	li	r3,0x58
+	li	r4,0
+	li	r5,1
+	.long	0x44000022
+	blr
+
+relTag:
+	.ascii  RELEASE
+	.ascii	"\0"
+	.align	2
+
+C_ENTRY(proceedInterrupt)
+
+	ld      r3,exception_stack_frame at got(r2)
+	ld	r1,0(r3)
+
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	ld	r14,0x138(r1);
+	mtsrr0	r14
+
+	ld	r14,0x140(r1);
+	mtsrr1	r14
+
+	ld	r14,0x148(r1);
+	mtcr	r14
+
+	ld	0,XVECT_M_HANDLER(0)
+	mtctr	0
+
+	ld	r0,0x30(r1); # restore vector number
+	ld	r1,0x38(r1);
+
+	bctr
+
+intHandler2C:
+	mtctr	r1 # save old stack pointer
+	lis	r1,0x4
+	stdu	r1, -0x160(r1)
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	std	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	std	r0,0x30(r1);  # save vector number
+
+	mfctr	r14
+	std	r14,0x38(r1); # save old r1
+
+	mfsrr0	r14
+	std	r14,0x138(r1);
+
+	mfsrr1	r14
+	std	r14,0x140(r1);
+
+	mfcr	r14
+	std	r14,0x148(r1);
+
+	mfxer	r14
+	std	r14,0x150(r1);
+
+	bl	toc_init
+
+	ld      r3,exception_stack_frame at got(r2)
+	std     r1,0(r3)
+
+
+	mr 	r3,r0
+	bl	.c_interrupt
+
+	ld	r14,0x138(r1);
+	mtsrr0	r14
+
+	ld	r14,0x140(r1);
+	mtsrr1	r14
+
+	ld	r14,0x148(r1);
+	mtcr	r14
+
+	ld	r14,0x150(r1);
+	mtxer	r14
+
+
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+
+	ld	r1,0x38(r1);
+
+	mfsprg	r0,2
+	mtctr	r0
+	mfsprg	r0,3
+	mtlr	r0
+	mfsprg	r0,0
+	rfid
+
+/* Set exception handler for given exception vector.  
+	r3:	exception vector offset
+	r4:	exception handler
+*/
+	.globl .set_exception
+.set_exception:
+	.globl set_exception
+set_exception:
+	ld r4,0x0(r4)
+	.globl .set_exception_asm
+.set_exception_asm:
+	.globl set_exception_asm
+set_exception_asm:
+	std	r4, 0x60(r3)	# fixme diff 1f - 0b
+	blr
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/romfs/boot_rom.ffs b/qemu-0.15.x/roms/SLOF/board-qemu/romfs/boot_rom.ffs
new file mode 100644
index 0000000..385a08d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/romfs/boot_rom.ffs
@@ -0,0 +1,21 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+# FFile-Name	Real Filename			Flags			ROM-Offset i/a
+#--------------|-------------------------------|-----------------------|--------------
+header		romfs/header.img		0			0
+stage1		board-qemu/llfw/stage1.bin	1			0x100
+xvect		slof/xvect.bin			0			0
+ofw_main	board-qemu/slof/paflof		0			0
+bootinfo	board-qemu/llfw/Cboot.bin	0			0
+snk		clients/net-snk.client		0			0
+net_veth	board-qemu/veth/net_veth.bin	0			0
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/Makefile b/qemu-0.15.x/roms/SLOF/board-qemu/slof/Makefile
new file mode 100644
index 0000000..842767f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/Makefile
@@ -0,0 +1,96 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+include ../Makefile.dirs
+
+include $(TOPBRDDIR)/config
+include $(TOPCMNDIR)/make.rules
+
+
+all: Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin
+
+CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \
+	 -I$(LIBCMNDIR)/libnvram
+SLOF_LIBS = $(LIBCMNDIR)/libbootmsg.a $(LIBCMNDIR)/libhvcall.a \
+	$(LIBCMNDIR)/libnvram.a
+BOARD_SLOF_IN = \
+	$(LIBCMNDIR)/libhvcall/hvcall.in \
+	$(LIBCMNDIR)/libbootmsg/bootmsg.in \
+	$(LIBCMNDIR)/libnvram/libnvram.in \
+	$(LIBCMNDIR)/libbases/libbases.in
+BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)
+
+include $(SLOFCMNDIR)/Makefile.inc
+
+FPPINCLUDES = -I. -I$(SLOFCMNDIR)/fs -I$(SLOFCMNDIR)
+
+# FCode Evaluator files for the ROM fs:
+FCODE_FFS_FILES = \
+	$(SLOFCMNDIR)/fs/fcode/core.fs \
+	$(SLOFCMNDIR)/fs/fcode/evaluator.fs \
+	$(SLOFCMNDIR)/fs/fcode/big.fs \
+	$(SLOFCMNDIR)/fs/fcode/tokens.fs \
+	$(SLOFCMNDIR)/fs/fcode/1275.fs
+
+
+USB_FFS_FILES = \
+	$(SLOFCMNDIR)/fs/devices/pci-class_0c.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-ohci.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-hub.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-enumerate.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-storage-wrapper.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-keyboard.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-kbd-device-support.fs \
+	$(SLOFCMNDIR)/fs/usb/usb-mouse.fs \
+	$(SLOFCMNDIR)/fs/scsi-support.fs
+
+VIO_FFS_FILES = \
+	$(SLOFBRDDIR)/vio-hvterm.fs \
+	$(SLOFBRDDIR)/vio-vscsi.fs \
+	$(SLOFBRDDIR)/vio-vscsi-device.fs \
+	$(SLOFBRDDIR)/vio-veth.fs
+
+# Files that should go into the ROM fs (and so have to be listed in OF.ffs):
+OF_FFS_FILES = \
+	$(SLOFCMNDIR)/fs/ide.fs \
+	$(SLOFCMNDIR)/fs/fbuffer.fs \
+	$(SLOFCMNDIR)/fs/generic-disk.fs \
+	$(SLOFCMNDIR)/fs/pci-device.fs \
+	$(SLOFCMNDIR)/fs/pci-bridge.fs \
+	$(SLOFCMNDIR)/fs/pci-properties.fs \
+	$(SLOFCMNDIR)/fs/pci-config-bridge.fs \
+	$(SLOFCMNDIR)/fs/update_flash.fs \
+	$(SLOFCMNDIR)/fs/xmodem.fs \
+	$(SLOFBRDDIR)/default-font.bin \
+	$(FCODE_FFS_FILES)
+
+# Uncomment the following line to enable the USB code:
+OF_FFS_FILES += $(USB_FFS_FILES) $(VIO_FFS_FILES)
+
+OF_FFS_FILES := $(OF_FFS_FILES:%.fs=%.fsi)
+
+OF.ffs: Makefile $(SLOFCMNDIR)/Makefile.inc $(OF_FFS_FILES)
+	$(MAKE) create_OF_ffs
+
+# Rules for cleaning up:
+.PHONY: clean_here clean distclean
+
+clean_here:
+	rm -f *.o OF.fsi OF.ffs
+
+clean: clean_here clean_slof
+
+distclean: clean_here distclean_slof
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/OF.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/OF.fs
new file mode 100644
index 0000000..ede41e7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/OF.fs
@@ -0,0 +1,160 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ The master file.  Everything else is included into here.
+
+hex
+
+' ll-cr to cr
+
+#include "header.fs"
+
+#include "hvterm.fs"
+
+#include "base.fs"
+
+\ Little-endian accesses.  Also known as `wrong-endian'.
+#include <little-endian.fs>
+
+: #join  ( lo hi #bits -- x )  lshift or ;
+: #split ( x #bits -- lo hi )  2dup rshift dup >r swap lshift xor r> ;
+
+: blink ;
+: reset-dual-emit ;
+: console-clean-fifo ;
+: bootmsg-nvupdate ;
+: asm-cout 2drop drop ;
+
+#include "logging.fs"
+
+: log-string 2drop ;
+
+#include "bootmsg.fs"
+
+000 cp
+
+#include "exception.fs"
+
+: mm-log-warning 2drop ;
+
+: write-mm-log ( data length type -- status )
+	3drop 0
+;
+
+080 cp
+
+100 cp
+
+\ Input line editing.
+#include "accept.fs"
+
+120 cp
+
+#include "dump.fs"
+
+cistack ciregs >r1 ! \ kernel wants a stack :-)
+
+#include "romfs.fs"
+
+140 cp
+
+200 cp
+
+201 cp
+#include <slof-logo.fs>
+#include <banner.fs>
+
+: .banner .slof-logo .banner ;
+
+220 cp
+
+DEFER find-boot-sector ( -- )
+
+240 cp
+\ Timebase frequency, in Hz. Start with a good default
+\ Use device-tree later to fix it up
+d# 512000000 VALUE tb-frequency   \ default value - needed for "ms" to work
+-1 VALUE cpu-frequency
+
+#include "helper.fs"
+260 cp
+
+#include <timebase.fs>
+
+280 cp
+
+2c0 cp
+
+2e0 cp
+
+#include <quiesce.fs>
+
+300 cp
+
+#include <usb/usb-static.fs>
+
+320 cp
+
+#include <scsi-loader.fs>
+
+340 cp
+
+360 cp
+
+#include "fdt.fs"
+
+370 cp
+
+#include "tree.fs"
+
+800 cp
+
+#include "nvram.fs"
+
+880 cp
+
+#include "envvar.fs"
+check-for-nvramrc
+
+890 cp
+
+#include "qemu-bootlist.fs"
+
+8a0 cp
+
+\ The client interface.
+#include "client.fs"
+\ ELF binary file format.
+#include "elf.fs"
+#include <loaders.fs>
+
+8b0 cp
+
+8e0 cp
+
+8ff cp
+
+#include <start-up.fs>
+
+."      "   \ Clear last checkpoint
+
+#include <boot.fs>
+
+cr .(   Welcome to Open Firmware)
+cr
+#include "copyright-oss.fs"
+cr cr
+
+\ this CATCH is to ensure the code bellow always executes:  boot may ABORT!
+' start-it CATCH drop
+
+cr ." Ready!"
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/copyright-oss.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/copyright-oss.fs
new file mode 100644
index 0000000..e45b194
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/copyright-oss.fs
@@ -0,0 +1,16 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+cr .(   Copyright (c) char ) emit .(  2004, 2011 IBM Corporation All rights reserved.)
+cr .(   This program and the accompanying materials are made available)
+cr .(   under the terms of the BSD License available at)
+cr .(   http://www.opensource.org/licenses/bsd-license.php)
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/fdt.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/fdt.fs
new file mode 100644
index 0000000..43b97fe
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/fdt.fs
@@ -0,0 +1,251 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 VALUE fdt-debug
+
+\ Bail out if no fdt
+fdt-start 0 = IF -1 throw THEN
+
+struct
+  4 field >fdth_magic
+  4 field >fdth_tsize
+  4 field >fdth_struct_off
+  4 field >fdth_string_off
+  4 field >fdth_rsvmap_off
+  4 field >fdth_version
+  4 field >fdth_compat_vers
+  4 field >fdth_boot_cpu
+  4 field >fdth_string_size
+  4 field >fdth_struct_size
+drop
+
+h# d00dfeed constant OF_DT_HEADER
+h#        1 constant OF_DT_BEGIN_NODE
+h#        2 constant OF_DT_END_NODE
+h#        3 constant OF_DT_PROP
+h#        4 constant OF_DT_NOP
+h#        9 constant OF_DT_END
+
+\ Create some variables early
+fdt-start
+dup dup >fdth_struct_off l@ + value fdt-struct
+dup dup >fdth_string_off l@ + value fdt-strings
+drop
+
+\ Dump fdt header for all to see and check FDT validity
+: fdt-check-header ( -- )
+    fdt-start dup 0 = IF
+        ." No flat device tree !" cr drop -1 throw EXIT THEN
+    hex
+    fdt-debug IF
+        ." Flat device tree header at 0x" dup . s" :" type cr
+        ."  magic            : 0x" dup >fdth_magic l@ . cr
+        ."  total size       : 0x" dup >fdth_tsize l@ . cr
+        ."  offset to struct : 0x" dup >fdth_struct_off l@ . cr
+        ."  offset to strings: 0x" dup >fdth_string_off l@ . cr
+        ."  offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr
+        ."  version          : " dup >fdth_version l@ decimal . hex cr
+        ."  last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr
+        dup >fdth_version l@ 2 >= IF
+            ."  boot CPU         : 0x" dup >fdth_boot_cpu l@ . cr
+        THEN
+        dup >fdth_version l@ 3 >= IF
+            ."  strings size     : 0x" dup >fdth_string_size l@ . cr
+        THEN
+        dup >fdth_version l@ 17 >= IF
+            ."  struct size      : 0x" dup >fdth_struct_size l@ . cr
+        THEN
+    THEN
+    dup >fdth_magic l@ OF_DT_HEADER <> IF
+        ." Flat device tree has incorrect magic value !" cr
+	drop -1 throw EXIT
+    THEN
+    dup >fdth_version l@ 10 < IF
+        ." Flat device tree has usupported version !" cr
+	drop -1 throw EXIT
+    THEN
+
+    drop
+;
+fdt-check-header
+
+\ Fetch next tag, skip nops and increment address
+: fdt-next-tag ( addr -- nextaddr tag )
+  0	       	      	 	( dummy tag on stack for loop )
+  BEGIN
+    drop			( drop previous tag )
+    dup l@			( read new tag )
+    swap 4 + swap		( increment addr )
+  dup OF_DT_NOP <> UNTIL 	( loop until not nop )
+;
+
+\ Parse unit name and advance addr
+: fdt-fetch-unit ( addr -- addr $name )
+  dup from-cstring	       \  get string size
+  2dup + 1 + 3 + fffffffc and -rot
+;
+
+\ Lookup a string by index
+: fdt-fetch-string ( index -- $string)  
+  fdt-strings + dup from-cstring
+;
+
+: fdt-create-dec  s" decode-unit" $CREATE , DOES> @ hex-decode-unit ;
+: fdt-create-enc  s" encode-unit" $CREATE , DOES> @ hex-encode-unit ;
+
+\ Method to unflatten a node
+: fdt-unflatten-node ( start -- end )
+  \ this can and will recurse
+  recursive
+
+  \ Get & check first tag of node ( addr -- addr)
+  fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
+    s" Weird tag 0x" type . " at start of node" type cr
+    -1 throw
+  THEN drop
+
+  new-device
+
+  \ Parse name, split unit address
+  fdt-fetch-unit
+  dup 0 = IF drop drop " /" THEN
+  40 left-parse-string
+  \ Set name
+  device-name
+
+  \ Set unit address
+  dup IF
+     " #address-cells" get-parent get-package-property IF
+        2drop
+     ELSE
+        decode-int nip nip
+	hex-decode-unit
+	set-unit
+     THEN
+  ELSE 2drop THEN
+
+  \ Iterate sub tags
+  BEGIN
+    fdt-next-tag dup OF_DT_END_NODE <>
+  WHILE
+    dup OF_DT_PROP = IF
+      \ Found property
+      drop dup			( drop tag, dup addr     : a1 a1 )
+      dup l@ dup rot 4 +	( fetch size, stack is   : a1 s s a2)
+      dup l@ swap 4 +		( fetch nameid, stack is : a1 s s i a3 )
+      rot                       ( we now have: a1 s i a3 s )
+      encode-bytes rot		( a1 s pa ps i)
+      fdt-fetch-string		( a1 s pa ps $pn )
+      property
+      + 8 + 3 + fffffffc and
+    ELSE dup OF_DT_BEGIN_NODE = IF
+      drop			( drop tag )
+      4 -
+      fdt-unflatten-node
+    ELSE
+      drop -1 throw
+    THEN THEN
+  REPEAT drop \ drop tag
+
+  \ Create encode/decode unit
+  " #address-cells" get-node get-package-property IF ELSE
+    decode-int dup fdt-create-dec fdt-create-enc 2drop
+  THEN
+
+  finish-device  
+;
+
+\ Start unflattening
+: fdt-unflatten-tree
+    fdt-debug IF
+        ." Unflattening device tree..." cr THEN
+    fdt-struct fdt-unflatten-node drop
+    fdt-debug IF
+        ." Done !" cr THEN
+;
+fdt-unflatten-tree
+
+\ Find memory size
+: fdt-parse-memory
+    " /memory" find-device
+    " reg" get-node get-package-property IF throw -1 THEN
+
+    \ XXX FIXME Assume one entry only in "reg" property for now
+    decode-phys 2drop decode-phys
+    my-#address-cells 1 > IF 20 << or THEN
+    
+    fdt-debug IF
+        dup ." Memory size: " . cr
+    THEN
+    MIN-RAM-SIZE swap release
+    2drop device-end
+;
+fdt-parse-memory
+
+
+\ Claim fdt memory and reserve map
+: fdt-claim-reserve
+    fdt-start
+    dup dup >fdth_tsize l@ 0 claim drop
+    dup >fdth_rsvmap_off l@ +
+    BEGIN
+        dup dup x@ swap 8 + x@
+	dup 0 <>
+    WHILE
+	fdt-debug IF
+	    2dup swap ." Reserve map entry: " . ." : " . cr
+	THEN
+	0 claim drop
+	10 +
+    REPEAT drop drop drop
+;
+fdt-claim-reserve 
+
+\ Remaining bits from root.fs
+
+defer (client-exec)
+defer client-exec
+
+\ defined in slof/fs/client.fs
+defer callback
+defer continue-client
+
+: set-chosen ( prop len name len -- )
+  s" /chosen" find-node set-property ;
+
+: get-chosen ( name len -- [ prop len ] success )
+  s" /chosen" find-node get-property 0= ;
+
+" /" find-device
+
+new-device
+  s" aliases" device-name
+finish-device
+
+new-device
+  s" options" device-name
+finish-device
+
+new-device
+  s" openprom" device-name
+  s" BootROM" device-type
+finish-device
+
+new-device 
+#include <packages.fs>
+finish-device
+
+: open true ;
+: close ;
+
+device-end
+
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/header.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/header.fs
new file mode 100644
index 0000000..0519cc9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/header.fs
@@ -0,0 +1,22 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ XXXFIXME: Old Bimini/JX2x crap to remove
+
+get-flash-base VALUE flash-addr
+
+get-nvram-base CONSTANT nvram-base
+get-nvram-size CONSTANT nvram-size
+ff8f9000 CONSTANT sec-nvram-base  \ save area from phype.... not really known
+2000 CONSTANT sec-nvram-size
+
+nvram-base 20000 + CONSTANT nvram-log-be1-base
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/helper.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/helper.fs
new file mode 100644
index 0000000..96da498
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/helper.fs
@@ -0,0 +1,35 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: slof-build-id  ( -- str len )
+   flash-header 10 + a
+;
+
+: slof-revision s" 001" ;
+
+: read-version-and-date
+   flash-header 0= IF
+   s"  " encode-string
+   ELSE
+   flash-header 10 + 10
+   here swap rmove
+   here 10
+   s" , " $cat
+   bdate2human $cat encode-string THEN
+;
+
+\ Fetch C string
+: from-cstring ( addr - len )  
+  dup dup BEGIN c@ 0 <> WHILE 1 + dup REPEAT
+  swap -
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/hvterm.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/hvterm.fs
new file mode 100644
index 0000000..2827e25
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/hvterm.fs
@@ -0,0 +1,26 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ PAPR hvterm console.  Enabled very early.
+
+: hvterm-emit  hv-putchar ;
+: hvterm-key?  hv-haschar ;
+: hvterm-key   BEGIN hvterm-key? UNTIL hv-getchar ;
+
+' hvterm-emit to emit
+' hvterm-key  to key
+' hvterm-key? to key?
+
+\ Override serial methods to make term-io.fs happy
+: serial-emit hvterm-emit ;
+: serial-key? hvterm-key? ;
+: serial-key  hvterm-key  ;
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/qemu-bootlist.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/qemu-bootlist.fs
new file mode 100644
index 0000000..6b52b97
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/qemu-bootlist.fs
@@ -0,0 +1,38 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+defer set-boot-device
+defer add-boot-device
+
+: qemu-read-bootlist ( -- )
+   0 0 set-boot-device
+
+   \ check nvram
+   " boot-device" evaluate swap drop 0 <> IF EXIT THEN   
+
+   \ check qemu boot list
+   " qemu,boot-device" get-chosen not IF EXIT THEN
+   
+   0 ?DO
+       dup i + c@ CASE
+           0        OF ENDOF
+           [char] a OF ENDOF
+           [char] b OF ENDOF
+           [char] c OF " disk"  add-boot-device ENDOF
+           [char] d OF " cdrom" add-boot-device ENDOF
+           [char] n OF " net"   add-boot-device ENDOF
+       ENDCASE cr
+   LOOP
+   drop
+;
+
+' qemu-read-bootlist to read-bootlist
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/rtas.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/rtas.fs
new file mode 100644
index 0000000..d8a6c58
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/rtas.fs
@@ -0,0 +1,126 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ KVM/qemu RTAS
+
+\ rtas control block
+
+4d0 cp
+
+STRUCT
+    /l field rtas>token
+    /l field rtas>nargs
+    /l field rtas>nret
+    /l field rtas>args0
+    /l field rtas>args1
+    /l field rtas>args2
+    /l field rtas>args3
+    /l field rtas>args4
+    /l field rtas>args5
+    /l field rtas>args6
+    /l field rtas>args7
+    /l C * field rtas>args
+    /l field rtas>bla
+CONSTANT /rtas-control-block
+
+CREATE rtas-cb /rtas-control-block allot
+rtas-cb /rtas-control-block erase
+
+0 VALUE rtas-base
+0 VALUE rtas-size
+0 VALUE rtas-entry
+0 VALUE rtas-node
+
+\ Locate qemu RTAS, remove the linux,... properties we really don't
+\ want them to stick around
+
+4d1 cp
+
+: find-qemu-rtas ( -- )
+    " /rtas" find-device get-node to rtas-node
+
+    " linux,rtas-base" rtas-node get-package-property IF
+         device-end EXIT THEN
+    drop l@ to rtas-base
+    " linux,rtas-base" delete-property
+
+    " rtas-size" rtas-node get-package-property IF
+         device-end EXIT THEN
+    drop l@ to rtas-size
+
+    " linux,rtas-entry" rtas-node get-package-property IF
+        rtas-base to rtas-entry
+    ELSE
+        drop l@ to rtas-entry
+        " linux,rtas-entry" delete-property
+    THEN
+
+    \ ." RTAS found, base=" rtas-base . ."  size=" rtas-size . cr
+
+    device-end
+;
+find-qemu-rtas
+
+4d2 cp
+
+: enter-rtas ( -- )
+    rtas-cb rtas-base 0 rtas-entry call-c drop
+;
+
+: rtas-get-token ( str len -- token | 0 )
+    rtas-node get-package-property IF 0 ELSE drop l@ THEN
+;
+
+: rtas-start-cpu  ( pid loc r3 -- status )
+   " start-cpu" rtas-get-token rtas-cb rtas>token l!
+   3  rtas-cb rtas>nargs l!
+   1  rtas-cb rtas>nret l!
+   rtas-cb rtas>args2 l!
+   rtas-cb rtas>args1 l!
+   rtas-cb rtas>args0 l!
+   0 rtas-cb rtas>args3 l!
+   enter-rtas
+   rtas-cb rtas>args3 l@
+;
+
+: rtas-set-tce-bypass ( unit enable -- )
+    " ibm,set-tce-bypass" rtas-get-token rtas-cb rtas>token l!
+    2 rtas-cb rtas>nargs l!
+    0 rtas-cb rtas>nret l!
+    rtas-cb rtas>args1 l!
+    rtas-cb rtas>args0 l!
+    enter-rtas
+;
+
+: rtas-quiesce ( -- )
+    " quiesce" rtas-get-token rtas-cb rtas>token l!
+    0 rtas-cb rtas>nargs l!
+    0 rtas-cb rtas>nret l!
+    enter-rtas
+;
+
+: of-start-cpu rtas-start-cpu ;
+
+\ Methods of the rtas node proper
+rtas-node set-node
+
+: open true ;
+: close ;
+
+: instantiate-rtas ( adr -- entry )
+    dup rtas-base swap rtas-size move
+    rtas-entry rtas-base - +
+;
+
+device-end
+
+4d8 cp
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/tree.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/tree.fs
new file mode 100644
index 0000000..c2ab824
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/tree.fs
@@ -0,0 +1,150 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: strequal ( str1 len1 str2 len2 -- flag )
+  rot dup rot = IF comp 0= ELSE 2drop drop 0 THEN ; 
+
+400 cp
+
+0 value puid
+
+440 cp
+
+480 cp
+
+\ The root of the device tree and some of its kids.
+" /" find-device
+
+" QEMU" encode-string s" model" property
+
+2 encode-int s" #address-cells" property
+2 encode-int s" #size-cells" property
+
+\ Yaboot is stupid.  Without this, it can't/won't find /etc/yaboot.conf.
+s" chrp" device-type
+
+\ See 3.6.5, and the PowerPC OF binding document.
+new-device
+s" mmu" 2dup device-name device-type
+0 0 s" translations" property
+
+: open  true ;
+: close ;
+
+finish-device
+device-end
+
+4c0 cp
+
+\ Fixup timebase frequency from device-tree
+: fixup-tbfreq
+    " /cpus/@0" find-device
+    " timebase-frequency" get-node get-package-property IF
+        2drop
+    ELSE
+        decode-int to tb-frequency 2drop
+    THEN
+    device-end
+;
+fixup-tbfreq
+
+4d0 cp
+
+\ Grab rtas from qemu
+#include "rtas.fs"
+
+500 cp
+
+: populate-vios ( -- )
+    \ Populate the /vdevice children with their methods
+    \ WARNING: Quite a few SLOFisms here like get-node, set-node, ...
+
+    ." Populating /vdevice methods" cr
+    " /vdevice" find-device get-node child
+    BEGIN
+        dup 0 <>
+    WHILE
+        dup set-node
+        dup " compatible" rot get-package-property 0 = IF
+            drop dup from-cstring
+            2dup " hvterm1" strequal IF
+                " vio-hvterm.fs" included
+            THEN
+            2dup " IBM,v-scsi" strequal IF
+                " vio-vscsi.fs" included
+            THEN
+            2dup " IBM,l-lan" strequal IF
+                " vio-veth.fs" included
+            THEN
+            2drop
+       THEN
+       peer
+    REPEAT drop
+
+    device-end
+;
+
+\ Now do it
+populate-vios
+
+580 cp
+
+5a0 cp
+
+600 cp
+
+\ Add rtas cleanup last
+' rtas-quiesce add-quiesce-xt
+
+640 cp
+
+690 cp
+
+6a0 cp
+
+6a8 cp
+
+6b0 cp
+
+6b8 cp
+
+6c0 cp
+
+s" /cpus/@0" open-dev encode-int s" cpu" set-chosen
+s" /memory" open-dev encode-int s" memory" set-chosen
+
+6e0 cp
+
+700 cp
+
+\ See 3.5.
+s" /openprom" find-device
+   s" SLOF," slof-build-id here swap rmove here slof-build-id nip $cat encode-string s" model" property
+   0 0 s" relative-addressing" property
+device-end
+
+s" /aliases" find-device
+   : open  true ;
+   : close ;
+device-end
+
+s" /mmu" open-dev encode-int s" mmu" set-chosen
+
+#include "available.fs"
+
+\ Setup terminal IO
+
+#include <term-io.fs>
+
+" hvterm" find-alias IF drop
+  " hvterm" io
+THEN
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-hvterm.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-hvterm.fs
new file mode 100644
index 0000000..32b2a59
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-hvterm.fs
@@ -0,0 +1,32 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+." Populating " pwd cr
+
+: open true ;
+: close ;
+
+: write ( adr len -- actual )  tuck type ;
+
+: read  ( adr len -- actual )
+   0= IF drop 0 EXIT THEN
+   hvterm-key? 0= IF 0 swap c! -2 EXIT THEN
+   hvterm-key swap c! 1
+;
+
+: setup-alias
+    " hvterm" find-alias 0= IF
+        " hvterm" get-node node>path set-alias
+    ELSE THEN 
+;
+
+setup-alias
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-veth.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-veth.fs
new file mode 100644
index 0000000..0da0c61
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-veth.fs
@@ -0,0 +1,41 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+." Populating " pwd cr
+
+" network" device-type
+
+INSTANCE VARIABLE obp-tftp-package
+: open  ( -- okay? )
+   my-unit 1 rtas-set-tce-bypass
+   my-args s" obp-tftp" $open-package obp-tftp-package ! true
+;
+
+: close  ( -- )
+   s" close" obp-tftp-package @ $call-method
+   my-unit 0 rtas-set-tce-bypass
+;
+
+: load  ( addr -- len )
+    s" load" obp-tftp-package @ $call-method 
+;
+
+: ping  ( -- )
+    s" ping" obp-tftp-package @ $call-method
+;
+
+: setup-alias
+    " net" find-alias 0= IF
+        " net" get-node node>path set-alias
+    ELSE THEN 
+;
+setup-alias
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi-device.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi-device.fs
new file mode 100644
index 0000000..1c48706
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi-device.fs
@@ -0,0 +1,72 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Create new VSCSI child device
+\ ( lun id $name is_cdrom -- )
+
+\ Create device
+new-device
+
+VALUE is_cdrom
+
+2swap	( $name lun id )
+
+\ Set reg & unit
+2dup set-unit encode-phys " reg" property
+
+\ Set name
+2dup device-name
+
+2dup find-alias 0= IF
+    get-node node>path set-alias
+ELSE 2drop THEN 
+
+s" block" device-type      
+
+\ Required interface for deblocker
+
+0 INSTANCE VALUE block-size
+0 INSTANCE VALUE max-block-num
+0 INSTANCE VALUE max-transfer
+
+: read-blocks ( addr block# #blocks -- #read )
+    block-size " dev-read-blocks" $call-parent
+    not IF
+        ." Read blocks failed !" cr -1 throw
+    THEN
+;    
+
+INSTANCE VARIABLE deblocker
+
+: open ( -- true | false )
+    my-unit " set-address" $call-parent
+    is_cdrom IF " dev-prep-cdrom" ELSE " dev-prep-disk" THEN $call-parent
+    " dev-get-capacity" $call-parent to max-block-num to block-size
+    " dev-max-transfer" $call-parent to max-transfer
+
+    0 0 " deblocker" $open-package dup deblocker ! dup IF 
+        " disk-label" find-package IF
+	    my-args rot interpose
+        THEN
+   THEN 0<>
+;
+
+: close ( -- )
+    deblocker @ close-package ;
+
+: seek ( pos.lo pos.hi -- status )
+    s" seek" deblocker @ $call-method ;
+
+: read ( addr len -- actual )
+    s" read" deblocker @ $call-method ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi.fs b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi.fs
new file mode 100644
index 0000000..7bf5ae8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/slof/vio-vscsi.fs
@@ -0,0 +1,623 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+." Populating " pwd
+
+0 CONSTANT vscsi-debug
+
+0 VALUE vscsi-unit
+
+\ -----------------------------------------------------------
+\ Direct DMA conversion hack
+\ -----------------------------------------------------------
+: l2dma ( laddr - dma_addr)      
+;
+
+\ -----------------------------------------------------------
+\ CRQ related functions
+\ -----------------------------------------------------------
+
+0    VALUE     crq-base
+0    VALUE     crq-dma
+0    VALUE     crq-offset
+1000 CONSTANT  CRQ-SIZE
+
+CREATE crq 10 allot
+
+: crq-alloc ( -- )
+    \ XXX We rely on SLOF alloc-mem being aligned
+    CRQ-SIZE alloc-mem to crq-base 0 to crq-offset
+    crq-base l2dma to crq-dma
+;
+
+: crq-free ( -- )
+    vscsi-unit hv-free-crq
+    crq-base CRQ-SIZE free-mem 0 to crq-base
+;
+
+: crq-init ( -- res )
+    \ Allocate CRQ. XXX deal with fail
+    crq-alloc
+
+    vscsi-debug IF
+        ." VSCSI: allocated crq at " crq-base . cr
+    THEN
+
+    \ Clear buffer
+    crq-base CRQ-SIZE erase
+
+    \ Register with HV
+    vscsi-unit crq-dma CRQ-SIZE hv-reg-crq
+
+    \ Fail case
+    dup 0 <> IF
+        ." VSCSI: Error " . ."  registering CRQ !" cr
+	crq-free
+    THEN
+;
+
+: crq-cleanup ( -- )
+    crq-base 0 = IF EXIT THEN
+
+    vscsi-debug IF
+        ." VSCSI: freeing crq at " crq-base . cr
+    THEN
+    crq-free
+;
+
+: crq-send ( msgaddr -- true | false )
+    vscsi-unit swap hv-send-crq 0 =
+;
+
+: crq-poll ( -- true | false)
+    crq-offset crq-base + dup
+    vscsi-debug IF
+        ." VSCSI: crq poll " dup .
+    THEN
+    c@
+    vscsi-debug IF
+        ."  value=" dup . cr
+    THEN
+    80 and 0 <> IF
+        dup crq 10 move
+	0 swap c!
+	crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset
+	true
+    ELSE drop false THEN
+;
+
+: crq-wait ( -- true | false)
+    \ FIXME: Add timeout
+    0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT
+    dup not IF
+        ." VSCSI: Timeout waiting response !" cr EXIT
+    ELSE
+        vscsi-debug IF
+            ." VSCSI: got crq: " crq dup l@ . ."  " 4 + dup l@ . ."  "
+	    4 + dup l@ . ."  " 4 + l@ . cr
+        THEN
+    THEN
+;
+
+\ -----------------------------------------------------------
+\ CRQ encapsulated SRP definitions
+\ -----------------------------------------------------------
+
+01 CONSTANT VIOSRP_SRP_FORMAT
+02 CONSTANT VIOSRP_MAD_FORMAT
+03 CONSTANT VIOSRP_OS400_FORMAT
+04 CONSTANT VIOSRP_AIX_FORMAT
+06 CONSTANT VIOSRP_LINUX_FORMAT
+07 CONSTANT VIOSRP_INLINE_FORMAT
+
+struct
+   1 field >crq-valid
+   1 field >crq-format
+   1 field >crq-reserved
+   1 field >crq-status
+   2 field >crq-timeout
+   2 field >crq-iu-len
+   8 field >crq-iu-data-ptr
+constant /crq
+
+: srp-send-crq ( addr len -- )
+    80                crq >crq-valid c!
+    VIOSRP_SRP_FORMAT crq >crq-format c!
+    0                 crq >crq-reserved c!
+    0                 crq >crq-status c!
+    0                 crq >crq-timeout w!
+    ( len )           crq >crq-iu-len w!
+    ( addr ) l2dma    crq >crq-iu-data-ptr x!
+    crq crq-send
+    not IF
+        ." VSCSI: Error sending CRQ !" cr
+    THEN
+;
+
+: srp-wait-crq ( -- [tag true] | false )
+    crq-wait not IF false EXIT THEN
+
+    crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF
+    	." VSCSI: Unsupported SRP response: "
+	crq >crq-format c@ . cr
+	false EXIT
+    THEN
+
+    crq >crq-iu-data-ptr x@ true
+;
+
+\ Add scsi functions to dictionary
+scsi-open
+
+
+\ -----------------------------------------------------------
+\ SRP definitions
+\ -----------------------------------------------------------
+
+0 VALUE >srp_opcode
+
+00 CONSTANT SRP_LOGIN_REQ
+01 CONSTANT SRP_TSK_MGMT
+02 CONSTANT SRP_CMD
+03 CONSTANT SRP_I_LOGOUT
+c0 CONSTANT SRP_LOGIN_RSP
+c1 CONSTANT SRP_RSP
+c2 CONSTANT SRP_LOGIN_REJ
+80 CONSTANT SRP_T_LOGOUT
+81 CONSTANT SRP_CRED_REQ
+82 CONSTANT SRP_AER_REQ
+41 CONSTANT SRP_CRED_RSP
+42 CONSTANT SRP_AER_RSP
+
+02 CONSTANT SRP_BUF_FORMAT_DIRECT
+04 CONSTANT SRP_BUF_FORMAT_INDIRECT
+
+struct
+   1 field >srp-login-opcode
+   3 +
+   8 field >srp-login-tag
+   4 field >srp-login-req-it-iu-len
+   4 +
+   2 field >srp-login-req-buf-fmt
+   1 field >srp-login-req-flags
+   5 +
+  10 field >srp-login-init-port-ids
+  10 field >srp-login-trgt-port-ids
+constant /srp-login
+
+struct
+   1 field >srp-lresp-opcode
+   3 +
+   4 field >srp-lresp-req-lim-delta
+   8 field >srp-lresp-tag
+   4 field >srp-lresp-max-it-iu-len
+   4 field >srp-lresp-max-ti-iu-len
+   2 field >srp-lresp-buf-fmt
+   1 field >srp-lresp-flags
+constant /srp-login-resp
+
+struct
+   1 field >srp-lrej-opcode
+   3 +
+   4 field >srp-lrej-reason
+   8 field >srp-lrej-tag
+   8 +
+   2 field >srp-lrej-buf-fmt
+constant /srp-login-rej
+
+00 CONSTANT SRP_NO_DATA_DESC
+01 CONSTANT SRP_DATA_DESC_DIRECT
+02 CONSTANT SRP_DATA_DESC_INDIRECT
+
+struct
+    1 field >srp-cmd-opcode
+    1 field >srp-cmd-sol-not
+    3 +
+    1 field >srp-cmd-buf-fmt
+    1 field >srp-cmd-dout-desc-cnt
+    1 field >srp-cmd-din-desc-cnt
+    8 field >srp-cmd-tag
+    4 +
+    8 field >srp-cmd-lun
+    1 +
+    1 field >srp-cmd-task-attr
+    1 +
+    1 field >srp-cmd-add-cdb-len
+   10 field >srp-cmd-cdb
+    0 field >srp-cmd-cdb-add
+constant /srp-cmd
+
+struct
+    1 field >srp-rsp-opcode
+    1 field >srp-rsp-sol-not
+    2 +
+    4 field >srp-rsp-req-lim-delta
+    8 field >srp-rsp-tag
+    2 +
+    1 field >srp-rsp-flags
+    1 field >srp-rsp-status
+    4 field >srp-rsp-dout-res-cnt
+    4 field >srp-rsp-din-res-cnt
+    4 field >srp-rsp-sense-len
+    4 field >srp-rsp-resp-len
+    0 field >srp-rsp-data
+constant /srp-rsp
+
+\ Storage for up to 256 bytes SRP request */
+CREATE srp 100 allot
+0 VALUE srp-len
+
+: srp-prep-cmd-nodata ( id lun -- )
+    srp /srp-cmd erase
+    SRP_CMD srp >srp-cmd-opcode c!
+    1 srp >srp-cmd-tag x!
+    srp >srp-cmd-lun 1 + c!	\ lun
+    srp >srp-cmd-lun c!		\ id
+    /srp-cmd to srp-len   
+;
+
+: srp-prep-cmd-io ( addr len id lun -- )
+    srp-prep-cmd-nodata		( addr len )
+    swap l2dma			( len dmaaddr )
+    srp srp-len +    		( len dmaaddr descaddr )
+    dup >r x! r> 8 +		( len descaddr+8 )
+    dup 0 swap l! 4 +		( len descaddr+c )
+    l!    
+    srp-len 10 + to srp-len
+;
+
+: srp-prep-cmd-read ( addr len id lun -- )
+    srp-prep-cmd-io
+    01 srp >srp-cmd-buf-fmt c!	\ in direct buffer
+    1 srp >srp-cmd-din-desc-cnt c!
+;
+
+: srp-prep-cmd-write ( addr len id lun -- )
+    srp-prep-cmd-io
+    10 srp >srp-cmd-buf-fmt c!	\ out direct buffer
+    1 srp >srp-cmd-dout-desc-cnt c!
+;
+
+: srp-send-cmd ( -- )
+    vscsi-debug IF
+        ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr
+    THEN
+    srp srp-len srp-send-crq
+;
+
+: srp-rsp-find-sense ( -- addr )
+    \ XXX FIXME: Always in same position
+    srp >srp-rsp-data
+;
+
+: srp-wait-rsp ( -- true | [ ascq asc sense-key false ] )
+    srp-wait-crq not IF false EXIT THEN
+    dup 1 <> IF
+        ." VSCSI: Invalid CRQ response tag, want 1 got " . cr
+	false EXIT
+    THEN drop
+    
+    srp >srp-rsp-tag x@ dup 1 <> IF
+        ." VSCSI: Invalid SRP response tag, want 1 got " . cr
+	false EXIT
+    THEN drop
+    
+    srp >srp-rsp-status c@
+    vscsi-debug IF
+        ." VSCSI: Got response status: "
+	dup .status-text cr
+    THEN
+
+    0 <> IF
+       srp-rsp-find-sense
+       scsi-get-sense-data
+       vscsi-debug IF
+           ." VSCSI: Sense key: " dup .sense-text cr	   
+       THEN
+       false EXIT
+    THEN
+    true
+;
+
+
+\ -----------------------------------------------------------
+\ Core VSCSI
+\ -----------------------------------------------------------
+
+CREATE sector d# 512 allot
+
+0 VALUE current-id
+0 VALUE current-lun
+
+\ SCSI test-unit-read
+: test-unit-ready ( -- true | [ ascq asc sense-key false ] )
+    current-id current-lun srp-prep-cmd-nodata
+    srp >srp-cmd-cdb scsi-build-test-unit-ready
+    srp-send-cmd
+    srp-wait-rsp
+;
+
+: inquiry ( -- true | false )
+    \ WARNING: ATAPI devices with libata seem to ignore the MSB of
+    \ the allocation length... let's only ask for ff bytes
+    sector ff current-id current-lun srp-prep-cmd-read
+    ff srp >srp-cmd-cdb scsi-build-inquiry
+    srp-send-cmd
+    srp-wait-rsp
+    dup not IF nip nip nip EXIT THEN \ swallow sense
+;
+
+: read-capacity ( -- true | false )
+    sector scsi-length-read-cap-10 current-id current-lun srp-prep-cmd-read
+    srp >srp-cmd-cdb scsi-build-read-cap-10
+    srp-send-cmd
+    srp-wait-rsp
+    dup not IF nip nip nip EXIT THEN \ swallow sense    
+;
+
+: start-stop-unit ( state# -- true | false )
+    current-id current-lun srp-prep-cmd-nodata
+    srp >srp-cmd-cdb scsi-build-start-stop-unit
+    srp-send-cmd
+    srp-wait-rsp
+    dup not IF nip nip nip EXIT THEN \ swallow sense    
+;
+
+: get-media-event ( -- true | false )
+    sector scsi-length-media-event current-id current-lun srp-prep-cmd-read
+    srp >srp-cmd-cdb scsi-build-get-media-event
+    srp-send-cmd
+    srp-wait-rsp
+    dup not IF nip nip nip EXIT THEN \ swallow sense    
+;
+
+: read-blocks ( -- addr block# #blocks blksz -- [ #read-blocks true ] | false )
+    over * 					( addr block# #blocks len )    
+    >r rot r> 			                ( block# #blocks addr len )
+    5 0 DO
+      	2dup current-id current-lun
+	srp-prep-cmd-read                       ( block# #blocks addr len )
+        2swap					( addr len block# #blocks )
+        2dup srp >srp-cmd-cdb scsi-build-read-10 ( addr len block# #blocks )
+	2swap                                   ( block# #blocks addr len )
+        srp-send-cmd
+ 	srp-wait-rsp
+	IF 2drop nip true UNLOOP EXIT THEN
+	srp >srp-rsp-status c@ 8 <> IF
+	    nip nip nip 2drop 2drop false EXIT
+	THEN
+	3drop
+	100 ms
+    LOOP
+    2drop 2drop false
+;
+
+\ Cleanup behind us
+: vscsi-cleanup
+    ." VSCSI: Cleaning up" cr
+
+    crq-cleanup
+
+    \ Disable TCE bypass
+    vscsi-unit 0 rtas-set-tce-bypass
+;
+
+\ Initialize our vscsi instance
+: vscsi-init ( -- true | false )
+    ." VSCSI: Initializing" cr
+
+    \ Can't use my-unit bcs we aren't instanciating (fix this ?)
+    " reg" get-node get-package-property IF
+        ." VSCSI: Not reg property !!!" 0
+    THEN
+    decode-int to vscsi-unit 2drop
+
+    \ Enable TCE bypass special qemu feature
+    vscsi-unit 1 rtas-set-tce-bypass
+
+    \ Initialize CRQ
+    crq-init 0 <> IF false EXIT THEN
+
+    \ Send init command
+    " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop
+    crq-send not IF
+        ." VSCSI: Error sending init command"
+        crq-cleanup false EXIT
+    THEN
+
+    \ Wait reply
+    crq-wait not IF
+        crq-cleanup false EXIT
+    THEN
+
+    \ Check init reply
+    crq c@ c0 <> crq 1 + c@ 02 <> or IF
+        ." VSCSI: Initial handshake failed"
+	crq-cleanup false EXIT
+    THEN
+
+    \ We should now login etc.. but we really don't need to
+    \ with our qemu model
+
+    \ Ensure we cleanup after booting
+    ['] vscsi-cleanup add-quiesce-xt
+
+    true
+;
+
+\ -----------------------------------------------------------
+\ SCSI scan at boot and child device support
+\ -----------------------------------------------------------
+
+0 INSTANCE VALUE target-id
+0 INSTANCE VALUE target-lun
+
+: set-address ( lun id -- )
+    to target-id to target-lun 
+;
+
+: dev-max-transfer ( -- n )
+    10000 \ Larger value seem to have problems with some CDROMs
+;
+
+: dev-get-capacity ( -- blocksize #blocks )
+    target-id to current-id target-lun to current-lun
+    read-capacity not IF 0 0 EXIT THEN
+    sector scsi-get-capacity-10
+;
+
+: dev-read-blocks ( -- addr block# #blocks blksize -- #read-blocks )
+    target-id to current-id target-lun to current-lun
+    read-blocks    
+;
+
+: initial-test-unit-ready ( -- true | [ ascq asc sense-key false ] )
+    0 0 0 false
+    3 0 DO
+        2drop 2drop
+        test-unit-ready dup IF UNLOOP EXIT THEN
+    LOOP    
+;
+
+: compare-sense ( ascq asc key ascq2 asc2 key2 -- true | false )
+    3 pick =	    ( ascq asc key ascq2 asc2 keycmp )
+    swap 4 pick =   ( ascq asc key ascq2 keycmp asccmp )
+    rot 5 pick =    ( ascq asc key keycmp asccmp ascqcmp )
+    and and nip nip nip
+;
+
+0 CONSTANT CDROM-READY
+1 CONSTANT CDROM-NOT-READY
+2 CONSTANT CDROM-NO-DISK
+3 CONSTANT CDROM-TRAY-OPEN
+4 CONSTANT CDROM-INIT-REQUIRED
+5 CONSTANT CDROM-TRAY-MAYBE-OPEN
+
+: cdrom-status ( -- status )
+    initial-test-unit-ready
+    IF CDROM-READY EXIT THEN
+
+    vscsi-debug IF
+        ." TestUnitReady sense: " 3dup . . . cr
+    THEN
+
+    3dup 1 4 2 compare-sense IF
+        3drop CDROM-NOT-READY EXIT
+    THEN
+
+    get-media-event IF
+        sector w@ 4 >= IF
+	    sector 2 + c@ 04 = IF
+	        sector 5 + c@
+		dup 02 and 0<> IF drop 3drop CDROM-READY EXIT THEN
+		dup 01 and 0<> IF drop 3drop CDROM-TRAY-OPEN EXIT THEN
+		drop 3drop CDROM-NO-DISK EXIT
+	    THEN
+	THEN
+    THEN
+
+    3dup 2 4 2 compare-sense IF
+        3drop CDROM-INIT-REQUIRED EXIT
+    THEN
+    over 4 = over 2 = and IF
+        \ Format in progress... what do we do ? Just ignore
+	3drop CDROM-READY EXIT
+    THEN
+    over 3a = IF
+        3drop CDROM-NO-DISK EXIT
+    THEN
+
+    \ Other error...
+    3drop CDROM-TRAY-MAYBE-OPEN    
+;
+
+: cdrom-try-close-tray ( -- )
+    scsi-const-load start-stop-unit drop
+;
+
+: cdrom-must-close-tray ( -- )
+    scsi-const-load start-stop-unit not IF
+        ." Tray open !" cr -65 throw
+    THEN
+;
+
+: dev-prep-cdrom ( -- )
+    target-id to current-id target-lun to current-lun
+
+    5 0 DO
+        cdrom-status CASE
+	    CDROM-READY           OF UNLOOP EXIT ENDOF
+	    CDROM-NO-DISK         OF ." No medium !" cr -65 THROW ENDOF
+	    CDROM-TRAY-OPEN       OF cdrom-must-close-tray ENDOF
+	    CDROM-INIT-REQUIRED   OF cdrom-try-close-tray ENDOF
+	    CDROM-TRAY-MAYBE-OPEN OF cdrom-try-close-tray ENDOF
+	ENDCASE
+	d# 1000 ms
+    LOOP
+    ." Drive not ready !" cr -65 THROW
+;
+
+: dev-prep-disk ( -- )
+;
+
+: vscsi-create-disk	( lun id -- )
+    " disk" 0 " vio-vscsi-device.fs" included
+;
+
+: vscsi-create-cdrom	( lun id -- )
+    " cdrom" 1 " vio-vscsi-device.fs" included
+;
+
+: wrapped-inquiry ( -- true | false )
+    inquiry not IF false EXIT THEN
+    \ Skip devices with PQ != 0
+    sector inquiry-data>peripheral c@ e0 and 0 =
+;
+
+8 CONSTANT #dev
+: vscsi-find-disks      ( -- )   
+    ." VSCSI: Looking for disks" cr
+    #dev 0 DO                                      \ check 8 devices (no LUNs)
+        i to current-id 0 to current-lun
+	wrapped-inquiry IF	
+	    ."   SCSI ID " i .
+	    \ XXX FIXME: Check top bits to ignore unsupported units
+	    \            and maybe provide better printout & more cases
+	    sector inquiry-data>peripheral c@ CASE
+                0   OF ." DISK     : " 0 i vscsi-create-disk  ENDOF
+                5   OF ." CD-ROM   : " 0 i vscsi-create-cdrom ENDOF
+                7   OF ." OPTICAL  : " 0 i vscsi-create-cdrom ENDOF
+                e   OF ." RED-BLOCK: " 0 i vscsi-create-disk  ENDOF
+                dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF
+            ENDCASE
+	    sector .inquiry-text cr
+	THEN
+    LOOP
+;
+
+\ Remove scsi functions from word list
+scsi-close
+
+: setup-alias
+    " scsi" find-alias 0= IF
+        " scsi" get-node node>path set-alias
+    ELSE THEN 
+;
+
+: vscsi-init-and-scan  ( -- )
+    vscsi-init IF
+        vscsi-find-disks
+	setup-alias
+    THEN
+;
+
+vscsi-init-and-scan
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/veth/Makefile b/qemu-0.15.x/roms/SLOF/board-qemu/veth/Makefile
new file mode 100644
index 0000000..0032b8e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/veth/Makefile
@@ -0,0 +1,50 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS = -O2 -I./ -I$(TOP)/clients/net-snk/include/ -I$(TOP)/lib/libc/include/
+CFLAGS += -I$(TOP)/lib/libhvcall
+CFLAGS += -fno-builtin -ffreestanding -fno-stack-protector -msoft-float -nostdinc -Wall
+
+SRCS   = module_entry.c veth.c
+
+OBJS   = $(SRCS:.c=.o) $(TOP)/lib/libhvcall/hvcall.o
+
+all: Makefile.dep net_veth.bin
+
+net_veth.o: $(OBJS)
+	$(LD) $(LDFLAGS) $^ -o $@ -T veth.lds -N
+
+net_veth.bin: net_veth.o
+	$(OBJCOPY) -O binary $^ $@ 
+clean:		
+	$(RM) -f *.o *.a *.i *.bin
+
+distclean : clean
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+		$(CC) -MM $(CFLAGS) $(SRCS) > Makefile.dep
+Makefile.dep:
+		$(MAKE) depend
+
+# Include dependency file if available:
+ifneq (,$(wildcard Makefile.dep))
+include Makefile.dep
+endif
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/veth/module_entry.c b/qemu-0.15.x/roms/SLOF/board-qemu/veth/module_entry.c
new file mode 100644
index 0000000..30a3508
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/veth/module_entry.c
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "netdriver_int.h"
+
+static void* memset( void *dest, int c, size_t n )
+{
+	while( n-- ) {
+		*( char * ) dest++ = ( char ) c;
+	}
+	return dest;
+}
+
+extern char __bss_start;
+extern char __bss_size;
+
+extern snk_module_t* veth_module_init(snk_kernel_t *snk_kernel_int,
+				      vio_config_t *conf);
+
+snk_module_t* module_init(snk_kernel_t *snk_kernel_int, pci_config_t *pciconf)
+{
+	char              *bss      = &__bss_start;
+	unsigned long long bss_size = (unsigned long long) &__bss_size;
+	vio_config_t	  *vioconf  = (vio_config_t *)pciconf;
+
+	if (((unsigned long long) bss) + bss_size >= 0xFF00000 
+	 || bss_size >= 0x2000000) {
+		snk_kernel_int->print("BSS size (%llu bytes) is too big!\n",
+				      bss_size);
+		return 0;
+	}
+	memset(bss, 0, bss_size);
+
+	return veth_module_init(snk_kernel_int, vioconf);
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.c b/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.c
new file mode 100644
index 0000000..0bbaebe
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.c
@@ -0,0 +1,280 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "types.h"
+#include "netdriver_int.h"
+#include "libhvcall.h"
+
+static snk_kernel_t     *snk_kernel_interface;
+static snk_module_t	*snk_module_interface;
+static unsigned int	g_reg;
+
+#define printk(fmt...)  do { snk_kernel_interface->print(fmt); } while(0)
+#define malloc(args...) snk_kernel_interface->k_malloc(args)
+#define malloc_aligned(args...) snk_kernel_interface->k_malloc_aligned(args)
+#define free(args...)  do { snk_kernel_interface->k_free(args); } while(0)
+
+#define dprintk(fmt...)
+//#define dprintk(fmt...)	printk(fmt)
+
+/* *** WARNING: We pass our addresses as-is as DMA addresses,
+ *     we -do- rely on the forth code to have enabled TCE bypass
+ *     on our device !
+ */
+#define vaddr_to_dma(vaddr)	((u64)vaddr)
+
+struct ibmveth_buf_desc_fields {
+	u32 flags_len;
+#define IBMVETH_BUF_VALID	0x80000000
+#define IBMVETH_BUF_TOGGLE	0x40000000
+#define IBMVETH_BUF_NO_CSUM	0x02000000
+#define IBMVETH_BUF_CSUM_GOOD	0x01000000
+#define IBMVETH_BUF_LEN_MASK	0x00FFFFFF
+	u32 address;
+};
+
+union ibmveth_buf_desc {
+	u64 desc;
+	struct ibmveth_buf_desc_fields fields;
+};
+
+struct ibmveth_rx_q_entry {
+	u32 flags_off;
+#define IBMVETH_RXQ_TOGGLE		0x80000000
+#define IBMVETH_RXQ_TOGGLE_SHIFT	31
+#define IBMVETH_RXQ_VALID		0x40000000
+#define IBMVETH_RXQ_NO_CSUM		0x02000000
+#define IBMVETH_RXQ_CSUM_GOOD		0x01000000
+#define IBMVETH_RXQ_OFF_MASK		0x0000FFFF
+
+	u32 length;
+	u64 correlator;
+};
+
+static void *buffer_list; 
+static void *filter_list; 
+static u64 *rx_bufs;
+static u64 *rx_bufs_aligned;
+static u32 cur_rx_toggle;
+static u32 cur_rx_index;
+
+#define RX_QUEUE_SIZE	16
+#define RX_BUF_SIZE	2048
+#define RX_BUF_MULT	(RX_BUF_SIZE >> 3)
+
+static struct ibmveth_rx_q_entry *rx_queue;
+
+static char * memcpy( char *dest, const char *src, size_t n )
+{
+        char *ret = dest;
+        while( n-- ) {
+                *dest++ = *src++;
+        }
+
+        return( ret );
+}
+
+static inline u64 *veth_get_rx_buf(unsigned int i)
+{
+	return &rx_bufs_aligned[i * RX_BUF_MULT];
+}
+
+static int veth_init(void)
+{
+	char *mac_addr = snk_module_interface->mac_addr;
+	union ibmveth_buf_desc rxq_desc;
+	unsigned long rx_queue_len = sizeof(struct ibmveth_rx_q_entry) *
+		RX_QUEUE_SIZE;
+	unsigned int i;
+	long rc;
+
+	dprintk("veth_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	if (snk_module_interface->running != 0)
+		return 0;
+
+	cur_rx_toggle = IBMVETH_RXQ_TOGGLE;
+	cur_rx_index = 0;
+	buffer_list = malloc_aligned(8192, 4096);
+	filter_list = buffer_list + 4096;
+	rx_queue = malloc_aligned(rx_queue_len, 16);
+	rx_bufs = malloc(2048 * RX_QUEUE_SIZE + 4);
+	if (!buffer_list || !filter_list || !rx_queue || !rx_bufs) {
+		printk("veth: Failed to allocate memory !\n");
+		goto fail;
+	}
+	rx_bufs_aligned = (u64 *)(((u64)rx_bufs | 3) + 1);
+	rxq_desc.fields.address = vaddr_to_dma(rx_queue);
+	rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | rx_queue_len;
+
+	rc = h_register_logical_lan(g_reg,
+				    vaddr_to_dma(buffer_list),
+				    rxq_desc.desc,
+				    vaddr_to_dma(filter_list),
+				    (*(u64 *)mac_addr) >> 16);
+	if (rc != H_SUCCESS) {
+		printk("veth: Error %ld registering interface !\n", rc);
+		goto fail;
+	}
+	for (i = 0; i < RX_QUEUE_SIZE; i++) {
+		u64 *buf = veth_get_rx_buf(i);
+		union ibmveth_buf_desc desc;
+		*buf = (u64)buf;
+		desc.fields.address = vaddr_to_dma(buf);
+		desc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
+		h_add_logical_lan_buffer(g_reg, desc.desc);
+	}
+
+	snk_module_interface->running = 1;
+
+	return 0;
+ fail:
+	if (filter_list)
+		free(filter_list);
+	if (buffer_list)
+		free(buffer_list);
+	if (rx_queue)
+		free(rx_queue);
+	if (rx_bufs)
+		free(rx_bufs);
+	return -1;
+}
+
+static int veth_term(void)
+{
+	dprintk("veth_term()\n");
+
+	if (snk_module_interface->running == 0)
+		return 0;
+
+	h_free_logical_lan(g_reg);
+
+	if (filter_list)
+		free(filter_list);
+	if (buffer_list)
+		free(buffer_list);
+	if (rx_queue)
+		free(rx_queue);
+	if (rx_bufs)
+		free(rx_bufs);
+
+	snk_module_interface->running = 0;
+
+	return 0;
+}
+
+static int veth_xmit(char *f_buffer_pc, int f_len_i)
+{
+	union ibmveth_buf_desc tx_desc;
+	long rc;
+
+	dprintk("veth_xmit(packet at %p, %d bytes)\n", f_buffer_pc, f_len_i);
+
+	tx_desc.fields.address = vaddr_to_dma(f_buffer_pc);
+	tx_desc.fields.flags_len = IBMVETH_BUF_VALID | f_len_i;
+
+	rc = hv_send_logical_lan(g_reg, tx_desc.desc, 0, 0, 0, 0, 0);
+	if (rc != H_SUCCESS) {
+		printk("veth: Error %ld sending packet !\n", rc);
+		return -1;
+	}
+
+	return f_len_i;
+}
+
+static int veth_receive(char *f_buffer_pc, int f_len_i)
+{
+	int packet = 0;
+
+	dprintk("veth_receive()\n");
+
+	while(!packet) {
+		struct ibmveth_rx_q_entry *desc = &rx_queue[cur_rx_index];
+		union ibmveth_buf_desc bdesc;
+		void *buf;
+
+		if ((desc->flags_off & IBMVETH_RXQ_TOGGLE) != cur_rx_toggle)
+			break;
+
+		if (!(desc->flags_off & IBMVETH_RXQ_VALID))
+			goto recycle;
+		if (desc->length > f_len_i) {
+			printk("veth: Dropping too big packet [%d bytes]\n",
+			       desc->length);
+			goto recycle;
+		}
+
+		buf = (void *)desc->correlator;
+		packet = desc->length;
+		memcpy(f_buffer_pc,
+		       buf + (desc->flags_off & IBMVETH_RXQ_OFF_MASK), packet);
+	recycle:
+		bdesc.fields.address = vaddr_to_dma(buf);
+		bdesc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
+		h_add_logical_lan_buffer(g_reg, bdesc.desc);
+
+		cur_rx_index = (cur_rx_index + 1) % RX_QUEUE_SIZE;
+		if (cur_rx_index == 0)
+			cur_rx_toggle ^= IBMVETH_RXQ_TOGGLE;
+	}
+
+	return packet;
+}
+
+static int veth_ioctl(int request, void* data)
+{
+	dprintk("veth_ioctl()\n");
+
+	return 0;
+}
+
+static snk_module_t veth_interface = {
+	.version = 1,
+	.type    = MOD_TYPE_NETWORK,
+	.running = 0,
+	.init    = veth_init,
+	.term    = veth_term,
+	.write   = veth_xmit,
+	.read    = veth_receive,
+	.ioctl   = veth_ioctl
+};
+
+
+static int check_driver(vio_config_t *conf)
+{
+	
+        if (snk_kernel_interface->strcmp(conf->compat, "IBM,l-lan")) {
+		printk( "veth: netdevice not supported\n" );
+		return -1;
+	}
+	g_reg = conf->reg;
+	
+	return 0;
+}
+
+snk_module_t* veth_module_init(snk_kernel_t *snk_kernel_int, vio_config_t *conf)
+{
+	snk_kernel_interface = snk_kernel_int;
+	snk_module_interface = &veth_interface;
+
+	if (snk_kernel_int->version != snk_module_interface->version)
+		return 0;
+
+	/* Check if this is the right driver */
+	if (check_driver(conf) < 0)
+		return 0;
+
+	snk_module_interface->link_addr = module_init;
+	return snk_module_interface;
+}
diff --git a/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.lds b/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.lds
new file mode 100644
index 0000000..a0c75d5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/board-qemu/veth/veth.lds
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(module_init)
+
+SECTIONS {
+	.code 0xF800000:
+	{
+	  module_entry.o(.opd) 
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+          *(.rodata .rodata.* .gnu.linkonce.r.*)
+	  *(.data .data.* .gnu.linkonce.d.*)
+	  *(.opd)
+	} 
+	.got : 
+	{
+	  _got = .;
+          *(.got .toc)
+	} 
+        .bss : {
+	  __bss_start = .;
+          *(*COM* .bss .gnu.linkonce.b.*)
+	  __bss_end = .;
+	} 
+	__bss_size = (__bss_end - __bss_start);	
+        __end = .;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/Makefile b/qemu-0.15.x/roms/SLOF/clients/Makefile
new file mode 100644
index 0000000..d656f08
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/Makefile
@@ -0,0 +1,29 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include clients.mk
+
+all:
+	for dir in $(CLIENTS); do \
+		if [ -r $$dir/Makefile ]; then \
+		$(MAKE) -C $$dir "FLAG=$(FLAG)" || exit 1; \
+		cp $$dir/client $$dir.client; \
+		fi; \
+	done
+
+clean distclean:
+	@for dir in $(CLIENTS); do \
+		if [ -r $$dir/Makefile ]; then \
+		$(MAKE) -C $$dir $@ || exit 1; \
+		rm -f $$dir.client; \
+		fi; \
+	done
diff --git a/qemu-0.15.x/roms/SLOF/clients/clients.mk b/qemu-0.15.x/roms/SLOF/clients/clients.mk
new file mode 100644
index 0000000..ca741e4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/clients.mk
@@ -0,0 +1,13 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+CLIENTS = net-snk
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/Makefile
new file mode 100644
index 0000000..f89ef28
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/Makefile
@@ -0,0 +1,66 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOP=$(shell pwd)
+export TOP
+include $(TOP)/make.rules
+    
+OBJS	=  kernel/kernel.o oflib/oflib.o libc/libc-glue.o app/app.o
+.PHONY : subdirs clean depend mrproper
+
+client : .depend subdirs $(OBJS) $(LIBCMNDIR)/libc.a
+	$(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS) $(LIBCMNDIR)/libc.a
+	$(OBJDUMP) -DSsx $@ > $@.dis
+	cp $@ $@.unstripped
+	$(STRIP) $@
+
+sec-client : subdirs $(OBJS) $(LIBCMNDIR)/libc.a
+	$(LD) $(LDFLAGS) -o $@ -Tsec-client.lds $(OBJS) $(LIBCMNDIR)/libc.a
+
+fpga-client : 
+	$(MAKE) -C . fpga-client-int SNK_LJTAG_PROCESS=1
+
+fpga-client-int : subdirs $(OBJS) $(LIBCMNDIR)/libc.a
+	$(LD) $(LDFLAGS) -o fpga-client -Tsec-client.lds $(OBJS) $(LIBCMNDIR)/libc.a
+	$(STRIP) fpga-client
+
+subdirs : 
+	@for dir in $(dir $(OBJS)); do \
+	  $(MAKE) -C $$dir || exit 1; \
+	done
+
+$(LIBCMNDIR)/libc.a:
+	$(MAKE) -C $(LIBCMNDIR) libc
+
+clean: 
+	@for dir in $(dir $(OBJS)); do \
+	  $(MAKE) -C $$dir clean; \
+	done
+	rm -f $(OBJS) client diag netboot sec-client net-diag \
+		*.dis client.unstripped fpga-client
+
+mrproper : clean
+	$(MAKE) -C app mrproper
+	$(MAKE) -C libc mrproper
+	$(MAKE) -C kernel mrproper
+	$(MAKE) -C oflib mrproper
+	find -name .*.bak | xargs rm -rf
+	$(RM) .depend
+
+distclean: mrproper
+
+depend .depend:
+	$(MAKE) -C app depend
+	$(MAKE) -C libc depend
+	$(MAKE) -C kernel depend
+	$(MAKE) -C oflib depend
+	touch .depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/Makefile
new file mode 100644
index 0000000..5d02afa
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/Makefile
@@ -0,0 +1,51 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS +=$(ADDCFLAGS)
+
+OBJS = main.o
+OBJDIRS = netlib/netlib.o netapps/netboot.o 
+OBJDIRS += netapps/netflash.o
+OBJDIRS += netapps/ping.o
+OBJDIRS += netapps/args.o
+
+ifeq ($(SNK_BIOSEMU_APPS), 1)
+OBJDIRS += biosemu/biosemu_app.o
+CFLAGS += -DSNK_BIOSEMU_APPS
+endif
+
+SUBDIRS = $(dir $(OBJDIRS))
+
+all: app.o
+
+subdirs:
+	for dir in $(SUBDIRS); do \
+		$(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+	done
+
+app.o: subdirs $(OBJS)
+	$(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r 
+
+clean :	
+	$(RM) -f *.o *.a *.i 
+	for dir in $(SUBDIRS); do \
+		$(CLEAN) ; \
+		$(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+	done
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/Makefile
new file mode 100644
index 0000000..3a07ada
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/Makefile
@@ -0,0 +1,38 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I$(ROOTDIR)/other-licence/x86emu -I$(ROOTDIR)/other-licence/x86emu/include
+
+OBJS    = biosemu.o debug.o device.o mem.o io.o interrupt.o vbe.o
+LIBX86EMU = $(ROOTDIR)/other-licence/x86emu/libx86emu.a 
+
+.PHONY: $(LIBX86EMU)
+
+all: biosemu_app.o
+
+# special rule for libx86emu.a
+$(LIBX86EMU):
+	$(MAKE) -C $(dir $@)
+
+biosemu_app.o: $(OBJS) $(LIBX86EMU)
+	$(LD) $(LDFLAGS) $^ -o $@ -r
+	
+clean:	
+		$(RM) -f *.o *.a *.i *.s
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c
new file mode 100644
index 0000000..8d36de6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c
@@ -0,0 +1,345 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <cpu.h>
+
+#include "debug.h"
+
+#include <x86emu/x86emu.h>
+#include <x86emu/regs.h>
+#include <x86emu/prim_ops.h>	// for push_word
+
+#include "biosemu.h"
+#include "io.h"
+#include "mem.h"
+#include "interrupt.h"
+#include "device.h"
+
+#include <rtas.h>
+
+
+static X86EMU_memFuncs my_mem_funcs = {
+	my_rdb, my_rdw, my_rdl,
+	my_wrb, my_wrw, my_wrl
+};
+
+static X86EMU_pioFuncs my_pio_funcs = {
+	my_inb, my_inw, my_inl,
+	my_outb, my_outw, my_outl
+};
+
+void dump(uint8_t * addr, uint32_t len);
+
+uint32_t
+biosemu(char argc, char **argv)
+{
+	uint8_t *rom_image;
+	int i = 0;
+	uint8_t *biosmem;
+	uint32_t biosmem_size;
+#ifdef DEBUG
+	//debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP;// | DEBUG_PMM;// | DEBUG_INTR | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;// | DEBUG_TRACE_X86EMU | DEBUG_JMP;
+#endif
+	if (argc < 4) {
+		printf("Usage %s <vmem_base> <vmem_size> <device_path> [<debug_flags>]\n", argv[0]);
+		for (i = 0; i < argc; i++) {
+			printf("argv[%d]: %s\n", i, argv[i]);
+		}
+		return -1;
+	}
+	// argv[1] is address of virtual BIOS mem...
+	// argv[2] is the size
+	biosmem = (uint8_t *) strtoul(argv[1], 0, 16);
+	biosmem_size = strtoul(argv[2], 0, 16);
+	if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
+		printf("Error: Not enough virtual memory: %x, required: %x!\n",
+		       biosmem_size, MIN_REQUIRED_VMEM_SIZE);
+		return -1;
+	}
+	// argv[3] is the device to open and use...
+	if (dev_init(argv[3]) != 0) {
+		printf("Error initializing device!\n");
+		return -1;
+	}
+	if (dev_check_exprom() != 0) {
+		printf("Error: Device Expansion ROM invalid!\n");
+		return -1;
+	}
+   // argv[4] if set, is additional debug_flags
+   if (argc >= 5) {
+      debug_flags |= strtoul(argv[4], 0, 16);
+      printf("debug_flags: %x\n", debug_flags);
+   }
+	rom_image = (uint8_t *) bios_device.img_addr;
+	DEBUG_PRINTF("executing rom_image from %p\n", rom_image);
+	DEBUG_PRINTF("biosmem at %p\n", biosmem);
+
+	DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size);
+
+	// in case we jump somewhere unexpected, or execution is finished,
+	// fill the biosmem with hlt instructions (0xf4)
+	memset(biosmem, 0xf4, biosmem_size);
+
+	M.mem_base = (long) biosmem;
+	M.mem_size = biosmem_size;
+	DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base,
+		     (int) M.mem_size);
+
+	// copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT
+	// NOTE: this sometimes fails, some bytes are 0x00... so we compare
+	// after copying and do some retries...
+	uint8_t *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4);
+	uint8_t copy_count = 0;
+	uint8_t cmp_result = 0;
+	do {
+#if 0
+		set_ci();
+		memcpy(mem_img, rom_image, len);
+		clr_ci();
+#else
+		// memcpy fails... try copy byte-by-byte with set/clr_ci
+		uint8_t c;
+		for (i = 0; i < bios_device.img_size; i++) {
+			set_ci();
+			c = *(rom_image + i);
+			if (c != *(rom_image + i)) {
+				clr_ci();
+				printf("Copy failed at: %x/%x\n", i,
+				       bios_device.img_size);
+				printf("rom_image(%x): %x, mem_img(%x): %x\n",
+				       i, *(rom_image + i), i, *(mem_img + i));
+				break;
+			}
+			clr_ci();
+			*(mem_img + i) = c;
+		}
+#endif
+		copy_count++;
+		set_ci();
+		cmp_result = memcmp(mem_img, rom_image, bios_device.img_size);
+		clr_ci();
+	}
+	while ((copy_count < 5) && (cmp_result != 0));
+	if (cmp_result != 0) {
+		printf
+		    ("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n",
+		     copy_count, cmp_result);
+		dump(rom_image, 0x20);
+		dump(mem_img, 0x20);
+		return 0;
+	}
+	// setup default Interrupt Vectors
+	// some expansion ROMs seem to check for these addresses..
+	// each handler is only an IRET (0xCF) instruction
+	// ROM BIOS Int 10 Handler F000:F065
+	my_wrl(0x10 * 4, 0xf000f065);
+	my_wrb(0x000ff065, 0xcf);
+	// ROM BIOS Int 11 Handler F000:F84D
+	my_wrl(0x11 * 4, 0xf000f84d);
+	my_wrb(0x000ff84d, 0xcf);
+	// ROM BIOS Int 12 Handler F000:F841
+	my_wrl(0x12 * 4, 0xf000f841);
+	my_wrb(0x000ff841, 0xcf);
+	// ROM BIOS Int 13 Handler F000:EC59
+	my_wrl(0x13 * 4, 0xf000ec59);
+	my_wrb(0x000fec59, 0xcf);
+	// ROM BIOS Int 14 Handler F000:E739
+	my_wrl(0x14 * 4, 0xf000e739);
+	my_wrb(0x000fe739, 0xcf);
+	// ROM BIOS Int 15 Handler F000:F859
+	my_wrl(0x15 * 4, 0xf000f859);
+	my_wrb(0x000ff859, 0xcf);
+	// ROM BIOS Int 16 Handler F000:E82E
+	my_wrl(0x16 * 4, 0xf000e82e);
+	my_wrb(0x000fe82e, 0xcf);
+	// ROM BIOS Int 17 Handler F000:EFD2
+	my_wrl(0x17 * 4, 0xf000efd2);
+	my_wrb(0x000fefd2, 0xcf);
+	// ROM BIOS Int 1A Handler F000:FE6E
+	my_wrl(0x1a * 4, 0xf000fe6e);
+	my_wrb(0x000ffe6e, 0xcf);
+
+	// setup BIOS Data Area (0000:04xx, or 0040:00xx)
+	// we currently 0 this area, meaning "we dont have
+	// any hardware" :-) no serial/parallel ports, floppys, ...
+	memset(biosmem + 0x400, 0x0, 0x100);
+
+	// at offset 13h in BDA is the memory size in kbytes
+	my_wrw(0x413, biosmem_size / 1024);
+	// at offset 0eh in BDA is the segment of the Extended BIOS Data Area
+	// see setup further down
+	my_wrw(0x40e, INITIAL_EBDA_SEGMENT);
+	// TODO: setup BDA Video Data ( offset 49h-66h)
+	// e.g. to store video mode, cursor position, ...
+	// in int10 (done) handler and VBE Functions
+
+	// TODO: setup BDA Fixed Disk Data
+	// 74h: Fixed Disk Last Operation Status
+	// 75h: Fixed Disk Number of Disk Drives
+
+	// TODO: check BDA for further needed data...
+
+	//setup Extended BIOS Data Area
+	//we currently 0 this area
+	memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE);
+	// at offset 0h in EBDA is the size of the EBDA in KB
+	my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024);
+	//TODO: check for further needed EBDA data...
+
+	// setup  original ROM BIOS Area (F000:xxxx)
+	char *date = "06/11/99";
+	for (i = 0; date[i]; i++)
+		my_wrb(0xffff5 + i, date[i]);
+	// set up eisa ident string
+	char *ident = "PCI_ISA";
+	for (i = 0; ident[i]; i++)
+		my_wrb(0xfffd9 + i, ident[i]);
+
+	// write system model id for IBM-AT
+	// according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515,
+	// model FC is the original AT and also used in all DOSEMU Versions.
+	my_wrb(0xFFFFE, 0xfc);
+
+	//setup interrupt handler
+	X86EMU_intrFuncs intrFuncs[256];
+	for (i = 0; i < 256; i++)
+		intrFuncs[i] = handleInterrupt;
+	X86EMU_setupIntrFuncs(intrFuncs);
+	X86EMU_setupPioFuncs(&my_pio_funcs);
+	X86EMU_setupMemFuncs(&my_mem_funcs);
+
+	// setup the CPU
+	M.x86.R_AH = bios_device.bus;
+	M.x86.R_AL = bios_device.devfn;
+	M.x86.R_DX = 0x80;
+	M.x86.R_EIP = 3;
+	M.x86.R_CS = OPTION_ROM_CODE_SEGMENT;
+
+	// Initialize stack and data segment
+	M.x86.R_SS = STACK_SEGMENT;
+	M.x86.R_SP = STACK_START_OFFSET;
+	M.x86.R_DS = DATA_SEGMENT;
+
+	// push a HLT instruction and a pointer to it onto the stack
+	// any return will pop the pointer and jump to the HLT, thus
+	// exiting (more or less) cleanly
+	push_word(0xf4f4);	//F4=HLT
+	push_word(M.x86.R_SS);
+	push_word(M.x86.R_SP + 2);
+
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	} else {
+#ifdef DEBUG
+		M.x86.debug |= DEBUG_SAVE_IP_CS_F;
+		M.x86.debug |= DEBUG_DECODE_F;
+		M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
+#endif
+	}
+	CHECK_DBG(DEBUG_JMP) {
+		M.x86.debug |= DEBUG_TRACEJMP_F;
+		M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
+		M.x86.debug |= DEBUG_TRACECALL_F;
+		M.x86.debug |= DEBUG_TRACECALL_REGS_F;
+		}
+
+	DEBUG_PRINTF("Executing Initialization Vector...\n");
+	X86EMU_exec();
+	DEBUG_PRINTF("done\n");
+
+	// according to PNP BIOS Spec, Option ROMs should upon exit, return some boot device status in
+	// AX (see PNP BIOS Spec Section 3.3
+	DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX);
+#ifdef DEBUG
+	DEBUG_PRINTF("Exit Status Decode:\n");
+	if (M.x86.R_AX & 0x100) {	// bit 8
+		DEBUG_PRINTF
+		    ("  IPL Device supporting INT 13h Block Device Format:\n");
+		switch (((M.x86.R_AX >> 4) & 0x3)) {	// bits 5:4
+		case 0:
+			DEBUG_PRINTF("    No IPL Device attached\n");
+			break;
+		case 1:
+			DEBUG_PRINTF("    IPL Device status unknown\n");
+			break;
+		case 2:
+			DEBUG_PRINTF("    IPL Device attached\n");
+			break;
+		case 3:
+			DEBUG_PRINTF("    IPL Device status RESERVED!!\n");
+			break;
+		}
+	}
+	if (M.x86.R_AX & 0x80) {	// bit 7
+		DEBUG_PRINTF
+		    ("  Output Device supporting INT 10h Character Output:\n");
+		switch (((M.x86.R_AX >> 4) & 0x3)) {	// bits 5:4
+		case 0:
+			DEBUG_PRINTF("    No Display Device attached\n");
+			break;
+		case 1:
+			DEBUG_PRINTF("    Display Device status unknown\n");
+			break;
+		case 2:
+			DEBUG_PRINTF("    Display Device attached\n");
+			break;
+		case 3:
+			DEBUG_PRINTF("    Display Device status RESERVED!!\n");
+			break;
+		}
+	}
+	if (M.x86.R_AX & 0x40) {	// bit 6
+		DEBUG_PRINTF
+		    ("  Input Device supporting INT 9h Character Input:\n");
+		switch (((M.x86.R_AX >> 4) & 0x3)) {	// bits 5:4
+		case 0:
+			DEBUG_PRINTF("    No Input Device attached\n");
+			break;
+		case 1:
+			DEBUG_PRINTF("    Input Device status unknown\n");
+			break;
+		case 2:
+			DEBUG_PRINTF("    Input Device attached\n");
+			break;
+		case 3:
+			DEBUG_PRINTF("    Input Device status RESERVED!!\n");
+			break;
+		}
+	}
+#endif
+	// check wether the stack is "clean" i.e. containing the HLT instruction
+	// we pushed before executing, and pointing to the original stack address...
+	// indicating that the initialization probably was successful
+	if ((pop_word() == 0xf4f4) && (M.x86.R_SS == STACK_SEGMENT)
+	    && (M.x86.R_SP == STACK_START_OFFSET)) {
+		DEBUG_PRINTF("Stack is clean, initialization successfull!\n");
+	} else {
+		DEBUG_PRINTF
+		    ("Stack unclean, initialization probably NOT COMPLETE!!!\n");
+		DEBUG_PRINTF("SS:SP = %04x:%04x, expected: %04x:%04x\n",
+			     M.x86.R_SS, M.x86.R_SP, STACK_SEGMENT,
+			     STACK_START_OFFSET);
+	}
+
+
+	// TODO: according to the BIOS Boot Spec initializations may be ended using INT18h and setting
+	// the status.
+	// We need to implement INT18 accordingly, pseudo code is in specsbbs101.pdf page 30
+	// (also for Int19)
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h
new file mode 100644
index 0000000..7ffd5bc
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _BIOSEMU_BIOSEMU_H_
+#define _BIOSEMU_BIOSEMU_H_
+
+#define MIN_REQUIRED_VMEM_SIZE 0x100000	// 1MB
+
+//define default segments for different components
+#define STACK_SEGMENT 0x1000	//1000:xxxx
+#define STACK_START_OFFSET 0xfffe
+
+#define DATA_SEGMENT 0x2000
+#define VBE_SEGMENT 0x3000
+
+#define PMM_CONV_SEGMENT 0x4000	// 4000:xxxx is PMM conventional memory area, extended memory area
+				// will be anything beyound MIN_REQUIRED_MEMORY_SIZE
+#define PNP_DATA_SEGMENT 0x5000
+
+#define OPTION_ROM_CODE_SEGMENT 0xc000
+
+#define BIOS_DATA_SEGMENT 0xF000
+// both EBDA values are _initial_ values, they may (and will be) changed at runtime by option ROMs!!
+#define INITIAL_EBDA_SEGMENT 0xF600	// segment of the Extended BIOS Data Area
+#define INITIAL_EBDA_SIZE 0x400	// size of the EBDA (at least 1KB!! since size is stored in KB!)
+
+#define PMM_INT_NUM 0xFC	// we misuse INT FC for PMM functionality, at the PMM Entry Point
+				// Address, there will only be a call to this INT and a RETF
+#define PNP_INT_NUM 0xFD
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.c
new file mode 100644
index 0000000..2fce244
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.c
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+
+#include "debug.h"
+
+uint32_t debug_flags = 0;
+
+void
+dump(uint8_t * addr, uint32_t len)
+{
+	printf("\n\r%s(%p, %x):\n", __FUNCTION__, addr, len);
+	while (len) {
+		unsigned int tmpCnt = len;
+		unsigned char x;
+		if (tmpCnt > 8)
+			tmpCnt = 8;
+		printf("\n\r%p: ", addr);
+		// print hex
+		while (tmpCnt--) {
+			set_ci();
+			x = *addr++;
+			clr_ci();
+			printf("%02x ", x);
+		}
+		tmpCnt = len;
+		if (tmpCnt > 8)
+			tmpCnt = 8;
+		len -= tmpCnt;
+		//reset addr ptr to print ascii
+		addr = addr - tmpCnt;
+		// print ascii
+		while (tmpCnt--) {
+			set_ci();
+			x = *addr++;
+			clr_ci();
+			if ((x < 32) || (x >= 127)) {
+				//non-printable char
+				x = '.';
+			}
+			printf("%c", x);
+		}
+	}
+	printf("\n");
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.h
new file mode 100644
index 0000000..c056190
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/debug.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef _BIOSEMU_DEBUG_H_
+#define _BIOSEMU_DEBUG_H_
+
+#include <stdio.h>
+#include <stdint.h>
+
+extern uint32_t debug_flags;
+// from x86emu...needed for debugging
+extern void x86emu_dump_xregs();
+
+#define DEBUG_IO 0x1
+#define DEBUG_MEM 0x2
+// set this to print messages for certain virtual memory accesses (Interrupt Vectors, ...)
+#define DEBUG_CHECK_VMEM_ACCESS 0x4
+#define DEBUG_INTR 0x8
+#define DEBUG_PRINT_INT10 0x10	// set to have the INT10 routine print characters
+#define DEBUG_VBE 0x20
+#define DEBUG_PMM 0x40
+#define DEBUG_DISK 0x80
+#define DEBUG_PNP 0x100
+
+#define DEBUG_TRACE_X86EMU 0x1000
+// set to enable tracing of JMPs in x86emu
+#define DEBUG_JMP 0x2000
+
+//#define DEBUG
+#ifdef DEBUG
+
+#define CHECK_DBG(_flag) if (debug_flags & _flag)
+
+#define DEBUG_PRINTF(_x...) printf(_x);
+// prints the CS:IP before the printout, NOTE: actually its CS:IP of the _next_ instruction
+// to be executed, since the x86emu advances CS:IP _before_ actually executing an instruction
+#define DEBUG_PRINTF_CS_IP(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x);
+
+#define DEBUG_PRINTF_IO(_x...) CHECK_DBG(DEBUG_IO) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_MEM(_x...) CHECK_DBG(DEBUG_MEM) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_INTR(_x...) CHECK_DBG(DEBUG_INTR) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_VBE(_x...) CHECK_DBG(DEBUG_VBE) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_PMM(_x...) CHECK_DBG(DEBUG_PMM) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_DISK(_x...) CHECK_DBG(DEBUG_DISK) { DEBUG_PRINTF_CS_IP(_x) }
+#define DEBUG_PRINTF_PNP(_x...) CHECK_DBG(DEBUG_PNP) { DEBUG_PRINTF_CS_IP(_x) }
+
+#else
+
+#define CHECK_DBG(_flag) if (0)
+
+#define DEBUG_PRINTF(_x...)
+#define DEBUG_PRINTF_CS_IP(_x...)
+
+#define DEBUG_PRINTF_IO(_x...)
+#define DEBUG_PRINTF_MEM(_x...)
+#define DEBUG_PRINTF_INTR(_x...)
+#define DEBUG_PRINTF_VBE(_x...)
+#define DEBUG_PRINTF_PMM(_x...)
+#define DEBUG_PRINTF_DISK(_x...)
+#define DEBUG_PRINTF_PNP(_x...)
+
+#endif				//DEBUG
+
+void dump(uint8_t * addr, uint32_t len);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.c
new file mode 100644
index 0000000..71402d5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "device.h"
+#include "rtas.h"
+#include <stdio.h>
+#include <string.h>
+#include "debug.h"
+
+typedef struct {
+	uint8_t info;
+	uint8_t bus;
+	uint8_t devfn;
+	uint8_t cfg_space_offset;
+	uint64_t address;
+	uint64_t size;
+} __attribute__ ((__packed__)) assigned_address_t;
+
+// use translate_address_dev and get_puid from net-snk's net_support.c
+void translate_address_dev(uint64_t *, phandle_t);
+uint64_t get_puid(phandle_t node);
+
+
+// scan all adresses assigned to the device ("assigned-addresses" and "reg")
+// store in translate_address_array for faster translation using dev_translate_address
+void
+dev_get_addr_info()
+{
+	// get bus/dev/fn from assigned-addresses
+	int32_t len;
+	//max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
+	assigned_address_t buf[11];
+	len =
+	    of_getprop(bios_device.phandle, "assigned-addresses", buf,
+		       sizeof(buf));
+	bios_device.bus = buf[0].bus;
+	bios_device.devfn = buf[0].devfn;
+	DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
+		     bios_device.devfn);
+	//store address translations for all assigned-addresses and regs in
+	//translate_address_array for faster translation later on...
+	int i = 0;
+	// index to insert data into translate_address_array
+	int taa_index = 0;
+	uint64_t address_offset;
+	for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
+		//copy all info stored in assigned-addresses
+		translate_address_array[taa_index].info = buf[i].info;
+		translate_address_array[taa_index].bus = buf[i].bus;
+		translate_address_array[taa_index].devfn = buf[i].devfn;
+		translate_address_array[taa_index].cfg_space_offset =
+		    buf[i].cfg_space_offset;
+		translate_address_array[taa_index].address = buf[i].address;
+		translate_address_array[taa_index].size = buf[i].size;
+		// translate first address and store it as address_offset
+		address_offset = buf[i].address;
+		translate_address_dev(&address_offset, bios_device.phandle);
+		translate_address_array[taa_index].address_offset =
+		    address_offset - buf[i].address;
+	}
+	//get "reg" property
+	len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
+	for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
+		if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
+			// we dont care for ranges with size 0 and
+			// BARs and Expansion ROM must be in assigned-addresses... so in reg
+			// we only look for those without config space offset set...
+			// i.e. the legacy ranges
+			continue;
+		}
+		//copy all info stored in assigned-addresses
+		translate_address_array[taa_index].info = buf[i].info;
+		translate_address_array[taa_index].bus = buf[i].bus;
+		translate_address_array[taa_index].devfn = buf[i].devfn;
+		translate_address_array[taa_index].cfg_space_offset =
+		    buf[i].cfg_space_offset;
+		translate_address_array[taa_index].address = buf[i].address;
+		translate_address_array[taa_index].size = buf[i].size;
+		// translate first address and store it as address_offset
+		address_offset = buf[i].address;
+		translate_address_dev(&address_offset, bios_device.phandle);
+		translate_address_array[taa_index].address_offset =
+		    address_offset - buf[i].address;
+		taa_index++;
+	}
+	// store last entry index of translate_address_array
+	taa_last_entry = taa_index - 1;
+#ifdef DEBUG
+	//dump translate_address_array
+	printf("translate_address_array: \n");
+	translate_address_t ta;
+	for (i = 0; i <= taa_last_entry; i++) {
+		ta = translate_address_array[i];
+		printf
+		    ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
+		     i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
+		     ta.address, ta.address_offset, ta.size);
+	}
+#endif
+}
+
+// to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
+// we look for the first prefetchable memory BAR, if no prefetchable BAR found,
+// we use the first memory BAR
+// dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
+void
+dev_find_vmem_addr()
+{
+	int i = 0;
+	translate_address_t ta;
+	int8_t tai_np = -1, tai_p = -1;	// translate_address_array index for non-prefetchable and prefetchable memory
+	//search backwards to find first entry
+	for (i = taa_last_entry; i >= 0; i--) {
+		ta = translate_address_array[i];
+		if ((ta.cfg_space_offset >= 0x10)
+		    && (ta.cfg_space_offset <= 0x24)) {
+			//only BARs
+			if ((ta.info & 0x03) >= 0x02) {
+				//32/64bit memory
+				tai_np = i;
+				if ((ta.info & 0x40) != 0) {
+					// prefetchable
+					tai_p = i;
+				}
+			}
+		}
+	}
+	if (tai_p != -1) {
+		ta = translate_address_array[tai_p];
+		bios_device.vmem_addr = ta.address;
+		bios_device.vmem_size = ta.size;
+		DEBUG_PRINTF
+		    ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
+		     __FUNCTION__, bios_device.vmem_addr,
+		     bios_device.vmem_size);
+	} else if (tai_np != -1) {
+		ta = translate_address_array[tai_np];
+		bios_device.vmem_addr = ta.address;
+		bios_device.vmem_size = ta.size;
+		DEBUG_PRINTF
+		    ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
+		     __FUNCTION__, bios_device.vmem_addr,
+		     bios_device.vmem_size);
+	}
+	// disable vmem
+	//bios_device.vmem_size = 0;
+}
+
+void
+dev_get_puid()
+{
+	// get puid
+	bios_device.puid = get_puid(bios_device.phandle);
+	DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
+}
+
+void
+dev_get_device_vendor_id()
+{
+	uint32_t pci_config_0 =
+	    rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
+				 bios_device.devfn, 0x0);
+	bios_device.pci_device_id =
+	    (uint16_t) ((pci_config_0 & 0xFFFF0000) >> 16);
+	bios_device.pci_vendor_id = (uint16_t) (pci_config_0 & 0x0000FFFF);
+	DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
+		     bios_device.pci_device_id, bios_device.pci_vendor_id);
+}
+
+/* check, wether the device has a valid Expansion ROM, also search the PCI Data Structure and
+ * any Expansion ROM Header (using dev_scan_exp_header()) for needed information */
+uint8_t
+dev_check_exprom()
+{
+	int i = 0;
+	translate_address_t ta;
+	uint64_t rom_base_addr = 0;
+	uint16_t pci_ds_offset;
+	pci_data_struct_t pci_ds;
+	// check for ExpROM Address (Offset 30) in taa
+	for (i = 0; i <= taa_last_entry; i++) {
+		ta = translate_address_array[i];
+		if (ta.cfg_space_offset == 0x30) {
+			rom_base_addr = ta.address + ta.address_offset;	//translated address
+			break;
+		}
+	}
+	// in the ROM there could be multiple Expansion ROM Images... start searching
+	// them for a x86 image
+	do {
+		if (rom_base_addr == 0) {
+			printf("Error: no Expansion ROM address found!\n");
+			return -1;
+		}
+		set_ci();
+		uint16_t rom_signature = *((uint16_t *) rom_base_addr);
+		clr_ci();
+		if (rom_signature != 0x55aa) {
+			printf
+			    ("Error: invalid Expansion ROM signature: %02x!\n",
+			     *((uint16_t *) rom_base_addr));
+			return -1;
+		}
+		set_ci();
+		// at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
+		pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
+		//copy the PCI Data Structure
+		memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
+		       sizeof(pci_ds));
+		clr_ci();
+#ifdef DEBUG
+		DEBUG_PRINTF("PCI Data Structure @%llx:\n",
+			     rom_base_addr + pci_ds_offset);
+		dump((void *) &pci_ds, sizeof(pci_ds));
+#endif
+		if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
+			printf("Invalid PCI Data Structure found!\n");
+			break;
+		}
+		//little-endian conversion
+		pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
+		pci_ds.device_id = in16le(&pci_ds.device_id);
+		pci_ds.img_length = in16le(&pci_ds.img_length);
+		pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
+		if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
+			printf
+			    ("Image has invalid Vendor ID: %04x, expected: %04x\n",
+			     pci_ds.vendor_id, bios_device.pci_vendor_id);
+			break;
+		}
+		if (pci_ds.device_id != bios_device.pci_device_id) {
+			printf
+			    ("Image has invalid Device ID: %04x, expected: %04x\n",
+			     pci_ds.device_id, bios_device.pci_device_id);
+			break;
+		}
+		//DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
+		//DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
+		if (pci_ds.code_type == 0) {
+			//x86 image
+			//store image address and image length in bios_device struct
+			bios_device.img_addr = rom_base_addr;
+			bios_device.img_size = pci_ds.img_length * 512;
+			// we found the image, exit the loop
+			break;
+		} else {
+			// no x86 image, check next image (if any)
+			rom_base_addr += pci_ds.img_length * 512;
+		}
+		if ((pci_ds.indicator & 0x80) == 0x80) {
+			//last image found, exit the loop
+			DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
+			break;
+		}
+	}
+	while (bios_device.img_addr == 0);
+	// in case we did not find a valid x86 Expansion ROM Image
+	if (bios_device.img_addr == 0) {
+		printf("Error: no valid x86 Expansion ROM Image found!\n");
+		return -1;
+	}
+	return 0;
+}
+
+uint8_t
+dev_init(char *device_name)
+{
+	uint8_t rval = 0;
+	//init bios_device struct
+	DEBUG_PRINTF("%s(%s)\n", __FUNCTION__, device_name);
+	memset(&bios_device, 0, sizeof(bios_device));
+	bios_device.ihandle = of_open(device_name);
+	if (bios_device.ihandle == 0) {
+		DEBUG_PRINTF("%s is no valid device!\n", device_name);
+		return -1;
+	}
+	bios_device.phandle = of_finddevice(device_name);
+	dev_get_addr_info();
+	dev_find_vmem_addr();
+	dev_get_puid();
+	dev_get_device_vendor_id();
+	return rval;
+}
+
+// translate address function using translate_address_array assembled
+// by dev_get_addr_info... MUCH faster than calling translate_address_dev
+// and accessing client interface for every translation...
+// returns: 0 if addr not found in translate_address_array, 1 if found.
+uint8_t
+dev_translate_address(uint64_t * addr)
+{
+	int i = 0;
+	translate_address_t ta;
+	//check if it is an access to legacy VGA Mem... if it is, map the address
+	//to the vmem BAR and then translate it...
+	// (translation info provided by Ben Herrenschmidt)
+	// NOTE: the translation seems to only work for NVIDIA cards... but it is needed
+	// to make some NVIDIA cards work at all...
+	if ((bios_device.vmem_size > 0)
+	    && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
+		*addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
+	}
+	if ((bios_device.vmem_size > 0)
+	    && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
+		uint8_t shift = *addr & 1;
+		*addr &= 0xfffffffe;
+		*addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
+	}
+	for (i = 0; i <= taa_last_entry; i++) {
+		ta = translate_address_array[i];
+		if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
+			*addr += ta.address_offset;
+			return 1;
+		}
+	}
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.h
new file mode 100644
index 0000000..074bd69
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/device.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef DEVICE_LIB_H
+#define DEVICE_LIB_H
+
+#include <stdint.h>
+#include <cpu.h>
+#include "of.h"
+#include <stdio.h>
+
+// a Expansion Header Struct as defined in Plug and Play BIOS Spec 1.0a Chapter 3.2
+typedef struct {
+	char signature[4];	// signature
+	uint8_t structure_revision;
+	uint8_t length;		// in 16 byte blocks
+	uint16_t next_header_offset;	// offset to next Expansion Header as 16bit little-endian value, as offset from the start of the Expansion ROM
+	uint8_t reserved;
+	uint8_t checksum;	// the sum of all bytes of the Expansion Header must be 0
+	uint32_t device_id;	// PnP Device ID as 32bit little-endian value
+	uint16_t p_manufacturer_string;	//16bit little-endian offset from start of Expansion ROM
+	uint16_t p_product_string;	//16bit little-endian offset from start of Expansion ROM
+	uint8_t device_base_type;
+	uint8_t device_sub_type;
+	uint8_t device_if_type;
+	uint8_t device_indicators;
+	// the following vectors are all 16bit little-endian offsets from start of Expansion ROM
+	uint16_t bcv;		// Boot Connection Vector
+	uint16_t dv;		// Disconnect Vector
+	uint16_t bev;		// Bootstrap Entry Vector
+	uint16_t reserved_2;
+	uint16_t sriv;		// Static Resource Information Vector
+} __attribute__ ((__packed__)) exp_header_struct_t;
+
+// a PCI Data Struct as defined in PCI 2.3 Spec Chapter 6.3.1.2
+typedef struct {
+	uint8_t signature[4];	// signature, the String "PCIR"
+	uint16_t vendor_id;
+	uint16_t device_id;
+	uint16_t reserved;
+	uint16_t pci_ds_length;	// PCI Data Structure Length, 16bit little-endian value
+	uint8_t pci_ds_revision;
+	uint8_t class_code[3];
+	uint16_t img_length;	// length of the Exp.ROM Image, 16bit little-endian value in 512 bytes
+	uint16_t img_revision;
+	uint8_t code_type;
+	uint8_t indicator;
+	uint16_t reserved_2;
+} __attribute__ ((__packed__)) pci_data_struct_t;
+
+typedef struct {
+	uint8_t bus;
+	uint8_t devfn;
+	uint64_t puid;
+	phandle_t phandle;
+	ihandle_t ihandle;
+	// store the address of the BAR that is used to simulate
+	// legacy VGA memory accesses
+	uint64_t vmem_addr;
+	uint64_t vmem_size;
+	// used to buffer I/O Accesses, that do not access the I/O Range of the device...
+	// 64k might be overkill, but we can buffer all I/O accesses...
+	uint8_t io_buffer[64 * 1024];
+	uint16_t pci_vendor_id;
+	uint16_t pci_device_id;
+	// translated address of the "PC-Compatible" Expansion ROM Image for this device
+	uint64_t img_addr;
+	uint32_t img_size;	// size of the Expansion ROM Image (read from the PCI Data Structure)
+} device_t;
+
+typedef struct {
+	uint8_t info;
+	uint8_t bus;
+	uint8_t devfn;
+	uint8_t cfg_space_offset;
+	uint64_t address;
+	uint64_t address_offset;
+	uint64_t size;
+} __attribute__ ((__packed__)) translate_address_t;
+
+// array to store address translations for this
+// device. Needed for faster address translation, so
+// not every I/O or Memory Access needs to call translate_address_dev
+// and access the device tree
+// 6 BARs, 1 Exp. ROM, 1 Cfg.Space, and 3 Legacy
+// translations are supported... this should be enough for
+// most devices... for VGA it is enough anyways...
+translate_address_t translate_address_array[11];
+
+// index of last translate_address_array entry
+// set by get_dev_addr_info function
+uint8_t taa_last_entry;
+
+device_t bios_device;
+
+uint8_t dev_init(char *device_name);
+// NOTE: for dev_check_exprom to work, dev_init MUST be called first!
+uint8_t dev_check_exprom();
+
+uint8_t dev_translate_address(uint64_t * addr);
+
+/* endianness swap functions for 16 and 32 bit words
+ * copied from axon_pciconfig.c
+ */
+static inline void
+out32le(void *addr, uint32_t val)
+{
+	asm volatile ("stwbrx  %0, 0, %1"::"r" (val), "r"(addr));
+}
+
+static inline uint32_t
+in32le(void *addr)
+{
+	uint32_t val;
+	asm volatile ("lwbrx  %0, 0, %1":"=r" (val):"r"(addr));
+	return val;
+}
+
+static inline void
+out16le(void *addr, uint16_t val)
+{
+	asm volatile ("sthbrx  %0, 0, %1"::"r" (val), "r"(addr));
+}
+
+static inline uint16_t
+in16le(void *addr)
+{
+	uint16_t val;
+	asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr));
+	return val;
+}
+
+/* debug function, dumps HID1 and HID4 to detect wether caches are on/off */
+static inline void
+dumpHID()
+{
+	uint64_t hid;
+	//HID1 = 1009
+	__asm__ __volatile__("mfspr %0, 1009":"=r"(hid));
+	printf("HID1: %016llx\n", hid);
+	//HID4 = 1012
+	__asm__ __volatile__("mfspr %0, 1012":"=r"(hid));
+	printf("HID4: %016llx\n", hid);
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c
new file mode 100644
index 0000000..f1137fe
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c
@@ -0,0 +1,607 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+#include <rtas.h>
+
+#include "biosemu.h"
+#include "mem.h"
+#include "device.h"
+#include "debug.h"
+
+#include <x86emu/x86emu.h>
+#include <x86emu/prim_ops.h>
+
+
+
+//setup to run the code at the address, that the Interrupt Vector points to...
+void
+setupInt(int intNum)
+{
+	DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
+			  __FUNCTION__, intNum, my_rdl(intNum * 4));
+	// push current R_FLG... will be popped by IRET
+	push_word((u16) M.x86.R_FLG);
+	CLEAR_FLAG(F_IF);
+	CLEAR_FLAG(F_TF);
+	// push current CS:IP to the stack, will be popped by IRET
+	push_word(M.x86.R_CS);
+	push_word(M.x86.R_IP);
+	// set CS:IP to the interrupt handler address... so the next executed instruction will
+	// be the interrupt handler
+	M.x86.R_CS = my_rdw(intNum * 4 + 2);
+	M.x86.R_IP = my_rdw(intNum * 4);
+}
+
+// handle int10 (VGA BIOS Interrupt)
+void
+handleInt10()
+{
+	// the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
+	// function number in AH
+	//DEBUG_PRINTF_CS_IP("%s:\n", __FUNCTION__);
+	//x86emu_dump_xregs();
+	//if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
+	//X86EMU_trace_on();
+	//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+	//}
+	switch (M.x86.R_AH) {
+	case 0x00:
+		// set video mode
+		// BDA offset 49h is current video mode
+		my_wrb(0x449, M.x86.R_AL);
+		if (M.x86.R_AL > 7)
+			M.x86.R_AL = 0x20;
+		else if (M.x86.R_AL == 6)
+			M.x86.R_AL = 0x3f;
+		else
+			M.x86.R_AL = 0x30;
+		break;
+	case 0x01:
+		// set cursor shape
+		// ignore
+		break;
+	case 0x02:
+		// set cursor position
+		// BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
+		// BDA offset 50h-60h are 8 cursor position words for
+		// eight possible video pages
+		my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
+		break;
+	case 0x03:
+		//get cursor position
+		// BH: pagenumber
+		// BDA offset 50h-60h are 8 cursor position words for
+		// eight possible video pages
+		M.x86.R_AX = 0;
+		M.x86.R_CH = 0;	// start scan line ???
+		M.x86.R_CL = 0;	// end scan line ???
+		M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
+		break;
+	case 0x05:
+		// set active page
+		// BDA offset 62h is current page number
+		my_wrb(0x462, M.x86.R_AL);
+		break;
+	case 0x06:
+		//scroll up windows
+		break;
+	case 0x07:
+		//scroll down windows
+		break;
+	case 0x08:
+		//read character and attribute at position
+		M.x86.R_AH = 0x07;	// white-on-black
+		M.x86.R_AL = 0x20;	// a space...
+		break;
+	case 0x09:
+		// write character and attribute
+		//AL: char, BH: page number, BL: attribute, CX: number of times to write
+		//BDA offset 62h is current page number
+		CHECK_DBG(DEBUG_PRINT_INT10) {
+			uint32_t i = 0;
+			if (M.x86.R_BH == my_rdb(0x462)) {
+				for (i = 0; i < M.x86.R_CX; i++)
+					printf("%c", M.x86.R_AL);
+			}
+		}
+		break;
+	case 0x0a:
+		// write character
+		//AL: char, BH: page number, BL: attribute, CX: number of times to write
+		//BDA offset 62h is current page number
+		CHECK_DBG(DEBUG_PRINT_INT10) {
+			uint32_t i = 0;
+			if (M.x86.R_BH == my_rdb(0x462)) {
+				for (i = 0; i < M.x86.R_CX; i++)
+					printf("%c", M.x86.R_AL);
+			}
+		}
+		break;
+	case 0x0e:
+		// teletype output: write character and advance cursor...
+		//AL: char, BH: page number, BL: attribute
+		//BDA offset 62h is current page number
+		CHECK_DBG(DEBUG_PRINT_INT10) {
+			// we ignore the pagenumber on this call...
+			//if (M.x86.R_BH == my_rdb(0x462))
+			{
+				printf("%c", M.x86.R_AL);
+				// for debugging, to read all lines
+				//if (M.x86.R_AL == 0xd) // carriage return
+				//      printf("\n");
+			}
+		}
+		break;
+	case 0x0f:
+		// get video mode
+		// BDA offset 49h is current video mode
+		// BDA offset 62h is current page number
+		// BDA offset 4ah is columns on screen
+		M.x86.R_AH = 80;	//number of character columns... we hardcode it to 80
+		M.x86.R_AL = my_rdb(0x449);
+		M.x86.R_BH = my_rdb(0x462);
+		break;
+	default:
+		printf("%s(): unknown function (%x) for int10 handler.\n",
+		       __FUNCTION__, M.x86.R_AH);
+		DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
+				  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
+				  M.x86.R_DX);
+		HALT_SYS();
+		break;
+	}
+}
+
+// this table translates ASCII chars into their XT scan codes:
+static uint8_t keycode_table[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 0 - 7
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 8 - 15
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 16 - 23
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 24 - 31
+	0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28,	// 32 - 39
+	0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35,	// 40 - 47
+	0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,	// 48 - 55
+	0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35,	// 56 - 63
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 64 - 71
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 72 - 79
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 80 - 87
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 88 - 95
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 96 - 103
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 104 - 111
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 112 - 119
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// 120 - 127
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// ...
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+}
+
+;
+
+void
+translate_keycode(uint64_t * keycode)
+{
+	uint8_t scan_code = 0;
+	uint8_t char_code = 0;
+	if (*keycode < 256) {
+		scan_code = keycode_table[*keycode];
+		char_code = (uint8_t) * keycode & 0xff;
+	} else {
+		switch (*keycode) {
+		case 0x1b50:
+			// F1
+			scan_code = 0x3b;
+			char_code = 0x0;
+			break;
+		default:
+			printf("%s(): unknown multibyte keycode: %llx\n",
+			       __FUNCTION__, *keycode);
+			break;
+		}
+	}
+	//assemble scan/char code in keycode
+	*keycode = (uint64_t) ((((uint16_t) scan_code) << 8) | char_code);
+}
+
+// handle int16 (Keyboard BIOS Interrupt)
+void
+handleInt16()
+{
+	// keyboard buffer is in BIOS Memory Area:
+	// offset 0x1a (WORD) pointer to next char in keybuffer
+	// offset 0x1c (WORD) pointer to next insert slot in keybuffer
+	// offset 0x1e-0x3e: 16 WORD Ring Buffer
+	// since we currently always read the char from the FW buffer,
+	// we misuse the ring buffer, we use it as pointer to a uint64_t that stores
+	// multi-byte keys (e.g. special keys in VT100 terminal)
+	// and as long as a key is available (not 0) we dont read further keys
+	uint64_t *keycode = (uint64_t *) (M.mem_base + 0x41e);
+	int8_t c;
+	// function number in AH
+	DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
+			  __FUNCTION__, M.x86.R_AH);
+	DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
+			  M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
+	switch (M.x86.R_AH) {
+	case 0x00:
+		// get keystroke
+		if (*keycode) {
+			M.x86.R_AX = (uint16_t) * keycode;
+			// clear keycode
+			*keycode = 0;
+		} else {
+			M.x86.R_AH = 0x61;	// scancode for space key
+			M.x86.R_AL = 0x20;	// a space
+		}
+		break;
+	case 0x01:
+		// check keystroke
+		// ZF set = no keystroke
+		// read first byte of key code
+		if (*keycode) {
+			// already read, but not yet taken
+			CLEAR_FLAG(F_ZF);
+			M.x86.R_AX = (uint16_t) * keycode;
+		} else {
+			c = getchar();
+			if (c == -1) {
+				// no key available
+				SET_FLAG(F_ZF);
+			} else {
+				*keycode = c;
+
+				// since after an ESC it may take a while to receive the next char,
+				// we send something that is not shown on the screen, and then try to get
+				// the next char
+				// TODO: only after ESC?? what about other multibyte keys
+				printf("tt%c%c", 0x08, 0x08);	// 0x08 == Backspace
+
+				while ((c = getchar()) != -1) {
+					*keycode = (*keycode << 8) | c;
+					DEBUG_PRINTF(" key read: %0llx\n",
+						     *keycode);
+				}
+				translate_keycode(keycode);
+				DEBUG_PRINTF(" translated key: %0llx\n",
+					     *keycode);
+				if (*keycode == 0) {
+					//not found
+					SET_FLAG(F_ZF);
+				} else {
+					CLEAR_FLAG(F_ZF);
+					M.x86.R_AX = (uint16_t) * keycode;
+					//X86EMU_trace_on();
+					//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+				}
+			}
+		}
+		break;
+	default:
+		printf("%s(): unknown function (%x) for int16 handler.\n",
+		       __FUNCTION__, M.x86.R_AH);
+		DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
+				  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
+				  M.x86.R_DX);
+		HALT_SYS();
+		break;
+	}
+}
+
+// handle int1a (PCI BIOS Interrupt)
+void
+handleInt1a()
+{
+	// function number in AX
+	uint8_t bus, devfn, offs;
+	switch (M.x86.R_AX) {
+	case 0xb101:
+		// Installation check
+		CLEAR_FLAG(F_CF);	// clear CF
+		M.x86.R_EDX = 0x20494350;	// " ICP" endian swapped "PCI "
+		M.x86.R_AL = 0x1;	// Config Space Mechanism 1 supported
+		M.x86.R_BX = 0x0210;	// PCI Interface Level Version 2.10
+		M.x86.R_CL = 0xff;	// number of last PCI Bus in system TODO: check!
+		break;
+	case 0xb102:
+		// Find PCI Device
+		// NOTE: we currently only allow the device to find itself...
+		// it SHOULD be all we ever need...
+		// device_id in CX, vendor_id in DX
+		// device index in SI (i.e. if multiple devices with same vendor/device id
+		// are connected). We currently only support device index 0
+		DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
+				  __FUNCTION__, M.x86.R_AX);
+		if ((M.x86.R_CX == bios_device.pci_device_id)
+		    && (M.x86.R_DX == bios_device.pci_vendor_id)
+		    // device index must be 0
+		    && (M.x86.R_SI == 0)) {
+			CLEAR_FLAG(F_CF);
+			M.x86.R_AH = 0x00;	// return code: success
+			M.x86.R_BH = bios_device.bus;
+			M.x86.R_BL = bios_device.devfn;
+			DEBUG_PRINTF_INTR
+			    ("%s(): function %x: PCI Find Device --> 0x%04x\n",
+			     __FUNCTION__, M.x86.R_AX, M.x86.R_BX);
+		} else {
+			DEBUG_PRINTF_INTR
+			    ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/0) \n",
+			     __FUNCTION__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
+			     M.x86.R_SI, bios_device.pci_device_id,
+			     bios_device.pci_vendor_id);
+			SET_FLAG(F_CF);
+			M.x86.R_AH = 0x86;	// return code: device not found
+		}
+		break;
+	case 0xb108:		//read configuration byte
+	case 0xb109:		//read configuration word
+	case 0xb10a:		//read configuration dword
+		bus = M.x86.R_BH;
+		devfn = M.x86.R_BL;
+		offs = M.x86.R_DI;
+		if ((bus != bios_device.bus)
+		    || (devfn != bios_device.devfn)) {
+			// fail accesses to any device but ours...
+			printf
+			    ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
+			     __FUNCTION__, bus, bios_device.bus, devfn,
+			     bios_device.devfn, offs);
+			SET_FLAG(F_CF);
+			M.x86.R_AH = 0x87;	//return code: bad pci register
+			HALT_SYS();
+			return;
+		} else {
+			switch (M.x86.R_AX) {
+			case 0xb108:
+				M.x86.R_CL =
+				    (uint8_t) rtas_pci_config_read(bios_device.
+								   puid, 1,
+								   bus, devfn,
+								   offs);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_CL);
+				break;
+			case 0xb109:
+				M.x86.R_CX =
+				    (uint16_t) rtas_pci_config_read(bios_device.
+								    puid, 2,
+								    bus, devfn,
+								    offs);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_CX);
+				break;
+			case 0xb10a:
+				M.x86.R_ECX =
+				    (uint32_t) rtas_pci_config_read(bios_device.
+								    puid, 4,
+								    bus, devfn,
+								    offs);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_ECX);
+				break;
+			}
+			CLEAR_FLAG(F_CF);
+			M.x86.R_AH = 0x0;	// return code: success
+		}
+		break;
+	case 0xb10b:		//write configuration byte
+	case 0xb10c:		//write configuration word
+	case 0xb10d:		//write configuration dword
+		bus = M.x86.R_BH;
+		devfn = M.x86.R_BL;
+		offs = M.x86.R_DI;
+		if ((bus != bios_device.bus)
+		    || (devfn != bios_device.devfn)) {
+			// fail accesses to any device but ours...
+			printf
+			    ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
+			     __FUNCTION__, bus, bios_device.bus, devfn,
+			     bios_device.devfn, offs);
+			SET_FLAG(F_CF);
+			M.x86.R_AH = 0x87;	//return code: bad pci register
+			HALT_SYS();
+			return;
+		} else {
+			switch (M.x86.R_AX) {
+			case 0xb10b:
+				rtas_pci_config_write(bios_device.puid, 1, bus,
+						      devfn, offs, M.x86.R_CL);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_CL);
+				break;
+			case 0xb10c:
+				rtas_pci_config_write(bios_device.puid, 2, bus,
+						      devfn, offs, M.x86.R_CX);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_CX);
+				break;
+			case 0xb10d:
+				rtas_pci_config_write(bios_device.puid, 4, bus,
+						      devfn, offs, M.x86.R_ECX);
+				DEBUG_PRINTF_INTR
+				    ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
+				     __FUNCTION__, M.x86.R_AX, offs,
+				     M.x86.R_ECX);
+				break;
+			}
+			CLEAR_FLAG(F_CF);
+			M.x86.R_AH = 0x0;	// return code: success
+		}
+		break;
+	default:
+		printf("%s(): unknown function (%x) for int1a handler.\n",
+		       __FUNCTION__, M.x86.R_AX);
+		DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
+				  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
+				  M.x86.R_DX);
+		HALT_SYS();
+		break;
+	}
+}
+
+// main Interrupt Handler routine, should be registered as x86emu interrupt handler
+void
+handleInterrupt(int intNum)
+{
+	uint8_t int_handled = 0;
+#ifndef DEBUG_PRINT_INT10
+	// this printf makes output by int 10 unreadable...
+	// so we only enable it, if int10 print is disabled
+	DEBUG_PRINTF_INTR("%s(%x)\n", __FUNCTION__, intNum);
+#endif
+	switch (intNum) {
+	case 0x10:		//BIOS video interrupt
+	case 0x42:		// INT 10h relocated by EGA/VGA BIOS
+	case 0x6d:		// INT 10h relocated by VGA BIOS
+		// get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
+		if ((my_rdl(intNum * 4) == 0xF000F065) ||	//F000:F065 is default BIOS interrupt handler address
+		    (my_rdl(intNum * 4) == 0xF4F4F4F4))	//invalid
+		{
+#if 0
+			// ignore interrupt...
+			DEBUG_PRINTF_INTR
+			    ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
+			     __FUNCTION__, intNum, my_rdl(intNum * 4));
+			DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
+					  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
+					  M.x86.R_DX);
+			//HALT_SYS();
+#endif
+			handleInt10();
+			int_handled = 1;
+		}
+		break;
+	case 0x16:
+		// Keyboard BIOS Interrupt
+		handleInt16();
+		int_handled = 1;
+		break;
+	case 0x1a:
+		// PCI BIOS Interrupt
+		handleInt1a();
+		int_handled = 1;
+		break;
+	default:
+		printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
+		       my_rdl(intNum * 4));
+		DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
+				  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
+				  M.x86.R_DX);
+		int_handled = 1;
+		HALT_SYS();
+		break;
+	}
+	// if we did not handle the interrupt, jump to the interrupt vector...
+	if (!int_handled) {
+		setupInt(intNum);
+	}
+}
+
+// prepare and execute Interrupt 10 (VGA Interrupt)
+void
+runInt10()
+{
+	// Initialize stack and data segment
+	M.x86.R_SS = STACK_SEGMENT;
+	M.x86.R_DS = DATA_SEGMENT;
+	M.x86.R_SP = STACK_START_OFFSET;
+
+	// push a HLT instruction and a pointer to it onto the stack
+	// any return will pop the pointer and jump to the HLT, thus
+	// exiting (more or less) cleanly
+	push_word(0xf4f4);	//F4=HLT
+	//push_word(M.x86.R_SS);
+	//push_word(M.x86.R_SP + 2);
+
+	// setupInt will push the current CS and IP to the stack to return to it,
+	// but we want to halt, so set CS:IP to the HLT instruction we just pushed
+	// to the stack
+	M.x86.R_CS = M.x86.R_SS;
+	M.x86.R_IP = M.x86.R_SP;	// + 4;
+
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	CHECK_DBG(DEBUG_JMP) {
+		M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
+		M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
+		M.x86.debug |= DEBUG_TRACECALL_F;
+		M.x86.debug |= DEBUG_TRACECALL_REGS_F;
+	}
+	setupInt(0x10);
+	DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
+			  __FUNCTION__);
+	X86EMU_exec();
+	DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__);
+}
+
+// prepare and execute Interrupt 13 (Disk Interrupt)
+void
+runInt13()
+{
+	// Initialize stack and data segment
+	M.x86.R_SS = STACK_SEGMENT;
+	M.x86.R_DS = DATA_SEGMENT;
+	M.x86.R_SP = STACK_START_OFFSET;
+
+	// push a HLT instruction and a pointer to it onto the stack
+	// any return will pop the pointer and jump to the HLT, thus
+	// exiting (more or less) cleanly
+	push_word(0xf4f4);	//F4=HLT
+	//push_word(M.x86.R_SS);
+	//push_word(M.x86.R_SP + 2);
+
+	// setupInt will push the current CS and IP to the stack to return to it,
+	// but we want to halt, so set CS:IP to the HLT instruction we just pushed
+	// to the stack
+	M.x86.R_CS = M.x86.R_SS;
+	M.x86.R_IP = M.x86.R_SP;
+
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	CHECK_DBG(DEBUG_JMP) {
+		M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
+		M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
+		M.x86.debug |= DEBUG_TRACECALL_F;
+		M.x86.debug |= DEBUG_TRACECALL_REGS_F;
+	}
+
+	setupInt(0x13);
+	DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
+			  __FUNCTION__);
+	X86EMU_exec();
+	DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h
new file mode 100644
index 0000000..9c09086
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef _BIOSEMU_INTERRUPT_H_
+#define _BIOSEMU_INTERRUPT_H_
+
+void handleInterrupt(int intNum);
+
+void runInt10();
+
+void runInt13();
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.c
new file mode 100644
index 0000000..0e46166
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.c
@@ -0,0 +1,431 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <cpu.h>
+#include "device.h"
+#include "rtas.h"
+#include "debug.h"
+#include "device.h"
+#include <stdint.h>
+#include <x86emu/x86emu.h>
+#include <time.h>
+
+// those are defined in net-snk/oflib/pci.c
+extern unsigned int read_io(void *, size_t);
+extern int write_io(void *, unsigned int, size_t);
+
+//defined in net-snk/kernel/timer.c
+extern uint64_t get_time(void);
+
+// these are not used, only needed for linking,  must be overridden using X86emu_setupPioFuncs
+// with the functions and struct below
+void
+outb(uint8_t val, uint16_t port)
+{
+	printf("WARNING: outb not implemented!\n");
+	HALT_SYS();
+}
+
+void
+outw(uint16_t val, uint16_t port)
+{
+	printf("WARNING: outw not implemented!\n");
+	HALT_SYS();
+}
+
+void
+outl(uint32_t val, uint16_t port)
+{
+	printf("WARNING: outl not implemented!\n");
+	HALT_SYS();
+}
+
+uint8_t
+inb(uint16_t port)
+{
+	printf("WARNING: inb not implemented!\n");
+	HALT_SYS();
+	return 0;
+}
+
+uint16_t
+inw(uint16_t port)
+{
+	printf("WARNING: inw not implemented!\n");
+	HALT_SYS();
+	return 0;
+}
+
+uint32_t
+inl(uint16_t port)
+{
+	printf("WARNING: inl not implemented!\n");
+	HALT_SYS();
+	return 0;
+}
+
+uint32_t pci_cfg_read(X86EMU_pioAddr addr, uint8_t size);
+void pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size);
+uint8_t handle_port_61h();
+
+uint8_t
+my_inb(X86EMU_pioAddr addr)
+{
+	uint8_t rval = 0xFF;
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
+				addr);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		rval = read_io((void *)translated_addr, 1);
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __FUNCTION__,
+				addr, rval);
+		return rval;
+	} else {
+		switch (addr) {
+		case 0x61:
+			//8254 KB Controller / Timer Port
+			rval = handle_port_61h();
+			//DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __FUNCTION__, addr, rval);
+			return rval;
+			break;
+		case 0xCFC:
+		case 0xCFD:
+		case 0xCFE:
+		case 0xCFF:
+			// PCI Config Mechanism 1 Ports
+			return (uint8_t) pci_cfg_read(addr, 1);
+			break;
+		case 0x0a:
+			CHECK_DBG(DEBUG_INTR) {
+				X86EMU_trace_on();
+			}
+			M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+			//HALT_SYS();
+			// no break, intentional fall-through to default!!
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x) reading from bios_device.io_buffer\n",
+			     __FUNCTION__, addr);
+			rval = *((uint8_t *) (bios_device.io_buffer + addr));
+			DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
+					__FUNCTION__, addr, rval);
+			return rval;
+			break;
+		}
+	}
+}
+
+uint16_t
+my_inw(X86EMU_pioAddr addr)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
+				addr);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		uint16_t rval;
+		if ((translated_addr & (uint64_t) 0x1) == 0) {
+			// 16 bit aligned access...
+			uint16_t tempval = read_io((void *)translated_addr, 2);
+			//little endian conversion
+			rval = in16le((void *) &tempval);
+		} else {
+			// unaligned access, read single bytes, little-endian
+			rval = (read_io((void *)translated_addr, 1) << 8)
+				| (read_io((void *)(translated_addr + 1), 1));
+		}
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__,
+				addr, rval);
+		return rval;
+	} else {
+		switch (addr) {
+		case 0xCFC:
+		case 0xCFE:
+			//PCI Config Mechanism 1
+			return (uint16_t) pci_cfg_read(addr, 2);
+			break;
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x) reading from bios_device.io_buffer\n",
+			     __FUNCTION__, addr);
+			uint16_t rval =
+			    in16le((void *) bios_device.io_buffer + addr);
+			DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
+					__FUNCTION__, addr, rval);
+			return rval;
+			break;
+		}
+	}
+}
+
+uint32_t
+my_inl(X86EMU_pioAddr addr)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
+				addr);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		uint32_t rval;
+		if ((translated_addr & (uint64_t) 0x3) == 0) {
+			// 32 bit aligned access...
+			uint32_t tempval = read_io((void *) translated_addr, 4);
+			//little endian conversion
+			rval = in32le((void *) &tempval);
+		} else {
+			// unaligned access, read single bytes, little-endian
+			rval = (read_io((void *)(translated_addr), 1) << 24)
+				| (read_io((void *)(translated_addr + 1), 1) << 16)
+				| (read_io((void *)(translated_addr + 2), 1) << 8)
+				| (read_io((void *)(translated_addr + 3), 1));
+		}
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__,
+				addr, rval);
+		return rval;
+	} else {
+		switch (addr) {
+		case 0xCFC:
+			//PCI Config Mechanism 1
+			return pci_cfg_read(addr, 4);
+			break;
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x) reading from bios_device.io_buffer\n",
+			     __FUNCTION__, addr);
+			uint32_t rval =
+			    in32le((void *) bios_device.io_buffer + addr);
+			DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
+					__FUNCTION__, addr, rval);
+			return rval;
+			break;
+		}
+	}
+}
+
+void
+my_outb(X86EMU_pioAddr addr, uint8_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
+				__FUNCTION__, addr, val);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		write_io((void *) translated_addr, val, 1);
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __FUNCTION__,
+				addr, val);
+	} else {
+		switch (addr) {
+		case 0xCFC:
+		case 0xCFD:
+		case 0xCFE:
+		case 0xCFF:
+			// PCI Config Mechanism 1 Ports
+			pci_cfg_write(addr, val, 1);
+			break;
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
+			     __FUNCTION__, addr, val);
+			*((uint8_t *) (bios_device.io_buffer + addr)) = val;
+			break;
+		}
+	}
+}
+
+void
+my_outw(X86EMU_pioAddr addr, uint16_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
+				__FUNCTION__, addr, val);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		if ((translated_addr & (uint64_t) 0x1) == 0) {
+			// little-endian conversion
+			uint16_t tempval = in16le((void *) &val);
+			// 16 bit aligned access...
+			write_io((void *) translated_addr, tempval, 2);
+		} else {
+			// unaligned access, write single bytes, little-endian
+			write_io(((void *) (translated_addr + 1)),
+				(uint8_t) ((val & 0xFF00) >> 8), 1);
+			write_io(((void *) translated_addr),
+				(uint8_t) (val & 0x00FF), 1);
+		}
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__,
+				addr, val);
+	} else {
+		switch (addr) {
+		case 0xCFC:
+		case 0xCFE:
+			// PCI Config Mechanism 1 Ports
+			pci_cfg_write(addr, val, 2);
+			break;
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
+			     __FUNCTION__, addr, val);
+			out16le((void *) bios_device.io_buffer + addr, val);
+			break;
+		}
+	}
+}
+
+void
+my_outl(X86EMU_pioAddr addr, uint32_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access Device I/O (BAR or Legacy...)
+		DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
+				__FUNCTION__, addr, val);
+		//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		if ((translated_addr & (uint64_t) 0x3) == 0) {
+			// little-endian conversion
+			uint32_t tempval = in32le((void *) &val);
+			// 32 bit aligned access...
+			write_io((void *) translated_addr,  tempval, 4);
+		} else {
+			// unaligned access, write single bytes, little-endian
+			write_io(((void *) translated_addr + 3),
+			    (uint8_t) ((val & 0xFF000000) >> 24), 1);
+			write_io(((void *) translated_addr + 2),
+			    (uint8_t) ((val & 0x00FF0000) >> 16), 1);
+			write_io(((void *) translated_addr + 1),
+			    (uint8_t) ((val & 0x0000FF00) >> 8), 1);
+			write_io(((void *) translated_addr),
+			    (uint8_t) (val & 0x000000FF), 1);
+		}
+		DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__,
+				addr, val);
+	} else {
+		switch (addr) {
+		case 0xCFC:
+			// PCI Config Mechanism 1 Ports
+			pci_cfg_write(addr, val, 4);
+			break;
+		default:
+			DEBUG_PRINTF_IO
+			    ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
+			     __FUNCTION__, addr, val);
+			out32le((void *) bios_device.io_buffer + addr, val);
+			break;
+		}
+	}
+}
+
+uint32_t
+pci_cfg_read(X86EMU_pioAddr addr, uint8_t size)
+{
+	uint32_t rval = 0xFFFFFFFF;
+	if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
+		// PCI Configuration Mechanism 1 step 1
+		// write to 0xCF8, sets bus, device, function and Config Space offset
+		// later read from 0xCFC-0xCFF returns the value...
+		uint8_t bus, devfn, offs;
+		uint32_t port_cf8_val = my_inl(0xCF8);
+		if ((port_cf8_val & 0x80000000) != 0) {
+			//highest bit enables config space mapping
+			bus = (port_cf8_val & 0x00FF0000) >> 16;
+			devfn = (port_cf8_val & 0x0000FF00) >> 8;
+			offs = (port_cf8_val & 0x000000FF);
+			offs += (addr - 0xCFC);	// if addr is not 0xcfc, the offset is moved accordingly
+			if ((bus != bios_device.bus)
+			    || (devfn != bios_device.devfn)) {
+				// fail accesses to any device but ours...
+				printf
+				    ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
+				     bus, devfn, offs);
+				HALT_SYS();
+			} else {
+				rval =
+				    (uint32_t) rtas_pci_config_read(bios_device.
+								    puid, size,
+								    bus, devfn,
+								    offs);
+				DEBUG_PRINTF_IO
+				    ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
+				     __FUNCTION__, addr, offs, size, rval);
+			}
+		}
+	}
+	return rval;
+}
+
+void
+pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size)
+{
+	if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
+		// PCI Configuration Mechanism 1 step 1
+		// write to 0xCF8, sets bus, device, function and Config Space offset
+		// later write to 0xCFC-0xCFF sets the value...
+		uint8_t bus, devfn, offs;
+		uint32_t port_cf8_val = my_inl(0xCF8);
+		if ((port_cf8_val & 0x80000000) != 0) {
+			//highest bit enables config space mapping
+			bus = (port_cf8_val & 0x00FF0000) >> 16;
+			devfn = (port_cf8_val & 0x0000FF00) >> 8;
+			offs = (port_cf8_val & 0x000000FF);
+			offs += (addr - 0xCFC);	// if addr is not 0xcfc, the offset is moved accordingly
+			if ((bus != bios_device.bus)
+			    || (devfn != bios_device.devfn)) {
+				// fail accesses to any device but ours...
+				printf
+				    ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
+				     bus, devfn, offs);
+				HALT_SYS();
+			} else {
+				rtas_pci_config_write(bios_device.puid,
+						      size, bus, devfn, offs,
+						      val);
+				DEBUG_PRINTF_IO
+				    ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
+				     __FUNCTION__, addr, offs, size, val);
+			}
+		}
+	}
+}
+
+uint8_t
+handle_port_61h()
+{
+	static uint64_t last_time = 0;
+	uint64_t curr_time = get_time();
+	uint64_t time_diff;	// time since last call
+	uint32_t period_ticks;	// length of a period in ticks
+	uint32_t nr_periods;	//number of periods passed since last call
+	// bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
+	time_diff = curr_time - last_time;
+	// at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
+	// TODO: as long as the frequency does not change, we should not calculate this every time
+	period_ticks = (15 * tb_freq) / 1000000;
+	nr_periods = time_diff / period_ticks;
+	// if the number if ticks passed since last call is odd, we toggle bit 4
+	if ((nr_periods % 2) != 0) {
+		*((uint8_t *) (bios_device.io_buffer + 0x61)) ^= 0x10;
+	}
+	//finally read the value from the io_buffer
+	return *((uint8_t *) (bios_device.io_buffer + 0x61));
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.h
new file mode 100644
index 0000000..5a0bb4b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/io.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _BIOSEMU_IO_H_
+#define _BIOSEMU_IO_H_
+#include <x86emu/x86emu.h>
+#include <stdint.h>
+
+uint8_t my_inb(X86EMU_pioAddr addr);
+
+uint16_t my_inw(X86EMU_pioAddr addr);
+
+uint32_t my_inl(X86EMU_pioAddr addr);
+
+void my_outb(X86EMU_pioAddr addr, uint8_t val);
+
+void my_outw(X86EMU_pioAddr addr, uint16_t val);
+
+void my_outl(X86EMU_pioAddr addr, uint32_t val);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.c
new file mode 100644
index 0000000..b214a96
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.c
@@ -0,0 +1,463 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <cpu.h>
+#include "debug.h"
+#include "device.h"
+#include "x86emu/x86emu.h"
+#include "biosemu.h"
+#include <time.h>
+
+// define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...)
+#ifdef DEBUG
+static uint8_t in_check = 0;	// to avoid recursion...
+uint16_t ebda_segment;
+uint32_t ebda_size;
+
+//TODO: these macros have grown so large, that they should be changed to an inline function,
+//just for the sake of readability...
+
+//declare prototypes of the functions to follow, for use in DEBUG_CHECK_VMEM_ACCESS
+uint8_t my_rdb(uint32_t);
+uint16_t my_rdw(uint32_t);
+uint32_t my_rdl(uint32_t);
+
+#define DEBUG_CHECK_VMEM_READ(_addr, _rval) \
+   if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
+         in_check = 1; \
+         /* determine ebda_segment and size \
+          * since we are using my_rdx calls, make sure, this is after setting in_check! */ \
+         /* offset 03 in BDA is EBDA segment */ \
+         ebda_segment = my_rdw(0x40e); \
+         /* first value in ebda is size in KB */ \
+         ebda_size = my_rdb(ebda_segment << 4) * 1024; \
+			/* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \
+			if (_addr < 0x400) { \
+				DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", \
+						__FUNCTION__, _addr / 4, _rval); \
+			} \
+			/* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \
+			else if ((_addr >= 0x400) && (addr < 0x500)) { \
+				DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", \
+						__FUNCTION__, _addr, _rval); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* access to first 64k of memory... */ \
+			else if (_addr < 0x10000) { \
+				DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", \
+						__FUNCTION__, _addr, _rval); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* read from PMM_CONV_SEGMENT */ \
+			else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", \
+						__FUNCTION__, PMM_CONV_SEGMENT, _addr, _rval); \
+				/* HALT_SYS(); */ \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* read from PNP_DATA_SEGMENT */ \
+			else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", \
+						__FUNCTION__, PNP_DATA_SEGMENT, _addr, _rval); \
+				/* HALT_SYS(); */ \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* read from EBDA Segment */ \
+			else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", \
+						__FUNCTION__, ebda_segment, ebda_size, _addr, _rval); \
+			} \
+			/* read from BIOS_DATA_SEGMENT */ \
+			else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", \
+						__FUNCTION__, BIOS_DATA_SEGMENT, _addr, _rval); \
+				/* for PMM debugging */ \
+				/*if (_addr == BIOS_DATA_SEGMENT << 4) { \
+					X86EMU_trace_on(); \
+					M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; \
+				}*/ \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+         in_check = 0; \
+   }
+#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \
+   if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
+         in_check = 1; \
+         /* determine ebda_segment and size \
+          * since we are using my_rdx calls, make sure, this is after setting in_check! */ \
+         /* offset 03 in BDA is EBDA segment */ \
+         ebda_segment = my_rdw(0x40e); \
+         /* first value in ebda is size in KB */ \
+         ebda_size = my_rdb(ebda_segment << 4) * 1024; \
+			/* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \
+			if (_addr < 0x400) { \
+				DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \
+						__FUNCTION__, _addr / 4, _val); \
+			} \
+			/* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \
+			else if ((_addr >= 0x400) && (addr < 0x500)) { \
+				DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", \
+						__FUNCTION__, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* access to first 64k of memory...*/ \
+			else if (_addr < 0x10000) { \
+				DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \
+						__FUNCTION__, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* write to PMM_CONV_SEGMENT... */ \
+			else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", \
+						__FUNCTION__, PMM_CONV_SEGMENT, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* write to PNP_DATA_SEGMENT... */ \
+			else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", \
+						__FUNCTION__, PNP_DATA_SEGMENT, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* write to EBDA Segment... */ \
+			else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", \
+						__FUNCTION__, ebda_segment, ebda_size, _addr, _val); \
+			} \
+			/* write to BIOS_DATA_SEGMENT... */ \
+			else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", \
+						__FUNCTION__, BIOS_DATA_SEGMENT, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+			/* write to current CS segment... */ \
+			else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { \
+				DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", \
+						__FUNCTION__, M.x86.R_CS, _addr, _val); \
+				/* dump registers */ \
+				/* x86emu_dump_xregs(); */ \
+			} \
+         in_check = 0; \
+   }
+#else
+#define DEBUG_CHECK_VMEM_READ(_addr, _rval)
+#define DEBUG_CHECK_VMEM_WRITE(_addr, _val)
+#endif
+
+//defined in net-snk/kernel/timer.c
+extern uint64_t get_time(void);
+
+void update_time(uint32_t);
+
+// read byte from memory
+uint8_t
+my_rdb(uint32_t addr)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	uint8_t rval;
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
+				 __FUNCTION__, addr);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		set_ci();
+		rval = *((uint8_t *) translated_addr);
+		clr_ci();
+		DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __FUNCTION__, addr,
+				 rval);
+		return rval;
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* read from virtual memory */
+		rval = *((uint8_t *) (M.mem_base + addr));
+		DEBUG_CHECK_VMEM_READ(addr, rval);
+		return rval;
+	}
+	return -1;
+}
+
+//read word from memory
+uint16_t
+my_rdw(uint32_t addr)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	uint16_t rval;
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
+				 __FUNCTION__, addr);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		// check for legacy memory, because of the remapping to BARs, the reads must
+		// be byte reads...
+		if ((addr >= 0xa0000) && (addr < 0xc0000)) {
+			//read bytes a using my_rdb, because of the remapping to BARs
+			//words may not be contiguous in memory, so we need to translate
+			//every address...
+			rval = ((uint8_t) my_rdb(addr)) |
+			    (((uint8_t) my_rdb(addr + 1)) << 8);
+		} else {
+			if ((translated_addr & (uint64_t) 0x1) == 0) {
+				// 16 bit aligned access...
+				set_ci();
+				rval = in16le((void *) translated_addr);
+				clr_ci();
+			} else {
+				// unaligned access, read single bytes
+				set_ci();
+				rval = (*((uint8_t *) translated_addr)) |
+				    (*((uint8_t *) translated_addr + 1) << 8);
+				clr_ci();
+			}
+		}
+		DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __FUNCTION__, addr,
+				 rval);
+		return rval;
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* read from virtual memory */
+		rval = in16le((void *) (M.mem_base + addr));
+		DEBUG_CHECK_VMEM_READ(addr, rval);
+		return rval;
+	}
+	return -1;
+}
+
+//read long from memory
+uint32_t
+my_rdl(uint32_t addr)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	uint32_t rval;
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
+				 __FUNCTION__, addr);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		// check for legacy memory, because of the remapping to BARs, the reads must
+		// be byte reads...
+		if ((addr >= 0xa0000) && (addr < 0xc0000)) {
+			//read bytes a using my_rdb, because of the remapping to BARs
+			//dwords may not be contiguous in memory, so we need to translate
+			//every address...
+			rval = ((uint8_t) my_rdb(addr)) |
+			    (((uint8_t) my_rdb(addr + 1)) << 8) |
+			    (((uint8_t) my_rdb(addr + 2)) << 16) |
+			    (((uint8_t) my_rdb(addr + 3)) << 24);
+		} else {
+			if ((translated_addr & (uint64_t) 0x3) == 0) {
+				// 32 bit aligned access...
+				set_ci();
+				rval = in32le((void *) translated_addr);
+				clr_ci();
+			} else {
+				// unaligned access, read single bytes
+				set_ci();
+				rval = (*((uint8_t *) translated_addr)) |
+				    (*((uint8_t *) translated_addr + 1) << 8) |
+				    (*((uint8_t *) translated_addr + 2) << 16) |
+				    (*((uint8_t *) translated_addr + 3) << 24);
+				clr_ci();
+			}
+		}
+		DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __FUNCTION__, addr,
+				 rval);
+		//HALT_SYS();
+		return rval;
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* read from virtual memory */
+		rval = in32le((void *) (M.mem_base + addr));
+		switch (addr) {
+		case 0x46c:
+			//BDA Time Data, update it, before reading
+			update_time(rval);
+			rval = in32le((void *) (M.mem_base + addr));
+			break;
+		}
+		DEBUG_CHECK_VMEM_READ(addr, rval);
+		return rval;
+	}
+	return -1;
+}
+
+//write byte to memory
+void
+my_wrb(uint32_t addr, uint8_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
+				 __FUNCTION__, addr, val);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		set_ci();
+		*((uint8_t *) translated_addr) = val;
+		clr_ci();
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* write to virtual memory */
+		DEBUG_CHECK_VMEM_WRITE(addr, val);
+		*((uint8_t *) (M.mem_base + addr)) = val;
+	}
+}
+
+void
+my_wrw(uint32_t addr, uint16_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
+				 __FUNCTION__, addr, val);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
+		// check for legacy memory, because of the remapping to BARs, the reads must
+		// be byte reads...
+		if ((addr >= 0xa0000) && (addr < 0xc0000)) {
+			//read bytes a using my_rdb, because of the remapping to BARs
+			//words may not be contiguous in memory, so we need to translate
+			//every address...
+			my_wrb(addr, (uint8_t) (val & 0x00FF));
+			my_wrb(addr + 1, (uint8_t) ((val & 0xFF00) >> 8));
+		} else {
+			if ((translated_addr & (uint64_t) 0x1) == 0) {
+				// 16 bit aligned access...
+				set_ci();
+				out16le((void *) translated_addr, val);
+				clr_ci();
+			} else {
+				// unaligned access, write single bytes
+				set_ci();
+				*((uint8_t *) translated_addr) =
+				    (uint8_t) (val & 0x00FF);
+				*((uint8_t *) translated_addr + 1) =
+				    (uint8_t) ((val & 0xFF00) >> 8);
+				clr_ci();
+			}
+		}
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* write to virtual memory */
+		DEBUG_CHECK_VMEM_WRITE(addr, val);
+		out16le((void *) (M.mem_base + addr), val);
+	}
+}
+void
+my_wrl(uint32_t addr, uint32_t val)
+{
+	uint64_t translated_addr = addr;
+	uint8_t translated = dev_translate_address(&translated_addr);
+	if (translated != 0) {
+		//translation successfull, access VGA Memory (BAR or Legacy...)
+		DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
+				 __FUNCTION__, addr, val);
+		//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n",  __FUNCTION__, addr, translated_addr);
+		// check for legacy memory, because of the remapping to BARs, the reads must
+		// be byte reads...
+		if ((addr >= 0xa0000) && (addr < 0xc0000)) {
+			//read bytes a using my_rdb, because of the remapping to BARs
+			//words may not be contiguous in memory, so we need to translate
+			//every address...
+			my_wrb(addr, (uint8_t) (val & 0x000000FF));
+			my_wrb(addr + 1, (uint8_t) ((val & 0x0000FF00) >> 8));
+			my_wrb(addr + 2, (uint8_t) ((val & 0x00FF0000) >> 16));
+			my_wrb(addr + 3, (uint8_t) ((val & 0xFF000000) >> 24));
+		} else {
+			if ((translated_addr & (uint64_t) 0x3) == 0) {
+				// 32 bit aligned access...
+				set_ci();
+				out32le((void *) translated_addr, val);
+				clr_ci();
+			} else {
+				// unaligned access, write single bytes
+				set_ci();
+				*((uint8_t *) translated_addr) =
+				    (uint8_t) (val & 0x000000FF);
+				*((uint8_t *) translated_addr + 1) =
+				    (uint8_t) ((val & 0x0000FF00) >> 8);
+				*((uint8_t *) translated_addr + 2) =
+				    (uint8_t) ((val & 0x00FF0000) >> 16);
+				*((uint8_t *) translated_addr + 3) =
+				    (uint8_t) ((val & 0xFF000000) >> 24);
+				clr_ci();
+			}
+		}
+	} else if (addr > M.mem_size) {
+		DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
+			     __FUNCTION__, addr);
+		//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
+		HALT_SYS();
+	} else {
+		/* write to virtual memory */
+		DEBUG_CHECK_VMEM_WRITE(addr, val);
+		out32le((void *) (M.mem_base + addr), val);
+	}
+}
+
+//update time in BIOS Data Area
+//DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz
+//byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00
+//cur_val is the current value, of offset 6c...
+void
+update_time(uint32_t cur_val)
+{
+	//for convenience, we let the start of timebase be at midnight, we currently dont support
+	//real daytime anyway...
+	uint64_t ticks_per_day = tb_freq * 60 * 24;
+	// at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second)
+	uint32_t period_ticks = (55 * tb_freq) / 1000;
+	uint64_t curr_time = get_time();
+	uint64_t ticks_since_midnight = curr_time % ticks_per_day;
+	uint32_t periods_since_midnight = ticks_since_midnight / period_ticks;
+	// if periods since midnight is smaller than last value, set overflow
+	// at BDA Offset 0x70
+	if (periods_since_midnight < cur_val) {
+		my_wrb(0x470, 1);
+	}
+	// store periods since midnight at BDA offset 0x6c
+	my_wrl(0x46c, periods_since_midnight);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.h
new file mode 100644
index 0000000..f0fbad9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/mem.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _BIOSEMU_MEM_H_
+#define _BIOSEMU_MEM_H_
+#include <x86emu/x86emu.h>
+#include <stdint.h>
+
+// read byte from memory
+uint8_t my_rdb(uint32_t addr);
+
+//read word from memory
+uint16_t my_rdw(uint32_t addr);
+
+//read long from memory
+uint32_t my_rdl(uint32_t addr);
+
+//write byte to memory
+void my_wrb(uint32_t addr, uint8_t val);
+
+//write word to memory
+void my_wrw(uint32_t addr, uint16_t val);
+
+//write long to memory
+void my_wrl(uint32_t addr, uint32_t val);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.c
new file mode 100644
index 0000000..06b1b18
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.c
@@ -0,0 +1,775 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <cpu.h>
+
+#include "debug.h"
+
+#include <x86emu/x86emu.h>
+#include <x86emu/regs.h>
+#include <x86emu/prim_ops.h>	// for push_word
+
+#include "biosemu.h"
+#include "io.h"
+#include "mem.h"
+#include "interrupt.h"
+#include "device.h"
+
+static X86EMU_memFuncs my_mem_funcs = {
+	my_rdb, my_rdw, my_rdl,
+	my_wrb, my_wrw, my_wrl
+};
+
+static X86EMU_pioFuncs my_pio_funcs = {
+	my_inb, my_inw, my_inl,
+	my_outb, my_outw, my_outl
+};
+
+// pointer to VBEInfoBuffer, set by vbe_prepare
+uint8_t *vbe_info_buffer = 0;
+// virtual BIOS Memory
+uint8_t *biosmem;
+uint32_t biosmem_size;
+
+// these structs are for input from and output to OF
+typedef struct {
+	uint8_t display_type;	// 0=NONE, 1= analog, 2=digital
+	uint16_t screen_width;
+	uint16_t screen_height;
+	uint16_t screen_linebytes;	// bytes per line in framebuffer, may be more than screen_width
+	uint8_t color_depth;	// color depth in bpp
+	uint32_t framebuffer_address;
+	uint8_t edid_block_zero[128];
+} __attribute__ ((__packed__)) screen_info_t;
+
+typedef struct {
+	uint8_t signature[4];
+	uint16_t size_reserved;
+	uint8_t monitor_number;
+	uint16_t max_screen_width;
+	uint8_t color_depth;
+} __attribute__ ((__packed__)) screen_info_input_t;
+
+// these structs only store a subset of the VBE defined fields
+// only those needed.
+typedef struct {
+	char signature[4];
+	uint16_t version;
+	uint8_t *oem_string_ptr;
+	uint32_t capabilities;
+	uint16_t video_mode_list[256];	// lets hope we never have more than 256 video modes...
+	uint16_t total_memory;
+} vbe_info_t;
+
+typedef struct {
+	uint16_t video_mode;
+	uint8_t mode_info_block[256];
+	uint16_t attributes;
+	uint16_t linebytes;
+	uint16_t x_resolution;
+	uint16_t y_resolution;
+	uint8_t x_charsize;
+	uint8_t y_charsize;
+	uint8_t bits_per_pixel;
+	uint8_t memory_model;
+	uint32_t framebuffer_address;
+} vbe_mode_info_t;
+
+typedef struct {
+	uint8_t port_number;	// i.e. monitor number
+	uint8_t edid_transfer_time;
+	uint8_t ddc_level;
+	uint8_t edid_block_zero[128];
+} vbe_ddc_info_t;
+
+static inline uint8_t
+vbe_prepare()
+{
+	vbe_info_buffer = biosmem + (VBE_SEGMENT << 4);	// segment:offset off VBE Data Area
+	//clear buffer
+	memset(vbe_info_buffer, 0, 512);
+	//set VbeSignature to "VBE2" to indicate VBE 2.0+ request
+	vbe_info_buffer[0] = 'V';
+	vbe_info_buffer[0] = 'B';
+	vbe_info_buffer[0] = 'E';
+	vbe_info_buffer[0] = '2';
+	// ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
+	M.x86.R_EDI = 0x0;
+	M.x86.R_ES = VBE_SEGMENT;
+
+	return 0;		// successfull init
+}
+
+// VBE Function 00h
+uint8_t
+vbe_info(vbe_info_t * info)
+{
+	vbe_prepare();
+	// call VBE function 00h (Info Function)
+	M.x86.R_EAX = 0x4f00;
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
+				 __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	//printf("VBE Info Dump:");
+	//dump(vbe_info_buffer, 64);
+
+	//offset 0: signature
+	info->signature[0] = vbe_info_buffer[0];
+	info->signature[1] = vbe_info_buffer[1];
+	info->signature[2] = vbe_info_buffer[2];
+	info->signature[3] = vbe_info_buffer[3];
+
+	// offset 4: 16bit le containing VbeVersion
+	info->version = in16le(vbe_info_buffer + 4);
+
+	// offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
+	info->oem_string_ptr =
+	    biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
+		       in16le(vbe_info_buffer + 6));
+
+	// offset 10: 32bit le capabilities
+	info->capabilities = in32le(vbe_info_buffer + 10);
+
+	// offset 14: 32 bit le containing segment:offset of supported video mode table
+	uint16_t *video_mode_ptr;
+	video_mode_ptr =
+	    (uint16_t *) (biosmem +
+			  ((in16le(vbe_info_buffer + 16) << 4) +
+			   in16le(vbe_info_buffer + 14)));
+	uint32_t i = 0;
+	do {
+		info->video_mode_list[i] = in16le(video_mode_ptr + i);
+		i++;
+	}
+	while ((i <
+		(sizeof(info->video_mode_list) /
+		 sizeof(info->video_mode_list[0])))
+	       && (info->video_mode_list[i - 1] != 0xFFFF));
+
+	//offset 18: 16bit le total memory in 64KB blocks
+	info->total_memory = in16le(vbe_info_buffer + 18);
+
+	return 0;
+}
+
+// VBE Function 01h
+uint8_t
+vbe_get_mode_info(vbe_mode_info_t * mode_info)
+{
+	vbe_prepare();
+	// call VBE function 01h (Return VBE Mode Info Function)
+	M.x86.R_EAX = 0x4f01;
+	M.x86.R_CX = mode_info->video_mode;
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
+		     __FUNCTION__, mode_info->video_mode, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	//pointer to mode_info_block is in ES:DI
+	memcpy(mode_info->mode_info_block,
+	       biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
+	       sizeof(mode_info->mode_info_block));
+
+	//printf("Mode Info Dump:");
+	//dump(mode_info_block, 64);
+
+	// offset 0: 16bit le mode attributes
+	mode_info->attributes = in16le(mode_info->mode_info_block);
+
+	// offset 16: 16bit le bytes per scan line
+	mode_info->linebytes = in16le(mode_info->mode_info_block + 16);
+
+	// offset 18: 16bit le x resolution
+	mode_info->x_resolution = in16le(mode_info->mode_info_block + 18);
+
+	// offset 20: 16bit le y resolution
+	mode_info->y_resolution = in16le(mode_info->mode_info_block + 20);
+
+	// offset 22: 8bit le x charsize
+	mode_info->x_charsize = *(mode_info->mode_info_block + 22);
+
+	// offset 23: 8bit le y charsize
+	mode_info->y_charsize = *(mode_info->mode_info_block + 23);
+
+	// offset 25: 8bit le bits per pixel
+	mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25);
+
+	// offset 27: 8bit le memory model
+	mode_info->memory_model = *(mode_info->mode_info_block + 27);
+
+	// offset 40: 32bit le containg offset of frame buffer memory ptr
+	mode_info->framebuffer_address =
+	    in32le(mode_info->mode_info_block + 40);
+
+	return 0;
+}
+
+// VBE Function 02h
+uint8_t
+vbe_set_mode(vbe_mode_info_t * mode_info)
+{
+	vbe_prepare();
+	// call VBE function 02h (Set VBE Mode Function)
+	M.x86.R_EAX = 0x4f02;
+	M.x86.R_BX = mode_info->video_mode;
+	M.x86.R_BX |= 0x4000;	// set bit 14 to request linear framebuffer mode
+	M.x86.R_BX &= 0x7FFF;	// clear bit 15 to request clearing of framebuffer
+
+	DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __FUNCTION__,
+			 M.x86.R_BX);
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, mode_info->video_mode, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	return 0;
+}
+
+//VBE Function 08h
+uint8_t
+vbe_set_palette_format(uint8_t format)
+{
+	vbe_prepare();
+	// call VBE function 09h (Set/Get Palette Data Function)
+	M.x86.R_EAX = 0x4f08;
+	M.x86.R_BL = 0x00;	// set format
+	M.x86.R_BH = format;
+
+	DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __FUNCTION__,
+			 format);
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	return 0;
+}
+
+// VBE Function 09h
+uint8_t
+vbe_set_color(uint16_t color_number, uint32_t color_value)
+{
+	vbe_prepare();
+	// call VBE function 09h (Set/Get Palette Data Function)
+	M.x86.R_EAX = 0x4f09;
+	M.x86.R_BL = 0x00;	// set color
+	M.x86.R_CX = 0x01;	// set only one entry
+	M.x86.R_DX = color_number;
+	// ES:DI is address where color_value is stored, we store it at 2000:0000
+	M.x86.R_ES = 0x2000;
+	M.x86.R_DI = 0x0;
+
+	// store color value at ES:DI
+	out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
+
+	DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __FUNCTION__,
+			 color_number, color_value);
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	return 0;
+}
+
+uint8_t
+vbe_get_color(uint16_t color_number, uint32_t * color_value)
+{
+	vbe_prepare();
+	// call VBE function 09h (Set/Get Palette Data Function)
+	M.x86.R_EAX = 0x4f09;
+	M.x86.R_BL = 0x00;	// get color
+	M.x86.R_CX = 0x01;	// get only one entry
+	M.x86.R_DX = color_number;
+	// ES:DI is address where color_value is stored, we store it at 2000:0000
+	M.x86.R_ES = 0x2000;
+	M.x86.R_DI = 0x0;
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	// read color value from ES:DI
+	*color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
+
+	DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __FUNCTION__,
+			 color_number, *color_value);
+
+	return 0;
+}
+
+// VBE Function 15h
+uint8_t
+vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
+{
+	vbe_prepare();
+	// call VBE function 15h (DDC Info Function)
+	M.x86.R_EAX = 0x4f15;
+	M.x86.R_BL = 0x00;	// get DDC Info
+	M.x86.R_CX = ddc_info->port_number;
+	M.x86.R_ES = 0x0;
+	M.x86.R_DI = 0x0;
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, ddc_info->port_number, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+	// BH = approx. time in seconds to transfer one EDID block
+	ddc_info->edid_transfer_time = M.x86.R_BH;
+	// BL = DDC Level
+	ddc_info->ddc_level = M.x86.R_BL;
+
+	vbe_prepare();
+	// call VBE function 15h (DDC Info Function)
+	M.x86.R_EAX = 0x4f15;
+	M.x86.R_BL = 0x01;	// read EDID
+	M.x86.R_CX = ddc_info->port_number;
+	M.x86.R_DX = 0x0;	// block number
+	// ES:DI is address where EDID is stored, we store it at 2000:0000
+	M.x86.R_ES = 0x2000;
+	M.x86.R_DI = 0x0;
+
+	// enable trace
+	CHECK_DBG(DEBUG_TRACE_X86EMU) {
+		X86EMU_trace_on();
+	}
+	// run VESA Interrupt
+	runInt10();
+
+	if (M.x86.R_AL != 0x4f) {
+		DEBUG_PRINTF_VBE
+		    ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
+		     __FUNCTION__, M.x86.R_AL);
+		return -1;
+	}
+
+	if (M.x86.R_AH != 0x0) {
+		DEBUG_PRINTF_VBE
+		    ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
+		     __FUNCTION__, ddc_info->port_number, M.x86.R_AH);
+		return M.x86.R_AH;
+	}
+
+	memcpy(ddc_info->edid_block_zero,
+	       biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
+	       sizeof(ddc_info->edid_block_zero));
+
+	return 0;
+}
+
+uint32_t
+vbe_get_info(uint8_t argc, char ** argv)
+{
+	uint8_t rval;
+	uint32_t i;
+	if (argc < 4) {
+		printf
+		    ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n",
+		     argv[0]);
+		int i = 0;
+		for (i = 0; i < argc; i++) {
+			printf("argv[%d]: %s\n", i, argv[i]);
+		}
+		return -1;
+	}
+	// get a copy of input struct...
+	screen_info_input_t input =
+	    *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16));
+	// output is pointer to the address passed as argv[4]
+	screen_info_t *output =
+	    (screen_info_t *) strtoul((char *) argv[4], 0, 16);
+	// zero output
+	memset(output, 0, sizeof(screen_info_t));
+
+	// argv[1] is address of virtual BIOS mem...
+	// argv[2] is the size
+	biosmem = (uint8_t *) strtoul(argv[1], 0, 16);
+	biosmem_size = strtoul(argv[2], 0, 16);;
+	if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
+		printf("Error: Not enough virtual memory: %x, required: %x!\n",
+		       biosmem_size, MIN_REQUIRED_VMEM_SIZE);
+		return -1;
+	}
+	// argv[3] is the device to open and use...
+	if (dev_init((char *) argv[3]) != 0) {
+		printf("Error initializing device!\n");
+		return -1;
+	}
+	//setup interrupt handler
+	X86EMU_intrFuncs intrFuncs[256];
+	for (i = 0; i < 256; i++)
+		intrFuncs[i] = handleInterrupt;
+	X86EMU_setupIntrFuncs(intrFuncs);
+	X86EMU_setupPioFuncs(&my_pio_funcs);
+	X86EMU_setupMemFuncs(&my_mem_funcs);
+
+	// set mem_base
+	M.mem_base = (long) biosmem;
+	M.mem_size = biosmem_size;
+	DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base,
+			 (int) M.mem_size);
+
+	vbe_info_t info;
+	rval = vbe_info(&info);
+	if (rval != 0)
+		return rval;
+
+	DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
+	DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
+	DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
+	DEBUG_PRINTF_VBE("Capabilities:\n");
+	DEBUG_PRINTF_VBE("\tDAC: %s\n",
+			 (info.capabilities & 0x1) ==
+			 0 ? "fixed 6bit" : "switchable 6/8bit");
+	DEBUG_PRINTF_VBE("\tVGA: %s\n",
+			 (info.capabilities & 0x2) ==
+			 0 ? "compatible" : "not compatible");
+	DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
+			 (info.capabilities & 0x4) ==
+			 0 ? "normal" : "use blank bit in Function 09h");
+
+	// argv[4] may be a pointer with enough space to return screen_info_t
+	// as input, it must contain a screen_info_input_t with the following content:
+	// byte[0:3] = "DDC\0" (zero-terminated signature header)
+	// byte[4:5] = reserved space for the return struct... just in case we ever change
+	//             the struct and dont have reserved enough memory (and let's hope the struct
+	//             never gets larger than 64KB)
+	// byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
+	// byte[7:8] = max. screen width (OF may want to limit this)
+	// byte[9] = required color depth in bpp
+	if (strncmp((char *) input.signature, "DDC", 4) != 0) {
+		printf
+		    ("%s: Invalid input signature! expected: %s, is: %s\n",
+		     __FUNCTION__, "DDC", input.signature);
+		return -1;
+	}
+	if (input.size_reserved != sizeof(screen_info_t)) {
+		printf
+		    ("%s: Size of return struct is wrong, required: %d, available: %d\n",
+		     __FUNCTION__, (int) sizeof(screen_info_t),
+		     input.size_reserved);
+		return -1;
+	}
+
+	vbe_ddc_info_t ddc_info;
+	ddc_info.port_number = input.monitor_number;
+	vbe_get_ddc_info(&ddc_info);
+
+#if 0
+	DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
+			 ddc_info.edid_transfer_time);
+	DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
+	DEBUG_PRINTF_VBE("DDC: EDID: \n");
+	CHECK_DBG(DEBUG_VBE) {
+		dump(ddc_info.edid_block_zero,
+		     sizeof(ddc_info.edid_block_zero));
+	}
+#endif
+	if (*((uint64_t *) ddc_info.edid_block_zero) !=
+	    (uint64_t) 0x00FFFFFFFFFFFF00) {
+		// invalid EDID signature... probably no monitor
+
+		output->display_type = 0x0;
+		return 0;
+	} else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
+		// digital display
+		output->display_type = 2;
+	} else {
+		// analog
+		output->display_type = 1;
+	}
+	DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
+	memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
+	       sizeof(ddc_info.edid_block_zero));
+	i = 0;
+	vbe_mode_info_t mode_info;
+	vbe_mode_info_t best_mode_info;
+	// initialize best_mode to 0
+	memset(&best_mode_info, 0, sizeof(best_mode_info));
+	while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
+		//DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
+		vbe_get_mode_info(&mode_info);
+#if 0
+		DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
+				 mode_info.video_mode,
+				 (mode_info.attributes & 0x1) ==
+				 0 ? "not supported" : "supported");
+		DEBUG_PRINTF_VBE("\tTTY: %s\n",
+				 (mode_info.attributes & 0x4) ==
+				 0 ? "no" : "yes");
+		DEBUG_PRINTF_VBE("\tMode: %s %s\n",
+				 (mode_info.attributes & 0x8) ==
+				 0 ? "monochrome" : "color",
+				 (mode_info.attributes & 0x10) ==
+				 0 ? "text" : "graphics");
+		DEBUG_PRINTF_VBE("\tVGA: %s\n",
+				 (mode_info.attributes & 0x20) ==
+				 0 ? "compatible" : "not compatible");
+		DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
+				 (mode_info.attributes & 0x40) ==
+				 0 ? "yes" : "no");
+		DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
+				 (mode_info.attributes & 0x80) ==
+				 0 ? "no" : "yes");
+		DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
+				 mode_info.x_resolution,
+				 mode_info.y_resolution);
+		DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
+				 mode_info.x_charsize, mode_info.y_charsize);
+		DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
+				 mode_info.bits_per_pixel);
+		DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
+				 mode_info.memory_model);
+		DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
+				 mode_info.framebuffer_address);
+#endif
+		if ((mode_info.bits_per_pixel == input.color_depth)
+		    && (mode_info.x_resolution <= input.max_screen_width)
+		    && ((mode_info.attributes & 0x80) != 0)	// framebuffer mode
+		    && ((mode_info.attributes & 0x10) != 0)	// graphics
+		    && ((mode_info.attributes & 0x8) != 0)	// color
+		    && (mode_info.x_resolution > best_mode_info.x_resolution))	// better than previous best_mode
+		{
+			// yiiiihaah... we found a new best mode
+			memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
+		}
+		i++;
+	}
+
+	if (best_mode_info.video_mode != 0) {
+		DEBUG_PRINTF_VBE
+		    ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
+		     best_mode_info.video_mode,
+		     best_mode_info.x_resolution,
+		     best_mode_info.y_resolution,
+		     best_mode_info.bits_per_pixel,
+		     best_mode_info.framebuffer_address);
+
+		//printf("Mode Info Dump:");
+		//dump(best_mode_info.mode_info_block, 64);
+
+		// set the video mode
+		vbe_set_mode(&best_mode_info);
+
+		if ((info.capabilities & 0x1) != 0) {
+			// switch to 8 bit palette format
+			vbe_set_palette_format(8);
+		}
+		// setup a palette:
+		// - first 216 colors are mixed colors for each component in 6 steps
+		//   (6*6*6=216)
+		// - then 10 shades of the three primary colors
+		// - then 10 shades of grey
+		// -------
+		// = 256 colors
+		//
+		// - finally black is color 0 and white color FF (because SLOF expects it
+		//   this way...)
+		// this resembles the palette that the kernel/X Server seems to expect...
+
+		uint8_t mixed_color_values[6] =
+		    { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
+		uint8_t primary_color_values[10] =
+		    { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
+			0x27
+		};
+		uint8_t mc_size = sizeof(mixed_color_values);
+		uint8_t prim_size = sizeof(primary_color_values);
+
+		uint8_t curr_color_index;
+		uint32_t curr_color;
+
+		uint8_t r, g, b;
+		// 216 mixed colors
+		for (r = 0; r < mc_size; r++) {
+			for (g = 0; g < mc_size; g++) {
+				for (b = 0; b < mc_size; b++) {
+					curr_color_index =
+					    (r * mc_size * mc_size) +
+					    (g * mc_size) + b;
+					curr_color = 0;
+					curr_color |= ((uint32_t) mixed_color_values[r]) << 16;	//red value
+					curr_color |= ((uint32_t) mixed_color_values[g]) << 8;	//green value
+					curr_color |= (uint32_t) mixed_color_values[b];	//blue value
+					vbe_set_color(curr_color_index,
+						      curr_color);
+				}
+			}
+		}
+
+		// 10 shades of each primary color
+		// red
+		for (r = 0; r < prim_size; r++) {
+			curr_color_index = mc_size * mc_size * mc_size + r;
+			curr_color = ((uint32_t) primary_color_values[r]) << 16;
+			vbe_set_color(curr_color_index, curr_color);
+		}
+		//green
+		for (g = 0; g < prim_size; g++) {
+			curr_color_index =
+			    mc_size * mc_size * mc_size + prim_size + g;
+			curr_color = ((uint32_t) primary_color_values[g]) << 8;
+			vbe_set_color(curr_color_index, curr_color);
+		}
+		//blue
+		for (b = 0; b < prim_size; b++) {
+			curr_color_index =
+			    mc_size * mc_size * mc_size + prim_size * 2 + b;
+			curr_color = (uint32_t) primary_color_values[b];
+			vbe_set_color(curr_color_index, curr_color);
+		}
+		// 10 shades of grey
+		for (i = 0; i < prim_size; i++) {
+			curr_color_index =
+			    mc_size * mc_size * mc_size + prim_size * 3 + i;
+			curr_color = 0;
+			curr_color |= ((uint32_t) primary_color_values[i]) << 16;	//red
+			curr_color |= ((uint32_t) primary_color_values[i]) << 8;	//green
+			curr_color |= ((uint32_t) primary_color_values[i]);	//blue
+			vbe_set_color(curr_color_index, curr_color);
+		}
+
+		// SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
+		vbe_set_color(0x00, 0x00000000);
+		vbe_set_color(0xFF, 0x00FFFFFF);
+
+		output->screen_width = best_mode_info.x_resolution;
+		output->screen_height = best_mode_info.y_resolution;
+		output->screen_linebytes = best_mode_info.linebytes;
+		output->color_depth = best_mode_info.bits_per_pixel;
+		output->framebuffer_address =
+		    best_mode_info.framebuffer_address;
+	} else {
+		printf("%s: No suitable video mode found!\n", __FUNCTION__);
+		//unset display_type...
+		output->display_type = 0;
+	}
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.h
new file mode 100644
index 0000000..07daedb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/biosemu/vbe.h
@@ -0,0 +1,16 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _BIOSEMU_VBE_H_
+#define _BIOSEMU_VBE_H_
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/main.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/main.c
new file mode 100644
index 0000000..fa9f49c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/main.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <of.h>
+#include <netapps/netapps.h>
+#include <libbootmsg.h>
+
+#ifdef SNK_BIOSEMU_APPS
+extern int biosemu(char argc, char**argv);
+extern int vbe_get_info(char argc, char**argv);
+#endif
+
+extern void _callback_entry(void);
+
+
+int
+main(int argc, char *argv[])
+{
+	int i;
+	of_set_callback((void *) &_callback_entry);
+
+	if (strcmp(argv[0], "netboot") == 0 && argc >= 5)
+		return netboot(argc, argv);
+	if (strcmp(argv[0], "netflash") == 0)
+		return netflash(argc, argv);
+	if (strcmp(argv[0], "ping") == 0)
+		return ping(argc, argv);
+#ifdef SNK_BIOSEMU_APPS
+	// BIOS Emulator applications
+	if (strcmp(argv[0], "biosemu") == 0)
+		return biosemu(argc, argv);
+	if (strcmp(argv[0], "get_vbe_info") == 0)
+		return vbe_get_info(argc, argv);
+#endif
+
+	printf("Unknown client application called\n");
+	for (i = 0; i < argc; i++)
+		printf("argv[%d] %s\n", i, argv[i]);
+
+	return -1;
+}
+
+int
+callback(int argc, char *argv[])
+{
+	int i;
+
+	printf("\n");
+
+	/*
+	 * Register your application's callback handler here, similar to
+	 * the way you would register an application.
+	 * Please note that callback functions can be called safely only after
+	 * your application has called of_yield(). If you return or exit() from
+	 * your client application, the callback can no longer be used.
+	 */
+#if 0
+	if (strcmp(argv[0], "example") == 0)
+		return example(argc, argv);
+#endif
+
+	printf("No such callback function\n");
+	for (i = 0; i < argc; i++)
+		printf("argv[%d] %s\n", i, argv[i]);
+
+	return (-1);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/Makefile
new file mode 100644
index 0000000..a40cb95
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/Makefile
@@ -0,0 +1,29 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I../ -I../../../../lib/ -Wall -W
+OBJS    = netboot.o netflash.o  
+OBJS	+= ping.o
+OBJS	+= args.o
+
+all: $(OBJS) 
+
+clean:	
+		$(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.c
new file mode 100644
index 0000000..2f4a615
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.c
@@ -0,0 +1,142 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Returns pointer of the n'th argument within a string.
+ *
+ * @param  arg_str    string with arguments, seperated with ','
+ * @param  index      index of the requested arguments whithin arg_str
+ * @return            pointer of argument[index] on success
+ *                    NULL if index is out of range
+ */
+const char *
+get_arg_ptr(const char *arg_str, unsigned int index)
+{
+	unsigned int i;
+
+	for (i = 0; i < index; ++i) {
+		for (; *arg_str != ',' && *arg_str != 0; ++arg_str);
+		if (*arg_str == 0)
+			return 0;
+		++arg_str;
+	}
+	return arg_str;
+}
+
+/**
+ * Returns number of arguments within a string.
+ *
+ * @param  arg_str    string with arguments, seperated with ','
+ * @return            number of arguments
+ */
+unsigned int
+get_args_count(const char *arg_str)
+{
+	unsigned int count = 1;
+
+	while ((arg_str = get_arg_ptr(arg_str, 1)) != 0)
+		++count;
+	return count;
+}
+
+/**
+ * Returns the length of the first argument.
+ *
+ * @param  arg_str    string with arguments, seperated with ','
+ * @return            length of first argument
+ */
+unsigned int
+get_arg_length(const char *arg_str)
+{
+	unsigned int i;
+
+	for (i = 0; *arg_str != ',' && *arg_str != 0; ++i)
+		++arg_str;
+	return i;
+}
+
+/**
+ * Copy the n'th argument within a string into a buffer in respect
+ * to a limited buffer size
+ *
+ * @param  arg_str    string with arguments, seperated with ','
+ * @param  index      index of the requested arguments whithin arg_str
+ * @param  buffer     pointer to the buffer
+ * @param  length     size of the buffer
+ * @return            pointer of buffer on success
+ *                    NULL if index is out of range.
+ */
+char *
+argncpy(const char *arg_str, unsigned int index, char *buffer,
+	unsigned int length)
+{
+	const char *ptr = get_arg_ptr(arg_str, index);
+	unsigned int len;
+
+	if (!ptr)
+		return 0;
+	len = get_arg_length(ptr);
+	if (!strncpy(buffer, ptr, length))
+		return 0;
+	buffer[len] = 0;
+	return buffer;
+}
+
+/**
+ * Converts "255.255.255.255" -> char[4] = { 0xff, 0xff, 0xff, 0xff }
+ *
+ * @param  str        string to be converted
+ * @param  ip         in case of SUCCESS - 32-bit long IP
+                      in case of FAULT - zero
+ * @return            TRUE - IP converted successfully;
+ *                    FALSE - error condition occurs (e.g. bad format)
+ */
+int
+strtoip(const char *str, char ip[4])
+{
+	char octet[10];
+	int res;
+	unsigned int i = 0, len;
+
+	while (*str != 0) {
+		if (i > 3 || !isdigit(*str))
+			return 0;
+		if (strstr(str, ".") != NULL) {
+			len = (int16_t) (strstr(str, ".") - str);
+			if (len >= 10)
+				return 0;
+			strncpy(octet, str, len);
+			octet[len] = 0;
+			str += len;
+		} else {
+			strncpy(octet, str, 9);
+			octet[9] = 0;
+			str += strlen(octet);
+		}
+		res = strtol(octet, NULL, 10);
+		if ((res > 255) || (res < 0))
+			return 0;
+		ip[i] = (char) res;
+		i++;
+		if (*str == '.')
+			str++;
+	}
+
+	if (i != 4)
+		return 0;
+	return -1;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.h
new file mode 100644
index 0000000..b80982a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/args.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _ARGS_H
+#define _ARGS_H
+
+const char *get_arg_ptr(const char *, unsigned int);
+unsigned int get_args_count(const char *);
+unsigned int get_arg_length(const char *);
+char *argncpy(const char *, unsigned int, char *, unsigned int);
+int strtoip(const char *, char[4]);
+
+#endif				/* _ARGS_H */
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netapps.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netapps.h
new file mode 100644
index 0000000..8b0a5e7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netapps.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+int netboot(int argc, char *argv[]);
+int netsave(int argc, char *argv[]);
+int netflash(int argc, char *argv[]);
+int bcmflash(int argc, char *argv[]);
+int mac_sync(int argc, char *argv[]);
+int net_eeprom_version( void );
+int ping(int argc, char *argv[]);
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netboot.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netboot.c
new file mode 100644
index 0000000..13202a7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netboot.c
@@ -0,0 +1,662 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <netlib/tftp.h>
+#include <netlib/ethernet.h>
+#include <netlib/dhcp.h>
+//#include <netlib/dhcpv6.h>
+#include <netlib/ipv4.h>
+//#include <netlib/ipv6.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netapps/args.h>
+#include <libbootmsg/libbootmsg.h>
+#include <of.h>
+
+#define IP_INIT_DEFAULT 2
+#define IP_INIT_NONE    0
+#define IP_INIT_BOOTP   1
+#define IP_INIT_DHCP    2
+#define IP_INIT_DHCPV6_STATELESS    3
+#define IP_INIT_IPV6_MANUAL         4
+
+#define DEFAULT_BOOT_RETRIES 600
+#define DEFAULT_TFTP_RETRIES 20
+static int ip_version = 4;
+
+typedef struct {
+	char filename[100];
+	int  ip_init;
+	char siaddr[4];
+	//ip6_addr_t si6addr;
+	char ciaddr[4];
+	//ip6_addr_t ci6addr;
+	char giaddr[4];
+	//ip6_addr_t gi6addr;
+	int  bootp_retries;
+	int  tftp_retries;
+} obp_tftp_args_t;
+
+
+/**
+ * Parses a argument string for IPv6 booting, extracts all
+ * parameters and fills a structure accordingly
+ *
+ * @param  arg_str        string with arguments, seperated with ','
+ * @param  argc           number of arguments
+ * @param  obp_tftp_args  structure which contains the result
+ * @return                updated arg_str
+ */
+/*
+static const char * 
+parse_ipv6args (const char *arg_str, unsigned int argc,
+		obp_tftp_args_t *obp_tftp_args)
+{
+	char *ptr = NULL;
+	char arg_buf[100];
+
+	// find out siaddr
+	if (argc == 0)
+		memset(&obp_tftp_args->si6addr.addr, 0, 16);
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(&obp_tftp_args->si6addr.addr, 0, 16);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(&obp_tftp_args->si6addr.addr, 0, 16);
+	}
+
+	// find out filename
+	if (argc == 0)
+		obp_tftp_args->filename[0] = 0;
+	else {
+		argncpy(arg_str, 0, obp_tftp_args->filename, 100);
+		for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr)
+			if(*ptr == '\\') {
+				*ptr = '/';
+			}
+		arg_str = get_arg_ptr(arg_str, 1);
+		--argc;
+	}
+
+	// find out ciaddr
+	if (argc == 0)
+		memset(&obp_tftp_args->ci6addr, 0, 16);
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr)) ) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(&obp_tftp_args->ci6addr.addr, 0, 16);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(&obp_tftp_args->ci6addr.addr, 0, 16);
+	}
+
+	// find out giaddr
+	if (argc == 0)
+		memset(&obp_tftp_args->gi6addr, 0, 16);
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(&obp_tftp_args->gi6addr, 0, 16);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(&obp_tftp_args->gi6addr.addr, 0, 16);
+	}
+
+	return arg_str;
+}
+*/
+
+
+/**
+ * Parses a argument string for IPv4 booting, extracts all
+ * parameters and fills a structure accordingly
+ *
+ * @param  arg_str        string with arguments, seperated with ','
+ * @param  argc           number of arguments
+ * @param  obp_tftp_args  structure which contains the result
+ * @return                updated arg_str
+ */
+static const char * 
+parse_ipv4args (const char *arg_str, unsigned int argc,
+		obp_tftp_args_t *obp_tftp_args)
+{
+	char *ptr = NULL;
+	char arg_buf[100];
+
+	// find out siaddr
+	if(argc==0) {
+		memset(obp_tftp_args->siaddr, 0, 4);
+	} else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(strtoip(arg_buf, obp_tftp_args->siaddr)) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(obp_tftp_args->siaddr, 0, 4);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(obp_tftp_args->siaddr, 0, 4);
+	}
+
+	// find out filename
+	if(argc==0)
+		obp_tftp_args->filename[0] = 0;
+	else {
+		argncpy(arg_str, 0, obp_tftp_args->filename, 100);
+		for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr)
+			if(*ptr == '\\')
+				*ptr = '/';
+		arg_str = get_arg_ptr(arg_str, 1);
+		--argc;
+	}
+
+	// find out ciaddr
+	if(argc==0)
+		memset(obp_tftp_args->ciaddr, 0, 4);
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(strtoip(arg_buf, obp_tftp_args->ciaddr)) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(obp_tftp_args->ciaddr, 0, 4);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(obp_tftp_args->ciaddr, 0, 4);
+	}
+
+	// find out giaddr
+	if(argc==0)
+		memset(obp_tftp_args->giaddr, 0, 4);
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(strtoip(arg_buf, obp_tftp_args->giaddr)) {
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(arg_buf[0] == 0) {
+			memset(obp_tftp_args->giaddr, 0, 4);
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else
+			memset(obp_tftp_args->giaddr, 0, 4);
+	}
+
+	return arg_str;
+}
+
+/**
+ * Parses a argument string which is given by netload, extracts all
+ * parameters and fills a structure according to this
+ *
+ * Netload-Parameters:
+ *    [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
+ *
+ * @param  arg_str        string with arguments, seperated with ','
+ * @param  obp_tftp_args  structure which contains the result
+ * @return                none
+ */
+static void
+parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args)
+{
+	unsigned int argc;
+	char arg_buf[100];
+
+	argc = get_args_count(arg_str);
+
+	// find out if we should use BOOTP or DHCP
+	if(argc==0)
+		obp_tftp_args->ip_init = IP_INIT_DEFAULT;
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if (strcasecmp(arg_buf, "bootp") == 0) {
+			obp_tftp_args->ip_init = IP_INIT_BOOTP;
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(strcasecmp(arg_buf, "dhcp") == 0) {
+			obp_tftp_args->ip_init = IP_INIT_DHCP;
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+		}
+		else if(strcasecmp(arg_buf, "ipv6") == 0) {
+			obp_tftp_args->ip_init = IP_INIT_DHCPV6_STATELESS;
+			arg_str = get_arg_ptr(arg_str, 1);
+			--argc;
+			ip_version = 6;
+		}
+		else
+			obp_tftp_args->ip_init = IP_INIT_DEFAULT;
+	}
+
+	if (ip_version == 4) {
+		arg_str = parse_ipv4args (arg_str, argc, obp_tftp_args);
+	}
+/*
+	else if (ip_version == 6) {
+		arg_str = parse_ipv6args (arg_str, argc, obp_tftp_args);
+	}
+*/
+
+	// find out bootp-retries
+	if (argc == 0)
+		obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(arg_buf[0] == 0)
+			obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+		else {
+			obp_tftp_args->bootp_retries = strtol(arg_buf, 0, 10);
+			if(obp_tftp_args->bootp_retries < 0)
+				obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+		}
+		arg_str = get_arg_ptr(arg_str, 1);
+		--argc;
+	}
+
+	// find out tftp-retries
+	if (argc == 0)
+		obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+	else {
+		argncpy(arg_str, 0, arg_buf, 100);
+		if(arg_buf[0] == 0)
+			obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+		else {
+			obp_tftp_args->tftp_retries = strtol(arg_buf, 0, 10);
+			if(obp_tftp_args->tftp_retries < 0)
+				obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+		}
+		arg_str = get_arg_ptr(arg_str, 1);
+		--argc;
+	}
+}
+
+int
+netboot(int argc, char *argv[])
+{
+	char buf[256];
+	int rc;
+	int len = strtol(argv[2], 0, 16);
+	char *buffer = (char *) strtol(argv[1], 0, 16);
+	char *ret_buffer = (char *) strtol(argv[3], 0, 16);
+	filename_ip_t fn_ip;
+	int fd_device;
+	tftp_err_t tftp_err;
+	obp_tftp_args_t obp_tftp_args;
+	char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 };
+/*
+	char null_ip6[16] = { 0x00, 0x00, 0x00, 0x00,
+			     0x00, 0x00, 0x00, 0x00,
+			     0x00, 0x00, 0x00, 0x00, 
+			     0x00, 0x00, 0x00, 0x00 };
+*/
+	int huge_load = strtol(argv[4], 0, 10);
+	int32_t block_size = strtol(argv[5], 0, 10);
+	uint8_t own_mac[6];
+
+	printf("\n");
+	printf(" Bootloader 1.6 \n");
+	memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+	/***********************************************************
+	 *
+	 * Initialize network stuff and retrieve boot informations
+	 *
+	 ***********************************************************/
+
+	/* Wait for link up and get mac_addr from device */
+	for(rc=0; rc<DEFAULT_BOOT_RETRIES; ++rc) {
+		if(rc > 0) {
+			set_timer(TICKS_SEC);
+			while (get_timer() > 0);
+		}
+		fd_device = socket(0, 0, 0, (char*) own_mac);
+		if(fd_device != -2)
+			break;
+		if(getchar() == 27) {
+			fd_device = -2;
+			break;
+		}
+	}
+
+	if (fd_device == -1) {
+		strcpy(buf,"E3000: (net) Could not read MAC address");
+		bootmsg_error(0x3000, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -100;
+	}
+	else if (fd_device == -2) {
+		strcpy(buf,"E3006: (net) Could not initialize network device");
+		bootmsg_error(0x3006, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -101;
+	}
+
+	printf("  Reading MAC address from device: "
+	       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       own_mac[0], own_mac[1], own_mac[2],
+	       own_mac[3], own_mac[4], own_mac[5]);
+
+	// init ethernet layer
+	set_mac_address(own_mac);
+
+	if (argc > 6) {
+		parse_args(argv[6], &obp_tftp_args);
+		if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES)
+			obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
+		else
+			obp_tftp_args.bootp_retries -= rc;
+	}
+	else {
+		memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t));
+		obp_tftp_args.ip_init = IP_INIT_DEFAULT;
+		obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
+		obp_tftp_args.tftp_retries = DEFAULT_TFTP_RETRIES;
+	}
+	memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4);
+
+	//  reset of error code
+	rc = 0;
+
+	/* if we still have got all necessary parameters, then we don't
+	   need to perform an BOOTP/DHCP-Request */
+	if (ip_version == 4) {
+		if (memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0
+		    && memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0
+		    && obp_tftp_args.filename[0] != 0) {
+
+			memcpy(&fn_ip.server_ip, &obp_tftp_args.siaddr, 4);
+			obp_tftp_args.ip_init = IP_INIT_NONE;
+		}
+	}
+/*
+	else if (ip_version == 6) {
+		if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0
+		    && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0
+		    && obp_tftp_args.filename[0] != 0) {
+
+			memcpy(&fn_ip.server_ip6.addr[0], 
+			       &obp_tftp_args.si6addr.addr, 16);
+			obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL;
+		} 
+		else {
+			obp_tftp_args.ip_init = IP_INIT_DHCPV6_STATELESS;
+		}
+	}
+*/
+	// construction of fn_ip from parameter
+	switch(obp_tftp_args.ip_init) {
+	case IP_INIT_BOOTP:
+		printf("  Requesting IP address via BOOTP: ");
+		// if giaddr in not specified, then we have to identify
+		// the BOOTP server via broadcasts
+		if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) {
+			// don't do this, when using DHCP !!!
+			fn_ip.server_ip = 0xFFFFFFFF;
+		}
+		// if giaddr is specified, then we have to use this
+		// IP address as proxy to identify the BOOTP server
+		else {
+			memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4);
+		}
+		rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries);
+		break;
+	case IP_INIT_DHCP:
+		printf("  Requesting IP address via DHCP: ");
+		rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries);
+		break;
+/*
+	case IP_INIT_DHCPV6_STATELESS:
+		set_ipv6_address(0);
+		rc = do_dhcpv6 (ret_buffer, &fn_ip, 10, DHCPV6_STATELESS);
+		break;
+	case IP_INIT_IPV6_MANUAL:
+		set_ipv6_address(&obp_tftp_args.ci6addr);
+		break;
+*/
+	case IP_INIT_NONE:
+	default:
+		break;
+	}
+
+	if(rc >= 0 && ip_version == 4) {
+		if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0
+		&& memcmp(obp_tftp_args.ciaddr, &fn_ip.own_ip, 4) != 0)
+			memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4);
+
+		if(memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0
+		&& memcmp(obp_tftp_args.siaddr, &fn_ip.server_ip, 4) != 0)
+			memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4);
+
+		// init IPv4 layer
+		set_ipv4_address(fn_ip.own_ip);
+	}
+/*
+	else if (rc >= 0 && ip_version == 6) {
+		if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) != 0
+		&& memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) != 0)
+			memcpy(&fn_ip.own_ip6, &obp_tftp_args.ci6addr.addr, 16);
+
+		if(memcmp(&obp_tftp_args.si6addr.addr, null_ip6, 16) != 0
+		&& memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) != 0)
+			memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16);
+	}
+*/
+	if (rc == -1) {
+		strcpy(buf,"E3001: (net) Could not get IP address");
+		bootmsg_error(0x3001, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -101;
+	}
+
+	printf("%d.%d.%d.%d\n",
+	       ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
+	       ((fn_ip.own_ip >>  8) & 0xFF), ( fn_ip.own_ip        & 0xFF));
+
+	if (rc == -2) {
+		sprintf(buf,
+			"E3002: (net) ARP request to TFTP server "
+			"(%d.%d.%d.%d) failed",
+			((fn_ip.server_ip >> 24) & 0xFF),
+			((fn_ip.server_ip >> 16) & 0xFF),
+			((fn_ip.server_ip >>  8) & 0xFF),
+			( fn_ip.server_ip        & 0xFF));
+		bootmsg_error(0x3002, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -102;
+	}
+	if (rc == -4 || rc == -3) {
+		strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address");
+		bootmsg_error(0x3008, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -107;
+	}
+
+
+	/***********************************************************
+	 *
+	 * Load file via TFTP into buffer provided by OpenFirmware
+	 *
+	 ***********************************************************/
+
+	if (obp_tftp_args.filename[0] != 0) {
+		strncpy((char *) fn_ip.filename, obp_tftp_args.filename, sizeof(fn_ip.filename)-1);
+		fn_ip.filename[sizeof(fn_ip.filename)-1] = 0;
+	}
+
+	printf("  Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
+		fn_ip.filename,
+		((fn_ip.server_ip >> 24) & 0xFF),
+		((fn_ip.server_ip >> 16) & 0xFF),
+		((fn_ip.server_ip >>  8) & 0xFF),
+		( fn_ip.server_ip        & 0xFF));
+
+	// accept at most 20 bad packets
+	// wait at most for 40 packets
+	rc = tftp(&fn_ip, (unsigned char *) buffer,
+	          len, obp_tftp_args.tftp_retries,
+	          &tftp_err, huge_load, block_size, ip_version);
+
+	if(obp_tftp_args.ip_init == IP_INIT_DHCP)
+		dhcp_send_release();
+
+	if (rc > 0) {
+		printf("  TFTP: Received %s (%d KBytes)\n", fn_ip.filename,
+		       rc / 1024);
+	} else if (rc == -1) {
+		bootmsg_error(0x3003, "(net) unknown TFTP error");
+		return -103;
+	} else if (rc == -2) {
+		sprintf(buf,
+			"E3004: (net) TFTP buffer of %d bytes "
+			"is too small for %s",
+			len, fn_ip.filename);
+		bootmsg_error(0x3004, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -104;
+	} else if (rc == -3) {
+		sprintf(buf,"E3009: (net) file not found: %s",
+		       fn_ip.filename);
+		bootmsg_error(0x3009, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -108;
+	} else if (rc == -4) {
+		strcpy(buf,"E3010: (net) TFTP access violation");
+		bootmsg_error(0x3010, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -109;
+	} else if (rc == -5) {
+		strcpy(buf,"E3011: (net) illegal TFTP operation");
+		bootmsg_error(0x3011, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -110;
+	} else if (rc == -6) {
+		strcpy(buf, "E3012: (net) unknown TFTP transfer ID");
+		bootmsg_error(0x3012, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -111;
+	} else if (rc == -7) {
+		strcpy(buf, "E3013: (net) no such TFTP user");
+		bootmsg_error(0x3013, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -112;
+	} else if (rc == -8) {
+		strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed");
+		bootmsg_error(0x3017, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -116;
+	} else if (rc == -9) {
+		strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size");
+		bootmsg_error(0x3018, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -117;
+	} else if (rc <= -10 && rc >= -15) {
+		sprintf(buf,"E3005: (net) ICMP ERROR \"");
+		switch (rc) {
+		case -ICMP_NET_UNREACHABLE - 10:
+			sprintf(buf+strlen(buf),"net unreachable");
+			break;
+		case -ICMP_HOST_UNREACHABLE - 10:
+			sprintf(buf+strlen(buf),"host unreachable");
+			break;
+		case -ICMP_PROTOCOL_UNREACHABLE - 10:
+			sprintf(buf+strlen(buf),"protocol unreachable");
+			break;
+		case -ICMP_PORT_UNREACHABLE - 10:
+			sprintf(buf+strlen(buf),"port unreachable");
+			break;
+		case -ICMP_FRAGMENTATION_NEEDED - 10:
+			sprintf(buf+strlen(buf),"fragmentation needed and DF set");
+			break;
+		case -ICMP_SOURCE_ROUTE_FAILED - 10:
+			sprintf(buf+strlen(buf),"source route failed");
+			break;
+		default:
+			sprintf(buf+strlen(buf)," UNKNOWN");
+			break;
+		}
+		sprintf(buf+strlen(buf),"\"");
+		bootmsg_error(0x3005, &buf[7]);
+
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -105;
+	} else if (rc == -40) {
+		sprintf(buf,
+			"E3014: (net) TFTP error occurred after "
+			"%d bad packets received",
+			tftp_err.bad_tftp_packets);
+		bootmsg_error(0x3014, &buf[7]);
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -113;
+	} else if (rc == -41) {
+		sprintf(buf,
+			"E3015: (net) TFTP error occurred after "
+			"missing %d responses",
+			tftp_err.no_packets);
+		bootmsg_error(0x3015, &buf[7]);
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -114;
+	} else if (rc == -42) {
+		sprintf(buf,
+			"E3016: (net) TFTP error missing block %d, "
+			"expected block was %d",
+			tftp_err.blocks_missed,
+			tftp_err.blocks_received);
+		bootmsg_error(0x3016, &buf[7]);
+		write_mm_log(buf, strlen(buf), 0x91);
+		return -115;
+	}
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netflash.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netflash.c
new file mode 100644
index 0000000..6865ecb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/netflash.c
@@ -0,0 +1,187 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <netlib/tftp.h>
+#include <netlib/dhcp.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv4.h>
+#include <rtas.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+int netflash(int argc, char * argv[])
+{
+	char buf[256];
+	int rc;
+	int manage_mode = 0;
+	static int len = 0x800000; //max flash size
+	char * buffer = NULL;
+	short arp_failed = 0;
+	filename_ip_t fn_ip;
+	int fd_device;
+	tftp_err_t tftp_err;
+	char * ptr;
+	uint8_t own_mac[6];
+
+	printf("\n Flasher 1.4 \n");
+	memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+	if (argc == 3 && argv[2][0] == '-' && argv[2][1] == 'c' && argv[2][2] == 0)
+		manage_mode = 1;
+	else if (argc == 3 && 
+		argv[2][0] == '-' && argv[2][1] == 'r' && argv[2][2] == 0)
+		manage_mode = 1;
+	else if (argc == 4 &&
+		argv[2][0] == '-' && argv[2][1] == 'f' && argv[2][2] == 0)
+	{
+		manage_mode = 0;
+		buffer = (char *)strtol(argv[1],0,16);
+		if ((long)buffer == -1) {
+			printf("   Bad buffer address. Exiting...\n");
+			return -1;
+		}
+	}
+	else
+	{
+		printf("   Usage: netflash [options] [<filename>]\n");
+		printf("   Options:\n");
+		printf("            -f     <filename> flash temporary image\n");
+		printf("            -c     commit temporary image\n");
+		printf("            -r     reject temporary image\n");
+		printf("   Bad arguments. Exiting...\n\n");
+		return -1;
+	}
+
+	if (manage_mode == 1) {
+		if (argv[2][1] == 99)
+			return rtas_ibm_manage_flash(1);
+		else
+			return rtas_ibm_manage_flash(0);
+	}
+
+	/* Get mac_addr from device */
+	printf("  Reading MAC address from device: ");
+	fd_device = socket(0, 0, 0, (char *) own_mac);
+	if (fd_device == -1) {
+		printf("\nE3000: Could not read MAC address\n");
+		return -100;
+	}
+	else if (fd_device == -2) {
+		printf("\nE3006: Could not initialize network device\n");
+		return -101;
+	}
+
+	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       own_mac[0], own_mac[1], own_mac[2],
+	       own_mac[3], own_mac[4], own_mac[5]);
+
+	// init ethernet layer
+	set_mac_address(own_mac);
+
+	// identify the BOOTP/DHCP server via broadcasts
+	// don't do this, when using DHCP !!!
+	//  fn_ip.server_ip = 0xFFFFFFFF;
+	//  memset(fn_ip.server_mac, 0xff, 6);
+
+	/* Get ip address for our mac address */
+	printf("  Requesting IP address via DHCP: ");
+	arp_failed = dhcp(0, &fn_ip, 30);
+
+	if(arp_failed >= 0) {
+		// reinit network stack
+		set_ipv4_address(fn_ip.own_ip);
+	}
+
+	if (arp_failed == -1) {
+		printf("\n  DHCP: Could not get ip address\n");
+		return 1;
+	}
+
+	if (arp_failed == -2) {
+		sprintf
+		    (buf,"\n  ARP request to TFTP server (%d.%d.%d.%d) failed",
+		     ((fn_ip.server_ip >> 24) & 0xFF), ((fn_ip.server_ip >> 16) & 0xFF),
+		     ((fn_ip.server_ip >>  8) & 0xFF), ( fn_ip.server_ip        & 0xFF));
+		return 1;
+	}
+
+	printf("%d.%d.%d.%d\n",
+		((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), 
+		((fn_ip.own_ip >>  8) & 0xFF), (fn_ip.own_ip & 0xFF));
+
+	/* Load file via TFTP into buffer provided by OpenFirmware */
+
+	for(ptr = argv[3]; *ptr != 0; ++ptr)
+		if(*ptr == '\\')
+			*ptr = '/';
+
+	printf("  Requesting file \"%s\" via TFTP\n",argv[3]);
+
+	strcpy((char *) fn_ip.filename,argv[3]);
+
+	rc = tftp(&fn_ip, (unsigned char*) buffer, len, 20, &tftp_err, 0, 512, 4);
+
+	dhcp_send_release();
+
+	if (rc > 0)
+	{
+		printf ("  TFTP: Received %s (%d KBytes)\n", fn_ip.filename, rc/1024);
+		printf ("  Now flashing:\n");
+		rc = rtas_ibm_update_flash_64((long long)buffer, rc);
+		return rc;
+	}
+	else if (rc == -1)
+	{
+		printf ("  Tftp: Could not load file %s\n", fn_ip.filename);
+		return 1;
+	}
+	else if (rc == -2)
+	{
+		printf ("  Tftp: Buffer to small for %s\n", fn_ip.filename);
+		return 1;
+	}
+	else if (rc <= -10 && rc >= -15)
+	{
+		printf("\n  ICMP ERROR: Destination unreachable: ");
+		switch(rc) {
+			case -ICMP_NET_UNREACHABLE-10:
+				printf("net unreachable");
+				break;
+			case -ICMP_HOST_UNREACHABLE-10:
+				printf("host unreachable");
+				break;
+			case -ICMP_PROTOCOL_UNREACHABLE-10:
+				printf("protocol unreachable");
+				break;
+			case -ICMP_PORT_UNREACHABLE-10:
+				printf("port unreachable");
+				break;
+			case -ICMP_FRAGMENTATION_NEEDED-10:
+				printf("fragmentation needed and DF set");
+				break;
+			case -ICMP_SOURCE_ROUTE_FAILED-10:
+				printf("source route failed");
+				break;
+			default:
+				printf(" UNKNOWN: this should not happen!");
+				break;
+		}
+		printf("\n");
+		return 1;
+	}
+	else if(rc < 0)
+		printf(" UNKNOWN: rc = %d!", rc);
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/ping.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/ping.c
new file mode 100644
index 0000000..5557baf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netapps/ping.c
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <netlib/ipv4.h>
+#include <netlib/dhcp.h>
+#include <netlib/ethernet.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <netapps/args.h>
+
+struct ping_args {
+	union {
+		char string[4];
+		unsigned int integer;
+	} server_ip;
+	union {
+		char string[4];
+		unsigned int integer;
+	} client_ip;
+	union {
+		char string[4];
+		unsigned int integer;
+	} gateway_ip;
+	unsigned int timeout;
+};
+
+static void
+usage()
+{
+	printf
+	    ("\nping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]\n");
+
+}
+
+static int
+parse_args(const char *args, struct ping_args *ping_args)
+{
+	unsigned int argc = get_args_count(args);
+	char buf[64];
+	ping_args->timeout = 10;
+	if (argc == 0)
+		/* at least server-ip has to be specified */
+		return -1;
+	if (argc == 1) {
+		/* probably only server ip is specified */
+		argncpy(args, 0, buf, 64);
+		if (!strtoip(buf, ping_args->server_ip.string))
+			return -1;
+		return 0;
+	}
+	/* get first option from list */
+	argncpy(args, 0, buf, 64);
+	if (!strtoip(buf, ping_args->server_ip.string)) {
+		/* it is not an IP address
+		 * therefore it has to be device-args
+		 * device-args are not supported and just ignored */
+		args = get_arg_ptr(args, 1);
+		argc--;
+	}
+
+	argncpy(args, 0, buf, 64);
+	if (!strtoip(buf, ping_args->server_ip.string)) {
+		/* this should have been the server IP address */
+		return -1;
+	} else {
+		args = get_arg_ptr(args, 1);
+		if (!--argc)
+			return 0;
+	}
+
+	argncpy(args, 0, buf, 64);
+	if (!strtoip(buf, ping_args->client_ip.string)) {
+		/* this should have been the client (our) IP address */
+		return -1;
+	} else {
+		args = get_arg_ptr(args, 1);
+		if (!--argc)
+			return 0;
+	}
+	argncpy(args, 0, buf, 64);
+	if (!strtoip(buf, ping_args->gateway_ip.string)) {
+		/* this should have been the gateway IP address */
+		return -1;
+	} else {
+		args = get_arg_ptr(args, 1);
+		if (!--argc)
+			return 0;
+	}
+	argncpy(args, 0, buf, 64);
+	ping_args->timeout = strtol(args, 0, 10);
+	return 0;
+}
+
+int
+ping(int argc, char *argv[])
+{
+	short arp_failed = 0;
+	filename_ip_t fn_ip;
+	int fd_device;
+	struct ping_args ping_args;
+	uint8_t own_mac[6];
+
+	memset(&ping_args, 0, sizeof(struct ping_args));
+
+	if (argc == 2) {
+		if (parse_args(argv[1], &ping_args)) {
+			usage();
+			return -1;
+		}
+	} else {
+		usage();
+		return -1;
+	}
+
+	memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+	/* Get mac_addr from device */
+	printf("\n  Reading MAC address from device: ");
+	fd_device = socket(0, 0, 0, (char *) own_mac);
+	if (fd_device == -1) {
+		printf("\nE3000: Could not read MAC address\n");
+		return -100;
+	} else if (fd_device == -2) {
+		printf("\nE3006: Could not initialize network device\n");
+		return -101;
+	}
+
+	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       own_mac[0], own_mac[1], own_mac[2],
+	       own_mac[3], own_mac[4], own_mac[5]);
+
+	// init ethernet layer
+	set_mac_address(own_mac);
+	// identify the BOOTP/DHCP server via broadcasts
+	// don't do this, when using DHCP !!!
+	//  fn_ip.server_ip = 0xFFFFFFFF;
+	//  memset(fn_ip.server_mac, 0xff, 6);
+
+	if (!ping_args.client_ip.integer) {
+		/* Get ip address for our mac address */
+		printf("  Requesting IP address via DHCP: ");
+		arp_failed = dhcp(0, &fn_ip, 30);
+
+		if (arp_failed == -1) {
+			printf("\n  DHCP: Could not get ip address\n");
+			return -1;
+		}
+
+	} else {
+		memcpy(&fn_ip.own_ip, &ping_args.client_ip.integer, 4);
+		arp_failed = 1;
+		printf("  Own IP address: ");
+	}
+
+	// reinit network stack
+	set_ipv4_address(fn_ip.own_ip);
+
+	printf("%d.%d.%d.%d\n",
+	       ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
+	       ((fn_ip.own_ip >> 8) & 0xFF), (fn_ip.own_ip & 0xFF));
+
+	memcpy(&fn_ip.server_ip, &ping_args.server_ip.integer, 4);
+	printf("  Ping to %d.%d.%d.%d ", ((fn_ip.server_ip >> 24) & 0xFF),
+	       ((fn_ip.server_ip >> 16) & 0xFF),
+	       ((fn_ip.server_ip >> 8) & 0xFF), (fn_ip.server_ip & 0xFF));
+
+
+	ping_ipv4(fn_ip.server_ip);
+
+	set_timer(TICKS_SEC / 10 * ping_args.timeout);
+	while(get_timer() > 0) {
+		receive_ether();
+		if(pong_ipv4() == 0) {
+			printf("success\n");
+			return 0;
+		}
+	}
+
+	printf("failed\n");
+	return -1;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/Makefile
new file mode 100644
index 0000000..5b91470
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/Makefile
@@ -0,0 +1,42 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I../
+
+ifeq ($(SNK_USE_MTFTP), 1)
+CFLAGS += -DUSE_MTFTP
+endif
+
+OBJS    = ethernet.o ipv4.o udp.o tcp.o  dns.o bootp.o \
+	  dhcp.o
+
+ifeq ($(SNK_USE_MTFTP), 1)
+OBJS += mtftp.o
+else
+OBJS += tftp.o
+endif
+
+all: netlib.o
+
+netlib.o: $(OBJS) 
+		$(LD) $(LDFLAGS) $^ -o $@ -r
+
+clean:	
+		$(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/bootp.c
new file mode 100644
index 0000000..b1e97ed
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/bootp.c
@@ -0,0 +1,248 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+#include <dhcp.h>
+
+#define DEBUG 0
+
+static char * response_buffer;
+
+void
+print_ip(char *ip)
+{
+	printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
+}
+
+
+/* IP header checksum calculation */
+unsigned short
+checksum(unsigned short *packet, int words)
+{
+	unsigned long checksum;
+	for (checksum = 0; words > 0; words--)
+		checksum += *packet++;
+	checksum = (checksum >> 16) + (checksum & 0xffff);
+	checksum += (checksum >> 16);
+	return ~checksum;
+}
+
+
+static int
+send_bootp(filename_ip_t * fn_ip)
+{
+#if DEBUG
+	int i;
+#endif
+	unsigned int packetsize =
+	    sizeof(struct iphdr) + sizeof(struct ethhdr) +
+	    sizeof(struct udphdr) + sizeof(struct btphdr);
+	unsigned char packet[packetsize];
+	struct iphdr *iph;
+	struct udphdr *udph;
+	struct btphdr *btph;
+
+	iph = (struct iphdr *) packet;
+	udph = (struct udphdr *) (iph + 1);
+	btph = (struct btphdr *) (udph + 1);
+
+	memset(packet, 0, packetsize);
+
+	fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)),
+	           IPTYPE_UDP, 0, fn_ip->server_ip);
+	fill_udphdr((uint8_t *) udph,
+	            htons(sizeof(struct udphdr) + sizeof(struct btphdr)),
+	            htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS));
+	btph->op = 1;
+	btph->htype = 1;
+	btph->hlen = 6;
+	strcpy((char *) btph->file, "bla");
+	memcpy(btph->chaddr, get_mac_address(), 6);
+
+#if DEBUG
+	printf("Sending packet\n");
+	printf("Packet is ");
+	for (i = 0; i < packetsize; i++)
+		printf(" %02x", packet[i]);
+	printf(".\n");
+#endif
+
+	send_ipv4(packet, iph->ip_len);
+#if DEBUG
+	printf("%d bytes transmitted over socket.\n", i);
+#endif
+
+	return 0;
+}
+
+
+static int
+receive_bootp(filename_ip_t * fn_ip)
+{
+	int len, old_sum;
+	unsigned int packetsize = 2000;
+	unsigned char packet[packetsize];
+	struct ethhdr *ethh;
+	struct iphdr *iph;
+	struct udphdr *udph;
+	struct btphdr *btph;
+
+	ethh = (struct ethhdr *) packet;
+	iph = (struct iphdr *) (packet + sizeof(struct ethhdr));
+	udph = (struct udphdr *) (iph + 1);
+	btph = (struct btphdr *) (udph + 1);
+
+	memset(packet, 0, packetsize);
+
+	/* setting up a timer with a timeout of one second */
+	set_timer(TICKS_SEC);
+
+	do {
+
+		/* let's receive a packet */
+		len = recv(0, packet, packetsize, 0);
+
+#if DEBUG
+		int j;
+		printf("%d bytes received, %d expected \n", len, packetsize);
+		if (len == 346) {
+			printf("Rec packet\n");
+			printf("Packet is ");
+			for (j = 0; j < len; j++) {
+				if (j % 16 == 0)
+					printf("\n");
+				printf(" %02x", packet[j]);
+			}
+			printf(".\n");
+		}
+#endif
+		/* check if the ip checksum is correct */
+		old_sum = iph->ip_sum;
+		iph->ip_sum = 0x00;
+		if (old_sum !=
+		    checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1))
+			/* checksum failed */
+			continue;
+		/* is it a udp packet */
+		if (iph->ip_p != IPTYPE_UDP)
+			continue;
+		/* check if the source port and destination port and the packet
+		 * say that it is a bootp answer */
+		if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS))
+			continue;
+		/* check if it is a Boot Reply */
+		if (btph->op != 2)
+			continue;
+		/* Comparing our mac address with the one in the bootp reply */	
+		if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN))
+			continue;
+
+		if(response_buffer)
+			memcpy(response_buffer, btph, 1720);
+
+		fn_ip->own_ip = btph->yiaddr;
+		fn_ip->server_ip = btph->siaddr;
+		strcpy((char *) fn_ip->filename, (char *) btph->file);
+
+#if DEBUG
+		printf("\nThese are the details of the bootp reply:\n");
+		printf("Our IP address: ");
+		print_ip((char*) &fn_ip->own_ip);
+		printf("Next server IP address: ");
+		print_ip((char*) &fn_ip->server_ip);
+		printf("Boot file name: %s\n", btph->file);
+		printf("Packet is: %s\n", btph->file);
+		for (j = 0; j < len; j++) {
+			if (j % 16 == 0)
+				printf("\n");
+			printf(" %02x", packet[j]);
+		}
+		printf(".\n");
+		printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		        get_mac_address()[0], get_mac_address()[1],
+		        get_mac_address()[2], get_mac_address()[3],
+		        get_mac_address()[4], get_mac_address()[5]);
+		printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		       ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2], 
+		       ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]);
+		printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		       ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2], 
+		       ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]);
+		printf("Header ethh->typ: %x\n",ethh->type); 
+		printf("Header iph->ip_hlv: %x\n",iph->ip_hlv); 
+		printf("Header iph->ip_len: %x\n",iph->ip_len); 
+		printf("Header iph->ip_id: %x\n",iph->ip_id); 
+		printf("Header iph->ip_off: %x\n",iph->ip_off); 
+		printf("Header iph->ip_ttl: %x\n",iph->ip_ttl); 
+		printf("Header iph->ip_p: %x\n",iph->ip_p); 
+		printf("Header iph->ip_sum: %x\n",iph->ip_sum); 
+		printf("Header iph->ip_src: %x\n",iph->ip_src); 
+		printf("Header iph->ip_dst: %x\n",iph->ip_dst); 
+
+		printf("Header btph->op: %x\n",btph->op); 
+		printf("Header btph->htype: %x\n",btph->htype); 
+		printf("Header btph->hlen: %x\n",btph->hlen); 
+		printf("Header btph->hops: %x\n",btph->hops); 
+		printf("Header btph->xid: %x\n",btph->xid); 
+		printf("Header btph->secs: %x\n",btph->secs); 
+		printf("Header btph->ciaddr: %x\n",btph->ciaddr); 
+		printf("Header btph->yiaddr: %x\n",btph->yiaddr); 
+		printf("Header btph->siaddr: %x\n",btph->siaddr); 
+		printf("Header btph->giaddr: %x\n",btph->giaddr); 
+
+ 		printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n",
+		       btph->chaddr[0], btph->chaddr[1], btph->chaddr[2],
+		       btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]);
+
+#endif
+		return 0;
+
+		/* only do this for the time specified during set_timer() */
+	} while (get_timer() > 0);
+	return -1;
+}
+
+
+int
+bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
+{
+	int i = (int) retries+1;
+	fn_ip->own_ip = 0;
+
+	printf("   ");
+
+	response_buffer = ret_buffer;
+
+	do {
+		printf("\b\b%02d", i);
+		if (!i--) {
+			printf("\nGiving up after %d bootp requests\n",
+			       retries+1);
+			return -1;
+		}
+		send_bootp(fn_ip);
+		/* if the timer in receive_bootp expired it will return
+		 * -1 and we will just send another bootp request just
+		 * in case the previous one was lost. And because we don't
+		 * trust the network cable we keep on doing this 30 times */
+	} while (receive_bootp(fn_ip) != 0);
+	printf("\b\b\b");
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
new file mode 100644
index 0000000..8f81bf3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
@@ -0,0 +1,993 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/** \file dhcp.c <pre>
+ * **************** State-transition diagram for DHCP client  *************
+ *
+ *   +---------+                  Note: DHCP-server msg / DHCP-client msg
+ *   |  INIT   |
+ *   +---------+
+ *        |
+ *        |  - / Discover
+ *        V
+ *   +---------+
+ *   | SELECT  |                     Timeout
+ *   +---------+                        |
+ *        |                             |
+ *        |  Offer / Request            |
+ *        |                             |
+ *        V                             V
+ *   +---------+     NACK / -      ***********
+ *   | REQUEST | ----------------> *  FAULT  *
+ *   +---------+                   ***********
+ *        |
+ *        |          ACK / -       ***********
+ *        +----------------------> * SUCCESS *
+ *                                 ***********
+ *
+ * ************************************************************************
+ * </pre> */
+
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <dhcp.h>
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+#include <dns.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* DHCP Message Types */
+#define DHCPDISCOVER    1
+#define DHCPOFFER       2
+#define DHCPREQUEST     3
+#define DHCPDECLINE     4
+#define DHCPACK	        5
+#define DHCPNACK        6
+#define DHCPRELEASE     7
+#define DHCPINFORM      8
+
+/* DHCP Option Codes */
+#define DHCP_MASK              1
+#define DHCP_ROUTER            3
+#define DHCP_DNS               6
+#define DHCP_REQUESTED_IP     50
+#define DHCP_OVERLOAD         52
+#define DHCP_MSG_TYPE         53
+#define DHCP_SERVER_ID        54
+#define DHCP_REQUEST_LIST     55
+#define DHCP_TFTP_SERVER      66
+#define DHCP_BOOTFILE         67
+#define DHCP_ENDOPT         0xFF
+#define DHCP_PADOPT         0x00
+
+/* "file/sname" overload option values */
+#define DHCP_OVERLOAD_FILE     1
+#define DHCP_OVERLOAD_SNAME    2
+#define DHCP_OVERLOAD_BOTH     3
+
+/* DHCP states codes */
+#define DHCP_STATE_SELECT      1
+#define DHCP_STATE_REQUEST     2
+#define DHCP_STATE_SUCCESS     3
+#define DHCP_STATE_FAULT       4
+
+static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
+/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
+
+/** \struct dhcp_options_t
+ *  This structure is used to fill options in DHCP-msg during transmitting
+ *  or to retrieve options from DHCP-msg during receiving.
+ *  <p>
+ *  If flag[i] == TRUE then field for i-th option retains valid value and
+ *  information from this field may retrived (in case of receiving) or will
+ *  be transmitted (in case of transmitting).
+ *  
+ */
+typedef struct {
+	uint8_t    flag[256];         /**< Show if corresponding opt. is valid */
+	uint8_t    request_list[256]; /**< o.55 If i-th member is TRUE, then i-th  
+	                                  option will be requested from server */
+	uint32_t   server_ID;         /**< o.54 Identifies DHCP-server         */
+	uint32_t   requested_IP;      /**< o.50 Must be filled in DHCP-Request */
+	uint32_t   dns_IP;            /**< o. 6 DNS IP                         */
+	uint32_t   router_IP;         /**< o. 3 Router IP                      */
+	uint32_t   subnet_mask;       /**< o. 1 Subnet mask                    */
+	uint8_t    msg_type;          /**< o.53 DHCP-message type              */
+	uint8_t    overload;          /**< o.52 Overload sname/file fields     */
+	int8_t     tftp_server[256];  /**< o.66 TFTP server name               */
+	int8_t     bootfile[256];     /**< o.67 Boot file name                 */
+} dhcp_options_t;
+
+/** Stores state of DHCP-client (refer to State-transition diagram) */
+static uint8_t dhcp_state;
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static int32_t
+dhcp_attempt(void);
+
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
+
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+                    dhcp_options_t * opt_struct);
+
+static int8_t
+dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+                   uint8_t src_options[], uint32_t src_len);
+
+static int8_t
+dhcp_find_option(uint8_t options[], uint32_t len,
+                 uint8_t op_code, uint32_t * op_offset);
+
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+                   uint8_t * new_option);
+
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+                    uint32_t dst_offset, uint8_t * new_option);
+
+static void
+dhcp_send_discover(void);
+
+static void
+dhcp_send_request(void);
+
+static uint8_t
+strtoip(int8_t * str, uint32_t * ip);
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t  ether_packet[ETH_MTU_SIZE];
+static uint32_t dhcp_own_ip        = 0;
+static uint32_t dhcp_server_ip     = 0;
+static uint32_t dhcp_siaddr_ip     = 0;
+static int8_t   dhcp_filename[256];
+static int8_t   dhcp_tftp_name[256];
+
+static char   * response_buffer;
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * DHCP: Obtains IP and configuration info from DHCP server
+ *       (makes several attempts).
+ *
+ * @param  boot_device   a socket number used to send and recieve packets
+ * @param  fn_ip         contains the following configuration information:
+ *                       client MAC, client IP, TFTP-server MAC, 
+ *                       TFTP-server IP, Boot file name
+ * @return               ZERO - IP and configuration info obtained;
+ *                       NON ZERO - error condition occurs.
+ */
+int32_t
+dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) {
+	int i = (int) retries+1;
+
+	uint32_t dhcp_tftp_ip     = 0;
+	strcpy((char *) dhcp_filename, "");
+	strcpy((char *) dhcp_tftp_name, "");
+
+	response_buffer = ret_buffer;
+
+	printf("    ");
+
+	do {
+		printf("\b\b\b%03d", i-1);
+		if (getchar() == 27) {
+			printf("\nAborted\n");
+			return -1;
+		}
+		if (!--i) {
+			printf("\nGiving up after %d DHCP requests\n", retries);
+			return -1;
+		}
+	} while (!dhcp_attempt());
+	printf("\b\b\b\b");
+
+	if (fn_ip->own_ip) {
+		dhcp_own_ip = fn_ip->own_ip;
+	}
+	if (fn_ip->server_ip) {
+		dhcp_siaddr_ip = fn_ip->server_ip;
+	}
+	if(fn_ip->filename[0] != 0) {
+		strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
+	}
+
+	// TFTP SERVER
+	if (!strlen((char *) dhcp_tftp_name)) {
+		if (!dhcp_siaddr_ip) {
+			// ERROR: TFTP name is not presented
+			return -3;
+		}
+
+		// take TFTP-ip from siaddr field
+		dhcp_tftp_ip = dhcp_siaddr_ip;
+	}
+	else {
+		// TFTP server defined by its name
+		if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
+			if (!dns_get_ip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
+				// DNS error - can't obtain TFTP-server name  
+				// Use TFTP-ip from siaddr field, if presented
+				if (dhcp_siaddr_ip) {
+					dhcp_tftp_ip = dhcp_siaddr_ip;
+				}
+				else {
+					// ERROR: Can't obtain TFTP server IP
+					return -4;
+				}
+			}
+		}
+	}
+
+	// Store configuration info into filename_ip strucutre
+	fn_ip -> own_ip = dhcp_own_ip;
+	fn_ip -> server_ip = dhcp_tftp_ip;
+	strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
+
+	return 0;
+}
+
+/**
+ * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
+ */
+static int32_t
+dhcp_attempt(void) {
+	int sec;
+
+	// Send DISCOVER message and switch DHCP-client to SELECT state
+	dhcp_send_discover();
+
+	dhcp_state = DHCP_STATE_SELECT;
+
+	// setting up a timer with a timeout of two seconds
+	for (sec = 0; sec < 2; sec++) {
+		set_timer(TICKS_SEC);
+		do {
+			receive_ether();
+
+			// Wait until client will switch to Final state or Timeout occurs
+			switch (dhcp_state) {
+			case DHCP_STATE_SUCCESS :
+				return 1;
+			case DHCP_STATE_FAULT :
+				return 0;
+			}
+		} while (get_timer() > 0);
+	}
+
+	// timeout 
+	return 0;
+}
+
+/**
+ * DHCP: Supplements DHCP-message with options stored in structure.
+ *       For more information about option coding see dhcp_options_t.
+ *
+ * @param  opt_field     Points to the "vend" field of DHCP-message  
+ *                       (destination)
+ * @param  opt_struct    this structure stores info about the options wich
+ *                       will be added to DHCP-message (source)
+ * @return               TRUE - options packed;
+ *                       FALSE - error condition occurs.
+ * @see                  dhcp_options_t
+ */
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
+	uint8_t * options = opt_field;
+	uint16_t i, sum; // used to define is any options set
+
+	// magic
+	memcpy(options, dhcp_magic, 4);
+	options += 4;
+
+	// fill message type
+	switch (opt_struct -> msg_type) {
+	case DHCPDISCOVER :
+	case DHCPREQUEST :
+	case DHCPDECLINE :
+	case DHCPINFORM :
+	case DHCPRELEASE :
+		options[0] = DHCP_MSG_TYPE;
+		options[1] = 1;
+		options[2] = opt_struct -> msg_type;
+		options += 3;
+		break;
+	default :
+		return 0; // Unsupported DHCP-message
+	}
+
+	if (opt_struct -> overload) {
+		options[0] = DHCP_OVERLOAD;
+		options[1] = 0x01;
+		options[2] = opt_struct -> overload;
+		options +=3;
+	}
+
+	if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
+		options[0] = DHCP_REQUESTED_IP;
+		options[1] = 0x04;
+		* (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
+		options +=6;
+	}
+
+	if (opt_struct -> flag[DHCP_SERVER_ID]) {
+		options[0] = DHCP_SERVER_ID;
+		options[1] = 0x04;
+		* (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
+		options +=6;
+	}
+
+	sum = 0;
+	for (i = 0; i < 256; i++)
+		sum += opt_struct -> request_list[i];
+
+	if (sum) {
+		options[0] = DHCP_REQUEST_LIST;
+		options[1] = sum;
+		options += 2;
+		for (i = 0; i < 256; i++) {
+			if (opt_struct -> request_list[i]) {
+				options[0] = i; options++;
+			}
+		}
+	}
+
+	if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
+		options[0] = DHCP_TFTP_SERVER;
+		options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
+		memcpy(options + 2, opt_struct -> tftp_server, options[1]);
+		options += options[1] + 2;
+	}
+
+	if (opt_struct -> flag[DHCP_BOOTFILE]) {
+		options[0] = DHCP_BOOTFILE;
+		options[1] = strlen((char *) opt_struct -> bootfile) + 1;
+		memcpy(options + 2, opt_struct -> bootfile, options[1]);
+		options += options[1] + 2;
+	}
+
+	// end options
+	options[0] = 0xFF;
+	options++;
+
+	return 1;
+}
+
+/**
+ * DHCP: Extracts encoded options from DHCP-message into the structure.
+ *       For more information about option coding see dhcp_options_t.
+ *
+ * @param  opt_field     Points to the "options" field of DHCP-message  
+ *                       (source).
+ * @param  opt_len       Length of "options" field.
+ * @param  opt_struct    this structure stores info about the options wich
+ *                       was extracted from DHCP-message (destination).
+ * @return               TRUE - options extracted;
+ *                       FALSE - error condition occurs.
+ * @see                  dhcp_options_t
+ */
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+                    dhcp_options_t * opt_struct) {
+	int32_t offset = 0;
+
+	memset(opt_struct, 0, sizeof(dhcp_options_t));
+
+	// magic
+	if (memcmp(opt_field, dhcp_magic, 4)) {
+		return 0;
+	}
+
+	offset += 4;
+	while (offset < opt_len) {
+		opt_struct -> flag[opt_field[offset]] = 1;
+		switch(opt_field[offset]) {
+		case DHCP_OVERLOAD :
+			opt_struct -> overload = opt_field[offset + 2];
+			offset += 2 + opt_field[offset + 1]; 
+			break;
+
+		case DHCP_REQUESTED_IP :
+			opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+			offset += 2 + opt_field[offset + 1]; 
+			break;
+
+		case DHCP_MASK :
+			opt_struct -> flag[DHCP_MASK] = 1;
+			opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
+			offset += 2 + opt_field[offset + 1]; 
+			break;
+
+		case DHCP_DNS :
+			opt_struct -> flag[DHCP_DNS] = 1;
+			opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+			offset += 2 + opt_field[offset + 1]; 
+			break;
+
+		case DHCP_ROUTER :
+			opt_struct -> flag[DHCP_ROUTER] = 1;
+			opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+			offset += 2 + opt_field[offset + 1]; 
+			break;
+
+		case DHCP_MSG_TYPE :
+			if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
+				opt_struct -> msg_type = opt_field[offset + 2];
+			else
+				return 0;
+			offset += 2 + opt_field[offset + 1];
+			break;
+
+		case DHCP_SERVER_ID :
+			opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
+			offset += 2 + opt_field[offset + 1];
+			break;
+
+		case DHCP_TFTP_SERVER	:
+			memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
+			(opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
+			offset += 2 + opt_field[offset + 1];
+			break;
+
+		case DHCP_BOOTFILE :
+			memcpy(opt_struct ->  bootfile, opt_field + offset + 2, opt_field[offset + 1]);
+			(opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
+			offset += 2 + opt_field[offset + 1];
+			break;
+
+		case DHCP_PADOPT :
+			offset++;
+			break;
+
+		case DHCP_ENDOPT :  // End of options
+			return 1;
+
+		default :
+			offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
+		}
+	}
+	if (offset == opt_len)
+		return 1; // options finished without 0xFF
+
+	return 0;
+}
+
+/**
+ * DHCP: Appends information from source "options" into dest "options".
+ *       This function is used to support "file/sname" overloading.
+ *
+ * @param  dst_options   destanation "options" field
+ * @param  dst_len       size of dst_options (modified by this function)
+ * @param  src_options   source "options" field
+ * @param  src_len       size of src_options
+ * @return               TRUE - options merged;
+ *                       FALSE - error condition occurs.
+ */
+static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+                                 uint8_t src_options[], uint32_t src_len) {
+	int32_t dst_offset, src_offset = 0;
+
+	// remove ENDOPT if presented
+	if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
+		* dst_len = dst_offset;
+
+	while (src_offset < src_len) {
+		switch(src_options[src_offset]) {
+		case DHCP_PADOPT:
+			src_offset++;
+			break;
+		case DHCP_ENDOPT:
+			return 1;
+		default:
+			if (dhcp_find_option(dst_options, * dst_len,
+			                     src_options[src_offset],
+			                     (uint32_t *) &dst_offset)) {
+				dhcp_combine_option(dst_options, dst_len,
+				                    dst_offset,
+				                    (uint8_t *) src_options +
+				                    src_offset);
+			}
+			else {
+				dhcp_append_option(dst_options, dst_len, src_options + src_offset);
+			}
+			src_offset += 2 + src_options[src_offset + 1];
+		}
+	}
+
+	if (src_offset == src_len) 
+		return 1;
+	return 0;
+}
+
+/**
+ * DHCP: Finds given occurence of the option with the given code (op_code)
+ *       in "options" field of DHCP-message.
+ *
+ * @param  options       "options" field of DHCP-message
+ * @param  len           length of the "options" field
+ * @param  op_code       code of the option to find
+ * @param  op_offset     SUCCESS - offset to an option occurence;
+ *                       FAULT - offset is set to zero.
+ * @return               TRUE - option was find;
+ *                       FALSE - option wasn't find.
+ */
+static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
+                               uint8_t op_code, uint32_t * op_offset) {
+	uint32_t srch_offset = 0;
+	* op_offset = 0;
+
+	while (srch_offset < len) {
+		if (options[srch_offset] == op_code) {
+			* op_offset = srch_offset;
+			return 1;
+		}
+		if (options[srch_offset] == DHCP_ENDOPT)
+			return 0;
+
+		if (options[srch_offset] == DHCP_PADOPT)
+			srch_offset++;
+		else
+			srch_offset += 2 + options[srch_offset + 1];
+	}
+	return 0;
+}
+
+/**
+ * DHCP: Appends new option from one list (src) into the tail
+ *       of another option list (dst)
+ *
+ * @param  dst_options   "options" field of DHCP-message
+ * @param  dst_len       length of the "options" field (modified)
+ * @param  new_option    points to an option in another list (src)
+ */
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+                   uint8_t * new_option) {
+	memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
+	* dst_len += 2 + *(new_option + 1);
+}
+
+/**
+ * DHCP: This function is used when options with the same code are
+ *       presented in both merged lists. In this case information
+ *       about the option from one list (src) is combined (complemented)
+ *       with information about the option in another list (dst).
+ *
+ * @param  dst_options  "options" field of DHCP-message
+ * @param  dst_len       length of the "options" field (modified)
+ * @param  dst_offset    offset of the option from beggining of the list
+ * @param  new_option    points to an option in another list (src)
+ */
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+                    uint32_t dst_offset, uint8_t * new_option) {
+
+	uint8_t tmp_buffer[1024]; // use to provide safe memcpy
+	uint32_t tail_len;
+
+	// move all subsequent options (allocate size for additional info)
+	tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
+
+	memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
+	memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
+	       tmp_buffer, tail_len);
+
+	// add new_content to option
+	memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
+	       * (new_option + 1));
+	dst_options[dst_offset + 1] += * (new_option + 1);
+
+	// correct dst_len
+	* dst_len += * (new_option + 1);
+}
+
+/**
+ * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
+ */
+static void
+dhcp_send_discover(void) {
+	uint32_t packetsize = sizeof(struct iphdr) +
+	                      sizeof(struct udphdr) + sizeof(struct btphdr);
+	struct btphdr *btph;
+	dhcp_options_t opt;
+
+	memset(ether_packet, 0, packetsize);
+
+	btph = (struct btphdr *) (&ether_packet[
+	       sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+	btph -> op = 1;
+	btph -> htype = 1;
+	btph -> hlen = 6;
+	memcpy(btph -> chaddr, get_mac_address(), 6);
+
+	memset(&opt, 0, sizeof(dhcp_options_t));
+
+	opt.msg_type = DHCPDISCOVER;
+
+	opt.request_list[DHCP_MASK] = 1;
+	opt.request_list[DHCP_DNS] = 1;
+	opt.request_list[DHCP_ROUTER] = 1;
+	opt.request_list[DHCP_TFTP_SERVER] = 1;
+	opt.request_list[DHCP_BOOTFILE] = 1;
+
+	dhcp_encode_options(btph -> vend, &opt);
+
+	fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+	            sizeof(struct btphdr) + sizeof(struct udphdr),
+	            UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+	fill_iphdr(ether_packet, sizeof(struct btphdr) +
+	           sizeof(struct udphdr) + sizeof(struct iphdr),
+	           IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
+
+	send_ipv4(ether_packet, packetsize);
+}
+
+/**
+ * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
+ */
+static void
+dhcp_send_request(void) {
+	uint32_t packetsize = sizeof(struct iphdr) +
+	                      sizeof(struct udphdr) + sizeof(struct btphdr);
+	struct btphdr *btph;
+	dhcp_options_t opt;
+
+	memset(ether_packet, 0, packetsize);
+
+	btph = (struct btphdr *) (&ether_packet[
+	       sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+	btph -> op = 1;
+	btph -> htype = 1;
+	btph -> hlen = 6;
+	memcpy(btph -> chaddr, get_mac_address(), 6);
+
+	memset(&opt, 0, sizeof(dhcp_options_t));
+
+	opt.msg_type = DHCPREQUEST;
+	memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
+	opt.flag[DHCP_REQUESTED_IP] = 1;
+	memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
+	opt.flag[DHCP_SERVER_ID] = 1;
+
+	opt.request_list[DHCP_MASK] = 1;
+	opt.request_list[DHCP_DNS] = 1;
+	opt.request_list[DHCP_ROUTER] = 1;
+	opt.request_list[DHCP_TFTP_SERVER] = 1;
+	opt.request_list[DHCP_BOOTFILE] = 1;
+
+	dhcp_encode_options(btph -> vend, &opt);
+
+	fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+	            sizeof(struct btphdr) + sizeof(struct udphdr),
+	            UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+	fill_iphdr(ether_packet, sizeof(struct btphdr) +
+	           sizeof(struct udphdr) + sizeof(struct iphdr),
+	           IPTYPE_UDP, 0, 0xFFFFFFFF);
+
+	send_ipv4(ether_packet, packetsize);
+}
+
+
+/**
+ * DHCP: Sends DHCP-Release message. Releases occupied IP.
+ */
+void dhcp_send_release(void) {
+	uint32_t packetsize = sizeof(struct iphdr) +
+	                      sizeof(struct udphdr) + sizeof(struct btphdr);
+	struct btphdr *btph;
+	dhcp_options_t opt;
+
+	btph = (struct btphdr *) (&ether_packet[
+	       sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+	memset(ether_packet, 0, packetsize);
+
+	btph -> op = 1;
+	btph -> htype = 1;
+	btph -> hlen = 6;
+	strcpy((char *) btph -> file, "");
+	memcpy(btph -> chaddr, get_mac_address(), 6);
+	btph -> ciaddr = htonl(dhcp_own_ip);
+
+	memset(&opt, 0, sizeof(dhcp_options_t));
+
+	opt.msg_type = DHCPRELEASE;
+	opt.server_ID = dhcp_server_ip;
+	opt.flag[DHCP_SERVER_ID] = 1;
+
+	dhcp_encode_options(btph -> vend, &opt);
+
+	fill_udphdr(&ether_packet[sizeof(struct iphdr)], 
+	            sizeof(struct btphdr) + sizeof(struct udphdr),
+	            UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+	fill_iphdr(ether_packet, sizeof(struct btphdr) +
+	           sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
+	           dhcp_own_ip, dhcp_server_ip);
+
+	send_ipv4(ether_packet, packetsize);
+}
+
+/**
+ * DHCP: Handles DHCP-messages according to Receive-handle diagram.
+ *       Changes the state of DHCP-client.
+ *
+ * @param  packet     BootP/DHCP-packet to be handled
+ * @param  packetsize length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ * @see               receive_ether
+ * @see               btphdr
+ */
+
+int8_t
+handle_dhcp(uint8_t * packet, int32_t packetsize) {
+	struct btphdr * btph;
+	struct iphdr * iph;
+	dhcp_options_t opt;
+
+	memset(&opt, 0, sizeof(dhcp_options_t));  
+	btph = (struct btphdr *) packet;
+	iph = (struct iphdr *) packet - sizeof(struct udphdr) -
+	      sizeof(struct iphdr);
+	if (btph -> op != 2)
+		return -1; // it is not Boot Reply
+
+	if(response_buffer) {
+		if(packetsize <= 1720)
+			memcpy(response_buffer, packet, packetsize);
+		else
+			memcpy(response_buffer, packet, 1720);
+	}
+
+	if (memcmp(btph -> vend, dhcp_magic, 4)) {
+		// It is BootP - RFC 951
+		dhcp_own_ip    = htonl(btph -> yiaddr);
+		dhcp_siaddr_ip = htonl(btph -> siaddr);
+		dhcp_server_ip = htonl(iph -> ip_src);
+
+		if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+			strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
+			        sizeof(btph -> sname));
+			dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+		}
+
+		if (strlen((char *) btph -> file)) {
+			strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+			dhcp_filename[sizeof(btph -> file)] = 0;
+		}
+
+		dhcp_state = DHCP_STATE_SUCCESS;
+		return 0;
+	}
+
+
+	// decode options  
+	if (!dhcp_decode_options(btph -> vend, packetsize -
+	                         sizeof(struct btphdr) + sizeof(btph -> vend),
+	                         &opt)) {
+		return -1;  // can't decode options
+	}
+
+	if (opt.overload) {
+		int16_t decode_res = 0;
+		uint8_t options[1024]; // buffer for merged options
+		uint32_t opt_len;
+
+		// move 1-st part of options from vend field into buffer
+		opt_len = packetsize - sizeof(struct btphdr) +
+		          sizeof(btph -> vend) - 4;
+		memcpy(options, btph -> vend, opt_len + 4);
+
+		// add other parts
+		switch (opt.overload) {
+		case DHCP_OVERLOAD_FILE:
+			decode_res = dhcp_merge_options(options + 4, &opt_len,
+			                                btph -> file,
+			                                sizeof(btph -> file));
+			break;
+		case DHCP_OVERLOAD_SNAME:
+			decode_res = dhcp_merge_options(options + 4, &opt_len,
+			                                btph -> sname,
+			                                sizeof(btph -> sname));
+			break;
+		case DHCP_OVERLOAD_BOTH:
+			decode_res = dhcp_merge_options(options + 4, &opt_len,
+			                                btph -> file,
+			                                sizeof(btph -> file));
+			if (!decode_res)
+				break;
+			decode_res = dhcp_merge_options(options + 4, &opt_len,
+			                                btph -> sname,
+			                                sizeof(btph -> sname));
+			break;
+		}
+
+		if (!decode_res)
+			return -1; // bad options in sname/file fields
+
+		// decode merged options
+		if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
+			return -1; // can't decode options
+		}
+	}
+
+	if (!opt.msg_type) {
+		// It is BootP with Extensions - RFC 1497
+		// retrieve conf. settings from BootP - reply
+		dhcp_own_ip = htonl(btph -> yiaddr);
+		dhcp_siaddr_ip = htonl(btph -> siaddr);
+		if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+			strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
+			dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+		}
+
+		if (strlen((char *) btph -> file)) {
+			strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+			dhcp_filename[sizeof(btph -> file)] = 0;
+		}
+
+		// retrieve DHCP-server IP from IP-header
+		dhcp_server_ip = iph -> htonl(ip_src);
+
+		dhcp_state = DHCP_STATE_SUCCESS;
+	}
+	else {
+		// It is DHCP - RFC 2131 & RFC 2132
+		// opt contains parameters from server
+		switch (dhcp_state) {
+		case DHCP_STATE_SELECT :
+			if (opt.msg_type == DHCPOFFER) {
+				dhcp_own_ip = htonl(btph -> yiaddr);
+				dhcp_server_ip = opt.server_ID;
+				dhcp_send_request();
+				dhcp_state = DHCP_STATE_REQUEST;
+			}
+			return 0;
+		case DHCP_STATE_REQUEST :
+			switch (opt.msg_type) {
+			case DHCPNACK :
+				dhcp_own_ip = 0;
+				dhcp_server_ip = 0;
+				dhcp_state = DHCP_STATE_FAULT;
+				break;
+			case DHCPACK :
+				dhcp_own_ip = htonl(btph -> yiaddr);
+				dhcp_server_ip = opt.server_ID;
+				dhcp_siaddr_ip = htonl(btph -> siaddr);
+				if (opt.flag[DHCP_TFTP_SERVER]) {
+					strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
+				}
+				else {
+					strcpy((char *) dhcp_tftp_name, "");
+					if ((opt.overload != DHCP_OVERLOAD_SNAME &&
+					     opt.overload != DHCP_OVERLOAD_BOTH) &&
+					     !dhcp_siaddr_ip) {
+						strncpy((char *) dhcp_tftp_name,
+						        (char *) btph->sname,
+						        sizeof(btph -> sname));
+						dhcp_tftp_name[sizeof(btph->sname)] = 0;
+					}
+				}
+
+				if (opt.flag[DHCP_BOOTFILE]) {
+					strcpy((char *) dhcp_filename, (char *) opt.bootfile);
+				}
+				else {
+					strcpy((char *) dhcp_filename, "");
+					if (opt.overload != DHCP_OVERLOAD_FILE &&
+						opt.overload != DHCP_OVERLOAD_BOTH && 
+						strlen((char *) btph -> file)) {
+						strncpy((char *) dhcp_filename,
+						        (char *) btph->file,
+						        sizeof(btph->file));
+						dhcp_filename[sizeof(btph -> file)] = 0;
+					}
+				}
+
+				dhcp_state = DHCP_STATE_SUCCESS;
+				break;
+			default:
+				break; // Unused DHCP-message - do nothing
+			}
+			break;
+		default :
+			return -1; // Illegal DHCP-client state
+		}
+	}
+
+	if (dhcp_state == DHCP_STATE_SUCCESS) {
+
+		// initialize network entity with real own_ip
+		// to be able to answer for foreign requests
+		set_ipv4_address(dhcp_own_ip);
+
+		/* Subnet mask */
+		if (opt.flag[DHCP_MASK]) {
+			/* Router */
+			if (opt.flag[DHCP_ROUTER]) {
+				set_ipv4_router(opt.router_IP);
+				set_ipv4_netmask(opt.subnet_mask);
+			}
+		}
+
+		/* DNS-server */
+		if (opt.flag[DHCP_DNS]) {
+			dns_init(opt.dns_IP);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * DHCP: Converts "255.255.255.255" -> 32-bit long IP
+ *
+ * @param  str        string to be converted
+ * @param  ip         in case of SUCCESS - 32-bit long IP
+                      in case of FAULT - zero
+ * @return            TRUE - IP converted successfully;
+ *                    FALSE - error condition occurs (e.g. bad format)
+ */
+static uint8_t
+strtoip(int8_t * str, uint32_t * ip) {
+	int8_t ** ptr = &str;
+	int16_t i = 0, res, len;
+	char octet[256];
+
+	* ip = 0;
+
+	while (**ptr != 0) {
+		if (i > 3 || !isdigit(**ptr))
+			return 0;
+		if (strstr((char *) * ptr, ".") != NULL) {
+			len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") - 
+			      (int8_t *) (* ptr));
+			strncpy(octet, (char *) * ptr, len); octet[len] = 0;
+			* ptr += len;
+		}
+		else {
+			strcpy(octet, (char *) * ptr);
+			* ptr += strlen(octet);
+		}
+		res = strtol(octet, NULL, 10);
+		if ((res > 255) || (res < 0))
+			return 0;
+		* ip = ((* ip) << 8) + res;
+		i++;
+		if (** ptr == '.')
+			(*ptr)++;
+	}
+
+	if (i != 4)
+		return 0;
+	return 1;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
new file mode 100644
index 0000000..853200c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _DHCP_H_
+#define _DHCP_H_
+
+#include <types.h>
+
+#ifdef USE_MTFTP
+#include <netlib/mtftp.h>
+#else
+#include <netlib/tftp.h>
+#endif
+
+/** \struct btphdr
+ *  A header for BootP/DHCP-messages.
+ *  For more information see RFC 951 / RFC 2131.
+ */
+struct btphdr {
+	uint8_t op;          /**< Identifies is it request (1) or reply (2)    */
+	uint8_t htype;       /**< HW address type (ethernet usually)           */
+	uint8_t hlen;        /**< HW address length                            */
+	uint8_t hops;        /**< This info used by relay agents (not used)    */
+	uint32_t xid;        /**< This ID is used to match queries and replies */
+	uint16_t secs;       /**< Unused                                       */
+	uint16_t unused;     /**< Unused                                       */
+	uint32_t ciaddr;     /**< Client IP address (if client knows it)       */
+	uint32_t yiaddr;     /**< "Your" (client) IP address                   */
+	uint32_t siaddr;     /**< Next server IP address (TFTP server IP)      */
+	uint32_t giaddr;     /**< Gateway IP address (used by relay agents)    */
+	uint8_t chaddr[16];  /**< Client HW address                            */
+	uint8_t sname[64];   /**< Server host name (TFTP server name)          */
+	uint8_t file[128];   /**< Boot file name                               */
+	uint8_t vend[64];    /**< Optional parameters field (DHCP-options)     */
+};
+
+int bootp(char *ret_buffer, filename_ip_t *, unsigned int);
+int dhcp(char *ret_buffer, filename_ip_t *, unsigned int);
+void dhcp_send_release(void);
+
+/* Handles DHCP-packets, which are detected by receive_ether. */
+extern int8_t handle_dhcp(uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.c
new file mode 100644
index 0000000..5a931d5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.c
@@ -0,0 +1,485 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <dns.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+
+#define DNS_FLAG_MSGTYPE    0xF800	/**< Message type mask (opcode) */
+#define DNS_FLAG_SQUERY     0x0000 	/**< Standard query type        */
+#define DNS_FLAG_SRESPONSE  0x8000	/**< Standard response type     */
+#define DNS_FLAG_RD         0x0100  /**< Recursion desired flag     */
+#define DNS_FLAG_RCODE      0x000F	/**< Response code mask
+                                         (stores err.cond.) code    */
+#define DNS_RCODE_NERROR    0       /**< "No errors" code           */
+
+#define DNS_QTYPE_A         1       /**< A 32-bit IP record type */
+#define DNS_QTYPE_CNAME     5       /**< Canonical name record type */
+
+#define DNS_QCLASS_IN       1       /**< Query class for internet msgs */
+
+/** \struct dnshdr
+ *  A header for DNS-messages (see RFC 1035, paragraph 4.1.1).
+ *  <p>
+ *  DNS-message consist of DNS-header and 4 optional sections,
+ *  arranged in the following order:<ul>
+ *    <li> DNS-header
+ *    <li> question section
+ *    <li> answer section
+ *    <li> authority section
+ *    <li> additional section
+ *  </ul>
+ */
+struct dnshdr {
+	uint16_t   id;      /**< an identifier used to match up replies */
+	uint16_t   flags;   /**< contains op_code, err_code, etc. */
+	uint16_t   qdcount; /**< specifies the number of entries in the 
+	                         question section */
+	uint16_t   ancount; /**< specifies the number of entries in the 
+	                         answer section */
+	uint16_t   nscount; /**< specifies the number of entries in the
+	                         authority section */
+	uint16_t   arcount; /**< specifies the number of entries in the 
+	                         additional section */
+};
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static void
+dns_send_query(int8_t * domain_name);
+
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name);
+
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name);
+
+static int8_t
+urltohost(char * url, char * host_name);
+
+static int8_t
+hosttodomain(char * host_name, char * domain_name);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static int32_t dns_server_ip     = 0;
+static int32_t dns_result_ip     = 0;
+static int8_t  dns_error         = 0;        /**< Stores error code or 0 */
+static int8_t  dns_domain_name[0x100];       /**< Raw domain name        */
+static int8_t  dns_domain_cname[0x100];      /**< Canonical domain name  */
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * DNS: Initialize the environment for DNS client.
+ *      To perfrom DNS-queries use the function dns_get_ip.
+ *
+ * @param  device_socket a socket number used to send and recieve packets
+ * @param  server_ip     DNS-server IPv4 address (e.g. 127.0.0.1)
+ * @return               TRUE in case of successful initialization;
+ *                       FALSE in case of fault (e.g. can't obtain MAC).
+ * @see                  dns_get_ip
+ */
+int8_t
+dns_init(uint32_t _dns_server_ip) {
+	dns_server_ip = _dns_server_ip;
+	return 0;
+}
+
+/**
+ * DNS: For given URL retrieves IPv4 from DNS-server.
+ *      <p>
+ *      URL can be given in one of the following form: <ul>
+ *      <li> scheme with full path with (without) user and password
+ *           <br>(e.g. "http://user:pass@www.host.org/url-path");
+ *      <li> host name with url-path
+ *           <br>(e.g. "www.host.org/url-path");
+ *      <li> nothing but host name
+ *           <br>(e.g. "www.host.org");
+ *      </ul>
+ *
+ * @param  url       the URL to be resolved
+ * @param  domain_ip In case of SUCCESS stores extracted IP.
+ *                   In case of FAULT stores zeros (0.0.0.0).
+ * @return           TRUE - IP successfuly retrieved;
+ *                   FALSE - error condition occurs.
+ */
+int8_t
+dns_get_ip(int8_t * url, uint32_t * domain_ip) {
+	/* this counter is used so that we abort after 30 DNS request */
+	int32_t i;
+	/* this buffer stores host name retrieved from url */
+	static int8_t host_name[0x100];
+
+	(* domain_ip) = 0;
+
+	// Retrieve host name from URL
+	if (!urltohost((char *) url, (char *) host_name)) {
+		printf("\nERROR:\t\t\tBad URL!\n");
+		return 0;
+	}
+
+	// Reformat host name into a series of labels
+	if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) {
+		printf("\nERROR:\t\t\tBad host name!\n");
+		return 0;
+	}
+
+	// Check if DNS server is presented and accessable
+	if (dns_server_ip == 0) {
+		printf("\nERROR:\t\t\tCan't resolve domain name "
+		       "(DNS server is not presented)!\n");
+		return 0;
+	}
+
+	// Use DNS-server to obtain IP
+	dns_result_ip = 0;
+	dns_error     = 0;
+	strcpy((char *) dns_domain_cname, "");
+
+	for(i = 0; i < 30; ++i) {
+		// Use canonical name in case we obtained it
+		if (strlen((char *) dns_domain_cname))
+		  dns_send_query(dns_domain_cname);
+		else
+		  dns_send_query(dns_domain_name);
+
+		// setting up a timer with a timeout of one seconds
+		set_timer(TICKS_SEC);
+		do {
+			receive_ether();
+			if (dns_error)
+				return 0; // FALSE - error
+			if (dns_result_ip != 0) {
+				(* domain_ip) = dns_result_ip;
+				return 1; // TRUE - success (domain IP retrieved)
+			}
+		} while (get_timer() > 0);
+	}
+
+	printf("\nGiving up after %d DNS requests\n", i);
+	return 0; // FALSE - domain name wasn't retrieved
+}
+
+/**
+ * DNS: Handles DNS-messages according to Receive-handle diagram.
+ *      Sets dns_result_ip for given dns_domain_name (see dns_get_ip)
+ *      or signals error condition occurs during DNS-resolving proccess
+ *      by setting dns_error flag.
+ *
+ * @param  packet     DNS-packet to be handled
+ * @param  packetsize length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ * @see               dns_get_ip
+ * @see               receive_ether
+ * @see               dnshdr
+ */
+int32_t
+handle_dns(uint8_t * packet, int32_t packetsize) {
+	struct dnshdr * dnsh = (struct dnshdr *) packet;
+	uint8_t * resp_section = packet + sizeof(struct dnshdr);
+	/* This string stores domain name from DNS-packets */
+	static int8_t handle_domain_name[0x100]; 
+	int i;
+
+	// verify ID - is it response for our query?
+	if (dnsh -> id != htons(0x1234))
+		return 0;
+
+	// Is it DNS response?
+	if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) != htons(DNS_FLAG_SRESPONSE))
+		return 0;
+
+	// Is error condition occurs? (check error field in incoming packet)
+	if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) != DNS_RCODE_NERROR) {
+		dns_error = 1;
+		return 0;
+	}
+
+	/*        Pass all (qdcount) records in question section         */
+
+	for (i = 0; i < htons(dnsh -> qdcount); i++) {
+		// pass QNAME
+		resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+		                                handle_domain_name);
+		if (resp_section == NULL) {
+			return -1; // incorrect domain name (bad packet)
+		}
+		// pass QTYPE & QCLASS
+		resp_section += 4;
+	}
+
+	/*       Handle all (ancount) records in answer section          */
+
+	for (i = 0; i < htons(dnsh -> ancount); i++) {
+		// retrieve domain name from the packet
+		resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+		                                handle_domain_name);
+
+		if (resp_section == NULL) {
+			return -1; // incorrect domain name (bad packet)
+		}
+
+		// Check the class of the query (should be IN for Internet)
+		if (* (uint16_t *) (resp_section + 2) == htons(DNS_QCLASS_IN)) {
+			// check if retrieved name fit raw or canonical domain name
+			if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) ||
+				!strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) {
+				switch (htons(* (uint16_t *) resp_section)) {
+
+				case DNS_QTYPE_A :
+					// rdata contains IP
+					dns_result_ip = htonl(* (uint32_t *) (resp_section + 10));
+					return 0; // IP successfully obtained
+
+				case DNS_QTYPE_CNAME :
+					// rdata contains canonical name, store it for further requests
+					if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10,
+					                     dns_domain_cname) == NULL) {
+						// incorrect domain name (bad packet)
+						return -1;
+					}
+					break;
+				}
+			}
+			// continue with next record in answer section
+			resp_section += htons(* (uint16_t *) (resp_section + 8)) + 10;
+		}
+	}
+	return 0; // Packet succesfuly handled but IP wasn't obtained
+}
+
+/**
+ * DNS: Sends a standard DNS-query (read request package) to a DNS-server.
+ *      DNS-server respones with host IP or signals some error condition.
+ *      Responses from the server are handled by handle_dns function.
+ *
+ * @param  domain_name the domain name given as series of labels preceded
+ *                     with length(label) and terminated with 0  
+ *                     <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see                handle_dns
+ */
+static void
+dns_send_query(int8_t * domain_name) {
+	int qry_len = strlen((char *) domain_name) + 5;
+
+	uint32_t packetsize = sizeof(struct iphdr) +
+	                      sizeof(struct udphdr) + sizeof(struct dnshdr) +
+	                      qry_len;
+
+	memset(ether_packet, 0, packetsize);
+	fill_dnshdr(&ether_packet[
+	            sizeof(struct iphdr) + sizeof(struct udphdr)],
+	            domain_name);
+	fill_udphdr(&ether_packet[
+	            sizeof(struct iphdr)], sizeof(struct dnshdr) +
+	            sizeof(struct udphdr) + qry_len,
+	            UDPPORT_DNSC, UDPPORT_DNSS);
+	fill_iphdr(ether_packet,
+	           sizeof(struct dnshdr) + sizeof(struct udphdr) +
+	           sizeof(struct iphdr) + qry_len,
+	           IPTYPE_UDP, 0, dns_server_ip);
+
+	send_ipv4(ether_packet, packetsize);
+}
+
+/**
+ * DNS: Creates standard DNS-query package. Places DNS-header
+ *      and question section in a packet and fills it with
+ *      corresponding information.
+ *      <p>
+ *      Use this function with similar functions for other network layers
+ *      (fill_udphdr, fill_iphdr, fill_ethhdr).
+ *
+ * @param  packet      Points to the place where ARP-header must be placed.
+ * @param  domain_name the domain name given as series of labels preceded
+ *                     with length(label) and terminated with 0  
+ *                     <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see                fill_udphdr
+ * @see                fill_iphdr
+ * @see                fill_ethhdr
+ */
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name) {
+	struct dnshdr * dnsh = (struct dnshdr *) packet;
+	uint8_t * qry_section = packet + sizeof(struct dnshdr);
+
+	dnsh -> id = htons(0x1234);
+	dnsh -> flags = htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD);
+	dnsh -> qdcount = htons(1);
+
+	strcpy((char *) qry_section, (char *) domain_name);
+	qry_section += strlen((char *) domain_name) + 1;
+
+	// fill QTYPE (ask for IP)
+	* (uint16_t *) qry_section = htons(DNS_QTYPE_A);
+	qry_section += 2;
+	// fill QCLASS (IN is a standard class for Internet)
+	* (uint16_t *) qry_section = htons(DNS_QCLASS_IN);
+}
+
+/**
+ * DNS: Extracts domain name from the question or answer section of
+ *      the DNS-message. This function is need to support message  
+ *      compression requirement (see RFC 1035, paragraph 4.1.4).
+ *
+ * @param  dnsh        Points at the DNS-header.
+ * @param  head        Points at the beginning of the domain_name
+ *                     which has to be extracted.
+ * @param  domain_name In case of SUCCESS this string stores extracted name.
+ *                     In case of FAULT this string is empty.
+ * @return             NULL in case of FAULT (domain name > 255 octets); 
+ *                     otherwise pointer to the data following the name.
+ * @see                dnshdr
+ */
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name) {
+	int8_t * tail = domain_name;
+	int8_t * ptr = head;
+	int8_t * next_section = NULL;
+
+	while (1) {
+		if ((ptr[0] & 0xC0) == 0xC0) {
+			// message compressed (reference is used)
+			next_section = ptr + 2;
+			ptr = (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF);
+			continue;
+		}
+		if (ptr[0] == 0) {
+			// message termination
+			tail[0] = 0;
+			ptr += 1;
+			break;
+		}
+		// maximum length for domain name is 255 octets w/o termination sym
+		if (tail - domain_name + ptr[0] + 1 > 255) {
+			strcpy((char *) domain_name, "");
+			return NULL;
+		}
+		memcpy(tail, ptr, ptr[0] + 1);
+		tail += ptr[0] + 1;
+		ptr += ptr[0] + 1;
+	}
+
+	if (next_section == NULL)
+		next_section = ptr;
+
+	return (uint8_t *) next_section;
+}
+
+/**
+ * DNS: Parses URL and returns host name.
+ *      Input string can be given as: <ul>
+ *      <li> scheme with full path with (without) user and password
+ *           <br>(e.g. "http://user:pass@www.host.org/url-path");
+ *      <li> host name with url-path
+ *           <br>(e.g. "www.host.org/url-path");
+ *      <li> nothing but host name
+ *           <br>(e.g. "www.host.org");
+ *      </ul>
+ *
+ * @param  url        string that stores incoming URL
+ * @param  host_name  In case of SUCCESS this string stores the host name,
+ *                    In case of FAULT this string is empty.
+ * @return            TRUE - host name retrieved,
+ *                    FALSE - host name > 255 octets or empty.
+ */
+static int8_t
+urltohost(char * url, char * host_name) {
+	uint16_t length1;
+	uint16_t length2;
+
+	strcpy(host_name, "");
+
+	if (strstr(url, "://") != NULL)
+		url = strstr(url, "//") + 2;  // URL
+
+	if (strstr(url, "@") != NULL) // truncate user & password
+		url = strstr(url, "@") + 1;
+
+	if (strstr(url, "/") != NULL) // truncate url path
+		length1 = strstr(url, "/") - url;
+	else
+		length1 = strlen(url);
+
+	if (strstr(url, ":") != NULL) // truncate port path
+		length2 = strstr(url, ":") - url;
+	else
+		length2 = strlen(url);
+
+	if(length1 > length2)
+		length1 = length2;
+
+	if (length1 == 0)
+		return 0; // string is empty
+	if(length1 >= 256)
+		return 0; // host name is too big
+
+	strncpy(host_name, url, length1);
+	host_name[length1] = 0;
+
+	return 1; // Host name is retrieved
+}
+
+/**
+ * DNS: Transforms host name string into a series of labels
+ *      each of them preceded with length(label). 0 is a terminator.
+ *      "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0"
+ *      <p>
+ *      This format is used in DNS-messages.
+ *
+ * @param  host_name   incoming string with the host name
+ * @param  domain_name resulting string with series of labels
+ *                     or empty string in case of FAULT
+ * @return             TRUE - host name transformed,
+ *                     FALSE - host name > 255 octets or label > 63 octets.
+ */
+static int8_t
+hosttodomain(char * host_name, char * domain_name) {
+	char * domain_iter = domain_name;
+	char * host_iter   = host_name;
+
+	strcpy(domain_name, "");
+
+	if(strlen(host_name) > 255)
+		return 0; // invalid host name (refer to RFC 1035)
+
+	for(; 1; ++host_iter) {
+		if(*host_iter != '.' && *host_iter != 0)
+			continue;
+		*domain_iter = host_iter - host_name;
+		if (*domain_iter > 63) {
+			strcpy(domain_name, "");
+			return 0; // invalid host name (refer to RFC 1035)
+		}
+		++domain_iter;
+		strncpy(domain_iter, host_name, host_iter - host_name);
+		domain_iter += (host_iter - host_name);
+		if(*host_iter == 0) {
+			*domain_iter = 0;
+			break;
+		}
+		host_name = host_iter + 1;
+	}
+	return 1; // ok
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.h
new file mode 100644
index 0000000..ef9f48e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/dns.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _DNS_H_
+#define _DNS_H_
+
+#include <types.h>
+
+/* Initialize the environment for DNS client. */
+extern int8_t dns_init(uint32_t dns_server_ip);
+
+/* For given URL retrieves IPv4 from DNS-server. */
+extern int8_t dns_get_ip(int8_t * domain_name, uint32_t * domain_ip);
+
+/* Handles DNS-packets, which are detected by receive_ether. */
+extern int32_t handle_dns(uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
new file mode 100644
index 0000000..cc77457
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/** \file netbase.c <pre>
+ * *********************** Receive-handle diagram *************************
+ *
+ * Note: Every layer calls out required upper layer
+ *
+ * lower
+ *  | MAC/LLC     Receive packet (receive_ether)
+ *  |                           |
+ *  | NETWORK       +-----------+---------+
+ *  |               |                     |
+ *  |           IPv4 (handle_ipv4)    IPv6 (handle_ipv4)
+ *  |           ARP  (handle_arp)     ICMP & NDP
+ *  |           ICMP                      |
+ *  |                 |                   |
+ *  |                 +---------+---------+
+ *  |                           |
+ *  | TRANSPORT       +---------+---------+
+ *  |                 |                   |
+ *  |              TCP (handle_tcp)    UDP (handle_udp)
+ *  |                                     |
+ *  | APPLICATION        +----------------+-----------+
+ *  V                    |                            |
+ * upper               DNS (handle_dns)      BootP / DHCP (handle_bootp_client)
+ * 
+ * ************************************************************************
+ * </pre> */
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <ethernet.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <ipv4.h>
+//#include <ipv6.h>
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0};
+static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E};
+static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * Ethernet: Set the own MAC address to initializes ethernet layer.
+ *
+ * @param  own_mac  own hardware-address (MAC)
+ */
+void
+set_mac_address(const uint8_t * _own_mac) {
+	if (_own_mac)
+		memcpy(own_mac, _own_mac, 6);
+	else
+		memset(own_mac, 0, 6);
+}
+
+/**
+ * Ethernet: Set the own MAC address to initializes ethernet layer.
+ *
+ * @return  own hardware-address (MAC)
+ */
+const uint8_t *
+get_mac_address(void) {
+	return own_mac;
+}
+
+/**
+ * Ethernet: Check if given multicast address is a multicast MAC address
+ *           starting with 0x3333 
+ *
+ * @return  true or false 
+ */
+static uint8_t
+is_multicast_mac(uint8_t * mac) {
+
+    	uint16_t mc = 0x3333;
+    	if (memcmp(mac, &mc, 2) == 0)
+	       return 1;
+
+	return 0;
+}
+
+
+/**
+ * Ethernet: Receives an ethernet-packet and handles it according to
+ *      Receive-handle diagram.
+ *
+ * @return  ZERO - packet was handled or no packets received;
+ *          NON ZERO - error condition occurs.
+ */
+int32_t
+receive_ether(void) {
+	int32_t bytes_received;
+	struct ethhdr * ethh;
+
+	memset(ether_packet, 0, ETH_MTU_SIZE);
+	bytes_received = recv(0, ether_packet, ETH_MTU_SIZE, 0);
+
+	if (!bytes_received) // No messages
+		return 0;
+
+	if (bytes_received < sizeof(struct ethhdr))
+		return -1; // packet is too small
+
+	ethh = (struct ethhdr *) ether_packet;
+
+	if(memcmp(ethh->dest_mac, broadcast_mac, 6) != 0
+	&& memcmp(ethh->dest_mac, multicast_mac, 3) != 0
+	&& memcmp(ethh->dest_mac, own_mac, 6      ) != 0
+	&& !is_multicast_mac(ethh->dest_mac))
+		return -1; // packet is too small
+
+	switch (htons(ethh -> type)) {
+	case ETHERTYPE_IP:
+		return handle_ipv4((uint8_t*) (ethh + 1),
+		                   bytes_received - sizeof(struct ethhdr));
+/*
+	case ETHERTYPE_IPv6:
+		return handle_ipv6(ether_packet + sizeof(struct ethhdr),
+				bytes_received - sizeof(struct ethhdr));
+*/
+	case ETHERTYPE_ARP:
+		return handle_arp((uint8_t*) (ethh + 1),
+		           bytes_received - sizeof(struct ethhdr));
+	default:
+		break;
+	}
+	return -1; // unknown protocol
+}
+
+/**
+ * Ethernet: Sends an ethernet frame via the initialized file descriptor.
+ *
+ * @return number of transmitted bytes
+ */
+int
+send_ether(void* buffer, int len)
+{
+	return send(0, buffer, len, 0);
+}
+
+/**
+ * Ethernet: Creates Ethernet-packet. Places Ethernet-header in a packet and
+ *           fills it with corresponding information.
+ *           <p>
+ *           Use this function with similar functions for other network layers
+ *           (fill_arphdr, fill_iphdr, fill_udphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param  packet      Points to the place where eth-header must be placed.
+ * @param  eth_type    Type of the next level protocol (e.g. IP or ARP).
+ * @param  src_mac     Sender MAC address
+ * @param  dest_mac    Receiver MAC address
+ * @see                ethhdr
+ * @see                fill_arphdr
+ * @see                fill_iphdr
+ * @see                fill_udphdr
+ * @see                fill_dnshdr
+ * @see                fill_btphdr
+ */
+void
+fill_ethhdr(uint8_t * packet, uint16_t eth_type,
+            const uint8_t * src_mac, const uint8_t * dest_mac) {
+	struct ethhdr * ethh = (struct ethhdr *) packet;
+
+	ethh -> type = htons(eth_type);
+	memcpy(ethh -> src_mac, src_mac, 6);
+	memcpy(ethh -> dest_mac, dest_mac, 6);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.h
new file mode 100644
index 0000000..e305a66
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ethernet.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _ETHERNET_H
+#define _ETHERNET_H
+
+#include <types.h>
+
+#define ETH_MTU_SIZE     1518   /**< Maximum Transfer Unit         */
+#define ETH_ALEN            6   /**< HW address length             */
+#define ETHERTYPE_IP   0x0800
+#define ETHERTYPE_IPv6 0x86DD
+#define ETHERTYPE_ARP  0x0806
+
+/** \struct ethhdr
+ *  A header for Ethernet-packets.
+ */
+struct ethhdr {
+	uint8_t dest_mac[ETH_ALEN];   /**< Destination HW address        */
+	uint8_t src_mac[ETH_ALEN];    /**< Source HW address             */
+	uint16_t type;                /**< Next level protocol type      */
+};
+
+/* Initializes ethernet layer */
+extern void set_mac_address(const uint8_t * own_mac);
+extern const uint8_t * get_mac_address(void);
+
+/* Receives and handles packets, according to Receive-handle diagram */
+extern int32_t receive_ether(void);
+
+/* Sends an ethernet frame. */
+extern int send_ether(void* buffer, int len);
+
+/* fills ethernet header */
+extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type,
+                        const uint8_t * src_mac, const uint8_t * dest_mac);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
new file mode 100644
index 0000000..df18970
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
@@ -0,0 +1,871 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <ipv4.h>
+#include <udp.h>
+#include <tcp.h>
+#include <ethernet.h>
+#include <sys/socket.h>
+#include <string.h>
+
+/* ARP Message types */
+#define ARP_REQUEST            1
+#define ARP_REPLY              2
+
+/* ARP talbe size (+1) */
+#define ARP_ENTRIES 10
+
+/* ICMP Message types */
+#define ICMP_ECHO_REPLY            0
+#define ICMP_DST_UNREACHABLE       3
+#define ICMP_SRC_QUENCH            4
+#define ICMP_REDIRECT              5
+#define ICMP_ECHO_REQUEST          8
+#define ICMP_TIME_EXCEEDED        11
+#define ICMP_PARAMETER_PROBLEM    12
+#define ICMP_TIMESTAMP_REQUEST    13
+#define ICMP_TIMESTAMP_REPLY      14
+#define ICMP_INFORMATION_REQUEST  15
+#define ICMP_INFORMATION_REPLY    16
+
+/** \struct arp_entry
+ *  A entry that describes a mapping between IPv4- and MAC-address.
+ */
+typedef struct arp_entry arp_entry_t;
+struct arp_entry {
+	uint32_t ipv4_addr;
+	uint8_t  mac_addr[6];
+	uint8_t  eth_frame[ETH_MTU_SIZE];
+	int      eth_len;
+};
+
+/** \struct icmphdr
+ *  ICMP packet
+ */
+struct icmphdr {
+	unsigned char type;
+	unsigned char code;
+	unsigned short int checksum;
+	union {
+		/* for type 3 "Destination Unreachable" */
+		unsigned int unused;
+		/* for type 0 and 8 */
+		struct echo {
+			unsigned short int id;
+			unsigned short int seq;
+		} echo;
+	} options;
+	union {
+		/* payload for destination unreachable */
+		struct dun {
+			unsigned char iphdr[20];
+			unsigned char data[64];
+		} dun;
+		/* payload for echo or echo reply */
+		/* maximum size supported is 84 */
+		unsigned char data[84];
+	} payload;
+};
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static unsigned short
+checksum(unsigned short *packet, int words);
+
+static void
+arp_send_request(uint32_t dest_ip);
+
+static void
+arp_send_reply(uint32_t src_ip, uint8_t * src_mac);
+
+static void
+fill_arphdr(uint8_t * packet, uint8_t opcode,
+            const uint8_t * src_mac, uint32_t src_ip,
+            const uint8_t * dest_mac, uint32_t dest_ip);
+
+static arp_entry_t*
+lookup_mac_addr(uint32_t ipv4_addr);
+
+static void
+fill_udp_checksum(struct iphdr *ipv4_hdr);
+
+static int8_t
+handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/* Routing parameters */
+static uint32_t own_ip       = 0;
+static uint32_t multicast_ip = 0;
+static uint32_t router_ip    = 0;
+static uint32_t subnet_mask  = 0;
+
+/* helper variables */
+static uint32_t ping_dst_ip;
+static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static       uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+/* There are only (ARP_ENTRIES-1) effective entries because
+ * the entry that is pointed by arp_producer is never used.
+ */
+static unsigned int arp_consumer = 0;
+static unsigned int arp_producer = 0;
+static arp_entry_t  arp_table[ARP_ENTRIES];
+
+/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
+int   (*send_ip) (void *, int);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * IPv4: Initialize the environment for the IPv4 layer.
+ */
+static void
+ipv4_init(void)
+{
+	int i;
+
+	ping_dst_ip = 0;
+
+	// clear ARP table
+	arp_consumer = 0;
+	arp_producer = 0;
+	for(i=0; i<ARP_ENTRIES; ++i) {
+		arp_table[i].ipv4_addr = 0;
+		memset(arp_table[i].mac_addr, 0, 6);
+		arp_table[i].eth_len = 0;
+	}
+
+	/* Set IP send function to send_ipv4() */ 
+	send_ip = &send_ipv4;
+}
+
+/**
+ * IPv4: Set the own IPv4 address.
+ *
+ * @param  _own_ip  client IPv4 address (e.g. 127.0.0.1)
+ */
+void
+set_ipv4_address(uint32_t _own_ip)
+{
+	own_ip = _own_ip;
+	ipv4_init();
+}
+
+/**
+ * IPv4: Get the own IPv4 address.
+ *
+ * @return client IPv4 address (e.g. 127.0.0.1)
+ */
+uint32_t
+get_ipv4_address(void)
+{
+	return own_ip;
+}
+
+/**
+ * IPv4: Set the IPv4 multicast address.
+ *
+ * @param  _own_ip  multicast IPv4 address (224.0.0.0 - 239.255.255.255)
+ */
+void
+set_ipv4_multicast(uint32_t _multicast_ip)
+{
+	// is this IP Multicast out of range (224.0.0.0 - 239.255.255.255)
+	if((htonl(_multicast_ip) < 0xE0000000)
+	|| (htonl(_multicast_ip) > 0xEFFFFFFF)) {
+		multicast_ip = 0;
+		memset(multicast_mac, 0xFF, 6);
+		return;
+	}
+
+	multicast_ip = _multicast_ip;
+	multicast_mac[0] = 0x01;
+	multicast_mac[1] = 0x00;
+	multicast_mac[2] = 0x5E;
+	multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16);
+	multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >>  8);
+	multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >>  0);
+}
+
+/**
+ * IPv4: Get the IPv4 multicast address.
+ *
+ * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
+ */
+uint32_t
+get_ipv4_multicast(void)
+{
+	return multicast_ip;
+}
+
+/**
+ * IPv4: Set the routers IPv4 address.
+ *
+ * @param  _router_ip   router IPv4 address
+ */
+void
+set_ipv4_router(uint32_t _router_ip)
+{
+	router_ip = _router_ip;
+	ipv4_init();
+}
+
+/**
+ * IPv4: Get the routers IPv4 address.
+ *
+ * @return router IPv4 address
+ */
+uint32_t
+get_ipv4_router(void)
+{
+	return router_ip;
+}
+
+/**
+ * IPv4: Set the subnet mask.
+ *
+ * @param  _subnet_mask   netmask of the own IPv4 address
+ */
+void
+set_ipv4_netmask(uint32_t _subnet_mask)
+{
+	subnet_mask = _subnet_mask;
+	ipv4_init();
+}
+
+/**
+ * IPv4: Get the subnet mask.
+ *
+ * @return netmask of the own IPv4 address
+ */
+uint32_t
+get_ipv4_netmask(void)
+{
+	return subnet_mask;
+}
+
+/**
+ * IPv4: Creates IP-packet. Places IP-header in a packet and fills it
+ *       with corresponding information.
+ *       <p>
+ *       Use this function with similar functions for other network layers
+ *       (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param  packet      Points to the place where IP-header must be placed.
+ * @param  packetsize  Size of the packet in bytes incl. this hdr and data.
+ * @param  ip_proto    Type of the next level protocol (e.g. UDP).
+ * @param  ip_src      Sender IP address
+ * @param  ip_dst      Receiver IP address
+ * @see                iphdr
+ * @see                fill_ethhdr
+ * @see                fill_udphdr
+ * @see                fill_dnshdr
+ * @see                fill_btphdr
+ */
+void
+fill_iphdr(uint8_t * packet, uint16_t packetsize,
+           uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) {
+	struct iphdr * iph = (struct iphdr *) packet;
+
+	iph -> ip_hlv = 0x45;
+	iph -> ip_tos = 0x10;
+	iph -> ip_len = htons(packetsize);
+	iph -> ip_id = htons(0);
+	iph -> ip_off = 0;
+	iph -> ip_ttl = 0xFF;
+	iph -> ip_p = ip_proto;
+	iph -> ip_src = htonl(ip_src);
+	iph -> ip_dst = htonl(ip_dst);
+	iph -> ip_sum = 0;
+}
+
+/**
+ * IPv4: Handles IPv4-packets according to Receive-handle diagram.
+ *
+ * @param  ip_packet  IP-packet to be handled
+ * @param  packetsize Length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ * @see               receive_ether
+ * @see               iphdr
+ */
+int8_t
+handle_ipv4(uint8_t * ip_packet, int32_t packetsize)
+{
+	struct iphdr * iph;
+	int32_t old_sum;
+	static uint8_t ip_heap[65536 + ETH_MTU_SIZE];
+
+	if (packetsize < sizeof(struct iphdr))
+		return -1; // packet is too small
+
+	iph = (struct iphdr * ) ip_packet;
+
+	/* Drop it if destination IPv4 address is no IPv4 Broadcast, no
+	 * registered IPv4 Multicast and not our Unicast address
+	 */
+	if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF)
+	|| (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF &&
+	    own_ip != 0 && iph->ip_dst != own_ip)) {
+		return -1;
+	}
+
+	old_sum = iph -> ip_sum;
+	iph -> ip_sum = 0;
+	if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1))
+		return -1; // Wrong IP checksum
+
+	// is it the first fragment in a packet?
+	if (((iph -> ip_off) & 0x1FFF) == 0) {
+		// is it part of more fragments?
+		if (((iph -> ip_off) & 0x2000) == 0x2000) {
+			memcpy(ip_heap, ip_packet, iph->ip_len);
+			return 0;
+		}
+	}
+	// it's not the first fragment
+	else {
+		// get the first fragment
+		struct iphdr * iph_first = (struct iphdr * ) ip_heap;
+
+		// is this fragment not part of the first one, then exit
+		if ((iph_first->ip_id  != iph->ip_id ) ||
+		    (iph_first->ip_p   != iph->ip_p  ) ||
+		    (iph_first->ip_src != iph->ip_src) ||
+		    (iph_first->ip_dst != iph->ip_dst)) {
+			return 0;
+		}
+
+		// this fragment is part of the first one!
+		memcpy(ip_heap + sizeof(struct iphdr) +
+		       ((iph -> ip_off) & 0x1FFF) * 8,
+		       ip_packet + sizeof(struct iphdr),
+		       iph -> ip_len - sizeof(struct iphdr));
+
+		// is it part of more fragments? Then return.
+		if (((iph -> ip_off) & 0x2000) == 0x2000) {
+			return 0;
+		}
+
+		// packet is completly reassambled now!
+
+		// recalculate ip_len and set iph and ip_packet to the
+		iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8;
+
+		// set iph and ip_packet to the resulting packet.
+		ip_packet = ip_heap;
+		iph = (struct iphdr * ) ip_packet;
+	}
+
+	switch (iph -> ip_p) {
+	case IPTYPE_ICMP:
+		return handle_icmp(iph, ip_packet + sizeof(struct iphdr),
+		                   iph -> ip_len - sizeof(struct iphdr));
+	case IPTYPE_UDP:
+		return handle_udp(ip_packet + sizeof(struct iphdr),
+		                  iph -> ip_len - sizeof(struct iphdr));
+	case IPTYPE_TCP:
+		return handle_tcp(ip_packet + sizeof(struct iphdr),
+		                  iph -> ip_len - sizeof(struct iphdr));
+	default:
+		break;
+	}
+	return -1; // Unknown protocol
+}
+
+/**
+ * IPv4: Send IPv4-packets.
+ *
+ *       Before the packet is sent there are some patcches performed:
+ *       - IPv4 source address is replaced by our unicast IPV4 address
+ *         if it is set to 0 or 1
+ *       - IPv4 destination address is replaced by our multicast IPV4 address
+ *         if it is set to 1
+ *       - IPv4 checksum is calculaded.
+ *       - If payload type is UDP, then the UDP checksum is calculated also.
+ *
+ *       We sent an ARP request first, if this is the first packet sent to
+ *       the declared IPv4 destination address. In this case we store the
+ *       the packet and sent it later if we receive the ARP response.
+ *       If the MAC address is known already, then we send the packet immediatly.
+ *       If there is already an ARP request pending, then we drop this packet
+ *       and send again an ARP request.
+ *
+ * @param  ip_packet  IP-packet to be handled
+ * @param  packetsize Length of the packet
+ * @return            -2 - packet dropped (MAC address not resolved - ARP request pending)
+ *                    -1 - packet dropped (bad format)
+ *                     0 - packet stored  (ARP request sent - packet will be sent if
+ *                                         ARP response is received)
+ *                    >0 - packet send    (number of transmitted bytes is returned)
+ *
+ * @see               receive_ether
+ * @see               iphdr
+ */
+int
+send_ipv4(void* buffer, int len)
+{
+	arp_entry_t *arp_entry;
+	struct iphdr *ip;
+	const uint8_t *mac_addr = 0;
+
+	if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE)
+		return -1;
+
+	ip = (struct iphdr  *) buffer;
+
+	/* Replace source IPv4 address with our own unicast IPv4 address
+	 * if it's 0 (= own unicast source address not specified).
+	 */
+	if(ip->ip_src == 0) {
+		ip->ip_src = htonl( own_ip );
+	}
+	/* Replace source IPv4 address with our unicast IPv4 address and
+	 * replace destination IPv4 address with our multicast IPv4 address
+	 * if source address is set to 1.
+	 */
+	else if(ip->ip_src == 1) {
+		ip->ip_src = htonl( own_ip );
+		ip->ip_dst = htonl( multicast_ip );
+	}
+
+	// Calculate the IPv4 checksum
+	ip->ip_sum = 0;
+	ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1);
+
+	// if payload type is UDP, then we need to calculate the
+	// UDP checksum that depends on the IP header
+	if(ip->ip_p == IPTYPE_UDP) {
+		fill_udp_checksum(ip);
+	}
+
+	// Check if the MAC address is already cached
+	if(~ip->ip_dst == 0
+	|| ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask &&
+	     (  subnet_mask  & ip->ip_dst) == (subnet_mask & own_ip)))  {
+		arp_entry = &arp_table[arp_producer];
+		mac_addr = broadcast_mac;
+	}
+	else if(ip->ip_dst == multicast_ip) {
+		arp_entry = &arp_table[arp_producer];
+		mac_addr = multicast_mac;
+	}
+	else {
+		// Check if IP address is in the same subnet as we are
+		if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst))
+			arp_entry = lookup_mac_addr(ip->ip_dst);
+		// if not then we need to know the router's IP address
+		else
+			arp_entry = lookup_mac_addr(router_ip);
+		if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0)
+			mac_addr = arp_entry->mac_addr;
+	}
+
+	// If we could not resolv the MAC address by our own...
+	if(!mac_addr) {
+		// send the ARP request
+		arp_send_request(ip->ip_dst);
+
+		// drop the current packet if there is already a ARP request pending
+		if(arp_entry)
+			return -2;
+
+		// take the next entry in the ARP table to prepare a the new ARP entry.
+		arp_entry = &arp_table[arp_producer];
+		arp_producer = (arp_producer+1)%ARP_ENTRIES;
+
+		// if ARP table is full then we must drop the oldes entry.
+		if(arp_consumer == arp_producer)
+			arp_consumer = (arp_consumer+1)%ARP_ENTRIES;
+
+		// store the packet to be send if the ARP reply is received
+		arp_entry->ipv4_addr = ip->ip_dst;
+		memset(arp_entry->mac_addr, 0, 6);
+		fill_ethhdr (arp_entry->eth_frame, htons(ETHERTYPE_IP),
+		             get_mac_address(), null_mac_addr);
+		memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)],
+		       buffer, len);
+		arp_entry->eth_len = len + sizeof(struct ethhdr);
+
+		return 0;
+	}
+
+	// Send the packet with the known MAC address
+	fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP),
+	            get_mac_address(), mac_addr);
+	memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len);
+	return send_ether(arp_entry->eth_frame, len + sizeof(struct ethhdr));
+}
+
+/**
+ * IPv4: Calculate UDP checksum. Places the result into the UDP-header.
+ *      <p>
+ *      Use this function after filling the UDP payload.
+ *
+ * @param  ipv4_hdr    Points to the place where IPv4-header starts.
+ */
+
+static void
+fill_udp_checksum(struct iphdr *ipv4_hdr)
+{
+	int i;
+	unsigned long checksum = 0;
+	struct iphdr ip_hdr;
+	char *ptr;
+	udp_hdr_t *udp_hdr;
+
+	udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1);
+	udp_hdr->uh_sum = 0;
+
+	memset(&ip_hdr, 0, sizeof(struct iphdr));
+	ip_hdr.ip_src    = ipv4_hdr->ip_src;
+	ip_hdr.ip_dst    = ipv4_hdr->ip_dst;
+	ip_hdr.ip_len    = udp_hdr->uh_ulen;
+	ip_hdr.ip_p      = ipv4_hdr->ip_p;
+
+	ptr = (char*) udp_hdr;
+	for (i = 0; i < udp_hdr->uh_ulen; i+=2)
+		checksum += *((uint16_t*) &ptr[i]);
+
+	ptr = (char*) &ip_hdr;
+	for (i = 0; i < sizeof(struct iphdr); i+=2)
+		checksum += *((uint16_t*) &ptr[i]);
+
+	checksum = (checksum >> 16) + (checksum & 0xffff);
+	checksum += (checksum >> 16);
+	udp_hdr->uh_sum = ~checksum;
+}
+
+/**
+ * IPv4: Calculates checksum for IP header.
+ *
+ * @param  packet     Points to the IP-header
+ * @param  words      Size of the packet in words incl. IP-header and data.
+ * @return            Checksum
+ * @see               iphdr
+ */
+static unsigned short
+checksum(unsigned short * packet, int words)
+{
+	unsigned long checksum;
+
+	for (checksum = 0; words > 0; words--)
+		checksum += *packet++;
+	checksum = (checksum >> 16) + (checksum & 0xffff);
+	checksum += (checksum >> 16);
+
+	return ~checksum;
+}
+
+static arp_entry_t*
+lookup_mac_addr(uint32_t ipv4_addr)
+{
+	unsigned int i;
+
+	for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
+		if(arp_table[i].ipv4_addr == ipv4_addr)
+			return &arp_table[i];
+	}
+	return 0;
+}
+
+
+/**
+ * ARP: Sends an ARP-request package.
+ *      For given IPv4 retrieves MAC via ARP (makes several attempts)
+ *
+ * @param  dest_ip   IP of the host which MAC should be obtained
+ */
+static void
+arp_send_request(uint32_t dest_ip)
+{
+	arp_entry_t *arp_entry = &arp_table[arp_producer];
+
+	memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+	fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST,
+	            get_mac_address(), own_ip, broadcast_mac, dest_ip);
+	fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
+	            get_mac_address(), broadcast_mac);
+
+	send_ether(arp_entry->eth_frame,
+	     sizeof(struct ethhdr) + sizeof(struct arphdr));
+}
+
+/**
+ * ARP: Sends an ARP-reply package.
+ *      This package is used to serve foreign requests (in case IP in
+ *      foreign request matches our host IP).
+ *
+ * @param  src_ip    requester IP address (foreign IP)
+ * @param  src_mac   requester MAC address (foreign MAC)
+ */
+static void
+arp_send_reply(uint32_t src_ip, uint8_t * src_mac)
+{
+	arp_entry_t *arp_entry = &arp_table[arp_producer];
+
+	memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+	fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
+	            get_mac_address(), src_mac);
+	fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY,
+	            get_mac_address(), own_ip, src_mac, src_ip);
+
+	send_ether(arp_entry->eth_frame,
+	     sizeof(struct ethhdr) + sizeof(struct arphdr));
+}
+
+/**
+ * ARP: Creates ARP package. Places ARP-header in a packet and fills it
+ *      with corresponding information.
+ *      <p>
+ *      Use this function with similar functions for other network layers
+ *      (fill_ethhdr).
+ *
+ * @param  packet      Points to the place where ARP-header must be placed.
+ * @param  opcode      Identifies is it request (ARP_REQUEST)
+ *                     or reply (ARP_REPLY) package.
+ * @param  src_mac     sender MAC address
+ * @param  src_ip      sender IP address
+ * @param  dest_mac    receiver MAC address
+ * @param  dest_ip     receiver IP address
+ * @see                arphdr
+ * @see                fill_ethhdr
+ */
+static void
+fill_arphdr(uint8_t * packet, uint8_t opcode,
+	    const uint8_t * src_mac, uint32_t src_ip,
+	    const uint8_t * dest_mac, uint32_t dest_ip)
+{
+	struct arphdr * arph = (struct arphdr *) packet;
+
+	arph -> hw_type = htons(1);
+	arph -> proto_type = htons(ETHERTYPE_IP);
+	arph -> hw_len = 6;
+	arph -> proto_len = 4;
+	arph -> opcode = htons(opcode);
+
+	memcpy(arph->src_mac, src_mac, 6);
+	arph->src_ip = htonl(src_ip);
+	memcpy(arph->dest_mac, dest_mac, 6);
+	arph->dest_ip = htonl(dest_ip);
+}
+
+/**
+ * ARP: Handles ARP-messages according to Receive-handle diagram.
+ *      Updates arp_table for outstanding ARP requests (see arp_getmac).
+ *
+ * @param  packet     ARP-packet to be handled
+ * @param  packetsize length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ * @see               arp_getmac
+ * @see               receive_ether
+ * @see               arphdr
+ */
+int8_t
+handle_arp(uint8_t * packet, int32_t packetsize)
+{
+	struct arphdr * arph = (struct arphdr *) packet;
+
+	if (packetsize < sizeof(struct arphdr))
+		return -1; // Packet is too small
+
+	if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP))
+		return -1; // Unknown hardware or unsupported protocol
+
+	if (arph -> dest_ip != htonl(own_ip))
+		return -1; // receiver IP doesn't match our IP
+
+	switch(htons(arph -> opcode)) {
+	case ARP_REQUEST:
+		// foreign request
+		if(own_ip != 0)
+			arp_send_reply(htonl(arph->src_ip), arph -> src_mac);
+		return 0; // no error
+	case ARP_REPLY: {
+		unsigned int i;
+		// if it is not for us -> return immediately
+		if(memcmp(get_mac_address(), arph->dest_mac, 6)) {
+			return 0; // no error
+		}
+
+		if(arph->src_ip == 0) {
+			// we are not interested for a MAC address if
+			// the IPv4 address is 0.0.0.0 or ff.ff.ff.ff
+			return -1;
+		}
+
+		// now let's find the corresponding entry in the ARP table
+
+		for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
+			if(arp_table[i].ipv4_addr == arph->src_ip)
+				break;
+		}
+		if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) {
+			// we have not asked to resolve this IPv4 address !
+			return -1;
+		}
+
+		memcpy(arp_table[i].mac_addr, arph->src_mac, 6);
+
+		// do we have something to send
+		if(arp_table[i].eth_len > 0) {
+			struct ethhdr * ethh = (struct ethhdr *) arp_table[i].eth_frame;
+			memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6);
+
+			send_ether(arp_table[i].eth_frame, arp_table[i].eth_len);
+			arp_table[i].eth_len = 0;
+		}
+		return 0; // no error
+	}
+	default:
+		break;
+	}
+	return -1; // Invalid message type
+}
+
+/**
+ * ICMP: Send an ICMP Echo request to destination IPv4 address.
+ *       This function does also set a global variable to the
+ *       destination IPv4 address. If there is an ICMP Echo Reply
+ *       received later then the variable is set back to 0.
+ *       In other words, reading a value of 0 form this variable
+ *       means that an answer to the request has been arrived.
+ *
+ * @param  _ping_dst_ip  destination IPv4 address
+ */
+void
+ping_ipv4(uint32_t _ping_dst_ip)
+{
+	unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
+	struct icmphdr *icmp;
+
+	ping_dst_ip = _ping_dst_ip;
+
+	if(ping_dst_ip == 0)
+		return;
+
+	fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
+	           0, ping_dst_ip);
+	icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
+	icmp->type = ICMP_ECHO_REQUEST;
+	icmp->code = 0;
+	icmp->checksum = 0;
+	icmp->options.echo.id = 0xd476;
+	icmp->options.echo.seq = 1;
+
+	memset(icmp->payload.data, '*', sizeof(icmp->payload.data));
+
+	icmp->checksum =
+	    checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
+	send_ipv4(packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
+}
+
+/**
+ * ICMP: Return host IPv4 address that we are waiting for a
+ *       ICMP Echo reply message. If this value is 0 then we have
+ *       received an reply.
+ *
+ * @return  ping_dst_ip  host IPv4 address
+ */
+uint32_t
+pong_ipv4(void)
+{
+	return ping_dst_ip;
+}
+
+/**
+ * ICMP: Handles ICMP-packets according to Receive-handle diagram.
+ *
+ * @param  icmp_packet  ICMP-packet to be handled
+ * @param  packetsize   Length of the packet
+ * @return              ZERO - packet handled successfully;
+ *                      NON ZERO - packet was not handled (e.g. bad format)
+ * @see                 handle_ipv4
+ */
+static int8_t
+handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize)
+{
+	struct icmphdr *icmp = (struct icmphdr *) packet;
+
+	switch(icmp->type) {
+	case ICMP_ECHO_REPLY:
+		if (icmp->options.echo.id != 0xd476)
+			return -1;
+		if (icmp->options.echo.seq != 1)
+			return -1;
+		if(ping_dst_ip != iph->ip_src
+		|| ping_dst_ip == 0)
+			return -1;
+		ping_dst_ip = 0;
+		break;
+	case ICMP_DST_UNREACHABLE: {
+		// We've got Destination Unreachable msg
+		// Inform corresponding upper network layers
+		struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload;
+
+		switch(bad_iph->ip_p) {
+		case IPTYPE_TCP:
+			handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize
+			               - sizeof(struct icmphdr)
+			               - sizeof(struct iphdr), icmp->code);
+			break;
+		case IPTYPE_UDP:
+			handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize
+			               - sizeof(struct icmphdr)
+			               - sizeof(struct iphdr), icmp->code);
+			break;
+		}
+		break;
+	}
+	case ICMP_SRC_QUENCH:
+		break;
+	case ICMP_REDIRECT:
+		break;
+	case ICMP_ECHO_REQUEST: {
+		// We've got an Echo Request - answer with Echo Replay msg
+		unsigned char reply_packet[sizeof(struct iphdr) + packetsize];
+		struct icmphdr *reply_icmph;
+
+		fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize,
+		           IPTYPE_ICMP, 0, iph->ip_src);
+
+		reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)];
+		memcpy(reply_icmph, packet, packetsize);
+		reply_icmph -> type = ICMP_ECHO_REPLY;
+		reply_icmph -> checksum = 0;
+		reply_icmph->checksum = checksum((unsigned short *) reply_icmph,
+		                                 sizeof(struct icmphdr) >> 1);
+
+		send_ipv4(reply_packet, sizeof(struct iphdr) + packetsize);
+		break;
+	}
+	case ICMP_TIME_EXCEEDED:
+		break;
+	case ICMP_PARAMETER_PROBLEM:
+		break;
+	case ICMP_TIMESTAMP_REQUEST:
+		break;
+	case ICMP_TIMESTAMP_REPLY:
+		break;
+	case ICMP_INFORMATION_REQUEST:
+		break;
+	case ICMP_INFORMATION_REPLY:
+		break;
+	}
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
new file mode 100644
index 0000000..0e5a408
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _IPV4_H_
+#define _IPV4_H_
+
+#include <types.h>
+
+#define IPTYPE_ICMP         1
+
+/** \struct iphdr
+ *  A header for IP-packets.
+ *  For more information see RFC 791.
+ */
+struct iphdr {
+	uint8_t ip_hlv;      /**< Header length and version of the header      */
+	uint8_t ip_tos;      /**< Type of Service                              */
+	uint16_t ip_len;     /**< Length in octets, inlc. this header and data */
+	uint16_t ip_id;      /**< ID is used to aid in assembling framents     */
+	uint16_t ip_off;     /**< Info about fragmentation (control, offset)   */
+	uint8_t ip_ttl;      /**< Time to Live                                 */
+	uint8_t ip_p;        /**< Next level protocol type                     */
+	uint16_t ip_sum;     /**< Header checksum                              */
+	uint32_t ip_src;     /**< Source IP address                            */
+	uint32_t ip_dst;     /**< Destination IP address                       */
+};
+typedef struct iphdr ipv4_hdr_t;
+
+/* ICMP Error Codes */
+#define ICMP_NET_UNREACHABLE 0
+#define ICMP_HOST_UNREACHABLE 1
+#define ICMP_PROTOCOL_UNREACHABLE 2
+#define ICMP_PORT_UNREACHABLE 3
+#define ICMP_FRAGMENTATION_NEEDED 4
+#define ICMP_SOURCE_ROUTE_FAILED 5
+
+/** \struct arphdr
+ *  A header for ARP-messages, retains info about HW and proto addresses.
+ *  For more information see RFC 826.
+ */
+struct arphdr {
+	uint16_t hw_type;    /**< HW address space (1 for Ethernet)            */
+	uint16_t proto_type; /**< Protocol address space                       */
+	uint8_t hw_len;      /**< Byte length of each HW address               */
+	uint8_t proto_len;   /**< Byte length of each proto address            */
+	uint16_t opcode;     /**< Identifies is it request (1) or reply (2)    */
+	uint8_t src_mac[6];  /**< HW address of sender of this packet          */
+	uint32_t src_ip;     /**< Proto address of sender of this packet       */
+	uint8_t dest_mac[6]; /**< HW address of target of this packet          */
+	uint32_t dest_ip;    /**< Proto address of target of this packet       */
+} __attribute((packed));
+
+/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/
+extern void     set_ipv4_address(uint32_t own_ip);
+extern uint32_t get_ipv4_address(void);
+extern void     set_ipv4_multicast(uint32_t multicast_ip);
+extern uint32_t get_ipv4_multicast(void);
+extern void     set_ipv4_router(uint32_t router_ip);
+extern uint32_t get_ipv4_router(void);
+extern void     set_ipv4_netmask(uint32_t subnet_mask);
+extern uint32_t get_ipv4_netmask(void);
+
+extern int   (*send_ip) (void *, int);
+
+/* fills ip header */
+extern void fill_iphdr(uint8_t * packet, uint16_t packetsize,
+                       uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst);
+
+/* Send a IPv4 packet. Adding the Ethernet-Header and resolving the
+ * MAC address is done transparent in the background if necessary.
+ */
+extern int send_ipv4(void* buffer, int len);
+
+/* Sends an ICMP Echo request to destination IPv4 address */
+extern void ping_ipv4(uint32_t _ping_dst_ip);
+
+/* Returns host IPv4 address that we are waiting for a response */
+extern uint32_t pong_ipv4(void);
+
+/* Handles IPv4-packets that are detected by receive_ether. */
+extern int8_t handle_ipv4(uint8_t * packet, int32_t packetsize);
+
+/* Handles ARP-packets that are detected by receive_ether. */
+extern int8_t handle_arp(uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.c
new file mode 100644
index 0000000..5511aa0
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.c
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <tcp.h>
+#include <sys/socket.h>
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+/**
+ * TCP: Handles TCP-packets according to Receive-handle diagram.
+ *
+ * @param  tcp_packet TCP-packet to be handled
+ * @param  packetsize Length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ */
+int8_t
+handle_tcp(uint8_t * tcp_packet, int32_t packetsize)
+{
+	return -1;
+}
+
+
+/**
+ * NET: This function handles situation when "Destination unreachable"
+ *      ICMP-error occurs during sending TCP-packet.
+ *
+ * @param  err_code   Error Code (e.g. "Host unreachable")
+ * @param  packet     original TCP-packet
+ * @param  packetsize length of the packet
+ * @see               handle_icmp
+ */
+void
+handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) {
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.h
new file mode 100644
index 0000000..7d0c906
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tcp.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _TCP_H
+#define _TCP_H
+
+#include <types.h>
+
+#define IPTYPE_TCP          6
+
+/* Handles TCP-packets that are detected by any network layer. */
+extern int8_t handle_tcp(uint8_t * udp_packet, int32_t packetsize);
+
+/* Handles TCP related ICMP-Dest.Unreachable packets that are detected by
+ * the network layers. */
+extern void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.c
new file mode 100644
index 0000000..e8e9d09
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.c
@@ -0,0 +1,597 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <tftp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+//#include <ipv6.h>
+#include <udp.h>
+
+//#define __DEBUG__
+
+#define MAX_BLOCKSIZE 1428
+#define BUFFER_LEN 2048
+#define ACK_BUFFER_LEN 256
+#define READ_BUFFER_LEN 256
+
+#define ENOTFOUND 1
+#define EACCESS   2
+#define EBADOP    4
+#define EBADID    5
+#define ENOUSER   7
+//#define EUNDEF 0
+//#define ENOSPACE 3
+//#define EEXISTS 6
+
+#define RRQ   1
+#define WRQ   2
+#define DATA  3
+#define ACK   4
+#define ERROR 5
+#define OACK  6
+
+/* Local variables */
+static unsigned char  *buffer = NULL;
+static unsigned short block = 0;
+static unsigned short blocksize;
+static char blocksize_str[6];    /* Blocksize string for read request */
+static int received_len = 0;
+static int retries = 0;
+static int huge_load;
+static int len;
+static int tftp_finished = 0;
+static int lost_packets = 0;
+static int tftp_errno = 0; 
+static int ip_version = 0; 
+static short port_number = -1;
+static tftp_err_t *tftp_err;
+static filename_ip_t  *fn_ip;
+
+/**
+ * dump_package - Prints a package.
+ *
+ * @package: package which is to print
+ * @len:     length of the package
+ */
+#ifdef __DEBUG__
+
+static void
+dump_package(unsigned char *buffer, unsigned int len)
+{
+	int i;
+
+	for (i = 1; i <= len; i++) {
+		printf("%02x%02x ", buffer[i - 1], buffer[i]);
+		i++;
+		if ((i % 16) == 0)
+			printf("\n");
+	}
+	printf("\n");
+}
+#endif
+
+/**
+ * send_rrq - Sends a read request package.
+ */
+static void
+send_rrq(void)
+{
+	int ip_len = 0;
+	//int ip6_payload_len    = 0;
+	unsigned short udp_len = 0;
+	unsigned char mode[] = "octet";
+	unsigned char packet[READ_BUFFER_LEN];
+	char *ptr	     = NULL;
+	struct iphdr *ip     = NULL;
+	//struct ip6hdr *ip6   = NULL;
+	struct udphdr *udph  = NULL;
+	struct tftphdr *tftp = NULL;
+
+	memset(packet, 0, READ_BUFFER_LEN);
+
+	if (4 == ip_version) {
+		ip = (struct iphdr *) packet;
+		udph = (struct udphdr *) (ip + 1);
+		ip_len = sizeof(struct iphdr) + sizeof(struct udphdr)
+			+ strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+			+ strlen("blksize") + strlen(blocksize_str) + 2;
+		fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+			    fn_ip->server_ip);
+	}
+/*
+	else if (6 == ip_version) {
+		ip6 = (struct ip6hdr *) packet;
+		udph = (struct udphdr *) (ip6 + 1);
+		ip6_payload_len = sizeof(struct udphdr)
+			+ strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+			+ strlen("blksize") + strlen(blocksize_str) + 2;
+		ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
+		fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+			     &(fn_ip->server_ip6)); 
+
+	}
+*/
+	udp_len = htons(sizeof(struct udphdr)
+			      + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+			      + strlen("blksize") + strlen(blocksize_str) + 2);
+	fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69));
+
+	tftp = (struct tftphdr *) (udph + 1);
+	tftp->th_opcode = htons(RRQ);
+
+	ptr = (char *) &tftp->th_data;
+	memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
+
+	ptr += strlen((char *) fn_ip->filename) + 1;
+	memcpy(ptr, mode, strlen((char *) mode) + 1);
+
+	ptr += strlen((char *) mode) + 1;
+	memcpy(ptr, "blksize", strlen("blksize") + 1);
+
+	ptr += strlen("blksize") + 1;
+	memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
+
+	send_ip (packet, ip_len);
+
+#ifdef __DEBUG__
+	printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
+#endif
+	return;
+}
+
+/**
+ * send_ack - Sends a acknowlege package.
+ *
+ * @blckno: block number
+ * @dport:  UDP destination port
+ */
+static void
+send_ack(int blckno, unsigned short dport)
+{
+	int ip_len 	       = 0;
+	//int ip6_payload_len    = 0;
+	unsigned short udp_len = 0;
+	unsigned char packet[ACK_BUFFER_LEN];
+	struct iphdr *ip     = NULL;
+	//struct ip6hdr *ip6   = NULL;
+	struct udphdr *udph  = NULL;
+	struct tftphdr *tftp = NULL;
+
+	memset(packet, 0, ACK_BUFFER_LEN);
+
+	if (4 == ip_version) {
+		ip = (struct iphdr *) packet;
+		udph = (struct udphdr *) (ip + 1);
+		ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4;
+		fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+			    fn_ip->server_ip);
+	}
+/*
+	else if (6 == ip_version) {
+		ip6 = (struct ip6hdr *) packet;
+		udph = (struct udphdr *) (ip6 + 1);
+		ip6_payload_len = sizeof(struct udphdr) + 4;
+		ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
+		    	 ip6_payload_len;
+		fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+			     &(fn_ip->server_ip6));
+	}
+*/
+	udp_len = htons(sizeof(struct udphdr) + 4);
+	fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
+
+	tftp = (struct tftphdr *) (udph + 1);
+	tftp->th_opcode = htons(ACK);
+	tftp->th_data = htons(blckno);
+
+	send_ip(packet, ip_len);
+
+#ifdef __DEBUG__
+	printf("tftp ACK %d bytes transmitted.\n", ip_len);
+#endif
+
+	return;
+}
+
+/**
+ * send_error - Sends an error package.
+ *
+ * @error_code:  Used sub code for error packet
+ * @dport:       UDP destination port
+ */
+static void
+send_error(int error_code, unsigned short dport)
+{
+	int ip_len 	       = 0;
+	//int ip6_payload_len    = 0;
+	unsigned short udp_len = 0;
+	unsigned char packet[256];
+	//struct ip6hdr *ip6   = NULL;
+	struct iphdr *ip     = NULL;
+	struct udphdr *udph  = NULL;
+	struct tftphdr *tftp = NULL;
+
+	memset(packet, 0, 256);
+
+	if (4 == ip_version) {
+		ip = (struct iphdr *) packet;
+		udph = (struct udphdr *) (ip + 1);
+		ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5;
+		fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+			    fn_ip->server_ip);
+	}
+/*
+	else if (6 == ip_version) {
+		ip6 = (struct ip6hdr *) packet;
+		udph = (struct udphdr *) (ip6 + 1);
+		ip6_payload_len = sizeof(struct udphdr) + 5;
+		ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
+		         ip6_payload_len; 
+		fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+			    &(fn_ip->server_ip6));
+	}
+*/
+	udp_len = htons(sizeof(struct udphdr) + 5);
+	fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
+
+	tftp = (struct tftphdr *) (udph + 1);
+	tftp->th_opcode = htons(ERROR);
+	tftp->th_data = htons(error_code);
+	((char *) &tftp->th_data)[2] = 0;
+
+	send_ip(packet, ip_len);
+
+#ifdef __DEBUG__
+	printf("tftp ERROR %d bytes transmitted.\n", ip_len);
+#endif
+
+	return;
+}
+
+static void
+print_progress(int urgent, int received_bytes)
+{
+	static unsigned int i = 1;
+	static int first = -1;
+	static int last_bytes = 0;
+	char buffer[100];
+	char *ptr;
+
+	// 1MB steps or 0x400 times or urgent 
+	if(((received_bytes - last_bytes) >> 20) > 0
+	|| (i & 0x3FF) == 0 || urgent) {
+		if(!first) {
+			sprintf(buffer, "%d KBytes", (last_bytes >> 10));
+			for(ptr = buffer; *ptr != 0; ++ptr)
+				*ptr = '\b';
+			printf(buffer);
+		}
+		printf("%d KBytes", (received_bytes >> 10));
+		i = 1;
+		first = 0;
+		last_bytes = received_bytes;
+	}
+	++i;
+}
+
+/**
+ * get_blksize tries to extract the blksize from the OACK package
+ * the TFTP returned. From RFC 1782
+ * The OACK packet has the following format:
+ *
+ *   +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ *   |  opc  |  opt1  | 0 | value1 | 0 |  optN  | 0 | valueN | 0 |
+ *   +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ *
+ * @param buffer  the network packet
+ * @param len  the length of the network packet
+ * @return  the blocksize the server supports or 0 for error
+ */
+static int
+get_blksize(unsigned char *buffer, unsigned int len)
+{
+	unsigned char *orig = buffer;
+	/* skip all headers until tftp has been reached */
+	buffer += sizeof(struct udphdr);
+	/* skip opc */
+	buffer += 2;
+	while (buffer < orig + len) {
+		if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
+			return (unsigned short) strtoul((char *) (buffer +
+							strlen("blksize") + 1),
+							(char **) NULL, 10);
+		else {
+			/* skip the option name */
+			buffer = (unsigned char *) strchr((char *) buffer, 0);
+			if (!buffer)
+				return 0;
+			buffer++;
+			/* skip the option value */
+			buffer = (unsigned char *) strchr((char *) buffer, 0);
+			if (!buffer)
+				return 0;
+			buffer++;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Handle incoming tftp packets after read request was sent 
+ *
+ * this function also prints out some status characters
+ * \|-/ for each packet received
+ * A for an arp packet
+ * I for an ICMP packet
+ * #+* for different unexpected TFTP packets (not very good)
+ *
+ * @param packet points to the UDP header of the packet 
+ * @param len    the length of the network packet
+ * @return       ZERO if packet was handled successfully
+ *               ERRORCODE if error occurred 
+ */
+int32_t
+handle_tftp(uint8_t *packet, int32_t packetsize) 
+{
+	struct udphdr *udph;
+	struct tftphdr *tftp;
+
+	/* buffer is only set if we are handling TFTP */
+	if (buffer == NULL )
+		return 0;
+
+#ifndef __DEBUG__
+	print_progress(0, received_len);
+#endif
+	udph = (struct udphdr *) packet;
+	tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
+	set_timer(TICKS_SEC);
+
+#ifdef __DEBUG__
+	dump_package(packet, packetsize);
+#endif
+
+	port_number = udph->uh_sport;
+	if (tftp->th_opcode == htons(OACK)) {
+		/* an OACK means that the server answers our blocksize request */
+		blocksize = get_blksize(packet, packetsize);
+		if (!blocksize || blocksize > MAX_BLOCKSIZE) {
+			send_error(8, port_number);
+			tftp_errno = -8;
+			goto error;
+		}
+		send_ack(0, port_number);
+	} else if (tftp->th_opcode == htons(ACK)) {
+		/* an ACK means that the server did not answers
+		 * our blocksize request, therefore we will set the blocksize
+		 * to the default value of 512 */
+		blocksize = 512;
+		send_ack(0, port_number);
+	} else if ((unsigned char) tftp->th_opcode == ERROR) {
+#ifdef __DEBUG__
+		printf("tftp->th_opcode : %x\n", tftp->th_opcode);
+		printf("tftp->th_data   : %x\n", tftp->th_data);
+#endif
+		switch ( (uint8_t) tftp->th_data) {
+		case ENOTFOUND:
+			tftp_errno = -3;	// ERROR: file not found
+			break;
+		case EACCESS:
+			tftp_errno = -4;	// ERROR: access violation
+			break;
+		case EBADOP:
+			tftp_errno = -5;	// ERROR: illegal TFTP operation
+			break;
+		case EBADID:
+			tftp_errno = -6;	// ERROR: unknown transfer ID
+			break;
+		case ENOUSER:
+			tftp_errno = -7;	// ERROR: no such user
+			break;
+		default:	
+			tftp_errno = -1;	// ERROR: unknown error
+		}
+		goto error;
+	} else if (tftp->th_opcode == DATA) {
+		/* DATA PACKAGE */
+		if (block + 1 == tftp->th_data) {
+			++block;
+		}
+		else if( block == 0xffff && huge_load != 0
+		     &&  (tftp->th_data == 0 || tftp->th_data == 1) ) {
+			block = tftp->th_data;
+		}
+		else if (tftp->th_data == block) {
+#ifdef __DEBUG__
+			printf
+			    ("\nTFTP: Received block %x, expected block was %x\n",
+			     tftp->th_data, block + 1);
+			printf("\b+ ");
+#endif
+			send_ack(tftp->th_data, port_number);
+			lost_packets++;
+			tftp_err->bad_tftp_packets++;
+			return 0;
+		} else if (tftp->th_data < block) {
+#ifdef __DEBUG__
+			printf
+			    ("\nTFTP: Received block %x, expected block was %x\n",
+			     tftp->th_data, block + 1);
+			printf("\b* ");
+#endif
+			/* This means that an old data packet appears (again);
+			 * this happens sometimes if we don't answer fast enough
+			 * and a timeout is generated on the server side;
+			 * as we already have this packet we just ignore it */
+			tftp_err->bad_tftp_packets++;
+			return 0;
+		} else {
+			tftp_err->blocks_missed = block + 1;
+			tftp_err->blocks_received = tftp->th_data;
+			tftp_errno = -42;
+			goto error;
+		}
+		tftp_err->bad_tftp_packets = 0;
+		/* check if our buffer is large enough */
+		if (received_len + udph->uh_ulen - 12 > len) {
+			tftp_errno = -2;
+			goto error;
+		}
+		memcpy(buffer + received_len, &tftp->th_data + 1,
+		       udph->uh_ulen - 12);
+		send_ack(tftp->th_data, port_number);
+		received_len += udph->uh_ulen - 12;
+		/* Last packet reached if the payload of the UDP packet
+		 * is smaller than blocksize + 12
+		 * 12 = UDP header (8) + 4 bytes TFTP payload */
+		if (udph->uh_ulen < blocksize + 12) {
+			tftp_finished = 1;
+			return 0;
+		}
+		/* 0xffff is the highest block number possible
+		 * see the TFTP RFCs */
+
+		if (block >= 0xffff && huge_load == 0) {
+			tftp_errno = -9;
+			goto error;
+		}
+	} else {
+#ifdef __DEBUG__
+		printf("Unknown packet %x\n", tftp->th_opcode);
+		printf("\b# ");
+#endif
+		tftp_err->bad_tftp_packets++;
+		return 0;
+	}
+
+	return 0;
+
+error:
+#ifdef __DEBUG__
+	printf("\nTFTP errno: %d\n", tftp_errno);
+#endif
+	tftp_finished = 1;
+	return tftp_errno;
+}
+
+/**
+ * TFTP: This function handles situation when "Destination unreachable"
+ *       ICMP-error occurs during sending TFTP-packet.
+ *
+ * @param  err_code   Error Code (e.g. "Host unreachable")
+ */
+void
+handle_tftp_dun(uint8_t err_code)
+{
+	tftp_errno = - err_code - 10;
+	tftp_finished = 1;
+}
+
+/**
+ * TFTP: Interface function to load files via TFTP.
+ *
+ * @param  _fn_ip        contains the following configuration information:
+ *                       client IP, TFTP-server IP, filename to be loaded
+ * @param  _buffer       destination buffer for the file
+ * @param  _len          size of destination buffer
+ * @param  _retries      max number of retries
+ * @param  _tftp_err     contains info about TFTP-errors (e.g. lost packets)
+ * @param  _mode         NON ZERO - multicast, ZERO - unicast
+ * @param  _blocksize    blocksize for DATA-packets
+ * @return               ZERO - error condition occurs
+ *                       NON ZERO - size of received file
+ */
+int
+tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
+     unsigned int _retries, tftp_err_t * _tftp_err,
+     int32_t _mode, int32_t _blocksize, int _ip_version)
+{
+	retries     = _retries;
+	fn_ip       = _fn_ip;
+	len         = _len;
+	huge_load   = _mode;
+	ip_version  = _ip_version;
+	tftp_errno  = 0;
+	tftp_err    = _tftp_err;
+	tftp_err->bad_tftp_packets = 0;
+	tftp_err->no_packets = 0;
+
+	/* Default blocksize must be 512 for TFTP servers
+	 * which do not support the RRQ blocksize option */
+	blocksize = 512;
+
+	/* Prefered blocksize - used as option for the read request */
+	if (_blocksize < 8)
+		_blocksize = 8;
+	else if (_blocksize > MAX_BLOCKSIZE)
+		_blocksize = MAX_BLOCKSIZE;
+	sprintf(blocksize_str, "%d", _blocksize);
+
+	printf("  Receiving data:  ");
+	print_progress(-1, 0);
+
+	// Setting buffer to a non-zero address enabled handling of received TFTP packets.
+	buffer = _buffer;
+
+	set_timer(TICKS_SEC);
+	send_rrq();
+
+	while (! tftp_finished) {
+		/* if timeout (no packet received) */
+		if(get_timer() <= 0) {
+			/* the server doesn't seem to retry let's help out a bit */
+			if (tftp_err->no_packets > 4 && port_number != -1
+				&& block > 1)
+				send_ack(block, port_number);
+			tftp_err->no_packets++;
+			set_timer(TICKS_SEC);
+		}
+
+		/* handle received packets */
+		receive_ether();
+
+		/* bad_tftp_packets are counted whenever we receive a TFTP packet
+			* which was not expected; if this gets larger than 'retries'
+			* we just exit */
+		if (tftp_err->bad_tftp_packets > retries) {
+			tftp_errno = -40;
+			break;
+		}
+
+		/* no_packets counts the times we have returned from receive_ether()
+			* without any packet received; if this gets larger than 'retries'
+			* we also just exit */
+		if (tftp_err->no_packets > retries) {
+			tftp_errno = -41;
+			break;
+		}
+	}
+
+	// Setting buffer to NULL disables handling of received TFTP packets.
+	buffer = NULL;
+
+	if (tftp_errno)
+		return tftp_errno;
+
+	print_progress(-1, received_len);
+	printf("\n");
+	if (lost_packets)
+		printf("Lost ACK packets: %d\n", lost_packets);
+		
+	return received_len;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.h
new file mode 100644
index 0000000..3f573b1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/tftp.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _TFTP_H_
+#define _TFTP_H_
+
+#include <types.h>
+//#include <netlib/ipv6.h>
+
+struct tftphdr {
+	int16_t th_opcode;
+	uint16_t th_data;
+};
+
+typedef struct {
+	uint32_t own_ip;
+	//ip6_addr_t own_ip6;
+	uint32_t server_ip;
+	//ip6_addr_t server_ip6;
+	int8_t filename[256];
+} __attribute__ ((packed)) filename_ip_t ;
+
+typedef struct {
+	uint32_t bad_tftp_packets;
+	uint32_t no_packets;
+	uint32_t blocks_missed;
+	uint32_t blocks_received;
+} tftp_err_t;
+
+int tftp(filename_ip_t *, unsigned char  *, int, unsigned int,
+         tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version);
+int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len,
+		 int use_ci, unsigned int retries, tftp_err_t * tftp_err);
+
+int32_t handle_tftp(uint8_t *, int32_t);
+void handle_tftp_dun(uint8_t err_code);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.c
new file mode 100644
index 0000000..3bc20ef
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.c
@@ -0,0 +1,153 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <udp.h>
+#include <sys/socket.h>
+#include <dhcp.h>
+//#include <dhcpv6.h>
+#include <dns.h>
+#ifdef USE_MTFTP
+#include <mtftp.h>
+#else
+#include <tftp.h>
+#endif
+
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+#ifdef USE_MTFTP
+
+uint16_t net_tftp_uport;
+uint16_t net_mtftp_uport;
+
+void net_set_tftp_port(uint16_t tftp_port) {
+	net_tftp_uport = tftp_port;
+}
+
+void net_set_mtftp_port(uint16_t tftp_port) {
+	net_mtftp_uport = tftp_port;
+}
+
+#endif
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+/**
+ * NET: Handles UDP-packets according to Receive-handle diagram.
+ *
+ * @param  udp_packet UDP-packet to be handled
+ * @param  packetsize Length of the packet
+ * @return            ZERO - packet handled successfully;
+ *                    NON ZERO - packet was not handled (e.g. bad format)
+ * @see               receive_ether
+ * @see               udphdr
+ */
+int8_t
+handle_udp(uint8_t * udp_packet, int32_t packetsize) {
+	struct udphdr * udph = (struct udphdr *) udp_packet;
+
+	if (packetsize < sizeof(struct udphdr))
+		return -1; // packet is too small
+
+	switch (htons(udph -> uh_dport)) {
+	case UDPPORT_BOOTPC:
+		if (udph -> uh_sport == htons(UDPPORT_BOOTPS))
+			return handle_dhcp(udp_packet + sizeof(struct udphdr),
+			                    packetsize - sizeof(struct udphdr));
+		else
+			return -1;
+	case UDPPORT_DNSC:
+		if (udph -> uh_sport == htons(UDPPORT_DNSS))
+			return handle_dns(udp_packet + sizeof(struct udphdr),
+			                  packetsize - sizeof(struct udphdr));
+		else
+			return -1;
+/*
+        case UDPPORT_DHCPV6C:
+                return handle_dhcpv6(udp_packet+sizeof(struct udphdr),
+                                     packetsize - sizeof(struct udphdr));
+*/
+	case UDPPORT_TFTPC:
+#ifdef USE_MTFTP
+	return handle_tftp(udp_packet + sizeof(struct udphdr),
+			               packetsize - sizeof(struct udphdr));
+#else
+	return handle_tftp(udp_packet, packetsize);
+#endif
+	default:
+#ifdef USE_MTFTP
+		if (htons(udph -> uh_dport) == net_tftp_uport)
+		return handle_tftp(udp_packet + sizeof(struct udphdr),
+                       packetsize - sizeof(struct udphdr));
+		else if (htons(udph -> uh_dport) == net_mtftp_uport)
+		return handle_tftp(udp_packet + sizeof(struct udphdr),
+                       packetsize - sizeof(struct udphdr));
+#endif
+		return -1;
+	}
+}
+
+/**
+ * NET: This function handles situation when "Destination unreachable"
+ *      ICMP-error occurs during sending UDP-packet.
+ *
+ * @param  err_code   Error Code (e.g. "Host unreachable")
+ * @param  packet     original UDP-packet
+ * @param  packetsize length of the packet
+ * @see               handle_icmp
+ */
+void
+handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) {
+	struct udphdr * udph = (struct udphdr *) udp_packet;
+
+	if (packetsize < sizeof(struct udphdr))
+		return; // packet is too small
+
+	switch (htons(udph -> uh_sport)) {
+	case UDPPORT_TFTPC:
+		handle_tftp_dun(err_code);
+		break;
+	}
+}
+
+/**
+ * NET: Creates UDP-packet. Places UDP-header in a packet and fills it
+ *      with corresponding information.
+ *      <p>
+ *      Use this function with similar functions for other network layers
+ *      (fill_ethhdr, fill_iphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param  packet      Points to the place where UDP-header must be placed.
+ * @param  packetsize  Size of the packet in bytes incl. this hdr and data.
+ * @param  src_port    UDP source port
+ * @param  dest_port   UDP destination port
+ * @see                udphdr
+ * @see                fill_ethhdr
+ * @see                fill_iphdr
+ * @see                fill_dnshdr
+ * @see                fill_btphdr
+ */
+void
+fill_udphdr(uint8_t * packet, uint16_t packetsize,
+            uint16_t src_port, uint16_t dest_port) {
+	struct udphdr * udph = (struct udphdr *) packet;
+
+	udph -> uh_sport = htons(src_port);
+	udph -> uh_dport = htons(dest_port);
+	udph -> uh_ulen = htons(packetsize);
+	udph -> uh_sum = htons(0);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.h
new file mode 100644
index 0000000..0432f52
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/app/netlib/udp.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _UDP_H
+#define _UDP_H
+
+#include <types.h>
+
+#define IPTYPE_UDP         17
+
+#define UDPPORT_BOOTPS     67   /**< UDP port of BootP/DHCP-server */
+#define UDPPORT_BOOTPC     68   /**< UDP port of BootP/DHCP-client */
+#define UDPPORT_DNSS       53   /**< UDP port of DNS-server        */
+#define UDPPORT_DNSC    32769   /**< UDP port of DNS-client        */
+#define UDPPORT_TFTPC    2001   /**< UDP port of TFTP-client	   */
+#define UDPPORT_DHCPV6C   546   /**< UDP port of DHCPv6-client     */
+
+/** \struct udphdr
+ *  A header for UDP-packets.
+ *  For more information see RFC 768.
+ */
+struct udphdr {
+	uint16_t uh_sport;   /**< Source port                                  */
+	uint16_t uh_dport;   /**< Destinantion port                            */
+	uint16_t uh_ulen;    /**< Length in octets, incl. this header and data */
+	uint16_t uh_sum;     /**< Checksum                                     */
+};
+typedef struct udphdr udp_hdr_t;
+
+typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t);
+typedef void    *(*handle_upper_udp_dun_t)(uint8_t);
+
+/* Handles UDP-packets that are detected by any network layer. */
+extern int8_t handle_udp(uint8_t * udp_packet, int32_t packetsize);
+
+/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by
+ * the network layers. */
+extern void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code);
+
+/* fills udp header */
+extern void fill_udphdr(uint8_t *packet, uint16_t packetsize,
+                        uint16_t src_port, uint16_t dest_port);
+
+#ifdef USE_MTFTP
+extern void net_set_tftp_port(uint16_t tftp_port);
+extern void net_set_mtftp_port(uint16_t tftp_port);
+#endif
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/client.lds b/qemu-0.15.x/roms/SLOF/clients/net-snk/client.lds
new file mode 100644
index 0000000..2ebf9d1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/client.lds
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+	.client 0xF000100:
+	{
+	__client_start = .;
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+          *(.rodata .rodata.* .gnu.linkonce.r.*)
+          KEEP (*(.opd))
+	  . = ALIGN(256); 
+	  *(.data .data.* .gnu.linkonce.d.*)
+	  . = ALIGN(256);
+	} =0x60000000
+
+	.lowmem :
+	{
+	  _lowmem_start = .;
+	  *(.lowmem)
+	  _lowmem_end = .;
+	}
+
+	.got :
+	{
+	  . = ALIGN(8);
+	  _got = .;
+          *(.got .toc)
+	  _got_end = .;
+	}  	
+	.comment : { *(.comment) }
+	.branch_lt : { *(.branch_lt) }
+	.bss :
+	{
+          *(*COM* .bss .gnu.linkonce.b.*)
+	__client_end = .;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/crt0.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/crt0.h
new file mode 100644
index 0000000..d8fce05
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/crt0.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _CRT0_H
+#define _CRT0_H
+
+int gen_argv(const char *, int, char **);
+
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/endian.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/endian.h
new file mode 100644
index 0000000..b4b9a94
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/endian.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef MY_ENDIAN_H
+#define MY_ENDIAN_H
+
+#include <stdint.h>
+
+extern inline uint16_t bswap_16 (uint16_t x);
+extern inline uint32_t bswap_32 (uint32_t x);
+extern inline uint64_t  bswap_64 (uint64_t x);
+#define CPU_BIG_ENDIAN
+
+#ifndef CPU_BIG_ENDIAN
+#define cpu_to_le64(x)  (x)
+#define cpu_to_le32(x)  (x)
+#define cpu_to_le16(x)  (x)
+#define cpu_to_be16(x)  bswap_16(x)
+#define cpu_to_be32(x)  bswap_32(x)
+#define le64_to_cpu(x)  (x)
+#define le32_to_cpu(x)  (x)
+#define le16_to_cpu(x)  (x)
+#define be32_to_cpu(x)  bswap_32(x)
+#else
+#define cpu_to_le64(x)  bswap_64(x)
+#define cpu_to_le32(x)  bswap_32(x)
+#define cpu_to_le16(x)  bswap_16(x)
+#define cpu_to_be16(x)  (x)
+#define cpu_to_be32(x)  (x)
+#define le64_to_cpu(x)  bswap_64(x)
+#define le32_to_cpu(x)  bswap_32(x)
+#define le16_to_cpu(x)  bswap_16(x)
+#define be32_to_cpu(x)  (x)
+#endif
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fcntl.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fcntl.h
new file mode 100644
index 0000000..69de2ce
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fcntl.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#define O_RDONLY    00
+#define O_WRONLY    01
+#define O_RDRW      02
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#endif /* fcntl.h */
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fileio.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fileio.h
new file mode 100644
index 0000000..7c9a2b5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/fileio.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef FILEIO_H
+#define FILEIO_H
+#include <sys/socket.h>
+
+struct snk_fileio_type;
+typedef struct snk_fileio_type snk_fileio_t;
+
+#define FILEIO_TYPE_EMPTY 0
+#define FILEIO_TYPE_USED  1
+
+typedef long (*fileio_read_t)
+	(snk_fileio_t *fileio, char *buf, long len);
+typedef long (*fileio_write_t)
+	(snk_fileio_t *fileio, char *buf, long len);
+typedef int  (*fileio_ioctl_t)
+	(snk_fileio_t *fileio, int request, void *data);
+typedef int  (*fileio_bind_t)
+	(snk_fileio_t *fileio, const struct sockaddr *, long len);
+typedef int  (*fileio_connect_t)
+	(snk_fileio_t *fileio, const struct sockaddr *, long len);
+typedef int  (*fileio_close_t)
+	(snk_fileio_t *fileio);
+
+struct snk_fileio_type {
+	int type;
+	int idx;
+
+	fileio_read_t    read;
+	fileio_write_t   write;
+	fileio_ioctl_t   ioctl;
+	fileio_bind_t    bind;
+	fileio_connect_t connect;
+	fileio_close_t   close;
+
+	void *data;
+};
+
+#define FILEIO_MAX 32
+extern snk_fileio_t fd_array[FILEIO_MAX];
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/ioctl.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/ioctl.h
new file mode 100644
index 0000000..c993798
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/ioctl.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _IOCTL_H
+#define _IOCTL_H
+
+extern int ioctl(int fd, int request, void *data);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/kernel.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/kernel.h
new file mode 100644
index 0000000..a7aff19
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/kernel.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef KERNEL_H
+#define KERNEL_H
+#include <stddef.h>
+
+int printk(const char *, ...);
+void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
+void udelay(unsigned int);
+void mdelay(unsigned int);
+int getchar(void);
+
+int strcmp(const char *, const char *);
+char *strcpy(char *, const char *);
+int printf(const char *, ...);
+void *malloc_aligned(size_t size, int align);
+
+void exception_forward(void);
+void undo_exception(void);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/macros.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/macros.h
new file mode 100644
index 0000000..e8ad919
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/macros.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#define LOAD64(rn,name)			\
+	lis     rn,name##@highest;	\
+	ori     rn,rn,name##@higher;	\
+	rldicr  rn,rn,32,31;		\
+	oris    rn,rn,name##@h;		\
+	ori     rn,rn,name##@l
+
+#define LOAD32(rn, name)		\
+	lis	rn,name##@h;		\
+	ori	rn,rn,name##@l
+
+// load 32 bit constant in little endian order		
+#define LOAD32le(rn,name) \
+        lis     rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00));  \
+        ori     rn,rn,(((name>>24)&0x00FF)|((name>>8)&0xFF00))
+
+// load 16 bit constant in little endian order
+#define LOAD16le(rn,name) \
+        li      rn,(((name>>8)&0x00FF)|(name<<8))
+
+#define SET_CI(rn)	\
+	sync;		\
+	mfspr rn,LPCR;	\
+	ori rn,rn,2;	\
+	mtspr LPCR,rn;	\
+	sync
+	
+#define CLR_CI(rn)	\
+	sync;		\
+	mfspr rn,LPCR;	\
+	ori rn,rn,2;	\
+	xori rn,rn,2;	\
+	mtspr LPCR,rn;	\
+	sync
+
+#define SAVE_AND_SET_CI(rn,rx)	\
+	sync;		\
+	mfspr rx,LPCR;	\
+	ori rn,rx,2;	\
+	mtspr LPCR,rn;	\
+	sync
+
+#define RESTORE_CI(rx)	\
+	sync;		\
+	mtspr LPCR,rx;	\
+	sync
+
+#define ENTRY(func_name)              \
+	.text;                        \
+	.align  2;                    \
+	.globl  .func_name;           \
+        .func_name:                   \
+	.globl  func_name;            \
+        func_name:
+
+#define ASM_ENTRY(fn)	\
+	.globl	fn;	\
+fn:
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/netdriver_int.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/netdriver_int.h
new file mode 100644
index 0000000..2f286ad
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/netdriver_int.h
@@ -0,0 +1,192 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _NETDRIVER_INT_H
+#define _NETDRIVER_INT_H
+#include <stddef.h>
+#include <unistd.h> /* ssize_t */
+#include <fileio.h>
+
+#if defined(__GNUC__) && !defined(UNUSED)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+typedef struct {
+	unsigned int addr;
+	unsigned int size;
+	int type;
+} bar_t;
+
+
+typedef struct {
+	unsigned long long puid;
+	unsigned int bus;
+	unsigned int devfn;
+	unsigned int vendor_id;
+	unsigned int device_id;
+	unsigned int revision_id;
+	unsigned int class_code;
+	bar_t bars[6];
+	unsigned int interrupt_line;
+} pci_config_t;
+
+typedef struct {
+	unsigned int reg;
+	char	     compat[64];
+} vio_config_t;
+
+#define MOD_TYPE_NETWORK 0
+#define MOD_TYPE_OTHER   1
+
+typedef int (*mod_init_t)  (void);
+typedef int (*mod_term_t)  (void);
+typedef int (*mod_socket_t)(snk_fileio_t *, int dom, int type, int proto);
+typedef int (*mod_open_t)  (snk_fileio_t *, const char *, int);
+typedef int (*mod_read_t)  (char *, int);
+typedef int (*mod_write_t) (char *, int);
+typedef int (*mod_ioctl_t) (int, void *);
+
+typedef struct {
+	int version;
+	int type;
+	int running;
+	void *link_addr;
+	mod_init_t   init;
+	mod_term_t   term;
+	mod_socket_t socket;
+	mod_open_t   open;
+	mod_read_t   read;
+	mod_write_t  write;
+	mod_ioctl_t  ioctl;
+
+	char mac_addr[6];
+} snk_module_t;
+
+#define MODULES_MAX 10
+extern snk_module_t *snk_modules[MODULES_MAX];
+
+typedef int (*print_t) (const char *, ...);
+typedef void (*us_delay_t) (unsigned int);
+typedef void (*ms_delay_t) (unsigned int);
+typedef int (*pci_config_read_t) (long long puid, int size,
+				  int bus, int devfn, int offset);
+typedef int (*pci_config_write_t) (long long puid, int size,
+				   int bus, int devfn, int offset, int value);
+typedef void *(*malloc_aligned_t) (size_t, int);
+typedef void *(*malloc_t) (size_t);
+typedef void (*free_t)    (void *);
+typedef int (*strcmp_t)   (const char *, const char *);
+typedef int (*snk_call_t) (int, char **);
+typedef unsigned int (*io_read_t) (void *, size_t);
+typedef int (*io_write_t) (void *, unsigned int, size_t);
+typedef unsigned int (*romfs_lookup_t) (const char *name, void **addr);
+typedef void (*translate_addr_t) (unsigned long *);
+
+typedef int (*k_open_t) (const char *, int);
+typedef int (*k_close_t) (int);
+typedef ssize_t (*k_read_t) (int, void *, size_t);
+typedef ssize_t (*k_write_t) (int, const void *, size_t);
+typedef int (*k_ioctl_t) (int, int, void *);
+
+typedef void (*modules_remove_t) (int);
+typedef snk_module_t *(*modules_load_t) (int);
+
+typedef struct {
+	int version;
+	print_t print;
+	us_delay_t us_delay;
+	ms_delay_t ms_delay;
+	pci_config_read_t pci_config_read;
+	pci_config_write_t pci_config_write;
+	malloc_t k_malloc;
+	malloc_aligned_t k_malloc_aligned;
+	free_t k_free;
+	strcmp_t strcmp;
+	snk_call_t snk_call;
+	io_read_t io_read;
+	io_write_t io_write;
+	romfs_lookup_t k_romfs_lookup;
+	translate_addr_t translate_addr;
+	union {
+		pci_config_t pci_conf;
+		vio_config_t vio_conf;
+	};
+	k_open_t k_open;
+	k_close_t k_close;
+	k_read_t k_read;
+	k_write_t k_write;
+	k_ioctl_t k_ioctl;
+	modules_remove_t modules_remove;
+	modules_load_t modules_load;
+} snk_kernel_t;
+
+/* Entry of module */
+snk_module_t *module_init(snk_kernel_t * snk_kernel_int,
+                          pci_config_t * pciconf);
+
+
+/*
+ * Constants for different kinds of IOCTL requests
+ */
+
+#define SIOCETHTOOL  0x1000
+
+/*
+ * special structure and constants for IOCTL requests of type ETHTOOL
+ */
+
+#define ETHTOOL_GMAC         0x03
+#define ETHTOOL_SMAC         0x04
+#define ETHTOOL_VERSION      0x05
+
+typedef struct {
+	int idx;
+	char address[6];
+} ioctl_ethtool_mac_t;
+
+typedef struct {
+	unsigned int length;
+	char *text;
+} ioctl_ethtool_version_t;
+
+
+/*
+ * default structure and constants for IOCTL requests
+ */
+
+#define IF_NAME_SIZE 0xFF
+
+typedef struct {
+	char if_name[IF_NAME_SIZE];
+	int subcmd;
+	union {
+		ioctl_ethtool_mac_t mac;
+		ioctl_ethtool_version_t version;
+	} data;
+} ioctl_net_data_t;
+
+/* paflof */
+enum {
+	PAFLOF_GDEPTH,
+	PAFLOF_GIO_BEHAVIOR,
+	PAFLOF_GSTATUS,
+	PAFLOF_POP,
+	PAFLOF_PUSH,
+};
+/*  - clint */
+enum {
+	CLINT_EXECUTE
+};
+
+#endif				/* _NETDRIVER_INT_H */
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/of.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/of.h
new file mode 100644
index 0000000..aced2d5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/of.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef OF_H
+#define OF_H
+#define p32 int
+#define p32cast (int) (unsigned long) (void*)
+
+#define phandle_t p32
+#define ihandle_t p32
+
+typedef struct 
+{
+    unsigned int serv;
+    int nargs;
+    int nrets;
+    unsigned int args[16];
+} of_arg_t;
+
+
+phandle_t of_finddevice (const char *);
+phandle_t of_peer (phandle_t);
+phandle_t of_child (phandle_t);
+phandle_t of_parent (phandle_t);
+int of_getprop (phandle_t, const char *, void *, int);
+void * of_call_method_3 (const char *, ihandle_t, int);
+
+
+ihandle_t of_open (const char *);
+void of_close(ihandle_t);
+int of_read (ihandle_t , void*, int);
+int of_write (ihandle_t, void*, int);
+int of_seek (ihandle_t, int, int);
+
+void * of_claim(void *, unsigned int , unsigned int );
+void of_release(void *, unsigned int );
+
+int of_yield(void);
+void * of_set_callback(void *);
+
+unsigned int romfs_lookup(const char *, void **);
+int vpd_read(unsigned int , unsigned int , char *);
+int vpd_write(unsigned int , unsigned int , char *);
+int write_mm_log(char *, unsigned int , unsigned short );
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/pci.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/pci.h
new file mode 100644
index 0000000..285a6d0
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/pci.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _PCI_H
+#define _PCI_H
+#include <netdriver_int.h>
+#include <of.h>
+
+int pci_calc_bar_size (long long puid, int bus, int devfn, int bar);
+int pci_get_bar_start (long long puid, int bus, int devfn, int bar);
+void pci_set_bar_start (long long puid, int bus, int devfn, int bar, int value);
+int pci_bus_scan_puid(long long puid, int class_to_check,
+		      pci_config_t *pci_devices, int max_devs);
+long long get_next_phb (phandle_t *phb);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/rtas.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/rtas.h
new file mode 100644
index 0000000..ff579f4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/rtas.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef RTAS_H
+#define RTAS_H
+
+#include "of.h"
+
+typedef struct dtime {
+        unsigned int year;
+        unsigned int month;
+        unsigned int day;
+        unsigned int hour;
+        unsigned int minute;
+        unsigned int second;
+        unsigned int nano;
+} dtime;
+
+typedef void (*thread_t) (int);
+
+int rtas_token(const char *);
+int rtas_call(int, int, int, int *, ...);
+void rtas_init();
+int rtas_pci_config_read (long long, int, int, int, int);
+int rtas_pci_config_write (long long, int, int, int, int, int);
+int rtas_set_time_of_day(dtime *);
+int rtas_get_time_of_day(dtime *);
+int rtas_ibm_update_flash_64(long long, long long);
+int rtas_ibm_update_flash_64_and_reboot(long long, long long);
+int rtas_system_reboot();
+int rtas_start_cpu (int, thread_t, int);
+int rtas_stop_self (void);
+int rtas_ibm_manage_flash(int);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/sys/socket.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/sys/socket.h
new file mode 100644
index 0000000..83238be
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/sys/socket.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _SOCKET_H
+#define _SOCKET_H
+#include <stdint.h>
+
+#include "systemcall.h"
+
+#define AF_PACKET 0
+#define AF_INET   1
+#define AF_INET6  2
+
+#define SOCK_RAW    0
+#define SOCK_PACKET 1
+#define SOCK_DGRAM  2
+#define SOCK_STREAM 3
+
+#define INADDR_ANY 0xFFFFFFFF
+
+#define IPPROTO_UDP 1
+
+#define ETH_ALEN 6   /**< HW address length             */
+
+struct sockaddr {
+	uint16_t tra_port;
+
+	uint16_t ipv4_proto;
+	uint32_t ipv4_addr;
+
+	// protocol field is only used by "connect"-handler
+	uint16_t llc_proto;
+	uint8_t  mac_addr[ETH_ALEN];
+};
+
+int socket(int, int, int, char *);
+int sendto(int, const void *, int, int, const void *, int);
+int send(int, void *, int, int);
+int recv(int, void *, int, int);
+
+#define htonl(x) x
+#define htons(x) x
+
+#endif
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/systemcall.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/systemcall.h
new file mode 100644
index 0000000..70aa92d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/systemcall.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef SYSTEMCALL_H
+#define SYSTEMCALL_H
+
+extern inline int
+syscall (int nr)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3");
+    asm volatile ("sc" : "=r" (r3) 
+                       : "r" (r0));
+    return r3;
+} 
+
+extern inline long
+syscall_1 (int nr, long arg0)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    asm volatile ("sc" : "=r" (r3) 
+                       : "0" (r3), "r" (r0));
+    return r3;
+} 
+
+extern inline long
+syscall_2 (int nr, long arg0, long arg1)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r0)); 
+    return r3;
+} 
+
+extern inline long
+syscall_3 (int nr, long arg0, long arg1, long arg2)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    register unsigned long r5 asm("r5") = arg2;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r5), "r" (r0)); 
+    return r3;
+} 
+
+extern inline long
+syscall_4 (int nr, long arg0, long arg1, long arg2, long arg3)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    register unsigned long r5 asm("r5") = arg2;
+    register unsigned long r6 asm("r6") = arg3;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r5), "r" (r6), "r" (r0)); 
+    return r3;
+} 
+
+extern inline long
+syscall_5 (int nr, long arg0, long arg1, long arg2, long arg3, 
+	   long arg4)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    register unsigned long r5 asm("r5") = arg2;
+    register unsigned long r6 asm("r6") = arg3;
+    register unsigned long r7 asm("r7") = arg4;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r5), 
+		         "r" (r6), "r" (r7), "r" (r0)); 
+    return r3;
+} 
+
+extern inline long
+syscall_6 (int nr, long arg0, long arg1, long arg2, long arg3, 
+	   long arg4, long arg5)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    register unsigned long r5 asm("r5") = arg2;
+    register unsigned long r6 asm("r6") = arg3;
+    register unsigned long r7 asm("r7") = arg4;
+    register unsigned long r8 asm("r8") = arg5;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r5), 
+		         "r" (r6), "r" (r7), "r" (r8), "r" (r0)); 
+    return r3;
+} 
+
+extern inline long
+syscall_7 (int nr, long arg0, long arg1, long arg2, long arg3, 
+	   long arg4, long arg5, long arg6)
+{
+    register unsigned long r0 asm("r0") = nr;
+    register unsigned long r3 asm("r3") = arg0;
+    register unsigned long r4 asm("r4") = arg1;
+    register unsigned long r5 asm("r5") = arg2;
+    register unsigned long r6 asm("r6") = arg3;
+    register unsigned long r7 asm("r7") = arg4;
+    register unsigned long r8 asm("r8") = arg5;
+    register unsigned long r9 asm("r9") = arg6;
+    asm volatile ("sc" : "=r" (r3) 
+		       : "0" (r3), "r" (r4), "r" (r5), 
+		         "r" (r6), "r" (r7), "r" (r8), 
+		         "r" (r9), "r" (r0)); 
+    return r3;
+} 
+
+
+#define _exit_sc_nr 1
+#define _read_sc_nr 2
+#define _write_sc_nr 3
+#define _open_sc_nr 4
+#define _close_sc_nr 5
+#define _getpid_sc_nr 6
+#define _brk_sc_nr 7
+#define _ioctl_sc_nr 8
+#define _socket_sc_nr 9
+#define _wait4_sc_nr 10
+#define _sigreturn_sc_nr 11
+#define _rt_sigaction_sc_nr 12
+#define _lseek_sc_nr 13
+
+#define _sock_sc_nr 1
+#define _sendto_sc_nr 2
+#define _send_sc_nr 3
+#define _recv_sc_nr 4
+
+
+//typedef unsigned long size_t; 
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/time.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/time.h
new file mode 100644
index 0000000..206f5a4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/time.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _TIME_H_
+#define _TIME_H_
+
+typedef unsigned long clock_t;
+typedef unsigned long time_t;
+
+time_t time(time_t *);
+
+extern unsigned long tb_freq;
+
+/* setup the timer to start counting from the given parameter */
+void set_timer(int);
+/* read the current value from the decrementer */
+int get_timer();
+/* get the number of ticks for which the decrementer needs 1 second */
+int get_sec_ticks();
+/* get the number of ticks for which the decrementer needs 1 millisecond */
+int get_msec_ticks();
+
+#define TICKS_MSEC get_msec_ticks()
+#define TICKS_SEC get_sec_ticks()
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/include/types.h b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/types.h
new file mode 100644
index 0000000..b5e5db3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/include/types.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+#include <stdint.h>
+
+#ifndef u32
+typedef unsigned int u32;
+#endif
+#ifndef u64
+typedef unsigned long long u64;
+#endif
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/Makefile
new file mode 100644
index 0000000..976d851
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/Makefile
@@ -0,0 +1,31 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS =  init.o systemcall.o crt0.o endian.o timer.o modules.o
+OBJS2 = entry.o lowmem.o
+
+all: kernel.o 
+
+kernel.o: $(OBJS) $(OBJS2)
+		$(LD) $(LDFLAGS) $(OBJS) $(OBJS2) -o $@ -r
+
+clean:		
+		$(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/crt0.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/crt0.c
new file mode 100644
index 0000000..353bd95
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/crt0.c
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+extern int main (int, char**);
+extern int callback (int, char **);
+
+#define MAX_ARGV 10
+int
+gen_argv(const char *arg_string, int len, char* argv[])
+{
+  const char *str, *str_end, *arg_string_end = arg_string + len;
+  int i;
+
+  str = arg_string;
+  for (i = 0; i < MAX_ARGV; i++)
+    {
+      str_end = str;
+
+      while((*str_end++ != ' ') && (str_end <= arg_string_end));
+
+      argv[i] = malloc(str_end-str);
+
+      memcpy (argv[i], str, str_end-str-1);
+      argv[i][str_end-str-1] = '\0';
+      str = str_end-1;
+      while(*(++str) == ' ');
+      if (str >= arg_string_end)
+	break;
+    }
+  return i+1;
+}
+
+
+
+int
+_start(char * arg_string, long len)
+{
+    int rc;
+    int argc;
+    char* argv[MAX_ARGV];
+
+    argc = gen_argv(arg_string, len, argv);
+
+    rc = main(argc, argv);
+
+    return rc;
+}
+
+/*
+ * Takes a Forth representation of a string and generates an argument array,
+ * then calls callback().
+ */
+unsigned long
+callback_entry(void *base, unsigned long len) {
+	char *argv[MAX_ARGV];
+	int argc;
+
+	argc = gen_argv(base, len, argv);
+
+	return (callback(argc, argv));
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/endian.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/endian.c
new file mode 100644
index 0000000..04182f5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/endian.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "endian.h"
+
+inline uint16_t bswap_16 (uint16_t x)
+{
+    return ((x&0xff00) >> 8) | ((x&0xff) << 8);
+}
+                                                                                
+inline uint32_t bswap_32 (uint32_t x)
+{
+    return bswap_16((x&0xffff0000) >> 16) | (bswap_16(x&0xffff) << 16);
+}
+                                                                                
+inline uint64_t  bswap_64 (uint64_t x)
+{
+    return (unsigned long long) bswap_32((x&0xffffffff00000000ULL) >> 32) |
+    (unsigned long long) bswap_32(x&0xffffffffULL) << 32;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/entry.S b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/entry.S
new file mode 100644
index 0000000..c0c7a12
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/entry.S
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define STACKSIZE 0x100000
+#include <macros.h>
+
+/*
+Function:	
+	Input:
+		r3:   
+		r4:   
+		r5:   prom entry	 
+	Output:		
+
+Decription: Main entry point, called from OF
+	
+*/
+	.globl	_entry
+        .section        ".opd","aw"
+        .align 3
+_entry:
+        .quad   ._entry,.TOC. at tocbase,0
+        .previous
+        .size   main,24
+	.globl ._entry
+._entry:	
+	mr	r3, r6	# parm 0 passed in r6
+	mr	r4, r7	# parm 1 passed in r7	
+	mr	r6, r1	# save stack pointer	
+	mflr	r7	# save link register
+	bcl	20,31,over	# branch after pointer table
+base:	
+	.align  3
+.LCgot:		.quad   _got-base+0x8000
+.LCstack:	.quad   _stack+STACKSIZE-0x80-base
+over:	
+	mflr	r8		# gpr 8 is the base
+	ld	r1,.LCstack-base(r8)	# load new stack pointer
+	add	r1, r1, r8		# add base
+	std	r2, 64(r1)		# save got
+	std	r7, 56(r1)		# save link register
+#	ld	r2, .LCgot-base(r8)	# load got pointer
+#	add	r2, r2, r8		# add base	
+	std	r6, 0(r1)		# save stack pointer
+
+	ld	r6, _prom_entry at got(r2)
+	std	r5, 0(r6)		# Save prom handle
+
+	ld	r10, _exit_sp at got(r2)	# save stack pointer for exit call
+	std	r1, 0(r10)
+
+	bl	._start_kernel		# call kernel init code
+
+the_end:
+	ld	r4, 56(r1)		# Restore link register
+	mtlr	r4
+	ld	r2, 64(r1)		# restore got
+	ld	r1, 0(r1)
+
+	blr
+
+/*
+ * Function: _callback_entry
+ * Input:   r6  start address of parameter string
+ *          r7  length of parameter string.
+ *
+ * Description: If a client application wants to register a callback function,
+ *  this function is registered w/ SLOF, not the application's function. SLOF
+ *  passes the parameter string in Forth representation in R6 and R7. This
+ *  function moves R6 to R3 and R7 to R4 and then calls callback_entry().
+ *
+ */
+	.globl		_callback_entry
+	.section	".opd", "aw"
+	.align		3
+_callback_entry:
+	.quad		._callback_entry,.TOC. at tocbase,0
+	.previous
+	.size		callback,24
+	.type		._callback_entry, @function
+	.globl		._callback_entry
+._callback_entry:
+	# Save the LR
+	mflr	r0
+	std	r0, 16(r1)
+
+	# Reserve stack space
+	stdu	r1,	-32(r1)
+
+	# SLOF passes the parameters in Registers R6 and R7 but the target
+	# wants them in registers R3 and R4
+	mr	r3, r6
+	mr	r4, r7
+
+	# Branch to the callback_entry function
+	bl	.callback_entry
+
+	# Destroy stack frame
+	ld	r1,	0(r1)
+
+	# Restore LR
+	ld	r0, 16(r1)
+	mtlr	r0
+
+	# Return to caller
+	blr
+
+
+	.globl  _exit_sp
+_exit_sp:	.quad 0
+	.globl	_prom_entry	
+_prom_entry:	.quad 0
+
+ENTRY(_exit)
+	ld	r1, _exit_sp at got(r2)
+	ld	r1, 0(r1)
+	b	the_end
+
+	.globl	.undo_exception
+.undo_exception:
+	.globl	undo_exception
+undo_exception:
+
+/* 
+	unwind stack
+*/
+	ld      r3,exception_stack_frame at got(r2)
+	ld      r1,0(r3)
+
+	ld 	r14,0x130(r1)
+	mtctr	r14
+
+//	restore regs same as in _exception_handler:
+
+	.irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+    addi	r1, r1, 0x130
+
+//	restore regs as in default handler 
+
+	ld	r0, 0x48(r1)	
+	mtsrr0	r0
+	ld	r0, 0x50(r1)	
+	mtsrr1	r0
+// 20
+	ld	r0, 0x38(r1)
+	mtlr	r0	
+	ld	r0, 0x30(r1)
+	ld	r11, 0x40(r1)
+// 30
+	addi 	r1, r1, 0x58
+
+	rfid
+
+	.lcomm	_stack,STACKSIZE,16
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/init.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/init.c
new file mode 100644
index 0000000..e88b4eb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/init.c
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <of.h>
+#include <pci.h>
+#include <kernel.h>
+#include <stdint.h>
+#include <string.h>
+#include <cpu.h>
+#include <fileio.h>
+#include <stdlib.h> /* malloc */
+#include <ioctl.h> /* ioctl */
+
+/* Application entry point .*/
+extern int _start(unsigned char *arg_string, long len);
+extern int main(int, char**);
+void * malloc_aligned(size_t size, int align);
+extern snk_module_t *insmod_by_type(int);
+extern void rmmod_by_type(int);
+
+unsigned long exception_stack_frame;
+
+snk_fileio_t fd_array[FILEIO_MAX];
+
+extern uint64_t tb_freq;
+
+void modules_init(void);
+void modules_term(void);
+int glue_init(snk_kernel_t *, unsigned int *, size_t, size_t);
+void glue_release(void);
+
+static char save_vector[0x4000];
+extern char _lowmem_start;
+extern char _lowmem_end;
+extern char __client_start;
+extern char __client_end;
+
+snk_kernel_t snk_kernel_interface = {
+	.version          = 1,
+	.print            = printk,
+	.us_delay         = udelay,
+	.ms_delay         = mdelay,
+	.k_malloc         = malloc,
+	.k_malloc_aligned = malloc_aligned,
+	.k_free           = free,
+	.strcmp           = strcmp,
+	.snk_call         = main,
+	.k_open           = open,
+	.k_close          = close,
+	.k_read           = read,
+	.k_write          = write,
+	.k_ioctl          = ioctl,
+	.modules_remove   = rmmod_by_type,
+	.modules_load     = insmod_by_type,
+};
+
+void *
+malloc_aligned(size_t size, int align)
+{
+	unsigned long p = (unsigned long) malloc(size + align - 1);
+	p = p + align - 1;
+	p = p & ~(align - 1);
+
+	return (void *) p;
+}
+
+static void
+copy_exception_vectors()
+{
+	char *dest;
+	char *src;
+	int len;
+
+	dest = save_vector;
+	src = (char *) 0x200;
+	len = &_lowmem_end - &_lowmem_start;
+	memcpy(dest, src, len);
+
+	dest = (char *) 0x200;
+	src = &_lowmem_start;
+	memcpy(dest, src, len);
+	flush_cache(dest, len);
+}
+
+static void
+restore_exception_vectors()
+{
+	char *dest;
+	char *src;
+	int len;
+
+	dest = (char *) 0x200;
+	src = save_vector;
+	len = &_lowmem_end - &_lowmem_start;
+	memcpy(dest, src, len);
+	flush_cache(dest, len);
+}
+
+int
+_start_kernel(unsigned long p0, unsigned long p1)
+{
+	int rc;
+	unsigned int timebase;
+
+	/* initialize all file descriptor by marking them as empty */
+	for(rc=0; rc<FILEIO_MAX; ++rc) {
+		fd_array[rc].type = FILEIO_TYPE_EMPTY;
+		fd_array[rc].idx  = rc;
+	}
+
+	/* this is step is e.g. resposible to initialize file descriptor 0 and 1 for STDIO */
+	rc = glue_init(&snk_kernel_interface, &timebase, (size_t)(unsigned long)&__client_start,
+	               (size_t)(unsigned long)&__client_end - (size_t)(unsigned long)&__client_start);
+	if(rc < 0)
+		return -1;
+
+	tb_freq = (uint64_t) timebase;
+	copy_exception_vectors();
+	modules_init();
+	rc = _start((unsigned char *) p0, p1);
+	modules_term();
+	restore_exception_vectors();
+
+	glue_release();
+	return rc;
+}
+
+
+void
+exception_forward(void)
+{
+	restore_exception_vectors();
+	undo_exception();
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/lowmem.S b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/lowmem.S
new file mode 100644
index 0000000..8d6cfc6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/lowmem.S
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <macros.h>
+.section        .lowmem,"aw", at progbits
+
+	.irp i, 0x0200,0x0300,0x0380,0x0400,0x0480,0x0500,0x0600,0x0700, \
+		0x0800,0x0900,0x0a00,0x0b00
+	. = \i - 0x200
+// 0	
+	stdu	r1, -0x58(r1)
+	std	r0, 0x30(r1)
+	mflr	r0
+	std	r0, 0x38(r1)
+// 10
+	mfsrr0	r0
+	std	r0, 0x48(r1)	
+	mfsrr1	r0
+	std	r0, 0x50(r1)	
+// 20
+	std	r11, 0x40(r1)
+ 	li	r0, \i
+	ld	r11, 0x60 + \i(0)
+	bl	_exception_handler
+
+// 30
+	ld	r0, 0x48(r1)	
+	mtsrr0	r0
+	ld	r0, 0x50(r1)	
+	mtsrr1	r0
+
+// 40
+	ld	r0, 0x38(r1)
+	mtlr	r0	
+	ld	r0, 0x30(r1)
+	ld	r11, 0x40(r1)
+// 50
+	addi 	r1, r1, 0x58
+	rfid
+	nop
+	nop
+// 60	
+//	.quad	\i+0x68	
+	.quad	.exception_forward		
+// 68
+	blr
+	.endr
+
+	# System call entry
+	. = 0xc00 - 0x200
+
+	stdu	r1, -0x50(r1)
+	mflr	r11
+	std	r11, 0x30(r1)
+	mfsrr0	r11
+	std	r11, 0x40(r1)	
+	mfsrr1	r11
+	std	r11, 0x48(r1)	
+	ld	r11, _system_call at got(r2)
+	ld	r11, 0(r11)
+	mtctr	r11
+	mr	r10, r0
+	bctrl
+	ld	r11, 0x30(r1)
+	mtlr	r11
+	ld	r11, 0x40(r1)	
+	mtsrr0	r11
+	ld	r11, 0x48(r1)	
+	mtsrr1	r11
+	addi	r1, r1, 0x50
+	rfid
+	
+	.irp i, 0x0d00,0x0e00,0x0f00, \
+		0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
+		0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+		0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+		0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00,0x2f00
+	. = \i - 0x200
+// 0	
+	stdu	r1, -0x58(r1)
+	std	r0, 0x30(r1)
+	mflr	r0
+	std	r0, 0x38(r1)
+// 10
+	mfsrr0	r0
+	std	r0, 0x48(r1)	
+	mfsrr1	r0
+	std	r0, 0x50(r1)	
+// 20
+	std	r11, 0x40(r1)
+ 	li	r0, \i
+	ld	r11, 0x60 + \i(0)
+	bl	_exception_handler
+
+// 30
+	ld	r0, 0x48(r1)	
+	mtsrr0	r0
+	ld	r0, 0x50(r1)	
+	mtsrr1	r0
+
+// 40
+	ld	r0, 0x38(r1)
+	mtlr	r0	
+	ld	r0, 0x30(r1)
+	ld	r11, 0x40(r1)
+// 50
+	addi 	r1, r1, 0x58
+	rfid
+	nop
+	nop
+// 60	
+//	.quad	\i+0x68	
+	.quad	.exception_forward		
+// 68
+	blr
+	.endr
+
+/* Saves all register potential clobbered in exception handler.
+   In r0 the pointer to the function is passed.
+ */
+
+_exception_handler:
+    stdu	r1, -0x130(r1)	
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	std	r\i, 0x30+\i*8 (r1)
+	.endr
+	mfctr   r14
+	std	r14,0x130(r1)
+	mtctr	r11
+
+	LOAD64(r3,_entry)
+	ld	r2,8(r3)
+
+	ld      r3,exception_stack_frame at got(r2)
+	std     r1,0(r3)
+
+
+	mflr	r14
+	bctrl	
+	mtlr	r14
+
+	ld 	r14,0x130(r1)
+	mtctr	r14
+/*
+	mfsrr0	r2
+	addi	r2, r2, 4
+	mtsrr0	r2
+*/
+	.irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+		27, 28, 29, 30, 31
+	ld	r\i, 0x30+\i*8 (r1)
+	.endr
+    addi	r1, r1, 0x130
+	blr 
+
+	.text
+	
+/* Set exception handler for given exception vector.  
+	r3:	exception vector offset
+	r4:	exception handler
+*/	
+	.globl .set_exception
+.set_exception:
+	.globl set_exception
+set_exception:
+    ld r4,0x0(r4)
+	.globl .set_exception_asm
+.set_exception_asm:
+	.globl set_exception_asm
+set_exception_asm:
+	std	r4, 0x60(r3)	# fixme diff 1f - 0b
+	blr 	
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/modules.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/modules.c
new file mode 100644
index 0000000..1ebf0b9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/modules.c
@@ -0,0 +1,208 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <netdriver_int.h>
+#include <kernel.h>
+#include <of.h>
+#include <rtas.h> 
+#include <cpu.h> /* flush_cache */
+//#include <stdlib.h> /* malloc */
+#include <unistd.h> /* open, close, read, write */
+
+unsigned int read_io(void *, size_t);
+int write_io(void *, unsigned int, size_t);
+
+extern void get_mac(char *mac);
+extern snk_module_t of_module;
+
+typedef snk_module_t *(*module_init_t) (snk_kernel_t *, pci_config_t *);
+
+typedef struct {
+	const char *name;
+	void       *link_addr;
+	int        type;
+} mod_descriptor_t;
+
+static const mod_descriptor_t modules[] = {
+	{ "net_e1000" , (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ "net_bcm"   , (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ "net_nx203x", (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ "net_mcmal" , (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ "net_spider", (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ "net_veth",   (void*) 0xF800000, MOD_TYPE_NETWORK },
+	{ 0           , (void*) 0         }
+};
+
+snk_module_t *snk_modules[MODULES_MAX];
+
+extern snk_kernel_t snk_kernel_interface;
+
+/* Load module and call init code.
+   Init code will check, if module is responsible for device.
+   Returns -1, if not responsible for device, 0 otherwise.
+*/
+
+static int
+load_module(const char *name)
+{
+	int len, i;
+	void *addr;
+	void *link_addr;
+	module_init_t module_init;
+
+	/* find module in module list and lookup link address */
+	for(i=0; modules[i].name; ++i) {
+		if(strcmp(modules[i].name, name) == 0)
+			break;
+	}
+	if( modules[i].name == 0 ) {
+		/* module not in list */
+		return -1;
+	}
+	link_addr = modules[i].link_addr;
+
+	/* check if link address is used already */
+	for(i=0; i<MODULES_MAX; ++i) {
+		if(snk_modules[i] && snk_modules[i]->link_addr == link_addr) {
+			/* busy, can't load modules */
+			return -2;
+		}
+	}
+
+	/* find empty position in array of loaded modules */
+	for(i=0; i<MODULES_MAX; ++i) {
+		if(snk_modules[i] == 0) {
+			break;
+		}
+	}
+	if(i == MODULES_MAX) {
+		// no space avaliable!
+		return -3;
+	}
+
+	/* Read module from FLASH */
+	len = romfs_lookup(name, &addr);
+	if (len <= 0) {
+		/* file not found */
+		return -4;
+	}
+	/* Copy image from flash to RAM
+	 * FIXME fix address 8MB
+	 */
+
+	memcpy(link_addr, addr, len);
+
+	flush_cache(link_addr, len);
+
+	/* Module starts with opd structure of the module_init
+	 * function.
+	 */
+	module_init = (module_init_t) link_addr;
+
+	snk_modules[i] = module_init(&snk_kernel_interface, &snk_kernel_interface.pci_conf);
+	if(snk_modules[i] == 0) {
+		/* no device found that can be managed by this module */
+		return -5;
+	}
+
+	if(snk_modules[i]->type == MOD_TYPE_NETWORK) {
+		/* Get mac address from device tree */
+		get_mac(snk_modules[i]->mac_addr);
+	}
+
+	return i;
+}
+
+void
+modules_init(void)
+{
+	int i;
+
+	snk_kernel_interface.io_read  = read_io;
+	snk_kernel_interface.io_write = write_io;
+
+	snk_modules[0] = &of_module;
+
+	/* Setup Module List */
+	for(i=1; i<MODULES_MAX; ++i) {
+		snk_modules[i] = 0;
+	}
+
+	/* Load all modules */
+	for(i=0; modules[i].name; ++i) {
+		load_module(modules[i].name);
+	}
+}
+
+void
+modules_term()
+{
+	int i;
+
+	/* remove all modules */
+	for(i=0; i<MODULES_MAX; ++i) {
+		if(snk_modules[i] && snk_modules[i]->running != 0) {
+			snk_modules[i]->term();
+		}
+		snk_modules[i] = 0;
+	}
+}
+
+snk_module_t *
+get_module_by_type(int type) {
+	int i;
+
+	for(i=0; i<MODULES_MAX; ++i) {
+		if(snk_modules[i] && snk_modules[i]->type == type) {
+			return snk_modules[i];
+		}
+	}
+	return 0;
+}
+
+/**
+ * insmod_by_type - Load first module of given type
+ *
+ * @param type  Type of module that we want to load
+ * @return      module descriptor on success
+ *              NULL              if not successful
+ */
+snk_module_t *
+insmod_by_type(int type) {
+	int i, j;
+	for(i = 0; modules[i].name; ++i) {
+		if(modules[i].type != type)
+			continue;
+		j = load_module(modules[i].name);
+		if(j >= 0)
+			return snk_modules[j];
+	}
+	return 0;
+}
+
+/**
+ * rmmod_by_type - Remove all module of given type
+ *
+ * @param type  Type of module that we want to load
+ */
+void
+rmmod_by_type(int type) {
+	int i;
+
+	for (i = 0; i < MODULES_MAX; ++i) {
+		if (snk_modules[i] && snk_modules[i]->type == type) {
+			if (snk_modules[i]->running)
+				snk_modules[i]->term();
+			snk_modules[i] = 0;
+		}
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/systemcall.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/systemcall.c
new file mode 100644
index 0000000..3c70e7d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/systemcall.c
@@ -0,0 +1,285 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <of.h>
+#include <systemcall.h>
+#include <stdarg.h>
+#include <netdriver_int.h>
+#include <string.h>
+#include <fileio.h>
+
+//extern ihandle_t fd_array[32];
+extern snk_module_t *get_module_by_type(int type);
+extern int vsprintf(char *, const char *, va_list);
+extern void _exit(int status);
+
+int printk(const char*, ...);
+
+static int
+_syscall_open(const char* name, int flags)
+{
+	int fd, i;
+
+	/* search free file descriptor */
+	for(fd=0; fd<FILEIO_MAX; ++fd) {
+		if(fd_array[fd].type == FILEIO_TYPE_EMPTY) {
+			break;
+		}
+	}
+	if(fd == FILEIO_MAX) {
+		printk ("Can not open \"%s\" because file descriptor list is full\n", name);
+		/* there is no free file descriptor avaliable */
+		return -2;
+	}
+
+	for(i=0; i<MODULES_MAX; ++i) {
+		if(!snk_modules[i] || !snk_modules[i]->open) {
+			continue;
+		}
+
+		if(snk_modules[i]->running == 0) {
+			snk_modules[i]->init();
+		}
+
+		if(snk_modules[i]->open(&fd_array[fd], name, flags) == 0)
+			break;
+	}
+
+	if(i==MODULES_MAX) {
+		/* file not found */
+		return -1;
+	}
+
+	return fd;
+}
+
+static int
+_syscall_socket(int domain, int type, int proto, char *mac_addr)
+{
+	snk_module_t *net_module;
+
+	net_module = get_module_by_type(MOD_TYPE_NETWORK);
+	if( !net_module ||  !net_module->init) {
+		printk("No net_init function available");
+		return -1;
+	}
+
+	/* Init net device driver */
+	if(net_module->running == 0) {
+		net_module->init();
+	}
+
+	if(net_module->running == 0)
+		return -2;
+
+	memcpy(mac_addr, &net_module->mac_addr[0], 6);
+	return 0;
+}
+
+static int
+_syscall_close(int fd)
+{
+	if(fd < 0 || fd >= FILEIO_MAX
+	|| fd_array[fd].type == FILEIO_TYPE_EMPTY
+	|| fd_array[fd].close == 0)
+		return -1;
+
+	return fd_array[fd].close(&fd_array[fd]);
+}
+
+static long
+_syscall_read (int fd, char *buf, long len)
+{
+	if(fd < 0 || fd >= FILEIO_MAX
+	|| fd_array[fd].type == FILEIO_TYPE_EMPTY
+	|| fd_array[fd].read == 0)
+		return -1;
+
+	return fd_array[fd].read(&fd_array[fd], buf, len);
+}
+
+static long
+_syscall_write (int fd, char *buf, long len)
+{
+    char dest_buf[512];
+    char *dest_buf_ptr;
+    int i;
+    if (fd == 1 || fd == 2)
+    {
+	dest_buf_ptr = &dest_buf[0];
+        for (i = 0; i < len && i < 256; i++)
+        {
+            *dest_buf_ptr++ = *buf++;
+            if (buf[-1] == '\n')
+                *dest_buf_ptr++ = '\r';
+	}
+	len = dest_buf_ptr - &dest_buf[0];
+	buf = &dest_buf[0];
+    }
+
+	if(fd < 0 || fd >= FILEIO_MAX
+	|| fd_array[fd].type == FILEIO_TYPE_EMPTY
+	|| fd_array[fd].write == 0)
+		return -1;
+
+	return fd_array[fd].write(&fd_array[fd], buf, len);
+}
+
+static long
+_syscall_lseek (int fd, long offset, int whence)
+{
+	return 0; // this syscall is unused !!!
+#if 0
+    if (whence != 0)
+	return -1;
+
+    of_seek (fd_array[fd], (unsigned int) (offset>>32), (unsigned int) (offset & 0xffffffffULL));
+
+    return offset;
+#endif
+}
+
+static int
+_syscall_ioctl (int fd, int request, void* data)
+{
+	if (fd < 0
+	 || fd >= FILEIO_MAX
+	 || fd_array[fd].type == FILEIO_TYPE_EMPTY)
+		return -1;
+	if (!fd_array[fd].ioctl) { /* for backwards compatibility with network modules */
+		snk_module_t *net_module;
+
+		net_module = get_module_by_type(MOD_TYPE_NETWORK);
+		if ( !net_module || !net_module->ioctl ) {
+			printk("No net_ioctl function available");
+			return -1;
+		}
+
+		return net_module->ioctl(request, data);
+	}
+
+	return fd_array[fd].ioctl(&fd_array[fd], request, data);
+}
+
+static long
+_syscall_recv(int fd, void *packet, int packet_len, int flags)
+{
+	snk_module_t *net_module;
+
+	net_module = get_module_by_type(MOD_TYPE_NETWORK);
+	if( !net_module || !net_module->read ) {
+		printk("No net_receive function available");
+		return -1;
+	}
+
+	return net_module->read(packet, packet_len);
+}
+
+static long
+_syscall_send(int fd, void *packet, int packet_len, int flags)
+{
+	snk_module_t *net_module;
+
+	net_module = get_module_by_type(MOD_TYPE_NETWORK);
+	if( !net_module || !net_module->write ) {
+		printk("No net_xmit function available");
+		return -1;
+	}
+
+	return net_module->write(packet, packet_len);
+}
+
+static long
+_syscall_sendto(int fd, void *packet, int packet_len, int flags,
+	void *sock_addr, int sock_addr_len)
+{
+	return _syscall_send(fd, packet, packet_len, flags);
+}
+
+
+
+
+
+
+
+
+long
+_system_call(long arg0, long arg1, long arg2, long arg3, 
+	     long arg4, long arg5, long arg6, int nr)
+{
+	long rc = -1;
+
+	switch (nr)
+	{
+	case _open_sc_nr:
+		rc = _syscall_open ((void *) arg0, arg1);
+		break;
+	case _read_sc_nr:
+		rc = _syscall_read (arg0, (void *) arg1, arg2);
+		break;
+	case _close_sc_nr:
+		_syscall_close (arg0);
+		break;
+	case _lseek_sc_nr:
+		rc = _syscall_lseek (arg0, arg1, arg2);
+		break;
+	case _write_sc_nr:
+		rc = _syscall_write (arg0, (void *) arg1, arg2);
+		break;
+	case _ioctl_sc_nr:
+		rc = _syscall_ioctl (arg0, arg1, (void *) arg2);
+		break;
+	case _socket_sc_nr:
+		switch (arg0)
+		{
+		case _sock_sc_nr:
+			rc = _syscall_socket (arg1, arg2, arg3, (char*) arg4);
+			break;
+		case _recv_sc_nr:
+			rc = _syscall_recv (arg1, (void *) arg2, arg3, arg4);
+			break;
+		case _send_sc_nr:
+			rc = _syscall_send (arg1, (void *) arg2, arg3, arg4);
+			break;
+		case _sendto_sc_nr:
+			rc = _syscall_sendto (arg1, (void *) arg2, arg3, arg4, (void *) arg5, arg6);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+void 
+exit(int status)
+{
+	_exit(status);
+}
+
+int
+printk(const char* fmt, ...)
+{
+	int count;
+	va_list ap;
+	char buffer[256];
+	va_start (ap, fmt);
+	count=vsprintf(buffer, fmt, ap);
+	_syscall_write (1, buffer, count);
+	va_end (ap);
+	return count;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/timer.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/timer.c
new file mode 100644
index 0000000..630a9b4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/kernel/timer.c
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <types.h>
+
+//*******************************************************************
+// variable "tb_freq" contains the frequency in Hz
+// and is read from the device tree (setup by LLFW) in "init.c"
+uint64_t tb_freq;
+
+//-------------------------------------------------------------------
+// Read the current timebase
+uint64_t get_time(void)
+{
+    uint64_t act;
+
+    __asm__ __volatile__( 
+        "0:     mftbu   %0 ;\
+                mftbl   %%r0 ; \
+                mftbu   %%r4 ; \
+                cmpw    %0,%%r4 ; \
+                bne     0b; \
+                sldi    %0,%0,32; \
+                or      %0,%0,%%r0"
+        : "=r"(act)
+        : /* no inputs */
+        : "r0", "r4");
+    return act;
+}
+
+//-------------------------------------------------------------------
+// wait for ticks/scale timebase ticks
+void wait_ticks(uint64_t ticks)
+{
+        uint64_t timeout = get_time() + ticks;
+        while (get_time() < timeout) {
+                unsigned int i;
+                for (i = 1000; i > 0; i--)
+                        __asm__ __volatile__ ("" : : : "memory");
+        }
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) usecs microseconds
+void udelay(unsigned int usecs)
+{
+        // first multiply the usec with timebase and then devide
+        // because 1.000.000 is relatively huge compared to usecs
+        wait_ticks((usecs*tb_freq)/1000000);
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) msecs milliseconds
+void mdelay(unsigned int msecs)
+{
+        // first multiply the msec and timebase and then devide
+        // because 1.000 is relatively huge compared to msecs
+        wait_ticks((msecs*tb_freq)/1000);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/Makefile
new file mode 100644
index 0000000..21e0edf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/Makefile
@@ -0,0 +1,44 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+
+OBJS	= sbrk.o io.o ioctl.o
+OBJDIRS = socket/socket.o time/time.o
+SUBDIRS = $(filter-out ./,$(dir $(OBJDIRS)))
+
+
+all: libc-glue.o
+
+libc-glue.o: subdirs sbrk.o io.o ioctl.o
+	$(LD) $(LDFLAGS) $(OBJS) $(OBJDIRS) -o $@ -r
+
+
+subdirs :
+	for dir in $(SUBDIRS); do \
+		$(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+	done
+
+clean:
+	$(RM) -f *.a *.o
+	@for dir in $(SUBDIRS); do \
+		$(CLEAN) ; \
+		$(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+	done
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/io.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/io.c
new file mode 100644
index 0000000..0364b9a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/io.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stddef.h"
+#include "systemcall.h"
+#include "unistd.h"
+
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+    return syscall_3 (_write_sc_nr, fd, (long) buf, count);
+}
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+    return syscall_3 (_read_sc_nr, fd, (long) buf, count);
+}
+
+ssize_t lseek(int fd, long off, int whence)
+{
+    return syscall_3 (_lseek_sc_nr, fd, off, whence);
+}
+
+int open(const char *name, int flags)
+{
+    return syscall_2 (_open_sc_nr, (long int) name, flags);
+}
+
+int close(int fd)
+{
+    return syscall_1(_close_sc_nr,fd);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/ioctl.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/ioctl.c
new file mode 100644
index 0000000..370472c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/ioctl.c
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "systemcall.h"
+
+
+int ioctl(int fd, int request, void *data)
+{
+    return syscall_3 (_ioctl_sc_nr, fd, request, (long) data);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/sbrk.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/sbrk.c
new file mode 100644
index 0000000..002e831
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/sbrk.c
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define HEAP_SIZE 0x200000
+
+
+static char heap[HEAP_SIZE];
+static char *actptr;
+
+void *sbrk(int increment)
+{
+	char *oldptr;
+
+	/* Called for the first time? Then init the actual pointer */
+	if (!actptr) {
+		actptr = heap;
+	}
+
+	if (actptr + increment > heap + HEAP_SIZE) {
+		/* Out of memory */
+		return (void *)-1;
+	}
+
+	oldptr = actptr;
+	actptr += increment;
+
+	return oldptr;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/Makefile
new file mode 100644
index 0000000..cffa6b3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/Makefile
@@ -0,0 +1,39 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+
+OBJS = send.o
+
+
+all: socket.o
+
+
+socket.o: $(OBJS)
+	$(LD) $(LDFLAGS) -r $< -o $@
+
+%.o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+
+clean:
+	$(RM) -f *.o *.i *.s
+
+distclean mrproper: clean
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/send.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/send.c
new file mode 100644
index 0000000..7526f29
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/socket/send.c
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "sys/socket.h"
+
+int socket(int dom, int type, int proto, char *mac_addr)
+{
+    return syscall_5 (_socket_sc_nr, _sock_sc_nr, dom, type, proto, (long)mac_addr);
+}
+
+int sendto(int fd, const void* buffer, int len, int flags, const void* sock_addr, int sock_addr_len)
+{
+    return syscall_7 (_socket_sc_nr, _sendto_sc_nr, fd, (long) buffer, len, flags, (long) sock_addr, sock_addr_len);
+}
+
+int send(int fd, void* buffer, int len, int flags)
+{
+    return syscall_5 (_socket_sc_nr, _send_sc_nr, fd, (long) buffer, len, flags);
+}
+
+int recv(int fd, void* buffer, int len, int flags)
+{
+    return syscall_5 (_socket_sc_nr, _recv_sc_nr, fd, (long) buffer, len, flags);
+}
+
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/Makefile
new file mode 100644
index 0000000..072df55
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/Makefile
@@ -0,0 +1,39 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2011 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+
+endif
+include $(TOP)/make.rules
+
+
+OBJS = timer.o ftime.o
+
+
+all: time.o
+	
+
+time.o: $(OBJS)
+	$(LD) $(LDFLAGS) -r $< -o $@
+
+%.o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+
+clean:
+	$(RM) -f *.o *.i *.s
+
+distclean mrproper: clean
+
+include $(TOP)/make.depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/ftime.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/ftime.c
new file mode 100644
index 0000000..e092ba5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/ftime.c
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <time.h>
+#include <rtas.h>
+#include <stdio.h>
+
+time_t
+time(time_t *tod)
+{
+	dtime ts;
+
+	rtas_get_time_of_day(&ts);
+	printf("debug!!\n");
+	
+	printf("year  : %d\n", ts.year);
+	printf("month : %d\n", ts.month);
+	printf("day   : %d\n", ts.day);
+	printf("hour  : %d\n", ts.hour);
+	printf("minute: %d\n", ts.minute);
+	printf("second: %d\n", ts.second);
+	printf("nano  : %d\n", ts.nano);
+	printf("debug ende\n");
+
+//	if(tod)
+//		*tod = t;
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/timer.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/timer.c
new file mode 100644
index 0000000..08477f1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/libc/time/timer.c
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "time.h"
+
+int get_msec_ticks()
+{
+        return tb_freq/1000;
+}
+
+int get_sec_ticks()
+{
+        return tb_freq;
+}
+
+void set_timer(int val)
+{
+        asm volatile ("mtdec %0"::"r" (val));
+}
+
+int get_timer()
+{
+        int val;
+        asm volatile ("mfdec %0":"=r" (val));
+        return val;
+}
+
+
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/make.rules b/qemu-0.15.x/roms/SLOF/clients/net-snk/make.rules
new file mode 100644
index 0000000..ea89e08
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/make.rules
@@ -0,0 +1,26 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ROOTDIR		?= $(TOP)/../..
+
+include $(ROOTDIR)/make.rules
+
+INCLCMNDIR	?= $(ROOTDIR)/include
+LIBCMNDIR	?= $(ROOTDIR)/lib
+CFLAGS		= -g -I. -I$(TOP)/include -I$(LIBCMNDIR)/libc/include \
+		  -I$(LIBCMNDIR)/libbootmsg -I$(INCLCMNDIR)/$(CPUARCH) \
+		  -O2 -fno-builtin -ffreestanding -msoft-float -mno-altivec \
+		  -Wall $(FLAG) -nostdinc -fno-stack-protector
+
+LDFLAGS		= -nostdlib
+ASFLAGS		= -I. -I$(TOP)/include -Wa,-mregnames -I$(INCLCMNDIR)/$(CPUARCH)
+DD		= dd
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/Makefile b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/Makefile
new file mode 100644
index 0000000..aad3e89
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/Makefile
@@ -0,0 +1,41 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS    = rtas.o of.o pci.o
+OBJS2   = entry.o
+
+all: 		oflib.o
+
+
+oflib.o:	$(OBJS) $(OBJS2)
+		$(LD) $(LDFLAGS) $^ -o oflib.o -r
+
+clean:		
+		$(RM) -f $(OBJS) $(OBJS2) oflib.o
+
+include $(TOP)/make.depend
+
+
+#mrproper : clean
+#	rm -rf .depend 
+#
+#depend :
+#	@rm -rf .depend ; touch .depend ; \
+#	makedepend -v -f.depend -- $(CFLAGS) -- $(OBJS:.o=.c) 2> /dev/null ; \
+#	$(CC) -M $(CFLAGS) $(OBJS2:.o=.S) >> .depend
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/entry.S b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/entry.S
new file mode 100644
index 0000000..5deeb04
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/entry.S
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+	.globl call_client_interface
+call_client_interface:	
+	.globl .call_client_interface
+.call_client_interface:
+	ld	r4, _prom_entry at got(r2)	# Load prom entry point
+	mflr	r0
+	ld	r4, 0(r4)
+	stdu	r1, -16(r1)
+	mtctr	r4
+	std	r0, 8(r1)
+	bctrl
+	ld	r0, 8(r1)
+	mtlr	r0
+	addi	r1, r1, 16
+	blr
+
+	.globl rtas_call_entry
+rtas_call_entry:	
+	.globl .rtas_call_entry
+.rtas_call_entry:
+	mtctr	r5
+	bctr	
+
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/of.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/of.c
new file mode 100644
index 0000000..a4d98b8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/of.c
@@ -0,0 +1,886 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <of.h>
+#include <rtas.h>
+#include <string.h>
+#include <netdriver_int.h>
+#include <fileio.h>
+#include <types.h>
+
+extern void call_client_interface(of_arg_t *);
+
+static int ofmod_init(void);
+static int ofmod_term(void);
+static int ofmod_open(snk_fileio_t*, const char* name, int flags);
+static int ofmod_read(char *buffer, int len);
+static int ofmod_write(char *buffer, int len);
+static int ofmod_ioctl(int request, void *data);
+
+snk_module_t of_module = {
+	.version = 1,
+	.type    = MOD_TYPE_OTHER,
+	.running = 1,
+	.link_addr = (char*) 1,
+	.init    = ofmod_init,
+	.term    = ofmod_term,
+	.open    = ofmod_open,
+	.write   = ofmod_write,
+	.read    = ofmod_read,
+	.ioctl   = ofmod_ioctl
+};
+
+static ihandle_t fd_ihandle_array[FILEIO_MAX];
+static int claim_rc = 0;
+static void* client_start;
+static size_t client_size;
+
+extern inline int
+of_0_1(const char *serv)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		0, 1,
+		{ 0 }
+	};
+
+	call_client_interface(&arg);
+
+	return arg.args[0];
+}
+
+extern inline void
+of_1_0(const char *serv, int arg0)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		1, 0,
+		{arg0, 0}
+	};
+
+	call_client_interface(&arg);
+}
+
+extern inline unsigned int
+of_1_1(const char *serv, int arg0)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		1, 1,
+		{arg0, 0}
+	};
+
+	call_client_interface(&arg);
+	return arg.args[1];
+}
+
+extern inline unsigned int
+of_1_2(const char *serv, int arg0, int *ret0)
+{
+        of_arg_t arg = {
+                p32cast serv,
+                1, 2,
+                {arg0, 0, 0}
+        };
+
+        call_client_interface(&arg);
+        *ret0 = arg.args[2];
+        return arg.args[1];
+}
+
+extern inline void
+of_2_0(const char *serv, int arg0, int arg1)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		2, 0,
+		{arg0, arg1, 0}
+	};
+
+	call_client_interface(&arg);
+}
+
+extern inline unsigned int
+of_2_1(const char *serv, int arg0, int arg1)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		2, 1,
+		{arg0, arg1, 0}
+	};
+
+	call_client_interface(&arg);
+	return arg.args[2];
+}
+
+extern inline unsigned int
+of_2_2(const char *serv, int arg0, int arg1, int *ret0)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		2, 2,
+		{arg0, arg1, 0, 0}
+	};
+
+	call_client_interface(&arg);
+	*ret0 = arg.args[3];
+	return arg.args[2];
+}
+
+extern inline unsigned int
+of_2_3(const char *serv, int arg0, int arg1, int *ret0, int *ret1)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		2, 3,
+		{arg0, arg1, 0, 0, 0}
+	};
+
+	call_client_interface(&arg);
+	*ret0 = arg.args[3];
+	*ret1 = arg.args[4];
+	return arg.args[2];
+}
+
+extern inline void
+of_3_0(const char *serv, int arg0, int arg1, int arg2)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		3, 0,
+		{arg0, arg1, arg2, 0}
+	};
+
+	call_client_interface(&arg);
+	return;
+}
+
+extern inline unsigned int
+of_3_1(const char *serv, int arg0, int arg1, int arg2)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		3, 1,
+		{arg0, arg1, arg2, 0}
+	};
+
+	call_client_interface(&arg);
+	return arg.args[3];
+}
+
+extern inline unsigned int
+of_3_2(const char *serv, int arg0, int arg1, int arg2, int *ret0)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		3, 2,
+		{arg0, arg1, arg2, 0, 0}
+	};
+
+	call_client_interface(&arg);
+	*ret0 = arg.args[4];
+	return arg.args[3];
+}
+
+extern inline unsigned int
+of_3_3(const char *serv, int arg0, int arg1, int arg2, int *ret0, int *ret1)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		3, 3,
+		{arg0, arg1, arg2, 0, 0, 0}
+	};
+
+	call_client_interface(&arg);
+	*ret0 = arg.args[4];
+	*ret1 = arg.args[5];
+	return arg.args[3];
+}
+
+extern inline unsigned int
+of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3)
+{
+	of_arg_t arg = {
+		p32cast serv,
+		4, 1,
+		{arg0, arg1, arg2, arg3, 0}
+	};
+
+	call_client_interface(&arg);
+	return arg.args[4];
+}
+
+int
+of_interpret_1(void *s, void *ret)
+{
+	return of_1_2("interpret", p32cast s, ret);
+}
+
+void
+of_close(ihandle_t ihandle)
+{
+	of_1_0("close", ihandle);
+}
+
+int
+of_write(ihandle_t ihandle, void *s, int len)
+{
+	return of_3_1("write", ihandle, p32cast s, len);
+}
+
+int
+of_read(ihandle_t ihandle, void *s, int len)
+{
+	return of_3_1("read", ihandle, p32cast s, len);
+}
+
+int
+of_seek(ihandle_t ihandle, int poshi, int poslo)
+{
+	return of_3_1("seek", ihandle, poshi, poslo);
+}
+
+int
+of_getprop(phandle_t phandle, const char *name, void *buf, int len)
+{
+	return of_4_1("getprop", phandle, p32cast name, p32cast buf, len);
+}
+
+phandle_t
+of_peer(phandle_t phandle)
+{
+	return (phandle_t) of_1_1("peer", phandle);
+}
+
+phandle_t
+of_child(phandle_t phandle)
+{
+	return (phandle_t) of_1_1("child", phandle);
+}
+
+phandle_t
+of_parent(phandle_t phandle)
+{
+	return (phandle_t) of_1_1("parent", phandle);
+}
+
+phandle_t
+of_finddevice(const char *name)
+{
+	return (phandle_t) of_1_1("finddevice", p32cast name);
+}
+
+ihandle_t
+of_open(const char *name)
+{
+	return (ihandle_t) of_1_1("open", p32cast name);
+}
+
+void *
+of_claim(void *start, unsigned int size, unsigned int align)
+{
+	return(void *)(long)(size_t)of_3_1("claim", p32cast start, size, align);
+}
+
+void
+of_release(void *start, unsigned int size)
+{
+	(void) of_2_0("release", p32cast start, size);
+}
+
+unsigned int
+romfs_lookup(const char *name, void **addr)
+{
+	unsigned int high, low;
+	unsigned int i = of_2_3("ibm,romfs-lookup", p32cast name, strlen(name),
+				(int *) &high, (int *) &low);
+	*addr = (void*)(((unsigned long) high << 32) | (unsigned long) low);
+	return i;
+}
+
+void *
+of_call_method_3(const char *name, ihandle_t ihandle, int arg0)
+{
+	int entry, rc;
+	rc = of_3_2("call-method", p32cast name, ihandle, arg0, &entry);
+	return rc != 0 ? 0 : (void *) (long) entry;
+}
+
+int
+vpd_read(unsigned int offset, unsigned int length, char *data)
+{
+	int result;
+	long tmp = (long) data;
+	result = of_3_1("rtas-read-vpd", offset, length, (int) tmp);
+	return result;
+}
+
+int
+vpd_write(unsigned int offset, unsigned int length, char *data)
+{
+	int result;
+	long tmp = (long) data;
+	result = of_3_1("rtas-write-vpd", offset, length, (int) tmp);
+	return result;
+}
+
+static void
+ipmi_oem_led_set(int type, int instance, int state)
+{
+	return of_3_0("set-led", type, instance, state);
+}
+
+int
+write_mm_log(char *data, unsigned int length, unsigned short type)
+{
+	long tmp = (long) data;
+
+	ipmi_oem_led_set(2, 0, 1);
+	return of_3_1("write-mm-log", (int) tmp, length, type);
+}
+
+int
+of_yield(void)
+{
+	return of_0_1("yield");
+}
+
+void *
+of_set_callback(void *addr)
+{
+	return (void *) (long) (size_t) of_1_1("set-callback", p32cast addr);
+}
+
+void
+bootmsg_warning(short id, const char *str, short lvl)
+{
+	(void) of_3_0("bootmsg-warning", id, lvl, p32cast str);
+}
+
+void
+bootmsg_error(short id, const char *str)
+{
+	(void) of_2_0("bootmsg-error", id, p32cast str);
+}
+
+void
+bootmsg_debugcp(short id, const char *str, short lvl)
+{
+	(void) of_3_0("bootmsg-debugcp", id, lvl, p32cast str);
+}
+
+void
+bootmsg_cp(short id)
+{
+	(void) of_1_0("bootmsg-cp", id);
+}
+
+
+static long
+of_fileio_read(snk_fileio_t *fileio, char *buf, long len)
+{
+	if(!fileio)
+		return -1;
+	return of_read( * (ihandle_t*) fileio->data, buf, len );
+}
+
+static long
+of_fileio_write(snk_fileio_t *fileio, char *buf, long len)
+{
+	if(!fileio)
+		return -1;
+	return of_write( * (ihandle_t*) fileio->data, buf, len );
+}
+
+static int
+of_fileio_close(snk_fileio_t *fileio)
+{
+	if(!fileio)
+		return -1;
+
+	fileio->type = FILEIO_TYPE_EMPTY;
+	of_close( * (ihandle_t*) fileio->data );
+	return 0;
+}
+
+
+#define CONFIG_SPACE 0
+#define IO_SPACE 1
+#define MEM_SPACE 2
+
+#define ASSIGNED_ADDRESS_PROPERTY 0
+#define REG_PROPERTY 1
+
+#define DEBUG_TRANSLATE_ADDRESS 0
+#if DEBUG_TRANSLATE_ADDRESS != 0
+#define DEBUG_TR(str...) printk(str)
+#else
+#define DEBUG_TR(str...)
+#endif
+
+/**
+ * pci_address_type tries to find the type for which a
+ * mapping should be done. This is PCI specific and is done by
+ * looking at the first 32bit of the phys-addr in
+ * assigned-addresses
+ *
+ * @param node     the node of the device which requests
+ *                 translatation
+ * @param address  the address which needs to be translated
+ * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY)
+ * @return         the corresponding type (config, i/o, mem)
+ */
+static int
+pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type)
+{
+	char *prop_name = "assigned-addresses";
+	if (prop_type == REG_PROPERTY)
+		prop_name = "reg";
+	/* #address-cells */
+	const unsigned int nac = 3;	//PCI
+	/* #size-cells */
+	const unsigned int nsc = 2;	//PCI
+	/* up to 11 pairs of (phys-addr(3) size(2)) */
+	unsigned char buf[11 * (nac + nsc) * sizeof(int)];
+	unsigned int *assigned_ptr;
+	int result = -1;
+	int len;
+	len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int));
+	assigned_ptr = (unsigned int *) &buf[0];
+	while (len > 0) {
+		if ((prop_type == REG_PROPERTY)
+		    && ((assigned_ptr[0] & 0xFF) != 0)) {
+			//BARs and Expansion ROM must be in assigned-addresses... so in reg
+			// we only look for those without config space offset set...
+			assigned_ptr += (nac + nsc);
+			len -= (nac + nsc) * sizeof(int);
+			continue;
+		}
+		DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2],
+			 assigned_ptr[4]);
+		if (address >= assigned_ptr[2]
+		    && address <= assigned_ptr[2] + assigned_ptr[4]) {
+			DEBUG_TR("found a match\n");
+			result = (assigned_ptr[0] & 0x03000000) >> 24;
+			break;
+		}
+		assigned_ptr += (nac + nsc);
+		len -= (nac + nsc) * sizeof(int);
+	}
+	/* this can only handle 32bit memory space and should be
+	 * removed as soon as translations for 64bit are available */
+	return (result == 3) ? MEM_SPACE : result;
+}
+
+/**
+ * this is a hack which returns the lower 64 bit of any number of cells
+ * all the higher bits will silently discarded
+ * right now this works pretty good as long 64 bit addresses is all we want
+ *
+ * @param addr  a pointer to the first address cell
+ * @param nc    number of cells addr points to
+ * @return      the lower 64 bit to which addr points
+ */
+static uint64_t
+get_dt_address(uint32_t *addr, uint32_t nc)
+{
+	uint64_t result = 0;
+	while (nc--)
+		result = (result << 32) | *(addr++);
+	return result;
+}
+
+/**
+ * this functions tries to find a mapping for the given address
+ * it assumes that if we have #address-cells == 3 that we are trying
+ * to do a PCI translation
+ *
+ * @param  addr    a pointer to the address that should be translated
+ *                 if a translation has been found the address will
+ *                 be modified
+ * @param  type    this is required for PCI devices to find the
+ *                 correct translation
+ * @param ranges   this is one "range" containing the translation
+ *                 information (one range = nac + pnac + nsc)
+ * @param nac      the OF property #address-cells
+ * @param nsc      the OF property #size-cells
+ * @param pnac     the OF property #address-cells from the parent node
+ * @return         -1 if no translation was possible; else 0
+ */
+static int
+map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac,
+	      uint32_t nsc, uint32_t pnac)
+{
+	long offset;
+	/* cm - child mapping */
+	/* pm - parent mapping */
+	uint64_t cm, size, pm;
+	/* only check for the type if nac == 3 (PCI) */
+	DEBUG_TR("type %x, nac %x\n", ranges[0], nac);
+	if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3)
+		return -1;
+	/* okay, it is the same type let's see if we find a mapping */
+	size = get_dt_address(ranges + nac + pnac, nsc);
+	if (nac == 3)		/* skip type if PCI */
+		cm = get_dt_address(ranges + 1, nac - 1);
+	else
+		cm = get_dt_address(ranges, nac);
+
+	DEBUG_TR("\t\tchild_mapping %lx\n", cm);
+	DEBUG_TR("\t\tsize %lx\n", size);
+	DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr);
+	if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr)
+		/* it is not inside the mapping range */
+		return -1;
+	/* get the offset */
+	offset = *addr - cm;
+	/* and add the offset on the parent mapping */
+	if (pnac == 3)		/* skip type if PCI */
+		pm = get_dt_address(ranges + nac + 1, pnac - 1);
+	else
+		pm = get_dt_address(ranges + nac, pnac);
+	DEBUG_TR("\t\tparent_mapping %lx\n", pm);
+	*addr = pm + offset;
+	DEBUG_TR("\t\t*address %lx\n", *addr);
+	return 0;
+}
+
+/**
+ * translate_address_dev tries to translate the device specific address
+ * to a host specific address by walking up in the device tree
+ *
+ * @param address  a pointer to a 64 bit value which will be
+ *                 translated
+ * @param current_node phandle of the device from which the
+ *                     translation will be started
+ */
+void
+translate_address_dev(uint64_t *addr, phandle_t current_node)
+{
+	unsigned char buf[1024];
+	phandle_t parent;
+	unsigned int pnac;
+	unsigned int nac;
+	unsigned int nsc;
+	int addr_type;
+	int len;
+	unsigned int *ranges;
+	unsigned int one_range;
+	DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node);
+	of_getprop(current_node, "name", buf, 400);
+	DEBUG_TR("current node: %s\n", buf);
+	addr_type =
+	    pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY);
+	if (addr_type == -1) {
+		// check in "reg" property if not found in "assigned-addresses"
+		addr_type = pci_address_type(current_node, *addr, REG_PROPERTY);
+	}
+	DEBUG_TR("address_type %x\n", addr_type);
+	current_node = of_parent(current_node);
+	while (1) {
+		parent = of_parent(current_node);
+		if (!parent) {
+			DEBUG_TR("reached root node...\n");
+			break;
+		}
+		of_getprop(current_node, "#address-cells", &nac, 4);
+		of_getprop(current_node, "#size-cells", &nsc, 4);
+		of_getprop(parent, "#address-cells", &pnac, 4);
+		one_range = nac + pnac + nsc;
+		len = of_getprop(current_node, "ranges", buf, 400);
+		if (len < 0) {
+			DEBUG_TR("no 'ranges' property; not translatable\n");
+			return;
+		}
+		ranges = (unsigned int *) &buf[0];
+		while (len > 0) {
+			if (!map_one_range
+			    ((uint64_t *) addr, addr_type, ranges, nac, nsc,
+			     pnac))
+				/* after a successful mapping we stop
+				 * going through the ranges */
+				break;
+			ranges += one_range;
+			len -= one_range * sizeof(int);
+		}
+		DEBUG_TR("address %lx\n", *addr);
+		of_getprop(current_node, "name", buf, 400);
+		DEBUG_TR("current node: %s\n", buf);
+		DEBUG_TR("\t#address-cells: %x\n", nac);
+		DEBUG_TR("\t#size-cells: %x\n", nsc);
+		of_getprop(parent, "name", buf, 400);
+		DEBUG_TR("parent node: %s\n", buf);
+		DEBUG_TR("\t#address-cells: %x\n", pnac);
+		current_node = parent;
+	}
+}
+
+static phandle_t
+get_boot_device(void)
+{
+	char buf[1024];
+	phandle_t dev = of_finddevice("/chosen");
+
+	if (dev == -1) {
+		dev = of_finddevice("/aliases");
+		if (dev == -1)
+			return dev;
+		of_getprop(dev, "net", buf, 1024);
+	} else
+		of_getprop(dev, "bootpath", buf, 1024);
+
+	return of_finddevice(buf);
+}
+
+/**
+ * translate_address tries to translate the device specific address
+ * of the boot device to a host specific address
+ *
+ * @param address  a pointer to a 64 bit value which will be
+ *                 translated
+ */
+void
+translate_address(unsigned long *addr)
+{
+	translate_address_dev((uint64_t*) addr, get_boot_device());
+}
+
+/**
+ * get_puid walks up in the device tree until it finds a parent
+ * node without a reg property. get_puid is assuming that if the
+ * parent node has no reg property it has found the pci host bridge
+ *
+ * this is not the correct way to find PHBs but it seems to work
+ * for all our systems
+ *
+ * @param node   the device for which to find the puid
+ *
+ * @return       the puid or 0
+ */
+uint64_t
+get_puid(phandle_t node)
+{
+	uint64_t puid = 0;
+	uint64_t tmp = 0;
+	phandle_t curr_node = of_parent(node);
+	if (!curr_node)
+		/* no parent found */
+		return 0;
+	for (;;) {
+		puid = tmp;
+		if (of_getprop(curr_node, "reg", &tmp, 8) < 8) {
+			/* if the found PHB is not directly under
+			 * root we need to translate the found address */
+			translate_address_dev(&puid, node);
+			return puid;
+		}
+		curr_node = of_parent(curr_node);
+		if (!curr_node)
+			return 0;
+	}
+	return 0;
+}
+
+static int set_vio_config(vio_config_t * vio_config, phandle_t net)
+{
+	of_getprop(net, "reg", &vio_config->reg, 4);
+	of_getprop(net, "compatible", &vio_config->compat, 64);
+
+	return 0;
+}
+
+/* Fill in the pci config structure from the device tree */
+static int set_pci_config(pci_config_t * pci_config, phandle_t net)
+{
+	unsigned char buf[400];
+	int len, bar_nr;
+	unsigned int *assigned_ptr;
+
+	of_getprop(net, "vendor-id", &pci_config->vendor_id, 4);
+	of_getprop(net, "device-id", &pci_config->device_id, 4);
+	of_getprop(net, "revision-id", &pci_config->revision_id, 4);
+	of_getprop(net, "class-code", &pci_config->class_code, 4);
+	of_getprop(net, "interrupts", &pci_config->interrupt_line, 4);
+
+	len = of_getprop(net, "assigned-addresses", buf, 400);
+	if (len <= 0)
+		return -1;
+
+	assigned_ptr = (unsigned int *) &buf[0];
+	pci_config->bus = (assigned_ptr[0] & 0x00ff0000) >> 16;
+	pci_config->devfn = (assigned_ptr[0] & 0x0000ff00) >> 8;
+
+	while (len > 0) {
+		/* Fixme 64 bit bars */
+		bar_nr = ((assigned_ptr[0] & 0xff) - 0x10) / 4;
+		pci_config->bars[bar_nr].type =
+		    (assigned_ptr[0] & 0x0f000000) >> 24;
+		pci_config->bars[bar_nr].addr = assigned_ptr[2];
+		pci_config->bars[bar_nr].size = assigned_ptr[4];
+		assigned_ptr += 5;
+		len -= 5 * sizeof(int);
+	}
+
+	pci_config->puid = get_puid(net);
+
+	return 0;
+}
+
+static int set_config(snk_kernel_t * snk_kernel_interface)
+{
+	phandle_t parent, net = get_boot_device();
+	char compat[64];
+
+	if (net == -1)
+		return -1;
+
+	parent = of_parent(net);
+	of_getprop(parent, "compatible", compat, 64);
+	if (!strcmp(compat, "IBM,vdevice"))
+		return set_vio_config(&snk_kernel_interface->vio_conf, net);
+	return set_pci_config(&snk_kernel_interface->pci_conf, net);
+}
+
+void
+get_mac(char *mac)
+{
+	phandle_t net = get_boot_device();
+
+	if (net == -1)
+		return;
+
+	of_getprop(net, "local-mac-address", mac, 6);
+}
+
+static void
+get_timebase(unsigned int *timebase)
+{
+	phandle_t cpu;
+	phandle_t cpus = of_finddevice("/cpus");
+
+	if (cpus == -1)
+		return;
+
+	cpu = of_child(cpus);
+
+	if (cpu == -1)
+		return;
+
+	of_getprop(cpu, "timebase-frequency", timebase, 4);
+}
+
+int
+glue_init(snk_kernel_t * snk_kernel_interface, unsigned int * timebase,
+          size_t _client_start, size_t _client_size)
+{
+	phandle_t chosen = of_finddevice("/chosen");
+
+	client_start = (void *) (long) _client_start;
+	client_size = _client_size;
+
+	if (chosen == -1)
+		return -1;
+
+	fd_array[0].type  = FILEIO_TYPE_USED;
+	fd_array[0].read  = of_fileio_read;
+	fd_array[0].write = of_fileio_write;
+	fd_array[0].ioctl = 0;
+	fd_array[0].close = of_fileio_close;
+	fd_array[0].data  = &fd_ihandle_array[0];
+	of_getprop(chosen, "stdin", fd_array[0].data, sizeof(ihandle_t));
+
+	fd_array[1].type  = FILEIO_TYPE_USED;
+	fd_array[1].read  = of_fileio_read;
+	fd_array[1].write = of_fileio_write;
+	fd_array[1].ioctl = 0;
+	fd_array[1].close = of_fileio_close;
+	fd_array[1].data  = &fd_ihandle_array[1];
+	of_getprop(chosen, "stdout", fd_array[1].data, sizeof(ihandle_t));
+
+	if (of_write(fd_ihandle_array[1], " ", 1) < 0)
+		return -2;
+
+	/* Setup Kernel Struct */
+	if (set_config(snk_kernel_interface) == -1) {
+		snk_kernel_interface->print(" No net device found \n");
+	}
+
+	get_timebase(timebase);
+	rtas_init();
+
+	snk_kernel_interface->k_romfs_lookup = romfs_lookup;
+	snk_kernel_interface->translate_addr = translate_address;
+	snk_kernel_interface->pci_config_read = rtas_pci_config_read;
+	snk_kernel_interface->pci_config_write = rtas_pci_config_write;
+	claim_rc=(int)(long)of_claim(client_start, client_size, 0);
+
+	return 0;
+}
+
+void
+glue_release(void)
+{
+	if (claim_rc >= 0) {
+		of_release(client_start, client_size);
+	}
+}
+
+static int
+ofmod_init(void)
+{
+	of_module.running = 1;
+	return 0;
+}
+
+static int
+ofmod_term(void)
+{
+	of_module.running = 0;
+	return 0;
+}
+
+static int
+ofmod_open(snk_fileio_t *fileio, const char* name, int flags)
+{
+	if ((fd_ihandle_array[fileio->idx] = of_open (name)) == 0)
+	{
+		/* this module can not open this file */
+		return -1;
+	}
+
+	fileio->type  = FILEIO_TYPE_USED;
+	fileio->read  = of_fileio_read;
+	fileio->write = of_fileio_write;
+	fileio->close = of_fileio_close;
+	fileio->data  = &fd_ihandle_array[fileio->idx];
+	return 0;
+}
+
+static int
+ofmod_read(char *buffer, int len)
+{
+	return len;
+}
+
+static int
+ofmod_write(char *buffer, int len)
+{
+	return len;
+}
+
+static int
+ofmod_ioctl(int request, void *data)
+{
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/pci.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/pci.c
new file mode 100644
index 0000000..2a75829
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/pci.c
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <rtas.h>
+#include <of.h>
+#include <pci.h>
+#include <string.h>
+#include <kernel.h>
+#include <cpu.h>
+#include <cache.h>
+
+int
+pci_calc_bar_size(long long puid, int bus, int devfn, int bar)
+{
+	int size;
+	int old;
+	bar = bar * 4 + 0x10;
+	old = rtas_pci_config_read(puid, 4, bus, devfn, bar);
+	rtas_pci_config_write(puid, 4, bus, devfn, bar, 0xffffffff);
+	size = (rtas_pci_config_read(puid, 4, bus, devfn, bar) & (-4)) * -1;
+	rtas_pci_config_write(puid, 4, bus, devfn, bar, old);
+	return size;
+}
+
+int
+pci_get_bar_start(long long puid, int bus, int devfn, int bar)
+{
+	return rtas_pci_config_read(puid, 4, bus, devfn, bar * 4 + 0x10);
+}
+
+void
+pci_set_bar_start(long long puid, int bus, int devfn, int bar, int value)
+{
+	rtas_pci_config_write(puid, 4, bus, devfn, bar * 4 + 0x10, value);
+}
+
+unsigned int
+read_io(void *addr, size_t sz)
+{
+	unsigned int ret;
+
+	switch (sz) {
+	case 1:
+		ret = ci_read_8(addr);
+		break;
+	case 2:
+		ret = ci_read_16(addr);
+		break;
+	case 4:
+		ret = ci_read_32(addr);
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
+int
+write_io(void *addr, unsigned int value, size_t sz)
+{
+	switch (sz) {
+	case 1:
+		ci_write_8(addr, value);
+		break;
+	case 2:
+		ci_write_16(addr, value);
+		break;
+	case 4:
+		ci_write_32(addr, value);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/rtas.c b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/rtas.c
new file mode 100644
index 0000000..63d6e2f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/oflib/rtas.c
@@ -0,0 +1,334 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <rtas.h>
+#include <of.h>
+#include <types.h>
+#include "kernel.h"
+
+typedef int rtas_arg_t;
+
+typedef struct {
+	int token;
+	int nargs;
+	int nret;
+	rtas_arg_t args[16];
+	rtas_arg_t *rets;	/* Pointer to return values in args[]. */
+} rtas_args_t;
+
+rtas_args_t rtas_args;
+
+typedef struct {
+	void *rtas_start;
+	void *rtas_entry;
+	int rtas_size;
+	phandle_t dev;
+} rtas_t;
+
+extern rtas_t _rtas;
+static int instantiate_rtas(void);
+void rtas_call_entry(rtas_args_t *, void *, void *);
+
+int
+rtas_token(const char *service)
+{
+	int token;
+	int retVal;
+	if (_rtas.dev == 0)
+		instantiate_rtas();
+
+	retVal = of_getprop(_rtas.dev, service, &token, sizeof(token));
+	if (retVal == -1) {
+		token = 0;
+	}
+	return token;
+}
+
+int
+rtas_call(int token, int nargs, int nret, int *outputs, ...)
+{
+	va_list list;
+	int i;
+
+	rtas_args.token = token;
+	rtas_args.nargs = nargs;
+	rtas_args.nret = nret;
+	rtas_args.rets = (rtas_arg_t *) & (rtas_args.args[nargs]);
+	va_start(list, outputs);
+	for (i = 0; i < nargs; ++i) {
+		rtas_args.args[i] = (rtas_arg_t) (va_arg(list, unsigned int));
+	}
+	va_end(list);
+
+	for (i = 0; i < nret; ++i)
+		rtas_args.rets[i] = 0;
+
+	rtas_call_entry(&rtas_args, _rtas.rtas_start, _rtas.rtas_entry);
+	if (nret > 0 && outputs != 0)
+		for (i = 0; i < nret; i++)
+			outputs[i] = rtas_args.rets[i];
+#if 0
+	printf("rtas call %x %x %x args: %x %x %x %x %x %x %x %x\n",
+	       token, nargs, nret,
+	       rtas_args.args[0],
+	       rtas_args.args[1],
+	       rtas_args.args[2],
+	       rtas_args.args[3],
+	       rtas_args.args[4], rtas_args.args[5], outputs[0], outputs[1]);
+#endif
+	return ((nret > 0) ? rtas_args.rets[0] : 0);
+}
+
+rtas_t _rtas;
+
+static int
+instantiate_rtas(void)
+{
+	long long *rtas_mem_space;
+	ihandle_t ihandle;
+	_rtas.dev = of_finddevice("/rtas");
+	if ((long) _rtas.dev < 0) {
+		printf("Could not open /rtas\n");
+		return -1;
+	}
+
+	of_getprop(_rtas.dev, "rtas-size", &_rtas.rtas_size,
+		   sizeof(_rtas.rtas_size));
+
+	if (_rtas.rtas_size <= 0) {
+		printf("Size of rtas (%x) too small to make sense\n",
+		       _rtas.rtas_size);
+		return -1;
+	}
+
+	rtas_mem_space = (long long *) malloc_aligned(_rtas.rtas_size, 0x100);
+
+	if (!rtas_mem_space) {
+		printf("Failed to allocated memory for RTAS\n");
+		return -1;
+	}
+
+	ihandle = of_open("/rtas");
+
+	if ((long) ihandle < 0) {
+		printf("Could not open /rtas\n");
+		return -1;
+	}
+
+	if ((long) (_rtas.rtas_entry = of_call_method_3("instantiate-rtas",
+							ihandle,
+							p32cast rtas_mem_space))
+	    > 0) {
+		_rtas.rtas_start = rtas_mem_space;
+	} else {
+		printf("instantiate-rtas failed\n");
+		return -1;
+	}
+#if 0
+	printf("\ninstantiate-rtas at %x size %x entry %x\n",
+	       _rtas.rtas_start, _rtas.rtas_size, _rtas.rtas_entry);
+#endif
+	return 0;
+}
+
+static int read_pci_config_token = 0;
+static int write_pci_config_token = 0;
+static int ibm_read_pci_config_token = 0;
+static int ibm_write_pci_config_token = 0;
+static int ibm_update_flash_64_and_reboot_token = 0;
+static int ibm_update_flash_64_token = 0;
+static int manage_flash_token = 0;
+static int system_reboot_token = 0;
+static int get_time_of_day_token = 0;
+static int set_time_of_day_token = 0;
+static int start_cpu_token = 0;
+static int stop_self_token = 0;
+
+void
+rtas_init()
+{
+	int ret;
+	ret = instantiate_rtas();
+	if (ret)
+		return;
+	read_pci_config_token = rtas_token("read-pci-config");
+	ibm_read_pci_config_token = rtas_token("ibm,read-pci-config");
+	write_pci_config_token = rtas_token("write-pci-config");
+	ibm_write_pci_config_token = rtas_token("ibm,write-pci-config");
+	ibm_update_flash_64_and_reboot_token =
+	    rtas_token("ibm,update-flash-64-and-reboot");
+	ibm_update_flash_64_token = rtas_token("ibm,update-flash-64");
+	manage_flash_token = rtas_token("ibm,manage-flash-image");
+	system_reboot_token = rtas_token("system-reboot");
+	get_time_of_day_token = rtas_token("get-time-of-day");
+	set_time_of_day_token = rtas_token("set-time-of-day");
+	start_cpu_token = rtas_token("start-cpu");
+	stop_self_token = rtas_token("stop-self");
+}
+
+
+int
+rtas_pci_config_read(long long puid, int size, int bus, int devfn, int offset)
+{
+	int value[2];
+
+	if (ibm_read_pci_config_token && puid) {
+		rtas_call(ibm_read_pci_config_token, 4, 2, value,
+			  bus << 16 | devfn << 8 | offset,
+			  puid >> 32, puid & 0xffffffffULL, size);
+	} else if (read_pci_config_token) {
+		rtas_call(read_pci_config_token, 2, 2, value,
+			  bus << 16 | devfn << 8 | offset, size);
+	}
+
+	return value[1];
+}
+
+int
+rtas_pci_config_write(long long puid, int size, int bus, int devfn,
+		      int offset, int value)
+{
+	int rc;
+
+	if (ibm_write_pci_config_token && puid) {
+		rtas_call(ibm_write_pci_config_token, 5, 1, &rc,
+			  bus << 16 | devfn << 8 | offset,
+			  puid >> 32, puid & 0xffffffffULL, size, value);
+	} else
+		rtas_call(write_pci_config_token, 3, 1, &rc,
+			  bus << 16 | devfn << 8 | offset, size, value);
+
+	return rc;
+}
+
+/* a simple blocklist like this will us give no animation during flashing */
+
+struct block_list {
+	long long size;		//size of blocklist in bytes
+	long long address;	//address of memory area
+	long long length;	//lenght of memory area
+};
+
+int
+rtas_ibm_update_flash_64_and_reboot(long long address, long long length)
+{
+	int rc;
+	struct block_list block_list;
+	block_list.size = sizeof(block_list);
+	block_list.address = address;
+	block_list.length = length;
+	if (ibm_update_flash_64_and_reboot_token)
+		rtas_call(ibm_update_flash_64_and_reboot_token, 1, 1, &rc,
+			  &block_list);
+
+	return rc;
+}
+
+int
+rtas_ibm_manage_flash(int mode)
+{
+	int rc;
+	if (manage_flash_token)
+		rtas_call(manage_flash_token, 1, 1, &rc, mode);
+	return rc;
+}
+
+int
+rtas_ibm_update_flash_64(long long address, long long length)
+{
+	int rc;
+	struct block_list block_list;
+	block_list.size = sizeof(block_list);
+	block_list.address = address;
+	block_list.length = length;
+	if (ibm_update_flash_64_token)
+		rtas_call(ibm_update_flash_64_token, 1, 1, &rc, &block_list);
+
+	return rc;
+}
+
+int
+rtas_system_reboot()
+{
+	int rc;
+	if (system_reboot_token)
+		rtas_call(system_reboot_token, 0, 1, &rc);
+	return rc;
+}
+
+
+int
+rtas_get_time_of_day(dtime * get)
+{
+	int rc = -1;
+	unsigned int year;
+	unsigned int month;
+	unsigned int day;
+	unsigned int hour;
+	unsigned int minute;
+	unsigned int second;
+	unsigned int nano;
+
+	if (get_time_of_day_token)
+		rtas_call(get_time_of_day_token, 0, 8, &rc, &year, &month, &day,
+			  &hour, &minute, &second, &nano);
+
+	get->year = year;
+	get->month = month;
+	get->day = day;
+	get->hour = hour;
+	get->minute = minute;
+	get->second = second;
+	get->nano = nano;
+
+	return rc;
+}
+
+int
+rtas_set_time_of_day(dtime * set)
+{
+	int rc = -1;
+	if (set_time_of_day_token)
+		rtas_call(set_time_of_day_token, 7, 1, &rc, set->year,
+			  set->month, set->day, set->hour, set->minute,
+			  set->second, set->nano);
+	return rc;
+}
+
+
+int
+rtas_start_cpu(int pid, thread_t func_ptr, int r3)
+{
+	int rc;
+	if (start_cpu_token)
+		rtas_call(start_cpu_token, 3, 1, &rc, pid,
+			  (int) (long) func_ptr, (int) r3);
+	printk("start-cpu called %d %x %x %x\n", rc, start_cpu_token, pid,
+	       (long) func_ptr);
+	return rc;
+}
+
+int
+rtas_stop_self()
+{
+	int rc;
+	// fixme
+	stop_self_token = 0x20;
+
+	if (stop_self_token) {
+		rtas_call(stop_self_token, 0, 1, &rc);
+		printk("TOK\n");
+	}
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/net-snk/sec-client.lds b/qemu-0.15.x/roms/SLOF/clients/net-snk/sec-client.lds
new file mode 100644
index 0000000..0ca24ab
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/net-snk/sec-client.lds
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+	.client 0x200000:
+	{
+	__client_start = .;
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+          *(.rodata .rodata.* .gnu.linkonce.r.*)
+          KEEP (*(.opd))
+	  . = ALIGN(256); 
+	  *(.data .data.* .gnu.linkonce.d.*)
+	  . = ALIGN(256);
+/*          *(*COM* .bss .gnu.linkonce.b.*) */
+	} =0x60000000
+
+	.lowmem :
+	{
+	  _lowmem_start = .;
+	  *(.lowmem)
+	  _lowmem_end = .;
+	}
+
+	.got : 
+	{
+	  . = ALIGN(8);
+	  _got = .;
+          *(.got .toc)
+	  _got_end = .;
+	}  	
+	.bss :
+	{
+          *(*COM* .bss .gnu.linkonce.b.*)
+	__client_end = .;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/Makefile b/qemu-0.15.x/roms/SLOF/clients/takeover/Makefile
new file mode 100644
index 0000000..f492234
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/Makefile
@@ -0,0 +1,59 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include $(TOPCMNDIR)/make.rules
+
+SNKDIR = $(TOPCMNDIR)/clients/net-snk
+
+CFLAGS += -fno-builtin -I$(LIBCMNDIR)/libc/include
+CFLAGS += -I$(SNKDIR)/include -I. $(CPUARCHDEF)
+CFLAGS += -I$(INCLBRDDIR) -I.. -I$(INCLCMNDIR)/$(CPUARCH)
+CFLAGS += -O2 -msoft-float -Wa,-mregnames $(RELEASE)
+
+OBJS = $(SNKDIR)/kernel/kernel.o
+OBJS += $(SNKDIR)/oflib/oflib.o
+OBJS += $(SNKDIR)/libc/time/timer.o
+OBJS += $(LIBCMNDIR)/libc.a entry.o main.o of.elf takeover.o
+
+%.o: %.S
+	$(CC) $(CFLAGS) -c $^
+
+all: takeover.elf 
+
+takeover.elf: ppc32wrap.o takeover.elf32
+	@echo " ====== Building $@ ======"
+	$(LD) -N -melf32ppclinux -static -nostdlib \
+		-Ttext=0x400000 -Tdata=0x400100 \
+		$(LDFLAGS) $^ -o $@
+
+takeover.elf64: entry.o main.o takeover.o $(SNKDIR)/libc/time/timer.o of.elf
+	make -C $(LIBCMNDIR) libc
+	make -C $(CLIENTSDIR)
+	$(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS)
+
+of.elf: ../../boot_rom.bin
+	$(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf64-powerpc $< $@
+
+takeover.elf32: takeover.elf64
+	$(OBJCOPY) -O binary $^ takeover.tmp 
+	$(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf32-powerpc takeover.tmp $@
+
+ppc32wrap.o: ppc32wrap.S
+	$(CROSS)gcc -m32 -a32 $(CFLAGS) -c $< -o $@
+
+clean distclean:
+	make -C $(LIBCMNDIR) $@
+	make -C $(CLIENTSDIR) $@
+	$(RM) *.o *.bin *.elf
+	$(RM) takeover.elf32 takeover.elf64 takeover.tmp
+%.o: %.oco
+	cp -f $< $@
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/client.lds b/qemu-0.15.x/roms/SLOF/clients/takeover/client.lds
new file mode 100644
index 0000000..2701d8e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/client.lds
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+	.client 0x400100:
+	{
+	__client_start = .;
+	  *(.start)
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+          *(.rodata .rodata.* .gnu.linkonce.r.*)
+          KEEP (*(.opd))
+	  . = ALIGN(256); 
+	  *(.data .data.* .gnu.linkonce.d.*)
+	  . = ALIGN(256);
+	} =0x60000000
+
+	.diag_table :
+	{
+	  _diag_init_start = .;
+	  *(.diag_init)
+	  _diag_init_end = .;
+        }
+	.lowmem :
+	{
+	  _lowmem_start = .;
+	  *(.lowmem)
+	  _lowmem_end = .;
+	}
+
+	.got :
+	{
+	  . = ALIGN(8);
+	  _got = .;
+          *(.got .toc)
+	  _got_end = .;
+	}  	
+	.comment : { *(.comment) }
+	.branch_lt : { *(.branch_lt) }
+	.bss :
+	{
+	__bssStart = .;
+          *(*COM* .bss .gnu.linkonce.b.*)
+	__client_end = .;
+	__bssSize = . - __bssStart;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/entry.S b/qemu-0.15.x/roms/SLOF/clients/takeover/entry.S
new file mode 100644
index 0000000..ff52dc6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/entry.S
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <macros.h>
+#include "takeover.h"
+
+	.globl	_wrapclient
+	.section        ".start"
+	.align 3
+
+_wrapclient:
+	bcl	20,31,over	# branch after pointer table
+base:	
+	.align  3
+.LCgot:		.quad   _got-base+0x8000
+over:	
+	mflr	r8		# gpr 8 is the base
+	ld	r2, .LCgot-base(r8)	# load got pointer
+	add	r2, r2, r8		# add base
+	li	14, 0
+	oris	14, 14, __bssSize at h
+	ori	14, 14, __bssSize at l
+	addi 14,14,7
+	srwi 14,14,3
+	mtctr	14
+	li	14, 0
+	oris	14, 14, __bssStart at h
+	ori	14, 14, __bssStart at l
+	subi	14, 14, 8
+	li	15, 0
+1:
+	stdu 15,8(14)
+	bdnz	1b
+		
+	bl ._entry
+
+
+
+    .globl slaveLoopNoTakeover
+slaveLoopNoTakeover:
+	mr 28,3
+
+	li	14,0
+	oris	14, 14, slaveQuitt at h
+	ori	14, 14, slaveQuitt at l
+
+	li	3,0
+	std	3,0(14)
+1:
+	ld	3,0(14)
+	cmpld	3,28
+	bne	1b
+
+	li	3,0
+	std	3,0(14)
+
+	LOAD64(r3, (TAKEOVERBASEADDRESS+0x150))
+	mtctr	r3
+	bctr
+
+
+    .globl slaveLoop
+slaveLoop:
+	mr 28,3
+    	li r3, 0x5124
+    	li r0, -1; .long 0x44000022
+	
+	li	14,0
+	oris	14, 14, slaveQuitt at h
+	ori	14, 14, slaveQuitt at l
+	li	3,0
+	std	3,0(14)
+1:
+	ld	3,0(14)
+	cmpld	3,28
+	bne	1b
+
+	li	3,0
+	std	3,0(14)
+
+	LOAD64(r3, (TAKEOVERBASEADDRESS+0x150))
+	mtctr	r3
+	bctr
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/main.c b/qemu-0.15.x/roms/SLOF/clients/takeover/main.c
new file mode 100644
index 0000000..c79ea72
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/main.c
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <of.h>
+#include <pci.h>
+#include <cpu.h>
+#include <takeover.h>
+
+extern void call_client_interface(of_arg_t *);
+
+#define boot_rom_bin_start _binary_______boot_rom_bin_start
+#define boot_rom_bin_end   _binary_______boot_rom_bin_end
+
+extern char boot_rom_bin_start;
+extern char boot_rom_bin_end;
+
+#if defined(__GNUC__)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+
+/*
+ * These functions are just dummy implemented to resolve symbols for linking to other objects
+ */
+
+int
+open(const char *name UNUSED, int flags UNUSED)
+{
+	return 0;
+}
+
+int
+close(int fd UNUSED)
+{
+	return 0;
+}
+
+ssize_t
+read(int fd UNUSED, void *buf UNUSED, size_t count UNUSED)
+{
+	return 0;
+}
+
+int
+ioctl(int fd UNUSED, int req UNUSED, void *data UNUSED)
+{
+	return 0;
+}
+
+/*
+ * These functions are required for using libc.a
+ */
+ssize_t
+write(int fd, const void *buf, size_t len)
+{
+	char  dst_buf[512];
+	char *dst_buf_ptr;
+	char *src_buf_ptr;
+	int i;
+
+	src_buf_ptr = (char *) buf;
+	if (fd == 1 || fd == 2)
+	{
+		dst_buf_ptr = &dst_buf[0];
+		for (i = 0; i < len && i < 256; i++)
+		{
+			*dst_buf_ptr++ = *src_buf_ptr++;
+			if (src_buf_ptr[-1] == '\n')
+				*dst_buf_ptr++ = '\r';
+		}
+		len = dst_buf_ptr - &dst_buf[0];
+		src_buf_ptr = &dst_buf[0];
+	}
+
+	if(fd < 0 || fd >= FILEIO_MAX
+	|| fd_array[fd].type == FILEIO_TYPE_EMPTY
+	|| fd_array[fd].write == 0)
+		return -1;
+
+	return fd_array[fd].write(&fd_array[fd], src_buf_ptr, len);
+}
+
+void *
+sbrk(int incr)
+{
+	return (void *) -1;
+}
+
+void
+doWait(void)
+{
+	static const char *wheel = "|/-\\";
+	static int i = 0;
+	volatile int dly = 0xf0000;
+	while (dly--);
+	printf("\b%c", wheel[i++]);
+	i &= 0x3;
+}
+
+void
+quiesce(void)
+{
+	of_arg_t arg = {
+		p32cast "quiesce",
+		0, 0,
+	};
+	call_client_interface(&arg);
+}
+
+int
+startCpu(int num, int addr, int reg)
+{
+	of_arg_t arg = {
+		p32cast "start-cpu",
+		3, 0,
+		{num, addr, reg}
+	};
+	call_client_interface(&arg);
+	return arg.args[3];
+}
+
+volatile unsigned long slaveQuitt;
+int takeoverFlag;
+
+void
+main(int argc, char *argv[])
+{
+	phandle_t cpus;
+	phandle_t cpu;
+	unsigned long slaveMask;
+	extern int slaveLoop[];
+	extern int slaveLoopNoTakeover[];
+	int rcode;
+	int index = 0;
+	int delay = 100;
+	unsigned long reg;
+	unsigned long msr;
+	asm volatile ("mfmsr %0":"=r" (msr));
+	if (msr & 0x1000000000000000)
+		takeoverFlag = 0;
+	else
+		takeoverFlag = 1;
+
+	cpus = of_finddevice("/cpus");
+	cpu = of_child(cpus);
+	slaveMask = 0;
+	while (cpu) {
+		char devType[100];
+		*devType = '\0';
+		of_getprop(cpu, "device_type", devType, sizeof(devType));
+		if (strcmp(devType, "cpu") == 0) {
+			of_getprop(cpu, "reg", &reg, sizeof(reg));
+			if (index) {
+				printf("\r\n takeover on cpu%d (%x, %lx) ", index,
+				       cpu, reg);
+				slaveQuitt = -1;
+				if (takeoverFlag)
+					startCpu(cpu, (int)(unsigned long)slaveLoop, index);
+				else
+					startCpu(cpu, (int)(unsigned long)slaveLoopNoTakeover,
+						 index);
+				slaveMask |= 0x1 << index;
+				delay = 100;
+				while (delay-- && slaveQuitt)
+					doWait();
+			}
+			index++;
+		}
+		cpu = of_peer(cpu);
+	}
+
+
+	printf("\r\n takeover on master cpu  ");
+	quiesce();
+
+	delay = 5;
+	while (delay--)
+		doWait();
+	if (takeoverFlag)
+		rcode = takeover();
+
+	memcpy((void*)TAKEOVERBASEADDRESS, &boot_rom_bin_start, &boot_rom_bin_end - &boot_rom_bin_start);
+	flush_cache((void *)TAKEOVERBASEADDRESS, &boot_rom_bin_end - &boot_rom_bin_start);
+	index = 0;
+
+	while (slaveMask) {
+		unsigned long shifter = 0x1 << index;
+		if (shifter & slaveMask) {
+			slaveQuitt = index;
+			while (slaveQuitt);
+			slaveMask &= ~shifter;
+		}
+		index++;
+	}
+
+	asm volatile(" mtctr %0 ; bctr " : : "r" (TAKEOVERBASEADDRESS+0x180) );
+}
+
+int
+callback(int argc, char *argv[])
+{
+	/* Dummy, only for takeover */
+	return (0);
+}
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/ppc32wrap.S b/qemu-0.15.x/roms/SLOF/clients/takeover/ppc32wrap.S
new file mode 100644
index 0000000..90afa26
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/ppc32wrap.S
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+	.globl	_start
+        .section        ".text"
+        .align 3
+		
+_start:
+	nop
+	bl over
+	.llong 0x9000000000003000
+over:
+	li	14, 0
+	oris	14, 14, _binary_takeover_tmp_start at h
+	ori	14, 14, _binary_takeover_tmp_start at l
+	mtsrr0	14
+	mflr	15
+	ld	14,0(15)
+	mtsrr1	14
+	rfid
+
diff --git a/qemu-0.15.x/roms/SLOF/clients/takeover/takeover.h b/qemu-0.15.x/roms/SLOF/clients/takeover/takeover.h
new file mode 100644
index 0000000..1949f71
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/clients/takeover/takeover.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#if defined(CPU_CBEA)
+#define TAKEOVERBASEADDRESS  0x0e000000
+#elif defined(CPU_PPC970)
+#define TAKEOVERBASEADDRESS  0x00000000
+#else
+#error no processor specified
+#endif
+
+#ifndef __ASSEMBLER__
+int takeover();
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/calculatecrc.h b/qemu-0.15.x/roms/SLOF/include/calculatecrc.h
new file mode 100644
index 0000000..2168478
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/calculatecrc.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef CALCULATECRC_H
+#define CALCULATECRC_H
+
+	#define FLASHFS_DATADDR 0x18                // uint64_t position of pointer to data
+	#define FLASHFS_FILE_SIZE_ADDR 0x08         // uint64_t pos of total flashimage size value relative to data
+	#define FLASHFS_HEADER_SIZE_ADDR 0x08       // uint64_t position of total flash header size value
+
+	#ifdef __ASSEMBLER__
+		// "CRC_GENERATOR" must contain equal inforamtion as "CRC_METHODE"
+		#define CRC_GENERATOR 0x0000000004C11DB7
+		#define CRC_REGISTERMASK 0x00000000FFFFFFFF
+		#define CRC_REGISTERLENGTH 32
+	#endif		/* __ASSEMBLER__ */
+
+	#ifndef __ASSEMBLER__
+		#define FLASHFS_ROMADDR 0x00		// uint64_t position of pointer to next file
+		#define FLASHFS_HEADER_DATA_SIZE 0x68	// 104 bytes of total header data size
+		#define CRC_METHODE Ethernet_32		// define the CRc genarator (CRC 16 bit to 64 is supported)
+
+	//--- header format ---------------------------------
+		struct stH {
+				char magic[8];            // (generic!) headerfile
+				uint64_t flashlen;        // dyn
+				char version[16];         // $DRIVER_INFO alignment!
+				char platform_name[32];   // (hardware)   headerfile
+				char date[6];             // dyn (format -> JB)
+				char padding1[2];         // padding byte
+				char mdate[6];            // modify date
+				char padding2[2];         // padding byte
+				char platform_revision[4];// (hardware)   headerfile
+				uint32_t padding;
+				uint64_t ui64CRC;         // insert calculated CRC here
+				uint64_t ui64FileEnd;     // = 0xFFFF FFFF FFFF FFFF
+		};
+	#endif		/* __ASSEMBLER__ */
+
+#endif		/* CALCULATECRC_H */
+
+/*--- supported CRC Generators -------------------------
++	Name						length		usage						Generator
++	Tap_16						16 bit		Tape						0x00008005	
++	Floppy_16					16 bit		Floppy						0x00001021
++	Ethernet_32					32 bit		Ethernet					0x04C11DB7
++	SPTrEMBL_64					64 bit		white noise like date		0x0000001B
++	SPTrEMBL_improved_64   		64 bit		DNA code like date			0xAD93D23594C9362D
++	DLT1_64						64 bit		Tape						0x42F0E1EBA9EA3693
++	
++	CRC_REGISTERLENGTH 	= bit length
++	CRC_REGISTERMASK 	= -1 for a n-bit numer where n = bit length
++		example TAP_16:		CRC_REGSISTERLENGTH = 16
++							CRC_REGISTERMASK = 0xFFFFFFFF = (-1 if 16 bit number is used)
++
++	TrEMBL see also	http://www.cs.ud.ac.uk/staff/D.Jones/crcbote.pdf
++	DLT1 se also 	http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf
++--------------------------------------------------------*/
diff --git a/qemu-0.15.x/roms/SLOF/include/libelf.h b/qemu-0.15.x/roms/SLOF/include/libelf.h
new file mode 100644
index 0000000..905c76b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/libelf.h
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __LIBELF_H
+#define __LIBELF_H
+
+int load_elf_file(unsigned long *, unsigned long *);
+
+#endif				/* __LIBELF_H */
diff --git a/qemu-0.15.x/roms/SLOF/include/macros.h b/qemu-0.15.x/roms/SLOF/include/macros.h
new file mode 100644
index 0000000..f519bb8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/macros.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define LOAD64(rn,name)			\
+	lis     rn,name##@highest;	\
+	ori     rn,rn,name##@higher;	\
+	rldicr  rn,rn,32,31;		\
+	oris    rn,rn,name##@h;		\
+	ori     rn,rn,name##@l
+
+#define LOAD32(rn, name)		\
+	lis	rn,name##@h;		\
+	ori	rn,rn,name##@l
+
+// load 32 bit constant in little endian order
+#define LOAD32le(rn,name) \
+        lis     rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00));  \
+        ori     rn,rn,(((name>>24)&0x00FF)|((name>>8)&0xFF00))
+
+// load 16 bit constant in little endian order
+#define LOAD16le(rn,name) \
+        li      rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00))
+
+#define ENTRY(func_name)              \
+	.text;                        \
+	.align  2;                    \
+	.globl  .func_name;           \
+        .func_name:                   \
+	.globl  func_name;            \
+        func_name:
+
+#define C_ENTRY(func_name)			\
+	.section	".text";		\
+	.align 2;				\
+	.globl func_name;			\
+	.section	".opd","aw";		\
+	.align 3;				\
+ func_name:					\
+	.quad	.func_name,.TOC. at tocbase,0;	\
+	.previous;				\
+	.size	func_name,24;			\
+	.type	.func_name, at function;		\
+	.globl	.func_name;			\
+ .func_name:
+
+#define ASM_ENTRY(fn)	\
+	.globl	fn;	\
+fn:
+
diff --git a/qemu-0.15.x/roms/SLOF/include/memmap.h b/qemu-0.15.x/roms/SLOF/include/memmap.h
new file mode 100644
index 0000000..abf3c1f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/memmap.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef MEMMAP_H
+#define MEMMAP_H
+
+#define MEG			0x100000
+
+#define SLAVELOOP_LOADBASE	0x0000000000003f00
+#define STAGE2_LOADBASE		(60 * MEG)
+#define OF_LOADBASE		0x000000000000a000
+
+#define MEM_HALF		(512 * MEG)
+
+/* BE Engines Offsets */
+#define BE_MIC_BASE 0x50A000
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/pcd.h b/qemu-0.15.x/roms/SLOF/include/pcd.h
new file mode 100644
index 0000000..9794b76
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/pcd.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef PCD_H
+#define PCD_H
+
+#define PCD_START_ADDR 0xFF00000       // FIXME: this should not interfere with
+				       // other parts of the firmware
+#define PCD_HDR_SIZE   (6 * 8)   /* only use for ctrl file */
+
+/* PCD File Definition ****************************************/
+/* File = "p:ctrl"   0x703a6374726c0000                       */
+/* Data :                                                     */
+/* [00:07] - pointer to header of last file which was created */
+/* [08:0f] - pointer to header of next file for creation      */
+/**************************************************************/
+#define PCDF_CTRL_LAST	0
+#define PCDF_CTRL_NEXT  8
+
+/* PCD File Definition ****************************************/
+/* File = "p:pXmem"                                           */
+/* Data :                                                     */
+/* [00:07] - number of memory segments                        */
+/* [08:0f] - real base of memory segment #n                   */
+/* [10:17] - real size of memory segment #n                   */
+/* [18:1f] - real base of memory segment #n+1                 */
+/* [20:27] - real size of memory segment #n+1                 */
+/* ... and so on..                                            */
+/**************************************************************/
+#define PCDF_MEM_NUM       0
+#define PCDF_MEMN_BASE(N)  (8 + ((N) * 16))
+#define PCDF_MEMN_SIZE(M)  (PCDF_MEMN_BASE(M) + 8)
+
+/* PCD File Definition ****************************************/
+/* File = "p:pXcfg"                                           */
+/* Data :                                                     */
+/* [00:07] - number of memory segments                        */
+/* [08:0f] - real base of memory segment #n                   */
+/* [10:17] - real size of memory segment #n                   */
+/* [18:1f] - real base of memory segment #n+1                 */
+/* [20:27] - real size of memory segment #n+1                 */
+/* ... and so on..                                            */
+/**************************************************************/
+#define PCDF_PCFG_IOCBASE	(0 * 8)
+#define PCDF_PCFG_BPBASE	(1 * 8)
+#define PCDF_PCFG_SPUMAP	(2 * 8)
+#define PCDF_PCFG_TIMEBASE	(3 * 8)
+#define PCDF_PCFG_CPUFREQ   (4 * 8)
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/ppc970/cache.h b/qemu-0.15.x/roms/SLOF/include/ppc970/cache.h
new file mode 100644
index 0000000..284ebde
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/ppc970/cache.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __CACHE_H
+#define __CACHE_H
+
+#include <cpu.h>
+#include <stdint.h>
+
+#define cache_inhibited_access(type,name) 			\
+	static inline type ci_read_##name(type * addr)		\
+	{							\
+		type val;					\
+		set_ci();					\
+		val = *addr;					\
+		clr_ci();					\
+		return val;					\
+	}							\
+	static inline void ci_write_##name(type * addr, type data)	\
+	{							\
+		set_ci();					\
+		*addr = data;					\
+		clr_ci();					\
+	}
+
+cache_inhibited_access(uint8_t,  8)
+cache_inhibited_access(uint16_t, 16)
+cache_inhibited_access(uint32_t, 32)
+cache_inhibited_access(uint64_t, 64)
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/ppc970/cpu.h b/qemu-0.15.x/roms/SLOF/include/ppc970/cpu.h
new file mode 100644
index 0000000..f42fd48
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/ppc970/cpu.h
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __PPC970_H
+#define __PPC970_H
+
+/* SPRs numbers */
+
+#define CTRL_RD 136
+#define CTRL_WR 152
+#define PVR     287
+#define HSPRG0  304
+#define HSPRG1  305
+#define HIOR    311
+#define HID0    1008
+#define HID1    1009
+#define HID4    1012
+#define HID6    1017
+#define PIR     1023
+
+#define SETCI(r)	sync; \
+			mfspr	r, HID4; \
+			sync; \
+			rldicl	r, r, 32,0; \
+			ori	r, r, 0x0100; \
+			rldicl	r, r, 32,0; \
+			sync; \
+			slbia; \
+			mtspr	HID4, r; \
+			isync; \
+			eieio;
+
+#define CLRCI(r)	sync; \
+			mfspr	r, HID4; \
+			sync; \
+			rldicl	r, r, 32, 0; \
+			ori	r, r, 0x0100; \
+			xori	r, r, 0x0100; \
+			rldicl	r, r, 32, 0; \
+			sync; \
+			slbia; \
+			mtspr	HID4, r; \
+			isync; \
+			eieio;
+
+/* This macro uses r0 */
+#define FLUSH_CACHE(r, n)	add	n, n, r; \
+				addi	n, n, 127; \
+				rlwinm	r, r, 0,0,24; \
+				rlwinm	n, n, 0,0,24; \
+				sub	n, n, r; \
+				srwi	n, n, 7; \
+				mtctr	n; \
+			0:	dcbst	0, r; \
+				sync; \
+				icbi	0, r; \
+				sync; \
+				isync; \
+				addi	r, r, 128; \
+				bdnz	0b;
+
+#ifndef __ASSEMBLER__
+#define STRINGIFY(x...) #x
+#define EXPAND(x) STRINGIFY(x)
+
+static inline void
+set_ci()
+{
+	unsigned long tmp;
+	asm volatile(EXPAND(SETCI(%0)) : "=r"(tmp) :: "memory", "cc");
+}
+
+static inline void
+clr_ci()
+{
+	unsigned long tmp;
+	asm volatile(EXPAND(CLRCI(%0)) : "=r"(tmp) :: "memory", "cc");
+}
+
+static inline void
+eieio()
+{
+	asm volatile ("eieio":::"memory");
+}
+
+static inline void
+flush_cache(void* r, long n)
+{
+	asm volatile(EXPAND(FLUSH_CACHE(%0, %1)) : "+r"(r), "+r"(n) :: "memory", "cc", "r0", "ctr");
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/ppcp7/cache.h b/qemu-0.15.x/roms/SLOF/include/ppcp7/cache.h
new file mode 100644
index 0000000..ecbec1c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/ppcp7/cache.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __CACHE_H
+#define __CACHE_H
+
+#include <cpu.h>
+#include <stdint.h>
+
+// XXX FIXME: Use proper CI load/store */
+#define cache_inhibited_access(type,name) 			\
+	static inline type ci_read_##name(type * addr)		\
+	{							\
+		type val;					\
+		val = *addr;					\
+		return val;					\
+	}							\
+	static inline void ci_write_##name(type * addr, type data)	\
+	{							\
+		*addr = data;					\
+	}
+
+cache_inhibited_access(uint8_t,  8)
+cache_inhibited_access(uint16_t, 16)
+cache_inhibited_access(uint32_t, 32)
+cache_inhibited_access(uint64_t, 64)
+
+static inline uint16_t bswap16_load(uint64_t addr)
+{
+	unsigned int val;
+	asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr));
+	return val;
+}
+
+static inline uint32_t bswap32_load(uint64_t addr)
+{
+	unsigned int val;
+	asm volatile ("lwbrx %0, 0, %1":"=r" (val):"r"(addr));
+	return val;
+}
+
+static inline void bswap16_store(uint64_t addr, uint16_t val)
+{
+	asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr));
+}
+
+static inline void bswap32_store(uint64_t addr, uint32_t val)
+{
+	asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr));
+}
+
+#endif /* __CACHE_H */
+
diff --git a/qemu-0.15.x/roms/SLOF/include/ppcp7/cpu.h b/qemu-0.15.x/roms/SLOF/include/ppcp7/cpu.h
new file mode 100644
index 0000000..6de50d7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/ppcp7/cpu.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __CPU_H
+#define __CPU_H
+
+/* Used in boot_abort.S, will need something better for KVM */
+#define HSPRG0  304
+
+/* XXX FIXME: Can be more efficient, no dcbst nor loop needed on P7 */
+/* This macro uses r0 */
+#define FLUSH_CACHE(r, n)	add	n, n, r; \
+				addi	n, n, 127; \
+				rlwinm	r, r, 0,0,24; \
+				rlwinm	n, n, 0,0,24; \
+				sub	n, n, r; \
+				srwi	n, n, 7; \
+				mtctr	n; \
+			0:	dcbst	0, r; \
+				sync; \
+				icbi	0, r; \
+				sync; \
+				isync; \
+				addi	r, r, 128; \
+				bdnz	0b;
+
+#ifndef __ASSEMBLER__
+#define STRINGIFY(x...) #x
+#define EXPAND(x) STRINGIFY(x)
+
+static inline void flush_cache(void* r, long n)
+{
+	asm volatile(EXPAND(FLUSH_CACHE(%0, %1))
+		     : "+r"(r), "+r"(n)
+		     :: "memory", "cc", "r0", "ctr");
+}
+
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/romfs.h b/qemu-0.15.x/roms/SLOF/include/romfs.h
new file mode 100644
index 0000000..7228502
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/romfs.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef ROMFS_H
+#define ROMFS_H
+
+#define RFS_T_SIZE	0x00
+#define RFS_T_FLAGS	0x08
+#define RFS_T_FILEADDR	0x10
+#define RFS_T_NEXT	0x18
+#define RFS_T_NAME	0x20
+#define RFS_T_DATA	0x28
+
+#define RFS_H_NEXT	0x00
+#define RFS_H_SIZE	0x08
+#define RFS_H_FLAGS	0x10
+#define RFS_H_DATA	0x18
+#define RFS_H_NAME	0x20
+
+#define ROMFS_HDR_NEXT (0 * 8)
+#define ROMFS_HDR_LEN  (1 * 8)
+#define ROMFS_HDR_FLAG (2 * 8)
+#define ROMFS_HDR_DPTR (3 * 8)
+#define ROMFS_HDR_NAME (4 * 8)
+
+#ifndef  __ASSEMBLER__
+/* no not change except if you change romfs.S */
+struct romfs_t {
+	unsigned long	size;
+	unsigned long	flags;
+	unsigned long	fileaddr;
+	unsigned long	nexfile;
+	unsigned char	*namep;
+	unsigned char	*datap;
+};
+
+struct romfs_lookup_t {
+	unsigned long	addr_header;
+	unsigned long	addr_data;
+	unsigned long	size_data;
+	unsigned long	flags;
+};
+
+int romfs_stat(char *filename, struct romfs_t *hnd);
+
+int romfs_stat_file(char *filename, struct romfs_t *hnd);
+
+int c_romfs_lookup(char *filename, unsigned long rombase,
+		struct romfs_lookup_t *ret);
+
+#endif		/*  __ASSEMBLER__ */
+#endif		/* ROMFS_H */
diff --git a/qemu-0.15.x/roms/SLOF/include/rtas.h b/qemu-0.15.x/roms/SLOF/include/rtas.h
new file mode 100644
index 0000000..e44dedb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/rtas.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __RTAS_H
+#define __RTAS_H
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+
+typedef int rtas_arg_t;
+typedef struct {
+	int token;
+	int nargs;
+	int nret;
+	rtas_arg_t args[16];
+} rtas_args_t;
+
+#else
+
+#define RTAS_STACKSIZE 0x1000
+
+#define RTAS_PARM_0 0x0c
+#define RTAS_PARM_1 0x10
+#define RTAS_PARM_2 0x14
+#define RTAS_PARM_3 0x18
+#define RTAS_PARM_4 0x1C
+#define RTAS_PARM_5 0x20
+#define RTAS_PARM_6 0x24
+#define RTAS_PARM_7 0x28
+
+#endif		/* __ASSEMBLER__ */
+#endif		/* __RTAS_H */
diff --git a/qemu-0.15.x/roms/SLOF/include/rtas_table.h b/qemu-0.15.x/roms/SLOF/include/rtas_table.h
new file mode 100644
index 0000000..cdf9db7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/rtas_table.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __RTAS_TABLE_H
+#define __RTAS_TABLE_H
+
+
+typedef struct {
+	char *name;
+	void (*func)(rtas_args_t *args);
+	unsigned long flags;
+} rtas_funcdescr_t;
+
+
+// Flags for the RTAS table:
+#define RTAS_TBLFLG_INTERNAL 1
+
+
+extern const rtas_funcdescr_t rtas_func_tab[];
+extern const int rtas_func_tab_size;
+
+
+#endif  // __RTAS_TABLE_H
diff --git a/qemu-0.15.x/roms/SLOF/include/termctrl.h b/qemu-0.15.x/roms/SLOF/include/termctrl.h
new file mode 100644
index 0000000..502ecae
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/termctrl.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef TERMCTRL_H
+#define TERMCTRL_H
+
+/* foreground colors */
+#define TERM_FG_BLACK    ""
+#define TERM_FG_RED      ""
+#define TERM_FG_GREEN    ""
+#define TERM_FG_YELLOW   ""
+#define TERM_FG_BLUE     ""
+#define TERM_FG_MAGENTA  ""
+#define TERM_FG_CYAN     ""
+#define TERM_FG_WHITE    ""
+
+/* background colors */
+#define TERM_BG_BLACK    ""
+#define TERM_BG_RED      ""
+#define TERM_BG_GREEN    ""
+#define TERM_BG_YELLOW   ""
+#define TERM_BG_BLUE     ""
+#define TERM_BG_MAGENTA  ""
+#define TERM_BG_CYAN     ""
+#define TERM_BG_WHITE    ""
+
+/* control */
+#define TERM_CTRL_RESET      ""
+#define TERM_CTRL_BRIGHT     ""
+#define TERM_CTRL_DIM        ""
+#define TERM_CTRL_UNDERSCORE ""
+#define TERM_CTRL_BLINK      ""
+#define TERM_CTRL_REVERSE    ""
+#define TERM_CTRL_HIDDEN     ""
+#define TERM_CTRL_CLEAR      ""
+#define TERM_CTRL_HOME       ""
+
+#define TERM_CTRL_1UP        ""
+#define TERM_CTRL_1BACK      ""
+#define TERM_CTRL_SAVECRS    ""
+#define TERM_CTRL_RESTCRS    ""
+#define TERM_CTRL_CRSON      "[?25h"
+#define TERM_CTRL_CRSOFF     "[?25l"
+#define TERM_CTRL_CRSFWDN    "[%dC"
+#define TERM_CTRL_CRSX       "[%dC"
+#define TERM_CTRL_CRSY       "[%dB"
+#define TERM_CTRL_CRSXY      "[%d;%dH" /* y,x */
+
+/* keys */
+#define KEY_CTRL 0x1b
+#define KEY_UP   0x41
+#define KEY_DN   0x42
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/types.h b/qemu-0.15.x/roms/SLOF/include/types.h
new file mode 100644
index 0000000..cbadd7c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/types.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+#warning "This file is obsolete. Please use #include <stdint.h> instead."
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/include/xvect.h b/qemu-0.15.x/roms/SLOF/include/xvect.h
new file mode 100644
index 0000000..5926b18
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/include/xvect.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __XVECT_H
+#define __XVECT_H
+
+#define XVECT_M_HANDLER	0x2ff0 /* Master Handler */
+#define XVECT_S_HANDLER	0x2ff8 /* Slave Handler  */
+#define XVECT_TOPADDR   0x3fff
+#define XVECT_SLP_ENTRY SLAVELOOP_LOADBASE
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/Makefile b/qemu-0.15.x/roms/SLOF/lib/Makefile
new file mode 100644
index 0000000..ae03f8f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/Makefile
@@ -0,0 +1,35 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+SUBDIRS = libc libipmi  libbootmsg libbases  libnvram libelf libhvcall
+	
+
+all:  subdirs
+
+.PHONY : subdirs $(SUBDIRS) clean distclean
+
+
+subdirs: $(SUBDIRS)
+
+$(SUBDIRS):
+	$(MAKE) -C $@ $(MAKEARG)
+
+# Rules for making clean:
+clean:
+	@for dir in $(SUBDIRS); do \
+		$(MAKE) -C $$dir clean || exit 1; \
+	done
+
+distclean:
+	@for dir in $(SUBDIRS); do \
+		$(MAKE) -C $$dir distclean || exit 1; \
+	done
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbases/Makefile b/qemu-0.15.x/roms/SLOF/lib/libbases/Makefile
new file mode 100644
index 0000000..add4ed1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbases/Makefile
@@ -0,0 +1,40 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include
+LDFLAGS = -nostdlib
+
+all:
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+	$(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	$(RM) Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.code b/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.code
new file mode 100644
index 0000000..7dc941d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.code
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <southbridge.h>
+
+// : get-nvram-base ( -- base )
+PRIM(get_X2d_nvram_X2d_base)
+	PUSH;
+	TOS.u = SB_NVRAM_adr;
+MIRP
+
+// : get-nvram-size ( -- size )
+PRIM(get_X2d_nvram_X2d_size)
+	PUSH;
+	TOS.u = NVRAM_LENGTH;
+MIRP
+
+// : get-flash-base ( -- base )
+PRIM(get_X2d_flash_X2d_base)
+	PUSH;
+	TOS.u = SB_FLASH_adr;
+MIRP
+
+// : get-flash-size ( -- size )
+PRIM(get_X2d_flash_X2d_size)
+	PUSH;
+	TOS.u = FLASH_LENGTH;
+MIRP
+
+// : get-mbx-base ( -- base )
+PRIM(get_X2d_mbx_X2d_base)
+	PUSH;
+	TOS.u = SB_MAILBOX_adr;
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.in b/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.in
new file mode 100644
index 0000000..844a55d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbases/libbases.in
@@ -0,0 +1,17 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(get-nvram-base)
+cod(get-nvram-size)
+cod(get-flash-base)
+cod(get-flash-size)
+cod(get-mbx-base)
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbootmsg/Makefile b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/Makefile
new file mode 100644
index 0000000..891987e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/Makefile
@@ -0,0 +1,73 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include
+LDFLAGS = -nostdlib
+
+TARGET = ../libbootmsg.a
+
+
+all: $(TARGET)
+
+ifeq ($(CPUARCH),cbea)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else 
+ifeq ($(CPUARCH),ppc970)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else 
+ifeq ($(CPUARCH),p5)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+ifeq ($(CPUARCH),ppcp7)
+SRCS =
+SRCSS = bootmsg_lvl.S
+else
+SRCS = bootmsg.c
+SRCSS = 
+endif
+endif
+endif
+endif
+
+OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o)
+
+$(TARGET): $(OBJS)
+	$(AR) -rc $@ $(OBJS)
+	$(RANLIB) $@
+
+%.o: %.S
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+	$(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	$(RM) Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.code b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.code
new file mode 100644
index 0000000..ae370af
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.code
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <libbootmsg.h>
+
+// : cp ( cp-id -- )
+PRIM(bootmsg_X2d_cp)
+	int cpid = TOS.n; POP;
+	bootmsg_cp(cpid);
+MIRP
+
+// : bootmsg-warning ( cp-id lvl pstr -- )
+PRIM(bootmsg_X2d_warning)
+	char* str = TOS.a; POP;
+	short lvl = TOS.n; POP;
+	short cpid = TOS.n; POP;
+	bootmsg_warning(cpid, (const char*)str, lvl);
+MIRP
+
+// : bootmsg-error ( cp-id pstr -- )
+PRIM(bootmsg_X2d_error)
+	char* str = TOS.a; POP;
+	short cpid = TOS.n; POP;
+	bootmsg_error(cpid, (const char*)str);
+MIRP
+
+// : bootmsg-debugcp ( cp-id lvl pstr -- )
+PRIM(bootmsg_X2d_debugcp)
+	char* str = TOS.a; POP;
+	short lvl = TOS.n; POP;
+	short cpid = TOS.n; POP;
+	bootmsg_debugcp(cpid, (const char*)str, lvl);
+MIRP
+
+// : bootmsg-setlevel ( area lvl -- )
+PRIM(bootmsg_X2d_setlevel)
+	char lvl = TOS.n; POP;
+	short area = TOS.n; POP;
+	bootmsg_setlevel(area, lvl);
+MIRP
+
+// : bootmsg-checklevel ( area lvl -- [true|false] )
+PRIM(bootmsg_X2d_checklevel)
+	char lvl = TOS.n; POP;
+	short area = TOS.n; POP;
+	PUSH;
+	TOS.n = (bootmsg_checklevel(area, lvl)) ? -1 : 0;
+MIRP
+
+// : bootmsg-nvupdate ( -- )
+PRIM(bootmsg_X2d_nvupdate)
+	bootmsg_nvupdate();
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.in b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.in
new file mode 100644
index 0000000..73e01e3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg.in
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(bootmsg-cp)
+cod(bootmsg-warning)
+cod(bootmsg-error)
+cod(bootmsg-debugcp)
+cod(bootmsg-setlevel)
+cod(bootmsg-nvupdate)
+cod(bootmsg-checklevel)
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S
new file mode 100644
index 0000000..65cf0c3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S
@@ -0,0 +1,203 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#define _ASM_
+#include "macros.h"
+#include "southbridge.h"
+#include "nvramlog.h"
+
+#define bootmsg_area_size 128
+
+	.text
+	.align	3
+
+// Declare the warning level for all 128 possibilities of AC/pCKG kombinations
+	WRNG_LVL:
+	        .rept bootmsg_area_size
+		.byte 0x0
+	        .endr
+
+
+//*****************************************************************************
+// Check UserWarningLevel against SystemWarningLevel
+// input : r3=cp-id, r5=level
+// change: r6,r7
+// output: CR0 ( compared user vs system level )
+//      example:
+//              bl GET_WRNG_LVL
+//              ble print_warning
+//              bgt do_not_print_warning
+ENTRY(GET_WRNG_LVL)
+	mflr    r7                      // save linkage register
+	bl      0f                      // get current
+0:	mflr    r6                      // Instruction Address
+	mtlr    r7                      // restore linkage register
+	addi    r6,r6,WRNG_LVL-0b       // calc addr of WRNG_LVL array
+	rldic   r7,r3,56,57             // calc index into array
+	lbzux   r7,r6,r7                // read the warning level
+	cmpw    r5,r7                   // and compare it
+	blr
+
+//*****************************************************************************
+// Print CheckPoint
+// input : r3=cp-id
+// change: r3, r4, r5, r6, r7, r11
+// output: none
+ENTRY(bootmsg_cp)
+	mflr	r11
+	mr	r9, r3          // save checkpoint ID
+	li	r3, 'C'
+	bl      io_putchar      // print character
+	mr	r3, r9
+	bl      io_printhex16   // print checkpoint ID
+	.rept   5
+	li      r3,'\b'
+	bl      io_putchar      // print backspaces
+	.endr
+	mtlr	r11
+	blr
+
+//*****************************************************************************
+// Print a general BootMessage
+// input : r3=cp-id, r4=string, r5=char (type C,W,E)
+// change: r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output: none
+ENTRY(print_msg)
+	mflr	r11             // Save linkage register
+	mr	r9, r3          // Save ID
+	mr	r10, r4         // Save ptr to string
+	mr	r12, r5         // Save type (char [CWE])
+	li	r3, '\n'        // make it a new line
+	bl      io_putchar
+	li	r3, '\r'
+	bl      io_putchar
+	mr	r3, r12         // restore type
+	bl      io_putchar      // print character
+	mr	r3, r9          // restore ID
+	bl      io_printhex16   // print checkpoint ID
+	li	r3, ' '         // print a space
+	bl      io_putchar
+	mr	r3, r10         // restore ptr to string
+	bl      io_print        // print message
+	li	r3, '\n'        // add a new line
+	bl      io_putchar
+	li	r3, '\r'
+	bl      io_putchar
+	mtlr	r11             // restore linkage register
+	blr
+
+//*****************************************************************************
+// Print an Error Boot Message
+// input  : r3=cp-id, r4=string-ptr
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+ENTRY(bootmsg_error)
+	li	r5, 'E'         // E is for Error
+	b	print_msg       // and print this message
+
+//*****************************************************************************
+// Print a Warning Boot Message
+// input  : r3=cp-id, r4=string-ptr, r5=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+ENTRY(bootmsg_warning)
+	mflr	r11             // save linkage register
+	bl	GET_WRNG_LVL    // check UserLevel against SystemLevel
+	mtlr	r11             // restore linkage register
+	li	r5, 'W'         // 'W' is for Warning
+	ble     print_msg       // if UserLevel<=SystemLevel print and return
+	blr                     // else return
+
+//*****************************************************************************
+// Print a Debug Checkpoint
+// input  : r3=cp-id, r4=string-ptr, r5=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11,r12
+// output : none
+// r3=cp-id, r4=string, r5=level
+ENTRY(bootmsg_debugcp)
+	mflr	r11             // save linkage register
+	addi	r5,r5,0x20      // add checkpoint offset
+	bl	GET_WRNG_LVL    // check UserLevel against SystemLevel
+	mtlr	r11             // restore linkage register
+	li	r5, 'D'         // 'D' is for Debug CheckPoint
+	ble     print_msg       // if UserLevel<=SystemLevel print and return
+	blr                     // else return
+
+//*****************************************************************************
+// Check warning level
+// input  : r3=cp-id, r4=level
+// change : r3,r4,r5,r6,r7,r9,r10,r11
+// output : r3 (true, false)
+// r3=cp-id, r4=level
+ENTRY(bootmsg_checklevel)
+	mflr    r11
+	mr      r5, r4
+	slwi    r3, r3, 8
+	bl	GET_WRNG_LVL    // check UserLevel against SystemLevel
+	li      r3, 0           // return 0
+	bgt     0f              // IF ( UserLevel < SystemLevel )
+	li      r3, 1           // | return 1
+0:	mtlr    r11             // FI
+	blr
+
+// r3=area|pkg, r4=level
+ENTRY(bootmsg_setlevel)
+	mflr    r5
+	bl	WarningMsg	// calc current IA
+	WarningMsg:
+	mflr	r6		// get current IA
+	addi	r6,r6,WRNG_LVL-WarningMsg
+	andi.	r3, r3, 0x7F
+	add     r6,r3,r6        // address     |
+	stb     r4,0(r6)        // store level |_ stwbrx r4,r3,r6
+#ifndef DISABLE_NVRAM
+	LOAD64(r6, SB_NVRAM_FWONLY_adr + 8 )
+	add	r6,r6,r3
+	stb     r4,0(r6)
+#endif
+	mtlr    r5
+	blr
+
+ENTRY(bootmsg_nvupdate)
+#ifndef DISABLE_NVRAM
+	mflr	r10
+	LOAD64(r3, SB_NVRAM_FWONLY_adr)
+	lwz	r4, 0(r3)
+	cmpwi	r4, 0x424E                 // find bootmsg area header
+	bne	0f
+
+	LOAD64(r5, bootmsg_area_size/8)
+	mtctr	r5
+	bl	WngMsg
+	WngMsg:
+	mflr	r5
+	addi	r5,r5,WRNG_LVL-WngMsg-8
+
+1:
+	ldu	r4, 8(r3)
+	stdu	r4, 8(r5)
+	bdnz+   1b
+	b	2f
+
+0:
+	LOAD64(r5, bootmsg_area_size)
+	mtctr	r5
+	li	r4, 0x424E              // clear bootmsg log area
+	stw	r4, 0(r3)
+	li	r4, 0
+
+1:	stdu	r4, 8(r3)
+	bdnz+   1b
+
+2:                              // the end
+	mtlr	r10
+#endif
+	blr
diff --git a/qemu-0.15.x/roms/SLOF/lib/libbootmsg/libbootmsg.h b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/libbootmsg.h
new file mode 100644
index 0000000..9d0bd15
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libbootmsg/libbootmsg.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef _LIBBOOTMSG_H
+#define _LIBBOOTMSG_H
+void bootmsg_cp(short p);
+void bootmsg_error(short p, const char *str);
+void bootmsg_warning(short p, const char *str, short lvl);
+void bootmsg_debugcp(short p, const char *str, short lvl);
+void bootmsg_setlevel(short p, short level);
+int bootmsg_checklevel(short p, short level);
+void *bootmsg_nvupdate(void);
+#endif /* _LIBBOOTMSG_H */
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/Makefile b/qemu-0.15.x/roms/SLOF/lib/libc/Makefile
new file mode 100644
index 0000000..0c762ec
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/Makefile
@@ -0,0 +1,61 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+LIBCCMNDIR = $(shell pwd)
+STRINGCMNDIR = $(LIBCCMNDIR)/string
+CTYPECMNDIR = $(LIBCCMNDIR)/ctype
+STDLIBCMNDIR = $(LIBCCMNDIR)/stdlib
+STDIOCMNDIR = $(LIBCCMNDIR)/stdio
+GETOPTCMNDIR = $(LIBCCMNDIR)/getopt
+
+include $(TOPCMNDIR)/make.rules
+
+
+CPPFLAGS = -I$(LIBCCMNDIR)/include
+LDFLAGS= -nostdlib
+
+TARGET = ../libc.a
+
+
+all: $(TARGET)
+
+# Use the following target to build a native version of the lib
+# (for example for debugging purposes):
+native:
+	$(MAKE) CROSS="" CC=$(HOSTCC) NATIVEBUILD=1
+
+
+include $(STRINGCMNDIR)/Makefile.inc
+include $(CTYPECMNDIR)/Makefile.inc
+include $(STDLIBCMNDIR)/Makefile.inc
+include $(STDIOCMNDIR)/Makefile.inc
+include $(GETOPTCMNDIR)/Makefile.inc
+
+OBJS = $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) $(GETOPT_OBJS)
+
+ifneq ($(NATIVEBUILD),1)
+# These parts of the libc use assembler, so they can only be compiled when
+# we are _not_ building a native version.
+endif
+
+
+$(TARGET): $(OBJS)
+	$(AR) -rc $@ $(OBJS)
+	$(RANLIB) $@
+
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/README.txt b/qemu-0.15.x/roms/SLOF/lib/libc/README.txt
new file mode 100644
index 0000000..eaafdf4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/README.txt
@@ -0,0 +1,49 @@
+
+ Standard C library for the SLOF firmware project
+ ================================================
+
+To use this library, link your target against the "libc.a" archive.
+
+However, there are some prerequisites before you can use certain parts of the
+library:
+
+1) If you want to use malloc() and the like, you have to supply an implemen-
+   tation of sbrk() in your own code. malloc() uses sbrk() to get new, free
+   memory regions.
+   
+   Prototype:   void *sbrk(int incr);
+   Description: sbrk() increments the available data space by incr bytes and
+                returns a pointer to the start of the new area.
+   
+   See the man-page of sbrk for details about this function.
+
+2) Before you can use the stdio output functions like printf(), puts() and the
+   like, you have to provide a standard write() function in your code.
+   printf() and the like use write() to print out the strings to the standard
+   output.
+
+   Prototype:   ssize_t write(int fd, const void *buf, size_t cnt);
+   Description: Write cnt byte from the buffer buf to the stream associated
+                with the file descriptor fd.
+
+   The stdio functions will print their output to the stdout channel which is
+   assigned with the file descriptor 1 by default. Note that the stdio
+   functions will not use open() before calling write(), so if the stdout
+   cannel needs to be opened first, you should do that in your start-up code
+   before using the libc functions for the first time.
+   
+3) Before you can use the stdio input functions like scanf() and the
+   like, you have to provide a standard read() function in your code.
+   scanf() and the like use read() to get the characters from the standard
+   input.
+
+   Prototype:   ssize_t read(int fd, void *buf, size_t cnt);
+   Description: Read cnt byte from the stream associated with the file
+                descriptor fd and put them into the buffer buf.
+
+   The stdio functions will get their input from the stdin channel which is
+   assigned with the file descriptor 0 by default. Note that the stdio
+   functions will not use open() before calling read(), so if the stdin
+   cannel needs to be opened first, you should do that in your start-up code
+   before using the libc functions for the first time.
+   
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/Makefile.inc b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/Makefile.inc
new file mode 100644
index 0000000..25513a9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/Makefile.inc
@@ -0,0 +1,20 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+CTYPE_SRC_C = isdigit.c isprint.c isspace.c isxdigit.c tolower.c toupper.c
+CTYPE_SRC_ASM = 
+CTYPE_SRCS = $(CTYPE_SRC_C:%=$(CTYPECMNDIR)/%) $(CTYPE_SRC_ASM:%=$(CTYPECMNDIR)/%)
+CTYPE_OBJS = $(CTYPE_SRC_C:%.c=%.o) $(CTYPE_SRC_ASM:%.S=%.o)
+
+%.o : $(CTYPECMNDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isdigit.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isdigit.c
new file mode 100644
index 0000000..62d08a1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isdigit.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isdigit(int ch)
+{
+	switch (ch) {
+	 case '0': case '1': case '2': case '3': case '4':
+	 case '5': case '6': case '7': case '8': case '9':
+		return 1;
+	
+	 default:
+		return 0;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isprint.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isprint.c
new file mode 100644
index 0000000..c74880f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isprint.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isprint(int ch)
+{
+	return (ch >= 32 && ch < 127);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isspace.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isspace.c
new file mode 100644
index 0000000..5123019
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isspace.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isspace(int ch)
+{
+	switch (ch) {
+	 case ' ':
+	 case '\f':
+	 case '\n':
+	 case '\r':
+	 case '\t':
+	 case '\v':
+		return 1;
+	
+	 default:
+		return 0;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isxdigit.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isxdigit.c
new file mode 100644
index 0000000..9d323f3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/isxdigit.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int isxdigit(int ch)
+{
+  return ( 
+      (ch >= '0' && ch <= '9') |
+      (ch >= 'A' && ch <= 'F') |
+      (ch >= 'a' && ch <= 'f') );
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/tolower.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/tolower.c
new file mode 100644
index 0000000..f775e90
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/tolower.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <ctype.h>
+
+int tolower(int c) 
+{
+	return (((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a' ) : c);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/ctype/toupper.c b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/toupper.c
new file mode 100644
index 0000000..9bcee52
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/ctype/toupper.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "ctype.h"
+
+int toupper (int cha)
+{
+	if((cha >= 'a') && (cha <= 'z'))
+		return(cha - 'a' + 'A');
+	return(cha);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/getopt/Makefile.inc b/qemu-0.15.x/roms/SLOF/lib/libc/getopt/Makefile.inc
new file mode 100644
index 0000000..8a2e32f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/getopt/Makefile.inc
@@ -0,0 +1,17 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+GETOPT_SRC_C = getopt.c
+GETOPT_OBJS = $(GETOPT_SRC_C:%.c=%.o)
+
+%.o : $(GETOPTCMNDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/getopt/getopt.c b/qemu-0.15.x/roms/SLOF/lib/libc/getopt/getopt.c
new file mode 100644
index 0000000..be626dd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/getopt/getopt.c
@@ -0,0 +1,470 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * includes
+ *******************************************************************************
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+/*
+ * global variables, types & constants
+ * may be removed if already defined
+ *******************************************************************************
+ */
+int opterr = 1;
+int optopt = 0;
+int optind = 1;
+char *optarg = NULL;
+
+/*
+ * internal values needed by getopt
+ * DO NOT CHANGE or REMOVE
+ */
+enum {
+	OPTIONAL_ARG = 0,
+	MANDATORY_ARG = 1,
+	NO_ARG = 2
+};
+
+/*
+ * variables needed by getopt & getopt_long!
+ * DO NOT REMOVE
+ */
+static char *optstart = NULL;
+
+int
+getopt(int argc, char **argv, const char *options)
+{
+	char *optptr;
+	char *argptr;
+	int optman;
+	int idx;
+	int ret = 0;
+	int argpresent;
+
+	/*
+	 * reset used global values
+	 */
+	optopt = 0;
+	optarg = NULL;
+
+	/*
+	 * reset getopt if a new argv pointer is passed
+	 */
+	if (optstart != argv[0]) {
+		optopt = 0;
+		optind = 1;
+		optarg = NULL;
+		optstart = argv[0];
+	}
+
+	/*
+	 * return if no more arguments are available
+	 */
+	if (optind >= argc) {
+		return -1;
+	}
+
+	/*
+	 * start parsing argv[optind]
+	 */
+	idx = 0;
+
+	/*
+	 * return if the option does not begin with a '-' or has more than 2 characters
+	 */
+	if (argv[optind][idx] != '-') {
+
+		if (opterr != 0) {
+			printf("unknown option \'%s\', expecting \'-\'\n",
+			       argv[optind]);
+		}
+
+		optopt = (int) argv[optind][idx];
+		optind++;
+
+		return '?';
+	}
+
+	/*
+	 * continue to the next character in argv[optind]
+	 */
+	idx++;
+
+	/*
+	 * identify the option
+	 * make sure if an option contains a ':' to invalidate the option
+	 */
+	optptr = strchr(argv[optind], ':');
+
+	if (optptr == NULL) {
+		optptr = strchr(options, (int) argv[optind][idx]);
+	} else {
+		optptr = NULL;
+	}
+
+	/*
+	 * check whether the option is present
+	 */
+	if (optptr == NULL) {
+		/*
+		 * unknown option detected
+		 */
+		if (opterr != 0) {
+			printf("unknown option \'%s\'\n", argv[optind]);
+		}
+
+		optopt = (int) argv[optind][idx];
+		optind++;
+
+		return '?';
+	}
+
+	/*
+	 * the option is present in the option string
+	 * setup return value
+	 */
+	ret = (int) *optptr;
+
+	/*
+	 * get option argument if needed
+	 */
+	optptr++;
+
+	/*
+	 * determine between mandatory and optional argument
+	 */
+	optman = NO_ARG;
+
+	if (*optptr == ':') {
+		optman--;	// now set to MANDATORY_ARG
+	}
+
+	if (optman == MANDATORY_ARG) {
+		optptr++;
+
+		if (*optptr == ':') {
+			optman--;	// now set to OPTIONAL_ARG
+		}
+
+	}
+
+	/*
+	 * if strlen( argv[optind ) is greater than 2,
+	 * the argument is in the same argv
+	 */
+	if (strlen(argv[optind]) > 2) {
+		argptr = &argv[optind][2];
+
+		/*
+		 * do not allow '-' in an argument
+		 */
+		if (strchr(argptr, '-') != NULL) {
+
+			if (opterr != 0) {
+				printf
+				    ("illegal argument value \'%s\' for option \'-%c\'\n",
+				     argptr, ret);
+			}
+
+			optopt = ret;
+
+			return '?';
+		}
+
+	} else {
+		/*
+		 * move on to the next argv
+		 * it now either contains an argument or the next option
+		 */
+		optind++;
+
+		/*
+		 * make sure not to overflow
+		 */
+		if (optind < argc) {
+			argptr = argv[optind];
+		} else {
+			argptr = NULL;
+		}
+
+	}
+
+	/*
+	 * do the needed actions for the argument state
+	 */
+	switch (optman) {
+	case OPTIONAL_ARG:
+
+		if (argptr == NULL) {
+			break;
+		}
+
+		if (*argptr != '-') {
+			/*
+			 * argument present
+			 */
+			optarg = argptr;
+			optind++;
+
+		}
+
+
+		break;
+
+	case MANDATORY_ARG:
+		argpresent = (argptr != NULL);
+
+		if (argpresent) {
+			argpresent = (*argptr != '-');
+		}
+
+		if (argpresent) {
+			/*
+			 * argument present
+			 */
+			optarg = argptr;
+			optind++;
+		} else {
+			/*
+			 * mandatory argument missing
+			 */
+			if (opterr != 0) {
+				printf
+				    ("missing argument for option \'-%c\'\n",
+				     ret);
+			}
+
+			optopt = ret;
+
+			/*
+			 * if the first character of options is a ':'
+			 * return a ':' instead of a '?' in case of
+			 * a missing argument
+			 */
+			if (*options == ':') {
+				ret = ':';
+			} else {
+				ret = '?';
+			}
+
+		}
+
+
+		break;
+
+	case NO_ARG:
+
+		if (strlen(argv[optind - 1]) > 2) {
+
+			if (opterr != 0) {
+				printf
+				    ("too many arguments for option \'-%c\'\n",
+				     ret);
+			}
+
+			optopt = ret;
+			ret = '?';
+		}
+
+
+		break;
+
+	}
+
+	return ret;
+}
+
+int
+getopt_long(int argc, char **argv, const char *shortopts,
+	    const struct option *longopts, int *indexptr)
+{
+	struct option *optptr = (struct option *) longopts;
+	int optidx = 0;
+	int idx;
+	int ret = 0;
+	int argpresent;
+
+	/*
+	 * reset used global values
+	 */
+	optopt = 0;
+	optarg = NULL;
+
+	/*
+	 * reset indexptr
+	 */
+	*indexptr = -1;
+
+	/*
+	 * reset getopt if a new argv pointer is passed
+	 */
+	if (optstart != argv[0]) {
+		optopt = 0;
+		optind = 1;
+		optarg = NULL;
+		optstart = argv[0];
+	}
+
+	/*
+	 * return if no more arguments are available
+	 */
+	if (optind >= argc) {
+		return -1;
+	}
+
+	/*
+	 * start parsing argv[optind]
+	 */
+	idx = 0;
+
+	/*
+	 * return if the option does not begin with a '-'
+	 */
+	if (argv[optind][idx] != '-') {
+		printf("unknown option \'%s\', expecting \'-\'\n",
+		       argv[optind]);
+
+		optind++;
+
+		return '?';
+	}
+
+	/*
+	 * move on to the next character in argv[optind]
+	 */
+	idx++;
+
+	/*
+	 * return getopt() in case of a short option
+	 */
+	if (argv[optind][idx] != '-') {
+		return getopt(argc, argv, shortopts);
+	}
+
+	/*
+	 * handle a long option
+	 */
+	idx++;
+
+	while (optptr->name != NULL) {
+
+		if (strcmp(&argv[optind][idx], optptr->name) == 0) {
+			break;
+		}
+
+		optptr++;
+		optidx++;
+	}
+
+	/*
+	 * no matching option found
+	 */
+	if (optptr->name == NULL) {
+		printf("unknown option \'%s\'\n", argv[optind]);
+
+		optind++;
+
+		return '?';
+	}
+
+	/*
+	 * option was found, set up index pointer
+	 */
+	*indexptr = optidx;
+
+	/*
+	 * get argument
+	 */
+	optind++;
+
+	switch (optptr->has_arg) {
+	case no_argument:
+		/*
+		 * nothing to do
+		 */
+
+		break;
+
+	case required_argument:
+		argpresent = (optind != argc);
+
+		if (argpresent) {
+			argpresent = (argv[optind][0] != '-');
+		}
+
+		if (argpresent) {
+			/*
+			 * argument present
+			 */
+			optarg = argv[optind];
+			optind++;
+		} else {
+			/*
+			 * mandatory argument missing
+			 */
+			printf("missing argument for option \'%s\'\n",
+			       argv[optind - 1]);
+
+			ret = '?';
+		}
+
+
+		break;
+
+	case optional_argument:
+
+		if (optind == argc) {
+			break;
+		}
+
+		if (argv[optind][0] != '-') {
+			/*
+			 * argument present
+			 */
+			optarg = argv[optind];
+			optind++;
+		}
+
+
+		break;
+
+	default:
+		printf("unknown argument option for option \'%s\'\n",
+		       argv[optind - 1]);
+
+		ret = '?';
+
+		break;
+
+	}
+
+	/*
+	 * setup return values
+	 */
+	if (ret != '?') {
+
+		if (optptr->flag == NULL) {
+			ret = optptr->val;
+		} else {
+			*optptr->flag = optptr->val;
+			ret = 0;
+		}
+
+	}
+
+	return ret;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/ctype.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/ctype.h
new file mode 100644
index 0000000..9051a75
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/ctype.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+int isdigit(int c);
+int isxdigit(int c);
+int isprint(int c);
+int isspace(int c);
+
+int tolower(int c);
+int toupper(int c);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/errno.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/errno.h
new file mode 100644
index 0000000..d585934
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/errno.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+extern int errno;
+
+/*
+ * Error number definitions
+ */
+#define EPERM		1	/* not permitted */
+#define ENOENT		2	/* file or directory not found */
+#define EIO		5	/* input/output error */
+#define ENOMEM		12	/* not enough space */
+#define EACCES		13	/* permission denied */
+#define EFAULT		14	/* bad address */
+#define EBUSY		16	/* resource busy */
+#define EEXIST		17	/* file already exists */
+#define ENODEV		19	/* device not found */
+#define EINVAL		22	/* invalid argument */
+#define EDOM		33	/* math argument out of domain of func */
+#define ERANGE		34	/* math result not representable */
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/getopt.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/getopt.h
new file mode 100644
index 0000000..5956986
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/getopt.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef GETOPT_H
+#define GETOPT_H
+
+extern char *optarg;
+extern int optind;
+extern int opterr;
+extern int optopt;
+
+struct option {
+	const char *name;
+	int has_arg;
+	int *flag;
+	int val;
+};
+
+enum {
+	no_argument = 0,
+	required_argument,
+	optional_argument
+};
+
+int getopt(int argc, char **, const char *);
+int getopt_long(int argc, char **, const char *, const struct option *, int *);
+
+#endif				/* GETOPT_H */
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/limits.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/limits.h
new file mode 100644
index 0000000..4726835
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/limits.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#define 	UCHAR_MAX	255
+#define 	SCHAR_MAX	127
+#define 	SCHAR_MIN	(-128)
+
+#define 	USHRT_MAX	65535
+#define 	SHRT_MAX	32767
+#define 	SHRT_MIN	(-32768)
+
+#define 	UINT_MAX	(4294967295U)
+#define 	INT_MAX 	2147483647
+#define 	INT_MIN 	(-2147483648)
+
+#define 	ULONG_MAX	((unsigned long)-1L)
+#define 	LONG_MAX	(ULONG_MAX/2)
+#define 	LONG_MIN	((-LONG_MAX)-1)
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/stdarg.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdarg.h
new file mode 100644
index 0000000..d3d12f7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdarg.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDARG_H
+#define _STDARG_H
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v,l)  __builtin_va_start(v,l)
+#define va_arg(v,l)  __builtin_va_arg(v,l)
+#define va_end(v)  __builtin_va_end(v)
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/stddef.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/stddef.h
new file mode 100644
index 0000000..ba2d960
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/stddef.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+
+#define NULL ((void *)0)
+
+
+typedef unsigned int size_t;
+
+
+#endif
+
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/stdint.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdint.h
new file mode 100644
index 0000000..518a723
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdint.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/stdio.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdio.h
new file mode 100644
index 0000000..84cddea
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdio.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <stdarg.h>
+#include "stddef.h"
+
+#define EOF (-1)
+
+#define _IONBF 0
+#define _IOLBF 1
+#define _IOFBF 2
+#define BUFSIZ 80
+
+typedef struct {
+	int fd;
+	int mode;
+	int pos;
+	char *buf;
+	int bufsiz;
+} FILE;
+
+extern FILE stdin_data;
+extern FILE stdout_data;
+extern FILE stderr_data;
+
+#define stdin (&stdin_data)
+#define stdout (&stdout_data)
+#define stderr (&stderr_data)
+
+int fileno(FILE *stream);
+int printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
+int fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+int sprintf(char *str, const char *format, ...)  __attribute__((format (printf, 2, 3)));
+int vfprintf(FILE *stream, const char *format, va_list);
+int vsprintf(char *str, const char *format, va_list);
+int vsnprintf(char *str, size_t size, const char *format, va_list);
+void setbuf(FILE *stream, char *buf);
+int setvbuf(FILE *stream, char *buf, int mode , size_t size);
+
+int putc(int ch, FILE *stream);
+int putchar(int ch);
+int puts(char *str);
+
+int scanf(const char *format, ...)  __attribute__((format (scanf, 1, 2)));
+int fscanf(FILE *stream, const char *format, ...) __attribute__((format (scanf, 2, 3)));
+int vfscanf(FILE *stream, const char *format, va_list);
+int vsscanf(const char *str, const char *format, va_list);
+int getc(FILE *stream);
+int getchar(void);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/stdlib.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdlib.h
new file mode 100644
index 0000000..dff57f5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/stdlib.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include "stddef.h"
+
+#define RAND_MAX 32767
+
+
+void *malloc(size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+void *memalign(size_t boundary, size_t size);
+
+int atoi(const char *str);
+long atol(const char *str);
+unsigned long int strtoul(const char *nptr, char **endptr, int base);
+long int strtol(const char *nptr, char **endptr, int base);
+
+int rand(void);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/string.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/string.h
new file mode 100644
index 0000000..ebc7568
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/string.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include "stddef.h"
+
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t n);
+char *strcat(char *dest, const char *src);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(const char *s1, const char *s2, size_t n);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+size_t strlen(const char *s);
+char *strstr(const char *hay, const char *needle);
+
+void *memset(void *s, int c, size_t n);
+void *memchr(const void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/include/unistd.h b/qemu-0.15.x/roms/SLOF/lib/libc/include/unistd.h
new file mode 100644
index 0000000..f1b1c62
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/include/unistd.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+typedef long ssize_t;
+
+extern int open(const char *name, int flags);
+extern int close(int fd);
+extern ssize_t read(int fd, void *buf, size_t count);
+extern ssize_t write(int fd, const void *buf, size_t count);
+extern ssize_t lseek(int fd, long offset, int whence);
+
+extern void *sbrk(int increment);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/Makefile.inc b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/Makefile.inc
new file mode 100644
index 0000000..ac5302d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/Makefile.inc
@@ -0,0 +1,23 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STDIO_SRC_C = fscanf.c sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprintf.c \
+	      printf.c setvbuf.c putc.c puts.c putchar.c scanf.c stdchnls.c \
+	      vfscanf.c vsscanf.c fileno.c
+
+STDIO_SRC_ASM = 
+STDIO_SRCS = $(STDIO_SRC_C:%=$(STDIOCMNDIR)/%) $(STDIO_SRC_ASM:%=$(STDIOCMNDIR)/%)
+STDIO_OBJS = $(STDIO_SRC_C:%.c=%.o) $(STDIO_SRC_ASM:%.S=%.o)
+
+%.o : $(STDIOCMNDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fileno.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fileno.c
new file mode 100644
index 0000000..6e23951
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fileno.c
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+fileno(FILE *stream)
+{
+	return stream->fd;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fprintf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fprintf.c
new file mode 100644
index 0000000..866df39
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fprintf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+
+int fprintf(FILE *stream, const char* fmt, ...)
+{
+	int count;
+	va_list ap;
+    
+	va_start(ap, fmt);
+	count = vfprintf(stream, fmt, ap);
+	va_end(ap);
+    
+	return count;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fscanf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fscanf.c
new file mode 100644
index 0000000..321b163
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/fscanf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+fscanf(FILE *stream, const char *fmt, ...)
+{
+	int count;
+	va_list ap;
+
+	va_start(ap, fmt);
+	count = vfscanf(stream, fmt, ap);
+	va_end(ap);
+
+	return count;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/printf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/printf.c
new file mode 100644
index 0000000..01f4592
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/printf.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+
+int printf(const char* fmt, ...)
+{
+	int count;
+	va_list ap;
+    
+	va_start(ap, fmt);
+	count = vfprintf(stdout, fmt, ap);
+	va_end(ap);
+    
+	return count;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putc.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putc.c
new file mode 100644
index 0000000..230e9d1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putc.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "unistd.h"
+
+int
+putc(int ch, FILE *stream)
+{
+	unsigned char outchar = ch;
+
+	if (write(stream->fd, &outchar, 1) == 1)
+		return outchar;
+	else
+		return EOF;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putchar.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putchar.c
new file mode 100644
index 0000000..5c750d9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/putchar.c
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+
+
+int
+putchar(int ch)
+{
+	return putc(ch, stdout);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/puts.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/puts.c
new file mode 100644
index 0000000..3f48dbf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/puts.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+#include "string.h"
+#include "unistd.h"
+
+
+int
+puts(char *str)
+{
+	int ret;
+
+	ret = write(stdout->fd, str, strlen(str));
+	write(stdout->fd, "\r\n", 2);
+
+	return ret;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/scanf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/scanf.c
new file mode 100644
index 0000000..96b6399
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/scanf.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int
+scanf(const char *fmt, ...)
+{
+	int count;
+	va_list ap;
+
+	va_start(ap, fmt);
+	count = vfscanf(stdin, fmt, ap);
+	va_end(ap);
+
+	return count;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/setvbuf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/setvbuf.c
new file mode 100644
index 0000000..9b62dd8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/setvbuf.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+int setvbuf(FILE *stream, char *buf, int mode , size_t size)
+{
+	if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF)
+		return -1;
+	stream->buf = buf;
+	stream->mode = mode;
+	stream->bufsiz = size;
+	return 0;
+}
+
+void setbuf(FILE *stream, char *buf)
+{
+	setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/sprintf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/sprintf.c
new file mode 100644
index 0000000..9c4540e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/sprintf.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+
+
+int sprintf(char *buff, const char *format, ...)
+{
+	va_list ar;
+	int count;
+
+	if ((buff==NULL) || (format==NULL))
+		return(-1);
+
+	va_start(ar, format);
+	count = vsprintf(buff, format, ar);
+	va_end(ar);
+	
+	return(count);
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/stdchnls.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/stdchnls.c
new file mode 100644
index 0000000..41ed958
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/stdchnls.c
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdio.h"
+
+static char stdin_buffer[BUFSIZ], stdout_buffer[BUFSIZ];
+
+FILE stdin_data = { .fd = 0, .mode = _IOLBF, .pos = 0,
+		    .buf = stdin_buffer, .bufsiz = BUFSIZ };
+FILE stdout_data = { .fd = 1, .mode = _IOLBF, .pos = 0,
+		     .buf = stdout_buffer, .bufsiz = BUFSIZ };
+FILE stderr_data = { .fd = 2, .mode = _IONBF, .pos = 0,
+		     .buf = NULL, .bufsiz = 0 };
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfprintf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfprintf.c
new file mode 100644
index 0000000..765feea
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfprintf.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "unistd.h"
+
+
+int vfprintf(FILE *stream, const char *fmt, va_list ap)
+{
+	int count;
+	char buffer[320];
+
+	count = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+	write(stream->fd, buffer, count);
+
+	return count;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfscanf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfscanf.c
new file mode 100644
index 0000000..4ddd210
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vfscanf.c
@@ -0,0 +1,266 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+#include "ctype.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "unistd.h"
+
+
+static int
+_getc(FILE * stream)
+{
+	int count;
+	char c;
+
+	if (stream->mode == _IONBF || stream->buf == NULL) {
+		if (read(stream->fd, &c, 1) == 1)
+			return (int) c;
+		else
+			return EOF;
+	}
+
+	if (stream->pos == 0 || stream->pos >= BUFSIZ ||
+	    stream->buf[stream->pos] == '\0') {
+		count = read(stream->fd, stream->buf, BUFSIZ);
+		if (count < 0)
+			count = 0;
+		if (count < BUFSIZ)
+			stream->buf[count] = '\0';
+		stream->pos = 0;
+	}
+
+	return stream->buf[stream->pos++];
+}
+
+static void
+_ungetc(int ch, FILE * stream)
+{
+	if (stream->mode != _IONBF && stream->pos > 0)
+		stream->pos--;
+}
+
+static int
+_is_voidage(int ch)
+{
+	if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\0')
+		return 1;
+	else
+		return 0;
+}
+
+
+static int
+_scanf(FILE * stream, const char *fmt, va_list * ap)
+{
+	int i = 0;
+	int length = 0;
+
+	fmt++;
+
+	while (*fmt != '\0') {
+
+		char tbuf[256];
+		char ch;
+
+		switch (*fmt) {
+		case 'd':
+		case 'i':
+			ch = _getc(stream);
+			if (length == 0) {
+				while (!_is_voidage(ch) && isdigit(ch)) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			} else {
+				while (!_is_voidage(ch) && i < length
+				       && isdigit(ch)) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			}
+			/* We tried to understand what this is good for...
+			 * but we did not. We know for sure that it does not
+			 * work on SLOF if this is active. */
+			/* _ungetc(ch, stream); */
+			tbuf[i] = '\0';
+
+			/* ch = _getc(stream); */
+			if (!_is_voidage(ch))
+				_ungetc(ch, stream);
+
+			if (strlen(tbuf) == 0)
+				return 0;
+
+			*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10);
+			break;
+		case 'X':
+		case 'x':
+			ch = _getc(stream);
+			if (length == 0) {
+				while (!_is_voidage(ch) && isxdigit(ch)) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			} else {
+				while (!_is_voidage(ch) && i < length
+				       && isxdigit(ch)) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			}
+			/* _ungetc(ch, stream); */
+			tbuf[i] = '\0';
+
+			/* ch = _getc(stream); */
+			if (!_is_voidage(ch))
+				_ungetc(ch, stream);
+
+			if (strlen(tbuf) == 0)
+				return 0;
+
+			*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16);
+			break;
+		case 'O':
+		case 'o':
+			ch = _getc(stream);
+			if (length == 0) {
+				while (!_is_voidage(ch)
+				       && !(ch < '0' || ch > '7')) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			} else {
+				while (!_is_voidage(ch) && i < length
+				       && !(ch < '0' || ch > '7')) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			}
+			/* _ungetc(ch, stream); */
+			tbuf[i] = '\0';
+
+			/* ch = _getc(stream); */
+			if (!_is_voidage(ch))
+				_ungetc(ch, stream);
+
+			if (strlen(tbuf) == 0)
+				return 0;
+
+			*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8);
+			break;
+		case 'c':
+			ch = _getc(stream);
+			while (_is_voidage(ch))
+				ch = _getc(stream);
+
+			*(va_arg(*ap, char *)) = ch;
+
+			ch = _getc(stream);
+			if (!_is_voidage(ch))
+				_ungetc(ch, stream);
+
+			break;
+		case 's':
+			ch = _getc(stream);
+			if (length == 0) {
+				while (!_is_voidage(ch)) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			} else {
+				while (!_is_voidage(ch) && i < length) {
+					tbuf[i] = ch;
+					ch = _getc(stream);
+					i++;
+				}
+			}
+			/* _ungetc(ch, stream); */
+			tbuf[i] = '\0';
+
+			/* ch = _getc(stream); */
+			if (!_is_voidage(ch))
+				_ungetc(ch, stream);
+
+			strcpy(va_arg(*ap, char *), tbuf);
+			break;
+		default:
+			if (*fmt >= '0' && *fmt <= '9')
+				length += *fmt - '0';
+			break;
+		}
+		fmt++;
+	}
+
+	return 1;
+}
+
+
+
+int
+vfscanf(FILE * stream, const char *fmt, va_list ap)
+{
+	int args = 0;
+
+	while (*fmt != '\0') {
+
+		if (*fmt == '%') {
+
+			char formstr[20];
+			int i = 0;
+
+			do {
+				formstr[i] = *fmt;
+				fmt++;
+				i++;
+			} while (!
+				 (*fmt == 'd' || *fmt == 'i' || *fmt == 'x'
+				  || *fmt == 'X' || *fmt == 'p' || *fmt == 'c'
+				  || *fmt == 's' || *fmt == '%' || *fmt == 'O'
+				  || *fmt == 'o'));
+			formstr[i++] = *fmt;
+			formstr[i] = '\0';
+			if (*fmt != '%') {
+				if (_scanf(stream, formstr, &ap) <= 0)
+					return args;
+				else
+					args++;
+			}
+
+		}
+
+		fmt++;
+
+	}
+
+	return args;
+}
+
+int
+getc(FILE * stream)
+{
+	return _getc(stream);
+}
+
+int
+getchar(void)
+{
+	return _getc(stdin);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsnprintf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsnprintf.c
new file mode 100644
index 0000000..e78fb3d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsnprintf.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+const static unsigned long long convert[] = {
+	0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
+	0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
+};
+
+
+
+static int
+print_itoa(char **buffer,unsigned long value, unsigned short int base)
+{
+	const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+	static char sign = 0;
+
+	if(base <= 2 || base > 16)
+		return 0;
+
+	if(value < 0) {
+		sign = 1;
+		value *= -1;
+	}
+
+	if(value < base) {
+		if(sign) {
+			**buffer = '-';
+			*buffer += 1;
+			sign = 0;
+		}
+		**buffer = zeichen[value];
+		*buffer += 1;
+	} else {
+		print_itoa(buffer, value / base, base);
+		**buffer = zeichen[(value % base)];
+		*buffer += 1;
+	}
+
+	return 1;
+}
+
+
+static unsigned int
+print_intlen(unsigned long value, unsigned short int base)
+{
+	int i = 0;
+
+	while(value > 0) {
+		value /= base;
+		i++;
+	}
+	if(i == 0) i = 1;
+	return i;
+}
+
+
+static int
+print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen)
+{
+	int i, sizei, len;
+
+	sizei = strtoul(sizec, NULL, 10);
+ 	len = print_intlen(size, base) + optlen;
+	if(sizei > len) {
+		for(i = 0; i < (sizei - len); i++) {
+			**buffer = c;
+			*buffer += 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int
+print_format(char **buffer, const char *format, void *var)
+{
+	unsigned long start;
+	unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int);
+	unsigned long value = 0;
+	unsigned long signBit;
+	char *form, sizec[32];
+	char sign = ' ';
+
+	form  = (char *) format;
+	start = (unsigned long) *buffer;
+
+	form++;
+	if(*form == '0' || *form == '.') {
+		sign = '0';
+		form++;
+	}
+
+	while(*form != '\0') {
+		switch(*form) {
+			case 'u':
+			case 'd':
+			case 'i':
+				sizec[i] = '\0';
+				value = (unsigned long) var;
+				signBit = 0x1ULL << (length_mod * 8 - 1);
+				if (signBit & value) {
+					**buffer = '-';
+					*buffer += 1;
+					value = (-(unsigned long)value) & convert[length_mod];
+				}
+				print_fill(buffer, sizec, value, 10, sign, 0);
+				print_itoa(buffer, value, 10);
+				break;
+			case 'X':
+			case 'x':
+				sizec[i] = '\0';
+				value = (unsigned long) var & convert[length_mod];
+				print_fill(buffer, sizec, value, 16, sign, 0);
+				print_itoa(buffer, value, 16);
+				break;
+			case 'O':
+			case 'o':
+				sizec[i] = '\0';
+				value = (long int) var & convert[length_mod];
+				print_fill(buffer, sizec, value, 8, sign, 0);
+				print_itoa(buffer, value, 8);
+				break;
+			case 'p':
+				sizec[i] = '\0';
+				print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2);
+				**buffer = '0';
+				*buffer += 1;	
+				**buffer = 'x';
+				*buffer += 1;
+				print_itoa(buffer,(unsigned long) var, 16);
+				break;
+			case 'c':
+				sizec[i] = '\0';
+				print_fill(buffer, sizec, 1, 10, ' ', 0);
+				**buffer = (unsigned long) var;
+				*buffer += 1;
+				break;
+			case 's':
+				sizec[i] = '\0';
+				sizei = strtoul(sizec, NULL, 10);
+				len = strlen((char *) var);
+				if(sizei > len) {
+					for(i = 0; i < (sizei - len); i++) {
+						**buffer = ' ';
+						*buffer += 1;
+					}
+				}
+				for(i = 0; i < strlen((char *) var); i++) {
+					**buffer = ((char *) var)[i];
+					*buffer += 1;
+				}
+				break;
+			case 'l':
+				form++;
+				if(*form == 'l') {
+					length_mod = sizeof(long long int);
+				} else {
+					form--;
+					length_mod = sizeof(long int);
+				}
+				break;
+			case 'h':
+				form++;
+				if(*form == 'h') {
+					length_mod = sizeof(signed char);
+				} else {
+					form--;
+					length_mod = sizeof(short int);
+				}
+				break;
+			default:
+				if(*form >= '0' && *form <= '9')
+					sizec[i++] = *form;
+		}
+		form++;
+	}
+
+	
+	return (long int) (*buffer - start);
+}
+
+
+/*
+ * The vsnprintf function prints a formated strings into a buffer.
+ * BUG: buffer size checking does not fully work yet
+ */
+int
+vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
+{
+	char *ptr, *bstart;
+
+	bstart = buffer;
+	ptr = (char *) format;
+
+	while(*ptr != '\0' && (buffer - bstart) < bufsize)
+	{
+		if(*ptr == '%') {
+			char formstr[20];
+			int i=0;
+			
+			do {
+				formstr[i] = *ptr;
+				ptr++;
+				i++;
+			} while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X'
+						|| *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%'
+						|| *ptr == 'O' || *ptr == 'o' )); 
+			formstr[i++] = *ptr;
+			formstr[i] = '\0';
+			if(*ptr == '%') {
+				*buffer++ = '%';
+			} else {
+				print_format(&buffer, formstr, va_arg(arg, void *));
+			}
+			ptr++;
+		} else {
+
+			*buffer = *ptr;
+
+			buffer++;
+			ptr++;
+		}
+	}
+	
+	*buffer = '\0';
+
+	return (buffer - bstart);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsprintf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsprintf.c
new file mode 100644
index 0000000..0dfd737
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsprintf.c
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+
+int
+vsprintf(char *buffer, const char *format, va_list arg)
+{
+	return vsnprintf(buffer, 0x7fffffff, format, arg);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsscanf.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsscanf.c
new file mode 100644
index 0000000..b9603e9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdio/vsscanf.c
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+
+static void
+_scanf(const char **buffer, const char *fmt, va_list *ap)
+{
+	int i;
+	int length = 0;
+
+	fmt++;	
+
+	while(*fmt != '\0') {
+		
+		char tbuf[256];
+
+		switch(*fmt) {
+			case 'd':
+			case 'i':
+				if(length == 0) length = 256;
+				
+				for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+					tbuf[i] = **buffer;
+					*buffer += 1;
+				}
+				tbuf[i] = '\0';
+
+				*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10);
+				break;
+			case 'X':
+			case 'x':
+				if(length == 0) length = 256;
+				
+				for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+					tbuf[i] = **buffer;
+					*buffer += 1;
+				}
+				tbuf[i] = '\0';
+					
+				*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16);
+				break;
+			case 'O':
+			case 'o':
+				if(length == 0) length = 256;
+				
+				for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+					tbuf[i] = **buffer;
+					*buffer += 1;
+				}
+				tbuf[i] = '\0';
+
+				*(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8);
+				break;
+			case 'c':
+				*(va_arg(*ap, char *)) = **buffer;
+				*buffer += 1;
+				if(length > 1)
+					for(i = 1; i < length; i++)
+						*buffer += 1;
+				break;
+			case 's':
+				if(length == 0) length = 256;
+				
+				for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) {
+					tbuf[i] = **buffer;
+					*buffer += 1;
+				}
+
+				tbuf[i] = '\0';
+
+				strcpy(va_arg(*ap, char *), tbuf);
+				break;
+			default:
+				if(*fmt >= '0' && *fmt <= '9') 
+					length += *fmt - '0';
+				break;
+		}
+		fmt++;
+	}
+
+}
+
+
+int
+vsscanf(const char *buffer, const char *fmt, va_list ap)
+{
+
+	while(*fmt != '\0') {
+		
+		if(*fmt == '%') {
+			
+			char formstr[20];
+			int i=0;
+			
+			do {
+				formstr[i] = *fmt;
+				fmt++;
+				i++;
+			} while(!(*fmt == 'd' || *fmt == 'i' || *fmt == 'x' || *fmt == 'X'
+						|| *fmt == 'p' || *fmt == 'c' || *fmt == 's' || *fmt == '%'
+						|| *fmt == 'O' || *fmt == 'o' )); 
+			formstr[i++] = *fmt;
+			formstr[i] = '\0';
+			if(*fmt != '%') {
+				while(*buffer == ' ' || *buffer == '\t' || *buffer == '\n')
+					buffer++;
+				_scanf(&buffer, formstr, &ap);
+			}
+
+		} 
+
+		fmt++;
+
+	}
+
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/Makefile.inc b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/Makefile.inc
new file mode 100644
index 0000000..702f6d7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/Makefile.inc
@@ -0,0 +1,22 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STDLIB_SRC_C =  error.c atoi.c atol.c strtoul.c strtol.c rand.c \
+		 malloc.c memalign.c realloc.c free.c
+		
+STDLIB_SRC_ASM = 
+STDLIB_SRCS = $(STDLIB_SRC_C:%=$(STDLIBCMNDIR)/%) $(STDLIB_SRC_ASM:%=$(STDLIBCMNDIR)/%)
+STDLIB_OBJS = $(STDLIB_SRC_C:%.c=%.o) $(STDLIB_SRC_ASM:%.S=%.o)
+
+%.o : $(STDLIBCMNDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atoi.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atoi.c
new file mode 100644
index 0000000..d2fb33b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atoi.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+int atoi(const char *str)
+{
+	return strtol(str, NULL, 0);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atol.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atol.c
new file mode 100644
index 0000000..a6aa47b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/atol.c
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+long atol(const char *str)
+{
+	return strtol(str, NULL, 0);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/error.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/error.c
new file mode 100644
index 0000000..81020ca
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/error.c
@@ -0,0 +1,15 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+int errno;
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/free.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/free.c
new file mode 100644
index 0000000..9005450
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/free.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+#include "malloc_defs.h"
+
+void
+free(void *ptr)
+{
+	struct chunk *header;
+
+	header = (struct chunk *) ptr;
+	header--;
+	header->inuse = 0;
+
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc.c
new file mode 100644
index 0000000..b2a3138
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc.c
@@ -0,0 +1,157 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stddef.h"
+#include "stdlib.h"
+#include "unistd.h"
+#include "malloc_defs.h"
+
+
+static int clean(void);
+
+
+/* act points to the end of the initialized heap and the start of uninitialized heap */
+static char *act;
+
+/* Pointers to start and end of heap: */
+static char *heap_start, *heap_end;
+
+
+/*
+ * Standard malloc function
+ */
+void *
+malloc(size_t size)
+{
+	char *header;
+	void *data;
+	size_t blksize;         /* size of memory block including the chunk */
+
+	blksize = size + sizeof(struct chunk);
+
+	/* has malloc been called for the first time? */
+	if (act == 0) {
+		size_t initsize;
+		/* add some space so we have a good initial playground */
+		initsize = (blksize + 0x1000) & ~0x0fff;
+		/* get initial memory region with sbrk() */
+		heap_start = sbrk(initsize);
+		if (heap_start == (void*)-1)
+			return NULL;
+		heap_end = heap_start + initsize;
+		act = heap_start;
+	}
+
+	header = act;
+	data = act + sizeof(struct chunk);
+
+	/* Check if there is space left in the uninitialized part of the heap */
+	if (act + blksize > heap_end) {
+		//search at begin of heap
+		header = heap_start;
+
+		while ((((struct chunk *) header)->inuse != 0
+		        || ((struct chunk *) header)->length < size)
+		       && header < act) {
+			header = header + sizeof(struct chunk)
+			         + ((struct chunk *) header)->length;
+		}
+
+		// check if heap is full
+		if (header >= act) {
+			if (clean()) {
+				// merging of free blocks succeeded, so try again
+				return malloc(size);
+			} else if (sbrk(blksize) == heap_end) {
+				// succeeded to get more memory, so try again
+				heap_end += blksize;
+				return malloc(size);
+			} else {
+				// No more memory available
+				return 0;
+			}
+		}
+
+		// Check if we need to split this memory block into two
+		if (((struct chunk *) header)->length > blksize) {
+			//available memory is too big
+			int alt;
+
+			alt = ((struct chunk *) header)->length;
+			((struct chunk *) header)->inuse = 1;
+			((struct chunk *) header)->length = size;
+			data = header + sizeof(struct chunk);
+
+			//mark the rest of the heap
+			header = data + size;
+			((struct chunk *) header)->inuse = 0;
+			((struct chunk *) header)->length =
+			    alt - blksize;
+		} else {
+			//new memory matched exactly in available memory
+			((struct chunk *) header)->inuse = 1;
+			data = header + sizeof(struct chunk);
+		}
+
+	} else {
+
+		((struct chunk *) header)->inuse = 1;
+		((struct chunk *) header)->length = size;
+
+		act += blksize;
+	}
+
+	return data;
+}
+
+
+/*
+ * Merge free memory blocks in initialized heap if possible
+ */
+static int
+clean(void)
+{
+	char *header;
+	char *firstfree = 0;
+	char check = 0;
+
+	header = heap_start;
+	//if (act == 0)		// This should never happen
+	//	act = heap_end;
+
+	while (header < act) {
+
+		if (((struct chunk *) header)->inuse == 0) {
+			if (firstfree == 0) {
+				/* First free block in a row, only save address */
+				firstfree = header;
+
+			} else {
+				/* more than one free block in a row, merge them! */
+				((struct chunk *) firstfree)->length +=
+				    ((struct chunk *) header)->length +
+				    sizeof(struct chunk);
+				check = 1;
+			}
+		} else {
+			firstfree = 0;
+
+		}
+
+		header = header + sizeof(struct chunk)
+		         + ((struct chunk *) header)->length;
+
+	}
+
+	return check;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc_defs.h b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc_defs.h
new file mode 100644
index 0000000..1933026
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/malloc_defs.h
@@ -0,0 +1,16 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+struct chunk {
+	unsigned inuse : 4;
+	unsigned length : 28;
+} __attribute__((packed));
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/memalign.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/memalign.c
new file mode 100644
index 0000000..3b678aa
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/memalign.c
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+
+
+void *
+memalign(size_t blocksize, size_t bytes)
+{
+	void *x;
+
+	x = malloc(bytes + blocksize);
+	x = (void *) (((unsigned long) x + blocksize - 1) & ~(blocksize - 1));
+
+	return (void *) x;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/rand.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/rand.c
new file mode 100644
index 0000000..87e3efd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/rand.c
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+
+static unsigned long _rand = 1;
+
+int
+rand(void)
+{
+	_rand = _rand * 25364735 + 34563;
+
+	return ((unsigned int) (_rand << 16) & RAND_MAX);
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/realloc.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/realloc.c
new file mode 100644
index 0000000..652e900
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/realloc.c
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stdlib.h"
+#include "string.h"
+#include "malloc_defs.h"
+
+void *
+realloc(void *ptr, size_t size)
+{
+	struct chunk *header;
+	char *newptr, *start;
+
+	header = (struct chunk *) ptr;
+	header--;
+
+	if (size <= header->length)
+		return ptr;
+
+	newptr = (char *) malloc(size);
+	if (newptr == NULL)
+		return 0;
+
+	start = newptr;
+	memcpy((void *) newptr, (const void *) ptr, header->length);
+
+	header->inuse = 0;
+
+	return start;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtol.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtol.c
new file mode 100644
index 0000000..aae5e54
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtol.c
@@ -0,0 +1,113 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+long int strtol(const char *S, char **PTR,int BASE)
+{
+	long rval = 0;
+	short int negative = 0;
+	short int digit;
+	// *PTR is S, unless PTR is NULL, in which case i override it with my own ptr
+	char* ptr;
+	if (PTR == 0)
+	{
+		//override
+		PTR = &ptr;
+	}
+	// i use PTR to advance through the string
+	*PTR = (char *) S;
+	//check if BASE is ok
+	if ((BASE < 0) || BASE > 36)
+	{
+		return 0;
+	}
+	// ignore white space at beginning of S
+	while ((**PTR == ' ')
+			|| (**PTR == '\t')
+			|| (**PTR == '\n')
+			|| (**PTR == '\r')
+			)
+	{
+		(*PTR)++;
+	}
+	// check if S starts with "-" in which case the return value is negative
+	if (**PTR == '-')
+	{
+		negative = 1;
+		(*PTR)++;
+	}
+	// if BASE is 0... determine the base from the first chars...
+	if (BASE == 0)
+	{
+		// if S starts with "0x", BASE = 16, else 10
+		if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+		{
+			BASE = 16;
+			(*PTR)++;
+			(*PTR)++;
+		}
+		else
+		{
+			BASE = 10;
+		}
+	}
+	if (BASE == 16)
+	{
+		// S may start with "0x"
+		if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+		{
+			(*PTR)++;
+			(*PTR)++;
+		}
+	}
+	//until end of string
+	while (**PTR)
+	{
+		if (((**PTR) >= '0') && ((**PTR) <= '9'))
+		{
+			//digit (0..9)
+			digit = **PTR - '0';
+		}
+		else if (((**PTR) >= 'a') && ((**PTR) <='z'))
+		{
+			//alphanumeric digit lowercase(a (10) .. z (35) )
+			digit = (**PTR - 'a') + 10;
+		}
+		else if (((**PTR) >= 'A') && ((**PTR) <='Z'))
+		{
+			//alphanumeric digit uppercase(a (10) .. z (35) )
+			digit = (**PTR - 'A') + 10;
+		}
+		else
+		{
+			//end of parseable number reached...
+			break;
+		}
+		if (digit < BASE)
+		{
+			rval = (rval * BASE) + digit;
+		}
+		else
+		{
+			//digit found, but its too big for current base
+			//end of parseable number reached...
+			break;
+		}
+		//next...
+		(*PTR)++;
+	}
+	if (negative)
+	{
+		return rval * -1;
+	}
+	//else
+	return rval;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtoul.c b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtoul.c
new file mode 100644
index 0000000..3a86c50
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/stdlib/strtoul.c
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+unsigned long int strtoul(const char *S, char **PTR,int BASE)
+{
+	unsigned long rval = 0;
+	short int digit;
+	// *PTR is S, unless PTR is NULL, in which case i override it with my own ptr
+	char* ptr;
+	if (PTR == 0)
+	{
+		//override
+		PTR = &ptr;
+	}
+	// i use PTR to advance through the string
+	*PTR = (char *) S;
+	//check if BASE is ok
+	if ((BASE < 0) || BASE > 36)
+	{
+		return 0;
+	}
+	// ignore white space at beginning of S
+	while ((**PTR == ' ')
+			|| (**PTR == '\t')
+			|| (**PTR == '\n')
+			|| (**PTR == '\r')
+			)
+	{
+		(*PTR)++;
+	}
+	// if BASE is 0... determine the base from the first chars...
+	if (BASE == 0)
+	{
+		// if S starts with "0x", BASE = 16, else 10
+		if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+		{
+			BASE = 16;
+			(*PTR)++;
+			(*PTR)++;
+		}
+		else
+		{
+			BASE = 10;
+		}
+	}
+	if (BASE == 16)
+	{
+		// S may start with "0x"
+		if ((**PTR == '0') && (*((*PTR)+1) == 'x'))
+		{
+			(*PTR)++;
+			(*PTR)++;
+		}
+	}
+	//until end of string
+	while (**PTR)
+	{
+		if (((**PTR) >= '0') && ((**PTR) <='9'))
+		{
+			//digit (0..9)
+			digit = **PTR - '0';
+		}
+		else if (((**PTR) >= 'a') && ((**PTR) <='z'))
+		{
+			//alphanumeric digit lowercase(a (10) .. z (35) )
+			digit = (**PTR - 'a') + 10;
+		}
+		else if (((**PTR) >= 'A') && ((**PTR) <='Z'))
+		{
+			//alphanumeric digit uppercase(a (10) .. z (35) )
+			digit = (**PTR - 'A') + 10;
+		}
+		else
+		{
+			//end of parseable number reached...
+			break;
+		}
+		if (digit < BASE)
+		{
+			rval = (rval * BASE) + digit;
+		}
+		else
+		{
+			//digit found, but its too big for current base
+			//end of parseable number reached...
+			break;
+		}
+		//next...
+		(*PTR)++;
+	}
+	//done
+	return rval;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/Makefile.inc b/qemu-0.15.x/roms/SLOF/lib/libc/string/Makefile.inc
new file mode 100644
index 0000000..7ccf3c4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/Makefile.inc
@@ -0,0 +1,22 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+STRING_SRC_C = strcat.c strchr.c strcmp.c strcpy.c strlen.c strncmp.c \
+		strncpy.c strstr.c memset.c memcpy.c memmove.c memchr.c \
+		memcmp.c strcasecmp.c strncasecmp.c strtok.c
+STRING_SRC_ASM = 
+STRING_SRCS = $(STRING_SRC_C:%=$(STRINGCMNDIR)/%) $(STRING_SRC_ASM:%=$(STRINGCMNDIR)/%)
+STRING_OBJS = $(STRING_SRC_C:%.c=%.o) $(STRING_SRC_ASM:%.S=%.o)
+
+%.o : $(STRINGCMNDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/memchr.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/memchr.c
new file mode 100644
index 0000000..c3fe751
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/memchr.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+void *
+memchr(const void *ptr, int c, size_t n)
+{
+	unsigned char ch = (unsigned char)c;
+	const unsigned char *p = ptr;
+
+	while (n-- > 0) {
+		if (*p == ch)
+			return (void *)p;
+		p += 1;
+	}
+
+	return NULL;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/memcmp.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/memcmp.c
new file mode 100644
index 0000000..3b69cef
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/memcmp.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+int
+memcmp(const void *ptr1, const void *ptr2, size_t n)
+{
+	const unsigned char *p1 = ptr1;
+	const unsigned char *p2 = ptr2;
+
+	while (n-- > 0) {
+		if (*p1 != *p2)
+			return (*p1 - *p2);
+		p1 += 1;
+		p2 += 1;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/memcpy.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/memcpy.c
new file mode 100644
index 0000000..00f419b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/memcpy.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+void *
+memcpy(void *dest, const void *src, size_t n)
+{
+	char *cdest;
+	const char *csrc = src;
+
+	cdest = dest;
+	while (n-- > 0) {
+		*cdest++ = *csrc++;
+	}
+
+	return dest;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/memmove.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/memmove.c
new file mode 100644
index 0000000..3acf1a9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/memmove.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+
+void *
+memmove(void *dest, const void *src, size_t n)
+{
+	char *cdest;
+	const char *csrc;
+	int i;
+
+	/* Do the buffers overlap in a bad way? */
+	if (src < dest && src + n >= dest) {
+		/* Copy from end to start */
+		cdest = dest + n - 1;
+		csrc = src + n - 1;
+		for (i = 0; i < n; i++) {
+			*cdest-- = *csrc--;
+		}
+	}
+	else {
+		/* Normal copy is possible */
+		cdest = dest;
+		csrc = src;
+		for (i = 0; i < n; i++) {
+			*cdest++ = *csrc++;
+		}
+	}
+
+	return dest;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/memset.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/memset.c
new file mode 100644
index 0000000..f8dfbf5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/memset.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "string.h"
+
+void *
+memset(void *dest, int c, size_t size)
+{
+	unsigned char *d = (unsigned char *)dest;
+
+	while (size-- > 0) {
+		*d++ = (unsigned char)c;
+	}
+
+	return dest;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strcasecmp.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcasecmp.c
new file mode 100644
index 0000000..f75294f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcasecmp.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+	while (*s1 != 0 && *s2 != 0) {
+		if (toupper(*s1) != toupper(*s2))
+			break;
+		++s1;
+		++s2;
+	}
+
+	return *s1 - *s2;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strcat.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcat.c
new file mode 100644
index 0000000..eb597a0
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcat.c
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strcat(char *dst, const char *src)
+{
+	int p;
+
+	p = strlen(dst);
+	strcpy(&dst[p], src);
+
+	return dst;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strchr.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strchr.c
new file mode 100644
index 0000000..528a319
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strchr.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strchr(const char *s, int c)
+{
+	char cb = c;
+
+	while (*s != 0) {
+		if (*s == cb) {
+			return (char *)s;
+		}
+		s += 1;
+	}
+
+	return NULL;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strcmp.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcmp.c
new file mode 100644
index 0000000..48eaed2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcmp.c
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+
+int
+strcmp(const char *s1, const char *s2)
+{
+	while (*s1 != 0 && *s2 != 0) {
+		if (*s1 != *s2)
+			break;
+		s1 += 1;
+		s2 += 1;
+	}
+
+	return *s1 - *s2;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strcpy.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcpy.c
new file mode 100644
index 0000000..48eb62c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strcpy.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strcpy(char *dst, const char *src)
+{
+	char *ptr = dst;
+
+	do {
+		*ptr++ = *src;
+	} while (*src++ != 0);
+
+	return dst;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strlen.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strlen.c
new file mode 100644
index 0000000..37a1b78
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strlen.c
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+size_t
+strlen(const char *s)
+{
+	int len = 0;
+
+	while (*s != 0) {
+		len += 1;
+		s += 1;
+	}
+
+	return len;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strncasecmp.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncasecmp.c
new file mode 100644
index 0000000..4140931
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncasecmp.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <ctype.h>
+
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	if (n < 1)
+		return 0;
+
+	while (*s1 != 0 && *s2 != 0 && --n > 0) {
+		if (toupper(*s1) != toupper(*s2))
+			break;
+		++s1;
+		++s2;
+	}
+
+	return toupper(*s1) - toupper(*s2);
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strncmp.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncmp.c
new file mode 100644
index 0000000..a886736
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncmp.c
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+	if (n < 1)
+		return 0;
+
+	while (*s1 != 0 && *s2 != 0 && --n > 0) {
+		if (*s1 != *s2)
+			break;
+		s1 += 1;
+		s2 += 1;
+	}
+
+	return *s1 - *s2;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strncpy.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncpy.c
new file mode 100644
index 0000000..0f41f93
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strncpy.c
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strncpy(char *dst, const char *src, size_t n)
+{
+	char *ret = dst;
+
+	/* Copy string */
+	while (*src != 0 && n > 0) {
+		*dst++ = *src++;
+		n -= 1;
+	}
+
+	/* strncpy always clears the rest of destination string... */
+	while (n > 0) {
+		*dst++ = 0;
+		n -= 1;
+	}
+
+	return ret;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strstr.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strstr.c
new file mode 100644
index 0000000..3e090d2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strstr.c
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strstr(const char *hay, const char *needle)
+{
+	char *pos;
+	int hlen, nlen;
+
+	if (hay == NULL || needle == NULL)
+		return NULL;
+	
+	hlen = strlen(hay);
+	nlen = strlen(needle);
+	if (nlen < 1)
+		return (char *)hay;
+
+	for (pos = (char *)hay; pos < hay + hlen; pos++) {
+		if (strncmp(pos, needle, nlen) == 0) {
+			return pos;
+		}
+	}
+
+	return NULL;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libc/string/strtok.c b/qemu-0.15.x/roms/SLOF/lib/libc/string/strtok.c
new file mode 100644
index 0000000..665c08d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libc/string/strtok.c
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+
+char *
+strtok(char *src, const char *pattern)
+{
+	static char *nxtTok;
+	char *retVal = NULL;
+
+	if (!src)
+		src = nxtTok;
+
+	while (*src) {
+		const char *pp = pattern;
+		while (*pp) {
+			if (*pp == *src) {
+				break;
+			}
+			pp++;
+		}
+		if (!*pp) {
+			if (!retVal)
+				retVal = src;
+			else if (!src[-1])
+				break;
+		} else
+			*src = '\0';
+		src++;
+	}
+
+	nxtTok = src;
+
+	return retVal;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libelf/Makefile b/qemu-0.15.x/roms/SLOF/lib/libelf/Makefile
new file mode 100644
index 0000000..82ef0bb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libelf/Makefile
@@ -0,0 +1,47 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS= -nostdlib
+
+TARGET = ../libelf.a
+
+all: $(TARGET)
+
+SRCS = elf.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+	$(AR) -rc $@ $(OBJS)
+	$(RANLIB) $@
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+	$(RM) Makefile.dep
+
+# Rules for creating the dependency file:
+depend:
+	$(RM) Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu-0.15.x/roms/SLOF/lib/libelf/elf.c b/qemu-0.15.x/roms/SLOF/lib/libelf/elf.c
new file mode 100644
index 0000000..359f628
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libelf/elf.c
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* this is elf.fs rewritten in C */
+
+#include <string.h>
+#include <cpu.h>
+#include <libelf.h>
+
+struct ehdr {
+	unsigned int ei_ident;
+	unsigned char ei_class;
+	unsigned char ei_data;
+	unsigned char ei_version;
+	unsigned char ei_pad[9];
+	unsigned short e_type;
+	unsigned short e_machine;
+	unsigned int e_version;
+	unsigned int e_entry;
+	unsigned int e_phoff;
+	unsigned int e_shoff;
+	unsigned int e_flags;
+	unsigned short e_ehsize;
+	unsigned short e_phentsize;
+	unsigned short e_phnum;
+	unsigned short e_shentsize;
+	unsigned short e_shnum;
+	unsigned short e_shstrndx;
+};
+
+struct phdr {
+	unsigned int p_type;
+	unsigned int p_offset;
+	unsigned int p_vaddr;
+	unsigned int p_paddr;
+	unsigned int p_filesz;
+	unsigned int p_memsz;
+	unsigned int p_flags;
+	unsigned int p_align;
+};
+
+struct ehdr64 {
+	unsigned int ei_ident;
+	unsigned char ei_class;
+	unsigned char ei_data;
+	unsigned char ei_version;
+	unsigned char ei_pad[9];
+	unsigned short e_type;
+	unsigned short e_machine;
+	unsigned int e_version;
+	unsigned long e_entry;
+	unsigned long e_phoff;
+	unsigned long e_shoff;
+	unsigned int e_flags;
+	unsigned short e_ehsize;
+	unsigned short e_phentsize;
+	unsigned short e_phnum;
+	unsigned short e_shentsize;
+	unsigned short e_shnum;
+	unsigned short e_shstrndx;
+};
+
+struct phdr64 {
+	unsigned int p_type;
+	unsigned int p_flags;
+	unsigned long p_offset;
+	unsigned long p_vaddr;
+	unsigned long p_paddr;
+	unsigned long p_filesz;
+	unsigned long p_memsz;
+	unsigned long p_align;
+};
+
+#define VOID(x) (void *)((unsigned long)x)
+
+static void
+load_segment(unsigned long *file_addr, struct phdr *phdr)
+{
+	unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+	/* copy into storage */
+	memmove(VOID(phdr->p_vaddr), VOID(src), phdr->p_filesz);
+
+	/* clear bss */
+	memset(VOID(phdr->p_vaddr + phdr->p_filesz), 0,
+	       phdr->p_memsz - phdr->p_filesz);
+
+	if (phdr->p_memsz) {
+		flush_cache(VOID(phdr->p_vaddr), phdr->p_memsz);
+	}
+}
+
+static unsigned int
+load_segments(unsigned long *file_addr)
+{
+	struct ehdr *ehdr = (struct ehdr *) file_addr;
+	/* Calculate program header address */
+	struct phdr *phdr =
+	    (struct phdr *) (((unsigned char *) file_addr) + ehdr->e_phoff);
+	int i;
+	/* loop e_phnum times */
+	for (i = 0; i <= ehdr->e_phnum; i++) {
+		/* PT_LOAD ? */
+		if (phdr->p_type == 1) {
+			/* copy segment */
+			load_segment(file_addr, phdr);
+		}
+		/* step to next header */
+		phdr =
+		    (struct phdr *) (((unsigned char *) phdr) +
+				     ehdr->e_phentsize);
+	}
+	return ehdr->e_entry;
+}
+
+static void
+load_segment64(unsigned long *file_addr, struct phdr64 *phdr64)
+{
+	unsigned long src = phdr64->p_offset + (unsigned long) file_addr;
+	/* copy into storage */
+	memmove(VOID(phdr64->p_vaddr), VOID(src), phdr64->p_filesz);
+
+	/* clear bss */
+	memset(VOID(phdr64->p_vaddr + phdr64->p_filesz), 0,
+	       phdr64->p_memsz - phdr64->p_filesz);
+
+	if (phdr64->p_memsz) {
+		flush_cache(VOID(phdr64->p_vaddr), phdr64->p_memsz);
+	}
+}
+
+static unsigned long
+load_segments64(unsigned long *file_addr)
+{
+	struct ehdr64 *ehdr64 = (struct ehdr64 *) file_addr;
+	/* Calculate program header address */
+	struct phdr64 *phdr64 =
+	    (struct phdr64 *) (((unsigned char *) file_addr) + ehdr64->e_phoff);
+	int i;
+	/* loop e_phnum times */
+	for (i = 0; i <= ehdr64->e_phnum; i++) {
+		/* PT_LOAD ? */
+		if (phdr64->p_type == 1) {
+			/* copy segment */
+			load_segment64(file_addr, phdr64);
+		}
+		/* step to next header */
+		phdr64 =
+		    (struct phdr64 *) (((unsigned char *) phdr64) +
+				       ehdr64->e_phentsize);
+	}
+	return ehdr64->e_entry;
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x)  (x)
+#else
+#define cpu_to_be32(x)  bswap_32(x)
+#endif
+
+/**
+ * elf_check_file tests if the file at file_addr is
+ * a correct endian, ELF PPC executable
+ * @param file_addr  pointer to the start of the ELF file
+ * @return           the class (1 for 32 bit, 2 for 64 bit)
+ *                   -1 if it is not an ELF file
+ *                   -2 if it has the wrong endianess
+ *                   -3 if it is not an ELF executable
+ *                   -4 if it is not for PPC
+ */
+static int
+elf_check_file(unsigned long *file_addr)
+{
+	struct ehdr *ehdr = (struct ehdr *) file_addr;
+	/* check if it is an ELF image at all */
+	if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
+		return -1;
+
+	/* endian check */
+#if __BYTE_ORDER == __BIG_ENDIAN
+	if (ehdr->ei_data != 2)
+		/* not a big endian image */
+#else
+	if (ehdr->ei_data == 2)
+		/* not a little endian image */
+#endif
+		return -2;
+
+	/* check if it is an ELF executable */
+	if (ehdr->e_type != 2)
+		return -3;
+
+	/* check if it is a PPC ELF executable */
+	if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
+		return -4;
+
+	return ehdr->ei_class;
+}
+
+/**
+ * load_elf_file tries to load the ELF file specified in file_addr
+ *
+ * it first checks if the file is a PPC ELF executable and then loads
+ * the segments depending if it is a 64bit or 32 bit ELF file
+ *
+ * @param file_addr  pointer to the start of the elf file
+ * @param entry      pointer where the ELF loader will store
+ *                   the entry point
+ * @return           1 for a 32 bit file
+ *                   2 for a 64 bit file
+ *                   anything else means an error during load
+ */
+int
+load_elf_file(unsigned long *file_addr, unsigned long *entry)
+{
+	int type = elf_check_file(file_addr);
+	switch (type) {
+	case 1:
+		*entry = load_segments(file_addr);
+		break;
+	case 2:
+		*entry = load_segments64(file_addr);
+		break;
+	}
+	return type;
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.code b/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.code
new file mode 100644
index 0000000..6e019fc
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.code
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+int load_elf_file(unsigned long *file_addr, unsigned long *entry);
+
+PRIM(LOADELF)
+	void *file_addr = TOS.a;
+	int type;
+	unsigned long entry;
+	type = load_elf_file(file_addr, &entry);
+	TOS.u = entry;
+	PUSH; TOS.n = type;
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.in b/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.in
new file mode 100644
index 0000000..1fea40c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libelf/libelf.in
@@ -0,0 +1,12 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+cod(LOADELF)
diff --git a/qemu-0.15.x/roms/SLOF/lib/libhvcall/Makefile b/qemu-0.15.x/roms/SLOF/lib/libhvcall/Makefile
new file mode 100644
index 0000000..41ee633
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libhvcall/Makefile
@@ -0,0 +1,53 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include
+LDFLAGS = -nostdlib
+
+TARGET = ../libhvcall.a
+
+
+all: $(TARGET)
+
+SRCSS = hvcall.S
+
+
+OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o)
+
+$(TARGET): $(OBJS)
+	$(AR) -rc $@ $(OBJS)
+	$(RANLIB) $@
+
+%.o: %.S
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+	$(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	$(RM) Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.S b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.S
new file mode 100644
index 0000000..5cc0bd7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.S
@@ -0,0 +1,86 @@
+#define _ASM
+#define __ASSEMBLY__
+#include "macros.h"
+#include "libhvcall.h"
+	
+#define HVCALL			.long 0x44000022
+	
+	.text
+	.align	3
+
+ENTRY(hv_generic)
+	HVCALL
+	blr
+
+ENTRY(hv_putchar)
+	sldi	r6,r3,(24+32)
+	li	r3,H_PUT_TERM_CHAR
+	li	r4,0
+	li	r5,1
+	HVCALL
+	blr
+
+ENTRY(hv_getchar)
+	mflr	r10
+	bl	.hv_haschar
+	mtlr	r10
+	cmpwi	cr0,r3,0
+	beqlr
+	lis	r9,inbuf at h
+	ori	r9,r9,inbuf at l
+	lwz	r4,20(r9)
+	lbzx	r3,r4,r9
+	addi	r4,r4,1
+	stw	r4,20(r9)
+	blr
+
+ENTRY(hv_haschar)
+	li	r3,-1
+	lis	r9,inbuf at h
+	ori	r9,r9,inbuf at l
+	lwz	r5,16(r9)
+	lwz	r6,20(r9)
+	cmplw	cr0,r5,r6
+	bnelr
+	li	r3,H_GET_TERM_CHAR
+	li	r4,0
+	HVCALL
+	lis	r9,inbuf at h
+	ori	r9,r9,inbuf at l
+	stw	r4,16(r9)
+	li	r3,0
+	stw	r3,20(r9)
+	cmplwi	cr0,r4,0
+	beqlr
+	li	r3,-1
+	std	r5,0(r9)
+	std	r6,8(r9)
+	blr
+
+ENTRY(hv_send_crq)
+	ld	r5,0(r4)
+	ld	r6,8(r4)
+	mr	r4,r3
+	li	r3,H_SEND_CRQ
+	HVCALL
+	blr
+
+ENTRY(hv_send_logical_lan)
+	li	r11,0	/* no continue token for now */
+	mr	r10,r9
+	mr	r9,r8
+	mr	r8,r7
+	mr	r7,r6
+	mr	r6,r5
+	mr	r5,r4
+	mr	r4,r3
+	li	r3,H_SEND_LOGICAL_LAN
+	HVCALL
+	blr
+
+	.section ".bss"
+ inbuf:	.space	16
+inlen:	.space	4
+inpos:	.space	4
+	.text
+	
\ No newline at end of file
diff --git a/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.code b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.code
new file mode 100644
index 0000000..4e47c06
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.code
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <libhvcall.h>
+
+// : hv-putchar ( char -- )
+PRIM(hv_X2d_putchar)
+	char c = TOS.n; POP;
+	hv_putchar(c);
+MIRP
+
+// : hv-getchar ( -- char )
+PRIM(hv_X2d_getchar)
+	PUSH;
+	TOS.n = hv_getchar();
+MIRP
+
+// : hv-haschar ( -- res )
+PRIM(hv_X2d_haschar)
+	PUSH;
+	TOS.n = hv_haschar();
+MIRP
+
+// : hv-reg-crq ( unit qaddr qsize -- res )
+PRIM(hv_X2d_reg_X2d_crq)
+	unsigned long qsize = TOS.u; POP;
+	unsigned long qaddr = TOS.u; POP;
+	unsigned int unit = TOS.u;
+	TOS.n = hv_reg_crq(unit, qaddr, qsize);
+MIRP
+
+// : hv-free-crq ( unit -- )
+PRIM(hv_X2d_free_X2d_crq)
+	unsigned int unit = TOS.u; POP;
+	hv_free_crq(unit);
+MIRP
+
+// : hv-send-crq ( unit msgaddr -- rc )
+PRIM(hv_X2d_send_X2d_crq)
+	uint64_t *msgaddr = (uint64_t *)TOS.u; POP;
+	unsigned int unit = TOS.u;
+	TOS.n = hv_send_crq(unit, msgaddr);
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.in b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.in
new file mode 100644
index 0000000..827aed4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libhvcall/hvcall.in
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(hv-putchar)
+cod(hv-getchar)
+cod(hv-haschar)
+cod(hv-reg-crq)
+cod(hv-free-crq)
+cod(hv-send-crq)
diff --git a/qemu-0.15.x/roms/SLOF/lib/libhvcall/libhvcall.h b/qemu-0.15.x/roms/SLOF/lib/libhvcall/libhvcall.h
new file mode 100644
index 0000000..db1d890
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libhvcall/libhvcall.h
@@ -0,0 +1,65 @@
+#ifndef __LIBHVCALL_H__
+#define __LIBHVCALL_H__
+
+#define H_SUCCESS		0
+
+#define H_GET_TERM_CHAR		0x54
+#define H_PUT_TERM_CHAR		0x58
+#define H_REG_CRQ		0xFC
+#define H_FREE_CRQ		0x100
+#define H_SEND_CRQ		0x108
+#define H_REGISTER_LOGICAL_LAN	0x114
+#define H_FREE_LOGICAL_LAN	0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN	0x120
+
+#ifndef __ASSEMBLY__
+
+extern long hv_generic(unsigned long opcode, ...);
+
+extern void hv_putchar(char c);
+extern char hv_getchar(void);
+extern char hv_haschar(void);
+
+extern int hv_send_crq(unsigned int unit, uint64_t *msgaddr);
+
+static inline long hv_reg_crq(unsigned int unit, unsigned long qaddr,
+			      unsigned long qsize)
+{
+	return hv_generic(H_REG_CRQ, unit, qaddr, qsize);
+}
+
+static inline void hv_free_crq(unsigned int unit)
+{
+	hv_generic(H_FREE_CRQ, unit);
+}
+
+extern long  hv_send_logical_lan(unsigned long unit_address,
+				 unsigned long desc1, unsigned long desc2,
+				 unsigned long desc3, unsigned long desc4,
+				 unsigned long desc5, unsigned long desc6);
+
+static inline long h_register_logical_lan(unsigned long unit_address,
+					  unsigned long buf_list,
+					  unsigned long rec_q,
+					  unsigned long filter_list,
+					  unsigned long mac_address)
+{
+	return hv_generic(H_REGISTER_LOGICAL_LAN, unit_address,
+			  buf_list, rec_q, filter_list, mac_address);
+}
+
+static inline long h_free_logical_lan(unsigned long unit_address)
+{
+	return hv_generic(H_FREE_LOGICAL_LAN, unit_address);
+}
+
+static inline long h_add_logical_lan_buffer(unsigned long unit_address,
+					    unsigned long buffer)
+{
+	return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __LIBHVCALL_H__ */
diff --git a/qemu-0.15.x/roms/SLOF/lib/libipmi/Makefile b/qemu-0.15.x/roms/SLOF/lib/libipmi/Makefile
new file mode 100644
index 0000000..4777f9e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libipmi/Makefile
@@ -0,0 +1,28 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+LIBIPMICMNDIR = $(shell pwd)
+
+include $(TOPCMNDIR)/make.rules
+
+TARGET = ../libipmi.a
+
+all: $(TARGET)
+
+$(TARGET):
+	cp libipmi.oco $@
+
+clean:
+
+distclean:
diff --git a/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.code b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.code
new file mode 100644
index 0000000..59c1244
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.code
@@ -0,0 +1,120 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <libipmi.h>
+
+// : ipmi-kcs-cmd  ( in-buf in-len out-buf out-maxlen -- out-len errorcode )
+PRIM(IPMI_X2d_KCS_X2d_CMD)
+	cell maxlen = TOS; POP;
+	cell outbuf = TOS; POP;
+	int len = TOS.n; POP;
+	cell inbuf = TOS;
+	int retval;
+	retval = ipmi_kcs_cmd(inbuf.a, outbuf.a, maxlen.n, (uint32_t *) &len);
+	TOS.n = len;
+	PUSH; TOS.n = retval;
+MIRP
+
+
+PRIM(IPMI_X2d_SYSTEM_X2d_REBOOT)
+	ipmi_system_reboot();
+MIRP
+
+
+PRIM(IPMI_X2d_POWER_X2d_OFF)
+	ipmi_power_off();
+MIRP
+
+
+// : ipmi-oem-stop-bootwatchdog  ( -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_STOP_X2d_BOOTWATCHDOG)
+	PUSH;
+	TOS.n = ipmi_oem_stop_bootwatchdog();
+MIRP
+
+
+// : ipmi-oem-set-bootwatchdog  ( seconds -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_SET_X2d_BOOTWATCHDOG)
+	int sec = TOS.n;
+	TOS.n = ipmi_oem_set_bootwatchdog(sec);
+MIRP
+
+
+// : ipmi-oem-reset-bootwatchdog  ( -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_RESET_X2d_BOOTWATCHDOG)
+	PUSH;
+	TOS.n = ipmi_oem_reset_bootwatchdog();
+MIRP
+
+
+// : ipmi-oem-led-set  ( type instance state -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_LED_X2d_SET)
+	int state = TOS.n; POP;
+	int instance = TOS.n; POP;
+	int type = TOS.n;
+	TOS.n = ipmi_oem_led_set(type, instance, state);
+MIRP
+
+
+// : ipmi-oem-read-vpd  ( offset length dst -- status )
+PRIM(IPMI_X2d_OEM_X2d_READ_X2d_VPD)
+	cell dest = TOS; POP;
+	int len = TOS.n; POP;
+	int offset = TOS.n;
+	TOS.n = ipmi_oem_read_vpd(dest.a, len, offset);
+MIRP
+
+// : ipmi-oem-write-vpd  ( offset length src -- status )
+PRIM(IPMI_X2d_OEM_X2d_WRITE_X2d_VPD)
+	cell src = TOS; POP;
+	int len = TOS.n; POP;
+	int offset = TOS.n;
+	TOS.n = ipmi_oem_write_vpd(src.a, len, offset);
+MIRP
+
+
+// : ipmi-oem-get-blade-descr  ( buf maxlen -- len status )
+PRIM(IPMI_X2d_OEM_X2d_GET_X2d_BLADE_X2d_DESCR)
+	int maxlen = TOS.n; POP;
+	cell buf = TOS;
+	int len = 0;
+	int retval;
+	retval = ipmi_oem_get_blade_descr(buf.a, maxlen, (uint32_t *) &len);
+	TOS.n = len;
+	PUSH; TOS.n = retval;
+MIRP
+
+
+// : ipmi-oem-bios2sp  ( str-ptr str-len swid type -- errorcode )
+PRIM(IPMI_X2d_OEM_X2d_BIOS2SP)
+	int type = TOS.n; POP;
+	int swid = TOS.n; POP;
+	int len = TOS.n; POP;
+	void* addr = TOS.a;
+	TOS.n = ipmi_oem_bios2sp(swid, type, addr, len);
+MIRP
+
+// : ipmi-set-sensor ( param-1 ... param-n n command sensor - errorcode )
+PRIM(IPMI_X2d_SET_X2d_SENSOR)
+	int sensor = TOS.n; POP;
+	int cmd    = TOS.n; POP;
+	int n      = TOS.n;
+	int i      = n;
+	uint8_t param[10];
+	while (i>0) {
+		i--;
+		POP; param[i]=TOS.n;
+	};
+	TOS.n = ipmi_set_sensor((cmd<<8)+sensor,n,
+		param[0],param[1],param[2],param[3],param[4],
+		param[5],param[6],param[7],param[8],param[9]);
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.h b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.h
new file mode 100644
index 0000000..9ac8308
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __LIBIPMI_H
+#define __LIBIPMI_H
+
+#include <stdint.h>
+
+extern int ipmi_kcs_cmd(uint8_t *, uint8_t *, uint32_t, uint32_t *);
+
+extern void ipmi_system_reboot(void);
+extern void ipmi_power_off(void);
+extern int ipmi_set_sensor(const int sensor, int number_of_args, ...);
+
+extern int ipmi_oem_stop_bootwatchdog(void);
+extern int ipmi_oem_set_bootwatchdog(uint16_t seconds);
+extern int ipmi_oem_reset_bootwatchdog(void);
+extern int ipmi_oem_led_set(int type, int instance, int state);
+extern uint32_t ipmi_oem_read_vpd(uint8_t *dst, uint32_t len, uint32_t offset);
+extern uint32_t ipmi_oem_write_vpd(uint8_t *src, uint32_t len, uint32_t offset);
+extern uint32_t ipmi_oem_get_blade_descr(uint8_t *dst, uint32_t maxlen, uint32_t *len);
+extern int ipmi_oem_bios2sp(int swid, int type, char *data, int len);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.in b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.in
new file mode 100644
index 0000000..5b0e0ec
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libipmi/libipmi.in
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(IPMI-KCS-CMD)
+cod(IPMI-SYSTEM-REBOOT)
+cod(IPMI-POWER-OFF)
+cod(IPMI-OEM-STOP-BOOTWATCHDOG)
+cod(IPMI-OEM-SET-BOOTWATCHDOG)
+cod(IPMI-OEM-RESET-BOOTWATCHDOG)
+cod(IPMI-OEM-LED-SET)
+cod(IPMI-OEM-READ-VPD)
+cod(IPMI-OEM-WRITE-VPD)
+cod(IPMI-OEM-GET-BLADE-DESCR)
+cod(IPMI-OEM-BIOS2SP)
+cod(IPMI-SET-SENSOR)
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/Makefile b/qemu-0.15.x/roms/SLOF/lib/libnvram/Makefile
new file mode 100644
index 0000000..afd536f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/Makefile
@@ -0,0 +1,50 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+SRCS = nvram.c envvar.c
+
+TOPCMNDIR ?= ../..
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) $(FLAG) \
+	   -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I. -I../../include
+LDFLAGS = -nostdlib
+
+TARGET = ../libnvram.a
+
+all: $(TARGET)
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+	$(AR) -rc $@ $(OBJS)
+	$(RANLIB) $@
+
+
+clean:
+	$(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+	$(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	$(RM) Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/envvar.c b/qemu-0.15.x/roms/SLOF/lib/libnvram/envvar.c
new file mode 100644
index 0000000..eec7db7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/envvar.c
@@ -0,0 +1,244 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include "../libc/include/stdio.h"
+#include "../libc/include/string.h"
+#include "../libc/include/stdlib.h"
+#include "nvram.h"
+
+/* returns the offset of the first byte after the searched envvar */
+static int get_past_env_pos(partition_t part, char *envvar)
+{
+	int offset, len;
+	static char temp[256];
+	uint8_t data;
+
+	offset=part.addr;
+
+	memset(temp, 0, 256);
+
+	do {
+		len=0;
+		while((data=nvram_read_byte(offset++)) && len < 256) {
+			temp[len++]=data;
+		}
+		if (!strncmp(envvar, temp, strlen(envvar))) {
+			return offset;
+		}
+	} while (len);
+
+	return -1;
+}
+
+/**
+ * @param partition name of the envvar partition
+ * @param envvar name of the environment variable
+ * @return pointer to temporary string containing the value of envvar
+ */
+
+char *get_env(partition_t part, char *envvar)
+{
+	static char temp[256+1];
+	int len, offset;
+	uint8_t data;
+
+	DEBUG("get_env %s... ", envvar);
+	if(!part.addr) {
+		/* ERROR: No environment variable partition */
+		DEBUG("invalid partition.\n");
+		return NULL;
+	}
+
+	offset=part.addr;
+
+	do {
+		len=0;
+		while((data=nvram_read_byte(offset++)) && len < 256) {
+			temp[len++]=data;
+		}
+		temp[len]=0;
+
+		if (!strncmp(envvar, temp, strlen(envvar))) {
+			int pos=0;
+			while (temp[pos]!='=' && pos < len) pos++;
+			// DEBUG("value='%s'\n", temp+pos+1); 
+			return temp+pos+1;
+		}
+	} while (len);
+
+	DEBUG("not found\n");
+	return NULL;
+}
+
+static int find_last_envvar(partition_t part)
+{
+	uint8_t last, current;
+	int offset, len;
+
+	offset=part.addr;
+	len=part.len;
+
+	last=nvram_read_byte(part.addr);
+
+	for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) {
+		current=nvram_read_byte(offset);
+		if(!last && !current)
+			return offset;
+
+		last=current;
+	}
+
+	return -1;
+}
+
+int add_env(partition_t part, char *envvar, char *value)
+{
+	int freespace, last, len, offset;
+	unsigned int i;
+
+	/* Find offset where we can write */
+	last = find_last_envvar(part);
+
+	/* How much space do we have left? */
+	freespace = part.addr+part.len-last;
+
+	/* how long is the entry we want to write? */
+	len = strlen(envvar) + strlen(value) + 2;
+
+	if(freespace<len) {
+		// TODO try to increase partition size
+		return -1;
+	}
+
+	offset=last;
+
+	for(i=0; i<strlen(envvar); i++)
+		nvram_write_byte(offset++, envvar[i]);
+
+	nvram_write_byte(offset++, '=');
+
+	for(i=0; i<strlen(value); i++)
+		nvram_write_byte(offset++, value[i]);
+
+	return 0;
+}
+
+int del_env(partition_t part, char *envvar)
+{
+	int last, current, pos, i;
+	char *buffer;
+
+	if(!part.addr)
+		return -1;
+
+	last=find_last_envvar(part);
+	current = pos = get_past_env_pos(part, envvar);
+	
+	// TODO is this really required?
+	/* go back to non-0 value */
+	current--;
+
+	while (nvram_read_byte(current))
+		current--;
+
+	// TODO is this required?
+	current++;
+
+	buffer=get_nvram_buffer(last-pos);
+
+	for (i=0; i<last-pos; i++)
+		buffer[i]=nvram_read_byte(i+pos);
+
+	for (i=0; i<last-pos; i++)
+		nvram_write_byte(i+current, buffer[i]);
+
+	free_nvram_buffer(buffer);
+
+	erase_nvram(last, current+last-pos);
+
+	return 0;
+}
+
+int set_env(partition_t part, char *envvar, char *value)
+{
+	char *oldvalue, *buffer;
+	int last, current, buffersize, i;
+
+	DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value);
+
+	if(!part.addr)
+		return -1;
+
+	/* Check whether the environment variable exists already */
+	oldvalue = get_env(part, envvar);
+
+	if(oldvalue==NULL)
+		return add_env(part, envvar, value);
+
+
+	/* The value did not change. So we succeeded! */
+	if(!strncmp(oldvalue, value, strlen(value)+1))
+		return 0;
+
+	/* we need to overwrite environment variables, back them up first */
+
+	// DEBUG("overwriting existing environment variable\n");
+
+	/* allocate a buffer */
+	last=find_last_envvar(part);
+	current=get_past_env_pos(part, envvar);
+	buffersize = last - current;
+	buffer=get_nvram_buffer(buffersize);
+	if(!buffer)
+		return -1;
+
+	for (i=0; i<buffersize; i++) {
+		buffer[i] = nvram_read_byte(current+i);
+	}
+
+	/* walk back until the = */
+	while (nvram_read_byte(current)!='=') {
+		current--;
+	}
+
+	/* Start at envvar= */
+	current++;
+
+	/* Write the new value */
+	for(i=0; i<(int)strlen(value); i++) {
+		nvram_write_byte(current++, value[i]);
+	}
+	
+	/* Write end of string marker */
+	nvram_write_byte(current++, 0);
+
+	/* Copy back the buffer */
+	for (i=0; i<buffersize; i++) {
+		nvram_write_byte(current++, buffer[i]);
+	}
+
+	free_nvram_buffer(buffer);
+
+	/* If the new environment variable content is shorter than the old one,
+	 * we need to erase the rest of the bytes 
+	 */
+
+	if (current<last) {
+		for(i=current; i<last; i++) {
+			nvram_write_byte(i, 0);
+		}
+	}
+
+	return 0; /* success */
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.code b/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.code
new file mode 100644
index 0000000..f1fd414
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.code
@@ -0,0 +1,279 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <nvram.h>
+
+#define STRING_INIT(str)	\
+	char str[255];		\
+	char * str##_address;	\
+	int  str##_length;
+
+#define STRING_FROM_STACK(str)				\
+	str##_length = TOS.u; POP;				\
+	str##_address = TOS.a; POP;			\
+	memcpy(str, str##_address, str##_length);	\
+	memset(str + str##_length, 0, 255 - str##_length);
+
+PRIM(nvram_X2d_c_X40)
+	unsigned int offset = TOS.u;
+	TOS.u=nvram_read_byte(offset);
+MIRP
+
+PRIM(nvram_X2d_w_X40)
+	unsigned int offset = TOS.u;
+	TOS.u=nvram_read_word(offset);
+MIRP
+
+PRIM(nvram_X2d_l_X40)
+	unsigned int offset = TOS.u;
+	TOS.u=nvram_read_dword(offset);
+MIRP
+
+PRIM(nvram_X2d_x_X40)
+	unsigned int offset = TOS.u;
+	TOS.u=nvram_read_qword(offset);
+MIRP
+
+PRIM(nvram_X2d_c_X21)
+	nvram_write_byte(TOS.u, NOS.u);
+	POP; POP;
+MIRP
+
+PRIM(nvram_X2d_w_X21)
+	nvram_write_word(TOS.u, NOS.u);
+	POP; POP;
+MIRP
+
+PRIM(nvram_X2d_l_X21)
+	nvram_write_dword(TOS.u, NOS.u);
+	POP; POP;
+MIRP
+
+PRIM(nvram_X2d_x_X21)
+	nvram_write_qword(TOS.u, NOS.u);
+	POP; POP;
+MIRP
+
+/* get-nvram-partition ( type -- addr len FAILED? ) */
+PRIM(get_X2d_nvram_X2d_partition)
+	partition_t partition;
+	unsigned int ptype = TOS.u;
+	partition = get_partition(ptype, NULL);
+	if(partition.len && partition.len != -1) {
+		TOS.u = partition.addr;
+		PUSH;
+		TOS.u = partition.len;
+		PUSH;
+		TOS.u = 0; // FALSE
+	} else {
+		TOS.u = -1; // TRUE
+	}
+MIRP
+
+/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */
+PRIM(get_X2d_named_X2d_nvram_X2d_partition)
+	STRING_INIT(name)
+	partition_t partition;
+
+	STRING_FROM_STACK(name)
+	partition = get_partition(-1, name);
+
+	if(partition.len && partition.len != -1) {
+		PUSH;
+		TOS.u = partition.addr;
+		PUSH;
+		TOS.u = partition.len;
+		PUSH;
+		TOS.u = 0; // FALSE
+	} else {
+		PUSH;
+		TOS.u = -1; // TRUE
+	}
+MIRP
+
+
+
+/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */
+PRIM(new_X2d_nvram_X2d_partition)
+	int type, len, i, slen;
+	char name[12], *addr;
+	partition_t partition;
+
+	len = TOS.u; POP;
+	slen = TOS.u; POP;
+	addr = (char *)TOS.u; POP;
+	type = TOS.u; POP;
+
+	for (i=0; i<12; i++) {
+		if(slen>i)
+			name[i]=addr[i];
+		else
+			name[i]=0;
+	}
+
+	partition=new_nvram_partition(type, name, len);
+
+	if(!partition.len) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = partition.addr;
+		PUSH; TOS.u = partition.len;
+		PUSH; TOS.u = 0; // FALSE
+	}
+MIRP
+
+/* inrease-nvram-partition ( part.offs part.len new-len -- FALSE | TRUE ) */
+PRIM(increase_X2d_nvram_X2d_partition)
+	int len, ret;
+	partition_t partition;
+
+	// FIXME
+	partition.addr = TOS.u; POP;
+	partition.len  = TOS.u; POP;
+	len = TOS.u; POP;
+
+	ret=increase_nvram_partition_size(partition, len);
+
+	PUSH;
+
+	if(!ret) 
+		TOS.u=-1; // TRUE
+	else
+		TOS.u=0; // FALSE
+
+MIRP
+
+PRIM(internal_X2d_reset_X2d_nvram)
+	reset_nvram();
+MIRP
+
+PRIM(wipe_X2d_nvram)
+	wipe_nvram();
+MIRP
+
+PRIM(nvram_X2d_debug)
+	nvram_debug();
+MIRP
+
+// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false )
+PRIM(internal_X2d_get_X2d_env)
+	STRING_INIT(name)
+	partition_t part;
+	char *val;
+
+	STRING_FROM_STACK(name)
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	val=get_env(part, name);
+	if(val) {
+		PUSH; TOS.a = val;
+		PUSH; TOS.u = strlen(val);
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+MIRP
+
+// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
+PRIM(internal_X2d_add_X2d_env)
+	STRING_INIT(name)
+	STRING_INIT(value)
+	partition_t part;
+	int ret;
+
+	STRING_FROM_STACK(value)
+	STRING_FROM_STACK(name)
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	ret=add_env(part, name, value);
+	if(ret) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+MIRP
+
+// ( part.addr part.len name.addr name.len -- FALSE|TRUE)
+PRIM(internal_X2d_del_X2d_env)
+	STRING_INIT(name)
+	partition_t part;
+	int ret;
+
+	STRING_FROM_STACK(name);
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	ret=del_env(part, name);
+	if(ret) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+
+MIRP
+
+// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
+PRIM(internal_X2d_set_X2d_env)
+	STRING_INIT(name)
+	STRING_INIT(value)
+	partition_t part;
+	int ret;
+
+	STRING_FROM_STACK(value)
+	STRING_FROM_STACK(name)
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	ret=set_env(part, name, value);
+	if(ret) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+MIRP
+
+// ( part.addr part.len -- FALSE|TRUE)
+PRIM(erase_X2d_nvram_X2d_partition)
+	partition_t part;
+	int ret;
+
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	ret=clear_nvram_partition(part);
+	if(ret) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+
+MIRP
+
+// ( part.addr part.len -- FALSE|TRUE)
+PRIM(delete_X2d_nvram_X2d_partition)
+	partition_t part;
+	int ret;
+
+	part.len = TOS.u; POP;
+	part.addr = TOS.u; POP;
+
+	ret=delete_nvram_partition(part);
+	if(ret) {
+		PUSH; TOS.u = -1; // TRUE
+	} else {
+		PUSH; TOS.u = 0; // FALSE
+	}
+
+MIRP
+
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.in b/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.in
new file mode 100644
index 0000000..33ab3bc
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/libnvram.in
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* NVRAM access primitives */
+cod(nvram-c@)
+cod(nvram-c!)
+cod(nvram-w@)
+cod(nvram-w!)
+cod(nvram-l@)
+cod(nvram-l!)
+cod(nvram-x@)
+cod(nvram-x!)
+
+/* Generic NVRAM helpers */
+cod(internal-reset-nvram)
+cod(nvram-debug)
+cod(wipe-nvram)
+
+/* NVRAM Partition Handling */
+cod(get-nvram-partition)
+cod(get-named-nvram-partition)
+cod(new-nvram-partition)
+cod(increase-nvram-partition)
+cod(erase-nvram-partition)
+cod(delete-nvram-partition)
+
+/* NVRAM environment access words */
+cod(internal-get-env)
+cod(internal-add-env)
+cod(internal-del-env)
+cod(internal-set-env)
+
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.c b/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.c
new file mode 100644
index 0000000..e9500ec
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.c
@@ -0,0 +1,527 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "cache.h"
+
+#include "../libc/include/stdio.h"
+#include "../libc/include/string.h"
+#include "../libc/include/stdlib.h"
+
+#include "nvram.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <southbridge.h>
+#include <nvramlog.h>
+
+#ifndef NVRAM_LENGTH
+#define NVRAM_LENGTH	0x10000
+#endif
+
+void asm_cout(long Character,long UART,long NVRAM);
+
+#if defined(DISABLE_NVRAM)
+static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */
+#else
+static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr;
+#endif
+
+/* This is extremely ugly, but still better than implementing 
+ * another sbrk() around it.
+ */
+static char nvram_buffer[NVRAM_LENGTH];
+static uint8_t nvram_buffer_locked=0x00;
+
+/**
+ * producer for nvram access functions. Since these functions are
+ * basically all the same except for the used data types, produce 
+ * them via the following macro to keep the code from bloating.
+ */
+
+#define nvram_access(type,size,name) 				\
+	type nvram_read_##name(unsigned int offset)		\
+	{							\
+		type *pos;					\
+		if (offset > (NVRAM_LENGTH - sizeof(type)))	\
+			return 0;				\
+		pos = (type *)(nvram+offset);			\
+		return ci_read_##size(pos);			\
+	}							\
+	void nvram_write_##name(unsigned int offset, type data)	\
+	{							\
+		type *pos;					\
+		if (offset > (NVRAM_LENGTH - sizeof(type)))	\
+			return;					\
+		pos = (type *)(nvram+offset);			\
+		ci_write_##size(pos, data);			\
+	}
+
+nvram_access(uint8_t,   8, byte)
+nvram_access(uint16_t, 16, word)
+nvram_access(uint32_t, 32, dword)
+nvram_access(uint64_t, 64, qword)
+
+/**
+ * This function is a minimal abstraction for our temporary
+ * buffer. It should have been malloced, but since there is no
+ * usable malloc, we go this route.
+ *
+ * @return pointer to temporary buffer
+ */
+
+char *get_nvram_buffer(int len)
+{
+	if(len>NVRAM_LENGTH)
+		return NULL;
+
+	if(nvram_buffer_locked)
+		return NULL;
+
+	nvram_buffer_locked = 0xff;
+
+	return nvram_buffer;
+}
+
+/**
+ * @param buffer pointer to the allocated buffer. This
+ * is unused, but nice in case we ever get a real malloc
+ */
+
+void free_nvram_buffer(char *buffer __attribute__((unused)))
+{
+	nvram_buffer_locked = 0x00;
+}
+
+/**
+ * @param fmt format string, like in printf
+ * @param ... variable number of arguments
+ */
+
+int nvramlog_printf(const char* fmt, ...)
+{
+	char buff[256];
+	int count, i;
+	va_list ap;
+    
+	va_start(ap, fmt);
+	count = vsprintf(buff, fmt, ap);
+	va_end(ap);
+ 
+	for (i=0; i<count; i++)
+		asm_cout(buff[i], 0, 1);
+
+	return count;
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint8_t get_partition_type(int offset)
+{
+	return nvram_read_byte(offset);
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint8_t get_partition_header_checksum(int offset)
+{
+	return nvram_read_byte(offset+1);
+}
+
+/**
+ * @param offset start offset of the partition header
+ */
+
+static uint16_t get_partition_len(int offset)
+{
+	return nvram_read_word(offset+2);
+}
+
+/**
+ * @param offset start offset of the partition header
+ * @return static char array containing the partition name
+ *
+ * NOTE: If the partition name needs to be non-temporary, strdup 
+ * and use the copy instead.
+ */
+
+static char * get_partition_name(int offset)
+{
+	static char name[12];
+	int i;
+	for (i=0; i<12; i++)
+		name[i]=nvram_read_byte(offset+4+i);
+
+	// DEBUG("name: \"%s\"\n", name);
+	return name;
+}
+
+static uint8_t calc_partition_header_checksum(int offset)
+{
+	uint16_t plainsum;
+	uint8_t checksum;
+	int i;
+
+	plainsum = nvram_read_byte(offset);
+
+	for (i=2; i<PARTITION_HEADER_SIZE; i++)
+		plainsum+=nvram_read_byte(offset+i);
+
+	checksum=(plainsum>>8)+(plainsum&0xff);
+
+	return checksum;
+}
+
+static int calc_used_nvram_space(void)
+{
+	int walk, len;
+
+	for (walk=0; walk<NVRAM_LENGTH;) {
+		if(get_partition_header_checksum(walk) != 
+				calc_partition_header_checksum(walk)) {
+			/* If there's no valid entry, bail out */
+			break;
+		}
+
+		len=get_partition_len(walk);
+		// DEBUG("... part len=%x, %x\n", len, len*16);
+
+		if(!len) {
+			/* If there's a partition type but no len, bail out.
+			 * Don't bail out if type is 0. This can be used to
+			 * find the offset of the first free byte.
+			 */
+			break;
+		}
+
+		walk += len * 16;
+	}
+	DEBUG("used nvram space: %d\n", walk);
+
+	return walk;
+}
+
+/**
+ *
+ * @param type partition type. Set this to the partition type you are looking
+ *             for. If there are several partitions with the same type, only
+ *             the first partition with that type will be found.
+ *             Set to -1 to ignore. Set to 0 to find free unpartitioned space.
+ *
+ * @param name partition name. Set this to the name of the partition you are
+ *             looking for. If there are several partitions with the same name,
+ *             only the first partition with that name will be found.
+ *             Set to NULL to ignore.
+ *
+ * To disambiguate the partitions you should have a unique name if you plan to
+ * have several partitions of the same type.
+ *
+ */
+
+partition_t get_partition(unsigned int type, char *name)
+{
+	partition_t ret={0,-1};
+	int walk, len;
+	
+	for (walk=0; walk<NVRAM_LENGTH;) {
+		// DEBUG("get_partition: walk=%x\n", walk);
+		if(get_partition_header_checksum(walk) != 
+				calc_partition_header_checksum(walk)) {
+			/* If there's no valid entry, bail out */
+			break;
+		}
+
+		len=get_partition_len(walk);
+		if(type && !len) {
+			/* If there's a partition type but no len, bail out.
+			 * Don't bail out if type is 0. This can be used to
+			 * find the offset of the first free byte.
+			 */
+			break;
+		}
+
+		/* Check if either type or name or both do not match. */
+		if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) ||
+			(name && strncmp(get_partition_name(walk), name, 12)) ) {
+			/* We hit another partition. Continue
+			 * at the end of this partition
+			 */
+			walk += len*16;
+			continue;
+		}
+
+		ret.addr=walk+PARTITION_HEADER_SIZE;
+		ret.len=(len*16)-PARTITION_HEADER_SIZE;
+		break;
+	}
+
+	return ret;
+}
+
+void erase_nvram(int offset, int len)
+{
+	int i;
+
+	for (i=offset; i<offset+len; i++)
+		nvram_write_byte(i, 0);
+}
+
+void wipe_nvram(void)
+{
+	erase_nvram(0, NVRAM_LENGTH);
+}
+
+/**
+ * @param partition   partition structure pointing to the partition to wipe.
+ * @param header_only if header_only is != 0 only the partition header is
+ *                    nulled out, not the whole partition.
+ */
+
+int wipe_partition(partition_t partition, int header_only)
+{
+	int pstart, len;
+
+	pstart=partition.addr-PARTITION_HEADER_SIZE;
+	
+	len=PARTITION_HEADER_SIZE;
+
+	if(!header_only)
+		len += partition.len;
+
+	erase_nvram(pstart, len);
+
+	return 0;
+}
+
+
+static partition_t create_nvram_partition(int type, const char *name, int len)
+{
+	partition_t ret = { 0, 0 };
+	int offset, plen;
+	unsigned int i;
+
+	plen = ALIGN(len+PARTITION_HEADER_SIZE, 16);
+
+	DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n",
+			type, name, len, plen);
+
+	offset = calc_used_nvram_space();
+
+	if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) {
+		DEBUG("Not enough free space.\n");
+		return ret;
+	}
+
+	DEBUG("Writing header.");
+
+	nvram_write_byte(offset, type);
+	nvram_write_word(offset+2, plen/16);
+
+	for (i=0; i<strlen(name); i++)
+		nvram_write_byte(offset+4+i, name[i]);
+
+	nvram_write_byte(offset+1, calc_partition_header_checksum(offset));
+
+	ret.addr = offset+PARTITION_HEADER_SIZE;
+	ret.len = len;
+
+	DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len);
+
+	return ret;
+}
+
+static int create_free_partition(void)
+{
+	int free_space;
+	partition_t free_part;
+
+	free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE;
+	free_part = create_nvram_partition(0x7f, "free space", free_space);
+
+	return (free_part.addr != 0);
+}
+
+partition_t new_nvram_partition(int type, char *name, int len)
+{
+	partition_t free_part, new_part = { 0, 0 };
+
+	/* NOTE: Assume all free space is consumed by the "free space"
+	 * partition. This means a partition can not be increased in the middle
+	 * of reset_nvram, which is obviously not a big loss.
+	 */
+
+	free_part=get_partition(0x7f, NULL);
+	if( free_part.len && free_part.len != -1)
+		wipe_partition(free_part, 1);
+
+	new_part = create_nvram_partition(type, name, len);
+
+	if(new_part.len != len) {
+		new_part.len = 0;
+		new_part.addr = 0;
+	}
+
+	create_free_partition();
+
+	return new_part;
+}
+
+/**
+ * @param partition   partition structure pointing to the partition to wipe.
+ */
+
+int delete_nvram_partition(partition_t partition)
+{
+	int i;
+	partition_t free_part;
+
+	if(!partition.len || partition.len == -1)
+		return 0;
+
+	for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++) 
+		nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i));
+
+	erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE, 
+			partition.len-PARTITION_HEADER_SIZE);
+
+	free_part=get_partition(0x7f, NULL);
+	wipe_partition(free_part, 0);
+	create_free_partition();
+
+	return 1;
+}
+
+int clear_nvram_partition(partition_t part)
+{
+	if(!part.addr)
+		return 0;
+
+	erase_nvram(part.addr, part.len);
+
+	return 1;
+}
+
+
+int increase_nvram_partition_size(partition_t partition, int newsize)
+{
+	partition_t free_part;
+	int free_offset, end_offset, i;
+
+	/* We don't support shrinking partitions (yet) */
+	if (newsize < partition.len) {
+		return 0;
+	}
+
+	/* NOTE: Assume all free space is consumed by the "free space"
+	 * partition. This means a partition can not be increased in the middle
+	 * of reset_nvram, which is obviously not a big loss.
+	 */
+
+	free_part=get_partition(0x7f, NULL);
+
+	// FIXME: It could be 16 byte more. Also handle empty "free" partition.
+	if (free_part.len == -1 || free_part.len < newsize - partition.len ) {
+		return 0;
+	}
+	
+	free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte
+	end_offset=partition.addr + partition.len; // last used byte of partition + 1
+
+	if(free_offset > end_offset) {
+		int j, bufferlen;
+		char *overlap_buffer;
+
+		bufferlen=free_offset - end_offset;
+
+		overlap_buffer=get_nvram_buffer(bufferlen);
+		if(!overlap_buffer) {
+			return 0;
+		}
+
+		for (i=end_offset, j=0; i<free_offset; i++, j++)
+			overlap_buffer[j]=nvram_read_byte(i);
+
+		/* Only wipe the header. The free space partition is empty per
+		 * definition
+		 */
+
+		wipe_partition(free_part, 1);
+
+		for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++)
+			nvram_write_byte(i, overlap_buffer[j]);
+
+		free_nvram_buffer(overlap_buffer);
+	} else {
+		/* Only wipe the header. */
+		wipe_partition(free_part, 1);
+	}
+
+	/* Clear the new partition space */
+	erase_nvram(partition.addr+partition.len, newsize-partition.len);
+
+	nvram_write_word(partition.addr - 16 + 2, newsize);
+
+	create_free_partition();
+
+	return 1;
+}
+
+static void init_cpulog_partition(partition_t cpulog)
+{
+	unsigned int offset=cpulog.addr;
+
+	/* see board-xxx/include/nvramlog.h for information */
+	nvram_write_word(offset+0, 0x40);  // offset
+	nvram_write_word(offset+2, 0x00);  // flags
+	nvram_write_dword(offset+4, 0x01); // pointer
+
+}
+
+void reset_nvram(void)
+{
+	partition_t cpulog0, cpulog1;
+	char header[12];
+
+	DEBUG("Erasing NVRAM\n");
+	erase_nvram(0, NVRAM_LENGTH);
+
+	DEBUG("Creating CPU log partitions\n");
+	*(uint32_t *)(char *)&(header[0]) = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX);
+	*(uint64_t *)(char *)&(header[4]) = be64_to_cpu(LLFW_LOG_BE0_NAME);
+	cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, header, 
+			(LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE);
+
+	*(uint32_t *)(char *)&(header[0]) = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX);
+	*(uint64_t *)(char *)&(header[4]) = be64_to_cpu(LLFW_LOG_BE1_NAME);
+	cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, header, 
+			(LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE);
+
+	DEBUG("Initializing CPU log partitions\n");
+	init_cpulog_partition(cpulog0);
+	init_cpulog_partition(cpulog1);
+
+	nvramlog_printf("Creating common NVRAM partition\r\n");
+	create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE);
+
+	create_free_partition();
+}
+
+void nvram_debug(void)
+{
+#if !defined(DISABLE_NVRAM)
+	printf("\nNVRAM_BASE: %lx\n", (unsigned long)SB_NVRAM_adr);
+	printf("NVRAM_LEN: %x\n", NVRAM_LENGTH);
+#endif
+}
diff --git a/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.h b/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.h
new file mode 100644
index 0000000..d15b85e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/lib/libnvram/nvram.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __NVRAM_H
+#define __NVRAM_H 1
+
+/* data structures */
+
+typedef struct {
+	unsigned long addr;
+	long len;
+} partition_t;
+
+/* macros */
+
+#define DEBUG(x...)
+// #define DEBUG(x...) printf(x);
+
+#ifndef ALIGN
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#endif
+
+#define NULL ((void *)0)
+
+#define PARTITION_HEADER_SIZE 16
+
+/* FIXME this should be done complete and in a more prominent place */
+#define	__LITTLE_ENDIAN	1234
+#define	__BIG_ENDIAN	4321
+#ifdef __i386__
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#else
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be64(x)  (x)
+#define be64_to_cpu(x)  (x)
+#define cpu_to_be32(x)  (x)
+#define be32_to_cpu(x)  (x)
+#else
+#include <byteswap.h>
+#define cpu_to_be64(x)  bswap_64(x)
+#define be64_to_cpu(x)  bswap_64(x)
+#define cpu_to_be32(x)  bswap_32(x)
+#define be32_to_cpu(x)  bswap_32(x)
+#endif
+
+/* exported functions */
+
+#define nvram_access_proto(type,name)			\
+	type nvram_read_##name(unsigned int offset);		\
+	void nvram_write_##name(unsigned int offset, type data);
+
+nvram_access_proto(uint8_t,  byte)
+nvram_access_proto(uint16_t, word)
+nvram_access_proto(uint32_t, dword)
+nvram_access_proto(uint64_t, qword)
+
+/* nvram.c */
+
+char *get_nvram_buffer(int len);
+void free_nvram_buffer(char *buffer);
+int nvramlog_printf(const char* fmt, ...);
+partition_t get_partition(unsigned int type, char *name);
+void erase_nvram(int offset, int len);
+int wipe_partition(partition_t partition, int header_only);
+partition_t new_nvram_partition(int type, char *name, int len);
+int increase_nvram_partition_size(partition_t partition, int newsize);
+int clear_nvram_partition(partition_t part);
+int delete_nvram_partition(partition_t part);
+void reset_nvram(void);
+void wipe_nvram(void);
+void nvram_debug(void);
+
+/* envvar.c */
+char *get_env(partition_t part, char *envvar);
+int add_env(partition_t part, char *envvar, char *value);
+int del_env(partition_t part, char *envvar);
+int set_env(partition_t part, char *envvar, char *value);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/llfw/boot_abort.S b/qemu-0.15.x/roms/SLOF/llfw/boot_abort.S
new file mode 100644
index 0000000..996bdd7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/boot_abort.S
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include "macros.h"
+#include "termctrl.h"
+#include "boot_abort.h"
+#include <cpu.h>
+
+#define MSG_LOOK_HDR TERM_CTRL_BRIGHT, TERM_BG_RED, TERM_FG_WHITE
+
+ASM_ENTRY(msg_e_crc)
+	.ascii	MSG_LOOK_HDR
+	.ascii	"\n\r\n\rE1001 - Boot ROM CRC failure\n\r"
+	.ascii	TERM_CTRL_RESET, "\0"
+	.align	2
+
+ASM_ENTRY(msg_e_nomem)
+	.ascii	MSG_LOOK_HDR
+	.ascii	"\n\r\n\rE1002 - Memory could not be initialized\n\r"
+	.ascii	TERM_CTRL_RESET, "\0"
+	.align	2
+
+ASM_ENTRY(msg_e_nofile)
+	.ascii	MSG_LOOK_HDR
+	.ascii	"\n\r\n\rE1003 - Firmware image incomplete"
+	.ascii	TERM_CTRL_RESET
+	.ascii	    "\n\r       internal FLS1-FFS-0.\0"
+	.align	2
+
+ASM_ENTRY(msg_e_ierror)
+	.ascii	MSG_LOOK_HDR
+	.ascii	"\n\r\n\rE1004 - Unspecified Internal Firmware Error"
+	.ascii	TERM_CTRL_RESET
+	.ascii	    "\n\r       internal FLSX-SE-0.\0"
+	.align	2
+
+/* E1005 : used in memory init code */
+
+/*****************************************************************************
+ * Boot Abort Handler
+ *
+ * Input:
+ *        R3 - capability informatin (i/o etc.)
+ *        R4 - handling suggestion
+ *        R5 - error string reference
+ *        R6 - error number
+ * 
+ * Return: 
+ *        if possible input to H8 and NVRAM log and console , then reboot/halt
+ *
+ * Input definitions:
+ *
+ * R3 bits: 63 (h8/console possible) ... add more
+ * R4 bits: 63 (do not attempt reboot)
+ * R5 reference to error message string
+ * R6 32-bit error enumerator
+ *
+ ******************************************************************************/
+ASM_ENTRY(boot_abort)
+	/* save arguments */
+	mr	r31, r3
+	mr	r30, r4
+	mr	r29, r5
+	mr	r28, r6
+	
+	/* check if i/o is possible, if yes then print message */
+	li	r10, ABORT_CANIO
+	andi.	r3, r31, r10
+	bne	abort_noio
+
+	/* use i/o ..., first print reference message */
+	/* then add internal number if != 0           */
+	mr	r3, r29
+	mfspr	r4, HSPRG0 /* get runbase */
+	or	r3, r3, r4
+	bl	io_print
+	mr	r3, r28
+	li	r28, 0
+	cmpd	r3, r28
+	beq	0f
+	bl	io_printhex32
+0:
+
+  abort_noio:
+  	b	$	// FIXME
+	/* never reached */
+
diff --git a/qemu-0.15.x/roms/SLOF/llfw/boot_abort.h b/qemu-0.15.x/roms/SLOF/llfw/boot_abort.h
new file mode 100644
index 0000000..b708206
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/boot_abort.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef BOOT_ABORT_H
+#define BOOT_ABORT_H
+
+/* boot abort function suitable for assembly */
+#define BOOT_ABORT(cap, action, msg, numhint)		\
+		li	r3, cap;			\
+		li	r4, action;			\
+		LOAD32(r5, msg);			\
+		LOAD32(r6, numhint);			\
+		bl	boot_abort
+
+/* boot abort function suitable called from c (takes r3 as hint) */
+#define BOOT_ABORT_R3HINT(cap, action, msg)		\
+		mr	r6, r3;				\
+		li	r3, cap;			\
+		li	r4, action;			\
+		LOAD32(r5, msg);			\
+		bl	boot_abort
+
+#define ABORT_CANIO	(1 << 0)
+#define ABORT_NOIO	(1 << 1)
+
+#define ALTBOOT		(1 << 0)
+#define HALT		(1 << 1)
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/llfw/clib/Makefile.inc b/qemu-0.15.x/roms/SLOF/llfw/clib/Makefile.inc
new file mode 100644
index 0000000..7003798
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/clib/Makefile.inc
@@ -0,0 +1,42 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../../make.rules
+
+CFLAGS_COMLIB = -pedantic -std=gnu99 -O0
+ASFLAGS_COMLIB =
+
+
+COMLIBDIR 	= $(LLFWCMNDIR)/clib
+
+COMLIB_SRC_ASM	=
+COMLIB_SRC_C	= iolib.c
+
+COMLIB_SRCS 	= $(COMLIB_SRC_ASM:%=$(COMLIBDIR)/%) \
+		  $(COMLIB_SRC_C:%=$(COMLIBDIR)/%)
+COMLIB_OBJ_ASM	= $(COMLIB_SRC_ASM:%.S=%.o)
+COMLIB_OBJ_C	= $(COMLIB_SRC_C:%.c=%.o)
+
+
+comlib.o:	$(COMLIB_OBJ_C) $(COMLIB_OBJ_ASM)
+		$(LD) $(LDFLAGS) $^ -o $@ -r
+
+%.o: $(LLFWCMNDIR)/clib/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_COMLIB) -c $< -o $@
+
+%.o: $(LLFWCMNDIR)/clib/%.S
+	$(CC) $(CPPFLAGS) $(ASFLAGS) $(ASFLAGS_COMLIB) -c $< -o $@
+
+LLFW_CLEAN_TARGETS	+= clean_clib
+.PHONY : clean_clib
+clean_clib:
+	rm -f $(COMLIB_OBJ_C) $(COMLIB_OBJ_ASM) comlib.o
diff --git a/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.c b/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.c
new file mode 100644
index 0000000..56b7caf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.c
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stddef.h>
+#include <unistd.h>
+#include "iolib.h"
+
+void uart_send_byte(unsigned char b)
+{
+	asm volatile ("":::"3","4","5","6","7");
+	io_putchar(b);
+}
+
+/**
+ * Standard write function for the libc.
+ *
+ * @param fd	file descriptor (should always be 1 or 2)
+ * @param buf	pointer to the array with the output characters
+ * @param count	number of bytes to be written
+ * @return	the number of bytes that have been written successfully
+ */
+ssize_t write(int fd, const void *buf, size_t count)
+{
+	size_t i;
+	char *ptr = (char *)buf;
+
+	if (fd != 1 && fd != 2)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		if (*ptr == '\n')
+			uart_send_byte('\r');
+		uart_send_byte(*ptr++);
+	}
+
+	return i;
+}
+
+
+/**
+ * @brief C-routine to delay for a number of milliseconds.
+ * @param delay interval in terms of ms
+ */
+void delay_ms( unsigned int ms )
+{
+	uint32_t ticks_per_ms;
+	
+	ticks_per_ms = tb_frequency() / 1000;
+
+	while (0 < ms) {
+		set_dec(ticks_per_ms);
+		while( ((get_dec()) & 0x80000000) == 0 );
+		ms--;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.h b/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.h
new file mode 100644
index 0000000..30dfa37
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/clib/iolib.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef IOLIB_H
+#define IOLIB_H
+
+#include <stdint.h>
+
+#define addr_t  	volatile unsigned int
+#define addr8_t 	volatile unsigned char
+
+extern void     halt_sys (unsigned int);
+
+extern uint32_t get_sb_version (void);
+
+extern void     uart_send_byte(unsigned char b);
+extern void     io_putchar(unsigned char);
+
+extern uint64_t tb_frequency(void);
+extern uint64_t be_frequency(void);
+
+extern uint32_t get_dec(void);
+extern void     set_dec(uint32_t);
+extern void     delay_ms( unsigned int ms );
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/llfw/io_generic/Makefile.inc b/qemu-0.15.x/roms/SLOF/llfw/io_generic/Makefile.inc
new file mode 100644
index 0000000..b660725
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/io_generic/Makefile.inc
@@ -0,0 +1,38 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+IOGENERICDIR 	= $(LLFWCMNDIR)/io_generic
+
+IO_GENERIC_SRC_ASM	= io_generic.S
+IO_GENERIC_SRC_C	= 
+
+IO_GENERIC_SRCS 	= $(IO_GENERIC_SRC_ASM:%=$(IOGENERICDIR)/%) \
+			  $(IO_GENERIC_SRC_C:%=$(IOGENERICDIR)/%)
+IO_GENERIC_OBJ_ASM	= $(IO_GENERIC_SRC_ASM:%.S=%.o)
+IO_GENERIC_OBJ_C	= $(IO_GENERIC_SRC_C:%.c=%.o)
+
+
+io_generic_lib.o:	$(IO_GENERIC_OBJ_ASM) $(IO_GENERIC_OBJ_C)
+	$(LD) $(LDFLAGS) $^ -o $@ -r
+
+
+%.o: $(IOGENERICDIR)/%.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+%.o: $(IOGENERICDIR)/%.S
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+
+LLFW_CLEAN_TARGETS	+= clean_io_generic
+.PHONY : clean_io_generic
+clean_io_generic:
+	rm -f $(IO_GENERIC_OBJ_C) $(IO_GENERIC_OBJ_ASM) io_generic_lib.o
diff --git a/qemu-0.15.x/roms/SLOF/llfw/io_generic/io_generic.S b/qemu-0.15.x/roms/SLOF/llfw/io_generic/io_generic.S
new file mode 100644
index 0000000..9c1db41
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/io_generic/io_generic.S
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include "macros.h"
+#include "calculatecrc.h"
+#include "calculatecrc.h"
+
+	.text
+
+/****************************************************************************
+ * prints a 0-terminated string to serial console
+ *
+ * Input:
+ * R3 - pointer to string in memory
+ *
+ * Returns: -
+ *
+ * Modifies Registers:
+ * R3, R4, R5, R6, R7, R8, R9
+ ****************************************************************************/
+ASM_ENTRY(io_print)
+	mflr	r8
+	mr	r9, r3
+
+0:
+	lbz	r3, 0(r9)
+	cmpwi	r3, 0
+	beq	1f
+	bl	io_putchar
+	addi	r9, r9, 1
+	b		0b
+1:
+	mtlr	r8
+	blr
+
+/****************************************************************************
+ * prints Hex integer to the UART and the NVRAM (using board io_putchar)
+ *
+ * Input:
+ * R3 - integer to print
+ *
+ * Returns: -
+ *
+ * Modifies Registers:
+ * R3, R4, R5, R6, R7, R8, R9
+ ****************************************************************************/
+#define _io_gen_print_nib(reg, src, shift)	\
+	srdi	reg, src, shift;		\
+	andi.	reg, reg, 0x0F;			\
+	cmpwi	reg, 0x0A;			\
+	blt	0f;				\
+	addi	reg, reg, ('A'-'0'-10);		\
+0:;						\
+	addi	reg, reg, '0';			\
+	bl	io_putchar
+
+ASM_ENTRY(io_printhex64)
+	mflr	r8
+	mr	r9, r3
+
+_io_printhex64:
+	_io_gen_print_nib(r3, r9, 60)
+	_io_gen_print_nib(r3, r9, 56)
+	_io_gen_print_nib(r3, r9, 52)
+	_io_gen_print_nib(r3, r9, 48)
+	_io_gen_print_nib(r3, r9, 44)
+	_io_gen_print_nib(r3, r9, 40)
+	_io_gen_print_nib(r3, r9, 36)
+	_io_gen_print_nib(r3, r9, 32)
+_io_printhex32:
+	_io_gen_print_nib(r3, r9, 28)
+	_io_gen_print_nib(r3, r9, 24)
+	_io_gen_print_nib(r3, r9, 20)
+	_io_gen_print_nib(r3, r9, 16)
+_io_printhex16:
+	_io_gen_print_nib(r3, r9, 12)
+	_io_gen_print_nib(r3, r9,  8)
+_io_printhex8:
+	_io_gen_print_nib(r3, r9,  4)
+	_io_gen_print_nib(r3, r9,  0)
+
+	mtlr	r8
+	blr
+
+ASM_ENTRY(io_printhex32)
+	mflr	r8
+	mr	r9, r3
+	b       _io_printhex32
+
+ASM_ENTRY(io_printhex16)
+	mflr	r8
+	mr	r9, r3
+	b       _io_printhex16
+
+ASM_ENTRY(io_printhex8)
+	mflr	r8
+	mr	r9, r3
+	b       _io_printhex8
+
+
+/****************************************************************************
+ * print the address and its contents as 64-bit hex values
+ *
+ * Input:
+ * R3 - Address to read from
+ *
+ * Returns: -
+ *
+ * Modifies Registers:
+ * R3, R4, R5, R6, R7, R8, R9, R10
+ ****************************************************************************/
+#if 0   /* currently unused */
+ASM_ENTRY(io_dump)
+        mflr    r10
+        bl      io_printhex64
+        li      r3,':'
+        bl      io_putchar
+        ld      r9,0(r9)
+        mr      r8,r10
+        b       _io_printhex64
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/llfw/nvramlog.S b/qemu-0.15.x/roms/SLOF/llfw/nvramlog.S
new file mode 100644
index 0000000..be6bfd8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/nvramlog.S
@@ -0,0 +1,351 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <macros.h>
+#include <nvramlog.h>
+#include <southbridge.h>
+#include <calculatecrc.h>
+
+
+#if !defined(DISABLE_NVRAM)
+
+// detect overflow: if(a<b)  return a else return 0
+#define NVRAM_LOG_DATA_OVERFLOW( a, b) \
+	cmpd    7, a, b; \
+	blt+    7, 0f; \
+	li      a, 0; \
+	0:
+
+// get Pointer(pointer) to next byte in NVRAM data section
+//  and size of this data sechtion (modulo)
+// modifies register pointer, modulo
+#define NVRAM_POINTER_DATASIZE_BE0(pointer, modulo, address) \
+	LOAD64(	modulo, LLFW_LOG_BE0_LENGTH); \
+	lwz     pointer, LLFW_LOG_POS_POINTER(address); \
+	sldi    modulo, modulo, 4; \
+	addi    modulo, modulo,-LLFW_LOG_BE0_DATA_OFFSET
+#define NVRAM_POINTER_DATASIZE_BE1(pointer, modulo, address) \
+	LOAD64(	modulo, LLFW_LOG_BE1_LENGTH); \
+	lwz     pointer, LLFW_LOG_POS_POINTER(address); \
+	sldi    modulo, modulo, 4; \
+	addi    modulo, modulo,-LLFW_LOG_BE1_DATA_OFFSET
+
+/****************************************************************************
+ *	checkLogHeaderData
+ *	compare the fixed values in the header if any change was done since
+ *	last initialisation.
+ *	Flags are not checked!
+ *
+ *	Retrun 0 if no manimulation was found 1 else
+ *
+ *	input:
+ *			r3 - NVRAM Base Address 
+ *
+ *	output:
+ *			r3 - status: 0 = ok, 1 = corrupt
+ *			r4 - NVRAM Base Address
+ *
+ ***************************************************************************/
+ASM_ENTRY(checkLogHeaderData)
+	li	r4, 0					// init error flag
+	lbz	r5, 0(r3)				// check signature
+	addi	r5, r5, -LLFW_LOG_BE0_SIGNATURE
+	add	r4, r4, r5
+
+	lhz	r5, LLFW_LOG_POS_LENGTH(r3)		// check length
+	addi	r5, r5, -LLFW_LOG_BE0_LENGTH
+	add 	r4, r4, r5
+
+	lwz	r5, LLFW_LOG_POS_NAME(r3)		// check name prefix
+	LOAD64( r6, LLFW_LOG_BE0_NAME_PREFIX)
+	subf	r5, r6, r5
+	add	r4, r4, r5
+
+	ld	r5, (LLFW_LOG_POS_NAME+4)(r3)		// check name
+	LOAD64(	r6, LLFW_LOG_BE0_NAME)
+	subf	r5, r6, r5
+	add	r4, r4, r5
+	
+	lhz	r5, LLFW_LOG_POS_DATA_OFFSET(r3)	//check data offset
+	addi	r5, r5, -LLFW_LOG_BE0_DATA_OFFSET
+	add	r4, r4, r5
+
+	lhz	r5, LLFW_LOG_POS_FLAGS(r3)		//check flags
+	addi	r5, r5, -LLFW_LOG_BE0_FLAGS
+	add	r4, r4, r5
+
+	cmpldi	7, r4, 0
+	beq+	7, 0f
+	li	r4, 1
+0:
+	mr	r5, r3
+	mr	r3, r4
+	mr	r4, r5
+	blr
+/*****************************************************************************
+ * checkLogPartition:	check Partition Header entries and Checksum
+ *			check also the NVRAM-Log-Partition CRC
+ *			if Partition is not ok set the following bits to 1
+ *			bit 1:	if Partiton Header Checksum is corrupt
+ *			bit 2: 	if CRC is corrupt
+ *			bit 3: 	if Header entries are corrupt
+ *						
+ *	input:	
+ *		r3 - NVRAM log address (BASE + NVRAM_LOG_OFFSET)
+ *
+ *	output:	
+ *		r3 - CRC status  
+ *		r4 - NVRAM log address
+ *
+ *	Modifies Register:	R3, R4, R5, R6, R7, R8, R9
+ ****************************************************************************/
+ASM_ENTRY(.checkLogPartition)
+	mflr	r8
+	mr      r4, r3                  // emulate "bl updateCRC_NVRAM"
+	li      r3, 0                   // with successfull CRC check
+	li      r7, 0
+	cmpwi   7, r3, 0
+	beq+    7, 0f
+	li      r7, 2
+0:
+	mr	r3, r4
+	bl 	.calPartitionHeaderChecksum	// r3=checksum, r4=NVARM addr
+	lbz	r6, LLFW_LOG_POS_CHECKSUM(r4)
+	cmpw	7, r3, r6
+	beq+	7, 0f			// cal checksum must eq checksum
+	ori	r7, r7, 1
+0:
+	cmpwi	7, r3, 0
+	bne+	7, 0f
+	ori	r7, r7, 1		// 0 as checksum is invalid
+0:
+	mr	r3, r4
+	bl	checkLogHeaderData	
+	cmpdi	7, r3, 0
+	beq+	7, 0f
+	ori	r7, r7, 4
+0:
+	mr	r3, r7
+	mtlr	r8
+	blr
+/*****************************************************************************
+ * checkinitLog:	check the NVRAM Log Partition Header 
+ *			initialize the NVRAM if the Header was modified
+ *					
+ *	input:	
+ *		r3 - NVRAM BASE address 
+ *
+ *	output:	
+ *		r3 - 0 = check ok, no new header written
+ *		r3 - 1 = check not ok, header and NVRAM initialized
+ *		r4 - NVRAM log address
+ *
+ *	Modifies Register:	R3, R4, R5, R6, R7, r8, r9
+ ****************************************************************************/
+// init is done if checkLogPartiton returns not 0 (= check failed)
+ASM_ENTRY(.checkinitLog)
+ASM_ENTRY(checkinitLog)
+	mflr	r9
+	bl 	.checkLogPartition		//r3..r8, r4_out = r3_in   
+	mtlr	r9
+	
+	cmpwi	7, r3, 0
+	mr	r3, r4			// r3=NVRAM_LOG address
+	bne-	7, .initLog		// if header is not ok, init header
+	li	r3, 0
+	blr				// header OK, return 0			
+
+
+/* this is basically just a copy of .initLog 
+   registers used: r3, r4, r5, r6, r7, r9*/
+init_log_2nd_be:
+	mflr	r9	
+	li	r6, LLFW_LOG_BE0_LENGTH
+	mulli	r6, r6, 0x10
+	add	r6, r7, r6
+	li      r5, LLFW_LOG_BE1_SIGNATURE
+	li      r4, LLFW_LOG_BE1_LENGTH
+	stb     r5, 0(r6)
+	sth     r4, LLFW_LOG_POS_LENGTH(r6)
+	li      r5, LLFW_LOG_BE1_DATA_OFFSET
+	li      r4, LLFW_LOG_BE1_FLAGS
+	sth     r5, LLFW_LOG_POS_DATA_OFFSET(r6)
+	sth     r4, LLFW_LOG_POS_FLAGS(r6)
+	li      r5, 1
+
+	LOAD32( r4, LLFW_LOG_BE1_NAME_PREFIX)
+	stw     r5, LLFW_LOG_POS_POINTER(r6)
+	stw     r4, (LLFW_LOG_POS_NAME+0x00)(r6)
+	LOAD64( r5, LLFW_LOG_BE1_NAME)
+	std     r5, (LLFW_LOG_POS_NAME+0x04)(r6)
+	mr	r3, r6
+	bl 	.calPartitionHeaderChecksum
+	stb     r3, LLFW_LOG_POS_CHECKSUM(r6)
+	mtlr	r9
+	blr
+/*****************************************************************************
+ * initLog:	initialize the NVRAM with 0
+ *		write a new NVRAM Log-Partition-Header
+ *					
+ *	input:	
+ *		r3 - NVRAM BASE address 
+ *
+ *	output:	
+ *		r3 - 0 = check ok, no new header written
+ *		r3 - 1 = check not ok, header and NVRAM initialized
+ *		r4 - NVRAM log address
+ *
+ *	Modifies Register:	R3, R4, R5, R6, R7, r8, r9
+ ****************************************************************************/
+ASM_ENTRY(.initLog)
+ 	mflr    r8
+	mr	r7, r3
+
+	bl clearNVRAM
+0:
+	li      r5, LLFW_LOG_BE0_SIGNATURE
+	li      r4, LLFW_LOG_BE0_LENGTH
+	stb     r5, 0(r7)
+	sth     r4, LLFW_LOG_POS_LENGTH(r7)
+	li      r5, LLFW_LOG_BE0_DATA_OFFSET
+	li      r4, LLFW_LOG_BE0_FLAGS
+	sth     r5, LLFW_LOG_POS_DATA_OFFSET(r7)
+	sth     r4, LLFW_LOG_POS_FLAGS(r7)
+	li      r5, 1
+
+	LOAD32( r4, LLFW_LOG_BE0_NAME_PREFIX)
+	stw     r5, LLFW_LOG_POS_POINTER(r7)
+	stw     r4, (LLFW_LOG_POS_NAME+0x00)(r7)
+	LOAD64( r5, LLFW_LOG_BE0_NAME)
+	std     r5, (LLFW_LOG_POS_NAME+0x04)(r7)
+	bl 	.calPartitionHeaderChecksum
+	stb     r3, LLFW_LOG_POS_CHECKSUM(r7)
+	bl	init_log_2nd_be			// create a second log partition for BE1
+	mr	r4, r7
+	li	r3, 1
+	mtlr 	r8
+	blr
+/*****************************************************************************
+ *	clearNVRAM:	set all not used NVRAM memory to zero
+ *
+ *
+ *	input:	
+ *		R3 - NVRAM BASE ADDRESS
+ *
+ *	output:	
+ *		R3 - NVARM END ADDRESS
+ *
+ *	Modifies Register: r4, r5
+ ****************************************************************************/
+ASM_ENTRY(clearNVRAM)
+	LOAD64(	r4, NVRAM_LENGTH)
+	srdi	r4, r4, 3
+	mtctr	r4
+	li	r5, 0x0
+	LOAD64(	r4, NVRAM_EMPTY_PATTERN)
+0:
+	stdx	r4, r3,r5
+	addi	r5, r5, 8
+	bdnz+	0b
+	blr	
+/*****************************************************************************
+ * writeNVRAMbyte:	write next log into NVRAM
+ *					
+ *
+ *	input:	
+ *		R3 - byte to be written
+ *		R4 - NVRAM Base Address
+ *
+ *	output:	
+ *		R3 - byte that was written
+ *		R4 - NVRAM Base Address 
+ *
+ * 	Modifies Register:	R3, R4, R5, R6
+ ****************************************************************************/
+ASM_ENTRY(.writeNVRAMbyte)
+ENTRY(writeLogByte)
+	NVRAM_POINTER_DATASIZE_BE0( r5, r6, r4)	// get pointer,size of data
+	NVRAM_LOG_DATA_OVERFLOW( r5, r6)	// check for overflow
+	addi    r5, r5, 1                       // increment pointer
+	stw     r5, LLFW_LOG_POS_POINTER(r4)    // store pointer
+	addi    r5, r5, -1			// restore old pointer
+	add     r6, r4, r5                      // byte address in data section 
+
+	stb 	r3, LLFW_LOG_BE0_DATA_OFFSET(r6)	
+	blr
+
+/*****************************************************************************
+ * writeNVRAMbyte:	write next log into NVRAM
+ *					
+ *
+ *	input:	
+ *		R3 - byte to be written
+ *		R4 - NVRAM Base Address
+ *
+ *	output:	
+ *		R3 - byte that was written
+ *		R4 - NVRAM Base Address 
+ *
+ * 	Modifies Register:	R3, R4, R5, R6
+ ****************************************************************************/
+ENTRY(writeLogByteBE1)
+	li	r6, LLFW_LOG_BE0_LENGTH
+	mulli	r6, r6, 0x10
+	add	r4, r6, r4
+	NVRAM_POINTER_DATASIZE_BE1( r5, r6, r4)	// get pointer,size of data
+	NVRAM_LOG_DATA_OVERFLOW( r5, r6)	// check for overflow
+	addi    r5, r5, 1                       // increment pointer
+	stw     r5, LLFW_LOG_POS_POINTER(r4)    // store pointer
+	addi    r5, r5, -1			// restore old pointer
+	add     r6, r4, r5                      // byte address in data section 
+
+	stb 	r3, LLFW_LOG_BE1_DATA_OFFSET(r6)	
+	blr
+
+/*****************************************************************************
+ * calPartitionHeaderChecksum: 	calculate the Checksum of the 
+ *	Partition Header as described in ....
+ *
+ *	input: r3 - NVRAM BASE adresse
+ *
+ *	output:	R3 - the calculated checksum as 8 bit value 
+ *			R4 - NVRAM log address
+ *
+ *	Modifies Register:	R3, R4, R5, R6
+ ****************************************************************************/
+ASM_ENTRY(.calPartitionHeaderChecksum)
+	mr	r6, r3
+	lbz 	r3,0(r6)			// load first byte
+	LOAD64( r4, LLFW_LOG_POS_LENGTH)	// load position of 3rd byte
+.L6:
+	lbzx 	r5, r4, r6			// r5  nexed byte
+	addi 	r4, r4, 1			// r4++ (index)
+	add 	r5, r5, r3			// r5 new sum =sum +  nexed byte
+	rldicl 	r5, r5, 0, 56
+	cmpld 	7, r5, r3					
+	cmpldi 	6, r4, LLFW_LOG_POS_DATA_OFFSET
+	bge+ 	7,.L5				// if new sum > sum 
+	addi 	r5, r5, 1			// new sum ++
+	rldicl	r5, r5, 0, 56
+.L5:
+	mr 	r3,r5				// sum = new sum
+	blt+ 	6,.L6
+
+	mr r4, r6
+	blr
+
+#else	/* defined(DISABLE_NVRAM) */
+
+ASM_ENTRY(.writeNVRAMbyte)
+	ENTRY(writeLogByte)
+	blr
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/llfw/romfs.S b/qemu-0.15.x/roms/SLOF/llfw/romfs.S
new file mode 100644
index 0000000..325f79e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/romfs.S
@@ -0,0 +1,362 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include "macros.h"
+#include "romfs.h"
+
+/*******************************************************************
+ * Wrapper for romfs_lookup.
+ *
+ * Input:
+ * R3 = address of filename string
+ * R4 = address of struct romfs_t
+ *		 0: file size (return)
+ *		 8: flags     (return)
+ *		10: fileaddr  (return and input: tells if first search)
+ *		18: nextfile  (return)
+ *		20: namep     (return)
+ *
+ * Find File Procedure
+ * - set filename and rombase, on return 0 file properties are stored
+ *   in romfs_t else struct not valid
+ * 
+ * Listing procedure
+ * - clear romfs_t (important!)
+ * - set filename = NULL and rombase and call returns first file 
+ *   with properties in romfs_t including next-file pointer
+ * - if nextpointer is non-zero then just the next file is returned
+ *
+ * Returns:
+ * <Success>: 
+ *      R3 = 0
+ *	romfs_t is updated
+ * <FileNotFound>:
+ *      R3 = 1
+ * 	romfs_t not touched
+ *
+ * Potentially modifies the following registers:
+ *
+ 
+ Example usage from C:
+
+  int list_bootrom()
+  {
+	struct romfs_t rfs;
+	int i;
+
+	printf("Build: "__TIME__" "__DATE__" \n");
+
+	i = 0;
+	memset((void*) &rfs, 0, sizeof(struct romfs_t));
+	printf("         No. File      Data          Size  Name\n");
+
+	while (romfs_stat(NULL, &rfs) == 0) {
+		i++;
+		printf("         %02d: %08X  %08X   %7d  %s\n",
+				i, rfs.fileaddr, rfs.datap, 
+				rfs.size, rfs.namep);
+	}
+	if (0 == i) {
+		printf("Error in reading ROMFS\n");
+		return 1;
+	}
+	return 0;
+  }
+ *******************************************************************/
+#define RFS_T_SIZE	0x00
+#define RFS_T_FLAGS	0x08
+#define RFS_T_FILEADDR	0x10
+#define RFS_T_NEXT	0x18
+#define RFS_T_NAME	0x20
+#define RFS_T_DATA	0x28
+
+#define RFS_H_NEXT	0x00
+#define RFS_H_SIZE	0x08
+#define RFS_H_FLAGS	0x10
+#define RFS_H_DATA	0x18
+#define RFS_H_NAME	0x20
+
+ENTRY(romfs_stat_file)
+	/* save link register and romfs_t pointer         */
+	mflr	r15
+	mr	r16, r4
+
+	/* if filename R3 is 0 then its a listing request */
+	/* if not then just continue to lookup name       */
+	/* save R4 to R8 which is the address of header   */
+	li	r7, 0
+	cmpd	r3, r7
+	beq	romfs_list
+	bl	romfs_lookup
+	mfsprg	r8, 1
+
+	/* if file found then go to romfs_fill_properties */
+	/* else return 1 to caller                        */
+	cmpwi	r3, 0
+	beq	romfs_fill_properties
+	b	romfs_stat_end
+
+  romfs_list:
+	/* check if fileaddr == 0, in this case its       */
+	/* the first search on this handle, so return all */
+	/* info for file at rombase (R8=R4)               */
+	ld	r6, RFS_T_FILEADDR(r4)
+	mfsprg	r8, 1
+	li	r7, 0
+	cmpd	r7, r6
+	beq	romfs_fill_properties
+
+	/* check if next file != 0   by looking into      */
+	/* romfs_t, if not then return (next = 0) 1       */
+	li	r7, 0
+	ld	r4, RFS_T_NEXT(r4)
+	cmpd	r7, r4
+	li	r3, 1
+	beq	romfs_stat_end
+
+	/* now next file is available so move R8 to next  */
+	/* file address                                   */
+	mr	r8, r4
+
+  romfs_fill_properties:
+	/* set properties in romfs_t takes R8 as address  */
+	/* to file header and R16 as address of romfs_t   */
+	mfsprg	r3, 1
+	std	r8, RFS_T_FILEADDR(r16)
+
+	ld	r4, RFS_H_NEXT(r8)
+	li	r7, 0
+	cmpd	r7, r4
+	beq	$ + (2 * 4) /* =0 so add no rombase */
+	add	r4, r4, r3
+	std	r4, RFS_T_NEXT(r16)
+
+	ld	r4, RFS_H_SIZE(r8)
+	std	r4, RFS_T_SIZE(r16)
+	ld	r4, RFS_H_FLAGS(r8)
+	std	r4, RFS_T_FLAGS(r16)
+
+	ld	r4, RFS_H_DATA(r8)
+	add	r4, r4, r3
+	std	r4, RFS_T_DATA(r16)
+
+	addi	r4, r8, RFS_H_NAME
+	std	r4, RFS_T_NAME(r16)
+
+	li	r3, 0
+
+	/* restore romfs_t pointer and link register      */
+  romfs_stat_end:
+	mr	r5, r16
+	mtlr	r15
+	blr
+
+/*******************************************************************
+ * Copies the data of file referenced by name string to address 
+ * requires root address of filesystem.
+ * FIXME: ignores flags
+ *
+ * Input:
+ * R3 = address of filename string
+ * R4 = ROMBASE
+ * R5 = destination address
+ *
+ * Returns:
+ * <Success>: R3 = 0, R6 = size, <FileNotFound>: R3 = 1
+ * R5 is kept
+ *  
+ * Potentially modifies the following registers:
+ * ctr, r15, r16, r17, r18
+ * 
+ * Uses the following calls with subsequent register modification:
+ * - romfs_lookup
+ *******************************************************************/
+ASM_ENTRY(romfs_load)
+	mflr	r15
+	
+	/* save R5 twice              */
+	/* lookup file, input regs    */
+	/* are already set            */
+	/* if not found, just return  */
+	mr	r16, r5
+	mr	r17, r5
+	bl	romfs_lookup
+	cmpwi	r3, 1
+	bne	0f
+	mtlr	r15
+	blr     /* abort, not found   */
+
+	/* save data size for return  */
+	/* found, copy data           */
+	/* data size is in R6         */
+0:
+	//mr	r3, r6
+	mtctr	r6
+	addi	r16, r16, -1 /* dest  */
+	addi	r5, r5, -1   /* source*/
+
+	/* data is expected to be     */
+	/* 8 byte aligned             */
+	/* copy loop                  */
+0:	lbzu	r18, 1(r5)
+	stbu	r18, 1(r16)
+	bdnz	0b
+
+	/* restore size, keep padding */
+	/* restore target address     */
+	/* return                     */
+	mr	r5, r17
+	mtlr	r15
+	blr
+
+/*******************************************************************
+ * looks up a file based on filename 
+ *
+ * Input:
+ * R3 = address of filename string
+ * R4 = ROMBASE
+ *
+ * Returns:
+ * <Success>: 
+ *      R3 = 0
+ *      R4 = address of file header
+ *      R5 = address of data (real address)
+ *      R6 = size of data
+ *      R7 = flags for file
+ * <FileNotFound>:
+ *      R3 = 1
+ *
+ * Potentially modifies the following registers:
+ * R3, R4, R5, R6, R7, R8, R9
+ * 
+ * Uses the following calls with subsequent register modification:
+ * - romfs_namematch
+ *******************************************************************/
+ASM_ENTRY(romfs_lookup)
+	mflr	r9
+	
+  romfs_lookup_next:
+  	/* save current file base        */
+	mr	r8, r4
+  	/* name to look for              */
+	mr	r10, r3 
+	/* name of file                  */
+	mr	r5,  r4
+	addi	r5,  r5, (4 /* elems     */ * 8 /* elem-size */)
+	mr	r11, r5 /* for namematch */
+	/* compare                       */
+	bl	romfs_namematch
+	cmpwi	r12, 1
+	bne	romfs_lookup_match
+
+	/* load next pointer             */
+	/* check if next is 0            */
+	/* apply root-offset             */
+	ld	r5, 0(r4)
+	cmpwi	r5, 0
+	add	r4, r4, r5
+	bne	romfs_lookup_next
+	/* last file reached, abort      */
+	li	r3, 1
+	mtlr	r9
+	blr
+
+	/* here the name did match       */
+	/* r4 is still usable here and   */
+	/* pointing to the initial file  */
+	/* load r5 with data ptr         */
+	/* load r6 with data size        */
+	/* load r7 with flags            */
+	/* get abs addr of data          */
+  romfs_lookup_match:
+	li	r3, 0
+	ld	r5, (3 * 8)(r4) /* data  */
+	ld	r6, (1 * 8)(r4) /* len   */
+	ld	r7, (2 * 8)(r4) /* flags */
+	add	r5, r5, r8
+	mtlr	r9
+	blr
+
+/*******************************************************************
+ * compares two strings in memory, 
+ * both must be null-terminated and 8-byte aligned
+ *
+ * Input:
+ * R10 = string 1
+ * R11 = string 2
+ *
+ * Returns:
+ * <Match>: R12 = 0 <NoMatch>: R12 = 1
+ *
+ * Potentially modifies the following registers:
+ * R10, R11, r12, r13, r14 
+ *******************************************************************/
+romfs_namematch:
+	subi	r10, r10, 8
+	subi	r11, r11, 8
+
+	/* 
+	 * load chars as 8byte chunk from current pos, name is 
+	 * always 8 byte aligned :)
+	 */
+  romfs_cmp_loop:
+	ldu	r13, 8(r10) /* A */
+	ldu	r14, 8(r11) /* B */
+
+	cmpd	r13, r14
+	li	r12, 1
+	beq	1f
+	blr
+
+1:	andi.	r14, r14, 0xff
+	bne	romfs_cmp_loop
+
+	li	r12, 0
+	blr
+
+/*******************************************************************
+ * wrapper for romfs_lookup
+ * this function saves the registers from r13 - r15 on the stack
+ * calls romfs_lookup
+ * restores the saved registers
+ *
+ * the return parameters are copied to (r5) and (r5) has to
+ * be 0x20 big
+ *******************************************************************/
+ENTRY(c_romfs_lookup)
+	stdu	r1,-0x50(r1)		# allocate space on stack
+
+	mflr	r0			# save link register
+	std	r0,0x30(r1)
+
+	std	r15,0x38(r1)		# save r15
+	std	r14,0x40(r1)		# save r14
+	std	r13,0x48(r1)		# and r13
+	
+	mr	r15,r5			# save the pointer for the return value
+
+	bl	romfs_lookup		# do the thing
+
+	ld	r0,0x30(r1)		# restore link register
+	mtlr	r0
+
+	std	r4,0x00(r15)		# copy return values
+	std	r5,0x08(r15)		# to the return pointer
+	std	r6,0x10(r15)
+	std	r7,0x18(r15)
+
+	ld	r13,0x48(r1)		# restore registers from stack
+	ld	r14,0x40(r1)
+	ld	r15,0x38(r1)
+
+	addi	r1,r1,0x50		# cleanup stack
+
+	blr
diff --git a/qemu-0.15.x/roms/SLOF/llfw/romfs_wrap.c b/qemu-0.15.x/roms/SLOF/llfw/romfs_wrap.c
new file mode 100644
index 0000000..323d975
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/llfw/romfs_wrap.c
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <romfs.h>
+
+int romfs_stat(char *filename, struct romfs_t *hnd)
+{
+	asm volatile ("":::"3","4","5","6","7","9","10");
+	asm volatile ("":::"11","12");
+	asm volatile ("":::"13","14","15","16","17","18");
+
+	return romfs_stat_file(filename, hnd);
+}
diff --git a/qemu-0.15.x/roms/SLOF/make.rules b/qemu-0.15.x/roms/SLOF/make.rules
new file mode 100644
index 0000000..2ecf809
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/make.rules
@@ -0,0 +1,68 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+#############################################################################
+# BUILD ENV SETTINGS
+#############################################################################
+
+# CROSS is the prefix of your cross-compiler.
+# You can override this variable in your environment (export CROSS=...).
+CROSS		?= powerpc64-linux-
+
+CELLSIZE	?= 64
+
+HOSTCC		?= gcc
+HOSTCFLAGS	= -g -Wall -W -O2 -I. -I../include
+DD		= dd
+
+ONLY_CC 	= $(CROSS)gcc -m$(CELLSIZE)
+ONLY_AS 	= $(CROSS)as -m$(CELLSIZE)
+ONLY_LD 	= $(CROSS)ld -melf$(CELLSIZE)ppc
+
+# Verbose level:
+#   V=0 means completely silent
+#   V=1 means brief output
+#   V=2 means full output
+V		?= 1
+
+ifeq ($(V),0)
+Q		:= @
+MAKEFLAGS	+= --silent
+MAKE		+= -s
+endif
+
+ifeq ($(V),1)
+MAKEFLAGS	+= --silent
+MAKE		+= -s
+CC		= printf "\t[CC]\t%s\n" `basename "$@"`; $(ONLY_CC)
+AS		= printf "\t[AS]\t%s\n" `basename "$@"`; $(ONLY_AS)
+LD		= printf "\t[LD]\t%s\n" `basename "$@"`; $(ONLY_LD)
+CLEAN		= printf "\t[CLEAN]\t%s\n" "$(DIRECTORY)$$dir"
+else
+CC		= $(ONLY_CC)
+AS		= $(ONLY_AS)
+LD		= $(ONLY_LD)
+CLEAN		= echo -n
+endif
+
+OBJCOPY 	?= $(CROSS)objcopy
+OBJDUMP 	?= $(CROSS)objdump
+STRIP		?= $(CROSS)strip
+AR		?= $(CROSS)ar
+RANLIB		?= $(CROSS)ranlib
+CPP		?= $(CROSS)cpp
+
+CFLAGS ?= -g -O2 -fno-builtin -ffreestanding -nostdinc -msoft-float \
+	  -mno-altivec -mabi=no-altivec -Wall -fno-stack-protector
+
+export CC AS LD CLEAN OBJCOPY OBJDUMP STRIP AR RANLIB CFLAGS
+
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/Makefile b/qemu-0.15.x/roms/SLOF/other-licence/Makefile
new file mode 100644
index 0000000..fb5397d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/Makefile
@@ -0,0 +1,31 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+SUBDIRS=common bcm
+ifeq ($(SNK_BIOSEMU_APPS), 1)
+SUBDIRS += x86emu
+endif
+CLEANSUBDIRS = $(SUBDIRS) 
+
+
+all :		
+		for subdir in $(SUBDIRS) ; do $(MAKE) -C $${subdir} || exit 1 ; done
+
+# Common targets for all subdirectories:
+clean distclean depend:		
+		for subdir in $(CLEANSUBDIRS) ; do $(MAKE) -C $${subdir} $@ ; done
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/bcm/Makefile b/qemu-0.15.x/roms/SLOF/other-licence/bcm/Makefile
new file mode 100644
index 0000000..b7b386d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/bcm/Makefile
@@ -0,0 +1,57 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS = -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc
+
+SRCS   = bcm57xx.c
+
+COMMONOBJS = ../common/module_entry.o
+
+OBJS   += $(COMMONOBJS) $(SRCS:.c=.o)
+
+
+all:		Makefile.dep net_bcm57xx.bin
+
+bcm57xx_net.o:  $(OBJS) 
+		$(LD) $(LDFLAGS) $^ -o $@ -T ../common/module.lds -N
+
+net_bcm57xx.bin: bcm57xx_net.o
+		$(OBJCOPY) -O binary $^ $@ 
+
+# A rule for making the object files in the common directory:
+../common/%.o: ../common/%.c
+	$(MAKE) -C ../common all
+
+
+clean:		
+		$(RM) -f *.o *.a *.i *.bin
+
+distclean : clean
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+		$(CC) -MM $(CFLAGS) $(SRCS) > Makefile.dep
+Makefile.dep:
+		$(MAKE) depend
+
+# Include dependency file if available:
+ifneq (,$(wildcard Makefile.dep))
+include Makefile.dep
+endif
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.c b/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.c
new file mode 100644
index 0000000..65b319b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.c
@@ -0,0 +1,3428 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ *
+ ******************************************************************************
+ * reference:
+ * Broadcom 57xx
+ * Host Programmer Interface Specification for the
+ * NetXtreme Family of Highly-Integrated Media Access Controlers
+ */
+#include "types.h"
+#include "bcm57xx.h"
+
+
+/*
+ * local defines
+ ******************************************************************************
+ */
+
+
+// #define BCM_VLAN_TAG    ( (u32_t) 0x1 )
+
+// number of tx/rx rings
+// NOTE: 5714 only uses 1 rx/tx ring, but memory
+// for the other rings is cleaned anyways for
+// sanity & future use
+#define BCM_MAX_TX_RING         16
+#define BCM_MAX_RXRET_RING      16
+#define BCM_MAX_RXPROD_RCB       3
+
+// bd descriptions
+#define BCM_RXPROD_RING_SIZE     512    // don't change
+#define BCM_RXRET_RING_SIZE	 512    // don't change
+#define BCM_TX_RING_SIZE         512    // don't change
+#define BCM_BUF_SIZE            1536    // don't change
+#define BCM_MTU_MAX_LEN         1522
+#define BCM_MAX_RX_BUF            64
+#define BCM_MAX_TX_BUF            16
+
+// number of MAC addresses in NIC
+#define BCM_NUM_MAC_ADDR	   4
+#define BCM_NUM_MAC5704_ADDR	  12
+// offset of mac address field(s) in bcm register space
+#define MAC5704_ADDR_OFFS	( (u16_t) 0x0530 )
+
+// offset of NIC memory start address from base address
+#define BCM_MEMORY_OFFS         ( (u64_t) 0x8000 )
+
+// offset of statistics block in NIC memory
+#define BCM_STATISTIC_OFFS	( (u64_t) 0x0300 )
+// size of statistic block in NIC memory
+#define BCM_STATISTIC_SIZE	0x800
+
+// offsets of NIC rx/tx rings in NIC memory
+#define BCM_NIC_TX_OFFS		( (u16_t) 0x4000 )
+#define BCM_NIC_RX_OFFS		( (u16_t) 0x6000 )
+#define BCM_NIC_TX_SIZE		( (u16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) )
+
+// device mailboxes
+#define BCM_FW_MBX          	( (u16_t) 0x0b50 )
+#define BCM_FW_MBX_CMD      	( (u16_t) 0x0b78 )
+#define BCM_FW_MBX_LEN      	( (u16_t) 0x0b7c )
+#define BCM_FW_MBX_DATA     	( (u16_t) 0x0b80 )
+#define BCM_NICDRV_STATE_MBX	( (u16_t) 0x0c04 )
+
+// device mailbox commands
+#define BCM_NICDRV_ALIVE	( (u32_t) 0x00000001 )
+#define BCM_NICDRV_PAUSE_FW	( (u32_t) 0x00000002 )
+
+// device values
+#define BCM_MAGIC_NUMBER           	( (u32_t) 0x4b657654 )
+
+// device states
+#define NIC_FWDRV_STATE_START      	( (u32_t) 0x00000001 )
+#define NIC_FWDRV_STATE_START_DONE 	( (u32_t) 0x80000001 )
+#define NIC_FWDRV_STATE_UNLOAD     	( (u32_t) 0x00000002 )
+#define NIC_FWDRV_STATE_UNLOAD_DONE	( (u32_t) 0x80000002 )
+#define NIC_FWDRV_STATE_SUSPEND    	( (u32_t) 0x00000004 )
+
+// timer prescaler value
+#define BCM_TMR_PRESCALE        ( (u32_t) 0x41 )
+
+// offset of transmit rcb's in NIC memory
+#define BCM_TX_RCB_OFFS         ( (u16_t) 0x0100 )
+// offset of receive return rcb's in NIC memory
+#define BCM_RXRET_RCB_OFFS      ( (u16_t) 0x0200 )
+
+// register offsets for ring indices
+#define TX_PROD_IND             ( (u16_t) 0x0304 )
+#define TX_CONS_IND             ( (u16_t) 0x3cc0 )
+#define RXPROD_PROD_IND         ( (u16_t) 0x026c )
+#define RXPROD_CONS_IND         ( (u16_t) 0x3c54 )
+#define RXRET_PROD_IND          ( (u16_t) 0x3c80 )
+#define RXRET_CONS_IND          ( (u16_t) 0x0284 )
+// NIC producer index only needed for initialization
+#define TX_NIC_PROD_IND         ( (u16_t) 0x0384 )
+
+/*
+ * predefined register values used during initialization
+ * may be adapted by user
+ */
+#define DMA_RW_CTRL_VAL_5714    ( (u32_t) 0x76144000 )
+#define DMA_RW_CTRL_VAL         ( (u32_t) 0x760F0000 )
+#define TX_MAC_LEN_VAL          ( (u32_t) 0x00002620 )
+
+#define RX_LST_PLC_CFG_VAL      ( (u32_t) 0x00000109 )
+#define RX_LST_PLC_STAT_EN_VAL  ( (u32_t) 0x007e000f )
+#define NVM_ADDR_MSK            ( (u32_t) 0x000fffff )
+
+// Number of Receive Rules /w or /wo SOL enabled
+#define RX_RULE_CFG_VAL		( (u32_t) 0x00000008 )
+#define NUM_RX_RULE		( (u32_t) 16 )
+#define NUM_RX_RULE_ASF		( (u32_t) ( NUM_RX_RULE - 4 ) )
+
+// RCB register offsets
+#define BCM_RXPROD_RCB_JUM      ( (u16_t) 0x2440 )
+#define BCM_RXPROD_RCB_STD      ( (u16_t) 0x2450 )
+#define BCM_RXPROD_RCB_MIN      ( (u16_t) 0x2460 )
+
+// macros needed for new addressing method
+#define BCM_RCB_HOSTADDR_HI_u16( rcb )	( (u16_t) rcb + 0x00 )
+#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (u16_t) rcb + 0x04 )
+#define BCM_RCB_LENFLAG_u16( rcb )      ( (u16_t) rcb + 0x08 )
+#define BCM_RCB_NICADDR_u16( rcb )      ( (u16_t) rcb + 0x0c )
+#define BCM_RCB_SIZE_u16		( (u16_t) 0x0010 )
+
+// RCB flags
+#define RCB_FLAG_RING_DISABLED  BIT32( 1 )
+
+// BCM device ID masks
+#define BCM_DEV_5714   ( (u64_t) 0x1 )
+#define BCM_DEV_5704   ( (u64_t) 0x2 )
+#define BCM_DEV_5703   ( (u64_t) 0x4 )
+#define BCM_DEV_SERDES ( (u64_t) 0x80000000 )
+#define BCM_DEV_COPPER ( (u64_t) 0x40000000 )
+
+#define IS_5714        ( ( bcm_device_u64 & BCM_DEV_5714 ) != 0 )
+#define IS_5704        ( ( bcm_device_u64 & BCM_DEV_5704 ) != 0 )
+#define IS_5703        ( ( bcm_device_u64 & BCM_DEV_5703 ) != 0 )
+#define IS_SERDES      ( ( bcm_device_u64 & BCM_DEV_SERDES ) != 0 )
+#define IS_COPPER_PHY  ( ( bcm_device_u64 & BCM_DEV_COPPER ) != 0 )
+
+#define BUFFERED_FLASH_PAGE_POS		9
+#define BUFFERED_FLASH_BYTE_ADDR_MASK	((<<BUFFERED_FLASH_PAGE_POS) - 1)
+#define BUFFERED_FLASH_PAGE_SIZE	264
+#define BUFFERED_FLASH_PHY_SIZE		512
+#define MANUFACTURING_INFO_SIZE		140
+#define CRC32_POLYNOMIAL		0xEDB88320
+
+/*
+ * local types
+ ******************************************************************************
+ */
+typedef struct {
+	u32_t m_dev_u32;
+	u64_t m_devmsk_u64;
+}	bcm_dev_t;
+
+/*
+ * BCM common data structures
+ * BCM57xx Programmer's Guide: Section 5
+ */
+
+/*
+ * 64bit host address in a way the NIC is able to understand it
+ */
+typedef struct {
+	u32_t m_hi_u32;
+	u32_t m_lo_u32;
+}	bcm_addr64_t;
+/*
+ * ring control block
+ */
+typedef struct {
+	bcm_addr64_t m_hostaddr_st;
+	u32_t        m_lenflags_u32;	// upper 16b: len, lower 16b: flags
+	u32_t        m_nicaddr_u32;
+}	bcm_rcb_t;
+
+/*
+ * tx buffer descriptor
+ */
+typedef struct {
+	bcm_addr64_t m_hostaddr_st;
+	u32_t        m_lenflags_u32;	// upper 16b: len, lower 16b: flags
+	u32_t        m_VLANtag_u32;	// lower 16b: vtag
+}       bcm_txbd_t;
+
+/*
+ * rx buffer descriptor
+ */
+typedef struct {
+	bcm_addr64_t m_hostaddr_st;
+	u32_t        m_idxlen_u32;	// upper 16b: idx, lower 16b: len
+	u32_t        m_typeflags_u32;	// upper 16b: type, lower 16b: flags
+	u32_t        m_chksum_u32;	// upper 16b: ip, lower 16b: tcp/udp
+	u32_t        m_errvlan_u32;	// upper 16b: err, lower 16b: vlan tag
+	u32_t        m_reserved_u32;
+	u32_t        m_opaque_u32;
+}	bcm_rxbd_t;
+
+/*
+ * bcm status block
+ * NOTE: in fact the status block is not used and configured
+ * so that it is not updated by the NIC. Still it has to be
+ * set up so the NIC is satisfied
+ */
+typedef struct {
+	u32_t   m_st_word_u32;
+	u32_t   m_st_tag_u32;
+	u16_t   m_rxprod_cons_u16;
+	u16_t   m_unused_u16;
+	u32_t   m_unused_u32;
+	u16_t   m_tx_cons_u16;
+	u16_t   m_rxret_prod_u16;
+}	bcm_status_t;
+
+/*
+ * local constants
+ ******************************************************************************
+ */
+static const bcm_dev_t bcm_dev[] = {
+	{ 0x166b, BCM_DEV_5714  		},
+	{ 0x1668, BCM_DEV_5714  		},
+	{ 0x1669, BCM_DEV_5714  		},
+	{ 0x166a, BCM_DEV_5714			},
+	{ 0x1648, BCM_DEV_5704  		},
+	{ 0x1649, BCM_DEV_5704 | BCM_DEV_SERDES },
+	{ 0x16a8, BCM_DEV_5704 | BCM_DEV_SERDES },
+	{ 0x16a7, BCM_DEV_5703 | BCM_DEV_SERDES },
+	{ 0x16c7, BCM_DEV_5703 | BCM_DEV_SERDES },
+	{ 0     , 0             		}
+};
+
+/*
+ * local variables
+ ******************************************************************************
+ */
+static u64_t       bcm_device_u64;
+static u32_t       bcm_rxret_ring_sz;
+static u64_t       bcm_baseaddr_u64;
+static u64_t       bcm_memaddr_u64;
+
+/*
+ * rings & their buffers
+ */
+// the rings made of buffer descriptors
+static bcm_txbd_t  bcm_tx_ring[BCM_TX_RING_SIZE];
+static bcm_rxbd_t  bcm_rxprod_ring[BCM_RXPROD_RING_SIZE];
+static bcm_rxbd_t  bcm_rxret_ring[BCM_RXRET_RING_SIZE*2];
+
+// the buffers used in the rings
+static u08_t       bcm_tx_buffer_pu08[BCM_MAX_TX_BUF][BCM_BUF_SIZE];
+static u08_t       bcm_rx_buffer_pu08[BCM_MAX_RX_BUF][BCM_BUF_SIZE];
+
+// tx ring index of first/last bd
+static u32_t       bcm_tx_start_u32;
+static u32_t       bcm_tx_stop_u32;
+static u32_t       bcm_tx_bufavail_u32;
+
+// PCI device location needed for indirect addressing
+static u64_t       bcm_pcicfg_puid;
+static u08_t       bcm_pcicfg_bus;
+static u08_t       bcm_pcicfg_devfn;
+
+/*
+ * status block
+ */
+static bcm_status_t bcm_status;
+
+/*
+ * snk module interface
+ ******************************************************************************
+ */
+static int bcm_init   ( void );
+static int bcm_term   ( void );
+static int bcm_xmit   ( char *f_buffer_pc, int f_len_i );
+static int bcm_receive( char *f_buffer_pc, int f_len_i );
+static int bcm_ioctl  ( int request, void* data );
+
+snk_module_t snk_module_interface = {
+	.version = 1,
+	.type    = MOD_TYPE_NETWORK,
+	.running = 0,
+	.init    = bcm_init,
+	.term    = bcm_term,
+	.write   = bcm_xmit,
+	.read    = bcm_receive,
+	.ioctl   = bcm_ioctl
+};
+
+/*
+ * implementation
+ ******************************************************************************
+ */
+
+
+/*
+ * global functions
+ ******************************************************************************
+ */
+int
+check_driver( pci_config_t *pci_conf );
+
+
+/*
+ * local helper functions
+ ******************************************************************************
+ */
+static char *
+memcpy( char *dest, const char *src, size_t n )
+{
+        char *ret = dest;
+        while( n-- ) {
+                *dest++ = *src++;
+        }
+
+        return( ret );
+}
+
+static char *
+memset_ci( char *dest, int c, size_t n )
+{
+        char *ret = dest;
+        
+        while( n-- ) {
+                wr08( dest, c );
+		dest++;
+        }
+
+        return( ret );
+}
+
+static char *
+memset( char *dest, int c, size_t n )
+{
+        char *ret = dest;
+        while( n-- ) {
+                *dest++ = (char) c;
+        }
+
+        return( ret );
+}
+
+static u32_t
+bcm_nvram_logical_to_physical_address(u32_t address)
+{
+	u32_t page_no   = address / BUFFERED_FLASH_PAGE_SIZE;
+	u32_t page_addr = address % BUFFERED_FLASH_PAGE_SIZE;
+
+	return (page_no << BUFFERED_FLASH_PAGE_POS) + page_addr;
+}
+
+
+/*
+ * local inline functions for endian swapping
+ ******************************************************************************
+ */
+
+static u16_t
+bswap_16 (u16_t x) {
+	return ((x&0xff00) >> 8)
+	     | ((x&0x00ff) << 8);
+}
+
+u32_t
+static bswap_32 (u32_t x) {
+	return bswap_16((x&0xffff0000) >> 16)
+	     | (bswap_16(x&0x0000ffff) << 16);
+}
+
+/*
+ * read/write functions to access NIC registers & memory
+ * NOTE: all functions are executed with cache inhibitation (dead slow :-) )
+ */
+static u32_t
+bcm_read_mem32( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	return rd32( bcm_memaddr_u64 + (u64_t) f_offs_u16 );
+}
+
+/* not used so far
+static u16_t
+bcm_read_mem16( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	return rd16( bcm_memaddr_u64 + (u64_t) f_offs_u16 );
+}*/
+/* not used so far
+static u08_t
+bcm_read_mem08( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	return rd08( bcm_memaddr_u64 + (u64_t) f_offs_u16 );
+}*/
+
+static u32_t
+bcm_read_reg32_indirect( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        REG_BASE_ADDR_REG,
+	                                        f_offs_u16 );
+	return (u32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                                4,
+	                                                                bcm_pcicfg_bus,
+	                                                                bcm_pcicfg_devfn,
+	                                                                REG_DATA_REG ) ) ;
+}
+
+static u32_t
+bcm_read_reg32( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400)
+		return bcm_read_reg32_indirect( f_offs_u16 + 0x5600 );
+	return rd32( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+}
+
+static u16_t
+bcm_read_reg16( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	return rd16( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+}
+/* not used so far
+static u08_t
+bcm_read_reg08( u16_t f_offs_u16 )
+{       // caution: shall only be used after initialization!
+	return rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+}*/
+
+static void
+bcm_write_mem32_indirect( u16_t f_offs_u16, u32_t f_val_u32 )
+{       // caution: shall only be used after initialization!
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        MEM_BASE_ADDR_REG,
+	                                        f_offs_u16 );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        MEM_DATA_REG,
+	                                        bswap_32 ( f_val_u32 ) );
+}
+
+static void
+bcm_write_mem32( u16_t f_offs_u16, u32_t f_val_u32 )
+{       // caution: shall only be used after initialization!
+	if(f_offs_u16 >= BCM_RXRET_RCB_OFFS &&
+           f_offs_u16 < BCM_RXRET_RCB_OFFS + (BCM_MAX_RXRET_RING*BCM_RCB_SIZE_u16))
+		bcm_write_mem32_indirect( f_offs_u16, f_val_u32 );
+	else if(f_offs_u16 >= BCM_TX_RCB_OFFS &&
+           f_offs_u16 < BCM_TX_RCB_OFFS + (BCM_MAX_TX_RING*BCM_RCB_SIZE_u16))
+		bcm_write_mem32_indirect( f_offs_u16, f_val_u32 );
+	else
+		wr32( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u32 );
+}
+/* not used so far
+static void
+bcm_write_mem16( u16_t f_offs_u16, u16_t f_val_u16 )
+{       // caution: shall only be used after initialization!
+	wr16( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u16 );
+}*/
+/* not used so far
+static void
+bcm_write_mem08( u16_t f_offs_u16, u08_t f_val_u08 )
+{       // caution: shall only be used after initialization!
+	wr08( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u08 );
+}*/
+
+static void
+bcm_write_reg32_indirect( u16_t f_offs_u16, u32_t f_val_u32 )
+{       // caution: shall only be used after initialization!
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        REG_BASE_ADDR_REG,
+	                                        f_offs_u16 );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        REG_DATA_REG,
+	                                        bswap_32 ( f_val_u32 ) );
+}
+
+static void
+bcm_write_reg32( u16_t f_offs_u16, u32_t f_val_u32 )
+{       // caution: shall only be used after initialization!
+	if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400)
+		bcm_write_reg32_indirect( f_offs_u16 + 0x5600, f_val_u32 );
+	else
+		wr32( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u32 );
+}
+
+static void
+bcm_write_reg16( u16_t f_offs_u16, u16_t f_val_u16 )
+{       // caution: shall only be used after initialization!
+	wr16( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u16 );
+}
+/* not used so far
+static void
+bcm_write_reg08( u16_t f_offs_u16, u08_t f_val_u08 )
+{       // caution: shall only be used after initialization!
+        wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u08 );
+}*/
+
+static void
+bcm_setb_reg32( u16_t f_offs_u16, u32_t f_mask_u32 )
+{
+	u32_t v;
+
+	v  = bcm_read_reg32( f_offs_u16 );
+	v |= f_mask_u32;
+	bcm_write_reg32( f_offs_u16, v );
+}
+/* not used so far
+static void
+bcm_setb_reg16( u16_t f_offs_u16, u16_t f_mask_u16 )
+{
+	u16_t v;
+	v  = rd16( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+        v |= f_mask_u16;
+	wr16( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v );
+}*/
+/* not used so far
+static void
+bcm_setb_reg08( u16_t f_offs_u16, u08_t f_mask_u08 )
+{
+	u08_t v;
+	v  = rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+        v |= f_mask_u08;
+	wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v );
+}*/
+
+static void
+bcm_clrb_reg32( u16_t f_offs_u16, u32_t f_mask_u32 )
+{
+	u32_t v;
+
+	v  = bcm_read_reg32( f_offs_u16 );
+	v &= ~f_mask_u32;
+	bcm_write_reg32( f_offs_u16, v );
+}
+
+static void
+bcm_clrb_reg16( u16_t f_offs_u16, u16_t f_mask_u16 )
+{
+	u16_t v;
+
+	v  = bcm_read_reg16( f_offs_u16 );
+	v &= ~f_mask_u16;
+	bcm_write_reg16( f_offs_u16, v );
+}
+/* not used so far
+static void
+bcm_clrb_reg08( u16_t f_offs_u16, u08_t f_mask_u08 )
+{
+	u08_t v;
+	v  = rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 );
+        v &= ~f_mask_u32;
+	wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v );
+}*/
+
+static void
+bcm_clr_wait_bit32( u16_t r, u32_t b )
+{
+	u32_t i;
+
+	bcm_clrb_reg32( r, b );
+
+	i = 1000;
+	while( --i ) {
+
+		if( ( bcm_read_reg32( r ) & b ) == 0 ) {
+			break;
+		}
+
+		us_delay( 10 );
+	}
+#ifdef BCM_DEBUG
+	if( ( bcm_read_reg32( r ) & b ) != 0 ) {
+		printk( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r );
+	}
+#endif
+}
+
+/*
+ * (g)mii bus access
+ */
+#if 0
+// not used so far
+static i32_t
+bcm_mii_write16( u32_t f_reg_u32, u16_t f_value_u16 )
+{
+	static const u32_t WR_VAL = ( ( ((u32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) );
+	i32_t              l_autopoll_i32 = 0;
+	u32_t              l_wrval_u32;
+	u32_t              i;
+
+	/*
+	 * only 0x00-0x1f are valid registers
+	 */
+	if( f_reg_u32 > (u32_t) 0x1f ) {
+		return -1;
+	}
+
+	/*
+	 * disable auto polling if enabled
+	 */
+	if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) {
+		l_autopoll_i32 = (i32_t) !0;
+		bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) );
+		us_delay( 40 );
+	}
+
+	/*
+	 * construct & write mi com register value
+	 */
+	l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (u32_t) f_value_u16 );
+	bcm_write_reg32( MI_COM_R, l_wrval_u32 );
+
+	/*
+	 * wait for transaction to complete
+	 */
+	i = 25;
+	while( ( --i ) &&
+	       ( ( bcm_read_reg32( MI_COM_R ) & BIT32( 29 ) ) != 0 ) ) {
+		us_delay( 10 );
+	}
+
+	/*
+	 * re-enable auto polling if necessary
+	 */
+	if( l_autopoll_i32 ) {
+		bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) );
+	}
+
+	// return on error
+	if( i == 0 ) {
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
+static i32_t
+bcm_mii_read16( u32_t f_reg_u32, u16_t *f_value_pu16 )
+{
+	static const u32_t RD_VAL = ( ( ((u32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) );
+	i32_t l_autopoll_i32 = 0;
+	u32_t l_rdval_u32;
+	u32_t i;
+	u16_t first_not_busy;
+
+	/*
+	 * only 0x00-0x1f are valid registers
+	 */
+	if( f_reg_u32 > (u32_t) 0x1f ) {
+		return -1;
+	}
+
+	/*
+	 * disable auto polling if enabled
+	 */
+	if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) {
+		l_autopoll_i32 = ( i32_t ) !0;
+		bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) );
+		us_delay( 40 );
+	}
+
+	/*
+	 * construct & write mi com register value
+	 */
+	l_rdval_u32 = ( RD_VAL | ( f_reg_u32 << 16 ) );
+	bcm_write_reg32( MI_COM_R, l_rdval_u32 );
+
+	/*
+	 * wait for transaction to complete
+	 * ERRATA workaround: must read two "not busy" states to indicate transaction complete
+	 */
+	i = 25;
+	first_not_busy = 0;
+	l_rdval_u32 = bcm_read_reg32( MI_COM_R );
+	while( ( --i ) &&
+	       ( (first_not_busy == 0) || ( ( l_rdval_u32 & BIT32( 29 ) ) != 0 ) ) ) {
+                /* Is this the first clear BUSY state? */
+		if ( ( l_rdval_u32 & BIT32( 29 ) ) == 0 )
+			first_not_busy++;
+		us_delay( 10 );
+		l_rdval_u32 = bcm_read_reg32( MI_COM_R );
+	}
+
+	/*
+	 * re-enable autopolling if necessary
+	 */
+	if( l_autopoll_i32 ) {
+		bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) );
+	}
+
+	/*
+	 * return on read transaction error
+	 * (check read failed bit)
+	 */
+	if( ( i == 0 ) ||
+	    ( ( l_rdval_u32 & BIT32( 28 ) ) != 0 ) ) {
+		return -1;
+	}
+
+	/*
+	 * return read value
+	 */
+	*f_value_pu16 = (u16_t) ( l_rdval_u32 & (u32_t) 0xffff );
+
+	return 0;
+}
+
+/*
+ * ht2000 dump (not complete)
+ */
+#if 0
+static void
+bcm_dump( void )
+{
+	u32_t i, j;
+
+	printk( "*** DUMP ***********************************************************************\n\n" );
+
+	printk( "* PCI Configuration Registers:\n" );
+	for( i = 0, j = 0; i < 0x40; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Private PCI Configuration Registers:\n" );
+	for( i = 0x68, j = 0; i < 0x88; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* VPD Config:\n" );
+	printk( "%04X: %08X  \n", 0x94, bcm_read_reg32( 0x94 ) );
+
+	printk( "\n* Dual MAC Control Registers:\n" );
+	for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Ethernet MAC Control Registers:\n" );
+	for( i = 0x400, j = 0; i < 0x590; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Send Data Initiator Control:\n" );
+	for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Send Data Completion Control:\n" );
+	printk( "%04X: %08X  ", 0x1000, bcm_read_reg32( 0x1000 ) );
+	printk( "%04X: %08X  \n", 0x1008, bcm_read_reg32( 0x1008 ) );
+	
+	printk( "\n* Send BD Ring Selector Control:\n" );
+	printk( "%04X: %08X  ", 0x1400, bcm_read_reg32( 0x1400 ) );
+	printk( "%04X: %08X  ", 0x1404, bcm_read_reg32( 0x1404 ) );
+	printk( "%04X: %08X  \n", 0x1408, bcm_read_reg32( 0x1408 ) );
+
+	printk( "\n* Send BD Initiator Control:\n" );
+	printk( "%04X: %08X  ", 0x1800, bcm_read_reg32( 0x1800 ) );
+	printk( "%04X: %08X  \n", 0x1804, bcm_read_reg32( 0x1804 ) );
+
+	printk( "\n* Send BD Completion Control:\n" );
+	printk( "%04X: %08X  ", 0x1c00, bcm_read_reg32( 0x1c00 ) );
+
+	printk( "\n* Receive List Placement Control:\n" );
+	for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Receive Data & Receive BD Initiator Control:\n" );
+	printk( "%04X: %08X  ", 0x2400, bcm_read_reg32( 0x2400 ) );
+	printk( "%04X: %08X  \n", 0x2404, bcm_read_reg32( 0x2404 ) );
+
+	printk( "\n* Jumbo Receive BD Ring RCB:\n" );
+	for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Standard Receive BD Ring RCB:\n" );
+	for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Mini Receive BD Ring RCB:\n" );
+	for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\nRDI Timer Mode Register:\n" );
+	printk( "%04X: %08X  \n", 0x24f0, bcm_read_reg32( 0x24f0 ) );
+
+	printk( "\n* Receive BD Initiator Control:\n" );
+	for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+
+	printk( "\n* Receive BD Completion Control:\n" );
+	for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) {
+
+		printk( "%04X: %08X  ", i, bcm_read_reg32( i ) );
+
+		if( ( ++j & 0x3 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+}
+#endif
+
+
+
+/*
+ * NVRAM access
+ */
+
+static int
+bcm_nvram_lock( void )
+{
+	int i;
+
+	/*
+	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+	 */
+//	bcm_setb_reg32( SW_ARB_R, BIT32( 0 ) );
+	bcm_setb_reg32( SW_ARB_R, BIT32( 1 ) );
+
+	i = 2000;
+	while( ( --i ) && 
+//	       ( bcm_read_reg32( SW_ARB_R ) & BIT32( 8 ) ) == 0 ) {
+	       ( bcm_read_reg32( SW_ARB_R ) & BIT32( 9 ) ) == 0 ) {
+		ms_delay( 1 );
+	}
+
+	// return on error
+	if( i == 0 ) {
+#ifdef BCM_DEBUG
+		printk("bcm57xx: failed to lock nvram");
+#endif
+		return -1;
+	}
+
+	return 0;
+}
+
+static void
+bcm_nvram_unlock( void )
+{
+	/*
+	 * release NVRam lock (CLR0)
+	 */
+//	bcm_setb_reg32( SW_ARB_R, BIT32( 4 ) );
+	bcm_setb_reg32( SW_ARB_R, BIT32( 5 ) );
+}
+
+static void
+bcm_nvram_init( void )
+{
+	/*
+	 * enable access to NVRAM registers
+	 */
+	if(IS_5714) {
+		bcm_setb_reg32( NVM_ACC_R, BIT32( 1 ) | BIT32( 0 ) );
+	}
+
+	/*
+	 * disable bit-bang method 19& disable interface bypass
+	 */
+	bcm_clrb_reg32( NVM_CFG1_R, BIT32( 31 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 14 ) | BIT32( 16 ) );
+	bcm_setb_reg32( NVM_CFG1_R, BIT32 ( 13 ) | BIT32 ( 17 ));
+
+	/*
+	 * enable Auto SEEPROM Access
+	 */
+	bcm_setb_reg32( MISC_LOCAL_CTRL_R, BIT32 ( 24 ) );
+
+	/*
+	 * NVRAM write enable
+	 */
+	bcm_setb_reg32( MODE_CTRL_R, BIT32 ( 21 ) );
+}
+
+static i32_t
+bcm_nvram_read( u32_t f_addr_u32, u32_t *f_val_pu32, u32_t lock )
+{
+	u32_t i;
+
+	/*
+	 * parameter check
+	 */
+	if( f_addr_u32 > NVM_ADDR_MSK ) {
+		return -1;
+	}
+
+	/*
+	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+	 */
+	if( lock && (bcm_nvram_lock() == -1) ) {
+		return -1;
+	}
+
+	/*
+	 * setup address to read
+	 */
+	bcm_write_reg32( NVM_ADDR_R,
+		bcm_nvram_logical_to_physical_address(f_addr_u32) );
+//	bcm_write_reg32( NVM_ADDR_R, f_addr_u32 );
+
+	/*
+	 * get the command going
+	 */
+	bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) |
+	                            BIT32( 4 ) | BIT32( 3 ) );
+
+	/*
+	 * wait for command completion
+	 */
+	i = 2000;
+        while( ( --i ) &&
+               ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) {
+		ms_delay( 1 );
+	}
+
+	/*
+	 * read back data if no error
+	 */
+	if( i != 0 ) {
+		/*
+		 * read back data
+		 */
+		*f_val_pu32 = bcm_read_reg32( NVM_READ_R );
+	}
+
+	if(lock)
+		bcm_nvram_unlock();
+
+	// error
+	if( i == 0 ) {
+#ifdef BCM_DEBUG
+		printk("bcm57xx: reading from NVRAM failed\n");
+#endif
+		return -1;
+	}
+
+	// success
+	return 0;
+}
+
+static i32_t
+bcm_nvram_write( u32_t f_addr_u32, u32_t f_value_u32, u32_t lock )
+{
+	u32_t i;
+
+	/*
+	 * parameter check
+	 */
+	if( f_addr_u32 > NVM_ADDR_MSK ) {
+		return -1;
+	}
+
+	/*
+	 * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON)
+	 */
+	if( lock && (bcm_nvram_lock() == -1) ) {
+			return -1;
+	}
+
+	/*
+	 * setup address to write
+	 */
+	bcm_write_reg32( NVM_ADDR_R, bcm_nvram_logical_to_physical_address( f_addr_u32 ) );
+
+	/*
+	 * setup write data
+	 */
+	bcm_write_reg32( NVM_WRITE_R, f_value_u32 );
+
+	/*
+	 * get the command going
+	 */
+	bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) |
+	                            BIT32( 5 ) | BIT32( 4 ) | BIT32( 3 ) );
+
+	/*
+	 * wait for command completion
+	 */
+	i = 2000;
+	while( ( --i ) &&
+	       ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) {
+		ms_delay( 1 );
+	}
+
+	/*
+	 * release NVRam lock (CLR0)
+	 */
+	if(lock)
+		bcm_nvram_unlock();
+
+	// error
+	if( i == 0 ) {
+#ifdef BCM_DEBUG
+		printk("bcm57xx: writing to NVRAM failed\n");
+#endif
+		return -1;
+	}
+
+	// success
+	return 0;
+}
+
+/*
+ * PHY initialization
+ */
+static i32_t
+bcm_mii_phy_init( void )
+{
+	static const u32_t PHY_STAT_R   = (u32_t) 0x01;
+	static const u32_t AUX_STAT_R   = (u32_t) 0x19;
+	static const u32_t MODE_GMII    = BIT32( 3 );
+	static const u32_t MODE_MII     = BIT32( 2 );
+	static const u32_t NEG_POLARITY = BIT32( 10 );
+	static const u32_t MII_MSK      = ( MODE_GMII | MODE_MII );
+	static const u16_t GIGA_ETH     = ( BIT16( 10 ) | BIT16( 9 ) );
+	i32_t i;
+	u16_t v;
+
+	/*
+	 * enable MDI communication
+	 */
+	bcm_write_reg32( MDI_CTRL_R, (u32_t) 0x0 );
+
+	/*
+	 * check link up
+	 */
+	i = 2500;
+	do {
+		ms_delay( 1 );
+		// register needs to be read twice!
+		bcm_mii_read16( PHY_STAT_R, &v );
+		bcm_mii_read16( PHY_STAT_R, &v );
+	} while( ( --i ) &&
+		 ( ( v & BIT16( 2 ) ) == 0 ) );
+
+	if( i == 0 ) {
+#ifdef BCM_DEBUG	
+		printk( "bcm57xx: link is down\n" );
+#endif
+		return -1;
+	}
+
+#ifdef BCM_DEBUG	
+	printk( "bcm57xx: link is up\n" );
+#endif
+	if( !IS_COPPER_PHY ) {
+		return 0;
+	}
+
+	/*
+	 * setup GMII or MII interface
+	 */
+	i = bcm_read_reg32( ETH_MAC_MODE_R );
+	/*
+	 * read status register twice, since the first
+	 * read fails once between here and the moon...
+	 */
+	bcm_mii_read16( AUX_STAT_R, &v );
+	bcm_mii_read16( AUX_STAT_R, &v );
+
+	if( ( v & GIGA_ETH ) == GIGA_ETH ) {
+#ifdef BCM_DEBUG	
+	printk( "bcm57xx: running PHY in GMII mode (1000BaseT)\n" );
+#endif
+		// GMII device
+		if( ( i & MII_MSK ) != MODE_GMII ) {
+			i &= ~MODE_MII;
+			i |=  MODE_GMII;
+		}
+
+	} else {
+#ifdef BCM_DEBUG	
+	printk( "bcm57xx: running PHY in MII mode (10/100BaseT)\n" );
+#endif
+		// MII device
+		if( ( i & MII_MSK ) != MODE_MII ) {
+			i &= ~MODE_GMII;
+			i |=  MODE_MII;
+		}
+
+	}
+
+	if( IS_5704 && !IS_SERDES ) {
+#ifdef BCM_DEBUG	
+		printk( "bcm57xx: set the link ready signal for 5704C to negative polarity\n" );
+#endif
+		i |= NEG_POLARITY; // set the link ready signal for 5704C to negative polarity
+	}
+
+	bcm_write_reg32( ETH_MAC_MODE_R, i );
+
+	return 0;
+}
+
+static i32_t
+bcm_tbi_phy_init( void )
+{
+	i32_t i;
+#if 0
+	/*
+	 * set TBI mode full duplex
+	 */
+	bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 1 ) );
+	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) );
+
+	/*
+	 * enable MDI communication
+	 */
+	bcm_write_reg32( MDI_CTRL_R, (u32_t) 0x0 );
+
+	/* Disable link change interrupt.  */
+	bcm_write_reg32( ETH_MAC_EVT_EN_R, 0 );
+
+	/*
+	 * set link polarity
+	 */
+	bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 10 ) );
+
+	/*
+	 * wait for sync/config changes
+	 */
+	for( i = 0; i < 100; i++ ) {
+		bcm_write_reg32( ETH_MAC_STAT_R,
+				 BIT32( 3 ) | BIT32( 4 ) );
+
+		us_delay( 20 );
+
+		if( ( bcm_read_reg32( ETH_MAC_STAT_R ) &
+		    ( BIT32( 3 ) | BIT32( 4 ) ) ) == 0 ) {
+			break;
+		}
+
+	}
+#endif
+	/*
+	 * wait for sync to come up
+	 */
+	for( i = 0; i < 100; i++ ) {
+
+		if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) != 0 ) {
+			break;
+		}
+
+		us_delay( 20 ); 
+	}
+
+	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) {
+#ifdef BCM_DEBUG	
+		printk( "bcm57xx: link is down\n" );
+#endif
+		return -1;
+	}
+#if 0
+	/*
+	 * clear all attentions
+	 */
+	bcm_write_reg32( ETH_MAC_STAT_R, (u32_t) ~0 );
+#endif
+
+#ifdef BCM_DEBUG	
+	printk( "bcm57xx: link is up\n" );
+#endif
+	return 0;
+}
+
+static i32_t
+bcm_phy_init( void )
+{
+	static const u16_t SRAM_HW_CFG = (u16_t) 0x0b58;
+	u32_t l_val_u32;
+	i32_t l_ret_i32 = 0;
+
+	/*
+         * get HW configuration from SRAM
+	 */
+	l_val_u32  = bcm_read_mem32( SRAM_HW_CFG );
+	l_val_u32 &= ( BIT32( 5 ) | BIT32( 4 ) );
+
+	switch( l_val_u32 ) {
+		case 0x10: {
+			#ifdef BCM_DEBUG
+			printk( "bcm57xx: copper PHY detected\n" );
+			#endif
+
+			bcm_device_u64 |= BCM_DEV_COPPER;
+			l_ret_i32       = bcm_mii_phy_init();
+		} break;
+
+		case 0x20: {
+			#ifdef BCM_DEBUG
+			printk( "bcm57xx: fiber PHY detected\n" );
+			#endif
+
+			if( !IS_SERDES ) {
+				#ifdef BCM_DEBUG
+				printk( "bcm57xx: running PHY in gmii/mii mode\n" );
+				#endif
+				l_ret_i32 = bcm_mii_phy_init();
+			} else {
+				#ifdef BCM_DEBUG
+				printk( "bcm57xx: running PHY in tbi mode\n" );
+				#endif
+				l_ret_i32 = bcm_tbi_phy_init();
+			}
+
+		} break;
+
+		default: {
+			#ifdef BCM_DEBUG
+			printk( "bcm57xx: unknown PHY type detected, terminating\n" );
+			#endif
+			l_ret_i32 = -1;
+		}
+
+	}
+
+	return l_ret_i32;
+}
+
+/*
+ * ring initialization
+ */
+static void
+bcm_init_rxprod_ring( void )
+{
+	u32_t      v;
+	u32_t      i;
+
+	/*
+	 * clear out the whole rx prod ring for sanity
+	 */
+	memset( (void *) &bcm_rxprod_ring,
+		0,
+		BCM_RXPROD_RING_SIZE * sizeof( bcm_rxbd_t ) );
+	mb();
+
+	/*
+	 * assign buffers & indices to the ring members
+	 */
+	for( i = 0; i < BCM_MAX_RX_BUF; i++ ) {
+		bcm_rxprod_ring[i].m_hostaddr_st.m_hi_u32 =
+			(u32_t) ( (u64_t) &bcm_rx_buffer_pu08[i] >> 32 );
+		bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 =
+			(u32_t) ( (u64_t) &bcm_rx_buffer_pu08[i] &
+			          (u64_t) 0xffffffff );
+		bcm_rxprod_ring[i].m_idxlen_u32  = ( i << 16 );
+		bcm_rxprod_ring[i].m_idxlen_u32 += BCM_BUF_SIZE;
+	}
+
+	/*
+	 * clear rcb registers & disable rings
+	 * NOTE: mini & jumbo rings are not supported,
+	 * still rcb's are cleaned out for sanity
+	 */
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_JUM ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_JUM ), 0 );
+
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_STD ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_STD ), 0 );
+
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_MIN ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_MIN ), 0 );
+
+	/*
+	 * clear rx producer index of std producer ring
+	 */
+	bcm_write_reg32( RXPROD_PROD_IND, 0 );
+
+	/*
+	 * setup rx standard rcb using recommended NIC addr (hard coded)
+	 */
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ),
+			 (u32_t) ( (u64_t) &bcm_rxprod_ring >> 32 ) );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ),
+		         (u32_t) ( (u64_t) &bcm_rxprod_ring & (u64_t) 0xffffffff ) );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ),
+			 (u32_t) BCM_NIC_RX_OFFS );
+
+	if( IS_5704 || IS_5703 ) {
+		// 5704: length field = max buffer len
+		v = (u32_t) BCM_BUF_SIZE << 16;
+	} else {
+		// 5714: length field = number of ring entries
+		v = (u32_t) BCM_RXPROD_RING_SIZE << 16;
+	}
+
+	v &= (u32_t) ~RCB_FLAG_RING_DISABLED;
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v );
+}
+
+static void
+bcm_init_rxret_ring( void )
+{
+	u32_t      i;
+	u16_t      v;
+
+	/*
+	 * clear out the whole rx ret ring for sanity
+	 */
+	memset( (void *) &bcm_rxret_ring,
+		0,
+		2 * BCM_RXRET_RING_SIZE * sizeof( bcm_rxbd_t ) );
+	mb();
+
+	/*
+	 * setup return ring size dependent on installed device
+	 */
+	bcm_rxret_ring_sz = BCM_RXRET_RING_SIZE;
+	if( IS_5704 || IS_5703 ) {
+		bcm_rxret_ring_sz *= 2;
+	}
+
+        /*
+	 * clear rcb memory & disable rings
+	 * NOTE: 5714 only supports one return ring,
+	 * still all possible rcb's are cleaned out for sanity
+	 */
+	v = BCM_RXRET_RCB_OFFS;
+	for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) {
+		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 );
+
+		v += BCM_RCB_SIZE_u16;
+        }
+
+	/*
+	 * clear rx consumer index of return ring
+	 */
+	bcm_write_reg32( RXRET_CONS_IND, 0 );
+
+	/*
+	 * setup rx ret rcb
+	 * NOTE: NIC address not aplicable in return rings
+	 */
+	bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXRET_RCB_OFFS ),
+	                 (u32_t) ( (u64_t) &bcm_rxret_ring >> 32 ) );
+	bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ),
+	                 (u32_t) ( (u64_t) &bcm_rxret_ring  &
+				   (u64_t) 0xffffffff ) );
+	bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 );
+
+	i   = bcm_rxret_ring_sz;
+	i <<= 16;
+	i  &= (u32_t) ~RCB_FLAG_RING_DISABLED;
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i );
+}
+
+static void
+bcm_init_tx_ring( void )
+{
+	u32_t      i;
+	u16_t	   v;
+
+	/*
+	 * clear out the whole tx ring for sanity
+	 */
+	memset( (void *) &bcm_tx_ring,
+		0,
+		BCM_TX_RING_SIZE * sizeof( bcm_txbd_t ) );
+	mb();
+
+        /*
+	 * assign buffers to the ring members & setup invariant flags
+	 */
+        for( i = 0; i < BCM_MAX_TX_BUF; i++ ) {
+		bcm_tx_ring[i].m_hostaddr_st.m_hi_u32 =
+			(u32_t) ( (u64_t) &bcm_tx_buffer_pu08[i] >> 32 );
+		bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 =
+			(u32_t) ( (u64_t) &bcm_tx_buffer_pu08[i] &
+			          (u64_t) 0xffffffff );
+		// flags: indicate last packet & coal now
+		// -last packet is always true (only one send packet supported)
+		// -coal now needed to always get the consumed bd's (since
+		//  only a few bd's are set up which permanently are recycled)
+		bcm_tx_ring[i].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) );
+		bcm_tx_ring[i].m_VLANtag_u32  = (u32_t) 0;	// not used
+        }
+
+        /*
+	 * clear rcb memory & disable rings
+	 * NOTE: 5714 only supports one send ring,
+	 * still all possible rcb's are cleaned out for sanity
+	 */
+        v = BCM_TX_RCB_OFFS;
+	for( i = 0; i < BCM_MAX_TX_RING; i++ ) {
+		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 );
+
+		v += BCM_RCB_SIZE_u16;
+	}
+
+	/*
+	 * clear host/nic producer indices
+	 */
+	bcm_write_reg32( TX_NIC_PROD_IND, 0 );
+	bcm_write_reg32( TX_PROD_IND, 0 );
+
+	/*
+	 * setup tx rcb using recommended NIC addr (hard coded)
+	 */
+	bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_TX_RCB_OFFS ),
+			          (u32_t) ( (u64_t) &bcm_tx_ring >> 32 ) );
+	bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ),
+			          (u32_t) ( (u64_t) &bcm_tx_ring &
+				            (u64_t) 0xffffffff ) );
+	bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ),
+			          (u32_t) BCM_NIC_TX_OFFS );
+
+	if( IS_5704 || IS_5703 ) {
+		// 5704: length field = max buffer len
+		i = (u32_t) BCM_BUF_SIZE << 16;
+	} else {
+		// 5714: length field = number of ring entries
+		i = (u32_t) BCM_TX_RING_SIZE << 16;
+	}
+
+	i &= ( u32_t ) ~RCB_FLAG_RING_DISABLED;
+	bcm_write_mem32( BCM_RCB_LENFLAG_u16( BCM_TX_RCB_OFFS ), i );
+
+	/*
+	 * remember the next bd index to be used
+	 * & number of available buffers
+	 */
+	bcm_tx_stop_u32     = BCM_MAX_TX_BUF;
+	bcm_tx_bufavail_u32 = BCM_MAX_TX_BUF;
+}
+
+static i32_t
+bcm_mac_init( u08_t *f_mac_pu08 )
+{
+	static const u16_t MEM_MAC_LO = (u16_t) 0x0c18;
+	static const u16_t MEM_MAC_HI = (u16_t) 0x0c14;
+
+	u32_t              NVR_MAC_LO = (u16_t) 0x80;
+	u32_t              NVR_MAC_HI = (u16_t) 0x7c;
+
+	bcm_addr64_t       l_mac_st;
+	u32_t              i;
+	u32_t              v;
+
+	/*
+	 * Use MAC address from device tree if possible
+	 */
+	for( i = 0, v = 0; i < 6; i++ ) {
+		v += (u32_t) f_mac_pu08[i];
+	}
+
+	if( v != 0 ) {
+		l_mac_st.m_hi_u32  = ( ( (u32_t) f_mac_pu08[0]) <<  8 );
+		l_mac_st.m_hi_u32 |= ( ( (u32_t) f_mac_pu08[1]) <<  0 );
+		l_mac_st.m_lo_u32  = ( ( (u32_t) f_mac_pu08[2]) << 24 );
+		l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[3]) << 16 );
+		l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[4]) <<  8 );
+		l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[5]) <<  0 );
+	} else {
+		/*
+		 * try to read MAC address from MAC mailbox
+		 */
+		l_mac_st.m_hi_u32 = bcm_read_mem32( MEM_MAC_HI );
+
+		if( ( l_mac_st.m_hi_u32 >> 16 ) == (u32_t) 0x484b ) {
+			l_mac_st.m_hi_u32 &= (u32_t) 0xffff;
+			l_mac_st.m_lo_u32  = bcm_read_mem32( MEM_MAC_LO );
+		} else {
+			i32_t l_err_i32;
+
+			/*
+			 * otherwise retrieve MAC address from NVRam
+			 */
+			if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) != 0 ) {
+				// secondary MAC is in use, address in NVRAM changes
+				NVR_MAC_LO += 0x50;
+				NVR_MAC_HI += 0x50;
+			}
+		
+			l_err_i32  = bcm_nvram_read( NVR_MAC_LO, &l_mac_st.m_lo_u32, 1 );
+			l_err_i32 += bcm_nvram_read( NVR_MAC_HI, &l_mac_st.m_hi_u32, 1 );
+
+			// return on read error
+			if( l_err_i32 < 0 ) {
+#ifdef BCM_DEBUG
+				printk( "bcm57xx: failed to retrieve MAC address\n" );
+#endif
+				return -1;
+			}
+		}
+	}
+
+        /*
+         * write the mac addr into the NIC's register area
+         */
+	bcm_write_reg32( MAC_ADDR_OFFS_HI(0), l_mac_st.m_hi_u32 );
+	bcm_write_reg32( MAC_ADDR_OFFS_LO(0), l_mac_st.m_lo_u32 );
+	for( i = 1; i < BCM_NUM_MAC_ADDR; i++ ) {
+		bcm_write_reg32( MAC_ADDR_OFFS_HI(i), 0 );
+		bcm_write_reg32( MAC_ADDR_OFFS_LO(i), 0 );
+	}
+	
+	/*
+	 * WY 26.01.07
+	 * not needed anymore, s.a.
+	if( IS_5704 != 0 ) {
+
+		v = MAC5704_ADDR_OFFS;
+		for( i = 0; i < BCM_NUM_MAC5704_ADDR; i++ ) {
+			bcm_write_reg32( v, l_mac_st.m_hi_u32 );
+			v += sizeof( u32_t );
+			bcm_write_reg32( v, l_mac_st.m_lo_u32 );
+			v += sizeof( u32_t );
+		}
+
+	}
+	*/
+
+        /*
+         * return MAC address as string
+         */
+        f_mac_pu08[0] = (u08_t) ( ( l_mac_st.m_hi_u32 >>  8 ) & (u32_t) 0xff );
+        f_mac_pu08[1] = (u08_t) ( ( l_mac_st.m_hi_u32       ) & (u32_t) 0xff );
+        f_mac_pu08[2] = (u08_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (u32_t) 0xff );
+        f_mac_pu08[3] = (u08_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (u32_t) 0xff );
+        f_mac_pu08[4] = (u08_t) ( ( l_mac_st.m_lo_u32 >>  8 ) & (u32_t) 0xff );
+        f_mac_pu08[5] = (u08_t) ( ( l_mac_st.m_lo_u32       ) & (u32_t) 0xff );
+
+#ifdef BCM_DEBUG
+	do {
+		i32_t i;
+		printk( "bcm57xx: retrieved MAC address " );
+
+		for( i = 0; i < 6; i++ ) {
+			printk( "%02X", f_mac_pu08[i] );
+
+			if( i != 5 ) {
+				printk( ":" );
+			}
+
+		}
+
+		printk( "\n" );
+	} while( 0 );
+#endif 
+
+	return 0;
+}
+
+
+/*
+ ******************************************************************************
+ * ASF Firmware
+ ******************************************************************************
+ */
+
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_ASF_REGS
+static void
+bcm_asf_check_register( void )
+{
+	u32_t i;
+
+	i = bcm_read_reg32( ASF_CTRL_R );
+	printk( "bcm57xx: ASF control          : %x\n", i );
+
+	i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R );
+	printk( "bcm57xx: ASF Watchdog Timer   : %x\n", i );
+
+	i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R );
+	printk( "bcm57xx: ASF Heartbeat Timer  : %x\n", i );
+
+	i = bcm_read_reg32( ASF_POLL_TIMER_R );
+	printk( "bcm57xx: ASF Poll Timer       : %x\n", i );
+
+	i = bcm_read_reg32( POLL_LEGACY_TIMER_R );
+	printk( "bcm57xx: Poll Legacy Timer    : %x\n", i );
+
+	i = bcm_read_reg32( RETRANSMISSION_TIMER_R );
+	printk( "bcm57xx: Retransmission Timer : %x\n", i );
+
+	i = bcm_read_reg32( TIME_STAMP_COUNTER_R );
+	printk( "bcm57xx: Time Stamp Counter   : %x\n", i );
+
+	i = bcm_read_reg32( RX_CPU_MODE_R );
+	printk( "bcm57xx: RX RISC Mode         : %x\n", i );
+
+	i = bcm_read_reg32( RX_CPU_STATE_R );
+	printk( "bcm57xx: RX RISC State        : %x\n", i );
+
+	i = bcm_read_reg32( RX_CPU_PC_R );
+	printk( "bcm57xx: RX RISC Prg. Counter : %x\n", i );
+}
+#endif
+#endif
+
+static int
+bcm_fw_halt( void )
+{
+	int i;
+
+	bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_PAUSE_FW );
+	bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) );
+
+	/* Wait for RX cpu to ACK the event.  */
+	for (i = 0; i < 100; i++) {
+		if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 ))
+			break;
+		ms_delay(1);
+	}
+	if( i>= 100)
+		return -1;
+	return 0;
+}
+
+
+#ifdef BCM_SW_AUTONEG
+static void
+bcm_sw_autoneg( void ) {
+	u32_t i, j, k;
+	u32_t SerDesCfg;
+	u32_t SgDigControl;
+	u32_t SgDigStatus;
+	u32_t ExpectedSgDigControl;
+	int   AutoNegJustInitiated = 0;
+
+	// step 1: init TX 1000BX Autoneg. Register to zero
+	bcm_write_reg32(TX_1000BX_AUTONEG_R, 0);
+
+	// step 2&3: set TBI mode
+	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) );
+	us_delay(10);
+
+	// step 4: enable link attention
+	bcm_setb_reg32( ETH_MAC_EVT_EN_R, BIT32( 12 ) );
+
+	// step 5: preserve voltage regulator bits
+	SerDesCfg = bcm_read_reg32(SERDES_CTRL_R) & ( BIT32( 20 ) | BIT32( 21 )
+	                                            | BIT32( 22 ) | BIT32( 23 ) );
+
+	// step 6: preserve voltage regulator bits
+	SgDigControl = bcm_read_reg32(HW_AUTONEG_CTRL_R);
+
+	// step 7: if device is NOT set-up for auto negotiation, then go to step 26
+	// goto bcm_setup_phy_step26;
+
+	// We want to use auto negotiation
+
+	// step 8: we don't want to use flow control
+	ExpectedSgDigControl = 0x81388400; // no flow control
+
+	// step 9: compare SgDigControl with 0x81388400
+	if(SgDigControl == ExpectedSgDigControl) {
+		goto bcm_setup_phy_step17;
+	}
+#ifdef BCM_DEBUG
+	printk("bcm57xx: SgDigControl = %08X\n", SgDigControl);
+#endif
+	// step 10
+	bcm_write_reg32(SERDES_CTRL_R, SerDesCfg | 0xC011880);
+
+	// step 11: restart auto negotiation
+	bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl | BIT32( 30 ) );
+
+	// step 12: read back HW_AUTONEG_CTRL_R
+	bcm_read_reg32(HW_AUTONEG_CTRL_R);
+
+	// step 13
+	us_delay( 5 );
+
+	// step 14,15,16: same as step 11, but don't restart auto neg.
+	bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl);
+	AutoNegJustInitiated = 1;
+	goto bcm_setup_phy_step30;
+
+	// step 17:
+	bcm_setup_phy_step17:
+	if( ( bcm_read_reg32(ETH_MAC_STAT_R) & ( BIT32( 1 ) | BIT32( 0 ) ) ) == 0 ) {
+		goto bcm_setup_phy_step30;
+	}
+
+	// step 18: Get HW Autoneg. Status
+	SgDigStatus = bcm_read_reg32(HW_AUTONEG_STAT_R);
+
+	// step 19:
+	if( ( SgDigStatus & BIT32(1) )
+	&&  ( bcm_read_reg32(ETH_MAC_STAT_R) & BIT32(0) ) ) {
+		// resolve the current flow control?
+		AutoNegJustInitiated = 0;
+		goto bcm_setup_phy_step30;
+	}
+
+	// step 20
+	if( SgDigStatus & BIT32(1) ) {
+		goto bcm_setup_phy_step30;
+	}
+	if( AutoNegJustInitiated != 0) {
+		AutoNegJustInitiated = 0;
+		goto bcm_setup_phy_step29;
+	}
+
+	// step 21, 22, 23, 24: fallback to 1000Mbps-FullDuplex forced mode
+	if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) {
+		// port 0
+		bcm_write_reg32( SERDES_CTRL_R, 0xC010880 );
+	}
+	else {	// port 1
+		bcm_write_reg32( SERDES_CTRL_R, 0x4010880 );
+	}
+	// set to 1000Mbps-FullDuplex
+	bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400);
+	// read back
+	bcm_read_reg32(HW_AUTONEG_CTRL_R);
+	us_delay( 40 );
+
+	// step 25: a little bit reduces...
+	goto bcm_setup_phy_step30;
+
+	// step 26: check if auto negotiation bit is NOT set
+//	bcm_setup_phy_step26:
+	if( ( SgDigControl & BIT32(31) )== 0 ) {
+		printk("No autoneg.\n");
+		goto bcm_setup_phy_step29;
+	}
+
+	// step 27:
+	if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) {
+		// port 0
+		bcm_write_reg32( SERDES_CTRL_R, 0xC010880 );
+	}
+	else {	// port 1
+		bcm_write_reg32( SERDES_CTRL_R, 0x4010880 );
+	}
+
+	// step 28: disable auto neg. and force 1000FD mode
+	bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400);
+
+	// step 29-31: omitted for 5704S
+	bcm_setup_phy_step29:
+	bcm_setup_phy_step30:
+
+	// step 32: clear link attentions
+	i = bcm_read_reg32( ETH_MAC_STAT_R ) | BIT32( 3 ) | BIT32( 4 );
+	k = 100;
+	do {
+		bcm_write_reg32( ETH_MAC_STAT_R, i );
+		j = bcm_read_reg32( ETH_MAC_STAT_R );
+		if( ( j & BIT32( 3 ) ) != 0 )
+			i = i & ~(BIT32( 3 ));
+		if( ( j & BIT32( 4 ) ) != 0 )
+			i = i & ~(BIT32( 4 ));
+		--k;
+	} while( i & k);
+
+	// step 33
+	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0 ) {
+		goto bcm_setup_phy_step35;
+	}
+
+	// step 34
+	i = bcm_read_reg32( ETH_MAC_MODE_R );
+	i|= BIT32( 17 );
+	bcm_write_reg32( ETH_MAC_MODE_R, i );
+
+	us_delay( 1 );
+
+	i = bcm_read_reg32( ETH_MAC_STAT_R );
+	i&= ~BIT32( 17 );
+	bcm_write_reg32( ETH_MAC_STAT_R, i );
+
+	// step 35 & 36: done
+	bcm_setup_phy_step35:
+#ifdef BCM_DEBUG
+	printk("bcm57xx: SetupPhy\n");
+#endif
+	return;
+}
+#endif
+
+static int
+bcm_handle_events( void ) {
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_ASF_REGS
+	// ASF REGISTER CHECK
+	// ------------------
+	// check if watchdog timer expired
+	if( bcm_read_reg32( ASF_WATCHDOG_TIMER_R ) == 0 ) {
+		// Show ASF registers
+		bcm_asf_check_register();
+
+		// rearm watchdog timer
+		bcm_write_reg32( ASF_WATCHDOG_TIMER_R, 5 );
+	}
+#endif
+#endif
+
+#ifdef BCM_SW_AUTONEG
+	// AUTO NEGOTIATION
+	// ----------------
+
+	// Check event for Auto Negotiation
+	if( ( bcm_read_reg32( ETH_MAC_STAT_R ) &
+	    ( BIT32( 12 ) | BIT32( 3 ) | BIT32( 0 ) ) ) != 0 ) {
+		// link timer procedure
+		bcm_sw_autoneg();
+	}
+#endif
+
+	// ASF FW HEARTBEAT
+	// ----------------
+
+	// check if heartsbeat timer expired
+	if( bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ) <= 2) {
+		int i;
+
+		// Send heartbeat event
+		bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_ALIVE );
+		bcm_write_mem32( BCM_FW_MBX_LEN, 4 );
+		bcm_write_mem32( BCM_FW_MBX_DATA, 5 );
+		bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) );
+
+		// Wait for RX cpu to ACK the event.
+		for (i = 100; i > 0; i--) {
+			if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 ))
+				break;
+			ms_delay(1);
+		}
+		if( i == 0) {
+#ifdef BCM_DEBUG
+			printk( "bcm57xx: RX cpu did not acknowledge heartbeat event\n" );
+#endif
+			return -1;
+		}
+
+		// rearm heartbeat timer
+		bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 5 );
+	}
+	return 0;
+}
+
+/*
+ * interface
+ ******************************************************************************
+ */
+  
+/*
+ * bcm_receive
+ */
+static int
+bcm_receive( char *f_buffer_pc, int f_len_i )
+{
+	u32_t l_rxret_prod_u32  = bcm_read_reg32( RXRET_PROD_IND );
+	u32_t l_rxret_cons_u32  = bcm_read_reg32( RXRET_CONS_IND );
+	u32_t l_rxprod_prod_u32 = bcm_read_reg32( RXPROD_PROD_IND );
+	int   l_ret_i;
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_RCV_DATA
+	int i, j;
+#endif
+#endif
+
+	/*
+	 * NOTE: dummy read to ensure data has already been DMA'd is
+	 *       done by the indice reads
+	 */
+
+	bcm_handle_events();
+
+	/*
+	 * if producer index == consumer index then nothing was received
+	 */
+	if( l_rxret_prod_u32 == l_rxret_cons_u32 ) {
+		return 0;
+	}
+
+	/*
+	 * discard erroneous packets
+	 */
+	if( ( bcm_rxret_ring[l_rxret_cons_u32].m_typeflags_u32 & BIT32( 10 ) ) != 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: erroneous frame received\n" );
+		printk( "       : frame discarded\n" );
+#endif
+		l_ret_i = 0;
+	} else {
+	        /*
+	         * get packet length, throw away checksum (last 4 bytes)
+	         */
+	        l_ret_i = (int) ( bcm_rxret_ring[l_rxret_cons_u32].m_idxlen_u32 &
+	                          (u32_t) 0xffff ) - (int) 4;
+
+		/*
+		 * discard oversized packets
+	         */
+		if( l_ret_i > f_len_i ) {
+#ifdef BCM_DEBUG
+			printk( "bcm57xx: receive packet length error:\n" );
+			printk( "       : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i );
+			printk( "       : frame discarded\n" );
+#endif		
+			l_ret_i = 0;
+		}
+
+        }
+
+        /*
+         * copy & update data & indices
+         */
+	if( l_ret_i != 0 ) {
+		u64_t l_cpyaddr_u64;
+
+		l_cpyaddr_u64  = 
+		( (u64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 );
+		l_cpyaddr_u64 += 
+		( (u64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 );
+
+// FIXME:
+		if(l_cpyaddr_u64 == 0) {
+#ifdef BCM_DEBUG
+			printk("bcm57xx: NULL address\n");
+#endif
+			return 0;
+		}
+// 
+		memcpy( (void *) f_buffer_pc,
+		        (void *) l_cpyaddr_u64,
+		        (size_t) l_ret_i );
+
+	}
+
+	/*
+	 * replenish bd to producer ring
+	 */
+	bcm_rxprod_ring[l_rxprod_prod_u32] =
+	                                bcm_rxret_ring[l_rxret_cons_u32];
+        bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 = 
+	                                ( l_rxprod_prod_u32 << 16 );
+	bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 +=
+	                                (u32_t) BCM_BUF_SIZE;
+
+        /*
+         * update producer ring's producer index
+         */
+        l_rxprod_prod_u32 = ( l_rxprod_prod_u32 + 1 ) & ( BCM_RXPROD_RING_SIZE - 1 );
+
+        /*
+         * move to the next bd in return ring
+         */
+        l_rxret_cons_u32 = ( l_rxret_cons_u32 + 1 ) & (  bcm_rxret_ring_sz - 1 );
+
+	/*
+	 * synchronize before new indices are send to NIC
+	 */
+	mb();
+
+        /*
+         * write back new indices
+         */
+        bcm_write_reg32( RXRET_CONS_IND,  l_rxret_cons_u32  );
+        bcm_write_reg32( RXPROD_PROD_IND, l_rxprod_prod_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_RCV
+	if( l_ret_i != 0 ) {
+		printk( "bcm57xx: received bytes: %d\n", l_ret_i );
+	}
+#ifdef BCM_SHOW_RCV_DATA
+	for( i = 0, j = 0; i < l_ret_i; i++ ) {
+		printk( "%02X ", ( u32_t ) f_buffer_pc[i] );
+
+		if( ( ++j % 0x18 ) == 0 ) {
+			printk( "\n" );
+		}
+	}
+
+	if( ( i % 0x18 ) != 0 ) {
+		printk( "\n" );
+	}
+#endif
+#endif
+#endif
+
+        /*
+         * return packet length
+         */
+        return l_ret_i;
+}
+
+static int
+bcm_xmit( char *f_buffer_pc, int f_len_i )
+{
+	u32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND );
+	u32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND );
+	u64_t l_cpyaddr_u64;
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT_DATA
+	int i, j;
+#endif
+#ifdef BCM_SHOW_IDX
+	printk( "\n" );
+	printk( "bcm57xx: TX_PROD_IND    : 0x%03X\n", l_tx_prod_u32 );
+	printk( "bcm57xx: TX_CONS_IND    : 0x%03X\n", l_tx_cons_u32 );
+	printk( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) );
+	printk( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) );
+	printk( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) );
+	printk( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) );
+	printk( "bcm57xx: available txb  : 0x%03X\n", bcm_tx_bufavail_u32 );
+#endif
+#ifdef BCM_SHOW_STATS
+	printk( "bcm57xx: bcm_status.m_st_word_u32:    %08X\n",               bcm_status.m_st_word_u32 );
+	printk( "bcm57xx: bcm_status.m_st_tag_u32 :    %08X\n",               bcm_status.m_st_tag_u32 );
+	printk( "bcm57xx: bcm_status.m_rxprod_cons_u16:    %04X\n", ( u32_t ) bcm_status.m_rxprod_cons_u16 );
+	printk( "bcm57xx: bcm_status.m_unused_u16:         %04X\n", ( u32_t ) bcm_status.m_unused_u16 );
+	printk( "bcm57xx: bcm_status.m_unused_u32:     %08X\n",               bcm_status.m_unused_u32 );
+	printk( "bcm57xx: bcm_status.m_tx_cons_u16:        %04X\n", ( u32_t ) bcm_status.m_tx_cons_u16 );
+	printk( "bcm57xx: bcm_status.m_rxret_prod_u16:     %04X\n", ( u32_t ) bcm_status.m_rxret_prod_u16 );
+#endif
+#endif
+
+	bcm_handle_events();
+
+	/*
+	 * make all consumed bd's available in the ring again
+	 * this way only a few buffers are needed instead of
+	 * having 512 buffers allocated
+	 */
+	while( bcm_tx_start_u32 != l_tx_cons_u32 ) {
+		bcm_tx_ring[bcm_tx_stop_u32] = bcm_tx_ring[bcm_tx_start_u32];
+		bcm_tx_stop_u32  = ( bcm_tx_stop_u32  + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+		bcm_tx_start_u32 = ( bcm_tx_start_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+		bcm_tx_bufavail_u32++;
+	}
+
+	/*
+	 * check for tx buffer availability
+	 */
+	if( bcm_tx_bufavail_u32 == 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: no more transmit buffers available\n" );
+#endif
+		return 0;
+	}
+
+	/*
+	 * setup next available bd in tx ring
+	 */
+	bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32  = ( BIT32( 2 ) | BIT32( 7 ) /*| BIT32( 6 )*/ );
+	bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 += ( (u32_t) f_len_i << 16 );
+//	bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32   = BCM_VLAN_TAG;
+
+	l_cpyaddr_u64  = ( (u64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 );
+	l_cpyaddr_u64 += ( (u64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT_STATS
+	printk("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 );
+	printk("               f_buffer_pc  : 0x%lx\n", f_buffer_pc );
+	printk("               f_len_i      : %d\n", f_len_i );
+#endif
+#endif
+	memcpy( (void *) l_cpyaddr_u64, (void *) f_buffer_pc, (size_t) f_len_i );
+
+	/*
+	 * update tx producer index & available buffers
+	 */
+	l_tx_prod_u32 = ( l_tx_prod_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 );
+	bcm_tx_bufavail_u32--;
+
+	/*
+	 * synchronize before new index is send to NIC
+	 */
+	mb();
+
+	bcm_write_reg32( TX_PROD_IND, l_tx_prod_u32 );
+
+#ifdef BCM_DEBUG
+#ifdef BCM_SHOW_XMIT
+	printk( "bcm57xx: sent bytes: %d\n", f_len_i );
+#ifdef BCM_SHOW_XMIT_DATA
+	for( i = 0, j = 0; i < f_len_i; i++ ) {
+		printk( "%02X ", ( u32_t ) f_buffer_pc[i] );
+
+		if( ( ++j % 0x18 ) == 0 ) {
+			printk( "\n" );
+		}
+
+	}
+	if( ( i % 0x18 ) != 0 ) {
+		printk( "\n" );
+	}
+#endif
+#endif
+
+#ifdef BCM_SHOW_STATS
+	// coalesce status block now
+	bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 3 ) | BIT32( 1 ) );
+#endif
+
+#endif
+	return f_len_i;
+}
+
+int
+check_driver( pci_config_t *pci_conf )
+{
+	u64_t i;
+
+	/*
+	 * checks whether the driver is handling this device
+	 * by verifying vendor & device id
+	 * vendor id 0x14e4 == Broadcom
+	 */
+        if( pci_conf->vendor_id != 0x14e4 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: netdevice not supported, illegal vendor id\n" );
+#endif
+		return -1;
+	}
+
+	for( i = 0; bcm_dev[i].m_dev_u32 != 0; i++ ) {
+		if( bcm_dev[i].m_dev_u32 == (u32_t) pci_conf->device_id ) {
+			// success
+			break;
+		}
+	}
+
+	if(bcm_dev[i].m_dev_u32 == 0) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: netdevice not supported, illegal device ID\n" );
+#endif
+		return -1;
+	}
+
+	/*
+	 * initialize static variables
+	 */
+	bcm_device_u64 = bcm_dev[i].m_devmsk_u64;
+	bcm_rxret_ring_sz = 0;
+	bcm_baseaddr_u64  = 0;
+	bcm_memaddr_u64   = 0;
+
+	bcm_tx_start_u32    = 0;
+	bcm_tx_stop_u32     = 0;
+	bcm_tx_bufavail_u32 = 0;
+
+	bcm_pcicfg_puid  = pci_conf->puid;
+	bcm_pcicfg_bus   = pci_conf->bus;
+	bcm_pcicfg_devfn = pci_conf->devfn;
+
+	return 0;
+}
+
+static void
+bcm_wol_activate(void)
+{
+#ifdef BCM_DEBUG
+	u16_t reg_pwr_cap;
+#endif
+	u16_t reg_pwr_crtl;
+	u32_t wol_mode;
+
+	wol_mode = bcm_read_reg32( WOL_MODE_R );
+	bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) );
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: WOL activating..." );
+#endif
+
+//	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL );
+//	ms_delay( 100 );
+
+#ifdef BCM_DEBUG
+	reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                     2,
+	                                                     bcm_pcicfg_bus,
+	                                                     bcm_pcicfg_devfn,
+	                                                     0x4a );
+	printk( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap );
+#endif
+	/* get curretn power control register */
+	reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                      2,
+	                                                      bcm_pcicfg_bus,
+	                                                      bcm_pcicfg_devfn,
+	                                                      0x4c );
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl );
+#endif
+
+	/* switch to power state D0 */
+	reg_pwr_crtl |= 0x8000;
+	reg_pwr_crtl &= ~(0x0003);
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        0x4c,
+	                                        reg_pwr_crtl );
+	ms_delay(10);
+
+/*
+	bcm_write_mem32( BCM_NICDRV_WOL_MBX, BCM_WOL_MAGIC_NUMBER |
+	                                     NIC_WOLDRV_STATE_SHUTDOWN |
+	                                     NIC_WOLDRV_WOL |
+	                                     NIC_WOLDRV_SET_MAGIC_PKT );
+*/
+
+	/* switch to power state D3hot */
+/*
+	reg_pwr_crtl |= 0x0103;
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        0x4c,
+	                                        reg_pwr_crtl );
+	ms_delay(10);
+*/
+
+#ifdef BCM_DEBUG
+	reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                      2,
+	                                                      bcm_pcicfg_bus,
+	                                                      bcm_pcicfg_devfn,
+	                                                      0x4c );
+
+	printk( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl );
+#endif
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: WOL activated" );
+#endif
+}
+
+static int
+bcm_init( void )
+{
+	static const u32_t  lc_Maxwait_u32 = (u32_t) 1000;
+	u32_t               l_baseaddrL_u32;
+	u32_t               l_baseaddrH_u32;
+	u32_t               i;
+	char               *mac_addr = snk_module_interface.mac_addr;
+
+	if(snk_module_interface.running != 0) {
+		return 0;
+	}
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: detected device " );
+	if( IS_5703 ) {
+		printk( "5703S\n" );
+	} else if( IS_5704 ) {
+		printk( "5704" );
+
+		if( IS_SERDES ) {
+			printk( "S\n" );
+		} else {
+			printk( "C\n" );
+		}
+
+	} else if( IS_5714 ) {
+		printk( "5714\n" );
+	}
+#endif
+	/*
+	 * setup register & memory base addresses of NIC
+	 */
+	l_baseaddrL_u32 = ( (u32_t) ~0xf &
+	      (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                     4,
+	                                                     bcm_pcicfg_bus,
+	                                                     bcm_pcicfg_devfn,
+	                                                     PCI_BAR1_R ) );
+
+	l_baseaddrH_u32 = 
+	      (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                                     4,
+	                                                     bcm_pcicfg_bus,
+	                                                     bcm_pcicfg_devfn,
+	                                                     PCI_BAR2_R );
+	bcm_baseaddr_u64   = (u64_t) l_baseaddrH_u32;
+	bcm_baseaddr_u64 <<= 32;
+	bcm_baseaddr_u64  += (u64_t) l_baseaddrL_u32;
+	snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));
+	bcm_memaddr_u64    = bcm_baseaddr_u64 + BCM_MEMORY_OFFS;
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: PCI-Puid  = 0x%X\n", bcm_pcicfg_puid );
+	printk( "bcm57xx: PCI-Bus   = 0x%X\n", bcm_pcicfg_bus );
+	printk( "bcm57xx: PCI-DevFn = 0x%X\n", bcm_pcicfg_devfn );
+	printk( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 );
+	printk( "bcm57xx: device's register base low address  = 0x%08X\n", l_baseaddrL_u32 );
+	printk( "bcm57xx: device's register address           = 0x%lx\n", bcm_baseaddr_u64 );
+#endif
+
+	/*
+	 * 57xx hardware initialization
+	 * BCM57xx Programmer's Guide: Section 8, "Initialization"
+	 * steps 1 through 101
+	 */
+
+	// step 1: enable bus master & memory space in command reg
+	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_COM_R,
+	                                        ( int ) i );
+	// step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode
+	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+
+	/*
+	 * from now on access may be made through the local
+	 * read/write functions
+	 */
+
+	// step 3: Save ahche line size register
+	// omitted, because register is not used for 5704
+
+	// step 4: acquire the nvram lock
+	if( bcm_nvram_lock() != 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: locking NVRAM failed\n" );
+#endif
+		return -1;
+	}
+
+	// step 5: prepare the chip for writing TG3_MAGIC_NUMBER
+	bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) );
+	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+	bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) |
+	                              BIT32( 17 ) | BIT32( 16 ) |
+	                              BIT32( 14 ) | BIT32( 13 ) |
+	                              BIT32(  5 ) | BIT32(  4 ) |
+	                              BIT32(  2 ) | BIT32(  1 ) );
+
+	// step 6: write TG3_MAGIC_NUMBER
+	bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER );
+
+	// step 7: reset core clocks
+
+	if( IS_5714 ) {
+		bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) );
+	} else {
+		bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) );
+	}
+	// step 8
+	ms_delay( 20 );
+
+	// step 9: disable & mask interrupts & enable indirect addressing mode &
+	//              enable pci byte/word swapping initialize the misc host control register
+	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+
+	// step 10: set but master et cetera
+	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_COM_R,
+	                                        ( int ) i );
+
+	// step 11: disable PCI-X relaxed ordering
+	bcm_clrb_reg16( PCI_X_COM_R, BIT16( 1 ) );
+
+	// step 12: enable the MAC memory arbiter
+	bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) );
+
+	// step 13: omitted, only for BCM5700
+	// step 14: s. step 10
+	i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+	// step 15: set byte swapping (incl. step 27/28/29/30)
+	// included prohibition of tx/rx interrupts
+	bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) |
+	                              BIT32( 17 ) | BIT32( 16 ) |
+	                              BIT32( 14 ) | BIT32( 13 ) |
+			  	      BIT32(  5 ) | BIT32(  4 ) |
+	                              BIT32(  2 ) | BIT32(  1 ) );
+	// step 16: omitted
+	i = 1000;
+	while( ( --i ) &&
+	       ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) {
+#ifdef BCM_DEBUG
+		printk( "." );
+#endif
+		ms_delay( 1 );
+	}
+
+	// return on error
+	if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) {
+		printk( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) );
+#ifdef BCM_DEBUG
+		printk( "failed\n" );
+#endif
+		return -1;
+	}
+
+
+	// if ASF Firmware enabled
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START );
+	ms_delay( 10 );
+
+	// step 17: write ethernet mac mode register
+	/*
+	 * WY 07.02.07
+	 * omitted for correct SOL function
+	 */
+	/*
+	if( IS_SERDES ) {
+		bcm_write_reg32( ETH_MAC_MODE_R, (u32_t) 0xc );
+	} else {
+		bcm_write_reg32( ETH_MAC_MODE_R, (u32_t) 0x0 );
+	}
+	*/
+
+	// step 18/19: omitted
+	// step 20: enable hw bugfix for 5704
+	if( IS_5704 || IS_5703 ) {
+		bcm_setb_reg32( MSG_DATA_R, BIT32( 26 ) |
+		                            BIT32( 28 ) |
+		                            BIT32( 29 ) );
+	}
+
+	// step 21: omitted
+	// step 22: omitted
+	// step 23: 5704 clear statistics block
+	if( IS_5703 || IS_5704 ) {
+		memset_ci( (void *) ( bcm_memaddr_u64 + BCM_STATISTIC_OFFS ),
+		           0,
+		           BCM_STATISTIC_SIZE );
+	}
+
+	// step 24/25: omitted
+	// step 26: set DMA Read/Write Control register
+	// NOTE: recommended values from the spec are used here
+	if( IS_5714 ) {
+		bcm_write_reg32( DMA_RW_CTRL_R, DMA_RW_CTRL_VAL_5714 );
+	} else {
+		u32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R );
+		u32_t l_DMAVal_u32   = DMA_RW_CTRL_VAL;
+
+		if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) {	// PCI
+			l_DMAVal_u32 |= (u32_t) 0x300000;
+		} else {					// PCI-X
+			l_DMAVal_u32 |= (u32_t) 0x900000;
+
+			if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (u32_t) 0x1f )
+			    >= (u32_t) 6 ) {
+				l_DMAVal_u32 |= (u32_t) 0x4000;
+			}
+
+		}
+
+		bcm_write_reg32( DMA_RW_CTRL_R, l_DMAVal_u32 );
+	}
+
+	// step 27/28/29: s. step 14
+
+	// step 30: Configure TCP/UDP pseudo header checksum offloading
+	// already done in step 14: offloading disabled
+
+	// step 31: setup timer prescaler
+	i  = bcm_read_reg32( MISC_CFG_R );
+	i &= (u32_t) ~0xfe;   // clear bits 7-1 first
+	i |= ( BCM_TMR_PRESCALE << 1 );
+	bcm_write_reg32( MISC_CFG_R, i );
+
+	// step 32: 5703/4 configure Mbuf pool address/length
+	// step 33: 5703/4 configure MAC DMA resource pool
+	// step 34: configure MAC memory pool watermarks
+	// step 35: 5703/4 configure DMA resource watermarks
+	//          using recommended settings (hard coded)
+	if( IS_5703 || IS_5704 ) {
+
+		if( IS_5703 ) {
+			bcm_write_reg32( MBUF_POOL_ADDR_R, (u32_t) 0x8000 );
+			bcm_write_reg32( MBUF_POOL_LEN_R,  (u32_t) 0x18000 );
+		} else {
+			bcm_write_reg32( MBUF_POOL_ADDR_R, (u32_t) 0x10000 );
+			bcm_write_reg32( MBUF_POOL_LEN_R,  (u32_t) 0x10000 );
+		}
+
+		bcm_write_reg32( DMA_DESC_POOL_ADDR_R,   (u32_t) 0x2000 );
+		bcm_write_reg32( DMA_DESC_POOL_LEN_R,    (u32_t) 0x2000 );
+
+		bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R,  (u32_t) 0x50 );
+		bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (u32_t) 0x20 );
+		bcm_write_reg32( MBUF_HIGH_WMARK_R,      (u32_t) 0x60 );
+
+		bcm_write_reg32( DMA_DESC_LOW_WM_R,      (u32_t)  5 );
+		bcm_write_reg32( DMA_DESC_HIGH_WM_R,     (u32_t) 10 );
+	} else {
+		bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R,  (u32_t) 0x00 );
+		bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (u32_t) 0x10 );
+		bcm_write_reg32( MBUF_HIGH_WMARK_R,      (u32_t) 0x60 );
+	}
+
+	// step 35: omitted
+	// step 36: Configure flow control behaviour
+	//          using recommended settings (hard coded)
+	bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (u32_t) 0x02 );
+
+	// step 37/38: enable buffer manager & wait for successful start
+	bcm_setb_reg32( BUF_MAN_MODE_R, BIT32( 2 ) | BIT32( 1 ) );
+
+	i = lc_Maxwait_u32;
+	while( ( --i ) &&
+	       ( ( bcm_read_reg32( BUF_MAN_MODE_R ) & BIT32( 1 ) ) == 0 ) ) {
+		us_delay( 10 );
+	}
+
+	// return on error
+	if( i == 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: init step 38: enable buffer manager failed\n" );
+#endif
+		return -1;
+	}
+
+	// step 39: enable internal hardware queues
+	bcm_write_reg32( FTQ_RES_R, (u32_t) ~0 );
+	bcm_write_reg32( FTQ_RES_R, (u32_t)  0 );
+
+	// step 40/41/42: initialize rx producer ring
+	bcm_init_rxprod_ring();
+
+	// step 43: set rx producer ring replenish threshhold
+	// using recommended setting of maximum allocated BD's/8
+	bcm_write_reg32( STD_RXPR_REP_THR_R, (u32_t) BCM_MAX_RX_BUF / 8 );
+
+	// step 44/45/46: initialize send rings
+	bcm_init_tx_ring();
+	bcm_init_rxret_ring();
+
+	// steps 47-50 done in ring init functions
+	// step 51: configure MAC unicast address
+	bcm_nvram_init();
+	if( bcm_mac_init( (u08_t *) mac_addr ) < 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: init step 51: configure MAC unicast address failed\n" );
+#endif
+		return -1;
+	}
+
+	// step 52: configure backoff random seed for transmit
+	// using recommended algorithm
+	i  = (u32_t) mac_addr[0] + (u32_t) mac_addr[1] +
+	     (u32_t) mac_addr[2] + (u32_t) mac_addr[3] +
+	     (u32_t) mac_addr[4] + (u32_t) mac_addr[5];
+	i &= (u32_t) 0x03ff; 
+	bcm_write_reg32( ETH_TX_RND_BO_R, i );
+
+	// step 53: configure message transfer unit MTU size
+	bcm_write_reg32( RX_MTU_SIZE_R, (u32_t) BCM_MTU_MAX_LEN );
+
+	// step 54: configure IPG for transmit
+	// using recommended value (through #define)
+	bcm_write_reg32( TX_MAC_LEN_R, TX_MAC_LEN_VAL );
+
+	// step 55: configure receive rules
+
+	// set RX rule default class
+	bcm_write_reg32( RX_RULE_CFG_R, RX_RULE_CFG_VAL );
+
+	// step 56: configure the number of receive lists
+	bcm_write_reg32( RX_LST_PLACE_CFG_R, RX_LST_PLC_CFG_VAL );
+	bcm_write_reg32( RX_LST_PLACE_STAT_EN_R, RX_LST_PLC_STAT_EN_VAL );
+
+/*
+	// rule 1: accept frames for our MAC address
+	bcm_write_reg32( RX_RULE_CTRL_R ( 0 ),
+			 BIT32( 31 ) | 	// enable rule
+			 BIT32( 30 ) | 	// and with next
+			 BIT32( 26 ) | 	// split value register
+			 BIT32(  8 ) );	// class 1
+	bcm_write_reg32( RX_RULE_VAL_R  ( 0 ),
+			 (u32_t) 0xffff0000 |
+			 ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) &
+			   (u32_t) 0xffff ) );
+
+	bcm_write_reg32( RX_RULE_CTRL_R ( 1 ),
+			 BIT32( 31 ) | 	// enable rule
+			 BIT32(  8 ) | 	// class 1
+			 BIT32(  1 ) );	// offset 2
+	bcm_write_reg32( RX_RULE_VAL_R  ( 1 ),
+			 bcm_read_reg32( MAC_ADDR_OFFS_LO(0) ) );
+
+	// rule 2: accept broadcast frames
+	bcm_write_reg32( RX_RULE_CTRL_R ( 2 ),
+			 BIT32( 31 ) | 	// enable rule
+			 BIT32( 30 ) | 	// and with next
+			 BIT32( 26 ) | 	// split value register
+			 BIT32(  8 ) );	// class 1
+	bcm_write_reg32( RX_RULE_VAL_R  ( 2 ),
+			 (u32_t) ~0 );
+
+	bcm_write_reg32( RX_RULE_CTRL_R ( 3 ),
+			 BIT32( 31 ) | 	// enable rule
+			 BIT32(  8 ) | 	// class 1
+			 BIT32(  1 ) );	// offset 2
+	bcm_write_reg32( RX_RULE_VAL_R  ( 3 ),
+			 (u32_t) ~0 );
+*/
+	for( i=0; i<NUM_RX_RULE_ASF; ++i) {
+		bcm_write_reg32( RX_RULE_CTRL_R ( i ),  0 );
+		bcm_write_reg32( RX_RULE_VAL_R  ( i ),  0 );
+	}
+
+	// step 57-60: enable rx/tx statistics
+	// omitted, no need for statistics (so far)
+
+	// step 61/62: disable host coalescing engine/wait 20ms
+	bcm_write_reg32( HOST_COAL_MODE_R, (u32_t) 0 );
+
+	i = lc_Maxwait_u32 * 2;
+	while( ( --i ) &&
+	       ( bcm_read_reg32( HOST_COAL_MODE_R ) != 0 ) ) {
+		us_delay( 10 );
+	}
+
+	// return on error
+	if( i == 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: init step 62: disable host coal. engine failed\n" );
+#endif
+		return -1;
+	}
+
+	// step 63-66: initialize coalescing engine
+	// NOTE: status block is unused in this driver,
+	//       therefore the coal. engine status block
+	//       automatic update is disabled (by writing
+	//       0 to every counter
+	bcm_write_reg32( RX_COAL_TICKS_R, 0 );
+	bcm_write_reg32( TX_COAL_TICKS_R, 0 );
+	bcm_write_reg32( RX_COAL_MAX_BD_R, 0 );
+	bcm_write_reg32( TX_COAL_MAX_BD_R, 0 );
+	bcm_write_reg32( RX_COAL_TICKS_INT_R, 0 );
+	bcm_write_reg32( TX_COAL_TICKS_INT_R, 0 );
+	bcm_write_reg32( RX_COAL_MAX_BD_INT_R, 0 );
+	bcm_write_reg32( TX_COAL_MAX_BD_INT_R, 0 );
+
+	// step 67: initialize host status block address
+	// NOTE: status block is not needed in this driver,
+	//       still it needs to be set up
+	i = (u32_t) ( (u64_t) &bcm_status >> 32 );
+	bcm_write_reg32( STB_HOST_ADDR_HI_R, i );
+	i = (u32_t) ( (u64_t) &bcm_status & (u64_t) 0xffffffff );
+	bcm_write_reg32( STB_HOST_ADDR_LO_R, i );
+
+	// 5704/3 adaption
+	if( IS_5703 || IS_5704 ) {
+		// step 68: 5704, for now omitted
+		// step 69: 5704 set the statistics coalescing tick counter
+		bcm_write_reg32( STAT_TICK_CNT_R, 0 );
+		// step 70: 5704 configure statistics block address in NIC memory
+		//          using recommended values (hard coded)
+		bcm_write_reg32( STAT_NIC_ADDR_R, (u32_t) 0x300 );
+		// step 71: 5704 configure status block address in NIC memory
+		//          using recommended values (hard coded)
+		bcm_write_reg32( STB_NIC_ADDR_R, (u32_t) 0xb00 );
+	}
+
+	// step 72: enable host coalescing engine
+	bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 12 ) | BIT32( 11 ) | BIT32( 1 ) );
+
+	// step 73: enable rx bd completion functional block
+	bcm_write_reg32( RX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+
+	// step 74: enable rx list placement functional block
+	bcm_write_reg32( RX_LST_PLACE_MODE_R, BIT32( 1 ) );
+	// 5704/3 adaption
+	if( IS_5703 || IS_5704 ) {
+		// step 75: 5704/3 enable receive list selector func block
+		bcm_write_reg32( RX_LST_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+	}
+
+	// step 76: enable DMA engines
+	bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 23 ) | BIT32( 22 ) | BIT32( 21 ) );
+	/*
+	 * WY 26.10.07 This is wrong for 5714, better leave it alone
+	if( IS_5714 ) {
+		bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 20 ) );
+	}
+	*/
+
+	// step 77: omitted, statistics are not used
+	// step 78: Configure the General Misc Local Control register
+	// NOTE:    as known so far nothing needs to be done here,
+	//          default values should work fine
+	//bcm_setb_reg32( MISC_LOCAL_CTRL_R, 0 );
+
+	// step 79: clear interrupts in INT_MBX0_R low word
+	bcm_write_reg32( INT_MBX0_R, 0 );
+	// 5704/3 adaption
+	// step 80: 5704/3 enable DMA completion functional block
+	if( IS_5703 || IS_5704 ) {
+		bcm_write_reg32( DMA_COMPL_MODE_R, BIT32( 1 ) );
+	}
+
+	// step 81/82: configure write/read DMA mode registers
+	//             disable MSI
+	bcm_write_reg32( RD_DMA_MODE_R, BIT32( 10 ) | BIT32( 9 ) | BIT32( 8 ) |
+	                                BIT32(  7 ) | BIT32( 6 ) | BIT32( 5 ) |
+	                                BIT32(  4 ) | BIT32( 3 ) | BIT32( 2 ) |
+	                                BIT32(  1 ) );
+	bcm_write_reg32( WR_DMA_MODE_R, BIT32( 9 ) | BIT32( 8 ) | BIT32( 7 ) |
+	                                BIT32( 6 ) | BIT32( 5 ) | BIT32( 4 ) |
+	                                BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) );
+	bcm_clrb_reg32( MSI_MODE_R,     BIT32( 1 ) );
+	us_delay( 100 );
+
+	// step 83-91: enable all these functional blocks...
+	bcm_write_reg32( RX_DAT_COMPL_MODE_R,   BIT32( 1 ) | BIT32( 2 ) );
+
+	if( IS_5703 || IS_5704 ) {
+		bcm_write_reg32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) );
+	}
+
+	bcm_write_reg32( TX_DAT_COMPL_MODE_R,   BIT32( 1 ) );
+	bcm_write_reg32( TX_BD_COMPL_MODE_R,    BIT32( 1 ) | BIT32( 2 ) );
+	bcm_write_reg32( RX_BD_INIT_MODE_R,     BIT32( 1 ) | BIT32( 2 ) );
+	bcm_write_reg32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) );
+	bcm_write_reg32( TX_DAT_INIT_MODE_R,    BIT32( 1 ) | BIT32( 3 ) );
+	bcm_write_reg32( TX_BD_INIT_MODE_R,     BIT32( 1 ) | BIT32( 2 ) );
+	bcm_write_reg32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) );
+
+	// step 92: omitted
+	// step 93/94: Enable Tx/Rx MAC
+	bcm_setb_reg32( TX_MAC_MODE_R, BIT32( 1 ) );
+//	bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) | BIT32( 2 ) );	// set BIT32( 8 ) for promiscious mode!
+	bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) );	// set BIT32( 8 ) for promiscious mode!
+	                                            	// set BIT32( 10) for VLAN
+
+	// step 95: disable auto polling:
+	//          bcm_phy_init takes care of this
+	// step 96: omitted
+	// step 97: omitted, may change though, but is not important
+	// step 98: activate link & enable MAC functional block
+	// NOTE     autopolling is enabled so bit 0 needs not to be set
+	//bcm_setb_reg32( MI_STATUS_R, BIT32( 0 ) );
+
+	// step 99: setup PHY
+	// return if link is down
+	if( bcm_phy_init() < 0 ) {
+#ifdef BCM_DEBUG
+		printk( "bcm57xx: init step 99: PHY initialization failed\n" );
+#endif
+		return -1;
+	}
+
+	// step 100: setup multicast filters
+	bcm_write_reg32( MAC_HASH0_R, (u32_t) 0 );
+	bcm_write_reg32( MAC_HASH1_R, (u32_t) 0 );
+	bcm_write_reg32( MAC_HASH2_R, (u32_t) 0 );
+	bcm_write_reg32( MAC_HASH3_R, (u32_t) 0 );
+/*
+	// accept all multicast frames
+	bcm_write_reg32( MAC_HASH0_R, (u32_t) 0xffffffff );
+	bcm_write_reg32( MAC_HASH1_R, (u32_t) 0xffffffff );
+	bcm_write_reg32( MAC_HASH2_R, (u32_t) 0xffffffff );
+	bcm_write_reg32( MAC_HASH3_R, (u32_t) 0xffffffff );
+*/
+	// step 101: omitted, no interrupts used
+
+	// make initial receive buffers available for NIC
+	// this step has to be done here after RX DMA engine has started (step 94)
+	bcm_write_reg32( RXPROD_PROD_IND, BCM_MAX_RX_BUF );
+
+	// if ASF Firmware enabled
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE );
+	ms_delay( 10 );
+
+	// enable heartbeat timer
+
+	bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 );
+
+	snk_module_interface.running = 1;
+	// off we go..
+	return 0;
+}
+
+static int
+bcm_reset( void )
+{
+	u32_t i;
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: resetting controller.." );
+#endif
+
+	bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER );
+
+	if( IS_5714 ) {
+		bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) );
+	} else {
+		bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) );
+	}
+
+	ms_delay( 20 );
+
+	/*
+	 * after reset local read/write functions cannot be used annymore
+	 * until bus master & stuff is set up again
+	 */
+
+	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_COM_R,
+	                                        ( int ) i );
+
+	// step 9 & 13: disable & mask interrupts & enable indirect addressing mode &
+	//              enable pci byte/word swapping initialize the misc host control register
+	i = ( BIT32( 7 ) | BIT32( 5 ) | BIT32( 4 ) |
+	      BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+
+	// step 16: poll for bootcode completion by waiting for the one's
+	//          complement of the magic number previously written
+	i = 1000;
+	while( ( --i ) &&
+	       ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) {
+#ifdef BCM_DEBUG
+		printk( "." );
+#else
+		ms_delay( 1 );
+#endif
+	}
+
+	// return on error
+	if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) {
+#ifdef BCM_DEBUG
+		printk( "failed\n" );
+#endif
+		return -1;
+	}
+
+#ifdef BCM_DEBUG
+	printk( "done\n" );
+#endif
+	return 0;
+}
+
+static int
+bcm_term( void )
+{
+	u32_t i;
+	u16_t v;
+
+	if(snk_module_interface.running == 0) {
+		return 0;
+	}
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: driver shutdown.." );
+#endif
+
+	/*
+	 * halt ASF firmware
+	 */
+	bcm_fw_halt();
+
+	/*
+	 * unload ASF firmware
+	 */
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD );
+
+	/*
+	 * disable RX producer rings
+	 */
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_JUM ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_JUM ), 0 );
+
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_STD ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_STD ), 0 );
+
+	bcm_write_reg32( BCM_RCB_LENFLAG_u16(      BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16(  BCM_RXPROD_RCB_MIN ), 0 );
+	bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 );
+	bcm_write_reg32( BCM_RCB_NICADDR_u16(      BCM_RXPROD_RCB_MIN ), 0 );
+
+	/*
+	 * disable RX return rings
+	 */
+	v = BCM_RXRET_RCB_OFFS;
+	for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) {
+		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 );
+
+		v += BCM_RCB_SIZE_u16;
+        }
+
+	/*
+	 * disable TX rings
+	 */
+        v = BCM_TX_RCB_OFFS;
+	for( i = 0; i < BCM_MAX_TX_RING; i++ ) {
+		bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ),      RCB_FLAG_RING_DISABLED );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ),  0 );
+		bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 );
+		bcm_write_mem32( BCM_RCB_NICADDR_u16( v ),      0 );
+
+		v += BCM_RCB_SIZE_u16;
+	}
+
+	/*
+	 * remove receive rules
+	 */
+	bcm_write_reg32( RX_RULE_CTRL_R (  0 ), 0 );
+	bcm_write_reg32( RX_RULE_VAL_R  (  0 ), 0 );
+	bcm_write_reg32( RX_RULE_CTRL_R (  1 ), 0 );
+	bcm_write_reg32( RX_RULE_VAL_R  (  1 ), 0 );
+
+	/*
+	 * shutdown sequence
+	 * BCM57xx Programmer's Guide: Section 8, "Shutdown"
+	 * the enable bit of every state machine of the 57xx
+	 * has to be reset.
+	 */
+
+	/*
+	 * receive path shutdown sequence
+	 */
+	bcm_clr_wait_bit32( RX_MAC_MODE_R,         BIT32( 1 ) );
+	bcm_clr_wait_bit32( RX_LST_PLACE_MODE_R,   BIT32( 1 ) );
+	bcm_clr_wait_bit32( RX_BD_INIT_MODE_R,     BIT32( 1 ) );
+	bcm_clr_wait_bit32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) );
+	bcm_clr_wait_bit32( RX_DAT_COMPL_MODE_R,   BIT32( 1 ) );
+	bcm_clr_wait_bit32( RX_BD_COMPL_MODE_R,    BIT32( 1 ) );
+
+	if( IS_5704 || IS_5703 ) {
+		bcm_clr_wait_bit32( RX_LST_SEL_MODE_R, BIT32( 1 ) );
+	}
+
+	/*
+	 * transmit path & memory shutdown sequence
+	 */
+	bcm_clr_wait_bit32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) );
+	bcm_clr_wait_bit32( TX_BD_INIT_MODE_R,     BIT32( 1 ) );
+	bcm_clr_wait_bit32( TX_DAT_INIT_MODE_R,    BIT32( 1 ) );
+	bcm_clr_wait_bit32( RD_DMA_MODE_R,         BIT32( 1 ) );
+	bcm_clr_wait_bit32( TX_DAT_COMPL_MODE_R,   BIT32( 1 ) );
+
+	if( IS_5704 ) {
+		bcm_clr_wait_bit32( DMA_COMPL_MODE_R, BIT32( 1 ) );
+	}
+
+	bcm_clr_wait_bit32( TX_BD_COMPL_MODE_R,    BIT32( 1 ) );
+	bcm_clr_wait_bit32( ETH_MAC_MODE_R,        BIT32( 21 ) );
+	bcm_clr_wait_bit32( TX_MAC_MODE_R,         BIT32( 1 ) );
+
+	bcm_clr_wait_bit32( HOST_COAL_MODE_R,      BIT32( 1 ) );
+	bcm_clr_wait_bit32( WR_DMA_MODE_R,         BIT32( 1 ) );
+
+	if( IS_5704 || IS_5703 ) {
+		bcm_clr_wait_bit32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) );
+	}
+
+	bcm_write_reg32( FTQ_RES_R, (u32_t) ~0 );
+	bcm_write_reg32( FTQ_RES_R, (u32_t)  0 );
+
+	if( IS_5704 || IS_5703 ) {
+		bcm_clr_wait_bit32( BUF_MAN_MODE_R, BIT32( 1 ) );
+		bcm_clr_wait_bit32( MEMARB_MODE_R,  BIT32( 1 ) );
+	}
+
+#ifdef BCM_DEBUG
+	printk( "done.\n" );
+#endif
+	/*
+	 * controller reset
+	 */
+	if( bcm_reset() != 0 ) {
+		return -1;
+	}
+
+	/*
+	 * restart ASF firmware
+	 */
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD );
+	ms_delay( 10 );
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE );
+	ms_delay( 100 );
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START );
+	ms_delay( 10 );
+	bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE );
+
+	/*
+	 * activate Wake-on-LAN
+	 */
+	bcm_wol_activate();
+
+	/*
+	 * PCI shutdown
+	 */
+	bcm_clrb_reg32( PCI_MISC_HCTRL_R, BIT32( 3 ) | BIT32( 2 ) );
+
+	/*
+	 * from now on local rw functions cannot be used anymore
+	 */
+
+//	bcm_clrb_reg32( PCI_COM_R, BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_COM_R,
+	                                        BIT32(8) | BIT32(6) );
+
+	// no more networking...
+	snk_module_interface.running = 0;
+	return 0;
+}
+
+static int
+bcm_getmac(u32_t addr, char mac[6])
+{
+	u32_t t1, t2;
+	u64_t t3;
+
+	if (bcm_nvram_read(addr, &t1, 1) != 0)
+		return -1;
+	if (bcm_nvram_read(addr+4, &t2, 1) != 0)
+		return -1;
+	t3 = ((u64_t)t1 << 32) + t2;
+
+	mac[0] = (t3 >> 40) & 0xFF;
+	mac[1] = (t3 >> 32) & 0xFF;
+	mac[2] = (t3 >> 24) & 0xFF;
+	mac[3] = (t3 >> 16) & 0xFF;
+	mac[4] = (t3 >>  8) & 0xFF;
+	mac[5] = (t3 >>  0) & 0xFF;
+
+	return 0;
+}
+
+static char*
+print_itoa(char *text, u32_t value)
+{
+	if(value >= 10)
+		text = print_itoa(text, value / 10);
+	*text = '0' + (value % 10);
+	++text;
+	return text;
+}
+
+static int
+bcm_get_version(char *text)
+{
+	u32_t t1;
+
+	if (bcm_nvram_read(0x94, &t1, 1) != 0)
+		return -1;
+
+	text = print_itoa(text, (t1 >> 8) & 0xFF);
+	text[0] = '.';
+	text = print_itoa(&text[1], t1 & 0xFF);
+	text[0] = '\n';
+	return 0;
+}
+
+static u32_t
+util_gen_crc( char *pcDatabuf, u32_t ulDatalen, u32_t ulCrc_in)
+{
+	unsigned char data;
+	u32_t idx, bit, crc = ulCrc_in;
+
+	for(idx = 0; idx < ulDatalen; idx++) {
+		data = *pcDatabuf++;
+		for(bit = 0; bit < 8; bit++, data >>= 1) {
+			crc = (crc >> 1) ^ (((crc ^ data) & 1) ?
+				CRC32_POLYNOMIAL : 0);
+		}
+	}
+	return bswap_32(~crc);
+}
+
+static int
+bcm_setmac(char mac_addr1[6], char mac_addr2[6])
+{
+	u64_t mac1 = 0, mac2 = 0;
+	u32_t manu[MANUFACTURING_INFO_SIZE/4];
+	int addr, i;
+	u32_t crc, val1, val2, val3, val4;
+
+#ifdef BCM_DEBUG
+	printk("Flashing MAC 1: %02X:%02X:%02X:%02X:%02X:%02X\n",
+		((unsigned int) mac_addr1[0]) & 0xFF,
+		((unsigned int) mac_addr1[1]) & 0xFF,
+		((unsigned int) mac_addr1[2]) & 0xFF,
+		((unsigned int) mac_addr1[3]) & 0xFF,
+		((unsigned int) mac_addr1[4]) & 0xFF,
+		((unsigned int) mac_addr1[5]) & 0xFF);
+
+	printk("Flashing MAC 2: %02X:%02X:%02X:%02X:%02X:%02X\n",
+		((unsigned int) mac_addr2[0]) & 0xFF,
+		((unsigned int) mac_addr2[1]) & 0xFF,
+		((unsigned int) mac_addr2[2]) & 0xFF,
+		((unsigned int) mac_addr2[3]) & 0xFF,
+		((unsigned int) mac_addr2[4]) & 0xFF,
+		((unsigned int) mac_addr2[5]) & 0xFF);
+#endif
+
+	mac1 |= ((u64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8;
+	mac1 |= ((u64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8;
+	mac1 |= ((u64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8;
+	mac1 |= ((u64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8;
+	mac1 |= ((u64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8;
+	mac1 |= ((u64_t) mac_addr1[5]) & 0xFF;
+
+	mac2 |= ((u64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8;
+	mac2 |= ((u64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8;
+	mac2 |= ((u64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8;
+	mac2 |= ((u64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8;
+	mac2 |= ((u64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8;
+	mac2 |= ((u64_t) mac_addr2[5]) & 0xFF;
+
+	/* Extract the manufacturing data, starts at 0x74 */
+	if(bcm_nvram_lock() == -1) {
+		return -1;
+	}
+
+	addr = 0x74;
+	for (i = 0; i < (MANUFACTURING_INFO_SIZE/4); i++) {
+		if (bcm_nvram_read(addr, &manu[i], 0) != 0) {
+			printk("\nREAD FAILED\n");
+			bcm_nvram_unlock();
+			return -1;
+		}
+		addr+=4;
+	}
+	bcm_nvram_unlock();
+
+	/* Store the new MAC address in the manufacturing data */
+	val1 = mac1 >> 32;
+	val2 = mac1 & 0xFFFFFFFF;
+	val3 = mac2 >> 32;
+	val4 = mac2 & 0xFFFFFFFF;
+	manu[(0x7C-0x74)/4] = val1;
+	manu[(0x80-0x74)/4] = val2;
+	manu[(0xCC-0x74)/4] = val3;
+	manu[(0xD0-0x74)/4] = val4;
+
+	/* Calculate the new manufacturing datas CRC */
+	crc = util_gen_crc(((char *)manu),
+		MANUFACTURING_INFO_SIZE - 4, 0xFFFFFFFF);
+
+	/* Now write the new MAC addresses and CRC */
+	if ((bcm_nvram_write(0x7C, val1, 1) != 0) ||
+	    (bcm_nvram_write(0x80, val2, 1) != 0) ||
+	    (bcm_nvram_write(0xCC, val3, 1) != 0) ||
+	    (bcm_nvram_write(0xD0, val4, 1) != 0) ||
+	    (bcm_nvram_write(0xFC, crc,  1) != 0) )
+	{
+		/* Disastor ! */
+#ifdef BCM_DEBUG
+		printk("failed to write MAC address\n");
+#endif
+		return -1;
+	}
+
+	/* Success !!!! */
+	return 0;
+}
+
+static int
+bcm_ioctl( int request, void* data )
+{
+	u32_t                l_baseaddrL_u32;
+	u32_t                l_baseaddrH_u32;
+	u32_t                i;
+	int                  ret_val = 0;
+	char                 mac_addr[6];
+	ioctl_net_data_t     *ioctl_data = (ioctl_net_data_t*) data;
+
+	if(request != SIOCETHTOOL) {
+		return -1;
+	}
+
+#ifdef BCM_DEBUG
+	printk( "bcm57xx: detected device " );
+	if( IS_5703 ) {
+		printk( "5703S" );
+	} else if( IS_5704 ) {
+		printk( "5704" );
+		if( IS_SERDES ) {
+			printk( "S\n" );
+		} else {
+			printk( "C\n" );
+		}
+	} else if( IS_5714 ) {
+		printk( "5714\n" );
+	}
+#endif
+	/*
+	 * setup register & memory base addresses of NIC
+	 */
+	l_baseaddrL_u32 = ( (u32_t) ~0xf &
+	(u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                               4,
+	                                               bcm_pcicfg_bus,
+	                                               bcm_pcicfg_devfn,
+	                                               PCI_BAR1_R ) );
+
+	l_baseaddrH_u32 = 
+	(u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid,
+	                                               4,
+	                                               bcm_pcicfg_bus,
+	                                               bcm_pcicfg_devfn,
+	                                               PCI_BAR2_R );
+
+	bcm_baseaddr_u64   = (u64_t) l_baseaddrH_u32;
+	bcm_baseaddr_u64 <<= 32;
+	bcm_baseaddr_u64  += (u64_t) l_baseaddrL_u32;
+	snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));
+	bcm_memaddr_u64    = bcm_baseaddr_u64 + BCM_MEMORY_OFFS;
+
+	/*
+	 * 57xx hardware initialization
+	 * BCM57xx Programmer's Guide: Section 8, "Initialization"
+	 * steps 1 through 101
+	 */
+
+	// step 1: enable bus master & memory space in command reg
+	i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        2,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_COM_R,
+	                                        ( int ) i );
+
+	// step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode
+	i = ( BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) );
+	snk_kernel_interface->pci_config_write( bcm_pcicfg_puid,
+	                                        4,
+	                                        bcm_pcicfg_bus,
+	                                        bcm_pcicfg_devfn,
+	                                        PCI_MISC_HCTRL_R,
+	                                        ( int ) i );
+
+	bcm_nvram_init();
+
+	switch(ioctl_data->subcmd) {
+	case ETHTOOL_GMAC:
+		switch(ioctl_data->data.mac.idx) {
+		case 0:
+			ret_val = bcm_getmac(0x7C, ioctl_data->data.mac.address);
+			break;
+		case 1:
+			ret_val = bcm_getmac(0xCC, ioctl_data->data.mac.address);
+			break;
+		default:
+			ret_val = -1;
+			break;
+		}
+		break;
+	case ETHTOOL_SMAC:
+		switch(ioctl_data->data.mac.idx) {
+		case 0:
+			ret_val = bcm_getmac(0xCC, mac_addr);
+			if(ret_val == 0)
+				ret_val = bcm_setmac(ioctl_data->data.mac.address, mac_addr);
+			break;
+		case 1:
+			ret_val = bcm_getmac(0x7C, mac_addr);
+			if(ret_val == 0)
+				ret_val = bcm_setmac(mac_addr, ioctl_data->data.mac.address);
+			break;
+		default:
+			ret_val = -1;
+			break;
+		}
+		break;
+	case ETHTOOL_VERSION: {
+		char *text = ioctl_data->data.version.text;
+		memcpy(text, "  BCM57xx Boot code level: ", 27);
+		ret_val = bcm_get_version(&text[27]);
+		break;
+	}
+	default:
+		ret_val = -1;
+		break;
+	}
+	
+	snk_module_interface.running = 1;
+	bcm_term();
+	return ret_val;
+}
+
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.h b/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.h
new file mode 100644
index 0000000..d968313
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/bcm/bcm57xx.h
@@ -0,0 +1,296 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "netdriver_int.h"
+#include "types.h"
+
+// compiler switches
+
+// Debug switches
+//#define BCM_DEBUG	// main debug switch, w/o it the other ones don't work
+//#define BCM_SHOW_RCV
+//#define BCM_SHOW_RCV_DATA
+//#define BCM_SHOW_XMIT
+//#define BCM_SHOW_XMIT_DATA
+//#define BCM_SHOW_XMIT_STATS
+//#define BCM_SHOW_IDX
+//#define BCM_SHOW_STATS
+//#define BCM_SHOW_ASF_REGS
+
+// Switch to enable SW AUTO-NEG
+// don't try, it's still incomplete
+//#define BCM_SW_AUTONEG
+
+/*
+ * used register offsets
+ */
+// PCI command register
+#define PCI_COM_R               ( (u16_t) 0x0004 )
+// PCI Cache Line Size register
+#define PCI_CACHELS_R           ( (u16_t) 0x000c )
+// PCI bar1 register
+#define PCI_BAR1_R              ( (u16_t) 0x0010 )
+// PCI bar2 register
+#define PCI_BAR2_R              ( (u16_t) 0x0014 )
+// PCI bar1 register
+#define PCI_SUBID_R             ( (u16_t) 0x002e )
+// PCI-X Comand register
+#define PCI_X_COM_R             ( (u16_t) 0x0042 )
+// Message Data Register
+#define MSG_DATA_R		( (u16_t) 0x0064 )
+// PCI misc host contrl register
+#define PCI_MISC_HCTRL_R        ( (u16_t) 0x0068 )
+// DMA Read/Write Control register
+#define DMA_RW_CTRL_R           ( (u16_t) 0x006c )
+// PCI State register
+#define PCI_STATE_R		( (u16_t) 0x0070 )
+// PCI_Clock Control register
+#define PCI_CLK_CTRL_R		( (u16_t) 0x0074 )
+// Register Base Address Register
+#define REG_BASE_ADDR_REG	( (u16_t) 0x0078 )
+// Memory Window Base Address Register
+#define MEM_BASE_ADDR_REG	( (u16_t) 0x007c )
+// Register Data Register
+#define REG_DATA_REG		( (u16_t) 0x0080 )
+// Memory Window Data Register
+#define MEM_DATA_REG		( (u16_t) 0x0084 )
+// MAC Function register
+#define MAC_FUNC_R		( (u16_t) 0x00b8 )
+// Interrupt Mailbox 0 register
+#define INT_MBX0_R              ( (u16_t) 0x0204 )
+// Ethernet MAC Mode register
+#define ETH_MAC_MODE_R          ( (u16_t) 0x0400 )
+// Ethernet MAC Addresses registers
+#define MAC_ADDR_OFFS_HI( idx )	( (u16_t) ( (idx*2 + 0)*sizeof( u32_t ) + 0x0410 ) )
+#define MAC_ADDR_OFFS_LO( idx )	( (u16_t) ( (idx*2 + 1)*sizeof( u32_t ) + 0x0410 ) )
+// Ethernet MAC Status register
+#define ETH_MAC_STAT_R		( (u16_t) 0x0404 )
+// Ethernet MAC Event Enable register
+#define ETH_MAC_EVT_EN_R	( (u16_t) 0x0408 )
+// Ethernet Transmit Random Backoff register
+#define ETH_TX_RND_BO_R         ( (u16_t) 0x0438 )
+// Receive MTU Size register
+#define RX_MTU_SIZE_R           ( (u16_t) 0x043c )
+// Transmit 1000BASE-X Auto Negotiation register
+#define TX_1000BX_AUTONEG_R	( (u16_t) 0x0444 )
+// Receive 1000BASE-X Auto Negotiation register
+#define RX_1000BX_AUTONEG_R	( (u16_t) 0x0448 )
+// MI Communication register
+#define MI_COM_R                ( (u16_t) 0x044c )
+// MI Status Register
+#define MI_STATUS_R             ( (u16_t) 0x0450 )
+// MI Mode register
+#define MI_MODE_R		( (u16_t) 0x0454 )
+// Transmit MAC Mode register
+#define TX_MAC_MODE_R           ( (u16_t) 0x045c )
+// Transmit MAC Length register
+#define TX_MAC_LEN_R            ( (u16_t) 0x0464 )
+// Receive MAC Mode register
+#define RX_MAC_MODE_R           ( (u16_t) 0x0468 )
+// MAC Hash 0 register* VPD Config:
+#define MAC_HASH0_R		( (u16_t) 0x0470 )
+// MAC Hash 1 register
+#define MAC_HASH1_R		( (u16_t) 0x0474 )
+// MAC Hash 2 register
+#define MAC_HASH2_R		( (u16_t) 0x0478 )
+// MAC Hash 3 register
+#define MAC_HASH3_R		( (u16_t) 0x047c )
+// Receive Rules Control register
+#define RX_RULE_CTRL_R( idx )	( (u16_t) ( idx*8 + 0x0480 ) )
+// Receive Rules Value register
+#define RX_RULE_VAL_R( idx )	( (u16_t) ( idx*8 + 0x0484 ) )
+// Receive Rules Configuration register
+#define RX_RULE_CFG_R           ( (u16_t) 0x0500 )
+// Low Watermark Max Receive Frames register
+#define LOW_WMARK_MAX_RXFRAM_R  ( (u16_t) 0x0504 )
+// SerDes Control Register
+#define SERDES_CTRL_R           ( (u16_t) 0x0590 )
+// Hardware Auto Negotiation Control Register
+#define HW_AUTONEG_CTRL_R       ( (u16_t) 0x05B0 )
+// Hardware Auto Negotiation Status Register
+#define HW_AUTONEG_STAT_R       ( (u16_t) 0x05B4 )
+// Send Data Initiator Mode register
+#define TX_DAT_INIT_MODE_R      ( (u16_t) 0x0c00 )
+// Send Data Completion Mode register
+#define TX_DAT_COMPL_MODE_R     ( (u16_t) 0x1000 )
+// Send BD Ring Selector Mode register
+#define TX_BD_RING_SEL_MODE_R   ( (u16_t) 0x1400 )
+// Send BD Initiator Mode register
+#define TX_BD_INIT_MODE_R       ( (u16_t) 0x1800 )
+// Send BD Completion Mode register
+#define TX_BD_COMPL_MODE_R      ( (u16_t) 0x1c00 )
+// Receive List Placement Mode register
+#define RX_LST_PLACE_MODE_R     ( (u16_t) 0x2000 )
+// Receive List Placement Configuration register
+#define RX_LST_PLACE_CFG_R      ( (u16_t) 0x2010 )
+// Receive List Placement Statistics Enable Mask register
+#define RX_LST_PLACE_STAT_EN_R	( (u16_t) 0x2018 )
+// Receive Data & Receive BD Initiator Mode register
+#define RX_DAT_BD_INIT_MODE_R   ( (u16_t) 0x2400 )
+// Receive Data Completion Mode register
+#define RX_DAT_COMPL_MODE_R     ( (u16_t) 0x2800 )
+// Receive BD Initiator Mode register
+#define RX_BD_INIT_MODE_R       ( (u16_t) 0x2c00 )
+// Standard Receive Producer Ring Replenish Threshhold register
+#define STD_RXPR_REP_THR_R      ( (u16_t) 0x2c18 )
+// Receive BD Completion Mode register
+#define RX_BD_COMPL_MODE_R      ( (u16_t) 0x3000 )
+// Receive List Selector Mode register
+#define RX_LST_SEL_MODE_R	( (u16_t) 0x3400 )
+// MBUF Cluster Free Mode register
+#define MBUF_CLSTR_FREE_MODE_R	( (u16_t) 0x3800 )
+// Host Coalescing Mode register
+#define HOST_COAL_MODE_R        ( (u16_t) 0x3c00 )
+// Receive Coalescing Ticks register
+#define RX_COAL_TICKS_R         ( (u16_t) 0x3c08 )
+// Send Coalescing Ticks register
+#define TX_COAL_TICKS_R         ( (u16_t) 0x3c0c )
+// Receive Max Coalesced BD Count register
+#define RX_COAL_MAX_BD_R        ( (u16_t) 0x3c10 )
+// Send Max Coalesced BD Count register
+#define TX_COAL_MAX_BD_R        ( (u16_t) 0x3c14 )
+// Receive Coalescing Ticks During Int register
+#define RX_COAL_TICKS_INT_R     ( (u16_t) 0x3c18 )
+// Send Coalescing Ticks During Int register
+#define TX_COAL_TICKS_INT_R     ( (u16_t) 0x3c1c )
+// Receive Max Coalesced BD Count During Int register
+#define RX_COAL_MAX_BD_INT_R    ( (u16_t) 0x3c18 )
+// Send Max Coalesced BD Count During Int register
+#define TX_COAL_MAX_BD_INT_R    ( (u16_t) 0x3c1c )
+// Statistics Ticks Counter register
+#define STAT_TICK_CNT_R		( (u16_t) 0x3c28 )
+// Status Block Host Address Low register
+#define STB_HOST_ADDR_HI_R      ( (u16_t) 0x3c38 )
+// Status Block Host Address High register
+#define STB_HOST_ADDR_LO_R	( (u16_t) 0x3c3c )
+// Statistsics Base Adress register
+#define STAT_NIC_ADDR_R		( (u16_t) 0x3c40 )
+// Status Block Base Address register
+#define STB_NIC_ADDR_R		( (u16_t) 0x3c44 )
+// Memory Arbiter Mode register
+#define MEMARB_MODE_R           ( (u16_t) 0x4000 )
+// Buffer Manager Mode register
+#define BUF_MAN_MODE_R          ( (u16_t) 0x4400 )
+// MBuf Pool Address register
+#define MBUF_POOL_ADDR_R	( (u16_t) 0x4408 )
+// MBuf Pool Length register
+#define MBUF_POOL_LEN_R		( (u16_t) 0x440c )
+// Read DMA Mbuf Low Watermark register
+#define DMA_RMBUF_LOW_WMARK_R   ( (u16_t) 0x4410 )
+// MAC Rx Mbuf Low Watermark register
+#define MAC_RXMBUF_LOW_WMARK_R  ( (u16_t) 0x4414 )
+// Mbuf High Watermark register
+#define MBUF_HIGH_WMARK_R       ( (u16_t) 0x4418 )
+// DMA Descriptor Pool Address register
+#define DMA_DESC_POOL_ADDR_R	( (u16_t) 0x442c )
+// DMA Descriptor Pool Length register
+#define DMA_DESC_POOL_LEN_R	( (u16_t) 0x4430 )
+// DMA Descriptor Low Watermark register
+#define DMA_DESC_LOW_WM_R	( (u16_t) 0x4434 )
+// DMA Descriptor HIGH Watermark register
+#define DMA_DESC_HIGH_WM_R	( (u16_t) 0x4438 )
+// Read DMA Mode register
+#define RD_DMA_MODE_R           ( (u16_t) 0x4800 )
+// Write DMA Mode register
+#define WR_DMA_MODE_R           ( (u16_t) 0x4c00 )
+// FTQ Reset register
+#define FTQ_RES_R               ( (u16_t) 0x5c00 )
+// MSI Mode register
+#define MSI_MODE_R		( (u16_t) 0x6000 )
+// DMA completion Mode register
+#define DMA_COMPL_MODE_R	( (u16_t) 0x6400 )
+// Mode Control register
+#define MODE_CTRL_R             ( (u16_t) 0x6800 )
+// Misc Configuration register
+#define MISC_CFG_R              ( (u16_t) 0x6804 )
+// Misc Local Control register
+#define MISC_LOCAL_CTRL_R       ( (u16_t) 0x6808 )
+// RX-Risc Mode Register
+#define RX_CPU_MODE_R    	( (u16_t) 0x5000 )
+// RX-Risc State Register
+#define RX_CPU_STATE_R    	( (u16_t) 0x5004 )
+// RX-Risc Program Counter
+#define RX_CPU_PC_R  		( (u16_t) 0x501c )
+// RX-Risc Event Register
+#define RX_CPU_EVENT_R    	( (u16_t) 0x6810 )
+// MDI Control register
+#define MDI_CTRL_R		( (u16_t) 0x6844 )
+// WOL Mode register
+#define WOL_MODE_R		( (u16_t) 0x6880 )
+// WOL Config register
+#define WOL_CFG_R		( (u16_t) 0x6884 )
+// WOL Status register
+#define WOL_STATUS_R		( (u16_t) 0x6888 )
+
+// ASF Control register
+#define ASF_CTRL_R		( (u16_t) 0x6c00 )
+// ASF Watchdog Timer register
+#define ASF_WATCHDOG_TIMER_R	( (u16_t) 0x6c0c )
+// ASF Heartbeat Timer register
+#define ASF_HEARTBEAT_TIMER_R	( (u16_t) 0x6c10 )
+// Poll ASF Timer register
+#define ASF_POLL_TIMER_R	( (u16_t) 0x6c14 )
+// Poll Legacy Timer register
+#define POLL_LEGACY_TIMER_R	( (u16_t) 0x6c18 )
+// Retransmission Timer register
+#define RETRANSMISSION_TIMER_R	( (u16_t) 0x6c1c )
+// Time Stamp Counter register
+#define TIME_STAMP_COUNTER_R	( (u16_t) 0x6c20 )
+
+// NVM Command register
+#define NVM_COM_R		( (u16_t) 0x7000 )
+// NVM Write register
+#define NVM_WRITE_R		( (u16_t) 0x7008 )
+// NVM Address register
+#define NVM_ADDR_R		( (u16_t) 0x700c )
+// NVM Read registertg3_phy_copper_begin
+#define NVM_READ_R		( (u16_t) 0x7010 )
+// NVM Access register
+#define NVM_ACC_R		( (u16_t) 0x7024 )
+// NVM Config 1 register
+#define NVM_CFG1_R		( (u16_t) 0x7014 )
+// Software arbitration register
+#define SW_ARB_R                ( (u16_t) 0x7020 )
+
+/*
+ * useful def's
+ */
+#define rd08(a)          (u08_t) snk_kernel_interface->io_read((void*)(a),1)
+#define rd16(a)          (u16_t) snk_kernel_interface->io_read((void*)(a),2)
+#define rd32(a)          (u32_t) snk_kernel_interface->io_read((void*)(a),4)
+#define wr08(a,v)        snk_kernel_interface->io_write((void*)(a),(u32_t)(v),1)
+#define wr16(a,v)        snk_kernel_interface->io_write((void*)(a),(u32_t)(v),2)
+#define wr32(a,v)        snk_kernel_interface->io_write((void*)(a),(u32_t)(v),4)
+#define printk           snk_kernel_interface->print
+#define us_delay         snk_kernel_interface->us_delay
+#define ms_delay         snk_kernel_interface->ms_delay
+
+#define BIT08( bit )     ( (u08_t) 0x1 << (bit) )
+#define BIT16( bit )     ( (u16_t) 0x1 << (bit) )
+#define BIT32( bit )     ( (u32_t) 0x1 << (bit) )
+
+/*
+ * type definition
+ */
+
+extern snk_kernel_t       *snk_kernel_interface;
+
+
+/*
+ * inline functions
+ */
+// memory barrier function implementation
+static inline void
+mb()
+{
+        asm volatile( "sync;" );
+}
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/bcm/types.h b/qemu-0.15.x/roms/SLOF/other-licence/bcm/types.h
new file mode 100644
index 0000000..fb562d7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/bcm/types.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+typedef unsigned char 		u08_t;
+typedef unsigned short 		u16_t;
+typedef unsigned int 		u32_t;
+typedef unsigned long long 	u64_t;
+
+typedef signed char 		i08_t;
+typedef signed short 		i16_t;
+typedef signed int 		i32_t;
+typedef signed long long 	i64_t;
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/common/Makefile b/qemu-0.15.x/roms/SLOF/other-licence/common/Makefile
new file mode 100644
index 0000000..8b3ebe1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/common/Makefile
@@ -0,0 +1,44 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS = -O2 -I./ -I$(TOP)/clients/net-snk/include/ -I$(TOP)/lib/libc/include/ -fno-builtin -ffreestanding -msoft-float -nostdinc -Wall
+
+SRCS   = module_entry.c
+
+OBJS   = $(SRCS:.c=.o)
+
+all:		Makefile.dep $(OBJS)
+
+
+clean:		
+		$(RM) -f *.o *.a *.i *.bin
+
+distclean : clean
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+		$(CC) -MM $(CFLAGS) $(SRCS) > Makefile.dep
+Makefile.dep:
+		$(MAKE) depend
+
+# Include dependency file if available:
+ifneq (,$(wildcard Makefile.dep))
+include Makefile.dep
+endif
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/common/module.lds b/qemu-0.15.x/roms/SLOF/other-licence/common/module.lds
new file mode 100644
index 0000000..c17a055
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/common/module.lds
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(module_init)
+
+SECTIONS {
+	.code 0xF800000:
+	{
+	  ../common/module_entry.o(.opd) 
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+          *(.rodata .rodata.* .gnu.linkonce.r.*)
+	  *(.data .data.* .gnu.linkonce.d.*)
+	  *(.opd)
+	} 
+	.got : 
+	{
+	  _got = .;
+          *(.got .toc)
+	} 
+        .bss : {
+	  __bss_start = .;
+          *(*COM* .bss .gnu.linkonce.b.*)
+	  __bss_end = .;
+	} 
+	__bss_size = (__bss_end - __bss_start);	
+        __end = .;
+}
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/common/module_entry.c b/qemu-0.15.x/roms/SLOF/other-licence/common/module_entry.c
new file mode 100644
index 0000000..423d908
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/common/module_entry.c
@@ -0,0 +1,64 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include "netdriver_int.h"
+
+extern snk_module_t snk_module_interface;
+
+snk_kernel_t *snk_kernel_interface = 0;
+
+extern int
+check_driver( pci_config_t *pci_conf );
+
+
+static void*
+memset( void *dest, int c, size_t n )
+{
+	while( n-- ) {
+		*( char * ) dest++ = ( char ) c;
+	}
+	return dest;
+}
+
+
+extern char __bss_start;
+extern char __bss_size;
+
+snk_module_t*
+module_init(snk_kernel_t *snk_kernel_int, pci_config_t *pciconf)
+{
+	/* Need to clear bss, heavy linker script dependency, expert change only */
+	char              *bss      = &__bss_start;
+	unsigned long long bss_size = (unsigned long long) &__bss_size;
+
+	if (((unsigned long long) bss) + bss_size >= 0xFF00000 
+	 || bss_size >= 0x2000000) {
+		snk_kernel_int->print("BSS size (%llu bytes) is too big!\n", bss_size);
+		return 0;
+	}
+
+	memset(bss, 0, bss_size);
+
+	if (snk_kernel_int->version != snk_module_interface.version) {
+		return 0;
+	}
+
+	snk_kernel_interface = snk_kernel_int;
+
+	/* Check if this is the right driver */
+	if (check_driver(pciconf) < 0) {
+		return 0;
+	}
+
+	snk_module_interface.link_addr = module_init;
+	return &snk_module_interface;
+}
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/x86emu/Makefile b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/Makefile
new file mode 100644
index 0000000..5f1fac4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/Makefile
@@ -0,0 +1,46 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+ifndef TOP
+  TOP = $(shell while ! test -e make.rules; do cd ..  ; done; pwd)
+  export TOP
+endif
+include $(TOP)/make.rules
+
+ROOTDIR ?= ../..
+
+LDFLAGS		=
+ASFLAGS		= -I./include -Wa,-mregnames
+
+#NOTE: -DDEBUG only needed for debugging/tracing...
+#CFLAGS		= -DDEBUG -I. -I./include -I./include/x86emu -I$(ROOTDIR)/include -I$(ROOTDIR)/lib/libc/include -g -O2 -msoft-float -Wall -save-temps -nostdinc -fno-builtin -ffreestanding 
+CFLAGS		= -UDEBUG -m64 -I. -I./include -I./include/x86emu -I$(TOP)/clients/net-snk/include -I$(ROOTDIR)/include -I$(ROOTDIR)/lib/libc/include -O3 -Wall -nostdinc -fno-builtin -ffreestanding 
+
+X86EMU_OBJS	= debug.o decode.o fpu.o ops2.o ops.o prim_ops.o sys.o
+
+%.o: %.S
+		$(CC) $(ASFLAGS) -c -o $@  $^
+
+%.o: %.c
+		$(CC) $(CFLAGS) -c -o $@ $^
+
+all: libx86emu.a
+
+libx86emu.a: $(X86EMU_OBJS)
+	$(AR) -rc $@ $^
+	$(RANLIB) $@
+
+clean:
+	$(RM) *.o *.i *.s libx86emu.a 
+
+distclean: clean
+
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_changes.diff b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_changes.diff
new file mode 100644
index 0000000..aa1a359
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_changes.diff
@@ -0,0 +1,893 @@
+Index: debug.c
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/debug.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -u -u -r1.1 -r1.3
+--- debug.c	7 Sep 2007 10:01:21 -0000	1.1
++++ debug.c	15 Jan 2008 13:49:25 -0000	1.3
+@@ -52,7 +52,11 @@
+ void X86EMU_trace_regs (void)
+ {
+     if (DEBUG_TRACE()) {
+-        x86emu_dump_regs();
++	if (M.x86.mode & (SYSMODE_PREFIX_DATA | SYSMODE_PREFIX_ADDR)) {
++	        x86emu_dump_xregs();
++	} else {
++	        x86emu_dump_regs();
++	}
+     }
+     if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) {
+         printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip);
+@@ -185,7 +189,7 @@
+     for (i=0; i< M.x86.enc_pos; i++) {
+         sprintf(buf1+2*i,"%02x", fetch_data_byte_abs(s,o+i));
+     }
+-    printk("%-20s",buf1);
++    printk("%-20s ",buf1);
+ }
+ 
+ static void print_decoded_instruction (void)
+Index: ops2.c
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops2.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -u -u -r1.1 -r1.3
+--- ops2.c	7 Sep 2007 10:01:21 -0000	1.1
++++ ops2.c	20 Mar 2008 15:48:34 -0000	1.3
+@@ -149,8 +149,69 @@
+     target += (s16) M.x86.R_IP;
+     DECODE_PRINTF2("%04x\n", target);
+     TRACE_AND_STEP();
+-    if (cond)
++    if (cond) {
+         M.x86.R_IP = (u16)target;
++	JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " LONG COND ");
++    }
++    DECODE_CLEAR_SEGOVR();
++    END_OF_INSTR();
++}
++
++/****************************************************************************
++REMARKS:
++Handles opcode 0x0f,0xC8-0xCF
++****************************************************************************/
++s32 x86emu_bswap(s32 reg)
++{
++   // perform the byte swap
++   s32 temp = reg;
++   reg = (temp & 0xFF000000) >> 24;
++   reg |= (temp & 0xFF0000) >> 8;
++   reg |= (temp & 0xFF00) << 8;
++   reg |= (temp & 0xFF) << 24;
++   return reg;
++}
++
++void x86emuOp2_bswap(u8 op2)
++{
++    /* byte swap 32 bit register */
++    START_OF_INSTR();
++    DECODE_PRINTF("BSWAP\t");
++    switch (op2) {
++      case 0xc8:
++        DECODE_PRINTF("EAX\n");
++        M.x86.R_EAX = x86emu_bswap(M.x86.R_EAX);
++        break;
++      case 0xc9:
++        DECODE_PRINTF("ECX\n");
++        M.x86.R_ECX = x86emu_bswap(M.x86.R_ECX);
++        break;
++      case 0xca:
++        DECODE_PRINTF("EDX\n");
++        M.x86.R_EDX = x86emu_bswap(M.x86.R_EDX);
++        break;
++      case 0xcb:
++        DECODE_PRINTF("EBX\n");
++        M.x86.R_EBX = x86emu_bswap(M.x86.R_EBX);
++        break;
++      case 0xcc:
++        DECODE_PRINTF("ESP\n");
++        M.x86.R_ESP = x86emu_bswap(M.x86.R_ESP);
++        break;
++      case 0xcd:
++        DECODE_PRINTF("EBP\n");
++        M.x86.R_EBP = x86emu_bswap(M.x86.R_EBP);
++        break;
++      case 0xce:
++        DECODE_PRINTF("ESI\n");
++        M.x86.R_ESI = x86emu_bswap(M.x86.R_ESI);
++        break;
++      case 0xcf:
++        DECODE_PRINTF("EDI\n");
++        M.x86.R_EDI = x86emu_bswap(M.x86.R_EDI);
++        break;
++    }
++    TRACE_AND_STEP();
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -1702,14 +1763,14 @@
+ /*  0xc5 */ x86emuOp2_illegal_op,
+ /*  0xc6 */ x86emuOp2_illegal_op,
+ /*  0xc7 */ x86emuOp2_illegal_op,
+-/*  0xc8 */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xc9 */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xca */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xcb */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xcc */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xcd */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xce */ x86emuOp2_illegal_op,  /* TODO: bswap */
+-/*  0xcf */ x86emuOp2_illegal_op,  /* TODO: bswap */
++/*  0xc8 */ x86emuOp2_bswap,
++/*  0xc9 */ x86emuOp2_bswap,
++/*  0xca */ x86emuOp2_bswap,
++/*  0xcb */ x86emuOp2_bswap,
++/*  0xcc */ x86emuOp2_bswap,
++/*  0xcd */ x86emuOp2_bswap,
++/*  0xce */ x86emuOp2_bswap,
++/*  0xcf */ x86emuOp2_bswap,
+ 
+ /*  0xd0 */ x86emuOp2_illegal_op,
+ /*  0xd1 */ x86emuOp2_illegal_op,
+Index: ops.c
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops.c,v
+retrieving revision 1.1
+diff -u -u -r1.1 ops.c
+--- ops.c	7 Sep 2007 10:01:21 -0000	1.1
++++ ops.c	20 Mar 2008 16:52:00 -0000
+@@ -1061,7 +1061,11 @@
+     imm = (s8)fetch_byte_imm();
+     DECODE_PRINTF2("PUSH\t%d\n", imm);
+     TRACE_AND_STEP();
+-    push_word(imm);
++    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
++        push_long(imm);
++    } else {
++        push_word(imm);
++    }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -1256,8 +1260,10 @@
+     target = (u16)(M.x86.R_IP + (s16)offset);
+     DECODE_PRINTF2("%x\n", target);
+     TRACE_AND_STEP();
+-    if (cond)
++    if (cond) {
+         M.x86.R_IP = target;
++	JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " NEAR COND ");
++    }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -2516,9 +2522,11 @@
+     count = 1;
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        count = M.x86.R_CX;
++        /* move them until (E)CX is ZERO. */
++        count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
+         M.x86.R_CX = 0;
++	if (M.x86.mode & SYSMODE_32BIT_REP)
++            M.x86.R_ECX = 0;
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     }
+     while (count--) {
+@@ -2526,6 +2534,8 @@
+         store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val);
+         M.x86.R_SI += inc;
+         M.x86.R_DI += inc;
++        if (M.x86.intr & INTR_HALTED)
++            break;
+     }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -2559,9 +2569,11 @@
+     count = 1;
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        count = M.x86.R_CX;
++        /* move them until (E)CX is ZERO. */
++        count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
+         M.x86.R_CX = 0;
++	if (M.x86.mode & SYSMODE_32BIT_REP)
++            M.x86.R_ECX = 0;
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     }
+     while (count--) {
+@@ -2574,6 +2586,8 @@
+         }
+         M.x86.R_SI += inc;
+         M.x86.R_DI += inc;
++        if (M.x86.intr & INTR_HALTED)
++            break;
+     }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -2598,16 +2612,21 @@
+ 
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* REPE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             val1 = fetch_data_byte(M.x86.R_SI);
+             val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+                      cmp_byte(val1, val2);
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_SI += inc;
+             M.x86.R_DI += inc;
+             if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break;
+             if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     } else {
+@@ -2644,8 +2663,8 @@
+     TRACE_AND_STEP();
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* REPE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+                 val1 = fetch_data_long(M.x86.R_SI);
+                 val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+@@ -2655,11 +2674,16 @@
+                 val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+                 cmp_word((u16)val1, (u16)val2);
+             }
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_SI += inc;
+             M.x86.R_DI += inc;
+             if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break;
+             if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     } else {
+@@ -2741,11 +2765,16 @@
+     TRACE_AND_STEP();
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_DI += inc;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     } else {
+@@ -2783,9 +2812,11 @@
+     count = 1;
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        count = M.x86.R_CX;
++        /* move them until (E)CX is ZERO. */
++        count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
+         M.x86.R_CX = 0;
++	if (M.x86.mode & SYSMODE_32BIT_REP)
++            M.x86.R_ECX = 0;
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     }
+     while (count--) {
+@@ -2795,6 +2826,8 @@
+             store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX);
+         }
+         M.x86.R_DI += inc;
++        if (M.x86.intr & INTR_HALTED)
++            break;
+     }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -2817,11 +2850,16 @@
+         inc = 1;
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             M.x86.R_AL = fetch_data_byte(M.x86.R_SI);
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_SI += inc;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     } else {
+@@ -2859,9 +2897,11 @@
+     count = 1;
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* move them until CX is ZERO. */
+-        count = M.x86.R_CX;
++        /* move them until (E)CX is ZERO. */
++        count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
+         M.x86.R_CX = 0;
++	if (M.x86.mode & SYSMODE_32BIT_REP)
++            M.x86.R_ECX = 0;
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+     }
+     while (count--) {
+@@ -2871,6 +2911,8 @@
+             M.x86.R_AX = fetch_data_word(M.x86.R_SI);
+         }
+         M.x86.R_SI += inc;
++        if (M.x86.intr & INTR_HALTED)
++            break;
+     }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -2894,26 +2936,36 @@
+         inc = 1;
+     if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+         /* REPE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+             cmp_byte(M.x86.R_AL, val2);
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_DI += inc;
+             if (ACCESS_FLAG(F_ZF) == 0)
+                 break;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+     } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+         /* REPNE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+             cmp_byte(M.x86.R_AL, val2);
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_DI += inc;
+             if (ACCESS_FLAG(F_ZF))
+                 break;          /* zero flag set means equal */
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+     } else {
+@@ -2951,8 +3003,8 @@
+     TRACE_AND_STEP();
+     if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+         /* REPE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+                 val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+                 cmp_long(M.x86.R_EAX, val);
+@@ -2960,16 +3012,21 @@
+                 val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+                 cmp_word(M.x86.R_AX, (u16)val);
+             }
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_DI += inc;
+             if (ACCESS_FLAG(F_ZF) == 0)
+                 break;
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+     } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+         /* REPNE  */
+-        /* move them until CX is ZERO. */
+-        while (M.x86.R_CX != 0) {
++        /* move them until (E)CX is ZERO. */
++        while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
+             if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+                 val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+                 cmp_long(M.x86.R_EAX, val);
+@@ -2977,10 +3034,15 @@
+                 val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+                 cmp_word(M.x86.R_AX, (u16)val);
+             }
+-            M.x86.R_CX -= 1;
++            if (M.x86.mode & SYSMODE_32BIT_REP)
++                M.x86.R_ECX -= 1;
++            else
++                M.x86.R_CX -= 1;
+             M.x86.R_DI += inc;
+             if (ACCESS_FLAG(F_ZF))
+                 break;          /* zero flag set means equal */
++            if (M.x86.intr & INTR_HALTED)
++                break;
+         }
+         M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+     } else {
+@@ -3238,9 +3300,9 @@
+     DECODE_PRINTF("RET\t");
+     imm = fetch_word_imm();
+     DECODE_PRINTF2("%x\n", imm);
+-	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+ 	TRACE_AND_STEP();
+     M.x86.R_IP = pop_word();
++	RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR");
+     M.x86.R_SP += imm;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -3254,9 +3316,9 @@
+ {
+     START_OF_INSTR();
+     DECODE_PRINTF("RET\n");
+-	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+ 	TRACE_AND_STEP();
+     M.x86.R_IP = pop_word();
++	RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR");
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -3471,10 +3533,10 @@
+     DECODE_PRINTF("RETF\t");
+     imm = fetch_word_imm();
+     DECODE_PRINTF2("%x\n", imm);
+-	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+ 	TRACE_AND_STEP();
+     M.x86.R_IP = pop_word();
+     M.x86.R_CS = pop_word();
++	RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR");
+     M.x86.R_SP += imm;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -3488,10 +3550,10 @@
+ {
+     START_OF_INSTR();
+     DECODE_PRINTF("RETF\n");
+-	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+ 	TRACE_AND_STEP();
+     M.x86.R_IP = pop_word();
+     M.x86.R_CS = pop_word();
++	RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR");
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -4020,8 +4082,11 @@
+     ip += (s16) M.x86.R_IP;
+     DECODE_PRINTF2("%04x\n", ip);
+     TRACE_AND_STEP();
+-    M.x86.R_CX -= 1;
+-    if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF))      /* CX != 0 and !ZF */
++    if (M.x86.mode & SYSMODE_PREFIX_ADDR)
++        M.x86.R_ECX -= 1;
++    else
++        M.x86.R_CX -= 1;
++    if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && !ACCESS_FLAG(F_ZF))      /* (E)CX != 0 and !ZF */
+         M.x86.R_IP = ip;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -4041,8 +4106,11 @@
+     ip += (s16) M.x86.R_IP;
+     DECODE_PRINTF2("%04x\n", ip);
+     TRACE_AND_STEP();
+-    M.x86.R_CX -= 1;
+-    if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF))       /* CX != 0 and ZF */
++    if (M.x86.mode & SYSMODE_PREFIX_ADDR)
++        M.x86.R_ECX -= 1;
++    else
++        M.x86.R_CX -= 1;
++    if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && ACCESS_FLAG(F_ZF))      /* (E)CX != 0 and ZF */
+         M.x86.R_IP = ip;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -4062,8 +4130,11 @@
+     ip += (s16) M.x86.R_IP;
+     DECODE_PRINTF2("%04x\n", ip);
+     TRACE_AND_STEP();
+-    M.x86.R_CX -= 1;
+-    if (M.x86.R_CX != 0)
++    if (M.x86.mode & SYSMODE_PREFIX_ADDR)
++        M.x86.R_ECX -= 1;
++    else
++        M.x86.R_CX -= 1;
++    if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0)      /* (E)CX != 0 */
+         M.x86.R_IP = ip;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+@@ -4085,8 +4156,10 @@
+     target = (u16)(M.x86.R_IP + offset);
+     DECODE_PRINTF2("%x\n", target);
+     TRACE_AND_STEP();
+-    if (M.x86.R_CX == 0)
++    if (M.x86.R_CX == 0) {
+         M.x86.R_IP = target;
++	JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " CXZ ");
++    }
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -4213,6 +4286,7 @@
+     ip = (s16)fetch_word_imm();
+     ip += (s16)M.x86.R_IP;
+     DECODE_PRINTF2("%04x\n", ip);
++    JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, " NEAR ");
+     TRACE_AND_STEP();
+     M.x86.R_IP = (u16)ip;
+     DECODE_CLEAR_SEGOVR();
+@@ -4233,6 +4307,7 @@
+     cs = fetch_word_imm();
+     DECODE_PRINTF2("%04x:", cs);
+     DECODE_PRINTF2("%04x\n", ip);
++    JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, cs, ip, " FAR ");
+     TRACE_AND_STEP();
+     M.x86.R_IP = ip;
+     M.x86.R_CS = cs;
+@@ -4254,6 +4329,7 @@
+     offset = (s8)fetch_byte_imm();
+     target = (u16)(M.x86.R_IP + offset);
+     DECODE_PRINTF2("%x\n", target);
++    JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, target, " BYTE ");
+     TRACE_AND_STEP();
+     M.x86.R_IP = target;
+     DECODE_CLEAR_SEGOVR();
+@@ -4357,6 +4433,8 @@
+     DECODE_PRINTF("REPNE\n");
+     TRACE_AND_STEP();
+     M.x86.mode |= SYSMODE_PREFIX_REPNE;
++    if (M.x86.mode & SYSMODE_PREFIX_ADDR)
++        M.x86.mode |= SYSMODE_32BIT_REP;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -4371,6 +4449,8 @@
+     DECODE_PRINTF("REPE\n");
+     TRACE_AND_STEP();
+     M.x86.mode |= SYSMODE_PREFIX_REPE;
++    if (M.x86.mode & SYSMODE_PREFIX_ADDR)
++        M.x86.mode |= SYSMODE_32BIT_REP;
+     DECODE_CLEAR_SEGOVR();
+     END_OF_INSTR();
+ }
+@@ -5013,12 +5093,14 @@
+             break;
+         case 4:         /* jmp word ptr ... */
+             destval = fetch_data_word(destoffset);
++            JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, destval, " WORD ");
+             TRACE_AND_STEP();
+             M.x86.R_IP = destval;
+             break;
+         case 5:         /* jmp far ptr ... */
+             destval = fetch_data_word(destoffset);
+             destval2 = fetch_data_word(destoffset + 2);
++            JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, destval2, destval, " FAR ");
+             TRACE_AND_STEP();
+             M.x86.R_IP = destval;
+             M.x86.R_CS = destval2;
+Index: prim_ops.c
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/prim_ops.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -u -u -r1.1 -r1.3
+--- prim_ops.c	7 Sep 2007 10:01:21 -0000	1.1
++++ prim_ops.c	16 Jan 2008 14:18:15 -0000	1.3
+@@ -1921,7 +1921,7 @@
+ void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s)
+ {
+ #ifdef  __HAS_LONG_LONG__
+-    s64 res = (s64)d * (s64)s;
++    s64 res = (s64)(s32)d * (s64)(s32)s;
+ 
+     *res_lo = (u32)res;
+     *res_hi = (u32)(res >> 32);
+@@ -2013,7 +2013,7 @@
+ void mul_long(u32 s)
+ {
+ #ifdef  __HAS_LONG_LONG__
+-    u64 res = (u32)M.x86.R_EAX * (u32)s;
++    u64 res = (u64)M.x86.R_EAX * s;
+ 
+     M.x86.R_EAX = (u32)res;
+     M.x86.R_EDX = (u32)(res >> 32);
+@@ -2312,16 +2312,15 @@
+     }
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* in until CX is ZERO. */
+-        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
++        /* in until (E)CX is ZERO. */
++        u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ?
+                      M.x86.R_ECX : M.x86.R_CX);
+-
+         while (count--) {
+           single_in(size);
+           M.x86.R_DI += inc;
+           }
+         M.x86.R_CX = 0;
+-        if (M.x86.mode & SYSMODE_PREFIX_DATA) {
++        if (M.x86.mode & SYSMODE_32BIT_REP) {
+             M.x86.R_ECX = 0;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+@@ -2355,15 +2354,15 @@
+     }
+     if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+         /* dont care whether REPE or REPNE */
+-        /* out until CX is ZERO. */
+-        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
++        /* out until (E)CX is ZERO. */
++        u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ?
+                      M.x86.R_ECX : M.x86.R_CX);
+         while (count--) {
+           single_out(size);
+           M.x86.R_SI += inc;
+           }
+         M.x86.R_CX = 0;
+-        if (M.x86.mode & SYSMODE_PREFIX_DATA) {
++        if (M.x86.mode & SYSMODE_32BIT_REP) {
+             M.x86.R_ECX = 0;
+         }
+         M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+Index: sys.c
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/sys.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -u -u -r1.1 -r1.2
+--- sys.c	7 Sep 2007 10:01:21 -0000	1.1
++++ sys.c	7 Sep 2007 10:03:13 -0000	1.2
+@@ -45,11 +45,6 @@
+ #include <x86emu/regs.h>
+ #include "debug.h"
+ #include "prim_ops.h"
+-#ifdef LINUXBIOS_VERSION
+-#include "io.h"
+-#else
+-#include <sys/io.h>
+-#endif
+ 
+ #ifdef IN_MODULE
+ #include "xf86_ansic.h"
+@@ -220,7 +215,7 @@
+ {
+ 	DB(if (DEBUG_IO_TRACE())
+ 		printk("inb %#04x \n", addr);)
+-	return inb(addr);
++	return 0;
+ }
+ 
+ /****************************************************************************
+@@ -235,7 +230,7 @@
+ {
+ 	DB(if (DEBUG_IO_TRACE())
+ 		printk("inw %#04x \n", addr);)
+-	return inw(addr);
++	return 0;
+ }
+ 
+ /****************************************************************************
+@@ -250,7 +245,7 @@
+ {
+ 	DB(if (DEBUG_IO_TRACE())
+ 		printk("inl %#04x \n", addr);)
+-	return inl(addr);
++	return 0;
+ }
+ 
+ /****************************************************************************
+@@ -264,7 +259,6 @@
+ {
+ 	DB(if (DEBUG_IO_TRACE())
+ 		printk("outb %#02x -> %#04x \n", val, addr);)
+-	outb(val, addr);
+ 	return;
+ }
+ 
+@@ -279,7 +273,6 @@
+ {
+ 	DB(if (DEBUG_IO_TRACE())
+ 		printk("outw %#04x -> %#04x \n", val, addr);)
+-	outw(val, addr);
+ 	return;
+ }
+ 
+@@ -295,7 +288,6 @@
+ 	DB(if (DEBUG_IO_TRACE())
+ 	       printk("outl %#08x -> %#04x \n", val, addr);)
+ 
+-	outl(val, addr);
+ 	return;
+ }
+ 
+@@ -405,6 +397,6 @@
+ 
+ void X86EMU_setMemBase(void *base, size_t size)
+ {
+-	M.mem_base = (int) base;
++	M.mem_base = (unsigned long) base;
+ 	M.mem_size = size;
+ }
+Index: include/x86emu/debug.h
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/debug.h,v
+retrieving revision 1.1
+retrieving revision 1.4
+diff -u -u -r1.1 -r1.4
+--- include/x86emu/debug.h	7 Sep 2007 10:01:21 -0000	1.1
++++ include/x86emu/debug.h	20 Mar 2008 15:25:27 -0000	1.4
+@@ -40,8 +40,6 @@
+ #ifndef __X86EMU_DEBUG_H
+ #define __X86EMU_DEBUG_H
+ 
+-//#define DEBUG 0
+-#undef DEBUG
+ /*---------------------- Macros and type definitions ----------------------*/
+ 
+ /* checks to be enabled for "runtime" */
+@@ -78,6 +76,8 @@
+ # define DEBUG_SYSINT()        	(M.x86.debug & DEBUG_SYSINT_F)
+ # define DEBUG_TRACECALL()     	(M.x86.debug & DEBUG_TRACECALL_F)
+ # define DEBUG_TRACECALLREGS() 	(M.x86.debug & DEBUG_TRACECALL_REGS_F)
++# define DEBUG_TRACEJMP()       (M.x86.debug & DEBUG_TRACEJMP_F)
++# define DEBUG_TRACEJMPREGS()   (M.x86.debug & DEBUG_TRACEJMP_REGS_F)
+ # define DEBUG_SYS()           	(M.x86.debug & DEBUG_SYS_F)
+ # define DEBUG_MEM_TRACE()     	(M.x86.debug & DEBUG_MEM_TRACE_F)
+ # define DEBUG_IO_TRACE()      	(M.x86.debug & DEBUG_IO_TRACE_F)
+@@ -96,6 +96,8 @@
+ # define DEBUG_SYSINT()        	0
+ # define DEBUG_TRACECALL()     	0
+ # define DEBUG_TRACECALLREGS() 	0
++# define DEBUG_TRACEJMP()       0
++# define DEBUG_TRACEJMPREGS()   0
+ # define DEBUG_SYS()           	0
+ # define DEBUG_MEM_TRACE()     	0
+ # define DEBUG_IO_TRACE()      	0
+@@ -169,14 +171,20 @@
+ 		x86emu_dump_regs();                                     \
+ 	if (DEBUG_TRACECALL())                                     	\
+ 		printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x);
+-# define RETURN_TRACE(n,u,v)                                    \
++# define RETURN_TRACE(u,v,w,x,s)                                    \
+ 	if (DEBUG_TRACECALLREGS())									\
+ 		x86emu_dump_regs();                                     \
+ 	if (DEBUG_TRACECALL())                                     	\
+-		printk("%04x:%04x: %s\n",u,v,n);
++		printk("%04x:%04x: RET %s %04x:%04x\n",u,v,s,w,x);
++# define  JMP_TRACE(u,v,w,x,s)                                 \
++   if (DEBUG_TRACEJMPREGS()) \
++      x86emu_dump_regs(); \
++   if (DEBUG_TRACEJMP()) \
++      printk("%04x:%04x: JMP %s%04x:%04x\n", u , v, s, w, x);
+ #else
+ # define CALL_TRACE(u,v,w,x,s)
+-# define RETURN_TRACE(n,u,v)
++# define RETURN_TRACE(u,v,w,x,s)
++# define  JMP_TRACE(u,v,w,x,s)
+ #endif
+ 
+ #ifdef DEBUG
+Index: include/x86emu/regs.h
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/regs.h,v
+retrieving revision 1.1
+retrieving revision 1.4
+diff -u -u -r1.1 -r1.4
+--- include/x86emu/regs.h	7 Sep 2007 10:01:21 -0000	1.1
++++ include/x86emu/regs.h	15 Jan 2008 13:46:40 -0000	1.4
+@@ -231,6 +231,9 @@
+ #define SYSMODE_PREFIX_REPNE    0x00000100
+ #define SYSMODE_PREFIX_DATA     0x00000200
+ #define SYSMODE_PREFIX_ADDR     0x00000400
++//phueper: for REP(E|NE) Instructions, we need to decide wether it should be using
++//the 32bit ECX register as or the 16bit CX register as count register
++#define SYSMODE_32BIT_REP       0x00000800
+ #define SYSMODE_INTR_PENDING    0x10000000
+ #define SYSMODE_EXTRN_INTR      0x20000000
+ #define SYSMODE_HALTED          0x40000000
+@@ -250,7 +253,8 @@
+ 						 SYSMODE_SEGOVR_GS      | \
+ 						 SYSMODE_SEGOVR_SS      | \
+ 						 SYSMODE_PREFIX_DATA    | \
+-						 SYSMODE_PREFIX_ADDR)
++						 SYSMODE_PREFIX_ADDR    | \
++						 SYSMODE_32BIT_REP)
+ 
+ #define  INTR_SYNCH           0x1
+ #define  INTR_ASYNCH          0x2
+@@ -274,9 +278,9 @@
+      */
+     u32                         mode;
+     volatile int                intr;   /* mask of pending interrupts */
+-	int                         debug;
++    volatile int                         debug;
+ #ifdef DEBUG
+-	int                         check;
++    int                         check;
+     u16                         saved_ip;
+     u16                         saved_cs;
+     int                         enc_pos;
+@@ -366,7 +370,7 @@
+ 
+ /* Function to log information at runtime */
+ 
+-//void	printk(const char *fmt, ...);
++void	printk(const char *fmt, ...);
+ 
+ #ifdef  __cplusplus
+ }                       			/* End of "C" linkage for C++   	*/
+Index: include/x86emu/x86emu.h
+===================================================================
+RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/x86emu.h,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -u -u -r1.1 -r1.3
+--- include/x86emu/x86emu.h	7 Sep 2007 10:01:21 -0000	1.1
++++ include/x86emu/x86emu.h	19 Oct 2007 08:42:15 -0000	1.3
+@@ -42,14 +42,6 @@
+ #ifndef __X86EMU_X86EMU_H
+ #define __X86EMU_X86EMU_H
+ 
+-/* FIXME: undefine printk for the moment */
+-#ifdef LINUXBIOS_VERSION
+-#include <console.h>
+-#define printk(x...) printk(BIOS_DEBUG, x)
+-#else
+-#define printk printf
+-#endif 
+-
+ #ifdef SCITECH
+ #include "scitech.h"
+ #define	X86API	_ASMAPI
+@@ -189,6 +181,8 @@
+ #define DEBUG_TRACECALL_REGS_F  0x004000
+ #define DEBUG_DECODE_NOPRINT_F  0x008000 
+ #define DEBUG_SAVE_IP_CS_F      0x010000
++#define DEBUG_TRACEJMP_F        0x020000
++#define DEBUG_TRACEJMP_REGS_F   0x040000
+ #define DEBUG_SYS_F             (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F)
+ 
+ void 	X86EMU_trace_regs(void);
+@@ -200,5 +194,4 @@
+ #ifdef  __cplusplus
+ }                       			/* End of "C" linkage for C++   	*/
+ #endif
+-
+ #endif /* __X86EMU_X86EMU_H */
diff --git a/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_download.sh b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_download.sh
new file mode 100755
index 0000000..36b1e10
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/other-licence/x86emu/x86emu_download.sh
@@ -0,0 +1,60 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+#!/bin/bash
+
+#set -x
+#set -e
+
+SVN=`which svn`
+PATCH=`which patch`
+DIFF_FILE=./x86emu_changes.diff
+
+# check wether svn, patch, ... is available...
+
+if [ ! -x $SVN ]; then
+	echo "subversion executable not found!"
+	exit -1
+fi
+if [ ! -x $PATCH ]; then
+	echo "patch executable not found!"
+	exit -1
+fi
+if [ ! -r $DIFF_FILE ]; then
+	echo "diff file $DIFF_FILE not found!"
+	exit -1
+fi
+
+# download the x86emu sources from LinuxBIOS subversion
+
+#revision known to work...
+REV=496
+
+echo "Checking out x86emu from coreboot-v3 repository revision $REV"
+$SVN co svn://coreboot.org/repository/coreboot-v3/util/x86emu -r $REV
+
+echo "Copying files..."
+
+cp -v x86emu/x86emu/*.c .
+cp -v x86emu/x86emu/*.h include/x86emu
+cp -v x86emu/include/x86emu/*.h include/x86emu
+
+echo "Removing checkedout subversion director..."
+
+rm -rf x86emu
+
+echo "Patching files..."
+
+$PATCH -p0 < x86emu_changes.diff
+
+
+echo "done"
+exit 0
diff --git a/qemu-0.15.x/roms/SLOF/romfs/header.img b/qemu-0.15.x/roms/SLOF/romfs/header.img
new file mode 100644
index 0000000..794129c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/header.img
@@ -0,0 +1 @@
+Key.Polynome....XXXXXXXX..Mask..XXXXXXXX.Polynome.Length....XXXX.Header.and.File.lengthXXXXXXXX... und weiter im Text!
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/Makefile b/qemu-0.15.x/roms/SLOF/romfs/tools/Makefile
new file mode 100644
index 0000000..8f399a8
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/Makefile
@@ -0,0 +1,55 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+# FIXME review -I ...
+# export NEW_BUILD=1
+
+TOPCMNDIR	?= ../..
+INCLCMNDIR	?= ../../include
+
+include $(TOPCMNDIR)/make.rules
+
+
+CPPFLAGS = -I$(INCLCMNDIR) -I$(INCLBRDDIR) -I.
+CFLAGS += $(FLAG)
+
+SRCS = build_ffs.c cfg_parse.c create_flash.c create_crc.c
+OBJS = $(SRCS:%.c=%.o)
+
+all: build_romfs
+
+build_romfs: $(OBJS)
+	$(HOSTCC) $(HOSTCFLAGS) $(FLAG) -o $@ $^
+
+testing: build_romfs
+	make -C test
+
+%.o: %.c
+	$(HOSTCC) $(CPPFLAGS) $(HOSTCFLAGS) $(FLAG) -c $< -o $@
+
+clean:
+	rm -f build_romfs *.o 
+
+distclean: clean
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	rm -f Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+	$(HOSTCC) -MM $(CPPFLAGS) $(HOSTCFLAGS) $(SRCS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/build_ffs.c b/qemu-0.15.x/roms/SLOF/romfs/tools/build_ffs.c
new file mode 100644
index 0000000..d00fecb
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/build_ffs.c
@@ -0,0 +1,476 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cfgparse.h>
+#include <createcrc.h>
+
+#define FFS_TARGET_HEADER_SIZE (4 * 8)
+
+extern int verbose;
+
+#define pad8_num(x) (((x) + 7) & ~7)
+
+static int
+file_exist(const char *name, int errdisp)
+{
+	struct stat fileinfo;
+
+	memset((void *) &fileinfo, 0, sizeof(struct stat));
+	if (stat(name, &fileinfo) != 0) {
+		if (0 != errdisp) {
+			perror(name);
+		}
+		return 0;
+	}
+	if (S_ISREG(fileinfo.st_mode)) {
+		return 1;
+	}
+	return 0;
+}
+
+static int
+file_getsize(const char *name)
+{
+	int rc;
+	struct stat fi;
+
+	rc = stat(name, &fi);
+	if (rc != 0)
+		return -1;
+	return fi.st_size;
+}
+
+static int
+ffshdr_compare(const void *_a, const void *_b)
+{
+	const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a;
+	const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b;
+
+	if (a->romaddr == b->romaddr)
+		return 0;
+	if (a->romaddr > b->romaddr)
+		return 1;
+	return -1;
+}
+
+static void
+hdr_print(struct ffs_header_t *hdr)
+{
+	printf("hdr: %p\n", hdr);
+	printf("\taddr:      %08llx token:    %s\n"
+	       "\tflags:     %08llx romaddr:  %08llx image_len: %08x\n"
+	       "\tsave_len:  %08llx ffsize:   %08x hdrsize:   %08x\n"
+	       "\ttokensize: %08x\n",
+	       hdr->addr, hdr->token, hdr->flags, hdr->romaddr,
+	       hdr->imagefile_length, hdr->save_data_len,
+	       hdr->ffsize, hdr->hdrsize, hdr->tokensize);
+}
+
+int
+reorder_ffs_chain(struct ffs_chain_t *fs)
+{
+	int i, j;
+	int free_space;
+	unsigned long long addr;
+	struct ffs_header_t *hdr;
+	int fix, flx, res, tab_size = fs->count;
+	struct ffs_header_t *fix_tab[tab_size];	/* fixed offset */
+	struct ffs_header_t *flx_tab[tab_size];	/* flexible offset */
+	struct ffs_header_t *res_tab[tab_size];	/* result */
+
+	/* determine size data to be able to do the reordering */
+	for (hdr = fs->first; hdr; hdr = hdr->next) {
+		if (hdr->linked_to)
+			hdr->imagefile_length = 0;
+		else
+			hdr->imagefile_length = file_getsize(hdr->imagefile);
+		if (hdr->imagefile_length == -1)
+			return -1;
+
+		hdr->tokensize = pad8_num(strlen(hdr->token) + 1);
+		hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize;
+		hdr->ffsize =
+		    hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8;
+	}
+
+	memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+	memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+	memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *));
+
+	/* now start with entries having fixed offs, reorder if needed */
+	for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next)
+		if (needs_fix_offset(hdr))
+			fix_tab[fix++] = hdr;
+		else
+			flx_tab[flx++] = hdr;
+	qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare);
+
+	/*
+	 * for fixed files we need to also remove the hdrsize from the
+	 * free space because it placed in front of the romaddr
+	 */
+	for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) {
+		fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize;
+		free_space = fix_tab[i]->addr - addr;
+
+		/* insert as many flexible files as possible */
+		for (; free_space > 0 && j < flx; j++) {
+			if (flx_tab[j]->ffsize <= free_space) {	/* fits */
+				flx_tab[j]->addr = addr;
+				free_space -= flx_tab[j]->ffsize;
+				addr += flx_tab[j]->ffsize;
+				res_tab[res++] = flx_tab[j];
+			} else
+				break;
+		}
+		res_tab[res++] = fix_tab[i];
+		addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize -
+		    fix_tab[i]->hdrsize;
+	}
+	/* at the end fill up the table with remaining flx entries */
+	for (; j < flx; j++) {
+		flx_tab[j]->addr = addr;
+		addr += flx_tab[j]->ffsize;
+		res_tab[res++] = flx_tab[j];
+	}
+
+	if (verbose) {
+		printf("--- resulting order ---\n");
+		for (i = 0; i < tab_size; i++)
+			hdr_print(res_tab[i]);
+	}
+
+	/* to check if the requested romfs images is greater than
+	 * the specified romfs_size it is necessary to add 8 for
+	 * the CRC to the totalsize */
+	addr += 8;
+
+	/* sanity checking if user specified maximum romfs size */
+	if ((fs->romfs_size != 0) && addr > fs->romfs_size) {
+		fprintf(stderr, "[build_romfs] romfs_size specified as %d "
+			"bytes, but %lld bytes need to be written.\n",
+			fs->romfs_size, addr);
+		return 1;
+	}
+
+	/* resort result list */
+	for (i = 0; i < tab_size - 1; i++)
+		res_tab[i]->next = res_tab[i + 1];
+	res_tab[i]->next = NULL;
+	fs->first = res_tab[0];
+	return 0;
+}
+
+/**
+ * allocate memory for a romfs file including header
+ */
+static unsigned char *
+malloc_file(int hdrsz, int datasz, int *ffsz)
+{
+	void *tmp;
+
+	/* complete file size is:
+	 * header + 8byte aligned(data) + end of file marker (-1) */
+	*ffsz = hdrsz + pad8_num(datasz) + 8;
+	/* get the mem */
+	tmp = malloc(*ffsz);
+
+	if (!tmp)
+		return NULL;
+
+	memset(tmp, 0, *ffsz);
+
+	return (unsigned char *) tmp;
+}
+
+static int
+copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize,
+	  int ffile_offset, int ffsize)
+{
+	int cnt = 0;
+	int imgfd;
+	int i;
+
+	if (!file_exist(hdr->imagefile, 1)) {
+		printf("access error to file: %s\n", hdr->imagefile);
+		free(ffile);
+		return -1;
+	}
+
+	imgfd = open(hdr->imagefile, O_RDONLY);
+	if (0 >= imgfd) {
+		perror(hdr->imagefile);
+		free(ffile);
+		return -1;
+	}
+
+	/* now copy file to file buffer */
+	/* FIXME using fread might be a good idea so
+	   that we do not need to deal with shortened
+	   reads/writes. Also error handling looks
+	   broken to me. Are we sure that all data is
+	   read when exiting this loop? */
+	while (1) {
+		i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset);
+		if (i <= 0)
+			break;
+		ffile_offset += i;
+		cnt += i;
+	}
+
+	/* sanity check */
+	if (cnt != datasize) {
+		printf("BUG!!! copy error on image file [%s](e%d, g%d)\n",
+		       hdr->imagefile, datasize, cnt);
+		close(imgfd);
+		free(ffile);
+		return -1;
+	}
+
+	close(imgfd);
+
+	return cnt;
+}
+
+static uint64_t
+next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize)
+{
+	uint64_t tmp;
+
+	/* no next file; end of filesystem */
+	if (hdr->next == NULL)
+		return 0;
+
+	if (hdr->next->romaddr > 0) {
+		/* the next file does not follow directly after the
+		 * current file because it requested to be
+		 * placed at a special address;
+		 * we need to calculate the offset of the
+		 * next file;
+		 * the next file starts at hdr->next->romaddr which
+		 * is the address requested by the user */
+		tmp = hdr->next->romaddr;
+		/* the next file starts, however, a bit earlier;
+		 * we need to point at the header of the next file;
+		 * therefore it is necessary to subtract the header size
+		 * of the _next_ file */
+		tmp -= FFS_TARGET_HEADER_SIZE;
+		/* also remove the length of the filename of the _next_
+		 * file */
+		tmp -= pad8_num(strlen(hdr->next->token) + 1);
+		/* and it needs to be relative to the current file */
+		tmp -= rom_pos;
+		return tmp;
+	}
+
+	/* if no special treatment is required the next file just
+	 * follows after the current file;
+	 * therefore just return the complete filesize as offset */
+	return ffsize;
+}
+
+static int
+next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize,
+		  unsigned int num_files)
+{
+	/* check if file wants a specific address */
+	void *tmp;
+
+	if ((hdr->flags & FLAG_LLFW) == 0)
+		/* flag to get a specific address has been set */
+		return rom_pos;
+
+	if (hdr->romaddr == 0)
+		/* if the requested address is 0 then
+		 * something is not right; ignore the flag */
+		return rom_pos;
+
+	/* check if romaddress is below current position */
+	if (hdr->romaddr < (rom_pos + hdrsize)) {
+		printf("[%s] ERROR: requested impossible " "romaddr of %llx\n",
+		       hdr->token, hdr->romaddr);
+		return -1;
+	}
+
+	/* spin offset to new positon */
+	if (pad8_num(hdr->romaddr) != hdr->romaddr) {
+		printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n");
+		return -1;
+	}
+
+	tmp = malloc(hdr->romaddr - rom_pos - hdrsize);
+
+	if (!tmp)
+		return -1;
+
+	memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize);
+	if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) {
+		free(tmp);
+		printf("write failed\n");
+		return -1;
+	}
+
+	free(tmp);
+
+	if (!num_files)
+		printf("\nWARNING: The filesystem will have no entry header!\n"
+		       "         It is still usable but you need to find\n"
+		       "         the FS by yourself in the image.\n\n");
+
+	return hdr->romaddr - hdrsize;
+}
+
+int
+build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime)
+{
+	int ofdCRC;
+	int ffsize, datasize, i;
+	int tokensize, hdrsize, ffile_offset, hdrbegin;
+	struct ffs_header_t *hdr;
+	unsigned char *ffile;
+	unsigned int rom_pos = 0;
+	unsigned int num_files = 0;
+	uint64_t tmp;
+
+	if (NULL == fs->first) {
+		return 1;
+	}
+	hdr = fs->first;
+
+	/* check output file and open it for creation */
+	if (file_exist(outfile, 0)) {
+		printf("Output file (%s) will be overwritten\n", outfile);
+	}
+
+	while (hdr) {
+
+		if (hdr->linked_to) {
+			printf("\nBUG!!! links not supported anymore\n");
+			return 1;
+		}
+
+		/* add +1 to strlen for zero termination */
+		tokensize = pad8_num(strlen(hdr->token) + 1);
+		hdrsize = FFS_TARGET_HEADER_SIZE + tokensize;
+		datasize = file_getsize(hdr->imagefile);
+
+		if (datasize == -1) {
+			perror(hdr->imagefile);
+			return 1;
+		}
+
+		ffile_offset = 0;
+		ffile = malloc_file(hdrsize, datasize, &ffsize);
+
+		if (NULL == ffile) {
+			perror("alloc mem for ffile");
+			return 1;
+		}
+
+		/* check if file wants a specific address */
+		rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files);
+		hdrbegin = rom_pos;
+
+		if (hdrbegin == -1) {
+			/* something went wrong */
+			free(ffile);
+			return 1;
+		}
+
+		/* write header ******************************************* */
+		/* next addr ********************************************** */
+		tmp = next_file_offset(hdr, rom_pos, ffsize);
+
+		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
+		rom_pos += 8;
+		ffile_offset += 8;
+
+		/* length ************************************************* */
+		hdr->save_data_len = datasize;
+
+		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize);
+		rom_pos += 8;
+		ffile_offset += 8;
+
+		/* flags ************************************************** */
+		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags);
+		rom_pos += 8;
+		ffile_offset += 8;
+
+		/* datapointer ******************************************** */
+
+		//save-data pointer is relative to rombase
+		hdr->save_data = hdrbegin + hdrsize;
+		hdr->save_data_valid = 1;
+		//changed pointers to be relative to file:
+		tmp = hdr->save_data - hdrbegin;
+
+		*(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp);
+		rom_pos += 8;
+		ffile_offset += 8;
+
+		/* name (token) ******************************************* */
+		memset(ffile + ffile_offset, 0, tokensize);
+		strcpy((char *) ffile + ffile_offset, hdr->token);
+		rom_pos += tokensize;
+		ffile_offset += tokensize;
+
+		/* image file ********************************************* */
+		i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize);
+
+		if (i == -1)
+			return 1;
+
+		/* pad file */
+		rom_pos += i + pad8_num(datasize) - datasize;
+		ffile_offset += i + pad8_num(datasize) - datasize;
+
+		/* limiter ************************************************ */
+		*(uint64_t *) (ffile + ffile_offset) = -1;
+		rom_pos += 8;
+		ffile_offset += 8;
+
+		if (buildDataStream(ffile, ffsize) != 0) {
+			printf
+			    ("Failed while processing file '%s' (size = %d bytes)\n",
+			     hdr->imagefile, datasize);
+			return 1;
+		}
+		free(ffile);
+		hdr = hdr->next;
+		num_files++;
+	}
+
+	/*
+	 * FIXME Current limination seems to be about 4MiB.
+	 */
+	ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+	if (0 > ofdCRC) {
+		perror(outfile);
+		return 1;
+	}
+	i = writeDataStream(ofdCRC, notime);
+	close(ofdCRC);
+
+	if (i)
+		return 1;
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/cfg_parse.c b/qemu-0.15.x/roms/SLOF/romfs/tools/cfg_parse.c
new file mode 100644
index 0000000..5137fbe
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/cfg_parse.c
@@ -0,0 +1,371 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cfgparse.h>
+
+static int inbetween_white(char *s, int max, char **start, char **end,
+			   char **next);
+static int add_header(struct ffs_chain_t *, struct ffs_header_t *);
+
+static int glob_come_from_cr = 0;
+
+static int
+find_next_entry(int file, struct ffs_chain_t *chain)
+{
+#define MAX_LINE_SIZE 1024
+	char lnbuf[MAX_LINE_SIZE], b0 = 0, b1 = 0;
+	char *start, *end, *next;
+	struct ffs_header_t *hdr;	//, *hdr2;
+	int lc, rc;
+	char c;
+
+	/* search for new config line */
+	if (0 == glob_come_from_cr) {
+		while (1 == (rc = read(file, &c, 1))) {
+			//printf("b0=%c b1=%c c=%c\n",
+			//              b0, b1, c);
+			b0 = b1;
+			b1 = c;
+			/* this looks for starting sign "<CR>[^#]" */
+			if (((0x0a == b0) || (0x0d == b0)) &&
+			    (('#' != b1) && (0x0a != b1) && (0x0d != b1))) {
+				break;
+			}
+		}
+	} else {
+		/* normalize */
+		while (1 == (rc = read(file, &c, 1))) {
+			//printf("read c=%c\n", c);
+			if ((0x0a != c) && (0x0d != c)) {
+				break;
+			}
+		}
+		glob_come_from_cr = 0;
+		//printf("debug: glob_come_from_cr = 0\n");
+	}
+	if (1 != rc) {
+		return 1;
+	}
+
+	/* now buffer it until end of line */
+	memset((void *) lnbuf, 0, MAX_LINE_SIZE);
+	lnbuf[0] = c;
+	lc = 1;
+	while ((1 == read(file, &(lnbuf[lc]), 1)) && (lc < MAX_LINE_SIZE)) {
+		//printf("read lnbuf=%c\n", lnbuf[lc]);
+		if ((0x0a == lnbuf[lc]) || (0x0d == lnbuf[lc])) {
+			glob_come_from_cr = 1;
+			//printf("debug: glob_come_from_cr = 1\n");
+			break;
+		}
+		lc++;
+	}
+
+	/* allocate header */
+	hdr = malloc(sizeof(struct ffs_header_t));
+	if (NULL == hdr) {
+		perror("alloc memory");
+		return 2;
+	}
+	memset((void *) hdr, 0, sizeof(struct ffs_header_t));
+
+	/* attach header to chain */
+	if (0 != add_header(chain, hdr)) {
+		return 2;
+	}
+
+	/**********************************************************/
+	/* extract token name *********************************** */
+	start = NULL;
+	if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) {
+		printf("parsing error 1");
+		return 2;
+	}
+	/* get memory for it */
+	hdr->token = malloc(end - start + 1);
+	if (NULL == hdr->token) {
+		return 2;
+	}
+	/* set string */
+	strncpy(hdr->token, start, end - start + 1);
+	hdr->token[end - start] = 0;
+
+	/**********************************************************/
+	/* extract file name *********************************** */
+	if (NULL == next) {
+		return 2;
+	}
+	start = next;
+	if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) {
+		printf("parsing error 1");
+		return 2;
+	}
+
+	/* get memory for it */
+	hdr->imagefile = malloc(end - start + 1);
+	if (NULL == hdr->imagefile) {
+		return 2;
+	}
+
+	/* check if file is existing */
+
+	/* set string */
+	strncpy(hdr->imagefile, start, end - start + 1);
+	hdr->imagefile[end - start] = 0;
+
+	/* check if entry is linked to another header */
+	if (':' == *start) {
+		printf
+		    ("\nERROR: links are removed as feature in this version\n");
+		return 2;
+
+		/*
+		   start++;
+		   if (0 != find_entry_by_token(chain, hdr->imagefile+1, &hdr2)) {
+		   printf("[%s]: link to [%s] not found\n", 
+		   hdr->token, hdr->imagefile+1);
+		   dump_fs_contents(chain);
+		   return 2;
+		   }
+		   hdr->linked_to = hdr2;
+		 */
+	}
+
+	/**********************************************************/
+	/* extract flags name *********************************** */
+	if (NULL == next) {
+		return 2;
+	}
+	start = next;
+	if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) {
+		printf("parsing error 1");
+		return 2;
+	}
+	hdr->flags = strtoul(start, NULL, 16);
+
+	/**********************************************************/
+	/* extract rom start name *********************************** */
+	if (NULL == next) {
+		return 2;
+	}
+	start = next;
+	if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) {
+		printf("parsing error 1");
+		return 2;
+	}
+	if ('-' == *start) {
+		/* this means not specific address request for data */
+		hdr->romaddr = 0;
+	} else {
+		/* data has to begin at specific address */
+		hdr->romaddr = strtoul(start, NULL, 16);
+	}
+
+	return 0;
+}
+
+int
+read_config(int conf_file, struct ffs_chain_t *ffs_chain)
+{
+	int rc;
+
+	while (1) {
+		rc = find_next_entry(conf_file, ffs_chain);
+		if (rc != 0)
+			break;
+	}
+	return rc;
+}
+
+static int
+inbetween_white(char *s, int max, char **start, char **end, char **next)
+{
+	int pos = 0, posalt;
+
+	if (NULL != *start) {
+		pos = *start - s;
+		s = *start;
+	}
+
+	/* wind to first non white */
+	while (pos < max) {
+		if ((' ' == *s) || ('	' == *s)) {
+			s++;
+			pos++;
+			continue;
+		}
+		break;
+	}
+	if (pos >= max) {
+		/* no non-white found */
+		return 1;
+	}
+
+	/* assign start */
+	*start = s;
+
+	/* wind to end of non white or end of buffer */
+	posalt = pos;
+	while (pos < max) {
+		if ((' ' == *s) || ('	' == *s) ||
+		    (0x0a == *s) || (0x0d == *s)) {
+			break;
+		}
+		s++;
+		pos++;
+	}
+
+	if (pos == posalt) {
+		return 1;
+	}
+
+	*end = s;
+
+	if ((pos + 1) >= max) {
+		*next = NULL;
+	} else {
+		*next = s;
+	}
+
+	return 0;
+}
+
+int
+add_header(struct ffs_chain_t *chain, struct ffs_header_t *hdr)
+{
+	struct ffs_header_t *next;
+
+	if (NULL == chain->first) {
+		chain->count = 1;
+		chain->first = hdr;
+		return 0;
+	}
+	next = chain->first;
+
+	/* find last */
+	while (NULL != next->next) {
+		next = next->next;
+	}
+	next->next = hdr;
+	chain->count++;
+
+	return 0;
+}
+
+void
+dump_fs_contents(struct ffs_chain_t *chain)
+{
+	struct ffs_header_t *next;
+
+	if (NULL == chain->first) {
+		printf("no contents in fs\n");
+		return;
+	}
+	next = chain->first;
+
+	while (1) {
+		if (NULL != next->token) {
+			printf("Token [%s] ", next->token);
+		} else {
+			printf(" [not-set], ");
+		}
+
+		if (NULL != next->imagefile) {
+			printf(" <%s>, ", next->imagefile);
+		} else {
+			printf(" file<not-set>, ");
+		}
+
+		printf("flags<%llx>, ", next->flags);
+		printf("romaddr<%llx>, ", next->romaddr);
+
+		if (NULL != next->linked_to) {
+			printf("linked to [%s]", next->linked_to->token);
+		}
+
+		printf("\n");
+		if (NULL == next->next) {
+			break;
+		}
+
+		next = next->next;
+	}
+
+}
+
+void
+free_chain_memory(struct ffs_chain_t *chain)
+{
+	struct ffs_header_t *hdr, *next_hdr;
+
+	if (NULL != chain->first) {
+		hdr = chain->first;
+		chain->first = NULL;
+	} else {
+		return;
+	}
+
+	while (NULL != hdr) {
+		//printf("%p  ", hdr);
+		if (NULL != hdr->token) {
+			//printf("free up %s\n", hdr->token);
+			free(hdr->token);
+		}
+		if (NULL != hdr->imagefile) {
+			free(hdr->imagefile);
+		}
+		next_hdr = hdr->next;
+		free(hdr);
+		hdr = next_hdr;
+	}
+}
+
+
+/*
+ * Detect duplicate entries in the romfs list
+ */
+void
+find_duplicates(struct ffs_chain_t *chain)
+{
+	struct ffs_header_t *act, *sub;
+
+	if (NULL == chain->first) {
+		printf("no contents in fs\n");
+		return;
+	}
+	act = chain->first;
+
+	do {
+		sub = act->next;
+		while (sub != NULL) {
+
+			if (act->token == NULL || sub->token == NULL) {
+				printf("find_duplicates: token not set!\n");
+			} else if (strcmp(act->token, sub->token) == 0) {
+				printf("*** NOTE: duplicate romfs file '%s'.\n",
+				       act->token);
+			}
+			sub = sub->next;
+		}
+
+		act = act->next;
+
+	} while (act != NULL);
+
+}
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/cfgparse.h b/qemu-0.15.x/roms/SLOF/romfs/tools/cfgparse.h
new file mode 100644
index 0000000..ed5c885
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/cfgparse.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef CFGPARSE_H
+#define CFGPARSE_H
+
+#include <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be64(x)	(x)
+#else
+#define cpu_to_be64(x)	bswap_64(x)
+#endif
+
+struct ffs_chain_t {
+	int count;
+	unsigned int romfs_size;
+	struct ffs_header_t *first;
+};
+
+#define FLAG_LLFW 1		/* low level firmware at fix offs in romfs */
+
+#define needs_fix_offset(hdr) ((hdr)->flags & FLAG_LLFW)
+
+struct ffs_header_t {
+	unsigned long long flags;
+	unsigned long long romaddr;
+	char *token;
+	char *imagefile;
+	int imagefile_length;
+	struct ffs_header_t *linked_to;
+	struct ffs_header_t *next;
+	unsigned long long save_data;
+	unsigned long long save_data_len;
+	int save_data_valid;
+
+	unsigned long long addr;	/* tmp */
+	int hdrsize;		/* tmp */
+	int tokensize;		/* tmp */
+	int ffsize;		/* tmp */
+};
+
+void dump_fs_contents(struct ffs_chain_t *chain);
+void find_duplicates(struct ffs_chain_t *chain);
+void free_chain_memory(struct ffs_chain_t *chain);
+
+int read_config(int conf_file, struct ffs_chain_t *ffs_chain);
+int reorder_ffs_chain(struct ffs_chain_t *fs);
+int build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime);
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/create_crc.c b/qemu-0.15.x/roms/SLOF/romfs/tools/create_crc.c
new file mode 100644
index 0000000..8ea6347
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/create_crc.c
@@ -0,0 +1,467 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <cfgparse.h>
+#include <time.h>
+#include <calculatecrc.h>
+#include <product.h>
+#include "createcrc.h"
+
+int createHeaderImage(int);
+unsigned int calCRCEthernet32(unsigned char *TextPtr,
+			      unsigned long int TextLength,
+			      unsigned int AccumCRC);
+int createCRCParameter(uint64_t * ui64RegisterMask,
+		       unsigned int *iRegisterLength);
+uint64_t calCRCbyte(unsigned char *TextPtr, uint32_t Residual,
+		    uint64_t AccumCRC);
+uint64_t calCRCword(unsigned char *TextPtr, uint32_t Residual,
+		    uint64_t AccumCRC);
+uint64_t checkCRC(unsigned char *TextPtr, uint32_t Residual, uint64_t AccumCRC);
+
+/* file length in bytes */
+static uint64_t ui64globalFileSize = 0;
+/* space for the file stream >= 4MB + 4bytes */
+static unsigned char pucFileStream[4400000];
+/* header length in bytes */
+static uint64_t ui64globalHeaderSize = 0;
+/* flag to filter detect the header in buildDataStream() */
+static int iglobalHeaderFlag = 1;
+static uint64_t ui64Generator1;
+
+/**
+ * Build the file image and store it as Data Stream of bytes
+ * calculate a first CRC for the first file and
+ * catch the position of this CRC
+ */
+int
+buildDataStream(unsigned char *pucbuf, int size)
+{
+	if (ui64globalFileSize + size > sizeof(pucFileStream)) {
+		printf("Error: File size is too big!\n");
+		return -1;
+	}
+
+	/* copy the data into the destination buffer */
+	memcpy(pucFileStream + ui64globalFileSize, pucbuf, size);
+	ui64globalFileSize += size;
+
+	if (iglobalHeaderFlag == 1) {	// catch header
+
+		ui64globalHeaderSize = ui64globalFileSize;
+		iglobalHeaderFlag = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * write Header.img
+ */
+int
+createHeaderImage(int notime)
+{
+	int iCounter;
+	uint64_t ui64RomAddr, ui64DataAddr;
+	time_t caltime;
+	struct tm *tm;
+	char *pcVersion;
+	char dastr[16] = { 0, };
+	unsigned long long da = 0;
+
+	union {
+		unsigned char pcArray[FLASHFS_HEADER_DATA_SIZE];
+		struct stH stHeader;
+	} uHeader;
+
+	/* initialize Header */
+	memset(uHeader.pcArray, 0x00, FLASHFS_HEADER_DATA_SIZE);
+
+	/* read driver info */
+	if (NULL != (pcVersion = getenv("DRIVER_NAME"))) {
+		strncpy(uHeader.stHeader.version, pcVersion, 16);
+	} else if (NULL != (pcVersion = getenv("USER"))) {
+		strncpy(uHeader.stHeader.version, pcVersion, 16);
+	} else if (pcVersion == NULL) {
+		strncpy(uHeader.stHeader.version, "No known user!", 16);
+	}
+
+	if (!notime) {
+		/* read time and write it into data stream */
+		if ((caltime = time(NULL)) == -1) {
+			printf("time error\n");
+		}
+		if ((tm = localtime(&caltime)) == NULL) {
+			printf("local time error\n");
+		}
+		// length must be 13 instead 12 because of terminating
+		// NUL. Therefore uH.stH.platform_revison must be
+		// writen later to overwrite the terminating NUL
+		if (strftime(dastr, 15, "0x%Y%m%d%H%M", tm) == 0) {
+			printf("strftime error\n");
+		}
+		da = cpu_to_be64(strtoll(dastr, NULL, 16));
+	}
+	memcpy(uHeader.stHeader.date, &da, 8);
+
+	/* write Magic value into data stream */
+	strncpy(uHeader.stHeader.magic, FLASHFS_MAGIC, 8);
+	/* write platform name into data stream */
+	strcpy(uHeader.stHeader.platform_name, FLASHFS_PLATFORM_MAGIC);
+	/* write platform revision into data stream */
+	strcpy(uHeader.stHeader.platform_revision, FLASHFS_PLATFORM_REVISION);
+
+
+	/* fill end of file info (8 bytes of FF) into data stream */
+	uHeader.stHeader.ui64FileEnd = -1;
+
+	/* read address of next file and address of header date, both are 64 bit values */
+	ui64RomAddr = 0;
+	ui64DataAddr = 0;
+	for (iCounter = 0; iCounter < 8; iCounter++) {
+		/* addr of next file */
+		ui64RomAddr = (ui64RomAddr << 8) + pucFileStream[FLASHFS_ROMADDR + iCounter];
+		/* addr of header data */
+		ui64DataAddr = (ui64DataAddr << 8) + pucFileStream[FLASHFS_DATADDR + iCounter];
+	}
+
+	/* calculate final flash-header-size and flash-file-size */
+	/* calculate end addr of header */
+	ui64globalHeaderSize = (uint32_t) ui64DataAddr + (uint32_t) FLASHFS_HEADER_DATA_SIZE;
+	/* cut 64 bit to place CRC for File-End */
+	ui64globalHeaderSize -= 8;
+	/* add 64 bit to place CRC behind File-End */
+	ui64globalFileSize += 8;
+
+	if (ui64globalHeaderSize >= ui64RomAddr) {
+		printf("%s\n", "--- Header File to long");
+		return 1;
+	}
+
+	/* fill free space in Header with zeros */
+	memset(&pucFileStream[ui64DataAddr], 0, (ui64RomAddr - ui64DataAddr));
+	/* place data to header */
+	memcpy(&pucFileStream[ui64DataAddr], uHeader.pcArray,
+	       FLASHFS_HEADER_DATA_SIZE);
+
+	/* insert header length into data stream */
+	*(uint64_t *) (pucFileStream + FLASHFS_HEADER_SIZE_ADDR) =
+	    cpu_to_be64(ui64globalHeaderSize);
+
+	/* insert flash length into data stream */
+	*(uint64_t *) (pucFileStream + ui64DataAddr + FLASHFS_FILE_SIZE_ADDR) =
+	    cpu_to_be64(ui64globalFileSize);
+
+	/* insert zeros as placeholder for CRC */
+	*(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = 0;
+	*(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = 0;
+
+	return 0;
+}
+
+/**
+ * calculate standart ethernet 32 bit CRC
+ * generator polynome is 0x104C11DB7
+ * this algorithm can be used for encoding and decoding
+ */
+unsigned int
+calCRCEthernet32(unsigned char *TextPtr, unsigned long int TextLength,
+		 unsigned int AccumCRC)
+{
+	const unsigned int CrcTableHigh[16] = {
+		0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90,
+		0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7,
+		0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E,
+		0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09
+	};
+	const unsigned CrcTableLow[16] = {
+		0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
+		0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
+		0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
+		0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
+	};
+
+	unsigned char *Buffer = TextPtr;
+	unsigned long int Residual = TextLength;
+
+
+	while (Residual > 0) {
+		unsigned int Temp = ((AccumCRC >> 24) ^ *Buffer) & 0x000000ff;
+		AccumCRC <<= 8;
+		AccumCRC ^= CrcTableHigh[Temp / 16];
+		AccumCRC ^= CrcTableLow[Temp % 16];
+		++Buffer;
+		--Residual;
+	}
+	return AccumCRC;
+}
+
+/**
+ * create CRC Parameter:  CRC Polynome, Shiftregister Mask and length
+ *
+ *   ui64Generator[0] = 0;
+ *   ui64Generator[1] = 0x42F0E1EB;
+ *   ui64Generator[1] = (ui64Generator[1] << 32) + 0xA9EA3693;
+ *   iRegisterLength = 63;
+ *   ui64RegisterMask =  0xffffffff;
+ *   ui64RegisterMask = ((ui64RegisterMask) << 32) + 0xffffffff;
+ *
+ *    ucl=0x00000000ffffffff = Mask for 32 bit LSFR to cut down number of bits
+ *    in the variable to get the same length as LFSR
+ *
+ *    il = length of LSFR = degree of generator polynom reduce il by one to calculate the degree
+ *    of the highest register in LSFR
+ *
+ *    Examples:
+ *    CRC-16 for Tap:		x16 + x15 + x2 + 1
+ *     generator = 0x8005,	il = 16,	ucl = 0x000000000000FFFF
+ *
+ *    CRC-16 for Floppy:		x16 + x12 + x5 +1
+ *     generator = 0x1021,	il = 16,	ucl = 0x000000000000FFFF
+ *
+ *    CRC-32 for Ethernet:	x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
+ *     generator = 0x04C11DB7,	il = 32,	ucl = 0x00000000FFFFFFFF
+ *
+ *    CRC-64 SP-TrEMBL	x64 + x4 + x3 + x + 1 (maximal-length LFSR)
+ *     generator = 0x1B,	il = 64,	ucl = 0xFFFFFFFFFFFFFFFF
+ *
+ *    CRC-64 improved
+ *     x64 + x63 + x61 + x59 + x58 + x56 + x55 + x52 + x49 + x48 + x47 + x46+ x44 +
+ *     x41 + x37 + x36 + x34 + x32 + x31 + x28 + x26 + x23 + x22 + x19 + x16 + x13 +
+ *     x12 + x10 + x9 + x6 + x4 + x3 + 1
+ *     (see http://www.cs.ud.ac.uk/staff/D.Jones/crcbote.pdf)
+ *     generator = 0xAD93D23594C9362D,  il = 64,    ucl = 0xFFFFFFFFFFFFFFFF
+ *
+ *    CRC-64 DLT1 spec
+ *     x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 +
+ *     x35 + x33 + x32 + x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 +
+ *     x10 + x9 + x7 + x4 + x + 1
+ *     (see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf  -> page63)
+ *     generator = 0x42F0E1EBA9EA3693
+ *
+ *    CRC-64 from internet G(x)= 1006003C000F0D50B
+ */
+int
+createCRCParameter(uint64_t * ui64RegisterMask, unsigned int *uiRegisterLength)
+{
+	enum Generators { Tape_16, Floppy_16, Ethernet_32, SPTrEMBL_64,
+		SPTrEMBL_improved_64, DLT1_64
+	};
+	enum Generators Generator;
+
+	Generator = CRC_METHODE;
+	switch (Generator) {
+	case Tape_16:{
+			*ui64RegisterMask = 0x0000ffff;
+			ui64Generator1 = 0x00008005;
+			*uiRegisterLength = 16;
+			break;
+		}
+	case Floppy_16:{
+			*ui64RegisterMask = 0x0000ffff;
+			ui64Generator1 = 0x00001021;
+			*uiRegisterLength = 16;
+			break;
+		}
+	case Ethernet_32:{
+			*ui64RegisterMask = 0xffffffff;
+			ui64Generator1 = 0x04C11DB7;
+			*uiRegisterLength = 32;
+			break;
+		}
+	case SPTrEMBL_64:{
+			*ui64RegisterMask = 0xffffffff;
+			*ui64RegisterMask =
+			    ((*ui64RegisterMask) << 32) + 0xffffffff;
+			ui64Generator1 = 0x0000001B;
+			*uiRegisterLength = 64;
+			break;
+		}
+	case SPTrEMBL_improved_64:{
+			*ui64RegisterMask = 0xffffffff;
+			*ui64RegisterMask =
+			    ((*ui64RegisterMask) << 32) + 0xffffffff;
+			ui64Generator1 = 0xAD93D235;
+			ui64Generator1 = (ui64Generator1 << 32) + 0x94C9362D;
+			*uiRegisterLength = 64;
+			break;
+		}
+	case DLT1_64:{
+			*ui64RegisterMask = 0xffffffff;
+			*ui64RegisterMask =
+			    ((*ui64RegisterMask) << 32) + 0xffffffff;
+			ui64Generator1 = 0x42F0E1EB;
+			ui64Generator1 = (ui64Generator1 << 32) + 0xA9EA3693;
+			*uiRegisterLength = 64;
+			break;
+		}
+	}
+	(*uiRegisterLength)--;
+
+	return 0;
+}
+
+/**
+ *  Check CRC by using Linear Feadback Shift Register (LFSR)
+ */
+uint64_t
+calCRCbyte(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
+{
+
+	uint64_t ui64Mask, ui64Generator0;
+	uint8_t ui8Buffer;
+	unsigned int uiRegisterLength;
+	int iShift;
+
+	createCRCParameter(&ui64Mask, &uiRegisterLength);
+
+	ui8Buffer = (*cPtr);
+	while (ui32NoWords > 0) {
+		for (iShift = 7; iShift >= 0; iShift--) {
+
+			ui64Generator0 = (AccumCRC >> uiRegisterLength);
+			AccumCRC <<= 1;
+			ui64Generator0 &= 0x01;
+			ui64Generator0 = (0 - ui64Generator0);
+			AccumCRC ^= (ui64Generator1 & ui64Generator0);
+		}
+		AccumCRC ^= ui8Buffer;
+		AccumCRC &= ui64Mask;
+		ui32NoWords -= 1;
+		cPtr += 1;
+		ui8Buffer = (*cPtr);
+	}
+	return AccumCRC;
+}
+
+/**
+ *  Check CRC by using Linear Feadback Shift Register (LFSR)
+ */
+uint64_t
+calCRCword(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
+{
+
+	uint64_t ui64Mask, ui64Generator0;
+	uint16_t ui16Buffer;
+	unsigned int uiRegisterLength;
+	int iShift;
+
+	createCRCParameter(&ui64Mask, &uiRegisterLength);
+
+	if ((ui32NoWords % 2) != 0) {
+		/* if Data string does not end at word boundery add one byte */
+		ui32NoWords++;
+		cPtr[ui32NoWords] = 0;
+	}
+	ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
+	while (ui32NoWords > 0) {
+		for (iShift = 15; iShift >= 0; iShift--) {
+			ui64Generator0 = (AccumCRC >> uiRegisterLength);
+			AccumCRC <<= 1;
+			ui64Generator0 &= 0x01;
+			ui64Generator0 = (0 - ui64Generator0);
+			AccumCRC ^= (ui64Generator1 & ui64Generator0);
+		}
+		AccumCRC ^= ui16Buffer;
+		AccumCRC &= ui64Mask;
+		ui32NoWords -= 2;
+		cPtr += 2;
+		ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
+	}
+	return AccumCRC;
+}
+
+uint64_t
+checkCRC(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
+{
+
+	enum Generators { Ethernet_32 };
+	enum Generators Generator;
+	uint64_t ui64Buffer = AccumCRC;
+
+	Generator = CRC_METHODE;
+
+	switch (Generator) {
+	case Ethernet_32:{
+			/* (ui32NoWords - 4),no need of 4 bytes 0x as
+			 * with shift-register method */
+			AccumCRC =
+			    calCRCEthernet32(cPtr, (ui32NoWords - 4), AccumCRC);
+			break;
+		}
+	default:{
+			AccumCRC = calCRCword(cPtr, ui32NoWords, AccumCRC);
+			break;
+		}
+	}
+
+	if (calCRCbyte(cPtr, ui32NoWords, ui64Buffer) != AccumCRC) {
+		printf("\n --- big Endian - small Endian problem --- \n");
+		AccumCRC--;
+	}
+
+	return (AccumCRC);
+}
+
+/**
+ *  insert header and file CRC into data stream
+ *  do CRC check on header and file
+ *  write data stream to disk
+ */
+int
+writeDataStream(int iofd, int notime)
+{
+	uint64_t ui64FileCRC = 0, ui64HeaderCRC = 0, ui64RegisterMask;
+	unsigned int uiRegisterLength;
+
+	if (0 != createHeaderImage(notime)) {
+		return 1;
+	}
+
+	createCRCParameter(&ui64RegisterMask, &uiRegisterLength);
+
+	/* calculate CRC */
+	ui64HeaderCRC = checkCRC(pucFileStream, ui64globalHeaderSize, 0);
+	*(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) =
+	    cpu_to_be64(ui64HeaderCRC);
+
+	ui64FileCRC = checkCRC(pucFileStream, ui64globalFileSize, 0);
+	*(uint64_t *) (pucFileStream + ui64globalFileSize - 8) =
+	    cpu_to_be64(ui64FileCRC);
+
+	/* check CRC-implementation */
+	ui64HeaderCRC = calCRCword(pucFileStream, ui64globalHeaderSize, 0);
+	ui64FileCRC = calCRCword(pucFileStream, ui64globalFileSize, 0);
+
+	if ((ui64HeaderCRC != 0) || (ui64FileCRC != 0)) {
+		printf("\n\n %s \n %s \n\n", "CRCs not correct implemented.",
+		       " ---> Data will not be written do disk.");
+		return -1;
+	}
+
+	/* write file image to disk */
+	if (0 < write(iofd, pucFileStream, ui64globalFileSize))
+		return 0;
+
+	printf("<< write failed >>\n");
+	return -1;
+}
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/create_flash.c b/qemu-0.15.x/roms/SLOF/romfs/tools/create_flash.c
new file mode 100644
index 0000000..f99fd62
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/create_flash.c
@@ -0,0 +1,163 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <cfgparse.h>
+
+int verbose = 0;
+
+#define dprintf(fmt, args...) if (verbose) printf(fmt, ##args)
+
+static void
+print_usage(void)
+{
+	printf
+	    ("Usage: build_romfs [-?] [--help] [-s|--romfs-size <romfs_size>]\n"
+	     "\t[-p|--smart-pad] [-n|--notime] <config-file> <output-file>\n");
+}
+
+unsigned long
+str_to_num(const char *str)
+{
+	char *s = (char *) str;
+	unsigned long num = strtoul(s, &s, 0);
+	if (s) {
+		if (s[0] == 'K')
+			num <<= 10;
+		if (s[0] == 'M')
+			num <<= 20;
+	}
+	return num;
+}
+
+/*
+ * NOTE: We should consider to install an exit handler which does the
+ * unlink() of the output file. In case of error we just do exit() and
+ * forget about all the clumsy error handling free/close code, which
+ * blows up the code significantly and makes it hard to read.
+ */
+int
+main(int argc, char *argv[])
+{
+	int conf_file, rc;
+	struct ffs_chain_t ffs_chain;
+	int c;
+	int smart_pad = 0;	/* default */
+	int notime = 0;
+	const char *config_file = "boot_rom.ffs";
+	const char *output_file = "boot_rom.bin";
+
+	memset((void *) &ffs_chain, 0, sizeof(struct ffs_chain_t));
+
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{"romfs-size", 1, 0, 's'},
+			{"smart-pad", 0, 0, 'p'},
+			{"notime", 0, 0, 'n'},
+			{"verbose", 0, 0, 'v'},
+			{"help", 1, 0, 'h'},
+			{0, 0, 0, 0}
+		};
+		c = getopt_long(argc, argv, "s:ph?nv", long_options,
+				&option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 's':
+			ffs_chain.romfs_size = str_to_num(optarg);
+			break;
+		case 'p':
+			smart_pad = 1;
+			break;
+		case 'n':
+			notime = 1;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		case '?':
+		case 'h':
+			print_usage();
+			return EXIT_SUCCESS;
+		default:
+			printf("?? getopt returned character code 0%o ??\n", c);
+		}
+	}
+
+	/* two files must always be specified: config-file and output-file */
+	if (optind + 2 != argc) {
+		print_usage();
+		return EXIT_FAILURE;
+	}
+
+	config_file = argv[optind++];
+	output_file = argv[optind++];
+
+	dprintf("ROMFS FILESYSTEM CREATION V0.3 (bad parser)\n"
+		"Build directory structure...\n"
+		"  smart padding %s, maximum romfs size %d bytes\n",
+		smart_pad ? "enabled" : "disabled", ffs_chain.romfs_size);
+
+	conf_file = open(config_file, O_RDONLY);
+	if (0 >= conf_file) {
+		perror("load config file:");
+		return EXIT_FAILURE;
+	}
+
+	rc = read_config(conf_file, &ffs_chain);
+	close(conf_file);
+	if (rc < 1) {
+		fprintf(stderr, "flash cannot be built due to config errors\n");
+		return EXIT_FAILURE;
+	}
+
+	rc = EXIT_SUCCESS;
+
+	if (verbose)
+		dump_fs_contents(&ffs_chain);
+	if (smart_pad)
+		/* FIXME: size is only verified during reorder */
+		rc = reorder_ffs_chain(&ffs_chain);
+
+	if (rc == EXIT_FAILURE)
+		goto out;
+
+	dprintf("Build ffs and write to image file...\n");
+	if (build_ffs(&ffs_chain, output_file, notime) != 0) {
+		fprintf(stderr, "build ffs failed\n");
+		rc = EXIT_FAILURE;
+	} else {
+		rc = EXIT_SUCCESS;
+	}
+
+	/* Check if there are any duplicate entries in the image,
+	   print warning if this is the case. */
+	find_duplicates(&ffs_chain);
+	free_chain_memory(&ffs_chain);
+	dprintf("\n");
+
+      out:
+	/* If the build failed, remove the target image file */
+	if (rc == EXIT_FAILURE)
+		unlink(output_file);
+
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/SLOF/romfs/tools/createcrc.h b/qemu-0.15.x/roms/SLOF/romfs/tools/createcrc.h
new file mode 100644
index 0000000..1f23598
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/romfs/tools/createcrc.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef CREATECRC_H
+#define CREATECRC_H
+
+int buildDataStream(unsigned char *pucbuf, int size);
+int createHeaderImgage(char *pcFilename);
+int writeDataStream(int ofd, int notime);
+
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/rtas/Makefile.inc b/qemu-0.15.x/roms/SLOF/rtas/Makefile.inc
new file mode 100644
index 0000000..4297f86
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/Makefile.inc
@@ -0,0 +1,89 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+# Before including this Makefile, you should specify the following variables
+# in your Makefile:
+# - RTASCMNDIR : Points to the common RTAS directory
+# - RTASBRDDIR : Points to the board specific RTAS directory
+# - TOOLSDIR : Points to the common tools directory
+# - OBJS : A list with all object files that should be linked into rtas.bin
+# - BOARD_SRCS : A list with all board specific source code files
+#                (needed for "make depend")
+
+
+LDFLAGS		= -nostdlib
+CPPFLAGS	+= -I$(RTASBRDDIR) -I$(RTASCMNDIR) \
+		  -I$(INCLCMNDIR) -I$(INCLBRDDIR) \
+		  -I$(LIBCMNDIR)/libc/include \
+		  -I$(INCLCMNDIR)/$(CPUARCH)
+ASFLAGS		= -Wa,-mregnames $(FLAG)
+CFLAGS		+= -g -nostdinc -ffreestanding -Wall -Wextra -O2 -msoft-float \
+		  -mno-altivec -mabi=no-altivec $(FLAG)
+
+# Common RTAS files:
+RTAS_SRC_ASM	= reloc.S rtas_common.S rtas_entry.S rtas_term.S \
+		  rtas_cpu.S rtas_flash_asm.S rtas_mem.S rtas_ras.S
+RTAS_SRC_C	= rtas_call.c rtas_flash_c.c rtas_h8.c \
+		  rtas_nvramlog.c rtas_sensor.c rtas_init.c \
+		  rtas_flash_cfi.c
+RTAS_SRCS	= $(RTAS_SRC_ASM) $(RTAS_SRC_C)
+RTAS_OBJ_ASM	= $(RTAS_SRC_ASM:%.S=%.o)
+RTAS_OBJ_C	= $(RTAS_SRC_C:%.c=%.o)
+
+# Common build rules:
+$(RTAS_OBJ_C):
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $(@:%.o=$(RTASCMNDIR)/%.c) -o $@
+
+$(RTAS_OBJ_ASM):
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c $(@:%.o=$(RTASCMNDIR)/%.S) -o $@
+
+$(TOOLSDIR)/gen_reloc_table: $(TOOLSDIR)/gen_reloc_table.c
+	$(MAKE) -C $(TOOLSDIR) gen_reloc_table
+
+
+# Rules for building rtas.bin:
+rtas.bin: rtas
+	$(OBJCOPY) -O binary $< $@
+
+rtas: $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o $(LIBCMNDIR)/libc.a
+	$(LD) $(LDFLAGS) -o $@ -T $(RTASCMNDIR)/rtas.lds $(OBJS) \
+	    reloc_table.o $(LIBCMNDIR)/libc.a
+
+reloc_table.o: $(TOOLSDIR)/gen_reloc_table $(OBJS) $(LIBCMNDIR)/libc.a
+	$(TOOLSDIR)/create_reloc_table.sh --ld "$(ONLY_LD)" --ldflags "$(LDFLAGS)" \
+	  --lds "$(RTASCMNDIR)/rtas.lds" --objcopy "$(OBJCOPY)" $(OBJS)  $(LIBCMNDIR)/libc.a
+
+
+$(LIBCMNDIR)/libc.a:
+	$(MAKE) -C $(LIBCMNDIR) libc
+
+
+# Rules for cleaning up:
+clean_rtas:
+	rm -f $(OBJS) reloc_table.o rtas rtas.bin
+	rm -f $(RTASCMNDIR)/*~ $(RTASCMNDIR)/*.o
+
+distclean_rtas: clean_rtas
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	rm -f Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile $(RTASCMNDIR)/Makefile.inc
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(RTAS_SRCS:%=$(RTASCMNDIR)/%) > Makefile.dep
+	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(BOARD_SRCS) >> Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.c b/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.c
new file mode 100644
index 0000000..4c08e3f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.c
@@ -0,0 +1,274 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <product.h>
+#include <stdio.h>
+
+unsigned char sig_org[] = FLASHFS_PLATFORM_MAGIC;
+
+/* this function is part of the crc_lib assembler code */
+unsigned long check_flash_image(unsigned long, unsigned long, unsigned long);
+
+/* this functions needs to be implemented by the board specific flash code
+ * the functions always get 32 bytes and needs to deal with the data */
+void write_flash(unsigned long, unsigned short *);
+
+int progress = 0;
+
+int
+print_progress()
+{
+	static int i = 3;
+	switch (i--) {
+	case 3:
+		printf("\b|");
+		break;
+	case 2:
+		printf("\b/");
+		break;
+	case 1:
+		printf("\b-");
+		break;
+	case 0:
+		printf("\b\\");
+	default:
+		i = 3;
+	}
+	return 0;
+}
+
+void
+print_hash()
+{
+	printf("\b# ");
+}
+
+void
+print_writing()
+{
+	int counter = 42;
+	printf("\nWriting Flash: |");
+	while (counter--)
+		printf(" ");
+	printf("|");
+	counter = 41;
+	while (counter--)
+		printf("\b");
+
+}
+
+int
+get_block_list_version(unsigned char *data)
+{
+	if (data[0] == 0x01)
+		return 1;
+	return 0;
+}
+
+static long
+get_image_size(unsigned long *data, unsigned long length)
+{
+	long size = 0;
+	unsigned long i;
+	for (i = 0; i < length / 8; i += 2) {
+		size += data[1 + i];
+	}
+	return size;
+}
+
+static long
+get_image_size_v0(unsigned long *data)
+{
+	unsigned long bl_size = data[0];
+	return get_image_size(data + 1, bl_size - 8);
+}
+
+static long
+get_image_size_v1(unsigned long *data)
+{
+	unsigned long *bl_addr = data;
+	unsigned long bl_size;
+	unsigned long *next;
+	long size = 0;
+	while (bl_addr) {
+		bl_size = bl_addr[0];
+		next = (unsigned long *) bl_addr[1];
+		bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+		size += get_image_size(bl_addr + 2, bl_size - 0x10);
+		bl_addr = next;
+	}
+	return size;
+}
+
+long
+get_size(unsigned long *data, int version)
+{
+	if (version == 1)
+		return get_image_size_v1(data);
+	return get_image_size_v0(data);
+}
+
+static unsigned long
+write_one_block(unsigned long *block, unsigned long length,
+		unsigned long offset)
+{
+	unsigned long block_addr = (unsigned long) block;
+	unsigned long i = 0;
+	static unsigned int hash;
+	if (offset == 0)
+		hash = 0;
+
+	for (i = 0; i < length; i += 32, offset += 32, block_addr += 32) {
+		write_flash(offset, (unsigned short *) block_addr);
+		if (offset % 10 == 0) {
+			print_progress();
+		}
+		if (offset > hash * progress) {
+			print_hash();
+			hash++;
+		}
+	}
+
+	return offset;
+}
+
+static unsigned long
+write_one_list(unsigned long *bl, unsigned long length, unsigned long offset)
+{
+	unsigned long i;
+	// 0x10: /8 for pointer /2 it has to be done in steps of 2
+	for (i = 0; i < length / 0x10; i++) {
+		offset =
+		    write_one_block((unsigned long *) *bl, *(bl + 1), offset);
+		bl += 2;
+	}
+	return offset;
+}
+
+void
+write_block_list(unsigned long *bl, int version)
+{
+	unsigned long offset = 0;
+	unsigned long *bl_addr = bl;
+	unsigned long bl_size;
+	unsigned long *next;
+
+	if (version == 0) {
+		// -8 = removed header length
+		write_one_list(bl + 1, *(bl) - 8, offset);
+		return;
+	}
+
+	while (bl_addr) {
+		bl_size = bl_addr[0];
+		next = (unsigned long *) bl_addr[1];
+		bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+		// -0x10 = removed header length
+		offset = write_one_list(bl_addr + 2, bl_size - 0x10, offset);
+		bl_addr = next;
+	}
+
+}
+
+static int
+check_one_list(unsigned long *bl, unsigned long length, unsigned long crc)
+{
+	unsigned long i;
+	// 0x10: /8 for pointer /2 it has to be done in steps of 2
+	for (i = 0; i < length / 0x10; i++) {
+		crc = check_flash_image((unsigned long) *bl, *(bl + 1), crc);
+		bl += 2;
+	}
+	return crc;
+}
+
+int
+image_check_crc(unsigned long *bl, int version)
+{
+	unsigned long *bl_addr = bl;
+	unsigned long bl_size;
+	unsigned long *next;
+	unsigned long crc = 0;
+
+	if (version == 0) {
+		// -8 = removed header length
+		return check_one_list(bl + 1, *(bl) - 8, crc);
+	}
+
+	while (bl_addr) {
+		bl_size = bl_addr[0];
+		next = (unsigned long *) bl_addr[1];
+		bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+		// -0x10 = removed header length
+		crc = check_one_list(bl_addr + 2, bl_size - 0x10, crc);
+		bl_addr = next;
+	}
+	return crc;
+}
+
+static int
+check_platform_one_list(unsigned long *bl, unsigned long bytesec)
+{
+	unsigned long pos = bytesec;
+	unsigned char *sig_tmp, *sig;
+	unsigned long size = 0;
+	sig = sig_org;
+
+	while (size < bytesec) {
+		size += bl[1];
+
+		while (size > pos) {	// 32 == FLASHFS_PLATFORM_MAGIC length
+			sig_tmp = (unsigned char *) (bl[0] + pos);
+			if (*sig++ != *sig_tmp)
+				return -1;
+			if (*sig_tmp == '\0' || (pos == bytesec + 32)) {
+				pos = bytesec + 32;
+				break;
+			}
+			pos++;
+		}
+		if (pos == (bytesec + 32))
+			return 0;
+		bl += 2;
+	}
+	return 0;
+}
+
+int
+check_platform(unsigned long *bl, unsigned int bytesec, int version)
+{
+	unsigned long *bl_addr = bl;
+	unsigned long bl_size;
+	unsigned long *next;
+	unsigned long *ptr;
+	ptr = bl;
+
+	if (version == 0) {
+		ptr += 1;	// -8 = removed header length
+		return check_platform_one_list(ptr, bytesec);
+	}
+	while (bl_addr) {
+		ptr = bl_addr + 2;	// -0x10 = removed header length
+		bl_size = bl_addr[0];
+		next = (unsigned long *) bl_addr[1];
+		bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+		if ((bl_size - 0x10) == 0) {
+			bl_addr = next;
+			continue;
+		}
+		if (check_platform_one_list(ptr, bytesec) == 0)
+			return 0;
+
+		bl_addr = next;
+	}
+	return -1;
+}
diff --git a/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.h b/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.h
new file mode 100644
index 0000000..80044c3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/flash/block_lists.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+extern int progress;
+extern unsigned char sig_org[];
+
+void print_progress(void);
+void print_hash(void);
+int get_block_list_version(unsigned char *);
+int image_check_crc(unsigned long *, int);
+long get_size(unsigned long *, int);
+void print_writing(void);
+void write_block_list(unsigned long *, int);
+int check_platform(unsigned long *, unsigned int, int);
diff --git a/qemu-0.15.x/roms/SLOF/rtas/flash/tmpXXX.update-comments b/qemu-0.15.x/roms/SLOF/rtas/flash/tmpXXX.update-comments
new file mode 100644
index 0000000..cd3d137
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/flash/tmpXXX.update-comments
@@ -0,0 +1,11 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
diff --git a/qemu-0.15.x/roms/SLOF/rtas/reloc.S b/qemu-0.15.x/roms/SLOF/rtas/reloc.S
new file mode 100644
index 0000000..e24d293
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/reloc.S
@@ -0,0 +1,183 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <rtas.h>		
+			
+/*
+Function:	
+	Input:
+		r3:   Destination to copy rtas code to
+		r4:   Configuration	
+	Output:		
+		r3:   Entry point for rtas calls	
+Decription: Called by OpenFirmware to instantiate rtas, needs to copy
+	itself to destination, also do a relocations.
+	
+*/
+
+.extern	rtas_entry
+.extern .stack
+.extern _got
+.extern _got_end
+.extern __bss_start
+.extern __bss_end
+.extern rtas_config
+
+
+	.section        ".rtasstart","ax";
+	.align	3
+	.globl _rtas_start
+_rtas_start:
+	mflr	r10		# save link register
+	bcl	20,31,.over	# branch (always) to .over 
+
+.base:
+	.align  3
+
+/* Our Open Firmware needs to know the size of the RTAS binary and the
+ * size & address of the RTAS function jump table. SLOF always looks for this
+ * information in the following three quads here at the very beginning of the
+ * RTAS binary at offset 8. So DO NOT DELETE/MOVE them! */
+
+._rtas_size:		.quad	_rtas_end-_rtas_start
+._ptr_to_func_tab:	.quad	rtas_func_tab-_rtas_start
+._ptr_to_func_tab_size:	.quad	rtas_func_tab_size-_rtas_start
+
+/* The other variables are not accessed by SLOF anymore: */
+
+._rel_offset:		.quad   _reloc_table_start-_rtas_start
+._rel_end_offset:	.quad   _reloc_table_end-_rtas_start
+._bss_offset:		.quad   __bss_start-_rtas_start
+._bss_end_offset:	.quad   __bss_end-_rtas_start
+._rtas_entry_offset:	.quad   rtas_entry-_rtas_start
+._rtas_config_offset:	.quad   rtas_config-_rtas_start
+._rtas_stack:	        .quad   .stack-_rtas_start+RTAS_STACKSIZE-0x60
+._rtas_toc:	        .quad   _got-_rtas_start+0x8000
+
+.over:	
+	mflr r8			# gpr 8 is the base
+	addi r8,r8,_rtas_start-.base # points to _rtas_start
+	mr r11,r4		# Save config value	
+	
+# Copy rtas code
+	
+	ld r5,._rtas_size-_rtas_start(r8) 
+	mr r4,r8		# Start of rtas
+	addi r6,r3,-8		# Destination
+	addi r4,r4,-8		# Source
+	srdi r5,r5,3		# Count in quads
+	mtctr r5
+0:				
+	ldu r0,8(r4)		
+	stdu r0,8(r6)
+	bdnz 0b		
+
+# Clear bss
+
+	ld r4,._bss_offset-_rtas_start(r8)
+	ld r5,._bss_end_offset-_rtas_start(r8)
+	li r0,0
+	add r6,r3,r4		# Address bss in copied code
+	addi r6,r6,-8
+	sub r5,r5,r4		# Calculate bss size
+	srdi r5,r5,3		# Count in quads
+	mtctr r5	
+0:	
+	stdu r0,8(r6)
+	bdnz 0b
+
+# Relocate got
+
+	ld	r4, ._rel_offset-_rtas_start(r8)
+	ld	r5, ._rel_end_offset-_rtas_start(r8)
+	sub	r5, r5,r4	# Calculate reloc table size
+	cmpdi	r5, 0		# No reloc table ?
+	beq	1f
+
+	add	r4, r4, r3	# Calculate reloc table address
+	addi	r4, r4, -4
+	srdi	r5, r5, 2	# Count in words	
+	mtctr	r5
+0:	
+	lwzu	r6, 4(r4)	# Load offset out of reloc table
+	ldx	r0, r6, r3	# Load value 	
+	add	r0, r0, r3	# Add relocation offset = load address
+	stdx	r0, r6, r3
+	bdnz	0b		
+1:			
+
+# Save config data
+
+	ld r5,._rtas_config_offset-_rtas_start(r8)
+	add r5,r5,r3
+	std r11,0(r5)
+	
+# Flush to memory
+	
+	mr r4,r3		# Destination address
+	ld r5,._rtas_size-_rtas_start(r8) 
+		
+	add r5,r5,r4
+	addi r5,r5,127
+	rlwinm r4,r4,0,0,24
+	rlwinm r5,r5,0,0,24
+	sub r5,r5,r4
+	srwi r5,r5,7
+	mtctr r5
+0:
+	dcbst 0,r4
+	sync
+	icbi 0,r4
+	sync
+	isync
+	addi r4,r4,128
+	bdnz 0b
+
+# Call init function
+	mfmsr	r11			# Switch to 64 bit mode
+	mr	r7,r11
+	rotldi	r11,r11,1
+	ori	r11,r11,1
+	rotldi	r11,r11,63
+	mtmsrd	r11
+	isync
+	mr	r9,r1			# save old stack pointer
+	ld	r1,._rtas_stack-_rtas_start(r8)	# load new stack pointer
+	add	r1,r1,r3
+	std	r9,0(r1)		# save stack pointer
+	std	r2,64(r1)		# save toc
+	std	r7,72(r1)		# save old msr value
+
+	ld	r2,._rtas_toc-_rtas_start(r8)	# load got pointer
+	add	r2,r2,r3
+
+	bl	save_regs_r3_r12
+	bl	.rtas_init
+	bl	restore_regs_r3_r12
+
+	ld	r11,72(r1)		# restore msr value	
+	ld	r2,64(r1)		# restore toc
+	ld	r1,0(r1)		# get old stack
+
+	mtmsrd	r11			# restore msr
+	isync
+
+
+# Return rtas entry
+
+	ld r4,._rtas_entry_offset-_rtas_start(r8)
+	add r3,r3,r4
+	mtlr	r10
+	blr	
+
+
+
diff --git a/qemu-0.15.x/roms/SLOF/rtas/rtas.lds b/qemu-0.15.x/roms/SLOF/rtas/rtas.lds
new file mode 100644
index 0000000..a5ba1da
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/rtas.lds
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+
+SECTIONS {
+	.text 0:
+	{
+	  *(.rtasstart)
+	  *(.text .stub .text.* .gnu.linkonce.t.*)
+	  *(.sfpr .glink)
+	  *(.rodata .rodata.* .gnu.linkonce.r.*)
+	  *(.opd)
+	} =0x60000000
+	.data :
+	{
+	  *(.data .data.* .gnu.linkonce.d.*)
+	}
+	.got :
+	{
+	  _got = .;
+	  *(.got .toc)
+	}  	
+	.reloc :
+	{
+	  . = ALIGN(4);
+	  _reloc_table_start = .;
+	  *(.reloc)
+	  _reloc_table_end = .;
+	}
+	.bss :
+	{
+	  __bss_start = .;
+	  *(*COM* .bss .sbss .gnu.linkonce.b.*)
+	  __bss_end = .;
+	}
+	__bss_size = (__bss_end - __bss_start);
+	_rtas_end = .;
+}
diff --git a/qemu-0.15.x/roms/SLOF/rtas/rtas_call.c b/qemu-0.15.x/roms/SLOF/rtas/rtas_call.c
new file mode 100644
index 0000000..bf1cf89
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/rtas_call.c
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <rtas.h>
+#include "rtas_table.h"
+
+
+//#define _RTAS_TRACE
+//#define _RTAS_COUNT_CALLS
+
+
+#ifdef _RTAS_COUNT_CALLS
+int rtas_callcount[0x40] __attribute__((aligned (16)));
+#endif
+
+/* rtas_config is used to store the run-time configuration flags (which are
+ * provided by SLOF during instantiate-rtas) */
+long rtas_config;
+
+
+/* 
+Function: rtas_call
+	Input:
+		rtas_args: pointer to RTAS arguments structure
+	Output:
+		
+Decription: Handle RTAS call. This C function is called
+		from the asm function rtas_entry.
+*/
+
+void
+rtas_call (rtas_args_t *rtas_args)
+{
+	int idx;
+
+#ifdef _RTAS_COUNT_CALLS
+	/* Count how often every RTAS function is called. */
+	if (rtas_args->token < (int)(sizeof(rtas_callcount)/sizeof(rtas_callcount[0]))) {
+		static int callcount_initialized = 0;
+		/* If the array is used the first time, we have to set all entries to 0 */
+		if (!callcount_initialized) {
+			unsigned int i;
+			callcount_initialized = 1;
+			for (i = 0; i < sizeof(rtas_callcount)/sizeof(rtas_callcount[0]); i++)
+				rtas_callcount[i] = 0;
+		}
+		/* Increment the counter of the RTAS call */
+		rtas_callcount[rtas_args->token] += 1;
+	}
+#endif
+
+#ifdef _RTAS_TRACE
+	unsigned int parCnt = rtas_args->nargs;
+	unsigned int *pInt = rtas_args->args;
+	printf("\n\r*** rtas_call=0x%x", rtas_args->token);
+#ifdef _RTAS_COUNT_CALLS
+	printf(" count=0x%x", rtas_callcount[rtas_args->token]);
+#endif
+	printf(" len=0x%x", parCnt);
+	printf("\n\r ");
+	while(parCnt--) {
+		printf("0x%x ", *pInt++);
+	}
+#endif
+
+	idx = rtas_args->token - 1;
+
+	/* Check if there's a function for the token: */
+	if (idx >= 0 && idx < rtas_func_tab_size
+	    && rtas_func_tab[idx].func != NULL) {
+		/* Now jump to the RTAS function: */
+		rtas_func_tab[idx].func(rtas_args);
+	}
+	else {
+		/* We didn't find a function - return error code: */
+		rtas_args->args[rtas_args->nargs] = -1;
+	}
+
+}
diff --git a/qemu-0.15.x/roms/SLOF/rtas/rtas_common.S b/qemu-0.15.x/roms/SLOF/rtas/rtas_common.S
new file mode 100644
index 0000000..35cd9a9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/rtas_common.S
@@ -0,0 +1,87 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+.globl save_regs_r3_r12
+.globl restore_regs_r3_r12
+.globl save_regs_r13_r25
+.globl restore_regs_r13_r25
+
+
+save_regs_r3_r12:
+	stdu    r1,-0x80(r1)            # allocate space on stack
+
+	std     r3,0x30(r1)
+	std     r4,0x38(r1)
+	std     r5,0x40(r1)
+	std     r6,0x48(r1)
+	std     r7,0x50(r1)
+	std     r8,0x58(r1)
+	std     r9,0x60(r1)
+	std     r10,0x68(r1)
+	std     r11,0x70(r1)
+	std     r12,0x78(r1)
+
+	blr
+	
+restore_regs_r3_r12:
+	ld      r3,0x30(r1)
+	ld      r4,0x38(r1)
+	ld      r5,0x40(r1)
+	ld      r6,0x48(r1)
+	ld      r7,0x50(r1)
+	ld      r8,0x58(r1)
+	ld      r9,0x60(r1)
+	ld      r10,0x68(r1)
+	ld      r11,0x70(r1)
+	ld      r12,0x78(r1)
+
+	addi    r1,r1,0x80		# cleanup stack
+
+	blr
+
+save_regs_r13_r25:
+	stdu    r1,-0x98(r1)            # allocate space on stack
+
+	std     r13,0x30(r1)
+	std     r14,0x38(r1)
+	std     r15,0x40(r1)
+	std     r16,0x48(r1)
+	std     r17,0x50(r1)
+	std     r18,0x58(r1)
+	std     r19,0x60(r1)
+	std     r20,0x68(r1)
+	std     r21,0x70(r1)
+	std     r22,0x78(r1)
+	std     r23,0x80(r1)
+	std     r24,0x88(r1)
+	std     r25,0x90(r1)
+
+	blr
+
+restore_regs_r13_r25:
+	ld      r13,0x30(r1)            # restore registers from stack
+	ld      r14,0x38(r1)
+	ld      r15,0x40(r1)
+	ld      r16,0x48(r1)
+	ld      r17,0x50(r1)
+	ld      r18,0x58(r1)
+	ld      r19,0x60(r1)
+	ld      r20,0x68(r1)
+	ld      r21,0x70(r1)
+	ld      r22,0x78(r1)
+	ld      r23,0x80(r1)
+	ld      r24,0x88(r1)
+	ld      r25,0x90(r1)
+
+	addi    r1,r1,0x98		# cleanup stack
+
+	blr
diff --git a/qemu-0.15.x/roms/SLOF/rtas/rtas_entry.S b/qemu-0.15.x/roms/SLOF/rtas/rtas_entry.S
new file mode 100644
index 0000000..74693aa
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/rtas/rtas_entry.S
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <rtas.h>		
+
+
+/*
+Function:	
+	Input:
+		r3:   rtas parm structure	
+		r4:   base address
+	Output:		
+
+Decription: Main entry point, called from OS. Second parameter is not
+	used.	
+	
+*/
+	.globl rtas_entry
+rtas_entry:	
+	mfmsr	r11		# Get MSR to enable 64-bit mode
+	mr	r7,r11
+	rotldi	r11,r11,1
+	ori	r11,r11,1	# Always enable 64-bit mode flag
+	rotldi	r11,r11,63
+	mtmsrd	r11		# Switch to 64-bit mode
+	isync
+
+	mr r9,r1		# save old stack pointer
+	mflr r10		# save link register
+	bcl 20,31,.over		# branch to over 
+.base:	
+	.align  3
+..got:			.quad   _got-.base+0x8000
+..stack:		.quad   .stack+RTAS_STACKSIZE-0x60-.base
+.over:	
+	mflr r8			# gpr 8 is the base
+	ld r1,..stack-.base(r8)	# load new stack pointer
+	add r1,r1,r8		# add base
+	std r2,64(r1)		# save toc
+	ld r2,..got-.base(r8)	# load got pointer
+	std r7,72(r1)		# save original msr
+	std r10,80(r1)		# save link register
+	std r9,0(r1)		# save stack pointer
+	add r2,r2,r8		# add base
+
+	bl save_regs_r3_r12
+	bl .rtas_call
+	bl restore_regs_r3_r12
+
+rtas_return:
+	ld r11,72(r1)		# restore msr value	
+	ld r0,80(r1)		# restore link register value
+	ld r2,64(r1)		# restore toc
+	ld r1,0(r1)		# get old stack
+	mtmsrd r11		# restore msr (32 bit ?)
+	isync
+	mtlr r0
+	blr
+
+
+
+	.globl 	.stack
+	.lcomm	.stack,RTAS_STACKSIZE
diff --git a/qemu-0.15.x/roms/SLOF/slof/Makefile.inc b/qemu-0.15.x/roms/SLOF/slof/Makefile.inc
new file mode 100644
index 0000000..8c77727
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/Makefile.inc
@@ -0,0 +1,165 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+# Before including this Makefile, you should specify the following variables
+# in your Makefile:
+# - INCLCMNDIR : Points to the common include directory
+# - INCLCMNDIR : Points to the board specific include directory
+# - SLOFCMNDIR : Points to the common SLOF directory
+# - SLOFBRDDIR : Points to the board specific SLOF directory
+# - LLFWCMNDIR : Points to the common LLFW directory
+# - LLFWBRDDIR : Points to the board specific LLFW directory
+
+# Set LLFW directories (should normally be set from parent Makefile):
+TOPBRDDIR ?= $(shell cd .. && pwd)
+LLFWBRDDIR ?= $(TOPBRDDIR)/llfw
+LLFWCMNDIR ?= $(SLOFCMNDIR:%/slof=%/llfw)
+INCLBRDDIR ?= $(TOPBRDDIR)/include
+
+
+CPPFLAGS += -I. -I$(INCLCMNDIR) -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+CFLAGS  = -DTARG=$(TARG) -static -Wall -W -std=gnu99 \
+	  -O2 -fomit-frame-pointer -msoft-float $(FLAG) $(CPUARCHDEF) \
+	  -fno-stack-protector
+ASFLAGS = -Wa,-mpower4 -Wa,-mregnames $(FLAG) $(CPUARCHDEF)
+
+LDFLAGS += -static -nostdlib 
+
+ifneq ($(TARG),unix)
+CFLAGS	+= -nostdinc -fno-builtin
+CPPFLAGS += -I$(LIBCMNDIR)/libc/include
+SLOF_LIBS += $(LIBCMNDIR)/libc.a
+endif
+
+DICT = $(SLOFCMNDIR)/prim.in $(SLOFCMNDIR)/engine.in \
+	$(BOARD_SLOF_IN) $(SLOFCMNDIR)/$(TARG).in
+
+# Source code files with automatic dependencies:
+SLOF_BUILD_SRCS = paflof.c
+
+# Flags for pre-processing Forth code with CPP:
+FPPFLAGS = -nostdinc -traditional-cpp -undef -P -C $(FLAG)
+FPPINCLUDES ?= -I$(SLOFBRDDIR) -I$(SLOFCMNDIR)/fs
+
+# Rules for pre-processing Forth code:
+# - Use CPP for pre-processing #include directives
+# - Use sed to strip all white spaces at the beginning of a line
+# - Use sed to remove all lines that only contain a comment
+# - Use sed to remove all empty lines from the file
+%.fsi: %.fs
+ifeq ($(V),1)
+	printf "\t[FPP]\t%s\n" `basename "$@"`
+endif
+	rm -f $@
+	cpp $(FPPFLAGS) $(FPPINCLUDES) $< > $@.tmp
+	sed -e 's/^[	 ]*//' < $@.tmp \
+	  | sed -e '/^\\[	 ]/d' \
+	  | sed -e '/^([	 ][^)]*[	 ])[	 ]*$$/d' \
+	  | sed -e '/^$$/d' > $@
+	rm -f $@.tmp
+
+
+OF.o:	OF.fsi
+	$(LD) -o $@ -r -bbinary $<
+
+
+dict.xt: $(DICT) $(SLOFCMNDIR)/ref.pl 
+	cat $(DICT) | perl $(SLOFCMNDIR)/ref.pl -s $(CELLSIZE) > dict.xt
+
+ifdef BOARD_SLOF_CODE
+board.code: $(BOARD_SLOF_CODE)
+	cat $(BOARD_SLOF_CODE) > $@
+else
+board.code:
+	echo > $@
+endif
+
+paflof: $(SLOFCMNDIR)/OF.lds $(SLOFCMNDIR)/ofw.o paflof.o $(SLOFCMNDIR)/entry.o \
+	    romfs.o OF.o nvramlog.o $(LLFWBRDDIR)/board_io.o \
+	    $(LLFWBRDDIR)/io_generic_lib.o $(SLOF_LIBS)
+	$(CC) -T$(SLOFCMNDIR)/OF.lds $(SLOFCMNDIR)/ofw.o paflof.o \
+	    $(SLOFCMNDIR)/entry.o romfs.o OF.o nvramlog.o $(LLFWBRDDIR)/board_io.o \
+	    $(LLFWBRDDIR)/io_generic_lib.o $(LDFLAGS) $(SLOF_LIBS) -o $@
+	#save a copy of paflof before stripping
+	@cp $@ $@.unstripped
+	$(STRIP) -s $@
+
+paflof.o: board.code dict.xt
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/paflof.c
+
+$(SLOFCMNDIR)/xvect.bin: $(SLOFCMNDIR)/lowmem.o
+	$(CC) $(LDFLAGS) -Wl,--oformat,binary -Ttext=0x100 -o xvect.bin.tmp $<
+	dd if=xvect.bin.tmp of=$(SLOFCMNDIR)/xvect.bin bs=256 skip=1 2>/dev/null
+	rm -f xvect.bin.tmp
+
+romfs.o:
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/romfs.S
+
+nvramlog.o:
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/nvramlog.S
+
+checkpoint.o:
+	$(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/checkpoint.S
+
+$(LLFWBRDDIR)/board_io.o:
+	make -C $(LLFWBRDDIR) board_io.o
+
+$(LLFWBRDDIR)/io_generic_lib.o:
+	make -C $(LLFWBRDDIR) io_generic_lib.o
+
+default-font.o: $(SLOFCMNDIR)/default-font.c
+	$(CC) $(CPPFLAGS) $< -c -o default-font.o
+
+$(SLOFBRDDIR)/default-font.bin: default-font.o
+	$(OBJCOPY) -Obinary default-font.o $@ 
+
+.PHONY : create_OF.ffs clean_slof distclean_slof depend
+
+
+# Create OF.ffs automatically from file list in OF_FFS_FILES variable.
+# We have to use absolute path names there, so we have to use `pwd` to
+# find them out:
+create_OF_ffs:
+	rm -f OF.ffs
+	@for i in $(OF_FFS_FILES) ; do \
+		CURRENTDIR=`pwd` ; cd `dirname $$i` ; \
+		DIRNAME=`pwd` ; cd $$CURRENTDIR ; \
+		echo `basename $$i | sed  -e s/\.fsi/\.fs/` \
+		     $$DIRNAME/`basename $$i` 0 0 >> OF.ffs ; \
+	 done
+
+
+# Targets for cleaning up:
+clean_slof:
+	rm -f $(SLOFCMNDIR)/*.o $(SLOFCMNDIR)/*.bin $(SLOFCMNDIR)/*.elf
+	rm -f dict.xt board.code paflof paflof.unstripped default-font.bin
+	rm -f $(filter %.fsi,$(OF_FFS_FILES))
+
+distclean_slof:	clean_slof
+	rm -f Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+	rm -f Makefile.dep
+	$(MAKE) Makefile.dep
+
+Makefile.dep: Makefile $(SLOFCMNDIR)/Makefile.inc OF.fs
+	$(CC) -M -MG $(CPPFLAGS) $(CFLAGS) $(SLOF_BUILD_SRCS:%=$(SLOFCMNDIR)/%) > Makefile.dep
+	cpp -M -MG $(FPPFLAGS) $(FPPINCLUDES) -MT OF.fsi OF.fs >> Makefile.dep
+	for i in $(filter %.fsi,$(OF_FFS_FILES)) ; do \
+		cpp -M -MG $(FPPFLAGS) $(FPPINCLUDES) -MT $$i \
+			`echo $$i | sed  -e 's/\.fsi/\.fs/'` >> Makefile.dep ; \
+	done
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu-0.15.x/roms/SLOF/slof/OF.lds b/qemu-0.15.x/roms/SLOF/slof/OF.lds
new file mode 100644
index 0000000..5f8b2b1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/OF.lds
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_start_OF)
+
+
+SECTIONS
+{
+	. = 0x0E100100;
+	_start_OF = .;
+	.slof.loader : { *(.slof.loader) }
+	. = ALIGN(0x100);
+	_slof_text = .;
+	.text : { *(.entry_text) *(.text) } = 0x60000000
+	_slof_text_end = .;
+	. = ALIGN(8);
+	_slof_text_size = (_slof_text_end - _slof_text);
+
+	. = ALIGN(0x100);
+	.opd : 
+	{ 
+		_slof_data = .;
+		*(.opd)
+	}
+	. = ALIGN(8);
+	.got :
+	{
+		*(.got .toc)
+	}
+
+	.data : { 
+		*(.rodata .rodata.*)
+		*(.data .data.*)
+		*(.note.gnu.build-id)
+	}
+
+	.comment : { *(.comment) }
+	.branch_lt : { *(.branch_lt) }
+
+	. = ALIGN(8);
+	_slof_data_end = .;
+	_slof_data_size = (_slof_data_end - _slof_data);
+
+	.bss :
+	{
+	  _slof_bss = .;
+	  *(*COM* .bss .sbss .gnu.linkonce.b.*)
+	  _slof_bss_end = .;
+	}
+	_slof_bss_size = (_slof_bss_end - _slof_bss);
+	
+	. = ALIGN(0x1000);
+	the_mem = .;
+}
diff --git a/qemu-0.15.x/roms/SLOF/slof/default-font.c b/qemu-0.15.x/roms/SLOF/slof/default-font.c
new file mode 100644
index 0000000..328f1b4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/default-font.c
@@ -0,0 +1,1653 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* Bitmap font 8x16.
+   FIXME: Only characters from 0x20 - 0x7f
+
+
+*/
+
+const char bmfont_8x16[] =
+{
+    /* 0x20 " " */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x21 "!" */
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x00,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x22 """ */
+    0x00,
+    0x00,
+    0x28,
+    0x28,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x23 "#" */
+    0x00,
+    0x00,
+    0x24,
+    0x24,
+    0x7e,
+    0x24,
+    0x24,
+    0x7e,
+    0x24,
+    0x24,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x24 "$" */
+    0x00,
+    0x08,
+    0x1c,
+    0x2a,
+    0x28,
+    0x28,
+    0x1c,
+    0x0a,
+    0x0a,
+    0x2a,
+    0x1c,
+    0x08,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x25 "%" */
+    0x00,
+    0x00,
+    0x30,
+    0x48,
+    0x30,
+    0x02,
+    0x0c,
+    0x30,
+    0x40,
+    0x0c,
+    0x12,
+    0x0c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x26 "&" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x44,
+    0x40,
+    0x22,
+    0x54,
+    0x48,
+    0x54,
+    0x22,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x27 "'" */
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x28 "(" */
+    0x00,
+    0x00,
+    0x08,
+    0x10,
+    0x10,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x10,
+    0x10,
+    0x08,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x29 ")" */
+    0x00,
+    0x00,
+    0x10,
+    0x08,
+    0x08,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x08,
+    0x08,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2a "*" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x7c,
+    0x10,
+    0x28,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2b "+" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x7c,
+    0x10,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2c "," */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x08,
+    0x08,
+    0x18,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2d "-" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x7c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2e "." */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x30,
+    0x30,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x2f "/" */
+    0x00,
+    0x00,
+    0x02,
+    0x04,
+    0x04,
+    0x08,
+    0x08,
+    0x10,
+    0x10,
+    0x20,
+    0x20,
+    0x40,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x30 "0" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x31 "1" */
+    0x00,
+    0x00,
+    0x08,
+    0x18,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x1c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x32 "2" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x44,
+    0x04,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x40,
+    0x78,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x33 "3" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x04,
+    0x04,
+    0x04,
+    0x18,
+    0x04,
+    0x04,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x34 "4" */
+    0x00,
+    0x00,
+    0x40,
+    0x40,
+    0x40,
+    0x48,
+    0x48,
+    0x7e,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x35 "5" */
+    0x00,
+    0x00,
+    0x7e,
+    0x40,
+    0x40,
+    0x40,
+    0x78,
+    0x04,
+    0x02,
+    0x02,
+    0x04,
+    0x78,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x36 "6" */
+    0x00,
+    0x00,
+    0x1c,
+    0x20,
+    0x40,
+    0x40,
+    0x40,
+    0x78,
+    0x44,
+    0x44,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x37 "7" */
+    0x00,
+    0x00,
+    0x7e,
+    0x42,
+    0x04,
+    0x08,
+    0x08,
+    0x10,
+    0x10,
+    0x20,
+    0x20,
+    0x20,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x38 "8" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x44,
+    0x44,
+    0x38,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x39 "9" */
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x44,
+    0x44,
+    0x3c,
+    0x04,
+    0x04,
+    0x04,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x3a ":" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x30,
+    0x30,
+    0x00,
+    0x00,
+    0x30,
+    0x30,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x3b ";" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x30,
+    0x30,
+    0x00,
+    0x00,
+    0x30,
+    0x30,
+    0x20,
+    0x40,
+    0x00,
+    0x00,
+    /* 0x3c "<" */
+    0x00,
+    0x00,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x40,
+    0x40,
+    0x20,
+    0x10,
+    0x08,
+    0x04,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x3d "=" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x7e,
+    0x00,
+    0x7e,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x3e ">" */
+    0x00,
+    0x00,
+    0x20,
+    0x10,
+    0x08,
+    0x04,
+    0x02,
+    0x02,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x3f "?" */
+    0x00,
+    0x00,
+    0x1c,
+    0x22,
+    0x02,
+    0x02,
+    0x04,
+    0x18,
+    0x10,
+    0x10,
+    0x00,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x40 "@" */
+    0x00,
+    0x00,
+    0x18,
+    0x24,
+    0x42,
+    0x4e,
+    0x52,
+    0x4e,
+    0x40,
+    0x40,
+    0x24,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x41 "A" */
+    0x00,
+    0x00,
+    0x18,
+    0x18,
+    0x24,
+    0x24,
+    0x24,
+    0x7e,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x42 "B" */
+    0x00,
+    0x00,
+    0x7c,
+    0x42,
+    0x42,
+    0x42,
+    0x7c,
+    0x7c,
+    0x42,
+    0x42,
+    0x42,
+    0x7c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x44 "C" */
+    0x00,
+    0x00,
+    0x3c,
+    0x22,
+    0x60,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x60,
+    0x22,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x45 "D" */
+    0x00,
+    0x00,
+    0x78,
+    0x44,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x44,
+    0x78,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x46 "E" */
+    0x00,
+    0x00,
+    0x7e,
+    0x40,
+    0x40,
+    0x40,
+    0x7e,
+    0x7e,
+    0x40,
+    0x40,
+    0x40,
+    0x7e,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x47 "F" */
+    0x00,
+    0x00,
+    0x7e,
+    0x40,
+    0x40,
+    0x40,
+    0x7e,
+    0x7e,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x48 "G" */
+    0x00,
+    0x00,
+    0x3c,
+    0x42,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x4e,
+    0x42,
+    0x42,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x49 "H" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x7e,
+    0x7e,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x49 "I" */
+    0x00,
+    0x00,
+    0x3c,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4a "J" */
+    0x00,
+    0x00,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x24,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4b "K" */
+    0x00,
+    0x00,
+    0x42,
+    0x44,
+    0x48,
+    0x50,
+    0x60,
+    0x60,
+    0x50,
+    0x48,
+    0x44,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4c "L" */
+    0x00,
+    0x00,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x7e,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4d "M" */
+    0x00,
+    0x00,
+    0x42,
+    0x66,
+    0x7e,
+    0x5a,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4e "N" */
+    0x00,
+    0x00,
+    0x42,
+    0x62,
+    0x62,
+    0x52,
+    0x52,
+    0x4a,
+    0x4a,
+    0x46,
+    0x46,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x4f "O" */
+    0x00,
+    0x00,
+    0x18,
+    0x24,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x24,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x50 "P" */
+    0x00,
+    0x00,
+    0x70,
+    0x48,
+    0x44,
+    0x44,
+    0x48,
+    0x70,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x51 "Q" */
+    0x00,
+    0x00,
+    0x18,
+    0x24,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x4a,
+    0x24,
+    0x1a,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x52 "R" */
+    0x00,
+    0x00,
+    0x70,
+    0x48,
+    0x44,
+    0x44,
+    0x48,
+    0x70,
+    0x50,
+    0x48,
+    0x44,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x53 "S" */
+    0x00,
+    0x00,
+    0x1e,
+    0x20,
+    0x40,
+    0x40,
+    0x20,
+    0x18,
+    0x04,
+    0x02,
+    0x02,
+    0x7e,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x54 "T" */
+    0x00,
+    0x00,
+    0x7e,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x55 "U" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x56 "V" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x24,
+    0x24,
+    0x24,
+    0x24,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x57 "W" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x42,
+    0x5a,
+    0x66,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x58 "X" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x24,
+    0x24,
+    0x18,
+    0x18,
+    0x24,
+    0x24,
+    0x42,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x59 "Y" */
+    0x00,
+    0x00,
+    0x42,
+    0x42,
+    0x24,
+    0x24,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x5a "Z" */
+    0x00,
+    0x00,
+    0x7e,
+    0x42,
+    0x04,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x20,
+    0x42,
+    0x7e,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+      /* 0x5b "[" */
+    0x00,
+    0x00,
+    0x30,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x20,
+    0x30,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+       /* 0x5c "\" */
+    0x00,
+    0x00,
+    0x40,
+    0x20,
+    0x20,
+    0x10,
+    0x10,
+    0x08,
+    0x08,
+    0x04,
+    0x04,
+    0x02,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+       /* 0x5d "]" */
+    0x00,
+    0x00,
+    0x18,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+       /* 0x5e "^" */
+    0x00,
+    0x00,
+    0x18,
+    0x3c,
+    0x66,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+       /* 0x5f "_" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x7e,
+    0x00,
+     /*  0x60 "`" */
+    0x00,
+    0x00,
+    0x00,
+    0x20,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x61 "a" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x04,
+    0x3c,
+    0x44,
+    0x3a,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x62 "b" */
+    0x00,
+    0x00,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x58,
+    0x64,
+    0x44,
+    0x44,
+    0x64,
+    0x58,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x63 "c" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x40,
+    0x40,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x64 "d" */
+    0x00,
+    0x00,
+    0x04,
+    0x04,
+    0x04,
+    0x04,
+    0x3c,
+    0x4c,
+    0x44,
+    0x44,
+    0x4c,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x65 "e" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x38,
+    0x44,
+    0x78,
+    0x40,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x66 "f" */
+    0x00,
+    0x00,
+    0x0c,
+    0x12,
+    0x10,
+    0x10,
+    0x38,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x67 "g" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x34,
+    0x4c,
+    0x44,
+    0x4c,
+    0x34,
+    0x04,
+    0x44,
+    0x38,
+    0x00,
+    0x00,
+     /* 0x68 "h" */
+    0x00,
+    0x00,
+    0x40,
+    0x40,
+    0x40,
+    0x58,
+    0x64,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x44,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x69 "i" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x08,
+    0x00,
+    0x18,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x1c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x6a "j" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x08,
+    0x00,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x48,
+    0x30,
+    0x00,
+     /* 0x6b "k" */
+    0x00,
+    0x00,
+    0x40,
+    0x40,
+    0x40,
+    0x44,
+    0x48,
+    0x50,
+    0x70,
+    0x48,
+    0x44,
+    0x42,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x6c "l" */
+    0x00,
+    0x00,
+    0x30,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x38,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x6d "m" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x54,
+    0x2a,
+    0x2a,
+    0x2a,
+    0x2a,
+    0x6a,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x6e "n" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x58,
+    0x24,
+    0x24,
+    0x24,
+    0x24,
+    0x76,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x6f "o" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x1c,
+    0x22,
+    0x22,
+    0x22,
+    0x22,
+    0x1c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x70 "p" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x58,
+    0x64,
+    0x44,
+    0x64,
+    0x58,
+    0x40,
+    0x40,
+    0x40,
+    0x00,
+    0x00,
+     /* 0x71 "q" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x34,
+    0x4c,
+    0x44,
+    0x4c,
+    0x34,
+    0x04,
+    0x04,
+    0x04,
+    0x00,
+    0x00,
+     /* 0x72 "r" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x78,
+    0x44,
+    0x40,
+    0x40,
+    0x40,
+    0x40,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x73 "s" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x18,
+    0x24,
+    0x10,
+    0x08,
+    0x24,
+    0x18,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x74 "t" */
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x10,
+    0x38,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x14,
+    0x08,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+     /* 0x75 "u" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x24,
+    0x24,
+    0x24,
+    0x24,
+    0x24,
+    0x1a,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x76 "v" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x44,
+    0x44,
+    0x44,
+    0x28,
+    0x28,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x77 "w" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x2a,
+    0x2a,
+    0x2a,
+    0x2a,
+    0x2a,
+    0x14,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x78 "x" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x44,
+    0x44,
+    0x28,
+    0x10,
+    0x28,
+    0x44,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x79 "y" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x22,
+    0x22,
+    0x14,
+    0x14,
+    0x08,
+    0x08,
+    0x10,
+    0x20,
+    0x00,
+    0x00,
+    /* 0x7a "z" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x3c,
+    0x04,
+    0x08,
+    0x10,
+    0x20,
+    0x3c,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x7b "{" */
+    0x00,
+    0x04,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x10,
+    0x08,
+    0x08,
+    0x08,
+    0x08,
+    0x04,
+    0x00,
+    0x00,
+    /* 0x7c "|" */
+    0x00,
+    0x00,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x00,
+    0x00,
+    /* 0x7d "}" */
+    0x00,
+    0x20,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x08,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x10,
+    0x20,
+    0x00,
+    0x00,
+    /* 0x7e "~" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x24,
+    0x54,
+    0x48,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    /* 0x7f "v" */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x44,
+    0x44,
+    0x44,
+    0x28,
+    0x28,
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00
+};
diff --git a/qemu-0.15.x/roms/SLOF/slof/engine.in b/qemu-0.15.x/roms/SLOF/slof/engine.in
new file mode 100644
index 0000000..2cc9d26
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/engine.in
@@ -0,0 +1,540 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+// ============================================================================
+// ============================================================================
+
+
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+// This is the core engine of Paflof.  It is almost ANS Forth compatible.
+// There are two possibilities why an aspect would not be:
+//   a) Open Firmware requires different semantics;
+//   b) bugs.
+// Most of the "extended" semantics defined in the OF specification are
+// not implemented; just the bare essentials.  For example, you can't
+// use structural words (IF, THEN, BEGIN, etc.) or return-stack
+// manipulation words (R> etc.) in the interpreter.
+
+// The data stack pointer.
+raw(HERE DOVAL _A(the_mem))
+
+// Some common constant numbers; smaller and faster if they are defined
+// as constants, than when inlined as a literal.
+con(-1 -1)
+con(0 0)
+con(1 1)
+con(2 2)
+con(3 3)
+con(4 4)
+con(8 8)
+con(H#10 0x10)
+con(H#20 0x20)
+con(H#FF 0xff)
+con(H#FFFF 0xffff)
+con(H#FFFFFFFF 0xffffffff)
+con(D#10 0x0a)
+
+
+// Manipulating different kinds of addresses.
+con(/C 1)
+con(/W 2)
+con(/L 4)
+con(/X 8)
+con(/N CELLSIZE)
+con(CELL CELLSIZE)
+col(/C* /C *)
+col(/W* /W *)
+col(/L* /L *)
+col(/X* /X *)
+col(/N* /N *)
+col(CA+ /C* +)
+col(WA+ /W* +)
+col(LA+ /L* +)
+col(XA+ /X* +)
+col(NA+ /N* +)
+col(CA1+ /C +)
+col(WA1+ /W +)
+col(LA1+ /L +)
+col(XA1+ /X +)
+col(NA1+ /N +)
+col(CHAR+ CA1+)
+col(CELL+ NA1+)
+col(CHAR- /C -)
+col(CELL- /N -)
+col(CHARS /C*)
+col(CELLS /N*)
+col(CHARS+ CA+)
+col(CELLS+ NA+)
+
+
+// Run-time words for TO and for string literals.
+col(DOTO R> CELL+ DUP >R @ CELL+ !)
+col(SLITERAL R> CELL+ DUP DUP C@ + LIT(-CELLSIZE) AND >R)
+
+
+// Stack manipulation.
+col(?DUP DUP 0BRANCH(1) DUP)
+col(TUCK SWAP OVER)
+col(2DUP OVER OVER)
+col(3DUP 2 PICK 2 PICK 2 PICK)
+col(2OVER 3 PICK 3 PICK)
+col(2DROP DROP DROP)
+col(3DROP DROP DROP DROP)
+col(NIP SWAP DROP)
+col(CLEAR 0 DEPTH!)
+col(ROT >R SWAP R> SWAP)
+col(-ROT SWAP >R SWAP R>)
+col(2SWAP >R -ROT R> -ROT)
+col(2ROT >R >R 2SWAP R> R> 2SWAP)
+col(ROLL DUP ?DUP 0BRANCH(6) ROT >R 1 - BRANCH(-9) ?DUP 0BRANCH(6) R> -ROT 1 - BRANCH(-9))
+col(-ROLL DUP ?DUP 0BRANCH(9) >R ROT R> SWAP >R 1 - BRANCH(-12) ?DUP 0BRANCH(6) R> SWAP 1 - BRANCH(-9))
+col(2>R R> ROT >R SWAP >R >R)
+col(2R> R> R> R> ROT >R SWAP)
+col(2R@ R> R> R@ OVER >R ROT >R SWAP)
+cod(?PICK)
+
+// Arithmetic.
+col(2* 1 LSHIFT)
+col(U2/ 1 RSHIFT)
+col(2/ 1 ASHIFT)
+col(<< LSHIFT)
+col(>> RSHIFT)
+col(>>A ASHIFT)
+col(INVERT -1 XOR)
+col(NOT INVERT)
+
+
+// Booleans.
+con(TRUE -1)
+con(FALSE 0)
+
+
+// Comparisons.
+col(> SWAP <)
+col(U> SWAP U<)
+col(<= > 0=)
+col(<> = 0=)
+col(>= < 0=)
+col(0<= 0 <=)
+col(0<> 0 <>)
+col(0> 0 >)
+col(0>= 0 >=)
+col(U<= U> 0=)
+col(U>= U< 0=)
+col(WITHIN ROT DUP ROT >= 0BRANCH(3) 2DROP FALSE EXIT > 0BRANCH(2) FALSE EXIT TRUE)
+col(BETWEEN 1 + WITHIN)
+
+// Double-cell single-bit shifts.
+col(D2* 2* OVER 0< - >R 2* R>)
+col(UD2/ >R U2/ R@ LIT(8*CELLSIZE-1) LSHIFT OR R> U2/)
+col(D2/ >R U2/ R@ LIT(8*CELLSIZE-1) LSHIFT OR R> 2/)
+
+
+// More arithmetic.
+col(NEGATE 0 SWAP -)
+col(ABS DUP 0< 0BRANCH(1) NEGATE)
+col(MAX 2DUP < 0BRANCH(1) SWAP DROP)
+col(MIN 2DUP > 0BRANCH(1) SWAP DROP)
+col(U* *)
+col(1+ 1 +)
+col(1- 1 -)
+col(2+ 2 +)
+col(2- 2 -)
+col(EVEN 1+ -1 AND)
+col(BOUNDS OVER + SWAP)
+
+
+// Double-cell and mixed-size arithmetic.
+col(S>D DUP 0<)
+col(DNEGATE INVERT >R NEGATE DUP 0= R> SWAP -)
+col(DABS DUP 0< 0BRANCH(1) DNEGATE)
+col(M+ SWAP >R DUP >R + DUP R> U< R> SWAP -)
+col(D+ >R M+ R> +)
+col(D- DNEGATE D+)
+col(*' >R DUP 0< >R D2* R> 0BRANCH(2) R@ M+ R>)
+col(UM* 0 -ROT LIT(8*CELLSIZE) 0 DODO *' DOLOOP(-3) DROP)
+col(M* 2DUP XOR >R >R ABS R> ABS UM* R> 0< 0BRANCH(1) DNEGATE)
+col(/' >R DUP 0< >R D2* R> OVER R@ U>= OR 0BRANCH(6) >R 1 OR R> R@ - R>)
+col(UM/MOD LIT(8*CELLSIZE) 0 DODO /' DOLOOP(-3) DROP SWAP)
+col(SM/REM OVER >R >R DABS R@ ABS UM/MOD R> 0< 0BRANCH(1) NEGATE R> 0< 0BRANCH(4) NEGATE SWAP NEGATE SWAP)
+col(FM/MOD DUP >R 2DUP XOR 0< >R SM/REM OVER 0<> R> AND 0BRANCH(6) 1- SWAP R> + SWAP EXIT R> DROP)
+
+
+// Division.
+col(U/MOD 0 SWAP UM/MOD)
+col(/MOD >R S>D R> FM/MOD)
+col(/ /MOD NIP)
+col(MOD /MOD DROP)
+col(*/MOD >R M* R> FM/MOD)
+col(*/ */MOD NIP)
+
+
+// Splitting, joining, flipping the components of a number.
+col(WBSPLIT DUP H#FF AND SWAP 8 RSHIFT)
+col(LWSPLIT DUP H#FFFF AND SWAP H#10 RSHIFT)
+col(XLSPLIT DUP H#FFFFFFFF AND SWAP H#20 RSHIFT)
+col(LBSPLIT LWSPLIT >R WBSPLIT R> WBSPLIT)
+col(XWSPLIT XLSPLIT >R LWSPLIT R> LWSPLIT)
+col(XBSPLIT XLSPLIT >R LBSPLIT R> LBSPLIT)
+col(BWJOIN 8 LSHIFT OR)
+col(WLJOIN H#10 LSHIFT OR)
+col(BLJOIN BWJOIN >R BWJOIN R> WLJOIN)
+col(WBFLIP WBSPLIT SWAP BWJOIN)
+col(LWFLIP LWSPLIT SWAP WLJOIN)
+col(LXJOIN H#20 LSHIFT OR)
+col(XLFLIP XLSPLIT SWAP LXJOIN)
+col(LBFLIP LBSPLIT SWAP 2SWAP SWAP BLJOIN)
+col(WXJOIN WLJOIN >R WLJOIN R> LXJOIN)
+col(XWFLIP XWSPLIT SWAP 2SWAP SWAP WXJOIN)
+col(BXJOIN BLJOIN >R BLJOIN R> LXJOIN)
+col(XBFLIP XLSPLIT LBFLIP SWAP LBFLIP LXJOIN)
+
+// Aligning to cell size.
+col(ALIGNED /N 1- + /N NEGATE AND)
+
+
+// Counted loop stuff.
+col(I R> R@ SWAP >R)
+col(J R> R> R> R@ SWAP >R SWAP >R SWAP >R)
+col(UNLOOP R> R> R> 2DROP >R)
+
+
+// Memory accesses.
+col(+! TUCK @ + SWAP !)
+cod(COMP)
+col(OFF FALSE SWAP !)
+col(ON TRUE SWAP !)
+col(<W@ W@ DUP LIT(0x8000) >= 0BRANCH(3) LIT(0x10000) -)
+col(2@ DUP CELL+ @ SWAP @)
+col(2! DUP >R ! R> CELL+ !)
+col(WBFLIPS BOUNDS DO?DO(8) I W@ WBFLIP I W! /W DO+LOOP(-8))
+col(LWFLIPS BOUNDS DO?DO(8) I L@ LWFLIP I L! /L DO+LOOP(-8))
+col(LBFLIPS BOUNDS DO?DO(8) I L@ LBFLIP I L! /L DO+LOOP(-8))
+col(XBFLIPS BOUNDS DO?DO(8) I X@ XBFLIP I X! /X DO+LOOP(-8))
+col(XWFLIPS BOUNDS DO?DO(8) I X@ XWFLIP I X! /X DO+LOOP(-8))
+col(XLFLIPS BOUNDS DO?DO(8) I X@ XLFLIP I X! /X DO+LOOP(-8))
+cod(FILL)
+col(BLANK LIT(0x20) FILL)
+col(ERASE LIT(0x00) FILL)
+
+
+// Exception handling.
+var(CATCHER 0)
+var(ABORT"-STR 0)
+col(CATCH DEPTH >R CATCHER @ >R RDEPTH CATCHER ! EXECUTE R> CATCHER ! R> DROP 0)
+col(THROW ?DUP 0BRANCH(12) CATCHER @ RDEPTH! R> CATCHER ! R> SWAP >R DEPTH! DROP R>)
+col(ABORT -1 THROW)
+
+
+// Text input.
+var(#TIB TIBSIZE)
+val(IB 0)
+var(#IB 0)
+val(SOURCE-ID 0)
+col(SOURCE IB #IB @)
+var(>IN 0)
+col(TERMINAL TIB DOTO IB #TIB @ #IB ! 0 DOTO SOURCE-ID)
+
+
+// ASCII codes.
+con(BL 0x20)
+con(BELL 7)
+con(BS 8)
+con(CARRET 0x0d)
+con(LINEFEED 0x0a)
+
+
+// Text output.
+dfr(EMIT)
+dfr(CR)
+col(TYPE BOUNDS DO?DO(5) I C@ EMIT DOLOOP(-5))
+col(LL-CR CARRET EMIT LINEFEED EMIT)
+col(SPACE BL EMIT)
+col(SPACES 0 DO?DO(3) SPACE DOLOOP(-3))
+
+
+// Text manipulation.
+col(COUNT DUP CHAR+ SWAP C@)
+col(PACK DUP >R SWAP MOVE R>)
+col(UPC DUP LIT('a') LIT('z') BETWEEN 0BRANCH(3) LIT(0x20) - )
+col(LCC DUP LIT('A') LIT('Z') BETWEEN 0BRANCH(3) LIT(0x20) + )
+
+
+// Text input.
+dfr(KEY)
+dfr(KEY?)
+dfr(ACCEPT)
+var(SPAN 0)
+col(EXPECT ACCEPT SPAN !)
+col(REFILL SOURCE-ID 0= 0BRANCH(7) SOURCE EXPECT 0 >IN ! TRUE EXIT SOURCE-ID -1 = 0BRANCH(2) FALSE EXIT LIT(0x6502) THROW)
+
+
+// Number base.
+var(BASE 16)
+col(DECIMAL D#10 BASE !)
+col(HEX H#10 BASE !)
+col(OCTAL 8 BASE !)
+
+
+// Pictured numeric output.
+col(PAD HERE LIT(256) +)
+col(TODIGIT DUP LIT(9) > 0BRANCH(3) LIT(0x27) + LIT(0x30) +)
+col(MU/MOD DUP >R U/MOD R> SWAP >R UM/MOD R>)
+col(<# PAD DUP !)
+col(HOLD PAD DUP @ 1- TUCK SWAP ! C!)
+col(SIGN 0< 0BRANCH(3) LIT('-') HOLD)
+col(# BASE @ MU/MOD ROT TODIGIT HOLD)
+col(#S # 2DUP OR 0BRANCH(2) BRANCH(-7))
+col(#> 2DROP PAD DUP @ TUCK -)
+col((.) <# DUP >R ABS 0 #S R> SIGN #>)
+col(U# BASE @ U/MOD SWAP TODIGIT HOLD)
+col(U#S U# DUP 0BRANCH(2) BRANCH(-6))
+col(U#> DROP PAD DUP @ TUCK -)
+col((U.) <# U#S U#>)
+col(. (.) TYPE SPACE)
+col(S. .)
+col(U. (U.) TYPE SPACE)
+col(.R SWAP (.) ROT 2DUP < 0BRANCH(5) OVER - SPACES BRANCH(1) DROP TYPE)
+col(U.R SWAP (U.) ROT 2DUP < 0BRANCH(5) OVER - SPACES BRANCH(1) DROP TYPE)
+col(.D BASE @ SWAP DECIMAL . BASE !)
+col(.H BASE @ SWAP HEX . BASE !)
+col(.S DEPTH DUP 0< 0BRANCH(2) DROP EXIT 0 DO?DO(8) DEPTH I - 1- PICK . DOLOOP(-8))
+col(? @ .)
+
+
+// Numeric input.
+col(DIGIT OVER UPC DUP LIT('A') LIT('Z') BETWEEN 0BRANCH(3) LIT(7) - LIT(0x30) - DUP ROT 0 SWAP WITHIN 0BRANCH(4) NIP TRUE BRANCH(2) DROP FALSE)
+col(>NUMBER DUP 0= 0BRANCH(1) EXIT OVER C@ BASE @ DIGIT 0BRANCH(23) SWAP >R SWAP >R >R BASE @ U* SWAP BASE @ UM* ROT + R> 0 D+ R> CHAR+ R> 1- BRANCH(-35) DROP)
+col($NUMBER DUP 0= 0BRANCH(4) DROP DROP TRUE EXIT >R DUP >R C@ LIT('-') = DUP 0BRANCH(15) R> CHAR+ R> 1- DUP 0= 0BRANCH(5) DROP DROP DROP TRUE EXIT >R >R 0 0 R> R> >NUMBER NIP 0= 0BRANCH(7) DROP SWAP 0BRANCH(1) NEGATE FALSE EXIT DROP DROP DROP TRUE)
+
+
+// Data space allocation.
+col(ALLOT HERE + DOTO HERE)
+col(, HERE ! /N ALLOT)
+col(C, HERE C! /C ALLOT)
+col(W, HERE W! /W ALLOT)
+col(L, HERE L! /L ALLOT)
+col(X, HERE X! /X ALLOT)
+col(ALIGN HERE /N 1- AND 0BRANCH(4) 0 C, BRANCH(-10))
+col(PLACE 2DUP C! CHAR+ SWAP CHARS BOUNDS DO?DO(9) DUP C@ I C! CHAR+ 1 CHARS DO+LOOP(-9) DROP)
+col(STRING, HERE OVER 1+ CHARS ALLOT PLACE)
+
+
+// Every language needs a no-op.
+col(NOOP)
+
+
+// Now it gets ugly: search-order and word-lisst infrastructure.
+
+raw(FORTH-WORDLIST DODOES _A(xt_NOOP+2+(8/sizeof(long))) _A(0) _A(0))
+	// Engine initialisation will set this last cell to the xt of LASTWORD.
+
+// compilation dictionary
+raw(CURRENT DOVAL _A(xt_FORTH_X2d_WORDLIST+3+(16/sizeof(long))))
+	// +7 for 32-bit, +5 for 64-bit
+
+col(LAST CURRENT CELL+)
+
+// for context dictionaries
+raw(SEARCH-ORDER DOVAR _A(xt_FORTH_X2d_WORDLIST+3+(16/sizeof(long))) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0))
+	// +7 for 32-bit, +5 for 64-bit
+// for context dictionaries
+//raw(SEARCH-ORDER DOVAR _A(xt_FORTH_X2d_WORDLIST+3+(sizeof("  FORTH-WORDLIST")/sizeof(long))) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0))
+// +7 for 32-bit, +5 for 64-bit
+raw(CONTEXT DOVAL _A(xt_SEARCH_X2d_ORDER+2+(16/sizeof(long))))
+//raw(CONTEXT DOVAL _A(xt_SEARCH_X2d_ORDER+6))
+// +6 for 32-bit, +4 for 64-bit
+
+// Dictionary structure.
+col(LINK>NAME CELL+)
+col(NAME> CHAR+ DUP C@ 1+ CHARS+ ALIGNED)
+col(LINK> LINK>NAME NAME>)
+col(NAME>STRING CHAR+ COUNT)
+
+// Creating word headers.
+var(LATEST 0)
+dfr((REVEAL))
+col(HEADER ALIGN HERE LAST @ , LATEST ! 0 C, STRING, ALIGN)
+col(REVEAL   LATEST @ LINK>NAME NAME>STRING (REVEAL) LATEST @ LAST !)
+
+
+// Finding words.
+cod(STRING=CI)
+// (find) ( str len head -- 0 | link )
+dfr((FIND))
+col(((FIND)) DUP 0BRANCH(15) >R 2DUP R@ LINK>NAME NAME>STRING STRING=CI 0BRANCH(3) 2DROP R> EXIT R> @ BRANCH(-18) 3DROP FALSE)
+col((FIND-ORDER) CONTEXT DUP >R SEARCH-ORDER U>= 0BRANCH(18) 2DUP R@ @ CELL+ @ (FIND) ?DUP 0BRANCH(5) NIP NIP R> DROP EXIT R> CELL- BRANCH(-24) R> 3DROP 0)
+col($FIND (FIND-ORDER) DUP 0BRANCH(6) LINK>NAME DUP NAME> SWAP C@ TRUE)
+
+// Flags on words.
+con('IMMEDIATE 1)
+col(IMMEDIATE? 'IMMEDIATE AND 0<>)
+col(IMMEDIATE LAST @ CELL+ DUP C@ 'IMMEDIATE OR SWAP C!)
+
+// Parsing.
+col(FINDCHAR SWAP 0 DO?DO(24) OVER I + C@ OVER DUP BL = 0BRANCH(3) <= BRANCH(1) = 0BRANCH(6) I UNLOOP NIP NIP TRUE EXIT DOLOOP(-24) DROP DROP FALSE)
+col(PARSE >R IB >IN @ + SPAN @ >IN @ - 2DUP R> FINDCHAR 0BRANCH(6) NIP DUP 1 + BRANCH(1) DUP >IN +!)
+col(SKIPWS IB SPAN @ DUP >IN @ > 0BRANCH(14) OVER >IN @ + C@ BL <= 0BRANCH(5) 1 >IN +! BRANCH(-20) DROP DROP)
+col(PARSE-WORD SKIPWS BL PARSE)
+var(WHICHPOCKET 0)
+// We reserved 0x1000 for the pockets. So we have 16 pockets a 0x100
+col(POCKET POCKETS WHICHPOCKET @ LIT(POCKETSIZE) * + WHICHPOCKET @ 1 + DUP LIT(NUMPOCKETS) = 0BRANCH(2) DROP 0 WHICHPOCKET !)
+
+col(WORD POCKET >R PARSE DUP R@ C! BOUNDS R> DUP 2SWAP DO?DO(7) CHAR+ I C@ OVER C! DOLOOP(-7) DROP)
+
+// Some simple parsing words.
+col(CHAR PARSE-WORD DROP C@)
+imm(( LIT(')') PARSE 2DROP)
+// Removing comments out of the code, the code from the backslash to the next \n is removed.
+// We need to start from cursor -1 (the backslash) to handle the case backslash+linefeed correctly 0x5c0a
+imm(\ >IN @ 1- >IN ! LINEFEED PARSE 2DROP)
+
+// The compiler infrastructure.
+var(STATE 0)
+imm([ STATE OFF)
+col(] LIT(0x100) STATE !)
+col(?COMP STATE @ 0BRANCH(1) EXIT LIT(-134) THROW)
+
+col(COMPILE, ,)
+col(: PARSE-WORD HEADER DOTICK DOCOL COMPILE, ])
+col(:NONAME ALIGN HERE DOTICK DOCOL COMPILE, ])
+imm(; ?COMP DOTICK SEMICOLON COMPILE, REVEAL [)
+
+// Compiling strings.
+imm(C" ?COMP LIT('"') PARSE DOTICK SLITERAL COMPILE, DUP C, BOUNDS DO?DO(5) I C@ C, DOLOOP(-5) ALIGN)
+imm(S" STATE @ 0BRANCH(5) C" DOTICK COUNT COMPILE, EXIT LIT('"') PARSE DUP >R POCKET DUP >R SWAP MOVE R> R>)
+imm(Z" S" 2DUP + 0 SWAP C! DROP)
+imm(." STATE @ 0BRANCH(5) S" DOTICK TYPE COMPILE, EXIT  LIT('"') PARSE TYPE)
+imm(.( LIT(')') PARSE TYPE)
+
+col(COMPILE R> CELL+ DUP @ COMPILE, >R)
+
+var(THERE 0)
+col(+COMP STATE @ 1 STATE +! 0BRANCH(1) EXIT HERE THERE ! COMP-BUFFER DOTO HERE COMPILE DOCOL)
+col(-COMP -1 STATE +! STATE @ 0BRANCH(1) EXIT COMPILE EXIT THERE @ DOTO HERE COMP-BUFFER EXECUTE)
+
+// Structure words.
+col(RESOLVE-ORIG HERE OVER CELL+ - SWAP !)
+imm(AHEAD +COMP DOTICK DOBRANCH COMPILE, HERE 0 COMPILE,)
+imm(IF +COMP DOTICK DO0BRANCH COMPILE, HERE 0 COMPILE,)
+imm(THEN ?COMP RESOLVE-ORIG -COMP)
+imm(ELSE ?COMP DOTICK DOBRANCH COMPILE, HERE 0 COMPILE, SWAP RESOLVE-ORIG)
+
+imm(CASE +COMP 0)
+imm(ENDCASE ?COMP DOTICK DROP COMPILE, ?DUP 0BRANCH(5) 1- SWAP THEN BRANCH(-8) -COMP)
+imm(OF ?COMP 1+ >R DOTICK OVER COMPILE, DOTICK = COMPILE, IF DOTICK DROP COMPILE, R>)
+imm(ENDOF ?COMP >R ELSE R>)
+
+col(RESOLVE-DEST HERE CELL+ - COMPILE,)
+imm(BEGIN +COMP HERE)
+imm(AGAIN ?COMP DOTICK DOBRANCH COMPILE, RESOLVE-DEST -COMP)
+imm(UNTIL ?COMP DOTICK DO0BRANCH COMPILE, RESOLVE-DEST -COMP)
+imm(WHILE ?COMP IF SWAP)
+imm(REPEAT ?COMP AGAIN THEN)
+
+// Counted loops.
+var(LEAVES 0)
+col(RESOLVE-LOOP LEAVES @ ?DUP 0BRANCH(10) DUP @ SWAP HERE OVER - SWAP ! BRANCH(-13) HERE - COMPILE, LEAVES !)
+imm(DO +COMP LEAVES @ HERE DOTICK DODO COMPILE, 0 LEAVES !)
+imm(?DO +COMP LEAVES @ DOTICK DODO?DO COMPILE, HERE HERE LEAVES ! 0 COMPILE,)
+imm(LOOP ?COMP DOTICK DODOLOOP COMPILE, RESOLVE-LOOP -COMP)
+imm(+LOOP ?COMP DOTICK DODO+LOOP COMPILE, RESOLVE-LOOP -COMP)
+imm(LEAVE ?COMP DOTICK DODOLEAVE COMPILE, LEAVES @ HERE LEAVES ! COMPILE,)
+imm(?LEAVE ?COMP DOTICK DODO?LEAVE COMPILE, LEAVES @ HERE LEAVES ! COMPILE,)
+
+// Interpreter nesting.
+col(SAVE-SOURCE R> IB >R #IB @ >R SOURCE-ID >R SPAN @ >R >IN @ >R >R)
+col(RESTORE-SOURCE R> R> >IN ! R> SPAN ! R> DOTO SOURCE-ID R> #IB ! R> DOTO IB >R)
+
+// System replies.
+str(OK-STR "ok")
+str(ABORTED-STR "Aborted")
+str(EXCEPTION-STR "Exception #")
+str(UNKNOWN-STR "Undefined word")
+dfr(HW-EXCEPTION-HANDLER)
+val(SHOW-STACK? 0)
+col(SHOWSTACK -1 DOTO  SHOW-STACK?)
+col(NOSHOWSTACK 0 DOTO  SHOW-STACK?)
+col(PRINT-STACK SHOW-STACK? 0BRANCH(5) >R >R .S R> R> )
+col(PRINT-EXCEPTION DUP LIT(-99) = 0BRANCH(7) DOTICK UNKNOWN-STR COUNT TYPE CR DROP EXIT DUP LIT(0x100) = 0BRANCH(2) DROP EXIT HW-EXCEPTION-HANDLER )
+col(PRINT-STATUS SPACE DUP 0= 0BRANCH(5) PRINT-STACK DOTICK OK-STR BRANCH(7) DUP -1 = 0BRANCH(6) DOTICK ABORTED-STR COUNT TYPE BRANCH(10) DUP LIT(-2) = 0BRANCH(7) ABORT"-STR @ COUNT TYPE DROP BRANCH(1) PRINT-EXCEPTION CR)
+
+// The compiler and interpreter.
+col(COMPILE-WORD 2DUP $FIND 0BRANCH(10) IMMEDIATE? 0BRANCH(4) NIP NIP EXECUTE EXIT COMPILE, 2DROP EXIT 2DUP $NUMBER 0BRANCH(4) TYPE LIT(-99) THROW DOTICK DOLIT COMPILE, COMPILE, 2DROP)
+col(INTERPRET-WORD 2DUP $FIND 0BRANCH(5) DROP NIP NIP EXECUTE EXIT 2DUP $NUMBER 0BRANCH(4) TYPE LIT(-99) THROW >R 2DROP R>)
+col(INTERPRET 0 >IN ! PARSE-WORD DUP 0BRANCH(10) STATE @ 0BRANCH(3) COMPILE-WORD BRANCH(1) INTERPRET-WORD BRANCH(-14) 2DROP)
+
+// Evaluate, the one word to rule them all.  It is evil, btw.
+col(EVALUATE SAVE-SOURCE -1 DOTO SOURCE-ID DUP #IB ! SPAN ! DOTO IB DOTICK INTERPRET CATCH RESTORE-SOURCE THROW)
+col(EVAL EVALUATE)
+
+// Abort with a message.
+col(DOABORT" SWAP 0BRANCH(5) ABORT"-STR ! LIT(-2) THROW DROP)
+imm(ABORT" C" DOTICK DOABORT" COMPILE,)
+
+// Tick.
+str(UNDEFINED-STR "undefined word")
+col(' PARSE-WORD $FIND 0= DOTICK UNDEFINED-STR DOABORT" DROP)
+
+// The outer interpreter.
+col(QUIT 0 RDEPTH! [ TERMINAL DEPTH . LIT('>') EMIT SPACE REFILL 0BRANCH(10) SPACE DOTICK INTERPRET CATCH DUP PRINT-STATUS 0BRANCH(-17) BRANCH(-23))
+
+// Reading and writing to/from file; including files.
+dfr(MAP-FILE)
+dfr(UNMAP-FILE)
+dfr(WRITE-FILE)
+col(INCLUDED MAP-FILE 2DUP >R >R BOUNDS DO?DO(21) R> R@ SWAP >R R@ - R@ SWAP 2DUP LINEFEED FINDCHAR 0BRANCH(1) NIP DUP >R EVALUATE R> 1+ DO+LOOP(-21) R> R> UNMAP-FILE)
+col(INCLUDE PARSE-WORD INCLUDED)
+
+// CREATE ... DOES> ...
+col($CREATE HEADER DOTICK DODOES COMPILE, DOTICK NOOP CELL+ COMPILE, REVEAL)
+col(CREATE PARSE-WORD $CREATE)
+col(DODOES> R> CELL+ LATEST @ LINK> CELL+ !)
+imm(DOES> DOTICK DODOES> COMPILE,)
+
+// Defining words.
+col(CONSTANT PARSE-WORD HEADER DOTICK DOCON COMPILE, COMPILE, REVEAL)
+col(VALUE PARSE-WORD HEADER DOTICK DOVAL COMPILE, COMPILE, REVEAL)
+col(VARIABLE PARSE-WORD HEADER DOTICK DOVAR COMPILE, 0 COMPILE, REVEAL)
+col(BUFFER: PARSE-WORD HEADER DOTICK DOBUFFER: COMPILE, ALLOT REVEAL)
+col(DEFER PARSE-WORD HEADER DOTICK DODEFER COMPILE, DOTICK ABORT COMPILE, REVEAL)
+col(ALIAS PARSE-WORD HEADER DOTICK DOALIAS COMPILE, ' COMPILE, REVEAL)
+col(STRUCT 0)
+col(END-STRUCT DROP)
+col(FIELD PARSE-WORD HEADER DOTICK DOFIELD COMPILE, OVER , + REVEAL)
+
+// Words with (mostly) non-standard compilation behaviour.
+imm(LITERAL DOTICK DOLIT COMPILE, COMPILE,)
+imm([COMPILE] ' COMPILE,)
+imm(POSTPONE PARSE-WORD $FIND 0= DOTICK UNDEFINED-STR DOABORT" IMMEDIATE? 0= 0BRANCH(6) DOTICK DOTICK COMPILE, COMPILE, DOTICK COMPILE, COMPILE,)
+imm([CHAR] CHAR LITERAL)
+imm(['] ' DOTICK DOTICK COMPILE, COMPILE,)
+
+// FIND.
+col(FIND DUP COUNT $FIND 0BRANCH(9) ROT DROP TRUE SWAP IMMEDIATE? 0BRANCH(1) NEGATE EXIT FALSE EXIT)
+
+// Accessing data in CREATE'd words.
+imm(TO ' STATE @ 0BRANCH(5) DOTICK DOTO COMPILE, COMPILE, EXIT CELL+ !)
+col(BEHAVIOR CELL+ @)
+col(>BODY 2 CELLS +)
+col(BODY> 2 CELLS -)
+
+// Making words recursive.
+imm(RECURSIVE REVEAL)
+imm(RECURSE LATEST @ LINK> COMPILE,)
+
+// Numeric input.
+imm(d# PARSE-WORD BASE @ >R DECIMAL EVALUATE R> BASE !)
+imm(h# PARSE-WORD BASE @ >R HEX EVALUATE R> BASE !)
+imm(o# PARSE-WORD BASE @ >R OCTAL EVALUATE R> BASE !)
diff --git a/qemu-0.15.x/roms/SLOF/slof/entry.S b/qemu-0.15.x/roms/SLOF/slof/entry.S
new file mode 100644
index 0000000..ce9dd83
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/entry.S
@@ -0,0 +1,187 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <macros.h>
+
+#define STACKSIZE 0x1000
+
+	#
+	# The generic exception code.
+	#
+	# Enter with GPR0 = vector, SPRG0 = saved GPR0
+	#
+
+	.section ".entry_text"
+
+the_handler:
+	.quad	handler
+
+eregs:
+	/* the_exception_frame is a C variable which is usually
+	 * defined in $(TARG).c
+	 * the_exception_frame can be accessed from paflof through
+	 * the word eregs
+	 * in the case an excpetion is handled paflof will read
+	 * from eregs the values of all registers and print them
+	 * out in the exception handler */
+	.quad	the_exception_frame
+
+handler:
+	mtsprg 1,1	# SPRG1 = saved GPR1
+	bcl 20,31,$+4
+	mflr 1
+	ld 1,eregs-$+4(1)	# GPR1 = address of register save area
+
+	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15, \
+		16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+	std \i,\i*8(1)
+	.endr		# save GPR2..GPR31
+
+	li r3, 3        // GPR3 = mode (param_1, param_2)
+	mr 4,0		// GPR4 = vector
+
+	mfsprg 0,0
+	std 0,0(1)	# save GPR0
+	mfsprg 0,1
+	std 0,8(1)	# save GPR1
+
+	cmpwi	r4, 0x900	# Decrementer interrupt
+	bne	0f
+	mfdec	r5		# Save old value of decrementer as reason
+	lis	r0,0x7fff	# Set decrementer to highest value 
+	mtdec	r0
+0:
+	mfcr 0
+	std 0,0x100(1)
+	mfxer 0
+	std 0,0x108(1)
+	mfsprg 0,3	# save lr	
+	std 0,0x110(1)
+	mfsprg 0,2	# save ctr	
+	std 0,0x118(1)
+	mfsrr0 0
+	std 0,0x120(1)
+	mfsrr1 0
+	std 0,0x128(1)
+	mfdar 0
+	std 0,0x130(1)
+	mfdsisr 0
+	std 0,0x138(1)	# save special regs
+
+	bcl	20, 31, over
+base:
+	.align	3
+.the_system_stack:
+	.quad   the_system_stack+STACKSIZE-base
+over:
+	mflr	r2				/* gpr 2 is the base */
+	ld	r1, .the_system_stack-base(r2)	/* load stack pointer */
+	add	r1, r1, r2			/* add base */
+	li	r0, 0
+	stdu	r0, -0x10(r1)
+	stdu	r1, -0x100(r1)
+
+	lis 2,engine at ha
+	ld 0,engine at l(2) # set up entry
+	mtsrr0	0
+		
+	ld 2,8+engine at l(2) # set up TOC pointer
+
+	rfid
+#	b .engine	# ...and run!
+
+
+
+	#
+	# Swap non-volatile client interface regs, plus GPR3..GPR7.
+	#
+
+swap_ci_regs:
+	/* save lr */
+	mflr	r0
+	/* let's find out where our client stack is */
+	bcl	20, 31, client_over
+client_base:
+	.align	3
+.the_client_frame:
+	.quad   the_client_frame-client_base
+client_over:
+	mflr	r8				/* gpr 2 is the client_base */
+	mtlr	r0				/* restore the original lr */
+	ld	r0, .the_client_frame-client_base(r8)
+	add	r8, r0, r8			/* add the client_base */
+	/* r8 now contains the address of the_client_frame */
+
+	.irp i, 1,2,3,4,5,6,7, \
+		13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+	ld 0,\i*8(8)
+	std \i,\i*8(8)
+	mr \i,0
+	.endr		# swap GPR1..7, GPR13..31
+
+	ld 0,0x100(8)
+	mfcr 9
+	mtcrf 0xff,0
+	std 9,0x100(8)	# swap CR
+
+	ld 0,0x128(8)
+	mfmsr 9
+	mtmsrd 0
+	sync
+	isync
+	std 9,0x128(8)	# swap MSR
+
+	blr
+
+	#
+	# Entry point for the OF client interface.
+	#
+
+        .globl client_entry_point
+        .section        ".opd","aw"
+        .align 3
+client_entry_point:
+        .quad   .client_entry_point,.TOC. at tocbase,0
+        .previous
+        .type   .client_entry_point, at function
+        .globl  .client_entry_point
+.client_entry_point:
+	mflr 4
+	bl swap_ci_regs	# swap regs
+	mtlr 4
+	li 3, 0 # client call
+	blr	
+
+	#
+	# Start the client.
+	#
+
+        .globl call_client
+        .section        ".opd","aw"
+        .align 3
+call_client:
+        .quad   .call_client,.TOC. at tocbase,0
+        .previous
+        .type   .call_client, at function
+        .globl  .call_client
+
+.call_client:	# called with r3 = address, returns r3
+	mflr 4
+	mtctr 3
+	bl swap_ci_regs
+	bctrl
+	bl swap_ci_regs
+	mtlr 4
+	li 3, -1 # client app return
+	blr
+
+	.lcomm	the_system_stack, STACKSIZE, 16
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/accept.fs b/qemu-0.15.x/roms/SLOF/slof/fs/accept.fs
new file mode 100644
index 0000000..7e8e271
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/accept.fs
@@ -0,0 +1,410 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Implementation of ACCEPT.  Using ECMA-48 for terminal control.
+
+: beep  bell emit ;
+
+: TABLE-EXECUTE
+  CREATE DOES> swap cells+ @ ?dup IF execute ELSE beep THEN ;
+
+0 VALUE accept-adr
+0 VALUE accept-max
+0 VALUE accept-len
+0 VALUE accept-cur
+
+: esc  1b emit ;
+: csi  esc 5b emit ;
+
+: move-cursor ( -- )
+   esc ." 8" accept-cur IF
+      csi base @ decimal accept-cur 0 .r base ! ." C"
+   THEN
+;
+
+: redraw-line ( -- )
+   accept-cur accept-len = IF EXIT THEN
+   move-cursor
+   accept-adr accept-len accept-cur /string type
+   csi ." K" move-cursor
+;
+
+: full-redraw-line ( -- )
+   accept-cur 0 to accept-cur move-cursor
+   accept-adr accept-len type
+   csi ." K" to accept-cur move-cursor
+;
+
+: redraw-prompt ( -- )
+   cr depth . [char] > emit
+;
+
+: insert-char ( char -- )
+   accept-len accept-max = IF drop beep EXIT THEN
+   accept-cur accept-len <> IF csi ." @" dup emit
+   accept-adr accept-cur + dup 1+ accept-len accept-cur - move
+   ELSE dup emit THEN
+   accept-adr accept-cur + c!
+   accept-cur 1+ to accept-cur
+   accept-len 1+ to accept-len redraw-line
+;
+
+: delete-char ( -- )
+   accept-cur accept-len = IF beep EXIT THEN
+   accept-len 1- to accept-len
+   accept-adr accept-cur + dup 1+ swap accept-len accept-cur - move
+   csi ." P" redraw-line
+;
+
+\ *
+\ * History handling
+\ *
+
+STRUCT
+cell FIELD his>next
+cell FIELD his>prev
+cell FIELD his>len
+   0 FIELD his>buf
+CONSTANT /his
+0 VALUE his-head
+0 VALUE his-tail
+0 VALUE his-cur
+
+: add-history ( -- )
+   accept-len 0= IF EXIT THEN
+   /his accept-len + alloc-mem
+   his-tail IF dup his-tail his>next ! ELSE dup to his-head THEN
+   his-tail over his>prev !  0 over his>next !  dup to his-tail
+   accept-len over his>len !  accept-adr swap his>buf accept-len move
+;
+
+: history  ( -- )
+   his-head BEGIN dup WHILE
+   cr dup his>buf over his>len @ type
+   his>next @ REPEAT drop
+;
+
+: select-history ( his -- )
+   dup to his-cur dup IF
+   dup his>len @ accept-max min dup to accept-len to accept-cur
+   his>buf accept-adr accept-len move ELSE
+   drop 0 to accept-len 0 to accept-cur THEN
+   full-redraw-line
+;
+
+
+\
+\ tab completion
+\
+
+\ tab completion state variables
+0 value ?tab-pressed
+0 value tab-last-adr
+0 value tab-last-len
+
+\ compares two strings and returns the longest equal substring.
+: $same-string ( addr-1 len-1 addr-2 len-2 -- addr-1 len-1' )
+   dup 0= IF    \ The second parameter is not a string.
+      2drop EXIT \ bail out
+   THEN
+   rot min 0 0 -rot ( addr1 addr2 0 len' 0 )
+   DO ( addr1 addr2 len-1' )
+      2 pick i + c@ lcc
+      2 pick i + c@ lcc
+      = IF 1 + ELSE leave THEN
+   LOOP
+   nip
+;
+
+: $tab-sift-words    ( text-addr text-len -- sift-count )
+   sift-compl-only >r true to sift-compl-only \ save sifting mode
+
+   last BEGIN @ ?dup WHILE \ loop over all words
+      $inner-sift IF \ any completions possible?
+         \ convert to lower case for user interface sanity
+         2dup bounds DO I c@ lcc I c! LOOP
+         ?tab-pressed IF 2dup type space THEN  \ <tab><tab> prints possibilities
+         tab-last-adr tab-last-len $same-string \ find matching substring ...
+         to tab-last-len to tab-last-adr       \ ... and save it
+      THEN
+   repeat
+   2drop
+
+   #sift-count 0 to #sift-count	\ how many words were found?
+   r> to sift-compl-only		\ restore sifting completion mode
+;
+
+\ 8< node sifting for tab completion on device tree nodes below this line 8<
+
+#include <stack.fs>
+
+10 new-stack device-stack
+
+: (next-dev) ( node -- node' addr len )
+   device-stack
+   dup (node>path) rot
+   dup child IF dup push child -rot EXIT THEN
+   dup peer IF peer -rot EXIT THEN
+   drop
+   BEGIN
+      stack-depth
+   WHILE
+      pop peer ?dup IF -rot EXIT THEN
+   REPEAT
+   0 -rot
+;
+
+: $inner-sift-nodes ( text-addr text-len node -- ... path-addr path-len true | false )
+   (next-dev) ( text-addr text-len node' path-addr path-len )
+   dup 0= IF drop false EXIT THEN
+   2dup 6 pick 6 pick find-isubstr ( text-addr text-len node' path-addr path-len pos )
+   0= IF
+      #sift-count 1+ to #sift-count \ count completions
+      true
+   ELSE
+      2drop false
+   THEN
+;
+
+\
+\ test function for (next-dev)
+: .nodes ( -- )
+   s" /" find-node BEGIN dup WHILE
+      (next-dev)
+      type cr
+   REPEAT
+   drop
+   reset-stack
+;
+
+\ node sifting wants its own pockets
+create sift-node-buffer 1000 allot
+0 value sift-node-num
+: sift-node-buffer
+   sift-node-buffer sift-node-num 100 * +
+   sift-node-num 1+ dup 10 = IF drop 0 THEN
+   to sift-node-num
+;
+
+: $tab-sift-nodes    ( text-addr text-len -- sift-count )
+   s" /" find-node BEGIN dup WHILE
+      $inner-sift-nodes IF \ any completions possible?
+         sift-node-buffer swap 2>r 2r@ move 2r> \ make an almost permanent copy without strdup
+         ?tab-pressed IF 2dup type space THEN  \ <tab><tab> prints possibilities
+         tab-last-adr tab-last-len $same-string \ find matching substring ...
+         to tab-last-len to tab-last-adr       \ ... and save it
+      THEN
+   REPEAT
+   2drop drop
+   #sift-count 0 to #sift-count	\ how many words were found?
+   reset-stack
+;
+
+: $tab-sift    ( text-addr text-len -- sift-count )
+   ?tab-pressed IF beep space THEN \ cosmetical fix for <tab><tab>
+
+   dup IF bl rsplit dup IF 2swap THEN ELSE 0 0 THEN >r >r
+
+   0 dup to tab-last-len to tab-last-adr	\ reset last possible match
+   current-node @ IF			\ if we are in a node?
+      2dup 2>r				\ save text
+      $tab-sift-words to #sift-count	\ search in current node first
+      2r>				\ fetch text to complete, again
+   THEN
+   2dup 2>r
+   current-node @ >r 0 set-node		\ now search in global words
+   $tab-sift-words to #sift-count
+   r> set-node
+   2r> $tab-sift-nodes
+   \ concatenate previous commands
+   r> r> dup IF s"  " $cat THEN tab-last-adr tab-last-len $cat
+   to tab-last-len to tab-last-adr  \ ... and save the whole string
+;
+
+\ 8< node sifting for tab completion on device tree nodes above this line 8<
+
+: handle-^A
+   0 to accept-cur move-cursor ;
+: handle-^B
+   accept-cur ?dup IF 1- to accept-cur ( csi ." D" ) move-cursor THEN ;
+: handle-^D
+   delete-char ( redraw-line ) ;
+: handle-^E
+   accept-len to accept-cur move-cursor ;
+: handle-^F
+   accept-cur accept-len <> IF accept-cur 1+ to accept-cur csi ." C" THEN ;
+: handle-^H
+   accept-cur 0= IF beep EXIT THEN
+   handle-^B delete-char
+;
+: handle-^I
+   accept-adr accept-len
+   $tab-sift 0 > IF
+      ?tab-pressed IF
+         redraw-prompt full-redraw-line
+         false to ?tab-pressed
+      ELSE
+         tab-last-adr accept-adr tab-last-len move    \ copy matching substring
+         tab-last-len dup to accept-len to accept-cur \ len and cursor position
+         full-redraw-line		\ redraw new string
+         true to ?tab-pressed	\ second tab will print possible matches
+      THEN
+   THEN
+;
+
+: handle-^K
+   BEGIN accept-cur accept-len <> WHILE delete-char REPEAT ;
+: handle-^L
+   history redraw-prompt full-redraw-line ;
+: handle-^N
+   his-cur IF his-cur his>next @ ELSE his-head THEN
+   dup to his-cur select-history
+;
+: handle-^P
+   his-cur IF his-cur his>prev @ ELSE his-tail THEN
+   dup to his-cur select-history
+;
+: handle-^Q  \ Does not handle terminal formatting yet.
+   key insert-char ;
+: handle-^R
+   full-redraw-line ;
+: handle-^U
+   0 to accept-len 0 to accept-cur full-redraw-line ;
+
+: handle-fn
+   key drop beep
+;
+
+TABLE-EXECUTE handle-CSI
+0 , ' handle-^P , ' handle-^N , ' handle-^F ,
+' handle-^B , 0 , 0 , 0 ,
+' handle-^A , 0 , 0 , ' handle-^E ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+
+TABLE-EXECUTE handle-meta
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , ' handle-fn ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , 0 ,
+0 , 0 , 0 , ' handle-CSI ,
+0 , 0 , 0 , 0 ,
+
+: handle-ESC-O
+   key
+   dup 48 = IF
+      handle-^A
+   ELSE
+      dup 46 = IF
+         handle-^E
+      THEN
+   THEN drop
+;
+
+: handle-ESC-5b
+   key
+   dup 31 = IF \ HOME
+      key drop ( drops closing 7e ) handle-^A
+   ELSE
+      dup 33 = IF \ DEL
+         key drop handle-^D
+      ELSE
+         dup 34 = IF \ END
+            key drop handle-^E
+         ELSE
+            dup 1f and handle-CSI
+         THEN
+      THEN
+   THEN drop
+;
+
+: handle-ESC
+   key
+   dup 5b = IF
+      handle-ESC-5b
+   ELSE
+      dup 4f = IF
+         handle-ESC-O
+      ELSE
+         dup 1f and handle-meta
+      THEN
+   THEN drop
+;
+
+TABLE-EXECUTE handle-control
+0 , \ ^@:
+' handle-^A ,
+' handle-^B ,
+0 , \ ^C:
+' handle-^D ,
+' handle-^E ,
+' handle-^F ,
+0 , \ ^G:
+' handle-^H ,
+' handle-^I , \ tab
+0 , \ ^J:
+' handle-^K ,
+' handle-^L ,
+0 , \ ^M: enter: handled in main loop
+' handle-^N ,
+0 , \ ^O:
+' handle-^P ,
+' handle-^Q ,
+' handle-^R ,
+0 , \ ^S:
+0 , \ ^T:
+' handle-^U ,
+0 , \ ^V:
+0 , \ ^W:
+0 , \ ^X:
+0 , \ ^Y: insert save buffer
+0 , \ ^Z:
+' handle-ESC ,
+0 , \ ^\:
+0 , \ ^]:
+0 , \ ^^:
+0 , \ ^_:
+
+: (accept) ( adr len -- len' )
+   cursor-on
+   to accept-max to accept-adr
+   0 to accept-len 0 to accept-cur
+   0 to his-cur
+   1b emit 37 emit
+   BEGIN
+      key dup 0d <>
+   WHILE
+      dup 9 <> IF 0 to ?tab-pressed THEN \ reset state machine
+      dup 7f = IF drop 8 THEN \ Handle DEL as if it was BS. ??? bogus
+      dup bl < IF handle-control ELSE
+         dup 80 and IF
+            dup a0 < IF 7f and handle-meta ELSE drop beep THEN
+         ELSE
+            insert-char
+	 THEN
+      THEN
+   REPEAT
+   drop add-history
+   accept-len to accept-cur
+   move-cursor space
+   accept-len
+   cursor-off
+;
+
+' (accept) to accept
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/alloc-mem.fs b/qemu-0.15.x/roms/SLOF/slof/fs/alloc-mem.fs
new file mode 100644
index 0000000..59381a7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/alloc-mem.fs
@@ -0,0 +1,75 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+#include <claim.fs>
+\ Memory "heap" (de-)allocation.
+
+\ Keep a linked list of free blocks per power-of-two size.
+\ Never coalesce entries when freed; split blocks when needed while allocating.
+
+\ 3f CONSTANT (max-heads#)
+heap-end heap-start - log2 1+ CONSTANT (max-heads#)
+
+CREATE heads (max-heads#) cells allot
+heads (max-heads#) cells erase
+
+
+: size>head  ( size -- headptr )  log2 3 max cells heads + ;
+
+
+\ Allocate a memory block
+: alloc-mem  ( len -- a-addr )
+   dup 0= IF EXIT THEN
+   1 over log2 3 max                   ( len 1 log_len )
+   dup (max-heads#) >= IF cr ." Out of internal memory." cr 3drop 0 EXIT THEN
+   lshift >r                           ( len  R: 1<<log_len )
+   size>head dup @ IF
+      dup @ dup >r @ swap ! r> r> drop EXIT
+   THEN                                ( headptr  R: 1<<log_len)
+   r@ 2* recurse dup                   ( headptr a-addr2 a-addr2  R: 1<<log_len)
+   dup 0= IF r> 2drop 2drop 0 EXIT THEN
+   r> + >r 0 over ! swap ! r>
+;
+
+
+\ Free a memory block
+
+: free-mem  ( a-addr len -- )
+   dup 0= IF 2drop EXIT THEN size>head 2dup @ swap ! !
+;
+
+
+: #links  ( a -- n )
+   @ 0 BEGIN over WHILE 1+ swap @ swap REPEAT nip
+;
+
+
+: .free  ( -- )
+   0 (max-heads#) 0 DO
+      heads i cells + #links dup IF
+         cr dup . ." * " 1 i lshift dup . ." = " * dup .
+      THEN
+      +
+   LOOP
+   cr ." Total " .
+;
+
+
+\ Start with just one free block.
+heap-start heap-end heap-start - free-mem
+
+
+\ : free-mem  ( a-addr len -- ) 2drop ;
+
+\ Uncomment the following line for debugging:
+\ #include <alloc-mem-debug.fs>
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/available.fs b/qemu-0.15.x/roms/SLOF/slof/fs/available.fs
new file mode 100644
index 0000000..5eb8fa9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/available.fs
@@ -0,0 +1,72 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+VARIABLE chosen-memory-ih 0 chosen-memory-ih !
+
+\ +
+\ Maintain "available" property.
+\ Sun has a single memory node with "available" property
+\ and separate memory controller nodes.
+\ We corespond memory nodes with their respective memory controllers
+\ and use /chosen/memory as default memory node to hold the "available" map
+\ NOTE -> /chosen/memory is expected 2B initialized before using claim/release
+\ +
+
+: (chosen-memory-ph) ( -- phandle )
+	chosen-memory-ih @ ?dup 0= IF
+		s" memory" get-chosen IF
+			decode-int nip nip dup chosen-memory-ih !
+			ihandle>phandle
+		ELSE 0 THEN
+	ELSE ihandle>phandle THEN
+;
+
+: (set-available-prop) ( prop plen -- )
+	s" available"
+	(chosen-memory-ph) ?dup 0<> IF set-property ELSE
+		cr ." Can't find chosen memory node - "
+		." no available property created" cr
+		2dup 2dup
+	THEN
+;
+
+: update-available-property ( available-ptr -- )
+	dup >r available>size@
+	0= r@ available AVAILABLE-SIZE /available * + >= or IF
+		available r> available - encode-bytes (set-available-prop)
+	ELSE
+		r> /available + RECURSE
+	THEN
+;
+
+: update-available-property available update-available-property ;
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ +
+\ IEEE 1275 implementation:
+\	claim
+\ Claim the region with given start address and size (if align parameter is 0);
+\ alternatively claim any region of given alignment
+\ +
+\ Throw an exception if failed
+\ +
+: claim ( [ addr ] len align -- base ) claim update-available-property ;
+
+\ +
+\ IEEE 1275 implementation:
+\	release
+\ Free the region with given start address and size
+\ +
+: release ( addr len -- ) release update-available-property ;
+
+update-available-property
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/banner.fs b/qemu-0.15.x/roms/SLOF/slof/fs/banner.fs
new file mode 100644
index 0000000..efdba0c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/banner.fs
@@ -0,0 +1,23 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: banner
+   cr ."   Type 'boot'  and press return  to  continue  booting  the system."
+   s" /packages/sms" find-node IF
+      cr ."   Type 'sms-start' and press return to enter the configuration menu."
+   THEN
+   cr ."   Type 'reset-all'  and  press  return  to   reboot   the   system."
+   cr cr
+;
+
+: .banner banner console-clean-fifo ;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/base.fs b/qemu-0.15.x/roms/SLOF/slof/fs/base.fs
new file mode 100644
index 0000000..8452f92
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/base.fs
@@ -0,0 +1,558 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Hash for faster lookup
+#include <find-hash.fs>
+
+: >name ( xt -- nfa ) \ note: still has the "immediate" field!
+   BEGIN char- dup c@ UNTIL ( @lastchar )
+   dup dup aligned - cell+ char- ( @lastchar lenmodcell )
+   dup >r -
+   BEGIN dup c@ r@ <> WHILE
+      cell- r> cell+ >r
+   REPEAT
+   r> drop char-
+;
+
+\ Words missing in *.in files
+VARIABLE mask -1 mask !
+
+VARIABLE huge-tftp-load 1 huge-tftp-load !
+\ Default implementation for sms-get-tftp-blocksize that return 1432 (decimal)
+: sms-get-tftp-blocksize 598 ;
+
+: default-hw-exception s" Exception #" type . ;
+
+' default-hw-exception to hw-exception-handler
+
+: diagnostic-mode? false ;	\ 2B DOTICK'D later in envvar.fs
+
+: memory-test-suite ( addr len -- fail? )
+	diagnostic-mode? IF
+		." Memory test mask value: " mask @ . cr
+		." No memory test suite currently implemented! " cr
+	THEN
+	false
+;
+
+: 0.r  0 swap <# 0 ?DO # LOOP #> type ;
+
+\ count the number of bits equal 1
+\ the idea is to clear in each step the least significant bit
+\ v&(v-1) does exactly this, so count the steps until v == 0
+: cnt-bits  ( 64-bit-value -- #bits=1 )
+	dup IF
+		41 1 DO dup 1- and dup 0= IF drop i LEAVE THEN LOOP
+	THEN
+;
+
+: bcd-to-bin  ( bcd -- bin )
+   dup f and swap 4 rshift a * +
+;
+
+\ calcs the exponent of the highest power of 2 not greater than n
+: 2log ( n -- lb{n} )
+   8 cells 0 DO 1 rshift dup 0= IF drop i LEAVE THEN LOOP
+;
+
+\ calcs the exponent of the lowest power of 2 not less than n
+: log2  ( n -- log2-n )
+   1- 2log 1+
+;
+
+\ Standard compliant $find
+: $find ( str len -- xt true | str len false )
+    2dup $find
+    IF
+	drop nip nip TRUE
+    ELSE
+	FALSE
+    THEN
+;
+
+CREATE $catpad 100 allot
+: $cat ( str1 len1 str2 len2 -- str3 len3 )
+   >r >r dup >r $catpad swap move
+   r> dup $catpad + r> swap r@ move
+   r> + $catpad swap ;
+
+\ WARNING: The following two ($cat-comm & $cat-space) are dirty in a sense
+\ that they add 1 or 2 characters to str1 before executing $cat
+\ The ASSUMPTION is that str1 buffer provides that extra space and it is
+\ responsibility of the code owner to ensure that
+: $cat-comma ( str2 len2 str1 len1 -- "str1, str2" len1+len2+2 )
+	2dup + s" , " rot swap move 2+ 2swap $cat
+;
+
+: $cat-space ( str2 len2 str1 len1 -- "str1 str2" len1+len2+1 )
+	2dup + bl swap c! 1+ 2swap $cat
+;
+: $cathex ( str len val -- str len' )
+   (u.) $cat
+;
+
+
+
+: 2CONSTANT    CREATE , , DOES> 2@ ;
+: $2CONSTANT  $CREATE , , DOES> 2@ ;
+: 2VARIABLE    CREATE 0 , 0 ,  DOES> ;
+
+: (is-user-word) ( name-str name-len xt -- ) -rot $CREATE , DOES> @ execute ;
+
+: zplace ( str len buf -- )  2dup + 0 swap c! swap move ;
+: rzplace ( str len buf -- )  2dup + 0 swap rb! swap rmove ;
+
+: strdup ( str len -- dupstr len ) here over allot swap 2dup 2>r move 2r> ;
+
+: str= ( str1 len1 str2 len2 -- equal? )
+  rot over <> IF 3drop false ELSE comp 0= THEN ;
+
+: #aligned ( adr alignment -- adr' ) negate swap negate and negate ;
+: #join  ( lo hi #bits -- x )  lshift or ;
+: #split ( x #bits -- lo hi )  2dup rshift dup >r swap lshift xor r> ;
+
+: /string ( str len u -- str' len' )
+  >r swap r@ chars + swap r> - ;
+: skip ( str len c -- str' len' )
+  >r BEGIN dup WHILE over c@ r@ = WHILE 1 /string REPEAT THEN r> drop ;
+: scan ( str len c -- str' len' )
+  >r BEGIN dup WHILE over c@ r@ <> WHILE 1 /string REPEAT THEN r> drop ;
+: split ( str len char -- left len right len )
+  >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ;
+\ reverse findchar -- search from the end of the string
+: rfindchar ( str len char -- offs true | false )
+   swap 1 - 0 swap do
+      over i + c@
+      over dup bl = if <= else = then if
+         2drop i dup dup leave
+      then
+   -1 +loop =
+;
+\ reverse split -- split at the last occurence of char
+: rsplit ( str len char -- left len right len )
+  >r 2dup r> rfindchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ;
+
+: left-parse-string ( str len char -- R-str R-len L-str L-len )
+  split 2swap ;
+: replace-char ( str len chout chin -- )
+  >r -rot BEGIN 2dup 4 pick findchar WHILE tuck - -rot + r@ over c! swap REPEAT
+  r> 2drop 2drop
+;
+\ Duplicate string and replace \ with /
+: \-to-/ ( str len -- str' len ) strdup 2dup [char] \ [char] / replace-char ;
+
+: //  dup >r 1- + r> / ; \ division, round up
+
+: c at + ( adr -- c adr' )  dup c@ swap char+ ;
+: 2c@ ( adr -- c1 c2 )  c at + c@ ;
+: 4c@ ( adr -- c1 c2 c3 c4 )  c at + c at + c at + c@ ;
+: 8c@ ( adr -- c1 c2 c3 c4 c5 c6 c7 c8 )  c at + c at + c at + c at + c at + c at + c at + c@ ;
+
+
+: 4dup  ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 )  2over 2over ;
+: 4drop  ( n1 n2 n3 n4 -- )  2drop 2drop ;
+
+\ yes sometimes even something like this is needed
+: 6dup  ( 1 2 3 4 5 6 -- 1 2 3 4 5 6 1 2 3 4 5 6 )
+   5 pick 5 pick 5 pick 5 pick 5 pick 5 pick
+;
+
+\ convert a 32 bit signed into a 64 signed
+\ ( propagate bit 31 to all bits 32:63 )
+: signed ( n1 -- n2 ) dup 80000000 and IF FFFFFFFF00000000 or THEN ;
+
+: <l@ ( addr -- x ) l@ signed ;
+
+: -leading  BEGIN dup WHILE over c@ bl <= WHILE 1 /string REPEAT THEN ;
+: (parse-line)  skipws 0 parse ;
+
+
+\ Append two character to hex byte, if possible
+
+: hex-byte ( char0 char1 -- value true|false )
+   10 digit IF
+      swap 10 digit IF
+	 4 lshift or true EXIT
+      ELSE
+	 2drop 0
+      THEN
+   ELSE
+      drop
+   THEN
+   false EXIT
+;
+
+\ Parse hex string within brackets
+
+: parse-hexstring ( dst-adr -- dst-adr' )
+   [char] ) parse cr                 ( dst-adr str len )
+   bounds ?DO                        ( dst-adr )
+      i c@ i 1+ c@ hex-byte IF       ( dst-adr hex-byte )
+	 >r dup r> swap c! 1+ 2      ( dst-adr+1 2 )
+      ELSE
+	 drop 1                      ( dst-adr 1 )
+      THEN
+   +LOOP
+;
+
+\ Add special character to string
+
+: add-specialchar ( dst-adr special -- dst-adr' )
+   over c! 1+                        ( dst-adr' )
+   1 >in +!                          \ advance input-index
+;
+
+\ Parse upto next "
+
+: parse-" ( dst-adr -- dst-adr' )
+   [char] " parse dup 3 pick + >r    ( dst-adr str len R: dst-adr' )
+   >r swap r> move r>                ( dst-adr' )
+;
+
+: (") ( dst-adr -- dst-adr' )
+   begin                             ( dst-adr )
+      parse-"                        ( dst-adr' )
+      >in @ dup span @ >= IF         ( dst-adr' >in-@ )
+         drop
+         EXIT
+      THEN
+
+      ib + c@
+      CASE
+         [char] ( OF parse-hexstring ENDOF
+         [char] " OF [char] " add-specialchar ENDOF
+         dup      OF EXIT ENDOF
+      ENDCASE
+   again
+;
+
+CREATE "pad 100 allot
+
+\ String with embedded hex strings
+\ Example: " ba"( 12 34,4567)ab" -> >x62x61x12x34x45x67x61x62<
+
+: " ( [text<">< >] -- text-str text-len )
+   state @ IF                        \ compile sliteral, pstr into dict
+      "pad dup (") over -            ( str len )
+      ['] sliteral compile, dup c,   ( str len )
+      bounds ?DO i c@ c, LOOP
+      align ['] count compile,
+   ELSE
+      pocket dup (") over -          \ Interpretation, put string
+   THEN                              \ in temp buffer
+; immediate
+
+\ Remove command old-name and all subsequent definitions
+
+: $forget ( str len -- )
+   2dup last @            ( str len str len last-bc )
+   BEGIN
+      dup >r             ( str len str len last-bc R: last-bc )
+      cell+ char+ count  ( str len str len found-str found-len R: last-bc )
+      string=ci IF       ( str len R: last-bc )
+         r> @ last ! 2drop clean-hash EXIT ( -- )
+      THEN
+      2dup r> @ dup 0=   ( str len str len next-bc next-bc )
+   UNTIL
+   drop 2drop 2drop            \ clean hash table
+;
+
+: forget ( "old-name<>" -- )
+    parse-word $forget
+;
+
+#include <search.fs>
+
+\ The following constants are required in some parts
+\ of the code, mainly instance variables and see. Having to reverse
+\ engineer our own CFAs seems somewhat weird, but we gained a bit speed.
+
+\ Each colon definition is surrounded by colon and semicolon
+\ constant below contain address of their xt
+
+: (function) ;
+defer (defer)
+0 value (value)
+0 constant (constant)
+variable (variable)
+create (create)
+alias (alias) (function)
+cell buffer: (buffer:)
+
+' (function) @        \ ( <colon> )
+' (function) cell + @ \ ( ... <semicolon> )
+' (defer) @           \ ( ... <defer> )
+' (value) @           \ ( ... <value> )
+' (constant) @	      \ ( ... <constant> )
+' (variable) @        \ ( ... <variable> )
+' (create) @          \ ( ... <create> )
+' (alias) @           \ ( ... <alias> )
+' (buffer:) @         \ ( ... <buffer:> )
+
+\ now clean up the test functions
+forget (function)
+
+\ and remember the constants
+constant <buffer:>
+constant <alias>
+constant <create>
+constant <variable>
+constant <constant>
+constant <value>
+constant <defer>
+constant <semicolon>
+constant <colon>
+
+' lit      constant <lit>
+' sliteral constant <sliteral>
+' 0branch  constant <0branch>
+' branch   constant <branch>
+' doloop   constant <doloop>
+' dotick   constant <dotick>
+' doto     constant <doto>
+' do?do    constant <do?do>
+' do+loop  constant <do+loop>
+' do       constant <do>
+' exit     constant <exit>
+' doleave  constant <doleave>
+' do?leave  constant <do?leave>
+
+
+\ provide the memory management words
+\ #include <claim.fs>
+\ #include "memory.fs"
+#include <alloc-mem.fs>
+
+#include <node.fs>
+
+: find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos )
+  \ if substr-len == 0 ?
+  dup 0 = IF
+    \ return 0
+    2drop 2drop 0 exit THEN
+  \ if substr-len <= basestr-len ?
+  dup 3 pick <= IF
+    \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1
+    2 pick over - 1+ 0 DO dup 0 DO
+      \ substr-ptr[i] == basestr-ptr[j+i] ?
+      over i + c@ 4 pick j + i + c@ = IF
+        \ (I+1) == substr-len ?
+        dup i 1+ = IF
+          \ return J
+          2drop 2drop j unloop unloop exit THEN
+      ELSE leave THEN
+    LOOP LOOP
+  THEN
+  \ if there is no match then exit with basestr-len as return value
+  2drop nip
+;
+
+: find-isubstr ( basestr-ptr basestr-len substr-ptr substr-len -- pos )
+  \ if substr-len == 0 ?
+  dup 0 = IF
+    \ return 0
+    2drop 2drop 0 exit THEN
+  \ if substr-len <= basestr-len ?
+  dup 3 pick <= IF
+    \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1
+    2 pick over - 1+ 0 DO dup 0 DO
+      \ substr-ptr[i] == basestr-ptr[j+i] ?
+      over i + c@ lcc 4 pick j + i + c@ lcc = IF
+        \ (I+1) == substr-len ?
+        dup i 1+ = IF
+          \ return J
+          2drop 2drop j unloop unloop exit THEN
+      ELSE leave THEN
+    LOOP LOOP
+  THEN
+  \ if there is no match then exit with basestr-len as return value
+  2drop nip
+;
+
+: find-nextline ( str-ptr str-len -- pos )
+  \ run I from 0 to "str-len"-1 and check str-ptr[i]
+  dup 0 ?DO over i + c@ CASE
+    \ 0x0a (=LF) found ?
+    0a OF
+      \ if current cursor is at end position (I == "str-len"-1) ?
+      dup 1- i = IF
+        \ return I+1
+        2drop i 1+ unloop exit THEN
+        \ if str-ptr[I+1] == 0x0d (=CR) ?
+      over i 1+ + c@ 0d = IF
+        \ return I+2
+        2drop i 2+ ELSE
+        \ else return I+1
+        2drop i 1+ THEN
+      unloop exit
+    ENDOF
+    \ 0x0d (=CR) found ?
+    0d OF
+      \ if current cursor is at end position (I == "str-len"-1) ?
+      dup 1- i = IF
+        \ return I+1
+        2drop i 1+ unloop exit THEN
+      \ str-ptr[I+1] == 0x0a (=LF) ?
+      over i 1+ + c@ 0a = IF
+        \ return I+2
+        2drop i 2+ ELSE
+        \ return I+1
+        2drop i 1+ THEN
+      unloop exit
+    ENDOF
+  ENDCASE LOOP nip
+;
+
+: string-at ( str1-ptr str1-len pos -- str2-ptr str2-len )
+  -rot 2 pick - -rot swap chars + swap
+;
+
+\ appends the string beginning at addr2 to the end of the string
+\ beginning at addr1
+\ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!!
+\ !!!        BEGINNING AT ADDR1 (cp. 'strcat' in 'C' )        !!!
+
+: string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 )
+  \ len1 := len1+len2
+  rot dup >r over + -rot
+  ( addr1 len1+len2 dest-ptr src-ptr len2 )
+  3 pick r> chars + -rot
+  ( ... dest-ptr src-ptr )
+  0 ?DO
+    2dup c@ swap c!
+    char+ swap char+ swap
+  LOOP 2drop
+;
+
+\ appends a character to the end of the string beginning at addr
+\ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!!
+\ !!!        BEGINNING AT ADDR1 (cp. 'strcat' in 'C' )        !!!
+
+: char-cat ( addr len character -- addr len+1 )
+  -rot 2dup >r >r 1+ rot r> r> chars + c!
+;
+
+\ Returns true if source and destination overlap
+: overlap ( src dest size -- true|false )
+	3dup over + within IF 3drop true ELSE rot tuck + within THEN
+;
+
+: parse-2int ( str len -- val.lo val.hi )
+\ ." parse-2int ( " 2dup swap . . ." -- "
+	[char] , split ?dup IF eval ELSE drop 0 THEN
+	-rot ?dup IF eval ELSE drop 0 THEN
+\ 2dup swap . . ." )" cr
+;
+
+\ peek/poke minimal implementation, just to support FCode drivers
+\ Any implmentation with full error detection will be platform specific
+: cpeek ( addr -- false | byte true ) c@ true ;
+: cpoke ( byte addr -- success? ) c! true ;
+: wpeek ( addr -- false | word true ) w@ true ;
+: wpoke ( word addr -- success? ) w! true ;
+: lpeek ( addr -- false | lword true ) l@ true ;
+: lpoke ( lword addr -- success? ) l! true ;
+
+defer reboot ( -- )
+defer halt ( -- )
+defer disable-watchdog ( -- )
+defer reset-watchdog ( -- )
+defer set-watchdog ( +n -- )
+defer set-led ( type instance state -- status )
+defer get-flashside ( -- side )
+defer set-flashside ( side -- status )
+defer read-bootlist ( -- )
+defer furnish-boot-file ( -- adr len )
+defer set-boot-file ( adr len -- )
+defer mfg-mode? ( -- flag )
+defer of-prompt? ( -- flag )
+defer debug-boot? ( -- flag )
+defer bmc-version ( -- adr len )
+defer cursor-on ( -- )
+defer cursor-off ( -- )
+
+: nop-reboot ( -- ) ." reboot not available" abort ;
+: nop-halt ( -- ) ." halt not available" abort ;
+: nop-disable-watchdog ( -- )  ;
+: nop-reset-watchdog ( -- )  ;
+: nop-set-watchdog ( +n -- ) drop ;
+: nop-set-led ( type instance state -- status ) drop drop drop ;
+: nop-get-flashside ( -- side ) ." Cannot get flashside" cr ABORT ;
+: nop-set-flashside ( side -- status ) ." Cannot set flashside" cr ABORT ;
+: nop-read-bootlist ( -- ) ;
+: nop-furnish-bootfile ( -- adr len ) s" net:" ;
+: nop-set-boot-file ( adr len -- ) 2drop ;
+: nop-mfg-mode? ( -- flag ) false ;
+: nop-of-prompt? ( -- flag ) false ;
+: nop-debug-boot? ( -- flag ) false ;
+: nop-bmc-version ( -- adr len ) s" XXXXX" ;
+: nop-cursor-on ( -- ) ;
+: nop-cursor-off ( -- ) ;
+
+' nop-reboot to reboot
+' nop-halt to halt
+' nop-disable-watchdog to disable-watchdog
+' nop-reset-watchdog   to reset-watchdog
+' nop-set-watchdog     to set-watchdog
+' nop-set-led          to set-led
+' nop-get-flashside    to get-flashside
+' nop-set-flashside    to set-flashside
+' nop-read-bootlist    to read-bootlist
+' nop-furnish-bootfile to furnish-boot-file
+' nop-set-boot-file    to set-boot-file
+' nop-mfg-mode?        to mfg-mode?
+' nop-of-prompt?       to of-prompt?
+' nop-debug-boot?      to debug-boot?
+' nop-bmc-version      to bmc-version
+' nop-cursor-on        to cursor-on
+' nop-cursor-off       to cursor-off
+
+: reset-all reboot ;
+
+\ Load base
+10000000 value load-base
+2000000 value flash-load-base
+
+\ provide first level debug support
+#include "debug.fs"
+\ provide 7.5.3.1 Dictionary search
+#include "dictionary.fs"
+\ block data access for IO devices - ought to be implemented in engine
+#include "rmove.fs"
+\ provide a simple run time preprocessor
+#include <preprocessor.fs>
+
+: $dnumber base @ >r decimal $number r> base ! ;
+: (.d) base @ >r decimal (.) r> base ! ;
+
+\ IP address conversion
+
+: (ipaddr) ( "a.b.c.d" -- FALSE | n1 n2 n3 n4 TRUE )
+   base @ >r decimal
+   over s" 000.000.000.000" comp 0= IF 2drop false r> base ! EXIT THEN
+   [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot
+   [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot
+   [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot
+   $number IF false r> base ! EXIT THEN
+   true r> base !
+;
+
+: (ipformat)  ( n1 n2 n3 n4 -- str len )
+   base @ >r decimal
+   0 <# # # # [char] . hold drop # # # [char] . hold
+   drop # # # [char] . hold drop # # #s #>
+   r> base !
+;
+
+: ipformat  ( n1 n2 n3 n4 -- ) (ipformat) type ;
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/boot.fs b/qemu-0.15.x/roms/SLOF/slof/fs/boot.fs
new file mode 100644
index 0000000..9394274
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/boot.fs
@@ -0,0 +1,243 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 VALUE load-size
+0 VALUE go-entry
+VARIABLE state-valid false state-valid !
+CREATE go-args 2 cells allot go-args 2 cells erase
+
+\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
+
+: $bootargs
+   bootargs 2@ ?dup IF
+   ELSE s" diagnostic-mode?" evaluate and IF s" diag-file" evaluate
+   ELSE s" boot-file" evaluate THEN THEN
+;
+
+: $bootdev ( -- device-name len )
+   bootdevice 2@ dup IF s"  " $cat THEN
+   s" diagnostic-mode?" evaluate IF
+      s" diag-device" evaluate
+   ELSE
+      s" boot-device" evaluate
+   THEN
+   $cat \ prepend bootdevice setting from vpd-bootlist
+   strdup
+   ?dup 0= IF
+      disable-watchdog
+      drop true ABORT" No boot device!"
+   THEN
+;
+
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ *
+\ *
+: set-boot-args ( str len -- ) dup IF strdup ELSE nip dup THEN bootargs 2! ;
+
+: (set-boot-device) ( str len -- )
+   ?dup IF 1+ strdup 1- ELSE drop 0 0 THEN bootdevice 2!
+;
+
+' (set-boot-device) to set-boot-device
+
+: (add-boot-device) ( str len -- )	\ Concatenate " str" to "bootdevice"
+   bootdevice 2@ ?dup IF $cat-space ELSE drop THEN set-boot-device
+;
+
+' (add-boot-device) to add-boot-device
+
+0 value claim-list
+
+: no-go ( -- ) -64 boot-exception-handler ABORT ;
+
+defer go ( -- )
+
+: go-32 ( -- )
+   state-valid @ IF
+      0 ciregs >r3 ! 0 ciregs >r4 !
+      go-args 2@ go-entry start-elf client-data
+      claim-list elf-release 0 to claim-list
+   THEN
+   -6d boot-exception-handler ABORT
+;
+: go-64 ( -- )
+   state-valid @ IF
+      0 ciregs >r3 ! 0 ciregs >r4 !
+      go-args 2@ go-entry start-elf64 client-data
+      claim-list elf-release 0 to claim-list
+   THEN
+   -6d boot-exception-handler ABORT
+;
+
+: load-elf-init ( arg len file-addr -- success )
+   false state-valid !                            \ Not valid anymore ...
+   claim-list IF                                    \ Release claimed mem
+      claim-list elf-release 0 to claim-list        \ from last load
+   THEN
+
+   dup ['] elf-check-file CATCH IF
+      ( -64 THROW ) \ Not now, let the 'go' (i.e. no-go) whine about it
+      drop 0
+   THEN
+   CASE
+      1 OF true swap ['] load-elf32-claim CATCH IF
+	    2drop drop -66 THROW
+	 THEN
+	 ['] go-32 ENDOF                            ( arg len true claim-list entry go )
+      2 OF true swap ['] load-elf64-claim CATCH IF
+	    2drop drop -66 THROW
+	 THEN
+	 ['] go-64 ENDOF                            ( arg len true claim-list entry go )
+      dup OF drop ['] no-go to go
+	 2drop false EXIT   ENDOF                   ( false )
+   ENDCASE
+
+   to go to go-entry to claim-list
+   dup state-valid ! -rot
+
+   2 pick IF
+      go-args 2!
+   ELSE
+      2drop
+   THEN
+;
+
+: init-program ( -- )
+   $bootargs LOAD-BASE ['] load-elf-init CATCH ?dup IF
+      boot-exception-handler
+      2drop 2drop false          \ Could not claim
+   ELSE IF
+         0 ciregs 2dup >r3 ! >r4 !  \ Valid (ELF ) Image
+      THEN
+   THEN
+;
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ Generic device load method:
+\ *
+
+: do-load ( devstr len -- img-size )	\ Device method wrapper
+   use-load-watchdog? IF
+      \ Set watchdog timer to 10 minutes, multiply with 2 because DHCP
+      \ needs 1 second per try and add 1 min to avoid race conditions
+      \ with watchdog timeout.
+      4ec set-watchdog
+   THEN
+   my-self >r current-node @ >r         \ Save my-self
+   ." Trying to load: " $bootargs type ."  from: " 2dup type ."  ... "
+   2dup open-dev dup IF
+      dup to my-self
+      dup ihandle>phandle set-node
+      -rot                              ( ihandle devstr len )
+      my-args nip 0= IF
+	 2dup 1- + c@ [char] : <> IF    \ Add : to device path if missing
+	    1+ strdup 2dup 1- + [char] : swap c!
+	 THEN
+      THEN
+      encode-string s" bootpath" set-chosen
+      $bootargs encode-string s" bootargs" set-chosen
+      LOAD-BASE s" load" 3 pick ['] $call-method CATCH IF
+	-67 boot-exception-handler 3drop drop false
+      ELSE
+	 dup 0> IF
+	    init-program
+	 ELSE
+	    false state-valid !
+	    drop 0                                     \ Could not load
+	 THEN
+      THEN
+      swap close-dev device-end dup to load-size
+   ELSE -68 boot-exception-handler 3drop false THEN
+   r> set-node r> to my-self                           \ Restore my-self
+;
+
+: parse-load ( "{devlist}" -- success )	\ Parse-execute boot-device list
+   cr BEGIN parse-word dup WHILE
+	 ( de-alias ) do-load dup 0< IF drop 0 THEN IF
+	    state-valid @ IF ."   Successfully loaded" cr THEN
+	    true 0d parse strdup load-list 2! EXIT
+	 THEN
+   REPEAT 2drop 0 0 load-list 2! false
+;
+
+: load ( "{params}<eol>"} -- success )	\ Client interface to load
+   parse-word 0d parse -leading 2swap ?dup IF
+      de-alias
+      set-boot-device
+   ELSE
+      drop
+   THEN
+   set-boot-args s" parse-load " $bootdev $cat strdup evaluate
+;
+
+: load-next ( -- success )	\ Continue after go failed
+   load-list 2@ ?dup IF s" parse-load " 2swap $cat strdup evaluate
+   ELSE drop false THEN
+;
+
+\ \\\\\\\\\\\\\\\\\\\\\\\\\\
+\ load/go utilities
+\ -> Should be in loaders.fs
+
+: noload false ;
+
+' no-go to go
+
+: (go-and-catch)  ( -- )
+   ['] go behavior CATCH IF -69 boot-exception-handler THEN
+;
+
+
+\ if the board does not get the bootlist from the nvram
+\ then this word is supposed to be overloaded with the
+\ word to get the bootlist from VPD (or from wheresoever)
+read-bootlist
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ IEEE 1275 : load (user interface)
+\ *
+: boot
+   load 0= IF -65 boot-exception-handler EXIT THEN
+   disable-watchdog (go-and-catch)
+   BEGIN load-next WHILE
+      disable-watchdog (go-and-catch)
+   REPEAT
+
+   \ When we return from boot print the banner again.
+   .banner
+;
+
+: load load 0= IF -65 boot-exception-handler THEN ;
+
+\ \\\\ Temporary hacks for backwards compatibility
+: yaboot ." Use 'boot disk' instead " ;
+
+: netboot ( -- rc ) ." Use 'boot net' instead " ;
+
+: netboot-arg ( arg-string -- rc )
+   s" boot net " 2swap $cat (parse-line) $cat
+   evaluate
+;
+
+: netload ( -- rc ) (parse-line)
+   load-base >r FLASH-LOAD-BASE to load-base
+   s" load net:" strdup 2swap $cat strdup evaluate
+   r> to load-base
+   load-size
+;
+
+: neteval ( -- ) FLASH-LOAD-BASE netload evaluate ;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/bootmsg.fs b/qemu-0.15.x/roms/SLOF/slof/fs/bootmsg.fs
new file mode 100644
index 0000000..524d469
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/bootmsg.fs
@@ -0,0 +1,74 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+create debugstr 255 allot
+0 VALUE debuglen
+\ tbl@ d# 1000 * 196e6aa / VALUE TIME1
+\ 0 VALUE TIME2
+
+\ Usage: 42 cp
+: cp ( checkpoint -- )
+  \ cr depth 2 0.r s"  : " type .s cr  \ DEBUG
+  \ cr ." time: " tbl@ d# 1000 * 196e6aa / dup TIME1 - dup . cr TIME2 + TO TIME2 TO TIME1
+  bootmsg-cp ;
+
+: (warning) ( id level ptr len -- )
+  dup TO debuglen
+  debugstr swap move           \ copy into buffer
+  0 debuglen debugstr + c!     \ terminate '\0'
+  debugstr bootmsg-warning
+;
+
+\ Usage: 42 0 warning" warning-txt"
+: warning" ( id level [text<">] -- )
+  postpone s" state @
+  IF
+    ['] (warning) compile,
+  ELSE
+    (warning)
+  THEN
+; immediate
+
+: (debug-cp) ( id level ptr len -- )
+  dup TO debuglen
+  debugstr swap move           \ copy into buffer
+  0 debuglen debugstr + c!     \ terminate '\0'
+  debugstr bootmsg-debugcp
+;
+
+\ Usage: 42 0 debug-cp" debug-cp-txt"
+: debug-cp" ( id level [text<">] -- )
+  postpone s" state @
+  IF
+    ['] (debug-cp) compile,
+  ELSE
+    (debug-cp)
+  THEN
+; immediate
+
+: (error) ( id ptr len -- )
+  dup TO debuglen
+  debugstr swap move           \ copy into buffer
+  0 debuglen debugstr + c!     \ terminate '\0'
+  debugstr bootmsg-error
+;
+
+\ Usage: 42 error" error-txt"
+: error" ( id level [text<">] -- )
+  postpone s" state @
+  IF
+    ['] (error) compile,
+  ELSE
+    (error)
+  THEN
+; immediate
+
+bootmsg-nvupdate
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/claim.fs b/qemu-0.15.x/roms/SLOF/slof/fs/claim.fs
new file mode 100644
index 0000000..5ed7686
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/claim.fs
@@ -0,0 +1,406 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ \\\\\\\\\\\\\\ Constants
+500 CONSTANT AVAILABLE-SIZE
+10000000 CONSTANT MIN-RAM-SIZE \ assumed minimal memory size
+4000 CONSTANT MIN-RAM-RESERVE \ prevent from using first pages
+
+\ \\\\\\\\\\\\\\ Structures
+\ +
+\ The available element size depends strictly on the address/size
+\ value formats and will be different for various device types
+\ +
+STRUCT
+	cell field available>address
+	cell field available>size
+CONSTANT /available
+
+
+\ \\\\\\\\\\\\\\ Global Data
+CREATE available AVAILABLE-SIZE /available * allot available AVAILABLE-SIZE /available * erase
+VARIABLE mem-pre-released 0 mem-pre-released !
+
+\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
+: available>size@	available>size @ ;
+: available>address@	available>address @ ;
+: available>size!	available>size ! ;
+: available>address!	available>address ! ;
+
+: available! ( addr size available-ptr -- )
+	dup -rot available>size! available>address!
+;
+
+: available@ ( available-ptr -- addr size )
+	dup available>address@ swap available>size@
+;
+
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ +
+\ Warning: They are not yet really independent from available formatting
+\ +
+
+\ +
+\ Find position in the "available" where given range exists or can be inserted,
+\ return pointer and logical found/notfound value
+\ If error, return NULL pointer in addition to notfound code
+\ +
+: (?available-segment<) ( start1 end1 start2 end2 -- true/false ) drop < nip ;
+
+: (?available-segment>) ( start1 end1 start2 end2 -- true/false ) -rot 2drop > ;
+
+\ start1 to end1 is the area that should be claimed
+\ start2 to end2 is the available segment
+\ return true if it can not be claimed, false if it can be claimed
+: (?available-segment-#) ( start1 end1 start2 end2 -- true/false )
+	2dup 5 roll -rot                ( e1 s2 e2 s1 s2 e2 )
+	between >r between r> and not
+;
+
+: (find-available) ( addr addr+size-1 a-ptr a-size -- a-ptr' found )
+	?dup 0= IF -rot 2drop false EXIT THEN	\ Not Found
+
+	2dup 2/ dup >r /available * +
+	( addr addr+size-1 a-ptr a-size a-ptr'  R: a-size' )
+	dup available>size@ 0= IF 2drop r> RECURSE EXIT THEN
+
+	( addr addr+size-1 a-ptr a-size a-ptr'  R: a-size' )
+	dup >r available@
+	( addr addr+size-1 a-ptr a-size addr' size'  R: a-size' a-ptr' )
+	over + 1- 2>r 2swap
+	( a-ptr a-size addr addr+size-1 )
+	( R: a-size' a-ptr' addr' addr'+size'-1 )
+
+	2dup 2r@ (?available-segment>) IF
+		2swap 2r> 2drop r>
+		/available + -rot r> - 1- nip RECURSE EXIT	\ Look Right
+	THEN
+	2dup 2r@ (?available-segment<) IF
+		2swap 2r> 2drop r>
+		2drop r> RECURSE EXIT	\ Look Left
+	THEN
+	2dup 2r@ (?available-segment-#) IF	\ Conflict - segments overlap
+		2r> 2r> 3drop 3drop 2drop
+		1212 throw
+	THEN
+	2r> 3drop 3drop r> r> drop	( a-ptr' -- )
+	dup available>size@ 0<>		( a-ptr' found -- )
+;
+
+: (find-available) ( addr size -- seg-ptr found )
+	over + 1- available AVAILABLE-SIZE ['] (find-available) catch IF
+		2drop 2drop 0 false
+	THEN
+;
+
+
+: dump-available ( available-ptr -- )
+	cr
+	dup available - /available / AVAILABLE-SIZE swap - 0 ?DO
+		dup available@ ?dup 0= IF
+			2drop UNLOOP EXIT
+		THEN
+		swap . . cr
+		/available +
+	LOOP
+	dup
+;
+
+: .available available dump-available ;
+
+\ +
+\ release utils:
+\ +
+
+\ +
+\ (drop-available) just blindly compresses space of available map
+\ +
+: (drop-available) ( available-ptr -- )
+	dup available - /available /	\ current element index
+	AVAILABLE-SIZE swap -		\ # of remaining elements
+
+	( first nelements ) 1- 0 ?DO
+		dup /available + dup available@
+
+		( current next next>address next>size ) ?dup 0= IF
+			2drop LEAVE \ NULL element - goto last copy
+		THEN
+		3 roll available!		( next )
+	LOOP
+
+	\ Last element : just zero it out
+	0 0 rot available!
+;
+
+\ +
+\ (stick-to-previous-available) merge the segment on stack
+\ with the previous one, if possible, and modified segment parameters if merged
+\ Return success code
+\ +
+: (stick-to-previous-available) ( addr size available-ptr -- naddr nsize nptr success )
+	dup available = IF
+		false EXIT		\ This was the first available segment
+	THEN
+
+	dup /available - dup available@
+	+ 4 pick = IF
+		nip	\ Drop available-ptr since we are going to previous one
+		rot drop	\ Drop start addr, we take the previous one
+
+		dup available@ 3 roll + rot true
+		( prev-addr prev-size+size prev-ptr true )
+	ELSE
+		drop false
+		( addr size available-ptr false )
+	THEN
+;
+
+\ +
+\ (insert-available) just blindly makes space for another element on given
+\ position
+\ +
+\ insert-available should also check adjacent elements and merge if new
+\ region is contiguos w. others
+\ +
+: (insert-available) ( available-ptr -- available-ptr )
+	dup				\ current element
+	dup available - /available /	\ current element index
+	AVAILABLE-SIZE swap -		\ # of remaining elements
+
+	dup 0<= 3 pick available>size@ 0= or IF
+		\ End of "available" or came to an empty element - Exit
+		drop drop EXIT
+	THEN
+
+	over available@ rot
+
+	( first	first/=current/ first>address first>size nelements ) 1- 0 ?DO
+		2>r
+		( first current R: current>address current>size )
+
+		/available + dup available@
+		( first current+1/=next/ next>address next>size )
+		( R: current>address current>size )
+
+		2r> 4 pick available! dup 0= IF
+			\ NULL element - last copy
+			rot /available + available!
+			UNLOOP EXIT
+		THEN
+	LOOP
+
+	( first next/=last/ last[0]>address last[0]>size ) ?dup 0<> IF
+		cr ." release error: available map overflow"
+		cr ." Dumping available property"
+		.available
+		cr ." No space for one before last entry:" cr swap . .
+		cr ." Dying ..." cr 123 throw
+	THEN
+
+	2drop
+;
+
+: insert-available ( addr size available-ptr -- addr size available-ptr )
+	dup available>address@ 0<> IF
+		\ Not empty :
+		dup available>address@ rot dup -rot -
+
+		( addr available-ptr size available>address at -size )
+
+		3 pick = IF	\ if (available>address@ - size == addr)
+			\ Merge w. next segment - no insert needed
+
+			over available>size@ + swap
+			( addr size+available>size@ available-ptr )
+
+			(stick-to-previous-available) IF
+				\ Merged w. prev & next one : discard extra seg
+				dup /available + (drop-available)
+			THEN
+		ELSE
+			\ shift the rest of "available" to make space
+
+			swap (stick-to-previous-available)
+			not IF (insert-available) THEN
+		THEN
+	ELSE
+		(stick-to-previous-available) drop
+	THEN
+;
+
+defer release
+
+\ +
+\ claim utils:
+\ +
+: drop-available ( addr size available-ptr -- addr )
+	dup >r available@
+	( req_addr req_size segment_addr segment_size	R: available-ptr )
+
+	over 4 pick swap - ?dup 0<> IF
+		\ Segment starts before requested address : free the head space
+		dup 3 roll swap r> available! -
+
+		( req_addr req_size segment_size-segment_addr+req_addr )
+		over - ?dup 0= IF
+			\ That's it - remainder of segment is what we claim
+			drop
+		ELSE
+			\ Both head and tail of segment remain unclaimed :
+			\ need an extra available element
+			swap 2 pick + swap release
+		THEN
+	ELSE
+		nip ( req_addr req_size segment_size )
+		over - ?dup 0= IF
+			\ Exact match : drop the whole available segment
+			drop r> (drop-available)
+		ELSE
+			\ We claimed the head, need to leave the tail available
+			-rot over + rot r> available!
+		THEN
+	THEN
+	( base	R: -- )
+;
+
+: pwr2roundup ( value -- pwr2value )
+	dup CASE
+		0 OF EXIT ENDOF
+		1 OF EXIT ENDOF
+	ENDCASE
+	dup 1 DO drop i dup +LOOP
+	dup +
+;
+
+: (claim-best-fit) ( len align -- len base )
+	pwr2roundup 1- -1 -1
+	( len align-1 best-fit-residue/=-1/ best-fit-base/=-1/ )
+
+	available AVAILABLE-SIZE /available * + available DO
+		i		\ Must be saved now, before we use Return stack
+		-rot >r >r swap >r
+
+		( len i		R: best-fit-base best-fit-residue align-1 )
+
+		available@ ?dup 0= IF drop r> r> r> LEAVE THEN		\ EOL
+
+		2 pick - dup 0< IF
+			2drop			\ Can't Fit: Too Small
+		ELSE
+			dup 2 pick r@ and - 0< IF
+				2drop		\ Can't Fit When Aligned
+			ELSE
+				( len i>address i>size-len )
+				( R: best-fit-base best-fit-residue align-1 )
+				r> -rot dup r@ U< IF
+					\ Best Fit so far: drop the old one
+					2r> 2drop
+
+					( len align-1 nu-base nu-residue   R: )
+					\ Now align new base and push to R:
+					swap 2 pick + 2 pick invert and >r >r >r
+				ELSE
+					2drop >r
+				THEN
+			THEN
+		THEN
+		r> r> r>
+	/available +LOOP
+
+	-rot 2drop	( len best-fit-base/or -1 if none found/ )
+;
+
+: (adjust-release0) ( 0 size -- addr' size' )
+	\ segment 0 already pre-relased in early phase: adjust
+	2dup MIN-RAM-SIZE dup 3 roll + -rot -
+	dup 0< IF 2drop ELSE
+		2swap 2drop 0 mem-pre-released !
+	THEN
+;
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ +
+\ IEEE 1275 implementation:
+\ 	claim
+\ Claim the region with given start address and size (if align parameter is 0);
+\ alternatively claim any region of given alignment
+\ +
+\ Throw an exception if failed
+\ +
+: claim ( [ addr ] len align -- base )
+	?dup 0<> IF
+		(claim-best-fit) dup -1 = IF
+			2drop cr ." claim error : aligned allocation failed" cr
+			." available:" cr .available
+			321 throw EXIT
+		THEN
+		swap
+	THEN
+
+	2dup (find-available) not IF
+		drop
+\ 		cr ." claim error : requested " . ." bytes of memory at " .
+\ 		." not available" cr
+\ 		." available:" cr .available
+		2drop
+		321 throw EXIT
+	THEN
+	( req_addr req_size available-ptr ) drop-available
+
+	( req_addr )
+;
+
+
+\ +
+\ IEEE 1275 implementation:
+\ 	release
+\ Free the region with given start address and size
+\ +
+: .release ( addr len -- )
+	over 0= mem-pre-released @ and IF (adjust-release0) THEN
+
+	2dup (find-available) IF
+		drop swap
+		cr ." release error: region " . ." , " . ." already released" cr
+	ELSE
+		?dup 0= IF
+			swap 
+			cr ." release error: Bad/conflicting region " . ." , " .
+			." or available list full " cr
+		ELSE
+			( addr size available-ptr ) insert-available
+
+			\ NOTE: insert did not change the stack layout
+			\ 	but it may have changed any of the three values
+			\ 	in order to implement merge of free regions
+			\ 	We do not interpret these values any more
+			\ 	just blindly copy it in
+
+			( addr size available-ptr ) available!
+		THEN
+	THEN
+;
+
+' .release to release
+
+
+\ pre-release minimal memory size
+0 MIN-RAM-SIZE release 1 mem-pre-released !
+
+\ claim first pages used for PPC exception vectors
+0 MIN-RAM-RESERVE 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop
+
+\ claim region used by firmware
+E000000 2000000 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/client.fs b/qemu-0.15.x/roms/SLOF/slof/fs/client.fs
new file mode 100644
index 0000000..642d04f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/client.fs
@@ -0,0 +1,208 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Client interface.
+
+\ First, the machinery.
+
+VOCABULARY client-voc \ We store all client-interface callable words here.
+
+6789  CONSTANT  sc-exit
+4711  CONSTANT  sc-yield
+
+VARIABLE  client-callback \ Address of client's callback function
+
+: client-data  ciregs >r3 @ ;
+: nargs  client-data la1+ l@ ;
+: nrets  client-data la1+ la1+ l@ ;
+: client-data-to-stack
+  client-data 3 la+ nargs 0 ?DO dup l@ swap la1+ LOOP drop ;
+: stack-to-client-data
+  client-data nargs nrets + 2 + la+ nrets 0 ?DO tuck l! /l - LOOP drop ;
+
+: call-client ( args len client-entry -- )
+  \ (args, len) describe the argument string, client-entry is the address of
+  \ the client's .entry symbol, i.e. where we eventually branch to.
+  \ ciregs is a variable that describes the register set of the host processor,
+  \ see slof/fs/exception.fs for details
+  \ client-entry-point maps to client_entry_point in slof/entry.S which is
+  \ the SLOF entry point when calling a SLOF client interface word from the
+  \ client.
+  \ We pass the arguments for the client in R6 and R7, the client interface
+  \ entry point address is passed in R5.
+  >r  ciregs >r7 !  ciregs >r6 !  client-entry-point @ ciregs >r5 !
+  \ Initialise client-stack-pointer
+  cistack ciregs >r1 !
+  \ jump-client maps to call_client in slof/entry.S
+  \ When jump-client returns, R3 holds the address of a NUL-terminated string
+  \ that holds the client interface word the client wants to call, R4 holds
+  \ the return address.
+  r> jump-client drop
+  BEGIN
+    client-data-to-stack
+    \ Now create a Forth-style string, look it up in the client dictionary and
+    \ execute it, guarded by CATCH. Result of xt == 0 is stored on the return
+    \ stack
+    client-data l@ zcount
+    \ XXX: Should only look in client-voc...
+    ALSO client-voc $find PREVIOUS
+    dup 0= >r IF 
+      CATCH
+      \ If a client interface word needs some special treatment, like exit and
+      \ yield, then the implementation needs to use THROW to indicate its needs
+      ?dup IF
+        dup CASE
+          sc-exit OF drop r> drop EXIT ENDOF
+          sc-yield OF drop r> drop EXIT ENDOF
+        ENDCASE
+	\ Some special call was made but we don't know that to do with it...
+        THROW
+      THEN
+      stack-to-client-data
+    ELSE
+      cr type ."  NOT FOUND"
+    THEN
+    \ Return to the client
+    r> ciregs >r3 !  ciregs >r4 @ jump-client 
+  UNTIL ;
+
+: flip-stack ( a1 ... an n -- an ... a1 )  ?dup IF 1 ?DO i roll LOOP THEN ;
+
+: (callback) ( "service-name<>" "arguments<cr>" -- )
+  client-callback @  \ client-callback points to the function prolog
+  dup 8 + @ ciregs >r2 !  \ Set up the TOC pointer (???)
+  @ call-client ;  \ Resolve the function's address from the prolog
+' (callback) to callback
+
+: (continue-client)
+  s" "  \ make call-client happy, client won't use the string anyways.
+  ciregs >r4 @ call-client ;
+' (continue-client) to continue-client
+
+\ Utility.
+: string-to-buffer ( str len buf len -- len' )
+  2dup erase rot min dup >r move r> ;
+
+\ Now come the actual client interface words.
+
+ALSO client-voc DEFINITIONS
+
+: exit  sc-exit THROW ;
+
+: yield  sc-yield THROW ;
+
+: test ( zstr -- missing? )
+  \ XXX: Should only look in client-voc...
+  zcount 
+  ALSO client-voc $find PREVIOUS IF nip FALSE ELSE nip nip TRUE THEN 
+  ;
+
+: finddevice ( zstr -- phandle )
+  zcount find-node dup 0= IF drop -1 THEN ;
+
+: getprop ( phandle zstr buf len -- len' )
+  >r >r zcount rot get-property
+  0= IF r> swap dup r> min swap >r move r>
+  ELSE r> r> 2drop -1 THEN ;
+
+: getproplen ( phandle zstr -- len )
+  zcount rot get-property 0= IF nip ELSE -1 THEN ;
+
+: setprop ( phandle zstr buf len -- size|-1 )
+   dup >r            \ save len
+   encode-bytes      ( phandle zstr prop-addr prop-len )
+   2swap zcount rot  ( prop-addr prop-len name-addr name-len phandle )
+   current-node @ >r \ save current node
+   set-node          \ change to specified node
+   property          \ set property
+   r> set-node       \ restore original node
+   r>                \ always return size, because we can not fail.
+;
+
+\ VERY HACKISH
+: canon ( zstr buf len -- len' )
+  over >r move r> zcount nip ;
+
+: nextprop ( phandle zstr buf -- flag ) \ -1 invalid, 0 end, 1 ok
+  >r zcount rot next-property IF r> zplace 1 ELSE r> drop 0 THEN ; 
+
+: open ( zstr -- ihandle )  zcount open-dev ;
+: close ( ihandle -- )  close-dev ;
+
+\ Now implemented: should return -1 if no such method exists in that node
+: write ( ihandle str len -- len' )      rot s" write" rot
+	['] $call-method CATCH IF 2drop 3drop -1 THEN ;
+: read  ( ihandle str len -- len' )      rot s" read"  rot
+	['] $call-method CATCH IF 2drop 3drop -1 THEN ;
+: seek  ( ihandle hi lo -- status  ) swap rot s" seek" rot
+	['] $call-method CATCH IF 2drop 3drop -1 THEN ;
+
+\ A real claim implementation: 3.2% memory fat :-)
+: claim  ( addr len align -- base )
+   dup  IF  rot drop
+      ['] claim CATCH  IF  2drop -1  THEN
+   ELSE
+      ['] claim CATCH  IF  3drop -1  THEN
+   THEN
+;
+
+: release ( addr len -- ) release ;
+
+: instance-to-package ( ihandle -- phandle )
+  ihandle>phandle ;
+
+: package-to-path ( phandle buf len -- len' )
+  2>r node>path 2r> string-to-buffer ;
+: instance-to-path ( ihandle buf len -- len' )
+  2>r instance>path 2r> string-to-buffer ;
+: instance-to-interposed-path ( ihandle buf len -- len' )
+  2>r instance>qpath 2r> string-to-buffer ;
+
+: call-method ( str ihandle arg ... arg -- result return ... return )
+  nargs flip-stack zcount rot ['] $call-method CATCH
+  nrets 0= IF drop ELSE \ if called with 0 return args do not return the catch result
+     dup IF nrets 1 ?DO -444 LOOP THEN
+     nrets flip-stack 
+  THEN ;
+
+\ From the PAPR.
+: test-method ( phandle str -- missing? )
+  zcount rot find-method dup IF nip THEN 0= ;
+
+: milliseconds  milliseconds ;
+
+: start-cpu ( phandle addr r3 -- )
+  >r >r 
+  s" reg" rot get-property 0= IF drop l@ 
+    ELSE true ABORT" start-cpu called with invalid phandle" THEN 
+  r> r> of-start-cpu drop
+;
+
+\ Quiesce firmware and assert that all hardware is in a sane state
+\ (e.g. assert that no background DMA is running anymore)
+: quiesce  ( -- )
+   \ The main quiesce call is defined in quiesce.fs
+   quiesce
+;
+
+\
+\ User Interface, defined in 6.3.2.6
+\
+: interpret ( ... zstr -- result ... )
+  zcount ['] evaluate CATCH ;
+
+\ Allow the client to register a callback
+: set-callback ( newfunc -- oldfunc )
+  client-callback @ swap client-callback ! ;
+
+PREVIOUS DEFINITIONS
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/debug.fs b/qemu-0.15.x/roms/SLOF/slof/fs/debug.fs
new file mode 100644
index 0000000..bfdc9fc
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/debug.fs
@@ -0,0 +1,437 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+false constant <debug-dummy>
+
+12 34 2constant (2constant) ' (2constant) cell+ @
+\ fake device node
+here 0
+dup , dup , dup , dup , dup ,
+over 7 cells + ,
+dup , dup , dup , dup , dup ,
+dup , drop
+current-node ! \ FAKE!
+12 instance value (instancevalue) ' (instancevalue) cell+ @
+instance variable (instancevariable) ' (instancevariable) cell+ @
+instance defer (instancedefer) ' (instancedefer) cell+ @
+0 current-node !
+
+forget <debug-dummy>
+
+constant <instancedefer>
+constant <instancevariable>
+constant <instancevalue>
+constant <2constant>
+
+
+\ Get the name of Forth command whose execution token is xt
+
+: xt>name ( xt -- str len )
+    BEGIN
+	cell - dup c@ 0 2 within IF
+	    dup 2+ swap 1+ c@ exit
+	THEN
+    AGAIN
+;
+
+cell -1 * CONSTANT -cell
+: cell- ( n -- n-cell-size )
+   [ cell -1 * ] LITERAL +
+;
+
+\ Search for xt of given address
+: find-xt-addr ( addr -- xt )
+   BEGIN
+      dup @ <colon> = IF
+	 EXIT
+      THEN
+      cell-
+   AGAIN
+;
+
+: (.immediate) ( xt -- )
+   \ is it immediate?
+   xt>name drop 2 - c@ \ skip len and flags
+   immediate? IF
+     ."  IMMEDIATE"
+   THEN
+;
+
+: (.xt) ( xt -- )
+   xt>name type
+;
+
+\ Trace back on current return stack.
+\ Start at 1, since 0 is return of trace-back itself
+
+: trace-back (  )
+   1
+   BEGIN
+      cr dup dup . ."  : " rpick dup . ."  : "
+      ['] tib here within IF
+	  dup rpick find-xt-addr (.xt)
+      THEN
+      1+ dup rdepth 5 - >= IF cr drop EXIT THEN
+   AGAIN
+;
+
+VARIABLE see-my-type-column
+
+: (see-my-type) ( indent limit xt str len -- indent limit xt )
+   dup see-my-type-column @ + dup 50 >= IF
+      -rot over "  " comp 0= IF
+         \ blank causes overflow: just enforce new line with next call
+         2drop see-my-type-column !
+      ELSE
+         rot drop                      ( indent limit xt str len )
+         2 pick (u.) dup -rot cr type  ( indent limit xt str len xt-len )
+         " :" type 1+                  ( indent limit xt str len prefix-len )
+         5 pick dup spaces +           ( indent limit xt str len prefix-len )
+         over + see-my-type-column !   ( indent limit xt str len )
+         type
+      THEN                          ( indent limit xt )
+   ELSE
+      see-my-type-column ! type     ( indent limit xt )
+   THEN
+;
+
+: (see-my-type-init) ( -- )
+   ffff see-my-type-column !        \ just enforce a new line
+;
+
+: (see-colon-body) ( indent limit xt -- indent limit xt )
+   (see-my-type-init)                              \ enforce new line
+   BEGIN                                           ( indent limit xt )
+      cell+ 2dup <>
+      over @
+      dup <semicolon> <>
+      rot and			                   ( indent limit xt @xt flag )
+   WHILE                                           ( indent limit xt @xt )
+      xt>name (see-my-type) "  " (see-my-type)
+      dup @                                        ( indent limit xt @xt)
+      CASE
+	 <0branch>  OF cell+ dup @
+                    over + cell+ dup >r
+                    (u.) (see-my-type) r>          ( indent limit xt target)
+                    2dup < IF
+                       over 4 pick 3 + -rot recurse
+                       nip nip nip cell-           ( indent limit xt )
+                    ELSE
+                       drop                        ( indent limit xt )
+                    THEN
+                    (see-my-type-init) ENDOF       \ enforce new line
+	 <branch>   OF cell+ dup @ over + cell+ (u.)
+                    (see-my-type) "  " (see-my-type) ENDOF
+	 <do?do>    OF cell+ dup @ (u.) (see-my-type)
+                    "  " (see-my-type) ENDOF
+	 <lit>      OF cell+ dup @ (u.) (see-my-type)
+                    "  " (see-my-type) ENDOF
+	 <dotick>   OF cell+ dup @ xt>name (see-my-type)
+                    "  " (see-my-type) ENDOF
+	 <doloop>   OF cell+ dup @ (u.) (see-my-type)
+                    "  " (see-my-type) ENDOF
+	 <doleave>  OF cell+ dup @ over + cell+ (u.)
+                    (see-my-type) "  " (see-my-type) ENDOF
+	 <do?leave> OF cell+ dup @ over + cell+ (u.)
+                    (see-my-type) "  " (see-my-type) ENDOF
+	 <sliteral> OF cell+ " """ (see-my-type) dup count dup >r
+                    (see-my-type) " """ (see-my-type)
+                    "  " (see-my-type)
+                    r> -cell and + ENDOF
+      ENDCASE
+   REPEAT
+   drop
+;
+
+: (see-colon) ( xt -- )
+   (see-my-type-init)
+   1 swap 0 swap                                    ( indent limit xt )
+   " : " (see-my-type) dup xt>name (see-my-type)
+   rot drop 4 -rot (see-colon-body)                 ( indent limit xt )
+   rot drop 1 -rot (see-my-type-init) " ;" (see-my-type)
+   3drop 
+;
+
+\ Create words are a bit tricky. We find out where their code points.
+\ If this code is part of SLOF, it is not a user generated CREATE.
+
+: (see-create) ( xt -- )
+   dup cell+ @
+   CASE
+      <2constant> OF
+         dup cell+ cell+ dup @ swap cell+ @ . .  ." 2CONSTANT "
+      ENDOF
+
+      <instancevalue> OF
+         dup cell+ cell+ @ . ." INSTANCE VALUE "
+      ENDOF
+
+      <instancevariable> OF
+         ." INSTANCE VARIABLE "
+      ENDOF
+
+      dup OF
+         ." CREATE "
+      ENDOF
+   ENDCASE
+   (.xt)
+;
+
+\ Decompile Forth command whose execution token is xt
+
+: (see) ( xt -- )
+   cr dup dup @
+   CASE
+      <variable> OF ." VARIABLE " (.xt) ENDOF
+      <value>    OF dup execute . ." VALUE " (.xt) ENDOF
+      <constant> OF dup execute . ." CONSTANT " (.xt) ENDOF
+      <defer>    OF dup cell+ @ swap ." DEFER " (.xt) ."  is " (.xt) ENDOF
+      <alias>    OF dup cell+ @ swap ." ALIAS " (.xt) ."  " (.xt) ENDOF
+      <buffer:>  OF ." BUFFER: " (.xt) ENDOF
+      <create>   OF (see-create) ENDOF
+      <colon>    OF (see-colon)  ENDOF
+      dup        OF ." ??? PRIM " (.xt) ENDOF
+   ENDCASE
+   (.immediate) cr
+  ;
+
+\ Decompile Forth command old-name
+
+: see ( "old-name<>" -- )
+   ' (see)
+;
+
+\ Work in progress...
+
+0    value forth-ip
+true value trace>stepping?
+true value trace>print?
+true value trace>up?
+0    value trace>depth
+0    value trace>rdepth
+0    value trace>recurse
+: trace-depth+ ( -- ) trace>depth 1+ to trace>depth ;
+: trace-depth- ( -- ) trace>depth 1- to trace>depth ;
+
+: stepping ( -- )
+    true to trace>stepping?
+;
+
+: tracing ( -- )
+    false to trace>stepping?
+;
+
+: trace-print-on ( -- )
+    true to trace>print?
+;
+
+: trace-print-off ( -- )
+    false to trace>print?
+;
+
+
+\ Add n to ip
+
+: fip-add ( n -- )
+   forth-ip + to forth-ip
+;
+
+\ Save execution token address and content
+
+0 value debug-last-xt
+0 value debug-last-xt-content
+
+: trace-print ( -- )
+   forth-ip cr u. ." : "
+   forth-ip @ 
+   dup ['] breakpoint = IF drop debug-last-xt-content THEN
+   xt>name type ."  "
+   ."     ( " .s  ."  )  | "
+;
+
+: trace-interpret ( -- )
+   rdepth 1- to trace>rdepth
+   BEGIN
+      depth . [char] > dup emit emit space
+      source expect                        ( str len )
+      ['] interpret catch print-status
+   AGAIN
+;
+
+\ Main trace routine, trace a colon definition
+
+: trace-xt ( xt -- )
+    trace>recurse IF
+       r> drop                                \ Drop return of 'trace-xt call
+       cell+                                  \ Step over ":"
+    ELSE
+       debug-last-xt-content <colon> = IF
+          \ debug colon-definition
+          ['] breakpoint @ debug-last-xt !    \ Re-arm break point
+          r> drop                             \ Drop return of 'trace-xt call
+          cell+                               \ Step over ":"
+       ELSE
+          ['] breakpoint debug-last-xt !      \ Re-arm break point
+          2r> 2drop
+       THEN
+    THEN
+
+    to forth-ip
+    true to trace>print?
+    BEGIN
+       trace>print? IF trace-print THEN
+
+       forth-ip                                              ( ip )
+       trace>stepping? IF
+	  BEGIN
+             key
+             CASE
+		[char] d OF dup @ @ <colon> = IF             \ recurse only into colon definitions
+			                         trace-depth+
+                                                 1 to trace>recurse
+                                                 dup >r @ recurse
+		                              THEN true ENDOF
+	        [char] u OF trace>depth IF tracing trace-print-off true ELSE false THEN ENDOF
+	        [char] f OF drop cr trace-interpret ENDOF	\ quit trace and start interpreter FIXME rstack
+	        [char] c OF tracing true ENDOF
+		[char] t OF trace-back false ENDOF
+		[char] q OF drop cr quit ENDOF
+	        20       OF true ENDOF
+		dup      OF cr ." Press d:       Down into current word" cr
+		            ." Press u:       Up to caller" cr
+		            ." Press f:       Switch to forth interpreter, 'resume' will continue tracing" cr
+                            ." Press c:       Switch to tracing" cr
+		            ." Press <space>: Execute current word" cr
+		            ." Press q:       Abort execution, switch to interpreter" cr
+		            false ENDOF
+	     ENDCASE
+	  UNTIL
+       THEN	                                              ( ip' )
+       dup to forth-ip @                                      ( xt )
+       dup ['] breakpoint = IF drop debug-last-xt-content THEN
+       dup                                                    ( xt xt )
+
+       CASE
+	    <sliteral>  OF drop forth-ip cell+ dup dup c@ + -cell and to forth-ip ENDOF
+	    <dotick>    OF drop forth-ip cell+ @ cell fip-add ENDOF
+	    <lit>       OF drop forth-ip cell+ @ cell fip-add ENDOF
+	    <doto>      OF drop forth-ip cell+ @ cell+ ! cell fip-add ENDOF
+	    <0branch>   OF drop IF
+		                    cell fip-add
+		                ELSE
+				    forth-ip cell+ @ cell+ fip-add THEN
+			ENDOF
+            <do?do>     OF drop 2dup <> IF
+				           swap >r >r cell fip-add
+		                        ELSE
+					   forth-ip cell+ @ cell+ fip-add 2drop THEN
+		        ENDOF
+	    <branch>    OF drop forth-ip cell+ @ cell+ fip-add ENDOF
+	    <doleave>   OF drop r> r> 2drop forth-ip cell+ @ cell+ fip-add ENDOF		
+	    <do?leave>  OF drop IF
+		                   r> r> 2drop forth-ip cell+ @ cell+ fip-add
+		                ELSE
+		                   cell fip-add
+		                THEN
+		        ENDOF		
+	    <doloop>    OF drop r> 1+ r> 2dup = IF
+		                                   2drop cell fip-add
+		                                ELSE >r >r
+						    forth-ip cell+ @ cell+ fip-add THEN
+			ENDOF
+	    <do+loop>   OF drop r> + r> 2dup >= IF
+		                                   2drop cell fip-add
+		                                ELSE >r >r
+						    forth-ip cell+ @ cell+ fip-add THEN
+			ENDOF
+
+	    <semicolon> OF trace>depth 0> IF
+		                             trace-depth- 1 to trace>recurse
+                                             stepping drop r> recurse
+		                          ELSE
+		                             drop exit THEN
+			ENDOF
+            <exit>      OF trace>depth 0> IF
+		                             trace-depth- stepping drop r> recurse
+		                          ELSE
+				             drop exit THEN
+			ENDOF
+	    dup         OF execute ENDOF
+	ENDCASE
+	forth-ip cell+ to forth-ip
+    AGAIN
+;
+
+\ Resume execution from tracer
+: resume ( -- )
+    trace>rdepth rdepth!
+    forth-ip cell - trace-xt
+;
+
+\ Turn debug off, by erasing breakpoint
+
+: debug-off ( -- )
+    debug-last-xt IF
+	debug-last-xt-content debug-last-xt !  \ Restore overwriten token
+	0 to debug-last-xt
+    THEN
+;
+
+
+
+\ Entry point for debug
+
+: (break-entry) ( -- )
+   debug-last-xt dup @ ['] breakpoint <> swap  ( debug-addr? debug-last-xt )
+   debug-last-xt-content swap !                \ Restore overwriten token
+   r> drop                                     \ Don't return to bp, but to caller
+   debug-last-xt-content <colon> <> and IF     \ Execute non colon definition
+      debug-last-xt cr u. ." : "
+      debug-last-xt xt>name type ."  "
+      ."     ( " .s  ."  )  | "
+      key drop
+      debug-last-xt execute
+   ELSE
+      debug-last-xt 0 to trace>depth 0 to trace>recurse trace-xt   \ Trace colon definition
+   THEN
+;
+
+\ Put entry point bp defer
+' (break-entry) to BP
+
+\ Mark an address for debugging
+
+: debug-address ( addr --  )
+   debug-off                       ( xt )  \ Remove active breakpoint
+   dup to debug-last-xt            ( xt )  \ Save token for later debug
+   dup @ to debug-last-xt-content  ( xt )  \ Save old value
+   ['] breakpoint swap !
+;
+
+\ Mark the command indicated by xt for debugging
+
+: (debug ( xt --  )
+   debug-off                       ( xt )  \ Remove active breakpoint
+   dup to debug-last-xt            ( xt )  \ Save token for later debug
+   dup @ to debug-last-xt-content  ( xt )  \ Save old value
+   ['] breakpoint @ swap !
+;
+
+\ Mark the command indicated by xt for debugging
+
+: debug ( "old-name<>" -- )
+    parse-word $find IF                       \ Get xt for old-name
+       (debug
+    ELSE
+       ." undefined word " type cr
+    THEN
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_02.fs b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_02.fs
new file mode 100644
index 0000000..ff78496
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_02.fs
@@ -0,0 +1,35 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+s" network [ " type my-space pci-class-name type s"  ]" type
+
+my-space pci-device-generic-setup
+my-space pci-alias-net
+
+s" network" device-type
+
+cr
+
+INSTANCE VARIABLE obp-tftp-package
+: open  ( -- okay? )
+   open IF           \ enables PCI mem, io and Bus master and returns TRUE
+      my-args s" obp-tftp" $open-package obp-tftp-package ! true
+   ELSE
+       false
+   THEN ;
+: close  ( -- )
+    s" close" obp-tftp-package @ $call-method
+    close ;         \ disables PCI mem, io and Bus master
+: load  ( addr -- len )
+    s" load" obp-tftp-package @ $call-method  ;
+
+: ping  ( -- )  s" ping" obp-tftp-package @ $call-method  ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_0c.fs b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_0c.fs
new file mode 100644
index 0000000..53e1e19
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-class_0c.fs
@@ -0,0 +1,39 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+s" serial bus [ " type my-space pci-class-name type s"  ]" type cr
+
+my-space pci-device-generic-setup
+
+
+\ Handle USB OHCI controllers:
+: handle-usb-ohci-class  ( -- )
+   \ set Memory Write and Invalidate Enable, SERR# Enable
+   \ (see PCI 3.0 Spec Chapter 6.2.2 device control):
+   4 config-w@ 110 or 4 config-w!
+   pci-master-enable               \ set PCI Bus master bit and
+   pci-mem-enable                  \ memory space enable for USB scan
+   10 config-l@                    \ get base address on stack for usb-ohci.fs
+                                   \ TODO: Use translate-address here
+   s" usb-ohci.fs" included
+;
+
+\ Check PCI sub-class and interface type of Serial Bus Controller
+\ to include the appropriate driver:
+: handle-sbc-subclass  ( -- )
+   my-space pci-class@ ffff and CASE         \ get PCI sub-class and interface
+      0310 OF handle-usb-ohci-class ENDOF    \ USB OHCI controller
+   ENDCASE
+;
+
+handle-sbc-subclass
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs
new file mode 100644
index 0000000..507c383
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs
@@ -0,0 +1,49 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space pci-class-name type
+
+my-space pci-device-generic-setup
+
+enable-io-access
+enable-mem-access
+
+30 config-l@  pci-find-fcode execute-rom-fcode
+
+: check-display ( nodepath len -- true|false ) \ true if display found and "screen" alias set
+\ check if display availabe, set screen alias
+2dup find-node \ ( path len phandle|0 ) find node
+?dup IF
+   \ node found, get "display-type" property
+   s" display-type" rot get-property ( path len true|propaddr proplen 0 )
+   0= IF
+      ( path len propaddr proplen ) \ property found, check if the value is not "NONE"
+      s" NONE" 0 char-cat ( path len propaddr proplen str strlen ) \ null-terminated NONE string
+      str= 0= IF
+         ( path len ) \ "display-type" property is not "NONE" so we can set "screen" alias
+         s" screen" 2swap set-alias 
+         true ( true ) \  return true
+      ELSE
+         2drop false ( false ) \ return false
+      THEN
+   THEN
+THEN
+;
+
+get-node node>path s" /NVDA,DISPLAY-A" $cat check-display
+0= IF
+   \ no display found on DISPLAY-A ... check DISPLAY-B
+   get-node node>path s" /NVDA,DISPLAY-B" $cat check-display
+   drop \ drop result 
+THEN
+
+s" name" get-my-property drop s"  ( " type type s"  ) " type cr
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/dictionary.fs b/qemu-0.15.x/roms/SLOF/slof/fs/dictionary.fs
new file mode 100644
index 0000000..5d1dae7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/dictionary.fs
@@ -0,0 +1,74 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: words
+   last @
+   BEGIN ?dup WHILE
+     dup cell+ char+ count type space @
+   REPEAT
+;
+
+: .calls    ( xt -- )
+   current-node @ >r 0 set-node    \ only search commands, according too IEEE1275
+
+   last BEGIN @ ?dup WHILE    ( xt currxt )
+      dup cell+ char+         ( xt currxt name* )
+      dup dup c@ + 1+ aligned ( xt currxt name* CFA )
+      dup @ <colon> = IF      ( xt currxt name* CFA )
+         BEGIN
+            cell+ dup @ ['] semicolon <>
+         WHILE		      ( xt currxt *name pos )
+            dup @ 4 pick = IF ( xt currxt *name pos )
+	       over count type space
+	       BEGIN cell+ dup @ ['] semicolon = UNTIL cell - \ eat up other occurences
+            THEN
+         REPEAT
+      THEN
+      2drop ( xt currxt )
+   REPEAT
+   drop
+
+   r> set-node		   \ restore node
+;
+
+0 value #sift-count
+false value sift-compl-only
+
+: $inner-sift ( text-addr text-len LFA -- ... word-addr word-len true | false )
+   dup cell+ char+ count           \ get word name
+   2dup 6 pick 6 pick find-isubstr \ is there a partly match?
+   \ in tab completion mode the substring has to be at the beginning
+   sift-compl-only IF 0= ELSE over < THEN
+   IF
+      #sift-count 1+ to #sift-count \ count completions
+      true
+   ELSE
+      2drop false
+   THEN
+;
+
+: $sift    ( text-addr text-len -- )
+   current-node @ >r 0 set-node	\ only search commands, according too IEEE1275
+   sift-compl-only >r false to sift-compl-only \ all substrings, not only compl.
+   last BEGIN @ ?dup WHILE	\ walk the whole dictionary
+      $inner-sift IF type space THEN
+   REPEAT
+   2drop
+   0 to #sift-count	   \ we don't need completions here.
+   r> to sift-compl-only    \ restore previous sifting mode
+   r> set-node		   \ restore node
+;
+
+: sifting    ( "text< >" -- )
+   parse-word $sift
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/display.fs b/qemu-0.15.x/roms/SLOF/slof/fs/display.fs
new file mode 100644
index 0000000..5bb8797
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/display.fs
@@ -0,0 +1,123 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 VALUE char-height
+0 VALUE char-width
+0 VALUE fontbytes
+
+CREATE display-emit-buffer 20 allot
+
+\ \\\\\\\\\\\\\\ Global Data
+
+\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ *
+\ *
+defer dis-old-emit
+' emit behavior to dis-old-emit
+
+: display-write terminal-write ;
+: display-emit dup dis-old-emit display-emit-buffer tuck c! 1 terminal-write drop ;
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ Generic device methods:
+\ *
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ IEEE 1275 : display device driver initialization
+\ *
+: is-install ( 'open -- )
+	s" defer vendor-open to vendor-open" eval
+	s" : open deadbeef vendor-open dup deadbeef = IF drop true ELSE nip THEN ;" eval
+	s" defer write ' display-write to write" eval
+	s" : draw-logo ['] draw-logo CATCH IF 2drop 2drop THEN ;" eval
+	s" : reset-screen ['] reset-screen CATCH drop ;" eval
+;
+
+: is-remove ( 'close -- )
+	s" defer close to close" eval
+;
+
+: is-selftest ( 'selftest -- )
+	s" defer selftest to selftest" eval
+;
+
+
+STRUCT
+	cell FIELD font>addr
+	cell FIELD font>width
+	cell FIELD font>height
+	cell FIELD font>advance
+	cell FIELD font>min-char
+	cell FIELD font>#glyphs
+CONSTANT /font
+
+CREATE default-font-ctrblk /font allot default-font-ctrblk
+	dup font>addr 0 swap !
+	dup font>width 8 swap !
+	dup font>height -10 swap !
+	dup font>advance 1 swap !
+	dup font>min-char 20 swap !
+	font>#glyphs 7f swap !
+
+: display-default-font ( str len -- )
+   romfs-lookup dup 0= IF drop EXIT THEN
+   600 <> IF ." Only support 60x8x16 fonts ! " drop EXIT THEN
+   default-font-ctrblk font>addr !
+;
+
+s" default-font.bin" display-default-font
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ *
+\ *
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ Generic device methods:
+\ *
+: .scan-lines ( height -- scanlines ) dup 0>= IF 1- ELSE negate THEN ;
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ *
+
+: set-font ( addr width height advance min-char #glyphs -- )
+   default-font-ctrblk /font + /font 0
+   DO
+      1 cells - dup >r ! r> 1 cells
+   +LOOP drop
+   default-font-ctrblk dup font>height @ abs to char-height
+   dup font>width @ to char-width font>advance @ to fontbytes
+;
+
+: >font ( char -- addr )
+   dup default-font-ctrblk dup >r font>min-char @ dup r@ font>#glyphs + within
+   IF
+      r@ font>min-char @ -
+      r@ font>advance @ * r@ font>height @ .scan-lines *
+      r> font>addr @ +
+   ELSE
+      drop r> font>addr @
+   THEN
+;
+
+: default-font ( -- addr width height advance min-char #glyphs )
+    default-font-ctrblk /font 0 DO dup cell+ >r @ r> 1 cells +LOOP drop
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/dump.fs b/qemu-0.15.x/roms/SLOF/slof/fs/dump.fs
new file mode 100644
index 0000000..90d60c4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/dump.fs
@@ -0,0 +1,42 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Hex dump facilities.
+
+1 VALUE /dump
+' c@ VALUE 'dump
+0 VALUE dump-first
+0 VALUE dump-last
+0 VALUE dump-cur
+: .char ( c -- )  dup bl 7f within 0= IF drop [char] . THEN emit ;
+: dump-line ( -- )
+  cr dump-cur dup 8 0.r [char] : emit 10 /dump / 0 DO
+  space dump-cur dump-first dump-last within IF
+  dump-cur 'dump execute /dump 2* 0.r ELSE
+  /dump 2* spaces THEN dump-cur /dump + to dump-cur LOOP
+  /dump 1 <> IF drop EXIT THEN
+  to dump-cur 2 spaces
+  10 0 DO dump-cur dump-first dump-last within IF
+  dump-cur 'dump execute .char ELSE space THEN dump-cur 1+ to dump-cur LOOP ;
+: (dump) ( addr len reader size -- )
+  to /dump to 'dump bounds /dump negate and to dump-first to dump-last
+  dump-first f invert and to dump-cur
+  base @ hex BEGIN dump-line dump-cur dump-last >= UNTIL base ! ;
+: du ( -- )  dump-last 100 'dump /dump (dump) ;
+: dump     ['] c@      1 (dump) ;
+: wdump    ['] w@      2 (dump) ;
+: ldump    ['] l@      4 (dump) ;
+: xdump    ['] x@      8 (dump) ;
+: rdump    ['] rb@     1 (dump) ;
+\ : iodump   ['] io-c@   1 (dump) ;
+\ : siodump  ['] siocfg@ 1 (dump) ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/elf.fs b/qemu-0.15.x/roms/SLOF/slof/fs/elf.fs
new file mode 100644
index 0000000..8f1c7b7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/elf.fs
@@ -0,0 +1,305 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ ELF 32 bit header
+
+STRUCT
+        /l field ehdr>e_ident
+        /c field ehdr>e_class
+        /c field ehdr>e_data
+        /c field ehdr>e_version
+        /c field ehdr>e_pad
+	/l field ehdr>e_ident_2
+	/l field ehdr>e_ident_3
+	/w field ehdr>e_type
+	/w field ehdr>e_machine
+	/l field ehdr>e_version
+	/l field ehdr>e_entry
+	/l field ehdr>e_phoff
+	/l field ehdr>e_shoff
+	/l field ehdr>e_flags
+	/w field ehdr>e_ehsize
+	/w field ehdr>e_phentsize
+	/w field ehdr>e_phnum
+	/w field ehdr>e_shentsize
+	/w field ehdr>e_shnum
+	/w field ehdr>e_shstrndx
+END-STRUCT
+
+
+\ ELF 32 bit program header
+
+STRUCT
+	/l field phdr>p_type
+	/l field phdr>p_offset
+	/l field phdr>p_vaddr
+	/l field phdr>p_paddr
+	/l field phdr>p_filesz
+	/l field phdr>p_memsz
+	/l field phdr>p_flags
+	/l field phdr>p_align
+END-STRUCT
+
+\ Provide word to load image to an offset of vaddr
+0 value elf-segment-offset
+
+: xlate-vaddr32 ( programm-header-addr -- addr )
+    phdr>p_vaddr l@ elf-segment-offset + 
+;
+
+
+\ ELF 64 bit header
+
+STRUCT
+        /l field ehdr64>e_ident
+        /c field ehdr64>e_class
+        /c field ehdr64>e_data
+        /c field ehdr64>e_version
+        /c field ehdr64>e_pad
+	/l field ehdr64>e_ident_2
+	/l field ehdr64>e_ident_3
+	/w field ehdr64>e_type
+	/w field ehdr64>e_machine
+	/l field ehdr64>e_version
+	cell field ehdr64>e_entry
+	cell field ehdr64>e_phoff
+	cell field ehdr64>e_shoff
+	/l field ehdr64>e_flags
+	/w field ehdr64>e_ehsize
+	/w field ehdr64>e_phentsize
+	/w field ehdr64>e_phnum
+	/w field ehdr64>e_shentsize
+	/w field ehdr64>e_shnum
+	/w field ehdr64>e_shstrndx
+END-STRUCT
+
+
+\ ELF 64 bit program header
+
+STRUCT
+        /l field phdr64>p_type
+        /l field phdr64>p_flags
+	cell field phdr64>p_offset
+	cell field phdr64>p_vaddr
+	cell field phdr64>p_paddr
+	cell field phdr64>p_filesz
+	cell field phdr64>p_memsz
+	cell field phdr64>p_align
+END-STRUCT
+
+
+\ Claim memory for segment
+\ Abort, if no memory available
+
+false value elf-claim?
+0     value last-claim
+
+: claim-segment ( file-addr program-header-addr -- )
+    elf-claim? IF
+       >r
+       here last-claim , to last-claim                \ Setup ptr to last claim
+       \ Put addr and size ain the data space
+       r@ phdr>p_vaddr l@ dup , r> phdr>p_memsz l@ dup , ( file-addr addr size )
+       0 ['] claim CATCH IF ABORT" Memory for ELF file already in use " THEN
+    THEN
+    2drop
+;
+
+: claim-segment64 ( file-addr program-header-addr -- )
+    elf-claim? IF
+       >r
+       here last-claim , to last-claim                \ Setup ptr to last claim
+       \ Put addr and size ain the data space
+       r@ phdr64>p_vaddr @ dup , r> phdr64>p_memsz @ dup , ( file-addr addr size )
+       0 ['] claim CATCH IF ABORT" Memory for ELF file already in use " THEN
+    THEN
+    2drop
+;
+
+: load-segment ( file-addr program-header-addr -- )
+  >r
+  ( file-addr  R: program-header-addr )
+  \ Copy into storage
+    r@ phdr>p_offset l@ +  r@ xlate-vaddr32 r@ phdr>p_filesz l@  move
+
+  ( R: programm-header-addr )
+  \ Clear BSS
+    r@ xlate-vaddr32 r@ phdr>p_filesz l@ +
+    r@ phdr>p_memsz l@ r@ phdr>p_filesz l@ - erase
+
+  ( R: programm-header-addr )
+  \ Flush cache
+    r@ xlate-vaddr32 r> phdr>p_memsz l@ dup 0= IF 2drop ELSE flushcache THEN
+;
+
+: load-segments ( file-addr -- )
+  ( file-addr )
+    dup dup ehdr>e_phoff l@ +	  \ Calculate program header address
+
+  ( file-addr program-header-addr )
+    over ehdr>e_phnum w@ 0 ?DO	  \ loop e_phnum times
+
+  ( file-addr program-header-addr )
+      dup phdr>p_type l@ 1 = IF	  \ PT_LOAD ?
+
+  ( file-addr program-header-addr )
+        2dup claim-segment	  \ claim segment
+
+  ( file-addr program-header-addr )
+        2dup load-segment THEN	  \ copy segment
+
+  ( file-addr program-header-addr )
+      over ehdr>e_phentsize w@ + LOOP  \ step to next header
+
+  ( file-addr program-header-addr )
+      over ehdr>e_entry l@
+
+  ( file-addr program-header-addr )
+      nip nip			  \ cleanup
+;
+
+: load-segment64 ( file-addr program-header-addr -- )
+  >r
+  ( file-addr  R: program-header-addr )
+  \ Copy into storage
+    r@ phdr64>p_offset @ +  r@ phdr64>p_vaddr @  r@ phdr64>p_filesz @  move
+
+  ( R: programm-header-addr )
+  \ Clear BSS
+    r@ phdr64>p_vaddr @ r@ phdr64>p_filesz @ +
+    r@ phdr64>p_memsz @ r@ phdr64>p_filesz @ - erase
+
+  ( R: programm-header-addr )
+  \ Flush cache
+    r@ phdr64>p_vaddr @ r> phdr64>p_memsz @ dup 0= IF 2drop ELSE flushcache THEN
+;
+
+: load-segments64 ( file-addr -- entry )
+  ( file-addr )
+    dup dup ehdr64>e_phoff @ +	  \ Calculate program header address
+
+  ( file-addr program-header-addr )
+    over ehdr64>e_phnum w@ 0 ?DO	  \ loop e_phnum times
+
+  ( file-addr program-header-addr )
+      dup phdr64>p_type l@ 1 = IF	  \ PT_LOAD ?
+
+  ( file-addr program-header-addr )
+        2dup claim-segment64	          \ claim segment
+
+  ( file-addr program-header-addr )
+        2dup load-segment64 THEN	  \ copy segment
+
+  ( file-addr program-header-addr )
+      over ehdr64>e_phentsize w@ + LOOP  \ step to next header
+
+  ( file-addr program-header-addr )
+      over ehdr64>e_entry @
+
+  ( file-addr program-header-addr entry )
+      nip nip			  \ cleanup
+;
+
+\ Return type of ELF image, abort if not valid
+\ 1: 32 Bit PPC image
+\ 2: 64 Bit PPC image
+\ 5: 32 Bit SPU image
+
+: elf-check-file ( file-addr --  image-type  )
+  ( file-addr )
+  dup ehdr>e_ident l at -be 7f454c46 <> IF
+     ABORT" Not an ELF executable"
+  THEN
+
+  ( file-addr )
+  dup ehdr>e_data c@
+  ?bigendian IF
+    2 <> ABORT" Not a Big Endian ELF file"
+  ELSE
+    2 = ABORT" Not a Little Endian ELF file"
+  THEN
+
+  ( file-addr )
+  dup ehdr>e_type w@ 2 <> ABORT" Not an ELF executable"
+
+  ( file-addr )
+  dup ehdr>e_machine w@
+  CASE
+      14 OF ehdr>e_class c@ ENDOF       \ PPC 32 bit executable        
+      15 OF ehdr>e_class c@ ENDOF       \ PPC 64 bit executable        
+      17 OF ehdr>e_class c@ 4 or ENDOF  \ SPU 32 bit executable
+      dup OF drop ABORT" Not a PPC / SPU ELF executable" ENDOF 
+  ENDCASE
+;
+
+: load-elf32 ( file-addr -- entry )
+
+  ( file-addr)
+  load-segments
+;
+
+: load-elf32-claim ( file-addr -- claim-list entry )
+    true to elf-claim?
+    0 to last-claim
+    ['] load-elf32 CATCH IF false to elf-claim? ABORT THEN
+    last-claim swap
+    false to elf-claim?
+;
+
+
+: load-elf64 ( file-addr -- entry )
+
+  ( file-addr)
+  load-segments64
+;
+
+: load-elf64-claim ( file-addr -- claim-list entry )
+    true to elf-claim?
+    0 to last-claim
+    ['] load-elf64 CATCH IF false to elf-claim? ABORT THEN
+    last-claim swap
+    false to elf-claim?
+;
+
+: load-elf-file ( file-addr -- entry 32-bit )
+
+   ( file-addr )
+   dup elf-check-file
+
+  ( file-addr 1|2|x )
+
+    CASE
+	1 OF 0 to elf-segment-offset load-elf32 true ENDOF
+	2 OF 0 to elf-segment-offset load-elf64 false ENDOF
+	5 OF load-elf32 true ENDOF
+	dup OF true ABORT" load-elf-file: Not valid image" ENDOF
+    ENDCASE
+;
+
+\ Method to load SPU image 
+
+: elf-spu-load ( ls-start-addr file-addr -- entry )
+    swap to elf-segment-offset
+    load-elf-file drop
+;
+
+\ Release memory claimed before
+
+: elf-release ( claim-list -- )
+   BEGIN
+      dup cell+                   ( claim-list claim-list-addr )
+      dup @ swap cell+ @          ( claim-list claim-list-addr claim-list-sz )
+      release                     ( claim-list )
+      @ dup 0=                    ( Next-element )
+   UNTIL
+   drop
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/envvar.fs b/qemu-0.15.x/roms/SLOF/slof/fs/envvar.fs
new file mode 100644
index 0000000..cdf9226
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/envvar.fs
@@ -0,0 +1,421 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ configuration variables
+
+wordlist CONSTANT envvars
+
+\ list the names in  envvars
+: listenv  ( -- )
+   get-current envvars set-current  words  set-current
+;
+
+\ create a definition in  envvars
+: create-env ( "name" -- )
+   get-current  envvars set-current  CREATE  set-current
+;
+
+\ lay out the data for the separate envvar types
+: env-int     ( n -- )  1 c, align , DOES> char+ aligned @ ;
+: env-bytes   ( a len -- )
+   2 c, align dup , here swap dup allot move
+   DOES> char+ aligned dup @ >r cell+ r>
+;
+: env-string  ( str len -- )  3 c, string, DOES> char+ count ;
+: env-flag    ( f -- )  4 c, c, DOES> char+ c@ 0<> ;
+: env-secmode ( sm -- )  5 c, c, DOES> char+ c@ ;
+
+\ create default envvars
+: default-int     ( n "name" -- )      create-env env-int ;
+: default-bytes   ( a len "name" -- )  create-env env-bytes ;
+: default-string  ( a len "name" -- )  create-env env-string ;
+: default-flag    ( f "name" -- )      create-env env-flag ;
+: default-secmode ( sm "name" -- )     create-env env-secmode ;
+
+: set-option ( option-name len option len -- )
+   2swap encode-string
+   2swap s" /options" find-node dup IF set-property ELSE drop 2drop 2drop THEN
+;
+
+\ find an envvar's current and default value, and its type
+: findenv ( name len -- adr def-adr type | 0 )
+   2dup envvars voc-find dup 0<> IF ( ABORT" not a configuration variable" )
+      link> >body char+ >r (find-order) link> >body dup char+ swap c@ r> swap
+   ELSE
+      nip nip
+   THEN
+;
+
+
+: test-flag ( param len -- true | false )
+   2dup s" true" string=ci -rot s" false" string=ci or
+;
+
+: test-secmode ( param len -- true | false )
+   2dup s" none" string=ci -rot 2dup s" command" string=ci -rot s" full"
+   string=ci or or
+;
+
+: isdigit ( char -- true | false )
+   30 39 between
+;
+
+: test-int ( param len -- true | false )
+  drop c@ isdigit if true else false then ;
+
+: test-string ( param len -- true | false )
+   0 ?DO
+      dup i + c@                     \ Get character / byte at current index
+      dup 20 <  swap 7e >  OR IF     \ Is it out of range 32 to 126 (=ASCII)
+         drop FALSE UNLOOP EXIT      \ FALSE means: No ASCII string
+      THEN
+   LOOP
+   drop TRUE    \ Only ASCII found --> it is a string
+;
+
+: findtype ( param len name len -- param len name len type )
+   2dup findenv dup 0= \ try to find type of envvar
+   IF             \ no type found
+    drop 2swap
+    2dup test-flag if 4 -rot else
+    2dup test-secmode if 5 -rot else
+       2dup test-int if 1 -rot else
+	  2dup test-string IF 3 ELSE 2 THEN  \ 3 = string, 2 = default to bytes
+	  -rot then then then
+    rot
+    >r 2swap r>
+    \ XXX: create env
+  else           \ take type from default value
+    nip nip
+  THEN
+;
+
+\ set an envvar
+: $setenv ( param len name len -- )
+   4dup set-option
+   findtype dup 0=
+   IF
+      true ABORT" not a configuration variable"
+   ELSE
+      -rot $CREATE CASE
+      1 OF evaluate env-int ENDOF \ XXX: wants decimal and 0x...
+      \ Since we don't have 0x for hexnumbers, we need to find out the type ...
+      2 OF
+         2dup                    ( param len param len )
+         depth >r                ( param len param len  R: depth-before )
+         ['] evaluate CATCH IF   \ Catch 'unknown Forth words'...
+            ( param len param' len'  R: depth-before )
+            2drop  r> drop
+            env-string           \ and encode 'unknown word' as string
+         ELSE
+            ( param len [...evaluated results...]  R: depth-before )
+            \ If EVALUATE placed two items on the stack, use env-bytes,
+            \ for one item use env-int:
+            depth r> = IF env-bytes ELSE env-int THEN
+            2drop
+         THEN
+      ENDOF
+      3 OF env-string ENDOF
+      4 OF evaluate env-flag ENDOF
+      5 OF evaluate env-secmode ENDOF \ XXX: recognize none, command, full
+      ENDCASE
+   THEN
+;
+
+\ print an envvar
+: (printenv) ( adr type -- )
+   CASE
+   1 OF aligned @ . ENDOF
+   2 OF aligned dup cell+ swap @ dup IF dump ELSE 2drop THEN ENDOF
+   3 OF count type ENDOF
+   4 OF c@ IF ." true" ELSE ." false" THEN ENDOF
+   5 OF c@ . ENDOF \ XXX: print symbolically
+   ENDCASE
+;
+
+: .printenv-header ( -- )
+   cr
+   s" ---environment variable--------current value-------------default value------"
+   type cr
+;
+
+DEFER old-emit
+0 VALUE emit-counter
+
+: emit-and-count emit-counter 1 + to emit-counter old-emit ;
+
+: .enable-emit-counter
+   0 to emit-counter
+   ['] emit behavior to old-emit
+   ['] emit-and-count to emit
+;
+
+: .disable-emit-counter
+   ['] old-emit behavior to emit
+;
+
+: .spaces
+   dup 0 > IF spaces ELSE
+   drop space THEN
+;
+
+: .print-one-env
+   3 .spaces
+   2dup dup -rot type 1c swap - .spaces
+   findenv rot over
+   .enable-emit-counter
+   (printenv) .disable-emit-counter
+   1a emit-counter - .spaces
+   (printenv)
+;
+
+: .print-all-env
+   .printenv-header
+   envvars cell+ BEGIN @ dup WHILE dup link> >name
+   name>string .print-one-env cr REPEAT drop
+;
+
+: printenv
+   parse-word dup 0= IF
+   2drop .print-all-env ELSE findenv dup 0=
+   ABORT" not a configuration variable"
+   rot over cr ." Current: " (printenv)
+   cr ." Default: " (printenv) THEN
+;
+
+\ set envvar(s) to default value
+: (set-default)  ( def-xt -- )
+   dup >name name>string $CREATE dup >body c@ >r execute r> CASE
+   1 OF env-int ENDOF
+   2 OF env-bytes ENDOF
+   3 OF env-string ENDOF
+   4 OF env-flag ENDOF
+   5 OF env-secmode ENDOF ENDCASE
+;
+
+\ Enviroment variables might be board specific
+
+#include <envvar_defaults.fs>
+
+VARIABLE nvoff \ offset in envvar partition
+
+: (nvupdate-one) ( adr type -- "value" )
+   CASE
+   1 OF aligned @ (.) ENDOF
+   2 OF drop s" 0 0" ENDOF
+   3 OF count ENDOF
+   4 OF c@ IF s" true" ELSE s" false" THEN ENDOF
+   5 OF c@ (.) ENDOF \ XXX: print symbolically
+   ENDCASE
+;
+
+: nvupdate-one   ( def-xt -- )
+   >r nvram-partition-type-common get-nvram-partition       ( part.addr part.len FALSE|TRUE R: def-xt )
+   ABORT" No valid NVRAM." r>      ( part.addr part.len def-xt )
+   >name name>string               ( part.addr part.len var.a var.l )
+   2dup findenv nip (nvupdate-one)
+   ( part.addr part.len var.addr var.len val.addr val.len )
+   internal-add-env
+   drop
+;
+
+: (nvupdate) ( -- )
+   nvram-partition-type-common get-nvram-partition ABORT" No valid NVRAM."
+   erase-nvram-partition drop
+   envvars cell+
+   BEGIN @ dup WHILE dup link> nvupdate-one REPEAT
+   drop
+;
+
+: nvupdate ( -- )
+   ." nvupdate is obsolete." cr
+;
+
+: set-default
+   parse-word envvars voc-find
+   dup 0= ABORT" not a configuration variable" link> (set-default)
+;
+
+: (set-defaults)
+   envvars cell+
+   BEGIN @ dup WHILE dup link> (set-default) REPEAT
+   drop
+;
+
+\ Preset nvram variables in RAM, but do not overwrite them in NVRAM
+(set-defaults)
+
+: set-defaults
+   (set-defaults) (nvupdate)
+;
+
+: setenv  parse-word ( skipws ) 0d parse -leading 2swap $setenv (nvupdate) ;
+
+: get-nv  ( -- )
+   nvram-partition-type-common get-nvram-partition ( addr offset not-found | not-found ) \ find partition header
+   IF
+      ." No NVRAM common partition, re-initializing..." cr
+      internal-reset-nvram
+      (nvupdate)
+      nvram-partition-type-common get-nvram-partition IF ." NVRAM seems to be broken." cr EXIT THEN
+   THEN
+   \ partition header found: read data from nvram
+   drop ( addr )           \ throw away offset
+   BEGIN
+      dup rzcount  dup     \ make string from offset and make condition
+   WHILE                   ( offset offset length )
+      2dup [char] = split  \ Split string at equal sign (=)
+                           ( offset offset length name len param len )
+      2swap                ( offset offset length param len name len )
+      $setenv              \ Set envvar
+      nip                  \ throw away old string begin
+      + 1+                 \ calc new offset
+   REPEAT
+   2drop drop              \ cleanup
+;
+
+get-nv
+
+: check-for-nvramrc  ( -- )
+   use-nvramrc?  IF
+      s" Executing following code from nvramrc: "
+      s" nvramrc" evaluate $cat
+      nvramlog-write-string-cr
+      s" (!) Executing code specified in nvramrc" type
+      cr s"  SLOF Setup = " type
+      \ to remove the string from the console if the nvramrc is broken
+      \ we need to know how many chars are printed
+      .enable-emit-counter
+      s" nvramrc" evaluate ['] evaluate  CATCH  IF
+         \ dropping the rest of the nvram string
+         2drop
+         \ delete the chars we do not want to see
+         emit-counter 0  DO  8 emit  LOOP
+         s" (!) Code in nvramrc triggered exception. "
+         2dup nvramlog-write-string
+         type cr 12 spaces s" Aborting nvramrc execution" 2dup
+         nvramlog-write-string-cr type cr
+         s"  SLOF Setup = " type
+      THEN
+      .disable-emit-counter
+   THEN
+;
+
+
+: (nv-findalias) ( alias-ptr alias-len -- pos )
+   \ create a temporary empty string
+   here 0
+   \ append "devalias " to the temporary string
+   s" devalias " string-cat
+   \ append "<name-str>" to the temporary string
+   3 pick 3 pick string-cat
+   \ append a SPACE character to the temporary string
+   s"  " string-cat
+   \ get nvramrc
+   s" nvramrc" evaluate
+   \ get position of the temporary string inside of nvramrc
+   2swap find-substr
+   nip nip
+;
+
+: (nv-build-real-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len )
+   \ create a temporary empty string
+   2swap here 0
+   \ append "devalias " to the temporary string
+   s" devalias " string-cat
+   \ append "<name-ptr>" to the temporary string
+   2swap string-cat
+   \ append a SPACE character to the temporary string
+   s"  " string-cat
+   \ append "<dev-ptr> to the temporary string
+   2swap string-cat
+   \ append a CR character to the temporary string
+   0d char-cat
+   \ append a LF character to the temporary string
+   0a char-cat
+;
+
+: (nv-build-null-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len )
+   4drop here 0
+;
+
+: (nv-build-nvramrc) ( name-str name-len dev-str dev-len xt-build-entry -- )
+   \ *** PART 1: check if there is still an alias definition available ***
+   ( alias-ptr alias-len path-ptr path-ptr call-build-entry alias-pos )
+   4 pick 4 pick (nv-findalias)
+   \ if our alias definition is a new one
+   dup s" nvramrc" evaluate nip >= IF
+      \ call-build-entry
+      drop execute
+      \ append content of "nvramrc" to the temporary string
+      s" nvramrc" evaluate string-cat
+      \ Allocate the temporary string
+      dup allot
+      \ write the string into nvramrc
+      s" nvramrc" $setenv
+   ELSE  \ if our alias is still defined in nvramrc
+      \ *** PART 2: calculate the memory size for the new content of nvramrc ***
+      \ add number of bytes needed for nvramrc-prefix to number of bytes needed
+      \ for the new entry
+      5 pick 5 pick 5 pick 5 pick 5 pick execute nip over +
+      ( alias-ptr alias-len path-ptr path-ptr build-entry-xt alias-pos tmp-len )
+      \ add number of bytes needed for nvramrc-postfix
+      s" nvramrc" evaluate 3 pick string-at
+      2dup find-nextline string-at nip +
+      \ *** PART 3: build the new content ***
+      \ allocate enough memory for new content
+      alloc-mem 0
+      ( alias-ptr alias-len path-ptr path-ptr build-entry-xt alias-pos mem len )
+      \ add nvramrc-prefix
+      s" nvramrc" evaluate drop 3 pick string-cat
+      \ add new entry
+      rot >r >r >r execute r> r> 2swap string-cat
+      ( mem, len ) ( R: alias-pos )
+      \ add nvramrc-postfix
+      s" nvramrc" evaluate r> string-at
+      2dup find-nextline string-at string-cat
+      ( mem len )
+      \ write the temporary string into nvramrc and clean up memory
+      2dup s" nvramrc" $setenv free-mem
+   THEN
+;
+
+: $nvalias ( name-str name-len dev-str dev-len -- )
+   4dup ['] (nv-build-real-entry) (nv-build-nvramrc)
+   set-alias
+   s" true" s" use-nvramrc?" $setenv
+   (nvupdate)
+;
+
+: nvalias ( "alias-name< >device-specifier<eol>" -- )
+   parse-word parse-word dup 0<> IF
+      $nvalias
+   ELSE
+      2drop 2drop
+      cr
+      "    Usage: nvalias (""alias-name< >device-specifier<eol>"" -- )" type
+      cr
+   THEN    
+;
+
+: $nvunalias ( name-str name-len -- )
+   s" " ['] (nv-build-null-entry) (nv-build-nvramrc)
+   (nvupdate)
+;
+
+: nvunalias ( "alias-name< >" -- )
+   parse-word $nvunalias
+;
+
+: diagnostic-mode? ( -- diag-switch? ) diag-switch? ;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/envvar_defaults.fs b/qemu-0.15.x/roms/SLOF/slof/fs/envvar_defaults.fs
new file mode 100644
index 0000000..21a26e6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/envvar_defaults.fs
@@ -0,0 +1,44 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ the defaults
+\ some of those are platform dependent, and should e.g. be
+\ created from VPD values
+true default-flag auto-boot?
+s" " default-string boot-device
+s" " default-string boot-file
+s" boot" default-string boot-command
+s" " default-string diag-device
+s" " default-string diag-file
+false default-flag diag-switch?
+true default-flag fcode-debug?
+s" " default-string input-device
+s" " default-string nvramrc
+s" " default-string oem-banner
+false default-flag oem-banner?
+0 0 default-bytes oem-logo
+false default-flag oem-logo?
+s" " default-string output-device
+200 default-int screen-#columns
+200 default-int screen-#rows
+0 default-int security-#badlogins
+0 default-secmode security-mode
+s" " default-string security-password
+0 default-int selftest-#megs
+false default-flag use-nvramrc?
+false default-flag direct-serial?
+true default-flag real-mode?
+true default-flag use-axon-ddr?
+#ifdef BIOSEMU
+true default-flag use-biosemu?
+0 default-int biosemu-debug
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/exception.fs b/qemu-0.15.x/roms/SLOF/slof/fs/exception.fs
new file mode 100644
index 0000000..91e39be
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/exception.fs
@@ -0,0 +1,154 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+STRUCT
+   cell FIELD >r0   cell FIELD >r1   cell FIELD >r2   cell FIELD >r3
+   cell FIELD >r4   cell FIELD >r5   cell FIELD >r6   cell FIELD >r7
+   cell FIELD >r8   cell FIELD >r9   cell FIELD >r10  cell FIELD >r11
+   cell FIELD >r12  cell FIELD >r13  cell FIELD >r14  cell FIELD >r15
+   cell FIELD >r16  cell FIELD >r17  cell FIELD >r18  cell FIELD >r19
+   cell FIELD >r20  cell FIELD >r21  cell FIELD >r22  cell FIELD >r23
+   cell FIELD >r24  cell FIELD >r25  cell FIELD >r26  cell FIELD >r27
+   cell FIELD >r28  cell FIELD >r29  cell FIELD >r30  cell FIELD >r31
+   cell FIELD >cr   cell FIELD >xer  cell FIELD >lr   cell FIELD >ctr
+   cell FIELD >srr0 cell FIELD >srr1 cell FIELD >dar  cell FIELD >dsisr
+CONSTANT ciregs-size
+
+
+
+: .16  10 0.r 3 spaces ;
+: .8   8 spaces 8 0.r 3 spaces ;
+: .4regs  cr 4 0 DO dup @ .16 8 cells+ LOOP drop ;
+: .fixed-regs
+   cr ."     R0 .. R7           R8 .. R15         R16 .. R23         R24 .. R31"
+   dup 8 0 DO dup .4regs cell+ LOOP drop
+;
+
+: .special-regs
+   cr ."     CR / XER           LR / CTR          SRR0 / SRR1        DAR / DSISR"
+   cr dup >cr  @ .8   dup >lr  @ .16  dup >srr0 @ .16  dup >dar @ .16
+   cr dup >xer @ .16  dup >ctr @ .16  dup >srr1 @ .16    >dsisr @ .8
+;
+
+: .regs
+   cr .fixed-regs
+   cr .special-regs
+   cr cr
+;
+
+: .hw-exception ( reason-code exception-nr -- )
+   ." ( " dup . ." ) "
+   CASE
+      200 OF ." Machine Check" ENDOF
+      300 OF ." Data Storage" ENDOF
+      380 OF ." Data Segment" ENDOF
+      400 OF ." Intruction Storage" ENDOF
+      480 OF ." Instruction Segment" ENDOF
+      500 OF ." External" ENDOF
+      600 OF ." Alignment" ENDOF
+      700 OF ." Program" ENDOF
+      800 OF ." Floating-point unavailable" ENDOF
+      900 OF ." Decrementer" ENDOF
+      980 OF ." Hypervisor Decrementer" ENDOF
+      C00 OF ." System Call" ENDOF
+      D00 OF ." Trace" ENDOF
+      F00 OF ." Performance Monitor" ENDOF
+      F20 OF ." VMX Unavailable" ENDOF
+      1200 OF ." System Error" ENDOF
+      1600 OF ." Maintenance" ENDOF
+      1800 OF ." Thermal" ENDOF
+      dup OF ." Unknown" ENDOF
+   ENDCASE
+   ."  Exception [ " . ." ]"
+;
+
+: .sw-exception ( exception-nr -- )
+   ."  Exception [ " . ." ] triggered by boot firmware."
+;
+
+\ this word gets also called for non-hardware exceptions.
+: be-hw-exception ( [reason-code] exception-nr -- )
+   cr cr
+   dup 0> IF .hw-exception ELSE .sw-exception THEN
+   cr eregs .regs
+;
+' be-hw-exception to hw-exception-handler
+
+: (boot-exception-handler) ( x1...xn exception-nr -- x1...xn)
+   dup IF
+      dup 0 > IF
+	 negate cp 9 emit ." : " type
+      ELSE
+	 CASE
+	    -6d OF cr ." W3411: Client application returned." cr ENDOF
+	    -6c OF cr ." E3400: It was not possible to boot from any device "
+		." specified in the VPD." cr
+	    ENDOF
+	    -6b OF cr ." E3410: Boot list successfully read from VPD "
+		." but no useful information received." cr
+	    ENDOF
+	    -6a OF cr ." E3420: Boot list could not be read from VPD." cr
+	    ENDOF
+	    -69 OF
+	        cr ." E3406: Client application returned an error"
+		abort"-str @ count dup IF
+		   ." :    " type cr
+		ELSE
+		   ." ." cr
+		   2drop
+		THEN
+	    ENDOF
+	    -68 OF cr ." E3405: No such device" cr ENDOF
+	    -67 OF cr ." E3404: Not a bootable device!" cr ENDOF
+	    -66 OF cr ." E3408: Failed to claim memory for the executable" cr
+	    ENDOF
+	    -65 OF cr ." E3407: Load failed" cr ENDOF
+	    -64 OF cr ." E3403: Bad executable:   " abort"-str @ count type cr
+	    ENDOF
+	    -63 OF cr ." E3409: Unknown FORTH Word" cr ENDOF
+	    -2 OF cr ." E3401: Aborting boot,  " abort"-str @ count type cr
+	    ENDOF
+	    dup OF ." E3402: Aborting boot, internal error" cr ENDOF
+	 ENDCASE
+      THEN
+   ELSE
+      drop
+   THEN
+;
+
+' (boot-exception-handler) to boot-exception-handler
+
+: throw-error ( error-code "error-string" -- )
+   skipws 0a parse rot throw
+;
+
+\ Enable external interrupt in msr
+
+: enable-ext-int ( -- )
+   msr@ 8000 or msr!
+;
+
+\ Disable external interrupt in msr
+
+: disable-ext-int ( -- )
+   msr@ 8000 not and msr!
+;
+
+\ Generate external interrupt thru Internal Interrupt Controller of BE
+
+: gen-ext-int ( -- )
+   7fffffff dec!               \ Reset decrementer
+   enable-ext-int              \ Enable interrupt
+   FF 20000508418 rx!          \ Interrupt priority mask
+   10 20000508410 rx!          \ Interrupt priority
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fbuffer.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fbuffer.fs
new file mode 100644
index 0000000..d19c330
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fbuffer.fs
@@ -0,0 +1,178 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+#include "terminal.fs"
+#include "display.fs"
+
+\ \\\\\\\\\\\\\\ Global Data
+
+0 VALUE frame-buffer-adr
+0 VALUE screen-height
+0 VALUE screen-width
+0 VALUE window-top
+0 VALUE window-left
+
+0 VALUE .sc
+: screen-#rows .sc IF 18 ELSE true to .sc s" screen-#rows" eval false to .sc THEN ;
+: screen-#columns .sc IF 50 ELSE true to .sc s" screen-#columns" eval false to .sc THEN ;
+
+\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
+
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ *
+\ *
+
+: fb8-background inverse-screen? ;
+: fb8-foreground inverse? invert ;
+
+: fb8-lines2bytes ( #lines -- #bytes ) char-height * screen-width * ;
+: fb8-columns2bytes ( #columns -- #bytes ) char-width * ;
+: fb8-line2addr ( line# -- addr )
+	char-height * window-top + screen-width *
+	frame-buffer-adr + window-left +
+;
+
+: fb8-erase-block ( addr len ) fb8-background rfill ;
+
+
+0 VALUE .ab
+CREATE bitmap-buffer 400 allot
+
+: active-bits ( -- new ) .ab dup 8 > IF 8 - to .ab 8 ELSE
+		char-width to .ab ?dup 0= IF recurse THEN
+	THEN ;
+
+: fb8-char2bitmap ( font-height font-addr -- bitmap-buffer )
+	bitmap-buffer >r
+	char-height rot 0> IF r> char-width 2dup fb8-erase-block + >r 1- THEN
+
+	r> -rot char-width to .ab
+	( fb-addr font-addr font-height )
+	fontbytes * bounds ?DO
+		i c@ active-bits 0 ?DO
+			dup 80 and IF fb8-foreground ELSE fb8-background THEN
+			( fb-addr fbyte colr ) 2 pick ! 1 lshift swap 1+ swap
+		LOOP drop
+	LOOP drop
+	bitmap-buffer
+;
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ * IEEE 1275: Frame buffer support routines
+\ *
+
+: fb8-draw-logo ( line# addr width height -- ) ." fb8-draw-logo ( " .s ."  )" cr
+	2drop 2drop
+;
+
+: fb8-toggle-cursor ( -- )
+	line# fb8-line2addr column# fb8-columns2bytes +
+	char-height 0 ?DO
+		char-width 0 ?DO dup dup rb@ -1 xor swap rb! 1+ LOOP
+		screen-width + char-width -
+	LOOP drop
+;
+
+: fb8-draw-character ( char -- )
+    >r default-font over + r@ -rot between IF
+	2swap 3drop r> >font fb8-char2bitmap ( bitmap-buf )
+	line# fb8-line2addr column# fb8-columns2bytes + ( bitmap-buf fb-addr )
+	char-height 0 ?DO
+		2dup char-width mrmove
+		screen-width + >r char-width + r>
+	LOOP 2drop
+    ELSE 2drop r> 3drop THEN
+;
+
+: fb8-insert-lines ( n -- )
+	fb8-lines2bytes >r line# fb8-line2addr dup dup r@ +
+	#lines line# - fb8-lines2bytes r@ - rmove
+	r> fb8-erase-block
+;
+
+: fb8-delete-lines ( n -- )
+	fb8-lines2bytes >r line# fb8-line2addr dup dup r@ + swap
+	#lines fb8-lines2bytes r@ - dup >r rmove
+	r> + r> fb8-erase-block
+;
+
+: fb8-insert-characters ( n -- )
+	line# fb8-line2addr column# fb8-columns2bytes + >r
+	#columns column# - 2dup >= IF
+		nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN
+	ELSE
+		fb8-columns2bytes swap fb8-columns2bytes tuck -
+		over r@ tuck + rot char-height 0 ?DO
+			3dup rmove
+			-rot screen-width tuck + -rot + swap rot
+		LOOP
+		3drop r>
+	THEN
+	char-height 0 ?DO dup 2 pick fb8-erase-block screen-width + LOOP 2drop
+;
+
+: fb8-delete-characters ( n -- )
+	line# fb8-line2addr column# fb8-columns2bytes + >r
+	#columns column# - 2dup >= IF
+		nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN
+	ELSE
+		fb8-columns2bytes swap fb8-columns2bytes tuck -
+		over r@ + 2dup + r> swap >r rot char-height 0 ?DO
+			3dup rmove
+			-rot screen-width tuck + -rot + swap rot
+		LOOP
+		3drop r> over -
+	THEN
+	char-height 0 ?DO dup 2 pick fb8-erase-block screen-width + LOOP 2drop
+;
+
+: fb8-reset-screen ( -- ) ( Left as no-op by design ) ;
+
+: fb8-erase-screen ( -- )
+	frame-buffer-adr screen-height screen-width * fb8-erase-block
+;
+
+: fb8-invert-screen ( -- )
+	frame-buffer-adr screen-height screen-width * 2dup /x / 0 ?DO
+		dup rx@ -1 xor over rx! xa1+
+	LOOP 3drop
+;
+
+: fb8-blink-screen ( -- ) fb8-invert-screen fb8-invert-screen ;
+
+: fb8-install ( width height #columns #lines -- )
+	screen-#rows min to #lines
+	screen-#columns min to #columns
+	dup to screen-height char-height #lines * - 2/ to window-top
+	dup to screen-width char-width #columns * - 2/ to window-left
+	['] fb8-toggle-cursor to toggle-cursor
+	['] fb8-draw-character to draw-character
+	['] fb8-insert-lines to insert-lines
+	['] fb8-delete-lines to delete-lines
+	['] fb8-insert-characters to insert-characters
+	['] fb8-delete-characters to delete-characters
+	['] fb8-erase-screen to erase-screen
+	['] fb8-blink-screen to blink-screen
+	['] fb8-invert-screen to invert-screen
+	['] fb8-reset-screen to reset-screen
+	['] fb8-draw-logo to draw-logo
+;
+
+\ \\\\\\\\\\\\ Debug Stuff \\\\\\\\\\\\\\\\
+
+: fb8-dump-bitmap cr char-height 0 ?do char-width 0 ?do dup c@ if ." @" else ." ." then 1+ loop cr loop drop ;
+
+: fb8-dump-char >font -b swap fb8-char2bitmap fb8-dump-bitmap ;
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fcode/1275.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/1275.fs
new file mode 100644
index 0000000..ace0933
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/1275.fs
@@ -0,0 +1,353 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 value function-type    ' function-type @ constant <value>
+  variable function-type ' function-type @ constant <variable>
+0 constant function-type ' function-type @ constant <constant>
+: function-type ;        ' function-type @ constant <colon>
+create function-type     ' function-type @ constant <create>
+defer function-type      ' function-type @ constant <defer>
+
+\ variable tmp-buf-current
+\ variable orig-here
+\ create tmp-buf 10000 allot
+
+( ---------------------------------------------------- )
+
+: fcode-revision ( -- n )
+  00030000 \ major * 65536 + minor
+  ;
+
+: b(lit) ( -- n )
+  next-ip read-fcode-num32
+  ?compile-mode IF literal, THEN
+  ;
+
+: b(")
+  next-ip read-fcode-string
+  ?compile-mode IF fc-string, align postpone count THEN
+  ;
+
+: b(')
+  next-ip read-fcode# get-token drop ?compile-mode IF literal, THEN
+  ;
+
+: ?jump-direction ( n -- )
+  dup 8000 >= IF FFFF swap - negate 2- THEN
+  ;
+
+: ?negative
+  8000 and
+  ;
+
+: dest-on-top
+  0 >r BEGIN dup @ 0= WHILE >r REPEAT
+       BEGIN r> dup WHILE swap REPEAT 
+  drop
+  ;
+
+: ?branch
+  true =
+  ;
+
+: read-fcode-offset \ ELSE needs to be fixed!
+  ?offset16 IF next-ip read-fcode-num16 ELSE THEN
+  ;
+
+: b?branch ( flag -- )
+  ?compile-mode IF  
+                    read-fcode-offset ?negative IF   dest-on-top postpone until
+                                                ELSE postpone if
+												THEN
+                ELSE
+					?branch IF   2 jump-n-ip
+							ELSE read-fcode-offset
+								 ?jump-direction 2- jump-n-ip
+							THEN
+                THEN
+  ; immediate
+
+: bbranch ( -- )
+  ?compile-mode IF 
+                     read-fcode-offset
+					 ?negative IF   dest-on-top postpone again
+							   ELSE postpone else
+                     get-ip next-ip fcode@ B2 = IF drop ELSE set-ip THEN
+							   THEN
+				ELSE  
+                     read-fcode-offset ?jump-direction 2- jump-n-ip
+                THEN
+  ; immediate
+
+: b(<mark) ( -- )
+  ?compile-mode IF postpone begin THEN
+  ; immediate
+
+: b(>resolve) ( -- )
+  ?compile-mode IF postpone then THEN
+  ; immediate
+
+: ffwto; ( -- )
+	BEGIN fcode@ dup c2 <> WHILE
+." ffwto: skipping " dup . ." @ " get-ip . cr
+		CASE	10 OF ( lit ) read-fcode-num32 drop ENDOF
+			11 OF ( ' ) read-fcode# drop ENDOF
+			12 OF ( " ) read-fcode-string 2drop ENDOF
+			13 OF ( bbranch ) read-fcode-offset drop ENDOF
+			14 OF ( b?branch ) read-fcode-offset drop ENDOF
+			15 OF ( loop ) read-fcode-offset drop ENDOF
+			16 OF ( +loop ) read-fcode-offset drop ENDOF
+			17 OF ( do ) read-fcode-offset drop ENDOF
+			18 OF ( ?do ) read-fcode-offset drop ENDOF
+			1C OF ( of ) read-fcode-offset drop ENDOF
+			C6 OF ( endof ) read-fcode-offset drop ENDOF
+			C3 OF ( to ) read-fcode# drop ENDOF
+			dup OF next-ip ENDOF
+		ENDCASE
+	REPEAT next-ip
+;
+
+: rpush ( rparm -- ) \ push the rparm to be on top of return stack after exit
+	r> swap >r >r
+;
+
+: rpop ( -- rparm ) \ pop the rparm that was on top of return stack before this
+	r> r> swap >r
+;
+
+: b1(;) ( -- )
+." b1(;)" cr
+  rpop set-ip 
+;
+
+\ : b1(:) ( -- )
+\ ." b1(:)" cr
+\ <colon> compile, get-ip 1+ literal ] get-ip rpush set-ip [
+\ ffwto;
+\   ; immediate
+
+: b(;) ( -- )
+  postpone exit reveal postpone [ 
+  ; immediate
+
+: b(:) ( -- )
+  <colon> compile, ]
+  ; immediate
+
+: b(case) ( sel -- sel )
+  postpone case
+  ; immediate
+
+: b(endcase)
+  postpone endcase
+  ; immediate
+
+: b(of)
+  postpone of
+  read-fcode-offset drop   \ read and discard offset
+  ; immediate
+
+: b(endof)
+  postpone endof
+  read-fcode-offset drop   
+  ; immediate
+
+: b(do)
+  postpone do
+  read-fcode-offset drop   
+  ; immediate
+
+: b(?do)
+  postpone ?do
+  read-fcode-offset drop   
+  ; immediate
+
+: b(loop)
+  postpone loop
+  read-fcode-offset drop   
+  ; immediate
+
+: b(+loop)
+  postpone +loop
+  read-fcode-offset drop   
+  ; immediate
+
+: b(leave)
+  postpone leave
+  ; immediate
+
+: new-token  \ unnamed local fcode function
+  align here next-ip read-fcode# 0 swap set-token
+  ;
+
+: external-token ( -- )  \ named local fcode function 
+  next-ip read-fcode-string
+  header         ( str len -- )  \ create a header in the current dictionary entry
+  new-token
+  ;
+
+: new-token
+	eva-debug? IF
+		s" x" get-ip >r next-ip read-fcode# r> set-ip (u.) $cat strdup
+		header
+	THEN new-token
+;
+
+: named-token  \ decide wether or not to give a new token an own name in the dictionary
+  fcode-debug? IF new-token ELSE external-token THEN
+  ;
+
+: b(to) ( x -- )
+  next-ip read-fcode#
+  get-token drop
+  >body cell -
+  ?compile-mode IF literal, postpone !  ELSE !  THEN
+  ; immediate
+
+: b(value)
+  <value> , , reveal
+  ;
+
+: b(variable)
+  <variable> , 0 , reveal
+  ;
+
+: b(constant)
+  <constant> , , reveal
+  ;
+
+: undefined-defer
+  cr cr ." Unititialized defer word has been executed!" cr cr 
+  true fcode-end !
+  ;
+
+: b(defer)
+  <defer> , reveal
+  postpone undefined-defer
+  ;
+
+: b(create)
+  <variable> , 
+  postpone noop reveal
+  ;
+
+: b(field) ( E: addr -- addr+offset ) ( F: offset size -- offset+size )
+  <colon> , over literal,
+  postpone + postpone exit
+  +
+  ;
+
+: b(buffer:) ( E: -- a-addr) ( F: size -- )
+  <variable> , allot
+  ;
+
+: suspend-fcode ( -- )
+  noop        \ has to be implemented more efficiently ;-)
+  ;
+
+: offset16 ( -- )
+  16 to fcode-offset
+  ;
+
+: version1 ( -- )
+  1 to fcode-spread
+  8 to fcode-offset
+  read-header
+  ;
+
+: start0 ( -- )
+  0 to fcode-spread
+  offset16
+  read-header
+  ;
+  
+: start1 ( -- )
+  1 to fcode-spread
+  offset16
+  read-header
+  ;
+    
+: start2 ( -- )
+  2 to fcode-spread
+  offset16
+  read-header
+  ;
+
+: start4 ( -- )
+  4 to fcode-spread
+  offset16
+  read-header
+  ;
+
+: end0 ( -- ) 
+  true fcode-end ! 
+  ;
+
+: end1 ( -- ) 
+  end0 
+  ;
+
+: ferror ( -- )
+  clear end0
+  cr ." FCode# " fcode-num @ . ." not assigned!"
+  cr ." FCode evaluation aborted." cr
+  ." ( -- S:" depth . ." R:" rdepth . ." ) " .s cr
+  abort
+  ;
+
+: reset-local-fcodes
+  FFF 800 DO ['] ferror 0 i set-token LOOP
+  ;
+
+: byte-load ( addr xt -- )
+  >r >r 
+  save-evaluator-state
+  r> r>
+  reset-fcode-end
+  1 to fcode-spread
+  dup 1 = IF drop ['] rb@ THEN to fcode-rb@
+  set-ip
+  reset-local-fcodes
+  depth >r
+  evaluate-fcode
+  r> depth 1- <> IF   clear end0 
+                      cr ." Ambiguous stack depth after byte-load!"
+                      cr ." FCode evaluation aborted." cr cr
+				 ELSE restore-evaluator-state 
+				 THEN
+  ['] c@ to fcode-rb@                
+  ;
+
+create byte-load-test-fcode
+f1 c, 08 c, 18 c, 69 c, 00 c, 00 c, 00 c, 68 c,
+12 c, 16 c, 62 c, 79 c, 74 c, 65 c, 2d c, 6c c, 
+6f c, 61 c, 64 c, 2d c, 74 c, 65 c, 73 c, 74 c, 
+2d c, 66 c, 63 c, 6f c, 64 c, 65 c, 21 c, 21 c, 
+90 c, 92 c, ( a6 c, a7 c, 2e c, ) 00 c,
+
+: byte-load-test
+  byte-load-test-fcode ['] w@
+  ; immediate
+
+: fcode-ms
+    s" ms" $find IF 0= IF compile, ELSE execute THEN THEN ; immediate
+
+: fcode-$find
+  $find
+  IF
+    drop true
+  ELSE
+    false
+  THEN    
+  ;
+
+( ---------------------------------------------------- )
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fcode/big.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/big.fs
new file mode 100644
index 0000000..00eb570
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/big.fs
@@ -0,0 +1,45 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ big-endian
+
+( ---------------------------------------------------- )
+
+: read-fcode-num16 ( -- n )
+  0 fcode-num !
+  ?arch64 IF
+                       read-byte fcode-num 6 + C!
+               next-ip read-byte fcode-num 7 + C!
+          ELSE
+                       read-byte fcode-num 2 + C!
+               next-ip read-byte fcode-num 3 + C!
+		  THEN
+  fcode-num @
+  ;
+
+: read-fcode-num32 ( -- n )
+  0 fcode-num !
+  ?arch64 IF
+					  read-byte fcode-num 4 + C!
+			  next-ip read-byte fcode-num 5 + C!
+			  next-ip read-byte fcode-num 6 + C!
+			  next-ip read-byte fcode-num 7 + C!
+          ELSE
+					  read-byte fcode-num 0 + C!
+			  next-ip read-byte fcode-num 1 + C!
+			  next-ip read-byte fcode-num 2 + C!
+			  next-ip read-byte fcode-num 3 + C!
+		  THEN
+  fcode-num @
+  ;
+
+( ---------------------------------------------------- )
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fcode/core.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/core.fs
new file mode 100644
index 0000000..79d47c3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/core.fs
@@ -0,0 +1,169 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: ?offset16 ( -- true|false )
+  fcode-offset 16 =
+  ;
+
+: ?arch64 ( -- true|false )
+  cell 8 =
+  ;
+
+: ?bigendian ( -- true|false )
+  deadbeef fcode-num !
+  fcode-num ?arch64 IF 4 + THEN 
+  c@ de =
+  ;
+
+: reset-fcode-end ( -- )
+  false fcode-end !
+  ;
+
+: get-ip ( -- n )
+  ip @
+  ;
+
+: set-ip ( n -- )
+  ip !
+  ;
+
+: next-ip ( -- )
+  get-ip 1+ set-ip
+  ;
+
+: jump-n-ip ( n -- )
+  get-ip + set-ip
+  ;
+
+: read-byte ( -- n )
+  get-ip fcode-rb@
+  ;
+
+: ?compile-mode ( -- on|off )
+  state @
+  ;
+
+: save-evaluator-state
+  get-ip               eva-debug? IF ." saved ip "           dup . cr THEN
+  fcode-end @          eva-debug? IF ." saved fcode-end "    dup . cr THEN
+  fcode-offset         eva-debug? IF ." saved fcode-offset " dup . cr THEN
+\ local fcodes are currently NOT saved!
+  fcode-spread         eva-debug? IF ." saved fcode-spread " dup . cr THEN  
+  ['] fcode@ behavior  eva-debug? IF ." saved fcode@ "       dup . cr THEN
+  ;
+
+: restore-evaluator-state
+  eva-debug? IF ." restored fcode@ "       dup . cr THEN  to fcode@            
+  eva-debug? IF ." restored fcode-spread " dup . cr THEN  to fcode-spread
+\ local fcodes are currently NOT restored!
+  eva-debug? IF ." restored fcode-offset " dup . cr THEN  to fcode-offset
+  eva-debug? IF ." restored fcode-end "    dup . cr THEN  fcode-end !
+  eva-debug? IF ." restored ip "           dup . cr THEN  set-ip
+  ;
+
+: token-table-index ( fcode# -- addr )
+  cells token-table +
+  ;
+
+: join-immediate ( xt immediate? addr -- xt+immediate? addr )
+  -rot + swap
+  ;
+
+: split-immediate ( xt+immediate? -- xt immediate? )
+  dup 1 and 2dup - rot drop swap
+  ;
+
+: literal, ( n -- )
+  postpone literal
+  ;
+
+: fc-string,
+  postpone sliteral
+  dup c, bounds ?do i c@ c, loop
+  ;
+
+: set-token ( xt immediate? fcode# -- )
+  token-table-index join-immediate !
+  ;
+
+: get-token ( fcode# -- xt immediate? )
+  token-table-index @ split-immediate
+  ;
+
+-1 VALUE break-fcode-addr 
+  
+: exec ( FCode# -- )
+    
+   eva-debug? IF
+      dup
+      get-ip 8 u.r ." : "
+      ." [" 3 u.r ." ] "
+   THEN
+   get-ip break-fcode-addr = IF
+	TRUE fcode-end ! drop EXIT
+   THEN
+   
+   get-token 0= IF  \ imm == 0 == false
+      ?compile-mode IF
+	  compile,
+      ELSE
+	  eva-debug? IF dup xt>name type space THEN	  
+	  execute
+      THEN
+  ELSE \ immediate
+      eva-debug? IF dup xt>name type space THEN
+      execute
+  THEN
+  eva-debug? IF .s cr THEN
+  ;
+
+( ---------------------------------------------------- )
+
+0 ?bigendian INCLUDE? big.fs
+0 ?bigendian NOT INCLUDE? little.fs
+
+( ---------------------------------------------------- )
+
+: read-fcode# ( -- FCode# )
+  read-byte
+  dup 01 0F between IF drop read-fcode-num16 THEN
+  ;
+
+: read-header ( adr -- )
+  next-ip read-byte        drop
+  next-ip read-fcode-num16 drop 
+  next-ip read-fcode-num32 drop 
+  ;
+
+: read-fcode-string ( -- str len )
+  read-byte            \ get string length ( -- len )
+  next-ip get-ip       \ get string addr   ( -- len str )
+  swap                 \ type needs the parameters swapped ( -- str len )
+  dup 1- jump-n-ip     \ jump to the end of the string in FCode
+  ;
+
+: evaluate-fcode ( -- )
+  fcode@ exec              \ read start code
+  BEGIN
+       next-ip fcode@ exec
+       fcode-end @
+  UNTIL
+  ;
+
+: step-fcode ( -- )
+  break-fcode-addr >r -1 to break-fcode-addr      
+  fcode@ exec next-ip
+  r> to break-fcode-addr   
+;    
+    
+  
+( ---------------------------------------------------- )
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fcode/evaluator.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/evaluator.fs
new file mode 100644
index 0000000..1434098
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/evaluator.fs
@@ -0,0 +1,99 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+( eva - gordons fcode bytecode evaluator )
+
+hex
+
+-1 constant true
+ 0 constant false
+
+variable ip
+variable fcode-end 
+variable fcode-num
+ 1 value fcode-spread
+16 value fcode-offset
+false value eva-debug?
+false value fcode-debug?
+defer fcode-rb@
+defer fcode@
+
+' c@ to fcode-rb@
+
+create token-table 2000 cells allot    \ 1000h = 4096d
+
+include core.fs
+include 1275.fs
+include tokens.fs
+
+0 value buff
+0 value buff-size
+
+( ---------------------------------------------------- )
+
+' read-fcode# to fcode@
+
+: step next-ip fcode@ exec ; immediate
+( ---------------------------------------------------- )
+
+: rom-code-ignored ( image# name len -- )
+    diagnostic-mode? IF type ."  code found in image " .  ." , ignoring ..." cr
+    ELSE 3drop THEN
+;
+
+: pci-find-rom ( baseaddr -- addr )
+    -8 and dup IF
+	dup rw@ 55aa = IF
+		diagnostic-mode? IF ." Device ROM found at " dup . cr THEN
+	ELSE drop 0 THEN
+    THEN
+;
+
+: pci-find-fcode ( baseaddr -- addr len | false )
+    pci-find-rom ?dup IF
+	dup 18 + rw@ wbflip +
+	0 swap BEGIN
+	    dup rl@ 50434952 ( 'PCIR') <> IF
+		diagnostic-mode? IF
+			." Invalid PCI Data structure, ignoring ROM contents" cr
+		THEN
+		2drop false EXIT
+	    THEN
+	    dup 14 + rb@ CASE
+		0 OF over . s" Intel x86 BIOS" rom-code-ignored ENDOF
+		1 OF swap diagnostic-mode? IF
+				." Open Firmware FCode found at image " . cr
+			ELSE drop THEN
+			dup a + rw@ wbflip over + \ This code start
+			swap 10 + rw@ wbflip 200 * \ This code length
+			EXIT
+		ENDOF
+		2 OF over . s" HP PA RISC" rom-code-ignored ENDOF
+		3 OF over . s" EFI" rom-code-ignored ENDOF
+		dup OF over . s" Unknown type" rom-code-ignored ENDOF
+	    ENDCASE
+	    dup 15 + rb@ 80 and IF 2drop EXIT THEN \ End of last image
+	    dup 10 + rw@ wbflip 200 * + \ Next image start
+	    swap 1+ swap \ Next image #
+	0 UNTIL
+    THEN false
+;
+
+: execute-rom-fcode ( addr len | false -- )
+	?dup IF
+		diagnostic-mode? IF ." , executing ..." cr THEN
+		dup >r r@ alloc-mem dup >r swap rmove
+		r@ set-ip evaluate-fcode
+		diagnostic-mode? IF ." Done." cr THEN
+		r> r> free-mem
+	THEN
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/fcode/tokens.fs b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/tokens.fs
new file mode 100644
index 0000000..ad6c52b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/fcode/tokens.fs
@@ -0,0 +1,411 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: fc-abort ." FCode called abort: IP " get-ip . ( ." STACK: " .s ) depth dup 0< IF abort THEN . rdepth . cr  abort ;
+: fc-0 ." 0(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 0 ;
+: fc-1 ." 1(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 1 ;
+
+: parse-1hex 1 hex-decode-unit ;
+
+
+: reset-token-table
+  FFF 0 DO ['] ferror 0 i set-token LOOP
+  ;
+
+reset-token-table
+
+' end0 0        00 set-token
+
+\ 01...0F beginning code of 2-byte FCode sequences
+
+\ ' ferror      1 08 set-token
+\ ' ferror      1 09 set-token
+\ ' ferror      1 0a set-token
+\ ' ferror      1 0b set-token
+\ ' ferror      1 0c set-token
+\ ' ferror      1 0d set-token
+\ ' ferror      1 0e set-token
+\ ' ferror      1 0f set-token
+
+' b(lit)      1 10 set-token
+
+' b(')        1 11 set-token
+' b(")        1 12 set-token
+' bbranch     1 13 set-token
+' b?branch    1 14 set-token
+' b(loop)     1 15 set-token
+' b(+loop)    1 16 set-token
+' b(do)       1 17 set-token
+' b(?do)      1 18 set-token
+' i           0 19 set-token
+' j           0 1A set-token
+' b(leave)    1 1B set-token
+' b(of)       1 1C set-token
+' execute     0 1D set-token
+' +           0 1E set-token
+' -           0 1F set-token
+' *           0 20 set-token
+' /           0 21 set-token
+' mod         0 22 set-token 
+' and         0 23 set-token 
+' or          0 24 set-token 
+' xor         0 25 set-token 
+' invert      0 26 set-token 
+' lshift      0 27 set-token 
+' rshift      0 28 set-token 
+' >>a         0 29 set-token 
+' /mod        0 2A set-token 
+' u/mod       0 2B set-token
+' negate      0 2C set-token 
+' abs         0 2D set-token 
+' min         0 2E set-token 
+' max         0 2F set-token 
+' >r          0 30 set-token 
+' r>          0 31 set-token 
+' r@          0 32 set-token 
+' exit        0 33 set-token 
+' 0=          0 34 set-token 
+' 0<>         0 35 set-token 
+' 0<          0 36 set-token 
+' 0<=         0 37 set-token 
+' 0>          0 38 set-token 
+' 0>=         0 39 set-token 
+' <           0 3A set-token
+' >           0 3B set-token
+' =           0 3C set-token
+' <>          0 3D set-token
+' u>          0 3E set-token
+' u<=         0 3F set-token 
+' u<          0 40 set-token 
+' u>=         0 41 set-token 
+' >=          0 42 set-token 
+' <=          0 43 set-token 
+' between     0 44 set-token 
+' within      0 45 set-token 
+' DROP        0 46 set-token
+' DUP         0 47 set-token
+' OVER        0 48 set-token
+' SWAP        0 49 set-token
+' ROT         0 4A set-token
+' -ROT        0 4B set-token
+' TUCK        0 4C set-token
+' nip         0 4D set-token 
+' pick        0 4E set-token 
+' roll        0 4F set-token 
+' ?dup        0 50 set-token 
+' depth       0 51 set-token 
+' 2drop       0 52 set-token 
+' 2dup        0 53 set-token 
+' 2over       0 54 set-token 
+' 2swap       0 55 set-token 
+' 2rot        0 56 set-token 
+' 2/          0 57 set-token 
+' u2/         0 58 set-token 
+' 2*          0 59 set-token 
+' /c          0 5A set-token
+' /w          0 5B set-token 
+' /l          0 5C set-token 
+' /n          0 5D set-token 
+' ca+         0 5E set-token 
+' wa+         0 5F set-token 
+' la+         0 60 set-token 
+' na+         0 61 set-token 
+' char+       0 62 set-token 
+' wa1+        0 63 set-token 
+' la1+        0 64 set-token 
+' cell+       0 65 set-token 
+' chars       0 66 set-token 
+' /w*         0 67 set-token 
+' /l*         0 68 set-token 
+' cells       0 69 set-token 
+' on          0 6A set-token 
+' off         0 6B set-token 
+' +!          0 6C set-token 
+' @           0 6D set-token 
+' l@          0 6E set-token 
+' w@          0 6F set-token 
+' <w@         0 70 set-token 
+' c@          0 71 set-token 
+' !           0 72 set-token 
+' l!          0 73 set-token 
+' w!          0 74 set-token 
+' c!          0 75 set-token 
+' 2@          0 76 set-token 
+' 2!          0 77 set-token 
+' move        0 78 set-token 
+' fill        0 79 set-token 
+' comp        0 7A set-token 
+' noop        0 7B set-token
+' lwsplit     0 7C set-token 
+' wljoin      0 7D set-token 
+' lbsplit     0 7E set-token 
+' bljoin      0 7F set-token 
+' wbflip      0 80 set-token 
+' upc         0 81 set-token 
+' lcc         0 82 set-token 
+' pack      0 83 set-token 
+' count       0 84 set-token 
+' body>       0 85 set-token 
+' >body       0 86 set-token 
+' fcode-revision 0 87 set-token 
+' span        0 88 set-token 
+' unloop      0 89 set-token 
+' expect      0 8A set-token 
+' alloc-mem   0 8B set-token \ alloc-mem  
+' free-mem    0 8C set-token \ free-mem 
+' key?        0 8D set-token 
+' key         0 8E set-token 
+' emit        0 8F set-token 
+' type        0 90 set-token 
+' cr          0 91 set-token \ should be (cr but terminal support is not
+                             \ available
+' cr          0 92 set-token 
+\ ' #out      0 93 set-token 
+\ ' #line     0 94 set-token 
+' hold        0 95 set-token 
+' <#          0 96 set-token 
+' u#>         0 97 set-token 
+' sign        0 98 set-token 
+' u#          0 99 set-token 
+' u#s         0 9A set-token 
+' u.          0 9B set-token 
+' u.r         0 9C set-token 
+' .           0 9D set-token 
+' .r          0 9E set-token 
+' .s          0 9F set-token 
+' base        0 A0 set-token 
+\ ' convert     0  A1 set-token 
+' $number     0 A2 set-token 
+' digit       0 A3 set-token 
+' -1          0 A4 set-token
+'  0          0 A5 set-token
+'  1          0 A6 set-token
+'  2          0 A7 set-token
+'  3          0 A8 set-token
+' bl          0 A9 set-token
+' bs          0 AA set-token 
+' bell        0 AB set-token 
+' bounds      0 AC set-token 
+' here        0 AD set-token 
+' aligned     0 AE set-token 
+' wbsplit     0 AF set-token 
+' bwjoin      0 B0 set-token 
+' b(<mark)    1 B1 set-token
+' b(>resolve) 1 B2 set-token
+\ ' ferror      0 B3 set-token 
+\ ' ferror      0 B4 set-token 
+' new-token   0 B5 set-token 
+' named-token 0 B6 set-token
+\ fcode-debug? IF
+' b(:)        1 B7 set-token
+\ ELSE
+\ ' b(:)        1 B7 set-token
+\ THEN
+' b(value)    1 B8 set-token 
+' b(variable) 1 B9 set-token 
+' b(constant) 1 BA set-token 
+' b(create)   1 BB set-token 
+' b(defer)    1 BC set-token 
+' b(buffer:)  1 BD set-token 
+' b(field)    1 BE set-token 
+\ ' ferror      0 BF set-token 
+' INSTANCE     0 C0 set-token 
+\ ' noop        1 C0 set-token
+\ ' ferror      0 C1 set-token
+\ fcode-debug? IF
+' b(;)        1 C2 set-token
+\ ELSE
+\ ' b(;)        1 C2 set-token
+\ THEN
+' b(to)       1 C3 set-token 
+' b(case)     1 C4 set-token
+' b(endcase)  1 C5 set-token
+' b(endof)    1 C6 set-token
+' #           0 C7 set-token
+' #s          0 C8 set-token
+' #>          0 C9 set-token
+' external-token 0 CA set-token 
+' $find       0 CB set-token
+' offset16    0 CC set-token 
+' evaluate    0 CD set-token
+\             0  CE reserved
+\             0  CF reserved
+' c,          0  D0 set-token
+' w,          0  D1 set-token
+' l,          0  D2 set-token
+' ,           0  D3 set-token
+' um*         0  D4 set-token
+' um/mod      0  D5 set-token
+\             0  D6 reserved
+\             0  D7 reserved
+' d+          0  D8 set-token
+' d-          0  D9 set-token
+' get-token   0  DA set-token 
+' set-token   0  DB set-token 
+' state       0  DC set-token  \ possibly broken
+' compile,    0  DD set-token
+' behavior    0  DE set-token 
+
+' start0             0  F0 set-token
+' start1             0  F1 set-token
+' start2             0  F2 set-token
+' start4             0  F3 set-token
+
+' ferror             0  FC set-token
+' version1           0  FD set-token
+
+\ ' 4-byte-id        0  FE set-token    \ Historical
+' end1               0  FF set-token
+
+\ ' dma-alloc   0 101 set-token 
+' my-address        0 102 set-token 
+' my-space          0 103 set-token
+' property          0 110 set-token
+' encode-int        0 111 set-token
+' encode+           0 112 set-token
+' encode-phys       0 113 set-token
+' encode-string     0 114 set-token
+' encode-bytes      0 115 set-token
+' reg               0 116 set-token
+' model             0 119 set-token    
+' device-type       0 11A set-token
+' parse-2int        0 11B set-token
+' is-install        0 11C set-token
+' is-remove         0 11D set-token
+' is-selftest       0 11E set-token
+' new-device        0 11F set-token
+' diagnostic-mode?  0 120 set-token
+' memory-test-suite 0 122 set-token
+' mask              0 124 set-token
+' get-msecs         0 125 set-token
+' ms                0 126 set-token
+' finish-device     0 127 set-token
+' decode-phys       0 128 set-token
+' #lines            0 150 set-token
+' #columns          0 151 set-token
+' line#             0 152 set-token
+' column#           0 153 set-token
+' inverse?          0 154 set-token
+' inverse-screen?   0 155 set-token
+
+' draw-character    0 157 set-token
+' reset-screen      0 158 set-token
+' toggle-cursor     0 159 set-token
+' erase-screen      0 15A set-token
+' blink-screen      0 15B set-token
+' invert-screen     0 15C set-token
+' insert-characters 0 15D set-token
+' delete-characters 0 15E set-token
+' insert-lines      0 15F set-token
+' delete-lines      0 160 set-token
+' draw-logo         0 161 set-token
+' frame-buffer-adr  0 162 set-token
+' screen-height     0 163 set-token
+' screen-width      0 164 set-token
+' window-top        0 165 set-token
+' window-left       0 166 set-token
+
+' default-font      0 16A set-token
+' set-font          0 16B set-token
+' char-height       0 16C set-token
+' char-width        0 16D set-token
+' >font             0 16E set-token
+' fontbytes         0 16F set-token
+
+' fb8-install       0 18B set-token
+
+' device-name       0 201 set-token
+' my-args           0 202 set-token
+' my-self           0 203 set-token
+' find-package      0 204 set-token
+' open-package      0 205 set-token
+' close-package     0 206 set-token
+' find-method       0 207 set-token
+' call-package      0 208 set-token
+' $call-parent      0 209 set-token
+' my-parent         0 20A set-token
+' ihandle>phandle   0 20B set-token
+' my-unit           0 20D set-token
+' $call-method      0 20E set-token
+' $open-package     0 20F set-token
+' (is-user-word)    0 214 set-token
+' suspend-fcode     0 215 set-token
+\ ' abort             0 216 set-token
+' fc-abort             0 216 set-token
+' catch             0 217 set-token
+' throw             0 218 set-token
+' get-my-property   0 21A set-token
+' decode-int        0 21B set-token
+' decode-string     0 21C set-token
+' get-inherited-property 0 21D set-token  
+' delete-property   0 21E set-token  
+' get-package-property 0 21F set-token
+' cpeek             0 220 set-token 
+' wpeek             0 221 set-token 
+' lpeek             0 222 set-token 
+' cpoke             0 223 set-token 
+' wpoke             0 224 set-token 
+' lpoke             0 225 set-token 
+' lwflip            0 226 set-token 
+' lbflip            0 227 set-token 
+' lbflips           0 228 set-token
+' rx@               0 22E set-token
+' rx!               0 22F set-token
+' rb@               0 230 set-token
+' rb!               0 231 set-token
+' rw@               0 232 set-token 
+' rw!               0 233 set-token 
+' rl@               0 234 set-token 
+' rl!               0 235 set-token 
+' wbflips           0 236 set-token 
+' lwflips           0 237 set-token 
+\ ' probe           0 238 set-token
+\ ' probe-virtual   0 239 set-token
+\                   0 23A reserved
+' child             0 23B set-token
+' peer              0 23C set-token
+' next-property     0 23D set-token
+' byte-load         0 23E set-token
+' set-args          0 23F set-token
+' left-parse-string 0 240 set-token
+' bxjoin            0 241 set-token
+' <l@               0 242 set-token
+' lxjoin            0 243 set-token
+' wxjoin            0 244 set-token
+' x,                0 245 set-token
+' x@                0 246 set-token
+' x!                0 247 set-token
+' /x                0 248 set-token
+' /x*               0 249 set-token
+' xa+               0 24A set-token
+' xa1+              0 24B set-token
+' xbflip            0 24C set-token
+' xbflips           0 24D set-token
+' xbsplit           0 24E set-token
+' xlflip            0 24F set-token
+' xlflips           0 250 set-token
+' xlsplit           0 251 set-token
+' xwflip            0 252 set-token
+' xwflips           0 253 set-token
+' xwsplit           0 254 set-token
+\                    0 254 RESERVED FCODES 
+\                    ...
+\                    0 5FF RESERVED FCODES 
+
+\                    0 600 VENDOR FCODES 
+\                    ...
+\                    0 7FF VENDOR FCODES 
+
+\                    0 800 LOCAL FCODES 
+\                    ...
+\                    0 FFF LOCAL FCODES 
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/find-hash.fs b/qemu-0.15.x/roms/SLOF/slof/fs/find-hash.fs
new file mode 100644
index 0000000..a40ccbd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/find-hash.fs
@@ -0,0 +1,77 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+#ifdef HASH_DEBUG
+0 value from-hash
+0 value not-from-hash
+0 value hash-collisions
+#endif
+
+clean-hash
+
+: hash-find ( str len head -- 0 | link )
+   >r 2dup 2dup hash                  ( str len str len hash          R: head )
+   dup >r @ dup                       ( str len str len *hash *hash   R: head hash )
+   IF                                 ( str len str len *hash         R: head hash )
+      link>name name>string string=ci ( str len true|false            R: head hash )
+      dup 0=
+      IF
+#ifdef HASH_DEBUG
+         hash-collisions 1+
+         to hash-collisions
+#endif
+      THEN
+   ELSE
+      nip nip                         ( str len 0                     R: head hash )
+   THEN
+   IF                                 \ hash found
+      2drop r> @ r> drop              (  *hash                        R: )
+#ifdef HASH_DEBUG
+      from-hash 1+ to from-hash
+#endif
+      exit
+   THEN                               \ hash not found
+   r> r> swap >r ((find))             ( str len head                  R: hash=0 )
+   dup
+   IF
+#ifdef HASH_DEBUG
+      not-from-hash 1+
+      to not-from-hash
+#endif
+      dup r> !                        ( link                          R: )
+   ELSE
+      r> drop                         ( 0                             R: )
+   THEN
+;
+
+: hash-reveal  hash off ;
+
+' hash-reveal to (reveal)
+' hash-find to (find)
+
+#ifdef HASH_DEBUG
+\ print out all entries in the hash table
+: dump-hash-table  ( -- )
+   cr
+   hash-table hash-size 0  DO
+      dup @ dup 0<>  IF
+         over . s" : " type link>name name>string type cr
+      ELSE
+         drop
+      THEN
+      cell+
+   LOOP drop
+   s" hash-collisions: " type hash-collisions . cr
+   s" from-hash: " type from-hash . cr
+   s" not-from-hash: " type not-from-hash . cr
+;
+#endif
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/generic-disk.fs b/qemu-0.15.x/roms/SLOF/slof/fs/generic-disk.fs
new file mode 100644
index 0000000..0543c89
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/generic-disk.fs
@@ -0,0 +1,68 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Generic disk support
+
+\ Input:
+\        name of device ( e.g. "disk", "cdrom", ... )
+\        dev# 
+
+\ Needs from parent in device tree:
+\        dev-read-blocks ( addr block# #blocks phys.lo ... phys.hi -- #read )
+\        block-size
+\        max-transfer
+
+\ Provides:
+\        open ( -- okay? )
+\        close ( -- )
+\        read ( addr len -- actual )
+\        seek ( pos.lo pos.hi -- status )
+\        read-blocks ( addr block# #blocks -- #read )
+\ Uses:
+\        disk-label package interpose for partition and file systems support
+\        deblocker package for byte read support
+
+( str len phys.lo ... phys.hi -- )
+new-device set-unit                                          ( str len )
+  2dup device-name 
+  s" 0 pci-alias-" 2swap $cat evaluate
+  s" block" device-type      
+
+\ Requiered interface for deblocker
+
+   s" block-size" $call-parent   CONSTANT block-size
+   s" max-transfer" $call-parent CONSTANT max-transfer 
+
+: read-blocks ( addr block# #blocks -- #read )
+   my-unit s" dev-read-blocks" $call-parent
+;    
+
+INSTANCE VARIABLE deblocker
+
+: open ( -- okay? )
+   0 0 s" deblocker" $open-package dup deblocker ! dup IF 
+      s" disk-label" find-package IF
+	 my-args rot interpose
+      THEN
+   THEN 0<> ;
+
+: close ( -- )
+   deblocker @ close-package ;
+
+: seek ( pos.lo pos.hi -- status )
+   s" seek" deblocker @ $call-method ;
+
+: read ( addr len -- actual )
+   s" read" deblocker @ $call-method ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/history.fs b/qemu-0.15.x/roms/SLOF/slof/fs/history.fs
new file mode 100644
index 0000000..2c2c70f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/history.fs
@@ -0,0 +1,107 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Create debug section in NVRAM
+: debug-init-nvram ( -- )
+   nvram-partition-type-debug get-nvram-partition IF
+      cr ." Could not find debug partition in NVRAM - "
+      nvram-partition-type-debug s" debug" d# 1024 new-nvram-partition
+      ABORT" Failed to create DEBUG NVRAM partition"
+      2dup erase-nvram-partition drop
+      ." created." cr
+   THEN
+   s" debug-nvram-partition" $2constant
+;
+
+debug-init-nvram
+
+: debug-add-env ( "name" "value" -- ) debug-nvram-partition 2rot 2rot internal-add-env drop ;
+: debug-set-env ( "name" "value" -- ) debug-nvram-partition 2rot 2rot internal-set-env drop ;
+: debug-get-env ( "name" -- "value" TRUE | FALSE) debug-nvram-partition 2swap internal-get-env ;
+
+: debug-get-history-enabled ( -- n )	s" history-enabled?" debug-get-env IF $number IF 0 THEN ELSE 0 THEN ;
+: debug-set-history-enabled ( n -- )	(.) s" history-enabled?" 2swap debug-set-env ;
+
+
+debug-get-history-enabled constant nvram-history?
+
+nvram-history? [IF]
+
+: history-init-nvram ( -- )
+   nvram-partition-type-history get-nvram-partition IF
+      cr ." Could not find history partition in NVRAM - "
+      nvram-partition-type-history s" history" d# 2048 new-nvram-partition
+      ABORT" Failed to create SMS NVRAM partition"
+      2dup erase-nvram-partition drop
+      ." created" cr
+   THEN
+   s" history-nvram-partition" $2constant
+;
+
+history-init-nvram
+
+0 value (history-len)
+0 value (history-adr)
+
+: (history-load-one) ( str len -- len )
+   \ 2dup ." loading " type cr
+   to (history-len) to (history-adr)
+   /his (history-len) + alloc-mem ( his )
+   his-tail 0= IF dup to his-tail THEN
+   his-head over his>next ! to his-head
+   his-head his>next @  his>prev his-head swap !
+   (history-len) his-head his>len !
+   (history-adr) his-head his>buf (history-len) move
+   (history-len) 1+
+;
+
+: history-load ( -- )
+   history-nvram-partition drop BEGIN dup WHILE
+      dup rzcount ( part str len )
+      dup IF
+         (history-load-one) +
+      ELSE
+         3drop 0
+      THEN
+   REPEAT
+   drop
+;
+
+: (history-store-one) ( pos len saddr slen -- FALSE | npos nlen TRUE )
+   dup 3 pick < IF \ enough space
+      dup >r rot >r
+      \ 2dup ." storing " type cr
+      bounds DO dup i c@ swap nvram-c! 1+ LOOP
+      dup 0 swap nvram-c! 1+
+      r> r> - 1- true
+   ELSE
+      2drop false
+   THEN
+;
+
+: history-store ( -- )
+   history-nvram-partition erase-nvram-partition drop
+   history-nvram-partition his-tail BEGIN dup WHILE
+      dup his>buf over his>len @
+      ( position len link saddr slen )
+      rot >r (history-store-one) r> 
+      swap IF his>prev @ ELSE drop 0 THEN
+   REPEAT
+   2drop drop
+;
+
+\ redefine "end of SLOF" words to safe history
+: reset-all history-store reset-all ;
+: reboot history-store reboot ;
+: boot history-store boot ;
+
+[THEN]
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/ide.fs b/qemu-0.15.x/roms/SLOF/slof/fs/ide.fs
new file mode 100644
index 0000000..93ca766
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/ide.fs
@@ -0,0 +1,612 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+\
+\ 26.06.2007  added: two devices (Master/Slave) per channel
+
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+: decode-unit  1 hex-decode-unit ;
+: encode-unit  1 hex-encode-unit ;
+
+0 VALUE >ata                                 \ base address for command-block
+0 VALUE >ata1                                \ base address for control block
+
+true VALUE no-timeout                        \ flag that no timeout occured
+
+0c  CONSTANT #cdb-bytes                      \ command descriptor block (12 bytes)
+800 CONSTANT atapi-size
+200 CONSTANT ata-size
+
+\ *****************************
+\ Some register access helpers.
+\ *****************************
+: ata-ctrl! 2 >ata1 + io-c! ;                      \ device control reg
+: ata-astat@ 2 >ata1 + io-c@ ;                     \ read alternate status
+                                                   
+: ata-data@ 0 >ata + io-w@ ;                       \ data reg
+: ata-data! 0 >ata + io-w! ;                       \ data reg
+: ata-err@  1 >ata + io-c@ ;                       \ error reg
+: ata-feat! 1 >ata + io-c! ;                       \ feature reg
+: ata-cnt@  2 >ata + io-c@ ;                       \ sector count reg
+: ata-cnt!  2 >ata + io-c! ;                       \ sector count reg
+: ata-lbal! 3 >ata + io-c! ;                       \ lba low reg
+: ata-lbal@ 3 >ata + io-c@ ;                       \ lba low reg
+: ata-lbam! 4 >ata + io-c! ;                       \ lba mid reg
+: ata-lbam@ 4 >ata + io-c@ ;                       \ lba mid reg
+: ata-lbah! 5 >ata + io-c! ;                       \ lba high reg
+: ata-lbah@ 5 >ata + io-c@ ;                       \ lba high reg
+: ata-dev!  6 >ata + io-c! ;                       \ device reg
+: ata-dev@  6 >ata + io-c@ ;                       \ device reg
+: ata-cmd!  7 >ata + io-c! ;                       \ command reg
+: ata-stat@ 7 >ata + io-c@ ;                       \ status reg
+
+\ **********************************************************************
+\ ATA / ATAPI Commands specifications:
+\ - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
+\ - ATA Packet Interface for CD-ROMs SFF-8020i
+\ - ATA/ATAPI Host Adapters Standard (T13/1510D)
+\ **********************************************************************
+00 CONSTANT cmd#nop                                \ ATA and ATAPI
+08 CONSTANT cmd#device-reset                       \ ATAPI only (mandatory)
+20 CONSTANT cmd#read-sector                        \ ATA and ATAPI
+90 CONSTANT cmd#execute-device-diagnostic          \ ATA and ATAPI
+a0 CONSTANT cmd#packet                             \ ATAPI only (mandatory)
+a1 CONSTANT cmd#identify-packet-device             \ ATAPI only (mandatory)
+ec CONSTANT cmd#identify-device                    \ ATA and ATAPI
+
+\ *****************************
+\ Setup Regs for ATA:
+\ BAR 0 & 1 : Device 0
+\ BAR 2 & 3 : Device 1
+\ *****************************
+: set-regs ( n -- )
+   dup
+   01 and                                    \ only Chan 0 or Chan 1 allowed
+   3 lshift dup 10 + config-l@ -4 and to >ata
+   14 + config-l@ -4 and to >ata1
+   02 ata-ctrl!                              \ disable interrupts
+   02 and
+   IF
+      10
+   ELSE
+      00
+   THEN
+   ata-dev!
+;
+
+ata-size VALUE block-size
+80000    VALUE max-transfer            \ Arbitrary, really
+
+CREATE sector d# 512 allot
+CREATE packet-cdb #cdb-bytes allot
+CREATE return-buffer atapi-size allot
+
+scsi-open                             \ add scsi functions
+
+\ ********************************
+\ show all ATAPI-registers
+\ data-register not read in order
+\ to not influence PIO mode
+\ ********************************
+: show-regs
+   cr
+   cr ." alt. Status: " ata-astat@ .
+   cr ." Status     : " ata-stat@ .
+   cr ." Device     : " ata-dev@ .
+   cr ." Error-Reg  : " ata-err@ .
+   cr ." Sect-Count : " ata-cnt@ .
+   cr ." LBA-Low    : " ata-lbal@ .
+   cr ." LBA-Med    : " ata-lbam@ .
+   cr ." LBA-High   : " ata-lbah@ .
+;
+
+\ ***************************************************
+\ reads ATAPI-Status and displays it if check-bit set
+\ ***************************************************
+: status-check               ( -- )
+   ata-stat@
+   dup   
+   01 and                                    \ is 'check' flag set ?
+   IF
+      cr
+      ."    - ATAPI-Status: " .
+      ata-err@                               \ retrieve sense code
+      dup
+      60 =                                   \ sense code = 6 ?
+      IF
+         ." ( media changed or reset )"      \ 'unit attention'
+         drop                                \ drop err-reg content
+      ELSE
+         dup
+         ." (Err : " .                       \ show err-reg content
+         space
+         rshift 4 .sense-text                \ show text string
+         29 emit
+      THEN
+      cr
+   ELSE
+      drop                                   \ remove unused status      
+   THEN      
+;
+
+\ *************************************
+\ Wait for interface ready condition
+\ Bit 7 of Status-Register is busy flag
+\ new version with abort after 5 sec.
+\ *************************************
+: wait-for-ready
+   get-msecs                                 \ start timer
+   BEGIN
+      ata-stat@ 80 and 0<>                   \ busy flag still set ?
+      no-timeout and
+      WHILE                                  \ yes
+         dup get-msecs swap
+         -                                   \ calculate timer difference
+         FFFF AND                            \ reduce to 65.5 seconds
+         d# 5000 >                           \ difference > 5 seconds ?
+         IF
+            false to no-timeout
+         THEN
+      REPEAT
+   drop
+;
+
+\ *************************************
+\ wait for specific status bits
+\ new version with abort after 5 sec.
+\ *************************************
+: wait-for-status          ( val mask -- )
+   get-msecs                                 \ initial timer value (start)
+   >r
+   BEGIN
+      2dup                                   \ val mask
+      ata-stat@ and <>                       \ expected status ?
+      no-timeout and                         \ and no timeout ?
+      WHILE      
+      get-msecs r@ -                         \ calculate timer difference
+      FFFF AND                               \ mask-off overflow bits
+      d# 5000 >                              \ 5 seconds exceeded ?
+      IF
+         false to no-timeout                 \ set global flag
+      THEN      
+   REPEAT                  
+   r>                                        \ clean return stack
+   3drop
+;
+
+\ *********************************    
+\ remove extra spaces from string end
+\ *********************************    
+: cut-string      ( saddr nul -- )
+   swap
+   over +
+   swap   
+   1 rshift                                  \ bytecount -> wordcount
+   0 do
+      /w -
+      dup               ( addr -- addr addr )
+      w@                ( addr addr -- addr nuw )
+      dup               ( addr nuw -- addr nuw nuw )
+      2020 =
+      IF
+         drop
+         0 
+      ELSE
+         LEAVE         
+      THEN
+      over         
+      w!
+   LOOP
+   drop
+   drop
+; 
+
+\ ****************************************************
+\ prints model-string received by identify device
+\ ****************************************************
+: show-model          ( dev# chan# -- )
+   2dup
+   ."    CH " .                  \ channel 0 / 1
+   0= IF ." / MA"                \ Master / Slave
+   ELSE  ." / SL"
+   THEN
+   swap
+   2 * + ."  (@" . ." ) : "      \ device number
+   sector 1 +
+   c@
+   80 AND 0=
+   IF
+      ." ATA-Drive    "
+   ELSE
+      ." ATAPI-Drive  "
+   THEN
+
+   22 emit                       \ start string display with "
+   sector d# 54 +                \ string starts 54 bytes from buffer start
+   dup
+   d# 40                         \ and is 40 chars long
+   cut-string                    \ remove all trailing spaces
+   
+   BEGIN
+      dup
+      w@
+      wbflip
+      wbsplit
+      dup 0<>                    \ first char
+      IF                   
+         emit
+         dup 0<>                 \ second char
+         IF
+            emit
+            wa1+                 \ increment address for next
+            false
+         ELSE                    \ second char = EndOfString
+            drop
+            true
+         THEN   
+      ELSE                       \ first char = EndOfString
+         drop
+         drop
+         true
+      THEN
+   UNTIL                         \ end of string detected
+   drop
+   22 emit                       \ end string display
+                                                  
+   sector c@                     \ get lower byte of first doublet
+   80 AND                        \ check bit 7
+   IF
+      ."  (removable media)"
+   THEN
+   
+   sector 1 +
+   c@
+   80 AND 0= IF                  \ is this an ATA drive ?
+      sector d# 120 +            \ get word 60 + 61
+      rl at -le                     \ read 32-bit as little endian value
+      d# 512                     \ standard ATA block-size
+      swap
+      .capacity-text ( block-size #blocks -- )
+   THEN
+   
+    sector d# 98 +               \ goto word 49
+    w@
+    wbflip
+    200 and 0= IF cr ."    ** LBA is not supported " THEN   
+
+   sector c@                     \ get lower byte of first doublet
+   03 AND 01 =                   \ we use 12-byte packet commands (=00b)
+   IF
+      cr ."    packet size = 16 ** not supported ! **"
+   THEN
+   no-timeout not                \ any timeout occured so far ?
+   IF
+      cr   ."    ** timeout **"
+   THEN
+;
+
+\ ****************************
+\ ATA functions
+\ ****************************
+: pio-sector ( addr -- )  100 0 DO ata-data@
+   over w! wa1+ LOOP drop ;
+: pio-sector ( addr -- ) 
+  wait-for-ready pio-sector ;
+: pio-sectors ( n addr -- )  swap 0 ?DO dup pio-sector 200 + LOOP drop ;
+
+: lba!  lbsplit   
+   0f and 40 or                  \ always set LBA-mode + LBA (27..24)
+   ata-dev@ 10 and or            \ add current device-bit (DEV)
+   ata-dev!                      \ set LBA (27..24)
+   ata-lbah!                     \ set LBA (23..16)
+   ata-lbam!                     \ set LBA (15..8)
+   ata-lbal!                     \ set LBA (7..0)
+;
+
+: read-sectors ( lba count addr -- ) 
+  >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ;
+
+: read-sectors ( lba count addr dev-nr -- )
+    set-regs             ( lba count addr ) \ Set ata regs 
+    BEGIN >r dup 100 > WHILE
+       over 100 r@ read-sectors
+       >r 100 + r> 100 - r> 20000 + REPEAT
+    r> read-sectors
+;
+
+: ata-read-blocks                ( addr block# #blocks dev# -- #read )
+   swap dup >r swap >r rot r>    ( addr block# #blocks dev # R: #blocks )
+   read-sectors r>               ( R: #read )
+;    
+
+\ *******************************
+\ ATAPI functions
+\ preset LBA register with maximum
+\ allowed block-size (16-bits)
+\ *******************************
+: set-lba                              ( block-length -- )
+   lbsplit                             ( quad -- b1.lo b2 b3 b4.hi )
+   drop                                \ skip upper two bytes
+   drop
+   ata-lbah!
+   ata-lbam!
+;
+   
+\ *******************************************
+\ gets byte-count and reads a block of words
+\ from data-register to a buffer
+\ *******************************************
+: read-pio-block                        ( buff-addr -- buff-addr-new )
+   ata-lbah@ 8 lshift                  \ get block length High
+   ata-lbam@ or                        \ get block length Low
+   1 rshift                            \ bcount -> wcount
+   dup
+   0> IF                               \ any data to transfer?
+      0 DO                             \ words to read
+         dup                           \ buffer-address
+         ata-data@ swap w!             \ write 16-bits
+         wa1+                          \ address of next entry
+         LOOP
+      ELSE
+         drop                          ( buff-addr wcount -- buff-addr )
+      THEN
+   wait-for-ready
+;
+
+\ ********************************************
+\ ATAPI support
+\ Send a command block (12 bytes) in PIO mode
+\ read data if requested
+\ ********************************************
+: send-atapi-packet                    ( req-buffer -- )
+   >r                                  (   R: req-buffer )
+   atapi-size set-lba                  \ set regs to length limit
+   00 ata-feat!
+   cmd#packet ata-cmd!                 \ A0 = ATAPI packet command
+   48 C8  wait-for-status     ( val mask -- )  \ BSY:0 DRDY:1 DRQ:1
+   6 0  do
+      packet-cdb i 2 * +                \ transfer command block (12 bytes)
+      w@
+      ata-data!                        \ 6 doublets PIO transfer to device
+      loop                             \ copy packet to data-reg
+   status-check                        ( -- ) \ status err bit set ? -> display
+   wait-for-ready                      ( -- ) \ busy released ?
+   BEGIN
+   ata-stat@ 08 and 08 = WHILE         \ Data-Request-Bit set ?
+      r>                               \ get last target buffer address
+      read-pio-block                   \ only if from device requested
+      >r                               \ start of next block
+      REPEAT
+   r>                                  \ original value
+   drop                                \ return clean
+;   
+
+: atapi-packet-io                      ( -- )
+   return-buffer atapi-size erase      \ clear return buffer
+   return-buffer send-atapi-packet     \ send 'packet-cdb' , get 'return-buffer'
+;
+
+
+
+\ ********************************
+\ ATAPI packet commands
+\ ********************************
+
+\ Methods to access atapi disk
+
+: atapi-test ( -- true|false )
+   packet-cdb scsi-build-test-unit-ready     \ command-code: 00
+   atapi-packet-io                           ( )  \ send CDB, get return-buffer
+   ata-stat@ 1 and IF false ELSE true THEN
+;
+
+: atapi-sense ( -- ascq asc sense-key )
+   d# 252 packet-cdb scsi-build-request-sense ( alloc-len cdb -- )
+   atapi-packet-io                           ( )  \ send CDB, get return-buffer
+   return-buffer scsi-get-sense-data         ( cdb-addr -- ascq asc sense-key )
+;
+
+: atapi-read-blocks                    ( address block# #blocks dev# -- #read-blocks )
+   set-regs                            ( address block# #blocks )
+   dup >r                              ( address block# #blocks )
+   packet-cdb scsi-build-read-10       ( address block# #blocks cdb -- )
+   send-atapi-packet                   ( address -- )
+   r>                                  \ return requested number of blocks
+;
+
+\ ***************************************
+\ read capacity of drive medium
+\ use SCSI-Support Package
+\ ***************************************
+: atapi-read-capacity                        ( -- )
+   packet-cdb scsi-build-read-cap-10         \ fill block with command
+   atapi-packet-io                           ( )  \ send CDB, get return-buffer
+   return-buffer scsi-get-capacity-10        ( cdb -- block-size #blocks )
+   .capacity-text                            ( block-size #blocks -- )
+   status-check                              ( -- )
+;
+
+\ ***************************************
+\ read capacity of drive medium
+\ use SCSI-Support Package
+\ ***************************************
+: atapi-read-capacity-ext                    ( -- )
+   packet-cdb scsi-build-read-cap-16         \ fill block with command
+   atapi-packet-io                           ( )  \ send CDB, get return-buffer
+   return-buffer scsi-get-capacity-16        ( cdb -- block-size #blocks )
+   .capacity-text                            ( block-size #blocks -- )
+   status-check                              ( -- )
+;
+
+
+\ ***********************************************
+\ wait until media in drive is ready ( max 5 sec)
+\ ***********************************************
+: wait-for-media-ready                 ( -- true|false )
+   get-msecs                                 \ initial timer value (start)
+   >r
+   BEGIN
+      atapi-test                             \ unit ready? false if not      
+      not
+      no-timeout and
+      WHILE
+         atapi-sense  ( -- ascq asc sense-key )
+         02 =                                \ sense key 2 = media error
+         IF                                  \ check add. sense code
+            3A =                             \ asc: device not ready ?
+            IF
+               false to no-timeout
+               ."  empty (" . 29 emit        \ show asc qualifier
+            ELSE
+               drop                          \ discard asc qualifier
+            THEN                             \ medium not present, abort waiting
+         ELSE
+            drop                             \ discard asc
+            drop                             \ discard ascq
+         THEN
+         get-msecs r@ -                      \ calculate timer difference
+         FFFF AND                            \ mask-off overflow bits
+         d# 5000 >                           \ 5 seconds exceeded ?
+         IF
+            false to no-timeout              \ set global flag
+         THEN      
+   REPEAT
+   r>
+   drop
+   no-timeout
+;
+
+\ ******************************************************
+\ Method pointer for read-blocks methods
+\ controller implements 2 channels (primary / secondary)
+\ for 2 devices each (master / slasve)
+\ ******************************************************
+\ 2 channels (primary/secondary) per controller
+2 CONSTANT #chan 
+
+\ 2 devices (master/slave) per channel
+2 CONSTANT #dev
+
+\ results in a total of devices
+\ connected to a controller with
+\ two separate channels (4)
+: #totaldev #dev #chan * ;
+ 
+CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase
+
+\ Execute read-blocks of device
+: dev-read-blocks  ( address block# #blocks dev# -- #read-blocks )
+   dup cells read-blocks-xt + @ execute
+;
+
+\ **********************************************************
+\ Read device type
+\ Signature      ATAPI             ATA
+\ ---------------------------------------------
+\ Sector Count    01h              01h
+\ Sector Number   01h              01h
+\ Cylinder Low    14h              00h
+\ Cylinder High   EBh              00h
+\ Device/Head     00h or 10h       00h or 01h
+\ see also ATA/ATAPI errata at:
+\ http://suif.stanford.edu/~csapuntz/blackmagic.html
+\ **********************************************************
+: read-ident  ( -- true|false )
+   false
+   00 ata-lbal!                              \ clear previous signature
+   00 ata-lbam!
+   00 ata-lbah!
+   cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command
+   ata-stat@ CF and 48 =
+   IF
+      drop true                                          \ cmd accepted, this is a ATA
+      d# 512 set-lba                                     \ set LBA to sector-length
+   ELSE                                                  \ ATAPI sends signature instead
+      ata-lbam@ 14 = IF                                  \ cylinder low  = 14 ?
+         ata-lbah@ EB = IF                               \ cylinder high = EB ?
+            cmd#device-reset ata-cmd! wait-for-ready     \ only supported by ATAPI
+            cmd#identify-packet-device ata-cmd! wait-for-ready                     \ first try ata
+            ata-stat@ CF and 48 = IF               
+               drop true                                 \ replace flag
+               THEN
+            THEN
+         THEN
+      THEN
+   dup IF
+      ata-stat@ 8 AND IF                        \ data requested (as expected) ?      
+         sector read-pio-block 
+         drop                                   \ discard address end 
+         ELSE
+         drop false
+         THEN
+      THEN
+   
+   no-timeout not IF                            \ check without any timeout ?
+      drop
+      false                                     \ no, detection discarded
+      THEN
+;
+
+scsi-close                             \ remove scsi commands from word list
+
+
+\ *************************************************
+\ Init controller ( chan 0 and 1 )
+\ device 0 (= master) and device 1 ( = slave)
+\  #dev  #chan   Dev-ID
+\ ----------------------
+\   0      0        0          Master of Channel 0
+\   0      1        1          Master of Channel 1
+\   1      0        2          Slave  of Channel 0
+\   1      1        3          Slave  of Channel 1
+\ *************************************************
+: find-disks      ( -- )   
+   #chan 0 DO                                      \ check 2 channels (primary & secondary)
+      #dev 0 DO                                    \ check 2 devices per channel (master / slave)
+         i 2 * j +
+         set-regs                                  \ set base address and dev-register for register access
+         ata-stat@ 7f and 7f <>                    \ Check, if device is connected
+         IF
+            true to no-timeout                     \ preset timeout-flag
+            read-ident        ( -- true|false )
+            IF
+               i j show-model                      \ print manufacturer + device string
+               sector 1+ c@ C0 and 80 =            \ Check for ata or atapi
+               IF
+                  wait-for-media-ready             \ wait up to 5 sec if not ready
+                  no-timeout and
+                  IF
+                     atapi-read-capacity
+                     atapi-size to block-size      \ ATAPI: 2048 bytes
+                     80000 to max-transfer
+                     ['] atapi-read-blocks i 2 * j + cells read-blocks-xt + !
+                     s" cdrom" strdup i 2 * j + s" generic-disk.fs" included
+                  ELSE
+                     ."  -"                        \ show hint for not registered
+                  THEN    
+               ELSE
+                  ata-size to block-size           \ ATA: 512 bytes
+                  80000 to max-transfer
+                  ['] ata-read-blocks i 2 * j + cells read-blocks-xt + !
+                  s" disk" strdup i 2 * j + s" generic-disk.fs" included
+               THEN
+            cr
+            THEN    
+         THEN
+         i 2 * j + 200 + cp
+      LOOP
+   LOOP
+;
+
+find-disks
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/instance.fs b/qemu-0.15.x/roms/SLOF/slof/fs/instance.fs
new file mode 100644
index 0000000..67c5b06
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/instance.fs
@@ -0,0 +1,130 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Support for device node instances.
+
+0 VALUE my-self
+
+: >instance
+   my-self 0= ABORT" No instance!"
+   my-self +
+;
+
+: (create-instance-var) ( initial-value -- )
+   get-node ?dup 0= ABORT" Instance word outside device context!"
+   dup node>instance @      ( iv phandle tmp-ihandle )
+   swap node>instance-size dup @     ( iv tmp-ih *instance-size instance-size )
+   dup ,                             \ compile current instance ptr
+   swap 1 cells swap +!              ( iv tmp-ih instance-size )
+   + !
+;
+
+: create-instance-var ( "name" initial-value -- )
+  CREATE (create-instance-var) PREVIOUS ;
+
+VOCABULARY instance-words  ALSO instance-words DEFINITIONS
+
+: VARIABLE  0 create-instance-var DOES> @ >instance ;
+: VALUE       create-instance-var DOES> @ >instance @ ;
+: DEFER     0 create-instance-var DOES> @ >instance @ execute ;
+\ No support for BUFFER: yet.
+
+PREVIOUS DEFINITIONS
+
+\ check whether a value or a defer word is an
+\ instance word: It must be a CREATE word and
+\ the DOES> part must do >instance as first thing
+
+: (instance?) ( xt -- xt true|false )
+   dup @ <create> = IF
+      dup cell+ @ cell+ @ ['] >instance =
+   ELSE
+      false
+   THEN
+;
+
+\ This word does instance values in compile mode.
+\ It corresponds to DOTO from engine.in
+: (doito) ( value R:*CFA -- )
+   r> cell+ dup >r
+   @ cell+ cell+ @ >instance !
+;
+
+: to ( value wordname<> -- )
+   ' (instance?)
+   state @ IF
+      \ compile mode handling normal or instance value
+      IF ['] (doito) ELSE ['] DOTO THEN
+      , , EXIT
+   THEN
+   IF
+      cell+ cell+ @ >instance ! \ interp mode instance value
+   ELSE
+      cell+ !                   \ interp mode normal value
+   THEN
+; IMMEDIATE
+
+: INSTANCE  ALSO instance-words ;
+
+
+STRUCT
+/n FIELD instance>node
+/n FIELD instance>parent
+/n FIELD instance>args
+/n FIELD instance>args-len
+CONSTANT /instance-header
+
+: my-parent  my-self instance>parent @ ;
+: my-args    my-self instance>args 2@ ;
+
+\ copy args from original instance to new created
+: set-my-args   ( old-addr len -- )
+   dup IF                             \ IF len > 0                    ( old-addr len )
+      dup alloc-mem                   \ | allocate space for new args ( old-addr len new-addr )
+      swap 2dup                       \ | write the new address       ( old-addr new-addr len new-addr len )
+      my-self instance>args 2!        \ | into the instance table     ( old-addr new-addr len )
+      move                            \ | and copy the args           ( -- )
+   ELSE                               \ ELSE                          ( old-addr len )
+      my-self instance>args 2!        \ | set new args to zero, too   ( )
+   THEN                               \ FI
+;
+
+\ Current node has already been set, when this is called.
+: create-instance-data ( -- instance )
+   get-node dup node>instance @ swap node>instance-size @  ( instance instance-size )
+   dup alloc-mem dup >r swap move r>
+;
+: create-instance ( -- )
+   my-self create-instance-data
+   dup to my-self instance>parent !
+   get-node my-self instance>node !
+;
+
+: destroy-instance ( instance -- )
+   dup @ node>instance-size @ free-mem
+;
+
+: ihandle>phandle ( ihandle -- phandle )
+   dup 0= ABORT" no current instance" instance>node @
+;
+
+: push-my-self ( ihandle -- )  r> my-self >r >r to my-self ;
+: pop-my-self ( -- )  r> r> to my-self >r ;
+: call-package  push-my-self execute pop-my-self ;
+: $call-static ( ... str len node -- ??? )
+\  cr ." call for " 3dup -rot type ."  on node " .
+   find-method IF execute ELSE -1 throw THEN
+;
+: $call-my-method  ( str len -- ) my-self ihandle>phandle $call-static ;
+: $call-method  push-my-self $call-my-method pop-my-self ;
+: $call-parent  my-parent $call-method ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/little-endian.fs b/qemu-0.15.x/roms/SLOF/slof/fs/little-endian.fs
new file mode 100644
index 0000000..cc9e7f2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/little-endian.fs
@@ -0,0 +1,72 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+deadbeef here l!
+here c@ de = CONSTANT ?bigendian
+here c@ ef = CONSTANT ?littleendian
+
+
+?bigendian [IF]
+
+: l!-le  >r lbflip r> l! ;
+: l at -le  l@ lbflip ;
+
+: w!-le  >r wbflip r> w! ;
+: w at -le  w@ wbflip ;
+
+: rl!-le  >r lbflip r> rl! ;
+: rl at -le  rl@ lbflip ;
+
+: rw!-le  >r wbflip r> rw! ;
+: rw at -le  rw@ wbflip ;
+
+: l!-be  l! ;
+: l at -be  l@ ;
+
+: w!-be  w! ;
+: w at -be  w@ ;
+
+: rl!-be  rl! ;
+: rl at -be  rl@ ;
+
+: rw!-be  rw! ;
+: rw at -be  rw@ ;
+
+
+[ELSE]
+
+: l!-le  l! ;
+: l at -le  l@ ;
+
+: w!-le  w! ;
+: w at -le  w@ ;
+
+: rl!-le  rl! ;
+: rl at -le  rl@ ;
+
+: rw!-le  rw! ;
+: rw at -le  rw@ ;
+
+: l!-be  >r lbflip r> l! ;
+: l at -be  l@ lbflip ;
+
+: w!-be  >r wbflip r> w! ;
+: w at -be  w@ wbflip ;
+
+: rl!-be  >r lbflip r> rl! ;
+: rl at -be  rl@ lbflip ;
+
+: rw!-be  >r wbflip r> rw! ;
+: rw at -be  rw@ wbflip ;
+
+[THEN]
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/loaders.fs b/qemu-0.15.x/roms/SLOF/slof/fs/loaders.fs
new file mode 100644
index 0000000..32cacaf
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/loaders.fs
@@ -0,0 +1,87 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ \\\\\\\\\\\\\\ Global Data
+CREATE bootdevice 2 cells allot bootdevice 2 cells erase
+CREATE bootargs 2 cells allot bootargs 2 cells erase
+CREATE load-list 2 cells allot load-list 2 cells erase
+
+: start-elf ( arg len entry -- )
+   msr@ 7fffffffffffffff and 2000 or ciregs >srr1 ! call-client
+;
+
+: start-elf64 ( arg len entry -- )
+   msr@ 2000 or ciregs >srr1 !
+   dup 8 + @ ciregs >r2 ! @ call-client \ entry point is pointer to .opd
+;
+
+10000000 VALUE LOAD-BASE
+2000000 VALUE FLASH-LOAD-BASE
+
+: set-bootpath
+   s" disk" find-alias
+   dup IF ELSE drop s" boot-device" evaluate find-alias THEN
+   dup IF strdup ELSE 0 THEN
+   encode-string s" bootpath" set-chosen
+;
+
+: set-netbootpath
+   s" net" find-alias
+   ?dup IF strdup encode-string s" bootpath" set-chosen THEN
+;
+
+: set-bootargs
+   skipws 0 parse dup 0= IF
+      2drop s" boot-file" evaluate
+   THEN
+   encode-string s" bootargs" set-chosen
+;
+
+: .(client-exec) ( arg len -- rc )
+   s" snk" romfs-lookup 0<> IF load-elf-file drop start-elf64 client-data
+   ELSE 2drop false THEN
+;
+' .(client-exec) to (client-exec)
+
+: .client-exec ( arg len -- rc ) set-bootargs (client-exec) ;
+' .client-exec to client-exec
+
+: netflash ( -- rc ) s" netflash 2000000 " (parse-line) $cat set-netbootpath
+   client-exec
+;
+
+: netsave  ( "addr len {filename}[,params]" -- rc )
+   (parse-line) dup 0> IF
+      s" netsave " 2swap $cat set-netbootpath client-exec
+   ELSE
+      cr
+      ." Usage: netsave addr len [bootp|dhcp,]filename[,siaddr][,ciaddr][,giaddr][,bootp-retries][,tftp-retries][,use_ci]"
+      cr 2drop
+   THEN
+;
+
+: ping  ( "{device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]}" -- )
+   my-self >r current-node @ >r  \ Save my-self
+   (parse-line) open-dev dup  IF
+      dup to my-self dup ihandle>phandle set-node
+      s" ping" rot ['] $call-method CATCH  IF
+         cr
+         ." Not a pingable device"
+         cr 3drop
+      THEN
+   ELSE
+      cr
+      ." Usage: ping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]"
+      cr drop
+   THEN
+   r> set-node r> to my-self  \ Restore my-self
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/logging.fs b/qemu-0.15.x/roms/SLOF/slof/fs/logging.fs
new file mode 100644
index 0000000..4a31b50
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/logging.fs
@@ -0,0 +1,45 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Words to write to nvram log
+
+defer nvramlog-write-byte
+
+: .nvramlog-write-byte ( byte -- )
+#ifndef DISABLE_NVRAM
+        0 1 asm-cout
+#else
+        drop
+#endif
+;
+
+' .nvramlog-write-byte to nvramlog-write-byte
+
+: nvramlog-write-string ( str len -- )
+   dup 0> IF
+      0 DO dup c@ 
+      nvramlog-write-byte char+ LOOP
+   ELSE
+      drop
+   THEN drop ;
+
+: nvramlog-write-number ( number format -- )
+  0 swap <# 0 ?DO # LOOP #> 
+  nvramlog-write-string ;
+
+: nvramlog-write-string-cr ( str len -- )
+  nvramlog-write-string
+  a nvramlog-write-byte d nvramlog-write-byte ;
+
+\ as long as dual-emit is enabled
+\ the string is written into NVRAM as well!!
+: log-string ( str len -- ) type ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/node.fs b/qemu-0.15.x/roms/SLOF/slof/fs/node.fs
new file mode 100644
index 0000000..085cd9d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/node.fs
@@ -0,0 +1,478 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Device nodes.
+
+VARIABLE device-tree
+VARIABLE current-node
+: get-node  current-node @ dup 0= ABORT" No active device tree node" ;
+
+STRUCT
+  cell FIELD node>peer
+  cell FIELD node>parent
+  cell FIELD node>child
+  cell FIELD node>properties
+  cell FIELD node>words
+  cell FIELD node>instance
+  cell FIELD node>instance-size
+  cell FIELD node>space?
+  cell FIELD node>space
+  cell FIELD node>addr1
+  cell FIELD node>addr2
+  cell FIELD node>addr3
+END-STRUCT
+
+: find-method ( str len phandle -- false | xt true )
+  node>words @ voc-find dup IF link> true THEN ;
+
+\ Instances.
+#include "instance.fs"
+
+1000 CONSTANT max-instance-size
+3000000 CONSTANT space-code-mask
+
+: create-node ( parent -- new )
+  max-instance-size alloc-mem dup max-instance-size erase >r
+  align wordlist >r wordlist >r
+  here 0 , swap , 0 , r> , r> , r> , /instance-header , 0 , 0 , 0 , 0 , ;
+
+: peer    node>peer   @ ;
+: parent  node>parent @ ;
+: child   node>child  @ ;
+: peer  dup IF peer ELSE drop device-tree @ THEN ;
+
+
+: link ( new head -- ) \ link a new node at the end of a linked list
+  BEGIN dup @ WHILE @ REPEAT ! ;
+: link-node ( parent child -- )
+  swap dup IF node>child link ELSE drop device-tree ! THEN ;
+
+\ Set a node as active node.
+: set-node ( phandle -- )
+  current-node @ IF previous THEN
+  dup current-node !
+  ?dup IF node>words @ also context ! THEN
+  definitions ;
+: get-parent  get-node parent ;
+
+
+: new-node ( -- phandle ) \ active node becomes new node's parent;
+                          \ new node becomes active node
+\ XXX: change to get-node, handle root node creation specially
+  current-node @ dup create-node
+  tuck link-node dup set-node ;
+
+: finish-node ( -- )
+\ we should resize the instance template buffer, but that doesn't help with our
+\ current implementation of alloc-mem anyway, so never mind. XXX
+  get-node parent set-node ;
+
+: device-end ( -- )  0 set-node ;
+
+\ Properties.
+CREATE $indent 100 allot  VARIABLE indent 0 indent !
+#include "property.fs"
+
+\ Unit address.
+: #address-cells  s" #address-cells" rot parent get-property
+   ABORT" parent doesn't have a #address-cells property!"
+   decode-int nip nip
+;
+
+\ my-#address-cells returns the #address-cells property of the parent node.
+\ child-#address-cells returns the #address-cells property of the current node.
+
+\ This is confusing in several ways: Remember that a node's address is always
+\ described in the parent's address space, thus the parent's property is taken
+\ into regard, rather than the own.
+
+\ Also, an address-cell here is always a 32bit cell, no matter whether the
+\ "real" cell size is 32bit or 64bit.
+
+: my-#address-cells  ( -- #address-cells )
+   get-node #address-cells
+;
+
+: child-#address-cells  ( -- #address-cells )
+   s" #address-cells" get-node get-property
+   ABORT" node doesn't have a #address-cells property!"
+   decode-int nip nip
+;
+
+: child-#size-cells  ( -- #address-cells )
+   s" #size-cells" get-node get-property
+   ABORT" node doesn't have a #size-cells property!"
+   decode-int nip nip
+;
+
+: encode-phys  ( phys.hi ... phys.low -- prop len )
+   encode-first?  IF  encode-start  ELSE  here 0  THEN
+   my-#address-cells 0 ?DO rot encode-int+ LOOP
+;
+
+: encode-child-phys  ( phys.hi ... phys.low -- prop len )
+   encode-first?  IF  encode-start  ELSE  here 0  THEN
+   child-#address-cells 0 ?DO rot encode-int+ LOOP
+;
+
+: encode-child-size  ( size.hi ... size.low -- prop len )
+   encode-first? IF  encode-start  ELSE  here 0  THEN
+   child-#size-cells 0 ?DO rot encode-int+ LOOP
+;
+
+: decode-phys
+  my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT drop
+  my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ;
+: decode-phys-and-drop
+  my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT 3drop
+  my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ;
+: reg  >r encode-phys r> encode-int+ s" reg" property ;
+
+
+: >space    node>space @ ;
+: >space?   node>space? @ ;
+: >address  dup >r #address-cells dup 3 > IF r@ node>addr3 @ swap THEN
+                                  dup 2 > IF r@ node>addr2 @ swap THEN
+                                      1 > IF r@ node>addr1 @ THEN r> drop ;
+: >unit     dup >r >address r> >space ;
+
+: my-space ( -- phys.hi )
+   my-self ihandle>phandle >space ;
+: my-address  my-self ihandle>phandle >address ;
+: my-unit     my-self ihandle>phandle >unit ;
+
+\ Return lower 64 bit of address
+: my-unit-64 ( -- phys.lo+1|phys.lo )
+   my-unit                                ( phys.lo ... phys.hi )
+   my-self ihandle>phandle #address-cells ( phys.lo ... phys.hi #ad-cells )
+   CASE
+      1   OF EXIT ENDOF
+      2   OF lxjoin EXIT ENDOF
+      3   OF drop lxjoin EXIT ENDOF
+      dup OF 2drop lxjoin EXIT ENDOF
+   ENDCASE
+;
+
+: set-space    get-node dup >r node>space ! true r> node>space? ! ;
+: set-address  my-#address-cells 1 ?DO
+               get-node node>space i cells + ! LOOP ;
+: set-unit     set-space set-address ;
+: set-unit-64 ( phys.lo|phys.hi -- )
+   my-#address-cells 2 <> IF
+      ." set-unit-64: #address-cells <> 2 " abort
+   THEN
+   xlsplit set-unit
+;
+
+\ Never ever use this in actual code, only when debugging interactively.
+\ Thank you.
+: set-args ( arg-str len unit-str len -- )
+           s" decode-unit" get-parent $call-static set-unit set-my-args ;
+
+: $cat-unit  dup parent 0= IF drop EXIT THEN
+             dup >space? not IF drop EXIT THEN
+             dup >r >unit s" encode-unit" r> parent $call-static dup IF
+             dup >r here swap move s" @" $cat here r> $cat
+             ELSE 2drop THEN ;
+
+\ Getting basic info about a node.
+: node>name  dup >r s" name" rot get-property IF r> (u.) ELSE 1- r> drop THEN ;
+: node>qname dup node>name rot ['] $cat-unit CATCH IF drop THEN ;
+: node>path  here 0 rot  BEGIN dup WHILE dup parent REPEAT 2drop
+             dup 0= IF [char] / c, THEN
+             BEGIN dup WHILE [char] / c, node>qname here over allot swap move
+	     REPEAT drop here 2dup - allot over - ;
+
+: interposed? ( ihandle -- flag )
+  \ We cannot actually detect if an instance is interposed; instead, we look
+  \ if an instance is part of the "normal" chain that would be opened by
+  \ open-dev and friends, if there were no interposition.
+  dup instance>parent @ dup 0= IF 2drop false EXIT THEN
+  ihandle>phandle swap ihandle>phandle parent <> ;
+: instance>qname  dup >r interposed? IF s" %" ELSE 0 0 THEN
+                  r@ ihandle>phandle node>qname $cat  r> instance>args 2@
+                  dup IF 2>r s" :" $cat 2r> $cat ELSE 2drop THEN ;
+: instance>qpath \ With interposed nodes.
+  here 0 rot BEGIN dup WHILE dup instance>parent @ REPEAT 2drop
+  dup 0= IF [char] / c, THEN
+  BEGIN dup WHILE [char] / c, instance>qname here over allot swap move
+  REPEAT drop here 2dup - allot over - ;
+: instance>path \ Without interposed nodes.
+  here 0 rot BEGIN dup WHILE
+  dup interposed? 0= IF dup THEN instance>parent @ REPEAT 2drop
+  dup 0= IF [char] / c, THEN
+  BEGIN dup WHILE [char] / c, instance>qname here over allot swap move
+  REPEAT drop here 2dup - allot over - ;
+
+: .node  node>path type ;
+: pwd  get-node .node ;
+
+: .instance instance>qpath type ;
+: .chain    dup instance>parent @ ?dup IF recurse THEN
+            cr dup . instance>qname type ;
+
+
+\ Alias helper
+defer find-node
+: set-alias ( alias-name len device-name len -- )
+    encode-string
+    2swap s" /aliases" find-node ?dup IF
+       set-property
+    ELSE
+       4drop
+    THEN
+;
+
+: find-alias ( alias-name len -- false | dev-path len )
+    s" /aliases" find-node dup IF
+	get-property 0= IF 1- dup 0= IF nip THEN ELSE false THEN
+    THEN ;
+
+: .alias ( alias-name len -- )
+    find-alias dup IF type ELSE ." no alias available" THEN ;
+
+: (.print-alias) ( lfa -- )
+    link> dup >name name>string
+    \ Don't print name property
+    2dup s" name" string=ci IF 2drop drop
+    ELSE cr type space ." : " execute type
+    THEN ;
+
+: (.list-alias) ( phandle -- )
+    node>properties @ cell+ @ BEGIN dup WHILE dup (.print-alias) @ REPEAT drop ;
+
+: list-alias ( -- )
+    s" /aliases" find-node dup IF (.list-alias) THEN ;
+
+: devalias ( "{alias-name}<>{device-specifier}<cr>" -- )
+    parse-word parse-word dup IF set-alias
+    ELSE 2drop dup IF .alias
+    ELSE 2drop list-alias THEN THEN ;
+
+\ sub-alias does a single iteration of an alias at the begining od dev path
+\ expression. de-alias will repeat this until all indirect alising is resolved
+: sub-alias ( arg-str arg-len -- arg' len' | false )
+	2dup
+	2dup [char] / findchar ?dup IF ELSE 2dup [char] : findchar THEN
+	( a l a l [p] -1|0 ) IF nip dup ELSE 2drop 0 THEN >r
+	( a l l p -- R:p | a l -- R:0 )
+	find-alias ?dup IF ( a l a' p' -- R:p | a' l' -- R:0 )
+		r@ IF 2swap r@ - swap r> + swap $cat strdup ( a" l-p+p' -- )
+		ELSE ( a' l' -- R:0 ) r> drop ( a' l' -- ) THEN
+	ELSE ( a l -- R:p | -- R:0 ) r> IF 2drop THEN false ( 0 -- ) THEN
+;
+
+: de-alias ( arg-str arg-len -- arg' len' )
+	BEGIN over c@ [char] / <> dup IF drop 2dup sub-alias ?dup THEN
+	WHILE 2swap 2drop REPEAT
+;
+
+
+\ Display the device tree.
+: +indent ( not-last? -- )
+  IF s" |   " ELSE s"     " THEN $indent indent @ + swap move 4 indent +! ;
+: -indent ( -- )  -4 indent +! ;
+: ls-node ( node -- )
+  cr $indent indent @ type
+  dup peer IF ." |-- " ELSE ." +-- " THEN node>qname type ;
+: (ls) ( node -- )
+  child BEGIN dup WHILE dup ls-node dup child IF
+  dup peer +indent dup recurse -indent THEN peer REPEAT drop ;
+: ls ( -- )  get-node dup cr node>path type (ls) 0 indent ! ;
+
+: show-devs ( {device-specifier}<eol> -- )
+   skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN   ( str len )
+   find-node dup 0= ABORT" No such device path" (ls)
+;
+
+
+VARIABLE interpose-node
+2VARIABLE interpose-args
+: interpose ( arg len phandle -- )  interpose-node ! interpose-args 2! ;
+: open-node ( arg len phandle -- ihandle | 0 )
+  current-node @ >r set-node create-instance set-my-args
+  ( and set unit-addr )
+\ XXX: assume default of success for nodes without open method
+  s" open" ['] $call-my-method CATCH IF 2drop true THEN
+  0= IF my-self destroy-instance 0 to my-self THEN
+  my-self my-parent to my-self r> set-node
+  \ Handle interposition.
+  interpose-node @ IF my-self >r to my-self
+  interpose-args 2@ interpose-node @
+  interpose-node off recurse  r> to my-self THEN ;
+: close-node ( ihandle -- )
+  my-self >r to my-self
+  s" close" ['] $call-my-method CATCH IF 2drop THEN
+  my-self destroy-instance r> to my-self ;
+
+: close-dev ( ihandle -- )
+  my-self >r to my-self
+  BEGIN my-self WHILE my-parent my-self close-node to my-self REPEAT
+  r> to my-self ;
+
+: new-device ( -- )
+  my-self new-node node>instance @ dup to my-self instance>parent !
+  get-node my-self instance>node ! ;
+: finish-device ( -- )
+  ( check for "name" property here, delete this node if not there )
+  finish-node my-parent my-self max-instance-size free-mem to my-self ;
+
+: split ( str len char -- left len right len )
+  >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ;
+: generic-decode-unit ( str len ncells -- addr.lo ... addr.hi )
+  dup >r -rot BEGIN r@ WHILE r> 1- >r [char] , split 2swap
+  $number IF 0 THEN r> swap >r >r REPEAT r> 3drop
+  BEGIN dup WHILE 1- r> swap REPEAT drop ;
+: generic-encode-unit ( addr.lo ... addr.hi ncells -- str len )
+  0 0 rot ?dup IF 0 ?DO rot (u.) $cat s" ," $cat LOOP 1- THEN ;
+: hex-decode-unit ( str len ncells -- addr.lo ... addr.hi )
+  base @ >r hex generic-decode-unit r> base ! ;
+: hex-encode-unit ( addr.lo ... addr.hi ncells -- str len )
+  base @ >r hex generic-encode-unit r> base ! ;
+
+: handle-leading-/ ( path len -- path' len' )
+  dup IF over c@ [char] / = IF 1 /string device-tree @ set-node THEN THEN ;
+: match-name ( name len node -- match? )
+  over 0= IF 3drop true EXIT THEN
+  s" name" rot get-property IF 2drop false EXIT THEN
+  1- string=ci ; \ XXX should use decode-string
+0 VALUE #search-unit   CREATE search-unit 4 cells allot
+: match-unit ( node -- match? )
+  node>space search-unit #search-unit 0 ?DO 2dup @ swap @ <> IF
+  2drop false UNLOOP EXIT THEN cell+ swap cell+ swap LOOP 2drop true ;
+: match-node ( name len node -- match? )
+  dup >r match-name r> match-unit and ; \ XXX e3d
+: find-kid ( name len -- node|0 )
+  dup -1 = IF \ are we supposed to stay in the same node? -> resolve-relatives
+    2drop get-node
+  ELSE
+    get-node child >r BEGIN r@ WHILE 2dup r@ match-node
+    IF 2drop r> EXIT THEN r> peer >r REPEAT
+    r> 3drop false
+  THEN ;
+: set-search-unit ( unit len -- )
+  dup 0= IF to #search-unit drop EXIT THEN
+  s" #address-cells" get-node get-property THROW
+  decode-int to #search-unit 2drop
+  s" decode-unit" get-node $call-static
+  #search-unit 0 ?DO search-unit i cells + ! LOOP ;
+: resolve-relatives ( path len -- path' len' )
+  \ handle ..
+  2dup 2 = swap s" .." comp 0= and IF
+    get-node parent ?dup IF
+      set-node drop -1
+    ELSE
+      s" Already in root node." type
+    THEN
+  THEN
+  \ handle .
+  2dup 1 = swap c@ [CHAR] . = and IF
+    drop -1
+  THEN
+  ;
+: find-component ( path len -- path' len' args len node|0 )
+  [char] / split 2swap ( path'. component. )
+  [char] : split 2swap ( path'. args. node-addr. )
+  [char] @ split ['] set-search-unit CATCH IF 2drop 2drop 0 EXIT THEN
+  resolve-relatives find-kid ;
+
+: .find-node ( path len -- phandle|0 )
+  current-node @ >r
+  handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN
+  BEGIN dup WHILE \ handle one component:
+  find-component ( path len args len node ) dup 0= IF
+  3drop 2drop r> set-node 0 EXIT THEN
+  set-node 2drop REPEAT 2drop
+  get-node r> set-node ;
+' .find-node to find-node
+: find-node ( path len -- phandle|0 ) de-alias find-node ;
+
+: delete-node ( phandle -- )
+   dup node>parent @ node>child @ ( phandle 1st peer )
+   2dup = IF
+     node>peer @ swap node>parent @ node>child !
+     EXIT
+   THEN
+       dup node>peer @
+       BEGIN 2 pick 2dup <> WHILE
+	     drop
+        	nip dup node>peer @
+	   dup 0= IF 2drop drop unloop EXIT THEN
+      REPEAT
+         drop
+    node>peer @ 	swap node>peer !
+      drop
+;
+
+
+: open-dev ( path len -- ihandle|0 )
+  de-alias current-node @ >r
+  handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN
+  my-self >r 0 to my-self
+  0 0 >r >r BEGIN dup WHILE \ handle one component:
+  ( arg len ) r> r> get-node open-node to my-self
+  find-component ( path len args len node ) dup 0= IF
+  3drop 2drop my-self close-dev r> to my-self r> set-node 0 EXIT THEN
+  set-node >r >r REPEAT 2drop
+  \ open final node
+  r> r> get-node open-node to my-self
+  my-self r> to my-self r> set-node ;
+: select-dev  open-dev dup to my-self ihandle>phandle set-node ;
+
+: find-device ( str len -- ) \ set as active node
+  find-node dup 0= ABORT" No such device path" set-node ;
+: dev  skipws 0 parse find-device ;
+
+: (lsprop) ( node --)
+	dup cr $indent indent @ type ."     node: " node>qname type
+	false +indent (.properties) cr -indent ;
+: (show-children) ( node -- )
+    child BEGIN dup WHILE
+	dup (lsprop) dup child IF false +indent dup recurse -indent THEN peer
+    REPEAT drop
+;
+: lsprop ( {device-specifier}<eol> -- )
+   skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN
+   find-device get-node dup dup
+   cr ." node: " node>path type (.properties) cr (show-children) 0 indent ! ;
+
+
+\ node>path does not allot the memory, since it is internally only used
+\ for typing.
+\ The external variant needs to allot memory !
+
+: (node>path) node>path ;
+
+: node>path ( phandle -- str len )
+   node>path dup allot
+;
+
+\ Support for support packages.
+
+\ The /packages node.
+0 VALUE packages
+
+\ We can't use the standard find-node stuff, as we are required to find the
+\ newest (i.e., last in our tree) matching package, not just any.
+: find-package  ( name len -- false | phandle true )
+  0 >r packages child BEGIN dup WHILE dup >r node>name 2over string=ci r> swap
+  IF r> drop dup >r THEN peer REPEAT 3drop r> dup IF true THEN ;
+
+: open-package ( arg len phandle -- ihandle | 0 )  open-node ;
+: close-package ( ihandle -- )  close-node ;
+: $open-package ( arg len name len -- ihandle | 0 )
+  find-package IF open-package ELSE 2drop false THEN ;
+
+
+\ device tree translate-address
+#include <translate.fs>
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/nvram.fs b/qemu-0.15.x/roms/SLOF/slof/fs/nvram.fs
new file mode 100644
index 0000000..322d858
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/nvram.fs
@@ -0,0 +1,189 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+51 CONSTANT nvram-partition-type-cpulog
+\ types 53-55 are omitted because they have been used for
+\ storing binary tables in the past
+60 CONSTANT nvram-partition-type-sas
+61 CONSTANT nvram-partition-type-sms
+6e CONSTANT nvram-partition-type-debug
+6f CONSTANT nvram-partition-type-history
+70 CONSTANT nvram-partition-type-common
+7f CONSTANT nvram-partition-type-freespace
+a0 CONSTANT nvram-partition-type-linux
+
+: rztype ( str len -- ) \ stop at zero byte, read with nvram-c@
+   0 DO
+      dup i + nvram-c@ ?dup IF ( str char )
+         emit
+      ELSE                     ( str )
+         drop UNLOOP EXIT
+      THEN
+   LOOP
+;
+
+create tmpStr 500 allot
+: rzcount ( zstr -- str len )
+   dup tmpStr >r BEGIN
+      dup nvram-c@ dup r> dup 1+ >r c!
+   WHILE
+      char+
+   REPEAT
+   r> drop over - swap drop tmpStr swap
+;
+
+: calc-header-cksum ( offset -- cksum )
+   dup nvram-c@
+   10 2 DO
+      over I + nvram-c@ +
+   LOOP
+   wbsplit + nip
+;
+
+: bad-header? ( offset -- flag )
+   dup 2+ nvram-w@        ( offset length )
+   0= IF                  ( offset )
+      drop true EXIT      ( )
+   THEN
+   dup calc-header-cksum  ( offset checksum' )
+   swap 1+ nvram-c@       ( checksum ' checksum )
+   <>                     ( flag )
+;
+
+: .header ( offset -- )
+   cr                         ( offset )
+   dup bad-header? IF         ( offset )
+      ."   BAD HEADER -- trying to print it anyway" cr
+   THEN
+   space                      ( offset )
+   \ print type
+   dup nvram-c@ 2 0.r         ( offset )
+   space space                ( offset )
+   \ print length
+   dup 2+ nvram-w@ 10 * 5 .r  ( offset )
+   space space                ( offset )
+   \ print name
+   4 + 0c rztype              ( )
+;
+
+: .headers ( -- )
+   cr cr ." Type  Size  Name"
+   cr ." ========================"
+   0 BEGIN                      ( offset )
+      dup nvram-c@              ( offset type )
+   WHILE
+      dup .header               ( offset )
+      dup 2+ nvram-w@ 10 * +    ( offset offset' )
+      dup nvram-size < IF       ( offset )
+      ELSE
+	 drop EXIT              ( )
+      THEN
+   REPEAT
+   drop                         ( )
+   cr cr
+;
+
+: reset-nvram ( -- )
+   internal-reset-nvram
+;
+
+: dump-partition     ['] nvram-c@      1 (dump) ;
+
+: type-no-zero ( addr len -- )
+   0 DO
+      dup I + dup nvram-c@ 0= IF drop ELSE nvram-c@ emit THEN
+   LOOP
+   drop
+;
+
+: type-no-zero-part ( from-str cnt-str addr len )
+   0 DO
+      dup i + dup nvram-c@ 0= IF
+         drop
+      ELSE
+         ( from-str cnt-str addr addr+i )
+         ( from-str==0 AND cnt-str > 0 )
+         3 pick 0= 3 pick 0 > AND IF
+            dup 1 type-no-zero
+         THEN
+
+         nvram-c@ a = IF
+            2 pick 0= IF
+               over 1- 0 max
+               rot drop swap
+            THEN
+            2 pick 1- 0 max
+            3 roll drop rot rot
+            ( from-str-- cnt-str-- addr addr+i )
+         THEN
+      THEN
+   LOOP
+   drop
+;
+
+: (dmesg-prepare) ( base-addr -- base-addr' addr len act-off )
+   10 - \ go back to header
+   dup 14 + nvram-l@ dup >r
+   ( base-addr act-off ) ( R: act-off )
+   over over over + swap 10 + nvram-w@ + >r
+   ( base-addr act-off ) ( R:  act-off nvram-act-addr )
+   over 2 + nvram-w@ 10 * swap - over swap
+   ( base-addr base-addr start-size ) ( R:  act-off nvram-act-addr )
+   r> swap rot 10 + nvram-w@ - r>
+;
+
+: .dmesg ( base-addr -- )
+   (dmesg-prepare) >r
+   ( base-addr addr len )
+   cr type-no-zero
+   ( base-addr ) ( R: act-off )
+   dup 10 + nvram-w@ + r> type-no-zero
+;
+
+: .dmesg-part ( from-str cnt-str base-addr -- )
+   (dmesg-prepare) >r
+   ( from-str cnt-str base-addr addr len )
+   >r >r -rot r> r>
+   ( base-addr from-str cnt-str addr len )
+   cr type-no-zero-part rot
+   ( base-addr ) ( R: act-off )
+   dup 10 + nvram-w@ + r> type-no-zero-part
+;
+
+: dmesg-part ( from-str cnt-str -- left-from-str left-cnt-str )
+   2dup
+   s" ibm,BE0log" get-named-nvram-partition IF
+      s" ibm,CPU0log" get-named-nvram-partition IF
+         2drop EXIT
+      THEN
+   THEN
+   drop .dmesg-part nip nip
+;
+
+: dmesg2 ( -- )
+   s" ibm,BE1log" get-named-nvram-partition IF
+      s" ibm,CPU1log" get-named-nvram-partition IF
+         ." No log partition." cr EXIT
+      THEN
+   THEN
+   drop .dmesg
+;
+
+: dmesg ( -- )
+   s" ibm,BE0log" get-named-nvram-partition IF
+      s" ibm,CPU0log" get-named-nvram-partition IF
+         ." No log partition." cr EXIT
+      THEN
+   THEN
+   drop .dmesg
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages.fs
new file mode 100644
index 0000000..a31be2e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages.fs
@@ -0,0 +1,62 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ =============================================================================
+\                               SUPPORT PACKAGES
+\ =============================================================================
+
+
+s" packages" device-name
+get-node to packages
+
+\   new-device
+\   #include "packages/filler.fs"
+\   finish-device
+
+new-device
+#include "packages/deblocker.fs"
+finish-device
+
+new-device
+#include "packages/disk-label.fs"
+finish-device
+
+new-device
+#include "packages/fat-files.fs"
+finish-device
+
+new-device
+#include "packages/rom-files.fs"
+finish-device
+
+new-device
+#include "packages/ext2-files.fs"
+finish-device
+
+new-device
+#include "packages/obp-tftp.fs"
+finish-device
+
+new-device
+#include "packages/iso-9660.fs"
+finish-device
+
+\ new-device
+\ #include "packages/scsi.fs"
+\ finish-device
+
+new-device
+#include "packages/bulk.fs"
+finish-device
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/bulk.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/bulk.fs
new file mode 100644
index 0000000..06d7eae
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/bulk.fs
@@ -0,0 +1,87 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" bulk" device-name
+
+
+\ standard open firmare method
+
+
+: open  true  ;
+
+\ standard open firmare method
+
+
+: close ;
+
+
+\ -------------------------------------------------
+\	Locals
+\ ------------------------------------------------
+
+
+8 chars alloc-mem VALUE setup-packet
+
+
+\ --------------------------------------------------
+\ signature --->4bytes offset --->0
+\ tag       --->4bytes offset --->4
+\ trans-len --->4bytes offset --->8
+\ dir-flag  --->1byte  offset --->c
+\ lun       --->1byte  offset --->d
+\ comm-len  --->1byte  offset --->e
+\ --------------------------------------------------
+
+
+0 VALUE cbw-addr
+: build-cbw ( address tag transfer-len direction lun command-len -- )
+   5 pick TO cbw-addr  ( address tag transfer-len direction lun command-len )
+   cbw-addr 0f erase   ( address tag transfer-len direction lun command-len )
+   cbw-addr e + c!     ( address tag transfer-len direction lun )
+   cbw-addr d + c!     ( address tag transfer-len direction )
+   cbw-addr c + c!     ( address tag transfer-len )
+   cbw-addr 8 + l!-le  ( address tag )
+   cbw-addr 4 + l!-le  ( address )
+   43425355 cbw-addr l!-le ( address )
+   drop  ;
+
+
+\ ---------------------------------------------------
+\ signature --->4bytes offset --->0
+\ tag       --->4bytes offset --->4
+\ residue   --->4bytes offset --->8
+\ status    --->1byte  offset --->c
+\ ---------------------------------------------------
+
+
+0 VALUE csw-addr
+: analyze-csw ( address -- residue tag true|reason false )
+   TO csw-addr
+   csw-addr l at -le 53425355 =  IF
+      csw-addr c + c@ dup 0=  IF ( reason )
+         drop
+         csw-addr 8 + l at -le ( residue )
+         csw-addr 4 + l at -le ( residue tag ) \ command  block tag
+         TRUE               ( residue tag TRUE )
+      ELSE
+         FALSE              ( reason FALSE )
+      THEN
+   ELSE
+      FALSE                 ( FALSE )
+   THEN
+   csw-addr 0c erase
+;
+
+: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- )
+  s" bulk-reset-recovery-procedure" $call-parent
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/deblocker.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/deblocker.fs
new file mode 100644
index 0000000..0b29079
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/deblocker.fs
@@ -0,0 +1,61 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ =============================================================================
+\ =============================================================================
+
+
+\ The deblocker.  Allows block devices to be used as a (seekable) byte device.
+
+s" deblocker" device-name
+
+INSTANCE VARIABLE offset
+INSTANCE VARIABLE block-size
+INSTANCE VARIABLE max-transfer
+INSTANCE VARIABLE my-block
+INSTANCE VARIABLE adr
+INSTANCE VARIABLE len
+
+: open
+  s" block-size" ['] $call-parent CATCH IF 2drop false EXIT THEN
+  block-size !
+  s" max-transfer" ['] $call-parent CATCH IF 2drop false EXIT THEN
+  max-transfer !
+  block-size @ alloc-mem my-block !
+  0 offset !
+  true ;
+: close  my-block @ block-size @ free-mem ;
+
+: seek ( lo hi -- status ) \ XXX: perhaps we should fail if the underlying
+                           \      device would fail at this offset
+  lxjoin offset !  0 ;
+: block+remainder ( -- block# remainder )  offset @ block-size @ u/mod swap ;
+: read-blocks ( addr block# #blocks -- actual )  s" read-blocks" $call-parent ;
+: read ( addr len -- actual )
+  dup >r  len ! adr !
+  \ First, handle a partial block at the start.
+  block+remainder dup IF ( block# offset-in-block )
+  >r my-block @ swap 1 read-blocks drop
+  my-block @ r@ + adr @ block-size @ r> - len @ min dup >r move
+  r> dup negate len +! dup adr +! offset +! ELSE 2drop THEN
+
+  \ Now, in a loop read max. max-transfer sized runs of whole blocks.
+  BEGIN len @ block-size @ >= WHILE
+  adr @ block+remainder drop len @ max-transfer @ min block-size @ / read-blocks
+  block-size @ * dup negate len +! dup adr +! offset +! REPEAT
+
+  \ And lastly, handle a partial block at the end.
+  len @ IF my-block @ block+remainder drop 1 read-blocks drop
+  my-block @ adr @ len @ move THEN
+
+  r> ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/disk-label.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/disk-label.fs
new file mode 100644
index 0000000..ca4b5b4
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/disk-label.fs
@@ -0,0 +1,521 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Set debug-disk-label? to true to get debug messages for the disk-label code.
+false VALUE debug-disk-label?
+
+\ This value defines the maximum number of blocks (512b) to load from a PREP
+\ partition. This is required to keep the load time in reasonable limits if the
+\ PREP partition becomes big.
+\ If we ever want to put a large kernel with initramfs from a PREP partition
+\ we might need to increase this value. The default value is 16384 blocks (8MB)
+d# 16384 value max-prep-partition-blocks
+
+s" disk-label" device-name
+
+0 INSTANCE VALUE partition
+0 INSTANCE VALUE part-offset
+
+0 INSTANCE VALUE part-start
+0 INSTANCE VALUE lpart-start
+0 INSTANCE VALUE part-size
+0 INSTANCE VALUE dos-logical-partitions
+
+0 INSTANCE VALUE block-size
+0 INSTANCE VALUE block
+
+0 INSTANCE VALUE args
+0 INSTANCE VALUE args-len
+
+
+INSTANCE VARIABLE block#  \ variable to store logical sector#
+INSTANCE VARIABLE hit#    \ partition counter
+INSTANCE VARIABLE success-flag
+
+\ ISO9660 specific information
+0ff constant END-OF-DESC
+3 constant  PARTITION-ID
+48 constant VOL-PART-LOC
+
+
+\ DOS partition label (MBR) specific structures
+
+STRUCT
+       1b8 field mbr>boot-loader
+        /l field mbr>disk-signature
+        /w field mbr>null
+        40 field mbr>partition-table
+        /w field mbr>magic
+
+CONSTANT /mbr
+
+STRUCT
+        /c field part-entry>active
+        /c field part-entry>start-head
+        /c field part-entry>start-sect
+        /c field part-entry>start-cyl
+        /c field part-entry>id
+        /c field part-entry>end-head
+        /c field part-entry>end-sect
+        /c field part-entry>end-cyl
+        /l field part-entry>sector-offset
+        /l field part-entry>sector-count
+
+CONSTANT /partition-entry
+
+
+\ Defined by IEEE 1275-1994 (3.8.1)
+
+: offset ( d.rel -- d.abs )
+   part-offset 0 d+
+;
+
+: seek  ( pos.lo pos.hi -- status )
+   offset
+   debug-disk-label? IF 2dup ." seek-parent: pos.hi=0x" u. ." pos.lo=0x" u. THEN
+   s" seek" $call-parent
+   debug-disk-label? IF dup ." status=" . cr THEN
+;
+
+: read ( addr len -- actual )
+   debug-disk-label? IF 2dup swap ." read-parent: addr=0x" u. ." len=" .d THEN
+   s" read" $call-parent
+   debug-disk-label? IF dup ." actual=" .d cr THEN
+;
+
+
+\ read sector to array "block"
+: read-sector ( sector-number -- )
+   \ block-size is 0x200 on disks, 0x800 on cdrom drives
+   block-size * 0 seek drop      \ seek to sector
+   block block-size read drop    \ read sector
+;
+
+: (.part-entry) ( part-entry )
+   cr ." part-entry>active:        " dup part-entry>active c@ .d
+   cr ." part-entry>start-head:    " dup part-entry>start-head c@ .d
+   cr ." part-entry>start-sect:    " dup part-entry>start-sect c@ .d
+   cr ." part-entry>start-cyl:     " dup part-entry>start-cyl  c@ .d
+   cr ." part-entry>id:            " dup part-entry>id c@ .d
+   cr ." part-entry>end-head:      " dup part-entry>end-head c@ .d
+   cr ." part-entry>end-sect:      " dup part-entry>end-sect c@ .d
+   cr ." part-entry>end-cyl:       " dup part-entry>end-cyl c@ .d
+   cr ." part-entry>sector-offset: " dup part-entry>sector-offset l at -le .d
+   cr ." part-entry>sector-count:  " dup part-entry>sector-count l at -le .d
+   cr
+;
+
+: (.name) r@ begin cell - dup @ <colon> = UNTIL xt>name cr type space ;
+
+: init-block ( -- )
+   s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN
+   to block-size
+   d# 2048 alloc-mem
+   dup d# 2048 erase
+   to block
+   debug-disk-label? IF
+      ." init-block: block-size=" block-size .d ." block=0x" block u. cr
+   THEN
+;
+
+
+\ This word returns true if the currently loaded block has _NO_ MBR magic
+: no-mbr? ( -- true|false )
+   0 read-sector block mbr>magic w at -le aa55 <>
+;
+
+: pc-extended-partition? ( part-entry-addr -- true|false )
+   part-entry>id c@      ( id )
+   dup 5 = swap          ( true|false id )
+   dup f = swap          ( true|false true|false id )
+   85 =                  ( true|false true|false true|false )
+   or or                 ( true|false )
+;
+
+: partition>part-entry ( partition -- part-entry )
+   1- /partition-entry * block mbr>partition-table +
+;
+
+: partition>start-sector ( partition -- sector-offset )
+   partition>part-entry part-entry>sector-offset l at -le
+;
+
+: count-dos-logical-partitions ( -- #logical-partitions )
+   no-mbr? IF 0 EXIT THEN
+   0 5 1 DO                                ( current )
+      i partition>part-entry               ( current part-entry )
+      dup pc-extended-partition? IF
+         part-entry>sector-offset l at -le    ( current sector )
+         dup to part-start to lpart-start  ( current )
+         BEGIN
+            part-start read-sector          \ read EBR
+            1 partition>start-sector IF
+               \ ." Logical Partition found at " part-start .d cr
+               1+
+            THEN \ another logical partition
+            2 partition>start-sector
+            ( current relative-sector )
+            ?dup IF lpart-start + to part-start false ELSE true THEN
+         UNTIL
+      ELSE
+         drop
+      THEN
+   LOOP
+;
+
+: (get-dos-partition-params) ( ext-part-start part-entry -- offset count active? id )
+   dup part-entry>sector-offset l at -le rot + swap ( offset part-entry )
+   dup part-entry>sector-count l at -le swap        ( offset count part-entry )
+   dup part-entry>active c@ 80 = swap            ( offset count active? part-entry )
+   part-entry>id c@                              ( offset count active? id )
+;
+
+: find-dos-partition ( partition# -- false | offset count active? id true )
+   to partition 0 to part-start 0 to part-offset
+
+   \ no negative partitions
+   partition 0<= IF 0 to partition false EXIT THEN
+
+   \ load MBR and check it
+   no-mbr? IF 0 to partition false EXIT THEN
+
+   partition 4 <= IF \ Is this a primary partition?
+      0 partition partition>part-entry
+      (get-dos-partition-params)
+      \ FIXME sanity checks?
+      true EXIT
+   ELSE
+      partition 4 - 0 5 1 DO                      ( logical-partition current )
+         i partition>part-entry                   ( log-part current part-entry )
+         dup pc-extended-partition? IF
+            part-entry>sector-offset l at -le        ( log-part current sector )
+            dup to part-start to lpart-start      ( log-part current )
+            BEGIN
+               part-start read-sector             \ read EBR
+               1 partition>start-sector IF        \ first partition entry
+                  1+ 2dup = IF                    ( log-part current )
+                     2drop
+                     part-start 1 partition>part-entry
+                     (get-dos-partition-params)
+                     true UNLOOP EXIT
+                  THEN
+                  2 partition>start-sector
+                  ( log-part current relative-sector )
+
+                  ?dup IF lpart-start + to part-start false ELSE true THEN
+               ELSE
+                  true
+               THEN
+            UNTIL
+         ELSE
+            drop
+         THEN
+      LOOP
+      2drop false
+   THEN
+;
+
+: try-dos-partition ( -- okay? )
+   \ Read partition table and check magic.
+   no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN
+
+   count-dos-logical-partitions TO dos-logical-partitions
+
+   debug-disk-label? IF
+      ." Found " dos-logical-partitions .d ." logical partitions" cr
+      ." Partition = " partition .d cr
+   THEN
+
+   partition 1 5 dos-logical-partitions +
+   within 0= IF
+      cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT
+   THEN
+
+   \ Could/should check for valid partition here...  the magic is not enough really.
+
+   \ Get the partition offset.
+
+   partition find-dos-partition IF
+     ( offset count active? id )
+     2drop drop
+     block-size * to part-offset
+     true
+   ELSE
+     false
+   THEN
+;
+
+\ Check for an ISO-9660 filesystem on the disk
+\ : try-iso9660-partition ( -- true|false )
+\ implement me if you can ;-)
+\ ;
+
+
+\ Check for an ISO-9660 filesystem on the disk
+\ (cf. CHRP IEEE 1275 spec., chapter 11.1.2.3)
+: has-iso9660-filesystem  ( -- TRUE|FALSE )
+   \ Seek to the begining of logical 2048-byte sector 16
+   \ refer to Chapter C.11.1 in PAPR 2.0 Spec
+   \ was: 10 read-sector, but this might cause trouble if you
+   \ try booting an ISO image from a device with 512b sectors.
+   10 800 * 0 seek drop      \ seek to sector
+   block 800 read drop       \ read sector
+   \ Check for CD-ROM volume magic:
+   block c@ 1 =
+   block 1+ 5 s" CD001"  str=
+   and
+   dup IF 800 to block-size THEN
+;
+
+
+\ Load from first active DOS boot partition.
+
+\ NOTE: block-size is always 512 bytes for DOS partition tables.
+
+: load-from-dos-boot-partition ( addr -- size )
+   no-mbr? IF FALSE EXIT THEN  \ read MBR and check for DOS disk-label magic
+
+   count-dos-logical-partitions TO dos-logical-partitions
+
+   debug-disk-label? IF
+      ." Found " dos-logical-partitions .d ." logical partitions" cr
+      ." Partition = " partition .d cr
+   THEN
+
+   \ Now walk through the partitions:
+   5 dos-logical-partitions + 1 DO
+      \ ." checking partition " i .
+      i find-dos-partition IF        ( addr offset count active? id )
+         41 = and                    ( addr offset count prep-boot-part? )
+         IF                          ( addr offset count )
+            max-prep-partition-blocks min  \ reduce load size
+            swap                     ( addr count offset )
+            block-size * to part-offset
+            0 0 seek drop            ( addr offset )
+            block-size * read        ( size )
+            UNLOOP EXIT
+         ELSE
+            2drop                    ( addr )
+         THEN
+      THEN
+   LOOP
+   drop 0
+;
+
+
+\ load from a bootable partition
+
+: load-from-boot-partition ( addr -- size )
+   load-from-dos-boot-partition
+   \ More boot partition formats ...
+;
+
+
+
+\ Extract the boot loader path from a bootinfo.txt file
+\ In: address and length of buffer where the bootinfo.txt has been loaded to.
+\ Out: string address and length of the boot loader (within the input buffer)
+\      or a string with length = 0 when parsing failed.
+
+\ Here is a sample bootinfo file:
+\ <chrp-boot>
+\   <description>Linux Distribution</description>
+\   <os-name>Linux</os-name>
+\   <boot-script>boot &device;:1,\boot\yaboot.ibm</boot-script>
+\   <icon size=64,64 color-space=3,3,2>
+\     <bitmap>[..]</bitmap>
+\   </icon>
+\ </chrp-boot>
+
+: parse-bootinfo-txt  ( addr len -- str len )
+   2dup s" <boot-script>" find-substr       ( addr len pos1 )
+   2dup = IF
+      \ String not found
+      3drop 0 0 EXIT
+   THEN
+   dup >r - swap r> + swap                  ( addr1 len1 )
+   2dup [char] \ findchar drop              ( addr1 len1 pos2 )
+   dup >r - swap r> + swap                  ( addr2 len2 )
+   2dup s" </boot-script>" find-substr nip  ( addr2 len3 )
+;
+
+\ Try to load \ppc\bootinfo.txt from the disk (used mainly on CD-ROMs), and if
+\ available, get the boot loader path from this file and load it.
+\ See the "CHRP system binding to IEEE 1275" specification for more information
+\ about bootinfo.txt. An example file can be found in the comment of
+\ parse-bootinfo-txt ( addr len -- str len )
+
+: load-chrp-boot-file ( addr -- size )
+   \ Create bootinfo.txt path name and load that file:
+   my-self parent ihandle>phandle node>path
+   s" :\ppc\bootinfo.txt" $cat strdup       ( addr str len )
+   open-dev dup 0= IF 2drop 0 EXIT THEN
+   >r dup                                   ( addr addr R:ihandle )
+   dup s" load" r@ $call-method             ( addr addr size R:ihandle )
+   r> close-dev                             ( addr addr size )
+
+   \ Now parse the information from bootinfo.txt:
+   parse-bootinfo-txt                       ( addr fnstr fnlen )
+   dup 0= IF 3drop 0 EXIT THEN
+   \ Create the full path to the boot loader:
+   my-self parent ihandle>phandle node>path ( addr fnstr fnlen nstr nlen )
+   s" :" $cat 2swap $cat strdup             ( addr str len )
+   \ Update the bootpath:
+   2dup encode-string s" bootpath" set-chosen
+   \ And finally load the boot loader itself:
+   open-dev dup 0= IF ." failed to load CHRP boot loader." 2drop 0 EXIT THEN
+   >r s" load" r@ $call-method              ( size R:ihandle )
+   r> close-dev                             ( size )
+;
+
+\ parse partition number from my-args
+
+\ my-args has the following format
+\ [<partition>[,<path>]]
+
+\ | example my-args  | example boot command      |
+\ +------------------+---------------------------+
+\ | 1,\boot\vmlinuz  | boot disk:1,\boot\vmlinuz |
+\ | 2                | boot disk:2               |
+
+\ 0 means the whole disk, this is the same behavior
+\ as if no partition is specified (yaboot wants this).
+
+: parse-partition ( -- okay? )
+   0 to partition
+   0 to part-offset
+
+   my-args to args-len to args
+
+   \ Fix up the "0" thing yaboot does.
+   args-len 1 = IF args c@ [char] 0 = IF 0 to args-len THEN THEN
+
+   \ Check for "full disk" arguments.
+   my-args [char] , findchar 0= IF true EXIT THEN drop \ no comma
+   my-args [char] , split to args-len to args
+   dup 0= IF 2drop true EXIT THEN \ no first argument
+
+   \ Check partition #.
+   base @ >r decimal $number r> base !
+   IF cr ." Not a partition #" false EXIT THEN
+
+   \ Store part #, done.
+   to partition
+   true
+;
+
+
+\ try-files and try-partitions
+
+: (interpose-filesystem) ( str len -- )
+   find-package IF args args-len rot interpose THEN
+;
+
+: try-dos-files ( -- found? )
+   no-mbr? IF false EXIT THEN
+
+   \ block 0 byte 0-2 is a jump instruction in all FAT
+   \ filesystems.
+   \ e9 and eb are jump instructions in x86 assembler.
+   block c@ e9 <> IF
+      block c@ eb <>
+      block 2+ c@ 90 <> or
+      IF false EXIT THEN
+   THEN
+   s" fat-files" (interpose-filesystem)
+   true
+;
+
+: try-ext2-files ( -- found? )
+   2 read-sector               \ read first superblock
+   block d# 56 + w at -le         \ fetch s_magic
+   ef53 <> IF false EXIT THEN  \ s_magic found?
+   s" ext2-files" (interpose-filesystem)
+   true
+;
+
+
+: try-iso9660-files
+   has-iso9660-filesystem 0= IF false exit THEN
+   s" iso-9660" (interpose-filesystem)
+   true
+;
+
+: try-files ( -- found? )
+   \ If no path, then full disk.
+   args-len 0= IF true EXIT THEN
+
+   try-dos-files IF true EXIT THEN
+   try-ext2-files IF true EXIT THEN
+   try-iso9660-files IF true EXIT THEN
+
+   \ ... more filesystem types here ...
+
+   false
+;
+
+: try-partitions ( -- found? )
+   try-dos-partition IF try-files EXIT THEN
+   \ try-iso9660-partition IF try-files EXIT THEN
+   \ ... more partition types here...
+   false
+;
+
+\ Interface functions for disk-label package
+\ as defined by IEEE 1275-1994 3.8.1
+
+: close ( -- )
+   debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN
+   block d# 2048 free-mem
+;
+
+
+: open ( -- true|false )
+   init-block
+
+   parse-partition 0= IF
+      close
+      false EXIT
+   THEN
+
+   partition IF
+       try-partitions
+   ELSE
+       try-files
+   THEN
+   dup 0= IF debug-disk-label? IF ." not found." cr THEN close THEN \ free memory again
+;
+
+
+\ Boot & Load w/o arguments is assumed to be boot from boot partition
+
+: load ( addr -- size )
+   debug-disk-label? IF
+      ." load: " dup u. cr
+   THEN
+
+   args-len IF
+      TRUE ABORT" Load done w/o filesystem"
+   ELSE
+      partition IF
+         0 0 seek drop
+         200000 read
+      ELSE
+         has-iso9660-filesystem IF
+             dup load-chrp-boot-file ?dup 0 > IF nip EXIT THEN
+         THEN
+         load-from-boot-partition
+         dup 0= ABORT" No boot partition found"
+      THEN
+   THEN
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/ext2-files.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/ext2-files.fs
new file mode 100644
index 0000000..454e919
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/ext2-files.fs
@@ -0,0 +1,140 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+s" ext2-files" device-name
+
+INSTANCE VARIABLE first-block
+INSTANCE VARIABLE block-size
+INSTANCE VARIABLE inodes/group
+
+INSTANCE VARIABLE group-descriptors
+
+: seek  s" seek" $call-parent ;
+: read  s" read" $call-parent ;
+
+INSTANCE VARIABLE data
+INSTANCE VARIABLE #data
+
+: free-data
+  data @ ?dup IF #data @ free-mem  0 data ! THEN ;
+: read-data ( offset size -- )
+  free-data  dup #data ! alloc-mem data !
+  xlsplit seek            -2 and ABORT" ext2-files read-data: seek failed"
+  data @ #data @ read #data @ <> ABORT" ext2-files read-data: read failed" ;
+
+: read-block ( block# -- )
+  block-size @ * block-size @ read-data ;
+
+INSTANCE VARIABLE inode
+INSTANCE VARIABLE file-len
+INSTANCE VARIABLE blocks
+INSTANCE VARIABLE #blocks
+INSTANCE VARIABLE ^blocks
+INSTANCE VARIABLE #blocks-left
+: blocks-read ( n -- )  dup negate #blocks-left +! 4 * ^blocks +! ;
+: read-indirect-blocks ( indirect-block# -- )
+  read-block data @ data off
+  dup #blocks-left @ 4 * block-size @ min dup >r ^blocks @ swap move
+  r> 2 rshift blocks-read block-size @ free-mem ;
+: read-double-indirect-blocks ( double-indirect-block# -- )
+\ TBD
+;
+: read-triple-indirect-blocks ( triple-indirect-block# -- )
+\ TBD
+;
+: read-block#s ( -- )
+  blocks @ ?dup IF #blocks @ 4 * free-mem THEN
+  inode @ 4 + l at -le file-len !
+  file-len @ block-size @ // #blocks !
+  #blocks @ 4 * alloc-mem blocks !
+  blocks @ ^blocks !  #blocks @ #blocks-left !
+  #blocks-left @ c min \ # direct blocks
+  inode @ 28 + over 4 * ^blocks @ swap move blocks-read
+  #blocks-left @ IF inode @ 58 + l at -le read-indirect-blocks THEN
+  #blocks-left @ IF inode @ 5c + l at -le read-double-indirect-blocks THEN
+  #blocks-left @ IF inode @ 60 + l at -le read-triple-indirect-blocks THEN ;
+: read-inode ( inode# -- )
+  1- inodes/group @ u/mod \ # in group, group #
+  20 * group-descriptors @ + 8 + l at -le block-size @ * \ # in group, inode table
+  swap 80 * + xlsplit seek drop  inode @ 80 read drop ;
+
+: .rwx ( bits last-char-if-special special? -- )
+  rot dup 4 and IF ." r" ELSE ." -" THEN
+      dup 2 and IF ." w" ELSE ." -" THEN
+  swap IF 1 and 0= IF upc THEN emit ELSE
+          1 and IF ." x" ELSE ." -" THEN drop THEN ;
+CREATE mode-chars 10 allot s" ?pc?d?b?-?l?s???" mode-chars swap move
+: .mode ( mode -- )
+  dup c rshift f and mode-chars + c@ emit
+  dup 6 rshift 7 and over 800 and 73 swap .rwx
+  dup 3 rshift 7 and over 400 and 73 swap .rwx
+  dup          7 and swap 200 and 74 swap .rwx ;
+: .inode ( -- )
+  base @ >r decimal
+  inode @      w at -le .mode \ file mode
+  inode @ 1a + w at -le 5 .r \ link count
+  inode @ 02 + w at -le 9 .r \ uid
+  inode @ 18 + w at -le 9 .r \ gid
+  inode @ 04 + l at -le 9 .r \ size
+  r> base ! ;
+
+: do-super ( -- )
+  400 400 read-data
+  data @ 14 + l at -le first-block !
+  400 data @ 18 + l at -le lshift block-size !
+  data @ 28 + l at -le inodes/group !
+  first-block @ 1+ read-block data @ group-descriptors ! data off ;
+
+INSTANCE VARIABLE current-pos
+
+: read ( adr len -- actual )
+  file-len @ current-pos @ - min \ can't go past end of file
+  current-pos @ block-size @ u/mod 4 * blocks @ + l at -le read-block
+  block-size @ over - rot min >r ( adr off r: len )
+  data @ + swap r@ move r> dup current-pos +! ;
+: read ( adr len -- actual )
+  ( check if a file is selected, first )
+  dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" ext2-files: read failed"
+  /string REPEAT 2drop r> ;
+: seek ( lo hi -- status )
+  lxjoin dup file-len @ > IF drop true EXIT THEN current-pos ! false ;
+: load ( adr -- len )
+  file-len @ read dup file-len @ <> ABORT" ext2-files: failed loading file" ;
+
+: .name ( adr -- )  dup 8 + swap 6 + c@ type ;
+: read-dir ( inode# -- adr )
+  read-inode read-block#s file-len @ alloc-mem
+  0 0 seek ABORT" ext2-files read-dir: seek failed"
+  dup file-len @ read file-len @ <> ABORT" ext2-files read-dir: read failed" ;
+: .dir ( inode# -- )
+  read-dir dup BEGIN 2dup file-len @ - > over l at -le tuck and WHILE
+  cr dup 8 0.r space read-inode .inode space space dup .name
+  dup 4 + w at -le + REPEAT 2drop file-len @ free-mem ;
+: (find-file) ( adr name len -- inode#|0 )
+  2>r dup BEGIN 2dup file-len @ - > over l at -le and WHILE
+  dup 8 + over 6 + c@ 2r@ str= IF 2r> 2drop nip l at -le EXIT THEN
+  dup 4 + w at -le + REPEAT 2drop 2r> 2drop 0 ;
+: find-file ( inode# name len -- inode#|0 )
+  2>r read-dir dup 2r> (find-file) swap file-len @ free-mem ;
+: find-path ( inode# name len -- inode#|0 )
+  dup 0= IF 3drop 0 ."  empty name " EXIT THEN
+  over c@ [char] \ = IF 1 /string ."  slash " RECURSE EXIT THEN
+  [char] \ split 2>r find-file ?dup 0= IF
+  2r> 2drop false ."  not found " EXIT THEN
+  r@ 0<> IF 2r> ."  more... " RECURSE EXIT THEN
+  2r> 2drop ."  got it " ;
+: close ;
+: open
+  do-super
+  80 alloc-mem inode !
+  my-args nip 0= IF 0 0 ELSE
+  2 my-args find-path ?dup 0= IF close false EXIT THEN THEN
+  read-inode read-block#s 0 0 seek 0= ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/fat-files.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/fat-files.fs
new file mode 100644
index 0000000..76d9f51
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/fat-files.fs
@@ -0,0 +1,187 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" fat-files" device-name
+
+INSTANCE VARIABLE bytes/sector
+INSTANCE VARIABLE sectors/cluster
+INSTANCE VARIABLE #reserved-sectors
+INSTANCE VARIABLE #fats
+INSTANCE VARIABLE #root-entries
+INSTANCE VARIABLE total-#sectors
+INSTANCE VARIABLE media-descriptor
+INSTANCE VARIABLE sectors/fat
+INSTANCE VARIABLE sectors/track
+INSTANCE VARIABLE #heads
+INSTANCE VARIABLE #hidden-sectors
+
+INSTANCE VARIABLE fat-type
+INSTANCE VARIABLE bytes/cluster
+INSTANCE VARIABLE fat-offset
+INSTANCE VARIABLE root-offset
+INSTANCE VARIABLE cluster-offset
+INSTANCE VARIABLE #clusters
+
+: seek  s" seek" $call-parent ;
+: read  s" read" $call-parent ;
+
+INSTANCE VARIABLE data
+INSTANCE VARIABLE #data
+
+: free-data
+  data @ ?dup IF #data @ free-mem  0 data ! THEN ;
+: read-data ( offset size -- )
+  free-data  dup #data ! alloc-mem data !
+  xlsplit seek            -2 and ABORT" fat-files read-data: seek failed"
+  data @ #data @ read #data @ <> ABORT" fat-files read-data: read failed" ;
+
+CREATE fat-buf 8 allot
+: read-fat ( cluster# -- data )
+  fat-buf 8 erase
+  1 #split fat-type @ * 2/ 2/ fat-offset @ +
+  xlsplit seek -2 and ABORT" fat-files read-fat: seek failed"
+  fat-buf 8 read 8 <> ABORT" fat-files read-fat: read failed"
+  fat-buf 8c@ bxjoin fat-type @ dup >r 2* #split drop r> #split
+  rot IF swap THEN drop ;
+  
+INSTANCE VARIABLE next-cluster
+
+: read-cluster ( cluster# -- )
+  dup bytes/cluster @ * cluster-offset @ + bytes/cluster @ read-data
+  read-fat dup #clusters @ >= IF drop 0 THEN next-cluster ! ;
+: read-dir ( cluster# -- )
+  ?dup 0= IF root-offset @ #root-entries @ 20 * read-data 0 next-cluster !
+  ELSE read-cluster THEN ;
+
+: .time ( x -- )
+  base @ >r decimal
+  b #split 2 0.r [char] : emit  5 #split 2 0.r [char] : emit  2* 2 0.r
+  r> base ! ;
+: .date ( x -- )
+  base @ >r decimal
+  9 #split 7bc + 4 0.r [char] - emit  5 #split 2 0.r [char] - emit  2 0.r
+  r> base ! ;
+: .attr ( attr -- )
+  6 0 DO dup 1 and IF s" RHSLDA" drop i + c@ ELSE bl THEN emit u2/ LOOP drop ;
+: .dir-entry ( adr -- )
+  dup 0b + c@ 8 and IF drop EXIT THEN \ volume label, not a file
+  dup c@ e5 = IF drop EXIT THEN \ deleted file
+  cr
+  dup 1a + 2c@ bwjoin [char] # emit 4 0.r space \ starting cluster
+  dup 18 + 2c@ bwjoin .date space
+  dup 16 + 2c@ bwjoin .time space
+  dup 1c + 4c@ bljoin base @ decimal swap a .r base ! space \ size in bytes
+  dup 0b + c@ .attr space
+  dup 8 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT type
+  dup 8 + 3 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT dup IF
+  [char] . emit type ELSE 2drop THEN
+  drop ;
+: .dir-entries ( adr n -- )
+  0 ?DO dup i 20 * + dup c@ 0= IF drop LEAVE THEN .dir-entry LOOP drop ;
+: .dir ( cluster# -- )
+  read-dir BEGIN data @ #data @ 20 / .dir-entries next-cluster @ WHILE
+  next-cluster @ read-cluster REPEAT ;
+
+: str-upper ( str len adr -- ) \ Copy string to adr, uppercase
+  -rot bounds ?DO i c@ upc over c! char+ LOOP drop ;
+CREATE dos-name b allot
+: make-dos-name ( str len -- )
+  dos-name b bl fill
+  2dup [char] . findchar IF
+  3dup 1+ /string 3 min dos-name 8 + str-upper nip THEN
+  8 min dos-name str-upper ;
+
+: (find-file) ( -- cluster file-len is-dir? true | false )
+  data @ BEGIN dup data @ #data @ + < WHILE
+  dup dos-name b comp WHILE 20 + REPEAT
+  dup 1a + 2c@ bwjoin swap dup 1c + 4c@ bljoin swap 0b + c@ 10 and 0<> true
+  ELSE drop false THEN ;
+: find-file ( dir-cluster name len -- cluster file-len is-dir? true | false )
+  make-dos-name read-dir BEGIN (find-file) 0= WHILE next-cluster @ WHILE
+  next-cluster @ read-cluster REPEAT false ELSE true THEN ;
+: find-path ( dir-cluster name len -- cluster file-len true | false )
+  dup 0= IF 3drop false ."  empty name " EXIT THEN
+  over c@ [char] \ = IF 1 /string ."  slash " RECURSE EXIT THEN
+  [char] \ split 2>r find-file 0= IF 2r> 2drop false ."  not found " EXIT THEN
+  r@ 0<> <> IF 2drop 2r> 2drop false ."  no dir<->file match " EXIT THEN
+  r@ 0<> IF drop 2r> ."  more... " RECURSE EXIT THEN
+  2r> 2drop true ."  got it " ;
+  
+: do-super ( -- )
+  0 200 read-data
+  data @ 0b + 2c@ bwjoin bytes/sector !
+  data @ 0d + c@ sectors/cluster !
+  bytes/sector @ sectors/cluster @ * bytes/cluster !
+  data @ 0e + 2c@ bwjoin #reserved-sectors !
+  data @ 10 + c@ #fats !
+  data @ 11 + 2c@ bwjoin #root-entries !
+  data @ 13 + 2c@ bwjoin total-#sectors !
+  data @ 15 + c@ media-descriptor !
+  data @ 16 + 2c@ bwjoin sectors/fat !
+  data @ 18 + 2c@ bwjoin sectors/track !
+  data @ 1a + 2c@ bwjoin #heads !
+  data @ 1c + 2c@ bwjoin #hidden-sectors !
+
+  \ For FAT16 and FAT32:
+  total-#sectors @ 0= IF data @ 20 + 4c@ bljoin total-#sectors ! THEN
+
+  \ For FAT32:
+  sectors/fat @ 0= IF data @ 24 + 4c@ bljoin sectors/fat ! THEN
+
+  \ XXX add other FAT32 stuff (offsets 28, 2c, 30)
+
+  \ Compute the number of data clusters, decide what FAT type we are.
+  total-#sectors @ #reserved-sectors @ - sectors/fat @ #fats @ * -
+  #root-entries @ 20 * bytes/sector @ // - sectors/cluster @ /
+  dup #clusters !
+  dup ff5 < IF drop c ELSE fff5 < IF 10 ELSE 20 THEN THEN fat-type !
+cr ." FAT" base @ decimal fat-type @ . base !
+
+  \ Starting offset of first fat.
+  #reserved-sectors @ bytes/sector @ * fat-offset !
+
+  \ Starting offset of root dir.
+  #fats @ sectors/fat @ * bytes/sector @ * fat-offset @ + root-offset !
+
+  \ Starting offset of "cluster 0".
+  #root-entries @ 20 * bytes/sector @ tuck // * root-offset @ +
+  bytes/cluster @ 2* - cluster-offset ! ;
+
+
+INSTANCE VARIABLE file-cluster
+INSTANCE VARIABLE file-len
+INSTANCE VARIABLE current-pos
+INSTANCE VARIABLE pos-in-data
+
+: seek ( lo hi -- status )
+  lxjoin dup current-pos ! file-cluster @ read-cluster
+  \ Read and skip blocks until we are where we want to be.
+  BEGIN dup #data @ >= WHILE #data @ - next-cluster @ dup 0= IF
+  2drop true EXIT THEN read-cluster REPEAT pos-in-data ! false ;
+: read ( adr len -- actual )
+  file-len @ current-pos @ - min \ can't go past end of file
+  #data @ pos-in-data @ - min >r \ length for this transfer
+  data @ pos-in-data @ + swap r@ move \ move the data
+  r@ pos-in-data +!  r@ current-pos +!  pos-in-data @ #data @ = IF
+  next-cluster @ ?dup IF read-cluster 0 pos-in-data ! THEN THEN r> ;
+: read ( adr len -- actual )
+  dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" fat-files: read failed"
+  /string ( tuck - >r + r> ) REPEAT 2drop r> ;
+: load ( adr -- len )
+  file-len @ read dup file-len @ <> ABORT" fat-files: failed loading file" ;
+
+: close  free-data ;
+: open
+  do-super
+  0 my-args find-path 0= IF close false EXIT THEN
+  file-len !  file-cluster !  0 0 seek 0= ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/filler.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/filler.fs
new file mode 100644
index 0000000..bd5c17a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/filler.fs
@@ -0,0 +1,21 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" filler" device-name
+
+: block-size  s" block-size" $call-parent ;
+: seek        s" seek"       $call-parent ;
+: read        s" read"       $call-parent ;
+
+: open  true ;
+: close ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/iso-9660.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/iso-9660.fs
new file mode 100644
index 0000000..296b46b
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/iso-9660.fs
@@ -0,0 +1,312 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" iso-9660" device-name
+
+
+0 VALUE iso-debug-flag
+
+\ Method for code clean up - For release version of code iso-debug-flag is
+\ cleared  and for debugging it is set
+
+: iso-debug-print ( str len -- )  iso-debug-flag IF type cr ELSE 2drop THEN  ;
+
+
+\ --------------------------------------------------------
+\ GLOBAL  VARIABLES
+\ --------------------------------------------------------
+
+
+0 VALUE  path-tbl-size
+0 VALUE  path-tbl-addr
+0 VALUE  root-dir-size
+0 VALUE  vol-size
+0 VALUE  logical-blk-size
+0 VALUE  path-table
+0 VALUE  count
+
+
+\ INSTANCE VARIABLES
+
+
+INSTANCE VARIABLE dir-addr
+INSTANCE VARIABLE data-buff
+INSTANCE VARIABLE #data
+INSTANCE VARIABLE ptable
+INSTANCE VARIABLE file-loc
+INSTANCE VARIABLE file-size
+INSTANCE VARIABLE cur-file-offset
+INSTANCE VARIABLE self
+INSTANCE VARIABLE index
+
+
+\ --------------------------------------------------------
+\ COLON DEFINITIONS
+\ --------------------------------------------------------
+
+
+\ This method is used to seek to the required position
+\ Which calls seek of disk-label
+
+: seek  ( pos.lo pos.hi -- status )  s" seek" $call-parent  ;
+
+
+\ This method is used to read the contents of disk
+\ it calls read of disk-label
+
+
+ : read  ( addr len -- actual )  s" read" $call-parent  ;
+
+
+\ This method releases the memory used as  scratch pad buffer.
+
+: free-data ( -- )
+   data-buff @                              ( data-buff )
+   ?DUP  IF  #data @  free-mem  0 data-buff ! THEN
+;
+
+
+\ This method will release the previous allocated scratch pad buffer and
+\ allocates a fresh buffer and copies the required number of bytes from the
+\ media in to it.
+
+: read-data ( offset size -- )
+   free-data  DUP                     ( offset size size )
+   #data !  alloc-mem   data-buff !   (  offset )
+   xlsplit                            ( pos.lo pos.hi )
+   seek   -2 and ABORT" seek failed."
+   data-buff  @  #data @  read        ( actual )
+   #data @  <> ABORT" read failed."
+;
+
+
+\ This method extracts the information required from primary volume
+\ descriptor and stores the required information in the global variables
+
+: extract-vol-info  (  --  )
+   10  800 * 800 read-data
+   data-buff @  88  + l at -be  to path-tbl-size   \ read path table size
+   data-buff @  94  + l at -be  to path-tbl-addr   \ read big-endian  path table
+   data-buff @  a2  + l at -be   dir-addr !        \ gather of root directory info
+   data-buff @  0aa + l at -be  to root-dir-size   \ get volume info
+   data-buff @  54  + l at -be  to vol-size        \ size in blocks
+   data-buff @  82  + l at -be  to logical-blk-size
+   path-tbl-size alloc-mem dup  TO path-table path-tbl-size erase
+   path-tbl-addr 800 *  xlsplit seek  drop
+   path-table  path-tbl-size  read  drop     \ pathtable in-system-memory copy
+;
+
+
+\ This method coverts the iso file name to user readble form
+
+: file-name  ( str len --  str' len' )
+   2dup  [char] ; findchar  IF
+      ( str len offset )
+      nip                 \ Omit the trailing ";1" revision of ISO9660 file name
+      2dup + 1-           ( str newlen endptr )
+      c@ [CHAR] . = IF
+         1-               ( str len' )    \ Remove trailing dot
+      THEN
+   THEN
+;
+
+
+\ triplicates top stack element
+
+: dup3  ( num  -- num num num ) dup dup dup  ;
+
+
+\ This method is used for traversing records of path table. If the
+\ file identifier length is odd 1 byte padding is done else not.
+
+: get-next-record  ( rec-addr -- next-rec-offset )
+   dup3               ( rec-addr rec-addr rec-addr rec-addr )
+   self @ 1 +  self ! ( rec-addr rec-addr rec-addr rec-addr )
+   c@  1 AND  IF      ( rec-addr rec-addr rec-addr )
+      c@ +  9         ( rec-addr rec-addr' rec-len )
+   ELSE
+      c@ +  8         ( rec-addr rec-addr' rec-len )
+   THEN
+   + swap  -          ( next-rec-offset )
+;
+
+
+\  This method does search of given directory name in the path table
+\ and returns true  if finds a match else  false.
+
+: path-table-search ( str len -- TRUE | FALSE )
+   path-table path-tbl-size +  path-table ptable @ +  DO ( str len )
+      2dup  I 6 + w at -be index @ =                        ( str len str len )
+      -rot  I 8 +  I c@  string=ci and  IF               ( str len )
+         s" Directory Matched!!  "   iso-debug-print     ( str len )
+         self @   index !                                ( str len )
+         I 2 + l at -be   dir-addr ! I  dup                 ( str len rec-addr )
+         get-next-record + path-table -   ptable !       ( str len )
+         2drop  TRUE UNLOOP EXIT                         ( TRUE )
+      THEN
+      I get-next-record                           ( str len next-rec-offset )
+   +LOOP
+   2drop
+   FALSE                                          ( FALSE )
+   s" Invalid path / directory "  iso-debug-print
+;
+
+
+\ METHOD for searching for a file with in a direcotory
+
+: search-file-dir ( str len  -- TRUE | FALSE )
+   dir-addr @  800 *  dir-addr !             ( str len )
+   dir-addr @ 100 read-data                  ( str len )
+   data-buff @  0e + l at -be  dup >r           ( str len rec-len )
+   100 >  IF                                 ( str len )
+      s" size dir record"  iso-debug-print   ( str len )
+      dir-addr @ r@  read-data               ( str len )
+   THEN
+   r> data-buff @  + data-buff @  DO         ( str len )
+      I 19 + c@  2 and 0=  IF                ( str len )
+         2dup                                ( str len  str len )
+         I 21 + I 20 + c@                    ( str len  str len  str' len' )
+         file-name  string=ci  IF            ( str len )
+            s" File found!"  iso-debug-print ( str len )
+            I 6 + l at -be 800 *                ( str len file-loc )
+            file-loc !                       ( str len )
+            I 0e + l at -be  file-size !        ( str len )
+            2drop
+            TRUE                             ( TRUE )
+            UNLOOP
+            EXIT
+         THEN
+      THEN
+      I c@ dup 0=  IF                        ( str len len )
+         s" file not found"   iso-debug-print
+         drop  2drop FALSE                   ( FALSE )
+         UNLOOP
+         EXIT
+      THEN
+   +LOOP
+   2drop
+   FALSE                                     ( FALSE )
+   s" file not found"   iso-debug-print
+;
+
+
+\ This method splits the given absolute path in to directories from root and
+\ calls search-path-table. when string reaches to state when it can not be
+\ split i.e., end of the path, calls search-file-dir is made to search for
+\ file .
+
+: search-path ( str len -- FALSE|TRUE )
+   0  ptable !
+   1  self !
+   1  index !
+   dup                                             ( str len len )
+   0=  IF
+      3drop FALSE                                  ( FALSE )
+      s"  Empty path name "  iso-debug-print  EXIT ( FALSE )
+   THEN
+   OVER c@                                         ( str len char )
+   [char] \ =  IF                                  ( str len )
+      swap 1 + swap 1 -  BEGIN                     ( str len )
+         [char] \  split                           ( str len  str' len ' )
+         dup 0 =   IF                              ( str len  str' len ' )
+            2drop search-file-dir EXIT             ( TRUE | FALSE )
+         ELSE
+            2swap path-table-search  invert  IF    ( str' len ' )
+               2drop FALSE  EXIT                   ( FALSE )
+            THEN
+         THEN
+      AGAIN
+   ELSE   BEGIN
+      [char] \  split   dup 0 =   IF               ( str len str' len' )
+         2drop search-file-dir EXIT                ( TRUE | FALSE )
+      ELSE
+         2swap path-table-search  invert  IF       ( str' len ' )
+            2drop FALSE  EXIT                      ( FALSE )
+            THEN
+         THEN
+      AGAIN
+   THEN
+;
+
+
+\ this method will seek and read the file in to the given memory location
+
+0 VALUE loc
+: load ( addr -- len )
+   dup to loc                     ( addr )
+   file-loc @  xlsplit seek drop
+   file-size @  read              ( file-size )
+   iso-debug-flag IF s" Bytes returned from read:" type dup . cr THEN
+   dup file-size @  <> ABORT" read failed!"
+;
+
+
+
+\ memory used by the file system will be freed
+
+: close ( -- )
+   free-data   count 1 - dup to count  0 =  IF
+      path-table path-tbl-size free-mem
+      0 TO path-table
+   THEN
+;
+
+
+\ open method of the file system
+
+: open ( -- TRUE | FALSE )
+   0 data-buff !
+   0 #data !
+   0 ptable !
+   0 file-loc !
+   0 file-size !
+   0 cur-file-offset !
+   1 self !
+   1 index !
+   count 0 =  IF
+      s" extract-vol-info called "   iso-debug-print
+      extract-vol-info
+   THEN
+   count  1 + to count
+   my-args search-path  IF
+      file-loc @  xlsplit seek drop
+      TRUE    ( TRUE )
+   ELSE
+      close
+      FALSE   ( FALSE )
+   THEN
+   0 cur-file-offset !
+   s" opened ISO9660 package" iso-debug-print
+;
+
+
+\ public seek method
+
+: seek ( pos.lo pos.hi -- status )
+   lxjoin dup  cur-file-offset !  ( offset )
+   file-loc @  + xlsplit          ( pos.lo pos.hi )
+   s" seek" $call-parent          ( status )
+;
+
+
+\ public read method
+
+ : read ( addr len -- actual )
+    file-size @ cur-file-offset @ -             ( addr len remainder-of-file )
+    min                                         ( addr len|remainder-of-file )
+    s" read" $call-parent                       ( actual )
+    dup cur-file-offset @ +  cur-file-offset !  ( actual )
+    cur-file-offset @                           ( offset actual )
+    xlsplit seek drop                           ( actual )
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/obp-tftp.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/obp-tftp.fs
new file mode 100644
index 0000000..6bb43c9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/obp-tftp.fs
@@ -0,0 +1,73 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+s" obp-tftp" device-name
+
+INSTANCE VARIABLE ciregs-buffer
+
+: open ( -- okay? ) 
+    ciregs-size alloc-mem ciregs-buffer ! 
+    true
+;
+
+: load ( addr -- size )
+
+    \ Save old client interface register 
+    ciregs ciregs-buffer @ ciregs-size move
+
+    s" bootargs" get-chosen 0= IF 0 0 THEN >r >r
+    s" bootpath" get-chosen 0= IF 0 0 THEN >r >r
+
+    \ Set bootpath to current device
+    my-parent ihandle>phandle node>path encode-string
+    s" bootpath" set-chosen
+
+    \ Generate arg string for snk like
+    \ "netboot load-addr length filename"
+    (u.) s" netboot " 2swap $cat s"  60000000 " $cat
+
+    \ Allocate 1720 bytes to store the BOOTP-REPLY packet
+    6B8 alloc-mem dup >r (u.) $cat s"  " $cat
+    huge-tftp-load @ IF s"  1 " ELSE s"  0 " THEN $cat
+    \ Add desired TFTP-Blocksize as additional argument
+    s" 1432 " $cat
+    \ Add OBP-TFTP Bootstring argument, e.g. "10.128.0.1,bootrom.bin,10.128.40.1"
+    my-args $cat
+
+    \ Call SNK netboot loadr
+    (client-exec) dup 0< IF drop 0 THEN
+
+    \ Restore to old client interface register 
+    ciregs-buffer @ ciregs ciregs-size move
+
+    \ Recover buffer address of BOOTP-REPLY packet
+    r>
+
+    r> r> over IF s" bootpath" set-chosen ELSE 2drop THEN
+    r> r> over IF s" bootargs" set-chosen ELSE 2drop THEN
+
+    \ Store BOOTP-REPLY packet as property
+    s" /chosen" select-dev
+    dup 6B8 encode-bytes s" bootp-response" property
+    device-end
+
+    \ free buffer
+    6B8 free-mem
+;
+
+: close ( -- )
+   ciregs-buffer @ ciregs-size free-mem 
+;
+
+: ping  ( -- )
+   s" ping " my-args $cat (client-exec)
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/rom-files.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/rom-files.fs
new file mode 100644
index 0000000..418cf4e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/rom-files.fs
@@ -0,0 +1,85 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ package which adds support to read the romfs
+\ this package is somehow limited as the maximum supported length
+\ for a file name is hardcoded to 0x100
+
+s" rom-files" device-name
+
+INSTANCE VARIABLE length
+INSTANCE VARIABLE next-file
+INSTANCE VARIABLE buffer
+INSTANCE VARIABLE buffer-size
+INSTANCE VARIABLE file
+INSTANCE VARIABLE file-size
+INSTANCE VARIABLE found
+
+: open  true 
+  100 dup buffer-size ! alloc-mem buffer ! false found ! ;
+: close buffer @ buffer-size @ free-mem ;
+
+: read ( addr len -- actual ) s" read" $call-parent ;
+
+: seek ( lo hi -- status ) s" seek" $call-parent ;
+
+: .read-file-name ( offset -- str len )
+  \ move to the file name offset
+  0 seek drop 
+  \ read <buffer-size> bytes from that address
+  buffer @ buffer-size @ read drop
+  \ write a 0 to make sure it is a 0 terminated string
+  buffer-size @ 1 - buffer @ + 0 swap c!
+  buffer @ zcount ;
+
+: .print-info ( offset -- )
+  dup 2 spaces 6 0.r 2 spaces dup
+  8 + 0 seek drop length 8 read drop
+  6 length @ swap 0.r 2 spaces
+  20 + .read-file-name type cr ;
+
+: .list-header cr
+  s" --offset---size-----file-name----" type cr ;
+
+: list
+  .list-header
+  0 0 BEGIN + dup 
+  .print-info dup 0 seek drop
+  next-file 8 read drop next-file @
+  dup 0= UNTIL 2drop ;
+
+: (find-file)  ( name len -- offset | -1 )
+   0 0 seek drop false found !
+   file-size ! file ! 0 0 BEGIN + dup
+   20 + .read-file-name file @ file-size @
+   str= IF true found ! THEN
+   dup 0 seek drop
+   next-file 8 read drop next-file @
+   dup 0= found @ or UNTIL drop found @ 0=
+   IF drop -1 THEN ;
+
+: load  ( addr -- size )
+   my-parent instance>args 2@ [char] \ left-parse-string 2drop
+   (find-file) dup -1 = IF 2drop 0 ELSE
+      \ got to the beginning
+      0 0 seek drop
+      \ read the file size
+      dup 8 + 0 seek drop
+      here 8 read drop here @  ( dest-addr offset file-size )
+      \ read data start offset
+      over 18 + 0 seek drop
+      here 8 read drop here @  ( dest-addr offset file-size data-offset )
+      rot + 0 seek drop  ( dest-addr file-size )
+      read 
+   THEN
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/packages/sms.fs b/qemu-0.15.x/roms/SLOF/slof/fs/packages/sms.fs
new file mode 100644
index 0000000..d8c672f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/packages/sms.fs
@@ -0,0 +1,29 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" /packages" find-device
+
+new-device
+   s" sms" device-name
+
+   : open true ;
+
+   : close ;
+
+   \ The rest of methods is loaded dynamically from the romfs
+   \ on a first call to sms-start
+
+finish-device
+
+device-end \ leave /packages
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-bridge.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-bridge.fs
new file mode 100644
index 0000000..81bfca1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-bridge.fs
@@ -0,0 +1,62 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ get the PUID from the node above
+s" my-puid" $call-parent CONSTANT my-puid
+\ Save the bus number provided by this bridge
+pci-bus-number 1+ CONSTANT my-bus
+
+s" pci-config-bridge.fs" included
+
+\ generate the rom-fs filename from the vendor and device ID "pci-bridge_VENDORID_DEVICEID.fs"
+: filename ( -- str len )
+  s" pci-bridge_"
+  my-space pci-vendor@ 4 int2str $cat
+  s" _" $cat
+  my-space pci-device@ 4 int2str $cat
+  s" .fs" $cat
+;
+
+\ Set up the Bridge with either default or special settings
+: setup ( -- )
+        \ is there special handling for this device, given vendor and device id?
+        filename romfs-lookup ?dup
+                IF
+                        \ give it a special treatment
+                        evaluate
+                ELSE
+                        \ no special handling for this device, attempt autoconfiguration
+                        my-space pci-class-name type 2a emit cr
+                        my-space pci-bridge-generic-setup
+                        my-space pci-reset-2nd
+                THEN
+;
+
+\ Disable Bus Master, Memory Space and I/O Space for
+\ this device and so for the scanning for the devices behind
+pci-device-disable
+
+\ Enalbe #PERR and #SERR reporting
+pci-error-enable
+
+\ Print out device information
+my-space 42 pci-out     \ config-addr ascii('B')
+
+\ and set up the bridge
+setup
+
+\ And enable Bus Master IO and MEM access again.
+\ we need that on bridges so that the devices behind
+\ can set their state on their own.
+pci-master-enable
+pci-mem-enable
+pci-io-enable
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-class-code-names.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-class-code-names.fs
new file mode 100644
index 0000000..4156fba
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-class-code-names.fs
@@ -0,0 +1,263 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: pci-class-name-00 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        01  OF s" display"               ENDOF
+        dup OF s" unknown-legacy-device" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-01 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" scsi"         ENDOF
+        01  OF s" ide"          ENDOF
+        02  OF s" fdc"          ENDOF
+        03  OF s" ipi"          ENDOF
+        04  OF s" raid"         ENDOF
+        05  OF s" ata"          ENDOF
+        06  OF s" sata"         ENDOF
+        07  OF s" sas"          ENDOF
+        dup OF s" mass-storage" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-02 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" ethernet"   ENDOF
+        01  OF s" token-ring" ENDOF
+        02  OF s" fddi"       ENDOF
+        03  OF s" atm"        ENDOF
+        04  OF s" isdn"       ENDOF
+        05  OF s" worldfip"   ENDOF
+        05  OF s" picmg"      ENDOF
+        dup OF s" network"    ENDOF
+        ENDCASE
+;
+
+: pci-class-name-03 ( addr -- str len )
+        pci-class@ FFFF and CASE
+        0000  OF s" vga"             ENDOF
+        0001  OF s" 8514-compatible" ENDOF
+        0100  OF s" xga"             ENDOF
+        0200  OF s" 3d-controller"   ENDOF
+        dup OF s" display"           ENDOF
+        ENDCASE
+;
+
+: pci-class-name-04 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" video"             ENDOF
+        01  OF s" sound"             ENDOF
+        02  OF s" telephony"         ENDOF
+        dup OF s" multimedia-device" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-05 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" memory"            ENDOF
+        01  OF s" flash"             ENDOF
+        dup OF s" memory-controller" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-06 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" host"                 ENDOF
+        01  OF s" isa"                  ENDOF
+        02  OF s" eisa"                 ENDOF
+        03  OF s" mca"                  ENDOF
+        04  OF s" pci"                  ENDOF
+        05  OF s" pcmcia"               ENDOF
+        06  OF s" nubus"                ENDOF
+        07  OF s" cardbus"              ENDOF
+        08  OF s" raceway"              ENDOF
+        09  OF s" semi-transparent-pci" ENDOF
+        0A  OF s" infiniband"           ENDOF
+        dup OF s" unkown-bridge"        ENDOF
+        ENDCASE
+;
+
+: pci-class-name-07 ( addr -- str len )
+        pci-class@ FFFF and CASE
+        0000  OF s" serial"                   ENDOF
+        0001  OF s" 16450-serial"             ENDOF
+        0002  OF s" 16550-serial"             ENDOF
+        0003  OF s" 16650-serial"             ENDOF
+        0004  OF s" 16750-serial"             ENDOF
+        0005  OF s" 16850-serial"             ENDOF
+        0006  OF s" 16950-serial"             ENDOF
+        0100  OF s" parallel"                 ENDOF
+        0101  OF s" bi-directional-parallel"  ENDOF
+        0102  OF s" ecp-1.x-parallel"         ENDOF
+        0103  OF s" ieee1284-controller"      ENDOF
+        01FE  OF s" ieee1284-device"          ENDOF
+        0200  OF s" multiport-serial"         ENDOF
+        0300  OF s" modem"                    ENDOF
+        0301  OF s" 16450-modem"              ENDOF
+        0302  OF s" 16550-modem"              ENDOF
+        0303  OF s" 16650-modem"              ENDOF
+        0304  OF s" 16750-modem"              ENDOF
+        0400  OF s" gpib"                     ENDOF
+        0500  OF s" smart-card"               ENDOF
+        dup   OF s" communication-controller" ENDOF
+        ENDCASE
+;
+
+
+: pci-class-name-08 ( addr -- str len )
+        pci-class@ FFFF and CASE
+        0000  OF s" interrupt-controller" ENDOF
+        0001  OF s" isa-pic"              ENDOF
+        0002  OF s" eisa-pic"             ENDOF
+        0010  OF s" io-apic"              ENDOF
+        0020  OF s" iox-apic"             ENDOF
+        0100  OF s" dma-controller"       ENDOF
+        0101  OF s" isa-dma"              ENDOF
+        0102  OF s" eisa-dma"             ENDOF
+        0200  OF s" timer"                ENDOF
+        0201  OF s" isa-system-timer"     ENDOF
+        0202  OF s" eisa-system-timer"    ENDOF
+        0300  OF s" rtc"                  ENDOF
+        0301  OF s" isa-rtc"              ENDOF
+        0400  OF s" hot-plug-controller"  ENDOF
+        0500  OF s" sd-host-conrtoller"   ENDOF
+        dup   OF s" system-periphal"      ENDOF
+        ENDCASE
+;
+
+: pci-class-name-09 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" keyboard"         ENDOF
+        01  OF s" pen"              ENDOF
+        02  OF s" mouse"            ENDOF
+        03  OF s" scanner"          ENDOF
+        04  OF s" gameport"         ENDOF
+        dup OF s" input-controller" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-0A ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" dock"            ENDOF
+        dup OF s" docking-station" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-0B ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" 386"           ENDOF
+        01  OF s" 486"           ENDOF
+        02  OF s" pentium"       ENDOF
+        10  OF s" alpha"         ENDOF
+        20  OF s" powerpc"       ENDOF
+        30  OF s" mips"          ENDOF
+        40  OF s" co-processor"  ENDOF
+        dup OF s" cpu"           ENDOF
+        ENDCASE
+;
+
+: pci-class-name-0C ( addr -- str len )
+        pci-class@ FFFF and CASE
+        0000  OF s" firewire"      ENDOF
+        0100  OF s" access-bus"    ENDOF
+        0200  OF s" ssa"           ENDOF
+        0300  OF s" usb-uhci"      ENDOF
+        0310  OF s" usb-ohci"      ENDOF
+        0320  OF s" usb-ehci"      ENDOF
+        0380  OF s" usb"           ENDOF
+        03FE  OF s" usb-device"    ENDOF
+        0400  OF s" fibre-channel" ENDOF
+        0500  OF s" smb"           ENDOF
+        0600  OF s" infiniband"    ENDOF
+        0700  OF s" ipmi-smic"     ENDOF
+        0701  OF s" ipmi-kbrd"     ENDOF
+        0702  OF s" ipmi-bltr"     ENDOF
+        0800  OF s" sercos"        ENDOF
+        0900  OF s" canbus"        ENDOF
+        dup OF s" serial-bus"      ENDOF
+        ENDCASE
+;
+
+: pci-class-name-0D ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" irda"                ENDOF
+        01  OF s" consumer-ir"         ENDOF
+        10  OF s" rf-controller"       ENDOF
+        11  OF s" bluetooth"           ENDOF
+        12  OF s" broadband"           ENDOF
+        20  OF s" enet-802.11a"        ENDOF
+        21  OF s" enet-802.11b"        ENDOF
+        dup OF s" wireless-controller" ENDOF
+        ENDCASE
+;
+
+
+: pci-class-name-0E ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        dup OF s" intelligent-io" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-0F ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        01  OF s" satelite-tv"     ENDOF
+        02  OF s" satelite-audio"  ENDOF
+        03  OF s" satelite-voice"  ENDOF
+        04  OF s" satelite-data"   ENDOF
+        dup OF s" satelite-devoce" ENDOF
+        ENDCASE
+;
+
+: pci-class-name-10 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" network-encryption"       ENDOF
+        01  OF s" entertainment-encryption" ENDOF
+        dup OF s" encryption"               ENDOF
+        ENDCASE
+;
+
+: pci-class-name-11 ( addr -- str len )
+        pci-class@ 8 rshift FF and CASE
+        00  OF s" dpio"                       ENDOF
+        01  OF s" counter"                    ENDOF
+        10  OF s" measurement"                ENDOF
+        20  OF s" managment-card"             ENDOF
+        dup OF s" data-processing-controller" ENDOF
+        ENDCASE
+;
+
+\ create a string holding the predefined Class-Code-Names
+: pci-class-name ( addr -- str len )
+        dup pci-class@ 10 rshift CASE
+        00  OF pci-class-name-00 ENDOF
+        01  OF pci-class-name-01 ENDOF
+        02  OF pci-class-name-02 ENDOF
+        03  OF pci-class-name-03 ENDOF
+        04  OF pci-class-name-04 ENDOF
+        05  OF pci-class-name-05 ENDOF
+        06  OF pci-class-name-06 ENDOF
+        07  OF pci-class-name-07 ENDOF
+        08  OF pci-class-name-08 ENDOF
+        09  OF pci-class-name-09 ENDOF
+        0A  OF pci-class-name-0A ENDOF
+        0B  OF pci-class-name-0B ENDOF
+        0C  OF pci-class-name-0C ENDOF
+        0C  OF pci-class-name-0D ENDOF
+        0C  OF pci-class-name-0E ENDOF
+        0C  OF pci-class-name-0F ENDOF
+        0C  OF pci-class-name-10 ENDOF
+        0C  OF pci-class-name-11 ENDOF
+        dup OF drop s" unknown"  ENDOF
+        ENDCASE
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-config-bridge.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-config-bridge.fs
new file mode 100644
index 0000000..f813431
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-config-bridge.fs
@@ -0,0 +1,85 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ define the config reads
+: config-b@  puid >r my-puid TO puid my-space + rtas-config-b@ r> TO puid ;
+: config-w@  puid >r my-puid TO puid my-space + rtas-config-w@ r> TO puid ;
+: config-l@  puid >r my-puid TO puid my-space + rtas-config-l@ r> TO puid ;
+
+\ define the config writes
+: config-b!  puid >r my-puid TO puid my-space + rtas-config-b! r> TO puid ;
+: config-w!  puid >r my-puid TO puid my-space + rtas-config-w! r> TO puid ;
+: config-l!  puid >r my-puid TO puid my-space + rtas-config-l! r> TO puid ;
+
+\ for Debug purposes: dumps the whole config space
+: config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ;
+
+\ needed to find the right path in the device tree
+: decode-unit ( addr len -- phys.lo ... phys.hi )
+        2 hex-decode-unit       \ decode string
+        B lshift swap           \ shift the devicenumber to the right spot
+        8 lshift or             \ add the functionnumber
+        my-bus 10 lshift or     \ add the busnumber
+        0 0 rot                 \ make phys.lo = 0 = phys.mid
+;
+
+\ needed to have the right unit address in the device tree listing
+\ phys.lo=phys.mid=0 , phys.hi=config-address
+: encode-unit ( phys.lo ... phys.hi -- unit-str unit-len )
+        nip nip                         \ forget the both zeros
+        dup 8 rshift 7 and swap         \ calc Functionnumber
+        B rshift 1F and                 \ calc Devicenumber
+        over IF                         \ IF Function!=0
+                2 hex-encode-unit       \ | create string with DevNum,FnNum
+        ELSE                            \ ELSE
+                nip 1 hex-encode-unit   \ | create string with only DevNum
+        THEN                            \ FI
+;
+
+: map-in ( phys.lo ... phys.hi size -- virt )
+   \ ." map-in called: " .s cr
+   2drop drop
+;
+
+: map-out ( virt size -- )
+   \ ." map-out called: " .s cr
+   2drop 
+;
+
+: dma-alloc ( ... size -- virt )
+   \ ." dma-alloc called: " .s cr
+   alloc-mem
+;
+
+: dma-free ( virt size -- )
+   \ ." dma-free called: " .s cr
+   free-mem
+;
+
+: dma-map-in ( ... virt size cacheable? -- devaddr )
+   \ ." dma-map-in called: " .s cr
+   2drop
+;
+
+: dma-map-out ( virt devaddr size -- )
+   \ ." dma-map-out called: " .s cr
+   2drop drop
+;
+
+: dma-sync ( virt devaddr size -- )
+   \ XXX should we add at least a memory barrier here?
+   \ ." dma-sync called: " .s cr
+   2drop drop
+;
+
+: open true ;
+: close ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-device.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-device.fs
new file mode 100644
index 0000000..fbb4c61
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-device.fs
@@ -0,0 +1,101 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ get the PUID from the node above
+s" my-puid" $call-parent CONSTANT my-puid
+
+\ define the config reads
+: config-b@  puid >r my-puid TO puid my-space + rtas-config-b@ r> TO puid ;
+: config-w@  puid >r my-puid TO puid my-space + rtas-config-w@ r> TO puid ;
+: config-l@  puid >r my-puid TO puid my-space + rtas-config-l@ r> TO puid ;
+
+\ define the config writes
+: config-b!  puid >r my-puid TO puid my-space + rtas-config-b! r> TO puid ;
+: config-w!  puid >r my-puid TO puid my-space + rtas-config-w! r> TO puid ;
+: config-l!  puid >r my-puid TO puid my-space + rtas-config-l! r> TO puid ;
+
+\ for Debug purposes: dumps the whole config space
+: config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ;
+
+\ prepare the device for subsequent use
+\ this word should be overloaded by the device file (if present)
+\ the device file can call this file before implementing
+\ its own open functionality
+: open
+        puid >r             \ save the old puid
+        my-puid TO puid     \ set up the puid to the devices Hostbridge
+        pci-master-enable   \ And enable Bus Master, IO and MEM access again.
+        pci-mem-enable      \ enable mem access
+        pci-io-enable       \ enable io access
+        r> TO puid          \ restore puid
+        true
+;
+
+\ close the previously opened device
+\ this word should be overloaded by the device file (if present)
+\ the device file can call this file after its implementation
+\ of own close functionality
+: close 
+        puid >r             \ save the old puid
+        my-puid TO puid     \ set up the puid
+        pci-device-disable  \ and disable the device
+        r> TO puid          \ restore puid
+;
+
+\ generate the rom-fs filename from the vendor and device ID "pci-device_VENDORID_DEVICEID.fs"
+: devicefile ( -- str len )
+  s" pci-device_"
+  my-space pci-vendor@ 4 int2str $cat
+  s" _" $cat
+  my-space pci-device@ 4 int2str $cat
+  s" .fs" $cat
+;
+
+\ generate the rom-fs filename from the base-class id "pci-class_BASECLASS.fs"
+: classfile ( -- str len )
+  s" pci-class_"
+  my-space pci-class@ 10 rshift 2 int2str $cat
+  s" .fs" $cat
+;
+
+\ Set up the device with either default or special settings
+: setup ( -- )
+        \ is there special handling for this device, given vendor and device id?
+        devicefile romfs-lookup ?dup
+                IF
+                        \ give it a special treatment
+                        evaluate
+                ELSE
+                        classfile romfs-lookup ?dup
+                        IF
+                            \ give it a pci-class related treatment
+                            evaluate
+                        ELSE
+                            \ no special handling for this device, attempt autoconfiguration
+                            my-space pci-class-name type 2a emit cr
+                            my-space pci-device-generic-setup
+                        THEN
+                THEN
+;
+
+\ Disable Bus Master, Memory Space and I/O Space for this device
+\ if Bus Master function is needed it should be enabled/disabled by open/close in the device driver code
+pci-device-disable
+
+\ Enalbe #PERR and #SERR reporting
+pci-error-enable
+
+\ Print out device information
+my-space 44 pci-out     \ config-addr ascii('D')
+
+\ and set up the device
+setup
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-properties.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-properties.fs
new file mode 100644
index 0000000..312f431
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-properties.fs
@@ -0,0 +1,650 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+#include "pci-class-code-names.fs"
+
+\ read the various bar type sizes
+: pci-bar-size@     ( bar-addr -- bar-size ) -1 over rtas-config-l! rtas-config-l@ ;
+: pci-bar-size-mem@ ( bar-addr -- mem-size ) pci-bar-size@ -10 and invert 1+ FFFFFFFF and ;
+: pci-bar-size-io@  ( bar-addr -- io-size  ) pci-bar-size@ -4 and invert 1+ FFFFFFFF and ;
+
+\ fetch raw bar size but keep original BAR value
+: pci-bar-size ( bar-addr -- bar-size-raw )
+        dup rtas-config-l@ swap \ fetch original Value  ( bval baddr )
+        -1 over rtas-config-l!  \ make BAR show size    ( bval baddr )
+        dup rtas-config-l@      \ and fetch the size    ( bval baddr bsize )
+        -rot rtas-config-l!     \ restore Value
+;
+
+\ calc 32 bit MEM BAR size
+: pci-bar-size-mem32 ( bar-addr -- bar-size )
+        pci-bar-size            \ fetch raw size
+        -10 and invert 1+       \ calc size
+        FFFFFFFF and            \ keep lower 32 bits
+;
+
+\ calc 32 bit ROM BAR size
+: pci-bar-size-rom ( bar-addr -- bar-size )
+        pci-bar-size            \ fetch raw size
+        FFFFF800 and invert 1+  \ calc size
+        FFFFFFFF and            \ keep lower 32 bits
+;
+
+
+\ calc 64 bit MEM BAR size
+: pci-bar-size-mem64 ( bar-addr -- bar-size )
+        dup pci-bar-size        \ fetch raw size lower 32 bits
+        swap 4 + pci-bar-size   \ fetch raw size upper 32 bits
+        20 lshift +             \ and put them together
+        -10 and invert 1+       \ calc size
+;
+
+\ calc IO BAR size
+: pci-bar-size-io ( bar-addr -- bar-size )
+        pci-bar-size            \ fetch raw size
+        -4 and invert 1+        \ calc size
+        FFFFFFFF and            \ keep lower 32 bits
+;
+
+
+\ decode the Bar Type
+\ +----------------------------------------------------------------------------------------+
+\ |                                         3 2 1 0                                        |
+\ |           +----------------------------+-+--+-+                                        |
+\ | MEM-BAR : |         Base Address       |P|TT|0|   P - prefechtable ; TT - 00 : 32 Bit  |
+\ |           +----------------------------+-+--+-+                           10 : 64 Bit  |
+\ |           +-------------------------------+-+-+                                        |
+\ |  IO-BAR : |         Base Address          |0|1|                                        |
+\ |           +-------------------------------+-+-+                                        |
+\ | That is: 0 - no encoded BarType                                                        |
+\ |          1 - IO - Bar                                                                  |
+\ |          2 - Memory 32 Bit                                                             |
+\ |          3 - Memory 32 Bit prefetchable                                                |
+\ |          4 - Memory 64 Bit                                                             |
+\ |          5 - Memory 64 Bit prefetchable                                                |
+\ +----------------------------------------------------------------------------------------+
+: pci-bar-code@ ( bar-addr -- 0|1..4|5 )
+        rtas-config-l@ dup                \ fetch the BaseAddressRegister
+        1 and IF                          \ IO BAR ?
+                2 and IF 0 ELSE 1 THEN    \ only '01' is valid
+        ELSE                              \ Memory BAR ?
+                F and CASE
+                        0   OF 2 ENDOF    \ Memory 32 Bit Non-Prefetchable
+                        8   OF 3 ENDOF    \ Memory 32 Bit Prefetchable
+                        4   OF 4 ENDOF    \ Memory 64 Bit Non-Prefetchable
+                        C   OF 5 ENDOF    \ Memory 64 Bit Prefechtable
+                        dup OF 0 ENDOF    \ Not a valid BarType
+                ENDCASE
+        THEN
+;
+
+\ ***************************************************************************************
+\ Assigning the new Value to the BARs
+\ ***************************************************************************************
+\ align the current mem and set var to next mem
+\ align with a size of 0 returns 0 !!!
+: assign-var ( size var -- al-mem )
+        2dup @                          \ ( size var size cur-mem ) read current free mem
+        swap #aligned                   \ ( size var al-mem )       align the mem to the size
+        dup 2swap -rot +                \ ( al-mem var new-mem )    add size to aligned mem
+        swap !                          \ ( al-mem )                set variable to new mem
+;
+
+\ set bar to current free mem ( in variable ) and set variable to next free mem
+: assign-bar-value32 ( bar size var -- 4 )
+        over IF                         \ IF size > 0
+                assign-var              \ | ( bar al-mem ) set variable to next mem
+                swap rtas-config-l!     \ | ( -- )         set the bar to al-mem
+        ELSE                            \ ELSE
+                2drop drop              \ | clear stack
+        THEN                            \ FI
+        4                               \ size of the base-address-register
+;
+
+\ set bar to current free mem ( in variable ) and set variable to next free mem
+: assign-bar-value64 ( bar size var -- 8 )
+        over IF                         \ IF size > 0
+                assign-var              \ | ( bar al-mem ) set variable to next mem
+                swap                    \ | ( al-mem addr ) calc config-addr of this bar
+                2dup rtas-config-l!     \ | ( al-mem addr ) set the Lower part of the bar to al-mem
+                4 + swap 20 rshift      \ | ( al-mem>>32 addr ) prepare the upper part of the al-mem
+                swap rtas-config-l!     \ | ( -- ) and set the upper part of the bar
+        ELSE                            \ ELSE
+                2drop drop              \ | clear stack
+        THEN                            \ FI
+        8                               \ size of the base-address-register
+;
+
+\ Setup a prefetchable 64bit BAR and return its size
+: assign-mem64-bar ( bar-addr -- 8 )
+        dup pci-bar-size-mem64         \ fetch size
+        pci-next-mem                    \ var to change
+        assign-bar-value64              \ and set it all
+;
+
+\ Setup a prefetchable 32bit BAR and return its size
+: assign-mem32-bar ( bar-addr -- 4 )
+        dup pci-bar-size-mem32          \ fetch size
+        pci-next-mem                    \ var to change
+        assign-bar-value32              \ and set it all
+;
+
+\ Setup a non-prefetchable 64bit BAR and return its size
+: assign-mmio64-bar ( bar-addr -- 8 )
+        dup pci-bar-size-mem64          \ fetch size
+        pci-next-mmio                   \ var to change
+        assign-bar-value64              \ and set it all
+;
+
+\ Setup a non-prefetchable 32bit BAR and return its size
+: assign-mmio32-bar ( bar-addr -- 4 )
+        dup pci-bar-size-mem32          \ fetch size
+        pci-next-mmio                   \ var to change
+        assign-bar-value32              \ and set it all
+;
+
+\ Setup an IO-Bar and return the size of the base-address-register
+: assign-io-bar ( bar-addr -- 4 )
+        dup pci-bar-size-io             \ fetch size
+        pci-next-io                     \ var to change
+        assign-bar-value32              \ and set it all
+;
+
+\ Setup an Expansion ROM bar
+: assign-rom-bar ( bar-addr -- )
+        dup pci-bar-size-rom            \ fetch size
+        dup IF                          \ IF size > 0
+                over >r                 \ | save bar addr for enable
+                pci-next-mmio           \ | var to change
+                assign-bar-value32      \ | and set it
+                drop                    \ | forget the BAR length
+                r@ rtas-config-l@       \ | fetch BAR
+                1 or r> rtas-config-l!  \ | and enable the ROM
+        ELSE                            \ ELSE
+                2drop                   \ | clear stack
+        THEN
+;
+
+\ Setup the BAR due to its type and return the size of the register (4 or 8 Bytes ) used as increment for the BAR-Loop
+: assign-bar ( bar-addr -- reg-size )
+        dup pci-bar-code@                       \ calc BAR type
+        dup IF                                  \ IF >0
+                CASE                            \ | CASE Setup the right type
+                1 OF assign-io-bar     ENDOF    \ | - set up an IO-Bar
+                2 OF assign-mmio32-bar ENDOF    \ | - set up an 32bit MMIO-Bar
+                3 OF assign-mem32-bar  ENDOF    \ | - set up an 32bit MEM-Bar (prefetchable)
+                4 OF assign-mmio64-bar ENDOF    \ | - set up an 64bit MMIO-Bar
+                5 OF assign-mem64-bar  ENDOF    \ | - set up an 64bit MEM-Bar (prefetchable)
+                ENDCASE                         \ | ESAC
+        ELSE                                    \ ELSE
+                ABORT                           \ | Throw an exception
+        THEN                                    \ FI
+;
+
+\ Setup all the bars of a pci device
+: assign-all-device-bars ( configaddr -- )
+        28 10 DO                        \ BARs start at 10 and end at 27
+                dup i +                 \ calc config-addr of the BAR
+                assign-bar              \ and set it up
+        +LOOP                           \ add 4 or 8 to the index and loop
+        30 + assign-rom-bar             \ set up the ROM if available
+;
+
+\ Setup all the bars of a pci device
+: assign-all-bridge-bars ( configaddr -- )
+        18 10 DO                        \ BARs start at 10 and end at 17
+                dup i +                 \ calc config-addr of the BAR
+                assign-bar              \ and set it up
+        +LOOP                           \ add 4 or 8 to the index and loop
+        38 + assign-rom-bar             \ set up the ROM if available
+;
+
+\ +---------------------------------------------------------------------------------------+
+\ | Numerical Representaton of a PCI address (PCI Bus Binding 2.2.1.1)                   |
+\ |                                                                                       |
+\ |           31      24       16    11   8        0                                      |
+\ |           +--------+--------+-----+---+--------+                                      |
+\ | phys.hi:  |npt000ss|  bus   | dev |fnc|   reg  |    n - 0 relocatable                 |
+\ |           +--------+--------+-----+---+--------+    p - 1 prefetchable                |
+\ |                                                     t - 1 aliased or <1MB or <64KB    |
+\ |                                                    ss - 00 Configuration Space        |
+\ |                                                         01 I/O Space                  |
+\ |                                                         10 Memory Space 32bits        |
+\ |                                                         11 Memory Space 64bits        |
+\ +---------------------------------------------------------------------------------------+
+
+\ ***************************************************************************************
+\ Generating the assigned-addresses property
+\ ***************************************************************************************
+\ generate assigned-addresses property for 64Bit MEM-BAR and return BAR-reg-size
+: gen-mem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 )
+        dup pci-bar-size-mem64                  \ fetch BAR Size        ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size)
+                over 4 + rtas-config-l@         \ | fetch upper 32 bits               ( paddr plen baddr val.lo val.hi R: size)
+                20 lshift + -10 and >r          \ | calc 64 bit value and save it     ( paddr plen baddr R: size val )
+                83000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        8                                       \ sizeof(BAR) = 8 Bytes
+;
+
+\ generate assigned-addresses property for prefetchable 64Bit MEM-BAR and return BAR-reg-size
+: gen-pmem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 )
+        dup pci-bar-size-mem64                  \ fetch BAR Size        ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size)
+                over 4 + rtas-config-l@         \ | fetch upper 32 bits               ( paddr plen baddr val.lo val.hi R: size)
+                20 lshift + -10 and >r          \ | calc 64 bit value and save it     ( paddr plen baddr R: size val )
+                C3000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        8                                       \ sizeof(BAR) = 8 Bytes
+;
+
+\ generate assigned-addresses property for 32Bit MEM-BAR and return BAR-reg-size
+: gen-mem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 )
+        dup pci-bar-size-mem32                  \ fetch BAR Size        ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch value         ( paddr plen baddr val R: size)
+                -10 and >r                      \ | calc 32 bit value and save it     ( paddr plen baddr R: size val )
+                82000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ sizeof(BAR) = 4 Bytes
+;
+
+\ generate assigned-addresses property for prefetchable 32Bit MEM-BAR and return BAR-reg-size
+: gen-pmem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 )
+        dup pci-bar-size-mem32                  \ fetch BAR Size        ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch value         ( paddr plen baddr val R: size)
+                -10 and >r                      \ | calc 32 bit value and save it     ( paddr plen baddr R: size val )
+                C2000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ sizeof(BAR) = 4 Bytes
+;
+
+\ generate assigned-addresses property for IO-BAR and return BAR-reg-size
+: gen-io-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 )
+        dup pci-bar-size-io                     \ fetch BAR Size                      ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch value         ( paddr plen baddr val R: size)
+                -4 and >r                       \ | calc 32 bit value and save it     ( paddr plen baddr R: size val )
+                81000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ sizeof(BAR) = 4 Bytes
+;
+
+\ generate assigned-addresses property for ROM-BAR
+: gen-rom-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len )
+        dup pci-bar-size-rom                    \ fetch BAR Size                      ( paddr plen baddr bsize )
+        dup IF                                  \ IF Size > 0
+                >r dup rtas-config-l@           \ | save size and fetch value         ( paddr plen baddr val R: size)
+                FFFFF800 and >r                 \ | calc 32 bit value and save it     ( paddr plen baddr R: size val )
+                82000000 or encode-int+         \ | Encode config addr                ( paddr plen R: size val )
+                r> encode-64+                   \ | Encode assigned addr              ( paddr plen R: size )
+                r> encode-64+                   \ | Encode size                       ( paddr plen )
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+;
+
+\ add another BAR to the assigned addresses property and return the size of the encoded register
+: pci-add-assigned-address ( prop-addr prop-len bar-addr -- prop-addr prop-len bsize )
+        dup pci-bar-code@                               \ calc BAR type                         ( paddr plen baddr btype)
+        CASE                                            \ CASE for the BAR types                ( paddr plen baddr )
+                0 OF drop 4              ENDOF          \ - not a valid type so do nothing
+                1 OF gen-io-bar-prop     ENDOF          \ - IO-BAR
+                2 OF gen-mem32-bar-prop  ENDOF          \ - MEM32
+                3 OF gen-pmem32-bar-prop ENDOF          \ - MEM32 prefetchable
+                4 OF gen-mem64-bar-prop  ENDOF          \ - MEM64
+                5 OF gen-pmem64-bar-prop ENDOF          \ - MEM64 prefetchable
+        ENDCASE                                         \ ESAC ( paddr plen bsize )
+;
+
+\ generate the assigned address property for a PCI device
+: pci-device-assigned-addresses-prop ( addr -- )
+        encode-start                                    \ provide mem for property              ( addr paddr plen )
+        2 pick 30 + gen-rom-bar-prop                    \ assign the rom bar
+        28 10 DO                                        \ we have 6 possible BARs
+                2 pick i +                              \ calc BAR address                      ( addr paddr plen bar-addr )      
+                pci-add-assigned-address                \ and generate the props for the BAR
+        +LOOP                                           \ increase Index by returned len
+        s" assigned-addresses" property drop            \ and write it into the device tree
+;
+
+\ generate the assigned address property for a PCI bridge
+: pci-bridge-assigned-addresses-prop ( addr -- )
+        encode-start                                    \ provide mem for property
+        2 pick 38 + gen-rom-bar-prop                    \ assign the rom bar
+        18 10 DO                                        \ we have 2 possible BARs
+                2 pick i +                              \ ( addr paddr plen current-addr )
+                pci-add-assigned-address                \ and generate the props for the BAR
+        +LOOP                                           \ increase Index by returned len
+        s" assigned-addresses" property drop            \ and write it into the device tree
+;
+
+\ check if the range is valid and if so encode it into
+\ child.hi child.mid child.lo parent.hi parent.mid parent.lo size.hi size.lo
+\ This is needed to translate the childrens addresses
+\ We implement only 1:1 mapping for all PCI bridges
+: pci-bridge-gen-range ( paddr plen base limit type -- paddr plen )
+        >r over -                       \ calc size             ( paddr plen base size R:type )
+        dup 0< IF                       \ IF Size < 0           ( paddr plen base size R:type )
+                2drop r> drop           \ | forget values       ( paddr plen )
+        ELSE                            \ ELSE
+                1+ swap 2swap           \ | adjust stack        ( size base paddr plen R:type )
+                r@ encode-int+          \ | Child type          ( size base paddr plen R:type )
+                2 pick encode-64+       \ | Child address       ( size base paddr plen R:type )
+                r> encode-int+          \ | Parent type         ( size base paddr plen )
+                rot encode-64+          \ | Parent address      ( size paddr plen )
+                rot encode-64+          \ | Encode size         ( paddr plen )
+        THEN                            \ FI
+;
+
+
+\ generate an mmio space to the ranges property
+: pci-bridge-gen-mmio-range ( addr prop-addr prop-len -- addr prop-addr prop-len )
+        2 pick 20 + rtas-config-l@      \ fetch Value           ( addr paddr plen val )
+        dup 0000FFF0 and 10 lshift      \ calc base-address     ( addr paddr plen val base )
+        swap 000FFFFF or                \ calc limit-address    ( addr paddr plen base limit )
+        02000000 pci-bridge-gen-range   \ and generate it       ( addr paddr plen )
+;
+
+\ generate an mem space to the ranges property
+: pci-bridge-gen-mem-range ( addr prop-addr prop-len -- addr prop-addr prop-len )
+        2 pick 24 + rtas-config-l@      \ fetch Value           ( addr paddr plen val )
+        dup 000FFFFF or                 \ calc limit Bits 31:0  ( addr paddr plen val limit.31:0 )
+        swap 0000FFF0 and 10 lshift     \ calc base Bits 31:0   ( addr paddr plen limit.31:0 base.31:0 )
+        4 pick 28 + rtas-config-l@      \ fetch upper Basebits  ( addr paddr plen limit.31:0 base.31:0 base.63:32 )
+        20 lshift or swap               \ and calc Base         ( addr paddr plen base.63:0 limit.31:0 )
+        4 pick 2C + rtas-config-l@      \ fetch upper Limitbits ( addr paddr plen base.63:0 limit.31:0 limit.63:32 )
+        20 lshift or                    \ and calc Limit        ( addr paddr plen base.63:0 limit.63:0 )
+        42000000 pci-bridge-gen-range   \ and generate it       ( addr paddr plen )
+;
+
+\ generate an io space to the ranges property
+: pci-bridge-gen-io-range ( addr prop-addr prop-len -- addr prop-addr prop-len )
+        2 pick 1C + rtas-config-l@      \ fetch Value           ( addr paddr plen val )
+        dup 0000F000 and 00000FFF or    \ calc Limit Bits 15:0  ( addr paddr plen val limit.15:0 )
+        swap 000000F0 and 8 lshift      \ calc Base Bits 15:0   ( addr paddr plen limit.15:0 base.15:0 )
+        4 pick 30 + rtas-config-l@      \ fetch upper Bits      ( addr paddr plen limit.15:0 base.15:0 val )
+        dup FFFF and 10 lshift rot or   \ calc Base             ( addr paddr plen limit.15:0 val base.31:0 )
+        -rot FFFF0000 and or            \ calc Limit            ( addr paddr plen base.31:0 limit.31:0 )
+        01000000 pci-bridge-gen-range   \ and generate it       ( addr paddr plen )
+;
+
+\ generate the ranges property for a PCI bridge
+: pci-bridge-range-props ( addr -- )
+        encode-start                    \ provide mem for property
+        pci-bridge-gen-mmio-range       \ generate the non prefetchable Memory Entry
+        pci-bridge-gen-mem-range        \ generate the prefetchable Memory Entry
+        pci-bridge-gen-io-range         \ generate the IO Entry
+        dup IF                          \ IF any space present (propsize>0)
+                s" ranges" property     \ | write it into the device tree
+        ELSE                            \ ELSE
+                2drop                   \ | forget the properties
+        THEN                            \ FI
+        drop                            \ forget the address
+;
+
+\ create the interrupt map for this bridge
+: pci-bridge-interrupt-map ( -- )
+        encode-start                                    \ create the property                           ( paddr plen )
+        get-node child                                  \ find the first child                          ( paddr plen handle )
+        BEGIN dup WHILE                                 \ Loop as long as the handle is non-zero        ( paddr plen handle )
+                dup >r >space                           \ Get the my-space                              ( paddr plen addr R: handle )
+                pci-gen-irq-entry                       \ and Encode the interrupt settings             ( paddr plen R: handle)
+                r> peer                                 \ Get neighbour                                 ( paddr plen handle )
+        REPEAT                                          \ process next childe node                      ( paddr plen handle )
+        drop                                            \ forget the null                               ( paddr plen )
+        s" interrupt-map" property                      \ and set it                                    ( -- )
+        1 encode-int s" #interrupt-cells" property      \ encode the cell#
+        f800 encode-int 0 encode-int+ 0 encode-int+     \ encode the bit mask for config addr (Dev only)
+        7 encode-int+ s" interrupt-map-mask" property   \ encode IRQ#=7 and generate property
+;
+
+\ ***************************************************************************************
+\ Generating the reg property
+\ ***************************************************************************************
+\ reg = config-addr 0 0 0 0 [BAR-config-addr 0 0 size.high size.low]
+
+\ encode the reg prop for a nonprefetchable 32bit MEM-BAR
+: encode-mem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 )
+        dup pci-bar-size-mem32                  \ calc BAR-size ( not changing the BAR )
+        dup IF                                  \ IF BAR-size > 0       ( paddr plen baddr bsize )
+                >r 02000000 or encode-int+      \ | save size and encode BAR addr
+                0 encode-64+                    \ | make mid and lo zero
+                r> encode-64+                   \ | encode size
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ BAR-Len = 4 (32Bit)
+;
+
+\ encode the reg prop for a prefetchable 32bit MEM-BAR
+: encode-pmem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 )
+        dup pci-bar-size-mem32                  \ calc BAR-size ( not changing the BAR )
+        dup IF                                  \ IF BAR-size > 0       ( paddr plen baddr bsize )
+                >r 42000000 or encode-int+      \ | save size and encode BAR addr
+                0 encode-64+                    \ | make mid and lo zero
+                r> encode-64+                   \ | encode size
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ BAR-Len = 4 (32Bit)
+;
+
+\ encode the reg prop for a nonprefetchable 64bit MEM-BAR
+: encode-mem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 )
+        dup pci-bar-size-mem64                  \ calc BAR-size ( not changing the BAR )
+        dup IF                                  \ IF BAR-size > 0       ( paddr plen baddr bsize )
+                >r 03000000 or encode-int+      \ | save size and encode BAR addr
+                0 encode-64+                    \ | make mid and lo zero
+                r> encode-64+                   \ | encode size
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        8                                       \ BAR-Len = 8 (64Bit)
+;
+
+\ encode the reg prop for a prefetchable 64bit MEM-BAR
+: encode-pmem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 )
+        dup pci-bar-size-mem64                  \ calc BAR-size ( not changing the BAR )
+        dup IF                                  \ IF BAR-size > 0       ( paddr plen baddr bsize )
+                >r 43000000 or encode-int+      \ | save size and encode BAR addr
+                0 encode-64+                    \ | make mid and lo zero
+                r> encode-64+                   \ | encode size
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        8                                       \ BAR-Len = 8 (64Bit)
+;
+
+\ encode the reg prop for a ROM-BAR
+: encode-rom-bar ( prop-addr prop-len configaddr -- prop-addr prop-len )
+        dup pci-bar-size-rom                            \ fetch raw BAR-size
+        dup IF                                          \ IF BAR is used
+                >r 02000000 or encode-int+              \ | save size and encode BAR addr
+                0 encode-64+                            \ | make mid and lo zero
+                r> encode-64+                           \ | calc and encode the size
+        ELSE                                            \ ELSE
+                2drop                                   \ | don't do anything
+        THEN                                            \ FI
+;
+
+\ encode the reg prop for an IO-BAR
+: encode-io-bar ( prop-addr prop-len BAR-addr BAR-value -- prop-addr prop-len 4 )
+        dup pci-bar-size-io                     \ calc BAR-size ( not changing the BAR )
+        dup IF                                  \ IF BAR-size > 0       ( paddr plen baddr bsize )
+                >r 01000000 or encode-int+      \ | save size and encode BAR addr
+                0 encode-64+                    \ | make mid and lo zero
+                r> encode-64+                   \ | encode size
+        ELSE                                    \ ELSE
+                2drop                           \ | don't do anything
+        THEN                                    \ FI
+        4                                       \ BAR-Len = 4 (32Bit)
+;
+
+\ write the representation of this BAR into the reg property
+: encode-bar ( prop-addr prop-len bar-addr -- prop-addr prop-len bar-len )
+        dup pci-bar-code@                               \ calc BAR type
+        CASE                                            \ CASE for the BAR types ( paddr plen baddr val )
+                0 OF drop 4             ENDOF           \ - not a valid type so do nothing
+                1 OF encode-io-bar      ENDOF           \ - IO-BAR
+                2 OF encode-mem32-bar   ENDOF           \ - MEM32
+                3 OF encode-pmem32-bar  ENDOF           \ - MEM32 prefetchable
+                4 OF encode-mem64-bar   ENDOF           \ - MEM64
+                5 OF encode-pmem64-bar  ENDOF           \ - MEM64 prefetchable
+        ENDCASE                                         \ ESAC ( paddr plen blen )
+;
+
+\ Setup reg property
+\ first encode the configuration space address
+: pci-reg-props ( configaddr -- )
+        dup encode-int                  \ configuration space           ( caddr paddr plen )
+        0 encode-64+                    \ make the rest 0
+        0 encode-64+                    \ encode the size as 0
+        2 pick pci-htype@               \ fetch Header Type             ( caddr paddr plen type )
+        1 and IF                        \ IF Bridge                     ( caddr paddr plen )
+                18 10 DO                \ | loop over all BARs
+                        2 pick i +      \ | calc bar-addr               ( caddr paddr plen baddr )
+                        encode-bar      \ | encode this BAR             ( caddr paddr plen blen )
+                     +LOOP              \ | increase LoopIndex by the BARlen
+                2 pick 38 +             \ | calc ROM-BAR for a bridge   ( caddr paddr plen baddr )
+                encode-rom-bar          \ | encode the ROM-BAR          ( caddr paddr plen )
+        ELSE                            \ ELSE ordinary device          ( caddr paddr plen )
+               28 10 DO                 \ | loop over all BARs
+                        2 pick i +      \ | calc bar-addr               ( caddr paddr plen baddr )
+                        encode-bar      \ | encode this BAR             ( caddr paddr plen blen )
+                     +LOOP              \ | increase LoopIndex by the BARlen
+                2 pick 30 +             \ | calc ROM-BAR for a device   ( caddr paddr plen baddr )
+                encode-rom-bar          \ | encode the ROM-BAR          ( caddr paddr plen )
+        THEN                            \ FI                            ( caddr paddr plen )
+        s" reg" property                \ and store it into the property
+        drop
+;
+
+\ ***************************************************************************************
+\ Generating common properties
+\ ***************************************************************************************
+\ set up common properties for devices and bridges
+: pci-common-props ( addr -- )
+        dup pci-class-name 2dup device-name device-type
+        dup pci-vendor@    encode-int s" vendor-id"      property
+        dup pci-device@    encode-int s" device-id"      property
+        dup pci-revision@  encode-int s" revision-id"    property
+        dup pci-class@     encode-int s" class-code"     property
+                         3 encode-int s" #address-cells" property
+                         2 encode-int s" #size-cells"    property
+
+        dup pci-config-ext? IF 1 encode-int s" ibm,pci-config-space-type" property THEN
+
+        dup pci-status@
+                dup 9 rshift 3 and encode-int s" devsel-speed" property
+                dup 7 rshift 1 and IF 0 0 s" fast-back-to-back" property THEN
+                dup 6 rshift 1 and IF 0 0 s" 66mhz-capable" property THEN
+                    5 rshift 1 and IF 0 0 s" udf-supported" property THEN
+        dup pci-cache@     ?dup IF encode-int s" cache-line-size" property THEN
+            pci-interrupt@ ?dup IF encode-int s" interrupts"      property THEN
+;
+
+\ set up device only properties
+: pci-device-props ( addr -- )
+        \ FIXME no s" compatible" prop
+        \ FIXME no s" alternate-reg" prop
+        \ FIXME no s" fcode-rom-offset" prop
+        \ FIXME no s" power-consumption" prop
+        dup pci-common-props
+        dup pci-min-grant@ encode-int s" min-grant"   property
+        dup pci-max-lat@   encode-int s" max-latency" property
+        dup pci-sub-device@ ?dup IF encode-int s" subsystem-id" property THEN
+        dup pci-sub-vendor@ ?dup IF encode-int s" subsystem-vendor-id" property THEN
+        dup pci-device-assigned-addresses-prop
+        pci-reg-props
+;
+
+\ set up bridge only properties
+: pci-bridge-props ( addr -- )
+        \ FIXME no s" slot-names" prop
+        \ FIXME no s" bus-master-capable" prop
+        \ FIXME no s" clock-frequency" prop
+        dup pci-bus@
+              encode-int s" primary-bus" property
+              encode-int s" secondary-bus" property
+              encode-int s" subordinate-bus" property
+        dup pci-bus@ drop encode-int rot encode-int+ s" bus-range" property
+            pci-device-slots encode-int s" slot-names" property
+        dup pci-bridge-range-props
+        dup pci-bridge-assigned-addresses-prop
+            pci-bridge-interrupt-map
+        pci-reg-props
+;
+
+\ FIXME still used in the device files slof/fs/devices/pci-device
+: assign-bar-mapping ( bar-offset size var -- )
+        rot my-unit-64 + -rot
+        assign-bar-value32 drop
+;
+
+\ FIXME this is still used by the devices in slof/fs/devices/pci-device_*
+: assigned-addresses-property (  -- )
+        my-unit-64
+        dup pci-common-props
+            pci-device-assigned-addresses-prop
+;
+
+\ used to set up all unknown Bridges.
+\ If a Bridge has no special handling for setup
+\ the device file (pci-bridge_VENDOR_DEVICE.fs) can call
+\ this word to setup busses and scan beyond.
+: pci-bridge-generic-setup ( addr -- )
+        pci-device-slots >r             \ save the slot array on return stack
+        dup pci-common-props            \ set the common properties before scanning the bus
+        s" pci" device-type             \ the type is allways "pci"
+        dup pci-bridge-probe            \ find all device connected to it
+        dup assign-all-bridge-bars      \ set up all memory access BARs
+        dup pci-set-irq-line            \ set the interrupt pin
+        dup pci-set-capabilities        \ set up the capabilities
+            pci-bridge-props            \ and generate all properties
+        r> TO pci-device-slots          \ and reset the slot array
+;
+
+\ used for an gerneric device set up
+\ if a device has no special handling for setup
+\ the device file (pci-device_VENDOR_DEVICE.fs) can call
+\ this word to setup the device
+: pci-device-generic-setup ( config-addr -- )
+        dup assign-all-device-bars      \ calc all BARs
+        dup pci-set-irq-line            \ set the interrupt pin
+        dup pci-set-capabilities        \ set up the capabilities
+        dup pci-device-props            \ and generate all properties
+        drop                            \ forget the config-addr
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/pci-scan.fs b/qemu-0.15.x/roms/SLOF/slof/fs/pci-scan.fs
new file mode 100644
index 0000000..454631e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/pci-scan.fs
@@ -0,0 +1,495 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ ----------------------------------------------------------
+\ **********  Variables to be set by host bridge  **********
+\ ----------------------------------------------------------
+
+\ Values of the next free memory area
+VARIABLE pci-next-mem           \ prefetchable memory mapped
+VARIABLE pci-max-mem
+VARIABLE pci-next-mmio          \ non-prefetchable memory
+VARIABLE pci-max-mmio
+VARIABLE pci-next-io            \ I/O space
+VARIABLE pci-max-io
+
+\ Counter of busses found
+0 VALUE pci-bus-number
+\ Counter of devices found
+0 VALUE pci-device-number
+\ bit field of devices plugged into this bridge
+0 VALUE pci-device-slots
+\ byte field holding the device-slot number vector of the current device
+\ the vector can be as deep as the max depth of bridges possible
+\ 3,4,5 means
+\       the 5th slot on the bus of the bridge in
+\       the 4th slot on the bus of the bridge in
+\       the 3rd slot on the HostBridge bus
+here 100 allot CONSTANT pci-device-vec
+0 VALUE pci-device-vec-len
+
+
+\ Fixme Glue to the pci-devices ... remove this later
+: next-pci-mem ( addr -- addr ) pci-next-mem ;
+: next-pci-mmio ( addr -- addr ) pci-next-mmio ;
+: next-pci-io ( addr -- addr ) pci-next-io ;
+
+\ ----------------------------------------------------------
+\ ******************  Helper functions  ********************
+\ ----------------------------------------------------------
+
+\ convert an integer to string of len digits
+: int2str ( int len -- str len ) swap s>d rot <# 0 ?DO # LOOP #> ;
+
+\ convert addr to busnr
+: pci-addr2bus ( addr -- busnr ) 10 rshift FF and ;
+
+\ convert addr to devnr
+: pci-addr2dev ( addr -- dev ) B rshift 1F and ;
+
+\ convert addr to functionnumber
+: pci-addr2fn ( addr -- dev ) 8 rshift 7 and ;
+
+\ convert busnr devnr to addr
+: pci-bus2addr ( busnr devnr -- addr ) B lshift swap 10 lshift + ;
+
+\ print out a pci config addr
+: pci-addr-out ( addr -- ) dup pci-addr2bus 2 0.r space FFFF and 4 0.r ;
+
+\ Dump out the whole configspace
+: pci-dump ( addr -- )
+        10 0 DO
+                dup
+                cr i 4 * +
+                dup pci-addr-out space
+                rtas-config-l@ 8 0.r
+        LOOP
+        drop cr
+;
+
+\ Dump out the pci device-slot vector
+: pci-vec ( -- )
+        cr s" device-vec(" type
+        pci-device-vec-len dup 2 0.r s" ):" type
+        1+ 0 DO
+                pci-device-vec i + c@
+                space 2 0.r
+        LOOP
+        cr
+;
+
+\ prints out all relevant pci variables
+: var-out ( --)
+        s"   mem:" type pci-next-mem @ 16 0.r cr
+        s"  mmio:" type pci-next-mmio @ 16 0.r cr
+        s"    io:" type pci-next-io @ 16 0.r cr
+;
+
+\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\ the following functions use l@ to fetch the data,
+\ that's because the pcie core on spider has some probs with w@ !!!
+\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\ read Vendor ID
+: pci-vendor@ ( addr -- id )                 rtas-config-l@ FFFF and ;
+\ read Device ID
+: pci-device@ ( addr -- id )                 rtas-config-l@ 10 rshift ;
+\ read Status
+: pci-status@ ( addr -- status )         4 + rtas-config-l@ 10 rshift ;
+\ read Revision ID
+: pci-revision@ ( addr -- id )           8 + rtas-config-b@ ;
+\ read Class Code
+: pci-class@  ( addr -- class )          8 + rtas-config-l@ 8 rshift ;
+\ read Cache Line Size
+: pci-cache@  ( addr -- size )           C + rtas-config-b@ ;
+\ read Header Type
+: pci-htype@  ( addr -- type )           E + rtas-config-b@  ;
+\ read Sub Vendor ID
+: pci-sub-vendor@ ( addr -- sub-id )    2C + rtas-config-l@ FFFF and ;
+\ read Sub Device ID
+: pci-sub-device@ ( addr -- sub-id )    2C + rtas-config-l@ 10 rshift FFFF and ;
+\ read Interrupt Pin
+: pci-interrupt@  ( addr -- interrupt ) 3D + rtas-config-b@ ;
+\ read Minimum Grant
+: pci-min-grant@  ( addr -- min-gnt )   3E + rtas-config-b@ ;
+\ read Maximum Latency
+: pci-max-lat@  ( addr -- max-lat )     3F + rtas-config-b@ ;
+\ Check if Capabilities are valid
+: pci-capabilities?  ( addr -- 0|1 ) pci-status@ 4 rshift 1 and ;
+\ fetch the offset of the next capability
+: pci-cap-next  ( cap-addr -- next-cap-off ) rtas-config-b@ FC and ;
+\ calc the address of the next capability
+: pci-cap-next-addr  ( cap-addr -- next-cap-addr ) 1+ dup pci-cap-next dup IF swap -100 and + ELSE nip THEN ;
+
+\ Dump out all capabilities
+: pci-cap-dump ( addr -- )
+        cr
+        dup pci-capabilities? IF
+                33 + BEGIN
+                        pci-cap-next-addr dup 0<>
+                WHILE
+                        dup pci-addr-out s"  : " type
+                        dup rtas-config-b@ 2 0.r cr
+                REPEAT
+                s" end found "
+        ELSE
+                s" capabilities not enabled!"
+        THEN
+        type cr drop
+;
+
+\ search the capability-list for this id
+: pci-cap-find ( addr id -- capp-addr|0 )
+        swap dup pci-capabilities? IF
+                33 + BEGIN
+                        pci-cap-next-addr dup 0<> IF
+                                dup rtas-config-b@ 2 pick =
+                        ELSE
+                                true
+                        THEN
+                UNTIL
+                nip
+        ELSE
+                2drop 0
+        THEN
+;
+
+\ check wether this device is a pci-express device
+: pci-express? ( addr -- 0|1 ) 10 pci-cap-find 0<> ;
+
+\ check wether this device is a pci-express device
+: pci-x? ( addr -- 0|1 ) 07 pci-cap-find 0<> ;
+
+\ check wether this device has extended config space
+: pci-config-ext? ( addr -- 0|1 ) pci-express? ;
+
+\ set and fetch the interrupt Pin
+: pci-irq-line@  ( addr -- irq-pin ) 3C + rtas-config-b@ ;
+: pci-irq-line!  ( pin addr -- ) 3C + rtas-config-b! ;
+
+\ set and fetch primary bus number
+: pci-bus-prim! ( nr addr -- ) 18 + dup rtas-config-l@ FFFFFF00 and rot + swap rtas-config-l! ;
+: pci-bus-prim@ ( addr -- nr ) 18 + rtas-config-l@ FF and ;
+
+\ set and fetch secondary bus number
+: pci-bus-scnd! ( nr addr -- ) 18 + dup rtas-config-l@ FFFF00FF and rot 8 lshift + swap rtas-config-l! ;
+: pci-bus-scnd@ ( addr -- nr ) 18 + rtas-config-l@ 8 rshift FF and ;
+
+\ set and fetch subordinate bus number
+: pci-bus-subo! ( nr addr -- ) 18 + dup rtas-config-l@ FF00FFFF and rot 10 lshift + swap rtas-config-l! ;
+: pci-bus-subo@ ( addr -- nr ) 18 + rtas-config-l@ 10 rshift FF and ;
+
+\ set and fetch primary, secondary and subordinate bus number
+: pci-bus! ( subo scnd prim addr -- ) swap rot 8 lshift + rot 10 lshift + swap 18 + dup rtas-config-l@ FF000000 and rot + swap rtas-config-l! ;
+: pci-bus@ ( addr -- subo scnd prim ) 18 + rtas-config-l@ dup 10 rshift FF and swap dup 8 rshift FF and swap FF and ;
+
+\ Reset secondary Status
+: pci-reset-2nd ( addr -- ) 1C + dup rtas-config-l@ FFFF0000 or swap rtas-config-l! ;
+
+\ Disable Bus Master, Memory Space and I/O Space for this device
+: pci-device-disable ( -- ) my-space 4 + dup rtas-config-l@ 7 invert and swap rtas-config-l! ;
+
+\ Enable Bus Master
+: pci-master-enable ( -- ) my-space 4 + dup rtas-config-l@ 4 or swap rtas-config-l! ;
+
+\ Disable Bus Master
+: pci-master-disable ( -- ) my-space 4 + dup rtas-config-l@ 4 invert and swap rtas-config-l! ;
+
+\ Enable response to mem accesses of pci device
+: pci-mem-enable ( -- ) my-space 4 + dup rtas-config-w@ 2 or swap rtas-config-w! ;
+: enable-mem-access ( -- ) pci-mem-enable ;
+
+\ Enable response to I/O accesses of pci-device
+: pci-io-enable ( -- ) my-space 4 + dup rtas-config-w@ 1 or swap rtas-config-w! ;
+: enable-io-access ( -- ) pci-io-enable ;
+
+\ Enable Bus Master, I/O and mem access
+: pci-enable ( -- ) my-space 4 + dup rtas-config-w@ 7 or swap rtas-config-w! ;
+
+\ Enable #PERR and #SERR errors of pci-device
+: pci-error-enable ( -- ) my-space 4 + dup rtas-config-w@ 140 or swap rtas-config-w! ;
+
+\ prints out the ScanInformation about a device
+\ char is a sign for device type e.g. D - device ; B - bridge
+: pci-out ( addr char -- )
+        15 spaces
+        over pci-addr-out
+        s"  (" type emit s" ) : " type
+        dup pci-vendor@ 4 0.r space
+        pci-device@ 4 0.r
+        4 spaces
+;
+
+\ Update the device-slot number vector
+\ Set the bit of the DeviceSlot in the Slot array
+: pci-set-slot ( addr -- )
+        pci-addr2dev dup                \ calc slot number
+        pci-device-vec-len              \ the end of the vector
+        pci-device-vec + c!             \ and update the vector
+        80000000 swap rshift            \ calc bit position of the device slot
+        pci-device-slots or             \ set this bit
+        TO pci-device-slots             \ and write it back
+;
+
+\ Update pci-next-mmio to be 1MB aligned and set the mmio-base register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-mmio-base ( addr -- )
+        pci-next-mmio @ 100000 #aligned         \ read the current Value and align to 1MB boundary
+        dup pci-next-mmio !                     \ and write it back
+        10 rshift                               \ mmio-base reg is only the upper 16 bits
+        pci-max-mmio @ FFFF0000 and or          \ and Insert mmio Limit (set it to max)
+        swap 20 + rtas-config-l!                \ and write it into the bridge
+;
+
+\ Update pci-next-mmio to be 1MB aligned and set the mmio-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the mmio is disabled
+: pci-bridge-set-mmio-limit ( addr -- )
+        pci-next-mmio @ 100000 #aligned         \ fetch current value and align to 1MB
+        dup pci-next-mmio !                     \ and write it back
+        1- FFFF0000 and                         \ make it one less and keep upper 16 bits
+        over 20 + rtas-config-l@ 0000FFFF and   \ fetch original value
+        or swap 20 + rtas-config-l!             \ and write it into the Reg
+;
+
+\ Update pci-next-mem to be 1MB aligned and set the mem-base and mem-base-upper register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-mem-base ( addr -- )
+        pci-next-mem @ 100000 #aligned          \ read the current Value and align to 1MB boundary
+        dup pci-next-mem !                      \ and write it back
+        over 24 + rtas-config-w@                \ check if 64bit support
+        1 and IF                                \ IF 64 bit support
+                2dup 20 rshift                  \ | keep upper 32 bits
+                swap 28 + rtas-config-l!        \ | and write it into the Base-Upper32-bits
+                pci-max-mem @ 20 rshift         \ | fetch max Limit address and keep upper 32 bits
+                2 pick 2C + rtas-config-l!      \ | and set the Limit
+        THEN                                    \ FI
+        10 rshift                               \ keep upper 16 bits
+        pci-max-mem @ FFFF0000 and or           \ and Insert mmem Limit (set it to max)
+        swap 24 + rtas-config-l!                \ and write it into the bridge
+;
+
+\ Update pci-next-mem to be 1MB aligned and set the mem-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the mem is disabled
+: pci-bridge-set-mem-limit ( addr -- )
+        pci-next-mem @ 100000 #aligned          \ read the current Value and align to 1MB boundary
+        dup pci-next-mem !                      \ and write it back
+        1-                                      \ make limit one less than boundary
+        over 24 + rtas-config-w@                \ check if 64bit support
+        1 and IF                                \ IF 64 bit support
+                2dup 20 rshift                  \ | keep upper 32 bits
+                swap 2C + rtas-config-l!        \ | and write it into the Limit-Upper32-bits
+        THEN                                    \ FI
+        FFFF0000 and                            \ keep upper 16 bits
+        over 24 + rtas-config-l@ 0000FFFF and   \ fetch original Value
+        or swap 24 + rtas-config-l!             \ and write it into the bridge
+;
+
+\ Update pci-next-io to be 4KB aligned and set the io-base and io-base-upper register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-io-base ( addr -- )
+        pci-next-io @ 1000 #aligned             \ read the current Value and align to 4KB boundary
+        dup pci-next-io !                       \ and write it back
+        over 1C + rtas-config-l@                \ check if 32bit support
+        1 and IF                                \ IF 32 bit support
+                2dup 10 rshift                  \ | keep upper 16 bits
+                pci-max-io @ FFFF0000 and or    \ | insert upper 16 bits of Max-Limit
+                swap 30 + rtas-config-l!        \ | and write it into the Base-Upper16-bits
+        THEN                                    \ FI
+        8 rshift 000000FF and                   \ keep upper 8 bits
+        pci-max-io @ 0000FF00 and or            \ insert upper 8 bits of Max-Limit
+        over rtas-config-l@ FFFF0000 and        \ fetch original Value
+        or swap 1C + rtas-config-l!             \ and write it into the bridge
+;
+
+\ Update pci-next-io to be 4KB aligned and set the io-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the io is disabled
+: pci-bridge-set-io-limit ( addr -- )
+        pci-next-io @ 1000 #aligned             \ read the current Value and align to 4KB boundary
+        dup pci-next-io !                       \ and write it back
+        1-                                      \ make limit one less than boundary
+        over 1D + rtas-config-b@                \ check if 32bit support
+        1 and IF                                \ IF 32 bit support
+                2dup FFFF0000 and               \ | keep upper 16 bits
+                over 30 + rtas-config-l@        \ | fetch original Value
+                or swap 30 + rtas-config-l!     \ | and write it into the Limit-Upper16-bits
+        THEN                                    \ FI
+        0000FF00 and                            \ keep upper 8 bits
+        over 1C + rtas-config-l@ FFFF00FF and   \ fetch original Value
+        or swap 1C + rtas-config-l!             \ and write it into the bridge
+;
+
+\ set up all base registers to the current variable Values
+: pci-bridge-set-bases ( addr -- )
+        dup pci-bridge-set-mmio-base
+        dup pci-bridge-set-mem-base
+            pci-bridge-set-io-base
+;
+
+\ set up all limit registers to the current variable Values
+: pci-bridge-set-limits ( addr -- )
+        dup pci-bridge-set-mmio-limit
+        dup pci-bridge-set-mem-limit
+            pci-bridge-set-io-limit
+;
+
+\ ----------------------------------------------------------
+\ ******************  PCI Scan functions  ******************
+\ ----------------------------------------------------------
+
+\ define function pointer as forward declaration of pci-probe-bus
+DEFER func-pci-probe-bus
+
+\ Setup the Base and Limits in the Bridge
+\ and scan the bus(es) beyond that Bridge
+: pci-bridge-probe ( addr -- )
+        dup pci-bridge-set-bases                        \ SetUp all Base Registers
+        pci-bus-number 1+ TO pci-bus-number             \ increase number of busses found
+        pci-device-vec-len 1+ TO pci-device-vec-len     \ increase the device-slot vector depth
+        dup                                             \ stack config-addr for pci-bus!
+        FF swap                                         \ Subordinate Bus Number ( for now to max to open all subbusses )
+        pci-bus-number swap                             \ Secondary   Bus Number ( the new busnumber )
+        dup pci-addr2bus swap                           \ Primary     Bus Number ( the current bus )
+        pci-bus!                                        \ and set them into the bridge
+        pci-enable                                      \ enable mem/IO transactions
+        dup pci-bus-scnd@ func-pci-probe-bus            \ and probe the secondary bus
+        dup pci-bus-number swap pci-bus-subo!           \ set SubOrdinate Bus Number to current number of busses
+        pci-device-vec-len 1- TO pci-device-vec-len     \ decrease the device-slot vector depth
+        dup pci-bridge-set-limits                       \ SetUp all Limit Registers
+        drop                                            \ forget the config-addr
+;
+
+\ set up the pci-device
+: pci-device-setup ( addr -- )
+        drop                            \ since the config-addr is coded in my-space, drop it here
+        s" pci-device.fs" included      \ and setup the device as node in the device tree
+;
+
+\ set up the pci bridge
+: pci-bridge-setup ( addr -- )
+        drop                            \ since the config-addr is coded in my-space, drop it here
+        s" pci-bridge.fs" included      \ and setup the bridge as node in the device tree
+;
+
+\ add the new found device/bridge to the device tree and set it up
+: pci-add-device ( addr -- )
+        new-device                      \ create a new device-tree node
+            dup set-space               \ set the config addr for this device tree entry
+            dup pci-set-slot            \ set the slot bit
+            dup pci-htype@              \ read HEADER-Type
+            1 and IF                    \ IF BRIDGE
+                    pci-bridge-setup    \ | set up the bridge
+            ELSE                        \ ELSE
+                    pci-device-setup    \ | set up the device
+            THEN                        \ FI
+        finish-device                   \ and close the device-tree node
+;
+
+\ check for multifunction and for each function
+\ (dependig from header type) call device or bridge setup
+: pci-setup-device ( addr -- )
+        dup pci-htype@                      \ read HEADER-Type
+        80 and IF 8 ELSE 1 THEN             \ check for multifunction
+        0 DO                                \ LOOP over all possible functions (either 8 or only 1)
+                dup
+                i 8 lshift +                \ calc device-function-config-addr
+                dup pci-vendor@             \ check if valid function
+                FFFF = IF
+                        drop                \ non-valid so forget the address
+                ELSE
+                    pci-device-number 1+    \ increase the number of devices
+                    TO pci-device-number    \ and store it
+                    pci-add-device          \ and add the device to the device tree and set it up
+                THEN
+        LOOP                                \ next function
+        drop                                \ forget the device-addr
+;
+
+\ check if a device is plugged into this bus at this device number
+: pci-probe-device ( busnr devicenr -- )
+        pci-bus2addr                                    \ calc pci-address
+        dup pci-vendor@                                 \ fetch Vendor-ID
+        FFFF = IF                                       \ check if valid
+                drop                                    \ if not forget it
+        ELSE
+                pci-setup-device                        \ if valid setup the device
+        THEN
+;
+
+\ walk through all 32 possible pci devices on this bus and probe them
+: pci-probe-bus ( busnr -- )
+        0 TO pci-device-slots           \ reset slot array to unpoppulated
+        20 0 DO
+                dup
+                i pci-probe-device
+        LOOP
+        drop
+;
+
+\ setup the function pointer used in pci-bridge-setup
+' pci-probe-bus TO func-pci-probe-bus
+
+\ ----------------------------------------------------------
+\ ******************  System functions  ********************
+\ ----------------------------------------------------------
+\ Setup the whole system for pci devices
+\ start with the bus-min and try all busses
+\ until at least 1 device was found
+\ ( needed for HostBridges that don't start with Bus 0 )
+: pci-probe-all ( bus-max bus-min -- )                  \ Check all busses from bus-min up to bus-max if needed
+        0 TO pci-device-vec-len                         \ reset the device-slot vector
+        DO
+                i TO pci-bus-number                     \ set current Busnumber
+                0 TO pci-device-number                  \ reset Device Number
+                pci-bus-number pci-probe-bus            \ and probe this bus
+                pci-device-number 0 > IF LEAVE THEN     \ if we found a device we're done
+        LOOP                                            \ else next bus
+;
+
+\ probe the hostbridge that is specified in my-puid
+\ for the mmio mem and io addresses:
+\ base is the least available address
+\ max is the highest available address
+: probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- )
+        puid >r TO puid                                 \ save puid and set the new
+        pci-next-io !                                   \ save the next io-base address
+        pci-max-io !                                    \ save the max io-space address
+        pci-next-mem !                                  \ save the next mem-base address
+        pci-max-mem !                                   \ save the max mem-space address
+        pci-next-mmio !                                 \ save the next mmio-base address
+        pci-max-mmio !                                  \ save the max mmio-space address
+
+        0d emit ."  Adapters on " puid 10 0.r cr        \ print the puid we're looking at
+        ( bus-max bus-min ) pci-probe-all               \ and walk the bus
+        pci-device-number 0= IF                         \ IF no devices found
+                15 spaces                               \ | indent the output
+                ." None" cr                             \ | tell the world our result
+        THEN                                            \ FI
+        r> TO  puid                                     \ restore puid
+;
+
+\ provide the device-alias definition words
+#include <pci-aliases.fs>
+
+\ provide all words for the interrupts settings
+#include <pci-interrupts.fs>
+
+\ provide all words for the pci capabilities init
+#include <pci-capabilities.fs>
+
+\ provide all words needed to generate the properties and/or assign BAR values
+#include "pci-properties.fs"
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/preprocessor.fs b/qemu-0.15.x/roms/SLOF/slof/fs/preprocessor.fs
new file mode 100644
index 0000000..a13fb30
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/preprocessor.fs
@@ -0,0 +1,41 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: ([IF])
+  BEGIN
+    BEGIN parse-word dup 0= WHILE
+      2drop refill
+    REPEAT
+
+    2dup s" [IF]" str= IF 1 throw THEN
+    2dup s" [ELSE]" str= IF 2 throw THEN
+    2dup s" [THEN]" str= IF 3 throw THEN
+    s" \" str= IF linefeed parse 2drop THEN
+  AGAIN
+  ;
+
+: [IF] ( flag -- )
+  IF exit THEN
+  1 BEGIN
+    ['] ([IF]) catch 
+    CASE
+      1 OF 1+ ENDOF
+      2 OF dup 1 = if 1- then ENDOF
+      3 OF 1- ENDOF
+    ENDCASE
+    dup 0 <=
+  UNTIL drop
+; immediate
+
+: [ELSE] 0 [COMPILE] [IF] ; immediate
+: [THEN] ; immediate
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/property.fs b/qemu-0.15.x/roms/SLOF/slof/fs/property.fs
new file mode 100644
index 0000000..c02a07d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/property.fs
@@ -0,0 +1,189 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Properties 5.3.5
+
+\ Words on the property list for a node are actually executable words,
+\ that return the address and length of the property's data.  Special
+\ nodes like /options can have their properties use specialized code to
+\ dynamically generate their data; most nodes just use a 2CONSTANT.
+
+\ Put the type as byte before the property
+\   { int = 1, bytes = 2, string = 3 }
+\ This is used by .properties for pretty print
+
+\ Flag for type encoding, encode-* resets, set-property set the flag
+true value encode-first?
+
+: decode-int  over >r 4 /string r> 4c@ swap 2swap swap bljoin ;
+: decode-64 decode-int -rot decode-int -rot 2swap swap lxjoin ;
+: decode-string ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 str len )
+   dup 0= IF 2dup EXIT THEN \ string properties with zero lenght
+   over BEGIN dup c@ 0= IF 1+ -rot swap 2 pick over - rot over - -rot 1-
+    EXIT THEN 1+ AGAIN ;
+
+\ Remove a word from a wordlist.
+: (prune) ( name len head -- )
+  dup >r (find) ?dup IF r> BEGIN dup @ WHILE 2dup @ = IF
+  >r @ r> ! EXIT THEN @ REPEAT 2drop ELSE r> drop THEN ;
+: prune ( name len -- )  last (prune) ;
+
+: set-property ( data dlen name nlen phandle -- )
+    true to encode-first?
+    get-current >r  node>properties @ set-current
+    2dup prune  $2CONSTANT  r> set-current ;
+: delete-property ( name nlen -- )
+    get-node get-current >r  node>properties @ set-current
+    prune r> set-current ;
+: property ( data dlen name nlen -- )  get-node set-property ;
+: get-property ( str len phandle -- true | data dlen false )
+  ?dup 0= IF cr cr cr ." get-property for " type ."  on zero phandle"
+  cr cr true EXIT THEN
+  node>properties @ voc-find dup IF link> execute false ELSE drop true THEN ;
+: get-package-property ( str len phandle -- true | data dlen false )
+  get-property ;
+: get-my-property ( str len -- true | data dlen false )
+  my-self ihandle>phandle get-property ;
+: get-parent-property ( str len -- true | data dlen false )
+  my-parent ihandle>phandle get-property ;
+: get-inherited-property ( str len -- true | data dlen false )
+    my-self ihandle>phandle
+    BEGIN 3dup get-property 0=
+	IF  \ Property found
+	    rot drop rot drop rot drop false EXIT
+	THEN
+	  parent 0=
+	IF
+	    nip nip true EXIT
+	THEN
+    AGAIN ;
+
+\ Print out properties.
+
+20 CONSTANT indent-prop
+
+: .prop-int ( str len -- )
+   space
+   400 min 0
+   ?DO
+      i over + dup                                 ( str act-addr act-addr )
+      c@ 2 0.r 1+ dup c@ 2 0.r 1+ dup c@ 2 0.r 1+ c@ 2 0.r ( str )
+      i c and c = IF                           \ check for multipleof 16 bytes
+	 cr indent @ indent-prop + 1+ 0        \ linefeed + indent
+	 DO
+	    space                              \ print spaces
+	 LOOP
+      ELSE
+	 space space                           \ print two spaces
+      THEN
+   4 +LOOP
+   drop
+;
+
+: .prop-bytes ( str len -- )
+   2dup -4 and .prop-int                       ( str len )
+
+   dup 3 and dup IF                            ( str len len%4 )
+      >r -4 and + r>                           ( str' len%4 )
+      bounds                                   ( str' str'+len%4 )
+      DO
+	 i c@ 2 0.r                            \ Print last 3 bytes
+      LOOP
+   ELSE
+      3drop
+   THEN
+;
+
+: .prop-string ( str len )
+   2dup space type
+   cr indent @ indent-prop + 0 DO space LOOP   \ Linefeed
+   .prop-bytes
+;
+
+: .propbytes ( xt -- )
+   execute dup
+   IF
+      over cell- @ execute
+   ELSE
+      2drop
+   THEN
+;
+: .property ( lfa -- )
+    cr indent @ 0
+    ?DO
+	space
+    LOOP
+    link> dup >name name>string 2dup type nip ( len )
+    indent-prop swap -                        ( xt 20-len )
+    dup 0< IF drop 0 THEN 0                   ( xt number-of-space 0 )
+    ?DO
+	space
+    LOOP
+    .propbytes
+;
+: (.properties) ( phandle -- )
+  node>properties @ cell+ @ BEGIN dup WHILE dup .property @ REPEAT drop ;
+: .properties ( -- )
+  get-node (.properties) ;
+
+: next-property ( str len phandle -- false | str' len' true )
+  ?dup 0= IF device-tree @ THEN  \ XXX: is this line required?
+  node>properties @
+  >r 2dup 0= swap 0= or IF 2drop r> cell+ ELSE r> voc-find THEN
+  @ dup IF link>name name>string true THEN ;
+
+
+\ encode-* words and all helpers
+
+\ Start a encoded property string
+: encode-start ( -- prop 0 )
+   ['] .prop-int compile,
+   false to encode-first?
+   here 0
+;
+
+: encode-int ( val -- prop prop-len )
+   encode-first? IF
+      ['] .prop-int compile,             \ Execution token for print
+      false to encode-first?
+   THEN
+   here swap lbsplit c, c, c, c, /l
+;
+: encode-bytes ( str len -- prop-addr prop-len )
+   encode-first? IF
+      ['] .prop-bytes compile,           \ Execution token for print
+      false to encode-first?
+   THEN
+   here over 2dup 2>r allot swap move 2r>
+;
+: encode-string ( str len -- prop-addr prop-len )
+   encode-first? IF
+      ['] .prop-string compile,          \ Execution token for print
+      false to encode-first?
+   THEN
+   encode-bytes 0 c, char+
+;
+
+: encode+ ( prop1-addr prop1-len prop2-addr prop2-len -- prop-addr prop-len )
+   nip + ;
+: encode-int+  encode-int encode+ ;
+: encode-64    xlsplit encode-int rot encode-int+ ;
+: encode-64+   encode-64 encode+ ;
+
+
+\ Helpers for common nodes.  Should perhaps remove "compatible", as it's
+\ not typically a single string.
+: device-name  encode-string s" name"        property ;
+: device-type  encode-string s" device_type" property ;
+: model        encode-string s" model"       property ;
+: compatible   encode-string s" compatible"  property ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/quiesce.fs b/qemu-0.15.x/roms/SLOF/slof/fs/quiesce.fs
new file mode 100644
index 0000000..3b2dee9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/quiesce.fs
@@ -0,0 +1,54 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+10 CONSTANT quiesce-xt#
+
+\ The array with the quiesce execution tokens:
+CREATE quiesce-xts quiesce-xt# cells allot
+quiesce-xts quiesce-xt# cells erase
+
+
+\ Add a token to the quiesce execution token array:
+: add-quiesce-xt  ( xt -- )
+   quiesce-xt# 0 DO
+      quiesce-xts I cells +    ( xt arrayptr )
+      dup @ 0=                 ( xt arrayptr true|false )
+      IF
+         ! UNLOOP EXIT
+      ELSE                     ( xt arrayptr )
+         over swap             ( xt xt arrayptr )
+         @ =                   \ xt already stored ?
+         IF
+            drop UNLOOP EXIT
+         THEN                  ( xt )
+      THEN
+   LOOP
+   drop                        ( xt -- )
+   ." Warning: quiesce xt list is full." cr
+;
+
+
+\ The quiesce call asserts that the firmware and all hardware
+\ is in a sane state (e.g. assert that no background DMA is
+\ running anymore)
+: quiesce  ( -- )
+   quiesce-xt# 0 DO
+      quiesce-xts I cells +    ( arrayptr )
+      @ dup IF                 ( xt )
+         EXECUTE
+      ELSE
+         drop UNLOOP EXIT
+      THEN
+   LOOP
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rmove.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rmove.fs
new file mode 100644
index 0000000..c28dba9
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rmove.fs
@@ -0,0 +1,53 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+defer '(r@)
+defer '(r!)
+1 VALUE /(r)
+
+
+\ The rest of the code already implemented in prim.in
+\ In the end all of this should be moved over there and this file terminated
+
+: (rfill) ( addr size pattern 'r! /r -- )
+	to /(r) to '(r!) ff and
+	dup 8 lshift or dup 10 lshift or dup 20 lshift or
+	-rot bounds ?do dup i '(r!) /(r) +loop drop
+;
+
+: (fwrmove) ( src dest size -- )
+	>r 0 -rot r> bounds ?do + dup '(r@) i '(r!) /(r) dup +loop 2drop
+;
+
+\ Move from main to device memory
+: mrmove ( src dest size -- )
+	3dup or or 7 AND CASE
+		0 OF ['] x@ ['] rx! /x ENDOF
+		4 OF ['] l@ ['] rl! /l ENDOF
+		2 OF ['] w@ ['] rw! /w ENDOF
+		dup OF ['] c@ ['] rb! /c ENDOF
+	ENDCASE
+	( We already know that source and destination do not overlap )
+	to /(r) to '(r!) to '(r@) (fwrmove)
+;
+
+: rfill ( addr size pattern -- )
+	3dup drop or 7 AND CASE
+		0 OF ['] rx! /x ENDOF
+		4 OF ['] rl! /l ENDOF
+		2 OF ['] rw! /w ENDOF
+		dup OF ['] rb! /c ENDOF
+	ENDCASE (rfill)
+;
+
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/romfs.fs b/qemu-0.15.x/roms/SLOF/slof/fs/romfs.fs
new file mode 100644
index 0000000..7d7e4637
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/romfs.fs
@@ -0,0 +1,123 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+STRUCT
+	cell field romfs>file-header
+	cell field romfs>data
+	cell field romfs>data-size
+	cell field romfs>flags
+
+CONSTANT /romfs-lookup-control-block
+
+CREATE romfs-lookup-cb /romfs-lookup-control-block allot
+romfs-lookup-cb /romfs-lookup-control-block erase
+
+: create-filename ( string -- string\0 )
+    here >r dup 8 + allot
+    r@ over 8 + erase
+    r@ zplace r> ;
+
+: romfs-lookup ( fn-str fn-len -- data size | false )
+    create-filename romfs-base
+    romfs-lookup-cb romfs-lookup-entry call-c
+    0= IF romfs-lookup-cb dup romfs>data @ swap romfs>data-size @ ELSE
+    false THEN ;
+
+: ibm,romfs-lookup ( fn-str fn-len -- data-high data-low size | 0 0 false )
+  romfs-lookup dup
+  0= if drop 0 0 false else
+  swap dup 20 rshift swap ffffffff and then ;
+
+\ FIXME For a short time ...
+: romfs-lookup-client ibm,romfs-lookup ;
+
+\ Fixme temp implementation
+
+STRUCT
+	cell field romfs>next-off
+	cell field romfs>size
+	cell field romfs>flags
+	cell field romfs>data-off
+	cell field romfs>name
+
+CONSTANT /romfs-cb
+
+: romfs-map-file ( fn-str fn-len -- file-addr file-size )
+  romfs-base >r
+  BEGIN 2dup r@ romfs>name zcount string=ci not WHILE
+    ( fn-str fn-len ) ( R: rom-cb-file-addr )
+    r> romfs>next-off dup @ dup 0= IF 1 THROW THEN + >r REPEAT
+    ( fn-str fn-len ) ( R: rom-cb-file-addr )
+    2drop r@ romfs>data-off @ r@ + r> romfs>size @ ;
+
+\ returns address of romfs-header file
+: flash-header ( -- address | false )
+    get-flash-base 28 +         \ prepare flash header file address
+    dup rx@                     \ fetch "magic123"
+    6d61676963313233 <> IF      \ IF flash is not valid
+       drop                     \ | forget address
+       false                    \ | return false
+    THEN                        \ FI
+;
+
+CREATE bdate-str 10 allot
+: bdate2human ( -- addr len )
+  flash-header 40 + rx@ (.)
+  drop dup 0 + bdate-str 6 + 4 move
+  dup 4 + bdate-str 0 + 2 move
+  dup 6 + bdate-str 3 + 2 move
+  dup 8 + bdate-str b + 2 move
+  a + bdate-str e + 2 move
+  2d bdate-str 2 + c!
+  2d bdate-str 5 + c!
+  20 bdate-str a + c!
+  3a bdate-str d + c!
+  bdate-str 10
+;
+
+
+\ Look up a file in the ROM file system and evaluate it
+
+: included  ( fn fn-len -- )
+   2dup >r >r romfs-lookup dup IF
+      r> drop r> drop evaluate
+   ELSE
+      drop ." Cannot open file : " r> r> type cr
+   THEN
+;
+
+: include  ( " fn " -- )
+   parse-word included
+;
+
+: ?include  ( flag " fn " -- )
+   parse-word rot IF included ELSE 2drop THEN
+;
+
+: include?  ( nargs flag " fn " -- )
+   parse-word rot IF
+      rot drop included
+   ELSE
+      2drop 0 ?DO drop LOOP
+   THEN
+;
+
+
+\ List files in ROMfs
+
+: (print-romfs-file-info)  ( file-addr -- )
+   9 emit  dup b 0.r  2 spaces  dup 8 + @ 6 0.r  2 spaces  20 + zcount type cr
+;
+
+: romfs-list  ( -- )
+   romfs-base 0 cr BEGIN + dup (print-romfs-file-info) dup @ dup 0= UNTIL 2drop
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/root.fs b/qemu-0.15.x/roms/SLOF/slof/fs/root.fs
new file mode 100644
index 0000000..429b77e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/root.fs
@@ -0,0 +1,57 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ this creates the root and common branches of the device tree
+
+defer (client-exec)
+defer client-exec
+
+\ defined in slof/fs/client.fs
+defer callback
+defer continue-client
+
+: set-chosen ( prop len name len -- )
+  s" /chosen" find-node set-property ;
+
+: get-chosen ( name len -- [ prop len ] success )
+  s" /chosen" find-node get-property 0= ;
+
+new-device
+  s" /" device-name
+  new-device
+    s" chosen" device-name
+    s" " encode-string s" bootargs" property
+    s" " encode-string s" bootpath" property
+  finish-device
+
+  new-device
+    s" aliases" device-name
+  finish-device
+
+  new-device
+    s" options" device-name
+  finish-device
+
+
+  new-device
+    s" openprom" device-name
+    s" BootROM" device-type
+  finish-device
+
+  new-device 
+#include <packages.fs>
+  finish-device
+
+: open true ;
+: close ;
+
+finish-device
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-cpu.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-cpu.fs
new file mode 100644
index 0000000..c133abc
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-cpu.fs
@@ -0,0 +1,23 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: rtas-start-cpu  ( pid loc r3 -- status )
+   [ s" start-cpu" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   3  rtas-cb rtas>nargs l!
+   1  rtas-cb rtas>nret l!
+   rtas-cb rtas>args2 l!
+   rtas-cb rtas>args1 l!
+   rtas-cb rtas>args0 l!
+   0 rtas-cb rtas>args3 l!
+   enter-rtas
+   rtas-cb rtas>args3 l@
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-flash.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-flash.fs
new file mode 100644
index 0000000..f8abeaa
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-flash.fs
@@ -0,0 +1,46 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: rtas-ibm-update-flash-64-and-reboot  ( block-list -- status )
+   [ s" ibm,update-flash-64-and-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   1 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
+
+: rtas-ibm-manage-flash-image  ( image-to-commit -- status )
+   [ s" ibm,manage-flash-image" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   1 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
+
+: rtas-set-flashside  ( flashside -- status )
+   [ s" rtas-set-flashside" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   1 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
+
+: rtas-get-flashside  ( -- status )
+   [ s" rtas-get-flashside" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   0 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   enter-rtas
+   rtas-cb rtas>args0 l@
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-init.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-init.fs
new file mode 100644
index 0000000..8451cfd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-init.fs
@@ -0,0 +1,121 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ (rtas-size) determines the size required for RTAS.
+\ It looks at the rtas binary in the flash and reads the rtas-size from
+\ its header at offset 8.
+: (rtas-size)  ( -- rtas-size )
+   s" rtas" romfs-lookup dup 0=
+   ABORT" romfs-lookup for rtas failed"
+   drop 8 + @
+;
+
+(rtas-size) CONSTANT rtas-size
+
+: instantiate-rtas ( adr -- entry )
+    dup rtas-size erase
+    s" rtas" romfs-lookup 0=
+    ABORT" romfs-lookup for rtas failed"
+    rtas-config swap start-rtas ;
+
+here fff + fffffffffffff000 and here - allot
+here rtas-size allot CONSTANT rtas-start-addr
+
+rtas-start-addr instantiate-rtas CONSTANT rtas-entry-point
+
+: drone-rtas
+   rtas-start-addr
+   dup rtas-size erase
+   2000000 start-rtas to rtas-entry-point
+;
+
+
+\ ffffffffffffffff CONSTANT rtas-entry-point
+
+\ rtas control block
+
+STRUCT
+	/l field rtas>token
+	/l field rtas>nargs
+	/l field rtas>nret
+	/l field rtas>args0
+        /l field rtas>args1
+        /l field rtas>args2
+        /l field rtas>args3
+        /l field rtas>args4
+        /l field rtas>args5
+        /l field rtas>args6
+        /l field rtas>args7
+        /l C * field rtas>args
+        /l field rtas>bla
+
+CONSTANT /rtas-control-block
+
+CREATE rtas-cb /rtas-control-block allot
+rtas-cb  /rtas-control-block erase
+
+\ call-c ( p0 p1 p2 entry -- ret )
+
+: enter-rtas ( -- )
+    rtas-cb rtas-start-addr 0 rtas-entry-point call-c drop ;
+
+
+\ This is the structure of the RTAS function jump table in the C code:
+STRUCT
+	cell FIELD rtasfunctab>name
+	cell FIELD rtasfunctab>func
+	cell FIELD rtasfunctab>flags
+CONSTANT rtasfunctab-size
+
+\ Create RTAS token properties by analyzing the jump table in the C code:
+: rtas-create-token-properties ( -- )
+    rtas-start-addr 10 + @ rtas-start-addr +     \ Get pointer to jump table
+    rtas-start-addr 18 + @ rtas-start-addr + l@  \ Get the number of entries
+    0  DO
+	dup rtasfunctab>func @ 0<>            \ function pointer must not be NULL
+	over rtasfunctab>flags @ 1 and 0=     \ Check the only-internal flag
+	and
+	IF
+	    i 1+ encode-int                   \ Create the token value
+	    2 pick rtasfunctab>name @ zcount  \ Create the token name string
+	    property                          \ Create the property
+	THEN
+	rtasfunctab-size +                    \ Proceed to the next entry
+    LOOP
+    drop
+;
+
+\ Get the RTAS token that corresponds to an RTAS property name:
+: rtas-get-token ( str len -- token|0 )
+    rtas-start-addr 10 + @ rtas-start-addr +     \ Get pointer to jump table
+    rtas-start-addr 18 + @ rtas-start-addr + l@  \ Get the number of entries
+    0  DO
+	dup rtasfunctab>name @          \ Get pointer to function name
+	dup 0<>                         \ function name must not be NULL
+	over zcount 5 pick = nip and    \ Check if both strings have same length
+	IF
+	    3 pick 3 pick               \ Make a copy of the token name string
+	    comp 0=
+	    IF
+		drop 2drop
+		i 1+                    \ If the name matched, return the token
+		UNLOOP EXIT
+	    THEN
+	ELSE
+	    drop
+	THEN
+	rtasfunctab-size +              \ Proceed to the next entry
+    LOOP
+    drop
+    ." RTAS token not found: " type cr
+    0
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-reboot.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-reboot.fs
new file mode 100644
index 0000000..a9539ec
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-reboot.fs
@@ -0,0 +1,33 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: rtas-power-off   ( x y -- status )
+   [ s" power-off" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   2 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   rtas-cb rtas>args1 l!
+   enter-rtas
+   rtas-cb rtas>args2 l@
+;
+
+: power-off  ( -- )  0 0 rtas-power-off ;
+
+
+: rtas-system-reboot  ( -- status )
+   [ s" system-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   0 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args1 l@
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-vpd.fs b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-vpd.fs
new file mode 100644
index 0000000..7fb4b54
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/rtas/rtas-vpd.fs
@@ -0,0 +1,33 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: rtas-read-vpd  ( offset length data -- status )
+   [ s" msg-read-vpd" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   3 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args2 l!
+   rtas-cb rtas>args1 l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args3 l@
+;
+
+: rtas-write-vpd  ( offset length data -- status )
+   [ s" msg-write-vpd" rtas-get-token ] LITERAL rtas-cb rtas>token l!
+   3 rtas-cb rtas>nargs l!
+   1 rtas-cb rtas>nret l!
+   rtas-cb rtas>args2 l!
+   rtas-cb rtas>args1 l!
+   rtas-cb rtas>args0 l!
+   enter-rtas
+   rtas-cb rtas>args3 l@
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/scsi-loader.fs b/qemu-0.15.x/roms/SLOF/slof/fs/scsi-loader.fs
new file mode 100644
index 0000000..406c184
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/scsi-loader.fs
@@ -0,0 +1,77 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ **************************************
+\ Last change: MiR 13.11.2007 10:55:57
+\ **************************************
+
+: .ansi-attr-off 1b emit ." [0m"  ;    \ ESC Sequence: all terminal atributes off
+: .ansi-blue     1b emit ." [34m" ;    \ ESC Sequence: foreground-color = blue
+: .ansi-green    1b emit ." [32m" ;    \ ESC Sequence: foreground-color = green
+: .ansi-red      1b emit ." [31m" ;    \ ESC Sequence: foreground-color = green
+: .ansi-bold     1b emit ." [1m"  ;    \ ESC Sequence: foreground-color bold
+
+false VALUE scsi-supp-present?
+
+: scsi-xt-err ." SCSI-ERROR (Intern) " ;
+' scsi-xt-err VALUE scsi-open-xt        \ preset with an invalid token
+
+\ *************************************
+\ utility to show all active word-lists
+\ *************************************
+: .wordlists      ( -- )
+   .ansi-red
+   get-order      ( -- wid1 .. widn n )
+   dup space 28 emit .d ." word lists : "
+   0 DO
+      . 08 emit 2c emit
+   LOOP
+   08 emit                 \ 'bs'
+   29 emit                 \ ')'
+   cr space 28 emit
+   ." Context: " context dup .
+   @ 5b emit . 8 emit 5d emit
+   space
+   ." / Current: " current .
+   .ansi-attr-off
+   cr
+;
+
+\ *************************************
+\ utility to show first word-lists
+\ *************************************
+: .context  ( num -- )
+   .ansi-red
+    space
+   5b emit
+   23 emit . 3a emit
+   context @
+   . 8 emit 5d emit space
+   .ansi-attr-off
+;
+
+\ ****************************************************************************
+\ open scsi-support by adding a new word list on top of search path
+\ first check if scsi-support.fs must be included (first call)
+\ when open use execution pointer to access version in new word list
+\ ****************************************************************************
+: scsi-open  ( -- )
+   scsi-supp-present? NOT
+   IF
+      s" scsi-support.fs" included  ( xt-open )
+      to scsi-open-xt               (  )
+      true to scsi-supp-present?
+   THEN
+   scsi-open-xt execute
+;
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/scsi-support.fs b/qemu-0.15.x/roms/SLOF/slof/fs/scsi-support.fs
new file mode 100644
index 0000000..4c6e1d1
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/scsi-support.fs
@@ -0,0 +1,809 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ ************************************************
+\ create a new scsi word-list named 'scsi-words'
+\ ************************************************
+vocabulary scsi-words                  \ create new word list named 'scsi-words'
+also scsi-words  definitions           \ place next definitions into new list
+
+\ for some commands specific parameters are used, which normally
+\ need not to be altered. These values are preset at include time
+\ or explicit by a call of 'scsi-supp-init'
+false  value   scsi-param-debug        \ common debugging flag
+d# 0   value   scsi-param-size         \ length of CDB processed last
+h# 0   value   scsi-param-control      \ control word for CDBs as defined in SAM-4
+d# 0   value   scsi-param-errors       \ counter for detected errors
+
+\ utility to increment error counter
+: scsi-inc-errors
+   scsi-param-errors 1 + to scsi-param-errors
+;
+
+\ ***************************************************************************
+\ SCSI-Command: TEST UNIT READY
+\         Type: Primary Command (SPC-3 clause 6.33)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-test-unit-ready    ( cdb -- )
+\ ***************************************************************************
+\ checks if a device is ready to receive commands
+\ ***************************************************************************
+\ command code:
+00 CONSTANT scsi-cmd-test-unit-ready
+\ CDB structure:
+STRUCT
+	/c	FIELD test-unit-ready>operation-code     \ 00h
+	4	FIELD test-unit-ready>reserved           \ unused
+	/c	FIELD test-unit-ready>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-test-unit-ready
+
+\ cdb build:
+\ all fields are zeroed
+: scsi-build-test-unit-ready  ( cdb -- )
+   dup scsi-length-test-unit-ready erase  ( cdb )
+   scsi-param-control swap test-unit-ready>control c!  ( )
+   scsi-length-test-unit-ready to scsi-param-size   \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: REQUEST SENSE
+\         Type: Primary Command (SPC-3 clause 6.27)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-request-sense    ( cdb -- )
+\ ***************************************************************************
+\ for return data a buffer of at least 252 bytes must be present!
+\ see spec: SPC-3 (r23) / clauses 4.5 and 6.27
+\ ***************************************************************************
+\ command code:
+03 CONSTANT scsi-cmd-request-sense
+\ CDB structure:
+STRUCT
+	/c	FIELD request-sense>operation-code     \ 03h
+	3	FIELD request-sense>reserved           \ unused
+	/c	FIELD request-sense>allocation-length  \ buffer-length for data response
+	/c	FIELD request-sense>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-request-sense
+
+\ cdb build:
+: scsi-build-request-sense    ( alloc-len cdb -- )
+   >r                         ( alloc-len )  ( R: -- cdb )
+   r@ scsi-length-request-sense erase  ( alloc-len )
+   scsi-cmd-request-sense r@           ( alloc-len cmd cdb )
+   request-sense>operation-code c!     ( alloc-len )
+   dup d# 252 >                        \ buffer length too big ?
+   IF
+      scsi-inc-errors
+      drop d# 252                      \ replace with 252
+   ELSE
+      dup d# 18 <                      \ allocated buffer too small ?
+      IF
+         scsi-inc-errors
+         drop 0                        \ reject return data
+      THEN
+   THEN                                      ( alloclen )
+   r@ request-sense>allocation-length c!     (  )
+   scsi-param-control r> request-sense>control c!  ( alloc-len cdb )  ( R: cdb -- )
+   scsi-length-request-sense to scsi-param-size  \ update CDB length
+;
+
+\ ----------------------------------------
+\ SCSI-Response: SENSE_DATA
+\ ----------------------------------------
+70 CONSTANT scsi-response(request-sense-0)
+71 CONSTANT scsi-response(request-sense-1)
+
+STRUCT
+   /c FIELD sense-data>response-code   \ 70h (current errors) or 71h (deferred errors)
+   /c FIELD sense-data>obsolete
+   /c FIELD sense-data>sense-key       \ D3..D0 = sense key, D7 = EndOfMedium
+   /l FIELD sense-data>info
+   /c FIELD sense-data>alloc-length    \ <= 244 (for max size)
+   /l FIELD sense-data>command-info
+   /c FIELD sense-data>asc             \ additional sense key
+   /c FIELD sense-data>ascq            \ additional sense key qualifier
+   /c FIELD sense-data>unit-code
+   3  FIELD sense-data>key-specific
+   /c FIELD sense-data>add-sense-bytes \ start of appended extra bytes
+CONSTANT scsi-length-sense-data
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Additional Sense Code Qualifier
+\  - Additional Sense Code
+\  - sense-key
+\ ----------------------------------------
+\ Forth Word:   scsi-get-sense-data  ( addr -- ascq asc sense-key )
+\ ----------------------------------------
+: scsi-get-sense-data                  ( addr -- ascq asc sense-key )   
+   >r                                  ( R: -- addr )
+   r@ sense-data>response-code c@ 7f and 72 >= IF
+     r@ 3 + c@                           ( ascq )
+     r@ 2 + c@                           ( ascq asc ) 
+     r> 1 + c@ 0f and                    ( ascq asc sense-key )
+   ELSE
+     r@ sense-data>ASCQ c@               ( ascq )
+     r@ sense-data>ASC c@                ( ascq asc )
+     r> sense-data>sense-key c@ 0f and   ( ascq asc sense-key ) ( R: addr -- )
+   THEN
+;
+
+\ --------------------------------------------------------------------------
+\ Forth Word:   scsi-get-sense-data?  ( addr -- false | ascq asc sense-key true )
+\ --------------------------------------------------------------------------
+: scsi-get-sense-data?                 ( addr -- false | ascq asc sense-key true )
+   dup
+   sense-data>response-code c@
+   7e AND 70 =          \ Response code (some devices have MSB set)
+   IF
+      scsi-get-sense-data TRUE
+   ELSE
+      drop FALSE        \ drop addr
+   THEN
+
+;
+
+\ --------------------------------------------------------------------------
+\ Forth Word:   scsi-get-sense-ID?  ( addr -- false | sense-ID true )
+\ same as scsi-get-sense-data? but returns
+\ a single word composed of: sense-key<<16 | asc<<8 | ascq
+\ --------------------------------------------------------------------------
+: scsi-get-sense-ID?                 ( addr -- false | ascq asc sense-key true )
+   dup
+   sense-data>response-code c@
+   7e AND 70 =          \ Response code (some devices have MSB set)
+   IF
+      scsi-get-sense-data        ( ascq asc sense-key )
+      10 lshift                  ( ascq asc sense-key16 )
+      swap 8 lshift or           ( ascq sense-key+asc )
+      swap or                    \ 24-bit sense-ID ( sense-key+asc+ascq )
+      TRUE
+   ELSE
+      drop FALSE        \ drop addr
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Command: INQUIRY
+\         Type: Primary Command (SPC-3 clause 6.4)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-inquiry    ( alloc-len cdb -- )
+\ ***************************************************************************
+\ command code:
+12 CONSTANT scsi-cmd-inquiry
+
+\ CDB structure
+STRUCT
+	/c	FIELD inquiry>operation-code     \ 0x12
+	/c	FIELD inquiry>reserved           \ + EVPD-Bit (vital product data)
+	/c	FIELD inquiry>page-code          \ page code for vital product data (if used)
+	/w	FIELD inquiry>allocation-length  \ length of Data-In-Buffer
+	/c	FIELD inquiry>control            \ control byte as specified in SAM-4
+CONSTANT scsi-length-inquiry
+
+\ Setup command INQUIRY
+: scsi-build-inquiry                   ( alloc-len cdb -- )
+   dup scsi-length-inquiry erase       \ 6 bytes CDB
+	scsi-cmd-inquiry over				   ( alloc-len cdb cmd cdb )
+	inquiry>operation-code c!	         ( alloc-len cdb )
+   scsi-param-control over inquiry>control c! ( alloc-len cdb )
+	inquiry>allocation-length w!	      \ size of Data-In Buffer
+   scsi-length-inquiry to scsi-param-size    \ update CDB length
+;
+
+\ ----------------------------------------
+\ block structure of inquiry return data:
+\ ----------------------------------------
+STRUCT
+	/c	   FIELD inquiry-data>peripheral       \ qualifier and device type
+	/c	   FIELD inquiry-data>reserved1
+	/c	   FIELD inquiry-data>version          \ supported SCSI version (1,2,3)
+	/c	   FIELD inquiry-data>data-format
+	/c	   FIELD inquiry-data>add-length       \ total block length - 4
+	/c	   FIELD inquiry-data>flags1
+	/c	   FIELD inquiry-data>flags2
+	/c	   FIELD inquiry-data>flags3
+	d# 8	FIELD inquiry-data>vendor-ident     \ vendor string
+	d# 16	FIELD inquiry-data>product-ident    \ device string
+	/l 	FIELD inquiry-data>product-revision \ revision string
+	d# 20	FIELD inquiry-data>vendor-specific  \ optional params
+\ can be increased by vendor specific fields
+CONSTANT scsi-length-inquiry-data
+
+\ ***************************************************************************
+\ SCSI-Command: READ CAPACITY (10)
+\         Type: Block Command (SBC-3 clause 5.12)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-capacity-10    ( cdb -- )
+\ ***************************************************************************
+25 CONSTANT scsi-cmd-read-capacity-10  \ command code
+
+STRUCT                                 \ SCSI 10-byte CDB structure
+	/c	FIELD read-cap-10>operation-code
+	/c	FIELD read-cap-10>reserved1
+	/l	FIELD read-cap-10>lba
+	/w	FIELD read-cap-10>reserved2
+	/c	FIELD read-cap-10>reserved3
+	/c	FIELD read-cap-10>control
+CONSTANT scsi-length-read-cap-10
+
+\ Setup READ CAPACITY (10) command
+: scsi-build-read-cap-10                     ( cdb -- )
+   dup scsi-length-read-cap-10 erase         ( cdb )
+	scsi-cmd-read-capacity-10 over            ( cdb cmd cdb )
+	read-cap-10>operation-code c!             ( cdb )
+   scsi-param-control swap read-cap-10>control c! ( )
+   scsi-length-read-cap-10 to scsi-param-size    \ update CDB length
+;
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Additional Sense Code Qualifier
+\  - Additional Sense Code
+\  - sense-key
+\ ----------------------------------------
+\ Forth Word:   scsi-get-capacity-10  ( addr -- block-size #blocks )
+\ ----------------------------------------
+\ Block structure
+STRUCT
+	/l	FIELD read-cap-10-data>max-lba
+	/l	FIELD read-cap-10-data>block-size
+CONSTANT scsi-length-read-cap-10-data
+
+\ get data-block
+: scsi-get-capacity-10                 ( addr -- block-size #blocks )
+   >r                                  ( addr -- ) ( R: -- addr )
+   r@ read-cap-10-data>block-size l@   ( block-size )
+   r> read-cap-10-data>max-lba l@      ( block-size #blocks ) ( R: addr -- )
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ CAPACITY (16)
+\         Type: Block Command (SBC-3 clause 5.13)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-capacity-16    ( cdb -- )
+\ ***************************************************************************
+9e CONSTANT scsi-cmd-read-capacity-16        \ command code
+
+STRUCT                                       \ SCSI 16-byte CDB structure
+	/c	FIELD read-cap-16>operation-code
+	/c	FIELD read-cap-16>service-action
+	/l	FIELD read-cap-16>lba-high
+	/l	FIELD read-cap-16>lba-low
+	/l	FIELD read-cap-16>allocation-length    \ should be 32
+	/c	FIELD read-cap-16>reserved
+	/c	FIELD read-cap-16>control
+CONSTANT scsi-length-read-cap-16
+
+\ Setup READ CAPACITY (16) command
+: scsi-build-read-cap-16  ( cdb -- )
+   >r r@                                     ( R: -- cdb )
+   scsi-length-read-cap-16 erase             (  )
+	scsi-cmd-read-capacity-16                 ( code )
+	r@ read-cap-16>operation-code c!          (  )
+   10 r@ read-cap-16>service-action c!
+   d# 32                                     \ response size 32 bytes
+   r@ read-cap-16>allocation-length l!       (  )
+   scsi-param-control r> read-cap-16>control c! ( R: cdb -- )
+   scsi-length-read-cap-16 to scsi-param-size \ update CDB length
+;
+
+\ ----------------------------------------
+\ get from SCSI response block:
+\  - Block Size (in Bytes)
+\  - Number of Blocks
+\ ----------------------------------------
+\ Forth Word:   scsi-get-capacity-16  ( addr -- block-size #blocks )
+\ ----------------------------------------
+\ Block structure for return data
+STRUCT
+	/l	FIELD read-cap-16-data>max-lba-high    \ upper quadlet of Max-LBA
+	/l	FIELD read-cap-16-data>max-lba-low     \ lower quadlet of Max-LBA
+	/l	FIELD read-cap-16-data>block-size      \ logical block length in bytes
+   /c	FIELD read-cap-16-data>protect         \ type of protection (4 bits)
+   /c	FIELD read-cap-16-data>exponent        \ logical blocks per physical blocks
+   /w	FIELD read-cap-16-data>lowest-aligned  \ first LBA of a phsy. block
+   10 FIELD read-cap-16-data>reserved        \ 16 reserved bytes
+CONSTANT scsi-length-read-cap-16-data        \ results in 32
+
+\ get data-block
+: scsi-get-capacity-16                       ( addr -- block-size #blocks )
+   >r                                        ( R: -- addr )
+   r@ read-cap-16-data>block-size l@         ( block-size )
+   r@ read-cap-16-data>max-lba-high l@       ( block-size #blocks-high )
+   d# 32 lshift                              ( block-size #blocks-upper )
+   r> read-cap-16-data>max-lba-low l@ +      ( block-size #blocks ) ( R: addr -- )
+;
+
+\ ***************************************************************************
+\ SCSI-Command: MODE SENSE (10)
+\         Type: Primary Command (SPC-3 clause 6.10)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-mode-sense-10  ( alloc-len subpage page cdb -- )
+\ ***************************************************************************
+5a CONSTANT scsi-cmd-mode-sense-10
+
+\ CDB structure
+STRUCT
+	/c	FIELD mode-sense-10>operation-code
+	/c	FIELD mode-sense-10>res-llbaa-dbd-res
+	/c	FIELD mode-sense-10>pc-page-code       \ page code + page control
+	/c	FIELD mode-sense-10>sub-page-code
+	3	FIELD mode-sense-10>reserved2
+	/w	FIELD mode-sense-10>allocation-length
+	/c	FIELD mode-sense-10>control
+CONSTANT scsi-length-mode-sense-10
+
+: scsi-build-mode-sense-10                   ( alloc-len subpage page cdb -- )
+   >r                                        ( alloc-len subpage page ) ( R: -- cdb )
+   r@ scsi-length-mode-sense-10 erase        \ 10 bytes CDB
+	scsi-cmd-mode-sense-10                    ( alloc-len subpage page cmd )
+   r@  mode-sense-10>operation-code c!		   ( alloc-len subpage page )
+   10 r@ mode-sense-10>res-llbaa-dbd-res c!  \ long LBAs accepted
+	r@ mode-sense-10>pc-page-code c!	         ( alloc-len subpage )
+	r@ mode-sense-10>sub-page-code c!	      ( alloc-len )
+	r@ mode-sense-10>allocation-length w!     ( )
+
+   scsi-param-control r> mode-sense-10>control c!  ( R: cdb -- )
+   scsi-length-mode-sense-10 to scsi-param-size  \ update CDB length
+;
+
+\ return data processing
+\ (see spec: SPC-3 clause 7.4.3)
+
+STRUCT
+	/w	FIELD mode-sense-10-data>head-length
+	/c	FIELD mode-sense-10-data>head-medium
+	/c	FIELD mode-sense-10-data>head-param
+	/c	FIELD mode-sense-10-data>head-longlba
+	/c	FIELD mode-sense-10-data>head-reserved
+	/w	FIELD mode-sense-10-data>head-descr-len
+CONSTANT scsi-length-mode-sense-10-data
+
+\ ****************************************
+\ This function shows the mode page header
+\ helpful for further analysis
+\ ****************************************
+: .mode-sense-data   ( addr -- )
+   cr
+   dup mode-sense-10-data>head-length
+   w@ ." Mode Length: " .d space
+   dup mode-sense-10-data>head-medium
+   c@ ." / Medium Type: " .d space
+   dup mode-sense-10-data>head-longlba
+   c@ ." / Long LBA: " .d space
+   mode-sense-10-data>head-descr-len
+   w@ ." / Descr. Length: " .d
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (6)
+\         Type: Block Command (SBC-3 clause 5.7)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-6  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ this SCSI command uses 21 bits to represent start LBA
+\ and 8 bits to specify the numbers of blocks to read
+\ The value of 0 blocks is interpreted as 256 blocks
+\
+\ command code
+08 CONSTANT scsi-cmd-read-6
+
+\ CDB structure
+STRUCT
+   /c FIELD read-6>operation-code      \ 08h
+   /c FIELD read-6>block-address-msb   \ upper 5 bits
+   /w FIELD read-6>block-address       \ lower 16 bits
+   /c FIELD read-6>length              \ number of blocks to read
+   /c FIELD read-6>control             \ CDB control
+CONSTANT scsi-length-read-6
+
+: scsi-build-read-6                    ( block# #blocks cdb -- )
+   >r                                  ( block# #blocks ) ( R: -- cdb )
+   r@ scsi-length-read-6 erase         \ 6 bytes CDB
+	scsi-cmd-read-6 r@ read-6>operation-code c! ( block# #blocks )
+
+   \ check block count to read (#blocks)
+   dup d# 255 >                        \ #blocks exceeded limit ?
+   IF
+      scsi-inc-errors
+      drop 1                           \ replace with any valid number
+   THEN
+   r@ read-6>length c!                 \ set #blocks to read
+
+   \ check starting block number (block#)
+   dup 1fffff >                        \ check address upper limit
+   IF
+      scsi-inc-errors
+      drop                             \ remove original block#
+      1fffff                           \ replace with any valid address
+   THEN
+   dup d# 16 rshift
+   r@ read-6>block-address-msb c!      \ set upper 5 bits
+   ffff and
+   r@ read-6>block-address w!                \ set lower 16 bits
+   scsi-param-control r> read-6>control c!   ( R: cdb -- )
+   scsi-length-read-6 to scsi-param-size     \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (10)
+\         Type: Block Command (SBC-3 clause 5.8)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-10  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ command code
+28 CONSTANT scsi-cmd-read-10
+
+\ CDB structure
+STRUCT
+   /c FIELD read-10>operation-code
+   /c FIELD read-10>protect
+   /l FIELD read-10>block-address      \ logical block address (32bits)
+   /c FIELD read-10>group
+   /w FIELD read-10>length             \ transfer length (16-bits)
+   /c FIELD read-10>control
+CONSTANT scsi-length-read-10
+
+: scsi-build-read-10                         ( block# #blocks cdb -- )
+   >r                                        ( block# #blocks )  ( R: -- cdb )
+   r@ scsi-length-read-10 erase             \ 10 bytes CDB
+	scsi-cmd-read-10 r@ read-10>operation-code c! ( block# #blocks )
+   r@ read-10>length w!                      ( block# )
+   r@ read-10>block-address l!               (  )
+   scsi-param-control r> read-10>control c!  ( R: cdb -- )
+   scsi-length-read-10 to scsi-param-size    \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ (12)
+\         Type: Block Command (SBC-3 clause 5.9)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read-12  ( block# #blocks cdb -- )
+\ ***************************************************************************
+\ command code
+a8 CONSTANT scsi-cmd-read-12
+
+\ CDB structure
+STRUCT
+   /c FIELD read-12>operation-code     \ code: a8
+   /c FIELD read-12>protect            \ RDPROTECT, DPO, FUA, FUA_NV
+   /l FIELD read-12>block-address      \ lba
+   /l FIELD read-12>length             \ transfer length (32bits)
+   /c FIELD read-12>group              \ group number
+   /c FIELD read-12>control
+CONSTANT scsi-length-read-12
+
+: scsi-build-read-12                         ( block# #blocks cdb -- )
+   >r                                        ( block# #blocks )  ( R: -- cdb )
+   r@ scsi-length-read-12 erase             \ 12 bytes CDB
+	scsi-cmd-read-12 r@ read-12>operation-code c! ( block# #blocks )
+   r@ read-12>length l!                      ( block# )
+   r@ read-12>block-address l!               (  )
+   scsi-param-control r> read-12>control c!  ( R: cdb -- )
+   scsi-length-read-12 to scsi-param-size    \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: READ with autodetection of required command
+\               read(10) or read(12) depending on parameter size
+\               (read(6) removed because obsolete in some cases (USB))
+\         Type: Block Command
+\ ***************************************************************************
+\ Forth Word:   scsi-build-read?    ( block# #blocks cdb -- )
+\
+\                         +----------------+---------------------------|
+\                         |  block# (lba)  |  #block (transfer-length) |
+\             +-----------+----------------+---------------------------|
+\             | read-6    |  16-Bits       |  8  Bits                  |
+\             | read-10   |  32-Bits       |  16 Bits                  |
+\             | read-12   |  32-Bits       |  32 Bits                  |
+\ ***************************************************************************
+: scsi-build-read?   ( block# #blocks cdb -- length )
+   over              ( block# #blocks cdb #blocks )
+   fffe >            \ tx-length (#blocks) exceeds 16-bit limit ?
+   IF
+      scsi-build-read-12   ( block# #blocks cdb -- )
+      scsi-length-read-12  ( length )
+   ELSE                    ( block# #blocks cdb )
+      scsi-build-read-10   ( block# #blocks cdb -- )
+      scsi-length-read-10  ( length )
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Command: START STOP UNIT
+\         Type: Block Command (SBC-3 clause 5.19)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-start-stop-unit  ( state# cdb -- )
+\ ***************************************************************************
+\ command code
+1b CONSTANT scsi-cmd-start-stop-unit
+
+\ CDB structure
+STRUCT
+   /c FIELD start-stop-unit>operation-code
+   /c FIELD start-stop-unit>immed
+   /w FIELD start-stop-unit>reserved
+   /c FIELD start-stop-unit>pow-condition
+   /c FIELD start-stop-unit>control
+CONSTANT scsi-length-start-stop-unit
+
+\ START/STOP constants
+\ (see spec: SBC-3 clause 5.19)
+f1 CONSTANT scsi-const-active-power    \ param used for start-stop-unit
+f2 CONSTANT scsi-const-idle-power      \ param used for start-stop-unit
+f3 CONSTANT scsi-const-standby-power   \ param used for start-stop-unit
+3  CONSTANT scsi-const-load            \ param used for start-stop-unit
+2  CONSTANT scsi-const-eject           \ param used for start-stop-unit
+1  CONSTANT scsi-const-start
+0  CONSTANT scsi-const-stop
+
+: scsi-build-start-stop-unit                 ( state# cdb -- )
+   >r                                        ( state# )  ( R: -- cdb )
+   r@ scsi-length-start-stop-unit erase      \ 6 bytes CDB
+	scsi-cmd-start-stop-unit r@ start-stop-unit>operation-code c!
+   dup 3 >
+   IF
+      4 lshift                         \ shift to upper nibble
+   THEN                                ( state )
+   r@ start-stop-unit>pow-condition c!       (  )
+   scsi-param-control r> start-stop-unit>control c!  ( R: cdb -- )
+   scsi-length-start-stop-unit to scsi-param-size  \ update CDB length
+;
+
+\ ***************************************************************************
+\ SCSI-Command: SEEK(10)
+\         Type: Block Command (obsolete)
+\ ***************************************************************************
+\ Forth Word:   scsi-build-seek  ( state# cdb -- )
+\ Obsolete function (last listed in spec SBC / Nov. 1997)
+\ implemented only for the sake of completeness
+\ ***************************************************************************
+\ command code
+2b CONSTANT scsi-cmd-seek
+
+\ CDB structure
+STRUCT
+   /c FIELD seek>operation-code
+   /c FIELD seek>reserved1
+   /l FIELD seek>lba
+   3  FIELD seek>reserved2
+   /c FIELD seek>control
+CONSTANT scsi-length-seek
+
+: scsi-build-seek  ( lba cdb -- )
+   >r              ( lba )  ( R: -- cdb )
+   r@ scsi-length-seek erase           \ 10 bytes CDB
+	scsi-cmd-seek r@ seek>operation-code c!
+   r> seek>lba l!  (  )  ( R: cdb -- )
+   scsi-length-seek to scsi-param-size \ update CDB length
+;
+
+\ ****************************************************************************
+\ CDROM media event stuff
+\ ****************************************************************************
+
+STRUCT
+    /w FIELD media-event-data-len
+    /c FIELD media-event-nea-class
+    /c FIELD media-event-supp-class
+    /l FIELD media-event-data
+CONSTANT scsi-length-media-event
+
+: scsi-build-get-media-event                     ( cdb -- )
+   dup c erase				         ( cdb )
+   4a over c!				         ( cdb )
+   01 over 1 + c!
+   10 over 4 + c!
+   08 over 8 + c!
+   drop
+;
+
+
+
+\ ***************************************************************************
+\ SCSI-Utility: .sense-code
+\ ***************************************************************************
+\ this utility prints a string associated to the sense code
+\ see specs: SPC-3/r23 clause 4.5.6
+\ ***************************************************************************
+: .sense-text ( scode -- )
+   case
+      0    OF s" OK"               ENDOF
+      1    OF s" RECOVERED ERR"    ENDOF
+      2    OF s" NOT READY"        ENDOF
+      3    OF s" MEDIUM ERROR"     ENDOF
+      4    OF s" HARDWARE ERR"     ENDOF
+      5    OF s" ILLEGAL REQUEST"  ENDOF
+      6    OF s" UNIT ATTENTION"   ENDOF
+      7    OF s" DATA PROTECT"     ENDOF
+      8    OF s" BLANK CHECK"      ENDOF
+      9    OF s" VENDOR SPECIFIC"  ENDOF
+      a    OF s" COPY ABORTED"     ENDOF
+      b    OF s" ABORTED COMMAND"  ENDOF
+      d    OF s" VOLUME OVERFLOW"  ENDOF
+      e    OF s" MISCOMPARE"       ENDOF
+      dup  OF s" UNKNOWN"          ENDOF
+   endcase
+   5b emit type 5d emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .status-code
+\ ***************************************************************************
+\ this utility prints a string associated to the status code
+\ see specs: SAM-3/r14 clause 5.3
+\ ***************************************************************************
+: .status-text  ( stat -- )
+   case
+      00  OF s" GOOD"                  ENDOF
+      02  OF s" CHECK CONDITION"       ENDOF
+      04  OF s" CONDITION MET"         ENDOF
+      08  OF s" BUSY"                  ENDOF
+      18  OF s" RESERVATION CONFLICT"  ENDOF
+      28  OF s" TASK SET FULL"         ENDOF
+      30  OF s" ACA ACTIVE"            ENDOF
+      40  OF s" TASK ABORTED"          ENDOF
+      dup OF s" UNKNOWN"               ENDOF
+   endcase
+   5b emit type 5d emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .capacity-text
+\ ***************************************************************************
+\ utility that shows total capacity on screen by use of the return data
+\ from read-capacity calculation is SI conform (base 10)
+\ ***************************************************************************
+\ sub function to print a 3 digit decimal
+\ number with 2 post decimal positions xxx.yy
+: .dec3-2 ( prenum postnum -- )
+   swap
+   base @ >r                           \ save actual base setting
+   decimal                             \ show decimal values
+   4 .r 2e emit
+   dup 9 <= IF 30 emit THEN .d         \ 3 pre-decimal, right aligned
+   r> base !                           \ restore base
+;
+
+: .capacity-text  ( block-size #blocks -- )
+   scsi-param-debug                    \ debugging flag set ?
+   IF                                  \ show additional info
+      2dup
+      cr
+      ." LBAs: " .d                    \ highest logical block number
+      ." / Block-Size: " .d
+      ." / Total Capacity: "
+   THEN
+   *                                   \ calculate total capacity
+   dup d# 1000000000000 >=             \ check terabyte limit
+   IF
+      d# 1000000000000 /mod
+      swap
+      d# 10000000000 /                 \ limit remainder to two digits
+      .dec3-2 ." TB"                   \ show terabytes as xxx.yy
+   ELSE
+      dup d# 1000000000 >=             \ check gigabyte limit
+      IF
+         d# 1000000000 /mod
+         swap
+         d# 10000000 /
+         .dec3-2 ." GB"                \ show gigabytes as xxx.yy
+      ELSE
+         dup d# 1000000 >=
+         IF
+            d# 1000000 /mod            \ check mega byte limit
+            swap
+            d# 10000 /
+            .dec3-2 ." MB"             \ show megabytes as xxx.yy
+         ELSE
+            dup d# 1000 >=             \ check kilo byte limit
+            IF
+               d# 1000 /mod
+               swap
+               d# 10 /
+               .dec3-2 ." kB"
+            ELSE
+               .d ."  Bytes"
+            THEN
+         THEN
+      THEN
+   THEN
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: .inquiry-text  ( addr -- )
+\ ***************************************************************************
+\ utility that shows:
+\     vendor-ident product-ident and revision
+\ from an inquiry return data block (addr)
+\ ***************************************************************************
+: .inquiry-text  ( addr -- )
+   22 emit     \ enclose text with "
+   dup inquiry-data>vendor-ident      8 type space
+   dup inquiry-data>product-ident    10 type space
+       inquiry-data>product-revision  4 type
+   22 emit
+;
+
+\ ***************************************************************************
+\ SCSI-Utility: scsi-supp-init  ( -- )
+\ ***************************************************************************
+\ utility that helps to ensure that parameters are set to valid values
+: scsi-supp-init  ( -- )
+   false   to scsi-param-debug         \ no debug strings
+   h# 0   to scsi-param-size
+   h# 0   to scsi-param-control        \ common CDB control byte
+   d# 0   to scsi-param-errors         \ local errors (param limits)
+;
+
+
+\ ***************************************************************************
+\ scsi loader
+\ ***************************************************************************
+0 VALUE scsi-context                   \ addr of word list on top
+
+
+\ ****************************************************************************
+\ open scsi-support by adding a new word list on top of search path
+\   precondition: scsi-support.fs must have been included
+\ ****************************************************************************
+: scsi-init  ( -- )
+   also scsi-words                     \ append scsi word-list
+   context  to scsi-context            \ save for close process
+   scsi-supp-init                      \ preset all scsi-param-xxx values
+   scsi-param-debug
+   IF
+      space ." SCSI-SUPPORT OPENED" cr
+      .wordlists
+   THEN
+;
+
+\ ****************************************************************************
+\ close scsi-session and remove scsi word list (if exists)
+\ ****************************************************************************
+\ if 'previous' is used without a preceeding 'also' all forth words are lost !
+\ ****************************************************************************
+: scsi-close  ( -- )
+\ FIXME This only works if scsi-words is the last vocabulary on the stack
+\       Instead we could use get-order to find us on the "wordlist stack",
+\       remove us and write the wordlist stack back with set-order.
+\       BUT: Is this worth the effort?
+
+   scsi-param-debug
+   IF
+      space ." Closing SCSI-SUPPORT .. " cr
+   THEN
+   context scsi-context =              \ scsi word list still active ?
+   IF
+      scsi-param-errors 0<>          \ any errors occured ?
+      IF
+         cr ." ** WARNING: " scsi-param-errors .d
+         ." SCSI Errors occured ** " cr
+      THEN
+      previous                         \ remove scsi word list on top
+      0 to scsi-context                \ prevent from being misinterpreted
+   ELSE
+      cr ." ** WARNING: Trying to close non-open SCSI-SUPPORT (1) ** " cr
+   THEN
+   scsi-param-debug
+   IF
+     .wordlists
+   THEN
+;
+
+
+s" scsi-init" $find drop               \ return execution pointer, when included
+
+previous                               \ remove scsi word list from search path
+definitions                            \ place next definitions into previous list
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/search.fs b/qemu-0.15.x/roms/SLOF/slof/fs/search.fs
new file mode 100644
index 0000000..3acca2f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/search.fs
@@ -0,0 +1,89 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+\
+\ Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+\
+
+
+\ stuff we should already have:
+
+: linked ( var -- )  here over @ , swap ! ;
+
+HEX
+
+\ \ \
+\ \ \	Wordlists
+\ \ \
+
+VARIABLE wordlists  forth-wordlist wordlists !
+
+\ create a new wordlist
+: wordlist ( -- wid )  here wordlists linked 0 , ;
+
+
+\ \ \
+\ \ \	Search order
+\ \ \
+
+10 CONSTANT max-in-search-order	\ should define elsewhere
+\ CREATE search-order max-in-search-order cells allot	\ stack of wids	\ is in engine now
+\ search-order VALUE context	\ top of stack	\ is in engine now
+
+: also ( -- )  clean-hash  context dup cell+ dup to context  >r @ r> ! ;
+: previous ( -- )  clean-hash  context cell- to context ;
+: only ( -- )  clean-hash  search-order to context  ( minimal-wordlist search-order ! ) ;
+: seal ( -- )  clean-hash  context @  search-order dup to context  ! ;
+
+: get-order ( -- wid_n .. wid_1 n )
+	context >r search-order BEGIN dup r@ u<= WHILE
+	dup @ swap cell+ REPEAT r> drop
+	search-order - cell / ;
+: set-order ( wid_n .. wid_1 n -- )	\ XXX: special cases for 0, -1
+	clean-hash  1- cells search-order + dup to context
+	BEGIN dup search-order u>= WHILE
+	dup >r ! r> cell- REPEAT drop ;
+
+
+\ \ \
+\ \ \	Compilation wordlist
+\ \ \
+
+: get-current ( -- wid )  current ;
+: set-current ( wid -- )  to current ;
+
+: definitions ( -- )  context @ set-current ;
+
+
+\ \ \
+\ \ \	Vocabularies
+\ \ \
+
+: VOCABULARY ( C: "name" -- ) ( -- )  CREATE wordlist drop  DOES> clean-hash  context ! ;
+\ : VOCABULARY ( C: "name" -- ) ( -- )  wordlist CREATE ,  DOES> @ context ! ;
+\ XXX we'd like to swap forth and forth-wordlist around (for .voc 's sake)
+: FORTH ( -- )  clean-hash  forth-wordlist context ! ;
+
+: .voc ( wid -- ) \ display name for wid \ needs work ( body> or something like that )
+	dup cell- @ ['] vocabulary ['] forth within IF
+	2 cells - >name name>string type ELSE u. THEN  space ;
+: vocs ( -- ) \ display all wordlist names
+	cr wordlists BEGIN @ dup WHILE dup .voc REPEAT drop ;
+: order ( -- )
+	cr ." context:  " get-order 0 ?DO .voc LOOP
+	cr ." current:  " get-current .voc ;
+
+
+
+
+\ some handy helper
+: voc-find ( wid -- 0 | link )
+   clean-hash  cell+ @ (find)  clean-hash ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/slof-logo.fs b/qemu-0.15.x/roms/SLOF/slof/fs/slof-logo.fs
new file mode 100644
index 0000000..53d3184
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/slof-logo.fs
@@ -0,0 +1,20 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: .slof-logo
+   cr ."         ..`. ..     .......  ..           ......      ......."
+   cr ."     ..`...`''.`'. .''``````..''.       .`''```''`.  `''``````"
+   cr ."        .`` .:' ': `''.....  .''.       ''`     .''..''......."
+   cr ."          ``.':.';. ``````''`.''.      .''.      ''``''`````'`"
+   cr ."          ``.':':`   .....`''.`'`...... `'`.....`''.`'`       "
+   cr ."         .`.`'``   .'`'`````.  ``''''''  ``''`'''`. `'`       "
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-load.fs b/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-load.fs
new file mode 100644
index 0000000..8e4db80
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-load.fs
@@ -0,0 +1,70 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+false VALUE (sms-loaded?)
+
+false value (sms-available?)
+
+s" sms.fs" romfs-lookup IF true to (sms-available?) drop THEN
+
+(sms-available?) [IF]
+
+#include "packages/sms.fs"
+
+\ Initialize SMS NVRAM handling.
+#include "sms-nvram.fs"
+
+\ Dynamically load sms code from the romfs file
+\ Assumption is that skeleton sms package already exists
+\ but aside of open & close, all other methods are in a romfs file (sms.fs)
+\ Here we open the package and load the rest of the functionality
+
+\ After that, one needs to find-device and execute sms-start method
+\ The shorthand for that is given as (global) sms-start word
+
+: $sms-node s" /packages/sms" ;
+
+: (sms-init-package) ( -- true|false )
+   (sms-loaded?) ?dup IF EXIT THEN
+   $sms-node ['] find-device catch IF 2drop false EXIT THEN
+   s" sms.fs" [COMPILE] included
+   device-end
+   true dup to (sms-loaded?)
+;
+
+\ External wrapper for sms package method
+: (sms-evaluate) ( addr len -- )
+   (sms-init-package) not IF
+      cr ." SMS is not available." cr 2drop exit
+   THEN
+
+   s" Entering SMS ..." type
+   disable-watchdog
+   reset-dual-emit
+
+   \ if we only had execute-device-method...
+   2>r $sms-node find-device
+   2r> evaluate
+   device-end
+   vpd-boot-import
+;
+
+: sms-start ( -- ) s" sms-start" (sms-evaluate) ;
+: sms-fru-replacement ( -- ) s" sms-fru-replacement" (sms-evaluate) ;
+
+[ELSE]
+
+: sms-start ( -- ) cr ." SMS is not available." cr ;
+: sms-fru-replacement ( -- ) cr ." SMS FRU replacement is not available." cr ;
+
+[THEN]
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-nvram.fs b/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-nvram.fs
new file mode 100644
index 0000000..4f5d6dd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/sms/sms-nvram.fs
@@ -0,0 +1,124 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Initialize SMS NVRAM handling.
+
+: sms-init-nvram ( -- )
+   nvram-partition-type-sms get-nvram-partition IF
+      cr ." Could not find SMS partition in NVRAM - "
+      nvram-partition-type-sms s" SMS" d# 1024 new-nvram-partition
+      ABORT" Failed to create SMS NVRAM partition"
+      2dup erase-nvram-partition drop
+
+      2dup s" lang"			  s" 1" internal-set-env drop
+
+      2dup s" tftp-retries"		  s" 5" internal-set-env drop
+      2dup s" tftp-blocksize"		s" 512" internal-set-env drop
+      2dup s" bootp-retries"		s" 255" internal-set-env drop
+      2dup s" client"	    s" 000.000.000.000" internal-set-env drop
+      2dup s" server"       s" 000.000.000.000" internal-set-env drop
+      2dup s" gateway"      s" 000.000.000.000" internal-set-env drop
+      2dup s" netmask"      s" 255.255.255.000" internal-set-env drop
+      2dup s" net-protocol"		  s" 0" internal-set-env drop
+      2dup s" net-flags"		  s" 0" internal-set-env drop
+      2dup s" net-device"		  s" 0" internal-set-env drop
+      2dup s" net-client-name"		   s" " internal-set-env drop
+
+      2dup s" scsi-spinup"		  s" 6" internal-set-env drop
+      2dup s" scsi-id-0"		  s" 7" internal-set-env drop
+      2dup s" scsi-id-1"		  s" 7" internal-set-env drop
+      2dup s" scsi-id-2"		  s" 7" internal-set-env drop
+      2dup s" scsi-id-3"		  s" 7" internal-set-env drop
+      ." created" cr
+   THEN
+   s" sms-nvram-partition" $2constant
+;
+
+sms-init-nvram
+
+: sms-add-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-add-env drop ;
+: sms-set-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-set-env drop ;
+: sms-get-env ( "name" -- "value" TRUE | FALSE) sms-nvram-partition 2swap internal-get-env ;
+
+: sms-get-net-device ( -- n )	s" net-device" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ;
+: sms-set-net-device ( n -- )	(.d) s" net-device" 2swap sms-set-env ;
+
+: sms-get-net-flags ( -- n )	s" net-flags" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ;
+: sms-set-net-flags ( n -- )	(.d) s" net-flags" 2swap sms-set-env ;
+
+: sms-get-net-protocol ( -- n )	s" net-protocol" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ;
+: sms-set-net-protocol ( n -- )	(.d) s" net-protocol" 2swap sms-set-env ;
+
+: sms-get-lang ( -- n )	s" lang" sms-get-env IF $dnumber IF 1 THEN ELSE 1 THEN ;
+: sms-set-lang ( n -- )	(.d) s" lang" 2swap sms-set-env ;
+
+: sms-get-bootp-retries ( -- n ) s" bootp-retries" sms-get-env IF $dnumber IF 255 THEN ELSE 255 THEN ;
+: sms-set-bootp-retries ( n -- ) (.d) s" bootp-retries" 2swap sms-set-env ;
+
+: sms-get-tftp-retries ( -- n )	s" tftp-retries" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ;
+: sms-set-tftp-retries ( n -- ) (.d) s" tftp-retries" 2swap sms-set-env ;
+
+: sms-get-tftp-blocksize ( -- n ) s" tftp-blocksize" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ;
+: sms-set-tftp-blocksize ( n -- ) (.d) s" tftp-blocksize" 2swap sms-set-env ;
+
+: sms-get-client ( -- FALSE | n1 n2 n3 n4 TRUE ) s" client" sms-get-env IF (ipaddr) ELSE false THEN ;
+: sms-set-client ( n1 n2 n3 n4 -- ) (ipformat) s" client" 2swap sms-set-env ;
+
+: sms-get-server ( -- FALSE | n1 n2 n3 n4 TRUE ) s" server" sms-get-env IF (ipaddr) ELSE false THEN ;
+: sms-set-server ( n1 n2 n3 n4 -- ) (ipformat) s" server" 2swap sms-set-env ;
+
+: sms-get-gateway ( -- FALSE | n1 n2 n3 n4 TRUE ) s" gateway" sms-get-env IF (ipaddr) ELSE false THEN ;
+: sms-set-gateway ( n1 n2 n3 n4 -- ) (ipformat) s" gateway" 2swap sms-set-env ;
+
+: sms-get-subnet ( -- FALSE | n1 n2 n3 n4 TRUE ) s" netmask" sms-get-env IF (ipaddr) ELSE false THEN ;
+: sms-set-subnet ( n1 n2 n3 n4 -- ) (ipformat) s" netmask" 2swap sms-set-env ;
+
+: sms-get-client-name ( -- FALSE | addr len TRUE ) s" net-client-name" sms-get-env ;
+: sms-set-client-name ( addr len -- ) s" net-client-name" 2swap sms-set-env ;
+
+: sms-get-scsi-spinup ( -- n )	s" scsi-spinup" sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ;
+: sms-set-scsi-spinup ( n -- )	(.d) s" scsi-spinup" 2swap sms-set-env ;
+
+: sms-get-scsi-id ( n -- id )	s" scsi-id-" rot (.) $cat sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ;
+: sms-set-scsi-id ( id n -- ) swap (.d) rot s" scsi-id-" rot (.) $cat sms-set-env ;
+
+
+\ generates the boot-file part of the boot string
+
+: sms-get-net-boot-file ( -- addr len )
+   \ the format is
+   \ :[bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
+   \ we choose dhcp as a default!
+   s" net" sms-get-net-device (.) $cat
+   s" :dhcp," $cat
+   sms-get-server IF (ipformat) $cat THEN
+   s" ," $cat
+   sms-get-client-name IF $cat THEN
+   s" ," $cat
+   sms-get-client IF (ipformat) $cat THEN
+   s" ," $cat
+   sms-get-gateway IF (ipformat) $cat THEN
+   s" ," $cat
+   \ If the number of retries is 255 (max), assume default timeout (10min)
+   sms-get-bootp-retries dup ff <> IF (.) $cat ELSE drop THEN
+   s" ," $cat
+   sms-get-tftp-retries (.) $cat
+   \ now write the string to the boot path
+   dup IF
+      \ This could be considered a memory leak, but it is only
+      \ executed once for booting so it is not a problem
+      strdup ( s" :" 2swap $cat strdup )
+   THEN
+;
+
+' sms-get-net-boot-file to furnish-boot-file
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/stack.fs b/qemu-0.15.x/roms/SLOF/slof/fs/stack.fs
new file mode 100644
index 0000000..0f7e097
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/stack.fs
@@ -0,0 +1,57 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Example:
+\
+\ To get a 30 element stack, go:
+\
+\ 0 > 30 new-stack my-stack
+\ 0 > my-stack
+\ 0 > 20 push 30 push
+\ 0 > pop pop .s
+
+0 value current-stack
+
+: new-stack ( cells <>name -- )
+   create >r here    ( here R: cells )
+   dup r@ 2 + cells  ( here here bytes R: cells )
+   dup allot erase   ( here R: cells)
+   cell+ r>          ( here+1cell cells )
+   swap !            ( )
+   DOES> to current-stack
+;
+
+: reset-stack ( -- )
+   0 current-stack !
+;
+
+: stack-depth ( -- depth )
+   current-stack @
+;
+
+: push ( value -- )
+   current-stack @
+   current-stack cell+ @ over <= ABORT" Stack overflow"
+   cells
+   1 current-stack +!
+   current-stack 2 cells + + !
+;
+
+: pop ( -- value )
+   current-stack @ 0= ABORT" Stack underflow"
+   current-stack @ cells
+   current-stack + cell+ @
+   -1 current-stack +!
+;
+
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/start-up.fs b/qemu-0.15.x/roms/SLOF/slof/fs/start-up.fs
new file mode 100644
index 0000000..0ce0f3c
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/start-up.fs
@@ -0,0 +1,92 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+: (boot) ( -- )
+   s" Executing following boot-command: "
+   boot-command $cat nvramlog-write-string-cr
+   s" boot-command" evaluate      \ get boot command
+   ['] evaluate catch ?dup IF     \ and execute it
+      ." boot attempt returned: "
+      abort"-str @ count type cr
+      nip nip                     \ drop string from 1st evaluate
+      throw
+   THEN
+;
+
+\ Note: The following ESC sequences has to be handled:
+\     1B 4F 50
+\     1B 5B 31 31 7E
+
+\ Reads and converts the function key.
+\ key = F1 -- n = 1
+: (function-key) ( -- n )
+   key? IF
+      key CASE
+	 50  OF 1 ENDOF
+	 7e  OF 1 ENDOF
+	 dup OF 0 ENDOF
+      ENDCASE
+   THEN
+;
+
+\ Checks if an ESC sequence occurs.
+: (esc-sequence) ( -- n )
+   key? IF
+      key CASE
+	  4f  OF (function-key) ENDOF
+	  5b  OF
+	     key key drop (function-key) ENDOF
+	  dup OF 0 ENDOF
+       ENDCASE
+   THEN
+;
+
+: (s-pressed) ( -- )
+   s" An 's' has been pressed. Entering Open Firmware Prompt"
+   nvramlog-write-string-cr
+;
+
+: (boot?) ( -- )
+   of-prompt? not auto-boot? and IF
+      (boot)
+   THEN
+;
+
+
+#include "sms/sms-load.fs"
+
+
+\ Watchdog will be rearmed during load if use-load-watchdog variable is TRUE
+TRUE VALUE use-load-watchdog?
+
+
+: start-it ( -- )
+   key? IF
+      key CASE
+	 [char] s  OF (s-pressed) ENDOF
+	 1b        OF
+
+	    (esc-sequence) CASE
+	       1   OF console-clean-fifo sms-start (boot) ENDOF
+	       dup OF (boot?) ENDOF
+	    ENDCASE
+
+	 ENDOF
+	 dup OF (boot?) ENDOF
+      ENDCASE
+   ELSE
+      (boot?)
+   THEN
+
+   disable-watchdog  FALSE to use-load-watchdog?
+   .banner
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/term-io.fs b/qemu-0.15.x/roms/SLOF/slof/fs/term-io.fs
new file mode 100644
index 0000000..cdd754a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/term-io.fs
@@ -0,0 +1,95 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+: input  ( dev-str dev-len -- )
+   open-dev ?dup IF
+      \ Close old stdin:
+      s" stdin" get-chosen IF
+         decode-int nip nip ?dup IF close-dev THEN
+      THEN
+      \ Now set the new stdin:
+      encode-int s" stdin"  set-chosen
+   THEN
+;
+
+: output  ( dev-str dev-len -- )
+   open-dev ?dup IF
+      \ Close old stdout:
+      s" stdout" get-chosen IF
+         decode-int nip nip ?dup IF close-dev THEN
+      THEN
+      \ Now set the new stdout:
+      encode-int s" stdout" set-chosen
+   THEN
+;
+
+: io  ( dev-str dev-len -- )
+   2dup input output
+;
+
+
+1 BUFFER: (term-io-char-buf)
+
+: term-io-key  ( -- char )
+   s" stdin" get-chosen IF
+      decode-int nip nip dup 0= IF 0 EXIT THEN
+      >r BEGIN
+         (term-io-char-buf) 1 s" read" r@ $call-method
+         0 >
+      UNTIL
+      (term-io-char-buf) c@
+      r> drop
+   THEN
+;
+
+' term-io-key to key
+
+\ this word will check what the current chosen input device is:
+\ - if it is a serial device, it will use serial-key? to check for available input
+\ - if it is a keyboard, it will check if the "key-available?" method is implemented (i.e. for usb-keyboard) and use that
+\ - if it's an hv console, use hvterm-key?
+\ otherwise it will always return false
+: term-io-key?  ( -- true|false )
+   s" stdin" get-chosen IF
+      decode-int nip nip dup 0= IF drop 0 EXIT THEN \ return false and exit if no stdin set
+      >r \ store ihandle on return stack
+      s" device_type" r@ ihandle>phandle ( propstr len phandle )
+      get-property ( true | data dlen false )
+      IF
+         \ device_type not found, return false and exit
+         false
+      ELSE
+         1 - \ remove 1 from length to ignore null-termination char
+         \ device_type found, check wether it is serial or keyboard
+         2dup s" serial" str= IF
+	    2drop serial-key? r> drop EXIT
+	 THEN \ call serial-key, cleanup return-stack, exit
+         2dup s" keyboard" str= IF 
+            2drop ( )
+            \ keyboard found, check for key-available? method, execute it or return false 
+            s" key-available?" r@ ihandle>phandle find-method IF 
+               drop s" key-available?" r@ $call-method  
+            ELSE 
+               false 
+            THEN
+            r> drop EXIT \ cleanup return-stack, exit
+         THEN
+         2drop r> drop false EXIT \ unknown device_type cleanup return-stack, return false
+      THEN
+   ELSE
+      \ stdin not set, return false
+      false
+   THEN
+;
+
+' term-io-key? to key?
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/terminal.fs b/qemu-0.15.x/roms/SLOF/slof/fs/terminal.fs
new file mode 100644
index 0000000..3004265
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/terminal.fs
@@ -0,0 +1,196 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ \\\\\\\\\\\\\\ Global Data
+
+0 VALUE line#
+0 VALUE column#
+false VALUE inverse?
+false VALUE inverse-screen?
+18 VALUE #lines
+50 VALUE #columns
+
+false VALUE cursor
+false VALUE saved-cursor
+
+
+\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
+
+defer draw-character	\ 2B inited by display driver
+defer reset-screen	\ 2B inited by display driver
+defer toggle-cursor	\ 2B inited by display driver
+defer erase-screen	\ 2B inited by display driver
+defer blink-screen	\ 2B inited by display driver
+defer invert-screen	\ 2B inited by display driver
+defer insert-characters	\ 2B inited by display driver
+defer delete-characters	\ 2B inited by display driver
+defer insert-lines	\ 2B inited by display driver
+defer delete-lines	\ 2B inited by display driver
+defer draw-logo		\ 2B inited by display driver
+
+: nop-toggle-cursor ( nop ) ;
+' nop-toggle-cursor to toggle-cursor
+
+\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
+\ *
+\ *
+: (cursor-off) ( -- ) cursor dup to saved-cursor
+	IF toggle-cursor false to cursor THEN ;
+: (cursor-on) ( -- ) cursor dup to saved-cursor
+	0= IF toggle-cursor true to cursor THEN ;
+: restore-cursor ( -- ) saved-cursor dup cursor
+	<> IF toggle-cursor to cursor ELSE drop THEN ;
+
+' (cursor-off) to cursor-off
+' (cursor-on) to cursor-on
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ Generic device methods:
+\ *
+
+
+\ \\\\\\\\\\\\\\ Exported Interface:
+\ *
+\ *
+
+false VALUE esc-on
+false VALUE csi-on
+defer esc-process
+0 VALUE esc-num-parm
+0 VALUE esc-num-parm2
+0 VALUE saved-line#
+0 VALUE saved-column#
+
+: get-esc-parm ( default -- value )
+	esc-num-parm dup 0> IF nip ELSE drop THEN 0 to esc-num-parm ;
+: get-esc-parm2 ( default -- value )
+	esc-num-parm2 dup 0> IF nip ELSE drop THEN 0 to esc-num-parm2 ;
+: set-esc-parm ( newdigit -- ) [char] 0 - esc-num-parm a * + to esc-num-parm ;
+
+: reverse-cursor ( oldpos -- newpos) dup IF 1 get-esc-parm - THEN ;
+: advance-cursor ( bound oldpos -- newpos) tuck > IF 1 get-esc-parm + THEN ;
+: erase-in-line #columns column# - dup 0> IF delete-characters ELSE drop THEN ;
+
+: terminal-line++ ( -- )
+	line# 1+ dup #lines = IF 1- 0 to line# 1 delete-lines THEN
+	to line#
+;
+
+0 VALUE dang
+0 VALUE blipp
+
+: ansi-esc ( char -- )
+    csi-on IF
+	dup [char] 0 [char] 9 between IF set-esc-parm
+	ELSE CASE
+	    [char] A OF line# reverse-cursor to line# ENDOF
+	    [char] B OF #lines line# advance-cursor to line# ENDOF
+	    [char] C OF #columns column# advance-cursor to column# ENDOF
+	    [char] D OF column# reverse-cursor to column# ENDOF
+	    [char] E OF ( FIXME: Cursor Next Line - No idea what does it mean )
+	    	#lines line# advance-cursor to line#
+	    ENDOF
+	    [char] f OF
+		1 get-esc-parm2 to line# column# get-esc-parm to column#
+	    ENDOF
+	    [char] H OF
+		1 get-esc-parm2 to line# column# get-esc-parm to column#
+	    ENDOF
+	    ( second parameter delimiter for f and H commands )
+	    [char] ; OF 0 get-esc-parm to esc-num-parm2 ENDOF
+	    [char] J OF
+		#lines line# - dup 0> IF
+			line# 1+ to line# delete-lines line# 1- to line#
+		ELSE drop THEN
+		erase-in-line
+	    ENDOF
+	    [char] K OF erase-in-line ENDOF
+	    [char] L OF 1 get-esc-parm insert-lines ENDOF
+	    [char] M OF 1 get-esc-parm delete-lines ENDOF
+	    [char] @ OF 1 get-esc-parm insert-characters ENDOF
+	    [char] P OF 1 get-esc-parm delete-characters ENDOF
+	    [char] m OF 0 get-esc-parm 0<> to inverse? ENDOF
+	    ( These are non-ANSI commands recommended by OpenBoot )
+	    [char] p OF inverse-screen? IF false to inverse-screen?
+			inverse? 0= to inverse? invert-screen
+		THEN
+	    ENDOF
+	    [char] q OF inverse-screen? 0= IF true to inverse-screen?
+			inverse? 0= to inverse? invert-screen
+		THEN
+	    ENDOF
+\ 	    [char] s OF reset-screen ENDOF ( FIXME: this conflicts w. ANSI )
+\ 	    [char] s OF line# to saved-line# column# to saved-column# ENDOF
+	    [char] u OF saved-line# to line# saved-column# to column# ENDOF
+	    dup dup to dang OF blink-screen ENDOF
+	ENDCASE false to csi-on
+	false to esc-on 0 to esc-num-parm 0 to esc-num-parm2
+	THEN
+    ELSE CASE
+	( DEV VT compatibility stuff used by accept.fs )
+	[char] 7 OF line# to saved-line# column# to saved-column# ENDOF
+	[char] 8 OF saved-line# to line# saved-column# to column# ENDOF
+	[char] [ OF true to csi-on ENDOF
+	dup dup OF false to esc-on to blipp ENDOF
+        ENDCASE
+	csi-on 0= IF false to esc-on THEN 0 to esc-num-parm 0 to esc-num-parm2
+    THEN
+;
+
+' ansi-esc to esc-process
+CREATE twtracebuf 4000 allot twtracebuf 4000 erase
+twtracebuf VALUE twbp
+0 VALUE twbc
+
+: twtrace
+	twbc 4000 = IF 0 to twbc twtracebuf to twbp THEN
+	dup twbp c! twbp 1+ to twbp twbc 1+ to twbc
+;
+
+: terminal-write ( addr len -- actual-len )
+ 	cursor-off
+	tuck bounds ?DO i c@
+		twtrace
+		esc-on IF esc-process
+		ELSE CASE
+			1B OF true to esc-on ENDOF
+			carret OF 0 to column# ENDOF
+			linefeed OF terminal-line++ ENDOF
+			bell OF blink-screen ENDOF
+			9 ( TAB ) OF column# 7 + -8 and dup #columns < IF
+					to column#
+				ELSE drop THEN
+			ENDOF
+			B ( VT ) OF line# ?dup IF 1- to line# THEN ENDOF
+			C ( FF ) OF 0 to line# 0 to column# erase-screen ENDOF
+			bs OF	column# 1- dup 0< IF
+					line# IF
+						line# 1- to line#
+						drop #columns 1-
+					ELSE drop column#
+					THEN
+				THEN
+				to column# ( bl draw-character )
+			ENDOF
+			dup OF
+				i c@ draw-character
+				column# 1+ dup #columns >= IF
+					drop 0 terminal-line++
+				THEN
+				to column#
+			ENDOF
+		    ENDCASE
+		THEN
+	LOOP
+ 	restore-cursor
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/timebase.fs b/qemu-0.15.x/roms/SLOF/slof/fs/timebase.fs
new file mode 100644
index 0000000..00a0bd2
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/timebase.fs
@@ -0,0 +1,24 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+\ Define all timebase related words
+
+: tb@  ( -- tb )
+   BEGIN tbu@ tbl@ tbu@ rot over <> WHILE 2drop REPEAT
+   20 lshift swap ffffffff and or
+;
+
+: milliseconds ( -- ms ) tb@ d# 1000 * tb-frequency / ;
+: microseconds ( -- us ) tb@ d# 1000000 * tb-frequency / ;
+
+: ms ( ms-to-wait -- ) milliseconds + BEGIN milliseconds over >= UNTIL drop ;
+: get-msecs ( -- n ) milliseconds ;
+: us  ( us-to-wait -- )  microseconds +  BEGIN microseconds over >= UNTIL  drop ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/translate.fs b/qemu-0.15.x/roms/SLOF/slof/fs/translate.fs
new file mode 100644
index 0000000..e2633e5
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/translate.fs
@@ -0,0 +1,152 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ this is a C-to-Forth translation from the translate
+\ address code in the client
+\ with extensions to handle different sizes of #size-cells
+
+\ this tries to figure out if it is a PCI device what kind of
+\ translation is wanted
+\ if prop_type is 0, "reg" property is used, otherwise "assigned-addresses"
+: pci-address-type  ( node address prop_type -- type )
+   -rot 2 pick ( prop_type node address prop_type )
+   0= IF
+      swap s" reg" rot get-property  ( prop_type address data dlen false )
+   ELSE
+      swap s" assigned-addresses" rot get-property  ( prop_type address data dlen false )
+   THEN
+   IF  2drop -1  EXIT  THEN  4 / 5 /
+   \ advance (phys-addr(3) size(2)) steps
+   0 DO
+      \ BARs and Expansion ROM must be in assigned-addresses...
+      \ so if prop_type is 0 ("reg") and a config space offset is set
+      \ we skip this entry...
+      dup l@ FF AND 0<> ( prop_type address data cfgspace_offset? )
+      3 pick 0= ( prop_type address data cfgspace_offset? reg_prop? )
+      AND NOT IF 
+         2dup 8 + ( prop_type address data address data' )
+         2dup l@ 2 pick 8 + l@ + <= -rot l@  >= and  IF
+            l@ 03000000 and 18 rshift nip
+            \ no 64bit translations supported pretend it is 32bit
+            dup 3 = IF  1-  THEN
+            ( prop_type type )
+            swap drop ( type )
+            UNLOOP EXIT
+         THEN
+      THEN
+      \ advance in 4 byte steps and (phys-addr(3) size(2)) steps
+      4 5 * +
+   LOOP
+   3drop -1
+;
+
+: (range-read-cells)  ( range-addr #cells -- range-value )
+   \ if number of cells != 1; do 64bit read; else a 32bit read
+   1 =  IF  l@  ELSE  @  THEN
+;
+
+\ this functions tries to find a mapping for the given address
+\ it assumes that if we have #address-cells == 3 that we are trying
+\ to do a PCI translation
+
+\ nac - #address-cells
+\ nsc - #size-cells
+\ pnac - parent #address-cells
+
+: (map-one-range)  ( type range pnac nsc nac address -- address true | address false )
+   \ only check for the type if nac == 3 (PCI)
+   over 3 = 5 pick l@ 3000000 and 18 rshift 7 pick <> and  IF
+      >r 2drop 3drop r> false EXIT
+   THEN
+   \ get size
+   4 pick 4 pick 3 pick + 4 * +
+   \ get nsc
+   3 pick
+   \ read size
+   ( type range pnac nsc nac address range nsc )
+   (range-read-cells)
+   ( type range pnac nsc nac address size )
+   \ skip type if PCI
+   5 pick 3 pick 3 =  IF
+      4 +
+   THEN
+   \ get nac
+   3 pick
+   ( type range pnac nsc nac address size range nac )
+   \ read child-mapping
+   (range-read-cells)
+   ( type range pnac nsc nac address size child-mapping )
+   dup >r dup 3 pick > >r + over <= r> or  IF
+      \ address is not inside the mapping range
+      >r 2drop 3drop r> r> drop false EXIT
+   THEN
+   dup r> -
+   ( type range pnac nsc nac address offset )
+   \ add the offset on the parent mapping
+   5 pick 5 pick 3 =  IF
+      \ skip type if PCI
+      4 +
+   THEN
+   3 pick 4 * +
+   ( type range pnac nsc nac address offset parent-mapping-address )
+   \ get pnac
+   5 pick
+   \ read parent mapping
+   (range-read-cells)
+   ( type range pnac nsc nac address offset parent-mapping )
+   + >r 3drop 3drop r> true
+;
+
+\ this word translates the given address starting from the node specified
+\ in node; the word will return to the node it was started from
+: translate-address  ( node address -- address )
+   \ check for address type in "assigned-addresses"
+   2dup 1 pci-address-type  ( node address type )
+   dup -1 = IF
+      \ not found in "assigned-addresses", check in "reg"
+      drop 2dup 0 pci-address-type ( node address type )
+   THEN
+   rot parent BEGIN
+      \ check if it is the root node
+      dup parent 0=  IF  2drop EXIT  THEN
+      ( address type parent )
+      s" #address-cells" 2 pick get-property 2drop l@ >r        \ nac
+      s" #size-cells" 2 pick get-property 2drop l@ >r           \ nsc
+      s" #address-cells" 2 pick parent get-property 2drop l@ >r \ pnac
+      -rot ( node address type )
+      s" ranges" 4 pick get-property  IF
+         3drop
+         ABORT" no ranges property; not translatable"
+      THEN
+      r> r> r> 3 roll
+      ( node address type ranges pnac nsc nac length )
+      4 / >r 3dup + + >r 5 roll r> r> swap / 0 ?DO
+         ( node type ranges pnac nsc nac address )
+         6dup (map-one-range) IF
+            nip leave
+         THEN
+         nip
+         \ advance ranges
+         4 roll
+         ( node type pnac nsc nac address ranges )
+         4 pick 4 pick 4 pick + + 4 * + 4 -roll
+      LOOP
+      >r 2drop 2drop r> ( node type address )
+      swap rot parent ( address type node )
+      dup 0=
+   UNTIL
+;
+
+\ this words translates the given address starting from the current node
+: translate-my-address  ( address -- address' )
+   get-node swap translate-address
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/update_flash.fs b/qemu-0.15.x/roms/SLOF/slof/fs/update_flash.fs
new file mode 100644
index 0000000..495e15f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/update_flash.fs
@@ -0,0 +1,110 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Set by update-flash -f to true, preventing update-flash -c
+false value flash-new
+
+: update-flash-help ( -- )
+   cr ." update-flash tool to flash host FW " cr
+   ."              -f <filename>      : Flash from file (e.g. net:\boot_rom.bin)" cr
+   ."              -l                 : Flash from load-base" cr
+   ."              -d                 : Flash from old load base (used by drone)" cr
+   ."              -c                 : Flash from temp to perm" cr
+   ."              -r                 : Flash from perm to temp" cr
+;
+
+: flash-read-temp ( -- success? )
+   get-flashside 1 = IF flash-addr load-base over flash-image-size rmove true
+   ELSE
+      false
+   THEN
+;
+
+: flash-read-perm ( -- success? )
+   get-flashside 0= IF
+      flash-addr load-base over flash-image-size rmove true
+   ELSE
+      false
+   THEN
+;
+
+: flash-switch-side ( side -- success? )
+   set-flashside 0<> IF
+      s" Cannot change flashside" type cr false
+   ELSE
+      true
+   THEN
+;
+
+: flash-ensure-temp ( -- success? )
+   get-flashside 0= IF
+      cr ." Cannot flash perm! Switching to temp side!"
+      1 flash-switch-side
+   ELSE
+      true
+   THEN
+;
+
+\ update-flash -f <filename>
+\              -l
+\              -c
+\              -r
+
+: update-flash ( "text" )
+   get-flashside >r                              \ Save old flashside
+   parse-word                      ( str len )   \ Parse first string
+   drop dup c@                     ( str first-char )
+   [char] - <> IF
+      update-flash-help r> 2drop EXIT
+   THEN
+
+   1+ c@                           ( second-char )
+   CASE
+      [char] f OF
+         parse-word cr s" do-load" evaluate
+         flash-ensure-temp TO flash-new
+      ENDOF
+      [char] l OF
+         flash-ensure-temp
+      ENDOF
+      [char] d OF
+         flash-load-base load-base 200000 move
+         flash-ensure-temp
+      ENDOF
+      [char] c OF
+         flash-read-temp 0= flash-new or IF
+            ." Cannot commit temp, need to boot on temp first " cr false
+         ELSE
+            0 flash-switch-side
+         THEN
+      ENDOF
+      [char] r OF
+         flash-read-perm 0= IF
+         ." Cannot commit perm, need to boot on perm first " cr false
+         ELSE
+         1 flash-switch-side
+         THEN
+      ENDOF
+      dup      OF
+         false
+      ENDOF
+   ENDCASE
+
+   ( true| false )
+
+   0= IF
+      update-flash-help r> drop EXIT
+   THEN
+
+   load-base flash-write 0= IF ." Flash write failed !! " cr THEN
+   r> set-flashside drop                           \ Restore old flashside
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-enumerate.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-enumerate.fs
new file mode 100644
index 0000000..7118f17
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-enumerate.fs
@@ -0,0 +1,324 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ create the device tree for hub
+
+: (hub-create) ( -- )
+   mps port-number new-device-address port-number 
+   ( mps port-number usb-address port-number )
+   new-device set-space                ( mps port-number usb-address )
+   encode-int s" USB-ADDRESS" property ( mps port-number )
+   s" Address Set"  usb-debug-print
+   encode-int s" reg" property         ( mps )
+   s" Port Number Set"   usb-debug-print 
+   encode-int s" MPS-DCP" property
+   s" MPS Set"   usb-debug-print
+   s" usb-hub.fs" INCLUDED
+   s" Driver Included"   usb-debug-print
+   finish-device
+;
+
+
+\ encode properties for scsi or atapi device
+
+: (atapi-scsi-property-set) ( -- )
+   dd-buffer @ e + c@     ( Manuf )
+   dd-buffer @ f + c@     ( Manuf Prod )
+   dd-buffer @ 10 + c@    ( Manuf Prod Serial-Num )
+   cd-buffer @ 16 + w at -le ( Manuf Prod Serial-Num ep-mps )
+   cd-buffer @ 14 + c@    ( Manuf Prod Serial-Num ep-mps ep-addr )
+   cd-buffer @ 1d + w at -le ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps )
+   cd-buffer @ 1b + c@    ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr )
+   mps port-number new-device-address port-number
+                        ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr 
+                          mps port-num usb-addr port-num )
+   new-device set-space
+                        ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+                           mps port-num usb-addr )
+   encode-int s" USB-ADDRESS" property
+                        ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+                           mps port-num )
+   encode-int s" reg" property
+                        ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr 
+                           mps )
+   encode-int s" MPS-DCP" property
+                        ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr )
+   2 0  DO
+      dup 80 and IF
+         7f and encode-int
+         s" BULK-IN-EP-ADDR" property
+         encode-int s" MPS-BULKIN" property
+      ELSE
+         encode-int s" BULK-OUT-EP-ADDR" property
+         encode-int s" MPS-BULKOUT" property
+      THEN
+   LOOP                                  ( Manuf Prod Serial-Num )
+   encode-int s" iSerialNumber" property ( Manuf Prod )
+   encode-int s" iProduct" property      ( Manuf )
+   encode-int s" iManufacturer" property
+;
+
+
+\ To classify device as hub/atapi/scsi/HID device
+
+: (device-classify) 
+   ( -- Interface-protocol Interface-subclass Interface-class TRUE|FALSE )
+   cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN erase
+   cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN mps new-device-address 
+                                  ( buffer descp-len mps usb-address )
+   control-std-get-configuration-descriptor
+   IF
+      cd-buffer @ 1+ c@           ( Descriptor-type )
+      2 =   IF
+         cd-buffer @ 10 + c@      ( protocol )
+         cd-buffer @ f + c@       ( protocol subclass )
+         cd-buffer @ e + c@       ( protocol subclass class )
+         TRUE
+      ELSE
+         s" Not a valid configuration descriptor!!" usb-debug-print
+         FALSE
+      THEN
+   ELSE
+      s" Unable to read configuration descriptor!!" usb-debug-print
+      FALSE
+   THEN
+;
+
+
+\ create device tree for Atapi SFF-8020 device
+
+: (atapi-8020-create) ( -- )
+   (atapi-scsi-property-set)
+   s" usb-storage.fs" INCLUDED
+   finish-device
+;
+
+\ create device tree for Atapi SFF-8070 device
+
+: (atapi-8070-create) ( -- )
+   (atapi-scsi-property-set)
+   s" usb-storage.fs" INCLUDED
+   \ s" storage" device-name
+   finish-device
+;
+
+
+\ create device tree for SCSI device
+
+: (scsi-create) ( -- )
+   s" SCSI-CREATE " usb-debug-print
+
+\ ***********************************************************************
+\ a problem was encountered on Media-Tray (REV-0):
+\ The CDROM is connected to USB via an ATA/USB-Bridge (U38: CYPRESS CY7C68300)
+\ The C-Revision of this chip has an malfunction which results in a
+\ hanging IORD Signal at the ATA-Interface and so prevents from reading.
+\ The B-Revision doesn't have this problem (populated on Media-Tray REV-5)
+\ Two additional Mass-Storage-Resets are necessary to reset the ATA-Interface.
+\ (see CYPRESS Application Notes to CY7C68300)
+\ (see USB-Spec: 'Bulk-Only-Transport')
+\ ***********************************************************************
+\ a mounted ISO image (via USB) doesn't accept this bulk-reset-command!
+\ ***********************************************************************
+
+   dd-buffer @ 8 + w at -le 4b4 =         \ VendorID = CYPRESS ?
+   IF
+      dd-buffer @ a + w at -le 6830 =     \ Device = CY7C68300 ?
+      IF
+       \ here a Cypress ATA/USB Bridge is detected
+       d# 20 ms
+       mps new-device-address 0 0 0   ( MPS fun-addr dir data-buff data-len )
+       control-bulk-reset             ( TRUE|FALSE )
+       d# 100 ms
+       mps new-device-address 0 0 0   ( TRUE|FALSE MPS fun-addr dir data-buff data-len )
+       control-bulk-reset             ( TRUE|FALSE TRUE|FALSE )
+       and invert
+       IF
+          ."   ** BULK-RESET failed **" cr
+       THEN
+       d# 20 ms
+      THEN
+   THEN
+
+   0 ch-buffer !                 \ preset a clean response
+   mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE )
+   IF
+\      s" GET-MAX-LUN IS WORKING :" usb-debug-print
+\      ch-buffer  5 dump cr      \ dump the responsed message
+   ELSE
+      s" ERROR in GET-MAX-LUN " usb-debug-print
+      0 ch-buffer !              \ clear invalid numbers
+      cd-buffer @ 5 + c@ to temp1
+      temp1 new-device-address control-std-set-configuration drop
+   THEN
+   \ FIXME: an IBM external HDD reported a number of 127 LUNs which could
+   \        not be set up. We need to understand how to set up the device
+   \        to report the correct number of LUNs.
+   \        The USB Massbulk Standard 1.0 defines a maximum of 15 mult. LUNs.
+   \ Workaround: Devices that might report a higher number are treated
+   \             as having exactly one LUN. Without this workaround the
+   \             USB scan hangs during the setup of non-available LUNs.
+   \
+   \ Concerns: "FUJITSU MHV2040AT" (VendorID: 0x984 / DeviceID: 0x70)
+   \
+   \ MR: This Device reports an invalid MaxLUN number within the first
+   \ three seconds after power-on or USB-Reset. The following loop repeats
+   \ the MaxLUN request up to 8 times until a valid ( <15 ) value is responded.
+   \ This can last up to four seconds as there is a delay of 500ms in every loop
+
+   0                       ( counter )
+   begin
+      dup 8 <              ( counter flag )           \ max 8 * 500 ms
+      ch-buffer c@ f >     ( counter flag flag )      \ is MuxLUN above limit ?
+      AND                  ( counter flag )
+      while
+         d# 500 ms                     \ this device is not yet ready
+         0 ch-buffer !                 \ preset a clean response
+         mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE )
+         not
+         IF
+            s"  ** ERROR in GET-MAX-LUN ** " usb-debug-print
+            drop 10                    \ replace counter to force loop end
+         THEN
+         1+                ( counter+1 )
+      repeat
+   drop
+
+   \ here is still the workaround to handle invalid MaxLUNs as '0'
+   \
+   ch-buffer c@ dup 0= swap f > or IF   
+      s" + LUN: " ch-buffer c@  usb-debug-print-val
+      (atapi-scsi-property-set)
+      s" usb-storage.fs" INCLUDED
+      finish-device
+
+   ELSE
+      s" - LUN: " ch-buffer c@ usb-debug-print-val
+      (atapi-scsi-property-set)
+      s" usb-storage-wrapper.fs" INCLUDED
+      finish-device
+
+   THEN
+;
+
+
+\ Classify USB storage device by sub-class code
+
+: (classify-storage)  ( interface-protocol interface-subclass -- )
+   s" USB: Mass Storage Device Found!" usb-debug-print
+   swap 50 <> IF
+      s" USB storage: Protocol is not 50." usb-debug-print
+      drop EXIT
+   THEN
+   ( interface-subclass )
+   CASE
+      02 OF  (atapi-8020-create) s" ATAPI Interface " usb-debug-print ENDOF
+      05 OF  (atapi-8070-create) s" ATAPI Interface " usb-debug-print ENDOF
+      06 OF  (scsi-create) s" SCSI Interface " usb-debug-print ENDOF
+      dup OF  s" USB storage: Unsupported sub-class code." usb-debug-print ENDOF
+   ENDCASE
+;
+
+
+\ create keyboard device tree
+
+: (keyboard-create) ( -- )
+   cd-buffer @ 1f + c@                 ( ep-mps )
+   cd-buffer @ 1d + c@                 ( ep-mps ep-addr )  
+   mps port-number new-device-address port-number
+                                        ( ep-mps ep-addr mps port-num usb-addr port-num )
+   new-device set-space                 ( ep-mps ep-addr mps port-num usb-addr )
+   encode-int s" USB-ADDRESS" property  ( ep-mps ep-addr mps port-num )
+   encode-int s" reg" property          ( ep-mps ep-addr mps )
+   encode-int s" MPS-DCP" property      ( ep-mps ep-addr )
+   7f and encode-int s" INT-IN-EP-ADDR" property
+   encode-int s" MPS-INTIN" property
+   new-device-address   \ device-speed
+   s" usb-keyboard.fs" INCLUDED
+   finish-device
+;
+
+: (mouse-create) ( -- )
+   mps port-number new-device-address port-number
+                                        ( mps port-num usb-addr port-num )
+   new-device set-space                 ( mps port-num usb-addr )
+   encode-int s" USB-ADDRESS" property  ( mps port-num )
+   encode-int s" reg" property          ( mps )
+   encode-int s" MPS-DCP" property
+   s" usb-mouse.fs" INCLUDED
+   finish-device
+;
+
+
+\ Classify by interface class code
+
+: (classify-by-interface) ( -- )
+   (device-classify)  IF
+      ( Interface-protocol Interface-subclass Interface-class )
+      CASE
+         08 OF
+            ( Interface-protocol Interface-subclass )
+            (classify-storage)
+         ENDOF
+         03 OF
+	         ( Interface-protocol Interface-subclass )
+	         s" USB: HID Found!" usb-debug-print
+	         01 =
+            IF
+		         case
+		            01 of
+			            s" USB keyboard!" usb-debug-print
+			            (keyboard-create)
+		            endof
+		            02 of
+		     	         s" USB mouse!" usb-debug-print
+		     	         (mouse-create)
+		            endof
+		            dup of
+			            s" USB: unsupported HID!" usb-debug-print
+		            endof
+		         endcase
+	         ELSE
+		         s" USB: unsupported HID!" usb-debug-print
+	         THEN
+	      ENDOF
+         dup OF
+            ( Interface-protocol Interface-subclass )
+            s" USB: unsupported interface type." usb-debug-print
+            2drop
+         ENDOF
+      ENDCASE
+   THEN
+;
+
+
+\ create usb device tree depending upon classification of the device
+\ after encoding apt properties
+
+: create-usb-device-tree ( -- )
+   dd-buffer @ DEVICE-DESCRIPTOR-DEVCLASS-OFFSET + c@    ( Device-class )
+   CASE
+      HUB-DEVICE-CLASS OF s" USB: HUB found"   usb-debug-print
+         (hub-create)
+      ENDOF
+      NO-CLASS  OF
+         \ In this case, the INTERFACE descriptor
+         \ tells you whats what -- Refer USB spec.
+         (classify-by-interface)
+      ENDOF
+      DUP OF
+         s" USB: Unknown device found." usb-debug-print
+      ENDOF
+   ENDCASE
+   uDOC-present 0f and to uDOC-present \ remove uDOC processing flag
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-hub.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-hub.fs
new file mode 100644
index 0000000..106b680
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-hub.fs
@@ -0,0 +1,459 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ ----------------------------------------------------------------------------
+\ On detection of a hub after reading the device descriptor this package has to
+\ be called so that the hub enumeration is done to idenitify the down stream 
+\ device  
+\ --------------------------------------------------------------------------
+\ OF properties
+\ --------------------------------------------------------------------------
+
+
+s" hub" device-name
+s" usb" device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+\ converts physical address to text unit string 
+
+
+: encode-unit ( port-addr -- unit-str unit-len )  1 hex-encode-unit ;
+
+
+\ Converts text unit string to phyical address 
+
+
+: decode-unit ( addr len -- port-addr ) 1 hex-decode-unit ;
+
+0 VALUE new-device-address
+0 VALUE port-number
+0 VALUE MPS-DCP
+0 VALUE mps
+0 VALUE my-usb-address
+
+00 value device-speed
+
+
+\ Get parameters passed from the parent.
+
+: mps-property-set ( -- )
+   s"  HUB Compiling mps-property-set " usb-debug-print
+   s" USB-ADDRESS" get-my-property ( TRUE | prop-addr prop-len FALSE )
+   IF
+      s" notpossible" usb-debug-print
+   ELSE
+      decode-int nip nip to my-usb-address
+   THEN  
+   s" MPS-DCP" get-my-property ( TRUE | prop-addr prop-len FALSE )
+   IF 
+      s" MPS-DCP property not found Assuming 8 as MAX PACKET SIZE" ( str len )  
+      usb-debug-print
+      s" for the default control pipe"  usb-debug-print
+      8 to MPS-DCP
+   ELSE
+      s" MPS-DCP property found!!" usb-debug-print ( prop-addr prop-len FALSE )
+      decode-int nip nip to MPS-DCP
+   THEN
+;
+
+
+\ --------------------------------------------------------------------------
+\ Constant declarations
+\ --------------------------------------------------------------------------
+
+
+2303080000000000 CONSTANT hppwr-set
+2301080000000000 CONSTANT hppwr-clear
+2303040000000000 CONSTANT hprst-set
+A300000000000400 CONSTANT hpsta-get
+2303010000000000 CONSTANT hpena-set
+A006002900000000 CONSTANT hubds-get
+8  CONSTANT DEFAULT-CONTROL-MPS
+12 CONSTANT DEVICE-DESCRIPTOR-LEN
+9  CONSTANT CONFIG-DESCRIPTOR-LEN
+20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN
+
+
+\ TODO:
+\ CONFIG-DESCRIPTOR-LEN should be only 9. The interface
+\ and endpoint descriptors returned along with config
+\ descriptor are variable and 0x19 is a very wrong VALUE
+\ to specify for this #define.
+
+
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET
+4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET
+7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET
+9 CONSTANT HUB-DEVICE-CLASS
+0 CONSTANT NO-CLASS
+
+
+\ --------------------------------------------------------------------------
+\ Temporary Variable declarations
+\ --------------------------------------------------------------------------
+
+00 VALUE temp1
+00 VALUE temp2
+00 VALUE temp3
+00 VALUE po2pg            \ Power On to Power Good
+
+
+\ --------------------------------------------------------------------------
+\ Buffer allocations
+\ --------------------------------------------------------------------------
+
+
+VARIABLE setup-packet     \ 8 bytes for setup packet
+VARIABLE ch-buffer        \ 1 byte character buffer
+
+INSTANCE VARIABLE dd-buffer
+INSTANCE VARIABLE cd-buffer
+
+\ TODO:
+\ Should arrive a proper value for the size of the "cd-buffer"
+
+8 chars alloc-mem VALUE status-buffer
+9 chars alloc-mem VALUE hd-buffer
+
+
+: (allocate-mem)  ( -- )
+   DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer !
+   BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer !
+;
+
+
+: (de-allocate-mem)  ( -- )
+   dd-buffer @ ?dup IF
+      DEVICE-DESCRIPTOR-LEN free-mem
+      0 dd-buffer !
+   THEN
+   cd-buffer @ ?dup IF
+      BULK-CONFIG-DESCRIPTOR-LEN free-mem
+      0 cd-buffer !
+   THEN
+;
+
+
+\ standard open firmware methods 
+
+: open ( -- TRUE )
+   (allocate-mem)
+   TRUE
+;
+
+: close ( -- )
+   (de-allocate-mem)
+;
+
+
+\ --------------------------------------------------------------------------
+\ Parent's method
+\ --------------------------------------------------------------------------
+
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE )
+   s" controlxfer" $call-parent 
+;
+
+: control-std-set-address ( speedbit -- usb-address TRUE|FALSE )
+   s" control-std-set-address" $call-parent 
+; 
+
+: control-std-get-device-descriptor 
+   ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+   s" control-std-get-device-descriptor" $call-parent 
+;
+
+: control-std-get-configuration-descriptor 
+   ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+   s" control-std-get-configuration-descriptor" $call-parent 
+;
+
+: control-std-get-maxlun
+   ( MPS fun-addr dir data-buff data-len -- TRUE|FALSE )
+   s" control-std-get-maxlun" $call-parent 
+;
+
+: control-std-set-configuration 
+   ( configvalue FuncAddr -- TRUE|FALSE )
+   s" control-std-set-configuration" $call-parent 
+;
+
+: control-std-get-string-descriptor
+   ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+   s" control-std-get-string-descriptor" $call-parent 
+;
+
+: rw-endpoint 
+   ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+   s" rw-endpoint" $call-parent 
+;
+
+: debug-td ( -- )
+   s" debug-td" $call-parent
+;
+
+\ *** NEW ****
+: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+   s" control-bulk-reset" $call-parent
+;
+
+
+\ --------------------------------------------------------------------------
+\ HUB specific methods
+\ --------------------------------------------------------------------------
+\ To bring on the power on a valid port of a hub with a valid USB address
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-power-set  ( port# -- TRUE|FALSE )
+   hppwr-set setup-packet !	( port#)
+   setup-packet 4 + c!
+   0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE | FALSE )
+;
+
+
+\ --------------------------------------------------------------------------
+\ To put power off on ports where device detection or enumeration has failed
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-power-clear ( port#-- TRUE|FALSE )
+   hppwr-clear setup-packet !	( port#)
+   setup-packet 4 + c!
+   0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To reset a valid port of a hub with a valid USB 
+\ address
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-reset-set ( port# -- TRUE|FALSE )
+   hprst-set setup-packet !	( port# )
+   setup-packet 4 + c!
+   0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To enable a particular valid port of a hub with a valid USB address
+\ -------------------------------------------------------------------------
+
+
+: control-hub-port-enable ( port# -- TRUE|FALSE )
+   hpena-set setup-packet !	( port# )
+   setup-packet 4 +  c!
+   0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To get the status of a valid port of a hub with 
+\ a valid USB address
+\ -------------------------------------------------------------------------
+
+
+: control-hub-port-status-get ( buffer port# -- TRUE|FALSE )
+   hpsta-get setup-packet !	( buffer port# )
+   setup-packet 4 + c!		( buffer )
+   0 swap 4 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ --------------------------------------------------------------------------
+\ To get the hub descriptor to understand how many ports are vailable and the 
+\ specs of those ports
+\ ---------------------------------------------------------------------------
+
+
+: control-get-hub-descriptor ( buffer buffer-length -- TRUE|FALSE )
+   hubds-get setup-packet ! 
+   dup setup-packet 6 + w!-le ( buffer buffer-length )
+   0 -rot setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+s" usb-enumerate.fs" INCLUDED
+
+
+: hub-configure-port ( port# -- )
+
+\ this port has been powered on
+\ send reset to enable port and
+\ start device detection by hub
+\ some devices require a long timeout here (10s)
+
+   \ Step 1: check if reset state ended
+
+   BEGIN				( port# )
+      status-buffer 4 erase             ( port# )
+      status-buffer over control-hub-port-status-get drop ( port# ) 
+      status-buffer w at -le 102 and 0= 	( port# TRUE|FALSE )
+   WHILE				( port# )
+   REPEAT			( port# )
+   po2pg 3 * ms    \ wait for bPwrOn2PwrGood*3 ms
+   
+   \ STEP 2: Reset the port.
+   \         (this also enables the port)
+   dup control-hub-port-reset-set drop	( port# )
+   BEGIN				( port# )
+      status-buffer 4 erase             ( port# )
+      status-buffer over control-hub-port-status-get drop ( port# ) 
+      status-buffer w at -le 10 and 	( port# TRUE|FALSE )
+   WHILE				( port# )
+   REPEAT				( port# )
+
+   \ STEP 3: Check if a device is connected to the port.
+
+   status-buffer 4 erase                ( port# )
+   status-buffer over control-hub-port-status-get drop ( port# ) 
+   status-buffer w at -le    103 and    103 <> 	       ( port# TRUE|FALSE )
+   s" Port status bits: " status-buffer w at -le usb-debug-print-val
+   IF					( port# ) 
+      drop			
+      s" Connect status: No device connected "  usb-debug-print
+      EXIT 
+   THEN 
+
+
+   \ STEP 4: Assign an address to this device.
+
+   status-buffer w at -le 200 and 4 lshift \ get speed bit
+   dup to device-speed                  \ store speed bit
+                                ( port# speedbit )
+   control-std-set-address	( port# usb-addr TRUE|FALSE )
+   50 ms			( port# usb-addr TRUE|FALSE )
+   debug-td			( port# usb-addr TRUE|FALSE )
+   IF 				( port# usb-addr )
+      device-speed or           ( port# usb-addr+speedbit )
+      to new-device-address     ( port# )
+      to port-number
+      dd-buffer @ DEVICE-DESCRIPTOR-LEN erase
+      dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS new-device-address
+      ( buffer mps mps usb-addr ) 
+      control-std-get-device-descriptor     ( TRUE|FALSE )
+      IF
+         dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( descriptor-type )
+         DEVICE-DESCRIPTOR-TYPE <>          ( TRUE|FALSE )
+         IF 
+            s" HUB: ERROR!! Invalid Device Descriptor for the new device"
+            usb-debug-print
+         ELSE
+            dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ to mps
+
+            \ Re-read the device descriptor again with the known MPS.
+
+            dd-buffer @ DEVICE-DESCRIPTOR-LEN erase
+            dd-buffer @ DEVICE-DESCRIPTOR-LEN mps new-device-address
+            ( buffer descp-len mps usb-addr )
+            \ s" DEVICE DESCRIPTOR: " usb-debug-print
+            control-std-get-device-descriptor invert
+            IF
+               s" ** reading dev-descriptor failed ** " usb-debug-print
+            THEN
+            create-usb-device-tree
+         THEN
+      ELSE
+         s" ERROR!! Failed to get device descriptor" usb-debug-print 
+      THEN
+   ELSE						    ( port# )
+      s" USB Set Adddress failed!!" usb-debug-print ( port# )
+      s" Clearing Port Power..."  usb-debug-print   ( port# )
+      control-hub-port-power-clear		    ( TRUE|FALSE )
+      IF 
+         s" Port power down " usb-debug-print
+      ELSE
+         s" Unable to clear port power!!!" usb-debug-print
+      THEN
+   THEN
+;
+
+
+\ ---------------------------------------------------------------------------
+\ To enumerate all the valid ports of hub
+\ TODO:
+\ 1. Remove hardcoded constants.
+\ 2. Remove Endian Dependencies.
+\ 3. Return values of controlxfer should be checked. 
+\ ---------------------------------------------------------------------------
+
+: hub-enumerate ( -- )
+   cd-buffer @ CONFIG-DESCRIPTOR-LEN erase
+
+   \ Get HUB configuration and SET the configuration
+   \ note: remove hard-coded constants.
+
+   cd-buffer @ CONFIG-DESCRIPTOR-LEN MPS-DCP my-usb-address 
+   ( buffer descp-len mps usb-address )
+   control-std-get-configuration-descriptor drop 
+   cd-buffer @ 1+ c@ 2 <>  IF
+      s" Unable to read configuration descriptor" usb-debug-print
+      EXIT 
+   THEN 
+   cd-buffer @ 4 + c@ 1 <> IF
+      s" Not a valid HUB config descriptor" usb-debug-print 
+      EXIT 
+   THEN 
+
+   \ TODO: Do further checkings on the returned Configuration descriptor
+   \ before proceeding to accept it.
+
+   cd-buffer @ 5 + c@ to temp1 \ Store the configuration in temp1
+   temp1 my-usb-address control-std-set-configuration drop
+   my-usb-address to temp1
+   hd-buffer 9 erase
+   hd-buffer 9 control-get-hub-descriptor drop
+
+   \ PENDING: 1. Check Return value.
+   \          2. HUB descriptor size is variable. Currently we r hardcoding
+   \             a value of 9.
+
+   hd-buffer 2 + c@ to temp2     \ number of downstream ports
+
+   s" HUB: Found " usb-debug-print
+   s" number of downstream hub ports! : " temp2 usb-debug-print-val
+   hd-buffer 5 + c@ to po2pg     \ get bPwrOn2PwrGood
+
+   \ power on all present hub ports
+   \ to allow slow devices to set up
+
+   temp2 1+ 1 DO
+      i control-hub-port-power-set drop
+      d# 20 ms
+   LOOP
+
+   d# 200 ms      \ some devices need a long time (10s)
+
+   \ now start detection and configuration for these ports
+   
+   temp2 1+ 1 DO
+       s" hub-configure-port: " i usb-debug-print-val
+       i hub-configure-port
+   LOOP
+; 
+
+
+\ --------------------------------------------------------------------------  
+\ To initialize hub
+\ --------------------------------------------------------------------------
+
+(allocate-mem)
+mps-property-set
+hub-enumerate
+(de-allocate-mem)
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-kbd-device-support.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-kbd-device-support.fs
new file mode 100644
index 0000000..9fa4236
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-kbd-device-support.fs
@@ -0,0 +1,102 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+00 value kbd-addr
+to kbd-addr
+8 alloc-mem to kbd-report
+4 chars alloc-mem value kbd-data
+
+: rw-endpoint
+  s" rw-endpoint" $call-parent ;
+
+: controlxfer
+  s" controlxfer" $call-parent ;
+
+: control-std-get-device-descriptor
+  s" control-std-get-device-descriptor" $call-parent ;
+
+: control-std-get-configuration-descriptor
+  s" control-std-get-configuration-descriptor" $call-parent ;
+
+: control-std-set-configuration
+  s" control-std-set-configuration" $call-parent ;
+
+: control-cls-set-protocol ( reportvalue FuncAddr -- TRUE|FALSE )
+  to temp1
+  to temp2
+  210b000000000100 setup-packet ! 
+  temp2 kbd-data l!-le
+  1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer  
+;
+
+: control-cls-set-idle ( reportvalue FuncAddr -- TRUE|FALSE )
+  to temp1
+  to temp2
+  210a000000000000 setup-packet ! 
+  temp2 kbd-data l!-le
+  0 kbd-data 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer  
+;
+
+: control-std-get-report-descriptor ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+  to temp1
+  to temp2
+  to temp3
+  8106002200000000 setup-packet ! 
+  temp3 setup-packet 6 + w!-le
+  0 swap temp3 setup-packet temp2 temp1 controlxfer  
+;
+
+: kbd-init
+    s" Starting to initialize keyboard" usb-debug-print
+    s" MPS-INTIN" get-my-property
+    if
+	s" not possible" usb-debug-print
+    else
+	decode-int nip nip to mps-int-in
+    then
+    s" INT-IN-EP-ADDR" get-my-property
+    if
+	s" not possible" usb-debug-print
+    else
+	decode-int nip nip to int-in-ep
+    then
+
+  7f alloc-mem to cfg-buffer
+  s" Allocated buffers!!" usb-debug-print
+
+  cfg-buffer 12 8 kbd-addr                   \ get device descriptor
+  control-std-get-device-descriptor
+  drop
+  \ s" dev_desc=" type cfg-buffer 12 dump cr
+
+  cfg-buffer 9 8 kbd-addr                    \ get config descriptor  
+  control-std-get-configuration-descriptor
+  drop
+  \ s" cfg_desc=" type cfg-buffer 9 dump cr
+
+  cfg-buffer 5 + c@ kbd-addr                 \ set configuration  
+  control-std-set-configuration
+  drop
+  s" KBDS: Set config returned" usb-debug-print 
+
+  0 kbd-addr control-cls-set-idle drop       \ set idle  
+  s" KBDS: Set idle returned" usb-debug-print
+
+  cfg-buffer 40 8 kbd-addr                   \ get report descriptor
+  control-std-get-report-descriptor
+  drop
+  \ s" report_desc=" type cfg-buffer 40 dump cr
+
+  s" Finished initializing keyboard" usb-debug-print 
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-keyboard.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-keyboard.fs
new file mode 100644
index 0000000..fd96e6e
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-keyboard.fs
@@ -0,0 +1,371 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" keyboard" device-name
+s" keyboard" device-type
+
+."   USB Keyboard" cr
+
+3 encode-int s" assigned-addresses" property
+1 encode-int s" reg" property
+1 encode-int s" configuration#" property
+s" EN" encode-string s" language" property
+
+1 constant NumLk
+2 constant CapsLk
+4 constant ScrLk
+
+00 value kbd-addr
+to kbd-addr                                \ save speed bit
+8 value mps-dcp
+8 constant DEFAULT-CONTROL-MPS
+8 chars alloc-mem value setup-packet
+8 chars alloc-mem value kbd-report
+4 chars alloc-mem value multi-key
+0 value cfg-buffer
+0 value led-state
+0 value temp1
+0 value temp2
+0 value temp3
+0 value ret
+0 value scancode
+0 value kbd-shift
+0 value kbd-scan
+0 value key-old
+0 value expire-ms
+0 value mps-int-in
+0 value int-in-ep
+0 value int-in-toggle
+
+kbd-addr                                    \ give speed bit to include file 
+s" usb-kbd-device-support.fs" included
+
+: control-cls-set-report ( reportvalue FuncAddr -- TRUE|FALSE )
+  to temp1
+  to temp2
+  2109000200000100 setup-packet ! 
+  temp2 kbd-data l!-le  
+  1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer  
+;
+
+: control-cls-get-report ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+  to temp1
+  to temp2
+  to temp3
+  a101000100000000 setup-packet ! 
+  temp3 setup-packet 6 + w!-le  
+  0 swap temp3 setup-packet temp2 temp1 controlxfer  
+;
+
+: int-get-report ( -- )                                           \ get report for interrupt transfer
+    0 2 int-in-toggle kbd-report 8 mps-int-in
+    kbd-addr int-in-ep 7 lshift or rw-endpoint                    \ get report 
+    swap to int-in-toggle if
+	kbd-report @ ff00000000000000 and 38 rshift to kbd-shift  \ store shift status
+	kbd-report @ 0000ffffffffffff and to kbd-scan             \ store scan codes
+    else
+	0 to kbd-shift                                            \ clear shift status 
+	0 to kbd-scan                                             \ clear scan code buffer
+    then
+;
+
+: ctl-get-report ( -- )                                           \ get report for control transfer      
+    kbd-report 8 8 kbd-addr control-cls-get-report if             \ get report 
+        kbd-report @ ff00000000000000 and 38 rshift to kbd-shift  \ store shift status
+        kbd-report @ 0000ffffffffffff and to kbd-scan             \ store scan codes 
+    else
+	0 to kbd-shift                                            \ clear shift status 
+	0 to kbd-scan                                             \ clear scan code buffer
+    then
+;
+
+: set-led ( led -- ) 
+  dup to led-state  
+  kbd-addr control-cls-set-report drop
+;
+
+: is-shift ( -- true|false )
+    kbd-shift 22 and if
+	true
+    else
+	false
+    then
+;
+
+: is-alt ( -- true|false )
+    kbd-shift 44 and if
+	true
+    else
+	false
+    then
+;
+
+: is-ctrl ( -- true|false )
+    kbd-shift 11 and if
+	true
+    else
+	false
+    then
+;
+
+: ctrl_alt_del_key ( char -- )
+    is-ctrl if                                           \ ctrl is pressed?
+	is-alt if                                        \ alt is pressed?
+	    4c = if                                      \ del is pressed?
+		s" reboot.... " usb-debug-print 
+		\ reset-all                              \ reboot
+		drop false                               \ invalidate del key on top of stack
+	    then
+	    false                                        \ dummy for last drop
+	then
+    then
+    drop                                                 \ clear stack 
+;
+
+: get-ukbd-char ( ScanCode -- char|false )
+    dup ctrl_alt_del_key                                 \ check ctrl+alt+del 
+    dup to scancode                                      \ store scan code
+    case                                                 \ translate scan code --> char
+	 04 of [char] a endof 
+	 05 of [char] b endof 
+	 06 of [char] c endof 
+	 07 of [char] d endof 
+	 08 of [char] e endof 
+	 09 of [char] f endof 
+ 	 0a of [char] g endof 
+	 0b of [char] h endof 
+	 0c of [char] i endof 
+	 0d of [char] j endof 
+	 0e of [char] k endof 
+	 0f of [char] l endof 
+	 10 of [char] m endof 
+	 11 of [char] n endof 
+	 12 of [char] o endof 
+	 13 of [char] p endof 
+	 14 of [char] q endof 
+	 15 of [char] r endof 
+	 16 of [char] s endof 
+	 17 of [char] t endof 
+	 18 of [char] u endof 
+	 19 of [char] v endof 
+	 1a of [char] w endof 
+	 1b of [char] x endof 
+	 1c of [char] y endof 
+	 1d of [char] z endof 
+	 1e of [char] 1 endof 
+	 1f of [char] 2 endof 
+	 20 of [char] 3 endof 
+	 21 of [char] 4 endof 
+	 22 of [char] 5 endof 
+	 23 of [char] 6 endof 
+	 24 of [char] 7 endof 
+	 25 of [char] 8 endof 
+	 26 of [char] 9 endof 
+	 27 of [char] 0 endof 
+	 28 of 0d endof                            \ Enter
+	 29 of 1b endof                            \ ESC 
+	 2a of 08 endof                            \ Backsace 
+	 2b of 09 endof                            \ Tab
+ 	 2c of 20 endof                            \ Space
+ 	 2d of [char] - endof 
+ 	 2e of [char] = endof 
+ 	 2f of [char] [ endof 
+ 	 30 of [char] ] endof 
+ 	 31 of [char] \ endof 
+ 	 33 of [char] ; endof 
+	 34 of [char] ' endof 
+	 35 of [char] ` endof 
+	 36 of [char] , endof 
+	 37 of [char] . endof 
+	 38 of [char] / endof
+	 39 of led-state CapsLk xor set-led false endof  \ CapsLk
+	 3a of 1b 7e31315b to multi-key endof      \ F1
+	 3b of 1b 7e32315b to multi-key endof      \ F2
+	 3c of 1b 7e33315b to multi-key endof      \ F3
+	 3d of 1b 7e34315b to multi-key endof      \ F4
+	 3e of 1b 7e35315b to multi-key endof      \ F5
+	 3f of 1b 7e37315b to multi-key endof      \ F6
+	 40 of 1b 7e38315b to multi-key endof      \ F7
+	 41 of 1b 7e39315b to multi-key endof      \ F8
+	 42 of 1b 7e30315b to multi-key endof      \ F9
+	 43 of 1b 7e31315b to multi-key endof      \ F10
+	 44 of 1b 7e33315b to multi-key endof      \ F11
+	 45 of 1b 7e34315b to multi-key endof      \ F12
+	 47 of led-state ScrLk xor set-led false endof   \ ScrLk
+	 49 of 1b 7e315b to multi-key endof        \ Ins
+	 4a of 1b 7e325b to multi-key endof        \ Home
+	 4b of 1b 7e335b to multi-key endof        \ PgUp
+	 4c of 1b 7e345b to multi-key endof        \ Del
+	 4d of 1b 7e355b to multi-key endof        \ End
+	 4e of 1b 7e365b to multi-key endof        \ PgDn
+	 4f of 1b 435b to multi-key endof          \ R-arrow
+	 50 of 1b 445b to multi-key endof          \ L-arrow
+	 51 of 1b 425b to multi-key endof          \ D-arrow
+	 52 of 1b 415b to multi-key endof          \ U-arrow
+	 53 of led-state NumLk xor set-led false endof   \ NumLk
+	 54 of [char] / endof                      \ keypad / 
+	 55 of [char] * endof                      \ keypad *
+	 56 of [char] - endof                      \ keypad -
+	 57 of [char] + endof                      \ keypad +
+	 58 of 0d endof                            \ keypad Enter
+	 89 of [char] \ endof	                   \ japanese yen
+	 dup of false endof                        \ other keys are false
+     endcase
+     to ret                                        \ store char
+     led-state CapsLk and 0 <> if                  \ if CapsLk is on
+	 scancode 03 > if                          \ from a to z ?
+	     scancode 1e < if
+		 ret 20 - to ret                   \ to Upper case
+	     then
+	 then
+     then
+     is-shift if                                   \ if shift is on
+	 scancode 03 > if                          \ from a to z ?
+	     scancode 1e < if
+		 ret 20 - to ret                   \ to Upper case
+	     else
+		 scancode
+		 case                              \ translate scan code --> char
+		     1e of [char] ! endof
+		     1f of [char] @ endof
+		     20 of [char] # endof
+		     21 of [char] $ endof
+		     22 of [char] % endof
+		     23 of [char] ^ endof
+		     24 of [char] & endof
+		     25 of [char] * endof
+		     26 of [char] ( endof
+		     27 of [char] ) endof
+		     2d of [char] _ endof
+		     2e of [char] + endof
+		     2f of [char] { endof
+		     30 of [char] } endof
+		     31 of [char] | endof
+		     33 of [char] : endof
+		     34 of [char] " endof
+		     35 of [char] ~ endof
+		     36 of [char] < endof
+		     37 of [char] > endof
+		     38 of [char] ? endof
+		     dup of ret endof              \ other keys are no change
+		 endcase
+		 to ret                            \ overwrite new char    
+	     then
+	 then
+     then
+     led-state NumLk and 0 <> if                   \ if NumLk is on
+       scancode 
+       case                                        \ translate scan code --> char
+	 59 of [char] 1 endof
+	 5a of [char] 2 endof
+	 5b of [char] 3 endof
+	 5c of [char] 4 endof
+	 5d of [char] 5 endof
+	 5e of [char] 6 endof
+	 5f of [char] 7 endof
+	 60 of [char] 8 endof
+	 61 of [char] 9 endof
+	 62 of [char] 0 endof
+	 63 of [char] . endof                      \ keypad .
+	 dup of ret endof                          \ other keys are no change
+       endcase
+       to ret                                      \ overwirte new char
+     then
+     ret                                           \ return char
+;
+
+: key-available? ( -- true|false )
+   multi-key 0 <> IF 
+      true \ multi scan code key was pressed... so key is available
+      EXIT \ done
+   THEN
+   kbd-scan 0 = IF \ if no kbd-scan code is currently available 
+      int-get-report \ check for one using int-get-report 
+   THEN
+   kbd-scan 0 <> \ if a kbd-scan is available, report true, else false
+;
+
+: usb-kread ( -- char|false )                            \ usb key read for control transfer
+    multi-key 0 <> if                                    \ if multi scan code key is pressed
+	multi-key ff and                                 \ read one byte from buffer
+	multi-key 8 rshift to multi-key                  \ move to next byte 
+    else                                                 \ normal key check
+    \ check for new scan code only, if kbd-scan is not set, e.g.
+    \ by a previous call to key-available?
+   kbd-scan 0 = IF
+	\ if interrupt transfer
+	int-get-report                                   \ read report (interrupt transfer)
+	\ else control transfer
+	\ ctl-get-report                                 \ read report (control transfer)
+	\ end of interrupt/control switch
+   THEN
+ 	kbd-scan 0 <> if                                 \ scan code exist?
+	    begin kbd-scan ff and dup 00 = while         \ get a last scancode in report buffer
+		    kbd-scan 8 rshift to kbd-scan        \ This algorithm is wrong --> must be fixed!
+		    drop                                 \ KBD doesn't set scancode in pressed order!!!
+	    repeat
+	    dup key-old <> if                            \ if the scancode is new
+	    	dup to key-old                           \ save current scan code
+	    	get-ukbd-char                            \ translate scan code --> char
+	    	milliseconds fa + to expire-ms           \ set typematic delay 250ms	    
+	    else                                         \ scan code is not changed
+	    	milliseconds expire-ms > if              \ if timer is expired ... should be considered timer carry over
+	    	    get-ukbd-char                        \ translate scan code --> char
+	    	    milliseconds 21 + to expire-ms       \ set typematic rate 30cps
+	    	else                                     \ timer is not expired 
+	    	    drop false                           \ do nothing
+	    	then
+	    then
+       kbd-scan 8 rshift to kbd-scan \ handled scan-code
+ 	else
+	    0 to key-old                                 \ clear privious key
+	    false                                        \ no scan code --> return false
+ 	then
+    then
+;
+
+
+: key-read ( -- char )
+    0 begin drop usb-kread dup 0 <> until                \ read key input (Interrupt transfer)
+;
+
+
+: read ( addr len -- actual )
+   0= IF drop 0 EXIT THEN
+   usb-kread ?dup  IF  swap c! 1  ELSE  0 swap c! -2  THEN
+;
+
+
+kbd-init                                                 \ keyboard initialize
+milliseconds to expire-ms                                \ Timer initialize
+0 to multi-key                                           \ multi key buffer clear
+7 set-led                                                \ flash leds
+250 ms
+0 set-led
+
+s" keyboard" get-node node>path set-alias
+
+: open ( -- true )
+   7 set-led
+   100 ms
+   3 set-led
+   100 ms
+   1 set-led
+   100 ms
+   \ read once from keyboard before actually using it
+   usb-kread drop
+   0 set-led
+   true
+;
+
+: close ;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-mouse.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-mouse.fs
new file mode 100644
index 0000000..bd6fa50
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-mouse.fs
@@ -0,0 +1,28 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" mouse" device-name
+s" mouse" device-type
+
+."   USB Mouse" cr
+
+1 encode-int s" configuration#" property
+2 encode-int s" #buttons" property
+4 encode-int s" assigned-addresses" property
+2 encode-int s" reg" property
+
+: open true ;
+: close ;
+: get-event ( msec -- pos.x pos.y buttons true|false )
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-ohci.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-ohci.fs
new file mode 100644
index 0000000..f4d9670
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-ohci.fs
@@ -0,0 +1,1190 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ We expect to base address of the OHCI controller on the stack:
+
+CONSTANT baseaddrs
+
+s" OHCI base address = " baseaddrs usb-debug-print-val
+
+
+\ Open Firmware Properties
+
+
+s" usb" 2dup device-name device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+
+\ converts physical address to text unit string
+
+
+: encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ;
+
+
+\ Converts text unit string to phyical address
+
+
+: decode-unit ( addr len -- port ) 1 hex-decode-unit ;
+
+
+\  Data Structure Definitions
+\ OHCI Task Descriptor Structure.
+
+
+STRUCT
+   /l field td>tattr
+   /l field td>cbptr
+   /l field td>ntd
+   /l field td>bfrend
+CONSTANT /tdlen
+
+
+\ OHCI Endpoint Descriptor Structure.
+
+
+STRUCT
+   /l field ed>eattr
+   /l field ed>tdqtp
+   /l field ed>tdqhp
+   /l field ed>ned
+CONSTANT /edlen
+
+
+\ HCCA Done queue location packaged as a structure for ease OF use.
+
+
+STRUCT
+   /l field hc>hcattr
+   /l field hc>hcdone
+CONSTANT /hclen
+
+
+\ OHCI Memory Mapped Registers
+
+
+\ : get-base-address ( -- baseaddr )
+\    s" assigned-addresses" get-my-property  IF
+\       s" not possible"  usb-debug-print
+\       -1
+\    ELSE                  ( addr len )
+\       decode-int drop    ( addr len )
+\       decode-int drop    ( addr len )
+\       decode-int nip nip ( n )
+\    THEN
+\    \ TODO: Use translate-address here
+\ ;
+
+\ get-base-address CONSTANT baseaddrs
+
+baseaddrs      CONSTANT HcRevision
+baseaddrs 4  + CONSTANT hccontrol
+baseaddrs 8  + CONSTANT hccomstat
+baseaddrs 0c + CONSTANT hcintstat
+baseaddrs 14 + CONSTANT hcintdsbl
+baseaddrs 18 + CONSTANT hchccareg
+baseaddrs 20 + CONSTANT hcctrhead
+baseaddrs 24 + CONSTANT hccurcont
+baseaddrs 28 + CONSTANT hcbulkhead
+baseaddrs 2c + CONSTANT hccurbulk
+baseaddrs 30 + CONSTANT hcdnehead
+baseaddrs 34 + CONSTANT hcintrval
+baseaddrs 40 + CONSTANT HcPeriodicStart
+baseaddrs 48 + CONSTANT hcrhdescA
+baseaddrs 4c + CONSTANT hcrhdescB
+baseaddrs 50 + CONSTANT HcRhStatus
+baseaddrs 54 + CONSTANT hcrhpstat
+baseaddrs 58 + CONSTANT hcrhpstat2
+baseaddrs 5c + CONSTANT hcrhpstat3
+
+usb-debug-flag IF
+    0 config-l@ ."    - VENDOR: " 8 .r cr
+   40 config-l@ ."    - PMC   : " 8 .r
+   44 config-l@ ."      PMCSR : " 8 .r cr
+   E0 config-l@ ."    - EXT1  : " 8 .r
+   E4 config-l@ ."      EXT2  : " 8 .r cr
+THEN
+
+\ Constants for INTSTAT register
+
+2 CONSTANT WDH
+
+\ Constants for RH Port Status Register
+
+1      CONSTANT RHP-CCS    \ Current Connect Status
+2      CONSTANT RHP-PES    \ Port Enable Status
+10     CONSTANT RHP-PRS    \ Port Reset Status
+100    CONSTANT RHP-PPS    \ Port Power Status
+10000  CONSTANT RHP-CSC    \ Connect Status Changed
+100000 CONSTANT RHP-PRSC   \ Port Reset Status Changed
+
+
+\ Constants for OHCI
+
+0 CONSTANT OHCI-DP-SETUP
+1 CONSTANT OHCI-DP-OUT
+2 CONSTANT OHCI-DP-IN
+3 CONSTANT OHCI-DP-INVALID
+
+\ 8-byte Standard Device Requests + Hub class specific requests.
+
+8006000100001200 CONSTANT get-ddescp
+8006000200000900 CONSTANT get-cdescp
+8006000400000900 CONSTANT get-idescp
+8006000500000700 CONSTANT get-edescp
+A006000000001000 CONSTANT get-hdescp
+0009010000000000 CONSTANT set-cdescp
+2303010004000000 CONSTANT hpenable-set
+2303040001000000 CONSTANT hp1rst-set
+2303040002000000 CONSTANT hp2rst-set
+2303040003000000 CONSTANT hp3rst-set
+2303040004000000 CONSTANT hp4rst-set
+2303080001000000 CONSTANT hp1pwr-set
+2303080002000000 CONSTANT hp2pwr-set
+2303080003000000 CONSTANT hp3pwr-set
+2303080004000000 CONSTANT hp4pwr-set
+A003000000000400 CONSTANT hstatus-get
+A300000001000400 CONSTANT hp1sta-get
+A300000002000400 CONSTANT hp2sta-get
+A300000003000400 CONSTANT hp3sta-get
+A300000004000400 CONSTANT hp4sta-get
+8008000000000100 CONSTANT get-config
+
+A1FE000000000100 CONSTANT GET-MAX-LUN
+
+2    18 lshift CONSTANT DATA0-TOGGLE
+3    18 lshift CONSTANT DATA1-TOGGLE
+0f   1c lshift CONSTANT CC-FRESH-TD
+8 CONSTANT STD-REQUEST-SETUP-SIZE
+0    13 lshift CONSTANT TD-DP-SETUP
+1    13 lshift CONSTANT TD-DP-OUT
+2    13 lshift CONSTANT TD-DP-IN
+
+400001    CONSTANT ed-cntatr
+400002    CONSTANT ed-cntatr1
+80081     CONSTANT ed-hubatr
+80000     CONSTANT ed-defatr
+0f0e40000 CONSTANT td-attr
+00 VALUE ptr
+
+
+\ TD Management constants and Data structures.
+
+
+200 CONSTANT MAX-TDS
+0 VALUE td-freelist-head
+0 VALUE td-freelist-tail
+0 VALUE num-free-tds
+0 VALUE max-rh-ports
+0 VALUE current-stat
+
+INSTANCE VARIABLE td-list-region
+
+\ ED Management constants
+
+
+14 CONSTANT MAX-EDS
+0 VALUE ed-freelist-head
+0 VALUE num-free-eds
+INSTANCE VARIABLE ed-list-region
+0 VALUE usb-address
+0 VALUE initial-hub-address
+0 VALUE new-device-address
+0 VALUE mps
+0 VALUE DEBUG-TDS
+0 VALUE case-failed  \ available for general use to see IF a CASE statement
+                     \ failed or not.
+0 VALUE WHILE-failed \ available for general use to see IF a WHILE LOOP
+                     \ failed in the middle. Used to break from the
+                     \ WHILE LOOP
+
+8 CONSTANT DEFAULT-CONTROL-MPS
+12 CONSTANT DEVICE-DESCRIPTOR-LEN
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET
+4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET
+7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET
+
+20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN
+
+9 CONSTANT HUB-DEVICE-CLASS
+0 CONSTANT NO-CLASS
+
+VARIABLE  setup-packet     \ 8 bytes for setup packet
+VARIABLE  ch-buffer        \ 1 byte character buffer
+
+INSTANCE VARIABLE dd-buffer
+INSTANCE VARIABLE cd-buffer
+
+
+\ Temporary variables for functions. These variables have to be initialized
+\ before usage in functions and their values assume significance only during
+\ the function's execution time. Should be used like local variables.
+\ CAUTION:
+\ If you are calling functions that destroy contents OF these variables, be
+\ smart enuf to save the values before calling them.
+\ It is recommended that these temporary variables are used only amidst normal
+\ FORTH words -- not among the vicinity OF any OF the functions OF this node.
+
+
+0 VALUE temp1
+0 VALUE temp2
+0 VALUE temp3
+0 VALUE extra-bytes
+0 VALUE num-td
+0 VALUE current
+
+0 VALUE device-speed
+
+
+\ Debug functions for displaying ED, TD and their combo list.
+
+: Show-OHCI-Register
+   ." -> OHCI-Register: " cr
+   ." - HcControl : " hccontrol       rl at -le 8 .r
+   ."   CmdStat   : " hccomstat       rl at -le 8 .r
+   ."   HcInterr. : " hcintstat       rl at -le 8 .r cr
+
+   ." - HcFmIntval: " hcintrval       rl at -le 8 .r
+   ."   Per. Start: " HcPeriodicStart rl at -le 8 .r cr
+
+   ." - PortStat-1: " hcrhpstat       rl at -le 8 .r
+   ."   PortStat-2: " hcrhpstat2      rl at -le 8 .r
+   ."   PortStat-3: " hcrhpstat3      rl at -le 8 .r cr
+
+   ."   Descr-A   : " hcrhdescA       rl at -le 8 .r
+   ."   Descr-B   : " hcrhdescB       rl at -le 8 .r
+   ."   HcRhStat  : " HcRhStatus      rl at -le 8 .r cr
+;
+
+: display-ed ( ED-ADDRESS -- )
+   TO temp1
+   usb-debug-flag IF
+      s" Dump OF ED " type temp1 u. cr
+      s" eattr    : " type temp1 ed>eattr l at -le u. cr
+      s" tdqhp    : " type temp1 ed>tdqhp l at -le u. cr
+      s" tdqtp    : " type temp1 ed>tdqtp l at -le u. cr
+      s" ned      : " type temp1 ed>ned   l at -le u. cr
+   THEN
+;
+
+
+\ Displays the transfer descriptors
+
+: display-td ( TD-ADDRESS -- )
+   TO temp1
+   usb-debug-flag IF
+      s" TD " type temp1 u. s" dump: " type cr
+      s" td>tattr  : " type temp1 td>tattr l at -le u. cr
+      s" td>cbptr  : " type temp1 td>cbptr l at -le u. cr
+      s" td>ntd    : " type temp1 td>ntd l at -le u. cr
+      s" td>bfrend : " type temp1 td>bfrend l at -le u. cr
+   THEN
+;
+
+
+\ display's the descriptors
+
+
+: display-descriptors ( ED-ADDRESS -- )
+   10  1- not and             ( ED-ADDRESS~ )
+   dup display-ed ed>tdqhp l at -le  BEGIN ( ED-ADDRESS~ )
+      10  1- not and         ( ED-ADDRESS~ )
+      dup 0<>                ( ED-ADDRESS~ TRUE | FALSE )
+   WHILE
+      dup  display-td td>ntd l at -le ( ED-ADDRESS~ )
+   REPEAT
+   drop
+;
+
+
+\ ---------------------------------------------------------------------------
+\                   	TD LIST MANAGEMENT WORDS
+\                       ------------------------
+\        The following are WORDS internal to this node. They are supposed to
+\        be used by other WORDS inside this device node.
+\        The first three WORDS below form the interface. The fourth and fifth
+\        word is a helper function and is not exposed to other portions OF this
+\        device node.
+\        a) initialize-td-free-list
+\        b) allocate-td-list
+\        c) (free-td-list)
+\        d) find-td-list-tail-and-size
+\        e) zero-out-a-td-except-link
+\ ----------------------------------------------------------------------------
+
+
+: zero-out-a-td-except-link ( td -- )
+
+
+   \ There r definitely smarter ways to DO it especially
+   \ on a 64-bit machine.
+
+   \ Optimization, Portability:
+   \ --------------------------
+   \ Replace the following code by two "!" OF zeroes. Since
+   \ we know that an "td" is actually 16 bytes and that we
+   \ will be executing on a 64-bit machine, we can finish OFf
+   \ with 2 stores.  But that WONT be portable.
+
+
+   dup 0 swap td>tattr  l!-le		( td )
+   dup 0 swap td>cbptr  l!-le		( td )
+   dup 0 swap td>bfrend l!-le		( td )
+   drop
+;
+
+
+\ COLON DEFINITION: initialize-td-free-list - Internal Function
+
+\ Initialize the TD Free List Region and create a linked list OF successive
+\ TDs. Note that the NEXT pointers are all in little-endian and they
+\ can be directly used for HC purposes.
+
+
+: initialize-td-free-list ( -- )
+   MAX-TDS 0= IF EXIT THEN
+   td-list-region @ 0= IF EXIT THEN
+   td-list-region @ TO temp1
+   0 TO temp2  BEGIN
+      temp1 zero-out-a-td-except-link
+      temp1 /tdlen + dup   temp1 td>ntd   l!-le TO temp1
+      temp2 1+ TO temp2
+      temp2 MAX-TDS = 		( TRUE | FALSE )
+   UNTIL
+   temp1 /tdlen - dup 0 swap td>ntd l!-le TO td-freelist-tail
+   td-list-region @ TO td-freelist-head
+   MAX-TDS TO num-free-tds
+;
+
+
+\ COLON DEFINITION: allocate-td-list -- Internal function
+\ Argument:
+\ The function accepts a non-negative number and allocates
+\ a TD-LIST containing that many TDs. A TD-LIST is a list
+\ OF TDs that are linked by the next-td field. The next-td
+\ field is in little-endian mode so that the TD list can
+\ be directly re-used by the HC.
+\ Return value:
+\ The function returns "head" and "tail" OF the allocated
+\ TD-LIST. If for any reason, the function cannot allocate
+\ the TD-LIST, the function returns 2 NULL pointers in the
+\ stack indicating that the allocation failed.
+
+\ Note that the TD list returned is NULL terminated. i.e
+\ the nextTd field OF the tail is NULL.
+
+
+
+: allocate-td-list ( n -- head tail )
+   dup 0= IF drop 0 0 EXIT THEN 		( 0 0 )
+   dup num-free-tds > IF drop 0 0 EXIT THEN     ( 0 0 )
+   dup num-free-tds = IF			( n )
+      drop td-freelist-head td-freelist-tail	( td-freelist-head td-freelist-tail )
+      0 TO td-freelist-head			( td-freelist-head td-freelist-tail )
+      0 TO td-freelist-tail			( td-freelist-head td-freelist-tail )
+      0 TO num-free-tds				( td-freelist-head td-freelist-tail )
+      EXIT
+   THEN
+
+   \ If we are here THEN we know that the requested number OF TDs is less
+   \ than what we actually have. We need TO traverse the list and find the
+   \ new Head pointer position and THEN update the head pointer accordingly.
+   \ Update num-free-tds
+
+   dup num-free-tds swap - TO num-free-tds	( n )
+
+   \ Traverse through the Free list to identify the element that exists after
+   \ "n" TDs. Use the info to return the head and tail pointer and update
+   \ the new td-list-head
+
+   td-freelist-head 				( n td-list-head )
+   dup TO temp1					( n td-list-head )
+   swap 					( td-list-head n )
+   0 DO						( td-list-head   )
+      temp1 TO temp2				( td-list-head   )
+      temp1 td>ntd l at -le   TO   temp1		( td-list-head   )
+   LOOP						( td-list-head   )
+   temp2 					( td-list-head td-list-tail )
+   dup td>ntd 0 swap l!-le 			( td-list-head td-list-tail )
+   temp1 TO td-freelist-head 			( td-list-head td-list-tail )
+;
+
+
+\ COLON DEFINITION: find-td-list-tail-and-size
+\ This function counts the number OF TD elements
+\ in the given list. It also returns the last tail
+\ TD OF the TD list.
+
+\ ASSUMPTION:
+\ A NULL terminated TD list is assumed. A not-well formed
+\ list can result in in-determinate behaviour.
+
+\ ROOM FOR ENHANCEMENT:
+\ We could arrive at a generic function for counting
+\ list elements to which the next-ptr OFfset can also
+\ be passed as an argument (in this case it is >ntd)
+\ This function can THEN be changed to call the
+\ function with "0 >ntd" as an additional argument
+\ (apart from head and tail)
+
+
+: find-td-list-tail-and-size  ( head -- tail n )
+   TO temp1
+   0 TO temp2
+   0 TO temp3
+   DEBUG-TDS  IF
+      s" BEGIN find-td-list-tail-and-size: "   usb-debug-print
+   THEN
+   BEGIN
+      temp1 0<>					( TRUE|FALSE )
+   WHILE
+      DEBUG-TDS  IF
+         temp1 u. cr
+      THEN
+      temp1 TO temp3
+      temp1 td>ntd l at -le TO temp1
+      temp2 1+ TO temp2
+   REPEAT
+   temp3 temp2					( tail n )
+   DEBUG-TDS  IF
+      s" END find-td-list-tail-and-size"   usb-debug-print
+   THEN
+;
+
+
+\ COLON DEFINITION: (free-td-list)
+
+\ Arguments: (head  --)
+\ The "head" pointer OF the TD-LIST to be freed is passed as
+\ an argument to this function. The function merely adds the list to the
+\ already existing TD-LIST
+
+\ Assumptions:
+\ The function assumes that the TD-LIST passed as argument is a well-formed
+\ list. The function does not DO any check on it.
+\ But since, the "TD-LIST" is generally freed from the DONE-QUEUE which is
+\ a well-formed list, the interface makes much sense.
+
+\ Return values:
+\ Nothing is returned. The arguments passed are popped OFf.
+
+
+: (free-td-list) ( head  -- )
+
+   \ Enhancement:
+   \ We could zero-out-a-td-except-link for the TD list that is being freed.
+   \ This way, we could prevent some nasty repercussions OF bugs (that r yet
+   \ to be discovered). but we can include this enhancement during the testing
+   \ phase.
+
+   dup find-td-list-tail-and-size num-free-tds + TO num-free-tds ( head tail )
+   td-freelist-tail 0=  IF					 ( head tail )
+      dup TO td-freelist-tail					 ( head tail )
+   THEN								 ( head tail )
+   td>ntd td-freelist-head swap l!-le				 ( head )
+   TO td-freelist-head
+;
+
+
+\          END OF TD LIST MANAGEMENT WORDS
+\ 	   ED Management section BEGINs
+\ 	   ----------------------------
+
+
+: zero-out-an-ed-except-link ( ed -- )
+
+   \ There are definitely smarter ways to do it especially
+   \ on a 64-bit machine.
+
+   \ Optimization, Portability:
+   \ --------------------------
+   \ Replace by a  "!" and "l!". we know that an "ed" is
+   \ actually 16 bytes and that we will be executing on
+   \ a 64-bit machine, we can finish OFf with 2 stores.
+   \ But that WONT be portable.
+
+   dup 0 swap ed>eattr  l!-le 		( ed )
+   dup 0 swap ed>tdqtp  l!-le		( ed )
+   dup 0 swap ed>tdqhp  l!-le		( ed )
+   drop
+;
+
+\ Intialises ed-list afresh
+
+: initialize-ed-free-list ( -- )
+   MAX-EDS 0= IF EXIT THEN
+   ed-list-region @ 0= IF
+      s" init-ed-list: ed-list-region is not allocated!"   usb-debug-print
+      EXIT
+   THEN
+   ed-list-region @ TO temp1
+   0 TO temp2   BEGIN
+      temp1 zero-out-an-ed-except-link
+      temp1 /edlen + dup   temp1 ed>ned   l!-le TO temp1
+      temp2 1+ TO temp2
+      temp2 MAX-EDS =
+   UNTIL
+   temp1 /edlen - ed>ned 0 swap l!-le
+   ed-list-region @ TO ed-freelist-head
+   MAX-EDS TO num-free-eds
+;
+
+
+\ allocate an ed and return ed address
+
+
+: allocate-ed	( -- ed-ptr )
+   num-free-eds 0= IF 0 EXIT THEN
+   ed-freelist-head					( ed-freelist-head )
+   ed-freelist-head ed>ned l at -le TO ed-freelist-head	( ed-freelist-head )
+   num-free-eds 1- TO num-free-eds			( ed-freelist-head )
+   dup ed>ned 0 swap l!-le \ Terminate the Link.	( ed-freelist-head )
+;
+
+
+\ free the given ed pointer
+
+: free-ed ( ed-ptr  -- )
+   dup zero-out-an-ed-except-link			( ed-ptr )
+   dup ed>ned ed-freelist-head swap l!-le 		( ed-ptr )
+   TO ed-freelist-head
+   num-free-eds 1+ TO num-free-eds
+;
+
+
+\ Buffer allocations
+\ ------------------
+\ Note:
+\ -----
+\ 1. What should we DO IF alloc-mem fails ?
+\ 2. alloc-mem must return aligned memory addresses.
+\ 3. alloc-mem must return DMAable memory!
+
+\ Memory for the HCCA - must stay allocated as long as the HC is operational!
+100 alloc-mem VALUE hchcca
+hchcca ff and IF
+   \ This should never happen - alloc-mem always aligns
+   s" Warning: hchcca not aligned!" usb-debug-print
+THEN
+
+84 hchcca + CONSTANT hchccadneq
+
+
+: (allocate-mem)  ( -- )
+   /tdlen MAX-TDS * 10 + alloc-mem dup td-list-region !  ( td-list-region-ptr )
+   f and IF
+      s" Warning: td-list-region not aligned!" usb-debug-print
+   THEN
+   initialize-td-free-list
+
+   /edlen MAX-EDS * 10 + alloc-mem dup ed-list-region !  ( ed-list-region-ptr )
+   f and IF
+      s" Warning: ed-list-region not aligned!" usb-debug-print
+   THEN
+   initialize-ed-free-list
+
+   DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer !
+   BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer !
+;
+
+
+\ The method makes sure that when the host node is closed all
+\ associated buffer allocations made for data-structures as
+\ well as data-buffers are freed
+
+: (de-allocate-mem)  ( -- )
+   td-list-region @ ?dup IF
+      /tdlen MAX-TDS * 10 + free-mem
+      0 td-list-region !
+   THEN
+   ed-list-region @ ?dup IF
+      /edlen MAX-EDS * 10 + free-mem
+      0 ed-list-region !
+   THEN
+   dd-buffer @ ?dup IF
+      DEVICE-DESCRIPTOR-LEN free-mem
+      0 dd-buffer !
+   THEN
+   cd-buffer @ ?dup IF
+      BULK-CONFIG-DESCRIPTOR-LEN free-mem
+      0 cd-buffer !
+   THEN
+;
+
+
+\ Suspend hostcontroller (and the bus).
+\ This method must be called before the operating system starts.
+\ It prevents the HC from doing DMA in the background during boot
+\ (e.g. updating its frame number counter in the HCCA)
+
+: hc-suspend  ( -- )
+   \ s" USB HC suspend with hccontrol=" type hccontrol . cr
+   00C3 hccontrol rl!-le             \ Suspend USB host controller
+;
+
+
+\ OF methods
+
+: open  ( -- TRUE|FALSE )
+   (allocate-mem)
+   TRUE
+;
+
+: close  ( -- )
+   (de-allocate-mem)
+;
+
+
+\ COLON DEFINITION: HC-enable-control-list-processing
+\ Enables USB HC transactions on control list.
+
+: HC-enable-control-list-processing ( -- )
+   hccomstat dup rl at -le 02 or swap rl!-le
+   hccontrol dup rl at -le 10 or swap rl!-le
+;
+
+
+\ COLON DEFINTION: HC-enable-bulk-list-processing
+\ PENDING: Remove Hard coded constants.
+
+: HC-enable-bulk-list-processing ( -- )
+   hccomstat dup rl at -le 04 or swap rl!-le
+   hccontrol dup rl at -le 20 or swap rl!-le
+;
+
+
+: HC-enable-interrupt-list-processing ( -- )
+   hccontrol dup rl at -le 04 or swap rl!-le
+;
+
+
+\ Clearing WDH to allow HC to write into DOne queue again
+
+: (HC-ACK-WDH) ( -- )   WDH hcintstat rl!-le ;
+
+\ Checking whether anything has been written into DOne queue
+
+: (HC-CHECK-WDH) ( -- ) hcintstat rl at -le WDH and 0<> ;
+
+
+\ Disable USB transaction and keep it ready
+
+: disable-control-list-processing ( -- )
+   hccontrol dup rl at -le ffffffef and swap rl!-le
+   hccomstat dup rl at -le fffffffd and swap rl!-le
+;
+
+: disable-bulk-list-processing ( -- )
+   hccontrol dup rl at -le ffffffdf and swap rl!-le
+   hccomstat dup rl at -le fffffffb and swap rl!-le
+;
+
+
+: disable-interrupt-list-processing ( -- )
+   hccontrol dup rl at -le fffffffb and swap rl!-le
+;
+
+
+\ COLON DEFINITION: fill-TD-list
+
+\ This function accepts a TD list and a data-buffer and
+\ distributes this data buffer over the TD list depending
+\ on the Max Packet Size.
+
+\ Arguments:
+\ ----------
+\ (from bottom OF stack)
+\ 1. addr -- Address OF the data buffer
+\ 2. dlen -- Length OF the data buffer above.
+\ 3. dir  -- Tells whether the TDs r for an IN or
+\            OUT transaction.
+\ 4. MPS  -- Maximum Packet Size associated with the endpoint
+\            that will use this TD list.
+\ 5. TD-List-Head - Head pointer OF the List OF TDs.
+\            This list is NOT expected to be NULL terminated.
+
+\ Assumptions:
+\ -----------
+\ 1. TD-List for data is well-formed and has sufficient entries
+\    to hold "dlen".
+\ 2. The TDs toggle field is assumed to be taken from the endpoint
+\    descriptor's "toggle carry" field.
+\ 3. Assumes that the caller specifies the correct start-toggle.
+\    If the caller specifies a wrong data toggle OF 1 for a SETUP
+\    PACKET, this method will not find it out.
+
+\ COLON DEFINTION: (toggle-current-toggle)
+\ Scope: Internal to fill-TD-list
+\ Functionality:
+\        Toggles the "T" field that is passed as argument.
+\        "T" as in the "T" field OF the TD.
+
+0 VALUE current-toggle
+: fill-TD-list ( start-toggle addr dlen dp MPS TD-List-Head -- )
+   TO temp1 				( start-toggle addr dlen dp MPS )
+   TO temp2 				( start-toggle addr dlen dp )
+   CASE					( start-toggle addr dlen )
+      OHCI-DP-SETUP  OF  TD-DP-SETUP TO temp3 ENDOF ( start-toggle addr dlen )
+      OHCI-DP-IN     OF  TD-DP-IN    TO temp3 ENDOF ( start-toggle addr dlen )
+      OHCI-DP-OUT    OF  TD-DP-OUT   TO temp3 ENDOF ( start-toggle addr dlen )
+      dup            OF  -1          TO temp3       ( start-toggle addr dlen )
+      s" fill-TD-list: Invalid DP specified"   usb-debug-print
+                                                  ENDOF
+   ENDCASE
+   temp3 -1 = IF EXIT THEN                          ( start-toggle addr dlen )
+
+
+\ temp1 -- TD-List-Head
+\ temp2 -- Max Packet Size
+\ temp3 -- TD-DP-IN or TD-DP-OUT or TD-DP-SETUP
+
+   rot                                              ( addr dlen start-toggle )
+   TO current-toggle swap 			    ( dlen addr )
+   BEGIN
+      over temp2 >= 				    ( dlen addr TRUE|FALSE )
+   WHILE					    ( dlen addr )
+      dup temp1 td>cbptr l!-le			    ( dlen addr )
+      current-toggle 18 lshift                      ( dlen addr current-toggle~ )
+      DATA0-TOGGLE                        ( dlen  addr current-toggle~ toggle )
+      CC-FRESH-TD temp3 or or or          ( dlen  addr or-result )
+      temp1 td>tattr l!-le                ( dlen addr~  )
+      dup temp2 1- + temp1 td>bfrend l!-le ( dlen addr~  )
+      temp2 +                             ( dlen next-addr )
+      swap temp2 - swap
+      temp1 td>ntd l at -le TO temp1         ( dlen next-addr )
+      current-toggle                      ( dlen next-addr current-toggle )
+      CASE
+         0 OF 1 TO current-toggle ENDOF
+         1 OF 0 TO current-toggle ENDOF
+      ENDCASE
+   REPEAT                                   ( dlen addr )
+   over 0<>  IF
+      dup temp1 td>cbptr l!-le              ( dlen addr )
+      current-toggle 18 lshift              ( dlen addr curent-toggle~ )
+      DATA0-TOGGLE                          ( dlen addr curent-toggle~ toggle )
+      CC-FRESH-TD temp3 or or or            ( dlen addr or-result )
+      temp1 td>tattr l!-le                  ( dlen addr )
+      + 1- temp1 td>bfrend l!-le
+   ELSE
+      2drop
+   THEN
+;
+
+
+\ COLON DEFINITION: (td-list-status )
+\ FUNCTIONALITY:
+\ To traverse the TD list to check for a TD carrying non-zero CC return the
+\ respective TD address and CC ELSE 0
+\ SCOPE:
+\ Internal method
+
+: (td-list-status) ( PointerToTDlist -- failingTD CCode TRUE | 0 )
+   BEGIN 	 ( PointerToTDlist )
+      dup 0<>	 ( PointerToTDlist TRUE|FALSE )
+   IF 		 ( PointerToTDlist )
+      dup td>tattr l at -le f0000000 and 1c rshift dup 0= TRUE swap
+       ( PointerToTDlist CCode TRUE TRUE|FALSE )
+   ELSE
+      drop FALSE dup ( FALSE )
+   THEN
+   WHILE
+      drop drop td>ntd l at -le
+   REPEAT
+;
+
+
+\ ==================================================================
+\ COLON DEFINITION: (wait-for-done-q)
+\ FUNCTIONALITY:
+\ To DO a timed polling OF the DOne queue and acknowledge and return
+\ the address OF the last retired Td list
+\ SCOPE:
+\ Internal method
+\ ==================================================================
+
+: (wait-for-done-q)           ( timeout -- TD-list TRUE | FALSE )
+   BEGIN                      ( timeout )
+      dup 0<>                 ( timeout TRUE|FALSE )
+      (HC-CHECK-WDH) NOT      ( timeout TRUE|FALSE TRUE|FALSE )
+      AND                     \ not timed out AND WDH-bit not set
+      WHILE
+      1 ms                    \ wait
+      1-                      ( timeout )
+      dup ff and 0= IF show-proceed THEN
+   REPEAT	                  ( timeout )
+   drop
+   hchccadneq  l at -le          \ read last HcDoneHead (RAM)
+   (HC-CHECK-WDH)             \ HcDoneHead was updated ?
+   IF
+      (HC-ACK-WDH)	         \ clear register bit: WDH
+      TRUE                    ( td-list TRUE )
+   ELSE
+      FALSE
+   THEN
+;
+
+
+\ displays free tds
+
+
+: debug-td ( -- )
+   s" Num Free TDs = " num-free-tds usb-debug-print-val
+;
+
+
+\ display content of frame counter
+
+\ : debug-frame-counter ( -- )
+\   40 1 DO
+\      ." Frame ct at HCCA at end OF enumeration = "
+\      hchcca 80 + rl at -le .
+\   LOOP
+\ ;
+
+\ ============================================================================
+\ COLON DEFINITION: HC-reset
+\ This routine should be the first to be executed.
+\ This routine will reset the HC and will bring it to Operational
+\ state.
+\ PENDING:
+\ Arrive at the right value OF FrameInterval. Currently we are hardcoding
+\ it.
+\ ==========================================================================
+: HC-reset ( -- )
+
+   hccomstat dup rl at -le 01 or swap rl!-le    \ issue HC reset
+   BEGIN
+      hccomstat rl at -le 01 and 0<>            \ wait for reset end
+      WHILE
+   REPEAT
+
+   23f02edf hcintrval rl!-le                 \ frame-interval register
+   hchcca   hchccareg rl!-le                 \ HC communication area
+   0000     hcctrhead rl!-le                 \ control transfer head
+   0000     hcbulkhead rl!-le                \ bulk transfer head
+   0ffff    hcintdsbl rl!-le                 \ interrupt disable reg.
+
+\ all devices are still in reset-state
+\ next command starts sending SOFs
+   83       hccontrol rl!-le                 \ set USBOPERATIONAL
+
+\ these two repeated register settings are necessary for Bimini
+\ Its OHCI controller (AM8111) behaves different to NEC's one
+   23f02edf hcintrval rl!-le                 \ frame-interval register
+   hchcca   hchccareg rl!-le                 \ HC communication area
+   
+   d# 50 ms
+
+   hcrhdescA rl at -le ff and     ( total-rh-ports )
+   to max-rh-ports
+
+\ if no hardware-reset was issued (rescan)
+\ switch off all ports first !
+   hcrhpstat TO current-stat              \ start with first port status reg
+   0                                      \ port status default
+   max-rh-ports 0                         \ checking all ports
+   DO
+      current-stat rl at -le or              \ OR-ing all stats
+      200 current-stat rl!-le             \ Clear Port Power (CPP)
+      current-stat 4 + TO current-stat    \ check next RH-Port
+   LOOP
+   100 and 0<>                            \ any of the ports had power ?
+   IF
+      d# 750 wait-proceed                 \ wait for power discharge
+   THEN
+
+\ now power on all ports of this root-hub
+   hcrhpstat TO current-stat              \ start with first port status reg
+   max-rh-ports 0
+   DO
+      102 current-stat rl!-le             \ power on and enable
+      hcrhdescA 3 + rb@ 2 * ms            \ startup delay 30 ms (2 * POTPGT)
+      current-stat 4 + TO current-stat    \ check next RH-Port
+   LOOP
+   d# 500 wait-proceed                    \ STEC device needs 300 ms
+;
+
+: error-recovery ( -- )
+   initialize-td-free-list
+   initialize-ed-free-list
+   HC-reset
+;
+
+\ ================================================================
+: store-initial-usb-hub-address ( -- )
+    usb-address TO initial-hub-address
+;
+
+: reset-to-initial-usb-hub-address ( -- )
+    initial-hub-address TO usb-address
+;
+
+\ allocate-usb-address:
+\ Function allocates an USB address.
+\ See RISK below.
+
+
+: allocate-usb-address ( -- usb-address )
+   usb-address    7f <>		( TRUE|FALSE )
+   IF
+      usb-address 1+ TO usb-address \ RISK: Check to see IF it overflows 127
+      usb-address		( usb-address )
+   THEN				( usb-address )
+;
+
+s" usb-support.fs" INCLUDED
+
+
+
+\ =====================================================================
+\ COLON DEFINTION: control-std-set-address
+\                  INTERFACE FUNCTION
+\ Function allocates an USB addrss and uses it to send SET-ADDRESS packet
+\ to the default USB address.
+\ This is an interface function available to child nodes.
+
+: control-std-set-address        ( speedbit -- usb-address TRUE | FALSE )
+   >r                                                 ( R: speedbit )
+   0005000000000000 setup-packet !
+   allocate-usb-address dup setup-packet 2 + c!       ( usb-addr  R: speedbit )
+   s" USB set-address: " 2 pick usb-debug-print-val   ( usb-addr  R: speedbit )
+   0 0 0 setup-packet 8 r> controlxfer                ( usb-addr TRUE | FALSE )
+   IF						      ( TRUE | FALSE )
+      TRUE 					      ( TRUE )
+   ELSE
+      drop FALSE \ PENDING: Return the allocated address back. ( FALSE )
+   THEN						      ( TRUE | FALSE )
+;
+
+
+\ Fetches the device decriptor of the usb-device
+
+
+: control-std-get-device-descriptor
+	            ( data-buffer data-len MPS fa -- TRUE|FALSE )
+
+   8006000100000000 setup-packet !
+   2 pick setup-packet 6 + w!-le
+                     ( data-buffer data-len MPS fa )
+   setup-packet -rot ( data-buffer data-len setup-packet MPS fa )
+   >r >r >r >r >r 0 r> r> r> r> r>
+   		     ( 0 data-buffer data-len setup-packet MPS fa )
+   controlxfer	     ( TRUE | FALSE )
+;
+
+
+\ ==================================================================
+\ To retrieve the configuration descriptor OF a device
+\ with a valid USB address
+
+
+: control-std-get-configuration-descriptor
+   ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+   TO temp1 ( data-buffer data-len MPS )
+   TO temp2 ( data-buffer data-len )
+   TO temp3 ( data-buffer )
+   8006000200000000 setup-packet !
+   temp3 setup-packet 6 + w!-le
+   0 swap temp3 setup-packet temp2 temp1 controlxfer
+;
+
+\ Fetches num of logical units available for a device
+: control-std-get-maxlun ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+   GET-MAX-LUN setup-packet !  ( MPS fun-addr dir data-buff data-len )
+   setup-packet 5 pick 5 pick
+   ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr )
+   controlxfer ( MPS fun-addr  TRUE | FALSE )
+   nip nip    ( TRUE | FALSE )
+;
+
+\ Bulk-Only Mass Storage Reset
+\ fixed to interface #0
+: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+   21FF000000000000 setup-packet !  ( MPS fun-addr dir data-buff data-len )
+   setup-packet 5 pick 5 pick
+               ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr )
+   controlxfer ( MPS fun-addr  TRUE | FALSE )
+   nip nip    ( TRUE | FALSE )
+;
+
+
+
+\ get the string descriptor of the usb device
+
+
+: control-std-get-string-descriptor
+   ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE | FALSE )
+   TO temp1  ( StringIndex data-buffer data-len MPS )
+   TO temp2  ( StringIndex data-buffer data-len )
+   TO temp3  ( StringIndex )
+   8006000300000000 setup-packet !
+   temp3 setup-packet 6 + w!-le
+   409 setup-packet 4 + w!-le \ US English Language code.
+   swap      ( data buffer StringIndex )
+   setup-packet 2 + c! ( data-buffer )
+   0 swap temp3 setup-packet temp2 temp1 controlxfer ( TRUE | FALSE )
+;
+
+\ sets a valid usb configaration for a device
+
+: control-std-set-configuration ( configvalue FuncAddr -- TRUE|FALSE )
+   TO temp1                     ( configvalue )
+   TO temp2
+   0009000000000000 setup-packet ! \ RISK: Endian and 64-bit assumptions
+   temp2 setup-packet 2 + w!-le
+   0 0 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer
+
+   \ NOTE: We could use DEFAULT-CONTROL-MPS because there is no data phase
+   \ associated with this control xfer. Its a dont care.
+;
+
+
+\ To set the device address retrive the device descriptor and build the
+\ usb device tree by passing device class
+
+
+0 VALUE port-number
+
+s" usb-enumerate.fs" INCLUDED
+
+: rhport-enumerate ( port-num -- )
+   TO port-number
+   device-speed control-std-set-address        ( usb-addr TRUE | FALSE )
+   IF
+      device-speed or                          ( usb-addr+speedbit )
+      TO new-device-address
+      dd-buffer @ 8 erase
+
+      \ Read Device Descriptor - First 8 bytes.
+
+      dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS      ( buffer mps mps )
+      new-device-address control-std-get-device-descriptor   ( TRUE | FALSE )
+      IF
+      ELSE
+         s" USB: Read Dev Descriptor failed"   usb-debug-print EXIT
+
+         \ NOTE: Tomorrow, IF there is a LOOP here,we may need to UNLOOP before
+         \ "EXIT"ing. Beware. Much depends on what LOOPing construct is used.
+
+      THEN
+
+      \ Read the Descriptor Type and check IF we have read correctly.
+
+      dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@  ( Descriptor-type )
+      DEVICE-DESCRIPTOR-TYPE <> IF
+         s" USB: Error Reading Device Descriptor"   usb-debug-print
+         s" Read descriptor is not OF the right type"  usb-debug-print
+         s" Aborting enumeration"  usb-debug-print
+         EXIT
+         \ NOTE: Tomorrow, IF u have a LOOP here THEN we may need to
+         \ UNLOOP before EXITing. Depends on what type OF LOOPing construct
+         \ is used. Beware.
+
+      THEN
+
+      \ Read the MPS and store it.
+
+      dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ TO mps
+
+      \ NOTE: Probably, we could check MPS for only 8/16/32/64
+      \       hmm.. not now...
+
+      \ Read the device class to see what type OF device it is and create an
+      \ appropriate child node here.
+      create-usb-device-tree
+   ELSE
+      s" Set address failed on port " port-number usb-debug-print-val
+      s" Aborting Enumeration."   usb-debug-print
+      EXIT
+
+      \ NOTE: Tomorrow , IF u have a LOOP here THEN we may need to
+      \ UNLOOP before EXITing. Depends on what type OF LOOPing construct
+      \ is used. Beware.
+
+   THEN
+;
+
+
+\ =========================================================================
+\ PROTOTYPE FUNCTION: "rhport-initialize"
+\ Detect Device, reset and enable the respective port.
+\ COLON Definition rhport-initialize accepts the total number OF root hub
+\ ports as an argument and probes every available root hub port and initiates
+\ the build OF the USB devie sub-tree so is effectively the mother OF all
+\ USB device nodes that are to be detected and instantiated.
+\ ==========================================================================
+: rhport-initialize ( -- )
+
+   hcrhpstat TO current-stat              \ start with first port status reg
+   max-rh-ports 1+ 1
+   DO
+      \ any Device connected to that port ?
+      current-stat rl at -le RHP-CCS and 0<> 	( TRUE|FALSE )
+      IF
+         current-stat hcrhpstat3 =        \ third port of NEC ?
+         IF
+            81 to uDOC-present            \ uDOC is present and now processed
+         THEN
+
+         s" Device connected to this port!" usb-debug-print
+         RHP-PRS current-stat rl!-le      \ issue a port reset
+         BEGIN
+            current-stat rl at -le RHP-PRS AND    \ wait for reset end
+            WHILE
+         REPEAT
+         hcrhdescA 3 + rb@ 2 * ms         \ startup delay 30 ms (POTPGT)
+         d# 100 ms
+
+         current-stat rl at -le 200 and 4 lshift
+         to device-speed                  \ store speed bit
+
+         RHP-CSC RHP-PRSC or current-stat rl!-le
+
+         I ['] rhport-enumerate CATCH IF  \ Scan port
+            s" USB scan failed on root hub port: " rot usb-debug-print-val
+            reset-to-initial-usb-hub-address
+         THEN
+
+      ELSE
+         s" No device detected at this port." usb-debug-print
+         current-stat hcrhpstat3 =        \ third port of NEC ? (=ModFD)
+         IF                               \ here a ModFD should be on ELBA
+            current-stat rl at -le 80000 and 0<> 	\ is over-current detected ?
+            IF
+               uDOC-present 08 or to uDOC-present  \ set flag for uDOC-check
+            THEN
+         THEN
+      THEN
+      current-stat 4 + TO current-stat    \ check next RH-Port
+      uDOC-present 0f and to uDOC-present \ remove processing flag
+   LOOP
+;
+
+
+\ ===================================================
+\ Enumeration at Host level
+\ ===================================================
+
+: enumerate ( -- )
+   HC-reset
+   ['] hc-suspend add-quiesce-xt     \ Assert that HC will be supsended
+   store-initial-usb-hub-address
+   rhport-initialize                 \ Probe all available RH ports
+   reset-to-initial-usb-hub-address
+;
+
+
+\ Create an alias for this controller:
+set-ohci-alias
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-static.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-static.fs
new file mode 100644
index 0000000..8732957
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-static.fs
@@ -0,0 +1,297 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ #include "scsi-support.fs"
+
+\ Set usb-debug flag to TRUE for debugging output:
+0 VALUE usb-debug-flag
+false VALUE scan-time?
+
+VARIABLE ihandle-bulk-tran
+\ -scsi-supp-  VARIABLE ihandle-scsi-tran
+
+\ uDOC (Micro-Disk-On-Chip) is a FLASH-device
+\ normally connected to usb-port 5 on ELBA
+\
+0 VALUE uDOC-present       \ device present and working?
+
+\ Print a debug message when usb-debug-flag is set
+: usb-debug-print  ( str len -- )
+   usb-debug-flag  IF type cr ELSE 2drop THEN
+;
+
+\ Print a debug message with corresponding value when usb-debug-flag is set
+: usb-debug-print-val  ( str len val -- )
+   usb-debug-flag  IF -ROT type . cr ELSE drop 2drop THEN
+;
+
+\ show proceeding propeller only during scan process.
+\ As soon USB-keyboard can be used, this must be suppressed.
+0 VALUE proceed-char
+: show-proceed ( -- )
+   scan-time?              \ are we on usb-scan ?
+   IF
+      proceed-char
+      CASE
+         0   OF 2d ENDOF   \ show '-'
+         1   OF 5c ENDOF   \ show '\'
+         2   OF 7c ENDOF   \ show '|'
+         dup OF 2f ENDOF   \ show '/'
+      ENDCASE
+      emit 8 emit
+      proceed-char 1 + 3 AND to proceed-char
+   THEN
+;
+
+\ delay with proceeding signs
+: wait-proceed ( nl -- )
+   show-proceed
+   BEGIN
+      dup d# 100 >         ( nl true|false )
+      WHILE
+      100 - show-proceed
+      100 ms               \ do it in steps of 100ms
+   REPEAT
+   ms                      \ rest delay
+;
+
+\ register device alias
+: do-alias-setting ( num name-str name-len )
+   rot $cathex strdup            \ create alias name
+   get-node node>path            \ get path string
+   set-alias                     \ and set the alias
+;
+
+
+0 VALUE ohci-alias-num
+
+\ create a new ohci device alias for the current node:
+: set-ohci-alias  ( -- )
+   ohci-alias-num dup 1+ TO ohci-alias-num    ( num )
+   s" ohci"
+   do-alias-setting
+;
+
+0 VALUE cdrom-alias-num
+0 VALUE disk-alias-num        \ shall start with: pci-disk-num
+FALSE VALUE ext-disk-alias    \ first external disk: not yet assigned
+
+\ create a new ohci device alias for the current node:
+: set-drive-alias  ( --  )
+   space 5b emit
+   s" cdrom" drop                ( name-str )
+   get-node node>name comp 0=    ( true|false )
+   IF                            \ is this a cdrom ?
+      cdrom-alias-num dup 1+ TO cdrom-alias-num    ( num )
+      s" cdrom"                  \ yes, alias = cdrom
+   ELSE
+      s" sbc-dev" drop           \ is this a scsi-block-device?
+      get-node node>name comp 0= ( true|false )
+      IF
+         disk-alias-num dup 1 + to disk-alias-num
+         s" disk"                \ all block devices will be named "disk"
+
+         \ this is a block-device.
+         \ check if parent is 'usb' and not 'hub'
+         \ if so this block-device is directly connected
+         \ to root-hub and must be the uDOC-device in Elba
+         s" usb" drop            \ parent = usb controller ? (not hub)
+         get-node node>parent @ node>name
+         comp 0=                 \ parent node starts with 'usb' ?
+         IF                      ( true|false )
+            1 s" hdd"            \ add extra alias hdd1 for IntFlash
+            2dup type 2 pick .
+            8 emit 2f emit
+            do-alias-setting
+            uDOC-present 1 and
+            IF
+               uDOC-present 2 or to uDOC-present \ present and ready
+            THEN
+         ELSE
+            ext-disk-alias not   \ flag for first ext. disk already assigned
+            IF
+               TRUE to ext-disk-alias
+               2 s" hdd"         \ add extra alias hdd2 for first USB disk
+               2dup type 2 pick .
+               8 emit 2f emit
+               do-alias-setting
+            THEN
+         THEN
+      ELSE
+         0 s" ??? "              \ unknown device
+      THEN
+   THEN     ( num name-str name-len )
+   2dup type 2 pick .
+   8 emit 5d emit cr
+   do-alias-setting
+;
+
+: usb-create-alias-name ( num -- str len )
+    >r s" ohciX" 2dup + 1-           ( str len last-char-ptr  R: num )
+    r> [char] 0 + swap c!            ( str len  R: )
+;
+
+
+\ *****************************************************
+\ This is a final check to see, if a uDOC-device
+\ is ready for booting
+\ If physically present, but not working, an
+\ Error-LED must be activated (on ELBA only!)
+\ *****************************************************
+\ uDOC is now replaced by ModFD (Modular-Flash-Drive)
+\ due to right properties
+\ 'sys-signal-modfd-fault' sends an IPMI-Message to
+\ aMM for generating a log entry and to switch on
+\ an error LED (call to libsystem->libipmi)
+\ *****************************************************
+\ although there are IPMI-warnings defined concerning
+\ detected media errors, it doesn't make sense to send
+\ a warning when booting from this device is impossible.
+\ The decision was made to send an error call in this
+\ case as well
+\ *****************************************************
+\ uDOC-present bits:
+\ *****************************************************
+\ D0: any device is connected on port 3 of root-hub
+\ D1: device on port 3 is directly connected (no hub)
+\ D2: warnings were received (scancodes)
+\ D3: OverCurrentIndicator on USB-Port was set
+\ D7: flag, set while ModFD is beeing processed
+
+: uDOC-check   ( -- )
+#ifdef ELBA
+   uDOC-present 7 and               \ flags concerning ModFD device
+   CASE
+      0  OF                         \ not present not detected
+         uDOC-present 8 and 0<>     \ not detected due to OverCurrent?
+         IF
+            0d emit ."   * OverCurrent on ModFD *" cr
+            sys-signal-modfd-fault     ( -- )      \ send IPMI-call to BMC
+         ELSE
+            0d emit ."   ModFD not present" cr
+         THEN
+      ENDOF
+
+      1  OF       \ present but not detected by USB
+         0d emit ."   * ModFD not accessible *" cr
+         sys-signal-modfd-fault     ( -- )      \ send IPMI-call to BMC
+      ENDOF
+
+      3  OF       \ present and detected
+\        0d emit ."   ModFD OK" cr
+      ENDOF
+
+      7  OF       \ present and detected but with warnings
+         0d emit ."   * ModFD Warnings *" cr
+         sys-signal-modfd-fault     ( -- )      \ send IPMI-call to BMC
+      ENDOF
+
+      dup OF      \ we have a fault in our firmware !
+         s"   *** ModFD detection error ***" usb-debug-print
+      ENDOF
+   ENDCASE
+#endif
+;
+
+\ *****************************************************
+\ check if actual processed device is ModFD and
+\ then sets its warning bit
+\ *****************************************************
+: uDOC-failure?   ( -- )
+   uDOC-present 80 and 0<>                \ is ModFD actual beeing processed?
+   IF
+      uDOC-present 04 or to uDOC-present  \ set Warning flag
+   THEN
+;
+
+\ Scan all USB host controllers for attached devices:
+: usb-scan
+   \ Scan all OHCI chips:
+   space ." Scan USB... " cr
+   true to scan-time?            \ show proceeding signs
+   0 to uDOC-present             \ mark as not present
+   0 to disk-alias-num           \ start with disk0
+   s" pci-disk-num" $find        \ previously detected disks ?
+   IF
+      execute to disk-alias-num  \ overwrite start number
+   ELSE
+      2drop
+   THEN
+
+   0 >r                             \ Counter for alias
+   BEGIN
+      r@ usb-create-alias-name
+      find-alias ?dup               ( false | str len len  R: num )
+   WHILE
+      usb-debug-flag IF
+         ." * Scanning hub " 2dup type ." ..." cr
+      THEN
+      open-dev ?dup IF              ( ihandle  R: num )
+         dup to my-self
+         dup ihandle>phandle dup set-node
+          child ?dup IF
+              delete-node s" Deleting node" usb-debug-print
+          THEN
+         >r s" enumerate" r@ $call-method   \ Scan host controller
+         r> close-dev  0 set-node 0 to my-self
+      THEN                          ( R: num )
+      r> 1+ >r                      ( R: num+1 )
+   REPEAT   r> drop
+   0 TO ohci-alias-num
+   0 TO cdrom-alias-num
+   s" cdrom0" find-alias            ( false | dev-path len )
+   dup IF
+       s" cdrom" 2swap              ( alias-name len' dev-path len )
+       set-alias                    ( -- )
+       \ cdrom-alias-num 1 + TO cdrom-alias-num
+   ELSE 
+       drop                         ( -- )
+   THEN
+   uDOC-check  \ check if uDOC-device is present and working (ELBA only)
+   false to scan-time?                 \ suppress proceeding signs
+;
+
+: usb-probe
+
+  usb-scan
+
+  cdrom-alias-num 0= IF
+     ." Not found CDROM! " cr
+  THEN
+     ." CDROM found " cdrom-alias-num . cr 
+;
+
+ 
+: usb-dev-test ( -- TRUE )
+   s" USB Device Test " usb-debug-print
+   1 usb-create-alias-name
+   find-alias ?dup IF
+      ." * open " 2dup type . cr
+   ELSE
+      s" can't found alias " usb-debug-print
+   THEN
+   open-dev ?dup IF
+      dup to my-self
+      dup ihandle>phandle dup set-node
+      s" bulk" $open-package ihandle-bulk-tran !
+\      make-media-ready
+      s" close all " usb-debug-print
+      close-dev 0 set-node 0 to my-self
+
+      ihandle-bulk-tran close-package
+   ELSE
+      s" can't open usb hub" usb-debug-print
+   THEN
+
+   TRUE
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-support.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-support.fs
new file mode 100644
index 0000000..f5033de
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-support.fs
@@ -0,0 +1,155 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ ---------------------------------------------------------------------------
+\ Parent methods
+\ ---------------------------------------------------------------------------
+
+: rw-endpoint
+   ( pt ed-type toggle buffer length mps addres -- toggle TRUE | toggle FALSE )
+   s" rw-endpoint" $call-parent
+   ( toggle TRUE | toggle FALSE )
+;
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun --- TRUE|FALSE )
+   s" controlxfer" $call-parent
+   ( TRUE | FALSE )
+;
+
+: control-std-get-configuration-descriptor
+   ( data-buffer data-len MPS FuncAddr -- TRUE | FALSE )
+   s" control-std-get-configuration-descriptor" $call-parent
+   ( TRUE | FALSE )
+;
+
+: control-std-set-configuration ( configvalue FuncAddr -- TRUE | FALSE )
+   s" control-std-set-configuration" $call-parent   ( TRUE | FALSE )
+;
+
+: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- )
+  s" bulk-reset-recovery-procedure" $call-parent
+;
+
+
+\ ---------------------------------------------------------------------------
+\ Bulk support package methods
+\ ---------------------------------------------------------------------------
+
+: build-cbw ( address tag transfer-len direction lun command-len -- )
+   s" build-cbw" ihandle-bulk @ $call-method
+;
+
+: analyze-csw ( address -- residue tag TRUE | reason FALSE )
+   s" analyze-csw" ihandle-bulk @ $call-method
+   ( residue tag TRUE | reason FALSE )
+;
+
+
+\ =======================================================
+\ NATIVE METHODS USED EITHER AT PROBE TIME OR TIME
+\ WHEN INSTANCE IS CREATED
+\ =======================================================
+
+
+\ --------------------------------------------------------
+\ COLON DEFINITION: the method is a probe-time method
+\ used to:
+\ 1. decode the properties and store in variables
+\ 2. allocat buffers required for the device and
+\ 3. set the right configuration after extracting the
+\ configuration descriptor
+\ --------------------------------------------------------
+
+: device-init ( -- )
+   s" Starting to initialize usb-storage device" usb-debug-print
+   s" USB-ADDRESS" get-my-property         ( TRUE | propaddr proplen FALSE )
+   IF
+      s" not possible" usb-debug-print
+   ELSE
+      decode-int nip nip to my-usb-address
+   THEN
+   s" MPS-BULKOUT" get-my-property         ( TRUE | propaddr proplen FALSE )
+   IF
+      s" not possible"   usb-debug-print
+   ELSE
+      decode-int nip nip to mps-bulk-out
+   THEN
+   s" MPS-BULKIN" get-my-property          ( TRUE | propaddr proplen FALSE )
+   IF
+      s" not possible" usb-debug-print
+   ELSE
+      decode-int nip nip to mps-bulk-in
+   THEN
+   s" BULK-IN-EP-ADDR" get-my-property     ( TRUE | propaddr proplen FALSE )
+   IF
+      s" not possible" usb-debug-print
+   ELSE
+      decode-int nip nip to bulk-in-ep
+   THEN
+   s" BULK-OUT-EP-ADDR" get-my-property    ( TRUE | propaddr proplen FALSE )
+   IF
+      s" not possible"  usb-debug-print
+   ELSE
+      decode-int nip nip to bulk-out-ep
+   THEN
+   s" MPS-DCP" get-my-property             ( TRUE | propaddr proplen FALSE )
+   IF
+      s" Not possible" usb-debug-print
+   ELSE
+      decode-int nip nip to mps-dcp
+   THEN
+   s" LUN" get-my-property                 ( TRUE | propaddr proplen FALSE )
+   IF
+      s" NOT Possible to extract LUN" usb-debug-print
+   ELSE
+      decode-int nip nip to lun
+   THEN
+   s" Extracted properties inherited from parent."  usb-debug-print
+
+   \ PENDING:
+   \ Do some return value check here...
+
+   40 alloc-mem to command-buffer
+   80 alloc-mem to response-buffer
+   10 alloc-mem to csw-buffer
+   8 alloc-mem to cfg-buffer
+   s" Allocated buffers." usb-debug-print
+   cfg-buffer 8 mps-dcp my-usb-address      ( buffer len mps fun-addr )
+   control-std-get-configuration-descriptor ( TRUE | FALSE )
+   drop
+   s" Configuration descriptor extracted." usb-debug-print
+   cfg-buffer 5 + c@ my-usb-address         ( configvalue fun-addr )
+   control-std-set-configuration            ( TRUE | FALSE )
+   s" usb-storage: Set config returned: " rot usb-debug-print-val
+;
+
+
+\ ----------------------------------------------------
+\ Internal methods
+\ ----------------------------------------------------
+
+
+: (open-package)  ( ihandle-var name-str name-len -- )
+   find-package IF                 ( ihandle-var phandle )
+      0 0 rot open-package         ( ihandle-var ihandle )
+      swap !
+   ELSE
+      s" Support package not found"  usb-debug-print
+   THEN
+;
+
+: (close-package)  ( ihandle-var -- )
+   dup @ close-package
+   0 swap !
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-wrapper.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-wrapper.fs
new file mode 100644
index 0000000..c783541
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage-wrapper.fs
@@ -0,0 +1,181 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ -----------------------------------------------------------
+\ OF properties
+\ -----------------------------------------------------------
+
+s" scsi" device-name
+s" block-type" device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+
+: encode-unit   1 hex-encode-unit ;
+
+: decode-unit   1 hex-decode-unit ;
+
+
+\ -----------------------------------------------------------
+\ Specific properties
+\ -----------------------------------------------------------
+
+1 chars alloc-mem VALUE ch-buffer
+8 VALUE mps-dcp
+0 VALUE port-number
+0 VALUE my-usb-address
+
+
+: control-std-get-maxlun
+   ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+   s" control-std-get-maxlun" $call-parent
+;
+
+
+: control-std-get-configuration-descriptor
+   ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+   s" control-std-get-configuration-descriptor" $call-parent
+;
+
+: rw-endpoint
+   ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+   s" rw-endpoint" $call-parent
+;
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE )
+   s" controlxfer" $call-parent
+;
+
+: control-std-set-configuration
+   ( configvalue FuncAddr -- TRUE|FALSE )
+   s" control-std-set-configuration" $call-parent
+;
+
+\ This method is used for extracting the properties from it's parent and
+\ storing these value to temporary variable so that they can used later.
+
+: extract-properties ( -- )
+   s" USB-ADDRESS" get-inherited-property ( prop-addr prop-len FALSE | TRUE )
+   IF
+      s" notpossible" usb-debug-print
+   ELSE
+      decode-int nip nip to my-usb-address
+   THEN
+   s" MPS-DCP" get-inherited-property  ( prop-addr prop-len FALSE | TRUE )
+   IF
+      s" MPS-DCP property not found.Assume 8 as MAX PACKET SIZE" usb-debug-print
+      s" for the default control pipe"  usb-debug-print
+      8 to mps-dcp
+   ELSE
+      s" MPS-DCP property found!!"  usb-debug-print
+      decode-int nip nip to mps-dcp
+   THEN
+   s" reg" get-inherited-property   ( prop-addr prop-len FLASE | TRUE )
+   IF
+      s" notpossible" usb-debug-print
+   ELSE
+      decode-int nip nip to port-number
+   THEN
+;
+
+
+\ This method is used for creating the child nodes for every Logical unit
+\ available in the device, this method will call control-std-get-maxlun for
+\ for finding the maximum Logical units supported by the device and along with
+\ the creation of nodes this method encodes the properties of the node also.
+
+: create-tree ( -- )
+   mps-dcp my-usb-address 0 ch-buffer 1 ( MPS fun-addr dir data-buff data-len )
+   control-std-get-maxlun     ( TRUE | FALSE )
+
+   \ This method extracts the maximum number of Logical Units Supported by
+   \ the Device . if no Logical Units are present then 0 will be taken as the
+   \ max logical units. if the device doesn't support the GET-MAX-LUN command
+   \ then the device may can be stalled as a temporary fix to come out from
+   \ the stalling situations we can issue the control-std-set-configuration with
+   \ appropriate arguments
+
+
+   IF
+      s" GET-MAX-LUN IS WORKING :" usb-debug-print
+   ELSE
+      s" ERROR in GET-MAX-LUN " usb-debug-print
+   THEN
+   ch-buffer c@ 1 +  0                              ( max-lun+1 0 )
+   DO
+      s" iManufacturer" get-inherited-property drop ( prop-addr prop-len TRUE )
+      decode-int nip nip                  ( iManu )
+      s" iProduct" get-inherited-property drop
+      ( iManu prop-addr prop-len TRUE | FALSE )
+      decode-int nip nip                  ( iManu iProd )
+      s" iSerialNumber" get-inherited-property drop
+      ( iManu iProd prop-addr prop-len TRUE | FALSE )
+      decode-int nip nip                  ( iManu iProd iSerNum )
+      s" MPS-BULKOUT" get-inherited-property drop
+      ( iManu iProd iSerNum prop-len prop-addr TRUE | FALSE )
+      decode-int nip nip                  ( iManu iProd iSerNum MPS-BULKOUT )
+      s" BULK-OUT-EP-ADDR" get-inherited-property drop
+      ( iManu iProd iSerNum MPS-BULKOUT prop-addr prop-len TRUE|FALSE )
+      decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR )
+      s" MPS-BULKIN" get-inherited-property drop
+      ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR prop-addr prop-len
+        TRUE | FALSE )
+      decode-int nip nip
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+      s" BULK-IN-EP-ADDR" get-inherited-property drop
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN prop-addr
+        prop-len TRUE | FALSE )
+      decode-int nip nip
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+        BULKIN-EP-ADDR )
+      mps-dcp  port-number  my-usb-address I
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+        BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number )
+      new-device
+
+      \ creates new device child node, doesn't consume any argument from stack
+
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+      BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number )
+
+      set-space
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+        BULKIN-EP-ADDR mps-dcp port-number my-usb-address )
+      encode-int s" USB-ADDRESS" property
+       ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+         BULKIN-EP-ADDR mps-dcp port-number )
+      encode-int s" reg" property
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+      ( BULKIN-EP-ADDR mps-dcp port-number )
+      encode-int s" MPS-DCP" property
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+        BULKIN-EP-ADDR )
+      I encode-int s" LUN" property
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+       BULKIN-EP-ADDR )
+      encode-int s" BULK-IN-EP-ADDR" property
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+      encode-int s" MPS-BULKIN" property
+      ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR )
+      encode-int s" BULK-OUT-EP-ADDR" property
+      ( iManu iProd iSernum MPS-BULKOUT )
+      encode-int s" MPS-BULKOUT" property ( iManu iProd iSerNum )
+      encode-int s" iSerialNumber" property ( iManu iProd )
+      encode-int s" iProduct" property  ( iManu )
+      encode-int s" iManufacturer" property ( -- )
+      s" usb-storage.fs" INCLUDED
+      finish-device
+   LOOP
+;
+
+extract-properties  \ Extract the properties from parent
+create-tree       \ this method creates the node for every lun with properties
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage.fs
new file mode 100644
index 0000000..f23c27a
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-storage.fs
@@ -0,0 +1,639 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ -----------------------------------------------------------
+\ OF properties
+\ -----------------------------------------------------------
+
+s" storage" device-name
+s" block" device-type
+
+2 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+\ -----------------------------------------------------------
+\ Specific properties
+\ -----------------------------------------------------------
+
+8 VALUE mps-bulk-out
+8 VALUE mps-bulk-in
+8 VALUE mps-dcp
+0 VALUE bulk-in-ep
+0 VALUE bulk-out-ep
+0 VALUE bulk-in-toggle
+0 VALUE bulk-out-toggle
+0 VALUE lun
+0 VALUE my-usb-address
+
+
+\ ----------------------------------------------------------
+\ Instance specific values
+\ ----------------------------------------------------------
+
+0  VALUE csw-buffer
+0e VALUE cfg-buffer
+0  VALUE response-buffer
+0  VALUE command-buffer
+0  VALUE resp-size
+0  VALUE resp-buffer
+INSTANCE VARIABLE ihandle-bulk
+INSTANCE VARIABLE ihandle-deblocker
+INSTANCE VARIABLE flag
+INSTANCE VARIABLE count
+0     VALUE max-transfer
+200   VALUE block-size           \ default (512 Bytes)
+-1    VALUE max-block-num        \ highest reported block-number
+
+
+\ -------------------------------------------------------
+\ General Constants
+\ -------------------------------------------------------
+
+0f CONSTANT SCSI-COMMAND-OFFSET
+
+
+\ -------------------------------------------------------
+\ All support methods inherited from parent or imported
+\ from support packages are included here. Also included
+\ are the internal methods
+\ -------------------------------------------------------
+
+s" usb-storage-support.fs" INCLUDED
+
+\ ---------------------------------------------------------------
+\ COLON Definitions: Implementation of Standard SCSI commands
+\ over USB OHCI
+\ ---------------------------------------------------------------
+
+
+\ to use the general bulk command a lot of global variables
+\ must be set. See for example the inquiry command.
+0 VALUE bulk-cnt
+0 VALUE bulk-cmd-len
+0 VALUE itest
+: do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE )
+   TO resp-size
+   TO resp-buffer
+   \ dump buffer in debug-mode
+   usb-debug-flag
+   IF
+      command-buffer 0E + c@ TO bulk-cmd-len 
+      s" cmd-length: " bulk-cmd-len usb-debug-print-val
+      command-buffer bulk-cmd-len 0E + dump cr
+   THEN
+
+   6 TO bulk-cnt \ 2 old value
+   FALSE dup
+   BEGIN
+      0=
+      WHILE
+      drop
+      \ prepare and send bulk CBW
+      1 1 bulk-out-toggle command-buffer 1f mps-bulk-out
+               ( pt ed-type toggle buffer length mps-bulk-out )
+      my-usb-address bulk-out-ep 7 lshift or
+               ( pt ed-type toggle buffer length mps address )
+      rw-endpoint swap		             ( TRUE toggle | FALSE toggle )
+      to bulk-out-toggle                ( TRUE | FALSE )
+      IF
+         s" resp-size : " resp-size usb-debug-print-val
+         resp-size 0<>
+         IF       \ do we need a response ?!
+                  \ read the bulk response
+            0 1 bulk-in-toggle resp-buffer resp-size mps-bulk-in
+                     ( pt ed-type toggle buffer length mps-bulk-in )
+            my-usb-address bulk-in-ep 7 lshift or
+                     ( pt ed-type toggle buffer length mps address )
+            rw-endpoint swap                       ( TRUE toggle | FALSE toggle )
+            to bulk-in-toggle                      ( TRUE | FALSE )
+         ELSE
+            TRUE
+         THEN
+         IF               \ read the bulk CSW
+            0 1 bulk-in-toggle csw-buffer D mps-bulk-in
+                     ( pt ed-type toggle buffer length mps-bulk-in )
+            my-usb-address bulk-in-ep 7 lshift or
+                     ( pt ed-type toggle buffer length mps address )
+            rw-endpoint swap                    ( TRUE toggle | FALSE toggle )
+            to bulk-in-toggle                   ( TRUE | FALSE )
+            IF
+	            s" Command successful." usb-debug-print
+	            TRUE dup
+            ELSE
+               s" Command failed in CSW stage" usb-debug-print
+	            FALSE dup
+            THEN
+         ELSE
+            s" Command failed while receiving DATA... read CSW..." usb-debug-print
+            \ STALLED: Get CSW to send the CBW again
+            0 1 bulk-in-toggle csw-buffer D mps-bulk-in
+                     ( pt ed-type toggle buffer length mps-bulk-in )
+            my-usb-address bulk-in-ep 7 lshift or
+                     ( pt ed-type toggle buffer length mps address )
+            rw-endpoint swap                    ( TRUE toggle | FALSE toggle )
+            to bulk-in-toggle                   ( TRUE | FALSE )
+            IF
+	            s" OK evaluate the CSW ..." usb-debug-print
+               csw-buffer c + c@ dup TO itest
+	            s" CSW Status: " itest usb-debug-print-val
+	            dup
+               2 =
+               IF \ Phase Error
+	               s" Phase error do a bulk reset-recovery ..." usb-debug-print
+                  bulk-out-ep bulk-in-ep my-usb-address
+                  bulk-reset-recovery-procedure
+               THEN
+               \ ELSE
+	            \ don't abort if the read fails.
+	            1 =
+               IF \ Command failed
+                  s" Command Failed do a bulk-reset-recovery" usb-debug-print
+                  bulk-out-ep bulk-in-ep my-usb-address
+                  bulk-reset-recovery-procedure
+               THEN
+  	         THEN
+            FALSE dup
+         THEN
+      ELSE
+         s" Command failed while Sending CBW ..." usb-debug-print
+         FALSE dup
+      THEN
+      bulk-cnt 1 - TO bulk-cnt
+      bulk-cnt 0=
+      IF
+         2drop FALSE dup
+      THEN
+   REPEAT
+;
+
+
+\ ---------------------------------------------------------------
+\ Method to 1. Send the INQUIRY command 2. Receive and analyse
+\ (pending) INQUIRY data
+\ ---------------------------------------------------------------
+scsi-open
+usb-debug-flag to scsi-param-debug  \ copy debug flag
+
+24 CONSTANT inquiry-length    \ was 20
+
+: inquiry ( -- )
+   s" usb-storage: inquiry" usb-debug-print
+   command-buffer 1 inquiry-length 80 lun scsi-length-inquiry
+   ( address tag transfer-len direction lun command-len )
+   build-cbw
+   inquiry-length command-buffer SCSI-COMMAND-OFFSET +   ( alloc-len address  )
+   scsi-build-inquiry
+   response-buffer inquiry-length erase      \ provide clean buffer
+   response-buffer inquiry-length do-bulk-command
+   IF
+     s" Successfully read INQUIRY data" usb-debug-print
+     0d emit space space
+     response-buffer c@  \ get 'Peripheral Device Type' (PDT)
+     CASE
+        0   OF ." BLOCK-DEV: " ENDOF  \ SCSI Block Device
+        5   OF ." CD-ROM   : " ENDOF
+        7   OF ." OPTICAL  : " ENDOF
+        e   OF ." RED-BLOCK: " ENDOF  \ SCSI Reduced Block Device
+        dup dup OF ." ? (" . 8 emit 29 emit 2 spaces ENDOF
+     ENDCASE
+     space
+     \ create vendor identification in device property
+     response-buffer 8 + 16 encode-string s" ident-str" property
+     response-buffer .inquiry-text
+   ELSE
+     5040 error" (USB) Device transaction error. (inquiry)"
+     ABORT
+   THEN
+;
+
+\ ---------------------------------------------------------------
+\ Method to 1. Send the READ CAPACITY command
+\           2. Recieve and analyse the response data
+\ ---------------------------------------------------------------
+
+: read-capacity ( -- )
+   s" usb-storage: read-capacity" usb-debug-print
+   command-buffer 1 8  80 lun  scsi-length-read-cap-10
+   ( address tag transfer-len direction lun command-len )
+   build-cbw 
+   \ command-buffer 30 dump cr      \ dump the command buffer
+   command-buffer SCSI-COMMAND-OFFSET +      ( address )   
+   scsi-build-read-cap-10
+   lun 5 lshift
+   command-buffer SCSI-COMMAND-OFFSET +      ( address )
+   read-cap-10>reserved1 c!
+
+   response-buffer 8 erase          \ provide clean buffer
+   response-buffer 8 do-bulk-command
+   IF
+     s" Successfully read READ CAPACITY data" usb-debug-print
+   ELSE
+     5040 error" (USB) Device transaction error. (capacity)"
+     ABORT
+   THEN
+;
+
+
+\ -------------------------------------------------------------------
+\ Method to 1. Send TEST UNIT READY command 2. Analyse the status
+\ of the response
+\ -------------------------------------------------------------------
+
+: test-unit-ready ( -- TRUE | FALSE )
+   command-buffer 1 0 80 lun scsi-length-test-unit-ready    \ was: 0c
+   ( address tag transfer-len direction lun command-len )
+   build-cbw
+   command-buffer SCSI-COMMAND-OFFSET +      ( address )
+   scsi-build-test-unit-ready                ( cdb -- )
+   response-buffer 0 do-bulk-command
+   IF
+     s" Successfully read test unit ready data" usb-debug-print
+     s" Test Unit STATUS availabe in csw-buffer" usb-debug-print
+     csw-buffer 0c + c@ 0=  IF
+       s" Test Unit Command Successfully Executed" usb-debug-print
+       TRUE                             ( TRUE )
+     ELSE
+       s" Test Unit Command Failed to execute" usb-debug-print
+       FALSE                            ( FALSE )
+     THEN
+   ELSE
+     \ TRUE ABORT" USB device transaction error. (test-unit-ready)"
+      5040 error" (USB) Device transaction error. (test-unit-ready)"
+      ABORT
+   THEN
+;
+
+\ ****************************************************
+\ multiple checks of 'test-unit-ready' with timeout
+\ ****************************************************
+: wait-for-unit-ready            ( -- TRUE|FALSE )
+   s" --> WAIT: test-unit-ready ... " usb-debug-print
+   d# 100                        ( count )   \ up to 10 seconds
+   BEGIN                         ( count )
+      dup 0>                     ( count flag )
+      test-unit-ready      \ dup IF 2b ELSE 2d THEN emit
+      not and    ( count flag )
+      WHILE
+      1-                         ( count )
+      d# 100 wait-proceed        \ wait 100 ms
+   REPEAT                        ( count )
+   0=
+   IF
+      s" **  Device not ready **  " usb-debug-print
+      FALSE
+   ELSE
+      TRUE
+   THEN
+;
+
+
+\ -------------------------------------------------
+\ Method to 1. read sense data 2. analyse sesnse
+\ data(pending)
+\ ------------------------------------------------
+
+: request-sense ( -- )
+   s" request-sense: Command ready." usb-debug-print
+   command-buffer 1 12 80 lun scsi-length-request-sense
+   ( address tag transfer-len direction lun command-len )
+   build-cbw
+\ -scsi-supp-   command-buffer SCSI-COMMAND-OFFSET + 12   ( address alloc-len )
+\ -scsi-supp-   build-request-sense
+
+   12 command-buffer SCSI-COMMAND-OFFSET +   ( alloc-len cdb )
+   scsi-build-request-sense                  ( alloc-len cdb -- )
+
+   response-buffer 12 do-bulk-command
+   IF
+      s" Read Sense data successfully" usb-debug-print
+      \   response-buffer 12 dump cr      \ dump the rsponsed message
+   ELSE
+     \ TRUE ABORT" USB device transaction error. (request-sense)"
+     5040 error" (USB) Device transaction error. (request-sense)"
+     ABORT
+   THEN
+;
+
+: start ( -- )
+   command-buffer 1 0 80 lun scsi-length-start-stop-unit
+   ( address tag transfer-len direction lun command-len )
+   build-cbw
+\ -scsi-supp-   command-buffer SCSI-COMMAND-OFFSET +  ( address )
+\ -scsi-supp-   build-start
+
+   command-buffer SCSI-COMMAND-OFFSET +            ( cdb )
+   scsi-const-start scsi-build-start-stop-unit     ( state# cdb -- )
+
+   response-buffer 0 do-bulk-command
+   IF
+     s" Start successfully" usb-debug-print
+   ELSE
+     \ TRUE ABORT" USB device transaction error. (start)"
+     5040 error" (USB) Device transaction error. (start)"
+     ABORT
+   THEN
+;
+
+
+\ To transmit SCSI Stop command
+
+: stop ( -- )
+   command-buffer 1 0 80 lun scsi-length-start-stop-unit
+   ( address tag transfer-len direction lun command-len )
+   build-cbw
+\ -scsi-supp-   command-buffer SCSI-COMMAND-OFFSET +      ( address )
+\ -scsi-supp-   build-stop
+
+   command-buffer SCSI-COMMAND-OFFSET +         ( cdb )
+   scsi-const-stop scsi-build-start-stop-unit   ( state# cdb -- )
+
+   response-buffer 0 do-bulk-command
+   IF
+     s" Stop successfully" usb-debug-print
+   ELSE
+     \ TRUE ABORT" USB device transaction error. (stop)"
+     5040 error" (USB) Device transaction error. (stop)"
+     ABORT
+   THEN
+;
+
+
+0 VALUE temp1
+0 VALUE temp2
+0 VALUE temp3
+
+
+\ -------------------------------------------------------------
+\          block device's seek
+\ -------------------------------------------------------------
+\ if anything is wrong in the boot device, a seek-request can
+\ occur that exceeds the limits of the device in the following
+\ read-command. So checking is required and the appropriate
+\ return-value has to be returned
+\ Spec requires -1 if operation fails and 0 or 1 if it succeeds !!
+\ -------------------------------------------------------------
+
+: seek ( pos-lo pos-hi -- status )
+   2dup lxjoin max-block-num block-size * >
+   IF
+      ." ** Seek Error: pos too large ("
+      dup . over . ." -> " max-block-num block-size * .
+      ." ) ** " cr
+      -1                   \ see spec-1275 page 183
+   ELSE
+      s" seek" ihandle-deblocker @ $call-method
+   THEN
+;
+
+
+\ -------------------------------------------------------------
+\          block device's read
+\ -------------------------------------------------------------
+
+: read ( address length -- actual )
+   s" read" ihandle-deblocker @  $call-method
+;
+
+
+\ -------------------------------------------------------------
+\         read-blocks to be used by deblocker
+\ -------------------------------------------------------------
+: read-blocks ( address block# #blocks -- #read-blocks )
+   2dup + max-block-num >
+   IF
+      ." ** Requested block too large "
+      2dup + ." (" .d ." -> " max-block-num .d
+      bs emit ." ) ... read aborted **" cr
+      nip nip                       \ leave #blocks on stack
+   ELSE
+      block-size * command-buffer  ( address block# transfer-len command-buffer )
+      1 2 pick 80 lun 0c build-cbw ( address block# transfer-len )
+      dup to temp1                 ( address block# transfer-len )
+      block-size /                 ( address block# #blocks )
+      command-buffer               ( address block# #blocks command-addr )
+      SCSI-COMMAND-OFFSET +        ( address block# #blocks cdb )
+      scsi-build-read?                     ( block# #blocks cdb -- length )
+      command-buffer 0e + c!       \ update bCBWCBLength-field with resulting CDB length
+      temp1                        ( address length )
+      do-bulk-command
+      IF
+        s" Read  data successfully" usb-debug-print
+      ELSE
+        \ TRUE ABORT" USB device transaction error. (read-blocks)"
+        5040 error" (USB) Device transaction error. (read-blocks)"
+        ABORT
+      THEN
+      temp1 block-size /  ( #read-blocks )
+   THEN
+;
+
+\ ------------------------------------------------
+\ To bring the the media to seekable and readable
+\ condition.
+\ ------------------------------------------------
+
+d# 800 CONSTANT media-ready-retry
+
+: make-media-ready ( -- )
+   s" usb-storage: make-media-ready" usb-debug-print
+   0  flag !
+   0  count !
+   BEGIN
+      flag @  0=
+   WHILE
+      test-unit-ready IF
+         s" Media ready for access." usb-debug-print
+         1  flag !
+      ELSE
+         count @  1 +  count !
+         count @ media-ready-retry = IF
+            1 flag !
+            5000 error" (USB) Media or drive not ready for this blade."
+            ABORT
+         THEN
+         request-sense
+         response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+         IF
+            ffff00 AND     \ remaining: sense-key ASC
+            CASE
+               023a00 OF   \ MEDIUM NOT PRESENT (02 3a 00)
+                  5010 error" (USB) No Media found! Check for the drawer/inserted media."
+                  ABORT
+               ENDOF
+
+               020400 OF   \ LOGICAL DRIVE NOT READY - INITIALIZATION REQUIRED
+                  5010 error" (USB) No Media found! Check for the drawer/inserted media."
+                  ABORT
+               ENDOF
+
+               033000 OF   \ CANNOT READ MEDIUM - UNKNOWN FORMAT
+                  5020 error" (USB) Unknown media format."
+                  ABORT
+               ENDOF
+            ENDCASE
+         THEN
+      THEN
+      d# 10 ms             \ wait maximum 10ms * 800 (=8s)
+   REPEAT
+   usb-debug-flag IF
+      ." make-media-ready finished after "
+      count @ decimal . hex ." tries." cr
+   THEN
+;
+
+\ ------------------------------------------------
+\ read and show devices capacity
+\ ------------------------------------------------
+: .showcap
+   space
+   test-unit-ready drop             \ initial command
+   request-sense
+   response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+   IF
+      dup FFFF00 and 023a00 =       ( sense-id flag )
+      IF
+         uDOC-failure?
+         023a02 =                   \ see sense-codes SPC-3 clause 4.5.6
+         IF
+            ."  Tray Open!"
+         ELSE
+            ."    No Media"
+         THEN
+      ELSE                          ( sense-id )
+         drop
+         wait-for-unit-ready
+         IF
+            read-capacity
+            response-buffer scsi-get-capacity-10 space .capacity-text
+         ELSE
+            request-sense
+            response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+            IF
+               dup ff0000 and 040000 =       \ sense-code = 4 ?
+               IF
+                  ." *HW-ERROR*"
+                  uDOC-failure?
+               ELSE
+                  dup FFFF00 and 023a00 = IF uDOC-failure? THEN
+                  CASE              ( sense-ID )
+                     \ see SPC-3 clause 4.5.6
+                     023a00 OF ."   No Media " ENDOF
+                     023a02 OF ." Tray Open! " ENDOF
+                     dup    OF ."          ? " ENDOF
+                  ENDCASE
+               THEN
+            THEN
+         THEN
+      THEN
+   ELSE
+      ."       ??   "
+   THEN
+;
+
+
+
+: init-dev-ready
+   test-unit-ready drop
+   4 >r                \ loop-counter
+   0 0
+   BEGIN
+      2drop
+      request-sense
+      response-buffer scsi-get-sense-data ( ascq asc sense-key )
+      0<>  r> 1- dup >r 0<> AND          \ loop-counter or sense-key
+      WHILE
+   REPEAT
+   2drop
+   r> drop
+;
+
+
+
+scsi-close        \ no further scsi words required
+
+
+\ Set up the block-size of the device, using the READ CAPACITY command.
+\ Note: Media must be ready (=> make-media-ready) or READ CAPACITY
+\ might fail!
+
+: (init-block-size)
+   read-capacity
+   response-buffer l@ dup 0<>
+   IF
+      to max-block-num        \ highest block-number
+   ELSE
+      -1 to max-block-num     \ indeterminate
+   THEN
+   response-buffer 4 + 
+   l@ to block-size
+   s" usb-storage: block-size=" block-size usb-debug-print-val
+;
+
+
+\ Standard OF methods
+
+: open ( -- TRUE )
+   s" usb-storage: open" usb-debug-print
+   ihandle-bulk s" bulk" (open-package)
+
+   make-media-ready
+   (init-block-size)           \ Init block-size before opening the deblocker
+
+   ihandle-deblocker s" deblocker" (open-package)
+
+   s" disk-label" find-package IF  ( phandle )
+      usb-debug-flag IF ." my-args for disk-label = " my-args swap . . cr THEN
+      my-args rot interpose
+   THEN
+   TRUE                        ( TRUE )
+;
+
+
+: close  ( -- )
+   ihandle-deblocker (close-package)
+   ihandle-bulk (close-package)
+;
+
+
+\ Set device name according to type
+
+: (init-device-name)  ( -- )
+   init-dev-ready
+   inquiry
+   response-buffer c@
+   CASE
+      1  OF .showcap s" tape"    device-name ENDOF
+      5  OF .showcap s" cdrom"   device-name s" CDROM found" usb-debug-print ENDOF
+      0  OF .showcap s" sbc-dev" device-name s" SBC Direct access device" usb-debug-print ENDOF
+      7  OF .showcap s" optical" device-name s" Optical memory found" usb-debug-print ENDOF
+      0E OF .showcap s" rbc-dev" device-name s" RBC direct acces device found" usb-debug-print ENDOF
+      \ dup OF s" storage" device-name ENDOF
+   ENDCASE
+;
+
+
+\ Initial device node setup
+
+: (initial-setup)
+   ihandle-bulk s" bulk" (open-package)
+   device-init
+   (init-device-name)
+   set-drive-alias
+   200 to block-size       \ Default block-size, will be overwritten in "open"
+   10000 to max-transfer
+   
+   ihandle-bulk (close-package)
+;
+
+(initial-setup)
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-support.fs b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-support.fs
new file mode 100644
index 0000000..08ff9bd
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/usb/usb-support.fs
@@ -0,0 +1,651 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 value NEXT-TD
+
+0 VALUE num-tds
+0 VALUE td-retire-count
+0 VALUE saved-tail
+0 VALUE poll-timer
+VARIABLE controlxfer-cmd
+
+\  Allocate an ED and populate it
+
+: (ed-prepare) ( dir addr dlen setup-packet MPS ep-fun --
+                 FALSE | dir addr dlen ed-ptr setup-ptr )
+   allocate-ed dup 0=  IF ( dir addr dlen setup-packet MPS ep-fun ed-ptr )
+      drop 3drop 2drop FALSE EXIT  ( FALSE )
+   THEN
+   TO temp1               ( dir addr dlen setup-packet MPS ep-fun )
+   temp1 zero-out-an-ed-except-link ( dir addr dlen setup-packet MPS ep-fun )
+   temp1 ed>eattr l at -le or temp1 ed>eattr l!-le ( dir addr dlen setup-ptr MPS )
+   dup TO temp2 10 lshift temp1 ed>eattr l at -le or temp1 ed>eattr l!-le
+                          ( dir addr dlen setup-packet-address )
+   temp1 swap TRUE            ( dir addr dlen ed-ptr setup-ptr TRUE )
+;
+
+
+\ Allocate TD list
+
+
+: (td-prepare) ( dir addr dlen ed-ptr setup-ptr --
+                 dir FALSE | dir addr dlen ed-ptr setup-ptr td-head td-tail )
+   2 pick         ( dir addr dlen ed-ptr setup-ptr dlen )
+   temp2          ( dir addr dlen ed-ptr setup-ptr dlen MPS )
+   /mod           ( dir addr dlen ed-ptr setup-ptr rem quo )
+   swap 0<>   IF  ( dir addr dlen ed-ptr setup-ptr quo )
+      1+
+   THEN
+   2+
+   dup TO num-tds                ( dir addr dlen ed-ptr setup-ptr quo+2 )
+   allocate-td-list dup 0=  IF   ( dir addr dlen ed-ptr setup-ptr quo+2 )
+      2drop                      ( dir addr dlen ed-ptr setup-ptr )
+      drop                       ( dir addr dlen ed-ptr )
+      free-ed                    ( dir addr dlen )
+      2drop                      ( dir )
+      FALSE                      ( dir FALSE )
+      EXIT
+   THEN TRUE
+;
+
+
+\ Fill in the ED structure completely.
+
+
+: (td-ready)  ( dir addr dlen ed-ptr setup-ptr td-head td-tail -- )
+              ( dir addr dlen ed-ptr setup-ptr )
+   3 pick     ( dir addr dlen ed-ptr setup-ptr td-head td-tail ed-ptr )
+   tuck       ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr td-tail ed-ptr )
+   ed>tdqtp l!-le            ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr )
+   ed>tdqhp l!-le            ( dir addr dlen ed-ptr setup-ptr )
+   over ed>ned 0 swap l!-le  ( dir addr dlen ed-ptr setup-ptr )
+;
+
+
+\ Initialize the HEAD and TAIL TDs for SETUP and
+\ STATUS phase respectively.
+
+
+: (td-setup-status) ( dir addr dlen ed-ptr setup-ptr -- dir addr dlen ed-ptr )
+   over ed>tdqhp l at -le             ( dir addr dlen ed-ptr setup-ptr td-head )
+   dup zero-out-a-td-except-link   ( dir addr dlen ed-ptr setup-ptr td-head )
+   dup td>tattr DATA0-TOGGLE CC-FRESH-TD or swap l!-le
+                                   ( dir addr dlen ed-ptr setup-ptr td-head )
+   2dup td>cbptr l!-le             ( dir addr dlen ed-ptr setup-ptr td-head )
+   2dup td>bfrend swap STD-REQUEST-SETUP-SIZE 1- + swap l!-le
+                                   ( dir addr dlen ed-ptr setup-ptr td-head )
+   2drop                           ( dir addr dlen ed-ptr )
+;
+
+\ Initialize the TD TAIL pointer.
+
+
+: (td-tailpointer) ( dir addr dlen ed-ptr -- dir addr dlen ed-ptr )
+   dup ed>tdqtp l at -le              ( dir addr dlen ed-ptr td-tail )
+   dup zero-out-a-td-except-link   ( dir addr dlen ed-ptr td-tail )
+   dup td>tattr dup l at -le DATA1-TOGGLE CC-FRESH-TD or or swap l!-le
+                                   ( dir addr dlen ed-ptr td-tail )
+   4 pick 0=                       ( dir addr dlen ed-ptr td-tail flag )
+   3 pick 0<>                      ( dir addr dlen ed-ptr td-tail flag flag )
+   and   IF                        ( dir addr dlen ed-ptr td-tail )
+      dup td>tattr dup l at -le TD-DP-OUT or swap l!-le
+                                   ( dir addr dlen ed-ptr td-tail )
+   ELSE
+      dup td>tattr dup l at -le TD-DP-IN or swap l!-le
+                                  ( dir addr dlen ed-ptr td-tail )
+   THEN
+   drop                           ( dir addr dlen ed-ptr )
+;
+
+\  Initialize the Data TDs.
+
+
+: (td-data) ( dir addr dlen ed-ptr --  ed-ptr )
+   -rot             ( dir ed-ptr addr dlen )
+   dup 0<>  IF      ( dir ed-ptr addr dlen )
+      >r >r >r TO temp1 r> r> r> temp1 ( ed-ptr addr dlen dir )
+      3 pick 		            ( ed-ptr addr dlen dir ed-ptr )
+      ed>tdqhp l at -le td>ntd l at -le   ( ed-ptr addr dlen dir td-datahead )
+      4 pick 		           ( ed-ptr addr dlen dir td-datahead ed-ptr )
+      td>tattr l at -le 10 rshift ( ed-ptr addr dlen dir td-head-data MPS )
+      swap 			    ( ed-ptr addr dlen dir MPS td-head-data )
+      >r >r >r >r >r 1 r> r> r> r> r>
+                                   ( ed-ptr 1 addr dlen dir MPS td-head-data )
+      >r >r 0=  IF                 ( ed-ptr 1 addr dlen dir )
+         OHCI-DP-IN                ( ed-ptr 1 addr dlen dir  OHCI-DP-IN )
+      ELSE
+         OHCI-DP-OUT               ( ed-ptr 1 addr dlen dir  OHCI-DP-OUT )
+      THEN
+      r> r>               ( ed-ptr 1 addr dlen dir  OHCI-DP- MPS td-head-data )
+      fill-TD-list
+   ELSE
+      2drop nip           ( ed-ptr )
+   THEN
+;
+
+
+\ Program the HC with the ed-ptr value and wait for status to
+\ from the HC.
+\ Free the ED and TDs associated with it.
+\ PENDING: Above said.
+
+10 CONSTANT max-retire-td
+
+: (transfer-wait-for-doneq)  ( ed-ptr -- TRUE | FALSE )
+   dup                               ( ed-ptr ed-ptr )
+   hcctrhead rl!-le                  ( ed-ptr )
+   HC-enable-control-list-processing ( ed-ptr )
+   0 TO td-retire-count              ( ed-ptr )
+   0 TO poll-timer                   ( ed-ptr )
+   BEGIN
+      td-retire-count num-tds <>     ( ed-ptr TRUE | FALSE )
+      poll-timer max-retire-td < and       ( ed-ptr TRUE | FALSE )
+      WHILE
+      (HC-CHECK-WDH)                                      ( ed-ptr )
+      IF
+         hchccadneq l at -le find-td-list-tail-and-size nip ( ed-ptr n )
+         td-retire-count + TO td-retire-count             ( ed-ptr )
+         hchccadneq l at -le dup              ( ed-ptr done-td done-td )
+         (td-list-status)                  ( ed-ptr done-td failed-td CCcode )
+         IF
+            \ keep condition code of TD on return stack
+            dup >r
+            s" (transfer-wait-for-doneq: USB device communication error."
+            usb-debug-print                 ( ed-ptr done-td failed-td CCcode R: CCcode )
+            dup 4 = swap dup 5 = rot or     ( ed-ptr done-td failed-td CCcode R: CCcode )
+            IF
+                max-retire-td TO poll-timer ( ed-ptr done-td failed-td CCcode R: CCcode )
+            THEN
+            ( ed-ptr done-td failed-td CCcode R: CCcode )
+            usb-debug-flag
+            IF
+               s" CC code ->" type . cr
+               s" Failing TD contents:" type cr display-td
+            ELSE
+               2drop
+            THEN                           ( ed-ptr done-td R: CCcode )
+            controlxfer-cmd @ GET-MAX-LUN = r> 4 = and
+            IF
+               s" (transfer-wait-for-doneq): GET-MAX-LUN ControlXfer STALLed"
+               usb-debug-print
+               \ Condition Code = 4 means that the device does not support multiple LUNS
+               \ see USB Massbulk 1.0 Standard
+            ELSE
+               drop
+               5030 error" (USB) Device communication error."
+               ABORT
+               \ FIXME: ABORTing here might leave the HC in an unusable state.
+               \        We should maybe rather ABORT at the end of this Forth
+               \        word, when clean-up has been done (or not ABORT at all)
+            THEN
+         THEN                              ( ed-ptr done-td )
+         (free-td-list)                    ( ed-ptr )
+         0 hchccadneq l!-le                ( ed-ptr )
+         (HC-ACK-WDH) \ TDs were written to DOne queue. ACK the HC.
+      THEN
+      poll-timer 1+ TO poll-timer
+      4 ms              \ longer  1 ms
+   REPEAT                                  ( ed-ptr )
+   disable-control-list-processing         ( ed-ptr )
+   td-retire-count num-tds <>              ( ed-ptr )
+   IF
+      dup display-descriptors              ( ed-ptr )
+      s" maximum of retire " usb-debug-print						     
+   THEN
+   free-ed
+   td-retire-count num-tds <>
+   IF
+      FALSE                                ( FALSE )
+   ELSE
+      TRUE                                 ( TRUE )
+   THEN
+;
+
+
+\ COLON DEFINITION: controlxfer
+\                     INTERFACE FUNCTION
+
+\ ARGUMENTS:
+\ (from the bottom OF stack)
+\ 1. dir -- This is the direction OF data transfer associated with
+\           the DATA STAGE OF the control xfer.
+\           If there is no data transfer (argument dlen is zero)
+\           THEN this argument DOes not matter, nonethless it has
+\           to be passed.
+\           A "0" represents an IN and "1" represents an "OUT".
+\ 2. addr -- If therez a data stage associated with the transfer,
+\            THEN, this argument holds the address OF the data buffer
+\ 3. dlen -- This arg holds the length OF the data buffer discussed
+\            in previous step (addr)
+\ 4. setup-packet -- This holds the pointer to the setup packet that
+\                    will be transmitted during the SETUP stage OF
+\                    the control xfer. The function assumes the length
+\                    OF the status packet to be 8 bytes.
+\ 5. MPS -- This is the MAX PACKET SIZE OF the endpoint.
+\ 6. ep-fun -- This is the 11-bit value that holds the Endpoint and
+\              the function address. bit 7 to bit 10 holds the Endpoint
+\              address. Bits 0 to Bit 6 holds the Function Address.
+\              The BIT numbering followed : The left most bit is referred
+\              as bit 0. (not the one followed by PPC)
+\              Bit 13 must be set for low-speed devices.
+
+\ RETURN VALUE:
+\ Returns TRUE | FALSE depending on the success OF the transaction.
+
+\ ASSUMPTIONS:
+\ 1. Function assumes that the setup packet is 8-bytes in length.
+\    If in future, IF we need to add a new argument, we need to change
+\    the function in lot OF places.
+
+\ RISKS:
+\ 1. If for some reason, the USB controller DOes not retire all the TDs
+\    THEN, the status checking part OF this "word" can spin forever.
+
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE | FALSE )
+   2 pick @ controlxfer-cmd !
+   (ed-prepare)       ( FALSE | dir addr dlen ed-ptr setup-ptr  )
+   invert IF FALSE EXIT THEN
+   (td-prepare)       ( pt ed-type toggle buffer length mps head )
+   invert IF FALSE EXIT THEN
+   (td-ready)         ( dir addr dlen ed-ptr setup-ptr )
+   (td-setup-status)  ( dir addr dlen ed-ptr )
+   (td-tailpointer)   ( dir addr dlen ed-ptr )
+   (td-data)          ( ed-ptr )
+
+
+   \ FIXME:
+   \ Clear the TAIL pointer in ED. This has got sthg to DO with how
+   \ the HC finds an EMPTY queue condition. Refer spec.
+
+
+   dup ed>tdqtp l at -le TO saved-tail    ( ed-ptr )
+   dup ed>tdqtp 0 swap l!-le           ( ed-ptr )
+   (transfer-wait-for-doneq)           ( TRUE | FALSE )
+;
+
+0201000000000000 CONSTANT CLEARHALTFEATURE
+0 VALUE endpt-num
+0 VALUE usb-addr-contr-req
+: control-std-clear-feature ( endpoint-nr usb-addr -- TRUE|FALSE )
+   TO usb-addr-contr-req                        \ usb address
+   TO endpt-num                                 \ endpoint number
+   CLEARHALTFEATURE setup-packet !
+   endpt-num setup-packet 4 + c!                \ endpoint number
+   0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer
+   ( TRUE|FALSE )
+;  
+
+\ It resets the usb bulk-device
+21FF000000000000 CONSTANT BULK-RESET
+: control-std-bulk-reset ( usb-addr -- TRUE|FALSE )
+  TO usb-addr-contr-req
+  BULK-RESET setup-packet !
+  0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer
+  ( TRUE|FALSE )
+;
+
+: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- )
+    >r                                          ( bulk-out-endp bulk-in-endp R: usb-addr )
+    \ perform a bulk reset
+    r@ control-std-bulk-reset
+    IF s" bulk reset OK" 
+    ELSE s" bulk reset failed" 
+    THEN usb-debug-print
+    
+    \ clear bulk-in endpoint                    ( bulk-out-endp bulk-in-endp R: usb-addr )
+    80 or r@ control-std-clear-feature
+    IF s" control-std-clear IN endpoint OK" 
+    ELSE s" control-std-clear-IN endpoint failed" 
+    THEN usb-debug-print
+
+    \ clear bulk-out endpoint                   ( bulk-out-endp R: usb-addr )
+    r@ control-std-clear-feature
+    IF s" control-std-clear OUT endpoint OK" 
+    ELSE s" control-std-clear-OUT endpoint failed" 
+    THEN usb-debug-print
+    r> drop
+;
+
+0 VALUE saved-rw-ed
+0 VALUE num-rw-tds
+0 VALUE num-rw-retired-tds
+0 VALUE saved-rw-start-toggle
+0 VALUE saved-list-type
+
+\ Allocate an ED and populate what you can.
+
+
+: (ed-prepare-rw)
+   ( pt ed-type toggle buffer length mps address ed-ptr --
+      FALSE | pt ed-type toggle buffer length mps )
+   allocate-ed dup 0=  IF
+   ( pt ed-type toggle buffer length mps address ed-ptr )
+      drop 2drop 2drop 2drop drop
+      saved-rw-start-toggle FALSE EXIT  ( toggle FALSE )
+   THEN
+   TO saved-rw-ed             ( pt ed-type toggle buffer length mps address )
+   saved-rw-ed zero-out-an-ed-except-link
+                              ( pt ed-type toggle buffer length mps address )
+   saved-rw-ed ed>eattr l!-le   ( pt ed-type toggle buffer length mps )
+   dup 10 lshift saved-rw-ed ed>eattr l at -le or
+                              ( pt ed-type toggle buffer length mps mps~ )
+   saved-rw-ed ed>eattr l!-le TRUE  ( pt ed-type toggle buffer length mps TRUE )
+;
+
+
+\  Allocate TD List
+
+
+: (td-prepare-rw)
+   ( pt ed-type toggle buffer length mps --
+     FALSE | pt ed-type toggle buffer length mps head )
+   2dup              ( pt ed-type toggle buffer length mps  length mps )
+   /mod              ( pt ed-type toggle buffer length mps num-tds rem )
+   swap 0<> IF       ( pt ed-type toggle buffer length mps num-tds )
+      1+             ( pt ed-type toggle buffer length mps num-tds+1 )
+   THEN
+   dup TO num-rw-tds ( pt ed-type toggle buffer length mps num-tds )
+   allocate-td-list  ( pt ed-type toggle buffer length mps head tail )
+   dup 0=  IF
+      2drop 2drop 2drop 2drop
+      saved-rw-ed free-ed
+      ." rw-endpoint: TD list allocation failed" cr
+      saved-rw-start-toggle FALSE   ( FALSE )
+      EXIT
+   THEN
+   drop  TRUE         ( pt ed-type toggle buffer length mps head TRUE )
+;
+
+
+\ Populate TD list with data buffers and toggle info.
+
+
+: (td-data-rw)
+   ( pt ed-type toggle buffer length mps head -- FALSE | pt et head )
+   6 pick                    ( pt ed-type toggle buffer length mps head  pt )
+   FALSE TO case-failed  CASE
+      0   OF OHCI-DP-IN    ENDOF
+      1   OF OHCI-DP-OUT   ENDOF
+      2   OF OHCI-DP-SETUP ENDOF
+      dup OF TRUE TO case-failed
+      ." rw-endpoint: Invalid Packet Type!" cr
+      ENDOF
+   ENDCASE                   ( pt ed-type toggle buffer length mps head dp )
+   case-failed  IF
+      saved-rw-ed free-ed    ( pt ed-type toggle buffer length mps head dp )
+      drop (free-td-list)         ( pt ed-type toggle buffer length mps head )
+      2drop 2drop 2drop
+      saved-rw-start-toggle FALSE ( FALSE )
+      EXIT                        ( FALSE )
+   THEN
+   -rot                      ( pt ed-type toggle buffer length dp mps head )
+   dup >r                      ( pt ed-type toggle buffer length dp mps head )
+   fill-TD-list r>  TRUE      ( pt et head TRUE )
+;
+
+
+\ Enqueue the ED with the appropriate list
+
+
+: (ed-ready-rw)  ( pt et  -- - | toggle FALSE )
+   nip           ( et )
+   FALSE TO case-failed  CASE
+      0   OF \ Control List. Queue the ED to control list
+      0 TO saved-list-type
+      saved-rw-ed hcctrhead rl!-le
+      HC-enable-control-list-processing
+      ENDOF
+      1   OF \ Bulk List. Queue the ED to bulk list
+      1 TO saved-list-type
+      saved-rw-ed hcbulkhead rl!-le
+      HC-enable-bulk-list-processing
+      ENDOF
+      2   OF \ Interrupt List.
+      2 TO saved-list-type
+      saved-rw-ed hchccareg rl at -le rl!-le
+      HC-enable-interrupt-list-processing
+      ENDOF
+      dup OF
+      saved-rw-ed ed>tdqhp l at -le (free-td-list)
+      saved-rw-ed free-ed
+      TRUE TO case-failed
+      ENDOF
+   ENDCASE
+   case-failed  IF
+      saved-rw-start-toggle FALSE ( toggle FALSE )
+      EXIT
+   THEN
+   TRUE                           ( TRUE )
+;
+
+\  Wait for TDs to return to the Done Q.
+
+: (wait-td-retire) ( -- )
+   0 TO num-rw-retired-tds
+   FALSE TO while-failed
+   BEGIN
+      num-rw-retired-tds num-rw-tds <           ( TRUE | FALSE )
+      while-failed FALSE =  and                 ( TRUE | FALSE )
+      WHILE
+      d# 5000 (wait-for-done-q)                  ( TD-list TRUE|FALSE )
+      IF
+         dup find-td-list-tail-and-size nip         ( td-list size )
+         num-rw-retired-tds + TO num-rw-retired-tds ( td-list )
+         dup (td-list-status)                   ( td-list failed-TD CC )
+         IF
+            dup 4 =
+            IF
+               saved-list-type
+               CASE
+                  0 OF
+		               0 0 control-std-clear-feature
+		               s" clear feature " usb-debug-print
+                  ENDOF
+                  1 OF                             \ clean bulk stalled
+                     s" clear bulk when stalled " usb-debug-print
+		               disable-bulk-list-processing   \ disable procesing
+                     saved-rw-ed ed>eattr l at -le dup \ extract
+                     780 and 7 rshift 80 or         \ endpoint and
+                     swap 7f and                    \ usb addr
+                     control-std-clear-feature
+		            ENDOF
+                  2 OF
+		               0 saved-rw-ed ed>eattr l at -le
+                     control-std-clear-feature
+		            ENDOF
+		            dup OF
+		               s" unknown status " usb-debug-print
+		            ENDOF
+               ENDCASE
+            ELSE                             ( td-list failed-TD CC )
+               ."  TD failed  " 5b emit .s 5d emit cr
+               5040 error" (USB) device transaction error (wait-td-retire)."
+               ABORT
+            THEN
+            2drop drop
+            TRUE TO while-failed                \ transaction failed
+            NEXT-TD 0<>                         \ clean the TD if we
+            IF
+               NEXT-TD (free-td-list)           \ had a stalled
+   	      THEN
+         THEN
+         (free-td-list)
+      ELSE
+         drop                                   \ drop td-list pointer
+         scan-time? IF 2e emit THEN             \ show proceeding dots
+         TRUE TO while-failed
+	      s" time out wait for done" usb-debug-print
+	      20 ms     \ wait for bad device
+      THEN
+   REPEAT
+;
+
+
+\ Process retired TDs
+
+
+: (process-retired-td)   ( -- TRUE | FALSE )
+   saved-list-type  CASE
+      0 OF disable-control-list-processing ENDOF
+      1 OF disable-bulk-list-processing ENDOF
+      2 OF disable-interrupt-list-processing ENDOF
+   ENDCASE
+   saved-rw-ed ed>tdqhp l at -le 2 and 0<> IF 
+      1 
+      s" retired 1" usb-debug-print
+   ELSE
+      0 
+      s" retired 0" usb-debug-print
+   THEN
+   \ s" retired " usb-debug-print-val
+   WHILE-failed   IF
+      FALSE           ( FALSE )
+   ELSE
+      TRUE            ( TRUE )
+   THEN
+   saved-rw-ed free-ed
+;
+
+
+\ (DO-rw-endpoint): T1 12 80 0 0chis method is an privately visible function
+\ 		    to be used by the "rw-endpoint" the required
+\ 		    number OF times based on the actual length
+\ 		    to be transferred
+
+\ Arguments:
+\ pt: Packet type
+\     0 -> IN
+\     1 -> OUT
+\     2 -> SETUP
+\ et: Endpoint type
+\     0 -> Control
+\     1 -> Bulk
+\ toggle: Starting toggle for this transfer
+\ buffer length: Data buffer associated with the transfer limited
+\     accordingly by the "rw-endpoint" method to the
+\     value OF max packet size
+\ mps: Max Packet Size.
+\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent
+\          the USB addres and the upper 4-bits represent the Endpoint
+\          number.
+
+
+
+: (do-rw-endpoint)
+   ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+   4 pick              ( pt ed-type toggle buffer length mps address toggle )
+   TO saved-rw-start-toggle ( pt ed-type toggle buffer length mps address )
+   (ed-prepare-rw)     ( FALSE | pt ed-type toggle buffer length mps )
+    invert IF FALSE EXIT THEN
+   (td-prepare-rw)     ( FALSE | pt ed-type toggle buffer length mps head )
+   invert IF FALSE EXIT THEN
+   (td-data-rw)        ( FALSE | pt et head )
+   invert IF FALSE EXIT THEN
+   saved-rw-ed ed>tdqhp l!-le ( pt et )
+   saved-rw-ed ed>tdqhp l at -le td>ntd l at -le TO NEXT-TD \ save for a stalled
+   (ed-ready-rw)
+   invert IF FALSE EXIT THEN
+   (wait-td-retire)
+   (process-retired-td)         ( TRUE | FALSE )
+;
+
+
+\ rw-endpoint: The method is an externally visible method to be exported
+\	       to the child nodes. It uses the internal method
+\	       "(DO-rw-endpoint)", the required number OF times based on the
+\	       actual length OF transfer, so that the limitataion OF MAX-TDS
+\	       DO not hinder the transfer.
+
+\ Arguments:
+\ pt: Packet type
+\     0 -> IN
+\     1 -> OUT
+\     2 -> SETUP
+\ et: Endpoint type
+\     0 -> Control
+\     1 -> Bulk
+\ toggle: Starting toggle for this transfer
+\ buffer length: Data buffer associated with the transfer
+\ mps: Max Packet Size.
+\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent
+\          the USB addres and the upper 4-bits represent the Endpoint
+\          number.
+
+
+0 VALUE transfer-len
+0 VALUE mps-current
+0 VALUE addr-current
+0 VALUE usb-addr
+0 VALUE toggle-current
+0 VALUE type-current
+0 VALUE pt-current
+0 VALUE read-status
+0 VALUE counter
+0 VALUE residue
+
+
+: rw-endpoint
+   ( pt ed-type toggle buffer length mps address -- )
+   ( toggle TRUE |toggle FALSE )
+
+   \ a single transfer descriptor can point to a buffer OF
+   \ 8192 bytes a block on the CDROM has 2048 bytes
+   \ but a single transfer is constrained by the MPS
+
+   2 pick TO transfer-len  ( pt ed-type toggle buffer length mps address )
+   1 pick TO mps-current   ( pt ed-type toggle buffer length mps address )
+   TRUE TO read-status     ( pt ed-type toggle buffer length mps address )
+   transfer-len mps-current num-free-tds * <=  IF
+      (do-rw-endpoint)     ( toggle TRUE | toggle FALSE )
+      TO read-status       ( toggle )
+      TO toggle-current
+   ELSE
+      TO usb-addr          ( pt ed-type toggle buffer length mps )
+      2drop                ( pt ed-type toggle buffer )
+      TO addr-current      ( pt ed-type toggle )
+      TO toggle-current    ( pt ed-type )
+      TO type-current      ( pt )
+      TO pt-current
+      transfer-len mps-current num-free-tds * /mod  ( residue count )
+                           ( remainder=residue quotient=count )
+      TO counter           ( residue )
+      TO residue
+      mps-current num-free-tds * TO transfer-len   BEGIN
+         counter 0 >       ( TRUE | FALSE )
+         read-status TRUE = and   ( TRUE | FALSE )
+      WHILE
+         pt-current type-current toggle-current ( pt ed-type toggle )
+         addr-current transfer-len  ( pt ed-type toggle buffer length )
+         mps-current                ( pt ed-type toggle buffer length mps )
+         usb-addr (do-rw-endpoint)  ( toggle TRUE | toggle FALSE )
+         TO read-status             ( toggle )
+         TO toggle-current
+         addr-current transfer-len + TO addr-current
+         counter 1- TO counter
+      REPEAT
+      residue 0<>                    ( TRUE |FALSE )
+      read-status TRUE = and IF
+         residue TO transfer-len
+         pt-current type-current toggle-current ( pt ed-type toggle )
+         addr-current transfer-len   ( pt ed-type toggle buffer length )
+         mps-current                 ( pt ed-type toggle buffer length mps )
+         usb-addr (do-rw-endpoint)   ( toggle TRUE | toggle FALSE )
+         TO read-status
+         TO toggle-current
+      THEN
+   THEN
+   read-status invert  IF
+   THEN
+   toggle-current                    ( toggle )
+   read-status                       ( TRUE | FALSE )
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/vpd-bootlist.fs b/qemu-0.15.x/roms/SLOF/slof/fs/vpd-bootlist.fs
new file mode 100644
index 0000000..5a08215
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/vpd-bootlist.fs
@@ -0,0 +1,134 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+4 CONSTANT vpd-bootlist-size
+
+\ Bootable devices
+00 CONSTANT FLOPPY
+01 CONSTANT USB
+02 CONSTANT SAS
+03 CONSTANT SATA
+04 CONSTANT ISCSI
+05 CONSTANT ISCSICRITICAL
+06 CONSTANT NET
+07 CONSTANT NOTSPECIFIED
+08 CONSTANT HDD0
+09 CONSTANT HDD1
+0a CONSTANT HDD2
+0b CONSTANT HDD3
+0c CONSTANT CDROM
+0e CONSTANT HDD4
+10 CONSTANT SCSI
+
+: check-bootlist ( -- true | false )
+   vpd-bootlist l@
+   dup 0= IF
+      ( bootlist == 0 means that probably nothing from vpd has been received )
+      s" Boot list could not be read from VPD" log-string cr
+      s" Boot watchdog has been rearmed" log-string cr
+      2 set-watchdog
+      EXIT
+   THEN
+
+   FFFFFFFF = IF
+      ( bootlist all FFs means that the vpd has no useful information )
+      .banner
+      -6b boot-exception-handler
+      \ The next message is duplicate, but sent w. log-string
+      s" Boot list successfully read from VPD but no useful information received" log-string cr
+      s" Please specify the boot device in the management module" log-string cr
+      s" Specified Boot Sequence not valid" mm-log-warning
+      false
+      EXIT
+   THEN
+
+   true
+;
+
+\ the following words are necessary for vpd-boot-import
+defer set-boot-device
+defer add-boot-device
+
+\ select-install? is a flag which is used in the SMS panel #20
+\ "Select/Install Boot Devices".
+\ This panel can be used to temporarily override the boot device.
+false VALUE select-install?
+
+\ select/install-path stores string address and string length of the
+\ device node chosen in the SMS panel #20 "Select/Install Boot Devices"
+\ This device node is prepended to the boot path if select-install? is
+\ true.
+CREATE select/install-path 2 cells allot
+
+\ Import boot device list from VPD
+\ If none, keep the existing list in NVRAM
+\ This word can be used to overwrite read-bootlist if wanted
+
+: vpd-boot-import  ( -- )
+   0 0 set-boot-device
+
+   select-install? IF
+      select/install-path 2@ add-boot-device
+   THEN
+
+   vpd-read-bootlist
+   check-bootlist  IF
+      4 0  DO  vpd-bootlist i + c@
+         CASE
+            6  OF  \ cr s" 2B Booting from Network" log-string cr
+               furnish-boot-file strdup add-boot-device
+	    ENDOF
+
+            HDD0  OF  \ cr s" 2B Booting from hdd0" log-string cr
+               s" disk hdd0" add-boot-device ENDOF
+
+            HDD1  OF  \ cr s" 2B Booting from hdd1" log-string cr
+               s" hdd1" add-boot-device ENDOF
+
+            HDD2  OF  \ cr s" 2B Booting from hdd2" log-string cr
+               s" hdd2" add-boot-device ENDOF
+
+            HDD3  OF  \ cr s" 2B Booting from hdd3" log-string cr
+               s" hdd3" add-boot-device ENDOF
+
+            CDROM OF  \ cr s" 2B Booting from CDROM" log-string cr
+               s" cdrom" add-boot-device ENDOF
+
+            HDD4  OF  \ cr s" 2B Booting from hdd4" log-string cr
+               s" hdd4" add-boot-device ENDOF
+
+            F  OF  \ cr s" 2B Booting from SAS - w. Timeout" log-string cr
+		s" sas" add-boot-device ENDOF
+
+            SCSI  OF  \ cr s" 2B Booting from SAS - Continuous Retry" log-string cr
+		s" sas" add-boot-device ENDOF
+
+         ENDCASE
+      LOOP
+      bootdevice 2@ nip
+      IF 0
+      ELSE
+	 \ Check for all no device -> use boot-device  
+	 vpd-bootlist l@ 07070707 = IF 0 ELSE -6b THEN 
+      THEN
+   ELSE -6a THEN
+   boot-exception-handler
+;
+
+: vpd-bootlist-restore-default  ( -- )
+   NOTSPECIFIED vpd-bootlist 0 + c!
+   NOTSPECIFIED vpd-bootlist 1 + c!
+   NOTSPECIFIED vpd-bootlist 2 + c!
+   HDD0 vpd-bootlist 3 + c!
+   vpd-write-bootlist
+;
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/fs/xmodem.fs b/qemu-0.15.x/roms/SLOF/slof/fs/xmodem.fs
new file mode 100644
index 0000000..a111708
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/fs/xmodem.fs
@@ -0,0 +1,120 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+01 CONSTANT XM-SOH   \ Start of header
+04 CONSTANT XM-EOT   \ End-of-transmission
+06 CONSTANT XM-ACK   \ Acknowledge
+15 CONSTANT XM-NAK   \ Neg. acknowledge
+
+0 VALUE xm-retries   \ Retry count
+0 VALUE xm-block#
+
+
+\ *
+\ * Internal function:
+\ * wait <timeout> seconds for a new character
+\ *
+: xmodem-get-byte  ( timeout -- byte|-1 )
+   d# 1000 *
+   0 DO
+      key? IF key UNLOOP EXIT THEN
+      1 ms
+   LOOP
+   -1
+;
+
+
+\ *
+\ * Internal function:
+\ * Receive one XMODEM packet, check block number and check sum.
+\ *
+: xmodem-rx-packet  ( address -- success? )
+   1 xmodem-get-byte    \ Get block number
+   dup 0 < IF
+      2drop false EXIT  \ Timeout
+   THEN
+   1 xmodem-get-byte    \ Get neg. block number
+   dup 0 < IF
+      3drop false EXIT  \ Timeout
+   THEN
+   rot 0                ( blk# ~blk# address chksum )
+   80 0 DO
+      1 xmodem-get-byte dup 0 < IF     ( blk# ~blk# address chksum byte )
+         3drop 2drop UNLOOP FALSE EXIT
+      THEN
+      dup 3 pick c!            ( blk# ~blk# address chksum byte )
+      + swap 1+ swap           ( blk# ~blk# address+1 chksum' )
+   LOOP
+   ( blk# ~blk# address chksum )
+   \ Check sum:
+   0ff and
+   1 xmodem-get-byte <> IF
+      \ CRC failed!
+      3drop FALSE EXIT
+   THEN
+   drop                        ( blk# ~blk# )
+   \ finally check if block numbers are ok:
+   over xm-block# <> IF
+      \ Wrong block number!
+      2drop FALSE EXIT
+   THEN                        ( blk# ~blk# )
+   ff xor =
+;
+
+
+\ *
+\ * Internal function:
+\ * Load file to given address via XMODEM protocol
+\ *
+: (xmodem-load)  ( address -- bytes )
+   1 to xm-block#
+   0 to xm-retries
+   dup
+   BEGIN
+      d# 10 xmodem-get-byte dup >r
+      CASE
+         XM-SOH OF
+            dup xmodem-rx-packet IF
+               \ A packet has been received successfully
+               XM-ACK emit
+               80 +                     ( start-addr next-addr  R: rx-byte )
+               0 to xm-retries                    \ Reset retry count
+               xm-block# 1+ ff and to xm-block#   \ Increase current block#
+            ELSE
+               \ Error while receiving packet
+               XM-NAK emit
+               xm-retries 1+ to xm-retries  \ Increase retry count
+            THEN
+         ENDOF
+         XM-EOT OF
+            XM-ACK emit
+         ENDOF
+         dup OF
+            XM-NAK emit
+            xm-retries 1+ to xm-retries  \ Increase retry count
+         ENDOF
+      ENDCASE
+      r> XM-EOT =
+      xm-retries d# 10 >= OR
+   UNTIL                         ( start-address end-address )
+   swap -                        ( bytes received )
+;
+
+
+\ *
+\ * Load file to load-base via XMODEM protocol
+\ *
+: xmodem-load  ( -- bytes )
+   cr ." Waiting for start of XMODEM upload..." cr
+   load-base (xmodem-load)
+;
diff --git a/qemu-0.15.x/roms/SLOF/slof/lowmem.S b/qemu-0.15.x/roms/SLOF/slof/lowmem.S
new file mode 100644
index 0000000..9aaa9f7
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/lowmem.S
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <xvect.h>
+
+	.globl _start
+	/* All exception vectors *******************/
+_start:
+	.org 0x100
+	/* check if Master / Slave *****************/
+	/* Master will go to XVECT_M_HANDLER       */
+	/* Slave  will go to XVECT_S_HANDLER       */
+#ifdef SECONDARY_CPUS_STOPPED
+	ld	r3,XVECT_S_HANDLER(0)
+	mfspr	r0, PIR
+	cmpwi	r0, 0
+	bne	0f
+#endif
+	ld	r3,XVECT_M_HANDLER(0)
+0:
+	mtctr	r3
+	li	r0,0x100
+	bctr
+
+	/* FIXME: Also need 0280, 0380, 0f20, etc. */
+
+	.irp i, 0x0200,0x0280,0x0300,0x0380,0x0400,0x0480,0x0500,0x0600,0x0700, \
+		0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, \
+		0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
+		0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+		0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+		0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00,0x2f00
+	.org \i
+
+	/* enable this if you get exceptions before the console works    */
+	/* this will allow using the hardware debugger to see where      */
+	/* it traps, and with what register values etc.                  */
+	// b	$
+
+	mtsprg	0,r0
+	mfctr	r0
+	mtsprg  2,r0
+	mflr	r0
+	mtsprg  3,r0
+	ld	r0, XVECT_M_HANDLER(0)
+	mtctr	r0
+	li	r0,\i
+	bctr
+	.endr
+
+
+	.org XVECT_M_HANDLER
+	.quad 0
+
+	.org XVECT_S_HANDLER
+	.quad 0
+
+	.org XVECT_TOPADDR
+	.byte 0x36		# to fill out to exactly 16kB
diff --git a/qemu-0.15.x/roms/SLOF/slof/ofw.S b/qemu-0.15.x/roms/SLOF/slof/ofw.S
new file mode 100644
index 0000000..a8e9c91
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ofw.S
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <xvect.h>
+
+	.section ".slof.loader","ax"
+
+	/* this only works if paflof is running below 4GB */
+	lis	r31, fdt_start at h	/* save address of */
+	ori	r31, r31, fdt_start at l	/* flattened device */
+	std	r3, 0(r31)		/* tree */
+
+	/* this only works if paflof is running below 4GB */
+	lis	r31, romfs_base at h	/* save address of */
+	ori	r31, r31, romfs_base at l	/* the romfs */
+	std	r4, 0(r31)
+
+	/* this only works if paflof is running below 4GB */
+	lis	r31, epapr_magic at h	/* if it is an epapr compliant */
+	ori	r31, r31, epapr_magic at l	/* low level firmware; then r6 */
+	std	r6, 0(r31)		/* contains the epapr magic */
+
+	/* fill in handler address */
+
+	/* this only works if paflof is running below 4GB */
+	mfmsr	r0
+	mtsrr1	r0
+	lis	r3, _slof_text at h
+	ori	r3, r3, _slof_text at l
+	ld	r3, 0(r3)
+	std	r3, XVECT_M_HANDLER(0)
+
+	/* GO! */
+	ba	0x100
diff --git a/qemu-0.15.x/roms/SLOF/slof/paflof.c b/qemu-0.15.x/roms/SLOF/slof/paflof.c
new file mode 100644
index 0000000..62f47de
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/paflof.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+
+#define XSTR(x) #x
+#define ISTR(x,y) XSTR(x.y)
+#undef unix
+
+#include "paflof.h"
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+#include ISTR(TARG,h)
+
+#define LAST_ELEMENT(x) x[sizeof x / sizeof x[0] - 1]
+
+/* Hack to get around static inline issues */
+#include "../lib/libhvcall/libhvcall.h"
+
+unsigned long fdt_start;
+unsigned long romfs_base;
+unsigned long epapr_magic;
+unsigned char hash_table[HASHSIZE*CELLSIZE];
+
+#include ISTR(TARG,c)
+
+// the actual engine
+long engine(int mode, long param_1, long param_2)
+{
+	// For Exceptions:
+	//	mode = ENGINE_MODE_PARAM_1 | MODE_PARAM_2
+	//	(param_1 = error, param_2 = reason)
+	//
+	// For Push:
+	//	mode = ENGINE_MODE_PARAM_1 | ENGINE_MODE_NOP
+	//
+	// For Pop:
+	//	mode = ENGINE_MODE_NOP | ENGINE_MODE_POP
+	//
+	// For Evaluate:
+	//	mode = ENGINE_MODE_PARAM_1 | MODE_PARAM_2 | ENGINE_MODE_EVAL
+	//	(param_1 = strlen(string), param_2 = string)
+
+	cell *restrict ip;
+	cell *restrict cfa;
+	static cell handler_stack[160];
+	static cell c_return[2];
+	static cell dummy;
+
+	#include "prep.h"
+	#include "dict.xt"
+
+	static int init_engine = 0;
+	if (init_engine == 0) {
+		// one-time initialisation
+		init_engine = 1;
+		LAST_ELEMENT(xt_FORTH_X2d_WORDLIST).a = xt_LASTWORD;
+
+		// stack-pointers
+		dp = the_data_stack - 1;
+		rp = handler_stack - 1;
+
+		// return-address for "evaluate" personality
+		dummy.a = &&over;
+		c_return[1].a = &dummy;
+	}
+
+	if (mode & ENGINE_MODE_PARAM_2) {
+		(++dp)->n = param_2;
+	}
+	if (mode & ENGINE_MODE_PARAM_1) {
+		(++dp)->n = param_1;
+	}
+
+	if (mode & ENGINE_MODE_NOP ) {
+		goto over;
+	}
+
+        if (mode & ENGINE_MODE_EVAL) {
+		(++rp)->a = c_return;
+		ip = xt_EVALUATE + 2 + ((10 + CELLSIZE - 1) / CELLSIZE);
+	} else {
+		ip = xt_SYSTHROW;
+        }
+
+	#include "prim.code"
+	#include "board.code"
+	#include ISTR(TARG,code)
+
+
+	// Only reached in case of non-exception call
+over:	if (mode & ENGINE_MODE_POP) {
+		return ((dp--)->n);
+	} else {
+		return 0;
+	}
+}
diff --git a/qemu-0.15.x/roms/SLOF/slof/paflof.h b/qemu-0.15.x/roms/SLOF/slof/paflof.h
new file mode 100644
index 0000000..885c948
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/paflof.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+
+extern long engine(int, long, long);
+
+#define TIBSIZE 256
+
+#define POCKETSIZE 256
+#define NUMPOCKETS 16
+
+#define HASHSIZE 0x1000
+
+// engine mode bits
+#define ENGINE_MODE_PARAM_1	0x0001
+#define ENGINE_MODE_PARAM_2	0x0002
+#define ENGINE_MODE_NOP		0x0004
+#define ENGINE_MODE_EVAL	0x0008
+#define ENGINE_MODE_POP		0x0010
+
+// engine calls
+#define forth_eval(s)	engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_PARAM_2|ENGINE_MODE_EVAL,	\
+				strlen((s)), (long)(s))
+#define forth_eval_pop(s)	engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_PARAM_2|ENGINE_MODE_EVAL|ENGINE_MODE_POP,	\
+				strlen((s)), (long)(s))
+
+#define forth_push(v)	engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_NOP, v, 0)
+
+#define forth_pop()	engine(ENGINE_MODE_NOP|ENGINE_MODE_POP, 0, 0)
diff --git a/qemu-0.15.x/roms/SLOF/slof/ppc64.c b/qemu-0.15.x/roms/SLOF/slof/ppc64.c
new file mode 100644
index 0000000..20d9270
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ppc64.c
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+
+/* the exception frame should be page aligned
+ * the_exception_frame is used by the handler to store a copy of all
+ * registers after an exception; this copy can then be used by paflof's
+ * exception handler to printout a register dump */
+cell the_exception_frame[0x400 / CELLSIZE] __attribute__ ((aligned(PAGE_SIZE)));;
+
+/* the_client_frame is the register save area when starting a client */
+cell the_client_frame[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+cell the_client_stack[0x8000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+/* THE forth stack */
+cell the_data_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+/* the forth return stack */
+cell the_return_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+
+/* forth stack and return-stack pointers */
+cell *restrict dp;
+cell *restrict rp;
+
+/* terminal input buffer */
+cell the_tib[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+/* temporary string buffers */
+char the_pockets[NUMPOCKETS * POCKETSIZE] __attribute__ ((aligned(0x100)));
+
+cell the_comp_buffer[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100)));
+
+cell the_heap[HEAP_SIZE / CELLSIZE] __attribute__ ((aligned(0x1000)));
+cell *the_heap_start = &the_heap[0];
+cell *the_heap_end = &the_heap[HEAP_SIZE / CELLSIZE];
+
+extern void io_putchar(unsigned char);
+
+
+static unsigned long __attribute__((noinline))
+call_c(cell arg0, cell arg1, cell arg2, cell entry)
+{
+	register unsigned long r3 asm("r3") = arg0.u;
+	register unsigned long r4 asm("r4") = arg1.u;
+	register unsigned long r5 asm("r5") = arg2.u;
+	register unsigned long r6 = entry.u         ;
+
+	asm volatile("mflr 31 ; mtctr %4 ; bctrl ; mtlr 31"
+		     : "=r" (r3)
+		     : "r" (r3), "r" (r4), "r" (r5), "r" (r6)
+		     : "ctr", "r6", "r7", "r8", "r9", "r10", "r11",
+		       "r12", "r13", "r31", "lr", "cc");
+
+	return r3;
+}
+
+
+long
+writeLogByte_wrapper(long x, long y)
+{
+	unsigned long result;
+
+	SET_CI;
+	result = writeLogByte(x, y);
+	CLR_CI;
+
+	return result;
+}
+
+
+/**
+ * Standard write function for the libc.
+ *
+ * @param fd    file descriptor (should always be 1 or 2)
+ * @param buf   pointer to the array with the output characters
+ * @param count number of bytes to be written
+ * @return      the number of bytes that have been written successfully
+ */
+int
+write(int fd, const void *buf, int count)
+{
+	int i;
+	char *ptr = (char *)buf;
+
+	if (fd != 1 && fd != 2)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		if (*ptr == '\n')
+			io_putchar('\r');
+		io_putchar(*ptr++);
+	}
+
+	return i;
+}
+
+/* This should probably be temporary until a better solution is found */
+void
+asm_cout(long Character, long UART, long NVRAM __attribute__((unused)))
+{
+	if (UART)
+		io_putchar(Character);
+}
diff --git a/qemu-0.15.x/roms/SLOF/slof/ppc64.code b/qemu-0.15.x/roms/SLOF/slof/ppc64.code
new file mode 100644
index 0000000..49dc863
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ppc64.code
@@ -0,0 +1,264 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+// This file contains the implementation of the Forth code words specific
+// to PowerPC64.  Some of this is 970-only.
+
+// The I/O accesses themselves.
+PRIM(RB_X40) GET_CHAR1; SET_CI; GET_CHAR2; CLR_CI; GET_CHAR3; MIRP
+PRIM(RB_X21) PUT_CHAR1; SET_CI; PUT_CHAR2; CLR_CI; MIRP
+PRIM(RW_X40) GET_WORD1; SET_CI; GET_WORD2; CLR_CI; GET_WORD3; MIRP
+PRIM(RW_X21) PUT_WORD1; SET_CI; PUT_WORD2; CLR_CI; MIRP
+PRIM(RL_X40) GET_LONG1; SET_CI; GET_LONG2; CLR_CI; GET_LONG3; MIRP
+PRIM(RL_X21) PUT_LONG1; SET_CI; PUT_LONG2; CLR_CI; MIRP
+PRIM(RX_X40) GET_XONG1; SET_CI; GET_XONG2; CLR_CI; GET_XONG3; MIRP
+PRIM(RX_X21) PUT_XONG1; SET_CI; PUT_XONG2; CLR_CI; MIRP
+
+// 970-specific CPU registers.
+// Don't use on P7 !
+PRIM(HID0_X21)
+	unsigned long hid0 = TOS.u;
+	asm volatile("sync ; mtspr 1008,%0 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008" : "+r"(hid0));
+	POP;
+MIRP
+
+PRIM(HID0_X40)
+	PUSH;
+	asm volatile("mfspr %0,1008" : "=r"(TOS));
+MIRP
+
+PRIM(HID1_X21)
+	unsigned long hid1 = TOS.u;
+	asm volatile("mtspr 1009,%0 ; mtspr 1009,%0 ; isync" : : "r"(hid1));
+	POP;
+MIRP
+
+PRIM(HID1_X40)
+	PUSH;
+	asm volatile("mfspr %0,1009" : "=r"(TOS));
+MIRP
+
+PRIM(HID4_X21)
+	unsigned long hid4 = TOS.u;
+	asm volatile("sync ; mtspr 1012,%0 ; isync" : : "r"(hid4));
+	POP;
+MIRP
+
+PRIM(HID4_X40)
+	PUSH;
+	asm volatile("mfspr %0,1012" : "=r"(TOS));
+MIRP
+
+PRIM(HID5_X21)
+	unsigned long hid5 = TOS.u;
+	asm volatile("mtspr 1014,%0" : : "r"(hid5));
+	POP;
+MIRP
+
+PRIM(HID5_X40)
+	PUSH;
+	asm volatile("mfspr %0,1014" : "=r"(TOS));
+MIRP
+
+// PowerPC special registers.
+PRIM(MSR_X21)
+	unsigned long msr = TOS.u;
+	asm volatile("mtmsrd %0" : : "r"(msr));
+	POP;
+MIRP
+
+PRIM(MSR_X40)
+	PUSH;
+	asm volatile("mfmsr %0" : "=r"(TOS));
+MIRP
+
+PRIM(SDR1_X21)
+	unsigned long sdr1 = TOS.u;
+	asm volatile("mtsdr1 %0" : : "r"(sdr1));
+	POP;
+MIRP
+
+PRIM(SDR1_X40)
+	PUSH;
+	asm volatile("mfsdr1 %0" : "=r"(TOS));
+MIRP
+
+PRIM(PVR_X40)
+	PUSH;
+	asm volatile("mfpvr %0" : "=r"(TOS));
+MIRP
+
+PRIM(PIR_X40)
+	PUSH;
+	asm volatile("mfspr %0,1023" : "=r"(TOS));
+MIRP
+
+PRIM(TBL_X40)
+	PUSH;
+	asm volatile("mftbl %0" : "=r"(TOS));
+MIRP
+
+PRIM(TBU_X40)
+	PUSH;
+	asm volatile("mftbu %0" : "=r"(TOS));
+MIRP
+
+PRIM(DABR_X21)
+	unsigned long dabr = TOS.u;
+	asm volatile("mtspr 1013,%0" : : "r"(dabr));
+	POP;
+MIRP
+
+PRIM(DABR_X40)
+	PUSH;
+	asm volatile("mfspr %0,1013" : "=r"(TOS));
+MIRP
+
+PRIM(HIOR_X21)
+	unsigned long dabr = TOS.u;
+	asm volatile("mtspr 311,%0" : : "r"(dabr));
+	POP;
+MIRP
+
+PRIM(HIOR_X40)
+	PUSH;
+	asm volatile("mfspr %0,311" : "=r"(TOS));
+MIRP
+
+
+
+PRIM(SPRG0_X21)
+	unsigned long sprg0 = TOS.u;
+	asm volatile("mtsprg0 %0" : "+r"(sprg0));
+	POP;
+MIRP
+
+PRIM(SPRG0_X40)
+	PUSH;
+	asm volatile("mfsprg0 %0" : "=r"(TOS));
+MIRP
+
+PRIM(SPRG1_X21)
+	unsigned long sprg1 = TOS.u;
+	asm volatile("mtsprg1 %0" : "+r"(sprg1));
+	POP;
+MIRP
+
+PRIM(SPRG1_X40)
+	PUSH;
+	asm volatile("mfsprg1 %0" : "=r"(TOS));
+MIRP
+
+PRIM(SPRG2_X21)
+	unsigned long sprg2 = TOS.u;
+	asm volatile("mtsprg2 %0" : "+r"(sprg2));
+	POP;
+MIRP
+
+PRIM(SPRG2_X40)
+	PUSH;
+	asm volatile("mfsprg2 %0" : "=r"(TOS));
+MIRP
+
+PRIM(SPRG3_X21)
+	unsigned long sprg3 = TOS.u;
+	asm volatile("mtsprg3 %0" : "+r"(sprg3));
+	POP;
+MIRP
+
+PRIM(SPRG3_X40)
+	PUSH;
+	asm volatile("mfsprg3 %0" : "=r"(TOS));
+MIRP
+
+PRIM(HSPRG0_X21)
+	unsigned long hsprg0 = TOS.u;
+	asm volatile("mtspr 304,%0" : "+r"(hsprg0));
+	POP;
+MIRP
+
+PRIM(HSPRG0_X40)
+	PUSH;
+	asm volatile("mfspr %0,304" : "=r"(TOS));
+MIRP
+
+PRIM(HSPRG1_X21)
+	unsigned long hsprg1 = TOS.u;
+	asm volatile("mtspr 305,%0" : "+r"(hsprg1));
+	POP;
+MIRP
+
+PRIM(HSPRG1_X40)
+	PUSH;
+	asm volatile("mfspr %0,305" : "=r"(TOS));
+MIRP
+
+
+PRIM(MMCR0_X21)
+	unsigned long mmcr0 = TOS.u;
+	asm volatile("sync ; mtspr 795,%0 ; isync" : : "r"(mmcr0));
+	POP;
+MIRP
+
+PRIM(PMC1_X40)
+	PUSH;
+	asm volatile("sync ; mfspr %0,787" : "=r"(TOS));
+MIRP
+
+PRIM(ICBI)
+	asm volatile("dcbst 0,%0 ; sync ; icbi 0,%0 ; sync ; isync" : : "r"(TOS));
+	POP;
+MIRP
+
+// Call into the client program.
+PRIM(JUMP_X2d_CLIENT)
+	TOS.u = call_client(TOS);
+MIRP
+
+
+// Hang.  Useful for debugging, believe it or not.
+PRIM(CRASH)
+	for (;;) ;
+MIRP
+
+PRIM(START_X2d_RTAS)
+	cell e = TOS; POP;
+	cell p1 = TOS; POP;
+	cell p0 = TOS;
+	TOS.u = call_c(p0, p1, (cell)0UL, e);
+MIRP
+
+PRIM(CALL_X2d_C)
+	cell e = TOS; POP;
+	cell p2 = TOS; POP;
+	cell p1 = TOS; POP;
+	cell p0 = TOS;
+	TOS.u = call_c(p0, p1, p2, e);
+MIRP
+
+PRIM(FLUSHCACHE)
+	type_u n = TOS.u; POP;
+	unsigned char* p = TOS.a; POP;
+	flush_cache(p, n);	
+MIRP
+
+PRIM(DEC_X21)
+	unsigned long dec = TOS.u;
+	asm volatile("mtdec %0" : "+r"(dec));
+	POP;
+MIRP
+
+PRIM(DEC_X40)
+	PUSH;
+	asm volatile("mfdec %0" : "=r"(TOS));
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/slof/ppc64.h b/qemu-0.15.x/roms/SLOF/slof/ppc64.h
new file mode 100644
index 0000000..59a1b90
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ppc64.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include "types.h"
+
+#define PAGE_SIZE 4096
+#define HEAP_SIZE 0x800000
+
+#ifdef CPU_PPC970
+#define SET_CI set_ci()
+#define CLR_CI clr_ci()
+#else
+#define SET_CI
+#define CLR_CI
+#endif
+
+// The big Forth source file that contains everything but the core engine.
+// We include it as a hunk of data into the C part of SLOF; at startup
+// time, this will be EVALUATE'd.
+extern char _binary_OF_fsi_start[], _binary_OF_fsi_end[];
+
+extern cell the_mem[];   /* Space for the dictionary / the HERE pointer */
+
+extern cell *restrict dp;
+extern cell *restrict rp;
+
+void client_entry_point();
+
+extern unsigned long call_client(cell);
+extern long c_romfs_lookup(long, long, void *);
+extern long writeLogByte(long, long);
diff --git a/qemu-0.15.x/roms/SLOF/slof/ppc64.in b/qemu-0.15.x/roms/SLOF/slof/ppc64.in
new file mode 100644
index 0000000..56ab66d
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ppc64.in
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+// The Forth code words (primitives) that are specific to PowerPC64.
+
+// I/O accesses.
+cod(RB@)
+cod(RB!)
+cod(RW@)
+cod(RW!)
+cod(RL@)
+cod(RL!)
+cod(RX@)
+cod(RX!)
+
+// CPU register accesses.
+cod(HID0!)
+cod(HID0@)
+cod(HID1!)
+cod(HID1@)
+cod(HID4!)
+cod(HID4@)
+cod(HID5!)
+cod(HID5@)
+cod(MSR@)
+cod(MSR!)
+cod(SDR1@)
+cod(SDR1!)
+cod(PVR@)
+cod(PIR@)
+cod(TBL@)
+cod(TBU@)
+cod(DABR@)
+cod(DABR!)
+cod(HIOR@)
+cod(HIOR!)
+cod(SPRG0@)
+cod(SPRG0!)
+cod(SPRG1@)
+cod(SPRG1!)
+cod(SPRG2@)
+cod(SPRG2!)
+cod(SPRG3@)
+cod(SPRG3!)
+cod(HSPRG0@)
+cod(HSPRG0!)
+cod(HSPRG1@)
+cod(HSPRG1!)
+cod(DEC@)
+cod(DEC!)
+
+cod(MMCR0!)
+cod(PMC1@)
+
+cod(ICBI)
+
+
+// The start address of a binary payload.
+//con(PAYLOAD (type_u)_binary_payload_start)
+
+// Calling the client program.
+con(CLIENT-ENTRY-POINT (type_u)client_entry_point)
+cod(JUMP-CLIENT)
+dfr(CLIENTINTERFACE)
+
+
+con(ROMFS-LOOKUP-ENTRY (type_u) c_romfs_lookup)
+
+// not very elegant... but the only way it works for me
+con(.WRITE-LOG-BYTE-ENTRY (type_u) writeLogByte_wrapper)
+col(WRITE-LOG-BYTE-ENTRY .WRITE-LOG-BYTE-ENTRY @)
+
+cod(CALL-C)
+cod(START-RTAS)
+
+
+cod(FLUSHCACHE)
+
+
+// Hang.
+cod(CRASH)
+
+var(DAAR 0x00f00000)
+col(DUMBER DAAR @ C! LIT(1) DAAR +!)
+
+dfr(BOOT-EXCEPTION-HANDLER)
+
+col(NICEINIT DOTICK DROP DOTO EMIT DOTICK ((FIND)) DOTO (FIND) DOTICK 2DROP DOTO (REVEAL) LIT((type_u)_binary_OF_fsi_start) LIT((type_u)_binary_OF_fsi_end) OVER - DOTICK EVALUATE CATCH BOOT-EXCEPTION-HANDLER)
+
+static cell xt_SYSTHROW[] = { _0 RDEPTH_X21 DUP LIT(0x100) _X3d _0BRANCH(5) SWAP DROP NICEINIT BRANCH(7) DUP LIT(0x3800) _X3d _0BRANCH(1) CLIENTINTERFACE PRINT_X2d_STATUS QUIT };
+
+// sentinel, leave it here!
+col(LASTWORD )
+
diff --git a/qemu-0.15.x/roms/SLOF/slof/prep.h b/qemu-0.15.x/roms/SLOF/slof/prep.h
new file mode 100644
index 0000000..03950ba
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/prep.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+
+#define _N(_n)		{ .n = _n },
+#define _O(_n)		{ .n = CELLSIZE * (_n) },
+#define _C(_c)		{ .c = _c },
+#define _A(_a)		{ .a = _a },
+
+#define ref(_xt, _nname) _A(xt_ ## _xt + _nname)
+#define header(_xt, _header...) static cell xt_ ## _xt[] = { _header
+#define def(_xts...) _xts };
+#define lab(_xt) _A(&&code_ ## _xt)
+
+#define DOCOL lab(DOCOL)
+#define DODOES lab(DODOES)
+#define DODEFER lab(DODEFER)
+#define DOALIAS lab(DOALIAS)
+#define DOCON lab(DOCON)
+#define DOVAL lab(DOVAL)
+#define DOFIELD lab(DOFIELD)
+#define DOVAR lab(DOVAR)
+#define DOBUFFER_X3a lab(DOBUFFER_X3a)
+
+#define cod(_xt) def(lab(_xt))
+#define col(_xt, _def...) def(DOCOL _def SEMICOLON)
+#define con(_xt, _def) def(DOCON _N(_def))
+#define dfr(_xt) def(DODEFER _N(0))
+#define val(_xt, _def) def(DOVAL _N(_def))
+#define var(_xt, _def) def(DOVAR _N(_def))
+
+
+#define raw(_xt, _def) def(_def)
+#define str(_xt, _def...) def(_def)
diff --git a/qemu-0.15.x/roms/SLOF/slof/prim.code b/qemu-0.15.x/roms/SLOF/slof/prim.code
new file mode 100644
index 0000000..d1ac61f
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/prim.code
@@ -0,0 +1,634 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+
+#define NEXT00	goto *cfa->a
+#define NEXT0	cfa = ip->a; NEXT00
+#define NEXT	ip++; NEXT0
+
+#define PRIM(name) code_##name: { \
+		   asm("#### " #name); \
+		   void *w = (cfa = (++ip)->a)->a;
+#define MIRP	   goto *w; }
+
+
+
+	// start interpreting
+	NEXT0;
+
+
+
+// These macros could be replaced to allow for TOS caching etc.
+#define TOS (*dp)
+#define NOS (*(dp-1))
+#define POP dp--
+#define PUSH dp++
+
+#define RTOS (*rp)
+#define RNOS (*(rp-1))
+#define RPOP rp--
+#define RPUSH rp++
+
+
+
+
+// For terminal input.
+PRIM(TIB) PUSH; TOS.a = the_tib; MIRP
+
+// For pockets (temporary string buffers).
+PRIM(POCKETS) PUSH; TOS.a = the_pockets; MIRP
+
+// exception register area
+PRIM(EREGS) PUSH; TOS.a = the_exception_frame; MIRP
+
+// client register area
+PRIM(CIREGS) PUSH; TOS.a = the_client_frame; MIRP
+
+// Client stack
+//	(According to the PowerPC ABI the stack-pointer points to the
+//	 lowest **USED** value.
+//	 I.e. it is decremented before a new element is stored on the
+//	 stack.)
+PRIM(CISTACK) PUSH; TOS.a = the_client_stack
+                            + (sizeof(the_client_stack) / CELLSIZE); MIRP
+
+// compile-in-interpret buffer
+PRIM(COMP_X2d_BUFFER) PUSH; TOS.a = the_comp_buffer; MIRP
+
+// Heap pointers
+PRIM(HEAP_X2d_START) PUSH; TOS.a = the_heap_start; MIRP
+PRIM(HEAP_X2d_END) PUSH; TOS.a = the_heap_end; MIRP
+
+// FDT pointer
+PRIM(FDT_X2d_START) PUSH; TOS.u = fdt_start; MIRP
+
+// romfs-base
+PRIM(ROMFS_X2d_BASE) PUSH; TOS.u = romfs_base; MIRP
+
+// if the low level firmware is epapr compliant it will put the
+// epapr magic into r6 before starting paflof
+// epapr-magic is a copy of r6
+PRIM(EPAPR_X2d_MAGIC) PUSH; TOS.u = epapr_magic; MIRP
+
+// Codefields.
+code_DOCOL:
+	{
+		RPUSH; RTOS.a = ip;
+		ip = cfa;
+		NEXT;
+	}
+code_DODOES:
+	{
+		RPUSH; RTOS.a = ip;
+		ip = (cfa + 1)->a;
+		PUSH; TOS.a = cfa + 2;
+		NEXT0;
+	}
+code_DODEFER:
+	{
+		cfa = (cfa + 1)->a;
+		NEXT00;
+	}
+code_DOALIAS:
+	{
+		cfa = (cfa + 1)->a;
+		NEXT00;
+	}
+code_DOCON:
+	{
+		PUSH;
+		TOS = *(cfa + 1);
+		NEXT;
+	}
+code_DOVAL:
+	{
+		PUSH;
+		TOS = *(cfa + 1);
+		NEXT;
+	}
+code_DOFIELD:
+	{
+		dp->n += (cfa + 1)->n;
+		NEXT;
+	}
+code_DOVAR:
+	{
+		(++dp)->a = cfa + 1;
+		NEXT;
+	}
+code_DOBUFFER_X3a:
+	{
+		(++dp)->a = cfa + 1;
+		NEXT;
+	}
+
+
+
+
+
+// branching
+code_BRANCH:
+	{
+		type_n dis = (++ip)->n;
+		ip = (cell *)((type_u)ip + dis);
+		NEXT;
+	}
+code_0BRANCH:
+	{
+		type_n dis = (++ip)->n;
+		if (TOS.u == 0)
+			ip = (cell *)((type_u)ip + dis);
+		POP;
+		NEXT;
+	}
+
+// Jump to "defer BP"
+code_BREAKPOINT:
+	{
+		RPUSH; RTOS.a = ip;
+		ip = (cell * ) xt_BP+2;
+		NEXT;
+	}
+
+
+// literals
+code_LIT:
+	{
+		PUSH;
+		TOS = *++ip;
+		NEXT;
+	}
+code_DOTICK:
+	{
+		PUSH;
+		TOS = *++ip;
+		NEXT;
+	}
+
+
+
+// 1.1
+PRIM(DUP) cell x = TOS; PUSH; TOS = x; MIRP
+PRIM(OVER) cell x = NOS; PUSH; TOS = x; MIRP
+PRIM(PICK) TOS = *(dp - TOS.n - 1); MIRP
+
+// 1.2
+PRIM(DROP) POP; MIRP
+
+// 1.3
+PRIM(SWAP) cell x = NOS; NOS = TOS; TOS = x; MIRP
+
+// 1.4
+PRIM(_X3e_R) RPUSH; RTOS = TOS; POP; MIRP
+PRIM(R_X3e) PUSH; TOS = RTOS; RPOP; MIRP
+PRIM(R_X40) PUSH; TOS = RTOS; MIRP
+
+// 1.5
+PRIM(DEPTH) PUSH; TOS.u = dp - the_data_stack; MIRP
+PRIM(DEPTH_X21) dp = the_data_stack + TOS.u - 1; MIRP
+PRIM(RDEPTH) PUSH; TOS.u = rp - the_return_stack + 1; MIRP
+PRIM(RDEPTH_X21) rp = the_return_stack + TOS.u - 1; POP; MIRP
+PRIM(RPICK) TOS = *(rp - TOS.n); MIRP
+
+// 2.1
+PRIM(_X2b) NOS.u += TOS.u; POP; MIRP
+PRIM(_X2d) NOS.u -= TOS.u; POP; MIRP
+PRIM(_X2a) NOS.u *= TOS.u; POP; MIRP
+
+// 2.2
+PRIM(LSHIFT) NOS.u <<= TOS.u; POP; MIRP
+PRIM(RSHIFT) NOS.u >>= TOS.u; POP; MIRP
+PRIM(ASHIFT) NOS.n >>= TOS.u; POP; MIRP
+PRIM(AND) NOS.u &= TOS.u; POP; MIRP
+PRIM(OR) NOS.u |= TOS.u; POP; MIRP
+PRIM(XOR) NOS.u ^= TOS.u; POP; MIRP
+
+// 3.1
+#define GET_TYPE1(t) { \
+		t *restrict a = (t *restrict)(TOS.a); \
+		t b;
+
+#define GET_TYPE2(t) \
+		b = *a;
+
+#define GET_TYPE3(t) \
+		TOS.u = b; \
+}
+
+#define PUT_TYPE1(t) { \
+		t *restrict a = TOS.a; \
+		t b = NOS.u; \
+		POP; \
+		POP;
+
+#define PUT_TYPE2(t) \
+		*a = b; \
+}
+
+#define GET_CELL1 GET_TYPE1(type_u)
+#define PUT_CELL1 PUT_TYPE1(type_u)
+#define GET_CHAR1 GET_TYPE1(type_c)
+#define PUT_CHAR1 PUT_TYPE1(type_c)
+#define GET_WORD1 GET_TYPE1(type_w)
+#define PUT_WORD1 PUT_TYPE1(type_w)
+#define GET_LONG1 GET_TYPE1(type_l)
+#define PUT_LONG1 PUT_TYPE1(type_l)
+#define GET_XONG1 GET_TYPE1(type_u)
+#define PUT_XONG1 PUT_TYPE1(type_u)
+
+#define GET_CELL2 GET_TYPE2(type_u)
+#define PUT_CELL2 PUT_TYPE2(type_u)
+#define GET_CHAR2 GET_TYPE2(type_c)
+#define PUT_CHAR2 PUT_TYPE2(type_c)
+#define GET_WORD2 GET_TYPE2(type_w)
+#define PUT_WORD2 PUT_TYPE2(type_w)
+#define GET_LONG2 GET_TYPE2(type_l)
+#define PUT_LONG2 PUT_TYPE2(type_l)
+#define GET_XONG2 GET_TYPE2(type_u)
+#define PUT_XONG2 PUT_TYPE2(type_u)
+
+#define GET_CELL3 GET_TYPE3(type_u)
+#define GET_CHAR3 GET_TYPE3(type_c)
+#define GET_WORD3 GET_TYPE3(type_w)
+#define GET_LONG3 GET_TYPE3(type_l)
+#define GET_XONG3 GET_TYPE3(type_u)
+
+#define GET_CELL GET_CELL1 GET_CELL2 GET_CELL3
+#define PUT_CELL PUT_CELL1 PUT_CELL2
+#define GET_CHAR GET_CHAR1 GET_CHAR2 GET_CHAR3
+#define PUT_CHAR PUT_CHAR1 PUT_CHAR2
+#define GET_WORD GET_WORD1 GET_WORD2 GET_WORD3
+#define PUT_WORD PUT_WORD1 PUT_WORD2
+#define GET_LONG GET_LONG1 GET_LONG2 GET_LONG3
+#define PUT_LONG PUT_LONG1 PUT_LONG2
+#define GET_XONG GET_XONG1 GET_XONG2 GET_XONG3
+#define PUT_XONG PUT_XONG1 PUT_XONG2
+
+	PRIM(_X40)  GET_CELL; MIRP
+	PRIM(_X21)  PUT_CELL; MIRP
+	PRIM(C_X40) GET_CHAR; MIRP
+	PRIM(C_X21) PUT_CHAR; MIRP
+	PRIM(W_X40) GET_WORD; MIRP
+	PRIM(W_X21) PUT_WORD; MIRP
+	PRIM(L_X40) GET_LONG; MIRP
+	PRIM(L_X21) PUT_LONG; MIRP
+	PRIM(X_X40) GET_XONG; MIRP
+	PRIM(X_X21) PUT_XONG; MIRP
+
+
+#define UGET_TYPE1(t) { \
+		type_c *restrict a = (type_c *restrict)(TOS.a); \
+		t b; \
+		type_c *restrict c = (type_c *restrict)&b;
+
+#define UGET_TYPE2(t) \
+		*c++ = *a++; \
+		*c++ = *a++;
+
+#define UGET_TYPE3(t) \
+		TOS.u = b; \
+}
+
+#define UPUT_TYPE1(t) { \
+		type_c *restrict a = (type_c *restrict)(TOS.a); \
+		t b = NOS.u; \
+		type_c *restrict c = (type_c *restrict)&b; \
+		POP; \
+		POP;
+
+#define UPUT_TYPE2(t) \
+		*a++ = *c++; \
+		*a++ = *c++;
+
+#define UPUT_TYPE3(t) }
+
+#define UGET_WORD1 UGET_TYPE1(type_w)
+#define UPUT_WORD1 UPUT_TYPE1(type_w)
+#define UGET_WORD2 UGET_TYPE2(type_w)
+#define UPUT_WORD2 UPUT_TYPE2(type_w)
+#define UGET_WORD3 UGET_TYPE3(type_w)
+#define UPUT_WORD3 UPUT_TYPE3(type_w)
+#define UGET_LONG1 UGET_TYPE1(type_l)
+#define UPUT_LONG1 UPUT_TYPE1(type_l)
+#define UGET_LONG2 UGET_TYPE2(type_l)
+#define UPUT_LONG2 UPUT_TYPE2(type_l)
+#define UGET_LONG3 UGET_TYPE3(type_l)
+#define UPUT_LONG3 UPUT_TYPE3(type_l)
+
+#define UGET_WORD UGET_WORD1 UGET_WORD2 UGET_WORD3
+#define UPUT_WORD UPUT_WORD1 UPUT_WORD2 UPUT_WORD3
+#define UGET_LONG UGET_LONG1 UGET_LONG2 UGET_LONG2 UGET_LONG3
+#define UPUT_LONG UPUT_LONG1 UPUT_LONG2 UPUT_LONG2 UPUT_LONG3
+
+	PRIM(UNALIGNED_X2d_W_X40) UGET_WORD; MIRP
+	PRIM(UNALIGNED_X2d_W_X21) UPUT_WORD; MIRP
+	PRIM(UNALIGNED_X2d_L_X40) UGET_LONG; MIRP
+	PRIM(UNALIGNED_X2d_L_X21) UPUT_LONG; MIRP
+
+
+// 6
+PRIM(_X3c) NOS.n = -(NOS.n < TOS.n); POP; MIRP
+PRIM(U_X3c) NOS.n = -(NOS.u < TOS.u); POP; MIRP
+PRIM(0_X3c) TOS.n = -(TOS.n < 0); MIRP
+PRIM(_X3d) NOS.n = -(NOS.u == TOS.u); POP; MIRP
+PRIM(0_X3d) TOS.n = -(TOS.u == 0); MIRP
+
+
+
+
+
+
+// 8.4
+PRIM(DODO) RPUSH; RTOS = NOS; RPUSH; RTOS = TOS; POP; POP; MIRP
+code_DO_X3f_DO:
+	{
+		cell i = *dp--;
+		cell n = *dp--;
+		type_n dis = (++ip)->n;
+		if (i.n == n.n)
+			ip = (cell *restrict)((type_c *restrict)ip + dis);
+		else {
+			*(rp + 1) = n;
+			*(rp += 2) = i;
+		}
+		NEXT;
+	}
+code_DOLOOP:
+	{
+		type_n dis = (++ip)->n;
+		rp->n++;
+		if (rp->n == (rp - 1)->n)
+			rp -= 2;
+		else
+			ip = (cell *restrict)((type_c *restrict)ip + dis);
+		NEXT;
+	}
+code_DO_X2b_LOOP:
+	{
+		type_u lo, hi;
+		type_n inc;
+		type_n dis = (++ip)->n;
+		lo = rp->u;
+		inc = (dp--)->n;
+		rp->n += inc;
+		if (inc >= 0)
+			hi = rp->u;
+		else {
+			hi = lo;
+			lo = rp->u;
+		}
+		if ((type_u)((rp - 1)->n - 1 - lo) < hi - lo)
+			rp -= 2;
+		else
+			ip = (cell *restrict)((type_c *restrict)ip + dis);
+		NEXT;
+	}
+code_DOLEAVE:
+	{
+		type_n dis = (++ip)->n;
+		rp -= 2;
+		ip = (cell *restrict)((type_c *restrict)ip + dis);
+		NEXT;
+	}
+code_DO_X3f_LEAVE:
+	{
+		type_n dis = (++ip)->n;
+		if ((dp--)->n) {
+			rp -= 2;
+			ip = (cell *restrict)((type_c *restrict)ip + dis);
+		}
+		NEXT;
+	}
+
+
+
+
+
+
+// 8.5
+code_EXIT:
+	{
+		ip = (rp--)->a;
+		NEXT;
+	}
+
+code_SEMICOLON:
+	{
+		ip = (rp--)->a;
+		NEXT;
+	}
+
+code_EXECUTE:	// don't need this as prim
+	{
+		cfa = (dp--)->a;
+		NEXT00;
+	}
+
+
+
+
+// 3.1
+#define _FWMOVE(s, d, size, t)	\
+	{ t *s1=(t *)s, *d1=(t *)d; \
+		while (size > 0) { *d1++ = *s1++; size -= sizeof(t); } }
+
+#define _BWMOVE(s, d, size, t)	{ \
+	t *s1=(t *)((char *)s+size), *d1=(t *)((char *)d+size); \
+	while (size > 0) { *--d1 = *--s1; size -= sizeof(t); } \
+}
+
+#define _FWOVERLAP(s, d, size) ((d >= s) && ((type_u)d < ((type_u)s + size))) 
+
+#define	_MOVE(s, d, size, t) if _FWOVERLAP(s, d, size) _BWMOVE(s, d, size, t) else  _FWMOVE(s, d, size, t)
+
+#define _FASTMOVE(s, d, size) \
+	switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \
+		case 0:			_MOVE(s, d, size, type_u); break; \
+		case sizeof(type_l):	_MOVE(s, d, size, type_l); break; \
+		case sizeof(type_w):	_MOVE(s, d, size, type_w); break; \
+		default:		_MOVE(s, d, size, type_c); break; \
+	}
+
+PRIM(MOVE)
+	type_u n = TOS.u; POP;
+	unsigned char *q = TOS.a; POP;
+	unsigned char *p = TOS.a; POP;
+
+	_FASTMOVE(p, q, n);
+MIRP
+
+code_FILL:
+	{
+		unsigned char c = (dp--)->u;
+		type_n size = ((dp--)->n);
+		unsigned char *d = (unsigned char *)((dp--)->u);
+		type_u fill_v=c | c <<8;
+
+		fill_v |= fill_v << 16;
+		switch (((type_u)d | (type_u)size) & (sizeof(type_u)-1)) {
+			case 0: {
+				type_u *up = (type_u *)d;
+#if (__LONG_MAX__ > 2147483647L)
+				fill_v |= fill_v << 32;
+#endif
+				while ((size-=sizeof(type_u)) >= 0)
+					*up++ = fill_v;
+			}
+			case sizeof(type_l): {
+				type_l *lp = (type_l *)d;
+
+				while ((size-=sizeof(type_l)) >= 0)
+					*lp++ = (type_l)fill_v;
+			}
+			case sizeof(type_w): {
+				type_w *wp = (type_w *)d;
+
+				while ((size-=sizeof(type_w)) >= 0)
+					*wp++ = (type_w)fill_v;
+			}
+			default:
+				while (size-- > 0)
+					*d++ = (unsigned char)c;
+		}
+		NEXT;
+	}
+
+code_COMP:
+	{
+		type_n len = ((dp--)->n);
+		unsigned char *addr2 = (unsigned char *)((dp--)->u);
+		unsigned char *addr1 = (unsigned char *)((dp--)->u);
+
+		while (len-- > 0) {
+			if (*addr1 > *addr2) {
+				(++dp)->n = 1;
+				NEXT;
+			}
+			else if (*addr1 < *addr2) {
+				(++dp)->n = -1;
+				NEXT;
+			}
+			addr1 += 1;
+			addr2 += 1;
+		}
+		(++dp)->n = 0;
+		NEXT;
+	}
+
+// Device IO block data helpers
+#define _FWRMOVE(s, d, size, t)	\
+	{ t *s1=(t *)s, *d1=(t *)d; SET_CI; \
+		while (size > 0) { *d1++ = *s1++; size -= sizeof(t); } \
+		CLR_CI; \
+}
+
+#define _BWRMOVE(s, d, size, t)	{ \
+	t *s1=(t *)((char *)s+size), *d1=(t *)((char *)d+size); SET_CI; \
+	while (size > 0) { *--d1 = *--s1; size -= sizeof(t); } \
+		CLR_CI; \
+}
+
+#define	_RMOVE(s, d, size, t) if _FWOVERLAP(s, d, size) _BWRMOVE(s, d, size, t) else  _FWRMOVE(s, d, size, t)
+
+#define _FASTRMOVE(s, d, size) \
+	switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \
+		case 0:			_RMOVE(s, d, size, type_u); break; \
+		case sizeof(type_l):	_RMOVE(s, d, size, type_l); break; \
+		case sizeof(type_w):	_RMOVE(s, d, size, type_w); break; \
+		default:		_RMOVE(s, d, size, type_c); break; \
+	}
+
+code_RMOVE:
+	{
+		type_u size = ((dp--)->u);
+		type_u *d = (type_u *)((dp--)->u);
+		type_u *s = (type_u *)((dp--)->u);
+
+		_FASTRMOVE(s, d, size);
+		NEXT;
+	}
+
+
+// String compare, case insensitive:
+// : string=ci  ( str1 len1 str2 len2 -- equal? )
+PRIM(STRING_X3d_CI)
+	type_u l2 = TOS.u; POP;
+	unsigned char *p2 = TOS.a; POP;
+	type_u l1 = TOS.u; POP;
+	unsigned char *p1 = TOS.a;
+
+	if (l1 == l2) {
+		TOS.n = -1;		/* Default to TRUE */
+		while (l1 > 0) {
+			if (toupper(*p1) != toupper(*p2)) {
+				TOS.n = 0;
+				break;
+			}
+			++p1;  ++p2;
+			--l1;
+		}
+	}
+	else {
+		TOS.n = 0;
+	}
+MIRP
+
+// bool dependend pick
+// ?PICK ( v1 v2 bool -- v1|v2 )
+PRIM(_X3f_PICK)
+        type_u b = TOS.u; POP;
+        if (b) { NOS = TOS; }
+        POP;
+MIRP
+
+/* zcount ( zstr -- str len ) */
+PRIM(ZCOUNT)
+	type_u len = strlen(TOS.a);
+	PUSH; TOS.u = len;
+MIRP
+
+PRIM(CLEAN_X2d_HASH)
+	memset(hash_table, 0, sizeof(hash_table));
+MIRP
+
+PRIM(HASH_X2d_TABLE)
+	PUSH;
+	TOS.a = hash_table;
+MIRP
+
+/* hash ( str len -- hash )
+ * this word is used in find-hash.fs to create
+ * a hash to accelerate word lookup */
+PRIM(HASH)
+	type_u len = TOS.u; POP;
+	unsigned char *str = TOS.a;
+	type_u tmp = len;
+	type_u hash = 0;
+	while(len--) {
+		hash <<= 1;
+		hash ^= tolower(*str);
+		hash ^= tmp;
+		str++;
+	}
+	/* we only want hash values which size is smaller
+	 * than HASHSIZE */
+	hash &= HASHSIZE - 1;
+	/* access the hash table in steps of CELLSIZE */
+	hash *= CELLSIZE;
+	/* return a pointer for this hash in the hash table */
+	TOS.a = hash_table + hash;
+MIRP
diff --git a/qemu-0.15.x/roms/SLOF/slof/prim.in b/qemu-0.15.x/roms/SLOF/slof/prim.in
new file mode 100644
index 0000000..b14a867
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/prim.in
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+cod(TIB)
+cod(POCKETS)
+cod(EREGS)
+cod(CIREGS)
+cod(CISTACK)
+// compile buffer for the "structure words in interpret mode" OF extension
+cod(COMP-BUFFER)
+
+cod(HEAP-START)
+cod(HEAP-END)
+// flattened device tree start address
+cod(FDT-START)
+// romfs start address
+cod(ROMFS-BASE)
+// if the low level firmware is epapr compliant it will put the
+// epapr magic into r6 before starting paflof
+// epapr-magic is a copy of r6
+cod(EPAPR-MAGIC)
+
+cod(BRANCH) _ADDING _O
+cod(0BRANCH) _ADDING _O
+dfr(BP)
+cod(BREAKPOINT)
+
+cod(LIT) _ADDING _N
+cod(DOTICK)
+
+cod(DUP)
+cod(OVER)
+cod(PICK)
+cod(DROP)
+cod(SWAP)
+
+cod(>R)
+cod(R>)
+cod(R@)
+cod(RPICK)
+
+cod(DEPTH)
+cod(DEPTH!)
+cod(RDEPTH)
+cod(RDEPTH!)
+
+cod(+)
+cod(-)
+cod(*)
+cod(LSHIFT)
+cod(RSHIFT)
+cod(ASHIFT)
+cod(AND)
+cod(OR)
+cod(XOR)
+
+cod(@)
+cod(!)
+cod(C@)
+cod(C!)
+cod(W@)
+cod(W!)
+cod(L@)
+cod(L!)
+cod(X@)
+cod(X!)
+
+cod(UNALIGNED-W@)
+cod(UNALIGNED-W!)
+cod(UNALIGNED-L@)
+cod(UNALIGNED-L!)
+
+cod(<)
+cod(U<)
+cod(0<)
+cod(=)
+cod(0=)
+
+cod(DODO)
+cod(DO?DO) _ADDING _O
+cod(DOLOOP) _ADDING _O
+cod(DO+LOOP) _ADDING _O
+cod(DOLEAVE) _ADDING _O
+cod(DO?LEAVE) _ADDING _O
+
+cod(EXIT)
+cod(SEMICOLON)
+cod(EXECUTE)
+
+cod(MOVE)
+// cod(RMOVE64)
+cod(RMOVE)
+cod(ZCOUNT)
+con(HASH-SIZE HASHSIZE)
+cod(HASH)
+cod(CLEAN-HASH)
+cod(HASH-TABLE)
diff --git a/qemu-0.15.x/roms/SLOF/slof/ref.pl b/qemu-0.15.x/roms/SLOF/slof/ref.pl
new file mode 100644
index 0000000..b21f139
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/ref.pl
@@ -0,0 +1,148 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+#!/usr/bin/perl
+
+#
+# Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+#
+
+
+use Getopt::Std;
+use Data::Dumper;
+
+$CELLSIZE = length(sprintf "%x", ~0) / 2;
+$CELLSIZE = 8;
+$DEBUG = 0;
+
+sub usage
+{
+	printf STDERR "Usage: ref.pl [ -s 32|64 ] [ -d ] \n";
+	printf STDERR "       ref.pl -h\n";
+	exit 0;
+}
+
+sub string
+{
+	my ($s, $extra) = @_;
+
+	$DEBUG and printf STDERR "\nstring:[%s][%02x]\n", $s, ord $extra;
+	$s = sprintf "%s%c%s", $extra, length($s), $s;
+	@s = ($s =~ /(.{1,$CELLSIZE})/gs);
+	do { s/([\x00-\x1f\x22\x5c\x7f-\xff])/sprintf "\\%03o", ord $1/egs } for @s;
+	my @reut = ("{ .c = \"" . (join "\" }, { .c = \"", @s) . "\" },", scalar @s);
+	# $DEBUG and print STDERR Dumper \@reut;
+	return @reut;
+}
+
+sub forth_to_c_name
+{
+	($_, my $numeric) = @_;
+	s/([^a-zA-Z0-9])/sprintf("_X%02x_", ord($1))/ge;
+	s/__/_/g;
+#	s/^_//;
+	s/_$//;
+	s/^(\d)/_$1/ if $numeric;
+	return $_;
+}
+
+sub special_forth_to_c_name
+{
+	($_, my $numeric) = @_;
+
+	$DEBUG and print STDERR "\tasked for $_ [[numeric is $numeric]]\n";
+	my ($name, $arg) = (/^([^(]+)(.*)$/);
+	# $DEBUG and print STDERR "\tname is $name -- arg is $arg\n";
+	if ($special{$name} == 1) {
+		$_ = forth_to_c_name($name, $numeric) . $arg;
+	} elsif ($special{$name} != 2) {
+		$_ = forth_to_c_name($_, $numeric);
+	}
+	# $DEBUG and print STDERR "\tmaking it $_\n";
+	return $_;
+}
+
+getopts('dhs:') or die "Invalid option!\n";
+
+$opt_h and usage();
+$opt_d and $DEBUG=1;
+$opt_s and $opt_s != 32 and $opt_s != 64 and die("Only -s32 or -s64 allowed");
+
+$opt_s and $opt_s == 32 and $CELLSIZE=4;
+
+$DEBUG and printf STDERR "Cell size set to $CELLSIZE;\n";
+
+$link = "0";
+%special = ( _N => 2, _O => 2, _C => 2, _A => 2 );
+
+$DEBUG and print STDERR "Compiling:";
+while ($line = <>) {
+	if ($line =~ /^([a-z]{3})\(([^ ]+)./) {
+		$typ = $1;
+		$name = $2;
+
+		$DEBUG and print STDERR "\n\t\t$name###\n";
+
+		$name =~ s/\)$// if $line =~ /\)\s+_ADDING.*$/;
+		# $DEBUG and print STDERR " $name";
+		$cname = forth_to_c_name($name, 1);
+		$par = '';
+		$add = '';
+		$extra = "\0";
+		if ($typ eq "imm") {
+			$typ = "col";
+			$extra = "\1";
+		}
+#		if ($typ eq "com") {
+#			$typ = "col";
+#			$extra = "\3";
+#		}
+		($str, $strcells) = (string $name, $extra);
+		if ($line =~ /^str\([^"]*"([^"]*)"/) {
+		# $DEBUG and print STDERR "[[[$1]]]\n";
+			($s) = (string $1);
+			$line =~ s/"[^"]*"/$s/;
+		}
+		if ($line =~ /_ADDING +(.*)$/) {
+			$special{$name} = 1;
+			@typ = (split /\s+/, $1);
+			$count = 0;
+			$par = "(" . (join ", ", map { $count++; "_x$count" } @typ) . ")";
+			$count = 0;
+			$add = join " ", map { $count++; "$_(_x$count)" } @typ;
+			$line =~ s/\s+_ADDING.*$//;
+		}
+		# $DEBUG and print STDERR $line;
+		($body) = ($line =~ /^...\((.*)\)$/);
+		@body = split " ", $body;
+		# $DEBUG and print STDERR "\n";
+		# $DEBUG and print STDERR "BODY WAS: ", (join " ", @body), "\n";
+		if ($typ ne "str" and $typ ne "con") {
+			@body = map { special_forth_to_c_name($_, $typ eq "col") } @body;
+		} else {
+			$body[0] = special_forth_to_c_name($body[0]);
+		}
+		# $DEBUG and print STDERR "BODY IS: ", (join " ", @body), "\n";
+		$body = join " ", @body;
+		$body =~ s/ /, /;
+		# $DEBUG and print STDERR "===> $body\n";
+
+		print "header($cname, { .a = $link }, $str) ";
+		$link = "xt_$cname";
+		print "$typ($body)\n";
+		print "#define $cname$par ref($cname, $strcells+1) $add\n";
+		(my $xxcname) = ($cname =~ /^_?(.*)/);
+		$add and print "#define DO$xxcname ref($cname, $strcells+1)\n";
+	} else {
+		print $line;
+	}
+}
+$DEBUG and print STDERR "\n";
diff --git a/qemu-0.15.x/roms/SLOF/slof/types.h b/qemu-0.15.x/roms/SLOF/slof/types.h
new file mode 100644
index 0000000..e347cc3
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/slof/types.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+//
+// Copyright 2002,2003,2004  Segher Boessenkool  <segher at kernel.crashing.org>
+//
+
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+#if 0
+#include <stdint.h>
+
+typedef uint8_t		type_c;		// 1 byte
+typedef uint16_t	type_w;		// 2 bytes
+typedef uint32_t	type_l;		// 4 bytes
+typedef intptr_t	type_n;		// cell size
+typedef uintptr_t	type_u;		// cell size
+#else
+typedef unsigned char	type_c;		// 1 byte
+typedef unsigned short	type_w;		// 2 bytes
+typedef unsigned int	type_l;		// 4 bytes
+typedef long		type_n;		// cell size
+typedef unsigned long	type_u;		// cell size
+#endif
+
+//#define CELLSIZE (sizeof(type_u) / sizeof(type_c))
+#define CELLSIZE sizeof(type_u)
+
+typedef union cell {
+	type_n n;
+	type_u u;
+	void *a;
+	type_c c[CELLSIZE];
+	type_w w[CELLSIZE/2];
+	type_l l[CELLSIZE/4];
+} cell;
+
+
+#endif /* _TYPES_H */
diff --git a/qemu-0.15.x/roms/SLOF/tools/Makefile b/qemu-0.15.x/roms/SLOF/tools/Makefile
new file mode 100644
index 0000000..6de8fe6
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/tools/Makefile
@@ -0,0 +1,33 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../make.rules
+
+all: gen_reloc_table
+
+%.o: %.c
+		$(HOSTCC) -W $(HOSTCFLAGS) -c $^
+
+elf2tst:	elf2tst.o
+		$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
+gen_reloc_table: gen_reloc_table.o
+		$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
+clean_here:
+	rm -f elf2tst *.o gen_reloc_table
+
+clean:	clean_here
+
+
+distclean:	clean_here
+
diff --git a/qemu-0.15.x/roms/SLOF/tools/create_reloc_table.sh b/qemu-0.15.x/roms/SLOF/tools/create_reloc_table.sh
new file mode 100755
index 0000000..8cacb74
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/tools/create_reloc_table.sh
@@ -0,0 +1,60 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# *     IBM Corporation - initial implementation
+# ****************************************************************************/
+#!/bin/sh
+
+
+CROSSTMP=`grep ^CROSS $(dirname $0)/../make.rules | cut -d\  -f2`
+
+CROSS=${CROSS-$CROSSTMP}
+
+# Set defaults:
+LD="${CROSS}ld"
+LDFLAGS="-nostdlib"
+LDSFILE=""
+OBJCOPY="${CROSS}objcopy"
+
+DIRNAME=`dirname $0`
+
+# Parse parameters:
+while [ $# -gt 0 ] ; do
+	case "$1" in
+		--ld) LD=$2 ; shift 2 ;;
+		--ldflags) LDFLAGS=$2 ; shift 2 ;;
+		--lds) LDSFILE=$2 ; shift 2 ;;
+		--objcopy) OBJCOPY=$2 ; shift 2 ;;
+		*.o|*.a|-l*|-L*) OBJFILES="$OBJFILES $1" ; shift ;;
+		*) echo "$0:" ; echo " Unsupported argument: $1"; exit -1 ;;
+	esac
+done
+
+if [ -z $LDSFILE ]; then
+	echo "Please specifiy an lds file with the --lds option"
+	exit 42
+fi
+
+TMP1=`mktemp`
+TMP2=`mktemp`
+
+# Now create the two object files:
+$LD $LDFLAGS -T $LDSFILE -o $TMP1.o $OBJFILES || exit -1
+$LD $LDFLAGS -T $LDSFILE -o $TMP2.o $OBJFILES --section-start .text=0x4000000000000000 || exit -1
+
+$OBJCOPY -O binary $TMP1.o $TMP1.bin || exit -1
+$OBJCOPY -O binary $TMP2.o $TMP2.bin || exit -1
+
+# Create the relocation table with gen_reloc_table:
+$DIRNAME/gen_reloc_table $TMP1.bin $TMP2.bin reloc_table.bin
+
+$LD -o reloc_table.o -bbinary reloc_table.bin -e0 || exit -1
+$OBJCOPY --rename-section .data=.reloc reloc_table.o reloc_table.o || exit -1
+
+rm -f $TMP1.o $TMP2.o $TMP1.bin $TMP2.bin reloc_table.bin
diff --git a/qemu-0.15.x/roms/SLOF/tools/gen_reloc_table.c b/qemu-0.15.x/roms/SLOF/tools/gen_reloc_table.c
new file mode 100644
index 0000000..b2e2176
--- /dev/null
+++ b/qemu-0.15.x/roms/SLOF/tools/gen_reloc_table.c
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int reloc_64_cnt;
+
+static int reloc_64[4096];
+
+static void
+output_int(FILE *output_file, int i)
+{
+  fputc((i>>24) & 0xff, output_file);
+  fputc((i>>16) & 0xff, output_file);
+  fputc((i>>8) & 0xff, output_file);
+  fputc(i & 0xff, output_file);
+}
+
+static void
+output_reloc_table(FILE * output_file, int reloc_cnt, int reloc[])
+{
+  int i;
+  for (i=0; i < reloc_cnt; i++)
+    {
+#ifdef DEBUG
+      printf ("reloc %x\n", reloc[i]);
+#endif
+      output_int (output_file, reloc[i]);
+    }
+  if ((reloc_cnt & 1) == 0)
+    output_int (output_file, 0);
+}
+
+int
+main(int argc, char *argv[])
+{
+  int cnt_a, cnt_b, offset = -1;
+  unsigned char a, b;
+  FILE *orig, *other, *output_file;
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "reloc_diff orig_file other_file output_file\n");
+      exit(-1);
+    }
+    
+  orig = fopen(argv[1], "rb");
+  other = fopen(argv[2], "rb");
+  output_file = fopen(argv[3], "wb");
+  if(orig == NULL || other == NULL || output_file == NULL) {
+    printf("Could not open file.\n");
+    return -1;
+  }
+
+  while (1)
+    {
+      cnt_a = fread(&a, 1, 1, orig);
+      cnt_b = fread(&b, 1, 1, other);
+      offset ++;
+      if (cnt_a != cnt_b)
+	{
+	  fprintf (stderr, "Files >%s< and >%s< have not the same lenght\n",argv[1],argv[2]);
+	  exit(-1);
+	}
+
+      if (cnt_a == 0)
+	break;
+      
+      if (a == b)	continue;
+
+      if (a + 0x40 == b)
+	{
+	  reloc_64[reloc_64_cnt++] = offset;
+	}
+      else
+	{
+	  fprintf(stderr, "Unknown relocation");
+	  fprintf(stderr, "Offset %x: %02x %02x\n", offset, a, b);
+	  break;
+	}
+    }
+
+  output_reloc_table(output_file, reloc_64_cnt, reloc_64);
+  return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/COPYING b/qemu-0.15.x/roms/ipxe/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/qemu-0.15.x/roms/ipxe/COPYRIGHTS b/qemu-0.15.x/roms/ipxe/COPYRIGHTS
new file mode 100644
index 0000000..342330b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/COPYRIGHTS
@@ -0,0 +1,12 @@
+In general iPXE files are licensed under the GPL.  For historical
+reasons, individual files may contain their own licence declarations.
+Most builds of iPXE do not contain all iPXE code (in particular, most
+builds will include only one driver), and so the overall licence can
+vary depending on what target you are building.
+
+The resultant applicable licence(s) for any particular build can be
+determined by using "make bin/xxxxxxx.yyy.licence"; for example:
+
+  make bin/rtl8139.rom.licence
+
+to determine the resultant licence(s) for the build bin/rtl8139.rom
diff --git a/qemu-0.15.x/roms/ipxe/README b/qemu-0.15.x/roms/ipxe/README
new file mode 100644
index 0000000..011aa21
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/README
@@ -0,0 +1,8 @@
+iPXE README File
+
+Quick start guide:
+
+   cd src
+   make
+
+For any more detailed instructions, see http://ipxe.org
diff --git a/qemu-0.15.x/roms/ipxe/contrib/README b/qemu-0.15.x/roms/ipxe/contrib/README
new file mode 100644
index 0000000..e77d469
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/README
@@ -0,0 +1,9 @@
+Most of the content that was previously in this directory has been
+moved to a separate git repository:
+
+    http://git.etherboot.org/?p=contrib.git;a=summary
+
+or the Etherboot Project wiki:
+
+    http://etherboot.org/
+
diff --git a/qemu-0.15.x/roms/ipxe/contrib/errdb/.gitignore b/qemu-0.15.x/roms/ipxe/contrib/errdb/.gitignore
new file mode 100644
index 0000000..95bf5c3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/errdb/.gitignore
@@ -0,0 +1 @@
+errors.db
diff --git a/qemu-0.15.x/roms/ipxe/contrib/errdb/errdb.pl b/qemu-0.15.x/roms/ipxe/contrib/errdb/errdb.pl
new file mode 100755
index 0000000..fc1919f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/errdb/errdb.pl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+errdb.pl
+
+=head1 SYNOPSIS
+
+errdb.pl [options] ../../src/bin/errors
+
+Options:
+
+    -d,--database=db	Specify path to errors.db
+    -h,--help		Display brief help message
+    -v,--verbose	Increase verbosity
+    -q,--quiet		Decrease verbosity
+
+=cut
+
+use Getopt::Long;
+use Pod::Usage;
+use DBI;
+use strict;
+use warnings;
+
+# Parse command-line options
+my $verbosity = 0;
+my $errdb = "errors.db";
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+  'database|d=s' => sub { shift; $errdb = shift; },
+  'verbose|v+' => sub { $verbosity++; },
+  'quiet|q+' => sub { $verbosity--; },
+  'help|h' => sub { pod2usage ( 1 ); },
+) or die "Could not parse command-line options\n";
+pod2usage ( 1 ) unless @ARGV >= 1;
+
+# Open database
+my $dbh = DBI->connect ( "dbi:SQLite:dbname=".$errdb, "", "",
+			 { RaiseError => 1, PrintError => 0 } );
+$dbh->begin_work();
+
+# Create errors table if necessary
+eval {
+  $dbh->selectall_arrayref ( "SELECT * FROM errors LIMIT 1" );
+};
+if ( $@ ) {
+  print "Creating errors table\n" if $verbosity >= 1;
+  $dbh->do ( "CREATE TABLE errors (".
+	     " errno char(8) NOT NULL,".
+	     " description text NOT NULL,".
+	     " PRIMARY KEY ( errno ) )" );
+}
+
+# Create xrefs table if necessary
+eval {
+  $dbh->selectall_arrayref ( "SELECT * FROM xrefs LIMIT 1" );
+};
+if ( $@ ) {
+  print "Creating xrefs table\n" if $verbosity >= 1;
+  $dbh->do ( "CREATE TABLE xrefs (".
+	     " errno char(8) NOT NULL,".
+	     " filename text NOT NULL,".
+	     " line integer NOT NULL,".
+	     " UNIQUE ( errno, filename, line ),".
+	     " FOREIGN KEY ( errno ) REFERENCES errors ( errno ) )" );
+  $dbh->do ( "CREATE INDEX xrefs_errno ON xrefs ( errno )" );
+}
+
+# Parse input file(s)
+my $errors = {};
+my $xrefs = {};
+while ( <> ) {
+  chomp;
+  ( my $errno, my $filename, my $line, my $description ) = split ( /\t/ );
+  $errors->{$errno} = $description;
+  $xrefs->{$errno} ||= {};
+  $xrefs->{$errno}->{$filename} ||= {};
+  $xrefs->{$errno}->{$filename}->{$line} ||= 1;
+}
+
+# Ensure all errors are present in database
+my $error_update =
+    $dbh->prepare ( "UPDATE errors SET description = ? WHERE errno = ?" );
+my $error_insert = $dbh->prepare ( "INSERT INTO errors VALUES ( ?, ? )" );
+while ( ( my $errno, my $description ) = each %$errors ) {
+  print "Error ".$errno." is \"".$description."\"\n" if $verbosity >= 2;
+  if ( $error_update->execute ( $description, $errno ) == 0 ) {
+    $error_insert->execute ( $errno, $description );
+  }
+}
+
+# Replace xrefs in database
+$dbh->do ( "DELETE FROM xrefs" );
+my $xref_insert = $dbh->prepare ( "INSERT INTO xrefs VALUES ( ?, ?, ? )" );
+while ( ( my $errno, my $xref_errno ) = each %$xrefs ) {
+  while ( ( my $filename, my $xref_filename ) = each %$xref_errno ) {
+    foreach my $line ( keys %$xref_filename ) {
+      print "Error ".$errno." is used at ".$filename." line ".$line."\n"
+	  if $verbosity >= 2;
+      $xref_insert->execute ( $errno, $filename, $line );
+    }
+  }
+}
+
+# Close database
+$dbh->commit();
+$dbh->disconnect();
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/README b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/README
new file mode 100644
index 0000000..b68cf77
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/README
@@ -0,0 +1,62 @@
+ROM-o-matic web interface for building iPXE ROMs
+------------------------------------------------
+
+This web application generates iPXE images and sends them to a web
+browser.
+
+Available as part of the iPXE source code distribution, which can be
+downlaoded from http://etherboot.org/
+
+Author:  Marty Connor <mdc at etherboot.org>
+License: GPLv2
+Support: http://etherboot.org/mailman/listinfo/ipxe
+         Please send support questions to the iPXE mailing list
+
+System Requirements
+-------------------
+- Apache web server
+- PHP 4+
+- Tools required to build iPXE installed on the server
+  - gcc, mtools, syslinux, perl, etc.
+
+Setup
+-----
+As distributed, it is expected that the rom-o-matic source code
+directory is in the contrib directory of a iPXE source distribution.
+
+The easiest way to do this is to simply put a iPXE source distribution
+in a web server accessible directory.
+
+If this is not the case, you will need to either edit the file
+
+    "globals.php"
+
+or create a file called
+
+    "local-config.php"
+
+containing the following lines:
+
+<?php
+$src_dir = "../../src";
+?>
+
+Then change the line beginning "$src_dir = " to the path of your iPXE
+source code tree.
+
+To make build times shorter, before you run rom-o-matic for the first time
+you should cd to the ipxe "src" directory and enter the following
+commands:
+
+  $ make
+  $ make bin/NIC
+
+This will pro-compile most object files and will make your rom-o-matic
+builds much faster.
+
+Running rom-o-matic from a web browser
+--------------------------------------
+Enter a URL like:
+
+   http://example.com/ipxe-1.x.x/contrib/rom-o-matic
+
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/bottom.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/bottom.php
new file mode 100644
index 0000000..ff094fd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/bottom.php
@@ -0,0 +1,62 @@
+<?
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+?>
+<hr>
+<h4>
+Resources:
+</h4>
+<ul>
+  <li>
+    Source code for iPXE images is available at
+    <a href="http://etherboot.org/wiki/download" target="_blank">
+    http://etherboot.org/wiki/download</a>
+    <br><br>
+  </li>
+  <li>
+    For general information about using iPXE, please visit the
+    <a href="http://www.etherboot.org/" target="_blank">
+    Etherboot Project Home Page</a>
+    <br><br>
+  </li>
+  <li>
+    For Email-based support for iPXE please join
+    <a href="http://etherboot.org/wiki/mailinglists" target="_blank">
+    Etherboot Project mailing lists.</a>
+    <br><br>
+  </li>
+  <li>
+    For real-time online iPXE support via IRC please visit the
+    <a href="irc://irc.freenode.net/%23etherboot"> #etherboot channel
+    of irc.freenode.net</a>.
+    <br><br>
+  </li>
+</ul>
+<hr>
+  <font size="-1">
+    <br>
+    Please email <a href="mailto:<? echo "${webmaster_email}" ?>"><? echo "${webmaster_email}"?></a>
+    with questions or comments about this website.
+  </font>
+  <br><br>
+<hr>
+</body>
+</html>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/build.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/build.php
new file mode 100644
index 0000000..3101b3e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/build.php
@@ -0,0 +1,306 @@
+<?php // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Get utility functions and set globals
+require_once "utils.php";
+
+// Make sure at least $A (action)  was supplied
+if ( ! isset ( $_POST['A'] ) ) {
+
+    // Present user with form to customize build options
+    require_once "customize-flags.php";
+
+    exit ();
+
+// If user chose "Customize" option on form
+} else if ( $_POST['A'] == "Customize" ) {
+
+    // Present user with form to customize build options
+    require_once "customize-flags.php";
+
+    exit ();
+
+// The following conditional includes all other cases except "Get Image"
+// particularly the explicit ($A == "Start Over") case
+} else if ( $_POST['A'] != "Get Image" ) {
+
+    // Note that this method of redirections discards all the
+    // configuration flags, which is intentional in this case.
+
+    $dest = curDirURL ();
+    header ( "Location: $dest" );
+
+    // This next "echo" should normally not be seen, because
+    // the "header" statement above should cause immediate
+    // redirection but just in case...
+
+    echo "Try this link: <a href=\"$dest\">$dest</a>";
+
+    exit ();
+}
+
+// OK, we're going to try to use whatever options have been set
+// to build an image.
+
+// Make sure at least $nic was supplied
+if ( ! isset ( $_POST['nic'] ) ) {
+    die ( "No NIC supplied!" );
+}
+if ( isset ( $nics[$_POST['nic']] ) ) {
+    $nic = $nics[$_POST['nic']];
+} else {
+    die ( "Invalid NIC \"${_POST['nic']}\" supplied!" );
+}
+
+// Fetch flags
+$flags = get_flags ();
+
+// Get requested format
+$ofmt = isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "";
+$fmt_extension = isset ( $ofmts[$ofmt] ) ? $ofmts[$ofmt] : 'dsk';
+
+// Handle some special cases
+
+$pci_vendor_code = "";
+$pci_device_code = "";
+
+if ( $nic == 'undionly' && $fmt_extension == "pxe" ) {
+
+    // undionly.pxe can't work because it unloads the PXE stack
+    // that it needs to communicate with, so we set the extension
+    // to .kpxe, which has a chance of working. The extension
+    // .kkpxe is another option.
+
+    $fmt_extension = "kpxe";
+
+} else if ( $fmt_extension == "rom" ) {
+
+    if ( ! isset ( $_POST['pci_vendor_code'] )
+		 || ! isset ( $_POST['pci_device_code'] ) ) {
+		die ( "rom output format selected but PCI code(s) missing!" );
+	}
+
+	$pci_vendor_code = $_POST['pci_vendor_code'];
+	$pci_device_code = $_POST['pci_device_code'];
+
+    if ( $pci_vendor_code == ""
+		 || $pci_device_code == "" ) {
+		die ( "rom output format selected but PCI code(s) missing!" );
+	}
+
+	// Try to be forgiving of 0xAAAA format
+	if ( strtolower ( substr ( $pci_vendor_code, 0, 2 ) ) == "0x"
+		 && strlen ( $pci_vendor_code ) == 6 ) {
+		$pci_vendor_code = substr ( $pci_vendor_code, 2, 4 );
+	}
+	if ( strtolower ( substr ( $pci_device_code, 0, 2 ) ) == "0x"
+		 && strlen ( $pci_device_code ) == 6 ) {
+		$pci_device_code = substr ( $pci_device_code, 2, 4 );
+	}
+
+    // concatenate the pci codes to get the $nic part of the
+    // Make target
+    $pci_codes = strtolower (  $pci_vendor_code . $pci_device_code );
+
+    $nic = $pci_codes;
+    if ( ! isset ( $roms[$pci_codes] ) ) {
+        die (   "Sorry, no network driver supports PCI codes<br>"
+              . "${_POST['pci_vendor_code']}:"
+              . "${_POST['pci_device_code']}" );
+    }
+} else if ( $fmt_extension != "rom"
+            && ( $pci_vendor_code != "" || $pci_device_code != "" ) ) {
+    die (   "'$fmt_extension' format was selected but PCI IDs were"
+          . " also entered.<br>Did you mean to select 'rom' output format"
+          . " instead?" );
+}
+
+/**
+ * remove temporary build directory
+ *
+ * @return bool true if removal is successful, false otherwise
+ */
+function rm_build_dir ()
+{
+    global $build_dir;
+    global $keep_build_dir;
+
+    if ( $keep_build_dir !== true ) {
+        rm_file_or_dir ( $build_dir );
+    }
+}
+
+// Arrange for the build directory to always be removed on exit.
+$build_dir = "";
+$keep_build_dir = false;
+register_shutdown_function ( 'rm_build_dir' );
+
+// Make temporary copy of src directory
+$build_dir = mktempcopy ( "$src_dir", "/tmp", "MDCROM" );
+$config_dir = $build_dir . "/config";
+
+// Write config files with supplied flags
+write_ipxe_config_files ( $config_dir, $flags );
+
+// Handle a possible embedded script
+$emb_script_cmd = "";
+$embedded_script = isset ( $_POST['embedded_script'] ) ? $_POST['embedded_script'] : "";
+if ( $embedded_script != "" ) {
+    $emb_script_path = "$build_dir" . "/script0.ipxe";
+
+	if ( substr ( $embedded_script, 0, 5 ) != "#!ipxe" ) {
+		$embedded_script = "#!ipxe\n" . $embedded_script;
+	}
+
+    // iPXE 0.9.7 doesn't like '\r\n" in the shebang...
+    $embedded_script = str_replace ( "\r\n", "\n", $embedded_script );
+
+    write_file_from_string ( $emb_script_path, $embedded_script );
+    $emb_script_cmd = "EMBEDDED_IMAGE=${emb_script_path}";
+}
+
+// Make the requested image.  $status is set to 0 on success
+$make_target = "bin/${nic}.${fmt_extension}";
+$make_cmd = "make -C '$build_dir' '$make_target' $emb_script_cmd $2>&1";
+
+exec ( $make_cmd, $maketxt, $status );
+
+// Uncomment the following section for debugging
+
+/**
+
+echo "<h2>build.php:</h2>";
+echo "<h3>Begin debugging output</h3>";
+
+//echo "<h3>\$_POST variables</h3>";
+//echo "<pre>"; var_dump ( $_POST ); echo "</pre>";
+
+echo "<h3>Build options:</h3>";
+echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
+echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
+echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" .  "<br>";
+echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
+echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
+
+echo "<h3>Flags:</h3>";
+show_flags ( $flags );
+
+if ( $embedded_script != "" ) {
+    echo "<h3>Embedded script:</h3>";
+    echo "<blockquote>"."<pre>";
+    echo $embedded_script;
+    echo "</pre>"."</blockquote>";
+}
+
+echo "<h3>Make output:</h3>";
+echo "Make command: " . $make_cmd . "<br>";
+echo "Build status = <? echo $status ?>" . "<br>";
+echo "<blockquote>"."<pre>";
+echo htmlentities ( implode ("\n", $maketxt ) );
+echo "</pre>"."</blockquote>";
+// Uncomment the next line if you want to keep the
+// build directory around for inspection after building.
+$keep_build_dir = true;
+die ( "<h3>End debugging output</h3>" );
+
+**/ //   End debugging section
+
+// Send ROM to browser (with extreme prejudice)
+
+if ( $status == 0 ) {
+
+    $fp = fopen("${build_dir}/${make_target}", "rb" );
+    if ( $fp > 0 ) {
+
+        $len = filesize ( "${build_dir}/${make_target}" );
+        if ( $len > 0 ) {
+
+            $buf = fread ( $fp, $len );
+            fclose ( $fp );
+
+            // Delete build directory as soon as it is not needed
+            rm_build_dir ();
+
+            $output_filename = "ipxe-${version}-${nic}.${fmt_extension}";
+
+            // Try to force IE to handle downloading right.
+            Header ( "Cache-control: private");
+            Header ( "Content-Type: application/x-octet-stream; " .
+                     "name=$output_filename");
+            Header ( "Content-Disposition: attachment; " .
+                     "Filename=$output_filename");
+            Header ( "Content-Location: $output_filename");
+            Header ( "Content-Length: $len");
+
+            echo $buf;
+
+            exit ();
+        }
+    }
+}
+
+/*
+ * If we reach this point, the build has failed, and we provide
+ * debugging information for a potential bug report
+ *
+ */
+
+// Remove build directory
+rm_build_dir ();
+
+// Announce failure if $status from make was non-zero
+echo "<h2>Build failed.  Status = " . $status . "</h2>";
+echo "<h2>build.php:</h2>";
+echo "<h3>Build options:</h3>";
+echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
+echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
+echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" .  "<br>";
+echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
+echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
+
+echo "<h3>Flags:</h3>";
+show_flags ( $flags );
+
+if ( $embedded_script != "" ) {
+    echo "<h3>Embedded script:</h3>";
+    echo "<blockquote>"."<pre>";
+    echo $embedded_script;
+    echo "</pre>"."</blockquote>";
+}
+
+echo "<h3>Make output:</h3>";
+echo "Make command: " . $make_cmd . "<br>";
+echo "<blockquote>"."<pre>";
+echo htmlentities ( implode ("\n", $maketxt ) );
+echo "</pre>"."</blockquote>";
+
+echo "Please let us know that this happened, and paste the above output into your email message.<br>";
+
+include_once $bottom_inc;
+
+// For emacs:
+//  Local variables:
+//  c-basic-offset: 4
+//  c-indent-level: 4
+//  tab-width: 4
+//  End:
+
+?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/customize-flags.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/customize-flags.php
new file mode 100644
index 0000000..2309043
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/customize-flags.php
@@ -0,0 +1,69 @@
+<?php // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Get utility functions and set globals
+require_once "utils.php";
+
+// Prepare settable compile options for presentation to user
+$flags = default_flags ();
+
+$build = "<input type=\"submit\" name=\"A\" value=\"Get Image\">";
+$restart = "<input type=\"submit\" name=\"A\" value=\"Start Over\">";
+
+// Begin html output
+include_once $top_inc;
+
+?>
+
+<form action="build.php" method=POST>
+  <input type="hidden" name="version" value = "<? echo $version ?>">
+  <input type="hidden" name="use_flags" value="1">
+  <h3>
+    Make changes below and press <? echo $build ?> to create an image, <br>
+    Or press <? echo $restart ?> to return to the main page.
+  </h3>
+  <hr>
+  <ul>
+  <? require ( "directions.php" ); ?>
+  </ul>
+  <hr>
+  <? echo_flags( $flags ); ?>
+  <hr>
+  <h3>Embedded Script:</h3>
+  <? echo textarea ( "embedded_script", "", "10", "50" ); ?>
+  <br><br>
+  <hr>
+  <center><table width="35%"><tr>
+  <td align="left"> <? echo $build; ?> </td>
+  <td align="right"> <? echo $restart ?></td>
+  </tr></table></center>
+</form>
+
+<? include_once $bottom_inc; ?>
+<?
+// For emacs:
+//
+// Local variables:
+//  c-basic-offset: 4
+//  c-indent-level: 4
+//  tab-width: 4
+// End:
+?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/directions.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/directions.php
new file mode 100644
index 0000000..cba5eb4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/directions.php
@@ -0,0 +1,63 @@
+<?
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+?>
+    <li>
+      Choose an output format: <? echo keys_menubox ( "ofmt", $ofmts,
+      isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
+      <br><br>
+    </li>
+    <li>
+      Choose a NIC type: <? echo keys_menubox ( "nic", $nics,
+      isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
+      <br><br>
+    </li>
+    <li>
+      <strong>( optional — for binary ROM image format only )</strong> <br><br>
+      If you choose <em>Binary ROM image</em> as your output format, you must<br>
+      enter <strong>4 hex digits</strong> below for
+      <em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em>  <br>
+      that match the NIC device for which you are making this image.<br><br>
+      Information on how to determine NIC PCI IDs may be found
+      <a href="http://etherboot.org/wiki/romburning"
+      target="_blank">here</a>.
+      <br><br>
+      PCI VENDOR CODE:  <? echo textbox ( "pci_vendor_code",
+      isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
+              : "", 6 ); ?>
+        
+      PCI DEVICE CODE:  <? echo textbox ( "pci_device_code",
+      isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
+              : "", 6 ); ?>
+      <h4>Please note for ROM images:</h4>
+      <ul>
+        <li>
+          If you enter PCI IDs, we will attempt to determine the correct<br>
+          driver to support them, and will ignore any NIC type entered
+          above.<br><br>
+        </li>
+        <li>
+          iPXE does not support all possible PCI IDs for supported
+          NICs.
+          <br><br>
+        </li>
+      </ul>
+    </li>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html
new file mode 100644
index 0000000..444c5e6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html
@@ -0,0 +1 @@
+Automatic booting
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html
new file mode 100644
index 0000000..e135897
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html
@@ -0,0 +1 @@
+Tenths of a second for which the shell banner should appear
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html
new file mode 100644
index 0000000..e7036c0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html
@@ -0,0 +1,3 @@
+Serial Console I/O port address.  Common addresses are:<br>
+COM1 =>	0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8
+
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMDATA.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMDATA.html
new file mode 100644
index 0000000..a27e275
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMDATA.html
@@ -0,0 +1 @@
+Serial Console Data bits
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPARITY.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPARITY.html
new file mode 100644
index 0000000..14f3595
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPARITY.html
@@ -0,0 +1 @@
+Serial Console Parity: 0=None, 1=Odd, 2=Even
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html
new file mode 100644
index 0000000..6e41a10
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html
@@ -0,0 +1 @@
+Keep settings from a previous user of the serial port
\ No newline at end of file
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSPEED.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSPEED.html
new file mode 100644
index 0000000..32b6859
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSPEED.html
@@ -0,0 +1 @@
+Serial Console Baud rate
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSTOP.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSTOP.html
new file mode 100644
index 0000000..ae3fd24
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/COMSTOP.html
@@ -0,0 +1 @@
+Serial Console Stop bits
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html
new file mode 100644
index 0000000..1256c06
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html
@@ -0,0 +1 @@
+Option configuration console
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html
new file mode 100644
index 0000000..144eea3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html
@@ -0,0 +1 @@
+Enable Default BIOS console
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html
new file mode 100644
index 0000000..f35e2ff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html
@@ -0,0 +1 @@
+Enable Serial port console
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html
new file mode 100644
index 0000000..26fdf8a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html
@@ -0,0 +1 @@
+Wireless WEP encryption support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html
new file mode 100644
index 0000000..b218a1e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html
@@ -0,0 +1 @@
+Wireless WPA encryption support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html
new file mode 100644
index 0000000..947597d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html
@@ -0,0 +1 @@
+Wireless WPA2 encryption support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html
new file mode 100644
index 0000000..a0c31c7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html
@@ -0,0 +1 @@
+DHCP management commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html
new file mode 100644
index 0000000..1029b9c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html
@@ -0,0 +1 @@
+DNS resolver
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html
new file mode 100644
index 0000000..7686d5d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html
@@ -0,0 +1 @@
+File Transfer Protocol
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html
new file mode 100644
index 0000000..c28d888
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html
@@ -0,0 +1 @@
+Hypertext Transfer Protocol
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html
new file mode 100644
index 0000000..f2b31b1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html
@@ -0,0 +1 @@
+Trivial File Transfer Protocol
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html
new file mode 100644
index 0000000..0e2b2a5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html
@@ -0,0 +1 @@
+Interface management commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html
new file mode 100644
index 0000000..d85e5d0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html
@@ -0,0 +1 @@
+Linux bzImage image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html
new file mode 100644
index 0000000..6f5acb5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html
@@ -0,0 +1 @@
+Image management commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html
new file mode 100644
index 0000000..5e39e8b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html
@@ -0,0 +1 @@
+ELF image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html
new file mode 100644
index 0000000..6a092a2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html
@@ -0,0 +1 @@
+MultiBoot image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html
new file mode 100644
index 0000000..eb78e03
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html
@@ -0,0 +1 @@
+NBI image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html
new file mode 100644
index 0000000..bdca384
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html
@@ -0,0 +1 @@
+PXE image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html
new file mode 100644
index 0000000..8741672
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html
@@ -0,0 +1 @@
+iPXE script image support
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html
new file mode 100644
index 0000000..0d5bd4a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html
@@ -0,0 +1 @@
+Wireless interface management commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html
new file mode 100644
index 0000000..a0bdc17
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html
@@ -0,0 +1 @@
+NMB resolver
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NVO_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NVO_CMD.html
new file mode 100644
index 0000000..5346f3f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/NVO_CMD.html
@@ -0,0 +1 @@
+Non-volatile option storage commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html
new file mode 100644
index 0000000..8114c26
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html
@@ -0,0 +1 @@
+Routing table management commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html
new file mode 100644
index 0000000..2e9d840
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html
@@ -0,0 +1 @@
+SAN boot commands
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/flag-table.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/flag-table.php
new file mode 100644
index 0000000..078e5fd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/flag-table.php
@@ -0,0 +1,499 @@
+<?php // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+$ofmts = array
+	( "Floppy bootable image (.dsk)" => "dsk",
+	  "SYSLINUX-based bootable floppy image (.sdsk)" => "sdsk",
+	  "ISO bootable image (.iso)" => "iso",
+	  "ISO bootable image with legacy floppy emulation (.liso)" => "liso",
+	  "Linux kernel (SYSLINUX/GRUB/LILO) loadable image (.lkrn)" => "lkrn",
+	  "USB Keychain disk image (.usb)" => "usb",
+	  "ROM binary (flashable) image (.rom)" => "rom",
+	  "ROM binary (flashable) for problem PMM BIOSES  (.hrom)" => "hrom",
+	  "PXE bootstrap loader image [Unload PXE stack] (.pxe)" => "pxe",
+	  "PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)" => "kpxe",
+	  "PXE bootstrap loader keep [Keep PXE stack method 2] (.kkpxe)" => "kkpxe",
+	);
+
+$flag_table = array (
+
+	// Begin General Options:
+
+	"HDR_MISC_OPTIONS"
+	=> array (
+	   "flag" => "HDR_MISC_OPTIONS",
+	   "hide_from_user" => "yes",  // Hide even the header
+	   "type" => "header",
+	   "label" => "Miscellaneous Options"
+		),
+
+	"PRODUCT_NAME"
+	=> array (
+	   "flag" => "PRODUCT_NAME",
+	   "hide_from_user" => "yes",
+	   "type" => "string",
+	   "value" => "",
+	   "cfgsec" => "general"
+	   ),
+
+	"PRODUCT_SHORT_NAME"
+	=> array (
+	   "flag" => "PRODUCT_SHORT_NAME",
+	   "hide_from_user" => "yes",
+	   "type" => "string",
+	   "value" => "iPXE",
+	   "cfgsec" => "general"
+	   ),
+
+	// End General Options:
+
+	// Begin Console Options:
+
+	"HDR_CONSOLE_OPTIONS"
+	=> array (
+	   "flag" => "HDR_CONSOLE_OPTIONS",
+	   "type" => "header",
+	   "label" => "Console Options"
+		),
+
+	"CONSOLE_PCBIOS"
+	=> array (
+	   "flag" => "CONSOLE_PCBIOS",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "console"
+	   ),
+
+	"CONSOLE_SERIAL"
+	=> array (
+	   "flag" => "CONSOLE_SERIAL",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "console"
+	   ),
+
+	"BANNER_TIMEOUT"
+	=> array (
+	   "flag" => "BANNER_TIMEOUT",
+	   "type" => "integer",
+	   "value" => "20",
+	   "cfgsec" => "general"
+	   ),
+
+	// End Console Options
+
+	// Begin Network Protocol Options:
+
+	"HDR_NETWORK_PROTOCOL_OPTIONS"
+	=> array (
+	   "flag" => "HDR_NETWORK_PROTOCOL_OPTIONS",
+	   "hide_from_user" => "yes",  // Hide even the header
+	   "type" => "header",
+	   "label" => "Network Protocol Options"
+		),
+
+	"NET_PROTO_IPV4"
+	=> array (
+	   "flag" => "NET_PROTO_IPV4",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "hide_from_user" => "yes",
+	   "cfgsec" => "general"
+	   ),
+
+	// End Network Protocol Options
+
+	// Begin Serial Port configuration
+
+	"HDR_SERIAL_PORT_OPTIONS"
+	=> array (
+	   "flag" => "HDR_SERIAL_PORT_OPTIONS",
+	   "type" => "header",
+	   "label" => "Serial Port Options"
+		),
+
+	"COMCONSOLE"
+	=> array (
+	   "flag" => "COMCONSOLE",
+	   "type" => "integer-hex", // e.g. 0x378
+	   "value" => "0x3F8",
+	   "cfgsec" => "serial"
+		),
+
+	"COMPRESERVE"
+	=> array (
+	   "flag" => "COMPRESERVE",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "serial"
+	   ),
+
+	"COMSPEED"
+	=> array (
+	   "flag" => "COMSPEED",
+	   "type" => "integer",
+	   "value" => "115200",
+	   "cfgsec" => "serial"
+	   ),
+
+	"COMDATA"
+	=> array (
+	   "flag" => "COMDATA",
+	   "type" => "integer",
+	   "value" => "8",
+	   "cfgsec" => "serial"
+	   ),
+
+	"COMPARITY"
+	=> array (
+	   "flag" => "COMPARITY",
+	   "type" => "integer",
+	   "value" => "0",
+	   "cfgsec" => "serial"
+	   ),
+
+	"COMSTOP"
+	=> array (
+	   "flag" => "COMSTOP",
+	   "type" => "integer",
+	   "value" => "1",
+	   "cfgsec" => "serial"
+	   ),
+
+	// End Serial Options
+
+	// Begin Download Protocols
+
+	"HDR_DOWNLOAD_PROTOCOLS"
+	=> array (
+	   "flag" => "HDR_DOWNLOAD_PROTOCOLS",
+	   "type" => "header",
+	   "label" => "Download Protocols"
+		),
+
+	"DOWNLOAD_PROTO_TFTP"
+	=> array (
+	   "flag" => "DOWNLOAD_PROTO_TFTP",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"DOWNLOAD_PROTO_HTTP"
+	=> array (
+	   "flag" => "DOWNLOAD_PROTO_HTTP",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"DOWNLOAD_PROTO_HTTPS"
+	=> array (
+	   "flag" => "DOWNLOAD_PROTO_HTTPS",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "general"
+	   ),
+
+	"DOWNLOAD_PROTO_FTP"
+	=> array (
+	   "flag" => "DOWNLOAD_PROTO_FTP",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "general"
+	   ),
+
+	// End Download Protocols
+
+	// Begin SAN boot protocols
+
+	"HDR_SANBOOT_PROTOCOLS"
+	=> array (
+	   "flag" => "HDR_SANBOOT_PROTOCOLS",
+	   "type" => "header",
+	   "label" => "SAN Boot Protocols"
+		),
+
+	"SANBOOT_PROTO_ISCSI"
+	=> array (
+	   "flag" => "SANBOOT_PROTO_ISCSI",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"SANBOOT_PROTO_AOE"
+	=> array (
+	   "flag" => "SANBOOT_PROTO_AOE",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	// End SAN boot protocols
+
+	// Begin Name resolution modules
+
+	"HDR_NAME_RESOLUTION_MODULES"
+	=> array (
+	   "flag" => "HDR_NAME_RESOLUTION_MODULES",
+	   "type" => "header",
+	   "label" => "Name Resolution Modules"
+	   ),
+
+	"DNS_RESOLVER"
+	=> array (
+	   "flag" => "DNS_RESOLVER",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+		),
+
+	"NMB_RESOLVER"
+	=> array (
+	   "flag" => "NMB_RESOLVER",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "hide_from_user" => "yes",
+	   "cfgsec" => "general"
+		),
+
+	// End Name resolution modules
+
+	// Begin Image types
+
+	"HDR_IMAGE_TYPES"
+	=> array (
+	   "flag" => "HDR_IMAGE_TYPES",
+	   "type" => "header",
+	   "label" => "Image Types",
+	   ),
+
+	"IMAGE_ELF"
+	=> array (
+	   "flag" => "IMAGE_ELF",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_NBI"
+	=> array (
+	   "flag" => "IMAGE_NBI",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+		),
+
+	"IMAGE_MULTIBOOT"
+	=> array (
+	   "flag" => "IMAGE_MULTIBOOT",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_PXE"
+	=> array (
+	   "flag" => "IMAGE_PXE",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_SCRIPT"
+	=> array (
+	   "flag" => "IMAGE_SCRIPT",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_BZIMAGE"
+	=> array (
+	   "flag" => "IMAGE_BZIMAGE",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_COMBOOT"
+	=> array (
+	   "flag" => "IMAGE_COMBOOT",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	// End Image types
+
+	// Begin Command-line commands to include
+
+	"HDR_COMMAND_LINE_OPTIONS"
+	=> array (
+	   "flag" => "HDR_COMMAND_LINE_OPTIONS",
+	   "type" => "header",
+	   "label" => "Command Line Options",
+	   ),
+
+	"AUTOBOOT_CMD"
+	=> array (
+	   "flag" => "AUTOBOOT_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"NVO_CMD"
+	=> array (
+	   "flag" => "NVO_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"CONFIG_CMD"
+	=> array (
+	   "flag" => "CONFIG_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IFMGMT_CMD"
+	=> array (
+	   "flag" => "IFMGMT_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IWMGMT_CMD"
+	=> array (
+	   "flag" => "IWMGMT_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"ROUTE_CMD"
+	=> array (
+	   "flag" => "ROUTE_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"IMAGE_CMD"
+	=> array (
+	   "flag" => "IMAGE_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"DHCP_CMD"
+	=> array (
+	   "flag" => "DHCP_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+		),
+
+	"SANBOOT_CMD"
+	=> array (
+	   "flag" => "SANBOOT_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+		),
+
+	"LOGIN_CMD"
+	=> array (
+	   "flag" => "LOGIN_CMD",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+		),
+
+	"TIME_CMD"
+	=> array (
+	   "flag" => "TIME_CMD",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "general"
+		),
+
+	"DIGEST_CMD"
+	=> array (
+	   "flag" => "DIGEST_CMD",
+	   "type" => "on/off",
+	   "value" => "off",
+	   "cfgsec" => "general"
+		),
+
+	// End Command-line commands to include
+
+	// Begin Wireless options
+
+	"HDR_WIRELESS_OPTIONS"
+	=> array (
+	   "flag" => "HDR_WIRELESS_OPTIONS",
+	   "type" => "header",
+	   "label" => "Wireless Interface Options",
+	   ),
+
+	"CRYPTO_80211_WEP"
+	=> array (
+	   "flag" => "CRYPTO_80211_WEP",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"CRYPTO_80211_WPA"
+	=> array (
+	   "flag" => "CRYPTO_80211_WPA",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	"CRYPTO_80211_WPA2"
+	=> array (
+	   "flag" => "CRYPTO_80211_WPA2",
+	   "type" => "on/off",
+	   "value" => "on",
+	   "cfgsec" => "general"
+	   ),
+
+	// End Wireless options
+
+);
+
+// For emacs:
+// Local variables:
+//	c-basic-offset: 4
+//	c-indent-level: 4
+//	tab-width: 4
+// End:
+
+?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/globals.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/globals.php
new file mode 100644
index 0000000..822e4bc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/globals.php
@@ -0,0 +1,51 @@
+<?php // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Directory containing iPXE source code tree
+$src_dir = "../../src";
+
+// Compute iPXE version based on source tree
+exec ( "make -C '$src_dir' version 2>&1", $make_output, $status );
+$version = ( $status == 0 && count ( $make_output  ) > 1 )
+           ? trim ( $make_output[count ( $make_output ) - 2] )
+           : "";
+
+// Email address of person responsible for this website
+$webmaster_email = "webmaster at example.com";
+
+// Files that header and footer text
+$top_inc = "top.php";
+$bottom_inc = "bottom.php";
+
+// Descriptive strings
+$header_title = "ROM-o-matic for iPXE $version";
+$html_tagline = "ROM-o-matic dynamically generates iPXE images";
+$html_title   = "ROM-o-matic for iPXE $version";
+$description  = "a dynamic iPXE image generator";
+
+// For emacs:
+// Local variables:
+//  c-basic-offset: 4
+//  c-indent-level: 4
+//  tab-width: 4
+// End:
+
+?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/index.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/index.php
new file mode 100644
index 0000000..12b7e1a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/index.php
@@ -0,0 +1,47 @@
+<?php // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Get utility functions and set globals
+require_once "utils.php";
+
+// Begin html output
+include_once $top_inc;
+
+?>
+<form action="build.php" method=POST>
+  <input type="hidden" name="version" value = "<? echo $version ?>">
+  <h3>To create an image:</h3>
+  <ol>
+    <? require ( "directions.php" ); ?>
+    <li>
+      Generate and download an image:
+      <input type="submit" name="A" value="Get Image">
+      <br><br>
+    </li>
+    <li>
+      (optional) Customize image configuration options:
+      <input type="submit" name="A" value="Customize">
+      <br><br>
+    </li>
+  </ol>
+</form>
+
+<? include_once $bottom_inc ?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/top.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/top.php
new file mode 100644
index 0000000..2556208
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/top.php
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<?
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+?>
+
+<html>
+<head>
+  <link rev="made" href="mailto:<? echo "${webmaster_email}" ?>">
+  <meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net">
+  <title><? echo $header_title ?></title>
+  <meta name="description" content="<? echo $description ?>">
+</head>
+<h1>
+<? echo "$html_title" ?> 
+</h1>
+<hr>
+<h2>
+<? echo "$html_tagline" ?>
+</h2>
+</form>
+<hr>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/utils.php b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/utils.php
new file mode 100644
index 0000000..dc5bd41
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/rom-o-matic/utils.php
@@ -0,0 +1,683 @@
+<? // -*- Mode: PHP; -*-
+
+/**
+ * Copyright (C) 2009 Marty Connor <mdc at etherboot.org>.
+ * Copyright (C) 2009 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+// Include table of user-configurable iPXE options
+require_once "flag-table.php";
+
+// Include user-shadowable globals
+require_once "globals.php";
+
+// Allow user to shadow globals
+if ( is_file ( 'local-config.php' ) ) {
+    include_once "local-config.php";
+}
+
+////
+// General utility functions
+////
+
+/**
+ * Remove undesirable characters from a given string
+ *
+ * Certain characters have the potential to be used for
+ * malicious purposes by web-based attackers.  This routine
+ * filters out such characters.
+ *
+ * @param string $s supplied string
+ *
+ * @return string returned string with unwanted characters
+ *                removed
+ */
+function cleanstring ( $s )
+{
+    $len = strlen ( $s );
+    if ( $len > 80 ) {
+        $s = substr ( $s, 0, 80 );
+    }
+
+    $s      = trim ( $s );
+    $pos    = 0;
+    $result = "";
+
+    while ( $pos < $len ) {
+        $ltr = ord ( ucfirst ( $s[$pos] ) );
+        if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) ||
+             ( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) ||
+             ( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) ||
+             ( $ltr == ord ( "_" ) ) ||
+             ( $ltr == ord ( "+" ) ) ||
+             ( $ltr == ord ( ":" ) ) ||
+             ( $ltr == ord ( "/" ) ) ||
+             ( $ltr == ord ( "-" ) ) ) {
+            $result .= $s[$pos];
+        }
+        $pos++;
+    }
+    return $result;
+}
+
+/**
+ * Return URL of the currently running script, minus the filename
+ *
+ * @return string the URL of the currently running script, minus the filename
+ */
+function curDirURL ()
+{
+        $dir = dirname ( $_SERVER['PHP_SELF'] );
+
+        if ( $dir == "." || $dir == "/" ) {
+                $dir = "";
+        }
+
+        $isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" );
+        $port = ( isset($_SERVER["SERVER_PORT"] ) &&
+                          ( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) ||
+                                ( $isHTTPS  && $_SERVER["SERVER_PORT"] != "443" ) ) );
+
+        $port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : '';
+
+        $dest = ( $isHTTPS ? 'https://' : 'http://' ) .
+                $_SERVER["SERVER_NAME"] . $dir . "/";
+
+        return $dest;
+}
+
+/**
+ * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
+ *
+ * $src_dir must contain the path of the iPXE src directory for this build
+ *
+ * @return array[0] array $new_nics
+ * @return array[1] array $roms
+ */
+function parse_nic_file ()
+{
+    global $src_dir;
+
+    $fd = fopen ( "$src_dir/bin/NIC", "r" );
+    if ( ! $fd ) {
+        die ( "Missing src/bin/NIC file.  'make bin/NIC'" );
+    }
+
+    $nics = array ();
+    $roms = array ();
+    $nic = "";
+
+    while ( !feof ( $fd ) ) {
+
+        $line = trim ( fgets ( $fd, 200 ) );
+
+        $first_eight_chars = substr ( $line, 0, 8 );
+        settype ( $first_eight_chars, "string" );
+
+        if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
+
+            // get pathname of NIC driver
+            list ( $dummy, $nic ) = split( "[ \t]+", $line );
+            settype ( $nic, "string" );
+
+            // extract filename name of driver from pathname
+            $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
+			   strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
+
+            $nics[$nic] = $nic;
+
+            // For each ISA NIC, there can only be one ROM variant
+            $roms[$nic] = $nic;
+        }
+
+        // If the first 8 digits of the line are hex digits
+        // add this rom to the current nic family.
+
+        if (    ( strlen ( $first_eight_chars ) == 8 )
+             && ( ctype_xdigit ( $first_eight_chars ) )
+             && ( $nic != "" ) ) {
+
+            $roms[$first_eight_chars] = $nic;
+        }
+    }
+    fclose ( $fd );
+
+    // put most NICs in nice alpha order for menu
+    ksort ( $nics );
+
+    // add special cases to the top
+
+	$new_nics = array ( "all-drivers" => "ipxe",
+						"undionly" => "undionly",
+						"undi" => "undi",
+    );
+
+	foreach ( $nics as $key => $value ) {
+		// skip the undi driver
+		if ( $key != "undi" ) {
+			$new_nics[$key] = $value;
+		}
+	}
+
+	return array ( $new_nics, $roms );
+}
+
+////
+// HTML form utility functions
+////
+
+/**
+ * Return html code to create hidden form input fields
+ *
+ * @param string $flag  name of form variable to set
+ * @param string $value value to give form variable
+ *
+ * @return string html code for given hidden form input field
+ */
+function hidden ( $flag, $value )
+{
+    $value = htmlentities ( $value );
+    return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
+}
+
+/**
+ * Return html code to create checkbox form input fields
+ *
+ * @param string $flag  name of form variable to set
+ * @param string $value "on" means box should be checked
+ *
+ * @return string html code for given hidden form input field
+ */
+function checkbox ( $flag, $value )
+{
+    return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
+        ($value == "on" ? " checked>" : ">" );
+}
+
+/**
+ * Return html code to create text form input fields
+ *
+ * @param string $flag  name of form variable to set
+ * @param string $value initial contents of field
+ * @param string $size  size in characters of text box
+ *
+ * @return string html code for given text input field
+ */
+function textbox ( $flag, $value, $size )
+{
+    $value = htmlentities ( $value );
+    return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
+}
+
+/**
+ * Return html code to create textarea form fields
+ *
+ * @param string $flag  name of form variable to set
+ * @param string $value initial contents of textarea
+ * @param string $rows  height of text area in rows
+ * @param string $cols  width of text area in columns
+ *
+ * @return string html code for given textarea input field
+ */
+function textarea ( $flag, $value, $rows, $cols )
+{
+    $value = htmlentities ( $value );
+    return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
+            . $value . "</textarea>";
+}
+
+/**
+ * Return html code to create select (menu) form fields
+ *
+ * Use array of strings as menu choices
+ *
+ * @param string $flag    name of form variable to set
+ * @param array  $options array of strings representing choices
+ * @param string $value   value of choice to select in menu
+ *
+ * @return string html code for given select (menu) input field
+ */
+function menubox ( $name, $options, $value )
+{
+    $s="<select name=\"$name\">";
+
+	foreach ( $options as $ignore => $option ) {
+        if ( !$value ) $value = $option;
+        $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
+            htmlentities ( $option ) . "</option>";
+    }
+    return $s . "</select>";
+}
+
+/**
+ * Return html code to create select (menu) form fields
+ *
+ * Use indices of array of strings as menu choices rather than
+ * the values pointed to by the indicies.
+ *
+ * @param string $flag    name of form variable to set
+ * @param array  $options array of strings representing choices
+ * @param string $value   value of choice to select in menu
+ *
+ * @return string html code for given select (menu) input field
+ */
+function keys_menubox ( $name, $options, $value )
+{
+    $s="<select name=\"$name\">";
+
+    foreach ( $options as $option => $ignore ) {
+        if ( !$value ) $value = $option;
+        $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
+            htmlentities ( $option ) . "</option>";
+    }
+    return $s . "</select>";
+}
+
+////
+// Flag (compile option) handling functions
+////
+
+/**
+ * Return default compile options (flags)
+ *
+ * Initial compile options are in a global called $flag_table.
+ * Create and return an array containing the ones we want.
+ *
+ * @return array default compile options (flags)
+ */
+function default_flags ()
+{
+    global $flag_table;
+
+    $flags = array ();
+
+    foreach ( $flag_table as $key => $props ) {
+
+        $flag  = $props["flag"];
+        $type  = $props["type"];
+
+        // Fields like headers have no "value" property
+        if ( isset ( $props["value"] ) ) {
+            $flags[$flag] = $props["value"];
+        }
+    }
+    return $flags;
+}
+
+/**
+ * Return combination of default and user compile options (flags)
+ *
+ * Initial compile options are in a global called $flag_table.
+ * Compile options may have been changed via form input. We return
+ * an array with either the default value of each option or a user
+ * supplied value from form input.
+ *
+ * @return array combined default and user supplied compile options (flags)
+ */
+function get_flags ()
+{
+    global $flag_table;
+
+    $flags = default_flags ();
+
+    if ( ! isset ( $_POST["use_flags"] ) )
+        return $flags;
+
+    foreach ( $flag_table as $key => $props ) {
+
+        $flag = $props["flag"];
+        $type = $props["type"];
+
+        if ( isset ( $_POST["$flag"] ) ) {
+            $flags[$flag] = $_POST["$flag"];
+            if ( $type == "integer-hex" ) {
+                if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
+                    $flags[$flag] = "0x" . $flags[$flag];
+                }
+            }
+        } else if ( $type == "on/off" ) {
+			// Unchecked checkboxes don't pass any POST value
+			// so we must check for them specially.  At this
+			// point we know that there is no $_POST value set
+			// for this option.  If it is a checkbox, this means
+			// it is unchecked, so record that in $flags so we
+			// can later generate an #undef for this option.
+            $flags[$flag] = "off";
+        }
+    }
+    return $flags;
+}
+
+/**
+ * Output given value in appropriate format for iPXE config file
+ *
+ * iPXE config/*.h files use C pre-processor syntax.  Output the given
+ * compile option in a format appropriate to its type
+ *
+ * @param string $key   index into $flag_table for given compile option
+ * @param string $value value we wish to set compile option to
+ *
+ * @return string code to set compile option to given value
+ */
+function pprint_flag ( $key, $value )
+{
+    global $flag_table;
+
+    // Determine type of given compile option (flag)
+    $type = $flag_table[$key]["type"];
+    $s = "";
+
+    if ( $type == "on/off" && $value == "on" ) {
+        $s = "#define $key";
+    } else if ( $type == "on/off" && $value != "on" ) {
+        $s = "#undef $key";
+    } else if ( $type == "string" ) {
+        $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
+    } else if ($type == "qstring" ) {
+        $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
+    } else {
+        $s = "#define $key " . cleanstring ( $value );
+    }
+
+    return $s;
+}
+
+/**
+ * Output html code to display all compile options as a table
+ *
+ * @param array $flags array of compile options
+ *
+ * @return void
+ */
+function echo_flags ( $flags )
+{
+    global $flag_table;
+
+    echo "<table>\n";
+
+	foreach ( $flag_table as $key => $props ) {
+
+        // Hide parameters from users that should not be changed.
+        $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
+
+        $flag = $props["flag"];
+        $type = $props["type"];
+
+        $value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
+
+        if ( $hide_from_user == "yes" ) {
+
+            // Hidden flags cannot not be set by the user.  We use hidden form
+            // fields to keep them at their default values.
+            if ( $type != "header" ) {
+                echo hidden ( $flag, $value );
+            }
+
+        } else {
+
+            // Flag (iPXE compile option) should be displayed to user
+
+            if ( $type == "header" ) {
+
+                $label = $props["label"];
+                echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
+
+            } else if ($type == "on/off" ) {
+
+                echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
+
+            } else {   // don't display checkbox for non-on/off flags
+
+                echo "<td> </td><td><strong>$flag: </strong>";
+
+                if ($type == "choice" ) {
+                    $options = $props["options"];
+                    echo menubox($flag, $options, $value);
+
+                } else {
+
+                    echo textbox($flag, $value, ($type == "integer" ||
+                                                 $type == "integer-hex"
+                                                     ? 7 : 25));
+                }
+                echo "</td>";
+            }
+            echo "</tr>\n";
+
+            if ( $type != "header" ) {
+				echo "<tr><td> </td>";
+				echo "<td>\n";
+				if ( is_file ( "doc/$flag.html" ) ) {
+					include_once "doc/$flag.html";
+				}
+				echo "\n</td></tr>\n";
+            }
+        }
+    }
+    echo "</table>";
+}
+
+/**
+ * Return an array of configuration sections used in all compile options
+ *
+ * $flag_table, the global list of compile options contains a 'cfgsec'
+ * property for each flag we are interested in.  We return a list of
+ * all the unique cfgsec options we find in $flag_table.
+ *
+ * @return array an array of strings representing all unique cfgsec values
+ *               found in $flag_table
+ */
+function get_flag_cfgsecs ()
+{
+    global $flag_table;
+    $cfgsecs = array ();
+
+    foreach ( $flag_table as $key => $props ) {
+        if ( isset ( $props['cfgsec'] ) ) {
+            $cfgsec = $props["cfgsec"];
+            $cfgsecs[$cfgsec] = $cfgsec;
+        }
+    }
+    return $cfgsecs;
+}
+
+////
+// File and directory handling functions
+////
+
+/**
+ * Create a copy of a given source directory to a given destination
+ *
+ * Since we are going to modify the source directory, we create a copy
+ * of the directory with a unique name in the given destination directory.
+ * We supply a prefix for the tempnam call to prepend to the random filename
+ * it generates.
+ *
+ * @param string $src    source directory
+ * @param string $dst    destination directory
+ * @param string $prefix string to append to directory created
+ *
+ * @return string absolute path to destination directory
+ */
+function mktempcopy ( $src, $dst, $prefix )
+{
+    if ( $src[0] != "/" ) {
+        $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
+    }
+
+    // Create a file in the given destination directory with a unique name
+    $dir = tempnam ( $dst, $prefix );
+
+    // Delete the file just created, since it would interfere with the copy we
+    // are about to do.  We only care that the dir name we copy to is unique.
+    unlink ( $dir );
+
+    exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
+
+    if ( $status != 0 ) {
+        die ( "src directory copy failed!" );
+    }
+    return $dir;
+}
+
+/**
+ * Write iPXE config files based on value of given flags
+ *
+ * iPXE compile options are stored in src/config/*.h .
+ * We write out a config file for each set of options.
+ *
+ * @param string $config_dir directory to write .h files to
+ * @param array  $flags array of compile options for this build
+ *
+ * @return void
+ */
+function write_ipxe_config_files ( $config_dir, $flags )
+{
+    global $flag_table;
+
+    $cfgsecs = get_flag_cfgsecs ();
+
+    foreach ( $cfgsecs as $cfgsec ) {
+
+        $fname = $config_dir . "/" . $cfgsec . ".h";
+
+        $fp = fopen ( $fname, "wb" );
+        if ( $fp <= 0 ) {
+            die ( "Unable to open $fname file for output!" );
+        }
+
+        $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
+
+        fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
+        fwrite ( $fp, "#define ${ifdef_secname}\n" );
+        fwrite ( $fp, "#include <config/defaults.h>\n" );
+
+        foreach ( $flags as $key => $value ) {
+            // When the flag matches this section name, write it out
+            if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
+                fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
+            }
+        }
+        fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
+        fclose ( $fp );
+    }
+}
+
+/**
+ * Output a string to a file
+ *
+ * Output a given string to a given pathname. The file will be created if
+ * necessary, and the string will replace the file's contents in all cases.
+ *
+ * @param string $fname pathname of file to output string to
+ * @param string $ftext text to output to file
+ *
+ * @return void
+ */
+function write_file_from_string ( $fname, $ftext )
+{
+        $fp = fopen ( $fname, "wb" );
+        if ( ! $fp ) {
+            die ( "Unable to open $fname file for output!" );
+        }
+        fwrite ( $fp, $ftext );
+        fclose ( $fp );
+}
+
+/**
+ * Delete a file or recursively delete a directory tree
+ *
+ * @param   string   $file_or_dir_name  name of file or directory to delete
+ * @return  bool     Returns TRUE on success, FALSE on failure
+ */
+function rm_file_or_dir ( $file_or_dir_name )
+{
+    if ( ! file_exists ( $file_or_dir_name ) ) {
+        return false;
+    }
+
+    if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
+        return unlink ( $file_or_dir_name );
+    }
+
+    $dir = dir ( $file_or_dir_name );
+    while ( ( $dir_entry = $dir->read () ) !== false ) {
+
+        if ( $dir_entry == '.' || $dir_entry == '..') {
+            continue;
+        }
+        rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
+    }
+    $dir->close();
+
+    return rmdir ( $file_or_dir_name );
+}
+
+////
+// Debugging functions
+////
+
+/**
+ * Emit html code to display given array of compile options (flags)
+ *
+ * @param array  $flags array of compile options for this build
+ *
+ * @return void
+ */
+function show_flags ( $flags )
+{
+    echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
+
+	foreach ( $flags as $key => $flag ) {
+        echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
+    }
+}
+
+/**
+ * Emit HTML code to display default array of compile options (flags)
+ *
+ * $flag_table contains default compile options and properties.  This
+ * routine outputs HTML code to display all properties of $flag_table.
+ *
+ * @return void
+ */
+function dump_flag_table ()
+{
+    global $flag_table;
+
+    echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
+
+	foreach ( $flag_table as $key => $props ) {
+        print ( "flag_table[" . $key . "] = " . "<br>" );
+
+		foreach ( $props as $key2 => $props2 ) {
+            print ( "   " . $key2 . " = " . $props2 . "<br>" );
+        }
+    }
+}
+
+// Parse src/bin/NIC file
+list ( $nics, $roms ) = parse_nic_file ();
+
+// For emacs:
+// Local variables:
+//  c-basic-offset: 4
+//  c-indent-level: 4
+//  tab-width: 4
+// End:
+
+?>
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/.gitignore b/qemu-0.15.x/roms/ipxe/contrib/vm/.gitignore
new file mode 100644
index 0000000..610792e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/.gitignore
@@ -0,0 +1,6 @@
+bochsout.txt
+parport.out
+ne2k-tx.log
+ne2k-txdump.txt
+bochs
+qemu
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/Makefile b/qemu-0.15.x/roms/ipxe/contrib/vm/Makefile
new file mode 100644
index 0000000..3c0e645
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/Makefile
@@ -0,0 +1,7 @@
+all : serial-console.1
+
+%.1 : %
+	pod2man $< > $@
+
+clean :
+	rm -f serial-console.1
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/bochs-writable-ROM-patch b/qemu-0.15.x/roms/ipxe/contrib/vm/bochs-writable-ROM-patch
new file mode 100644
index 0000000..dc586dd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/bochs-writable-ROM-patch
@@ -0,0 +1,15 @@
+--- memory/memory.cc	18 Oct 2008 18:10:14 -0000	1.71
++++ memory/memory.cc	21 Oct 2008 19:47:07 -0000
+@@ -172,7 +172,11 @@
+             break;
+
+           case 0x0:   // Writes to ROM, Inhibit
+-            BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
++            if ((a20addr & 0xfffe0000) == 0x000e0000) {
++	      BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
++	    } else {
++	      BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ] = *data_ptr;
++            }
+             break;
+
+           default:
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/bochsrc.txt b/qemu-0.15.x/roms/ipxe/contrib/vm/bochsrc.txt
new file mode 100644
index 0000000..32842a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/bochsrc.txt
@@ -0,0 +1,751 @@
+# You may now use double quotes around pathnames, in case
+# your pathname includes spaces.
+
+#=======================================================================
+# CONFIG_INTERFACE
+#
+# The configuration interface is a series of menus or dialog boxes that
+# allows you to change all the settings that control Bochs's behavior.
+# There are two choices of configuration interface: a text mode version
+# called "textconfig" and a graphical version called "wx".  The text
+# mode version uses stdin/stdout and is always compiled in.  The graphical
+# version is only available when you use "--with-wx" on the configure
+# command.  If you do not write a config_interface line, Bochs will
+# choose a default for you.
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#=======================================================================
+#config_interface: textconfig
+#config_interface: wx
+
+#=======================================================================
+# DISPLAY_LIBRARY
+#
+# The display library is the code that displays the Bochs VGA screen.  Bochs
+# has a selection of about 10 different display library implementations for
+# different platforms.  If you run configure with multiple --with-* options,
+# the display_library command lets you choose which one you want to run with.
+# If you do not write a display_library line, Bochs will choose a default for
+# you.
+#
+# The choices are:
+#   x              use X windows interface, cross platform
+#   win32          use native win32 libraries
+#   carbon         use Carbon library (for MacOS X)
+#   beos           use native BeOS libraries
+#   macintosh      use MacOS pre-10
+#   amigaos        use native AmigaOS libraries
+#   sdl            use SDL library, cross platform
+#   svga           use SVGALIB library for Linux, allows graphics without X11
+#   term           text only, uses curses/ncurses library, cross platform
+#   rfb            provides an interface to AT&T's VNC viewer, cross platform
+#   wx             use wxWidgets library, cross platform
+#   nogui          no display at all
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#
+# Specific options:
+# Some display libraries now support specific option to control their
+# behaviour. See the examples below for currently supported options.
+#=======================================================================
+#display_library: amigaos
+#display_library: beos
+#display_library: carbon
+#display_library: macintosh
+#display_library: nogui
+#display_library: rfb, options="timeout=60" # time to wait for client
+#display_library: sdl, options="fullscreen" # startup in fullscreen mode
+#display_library: term
+#display_library: win32, options="legacyF12" # use F12 to toggle mouse
+#display_library: wx
+#display_library: x
+
+#=======================================================================
+# ROMIMAGE:
+# The ROM BIOS controls what the PC does when it first powers on.
+# Normally, you can use a precompiled BIOS in the source or binary
+# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded
+# starting at address 0xf0000, and it is exactly 64k long.
+# You can also use the environment variable $BXSHARE to specify the
+# location of the BIOS.
+# The usage of external large BIOS images (up to 512k) at memory top is
+# now supported, but we still recommend to use the BIOS distributed with
+# Bochs. Now the start address can be calculated from image size.
+#=======================================================================
+romimage: file=bochs/bios/BIOS-bochs-latest, address=0xe0000
+#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
+#romimage: file=mybios.bin # calculate start address from image size
+
+#=======================================================================
+# CPU:
+# This defines cpu-related parameters inside Bochs:
+#
+#  COUNT:
+#  Set the number of processors:cores per processor:threads per core
+#  when Bochs is compiled for SMP emulation.
+#  Bochs currently supports up to 8 threads running simultaniosly.
+#  If Bochs is compiled without SMP support, it won't accept values
+#  different from 1.
+#
+#  RESET_ON_TRIPLE_FAULT:
+#  Reset the CPU when triple fault occur (highly recommended) rather than
+#  PANIC. Remember that if you trying to continue after triple fault the
+#  simulation will be completely bogus !
+#
+#  IPS:
+#  Emulated Instructions Per Second.  This is the number of IPS that bochs
+#  is capable of running on your machine. You can recompile Bochs with
+#  --enable-show-ips option enabled, to find your workstation's capability.
+#  Measured IPS value will then be logged into your log file or status bar
+#  (if supported by the gui).
+#
+#  IPS is used to calibrate many time-dependent events within the bochs
+#  simulation.  For example, changing IPS affects the frequency of VGA
+#  updates, the duration of time before a key starts to autorepeat, and
+#  the measurement of BogoMips and other benchmarks.
+#
+#  Examples:
+#  Machine                                         Mips
+# ________________________________________________________________
+#  2.1Ghz Athlon XP with Linux 2.6/g++ 3.4         12 to 15 Mips
+#  1.6Ghz Intel P4 with Win2000/g++ 3.3             5 to  7 Mips
+#  650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66  2 to  2.5 Mips
+#  400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3   1 to  1.8 Mips
+#=======================================================================
+cpu: count=1, ips=10000000, reset_on_triple_fault=1
+
+#=======================================================================
+# MEGS
+# Set the number of Megabytes of physical memory you want to emulate.
+# The default is 32MB, most OS's won't need more than that.
+# The maximum amount of memory supported is 2048Mb.
+#=======================================================================
+#megs: 256
+#megs: 128
+#megs: 64
+megs: 32
+#megs: 16
+#megs: 8
+
+#=======================================================================
+# OPTROMIMAGE[1-4]:
+# You may now load up to 4 optional ROM images. Be sure to use a
+# read-only area, typically between C8000 and EFFFF. These optional
+# ROM images should not overwrite the rombios (located at
+# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
+# Those ROM images will be initialized by the bios if they contain
+# the right signature (0x55AA) and a valid checksum.
+# It can also be a convenient way to upload some arbitrary code/data
+# in the simulation, that can be retrieved by the boot loader
+#=======================================================================
+#optromimage1: file=optionalrom.bin, address=0xd0000
+#optromimage2: file=optionalrom.bin, address=0xd1000
+#optromimage3: file=optionalrom.bin, address=0xd2000
+#optromimage4: file=optionalrom.bin, address=0xd3000
+optromimage1: file=../../src/bin/pnic.rom, address=0xd0000
+#optromimage1: file=../../src/bin/rtl8029.rom, address=0xd0000
+
+#optramimage1: file=/path/file1.img, address=0x0010000
+#optramimage2: file=/path/file2.img, address=0x0020000
+#optramimage3: file=/path/file3.img, address=0x0030000
+#optramimage4: file=/path/file4.img, address=0x0040000
+
+#=======================================================================
+# VGAROMIMAGE
+# You now need to load a VGA ROM BIOS into C0000.
+#=======================================================================
+#vgaromimage: file=bios/VGABIOS-elpin-2.40
+vgaromimage: file=bochs/bios/VGABIOS-lgpl-latest
+#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
+
+#=======================================================================
+# VGA:
+# Here you can specify the display extension to be used. With the value
+# 'none' you can use standard VGA with no extension. Other supported
+# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
+#=======================================================================
+#vga: extension=cirrus
+#vga: extension=vbe
+vga: extension=none
+
+#=======================================================================
+# FLOPPYA:
+# Point this to pathname of floppy image file or device
+# This should be of a bootable floppy(image/device) if you're
+# booting from 'a' (or 'floppy').
+#
+# You can set the initial status of the media to 'ejected' or 'inserted'.
+#   floppya: 2_88=path, status=ejected             (2.88M 3.5" floppy)
+#   floppya: 1_44=path, status=inserted            (1.44M 3.5" floppy)
+#   floppya: 1_2=path, status=ejected              (1.2M  5.25" floppy)
+#   floppya: 720k=path, status=inserted            (720K  3.5" floppy)
+#   floppya: 360k=path, status=inserted            (360K  5.25" floppy)
+#   floppya: 320k=path, status=inserted            (320K  5.25" floppy)
+#   floppya: 180k=path, status=inserted            (180K  5.25" floppy)
+#   floppya: 160k=path, status=inserted            (160K  5.25" floppy)
+#   floppya: image=path, status=inserted           (guess type from image size)
+#
+# The path should be the name of a disk image file.  On Unix, you can use a raw
+# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
+# such as a: or b: as the path.  The parameter 'image' works with image files
+# only. In that case the size must match one of the supported types.
+#=======================================================================
+#floppya: 1_44=/dev/fd0, status=inserted
+#floppya: image=../1.44, status=inserted
+#floppya: 1_44=/dev/fd0H1440, status=inserted
+#floppya: 1_2=../1_2, status=inserted
+#floppya: 1_44=a:, status=inserted
+#floppya: 1_44=a.img, status=inserted
+#floppya: 1_44=/dev/rfd0a, status=inserted
+floppya: 1_44=../../src/bin/pnic.dsk, status=inserted
+
+#=======================================================================
+# FLOPPYB:
+# See FLOPPYA above for syntax
+#=======================================================================
+#floppyb: 1_44=b:, status=inserted
+floppyb: 1_44=b.img, status=inserted
+
+#=======================================================================
+# ATA0, ATA1, ATA2, ATA3
+# ATA controller for hard disks and cdroms
+#
+# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
+#
+# These options enables up to 4 ata channels. For each channel
+# the two base io addresses and the irq must be specified.
+#
+# ata0 and ata1 are enabled by default with the values shown below
+#
+# Examples:
+#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
+#=======================================================================
+ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
+
+#=======================================================================
+# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
+#
+# This defines the type and characteristics of all attached ata devices:
+#   type=       type of attached device [disk|cdrom]
+#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
+#   mode=       only valid for disks [undoable|growing|volatile]
+#   path=       path of the image
+#   cylinders=  only valid for disks
+#   heads=      only valid for disks
+#   spt=        only valid for disks
+#   status=     only valid for cdroms [inserted|ejected]
+#   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
+#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
+#   model=      string returned by identify device command
+#   journal=    optional filename of the redolog for undoable and volatile disks
+#
+# Point this at a hard disk image file, cdrom iso file, or physical cdrom
+# device.  To create a hard disk image, try running bximage.  It will help you
+# choose the size and then suggest a line that works with it.
+#
+# In UNIX it may be possible to use a raw device as a Bochs hard disk,
+# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
+#
+# In windows, the drive letter + colon notation should be used for cdroms.
+# Depending on versions of windows and drivers, you may only be able to
+# access the "first" cdrom in the system.  On MacOSX, use path="drive"
+# to access the physical drive.
+#
+# The path is always mandatory. For flat hard disk images created with
+# bximage geometry autodetection can be used (cylinders=0 -> cylinders are
+# calculated using heads=16 and spt=63). For other hard disk images and modes
+# the cylinders, heads, and spt are mandatory.
+#
+# Default values are:
+#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
+#
+# The biosdetect option has currently no effect on the bios
+#
+# Examples:
+#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
+#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
+#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
+#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
+#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
+#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
+#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
+#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
+#=======================================================================
+#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
+#ata0-slave: type=cdrom, path=D:, status=inserted
+#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
+#ata0-slave: type=cdrom, path="drive", status=inserted
+#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted
+
+#=======================================================================
+# BOOT:
+# This defines the boot sequence. Now you can specify up to 3 boot drives.
+# You can either boot from 'floppy', 'disk' or 'cdrom'
+# legacy 'a' and 'c' are also supported
+# Examples:
+#   boot: floppy
+#   boot: disk
+#   boot: cdrom
+#   boot: c
+#   boot: a
+#   boot: cdrom, floppy, disk
+#=======================================================================
+#boot: floppy
+#boot: disk
+boot: network, floppy
+
+#=======================================================================
+# CLOCK:
+# This defines the parameters of the clock inside Bochs:
+#
+#  SYNC:
+#  TO BE COMPLETED (see Greg explanation in feature request #536329)
+#
+#  TIME0:
+#  Specifies the start (boot) time of the virtual machine. Use a time
+#  value as returned by the time(2) system call. If no time0 value is
+#  set or if time0 equal to 1 (special case) or if time0 equal 'local',
+#  the simulation will be started at the current local host time.
+#  If time0 equal to 2 (special case) or if time0 equal 'utc',
+#  the simulation will be started at the current utc time.
+#
+# Syntax:
+#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
+#
+# Example:
+#   clock: sync=none,     time0=local       # Now (localtime)
+#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
+#   clock: sync=none,     time0=631148400   # Mon Jan  1 00:00:00 1990
+#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
+#   clock: sync=realtime, time0=946681200   # Sat Jan  1 00:00:00 2000
+#   clock: sync=none,     time0=1           # Now (localtime)
+#   clock: sync=none,     time0=utc         # Now (utc/gmt)
+#
+# Default value are sync=none, time0=local
+#=======================================================================
+#clock: sync=none, time0=local
+
+
+#=======================================================================
+# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
+# Enables or disables the 0xaa55 signature check on boot floppies
+# Defaults to disabled=0
+# Examples:
+#   floppy_bootsig_check: disabled=0
+#   floppy_bootsig_check: disabled=1
+#=======================================================================
+#floppy_bootsig_check: disabled=1
+floppy_bootsig_check: disabled=0
+
+#=======================================================================
+# LOG:
+# Give the path of the log file you'd like Bochs debug and misc. verbiage
+# to be written to. If you don't use this option or set the filename to
+# '-' the output is written to the console. If you really don't want it,
+# make it "/dev/null" (Unix) or "nul" (win32). :^(
+#
+# Examples:
+#   log: ./bochs.out
+#   log: /dev/tty
+#=======================================================================
+#log: /dev/null
+log: bochsout.txt
+
+#=======================================================================
+# LOGPREFIX:
+# This handles the format of the string prepended to each log line.
+# You may use those special tokens :
+#   %t : 11 decimal digits timer tick
+#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
+#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
+#   %d : 5 characters string of the device, between brackets
+#
+# Default : %t%e%d
+# Examples:
+#   logprefix: %t-%e-@%i-%d
+#   logprefix: %i%e%d
+#=======================================================================
+#logprefix: %t%e%d
+
+#=======================================================================
+# LOG CONTROLS
+#
+# Bochs now has four severity levels for event logging.
+#   panic: cannot proceed.  If you choose to continue after a panic,
+#          don't be surprised if you get strange behavior or crashes.
+#   error: something went wrong, but it is probably safe to continue the
+#          simulation.
+#   info: interesting or useful messages.
+#   debug: messages useful only when debugging the code.  This may
+#          spit out thousands per second.
+#
+# For events of each level, you can choose to crash, report, or ignore.
+# TODO: allow choice based on the facility: e.g. crash on panics from
+#       everything except the cdrom, and only report those.
+#
+# If you are experiencing many panics, it can be helpful to change
+# the panic action to report instead of fatal.  However, be aware
+# that anything executed after a panic is uncharted territory and can
+# cause bochs to become unstable.  The panic is a "graceful exit," so
+# if you disable it you may get a spectacular disaster instead.
+#=======================================================================
+panic: action=ask
+error: action=report
+info: action=report
+debug: action=ignore
+#pass: action=fatal
+
+#=======================================================================
+# DEBUGGER_LOG:
+# Give the path of the log file you'd like Bochs to log debugger output.
+# If you really don't want it, make it /dev/null or '-'. :^(
+#
+# Examples:
+#   debugger_log: ./debugger.out
+#=======================================================================
+#debugger_log: /dev/null
+#debugger_log: debugger.out
+debugger_log: -
+
+#=======================================================================
+# COM1, COM2, COM3, COM4:
+# This defines a serial port (UART type 16550A). In the 'term' you can specify
+# a device to use as com1. This can be a real serial line, or a pty.  To use
+# a pty (under X/Unix), create two windows (xterms, usually).  One of them will
+# run bochs, and the other will act as com1. Find out the tty the com1
+# window using the `tty' command, and use that as the `dev' parameter.
+# Then do `sleep 1000000' in the com1 window to keep the shell from
+# messing with things, and run bochs in the other window.  Serial I/O to
+# com1 (port 0x3f8) will all go to the other window.
+# Other serial modes are 'null' (no input/output), 'file' (output to a file
+# specified as the 'dev' parameter), 'raw' (use the real serial port - under
+# construction for win32), 'mouse' (standard serial mouse - requires
+# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket'
+# (connect a networking socket).
+#
+# Examples:
+#   com1: enabled=1, mode=null
+#   com1: enabled=1, mode=mouse
+#   com2: enabled=1, mode=file, dev=serial.out
+#   com3: enabled=1, mode=raw, dev=com1
+#   com3: enabled=1, mode=socket, dev=localhost:8888
+#=======================================================================
+#com1: enabled=1, mode=term, dev=/dev/ttyp9
+
+
+#=======================================================================
+# PARPORT1, PARPORT2:
+# This defines a parallel (printer) port. When turned on and an output file is
+# defined the emulated printer port sends characters printed by the guest OS
+# into the output file. On some platforms a device filename can be used to
+# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
+# win32 platforms).
+#
+# Examples:
+#   parport1: enabled=1, file="parport.out"
+#   parport2: enabled=1, file="/dev/lp0"
+#   parport1: enabled=0
+#=======================================================================
+parport1: enabled=1, file="parport.out"
+
+#=======================================================================
+# SB16:
+# This defines the SB16 sound emulation. It can have several of the
+# following properties.
+# All properties are in the format sb16: property=value
+# midi: The filename is where the midi data is sent. This can be a
+#       device or just a file if you want to record the midi data.
+# midimode:
+#      0=no data
+#      1=output to device (system dependent. midi denotes the device driver)
+#      2=SMF file output, including headers
+#      3=output the midi data stream to the file (no midi headers and no
+#        delta times, just command and data bytes)
+# wave: This is the device/file where wave output is stored
+# wavemode:
+#      0=no data
+#      1=output to device (system dependent. wave denotes the device driver)
+#      2=VOC file output, incl. headers
+#      3=output the raw wave stream to the file
+# log:  The file to write the sb16 emulator messages to.
+# loglevel:
+#      0=no log
+#      1=resource changes, midi program and bank changes
+#      2=severe errors
+#      3=all errors
+#      4=all errors plus all port accesses
+#      5=all errors and port accesses plus a lot of extra info
+# dmatimer:
+#      microseconds per second for a DMA cycle.  Make it smaller to fix
+#      non-continuous sound.  750000 is usually a good value.  This needs a
+#      reasonably correct setting for the IPS parameter of the CPU option.
+#
+# For an example look at the next line:
+#=======================================================================
+
+#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
+
+#=======================================================================
+# VGA_UPDATE_INTERVAL:
+# Video memory is scanned for updates and screen updated every so many
+# virtual seconds.  The default is 40000, about 25Hz. Keep in mind that
+# you must tweak the 'cpu: ips=N' directive to be as close to the number
+# of emulated instructions-per-second your workstation can do, for this
+# to be accurate.
+#
+# Examples:
+#   vga_update_interval: 250000
+#=======================================================================
+vga_update_interval: 300000
+
+# using for Winstone '98 tests
+#vga_update_interval:  100000
+
+#=======================================================================
+# KEYBOARD_SERIAL_DELAY:
+# Approximate time in microseconds that it takes one character to
+# be transfered from the keyboard to controller over the serial path.
+# Examples:
+#   keyboard_serial_delay: 200
+#=======================================================================
+keyboard_serial_delay: 250
+
+#=======================================================================
+# KEYBOARD_PASTE_DELAY:
+# Approximate time in microseconds between attempts to paste
+# characters to the keyboard controller. This leaves time for the
+# guest os to deal with the flow of characters.  The ideal setting
+# depends on how your operating system processes characters.  The
+# default of 100000 usec (.1 seconds) was chosen because it works
+# consistently in Windows.
+#
+# If your OS is losing characters during a paste, increase the paste
+# delay until it stops losing characters.
+#
+# Examples:
+#   keyboard_paste_delay: 100000
+#=======================================================================
+keyboard_paste_delay: 100000
+
+#=======================================================================
+# MOUSE:
+# This option prevents Bochs from creating mouse "events" unless a mouse
+# is  enabled. The hardware emulation itself is not disabled by this.
+# You can turn the mouse on by setting enabled to 1, or turn it off by
+# setting enabled to 0. Unless you have a particular reason for enabling
+# the mouse by default, it is recommended that you leave it off.
+# You can also toggle the mouse usage at runtime (control key + middle
+# mouse button on X11, SDL, wxWidgets and Win32).
+# With the mouse type option you can select the type of mouse to emulate.
+# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
+# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
+# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
+# connected with the 'mouse' device - requires PCI and USB support).
+#
+# Examples:
+#   mouse: enabled=1
+#   mouse: enabled=1, type=imps2
+#   mouse: enabled=1, type=serial
+#   mouse: enabled=0
+#=======================================================================
+mouse: enabled=0
+
+#=======================================================================
+# private_colormap: Request that the GUI create and use it's own
+#                   non-shared colormap.  This colormap will be used
+#                   when in the bochs window.  If not enabled, a
+#                   shared colormap scheme may be used.  Not implemented
+#                   on all GUI's.
+#
+# Examples:
+#   private_colormap: enabled=1
+#   private_colormap: enabled=0
+#=======================================================================
+private_colormap: enabled=0
+
+#=======================================================================
+# fullscreen: ONLY IMPLEMENTED ON AMIGA
+#             Request that Bochs occupy the entire screen instead of a
+#             window.
+#
+# Examples:
+#   fullscreen: enabled=0
+#   fullscreen: enabled=1
+#=======================================================================
+#fullscreen: enabled=0
+#screenmode: name="sample"
+
+#=======================================================================
+# ne2k: NE2000 compatible ethernet adapter
+#
+# Examples:
+# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+#
+# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
+# are IRQ conflicts.
+#
+# mac: The MAC address MUST NOT match the address of any machine on the net.
+# Also, the first byte must be an even number (bit 0 set means a multicast
+# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
+# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
+# be other restrictions too.  To be safe, just use the b0:c4... address.
+#
+# ethdev: The ethdev value is the name of the network interface on your host
+# platform.  On UNIX machines, you can get the name by running ifconfig.  On
+# Windows machines, you must run niclist to get the name of the ethdev.
+# Niclist source code is in misc/niclist.c and it is included in Windows
+# binary releases.
+#
+# script: The script value is optional, and is the name of a script that
+# is executed after bochs initialize the network interface. You can use
+# this script to configure this network interface, or enable masquerading.
+# This is mainly useful for the tun/tap devices that only exist during
+# Bochs execution. The network interface name is supplied to the script
+# as first parameter
+#
+# If you don't want to make connections to any physical networks,
+# you can use the following 'ethmod's to simulate a virtual network.
+#   null: All packets are discarded, but logged to a few files.
+#   arpback: ARP is simulated. Disabled by default.
+#   vde:  Virtual Distributed Ethernet
+#   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
+#         The virtual host uses 192.168.10.1.
+#         DHCP assigns 192.168.10.2 to the guest.
+#         TFTP uses the ethdev value for the root directory and doesn't
+#         overwrite files.
+#
+#=======================================================================
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
+pnic: mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
+#ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
+
+#=======================================================================
+# KEYBOARD_MAPPING:
+# This enables a remap of a physical localized keyboard to a
+# virtualized us keyboard, as the PC architecture expects.
+# If enabled, the keymap file must be specified.
+#
+# Examples:
+#   keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map
+#=======================================================================
+keyboard_mapping: enabled=0, map=
+
+#=======================================================================
+# KEYBOARD_TYPE:
+# Type of keyboard return by a "identify keyboard" command to the
+# keyboard controler. It must be one of "xt", "at" or "mf".
+# Defaults to "mf". It should be ok for almost everybody. A known
+# exception is french macs, that do have a "at"-like keyboard.
+#
+# Examples:
+#   keyboard_type: mf
+#=======================================================================
+#keyboard_type: mf
+
+#=======================================================================
+# USER_SHORTCUT:
+# This defines the keyboard shortcut to be sent when you press the "user"
+# button in the headerbar. The shortcut string is a combination of maximum
+# 3 key names (listed below) separated with a '-' character. The old-style
+# syntax (without the '-') still works for the key combinations supported
+# in Bochs 2.2.1.
+# Valid key names:
+# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
+# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
+# "plus", "right", "shift", "space", "tab", "up", and "win".
+#
+# Example:
+#   user_shortcut: keys=ctrl-alt-del
+#=======================================================================
+user_shortcut: keys=ctrl-alt-del
+
+#=======================================================================
+# I440FXSUPPORT:
+# This option controls the presence of the i440FX PCI chipset. You can
+# also specify the devices connected to PCI slots. Up to 5 slots are
+# available now. These devices are currently supported: ne2k, pcivga,
+# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support
+# you'll have the additional choice 'cirrus'.
+#
+# Example:
+#   i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k
+#=======================================================================
+i440fxsupport: enabled=1, slot1=pcipnic
+#i440fxsupport: enabled=1, slot1=ne2k
+
+#=======================================================================
+# USB1:
+# This option controls the presence of the USB root hub which is a part
+# of the i440FX PCI chipset. With the portX option you can connect devices
+# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
+# the mouse to one of the ports and use the mouse option 'type=usb' you'll
+# have a 3-button USB mouse.
+#
+# Example:
+#   usb1: enabled=1, port1=mouse, port2=keypad
+#=======================================================================
+#usb1: enabled=1
+
+#=======================================================================
+# CMOSIMAGE:
+# This defines image file that can be loaded into the CMOS RAM at startup.
+# The rtc_init parameter controls whether initialize the RTC with values stored
+# in the image. By default the time0 argument given to the clock option is used.
+# With 'rtc_init=image' the image is the source for the initial time.
+#
+# Example:
+#   cmosimage: file=cmos.img, rtc_init=image
+#=======================================================================
+#cmosimage: file=cmos.img, rtc_init=time0
+
+#=======================================================================
+# other stuff
+#=======================================================================
+magic_break: enabled=1
+#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
+#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
+#text_snapshot_check: enable
+
+#-------------------------
+# PCI host device mapping
+#-------------------------
+#pcidev: vendor=0x1234, device=0x5678
+
+#=======================================================================
+# GDBSTUB:
+# Enable GDB stub. See user documentation for details.
+# Default value is enabled=0.
+#=======================================================================
+#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
+
+#=======================================================================
+# IPS:
+# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU
+# directive instead.
+#=======================================================================
+#ips: 10000000
+
+#=======================================================================
+# for Macintosh, use the style of pathnames in the following
+# examples.
+#
+# vgaromimage: :bios:VGABIOS-elpin-2.40
+# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
+# floppya: 1_44=[fd:], status=inserted
+#=======================================================================
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/cow b/qemu-0.15.x/roms/ipxe/contrib/vm/cow
new file mode 100755
index 0000000..054ffdd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/cow
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+set -e
+
+imgloop=
+tmpfile=
+tmploop=
+dmname=
+cowlink=
+
+function cleanup () {
+    set +e
+    [ -n "$cowlink" ] && rm $cowlink
+    [ -n "$dmname" ] && dmsetup remove $dmname
+    [ -n "$tmploop" ] && losetup -d $tmploop
+    [ -n "$tmpfile" ] && rm $tmpfile
+    [ -n "$imgloop" ] && losetup -d $imgloop
+}
+
+trap cleanup EXIT
+
+imgfile=$1 ; shift
+command=$1 ; shift
+if [ -z "$imgfile" -o -z "$command" ] ; then
+    echo Syntax: $0 /path/to/image/file command [args..]
+    exit 1
+fi
+
+# Set up image loop device
+x=`losetup -f` ; losetup -r $x $imgfile ; imgloop=$x
+
+# Create temporary file and set up temporary loop device
+tmpfile=`mktemp $imgfile.XXXXXXXXXX`
+truncate -r $imgfile $tmpfile
+x=`losetup -f` ; losetup $x $tmpfile ; tmploop=$x
+
+# Create snapshot device
+imgsize=`blockdev --getsz $imgloop`
+x=`basename $imgfile` ; echo 0 $imgsize snapshot $imgloop $tmploop N 16 | \
+    dmsetup create $x ; dmname=$x
+chown --reference=$imgfile /dev/mapper/$dmname
+chmod --reference=$imgfile /dev/mapper/$dmname
+
+# Create symlink
+x=$imgfile.cow ; ln -s /dev/mapper/$dmname $x ; cowlink=$x
+
+# Wait until killed
+echo "Created $cowlink"
+$command "$@" $cowlink
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console b/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console
new file mode 100755
index 0000000..5d09876
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console
@@ -0,0 +1,278 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+serial-console
+
+=head1 SYNOPSIS
+
+serial-console [options]
+
+Options:
+
+    -h,--help         Display brief help message
+    -v,--verbose      Increase verbosity
+    -q,--quiet        Decrease verbosity
+    -l,--log FILE     Log output to file
+    -r,--rcfile	FILE  Modify specified bochsrc file
+
+=head1 DESCRIPTION
+
+C<serial-console> provides a virtual serial console for use with
+Bochs.  Running C<serial-console> creates a pseudo-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(C<bochsrc.txt>) for use by a subsequent Bochs session.
+
+=head1 EXAMPLES
+
+=over 4
+
+=item C<serial-console>
+
+Create a virtual serial console for Bochs, modify C<bochsrc.txt>
+appropriately.
+
+=item C<serial-console -r ../.bochsrc -l serial.log>
+
+Create a virtual serial console for Bochs, modify C<../.bochsrc>
+appropriately, log output to C<serial.log>.
+
+=back
+
+=head1 INVOCATION
+
+Before starting Bochs, run C<serial-console> in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running C<serial-console>, and anything typed in
+the C<serial-console> window will arrive on the emulated machine's
+serial port.
+
+You do B<not> need to rerun C<serial-console> afresh for each Bochs
+session.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-l,--log FILE>
+
+Log all output (i.e. everything that is printed in the
+C<serial-console> window) to the specified file.
+
+=item B<-r,--rcfile FILE>
+
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when C<serial-console> exits.  The
+default is to modify the file C<bochsrc.txt> in the current directory.
+
+To avoid modifying any bochsrc file, use C<--norcfile>.
+
+=back
+
+=cut
+
+use IO::Pty;
+use IO::Select;
+use File::Spec::Functions qw ( :ALL );
+use Getopt::Long;
+use Pod::Usage;
+use POSIX qw ( :termios_h );
+use strict;
+use warnings;
+
+my $o;
+my $restore_file = {};
+my $restore_termios;
+use constant BLOCKSIZE => 8192;
+
+##############################################################################
+#
+# Parse command line options into options hash ($o)
+#
+# $o = parse_opts();
+
+sub parse_opts {
+  # $o is the hash that will hold the options
+  my $o = {
+    verbosity => 1,
+    rcfile => 'bochsrc.txt',
+  };
+  # Special handlers for some options
+  my $opt_handlers = {
+    verbose => sub { $o->{verbosity}++; },
+    quiet => sub { $o->{verbosity}--; },
+    help => sub { pod2usage(1); },
+    norcfile => sub { delete $o->{rcfile}; },
+  };
+  # Merge handlers into main options hash (so that Getopt::Long can find them)
+  $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
+  # Option specifiers for Getopt::Long
+  my @optspec = ( 'help|h|?',
+                  'quiet|q+',
+                  'verbose|v+',
+		  'log|l=s',
+		  'rcfile|r=s',
+		  'norcfile',
+                  );
+  # Do option parsing
+  Getopt::Long::Configure ( 'bundling' );
+  pod2usage("Error parsing command-line options") unless GetOptions (
+  $o, @optspec );
+  # Clean up $o by removing the handlers
+  delete $o->{$_} foreach keys %$opt_handlers;
+  return $o;
+}
+
+##############################################################################
+#
+# Modify bochsrc file
+
+sub patch_bochsrc {
+  my $active = shift;
+  my $pty = shift;
+
+  # Rename active file to backup file
+  ( my $vol, my $dir, my $file ) = splitpath ( $active );
+  $file = '.'.$file.".serial-console";
+  my $backup = catpath ( $vol, $dir, $file );
+  rename $active, $backup
+      or die "Could not back up $active to $backup: $!\n";
+
+  # Derive line to be inserted
+  my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
+
+  # Modify file
+  open my $old, "<$backup" or die "Could not open $backup: $!\n";
+  open my $new, ">$active" or die "Could not open $active: $!\n";
+  print $new <<"EOF";
+##################################################
+#
+# This file has been modified by serial-console.
+#
+# Do not modify this file; it will be erased when
+# serial-console (pid $$) exits and will be
+# replaced with the backup copy held in
+# $backup.
+#
+##################################################
+
+
+EOF
+  my $patched;
+  while ( my $line = <$old> ) {
+    if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
+      if ( ! $patched ) {
+	$line = $patch;
+	$patched = 1;
+      } else {
+	$line = '# '.$line unless $line =~ /^\s*\#/;
+      }
+    }
+    print $new $line;
+  }
+  print $new $patch unless $patched;
+  close $old;
+  close $new;
+
+  return $backup;
+}
+
+##############################################################################
+#
+# Attach/detach message printing and terminal settings
+
+sub bochs_attached {
+  print STDERR "Bochs attached.\n\n\n"
+      if $o->{verbosity} >= 1;
+}
+
+sub bochs_detached {
+  print STDERR "\n\nWaiting for bochs to attach...\n"
+      if $o->{verbosity} >= 1;
+}
+
+##############################################################################
+#
+# Main program
+
+$o = parse_opts();
+pod2usage(1) if @ARGV;
+
+# Catch signals
+my $sigdie = sub { die "Exiting via signal\n"; };
+$SIG{INT} = $sigdie;
+
+# Create Pty, close slave side
+my $pty = IO::Pty->new();
+$pty->close_slave();
+$pty->set_raw();
+print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
+
+# Open logfile
+my $log;
+if ( $o->{log} ) {
+  open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
+}
+
+# Set up terminal
+my $termios;
+if ( -t STDIN ) {
+  $termios = POSIX::Termios->new;
+  $restore_termios = POSIX::Termios->new;
+  $termios->getattr ( fileno(STDIN) );
+  $restore_termios->getattr ( fileno(STDIN) );
+  $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
+  $termios->setiflag ( $termios->getiflag & ~(ICRNL) );
+  $termios->setattr ( fileno(STDIN), TCSANOW );
+}
+
+# Modify bochsrc file
+$restore_file = { $o->{rcfile} =>
+		  patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
+    if $o->{rcfile};
+
+# Start character shunt
+my $attached = 1;
+my $select = IO::Select->new ( \*STDIN, $pty );
+while ( 1 ) {
+  my %can_read = map { $_ => 1 }
+		     $select->can_read ( $attached ? undef : 1 );
+  if ( $can_read{\*STDIN} ) {
+    sysread ( STDIN, my $data, BLOCKSIZE )
+	or die "Cannot read from STDIN: $!\n";
+    $pty->syswrite ( $data );
+  }
+  if ( $can_read{$pty} ) {
+    if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
+      # Actual data available
+      bochs_attached() if $attached == 0;
+      $attached = 1;
+      syswrite ( STDOUT, $data );
+      $log->syswrite ( $data ) if $log;
+    } else {
+      # No data available but select() says we can read.  This almost
+      # certainly indicates that nothing is attached to the slave.
+      bochs_detached() if $attached == 1;
+      $attached = 0;
+      sleep ( 1 );
+    }
+  } else {
+    bochs_attached() if $attached == 0;
+    $attached = 1;
+  }
+}
+
+END {
+  # Restore bochsrc file if applicable
+  if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
+    unlink $orig_file;
+    rename $backup_file, $orig_file;
+  }
+  # Restore terminal settings if applicable
+  if ( $restore_termios ) {
+    $restore_termios->setattr ( fileno(STDIN), TCSANOW );
+  }
+}
diff --git a/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console.1 b/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console.1
new file mode 100644
index 0000000..6d19a7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/contrib/vm/serial-console.1
@@ -0,0 +1,190 @@
+.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.el \{\
+.    de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "SERIAL-CONSOLE 1"
+.TH SERIAL-CONSOLE 1 "2010-09-22" "perl v5.10.1" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+serial\-console
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+serial-console [options]
+.PP
+Options:
+.PP
+.Vb 5
+\&    \-h,\-\-help         Display brief help message
+\&    \-v,\-\-verbose      Increase verbosity
+\&    \-q,\-\-quiet        Decrease verbosity
+\&    \-l,\-\-log FILE     Log output to file
+\&    \-r,\-\-rcfile FILE  Modify specified bochsrc file
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with
+Bochs.  Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.ie n .IP """serial\-console""" 4
+.el .IP "\f(CWserial\-console\fR" 4
+.IX Item "serial-console"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR
+appropriately.
+.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4
+.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4
+.IX Item "serial-console -r ../.bochsrc -l serial.log"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR
+appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR.
+.SH "INVOCATION"
+.IX Header "INVOCATION"
+Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in
+the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's
+serial port.
+.PP
+You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs
+session.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4
+.IX Item "-l,--log FILE"
+Log all output (i.e. everything that is printed in the
+\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file.
+.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4
+.IX Item "-r,--rcfile FILE"
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits.  The
+default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory.
+.Sp
+To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR.
diff --git a/qemu-0.15.x/roms/ipxe/src/.gitignore b/qemu-0.15.x/roms/ipxe/src/.gitignore
new file mode 100644
index 0000000..cc8e33e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/.gitignore
@@ -0,0 +1,4 @@
+.toolcheck
+.echocheck
+TAGS*
+bin*
diff --git a/qemu-0.15.x/roms/ipxe/src/Makefile b/qemu-0.15.x/roms/ipxe/src/Makefile
new file mode 100644
index 0000000..8cc976b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/Makefile
@@ -0,0 +1,177 @@
+###############################################################################
+#
+# Initialise various variables
+#
+
+CLEANUP		:=
+CFLAGS		:=
+ASFLAGS		:=
+LDFLAGS		:=
+MAKEDEPS	:= Makefile
+
+###############################################################################
+#
+# Locations of tools
+#
+HOST_CC		:= gcc
+RM		:= rm -f
+TOUCH		:= touch
+MKDIR		:= mkdir
+CP		:= cp
+ECHO		:= echo
+PRINTF		:= printf
+PERL		:= perl
+TRUE		:= true
+CC		:= $(CROSS_COMPILE)gcc
+CPP		:= $(CC) -E
+AS		:= $(CROSS_COMPILE)as
+LD		:= $(CROSS_COMPILE)ld
+SIZE		:= $(CROSS_COMPILE)size
+AR		:= $(CROSS_COMPILE)ar
+RANLIB		:= $(CROSS_COMPILE)ranlib
+OBJCOPY		:= $(CROSS_COMPILE)objcopy
+NM		:= $(CROSS_COMPILE)nm
+OBJDUMP		:= $(CROSS_COMPILE)objdump
+PARSEROM	:= ./util/parserom.pl
+FIXROM		:= ./util/fixrom.pl
+SYMCHECK	:= ./util/symcheck.pl
+SORTOBJDUMP	:= ./util/sortobjdump.pl
+PADIMG		:= ./util/padimg.pl
+LICENCE		:= ./util/licence.pl
+NRV2B		:= ./util/nrv2b
+ZBIN		:= ./util/zbin
+ELF2EFI32	:= ./util/elf2efi32
+ELF2EFI64	:= ./util/elf2efi64
+EFIROM		:= ./util/efirom
+ICCFIX		:= ./util/iccfix
+EINFO		:= ./util/einfo
+GENKEYMAP	:= ./util/genkeymap.pl
+DOXYGEN		:= doxygen
+BINUTILS_DIR	:= /usr
+BFD_DIR		:= $(BINUTILS_DIR)
+ZLIB_DIR	:= /usr
+
+###############################################################################
+#
+# SRCDIRS lists all directories containing source files.
+#
+SRCDIRS		:=
+SRCDIRS		+= libgcc
+SRCDIRS		+= core
+SRCDIRS		+= net net/tcp net/udp net/infiniband net/80211
+SRCDIRS		+= image
+SRCDIRS		+= drivers/bus
+SRCDIRS		+= drivers/net
+SRCDIRS		+= drivers/net/e1000
+SRCDIRS		+= drivers/net/e1000e
+SRCDIRS		+= drivers/net/igb
+SRCDIRS		+= drivers/net/igbvf
+SRCDIRS		+= drivers/net/phantom
+SRCDIRS		+= drivers/net/rtl818x
+SRCDIRS		+= drivers/net/ath5k
+SRCDIRS		+= drivers/net/vxge
+SRCDIRS		+= drivers/net/efi
+SRCDIRS		+= drivers/block
+SRCDIRS		+= drivers/nvs
+SRCDIRS		+= drivers/bitbash
+SRCDIRS		+= drivers/infiniband
+SRCDIRS		+= interface/pxe interface/efi interface/smbios
+SRCDIRS		+= interface/bofm
+SRCDIRS		+= tests
+SRCDIRS		+= crypto crypto/axtls crypto/matrixssl
+SRCDIRS		+= hci hci/commands hci/tui
+SRCDIRS		+= hci/mucurses hci/mucurses/widgets
+SRCDIRS		+= hci/keymap
+SRCDIRS		+= usr
+SRCDIRS		+= config
+
+# NON_AUTO_SRCS lists files that are excluded from the normal
+# automatic build system.
+#
+NON_AUTO_SRCS	:=
+NON_AUTO_SRCS	+= drivers/net/prism2.c
+
+# INCDIRS lists the include path
+#
+INCDIRS		:=
+INCDIRS		+= include .
+
+###############################################################################
+#
+# Default build target: build the most common targets and print out a
+# helpfully suggestive message
+#
+ALL		:= bin/blib.a bin/ipxe.dsk bin/ipxe.lkrn bin/ipxe.iso \
+		   bin/ipxe.usb bin/undionly.kpxe bin/rtl8139.rom
+all : $(ALL)
+	@$(ECHO) '==========================================================='
+	@$(ECHO)
+	@$(ECHO) 'To create a bootable floppy, type'
+	@$(ECHO) '    cat bin/ipxe.dsk > /dev/fd0'
+	@$(ECHO) 'where /dev/fd0 is your floppy drive.  This will erase any'
+	@$(ECHO) 'data already on the disk.'
+	@$(ECHO)
+	@$(ECHO) 'To create a bootable USB key, type'
+	@$(ECHO) '    cat bin/ipxe.usb > /dev/sdX'
+	@$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
+	@$(ECHO) 'disk on your system.  This will erase any data already on'
+	@$(ECHO) 'the USB key.'
+	@$(ECHO)
+	@$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
+	@$(ECHO) 'bin/ipxe.iso to a blank CD-ROM.'
+	@$(ECHO)
+	@$(ECHO) 'These images contain drivers for all supported cards.  You'
+	@$(ECHO) 'can build more customised images, and ROM images, using'
+	@$(ECHO) '    make bin/<rom-name>.<output-format>'
+	@$(ECHO)
+	@$(ECHO) '==========================================================='
+
+###############################################################################
+#
+# Comprehensive build target: build a selection of cross-platform
+# targets to expose potential build errors that show up only on
+# certain platforms
+#
+everything :
+	$(Q)$(MAKE) --no-print-directory $(ALL) \
+		bin-i386-efi/ipxe.efi bin-i386-efi/ipxe.efidrv \
+		bin-i386-efi/ipxe.efirom \
+		bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \
+		bin-x86_64-efi/ipxe.efirom \
+		bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux
+
+###############################################################################
+#
+# Build targets that do nothing but might be tried by users
+#
+configure :
+	@$(ECHO) "No configuration needed."
+
+install :
+	@$(ECHO) "No installation required."
+
+###############################################################################
+#
+# Version number calculations
+#
+VERSION_MAJOR	= 1
+VERSION_MINOR	= 0
+VERSION_PATCH	= 0
+EXTRAVERSION	= +
+MM_VERSION	= $(VERSION_MAJOR).$(VERSION_MINOR)
+VERSION		= $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
+CFLAGS		+= -DVERSION_MAJOR=$(VERSION_MAJOR) \
+		   -DVERSION_MINOR=$(VERSION_MINOR) \
+		   -DVERSION_PATCH=$(VERSION_PATCH) \
+		   -DVERSION=\"$(VERSION)\"
+IDENT		= '$(@F) $(VERSION) (GPL) ipxe.org'
+version :
+	@$(ECHO) $(VERSION)
+
+###############################################################################
+#
+# Drag in the bulk of the build system
+#
+
+MAKEDEPS	+= Makefile.housekeeping
+include Makefile.housekeeping
diff --git a/qemu-0.15.x/roms/ipxe/src/Makefile.housekeeping b/qemu-0.15.x/roms/ipxe/src/Makefile.housekeeping
new file mode 100644
index 0000000..ba01f16
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/Makefile.housekeeping
@@ -0,0 +1,1145 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+#
+# This file contains various boring housekeeping functions that would
+# otherwise seriously clutter up the main Makefile.
+
+###############################################################################
+#
+# Find a usable "echo -e" substitute.
+#
+TAB 			:= $(shell $(PRINTF) '\t')
+ECHO_E_ECHO		:= $(ECHO)
+ECHO_E_ECHO_E		:= $(ECHO) -e
+ECHO_E_BIN_ECHO 	:= /bin/echo
+ECHO_E_BIN_ECHO_E 	:= /bin/echo -e
+ECHO_E_ECHO_TAB		:= $(shell $(ECHO_E_ECHO) '\t' | cat)
+ECHO_E_ECHO_E_TAB	:= $(shell $(ECHO_E_ECHO_E) '\t' | cat)
+ECHO_E_BIN_ECHO_TAB 	:= $(shell $(ECHO_E_BIN_ECHO) '\t')
+ECHO_E_BIN_ECHO_E_TAB 	:= $(shell $(ECHO_E_BIN_ECHO_E) '\t')
+
+ifeq ($(ECHO_E_ECHO_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_ECHO)
+endif
+ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_ECHO_E)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_BIN_ECHO)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_BIN_ECHO_E)
+endif
+
+.echocheck :
+ifdef ECHO_E
+	@$(TOUCH) $@
+else
+	@$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \
+				    '$(ECHO_E_ECHO_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \
+				    '$(ECHO_E_ECHO_E_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \
+				    '$(ECHO_E_BIN_ECHO_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \
+				    '$(ECHO_E_BIN_ECHO_E_TAB)'
+	@$(ECHO) "No usable \"echo -e\" substitute found"
+	@exit 1
+endif
+MAKEDEPS	+= .echocheck
+VERYCLEANUP	+= .echocheck
+
+echo :
+	@$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
+
+###############################################################################
+#
+# Generate a usable "seq" substitute
+#
+define seq
+	$(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }')
+endef
+
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS		:= $(shell uname -s)
+hostos :
+	@$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Determine compiler
+
+CCDEFS		:= $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2)
+ccdefs:
+	@$(ECHO) $(CCDEFS)
+
+ifeq ($(filter __ICC,$(CCDEFS)),__ICC)
+CCTYPE		:= icc
+else
+CCTYPE		:= gcc
+endif
+cctype:
+	@$(ECHO) $(CCTYPE)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+
+ifeq ($(CCTYPE),gcc)
+GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96')
+ifneq ($(GCC_2_96_BANNER),)
+$(warning gcc 2.96 is unsuitable for compiling iPXE)
+$(warning Use gcc 2.95 or a newer version instead)
+$(error Unsuitable build environment found)
+endif
+endif
+
+PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c)
+ifeq ($(PERL_UNICODE_CHECK),2)
+$(warning Your Perl version has a Unicode handling bug)
+$(warning Execute this command before building iPXE:)
+$(warning export LANG=$${LANG%.UTF-8})
+$(error Unsuitable build environment found)
+endif
+
+LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold')
+ifneq ($(LD_GOLD_BANNER),)
+$(warning GNU gold is unsuitable for building iPXE)
+$(warning Use GNU ld instead)
+$(error Unsuitable build environment found)
+endif
+
+###############################################################################
+#
+# Check for various tool workarounds
+#
+
+WORKAROUND_CFLAGS :=
+WORKAROUND_ASFLAGS :=
+WORKAROUND_LDFLAGS :=
+
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA	:= ,
+EMPTY	:=
+SPACE	:= $(EMPTY) $(EMPTY)
+
+# Check for an old version of gas (binutils 2.9.1)
+#
+OLDGAS	:= $(shell $(AS) --version | grep -q '2\.9\.1' && $(ECHO) -DGAS291)
+WORKAROUND_CFLAGS += $(OLDGAS)
+oldgas :
+	@$(ECHO) $(oldgas)
+
+# Some widespread patched versions of gcc include -fstack-protector by
+# default, even when -ffreestanding is specified.  We therefore need
+# to disable -fstack-protector if the compiler supports it.
+#
+ifeq ($(CCTYPE),gcc)
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+		-o /dev/null >/dev/null 2>&1
+SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
+WORKAROUND_CFLAGS += $(SP_FLAGS)
+endif
+
+# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
+# default.  Note that gcc will exit *successfully* if it fails to
+# recognise an option that starts with "no", so we have to test for
+# output on stderr instead of checking the exit status.
+#
+ifeq ($(CCTYPE),gcc)
+PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
+PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
+WORKAROUND_CFLAGS += $(PIE_FLAGS)
+endif
+
+# gcc 4.4 generates .eh_frame sections by default, which distort the
+# output of "size".  Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -x c -c /dev/null \
+		 -o /dev/null >/dev/null 2>&1
+CFI_FLAGS := $(shell $(CFI_TEST) && $(ECHO) '-fno-dwarf2-cfi-asm')
+WORKAROUND_CFLAGS += $(CFI_FLAGS)
+endif
+
+# gcc 4.6 generates spurious warnings if -Waddress is in force.
+# Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1
+WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address')
+WORKAROUND_CFLAGS += $(WNA_FLAGS)
+endif
+
+# Some versions of gas choke on division operators, treating them as
+# comment markers.  Specifying --divide will work around this problem,
+# but isn't available on older gas versions.
+#
+DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null
+DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide')
+WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS)
+
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS	:= $(filter bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOALS_BINS	:= $(sort $(foreach BG,$(BIN_GOALS),\
+				    $(firstword $(subst /, ,$(BG)))))
+NUM_BINS	:= $(words $(BIN_GOALS_BINS))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified.  Set BIN to "bin" as a sensible
+# default.
+
+BIN		:= bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN		:= $(firstword $(BIN_GOALS_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified.  We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.  Use exactly one target for each BIN
+# directory since running multiple make invocations within the same
+# BIN directory is likely to cause problems.
+#
+# Leave $(BIN) undefined.  This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
+#
+BIN_GOALS_FIRST	:= $(foreach BGB,$(BIN_GOALS_BINS),\
+			     $(firstword $(filter $(BGB)/%,$(BIN_GOALS))))
+BIN_GOALS_OTHER	:= $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS))
+
+$(BIN_GOALS_FIRST) : % : BIN_RECURSE
+	$(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \
+	    $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS))
+$(BIN_GOALS_OTHER) : % : BIN_RECURSE
+	$(Q)$(TRUE)
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+	@# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP	+= $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
+#
+NO_DEP_TARGETS	:= $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS	:= 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS	:= 1
+endif
+
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[arch-]platform]
+
+ARCHS		:= $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS	:= $(patsubst config/defaults/%.h,%,\
+		     $(wildcard config/defaults/*.h))
+archs :
+	@$(ECHO) $(ARCHS)
+
+platforms :
+	@$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Determine architecture portion of $(BIN), if present
+BIN_ARCH	:= $(strip $(foreach A,$(ARCHS),\
+			     $(patsubst bin-$(A)-%,$(A),\
+			       $(filter bin-$(A)-%,$(BIN)))))
+
+# Determine platform portion of $(BIN), if present
+ifeq ($(BIN_ARCH),)
+BIN_PLATFORM	:= $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
+else
+BIN_PLATFORM	:= $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
+endif
+
+# Determine build architecture
+DEFAULT_ARCH	:= i386
+ARCH		:= $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS		+= -DARCH=$(ARCH)
+arch :
+	@$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM	:= $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS		+= -DPLATFORM=$(PLATFORM)
+platform :
+	@$(ECHO) $(PLATFORM)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS	+= arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+# Include architecture-specific include path
+ifdef ARCH
+INCDIRS		+= arch/$(ARCH)/include
+INCDIRS		+= arch/$(ARCH)/include/$(PLATFORM)
+endif
+
+###############################################################################
+#
+# Source file handling
+
+# SRCDIRS lists all directories containing source files.
+srcdirs :
+	@$(ECHO) $(SRCDIRS)
+
+# SRCS lists all .c or .S files found in any SRCDIR
+#
+SRCS	+= $(wildcard $(patsubst %,%/*.c,$(SRCDIRS)))
+SRCS	+= $(wildcard $(patsubst %,%/*.S,$(SRCDIRS)))
+srcs :
+	@$(ECHO) $(SRCS)
+
+# AUTO_SRCS lists all files in SRCS that are not mentioned in
+# NON_AUTO_SRCS.  Files should be added to NON_AUTO_SRCS if they
+# cannot be built using the standard build template.
+#
+AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
+autosrcs :
+	@$(ECHO) $(AUTO_SRCS)
+
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# INCDIRS lists the include path
+incdirs :
+	@$(ECHO) $(INCDIRS)
+
+# Common flags
+#
+CFLAGS		+= $(foreach INC,$(INCDIRS),-I$(INC))
+CFLAGS		+= -Os
+CFLAGS		+= -g
+ifeq ($(CCTYPE),gcc)
+CFLAGS		+= -ffreestanding
+CFLAGS		+= -Wall -W -Wformat-nonliteral
+endif
+ifeq ($(CCTYPE),icc)
+CFLAGS		+= -fno-builtin
+CFLAGS		+= -no-ip
+CFLAGS		+= -no-gcc
+CFLAGS		+= -diag-disable 111 # Unreachable code
+CFLAGS		+= -diag-disable 128 # Unreachable loop
+CFLAGS		+= -diag-disable 170 # Array boundary checks
+CFLAGS		+= -diag-disable 177 # Unused functions
+CFLAGS		+= -diag-disable 181 # printf() format checks
+CFLAGS		+= -diag-disable 188 # enum strictness
+CFLAGS		+= -diag-disable 193 # Undefined preprocessor identifiers
+CFLAGS		+= -diag-disable 280 # switch ( constant )
+CFLAGS		+= -diag-disable 310 # K&R parameter lists
+CFLAGS		+= -diag-disable 424 # Extra semicolon
+CFLAGS		+= -diag-disable 589 # Declarations mid-code
+CFLAGS		+= -diag-disable 593 # Unused variables
+CFLAGS		+= -diag-disable 810 # Casting ints to smaller ints
+CFLAGS		+= -diag-disable 981 # Sequence point violations
+CFLAGS		+= -diag-disable 1292 # Ignored attributes
+CFLAGS		+= -diag-disable 1338 # void pointer arithmetic
+CFLAGS		+= -diag-disable 1361 # Variable-length arrays
+CFLAGS		+= -diag-disable 1418 # Missing prototypes
+CFLAGS		+= -diag-disable 1419 # Missing prototypes
+CFLAGS		+= -diag-disable 1599 # Hidden variables
+CFLAGS		+= -Wall -Wmissing-declarations
+endif
+CFLAGS		+= $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
+ASFLAGS		+= $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
+LDFLAGS		+= $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS		+= -Werror
+ASFLAGS		+= --fatal-warnings
+endif
+
+# Function trace recorder state in the last build.  This is needed
+# in order to correctly rebuild whenever the function recorder is
+# enabled/disabled.
+#
+FNREC_STATE	:= $(BIN)/.fnrec.state
+ifeq ($(wildcard $(FNREC_STATE)),)
+FNREC_OLD	:= <invalid>
+else
+FNREC_OLD	:= $(shell cat $(FNREC_STATE))
+endif
+ifeq ($(FNREC_OLD),$(FNREC))
+$(FNREC_STATE) :
+else
+$(FNREC_STATE) : clean
+$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
+endif
+
+VERYCLEANUP	+= $(FNREC_STATE)
+MAKEDEPS	+= $(FNREC_STATE)
+
+ifeq ($(FNREC),1)
+# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
+# warnings about use of uninitialised variables.
+#
+CFLAGS		+= -Wno-uninitialized
+CFLAGS		+= -finstrument-functions
+CFLAGS		+= -finstrument-functions-exclude-file-list=core/fnrec.c
+endif
+
+# Enable per-item sections and section garbage collection.  Note that
+# some older versions of gcc support -fdata-sections but treat it as
+# implying -fno-common, which would break our build.
+#
+ifeq ($(CCTYPE),gcc)
+DS_TEST		= $(ECHO) 'char x;' | \
+		  $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
+		  grep -E '\.comm' > /dev/null
+DS_FLAGS	:= $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
+CFLAGS		+= -ffunction-sections $(DS_FLAGS)
+endif
+LDFLAGS		+= --gc-sections
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS		+= -include compiler.h
+
+# CFLAGS for specific object types
+#
+CFLAGS_c	+=
+CFLAGS_S 	+= -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT		= $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files.  You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS	= $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+	@$(ECHO) $(OBJ_CFLAGS)
+
+# ICC requires postprocessing objects to fix up table alignments
+#
+ifeq ($(CCTYPE),icc)
+POST_O		= && $(ICCFIX) $@
+POST_O_DEPS	:= $(ICCFIX)
+else
+POST_O		:=
+POST_O_DEPS	:=
+endif
+
+# Rules for specific object types.
+#
+COMPILE_c	= $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c		= $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
+RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(subst -,_,$(OBJECT))=$* -c $< -o $@ $(POST_O)
+RULE_c_to_c	= $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s	= $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S	= $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S	= $(AS) $(ASFLAGS)
+RULE_S		= $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -Ddebug_$(subst -,_,$(OBJECT))=$* $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s	= $(Q)$(PREPROCESS_S) $< > $@
+
+DEBUG_TARGETS	+= dbg%.o c s
+
+# We automatically generate rules for any file mentioned in AUTO_SRCS
+# using the following set of templates.  It would be cleaner to use
+# $(eval ...), but this function exists only in GNU make >= 3.80.
+
+# deps_template : generate dependency list for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define deps_template
+	@$(ECHO) "  [DEPS] $(1)"
+	@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
+	@$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
+		-Wno-error -M $(1) -MG -MP | \
+		sed 's/\.o\s*:/_DEPS =/' > $(BIN)/deps/$(1).d
+endef
+
+# rules_template : generate rules for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define rules_template
+	@$(ECHO) "  [RULES] $(1)"
+	@$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+	@$(ECHO_E) '\n$$(BIN)/$(3).o :' \
+		 '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)' \
+		 '\n\t$$(QM)$(ECHO) "  [BUILD] $$@"' \
+		 '\n\t$$(RULE_$(2))\n' \
+		 '\nBOBJS += $$(BIN)/$(3).o\n' \
+		 $(foreach TGT,$(DEBUG_TARGETS), \
+		    $(if $(RULE_$(2)_to_$(TGT)), \
+		    '\n$$(BIN)/$(3).$(TGT) :' \
+		    '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)' \
+		    '\n\t$$(QM)$(ECHO) "  [BUILD] $$@"' \
+		    '\n\t$$(RULE_$(2)_to_$(TGT))\n' \
+		    '\n$(TGT)_OBJS += $$(BIN)/$(3).$(TGT)\n' ) ) \
+		 '\n$(BIN)/deps/$(1).d : $$($(3)_DEPS)\n' \
+		 '\nTAGS : $$($(3)_DEPS)\n' > $(BIN)/rules/$(1).r
+	@$(PERL) $(PARSEROM) $(1) >> $(BIN)/rules/$(1).r
+endef
+
+# Rule to generate the dependency list file
+#
+$(BIN)/deps/%.d : % $(MAKEDEPS)
+	$(call deps_template,$<,$(subst .,,$(suffix $<)),$(basename $(notdir $<)))
+
+# Calculate and include the list of dependency list files
+#
+AUTO_DEPS	= $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
+-include $(AUTO_DEPS)
+endif
+endif
+autodeps :
+	@$(ECHO) $(AUTO_DEPS)
+VERYCLEANUP	+= $(BIN)/deps
+
+# Rule to generate the rules file
+#
+$(BIN)/rules/%.r : % $(MAKEDEPS) $(PARSEROM)
+	$(call rules_template,$<,$(subst .,,$(suffix $<)),$(basename $(notdir $<)))
+
+# Calculate and include the list of rules files
+#
+AUTO_RULES	= $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS))
+ifdef NEED_DEPS
+ifneq ($(AUTO_RULES),)
+-include $(AUTO_RULES)
+endif
+endif
+autorules :
+	@$(ECHO) $(AUTO_RULES)
+VERYCLEANUP	+= $(BIN)/rules
+
+# The following variables are created by the rules files
+#
+bobjs :
+	@$(ECHO) $(BOBJS)
+drivers :
+	@$(ECHO) $(DRIVERS)
+.PHONY : drivers
+roms :
+	@$(ECHO) $(ROMS)
+
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBEDDED_LIST	:= $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBEDDED_IMAGE_OLD := <invalid>
+else
+EMBEDDED_IMAGE_OLD := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBEDDED_IMAGE_OLD),$(EMBEDDED_IMAGE))
+$(shell $(ECHO) "$(EMBEDDED_IMAGE)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) :
+
+VERYCLEANUP	+= $(EMBEDDED_LIST)
+
+EMBEDDED_FILES	:= $(subst $(COMMA), ,$(EMBEDDED_IMAGE))
+EMBED_ALL	:= $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
+		     EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+			     \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+
+# This file uses .incbin inline assembly to include a binary file.
+# Unfortunately ccache does not detect this dependency and caches builds even
+# when the binary file has changed.
+#
+$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
+
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
+
+# Generate error usage information
+#
+$(BIN)/%.einfo : $(BIN)/%.o
+	$(QM)$(ECHO) "  [EINFO] $@"
+	$(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \
+		$< $@
+
+EINFOS		:= $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS))
+$(BIN)/errors : $(EINFOS) $(EINFO)
+	$(QM)$(ECHO) "  [EINFO] $@"
+	$(Q)$(EINFO) $(EINFOS) | sort > $@
+CLEANUP		+= $(BIN)/errors	# Doesn't match the $(BIN)/*.* pattern
+
+# Generate the NIC file from the parsed source files.  The NIC file is
+# only for rom-o-matic.
+#
+$(BIN)/NIC : $(AUTO_DEPS)
+	@$(ECHO) '# This is an automatically generated file, do not edit' > $@
+	@$(ECHO) '# It does not affect anything in the build, ' \
+	     'it is only for rom-o-matic' >> $@
+	@$(ECHO) >> $@
+	@perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
+CLEANUP		+= $(BIN)/NIC	# Doesn't match the $(BIN)/*.* pattern
+
+# Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and
+# derive the variables:
+# 
+# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci")
+# TGT_PREFIX   : the prefix type (e.g. "zrom")
+# TGT_DRIVERS  : the driver for each element (e.g. "rtl8139 prism2_pci")
+# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
+# TGT_MEDIA    : the media type (e.g. "rom")
+#
+DRIVERS_ipxe	= $(DRIVERS)
+CARD_DRIVER	= $(firstword $(DRIVER_$(1)) $(1))
+TGT_ELEMENTS	= $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
+TGT_PREFIX	= $(word 2,$(subst ., ,$(notdir $@)))
+TGT_ROM_NAME	= $(firstword $(TGT_ELEMENTS))
+TGT_DRIVERS	= $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \
+			       $(DRIVERS_$(TGT_ROM_NAME)), \
+			       $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
+			         $(call CARD_DRIVER,$(TGT_ELEMENT))) ))
+TGT_MEDIA	= $(subst z,,$(TGT_PREFIX))
+
+# Look up ROM IDs for the current target
+# (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the variables:
+#
+# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186")
+# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300")
+#
+TGT_PCI_VENDOR	= $(PCI_VENDOR_$(TGT_ROM_NAME))
+TGT_PCI_DEVICE	= $(PCI_DEVICE_$(TGT_ROM_NAME))
+
+# Calculate link-time options for the current target
+# (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the variables:
+#
+# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers
+#		   (e.g. "obj_rtl8139 obj_prism2_pci")
+# TGT_LD_IDS :     symbols to define in order to fill in ID structures in the
+#		   ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300")
+#
+TGT_LD_DRIVERS	= $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS)))
+TGT_LD_IDS	= pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \
+		  pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0)
+TGT_LD_ENTRY	= _$(TGT_PREFIX)_start
+
+# Calculate linker flags based on link-time options for the current
+# target type (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the
+# variables:
+#
+# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g.
+#		 "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci
+#		  --defsym pci_vendor=0x1186 --defsym pci_device=0x1300")
+#
+TGT_LD_FLAGS	= $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\
+		    -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \
+		  $(patsubst %,--defsym %,$(TGT_LD_IDS)) \
+		  -e $(TGT_LD_ENTRY)
+
+# Calculate list of debugging versions of objects to be included in
+# the target.
+#
+DEBUG_LIST	= $(subst $(COMMA), ,$(DEBUG))
+DEBUG_OBJ_LEVEL	= $(firstword $(word 2,$(subst :, ,$(1))) 1)
+DEBUG_OBJ_BASE	= $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
+DEBUG_OBJ	= $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o
+DEBUG_ORIG_OBJ	= $(BIN)/$(word 1,$(subst :, ,$(1))).o
+DEBUG_OBJS	= $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D)))
+DEBUG_ORIG_OBJS	= $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D)))
+BLIB_OBJS	= $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS))
+
+# Print out all derived information for a given target.
+#
+$(BIN)/%.info :
+	@$(ECHO) 'Elements             : $(TGT_ELEMENTS)'
+	@$(ECHO) 'Prefix               : $(TGT_PREFIX)'
+	@$(ECHO) 'Drivers              : $(TGT_DRIVERS)'
+	@$(ECHO) 'ROM name             : $(TGT_ROM_NAME)'
+	@$(ECHO) 'Media                : $(TGT_MEDIA)'
+	@$(ECHO)
+	@$(ECHO) 'PCI vendor           : $(TGT_PCI_VENDOR)'
+	@$(ECHO) 'PCI device           : $(TGT_PCI_DEVICE)'
+	@$(ECHO)
+	@$(ECHO) 'LD driver symbols    : $(TGT_LD_DRIVERS)'
+	@$(ECHO) 'LD ID symbols        : $(TGT_LD_IDS)'
+	@$(ECHO) 'LD entry point       : $(TGT_LD_ENTRY)'
+	@$(ECHO)
+	@$(ECHO) 'LD target flags      : $(TGT_LD_FLAGS)'
+	@$(ECHO)
+	@$(ECHO) 'Debugging objects    : $(DEBUG_OBJS)'
+	@$(ECHO) 'Replaced objects     : $(DEBUG_ORIG_OBJS)'
+
+# List of objects included in the last build of blib.  This is needed
+# in order to correctly rebuild blib whenever the list of objects
+# changes.
+#
+BLIB_LIST	:= $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_OBJS_OLD	:= <invalid>
+else
+BLIB_OBJS_OLD	:= $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS))
+$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
+endif
+
+$(BLIB_LIST) :
+
+VERYCLEANUP	+= $(BLIB_LIST)
+
+# Library of all objects
+#
+BLIB		= $(BIN)/blib.a
+$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
+	$(Q)$(RM) $(BLIB)
+	$(QM)$(ECHO) "  [AR] $@"
+	$(Q)$(AR) r $@ $(BLIB_OBJS)
+	$(Q)$(RANLIB) $@
+blib : $(BLIB)
+
+# Command to generate build ID.  Must be unique for each $(BIN)/%.tmp,
+# even within the same build run.
+#
+BUILD_ID_CMD	:= perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );'
+
+# Build an intermediate object file from the objects required for the
+# specified target.
+#
+$(BIN)/%.tmp : $(BLIB) $(MAKEDEPS) $(LDSCRIPT)
+	$(QM)$(ECHO) "  [LD] $@"
+	$(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $(BLIB) -o $@ \
+		--defsym _build_id=`$(BUILD_ID_CMD)` -Map $(BIN)/$*.tmp.map
+	$(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map
+
+# Keep intermediate object file (useful for debugging)
+.PRECIOUS : $(BIN)/%.tmp
+
+# Show a linker map for the specified target
+#
+$(BIN)/%.map : $(BIN)/%.tmp
+	@less $(BIN)/$*.tmp.map
+
+# Get objects list for the specified target
+#
+define objs_list
+	$(sort $(foreach OBJ_SYMBOL,\
+		 $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+		 $(patsubst obj_%,%,$(OBJ_SYMBOL))))
+endef
+$(BIN)/%.objs : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call objs_list,$<)
+$(BIN)/%.sizes : $(BIN)/%.tmp
+	$(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \
+		sort -g
+
+# Get dependency list for the specified target
+#
+define deps_list
+	$(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS)))
+endef
+$(BIN)/%.deps : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call deps_list,$<)
+
+# Get unneeded source files for the specified target
+#
+define nodeps_list
+	$(sort $(filter-out $(call deps_list,$(1)),\
+		 $(foreach BOBJ,$(BOBJS),\
+		   $($(basename $(notdir $(BOBJ)))_DEPS))))
+endef
+$(BIN)/%.nodeps : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call nodeps_list,$<)
+
+# Get licensing verdict for the specified target
+#
+define licensable_deps_list
+	$(filter-out config/local/%.h,$(call deps_list,$(1)))
+endef
+define unlicensed_deps_list
+	$(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1)))
+endef
+define licence_list
+	$(patsubst __licence_%,%,\
+	  $(filter __licence_%,$(shell $(NM) $(1) | cut -d" " -f3)))
+endef
+$(BIN)/%.licence : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [LICENCE] $@"
+	$(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\
+		echo -n "Unable to determine licence because the following " ;\
+		echo "files are missing a licence declaration:" ;\
+		echo $(call unlicensed_deps_list,$<);\
+		exit 1,\
+		$(PERL) $(LICENCE) $(call licence_list,$<))
+
+# Extract compression information from intermediate object file
+#
+$(BIN)/%.zinfo : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [ZINFO] $@"
+	$(Q)$(OBJCOPY) -O binary -j .zinfo $< $@
+
+# Build raw binary file from intermediate object file
+#
+$(BIN)/%.bin : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [BIN] $@"
+	$(Q)$(OBJCOPY) -O binary -R .zinfo $< $@
+
+# Compress raw binary file
+#
+$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
+	$(QM)$(ECHO) "  [ZBIN] $@"
+	$(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
+
+# Rules for each media format.  These are generated and placed in an
+# external Makefile fragment.  We could do this via $(eval ...), but
+# that would require make >= 3.80.
+# 
+# Note that there's an alternative way to generate most .rom images:
+# they can be copied from their 'master' ROM image using cp and
+# reprocessed with makerom to add the PCI IDs and ident string.  The
+# relevant rule would look something like:
+#
+#   $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom
+#	cat $< $@
+#	$(FINALISE_rom)
+# 
+# You can derive the ROM/driver relationships using the variables
+# DRIVER_<rom> and/or ROMS_<driver>.
+# 
+# We don't currently do this, because (a) it would require generating
+# yet more Makefile fragments (since you need a rule for each ROM in
+# ROMS), and (b) the linker is so fast that it probably wouldn't make
+# much difference to the overall build time.
+
+# Add NON_AUTO_MEDIA to the media list, so that they show up in the
+# output of "make"
+#
+MEDIA		+= $(NON_AUTO_MEDIA)
+
+media :
+	@$(ECHO) $(MEDIA)
+
+AUTO_MEDIA	= $(filter-out $(NON_AUTO_MEDIA),$(MEDIA))
+automedia :
+	@$(ECHO) $(AUTO_MEDIA)
+
+# media_template : create Makefile rules for specified media
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template
+	@$(ECHO) "  [MEDIARULES] $(1)"
+	@$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+	@$(ECHO_E) '$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin' \
+		  '\n\t$$(QM)$(ECHO) "  [FINISH] $$@"' \
+		  '\n\t$$(Q)$$(CP) $$< $$@' \
+		  '\n\t$$(Q)$$(PAD_$(1))' \
+		  '\n\t$$(Q)$$(FINALISE_$(1))' \
+		> $(BIN)/rules/$(1).media.r
+endef
+
+# Rule to generate the Makefile rules to be included
+#
+$(BIN)/rules/%.media.r : $(MAKEDEPS)
+	$(call media_template,$*)
+
+# Calculate and include the list of Makefile rules files
+#
+MEDIA_RULES		= $(patsubst %,$(BIN)/rules/%.media.r,$(AUTO_MEDIA))
+mediarules :
+	@$(ECHO) $(MEDIA_RULES)
+ifdef NEED_DEPS
+ifneq ($(MEDIA_RULES),)
+-include $(MEDIA_RULES)
+endif
+endif
+
+# Wrap up binary blobs (for embedded images)
+#
+$(BIN)/%.o : payload/%.img
+	$(QM)echo "  [WRAP] $@"
+	$(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \
+		--defsym obj_$*=0
+
+BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img))
+
+# The "allXXXs" targets for each suffix
+#
+allall: allroms allmroms allpxes allisos alldsks
+allroms allmroms : all%s : $(foreach ROM,$(ROMS),$(BIN)/$(ROM).%)
+allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%)
+
+# Alias for ipxe.%
+#
+$(BIN)/etherboot.% : $(BIN)/ipxe.%
+	ln -sf $(notdir $<) $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# The compression utilities
+#
+$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
+		       -DBITSIZE=32 -DENDIAN=0 -o $@ $<
+CLEANUP	+= $(NRV2B)
+
+$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) -O2 -o $@ $<
+CLEANUP += $(ZBIN)
+
+###############################################################################
+#
+# The EFI image converter
+#
+ELF2EFI_CFLAGS	:= -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
+		   -I$(ZLIB_DIR)/include -idirafter include \
+		   -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
+		   -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
+
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 -O2 -o $@
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 -O2 -o $@
+CLEANUP += $(ELF2EFI64)
+
+$(EFIROM) : util/efirom.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+CLEANUP += $(EFIROM)
+
+###############################################################################
+#
+# The ICC fixup utility
+#
+$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+CLEANUP += $(ICCFIX)
+
+###############################################################################
+#
+# The error usage information utility
+#
+$(EINFO) : util/einfo.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+CLEANUP += $(EINFO)
+
+###############################################################################
+#
+# Local configs
+#
+config/local/%.h :
+	$(Q)touch $@
+
+###############################################################################
+#
+# Auto-incrementing build serial number.  Append "bs" to your list of
+# build targets to get a serial number printed at the end of the
+# build.  Enable -DBUILD_SERIAL in order to see it when the code runs.
+#
+BUILDSERIAL_H		= config/.buildserial.h
+BUILDSERIAL_NOW		= config/.buildserial.now
+BUILDSERIAL_NEXT	= config/.buildserial.next
+
+$(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) :
+	$(ECHO) 1 > $@
+
+$(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT)
+	$(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@
+
+ifeq ($(filter bs,$(MAKECMDGOALS)),bs)
+$(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \
+	cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW))
+endif
+
+bs : $(BUILDSERIAL_NOW)
+	@$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
+	@$(ECHO) "Build serial number is $(shell cat $<)"
+
+###############################################################################
+#
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+	ctags -e -R -f $@ --exclude=bin
+
+CLEANUP	+= TAGS
+
+###############################################################################
+#
+# Force rebuild for any given target
+#
+%.rebuild :
+	rm -f $*
+	$(Q)$(MAKE) $*
+
+###############################################################################
+#
+# Symbol table checks
+#
+
+ifdef BIN
+
+SYMTAB	= $(BIN)/symtab
+$(SYMTAB) : $(BLIB)
+	$(OBJDUMP) -w -t $< > $@
+
+CLEANUP	+= $(BIN)/symtab
+
+symcheck : $(SYMTAB)
+	$(PERL) $(SYMCHECK) $<
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
+#
+
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+	$(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Documentation
+#
+
+ifdef BIN
+
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+	$(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+		-e  's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \
+		-e  's{\@BIN\@}{$(BIN)}; ' \
+		-e  's{\@ARCH\@}{$(ARCH)}; ' \
+		$< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+	$(Q)$(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+doc : $(BIN)/doc
+
+doc-clean :
+	$(Q)$(RM) -r $(BIN)/doc
+
+VERYCLEANUP	+= $(BIN)/doc
+
+docview :
+	@[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+	@if [ -n "$$BROWSER" ] ; then \
+		( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+	else \
+		$(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
+	fi
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Keyboard maps
+#
+
+hci/keymap/keymap_%.c :
+	$(Q)$(PERL) $(GENKEYMAP) $* > $@
+
+###############################################################################
+#
+# Force deletion of incomplete targets
+#
+
+.DELETE_ON_ERROR :
+
+###############################################################################
+#
+# Clean-up
+#
+clean :
+	$(RM) $(CLEANUP)
+
+veryclean : clean
+	$(RM) -r $(VERYCLEANUP)
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile
new file mode 100644
index 0000000..3261fff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile
@@ -0,0 +1,105 @@
+# Force i386-only instructions
+#
+CFLAGS		+= -march=i386
+
+# Code size reduction.
+#
+CFLAGS		+= -fomit-frame-pointer
+
+# Code size reduction.
+#
+ifeq ($(CCTYPE),gcc)
+CFLAGS		+= -fstrength-reduce
+endif
+
+# Code size reduction.  gcc3 needs a different syntax to gcc2 if you
+# want to avoid spurious warnings.
+#
+ifeq ($(CCTYPE),gcc)
+GCC_VERSION	:= $(subst ., ,$(shell $(CC) -dumpversion))
+GCC_MAJOR	:= $(firstword $(GCC_VERSION))
+ifeq ($(GCC_MAJOR),2)
+CFLAGS		+= -malign-jumps=1 -malign-loops=1 -malign-functions=1
+else
+CFLAGS		+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
+endif # gcc2
+endif # gcc
+
+# Code size reduction.  This is almost always a win.  The kernel uses
+# it, too.
+#
+ifeq ($(CCTYPE),gcc)
+CFLAGS		+= -mpreferred-stack-boundary=2
+endif
+
+# Code size reduction.  Use regparm for all functions - C functions
+# called from assembly (or vice versa) need __asmcall now
+#
+CFLAGS		+= -mregparm=3
+
+# Code size reduction.  Use -mrtd (same __asmcall requirements as above)
+ifeq ($(CCTYPE),gcc)
+CFLAGS		+= -mrtd
+endif
+
+# Code size reduction.  This is the logical complement to -mregparm=3.
+# It doesn't currently buy us anything, but if anything ever tries to
+# return small structures, let's be prepared
+#
+CFLAGS		+= -freg-struct-return
+
+# Force 32-bit code even on an x86-64 machine
+#
+CFLAGS		+= -m32
+ASFLAGS		+= --32
+ifeq ($(HOST_OS),FreeBSD)
+LDFLAGS		+= -m elf_i386_fbsd
+else
+LDFLAGS		+= -m elf_i386
+endif
+
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
+#
+CFLAGS		+= -fshort-wchar
+
+# We need to undefine the default macro "i386" when compiling .S
+# files, otherwise ".arch i386" translates to ".arch 1"...
+#
+CFLAGS			+= -Ui386
+
+# Locations of utilities
+#
+ISOLINUX_BIN_LIST	:= \
+	$(ISOLINUX_BIN) \
+	/usr/lib/syslinux/isolinux.bin \
+	/usr/share/syslinux/isolinux.bin \
+	/usr/local/share/syslinux/isolinux.bin
+ISOLINUX_BIN	= $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
+
+# i386-specific directories containing source files
+#
+SRCDIRS		+= arch/i386/core arch/i386/transitions arch/i386/prefix
+SRCDIRS		+= arch/i386/firmware/pcbios
+SRCDIRS		+= arch/i386/image
+SRCDIRS		+= arch/i386/interface/pcbios
+SRCDIRS		+= arch/i386/interface/pxe
+SRCDIRS		+= arch/i386/interface/pxeparent
+SRCDIRS 	+= arch/i386/interface/syslinux
+SRCDIRS		+= arch/i386/hci/commands
+
+# The various xxx_loader.c files are #included into core/loader.c and
+# should not be compiled directly.
+#
+NON_AUTO_SRCS	+= arch/i386/core/aout_loader.c
+NON_AUTO_SRCS	+= arch/i386/core/freebsd_loader.c
+NON_AUTO_SRCS	+= arch/i386/core/wince_loader.c
+
+# Include common x86 Makefile
+#
+MAKEDEPS	+= arch/x86/Makefile
+include arch/x86/Makefile
+
+# Include platform-specific Makefile
+#
+MAKEDEPS	+= arch/i386/Makefile.$(PLATFORM)
+include arch/i386/Makefile.$(PLATFORM)
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.efi b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.efi
new file mode 100644
index 0000000..8d651b0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.efi
@@ -0,0 +1,10 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# Specify EFI image builder
+#
+ELF2EFI		= $(ELF2EFI32)
+
+# Include generic EFI Makefile
+#
+MAKEDEPS	+= arch/x86/Makefile.efi
+include arch/x86/Makefile.efi
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.linux b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.linux
new file mode 100644
index 0000000..46328c8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.linux
@@ -0,0 +1,6 @@
+LDSCRIPT = arch/i386/scripts/linux.lds
+
+SRCDIRS += arch/i386/core/linux
+
+MAKEDEPS += arch/x86/Makefile.linux
+include arch/x86/Makefile.linux
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.pcbios b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.pcbios
new file mode 100644
index 0000000..258c5d7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/Makefile.pcbios
@@ -0,0 +1,86 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The i386 linker script
+#
+LDSCRIPT	= arch/i386/scripts/i386.lds
+
+# Stop ld from complaining about our customised linker script
+#
+LDFLAGS		+= -N --no-check-sections
+
+# pcbios specific drivers
+SRCDIRS		+= arch/i386/drivers
+SRCDIRS		+= arch/i386/drivers/net
+
+# Media types.
+#
+MEDIA		+= rom
+MEDIA		+= mrom
+MEDIA		+= pxe
+MEDIA		+= kpxe
+MEDIA		+= kkpxe
+MEDIA		+= lkrn
+MEDIA		+= dsk
+MEDIA		+= nbi
+MEDIA		+= hd
+MEDIA		+= raw
+MEDIA		+= exe
+
+# Padding rules
+#
+PAD_rom		= $(PERL) $(PADIMG) --blksize=512 --byte=0xff $@
+PAD_mrom	= $(PAD_rom)
+PAD_dsk		= $(PERL) $(PADIMG) --blksize=512 $@
+PAD_hd		= $(PERL) $(PADIMG) --blksize=32768 $@
+PAD_exe		= $(PERL) $(PADIMG) --blksize=512 $@
+
+# Finalisation rules
+#
+FINALISE_rom	= $(PERL) $(FIXROM) $@
+FINALISE_mrom	= $(FINALISE_rom)
+
+# rule to make a non-emulation ISO boot image
+NON_AUTO_MEDIA	+= iso
+%iso:	%lkrn util/geniso
+	$(QM)$(ECHO) "  [GENISO] $@"
+	$(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
+
+# rule to make a floppy emulation ISO boot image
+NON_AUTO_MEDIA	+= liso
+%liso:	%lkrn util/genliso
+	$(QM)$(ECHO) "  [GENLISO] $@"
+	$(Q)bash util/genliso $@ $<
+
+# rule to make a syslinux floppy image (mountable, bootable)
+NON_AUTO_MEDIA	+= sdsk
+%sdsk:	%lkrn util/gensdsk
+	$(QM)$(ECHO) "  [GENSDSK] $@"
+	$(Q)bash util/gensdsk $@ $<
+
+# rule to write disk images to /dev/fd0
+NON_AUTO_MEDIA	+= fd0
+%fd0 : %dsk
+	$(QM)$(ECHO) "  [DD] $@"
+	$(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
+	$(Q)sync
+
+# Special target for building Master Boot Record binary
+$(BIN)/mbr.bin : $(BIN)/mbr.o
+	$(QM)$(ECHO) "  [OBJCOPY] $@"
+	$(Q)$(OBJCOPY) -O binary $< $@
+
+# rule to make a USB disk image
+$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
+	$(QM)$(ECHO) "  [OBJCOPY] $@"
+	$(Q)$(OBJCOPY) -O binary $< $@
+
+NON_AUTO_MEDIA	+= usb
+%usb: $(BIN)/usbdisk.bin %hd
+	$(QM)$(ECHO) "  [FINISH] $@"
+	$(Q)cat $^ > $@
+
+# Padded floppy image (e.g. for iLO)
+NON_AUTO_MEDIA += pdsk
+%pdsk : %dsk
+	$(Q)cp $< $@
+	$(Q)$(PADIMG) --blksize=1474560 $@
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/README.i386 b/qemu-0.15.x/roms/ipxe/src/arch/i386/README.i386
new file mode 100644
index 0000000..b9b79cc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/README.i386
@@ -0,0 +1,197 @@
+Etherboot/NILO i386 initialisation path and external call interface
+===================================================================
+
+1. Background
+
+GCC compiles 32-bit code.  It is capable of producing
+position-independent code, but the resulting binary is about 25%
+bigger than the corresponding fixed-position code.  Since one main use
+of Etherboot is as firmware to be burned into an EPROM, code size must
+be kept as small as possible.
+
+This means that we want to compile fixed-position code with GCC, and
+link it to have a predetermined start address.  The problem then is
+that we must know the address that the code will be loaded to when it
+runs.  There are several ways to solve this:
+
+1. Pick an address, link the code with this start address, then make
+   sure that the code gets loaded at that location.  This is
+   problematic, because we may pick an address that we later end up
+   wanting to use to load the operating system that we're booting.
+
+2. Pick an address, link the code with this start address, then set up
+   virtual addressing so that the virtual addresses match the
+   link-time addresses regardless of the real physical address that
+   the code is loaded to.  This enables us to relocate Etherboot to
+   the top of high memory, where it will be out of the way of any
+   loading operating system.
+
+3. Link the code with a text start address of zero and a data start
+   address also of zero.  Use 16-bit real mode and the
+   quasi-position-independence it gives you via segment addressing.
+   Doing this requires that we generate 16-bit code, rather than
+   32-bit code, and restricts us to a maximum of 64kB in each segment.
+
+There are other possible approaches (e.g. including a relocation table
+and code that performs standard dynamic relocation), but the three
+options listed above are probably the best available.
+
+Etherboot can be invoked in a variety of ways (ROM, floppy, as a PXE
+NBP, etc).  Several of these ways involve control being passed to
+Etherboot with the CPU in 16-bit real mode.  Some will involve the CPU
+being in 32-bit protected mode, and there's an outside chance that
+some may involve the CPU being in 16-bit protected mode.  We will
+almost certainly have to effect a CPU mode change in order to reach
+the mode we want to be in to execute the C code.
+
+Additionally, Etherboot may wish to call external routines, such as
+BIOS interrupts, which must be called in 16-bit real mode.  When
+providing a PXE API, Etherboot must provide a mechanism for external
+code to call it from 16-bit real mode.
+
+Not all i386 builds of Etherboot will want to make real-mode calls.
+For example, when built for LinuxBIOS rather than the standard PCBIOS,
+no real-mode calls are necessary.
+
+For the ultimate in PXE compatibility, we may want to build Etherboot
+to run permanently in real mode.
+
+There is a wide variety of potential combinations of mode switches
+that we may wish to implement.  There are additional complications,
+such as the inability to access a high-memory stack when running in
+real mode.
+
+2. Transition libraries
+
+To handle all these various combinations of mode switches, we have
+several "transition" libraries in Etherboot.  We also have the concept
+of an "internal" and an "external" environment.  The internal
+environment is the environment within which we can execute C code.
+The external environment is the environment of whatever external code
+we're trying to interface to, such as the system BIOS or a PXE NBP.
+
+As well as having a separate addressing scheme, the internal
+environment also has a separate stack.
+
+The transition libraries are:
+
+a) librm
+
+librm handles transitions between an external 16-bit real-mode
+environment and an internal 32-bit protected-mode environment with
+virtual addresses.
+
+b) libkir
+
+libkir handles transitions between an external 16-bit real-mode (or
+16:16 or 16:32 protected-mode) environment and an internal 16-bit
+real-mode (or 16:16 protected-mode) environment.
+
+c) libpm
+
+libpm handles transitions between an external 32-bit protected-mode
+environment with flat physical addresses and an internal 32-bit
+protected-mode environment with virtual addresses.
+
+The transition libraries handle the transitions required when
+Etherboot is started up for the first time, the transitions required
+to execute any external code, and the transitions required when
+Etherboot exits (if it exits).  When Etherboot provides a PXE API,
+they also handle the transitions required when a PXE client makes a
+PXE API call to Etherboot.
+
+Etherboot may use multiple transition libraries.  For example, an
+Etherboot ELF image does not require librm for its initial transitions
+from prefix to runtime, but may require librm for calling external
+real-mode functions.
+
+3. Setup and initialisation
+
+Etherboot is conceptually divided into the prefix, the decompressor,
+and the runtime image.  (For non-compressed images, the decompressor
+is a no-op.)  The complete image comprises all three parts and is
+distinct from the runtime image, which exclude the prefix and the
+decompressor.
+
+The prefix does several tasks:
+
+  Load the complete image into memory.  (For example, the floppy
+  prefix issues BIOS calls to load the remainder of the complete image
+  from the floppy disk into RAM, and the ISA ROM prefix copies the ROM
+  contents into RAM for faster access.)
+
+  Call the decompressor, if the runtime image is compressed.  This
+  decompresses the runtime image.
+
+  Call the runtime image's setup() routine.  This is a routine
+  implemented in assembly code which sets up the internal environment
+  so that C code can execute.
+
+  Call the runtime image's arch_initialise() routine.  This is a
+  routine implemented in C which does some basic startup tasks, such
+  as initialising the console device, obtaining a memory map and
+  relocating the runtime image to high memory.
+
+  Call the runtime image's arch_main() routine.  This records the exit
+  mechanism requested by the prefix and calls main().  (The prefix
+  needs to register an exit mechanism because by the time main()
+  returns, the memory occupied by the prefix has most likely been
+  overwritten.)
+
+When acting as a PXE ROM, the ROM prefix contains an UNDI loader
+routine in addition to its usual code.  The UNDI loader performs a
+similar sequence of steps:
+
+  Load the complete image into memory.
+
+  Call the decompressor.
+
+  Call the runtime image's setup() routine.
+
+  Call the runtime image's arch_initialise() routine.
+
+  Call the runtime image's install_pxe_stack() routine.
+
+  Return to caller.
+
+The runtime image's setup() routine will perform the following steps:
+
+  Switch to the internal environment using an appropriate transition
+  library.  This will record the parameters of the external
+  environment.
+
+  Set up the internal environment: load a stack, and set up a GDT for
+  virtual addressing if virtual addressing is to be used.
+
+  Switch back to the external environment using the transition
+  library.  This will record the parameters of the internal
+  environment.
+
+Once the setup() routine has returned, the internal environment has been
+set up ready for C code to run.  The prefix can call C routines using
+a function from the transition library.
+
+The runtime image's arch_initialise() routine will perform the
+following steps:
+
+  Zero the bss
+
+  Initialise the console device(s) and print a welcome message.
+
+  Obtain a memory map via the INT 15,E820 BIOS call or suitable
+  fallback mechanism. [not done if libkir is being used]
+
+  Relocate the runtime image to the top of high memory. [not done if
+  libkir is being used]
+
+  Install librm to base memory. [done only if librm is being used]
+
+  Call initialise().
+
+  Return to the prefix, setting registers to indicate to the prefix
+  the new location of the transition library, if applicable.  Which
+  registers these are is specific to the transition library being
+  used.
+
+Once the arch_initialise() routine has returned, the prefix will
+probably call arch_main().
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/aout_loader.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/aout_loader.c
new file mode 100644
index 0000000..f85620e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/aout_loader.c
@@ -0,0 +1,144 @@
+/* a.out */
+struct exec {
+	unsigned long      a_midmag;	/* flags<<26 | mid<<16 | magic */
+	unsigned long      a_text;	/* text segment size */
+	unsigned long      a_data;	/* initialized data size */
+	unsigned long      a_bss;	/* uninitialized data size */
+	unsigned long      a_syms;	/* symbol table size */
+	unsigned long      a_entry;	/* entry point */
+	unsigned long      a_trsize;	/* text relocation size */
+	unsigned long      a_drsize;	/* data relocation size */
+};
+
+struct aout_state {
+	struct exec head;
+	unsigned long curaddr;
+	int segment;			/* current segment number, -1 for none */
+	unsigned long loc;		/* start offset of current block */
+	unsigned long skip;		/* padding to be skipped to current segment */
+	unsigned long toread;		/* remaining data to be read in the segment */
+};
+
+static struct aout_state astate;
+
+static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
+static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
+{
+	unsigned long start, mid, end, istart, iend;
+	if (len < sizeof(astate.head)) {
+		return 0;
+	}
+	memcpy(&astate.head, data, sizeof(astate.head));
+	if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
+		return 0;
+	}
+	
+	printf("(a.out");
+	aout_freebsd_probe();
+	printf(")... ");
+	/* Check the aout image */
+	start  = astate.head.a_entry;
+	mid    = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
+	end    = ((mid + 4095) & ~4095) + astate.head.a_bss;
+	istart = 4096;
+	iend   = istart + (mid - start);
+	if (!prep_segment(start, mid, end, istart, iend))
+		return dead_download;
+	astate.segment = -1;
+	astate.loc = 0;
+	astate.skip = 0;
+	astate.toread = 0;
+	return aout_download;
+}
+
+static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
+{
+	unsigned int offset;	/* working offset in the current data block */
+
+	offset = 0;
+
+#ifdef AOUT_LYNX_KDI
+	astate.segment++;
+	if (astate.segment == 0) {
+		astate.curaddr = 0x100000;
+		astate.head.a_entry = astate.curaddr + 0x20;
+	}
+	memcpy(phys_to_virt(astate.curaddr), data, len);
+	astate.curaddr += len;
+	return 0;
+#endif
+
+	do {
+		if (astate.segment != -1) {
+			if (astate.skip) {
+				if (astate.skip >= len - offset) {
+					astate.skip -= len - offset;
+					break;
+				}
+				offset += astate.skip;
+				astate.skip = 0;
+			}
+
+			if (astate.toread) {
+				if (astate.toread >= len - offset) {
+					memcpy(phys_to_virt(astate.curaddr), data+offset,
+						len - offset);
+					astate.curaddr += len - offset;
+					astate.toread -= len - offset;
+					break;
+				}
+				memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
+				offset += astate.toread;
+				astate.toread = 0;
+			}
+		}
+
+		/* Data left, but current segment finished - look for the next
+		 * segment.  This is quite simple for a.out files.  */
+		astate.segment++;
+		switch (astate.segment) {
+		case 0:
+			/* read text */
+			astate.curaddr = astate.head.a_entry;
+			astate.skip = 4096;
+			astate.toread = astate.head.a_text;
+			break;
+		case 1:
+			/* read data */
+			/* skip and curaddr may be wrong, but I couldn't find
+			 * examples where this failed.  There is no reasonable
+			 * documentation for a.out available.  */
+			astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
+			astate.curaddr = (astate.curaddr + 4095) & ~4095;
+			astate.toread = astate.head.a_data;
+			break;
+		case 2:
+			/* initialize bss and start kernel */
+			astate.curaddr = (astate.curaddr + 4095) & ~4095;
+			astate.skip = 0;
+			astate.toread = 0;
+			memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
+			goto aout_startkernel;
+		default:
+			break;
+		}
+	} while (offset < len);
+
+	astate.loc += len;
+
+	if (eof) {
+		unsigned long entry;
+
+aout_startkernel:
+		entry = astate.head.a_entry;
+		done(1);
+
+		aout_freebsd_boot();
+#ifdef AOUT_LYNX_KDI
+		xstart32(entry);
+#endif
+		printf("unexpected a.out variant\n");
+		longjmp(restart_etherboot, -2);
+	}
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/basemem_packet.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/basemem_packet.c
new file mode 100644
index 0000000..d487cce
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/basemem_packet.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Packet buffer in base memory.  Used by various components which
+ * need to pass packets to and from external real-mode code.
+ *
+ */
+
+#include <basemem_packet.h>
+
+#undef basemem_packet
+char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cmdline.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cmdline.c
new file mode 100644
index 0000000..fa5adb8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cmdline.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Command line passed to iPXE
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ipxe/init.h>
+#include <ipxe/image.h>
+#include <ipxe/script.h>
+#include <realmode.h>
+
+/** Command line physical address
+ *
+ * This can be set by the prefix.
+ */
+uint32_t __bss16 ( cmdline_phys );
+#define cmdline_phys __use_data16 ( cmdline_phys )
+
+/** Internal copy of the command line */
+static char *cmdline_copy;
+
+/** Free command line image */
+static void cmdline_image_free ( struct refcnt *refcnt ) {
+	struct image *image = container_of ( refcnt, struct image, refcnt );
+
+	DBGC ( image, "CMDLINE freeing command line\n" );
+	free ( cmdline_copy );
+}
+
+/** Embedded script representing the command line */
+static struct image cmdline_image = {
+	.refcnt = REF_INIT ( cmdline_image_free ),
+	.name = "<CMDLINE>",
+	.type = &script_image_type,
+};
+
+/**
+ * Initialise command line
+ *
+ */
+static void cmdline_init ( void ) {
+	struct image *image = &cmdline_image;
+	userptr_t cmdline_user;
+	char *cmdline;
+	char *tmp;
+	size_t len;
+
+	/* Do nothing if no command line was specified */
+	if ( ! cmdline_phys ) {
+		DBGC ( image, "CMDLINE found no command line\n" );
+		return;
+	}
+	cmdline_user = phys_to_user ( cmdline_phys );
+	len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
+
+	/* Allocate and copy command line */
+	cmdline_copy = malloc ( len );
+	if ( ! cmdline_copy ) {
+		DBGC ( image, "CMDLINE could not allocate %zd bytes\n", len );
+		/* No way to indicate failure */
+		return;
+	}
+	cmdline = cmdline_copy;
+	copy_from_user ( cmdline, cmdline_user, 0, len );
+	DBGC ( image, "CMDLINE found \"%s\"\n", cmdline );
+
+	/* Check for unwanted cruft in the command line */
+	while ( isspace ( *cmdline ) )
+		cmdline++;
+	if ( ( tmp = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) {
+		DBGC ( image, "CMDLINE stripping \"%s\"\n", tmp );
+		*tmp = '\0';
+	}
+	DBGC ( image, "CMDLINE using \"%s\"\n", cmdline );
+
+	/* Prepare and register image */
+	cmdline_image.data = virt_to_user ( cmdline );
+	cmdline_image.len = strlen ( cmdline );
+	if ( cmdline_image.len )
+		register_image ( &cmdline_image );
+
+	/* Drop our reference to the image */
+	image_put ( &cmdline_image );
+}
+
+/** Command line initialisation function */
+struct init_fn cmdline_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = cmdline_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cpu.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cpu.c
new file mode 100644
index 0000000..c24fa4e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/cpu.c
@@ -0,0 +1,73 @@
+#include <stdint.h>
+#include <string.h>
+#include <cpu.h>
+
+/** @file
+ *
+ * CPU identification
+ *
+ */
+
+/**
+ * Test to see if CPU flag is changeable
+ *
+ * @v flag		Flag to test
+ * @ret can_change	Flag is changeable
+ */
+static inline int flag_is_changeable ( unsigned int flag ) {
+	uint32_t f1, f2;
+
+	__asm__ ( "pushfl\n\t"
+		  "pushfl\n\t"
+		  "popl %0\n\t"
+		  "movl %0,%1\n\t"
+		  "xorl %2,%0\n\t"
+		  "pushl %0\n\t"
+		  "popfl\n\t"
+		  "pushfl\n\t"
+		  "popl %0\n\t"
+		  "popfl\n\t"
+		  : "=&r" ( f1 ), "=&r" ( f2 )
+		  : "ir" ( flag ) );
+
+	return ( ( ( f1 ^ f2 ) & flag ) != 0 );
+}
+
+/**
+ * Get CPU information
+ *
+ * @v cpu		CPU information structure to fill in
+ */
+void get_cpuinfo ( struct cpuinfo_x86 *cpu ) {
+	unsigned int cpuid_level;
+	unsigned int cpuid_extlevel;
+	unsigned int discard_1, discard_2, discard_3;
+
+	memset ( cpu, 0, sizeof ( *cpu ) );
+
+	/* Check for CPUID instruction */
+	if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) {
+		DBG ( "CPUID not supported\n" );
+		return;
+	}
+
+	/* Get features, if present */
+	cpuid ( 0x00000000, &cpuid_level, &discard_1,
+		&discard_2, &discard_3 );
+	if ( cpuid_level >= 0x00000001 ) {
+		cpuid ( 0x00000001, &discard_1, &discard_2,
+			&discard_3, &cpu->features );
+	} else {
+		DBG ( "CPUID cannot return capabilities\n" );
+	}
+
+	/* Get 64-bit features, if present */
+	cpuid ( 0x80000000, &cpuid_extlevel, &discard_1,
+		&discard_2, &discard_3 );
+	if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) {
+		if ( cpuid_extlevel >= 0x80000001 ) {
+			cpuid ( 0x80000001, &discard_1, &discard_2,
+				&discard_3, &cpu->amd_features );
+		}
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/dumpregs.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/dumpregs.c
new file mode 100644
index 0000000..82dc218
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/dumpregs.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <realmode.h>
+
+void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
+
+	__asm__ __volatile__ (
+		TEXT16_CODE ( ".globl dump_regs\n\t"
+			      "\ndump_regs:\n\t"
+			      "pushl $_dump_regs\n\t"
+			      "pushw %%cs\n\t"
+			      "call prot_call\n\t"
+			      "addr32 leal 4(%%esp), %%esp\n\t"
+			      "ret\n\t" ) : : );
+
+	printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
+		 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
+		 "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
+		 ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx,
+		 ix86->regs.edx, ix86->regs.esi, ix86->regs.edi,
+		 ix86->regs.ebp, ix86->regs.esp,
+		 ix86->segs.cs, ix86->segs.ss, ix86->segs.ds,
+		 ix86->segs.es, ix86->segs.fs, ix86->segs.gs );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/freebsd_loader.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/freebsd_loader.c
new file mode 100644
index 0000000..464f6d9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/freebsd_loader.c
@@ -0,0 +1,377 @@
+/* bootinfo */
+#define BOOTINFO_VERSION 1
+#define NODEV           (-1)    /* non-existent device */
+#define PAGE_SHIFT      12              /* LOG2(PAGE_SIZE) */
+#define PAGE_SIZE       (1<<PAGE_SHIFT) /* bytes/page */
+#define PAGE_MASK       (PAGE_SIZE-1)
+#define N_BIOS_GEOM     8
+
+struct bootinfo {
+        unsigned int            bi_version;
+        const unsigned char     *bi_kernelname;
+        struct nfs_diskless     *bi_nfs_diskless;
+                                /* End of fields that are always present. */
+#define bi_endcommon            bi_n_bios_used
+        unsigned int            bi_n_bios_used;
+        unsigned long           bi_bios_geom[N_BIOS_GEOM];
+        unsigned int            bi_size;
+        unsigned char           bi_memsizes_valid;
+        unsigned char           bi_pad[3];
+        unsigned long           bi_basemem;
+        unsigned long           bi_extmem;
+        unsigned long           bi_symtab;
+        unsigned long           bi_esymtab;
+	/* Note that these are in the FreeBSD headers but were not here... */
+	unsigned long           bi_kernend;		/* end of kernel space */
+	unsigned long           bi_envp;		/* environment */
+	unsigned long           bi_modulep;		/* preloaded modules */
+};
+
+static struct bootinfo bsdinfo;
+
+#ifdef ELF_IMAGE
+static Elf32_Shdr *shdr;	/* To support the FreeBSD kludge! */
+static Address symtab_load;
+static Address symstr_load;
+static int symtabindex;
+static int symstrindex;
+#endif
+
+static enum {
+	Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
+} image_type = Unknown;
+
+static unsigned int off;
+
+
+#ifdef ELF_IMAGE
+static void elf_freebsd_probe(void)
+{
+	image_type = Elf;
+	if (	(estate.e.elf32.e_entry & 0xf0000000) && 
+		(estate.e.elf32.e_type == ET_EXEC))
+	{
+		image_type = Elf_FreeBSD;
+		printf("/FreeBSD");
+		off = -(estate.e.elf32.e_entry & 0xff000000);
+		estate.e.elf32.e_entry += off;
+	}
+	/* Make sure we have a null to start with... */
+	shdr = 0;
+	
+	/* Clear the symbol index values... */
+	symtabindex = -1;
+	symstrindex = -1;
+	
+	/* ...and the load addresses of the symbols  */
+	symtab_load = 0;
+	symstr_load = 0;
+}
+
+static void elf_freebsd_fixup_segment(void)
+{
+	if (image_type == Elf_FreeBSD) {
+		estate.p.phdr32[estate.segment].p_paddr += off;
+	}
+}
+
+static void elf_freebsd_find_segment_end(void)
+{
+	/* Count the bytes read even for the last block
+	 * as we will need to know where the last block
+	 * ends in order to load the symbols correctly.
+	 * (plus it could be useful elsewhere...)
+	 * Note that we need to count the actual size,
+	 * not just the end of the disk image size.
+	 */
+	estate.curaddr += 
+		(estate.p.phdr32[estate.segment].p_memsz - 
+		estate.p.phdr32[estate.segment].p_filesz);
+}
+
+static int elf_freebsd_debug_loader(unsigned int offset)
+{
+	/* No more segments to be loaded - time to start the
+	 * nasty state machine to support the loading of
+	 * FreeBSD debug symbols due to the fact that FreeBSD
+	 * uses/exports the kernel's debug symbols in order
+	 * to make much of the system work!  Amazing (arg!)
+	 *
+	 * We depend on the fact that for the FreeBSD kernel,
+	 * there is only one section of debug symbols and that
+	 * the section is after all of the loaded sections in
+	 * the file.  This assumes a lot but is somewhat required
+	 * to make this code not be too annoying.  (Where do you
+	 * load symbols when the code has not loaded yet?)
+	 * Since this function is actually just a callback from
+	 * the network data transfer code, we need to be able to
+	 * work with the data as it comes in.  There is no chance
+	 * for doing a seek other than forwards.
+	 *
+	 * The process we use is to first load the section
+	 * headers.  Once they are loaded (shdr != 0) we then
+	 * look for where the symbol table and symbol table
+	 * strings are and setup some state that we found
+	 * them and fall into processing the first one (which
+	 * is the symbol table) and after that has been loaded,
+	 * we try the symbol strings.  Note that the order is
+	 * actually required as the memory image depends on
+	 * the symbol strings being loaded starting at the
+	 * end of the symbol table.  The kernel assumes this
+	 * layout of the image.
+	 *
+	 * At any point, if we get to the end of the load file
+	 * or the section requested is earlier in the file than
+	 * the current file pointer, we just end up falling
+	 * out of this and booting the kernel without this
+	 * information.
+	 */
+
+	/* Make sure that the next address is long aligned... */
+	/* Assumes size of long is a power of 2... */
+	estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
+	
+	/* If we have not yet gotten the shdr loaded, try that */
+	if (shdr == 0)
+	{
+		estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
+		estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
+		if (estate.toread)
+		{
+#if ELF_DEBUG
+			printf("shdr *, size %lX, curaddr %lX\n", 
+				estate.toread, estate.curaddr);
+#endif
+			
+			/* Start reading at the curaddr and make that the shdr */
+			shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
+			
+			/* Start to read... */
+			return 1;
+		}
+	}
+	else
+	{
+		/* We have the shdr loaded, check if we have found
+		 * the indexs where the symbols are supposed to be */
+		if ((symtabindex == -1) && (symstrindex == -1))
+		{
+			int i;
+			/* Make sure that the address is page aligned... */
+			/* Symbols need to start in their own page(s)... */
+			estate.curaddr = (estate.curaddr + 4095) & ~4095;
+			
+			/* Need to make new indexes... */
+			for (i=0; i < estate.e.elf32.e_shnum; i++)
+			{
+				if (shdr[i].sh_type == SHT_SYMTAB)
+				{
+					int j;
+					for (j=0; j < estate.e.elf32.e_phnum; j++)
+					{
+						/* Check only for loaded sections */
+						if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
+						{
+							/* Only the extra symbols */
+							if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
+								((shdr[i].sh_offset + shdr[i].sh_size) <=
+									(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
+							{
+								shdr[i].sh_offset=0;
+								shdr[i].sh_size=0;
+								break;
+							}
+						}
+					}
+					if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
+					{
+						symtabindex = i;
+						symstrindex = shdr[i].sh_link;
+					}
+				}
+			}
+		}
+		
+		/* Check if we have a symbol table index and have not loaded it */
+		if ((symtab_load == 0) && (symtabindex >= 0))
+		{
+			/* No symbol table yet?  Load it first... */
+			
+			/* This happens to work out in a strange way.
+			 * If we are past the point in the file already,
+			 * we will skip a *large* number of bytes which
+			 * ends up bringing us to the end of the file and
+			 * an old (default) boot.  Less code and lets
+			 * the state machine work in a cleaner way but this
+			 * is a nasty side-effect trick... */
+			estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
+			
+			/* And we need to read this many bytes... */
+			estate.toread = shdr[symtabindex].sh_size;
+			
+			if (estate.toread)
+			{
+#if ELF_DEBUG
+				printf("db sym, size %lX, curaddr %lX\n", 
+					estate.toread, estate.curaddr);
+#endif
+				/* Save where we are loading this... */
+				symtab_load = estate.curaddr;
+				
+				*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
+				estate.curaddr += sizeof(long);
+				
+				/* Start to read... */
+				return 1;
+			}
+		}
+		else if ((symstr_load == 0) && (symstrindex >= 0))
+		{
+			/* We have already loaded the symbol table, so
+			 * now on to the symbol strings... */
+			
+			
+			/* Same nasty trick as above... */
+			estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
+			
+			/* And we need to read this many bytes... */
+			estate.toread = shdr[symstrindex].sh_size;
+			
+			if (estate.toread)
+			{
+#if ELF_DEBUG
+				printf("db str, size %lX, curaddr %lX\n", 
+					estate.toread, estate.curaddr);
+#endif
+				/* Save where we are loading this... */
+				symstr_load = estate.curaddr;
+				
+				*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
+				estate.curaddr += sizeof(long);
+				
+				/* Start to read... */
+				return 1;
+			}
+		}
+	}
+	/* all done */
+	return 0;
+}
+
+static void elf_freebsd_boot(unsigned long entry) 
+{
+	if (image_type != Elf_FreeBSD)
+		return;
+
+	memset(&bsdinfo, 0, sizeof(bsdinfo));
+	bsdinfo.bi_basemem = meminfo.basememsize;
+	bsdinfo.bi_extmem = meminfo.memsize;
+	bsdinfo.bi_memsizes_valid = 1;
+	bsdinfo.bi_version = BOOTINFO_VERSION;
+	bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
+	bsdinfo.bi_nfs_diskless = NULL;
+	bsdinfo.bi_size = sizeof(bsdinfo);
+#define RB_BOOTINFO     0x80000000      /* have `struct bootinfo *' arg */  
+	if(freebsd_kernel_env[0] != '\0'){
+		freebsd_howto |= RB_BOOTINFO;
+		bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
+	}
+	
+	/* Check if we have symbols loaded, and if so,
+	 * made the meta_data needed to pass those to
+	 * the kernel. */
+	if ((symtab_load !=0) && (symstr_load != 0))
+	{
+		unsigned long *t;
+		
+		bsdinfo.bi_symtab = symtab_load;
+		
+		/* End of symbols (long aligned...) */
+		/* Assumes size of long is a power of 2... */
+		bsdinfo.bi_esymtab = (symstr_load +
+			sizeof(long) +
+			*((long *)phys_to_virt(symstr_load)) +
+			sizeof(long) - 1) & ~(sizeof(long) - 1);
+		
+		/* Where we will build the meta data... */
+		t = phys_to_virt(bsdinfo.bi_esymtab);
+		
+#if ELF_DEBUG
+		printf("Metadata at %lX\n",t);
+#endif
+		
+		/* Set up the pointer to the memory... */
+		bsdinfo.bi_modulep = virt_to_phys(t);
+		
+		/* The metadata structure is an array of 32-bit
+		 * words where we store some information about the
+		 * system.  This is critical, as FreeBSD now looks
+		 * only for the metadata for the extended symbol
+		 * information rather than in the bootinfo.
+		 */
+		/* First, do the kernel name and the kernel type */
+		/* Note that this assumed x86 byte order... */
+		
+		/* 'kernel\0\0' */
+		*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
+		
+		/* 'elf kernel\0\0' */
+		*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
+		
+		/* Now the symbol start/end - note that they are
+		 * here in local/physical address - the Kernel
+		 * boot process will relocate the addresses. */
+		*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
+		*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
+		
+		*t++=MODINFO_END; *t++=0; /* end of metadata */
+		
+		/* Since we have symbols we need to make
+		 * sure that the kernel knows its own end
+		 * of memory...  It is not _end but after
+		 * the symbols and the metadata... */
+		bsdinfo.bi_kernend = virt_to_phys(t);
+		
+		/* Signal locore.s that we have a valid bootinfo
+		 * structure that was completely filled in. */
+		freebsd_howto |= 0x80000000;
+	}
+	
+	xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, 
+		virt_to_phys(&bsdinfo), 0, 0, 0);
+	longjmp(restart_etherboot, -2);
+}
+#endif
+
+#ifdef AOUT_IMAGE
+static void aout_freebsd_probe(void)
+{
+	image_type = Aout;
+	if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
+		/* Some other a.out variants have a different
+		 * value, and use other alignments (e.g. 1K),
+		 * not the 4K used by FreeBSD.  */
+		image_type = Aout_FreeBSD;
+		printf("/FreeBSD");
+		off = -(astate.head.a_entry & 0xff000000);
+		astate.head.a_entry += off;
+	}
+}
+
+static void aout_freebsd_boot(void)
+{
+	if (image_type == Aout_FreeBSD) {
+		memset(&bsdinfo, 0, sizeof(bsdinfo));
+		bsdinfo.bi_basemem = meminfo.basememsize;
+		bsdinfo.bi_extmem = meminfo.memsize;
+		bsdinfo.bi_memsizes_valid = 1;
+		bsdinfo.bi_version = BOOTINFO_VERSION;
+		bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
+		bsdinfo.bi_nfs_diskless = NULL;
+		bsdinfo.bi_size = sizeof(bsdinfo);
+		xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, 
+			virt_to_phys(&bsdinfo), 0, 0, 0);
+		longjmp(restart_etherboot, -2);
+	}
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbidt.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbidt.S
new file mode 100644
index 0000000..cd8b38a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbidt.S
@@ -0,0 +1,215 @@
+/*
+ * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
+ */
+
+#include <librm.h>
+
+#define SIZEOF_I386_REGS	32
+#define SIZEOF_I386_FLAGS	4
+
+/****************************************************************************
+ * Interrupt Descriptor Table
+ ****************************************************************************
+ */
+	.section ".data16", "aw", @progbits
+	.globl idtr
+idtr:
+idt_limit:
+	.word	idt_length - 1
+idt_base:
+	.long	0
+
+/* IDT entries have the following format:
+ * offset_lo, segment selector, flags, offset_hi
+ *
+ * Since it is not possible to specify relocations in arbitrary
+ * expressions like (int_overflow & 0xffff), we initialise the
+ * IDT with entries in an incorrect format.
+ *
+ * The entries are shuffled into the correct format in init_librm().
+ */
+#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0
+#define IDT_ENTRY_PRESENT(name) \
+	.long	int_##name; \
+	.word	0x8e00, VIRTUAL_CS
+
+.align 16
+idt:
+	IDT_ENTRY_PRESENT(divide_error)
+	IDT_ENTRY_PRESENT(debug_trap)
+	IDT_ENTRY_EMPTY(non_maskable_interrupt)
+	IDT_ENTRY_PRESENT(breakpoint)
+	IDT_ENTRY_PRESENT(overflow)
+	IDT_ENTRY_PRESENT(bound_range_exceeded)
+	IDT_ENTRY_PRESENT(invalid_opcode)
+	IDT_ENTRY_EMPTY(device_not_available)
+	IDT_ENTRY_PRESENT(double_fault)
+	IDT_ENTRY_EMPTY(coprocessor_segment_overrun)
+	IDT_ENTRY_PRESENT(invalid_tss)
+	IDT_ENTRY_PRESENT(segment_not_present)
+	IDT_ENTRY_PRESENT(stack_segment_fault)
+	IDT_ENTRY_PRESENT(general_protection)
+	IDT_ENTRY_PRESENT(page_fault)
+idt_end:
+	.equ	idt_length, idt_end - idt
+
+/* The IDT entries are fixed up (once) in init_librm() */
+idt_fixed:
+	.byte	0
+
+/****************************************************************************
+ * idt_init (real-mode near call, 16-bit real-mode near return address)
+ *
+ * Initialise the IDT, called from init_librm.
+ *
+ * Parameters:
+ *   %eax : IDT base address
+ *
+ * Destroys %ax, %bx, and %di.
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl idt_init
+idt_init:
+	movl	%eax, idt_base
+	addl	$idt, idt_base
+
+	/* IDT entries are only fixed up once */
+	movb	idt_fixed, %al
+	orb	%al, %al
+	jnz	2f
+	movb	$1, idt_fixed
+
+	/* Shuffle IDT entries into the correct format */
+	movb	$(idt_length / 8), %al
+	movw	$idt, %bx
+	or	%al, %al
+	jz	2f
+1:
+	movw	2(%bx), %di
+	xchg	%di, 6(%bx)
+	movw	%di, 2(%bx)
+	addw	$8, %bx
+	dec	%al
+	jnz	1b
+2:
+	ret
+
+/****************************************************************************
+ * Interrupt handlers
+ ****************************************************************************
+ */
+	.section ".text", "ax", @progbits
+	.code32
+
+/* POSIX signal numbers for reporting traps to GDB */
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGSEGV 11
+#define SIGSTKFLT 16
+
+int_divide_error:
+	pushl	$SIGFPE
+	jmp	do_interrupt
+
+int_debug_trap:
+int_breakpoint:
+	pushl	$SIGTRAP
+	jmp	do_interrupt
+
+int_overflow:
+int_bound_range_exceeded:
+	pushl	$SIGSTKFLT
+	jmp	do_interrupt
+
+int_invalid_opcode:
+	pushl	$SIGILL
+	jmp	do_interrupt
+
+int_double_fault:
+	movl	$SIGBUS, (%esp)
+	jmp	do_interrupt
+
+int_invalid_tss:
+int_segment_not_present:
+int_stack_segment_fault:
+int_general_protection:
+int_page_fault:
+	movl	$SIGSEGV, (%esp)
+	jmp	do_interrupt
+
+/* When invoked, the stack contains: eflags, cs, eip, signo. */
+#define IH_OFFSET_GDB_REGS ( 0 )
+#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
+#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
+#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
+#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
+#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
+#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
+#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
+#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
+#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )
+
+/* We also access the stack whilst still storing or restoring
+ * the register snapshot.  Since ESP is in flux, we need
+ * special offsets.
+ */
+#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
+#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
+#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
+#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
+do_interrupt:
+	/* Store CPU state in GDB register snapshot */
+	pushw	$0
+	pushw	%gs
+	pushw	$0
+	pushw	%fs
+	pushw	$0
+	pushw	%es
+	pushw	$0
+	pushw	%ds
+	pushw	$0
+	pushw	%ss
+	pushw	$0
+	pushw	IH_OFFSET_FLUX_OLD_CS + 2(%esp)
+	pushl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
+	pushl	IH_OFFSET_FLUX_OLD_EIP(%esp)
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebp
+	leal	IH_OFFSET_FLUX_END(%esp), %edi
+	pushl	%edi /* old ESP */
+	pushl	%ebx
+	pushl	%edx
+	pushl	%ecx
+	pushl	%eax
+
+	/* Call GDB stub exception handler */
+	pushl	%esp
+	pushl	(IH_OFFSET_SIGNO + 4)(%esp)
+	call	gdbmach_handler
+	addl	$8, %esp
+
+	/* Restore CPU state from GDB register snapshot */
+	popl	%eax
+	popl	%ecx
+	popl	%edx
+	popl	%ebx
+	addl	$4, %esp /* Changing ESP currently not supported */
+	popl	%ebp
+	popl	%esi
+	popl	%edi
+	popl	IH_OFFSET_FLUX_OLD_EIP(%esp)
+	popl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
+	popl	IH_OFFSET_FLUX_OLD_CS(%esp)
+	popl	%ss
+	popl	%ds
+	popl	%es
+	popl	%fs
+	popl	%gs
+
+	addl	$4, %esp /* drop signo */
+	iret
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbmach.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbmach.c
new file mode 100644
index 0000000..68b37c0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/gdbmach.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/gdbstub.h>
+#include <gdbmach.h>
+
+/** @file
+ *
+ * GDB architecture-specific bits for i386
+ *
+ */
+
+enum {
+	DR7_CLEAR = 0x00000400,    /* disable hardware breakpoints */
+	DR6_CLEAR = 0xffff0ff0,    /* clear breakpoint status */
+};
+
+/** Hardware breakpoint, fields stored in x86 bit pattern form */
+struct hwbp {
+	int type;           /* type (1=write watchpoint, 3=access watchpoint) */
+	unsigned long addr; /* linear address */
+	size_t len;         /* length (0=1-byte, 1=2-byte, 3=4-byte) */
+	int enabled;
+};
+
+static struct hwbp hwbps [ 4 ];
+static gdbreg_t dr7 = DR7_CLEAR;
+
+static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) {
+	struct hwbp *available = NULL;
+	unsigned int i;
+	for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) {
+		if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) {
+			return &hwbps [ i ];
+		}
+		if ( !hwbps [ i ].enabled ) {
+			available = &hwbps [ i ];
+		}
+	}
+	return available;
+}
+
+static void gdbmach_commit_hwbp ( struct hwbp *bp ) {
+	unsigned int regnum = bp - hwbps;
+
+	/* Set breakpoint address */
+	assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) );
+	switch ( regnum ) {
+		case 0:
+			__asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
+			break;
+		case 1:
+			__asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
+			break;
+		case 2:
+			__asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
+			break;
+		case 3:
+			__asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
+			break;
+	}
+
+	/* Set type */
+	dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
+	dr7 |= bp->type << ( 16 + 4 * regnum );
+
+	/* Set length */
+	dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) );
+	dr7 |= bp->len << ( 18 + 4 * regnum );
+
+	/* Set/clear local enable bit */
+	dr7 &= ~( 0x3 << 2 * regnum );
+ 	dr7 |= bp->enabled << 2 * regnum;
+}
+
+int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) {
+	struct hwbp *bp;
+	
+	/* Check and convert breakpoint type to x86 type */
+	switch ( type ) {
+		case GDBMACH_WATCH:
+			type = 0x1;
+			break;
+		case GDBMACH_AWATCH:
+			type = 0x3;
+			break;
+		default:
+			return 0; /* unsupported breakpoint type */
+	}
+
+	/* Only lengths 1, 2, and 4 are supported */
+	if ( len != 2 && len != 4 ) {
+		len = 1;
+	}
+	len--; /* convert to x86 breakpoint length bit pattern */
+
+	/* Calculate linear address by adding segment base */
+	addr += virt_offset;
+
+	/* Set up the breakpoint */
+	bp = gdbmach_find_hwbp ( type, addr, len );
+	if ( !bp ) {
+		return 0; /* ran out of hardware breakpoints */
+	}
+	bp->type = type;
+	bp->addr = addr;
+	bp->len = len;
+	bp->enabled = enable;
+	gdbmach_commit_hwbp ( bp );
+	return 1;
+}
+
+static void gdbmach_disable_hwbps ( void ) {
+	/* Store and clear hardware breakpoints */
+	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) );
+}
+
+static void gdbmach_enable_hwbps ( void ) {
+	/* Clear breakpoint status register */
+	__asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) );
+
+	/* Restore hardware breakpoints */
+	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
+}
+
+__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
+	gdbmach_disable_hwbps();
+	gdbstub_handler ( signo, regs );
+	gdbmach_enable_hwbps();
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/linux/linux_syscall.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/linux/linux_syscall.S
new file mode 100644
index 0000000..38a3e74
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/linux/linux_syscall.S
@@ -0,0 +1,45 @@
+
+	.section ".data"
+	.globl linux_errno
+
+linux_errno:	.int 0
+
+	.section ".text"
+	.code32
+	.globl linux_syscall
+	.type  linux_syscall, @function
+
+linux_syscall:
+	/* Save registers */
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+
+	movl	20(%esp), %eax  // C arg1 -> syscall number
+	movl	24(%esp), %ebx  // C arg2 -> syscall arg1
+	movl	28(%esp), %ecx  // C arg3 -> syscall arg2
+	movl	32(%esp), %edx  // C arg4 -> syscall arg3
+	movl	36(%esp), %esi  // C arg5 -> syscall arg4
+	movl	40(%esp), %edi  // C arg6 -> syscall arg5
+	movl	44(%esp), %ebp  // C arg7 -> syscall arg6
+
+	int	$0x80
+
+	/* Restore registers */
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+
+	cmpl	$-4095, %eax
+	jae	1f
+	ret
+
+1:
+	negl	%eax
+	movl	%eax, linux_errno
+	movl	$-1, %eax
+	ret
+
+	.size linux_syscall, . - linux_syscall
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/nulltrap.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/nulltrap.c
new file mode 100644
index 0000000..3046fbe
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/nulltrap.c
@@ -0,0 +1,51 @@
+#include <stdint.h>
+#include <stdio.h>
+
+__attribute__ (( noreturn, section ( ".text.null_trap" ) ))
+void null_function_trap ( void ) {
+	void *stack;
+
+	/* 128 bytes of NOPs; the idea of this is that if something
+	 * dereferences a NULL pointer and overwrites us, we at least
+	 * have some chance of still getting to execute the printf()
+	 * statement.
+	 */
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
+
+	__asm__ __volatile__ ( "movl %%esp, %0" : "=r" ( stack ) );
+	printf ( "NULL method called from %p (stack %p)\n", 
+		 __builtin_return_address ( 0 ), stack );
+	DBG_HD ( stack, 256 );
+	while ( 1 ) {}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/patch_cf.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/patch_cf.S
new file mode 100644
index 0000000..97a62f4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/patch_cf.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009 H. Peter Anvin <hpa at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.arch i386
+	.code16
+
+/****************************************************************************
+ * Set/clear CF on the stack as appropriate, assumes stack is as it should
+ * be immediately before IRET
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.globl patch_cf
+patch_cf:
+	pushw	%bp
+	movw	%sp, %bp
+	setc	8(%bp)	/* Set/reset CF; clears PF, AF, ZF, SF */
+	popw	%bp
+	ret
+	.size patch_cf, . - patch_cf
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/pic8259.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/pic8259.c
new file mode 100644
index 0000000..0264c0c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/pic8259.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/io.h>
+#include <pic8259.h>
+
+/** @file
+ *
+ * Minimal support for the 8259 Programmable Interrupt Controller
+ *
+ */
+
+/**
+ * Send non-specific EOI(s)
+ *
+ * @v irq		IRQ number
+ *
+ * This seems to be inherently unsafe.
+ */
+static inline void send_nonspecific_eoi ( unsigned int irq ) {
+	DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
+	if ( irq >= IRQ_PIC_CUTOFF ) {
+		outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
+	}		
+	outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
+}
+
+/**
+ * Send specific EOI(s)
+ *
+ * @v irq		IRQ number
+ */
+static inline void send_specific_eoi ( unsigned int irq ) {
+	DBG ( "Sending specific EOI for IRQ %d\n", irq );
+	if ( irq >= IRQ_PIC_CUTOFF ) {
+		outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( CHAINED_IRQ ) ),
+		       ICR_REG ( CHAINED_IRQ ) );
+	}
+	outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( irq ) ), ICR_REG ( irq ) );
+}
+
+/**
+ * Send End-Of-Interrupt to the PIC
+ *
+ * @v irq		IRQ number
+ */
+void send_eoi ( unsigned int irq ) {
+	send_specific_eoi ( irq );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/rdtsc_timer.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
new file mode 100644
index 0000000..d2a8cc8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#include <assert.h>
+#include <ipxe/timer.h>
+#include <ipxe/timer2.h>
+
+/**
+ * Number of TSC ticks per microsecond
+ *
+ * This is calibrated on the first use of the timer.
+ */
+static unsigned long rdtsc_ticks_per_usec;
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs		Number of microseconds for which to delay
+ */
+static void rdtsc_udelay ( unsigned long usecs ) {
+	unsigned long start;
+	unsigned long elapsed;
+
+	/* Sanity guard, since we may divide by this */
+	if ( ! usecs )
+		usecs = 1;
+
+	start = currticks();
+	if ( rdtsc_ticks_per_usec ) {
+		/* Already calibrated; busy-wait until done */
+		do {
+			elapsed = ( currticks() - start );
+		} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
+	} else {
+		/* Not yet calibrated; use timer2 and calibrate
+		 * based on result.
+		 */
+		timer2_udelay ( usecs );
+		elapsed = ( currticks() - start );
+		rdtsc_ticks_per_usec = ( elapsed / usecs );
+		DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
+		      "(%ld MHz)\n", elapsed, usecs,
+		      ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
+	}
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec	Number of ticks per second
+ */
+static unsigned long rdtsc_ticks_per_sec ( void ) {
+
+	/* Calibrate timer, if not already done */
+	if ( ! rdtsc_ticks_per_usec )
+		udelay ( 1 );
+
+	/* Sanity check */
+	assert ( rdtsc_ticks_per_usec != 0 );
+
+	return ( rdtsc_ticks_per_usec * 1000 * 1000 );
+}
+
+PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
+PROVIDE_TIMER_INLINE ( rdtsc, currticks );
+PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/relocate.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/relocate.c
new file mode 100644
index 0000000..47450e7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/relocate.c
@@ -0,0 +1,129 @@
+#include <ipxe/io.h>
+#include <registers.h>
+
+/*
+ * Originally by Eric Biederman
+ *
+ * Heavily modified by Michael Brown 
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * The linker passes in the symbol _max_align, which is the alignment
+ * that we must preserve, in bytes.
+ *
+ */
+extern char _max_align[];
+#define max_align ( ( unsigned int ) _max_align )
+
+/* Linker symbols */
+extern char _textdata[];
+extern char _etextdata[];
+
+/* within 1MB of 4GB is too close. 
+ * MAX_ADDR is the maximum address we can easily do DMA to.
+ *
+ * Not sure where this constraint comes from, but kept it from Eric's
+ * old code - mcb30
+ */
+#define MAX_ADDR (0xfff00000UL)
+
+/**
+ * Relocate iPXE
+ *
+ * @v ix86		x86 register dump from prefix
+ * @ret ix86		x86 registers to return to prefix
+ *
+ * This finds a suitable location for iPXE near the top of 32-bit
+ * address space, and returns the physical address of the new location
+ * to the prefix in %edi.
+ */
+__asmcall void relocate ( struct i386_all_regs *ix86 ) {
+	struct memory_map memmap;
+	unsigned long start, end, size, padded_size;
+	unsigned long new_start, new_end;
+	unsigned i;
+
+	/* Get memory map and current location */
+	get_memmap ( &memmap );
+	start = virt_to_phys ( _textdata );
+	end = virt_to_phys ( _etextdata );
+	size = ( end - start );
+	padded_size = ( size + max_align - 1 );
+
+	DBG ( "Relocate: currently at [%lx,%lx)\n"
+	      "...need %lx bytes for %d-byte alignment\n",
+	      start, end, padded_size, max_align );
+
+	/* Walk through the memory map and find the highest address
+	 * below 4GB that iPXE will fit into.
+	 */
+	new_end = end;
+	for ( i = 0 ; i < memmap.count ; i++ ) {
+		struct memory_region *region = &memmap.regions[i];
+		unsigned long r_start, r_end;
+
+		DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
+		
+		/* Truncate block to MAX_ADDR.  This will be less than
+		 * 4GB, which means that we can get away with using
+		 * just 32-bit arithmetic after this stage.
+		 */
+		if ( region->start > MAX_ADDR ) {
+			DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
+			continue;
+		}
+		r_start = region->start;
+		if ( region->end > MAX_ADDR ) {
+			DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
+			r_end = MAX_ADDR;
+		} else {
+			r_end = region->end;
+		}
+		DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
+
+		/* If we have rounded down r_end below r_ start, skip
+		 * this block.
+		 */
+		if ( r_end < r_start ) {
+			DBG ( "...truncated to negative size\n" );
+			continue;
+		}
+
+		/* Check that there is enough space to fit in iPXE */
+		if ( ( r_end - r_start ) < size ) {
+			DBG ( "...too small (need %lx bytes)\n", size );
+			continue;
+		}
+
+		/* If the start address of the iPXE we would
+		 * place in this block is higher than the end address
+		 * of the current highest block, use this block.
+		 *
+		 * Note that this avoids overlaps with the current
+		 * iPXE, as well as choosing the highest of all viable
+		 * blocks.
+		 */
+		if ( ( r_end - size ) > new_end ) {
+			new_end = r_end;
+			DBG ( "...new best block found.\n" );
+		}
+	}
+
+	/* Calculate new location of iPXE, and align it to the
+	 * required alignemnt.
+	 */
+	new_start = new_end - padded_size;
+	new_start += ( start - new_start ) & ( max_align - 1 );
+	new_end = new_start + size;
+
+	DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
+	      start, end, new_start, new_end );
+	
+	/* Let prefix know what to copy */
+	ix86->regs.esi = start;
+	ix86->regs.edi = new_start;
+	ix86->regs.ecx = size;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/setjmp.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/setjmp.S
new file mode 100644
index 0000000..0372714
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/setjmp.S
@@ -0,0 +1,42 @@
+/* setjmp and longjmp. Use of these functions is deprecated. */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.arch i386
+	.code32
+	
+/**************************************************************************
+SETJMP - Save stack context for non-local goto
+**************************************************************************/
+	.globl	setjmp
+setjmp:
+	movl	4(%esp),%ecx		/* jmpbuf */
+	movl	0(%esp),%edx		/* return address */
+	movl	%edx,0(%ecx)
+	movl	%ebx,4(%ecx)
+	movl	%esp,8(%ecx)
+	movl	%ebp,12(%ecx)
+	movl	%esi,16(%ecx)
+	movl	%edi,20(%ecx)
+	movl	$0,%eax
+	ret
+
+/**************************************************************************
+LONGJMP - Non-local jump to a saved stack context
+**************************************************************************/
+	.globl	longjmp
+longjmp:
+	movl	4(%esp),%edx		/* jumpbuf */
+	movl	8(%esp),%eax		/* result */
+	movl	0(%edx),%ecx
+	movl	4(%edx),%ebx
+	movl	8(%edx),%esp
+	movl	12(%edx),%ebp
+	movl	16(%edx),%esi
+	movl	20(%edx),%edi
+	cmpl	$0,%eax
+	jne	1f
+	movl	$1,%eax
+1:	movl	%ecx,0(%esp)
+	ret
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack.S
new file mode 100644
index 0000000..737ec0e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack.S
@@ -0,0 +1,15 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.arch i386
+
+/****************************************************************************
+ * Internal stack
+ ****************************************************************************
+ */
+	.section ".stack", "aw", @nobits
+	.align 8
+	.globl _stack
+_stack:
+	.space 4096
+	.globl _estack
+_estack:
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack16.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack16.S
new file mode 100644
index 0000000..523f028
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/stack16.S
@@ -0,0 +1,15 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.arch i386
+
+/****************************************************************************
+ * Internal stack
+ ****************************************************************************
+ */
+	.section ".stack16", "aw", @nobits
+	.align 8
+	.globl _stack16
+_stack16:
+	.space 4096
+	.globl _estack16
+_estack16:
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/timer2.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/timer2.c
new file mode 100644
index 0000000..0778665
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/timer2.c
@@ -0,0 +1,87 @@
+/*
+ * arch/i386/core/i386_timer.c
+ *
+ * Use the "System Timer 2" to implement the udelay callback in
+ * the BIOS timer driver. Also used to calibrate the clock rate
+ * in the RTDSC timer driver.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <ipxe/timer2.h>
+#include <ipxe/io.h>
+
+/* Timers tick over at this rate */
+#define TIMER2_TICKS_PER_SEC	1193180U
+
+/* Parallel Peripheral Controller Port B */
+#define	PPC_PORTB	0x61
+
+/* Meaning of the port bits */
+#define	PPCB_T2OUT	0x20	/* Bit 5 */
+#define	PPCB_SPKR	0x02	/* Bit 1 */
+#define	PPCB_T2GATE	0x01	/* Bit 0 */
+
+/* Ports for the 8254 timer chip */
+#define	TIMER2_PORT	0x42
+#define	TIMER_MODE_PORT	0x43
+
+/* Meaning of the mode bits */
+#define	TIMER0_SEL	0x00
+#define	TIMER1_SEL	0x40
+#define	TIMER2_SEL	0x80
+#define	READBACK_SEL	0xC0
+
+#define	LATCH_COUNT	0x00
+#define	LOBYTE_ACCESS	0x10
+#define	HIBYTE_ACCESS	0x20
+#define	WORD_ACCESS	0x30
+
+#define	MODE0		0x00
+#define	MODE1		0x02
+#define	MODE2		0x04
+#define	MODE3		0x06
+#define	MODE4		0x08
+#define	MODE5		0x0A
+
+#define	BINARY_COUNT	0x00
+#define	BCD_COUNT	0x01
+
+static void load_timer2 ( unsigned int ticks ) {
+	/*
+	 * Now let's take care of PPC channel 2
+	 *
+	 * Set the Gate high, program PPC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 *
+	 * Note some implementations have a bug where the high bits byte
+	 * of channel 2 is ignored.
+	 */
+	/* Set up the timer gate, turn off the speaker */
+	/* Set the Gate high, disable speaker */
+	outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
+	/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
+	/* LSB of ticks */
+	outb(ticks & 0xFF, TIMER2_PORT);
+	/* MSB of ticks */
+	outb(ticks >> 8, TIMER2_PORT);
+}
+
+static int timer2_running ( void ) {
+	return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
+}
+
+void timer2_udelay ( unsigned long usecs ) {
+	load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
+	while (timer2_running()) {
+		/* Do nothing */
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/video_subr.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/video_subr.c
new file mode 100644
index 0000000..6885ad9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/video_subr.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * modified from linuxbios code
+ * by Cai Qiang <rimy2000 at hotmail.com>
+ *
+ */
+
+#include "stddef.h"
+#include "string.h"
+#include <ipxe/io.h>
+#include <ipxe/console.h>
+#include <ipxe/init.h>
+#include "vga.h"
+
+struct console_driver vga_console __console_driver;
+
+static char *vidmem;		/* The video buffer */
+static int video_line, video_col;
+
+#define VIDBUFFER 0xB8000	
+
+static void memsetw(void *s, int c, unsigned int n)
+{
+	unsigned int i;
+	u16 *ss = (u16 *) s;
+
+	for (i = 0; i < n; i++) {
+		ss[i] = ( u16 ) c;
+	}
+}
+
+static void video_init(void)
+{
+	static int inited=0;
+
+	vidmem = (char *)phys_to_virt(VIDBUFFER);
+
+	if (!inited) {
+		video_line = 0;
+		video_col = 0;
+	
+	 	memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
+
+		inited=1;
+	}
+}
+
+static void video_scroll(void)
+{
+	int i;
+
+	memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
+	for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
+		vidmem[i] = ' ';
+}
+
+static void vga_putc(int byte)
+{
+	if (byte == '\n') {
+		video_line++;
+		video_col = 0;
+
+	} else if (byte == '\r') {
+		video_col = 0;
+
+	} else if (byte == '\b') {
+		video_col--;
+
+	} else if (byte == '\t') {
+		video_col += 4;
+
+	} else if (byte == '\a') {
+		//beep
+		//beep(500);
+
+	} else {
+		vidmem[((video_col + (video_line *COLS)) * 2)] = byte;
+		vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
+		video_col++;
+	}
+	if (video_col < 0) {
+		video_col = 0;
+	}
+	if (video_col >= COLS) {
+		video_line++;
+		video_col = 0;
+	}
+	if (video_line >= LINES) {
+		video_scroll();
+		video_line--;
+	}
+	// move the cursor
+	write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI);
+	write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
+}
+
+struct console_driver vga_console __console_driver = {
+	.putchar = vga_putc,
+	.disabled = 1,
+};
+
+struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
+	.initialise = video_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/virtaddr.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/virtaddr.S
new file mode 100644
index 0000000..aae1e1e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/virtaddr.S
@@ -0,0 +1,103 @@
+/*
+ * Functions to support the virtual addressing method of relocation
+ * that Etherboot uses.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#include "librm.h"
+		
+	.arch i386
+	.text
+	.code32
+	
+/****************************************************************************
+ * _virt_to_phys (virtual addressing)
+ *
+ * Switch from virtual to flat physical addresses.  %esp is adjusted
+ * to a physical value.  Segment registers are set to flat physical
+ * selectors.  All other registers are preserved.  Flags are
+ * preserved.
+ *
+ * Parameters: none
+ * Returns: none
+ ****************************************************************************
+ */
+	.globl _virt_to_phys
+_virt_to_phys:
+	/* Preserve registers and flags */
+	pushfl
+	pushl	%eax
+	pushl	%ebp
+
+	/* Change return address to a physical address */
+	movl	virt_offset, %ebp
+	addl	%ebp, 12(%esp)
+
+	/* Switch to physical code segment */
+	pushl	$PHYSICAL_CS
+	leal	1f(%ebp), %eax
+	pushl	%eax
+	lret
+1:
+	/* Reload other segment registers and adjust %esp */
+	movl	$PHYSICAL_DS, %eax
+	movl	%eax, %ds
+	movl	%eax, %es	
+	movl	%eax, %fs	
+	movl	%eax, %gs
+	movl	%eax, %ss	
+	addl	%ebp, %esp
+
+	/* Restore registers and flags, and return */
+	popl	%ebp
+	popl	%eax
+	popfl
+	ret
+
+/****************************************************************************
+ * _phys_to_virt (flat physical addressing)
+ *
+ * Switch from flat physical to virtual addresses.  %esp is adjusted
+ * to a virtual value.  Segment registers are set to virtual
+ * selectors.  All other registers are preserved.  Flags are
+ * preserved.
+ *
+ * Note that this depends on the GDT already being correctly set up
+ * (e.g. by a call to run_here()).
+ *
+ * Parameters: none
+ * Returns: none
+ ****************************************************************************
+ */
+	.globl _phys_to_virt
+_phys_to_virt:
+	/* Preserve registers and flags */
+	pushfl
+	pushl	%eax
+	pushl	%ebp
+
+	/* Switch to virtual code segment */
+	ljmp	$VIRTUAL_CS, $1f
+1:	
+	/* Reload data segment registers */
+	movl	$VIRTUAL_DS, %eax
+	movl	%eax, %ds
+	movl	%eax, %es	
+	movl	%eax, %fs	
+	movl	%eax, %gs
+
+	/* Reload stack segment and adjust %esp */
+	movl	virt_offset, %ebp
+	movl	%eax, %ss	
+	subl	%ebp, %esp
+
+	/* Change the return address to a virtual address */
+	subl	%ebp, 12(%esp)
+
+	/* Restore registers and flags, and return */
+	popl	%ebp
+	popl	%eax
+	popfl
+	ret
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/wince_loader.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/wince_loader.c
new file mode 100644
index 0000000..f452b65
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/wince_loader.c
@@ -0,0 +1,273 @@
+#define LOAD_DEBUG	0
+
+static int get_x_header(unsigned char *data, unsigned long now);
+static void jump_2ep();
+static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
+static char ** ep;
+
+#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
+
+typedef struct _BOOT_ARGS{
+	unsigned char ucVideoMode;
+	unsigned char ucComPort;
+	unsigned char ucBaudDivisor;
+	unsigned char ucPCIConfigType;
+	
+	unsigned long dwSig;
+	#define BOOTARG_SIG 0x544F4F42
+	unsigned long dwLen;
+	
+	unsigned char ucLoaderFlags;
+	unsigned char ucEshellFlags;
+	unsigned char ucEdbgAdapterType;
+	unsigned char ucEdbgIRQ;
+	
+	unsigned long dwEdbgBaseAddr;
+	unsigned long dwEdbgDebugZone;	
+	unsigned long dwDHCPLeaseTime;
+	unsigned long dwEdbgFlags;
+	
+	unsigned long dwEBootFlag;
+	unsigned long dwEBootAddr;
+	unsigned long dwLaunchAddr;
+	
+	unsigned long pvFlatFrameBuffer;
+	unsigned short vesaMode;
+	unsigned short cxDisplayScreen;
+	unsigned short cyDisplayScreen;
+	unsigned short cxPhysicalScreen;
+	unsigned short cyPhysicalScreen;
+	unsigned short cbScanLineLength;
+	unsigned short bppScreen;
+	
+	unsigned char RedMaskSize;
+	unsigned char REdMaskPosition;
+	unsigned char GreenMaskSize;
+	unsigned char GreenMaskPosition;
+	unsigned char BlueMaskSize;
+	unsigned char BlueMaskPosition;
+} BOOT_ARGS;
+
+BOOT_ARGS BootArgs;
+
+static struct segment_info{
+	unsigned long addr;		// Section Address
+	unsigned long size;		// Section Size
+	unsigned long checksum;		// Section CheckSum
+} X;
+
+#define PSIZE	(1500)			//Max Packet Size
+#define DSIZE  (PSIZE+12)
+static unsigned long dbuffer_available =0;
+static unsigned long not_loadin =0;
+static unsigned long d_now =0;
+
+unsigned long entry;
+static unsigned long ce_curaddr;
+
+
+static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
+static os_download_t wince_probe(unsigned char *data, unsigned int len)
+{
+	if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
+		return 0;
+	}
+	printf("(WINCE)");
+	return ce_loader;
+}
+
+static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
+{
+	static unsigned char dbuffer[DSIZE];
+	int this_write = 0;
+	static int firsttime = 1;
+
+	/*
+	 *	new packet in, we have to 
+	 *	[1] copy data to dbuffer,
+	 *
+	 *	update...
+	 *	[2]  dbuffer_available
+	 */
+	memcpy( (dbuffer+dbuffer_available), data, len);	//[1]
+	dbuffer_available += len;	// [2]
+	len = 0;
+
+	d_now = 0;
+	
+#if 0
+	printf("dbuffer_available =%ld \n", dbuffer_available);
+#endif 
+	
+	if (firsttime) 
+	{
+		d_now = sizeof(ce_signature);
+		printf("String Physical Address = %lx \n", 
+			*(unsigned long *)(dbuffer+d_now));
+		
+		d_now += sizeof(unsigned long);
+		printf("Image Size = %ld [%lx]\n", 
+			*(unsigned long *)(dbuffer+d_now), 
+			*(unsigned long *)(dbuffer+d_now));
+		
+		d_now += sizeof(unsigned long);
+		dbuffer_available -= d_now;			
+		
+		d_now = (unsigned long)get_x_header(dbuffer, d_now);
+		firsttime = 0;
+	}
+	
+	if (not_loadin == 0)
+	{
+		d_now = get_x_header(dbuffer, d_now);
+	}
+	
+	while ( not_loadin > 0 )
+	{
+		/* dbuffer do not have enough data to loading, copy all */
+#if LOAD_DEBUG
+		printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
+			not_loadin, dbuffer_available);
+		printf("[0] d_now = [%ld] \n", d_now);
+#endif
+		
+		if( dbuffer_available <= not_loadin)
+		{
+			this_write = dbuffer_available ;
+			memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
+			ce_curaddr += this_write;
+			not_loadin -= this_write;
+			
+			/* reset index and available in the dbuffer */
+			dbuffer_available = 0;
+			d_now = 0;
+#if LOAD_DEBUG
+			printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
+				not_loadin, dbuffer_available);
+			printf("[1] d_now = [%ld], this_write = [%d] \n", 
+				d_now, this_write);
+#endif
+				
+			// get the next packet...
+			return (0);
+		}
+			
+		/* dbuffer have more data then loading ... , copy partital.... */
+		else
+		{
+			this_write = not_loadin;
+			memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
+			ce_curaddr += this_write;
+			not_loadin = 0;
+			
+			/* reset index and available in the dbuffer */
+			dbuffer_available -= this_write;
+			d_now += this_write;
+#if LOAD_DEBUG
+			printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
+				not_loadin, dbuffer_available);
+			printf("[2] d_now = [%ld], this_write = [%d] \n\n", 
+				d_now, this_write);
+#endif
+			
+			/* dbuffer not empty, proceed processing... */
+			
+			// don't have enough data to get_x_header..
+			if ( dbuffer_available < (sizeof(unsigned long) * 3) )
+			{
+//				printf("we don't have enough data remaining to call get_x. \n");
+				memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
+				return (0);
+			}
+			else
+			{
+#if LOAD_DEBUG				
+				printf("with remaining data to call get_x \n");
+				printf("dbuffer available = %ld , d_now = %ld\n", 
+					dbuffer_available, d_now);
+#endif					
+				d_now = get_x_header(dbuffer, d_now);
+			}
+		}
+	}
+	return (0);
+}
+
+static int get_x_header(unsigned char *dbuffer, unsigned long now)
+{
+	X.addr = *(unsigned long *)(dbuffer + now);
+	X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
+	X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
+
+	if (X.addr == 0)
+	{
+		entry = X.size;
+		done(1);
+		printf("Entry Point Address = [%lx] \n", entry);
+		jump_2ep();		
+	}
+
+	if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
+		longjmp(restart_etherboot, -2);
+	}
+
+	ce_curaddr = X.addr;
+	now += sizeof(unsigned long)*3;
+
+	/* re-calculate dbuffer available... */
+	dbuffer_available -= sizeof(unsigned long)*3;
+
+	/* reset index of this section */
+	not_loadin = X.size;
+	
+#if 1
+	printf("\n");
+	printf("\t Section Address = [%lx] \n", X.addr);
+	printf("\t Size = %d [%lx]\n", X.size, X.size);
+	printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
+#endif
+#if LOAD_DEBUG
+	printf("____________________________________________\n");
+	printf("\t dbuffer_now = %ld \n", now);
+	printf("\t dbuffer available = %ld \n", dbuffer_available);
+	printf("\t not_loadin = %ld \n", not_loadin);
+#endif
+
+	return now;
+}
+
+static void jump_2ep()
+{
+	BootArgs.ucVideoMode = 1;
+	BootArgs.ucComPort = 1;
+	BootArgs.ucBaudDivisor = 1;
+	BootArgs.ucPCIConfigType = 1;	// do not fill with 0
+	
+	BootArgs.dwSig = BOOTARG_SIG;
+	BootArgs.dwLen = sizeof(BootArgs);
+	
+	if(BootArgs.ucVideoMode == 0)
+	{
+		BootArgs.cxDisplayScreen = 640;
+		BootArgs.cyDisplayScreen = 480;
+		BootArgs.cxPhysicalScreen = 640;
+		BootArgs.cyPhysicalScreen = 480;
+		BootArgs.bppScreen = 16;
+		BootArgs.cbScanLineLength  = 1024;
+		BootArgs.pvFlatFrameBuffer = 0x800a0000;	// ollie say 0x98000000
+	}	
+	else if(BootArgs.ucVideoMode != 0xFF)
+	{
+		BootArgs.cxDisplayScreen = 0;
+		BootArgs.cyDisplayScreen = 0;
+		BootArgs.cxPhysicalScreen = 0;
+		BootArgs.cyPhysicalScreen = 0;
+		BootArgs.bppScreen = 0;
+		BootArgs.cbScanLineLength  = 0;
+		BootArgs.pvFlatFrameBuffer = 0;	
+	}
+
+	ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
+	*ep= virt_to_phys(&BootArgs);
+	xstart32(entry);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/core/x86_io.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/x86_io.c
new file mode 100644
index 0000000..2fba068
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/core/x86_io.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/io.h>
+#include <ipxe/x86_io.h>
+
+/** @file
+ *
+ * iPXE I/O API for x86
+ *
+ */
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ *
+ * This routine uses MMX instructions.
+ */
+static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
+	uint64_t data;
+        __asm__ __volatile__ ( "pushl %%edx\n\t"
+			       "pushl %%eax\n\t"
+			       "movq (%1), %%mm0\n\t"
+			       "movq %%mm0, (%%esp)\n\t"
+			       "popl %%eax\n\t"
+			       "popl %%edx\n\t"
+			       "emms\n\t"
+                               : "=A" ( data ) : "r" ( io_addr ) );
+	return data;
+}
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ *
+ * This routine uses MMX instructions.
+ */
+static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
+	__asm__ __volatile__ ( "pushl %%edx\n\t"
+			       "pushl %%eax\n\t"
+			       "movq (%%esp), %%mm0\n\t"
+			       "movq %%mm0, (%1)\n\t"
+			       "popl %%eax\n\t"
+			       "popl %%edx\n\t"
+			       "emms\n\t"
+			       : : "A" ( data ), "r" ( io_addr ) );
+}
+
+PROVIDE_IOAPI_INLINE ( x86, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( x86, ioremap );
+PROVIDE_IOAPI_INLINE ( x86, iounmap );
+PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, readb );
+PROVIDE_IOAPI_INLINE ( x86, readw );
+PROVIDE_IOAPI_INLINE ( x86, readl );
+PROVIDE_IOAPI ( x86, readq, x86_readq );
+PROVIDE_IOAPI_INLINE ( x86, writeb );
+PROVIDE_IOAPI_INLINE ( x86, writew );
+PROVIDE_IOAPI_INLINE ( x86, writel );
+PROVIDE_IOAPI ( x86, writeq, x86_writeq );
+PROVIDE_IOAPI_INLINE ( x86, inb );
+PROVIDE_IOAPI_INLINE ( x86, inw );
+PROVIDE_IOAPI_INLINE ( x86, inl );
+PROVIDE_IOAPI_INLINE ( x86, outb );
+PROVIDE_IOAPI_INLINE ( x86, outw );
+PROVIDE_IOAPI_INLINE ( x86, outl );
+PROVIDE_IOAPI_INLINE ( x86, insb );
+PROVIDE_IOAPI_INLINE ( x86, insw );
+PROVIDE_IOAPI_INLINE ( x86, insl );
+PROVIDE_IOAPI_INLINE ( x86, outsb );
+PROVIDE_IOAPI_INLINE ( x86, outsw );
+PROVIDE_IOAPI_INLINE ( x86, outsl );
+PROVIDE_IOAPI_INLINE ( x86, iodelay );
+PROVIDE_IOAPI_INLINE ( x86, mb );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undi.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undi.c
new file mode 100644
index 0000000..34fd095
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undi.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/pci.h>
+#include <undi.h>
+#include <undirom.h>
+#include <undiload.h>
+#include <undinet.h>
+#include <undipreload.h>
+
+/** @file
+ *
+ * UNDI PCI driver
+ *
+ */
+
+/**
+ * Find UNDI ROM for PCI device
+ *
+ * @v pci		PCI device
+ * @ret undirom		UNDI ROM, or NULL
+ *
+ * Try to find a driver for this device.  Try an exact match on the
+ * ROM address first, then fall back to a vendor/device ID match only
+ */
+static struct undi_rom * undipci_find_rom ( struct pci_device *pci ) {
+	struct undi_rom *undirom;
+	unsigned long rombase;
+	
+	rombase = pci_bar_start ( pci, PCI_ROM_ADDRESS );
+	undirom = undirom_find_pci ( pci->vendor, pci->device, rombase );
+	if ( ! undirom )
+		undirom = undirom_find_pci ( pci->vendor, pci->device, 0 );
+	return undirom;
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int undipci_probe ( struct pci_device *pci ) {
+	struct undi_device *undi;
+	struct undi_rom *undirom;
+	int rc;
+
+	/* Ignore non-network devices */
+	if ( PCI_BASE_CLASS ( pci->class ) != PCI_BASE_CLASS_NETWORK )
+		return -ENOTTY;
+
+	/* Allocate UNDI device structure */
+	undi = zalloc ( sizeof ( *undi ) );
+	if ( ! undi )
+		return -ENOMEM;
+	pci_set_drvdata ( pci, undi );
+
+	/* Find/create our pixie */
+	if ( preloaded_undi.pci_busdevfn == pci->busdevfn ) {
+		/* Claim preloaded UNDI device */
+		DBGC ( undi, "UNDI %p using preloaded UNDI device\n", undi );
+		memcpy ( undi, &preloaded_undi, sizeof ( *undi ) );
+		memset ( &preloaded_undi, 0, sizeof ( preloaded_undi ) );
+	} else {
+		/* Find UNDI ROM for PCI device */
+		if ( ! ( undirom = undipci_find_rom ( pci ) ) ) {
+			rc = -ENODEV;
+			goto err_find_rom;
+		}
+
+		/* Call UNDI ROM loader to create pixie */
+		if ( ( rc = undi_load_pci ( undi, undirom,
+					    pci->busdevfn ) ) != 0 ) {
+			goto err_load_pci;
+		}
+	}
+
+	/* Add to device hierarchy */
+	snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
+		   "UNDI-%s", pci->dev.name );
+	memcpy ( &undi->dev.desc, &pci->dev.desc, sizeof ( undi->dev.desc ) );
+	undi->dev.parent = &pci->dev;
+	INIT_LIST_HEAD ( &undi->dev.children );
+	list_add ( &undi->dev.siblings, &pci->dev.children );
+
+	/* Create network device */
+	if ( ( rc = undinet_probe ( undi ) ) != 0 )
+		goto err_undinet_probe;
+	
+	return 0;
+
+ err_undinet_probe:
+	undi_unload ( undi );
+	list_del ( &undi->dev.siblings );
+ err_find_rom:
+ err_load_pci:
+	free ( undi );
+	pci_set_drvdata ( pci, NULL );
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci	PCI device
+ */
+static void undipci_remove ( struct pci_device *pci ) {
+	struct undi_device *undi = pci_get_drvdata ( pci );
+
+	undinet_remove ( undi );
+	undi_unload ( undi );
+	list_del ( &undi->dev.siblings );
+	free ( undi );
+	pci_set_drvdata ( pci, NULL );
+}
+
+static struct pci_device_id undipci_nics[] = {
+PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
+};
+
+struct pci_driver undipci_driver __pci_driver = {
+	.ids = undipci_nics,
+	.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
+	.probe = undipci_probe,
+	.remove = undipci_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiisr.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiisr.S
new file mode 100644
index 0000000..b27effe
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiisr.S
@@ -0,0 +1,87 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define PXENV_UNDI_ISR 0x0014
+#define PXENV_UNDI_ISR_IN_START 1
+#define PXENV_UNDI_ISR_OUT_OURS 0
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1
+
+#define IRQ_PIC_CUTOFF 8
+#define ICR_EOI_NON_SPECIFIC 0x20
+#define PIC1_ICR 0x20
+#define PIC2_ICR 0xa0
+	
+	.text
+	.arch i386
+	.code16
+
+	.section ".text16", "ax", @progbits
+	.globl undiisr
+undiisr:
+	
+	/* Preserve registers */
+	pushw	%ds
+	pushw	%es
+	pushw	%fs
+	pushw	%gs
+	pushfl
+	pushal
+
+	/* Set up our segment registers */
+	movw	%cs:rm_ds, %ax
+	movw	%ax, %ds
+
+	/* Check that we have an UNDI entry point */
+	cmpw	$0, pxeparent_entry_point
+	je	chain
+	
+	/* Issue UNDI API call */
+	movw	%ax, %es
+	movw	$undinet_params, %di
+	movw	$PXENV_UNDI_ISR, %bx
+	movw	$PXENV_UNDI_ISR_IN_START, funcflag
+	pushw	%es
+	pushw	%di
+	pushw	%bx
+	lcall	*pxeparent_entry_point
+	cli	/* Just in case */
+	addw	$6, %sp
+	cmpw	$PXENV_UNDI_ISR_OUT_OURS, funcflag
+	jne	eoi
+	
+trig:	/* Record interrupt occurence */
+	incb	undiisr_trigger_count
+
+eoi:	/* Send EOI */
+	movb	$ICR_EOI_NON_SPECIFIC, %al
+	cmpb	$IRQ_PIC_CUTOFF, undiisr_irq
+	jb	1f
+	outb	%al, $PIC2_ICR
+1:	outb	%al, $PIC1_ICR
+	jmp	exit
+	
+chain:	/* Chain to next handler */
+	pushfw
+	lcall	*undiisr_next_handler
+	
+exit:	/* Restore registers and return */
+	cli
+	popal
+	movzwl	%sp, %esp
+	addr32	movl -20(%esp), %esp	/* %esp isn't restored by popal */
+	popfl
+	popw	%gs
+	popw	%fs
+	popw	%es
+	popw	%ds
+	iret
+
+	.section ".data16", "aw", @progbits
+undinet_params:
+status:			.word	0
+funcflag:		.word	0
+bufferlength:		.word	0
+framelength:		.word	0
+frameheaderlength:	.word	0
+frame:			.word	0, 0
+prottype:		.byte	0
+pkttype:		.byte	0
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiload.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiload.c
new file mode 100644
index 0000000..c278db7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undiload.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pxe.h>
+#include <realmode.h>
+#include <bios.h>
+#include <pnpbios.h>
+#include <basemem.h>
+#include <ipxe/pci.h>
+#include <undi.h>
+#include <undirom.h>
+#include <undiload.h>
+
+/** @file
+ *
+ * UNDI load/unload
+ *
+ */
+
+/** Parameter block for calling UNDI loader */
+static struct s_UNDI_LOADER __bss16 ( undi_loader );
+#define undi_loader __use_data16 ( undi_loader )
+
+/** UNDI loader entry point */
+static SEGOFF16_t __bss16 ( undi_loader_entry );
+#define undi_loader_entry __use_data16 ( undi_loader_entry )
+
+/**
+ * Call UNDI loader to create a pixie
+ *
+ * @v undi		UNDI device
+ * @v undirom		UNDI ROM
+ * @ret rc		Return status code
+ */
+int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
+	struct s_PXE ppxe;
+	unsigned int fbms_seg;
+	uint16_t exit;
+	int rc;
+
+	/* Only one UNDI instance may be loaded at any given time */
+	if ( undi_loader_entry.segment ) {
+		DBG ( "UNDI %p cannot load multiple instances\n", undi );
+		return -EBUSY;
+	}
+
+	/* Set up START_UNDI parameters */
+	memset ( &undi_loader, 0, sizeof ( undi_loader ) );
+	undi_loader.AX = undi->pci_busdevfn;
+	undi_loader.BX = undi->isapnp_csn;
+	undi_loader.DX = undi->isapnp_read_port;
+	undi_loader.ES = BIOS_SEG;
+	undi_loader.DI = find_pnp_bios();
+
+	/* Allocate base memory for PXE stack */
+	undi->restore_fbms = get_fbms();
+	fbms_seg = ( undi->restore_fbms << 6 );
+	fbms_seg -= ( ( undirom->code_size + 0x0f ) >> 4 );
+	undi_loader.UNDI_CS = fbms_seg;
+	fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 );
+	undi_loader.UNDI_DS = fbms_seg;
+
+	/* Debug info */
+	DBGC ( undi, "UNDI %p loading UNDI ROM %p to CS %04x DS %04x for ",
+	       undi, undirom, undi_loader.UNDI_CS, undi_loader.UNDI_DS );
+	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
+		unsigned int bus = ( undi->pci_busdevfn >> 8 );
+		unsigned int devfn = ( undi->pci_busdevfn & 0xff );
+		DBGC ( undi, "PCI %02x:%02x.%x\n",
+		       bus, PCI_SLOT ( devfn ), PCI_FUNC ( devfn ) );
+	}
+	if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
+		DBGC ( undi, "ISAPnP(%04x) CSN %04x\n",
+		       undi->isapnp_read_port, undi->isapnp_csn );
+	}
+
+	/* Call loader */
+	undi_loader_entry = undirom->loader_entry;
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t"
+					   "pushw %%ax\n\t"
+					   "lcall *undi_loader_entry\n\t"
+					   "addw $4, %%sp\n\t" )
+			       : "=a" ( exit )
+			       : "a" ( __from_data16 ( &undi_loader ) )
+			       : "ebx", "ecx", "edx", "esi", "edi", "ebp" );
+
+	if ( exit != PXENV_EXIT_SUCCESS ) {
+		/* Clear entry point */
+		memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
+
+		rc = -undi_loader.Status;
+		if ( rc == 0 ) /* Paranoia */
+			rc = -EIO;
+		DBGC ( undi, "UNDI %p loader failed: %s\n",
+		       undi, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Populate PXE device structure */
+	undi->pxenv = undi_loader.PXENVptr;
+	undi->ppxe = undi_loader.PXEptr;
+	copy_from_real ( &ppxe, undi->ppxe.segment, undi->ppxe.offset,
+			 sizeof ( ppxe ) );
+	undi->entry = ppxe.EntryPointSP;
+	DBGC ( undi, "UNDI %p loaded PXENV+ %04x:%04x !PXE %04x:%04x "
+	       "entry %04x:%04x\n", undi, undi->pxenv.segment,
+	       undi->pxenv.offset, undi->ppxe.segment, undi->ppxe.offset,
+	       undi->entry.segment, undi->entry.offset );
+
+	/* Update free base memory counter */
+	undi->fbms = ( fbms_seg >> 6 );
+	set_fbms ( undi->fbms );
+	DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n",
+	       undi, undi->fbms, undi->restore_fbms );
+
+	return 0;
+}
+
+/**
+ * Unload a pixie
+ *
+ * @v undi		UNDI device
+ * @ret rc		Return status code
+ *
+ * Erases the PXENV+ and !PXE signatures, and frees the used base
+ * memory (if possible).
+ */
+int undi_unload ( struct undi_device *undi ) {
+	static uint32_t dead = 0xdeaddead;
+
+	DBGC ( undi, "UNDI %p unloading\n", undi );
+
+	/* Clear entry point */
+	memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
+
+	/* Erase signatures */
+	if ( undi->pxenv.segment )
+		put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );
+	if ( undi->ppxe.segment )
+		put_real ( dead, undi->ppxe.segment, undi->ppxe.offset );
+
+	/* Free base memory, if possible */
+	if ( undi->fbms == get_fbms() ) {
+		DBGC ( undi, "UNDI %p freeing [%d,%d) kB of base memory\n",
+		       undi, undi->fbms, undi->restore_fbms );
+		set_fbms ( undi->restore_fbms );
+		return 0;
+	} else {
+		DBGC ( undi, "UNDI %p leaking [%d,%d) kB of base memory\n",
+		       undi, undi->fbms, undi->restore_fbms );
+		return -EBUSY;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undinet.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undinet.c
new file mode 100644
index 0000000..56bd628
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undinet.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <pxe.h>
+#include <realmode.h>
+#include <pic8259.h>
+#include <biosint.h>
+#include <pnpbios.h>
+#include <basemem_packet.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <undi.h>
+#include <undinet.h>
+#include <pxeparent.h>
+
+
+/** @file
+ *
+ * UNDI network device driver
+ *
+ */
+
+/** An UNDI NIC */
+struct undi_nic {
+	/** Device supports IRQs */
+	int irq_supported;
+	/** Assigned IRQ number */
+	unsigned int irq;
+	/** Currently processing ISR */
+	int isr_processing;
+	/** Bug workarounds */
+	int hacks;
+};
+
+/**
+ * @defgroup undi_hacks UNDI workarounds
+ * @{
+ */
+
+/** Work around Etherboot 5.4 bugs */
+#define UNDI_HACK_EB54		0x0001
+
+/** @} */
+
+static void undinet_close ( struct net_device *netdev );
+
+/** Address of UNDI entry point */
+static SEGOFF16_t undinet_entry;
+
+/*****************************************************************************
+ *
+ * UNDI interrupt service routine
+ *
+ *****************************************************************************
+ */
+
+/**
+ * UNDI interrupt service routine
+ *
+ * The UNDI ISR increments a counter (@c trigger_count) and exits.
+ */
+extern void undiisr ( void );
+
+/** IRQ number */
+uint8_t __data16 ( undiisr_irq );
+#define undiisr_irq __use_data16 ( undiisr_irq )
+
+/** IRQ chain vector */
+struct segoff __data16 ( undiisr_next_handler );
+#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
+
+/** IRQ trigger count */
+volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
+#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
+
+/** Last observed trigger count */
+static unsigned int last_trigger_count = 0;
+
+/**
+ * Hook UNDI interrupt service routine
+ *
+ * @v irq		IRQ number
+ */
+static void undinet_hook_isr ( unsigned int irq ) {
+
+	assert ( irq <= IRQ_MAX );
+	assert ( undiisr_irq == 0 );
+
+	undiisr_irq = irq;
+	hook_bios_interrupt ( IRQ_INT ( irq ),
+			      ( ( unsigned int ) undiisr ),
+			      &undiisr_next_handler );
+}
+
+/**
+ * Unhook UNDI interrupt service routine
+ *
+ * @v irq		IRQ number
+ */
+static void undinet_unhook_isr ( unsigned int irq ) {
+
+	assert ( irq <= IRQ_MAX );
+
+	unhook_bios_interrupt ( IRQ_INT ( irq ),
+				( ( unsigned int ) undiisr ),
+				&undiisr_next_handler );
+	undiisr_irq = 0;
+}
+
+/**
+ * Test to see if UNDI ISR has been triggered
+ *
+ * @ret triggered	ISR has been triggered since last check
+ */
+static int undinet_isr_triggered ( void ) {
+	unsigned int this_trigger_count;
+
+	/* Read trigger_count.  Do this only once; it is volatile */
+	this_trigger_count = undiisr_trigger_count;
+
+	if ( this_trigger_count == last_trigger_count ) {
+		/* Not triggered */
+		return 0;
+	} else {
+		/* Triggered */
+		last_trigger_count = this_trigger_count;
+		return 1;
+	}
+}
+
+/*****************************************************************************
+ *
+ * UNDI network device interface
+ *
+ *****************************************************************************
+ */
+
+/** UNDI transmit buffer descriptor */
+static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
+#define undinet_tbd __use_data16 ( undinet_tbd )
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int undinet_transmit ( struct net_device *netdev,
+			      struct io_buffer *iobuf ) {
+	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
+	size_t len = iob_len ( iobuf );
+	int rc;
+
+	/* Technically, we ought to make sure that the previous
+	 * transmission has completed before we re-use the buffer.
+	 * However, many PXE stacks (including at least some Intel PXE
+	 * stacks and Etherboot 5.4) fail to generate TX completions.
+	 * In practice this won't be a problem, since our TX datapath
+	 * has a very low packet volume and we can get away with
+	 * assuming that a TX will be complete by the time we want to
+	 * transmit the next packet.
+	 */
+
+	/* Copy packet to UNDI I/O buffer */
+	if ( len > sizeof ( basemem_packet ) )
+		len = sizeof ( basemem_packet );
+	memcpy ( &basemem_packet, iobuf->data, len );
+
+	/* Create PXENV_UNDI_TRANSMIT data structure */
+	memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
+	undi_transmit.DestAddr.segment = rm_ds;
+	undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
+	undi_transmit.TBD.segment = rm_ds;
+	undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
+
+	/* Create PXENV_UNDI_TBD data structure */
+	undinet_tbd.ImmedLength = len;
+	undinet_tbd.Xmit.segment = rm_ds;
+	undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
+
+	/* Issue PXE API call */
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT,
+				     &undi_transmit,
+				     sizeof ( undi_transmit ) ) ) != 0 )
+		goto done;
+
+	/* Free I/O buffer */
+	netdev_tx_complete ( netdev, iobuf );
+
+ done:
+	return rc;
+}
+
+/** 
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ *
+ * Fun, fun, fun.  UNDI drivers don't use polling; they use
+ * interrupts.  We therefore cheat and pretend that an interrupt has
+ * occurred every time undinet_poll() is called.  This isn't too much
+ * of a hack; PCI devices share IRQs and so the first thing that a
+ * proper ISR should do is call PXENV_UNDI_ISR to determine whether or
+ * not the UNDI NIC generated the interrupt; there is no harm done by
+ * spurious calls to PXENV_UNDI_ISR.  Similarly, we wouldn't be
+ * handling them any more rapidly than the usual rate of
+ * undinet_poll() being called even if we did implement a full ISR.
+ * So it should work.  Ha!
+ *
+ * Addendum (21/10/03).  Some cards don't play nicely with this trick,
+ * so instead of doing it the easy way we have to go to all the hassle
+ * of installing a genuine interrupt service routine and dealing with
+ * the wonderful 8259 Programmable Interrupt Controller.  Joy.
+ *
+ * Addendum (10/07/07).  When doing things such as iSCSI boot, in
+ * which we have to co-operate with a running OS, we can't get away
+ * with the "ISR-just-increments-a-counter-and-returns" trick at all,
+ * because it involves tying up the PIC for far too long, and other
+ * interrupt-dependent components (e.g. local disks) start breaking.
+ * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
+ * from within interrupt context in order to deassert the device
+ * interrupt, and sends EOI if applicable.
+ */
+static void undinet_poll ( struct net_device *netdev ) {
+	struct undi_nic *undinic = netdev->priv;
+	struct s_PXENV_UNDI_ISR undi_isr;
+	struct io_buffer *iobuf = NULL;
+	size_t len;
+	size_t frag_len;
+	size_t max_frag_len;
+	int rc;
+
+	if ( ! undinic->isr_processing ) {
+		/* Allow interrupt to occur.  Do this even if
+		 * interrupts are not known to be supported, since
+		 * some cards erroneously report that they do not
+		 * support interrupts.
+		 */
+		if ( ! undinet_isr_triggered() ) {
+			/* Allow interrupt to occur */
+			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+							   "nop\n\t"
+							   "nop\n\t"
+							   "cli\n\t" ) : : );
+
+			/* If interrupts are known to be supported,
+			 * then do nothing on this poll; wait for the
+			 * interrupt to be triggered.
+			 */
+			if ( undinic->irq_supported )
+				return;
+		}
+
+		/* Start ISR processing */
+		undinic->isr_processing = 1;
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+	} else {
+		/* Continue ISR processing */
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+	}
+
+	/* Run through the ISR loop */
+	while ( 1 ) {
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
+					     &undi_isr,
+					     sizeof ( undi_isr ) ) ) != 0 )
+			break;
+		switch ( undi_isr.FuncFlag ) {
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
+			/* We don't care about transmit completions */
+			break;
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
+			/* Packet fragment received */
+			len = undi_isr.FrameLength;
+			frag_len = undi_isr.BufferLength;
+			if ( ( len == 0 ) || ( len < frag_len ) ) {
+				/* Don't laugh.  VMWare does it. */
+				DBGC ( undinic, "UNDINIC %p reported insane "
+				       "fragment (%zd of %zd bytes)\n",
+				       undinic, frag_len, len );
+				netdev_rx_err ( netdev, NULL, -EINVAL );
+				break;
+			}
+			if ( ! iobuf )
+				iobuf = alloc_iob ( len );
+			if ( ! iobuf ) {
+				DBGC ( undinic, "UNDINIC %p could not "
+				       "allocate %zd bytes for RX buffer\n",
+				       undinic, len );
+				/* Fragment will be dropped */
+				netdev_rx_err ( netdev, NULL, -ENOMEM );
+				goto done;
+			}
+			max_frag_len = iob_tailroom ( iobuf );
+			if ( frag_len > max_frag_len ) {
+				DBGC ( undinic, "UNDINIC %p fragment too big "
+				       "(%zd+%zd does not fit into %zd)\n",
+				       undinic, iob_len ( iobuf ), frag_len,
+				       ( iob_len ( iobuf ) + max_frag_len ) );
+				frag_len = max_frag_len;
+			}
+			copy_from_real ( iob_put ( iobuf, frag_len ),
+					 undi_isr.Frame.segment,
+					 undi_isr.Frame.offset, frag_len );
+			if ( iob_len ( iobuf ) == len ) {
+				/* Whole packet received; deliver it */
+				netdev_rx ( netdev, iob_disown ( iobuf ) );
+				/* Etherboot 5.4 fails to return all packets
+				 * under mild load; pretend it retriggered.
+				 */
+				if ( undinic->hacks & UNDI_HACK_EB54 )
+					--last_trigger_count;
+			}
+			break;
+		case PXENV_UNDI_ISR_OUT_DONE:
+			/* Processing complete */
+			undinic->isr_processing = 0;
+			goto done;
+		default:
+			/* Should never happen.  VMWare does it routinely. */
+			DBGC ( undinic, "UNDINIC %p ISR returned invalid "
+			       "FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
+			undinic->isr_processing = 0;
+			goto done;
+		}
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+	}
+
+ done:
+	if ( iobuf ) {
+		DBGC ( undinic, "UNDINIC %p returned incomplete packet "
+		       "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
+		       ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
+		netdev_rx_err ( netdev, iobuf, -EINVAL );
+	}
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int undinet_open ( struct net_device *netdev ) {
+	struct undi_nic *undinic = netdev->priv;
+	struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
+	struct s_PXENV_UNDI_OPEN undi_open;
+	int rc;
+
+	/* Hook interrupt service routine and enable interrupt if applicable */
+	if ( undinic->irq ) {
+		undinet_hook_isr ( undinic->irq );
+		enable_irq ( undinic->irq );
+		send_eoi ( undinic->irq );
+	}
+
+	/* Set station address.  Required for some PXE stacks; will
+	 * spuriously fail on others.  Ignore failures.  We only ever
+	 * use it to set the MAC address to the card's permanent value
+	 * anyway.
+	 */
+	memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
+		 sizeof ( undi_set_address.StationAddress ) );
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS,
+			 &undi_set_address, sizeof ( undi_set_address ) );
+
+	/* Open NIC.  We ask for promiscuous operation, since it's the
+	 * only way to ask for all multicast addresses.  On any
+	 * switched network, it shouldn't really make a difference to
+	 * performance.
+	 */
+	memset ( &undi_open, 0, sizeof ( undi_open ) );
+	undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN,
+				     &undi_open, sizeof ( undi_open ) ) ) != 0 )
+		goto err;
+
+	DBGC ( undinic, "UNDINIC %p opened\n", undinic );
+	return 0;
+
+ err:
+	undinet_close ( netdev );
+	return rc;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void undinet_close ( struct net_device *netdev ) {
+	struct undi_nic *undinic = netdev->priv;
+	struct s_PXENV_UNDI_ISR undi_isr;
+	struct s_PXENV_UNDI_CLOSE undi_close;
+	int rc;
+
+	/* Ensure ISR has exited cleanly */
+	while ( undinic->isr_processing ) {
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
+					     &undi_isr,
+					     sizeof ( undi_isr ) ) ) != 0 )
+			break;
+		switch ( undi_isr.FuncFlag ) {
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
+			/* Continue draining */
+			break;
+		default:
+			/* Stop processing */
+			undinic->isr_processing = 0;
+			break;
+		}
+	}
+
+	/* Close NIC */
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
+			 &undi_close, sizeof ( undi_close ) );
+
+	/* Disable interrupt and unhook ISR if applicable */
+	if ( undinic->irq ) {
+		disable_irq ( undinic->irq );
+		undinet_unhook_isr ( undinic->irq );
+	}
+
+	DBGC ( undinic, "UNDINIC %p closed\n", undinic );
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev		Net device
+ * @v enable		Interrupts should be enabled
+ */
+static void undinet_irq ( struct net_device *netdev, int enable ) {
+	struct undi_nic *undinic = netdev->priv;
+
+	/* Cannot support interrupts yet */
+	DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
+	       undinic, ( enable ? "enable" : "disable" ) );
+}
+
+/** UNDI network device operations */
+static struct net_device_operations undinet_operations = {
+	.open		= undinet_open,
+	.close		= undinet_close,
+	.transmit	= undinet_transmit,
+	.poll		= undinet_poll,
+	.irq   		= undinet_irq,
+};
+
+/**
+ * Probe UNDI device
+ *
+ * @v undi		UNDI device
+ * @ret rc		Return status code
+ */
+int undinet_probe ( struct undi_device *undi ) {
+	struct net_device *netdev;
+	struct undi_nic *undinic;
+	struct s_PXENV_START_UNDI start_undi;
+	struct s_PXENV_UNDI_STARTUP undi_startup;
+	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
+	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
+	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
+	struct s_PXENV_STOP_UNDI stop_undi;
+	int rc;
+
+	/* Allocate net device */
+	netdev = alloc_etherdev ( sizeof ( *undinic ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &undinet_operations );
+	undinic = netdev->priv;
+	undi_set_drvdata ( undi, netdev );
+	netdev->dev = &undi->dev;
+	memset ( undinic, 0, sizeof ( *undinic ) );
+	undinet_entry = undi->entry;
+	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
+
+	/* Hook in UNDI stack */
+	if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
+		memset ( &start_undi, 0, sizeof ( start_undi ) );
+		start_undi.AX = undi->pci_busdevfn;
+		start_undi.BX = undi->isapnp_csn;
+		start_undi.DX = undi->isapnp_read_port;
+		start_undi.ES = BIOS_SEG;
+		start_undi.DI = find_pnp_bios();
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI,
+					     &start_undi,
+					     sizeof ( start_undi ) ) ) != 0 )
+			goto err_start_undi;
+	}
+	undi->flags |= UNDI_FL_STARTED;
+
+	/* Bring up UNDI stack */
+	if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
+		memset ( &undi_startup, 0, sizeof ( undi_startup ) );
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP,
+					     &undi_startup,
+					     sizeof ( undi_startup ) ) ) != 0 )
+			goto err_undi_startup;
+		memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
+		if ( ( rc = pxeparent_call ( undinet_entry,
+					     PXENV_UNDI_INITIALIZE,
+					     &undi_initialize,
+					     sizeof ( undi_initialize ))) != 0 )
+			goto err_undi_initialize;
+	}
+	undi->flags |= UNDI_FL_INITIALIZED;
+
+	/* Get device information */
+	memset ( &undi_info, 0, sizeof ( undi_info ) );
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION,
+				     &undi_info, sizeof ( undi_info ) ) ) != 0 )
+		goto err_undi_get_information;
+	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
+	undinic->irq = undi_info.IntNumber;
+	if ( undinic->irq > IRQ_MAX ) {
+		DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
+		       undinic, undinic->irq );
+		rc = -EINVAL;
+		goto err_bad_irq;
+	}
+	DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
+	       undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
+
+	/* Get interface information */
+	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO,
+				     &undi_iface,
+				     sizeof ( undi_iface ) ) ) != 0 )
+		goto err_undi_get_iface_info;
+	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
+	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
+	       undi_iface.ServiceFlags );
+	if ( undi_iface.ServiceFlags & SUPPORTED_IRQ )
+		undinic->irq_supported = 1;
+	DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
+	       ( undinic->irq_supported ? "interrupt" : "polling" ) );
+	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
+		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
+		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
+		       undinic );
+		undinic->hacks |= UNDI_HACK_EB54;
+	}
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register;
+
+	/* Mark as link up; we don't handle link state */
+	netdev_link_up ( netdev );
+
+	DBGC ( undinic, "UNDINIC %p added\n", undinic );
+	return 0;
+
+ err_register:
+ err_undi_get_iface_info:
+ err_bad_irq:
+ err_undi_get_information:
+ err_undi_initialize:
+	/* Shut down UNDI stack */
+	memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
+			 sizeof ( undi_shutdown ) );
+	memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup,
+			 sizeof ( undi_cleanup ) );
+	undi->flags &= ~UNDI_FL_INITIALIZED;
+ err_undi_startup:
+	/* Unhook UNDI stack */
+	memset ( &stop_undi, 0, sizeof ( stop_undi ) );
+	pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
+			 sizeof ( stop_undi ) );
+	undi->flags &= ~UNDI_FL_STARTED;
+ err_start_undi:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	undi_set_drvdata ( undi, NULL );
+	return rc;
+}
+
+/**
+ * Remove UNDI device
+ *
+ * @v undi		UNDI device
+ */
+void undinet_remove ( struct undi_device *undi ) {
+	struct net_device *netdev = undi_get_drvdata ( undi );
+	struct undi_nic *undinic = netdev->priv;
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
+	struct s_PXENV_STOP_UNDI stop_undi;
+
+	/* Unregister net device */
+	unregister_netdev ( netdev );
+
+	/* If we are preparing for an OS boot, or if we cannot exit
+	 * via the PXE stack, then shut down the PXE stack.
+	 */
+	if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
+
+		/* Shut down UNDI stack */
+		memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
+		pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN,
+				 &undi_shutdown, sizeof ( undi_shutdown ) );
+		memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
+		pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP,
+				 &undi_cleanup, sizeof ( undi_cleanup ) );
+		undi->flags &= ~UNDI_FL_INITIALIZED;
+
+		/* Unhook UNDI stack */
+		memset ( &stop_undi, 0, sizeof ( stop_undi ) );
+		pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
+				 sizeof ( stop_undi ) );
+		undi->flags &= ~UNDI_FL_STARTED;
+	}
+
+	/* Clear entry point */
+	memset ( &undinet_entry, 0, sizeof ( undinet_entry ) );
+
+	/* Free network device */
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+
+	DBGC ( undinic, "UNDINIC %p removed\n", undinic );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undionly.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undionly.c
new file mode 100644
index 0000000..c38b574
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undionly.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/device.h>
+#include <ipxe/init.h>
+#include <undi.h>
+#include <undinet.h>
+#include <undipreload.h>
+
+/** @file
+ *
+ * "Pure" UNDI driver
+ *
+ * This is the UNDI driver without explicit support for PCI or any
+ * other bus type.  It is capable only of using the preloaded UNDI
+ * device.  It must not be combined in an image with any other
+ * drivers.
+ *
+ * If you want a PXE-loadable image that contains only the UNDI
+ * driver, build "bin/undionly.kpxe".
+ *
+ * If you want any other image format, or any other drivers in
+ * addition to the UNDI driver, build e.g. "bin/undi.dsk".
+ */
+
+/**
+ * Probe UNDI root bus
+ *
+ * @v rootdev		UNDI bus root device
+ *
+ * Scans the UNDI bus for devices and registers all devices it can
+ * find.
+ */
+static int undibus_probe ( struct root_device *rootdev ) {
+	struct undi_device *undi = &preloaded_undi;
+	int rc;
+
+	/* Check for a valie preloaded UNDI device */
+	if ( ! undi->entry.segment ) {
+		DBG ( "No preloaded UNDI device found!\n" );
+		return -ENODEV;
+	}
+
+	/* Add to device hierarchy */
+	strncpy ( undi->dev.name, "UNDI",
+		  ( sizeof ( undi->dev.name ) - 1 ) );
+	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
+		undi->dev.desc.bus_type = BUS_TYPE_PCI;
+		undi->dev.desc.location = undi->pci_busdevfn;
+		undi->dev.desc.vendor = undi->pci_vendor;
+		undi->dev.desc.device = undi->pci_device;
+	} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
+		undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
+	}
+	undi->dev.parent = &rootdev->dev;
+	list_add ( &undi->dev.siblings, &rootdev->dev.children);
+	INIT_LIST_HEAD ( &undi->dev.children );
+
+	/* Create network device */
+	if ( ( rc = undinet_probe ( undi ) ) != 0 )
+		goto err;
+
+	return 0;
+
+ err:
+	list_del ( &undi->dev.siblings );
+	return rc;
+}
+
+/**
+ * Remove UNDI root bus
+ *
+ * @v rootdev		UNDI bus root device
+ */
+static void undibus_remove ( struct root_device *rootdev __unused ) {
+	struct undi_device *undi = &preloaded_undi;
+
+	undinet_remove ( undi );
+	list_del ( &undi->dev.siblings );
+}
+
+/** UNDI bus root device driver */
+static struct root_driver undi_root_driver = {
+	.probe = undibus_probe,
+	.remove = undibus_remove,
+};
+
+/** UNDI bus root device */
+struct root_device undi_root_device __root_device = {
+	.dev = { .name = "UNDI" },
+	.driver = &undi_root_driver,
+};
+
+/**
+ * Prepare for exit
+ *
+ * @v booting		System is shutting down for OS boot
+ */
+static void undionly_shutdown ( int booting ) {
+	/* If we are shutting down to boot an OS, clear the "keep PXE
+	 * stack" flag.
+	 */
+	if ( booting )
+		preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
+}
+
+struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
+	.shutdown = undionly_shutdown,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undipreload.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
new file mode 100644
index 0000000..a4b2f4a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+#include <undipreload.h>
+
+/** @file
+ *
+ * Preloaded UNDI stack
+ *
+ */
+
+/**
+ * Preloaded UNDI device
+ *
+ * This is the UNDI device that was present when Etherboot started
+ * execution (i.e. when loading a .kpxe image).  The first driver to
+ * claim this device must zero out this data structure.
+ */
+struct undi_device __data16 ( preloaded_undi );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undirom.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undirom.c
new file mode 100644
index 0000000..2463d96
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/drivers/net/undirom.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pxe.h>
+#include <realmode.h>
+#include <undirom.h>
+
+/** @file
+ *
+ * UNDI expansion ROMs
+ *
+ */
+
+/** List of all UNDI ROMs */
+static LIST_HEAD ( undiroms );
+
+/**
+ * Parse PXE ROM ID structure
+ *
+ * @v undirom		UNDI ROM
+ * @v pxeromid		Offset within ROM to PXE ROM ID structure
+ * @ret rc		Return status code
+ */
+static int undirom_parse_pxeromid ( struct undi_rom *undirom,
+				   unsigned int pxeromid ) {
+	struct undi_rom_id undi_rom_id;
+	unsigned int undiloader;
+
+	DBGC ( undirom, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom,
+	       undirom->rom_segment, pxeromid );
+
+	/* Read PXE ROM ID structure and verify */
+	copy_from_real ( &undi_rom_id, undirom->rom_segment, pxeromid,
+			 sizeof ( undi_rom_id ) );
+	if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
+		DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
+		       "%08x\n", undirom, undi_rom_id.Signature );
+		return -EINVAL;
+	}
+
+	/* Check for UNDI loader */
+	undiloader = undi_rom_id.UNDILoader;
+	if ( ! undiloader ) {
+		DBGC ( undirom, "UNDIROM %p has no UNDI loader\n", undirom );
+		return -EINVAL;
+	}
+
+	/* Fill in UNDI ROM loader fields */
+	undirom->loader_entry.segment = undirom->rom_segment;
+	undirom->loader_entry.offset = undiloader;
+	undirom->code_size = undi_rom_id.CodeSize;
+	undirom->data_size = undi_rom_id.DataSize;
+
+	DBGC ( undirom, "UNDIROM %p has UNDI loader at %04x:%04x "
+	       "(code %04zx data %04zx)\n", undirom,
+	       undirom->loader_entry.segment, undirom->loader_entry.offset,
+	       undirom->code_size, undirom->data_size );
+	return 0;
+}
+
+/**
+ * Parse PCI expansion header
+ *
+ * @v undirom		UNDI ROM
+ * @v pcirheader	Offset within ROM to PCI expansion header
+ */
+static int undirom_parse_pcirheader ( struct undi_rom *undirom,
+				     unsigned int pcirheader ) {
+	struct pcir_header pcir_header;
+
+	DBGC ( undirom, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
+	       undirom, undirom->rom_segment, pcirheader );
+
+	/* Read PCI expansion header and verify */
+	copy_from_real ( &pcir_header, undirom->rom_segment, pcirheader,
+			 sizeof ( pcir_header ) );
+	if ( pcir_header.signature != PCIR_SIGNATURE ) {
+		DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
+		       "signature %08x\n", undirom, pcir_header.signature );
+		return -EINVAL;
+	}
+
+	/* Fill in UNDI ROM PCI device fields */
+	undirom->bus_type = PCI_NIC;
+	undirom->bus_id.pci.vendor_id = pcir_header.vendor_id;
+	undirom->bus_id.pci.device_id = pcir_header.device_id;
+
+	DBGC ( undirom, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom,
+	       undirom->bus_id.pci.vendor_id, undirom->bus_id.pci.device_id );
+	return 0;
+	
+}
+
+/**
+ * Probe UNDI ROM
+ *
+ * @v rom_segment	ROM segment address
+ * @ret rc		Return status code
+ */
+static int undirom_probe ( unsigned int rom_segment ) {
+	struct undi_rom *undirom = NULL;
+	struct undi_rom_header romheader;
+	size_t rom_len;
+	unsigned int pxeromid;
+	unsigned int pcirheader;
+	int rc;
+
+	/* Read expansion ROM header and verify */
+	copy_from_real ( &romheader, rom_segment, 0, sizeof ( romheader ) );
+	if ( romheader.Signature != ROM_SIGNATURE ) {
+		rc = -EINVAL;
+		goto err;
+	}
+	rom_len = ( romheader.ROMLength * 512 );
+
+	/* Allocate memory for UNDI ROM */
+	undirom = zalloc ( sizeof ( *undirom ) );
+	if ( ! undirom ) {
+		DBG ( "Could not allocate UNDI ROM structure\n" );
+		rc = -ENOMEM;
+		goto err;
+	}
+	DBGC ( undirom, "UNDIROM %p trying expansion ROM at %04x:0000 "
+	       "(%zdkB)\n", undirom, rom_segment, ( rom_len / 1024 ) );
+	undirom->rom_segment = rom_segment;
+
+	/* Check for and parse PXE ROM ID */
+	pxeromid = romheader.PXEROMID;
+	if ( ! pxeromid ) {
+		DBGC ( undirom, "UNDIROM %p has no PXE ROM ID\n", undirom );
+		rc = -EINVAL;
+		goto err;
+	}
+	if ( pxeromid > rom_len ) {
+		DBGC ( undirom, "UNDIROM %p PXE ROM ID outside ROM\n",
+		       undirom );
+		rc = -EINVAL;
+		goto err;
+	}
+	if ( ( rc = undirom_parse_pxeromid ( undirom, pxeromid ) ) != 0 )
+		goto err;
+
+	/* Parse PCIR header, if present */
+	pcirheader = romheader.PCIRHeader;
+	if ( pcirheader )
+		undirom_parse_pcirheader ( undirom, pcirheader );
+
+	/* Add to UNDI ROM list and return */
+	DBGC ( undirom, "UNDIROM %p registered\n", undirom );
+	list_add ( &undirom->list, &undiroms );
+	return 0;
+
+ err:
+	free ( undirom );
+	return rc;
+}
+
+/**
+ * Create UNDI ROMs for all possible expansion ROMs
+ *
+ * @ret 
+ */
+static void undirom_probe_all_roms ( void ) {
+	static int probed = 0;
+	unsigned int rom_segment;
+
+	/* Perform probe only once */
+	if ( probed )
+		return;
+
+	DBG ( "Scanning for PXE expansion ROMs\n" );
+
+	/* Scan through expansion ROM region at 512 byte intervals */
+	for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
+	      rom_segment += 0x20 ) {
+		undirom_probe ( rom_segment );
+	}
+
+	probed = 1;
+}
+
+/**
+ * Find UNDI ROM for PCI device
+ *
+ * @v vendor_id		PCI vendor ID
+ * @v device_id		PCI device ID
+ * @v rombase		ROM base address, or 0 for any
+ * @ret undirom		UNDI ROM, or NULL
+ */
+struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
+				     unsigned int device_id,
+				     unsigned int rombase ) {
+	struct undi_rom *undirom;
+
+	undirom_probe_all_roms();
+
+	list_for_each_entry ( undirom, &undiroms, list ) {
+		if ( undirom->bus_type != PCI_NIC )
+			continue;
+		if ( undirom->bus_id.pci.vendor_id != vendor_id )
+			continue;
+		if ( undirom->bus_id.pci.device_id != device_id )
+			continue;
+		if ( rombase && ( ( undirom->rom_segment << 4 ) != rombase ) )
+			continue;
+		DBGC ( undirom, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
+		       undirom, vendor_id, device_id, rombase );
+		return undirom;
+	}
+
+	DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
+	      vendor_id, device_id, rombase );
+	return NULL;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
new file mode 100644
index 0000000..d18e8b8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+#include <bios.h>
+#include <basemem.h>
+#include <ipxe/hidemem.h>
+
+/** @file
+ *
+ * Base memory allocation
+ *
+ */
+
+/**
+ * Set the BIOS free base memory counter
+ *
+ * @v new_fbms		New free base memory counter (in kB)
+ */
+void set_fbms ( unsigned int new_fbms ) {
+	uint16_t fbms = new_fbms;
+
+	/* Update the BIOS memory counter */
+	put_real ( fbms, BDA_SEG, BDA_FBMS );
+
+	/* Update our hidden memory region map */
+	hide_basemem();
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
new file mode 100644
index 0000000..1ecd07d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <realmode.h>
+#include <ipxe/console.h>
+#include <ipxe/ansiesc.h>
+#include <ipxe/keymap.h>
+
+#define ATTR_BOLD		0x08
+
+#define ATTR_FCOL_MASK		0x07
+#define ATTR_FCOL_BLACK		0x00
+#define ATTR_FCOL_BLUE		0x01
+#define ATTR_FCOL_GREEN		0x02
+#define ATTR_FCOL_CYAN		0x03
+#define ATTR_FCOL_RED		0x04
+#define ATTR_FCOL_MAGENTA	0x05
+#define ATTR_FCOL_YELLOW	0x06
+#define ATTR_FCOL_WHITE		0x07
+
+#define ATTR_BCOL_MASK		0x70
+#define ATTR_BCOL_BLACK		0x00
+#define ATTR_BCOL_BLUE		0x10
+#define ATTR_BCOL_GREEN		0x20
+#define ATTR_BCOL_CYAN		0x30
+#define ATTR_BCOL_RED		0x40
+#define ATTR_BCOL_MAGENTA	0x50
+#define ATTR_BCOL_YELLOW	0x60
+#define ATTR_BCOL_WHITE		0x70
+
+#define ATTR_DEFAULT		ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int bios_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count		Parameter count
+ * @v params[0]		Row (1 is top)
+ * @v params[1]		Column (1 is left)
+ */
+static void bios_handle_cup ( unsigned int count __unused, int params[] ) {
+	int cx = ( params[1] - 1 );
+	int cy = ( params[0] - 1 );
+
+	if ( cx < 0 )
+		cx = 0;
+	if ( cy < 0 )
+		cy = 0;
+
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "int $0x10\n\t"
+					   "cli\n\t" )
+			       : : "a" ( 0x0200 ), "b" ( 1 ),
+			           "d" ( ( cy << 8 ) | cx ) );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count		Parameter count
+ * @v params[0]		Region to erase
+ */
+static void bios_handle_ed ( unsigned int count __unused,
+			     int params[] __unused ) {
+	/* We assume that we always clear the whole screen */
+	assert ( params[0] == ANSIESC_ED_ALL );
+
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "int $0x10\n\t"
+					   "cli\n\t" )
+			       : : "a" ( 0x0600 ), "b" ( bios_attr << 8 ),
+			           "c" ( 0 ), "d" ( 0xffff ) );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count		Parameter count
+ * @v params		List of graphic rendition aspects
+ */
+static void bios_handle_sgr ( unsigned int count, int params[] ) {
+	static const uint8_t bios_attr_fcols[10] = {
+		ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+		ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+		ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+		ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+	};
+	static const uint8_t bios_attr_bcols[10] = {
+		ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+		ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+		ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+		ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+	};
+	unsigned int i;
+	int aspect;
+
+	for ( i = 0 ; i < count ; i++ ) {
+		aspect = params[i];
+		if ( aspect == 0 ) {
+			bios_attr = ATTR_DEFAULT;
+		} else if ( aspect == 1 ) {
+			bios_attr |= ATTR_BOLD;
+		} else if ( aspect == 22 ) {
+			bios_attr &= ~ATTR_BOLD;
+		} else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+			bios_attr &= ~ATTR_FCOL_MASK;
+			bios_attr |= bios_attr_fcols[ aspect - 30 ];
+		} else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+			bios_attr &= ~ATTR_BCOL_MASK;
+			bios_attr |= bios_attr_bcols[ aspect - 40 ];
+		}
+	}
+}
+
+/** BIOS console ANSI escape sequence handlers */
+static struct ansiesc_handler bios_ansiesc_handlers[] = {
+	{ ANSIESC_CUP, bios_handle_cup },
+	{ ANSIESC_ED, bios_handle_ed },
+	{ ANSIESC_SGR, bios_handle_sgr },
+	{ 0, NULL }
+};
+
+/** BIOS console ANSI escape sequence context */
+static struct ansiesc_context bios_ansiesc_ctx = {
+	.handlers = bios_ansiesc_handlers,
+};
+
+/**
+ * Print a character to BIOS console
+ *
+ * @v character		Character to be printed
+ */
+static void bios_putchar ( int character ) {
+	int discard_a, discard_b, discard_c;
+
+	/* Intercept ANSI escape sequences */
+	character = ansiesc_process ( &bios_ansiesc_ctx, character );
+	if ( character < 0 )
+		return;
+
+	/* Print character with attribute */
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   /* Skip non-printable characters */
+					   "cmpb $0x20, %%al\n\t"
+					   "jb 1f\n\t"
+					   /* Set attribute */
+					   "movw $0x0001, %%cx\n\t"
+					   "movb $0x09, %%ah\n\t"
+					   "int $0x10\n\t"
+					   "\n1:\n\t"
+					   /* Print character */
+					   "xorw %%bx, %%bx\n\t"
+					   "movb $0x0e, %%ah\n\t"
+					   "int $0x10\n\t"
+					   "cli\n\t" )
+			       : "=a" ( discard_a ), "=b" ( discard_b ),
+			         "=c" ( discard_c )
+			       : "a" ( character ), "b" ( bios_attr )
+			       : "ebp" );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return.  When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/** A mapping from a BIOS scan code to an ANSI escape sequence */
+#define BIOS_KEY( key, ansi ) key ansi "\0"
+
+/** Mapping from BIOS scan codes to ANSI escape sequences */
+static const char ansi_sequences[] = {
+	BIOS_KEY ( "\x53", "[3~" )	/* Delete */
+	BIOS_KEY ( "\x48", "[A" )	/* Up arrow */
+	BIOS_KEY ( "\x50", "[B" )	/* Down arrow */
+	BIOS_KEY ( "\x4b", "[D" )	/* Left arrow */
+	BIOS_KEY ( "\x4d", "[C" )	/* Right arrow */
+	BIOS_KEY ( "\x47", "[H" )	/* Home */
+	BIOS_KEY ( "\x4f", "[F" )	/* End */
+	BIOS_KEY ( "\x3f", "[15~" )	/* F5 */
+	BIOS_KEY ( "\x40", "[17~" )	/* F6 */
+	BIOS_KEY ( "\x41", "[18~" )	/* F7 */
+	BIOS_KEY ( "\x42", "[19~" )	/* F8 (required for PXE) */
+	BIOS_KEY ( "\x43", "[20~" )	/* F9 */
+	BIOS_KEY ( "\x44", "[21~" )	/* F10 */
+	BIOS_KEY ( "\x85", "[23~" )	/* F11 */
+	BIOS_KEY ( "\x86", "[24~" )	/* F12 */
+};
+
+/**
+ * Get ANSI escape sequence corresponding to BIOS scancode
+ *
+ * @v scancode		BIOS scancode
+ * @ret ansi_seq	ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+	const char *seq = ansi_sequences;
+
+	while ( *seq ) {
+		if ( *(seq++) == ( ( char ) scancode ) )
+			return seq;
+		seq += ( strlen ( seq ) + 1 );
+	}
+	DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
+	return NULL;
+}
+
+/**
+ * Map a key
+ *
+ * @v character		Character read from console
+ * @ret character	Mapped character
+ */
+static int bios_keymap ( unsigned int character ) {
+	struct key_mapping *mapping;
+
+	for_each_table_entry ( mapping, KEYMAP ) {
+		if ( mapping->from == character )
+			return mapping->to;
+	}
+	return character;
+}
+
+/**
+ * Get character from BIOS console
+ *
+ * @ret character	Character read from console
+ */
+static int bios_getchar ( void ) {
+	uint16_t keypress;
+	unsigned int character;
+	const char *ansi_seq;
+
+	/* If we are mid-sequence, pass out the next byte */
+	if ( ( character = *ansi_input ) ) {
+		ansi_input++;
+		return character;
+	}
+
+	/* Read character from real BIOS console */
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "int $0x16\n\t"
+					   "cli\n\t" )
+			       : "=a" ( keypress ) : "a" ( 0x1000 ) );
+	character = ( keypress & 0xff );
+
+	/* If it's a normal character, just map and return it */
+	if ( character && ( character < 0x80 ) )
+		return bios_keymap ( character );
+
+	/* Otherwise, check for a special key that we know about */
+	if ( ( ansi_seq = scancode_to_ansi_seq ( keypress >> 8 ) ) ) {
+		/* Start of escape sequence: return ESC (0x1b) */
+		ansi_input = ansi_seq;
+		return 0x1b;
+	}
+
+	return 0;
+}
+
+/**
+ * Check for character ready to read from BIOS console
+ *
+ * @ret True		Character available to read
+ * @ret False		No character available to read
+ */
+static int bios_iskey ( void ) {
+	unsigned int discard_a;
+	unsigned int flags;
+
+	/* If we are mid-sequence, we are always ready */
+	if ( *ansi_input )
+		return 1;
+
+	/* Otherwise check the real BIOS console */
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "int $0x16\n\t"
+					   "pushfw\n\t"
+					   "popw %w0\n\t"
+					   "cli\n\t" )
+			       : "=r" ( flags ), "=a" ( discard_a )
+			       : "a" ( 0x1100 ) );
+	return ( ! ( flags & ZF ) );
+}
+
+struct console_driver bios_console __console_driver = {
+	.putchar = bios_putchar,
+	.getchar = bios_getchar,
+	.iskey = bios_iskey,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
new file mode 100644
index 0000000..eeed51f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.arch i386
+	.code16
+
+#define SMAP 0x534d4150
+
+/* Most documentation refers to the E820 buffer as being 20 bytes, and
+ * the API makes it perfectly legitimate to pass only a 20-byte buffer
+ * and expect to get valid data.  However, some morons at ACPI decided
+ * to extend the data structure by adding an extra "extended
+ * attributes" field and by including critical information within this
+ * field, such as whether or not the region is enabled.  A caller who
+ * passes in only a 20-byte buffer therefore risks getting very, very
+ * misleading information.
+ *
+ * I have personally witnessed an HP BIOS that returns a value of
+ * 0x0009 in the extended attributes field.  If we don't pass this
+ * value through to the caller, 32-bit WinPE will die, usually with a
+ * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
+ *
+ * Allow a ridiculously large maximum value (64 bytes) for the E820
+ * buffer as a guard against insufficiently creative idiots in the
+ * future.
+ */
+#define E820MAXSIZE	64
+
+/****************************************************************************
+ *
+ * Allowed memory windows
+ *
+ * There are two ways to view this list.  The first is as a list of
+ * (non-overlapping) allowed memory regions, sorted by increasing
+ * address.  The second is as a list of (non-overlapping) hidden
+ * memory regions, again sorted by increasing address.  The second
+ * view is offset by half an entry from the first: think about this
+ * for a moment and it should make sense.
+ *
+ * xxx_memory_window is used to indicate an "allowed region"
+ * structure, hidden_xxx_memory is used to indicate a "hidden region"
+ * structure.  Each structure is 16 bytes in length.
+ *
+ ****************************************************************************
+ */
+	.section ".data16", "aw", @progbits
+	.align 16
+	.globl hidemem_base
+	.globl hidemem_umalloc
+	.globl hidemem_textdata
+memory_windows:
+base_memory_window:	.long 0x00000000, 0x00000000 /* Start of memory */
+
+hidemem_base:		.long 0x000a0000, 0x00000000 /* Changes at runtime */
+ext_memory_window:	.long 0x000a0000, 0x00000000 /* 640kB mark */
+
+hidemem_umalloc:	.long 0xffffffff, 0xffffffff /* Changes at runtime */
+			.long 0xffffffff, 0xffffffff /* Changes at runtime */
+
+hidemem_textdata:	.long 0xffffffff, 0xffffffff /* Changes at runtime */
+			.long 0xffffffff, 0xffffffff /* Changes at runtime */
+
+			.long 0xffffffff, 0xffffffff /* End of memory */
+memory_windows_end:
+
+/****************************************************************************
+ * Truncate region to memory window
+ *
+ * Parameters:
+ *  %edx:%eax	Start of region
+ *  %ecx:%ebx	Length of region
+ *  %si		Memory window
+ * Returns:
+ *  %edx:%eax	Start of windowed region
+ *  %ecx:%ebx	Length of windowed region
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+window_region:
+	/* Convert (start,len) to (start, end) */
+	addl	%eax, %ebx
+	adcl	%edx, %ecx
+	/* Truncate to window start */
+	cmpl	4(%si), %edx
+	jne	1f
+	cmpl	0(%si), %eax
+1:	jae	2f
+	movl	4(%si), %edx
+	movl	0(%si), %eax
+2:	/* Truncate to window end */
+	cmpl	12(%si), %ecx
+	jne	1f
+	cmpl	8(%si), %ebx
+1:	jbe	2f
+	movl	12(%si), %ecx
+	movl	8(%si), %ebx
+2:	/* Convert (start, end) back to (start, len) */
+	subl	%eax, %ebx
+	sbbl	%edx, %ecx
+	/* If length is <0, set length to 0 */
+	jae	1f
+	xorl	%ebx, %ebx
+	xorl	%ecx, %ecx
+	ret
+	.size	window_region, . - window_region
+
+/****************************************************************************
+ * Patch "memory above 1MB" figure
+ *
+ * Parameters:
+ *  %ax		Memory above 1MB, in 1kB blocks
+ * Returns:
+ *  %ax		Modified memory above 1M in 1kB blocks
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+patch_1m:
+	pushal
+	/* Convert to (start,len) format and call truncate */
+	xorl	%ecx, %ecx
+	movzwl	%ax, %ebx
+	shll	$10, %ebx
+	xorl	%edx, %edx
+	movl	$0x100000, %eax
+	movw	$ext_memory_window, %si
+	call	window_region
+	/* Convert back to "memory above 1MB" format and return via %ax */
+	pushfw
+	shrl	$10, %ebx
+	popfw
+	movw	%sp, %bp
+	movw	%bx, 28(%bp)
+	popal
+	ret
+	.size patch_1m, . - patch_1m
+
+/****************************************************************************
+ * Patch "memory above 16MB" figure
+ *
+ * Parameters:
+ *  %bx		Memory above 16MB, in 64kB blocks
+ * Returns:
+ *  %bx		Modified memory above 16M in 64kB blocks
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+patch_16m:
+	pushal
+	/* Convert to (start,len) format and call truncate */
+	xorl	%ecx, %ecx
+	shll	$16, %ebx
+	xorl	%edx, %edx
+	movl	$0x1000000, %eax
+	movw	$ext_memory_window, %si
+	call	window_region
+	/* Convert back to "memory above 16MB" format and return via %bx */
+	pushfw
+	shrl	$16, %ebx
+	popfw
+	movw	%sp, %bp
+	movw	%bx, 16(%bp)
+	popal
+	ret
+	.size patch_16m, . - patch_16m
+
+/****************************************************************************
+ * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
+ *
+ * Parameters:
+ *  %ax		Memory between 1MB and 16MB, in 1kB blocks
+ *  %bx		Memory above 16MB, in 64kB blocks
+ * Returns:
+ *  %ax		Modified memory between 1MB and 16MB, in 1kB blocks
+ *  %bx		Modified memory above 16MB, in 64kB blocks
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+patch_1m_16m:
+	call	patch_1m
+	call	patch_16m
+	/* If 1M region is no longer full-length, kill off the 16M region */
+	cmpw	$( 15 * 1024 ), %ax
+	je	1f
+	xorw	%bx, %bx
+1:	ret
+	.size patch_1m_16m, . - patch_1m_16m
+
+/****************************************************************************
+ * Get underlying e820 memory region to underlying_e820 buffer
+ *
+ * Parameters:
+ *   As for INT 15,e820
+ * Returns:
+ *   As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that the continuation
+ * value (%ebx) is a 16-bit simple sequence counter (with the high 16
+ * bits ignored), and termination is always via CF=1 rather than
+ * %ebx=0.
+ *
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+get_underlying_e820:
+
+	/* If the requested region is in the cache, return it */
+	cmpw	%bx, underlying_e820_index
+	jne	2f
+	pushw	%di
+	pushw	%si
+	movw	$underlying_e820_cache, %si
+	cmpl	underlying_e820_cache_size, %ecx
+	jbe	1f
+	movl	underlying_e820_cache_size, %ecx
+1:	pushl	%ecx
+	rep movsb
+	popl	%ecx
+	popw	%si
+	popw	%di
+	incw	%bx
+	movl	%edx, %eax
+	clc
+	ret
+2:	
+	/* If the requested region is earlier than the cached region,
+	 * invalidate the cache.
+	 */
+	cmpw	%bx, underlying_e820_index
+	jbe	1f
+	movw	$0xffff, underlying_e820_index
+1:
+	/* If the cache is invalid, reset the underlying %ebx */
+	cmpw	$0xffff, underlying_e820_index
+	jne	1f
+	andl	$0, underlying_e820_ebx
+1:	
+	/* If the cache is valid but the continuation value is zero,
+	 * this means that the previous underlying call returned with
+	 * %ebx=0.  Return with CF=1 in this case.
+	 */
+	cmpw	$0xffff, underlying_e820_index
+	je	1f
+	cmpl	$0, underlying_e820_ebx
+	jne	1f
+	stc
+	ret
+1:	
+	/* Get the next region into the cache */
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%esi	/* Some implementations corrupt %esi, so we	*/
+	pushl	%edi	/* preserve %esi, %edi and %ebp to be paranoid	*/
+	pushl	%ebp
+	pushw	%es
+	pushw	%ds
+	popw	%es
+	movw	$underlying_e820_cache, %di
+	cmpl	$E820MAXSIZE, %ecx
+	jbe	1f
+	movl	$E820MAXSIZE, %ecx
+1:	movl	underlying_e820_ebx, %ebx
+	stc
+	pushfw
+	lcall	*%cs:int15_vector
+	popw	%es
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	/* Check for error return from underlying e820 call */
+	jc	2f /* CF set: error */
+	cmpl	$SMAP, %eax
+	je	3f /* 'SMAP' missing: error */
+2:	/* An error occurred: return values returned by underlying e820 call */
+	stc	/* Force CF set if SMAP was missing */
+	addr32 leal 16(%esp), %esp /* avoid changing other flags */
+	ret
+3:	/* No error occurred */
+	movl	%ebx, underlying_e820_ebx
+	movl	%ecx, underlying_e820_cache_size
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	/* Mark cache as containing this result */
+	incw	underlying_e820_index
+
+	/* Loop until found */
+	jmp	get_underlying_e820
+	.size	get_underlying_e820, . - get_underlying_e820
+
+	.section ".data16", "aw", @progbits
+underlying_e820_index:
+	.word	0xffff /* Initialise to an invalid value */
+	.size underlying_e820_index, . - underlying_e820_index
+
+	.section ".bss16", "aw", @nobits
+underlying_e820_ebx:
+	.long	0
+	.size underlying_e820_ebx, . - underlying_e820_ebx
+
+	.section ".bss16", "aw", @nobits
+underlying_e820_cache:
+	.space	E820MAXSIZE
+	.size underlying_e820_cache, . - underlying_e820_cache
+
+	.section ".bss16", "aw", @nobits
+underlying_e820_cache_size:
+	.long	0
+	.size	underlying_e820_cache_size, . - underlying_e820_cache_size
+
+/****************************************************************************
+ * Get windowed e820 region, without empty region stripping
+ *
+ * Parameters:
+ *   As for INT 15,e820
+ * Returns:
+ *   As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned N times, windowed to fit within N visible-memory
+ * windows.  Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+get_windowed_e820:
+
+	/* Preserve registers */
+	pushl	%esi
+	pushw	%bp
+
+	/* Split %ebx into %si:%bx, store original %bx in %bp */
+	pushl	%ebx
+	popw	%bp
+	popw	%si
+
+	/* %si == 0 => start of memory_windows list */
+	testw	%si, %si
+	jne	1f
+	movw	$memory_windows, %si
+1:	
+	/* Get (cached) underlying e820 region to buffer */
+	call	get_underlying_e820
+	jc	99f /* Abort on error */
+
+	/* Preserve registers */
+	pushal
+	/* start => %edx:%eax, len => %ecx:%ebx */
+	movl	%es:0(%di), %eax
+	movl	%es:4(%di), %edx
+	movl	%es:8(%di), %ebx
+	movl	%es:12(%di), %ecx
+	/* Truncate region to current window */
+	call	window_region
+1:	/* Store modified values in e820 map entry */
+	movl	%eax, %es:0(%di)
+	movl	%edx, %es:4(%di)
+	movl	%ebx, %es:8(%di)
+	movl	%ecx, %es:12(%di)
+	/* Restore registers */
+	popal
+
+	/* Derive continuation value for next call */
+	addw	$16, %si
+	cmpw	$memory_windows_end, %si
+	jne	1f
+	/* End of memory windows: reset %si and allow %bx to continue */
+	xorw	%si, %si
+	jmp	2f
+1:	/* More memory windows to go: restore original %bx */
+	movw	%bp, %bx
+2:	/* Construct %ebx from %si:%bx */
+	pushw	%si
+	pushw	%bx
+	popl	%ebx
+
+98:	/* Clear CF */
+	clc
+99:	/* Restore registers and return */
+	popw	%bp
+	popl	%esi
+	ret
+	.size get_windowed_e820, . - get_windowed_e820
+
+/****************************************************************************
+ * Get windowed e820 region, with empty region stripping
+ *
+ * Parameters:
+ *   As for INT 15,e820
+ * Returns:
+ *   As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned up to N times, windowed to fit within N
+ * visible-memory windows.  Empty windows are never returned.
+ * Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+get_nonempty_e820:
+
+	/* Record entry parameters */
+	pushl	%eax
+	pushl	%ecx
+	pushl	%edx
+
+	/* Get next windowed region */
+	call	get_windowed_e820
+	jc	99f /* abort on error */
+
+	/* If region is non-empty, finish here */
+	cmpl	$0, %es:8(%di)
+	jne	98f
+	cmpl	$0, %es:12(%di)
+	jne	98f
+
+	/* Region was empty: restore entry parameters and go to next region */
+	popl	%edx
+	popl	%ecx
+	popl	%eax
+	jmp	get_nonempty_e820
+
+98:	/* Clear CF */
+	clc
+99:	/* Return values from underlying call */
+	addr32 leal 12(%esp), %esp /* avoid changing flags */
+	ret
+	.size get_nonempty_e820, . - get_nonempty_e820
+
+/****************************************************************************
+ * Get mangled e820 region, with empty region stripping
+ *
+ * Parameters:
+ *   As for INT 15,e820
+ * Returns:
+ *   As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that underlying regions
+ * are windowed to the allowed memory regions.  Empty regions are
+ * stripped from the map.  Termination is always via %ebx=0.
+ *
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+get_mangled_e820:
+
+	/* Get a nonempty region */
+	call	get_nonempty_e820
+	jc	99f /* Abort on error */
+
+	/* Peek ahead to see if there are any further nonempty regions */
+	pushal
+	pushw	%es
+	movw	%sp, %bp
+	subw	%cx, %sp
+	movl	$0xe820, %eax
+	movl	$SMAP, %edx
+	pushw	%ss
+	popw	%es
+	movw	%sp, %di
+	call	get_nonempty_e820
+	movw	%bp, %sp
+	popw	%es
+	popal
+	jnc	99f /* There are further nonempty regions */
+
+	/* No futher nonempty regions: zero %ebx and clear CF */
+	xorl	%ebx, %ebx
+	
+99:	/* Return */
+	ret
+	.size get_mangled_e820, . - get_mangled_e820
+
+/****************************************************************************
+ * INT 15,e820 handler
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+int15_e820:
+	pushw	%ds
+	pushw	%cs:rm_ds
+	popw	%ds
+	call	get_mangled_e820
+	popw	%ds
+	call	patch_cf
+	iret
+	.size int15_e820, . - int15_e820
+	
+/****************************************************************************
+ * INT 15,e801 handler
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+int15_e801:
+	/* Call previous handler */
+	pushfw
+	lcall	*%cs:int15_vector
+	call	patch_cf
+	/* Edit result */
+	pushw	%ds
+	pushw	%cs:rm_ds
+	popw	%ds
+	call	patch_1m_16m
+	xchgw	%ax, %cx
+	xchgw	%bx, %dx
+	call	patch_1m_16m
+	xchgw	%ax, %cx
+	xchgw	%bx, %dx
+	popw	%ds
+	iret
+	.size int15_e801, . - int15_e801
+	
+/****************************************************************************
+ * INT 15,88 handler
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+int15_88:
+	/* Call previous handler */
+	pushfw
+	lcall	*%cs:int15_vector
+	call	patch_cf
+	/* Edit result */
+	pushw	%ds
+	pushw	%cs:rm_ds
+	popw	%ds
+	call	patch_1m
+	popw	%ds
+	iret
+	.size int15_88, . - int15_88
+		
+/****************************************************************************
+ * INT 15 handler
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.globl int15
+int15:
+	/* See if we want to intercept this call */
+	pushfw
+	cmpw	$0xe820, %ax
+	jne	1f
+	cmpl	$SMAP, %edx
+	jne	1f
+	popfw
+	jmp	int15_e820
+1:	cmpw	$0xe801, %ax
+	jne	2f
+	popfw
+	jmp	int15_e801
+2:	cmpb	$0x88, %ah
+	jne	3f
+	popfw
+	jmp	int15_88
+3:	popfw
+	ljmp	*%cs:int15_vector
+	.size int15, . - int15
+	
+	.section ".text16.data", "aw", @progbits
+	.globl int15_vector
+int15_vector:
+	.long 0
+	.size int15_vector, . - int15_vector
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
new file mode 100644
index 0000000..ea116fe
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+#include <biosint.h>
+
+/** Assembly routine in inline asm */
+extern void int15_fakee820();
+
+/** Original INT 15 handler */
+static struct segoff __text16 ( real_int15_vector );
+#define real_int15_vector __use_text16 ( real_int15_vector )
+
+/** An INT 15,e820 memory map entry */
+struct e820_entry {
+	/** Start of region */
+	uint64_t start;
+	/** Length of region */
+	uint64_t len;
+	/** Type of region */
+	uint32_t type;
+} __attribute__ (( packed ));
+
+#define E820_TYPE_RAM		1 /**< Normal memory */
+#define E820_TYPE_RSVD		2 /**< Reserved and unavailable */
+#define E820_TYPE_ACPI		3 /**< ACPI reclaim memory */
+#define E820_TYPE_NVS		4 /**< ACPI NVS memory */
+
+/** Fake e820 map */
+static struct e820_entry __text16_array ( e820map, [] ) __used = {
+	{ 0x00000000ULL, ( 0x000a0000ULL - 0x00000000ULL ), E820_TYPE_RAM },
+	{ 0x00100000ULL, ( 0xcfb50000ULL - 0x00100000ULL ), E820_TYPE_RAM },
+	{ 0xcfb50000ULL, ( 0xcfb64000ULL - 0xcfb50000ULL ), E820_TYPE_RSVD },
+	{ 0xcfb64000ULL, ( 0xcfb66000ULL - 0xcfb64000ULL ), E820_TYPE_RSVD },
+	{ 0xcfb66000ULL, ( 0xcfb85c00ULL - 0xcfb66000ULL ), E820_TYPE_ACPI },
+	{ 0xcfb85c00ULL, ( 0xd0000000ULL - 0xcfb85c00ULL ), E820_TYPE_RSVD },
+	{ 0xe0000000ULL, ( 0xf0000000ULL - 0xe0000000ULL ), E820_TYPE_RSVD },
+	{ 0xfe000000ULL, (0x100000000ULL - 0xfe000000ULL ), E820_TYPE_RSVD },
+	{0x100000000ULL, (0x230000000ULL -0x100000000ULL ), E820_TYPE_RAM },
+};
+#define e820map __use_text16 ( e820map )
+
+void fake_e820 ( void ) {
+	__asm__ __volatile__ (
+		TEXT16_CODE ( "\nint15_fakee820:\n\t"
+			      "pushfw\n\t"
+			      "cmpl $0xe820, %%eax\n\t"
+			      "jne 99f\n\t"
+			      "cmpl $0x534d4150, %%edx\n\t"
+			      "jne 99f\n\t"
+			      "pushaw\n\t"
+			      "movw %%sp, %%bp\n\t"
+			      "andb $~0x01, 22(%%bp)\n\t" /* Clear return CF */
+			      "leaw e820map(%%bx), %%si\n\t"
+			      "cs rep movsb\n\t"
+			      "popaw\n\t"
+			      "movl %%edx, %%eax\n\t"
+			      "addl $20, %%ebx\n\t"
+			      "cmpl %0, %%ebx\n\t"
+			      "jne 1f\n\t"
+			      "xorl %%ebx,%%ebx\n\t"
+			      "\n1:\n\t"
+			      "popfw\n\t"
+			      "iret\n\t"
+			      "\n99:\n\t"
+			      "popfw\n\t"
+			      "ljmp *%%cs:real_int15_vector\n\t" )
+		: : "i" ( sizeof ( e820map ) ) );
+
+	hook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+			      &real_int15_vector );
+}
+
+void unfake_e820 ( void ) {
+	unhook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+				&real_int15_vector );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
new file mode 100644
index 0000000..cc5fc28
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <realmode.h>
+#include <biosint.h>
+#include <basemem.h>
+#include <fakee820.h>
+#include <ipxe/init.h>
+#include <ipxe/io.h>
+#include <ipxe/hidemem.h>
+
+/** Set to true if you want to test a fake E820 map */
+#define FAKE_E820 0
+
+/** Alignment for hidden memory regions */
+#define ALIGN_HIDDEN 4096   /* 4kB page alignment should be enough */
+
+/**
+ * A hidden region of iPXE
+ *
+ * This represents a region that will be edited out of the system's
+ * memory map.
+ *
+ * This structure is accessed by assembly code, so must not be
+ * changed.
+ */
+struct hidden_region {
+	/** Physical start address */
+	uint64_t start;
+	/** Physical end address */
+	uint64_t end;
+};
+
+/** Hidden base memory */
+extern struct hidden_region __data16 ( hidemem_base );
+#define hidemem_base __use_data16 ( hidemem_base )
+
+/** Hidden umalloc memory */
+extern struct hidden_region __data16 ( hidemem_umalloc );
+#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
+
+/** Hidden text memory */
+extern struct hidden_region __data16 ( hidemem_textdata );
+#define hidemem_textdata __use_data16 ( hidemem_textdata )
+
+/** Assembly routine in e820mangler.S */
+extern void int15();
+
+/** Vector for storing original INT 15 handler */
+extern struct segoff __text16 ( int15_vector );
+#define int15_vector __use_text16 ( int15_vector )
+
+/* The linker defines these symbols for us */
+extern char _textdata[];
+extern char _etextdata[];
+extern char _text16_memsz[];
+#define _text16_memsz ( ( unsigned int ) _text16_memsz )
+extern char _data16_memsz[];
+#define _data16_memsz ( ( unsigned int ) _data16_memsz )
+
+/**
+ * Hide region of memory from system memory map
+ *
+ * @v region		Hidden memory region
+ * @v start		Start of region
+ * @v end		End of region
+ */
+static void hide_region ( struct hidden_region *region,
+			  physaddr_t start, physaddr_t end ) {
+
+	/* Some operating systems get a nasty shock if a region of the
+	 * E820 map seems to start on a non-page boundary.  Make life
+	 * safer by rounding out our edited region.
+	 */
+	region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
+	region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
+
+	DBG ( "Hiding region [%llx,%llx)\n", region->start, region->end );
+}
+
+/**
+ * Hide used base memory
+ *
+ */
+void hide_basemem ( void ) {
+	/* Hide from the top of free base memory to 640kB.  Don't use
+	 * hide_region(), because we don't want this rounded to the
+	 * nearest page boundary.
+	 */
+	hidemem_base.start = ( get_fbms() * 1024 );
+}
+
+/**
+ * Hide umalloc() region
+ *
+ */
+void hide_umalloc ( physaddr_t start, physaddr_t end ) {
+	assert ( end <= virt_to_phys ( _textdata ) );
+	hide_region ( &hidemem_umalloc, start, end );
+}
+
+/**
+ * Hide .text and .data
+ *
+ */
+void hide_textdata ( void ) {
+	hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
+		      virt_to_phys ( _etextdata ) );
+}
+
+/**
+ * Hide Etherboot
+ *
+ * Installs an INT 15 handler to edit Etherboot out of the memory map
+ * returned by the BIOS.
+ */
+static void hide_etherboot ( void ) {
+	struct memory_map memmap;
+	unsigned int rm_ds_top;
+	unsigned int rm_cs_top;
+	unsigned int fbms;
+
+	/* Dump memory map before mangling */
+	DBG ( "Hiding iPXE from system memory map\n" );
+	get_memmap ( &memmap );
+
+	/* Hook in fake E820 map, if we're testing one */
+	if ( FAKE_E820 ) {
+		DBG ( "Hooking in fake E820 map\n" );
+		fake_e820();
+		get_memmap ( &memmap );
+	}
+
+	/* Initialise the hidden regions */
+	hide_basemem();
+	hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
+	hide_textdata();
+
+	/* Some really moronic BIOSes bring up the PXE stack via the
+	 * UNDI loader entry point and then don't bother to unload it
+	 * before overwriting the code and data segments.  If this
+	 * happens, we really don't want to leave INT 15 hooked,
+	 * because that will cause any loaded OS to die horribly as
+	 * soon as it attempts to fetch the system memory map.
+	 *
+	 * We use a heuristic to guess whether or not we are being
+	 * loaded sensibly.
+	 */
+	rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
+	rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
+	fbms = get_fbms();
+	if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
+		DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
+		      "DS=%04x FBMS=%dkB\n", rm_cs, rm_ds, fbms );
+		DBG ( "Disabling INT 15 memory hiding\n" );
+		return;
+	}
+
+	/* Hook INT 15 */
+	hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
+			      &int15_vector );
+
+	/* Dump memory map after mangling */
+	DBG ( "Hidden iPXE from system memory map\n" );
+	get_memmap ( &memmap );
+}
+
+/**
+ * Unhide Etherboot
+ *
+ * Uninstalls the INT 15 handler installed by hide_etherboot(), if
+ * possible.
+ */
+static void unhide_etherboot ( int flags __unused ) {
+
+	/* If we have more than one hooked interrupt at this point, it
+	 * means that some other vector is still hooked, in which case
+	 * we can't safely unhook INT 15 because we need to keep our
+	 * memory protected.  (We expect there to be at least one
+	 * hooked interrupt, because INT 15 itself is still hooked).
+	 */
+	if ( hooked_bios_interrupts > 1 ) {
+		DBG ( "Cannot unhide: %d interrupt vectors still hooked\n",
+		      hooked_bios_interrupts );
+		return;
+	}
+
+	/* Try to unhook INT 15.  If it fails, then just leave it
+	 * hooked; it takes care of protecting itself.  :)
+	 */
+	unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
+				&int15_vector );
+
+	/* Unhook fake E820 map, if used */
+	if ( FAKE_E820 )
+		unfake_e820();
+}
+
+/** Hide Etherboot startup function */
+struct startup_fn hide_etherboot_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+	.startup = hide_etherboot,
+	.shutdown = unhide_etherboot,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
new file mode 100644
index 0000000..493d2c2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <realmode.h>
+#include <bios.h>
+#include <memsizes.h>
+#include <ipxe/io.h>
+
+/**
+ * @file
+ *
+ * Memory mapping
+ *
+ */
+
+/** Magic value for INT 15,e820 calls */
+#define SMAP ( 0x534d4150 )
+
+/** An INT 15,e820 memory map entry */
+struct e820_entry {
+	/** Start of region */
+	uint64_t start;
+	/** Length of region */
+	uint64_t len;
+	/** Type of region */
+	uint32_t type;
+	/** Extended attributes (optional) */
+	uint32_t attrs;
+} __attribute__ (( packed ));
+
+#define E820_TYPE_RAM		1 /**< Normal memory */
+#define E820_TYPE_RESERVED	2 /**< Reserved and unavailable */
+#define E820_TYPE_ACPI		3 /**< ACPI reclaim memory */
+#define E820_TYPE_NVS		4 /**< ACPI NVS memory */
+
+#define E820_ATTR_ENABLED	0x00000001UL
+#define E820_ATTR_NONVOLATILE	0x00000002UL
+#define E820_ATTR_UNKNOWN	0xfffffffcUL
+
+#define E820_MIN_SIZE		20
+
+/** Buffer for INT 15,e820 calls */
+static struct e820_entry __bss16 ( e820buf );
+#define e820buf __use_data16 ( e820buf )
+
+/**
+ * Get size of extended memory via INT 15,e801
+ *
+ * @ret extmem		Extended memory size, in kB, or 0
+ */
+static unsigned int extmemsize_e801 ( void ) {
+	uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
+	uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
+	unsigned int flags;
+	unsigned int extmem;
+
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "int $0x15\n\t"
+					   "pushfw\n\t"
+					   "popw %w0\n\t" )
+			       : "=r" ( flags ),
+				 "=a" ( extmem_1m_to_16m_k ),
+				 "=b" ( extmem_16m_plus_64k ),
+				 "=c" ( confmem_1m_to_16m_k ),
+				 "=d" ( confmem_16m_plus_64k )
+			       : "a" ( 0xe801 ) );
+
+	if ( flags & CF ) {
+		DBG ( "INT 15,e801 failed with CF set\n" );
+		return 0;
+	}
+
+	if ( ! ( extmem_1m_to_16m_k | extmem_16m_plus_64k ) ) {
+		DBG ( "INT 15,e801 extmem=0, using confmem\n" );
+		extmem_1m_to_16m_k = confmem_1m_to_16m_k;
+		extmem_16m_plus_64k = confmem_16m_plus_64k;
+	}
+
+	extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
+	DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
+	      "[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
+	      extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
+
+	/* Sanity check.  Some BIOSes report the entire 4GB address
+	 * space as available, which cannot be correct (since that
+	 * would leave no address space available for 32-bit PCI
+	 * BARs).
+	 */
+	if ( extmem == ( 0x400000 - 0x400 ) ) {
+		DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
+		return 0;
+	}
+
+	return extmem;
+}
+
+/**
+ * Get size of extended memory via INT 15,88
+ *
+ * @ret extmem		Extended memory size, in kB
+ */
+static unsigned int extmemsize_88 ( void ) {
+	uint16_t extmem;
+
+	/* Ignore CF; it is not reliable for this call */
+	__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
+			       : "=a" ( extmem ) : "a" ( 0x8800 ) );
+
+	DBG ( "INT 15,88 extended memory size %d kB [100000, %x)\n",
+	      extmem, ( 0x100000 + ( extmem * 1024 ) ) );
+	return extmem;
+}
+
+/**
+ * Get size of extended memory
+ *
+ * @ret extmem		Extended memory size, in kB
+ *
+ * Note that this is only an approximation; for an accurate picture,
+ * use the E820 memory map obtained via get_memmap();
+ */
+unsigned int extmemsize ( void ) {
+	unsigned int extmem_e801;
+	unsigned int extmem_88;
+
+	/* Try INT 15,e801 first, then fall back to INT 15,88 */
+	extmem_88 = extmemsize_88();
+	extmem_e801 = extmemsize_e801();
+	return ( extmem_e801 ? extmem_e801 : extmem_88 );
+}
+
+/**
+ * Get e820 memory map
+ *
+ * @v memmap		Memory map to fill in
+ * @ret rc		Return status code
+ */
+static int meme820 ( struct memory_map *memmap ) {
+	struct memory_region *region = memmap->regions;
+	struct memory_region *prev_region = NULL;
+	uint32_t next = 0;
+	uint32_t smap;
+	size_t size;
+	unsigned int flags;
+	unsigned int discard_D;
+
+	/* Clear the E820 buffer.  Do this once before starting,
+	 * rather than on each call; some BIOSes rely on the contents
+	 * being preserved between calls.
+	 */
+	memset ( &e820buf, 0, sizeof ( e820buf ) );
+
+	do {
+		/* Some BIOSes corrupt %esi for fun. Guard against
+		 * this by telling gcc that all non-output registers
+		 * may be corrupted.
+		 */
+		__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
+						   "stc\n\t"
+						   "int $0x15\n\t"
+						   "pushfw\n\t"
+						   "popw %%dx\n\t"
+						   "popl %%ebp\n\t" )
+				       : "=a" ( smap ), "=b" ( next ),
+					 "=c" ( size ), "=d" ( flags ),
+					 "=D" ( discard_D )
+				       : "a" ( 0xe820 ), "b" ( next ),
+					 "D" ( __from_data16 ( &e820buf ) ),
+					 "c" ( sizeof ( e820buf ) ),
+					 "d" ( SMAP )
+				       : "esi", "memory" );
+
+		if ( smap != SMAP ) {
+			DBG ( "INT 15,e820 failed SMAP signature check\n" );
+			return -ENOTSUP;
+		}
+
+		if ( size < E820_MIN_SIZE ) {
+			DBG ( "INT 15,e820 returned only %zd bytes\n", size );
+			return -EINVAL;
+		}
+
+		if ( flags & CF ) {
+			DBG ( "INT 15,e820 terminated on CF set\n" );
+			break;
+		}
+
+		/* If first region is not RAM, assume map is invalid */
+		if ( ( memmap->count == 0 ) &&
+		     ( e820buf.type != E820_TYPE_RAM ) ) {
+		       DBG ( "INT 15,e820 failed, first entry not RAM\n" );
+		       return -EINVAL;
+		}
+
+		DBG ( "INT 15,e820 region [%llx,%llx) type %d",
+		      e820buf.start, ( e820buf.start + e820buf.len ),
+		      ( int ) e820buf.type );
+		if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+			DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
+					? "enabled" : "disabled" ) );
+			if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+				DBG ( ", non-volatile" );
+			if ( e820buf.attrs & E820_ATTR_UNKNOWN )
+				DBG ( ", other [%08x]", e820buf.attrs );
+			DBG ( ")" );
+		}
+		DBG ( "\n" );
+
+		/* Discard non-RAM regions */
+		if ( e820buf.type != E820_TYPE_RAM )
+			continue;
+
+		/* Check extended attributes, if present */
+		if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+			if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
+				continue;
+			if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+				continue;
+		}
+
+		region->start = e820buf.start;
+		region->end = e820buf.start + e820buf.len;
+
+		/* Check for adjacent regions and merge them */
+		if ( prev_region && ( region->start == prev_region->end ) ) {
+			prev_region->end = region->end;
+		} else {
+			prev_region = region;
+			region++;
+			memmap->count++;
+		}
+
+		if ( memmap->count >= ( sizeof ( memmap->regions ) /
+					sizeof ( memmap->regions[0] ) ) ) {
+			DBG ( "INT 15,e820 too many regions returned\n" );
+			/* Not a fatal error; what we've got so far at
+			 * least represents valid regions of memory,
+			 * even if we couldn't get them all.
+			 */
+			break;
+		}
+	} while ( next != 0 );
+
+	/* Sanity checks.  Some BIOSes report complete garbage via INT
+	 * 15,e820 (especially at POST time), despite passing the
+	 * signature checks.  We currently check for a base memory
+	 * region (starting at 0) and at least one high memory region
+	 * (starting at 0x100000).
+	 */
+	if ( memmap->count < 2 ) {
+		DBG ( "INT 15,e820 returned only %d regions; assuming "
+		      "insane\n", memmap->count );
+		return -EINVAL;
+	}
+	if ( memmap->regions[0].start != 0 ) {
+		DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
+		      "assuming insane\n", memmap->regions[0].start );
+		return -EINVAL;
+	}
+	if ( memmap->regions[1].start != 0x100000 ) {
+		DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
+		      "assuming insane\n", memmap->regions[0].start );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Get memory map
+ *
+ * @v memmap		Memory map to fill in
+ */
+void x86_get_memmap ( struct memory_map *memmap ) {
+	unsigned int basemem, extmem;
+	int rc;
+
+	DBG ( "Fetching system memory map\n" );
+
+	/* Clear memory map */
+	memset ( memmap, 0, sizeof ( *memmap ) );
+
+	/* Get base and extended memory sizes */
+	basemem = basememsize();
+	DBG ( "FBMS base memory size %d kB [0,%x)\n",
+	      basemem, ( basemem * 1024 ) );
+	extmem = extmemsize();
+	
+	/* Try INT 15,e820 first */
+	if ( ( rc = meme820 ( memmap ) ) == 0 ) {
+		DBG ( "Obtained system memory map via INT 15,e820\n" );
+		return;
+	}
+
+	/* Fall back to constructing a map from basemem and extmem sizes */
+	DBG ( "INT 15,e820 failed; constructing map\n" );
+	memmap->regions[0].end = ( basemem * 1024 );
+	memmap->regions[1].start = 0x100000;
+	memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
+	memmap->count = 2;
+}
+
+PROVIDE_IOAPI ( x86, get_memmap, x86_get_memmap );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
new file mode 100644
index 0000000..c572914
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <realmode.h>
+#include <pnpbios.h>
+
+/** @file
+ *
+ * PnP BIOS
+ *
+ */
+
+/** PnP BIOS structure */
+struct pnp_bios {
+	/** Signature
+	 *
+	 * Must be equal to @c PNP_BIOS_SIGNATURE
+	 */
+	uint32_t signature;
+	/** Version as BCD (e.g. 1.0 is 0x10) */
+	uint8_t version;
+	/** Length of this structure */
+	uint8_t length;
+	/** System capabilities */
+	uint16_t control;
+	/** Checksum */
+	uint8_t checksum;
+} __attribute__ (( packed ));
+
+/** Signature for a PnP BIOS structure */
+#define PNP_BIOS_SIGNATURE \
+	( ( '$' << 0 ) + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
+
+/**
+ * Test address for PnP BIOS structure
+ *
+ * @v offset		Offset within BIOS segment to test
+ * @ret rc		Return status code
+ */
+static int is_pnp_bios ( unsigned int offset ) {
+	union {
+		struct pnp_bios pnp_bios;
+		uint8_t bytes[256]; /* 256 is maximum length possible */
+	} u;
+	size_t len;
+	unsigned int i;
+	uint8_t sum = 0;
+
+	/* Read start of header and verify signature */
+	copy_from_real ( &u.pnp_bios, BIOS_SEG, offset, sizeof ( u.pnp_bios ));
+	if ( u.pnp_bios.signature != PNP_BIOS_SIGNATURE )
+		return -EINVAL;
+
+	/* Read whole header and verify checksum */
+	len = u.pnp_bios.length;
+	copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
+	for ( i = 0 ; i < len ; i++ ) {
+		sum += u.bytes[i];
+	}
+	if ( sum != 0 )
+		return -EINVAL;
+
+	DBG ( "Found PnP BIOS at %04x:%04x\n", BIOS_SEG, offset );
+
+	return 0;
+}
+
+/**
+ * Locate Plug-and-Play BIOS
+ *
+ * @ret pnp_offset	Offset of PnP BIOS structure within BIOS segment
+ *
+ * The PnP BIOS structure will be at BIOS_SEG:pnp_offset.  If no PnP
+ * BIOS is found, -1 is returned.
+ */
+int find_pnp_bios ( void ) {
+	static int pnp_offset = 0;
+
+	if ( pnp_offset )
+		return pnp_offset;
+
+	for ( pnp_offset = 0 ; pnp_offset < 0x10000 ; pnp_offset += 0x10 ) {
+		if ( is_pnp_bios ( pnp_offset ) == 0 )
+			return pnp_offset;
+	}
+
+	pnp_offset = -1;
+	return pnp_offset;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
new file mode 100644
index 0000000..79585cd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ipxe/netdevice.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <hci/ifmgmt_cmd.h>
+#include <pxe_call.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * PXE commands
+ *
+ */
+
+/** "startpxe" command descriptor */
+static struct command_descriptor startpxe_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>]" );
+
+/**
+ * "startpxe" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int startpxe_payload ( struct net_device *netdev ) {
+
+	if ( netdev_is_open ( netdev ) )
+		pxe_activate ( netdev );
+
+	return 0;
+}
+
+/**
+ * The "startpxe" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int startpxe_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &startpxe_cmd, startpxe_payload, 0 );
+}
+
+/** "stoppxe" options */
+struct stoppxe_options {};
+
+/** "stoppxe" option list */
+static struct option_descriptor stoppxe_opts[] = {};
+
+/** "stoppxe" command descriptor */
+static struct command_descriptor stoppxe_cmd =
+	COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, "" );
+
+/**
+ * The "stoppxe" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int stoppxe_exec ( int argc __unused, char **argv __unused ) {
+	struct stoppxe_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &stoppxe_cmd, &opts ) ) != 0 )
+		return rc;
+
+	pxe_deactivate();
+
+	return 0;
+}
+
+/** PXE commands */
+struct command pxe_commands[] __command = {
+	{
+		.name = "startpxe",
+		.exec = startpxe_exec,
+	},
+	{
+		.name = "stoppxe",
+		.exec = stoppxe_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c
new file mode 100644
index 0000000..d6a1d9a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <realmode.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Reboot command
+ *
+ */
+
+/** "reboot" options */
+struct reboot_options {};
+
+/** "reboot" option list */
+static struct option_descriptor reboot_opts[] = {};
+
+/** "reboot" command descriptor */
+static struct command_descriptor reboot_cmd =
+	COMMAND_DESC ( struct reboot_options, reboot_opts, 0, 0, "" );
+
+/**
+ * The "reboot" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int reboot_exec ( int argc, char **argv ) {
+	struct reboot_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &reboot_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Reboot system */
+	__asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : : );
+
+	return 0;
+}
+
+/** "reboot" command */
+struct command reboot_command __command = {
+	.name = "reboot",
+	.exec = reboot_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bootsector.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bootsector.c
new file mode 100644
index 0000000..f96cf20
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bootsector.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * x86 bootsector image format
+ *
+ */
+
+#include <errno.h>
+#include <realmode.h>
+#include <biosint.h>
+#include <bootsector.h>
+
+/** Vector for storing original INT 18 handler
+ *
+ * We do not chain to this vector, so there is no need to place it in
+ * .text16.
+ */
+static struct segoff int18_vector;
+
+/** Vector for storing original INT 19 handler
+ *
+ * We do not chain to this vector, so there is no need to place it in
+ * .text16.
+ */
+static struct segoff int19_vector;
+
+/** Restart point for INT 18 or 19 */
+extern void bootsector_exec_fail ( void );
+
+/**
+ * Jump to preloaded bootsector
+ *
+ * @v segment		Real-mode segment
+ * @v offset		Real-mode offset
+ * @v drive		Drive number to pass to boot sector
+ * @ret rc		Return status code
+ */
+int call_bootsector ( unsigned int segment, unsigned int offset,
+		      unsigned int drive ) {
+	int discard_b, discard_D, discard_d;
+
+	DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
+
+	/* Hook INTs 18 and 19 to capture failure paths */
+	hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
+			      &int18_vector );
+	hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
+			      &int19_vector );
+
+	/* Boot the loaded sector
+	 *
+	 * We assume that the boot sector may completely destroy our
+	 * real-mode stack, so we preserve everything we need in
+	 * static storage.
+	 */
+	__asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
+					   "popw %%cs:saved_retaddr\n\t"
+					   /* Save stack pointer */
+					   "movw %%ss, %%ax\n\t"
+					   "movw %%ax, %%cs:saved_ss\n\t"
+					   "movw %%sp, %%cs:saved_sp\n\t"
+					   /* Jump to boot sector */
+					   "pushw %%bx\n\t"
+					   "pushw %%di\n\t"
+					   "sti\n\t"
+					   "lret\n\t"
+					   /* Preserved variables */
+					   "\nsaved_ss: .word 0\n\t"
+					   "\nsaved_sp: .word 0\n\t"
+					   "\nsaved_retaddr: .word 0\n\t"
+					   /* Boot failure return point */
+					   "\nbootsector_exec_fail:\n\t"
+					   /* Restore stack pointer */
+					   "movw %%cs:saved_ss, %%ax\n\t"
+					   "movw %%ax, %%ss\n\t"
+					   "movw %%cs:saved_sp, %%sp\n\t"
+					   /* Return via saved address */
+					   "jmp *%%cs:saved_retaddr\n\t" )
+			       : "=b" ( discard_b ), "=D" ( discard_D ),
+			         "=d" ( discard_d )
+			       : "b" ( segment ), "D" ( offset ),
+			         "d" ( drive )
+			       : "eax", "ecx", "esi", "ebp" );
+
+	DBG ( "Booted disk returned via INT 18 or 19\n" );
+
+	/* Unhook INTs 18 and 19 */
+	unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
+				&int18_vector );
+	unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
+				&int19_vector );
+	
+	return -ECANCELED;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bzimage.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bzimage.c
new file mode 100644
index 0000000..cc7aeca
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/bzimage.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Linux bzImage image format
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <bzimage.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/segment.h>
+#include <ipxe/init.h>
+#include <ipxe/cpio.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
+
+/**
+ * bzImage context
+ */
+struct bzimage_context {
+	/** Boot protocol version */
+	unsigned int version;
+	/** Real-mode kernel portion load segment address */
+	unsigned int rm_kernel_seg;
+	/** Real-mode kernel portion load address */
+	userptr_t rm_kernel;
+	/** Real-mode kernel portion file size */
+	size_t rm_filesz;
+	/** Real-mode heap top (offset from rm_kernel) */
+	size_t rm_heap;
+	/** Command line (offset from rm_kernel) */
+	size_t rm_cmdline;
+	/** Command line maximum length */
+	size_t cmdline_size;
+	/** Real-mode kernel portion total memory size */
+	size_t rm_memsz;
+	/** Non-real-mode kernel portion load address */
+	userptr_t pm_kernel;
+	/** Non-real-mode kernel portion file and memory size */
+	size_t pm_sz;
+	/** Video mode */
+	unsigned int vid_mode;
+	/** Memory limit */
+	uint64_t mem_limit;
+	/** Initrd address */
+	physaddr_t ramdisk_image;
+	/** Initrd size */
+	physaddr_t ramdisk_size;
+
+	/** Command line magic block */
+	struct bzimage_cmdline cmdline_magic;
+	/** bzImage header */
+	struct bzimage_header bzhdr;
+};
+
+/**
+ * Parse bzImage header
+ *
+ * @v image		bzImage file
+ * @v bzimg		bzImage context
+ * @v src		bzImage to parse
+ * @ret rc		Return status code
+ */
+static int bzimage_parse_header ( struct image *image,
+				  struct bzimage_context *bzimg,
+				  userptr_t src ) {
+	unsigned int syssize;
+	int is_bzimage;
+
+	/* Sanity check */
+	if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) {
+		DBGC ( image, "bzImage %p too short for kernel header\n",
+		       image );
+		return -ENOEXEC;
+	}
+
+	/* Read in header structures */
+	memset ( bzimg, 0, sizeof ( *bzimg ) );
+	copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET,
+			 sizeof ( bzimg->cmdline_magic ) );
+	copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET,
+			 sizeof ( bzimg->bzhdr ) );
+
+	/* Calculate size of real-mode portion */
+	bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ?
+				 bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 );
+	if ( bzimg->rm_filesz > image->len ) {
+		DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
+		       image, bzimg->rm_filesz );
+		return -ENOEXEC;
+	}
+	bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE;
+
+	/* Calculate size of protected-mode portion */
+	bzimg->pm_sz = ( image->len - bzimg->rm_filesz );
+	syssize = ( ( bzimg->pm_sz + 15 ) / 16 );
+
+	/* Check for signatures and determine version */
+	if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) {
+		DBGC ( image, "bzImage %p missing 55AA signature\n", image );
+		return -ENOEXEC;
+	}
+	if ( bzimg->bzhdr.header == BZI_SIGNATURE ) {
+		/* 2.00+ */
+		bzimg->version = bzimg->bzhdr.version;
+	} else {
+		/* Pre-2.00.  Check that the syssize field is correct,
+		 * as a guard against accepting arbitrary binary data,
+		 * since the 55AA check is pretty lax.  Note that the
+		 * syssize field is unreliable for protocols between
+		 * 2.00 and 2.03 inclusive, so we should not always
+		 * check this field.
+		 */
+		bzimg->version = 0x0100;
+		if ( bzimg->bzhdr.syssize != syssize ) {
+			DBGC ( image, "bzImage %p bad syssize %x (expected "
+			       "%x)\n", image, bzimg->bzhdr.syssize, syssize );
+			return -ENOEXEC;
+		}
+	}
+
+	/* Determine image type */
+	is_bzimage = ( ( bzimg->version >= 0x0200 ) ?
+		       ( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 );
+
+	/* Calculate load address of real-mode portion */
+	bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 );
+	bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 );
+
+	/* Allow space for the stack and heap */
+	bzimg->rm_memsz += BZI_STACK_SIZE;
+	bzimg->rm_heap = bzimg->rm_memsz;
+
+	/* Allow space for the command line */
+	bzimg->rm_cmdline = bzimg->rm_memsz;
+	bzimg->rm_memsz += BZI_CMDLINE_SIZE;
+
+	/* Calculate load address of protected-mode portion */
+	bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR
+					: BZI_LOAD_LOW_ADDR );
+
+	/* Extract video mode */
+	bzimg->vid_mode = bzimg->bzhdr.vid_mode;
+
+	/* Extract memory limit */
+	bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ?
+			     bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX );
+
+	/* Extract command line size */
+	bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ?
+				bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE );
+
+	DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx "
+	       "cmdlen %zd\n", image, bzimg->version,
+	       user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz,
+	       user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz,
+	       bzimg->cmdline_size );
+
+	return 0;
+}
+
+/**
+ * Update bzImage header in loaded kernel
+ *
+ * @v image		bzImage file
+ * @v bzimg		bzImage context
+ * @v dst		bzImage to update
+ */
+static void bzimage_update_header ( struct image *image,
+				    struct bzimage_context *bzimg,
+				    userptr_t dst ) {
+
+	/* Set loader type */
+	if ( bzimg->version >= 0x0200 )
+		bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_IPXE;
+
+	/* Set heap end pointer */
+	if ( bzimg->version >= 0x0201 ) {
+		bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 );
+		bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP;
+	}
+
+	/* Set command line */
+	if ( bzimg->version >= 0x0202 ) {
+		bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel,
+							   bzimg->rm_cmdline );
+	} else {
+		bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
+		bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
+		bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
+	}
+
+	/* Set video mode */
+	bzimg->bzhdr.vid_mode = bzimg->vid_mode;
+
+	/* Set initrd address */
+	if ( bzimg->version >= 0x0200 ) {
+		bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image;
+		bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size;
+	}
+
+	/* Write out header structures */
+	copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic,
+		       sizeof ( bzimg->cmdline_magic ) );
+	copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr,
+		       sizeof ( bzimg->bzhdr ) );
+
+	DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode );
+}
+
+/**
+ * Parse kernel command line for bootloader parameters
+ *
+ * @v image		bzImage file
+ * @v bzimg		bzImage context
+ * @v cmdline		Kernel command line
+ * @ret rc		Return status code
+ */
+static int bzimage_parse_cmdline ( struct image *image,
+				   struct bzimage_context *bzimg,
+				   const char *cmdline ) {
+	char *vga;
+	char *mem;
+
+	/* Look for "vga=" */
+	if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
+		vga += 4;
+		if ( strcmp ( vga, "normal" ) == 0 ) {
+			bzimg->vid_mode = BZI_VID_MODE_NORMAL;
+		} else if ( strcmp ( vga, "ext" ) == 0 ) {
+			bzimg->vid_mode = BZI_VID_MODE_EXT;
+		} else if ( strcmp ( vga, "ask" ) == 0 ) {
+			bzimg->vid_mode = BZI_VID_MODE_ASK;
+		} else {
+			bzimg->vid_mode = strtoul ( vga, &vga, 0 );
+			if ( *vga && ( *vga != ' ' ) ) {
+				DBGC ( image, "bzImage %p strange \"vga=\""
+				       "terminator '%c'\n", image, *vga );
+			}
+		}
+	}
+
+	/* Look for "mem=" */
+	if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
+		mem += 4;
+		bzimg->mem_limit = strtoul ( mem, &mem, 0 );
+		switch ( *mem ) {
+		case 'G':
+		case 'g':
+			bzimg->mem_limit <<= 10;
+		case 'M':
+		case 'm':
+			bzimg->mem_limit <<= 10;
+		case 'K':
+		case 'k':
+			bzimg->mem_limit <<= 10;
+			break;
+		case '\0':
+		case ' ':
+			break;
+		default:
+			DBGC ( image, "bzImage %p strange \"mem=\" "
+			       "terminator '%c'\n", image, *mem );
+			break;
+		}
+		bzimg->mem_limit -= 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Set command line
+ *
+ * @v image		bzImage image
+ * @v bzimg		bzImage context
+ * @v cmdline		Kernel command line
+ * @ret rc		Return status code
+ */
+static int bzimage_set_cmdline ( struct image *image,
+				 struct bzimage_context *bzimg,
+				 const char *cmdline ) {
+	size_t cmdline_len;
+
+	/* Copy command line down to real-mode portion */
+	cmdline_len = ( strlen ( cmdline ) + 1 );
+	if ( cmdline_len > bzimg->cmdline_size )
+		cmdline_len = bzimg->cmdline_size;
+	copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
+		       cmdline, cmdline_len );
+	DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
+
+	return 0;
+}
+
+/**
+ * Load initrd
+ *
+ * @v image		bzImage image
+ * @v initrd		initrd image
+ * @v address		Address at which to load, or UNULL
+ * @ret len		Length of loaded image, rounded up to 4 bytes
+ */
+static size_t bzimage_load_initrd ( struct image *image,
+				    struct image *initrd,
+				    userptr_t address ) {
+	char *filename = initrd->cmdline;
+	struct cpio_header cpio;
+        size_t offset = 0;
+
+	/* Do not include kernel image itself as an initrd */
+	if ( initrd == image )
+		return 0;
+
+	/* Create cpio header before non-prebuilt images */
+	if ( filename && filename[0] ) {
+		size_t name_len = ( strlen ( filename ) + 1 );
+
+		DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
+		       image, initrd, filename );
+		memset ( &cpio, '0', sizeof ( cpio ) );
+		memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
+		cpio_set_field ( cpio.c_mode, 0100644 );
+		cpio_set_field ( cpio.c_nlink, 1 );
+		cpio_set_field ( cpio.c_filesize, initrd->len );
+		cpio_set_field ( cpio.c_namesize, name_len );
+		if ( address ) {
+			copy_to_user ( address, offset, &cpio,
+				       sizeof ( cpio ) );
+		}
+		offset += sizeof ( cpio );
+		if ( address ) {
+			copy_to_user ( address, offset, filename,
+				       name_len );
+		}
+		offset += name_len;
+		offset = ( ( offset + 0x03 ) & ~0x03 );
+	}
+
+	/* Copy in initrd image body */
+	if ( address )
+		memcpy_user ( address, offset, initrd->data, 0, initrd->len );
+	offset += initrd->len;
+	if ( address ) {
+		DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
+		       image, initrd, user_to_phys ( address, 0 ),
+		       user_to_phys ( address, offset ) );
+	}
+
+	/* Round up to 4-byte boundary */
+	offset = ( ( offset + 0x03 ) & ~0x03 );
+	return offset;
+}
+
+/**
+ * Load initrds, if any
+ *
+ * @v image		bzImage image
+ * @v bzimg		bzImage context
+ * @ret rc		Return status code
+ */
+static int bzimage_load_initrds ( struct image *image,
+				  struct bzimage_context *bzimg ) {
+	struct image *initrd;
+	size_t total_len = 0;
+	physaddr_t address;
+	int rc;
+
+	/* Add up length of all initrd images */
+	for_each_image ( initrd )
+		total_len += bzimage_load_initrd ( image, initrd, UNULL );
+
+	/* Give up if no initrd images found */
+	if ( ! total_len )
+		return 0;
+
+	/* Find a suitable start address.  Try 1MB boundaries,
+	 * starting from the downloaded kernel image itself and
+	 * working downwards until we hit an available region.
+	 */
+	for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
+	      address -= 0x100000 ) {
+		/* Check that we're not going to overwrite the
+		 * kernel itself.  This check isn't totally
+		 * accurate, but errs on the side of caution.
+		 */
+		if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
+			DBGC ( image, "bzImage %p could not find a location "
+			       "for initrd\n", image );
+			return -ENOBUFS;
+		}
+		/* Check that we are within the kernel's range */
+		if ( ( address + total_len - 1 ) > bzimg->mem_limit )
+			continue;
+		/* Prepare and verify segment */
+		if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
+					   total_len ) ) != 0 )
+			continue;
+		/* Use this address */
+		break;
+	}
+
+	/* Record initrd location */
+	bzimg->ramdisk_image = address;
+	bzimg->ramdisk_size = total_len;
+
+	/* Construct initrd */
+	DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
+	       image, address, ( address + total_len ) );
+	for_each_image ( initrd ) {
+		address += bzimage_load_initrd ( image, initrd,
+						 phys_to_user ( address ) );
+	}
+
+	return 0;
+}
+
+/**
+ * Execute bzImage image
+ *
+ * @v image		bzImage image
+ * @ret rc		Return status code
+ */
+static int bzimage_exec ( struct image *image ) {
+	struct bzimage_context bzimg;
+	const char *cmdline = ( image->cmdline ? image->cmdline : "" );
+	int rc;
+
+	/* Read and parse header from image */
+	if ( ( rc = bzimage_parse_header ( image, &bzimg,
+					   image->data ) ) != 0 )
+		return rc;
+
+	/* Prepare segments */
+	if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
+				   bzimg.rm_memsz ) ) != 0 ) {
+		DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+	if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
+				   bzimg.pm_sz ) ) != 0 ) {
+		DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Load segments */
+	memcpy_user ( bzimg.rm_kernel, 0, image->data,
+		      0, bzimg.rm_filesz );
+	memcpy_user ( bzimg.pm_kernel, 0, image->data,
+		      bzimg.rm_filesz, bzimg.pm_sz );
+
+	/* Update and write out header */
+	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
+
+	/* Parse command line for bootloader parameters */
+	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
+		return rc;
+
+	/* Store command line */
+	if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 )
+		return rc;
+
+	/* Load any initrds */
+	if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 )
+		return rc;
+
+	/* Update kernel header */
+	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
+
+	/* Prepare for exiting */
+	shutdown_boot();
+
+	DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
+	       "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
+	       bzimg.rm_kernel_seg, bzimg.rm_heap );
+
+	/* Jump to the kernel */
+	__asm__ __volatile__ ( REAL_CODE ( "movw %w0, %%ds\n\t"
+					   "movw %w0, %%es\n\t"
+					   "movw %w0, %%fs\n\t"
+					   "movw %w0, %%gs\n\t"
+					   "movw %w0, %%ss\n\t"
+					   "movw %w1, %%sp\n\t"
+					   "pushw %w2\n\t"
+					   "pushw $0\n\t"
+					   "lret\n\t" )
+			       : : "r" ( bzimg.rm_kernel_seg ),
+			           "r" ( bzimg.rm_heap ),
+			           "r" ( bzimg.rm_kernel_seg + 0x20 ) );
+
+	/* There is no way for the image to return, since we provide
+	 * no return address.
+	 */
+	assert ( 0 );
+
+	return -ECANCELED; /* -EIMPOSSIBLE */
+}
+
+/**
+ * Probe bzImage image
+ *
+ * @v image		bzImage file
+ * @ret rc		Return status code
+ */
+int bzimage_probe ( struct image *image ) {
+	struct bzimage_context bzimg;
+	int rc;
+
+	/* Read and parse header from image */
+	if ( ( rc = bzimage_parse_header ( image, &bzimg,
+					   image->data ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** Linux bzImage image type */
+struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "bzImage",
+	.probe = bzimage_probe,
+	.exec = bzimage_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/com32.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/com32.c
new file mode 100644
index 0000000..d6e48eb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/com32.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2008 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
+ *
+ * SYSLINUX COM32 image format
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <basemem.h>
+#include <comboot.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/segment.h>
+#include <ipxe/init.h>
+#include <ipxe/io.h>
+
+struct idt_register com32_external_idtr = {
+	.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
+	.base = COM32_IDT
+};
+
+struct idt_register com32_internal_idtr;
+
+/**
+ * Execute COMBOOT image
+ *
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_exec_loop ( struct image *image ) {
+	struct memory_map memmap;
+	unsigned int i;
+	int state;
+	uint32_t avail_mem_top;
+
+	state = rmsetjmp ( comboot_return );
+
+	switch ( state ) {
+	case 0: /* First time through; invoke COM32 program */
+
+		/* Get memory map */
+		get_memmap ( &memmap );
+
+		/* Find end of block covering COM32 image loading area */
+		for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
+			if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
+			     (memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
+				avail_mem_top = memmap.regions[i].end;
+				break;
+			}
+		}
+
+		DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
+		       image, avail_mem_top );
+
+		assert ( avail_mem_top != 0 );
+
+		com32_external_esp = phys_to_virt ( avail_mem_top );
+
+		/* Hook COMBOOT API interrupts */
+		hook_comboot_interrupts();
+
+		/* Unregister image, so that a "boot" command doesn't
+		 * throw us into an execution loop.  We never
+		 * reregister ourselves; COMBOOT images expect to be
+		 * removed on exit.
+		 */
+		unregister_image ( image );
+
+		__asm__ __volatile__ (
+			"sidt com32_internal_idtr\n\t"
+			"lidt com32_external_idtr\n\t"	       /* Set up IDT */
+			"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
+			"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
+			"call _virt_to_phys\n\t"               /* Switch to flat physical address space */
+			"sti\n\t"			       /* Enable interrupts */
+			"pushl %0\n\t"                         /* Pointer to CDECL helper function */
+			"pushl %1\n\t"                         /* Pointer to FAR call helper function */
+			"pushl %2\n\t"                         /* Size of low memory bounce buffer */
+			"pushl %3\n\t"                         /* Pointer to low memory bounce buffer */
+			"pushl %4\n\t"                         /* Pointer to INT call helper function */
+			"pushl %5\n\t"                         /* Pointer to the command line arguments */
+			"pushl $6\n\t"                         /* Number of additional arguments */
+			"call *%6\n\t"                         /* Execute image */
+			"cli\n\t"			       /* Disable interrupts */
+			"call _phys_to_virt\n\t"	       /* Switch back to internal virtual address space */
+			"lidt com32_internal_idtr\n\t"	       /* Switch back to internal IDT (for debugging) */
+			"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
+		:
+		:
+			/* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
+			/* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
+			/* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
+			/* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ),
+			/* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
+			/* %5 */ "r" ( virt_to_phys ( image->cmdline ?
+						      image->cmdline : "" ) ),
+			/* %6 */ "r" ( COM32_START_PHYS )
+		:
+			"memory" );
+		DBGC ( image, "COM32 %p: returned\n", image );
+		break;
+
+	case COMBOOT_EXIT:
+		DBGC ( image, "COM32 %p: exited\n", image );
+		break;
+
+	case COMBOOT_EXIT_RUN_KERNEL:
+		assert ( image->replacement );
+		DBGC ( image, "COM32 %p: exited to run kernel %s\n",
+		       image, image->replacement->name );
+		break;
+
+	case COMBOOT_EXIT_COMMAND:
+		DBGC ( image, "COM32 %p: exited after executing command\n",
+		       image );
+		break;
+
+	default:
+		assert ( 0 );
+		break;
+	}
+
+	unhook_comboot_interrupts();
+	comboot_force_text_mode();
+
+	return 0;
+}
+
+/**
+ * Check image name extension
+ * 
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_identify ( struct image *image ) {
+	const char *ext;
+	static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
+	uint8_t buf[5];
+	
+	if ( image->len >= 5 ) {
+		/* Check for magic number
+		 * mov eax,21cd4cffh
+		 * B8 FF 4C CD 21
+		 */
+		copy_from_user ( buf, image->data, 0, sizeof(buf) );
+		if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
+			DBGC ( image, "COM32 %p: found magic number\n",
+			       image );
+			return 0;
+		}
+	}
+
+	/* Magic number not found; check filename extension */
+
+	ext = strrchr( image->name, '.' );
+
+	if ( ! ext ) {
+		DBGC ( image, "COM32 %p: no extension\n",
+		       image );
+		return -ENOEXEC;
+	}
+
+	++ext;
+
+	if ( strcasecmp( ext, "c32" ) ) {
+		DBGC ( image, "COM32 %p: unrecognized extension %s\n",
+		       image, ext );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Load COM32 image into memory and set up the IDT
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_load_image ( struct image *image ) {
+	physaddr_t com32_irq_wrapper_phys;
+	struct idt_descriptor *idt;
+	struct ijb_entry *ijb;
+	size_t filesz, memsz;
+	userptr_t buffer;
+	int rc, i;
+
+	/* The interrupt descriptor table, interrupt jump buffer, and
+	 * image data are all contiguous in memory. Prepare them all at once.
+	 */
+	filesz = image->len +
+		COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) +
+		COM32_NUM_IDT_ENTRIES * sizeof ( struct ijb_entry );
+	memsz = filesz;
+	buffer = phys_to_user ( COM32_IDT );
+	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
+		DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Write the IDT and IJB */
+	idt = phys_to_virt ( COM32_IDT );
+	ijb = phys_to_virt ( COM32_IJB );
+	com32_irq_wrapper_phys = virt_to_phys ( com32_irq_wrapper );
+
+	for ( i = 0; i < COM32_NUM_IDT_ENTRIES; i++ ) {
+		uint32_t ijb_address = virt_to_phys ( &ijb[i] );
+
+		idt[i].offset_low = ijb_address & 0xFFFF;
+		idt[i].selector = PHYSICAL_CS;
+		idt[i].flags = IDT_INTERRUPT_GATE_FLAGS;
+		idt[i].offset_high = ijb_address >> 16;
+
+		ijb[i].pusha_instruction = IJB_PUSHA;
+		ijb[i].mov_instruction = IJB_MOV_AL_IMM8;
+		ijb[i].mov_value = i;
+		ijb[i].jump_instruction = IJB_JMP_REL32;
+		ijb[i].jump_destination = com32_irq_wrapper_phys -
+			virt_to_phys ( &ijb[i + 1] );
+	}
+
+	/* Copy image to segment */
+	buffer = phys_to_user ( COM32_START_PHYS );
+	memcpy_user ( buffer, 0, image->data, 0, filesz );
+
+	return 0;
+}
+
+/**
+ * Prepare COM32 low memory bounce buffer
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_prepare_bounce_buffer ( struct image * image ) {
+	unsigned int seg;
+	userptr_t seg_userptr;
+	size_t filesz, memsz;
+	int rc;
+
+	seg = COM32_BOUNCE_SEG;
+	seg_userptr = real_to_user ( seg, 0 );
+
+	/* Ensure the entire 64k segment is free */
+	memsz = 0xFFFF;
+	filesz = 0;
+
+	/* Prepare, verify, and load the real-mode segment */
+	if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
+		DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Probe COM32 image
+ *
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_probe ( struct image *image ) {
+	int rc;
+
+	DBGC ( image, "COM32 %p: name '%s'\n", image, image->name );
+
+	/* Check if this is a COMBOOT image */
+	if ( ( rc = com32_identify ( image ) ) != 0 ) {
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Execute COMBOOT image
+ *
+ * @v image		COM32 image
+ * @ret rc		Return status code
+ */
+static int com32_exec ( struct image *image ) {
+	int rc;
+
+	/* Load image */
+	if ( ( rc = com32_load_image ( image ) ) != 0 ) {
+		return rc;
+	}
+
+	/* Prepare bounce buffer segment */
+	if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
+		return rc;
+	}
+
+	return com32_exec_loop ( image );
+}
+
+/** SYSLINUX COM32 image type */
+struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "COM32",
+	.probe = com32_probe,
+	.exec = com32_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/comboot.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/comboot.c
new file mode 100644
index 0000000..0b924cc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/comboot.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2008 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
+ *
+ * SYSLINUX COMBOOT (16-bit) image format
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <basemem.h>
+#include <comboot.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/segment.h>
+#include <ipxe/init.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
+
+/**
+ * COMBOOT PSP, copied to offset 0 of code segment
+ */
+struct comboot_psp {
+	/** INT 20 instruction, executed if COMBOOT image returns with RET */
+	uint16_t int20;
+	/** Segment of first non-free paragraph of memory */
+	uint16_t first_non_free_para;
+};
+
+/** Offset in PSP of command line */
+#define COMBOOT_PSP_CMDLINE_OFFSET 0x81
+
+/** Maximum length of command line in PSP
+ * (127 bytes minus space and CR) */
+#define COMBOOT_MAX_CMDLINE_LEN    125
+
+
+/**
+ * Copy command line to PSP
+ * 
+ * @v image		COMBOOT image
+ */
+static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) {
+	const char *cmdline = ( image->cmdline ? image->cmdline : "" );
+	int cmdline_len = strlen ( cmdline );
+	if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN )
+		cmdline_len = COMBOOT_MAX_CMDLINE_LEN;
+	uint8_t len_byte = cmdline_len;
+	char spc = ' ', cr = '\r';
+
+	/* Copy length to byte before command line */
+	copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1,
+	               &len_byte, 1 );
+
+	/* Command line starts with space */
+	copy_to_user ( seg_userptr,
+	               COMBOOT_PSP_CMDLINE_OFFSET,
+	               &spc, 1 );
+
+	/* Copy command line */
+	copy_to_user ( seg_userptr,
+	               COMBOOT_PSP_CMDLINE_OFFSET + 1,
+	               cmdline, cmdline_len );
+
+	/* Command line ends with CR */
+	copy_to_user ( seg_userptr,
+	               COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1,
+	               &cr, 1 );
+}
+
+/**
+ * Initialize PSP
+ * 
+ * @v image		COMBOOT image
+ * @v seg_userptr	segment to initialize
+ */
+static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
+	struct comboot_psp psp;
+
+	/* Fill PSP */
+
+	/* INT 20h instruction, byte order reversed */
+	psp.int20 = 0x20CD;
+
+	/* get_fbms() returns BIOS free base memory counter, which is in
+	 * kilobytes; x * 1024 / 16 == x * 64 == x << 6 */
+	psp.first_non_free_para = get_fbms() << 6;
+
+	DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n",
+	       image, psp.first_non_free_para );
+
+	/* Copy the PSP to offset 0 of segment.
+	 * The rest of the PSP was already zeroed by
+	 * comboot_prepare_segment. */
+	copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) );
+
+	/* Copy the command line to the PSP */
+	comboot_copy_cmdline ( image, seg_userptr );
+}
+
+/**
+ * Execute COMBOOT image
+ *
+ * @v image		COMBOOT image
+ * @ret rc		Return status code
+ */
+static int comboot_exec_loop ( struct image *image ) {
+	userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
+	int state;
+
+	state = rmsetjmp ( comboot_return );
+
+	switch ( state ) {
+	case 0: /* First time through; invoke COMBOOT program */
+
+		/* Initialize PSP */
+		comboot_init_psp ( image, seg_userptr );
+
+		/* Hook COMBOOT API interrupts */
+		hook_comboot_interrupts();
+
+		DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
+		       COMBOOT_PSP_SEG );
+
+		/* Unregister image, so that a "boot" command doesn't
+		 * throw us into an execution loop.  We never
+		 * reregister ourselves; COMBOOT images expect to be
+		 * removed on exit.
+		 */
+		unregister_image ( image );
+
+		/* Store stack segment at 0x38 and stack pointer at 0x3A
+		 * in the PSP and jump to the image */
+		__asm__ __volatile__ (
+		    REAL_CODE ( /* Save return address with segment on old stack */
+				    "popw %%ax\n\t"
+				    "pushw %%cs\n\t"
+				    "pushw %%ax\n\t"
+				    /* Set DS=ES=segment with image */
+				    "movw %w0, %%ds\n\t"
+				    "movw %w0, %%es\n\t"
+				    /* Set SS:SP to new stack (end of image segment) */
+				    "movw %w0, %%ss\n\t"
+				    "xor %%sp, %%sp\n\t"
+				    "pushw $0\n\t"
+				    "pushw %w0\n\t"
+				    "pushw $0x100\n\t"
+				    /* Zero registers (some COM files assume GP regs are 0) */
+				    "xorw %%ax, %%ax\n\t"
+				    "xorw %%bx, %%bx\n\t"
+				    "xorw %%cx, %%cx\n\t"
+				    "xorw %%dx, %%dx\n\t"
+				    "xorw %%si, %%si\n\t"
+				    "xorw %%di, %%di\n\t"
+				    "xorw %%bp, %%bp\n\t"
+				    "lret\n\t" )
+					 : : "r" ( COMBOOT_PSP_SEG ) : "eax" );
+		DBGC ( image, "COMBOOT %p: returned\n", image );
+		break;
+
+	case COMBOOT_EXIT:
+		DBGC ( image, "COMBOOT %p: exited\n", image );
+		break;
+
+	case COMBOOT_EXIT_RUN_KERNEL:
+		assert ( image->replacement );
+		DBGC ( image, "COMBOOT %p: exited to run kernel %s\n",
+		       image, image->replacement->name );
+		break;
+
+	case COMBOOT_EXIT_COMMAND:
+		DBGC ( image, "COMBOOT %p: exited after executing command\n",
+		       image );
+		break;
+
+	default:
+		assert ( 0 );
+		break;
+	}
+
+	unhook_comboot_interrupts();
+	comboot_force_text_mode();
+
+	return 0;
+}
+
+/**
+ * Check image name extension
+ * 
+ * @v image		COMBOOT image
+ * @ret rc		Return status code
+ */
+static int comboot_identify ( struct image *image ) {
+	const char *ext;
+
+	ext = strrchr( image->name, '.' );
+
+	if ( ! ext ) {
+		DBGC ( image, "COMBOOT %p: no extension\n",
+		       image );
+		return -ENOEXEC;
+	}
+
+	++ext;
+
+	if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
+		DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
+		       image, ext );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/**
+ * Load COMBOOT image into memory, preparing a segment and returning it
+ * @v image		COMBOOT image
+ * @ret rc		Return status code
+ */
+static int comboot_prepare_segment ( struct image *image )
+{
+	userptr_t seg_userptr;
+	size_t filesz, memsz;
+	int rc;
+
+	/* Load image in segment */
+	seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
+
+	/* Allow etra 0x100 bytes before image for PSP */
+	filesz = image->len + 0x100; 
+
+	/* Ensure the entire 64k segment is free */
+	memsz = 0xFFFF;
+
+	/* Prepare, verify, and load the real-mode segment */
+	if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
+		DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Zero PSP */
+	memset_user ( seg_userptr, 0, 0, 0x100 );
+
+	/* Copy image to segment:0100 */
+	memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len );
+
+	return 0;
+}
+
+/**
+ * Probe COMBOOT image
+ *
+ * @v image		COMBOOT image
+ * @ret rc		Return status code
+ */
+static int comboot_probe ( struct image *image ) {
+	int rc;
+
+	DBGC ( image, "COMBOOT %p: name '%s'\n",
+	       image, image->name );
+
+	/* Check if this is a COMBOOT image */
+	if ( ( rc = comboot_identify ( image ) ) != 0 ) {
+		
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Execute COMBOOT image
+ *
+ * @v image		COMBOOT image
+ * @ret rc		Return status code
+ */
+static int comboot_exec ( struct image *image ) {
+	int rc;
+	
+	/* Sanity check for filesize */
+	if( image->len >= 0xFF00 ) {
+		DBGC( image, "COMBOOT %p: image too large\n",
+		      image );
+		return -ENOEXEC;
+	}
+
+	/* Prepare segment and load image */
+	if ( ( rc = comboot_prepare_segment ( image ) ) != 0 ) {
+		return rc;
+	}
+
+	return comboot_exec_loop ( image );
+}
+
+/** SYSLINUX COMBOOT (16-bit) image type */
+struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "COMBOOT",
+	.probe = comboot_probe,
+	.exec = comboot_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/elfboot.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/elfboot.c
new file mode 100644
index 0000000..89e70a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/elfboot.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <elf.h>
+#include <ipxe/image.h>
+#include <ipxe/elf.h>
+#include <ipxe/features.h>
+#include <ipxe/init.h>
+
+/**
+ * @file
+ *
+ * ELF bootable image
+ *
+ */
+
+FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
+
+/**
+ * Execute ELF image
+ *
+ * @v image		ELF image
+ * @ret rc		Return status code
+ */
+static int elfboot_exec ( struct image *image ) {
+	physaddr_t entry;
+	int rc;
+
+	/* Load the image using core ELF support */
+	if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
+		DBGC ( image, "ELF %p could not load: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* An ELF image has no callback interface, so we need to shut
+	 * down before invoking it.
+	 */
+	shutdown_boot();
+
+	/* Jump to OS with flat physical addressing */
+	DBGC ( image, "ELF %p starting execution at %lx\n", image, entry );
+	__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
+			       : : "D" ( entry )
+			       : "eax", "ebx", "ecx", "edx", "esi", "ebp",
+			         "memory" );
+
+	DBGC ( image, "ELF %p returned\n", image );
+
+	/* It isn't safe to continue after calling shutdown() */
+	while ( 1 ) {}
+
+	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
+}
+
+/**
+ * Probe ELF image
+ *
+ * @v image		ELF file
+ * @ret rc		Return status code
+ */
+static int elfboot_probe ( struct image *image ) {
+	Elf32_Ehdr ehdr;
+	static const uint8_t e_ident[] = {
+		[EI_MAG0]	= ELFMAG0,
+		[EI_MAG1]	= ELFMAG1,
+		[EI_MAG2]	= ELFMAG2,
+		[EI_MAG3]	= ELFMAG3,
+		[EI_CLASS]	= ELFCLASS32,
+		[EI_DATA]	= ELFDATA2LSB,
+		[EI_VERSION]	= EV_CURRENT,
+	};
+
+	/* Read ELF header */
+	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
+	if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
+		DBG ( "Invalid ELF identifier\n" );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/** ELF image type */
+struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "ELF",
+	.probe = elfboot_probe,
+	.exec = elfboot_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/multiboot.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/multiboot.c
new file mode 100644
index 0000000..15e8fd5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/multiboot.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Multiboot image format
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <multiboot.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/segment.h>
+#include <ipxe/io.h>
+#include <ipxe/elf.h>
+#include <ipxe/init.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
+
+/**
+ * Maximum number of modules we will allow for
+ *
+ * If this has bitten you: sorry.  I did have a perfect scheme with a
+ * dynamically allocated list of modules on the protected-mode stack,
+ * but it was incompatible with some broken OSes that can only access
+ * low memory at boot time (even though we kindly set up 4GB flat
+ * physical addressing as per the multiboot specification.
+ *
+ */
+#define MAX_MODULES 8
+
+/**
+ * Maximum combined length of command lines
+ *
+ * Again; sorry.  Some broken OSes zero out any non-base memory that
+ * isn't part of the loaded module set, so we can't just use
+ * virt_to_phys(cmdline) to point to the command lines, even though
+ * this would comply with the Multiboot spec.
+ */
+#define MB_MAX_CMDLINE 512
+
+/** Multiboot flags that we support */
+#define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
+			     MB_FLAG_VIDMODE | MB_FLAG_RAW )
+
+/** Compulsory feature multiboot flags */
+#define MB_COMPULSORY_FLAGS 0x0000ffff
+
+/** Optional feature multiboot flags */
+#define MB_OPTIONAL_FLAGS 0xffff0000
+
+/**
+ * Multiboot flags that we don't support
+ *
+ * We only care about the compulsory feature flags (bits 0-15); we are
+ * allowed to ignore the optional feature flags.
+ */
+#define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
+
+/** A multiboot header descriptor */
+struct multiboot_header_info {
+	/** The actual multiboot header */
+	struct multiboot_header mb;
+	/** Offset of header within the multiboot image */
+	size_t offset;
+};
+
+/** Multiboot module command lines */
+static char __bss16_array ( mb_cmdlines, [MB_MAX_CMDLINE] );
+#define mb_cmdlines __use_data16 ( mb_cmdlines )
+
+/** Offset within module command lines */
+static unsigned int mb_cmdline_offset;
+
+/**
+ * Build multiboot memory map
+ *
+ * @v image		Multiboot image
+ * @v mbinfo		Multiboot information structure
+ * @v mbmemmap		Multiboot memory map
+ * @v limit		Maxmimum number of memory map entries
+ */
+static void multiboot_build_memmap ( struct image *image,
+				     struct multiboot_info *mbinfo,
+				     struct multiboot_memory_map *mbmemmap,
+				     unsigned int limit ) {
+	struct memory_map memmap;
+	unsigned int i;
+
+	/* Get memory map */
+	get_memmap ( &memmap );
+
+	/* Translate into multiboot format */
+	memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
+	for ( i = 0 ; i < memmap.count ; i++ ) {
+		if ( i >= limit ) {
+			DBGC ( image, "MULTIBOOT %p limit of %d memmap "
+			       "entries reached\n", image, limit );
+			break;
+		}
+		mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) -
+				     sizeof ( mbmemmap[i].size ) );
+		mbmemmap[i].base_addr = memmap.regions[i].start;
+		mbmemmap[i].length = ( memmap.regions[i].end -
+				       memmap.regions[i].start );
+		mbmemmap[i].type = MBMEM_RAM;
+		mbinfo->mmap_length += sizeof ( mbmemmap[i] );
+		if ( memmap.regions[i].start == 0 )
+			mbinfo->mem_lower = ( memmap.regions[i].end / 1024 );
+		if ( memmap.regions[i].start == 0x100000 )
+			mbinfo->mem_upper = ( ( memmap.regions[i].end -
+						0x100000 ) / 1024 );
+	}
+}
+
+/**
+ * Add command line in base memory
+ *
+ * @v imgname		Image name
+ * @v cmdline		Command line
+ * @ret physaddr	Physical address of command line
+ */
+physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
+	char *mb_cmdline;
+
+	if ( ! cmdline )
+		cmdline = "";
+
+	/* Copy command line to base memory buffer */
+	mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
+	mb_cmdline_offset +=
+		( snprintf ( mb_cmdline,
+			     ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
+			     "%s %s", imgname, cmdline ) + 1 );
+
+	/* Truncate to terminating NUL in buffer if necessary */
+	if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
+		mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
+
+	return virt_to_phys ( mb_cmdline );
+}
+
+/**
+ * Build multiboot module list
+ *
+ * @v image		Multiboot image
+ * @v modules		Module list to fill, or NULL
+ * @ret count		Number of modules
+ */
+static unsigned int
+multiboot_build_module_list ( struct image *image,
+			      struct multiboot_module *modules,
+			      unsigned int limit ) {
+	struct image *module_image;
+	struct multiboot_module *module;
+	unsigned int count = 0;
+	unsigned int insert;
+	physaddr_t start;
+	physaddr_t end;
+	unsigned int i;
+
+	/* Add each image as a multiboot module */
+	for_each_image ( module_image ) {
+
+		if ( count >= limit ) {
+			DBGC ( image, "MULTIBOOT %p limit of %d modules "
+			       "reached\n", image, limit );
+			break;
+		}
+
+		/* Do not include kernel image itself as a module */
+		if ( module_image == image )
+			continue;
+
+		/* At least some OSes expect the multiboot modules to
+		 * be in ascending order, so we have to support it.
+		 */
+		start = user_to_phys ( module_image->data, 0 );
+		end = user_to_phys ( module_image->data, module_image->len );
+		for ( insert = 0 ; insert < count ; insert++ ) {
+			if ( start < modules[insert].mod_start )
+				break;
+		}
+		module = &modules[insert];
+		memmove ( ( module + 1 ), module,
+			  ( ( count - insert ) * sizeof ( *module ) ) );
+		module->mod_start = start;
+		module->mod_end = end;
+		module->string = multiboot_add_cmdline ( module_image->name,
+						       module_image->cmdline );
+		module->reserved = 0;
+		
+		/* We promise to page-align modules */
+		assert ( ( module->mod_start & 0xfff ) == 0 );
+
+		count++;
+	}
+
+	/* Dump module configuration */
+	for ( i = 0 ; i < count ; i++ ) {
+		DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
+		       image, i, modules[i].mod_start,
+		       modules[i].mod_end );
+	}
+
+	return count;
+}
+
+/**
+ * The multiboot information structure
+ *
+ * Kept in base memory because some OSes won't find it elsewhere,
+ * along with the other structures belonging to the Multiboot
+ * information table.
+ */
+static struct multiboot_info __bss16 ( mbinfo );
+#define mbinfo __use_data16 ( mbinfo )
+
+/** The multiboot bootloader name */
+static char __data16_array ( mb_bootloader_name, [] ) = "iPXE " VERSION;
+#define mb_bootloader_name __use_data16 ( mb_bootloader_name )
+
+/** The multiboot memory map */
+static struct multiboot_memory_map
+	__bss16_array ( mbmemmap, [MAX_MEMORY_REGIONS] );
+#define mbmemmap __use_data16 ( mbmemmap )
+
+/** The multiboot module list */
+static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
+#define mbmodules __use_data16 ( mbmodules )
+
+/**
+ * Find multiboot header
+ *
+ * @v image		Multiboot file
+ * @v hdr		Multiboot header descriptor to fill in
+ * @ret rc		Return status code
+ */
+static int multiboot_find_header ( struct image *image,
+				   struct multiboot_header_info *hdr ) {
+	uint32_t buf[64];
+	size_t offset;
+	unsigned int buf_idx;
+	uint32_t checksum;
+
+	/* Scan through first 8kB of image file 256 bytes at a time.
+	 * (Use the buffering to avoid the overhead of a
+	 * copy_from_user() for every dword.)
+	 */
+	for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) {
+		/* Check for end of image */
+		if ( offset > image->len )
+			break;
+		/* Refill buffer if applicable */
+		buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) );
+		if ( buf_idx == 0 ) {
+			copy_from_user ( buf, image->data, offset,
+					 sizeof ( buf ) );
+		}
+		/* Check signature */
+		if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC )
+			continue;
+		/* Copy header and verify checksum */
+		copy_from_user ( &hdr->mb, image->data, offset,
+				 sizeof ( hdr->mb ) );
+		checksum = ( hdr->mb.magic + hdr->mb.flags +
+			     hdr->mb.checksum );
+		if ( checksum != 0 )
+			continue;
+		/* Record offset of multiboot header and return */
+		hdr->offset = offset;
+		return 0;
+	}
+
+	/* No multiboot header found */
+	return -ENOEXEC;
+}
+
+/**
+ * Load raw multiboot image into memory
+ *
+ * @v image		Multiboot file
+ * @v hdr		Multiboot header descriptor
+ * @ret entry		Entry point
+ * @ret rc		Return status code
+ */
+static int multiboot_load_raw ( struct image *image,
+				struct multiboot_header_info *hdr,
+				physaddr_t *entry ) {
+	size_t offset;
+	size_t filesz;
+	size_t memsz;
+	userptr_t buffer;
+	int rc;
+
+	/* Sanity check */
+	if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) {
+		DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n",
+		       image );
+		return -EINVAL;
+	}
+
+	/* Verify and prepare segment */
+	offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr );
+	filesz = ( hdr->mb.load_end_addr ?
+		   ( hdr->mb.load_end_addr - hdr->mb.load_addr ) :
+		   ( image->len - offset ) );
+	memsz = ( hdr->mb.bss_end_addr ?
+		  ( hdr->mb.bss_end_addr - hdr->mb.load_addr ) : filesz );
+	buffer = phys_to_user ( hdr->mb.load_addr );
+	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
+		DBGC ( image, "MULTIBOOT %p could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Copy image to segment */
+	memcpy_user ( buffer, 0, image->data, offset, filesz );
+
+	/* Record execution entry point */
+	*entry = hdr->mb.entry_addr;
+
+	return 0;
+}
+
+/**
+ * Load ELF multiboot image into memory
+ *
+ * @v image		Multiboot file
+ * @ret entry		Entry point
+ * @ret rc		Return status code
+ */
+static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
+	int rc;
+
+	/* Load ELF image*/
+	if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
+		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Execute multiboot image
+ *
+ * @v image		Multiboot image
+ * @ret rc		Return status code
+ */
+static int multiboot_exec ( struct image *image ) {
+	struct multiboot_header_info hdr;
+	physaddr_t entry;
+	int rc;
+
+	/* Locate multiboot header, if present */
+	if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
+		DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
+		       image );
+		return rc;
+	}
+
+	/* Abort if we detect flags that we cannot support */
+	if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
+		DBGC ( image, "MULTIBOOT %p flags %08x not supported\n",
+		       image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
+		return -ENOTSUP;
+	}
+
+	/* There is technically a bit MB_FLAG_RAW to indicate whether
+	 * this is an ELF or a raw image.  In practice, grub will use
+	 * the ELF header if present, and Solaris relies on this
+	 * behaviour.
+	 */
+	if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
+	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
+		return rc;
+
+	/* Populate multiboot information structure */
+	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
+	mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
+			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
+	mb_cmdline_offset = 0;
+	mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
+	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
+				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
+	mbinfo.mods_addr = virt_to_phys ( mbmodules );
+	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
+	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
+
+	/* Multiboot images may not return and have no callback
+	 * interface, so shut everything down prior to booting the OS.
+	 */
+	shutdown_boot();
+
+	/* Build memory map after unhiding bootloader memory regions as part of
+	 * shutting everything down.
+	 */
+	multiboot_build_memmap ( image, &mbinfo, mbmemmap,
+				 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
+
+	/* Jump to OS with flat physical addressing */
+	DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
+	       image, entry );
+	__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
+					   "call *%%edi\n\t"
+					   "popl %%ebp\n\t" )
+			       : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
+			           "b" ( virt_to_phys ( &mbinfo ) ),
+			           "D" ( entry )
+			       : "ecx", "edx", "esi", "memory" );
+
+	DBGC ( image, "MULTIBOOT %p returned\n", image );
+
+	/* It isn't safe to continue after calling shutdown() */
+	while ( 1 ) {}
+
+	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
+}
+
+/**
+ * Probe multiboot image
+ *
+ * @v image		Multiboot file
+ * @ret rc		Return status code
+ */
+static int multiboot_probe ( struct image *image ) {
+	struct multiboot_header_info hdr;
+	int rc;
+
+	/* Locate multiboot header, if present */
+	if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
+		DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
+		       image );
+		return rc;
+	}
+	DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
+	       image, hdr.mb.flags );
+
+	return 0;
+}
+
+/** Multiboot image type */
+struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
+	.name = "Multiboot",
+	.probe = multiboot_probe,
+	.exec = multiboot_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/nbi.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/nbi.c
new file mode 100644
index 0000000..c516bb2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/nbi.c
@@ -0,0 +1,424 @@
+#include <errno.h>
+#include <assert.h>
+#include <realmode.h>
+#include <memsizes.h>
+#include <basemem_packet.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/segment.h>
+#include <ipxe/init.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/fakedhcp.h>
+#include <ipxe/image.h>
+#include <ipxe/features.h>
+
+/** @file
+ *
+ * NBI image format.
+ *
+ * The Net Boot Image format is defined by the "Draft Net Boot Image
+ * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap.  It is now
+ * considered to be a legacy format, but it still included because a
+ * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
+ *
+ * Etherboot does not implement the INT 78 callback interface
+ * described by the NBI specification.  For a callback interface on
+ * x86 architecture, use PXE.
+ *
+ */
+
+FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
+
+/**
+ * An NBI image header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
+struct imgheader {
+	unsigned long magic;		/**< Magic number (NBI_MAGIC) */
+	union {
+		unsigned char length;	/**< Nibble-coded header length */
+		unsigned long flags;	/**< Image flags */
+	};
+	segoff_t location;		/**< 16-bit seg:off header location */
+	union {
+		segoff_t segoff;	/**< 16-bit seg:off entry point */
+		unsigned long linear;	/**< 32-bit entry point */
+	} execaddr;
+} __attribute__ (( packed ));
+
+/** NBI magic number */
+#define NBI_MAGIC 0x1B031336UL
+
+/* Interpretation of the "length" fields */
+#define NBI_NONVENDOR_LENGTH(len)	( ( (len) & 0x0f ) << 2 )
+#define NBI_VENDOR_LENGTH(len)		( ( (len) & 0xf0 ) >> 2 )
+#define NBI_LENGTH(len) ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
+
+/* Interpretation of the "flags" fields */
+#define	NBI_PROGRAM_RETURNS(flags)	( (flags) & ( 1 << 8 ) )
+#define	NBI_LINEAR_EXEC_ADDR(flags)	( (flags) & ( 1 << 31 ) )
+
+/** NBI header length */
+#define NBI_HEADER_LENGTH	512
+
+/**
+ * An NBI segment header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
+struct segheader {
+	unsigned char length;		/**< Nibble-coded header length */
+	unsigned char vendortag;	/**< Vendor-defined private tag */
+	unsigned char reserved;
+	unsigned char flags;		/**< Segment flags */
+	unsigned long loadaddr;		/**< Load address */
+	unsigned long imglength;	/**< Segment length in NBI file */
+	unsigned long memlength;	/**< Segment length in memory */
+};
+
+/* Interpretation of the "flags" fields */
+#define NBI_LOADADDR_FLAGS(flags)	( (flags) & 0x03 )
+#define NBI_LOADADDR_ABS		0x00
+#define NBI_LOADADDR_AFTER		0x01
+#define NBI_LOADADDR_END		0x02
+#define NBI_LOADADDR_BEFORE		0x03
+#define NBI_LAST_SEGHEADER(flags)	( (flags) & ( 1 << 2 ) )
+
+/* Define a type for passing info to a loaded program */
+struct ebinfo {
+	uint8_t  major, minor;  /* Version */
+	uint16_t flags;         /* Bit flags */
+};
+
+/** Info passed to NBI image */
+static struct ebinfo loaderinfo = {
+	VERSION_MAJOR, VERSION_MINOR,
+	0
+};
+
+/**
+ * Prepare a segment for an NBI image
+ *
+ * @v image		NBI image
+ * @v offset		Offset within NBI image
+ * @v filesz		Length of initialised-data portion of the segment
+ * @v memsz		Total length of the segment
+ * @v src		Source for initialised data
+ * @ret rc		Return status code
+ */
+static int nbi_prepare_segment ( struct image *image, size_t offset __unused,
+				 userptr_t dest, size_t filesz, size_t memsz ){
+	int rc;
+
+	if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
+		DBGC ( image, "NBI %p could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Load a segment for an NBI image
+ *
+ * @v image		NBI image
+ * @v offset		Offset within NBI image
+ * @v filesz		Length of initialised-data portion of the segment
+ * @v memsz		Total length of the segment
+ * @v src		Source for initialised data
+ * @ret rc		Return status code
+ */
+static int nbi_load_segment ( struct image *image, size_t offset,
+			      userptr_t dest, size_t filesz,
+			      size_t memsz __unused ) {
+	memcpy_user ( dest, 0, image->data, offset, filesz );
+	return 0;
+}
+
+/**
+ * Process segments of an NBI image
+ *
+ * @v image		NBI image
+ * @v imgheader		Image header information
+ * @v process		Function to call for each segment
+ * @ret rc		Return status code
+ */
+static int nbi_process_segments ( struct image *image,
+				  struct imgheader *imgheader,
+				  int ( * process ) ( struct image *image,
+						      size_t offset,
+						      userptr_t dest,
+						      size_t filesz,
+						      size_t memsz ) ) {
+	struct segheader sh;
+	size_t offset = 0;
+	size_t sh_off;
+	userptr_t dest;
+	size_t filesz;
+	size_t memsz;
+	int rc;
+	
+	/* Copy image header to target location */
+	dest = real_to_user ( imgheader->location.segment,
+			      imgheader->location.offset );
+	filesz = memsz = NBI_HEADER_LENGTH;
+	if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
+		return rc;
+	offset += filesz;
+
+	/* Process segments in turn */
+	sh_off = NBI_LENGTH ( imgheader->length );
+	do {
+		/* Read segment header */
+		copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
+		if ( sh.length == 0 ) {
+			/* Avoid infinite loop? */
+			DBGC ( image, "NBI %p invalid segheader length 0\n",
+			       image );
+			return -ENOEXEC;
+		}
+		
+		/* Calculate segment load address */
+		switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
+		case NBI_LOADADDR_ABS:
+			dest = phys_to_user ( sh.loadaddr );
+			break;
+		case NBI_LOADADDR_AFTER:
+			dest = userptr_add ( dest, memsz + sh.loadaddr );
+			break;
+		case NBI_LOADADDR_BEFORE:
+			dest = userptr_add ( dest, -sh.loadaddr );
+			break;
+		case NBI_LOADADDR_END:
+			/* Not correct according to the spec, but
+			 * maintains backwards compatibility with
+			 * previous versions of Etherboot.
+			 */
+			dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
+					      - sh.loadaddr );
+			break;
+		default:
+			/* Cannot be reached */
+			assert ( 0 );
+		}
+
+		/* Process this segment */
+		filesz = sh.imglength;
+		memsz = sh.memlength;
+		if ( ( offset + filesz ) > image->len ) {
+			DBGC ( image, "NBI %p segment outside file\n", image );
+			return -ENOEXEC;
+		}
+		if ( ( rc = process ( image, offset, dest,
+				      filesz, memsz ) ) != 0 ) {
+			return rc;
+		}
+		offset += filesz;
+
+		/* Next segheader */
+		sh_off += NBI_LENGTH ( sh.length );
+		if ( sh_off >= NBI_HEADER_LENGTH ) {
+			DBGC ( image, "NBI %p header overflow\n", image );
+			return -ENOEXEC;
+		}
+
+	} while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
+
+	if ( offset != image->len ) {
+		DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
+		       image, image->len, offset );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/**
+ * Boot a 16-bit NBI image
+ *
+ * @v imgheader		Image header information
+ * @ret rc		Return status code, if image returns
+ */
+static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
+	int discard_D, discard_S, discard_b;
+	int rc;
+
+	DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
+	       imgheader->execaddr.segoff.segment,
+	       imgheader->execaddr.segoff.offset );
+
+	__asm__ __volatile__ (
+		REAL_CODE ( "pushw %%ds\n\t"	/* far pointer to bootp data */
+			    "pushw %%bx\n\t"
+			    "pushl %%esi\n\t"	/* location */
+			    "pushw %%cs\n\t"	/* lcall execaddr */
+			    "call 1f\n\t"
+			    "jmp 2f\n\t"
+			    "\n1:\n\t"
+			    "pushl %%edi\n\t"
+			    "lret\n\t"
+			    "\n2:\n\t"
+			    "addw $8,%%sp\n\t"	/* clean up stack */ )
+		: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
+		  "=b" ( discard_b )
+		: "D" ( imgheader->execaddr.segoff ),
+		  "S" ( imgheader->location ),
+		  "b" ( __from_data16 ( basemem_packet ) )
+		: "ecx", "edx", "ebp" );
+
+	return rc;
+}
+
+/**
+ * Boot a 32-bit NBI image
+ *
+ * @v imgheader		Image header information
+ * @ret rc		Return status code, if image returns
+ */
+static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
+	int discard_D, discard_S, discard_b;
+	int rc;
+
+	DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
+	       image, imgheader->execaddr.linear );
+
+	/* Jump to OS with flat physical addressing */
+	__asm__ __volatile__ (
+		PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
+			    "pushl %%esi\n\t" /* imgheader */
+			    "pushl %%eax\n\t" /* loaderinfo */
+			    "call *%%edi\n\t"
+			    "addl $12, %%esp\n\t" /* clean up stack */ )
+		: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
+		  "=b" ( discard_b )
+		: "D" ( imgheader->execaddr.linear ),
+		  "S" ( ( imgheader->location.segment << 4 ) +
+			imgheader->location.offset ),
+		  "b" ( virt_to_phys ( basemem_packet ) ),
+		  "a" ( virt_to_phys ( &loaderinfo ) )
+		: "ecx", "edx", "ebp", "memory" );
+
+	return rc;
+}
+
+/**
+ * Prepare DHCP parameter block for NBI image
+ *
+ * @v image		NBI image
+ * @ret rc		Return status code
+ */
+static int nbi_prepare_dhcp ( struct image *image ) {
+	struct net_device *boot_netdev;
+	int rc;
+
+	boot_netdev = last_opened_netdev();
+	if ( ! boot_netdev ) {
+		DBGC ( image, "NBI %p could not identify a network device\n",
+		       image );
+		return -ENODEV;
+	}
+
+	if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
+					 sizeof ( basemem_packet ) ) ) != 0 ) {
+		DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Execute a loaded NBI image
+ *
+ * @v image		NBI image
+ * @ret rc		Return status code
+ */
+static int nbi_exec ( struct image *image ) {
+	struct imgheader imgheader;
+	int may_return;
+	int rc;
+
+	/* Retrieve image header */
+	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
+
+	DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
+	       imgheader.location.segment, imgheader.location.offset );
+
+	/* NBI files can have overlaps between segments; the bss of
+	 * one segment may overlap the initialised data of another.  I
+	 * assume this is a design flaw, but there are images out
+	 * there that we need to work with.  We therefore do two
+	 * passes: first to initialise the segments, then to copy the
+	 * data.  This avoids zeroing out already-copied data.
+	 */
+	if ( ( rc = nbi_process_segments ( image, &imgheader,
+					   nbi_prepare_segment ) ) != 0 )
+		return rc;
+	if ( ( rc = nbi_process_segments ( image, &imgheader,
+					   nbi_load_segment ) ) != 0 )
+		return rc;
+
+	/* Prepare DHCP option block */
+	if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
+		return rc;
+
+	/* Shut down now if NBI image will not return */
+	may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
+	if ( ! may_return )
+		shutdown_boot();
+
+	/* Execute NBI image */
+	if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
+		rc = nbi_boot32 ( image, &imgheader );
+	} else {
+	        rc = nbi_boot16 ( image, &imgheader );
+	}
+
+	if ( ! may_return ) {
+		/* Cannot continue after shutdown() called */
+		DBGC ( image, "NBI %p returned %d from non-returnable image\n",
+		       image, rc  );
+		while ( 1 ) {}
+	}
+
+	DBGC ( image, "NBI %p returned %d\n", image, rc );
+
+	return rc;
+}
+
+/**
+ * Probe NBI image
+ *
+ * @v image		NBI image
+ * @ret rc		Return status code
+ */
+static int nbi_probe ( struct image *image ) {
+	struct imgheader imgheader;
+
+	/* If we don't have enough data give up */
+	if ( image->len < NBI_HEADER_LENGTH ) {
+		DBGC ( image, "NBI %p too short for an NBI image\n", image );
+		return -ENOEXEC;
+	}
+
+	/* Check image header */
+	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
+	if ( imgheader.magic != NBI_MAGIC ) {
+		DBGC ( image, "NBI %p has no NBI signature\n", image );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/** NBI image type */
+struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "NBI",
+	.probe = nbi_probe,
+	.exec = nbi_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/image/pxe_image.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/pxe_image.c
new file mode 100644
index 0000000..bdccc93
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/image/pxe_image.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * PXE image format
+ *
+ */
+
+#include <pxe.h>
+#include <pxe_call.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/segment.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
+
+/**
+ * Execute PXE image
+ *
+ * @v image		PXE image
+ * @ret rc		Return status code
+ */
+static int pxe_exec ( struct image *image ) {
+	userptr_t buffer = real_to_user ( 0, 0x7c00 );
+	struct net_device *netdev;
+	int rc;
+
+	/* Verify and prepare segment */
+	if ( ( rc = prep_segment ( buffer, image->len, image->len ) ) != 0 ) {
+		DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Copy image to segment */
+	memcpy_user ( buffer, 0, image->data, 0, image->len );
+
+	/* Arbitrarily pick the most recently opened network device */
+	if ( ( netdev = last_opened_netdev() ) == NULL ) {
+		DBGC ( image, "IMAGE %p could not locate PXE net device\n",
+		       image );
+		return -ENODEV;
+	}
+
+	/* Activate PXE */
+	pxe_activate ( netdev );
+
+	/* Start PXE NBP */
+	rc = pxe_start_nbp();
+
+	/* Deactivate PXE */
+	pxe_deactivate();
+
+	return rc;
+}
+
+/**
+ * Probe PXE image
+ *
+ * @v image		PXE file
+ * @ret rc		Return status code
+ */
+int pxe_probe ( struct image *image ) {
+
+	/* Images too large to fit in base memory cannot be PXE
+	 * images.  We include this check to help prevent unrecognised
+	 * images from being marked as PXE images, since PXE images
+	 * have no signature we can check against.
+	 */
+	if ( image->len > ( 0xa0000 - 0x7c00 ) )
+		return -ENOEXEC;
+
+	/* Rejecting zero-length images is also useful, since these
+	 * end up looking to the user like bugs in iPXE.
+	 */
+	if ( ! image->len )
+		return -ENOEXEC;
+
+	return 0;
+}
+
+/** PXE image type */
+struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
+	.name = "PXE",
+	.probe = pxe_probe,
+	.exec = pxe_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem.h
new file mode 100644
index 0000000..c477c7f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem.h
@@ -0,0 +1,35 @@
+#ifndef _BASEMEM_H
+#define _BASEMEM_H
+
+/** @file
+ *
+ * Base memory allocation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Read the BIOS free base memory counter
+ *
+ * @ret fbms		Free base memory counter (in kB)
+ */
+static inline unsigned int get_fbms ( void ) {
+	uint16_t fbms;
+
+	get_real ( fbms, BDA_SEG, BDA_FBMS );
+	return fbms;
+}
+
+extern void set_fbms ( unsigned int new_fbms );
+
+/* Actually in hidemem.c, but putting it here avoids polluting the
+ * architecture-independent include/hidemem.h.
+ */
+extern void hide_basemem ( void );
+
+#endif /* _BASEMEM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem_packet.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem_packet.h
new file mode 100644
index 0000000..3cb4776
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/basemem_packet.h
@@ -0,0 +1,15 @@
+#ifndef BASEMEM_PACKET_H
+#define BASEMEM_PACKET_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+
+/** Maximum length of base memory packet buffer */
+#define BASEMEM_PACKET_LEN 1514
+
+/** Base memory packet buffer */
+extern char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
+#define basemem_packet __use_data16 ( basemem_packet )
+
+#endif /* BASEMEM_PACKET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios.h
new file mode 100644
index 0000000..70bb73d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios.h
@@ -0,0 +1,10 @@
+#ifndef BIOS_H
+#define BIOS_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define BDA_SEG 0x0040
+#define BDA_FBMS 0x0013
+#define BDA_NUM_DRIVES 0x0075
+
+#endif /* BIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios_disks.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios_disks.h
new file mode 100644
index 0000000..0dd7c4e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bios_disks.h
@@ -0,0 +1,69 @@
+#ifndef BIOS_DISKS_H
+#define BIOS_DISKS_H
+
+#include "dev.h"
+
+/*
+ * Constants
+ *
+ */
+
+#define	BIOS_DISK_MAX_NAME_LEN	6
+
+struct bios_disk_sector {
+	char data[512];
+};
+
+/*
+ * The location of a BIOS disk
+ *
+ */
+struct bios_disk_loc {
+	uint8_t drive;
+};
+
+/*
+ * A physical BIOS disk device
+ *
+ */
+struct bios_disk_device {
+	char name[BIOS_DISK_MAX_NAME_LEN];
+	uint8_t drive;
+	uint8_t type;
+};
+
+/*
+ * A BIOS disk driver, with a valid device ID range and naming
+ * function.
+ *
+ */
+struct bios_disk_driver {
+	void ( *fill_drive_name ) ( char *buf, uint8_t drive );
+	uint8_t min_drive;
+	uint8_t max_drive;
+};
+
+/*
+ * Define a BIOS disk driver
+ *
+ */
+#define BIOS_DISK_DRIVER( _name, _fill_drive_name, _min_drive, _max_drive )   \
+	static struct bios_disk_driver _name = {			      \
+		.fill_drive_name = _fill_drive_name,			      \
+		.min_drive = _min_drive,				      \
+		.max_drive = _max_drive,				      \
+	}
+
+/*
+ * Functions in bios_disks.c
+ *
+ */
+
+
+/*
+ * bios_disk bus global definition
+ *
+ */
+extern struct bus_driver bios_disk_driver;
+
+#endif /* BIOS_DISKS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/biosint.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/biosint.h
new file mode 100644
index 0000000..ab466af
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/biosint.h
@@ -0,0 +1,33 @@
+#ifndef BIOSINT_H
+#define BIOSINT_H
+
+/**
+ * @file BIOS interrupts
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+
+struct segoff;
+
+/**
+ * Hooked interrupt count
+ *
+ * At exit, after unhooking all possible interrupts, this counter
+ * should be examined.  If it is non-zero, it means that we failed to
+ * unhook at least one interrupt vector, and so must not free up the
+ * memory we are using.  (Note that this also implies that we should
+ * re-hook INT 15 in order to hide ourselves from the memory map).
+ */
+extern uint16_t __text16 ( hooked_bios_interrupts );
+#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts )
+
+extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
+				  struct segoff *chain_vector );
+extern int unhook_bios_interrupt ( unsigned int interrupt,
+				   unsigned int handler,
+				   struct segoff *chain_vector );
+
+#endif /* BIOSINT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/byteswap.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/byteswap.h
new file mode 100644
index 0000000..ddbd40e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/byteswap.h
@@ -0,0 +1,43 @@
+#ifndef ETHERBOOT_BITS_BYTESWAP_H
+#define ETHERBOOT_BITS_BYTESWAP_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+static inline __attribute__ ((always_inline, const)) uint16_t
+__bswap_variable_16(uint16_t x)
+{
+	__asm__("xchgb %b0,%h0\n\t"
+		: "=q" (x)
+		: "0" (x));
+	return x;
+}
+
+static inline __attribute__ ((always_inline, const)) uint32_t
+__bswap_variable_32(uint32_t x)
+{
+	__asm__("xchgb %b0,%h0\n\t"
+		"rorl $16,%0\n\t"
+		"xchgb %b0,%h0"
+		: "=q" (x)
+		: "0" (x));
+	return x;
+}
+
+static inline __attribute__ ((always_inline, const)) uint64_t
+__bswap_variable_64(uint64_t x)
+{
+	union {
+		uint64_t qword;
+		uint32_t dword[2]; 
+	} u;
+
+	u.qword = x;
+	u.dword[0] = __bswap_variable_32(u.dword[0]);
+	u.dword[1] = __bswap_variable_32(u.dword[1]);
+	__asm__("xchgl %0,%1"
+		: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
+		: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
+	return u.qword;
+}
+
+#endif /* ETHERBOOT_BITS_BYTESWAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/compiler.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/compiler.h
new file mode 100644
index 0000000..000db0c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/compiler.h
@@ -0,0 +1,27 @@
+#ifndef _BITS_COMPILER_H
+#define _BITS_COMPILER_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef ASSEMBLY
+
+/** Declare a function with standard calling conventions */
+#define __asmcall __attribute__ (( cdecl, regparm(0) ))
+
+/**
+ * Declare a function with libgcc implicit linkage
+ *
+ * It seems as though gcc expects its implicit arithmetic functions to
+ * be cdecl, even if -mrtd is specified.  This is somewhat
+ * inconsistent; for example, if -mregparm=3 is used then the implicit
+ * functions do become regparm(3).
+ *
+ * The implicit calls to memcpy() and memset() which gcc can generate
+ * do not seem to have this inconsistency; -mregparm and -mrtd affect
+ * them in the same way as any other function.
+ */
+#define __libgcc __attribute__ (( cdecl ))
+
+#endif /* ASSEMBLY */
+
+#endif /* _BITS_COMPILER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/cpu.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/cpu.h
new file mode 100644
index 0000000..83339dd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/cpu.h
@@ -0,0 +1,86 @@
+#ifndef I386_BITS_CPU_H
+#define I386_BITS_CPU_H
+
+/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+#define X86_FEATURE_FPU		0 /* Onboard FPU */
+#define X86_FEATURE_VME		1 /* Virtual Mode Extensions */
+#define X86_FEATURE_DE		2 /* Debugging Extensions */
+#define X86_FEATURE_PSE 	3 /* Page Size Extensions */
+#define X86_FEATURE_TSC		4 /* Time Stamp Counter */
+#define X86_FEATURE_MSR		5 /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE		6 /* Physical Address Extensions */
+#define X86_FEATURE_MCE		7 /* Machine Check Architecture */
+#define X86_FEATURE_CX8		8 /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC	9 /* Onboard APIC */
+#define X86_FEATURE_SEP		11 /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR	12 /* Memory Type Range Registers */
+#define X86_FEATURE_PGE		13 /* Page Global Enable */
+#define X86_FEATURE_MCA		14 /* Machine Check Architecture */
+#define X86_FEATURE_CMOV	15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT		16 /* Page Attribute Table */
+#define X86_FEATURE_PSE36	17 /* 36-bit PSEs */
+#define X86_FEATURE_PN		18 /* Processor serial number */
+#define X86_FEATURE_CLFLSH	19 /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES	21 /* Debug Trace Store */
+#define X86_FEATURE_ACPI	22 /* ACPI via MSR */
+#define X86_FEATURE_MMX		23 /* Multimedia Extensions */
+#define X86_FEATURE_FXSR	24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
+				          /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM		25 /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2	26 /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP	27 /* CPU self snoop */
+#define X86_FEATURE_HT		28 /* Hyper-Threading */
+#define X86_FEATURE_ACC		29 /* Automatic clock control */
+#define X86_FEATURE_IA64	30 /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL	11 /* SYSCALL/SYSRET */
+#define X86_FEATURE_MMXEXT	22 /* AMD MMX extensions */
+#define X86_FEATURE_LM		29 /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT	30 /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW	31 /* 3DNow! */
+
+/** x86 CPU information */
+struct cpuinfo_x86 {
+	/** CPU features */
+	unsigned int features;
+	/** 64-bit CPU features */
+	unsigned int amd_features;
+};
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF	0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF	0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF	0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF	0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF	0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF	0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF	0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF	0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF	0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL	0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT	0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF	0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM	0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC	0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF	0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */
+
+/*
+ * Generic CPUID function
+ */
+static inline __attribute__ (( always_inline )) void
+cpuid ( int op, unsigned int *eax, unsigned int *ebx,
+	unsigned int *ecx, unsigned int *edx ) {
+	__asm__ ( "cpuid" :
+		  "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
+		: "0" ( op ) );
+}
+
+extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
+
+#endif /* I386_BITS_CPU_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/endian.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/endian.h
new file mode 100644
index 0000000..8418854
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/endian.h
@@ -0,0 +1,8 @@
+#ifndef ETHERBOOT_BITS_ENDIAN_H
+#define ETHERBOOT_BITS_ENDIAN_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/errfile.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/errfile.h
new file mode 100644
index 0000000..32b8a08
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/errfile.h
@@ -0,0 +1,42 @@
+#ifndef _BITS_ERRFILE_H
+#define _BITS_ERRFILE_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @addtogroup errfile Error file identifiers
+ * @{
+ */
+
+#define ERRFILE_memtop_umalloc	( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
+#define ERRFILE_memmap		( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
+#define ERRFILE_pnpbios		( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
+#define ERRFILE_bios_smbios	( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
+#define ERRFILE_biosint		( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
+#define ERRFILE_int13		( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
+#define ERRFILE_pxeparent	( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
+
+#define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
+#define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
+#define ERRFILE_eltorito       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00020000 )
+#define ERRFILE_multiboot      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_nbi	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_pxe_image      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
+#define ERRFILE_elfboot	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00060000 )
+#define ERRFILE_comboot        ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 )
+#define ERRFILE_com32          ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
+#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
+#define ERRFILE_comboot_call   ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
+
+#define ERRFILE_undi		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
+#define ERRFILE_undiload	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
+#define ERRFILE_undinet		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00020000 )
+#define ERRFILE_undionly	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
+#define ERRFILE_undirom		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
+
+#define ERRFILE_timer_rdtsc    ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
+#define ERRFILE_timer_bios     ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
+
+/** @} */
+
+#endif /* _BITS_ERRFILE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/io.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/io.h
new file mode 100644
index 0000000..f3ecf89
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/io.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * i386-specific I/O API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/x86_io.h>
+
+#endif /* _BITS_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/linux_api.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/linux_api.h
new file mode 100644
index 0000000..dc6e741
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/linux_api.h
@@ -0,0 +1,6 @@
+#ifndef _I386_LINUX_API_H
+#define _I386_LINUX_API_H
+
+#define __SYSCALL_mmap __NR_mmap2
+
+#endif /* _I386_LINUX_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/nap.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/nap.h
new file mode 100644
index 0000000..64066e6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/nap.h
@@ -0,0 +1,15 @@
+#ifndef _BITS_NAP_H
+#define _BITS_NAP_H
+
+/** @file
+ *
+ * i386-specific CPU sleeping API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bios_nap.h>
+#include <ipxe/efi/efix86_nap.h>
+
+#endif /* _BITS_MAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/sanboot.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/sanboot.h
new file mode 100644
index 0000000..9c77a4d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/sanboot.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_SANBOOT_H
+#define _BITS_SANBOOT_H
+
+/** @file
+ *
+ * i386-specific sanboot API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bios_sanboot.h>
+
+#endif /* _BITS_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/smbios.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/smbios.h
new file mode 100644
index 0000000..cc79eec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/smbios.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_SMBIOS_H
+#define _BITS_SMBIOS_H
+
+/** @file
+ *
+ * i386-specific SMBIOS API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bios_smbios.h>
+
+#endif /* _BITS_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/stdint.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/stdint.h
new file mode 100644
index 0000000..8edf131
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/stdint.h
@@ -0,0 +1,23 @@
+#ifndef _BITS_STDINT_H
+#define _BITS_STDINT_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+typedef __SIZE_TYPE__		size_t;
+typedef signed long		ssize_t;
+typedef signed long		off_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short		uint16_t;
+typedef unsigned int		uint32_t;
+typedef unsigned long long	uint64_t;
+
+typedef signed char		int8_t;
+typedef signed short		int16_t;
+typedef signed int		int32_t;
+typedef signed long long	int64_t;
+
+typedef unsigned long		physaddr_t;
+typedef unsigned long		intptr_t;
+
+#endif /* _BITS_STDINT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/timer.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/timer.h
new file mode 100644
index 0000000..50b676b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/timer.h
@@ -0,0 +1,15 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * i386-specific timer API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bios_timer.h>
+#include <ipxe/rdtsc_timer.h>
+
+#endif /* _BITS_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/uaccess.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/uaccess.h
new file mode 100644
index 0000000..2bb52e0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_UACCESS_H
+#define _BITS_UACCESS_H
+
+/** @file
+ *
+ * i386-specific user access API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <librm.h>
+
+#endif /* _BITS_UACCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/umalloc.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/umalloc.h
new file mode 100644
index 0000000..54fb006
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bits/umalloc.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_UMALLOC_H
+#define _BITS_UMALLOC_H
+
+/** @file
+ *
+ * i386-specific user memory allocation API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/memtop_umalloc.h>
+
+#endif /* _BITS_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bochs.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bochs.h
new file mode 100644
index 0000000..9d090fc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bochs.h
@@ -0,0 +1,34 @@
+#ifndef BOCHS_H
+#define BOCHS_H
+
+/** @file
+ *
+ * bochs breakpoints
+ *
+ * This file defines @c bochsbp, the magic breakpoint instruction that
+ * is incredibly useful when debugging under bochs.  This file should
+ * never be included in production code.
+ *
+ * Use the pseudo-instruction @c bochsbp in assembly code, or the
+ * bochsbp() function in C code.
+ *
+ */
+
+#ifdef ASSEMBLY
+
+/* Breakpoint for when debugging under bochs */
+#define bochsbp xchgw %bx, %bx
+#define BOCHSBP bochsbp
+
+#else /* ASSEMBLY */
+
+/** Breakpoint for when debugging under bochs */
+static inline void bochsbp ( void ) {
+	__asm__ __volatile__ ( "xchgw %bx, %bx" );
+}
+
+#endif /* ASSEMBLY */
+
+#warning "bochs.h should not be included into production code"
+
+#endif /* BOCHS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bootsector.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bootsector.h
new file mode 100644
index 0000000..8730fbf
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bootsector.h
@@ -0,0 +1,14 @@
+#ifndef _BOOTSECTOR_H
+#define _BOOTSECTOR_H
+
+/** @file
+ *
+ * x86 bootsector image format
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern int call_bootsector ( unsigned int segment, unsigned int offset,
+			     unsigned int drive );
+
+#endif /* _BOOTSECTOR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bzimage.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bzimage.h
new file mode 100644
index 0000000..7e42e31
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/bzimage.h
@@ -0,0 +1,142 @@
+#ifndef _BZIMAGE_H
+#define _BZIMAGE_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/**
+ * A bzImage header
+ *
+ * As documented in Documentation/i386/boot.txt
+ */
+struct bzimage_header {
+	/** The size of the setup in sectors
+	 *
+	 * If this field contains 0, assume it contains 4.
+	 */
+	uint8_t setup_sects;
+	/** If set, the root is mounted readonly */
+	uint16_t root_flags;
+	/** DO NOT USE - for bootsect.S use only */
+	uint16_t syssize;
+	/** DO NOT USE - obsolete */
+	uint16_t swap_dev;
+	/** DO NOT USE - for bootsect.S use only */
+	uint16_t ram_size;
+	/** Video mode control */
+	uint16_t vid_mode;
+	/** Default root device number */
+	uint16_t root_dev;
+	/** 0xAA55 magic number */
+	uint16_t boot_flag;
+	/** Jump instruction */
+	uint16_t jump;
+	/** Magic signature "HdrS" */
+	uint32_t header;
+	/** Boot protocol version supported */
+	uint16_t version;
+	/** Boot loader hook (see below) */
+	uint32_t realmode_swtch;
+	/** The load-low segment (0x1000) (obsolete) */
+	uint16_t start_sys;
+	/** Pointer to kernel version string */
+	uint16_t kernel_version;
+	/** Boot loader identifier */
+	uint8_t type_of_loader;
+	/** Boot protocol option flags */
+	uint8_t loadflags;
+	/** Move to high memory size (used with hooks) */
+	uint16_t setup_move_size;
+	/** Boot loader hook (see below) */
+	uint32_t code32_start;
+	/** initrd load address (set by boot loader) */
+	uint32_t ramdisk_image;
+	/** initrd size (set by boot loader) */
+	uint32_t ramdisk_size;
+	/** DO NOT USE - for bootsect.S use only */
+	uint32_t bootsect_kludge;
+	/** Free memory after setup end */
+	uint16_t heap_end_ptr;
+	/** Unused */
+	uint16_t pad1;
+	/** 32-bit pointer to the kernel command line */
+	uint32_t cmd_line_ptr;
+	/** Highest legal initrd address */
+	uint32_t initrd_addr_max;
+	/** Physical addr alignment required for kernel	*/
+	uint32_t kernel_alignment;
+	/** Whether kernel is relocatable or not */
+	uint8_t relocatable_kernel;
+	/** Unused */
+	uint8_t pad2[3];
+	/** Maximum size of the kernel command line */
+	uint32_t cmdline_size;
+} __attribute__ (( packed ));
+
+/** Offset of bzImage header within kernel image */
+#define BZI_HDR_OFFSET 0x1f1
+
+/** bzImage boot flag value */
+#define BZI_BOOT_FLAG 0xaa55
+
+/** bzImage magic signature value */
+#define BZI_SIGNATURE 0x53726448
+
+/** bzImage boot loader identifier for Etherboot */
+#define BZI_LOADER_TYPE_ETHERBOOT 0x40
+
+/** bzImage boot loader identifier for iPXE
+ *
+ * We advertise ourselves as Etherboot version 6.
+ */
+#define BZI_LOADER_TYPE_IPXE ( BZI_LOADER_TYPE_ETHERBOOT | 0x06 )
+
+/** bzImage "load high" flag */
+#define BZI_LOAD_HIGH 0x01
+
+/** Load address for high-loaded kernels */
+#define BZI_LOAD_HIGH_ADDR 0x100000
+
+/** Load address for low-loaded kernels */
+#define BZI_LOAD_LOW_ADDR 0x10000
+
+/** bzImage "kernel can use heap" flag */
+#define BZI_CAN_USE_HEAP 0x80
+
+/** bzImage special video mode "normal" */
+#define BZI_VID_MODE_NORMAL 0xffff
+
+/** bzImage special video mode "ext" */
+#define BZI_VID_MODE_EXT 0xfffe
+
+/** bzImage special video mode "ask" */
+#define BZI_VID_MODE_ASK 0xfffd
+
+/** bzImage maximum initrd address for versions < 2.03 */
+#define BZI_INITRD_MAX 0x37ffffff
+
+/** bzImage command-line structure used by older kernels */
+struct bzimage_cmdline {
+	/** Magic signature */
+	uint16_t magic;
+	/** Offset to command line */
+	uint16_t offset;
+} __attribute__ (( packed ));
+
+/** Offset of bzImage command-line structure within kernel image */
+#define BZI_CMDLINE_OFFSET 0x20
+
+/** bzImage command line present magic marker value */
+#define BZI_CMDLINE_MAGIC 0xa33f
+
+/** Assumed size of real-mode portion (including .bss) */
+#define BZI_ASSUMED_RM_SIZE 0x8000
+
+/** Amount of stack space to provide */
+#define BZI_STACK_SIZE 0x1000
+
+/** Maximum size of command line */
+#define BZI_CMDLINE_SIZE 0x7ff
+
+#endif /* _BZIMAGE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/comboot.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/comboot.h
new file mode 100644
index 0000000..b343413
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/comboot.h
@@ -0,0 +1,177 @@
+#ifndef COMBOOT_H
+#define COMBOOT_H
+
+/**
+ * @file
+ *
+ * SYSLINUX COMBOOT
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <setjmp.h>
+#include <ipxe/in.h>
+
+/** Descriptor in a 32-bit IDT */
+struct idt_descriptor {
+	uint16_t offset_low;
+	uint16_t selector;
+	uint16_t flags;
+	uint16_t offset_high;
+} __attribute__ (( packed ));
+
+/** Operand for the LIDT instruction */
+struct idt_register {
+	uint16_t limit;
+	uint32_t base;
+} __attribute__ (( packed ));
+
+/** Entry in the interrupt jump buffer */
+struct ijb_entry {
+	uint8_t pusha_instruction;
+	uint8_t mov_instruction;
+	uint8_t mov_value;
+	uint8_t jump_instruction;
+	uint32_t jump_destination;
+} __attribute__ (( packed ));
+
+/** The x86 opcode for "pushal" */
+#define IJB_PUSHA 0x60
+
+/** The x86 opcode for "movb $imm8,%al" */
+#define IJB_MOV_AL_IMM8 0xB0
+
+/** The x86 opcode for "jmp rel32" */
+#define IJB_JMP_REL32 0xE9
+
+/** Flags that specify a 32-bit interrupt gate with DPL=0 */
+#define IDT_INTERRUPT_GATE_FLAGS 0x8E00
+
+/** Address of COM32 interrupt descriptor table */
+#define COM32_IDT 0x100000
+
+/** Number of entries in a fully populated IDT */
+#define COM32_NUM_IDT_ENTRIES 256
+
+/** Address of COM32 interrupt jump buffer */
+#define COM32_IJB 0x100800
+
+/** Segment used for COMBOOT PSP and image */
+#define COMBOOT_PSP_SEG 0x07C0
+
+/** Entry point address of COM32 images */
+#define COM32_START_PHYS 0x101000
+
+/** COM32 bounce buffer segment */
+#define COM32_BOUNCE_SEG 0x07C0
+
+/** Size of SYSLINUX file block in bytes */
+#define COMBOOT_FILE_BLOCKSZ 512
+
+/** COMBOOT feature flags (INT 22h AX=15h) */
+#define COMBOOT_FEATURE_LOCAL_BOOT (1 << 0)
+#define COMBOOT_FEATURE_IDLE_LOOP  (1 << 1)
+
+/** Maximum number of shuffle descriptors for 
+ * shuffle and boot functions
+ * (INT 22h AX=0012h, 001Ah, 001Bh)
+ */
+#define COMBOOT_MAX_SHUFFLE_DESCRIPTORS 682
+
+typedef union {
+	uint32_t l;
+	uint16_t w[2];
+	uint8_t  b[4];
+} com32_reg32_t;
+
+typedef struct {
+	uint16_t gs;                /* Offset  0 */
+	uint16_t fs;                /* Offset  2 */
+	uint16_t es;                /* Offset  4 */
+	uint16_t ds;                /* Offset  6 */
+
+	com32_reg32_t edi;          /* Offset  8 */
+	com32_reg32_t esi;          /* Offset 12 */
+	com32_reg32_t ebp;          /* Offset 16 */
+	com32_reg32_t _unused_esp;  /* Offset 20 */
+	com32_reg32_t ebx;          /* Offset 24 */
+	com32_reg32_t edx;          /* Offset 28 */
+	com32_reg32_t ecx;          /* Offset 32 */
+	com32_reg32_t eax;          /* Offset 36 */
+
+	com32_reg32_t eflags;       /* Offset 40 */
+} com32sys_t;
+
+typedef struct {
+	uint32_t eax;               /* Offset  0 */
+	uint32_t ecx;               /* Offset  4 */
+	uint32_t edx;               /* Offset  8 */
+	uint32_t ebx;               /* Offset 12 */
+	uint32_t esp;               /* Offset 16 */
+	uint32_t ebp;               /* Offset 20 */
+	uint32_t esi;               /* Offset 24 */
+	uint32_t edi;               /* Offset 28 */
+
+	uint32_t eip;               /* Offset 32 */
+} syslinux_pm_regs;
+
+typedef struct {
+	uint16_t es;                /* Offset  0 */
+	uint16_t _unused_cs;        /* Offset  2 */
+	uint16_t ds;                /* Offset  4 */
+	uint16_t ss;                /* Offset  6 */
+	uint16_t fs;                /* Offset  8 */
+	uint16_t gs;                /* Offset 10 */
+
+	uint32_t eax;                /* Offset 12 */
+	uint32_t ecx;                /* Offset 16 */
+	uint32_t edx;                /* Offset 20 */
+	uint32_t ebx;                /* Offset 24 */
+	uint32_t esp;                /* Offset 28 */
+	uint32_t ebp;                /* Offset 32 */
+	uint32_t esi;                /* Offset 36 */
+	uint32_t edi;                /* Offset 40 */
+
+	uint16_t ip;                /* Offset 44 */
+	uint16_t cs;                /* Offset 46 */
+} syslinux_rm_regs;
+
+typedef struct {
+	uint32_t dest;
+	uint32_t src;
+	uint32_t len;
+} comboot_shuffle_descriptor;
+
+extern void hook_comboot_interrupts ( );
+extern void unhook_comboot_interrupts ( );
+
+/* These are not the correct prototypes, but it doens't matter, 
+ * as we only ever get the address of these functions;
+ * they are only called from COM32 code running in PHYS_CODE
+ */
+extern void com32_intcall_wrapper ( );
+extern void com32_farcall_wrapper ( );
+extern void com32_cfarcall_wrapper ( );
+extern void com32_irq_wrapper ( );
+
+/* Resolve a hostname to an (IPv4) address */
+extern int comboot_resolv ( const char *name, struct in_addr *address );
+
+/* setjmp/longjmp context buffer used to return after loading an image */
+extern rmjmp_buf comboot_return;
+
+extern void *com32_external_esp;
+
+#define COMBOOT_EXIT 1
+#define COMBOOT_EXIT_RUN_KERNEL 2
+#define COMBOOT_EXIT_COMMAND 3
+
+extern void comboot_force_text_mode ( void );
+
+#define COMBOOT_VIDEO_GRAPHICS    0x01
+#define COMBOOT_VIDEO_NONSTANDARD 0x02
+#define COMBOOT_VIDEO_VESA        0x04
+#define COMBOOT_VIDEO_NOTEXT      0x08
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
new file mode 100644
index 0000000..902caff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DHCP_ARCH_H
+#define _DHCP_ARCH_H
+
+/** @file
+ *
+ * Architecture-specific DHCP options
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/dhcp.h>
+
+#define DHCP_ARCH_VENDOR_CLASS_ID \
+	DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',      \
+		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '6', ':', \
+		      'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
+
+#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 6 )
+
+#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/fakee820.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/fakee820.h
new file mode 100644
index 0000000..9d00fb6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/fakee820.h
@@ -0,0 +1,9 @@
+#ifndef _FAKEE820_H
+#define _FAKEE820_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern void fake_e820 ( void );
+extern void unfake_e820 ( void );
+
+#endif /* _FAKEE820_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/gdbmach.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/gdbmach.h
new file mode 100644
index 0000000..794dab1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/gdbmach.h
@@ -0,0 +1,64 @@
+#ifndef GDBMACH_H
+#define GDBMACH_H
+
+/** @file
+ *
+ * GDB architecture specifics
+ *
+ * This file declares functions for manipulating the machine state and
+ * debugging context.
+ *
+ */
+
+#include <stdint.h>
+
+typedef unsigned long gdbreg_t;
+
+/* The register snapshot, this must be in sync with interrupt handler and the
+ * GDB protocol. */
+enum {
+	GDBMACH_EAX,
+	GDBMACH_ECX,
+	GDBMACH_EDX,
+	GDBMACH_EBX,
+	GDBMACH_ESP,
+	GDBMACH_EBP,
+	GDBMACH_ESI,
+	GDBMACH_EDI,
+	GDBMACH_EIP,
+	GDBMACH_EFLAGS,
+	GDBMACH_CS,
+	GDBMACH_SS,
+	GDBMACH_DS,
+	GDBMACH_ES,
+	GDBMACH_FS,
+	GDBMACH_GS,
+	GDBMACH_NREGS,
+	GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
+};
+
+/* Breakpoint types */
+enum {
+	GDBMACH_BPMEM,
+	GDBMACH_BPHW,
+	GDBMACH_WATCH,
+	GDBMACH_RWATCH,
+	GDBMACH_AWATCH,
+};
+
+static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
+	regs [ GDBMACH_EIP ] = pc;
+}
+
+static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
+	regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
+	regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
+}
+
+static inline void gdbmach_breakpoint ( void ) {
+	__asm__ __volatile__ ( "int $3\n" );
+}
+
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
+
+#endif /* GDBMACH_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/int13.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/int13.h
new file mode 100644
index 0000000..a14ebb2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/int13.h
@@ -0,0 +1,267 @@
+#ifndef INT13_H
+#define INT13_H
+
+/** @file
+ *
+ * INT 13 emulation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/edd.h>
+#include <realmode.h>
+
+/**
+ * @defgroup int13ops INT 13 operation codes
+ * @{
+ */
+
+/** Reset disk system */
+#define INT13_RESET			0x00
+/** Get status of last operation */
+#define INT13_GET_LAST_STATUS		0x01
+/** Read sectors */
+#define INT13_READ_SECTORS		0x02
+/** Write sectors */
+#define INT13_WRITE_SECTORS		0x03
+/** Get drive parameters */
+#define INT13_GET_PARAMETERS		0x08
+/** Get disk type */
+#define INT13_GET_DISK_TYPE		0x15
+/** Extensions installation check */
+#define INT13_EXTENSION_CHECK		0x41
+/** Extended read */
+#define INT13_EXTENDED_READ		0x42
+/** Extended write */
+#define INT13_EXTENDED_WRITE		0x43
+/** Verify sectors */
+#define INT13_EXTENDED_VERIFY		0x44
+/** Extended seek */
+#define INT13_EXTENDED_SEEK		0x47
+/** Get extended drive parameters */
+#define INT13_GET_EXTENDED_PARAMETERS	0x48
+/** Get CD-ROM status / terminate emulation */
+#define INT13_CDROM_STATUS_TERMINATE	0x4b
+
+/** @} */
+
+/**
+ * @defgroup int13status INT 13 status codes
+ * @{
+ */
+
+/** Operation completed successfully */
+#define INT13_STATUS_SUCCESS		0x00
+/** Invalid function or parameter */
+#define INT13_STATUS_INVALID		0x01
+/** Read error */
+#define INT13_STATUS_READ_ERROR		0x04
+/** Reset failed */
+#define INT13_STATUS_RESET_FAILED	0x05
+/** Write error */
+#define INT13_STATUS_WRITE_ERROR	0xcc
+
+/** @} */
+
+/** Block size for non-extended INT 13 calls */
+#define INT13_BLKSIZE 512
+
+/** An INT 13 disk address packet */
+struct int13_disk_address {
+	/** Size of the packet, in bytes */
+	uint8_t bufsize;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** Block count */
+	uint8_t count;
+	/** Reserved */
+	uint8_t reserved_b;
+	/** Data buffer */
+	struct segoff buffer;
+	/** Starting block number */
+	uint64_t lba;
+	/** Data buffer (EDD 3.0+ only) */
+	uint64_t buffer_phys;
+	/** Block count (EDD 4.0+ only) */
+	uint32_t long_count;
+	/** Reserved */
+	uint32_t reserved_c;
+} __attribute__ (( packed ));
+
+/** INT 13 disk parameters */
+struct int13_disk_parameters {
+	/** Size of this structure */
+	uint16_t bufsize;
+	/** Flags */
+	uint16_t flags;
+	/** Number of cylinders */
+	uint32_t cylinders;
+	/** Number of heads */
+	uint32_t heads;
+	/** Number of sectors per track */
+	uint32_t sectors_per_track;
+	/** Total number of sectors on drive */
+	uint64_t sectors;
+	/** Bytes per sector */
+	uint16_t sector_size;
+	/** Device parameter table extension */
+	struct segoff dpte;
+	/** Device path information */
+	struct edd_device_path_information dpi;
+} __attribute__ (( packed ));
+
+/**
+ * @defgroup int13types INT 13 disk types
+ * @{
+ */
+
+/** No such drive */
+#define INT13_DISK_TYPE_NONE	0x00
+/** Floppy without change-line support */
+#define INT13_DISK_TYPE_FDD	0x01
+/** Floppy with change-line support */
+#define INT13_DISK_TYPE_FDD_CL	0x02
+/** Hard disk */
+#define INT13_DISK_TYPE_HDD	0x03
+
+/** @} */
+
+/**
+ * @defgroup int13flags INT 13 disk parameter flags
+ * @{
+ */
+
+/** DMA boundary errors handled transparently */
+#define INT13_FL_DMA_TRANSPARENT 0x01
+/** CHS information is valid */
+#define INT13_FL_CHS_VALID	 0x02
+/** Removable drive */
+#define INT13_FL_REMOVABLE	 0x04
+/** Write with verify supported */
+#define INT13_FL_VERIFIABLE	 0x08
+/** Has change-line supported (valid only for removable drives) */
+#define INT13_FL_CHANGE_LINE	 0x10
+/** Drive can be locked (valid only for removable drives) */
+#define INT13_FL_LOCKABLE	 0x20
+/** CHS is max possible, not current media (valid only for removable drives) */
+#define INT13_FL_CHS_MAX	 0x40
+
+/** @} */
+
+/**
+ * @defgroup int13exts INT 13 extension flags
+ * @{
+ */
+
+/** Extended disk access functions supported */
+#define INT13_EXTENSION_LINEAR		0x01
+/** Removable drive functions supported */
+#define INT13_EXTENSION_REMOVABLE	0x02
+/** EDD functions supported */
+#define INT13_EXTENSION_EDD		0x04
+/** 64-bit extensions are present */
+#define INT13_EXTENSION_64BIT		0x08
+
+/** @} */
+
+/**
+ * @defgroup int13vers INT 13 extension versions
+ * @{
+ */
+
+/** INT13 extensions version 1.x */
+#define INT13_EXTENSION_VER_1_X		0x01
+/** INT13 extensions version 2.0 (EDD-1.0) */
+#define INT13_EXTENSION_VER_2_0		0x20
+/** INT13 extensions version 2.1 (EDD-1.1) */
+#define INT13_EXTENSION_VER_2_1		0x21
+/** INT13 extensions version 3.0 (EDD-3.0) */
+#define INT13_EXTENSION_VER_3_0		0x30
+
+/** @} */ 
+
+/** Maximum number of sectors for which CHS geometry is allowed to be valid
+ *
+ * This number is taken from the EDD specification.
+ */
+#define INT13_MAX_CHS_SECTORS		15482880
+
+/** Bootable CD-ROM specification packet */
+struct int13_cdrom_specification {
+	/** Size of packet in bytes */
+	uint8_t size;
+	/** Boot media type */
+	uint8_t media_type;
+	/** Drive number */
+	uint8_t drive;
+	/** CD-ROM controller number */
+	uint8_t controller;
+	/** LBA of disk image to emulate */
+	uint32_t lba;
+	/** Device specification */
+	uint16_t device;
+	/** Segment of 3K buffer for caching CD-ROM reads */
+	uint16_t cache_segment;
+	/** Load segment for initial boot image */
+	uint16_t load_segment;
+	/** Number of 512-byte sectors to load */
+	uint16_t load_sectors;
+	/** Low 8 bits of cylinder number */
+	uint8_t cyl;
+	/** Sector number, plus high 2 bits of cylinder number */
+	uint8_t cyl_sector;
+	/** Head number */
+	uint8_t head;
+} __attribute__ (( packed ));
+
+/** A C/H/S address within a partition table entry */
+struct partition_chs {
+	/** Head number */
+	uint8_t head;
+	/** Sector number, plus high 2 bits of cylinder number */
+	uint8_t cyl_sector;
+	/** Low 8 bits of cylinder number */
+	uint8_t cyl;
+} __attribute__ (( packed ));
+
+#define PART_HEAD(chs) ( (chs).head )
+#define PART_SECTOR(chs) ( (chs).cyl_sector & 0x3f )
+#define PART_CYLINDER(chs) ( (chs).cyl | ( ( (chs).cyl_sector & 0xc0 ) << 2 ) )
+
+/** A partition table entry within the MBR */
+struct partition_table_entry {
+	/** Bootable flag */
+	uint8_t bootable;
+	/** C/H/S start address */
+	struct partition_chs chs_start;
+	/** System indicator (partition type) */
+	uint8_t type;
+	/** C/H/S end address */
+	struct partition_chs chs_end;
+	/** Linear start address */
+	uint32_t start;
+	/** Linear length */
+	uint32_t length;
+} __attribute__ (( packed ));
+
+/** A Master Boot Record */
+struct master_boot_record {
+	/** Code area */
+	uint8_t code[440];
+	/** Disk signature */
+	uint32_t signature;
+	/** Padding */
+	uint8_t pad[2];
+	/** Partition table */
+	struct partition_table_entry partitions[4];
+	/** 0x55aa MBR signature */
+	uint16_t magic;
+} __attribute__ (( packed ));
+
+/** Use natural BIOS drive number */
+#define INT13_USE_NATURAL_DRIVE 0xff
+
+#endif /* INT13_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
new file mode 100644
index 0000000..5b684c0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_BIOS_NAP_H
+#define _IPXE_BIOS_NAP_H
+
+/** @file
+ *
+ * BIOS CPU sleeping
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef NAP_PCBIOS
+#define NAP_PREFIX_pcbios
+#else
+#define NAP_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _IPXE_BIOS_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
new file mode 100644
index 0000000..0979454
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_BIOS_SANBOOT_H
+#define _IPXE_BIOS_SANBOOT_H
+
+/** @file
+ *
+ * Standard PC-BIOS sanboot interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef SANBOOT_PCBIOS
+#define SANBOOT_PREFIX_pcbios
+#else
+#define SANBOOT_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _IPXE_BIOS_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
new file mode 100644
index 0000000..d8c7f64
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_BIOS_SMBIOS_H
+#define _IPXE_BIOS_SMBIOS_H
+
+/** @file
+ *
+ * Standard PC-BIOS SMBIOS interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef SMBIOS_PCBIOS
+#define SMBIOS_PREFIX_pcbios
+#else
+#define SMBIOS_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _IPXE_BIOS_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
new file mode 100644
index 0000000..f9fc804
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
@@ -0,0 +1,44 @@
+#ifndef _IPXE_BIOS_TIMER_H
+#define _IPXE_BIOS_TIMER_H
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIMER_PCBIOS
+#define TIMER_PREFIX_pcbios
+#else
+#define TIMER_PREFIX_pcbios __pcbios_
+#endif
+
+#include <ipxe/timer2.h>
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs		Number of microseconds for which to delay
+ */
+static inline __always_inline void
+TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
+	/* BIOS timer is not high-resolution enough for udelay(), so
+	 * we use timer2
+	 */
+	timer2_udelay ( usecs );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec	Number of ticks per second
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
+	/* BIOS timer ticks over at 18.2 ticks per second */
+	return 18;
+}
+
+#endif /* _IPXE_BIOS_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
new file mode 100644
index 0000000..001648f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_MEMTOP_UMALLOC_H
+#define _IPXE_MEMTOP_UMALLOC_H
+
+/** @file
+ *
+ * External memory allocation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef UMALLOC_MEMTOP
+#define UMALLOC_PREFIX_memtop
+#else
+#define UMALLOC_PREFIX_memtop __memtop_
+#endif
+
+#endif /* _IPXE_MEMTOP_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
new file mode 100644
index 0000000..472e140
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
@@ -0,0 +1,39 @@
+#ifndef _IPXE_RDTSC_TIMER_H
+#define _IPXE_RDTSC_TIMER_H
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIMER_RDTSC
+#define TIMER_PREFIX_rdtsc
+#else
+#define TIMER_PREFIX_rdtsc __rdtsc_
+#endif
+
+/**
+ * RDTSC values can easily overflow an unsigned long.  We discard the
+ * low-order bits in order to obtain sensibly-scaled values.
+ */
+#define TSC_SHIFT 8
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks		Current time, in ticks
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( rdtsc, currticks ) ( void ) {
+	unsigned long ticks;
+
+	__asm__ __volatile__ ( "rdtsc\n\t"
+			       "shrdl %1, %%edx, %%eax\n\t"
+			       : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
+	return ticks;
+}
+
+#endif /* _IPXE_RDTSC_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/timer2.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/timer2.h
new file mode 100644
index 0000000..322a3ed
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/timer2.h
@@ -0,0 +1,14 @@
+#ifndef _IPXE_TIMER2_H
+#define _IPXE_TIMER2_H
+
+/** @file
+ *
+ * Timer chip control
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern void timer2_udelay ( unsigned long usecs );
+
+#endif /* _IPXE_TIMER2_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h
new file mode 100644
index 0000000..a79501e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h
@@ -0,0 +1,153 @@
+#ifndef _IPXE_X86_IO_H
+#define _IPXE_X86_IO_H
+
+/** @file
+ *
+ * iPXE I/O API for x86
+ *
+ * i386 uses direct pointer dereferences for accesses to memory-mapped
+ * I/O space, and the inX/outX instructions for accesses to
+ * port-mapped I/O space.
+ *
+ * 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
+ * and will crash original Pentium and earlier CPUs.  Fortunately, no
+ * hardware that requires atomic 64-bit accesses will physically fit
+ * into a machine with such an old CPU anyway.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef IOAPI_X86
+#define IOAPI_PREFIX_x86
+#else
+#define IOAPI_PREFIX_x86 __x86_
+#endif
+
+/*
+ * Memory space mappings
+ *
+ */
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
+	return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
+	return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+	return phys_to_virt ( bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
+	/* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
+	return virt_to_phys ( io_addr );
+}
+
+/*
+ * MMIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_READX( _api_func, _type )					      \
+static inline __always_inline _type					      \
+IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) {		      \
+	return *io_addr;						      \
+}
+X86_READX ( readb, uint8_t );
+X86_READX ( readw, uint16_t );
+X86_READX ( readl, uint32_t );
+
+#define X86_WRITEX( _api_func, _type )					      \
+static inline __always_inline void					      \
+IOAPI_INLINE ( x86, _api_func ) ( _type data,				      \
+				  volatile _type *io_addr ) {		      \
+	*io_addr = data;						      \
+}
+X86_WRITEX ( writeb, uint8_t );
+X86_WRITEX ( writew, uint16_t );
+X86_WRITEX ( writel, uint32_t );
+
+/*
+ * PIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_INX( _insn_suffix, _type, _reg_prefix )			      \
+static inline __always_inline _type					      \
+IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) {	      \
+	_type data;							      \
+	__asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0"   \
+			       : "=a" ( data ) : "Nd" ( io_addr ) );	      \
+	return data;							      \
+}									      \
+static inline __always_inline void					      \
+IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr,	      \
+					    _type *data,		      \
+					    unsigned int count ) {	      \
+	unsigned int discard_D;						      \
+	__asm__ __volatile__ ( "rep ins" #_insn_suffix			      \
+			       : "=D" ( discard_D )			      \
+			       : "d" ( io_addr ), "c" ( count ),	      \
+				 "0" ( data ) );			      \
+}
+X86_INX ( b, uint8_t, "b" );
+X86_INX ( w, uint16_t, "w" );
+X86_INX ( l, uint32_t, "k" );
+
+#define X86_OUTX( _insn_suffix, _type, _reg_prefix )			      \
+static inline __always_inline void					      \
+IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data,			      \
+					    volatile _type *io_addr ) {	      \
+	__asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1"  \
+			       : : "a" ( data ), "Nd" ( io_addr ) );	      \
+}									      \
+static inline __always_inline void					      \
+IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr,	      \
+					     const _type *data,		      \
+					     unsigned int count ) {	      \
+	unsigned int discard_S;						      \
+	__asm__ __volatile__ ( "rep outs" #_insn_suffix			      \
+			       : "=S" ( discard_S )			      \
+			       : "d" ( io_addr ), "c" ( count ),	      \
+				 "0" ( data ) );			      \
+}
+X86_OUTX ( b, uint8_t, "b" );
+X86_OUTX ( w, uint16_t, "w" );
+X86_OUTX ( l, uint32_t, "k" );
+
+/*
+ * Slow down I/O
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iodelay ) ( void ) {
+	__asm__ __volatile__ ( "outb %al, $0x80" );
+}
+
+/*
+ * Memory barrier
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, mb ) ( void ) {
+	__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
+}
+
+#endif /* _IPXE_X86_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/kir.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/kir.h
new file mode 100644
index 0000000..84633d2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/kir.h
@@ -0,0 +1,18 @@
+#ifndef KIR_H
+#define KIR_H
+
+#ifndef KEEP_IT_REAL
+#error "kir.h can be used only with -DKEEP_IT_REAL"
+#endif
+
+#ifdef ASSEMBLY
+
+#define code32 code16gcc
+
+#else /* ASSEMBLY */
+
+__asm__ ( ".code16gcc" );
+
+#endif /* ASSEMBLY */
+
+#endif /* KIR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/libkir.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/libkir.h
new file mode 100644
index 0000000..1f5b135
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/libkir.h
@@ -0,0 +1,233 @@
+#ifndef LIBKIR_H
+#define LIBKIR_H
+
+#include "realmode.h"
+
+#ifndef ASSEMBLY
+
+/*
+ * Full API documentation for these functions is in realmode.h.
+ *
+ */
+
+/* Access to variables in .data16 and .text16 in a way compatible with librm */
+#define __data16( variable ) variable
+#define __data16_array( variable, array ) variable array
+#define __bss16( variable ) variable
+#define __bss16_array( variable, array ) variable array
+#define __text16( variable ) variable
+#define __text16_array( variable,array ) variable array
+#define __use_data16( variable ) variable
+#define __use_text16( variable ) variable
+#define __from_data16( pointer ) pointer
+#define __from_text16( pointer ) pointer
+
+/* Real-mode data and code segments */
+static inline __attribute__ (( always_inline )) unsigned int _rm_cs ( void ) {
+	uint16_t cs;
+	__asm__ __volatile__ ( "movw %%cs, %w0" : "=r" ( cs ) );
+	return cs;
+}
+
+static inline __attribute__ (( always_inline )) unsigned int _rm_ds ( void ) {
+	uint16_t ds;
+	__asm__ __volatile__ ( "movw %%ds, %w0" : "=r" ( ds ) );
+	return ds;
+}
+
+#define rm_cs ( _rm_cs() )
+#define rm_ds ( _rm_ds() )
+
+/* Copy to/from base memory */
+
+static inline void copy_to_real_libkir ( unsigned int dest_seg,
+					 unsigned int dest_off,
+					 const void *src, size_t n ) {
+	unsigned int discard_D, discard_S, discard_c;
+
+	__asm__ __volatile__ ( "pushw %%es\n\t"
+			       "movw %3, %%es\n\t"
+			       "rep movsb\n\t"
+			       "popw %%es\n\t"
+			       : "=D" ( discard_D ), "=S" ( discard_S ),
+			         "=c" ( discard_c )
+			       : "r" ( dest_seg ), "D" ( dest_off ),
+			         "S" ( src ),
+			         "c" ( n )
+			       : "memory" );
+}
+
+static inline void copy_from_real_libkir ( void *dest,
+					   unsigned int src_seg,
+					   unsigned int src_off,
+					   size_t n ) {
+	unsigned int discard_D, discard_S, discard_c;
+
+	__asm__ __volatile__ ( "pushw %%ds\n\t"
+			       "movw %4, %%ds\n\t"
+			       "rep movsb\n\t"
+			       "popw %%ds\n\t"
+			       : "=D" ( discard_D ), "=S" ( discard_S ),
+			         "=c" ( discard_c )
+			       : "D" ( dest ),
+			         "r" ( src_seg ), "S" ( src_off ),
+			         "c" ( n )
+			       : "memory" );
+}
+
+#define copy_to_real copy_to_real_libkir
+#define copy_from_real copy_from_real_libkir
+
+/*
+ * Transfer individual values to/from base memory.  There may well be
+ * a neater way to do this.  We have two versions: one for constant
+ * offsets (where the mov instruction must be of the form "mov
+ * %es:123, %xx") and one for non-constant offsets (where the mov
+ * instruction must be of the form "mov %es:(%xx), %yx".  If it's
+ * possible to incorporate both forms into one __asm__ instruction, I
+ * don't know how to do it.
+ *
+ * Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
+ * to expand to either "b", "w" or "l" depending on the size of
+ * operand 0.  This would remove the (minor) ambiguity in the mov
+ * instruction.  However, gcc on at least my system barfs with an
+ * "internal compiler error" when confronted with %z0.
+ *
+ */
+
+#define put_real_kir_const_off( var, seg, off )		  		     \
+	__asm__ ( "movw %w1, %%es\n\t"					     \
+		  "mov %0, %%es:%c2\n\t"				     \
+		  "pushw %%ds\n\t" /* restore %es */			     \
+		  "popw %%es\n\t"					     \
+		  :							     \
+		  : "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off )	     \
+		  )
+
+#define put_real_kir_nonconst_off( var, seg, off )	  		     \
+	__asm__ ( "movw %w1, %%es\n\t"					     \
+		  "mov %0, %%es:(%2)\n\t"				     \
+		  "pushw %%ds\n\t" /* restore %es */			     \
+		  "popw %%es\n\t"					     \
+		  :							     \
+		  : "r" ( var ), "rm" ( seg ), "r" ( off )		     \
+		  )
+
+#define put_real_kir( var, seg, off )					     \
+	do {								     \
+	  if ( __builtin_constant_p ( off ) )				     \
+		  put_real_kir_const_off ( var, seg, off );		     \
+	  else								     \
+		  put_real_kir_nonconst_off ( var, seg, off );		     \
+	} while ( 0 )
+
+#define get_real_kir_const_off( var, seg, off )		  		     \
+	__asm__ ( "movw %w1, %%es\n\t"					     \
+		  "mov %%es:%c2, %0\n\t"				     \
+		  "pushw %%ds\n\t" /* restore %es */			     \
+		  "popw %%es\n\t"					     \
+		  : "=r,r" ( var )					     \
+		  : "rm,rm" ( seg ), "i,!r" ( off )			     \
+		  )
+
+#define get_real_kir_nonconst_off( var, seg, off )			     \
+	__asm__ ( "movw %w1, %%es\n\t"					     \
+		  "mov %%es:(%2), %0\n\t"				     \
+		  "pushw %%ds\n\t" /* restore %es */			     \
+		  "popw %%es\n\t"					     \
+		  : "=r" ( var )					     \
+		  : "rm" ( seg ), "r" ( off )				     \
+		  )
+
+#define get_real_kir( var, seg, off )					     \
+	do {								     \
+	  if ( __builtin_constant_p ( off ) )				     \
+		  get_real_kir_const_off ( var, seg, off );		     \
+	  else								     \
+		  get_real_kir_nonconst_off ( var, seg, off );		     \
+	} while ( 0 )
+
+#define put_real put_real_kir
+#define get_real get_real_kir
+
+/**
+ * A pointer to a user buffer
+ *
+ * This is actually a struct segoff, but encoded as a uint32_t to
+ * ensure that gcc passes it around efficiently.
+ */
+typedef uint32_t userptr_t;
+
+/**
+ * Copy data to user buffer
+ *
+ * @v buffer	User buffer
+ * @v offset	Offset within user buffer
+ * @v src	Source
+ * @v len	Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
+	copy_to_real ( ( buffer >> 16 ), ( ( buffer & 0xffff ) + offset ),
+		       src, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest	Destination
+ * @v buffer	User buffer
+ * @v offset	Offset within user buffer
+ * @v len	Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
+	copy_from_real ( dest, ( buffer >> 16 ),
+			 ( ( buffer & 0xffff ) + offset ), len );
+}
+
+/**
+ * Convert segment:offset address to user buffer
+ *
+ * @v segment	Real-mode segment
+ * @v offset	Real-mode offset
+ * @ret buffer	User buffer
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+real_to_user ( unsigned int segment, unsigned int offset ) {
+	return ( ( segment << 16 ) | offset );
+}
+
+/**
+ * Convert virtual address to user buffer
+ *
+ * @v virtual	Virtual address
+ * @ret buffer	User buffer
+ *
+ * This constructs a user buffer from an ordinary pointer.  Use it
+ * when you need to pass a pointer to an internal buffer to a function
+ * that expects a @c userptr_t.
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+virt_to_user ( void * virtual ) {
+	return real_to_user ( rm_ds, ( intptr_t ) virtual );
+}
+
+/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
+#define TEXT16_CODE( asm_code_str )			\
+	".section \".text16\", \"ax\", @progbits\n\t"	\
+	".code16\n\t"					\
+	".arch i386\n\t"				\
+	asm_code_str "\n\t"				\
+	".code16gcc\n\t"				\
+	".previous\n\t"
+
+/* REAL_CODE: declare a fragment of code that executes in real mode */
+#define REAL_CODE( asm_code_str )	\
+	".code16\n\t"			\
+	asm_code_str "\n\t"		\
+	".code16gcc\n\t"
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBKIR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/librm.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/librm.h
new file mode 100644
index 0000000..c6992f6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/librm.h
@@ -0,0 +1,201 @@
+#ifndef LIBRM_H
+#define LIBRM_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* Segment selectors as used in our protected-mode GDTs.
+ *
+ * Don't change these unless you really know what you're doing.
+ */
+
+#define VIRTUAL_CS 0x08
+#define VIRTUAL_DS 0x10
+#define PHYSICAL_CS 0x18
+#define PHYSICAL_DS 0x20
+#define REAL_CS 0x28
+#define REAL_DS 0x30
+#if 0
+#define LONG_CS 0x38
+#define LONG_DS 0x40
+#endif
+
+#ifndef ASSEMBLY
+
+#ifdef UACCESS_LIBRM
+#define UACCESS_PREFIX_librm
+#else
+#define UACCESS_PREFIX_librm __librm_
+#endif
+
+/* Variables in librm.S */
+extern unsigned long virt_offset;
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr		Physical address
+ * @ret userptr		User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
+	return ( phys_addr - virt_offset );
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset from user pointer
+ * @ret phys_addr	Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+	return ( userptr + offset + virt_offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
+	return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+	return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
+	return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
+					userptr_t src, off_t src_off,
+					size_t len ) {
+	trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
+					 userptr_t src, off_t src_off,
+					 size_t len ) {
+	trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
+					int c, size_t len ) {
+	trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
+	return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
+					int c, size_t len ) {
+	return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+
+/******************************************************************************
+ *
+ * Access to variables in .data16 and .text16
+ *
+ */
+
+extern char *data16;
+extern char *text16;
+
+#define __data16( variable )						\
+	__attribute__ (( section ( ".data16" ) ))			\
+	_data16_ ## variable __asm__ ( #variable )
+
+#define __data16_array( variable, array )				\
+	__attribute__ (( section ( ".data16" ) ))			\
+	_data16_ ## variable array __asm__ ( #variable )
+
+#define __bss16( variable )						\
+	__attribute__ (( section ( ".bss16" ) ))			\
+	_data16_ ## variable __asm__ ( #variable )
+
+#define __bss16_array( variable, array )				\
+	__attribute__ (( section ( ".bss16" ) ))			\
+	_data16_ ## variable array __asm__ ( #variable )
+
+#define __text16( variable )						\
+	__attribute__ (( section ( ".text16.data" ) ))			\
+	_text16_ ## variable __asm__ ( #variable )
+
+#define __text16_array( variable, array )				\
+	__attribute__ (( section ( ".text16.data" ) ))			\
+	_text16_ ## variable array __asm__ ( #variable )
+
+#define __use_data16( variable )					\
+	( * ( ( typeof ( _data16_ ## variable ) * )			\
+	      & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
+
+#define __use_text16( variable )					\
+	( * ( ( typeof ( _text16_ ## variable ) * )			\
+	      & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
+
+#define __from_data16( pointer )					\
+	( ( unsigned int )						\
+	  ( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
+
+#define __from_text16( pointer )					\
+	( ( unsigned int )						\
+	  ( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
+
+/* Variables in librm.S, present in the normal data segment */
+extern uint16_t rm_sp;
+extern uint16_t rm_ss;
+extern uint16_t __data16 ( rm_cs );
+#define rm_cs __use_data16 ( rm_cs )
+extern uint16_t __text16 ( rm_ds );
+#define rm_ds __use_text16 ( rm_ds )
+
+/**
+ * Convert segment:offset address to user buffer
+ *
+ * @v segment		Real-mode segment
+ * @v offset		Real-mode offset
+ * @ret buffer		User buffer
+ */
+static inline __always_inline userptr_t
+real_to_user ( unsigned int segment, unsigned int offset ) {
+	return ( phys_to_user ( ( segment << 4 ) + offset ) );
+}
+
+extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
+extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
+
+/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
+#define TEXT16_CODE( asm_code_str )			\
+	".section \".text16\", \"ax\", @progbits\n\t"	\
+	".code16\n\t"					\
+	asm_code_str "\n\t"				\
+	".code32\n\t"					\
+	".previous\n\t"
+
+/* REAL_CODE: declare a fragment of code that executes in real mode */
+#define REAL_CODE( asm_code_str )			\
+	"pushl $1f\n\t"					\
+	"call real_call\n\t"				\
+	"addl $4, %%esp\n\t"				\
+	TEXT16_CODE ( "\n1:\n\t"			\
+		      asm_code_str			\
+		      "\n\t"				\
+		      "ret\n\t" )
+
+/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
+#define PHYS_CODE( asm_code_str )			\
+	"call _virt_to_phys\n\t"			\
+	asm_code_str					\
+	"call _phys_to_virt\n\t"
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBRM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/limits.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/limits.h
new file mode 100644
index 0000000..031b6c5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/limits.h
@@ -0,0 +1,61 @@
+#ifndef LIMITS_H
+#define LIMITS_H	1
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* Number of bits in a `char' */
+#define CHAR_BIT	8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN	(-128)
+#define SCHAR_MAX	127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX	255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN	SCHAR_MIN
+#define CHAR_MAX	SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN	(-32768)
+#define SHRT_MAX	32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX	65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN		(-INT_MAX - 1)
+#define INT_MAX		2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX	4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MAX		2147483647
+#define INT_MIN		(-INT_MAX - 1)
+
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX	4294967295U
+
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX	2147483647
+#define LONG_MIN	(-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX	4294967295UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX	9223372036854775807LL
+#define LLONG_MIN	(-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX	18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/memsizes.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/memsizes.h
new file mode 100644
index 0000000..7b21749
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/memsizes.h
@@ -0,0 +1,19 @@
+#ifndef _MEMSIZES_H
+#define _MEMSIZES_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <basemem.h>
+
+/**
+ * Get size of base memory from BIOS free base memory counter
+ *
+ * @ret basemem		Base memory size, in kB
+ */
+static inline unsigned int basememsize ( void ) {
+	return get_fbms();
+}
+
+extern unsigned int extmemsize ( void );
+
+#endif /* _MEMSIZES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/multiboot.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/multiboot.h
new file mode 100644
index 0000000..44614c7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/multiboot.h
@@ -0,0 +1,149 @@
+#ifndef _MULTIBOOT_H
+#define _MULTIBOOT_H
+
+/**
+ * @file
+ *
+ * Multiboot operating systems
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** The magic number for the Multiboot header */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/** Boot modules must be page aligned */
+#define MB_FLAG_PGALIGN 0x00000001
+
+/** Memory map must be provided */
+#define MB_FLAG_MEMMAP 0x00000002
+
+/** Video mode information must be provided */
+#define MB_FLAG_VIDMODE 0x00000004
+
+/** Image is a raw multiboot image (not ELF) */
+#define MB_FLAG_RAW 0x00010000
+
+/**
+ * The magic number passed by a Multiboot-compliant boot loader
+ *
+ * Must be passed in register %eax when jumping to the Multiboot OS
+ * image.
+ */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/** Multiboot information structure mem_* fields are valid */
+#define MBI_FLAG_MEM 0x00000001
+
+/** Multiboot information structure boot_device field is valid */
+#define MBI_FLAG_BOOTDEV 0x00000002
+
+/** Multiboot information structure cmdline field is valid */
+#define MBI_FLAG_CMDLINE 0x00000004
+
+/** Multiboot information structure module fields are valid */
+#define MBI_FLAG_MODS 0x00000008
+
+/** Multiboot information structure a.out symbol table is valid */
+#define MBI_FLAG_AOUT 0x00000010
+
+/** Multiboot information struture ELF section header table is valid */
+#define MBI_FLAG_ELF 0x00000020
+
+/** Multiboot information structure memory map is valid */
+#define MBI_FLAG_MMAP 0x00000040
+
+/** Multiboot information structure drive list is valid */
+#define MBI_FLAG_DRIVES 0x00000080
+
+/** Multiboot information structure ROM configuration field is valid */
+#define MBI_FLAG_CFGTBL 0x00000100
+
+/** Multiboot information structure boot loader name field is valid */
+#define MBI_FLAG_LOADER 0x00000200
+
+/** Multiboot information structure APM table is valid */
+#define MBI_FLAG_APM 0x00000400
+
+/** Multiboot information structure video information is valid */
+#define MBI_FLAG_VBE 0x00000800
+
+/** A multiboot header */
+struct multiboot_header {
+	uint32_t magic;
+	uint32_t flags;
+	uint32_t checksum;
+	uint32_t header_addr;
+	uint32_t load_addr;
+	uint32_t load_end_addr;
+	uint32_t bss_end_addr;
+	uint32_t entry_addr;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot a.out symbol table */
+struct multiboot_aout_symbol_table {
+	uint32_t tabsize;
+	uint32_t strsize;
+	uint32_t addr;
+	uint32_t reserved;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot ELF section header table */
+struct multiboot_elf_section_header_table {
+	uint32_t num;
+	uint32_t size;
+	uint32_t addr;
+	uint32_t shndx;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot information structure */
+struct multiboot_info {
+	uint32_t flags;
+	uint32_t mem_lower;
+	uint32_t mem_upper;
+	uint32_t boot_device;
+	uint32_t cmdline;
+	uint32_t mods_count;
+	uint32_t mods_addr;
+	union {
+		struct multiboot_aout_symbol_table aout_syms;
+		struct multiboot_elf_section_header_table elf_sections;
+	} syms;
+	uint32_t mmap_length;
+	uint32_t mmap_addr;
+	uint32_t drives_length;
+	uint32_t drives_addr;
+	uint32_t config_table;
+	uint32_t boot_loader_name;
+	uint32_t apm_table;
+	uint32_t vbe_control_info;
+	uint32_t vbe_mode_info;
+	uint16_t vbe_mode;
+	uint16_t vbe_interface_seg;
+	uint16_t vbe_interface_off;
+	uint16_t vbe_interface_len;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot module structure */
+struct multiboot_module {
+	uint32_t mod_start;
+	uint32_t mod_end;
+	uint32_t string;
+	uint32_t reserved;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot memory map entry */
+struct multiboot_memory_map {
+	uint32_t size;
+	uint64_t base_addr;
+	uint64_t length;
+	uint32_t type;
+} __attribute__ (( packed, may_alias ));
+
+/** Usable RAM */
+#define MBMEM_RAM 1
+
+#endif /* _MULTIBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
new file mode 100644
index 0000000..822b3eb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DHCP_ARCH_H
+#define _DHCP_ARCH_H
+
+/** @file
+ *
+ * Architecture-specific DHCP options
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/dhcp.h>
+
+#define DHCP_ARCH_VENDOR_CLASS_ID \
+	DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',      \
+		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':', \
+		      'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' )
+
+#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 0 )
+
+#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ )
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pic8259.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pic8259.h
new file mode 100644
index 0000000..f8e20c4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pic8259.h
@@ -0,0 +1,71 @@
+/*
+ * Basic support for controlling the 8259 Programmable Interrupt Controllers.
+ *
+ * Initially written by Michael Brown (mcb30).
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef PIC8259_H
+#define PIC8259_H
+
+/* For segoff_t */
+#include "realmode.h"
+
+#define IRQ_PIC_CUTOFF 8
+
+/* 8259 register locations */
+#define PIC1_ICW1 0x20
+#define PIC1_OCW2 0x20
+#define PIC1_OCW3 0x20
+#define PIC1_ICR 0x20
+#define PIC1_IRR 0x20
+#define PIC1_ISR 0x20
+#define PIC1_ICW2 0x21
+#define PIC1_ICW3 0x21
+#define PIC1_ICW4 0x21
+#define PIC1_IMR 0x21
+#define PIC2_ICW1 0xa0
+#define PIC2_OCW2 0xa0
+#define PIC2_OCW3 0xa0
+#define PIC2_ICR 0xa0
+#define PIC2_IRR 0xa0
+#define PIC2_ISR 0xa0
+#define PIC2_ICW2 0xa1
+#define PIC2_ICW3 0xa1
+#define PIC2_ICW4 0xa1
+#define PIC2_IMR 0xa1
+
+/* Register command values */
+#define OCW3_ID 0x08
+#define OCW3_READ_IRR 0x03
+#define OCW3_READ_ISR 0x02
+#define ICR_EOI_NON_SPECIFIC 0x20
+#define ICR_EOI_NOP 0x40
+#define ICR_EOI_SPECIFIC 0x60
+#define ICR_EOI_SET_PRIORITY 0xc0
+
+/* Macros to enable/disable IRQs */
+#define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
+#define IMR_BIT(x) ( 1 << ( (x) % IRQ_PIC_CUTOFF ) )
+#define irq_enabled(x) ( ( inb ( IMR_REG(x) ) & IMR_BIT(x) ) == 0 )
+#define enable_irq(x) outb ( inb( IMR_REG(x) ) & ~IMR_BIT(x), IMR_REG(x) )
+#define disable_irq(x) outb ( inb( IMR_REG(x) ) | IMR_BIT(x), IMR_REG(x) )
+
+/* Macros for acknowledging IRQs */
+#define ICR_REG( irq ) ( (irq) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
+#define ICR_VALUE( irq ) ( (irq) % IRQ_PIC_CUTOFF )
+#define CHAINED_IRQ 2
+
+/* Utility macros to convert IRQ numbers to INT numbers and INT vectors  */
+#define IRQ_INT( irq ) ( ( ( (irq) - IRQ_PIC_CUTOFF ) ^ 0x70 ) & 0x7f )
+
+/* Other constants */
+#define IRQ_MAX 15
+#define IRQ_NONE -1U
+
+/* Function prototypes
+ */
+void send_eoi ( unsigned int irq );
+
+#endif /* PIC8259_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pnpbios.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pnpbios.h
new file mode 100644
index 0000000..4c20e73
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pnpbios.h
@@ -0,0 +1,17 @@
+#ifndef _PNPBIOS_H
+#define _PNPBIOS_H
+
+/** @file
+ *
+ * PnP BIOS
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* BIOS segment address */
+#define BIOS_SEG 0xf000
+
+extern int find_pnp_bios ( void );
+
+#endif /* _PNPBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe.h
new file mode 100644
index 0000000..909c8d8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe.h
@@ -0,0 +1,152 @@
+#ifndef PXE_H
+#define PXE_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "pxe_types.h"
+#include "pxe_api.h"
+#include <ipxe/device.h>
+
+/* Parameter block for pxenv_unknown() */
+struct s_PXENV_UNKNOWN {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNKNOWN PXENV_UNKNOWN_t;
+
+/* Union used for PXE API calls; we don't know the type of the
+ * structure until we interpret the opcode.  Also, Status is available
+ * in the same location for any opcode, and it's convenient to have
+ * non-specific access to it.
+ */
+union u_PXENV_ANY {
+	/* Make it easy to read status for any operation */
+	PXENV_STATUS_t				Status;
+	struct s_PXENV_UNKNOWN			unknown;
+	struct s_PXENV_UNLOAD_STACK		unload_stack;
+	struct s_PXENV_GET_CACHED_INFO		get_cached_info;
+	struct s_PXENV_TFTP_READ_FILE		restart_tftp;
+	struct s_PXENV_START_UNDI		start_undi;
+	struct s_PXENV_STOP_UNDI		stop_undi;
+	struct s_PXENV_START_BASE		start_base;
+	struct s_PXENV_STOP_BASE		stop_base;
+	struct s_PXENV_TFTP_OPEN		tftp_open;
+	struct s_PXENV_TFTP_CLOSE		tftp_close;
+	struct s_PXENV_TFTP_READ		tftp_read;
+	struct s_PXENV_TFTP_READ_FILE		tftp_read_file;
+	struct s_PXENV_TFTP_GET_FSIZE		tftp_get_fsize;
+	struct s_PXENV_UDP_OPEN			udp_open;
+	struct s_PXENV_UDP_CLOSE		udp_close;
+	struct s_PXENV_UDP_WRITE		udp_write;
+	struct s_PXENV_UDP_READ			udp_read;
+	struct s_PXENV_UNDI_STARTUP		undi_startup;
+	struct s_PXENV_UNDI_CLEANUP		undi_cleanup;
+	struct s_PXENV_UNDI_INITIALIZE		undi_initialize;
+	struct s_PXENV_UNDI_RESET		undi_reset_adapter;
+	struct s_PXENV_UNDI_SHUTDOWN		undi_shutdown;
+	struct s_PXENV_UNDI_OPEN		undi_open;
+	struct s_PXENV_UNDI_CLOSE		undi_close;
+	struct s_PXENV_UNDI_TRANSMIT		undi_transmit;
+	struct s_PXENV_UNDI_SET_MCAST_ADDRESS	undi_set_mcast_address;
+	struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address;
+	struct s_PXENV_UNDI_SET_PACKET_FILTER	undi_set_packet_filter;
+	struct s_PXENV_UNDI_GET_INFORMATION	undi_get_information;
+	struct s_PXENV_UNDI_GET_STATISTICS	undi_get_statistics;
+	struct s_PXENV_UNDI_CLEAR_STATISTICS	undi_clear_statistics;
+	struct s_PXENV_UNDI_INITIATE_DIAGS	undi_initiate_diags;
+	struct s_PXENV_UNDI_FORCE_INTERRUPT	undi_force_interrupt;
+	struct s_PXENV_UNDI_GET_MCAST_ADDRESS	undi_get_mcast_address;
+	struct s_PXENV_UNDI_GET_NIC_TYPE	undi_get_nic_type;
+	struct s_PXENV_UNDI_GET_IFACE_INFO	undi_get_iface_info;
+	struct s_PXENV_UNDI_GET_STATE		undi_get_state;
+	struct s_PXENV_UNDI_ISR			undi_isr;
+	struct s_PXENV_FILE_OPEN		file_open;
+	struct s_PXENV_FILE_CLOSE		file_close;
+	struct s_PXENV_FILE_SELECT		file_select;
+	struct s_PXENV_FILE_READ		file_read;
+	struct s_PXENV_GET_FILE_SIZE		get_file_size;
+	struct s_PXENV_FILE_EXEC		file_exec;
+	struct s_PXENV_FILE_API_CHECK		file_api_check;
+	struct s_PXENV_FILE_EXIT_HOOK		file_exit_hook;
+};
+
+typedef union u_PXENV_ANY PXENV_ANY_t;
+
+/** An UNDI expansion ROM header */
+struct undi_rom_header {
+	/** Signature
+	 *
+	 * Must be equal to @c ROM_SIGNATURE
+	 */
+	UINT16_t Signature;
+	/** ROM length in 512-byte blocks */
+	UINT8_t ROMLength;
+	/** Unused */
+	UINT8_t unused[0x13];
+	/** Offset of the PXE ROM ID structure */
+	UINT16_t PXEROMID;
+	/** Offset of the PCI ROM structure */
+	UINT16_t PCIRHeader;
+} __attribute__ (( packed ));
+
+/** Signature for an expansion ROM */
+#define ROM_SIGNATURE 0xaa55
+
+/** An UNDI ROM ID structure */
+struct undi_rom_id {
+	/** Signature
+	 *
+	 * Must be equal to @c UNDI_ROM_ID_SIGNATURE
+	 */
+	UINT32_t Signature;
+	/** Length of structure */
+	UINT8_t StructLength;
+	/** Checksum */
+	UINT8_t StructCksum;
+	/** Structure revision
+	 *
+	 * Must be zero.
+	 */
+	UINT8_t StructRev;
+	/** UNDI revision
+	 *
+	 * Version 2.1.0 is encoded as the byte sequence 0x00, 0x01, 0x02.
+	 */
+	UINT8_t UNDIRev[3];
+	/** Offset to UNDI loader */
+	UINT16_t UNDILoader;
+	/** Minimum required stack segment size */
+	UINT16_t StackSize;
+	/** Minimum required data segment size */
+	UINT16_t DataSize;
+	/** Minimum required code segment size */
+	UINT16_t CodeSize;
+} __attribute__ (( packed ));
+
+/** Signature for an UNDI ROM ID structure */
+#define UNDI_ROM_ID_SIGNATURE \
+	( ( 'U' << 0 ) + ( 'N' << 8 ) + ( 'D' << 16 ) + ( 'I' << 24 ) )
+
+/** A PCI expansion header */
+struct pcir_header {
+	/** Signature
+	 *
+	 * Must be equal to @c PCIR_SIGNATURE
+	 */
+	uint32_t signature;
+	/** PCI vendor ID */
+	uint16_t vendor_id;
+	/** PCI device ID */
+	uint16_t device_id;
+} __attribute__ (( packed ));
+
+/** Signature for an UNDI ROM ID structure */
+#define PCIR_SIGNATURE \
+	( ( 'P' << 0 ) + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) )
+
+
+extern struct net_device *pxe_netdev;
+
+extern void pxe_set_netdev ( struct net_device *netdev );
+
+#endif /* PXE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_api.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_api.h
new file mode 100644
index 0000000..9b40187
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_api.h
@@ -0,0 +1,1909 @@
+#ifndef PXE_API_H
+#define PXE_API_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * As an alternative, at your option, you may use this file under the
+ * following terms, known as the "MIT license":
+ *
+ * Copyright (c) 2005-2009 Michael Brown <mbrown at fensystems.co.uk>
+ *
+ * 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.
+ */
+
+/** @file
+ *
+ * Preboot eXecution Environment (PXE) API
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "pxe_types.h"
+
+/** @addtogroup pxe Preboot eXecution Environment (PXE) API
+ *  @{
+ */
+
+/** @defgroup pxe_api_call PXE entry points
+ *
+ * PXE entry points and calling conventions
+ *
+ *  @{
+ */
+
+/** The PXENV+ structure */
+struct s_PXENV {
+	/** Signature
+	 *
+	 * Contains the bytes 'P', 'X', 'E', 'N', 'V', '+'.
+	 */
+	UINT8_t		Signature[6];
+	/** PXE API version
+	 *
+	 * MSB is major version number, LSB is minor version number.
+	 * If the API version number is 0x0201 or greater, the !PXE
+	 * structure pointed to by #PXEPtr should be used instead of
+	 * this data structure.
+	 */
+	UINT16_t	Version;
+	UINT8_t		Length;		/**< Length of this structure */
+	/** Checksum
+	 *
+	 * The byte checksum of this structure (using the length in
+	 * #Length) must be zero.
+	 */
+	UINT8_t		Checksum;
+	SEGOFF16_t	RMEntry;	/**< Real-mode PXENV+ entry point */
+	/** Protected-mode PXENV+ entry point offset
+	 *
+	 * PXE 2.1 deprecates this entry point.  For protected-mode
+	 * API calls, use the !PXE structure pointed to by #PXEPtr
+	 * instead.
+	 */
+	UINT32_t	PMOffset;
+	/** Protected-mode PXENV+ entry point segment selector
+	 *
+	 * PXE 2.1 deprecates this entry point.  For protected-mode
+	 * API calls, use the !PXE structure pointed to by #PXEPtr
+	 * instead.
+	 */
+	SEGSEL_t	PMSelector;
+	SEGSEL_t	StackSeg;	/**< Stack segment selector */
+	UINT16_t	StackSize;	/**< Stack segment size */
+	SEGSEL_t	BC_CodeSeg;	/**< Base-code code segment selector */
+	UINT16_t	BC_CodeSize;	/**< Base-code code segment size */
+	SEGSEL_t	BC_DataSeg;	/**< Base-code data segment selector */
+	UINT16_t	BC_DataSize;	/**< Base-code data segment size */
+	SEGSEL_t	UNDIDataSeg;	/**< UNDI data segment selector */
+	UINT16_t	UNDIDataSize;	/**< UNDI data segment size */
+	SEGSEL_t	UNDICodeSeg;	/**< UNDI code segment selector */
+	UINT16_t	UNDICodeSize;	/**< UNDI code segment size */
+	/** Address of the !PXE structure
+	 *
+	 * This field is present only if #Version is 0x0201 or
+	 * greater.  If present, it points to a struct s_PXE.
+	 */
+	SEGOFF16_t	PXEPtr;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV PXENV_t;
+
+/** The !PXE structure */
+struct s_PXE {
+	/** Signature
+	 *
+	 * Contains the bytes '!', 'P', 'X', 'E'.
+	 */
+	UINT8_t		Signature[4];
+	UINT8_t		StructLength;	/**< Length of this structure */
+	/** Checksum
+	 *
+	 * The byte checksum of this structure (using the length in
+	 * #StructLength) must be zero.
+	 */
+	UINT8_t		StructCksum;
+	/** Revision of this structure
+	 *
+	 * For PXE version 2.1, this field must be zero.
+	 */
+	UINT8_t		StructRev;
+	UINT8_t		reserved_1;	/**< Must be zero */
+	/** Address of the UNDI ROM ID structure
+	 *
+	 * This is a pointer to a struct s_UNDI_ROM_ID.
+	 */
+	SEGOFF16_t	UNDIROMID;
+	/** Address of the Base Code ROM ID structure
+	 *
+	 * This is a pointer to a struct s_BC_ROM_ID.
+	 */
+	SEGOFF16_t	BaseROMID;
+	/** 16-bit !PXE entry point
+	 *
+	 * This is the entry point for either real mode, or protected
+	 * mode with a 16-bit stack segment.
+	 */
+	SEGOFF16_t	EntryPointSP;
+	/** 32-bit !PXE entry point
+	 *
+	 * This is the entry point for protected mode with a 32-bit
+	 * stack segment.
+	 */
+	SEGOFF16_t	EntryPointESP;
+	/** Status call-out function
+	 *
+	 * @v 0		(if in a time-out loop)
+	 * @v n		Number of a received TFTP packet
+	 * @ret 0	Continue operation
+	 * @ret 1	Cancel operation
+	 *
+	 * This function will be called whenever the PXE stack is in
+	 * protected mode, is waiting for an event (e.g. a DHCP reply)
+	 * and wishes to allow the user to cancel the operation.
+	 * Parameters are passed in register %ax; the return value
+	 * must also be placed in register %ax.  All other registers
+	 * and flags @b must be preserved.
+	 *
+	 * In real mode, an internal function (that checks for a
+	 * keypress) will be used.
+	 *
+	 * If this field is set to -1, no status call-out function
+	 * will be used and consequently the user will not be allowed
+	 * to interrupt operations.
+	 *
+	 * @note The PXE specification version 2.1 defines the
+	 * StatusCallout field, mentions it 11 times, but nowhere
+	 * defines what it actually does or how it gets called.
+	 * Fortunately, the WfM specification version 1.1a deigns to
+	 * inform us of such petty details.
+	 */
+	SEGOFF16_t	StatusCallout;
+	UINT8_t		reserved_2;	/**< Must be zero */
+	/** Number of segment descriptors
+	 *
+	 * If this number is greater than 7, the remaining descriptors
+	 * follow immediately after #BC_CodeWrite.
+	 */
+	UINT8_t		SegDescCnt;
+	/** First protected-mode selector
+	 *
+	 * This is the segment selector value for the first segment
+	 * assigned to PXE.  Protected-mode selectors must be
+	 * consecutive, according to the PXE 2.1 specification, though
+	 * no reason is given.  Each #SEGDESC_t includes a field for
+	 * the segment selector, so this information is entirely
+	 * redundant.
+	 */
+	SEGSEL_t	FirstSelector;
+	/** Stack segment descriptor */
+	SEGDESC_t	Stack;
+	/** UNDI data segment descriptor */
+	SEGDESC_t	UNDIData;
+	/** UNDI code segment descriptor */
+	SEGDESC_t	UNDICode;
+	/** UNDI writable code segment descriptor */
+	SEGDESC_t	UNDICodeWrite;
+	/** Base-code data segment descriptor */
+	SEGDESC_t	BC_Data;
+	/** Base-code code segment descriptor */
+	SEGDESC_t	BC_Code;
+	/** Base-code writable code segment descriptor */
+	SEGDESC_t	BC_CodeWrite;
+} __attribute__ (( packed ));
+
+typedef struct s_PXE PXE_t;
+
+/** @} */ /* pxe_api_call */
+
+/** @defgroup pxe_preboot_api PXE Preboot API
+ *
+ * General high-level functions: #PXENV_UNLOAD_STACK, #PXENV_START_UNDI etc.
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_unload_stack PXENV_UNLOAD_STACK
+ *
+ *  UNLOAD BASE CODE STACK
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_unload_stack() */
+#define	PXENV_UNLOAD_STACK		0x0070
+
+/** Parameter block for pxenv_unload_stack() */
+struct s_PXENV_UNLOAD_STACK {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	UINT8_t reserved[10];			/**< Must be zero */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNLOAD_STACK PXENV_UNLOAD_STACK_t;
+
+extern PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK
+					 *unload_stack );
+
+/** @} */ /* pxenv_unload_stack */
+
+/** @defgroup pxenv_get_cached_info PXENV_GET_CACHED_INFO
+ *
+ *  GET CACHED INFO
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_get_cached_info() */
+#define	PXENV_GET_CACHED_INFO		0x0071
+
+/** The client's DHCPDISCOVER packet */
+#define PXENV_PACKET_TYPE_DHCP_DISCOVER	1
+
+/** The DHCP server's DHCPACK packet */
+#define PXENV_PACKET_TYPE_DHCP_ACK	2
+
+/** The Boot Server's Discover Reply packet
+ *
+ * This packet contains DHCP option 60 set to "PXEClient", a valid
+ * boot file name, and may or may not contain MTFTP options.
+ */
+#define PXENV_PACKET_TYPE_CACHED_REPLY	3
+
+/** Parameter block for pxenv_get_cached_info() */
+struct s_PXENV_GET_CACHED_INFO {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	/** Packet type.
+	 *
+	 * Valid values are #PXENV_PACKET_TYPE_DHCP_DISCOVER,
+	 * #PXENV_PACKET_TYPE_DHCP_ACK or #PXENV_PACKET_TYPE_CACHED_REPLY
+	 */
+	UINT16_t PacketType;
+	UINT16_t BufferSize;			/**< Buffer size */
+	SEGOFF16_t Buffer;			/**< Buffer address */
+	UINT16_t BufferLimit;			/**< Maximum buffer size */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_GET_CACHED_INFO PXENV_GET_CACHED_INFO_t;
+
+#define BOOTP_REQ	1	/**< A BOOTP request packet */
+#define BOOTP_REP	2	/**< A BOOTP reply packet */
+
+/** DHCP broadcast flag
+ *
+ * Request a broadcast response (DHCPOFFER or DHCPACK) from the DHCP
+ * server.
+ */
+#define BOOTP_BCAST	0x8000
+
+#define VM_RFC1048	0x63825363L	/**< DHCP magic cookie */
+
+/** Maximum length of DHCP options */
+#define BOOTP_DHCPVEND	1024
+
+/** Format of buffer filled in by pxenv_get_cached_info()
+ *
+ * This somewhat convoluted data structure simply describes the layout
+ * of a DHCP packet.  Refer to RFC2131 section 2 for a full
+ * description.
+ */
+struct bootph {
+	/** Message opcode.
+	 *
+	 * Valid values are #BOOTP_REQ and #BOOTP_REP.
+	 */
+	UINT8_t opcode;
+	/** NIC hardware type.
+	 *
+	 * Valid values are as for s_PXENV_UNDI_GET_INFORMATION::HwType.
+	 */
+	UINT8_t Hardware;
+	UINT8_t Hardlen;		/**< MAC address length */
+	/** Gateway hops
+	 *
+	 * Zero in packets sent by the client.  May be non-zero in
+	 * replies from the DHCP server, if the reply comes via a DHCP
+	 * relay agent.
+	 */
+	UINT8_t Gatehops;
+	UINT32_t ident;			/**< DHCP transaction id (xid) */
+	/** Elapsed time
+	 *
+	 * Number of seconds since the client began the DHCP
+	 * transaction.
+	 */
+	UINT16_t seconds;
+	/** Flags
+	 *
+	 * This is the bitwise-OR of any of the following values:
+	 * #BOOTP_BCAST.
+	 */
+	UINT16_t Flags;
+	/** Client IP address
+	 *
+	 * Set only if the client already has an IP address.
+	 */
+	IP4_t cip;
+	/** Your IP address
+	 *
+	 * This is the IP address that the server assigns to the
+	 * client.
+	 */
+	IP4_t yip;
+	/** Server IP address
+	 *
+	 * This is the IP address of the BOOTP/DHCP server.
+	 */
+	IP4_t sip;
+	/** Gateway IP address
+	 *
+	 * This is the IP address of the BOOTP/DHCP relay agent, if
+	 * any.  It is @b not (necessarily) the address of the default
+	 * gateway for routing purposes.
+	 */
+	IP4_t gip;
+	MAC_ADDR_t CAddr;		/**< Client MAC address */
+	UINT8_t Sname[64];		/**< Server host name */
+	UINT8_t bootfile[128];		/**< Boot file name */
+	/** DHCP options
+	 *
+	 * Don't ask.  Just laugh.  Then burn a copy of the PXE
+	 * specification and send Intel an e-mail asking them if
+	 * they've figured out what a "union" does in C yet.
+	 */
+	union bootph_vendor {
+		UINT8_t d[BOOTP_DHCPVEND]; /**< DHCP options */
+		/** DHCP options */
+		struct bootph_vendor_v {
+			/** DHCP magic cookie
+			 *
+			 * Should have the value #VM_RFC1048.
+			 */
+			UINT8_t magic[4];
+			UINT32_t flags;	/**< BOOTP flags/opcodes */
+			/** "End of BOOTP vendor extensions"
+			 *
+			 * Abandon hope, all ye who consider the
+			 * purpose of this field.
+			 */
+			UINT8_t pad[56];
+		} v;
+	} vendor;
+} __attribute__ (( packed ));
+
+typedef struct bootph BOOTPLAYER_t;
+
+extern PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
+					    *get_cached_info );
+
+/** @} */ /* pxenv_get_cached_info */
+
+/** @defgroup pxenv_restart_tftp PXENV_RESTART_TFTP
+ *
+ *  RESTART TFTP
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_restart_tftp() */
+#define	PXENV_RESTART_TFTP		0x0073
+
+/** Parameter block for pxenv_restart_tftp() */
+struct s_PXENV_TFTP_READ_FILE;
+
+typedef struct s_PXENV_RESTART_TFTP PXENV_RESTART_TFTP_t;
+
+extern PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
+					 *restart_tftp );
+
+/** @} */ /* pxenv_restart_tftp */
+
+/** @defgroup pxenv_start_undi PXENV_START_UNDI
+ *
+ *  START UNDI
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_start_undi() */
+#define	PXENV_START_UNDI		0x0000
+
+/** Parameter block for pxenv_start_undi() */
+struct s_PXENV_START_UNDI {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	/** %ax register as passed to the Option ROM initialisation routine.
+	 *
+	 * For a PCI device, this should contain the bus:dev:fn value
+	 * that uniquely identifies the PCI device in the system.  For
+	 * a non-PCI device, this field is not defined.
+	 */
+	UINT16_t AX;
+	/** %bx register as passed to the Option ROM initialisation routine.
+	 *
+	 * For an ISAPnP device, this should contain the Card Select
+	 * Number assigned to the ISAPnP card.  For non-ISAPnP
+	 * devices, this should contain 0xffff.
+	 */
+	UINT16_t BX;
+	/** %dx register as passed to the Option ROM initialisation routine.
+	 *
+	 * For an ISAPnP device, this should contain the ISAPnP Read
+	 * Port address as currently set in all ISAPnP cards.  If
+	 * there are no ISAPnP cards, this should contain 0xffff.  (If
+	 * this is a non-ISAPnP device, but there are ISAPnP cards in
+	 * the system, this value is not well defined.)
+	 */
+	UINT16_t DX;
+	/** %di register as passed to the Option ROM initialisation routine.
+	 *
+	 * This contains the #OFF16_t portion of a struct #s_SEGOFF16
+	 * that points to the System BIOS Plug and Play Installation
+	 * Check Structure.  (Refer to section 4.4 of the Plug and
+	 * Play BIOS specification for a description of this
+	 * structure.)
+	 *
+	 * @note The PXE specification defines the type of this field
+	 * as #UINT16_t.  For x86, #OFF16_t and #UINT16_t are
+	 * equivalent anyway; for other architectures #OFF16_t makes
+	 * more sense.
+	 */
+	OFF16_t DI;
+	/** %es register as passed to the Option ROM initialisation routine.
+	 *
+	 * This contains the #SEGSEL_t portion of a struct #s_SEGOFF16
+	 * that points to the System BIOS Plug and Play Installation
+	 * Check Structure.  (Refer to section 4.4 of the Plug and
+	 * Play BIOS specification for a description of this
+	 * structure.)
+	 *
+	 * @note The PXE specification defines the type of this field
+	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
+	 * equivalent anyway; for other architectures #SEGSEL_t makes
+	 * more sense.
+	 */
+	SEGSEL_t ES;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_START_UNDI PXENV_START_UNDI_t;
+
+extern PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi );
+
+/** @} */ /* pxenv_start_undi */
+
+/** @defgroup pxenv_stop_undi PXENV_STOP_UNDI
+ *
+ *  STOP UNDI
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_stop_undi() */
+#define	PXENV_STOP_UNDI			0x0015
+
+/** Parameter block for pxenv_stop_undi() */
+struct s_PXENV_STOP_UNDI {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_STOP_UNDI PXENV_STOP_UNDI_t;
+
+extern PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi );
+
+/** @} */ /* pxenv_stop_undi */
+
+/** @defgroup pxenv_start_base PXENV_START_BASE
+ *
+ *  START BASE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_start_base() */
+#define	PXENV_START_BASE		0x0075
+
+/** Parameter block for pxenv_start_base() */
+struct s_PXENV_START_BASE {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_START_BASE PXENV_START_BASE_t;
+
+extern PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base );
+
+/** @} */ /* pxenv_start_base */
+
+/** @defgroup pxenv_stop_base PXENV_STOP_BASE
+ *
+ *  STOP BASE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_stop_base() */
+#define	PXENV_STOP_BASE			0x0076
+
+/** Parameter block for pxenv_stop_base() */
+struct s_PXENV_STOP_BASE {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_STOP_BASE PXENV_STOP_BASE_t;
+
+extern PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base );
+
+/** @} */ /* pxenv_stop_base */
+
+/** @} */ /* pxe_preboot_api */
+
+/** @defgroup pxe_tftp_api PXE TFTP API
+ *
+ * Download files via TFTP or MTFTP
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_tftp_open PXENV_TFTP_OPEN
+ *
+ *  TFTP OPEN
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_tftp_open() */
+#define	PXENV_TFTP_OPEN			0x0020
+
+/** Parameter block for pxenv_tftp_open() */
+struct s_PXENV_TFTP_OPEN {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	IP4_t ServerIPAddress;			/**< TFTP server IP address */
+	IP4_t GatewayIPAddress;			/**< Relay agent IP address */
+	UINT8_t FileName[128];			/**< File name */
+	UDP_PORT_t TFTPPort;			/**< TFTP server UDP port */
+	/** Requested size of TFTP packets
+	 *
+	 * This is the TFTP "blksize" option.  This must be at least
+	 * 512, since servers that do not support TFTP options cannot
+	 * negotiate blocksizes smaller than this.
+	 */
+	UINT16_t PacketSize;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_TFTP_OPEN PXENV_TFTP_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open );
+
+/** @} */ /* pxenv_tftp_open */
+
+/** @defgroup pxenv_tftp_close PXENV_TFTP_CLOSE
+ *
+ *  TFTP CLOSE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_tftp_close() */
+#define	PXENV_TFTP_CLOSE		0x0021
+
+/** Parameter block for pxenv_tftp_close() */
+struct s_PXENV_TFTP_CLOSE {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_TFTP_CLOSE PXENV_TFTP_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close );
+
+/** @} */ /* pxenv_tftp_close */
+
+/** @defgroup pxenv_tftp_read PXENV_TFTP_READ
+ *
+ *  TFTP READ
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_tftp_read() */
+#define	PXENV_TFTP_READ			0x0022
+
+/** Parameter block for pxenv_tftp_read() */
+struct s_PXENV_TFTP_READ {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	UINT16_t PacketNumber;			/**< TFTP packet number */
+	UINT16_t BufferSize;			/**< Size of data buffer */
+	SEGOFF16_t Buffer;			/**< Address of data buffer */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_TFTP_READ PXENV_TFTP_READ_t;
+
+extern PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read );
+
+/** @} */ /* pxenv_tftp_read */
+
+/** @defgroup pxenv_tftp_read_file PXENV_TFTP_READ_FILE
+ *
+ *  TFTP/MTFTP READ FILE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_tftp_read_file() */
+#define	PXENV_TFTP_READ_FILE		0x0023
+
+/** Parameter block for pxenv_tftp_read_file() */
+struct s_PXENV_TFTP_READ_FILE {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	UINT8_t FileName[128];			/**< File name */
+	UINT32_t BufferSize;			/**< Size of data buffer */
+	ADDR32_t Buffer;			/**< Address of data buffer */
+	IP4_t ServerIPAddress;			/**< TFTP server IP address */
+	IP4_t GatewayIPAddress;			/**< Relay agent IP address */
+	/** File multicast IP address */
+	IP4_t McastIPAddress;
+	/** Client multicast listening port */
+	UDP_PORT_t TFTPClntPort;
+	/** Server multicast listening port */
+	UDP_PORT_t TFTPSrvPort;
+	/** TFTP open timeout.
+	 *
+	 * This is the timeout for receiving the first DATA or ACK
+	 * packets during the MTFTP Listen phase.
+	 */
+	UINT16_t TFTPOpenTimeOut;
+	/** TFTP reopen timeout.
+	 *
+	 * This is the timeout for receiving an ACK packet while in
+	 * the MTFTP Listen phase (when at least one ACK packet has
+	 * already been seen).
+	 */
+	UINT16_t TFTPReopenDelay;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_TFTP_READ_FILE PXENV_TFTP_READ_FILE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
+					   *tftp_read_file );
+
+/** @} */ /* pxenv_tftp_read_file */
+
+/** @defgroup pxenv_tftp_get_fsize PXENV_TFTP_GET_FSIZE
+ *
+ *  TFTP GET FILE SIZE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_tftp_get_fsize() */
+#define	PXENV_TFTP_GET_FSIZE		0x0025
+
+/** Parameter block for pxenv_tftp_get_fsize() */
+struct s_PXENV_TFTP_GET_FSIZE {
+	PXENV_STATUS_t Status;			/**< PXE status code */
+	IP4_t ServerIPAddress;			/**< TFTP server IP address */
+	IP4_t GatewayIPAddress;			/**< Relay agent IP address */
+	UINT8_t FileName[128];			/**< File name */
+	UINT32_t FileSize;			/**< Size of the file */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_TFTP_GET_FSIZE PXENV_TFTP_GET_FSIZE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
+					   *get_fsize );
+
+/** @} */ /* pxenv_tftp_get_fsize */
+
+/** @} */ /* pxe_tftp_api */
+
+/** @defgroup pxe_udp_api PXE UDP API
+ *
+ * Transmit and receive UDP packets
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_udp_open PXENV_UDP_OPEN
+ *
+ *  UDP OPEN
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_udp_open() */
+#define	PXENV_UDP_OPEN			0x0030
+
+/** Parameter block for pxenv_udp_open() */
+struct s_PXENV_UDP_OPEN {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	IP4_t		src_ip;		/**< IP address of this station */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UDP_OPEN PXENV_UDP_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open );
+
+/** @} */ /* pxenv_udp_open */
+
+/** @defgroup pxenv_udp_close PXENV_UDP_CLOSE
+ *
+ *  UDP CLOSE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_udp_close() */
+#define	PXENV_UDP_CLOSE			0x0031
+
+/** Parameter block for pxenv_udp_close() */
+struct s_PXENV_UDP_CLOSE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UDP_CLOSE PXENV_UDP_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close );
+
+/** @} */ /* pxenv_udp_close */
+
+/** @defgroup pxenv_udp_write PXENV_UDP_WRITE
+ *
+ *  UDP WRITE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_udp_write() */
+#define	PXENV_UDP_WRITE			0x0033
+
+/** Parameter block for pxenv_udp_write() */
+struct s_PXENV_UDP_WRITE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	IP4_t		ip;		/**< Destination IP address */
+	IP4_t		gw;		/**< Relay agent IP address */
+	UDP_PORT_t	src_port;	/**< Source UDP port */
+	UDP_PORT_t	dst_port;	/**< Destination UDP port */
+	UINT16_t	buffer_size;	/**< UDP payload buffer size */
+	SEGOFF16_t	buffer;		/**< UDP payload buffer address */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UDP_WRITE PXENV_UDP_WRITE_t;
+
+extern PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write );
+
+/** @} */ /* pxenv_udp_write */
+
+/** @defgroup pxenv_udp_read PXENV_UDP_READ
+ *
+ *  UDP READ
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_udp_read() */
+#define	PXENV_UDP_READ			0x0032
+
+/** Parameter block for pxenv_udp_read() */
+struct s_PXENV_UDP_READ {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	IP4_t		src_ip;		/**< Source IP address */
+	IP4_t		dest_ip;	/**< Destination IP address */
+	UDP_PORT_t	s_port;		/**< Source UDP port */
+	UDP_PORT_t	d_port;		/**< Destination UDP port */
+	UINT16_t	buffer_size;	/**< UDP payload buffer size */
+	SEGOFF16_t	buffer;		/**< UDP payload buffer address */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UDP_READ PXENV_UDP_READ_t;
+
+extern PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read );
+
+/** @} */ /* pxenv_udp_read */
+
+/** @} */ /* pxe_udp_api */
+
+/** @defgroup pxe_undi_api PXE UNDI API
+ *
+ * Direct control of the network interface card
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_undi_startup PXENV_UNDI_STARTUP
+ *
+ *  UNDI STARTUP
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_startup() */
+#define	PXENV_UNDI_STARTUP		0x0001
+
+#define PXENV_BUS_ISA		0	/**< ISA bus type */
+#define PXENV_BUS_EISA		1	/**< EISA bus type */
+#define PXENV_BUS_MCA		2	/**< MCA bus type */
+#define PXENV_BUS_PCI		3	/**< PCI bus type */
+#define PXENV_BUS_VESA		4	/**< VESA bus type */
+#define PXENV_BUS_PCMCIA	5	/**< PCMCIA bus type */
+
+/** Parameter block for pxenv_undi_startup() */
+struct s_PXENV_UNDI_STARTUP {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_STARTUP PXENV_UNDI_STARTUP_t;
+
+extern PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP
+					 *undi_startup );
+
+/** @} */ /* pxenv_undi_startup */
+
+/** @defgroup pxenv_undi_cleanup PXENV_UNDI_CLEANUP
+ *
+ *  UNDI CLEANUP
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_cleanup() */
+#define	PXENV_UNDI_CLEANUP		0x0002
+
+/** Parameter block for pxenv_undi_cleanup() */
+struct s_PXENV_UNDI_CLEANUP {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_CLEANUP PXENV_UNDI_CLEANUP_t;
+
+extern PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP
+					 *undi_cleanup );
+
+/** @} */ /* pxenv_undi_cleanup */
+
+/** @defgroup pxenv_undi_initialize PXENV_UNDI_INITIALIZE
+ *
+ *  UNDI INITIALIZE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_initialize() */
+#define	PXENV_UNDI_INITIALIZE		0x0003
+
+/** Parameter block for pxenv_undi_initialize() */
+struct s_PXENV_UNDI_INITIALIZE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** NDIS 2.0 configuration information, or NULL
+	 *
+	 * This is a pointer to the data structure returned by the
+	 * NDIS 2.0 GetProtocolManagerInfo() API call.  The data
+	 * structure is documented, in a rather haphazard way, in
+	 * section 4-17 of the NDIS 2.0 specification.
+	 */
+	ADDR32_t ProtocolIni;
+	UINT8_t reserved[8];		/**< Must be zero */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_INITIALIZE PXENV_UNDI_INITIALIZE_t;
+
+extern PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
+					    *undi_initialize );
+
+/** @} */ /* pxenv_undi_initialize */
+
+/** @defgroup pxenv_undi_reset_adapter PXENV_UNDI_RESET_ADAPTER
+ *
+ *  UNDI RESET ADAPTER
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_reset_adapter() */
+#define	PXENV_UNDI_RESET_ADAPTER	0x0004
+
+/** Maximum number of multicast MAC addresses */
+#define MAXNUM_MCADDR	8
+
+/** List of multicast MAC addresses */
+struct s_PXENV_UNDI_MCAST_ADDRESS {
+	/** Number of multicast MAC addresses */
+	UINT16_t MCastAddrCount;
+	/** List of up to #MAXNUM_MCADDR multicast MAC addresses */
+	MAC_ADDR_t McastAddr[MAXNUM_MCADDR];
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_MCAST_ADDRESS PXENV_UNDI_MCAST_ADDRESS_t;
+
+/** Parameter block for pxenv_undi_reset_adapter() */
+struct s_PXENV_UNDI_RESET {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Multicast MAC addresses */
+	struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t;
+
+extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
+					       *undi_reset_adapter );
+
+/** @} */ /* pxenv_undi_reset_adapter */
+
+/** @defgroup pxenv_undi_shutdown PXENV_UNDI_SHUTDOWN
+ *
+ *  UNDI SHUTDOWN
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_shutdown() */
+#define	PXENV_UNDI_SHUTDOWN		0x0005
+
+/** Parameter block for pxenv_undi_shutdown() */
+struct s_PXENV_UNDI_SHUTDOWN {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_SHUTDOWN PXENV_UNDI_SHUTDOWN_t;
+
+extern PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
+					  *undi_shutdown );
+
+/** @} */ /* pxenv_undi_shutdown */
+
+/** @defgroup pxenv_undi_open PXENV_UNDI_OPEN
+ *
+ *  UNDI OPEN
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_open() */
+#define	PXENV_UNDI_OPEN			0x0006
+
+/** Accept "directed" packets
+ *
+ * These are packets addresses to either this adapter's MAC address or
+ * to any of the configured multicast MAC addresses (see
+ * #s_PXENV_UNDI_MCAST_ADDRESS).
+ */
+#define FLTR_DIRECTED	0x0001
+/** Accept broadcast packets */
+#define FLTR_BRDCST	0x0002
+/** Accept all packets; listen in promiscuous mode */
+#define FLTR_PRMSCS	0x0004
+/** Accept source-routed packets */
+#define FLTR_SRC_RTG	0x0008
+
+/** Parameter block for pxenv_undi_open() */
+struct s_PXENV_UNDI_OPEN {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Open flags as defined in NDIS 2.0
+	 *
+	 * This is the OpenOptions field as passed to the NDIS 2.0
+	 * OpenAdapter() API call.  It is defined to be "adapter
+	 * specific", though 0 is guaranteed to be a valid value.
+	 */
+	UINT16_t OpenFlag;
+	/** Receive packet filter
+	 *
+	 * This is the bitwise-OR of any of the following flags:
+	 * #FLTR_DIRECTED, #FLTR_BRDCST, #FLTR_PRMSCS and
+	 * #FLTR_SRC_RTG.
+	 */
+	UINT16_t PktFilter;
+	/** Multicast MAC addresses */
+	struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_OPEN PXENV_UNDI_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open );
+
+/** @} */ /* pxenv_undi_open */
+
+/** @defgroup pxenv_undi_close PXENV_UNDI_CLOSE
+ *
+ *  UNDI CLOSE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_close() */
+#define	PXENV_UNDI_CLOSE		0x0007
+
+/** Parameter block for pxenv_undi_close() */
+struct s_PXENV_UNDI_CLOSE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_CLOSE PXENV_UNDI_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close );
+
+/** @} */ /* pxenv_undi_close */
+
+/** @defgroup pxenv_undi_transmit PXENV_UNDI_TRANSMIT
+ *
+ *  UNDI TRANSMIT PACKET
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_transmit() */
+#define	PXENV_UNDI_TRANSMIT		0x0008
+
+#define P_UNKNOWN	0		/**< Media header already filled in */
+#define P_IP		1		/**< IP protocol */
+#define P_ARP		2		/**< ARP protocol */
+#define P_RARP		3		/**< RARP protocol */
+#define P_OTHER		4		/**< Other protocol */
+
+#define XMT_DESTADDR	0x0000		/**< Unicast packet */
+#define XMT_BROADCAST	0x0001		/**< Broadcast packet */
+
+/** Maximum number of data blocks in a transmit buffer descriptor */
+#define MAX_DATA_BLKS	8
+
+/** A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD
+ */
+struct s_PXENV_UNDI_TBD {
+	UINT16_t ImmedLength;		/**< Length of the transmit buffer */
+	SEGOFF16_t Xmit;		/**< Address of the transmit buffer */
+	UINT16_t DataBlkCount;
+	/** Array of up to #MAX_DATA_BLKS additional transmit buffers */
+	struct DataBlk {
+		/** Always 1
+		 *
+		 * A value of 0 would indicate that #TDDataPtr were an
+		 * #ADDR32_t rather than a #SEGOFF16_t.  The PXE
+		 * specification version 2.1 explicitly states that
+		 * this is not supported; #TDDataPtr will always be a
+		 * #SEGOFF16_t.
+		 */
+		UINT8_t TDPtrType;
+		UINT8_t TDRsvdByte;	/**< Must be zero */
+		UINT16_t TDDataLen;	/**< Length of this transmit buffer */
+		SEGOFF16_t TDDataPtr;	/**< Address of this transmit buffer */
+	} DataBlock[MAX_DATA_BLKS];
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_TBD PXENV_UNDI_TBD_t;
+
+/** Parameter block for pxenv_undi_transmit() */
+struct s_PXENV_UNDI_TRANSMIT {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Protocol
+	 *
+	 * Valid values are #P_UNKNOWN, #P_IP, #P_ARP or #P_RARP.  If
+	 * the caller has already filled in the media header, this
+	 * field must be set to #P_UNKNOWN.
+	 */
+	UINT8_t Protocol;
+	/** Unicast/broadcast flag
+	 *
+	 * Valid values are #XMT_DESTADDR or #XMT_BROADCAST.
+	 */
+	UINT8_t XmitFlag;
+	SEGOFF16_t DestAddr;		/**< Destination MAC address */
+	/** Address of the Transmit Buffer Descriptor
+	 *
+	 * This is a pointer to a struct s_PXENV_UNDI_TBD.
+	 */
+	SEGOFF16_t TBD;
+	UINT32_t Reserved[2];		/**< Must be zero */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_TRANSMIT PXENV_UNDI_TRANSMIT_t;
+
+extern PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
+					  *undi_transmit );
+
+/** @} */ /* pxenv_undi_transmit */
+
+/** @defgroup pxenv_undi_set_mcast_address PXENV_UNDI_SET_MCAST_ADDRESS
+ *
+ *  UNDI SET MULTICAST ADDRESS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_set_mcast_address() */
+#define	PXENV_UNDI_SET_MCAST_ADDRESS	0x0009
+
+/** Parameter block for pxenv_undi_set_mcast_address() */
+struct s_PXENV_UNDI_SET_MCAST_ADDRESS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** List of multicast addresses */
+	struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_UNDI_SET_MCAST_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_mcast_address (
+	       struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address );
+
+/** @} */ /* pxenv_undi_set_mcast_address */
+
+/** @defgroup pxenv_undi_set_station_address PXENV_UNDI_SET_STATION_ADDRESS
+ *
+ *  UNDI SET STATION ADDRESS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_set_station_address() */
+#define	PXENV_UNDI_SET_STATION_ADDRESS	0x000a
+
+/** Parameter block for pxenv_undi_set_station_address() */
+struct s_PXENV_UNDI_SET_STATION_ADDRESS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	MAC_ADDR_t StationAddress;	/**< Station MAC address */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_UNDI_SET_STATION_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_station_address (
+	   struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address );
+
+/** @} */ /* pxenv_undi_set_station_address */
+
+/** @defgroup pxenv_undi_set_packet_filter PXENV_UNDI_SET_PACKET_FILTER
+ *
+ *  UNDI SET PACKET FILTER
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_set_packet_filter() */
+#define	PXENV_UNDI_SET_PACKET_FILTER	0x000b
+
+/** Parameter block for pxenv_undi_set_packet_filter() */
+struct s_PXENV_UNDI_SET_PACKET_FILTER {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Receive packet filter
+	 *
+	 * This field takes the same values as
+	 * s_PXENV_UNDI_OPEN::PktFilter.
+	 *
+	 * @note Yes, this field is a different size to
+	 * s_PXENV_UNDI_OPEN::PktFilter.  Blame "the managers at Intel
+	 * who apparently let a consultant come up with the spec
+	 * without any kind of adult supervision" (quote from hpa).
+	 */
+	UINT8_t filter;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER PXENV_UNDI_SET_PACKET_FILTER_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_packet_filter (
+	       struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter );
+
+/** @} */ /* pxenv_undi_set_packet_filter */
+
+/** @defgroup pxenv_undi_get_information PXENV_UNDI_GET_INFORMATION
+ *
+ *  UNDI GET INFORMATION
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_information() */
+#define	PXENV_UNDI_GET_INFORMATION	0x000c
+
+#define ETHER_TYPE		1	/**< Ethernet (10Mb) */
+#define EXP_ETHER_TYPE		2	/**< Experimental Ethernet (3Mb) */
+#define AX25_TYPE		3	/**< Amateur Radio AX.25 */
+#define TOKEN_RING_TYPE		4	/**< Proteon ProNET Token Ring */
+#define CHAOS_TYPE		5	/**< Chaos */
+#define IEEE_TYPE		6	/**< IEEE 802 Networks */
+#define ARCNET_TYPE		7	/**< ARCNET */
+
+/** Parameter block for pxenv_undi_get_information() */
+struct s_PXENV_UNDI_GET_INFORMATION {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	UINT16_t BaseIo;		/**< I/O base address */
+	UINT16_t IntNumber;		/**< IRQ number */
+	UINT16_t MaxTranUnit;		/**< Adapter MTU */
+	/** Hardware type
+	 *
+	 * Valid values are defined in RFC1010 ("Assigned numbers"),
+	 * and are #ETHER_TYPE, #EXP_ETHER_TYPE, #AX25_TYPE,
+	 * #TOKEN_RING_TYPE, #CHAOS_TYPE, #IEEE_TYPE or #ARCNET_TYPE.
+	 */
+	UINT16_t HwType;
+	UINT16_t HwAddrLen;		/**< MAC address length */
+	MAC_ADDR_t CurrentNodeAddress;	/**< Current MAC address */
+	MAC_ADDR_t PermNodeAddress;	/**< Permanent (EEPROM) MAC address */
+	SEGSEL_t ROMAddress;		/**< Real-mode ROM segment address */
+	UINT16_t RxBufCt;		/**< Receive queue length */
+	UINT16_t TxBufCt;		/**< Transmit queue length */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_INFORMATION PXENV_UNDI_GET_INFORMATION_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_information (
+		   struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information );
+
+/** @} */ /* pxenv_undi_get_information */
+
+/** @defgroup pxenv_undi_get_statistics PXENV_UNDI_GET_STATISTICS
+ *
+ *  UNDI GET STATISTICS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_statistics() */
+#define	PXENV_UNDI_GET_STATISTICS	0x000d
+
+/** Parameter block for pxenv_undi_get_statistics() */
+struct s_PXENV_UNDI_GET_STATISTICS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	UINT32_t XmtGoodFrames;		/**< Successful transmission count */
+	UINT32_t RcvGoodFrames;		/**< Successful reception count */
+	UINT32_t RcvCRCErrors;		/**< Receive CRC error count */
+	UINT32_t RcvResourceErrors;	/**< Receive queue overflow count */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_STATISTICS PXENV_UNDI_GET_STATISTICS_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_statistics (
+		     struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics );
+
+/** @} */ /* pxenv_undi_get_statistics */
+
+/** @defgroup pxenv_undi_clear_statistics PXENV_UNDI_CLEAR_STATISTICS
+ *
+ *  UNDI CLEAR STATISTICS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_clear_statistics() */
+#define	PXENV_UNDI_CLEAR_STATISTICS	0x000e
+
+/** Parameter block for pxenv_undi_clear_statistics() */
+struct s_PXENV_UNDI_CLEAR_STATISTICS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_CLEAR_STATISTICS PXENV_UNDI_CLEAR_STATISTICS_t;
+
+extern PXENV_EXIT_t pxenv_undi_clear_statistics (
+		 struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics );
+
+/** @} */ /* pxenv_undi_clear_statistics */
+
+/** @defgroup pxenv_undi_initiate_diags PXENV_UNDI_INITIATE_DIAGS
+ *
+ *  UNDI INITIATE DIAGS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_initiate_diags() */
+#define	PXENV_UNDI_INITIATE_DIAGS	0x000f
+
+/** Parameter block for pxenv_undi_initiate_diags() */
+struct s_PXENV_UNDI_INITIATE_DIAGS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_INITIATE_DIAGS PXENV_UNDI_INITIATE_DIAGS_t;
+
+extern PXENV_EXIT_t pxenv_undi_initiate_diags (
+		     struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags );
+
+/** @} */ /* pxenv_undi_initiate_diags */
+
+/** @defgroup pxenv_undi_force_interrupt PXENV_UNDI_FORCE_INTERRUPT
+ *
+ *  UNDI FORCE INTERRUPT
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_force_interrupt() */
+#define	PXENV_UNDI_FORCE_INTERRUPT	0x0010
+
+/** Parameter block for pxenv_undi_force_interrupt() */
+struct s_PXENV_UNDI_FORCE_INTERRUPT {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_FORCE_INTERRUPT PXENV_UNDI_FORCE_INTERRUPT_t;
+
+extern PXENV_EXIT_t pxenv_undi_force_interrupt (
+		   struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt );
+
+/** @} */ /* pxenv_undi_force_interrupt */
+
+/** @defgroup pxenv_undi_get_mcast_address PXENV_UNDI_GET_MCAST_ADDRESS
+ *
+ *  UNDI GET MULTICAST ADDRESS
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_mcast_address() */
+#define	PXENV_UNDI_GET_MCAST_ADDRESS	0x0011
+
+/** Parameter block for pxenv_undi_get_mcast_address() */
+struct s_PXENV_UNDI_GET_MCAST_ADDRESS {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	IP4_t InetAddr;			/**< Multicast IP address */
+	MAC_ADDR_t MediaAddr;		/**< Multicast MAC address */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS PXENV_UNDI_GET_MCAST_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_mcast_address (
+	       struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address );
+
+/** @} */ /* pxenv_undi_get_mcast_address */
+
+/** @defgroup pxenv_undi_get_nic_type PXENV_UNDI_GET_NIC_TYPE
+ *
+ *  UNDI GET NIC TYPE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_nic_type() */
+#define	PXENV_UNDI_GET_NIC_TYPE		0x0012
+
+#define PCI_NIC		2		/**< PCI network card */
+#define PnP_NIC		3		/**< ISAPnP network card */
+#define CardBus_NIC	4		/**< CardBus network card */
+
+/** Information for a PCI or equivalent NIC */
+struct pci_nic_info {
+	UINT16_t Vendor_ID;		/**< PCI vendor ID */
+	UINT16_t Dev_ID;		/**< PCI device ID */
+	UINT8_t Base_Class;		/**< PCI base class */
+	UINT8_t Sub_Class;		/**< PCI sub class */
+	UINT8_t Prog_Intf;		/**< PCI programming interface */
+	UINT8_t Rev;			/**< PCI revision */
+	UINT16_t BusDevFunc;		/**< PCI bus:dev:fn address */
+	UINT16_t SubVendor_ID;		/**< PCI subvendor ID */
+	UINT16_t SubDevice_ID;		/**< PCI subdevice ID */
+} __attribute__ (( packed ));
+ 
+/** Information for an ISAPnP or equivalent NIC */
+struct pnp_nic_info {
+	UINT32_t EISA_Dev_ID;		/**< EISA device ID */
+	UINT8_t Base_Class;		/**< Base class */
+	UINT8_t Sub_Class;		/**< Sub class */
+	UINT8_t Prog_Intf;		/**< Programming interface */
+	/** Card Select Number assigned to card */
+	UINT16_t CardSelNum;
+} __attribute__ (( packed ));
+
+/** Parameter block for pxenv_undi_get_nic_type() */
+struct s_PXENV_UNDI_GET_NIC_TYPE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** NIC type
+	 *
+	 * Valid values are #PCI_NIC, #PnP_NIC or #CardBus_NIC.
+	 */
+	UINT8_t NicType;
+	/** NIC information */
+	union nic_type_info {
+		/** NIC information (if #NicType==#PCI_NIC) */
+		struct pci_nic_info pci;
+		/** NIC information (if #NicType==#CardBus_NIC) */
+		struct pci_nic_info cardbus;
+		/** NIC information (if #NicType==#PnP_NIC) */
+		struct pnp_nic_info pnp;
+	} info;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_NIC_TYPE PXENV_UNDI_GET_NIC_TYPE_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_nic_type ( 
+			 struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type );
+
+/** @} */ /* pxenv_undi_get_nic_type */
+
+/** @defgroup pxenv_undi_get_iface_info PXENV_UNDI_GET_IFACE_INFO
+ *
+ *  UNDI GET IFACE INFO
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_iface_info() */
+#define	PXENV_UNDI_GET_IFACE_INFO	0x0013
+
+/** Broadcast supported */
+#define SUPPORTED_BROADCAST		0x0001
+/** Multicast supported */
+#define SUPPORTED_MULTICAST		0x0002
+/** Functional/group addressing supported */
+#define SUPPORTED_GROUP			0x0004
+/** Promiscuous mode supported */
+#define SUPPORTED_PROMISCUOUS		0x0008
+/** Software settable station address */
+#define SUPPORTED_SET_STATION_ADDRESS	0x0010
+/** InitiateDiagnostics supported */
+#define SUPPORTED_DIAGNOSTICS		0x0040
+/** Reset MAC supported */
+#define SUPPORTED_RESET			0x0400
+/** Open / Close Adapter supported */
+#define SUPPORTED_OPEN_CLOSE		0x0800
+/** Interrupt Request supported */
+#define SUPPORTED_IRQ			0x1000
+
+/** Parameter block for pxenv_undi_get_iface_info() */
+struct s_PXENV_UNDI_GET_IFACE_INFO {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Interface type
+	 *
+	 * This is defined in the NDIS 2.0 specification to be one of
+	 * the strings "802.3", "802.4", "802.5", "802.6", "DIX",
+	 * "DIX+802.3", "APPLETALK", "ARCNET", "FDDI", "SDLC", "BSC",
+	 * "HDLC", or "ISDN".
+	 *
+	 * "Normal" Ethernet, for various historical reasons, is
+	 * "DIX+802.3".
+	 */
+	UINT8_t IfaceType[16];
+	UINT32_t LinkSpeed;		/**< Link speed, in bits per second */
+	/** Service flags
+	 *
+	 * These are the "service flags" defined in the "MAC
+	 * Service-Specific Characteristics" table in the NDIS 2.0
+	 * specification.  Almost all of them are irrelevant to PXE.
+	 */
+	UINT32_t ServiceFlags;
+	UINT32_t Reserved[4];		/**< Must be zero */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_IFACE_INFO PXENV_UNDI_GET_IFACE_INFO_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_iface_info (
+		     struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info );
+
+/** @} */ /* pxenv_undi_get_iface_info */
+
+/** @defgroup pxenv_undi_get_state PXENV_UNDI_GET_STATE
+ *
+ *  UNDI GET STATE
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_get_state() */
+#define PXENV_UNDI_GET_STATE		0x0015
+
+/** pxenv_start_undi() has been called */
+#define PXE_UNDI_GET_STATE_STARTED	1
+/** pxenv_undi_initialize() has been called */
+#define PXE_UNDI_GET_STATE_INITIALIZED	2
+/** pxenv_undi_open() has been called */
+#define PXE_UNDI_GET_STATE_OPENED	3
+
+/** Parameter block for pxenv_undi_get_state() */
+struct s_PXENV_UNDI_GET_STATE {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Current state of the UNDI driver
+	 *
+	 * Valid values are #PXE_UNDI_GET_STATE_STARTED,
+	 * #PXE_UNDI_GET_STATE_INITIALIZED or
+	 * #PXE_UNDI_GET_STATE_OPENED.
+	 */
+	UINT8_t UNDIstate;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_GET_STATE PXENV_UNDI_GET_STATE_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
+					   *undi_get_state );
+
+/** @} */ /* pxenv_undi_get_state */
+
+/** @defgroup pxenv_undi_isr PXENV_UNDI_ISR
+ *
+ *  UNDI ISR
+ *
+ *  @{
+ */
+
+/** PXE API function code for pxenv_undi_isr() */
+#define	PXENV_UNDI_ISR			0x0014
+
+/** Determine whether or not this is our interrupt */
+#define PXENV_UNDI_ISR_IN_START		1
+/** Start processing interrupt */
+#define PXENV_UNDI_ISR_IN_PROCESS	2
+/** Continue processing interrupt */
+#define PXENV_UNDI_ISR_IN_GET_NEXT	3
+/** This interrupt was ours */
+#define PXENV_UNDI_ISR_OUT_OURS		0
+/** This interrupt was not ours */
+#define PXENV_UNDI_ISR_OUT_NOT_OURS	1
+/** Finished processing interrupt */
+#define PXENV_UNDI_ISR_OUT_DONE		0
+/** A packet transmission has completed */
+#define PXENV_UNDI_ISR_OUT_TRANSMIT	2
+/** A packet has been received */
+#define PXENV_UNDI_ISR_OUT_RECEIVE	3
+/** We are already in the middle of processing an interrupt */
+#define PXENV_UNDI_ISR_OUT_BUSY		4
+
+/** Unicast packet (or packet captured in promiscuous mode) */
+#define P_DIRECTED	0
+/** Broadcast packet */
+#define P_BROADCAST	1
+/** Multicast packet */
+#define P_MULTICAST	2
+
+/** Parameter block for pxenv_undi_isr() */
+struct s_PXENV_UNDI_ISR {
+	PXENV_STATUS_t	Status;		/**< PXE status code */
+	/** Function flag
+	 *
+	 * Valid values are #PXENV_UNDI_ISR_IN_START,
+	 * #PXENV_UNDI_ISR_IN_PROCESS, #PXENV_UNDI_ISR_IN_GET_NEXT,
+	 * #PXENV_UNDI_ISR_OUT_OURS, #PXENV_UNDI_ISR_OUT_NOT_OURS,
+	 * #PXENV_UNDI_ISR_OUT_DONE, #PXENV_UNDI_ISR_OUT_TRANSMIT,
+	 * #PXENV_UNDI_ISR_OUT_RECEIVE or #PXENV_UNDI_ISR_OUT_BUSY.
+	 */
+	UINT16_t FuncFlag;
+	UINT16_t BufferLength;		/**< Data buffer length */
+	UINT16_t FrameLength;		/**< Total frame length */
+	UINT16_t FrameHeaderLength;	/**< Frame header length */
+	SEGOFF16_t Frame;		/**< Data buffer address */
+	/** Protocol type
+	 *
+	 * Valid values are #P_IP, #P_ARP, #P_RARP or #P_OTHER.
+	 */
+	UINT8_t ProtType;
+	/** Packet type
+	 *
+	 * Valid values are #P_DIRECTED, #P_BROADCAST or #P_MULTICAST.
+	 */
+	UINT8_t PktType;
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t;
+
+extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
+
+/** @} */ /* pxenv_undi_isr */
+
+/** @} */ /* pxe_undi_api */
+
+/** @defgroup pxe_file_api PXE FILE API
+ *
+ * POSIX-like file operations
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_file_open PXENV_FILE_OPEN
+ *
+ * FILE OPEN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_open() */
+#define PXENV_FILE_OPEN			0x00e0
+
+/** Parameter block for pxenv_file_open() */
+struct s_PXENV_FILE_OPEN {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t FileHandle;		/**< File handle */
+	SEGOFF16_t FileName;		/**< File URL */
+	UINT32_t Reserved;		/**< Reserved */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open );
+
+/** @} */ /* pxenv_file_open */
+
+/** @defgroup pxenv_file_close PXENV_FILE_CLOSE
+ *
+ * FILE CLOSE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_close() */
+#define PXENV_FILE_CLOSE		0x00e1
+
+/** Parameter block for pxenv_file_close() */
+struct s_PXENV_FILE_CLOSE {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t FileHandle;		/**< File handle */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE
+				       *file_close );
+
+/** @} */ /* pxenv_file_close */
+
+/** @defgroup pxenv_file_select PXENV_FILE_SELECT
+ *
+ * FILE SELECT
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_select() */
+#define PXENV_FILE_SELECT		0x00e2
+
+/** File is ready for reading */
+#define RDY_READ			0x0001
+
+/** Parameter block for pxenv_file_select() */
+struct s_PXENV_FILE_SELECT {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t FileHandle;		/**< File handle */
+	UINT16_t Ready;			/**< Indication of readiness */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t;
+
+extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT
+					*file_select );
+
+/** @} */ /* pxenv_file_select */
+
+/** @defgroup pxenv_file_read PXENV_FILE_READ
+ *
+ * FILE READ
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_read() */
+#define PXENV_FILE_READ		0x00e3
+
+/** Parameter block for pxenv_file_read() */
+struct s_PXENV_FILE_READ {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t FileHandle;		/**< File handle */
+	UINT16_t BufferSize;		/**< Data buffer size */
+	SEGOFF16_t Buffer;		/**< Data buffer */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t;
+
+extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read );
+
+/** @} */ /* pxenv_file_read */
+
+/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE
+ *
+ * GET FILE SIZE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_get_file_size() */
+#define PXENV_GET_FILE_SIZE		0x00e4
+
+/** Parameter block for pxenv_get_file_size() */
+struct s_PXENV_GET_FILE_SIZE {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t FileHandle;		/**< File handle */
+	UINT32_t FileSize;		/**< File size */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t;
+
+extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
+					  *get_file_size );
+
+/** @} */ /* pxenv_get_file_size */
+
+/** @defgroup pxenv_file_exec PXENV_FILE_EXEC
+ *
+ * FILE EXEC
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_exec() */
+#define PXENV_FILE_EXEC			0x00e5
+
+/** Parameter block for pxenv_file_exec() */
+struct s_PXENV_FILE_EXEC {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	SEGOFF16_t Command;		/**< Command to execute */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_EXEC PXENV_FILE_EXEC_t;
+
+extern PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec );
+
+/** @} */ /* pxenv_file_exec */
+
+/** @defgroup pxenv_file_api_check PXENV_FILE_API_CHECK
+ *
+ * FILE API CHECK
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_api_check() */
+#define PXENV_FILE_API_CHECK		0x00e6
+
+/** Parameter block for pxenv_file_api_check() */
+struct s_PXENV_FILE_API_CHECK {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t Size;			/**< Size of structure  */
+	UINT32_t Magic;			/**< Magic number */
+	UINT32_t Provider;		/**< Implementation identifier */
+	UINT32_t APIMask;		/**< Supported API functions */
+	UINT32_t Flags;			/**< Reserved for the future */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_API_CHECK PXENV_FILE_API_CHECK_t;
+
+extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check );
+
+/** @} */ /* pxenv_file_api_check */
+
+/** @defgroup pxenv_file_exit_hook PXENV_FILE_EXIT_HOOK
+ *
+ * FILE EXIT HOOK
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_exit_hook() */
+#define PXENV_FILE_EXIT_HOOK			0x00e7
+
+/** Parameter block for pxenv_file_exit_hook() */
+struct s_PXENV_FILE_EXIT_HOOK {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	SEGOFF16_t Hook;		/**< SEG16:OFF16 to jump to */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_EXIT_HOOK PXENV_FILE_EXIT_HOOK_t;
+
+extern PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook );
+
+/** @} */ /* pxenv_file_exit_hook */
+
+/** @} */ /* pxe_file_api */
+
+/** @defgroup pxe_loader_api PXE Loader API
+ *
+ * The UNDI ROM loader API
+ *
+ * @{
+ */
+
+/** Parameter block for undi_loader() */
+struct s_UNDI_LOADER {
+	/** PXE status code */
+	PXENV_STATUS_t Status;
+	/** %ax register as for PXENV_START_UNDI */
+	UINT16_t AX;
+	/** %bx register as for PXENV_START_UNDI */
+	UINT16_t BX;
+	/** %dx register as for PXENV_START_UNDI */
+	UINT16_t DX;
+	/** %di register as for PXENV_START_UNDI */
+	OFF16_t DI;
+	/** %es register as for PXENV_START_UNDI */
+	SEGSEL_t ES;
+	/** UNDI data segment
+	 *
+	 * @note The PXE specification defines the type of this field
+	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
+	 * equivalent anyway; for other architectures #SEGSEL_t makes
+	 * more sense.
+	 */
+	SEGSEL_t UNDI_DS;
+	/** UNDI code segment
+	 *
+	 * @note The PXE specification defines the type of this field
+	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
+	 * equivalent anyway; for other architectures #SEGSEL_t makes
+	 * more sense.
+	 */
+	SEGSEL_t UNDI_CS;
+	/** Address of the !PXE structure (a struct s_PXE) */
+	SEGOFF16_t PXEptr;
+	/** Address of the PXENV+ structure (a struct s_PXENV) */
+	SEGOFF16_t PXENVptr;
+} __attribute__ (( packed ));
+
+typedef struct s_UNDI_LOADER UNDI_LOADER_t;
+
+extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
+
+/** @} */ /* pxe_loader_api */
+
+/** @} */ /* pxe */
+
+/** @page pxe_notes Etherboot PXE implementation notes
+
+ at section pxe_routing IP routing
+
+Several PXE API calls (e.g. pxenv_tftp_open() and pxenv_udp_write())
+allow for the caller to specify a "relay agent IP address", often in a
+field called "gateway" or similar.  The PXE specification states that
+"The IP layer should provide space for a minimum of four routing
+entries obtained from the default router and static route DHCP option
+tags in the DHCPACK message, plus any non-zero giaddr field from the
+DHCPOFFER message(s) accepted by the client".
+
+The DHCP static route option ("option static-routes" in dhcpd.conf)
+works only for classed IP routing (i.e. it provides no way to specify
+a subnet mask).  Since virtually everything now uses classless IP
+routing, the DHCP static route option is almost totally useless, and
+is (according to the dhcp-options man page) not implemented by any of
+the popular DHCP clients.
+
+This leaves the caller-specified "relay agent IP address", the giaddr
+field from the DHCPOFFER message(s) and the default gateway(s)
+provided via the routers option ("option routers" in dhcpd.conf) in
+the DHCPACK message.  Each of these is a default gateway address.
+It's a fair bet that the routers option should take priority over the
+giaddr field, since the routers option has to be explicitly specified
+by the DHCP server operator.  Similarly, it's fair to assume that the
+caller-specified "relay agent IP address", if present, should take
+priority over any other routing table entries.
+
+ at bug Etherboot currently ignores all potential sources of routing
+information other than the first router provided to it by a DHCP
+routers option.
+
+ at section pxe_x86_modes x86 processor mode restrictions
+
+On the x86 platform, different PXE API calls have different
+restrictions on the processor modes (real or protected) that can be
+used.  See the individual API call descriptions for the restrictions
+that apply to any particular call.
+
+ at subsection pxe_x86_pmode16 Real mode, or protected-mode with 16-bit stack
+
+The PXE specification states that the API function can be called in
+protected mode only if the s_PXE::StatusCallout field is set to a
+non-zero value, and that the API function cannot be called with a
+32-bit stack segment.
+
+Etherboot does not enforce either of these restrictions; they seem (as
+with so much of the PXE specification) to be artifacts of the Intel
+implementation.
+
+*/
+
+#endif /* PXE_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_call.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_call.h
new file mode 100644
index 0000000..45af465
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_call.h
@@ -0,0 +1,43 @@
+#ifndef _PXE_CALL_H
+#define _PXE_CALL_H
+
+/** @file
+ *
+ * PXE API entry point
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <pxe_api.h>
+#include <realmode.h>
+#include <setjmp.h>
+
+struct net_device;
+
+/** PXE load address segment */
+#define PXE_LOAD_SEGMENT 0
+
+/** PXE load address offset */
+#define PXE_LOAD_OFFSET 0x7c00
+
+/** PXE physical load address */
+#define PXE_LOAD_PHYS ( ( PXE_LOAD_SEGMENT << 4 ) + PXE_LOAD_OFFSET )
+
+/** !PXE structure */
+extern struct s_PXE __text16 ( ppxe );
+#define ppxe __use_text16 ( ppxe )
+
+/** PXENV+ structure */
+extern struct s_PXENV __text16 ( pxenv );
+#define pxenv __use_text16 ( pxenv )
+
+/** PXENV_RESTART_TFTP jump buffer */
+extern rmjmp_buf pxe_restart_nbp;
+
+extern void pxe_activate ( struct net_device *netdev );
+extern int pxe_deactivate ( void );
+extern int pxe_start_nbp ( void );
+extern __asmcall void pxe_api_call ( struct i386_all_regs *ix86 );
+extern int pxe_api_call_weak ( struct i386_all_regs *ix86 );
+
+#endif /* _PXE_CALL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_types.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_types.h
new file mode 100644
index 0000000..db82145
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxe_types.h
@@ -0,0 +1,127 @@
+#ifndef PXE_TYPES_H
+#define PXE_TYPES_H
+
+/** @file
+ *
+ * PXE data types
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h> /* PXE status codes */
+
+/** @addtogroup pxe Preboot eXecution Environment (PXE) API
+ *  @{
+ */
+
+/** @defgroup pxe_types PXE data types
+ *
+ * Basic PXE data types such as #UINT16_t, #ADDR32_t, #SEGSEL_t etc.
+ *
+ * These definitions are based on Table 1-1 ("Data Type Definitions")
+ * in the Intel PXE specification version 2.1.  They have been
+ * generalised to non-x86 architectures where possible.
+ *
+ * @{
+ */
+
+/** An 8-bit unsigned integer */
+typedef uint8_t UINT8_t;
+
+/** A 16-bit unsigned integer */
+typedef uint16_t UINT16_t;
+
+/** A 32-bit unsigned integer */
+typedef uint32_t UINT32_t;
+
+/** A PXE exit code.
+ *
+ * Permitted values are #PXENV_EXIT_SUCCESS and #PXENV_EXIT_FAILURE.
+ *
+ */
+typedef UINT16_t PXENV_EXIT_t;
+#define PXENV_EXIT_SUCCESS	0x0000	/**< No error occurred */
+#define PXENV_EXIT_FAILURE	0x0001	/**< An error occurred */
+
+/** A PXE status code.
+ *
+ * Status codes are defined in errno.h.
+ *
+ */
+typedef UINT16_t PXENV_STATUS_t;
+
+/** An IPv4 address.
+ *
+ * @note This data type is in network (big-endian) byte order.
+ *
+ */
+typedef UINT32_t IP4_t;
+
+/** A UDP port.
+ *
+ * @note This data type is in network (big-endian) byte order.
+ *
+ */
+typedef UINT16_t UDP_PORT_t;
+
+/** Maximum length of a MAC address */
+#define MAC_ADDR_LEN 16
+
+/** A MAC address */
+typedef UINT8_t MAC_ADDR_t[MAC_ADDR_LEN];
+
+#ifndef HAVE_ARCH_ADDR32
+/** A physical address.
+ *
+ * For x86, this is a 32-bit physical address, and is therefore
+ * limited to the low 4GB.
+ *
+ */
+typedef UINT32_t ADDR32_t;
+#endif
+
+#ifndef HAVE_ARCH_SEGSEL
+/** A segment selector.
+ *
+ * For x86, this is a real mode segment (0x0000-0xffff), or a
+ * protected-mode segment selector, such as could be loaded into a
+ * segment register.
+ *
+ */
+typedef UINT16_t SEGSEL_t;
+#endif
+
+#ifndef HAVE_ARCH_OFF16
+/** An offset within a segment identified by #SEGSEL
+ *
+ * For x86, this is a 16-bit offset.
+ *
+ */
+typedef UINT16_t OFF16_t;
+#endif
+
+/** A segment:offset address
+ *
+ * For x86, this is a 16-bit real-mode or protected-mode
+ * segment:offset address.
+ *
+ */
+typedef struct s_SEGOFF16 {
+	OFF16_t		offset;		/**< Offset within the segment */
+	SEGSEL_t	segment;	/**< Segment selector */
+} __attribute__ (( packed )) SEGOFF16_t;
+
+/** A segment descriptor */
+typedef struct s_SEGDESC {
+	SEGSEL_t	segment_address;	/**< Segment selector */
+	ADDR32_t	Physical_address;	/**< Segment base address */
+	OFF16_t		Seg_size;		/**< Size of the segment */
+} __attribute__ (( packed )) SEGDESC_t;
+
+/** @} */ /* pxe_types */
+
+/** @} */ /* pxe */
+
+#endif /* PXE_TYPES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxeparent.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxeparent.h
new file mode 100644
index 0000000..b31e24a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/pxeparent.h
@@ -0,0 +1,11 @@
+#ifndef PXEPARENT_H
+#define PXEPARENT_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <pxe_types.h>
+
+extern int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
+			    void *params, size_t params_len );
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/realmode.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/realmode.h
new file mode 100644
index 0000000..dafc5a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/realmode.h
@@ -0,0 +1,127 @@
+#ifndef REALMODE_H
+#define REALMODE_H
+
+#include <stdint.h>
+#include <registers.h>
+#include <ipxe/uaccess.h>
+
+/*
+ * Data structures and type definitions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * Declaration of variables in .data16
+ *
+ * To place a variable in the .data16 segment, declare it using the
+ * pattern:
+ *
+ *   int __data16 ( foo );
+ *   #define foo __use_data16 ( foo );
+ *
+ *   extern uint32_t __data16 ( bar );
+ *   #define bar __use_data16 ( bar );
+ *
+ *   static long __data16 ( baz ) = 0xff000000UL;
+ *   #define baz __use_data16 ( baz );
+ *
+ * i.e. take a normal declaration, add __data16() around the variable
+ * name, and add a line saying "#define <name> __use_data16 ( <name> )
+ *
+ * You can then access them just like any other variable, for example
+ *
+ *   int x = foo + bar;
+ *
+ * This magic is achieved at a cost of only around 7 extra bytes per
+ * group of accesses to .data16 variables.  When using KEEP_IT_REAL,
+ * there is no extra cost.
+ *
+ * You should place variables in .data16 when they need to be accessed
+ * by real-mode code.  Real-mode assembly (e.g. as created by
+ * REAL_CODE()) can access these variables via the usual data segment.
+ * You can therefore write something like
+ *
+ *   static uint16_t __data16 ( foo );
+ *   #define foo __use_data16 ( foo )
+ *
+ *   int bar ( void ) {
+ *     __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t"
+ *                                        "movw %ax, foo" )
+ *                            : : );
+ *     return foo;
+ *   }
+ *
+ * Variables may also be placed in .text16 using __text16 and
+ * __use_text16.  Some variables (e.g. chained interrupt vectors) fit
+ * most naturally in .text16; most should be in .data16.
+ *
+ * If you have only a pointer to a magic symbol within .data16 or
+ * .text16, rather than the symbol itself, you can attempt to extract
+ * the underlying symbol name using __from_data16() or
+ * __from_text16().  This is not for the faint-hearted; check the
+ * assembler output to make sure that it's doing the right thing.
+ */
+
+/**
+ * Copy data to base memory
+ *
+ * @v dest_seg		Destination segment
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v len		Length
+ */
+static inline __always_inline void
+copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
+	       void *src, size_t n ) {
+	copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
+}
+
+/**
+ * Copy data to base memory
+ *
+ * @v dest		Destination
+ * @v src_seg		Source segment
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+static inline __always_inline void
+copy_from_real ( void *dest, unsigned int src_seg,
+		 unsigned int src_off, size_t n ) {
+	copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
+}
+
+/**
+ * Write a single variable to base memory
+ *
+ * @v var		Variable to write
+ * @v dest_seg		Destination segment
+ * @v dest_off		Destination offset
+ */
+#define put_real( var, dest_seg, dest_off ) \
+	copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
+
+/**
+ * Read a single variable from base memory
+ *
+ * @v var		Variable to read
+ * @v src_seg		Source segment
+ * @v src_off		Source offset
+ */
+#define get_real( var, src_seg, src_off ) \
+	copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
+
+/*
+ * REAL_CODE ( asm_code_str )
+ *
+ * This can be used in inline assembly to create a fragment of code
+ * that will execute in real mode.  For example: to write a character
+ * to the BIOS console using INT 10, you would do something like:
+ *
+ *     __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
+ *			      : "=a" ( character ) : "a" ( 0x0000 ) );
+ *
+ */
+
+#endif /* REALMODE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/registers.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/registers.h
new file mode 100644
index 0000000..06d2365
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/registers.h
@@ -0,0 +1,198 @@
+#ifndef REGISTERS_H
+#define REGISTERS_H
+
+/** @file
+ *
+ * i386 registers.
+ *
+ * This file defines data structures that allow easy access to i386
+ * register dumps.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/**
+ * A 16-bit general register.
+ *
+ * This type encapsulates a 16-bit register such as %ax, %bx, %cx,
+ * %dx, %si, %di, %bp or %sp.
+ *
+ */
+typedef union {
+	struct {
+		union {
+			uint8_t l;
+			uint8_t byte;
+		};
+		uint8_t h;
+	} __attribute__ (( packed ));
+	uint16_t word;
+} __attribute__ (( packed )) reg16_t;
+
+/**
+ * A 32-bit general register.
+ *
+ * This type encapsulates a 32-bit register such as %eax, %ebx, %ecx,
+ * %edx, %esi, %edi, %ebp or %esp.
+ *
+ */
+typedef union {
+	struct {
+		union {
+			uint8_t l;
+			uint8_t byte;
+		};
+		uint8_t h;
+	} __attribute__ (( packed ));
+	uint16_t word;
+	uint32_t dword;
+} __attribute__ (( packed )) reg32_t;
+
+/**
+ * A 32-bit general register dump.
+ *
+ * This is the data structure that is created on the stack by the @c
+ * pushal instruction, and can be read back using the @c popal
+ * instruction.
+ *
+ */
+struct i386_regs {
+	union {
+		uint16_t di;
+		uint32_t edi;
+	};
+	union {
+		uint16_t si;
+		uint32_t esi;
+	};
+	union {
+		uint16_t bp;
+		uint32_t ebp;
+	};
+	union {
+		uint16_t sp;
+		uint32_t esp;
+	};
+	union {
+		struct {
+			uint8_t bl;
+			uint8_t bh;
+		} __attribute__ (( packed ));
+		uint16_t bx;
+		uint32_t ebx;
+	};
+	union {
+		struct {
+			uint8_t dl;
+			uint8_t dh;
+		} __attribute__ (( packed ));
+		uint16_t dx;
+		uint32_t edx;
+	};
+	union {
+		struct {
+			uint8_t cl;
+			uint8_t ch;
+		} __attribute__ (( packed ));
+		uint16_t cx;
+		uint32_t ecx;
+	};
+	union {
+		struct {
+			uint8_t al;
+			uint8_t ah;
+		} __attribute__ (( packed ));
+		uint16_t ax;
+		uint32_t eax;
+	};
+} __attribute__ (( packed ));
+
+/**
+ * A segment register dump.
+ *
+ * The i386 has no equivalent of the @c pushal or @c popal
+ * instructions for the segment registers.  We adopt the convention of
+ * always using the sequences
+ *
+ * @code
+ *
+ *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and
+ *
+ * @code
+ *
+ *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *
+ * @endcode
+ *
+ * This is the data structure that is created and read back by these
+ * instruction sequences.
+ *
+ */
+struct i386_seg_regs {
+	uint16_t cs;
+	uint16_t ss;
+	uint16_t ds;
+	uint16_t es;
+	uint16_t fs;
+	uint16_t gs;
+} __attribute__ (( packed ));
+
+/**
+ * A full register dump.
+ *
+ * This data structure is created by the instructions
+ *
+ * @code
+ *
+ *   pushfl
+ *   pushal
+ *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and can be read back using the instructions
+ *
+ * @code
+ *
+ *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *   popal
+ *   popfl
+ *
+ * @endcode
+ *
+ * prot_call() and kir_call() create this data structure on the stack
+ * and pass in a pointer to this structure.
+ *
+ */
+struct i386_all_regs {
+	struct i386_seg_regs segs;
+	struct i386_regs regs;
+	uint32_t flags;
+} __attribute__ (( packed ));
+
+/* Flags */
+#define CF ( 1 <<  0 )
+#define PF ( 1 <<  2 )
+#define AF ( 1 <<  4 )
+#define ZF ( 1 <<  6 )
+#define SF ( 1 <<  7 )
+#define OF ( 1 << 11 )
+
+/* Segment:offset structure.  Note that the order within the structure
+ * is offset:segment.
+ */
+struct segoff {
+	uint16_t offset;
+	uint16_t segment;
+} __attribute__ (( packed ));
+
+typedef struct segoff segoff_t;
+
+#endif /* REGISTERS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/setjmp.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/setjmp.h
new file mode 100644
index 0000000..5d3c11b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/setjmp.h
@@ -0,0 +1,40 @@
+#ifndef ETHERBOOT_SETJMP_H
+#define ETHERBOOT_SETJMP_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+
+/** A jump buffer */
+typedef struct {
+	uint32_t retaddr;
+	uint32_t ebx;
+	uint32_t esp;
+	uint32_t ebp;
+	uint32_t esi;
+	uint32_t edi;
+} jmp_buf[1];
+
+/** A real-mode-extended jump buffer */
+typedef struct {
+	jmp_buf env;
+	uint16_t rm_ss;
+	uint16_t rm_sp;
+} rmjmp_buf[1];
+
+extern int __asmcall setjmp ( jmp_buf env );
+extern void __asmcall longjmp ( jmp_buf env, int val );
+
+#define rmsetjmp( _env ) ( {			\
+	(_env)->rm_ss = rm_ss;			\
+	(_env)->rm_sp = rm_sp;			\
+	setjmp ( (_env)->env ); } )		\
+
+#define rmlongjmp( _env, _val ) do {		\
+	rm_ss = (_env)->rm_ss;			\
+	rm_sp = (_env)->rm_sp;			\
+	longjmp ( (_env)->env, (_val) );	\
+	} while ( 0 )
+
+#endif /* ETHERBOOT_SETJMP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undi.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undi.h
new file mode 100644
index 0000000..325fcbb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undi.h
@@ -0,0 +1,106 @@
+#ifndef _UNDI_H
+#define _UNDI_H
+
+/** @file
+ *
+ * UNDI driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef ASSEMBLY
+
+#include <ipxe/device.h>
+#include <pxe_types.h>
+
+/** An UNDI device
+ *
+ * This structure is used by assembly code as well as C; do not alter
+ * this structure without editing pxeprefix.S to match.
+ */
+struct undi_device {
+	/** PXENV+ structure address */
+	SEGOFF16_t pxenv;
+	/** !PXE structure address */
+	SEGOFF16_t ppxe;
+	/** Entry point */
+	SEGOFF16_t entry;
+	/** Free base memory after load */
+	UINT16_t fbms;
+	/** Free base memory prior to load */
+	UINT16_t restore_fbms;
+	/** PCI bus:dev.fn, or @c UNDI_NO_PCI_BUSDEVFN */
+	UINT16_t pci_busdevfn;
+	/** ISAPnP card select number, or @c UNDI_NO_ISAPNP_CSN */
+	UINT16_t isapnp_csn;
+	/** ISAPnP read port, or @c UNDI_NO_ISAPNP_READ_PORT */
+	UINT16_t isapnp_read_port;
+	/** PCI vendor ID
+	 *
+	 * Filled in only for the preloaded UNDI device by pxeprefix.S
+	 */
+	UINT16_t pci_vendor;
+	/** PCI device ID 
+	 *
+	 * Filled in only for the preloaded UNDI device by pxeprefix.S
+	 */
+	UINT16_t pci_device;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more UNDI_FL_XXX
+	 * constants.
+	 */
+	UINT16_t flags;
+
+	/** Generic device */
+	struct device dev;
+	/** Driver-private data
+	 *
+	 * Use undi_set_drvdata() and undi_get_drvdata() to access this
+	 * field.
+	 */
+	void *priv;
+} __attribute__ (( packed ));
+
+/**
+ * Set UNDI driver-private data
+ *
+ * @v undi		UNDI device
+ * @v priv		Private data
+ */
+static inline void undi_set_drvdata ( struct undi_device *undi, void *priv ) {
+	undi->priv = priv;
+}
+
+/**
+ * Get UNDI driver-private data
+ *
+ * @v undi		UNDI device
+ * @ret priv		Private data
+ */
+static inline void * undi_get_drvdata ( struct undi_device *undi ) {
+	return undi->priv;
+}
+
+#endif /* ASSEMBLY */
+
+/** PCI bus:dev.fn field is invalid */
+#define UNDI_NO_PCI_BUSDEVFN 0xffff
+
+/** ISAPnP card select number field is invalid */
+#define UNDI_NO_ISAPNP_CSN 0xffff
+
+/** ISAPnP read port field is invalid */
+#define UNDI_NO_ISAPNP_READ_PORT 0xffff
+
+/** UNDI flag: START_UNDI has been called */
+#define UNDI_FL_STARTED 0x0001
+
+/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */
+#define UNDI_FL_INITIALIZED 0x0002
+
+/** UNDI flag: keep stack resident */
+#define UNDI_FL_KEEP_ALL 0x0004
+
+#endif /* _UNDI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undiload.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undiload.h
new file mode 100644
index 0000000..426830e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undiload.h
@@ -0,0 +1,35 @@
+#ifndef _UNDILOAD_H
+#define _UNDILOAD_H
+
+/** @file
+ *
+ * UNDI load/unload
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct undi_device;
+struct undi_rom;
+
+extern int undi_load ( struct undi_device *undi, struct undi_rom *undirom );
+extern int undi_unload ( struct undi_device *undi );
+
+/**
+ * Call UNDI loader to create a pixie
+ *
+ * @v undi		UNDI device
+ * @v undirom		UNDI ROM
+ * @v pci_busdevfn	PCI bus:dev.fn
+ * @ret rc		Return status code
+ */
+static inline int undi_load_pci ( struct undi_device *undi,
+				  struct undi_rom *undirom,
+				  unsigned int pci_busdevfn ) {
+	undi->pci_busdevfn = pci_busdevfn;
+	undi->isapnp_csn = UNDI_NO_ISAPNP_CSN;
+	undi->isapnp_read_port = UNDI_NO_ISAPNP_READ_PORT;
+	return undi_load ( undi, undirom );
+}
+
+#endif /* _UNDILOAD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undinet.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undinet.h
new file mode 100644
index 0000000..c3c17c1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undinet.h
@@ -0,0 +1,17 @@
+#ifndef _UNDINET_H
+#define _UNDINET_H
+
+/** @file
+ *
+ * UNDI network device driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct undi_device;
+
+extern int undinet_probe ( struct undi_device *undi );
+extern void undinet_remove ( struct undi_device *undi );
+
+#endif /* _UNDINET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undipreload.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undipreload.h
new file mode 100644
index 0000000..de9b8fb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undipreload.h
@@ -0,0 +1,18 @@
+#ifndef _UNDIPRELOAD_H
+#define _UNDIPRELOAD_H
+
+/** @file
+ *
+ * Preloaded UNDI stack
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+#include <undi.h>
+
+extern struct undi_device __data16 ( preloaded_undi );
+#define preloaded_undi __use_data16 ( preloaded_undi )
+
+#endif /* _UNDIPRELOAD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undirom.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undirom.h
new file mode 100644
index 0000000..86d7077
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/undirom.h
@@ -0,0 +1,53 @@
+#ifndef _UNDIROM_H
+#define _UNDIROM_H
+
+/** @file
+ *
+ * UNDI expansion ROMs
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <pxe_types.h>
+
+/** An UNDI PCI device ID */
+struct undi_pci_device_id {
+	/** PCI vendor ID */
+	unsigned int vendor_id;
+	/** PCI device ID */
+	unsigned int device_id;
+};
+
+/** An UNDI device ID */
+union undi_device_id {
+	/** PCI device ID */
+	struct undi_pci_device_id pci;
+};
+
+/** An UNDI ROM */
+struct undi_rom {
+	/** List of UNDI ROMs */
+	struct list_head list;
+	/** ROM segment address */
+	unsigned int rom_segment;
+	/** UNDI loader entry point */
+	SEGOFF16_t loader_entry;
+	/** Code segment size */
+	size_t code_size;
+	/** Data segment size */
+	size_t data_size;
+	/** Bus type
+	 *
+	 * Values are as used by @c PXENV_UNDI_GET_NIC_TYPE
+	 */
+	unsigned int bus_type;
+	/** Device ID */
+	union undi_device_id bus_id;
+};
+
+extern struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
+					    unsigned int device_id,
+					    unsigned int rombase );
+
+#endif /* _UNDIROM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/include/vga.h b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/vga.h
new file mode 100644
index 0000000..01fc39d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/include/vga.h
@@ -0,0 +1,228 @@
+/*
+ *
+ * modified
+ * by Steve M. Gehlbach <steve at kesa.com>
+ *
+ * Originally  from linux/drivers/video/vga16.c by
+ * Ben Pfaff <pfaffben at debian.org> and Petr Vandrovec <VANDROVE at vc.cvut.cz>
+ * Copyright 1999 Ben Pfaff <pfaffben at debian.org> and Petr Vandrovec <VANDROVE at vc.cvut.cz>
+ * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel at goldbach.in-berlin.de>
+ *
+ */ 
+
+#ifndef VGA_H_INCL
+#define VGA_H_INCL 1
+
+//#include <cpu/p5/io.h>
+
+#define u8 unsigned char
+#define u16 unsigned short
+#define u32 unsigned int
+#define __u32 u32
+
+#define VERROR -1
+#define CHAR_HEIGHT 16
+#define LINES 25
+#define COLS 80
+
+// macros for writing to vga regs
+#define write_crtc(data,addr) outb(addr,CRT_IC); outb(data,CRT_DC)
+#define write_att(data,addr) inb(IS1_RC); inb(0x80); outb(addr,ATT_IW); inb(0x80); outb(data,ATT_IW); inb(0x80)
+#define write_seq(data,addr) outb(addr,SEQ_I); outb(data,SEQ_D)
+#define write_gra(data,addr) outb(addr,GRA_I); outb(data,GRA_D)
+u8 read_seq_b(u16 addr);
+u8 read_gra_b(u16 addr);
+u8 read_crtc_b(u16 addr);
+u8 read_att_b(u16 addr);
+
+
+#ifdef VGA_HARDWARE_FIXUP
+void vga_hardware_fixup(void);
+#else
+#define vga_hardware_fixup() do{} while(0)
+#endif
+
+#define SYNC_HOR_HIGH_ACT    1       /* horizontal sync high active  */
+#define SYNC_VERT_HIGH_ACT   2       /* vertical sync high active    */
+#define SYNC_EXT             4       /* external sync                */
+#define SYNC_COMP_HIGH_ACT   8       /* composite sync high active   */
+#define SYNC_BROADCAST       16      /* broadcast video timings      */
+                                        /* vtotal = 144d/288n/576i => PAL  */
+                                        /* vtotal = 121d/242n/484i => NTSC */
+
+#define SYNC_ON_GREEN        32      /* sync on green */
+
+#define VMODE_NONINTERLACED  0       /* non interlaced */
+#define VMODE_INTERLACED     1       /* interlaced   */
+#define VMODE_DOUBLE         2       /* double scan */
+#define VMODE_MASK           255
+
+#define VMODE_YWRAP          256     /* ywrap instead of panning     */
+#define VMODE_SMOOTH_XPAN    512     /* smooth xpan possible (internally used) */
+#define VMODE_CONUPDATE      512     /* don't update x/yoffset       */
+
+/* VGA data register ports */
+#define CRT_DC  0x3D5           /* CRT Controller Data Register - color emulation */
+#define CRT_DM  0x3B5           /* CRT Controller Data Register - mono emulation */
+#define ATT_R   0x3C1           /* Attribute Controller Data Read Register */
+#define GRA_D   0x3CF           /* Graphics Controller Data Register */
+#define SEQ_D   0x3C5           /* Sequencer Data Register */
+
+#define MIS_R   0x3CC           // Misc Output Read Register
+#define MIS_W   0x3C2           // Misc Output Write Register
+
+#define IS1_RC  0x3DA           /* Input Status Register 1 - color emulation */
+#define IS1_RM  0x3BA           /* Input Status Register 1 - mono emulation */
+#define PEL_D   0x3C9           /* PEL Data Register */
+#define PEL_MSK 0x3C6           /* PEL mask register */
+
+/* EGA-specific registers */
+#define GRA_E0  0x3CC           /* Graphics enable processor 0 */
+#define GRA_E1  0x3CA           /* Graphics enable processor 1 */
+
+
+/* VGA index register ports */
+#define CRT_IC  0x3D4           /* CRT Controller Index - color emulation */
+#define CRT_IM  0x3B4           /* CRT Controller Index - mono emulation */
+#define ATT_IW  0x3C0           /* Attribute Controller Index & Data Write Register */
+#define GRA_I   0x3CE           /* Graphics Controller Index */
+#define SEQ_I   0x3C4           /* Sequencer Index */
+#define PEL_IW  0x3C8           /* PEL Write Index */
+#define PEL_IR  0x3C7           /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define CRTC_C   25              /* 25 CRT Controller Registers sequentially set*/
+								 // the remainder are not in the par array
+#define ATT_C   21              /* 21 Attribute Controller Registers */
+#define GRA_C   9               /* 9  Graphics Controller Registers */
+#define SEQ_C   5               /* 5  Sequencer Registers */
+#define MIS_C   1               /* 1  Misc Output Register */
+
+#define CRTC_H_TOTAL            0
+#define CRTC_H_DISP             1
+#define CRTC_H_BLANK_START      2
+#define CRTC_H_BLANK_END        3
+#define CRTC_H_SYNC_START       4
+#define CRTC_H_SYNC_END         5
+#define CRTC_V_TOTAL            6
+#define CRTC_OVERFLOW           7
+#define CRTC_PRESET_ROW         8
+#define CRTC_MAX_SCAN           9
+#define CRTC_CURSOR_START       0x0A
+#define CRTC_CURSOR_END         0x0B
+#define CRTC_START_HI           0x0C
+#define CRTC_START_LO           0x0D
+#define CRTC_CURSOR_HI          0x0E
+#define CRTC_CURSOR_LO          0x0F
+#define CRTC_V_SYNC_START       0x10
+#define CRTC_V_SYNC_END         0x11
+#define CRTC_V_DISP_END         0x12
+#define CRTC_OFFSET             0x13
+#define CRTC_UNDERLINE          0x14
+#define CRTC_V_BLANK_START      0x15
+#define CRTC_V_BLANK_END        0x16
+#define CRTC_MODE               0x17
+#define CRTC_LINE_COMPARE       0x18
+
+#define ATC_MODE                0x10
+#define ATC_OVERSCAN            0x11
+#define ATC_PLANE_ENABLE        0x12
+#define ATC_PEL                 0x13
+#define ATC_COLOR_PAGE          0x14
+
+#define SEQ_CLOCK_MODE          0x01
+#define SEQ_PLANE_WRITE         0x02
+#define SEQ_CHARACTER_MAP       0x03
+#define SEQ_MEMORY_MODE         0x04
+
+#define GDC_SR_VALUE            0x00
+#define GDC_SR_ENABLE           0x01
+#define GDC_COMPARE_VALUE       0x02
+#define GDC_DATA_ROTATE         0x03
+#define GDC_PLANE_READ          0x04
+#define GDC_MODE                0x05
+#define GDC_MISC                0x06
+#define GDC_COMPARE_MASK        0x07
+#define GDC_BIT_MASK            0x08
+
+// text attributes
+#define VGA_ATTR_CLR_RED 0x4
+#define VGA_ATTR_CLR_GRN 0x2
+#define VGA_ATTR_CLR_BLU 0x1
+#define VGA_ATTR_CLR_YEL (VGA_ATTR_CLR_RED | VGA_ATTR_CLR_GRN)
+#define VGA_ATTR_CLR_CYN (VGA_ATTR_CLR_GRN | VGA_ATTR_CLR_BLU)
+#define VGA_ATTR_CLR_MAG (VGA_ATTR_CLR_BLU | VGA_ATTR_CLR_RED)
+#define VGA_ATTR_CLR_BLK 0
+#define VGA_ATTR_CLR_WHT (VGA_ATTR_CLR_RED | VGA_ATTR_CLR_GRN | VGA_ATTR_CLR_BLU)
+#define VGA_ATTR_BNK     0x80
+#define VGA_ATTR_ITN     0x08
+
+/*
+ * vga register parameters
+ * these are copied to the 
+ * registers.
+ *
+ */
+struct vga_par {
+        u8 crtc[CRTC_C];
+        u8 atc[ATT_C];
+        u8 gdc[GRA_C];
+        u8 seq[SEQ_C];
+        u8 misc; // the misc register, MIS_W
+        u8 vss;
+};
+
+
+/* Interpretation of offset for color fields: All offsets are from the right,
+ * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
+ * can use the offset as right argument to <<). A pixel afterwards is a bit
+ * stream and is written to video memory as that unmodified. This implies
+ * big-endian byte order if bits_per_pixel is greater than 8.
+ */
+struct fb_bitfield {
+        __u32 offset;                   /* beginning of bitfield        */
+        __u32 length;                   /* length of bitfield           */
+        __u32 msb_right;                /* != 0 : Most significant bit is */ 
+                                        /* right */ 
+};
+
+struct screeninfo {
+        __u32 xres;                     /* visible resolution           */
+        __u32 yres;
+        __u32 xres_virtual;             /* virtual resolution           */
+        __u32 yres_virtual;
+        __u32 xoffset;                  /* offset from virtual to visible */
+        __u32 yoffset;                  /* resolution                   */
+
+        __u32 bits_per_pixel;           /* guess what                   */
+        __u32 grayscale;                /* != 0 Graylevels instead of colors */
+
+        struct fb_bitfield red;         /* bitfield in fb mem if true color, */
+        struct fb_bitfield green;       /* else only length is significant */
+        struct fb_bitfield blue;
+        struct fb_bitfield transp;      /* transparency                 */      
+
+        __u32 nonstd;                   /* != 0 Non standard pixel format */
+
+        __u32 activate;                 /* see FB_ACTIVATE_*            */
+
+        __u32 height;                   /* height of picture in mm    */
+        __u32 width;                    /* width of picture in mm     */
+
+        __u32 accel_flags;              /* acceleration flags (hints)   */
+
+        /* Timing: All values in pixclocks, except pixclock (of course) */
+        __u32 pixclock;                 /* pixel clock in ps (pico seconds) */
+        __u32 left_margin;              /* time from sync to picture    */
+        __u32 right_margin;             /* time from picture to sync    */
+        __u32 upper_margin;             /* time from sync to picture    */
+        __u32 lower_margin;
+        __u32 hsync_len;                /* length of horizontal sync    */
+        __u32 vsync_len;                /* length of vertical sync      */
+        __u32 sync;                     /* sync polarity                */
+        __u32 vmode;                    /* interlaced etc				*/
+        __u32 reserved[6];              /* Reserved for future compatibility */
+};
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
new file mode 100644
index 0000000..7f46146
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
@@ -0,0 +1,16 @@
+#include <ipxe/nap.h>
+#include <realmode.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Save power by halting the CPU until the next interrupt
+ *
+ */
+static void bios_cpu_nap ( void ) {
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "hlt\n\t"
+					   "cli\n\t" ) : : );
+}
+
+PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
new file mode 100644
index 0000000..cde3d06
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/smbios.h>
+#include <realmode.h>
+#include <pnpbios.h>
+
+/** @file
+ *
+ * System Management BIOS
+ *
+ */
+
+/**
+ * Find SMBIOS
+ *
+ * @v smbios		SMBIOS entry point descriptor structure to fill in
+ * @ret rc		Return status code
+ */
+static int bios_find_smbios ( struct smbios *smbios ) {
+	union {
+		struct smbios_entry entry;
+		uint8_t bytes[256]; /* 256 is maximum length possible */
+	} u;
+	static unsigned int offset = 0;
+	size_t len;
+	unsigned int i;
+	uint8_t sum;
+
+	/* Try to find SMBIOS */
+	for ( ; offset < 0x10000 ; offset += 0x10 ) {
+
+		/* Read start of header and verify signature */
+		copy_from_real ( &u.entry, BIOS_SEG, offset,
+				 sizeof ( u.entry ));
+		if ( u.entry.signature != SMBIOS_SIGNATURE )
+			continue;
+
+		/* Read whole header and verify checksum */
+		len = u.entry.len;
+		copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
+		for ( i = 0 , sum = 0 ; i < len ; i++ ) {
+			sum += u.bytes[i];
+		}
+		if ( sum != 0 ) {
+			DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n",
+			      BIOS_SEG, offset, sum );
+			continue;
+		}
+
+		/* Fill result structure */
+		DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n",
+		      u.entry.major, u.entry.minor, BIOS_SEG, offset );
+		smbios->address = phys_to_user ( u.entry.smbios_address );
+		smbios->len = u.entry.smbios_len;
+		smbios->count = u.entry.smbios_count;
+		return 0;
+	}
+
+	DBG ( "No SMBIOS found\n" );
+	return -ENODEV;
+}
+
+PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
new file mode 100644
index 0000000..70c3986
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#include <ipxe/timer.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks		Current time, in ticks
+ *
+ * Use direct memory access to BIOS variables, longword 0040:006C
+ * (ticks today) and byte 0040:0070 (midnight crossover flag) instead
+ * of calling timeofday BIOS interrupt.
+ */
+static unsigned long bios_currticks ( void ) {
+	static int days = 0;
+	uint32_t ticks;
+	uint8_t midnight;
+
+	/* Re-enable interrupts so that the timer interrupt can occur */
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+					   "nop\n\t"
+					   "nop\n\t"
+					   "cli\n\t" ) : : );
+
+	get_real ( ticks, BDA_SEG, 0x006c );
+	get_real ( midnight, BDA_SEG, 0x0070 );
+
+	if ( midnight ) {
+		midnight = 0;
+		put_real ( midnight, BDA_SEG, 0x0070 );
+		days += 0x1800b0;
+	}
+
+	return ( days + ticks );
+}
+
+PROVIDE_TIMER_INLINE ( pcbios, udelay );
+PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
+PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
new file mode 100644
index 0000000..a193def
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
@@ -0,0 +1,92 @@
+#include <errno.h>
+#include <realmode.h>
+#include <biosint.h>
+
+/**
+ * @file BIOS interrupts
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Hook INT vector
+ *
+ * @v interrupt		INT number
+ * @v handler		Offset within .text16 to interrupt handler
+ * @v chain_vector	Vector for chaining to previous handler
+ *
+ * Hooks in an i386 INT handler.  The handler itself must reside
+ * within the .text16 segment.  @c chain_vector will be filled in with
+ * the address of the previously-installed handler for this interrupt;
+ * the handler should probably exit by ljmping via this vector.
+ */
+void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
+			   struct segoff *chain_vector ) {
+	struct segoff vector = {
+		.segment = rm_cs,
+		.offset = handler,
+	};
+
+	DBG ( "Hooking INT %#02x to %04x:%04x\n",
+	      interrupt, rm_cs, handler );
+
+	if ( ( chain_vector->segment != 0 ) ||
+	     ( chain_vector->offset != 0 ) ) {
+		/* Already hooked; do nothing */
+		DBG ( "...already hooked\n" );
+		return;
+	}
+
+	copy_from_real ( chain_vector, 0, ( interrupt * 4 ),
+			 sizeof ( *chain_vector ) );
+	DBG ( "...chaining to %04x:%04x\n",
+	      chain_vector->segment, chain_vector->offset );
+	if ( DBG_LOG ) {
+		char code[64];
+		copy_from_real ( code, chain_vector->segment,
+				 chain_vector->offset, sizeof ( code ) );
+		DBG_HDA ( *chain_vector, code, sizeof ( code ) );
+	}
+
+	copy_to_real ( 0, ( interrupt * 4 ), &vector, sizeof ( vector ) );
+	hooked_bios_interrupts++;
+}
+
+/**
+ * Unhook INT vector
+ *
+ * @v interrupt		INT number
+ * @v handler		Offset within .text16 to interrupt handler
+ * @v chain_vector	Vector containing address of previous handler
+ *
+ * Unhooks an i386 interrupt handler hooked by hook_i386_vector().
+ * Note that this operation may fail, if some external code has hooked
+ * the vector since we hooked in our handler.  If it fails, it means
+ * that it is not possible to unhook our handler, and we must leave it
+ * (and its chaining vector) resident in memory.
+ */
+int unhook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
+			    struct segoff *chain_vector ) {
+	struct segoff vector;
+
+	DBG ( "Unhooking INT %#02x from %04x:%04x\n",
+	      interrupt, rm_cs, handler );
+
+	copy_from_real ( &vector, 0, ( interrupt * 4 ), sizeof ( vector ) );
+	if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) ) {
+		DBG ( "...cannot unhook; vector points to %04x:%04x\n",
+		      vector.segment, vector.offset );
+		return -EBUSY;
+	}
+
+	DBG ( "...restoring to %04x:%04x\n",
+	      chain_vector->segment, chain_vector->offset );
+	copy_to_real ( 0, ( interrupt * 4 ), chain_vector,
+		       sizeof ( *chain_vector ) );
+
+	chain_vector->segment = 0;
+	chain_vector->offset = 0;
+	hooked_bios_interrupts--;
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/int13.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
new file mode 100644
index 0000000..392dbd5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
@@ -0,0 +1,1434 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/list.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/io.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/process.h>
+#include <ipxe/xfer.h>
+#include <ipxe/retry.h>
+#include <ipxe/timer.h>
+#include <ipxe/acpi.h>
+#include <ipxe/sanboot.h>
+#include <ipxe/device.h>
+#include <ipxe/pci.h>
+#include <realmode.h>
+#include <bios.h>
+#include <biosint.h>
+#include <bootsector.h>
+#include <int13.h>
+
+/** @file
+ *
+ * INT 13 emulation
+ *
+ * This module provides a mechanism for exporting block devices via
+ * the BIOS INT 13 disk interrupt interface.  
+ *
+ */
+
+/**
+ * Overall timeout for INT 13 commands (independent of underlying device
+ *
+ * Underlying devices should ideally never become totally stuck.
+ * However, if they do, then the INT 13 mechanism provides no means
+ * for the caller to cancel the operation, and the machine appears to
+ * hang.  Use an overall timeout for all commands to avoid this
+ * problem and bounce timeout failures to the caller.
+ */
+#define INT13_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )
+
+/** An INT 13 emulated drive */
+struct int13_drive {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of all registered drives */
+	struct list_head list;
+
+	/** Block device URI */
+	struct uri *uri;
+	/** Underlying block device interface */
+	struct interface block;
+
+	/** BIOS in-use drive number (0x80-0xff) */
+	unsigned int drive;
+	/** BIOS natural drive number (0x80-0xff)
+	 *
+	 * This is the drive number that would have been assigned by
+	 * 'naturally' appending the drive to the end of the BIOS
+	 * drive list.
+	 *
+	 * If the emulated drive replaces a preexisting drive, this is
+	 * the drive number that the preexisting drive gets remapped
+	 * to.
+	 */
+	unsigned int natural_drive;
+
+	/** Block device capacity */
+	struct block_device_capacity capacity;
+
+	/** Number of cylinders
+	 *
+	 * The cylinder number field in an INT 13 call is ten bits
+	 * wide, giving a maximum of 1024 cylinders.  Conventionally,
+	 * when the 7.8GB limit of a CHS address is exceeded, it is
+	 * the number of cylinders that is increased beyond the
+	 * addressable limit.
+	 */
+	unsigned int cylinders;
+	/** Number of heads
+	 *
+	 * The head number field in an INT 13 call is eight bits wide,
+	 * giving a maximum of 256 heads.  However, apparently all
+	 * versions of MS-DOS up to and including Win95 fail with 256
+	 * heads, so the maximum encountered in practice is 255.
+	 */
+	unsigned int heads;
+	/** Number of sectors per track
+	 *
+	 * The sector number field in an INT 13 call is six bits wide,
+	 * giving a maximum of 63 sectors, since sector numbering
+	 * (unlike head and cylinder numbering) starts at 1, not 0.
+	 */
+	unsigned int sectors_per_track;
+
+	/** Underlying device status, if in error */
+	int block_rc;
+	/** Status of last operation */
+	int last_status;
+};
+
+/** Vector for chaining to other INT 13 handlers */
+static struct segoff __text16 ( int13_vector );
+#define int13_vector __use_text16 ( int13_vector )
+
+/** Assembly wrapper */
+extern void int13_wrapper ( void );
+
+/** List of registered emulated drives */
+static LIST_HEAD ( int13s );
+
+/**
+ * Number of BIOS drives
+ *
+ * Note that this is the number of drives in the system as a whole
+ * (i.e. a mirror of the counter at 40:75), rather than a count of the
+ * number of emulated drives.
+ */
+static uint8_t num_drives;
+
+/** An INT 13 command */
+struct int13_command {
+	/** Status */
+	int rc;
+	/** INT 13 drive */
+	struct int13_drive *int13;
+	/** Underlying block device interface */
+	struct interface block;
+	/** Command timeout timer */
+	struct retry_timer timer;
+};
+
+/**
+ * Record INT 13 drive capacity
+ *
+ * @v command		INT 13 command
+ * @v capacity		Block device capacity
+ */
+static void int13_command_capacity ( struct int13_command *command,
+				     struct block_device_capacity *capacity ) {
+	memcpy ( &command->int13->capacity, capacity,
+		 sizeof ( command->int13->capacity ) );
+}
+
+/**
+ * Close INT 13 command
+ *
+ * @v command		INT 13 command
+ * @v rc		Reason for close
+ */
+static void int13_command_close ( struct int13_command *command, int rc ) {
+	intf_restart ( &command->block, rc );
+	stop_timer ( &command->timer );
+	command->rc = rc;
+}
+
+/**
+ * Handle INT 13 command timer expiry
+ *
+ * @v timer		Timer
+ */
+static void int13_command_expired ( struct retry_timer *timer,
+				    int over __unused ) {
+	struct int13_command *command =
+		container_of ( timer, struct int13_command, timer );
+
+	int13_command_close ( command, -ETIMEDOUT );
+}
+
+/** INT 13 command interface operations */
+static struct interface_operation int13_command_op[] = {
+	INTF_OP ( intf_close, struct int13_command *, int13_command_close ),
+	INTF_OP ( block_capacity, struct int13_command *,
+		  int13_command_capacity ),
+};
+
+/** INT 13 command interface descriptor */
+static struct interface_descriptor int13_command_desc =
+	INTF_DESC ( struct int13_command, block, int13_command_op );
+
+/**
+ * Open (or reopen) INT 13 emulated drive underlying block device
+ *
+ * @v int13		Emulated drive
+ * @ret rc		Return status code
+ */
+static int int13_reopen_block ( struct int13_drive *int13 ) {
+	int rc;
+
+	/* Close any existing block device */
+	intf_restart ( &int13->block, -ECONNRESET );
+
+	/* Open block device */
+	if ( ( rc = xfer_open_uri ( &int13->block, int13->uri ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not reopen block "
+		       "device: %s\n", int13->drive, strerror ( rc ) );
+		int13->block_rc = rc;
+		return rc;
+	}
+
+	/* Clear block device error status */
+	int13->block_rc = 0;
+
+	return 0;
+}
+
+/**
+ * Prepare to issue INT 13 command
+ *
+ * @v command		INT 13 command
+ * @v int13		Emulated drive
+ * @ret rc		Return status code
+ */
+static int int13_command_start ( struct int13_command *command,
+				 struct int13_drive *int13 ) {
+	int rc;
+
+	/* Sanity check */
+	assert ( command->int13 == NULL );
+	assert ( ! timer_running ( &command->timer ) );
+
+	/* Reopen block device if necessary */
+	if ( ( int13->block_rc != 0 ) &&
+	     ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) )
+		return rc;
+
+	/* Initialise command */
+	command->rc = -EINPROGRESS;
+	command->int13 = int13;
+	start_timer_fixed ( &command->timer, INT13_COMMAND_TIMEOUT );
+
+	/* Wait for block control interface to become ready */
+	while ( ( command->rc == -EINPROGRESS ) &&
+		( xfer_window ( &int13->block ) == 0 ) ) {
+		step();
+	}
+
+	return ( ( command->rc == -EINPROGRESS ) ?
+		 int13->block_rc : command->rc );
+}
+
+/**
+ * Wait for INT 13 command to complete
+ *
+ * @v command		INT 13 command
+ * @ret rc		Return status code
+ */
+static int int13_command_wait ( struct int13_command *command ) {
+
+	/* Sanity check */
+	assert ( timer_running ( &command->timer ) );
+
+	/* Wait for command to complete */
+	while ( command->rc == -EINPROGRESS )
+		step();
+
+	assert ( ! timer_running ( &command->timer ) );
+	return command->rc;
+}
+
+/**
+ * Terminate INT 13 command
+ *
+ * @v command		INT 13 command
+ */
+static void int13_command_stop ( struct int13_command *command ) {
+	stop_timer ( &command->timer );
+	command->int13 = NULL;
+}
+
+/** The single active INT 13 command */
+static struct int13_command int13_command = {
+	.block = INTF_INIT ( int13_command_desc ),
+	.timer = TIMER_INIT ( int13_command_expired ),
+};
+
+/**
+ * Read from or write to INT 13 drive
+ *
+ * @v int13		Emulated drive
+ * @v lba		Starting logical block address
+ * @v count		Number of logical blocks
+ * @v buffer		Data buffer
+ * @v block_rw		Block read/write method
+ * @ret rc		Return status code
+ */
+static int int13_rw ( struct int13_drive *int13, uint64_t lba,
+		      unsigned int count, userptr_t buffer,
+		      int ( * block_rw ) ( struct interface *control,
+					   struct interface *data,
+					   uint64_t lba, unsigned int count,
+					   userptr_t buffer, size_t len ) ) {
+	struct int13_command *command = &int13_command;
+	unsigned int frag_count;
+	size_t frag_len;
+	int rc;
+
+	while ( count ) {
+
+		/* Determine fragment length */
+		frag_count = count;
+		if ( frag_count > int13->capacity.max_count )
+			frag_count = int13->capacity.max_count;
+		frag_len = ( int13->capacity.blksize * frag_count );
+
+		/* Issue command */
+		if ( ( ( rc = int13_command_start ( command, int13 ) ) != 0 ) ||
+		     ( ( rc = block_rw ( &int13->block, &command->block, lba,
+					 frag_count, buffer,
+					 frag_len ) ) != 0 ) ||
+		     ( ( rc = int13_command_wait ( command ) ) != 0 ) ) {
+			int13_command_stop ( command );
+			return rc;
+		}
+		int13_command_stop ( command );
+
+		/* Move to next fragment */
+		lba += frag_count;
+		count -= frag_count;
+		buffer = userptr_add ( buffer, frag_len );
+	}
+
+	return 0;
+}
+
+/**
+ * Read INT 13 drive capacity
+ *
+ * @v int13		Emulated drive
+ * @ret rc		Return status code
+ */
+static int int13_read_capacity ( struct int13_drive *int13 ) {
+	struct int13_command *command = &int13_command;
+	int rc;
+
+	/* Issue command */
+	if ( ( ( rc = int13_command_start ( command, int13 ) ) != 0 ) ||
+	     ( ( rc = block_read_capacity ( &int13->block,
+					    &command->block ) ) != 0 ) ||
+	     ( ( rc = int13_command_wait ( command ) ) != 0 ) ) {
+		int13_command_stop ( command );
+		return rc;
+	}
+
+	int13_command_stop ( command );
+	return 0;
+}
+
+/**
+ * Guess INT 13 drive geometry
+ *
+ * @v int13		Emulated drive
+ * @ret rc		Return status code
+ *
+ * Guesses the drive geometry by inspecting the partition table.
+ */
+static int int13_guess_geometry ( struct int13_drive *int13 ) {
+	struct master_boot_record mbr;
+	struct partition_table_entry *partition;
+	unsigned int guessed_heads = 255;
+	unsigned int guessed_sectors_per_track = 63;
+	unsigned long blocks;
+	unsigned long blocks_per_cyl;
+	unsigned int i;
+	int rc;
+
+	/* Don't even try when the blksize is invalid for C/H/S access */
+	if ( int13->capacity.blksize != INT13_BLKSIZE )
+		return 0;
+
+	/* Read partition table */
+	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( &mbr ),
+			       block_read ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not read partition "
+		       "table to guess geometry: %s\n",
+		       int13->drive, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( int13, "INT13 drive %02x has MBR:\n", int13->drive );
+	DBGC2_HDA ( int13, 0, &mbr, sizeof ( mbr ) );
+	DBGC ( int13, "INT13 drive %02x has signature %08x\n",
+	       int13->drive, mbr.signature );
+
+	/* Scan through partition table and modify guesses for heads
+	 * and sectors_per_track if we find any used partitions.
+	 */
+	for ( i = 0 ; i < 4 ; i++ ) {
+		partition = &mbr.partitions[i];
+		if ( ! partition->type )
+			continue;
+		guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
+		guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
+		DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
+		       "on partition %d\n", int13->drive, guessed_heads,
+		       guessed_sectors_per_track, ( i + 1 ) );
+	}
+
+	/* Apply guesses if no geometry already specified */
+	if ( ! int13->heads )
+		int13->heads = guessed_heads;
+	if ( ! int13->sectors_per_track )
+		int13->sectors_per_track = guessed_sectors_per_track;
+	if ( ! int13->cylinders ) {
+		/* Avoid attempting a 64-bit divide on a 32-bit system */
+		blocks = ( ( int13->capacity.blocks <= ULONG_MAX ) ?
+			   int13->capacity.blocks : ULONG_MAX );
+		blocks_per_cyl = ( int13->heads * int13->sectors_per_track );
+		assert ( blocks_per_cyl != 0 );
+		int13->cylinders = ( blocks / blocks_per_cyl );
+		if ( int13->cylinders > 1024 )
+			int13->cylinders = 1024;
+	}
+
+	return 0;
+}
+
+/**
+ * Update BIOS drive count
+ */
+static void int13_set_num_drives ( void ) {
+	struct int13_drive *int13;
+
+	/* Get current drive count */
+	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
+
+	/* Ensure count is large enough to cover all of our emulated drives */
+	list_for_each_entry ( int13, &int13s, list ) {
+		if ( num_drives <= ( int13->drive & 0x7f ) )
+			num_drives = ( ( int13->drive & 0x7f ) + 1 );
+	}
+
+	/* Update current drive count */
+	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
+}
+
+/**
+ * Check number of drives
+ */
+static void int13_check_num_drives ( void ) {
+	uint8_t check_num_drives;
+
+	get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
+	if ( check_num_drives != num_drives ) {
+		int13_set_num_drives();
+		DBG ( "INT13 fixing up number of drives from %d to %d\n",
+		      check_num_drives, num_drives );
+	}
+}
+
+/**
+ * INT 13, 00 - Reset disk system
+ *
+ * @v int13		Emulated drive
+ * @ret status		Status code
+ */
+static int int13_reset ( struct int13_drive *int13,
+			 struct i386_all_regs *ix86 __unused ) {
+	int rc;
+
+	DBGC2 ( int13, "Reset drive\n" );
+
+	/* Reopen underlying block device */
+	if ( ( rc = int13_reopen_block ( int13 ) ) != 0 )
+		return -INT13_STATUS_RESET_FAILED;
+
+	/* Check that block device is functional */
+	if ( ( rc = int13_read_capacity ( int13 ) ) != 0 )
+		return -INT13_STATUS_RESET_FAILED;
+
+	return 0;
+}
+
+/**
+ * INT 13, 01 - Get status of last operation
+ *
+ * @v int13		Emulated drive
+ * @ret status		Status code
+ */
+static int int13_get_last_status ( struct int13_drive *int13,
+				   struct i386_all_regs *ix86 __unused ) {
+	DBGC2 ( int13, "Get status of last operation\n" );
+	return int13->last_status;
+}
+
+/**
+ * Read / write sectors
+ *
+ * @v int13		Emulated drive
+ * @v al		Number of sectors to read or write (must be nonzero)
+ * @v ch		Low bits of cylinder number
+ * @v cl (bits 7:6)	High bits of cylinder number
+ * @v cl (bits 5:0)	Sector number
+ * @v dh		Head number
+ * @v es:bx		Data buffer
+ * @v block_rw		Block read/write method
+ * @ret status		Status code
+ * @ret al		Number of sectors read or written
+ */
+static int int13_rw_sectors ( struct int13_drive *int13,
+			      struct i386_all_regs *ix86,
+			      int ( * block_rw ) ( struct interface *control,
+						   struct interface *data,
+						   uint64_t lba,
+						   unsigned int count,
+						   userptr_t buffer,
+						   size_t len ) ) {
+	unsigned int cylinder, head, sector;
+	unsigned long lba;
+	unsigned int count;
+	userptr_t buffer;
+	int rc;
+
+	/* Validate blocksize */
+	if ( int13->capacity.blksize != INT13_BLKSIZE ) {
+		DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
+		       "for non-extended read/write\n",
+		       int13->drive, int13->capacity.blksize );
+		return -INT13_STATUS_INVALID;
+	}
+	
+	/* Calculate parameters */
+	cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
+	assert ( cylinder < int13->cylinders );
+	head = ix86->regs.dh;
+	assert ( head < int13->heads );
+	sector = ( ix86->regs.cl & 0x3f );
+	assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
+	lba = ( ( ( ( cylinder * int13->heads ) + head )
+		  * int13->sectors_per_track ) + sector - 1 );
+	count = ix86->regs.al;
+	buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );
+
+	DBGC2 ( int13, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n",
+		cylinder, head, sector, lba, ix86->segs.es, ix86->regs.bx,
+		count );
+
+	/* Read from / write to block device */
+	if ( ( rc = int13_rw ( int13, lba, count, buffer, block_rw ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x I/O failed: %s\n",
+		       int13->drive, strerror ( rc ) );
+		return -INT13_STATUS_READ_ERROR;
+	}
+
+	return 0;
+}
+
+/**
+ * INT 13, 02 - Read sectors
+ *
+ * @v int13		Emulated drive
+ * @v al		Number of sectors to read (must be nonzero)
+ * @v ch		Low bits of cylinder number
+ * @v cl (bits 7:6)	High bits of cylinder number
+ * @v cl (bits 5:0)	Sector number
+ * @v dh		Head number
+ * @v es:bx		Data buffer
+ * @ret status		Status code
+ * @ret al		Number of sectors read
+ */
+static int int13_read_sectors ( struct int13_drive *int13,
+				struct i386_all_regs *ix86 ) {
+	DBGC2 ( int13, "Read: " );
+	return int13_rw_sectors ( int13, ix86, block_read );
+}
+
+/**
+ * INT 13, 03 - Write sectors
+ *
+ * @v int13		Emulated drive
+ * @v al		Number of sectors to write (must be nonzero)
+ * @v ch		Low bits of cylinder number
+ * @v cl (bits 7:6)	High bits of cylinder number
+ * @v cl (bits 5:0)	Sector number
+ * @v dh		Head number
+ * @v es:bx		Data buffer
+ * @ret status		Status code
+ * @ret al		Number of sectors written
+ */
+static int int13_write_sectors ( struct int13_drive *int13,
+				 struct i386_all_regs *ix86 ) {
+	DBGC2 ( int13, "Write: " );
+	return int13_rw_sectors ( int13, ix86, block_write );
+}
+
+/**
+ * INT 13, 08 - Get drive parameters
+ *
+ * @v int13		Emulated drive
+ * @ret status		Status code
+ * @ret ch		Low bits of maximum cylinder number
+ * @ret cl (bits 7:6)	High bits of maximum cylinder number
+ * @ret cl (bits 5:0)	Maximum sector number
+ * @ret dh		Maximum head number
+ * @ret dl		Number of drives
+ */
+static int int13_get_parameters ( struct int13_drive *int13,
+				  struct i386_all_regs *ix86 ) {
+	unsigned int max_cylinder = int13->cylinders - 1;
+	unsigned int max_head = int13->heads - 1;
+	unsigned int max_sector = int13->sectors_per_track; /* sic */
+
+	DBGC2 ( int13, "Get drive parameters\n" );
+
+	ix86->regs.ch = ( max_cylinder & 0xff );
+	ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
+	ix86->regs.dh = max_head;
+	get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
+	return 0;
+}
+
+/**
+ * INT 13, 15 - Get disk type
+ *
+ * @v int13		Emulated drive
+ * @ret ah		Type code
+ * @ret cx:dx		Sector count
+ * @ret status		Status code / disk type
+ */
+static int int13_get_disk_type ( struct int13_drive *int13,
+				 struct i386_all_regs *ix86 ) {
+	uint32_t blocks;
+
+	DBGC2 ( int13, "Get disk type\n" );
+	blocks = ( ( int13->capacity.blocks <= 0xffffffffUL ) ?
+		   int13->capacity.blocks : 0xffffffffUL );
+	ix86->regs.cx = ( blocks >> 16 );
+	ix86->regs.dx = ( blocks & 0xffff );
+	return INT13_DISK_TYPE_HDD;
+}
+
+/**
+ * INT 13, 41 - Extensions installation check
+ *
+ * @v int13		Emulated drive
+ * @v bx		0x55aa
+ * @ret bx		0xaa55
+ * @ret cx		Extensions API support bitmap
+ * @ret status		Status code / API version
+ */
+static int int13_extension_check ( struct int13_drive *int13 __unused,
+				   struct i386_all_regs *ix86 ) {
+	if ( ix86->regs.bx == 0x55aa ) {
+		DBGC2 ( int13, "INT13 extensions installation check\n" );
+		ix86->regs.bx = 0xaa55;
+		ix86->regs.cx = ( INT13_EXTENSION_LINEAR |
+				  INT13_EXTENSION_EDD |
+				  INT13_EXTENSION_64BIT );
+		return INT13_EXTENSION_VER_3_0;
+	} else {
+		return -INT13_STATUS_INVALID;
+	}
+}
+
+/**
+ * Extended read / write
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Disk address packet
+ * @v block_rw		Block read/write method
+ * @ret status		Status code
+ */
+static int int13_extended_rw ( struct int13_drive *int13,
+			       struct i386_all_regs *ix86,
+			       int ( * block_rw ) ( struct interface *control,
+						    struct interface *data,
+						    uint64_t lba,
+						    unsigned int count,
+						    userptr_t buffer,
+						    size_t len ) ) {
+	struct int13_disk_address addr;
+	uint8_t bufsize;
+	uint64_t lba;
+	unsigned long count;
+	userptr_t buffer;
+	int rc;
+
+	/* Get buffer size */
+	get_real ( bufsize, ix86->segs.ds,
+		   ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
+	if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) {
+		DBGC2 ( int13, "<invalid buffer size %#02x\n>\n", bufsize );
+		return -INT13_STATUS_INVALID;
+	}
+
+	/* Read parameters from disk address structure */
+	memset ( &addr, 0, sizeof ( addr ) );
+	copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize );
+	lba = addr.lba;
+	DBGC2 ( int13, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) );
+	if ( ( addr.count == 0xff ) ||
+	     ( ( addr.buffer.segment == 0xffff ) &&
+	       ( addr.buffer.offset == 0xffff ) ) ) {
+		buffer = phys_to_user ( addr.buffer_phys );
+		DBGC2 ( int13, "%08llx",
+			( ( unsigned long long ) addr.buffer_phys ) );
+	} else {
+		buffer = real_to_user ( addr.buffer.segment,
+					addr.buffer.offset );
+		DBGC2 ( int13, "%04x:%04x", addr.buffer.segment,
+			addr.buffer.offset );
+	}
+	if ( addr.count <= 0x7f ) {
+		count = addr.count;
+	} else if ( addr.count == 0xff ) {
+		count = addr.long_count;
+	} else {
+		DBGC2 ( int13, " <invalid count %#02x>\n", addr.count );
+		return -INT13_STATUS_INVALID;
+	}
+	DBGC2 ( int13, " (count %ld)\n", count );
+
+	/* Read from / write to block device */
+	if ( ( rc = int13_rw ( int13, lba, count, buffer, block_rw ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x extended I/O failed: %s\n",
+		       int13->drive, strerror ( rc ) );
+		/* Record that no blocks were transferred successfully */
+		addr.count = 0;
+		put_real ( addr.count, ix86->segs.ds,
+			   ( ix86->regs.si +
+			     offsetof ( typeof ( addr ), count ) ) );
+		return -INT13_STATUS_READ_ERROR;
+	}
+
+	return 0;
+}
+
+/**
+ * INT 13, 42 - Extended read
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Disk address packet
+ * @ret status		Status code
+ */
+static int int13_extended_read ( struct int13_drive *int13,
+				 struct i386_all_regs *ix86 ) {
+	DBGC2 ( int13, "Extended read: " );
+	return int13_extended_rw ( int13, ix86, block_read );
+}
+
+/**
+ * INT 13, 43 - Extended write
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Disk address packet
+ * @ret status		Status code
+ */
+static int int13_extended_write ( struct int13_drive *int13,
+				  struct i386_all_regs *ix86 ) {
+	DBGC2 ( int13, "Extended write: " );
+	return int13_extended_rw ( int13, ix86, block_write );
+}
+
+/**
+ * INT 13, 44 - Verify sectors
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Disk address packet
+ * @ret status		Status code
+ */
+static int int13_extended_verify ( struct int13_drive *int13,
+				   struct i386_all_regs *ix86 ) {
+	struct int13_disk_address addr;
+	uint64_t lba;
+	unsigned long count;
+
+	/* Read parameters from disk address structure */
+	if ( DBG_EXTRA ) {
+		copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
+				 sizeof ( addr ));
+		lba = addr.lba;
+		count = addr.count;
+		DBGC2 ( int13, "Verify: LBA %08llx (count %ld)\n",
+			( ( unsigned long long ) lba ), count );
+	}
+
+	/* We have no mechanism for verifying sectors */
+	return -INT13_STATUS_INVALID;
+}
+
+/**
+ * INT 13, 44 - Extended seek
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Disk address packet
+ * @ret status		Status code
+ */
+static int int13_extended_seek ( struct int13_drive *int13,
+				 struct i386_all_regs *ix86 ) {
+	struct int13_disk_address addr;
+	uint64_t lba;
+	unsigned long count;
+
+	/* Read parameters from disk address structure */
+	if ( DBG_EXTRA ) {
+		copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
+				 sizeof ( addr ));
+		lba = addr.lba;
+		count = addr.count;
+		DBGC2 ( int13, "Seek: LBA %08llx (count %ld)\n",
+			( ( unsigned long long ) lba ), count );
+	}
+
+	/* Ignore and return success */
+	return 0;
+}
+
+/**
+ * Build device path information
+ *
+ * @v int13		Emulated drive
+ * @v dpi		Device path information
+ * @ret rc		Return status code
+ */
+static int int13_device_path_info ( struct int13_drive *int13,
+				    struct edd_device_path_information *dpi ) {
+	struct device *device;
+	struct device_description *desc;
+	unsigned int i;
+	uint8_t sum = 0;
+	int rc;
+
+	/* Reopen block device if necessary */
+	if ( ( int13->block_rc != 0 ) &&
+	     ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) )
+		return rc;
+
+	/* Get underlying hardware device */
+	device = identify_device ( &int13->block );
+	if ( ! device ) {
+		DBGC ( int13, "INT13 drive %02x cannot identify hardware "
+		       "device\n", int13->drive );
+		return -ENODEV;
+	}
+
+	/* Fill in bus type and interface path */
+	desc = &device->desc;
+	switch ( desc->bus_type ) {
+	case BUS_TYPE_PCI:
+		dpi->host_bus_type.type = EDD_BUS_TYPE_PCI;
+		dpi->interface_path.pci.bus = PCI_BUS ( desc->location );
+		dpi->interface_path.pci.slot = PCI_SLOT ( desc->location );
+		dpi->interface_path.pci.function = PCI_FUNC ( desc->location );
+		dpi->interface_path.pci.channel = 0xff; /* unused */
+		break;
+	default:
+		DBGC ( int13, "INT13 drive %02x unrecognised bus type %d\n",
+		       int13->drive, desc->bus_type );
+		return -ENOTSUP;
+	}
+
+	/* Get EDD block device description */
+	if ( ( rc = edd_describe ( &int13->block, &dpi->interface_type,
+				   &dpi->device_path ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x cannot identify block device: "
+		       "%s\n", int13->drive, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Fill in common fields and fix checksum */
+	dpi->key = EDD_DEVICE_PATH_INFO_KEY;
+	dpi->len = sizeof ( *dpi );
+	for ( i = 0 ; i < sizeof ( *dpi ) ; i++ )
+		sum += *( ( ( uint8_t * ) dpi ) + i );
+	dpi->checksum -= sum;
+
+	return 0;
+}
+
+/**
+ * INT 13, 48 - Get extended parameters
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Drive parameter table
+ * @ret status		Status code
+ */
+static int int13_get_extended_parameters ( struct int13_drive *int13,
+					   struct i386_all_regs *ix86 ) {
+	struct int13_disk_parameters params;
+	struct segoff address;
+	size_t len = sizeof ( params );
+	uint16_t bufsize;
+	int rc;
+
+	/* Get buffer size */
+	get_real ( bufsize, ix86->segs.ds,
+		   ( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));
+
+	DBGC2 ( int13, "Get extended drive parameters to %04x:%04x+%02x\n",
+		ix86->segs.ds, ix86->regs.si, bufsize );
+
+	/* Build drive parameters */
+	memset ( &params, 0, sizeof ( params ) );
+	params.flags = INT13_FL_DMA_TRANSPARENT;
+	if ( ( int13->cylinders < 1024 ) &&
+	     ( int13->capacity.blocks <= INT13_MAX_CHS_SECTORS ) ) {
+		params.flags |= INT13_FL_CHS_VALID;
+	}
+	params.cylinders = int13->cylinders;
+	params.heads = int13->heads;
+	params.sectors_per_track = int13->sectors_per_track;
+	params.sectors = int13->capacity.blocks;
+	params.sector_size = int13->capacity.blksize;
+	memset ( &params.dpte, 0xff, sizeof ( params.dpte ) );
+	if ( ( rc = int13_device_path_info ( int13, &params.dpi ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not provide device "
+		       "path information: %s\n",
+		       int13->drive, strerror ( rc ) );
+		len = offsetof ( typeof ( params ), dpi );
+	}
+
+	/* Calculate returned "buffer size" (which will be less than
+	 * the length actually copied if device path information is
+	 * present).
+	 */
+	if ( bufsize < offsetof ( typeof ( params ), dpte ) )
+		return -INT13_STATUS_INVALID;
+	if ( bufsize < offsetof ( typeof ( params ), dpi ) ) {
+		params.bufsize = offsetof ( typeof ( params ), dpte );
+	} else {
+		params.bufsize = offsetof ( typeof ( params ), dpi );
+	}
+
+	DBGC ( int13, "INT 13 drive %02x described using extended "
+	       "parameters:\n", int13->drive );
+	address.segment = ix86->segs.ds;
+	address.offset = ix86->regs.si;
+	DBGC_HDA ( int13, address, &params, len );
+
+	/* Return drive parameters */
+	if ( len > bufsize )
+		len = bufsize;
+	copy_to_real ( ix86->segs.ds, ix86->regs.si, &params, len );
+
+	return 0;
+}
+
+/**
+ * INT 13 handler
+ *
+ */
+static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
+	int command = ix86->regs.ah;
+	unsigned int bios_drive = ix86->regs.dl;
+	struct int13_drive *int13;
+	int status;
+
+	/* Check BIOS hasn't killed off our drive */
+	int13_check_num_drives();
+
+	list_for_each_entry ( int13, &int13s, list ) {
+
+		if ( bios_drive != int13->drive ) {
+			/* Remap any accesses to this drive's natural number */
+			if ( bios_drive == int13->natural_drive ) {
+				DBGC2 ( int13, "INT13,%02x (%02x) remapped to "
+					"(%02x)\n", ix86->regs.ah,
+					bios_drive, int13->drive );
+				ix86->regs.dl = int13->drive;
+				return;
+			}
+			continue;
+		}
+		
+		DBGC2 ( int13, "INT13,%02x (%02x): ",
+			ix86->regs.ah, int13->drive );
+
+		switch ( command ) {
+		case INT13_RESET:
+			status = int13_reset ( int13, ix86 );
+			break;
+		case INT13_GET_LAST_STATUS:
+			status = int13_get_last_status ( int13, ix86 );
+			break;
+		case INT13_READ_SECTORS:
+			status = int13_read_sectors ( int13, ix86 );
+			break;
+		case INT13_WRITE_SECTORS:
+			status = int13_write_sectors ( int13, ix86 );
+			break;
+		case INT13_GET_PARAMETERS:
+			status = int13_get_parameters ( int13, ix86 );
+			break;
+		case INT13_GET_DISK_TYPE:
+			status = int13_get_disk_type ( int13, ix86 );
+			break;
+		case INT13_EXTENSION_CHECK:
+			status = int13_extension_check ( int13, ix86 );
+			break;
+		case INT13_EXTENDED_READ:
+			status = int13_extended_read ( int13, ix86 );
+			break;
+		case INT13_EXTENDED_WRITE:
+			status = int13_extended_write ( int13, ix86 );
+			break;
+		case INT13_EXTENDED_VERIFY:
+			status = int13_extended_verify ( int13, ix86 );
+			break;
+		case INT13_EXTENDED_SEEK:
+			status = int13_extended_seek ( int13, ix86 );
+			break;
+		case INT13_GET_EXTENDED_PARAMETERS:
+			status = int13_get_extended_parameters ( int13, ix86 );
+			break;
+		default:
+			DBGC2 ( int13, "*** Unrecognised INT13 ***\n" );
+			status = -INT13_STATUS_INVALID;
+			break;
+		}
+
+		/* Store status for INT 13,01 */
+		int13->last_status = status;
+
+		/* Negative status indicates an error */
+		if ( status < 0 ) {
+			status = -status;
+			DBGC ( int13, "INT13,%02x (%02x) failed with status "
+			       "%02x\n", ix86->regs.ah, int13->drive, status );
+		} else {
+			ix86->flags &= ~CF;
+		}
+		ix86->regs.ah = status;
+
+		/* Set OF to indicate to wrapper not to chain this call */
+		ix86->flags |= OF;
+
+		return;
+	}
+}
+
+/**
+ * Hook INT 13 handler
+ *
+ */
+static void int13_hook_vector ( void ) {
+	/* Assembly wrapper to call int13().  int13() sets OF if we
+	 * should not chain to the previous handler.  (The wrapper
+	 * clears CF and OF before calling int13()).
+	 */
+	__asm__  __volatile__ (
+	       TEXT16_CODE ( "\nint13_wrapper:\n\t"
+			     /* Preserve %ax and %dx for future reference */
+			     "pushw %%bp\n\t"
+			     "movw %%sp, %%bp\n\t"			     
+			     "pushw %%ax\n\t"
+			     "pushw %%dx\n\t"
+			     /* Clear OF, set CF, call int13() */
+			     "orb $0, %%al\n\t" 
+			     "stc\n\t"
+			     "pushl %0\n\t"
+			     "pushw %%cs\n\t"
+			     "call prot_call\n\t"
+			     /* Chain if OF not set */
+			     "jo 1f\n\t"
+			     "pushfw\n\t"
+			     "lcall *%%cs:int13_vector\n\t"
+			     "\n1:\n\t"
+			     /* Overwrite flags for iret */
+			     "pushfw\n\t"
+			     "popw 6(%%bp)\n\t"
+			     /* Fix up %dl:
+			      *
+			      * INT 13,15 : do nothing
+			      * INT 13,08 : load with number of drives
+			      * all others: restore original value
+			      */
+			     "cmpb $0x15, -1(%%bp)\n\t"
+			     "je 2f\n\t"
+			     "movb -4(%%bp), %%dl\n\t"
+			     "cmpb $0x08, -1(%%bp)\n\t"
+			     "jne 2f\n\t"
+			     "pushw %%ds\n\t"
+			     "pushw %1\n\t"
+			     "popw %%ds\n\t"
+			     "movb %c2, %%dl\n\t"
+			     "popw %%ds\n\t"
+			     /* Return */
+			     "\n2:\n\t"
+			     "movw %%bp, %%sp\n\t"
+			     "popw %%bp\n\t"
+			     "iret\n\t" )
+	       : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
+
+	hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
+			      &int13_vector );
+}
+
+/**
+ * Unhook INT 13 handler
+ */
+static void int13_unhook_vector ( void ) {
+	unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
+				&int13_vector );
+}
+
+/**
+ * Handle INT 13 emulated drive underlying block device closing
+ *
+ * @v int13		Emulated drive
+ * @v rc		Reason for close
+ */
+static void int13_block_close ( struct int13_drive *int13, int rc ) {
+
+	/* Any closing is an error from our point of view */
+	if ( rc == 0 )
+		rc = -ENOTCONN;
+
+	DBGC ( int13, "INT13 drive %02x went away: %s\n",
+	       int13->drive, strerror ( rc ) );
+
+	/* Record block device error code */
+	int13->block_rc = rc;
+
+	/* Shut down interfaces */
+	intf_restart ( &int13->block, rc );
+}
+
+/** INT 13 drive interface operations */
+static struct interface_operation int13_block_op[] = {
+	INTF_OP ( intf_close, struct int13_drive *, int13_block_close ),
+};
+
+/** INT 13 drive interface descriptor */
+static struct interface_descriptor int13_block_desc =
+	INTF_DESC ( struct int13_drive, block, int13_block_op );
+
+/**
+ * Free INT 13 emulated drive
+ *
+ * @v refcnt		Reference count
+ */
+static void int13_free ( struct refcnt *refcnt ) {
+	struct int13_drive *int13 =
+		container_of ( refcnt, struct int13_drive, refcnt );
+
+	uri_put ( int13->uri );
+	free ( int13 );
+}
+
+/**
+ * Hook INT 13 emulated drive
+ *
+ * @v uri		URI
+ * @v drive		Requested drive number
+ * @ret drive		Assigned drive number, or negative error
+ *
+ * Registers the drive with the INT 13 emulation subsystem, and hooks
+ * the INT 13 interrupt vector (if not already hooked).
+ */
+static int int13_hook ( struct uri *uri, unsigned int drive ) {
+	struct int13_drive *int13;
+	uint8_t num_drives;
+	unsigned int natural_drive;
+	int rc;
+
+	/* Calculate drive number */
+	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
+	natural_drive = ( num_drives | 0x80 );
+	if ( drive == INT13_USE_NATURAL_DRIVE )
+		drive = natural_drive;
+	drive |= 0x80;
+
+	/* Check that drive number is not in use */
+	list_for_each_entry ( int13, &int13s, list ) {
+		if ( int13->drive == drive ) {
+			rc = -EADDRINUSE;
+			goto err_in_use;
+		}
+	}
+
+	/* Allocate and initialise structure */
+	int13 = zalloc ( sizeof ( *int13 ) );
+	if ( ! int13 ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &int13->refcnt, int13_free );
+	intf_init ( &int13->block, &int13_block_desc, &int13->refcnt );
+	int13->uri = uri_get ( uri );
+	int13->drive = drive;
+	int13->natural_drive = natural_drive;
+
+	/* Open block device interface */
+	if ( ( rc = int13_reopen_block ( int13 ) ) != 0 )
+		goto err_reopen_block;
+
+	/* Read device capacity */
+	if ( ( rc = int13_read_capacity ( int13 ) ) != 0 )
+		return rc;
+
+	/* Give drive a default geometry */
+	if ( ( rc = int13_guess_geometry ( int13 ) ) != 0 )
+		goto err_guess_geometry;
+
+	DBGC ( int13, "INT13 drive %02x (naturally %02x) registered with C/H/S "
+	       "geometry %d/%d/%d\n", int13->drive, int13->natural_drive,
+	       int13->cylinders, int13->heads, int13->sectors_per_track );
+
+	/* Hook INT 13 vector if not already hooked */
+	if ( list_empty ( &int13s ) ) {
+		int13_hook_vector();
+		devices_get();
+	}
+
+	/* Add to list of emulated drives */
+	list_add ( &int13->list, &int13s );
+
+	/* Update BIOS drive count */
+	int13_set_num_drives();
+
+	return int13->drive;
+
+ err_guess_geometry:
+ err_reopen_block:
+	intf_shutdown ( &int13->block, rc );
+	ref_put ( &int13->refcnt );
+ err_zalloc:
+ err_in_use:
+	return rc;
+}
+
+/**
+ * Find INT 13 emulated drive by drive number
+ *
+ * @v drive		Drive number
+ * @ret int13		Emulated drive, or NULL
+ */
+static struct int13_drive * int13_find ( unsigned int drive ) {
+	struct int13_drive *int13;
+
+	list_for_each_entry ( int13, &int13s, list ) {
+		if ( int13->drive == drive )
+			return int13;
+	}
+	return NULL;
+}
+
+/**
+ * Unhook INT 13 emulated drive
+ *
+ * @v drive		Drive number
+ *
+ * Unregisters the drive from the INT 13 emulation subsystem.  If this
+ * is the last emulated drive, the INT 13 vector is unhooked (if
+ * possible).
+ */
+static void int13_unhook ( unsigned int drive ) {
+	struct int13_drive *int13;
+
+	/* Find drive */
+	int13 = int13_find ( drive );
+	if ( ! int13 ) {
+		DBG ( "INT13 cannot find emulated drive %02x\n", drive );
+		return;
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &int13->block, 0 );
+
+	/* Remove from list of emulated drives */
+	list_del ( &int13->list );
+
+	/* Should adjust BIOS drive count, but it's difficult
+	 * to do so reliably.
+	 */
+
+	DBGC ( int13, "INT13 drive %02x unregistered\n", int13->drive );
+
+	/* Unhook INT 13 vector if no more drives */
+	if ( list_empty ( &int13s ) ) {
+		devices_put();
+		int13_unhook_vector();
+	}
+
+	/* Drop list's reference to drive */
+	ref_put ( &int13->refcnt );
+}
+
+/**
+ * Attempt to boot from an INT 13 drive
+ *
+ * @v drive		Drive number
+ * @ret rc		Return status code
+ *
+ * This boots from the specified INT 13 drive by loading the Master
+ * Boot Record to 0000:7c00 and jumping to it.  INT 18 is hooked to
+ * capture an attempt by the MBR to boot the next device.  (This is
+ * the closest thing to a return path from an MBR).
+ *
+ * Note that this function can never return success, by definition.
+ */
+static int int13_boot ( unsigned int drive ) {
+	struct memory_map memmap;
+	int status, signature;
+	int discard_c, discard_d;
+	int rc;
+
+	DBG ( "INT13 drive %02x booting\n", drive );
+
+	/* Use INT 13 to read the boot sector */
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
+					   "pushw $0\n\t"
+					   "popw %%es\n\t"
+					   "stc\n\t"
+					   "sti\n\t"
+					   "int $0x13\n\t"
+					   "sti\n\t" /* BIOS bugs */
+					   "jc 1f\n\t"
+					   "xorl %%eax, %%eax\n\t"
+					   "\n1:\n\t"
+					   "movzwl %%es:0x7dfe, %%ebx\n\t"
+					   "popw %%es\n\t" )
+			       : "=a" ( status ), "=b" ( signature ),
+				 "=c" ( discard_c ), "=d" ( discard_d )
+			       : "a" ( 0x0201 ), "b" ( 0x7c00 ),
+				 "c" ( 1 ), "d" ( drive ) );
+	if ( status )
+		return -EIO;
+
+	/* Check signature is correct */
+	if ( signature != be16_to_cpu ( 0x55aa ) ) {
+		DBG ( "INT13 drive %02x invalid disk signature %#04x (should "
+		      "be 0x55aa)\n", drive, cpu_to_be16 ( signature ) );
+		return -ENOEXEC;
+	}
+
+	/* Dump out memory map prior to boot, if memmap debugging is
+	 * enabled.  Not required for program flow, but we have so
+	 * many problems that turn out to be memory-map related that
+	 * it's worth doing.
+	 */
+	get_memmap ( &memmap );
+
+	/* Jump to boot sector */
+	if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
+		DBG ( "INT13 drive %02x boot returned: %s\n",
+		      drive, strerror ( rc ) );
+		return rc;
+	}
+
+	return -ECANCELED; /* -EIMPOSSIBLE */
+}
+
+/** A boot firmware table generated by iPXE */
+union xbft_table {
+	/** ACPI header */
+	struct acpi_description_header acpi;
+	/** Padding */
+	char pad[768];
+};
+
+/** The boot firmware table generated by iPXE */
+static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
+#define xbftab __use_data16 ( xbftab )
+
+/**
+ * Describe INT 13 emulated drive for SAN-booted operating system
+ *
+ * @v drive		Drive number
+ * @ret rc		Return status code
+ */
+static int int13_describe ( unsigned int drive ) {
+	struct int13_drive *int13;
+	struct segoff xbft_address;
+	int rc;
+
+	/* Find drive */
+	int13 = int13_find ( drive );
+	if ( ! int13 ) {
+		DBG ( "INT13 cannot find emulated drive %02x\n", drive );
+		return -ENODEV;
+	}
+
+	/* Reopen block device if necessary */
+	if ( ( int13->block_rc != 0 ) &&
+	     ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) )
+		return rc;
+
+	/* Clear table */
+	memset ( &xbftab, 0, sizeof ( xbftab ) );
+
+	/* Fill in common parameters */
+	strncpy ( xbftab.acpi.oem_id, "FENSYS",
+		  sizeof ( xbftab.acpi.oem_id ) );
+	strncpy ( xbftab.acpi.oem_table_id, "iPXE",
+		  sizeof ( xbftab.acpi.oem_table_id ) );
+
+	/* Fill in remaining parameters */
+	if ( ( rc = acpi_describe ( &int13->block, &xbftab.acpi,
+				    sizeof ( xbftab ) ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not create ACPI "
+		       "description: %s\n", int13->drive, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Fix up ACPI checksum */
+	acpi_fix_checksum ( &xbftab.acpi );
+	xbft_address.segment = rm_ds;
+	xbft_address.offset = __from_data16 ( &xbftab );
+	DBGC ( int13, "INT13 drive %02x described using boot firmware "
+	       "table:\n", int13->drive );
+	DBGC_HDA ( int13, xbft_address, &xbftab,
+		   le32_to_cpu ( xbftab.acpi.length ) );
+
+	return 0;
+}
+
+PROVIDE_SANBOOT ( pcbios, san_hook, int13_hook );
+PROVIDE_SANBOOT ( pcbios, san_unhook, int13_unhook );
+PROVIDE_SANBOOT ( pcbios, san_boot, int13_boot );
+PROVIDE_SANBOOT ( pcbios, san_describe, int13_describe );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
new file mode 100644
index 0000000..16736e1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * External memory allocation
+ *
+ */
+
+#include <limits.h>
+#include <errno.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/hidemem.h>
+#include <ipxe/io.h>
+#include <ipxe/umalloc.h>
+
+/** Alignment of external allocated memory */
+#define EM_ALIGN ( 4 * 1024 )
+
+/** Equivalent of NOWHERE for user pointers */
+#define UNOWHERE ( ~UNULL )
+
+/** An external memory block */
+struct external_memory {
+	/** Size of this memory block (excluding this header) */
+	size_t size;
+	/** Block is currently in use */
+	int used;
+};
+
+/** Top of heap */
+static userptr_t top = UNULL;
+
+/** Bottom of heap (current lowest allocated block) */
+static userptr_t bottom = UNULL;
+
+/**
+ * Initialise external heap
+ *
+ * @ret rc		Return status code
+ */
+static int init_eheap ( void ) {
+	struct memory_map memmap;
+	unsigned long heap_size = 0;
+	unsigned int i;
+
+	DBG ( "Allocating external heap\n" );
+
+	get_memmap ( &memmap );
+	for ( i = 0 ; i < memmap.count ; i++ ) {
+		struct memory_region *region = &memmap.regions[i];
+		unsigned long r_start, r_end;
+		unsigned long r_size;
+
+		DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
+
+		/* Truncate block to 4GB */
+		if ( region->start > UINT_MAX ) {
+			DBG ( "...starts after 4GB\n" );
+			continue;
+		}
+		r_start = region->start;
+		if ( region->end > UINT_MAX ) {
+			DBG ( "...end truncated to 4GB\n" );
+			r_end = 0; /* =4GB, given the wraparound */
+		} else {
+			r_end = region->end;
+		}
+
+		/* Use largest block */
+		r_size = ( r_end - r_start );
+		if ( r_size > heap_size ) {
+			DBG ( "...new best block found\n" );
+			top = bottom = phys_to_user ( r_end );
+			heap_size = r_size;
+		}
+	}
+
+	if ( ! heap_size ) {
+		DBG ( "No external heap available\n" );
+		return -ENOMEM;
+	}
+
+	DBG ( "External heap grows downwards from %lx\n",
+	      user_to_phys ( top, 0 ) );
+	return 0;
+}
+
+/**
+ * Collect free blocks
+ *
+ */
+static void ecollect_free ( void ) {
+	struct external_memory extmem;
+
+	/* Walk the free list and collect empty blocks */
+	while ( bottom != top ) {
+		copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
+				 sizeof ( extmem ) );
+		if ( extmem.used )
+			break;
+		DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
+		      user_to_phys ( bottom, extmem.size ) );
+		bottom = userptr_add ( bottom,
+				       ( extmem.size + sizeof ( extmem ) ) );
+	}
+}
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr		Memory previously allocated by umalloc(), or UNULL
+ * @v new_size		Requested size
+ * @ret new_ptr		Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
+	struct external_memory extmem;
+	userptr_t new = ptr;
+	size_t align;
+	int rc;
+
+	/* Initialise external memory allocator if necessary */
+	if ( bottom == top ) {
+		if ( ( rc = init_eheap() ) != 0 )
+			return UNULL;
+	}
+
+	/* Get block properties into extmem */
+	if ( ptr && ( ptr != UNOWHERE ) ) {
+		/* Determine old size */
+		copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
+				 sizeof ( extmem ) );
+	} else {
+		/* Create a zero-length block */
+		ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
+		DBG ( "EXTMEM allocating [%lx,%lx)\n",
+		      user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
+		extmem.size = 0;
+	}
+	extmem.used = ( new_size > 0 );
+
+	/* Expand/shrink block if possible */
+	if ( ptr == bottom ) {
+		/* Update block */
+		new = userptr_add ( ptr, - ( new_size - extmem.size ) );
+		align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
+		new_size += align;
+		new = userptr_add ( new, -align );
+		DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
+		      user_to_phys ( ptr, 0 ),
+		      user_to_phys ( ptr, extmem.size ),
+		      user_to_phys ( new, 0 ),
+		      user_to_phys ( new, new_size ));
+		memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
+						 extmem.size : new_size ) );
+		extmem.size = new_size;
+		bottom = new;
+	} else {
+		/* Cannot expand; can only pretend to shrink */
+		if ( new_size > extmem.size ) {
+			/* Refuse to expand */
+			DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
+			      user_to_phys ( ptr, 0 ),
+			      user_to_phys ( ptr, extmem.size ) );
+			return UNULL;
+		}
+	}
+
+	/* Write back block properties */
+	copy_to_user ( new, -sizeof ( extmem ), &extmem,
+		       sizeof ( extmem ) );
+
+	/* Collect any free blocks and update hidden memory region */
+	ecollect_free();
+	hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
+		       user_to_phys ( top, 0 ) );
+
+	return ( new_size ? new : UNOWHERE );
+}
+
+PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
new file mode 100644
index 0000000..511ec62
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/pci.h>
+#include <realmode.h>
+
+/** @file
+ *
+ * PCI configuration space access via PCI BIOS
+ *
+ */
+
+/**
+ * Determine number of PCI buses within system
+ *
+ * @ret num_bus		Number of buses
+ */
+static int pcibios_num_bus ( void ) {
+	int discard_a, discard_D;
+	uint8_t max_bus;
+
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "int $0x1a\n\t"
+					   "jnc 1f\n\t"
+					   "xorw %%cx, %%cx\n\t"
+					   "\n1:\n\t" )
+			       : "=c" ( max_bus ), "=a" ( discard_a ),
+				 "=D" ( discard_D )
+			       : "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ),
+				 "D" ( 0 )
+			       : "ebx", "edx" );
+
+	return ( max_bus + 1 );
+}
+
+/**
+ * Read configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v command	PCI BIOS command
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ){
+	int discard_b, discard_D;
+	int status;
+
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "int $0x1a\n\t"
+					   "jnc 1f\n\t"
+					   "xorl %%eax, %%eax\n\t"
+					   "decl %%eax\n\t"
+					   "movl %%eax, %%ecx\n\t"
+					   "\n1:\n\t" )
+			       : "=a" ( status ), "=b" ( discard_b ),
+				 "=c" ( *value ), "=D" ( discard_D )
+			       : "a" ( command >> 16 ), "D" ( command ),
+				 "b" ( pci->busdevfn )
+			       : "edx" );
+
+	return ( ( status >> 8 ) & 0xff );
+}
+
+/**
+ * Write configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v command	PCI BIOS command
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
+	int discard_b, discard_c, discard_D;
+	int status;
+
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "int $0x1a\n\t"
+					   "jnc 1f\n\t"
+					   "movb $0xff, %%ah\n\t"
+					   "\n1:\n\t" )
+			       : "=a" ( status ), "=b" ( discard_b ),
+				 "=c" ( discard_c ), "=D" ( discard_D )
+			       : "a" ( command >> 16 ),	"D" ( command ),
+			         "b" ( pci->busdevfn ), "c" ( value )
+			       : "edx" );
+	
+	return ( ( status >> 8 ) & 0xff );
+}
+
+PROVIDE_PCIAPI ( pcbios, pci_num_bus, pcibios_num_bus );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
new file mode 100644
index 0000000..f320800
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/uaccess.h>
+#include <ipxe/init.h>
+#include <setjmp.h>
+#include <registers.h>
+#include <biosint.h>
+#include <pxe.h>
+#include <pxe_call.h>
+
+/** @file
+ *
+ * PXE API entry point
+ */
+
+/** Vector for chaining INT 1A */
+extern struct segoff __text16 ( pxe_int_1a_vector );
+#define pxe_int_1a_vector __use_text16 ( pxe_int_1a_vector )
+
+/** INT 1A handler */
+extern void pxe_int_1a ( void );
+
+/** INT 1A hooked flag */
+static int int_1a_hooked = 0;
+
+/** A function pointer to hold any PXE API call
+ *
+ * Used by pxe_api_call() to avoid large swathes of duplicated code.
+ */
+union pxenv_call {
+	PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * );
+	PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * );
+	PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * );
+	PXENV_EXIT_t ( * get_cached_info )
+			( struct s_PXENV_GET_CACHED_INFO * );
+	PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * );
+	PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * );
+	PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * );
+	PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * );
+	PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * );
+	PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * );
+	PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * );
+	PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * );
+	PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * );
+	PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * );
+	PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * );
+	PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * );
+	PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * );
+	PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * );
+	PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * );
+	PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * );
+	PXENV_EXIT_t ( * undi_initialize )
+			( struct s_PXENV_UNDI_INITIALIZE * );
+	PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * );
+	PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * );
+	PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * );
+	PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * );
+	PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * );
+	PXENV_EXIT_t ( * undi_set_mcast_address )
+			( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * );
+	PXENV_EXIT_t ( * undi_set_station_address )
+			( struct s_PXENV_UNDI_SET_STATION_ADDRESS * );
+	PXENV_EXIT_t ( * undi_set_packet_filter )
+			( struct s_PXENV_UNDI_SET_PACKET_FILTER * );
+	PXENV_EXIT_t ( * undi_get_information )
+			( struct s_PXENV_UNDI_GET_INFORMATION * );
+	PXENV_EXIT_t ( * undi_get_statistics )
+			( struct s_PXENV_UNDI_GET_STATISTICS * );
+	PXENV_EXIT_t ( * undi_clear_statistics )
+			( struct s_PXENV_UNDI_CLEAR_STATISTICS * );
+	PXENV_EXIT_t ( * undi_initiate_diags )
+			( struct s_PXENV_UNDI_INITIATE_DIAGS * );
+	PXENV_EXIT_t ( * undi_force_interrupt )
+			( struct s_PXENV_UNDI_FORCE_INTERRUPT * );
+	PXENV_EXIT_t ( * undi_get_mcast_address )
+			( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * );
+	PXENV_EXIT_t ( * undi_get_nic_type )
+			( struct s_PXENV_UNDI_GET_NIC_TYPE * );
+	PXENV_EXIT_t ( * undi_get_iface_info )
+			( struct s_PXENV_UNDI_GET_IFACE_INFO * );
+	PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
+	PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
+	PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * );
+	PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * );
+	PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * );
+	PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * );
+	PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * );
+	PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * );
+	PXENV_EXIT_t ( * file_api_check ) ( struct s_PXENV_FILE_API_CHECK * );
+	PXENV_EXIT_t ( * file_exit_hook ) ( struct s_PXENV_FILE_EXIT_HOOK * );
+};
+
+/**
+ * Handle an unknown PXE API call
+ *
+ * @v pxenv_unknown 			Pointer to a struct s_PXENV_UNKNOWN
+ * @ret #PXENV_EXIT_FAILURE		Always
+ * @err #PXENV_STATUS_UNSUPPORTED	Always
+ */
+static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
+	pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+}
+
+/**
+ * Dispatch PXE API call
+ *
+ * @v bx		PXE opcode
+ * @v es:di		Address of PXE parameter block
+ * @ret ax		PXE exit code
+ */
+__asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
+	int opcode = ix86->regs.bx;
+	userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
+	size_t param_len;
+	union u_PXENV_ANY pxenv_any;
+	union pxenv_call pxenv_call;
+	PXENV_EXIT_t ret;
+
+	switch ( opcode ) {
+	case PXENV_UNLOAD_STACK:
+		pxenv_call.unload_stack = pxenv_unload_stack;
+		param_len = sizeof ( pxenv_any.unload_stack );
+		break;
+	case PXENV_GET_CACHED_INFO:
+		pxenv_call.get_cached_info = pxenv_get_cached_info;
+		param_len = sizeof ( pxenv_any.get_cached_info );
+		break;
+	case PXENV_RESTART_TFTP:
+		pxenv_call.restart_tftp = pxenv_restart_tftp;
+		param_len = sizeof ( pxenv_any.restart_tftp );
+		break;
+	case PXENV_START_UNDI:
+		pxenv_call.start_undi = pxenv_start_undi;
+		param_len = sizeof ( pxenv_any.start_undi );
+		break;
+	case PXENV_STOP_UNDI:
+		pxenv_call.stop_undi = pxenv_stop_undi;
+		param_len = sizeof ( pxenv_any.stop_undi );
+		break;
+	case PXENV_START_BASE:
+		pxenv_call.start_base = pxenv_start_base;
+		param_len = sizeof ( pxenv_any.start_base );
+		break;
+	case PXENV_STOP_BASE:
+		pxenv_call.stop_base = pxenv_stop_base;
+		param_len = sizeof ( pxenv_any.stop_base );
+		break;
+	case PXENV_TFTP_OPEN:
+		pxenv_call.tftp_open = pxenv_tftp_open;
+		param_len = sizeof ( pxenv_any.tftp_open );
+		break;
+	case PXENV_TFTP_CLOSE:
+		pxenv_call.tftp_close = pxenv_tftp_close;
+		param_len = sizeof ( pxenv_any.tftp_close );
+		break;
+	case PXENV_TFTP_READ:
+		pxenv_call.tftp_read = pxenv_tftp_read;
+		param_len = sizeof ( pxenv_any.tftp_read );
+		break;
+	case PXENV_TFTP_READ_FILE:
+		pxenv_call.tftp_read_file = pxenv_tftp_read_file;
+		param_len = sizeof ( pxenv_any.tftp_read_file );
+		break;
+	case PXENV_TFTP_GET_FSIZE:
+		pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize;
+		param_len = sizeof ( pxenv_any.tftp_get_fsize );
+		break;
+	case PXENV_UDP_OPEN:
+		pxenv_call.udp_open = pxenv_udp_open;
+		param_len = sizeof ( pxenv_any.udp_open );
+		break;
+	case PXENV_UDP_CLOSE:
+		pxenv_call.udp_close = pxenv_udp_close;
+		param_len = sizeof ( pxenv_any.udp_close );
+		break;
+	case PXENV_UDP_WRITE:
+		pxenv_call.udp_write = pxenv_udp_write;
+		param_len = sizeof ( pxenv_any.udp_write );
+		break;
+	case PXENV_UDP_READ:
+		pxenv_call.udp_read = pxenv_udp_read;
+		param_len = sizeof ( pxenv_any.udp_read );
+		break;
+	case PXENV_UNDI_STARTUP:
+		pxenv_call.undi_startup = pxenv_undi_startup;
+		param_len = sizeof ( pxenv_any.undi_startup );
+		break;
+	case PXENV_UNDI_CLEANUP:
+		pxenv_call.undi_cleanup = pxenv_undi_cleanup;
+		param_len = sizeof ( pxenv_any.undi_cleanup );
+		break;
+	case PXENV_UNDI_INITIALIZE:
+		pxenv_call.undi_initialize = pxenv_undi_initialize;
+		param_len = sizeof ( pxenv_any.undi_initialize );
+		break;
+	case PXENV_UNDI_RESET_ADAPTER:
+		pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter;
+		param_len = sizeof ( pxenv_any.undi_reset_adapter );
+		break;
+	case PXENV_UNDI_SHUTDOWN:
+		pxenv_call.undi_shutdown = pxenv_undi_shutdown;
+		param_len = sizeof ( pxenv_any.undi_shutdown );
+		break;
+	case PXENV_UNDI_OPEN:
+		pxenv_call.undi_open = pxenv_undi_open;
+		param_len = sizeof ( pxenv_any.undi_open );
+		break;
+	case PXENV_UNDI_CLOSE:
+		pxenv_call.undi_close = pxenv_undi_close;
+		param_len = sizeof ( pxenv_any.undi_close );
+		break;
+	case PXENV_UNDI_TRANSMIT:
+		pxenv_call.undi_transmit = pxenv_undi_transmit;
+		param_len = sizeof ( pxenv_any.undi_transmit );
+		break;
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
+		pxenv_call.undi_set_mcast_address =
+			pxenv_undi_set_mcast_address;
+		param_len = sizeof ( pxenv_any.undi_set_mcast_address );
+		break;
+	case PXENV_UNDI_SET_STATION_ADDRESS:
+		pxenv_call.undi_set_station_address =
+			pxenv_undi_set_station_address;
+		param_len = sizeof ( pxenv_any.undi_set_station_address );
+		break;
+	case PXENV_UNDI_SET_PACKET_FILTER:
+		pxenv_call.undi_set_packet_filter =
+			pxenv_undi_set_packet_filter;
+		param_len = sizeof ( pxenv_any.undi_set_packet_filter );
+		break;
+	case PXENV_UNDI_GET_INFORMATION:
+		pxenv_call.undi_get_information = pxenv_undi_get_information;
+		param_len = sizeof ( pxenv_any.undi_get_information );
+		break;
+	case PXENV_UNDI_GET_STATISTICS:
+		pxenv_call.undi_get_statistics = pxenv_undi_get_statistics;
+		param_len = sizeof ( pxenv_any.undi_get_statistics );
+		break;
+	case PXENV_UNDI_CLEAR_STATISTICS:
+		pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics;
+		param_len = sizeof ( pxenv_any.undi_clear_statistics );
+		break;
+	case PXENV_UNDI_INITIATE_DIAGS:
+		pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags;
+		param_len = sizeof ( pxenv_any.undi_initiate_diags );
+		break;
+	case PXENV_UNDI_FORCE_INTERRUPT:
+		pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt;
+		param_len = sizeof ( pxenv_any.undi_force_interrupt );
+		break;
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
+		pxenv_call.undi_get_mcast_address =
+			pxenv_undi_get_mcast_address;
+		param_len = sizeof ( pxenv_any.undi_get_mcast_address );
+		break;
+	case PXENV_UNDI_GET_NIC_TYPE:
+		pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type;
+		param_len = sizeof ( pxenv_any.undi_get_nic_type );
+		break;
+	case PXENV_UNDI_GET_IFACE_INFO:
+		pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info;
+		param_len = sizeof ( pxenv_any.undi_get_iface_info );
+		break;
+	case PXENV_UNDI_ISR:
+		pxenv_call.undi_isr = pxenv_undi_isr;
+		param_len = sizeof ( pxenv_any.undi_isr );
+		break;
+	case PXENV_FILE_OPEN:
+		pxenv_call.file_open = pxenv_file_open;
+		param_len = sizeof ( pxenv_any.file_open );
+		break;
+	case PXENV_FILE_CLOSE:
+		pxenv_call.file_close = pxenv_file_close;
+		param_len = sizeof ( pxenv_any.file_close );
+		break;
+	case PXENV_FILE_SELECT:
+		pxenv_call.file_select = pxenv_file_select;
+		param_len = sizeof ( pxenv_any.file_select );
+		break;
+	case PXENV_FILE_READ:
+		pxenv_call.file_read = pxenv_file_read;
+		param_len = sizeof ( pxenv_any.file_read );
+		break;
+	case PXENV_GET_FILE_SIZE:
+		pxenv_call.get_file_size = pxenv_get_file_size;
+		param_len = sizeof ( pxenv_any.get_file_size );
+		break;
+	case PXENV_FILE_EXEC:
+		pxenv_call.file_exec = pxenv_file_exec;
+		param_len = sizeof ( pxenv_any.file_exec );
+		break;
+	case PXENV_FILE_API_CHECK:
+		pxenv_call.file_api_check = pxenv_file_api_check;
+		param_len = sizeof ( pxenv_any.file_api_check );
+		break;
+	case PXENV_FILE_EXIT_HOOK:
+		pxenv_call.file_exit_hook = pxenv_file_exit_hook;
+		param_len = sizeof ( pxenv_any.file_exit_hook );
+		break;
+	default:
+		DBG ( "PXENV_UNKNOWN_%hx", opcode );
+		pxenv_call.unknown = pxenv_unknown;
+		param_len = sizeof ( pxenv_any.unknown );
+		break;
+	}
+
+	/* Copy parameter block from caller */
+	copy_from_user ( &pxenv_any, parameters, 0, param_len );
+
+	/* Set default status in case child routine fails to do so */
+	pxenv_any.Status = PXENV_STATUS_FAILURE;
+
+	/* Hand off to relevant API routine */
+	DBG ( "[" );
+	ret = pxenv_call.any ( &pxenv_any );
+	if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) {
+		DBG ( " %02x", pxenv_any.Status );
+	}
+	if ( ret != PXENV_EXIT_SUCCESS ) {
+		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
+	}
+	DBG ( "]" );
+	
+	/* Copy modified parameter block back to caller and return */
+	copy_to_user ( parameters, 0, &pxenv_any, param_len );
+	ix86->regs.ax = ret;
+}
+
+/**
+ * Dispatch weak PXE API call with PXE stack available
+ *
+ * @v ix86		Registers for PXE call
+ * @ret present		Zero (PXE stack present)
+ */
+int pxe_api_call_weak ( struct i386_all_regs *ix86 )
+{
+	pxe_api_call ( ix86 );
+	return 0;
+}
+
+/**
+ * Dispatch PXE loader call
+ *
+ * @v es:di		Address of PXE parameter block
+ * @ret ax		PXE exit code
+ */
+__asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) {
+	userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
+	struct s_UNDI_LOADER params;
+	PXENV_EXIT_t ret;
+
+	/* Copy parameter block from caller */
+	copy_from_user ( &params, uparams, 0, sizeof ( params ) );
+
+	/* Fill in ROM segment address */
+	ppxe.UNDIROMID.segment = ix86->segs.ds;
+
+	/* Set default status in case child routine fails to do so */
+	params.Status = PXENV_STATUS_FAILURE;
+
+	/* Call UNDI loader */
+	ret = undi_loader ( &params );
+
+	/* Copy modified parameter block back to caller and return */
+	copy_to_user ( uparams, 0, &params, sizeof ( params ) );
+	ix86->regs.ax = ret;
+}
+
+/**
+ * Calculate byte checksum as used by PXE
+ *
+ * @v data		Data
+ * @v size		Length of data
+ * @ret sum		Checksum
+ */
+static uint8_t pxe_checksum ( void *data, size_t size ) {
+	uint8_t *bytes = data;
+	uint8_t sum = 0;
+
+	while ( size-- ) {
+		sum += *bytes++;
+	}
+	return sum;
+}
+
+/**
+ * Initialise !PXE and PXENV+ structures
+ *
+ */
+static void pxe_init_structures ( void ) {
+	uint32_t rm_cs_phys = ( rm_cs << 4 );
+	uint32_t rm_ds_phys = ( rm_ds << 4 );
+
+	/* Fill in missing segment fields */
+	ppxe.EntryPointSP.segment = rm_cs;
+	ppxe.EntryPointESP.segment = rm_cs;
+	ppxe.Stack.segment_address = rm_ds;
+	ppxe.Stack.Physical_address = rm_ds_phys;
+	ppxe.UNDIData.segment_address = rm_ds;
+	ppxe.UNDIData.Physical_address = rm_ds_phys;
+	ppxe.UNDICode.segment_address = rm_cs;
+	ppxe.UNDICode.Physical_address = rm_cs_phys;
+	ppxe.UNDICodeWrite.segment_address = rm_cs;
+	ppxe.UNDICodeWrite.Physical_address = rm_cs_phys;
+	pxenv.RMEntry.segment = rm_cs;
+	pxenv.StackSeg = rm_ds;
+	pxenv.UNDIDataSeg = rm_ds;
+	pxenv.UNDICodeSeg = rm_cs;
+	pxenv.PXEPtr.segment = rm_cs;
+
+	/* Update checksums */
+	ppxe.StructCksum -= pxe_checksum ( &ppxe, sizeof ( ppxe ) );
+	pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) );
+}
+
+/** PXE structure initialiser */
+struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = pxe_init_structures,
+};
+
+/**
+ * Activate PXE stack
+ *
+ * @v netdev		Net device to use as PXE net device
+ */
+void pxe_activate ( struct net_device *netdev ) {
+
+	/* Ensure INT 1A is hooked */
+	if ( ! int_1a_hooked ) {
+		hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
+				      &pxe_int_1a_vector );
+		devices_get();
+		int_1a_hooked = 1;
+	}
+
+	/* Set PXE network device */
+	pxe_set_netdev ( netdev );
+}
+
+/**
+ * Deactivate PXE stack
+ *
+ * @ret rc		Return status code
+ */
+int pxe_deactivate ( void ) {
+	int rc;
+
+	/* Clear PXE network device */
+	pxe_set_netdev ( NULL );
+
+	/* Ensure INT 1A is unhooked, if possible */
+	if ( int_1a_hooked ) {
+		if ( ( rc = unhook_bios_interrupt ( 0x1a,
+						    (unsigned int) pxe_int_1a,
+						    &pxe_int_1a_vector ))!= 0){
+			DBG ( "Could not unhook INT 1A: %s\n",
+			      strerror ( rc ) );
+			return rc;
+		}
+		devices_put();
+		int_1a_hooked = 0;
+	}
+
+	return 0;
+}
+
+/** Jump buffer for PXENV_RESTART_TFTP */
+rmjmp_buf pxe_restart_nbp;
+
+/**
+ * Start PXE NBP at 0000:7c00
+ *
+ * @ret rc		Return status code
+ */
+int pxe_start_nbp ( void ) {
+	int jmp;
+	int discard_b, discard_c, discard_d, discard_D;
+	uint16_t rc;
+
+	/* Allow restarting NBP via PXENV_RESTART_TFTP */
+	jmp = rmsetjmp ( pxe_restart_nbp );
+	if ( jmp )
+		DBG ( "Restarting NBP (%x)\n", jmp );
+
+	/* Far call to PXE NBP */
+	__asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t"
+					   "pushw %%es\n\t"
+					   "pushw %%di\n\t"
+					   "sti\n\t"
+					   "lcall $0, $0x7c00\n\t"
+					   "addw $4, %%sp\n\t" )
+			       : "=a" ( rc ), "=b" ( discard_b ),
+				 "=c" ( discard_c ), "=d" ( discard_d ),
+				 "=D" ( discard_D )
+			       : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ),
+			         "c" ( rm_cs ),
+			         "d" ( virt_to_phys ( &pxenv ) ),
+				 "D" ( __from_text16 ( &ppxe ) )
+			       : "esi", "ebp", "memory" );
+
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
new file mode 100644
index 0000000..0d3a57c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.arch i386
+
+/****************************************************************************
+ * !PXE structure
+ ****************************************************************************
+ */
+	.section ".text16.data", "aw", @progbits
+	.globl ppxe
+	.align 16
+ppxe:
+	.ascii "!PXE"			/* Signature */
+	.byte pxe_length		/* StructLength */
+	.byte 0				/* StructCksum */
+	.byte 0				/* StructRev */
+	.byte 0				/* reserved_1 */
+	.word undiheader, 0		/* UNDIROMID */
+	.word 0, 0			/* BaseROMID */
+	.word pxe_entry_sp, 0		/* EntryPointSP */
+	.word pxe_entry_esp, 0		/* EntryPointESP */
+	.word -1, -1			/* StatusCallout */
+	.byte 0				/* reserved_2 */
+	.byte SegDescCnt		/* SegDescCnt */
+	.word 0				/* FirstSelector */
+pxe_segments:
+	.word 0, 0, 0, _data16_memsz	/* Stack */
+	.word 0, 0, 0, _data16_memsz	/* UNDIData */
+	.word 0, 0, 0, _text16_memsz	/* UNDICode */
+	.word 0, 0, 0, _text16_memsz	/* UNDICodeWrite */
+	.word 0, 0, 0, 0		/* BC_Data */
+	.word 0, 0, 0, 0		/* BC_Code */
+	.word 0, 0, 0, 0		/* BC_CodeWrite */
+	.equ	SegDescCnt, ( ( . - pxe_segments ) / 8 )
+	.equ	pxe_length, . - ppxe
+	.size	ppxe, . - ppxe
+
+	/* Define undiheader=0 as a weak symbol for non-ROM builds */
+	.section ".weak", "a", @nobits
+	.weak	undiheader
+undiheader:
+
+/****************************************************************************
+ * PXENV+ structure
+ ****************************************************************************
+ */
+	.section ".text16.data", "aw", @progbits
+	.globl pxenv
+	.align 16
+pxenv:
+	.ascii "PXENV+"			/* Signature */
+	.word 0x0201			/* Version */
+	.byte pxenv_length		/* Length */
+	.byte 0				/* Checksum */
+	.word pxenv_entry, 0		/* RMEntry */
+	.long 0				/* PMEntry */
+	.word 0				/* PMSelector */
+	.word 0				/* StackSeg */
+	.word _data16_memsz		/* StackSize */
+	.word 0				/* BC_CodeSeg */
+	.word 0				/* BC_CodeSize */
+	.word 0				/* BC_DataSeg */
+	.word 0				/* BC_DataSize */
+	.word 0				/* UNDIDataSeg */
+	.word _data16_memsz		/* UNDIDataSize */
+	.word 0				/* UNDICodeSeg */
+	.word _text16_memsz		/* UNDICodeSize */
+	.word ppxe, 0			/* PXEPtr */
+	.equ	pxenv_length, . - pxenv
+	.size	pxenv, . - pxenv
+ 
+/****************************************************************************
+ * pxenv_entry (16-bit far call)
+ *
+ * PXE API call PXENV+ entry point
+ *
+ * Parameters:
+ *   %es:di : Far pointer to PXE parameter structure
+ *   %bx : PXE API call
+ * Returns:
+ *   %ax : PXE exit status
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	/* Wyse Streaming Manager server (WLDRM13.BIN) assumes that
+	 * the PXENV+ entry point is at UNDI_CS:0000; apparently,
+	 * somebody at Wyse has difficulty distinguishing between the
+	 * words "may" and "must"...
+	 */
+	.section ".text16.null", "ax", @progbits
+	.code16
+pxenv_null_entry:
+	jmp	pxenv_entry
+
+	.section ".text16", "ax", @progbits
+	.code16
+pxenv_entry:
+	pushl	$pxe_api_call
+	pushw	%cs
+	call	prot_call
+	addl	$4, %esp
+	lret
+	.size	pxenv_entry, . - pxenv_entry
+
+/****************************************************************************
+ * pxe_entry
+ *
+ * PXE API call !PXE entry point
+ *
+ * Parameters:
+ *   stack : Far pointer to PXE parameter structure
+ *   stack : PXE API call
+ * Returns:
+ *   %ax : PXE exit status
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+pxe_entry:
+pxe_entry_sp:
+	/* Preserve original %esp */
+	pushl	%esp
+	/* Zero high word of %esp to allow use of common code */
+	movzwl	%sp, %esp
+	jmp	pxe_entry_common
+pxe_entry_esp:
+	/* Preserve %esp to match behaviour of pxe_entry_sp */
+	pushl	%esp
+pxe_entry_common:
+	/* Save PXENV+ API call registers */
+	pushw	%es
+	pushw	%di
+	pushw	%bx
+	/* Load !PXE parameters from stack into PXENV+ registers */
+	addr32 movw	18(%esp), %bx
+	movw	%bx, %es
+	addr32 movw	16(%esp), %di
+	addr32 movw	14(%esp), %bx
+	/* Make call as for PXENV+ */
+	pushw	%cs
+	call	pxenv_entry
+	/* Restore PXENV+ registers */
+	popw	%bx
+	popw	%di
+	popw	%es
+	/* Restore original %esp and return */
+	popl	%esp
+	lret
+	.size	pxe_entry, . - pxe_entry
+
+/****************************************************************************
+ * pxe_int_1a
+ *
+ * PXE INT 1A handler
+ *
+ * Parameters:
+ *   %ax : 0x5650
+ * Returns:
+ *   %ax : 0x564e
+ *   %es:bx : Far pointer to the PXENV+ structure
+ *   %edx : Physical address of the PXENV+ structure
+ *   CF cleared
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl	pxe_int_1a
+pxe_int_1a:
+	pushfw
+	cmpw	$0x5650, %ax
+	jne	1f
+	/* INT 1A,5650 - PXE installation check */
+	xorl	%edx, %edx
+	movw	%cs, %dx
+	movw	%dx, %es
+	movw	$pxenv, %bx
+	shll	$4, %edx
+	addl	$pxenv, %edx
+	movw	$0x564e, %ax
+	pushw	%bp
+	movw	%sp, %bp
+	andb	$~0x01, 8(%bp)	/* Clear CF on return */
+	popw	%bp
+	popfw
+	iret
+1:	/* INT 1A,other - pass through */
+	popfw
+	ljmp	*%cs:pxe_int_1a_vector
+
+	.section ".text16.data", "aw", @progbits
+	.globl	pxe_int_1a_vector
+pxe_int_1a_vector:	.long 0
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
new file mode 100644
index 0000000..2676256
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
@@ -0,0 +1,306 @@
+/** @file
+ *
+ * PXE FILE API
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/posix_io.h>
+#include <ipxe/features.h>
+#include <pxe.h>
+#include <realmode.h>
+
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ * Portions (C) 2010 Shao Miller <shao.miller at yrdsb.edu.on.ca>.
+ *              [PXE exit hook logic]
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 );
+
+/**
+ * FILE OPEN
+ *
+ * @v file_open				Pointer to a struct s_PXENV_FILE_OPEN
+ * @v s_PXENV_FILE_OPEN::FileName	URL of file to open
+ * @ret #PXENV_EXIT_SUCCESS		File was opened
+ * @ret #PXENV_EXIT_FAILURE		File was not opened
+ * @ret s_PXENV_FILE_OPEN::Status	PXE status code
+ * @ret s_PXENV_FILE_OPEN::FileHandle	Handle of opened file
+ *
+ */
+PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
+	userptr_t filename;
+	size_t filename_len;
+	int fd;
+
+	DBG ( "PXENV_FILE_OPEN" );
+
+	/* Copy name from external program, and open it */
+	filename = real_to_user ( file_open->FileName.segment,
+			      file_open->FileName.offset );
+	filename_len = strlen_user ( filename, 0 );
+	{
+		char uri_string[ filename_len + 1 ];
+
+		copy_from_user ( uri_string, filename, 0,
+				 sizeof ( uri_string ) );
+		DBG ( " %s", uri_string );
+		fd = open ( uri_string );
+	}
+
+	if ( fd < 0 ) {
+		file_open->Status = PXENV_STATUS ( fd );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBG ( " as file %d", fd );
+
+	file_open->FileHandle = fd;
+	file_open->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE CLOSE
+ *
+ * @v file_close			Pointer to a struct s_PXENV_FILE_CLOSE
+ * @v s_PXENV_FILE_CLOSE::FileHandle	File handle
+ * @ret #PXENV_EXIT_SUCCESS		File was closed
+ * @ret #PXENV_EXIT_FAILURE		File was not closed
+ * @ret s_PXENV_FILE_CLOSE::Status	PXE status code
+ *
+ */
+PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
+
+	DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
+
+	close ( file_close->FileHandle );
+	file_close->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE SELECT
+ *
+ * @v file_select			Pointer to a struct s_PXENV_FILE_SELECT
+ * @v s_PXENV_FILE_SELECT::FileHandle	File handle
+ * @ret #PXENV_EXIT_SUCCESS		File has been checked for readiness
+ * @ret #PXENV_EXIT_FAILURE		File has not been checked for readiness
+ * @ret s_PXENV_FILE_SELECT::Status	PXE status code
+ * @ret s_PXENV_FILE_SELECT::Ready	Indication of readiness
+ *
+ */
+PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
+	fd_set fdset;
+	int ready;
+
+	DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle );
+
+	FD_ZERO ( &fdset );
+	FD_SET ( file_select->FileHandle, &fdset );
+	if ( ( ready = select ( &fdset, 0 ) ) < 0 ) {
+		file_select->Status = PXENV_STATUS ( ready );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	file_select->Ready = ( ready ? RDY_READ : 0 );
+	file_select->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE READ
+ *
+ * @v file_read				Pointer to a struct s_PXENV_FILE_READ
+ * @v s_PXENV_FILE_READ::FileHandle	File handle
+ * @v s_PXENV_FILE_READ::BufferSize	Size of data buffer
+ * @v s_PXENV_FILE_READ::Buffer		Data buffer
+ * @ret #PXENV_EXIT_SUCCESS		Data has been read from file
+ * @ret #PXENV_EXIT_FAILURE		Data has not been read from file
+ * @ret s_PXENV_FILE_READ::Status	PXE status code
+ * @ret s_PXENV_FILE_READ::Ready	Indication of readiness
+ * @ret s_PXENV_FILE_READ::BufferSize	Length of data read
+ *
+ */
+PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
+	userptr_t buffer;
+	ssize_t len;
+
+	DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle,
+	      file_read->Buffer.segment, file_read->Buffer.offset,
+	      file_read->BufferSize );
+
+	buffer = real_to_user ( file_read->Buffer.segment,
+				file_read->Buffer.offset );
+	if ( ( len = read_user ( file_read->FileHandle, buffer, 0,
+				file_read->BufferSize ) ) < 0 ) {
+		file_read->Status = PXENV_STATUS ( len );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBG ( " read %04zx", ( ( size_t ) len ) );
+
+	file_read->BufferSize = len;
+	file_read->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * GET FILE SIZE
+ *
+ * @v get_file_size			Pointer to a struct s_PXENV_GET_FILE_SIZE
+ * @v s_PXENV_GET_FILE_SIZE::FileHandle	File handle
+ * @ret #PXENV_EXIT_SUCCESS		File size has been determined
+ * @ret #PXENV_EXIT_FAILURE		File size has not been determined
+ * @ret s_PXENV_GET_FILE_SIZE::Status	PXE status code
+ * @ret s_PXENV_GET_FILE_SIZE::FileSize	Size of file
+ */
+PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
+				   *get_file_size ) {
+	ssize_t filesize;
+
+	DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
+
+	filesize = fsize ( get_file_size->FileHandle );
+	if ( filesize < 0 ) {
+		get_file_size->Status = PXENV_STATUS ( filesize );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBG ( " is %zd", ( ( size_t ) filesize ) );
+
+	get_file_size->FileSize = filesize;
+	get_file_size->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE EXEC
+ *
+ * @v file_exec				Pointer to a struct s_PXENV_FILE_EXEC
+ * @v s_PXENV_FILE_EXEC::Command	Command to execute
+ * @ret #PXENV_EXIT_SUCCESS		Command was executed successfully
+ * @ret #PXENV_EXIT_FAILURE		Command was not executed successfully
+ * @ret s_PXENV_FILE_EXEC::Status	PXE status code
+ *
+ */
+PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
+	userptr_t command;
+	size_t command_len;
+	int rc;
+
+	DBG ( "PXENV_FILE_EXEC" );
+
+	/* Copy name from external program, and exec it */
+	command = real_to_user ( file_exec->Command.segment,
+				 file_exec->Command.offset );
+	command_len = strlen_user ( command, 0 );
+	{
+		char command_string[ command_len + 1 ];
+
+		copy_from_user ( command_string, command, 0,
+				 sizeof ( command_string ) );
+		DBG ( " %s", command_string );
+
+		if ( ( rc = system ( command_string ) ) != 0 ) {
+			file_exec->Status = PXENV_STATUS ( rc );
+			return PXENV_EXIT_FAILURE;
+		}
+	}
+
+	file_exec->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 };
+#define pxe_exit_hook __use_data16 ( pxe_exit_hook )
+
+/**
+ * FILE API CHECK
+ *
+ * @v file_exec				Pointer to a struct s_PXENV_FILE_API_CHECK
+ * @v s_PXENV_FILE_API_CHECK::Magic     Inbound magic number (0x91d447b2)
+ * @ret #PXENV_EXIT_SUCCESS		Command was executed successfully
+ * @ret #PXENV_EXIT_FAILURE		Command was not executed successfully
+ * @ret s_PXENV_FILE_API_CHECK::Status	PXE status code
+ * @ret s_PXENV_FILE_API_CHECK::Magic	Outbound magic number (0xe9c17b20)
+ * @ret s_PXENV_FILE_API_CHECK::Provider "iPXE" (0x45585067)
+ * @ret s_PXENV_FILE_API_CHECK::APIMask API function bitmask
+ * @ret s_PXENV_FILE_API_CHECK::Flags	Reserved
+ *
+ */
+PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
+	DBG ( "PXENV_FILE_API_CHECK" );
+
+	if ( file_api_check->Magic != 0x91d447b2 ) {
+		file_api_check->Status = PXENV_STATUS_BAD_FUNC;
+		return PXENV_EXIT_FAILURE;
+	} else if ( file_api_check->Size <
+		    sizeof(struct s_PXENV_FILE_API_CHECK) ) {
+		file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+		return PXENV_EXIT_FAILURE;
+	} else {
+		file_api_check->Status   = PXENV_STATUS_SUCCESS;
+		file_api_check->Size     = sizeof(struct s_PXENV_FILE_API_CHECK);
+		file_api_check->Magic    = 0xe9c17b20;
+		file_api_check->Provider = 0x45585067; /* "iPXE" */
+		file_api_check->APIMask  = 0x0000007f; /* Functions e0-e6 */
+		/* Check to see if we have a PXE exit hook */
+		if ( pxe_exit_hook.segment | pxe_exit_hook.offset )
+			/* Function e7, also */
+			file_api_check->APIMask |= 0x00000080;
+		file_api_check->Flags    = 0;	       /* None defined */
+		return PXENV_EXIT_SUCCESS;
+	}
+}
+
+/**
+ * FILE EXIT HOOK
+ *
+ * @v file_exit_hook			Pointer to a struct
+ *					s_PXENV_FILE_EXIT_HOOK
+ * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
+ * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
+ * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
+ * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
+ *
+ */
+PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK
+					*file_exit_hook ) {
+	DBG ( "PXENV_FILE_EXIT_HOOK" );
+
+	/* Check to see if we have a PXE exit hook */
+	if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) {
+		/* We'll jump to the specified SEG16:OFF16 during exit */
+		pxe_exit_hook.segment = file_exit_hook->Hook.segment;
+		pxe_exit_hook.offset = file_exit_hook->Hook.offset;
+		file_exit_hook->Status = PXENV_STATUS_SUCCESS;
+		return PXENV_EXIT_SUCCESS;
+	}
+
+	DBG ( " not NBP" );
+	file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
new file mode 100644
index 0000000..63858be
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/init.h>
+#include "pxe.h"
+#include "pxe_call.h"
+
+/** @file
+ *
+ * PXE UNDI loader
+ *
+ */
+
+/* PXENV_UNDI_LOADER
+ *
+ */
+PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) {
+
+	/* Perform one-time initialisation (e.g. heap) */
+	initialise();
+
+	DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]",
+	      undi_loader->UNDI_CS, undi_loader->UNDI_DS );
+
+	/* Fill in UNDI loader structure */
+	undi_loader->PXEptr.segment = rm_cs;
+	undi_loader->PXEptr.offset = __from_text16 ( &ppxe );
+	undi_loader->PXENVptr.segment = rm_cs;
+	undi_loader->PXENVptr.offset = __from_text16 ( &pxenv );
+
+	undi_loader->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
new file mode 100644
index 0000000..9e4853b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
@@ -0,0 +1,332 @@
+/** @file
+ *
+ * PXE Preboot API
+ *
+ */
+
+/* PXE API interface for Etherboot.
+ *
+ * Copyright (C) 2004 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/fakedhcp.h>
+#include <ipxe/device.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/isapnp.h>
+#include <ipxe/init.h>
+#include <ipxe/if_ether.h>
+#include <basemem_packet.h>
+#include <biosint.h>
+#include "pxe.h"
+#include "pxe_call.h"
+
+/* Avoid dragging in isapnp.o unnecessarily */
+uint16_t isapnp_read_port;
+
+/** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */
+enum pxe_cached_info_indices {
+	CACHED_INFO_DHCPDISCOVER = ( PXENV_PACKET_TYPE_DHCP_DISCOVER - 1 ),
+	CACHED_INFO_DHCPACK = ( PXENV_PACKET_TYPE_DHCP_ACK - 1 ),
+	CACHED_INFO_BINL = ( PXENV_PACKET_TYPE_CACHED_REPLY - 1 ),
+	NUM_CACHED_INFOS
+};
+
+/** A cached DHCP packet */
+union pxe_cached_info {
+	struct dhcphdr dhcphdr;
+	/* This buffer must be *exactly* the size of a BOOTPLAYER_t
+	 * structure, otherwise WinPE will die horribly.  It takes the
+	 * size of *our* buffer and feeds it in to us as the size of
+	 * one of *its* buffers.  If our buffer is larger than it
+	 * expects, we therefore end up overwriting part of its data
+	 * segment, since it tells us to do so.  (D'oh!)
+	 *
+	 * Note that a BOOTPLAYER_t is not necessarily large enough to
+	 * hold a DHCP packet; this is a flaw in the PXE spec.
+	 */
+	BOOTPLAYER_t packet;
+} __attribute__ (( packed ));
+
+/** A PXE DHCP packet creator */
+struct pxe_dhcp_packet_creator {
+	/** Create DHCP packet
+	 *
+	 * @v netdev		Network device
+	 * @v data		Buffer for DHCP packet
+	 * @v max_len		Size of DHCP packet buffer
+	 * @ret rc		Return status code
+	 */
+	int ( * create ) ( struct net_device *netdev, void *data,
+			   size_t max_len );
+};
+
+/** PXE DHCP packet creators */
+static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
+	[CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
+	[CACHED_INFO_DHCPACK] = { create_fakedhcpack },
+	[CACHED_INFO_BINL] = { create_fakepxebsack },
+};
+
+/* The case in which the caller doesn't supply a buffer is really
+ * awkward to support given that we have multiple sources of options,
+ * and that we don't actually store the DHCP packets.  (We may not
+ * even have performed DHCP; we may have obtained all configuration
+ * from non-volatile stored options or from the command line.)
+ *
+ * Some NBPs rely on the buffers we provide being persistent, so we
+ * can't just use the temporary packet buffer.  4.5kB of base memory
+ * always wasted just because some clients are too lazy to provide
+ * their own buffers...
+ */
+static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] );
+#define cached_info __use_data16 ( cached_info )
+
+/**
+ * UNLOAD BASE CODE STACK
+ *
+ * @v None				-
+ * @ret ...
+ *
+ */
+PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
+	DBG ( "PXENV_UNLOAD_STACK" );
+
+	unload_stack->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_GET_CACHED_INFO
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
+				     *get_cached_info ) {
+	struct pxe_dhcp_packet_creator *creator;
+	union pxe_cached_info *info;
+	unsigned int idx;
+	size_t len;
+	userptr_t buffer;
+	int rc;
+
+	DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
+
+	DBG ( " to %04x:%04x+%x", get_cached_info->Buffer.segment,
+	      get_cached_info->Buffer.offset, get_cached_info->BufferSize );
+
+	/* Sanity check */
+        idx = ( get_cached_info->PacketType - 1 );
+	if ( idx >= NUM_CACHED_INFOS ) {
+		DBG ( " bad PacketType" );
+		goto err;
+	}
+	info = &cached_info[idx];
+
+	/* Construct cached version of packet, if not already constructed. */
+	if ( ! info->dhcphdr.op ) {
+		/* Construct DHCP packet */
+		creator = &pxe_dhcp_packet_creators[idx];
+		if ( ( rc = creator->create ( pxe_netdev, info,
+					      sizeof ( *info ) ) ) != 0 ) {
+			DBG ( " failed to build packet" );
+			goto err;
+		}
+	}
+
+	len = get_cached_info->BufferSize;
+	if ( len == 0 ) {
+		/* Point client at our cached buffer.
+		 *
+		 * To add to the fun, Intel decided at some point in
+		 * the evolution of the PXE specification to add the
+		 * BufferLimit field, which we are meant to fill in
+		 * with the length of our packet buffer, so that the
+		 * caller can safely modify the boot server reply
+		 * packet stored therein.  However, this field was not
+		 * present in earlier versions of the PXE spec, and
+		 * there is at least one PXE NBP (Altiris) which
+		 * allocates only exactly enough space for this
+		 * earlier, shorter version of the structure.  If we
+		 * actually fill in the BufferLimit field, we
+		 * therefore risk trashing random areas of the
+		 * caller's memory.  If we *don't* fill it in, then
+		 * the caller is at liberty to assume that whatever
+		 * random value happened to be in that location
+		 * represents the length of the buffer we've just
+		 * passed back to it.
+		 *
+		 * Since older PXE stacks won't fill this field in
+		 * anyway, it's probably safe to assume that no
+		 * callers actually rely on it, so we choose to not
+		 * fill it in.
+		 */
+		get_cached_info->Buffer.segment = rm_ds;
+		get_cached_info->Buffer.offset = __from_data16 ( info );
+		get_cached_info->BufferSize = sizeof ( *info );
+		DBG ( " returning %04x:%04x+%04x['%x']",
+		      get_cached_info->Buffer.segment,
+		      get_cached_info->Buffer.offset,
+		      get_cached_info->BufferSize,
+		      get_cached_info->BufferLimit );
+	} else {
+		/* Copy packet to client buffer */
+		if ( len > sizeof ( *info ) )
+			len = sizeof ( *info );
+		if ( len < sizeof ( *info ) )
+			DBG ( " buffer may be too short" );
+		buffer = real_to_user ( get_cached_info->Buffer.segment,
+					get_cached_info->Buffer.offset );
+		copy_to_user ( buffer, 0, info, len );
+		get_cached_info->BufferSize = len;
+	}
+
+	get_cached_info->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+
+ err:
+	get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+	return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_RESTART_TFTP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
+				  *restart_tftp ) {
+	PXENV_EXIT_t tftp_exit;
+
+	DBG ( "PXENV_RESTART_TFTP " );
+
+	/* Words cannot describe the complete mismatch between the PXE
+	 * specification and any possible version of reality...
+	 */
+	restart_tftp->Buffer = PXE_LOAD_PHYS; /* Fixed by spec, apparently */
+	restart_tftp->BufferSize = ( 0xa0000 - PXE_LOAD_PHYS ); /* Near enough */
+	tftp_exit = pxenv_tftp_read_file ( restart_tftp );
+	if ( tftp_exit != PXENV_EXIT_SUCCESS )
+		return tftp_exit;
+
+	/* Restart NBP */
+	rmlongjmp ( pxe_restart_nbp, PXENV_RESTART_TFTP );
+}
+
+/* PXENV_START_UNDI
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
+	unsigned int bus_type;
+	unsigned int location;
+	struct net_device *netdev;
+
+	DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
+	      start_undi->AX, start_undi->BX, start_undi->DX );
+
+	/* Determine bus type and location.  Use a heuristic to decide
+	 * whether we are PCI or ISAPnP
+	 */
+	if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
+	     ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
+	     ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
+	     ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
+		bus_type = BUS_TYPE_ISAPNP;
+		location = start_undi->BX;
+		/* Record ISAPnP read port for use by isapnp.c */
+		isapnp_read_port = start_undi->DX;
+	} else {
+		bus_type = BUS_TYPE_PCI;
+		location = start_undi->AX;
+	}
+
+	/* Probe for devices, etc. */
+	startup();
+
+	/* Look for a matching net device */
+	netdev = find_netdev_by_location ( bus_type, location );
+	if ( ! netdev ) {
+		DBG ( " no net device found" );
+		start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
+		return PXENV_EXIT_FAILURE;
+	}
+	DBG ( " using netdev %s", netdev->name );
+
+	/* Activate PXE */
+	pxe_activate ( netdev );
+
+	start_undi->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_STOP_UNDI
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
+	DBG ( "PXENV_STOP_UNDI" );
+
+	/* Deactivate PXE */
+	pxe_deactivate();
+
+	/* Prepare for unload */
+	shutdown_boot();
+
+	/* Check to see if we still have any hooked interrupts */
+	if ( hooked_bios_interrupts != 0 ) {
+		DBG ( "PXENV_STOP_UNDI failed: %d interrupts still hooked\n",
+		      hooked_bios_interrupts );
+		stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	stop_undi->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_START_BASE
+ *
+ * Status: won't implement (requires major structural changes)
+ */
+PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
+	DBG ( "PXENV_START_BASE" );
+
+	start_base->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_STOP_BASE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
+	DBG ( "PXENV_STOP_BASE" );
+
+	/* The only time we will be called is when the NBP is trying
+	 * to shut down the PXE stack.  There's nothing we need to do
+	 * in this call.
+	 */
+
+	stop_base->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
new file mode 100644
index 0000000..7f0af7a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
@@ -0,0 +1,564 @@
+/** @file
+ *
+ * PXE TFTP API
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/in.h>
+#include <ipxe/tftp.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/process.h>
+#include <pxe.h>
+
+/** A PXE TFTP connection */
+struct pxe_tftp_connection {
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Data buffer */
+	userptr_t buffer;
+	/** Size of data buffer */
+	size_t size;
+	/** Starting offset of data buffer */
+	size_t start;
+	/** File position */
+	size_t offset;
+	/** Maximum file position */
+	size_t max_offset;
+	/** Block size */
+	size_t blksize;
+	/** Block index */
+	unsigned int blkidx;
+	/** Overall return status code */
+	int rc;
+};
+
+/**
+ * Close PXE TFTP connection
+ *
+ * @v pxe_tftp		PXE TFTP connection
+ * @v rc		Final status code
+ */
+static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) {
+	intf_shutdown ( &pxe_tftp->xfer, rc );
+	pxe_tftp->rc = rc;
+}
+
+/**
+ * Receive new data
+ *
+ * @v pxe_tftp		PXE TFTP connection
+ * @v iobuf		I/O buffer
+ * @v meta		Transfer metadata
+ * @ret rc		Return status code
+ */
+static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp,
+				   struct io_buffer *iobuf,
+				   struct xfer_metadata *meta ) {
+	size_t len = iob_len ( iobuf );
+	int rc = 0;
+
+	/* Calculate new buffer position */
+	if ( meta->flags & XFER_FL_ABS_OFFSET )
+		pxe_tftp->offset = 0;
+	pxe_tftp->offset += meta->offset;
+
+	/* Copy data block to buffer */
+	if ( len == 0 ) {
+		/* No data (pure seek); treat as success */
+	} else if ( pxe_tftp->offset < pxe_tftp->start ) {
+		DBG ( " buffer underrun at %zx (min %zx)",
+		      pxe_tftp->offset, pxe_tftp->start );
+		rc = -ENOBUFS;
+	} else if ( ( pxe_tftp->offset + len ) >
+		    ( pxe_tftp->start + pxe_tftp->size ) ) {
+		DBG ( " buffer overrun at %zx (max %zx)",
+		      ( pxe_tftp->offset + len ),
+		      ( pxe_tftp->start + pxe_tftp->size ) );
+		rc = -ENOBUFS;
+	} else {
+		copy_to_user ( pxe_tftp->buffer,
+			       ( pxe_tftp->offset - pxe_tftp->start ),
+			       iobuf->data, len );
+	}
+
+	/* Calculate new buffer position */
+	pxe_tftp->offset += len;
+
+	/* Record maximum offset as the file size */
+	if ( pxe_tftp->max_offset < pxe_tftp->offset )
+		pxe_tftp->max_offset = pxe_tftp->offset;
+
+	/* Terminate transfer on error */
+	if ( rc != 0 )
+		pxe_tftp_close ( pxe_tftp, rc );
+
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** PXE TFTP connection interface operations */
+static struct interface_operation pxe_tftp_xfer_ops[] = {
+	INTF_OP ( xfer_deliver, struct pxe_tftp_connection *,
+		  pxe_tftp_xfer_deliver ),
+	INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ),
+};
+
+/** PXE TFTP connection interface descriptor */
+static struct interface_descriptor pxe_tftp_xfer_desc =
+	INTF_DESC ( struct pxe_tftp_connection, xfer, pxe_tftp_xfer_ops );
+
+/** The PXE TFTP connection */
+static struct pxe_tftp_connection pxe_tftp = {
+	.xfer = INTF_INIT ( pxe_tftp_xfer_desc ),
+};
+
+/**
+ * Maximum length of a PXE TFTP URI
+ *
+ * The PXE TFTP API provides 128 characters for the filename; the
+ * extra 128 bytes allow for the remainder of the URI.
+ */
+#define PXE_TFTP_URI_LEN 256
+
+/**
+ * Open PXE TFTP connection
+ *
+ * @v ipaddress		IP address
+ * @v port		TFTP server port
+ * @v filename		File name
+ * @v blksize		Requested block size
+ * @ret rc		Return status code
+ */
+static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
+			   const unsigned char *filename, size_t blksize,
+			   int sizeonly ) {
+	char uri_string[PXE_TFTP_URI_LEN];
+	struct in_addr address;
+	int rc;
+
+	/* Reset PXE TFTP connection structure */
+	memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
+	intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL );
+	pxe_tftp.rc = -EINPROGRESS;
+
+	/* Construct URI string */
+	address.s_addr = ipaddress;
+	if ( ! port )
+		port = htons ( TFTP_PORT );
+	if ( blksize < TFTP_DEFAULT_BLKSIZE )
+		blksize = TFTP_DEFAULT_BLKSIZE;
+	snprintf ( uri_string, sizeof ( uri_string ),
+		   "tftp%s://%s:%d%s%s?blksize=%zd",
+		   sizeonly ? "size" : "",
+		   inet_ntoa ( address ), ntohs ( port ),
+		   ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
+	DBG ( " %s", uri_string );
+
+	/* Open PXE TFTP connection */
+	if ( ( rc = xfer_open_uri_string ( &pxe_tftp.xfer,
+					   uri_string ) ) != 0 ) {
+		DBG ( " could not open (%s)\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TFTP OPEN
+ *
+ * @v tftp_open				Pointer to a struct s_PXENV_TFTP_OPEN
+ * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address
+ * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0
+ * @v s_PXENV_TFTP_OPEN::FileName	Name of file to open
+ * @v s_PXENV_TFTP_OPEN::TFTPPort	TFTP server UDP port
+ * @v s_PXENV_TFTP_OPEN::PacketSize	TFTP blksize option to request
+ * @ret #PXENV_EXIT_SUCCESS		File was opened
+ * @ret #PXENV_EXIT_FAILURE		File was not opened
+ * @ret s_PXENV_TFTP_OPEN::Status	PXE status code
+ * @ret s_PXENV_TFTP_OPEN::PacketSize	Negotiated blksize
+ * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small
+ *
+ * Opens a TFTP connection for downloading a file a block at a time
+ * using pxenv_tftp_read().
+ *
+ * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place.  See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ * 
+ * @note According to the PXE specification version 2.1, this call
+ * "opens a file for reading/writing", though how writing is to be
+ * achieved without the existence of an API call %pxenv_tftp_write()
+ * is not made clear.
+ *
+ * @note Despite the existence of the numerous statements within the
+ * PXE specification of the form "...if a TFTP/MTFTP or UDP connection
+ * is active...", you cannot use pxenv_tftp_open() and
+ * pxenv_tftp_read() to read a file via MTFTP; only via plain old
+ * TFTP.  If you want to use MTFTP, use pxenv_tftp_read_file()
+ * instead.  Astute readers will note that, since
+ * pxenv_tftp_read_file() is an atomic operation from the point of
+ * view of the PXE API, it is conceptually impossible to issue any
+ * other PXE API call "if an MTFTP connection is active".
+ */
+PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
+	int rc;
+
+	DBG ( "PXENV_TFTP_OPEN" );
+
+	/* Guard against callers that fail to close before re-opening */
+	pxe_tftp_close ( &pxe_tftp, 0 );
+
+	/* Open connection */
+	if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
+				    tftp_open->TFTPPort,
+				    tftp_open->FileName,
+				    tftp_open->PacketSize,
+				    0) ) != 0 ) {
+		tftp_open->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Wait for OACK to arrive so that we have the block size */
+	while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
+		( pxe_tftp.max_offset == 0 ) ) {
+		step();
+	}
+	pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
+	tftp_open->PacketSize = pxe_tftp.blksize;
+	DBG ( " blksize=%d", tftp_open->PacketSize );
+
+	/* EINPROGRESS is normal; we don't wait for the whole transfer */
+	if ( rc == -EINPROGRESS )
+		rc = 0;
+
+	tftp_open->Status = PXENV_STATUS ( rc );
+	return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
+}
+
+/**
+ * TFTP CLOSE
+ *
+ * @v tftp_close			Pointer to a struct s_PXENV_TFTP_CLOSE
+ * @ret #PXENV_EXIT_SUCCESS		File was closed successfully
+ * @ret #PXENV_EXIT_FAILURE		File was not closed
+ * @ret s_PXENV_TFTP_CLOSE::Status	PXE status code
+ * @err None				-
+ *
+ * Close a connection previously opened with pxenv_tftp_open().  You
+ * must have previously opened a connection with pxenv_tftp_open().
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ */
+PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
+	DBG ( "PXENV_TFTP_CLOSE" );
+
+	pxe_tftp_close ( &pxe_tftp, 0 );
+	tftp_close->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * TFTP READ
+ *
+ * @v tftp_read				Pointer to a struct s_PXENV_TFTP_READ
+ * @v s_PXENV_TFTP_READ::Buffer		Address of data buffer
+ * @ret #PXENV_EXIT_SUCCESS		Data was read successfully
+ * @ret #PXENV_EXIT_FAILURE		Data was not read
+ * @ret s_PXENV_TFTP_READ::Status	PXE status code
+ * @ret s_PXENV_TFTP_READ::PacketNumber	TFTP packet number
+ * @ret s_PXENV_TFTP_READ::BufferSize	Length of data written into buffer
+ *
+ * Reads a single packet from a connection previously opened with
+ * pxenv_tftp_open() into the data buffer pointed to by
+ * s_PXENV_TFTP_READ::Buffer.  You must have previously opened a
+ * connection with pxenv_tftp_open().  The data written into
+ * s_PXENV_TFTP_READ::Buffer is just the file data; the various
+ * network headers have already been removed.
+ *
+ * The buffer must be large enough to contain a packet of the size
+ * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the
+ * pxenv_tftp_open() call.  It is worth noting that the PXE
+ * specification does @b not require the caller to fill in
+ * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so
+ * the PXE stack is free to ignore whatever value the caller might
+ * place there and just assume that the buffer is large enough.  That
+ * said, it may be worth the caller always filling in
+ * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that
+ * mistake it for an input parameter.
+ *
+ * The length of the TFTP data packet will be returned via
+ * s_PXENV_TFTP_READ::BufferSize.  If this length is less than the
+ * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to
+ * pxenv_tftp_open(), this indicates that the block is the last block
+ * in the file.  Note that zero is a valid length for
+ * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of
+ * the file is a multiple of the blksize.
+ *
+ * The PXE specification doesn't actually state that calls to
+ * pxenv_tftp_read() will return the data packets in strict sequential
+ * order, though most PXE stacks will probably do so.  The sequence
+ * number of the packet will be returned in
+ * s_PXENV_TFTP_READ::PacketNumber.  The first packet in the file has
+ * a sequence number of one, not zero.
+ *
+ * To guard against flawed PXE stacks, the caller should probably set
+ * s_PXENV_TFTP_READ::PacketNumber to one less than the expected
+ * returned value (i.e. set it to zero for the first call to
+ * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ
+ * parameter block for subsequent calls without modifying
+ * s_PXENV_TFTP_READ::PacketNumber between calls).  The caller should
+ * also guard against potential problems caused by flawed
+ * implementations returning the occasional duplicate packet, by
+ * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber
+ * is as expected (i.e. one greater than that returned from the
+ * previous call to pxenv_tftp_read()).
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ */
+PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
+	int rc;
+
+	DBG ( "PXENV_TFTP_READ to %04x:%04x",
+	      tftp_read->Buffer.segment, tftp_read->Buffer.offset );
+
+	/* Read single block into buffer */
+	pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment,
+					 tftp_read->Buffer.offset );
+	pxe_tftp.size = pxe_tftp.blksize;
+	pxe_tftp.start = pxe_tftp.offset;
+	while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
+		( pxe_tftp.offset == pxe_tftp.start ) )
+		step();
+	pxe_tftp.buffer = UNULL;
+	tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
+	tftp_read->PacketNumber = ++pxe_tftp.blkidx;
+
+	/* EINPROGRESS is normal if we haven't reached EOF yet */
+	if ( rc == -EINPROGRESS )
+		rc = 0;
+
+	tftp_read->Status = PXENV_STATUS ( rc );
+	return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
+}
+
+/**
+ * TFTP/MTFTP read file
+ *
+ * @v tftp_read_file		     Pointer to a struct s_PXENV_TFTP_READ_FILE
+ * @v s_PXENV_TFTP_READ_FILE::FileName		File name
+ * @v s_PXENV_TFTP_READ_FILE::BufferSize 	Size of the receive buffer
+ * @v s_PXENV_TFTP_READ_FILE::Buffer		Address of the receive buffer
+ * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress	TFTP server IP address
+ * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress	Relay agent IP address
+ * @v s_PXENV_TFTP_READ_FILE::McastIPAddress	File's multicast IP address
+ * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort	Client multicast UDP port
+ * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort	Server multicast UDP port
+ * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut	Time to wait for first packet
+ * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay	MTFTP inactivity timeout
+ * @ret #PXENV_EXIT_SUCCESS			File downloaded successfully
+ * @ret #PXENV_EXIT_FAILURE			File not downloaded
+ * @ret s_PXENV_TFTP_READ_FILE::Status		PXE status code
+ * @ret s_PXENV_TFTP_READ_FILE::BufferSize	Length of downloaded file
+ *
+ * Downloads an entire file via either TFTP or MTFTP into the buffer
+ * pointed to by s_PXENV_TFTP_READ_FILE::Buffer.
+ *
+ * The PXE specification does not make it clear how the caller
+ * requests that MTFTP be used rather than TFTP (or vice versa).  One
+ * reasonable guess is that setting
+ * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP
+ * to be used instead of MTFTP, though it is conceivable that some PXE
+ * stacks would interpret that as "use the DHCP-provided multicast IP
+ * address" instead.  Some PXE stacks will not implement MTFTP at all,
+ * and will always use TFTP.
+ *
+ * It is not specified whether or not
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server
+ * port for TFTP (rather than MTFTP) downloads.  Callers should assume
+ * that the only way to access a TFTP server on a non-standard port is
+ * to use pxenv_tftp_open() and pxenv_tftp_read().
+ *
+ * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place.  See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an
+ * #ADDR32_t type, i.e. nominally a flat physical address.  Some PXE
+ * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real
+ * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above
+ * 1MB.  This means that PXE stacks must be prepared to write to areas
+ * outside base memory.  Exactly how this is to be achieved is not
+ * specified, though using INT 15,87 is as close to a standard method
+ * as any, and should probably be used.  Switching to protected-mode
+ * in order to access high memory will fail if pxenv_tftp_read_file()
+ * is called in V86 mode; it is reasonably to expect that a V86
+ * monitor would intercept the relatively well-defined INT 15,87 if it
+ * wants the PXE stack to be able to write to high memory.
+ *
+ * Things get even more interesting if pxenv_tftp_read_file() is
+ * called in protected mode, because there is then absolutely no way
+ * for the PXE stack to write to an absolute physical address.  You
+ * can't even get around the problem by creating a special "access
+ * everything" segment in the s_PXE data structure, because the
+ * #SEGDESC_t descriptors are limited to 64kB in size.
+ *
+ * Previous versions of the PXE specification (e.g. WfM 1.1a) provide
+ * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to
+ * work around this problem.  The s_PXENV_TFTP_READ_FILE_PMODE
+ * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a
+ * protected-mode segment:offset address for the data buffer.  This
+ * API call is no longer present in version 2.1 of the PXE
+ * specification.
+ *
+ * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer
+ * is an offset relative to the caller's data segment, when
+ * pxenv_tftp_read_file() is called in protected mode.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ */
+PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
+				    *tftp_read_file ) {
+	int rc;
+
+	DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
+	      tftp_read_file->BufferSize );
+
+	/* Open TFTP file */
+	if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
+				    tftp_read_file->FileName, 0, 0 ) ) != 0 ) {
+		tftp_read_file->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Read entire file */
+	pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer );
+	pxe_tftp.size = tftp_read_file->BufferSize;
+	while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
+		step();
+	pxe_tftp.buffer = UNULL;
+	tftp_read_file->BufferSize = pxe_tftp.max_offset;
+
+	/* Close TFTP file */
+	pxe_tftp_close ( &pxe_tftp, rc );
+
+	tftp_read_file->Status = PXENV_STATUS ( rc );
+	return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
+}
+
+/**
+ * TFTP GET FILE SIZE
+ *
+ * @v tftp_get_fsize		     Pointer to a struct s_PXENV_TFTP_GET_FSIZE
+ * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress	TFTP server IP address
+ * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress	Relay agent IP address
+ * @v s_PXENV_TFTP_GET_FSIZE::FileName	File name
+ * @ret #PXENV_EXIT_SUCCESS		File size was determined successfully
+ * @ret #PXENV_EXIT_FAILURE		File size was not determined
+ * @ret s_PXENV_TFTP_GET_FSIZE::Status	PXE status code
+ * @ret s_PXENV_TFTP_GET_FSIZE::FileSize	File size
+ *
+ * Determine the size of a file on a TFTP server.  This uses the
+ * "tsize" TFTP option, and so will not work with a TFTP server that
+ * does not support TFTP options, or that does not support the "tsize"
+ * option.
+ *
+ * The PXE specification states that this API call will @b not open a
+ * TFTP connection for subsequent use with pxenv_tftp_read().  (This
+ * is somewhat daft, since the only way to obtain the file size via
+ * the "tsize" option involves issuing a TFTP open request, but that's
+ * life.)
+ *
+ * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP
+ * connection is open.
+ *
+ * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place.  See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ * 
+ * @note There is no way to specify the TFTP server port with this API
+ * call.  Though you can open a file using a non-standard TFTP server
+ * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially,
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of
+ * a file from a TFTP server listening on the standard TFTP port.
+ * "Consistency" is not a word in Intel's vocabulary.
+ */
+PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
+				    *tftp_get_fsize ) {
+	int rc;
+
+	DBG ( "PXENV_TFTP_GET_FSIZE" );
+
+	/* Open TFTP file */
+	if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
+				    tftp_get_fsize->FileName, 0, 1 ) ) != 0 ) {
+		tftp_get_fsize->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Wait for initial seek to arrive, and record size */
+	while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
+		( pxe_tftp.max_offset == 0 ) ) {
+		step();
+	}
+	tftp_get_fsize->FileSize = pxe_tftp.max_offset;
+	DBG ( " fsize=%d", tftp_get_fsize->FileSize );
+
+	/* EINPROGRESS is normal; we don't wait for the whole transfer */
+	if ( rc == -EINPROGRESS )
+		rc = 0;
+
+	/* Close TFTP file */
+	pxe_tftp_close ( &pxe_tftp, rc );
+
+	tftp_get_fsize->Status = PXENV_STATUS ( rc );
+	return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
new file mode 100644
index 0000000..22af4ca
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
@@ -0,0 +1,407 @@
+/** @file
+ *
+ * PXE UDP API
+ *
+ */
+
+#include <string.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/udp.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/process.h>
+#include <pxe.h>
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A PXE UDP connection */
+struct pxe_udp_connection {
+	/** Data transfer interface to UDP stack */
+	struct interface xfer;
+	/** Local address */
+	struct sockaddr_in local;
+	/** Current PXENV_UDP_READ parameter block */
+	struct s_PXENV_UDP_READ *pxenv_udp_read;
+};
+
+/**
+ * Receive PXE UDP data
+ *
+ * @v pxe_udp			PXE UDP connection
+ * @v iobuf			I/O buffer
+ * @v meta			Data transfer metadata
+ * @ret rc			Return status code
+ *
+ * Receives a packet as part of the current pxenv_udp_read()
+ * operation.
+ */
+static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp,
+			     struct io_buffer *iobuf,
+			     struct xfer_metadata *meta ) {
+	struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
+	struct sockaddr_in *sin_src;
+	struct sockaddr_in *sin_dest;
+	userptr_t buffer;
+	size_t len;
+	int rc = 0;
+
+	if ( ! pxenv_udp_read ) {
+		DBG ( "PXE discarded UDP packet\n" );
+		rc = -ENOBUFS;
+		goto done;
+	}
+
+	/* Copy packet to buffer and record length */
+	buffer = real_to_user ( pxenv_udp_read->buffer.segment,
+				pxenv_udp_read->buffer.offset );
+	len = iob_len ( iobuf );
+	if ( len > pxenv_udp_read->buffer_size )
+		len = pxenv_udp_read->buffer_size;
+	copy_to_user ( buffer, 0, iobuf->data, len );
+	pxenv_udp_read->buffer_size = len;
+
+	/* Fill in source/dest information */
+	assert ( meta );
+	sin_src = ( struct sockaddr_in * ) meta->src;
+	assert ( sin_src );
+	assert ( sin_src->sin_family == AF_INET );
+	pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
+	pxenv_udp_read->s_port = sin_src->sin_port;
+	sin_dest = ( struct sockaddr_in * ) meta->dest;
+	assert ( sin_dest );
+	assert ( sin_dest->sin_family == AF_INET );
+	pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
+	pxenv_udp_read->d_port = sin_dest->sin_port;
+
+	/* Mark as received */
+	pxe_udp->pxenv_udp_read = NULL;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** PXE UDP data transfer interface operations */
+static struct interface_operation pxe_udp_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct pxe_udp_connection *, pxe_udp_deliver ),
+};
+
+/** PXE UDP data transfer interface descriptor */
+static struct interface_descriptor pxe_udp_xfer_desc =
+	INTF_DESC ( struct pxe_udp_connection, xfer, pxe_udp_xfer_operations );
+
+/** The PXE UDP connection */
+static struct pxe_udp_connection pxe_udp = {
+	.xfer = INTF_INIT ( pxe_udp_xfer_desc ),
+	.local = {
+		.sin_family = AF_INET,
+	},
+};
+
+/**
+ * UDP OPEN
+ *
+ * @v pxenv_udp_open			Pointer to a struct s_PXENV_UDP_OPEN
+ * @v s_PXENV_UDP_OPEN::src_ip		IP address of this station, or 0.0.0.0
+ * @ret #PXENV_EXIT_SUCCESS		Always
+ * @ret s_PXENV_UDP_OPEN::Status	PXE status code
+ * @err #PXENV_STATUS_UDP_OPEN		UDP connection already open
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES	Could not open connection
+ *
+ * Prepares the PXE stack for communication using pxenv_udp_write()
+ * and pxenv_udp_read().
+ *
+ * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
+ * recorded and used as the local station's IP address for all further
+ * communication, including communication by means other than
+ * pxenv_udp_write() and pxenv_udp_read().  (If
+ * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
+ * will remain unchanged.)
+ *
+ * You can only have one open UDP connection at a time.  This is not a
+ * meaningful restriction, since pxenv_udp_write() and
+ * pxenv_udp_read() allow you to specify arbitrary local and remote
+ * ports and an arbitrary remote address for each packet.  According
+ * to the PXE specifiation, you cannot have a UDP connection open at
+ * the same time as a TFTP connection; this restriction does not apply
+ * to Etherboot.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note The PXE specification does not make it clear whether the IP
+ * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
+ * for this UDP connection, or retained for all future communication.
+ * The latter seems more consistent with typical PXE stack behaviour.
+ *
+ * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
+ * parameter.
+ *
+ */
+PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
+	int rc;
+
+	DBG ( "PXENV_UDP_OPEN" );
+
+	/* Record source IP address */
+	pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
+	DBG ( " %s\n", inet_ntoa ( pxe_udp.local.sin_addr ) );
+
+	/* Open promiscuous UDP connection */
+	intf_restart ( &pxe_udp.xfer, 0 );
+	if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) {
+		DBG ( "PXENV_UDP_OPEN could not open promiscuous socket: %s\n",
+		      strerror ( rc ) );
+		pxenv_udp_open->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * UDP CLOSE
+ *
+ * @v pxenv_udp_close			Pointer to a struct s_PXENV_UDP_CLOSE
+ * @ret #PXENV_EXIT_SUCCESS		Always
+ * @ret s_PXENV_UDP_CLOSE::Status	PXE status code
+ * @err None				-
+ *
+ * Closes a UDP connection opened with pxenv_udp_open().
+ *
+ * You can only have one open UDP connection at a time.  You cannot
+ * have a UDP connection open at the same time as a TFTP connection.
+ * You cannot use pxenv_udp_close() to close a TFTP connection; use
+ * pxenv_tftp_close() instead.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ */
+PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
+	DBG ( "PXENV_UDP_CLOSE\n" );
+
+	/* Close UDP connection */
+	intf_restart ( &pxe_udp.xfer, 0 );
+
+	pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * UDP WRITE
+ *
+ * @v pxenv_udp_write			Pointer to a struct s_PXENV_UDP_WRITE
+ * @v s_PXENV_UDP_WRITE::ip		Destination IP address
+ * @v s_PXENV_UDP_WRITE::gw		Relay agent IP address, or 0.0.0.0
+ * @v s_PXENV_UDP_WRITE::src_port	Source UDP port, or 0
+ * @v s_PXENV_UDP_WRITE::dst_port	Destination UDP port
+ * @v s_PXENV_UDP_WRITE::buffer_size	Length of the UDP payload
+ * @v s_PXENV_UDP_WRITE::buffer		Address of the UDP payload
+ * @ret #PXENV_EXIT_SUCCESS		Packet was transmitted successfully
+ * @ret #PXENV_EXIT_FAILURE		Packet could not be transmitted
+ * @ret s_PXENV_UDP_WRITE::Status	PXE status code
+ * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
+ * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
+ *
+ * Transmits a single UDP packet.  A valid IP and UDP header will be
+ * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
+ * should not contain precomputed IP and UDP headers, nor should it
+ * contain space allocated for these headers.  The first byte of the
+ * buffer will be transmitted as the first byte following the UDP
+ * header.
+ *
+ * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
+ * place.  See the relevant @ref pxe_routing "implementation note" for
+ * more details.
+ *
+ * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
+ *
+ * You must have opened a UDP connection with pxenv_udp_open() before
+ * calling pxenv_udp_write().
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
+ * parameter.
+ *
+ */
+PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
+	struct sockaddr_in dest;
+	struct xfer_metadata meta = {
+		.src = ( struct sockaddr * ) &pxe_udp.local,
+		.dest = ( struct sockaddr * ) &dest,
+		.netdev = pxe_netdev,
+	};
+	size_t len;
+	struct io_buffer *iobuf;
+	userptr_t buffer;
+	int rc;
+
+	DBG ( "PXENV_UDP_WRITE" );
+
+	/* Construct destination socket address */
+	memset ( &dest, 0, sizeof ( dest ) );
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = pxenv_udp_write->ip;
+	dest.sin_port = pxenv_udp_write->dst_port;
+
+	/* Set local (source) port.  PXE spec says source port is 2069
+	 * if not specified.  Really, this ought to be set at UDP open
+	 * time but hey, we didn't design this API.
+	 */
+	pxe_udp.local.sin_port = pxenv_udp_write->src_port;
+	if ( ! pxe_udp.local.sin_port )
+		pxe_udp.local.sin_port = htons ( 2069 );
+
+	/* FIXME: we ignore the gateway specified, since we're
+	 * confident of being able to do our own routing.  We should
+	 * probably allow for multiple gateways.
+	 */
+
+	/* Allocate and fill data buffer */
+	len = pxenv_udp_write->buffer_size;
+	iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
+	if ( ! iobuf ) {
+		DBG ( " out of memory\n" );
+		pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+		return PXENV_EXIT_FAILURE;
+	}
+	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
+				pxenv_udp_write->buffer.offset );
+	copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
+
+	DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
+	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
+	      ntohs ( pxenv_udp_write->src_port ),
+	      inet_ntoa ( dest.sin_addr ),
+	      ntohs ( pxenv_udp_write->dst_port ) );
+	
+	/* Transmit packet */
+	if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
+		DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
+		      strerror ( rc ) );
+		pxenv_udp_write->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * UDP READ
+ *
+ * @v pxenv_udp_read			Pointer to a struct s_PXENV_UDP_READ
+ * @v s_PXENV_UDP_READ::dest_ip		Destination IP address, or 0.0.0.0
+ * @v s_PXENV_UDP_READ::d_port		Destination UDP port, or 0
+ * @v s_PXENV_UDP_READ::buffer_size	Size of the UDP payload buffer
+ * @v s_PXENV_UDP_READ::buffer		Address of the UDP payload buffer
+ * @ret #PXENV_EXIT_SUCCESS		A packet has been received
+ * @ret #PXENV_EXIT_FAILURE		No packet has been received
+ * @ret s_PXENV_UDP_READ::Status	PXE status code
+ * @ret s_PXENV_UDP_READ::src_ip	Source IP address
+ * @ret s_PXENV_UDP_READ::dest_ip	Destination IP address
+ * @ret s_PXENV_UDP_READ::s_port	Source UDP port
+ * @ret s_PXENV_UDP_READ::d_port	Destination UDP port
+ * @ret s_PXENV_UDP_READ::buffer_size	Length of UDP payload
+ * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
+ * @err #PXENV_STATUS_FAILURE		No packet was ready to read
+ *
+ * Receive a single UDP packet.  This is a non-blocking call; if no
+ * packet is ready to read, the call will return instantly with
+ * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
+ *
+ * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
+ * any IP address will be accepted and may be returned to the caller.
+ *
+ * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
+ * port will be accepted and may be returned to the caller.
+ *
+ * You must have opened a UDP connection with pxenv_udp_open() before
+ * calling pxenv_udp_read().
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode.  You cannot
+ * call this function with a 32-bit stack segment.  (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note The PXE specification (version 2.1) does not state that we
+ * should fill in s_PXENV_UDP_READ::dest_ip and
+ * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
+ * expects us to do so, and will fail if we don't.
+ *
+ */
+PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
+	struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
+	struct in_addr dest_ip;
+	uint16_t d_port_wanted = pxenv_udp_read->d_port;
+	uint16_t d_port;
+
+	/* Try receiving a packet */
+	pxe_udp.pxenv_udp_read = pxenv_udp_read;
+	step();
+	if ( pxe_udp.pxenv_udp_read ) {
+		/* No packet received */
+		DBG2 ( "PXENV_UDP_READ\n" );
+		pxe_udp.pxenv_udp_read = NULL;
+		goto no_packet;
+	}
+	dest_ip.s_addr = pxenv_udp_read->dest_ip;
+	d_port = pxenv_udp_read->d_port;
+	DBG ( "PXENV_UDP_READ" );
+
+	/* Filter on destination address and/or port */
+	if ( dest_ip_wanted.s_addr &&
+	     ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
+		DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
+		DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
+		goto no_packet;
+	}
+	if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
+		DBG ( " wrong port %d", htons ( d_port ) );
+		DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
+		goto no_packet;
+	}
+
+	DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
+	      pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
+	      inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
+	DBG ( "%d<-%s:%d\n",  ntohs ( pxenv_udp_read->s_port ),
+	      inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
+	      ntohs ( pxenv_udp_read->d_port ) );
+
+	pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+
+ no_packet:
+	pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
+	return PXENV_EXIT_FAILURE;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
new file mode 100644
index 0000000..3938207
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
@@ -0,0 +1,822 @@
+/** @file
+ *
+ * PXE UNDI API
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <byteswap.h>
+#include <basemem_packet.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/device.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ip.h>
+#include <ipxe/arp.h>
+#include <ipxe/rarp.h>
+#include "pxe.h"
+
+/**
+ * Count of outstanding transmitted packets
+ *
+ * This is incremented each time PXENV_UNDI_TRANSMIT is called, and
+ * decremented each time that PXENV_UNDI_ISR is called with the TX
+ * queue empty, stopping when the count reaches zero.  This allows us
+ * to provide a pessimistic approximation of TX completion events to
+ * the PXE NBP simply by monitoring the netdev's TX queue.
+ */
+static int undi_tx_count = 0;
+
+struct net_device *pxe_netdev = NULL;
+
+/**
+ * Set network device as current PXE network device
+ *
+ * @v netdev		Network device, or NULL
+ */
+void pxe_set_netdev ( struct net_device *netdev ) {
+	if ( pxe_netdev ) {
+		netdev_rx_unfreeze ( pxe_netdev );
+		netdev_put ( pxe_netdev );
+	}
+	pxe_netdev = NULL;
+	if ( netdev )
+		pxe_netdev = netdev_get ( netdev );
+}
+
+/**
+ * Open PXE network device
+ *
+ * @ret rc		Return status code
+ */
+static int pxe_netdev_open ( void ) {
+	int rc;
+
+	if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
+		return rc;
+
+	netdev_rx_freeze ( pxe_netdev );
+	netdev_irq ( pxe_netdev, 1 );
+	return 0;
+}
+
+/**
+ * Close PXE network device
+ *
+ */
+static void pxe_netdev_close ( void ) {
+	netdev_rx_unfreeze ( pxe_netdev );
+	netdev_irq ( pxe_netdev, 0 );
+	netdev_close ( pxe_netdev );
+	undi_tx_count = 0;
+}
+
+/**
+ * Dump multicast address list
+ *
+ * @v mcast		PXE multicast address list
+ */
+static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
+	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	unsigned int i;
+
+	for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
+		DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) );
+	}
+}
+
+/* PXENV_UNDI_STARTUP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
+	DBG ( "PXENV_UNDI_STARTUP\n" );
+
+	undi_startup->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_CLEANUP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
+	DBG ( "PXENV_UNDI_CLEANUP\n" );
+
+	pxe_netdev_close();
+
+	undi_cleanup->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_INITIALIZE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
+				     *undi_initialize ) {
+	DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n",
+	      undi_initialize->ProtocolIni );
+
+	undi_initialize->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_RESET_ADAPTER
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
+					*undi_reset_adapter ) {
+	int rc;
+
+	DBG ( "PXENV_UNDI_RESET_ADAPTER" );
+	pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
+	DBG ( "\n" );
+
+	pxe_netdev_close();
+	if ( ( rc = pxe_netdev_open() ) != 0 ) {
+		DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n",
+		      pxe_netdev->name, strerror ( rc ) );
+		undi_reset_adapter->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SHUTDOWN
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
+				   *undi_shutdown ) {
+	DBG ( "PXENV_UNDI_SHUTDOWN\n" );
+
+	pxe_netdev_close();
+
+	undi_shutdown->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_OPEN
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
+	int rc;
+
+	DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x",
+	      undi_open->OpenFlag, undi_open->PktFilter );
+	pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
+	DBG ( "\n" );
+
+	if ( ( rc = pxe_netdev_open() ) != 0 ) {
+		DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n",
+		      pxe_netdev->name, strerror ( rc ) );
+		undi_open->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	undi_open->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_CLOSE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
+	DBG ( "PXENV_UNDI_CLOSE\n" );
+
+	pxe_netdev_close();
+
+	undi_close->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_TRANSMIT
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
+				   *undi_transmit ) {
+	struct s_PXENV_UNDI_TBD tbd;
+	struct DataBlk *datablk;
+	struct io_buffer *iobuf;
+	struct net_protocol *net_protocol;
+	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	char destaddr[MAX_LL_ADDR_LEN];
+	const void *ll_dest;
+	size_t len;
+	unsigned int i;
+	int rc;
+
+	DBG2 ( "PXENV_UNDI_TRANSMIT" );
+
+	/* Forcibly enable interrupts and freeze receive queue
+	 * processing at this point, to work around callers that never
+	 * call PXENV_UNDI_OPEN before attempting to use the UNDI API.
+	 */
+	netdev_rx_freeze ( pxe_netdev );
+	netdev_irq ( pxe_netdev, 1 );
+
+	/* Identify network-layer protocol */
+	switch ( undi_transmit->Protocol ) {
+	case P_IP:	net_protocol = &ipv4_protocol;	break;
+	case P_ARP:	net_protocol = &arp_protocol;	break;
+	case P_RARP:	net_protocol = &rarp_protocol;	break;
+	case P_UNKNOWN:
+		net_protocol = NULL;
+		break;
+	default:
+		DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
+		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
+		return PXENV_EXIT_FAILURE;
+	}
+	DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
+
+	/* Calculate total packet length */
+	copy_from_real ( &tbd, undi_transmit->TBD.segment,
+			 undi_transmit->TBD.offset, sizeof ( tbd ) );
+	len = tbd.ImmedLength;
+	DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
+	       tbd.ImmedLength );
+	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
+		datablk = &tbd.DataBlock[i];
+		len += datablk->TDDataLen;
+		DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment,
+		       datablk->TDDataPtr.offset, datablk->TDDataLen );
+	}
+
+	/* Allocate and fill I/O buffer */
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + len );
+	if ( ! iobuf ) {
+		DBG2 ( " could not allocate iobuf\n" );
+		undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+		return PXENV_EXIT_FAILURE;
+	}
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+	copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
+			 tbd.Xmit.offset, tbd.ImmedLength );
+	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
+		datablk = &tbd.DataBlock[i];
+		copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
+				 datablk->TDDataPtr.segment,
+				 datablk->TDDataPtr.offset,
+				 datablk->TDDataLen );
+	}
+
+	/* Add link-layer header, if required to do so */
+	if ( net_protocol != NULL ) {
+
+		/* Calculate destination address */
+		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
+			copy_from_real ( destaddr,
+					 undi_transmit->DestAddr.segment,
+					 undi_transmit->DestAddr.offset,
+					 ll_protocol->ll_addr_len );
+			ll_dest = destaddr;
+			DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) );
+		} else {
+			ll_dest = pxe_netdev->ll_broadcast;
+			DBG2 ( " BCAST" );
+		}
+
+		/* Add link-layer header */
+		if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
+						pxe_netdev->ll_addr,
+						net_protocol->net_proto ))!=0){
+			DBG2 ( " could not add link-layer header: %s\n",
+			       strerror ( rc ) );
+			free_iob ( iobuf );
+			undi_transmit->Status = PXENV_STATUS ( rc );
+			return PXENV_EXIT_FAILURE;
+		}
+	}
+
+	/* Flag transmission as in-progress.  Do this before starting
+	 * to transmit the packet, because the ISR may trigger before
+	 * we return from netdev_tx().
+	 */
+	undi_tx_count++;
+
+	/* Transmit packet */
+	DBG2 ( "\n" );
+	if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
+		DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n",
+		       strerror ( rc ) );
+		undi_tx_count--;
+		undi_transmit->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+
+	undi_transmit->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SET_MCAST_ADDRESS
+ *
+ * Status: working (for NICs that support receive-all-multicast)
+ */
+PXENV_EXIT_t
+pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
+			       *undi_set_mcast_address ) {
+	DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
+	pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
+	DBG ( "\n" );
+
+	undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SET_STATION_ADDRESS
+ *
+ * Status: working
+ */
+PXENV_EXIT_t 
+pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
+				 *undi_set_station_address ) {
+	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+
+	DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s",
+	      ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
+
+	/* If adapter is open, the change will have no effect; return
+	 * an error
+	 */
+	if ( netdev_is_open ( pxe_netdev ) ) {
+		DBG ( " failed: netdev is open\n" );
+		undi_set_station_address->Status =
+			PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Update MAC address */
+	memcpy ( pxe_netdev->ll_addr,
+		 &undi_set_station_address->StationAddress,
+		 ll_protocol->ll_addr_len );
+
+	DBG ( "\n" );
+	undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SET_PACKET_FILTER
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t
+pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
+			       *undi_set_packet_filter ) {
+
+	DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
+	      undi_set_packet_filter->filter );
+
+	/* Pretend that we succeeded, otherwise the 3Com DOS UNDI
+	 * driver refuses to load.  (We ignore the filter value in the
+	 * PXENV_UNDI_OPEN call anyway.)
+	 */
+	undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
+
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_INFORMATION
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
+					  *undi_get_information ) {
+	struct device *dev = pxe_netdev->dev;
+	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	size_t ll_addr_len = ll_protocol->ll_addr_len;
+
+	DBG ( "PXENV_UNDI_GET_INFORMATION" );
+
+	undi_get_information->BaseIo = dev->desc.ioaddr;
+	undi_get_information->IntNumber =
+		( netdev_irq_supported ( pxe_netdev ) ? dev->desc.irq : 0 );
+	/* Cheat: assume all cards can cope with this */
+	undi_get_information->MaxTranUnit = ETH_MAX_MTU;
+	undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
+	undi_get_information->HwAddrLen = ll_addr_len;
+	assert ( ll_addr_len <=
+		 sizeof ( undi_get_information->CurrentNodeAddress ) );
+	memcpy ( &undi_get_information->CurrentNodeAddress,
+		 pxe_netdev->ll_addr,
+		 sizeof ( undi_get_information->CurrentNodeAddress ) );
+	ll_protocol->init_addr ( pxe_netdev->hw_addr,
+				 &undi_get_information->PermNodeAddress );
+	undi_get_information->ROMAddress = 0;
+		/* nic.rom_info->rom_segment; */
+	/* We only provide the ability to receive or transmit a single
+	 * packet at a time.  This is a bootloader, not an OS.
+	 */
+	undi_get_information->RxBufCt = 1;
+	undi_get_information->TxBufCt = 1;
+
+	DBG ( " io %04x irq %d mtu %d %s %s\n",
+	      undi_get_information->BaseIo, undi_get_information->IntNumber,
+	      undi_get_information->MaxTranUnit, ll_protocol->name,
+	      ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
+	undi_get_information->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_STATISTICS
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
+					 *undi_get_statistics ) {
+	DBG ( "PXENV_UNDI_GET_STATISTICS" );
+
+	undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
+	undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
+	undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
+	undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
+
+	DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n",
+	      undi_get_statistics->XmtGoodFrames,
+	      undi_get_statistics->RcvGoodFrames,
+	      undi_get_statistics->RcvCRCErrors,
+	      undi_get_statistics->RcvResourceErrors );
+	undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_CLEAR_STATISTICS
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
+					   *undi_clear_statistics ) {
+	DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" );
+
+	memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
+	memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
+
+	undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_INITIATE_DIAGS
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
+					 *undi_initiate_diags ) {
+	DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
+
+	undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_FORCE_INTERRUPT
+ *
+ * Status: won't implement (would require driver API changes for no
+ * perceptible benefit)
+ */
+PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
+					  *undi_force_interrupt ) {
+	DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
+
+	undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_GET_MCAST_ADDRESS
+ *
+ * Status: working
+ */
+PXENV_EXIT_t
+pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
+			       *undi_get_mcast_address ) {
+	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
+	int rc;
+
+	DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) );
+
+	if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
+				      undi_get_mcast_address->MediaAddr ))!=0){
+		DBG ( " failed: %s\n", strerror ( rc ) );
+		undi_get_mcast_address->Status = PXENV_STATUS ( rc );
+		return PXENV_EXIT_FAILURE;
+	}
+	DBG ( "=>%s\n",
+	      ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
+
+	undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_NIC_TYPE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
+				       *undi_get_nic_type ) {
+	struct device *dev = pxe_netdev->dev;
+
+	DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
+
+	memset ( &undi_get_nic_type->info, 0,
+		 sizeof ( undi_get_nic_type->info ) );
+
+	switch ( dev->desc.bus_type ) {
+	case BUS_TYPE_PCI: {
+		struct pci_nic_info *info = &undi_get_nic_type->info.pci;
+
+		undi_get_nic_type->NicType = PCI_NIC;
+		info->Vendor_ID = dev->desc.vendor;
+		info->Dev_ID = dev->desc.device;
+		info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
+		info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
+		info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
+		info->BusDevFunc = dev->desc.location;
+		/* Earlier versions of the PXE specification do not
+		 * have the SubVendor_ID and SubDevice_ID fields.  It
+		 * is possible that some NBPs will not provide space
+		 * for them, and so we must not fill them in.
+		 */
+		DBG ( " PCI %02x:%02x.%x %04x:%04x ('%04x:%04x') %02x%02x%02x "
+		      "rev %02x\n", PCI_BUS ( info->BusDevFunc ),
+		      PCI_SLOT ( info->BusDevFunc ),
+		      PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
+		      info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
+		      info->Base_Class, info->Sub_Class, info->Prog_Intf,
+		      info->Rev );
+		break; }
+	case BUS_TYPE_ISAPNP: {
+		struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
+
+		undi_get_nic_type->NicType = PnP_NIC;
+		info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
+				      dev->desc.device );
+		info->CardSelNum = dev->desc.location;
+		/* Cheat: remaining fields are probably unnecessary,
+		 * and would require adding extra code to isapnp.c.
+		 */
+		DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n",
+		      info->CardSelNum, info->EISA_Dev_ID,
+		      info->Base_Class, info->Sub_Class, info->Prog_Intf );
+		break; }
+	default:
+		DBG ( " failed: unknown bus type\n" );
+		undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_IFACE_INFO
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
+					 *undi_get_iface_info ) {
+	DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
+
+	/* Just hand back some info, doesn't really matter what it is.
+	 * Most PXE stacks seem to take this approach.
+	 */
+	snprintf ( ( char * ) undi_get_iface_info->IfaceType,
+		   sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
+	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
+	undi_get_iface_info->ServiceFlags =
+		( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
+		  SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
+		  SUPPORTED_OPEN_CLOSE );
+	if ( netdev_irq_supported ( pxe_netdev ) )
+		undi_get_iface_info->ServiceFlags |= SUPPORTED_IRQ;
+	memset ( undi_get_iface_info->Reserved, 0,
+		 sizeof(undi_get_iface_info->Reserved) );
+
+	DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType,
+	      undi_get_iface_info->LinkSpeed,
+	      undi_get_iface_info->ServiceFlags );
+	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_STATE
+ *
+ * Status: impossible
+ */
+PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
+				    *undi_get_state ) {
+	DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" );
+
+	undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
+	return PXENV_EXIT_FAILURE;
+};
+
+/* PXENV_UNDI_ISR
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
+	struct io_buffer *iobuf;
+	size_t len;
+	struct ll_protocol *ll_protocol;
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	size_t ll_hlen;
+	struct net_protocol *net_protocol;
+	unsigned int prottype;
+	int rc;
+
+	/* Use coloured debug, since UNDI ISR messages are likely to
+	 * be interspersed amongst other UNDI messages.
+	 */
+	DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
+
+	/* Just in case some idiot actually looks at these fields when
+	 * we weren't meant to fill them in...
+	 */
+	undi_isr->BufferLength = 0;
+	undi_isr->FrameLength = 0;
+	undi_isr->FrameHeaderLength = 0;
+	undi_isr->ProtType = 0;
+	undi_isr->PktType = 0;
+
+	switch ( undi_isr->FuncFlag ) {
+	case PXENV_UNDI_ISR_IN_START :
+		DBGC2 ( &pxenv_undi_isr, " START" );
+
+		/* Call poll().  This should acknowledge the device
+		 * interrupt and queue up any received packet.
+		 */
+		net_poll();
+
+		/* A 100% accurate determination of "OURS" vs "NOT
+		 * OURS" is difficult to achieve without invasive and
+		 * unpleasant changes to the driver model.  We settle
+		 * for always returning "OURS" if interrupts are
+		 * currently enabled.
+		 *
+		 * Returning "NOT OURS" when interrupts are disabled
+		 * allows us to avoid a potential interrupt storm when
+		 * we are on a shared interrupt line; if we were to
+		 * always return "OURS" then the other device's ISR
+		 * may never be called.
+		 */
+		if ( netdev_irq_enabled ( pxe_netdev ) ) {
+			DBGC2 ( &pxenv_undi_isr, " OURS" );
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
+		} else {
+			DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
+		}
+
+		/* Disable interrupts */
+		netdev_irq ( pxe_netdev, 0 );
+
+		break;
+	case PXENV_UNDI_ISR_IN_PROCESS :
+	case PXENV_UNDI_ISR_IN_GET_NEXT :
+		DBGC2 ( &pxenv_undi_isr, " %s",
+			( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
+			  "PROCESS" : "GET_NEXT" ) );
+
+		/* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
+		 * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
+		 * they just sit in a tight polling loop merrily
+		 * violating the PXE spec with repeated calls to
+		 * PXENV_UNDI_ISR_IN_PROCESS.  Force extra polls to
+		 * cope with these out-of-spec clients.
+		 */
+		net_poll();
+
+		/* If we have not yet marked a TX as complete, and the
+		 * netdev TX queue is empty, report the TX completion.
+		 */
+		if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
+			DBGC2 ( &pxenv_undi_isr, " TXC" );
+			undi_tx_count--;
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
+			break;
+		}
+
+		/* Remove first packet from netdev RX queue */
+		iobuf = netdev_rx_dequeue ( pxe_netdev );
+		if ( ! iobuf ) {
+			DBGC2 ( &pxenv_undi_isr, " DONE" );
+			/* No more packets remaining */
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
+			/* Re-enable interrupts */
+			netdev_irq ( pxe_netdev, 1 );
+			break;
+		}
+
+		/* Copy packet to base memory buffer */
+		len = iob_len ( iobuf );
+		DBGC2 ( &pxenv_undi_isr, " RX" );
+		if ( len > sizeof ( basemem_packet ) ) {
+			/* Should never happen */
+			DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
+			len = sizeof ( basemem_packet );
+		}
+		memcpy ( basemem_packet, iobuf->data, len );
+
+		/* Strip link-layer header */
+		ll_protocol = pxe_netdev->ll_protocol;
+		if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
+						&ll_source, &net_proto )) !=0){
+			/* Assume unknown net_proto and no ll_source */
+			net_proto = 0;
+			ll_source = NULL;
+		}
+		ll_hlen = ( len - iob_len ( iobuf ) );
+
+		/* Determine network-layer protocol */
+		switch ( net_proto ) {
+		case htons ( ETH_P_IP ):
+			net_protocol = &ipv4_protocol;
+			prottype = P_IP;
+			break;
+		case htons ( ETH_P_ARP ):
+			net_protocol = &arp_protocol;
+			prottype = P_ARP;
+			break;
+		case htons ( ETH_P_RARP ):
+			net_protocol = &rarp_protocol;
+			prottype = P_RARP;
+			break;
+		default:
+			net_protocol = NULL;
+			prottype = P_UNKNOWN;
+			break;
+		}
+
+		/* Fill in UNDI_ISR structure */
+		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
+		undi_isr->BufferLength = len;
+		undi_isr->FrameLength = len;
+		undi_isr->FrameHeaderLength = ll_hlen;
+		undi_isr->Frame.segment = rm_ds;
+		undi_isr->Frame.offset = __from_data16 ( basemem_packet );
+		undi_isr->ProtType = prottype;
+		if ( memcmp ( ll_dest, pxe_netdev->ll_addr,
+			      ll_protocol->ll_addr_len ) == 0 ) {
+			undi_isr->PktType = P_DIRECTED;
+		} else if ( memcmp ( ll_dest, pxe_netdev->ll_broadcast,
+				     ll_protocol->ll_addr_len ) == 0 ) {
+			undi_isr->PktType = P_BROADCAST;
+		} else {
+			undi_isr->PktType = P_MULTICAST;
+		}
+		DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
+			undi_isr->Frame.segment, undi_isr->Frame.offset,
+			undi_isr->BufferLength, undi_isr->FrameLength,
+			( net_protocol ? net_protocol->name : "RAW" ),
+			undi_isr->FrameHeaderLength );
+
+		/* Free packet */
+		free_iob ( iobuf );
+		break;
+	default :
+		DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
+			undi_isr->FuncFlag );
+
+		/* Should never happen */
+		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
+		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBGC2 ( &pxenv_undi_isr, "\n" );
+	undi_isr->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c
new file mode 100644
index 0000000..e933074
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/dhcp.h>
+#include <pxeparent.h>
+#include <pxe_api.h>
+#include <pxe_types.h>
+#include <pxe.h>
+
+/** @file
+ *
+ * Call interface to parent PXE stack
+ *
+ */
+
+/**
+ * Name PXE API call
+ *
+ * @v function		API call number
+ * @ret name		API call name
+ */
+static inline __attribute__ (( always_inline )) const char *
+pxeparent_function_name ( unsigned int function ) {
+	switch ( function ) {
+	case PXENV_START_UNDI:
+		return "PXENV_START_UNDI";
+	case PXENV_STOP_UNDI:
+		return "PXENV_STOP_UNDI";
+	case PXENV_UNDI_STARTUP:
+		return "PXENV_UNDI_STARTUP";
+	case PXENV_UNDI_CLEANUP:
+		return "PXENV_UNDI_CLEANUP";
+	case PXENV_UNDI_INITIALIZE:
+		return "PXENV_UNDI_INITIALIZE";
+	case PXENV_UNDI_RESET_ADAPTER:
+		return "PXENV_UNDI_RESET_ADAPTER";
+	case PXENV_UNDI_SHUTDOWN:
+		return "PXENV_UNDI_SHUTDOWN";
+	case PXENV_UNDI_OPEN:
+		return "PXENV_UNDI_OPEN";
+	case PXENV_UNDI_CLOSE:
+		return "PXENV_UNDI_CLOSE";
+	case PXENV_UNDI_TRANSMIT:
+		return "PXENV_UNDI_TRANSMIT";
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
+		return "PXENV_UNDI_SET_MCAST_ADDRESS";
+	case PXENV_UNDI_SET_STATION_ADDRESS:
+		return "PXENV_UNDI_SET_STATION_ADDRESS";
+	case PXENV_UNDI_SET_PACKET_FILTER:
+		return "PXENV_UNDI_SET_PACKET_FILTER";
+	case PXENV_UNDI_GET_INFORMATION:
+		return "PXENV_UNDI_GET_INFORMATION";
+	case PXENV_UNDI_GET_STATISTICS:
+		return "PXENV_UNDI_GET_STATISTICS";
+	case PXENV_UNDI_CLEAR_STATISTICS:
+		return "PXENV_UNDI_CLEAR_STATISTICS";
+	case PXENV_UNDI_INITIATE_DIAGS:
+		return "PXENV_UNDI_INITIATE_DIAGS";
+	case PXENV_UNDI_FORCE_INTERRUPT:
+		return "PXENV_UNDI_FORCE_INTERRUPT";
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
+		return "PXENV_UNDI_GET_MCAST_ADDRESS";
+	case PXENV_UNDI_GET_NIC_TYPE:
+		return "PXENV_UNDI_GET_NIC_TYPE";
+	case PXENV_UNDI_GET_IFACE_INFO:
+		return "PXENV_UNDI_GET_IFACE_INFO";
+	/*
+	 * Duplicate case value; this is a bug in the PXE specification.
+	 *
+	 *	case PXENV_UNDI_GET_STATE:
+	 *		return "PXENV_UNDI_GET_STATE";
+	 */
+	case PXENV_UNDI_ISR:
+		return "PXENV_UNDI_ISR";
+	case PXENV_GET_CACHED_INFO:
+		return "PXENV_GET_CACHED_INFO";
+	default:
+		return "UNKNOWN API CALL";
+	}
+}
+
+/**
+ * PXE parent parameter block
+ *
+ * Used as the paramter block for all parent PXE API calls.  Resides in base
+ * memory.
+ */
+static union u_PXENV_ANY __bss16 ( pxeparent_params );
+#define pxeparent_params __use_data16 ( pxeparent_params )
+
+/** PXE parent entry point
+ *
+ * Used as the indirection vector for all parent PXE API calls.  Resides in
+ * base memory.
+ */
+SEGOFF16_t __bss16 ( pxeparent_entry_point );
+#define pxeparent_entry_point __use_data16 ( pxeparent_entry_point )
+
+/**
+ * Issue parent PXE API call
+ *
+ * @v entry		Parent PXE stack entry point
+ * @v function		API call number
+ * @v params		PXE parameter block
+ * @v params_len	Length of PXE parameter block
+ * @ret rc		Return status code
+ */
+int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
+		     void *params, size_t params_len ) {
+	PXENV_EXIT_t exit;
+	int discard_b, discard_D;
+	int rc;
+
+	/* Copy parameter block and entry point */
+	assert ( params_len <= sizeof ( pxeparent_params ) );
+	memcpy ( &pxeparent_params, params, params_len );
+	memcpy ( &pxeparent_entry_point, &entry, sizeof ( entry ) );
+
+	/* Call real-mode entry point.  This calling convention will
+	 * work with both the !PXE and the PXENV+ entry points.
+	 */
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
+					   "pushw %%di\n\t"
+					   "pushw %%bx\n\t"
+					   "lcall *pxeparent_entry_point\n\t"
+					   "addw $6, %%sp\n\t" )
+			       : "=a" ( exit ), "=b" ( discard_b ),
+			         "=D" ( discard_D )
+			       : "b" ( function ),
+			         "D" ( __from_data16 ( &pxeparent_params ) )
+			       : "ecx", "edx", "esi", "ebp" );
+
+	/* Determine return status code based on PXENV_EXIT and
+	 * PXENV_STATUS
+	 */
+	if ( exit == PXENV_EXIT_SUCCESS ) {
+		rc = 0;
+	} else {
+		rc = -pxeparent_params.Status;
+		/* Paranoia; don't return success for the combination
+		 * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS
+		 */
+		if ( rc == 0 )
+			rc = -EIO;
+	}
+
+	/* If anything goes wrong, print as much debug information as
+	 * it's possible to give.
+	 */
+	if ( rc != 0 ) {
+		SEGOFF16_t rm_params = {
+			.segment = rm_ds,
+			.offset = __from_data16 ( &pxeparent_params ),
+		};
+
+		DBG ( "PXEPARENT %s failed: %s\n",
+		       pxeparent_function_name ( function ), strerror ( rc ) );
+		DBG ( "PXEPARENT parameters at %04x:%04x length "
+		       "%#02zx, entry point at %04x:%04x\n",
+		       rm_params.segment, rm_params.offset, params_len,
+		       pxeparent_entry_point.segment,
+		       pxeparent_entry_point.offset );
+		DBG ( "PXEPARENT parameters provided:\n" );
+		DBG_HDA ( rm_params, params, params_len );
+		DBG ( "PXEPARENT parameters returned:\n" );
+		DBG_HDA ( rm_params, &pxeparent_params, params_len );
+	}
+
+	/* Copy parameter block back */
+	memcpy ( params, &pxeparent_params, params_len );
+
+	return rc;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c
new file mode 100644
index 0000000..8fe1572
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/netdevice.h>
+#include <undipreload.h>
+#include <pxeparent.h>
+#include <realmode.h>
+#include <pxe_api.h>
+
+/**
+ * Present cached DHCP packet if it exists
+ */
+void get_cached_dhcpack ( void ) {
+	struct undi_device *undi;
+	struct s_PXENV_GET_CACHED_INFO get_cached_info;
+	int rc;
+
+	/* Use preloaded UNDI device to get at PXE entry point */
+	undi = &preloaded_undi;
+	if ( ! undi->entry.segment ) {
+		DBG ( "PXEDHCP no preloaded UNDI device found\n" );
+		return;
+	}
+
+	/* Check that stack is available to get cached info */
+	if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
+		DBG ( "PXEDHCP stack was unloaded, no cache available\n" );
+		return;
+	}
+
+	/* Obtain cached DHCP packet */
+	memset ( &get_cached_info, 0, sizeof ( get_cached_info ) );
+	get_cached_info.PacketType = PXENV_PACKET_TYPE_DHCP_ACK;
+
+	if ( ( rc = pxeparent_call ( undi->entry, PXENV_GET_CACHED_INFO,
+				     &get_cached_info,
+				     sizeof ( get_cached_info ) ) ) != 0 ) {
+		DBG ( "PXEDHCP GET_CACHED_INFO failed: %s\n", strerror ( rc ) );
+		return;
+	}
+
+	DBG ( "PXEDHCP got cached info at %04x:%04x length %d\n",
+	      get_cached_info.Buffer.segment, get_cached_info.Buffer.offset,
+	      get_cached_info.BufferSize );
+
+	/* Present cached DHCP packet */
+	store_cached_dhcpack ( real_to_user ( get_cached_info.Buffer.segment,
+					      get_cached_info.Buffer.offset ),
+			       get_cached_info.BufferSize );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c
new file mode 100644
index 0000000..47df64c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2008 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file SYSLINUX COM32 helpers
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+#include <comboot.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+
+static com32sys_t __bss16 ( com32_regs );
+#define com32_regs __use_data16 ( com32_regs )
+
+static uint8_t __bss16 ( com32_int_vector );
+#define com32_int_vector __use_data16 ( com32_int_vector )
+
+static uint32_t __bss16 ( com32_farcall_proc );
+#define com32_farcall_proc __use_data16 ( com32_farcall_proc )
+
+uint16_t __bss16 ( com32_saved_sp );
+
+/**
+ * Interrupt call helper
+ */
+void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
+
+	memcpy_user ( virt_to_user( &com32_regs ), 0,
+	              phys_to_user ( inregs_phys ), 0,
+	              sizeof(com32sys_t) );
+
+	com32_int_vector = interrupt;
+
+	__asm__ __volatile__ (
+		REAL_CODE ( /* Save all registers */
+		            "pushal\n\t"
+		            "pushw %%ds\n\t"
+		            "pushw %%es\n\t"
+		            "pushw %%fs\n\t"
+		            "pushw %%gs\n\t"
+		            /* Mask off unsafe flags */
+		            "movl (com32_regs + 40), %%eax\n\t"
+		            "andl $0x200cd7, %%eax\n\t"
+		            "movl %%eax, (com32_regs + 40)\n\t"
+		            /* Load com32_regs into the actual registers */
+		            "movw %%sp, %%ss:(com32_saved_sp)\n\t"
+		            "movw $com32_regs, %%sp\n\t"
+		            "popw %%gs\n\t"
+		            "popw %%fs\n\t"
+		            "popw %%es\n\t"
+		            "popw %%ds\n\t"
+		            "popal\n\t"
+		            "popfl\n\t"
+		            "movw %%ss:(com32_saved_sp), %%sp\n\t"
+		            /* patch INT instruction */
+		            "pushw %%ax\n\t"
+		            "movb %%ss:(com32_int_vector), %%al\n\t"
+		            "movb %%al, %%cs:(com32_intcall_instr + 1)\n\t" 
+		            /* perform a jump to avoid problems with cache
+		             * consistency in self-modifying code on some CPUs (486)
+		             */
+		            "jmp 1f\n"
+		            "1:\n\t"
+		            "popw %%ax\n\t"
+		            "com32_intcall_instr:\n\t"
+		            /* INT instruction to be patched */
+		            "int $0xFF\n\t"
+		            /* Copy regs back to com32_regs */
+		            "movw %%sp, %%ss:(com32_saved_sp)\n\t"
+		            "movw $(com32_regs + 44), %%sp\n\t"
+		            "pushfl\n\t"
+		            "pushal\n\t"
+		            "pushw %%ds\n\t"
+		            "pushw %%es\n\t"
+		            "pushw %%fs\n\t"
+		            "pushw %%gs\n\t"
+		            "movw %%ss:(com32_saved_sp), %%sp\n\t"
+		            /* Restore registers */
+		            "popw %%gs\n\t"
+		            "popw %%fs\n\t"
+		            "popw %%es\n\t"
+		            "popw %%ds\n\t"
+		            "popal\n\t")
+		            : : );
+
+	if ( outregs_phys ) {
+		memcpy_user ( phys_to_user ( outregs_phys ), 0,
+		              virt_to_user( &com32_regs ), 0, 
+		              sizeof(com32sys_t) );
+	}
+}
+
+/**
+ * Farcall helper
+ */
+void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
+
+	memcpy_user ( virt_to_user( &com32_regs ), 0,
+	              phys_to_user ( inregs_phys ), 0,
+	              sizeof(com32sys_t) );
+
+	com32_farcall_proc = proc;
+
+	__asm__ __volatile__ (
+		REAL_CODE ( /* Save all registers */
+		            "pushal\n\t"
+		            "pushw %%ds\n\t"
+		            "pushw %%es\n\t"
+		            "pushw %%fs\n\t"
+		            "pushw %%gs\n\t"
+		            /* Mask off unsafe flags */
+		            "movl (com32_regs + 40), %%eax\n\t"
+		            "andl $0x200cd7, %%eax\n\t"
+		            "movl %%eax, (com32_regs + 40)\n\t"
+		            /* Load com32_regs into the actual registers */
+		            "movw %%sp, %%ss:(com32_saved_sp)\n\t"
+		            "movw $com32_regs, %%sp\n\t"
+		            "popw %%gs\n\t"
+		            "popw %%fs\n\t"
+		            "popw %%es\n\t"
+		            "popw %%ds\n\t"
+		            "popal\n\t"
+		            "popfl\n\t"
+		            "movw %%ss:(com32_saved_sp), %%sp\n\t"
+		            /* Call procedure */
+		            "lcall *%%ss:(com32_farcall_proc)\n\t"
+		            /* Copy regs back to com32_regs */
+		            "movw %%sp, %%ss:(com32_saved_sp)\n\t"
+		            "movw $(com32_regs + 44), %%sp\n\t"
+		            "pushfl\n\t"
+		            "pushal\n\t"
+		            "pushw %%ds\n\t"
+		            "pushw %%es\n\t"
+		            "pushw %%fs\n\t"
+		            "pushw %%gs\n\t"
+		            "movw %%ss:(com32_saved_sp), %%sp\n\t"
+		            /* Restore registers */
+		            "popw %%gs\n\t"
+		            "popw %%fs\n\t"
+		            "popw %%es\n\t"
+		            "popw %%ds\n\t"
+		            "popal\n\t")
+		            : : );
+
+	if ( outregs_phys ) {
+		memcpy_user ( phys_to_user ( outregs_phys ), 0,
+		              virt_to_user( &com32_regs ), 0, 
+		              sizeof(com32sys_t) );
+	}
+}
+
+/**
+ * CDECL farcall helper
+ */
+int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
+	int32_t eax;
+
+	copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
+	com32_farcall_proc = proc;
+
+	__asm__ __volatile__ (
+		REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
+		: "=a" (eax)
+		: 
+		: "ecx", "edx" );
+
+	remove_user_from_rm_stack ( 0, stacksz );
+
+	return eax;
+}
+
+/**
+ * IRQ handler
+ */
+void __asmcall com32_irq ( uint32_t vector ) {
+	uint32_t *ivt_entry = phys_to_virt( vector * 4 );
+
+	__asm__ __volatile__ (
+		REAL_CODE ( "pushfw\n\t"
+			    "pushw %%cs\n\t"
+			    "pushw $com32_irq_return\n\t"
+			    "pushl %0\n\t"
+			    "lret\n"
+			    "com32_irq_return:\n\t" )
+		: /* no outputs */
+		: "r" ( *ivt_entry ) );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S
new file mode 100644
index 0000000..4cd8822
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.arch i386
+	.code32
+
+	/*
+	 * This code is entered after running the following sequence out of
+	 * the interrupt jump buffer:
+	 *
+	 * pushal
+	 * movb $vector, %al
+	 * jmp com32_irq_wrapper
+	 */
+
+	.globl com32_irq_wrapper
+com32_irq_wrapper:
+
+	movzbl %al,%eax
+	pushl %eax
+	movl $com32_irq, %eax
+	call com32_wrapper
+	popl %eax
+	popal
+	iret
+
+	.globl com32_farcall_wrapper
+com32_farcall_wrapper:
+
+	movl $com32_farcall, %eax
+	jmp com32_wrapper
+
+
+	.globl com32_cfarcall_wrapper
+com32_cfarcall_wrapper:
+
+	movl $com32_cfarcall, %eax
+	jmp com32_wrapper
+
+
+	.globl com32_intcall_wrapper
+com32_intcall_wrapper:
+
+	movl $com32_intcall, %eax
+	/*jmp com32_wrapper*/ /* fall through */
+
+com32_wrapper:
+	cli
+
+	/* Switch to internal virtual address space */
+	call _phys_to_virt
+
+	/* Switch to internal IDT (if we have one for debugging) */
+	lidt com32_internal_idtr
+
+	mov %eax, (com32_helper_function)
+
+	/* Save external COM32 stack pointer */
+	movl %esp, (com32_external_esp)
+
+	/* Copy arguments to caller-save registers */
+	movl 12(%esp), %eax
+	movl 8(%esp), %ecx
+	movl 4(%esp), %edx
+
+	/* Switch to internal stack */
+	movl (com32_internal_esp), %esp
+
+	/* Copy arguments to internal stack */
+	pushl %eax
+	pushl %ecx
+	pushl %edx
+
+	call *(com32_helper_function)
+
+	/* Clean up stack */
+	addl $12, %esp
+
+	/* Save internal stack pointer and restore external stack pointer */
+	movl %esp, (com32_internal_esp)
+	movl (com32_external_esp), %esp
+
+	/* Switch to com32 IDT */
+	lidt com32_external_idtr
+
+	/* Switch to external flat physical address space */
+	call _virt_to_phys
+
+	sti
+	ret
+
+
+	.data
+
+/* Internal iPXE virtual address space %esp */
+.globl com32_internal_esp
+.lcomm com32_internal_esp, 4
+
+/* External flat physical address space %esp */
+.globl com32_external_esp
+.lcomm com32_external_esp, 4
+
+/* Function pointer of helper to call */
+.lcomm com32_helper_function, 4
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
new file mode 100644
index 0000000..571ba9e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2008 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file SYSLINUX COMBOOT API
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <realmode.h>
+#include <biosint.h>
+#include <ipxe/console.h>
+#include <stdlib.h>
+#include <comboot.h>
+#include <bzimage.h>
+#include <pxe_call.h>
+#include <setjmp.h>
+#include <string.h>
+#include <ipxe/posix_io.h>
+#include <ipxe/process.h>
+#include <ipxe/serial.h>
+#include <ipxe/init.h>
+#include <ipxe/image.h>
+#include <usr/imgmgmt.h>
+#include "config/console.h"
+#include "config/serial.h"
+
+/** The "SYSLINUX" version string */
+static char __data16_array ( syslinux_version, [] ) = "\r\niPXE " VERSION;
+#define syslinux_version __use_data16 ( syslinux_version )
+
+/** The "SYSLINUX" copyright string */
+static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
+#define syslinux_copyright __use_data16 ( syslinux_copyright )
+
+static char __data16_array ( syslinux_configuration_file, [] ) = "";
+#define syslinux_configuration_file __use_data16 ( syslinux_configuration_file )
+
+/** Feature flags */
+static uint8_t __data16 ( comboot_feature_flags ) = COMBOOT_FEATURE_IDLE_LOOP;
+#define comboot_feature_flags __use_data16 ( comboot_feature_flags )
+
+typedef union {
+	syslinux_pm_regs pm; syslinux_rm_regs rm;
+} syslinux_regs;
+
+/** Initial register values for INT 22h AX=1Ah and 1Bh */
+static syslinux_regs __text16 ( comboot_initial_regs );
+#define comboot_initial_regs __use_text16 ( comboot_initial_regs )
+
+static struct segoff __text16 ( int20_vector );
+#define int20_vector __use_text16 ( int20_vector )
+
+static struct segoff __text16 ( int21_vector );
+#define int21_vector __use_text16 ( int21_vector )
+
+static struct segoff __text16 ( int22_vector );
+#define int22_vector __use_text16 ( int22_vector )
+
+extern void int20_wrapper ( void );
+extern void int21_wrapper ( void );
+extern void int22_wrapper ( void );
+
+/* setjmp/longjmp context buffer used to return after loading an image */
+rmjmp_buf comboot_return;
+
+/* Mode flags set by INT 22h AX=0017h */
+static uint16_t comboot_graphics_mode = 0;
+
+
+/**
+ * Print a string with a particular terminator
+ */
+static void print_user_string ( unsigned int segment, unsigned int offset, char terminator ) {
+	int i = 0;
+	char c;
+	userptr_t str = real_to_user ( segment, offset );
+	for ( ; ; ) {
+		copy_from_user ( &c, str, i, 1 );
+		if ( c == terminator ) break;
+		putchar ( c );
+		i++;
+	}
+}
+
+
+/**
+ * Perform a series of memory copies from a list in low memory
+ */
+static void shuffle ( unsigned int list_segment, unsigned int list_offset, unsigned int count )
+{
+	comboot_shuffle_descriptor shuf[COMBOOT_MAX_SHUFFLE_DESCRIPTORS];
+	unsigned int i;
+
+	/* Copy shuffle descriptor list so it doesn't get overwritten */
+	copy_from_user ( shuf, real_to_user ( list_segment, list_offset ), 0,
+	                 count * sizeof( comboot_shuffle_descriptor ) );
+
+	/* Do the copies */
+	for ( i = 0; i < count; i++ ) {
+		userptr_t src_u = phys_to_user ( shuf[ i ].src );
+		userptr_t dest_u = phys_to_user ( shuf[ i ].dest );
+
+		if ( shuf[ i ].src == 0xFFFFFFFF ) {
+			/* Fill with 0 instead of copying */
+			memset_user ( dest_u, 0, 0, shuf[ i ].len );
+		} else if ( shuf[ i ].dest == 0xFFFFFFFF ) {
+			/* Copy new list of descriptors */
+			count = shuf[ i ].len / sizeof( comboot_shuffle_descriptor );
+			assert ( count <= COMBOOT_MAX_SHUFFLE_DESCRIPTORS );
+			copy_from_user ( shuf, src_u, 0, shuf[ i ].len );
+			i = -1;
+		} else {
+			/* Regular copy */
+			memmove_user ( dest_u, 0, src_u, 0, shuf[ i ].len );
+		}
+	}
+}
+
+
+/**
+ * Set default text mode
+ */
+void comboot_force_text_mode ( void ) {
+	if ( comboot_graphics_mode & COMBOOT_VIDEO_VESA ) {
+		/* Set VGA mode 3 via VESA VBE mode set */
+		__asm__ __volatile__ (
+			REAL_CODE (
+				"mov $0x4F02, %%ax\n\t"
+				"mov $0x03, %%bx\n\t"
+				"int $0x10\n\t"
+			)
+		: : );
+	} else if ( comboot_graphics_mode & COMBOOT_VIDEO_GRAPHICS ) {
+		/* Set VGA mode 3 via standard VGA mode set */
+		__asm__ __volatile__ (
+			REAL_CODE (
+				"mov $0x03, %%ax\n\t"
+				"int $0x10\n\t"
+			)
+		: : );
+	}
+
+	comboot_graphics_mode = 0;
+}
+
+
+/**
+ * Fetch kernel and optional initrd
+ */
+static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
+	char *initrd_file;
+	int rc;
+
+	/* Find initrd= parameter, if any */
+	if ( ( initrd_file = strstr ( cmdline, "initrd=" ) ) != NULL ) {
+		char *initrd_end;
+
+		/* skip "initrd=" */
+		initrd_file += 7;
+
+		/* Find terminating space, if any, and replace with NUL */
+		initrd_end = strchr ( initrd_file, ' ' );
+		if ( initrd_end )
+			*initrd_end = '\0';
+
+		DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file );
+
+		/* Fetch initrd */
+		if ( ( rc = imgdownload_string ( initrd_file, NULL, NULL,
+						 register_and_put_image ))!=0){
+			DBG ( "COMBOOT: could not fetch initrd: %s\n",
+			      strerror ( rc ) );
+			return rc;
+		}
+
+		/* Restore space after initrd name, if applicable */
+		if ( initrd_end )
+			*initrd_end = ' ';
+	}
+
+	DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file );
+
+	/* Allocate and fetch kernel */
+	if ( ( rc = imgdownload_string ( kernel_file, NULL, cmdline,
+					 register_and_replace_image ) ) != 0 ) {
+		DBG ( "COMBOOT: could not fetch kernel: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Terminate program interrupt handler
+ */
+static __asmcall void int20 ( struct i386_all_regs *ix86 __unused ) {
+	rmlongjmp ( comboot_return, COMBOOT_EXIT );
+}
+
+
+/**
+ * DOS-compatible API
+ */
+static __asmcall void int21 ( struct i386_all_regs *ix86 ) {
+	ix86->flags |= CF;
+
+	switch ( ix86->regs.ah ) {
+	case 0x00:
+	case 0x4C: /* Terminate program */
+		rmlongjmp ( comboot_return, COMBOOT_EXIT );
+		break;
+
+	case 0x01: /* Get Key with Echo */
+	case 0x08: /* Get Key without Echo */
+		/* TODO: handle extended characters? */
+		ix86->regs.al = getchar( );
+
+		/* Enter */
+		if ( ix86->regs.al == 0x0A )
+			ix86->regs.al = 0x0D;
+
+		if ( ix86->regs.ah == 0x01 )
+			putchar ( ix86->regs.al );
+
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x02: /* Write Character */
+		putchar ( ix86->regs.dl );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x04: /* Write Character to Serial Port */
+		serial_putc ( ix86->regs.dl );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x09: /* Write DOS String to Console */
+		print_user_string ( ix86->segs.ds, ix86->regs.dx, '$' );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0B: /* Check Keyboard */
+		if ( iskey() )
+			ix86->regs.al = 0xFF;
+		else
+			ix86->regs.al = 0x00;
+
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x30: /* Check DOS Version */
+		/* Bottom halves all 0; top halves spell "SYSLINUX" */
+		ix86->regs.eax = 0x59530000;
+		ix86->regs.ebx = 0x4C530000;
+		ix86->regs.ecx = 0x4E490000;
+		ix86->regs.edx = 0x58550000;
+		ix86->flags &= ~CF;
+		break;
+
+	default:
+		DBG ( "COMBOOT unknown int21 function %02x\n", ix86->regs.ah );
+		break;
+	}
+}
+
+
+/**
+ * Dispatch PXE API call weakly
+ *
+ * @v ix86		Registers for PXE call
+ * @ret present		Zero if the PXE stack is present, nonzero if not
+ *
+ * A successful return only indicates that the PXE stack was available
+ * for dispatching the call; it says nothing about the success of
+ * whatever the call asked for.
+ */
+__weak int pxe_api_call_weak ( struct i386_all_regs *ix86 __unused ) {
+	return -1;
+}
+
+/**
+ * SYSLINUX API
+ */
+static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
+	ix86->flags |= CF;
+
+	switch ( ix86->regs.ax ) {
+	case 0x0001: /* Get Version */
+
+		/* Number of INT 22h API functions available */
+		ix86->regs.ax = 0x001D;
+
+		/* SYSLINUX version number */
+		ix86->regs.ch = 0; /* major */
+		ix86->regs.cl = 0; /* minor */
+
+		/* SYSLINUX derivative ID */
+		ix86->regs.dl = BZI_LOADER_TYPE_IPXE;
+
+		/* SYSLINUX version and copyright strings */
+		ix86->segs.es = rm_ds;
+		ix86->regs.si = ( ( unsigned ) __from_data16 ( syslinux_version ) );
+		ix86->regs.di = ( ( unsigned ) __from_data16 ( syslinux_copyright ) );
+
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0002: /* Write String */
+		print_user_string ( ix86->segs.es, ix86->regs.bx, '\0' );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0003: /* Run command */
+		{
+			userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx );
+			int len = strlen_user ( cmd_u, 0 );
+			char cmd[len + 1];
+			copy_from_user ( cmd, cmd_u, 0, len + 1 );
+			DBG ( "COMBOOT: executing command '%s'\n", cmd );
+			system ( cmd );
+			DBG ( "COMBOOT: exiting after executing command...\n" );
+			rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
+		}
+		break;
+
+	case 0x0004: /* Run default command */
+		/* FIXME: just exit for now */
+		rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
+		break;
+
+	case 0x0005: /* Force text mode */
+		comboot_force_text_mode ( );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0006: /* Open file */
+		{
+			int fd;
+			userptr_t file_u = real_to_user ( ix86->segs.es, ix86->regs.si );
+			int len = strlen_user ( file_u, 0 );
+			char file[len + 1];
+
+			copy_from_user ( file, file_u, 0, len + 1 );
+
+			if ( file[0] == '\0' ) {
+				DBG ( "COMBOOT: attempted open with empty file name\n" );
+				break;
+			}
+
+			DBG ( "COMBOOT: opening file '%s'\n", file );
+
+			fd = open ( file );
+
+			if ( fd < 0 ) {
+				DBG ( "COMBOOT: error opening file %s\n", file );
+				break;
+			}
+
+			/* This relies on the fact that a iPXE POSIX fd will
+			 * always fit in 16 bits.
+			 */
+#if (POSIX_FD_MAX > 65535)
+#error POSIX_FD_MAX too large
+#endif
+			ix86->regs.si = (uint16_t) fd;
+
+			ix86->regs.cx = COMBOOT_FILE_BLOCKSZ;
+			ix86->regs.eax = fsize ( fd );
+			ix86->flags &= ~CF;
+		}
+		break;
+
+	case 0x0007: /* Read file */
+		{
+			int fd = ix86->regs.si;
+			int len = ix86->regs.cx * COMBOOT_FILE_BLOCKSZ;
+			int rc;
+			fd_set fds;
+			userptr_t buf = real_to_user ( ix86->segs.es, ix86->regs.bx );
+
+			/* Wait for data ready to read */
+			FD_ZERO ( &fds );
+			FD_SET ( fd, &fds );
+
+			select ( &fds, 1 );
+
+			rc = read_user ( fd, buf, 0, len );
+			if ( rc < 0 ) {
+				DBG ( "COMBOOT: read failed\n" );
+				ix86->regs.si = 0;
+				break;
+			}
+
+			ix86->regs.ecx = rc;
+			ix86->flags &= ~CF;
+		}
+		break;
+
+	case 0x0008: /* Close file */
+		{
+			int fd = ix86->regs.si;
+			close ( fd );
+			ix86->flags &= ~CF;
+		}
+		break;
+
+	case 0x0009: /* Call PXE Stack */
+		if ( pxe_api_call_weak ( ix86 ) != 0 )
+			ix86->flags |= CF;
+		else
+			ix86->flags &= ~CF;
+		break;
+
+	case 0x000A: /* Get Derivative-Specific Information */
+
+		/* iPXE has its own derivative ID, so there is no defined
+		 * output here; just return AL for now */
+		ix86->regs.al = BZI_LOADER_TYPE_IPXE;
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x000B: /* Get Serial Console Configuration */
+#if defined(CONSOLE_SERIAL) && !defined(COMPRESERVE)
+		ix86->regs.dx = COMCONSOLE;
+		ix86->regs.cx = 115200 / COMSPEED;
+		ix86->regs.bx = 0;
+#else
+		ix86->regs.dx = 0;
+#endif
+
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x000E: /* Get configuration file name */
+		/* FIXME: stub */
+		ix86->segs.es = rm_ds;
+		ix86->regs.bx = ( ( unsigned ) __from_data16 ( syslinux_configuration_file ) );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x000F: /* Get IPAPPEND strings */
+		/* FIXME: stub */
+		ix86->regs.cx = 0;
+		ix86->segs.es = 0;
+		ix86->regs.bx = 0;
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0010: /* Resolve hostname */
+		{
+			userptr_t hostname_u = real_to_user ( ix86->segs.es, ix86->regs.bx );
+			int len = strlen_user ( hostname_u, 0 );
+			char hostname[len];
+			struct in_addr addr;
+
+			copy_from_user ( hostname, hostname_u, 0, len + 1 );
+			
+			/* TODO:
+			 * "If the hostname does not contain a dot (.), the
+			 * local domain name is automatically appended."
+			 */
+
+			comboot_resolv ( hostname, &addr );
+
+			ix86->regs.eax = addr.s_addr;
+			ix86->flags &= ~CF;
+		}
+		break;
+
+	case 0x0011: /* Maximum number of shuffle descriptors */
+		ix86->regs.cx = COMBOOT_MAX_SHUFFLE_DESCRIPTORS;
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0012: /* Cleanup, shuffle and boot */
+		if ( ix86->regs.cx > COMBOOT_MAX_SHUFFLE_DESCRIPTORS )
+			break;
+
+		/* Perform final cleanup */
+		shutdown_boot();
+
+		/* Perform sequence of copies */
+		shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx );
+
+		/* Jump to real-mode entry point */
+		__asm__ __volatile__ (
+			REAL_CODE ( 
+				"pushw %0\n\t"
+				"popw %%ds\n\t"
+				"pushl %1\n\t"
+				"lret\n\t"
+			)
+			:
+			: "r" ( ix86->segs.ds ),
+			  "r" ( ix86->regs.ebp ),
+			  "d" ( ix86->regs.ebx ),
+			  "S" ( ix86->regs.esi ) );
+
+		assert ( 0 ); /* Execution should never reach this point */
+
+		break;
+
+	case 0x0013: /* Idle loop call */
+		step ( );
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0015: /* Get feature flags */
+		ix86->segs.es = rm_ds;
+		ix86->regs.bx = ( ( unsigned ) __from_data16 ( &comboot_feature_flags ) );
+		ix86->regs.cx = 1; /* Number of feature flag bytes */
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0016: /* Run kernel image */
+		{
+			userptr_t file_u = real_to_user ( ix86->segs.ds, ix86->regs.si );
+			userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx );
+			int file_len = strlen_user ( file_u, 0 );
+			int cmd_len = strlen_user ( cmd_u, 0 );
+			char file[file_len + 1];
+			char cmd[cmd_len + 1];
+
+			copy_from_user ( file, file_u, 0, file_len + 1 );
+			copy_from_user ( cmd, cmd_u, 0, cmd_len + 1 );
+
+			DBG ( "COMBOOT: run kernel %s %s\n", file, cmd );
+			comboot_fetch_kernel ( file, cmd );
+			/* Technically, we should return if we
+			 * couldn't load the kernel, but it's not safe
+			 * to do that since we have just overwritten
+			 * part of the COMBOOT program's memory space.
+			 */
+			DBG ( "COMBOOT: exiting to run kernel...\n" );
+			rmlongjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL );
+		}
+		break;
+
+	case 0x0017: /* Report video mode change */
+		comboot_graphics_mode = ix86->regs.bx;
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x0018: /* Query custom font */
+		/* FIXME: stub */
+		ix86->regs.al = 0;
+		ix86->segs.es = 0;
+		ix86->regs.bx = 0;
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x001B: /* Cleanup, shuffle and boot to real mode */
+		if ( ix86->regs.cx > COMBOOT_MAX_SHUFFLE_DESCRIPTORS )
+			break;
+
+		/* Perform final cleanup */
+		shutdown_boot();
+
+		/* Perform sequence of copies */
+		shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx );
+
+		/* Copy initial register values to .text16 */
+		memcpy_user ( real_to_user ( rm_cs, (unsigned) __from_text16 ( &comboot_initial_regs ) ), 0,
+		              real_to_user ( ix86->segs.ds, ix86->regs.si ), 0,
+		              sizeof(syslinux_rm_regs) );
+
+		/* Load initial register values */
+		__asm__ __volatile__ (
+			REAL_CODE (
+				/* Point SS:SP at the register value structure */
+				"pushw %%cs\n\t"
+				"popw %%ss\n\t"
+				"movw $comboot_initial_regs, %%sp\n\t"
+
+				/* Segment registers */
+				"popw %%es\n\t"
+				"popw %%ax\n\t" /* Skip CS */
+				"popw %%ds\n\t"
+				"popw %%ax\n\t" /* Skip SS for now */
+				"popw %%fs\n\t"
+				"popw %%gs\n\t"
+
+				/* GP registers */
+				"popl %%eax\n\t"
+				"popl %%ecx\n\t"
+				"popl %%edx\n\t"
+				"popl %%ebx\n\t"
+				"popl %%ebp\n\t" /* Skip ESP for now */
+				"popl %%ebp\n\t"
+				"popl %%esi\n\t"
+				"popl %%edi\n\t"
+
+				/* Load correct SS:ESP */
+				"movw $(comboot_initial_regs + 6), %%sp\n\t"
+				"popw %%ss\n\t"
+				"movl %%cs:(comboot_initial_regs + 28), %%esp\n\t"
+
+				"ljmp *%%cs:(comboot_initial_regs + 44)\n\t"
+			)
+			: : );
+
+		break;
+
+	case 0x001C: /* Get pointer to auxilliary data vector */
+		/* FIXME: stub */
+		ix86->regs.cx = 0; /* Size of the ADV */
+		ix86->flags &= ~CF;
+		break;
+
+	case 0x001D: /* Write auxilliary data vector */
+		/* FIXME: stub */
+		ix86->flags &= ~CF;
+		break;
+
+	default:
+		DBG ( "COMBOOT unknown int22 function %04x\n", ix86->regs.ax );
+		break;
+	}
+}
+
+/**
+ * Hook BIOS interrupts related to COMBOOT API (INT 20h, 21h, 22h)
+ */
+void hook_comboot_interrupts ( ) {
+
+	__asm__ __volatile__ (
+		TEXT16_CODE ( "\nint20_wrapper:\n\t"
+		              "pushl %0\n\t"
+		              "pushw %%cs\n\t"
+		              "call prot_call\n\t"
+		              "addw $4, %%sp\n\t"
+			      "call patch_cf\n\t"
+		              "iret\n\t" )
+		          : : "i" ( int20 ) );
+
+	hook_bios_interrupt ( 0x20, ( unsigned int ) int20_wrapper,
+		                      &int20_vector );
+
+	__asm__ __volatile__ (
+		TEXT16_CODE ( "\nint21_wrapper:\n\t"
+		              "pushl %0\n\t"
+		              "pushw %%cs\n\t"
+		              "call prot_call\n\t"
+		              "addw $4, %%sp\n\t"
+			      "call patch_cf\n\t"
+		              "iret\n\t" )
+		          : : "i" ( int21 ) );
+
+	hook_bios_interrupt ( 0x21, ( unsigned int ) int21_wrapper,
+	                      &int21_vector );
+
+	__asm__  __volatile__ (
+		TEXT16_CODE ( "\nint22_wrapper:\n\t"
+		              "pushl %0\n\t"
+		              "pushw %%cs\n\t"
+		              "call prot_call\n\t"
+		              "addw $4, %%sp\n\t"
+			      "call patch_cf\n\t"
+		              "iret\n\t" )
+		          : : "i" ( int22) );
+
+	hook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper,
+	                      &int22_vector );
+}
+
+/**
+ * Unhook BIOS interrupts related to COMBOOT API (INT 20h, 21h, 22h)
+ */
+void unhook_comboot_interrupts ( ) {
+
+	unhook_bios_interrupt ( 0x20, ( unsigned int ) int20_wrapper,
+				&int20_vector );
+
+	unhook_bios_interrupt ( 0x21, ( unsigned int ) int21_wrapper,
+				&int21_vector );
+
+	unhook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper,
+				&int22_vector );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_resolv.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_resolv.c
new file mode 100644
index 0000000..03bbfd0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/interface/syslinux/comboot_resolv.c
@@ -0,0 +1,61 @@
+#include <errno.h>
+#include <comboot.h>
+#include <ipxe/in.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+#include <ipxe/resolv.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct comboot_resolver {
+	struct interface intf;
+	int rc;
+	struct in_addr addr;
+};
+
+static void comboot_resolv_close ( struct comboot_resolver *comboot_resolver,
+				   int rc ) {
+	comboot_resolver->rc = rc;
+	intf_shutdown ( &comboot_resolver->intf, rc );
+}
+
+static void comboot_resolv_done ( struct comboot_resolver *comboot_resolver,
+				  struct sockaddr *sa ) {
+	struct sockaddr_in *sin;
+
+	if ( sa->sa_family == AF_INET ) {
+		sin = ( ( struct sockaddr_in * ) sa );
+		comboot_resolver->addr = sin->sin_addr;
+	}
+}
+
+static struct interface_operation comboot_resolv_op[] = {
+	INTF_OP ( intf_close, struct comboot_resolver *, comboot_resolv_close ),
+	INTF_OP ( resolv_done, struct comboot_resolver *, comboot_resolv_done ),
+};
+
+static struct interface_descriptor comboot_resolv_desc =
+	INTF_DESC ( struct comboot_resolver, intf, comboot_resolv_op );
+
+static struct comboot_resolver comboot_resolver = {
+	.intf = INTF_INIT ( comboot_resolv_desc ),
+};
+
+int comboot_resolv ( const char *name, struct in_addr *address ) {
+	int rc;
+
+	comboot_resolver.rc = -EINPROGRESS;
+	comboot_resolver.addr.s_addr = 0;
+
+	if ( ( rc = resolv ( &comboot_resolver.intf, name, NULL ) ) != 0 )
+		return rc;
+
+	while ( comboot_resolver.rc == -EINPROGRESS )
+		step();
+
+	if ( ! comboot_resolver.addr.s_addr )
+		return -EAFNOSUPPORT;
+
+	*address = comboot_resolver.addr;
+	return comboot_resolver.rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/kir-Makefile b/qemu-0.15.x/roms/ipxe/src/arch/i386/kir-Makefile
new file mode 100644
index 0000000..bbfc1a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/kir-Makefile
@@ -0,0 +1,26 @@
+# Makefile to build a KEEP_IT_REAL flavour
+# 
+# KEEP_IT_REAL, by its nature, requires a different build of every
+# single object file, since the inclusion of ".code16gcc" will
+# generate different machine code from the assembly.  Unlike the other
+# config options, there is no way that this global dependency can ever
+# be reduced, so it makes sense to be able to build both the normal
+# and the KIR versions without having to force a full rebuild each
+# time.
+
+# Add this Makefile to MAKEDEPS
+#
+MAKEDEPS	+= arch/i386/kir-Makefile
+
+# Place binaries in bin-kir
+#
+BIN		= bin-kir
+
+# Compile with -DKEEP_IT_REAL, forcibly include kir.h at the start of
+# each file to drag in ".code16gcc"
+#
+CFLAGS		+= -DKEEP_IT_REAL -include kir.h
+
+include Makefile
+
+LDSCRIPT	= arch/i386/scripts/i386-kir.lds
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/bootpart.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/bootpart.S
new file mode 100644
index 0000000..968da1a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/bootpart.S
@@ -0,0 +1,218 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define BOOT_SEG	0x07c0
+#define EXEC_SEG	0x0100
+#define STACK_SEG 	0x0200
+#define STACK_SIZE	0x2000
+	
+	.text
+	.arch i386
+	.section ".prefix", "awx", @progbits
+	.code16
+
+/*
+ * Find active partition
+ *
+ * Parameters:
+ *   %dl	: BIOS drive number
+ *   %bp	: Active partition handler routine
+ */
+find_active_partition:
+	/* Set up stack at STACK_SEG:STACK_SIZE */
+	movw	$STACK_SEG, %ax
+	movw	%ax, %ss
+	movw	$STACK_SIZE, %sp
+
+	/* Relocate self to EXEC_SEG */
+	pushw	$BOOT_SEG
+	popw	%ds
+	pushw	$EXEC_SEG
+	popw	%es
+	xorw	%si, %si
+	xorw	%di, %di
+	movw	$0x200, %cx
+	rep movsb
+	ljmp	$EXEC_SEG, $1f
+1:	pushw	%ds
+	popw	%es
+	pushw	%cs
+	popw	%ds
+
+	/* Check for LBA extensions */
+	movb	$0x41, %ah
+	movw	$0x55aa, %bx
+	stc
+	int	$0x13
+	jc	1f
+	cmpw	$0xaa55, %bx
+	jne	1f
+	movw	$read_lba, read_sectors
+1:	
+	/* Read and process root partition table */
+	xorb	%dh, %dh
+	movw	$0x0001, %cx
+	xorl	%esi, %esi
+	xorl	%edi, %edi
+	call	process_table
+
+	/* Print failure message */
+	movw	$10f, %si
+	jmp	boot_error
+10:	.asciz	"Could not locate active partition\r\n"
+
+/*
+ * Print failure message and boot next device
+ *
+ * Parameters:
+ *   %si	: Failure string
+ */
+boot_error:
+	cld
+	movw	$0x0007, %bx
+	movb	$0x0e, %ah
+1:	lodsb
+	testb	%al, %al
+	je	99f
+	int	$0x10
+	jmp	1b
+99:	/* Boot next device */
+	int	$0x18
+
+/*
+ * Process partition table
+ *
+ * Parameters:
+ *   %dl	: BIOS drive number
+ *   %dh	: Head
+ *   %cl	: Sector (bits 0-5), high two bits of cylinder (bits 6-7)
+ *   %ch	: Low eight bits of cylinder
+ *   %esi:%edi	: LBA address
+ *   %bp	: Active partition handler routine
+ *
+ * Returns:
+ *   CF set on error
+ */
+process_table:
+	pushal
+	call	read_boot_sector
+	jc	99f
+	movw	$446, %bx
+1:	call	process_partition
+	addw	$16, %bx
+	cmpw	$510, %bx
+	jne	1b
+99:	popal
+	ret
+
+/*
+ * Process partition
+ *
+ * Parameters:
+ *   %dl	: BIOS drive number
+ *   %dh	: Head
+ *   %cl	: Sector (bits 0-5), high two bits of cylinder (bits 6-7)
+ *   %ch	: Low eight bits of cylinder
+ *   %esi:%edi	: LBA address
+ *   %bx	: Offset within partition table
+ *   %bp	: Active partition handler routine
+ */
+process_partition:
+	pushal
+	/* Load C/H/S values from partition entry */
+	movb	%es:1(%bx), %dh
+	movw	%es:2(%bx), %cx
+	/* Update LBA address from partition entry */
+	addl	%es:8(%bx), %edi
+	adcl	$0, %esi
+	/* Check active flag */
+	testb	$0x80, %es:(%bx)
+	jz	1f
+	call	read_boot_sector
+	jc	99f
+	jmp	*%bp
+1:	/* Check for extended partition */
+	movb	%es:4(%bx), %al
+	cmpb	$0x05, %al
+	je	2f
+	cmpb	$0x0f, %al
+	je	2f
+	cmpb	$0x85, %al
+	jne	99f
+2:	call	process_table
+99:	popal
+	/* Reload original partition table */
+	call	read_boot_sector
+	ret
+
+/*
+ * Read single sector to %es:0000 and verify 0x55aa signature
+ *
+ * Parameters:
+ *   %dl	: BIOS drive number
+ *   %dh	: Head
+ *   %cl	: Sector (bits 0-5), high two bits of cylinder (bits 6-7)
+ *   %ch	: Low eight bits of cylinder
+ *   %esi:%edi	: LBA address
+ *
+ * Returns:
+ *   CF set on error
+ */
+read_boot_sector:
+	pushw	%ax
+	movw	$1, %ax
+	call	*read_sectors
+	jc	99f
+	cmpw	$0xaa55, %es:(510)
+	je	99f
+	stc	
+99:	popw	%ax
+	ret
+	
+/*
+ * Read sectors to %es:0000
+ *
+ * Parameters:
+ *   %dl	: BIOS drive number
+ *   %dh	: Head
+ *   %cl	: Sector (bits 0-5), high two bits of cylinder (bits 6-7)
+ *   %ch	: Low eight bits of cylinder
+ *   %esi:%edi	: LBA address
+ *   %ax	: Number of sectors (max 127)
+ *
+ * Returns:
+ *   CF set on error
+ */
+read_sectors:	.word	read_chs
+
+read_chs:
+	/* Read sectors using C/H/S address */
+	pushal
+	xorw	%bx, %bx
+	movb	$0x02, %ah
+	stc
+	int	$0x13
+	sti
+	popal
+	ret
+
+read_lba:
+	/* Read sectors using LBA address */
+	pushal
+	movw	%ax, (lba_desc + 2)
+	pushw	%es
+	popw	(lba_desc + 6)
+	movl	%edi, (lba_desc + 8)
+	movl	%esi, (lba_desc + 12)
+	movw	$lba_desc, %si
+	movb	$0x42, %ah
+	int	$0x13
+	popal
+	ret
+
+lba_desc:
+	.byte	0x10
+	.byte	0
+	.word	1
+	.word	0x0000
+	.word	0x0000
+	.long	0, 0
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/dskprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/dskprefix.S
new file mode 100644
index 0000000..7aa017c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/dskprefix.S
@@ -0,0 +1,383 @@
+/* NOTE: this boot sector contains instructions that need at least an 80186.
+ * Yes, as86 has a bug somewhere in the valid instruction set checks.
+ *
+ */
+
+/*	floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
+ *	modified by Drew Eckhardt
+ *	modified by Bruce Evans (bde)
+ *
+ * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
+ *
+ * It then loads the system at SYSSEG<<4, using BIOS interrupts.
+ *
+ * The loader has been made as simple as possible, and continuous read errors
+ * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
+ * getting whole tracks at a time whenever possible.
+ */
+
+FILE_LICENCE ( GPL2_ONLY )
+
+.equ	BOOTSEG, 0x07C0			/* original address of boot-sector */
+
+.equ	SYSSEG, 0x1000			/* system loaded at SYSSEG<<4 */
+
+	.org	0
+	.arch i386
+	.text
+	.section ".prefix", "ax", @progbits
+	.code16
+	.globl	_dsk_start
+_dsk_start:
+
+	jmp	$BOOTSEG, $go		/* reload cs:ip to match relocation addr */
+go: 
+	movw	$0x2000-12, %di		/* 0x2000 is arbitrary value >= length */
+					/* of bootsect + room for stack + 12 for */
+					/* saved disk parm block */
+
+	movw	$BOOTSEG, %ax
+	movw	%ax,%ds
+	movw	%ax,%es
+	movw	%ax,%ss			/* put stack at BOOTSEG:0x4000-12. */
+	movw	%di,%sp
+
+/* Many BIOS's default disk parameter tables will not recognize multi-sector
+ * reads beyond the maximum sector number specified in the default diskette
+ * parameter tables - this may mean 7 sectors in some cases.
+ *
+ * Since single sector reads are slow and out of the question, we must take care
+ * of this by creating new parameter tables (for the first disk) in RAM.  We
+ * will set the maximum sector count to 36 - the most we will encounter on an
+ * ED 2.88.  High doesn't hurt.	Low does.
+ *
+ * Segments are as follows: ds=es=ss=cs - BOOTSEG
+ */
+
+	xorw	%cx,%cx
+	movw	%cx,%es			/* access segment 0 */
+	movw	$0x78, %bx		/* 0:bx is parameter table address */
+	pushw	%ds			/* save ds */
+/* 0:bx is parameter table address */
+	ldsw	%es:(%bx),%si		/* loads ds and si */
+
+	movw	%ax,%es			/* ax is BOOTSECT (loaded above) */
+	movb	$6, %cl			/* copy 12 bytes */
+	cld
+	pushw	%di			/* keep a copy for later */
+	rep
+	movsw				/* ds:si is source, es:di is dest */
+	popw	%di
+
+	movb	$36,%es:4(%di)
+
+	movw	%cx,%ds			/* access segment 0 */
+	xchgw	%di,(%bx)
+	movw	%es,%si
+	xchgw	%si,2(%bx)
+	popw	%ds			/* restore ds */
+	movw	%di, dpoff		/* save old parameters */
+	movw	%si, dpseg		/* to restore just before finishing */
+	pushw	%ds
+	popw	%es			/* reload es */
+
+/* Note that es is already set up.  Also cx is 0 from rep movsw above. */
+
+	xorb	%ah,%ah			/* reset FDC */
+	xorb	%dl,%dl
+	int	$0x13
+
+/* Get disk drive parameters, specifically number of sectors/track.
+ *
+ * It seems that there is no BIOS call to get the number of sectors.  Guess
+ * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
+ * 15 if sector 15 can be read.	Otherwise guess 9.
+ */
+
+	movw	$disksizes, %si		/* table of sizes to try */
+
+probe_loop: 
+	lodsb
+	cbtw				/* extend to word */
+	movw	%ax, sectors
+	cmpw	$disksizes+4, %si
+	jae	got_sectors		/* if all else fails, try 9 */
+	xchgw	%cx,%ax			/* cx = track and sector */
+	xorw	%dx,%dx			/* drive 0, head 0 */
+	movw	$0x0200, %bx		/* address after boot sector */
+					/*   (512 bytes from origin, es = cs) */
+	movw	$0x0201, %ax		/* service 2, 1 sector */
+	int	$0x13
+	jc	probe_loop		/* try next value */
+
+got_sectors: 
+	movw	$msg1end-msg1, %cx
+	movw	$msg1, %si
+	call	print_str
+
+/* ok, we've written the Loading... message, now we want to load the system */
+
+	movw	$SYSSEG, %ax
+	movw	%ax,%es			/* segment of SYSSEG<<4 */
+	pushw	%es
+	call	read_it
+
+/* This turns off the floppy drive motor, so that we enter the kernel in a
+ * known state, and don't have to worry about it later.
+ */
+	movw	$0x3f2, %dx
+	xorb	%al,%al
+	outb	%al,%dx
+
+	call	print_nl
+	pop	%es			/* = SYSSEG */
+
+/* Restore original disk parameters */
+	movw	$0x78, %bx
+	movw	dpoff, %di
+	movw	dpseg, %si
+	xorw	%ax,%ax
+	movw	%ax,%ds
+	movw	%di,(%bx)
+	movw	%si,2(%bx)
+
+	/* Everything now loaded.  %es = SYSSEG, so %es:0000 points to
+	 * start of loaded image.
+	 */
+
+	/* Jump to loaded copy */
+	ljmp	$SYSSEG, $start_runtime
+
+endseg:	.word SYSSEG
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDW"
+	.long	endseg
+	.long	16
+	.long	0
+	.previous
+
+/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
+ * boundaries are crossed. We try to load it as fast as possible, loading whole
+ * tracks whenever we can.
+ *
+ * in:	es - starting address segment (normally SYSSEG)
+ */
+read_it: 
+	movw	$0,sread		/* load whole image including prefix */
+	movw	%es,%ax
+	testw	$0x0fff, %ax
+die:	jne	die			/* es must be at 64kB boundary */
+	xorw	%bx,%bx			/* bx is starting address within segment */
+rp_read: 
+	movw	%es,%ax
+	movw	%bx,%dx
+	movb	$4, %cl
+	shrw	%cl,%dx			/* bx is always divisible by 16 */
+	addw	%dx,%ax
+	cmpw	endseg, %ax	/* have we loaded all yet? */
+	jb	ok1_read
+	ret
+ok1_read: 
+	movw	sectors, %ax
+	subw	sread, %ax
+	movw	%ax,%cx
+	shlw	$9, %cx
+	addw	%bx,%cx
+	jnc	ok2_read
+	je	ok2_read
+	xorw	%ax,%ax
+	subw	%bx,%ax
+	shrw	$9, %ax
+ok2_read: 
+	call	read_track
+	movw	%ax,%cx
+	addw	sread, %ax
+	cmpw	sectors, %ax
+	jne	ok3_read
+	movw	$1, %ax
+	subw	head, %ax
+	jne	ok4_read
+	incw	track
+ok4_read: 
+	movw	%ax, head
+	xorw	%ax,%ax
+ok3_read: 
+	movw	%ax, sread
+	shlw	$9, %cx
+	addw	%cx,%bx
+	jnc	rp_read
+	movw	%es,%ax
+	addb	$0x10, %ah
+	movw	%ax,%es
+	xorw	%bx,%bx
+	jmp	rp_read
+
+read_track: 
+	pusha
+	pushw	%ax
+	pushw	%bx
+	pushw	%bp			/* just in case the BIOS is buggy */
+	movw	$0x0e2e, %ax		/* 0x2e = . */
+	movw	$0x0007, %bx
+	int	$0x10
+	popw	%bp
+	popw	%bx
+	popw	%ax
+
+	movw	track, %dx
+	movw	sread, %cx
+	incw	%cx
+	movb	%dl,%ch
+	movw	head, %dx
+	movb	%dl,%dh
+	andw	$0x0100, %dx
+	movb	$2, %ah
+
+	pushw	%dx			/* save for error dump */
+	pushw	%cx
+	pushw	%bx
+	pushw	%ax
+
+	int	$0x13
+	jc	bad_rt
+	addw	$8, %sp
+	popa
+	ret
+
+bad_rt: pushw	%ax			/* save error code */
+	call	print_all		/* ah = error, al = read */
+
+	xorb	%ah,%ah
+	xorb	%dl,%dl
+	int	$0x13
+
+	addw	$10, %sp
+	popa
+	jmp	read_track
+
+/* print_all is for debugging purposes.	It will print out all of the registers.
+ * The assumption is that this is called from a routine, with a stack frame like
+ *	dx
+ *	cx
+ *	bx
+ *	ax
+ *	error
+ *	ret <- sp
+ */
+
+print_all: 
+	call	print_nl		/* nl for readability */
+	movw	$5, %cx			/* error code + 4 registers */
+	movw	%sp,%bp
+
+print_loop: 
+	pushw	%cx			/* save count left */
+
+	cmpb	$5, %cl
+	jae	no_reg			/* see if register name is needed */
+
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	movw	$0xe05+0x41-1, %ax
+	subb	%cl,%al
+	int	$0x10
+
+	movb	$0x58, %al		/* 'X' */
+	int	$0x10
+
+	movb	$0x3A, %al		/* ':' */
+	int	$0x10
+
+no_reg: 
+	addw	$2, %bp			/* next register */
+	call	print_hex		/* print it */
+	movb	$0x20, %al		/* print a space */
+	int	$0x10
+	popw	%cx
+	loop	print_loop
+	call	print_nl		/* nl for readability */
+	ret
+
+print_str: 
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	movb	$0x0e, %ah		/* write char, tty mode */
+prloop: 
+	lodsb
+	int	$0x10
+	loop	prloop
+	ret
+
+print_nl: 
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	movw	$0xe0d, %ax		/* CR */
+	int	$0x10
+	movb	$0xa, %al		/* LF */
+	int	$0x10
+	ret
+
+/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
+
+print_hex: 
+	movw	(%bp),%dx		/* load word into dx */
+	movb	$4, %cl
+	movb	$0x0e, %ah		/* write char, tty mode */
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	call	print_digit
+	call	print_digit
+	call	print_digit
+/* fall through */
+print_digit: 
+	rol	%cl,%dx			/* rotate so that lowest 4 bits are used */
+	movb	$0x0f, %al		/* mask for nybble */
+	andb	%dl,%al
+	addb	$0x90, %al		/* convert al to ascii hex (four instructions) */
+	daa
+	adcb	$0x40, %al
+	daa
+	int	$0x10
+	ret
+
+sread:	.word 0				/* sectors read of current track */
+head:	.word 0				/* current head */
+track:	.word 0				/* current track */
+
+sectors: 
+	.word 0
+
+dpseg:	.word 0
+dpoff:	.word 0
+
+disksizes: 
+	.byte 36,18,15,9
+
+msg1: 
+	.ascii "Loading ROM image"
+msg1end: 
+
+	.org 510, 0
+	.word 0xAA55
+
+start_runtime:
+	/* Install iPXE */
+	call	install
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Boot next device */
+	int $0x18
+
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/exeprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/exeprefix.S
new file mode 100644
index 0000000..c7e57ce
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/exeprefix.S
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/* Initial temporary stack size */
+#define EXE_STACK_SIZE 0x400
+
+/* Temporary decompression area (avoid DOS high memory area) */
+#define EXE_DECOMPRESS_ADDRESS 0x110000
+
+/* Fields within the Program Segment Prefix */
+#define PSP_CMDLINE_LEN 0x80
+#define PSP_CMDLINE_START 0x81
+
+	.text
+	.arch i386
+	.org 0
+	.code16
+	.section ".prefix", "awx", @progbits
+
+signature:
+	/* "MZ" signature */
+	.ascii	"MZ"
+
+last_block:
+	/* Number of bytes in last block that are really used */
+	.word	0
+
+blocks:
+	/* Number of 512-byte blocks */
+	.word	0
+	.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
+	.ascii	"ADDW"
+	.long	blocks
+	.long	512
+	.long	0
+	.previous
+
+num_reloc:
+	/* Number of relocation entries stored after the header */
+	.word	0
+
+header_pgh:
+	/* Number of paragraphs in the header */
+	.word	( ( _exe_start - signature ) / 16 )
+
+min_bss_pgh:
+	/* Minimum number of paragraphs of additional (BSS) memory */
+	.word	( EXE_STACK_SIZE / 16 )
+
+max_bss_pgh:
+	/* Maximum number of paragraphs of additional (BSS) memory */
+	.word	( EXE_STACK_SIZE / 16 )
+
+init_ss:
+	/* Initial stack segment (relative to start of executable) */
+	.word	-( ( _exe_start - signature ) / 16 )
+	.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
+	.ascii	"ADDW"
+	.long	init_ss
+	.long	16
+	.long	0
+	.previous
+
+init_sp:
+	/* Initial stack pointer */
+	.word	EXE_STACK_SIZE
+
+checksum:
+	/* Checksum (ignored) */
+	.word	0
+
+init_ip:
+	/* Initial instruction pointer */
+	.word	_exe_start
+
+init_cs:
+	/* Initial code segment (relative to start of executable) */
+	.word	-( ( _exe_start - signature ) / 16 )
+
+reloc_table:
+	/* Relocation table offset */
+	.word	0
+
+overlay:
+	/* Overlay number */
+	.word	0
+
+	.align 16, 0
+
+	.globl	_exe_start
+_exe_start:
+	/* Install iPXE.  Use a fixed temporary decompression area to
+	 * avoid trashing the DOS high memory area.
+	 */
+	call	alloc_basemem
+	xorl	%esi, %esi
+	movl	$EXE_DECOMPRESS_ADDRESS, %edi
+	clc
+	call	install_prealloc
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	/* Terminate command line with a NUL */
+	movzbw	PSP_CMDLINE_LEN, %si
+	movb	$0, PSP_CMDLINE_START(%si)
+
+	/* Calculate command line physical address */
+	xorl	%esi, %esi
+	movw	%ds, %si
+	shll	$4, %esi
+	addl	$PSP_CMDLINE_START, %esi
+
+	/* Set up %ds for access to .data16 */
+	movw	%bx, %ds
+
+	/* Record command line address */
+	movl	%esi, cmdline_phys
+
+	/* Run iPXE */
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Exit back to DOS.  This is very unlikely to work */
+	movw	$0x4c00, %ax
+	int	$0x21
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/hdprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/hdprefix.S
new file mode 100644
index 0000000..876bfe1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/hdprefix.S
@@ -0,0 +1,111 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.arch i386
+	.section ".prefix", "awx", @progbits
+	.code16
+	.org 0
+	.globl	_hd_start
+_hd_start:
+
+	movw	$load_image, %bp
+	jmp	find_active_partition
+
+#include "bootpart.S"
+
+load_image:
+	/* Get disk geometry */
+	pushal
+	pushw	%es
+	movb	$0x08, %ah
+	int	$0x13
+	jc	load_failed
+	movb	%cl, max_sector
+	movb	%dh, max_head
+	popw	%es
+	popal
+	
+1:	/* Read to end of current track */
+	movb	%cl, %al
+	negb	%al
+	addb	max_sector, %al
+	incb	%al
+	andb	$0x3f, %al
+	movzbl	%al, %eax
+	call	*read_sectors
+	jc	load_failed
+	
+	/* Update %es */
+	movw	%es, %bx
+	shll	$5, %eax
+	addw	%ax, %bx
+	movw	%bx, %es
+	shrl	$5, %eax
+	
+	/* Update LBA address */
+	addl	%eax, %edi
+	adcl	$0, %esi
+	
+	/* Update CHS address */
+	andb	$0xc0, %cl
+	orb	$0x01, %cl
+	incb	%dh
+	cmpb	max_head, %dh
+	jbe	2f
+	xorb	%dh, %dh
+	incb	%ch
+	jnc	2f
+	addb	$0xc0, %cl
+2:
+	/* Loop until whole image is read */
+	subl	%eax, load_length
+	ja	1b
+	ljmp	$BOOT_SEG, $start_image
+
+max_sector:
+	.byte	0
+max_head:
+	.byte	0
+load_length:
+	.long	0
+	
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDL"
+	.long	load_length
+	.long	512
+	.long	0
+	.previous
+
+
+load_failed:
+	movw	$10f, %si
+	jmp	boot_error
+10:	.asciz	"Could not load iPXE\r\n"
+
+	.org 510
+	.byte 0x55, 0xaa
+
+start_image:
+	/* Install iPXE */
+	call	install
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Boot next device */
+	int $0x18
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
new file mode 100644
index 0000000..d177d7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
@@ -0,0 +1,14 @@
+/*****************************************************************************
+ * PXE prefix that keeps the whole PXE stack present
+ *****************************************************************************
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/* Since we have the whole stack, we can use cached DHCP information */
+REQUEST_OBJECT ( pxeparent_dhcp )
+
+#define PXELOADER_KEEP_UNDI
+#define PXELOADER_KEEP_PXE
+#define _pxe_start _kkpxe_start
+#include "pxeprefix.S"
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
new file mode 100644
index 0000000..c756081
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
@@ -0,0 +1,10 @@
+/*****************************************************************************
+ * PXE prefix that keep the UNDI portion of the PXE stack present
+ *****************************************************************************
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define PXELOADER_KEEP_UNDI
+#define _pxe_start _kpxe_start
+#include "pxeprefix.S"
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/libprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/libprefix.S
new file mode 100644
index 0000000..77151a6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/libprefix.S
@@ -0,0 +1,934 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.arch i386
+
+/* Image compression enabled */
+#define COMPRESS 1
+
+/* Protected mode flag */
+#define CR0_PE 1
+
+/* Allow for DBG()-style messages within libprefix */
+#ifdef NDEBUG
+	.macro	progress message
+	.endm
+#else
+	.macro	progress message
+	pushfl
+	pushw	%ds
+	pushw	%si
+	pushw	%di
+	pushw	%cs
+	popw	%ds
+	xorw	%di, %di
+	movw	$progress_\@, %si
+	call	print_message
+	popw	%di
+	popw	%si
+	popw	%ds
+	popfl
+	.section ".prefix.data", "aw", @progbits
+progress_\@:
+	.asciz	"\message"
+	.size	progress_\@, . - progress\@
+	.previous
+	.endm
+#endif
+
+/*****************************************************************************
+ * Utility function: print character (with LF -> LF,CR translation)
+ *
+ * Parameters:
+ *   %al : character to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	print_character
+print_character:
+	/* Preserve registers */
+	pushw	%ax
+	pushw	%bx
+	pushw	%bp
+	/* If %di is non-zero, write character to buffer and exit */
+	testw	%di, %di
+	jz	1f
+	movb	%al, %ds:(%di)
+	incw	%di
+	jmp	3f
+1:	/* Print character */
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	movb	$0x0e, %ah		/* write char, tty mode */
+	cmpb	$0x0a, %al		/* '\n'? */
+	jne	2f
+	int	$0x10
+	movb	$0x0d, %al
+2:	int	$0x10
+	/* Restore registers and return */
+3:	popw	%bp
+	popw	%bx
+	popw	%ax
+	ret
+	.size	print_character, . - print_character
+
+/*****************************************************************************
+ * Utility function: print a NUL-terminated string
+ *
+ * Parameters:
+ *   %ds:si : string to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:si : character after terminating NUL
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	print_message
+print_message:
+	/* Preserve registers */
+	pushw	%ax
+	/* Print string */
+1: 	lodsb
+	testb	%al, %al
+	je	2f
+	call	print_character
+	jmp	1b
+2:	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	print_message, . - print_message
+
+/*****************************************************************************
+ * Utility functions: print hex digit/byte/word/dword
+ *
+ * Parameters:
+ *   %al (low nibble) : digit to print
+ *   %al : byte to print
+ *   %ax : word to print
+ *   %eax : dword to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	print_hex_dword
+print_hex_dword:
+	rorl	$16, %eax
+	call	print_hex_word
+	rorl	$16, %eax
+	/* Fall through */
+	.size	print_hex_dword, . - print_hex_dword
+	.globl	print_hex_word
+print_hex_word:
+	xchgb	%al, %ah
+	call	print_hex_byte
+	xchgb	%al, %ah
+	/* Fall through */
+	.size	print_hex_word, . - print_hex_word
+	.globl	print_hex_byte
+print_hex_byte:
+	rorb	$4, %al
+	call	print_hex_nibble
+	rorb	$4, %al
+	/* Fall through */
+	.size	print_hex_byte, . - print_hex_byte
+	.globl	print_hex_nibble
+print_hex_nibble:
+	/* Preserve registers */
+	pushw	%ax
+	/* Print digit (technique by Norbert Juffa <norbert.juffa at amd.com> */
+	andb	$0x0f, %al
+	cmpb	$10, %al
+	sbbb	$0x69, %al
+	das
+	call	print_character
+	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	print_hex_nibble, . - print_hex_nibble
+
+/*****************************************************************************
+ * Utility function: print PCI bus:dev.fn
+ *
+ * Parameters:
+ *   %ax : PCI bus:dev.fn to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	print_pci_busdevfn
+print_pci_busdevfn:
+	/* Preserve registers */
+	pushw	%ax
+	/* Print bus */
+	xchgb	%al, %ah
+	call	print_hex_byte
+	/* Print ":" */
+	movb	$( ':' ), %al
+	call	print_character
+	/* Print device */
+	movb	%ah, %al
+	shrb	$3, %al
+	call	print_hex_byte
+	/* Print "." */
+	movb	$( '.' ), %al
+	call	print_character
+	/* Print function */
+	movb	%ah, %al
+	andb	$0x07, %al
+	call	print_hex_nibble
+	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	print_pci_busdevfn, . - print_pci_busdevfn
+
+/*****************************************************************************
+ * Utility function: clear current line
+ *
+ * Parameters:
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	print_kill_line
+print_kill_line:
+	/* Preserve registers */
+	pushw	%ax
+	pushw	%cx
+	/* Print CR */
+	movb	$( '\r' ), %al
+	call	print_character
+	/* Print 79 spaces */
+	movb	$( ' ' ), %al
+	movw	$79, %cx
+1:	call	print_character
+	loop	1b
+	/* Print CR */
+	movb	$( '\r' ), %al
+	call	print_character
+	/* Restore registers and return */
+	popw	%cx
+	popw	%ax
+	ret
+	.size	print_kill_line, . - print_kill_line
+
+/****************************************************************************
+ * copy_bytes
+ *
+ * Copy bytes
+ *
+ * Parameters:
+ *   %ds:esi : source address
+ *   %es:edi : destination address
+ *   %ecx : length
+ * Returns:
+ *   %ds:esi : next source address
+ *   %es:edi : next destination address
+ * Corrupts:
+ *   None
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+copy_bytes:
+	pushl	%ecx
+	rep addr32 movsb
+	popl	%ecx
+	ret
+	.size	copy_bytes, . - copy_bytes
+
+/****************************************************************************
+ * zero_bytes
+ *
+ * Zero bytes
+ *
+ * Parameters:
+ *   %ds:esi : source address
+ *   %es:edi : destination address
+ *   %ecx : length
+ * Returns:
+ *   %ds:esi : next source address
+ *   %es:edi : next destination address
+ * Corrupts:
+ *   None
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+zero_bytes:
+	pushl	%ecx
+	pushw	%ax
+	xorw	%ax, %ax
+	rep addr32 stosb
+	popw	%ax
+	popl	%ecx
+	ret
+	.size	zero_bytes, . - zero_bytes
+
+/****************************************************************************
+ * process_bytes
+ *
+ * Call memcpy()-like function
+ *
+ * Parameters:
+ *   %esi : source physical address
+ *   %edi : destination physical address
+ *   %ecx : length
+ *   %bx : memcpy()-like function to call, passing parameters:
+ *	     %ds:esi : source address
+ *	     %es:edi : destination address
+ *	     %ecx : length
+ *         and returning:
+ *	     %ds:esi : next source address
+ *	     %es:edi : next destination address
+ * Returns:
+ *   %esi : next source physical address
+ *   %edi : next destination physical address
+ * Corrupts:
+ *   None
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+process_bytes:
+
+#ifndef KEEP_IT_REAL
+
+	/* Preserve registers */
+	pushfw
+	pushl	%eax
+	pushl	%ebp
+
+	/* Construct GDT on stack (since .prefix may not be writable) */
+	.equ	PM_DS, 0x18	/* Flat data segment */
+	pushl	$0x00cf9300
+	pushl	$0x0000ffff
+	.equ	PM_SS, 0x10	/* Stack segment based at %ss:0000 */
+	pushl	$0x008f0930
+	pushw	%ss
+	pushw	$0xffff
+	.equ	PM_CS, 0x08	/* Code segment based at %cs:0000 */
+	pushl	$0x008f09b0
+	pushw	%cs
+	pushw	$0xffff
+	pushl	$0		/* Base and length */
+	pushw	%ss
+	pushw	$0x1f
+	movzwl	%sp, %ebp
+	shll	$4, 0x02(%bp)
+	addl	%ebp, 0x02(%bp)
+	shll	$4, 0x0a(%bp)
+	shll	$4, 0x12(%bp)
+	subw	$8, %sp
+	sgdt	-8(%bp)
+
+	/* Switch to protected mode */
+	pushw	%gs
+	pushw	%fs
+	pushw	%es
+	pushw	%ds
+	pushw	%ss
+	pushw	%cs
+	pushw	$2f
+	cli
+	data32 lgdt (%bp)
+	movl	%cr0, %eax
+	orb	$CR0_PE, %al
+	movl	%eax, %cr0
+	ljmp	$PM_CS, $1f
+1:	movw	$PM_SS, %ax
+	movw	%ax, %ss
+	movw	$PM_DS, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+
+	/* Call memcpy()-like function */
+	call	*%bx
+
+	/* Return to (flat) real mode */
+	movl	%cr0, %eax
+	andb	$0!CR0_PE, %al
+	movl	%eax, %cr0
+	lret
+2:	/* lret will ljmp to here */
+	popw	%ss
+	popw	%ds
+	popw	%es
+	popw	%fs
+	popw	%gs
+
+	/* Restore GDT */
+	data32 lgdt -8(%bp)
+	addw	$( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
+
+	/* Restore registers and return */
+	popl	%ebp
+	popl	%eax
+	popfw
+	ret
+
+#else /* KEEP_IT_REAL */
+
+	/* Preserve registers */
+	pushl	%eax
+	pushw	%ds
+	pushw	%es
+	
+	/* Convert %esi and %edi to %ds:esi and %es:edi */
+	shrl	$4, %esi
+	movw	%si, %ds
+	xorw	%si, %si
+	shll	$4, %esi
+	shrl	$4, %edi
+	movw	%di, %es
+	xorw	%di, %di
+	shll	$4, %edi
+
+	/* Call memcpy()-like function */
+	call	*%bx
+
+	/* Convert %ds:esi and %es:edi back to physical addresses */
+	xorl	%eax, %eax
+	movw	%ds, %cx
+	shll	$4, %eax
+	addl	%eax, %esi
+	xorl	%eax, %eax
+	movw	%es, %cx
+	shll	$4, %eax
+	addl	%eax, %edi
+
+	/* Restore registers and return */
+	popw	%es
+	popw	%ds
+	popl	%eax
+	ret
+
+#endif /* KEEP_IT_REAL */
+
+	.size	process_bytes, . - process_bytes
+
+/****************************************************************************
+ * install_block
+ *
+ * Install block to specified address
+ *
+ * Parameters:
+ *   %esi : source physical address (must be a multiple of 16)
+ *   %edi : destination physical address (must be a multiple of 16)
+ *   %ecx : length of (decompressed) data
+ *   %edx : total length of block (including any uninitialised data portion)
+ * Returns:
+ *   %esi : next source physical address (will be a multiple of 16)
+ *   %edi : next destination physical address (will be a multiple of 16)
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+install_block:
+	/* Preserve registers */
+	pushl	%ecx
+	pushw	%bx
+
+	/* Decompress (or copy) source to destination */
+#if COMPRESS
+	movw	$decompress16, %bx
+#else
+	movw	$copy_bytes, %bx
+#endif
+	call	process_bytes
+
+	/* Zero .bss portion */
+	negl	%ecx
+	addl	%edx, %ecx
+	movw	$zero_bytes, %bx
+	call	process_bytes
+
+	/* Round up %esi and %edi to start of next blocks */
+	addl	$0xf, %esi
+	andl	$~0xf, %esi
+	addl	$0xf, %edi
+	andl	$~0xf, %edi
+
+	/* Restore registers and return */
+	popw	%bx
+	popl	%ecx
+	ret
+	.size install_block, . - install_block
+
+/****************************************************************************
+ * alloc_basemem
+ *
+ * Allocate space for .text16 and .data16 from top of base memory.
+ * Memory is allocated using the BIOS free base memory counter at
+ * 0x40:13.
+ *
+ * Parameters: 
+ *   none
+ * Returns:
+ *   %ax : .text16 segment address
+ *   %bx : .data16 segment address
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl	alloc_basemem
+alloc_basemem:
+	/* Preserve registers */
+	pushw	%fs
+
+	/* FBMS => %ax as segment address */
+	pushw	$0x40
+	popw	%fs
+	movw	%fs:0x13, %ax
+	shlw	$6, %ax
+
+	/* Calculate .data16 segment address */
+	subw	$_data16_memsz_pgh, %ax
+	pushw	%ax
+
+	/* Calculate .text16 segment address */
+	subw	$_text16_memsz_pgh, %ax
+	pushw	%ax
+
+	/* Update FBMS */
+	shrw	$6, %ax
+	movw	%ax, %fs:0x13
+
+	/* Retrieve .text16 and .data16 segment addresses */
+	popw	%ax
+	popw	%bx
+
+	/* Restore registers and return */
+	popw	%fs
+	ret
+	.size alloc_basemem, . - alloc_basemem
+
+/****************************************************************************
+ * free_basemem
+ *
+ * Free space allocated with alloc_basemem.
+ *
+ * Parameters:
+ *   %ax : .text16 segment address
+ *   %bx : .data16 segment address
+ * Returns:
+ *   %ax : 0 if successfully freed
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl	free_basemem
+free_basemem:
+	/* Preserve registers */
+	pushw	%fs
+
+	/* Check FBMS counter */
+	pushw	%ax
+	shrw	$6, %ax
+	pushw	$0x40
+	popw	%fs
+	cmpw	%ax, %fs:0x13
+	popw	%ax
+	jne	1f
+
+	/* Check hooked interrupt count */
+	cmpw	$0, %cs:hooked_bios_interrupts
+	jne	1f
+
+	/* OK to free memory */
+	addw	$_text16_memsz_pgh, %ax
+	addw	$_data16_memsz_pgh, %ax
+	shrw	$6, %ax
+	movw	%ax, %fs:0x13
+	xorw	%ax, %ax
+
+1:	/* Restore registers and return */
+	popw	%fs
+	ret
+	.size free_basemem, . - free_basemem
+
+	.section ".text16.data", "aw", @progbits
+	.globl	hooked_bios_interrupts
+hooked_bios_interrupts:
+	.word	0
+	.size	hooked_bios_interrupts, . - hooked_bios_interrupts
+
+/****************************************************************************
+ * install
+ *
+ * Install all text and data segments.
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   %ax  : .text16 segment address
+ *   %bx  : .data16 segment address
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl install
+install:
+	progress "install:\n"
+	/* Preserve registers */
+	pushl	%esi
+	pushl	%edi
+	/* Allocate space for .text16 and .data16 */
+	call	alloc_basemem
+	/* Image source = %cs:0000 */
+	xorl	%esi, %esi
+	/* Image destination = default */
+	xorl	%edi, %edi
+	/* Allow relocation */
+	clc
+	/* Install text and data segments */
+	call	install_prealloc
+	/* Restore registers and return */
+	popl	%edi
+	popl	%esi
+	ret
+	.size install, . - install
+
+/****************************************************************************
+ * install_prealloc
+ *
+ * Install all text and data segments.
+ *
+ * Parameters:
+ *   %ax  : .text16 segment address
+ *   %bx  : .data16 segment address
+ *   %esi : Image source physical address (or zero for %cs:0000)
+ *   %edi : Decompression temporary area physical address (or zero for default)
+ *   CF set : Avoid relocating to top of memory
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".prefix.lib", "awx", @progbits
+	.code16
+	.globl install_prealloc
+install_prealloc:
+	progress "install_prealloc:\n"
+	/* Save registers */
+	pushal
+	pushw	%ds
+	pushw	%es
+	cld			/* Sanity: clear the direction flag asap */
+	pushfw
+
+	/* Set up %ds for (read-only) access to .prefix */
+	pushw	%cs
+	popw	%ds
+
+	/* Copy decompression temporary area physical address to %ebp */
+	movl	%edi, %ebp
+
+	/* Install .text16.early */
+	progress "  .text16.early\n"
+	pushl	%esi
+	xorl	%esi, %esi
+	movw	%cs, %si
+	shll	$4, %esi
+	addl	$_text16_early_lma, %esi
+	movzwl	%ax, %edi
+	shll	$4, %edi
+	movl	$_text16_early_filesz, %ecx
+	movl	$_text16_early_memsz, %edx
+	call	install_block		/* .text16.early */
+	popl	%esi
+
+#ifndef KEEP_IT_REAL
+	/* Access high memory by enabling the A20 gate.  (We will
+	 * already have 4GB segment limits as a result of calling
+	 * install_block.)
+	 */
+	progress "  access_highmem\n"
+	pushw	%cs
+	pushw	$1f
+	pushw	%ax
+	pushw	$access_highmem
+	lret
+1:	/* Die if we could not access high memory */
+	jnc	3f
+	movw	$a20_death_message, %si
+	xorw	%di, %di
+	call	print_message
+2:	jmp	2b
+	.section ".prefix.data", "aw", @progbits
+a20_death_message:
+	.asciz	"\nHigh memory inaccessible - cannot continue\n"
+	.size	a20_death_message, . - a20_death_message
+	.previous
+3:
+#endif
+
+	/* Open payload (which may not yet be in memory) */
+	progress "  open_payload\n"
+	pushw	%cs
+	pushw	$1f
+	pushw	%ax
+	pushw	$open_payload
+	lret
+1:	/* Die if we could not access the payload */
+	jnc	3f
+	xorw	%di, %di
+	movl	%esi, %eax
+	call	print_hex_dword
+	movw	$payload_death_message, %si
+	call	print_message
+2:	jmp	2b
+	.section ".prefix.data", "aw", @progbits
+payload_death_message:
+	.asciz	"\nPayload inaccessible - cannot continue\n"
+	.size	payload_death_message, . - payload_death_message
+	.previous
+3:
+
+	/* Calculate physical address of payload (i.e. first source) */
+	testl	%esi, %esi
+	jnz	1f
+	movw	%cs, %si
+	shll	$4, %esi
+1:	addl	payload_lma, %esi
+
+	/* Install .text16.late and .data16 */
+	progress "  .text16.late\n"
+	movl	$_text16_late_filesz, %ecx
+	movl	$_text16_late_memsz, %edx
+	call	install_block		/* .text16.late */
+	progress "  .data16\n"
+	movzwl	%bx, %edi
+	shll	$4, %edi
+	movl	$_data16_filesz, %ecx
+	movl	$_data16_memsz, %edx
+	call	install_block		/* .data16 */
+
+	/* Set up %ds for access to .data16 */
+	movw	%bx, %ds
+
+#ifdef KEEP_IT_REAL
+	/* Initialise libkir */
+	movw	%ax, (init_libkir_vector+2)
+	lcall	*init_libkir_vector
+#else
+	/* Find a suitable decompression temporary area, if none specified */
+	pushl	%eax
+	testl	%ebp, %ebp
+	jnz	1f
+	/* Use INT 15,88 to find the highest available address via INT
+	 * 15,88.  This limits us to around 64MB, which should avoid
+	 * all of the POST-time memory map failure modes.
+	 */
+	movb	$0x88, %ah
+	int	$0x15
+	movw	%ax, %bp
+	addl	$0x400, %ebp
+	subl	$_textdata_memsz_kb, %ebp
+	shll	$10, %ebp
+	/* Sanity check: if we have ended up below 1MB, use 1MB */
+	cmpl	$0x100000, %ebp
+	jae	1f
+	movl	$0x100000, %ebp
+1:	popl	%eax
+
+	/* Install .text and .data to temporary area in high memory,
+	 * prior to reading the E820 memory map and relocating
+	 * properly.
+	 */
+	progress "  .textdata\n"
+	movl	%ebp, %edi
+	movl	$_textdata_filesz, %ecx
+	movl	$_textdata_memsz, %edx
+	call	install_block
+
+	/* Initialise librm at current location */
+	progress "  init_librm\n"
+	movw	%ax, (init_librm_vector+2)
+	movl	%ebp, %edi
+	lcall	*init_librm_vector
+
+	/* Skip relocation if CF was set on entry */
+	popfw
+	pushfw
+	jc	skip_relocate
+
+	/* Call relocate() to determine target address for relocation.
+	 * relocate() will return with %esi, %edi and %ecx set up
+	 * ready for the copy to the new location.
+	 */
+	progress "  relocate\n"
+	movw	%ax, (prot_call_vector+2)
+	pushl	$relocate
+	lcall	*prot_call_vector
+	popl	%edx /* discard */
+
+	/* Copy code to new location */
+	progress "  copy\n"
+	pushl	%edi
+	pushw	%bx
+	movw	$copy_bytes, %bx
+	call	process_bytes
+	popw	%bx
+	popl	%edi
+
+	/* Initialise librm at new location */
+	progress "  init_librm\n"
+	lcall	*init_librm_vector
+skip_relocate:
+#endif
+
+	/* Close access to payload */
+	progress "  close_payload\n"
+	movw	%ax, (close_payload_vector+2)
+	lcall	*close_payload_vector
+
+	/* Restore registers */
+	popfw
+	popw	%es
+	popw	%ds
+	popal
+	ret
+	.size install_prealloc, . - install_prealloc
+
+	/* Vectors for far calls to .text16 functions.  Must be in
+	 * .data16, since .prefix may not be writable.
+	 */
+	.section ".data16", "aw", @progbits
+#ifdef KEEP_IT_REAL
+init_libkir_vector:
+	.word init_libkir
+	.word 0
+	.size init_libkir_vector, . - init_libkir_vector
+#else
+init_librm_vector:
+	.word init_librm
+	.word 0
+	.size init_librm_vector, . - init_librm_vector
+prot_call_vector:
+	.word prot_call
+	.word 0
+	.size prot_call_vector, . - prot_call_vector
+#endif
+close_payload_vector:
+	.word close_payload
+	.word 0
+	.size close_payload_vector, . - close_payload_vector
+
+	/* Payload address */
+	.section ".prefix.lib", "awx", @progbits
+payload_lma:
+	.long 0
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADHL"
+	.long	payload_lma
+	.long	1
+	.long	0
+	.previous
+
+	/* Dummy routines to open and close payload */
+	.section ".text16.early.data", "aw", @progbits
+	.weak	open_payload
+	.weak	close_payload
+open_payload:
+close_payload:
+	clc
+	lret
+	.size	open_payload, . - open_payload
+	.size	close_payload, . - close_payload
+
+/****************************************************************************
+ * uninstall
+ *
+ * Uninstall all text and data segments.
+ *
+ * Parameters:
+ *   %ax  : .text16 segment address
+ *   %bx  : .data16 segment address
+ * Returns:
+ *   none
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl uninstall
+uninstall:
+	call	free_basemem
+	ret
+	.size uninstall, . - uninstall
+
+
+
+	/* File split information for the compressor */
+#if COMPRESS
+#define PACK_OR_COPY	"PACK"
+#else
+#define PACK_OR_COPY	"COPY"
+#endif
+	.section ".zinfo", "a", @progbits
+	.ascii	"COPY"
+	.long	_prefix_lma
+	.long	_prefix_filesz
+	.long	_max_align
+	.ascii	PACK_OR_COPY
+	.long	_text16_early_lma
+	.long	_text16_early_filesz
+	.long	_max_align
+	.ascii	"PAYL"
+	.long	0
+	.long	0
+	.long	_max_align
+	.ascii	PACK_OR_COPY
+	.long	_text16_late_lma
+	.long	_text16_late_filesz
+	.long	_max_align
+	.ascii	PACK_OR_COPY
+	.long	_data16_lma
+	.long	_data16_filesz
+	.long	_max_align
+	.ascii	PACK_OR_COPY
+	.long	_textdata_lma
+	.long	_textdata_filesz
+	.long	_max_align
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/linuxprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/linuxprefix.S
new file mode 100644
index 0000000..398d3cb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/linuxprefix.S
@@ -0,0 +1,28 @@
+#include <linux/unistd.h>
+
+	.section ".text"
+	.code32
+	.globl _linux_start
+	.type _linux_start, @function
+
+_linux_start:
+	xorl	%ebp, %ebp
+
+	popl	%esi       // save argc
+	movl	%esp, %edi // save argv
+
+	andl	$~15, %esp // 16-byte align the stack
+
+	pushl	%edi // argv -> C arg2
+	pushl	%esi // argc -> C arg1
+
+	call	save_args
+
+	/* Our main doesn't use any arguments */
+	call	main
+
+	movl	%eax, %ebx // rc -> syscall arg1
+	movl	$__NR_exit, %eax
+	int	$0x80
+
+	.size _linux_start, . - _linux_start
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
new file mode 100644
index 0000000..f87ef85
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
@@ -0,0 +1,228 @@
+/*
+	Copyright (C) 2000, Entity Cyber, Inc.
+
+	Authors: Gary Byers (gb at thinguin.org)
+		 Marty Connor (mdc at thinguin.org)
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License (GPL), incorporated herein by reference.
+
+	Description:	
+
+	This is just a little bit of code and data that can get prepended
+	to a ROM image in order to allow bootloaders to load the result
+	as if it were a Linux kernel image.
+
+	A real Linux kernel image consists of a one-sector boot loader
+	(to load the image from a floppy disk), followed a few sectors
+	of setup code, followed by the kernel code itself.  There's
+	a table in the first sector (starting at offset 497) that indicates
+	how many sectors of setup code follow the first sector and which
+	contains some other parameters that aren't interesting in this
+	case.
+
+	When a bootloader loads the sectors that comprise a kernel image,
+	it doesn't execute the code in the first sector (since that code
+	would try to load the image from a floppy disk.)  The code in the
+	first sector below doesn't expect to get executed (and prints an
+	error message if it ever -is- executed.)
+
+	We don't require much in the way of setup code.  Historically, the
+	Linux kernel required at least 4 sectors of setup code.
+	Therefore, at least 4 sectors must be present even though we don't
+	use them.
+
+*/
+
+FILE_LICENCE ( GPL_ANY )
+
+#define	SETUPSECS 4		/* Minimal nr of setup-sectors */
+#define PREFIXSIZE ((SETUPSECS+1)*512)
+#define PREFIXPGH (PREFIXSIZE / 16 )
+#define	BOOTSEG  0x07C0		/* original address of boot-sector */
+#define	INITSEG  0x9000		/* we move boot here - out of the way */
+#define	SETUPSEG 0x9020		/* setup starts here */
+#define SYSSEG   0x1000		/* system loaded at 0x10000 (65536). */
+
+	.text
+	.code16
+	.arch i386
+	.org	0
+	.section ".prefix", "ax", @progbits
+	.globl	_lkrn_start
+_lkrn_start:
+/* 
+	This is a minimal boot sector.	If anyone tries to execute it (e.g., if
+	a .lilo file is dd'ed to a floppy), print an error message. 
+*/
+
+bootsector: 
+	jmp	$BOOTSEG, $1f	/* reload cs:ip to match relocation addr */
+1:
+	movw	$0x2000, %di		/*  0x2000 is arbitrary value >= length
+					    of bootsect + room for stack */
+
+	movw	$BOOTSEG, %ax
+	movw	%ax,%ds
+	movw	%ax,%es
+
+	cli
+	movw	%ax, %ss		/* put stack at BOOTSEG:0x2000. */
+	movw	%di,%sp
+	sti
+
+	movw	$why_end-why, %cx
+	movw	$why, %si
+
+	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
+	movb	$0x0e, %ah		/* write char, tty mode */
+prloop: 
+	lodsb
+	int	$0x10
+	loop	prloop
+freeze: jmp	freeze
+
+why:	.ascii	"This image cannot be loaded from a floppy disk.\r\n"
+why_end: 
+
+
+/*
+	The following header is documented in the Linux source code at
+	Documentation/x86/boot.txt
+*/
+	.org	497
+setup_sects: 
+	.byte	SETUPSECS
+root_flags: 
+	.word	0
+syssize: 
+	.long	-PREFIXPGH
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDL"
+	.long	syssize
+	.long	16
+	.long	0
+	.previous
+	
+ram_size: 
+	.word	0
+vid_mode: 
+	.word	0
+root_dev: 
+	.word	0
+boot_flag: 
+	.word	0xAA55
+jump:
+	/* Manually specify a two-byte jmp instruction here rather
+	 * than leaving it up to the assembler. */
+	.byte	0xeb
+	.byte	setup_code - header
+header:
+	.byte	'H', 'd', 'r', 'S'
+version:
+	.word	0x0207 /* 2.07 */
+realmode_swtch:
+	.long	0
+start_sys:
+	.word	0
+kernel_version:
+	.word	0
+type_of_loader:
+	.byte	0
+loadflags:
+	.byte	0
+setup_move_size:
+	.word	0
+code32_start:
+	.long	0
+ramdisk_image:
+	.long	0
+ramdisk_size:
+	.long	0
+bootsect_kludge:
+	.long	0
+heap_end_ptr:
+	.word	0
+pad1:
+	.word	0
+cmd_line_ptr:
+	.long	0
+initrd_addr_max:
+	/* We don't use an initrd but some bootloaders (e.g. SYSLINUX) have
+	 * been known to require this field.  Set the value to 2 GB.  This
+	 * value is also used by the Linux kernel. */
+	.long	0x7fffffff
+kernel_alignment:
+	.long	0
+relocatable_kernel:
+	.byte	0
+pad2:
+	.byte	0, 0, 0
+cmdline_size:
+	.long	0
+hardware_subarch:
+	.long	0
+hardware_subarch_data:
+	.byte	0, 0, 0, 0, 0, 0, 0, 0
+
+/*
+	We don't need to do too much setup.
+
+	This code gets loaded at SETUPSEG:0.  It wants to start
+	executing the image that's loaded at SYSSEG:0 and
+	whose entry point is SYSSEG:0.
+*/
+setup_code:
+	/* We expect to be contiguous in memory once loaded.  The Linux image
+	 * boot process requires that setup code is loaded separately from
+	 * "non-real code".  Since we don't need any information that's left
+	 * in the prefix, it doesn't matter: we just have to ensure that
+	 * %cs:0000 is where the start of the image *would* be.
+	 */
+	ljmp	$(SYSSEG-(PREFIXSIZE/16)), $run_ipxe
+
+
+	.org	PREFIXSIZE
+/*
+	We're now at the beginning of the kernel proper.
+ */
+run_ipxe:
+	/* Set up stack just below 0x7c00 */
+	xorw	%ax, %ax
+	movw	%ax, %ss
+	movw	$0x7c00, %sp
+
+	/* Retrieve command-line pointer */
+	movl	%es:cmd_line_ptr, %edx
+
+	/* Install iPXE */
+	call	install
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	/* Set up %ds for access to .data16 */
+	movw	%bx, %ds
+
+	/* Store command-line pointer */
+	movl	%edx, cmdline_phys
+
+	/* Run iPXE */
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Boot next device */
+	int $0x18
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mbr.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mbr.S
new file mode 100644
index 0000000..adfe204
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mbr.S
@@ -0,0 +1,13 @@
+	.text
+	.arch i386
+	.section ".prefix", "awx", @progbits
+	.code16
+	.org 0
+
+mbr:
+	movw	$exec_sector, %bp
+	jmp	find_active_partition
+exec_sector:
+	ljmp	$0x0000, $0x7c00
+
+#include "bootpart.S"
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mromprefix.S
new file mode 100644
index 0000000..7bbe44c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/mromprefix.S
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define PCIBIOS_READ_CONFIG_WORD	0xb109
+#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
+#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
+#define PCI_COMMAND			0x04
+#define PCI_COMMAND_MEM				0x02
+#define PCI_BAR_0			0x10
+#define PCI_BAR_5			0x24
+#define PCI_BAR_EXPROM			0x30
+
+#define ROMPREFIX_EXCLUDE_PAYLOAD 1
+#define _rom_start _mrom_start
+#include "romprefix.S"
+
+	.text
+	.arch i386
+	.code16
+
+/* Obtain access to payload by exposing the expansion ROM BAR at the
+ * address currently used by a suitably large memory BAR on the same
+ * device.  The memory BAR is temporarily disabled.  Using a memory
+ * BAR on the same device means that we don't have to worry about the
+ * configuration of any intermediate PCI bridges.
+ *
+ * Parameters:
+ *   %ds:0000 : Prefix
+ *   %esi : Buffer for copy of image source (or zero if no buffer available)
+ * Returns:
+ *   %esi : Valid image source address (buffered or unbuffered)
+ *   CF set on error
+ */
+	.section ".text16.early", "awx", @progbits
+	.globl	open_payload
+open_payload:
+	/* Preserve registers */
+	pushl	%eax
+	pushw	%bx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%edi
+	pushw	%bp
+	pushw	%ds
+
+	/* Retrieve bus:dev.fn and image source length from .prefix */
+	movw	init_pci_busdevfn, %bx
+	movl	image_source_len_dword, %ecx
+
+	/* Set up %ds for access to .text16.early */
+	pushw	%cs
+	popw	%ds
+
+	/* Store bus:dev.fn and image source length to .text16.early */
+	movw	%bx, payload_pci_busdevfn
+	movl	%ecx, rom_bar_copy_len_dword
+
+	/* Get expansion ROM BAR current value */
+	movw	$PCI_BAR_EXPROM, %di
+	call	pci_read_bar
+	movl	%eax, rom_bar_orig_value
+
+	/* Get expansion ROM BAR size */
+	call	pci_size_mem_bar_low
+	movl	%ecx, rom_bar_size
+
+	/* Find a suitable memory BAR to use */
+	movw	$PCI_BAR_0, %di		/* %di is PCI BAR register */
+	xorw	%bp, %bp		/* %bp is increment */
+find_mem_bar:
+	/* Move to next BAR */
+	addw	%bp, %di
+	cmpw	$PCI_BAR_5, %di
+	jle	1f
+	stc
+	jmp	99f
+1:	movw	$4, %bp
+
+	/* Get BAR current value */
+	call	pci_read_bar
+
+	/* Skip non-existent BARs */
+	notl	%eax
+	testl	%eax, %eax
+	notl	%eax
+	jz	find_mem_bar
+
+	/* Skip I/O BARs */
+	testb	$0x01, %al
+	jnz	find_mem_bar
+
+	/* Set increment to 8 for 64-bit BARs */
+	testb	$0x04, %al
+	jz	1f
+	movw	$8, %bp
+1:
+	/* Skip 64-bit BARs with high dword set; we couldn't use this
+	 * address for the (32-bit) expansion ROM BAR anyway
+	 */
+	testl	%edx, %edx
+	jnz	find_mem_bar
+
+	/* Get low dword of BAR size */
+	call	pci_size_mem_bar_low
+
+	/* Skip BARs smaller than the expansion ROM BAR */
+	cmpl	%ecx, rom_bar_size
+	ja	find_mem_bar
+
+	/* We have a memory BAR with a 32-bit address that is large
+	 * enough to use.  Store BAR number and original value.
+	 */
+	movw	%di, stolen_bar_register
+	movl	%eax, stolen_bar_orig_value
+
+	/* Remove flags from BAR address */
+	xorb	%al, %al
+
+	/* Write zero to our stolen BAR.  This doesn't technically
+	 * disable it, but it's a pretty safe bet that the PCI bridge
+	 * won't pass through accesses to this region anyway.  Note
+	 * that the high dword (if any) must already be zero.
+	 */
+	xorl	%ecx, %ecx
+	call	pci_write_config_dword
+
+	/* Enable expansion ROM BAR at stolen BAR's address */
+	movl	%eax, %ecx
+	orb	$0x1, %cl
+	movw	$PCI_BAR_EXPROM, %di
+	call	pci_write_config_dword
+
+	/* Copy payload to buffer, or set buffer address to BAR address */
+	testl	%esi, %esi
+	jz	1f
+	/* We have a buffer; copy payload to it.  Since .mrom is
+	 * designed specifically for real hardware, we assume that
+	 * flat real mode is working properly.  (In the unlikely event
+	 * that this code is run inside a hypervisor that doesn't
+	 * properly support flat real mode, it will die horribly.)
+	 */
+	pushl	%esi
+	pushw	%es
+	movl	%esi, %edi
+	movl	%eax, %esi
+	movl	rom_bar_copy_len_dword, %ecx
+	xorw	%ax, %ax
+	movw	%ax, %es
+	addr32 es rep movsl
+	popw	%es
+	popl	%esi
+	jmp	2f
+1:	/* We have no buffer; set %esi to the BAR address */
+	movl	%eax, %esi
+2:
+
+	clc
+	/* Restore registers and return */
+99:	popw	%ds
+	popw	%bp
+	popl	%edi
+	popl	%edx
+	popl	%ecx
+	popw	%bx
+	popl	%eax
+	lret
+	.size	open_payload, . - open_payload
+
+	.section ".text16.early.data", "aw", @progbits
+payload_pci_busdevfn:
+	.word	0
+	.size	payload_pci_busdevfn, . - payload_pci_busdevfn
+
+	.section ".text16.early.data", "aw", @progbits
+rom_bar_orig_value:
+	.long	0
+	.size	rom_bar_orig_value, . - rom_bar_orig_value
+
+	.section ".text16.early.data", "aw", @progbits
+rom_bar_size:
+	.long	0
+	.size	rom_bar_size, . - rom_bar_size
+
+	.section ".text16.early.data", "aw", @progbits
+rom_bar_copy_len_dword:
+	.long	0
+	.size	rom_bar_copy_len_dword, . - rom_bar_copy_len_dword
+
+	.section ".text16.early.data", "aw", @progbits
+stolen_bar_register:
+	.word	0
+	.size	stolen_bar_register, . - stolen_bar_register
+
+	.section ".text16.early.data", "aw", @progbits
+stolen_bar_orig_value:
+	.long	0
+	.size	stolen_bar_orig_value, . - stolen_bar_orig_value
+
+/* Restore original BAR values
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   none
+ */
+	.section ".text16.early", "awx", @progbits
+	.globl	close_payload
+close_payload:
+	/* Preserve registers */
+	pushw	%bx
+	pushw	%di
+	pushl	%ecx
+	pushw	%ds
+
+	/* Set up %ds for access to .text16.early */
+	pushw	%cs
+	popw	%ds
+
+	/* Retrieve stored bus:dev.fn */
+	movw	payload_pci_busdevfn, %bx
+
+	/* Restore expansion ROM BAR original value */
+	movw	$PCI_BAR_EXPROM, %di
+	movl	rom_bar_orig_value, %ecx
+	call	pci_write_config_dword
+
+	/* Restore stolen BAR original value */
+	movw	stolen_bar_register, %di
+	movl	stolen_bar_orig_value, %ecx
+	call	pci_write_config_dword
+
+	/* Restore registers and return */
+	popw	%ds
+	popl	%ecx
+	popw	%di
+	popw	%bx
+	lret
+	.size	close_payload, . - close_payload
+
+/* Get PCI BAR value
+ *
+ * Parameters:
+ *   %bx : PCI bus:dev.fn
+ *   %di : PCI BAR register number
+ * Returns:
+ *   %edx:%eax : PCI BAR value
+ */
+	.section ".text16.early", "awx", @progbits
+pci_read_bar:
+	/* Preserve registers */
+	pushl	%ecx
+	pushw	%di
+
+	/* Read low dword value */
+	call	pci_read_config_dword
+	movl	%ecx, %eax
+
+	/* Read high dword value, if applicable */
+	xorl	%edx, %edx
+	andb	$0x07, %cl
+	cmpb	$0x04, %cl
+	jne	1f
+	addw	$4, %di
+	call	pci_read_config_dword
+	movl	%ecx, %edx
+1:
+	/* Restore registers and return */
+	popw	%di
+	popl	%ecx
+	ret
+	.size	pci_read_bar, . - pci_read_bar
+
+/* Get low dword of PCI memory BAR size
+ *
+ * Parameters:
+ *   %bx : PCI bus:dev.fn
+ *   %di : PCI BAR register number
+ *   %eax : Low dword of current PCI BAR value
+ * Returns:
+ *   %ecx : PCI BAR size
+ */
+	.section ".text16.early", "awx", @progbits
+pci_size_mem_bar_low:
+	/* Preserve registers */
+	pushw	%dx
+
+	/* Disable memory accesses */
+	xorw	%dx, %dx
+	call	pci_set_mem_access
+
+	/* Write all ones to BAR */
+	xorl	%ecx, %ecx
+	decl	%ecx
+	call	pci_write_config_dword
+
+	/* Read back BAR */
+	call	pci_read_config_dword
+
+	/* Calculate size */
+	notl	%ecx
+	orb	$0x0f, %cl
+	incl	%ecx
+
+	/* Restore original value */
+	pushl	%ecx
+	movl	%eax, %ecx
+	call	pci_write_config_dword
+	popl	%ecx
+
+	/* Enable memory accesses */
+	movw	$PCI_COMMAND_MEM, %dx
+	call	pci_set_mem_access
+
+	/* Restore registers and return */
+	popw	%dx
+	ret
+	.size	pci_size_mem_bar_low, . - pci_size_mem_bar_low
+
+/* Read PCI config dword
+ *
+ * Parameters:
+ *   %bx : PCI bus:dev.fn
+ *   %di : PCI register number
+ * Returns:
+ *   %ecx : Dword value
+ */
+	.section ".text16.early", "awx", @progbits
+pci_read_config_dword:
+	/* Preserve registers */
+	pushl	%eax
+	pushl	%ebx
+	pushl	%edx
+
+	/* Issue INT 0x1a,b10a */
+	movw	$PCIBIOS_READ_CONFIG_DWORD, %ax
+	int	$0x1a
+
+	/* Restore registers and return */
+	popl	%edx
+	popl	%ebx
+	popl	%eax
+	ret
+	.size	pci_read_config_dword, . - pci_read_config_dword
+
+/* Write PCI config dword
+ *
+ * Parameters:
+ *   %bx : PCI bus:dev.fn
+ *   %di : PCI register number
+ *   %ecx : PCI BAR value
+ * Returns:
+ *   none
+ */
+	.section ".text16.early", "awx", @progbits
+pci_write_config_dword:
+	/* Preserve registers */
+	pushal
+
+	/* Issue INT 0x1a,b10d */
+	movw	$PCIBIOS_WRITE_CONFIG_DWORD, %ax
+	int	$0x1a
+
+	/* Restore registers and return */
+	popal
+	ret
+	.size	pci_write_config_dword, . - pci_write_config_dword
+
+/* Enable/disable memory access response in PCI command word
+ *
+ * Parameters:
+ *   %bx : PCI bus:dev.fn
+ *   %dx : PCI_COMMAND_MEM, or zero
+ * Returns:
+ *   none
+ */
+	.section ".text16.early", "awx", @progbits
+pci_set_mem_access:
+	/* Preserve registers */
+	pushal
+
+	/* Read current value of command register */
+	pushw	%bx
+	pushw	%dx
+	movw	$PCI_COMMAND, %di
+	movw	$PCIBIOS_READ_CONFIG_WORD, %ax
+	int	$0x1a
+	popw	%dx
+	popw	%bx
+
+	/* Set memory access enable as appropriate */
+	andw	$~PCI_COMMAND_MEM, %cx
+	orw	%dx, %cx
+
+	/* Write new value of command register */
+	movw	$PCIBIOS_WRITE_CONFIG_WORD, %ax
+	int	$0x1a
+
+	/* Restore registers and return */
+	popal
+	ret
+	.size	pci_set_mem_access, . - pci_set_mem_access
+
+/* Image source area length (in dwords)
+ *
+ */
+	.section ".prefix", "ax", @progbits
+image_source_len_dword:
+	.long	0
+	.size	image_source_len_dword, . - image_source_len_dword
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDL"
+	.long	image_source_len_dword
+	.long	4
+	.long	0
+	.previous
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nbiprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
new file mode 100644
index 0000000..20d224d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
@@ -0,0 +1,78 @@
+	.text
+	.arch i386
+	.code16
+	.section ".prefix", "ax", @progbits
+	.org 0
+
+nbi_header:
+	
+/*****************************************************************************
+ * NBI file header
+ *****************************************************************************
+ */
+file_header:
+	.long	0x1b031336	/* Signature */
+	.byte	0x04		/* 16 bytes header, no vendor info */
+	.byte	0
+	.byte	0
+	.byte	0		/* No flags */
+	.word	0x0000, 0x07c0	/* Load header to 0x07c0:0x0000 */
+	.word	_nbi_start, 0x07c0	/* Start execution at 0x07c0:entry */
+	.size	file_header, . - file_header
+
+/*****************************************************************************
+ * NBI segment header
+ *****************************************************************************
+ */
+segment_header:
+	.byte	0x04		/* 16 bytes header, no vendor info */
+	.byte	0
+	.byte	0
+	.byte	0x04		/* Last segment */
+	.long	0x00007e00
+imglen:	.long	-512
+memlen:	.long	-512
+	.size	segment_header, . - segment_header
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDL"
+	.long	imglen
+	.long	1
+	.long	0
+	.ascii	"ADDL"
+	.long	memlen
+	.long	1
+	.long	0
+	.previous
+
+/*****************************************************************************
+ * NBI entry point
+ *****************************************************************************
+ */
+	.globl	_nbi_start
+_nbi_start:
+	/* Install iPXE */
+	call	install
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Reboot system */
+	int $0x19
+
+	.previous
+	.size	_nbi_start, . - _nbi_start
+
+nbi_header_end:
+	.org 512
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nullprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nullprefix.S
new file mode 100644
index 0000000..032d41e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/nullprefix.S
@@ -0,0 +1,13 @@
+	.org	0
+	.text
+	.arch i386
+
+	.section ".prefix", "ax", @progbits
+	.code16
+_prefix:
+
+	.section ".text16", "ax", @progbits
+prefix_exit:
+
+prefix_exit_end:
+	.previous
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/pxeprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
new file mode 100644
index 0000000..b7468cd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
@@ -0,0 +1,763 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define PXENV_UNDI_SHUTDOWN		0x0005
+#define	PXENV_UNDI_GET_NIC_TYPE		0x0012
+#define PXENV_UNDI_GET_IFACE_INFO	0x0013
+#define	PXENV_STOP_UNDI			0x0015
+#define PXENV_UNLOAD_STACK		0x0070
+
+#define PXE_HACK_EB54			0x0001
+
+	.text
+	.arch i386
+	.org 0
+	.code16
+
+#include <undi.h>
+
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
+#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
+
+/*****************************************************************************
+ * Entry point:	set operating context, print welcome message
+ *****************************************************************************
+ */
+	.section ".prefix", "ax", @progbits
+	.globl	_pxe_start
+_pxe_start:
+	jmp	$0x7c0, $1f
+1:
+	/* Preserve registers for possible return to PXE */
+	pushfl
+	pushal
+	pushw	%gs
+	pushw	%fs
+	pushw	%es
+	pushw	%ds
+
+	/* Store magic word on PXE stack and remember PXE %ss:esp */
+	pushl	$STACK_MAGIC
+	movw	%ss, %cs:pxe_ss
+	movl	%esp, %cs:pxe_esp
+
+	/* Set up segments */
+	movw	%cs, %ax
+	movw	%ax, %ds
+	movw	$0x40, %ax		/* BIOS data segment access */
+	movw	%ax, %fs
+	/* Set up stack just below 0x7c00 */
+	xorw	%ax, %ax
+	movw	%ax, %ss
+	movl	$0x7c00, %esp
+	/* Clear direction flag, for the sake of sanity */
+	cld
+	/* Print welcome message */
+	movw	$10f, %si
+	xorw	%di, %di
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"PXE->EB:"
+	.previous
+
+/*****************************************************************************
+ * Find us a usable !PXE or PXENV+ entry point
+ *****************************************************************************
+ */
+detect_pxe:
+	/* Plan A: !PXE pointer from the stack */
+	lgsl	pxe_esp, %ebp		/* %gs:%bp -> original stack */
+	lesw	%gs:52(%bp), %bx
+	call	is_valid_ppxe
+	je	have_ppxe
+
+	/* Plan B: PXENV+ pointer from initial ES:BX */
+	movw	%gs:32(%bp),%bx
+	movw	%gs:8(%bp),%es
+	call	is_valid_pxenv
+	je	have_pxenv
+
+	/* Plan C: PXENV+ structure via INT 1Ah */
+	movw	$0x5650, %ax
+	int	$0x1a
+	jc	1f
+	cmpw	$0x564e, %ax
+	jne	1f
+	call	is_valid_pxenv
+	je	have_pxenv
+1:
+	/* Plan D: scan base memory for !PXE */
+	call	memory_scan_ppxe
+	je	have_ppxe
+
+	/* Plan E: scan base memory for PXENV+ */
+	call	memory_scan_pxenv
+	jne	stack_not_found
+	
+have_pxenv:
+	movw	%bx, pxenv_offset
+	movw	%es, pxenv_segment
+
+	cmpw	$0x201, %es:6(%bx)	/* API version >= 2.01 */
+	jb	1f
+	cmpb	$0x2c, %es:8(%bx)	/* ... and structure long enough */
+	jb	2f
+
+	lesw	%es:0x28(%bx), %bx	/* Find !PXE from PXENV+ */
+	call	is_valid_ppxe
+	je	have_ppxe
+2:
+	call	memory_scan_ppxe	/* We are *supposed* to have !PXE... */
+	je	have_ppxe
+1:
+	lesw	pxenv_segoff, %bx	/* Nope, we're stuck with PXENV+ */
+
+	/* Record entry point and UNDI segments */
+	pushl	%es:0x0a(%bx)		/* Entry point */
+	pushw	%es:0x24(%bx)		/* UNDI code segment */
+	pushw	%es:0x26(%bx)		/* UNDI code size */
+	pushw	%es:0x20(%bx)		/* UNDI data segment */
+	pushw	%es:0x22(%bx)		/* UNDI data size */
+
+	/* Print "PXENV+ at <address>" */
+	movw	$10f, %si
+	jmp	check_have_stack
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" PXENV+ at "
+	.previous
+
+have_ppxe:
+	movw	%bx, ppxe_offset
+	movw	%es, ppxe_segment
+	
+	pushl	%es:0x10(%bx)		/* Entry point */
+	pushw	%es:0x30(%bx)		/* UNDI code segment */
+	pushw	%es:0x36(%bx)		/* UNDI code size */
+	pushw	%es:0x28(%bx)		/* UNDI data segment */
+	pushw	%es:0x2e(%bx)		/* UNDI data size */
+
+	/* Print "!PXE at <address>" */
+	movw	$10f, %si
+	jmp	check_have_stack
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" !PXE at "
+	.previous
+
+is_valid_ppxe:
+	cmpl	$0x45585021, %es:(%bx)
+	jne	1f
+	movzbw	%es:4(%bx), %cx
+	cmpw	$0x58, %cx
+	jae	is_valid_checksum
+1:
+	ret
+	
+is_valid_pxenv:
+	cmpl	$0x4e455850, %es:(%bx)
+	jne	1b
+	cmpw	$0x2b56, %es:4(%bx)
+	jne	1b
+	movzbw	%es:8(%bx), %cx
+	cmpw	$0x28, %cx
+	jb	1b
+	
+is_valid_checksum:
+	pushw	%ax
+	movw	%bx, %si
+	xorw	%ax, %ax
+2:
+	es lodsb
+	addb	%al, %ah
+	loopw	2b
+	popw	%ax
+	ret
+
+memory_scan_ppxe:
+	movw	$is_valid_ppxe, %dx
+	jmp	memory_scan_common
+
+memory_scan_pxenv:
+	movw	$is_valid_pxenv, %dx
+
+memory_scan_common:
+	movw	%fs:(0x13), %ax
+	shlw	$6, %ax
+	decw	%ax
+1:	incw	%ax
+	cmpw	$( 0xa000 - 1 ), %ax
+	ja	2f
+	movw	%ax, %es
+	xorw	%bx, %bx
+	call	*%dx
+	jne	1b
+2:	ret
+	
+/*****************************************************************************
+ * Sanity check: we must have an entry point
+ *****************************************************************************
+ */
+check_have_stack:
+	/* Save common values pushed onto the stack */
+	popl	undi_data_segoff
+	popl	undi_code_segoff
+	popl	entry_segoff
+
+	/* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */
+	call	print_message
+	call	print_segoff
+	movb	$( ',' ), %al
+	call	print_character
+
+	/* Check for entry point */
+	movl	entry_segoff, %eax
+	testl	%eax, %eax
+	jnz	99f
+	/* No entry point: print message and skip everything else */
+stack_not_found:
+	movw	$10f, %si
+	call	print_message
+	jmp	finished
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" No PXE stack found!\n"
+	.previous
+99:	
+
+/*****************************************************************************
+ * Calculate base memory usage by UNDI
+ *****************************************************************************
+ */
+find_undi_basemem_usage:
+	movw	undi_code_segment, %ax
+	movw	undi_code_size, %bx
+	movw	undi_data_segment, %cx
+	movw	undi_data_size, %dx
+	cmpw	%ax, %cx
+	ja	1f
+	xchgw	%ax, %cx
+	xchgw	%bx, %dx
+1:	/* %ax:%bx now describes the lower region, %cx:%dx the higher */
+	shrw	$6, %ax			/* Round down to nearest kB */
+	movw	%ax, undi_fbms_start
+	addw	$0x0f, %dx		/* Round up to next segment */
+	shrw	$4, %dx
+	addw	%dx, %cx
+	addw	$((1024 / 16) - 1), %cx	/* Round up to next kB */
+	shrw	$6, %cx
+	movw	%cx, undi_fbms_end
+
+/*****************************************************************************
+ * Print information about detected PXE stack
+ *****************************************************************************
+ */
+print_structure_information:
+	/* Print entry point */
+	movw	$10f, %si
+	call	print_message
+	les	entry_segoff, %bx
+	call	print_segoff
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" entry point at "
+	.previous
+	/* Print UNDI code segment */
+	movw	$10f, %si
+	call	print_message
+	les	undi_code_segoff, %bx
+	call	print_segoff
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"\n         UNDI code segment "
+	.previous
+	/* Print UNDI data segment */
+	movw	$10f, %si
+	call	print_message
+	les	undi_data_segoff, %bx
+	call	print_segoff
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	", data segment "
+	.previous
+	/* Print UNDI memory usage */
+	movw	$10f, %si
+	call	print_message
+	movw	undi_fbms_start, %ax
+	call	print_word
+	movb	$( '-' ), %al
+	call	print_character
+	movw	undi_fbms_end, %ax
+	call	print_word
+	movw	$20f, %si
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" ("
+20:	.asciz	"kB)\n"
+	.previous
+
+/*****************************************************************************
+ * Determine physical device
+ *****************************************************************************
+ */
+get_physical_device:
+	/* Issue PXENV_UNDI_GET_NIC_TYPE */
+	movw	$PXENV_UNDI_GET_NIC_TYPE, %bx
+	call	pxe_call
+	jnc	1f
+	call	print_pxe_error
+	jmp	no_physical_device
+1:	/* Determine physical device type */
+	movb	( pxe_parameter_structure + 0x02 ), %al
+	cmpb	$2, %al
+	je	pci_physical_device
+	jmp	no_physical_device
+
+pci_physical_device:
+	/* Record PCI bus:dev.fn and vendor/device IDs */
+	movl	( pxe_parameter_structure + 0x03 ), %eax
+	movl	%eax, pci_vendor
+	movw	( pxe_parameter_structure + 0x0b ), %ax
+	movw	%ax, pci_busdevfn
+	movw	$10f, %si
+	call	print_message
+	call	print_pci_busdevfn
+	jmp	99f
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"         UNDI device is PCI "
+	.previous
+
+no_physical_device:
+	/* No device found, or device type not understood */
+	movw	$10f, %si
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"         Unable to determine UNDI physical device"
+	.previous
+
+99:
+
+/*****************************************************************************
+ * Determine interface type
+ *****************************************************************************
+ */
+get_iface_type:
+	/* Issue PXENV_UNDI_GET_IFACE_INFO */
+	movw	$PXENV_UNDI_GET_IFACE_INFO, %bx
+	call	pxe_call
+	jnc	1f
+	call	print_pxe_error
+	jmp	99f
+1:	/* Print interface type */
+	movw	$10f, %si
+	call	print_message
+	leaw	( pxe_parameter_structure + 0x02 ), %si
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	", type "
+	.previous
+	/* Check for "Etherboot" interface type */
+	cmpl	$EB_MAGIC_1, ( pxe_parameter_structure + 0x02 )
+	jne	99f
+	cmpl	$EB_MAGIC_2, ( pxe_parameter_structure + 0x06 )
+	jne	99f
+	movw	$10f, %si
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	" (workaround enabled)"
+	.previous
+	/* Flag Etherboot workarounds as required */
+	orw	$PXE_HACK_EB54, pxe_hacks
+
+99:	movb	$0x0a, %al
+	call	print_character
+
+/*****************************************************************************
+ * Leave NIC in a safe state
+ *****************************************************************************
+ */
+#ifndef PXELOADER_KEEP_PXE
+shutdown_nic:
+	/* Issue PXENV_UNDI_SHUTDOWN */
+	movw	$PXENV_UNDI_SHUTDOWN, %bx
+	call	pxe_call
+	jnc	1f
+	call	print_pxe_error
+1:
+unload_base_code:
+	/* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so
+	 * we must not issue this call if the underlying stack is
+	 * Etherboot and we were not intending to issue a PXENV_STOP_UNDI.
+	 */
+#ifdef PXELOADER_KEEP_UNDI
+	testw	$PXE_HACK_EB54, pxe_hacks
+	jnz	99f
+#endif /* PXELOADER_KEEP_UNDI */
+	/* Issue PXENV_UNLOAD_STACK */
+	movw	$PXENV_UNLOAD_STACK, %bx
+	call	pxe_call
+	jnc	1f
+	call	print_pxe_error
+	jmp	99f
+1:	/* Free base memory used by PXE base code */
+	movw	undi_fbms_start, %ax
+	movw	%fs:(0x13), %bx
+	call	free_basemem
+99:
+	andw	$~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
+#endif /* PXELOADER_KEEP_PXE */
+
+/*****************************************************************************
+ * Unload UNDI driver
+ *****************************************************************************
+ */
+#ifndef PXELOADER_KEEP_UNDI
+unload_undi:
+	/* Issue PXENV_STOP_UNDI */
+	movw	$PXENV_STOP_UNDI, %bx
+	call	pxe_call
+	jnc	1f
+	call	print_pxe_error
+	jmp	99f
+1:	/* Free base memory used by UNDI */
+	movw	undi_fbms_end, %ax
+	movw	undi_fbms_start, %bx
+	call	free_basemem
+	/* Clear UNDI_FL_STARTED */
+	andw	$~UNDI_FL_STARTED, flags
+99:	
+#endif /* PXELOADER_KEEP_UNDI */
+
+/*****************************************************************************
+ * Print remaining free base memory
+ *****************************************************************************
+ */
+print_free_basemem:
+	movw	$10f, %si
+	call	print_message
+	movw	%fs:(0x13), %ax
+	call	print_word
+	movw	$20f, %si
+	call	print_message
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"         "
+20:	.asciz	"kB free base memory after PXE unload\n"
+	.previous
+	
+/*****************************************************************************
+ * Exit point
+ *****************************************************************************
+ */	
+finished:
+	jmp	run_ipxe
+
+/*****************************************************************************
+ * Subroutine: print segment:offset address
+ *
+ * Parameters:
+ *   %es:%bx : segment:offset address to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+print_segoff:
+	/* Preserve registers */
+	pushw	%ax
+	/* Print "<segment>:offset" */
+	movw	%es, %ax
+	call	print_hex_word
+	movb	$( ':' ), %al
+	call	print_character
+	movw	%bx, %ax
+	call	print_hex_word
+	/* Restore registers and return */
+	popw	%ax
+	ret
+
+/*****************************************************************************
+ * Subroutine: print decimal word
+ *
+ * Parameters:
+ *   %ax : word to print
+ *   %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ *   %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+print_word:
+	/* Preserve registers */
+	pushw	%ax
+	pushw	%bx
+	pushw	%cx
+	pushw	%dx
+	/* Build up digit sequence on stack */
+	movw	$10, %bx
+	xorw	%cx, %cx
+1:	xorw	%dx, %dx
+	divw	%bx, %ax
+	pushw	%dx
+	incw	%cx
+	testw	%ax, %ax
+	jnz	1b
+	/* Print digit sequence */
+1:	popw	%ax
+	call	print_hex_nibble
+	loop	1b
+	/* Restore registers and return */
+	popw	%dx
+	popw	%cx
+	popw	%bx
+	popw	%ax
+	ret
+	
+/*****************************************************************************
+ * Subroutine: zero 1kB block of base memory
+ *
+ * Parameters:
+ *   %bx : block to zero (in kB)
+ * Returns:
+ *   Nothing
+ *****************************************************************************
+ */
+zero_kb:
+	/* Preserve registers */
+	pushw	%ax
+	pushw	%cx
+	pushw	%di
+	pushw	%es
+	/* Zero block */
+	movw	%bx, %ax
+	shlw	$6, %ax
+	movw	%ax, %es
+	movw	$0x400, %cx
+	xorw	%di, %di
+	xorw	%ax, %ax
+	rep stosb
+	/* Restore registers and return */
+	popw	%es
+	popw	%di
+	popw	%cx
+	popw	%ax
+	ret
+	
+/*****************************************************************************
+ * Subroutine: free and zero base memory
+ *
+ * Parameters:
+ *   %ax : Desired new free base memory counter (in kB)
+ *   %bx : Expected current free base memory counter (in kB)
+ *   %fs : BIOS data segment (0x40)
+ * Returns:
+ *   None
+ *
+ * The base memory from %bx kB to %ax kB is unconditionally zeroed.
+ * It will be freed if and only if the expected current free base
+ * memory counter (%bx) matches the actual current free base memory
+ * counter in 0x40:0x13; if this does not match then the memory will
+ * be leaked.
+ *****************************************************************************
+ */
+free_basemem:
+	/* Zero base memory */
+	pushw	%bx
+1:	cmpw	%bx, %ax
+	je	2f
+	call	zero_kb
+	incw	%bx
+	jmp	1b
+2:	popw	%bx
+	/* Free base memory */
+	cmpw	%fs:(0x13), %bx		/* Update FBMS only if "old" value  */
+	jne	1f			/* is correct			    */
+1:	movw	%ax, %fs:(0x13)
+	ret
+
+/*****************************************************************************
+ * Subroutine: make a PXE API call.  Works with either !PXE or PXENV+ API.
+ *
+ * Parameters:
+ *   %bx : PXE API call number
+ *   %ds:pxe_parameter_structure : Parameters for PXE API call
+ * Returns:
+ *   %ax : PXE status code (not exit code)
+ *   CF set if %ax is non-zero
+ *****************************************************************************
+ */
+pxe_call:
+	/* Preserve registers */
+	pushw	%di
+	pushw	%es
+	/* Set up registers for PXENV+ API.  %bx already set up */
+	pushw	%ds
+	popw	%es
+	movw	$pxe_parameter_structure, %di
+	/* Set up stack for !PXE API */
+	pushw   %es
+	pushw	%di
+	pushw	%bx
+	/* Make the API call */
+	lcall	*entry_segoff
+	/* Reset the stack */
+	addw	$6, %sp
+	movw	pxe_parameter_structure, %ax
+	clc
+	testw	%ax, %ax
+	jz	1f
+	stc
+1:	/* Clear direction flag, for the sake of sanity */
+	cld
+	/* Restore registers and return */
+	popw	%es
+	popw	%di
+	ret
+
+/*****************************************************************************
+ * Subroutine: print PXE API call error message
+ *
+ * Parameters:
+ *   %ax : PXE status code
+ *   %bx : PXE API call number
+ * Returns:
+ *   Nothing
+ *****************************************************************************
+ */
+print_pxe_error:
+	pushw	%si
+	movw	$10f, %si
+	call	print_message
+	xchgw	%ax, %bx
+	call	print_hex_word
+	movw	$20f, %si
+	call	print_message
+	xchgw	%ax, %bx
+	call	print_hex_word
+	movw	$30f, %si
+	call	print_message
+	popw	%si
+	ret
+	.section ".prefix.data", "aw", @progbits
+10:	.asciz	"         UNDI API call "
+20:	.asciz	" failed: status code "
+30:	.asciz	"\n"
+	.previous
+
+/*****************************************************************************
+ * PXE data structures
+ *****************************************************************************
+ */
+	.section ".prefix.data"
+
+pxe_esp:		.long 0
+pxe_ss:			.word 0
+
+pxe_parameter_structure: .fill 64
+
+undi_code_segoff:
+undi_code_size:		.word 0
+undi_code_segment:	.word 0
+
+undi_data_segoff:
+undi_data_size:		.word 0
+undi_data_segment:	.word 0
+
+pxe_hacks:		.word 0
+
+/* The following fields are part of a struct undi_device */
+
+undi_device:
+
+pxenv_segoff:
+pxenv_offset:		.word 0
+pxenv_segment:		.word 0
+
+ppxe_segoff:
+ppxe_offset:		.word 0
+ppxe_segment:		.word 0
+	
+entry_segoff:
+entry_offset:		.word 0
+entry_segment:		.word 0
+
+undi_fbms_start:	.word 0
+undi_fbms_end:		.word 0
+
+pci_busdevfn:		.word UNDI_NO_PCI_BUSDEVFN
+isapnp_csn:		.word UNDI_NO_ISAPNP_CSN
+isapnp_read_port:	.word UNDI_NO_ISAPNP_READ_PORT
+
+pci_vendor:		.word 0
+pci_device:		.word 0
+flags:
+	.word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
+
+	.equ undi_device_size, ( . - undi_device )
+
+/*****************************************************************************
+ * Run iPXE main code
+ *****************************************************************************
+ */
+	.section ".prefix"
+run_ipxe:
+	/* Install iPXE */
+	call	install
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+#ifdef PXELOADER_KEEP_UNDI
+	/* Copy our undi_device structure to the preloaded_undi variable */
+	movw	%bx, %es
+	movw	$preloaded_undi, %di
+	movw	$undi_device, %si
+	movw	$undi_device_size, %cx
+	rep movsb
+#endif
+
+	/* Retrieve PXE %ss:esp */
+	movw	pxe_ss,	%di
+	movl	pxe_esp, %ebp
+
+	/* Jump to .text16 segment with %ds pointing to .data16 */
+	movw	%bx, %ds
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "ax", @progbits
+1:
+	/* Update the exit hook */
+	movw	%cs,pxe_exit_hook+2
+	push	%ax
+	mov	$2f,%ax
+	mov	%ax,pxe_exit_hook
+	pop	%ax
+
+	/* Run main program */
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Restore PXE stack */
+	movw	%di, %ss
+	movl	%ebp, %esp
+
+	/* Jump to hook if applicable */
+	ljmpw	*pxe_exit_hook
+
+2:	/* Check PXE stack magic */
+	popl	%eax
+	cmpl	$STACK_MAGIC, %eax
+	jne	1f
+
+	/* PXE stack OK: return to caller */
+	popw	%ds
+	popw	%es
+	popw	%fs
+	popw	%gs
+	popal
+	popfl
+	xorw	%ax, %ax	/* Return success */
+	lret
+
+1:	/* PXE stack corrupt or removed: use INT 18 */
+	int	$0x18
+	.previous
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/romprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/romprefix.S
new file mode 100644
index 0000000..dd602dd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/romprefix.S
@@ -0,0 +1,812 @@
+/* At entry, the processor is in 16 bit real mode and the code is being
+ * executed from an address it was not linked to. Code must be pic and
+ * 32 bit sensitive until things are fixed up.
+ *
+ * Also be very careful as the stack is at the rear end of the interrupt
+ * table so using a noticeable amount of stack space is a no-no.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#include <config/general.h>
+
+#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
+#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
+#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+#define PMM_ALLOCATE 0x0000
+#define PMM_FIND 0x0001
+#define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
+			  ( ( 'E' - 'A' + 1 ) << 21 ) + \
+			  ( ( 'N' - 'A' + 1 ) << 16 ) )
+#define PMM_HANDLE_BASE_IMAGE_SOURCE \
+	( PMM_HANDLE_BASE | 0x00001000 )
+#define PMM_HANDLE_BASE_DECOMPRESS_TO \
+	( PMM_HANDLE_BASE | 0x00002000 )
+
+/* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
+ * config.h, but converted to a number of (18Hz) timer ticks, and
+ * doubled to allow for BIOSes that switch video modes immediately
+ * beforehand, so rendering the message almost invisible to the user.
+ */
+#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
+
+/* Allow payload to be excluded from ROM size
+ */
+#if ROMPREFIX_EXCLUDE_PAYLOAD
+#define	ZINFO_TYPE_ADxB "ADHB"
+#define	ZINFO_TYPE_ADxW "ADHW"
+#else
+#define	ZINFO_TYPE_ADxB "ADDB"
+#define	ZINFO_TYPE_ADxW "ADDW"
+#endif
+
+	.text
+	.code16
+	.arch i386
+	.section ".prefix", "ax", @progbits
+	.globl	_rom_start
+_rom_start:
+	
+	.org	0x00
+romheader:
+	.word	0xAA55			/* BIOS extension signature */
+romheader_size:	.byte 0			/* Size in 512-byte blocks */
+	jmp	init			/* Initialisation vector */
+checksum:
+	.byte	0
+	.org	0x16
+	.word	undiheader
+	.org	0x18
+	.word	pciheader
+	.org	0x1a
+	.word	pnpheader
+	.size romheader, . - romheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	ZINFO_TYPE_ADxB
+	.long	romheader_size
+	.long	512
+	.long	0
+	.previous
+
+build_id:
+	.long	_build_id		/* Randomly-generated build ID */
+
+pciheader:
+	.ascii	"PCIR"			/* Signature */
+	.word	pci_vendor_id		/* Vendor identification */ 
+	.word	pci_device_id		/* Device identification */
+	.word	0x0000			/* Device list pointer */
+	.word	pciheader_len		/* PCI data structure length */
+	.byte	0x03			/* PCI data structure revision */
+	.byte	0x02, 0x00, 0x00	/* Class code */
+pciheader_image_length:
+	.word	0			/* Image length */
+	.word	0x0001			/* Revision level */
+	.byte	0x00			/* Code type */
+	.byte	0x80			/* Last image indicator */
+pciheader_runtime_length:
+	.word	0			/* Maximum run-time image length */
+	.word	0x0000			/* Configuration utility code header */
+	.word	0x0000			/* DMTF CLP entry point */
+	.equ pciheader_len, . - pciheader
+	.size pciheader, . - pciheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	ZINFO_TYPE_ADxW
+	.long	pciheader_image_length
+	.long	512
+	.long	0
+	.ascii	ZINFO_TYPE_ADxW
+	.long	pciheader_runtime_length
+	.long	512
+	.long	0
+	.previous
+
+pnpheader:
+	.ascii	"$PnP"			/* Signature */
+	.byte	0x01			/* Structure revision */
+	.byte	( pnpheader_len	/ 16 )	/* Length (in 16 byte increments) */
+	.word	0x0000			/* Offset of next header */
+	.byte	0x00			/* Reserved */
+	.byte	0x00			/* Checksum */
+	.long	0x00000000		/* Device identifier */
+	.word	mfgstr			/* Manufacturer string */
+	.word	prodstr			/* Product name */
+	.byte	0x02			/* Device base type code */
+	.byte	0x00			/* Device sub-type code */
+	.byte	0x00			/* Device interface type code */
+	.byte	0xf4			/* Device indicator */
+	.word	0x0000			/* Boot connection vector */
+	.word	0x0000			/* Disconnect vector */
+	.word	bev_entry		/* Boot execution vector */
+	.word	0x0000			/* Reserved */
+	.word	0x0000			/* Static resource information vector*/
+	.equ pnpheader_len, . - pnpheader
+	.size pnpheader, . - pnpheader
+
+/* Manufacturer string */
+mfgstr:
+	.asciz	"http://ipxe.org"
+	.size mfgstr, . - mfgstr
+
+/* Product string
+ *
+ * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
+ * initialisation time, it will be filled in to include the PCI
+ * bus:dev.fn number of the card as well.
+ */
+prodstr:
+	.ascii	PRODUCT_SHORT_NAME
+prodstr_separator:
+	.byte	0
+	.ascii	"(PCI "
+prodstr_pci_id:
+	.asciz	"xx:xx.x)"		/* Filled in by init code */
+	.size prodstr, . - prodstr
+
+	.globl	undiheader	
+	.weak	undiloader
+undiheader:
+	.ascii	"UNDI"			/* Signature */
+	.byte	undiheader_len		/* Length of structure */
+	.byte	0			/* Checksum */
+	.byte	0			/* Structure revision */
+	.byte	0,1,2			/* PXE version: 2.1.0 */
+	.word	undiloader		/* Offset to loader routine */
+	.word	_data16_memsz		/* Stack segment size */
+	.word	_data16_memsz		/* Data segment size */
+	.word	_text16_memsz		/* Code segment size */
+	.ascii	"PCIR"			/* Bus type */
+	.equ undiheader_len, . - undiheader
+	.size undiheader, . - undiheader
+
+/* Initialisation (called once during POST)
+ *
+ * Determine whether or not this is a PnP system via a signature
+ * check.  If it is PnP, return to the PnP BIOS indicating that we are
+ * a boot-capable device; the BIOS will call our boot execution vector
+ * if it wants to boot us.  If it is not PnP, hook INT 19.
+ */
+init:
+	/* Preserve registers, clear direction flag, set %ds=%cs */
+	pushaw
+	pushw	%ds
+	pushw	%es
+	pushw	%fs
+	pushw	%gs
+	cld
+	pushw	%cs
+	popw	%ds
+
+	/* Shuffle some registers around.  We need %di available for
+	 * the print_xxx functions, and in a register that's
+	 * addressable from %es, so shuffle as follows:
+	 *
+	 *    %di (pointer to PnP structure) => %bx
+	 *    %bx (runtime segment address, for PCI 3.0) => %gs
+	 */
+	movw	%bx, %gs
+	movw	%di, %bx
+
+	/* Store PCI bus:dev.fn address */
+	movw	%ax, init_pci_busdevfn
+
+	/* Print message as early as possible */
+	movw	$init_message, %si
+	xorw	%di, %di
+	call	print_message
+	call	print_pci_busdevfn
+
+	/* Fill in product name string, if possible */
+	movw	$prodstr_pci_id, %di
+	call	print_pci_busdevfn
+	movb	$( ' ' ), prodstr_separator
+
+	/* Print segment address */
+	movb	$( ' ' ), %al
+	xorw	%di, %di
+	call	print_character
+	movw	%cs, %ax
+	call	print_hex_word
+
+	/* Check for PCI BIOS version */
+	pushl	%ebx
+	pushl	%edx
+	pushl	%edi
+	stc
+	movw	$0xb101, %ax
+	int	$0x1a
+	jc	no_pci3
+	cmpl	$PCI_SIGNATURE, %edx
+	jne	no_pci3
+	testb	%ah, %ah
+	jnz	no_pci3
+	movw	$init_message_pci, %si
+	xorw	%di, %di
+	call	print_message
+	movb	%bh, %al
+	call	print_hex_nibble
+	movb	$( '.' ), %al
+	call	print_character
+	movb	%bl, %al
+	call	print_hex_byte
+	cmpb	$3, %bh
+	jb	no_pci3
+	/* PCI >=3.0: leave %gs as-is if sane */
+	movw	%gs, %ax
+	cmpw	$0xa000, %ax	/* Insane if %gs < 0xa000 */
+	jb	pci3_insane
+	movw	%cs, %bx	/* Sane if %cs == %gs */
+	cmpw	%bx, %ax
+	je	1f
+	movzbw	romheader_size, %cx /* Sane if %cs+len <= %gs */
+	shlw	$5, %cx
+	addw	%cx, %bx
+	cmpw	%bx, %ax
+	jae	1f
+	movw	%cs, %bx	/* Sane if %gs+len <= %cs */
+	addw	%cx, %ax
+	cmpw	%bx, %ax
+	jbe	1f
+pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
+	movb	$( '!' ), %al
+	call	print_character
+	movw	%gs, %ax
+	call	print_hex_word
+no_pci3:
+	/* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
+	pushw	%cs
+	popw	%gs
+1:	popl	%edi
+	popl	%edx
+	popl	%ebx
+
+	/* Check for PnP BIOS.  Although %es:di should point to the
+	 * PnP BIOS signature on entry, some BIOSes fail to do this.
+	 */
+	movw	$( 0xf000 - 1 ), %bx
+pnp_scan:
+	incw	%bx
+	jz	no_pnp
+	movw	%bx, %es
+	cmpl	$PNP_SIGNATURE, %es:0
+	jne	pnp_scan
+	xorw	%dx, %dx
+	xorw	%si, %si
+	movzbw	%es:5, %cx
+1:	es lodsb
+	addb	%al, %dl
+	loop	1b
+	jnz	pnp_scan
+	/* Is PnP: print PnP message */
+	movw	$init_message_pnp, %si
+	xorw	%di, %di
+	call	print_message
+	jmp	pnp_done
+no_pnp:	/* Not PnP-compliant - hook INT 19 */
+	movw	$init_message_int19, %si
+	xorw	%di, %di
+	call	print_message
+	xorw	%ax, %ax
+	movw	%ax, %es
+	pushl	%es:( 0x19 * 4 )
+	popl	orig_int19
+	pushw	%gs /* %gs contains runtime %cs */
+	pushw	$int19_entry
+	popl	%es:( 0x19 * 4 )
+pnp_done:
+
+	/* Check for PMM */
+	movw	$( 0xe000 - 1 ), %bx
+pmm_scan:
+	incw	%bx
+	jz	no_pmm
+	movw	%bx, %es
+	cmpl	$PMM_SIGNATURE, %es:0
+	jne	pmm_scan
+	xorw	%dx, %dx
+	xorw	%si, %si
+	movzbw	%es:5, %cx
+1:	es lodsb
+	addb	%al, %dl
+	loop	1b
+	jnz	pmm_scan
+	/* PMM found: print PMM message */
+	movw	$init_message_pmm, %si
+	xorw	%di, %di
+	call	print_message
+	/* We have PMM and so a 1kB stack: preserve whole registers */
+	pushal
+	/* Allocate image source PMM block */
+	movzwl	image_source_size, %ecx
+	shll	$5, %ecx
+	movl	$PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
+	movw	$get_pmm_image_source, %bp
+	call	get_pmm
+	movl	%esi, image_source
+	jc	1f
+	/* Copy ROM to image source PMM block */
+	pushw	%es
+	xorw	%ax, %ax
+	movw	%ax, %es
+	movl	%esi, %edi
+	xorl	%esi, %esi
+	movzbl	romheader_size, %ecx
+	shll	$9, %ecx
+	addr32 rep movsb	/* PMM presence implies flat real mode */
+	popw	%es
+	/* Shrink ROM */
+	movb	shrunk_rom_size, %al
+	movb	%al, romheader_size
+1:	/* Allocate decompression PMM block.  Round up the size to the
+	 * nearest 128kB and use the size within the PMM handle; this
+	 * allows the same decompression area to be shared between
+	 * multiple iPXE ROMs even with differing build IDs
+	 */
+	movl	$_textdata_memsz_pgh, %ecx
+	addl	$0x00001fff, %ecx
+	andl	$0xffffe000, %ecx
+	movl	%ecx, %ebx
+	shrw	$12, %bx
+	orl	$PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
+	movw	$get_pmm_decompress_to, %bp
+	call	get_pmm
+	movl	%esi, decompress_to
+	/* Restore registers */
+	popal
+no_pmm:
+
+	/* Update checksum */
+	xorw	%bx, %bx
+	xorw	%si, %si
+	movzbw	romheader_size, %cx
+	shlw	$9, %cx
+1:	lodsb
+	addb	%al, %bl
+	loop	1b
+	subb	%bl, checksum
+
+	/* Copy self to option ROM space.  Required for PCI3.0, which
+	 * loads us to a temporary location in low memory.  Will be a
+	 * no-op for lower PCI versions.
+	 */
+	movb	$( ' ' ), %al
+	xorw	%di, %di
+	call	print_character
+	movw	%gs, %ax
+	call	print_hex_word
+	movzbw	romheader_size, %cx
+	shlw	$9, %cx
+	movw	%ax, %es
+	xorw	%si, %si
+	xorw	%di, %di
+	cs rep	movsb
+
+	/* Prompt for POST-time shell */
+	movw	$init_message_prompt, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$prodstr, %si
+	call	print_message
+	movw	$init_message_dots, %si
+	call	print_message
+	/* Wait for Ctrl-B */
+	movw	$0xff02, %bx
+	call	wait_for_key
+	/* Clear prompt */
+	pushf
+	xorw	%di, %di
+	call	print_kill_line
+	movw	$init_message_done, %si
+	call	print_message
+	popf
+	jnz	2f
+	/* Ctrl-B was pressed: invoke iPXE.  The keypress will be
+	 * picked up by the initial shell prompt, and we will drop
+	 * into a shell.
+	 */
+	stc			/* Inhibit relocation */
+	pushw	%cs
+	call	exec
+2:
+	/* Restore registers */
+	popw	%gs
+	popw	%fs
+	popw	%es
+	popw	%ds
+	popaw
+
+	/* Indicate boot capability to PnP BIOS, if present */
+	movw	$0x20, %ax
+	lret
+	.size init, . - init
+
+/* Attempt to find or allocate PMM block
+ *
+ * Parameters:
+ *  %ecx : size of block to allocate, in paragraphs
+ *  %ebx : PMM handle base
+ *  %bp : routine to check acceptability of found blocks
+ *  %es:0000 : PMM structure
+ * Returns:
+ *  %ebx : PMM handle
+ *  %esi : allocated block address, or zero (with CF set) if allocation failed
+ */
+get_pmm:
+	/* Preserve registers */
+	pushl	%eax
+	pushw	%di
+	movw	$' ', %di
+get_pmm_find:
+	/* Try to find existing block */
+	pushl	%ebx		/* PMM handle */
+	pushw	$PMM_FIND
+	lcall	*%es:7
+	addw	$6, %sp
+	pushw	%dx
+	pushw	%ax
+	popl	%esi
+	testl	%esi, %esi
+	jz	get_pmm_allocate
+	/* Block found - check acceptability */
+	call	*%bp
+	jnc	get_pmm_done
+	/* Block not acceptable - increment handle and retry */
+	incl	%ebx
+	jmp	get_pmm_find
+get_pmm_allocate:
+	/* Block not found - try to allocate new block */
+	pushw	$0x0002		/* Extended memory */
+	pushl	%ebx		/* PMM handle */
+	pushl	%ecx		/* Length */
+	pushw	$PMM_ALLOCATE
+	lcall	*%es:7
+	addw	$12, %sp
+	pushw	%dx
+	pushw	%ax
+	popl	%esi
+	movw	$'+', %di	/* Indicate allocation attempt */
+	testl	%esi, %esi
+	jnz	get_pmm_done
+	stc
+get_pmm_done:
+	/* Print block address */
+	pushfw
+	movw	%di, %ax
+	xorw	%di, %di
+	call	print_character
+	movl	%esi, %eax
+	call	print_hex_dword
+	popfw
+	/* Restore registers and return */
+	popw	%di
+	popl	%eax
+	ret
+	.size	get_pmm, . - get_pmm
+
+	/* Check acceptability of image source block */
+get_pmm_image_source:
+	pushw	%es
+	xorw	%ax, %ax
+	movw	%ax, %es
+	movl	build_id, %eax
+	addr32 cmpl %es:build_id(%esi), %eax
+	je	1f
+	stc
+1:	popw	%es
+	ret
+	.size	get_pmm_image_source, . - get_pmm_image_source
+
+	/* Check acceptability of decompression block */
+get_pmm_decompress_to:
+	clc
+	ret
+	.size	get_pmm_decompress_to, . - get_pmm_decompress_to
+
+/*
+ * Note to hardware vendors:
+ *
+ * If you wish to brand this boot ROM, please do so by defining the
+ * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
+ *
+ * While nothing in the GPL prevents you from removing all references
+ * to iPXE or http://ipxe.org, we prefer you not to do so.
+ *
+ * If you have an OEM-mandated branding requirement that cannot be
+ * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
+ * please contact us.
+ *
+ * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
+ *   bypassing the spirit of this request! ]
+ */
+init_message:
+	.ascii	"\n"
+	.ascii	PRODUCT_NAME
+	.ascii	"\n"
+	.asciz	"iPXE (http://ipxe.org) "
+	.size	init_message, . - init_message
+init_message_pci:
+	.asciz	" PCI"
+	.size	init_message_pci, . - init_message_pci
+init_message_pnp:
+	.asciz	" PnP"
+	.size	init_message_pnp, . - init_message_pnp
+init_message_pmm:
+	.asciz	" PMM"
+	.size	init_message_pmm, . - init_message_pmm
+init_message_int19:
+	.asciz	" INT19"
+	.size	init_message_int19, . - init_message_int19
+init_message_prompt:
+	.asciz	"\nPress Ctrl-B to configure "
+	.size	init_message_prompt, . - init_message_prompt
+init_message_dots:
+	.asciz	"..."
+	.size	init_message_dots, . - init_message_dots
+init_message_done:
+	.asciz	"\n\n"
+	.size	init_message_done, . - init_message_done
+
+/* PCI bus:dev.fn
+ *
+ */
+init_pci_busdevfn:
+	.word	0xffff
+	.size	init_pci_busdevfn, . - init_pci_busdevfn
+
+/* Image source area
+ *
+ * May be either zero (indicating to use option ROM space as source),
+ * or within a PMM-allocated block.
+ */
+	.globl	image_source
+image_source:
+	.long	0
+	.size	image_source, . - image_source
+
+/* Image source size (in 512-byte sectors)
+ *
+ */
+image_source_size:
+	.word	0
+	.size	image_source_size, . - image_source_size
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDW"
+	.long	image_source_size
+	.long	512
+	.long	0
+	.previous
+
+/* Shrunk ROM size (in 512-byte sectors)
+ *
+ */
+shrunk_rom_size:
+	.byte	0
+	.size	shrunk_rom_size, . - shrunk_rom_size
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADHB"
+	.long	shrunk_rom_size
+	.long	512
+	.long	0
+	.previous
+
+/* Temporary decompression area
+ *
+ * May be either zero (indicating to use default decompression area in
+ * high memory), or within a PMM-allocated block.
+ */
+	.globl	decompress_to
+decompress_to:
+	.long	0
+	.size	decompress_to, . - decompress_to
+
+/* Boot Execution Vector entry point
+ *
+ * Called by the PnP BIOS when it wants to boot us.
+ */
+bev_entry:
+	clc			/* Allow relocation */
+	pushw	%cs
+	call	exec
+	lret
+	.size	bev_entry, . - bev_entry
+
+/* INT19 entry point
+ *
+ * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
+ * attempt to return via the original INT 19 vector (if we were able
+ * to store it).
+ */
+int19_entry:
+	pushw	%cs
+	popw	%ds
+	/* Prompt user to press B to boot */
+	movw	$int19_message_prompt, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$prodstr, %si
+	call	print_message
+	movw	$int19_message_dots, %si
+	call	print_message
+	movw	$0xdf4e, %bx
+	call	wait_for_key
+	pushf
+	xorw	%di, %di
+	call	print_kill_line
+	movw	$int19_message_done, %si
+	call	print_message
+	popf
+	jz	1f
+	/* Leave keypress in buffer and start iPXE.  The keypress will
+	 * cause the usual initial Ctrl-B prompt to be skipped.
+	 */
+	clc			/* Allow relocation */
+	pushw	%cs
+	call	exec
+1:	/* Try to call original INT 19 vector */
+	movl	%cs:orig_int19, %eax
+	testl	%eax, %eax
+	je	2f
+	ljmp	*%cs:orig_int19
+2:	/* No chained vector: issue INT 18 as a last resort */
+	int	$0x18
+	.size	int19_entry, . - int19_entry
+orig_int19:
+	.long	0
+	.size	orig_int19, . - orig_int19
+
+int19_message_prompt:
+	.asciz	"Press N to skip booting from "
+	.size	int19_message_prompt, . - int19_message_prompt
+int19_message_dots:
+	.asciz	"..."
+	.size	int19_message_dots, . - int19_message_dots
+int19_message_done:
+	.asciz	"\n\n"
+	.size	int19_message_done, . - int19_message_done
+	
+/* Execute as a boot device
+ *
+ */
+exec:	/* Set %ds = %cs */
+	pushw	%cs
+	popw	%ds
+
+	/* Preserve state of CF */
+	lahf
+
+	/* Print message as soon as possible */
+	movw	$prodstr, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$exec_message_pre_install, %si
+	call	print_message
+
+	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
+	pushl	$STACK_MAGIC
+	movw	%ss, %dx
+	movw	%sp, %bp
+
+	/* Obtain a reasonably-sized temporary stack */
+	xorw	%bx, %bx
+	movw	%bx, %ss
+	movw	$0x7c00, %sp
+
+	/* Install iPXE */
+	sahf
+	pushfw
+	call	alloc_basemem
+	popfw
+	movl	image_source, %esi
+	movl	decompress_to, %edi
+	call	install_prealloc
+
+	/* Print message indicating successful installation */
+	movw	$exec_message_post_install, %si
+	xorw	%di, %di
+	call	print_message
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:	/* Call main() */
+	pushl	$main
+	pushw	%cs
+	call	prot_call
+	popl	%ecx /* discard */
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Restore BIOS stack */
+	movw	%dx, %ss
+	movw	%bp, %sp
+
+	/* Check magic word on BIOS stack */
+	popl	%eax
+	cmpl	$STACK_MAGIC, %eax
+	jne	1f
+	/* BIOS stack OK: return to caller */
+	lret
+1:	/* BIOS stack corrupt: use INT 18 */
+	int	$0x18
+	.previous
+
+exec_message_pre_install:
+	.asciz	" starting execution..."
+	.size exec_message_pre_install, . - exec_message_pre_install
+exec_message_post_install:
+	.asciz	"ok\n"
+	.size exec_message_post_install, . - exec_message_post_install
+
+/* Wait for key press specified by %bl (masked by %bh)
+ *
+ * Used by init and INT19 code when prompting user.  If the specified
+ * key is pressed, it is left in the keyboard buffer.
+ *
+ * Returns with ZF set iff specified key is pressed.
+ */
+wait_for_key:
+	/* Preserve registers */
+	pushw	%cx
+	pushw	%ax
+1:	/* Empty the keyboard buffer before waiting for input */
+	movb	$0x01, %ah
+	int	$0x16
+	jz	2f
+	xorw	%ax, %ax
+	int	$0x16
+	jmp	1b
+2:	/* Wait for a key press */
+	movw	$ROM_BANNER_TIMEOUT, %cx
+3:	decw	%cx
+	js	99f		/* Exit with ZF clear */
+	/* Wait for timer tick to be updated */
+	call	wait_for_tick
+	/* Check to see if a key was pressed */
+	movb	$0x01, %ah
+	int	$0x16
+	jz	3b
+	/* Check to see if key was the specified key */
+	andb	%bh, %al
+	cmpb	%al, %bl
+	je	99f		/* Exit with ZF set */
+	/* Not the specified key: remove from buffer and stop waiting */
+	pushfw
+	xorw	%ax, %ax
+	int	$0x16
+	popfw			/* Exit with ZF clear */
+99:	/* Restore registers and return */
+	popw	%ax
+	popw	%cx
+	ret
+	.size wait_for_key, . - wait_for_key
+
+/* Wait for timer tick
+ *
+ * Used by wait_for_key
+ */
+wait_for_tick:
+	pushl	%eax
+	pushw	%fs
+	movw	$0x40, %ax
+	movw	%ax, %fs
+	movl	%fs:(0x6c), %eax
+1:	pushf
+	sti
+	hlt
+	popf
+	cmpl	%fs:(0x6c), %eax
+	je	1b
+	popw	%fs
+	popl	%eax
+	ret
+	.size wait_for_tick, . - wait_for_tick
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/undiloader.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/undiloader.S
new file mode 100644
index 0000000..951b5c1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/undiloader.S
@@ -0,0 +1,52 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.text
+	.code16
+	.arch i386
+	.section ".prefix", "ax", @progbits
+
+/* UNDI loader
+ *
+ * Called by an external program to load our PXE stack.
+ */
+	.globl	undiloader
+undiloader:
+	/* Save registers */
+	pushl	%esi
+	pushl	%edi
+	pushw	%ds
+	pushw	%es
+	pushw	%bx
+	/* ROM segment address to %ds */
+	pushw	%cs
+	popw	%ds
+	/* UNDI loader parameter structure address into %es:%di */
+	movw	%sp, %bx
+	movw	%ss:18(%bx), %di
+	movw	%ss:20(%bx), %es
+	/* Install to specified real-mode addresses */
+	pushw	%di
+	movw	%es:12(%di), %bx
+	movw	%es:14(%di), %ax
+	movl	image_source, %esi
+	movl	decompress_to, %edi
+	clc			/* Allow relocation */
+	call	install_prealloc
+	popw	%di
+	/* Call UNDI loader C code */
+	pushl	$pxe_loader_call
+	pushw	%cs
+	pushw	$1f
+	pushw	%ax
+	pushw	$prot_call
+	lret
+1:	popw	%bx	/* discard */
+	popw	%bx	/* discard */
+	/* Restore registers and return */
+	popw	%bx
+	popw	%es
+	popw	%ds
+	popl	%edi
+	popl	%esi
+	lret
+	.size undiloader, . - undiloader
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
new file mode 100644
index 0000000..f5724c1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
@@ -0,0 +1,184 @@
+/* 
+ * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Originally this code was part of ucl the data compression library
+ * for upx the ``Ultimate Packer of eXecutables''.
+ *
+ * - Converted to gas assembly, and refitted to work with etherboot.
+ *   Eric Biederman 20 Aug 2002
+ *
+ * - Structure modified to be a subroutine call rather than an
+ *   executable prefix.
+ *   Michael Brown 30 Mar 2004
+ *
+ * - Modified to be compilable as either 16-bit or 32-bit code.
+ *   Michael Brown 9 Mar 2005
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/****************************************************************************
+ * This file provides the decompress() and decompress16() functions
+ * which can be called in order to decompress an image compressed with
+ * the nrv2b utility in src/util.
+ *
+ * These functions are designed to be called by the prefix.  They are
+ * position-independent code.
+ *
+ * The same basic assembly code is used to compile both
+ * decompress() and decompress16().
+ ****************************************************************************
+ */
+
+	.text
+	.arch i386
+	.section ".prefix.lib", "ax", @progbits
+
+#ifdef CODE16
+/****************************************************************************
+ * decompress16 (real-mode near call, position independent)
+ *
+ * Decompress data in 16-bit mode
+ *
+ * Parameters (passed via registers):
+ *   %ds:%esi - Start of compressed input data
+ *   %es:%edi - Start of output buffer
+ * Returns:
+ *   %ds:%esi - End of compressed input data
+ *   %es:%edi - End of decompressed output data
+ *   All other registers are preserved
+ *
+ * NOTE: It would be possible to build a smaller version of the
+ * decompression code for -DKEEP_IT_REAL by using
+ *    #define REG(x) x
+ * to use 16-bit registers where possible.  This would impose limits
+ * that the compressed data size must be in the range [1,65533-%si]
+ * and the uncompressed data size must be in the range [1,65536-%di]
+ * (where %si and %di are the input values for those registers).  Note
+ * particularly that the lower limit is 1, not 0, and that the upper
+ * limit on the input (compressed) data really is 65533, since the
+ * algorithm may read up to three bytes beyond the end of the input
+ * data, since it reads dwords.
+ ****************************************************************************
+ */
+
+#define REG(x) e ## x
+#define ADDR32 addr32
+
+	.code16
+	.globl	decompress16
+decompress16:
+	
+#else /* CODE16 */
+
+/****************************************************************************
+ * decompress (32-bit protected-mode near call, position independent)
+ *
+ * Parameters (passed via registers):
+ *   %ds:%esi - Start of compressed input data
+ *   %es:%edi - Start of output buffer
+ * Returns:
+ *   %ds:%esi - End of compressed input data
+ *   %es:%edi - End of decompressed output data
+ *   All other registers are preserved
+ ****************************************************************************
+ */
+
+#define REG(x) e ## x
+#define ADDR32
+	
+	.code32
+	.globl	decompress
+decompress:
+
+#endif /* CODE16 */
+
+#define xAX	REG(ax)
+#define xCX	REG(cx)
+#define xBP	REG(bp)
+#define xSI	REG(si)
+#define xDI	REG(di)
+
+	/* Save registers */
+	push	%xAX
+	pushl	%ebx
+	push	%xCX
+	push	%xBP
+	/* Do the decompression */
+	cld
+	xor	%xBP, %xBP
+	dec	%xBP		/* last_m_off = -1 */
+	jmp	dcl1_n2b
+	
+decompr_literals_n2b:
+	ADDR32 movsb
+decompr_loop_n2b:
+	addl	%ebx, %ebx
+	jnz	dcl2_n2b
+dcl1_n2b:
+	call	getbit32
+dcl2_n2b:
+	jc	decompr_literals_n2b
+	xor	%xAX, %xAX
+	inc	%xAX		/* m_off = 1 */
+loop1_n2b:
+	call	getbit1
+	adc	%xAX, %xAX	/* m_off = m_off*2 + getbit() */
+	call	getbit1
+	jnc	loop1_n2b	/* while(!getbit()) */
+	sub	$3, %xAX
+	jb	decompr_ebpeax_n2b	/* if (m_off == 2) goto decompr_ebpeax_n2b ? */
+	shl	$8, %xAX	
+	ADDR32 movb (%xSI), %al	/* m_off = (m_off - 3)*256 + src[ilen++] */
+	inc	%xSI
+	xor	$-1, %xAX
+	jz	decompr_end_n2b	/* if (m_off == 0xffffffff) goto decomp_end_n2b */
+	mov	%xAX, %xBP	/* last_m_off = m_off ?*/
+decompr_ebpeax_n2b:
+	xor	%xCX, %xCX
+	call	getbit1
+	adc	%xCX, %xCX	/* m_len = getbit() */
+	call	getbit1
+	adc	%xCX, %xCX	/* m_len = m_len*2 + getbit()) */
+	jnz	decompr_got_mlen_n2b	/* if (m_len == 0) goto decompr_got_mlen_n2b */
+	inc	%xCX		/* m_len++ */
+loop2_n2b:
+	call	getbit1	
+	adc	%xCX, %xCX	/* m_len = m_len*2 + getbit() */
+	call	getbit1
+	jnc	loop2_n2b	/* while(!getbit()) */
+	inc	%xCX
+	inc	%xCX		/* m_len += 2 */
+decompr_got_mlen_n2b:
+	cmp	$-0xd00, %xBP
+	adc	$1, %xCX	/* m_len = m_len + 1 + (last_m_off > 0xd00) */
+	push	%xSI
+	ADDR32 lea (%xBP,%xDI), %xSI	/* m_pos = dst + olen + -m_off  */
+	rep
+	es ADDR32 movsb		/* dst[olen++] = *m_pos++ while(m_len > 0) */
+	pop	%xSI
+	jmp	decompr_loop_n2b
+
+
+getbit1:
+	addl	%ebx, %ebx
+	jnz	1f
+getbit32:
+	ADDR32 movl (%xSI), %ebx
+	sub	$-4, %xSI	/* sets carry flag */
+	adcl	%ebx, %ebx
+1:
+	ret
+
+decompr_end_n2b:
+	/* Restore registers and return */
+	pop	%xBP
+	pop	%xCX
+	popl	%ebx
+	pop	%xAX
+	ret
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S
new file mode 100644
index 0000000..b24c284
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S
@@ -0,0 +1,9 @@
+/*
+ * 16-bit version of the decompressor
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define CODE16
+#include "unnrv2b.S"
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/usbdisk.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/usbdisk.S
new file mode 100644
index 0000000..fa7d195
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/prefix/usbdisk.S
@@ -0,0 +1,23 @@
+	.text
+	.arch i386
+	.section ".prefix", "awx", @progbits
+	.code16
+	.org 0
+
+#include "mbr.S"
+
+/* Partition table: ZIP-compatible partition 4, 64 heads, 32 sectors/track */
+	.org 446
+	.space 16
+	.space 16
+	.space 16
+	.byte 0x80, 0x01, 0x01, 0x00
+	.byte 0xeb, 0x3f, 0x20, 0x01
+	.long 0x00000020
+	.long 0x00000fe0
+
+	.org 510
+	.byte 0x55, 0xaa
+
+/* Skip to start of partition */
+	.org 32 * 512
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386-kir.lds b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386-kir.lds
new file mode 100644
index 0000000..338d6ee
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386-kir.lds
@@ -0,0 +1,200 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for i386 images
+ *
+ */
+
+OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
+OUTPUT_ARCH ( i386 )
+
+SECTIONS {
+
+    /* All sections in the resulting file have consecutive load
+     * addresses, but may have individual link addresses depending on
+     * the memory model being used.
+     *
+     * The linker symbols _prefix_link_addr, load_addr, and
+     * _max_align may be specified explicitly.  If not specified, they
+     * will default to:
+     *
+     *   _prefix_link_addr	= 0
+     *   _load_addr		= 0
+     *   _max_align		= 16
+     * 
+     * We guarantee alignment of virtual addresses to any alignment
+     * specified by the constituent object files (e.g. via
+     * __attribute__((aligned(x)))).  Load addresses are guaranteed
+     * only up to _max_align.  Provided that all loader and relocation
+     * code honours _max_align, this means that physical addresses are
+     * also guaranteed up to _max_align.
+     *
+     * Note that when using -DKEEP_IT_REAL, the UNDI segments are only
+     * guaranteed to be loaded on a paragraph boundary (i.e. 16-byte
+     * alignment).  Using _max_align>16 will therefore not guarantee
+     * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
+     * used (though virtual addresses will still be fully aligned).
+     *
+     */
+
+    /*
+     * The prefix
+     */
+
+    _prefix_link_addr = DEFINED ( _prefix_link_addr ) ? _prefix_link_addr : 0;
+    . = _prefix_link_addr;
+    _prefix = .;
+
+    .prefix : AT ( _prefix_load_offset + __prefix ) {
+	__prefix = .;
+	_entry = .;
+	*(.prefix)
+	*(.prefix.*)
+	_eprefix_progbits = .;
+    }
+    
+    _eprefix = .;
+
+    /*
+     * The 16-bit sections
+     */
+
+    _text16_link_addr = 0;
+    . = _text16_link_addr;
+    _text16 = .;
+
+    . += 1;			/* Prevent NULL being valid */
+
+    .text16 : AT ( _text16_load_offset + __text16 ) {
+	__text16 = .;
+	KEEP(*(.text.null_trap))
+	KEEP(*(.text.null_trap.*))
+	*(.text16)
+	*(.text16.*)
+	*(.text)
+	*(.text.*)
+	_etext16_progbits = .;
+    } = 0x9090
+
+    _etext16 = .;
+
+    _data16_link_addr = 0;
+    . = _data16_link_addr;
+    _data16 = .;
+
+    . += 1;			/* Prevent NULL being valid */
+
+    .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
+	__rodata16 = .;
+	*(.rodata16)
+	*(.rodata16.*)
+	*(.rodata)
+	*(.rodata.*)
+    }
+    .data16 : AT ( _data16_load_offset + __data16 ) {
+	__data16 = .;
+	*(.data16)
+	*(.data16.*)
+	*(.data)
+	*(.data.*)
+	KEEP(*(SORT(.tbl.*)))	/* Various tables.  See include/tables.h */
+	_edata16_progbits = .;
+    }
+    .bss16 : AT ( _data16_load_offset + __bss16 ) {
+	__bss16 = .;
+	_bss16 = .;
+	*(.bss16)
+	*(.bss16.*)
+	*(.bss)
+	*(.bss.*)
+	*(COMMON)
+	_ebss16 = .;
+    }
+    .stack16 : AT ( _data16_load_offset + __stack16 ) {
+	__stack16 = .;
+	*(.stack16)
+	*(.stack16.*)
+	*(.stack)
+	*(.stack.*)
+    }
+
+    _edata16 = .;
+
+    _end = .;
+
+    /*
+     * Dispose of the comment and note sections to make the link map
+     * easier to read
+     */
+
+    /DISCARD/ : {
+	*(.comment)
+	*(.comment.*)
+	*(.note)
+	*(.note.*)
+	*(.discard)
+	*(.discard.*)
+    }
+
+    /*
+     * Load address calculations.  The slightly obscure nature of the
+     * calculations is because ALIGN(x) can only operate on the
+     * location counter.
+     */
+
+    _max_align		    = DEFINED ( _max_align ) ? _max_align : 16;
+    _load_addr		    = DEFINED ( _load_addr ) ? _load_addr : 0;
+
+    .			    = _load_addr;
+
+    .			   -= _prefix_link_addr;
+    _prefix_load_offset	    = ALIGN ( _max_align );
+    _prefix_load_addr	    = _prefix_link_addr + _prefix_load_offset;
+    _prefix_size	    = _eprefix - _prefix;
+    _prefix_progbits_size   = _eprefix_progbits - _prefix;
+    .			    = _prefix_load_addr + _prefix_progbits_size;
+
+    .			   -= _text16_link_addr;
+    _text16_load_offset	    = ALIGN ( _max_align );
+    _text16_load_addr	    = _text16_link_addr + _text16_load_offset;
+    _text16_size	    = _etext16 - _text16;
+    _text16_progbits_size   = _etext16_progbits - _text16;
+    .			    = _text16_load_addr + _text16_progbits_size;
+
+    .			   -= _data16_link_addr;
+    _data16_load_offset	    = ALIGN ( _max_align );
+    _data16_load_addr	    = _data16_link_addr + _data16_load_offset;
+    _data16_size	    = _edata16 - _data16;
+    _data16_progbits_size   = _edata16_progbits - _data16;
+    .			    = _data16_load_addr + _data16_progbits_size;
+
+    .			    = ALIGN ( _max_align );
+
+    _load_size		    = . - _load_addr;
+
+    /*
+     * Alignment checks.  ALIGN() can only operate on the location
+     * counter, so we set the location counter to each value we want
+     * to check.
+     */
+
+    . = _prefix_load_addr - _prefix_link_addr;
+    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
+		       "_prefix is badly aligned" );
+
+    . = _text16_load_addr - _text16_link_addr;
+    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
+		       "_text16 is badly aligned" );
+
+    . = _data16_load_addr - _data16_link_addr;
+    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
+		       "_data16 is badly aligned" );
+
+    /*
+     * Values calculated to save code from doing it
+     */
+    _text16_size_pgh	= ( ( _text16_size + 15 ) / 16 );
+    _data16_size_pgh	= ( ( _data16_size + 15 ) / 16 );
+    _load_size_pgh	= ( ( _load_size + 15 ) / 16 );
+    _load_size_sect	= ( ( _load_size + 511 ) / 512 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386.lds b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386.lds
new file mode 100644
index 0000000..c5bc631
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/i386.lds
@@ -0,0 +1,220 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for i386 images
+ *
+ */
+
+SECTIONS {
+
+    /* Each section starts at a virtual address of zero.
+     *
+     * We guarantee alignment of virtual addresses to any alignment
+     * specified by the constituent object files (e.g. via
+     * __attribute__((aligned(x)))).  Load addresses are guaranteed
+     * only up to _max_align.  Provided that all loader and relocation
+     * code honours _max_align, this means that physical addresses are
+     * also guaranteed up to _max_align.
+     *
+     * Note that when using -DKEEP_IT_REAL, the UNDI segments are only
+     * guaranteed to be loaded on a paragraph boundary (i.e. 16-byte
+     * alignment).  Using _max_align>16 will therefore not guarantee
+     * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
+     * used (though virtual addresses will still be fully aligned).
+     *
+     */
+
+    PROVIDE ( _max_align = 16 );
+
+    /*
+     * The prefix
+     *
+     */
+
+    .prefix 0x0 : AT ( _prefix_lma ) {
+	_prefix = .;
+	*(.prefix)
+	*(.prefix.*)
+	_mprefix = .;
+    } .bss.prefix (NOLOAD) : AT ( _end_lma ) {
+	_eprefix = .;
+    }
+    _prefix_filesz	= ABSOLUTE ( _mprefix - _prefix );
+    _prefix_memsz	= ABSOLUTE ( _eprefix - _prefix );
+
+    /*
+     * The 16-bit (real-mode) code section
+     *
+     */
+
+    .text16.early 0x0 : AT ( _text16_early_lma ) {
+	_text16 = .;
+	KEEP(*(.text16.null))
+	KEEP(*(.text16.null.*))
+	. += 1;				/* Prevent NULL being valid */
+	*(.text16.early)
+	*(.text16.early.*)
+	_etext16_early = .;
+    } .text16.late ALIGN ( _max_align ) : AT ( _text16_late_lma ) {
+	_text16_late = .;
+	*(.text16)
+	*(.text16.*)
+	_mtext16 = .;
+    } .bss.text16 (NOLOAD) : AT ( _end_lma ) {
+	_etext16 = .;
+    }
+    _text16_early_filesz = ABSOLUTE ( _etext16_early - _text16 );
+    _text16_early_memsz	= ABSOLUTE ( _etext16_early - _text16 );
+    _text16_late_filesz	= ABSOLUTE ( _mtext16 - _text16_late );
+    _text16_late_memsz	= ABSOLUTE ( _etext16 - _text16_late );
+    _text16_memsz	= ABSOLUTE ( _etext16 - _text16 );
+
+    /*
+     * The 16-bit (real-mode) data section
+     *
+     */
+
+    .data16 0x0 : AT ( _data16_lma ) {
+	_data16 = .;
+	. += 1;				/* Prevent NULL being valid */
+	*(.rodata16)
+	*(.rodata16.*)
+	*(.data16)
+	*(.data16.*)
+	_mdata16 = .;
+    } .bss.data16 (NOLOAD) : AT ( _end_lma ) {
+	*(.bss16)
+	*(.bss16.*)
+	*(.stack16)
+	*(.stack16.*)
+	_edata16 = .;
+    }
+    _data16_filesz	= ABSOLUTE ( _mdata16 - _data16 );
+    _data16_memsz	= ABSOLUTE ( _edata16 - _data16 );
+
+    /*
+     * The 32-bit sections
+     *
+     */
+
+    .textdata 0x0 : AT ( _textdata_lma ) {
+	_textdata = .;
+	KEEP(*(.text.null_trap))
+	KEEP(*(.text.null_trap.*))
+	. += 1;				/* Prevent NULL being valid */
+	*(.text)
+	*(.text.*)
+	*(.rodata)
+	*(.rodata.*)
+	*(.data)
+	*(.data.*)
+	KEEP(*(SORT(.tbl.*)))	/* Various tables.  See include/tables.h */
+	_mtextdata = .;
+    } .bss.textdata (NOLOAD) : AT ( _end_lma ) {
+	*(.bss)
+	*(.bss.*)
+	*(COMMON)
+	*(.stack)
+	*(.stack.*)
+	_etextdata = .;
+    }
+    _textdata_filesz	= ABSOLUTE ( _mtextdata - _textdata );
+    _textdata_memsz	= ABSOLUTE ( _etextdata - _textdata );
+
+    /*
+     * Compressor information block
+     *
+     */
+
+    .zinfo 0x0 : AT ( _zinfo_lma ) {
+	_zinfo = .;
+	KEEP(*(.zinfo))
+	KEEP(*(.zinfo.*))
+	_mzinfo = .;
+    } .bss.zinfo (NOLOAD) : AT ( _end_lma ) {
+	_ezinfo = .;
+    }
+    _zinfo_filesz	= ABSOLUTE ( _mzinfo - _zinfo );
+    _zinfo_memsz	= ABSOLUTE ( _ezinfo - _zinfo );
+
+    /*
+     * Weak symbols that need zero values if not otherwise defined
+     *
+     */
+
+    .weak 0x0 : AT ( _end_lma ) {
+	_weak = .;
+	*(.weak)
+	*(.weak.*)
+	_eweak = .;
+    }
+    _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+    /*
+     * Dispose of the comment and note sections to make the link map
+     * easier to read
+     *
+     */
+
+    /DISCARD/ : {
+	*(.comment)
+	*(.comment.*)
+	*(.note)
+	*(.note.*)
+	*(.eh_frame)
+	*(.eh_frame.*)
+	*(.rel)
+	*(.rel.*)
+	*(.einfo)
+	*(.einfo.*)
+	*(.discard)
+	*(.discard.*)
+    }
+
+    /*
+     * Load address calculations.  In older versions of ld, ALIGN()
+     * can operate only on the location counter, so we use that.
+     *
+     */
+
+    .			= 0;
+
+    .			= ALIGN ( _max_align );
+    _prefix_lma		= .;
+    .			+= _prefix_filesz;
+
+    .			= ALIGN ( _max_align );
+    _text16_early_lma	= .;
+    .			+= _text16_early_filesz;
+
+    .			= ALIGN ( _max_align );
+    _payload_lma	= .;
+    _text16_late_lma	= .;
+    .			+= _text16_late_filesz;
+
+    .			= ALIGN ( _max_align );
+    _data16_lma		= .;
+    .			+= _data16_filesz;
+
+    .			= ALIGN ( _max_align );
+    _textdata_lma	= .;
+    .			+= _textdata_filesz;
+
+    _filesz		= .; /* Do not include zinfo block in file size */
+
+    .			= ALIGN ( _max_align );
+    _zinfo_lma		= .;
+    .			+= _zinfo_filesz;
+
+    .			= ALIGN ( _max_align );
+    _end_lma		= .;
+
+    /*
+     * Values calculated to save code from doing it
+     *
+     */
+    _text16_memsz_pgh	= ( ( _text16_memsz + 15 ) / 16 );
+    _data16_memsz_pgh	= ( ( _data16_memsz + 15 ) / 16 );
+    _textdata_memsz_pgh	= ( ( _textdata_memsz + 15 ) / 16 );
+    _textdata_memsz_kb	= ( ( _textdata_memsz + 1023 ) / 1024 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/linux.lds b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/linux.lds
new file mode 100644
index 0000000..64c9b97
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/scripts/linux.lds
@@ -0,0 +1,102 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for i386 Linux images
+ *
+ */
+
+OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
+OUTPUT_ARCH ( i386 )
+
+SECTIONS {
+	_max_align = 32;
+
+	. = 0x08048000;
+
+	/*
+	 * The text section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.text : {
+		_text = .;
+		*(.text)
+		*(.text.*)
+		_etext = .;
+	}
+
+	/*
+	 * The rodata section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.rodata : {
+		_rodata = .;
+		*(.rodata)
+		*(.rodata.*)
+		_erodata = .;
+	}
+
+	/*
+	 * The data section
+	 *
+	 * Adjust the address for the data segment.  We want to adjust up to
+	 * the same address within the page on the next page up.
+	 */
+
+	. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1));
+	. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+	.data : {
+		_data = .;
+		*(.data)
+		*(.data.*)
+		KEEP(*(SORT(.tbl.*)))
+		_edata = .;
+	}
+
+	/*
+	 * The bss section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.bss : {
+		_bss = .;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		_ebss = .;
+	}
+
+	/*
+	 * Weak symbols that need zero values if not otherwise defined
+	 *
+	 */
+
+	.weak 0x0 : {
+		_weak = .;
+		*(.weak)
+		*(.weak.*)
+		_eweak = .;
+	}
+	_assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+	/*
+	 * Dispose of the comment and note sections to make the link map
+	 * easier to read
+	 *
+	 */
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.comment.*)
+		*(.note)
+		*(.note.*)
+		*(.rel)
+		*(.rel.*)
+		*(.discard)
+		*(.discard.*)
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/liba20.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/liba20.S
new file mode 100644
index 0000000..594d620
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/liba20.S
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+	.arch i386
+
+/****************************************************************************
+ * test_a20_short, test_a20_long
+ *
+ * Check to see if A20 line is enabled
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if A20 line is not enabled
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+#define TEST_A20_SHORT_MAX_RETRIES 0x20
+#define TEST_A20_LONG_MAX_RETRIES 0x200000
+	.section ".text16.early", "awx", @progbits
+	.code16
+test_a20_short:
+	pushl	%ecx
+	movl	$TEST_A20_SHORT_MAX_RETRIES, %ecx
+	jmp	1f
+	.size	test_a20_short, . - test_a20_short
+test_a20_long:
+	pushl	%ecx
+	movl	$TEST_A20_LONG_MAX_RETRIES, %ecx
+1:	pushw	%ax
+	pushw	%ds
+	pushw	%es
+
+	/* Set up segment registers for access across the 1MB boundary */
+	xorw	%ax, %ax
+	movw	%ax, %ds
+	decw	%ax
+	movw	%ax, %es
+
+2:	/* Modify and check test pattern; succeed if we see a difference */
+	pushfw
+	cli
+	xchgw	%ds:0, %cx
+	movw	%es:0x10, %ax
+	xchgw	%ds:0, %cx
+	popfw
+	cmpw	%ax, %cx
+	clc
+	jnz	99f
+
+	/* Delay and retry */
+	outb	%al, $0x80
+	addr32 loop 2b
+	stc
+
+99:	/* Restore registers and return */
+	popw	%es
+	popw	%ds
+	popw	%ax
+	popl	%ecx
+	ret
+	.size	test_a20_long, . - test_a20_long
+
+/****************************************************************************
+ * enable_a20_bios
+ *
+ * Try enabling A20 line via BIOS
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if A20 line is not enabled
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16.early", "awx", @progbits
+	.code16
+enable_a20_bios:
+	/* Preserve registers */
+	pushw	%ax
+
+	/* Attempt INT 15,2401 */
+	movw	$0x2401, %ax
+	int	$0x15
+	jc	99f
+
+	/* Check that success was really successful */
+	call	test_a20_short
+
+99:	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	enable_a20_bios, . - enable_a20_bios
+
+/****************************************************************************
+ * enable_a20_kbc
+ *
+ * Try enabling A20 line via keyboard controller
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if A20 line is not enabled
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+#define KC_RDWR		0x60
+#define KC_RDWR_SET_A20		0xdf
+#define	KC_CMD		0x64
+#define KC_CMD_WOUT		0xd1
+#define KC_CMD_NULL		0xff
+#define KC_STATUS	0x64
+#define KC_STATUS_OBUF_FULL	0x01
+#define KC_STATUS_IBUF_FULL	0x02
+#define KC_MAX_RETRIES	100000
+	.section ".text16.early", "awx", @progbits
+	.code16
+enable_a20_kbc:
+	/* Preserve registers */
+	pushw	%ax
+
+	/* Try keyboard controller */
+	call	empty_kbc
+	movb	$KC_CMD_WOUT, %al
+	outb	%al, $KC_CMD
+	call	empty_kbc
+	movb	$KC_RDWR_SET_A20, %al
+	outb	%al, $KC_RDWR
+	call	empty_kbc
+	movb	$KC_CMD_NULL, %al
+	outb	%al, $KC_CMD
+	call	empty_kbc
+
+	/* Check to see if it worked */
+	call	test_a20_long
+
+	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	enable_a20_kbc, . - enable_a20_kbc
+
+	.section ".text16.early", "awx", @progbits
+	.code16
+empty_kbc:
+	/* Preserve registers */
+	pushl	%ecx
+	pushw	%ax
+
+	/* Wait for KBC to become empty */
+	movl	$KC_MAX_RETRIES, %ecx
+1:	outb	%al, $0x80
+	inb	$KC_STATUS, %al
+	testb	$( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
+	jz	99f
+	testb	$KC_STATUS_OBUF_FULL, %al
+	jz	2f
+	outb	%al, $0x80
+	inb	$KC_RDWR, %al
+2:	addr32 loop 1b
+
+99:	/* Restore registers and return */
+	popw	%ax
+	popl	%ecx
+	ret
+	.size	empty_kbc, . - empty_kbc
+
+/****************************************************************************
+ * enable_a20_fast
+ *
+ * Try enabling A20 line via "Fast Gate A20"
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if A20 line is not enabled
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+#define SCP_A 0x92
+	.section ".text16.early", "awx", @progbits
+	.code16
+enable_a20_fast:
+	/* Preserve registers */
+	pushw	%ax
+
+	/* Try "Fast Gate A20" */
+	inb	$SCP_A, %al
+	orb	$0x02, %al
+	andb	$~0x01, %al
+	outb	%al, $SCP_A
+
+	/* Check to see if it worked */
+	call	test_a20_long
+
+	/* Restore registers and return */
+	popw	%ax
+	ret
+	.size	enable_a20_fast, . - enable_a20_fast
+
+/****************************************************************************
+ * enable_a20
+ *
+ * Try enabling A20 line via any available method
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if A20 line is not enabled
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+#define ENABLE_A20_RETRIES 255
+	.section ".text16.early", "awx", @progbits
+	.code16
+	.globl	enable_a20
+enable_a20:
+	/* Preserve registers */
+	pushl	%ecx
+	pushw	%ax
+
+	/* Check to see if A20 is already enabled */
+	call	test_a20_short
+	jnc	99f
+
+	/* Use known working method, if we have one */
+	movw	%cs:enable_a20_method, %ax
+	testw	%ax, %ax
+	jz	1f
+	call	*%ax
+	jmp	99f
+1:
+	/* Try all methods in turn until one works */
+	movl	$ENABLE_A20_RETRIES, %ecx
+2:	movw	$enable_a20_bios, %ax
+	movw	%ax, %cs:enable_a20_method
+	call	*%ax
+	jnc	99f
+	movw	$enable_a20_kbc, %ax
+	movw	%ax, %cs:enable_a20_method
+	call	*%ax
+	jnc	99f
+	movw	$enable_a20_fast, %ax
+	movw	%ax, %cs:enable_a20_method
+	call	*%ax
+	jnc	99f
+	addr32 loop 2b
+	/* Failure; exit with carry set */
+	movw	$0, %cs:enable_a20_method
+	stc
+
+99:	/* Restore registers and return */
+	popw	%ax
+	popl	%ecx
+	ret
+
+	.section ".text16.early.data", "aw", @progbits
+	.align	2
+enable_a20_method:
+	.word	0
+	.size	enable_a20_method, . - enable_a20_method
+
+/****************************************************************************
+ * access_highmem (real mode far call)
+ *
+ * Open up access to high memory with A20 enabled
+ *
+ * Parameters:
+ *   none
+ * Returns:
+ *   CF set if high memory could not be accessed
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+	.section ".text16.early", "awx", @progbits
+	.code16
+	.globl	access_highmem
+access_highmem:
+	/* Enable A20 line */
+	call	enable_a20
+	lret
+	.size	access_highmem, . - access_highmem
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/libkir.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/libkir.S
new file mode 100644
index 0000000..1176fcc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/libkir.S
@@ -0,0 +1,256 @@
+/*
+ * libkir: a transition library for -DKEEP_IT_REAL
+ *
+ * Michael Brown <mbrown at fensystems.co.uk>
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/****************************************************************************
+ * This file defines libkir: an interface between external and
+ * internal environments when -DKEEP_IT_REAL is used, so that both
+ * internal and external environments are in real mode.  It deals with
+ * switching data segments and the stack.  It provides the following
+ * functions:
+ *
+ * ext_to_kir &		switch between external and internal (kir)
+ * kir_to_ext		environments, preserving all non-segment
+ *			registers
+ *
+ * kir_call		issue a call to an internal routine from external
+ *			code
+ *
+ * libkir is written to avoid assuming that segments are anything
+ * other than opaque data types, and also avoids assuming that the
+ * stack pointer is 16-bit.  This should enable it to run just as well
+ * in 16:16 or 16:32 protected mode as in real mode.
+ ****************************************************************************
+ */
+
+/* Breakpoint for when debugging under bochs */
+#define BOCHSBP xchgw %bx, %bx
+
+	.text
+	.arch i386
+	.section ".text16", "awx", @progbits
+	.code16
+	
+/****************************************************************************
+ * init_libkir (real-mode or 16:xx protected-mode far call)
+ *
+ * Initialise libkir ready for transitions to the kir environment
+ *
+ * Parameters:
+ *   %cs : .text16 segment
+ *   %ds : .data16 segment
+ ****************************************************************************
+ */
+	.globl	init_libkir
+init_libkir:
+	/* Record segment registers */
+	pushw	%ds
+	popw	%cs:kir_ds
+	lret
+	
+/****************************************************************************
+ * ext_to_kir (real-mode or 16:xx protected-mode near call)
+ *
+ * Switch from external stack and segment registers to internal stack
+ * and segment registers.  %ss:sp is restored from the saved kir_ds
+ * and kir_sp.  %ds, %es, %fs and %gs are all restored from the saved
+ * kir_ds.  All other registers are preserved.
+ *
+ * %cs:0000 must point to the start of the runtime image code segment
+ * on entry.
+ *
+ * Parameters: none
+ ****************************************************************************
+ */
+
+	.globl	ext_to_kir
+ext_to_kir:
+	/* Record external segment registers */
+	movw	%ds, %cs:ext_ds
+	pushw	%cs
+	popw	%ds	/* Set %ds = %cs for easier access to variables */
+	movw	%es, %ds:ext_es
+	movw	%fs, %ds:ext_fs
+	movw	%gs, %ds:ext_fs
+
+	/* Preserve registers */
+	movw	%ax, %ds:save_ax
+
+	/* Extract near return address from stack */
+	popw	%ds:save_retaddr
+
+	/* Record external %ss:esp */
+	movw	%ss, %ds:ext_ss
+	movl	%esp, %ds:ext_esp
+
+	/* Load internal segment registers and stack pointer */
+	movw	%ds:kir_ds, %ax
+	movw	%ax, %ss
+	movzwl	%ds:kir_sp, %esp
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+1:
+
+	/* Place return address on new stack */
+	pushw	%cs:save_retaddr
+	
+	/* Restore registers and return */
+	movw	%cs:save_ax, %ax
+	ret
+
+/****************************************************************************
+ * kir_to_ext (real-mode or 16:xx protected-mode near call)
+ *
+ * Switch from internal stack and segment registers to external stack
+ * and segment registers.  %ss:%esp is restored from the saved ext_ss
+ * and ext_esp.  Other segment registers are restored from the
+ * corresponding locations.  All other registers are preserved.
+ *
+ * Note that it is actually %ss that is recorded as kir_ds, on the
+ * assumption that %ss == %ds when kir_to_ext is called.
+ *
+ * Parameters: none
+ ****************************************************************************
+ */
+
+	.globl	kir_to_ext
+kir_to_ext:
+	/* Record near return address */
+	pushw	%cs
+	popw	%ds	/* Set %ds = %cs for easier access to variables */
+	popw	%ds:save_retaddr
+	
+	/* Record internal segment registers and %sp */
+	movw	%ss, %ds:kir_ds
+	movw	%sp, %ds:kir_sp
+
+	/* Load external segment registers and stack pointer */
+	movw	%ds:ext_ss, %ss
+	movl	%ds:ext_esp, %esp
+	movw	%ds:ext_gs, %gs
+	movw	%ds:ext_fs, %fs
+	movw	%ds:ext_es, %es
+	movw	%ds:ext_ds, %ds
+
+	/* Return */
+	pushw	%cs:save_retaddr
+	ret
+	
+/****************************************************************************
+ * kir_call (real-mode or 16:xx protected-mode far call)
+ *
+ * Call a specific C function in the internal code.  The prototype of
+ * the C function must be
+ *   void function ( struct i386_all_resg *ix86 ); 
+ * ix86 will point to a struct containing the real-mode registers
+ * at entry to kir_call.
+ *
+ * All registers will be preserved across kir_call(), unless the C
+ * function explicitly overwrites values in ix86.  Interrupt status
+ * will also be preserved.
+ *
+ * Parameters:
+ *   function : (32-bit) virtual address of C function to call
+ *
+ * Example usage:
+ *	pushl	$pxe_api_call
+ *	lcall	$UNDI_CS, $kir_call
+ *	addw	$4, %sp
+ * to call in to the C function
+ *      void pxe_api_call ( struct i386_all_regs *ix86 );
+ ****************************************************************************
+ */
+
+	.globl	kir_call
+kir_call:
+	/* Preserve flags.  Must do this before any operation that may
+	 * affect flags.
+	 */
+	pushfl
+	popl	%cs:save_flags
+
+	/* Disable interrupts.  We do funny things with the stack, and
+	 * we're not re-entrant.
+	 */
+	cli
+		
+	/* Extract address of internal routine from stack.  We must do
+	 * this without using (%bp), because we may be called with
+	 * either a 16-bit or a 32-bit stack segment.
+	 */
+	popl	%cs:save_retaddr	/* Scratch location */
+	popl	%cs:save_function
+	subl	$8, %esp		/* Restore %esp */
+	
+	/* Switch to internal stack.  Note that the external stack is
+	 * inaccessible once we're running internally (since we have
+	 * no concept of 48-bit far pointers)
+	 */
+	call	ext_to_kir
+	
+	/* Store external registers on internal stack */
+	pushl	%cs:save_flags
+	pushal
+	pushl	%cs:ext_fs_and_gs
+	pushl	%cs:ext_ds_and_es
+	pushl	%cs:ext_cs_and_ss
+
+	/* Push &ix86 on stack and call function */
+	sti
+	pushl	%esp
+	data32 call *%cs:save_function
+	popl	%eax /* discard */
+	
+	/* Restore external registers from internal stack */
+	popl	%cs:ext_cs_and_ss
+	popl	%cs:ext_ds_and_es
+	popl	%cs:ext_fs_and_gs
+	popal
+	popl	%cs:save_flags
+
+	/* Switch to external stack */
+	call	kir_to_ext
+
+	/* Restore flags */
+	pushl	%cs:save_flags
+	popfl
+
+	/* Return */
+	lret
+
+/****************************************************************************
+ * Stored internal and external stack and segment registers
+ ****************************************************************************
+ */
+	
+ext_cs_and_ss:	
+ext_cs:		.word 0
+ext_ss:		.word 0
+ext_ds_and_es:	
+ext_ds:		.word 0
+ext_es:		.word 0
+ext_fs_and_gs:	
+ext_fs:		.word 0
+ext_gs:		.word 0
+ext_esp:	.long 0
+
+		.globl kir_ds
+kir_ds:		.word 0
+		.globl kir_sp
+kir_sp:		.word _estack
+
+/****************************************************************************
+ * Temporary variables
+ ****************************************************************************
+ */
+save_ax:	.word 0
+save_retaddr:	.long 0
+save_flags:	.long 0
+save_function:	.long 0
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/libpm.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/libpm.S
new file mode 100644
index 0000000..e69de29
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm.S b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm.S
new file mode 100644
index 0000000..5eb82b4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm.S
@@ -0,0 +1,571 @@
+/*
+ * librm: a library for interfacing to real-mode code
+ *
+ * Michael Brown <mbrown at fensystems.co.uk>
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/* Drag in local definitions */
+#include "librm.h"
+
+/* For switches to/from protected mode */
+#define CR0_PE 1
+
+/* Size of various C data structures */
+#define SIZEOF_I386_SEG_REGS	12
+#define SIZEOF_I386_REGS	32
+#define SIZEOF_REAL_MODE_REGS	( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
+#define SIZEOF_I386_FLAGS	4
+#define SIZEOF_I386_ALL_REGS	( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
+	
+	.arch i386
+
+/****************************************************************************
+ * Global descriptor table
+ *
+ * Call init_librm to set up the GDT before attempting to use any
+ * protected-mode code.
+ *
+ * NOTE: This must be located before prot_to_real, otherwise gas
+ * throws a "can't handle non absolute segment in `ljmp'" error due to
+ * not knowing the value of REAL_CS when the ljmp is encountered.
+ *
+ * Note also that putting ".word gdt_end - gdt - 1" directly into
+ * gdt_limit, rather than going via gdt_length, will also produce the
+ * "non absolute segment" error.  This is most probably a bug in gas.
+ ****************************************************************************
+ */
+	.section ".data16", "aw", @progbits
+	.align 16
+gdt:
+gdtr:		/* The first GDT entry is unused, the GDTR can fit here. */
+gdt_limit:		.word gdt_length - 1
+gdt_base:		.long 0
+			.word 0 /* padding */
+
+	.org	gdt + VIRTUAL_CS, 0
+virtual_cs:	/* 32 bit protected mode code segment, virtual addresses */
+	.word	0xffff, 0
+	.byte	0, 0x9f, 0xcf, 0
+
+	.org	gdt + VIRTUAL_DS, 0
+virtual_ds:	/* 32 bit protected mode data segment, virtual addresses */
+	.word	0xffff, 0
+	.byte	0, 0x93, 0xcf, 0
+	
+	.org	gdt + PHYSICAL_CS, 0
+physical_cs:	/* 32 bit protected mode code segment, physical addresses */
+	.word	0xffff, 0
+	.byte	0, 0x9f, 0xcf, 0
+
+	.org	gdt + PHYSICAL_DS, 0
+physical_ds:	/* 32 bit protected mode data segment, physical addresses */
+	.word	0xffff, 0
+	.byte	0, 0x93, 0xcf, 0	
+
+	.org	gdt + REAL_CS, 0
+real_cs: 	/* 16 bit flat real mode code segment */
+	.word	0xffff, 0
+	.byte	0, 0x9b, 0x8f, 0
+
+	.org	gdt + REAL_DS	
+real_ds:	/* 16 bit flat real mode data segment */
+	.word	0xffff, 0
+	.byte	0, 0x93, 0x8f, 0
+	
+gdt_end:
+	.equ	gdt_length, gdt_end - gdt
+
+/****************************************************************************
+ * init_librm (real-mode far call, 16-bit real-mode far return address)
+ *
+ * Initialise the GDT ready for transitions to protected mode.
+ *
+ * Parameters:
+ *   %cs : .text16 segment
+ *   %ds : .data16 segment
+ *   %edi : Physical base of protected-mode code (virt_offset)
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl init_librm
+init_librm:
+	/* Preserve registers */
+	pushl	%eax
+	pushl	%ebx
+
+	/* Store _virt_offset and set up virtual_cs and virtual_ds segments */
+	movl	%edi, %eax
+	movw	$virtual_cs, %bx
+	call	set_seg_base
+	movw	$virtual_ds, %bx
+	call	set_seg_base	
+	movl	%edi, _virt_offset
+
+	/* Negate virt_offset */
+	negl	%edi
+		
+	/* Store rm_cs and _text16, set up real_cs segment */
+	xorl	%eax, %eax
+	movw	%cs, %ax
+	movw	%ax, rm_cs
+	shll	$4, %eax
+	movw	$real_cs, %bx
+	call	set_seg_base
+	addr32 leal	(%eax, %edi), %ebx
+	movl	%ebx, _text16
+
+	/* Store rm_ds and _data16, set up real_ds segment */
+	xorl	%eax, %eax
+	movw	%ds, %ax
+	movw	%ax, %cs:rm_ds
+	shll	$4, %eax
+	movw	$real_ds, %bx
+	call	set_seg_base
+	addr32 leal	(%eax, %edi), %ebx
+	movl	%ebx, _data16
+
+	/* Set GDT and IDT base */
+	movl	%eax, gdt_base
+	addl	$gdt, gdt_base
+	call	idt_init
+
+	/* Restore registers */
+	negl	%edi
+	popl	%ebx
+	popl	%eax
+	lret
+
+	.section ".text16", "ax", @progbits
+	.code16
+	.weak idt_init
+set_seg_base:
+1:	movw	%ax, 2(%bx)
+	rorl	$16, %eax
+	movb	%al, 4(%bx)
+	movb	%ah, 7(%bx)
+	roll	$16, %eax
+idt_init: /* Reuse the return opcode here */
+	ret
+
+/****************************************************************************
+ * real_to_prot (real-mode near call, 32-bit virtual return address)
+ *
+ * Switch from 16-bit real-mode to 32-bit protected mode with virtual
+ * addresses.  The real-mode %ss:sp is stored in rm_ss and rm_sp, and
+ * the protected-mode %esp is restored from the saved pm_esp.
+ * Interrupts are disabled.  All other registers may be destroyed.
+ *
+ * The return address for this function should be a 32-bit virtual
+ * address.
+ *
+ * Parameters: 
+ *   %ecx : number of bytes to move from RM stack to PM stack
+ *
+ ****************************************************************************
+ */
+	.section ".text16", "ax", @progbits
+	.code16
+real_to_prot:
+	/* Enable A20 line */
+	call	enable_a20
+	/* A failure at this point is fatal, and there's nothing we
+	 * can do about it other than lock the machine to make the
+	 * problem immediately visible.
+	 */
+1:	jc	1b
+
+	/* Make sure we have our data segment available */
+	movw	%cs:rm_ds, %ax
+	movw	%ax, %ds
+
+	/* Add _virt_offset, _text16 and _data16 to stack to be
+	 * copied, and also copy the return address.
+	 */
+	pushl	_virt_offset
+	pushl	_text16
+	pushl	_data16
+	addw	$16, %cx /* %ecx must be less than 64kB anyway */
+
+	/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
+	xorl	%ebp, %ebp
+	movw	%ss, %bp
+	movzwl	%sp, %edx
+	movl	%ebp, %eax
+	shll	$4, %eax
+	addr32 leal (%eax,%edx), %esi
+	subl	_virt_offset, %esi
+
+	/* Switch to protected mode */
+	cli
+	data32 lgdt gdtr
+	data32 lidt idtr
+	movl	%cr0, %eax
+	orb	$CR0_PE, %al
+	movl	%eax, %cr0
+	data32 ljmp	$VIRTUAL_CS, $1f
+	.section ".text", "ax", @progbits
+	.code32
+1:
+	/* Set up protected-mode data segments and stack pointer */
+	movw	$VIRTUAL_DS, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+	movl	pm_esp, %esp
+
+	/* Record real-mode %ss:sp (after removal of data) */
+	movw	%bp, rm_ss
+	addl	%ecx, %edx
+	movw	%dx, rm_sp
+
+	/* Move data from RM stack to PM stack */
+	subl	%ecx, %esp
+	movl	%esp, %edi
+	rep movsb
+
+	/* Publish virt_offset, text16 and data16 for PM code to use */
+	popl	data16
+	popl	text16
+	popl	virt_offset
+
+	/* Return to virtual address */
+	ret
+
+	/* Default IDTR with no interrupts */
+	.section ".data16", "aw", @progbits
+	.weak idtr
+idtr:
+rm_idtr:
+	.word 0xffff /* limit */
+	.long 0 /* base */
+
+/****************************************************************************
+ * prot_to_real (protected-mode near call, 32-bit real-mode return address)
+ *
+ * Switch from 32-bit protected mode with virtual addresses to 16-bit
+ * real mode.  The protected-mode %esp is stored in pm_esp and the
+ * real-mode %ss:sp is restored from the saved rm_ss and rm_sp.  The
+ * high word of the real-mode %esp is set to zero.  All real-mode data
+ * segment registers are loaded from the saved rm_ds.  Interrupts are
+ * *not* enabled, since we want to be able to use prot_to_real in an
+ * ISR.  All other registers may be destroyed.
+ *
+ * The return address for this function should be a 32-bit (sic)
+ * real-mode offset within .code16.
+ *
+ * Parameters: 
+ *   %ecx : number of bytes to move from PM stack to RM stack
+ *
+ ****************************************************************************
+ */
+	.section ".text", "ax", @progbits
+	.code32
+prot_to_real:
+	/* Add return address to data to be moved to RM stack */
+	addl	$4, %ecx
+	
+	/* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
+	movzwl	rm_ss, %ebp
+	movzwl	rm_sp, %edx
+	subl	%ecx, %edx
+	movl	%ebp, %eax
+	shll	$4, %eax
+	leal	(%eax,%edx), %edi
+	subl	virt_offset, %edi
+	
+	/* Move data from PM stack to RM stack */
+	movl	%esp, %esi
+	rep movsb
+	
+	/* Record protected-mode %esp (after removal of data) */
+	movl	%esi, pm_esp
+
+	/* Load real-mode segment limits */
+	movw	$REAL_DS, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+	ljmp	$REAL_CS, $1f
+	.section ".text16", "ax", @progbits
+	.code16
+1:
+	/* Switch to real mode */
+	movl	%cr0, %eax
+	andb	$0!CR0_PE, %al
+	movl	%eax, %cr0
+	ljmp	*p2r_jump_vector
+p2r_jump_target:
+
+	/* Set up real-mode data segments and stack pointer */
+	movw	%cs:rm_ds, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%bp, %ss
+	movl	%edx, %esp
+
+	/* Reset IDTR to the real-mode defaults */
+	data32 lidt rm_idtr
+
+	/* Return to real-mode address */
+	data32 ret
+
+
+	/* Real-mode code and data segments.  Assigned by the call to
+	 * init_librm.  rm_cs doubles as the segment part of the jump
+	 * vector used by prot_to_real.  rm_ds is located in .text16
+	 * rather than .data16 because code needs to be able to locate
+	 * the data segment.
+	 */
+	.section ".data16", "aw", @progbits
+p2r_jump_vector:
+	.word	p2r_jump_target
+	.globl rm_cs
+rm_cs:	.word 0
+	.globl rm_ds
+	.section ".text16.data", "aw", @progbits
+rm_ds:	.word 0
+
+/****************************************************************************
+ * prot_call (real-mode far call, 16-bit real-mode far return address)
+ *
+ * Call a specific C function in the protected-mode code.  The
+ * prototype of the C function must be
+ *   void function ( struct i386_all_regs *ix86 ); 
+ * ix86 will point to a struct containing the real-mode registers
+ * at entry to prot_call.  
+ *
+ * All registers will be preserved across prot_call(), unless the C
+ * function explicitly overwrites values in ix86.  Interrupt status
+ * and GDT will also be preserved.  Gate A20 will be enabled.
+ *
+ * Note that prot_call() does not rely on the real-mode stack
+ * remaining intact in order to return, since everything relevant is
+ * copied to the protected-mode stack for the duration of the call.
+ * In particular, this means that a real-mode prefix can make a call
+ * to main() which will return correctly even if the prefix's stack
+ * gets vapourised during the Etherboot run.  (The prefix cannot rely
+ * on anything else on the stack being preserved, so should move any
+ * critical data to registers before calling main()).
+ *
+ * Parameters:
+ *   function : virtual address of protected-mode function to call
+ *
+ * Example usage:
+ *	pushl	$pxe_api_call
+ *	call	prot_call
+ *	addw	$4, %sp
+ * to call in to the C function
+ *      void pxe_api_call ( struct i386_all_regs *ix86 );
+ ****************************************************************************
+ */
+
+#define PC_OFFSET_GDT ( 0 )
+#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 8 /* pad to 8 to keep alignment */ )
+#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 8 /* pad to 8 to keep alignment */ )
+#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
+#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
+#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
+
+	.section ".text16", "ax", @progbits
+	.code16
+	.globl prot_call
+prot_call:
+	/* Preserve registers, flags and GDT on external RM stack */
+	pushfl
+	pushal
+	pushw	%gs
+	pushw	%fs
+	pushw	%es
+	pushw	%ds
+	pushw	%ss
+	pushw	%cs
+	subw	$16, %sp
+	movw	%sp, %bp
+	sidt	8(%bp)
+	sgdt	(%bp)
+
+	/* For sanity's sake, clear the direction flag as soon as possible */
+	cld
+
+	/* Switch to protected mode and move register dump to PM stack */
+	movl	$PC_OFFSET_END, %ecx
+	pushl	$1f
+	jmp	real_to_prot
+	.section ".text", "ax", @progbits
+	.code32
+1:
+	/* Call function */
+	leal	PC_OFFSET_IX86(%esp), %eax
+	pushl	%eax
+	call	*(PC_OFFSET_FUNCTION+4)(%esp)
+	popl	%eax /* discard */
+
+	/* Switch to real mode and move register dump back to RM stack */
+	movl	$PC_OFFSET_END, %ecx
+	pushl	$1f
+	jmp	prot_to_real
+	.section ".text16", "ax", @progbits
+	.code16
+1:	
+	/* Reload GDT and IDT, restore registers and flags and return */
+	movw	%sp, %bp
+	data32 lgdt (%bp)
+	data32 lidt 8(%bp)
+	addw	$20, %sp /* also skip %cs and %ss */
+	popw	%ds
+	popw	%es
+	popw	%fs
+	popw	%gs
+	popal
+	/* popal skips %esp.  We therefore want to do "movl -20(%sp),
+	 * %esp", but -20(%sp) is not a valid 80386 expression.
+	 * Fortunately, prot_to_real() zeroes the high word of %esp, so
+	 * we can just use -20(%esp) instead.
+	 */
+	addr32 movl -20(%esp), %esp
+	popfl
+	lret
+
+/****************************************************************************
+ * real_call (protected-mode near call, 32-bit virtual return address)
+ *
+ * Call a real-mode function from protected-mode code.
+ *
+ * The non-segment register values will be passed directly to the
+ * real-mode code.  The segment registers will be set as per
+ * prot_to_real.  The non-segment register values set by the real-mode
+ * function will be passed back to the protected-mode caller.  A
+ * result of this is that this routine cannot be called directly from
+ * C code, since it clobbers registers that the C ABI expects the
+ * callee to preserve.
+ *
+ * librm.h defines a convenient macro REAL_CODE() for using real_call.
+ * See librm.h and realmode.h for details and examples.
+ *
+ * Parameters:
+ *   (32-bit) near pointer to real-mode function to call
+ *
+ * Returns: none
+ ****************************************************************************
+ */
+
+#define RC_OFFSET_PRESERVE_REGS ( 0 )
+#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS )
+#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
+#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
+
+	.section ".text", "ax", @progbits
+	.code32
+	.globl real_call
+real_call:
+	/* Create register dump and function pointer copy on PM stack */
+	pushal
+	pushl	RC_OFFSET_FUNCTION(%esp)
+
+	/* Switch to real mode and move register dump to RM stack  */
+	movl	$( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
+	pushl	$1f
+	jmp	prot_to_real
+	.section ".text16", "ax", @progbits
+	.code16
+1:
+	/* Call real-mode function */
+	popl	rc_function
+	popal
+	call	*rc_function
+	pushal
+
+	/* For sanity's sake, clear the direction flag as soon as possible */
+	cld
+
+	/* Switch to protected mode and move register dump back to PM stack */
+	movl	$RC_OFFSET_RETADDR, %ecx
+	pushl	$1f
+	jmp	real_to_prot
+	.section ".text", "ax", @progbits
+	.code32
+1:
+	/* Restore registers and return */
+	popal
+	ret
+
+
+	/* Function vector, used because "call xx(%sp)" is not a valid
+	 * 16-bit expression.
+	 */
+	.section ".data16", "aw", @progbits
+rc_function:	.word 0, 0
+
+/****************************************************************************
+ * Stored real-mode and protected-mode stack pointers
+ *
+ * The real-mode stack pointer is stored here whenever real_to_prot
+ * is called and restored whenever prot_to_real is called.  The
+ * converse happens for the protected-mode stack pointer.
+ *
+ * Despite initial appearances this scheme is, in fact re-entrant,
+ * because program flow dictates that we always return via the point
+ * we left by.  For example:
+ *    PXE API call entry
+ *  1   real => prot
+ *        ...
+ *        Print a text string
+ *	    ...
+ *  2       prot => real
+ *            INT 10
+ *  3       real => prot
+ *	    ...
+ *        ...
+ *  4   prot => real
+ *    PXE API call exit
+ *
+ * At point 1, the RM mode stack value, say RPXE, is stored in
+ * rm_ss,sp.  We want this value to still be present in rm_ss,sp when
+ * we reach point 4.
+ *
+ * At point 2, the RM stack value is restored from RPXE.  At point 3,
+ * the RM stack value is again stored in rm_ss,sp.  This *does*
+ * overwrite the RPXE that we have stored there, but it's the same
+ * value, since the code between points 2 and 3 has managed to return
+ * to us.
+ ****************************************************************************
+ */
+	.section ".data", "aw", @progbits
+	.globl rm_sp
+rm_sp:	.word 0
+	.globl rm_ss
+rm_ss:	.word 0
+pm_esp:	.long _estack
+
+/****************************************************************************
+ * Virtual address offsets
+ *
+ * These are used by the protected-mode code to map between virtual
+ * and physical addresses, and to access variables in the .text16 or
+ * .data16 segments.
+ ****************************************************************************
+ */
+	/* Internal copies, created by init_librm (which runs in real mode) */
+	.section ".data16", "aw", @progbits
+_virt_offset:	.long 0
+_text16:	.long 0
+_data16:	.long 0
+
+	/* Externally-visible copies, created by real_to_prot */
+	.section ".data", "aw", @progbits
+	.globl virt_offset
+virt_offset:	.long 0	
+	.globl text16
+text16:		.long 0
+	.globl data16
+data16:		.long 0
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
new file mode 100644
index 0000000..f00be81
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
@@ -0,0 +1,58 @@
+/*
+ * librm: a library for interfacing to real-mode code
+ *
+ * Michael Brown <mbrown at fensystems.co.uk>
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+
+/*
+ * This file provides functions for managing librm.
+ *
+ */
+
+/**
+ * Allocate space on the real-mode stack and copy data there from a
+ * user buffer
+ *
+ * @v data			User buffer
+ * @v size			Size of stack data
+ * @ret sp			New value of real-mode stack pointer
+ */
+uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
+	userptr_t rm_stack;
+	rm_sp -= size;
+	rm_stack = real_to_user ( rm_ss, rm_sp );
+	memcpy_user ( rm_stack, 0, data, 0, size );
+	return rm_sp;
+};
+
+/**
+ * Deallocate space on the real-mode stack, optionally copying back
+ * data to a user buffer.
+ *
+ * @v data			User buffer
+ * @v size			Size of stack data
+ */
+void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
+	if ( data ) {
+		userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
+		memcpy_user ( rm_stack, 0, data, 0, size );
+	}
+	rm_sp += size;
+};
+
+PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
+PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
+PROVIDE_UACCESS_INLINE ( librm, userptr_add );
+PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
+PROVIDE_UACCESS_INLINE ( librm, memmove_user );
+PROVIDE_UACCESS_INLINE ( librm, memset_user );
+PROVIDE_UACCESS_INLINE ( librm, strlen_user );
+PROVIDE_UACCESS_INLINE ( librm, memchr_user );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile
new file mode 100644
index 0000000..37e03aa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile
@@ -0,0 +1,15 @@
+# Include common x86 headers
+#
+INCDIRS		+= arch/x86/include
+
+# x86-specific directories containing source files
+#
+SRCDIRS		+= arch/x86/core
+SRCDIRS		+= arch/x86/interface/efi
+SRCDIRS		+= arch/x86/prefix
+
+# breaks building some of the linux-related objects
+CFLAGS		+= -Ulinux
+
+# disable valgrind
+CFLAGS		+= -DNVALGRIND
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.efi b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.efi
new file mode 100644
index 0000000..bef8d59
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.efi
@@ -0,0 +1,28 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The EFI linker script
+#
+LDSCRIPT	= arch/x86/scripts/efi.lds
+
+# Retain relocation information for elf2efi
+#
+LDFLAGS		+= -q -S
+
+# Media types.
+#
+NON_AUTO_MEDIA	+= efi
+NON_AUTO_MEDIA	+= efidrv
+
+# Rules for building EFI files
+#
+$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI)
+	$(QM)$(ECHO) "  [FINISH] $@"
+	$(Q)$(ELF2EFI) --subsystem=10 $< $@
+
+$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI)
+	$(QM)$(ECHO) "  [FINISH] $@"
+	$(Q)$(ELF2EFI) --subsystem=11 $< $@
+
+$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
+	$(QM)$(ECHO) "  [FINISH] $@"
+	$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.linux b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.linux
new file mode 100644
index 0000000..e35b04f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/Makefile.linux
@@ -0,0 +1,13 @@
+MEDIA = linux
+
+# enable valgrind
+CFLAGS += -UNVALGRIND
+
+INCDIRS += arch/x86/include/linux
+SRCDIRS += interface/linux
+SRCDIRS += drivers/linux
+SRCDIRS += arch/x86/core/linux
+
+$(BIN)/%.linux : $(BIN)/%.linux.tmp
+	$(QM)$(ECHO) "  [FINISH] $@"
+	$(Q)cp -p $< $@
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_api.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_api.c
new file mode 100644
index 0000000..c8a09b7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_api.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Implementation of most of the linux API.
+ */
+
+#include <linux_api.h>
+
+#include <stdarg.h>
+#include <asm/unistd.h>
+#include <string.h>
+
+int linux_open ( const char *pathname, int flags ) {
+	return linux_syscall ( __NR_open, pathname, flags );
+}
+
+int linux_close ( int fd ) {
+	return linux_syscall ( __NR_close, fd );
+}
+
+__kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) {
+	return linux_syscall ( __NR_read, fd, buf, count );
+}
+
+__kernel_ssize_t linux_write ( int fd, const void *buf,
+			       __kernel_size_t count ) {
+	return linux_syscall  (  __NR_write, fd, buf, count );
+}
+
+int linux_fcntl ( int fd, int cmd, ... ) {
+	long arg;
+	va_list list;
+
+	va_start ( list, cmd );
+	arg = va_arg ( list, long );
+	va_end ( list );
+
+	return linux_syscall ( __NR_fcntl, fd, cmd, arg );
+}
+
+int linux_ioctl ( int fd, int request, ... ) {
+	void *arg;
+	va_list list;
+
+	va_start ( list, request );
+	arg = va_arg ( list, void * );
+	va_end ( list );
+
+	return linux_syscall ( __NR_ioctl, fd, request, arg );
+}
+
+int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ) {
+	return linux_syscall ( __NR_poll, fds, nfds, timeout );
+}
+
+int linux_nanosleep ( const struct timespec *req, struct timespec *rem ) {
+	return linux_syscall ( __NR_nanosleep, req, rem );
+}
+
+int linux_usleep ( useconds_t usec ) {
+	struct timespec ts = {
+		.tv_sec = ( ( long ) ( usec / 1000000 ) ),
+		.tv_nsec = ( ( long ) ( usec % 1000000 ) * 1000UL ),
+	};
+
+	return linux_nanosleep ( &ts, NULL );
+}
+
+int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) {
+	return linux_syscall ( __NR_gettimeofday, tv, tz );
+}
+
+void * linux_mmap ( void *addr, __kernel_size_t length, int prot, int flags,
+		    int fd, __kernel_off_t offset ) {
+	return ( void * ) linux_syscall ( __SYSCALL_mmap, addr, length, prot,
+					  flags, fd, offset );
+}
+
+void * linux_mremap ( void *old_address, __kernel_size_t old_size,
+		      __kernel_size_t new_size, int flags ) {
+	return ( void * ) linux_syscall ( __NR_mremap, old_address, old_size,
+					  new_size, flags );
+}
+
+int linux_munmap ( void *addr, __kernel_size_t length ) {
+	return linux_syscall ( __NR_munmap, addr, length );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_strerror.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_strerror.c
new file mode 100644
index 0000000..24c9b77
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/linux/linux_strerror.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * linux_strerror implementation
+ */
+
+#include <linux_api.h>
+#include <stdio.h>
+
+/** Error names from glibc */
+static const char *errors[] = {
+	"Success",
+	"Operation not permitted",
+	"No such file or directory",
+	"No such process",
+	"Interrupted system call",
+	"Input/output error",
+	"No such device or address",
+	"Argument list too long",
+	"Exec format error",
+	"Bad file descriptor",
+	"No child processes",
+	"Resource temporarily unavailable",
+	"Cannot allocate memory",
+	"Permission denied",
+	"Bad address",
+	"Block device required",
+	"Device or resource busy",
+	"File exists",
+	"Invalid cross-device link",
+	"No such device",
+	"Not a directory",
+	"Is a directory",
+	"Invalid argument",
+	"Too many open files in system",
+	"Too many open files",
+	"Inappropriate ioctl for device",
+	"Text file busy",
+	"File too large",
+	"No space left on device",
+	"Illegal seek",
+	"Read-only file system",
+	"Too many links",
+	"Broken pipe",
+	"Numerical argument out of domain",
+	"Numerical result out of range",
+	"Resource deadlock avoided",
+	"File name too long",
+	"No locks available",
+	"Function not implemented",
+	"Directory not empty",
+	"Too many levels of symbolic links",
+	"",
+	"No message of desired type",
+	"Identifier removed",
+	"Channel number out of range",
+	"Level 2 not synchronized",
+	"Level 3 halted",
+	"Level 3 reset",
+	"Link number out of range",
+	"Protocol driver not attached",
+	"No CSI structure available",
+	"Level 2 halted",
+	"Invalid exchange",
+	"Invalid request descriptor",
+	"Exchange full",
+	"No anode",
+	"Invalid request code",
+	"Invalid slot",
+	"",
+	"Bad font file format",
+	"Device not a stream",
+	"No data available",
+	"Timer expired",
+	"Out of streams resources",
+	"Machine is not on the network",
+	"Package not installed",
+	"Object is remote",
+	"Link has been severed",
+	"Advertise error",
+	"Srmount error",
+	"Communication error on send",
+	"Protocol error",
+	"Multihop attempted",
+	"RFS specific error",
+	"Bad message",
+	"Value too large for defined data type",
+	"Name not unique on network",
+	"File descriptor in bad state",
+	"Remote address changed",
+	"Can not access a needed shared library",
+	"Accessing a corrupted shared library",
+	".lib section in a.out corrupted",
+	"Attempting to link in too many shared libraries",
+	"Cannot exec a shared library directly",
+	"Invalid or incomplete multibyte or wide character",
+	"Interrupted system call should be restarted",
+	"Streams pipe error",
+	"Too many users",
+	"Socket operation on non-socket",
+	"Destination address required",
+	"Message too long",
+	"Protocol wrong type for socket",
+	"Protocol not available",
+	"Protocol not supported",
+	"Socket type not supported",
+	"Operation not supported",
+	"Protocol family not supported",
+	"Address family not supported by protocol",
+	"Address already in use",
+	"Cannot assign requested address",
+	"Network is down",
+	"Network is unreachable",
+	"Network dropped connection on reset",
+	"Software caused connection abort",
+	"Connection reset by peer",
+	"No buffer space available",
+	"Transport endpoint is already connected",
+	"Transport endpoint is not connected",
+	"Cannot send after transport endpoint shutdown",
+	"Too many references: cannot splice",
+	"Connection timed out",
+	"Connection refused",
+	"Host is down",
+	"No route to host",
+	"Operation already in progress",
+	"Operation now in progress",
+	"Stale NFS file handle",
+	"Structure needs cleaning",
+	"Not a XENIX named type file",
+	"No XENIX semaphores available",
+	"Is a named type file",
+	"Remote I/O error",
+	"Disk quota exceeded",
+	"No medium found",
+	"Wrong medium type",
+};
+
+const char *linux_strerror(int errnum)
+{
+	static char errbuf[64];
+	static int errors_size = sizeof(errors) / sizeof(*errors);
+	
+	if (errnum >= errors_size || errnum < 0) {
+		snprintf(errbuf, sizeof(errbuf), "Error %#08x", errnum);
+		return errbuf;
+	} else {
+		return errors[errnum];
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/core/pcidirect.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/pcidirect.c
new file mode 100644
index 0000000..a07f7d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/pcidirect.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+
+/** @file
+ *
+ * PCI configuration space access via Type 1 accesses
+ *
+ */
+
+/**
+ * Prepare for Type 1 PCI configuration space access
+ *
+ * @v pci		PCI device
+ * @v where	Location within PCI configuration space
+ */
+void pcidirect_prepare ( struct pci_device *pci, int where ) {
+	outl ( ( 0x80000000 | ( pci->busdevfn << 8 ) | ( where & ~3 ) ),
+	       PCIDIRECT_CONFIG_ADDRESS );
+}
+
+PROVIDE_PCIAPI_INLINE ( direct, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/core/x86_string.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/x86_string.c
new file mode 100644
index 0000000..5838eba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/core/x86_string.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * Optimised string operations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+
+/**
+ * Copy memory area
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+void * __memcpy ( void *dest, const void *src, size_t len ) {
+	void *edi = dest;
+	const void *esi = src;
+	int discard_ecx;
+
+	/* We often do large dword-aligned and dword-length block
+	 * moves.  Using movsl rather than movsb speeds these up by
+	 * around 32%.
+	 */
+	if ( len >> 2 ) {
+		__asm__ __volatile__ ( "rep movsl"
+				       : "=&D" ( edi ), "=&S" ( esi ),
+				         "=&c" ( discard_ecx )
+				       : "0" ( edi ), "1" ( esi ),
+				         "2" ( len >> 2 )
+				       : "memory" );
+	}
+	if ( len & 0x02 ) {
+		__asm__ __volatile__ ( "movsw" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	}
+	if ( len & 0x01 ) {
+		__asm__ __volatile__ ( "movsb" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	}
+	return dest;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/linux_api_platform.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/linux_api_platform.h
new file mode 100644
index 0000000..4a9ced5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/linux_api_platform.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_API_PLATFORM_H
+#define _LINUX_API_PLATFORM_H
+
+extern int linux_errno;
+
+#endif /* _LINUX_API_PLATFORM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/pci_io.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/pci_io.h
new file mode 100644
index 0000000..01b1232
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/pci_io.h
@@ -0,0 +1,15 @@
+#ifndef _BITS_PCI_IO_H
+#define _BITS_PCI_IO_H
+
+/** @file
+ *
+ * i386-specific PCI I/O API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/pcibios.h>
+#include <ipxe/pcidirect.h>
+
+#endif /* _BITS_PCI_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/string.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/string.h
new file mode 100644
index 0000000..f35cdab
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/bits/string.h
@@ -0,0 +1,252 @@
+#ifndef ETHERBOOT_BITS_STRING_H
+#define ETHERBOOT_BITS_STRING_H
+/*
+ * Taken from Linux /usr/include/asm/string.h
+ * All except memcpy, memmove, memset and memcmp removed.
+ *
+ * Non-standard memswap() function added because it saves quite a bit
+ * of code (mbrown at fensystems.co.uk).
+ */
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ *		NO Copyright (C) 1991, 1992 Linus Torvalds,
+ *		consider these trivial functions to be PD.
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#define __HAVE_ARCH_MEMCPY
+
+extern void * __memcpy ( void *dest, const void *src, size_t len );
+
+#if 0
+static inline __attribute__ (( always_inline )) void *
+__memcpy ( void *dest, const void *src, size_t len ) {
+	int d0, d1, d2;
+	__asm__ __volatile__ ( "rep ; movsb"
+			       : "=&c" ( d0 ), "=&S" ( d1 ), "=&D" ( d2 )
+			       : "0" ( len ), "1" ( src ), "2" ( dest )
+			       : "memory" );
+	return dest; 
+}
+#endif
+
+static inline __attribute__ (( always_inline )) void *
+__constant_memcpy ( void *dest, const void *src, size_t len ) {
+	union {
+		uint32_t u32[2];
+		uint16_t u16[4];
+		uint8_t  u8[8];
+	} __attribute__ (( __may_alias__ )) *dest_u = dest;
+	const union {
+		uint32_t u32[2];
+		uint16_t u16[4];
+		uint8_t  u8[8];
+	} __attribute__ (( __may_alias__ )) *src_u = src;
+	const void *esi;
+	void *edi;
+
+	switch ( len ) {
+	case 0 : /* 0 bytes */
+		return dest;
+	/*
+	 * Single-register moves; these are always better than a
+	 * string operation.  We can clobber an arbitrary two
+	 * registers (data, source, dest can re-use source register)
+	 * instead of being restricted to esi and edi.  There's also a
+	 * much greater potential for optimising with nearby code.
+	 *
+	 */
+	case 1 : /* 4 bytes */
+		dest_u->u8[0]  = src_u->u8[0];
+		return dest;
+	case 2 : /* 6 bytes */
+		dest_u->u16[0] = src_u->u16[0];
+		return dest;
+	case 4 : /* 4 bytes */
+		dest_u->u32[0] = src_u->u32[0];
+		return dest;
+	/*
+	 * Double-register moves; these are probably still a win.
+	 *
+	 */
+	case 3 : /* 12 bytes */
+		dest_u->u16[0] = src_u->u16[0];
+		dest_u->u8[2]  = src_u->u8[2];
+		return dest;
+	case 5 : /* 10 bytes */
+		dest_u->u32[0] = src_u->u32[0];
+		dest_u->u8[4]  = src_u->u8[4];
+		return dest;
+	case 6 : /* 12 bytes */
+		dest_u->u32[0] = src_u->u32[0];
+		dest_u->u16[2] = src_u->u16[2];
+		return dest;
+	case 8 : /* 10 bytes */
+		dest_u->u32[0] = src_u->u32[0];
+		dest_u->u32[1] = src_u->u32[1];
+		return dest;
+	}
+
+	/* Even if we have to load up esi and edi ready for a string
+	 * operation, we can sometimes save space by using multiple
+	 * single-byte "movs" operations instead of loading up ecx and
+	 * using "rep movsb".
+	 *
+	 * "load ecx, rep movsb" is 7 bytes, plus an average of 1 byte
+	 * to allow for saving/restoring ecx 50% of the time.
+	 *
+	 * "movsl" and "movsb" are 1 byte each, "movsw" is two bytes.
+	 * (In 16-bit mode, "movsl" is 2 bytes and "movsw" is 1 byte,
+	 * but "movsl" moves twice as much data, so it balances out).
+	 *
+	 * The cutoff point therefore occurs around 26 bytes; the byte
+	 * requirements for each method are:
+	 *
+	 * len		   16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+	 * #bytes (ecx)	    8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
+	 * #bytes (no ecx)  4  5  6  7  5  6  7  8  6  7  8  9  7  8  9 10
+	 */
+
+	esi = src;
+	edi = dest;
+	
+	if ( len >= 26 )
+		return __memcpy ( dest, src, len );
+	
+	if ( len >= 6*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( len >= 5*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( len >= 4*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( len >= 3*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( len >= 2*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( len >= 1*4 )
+		__asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( ( len % 4 ) >= 2 )
+		__asm__ __volatile__ ( "movsw" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	if ( ( len % 2 ) >= 1 )
+		__asm__ __volatile__ ( "movsb" : "=&D" ( edi ), "=&S" ( esi )
+				       : "0" ( edi ), "1" ( esi ) : "memory" );
+
+	return dest;
+}
+
+#define memcpy( dest, src, len )			\
+	( __builtin_constant_p ( (len) ) ?		\
+	  __constant_memcpy ( (dest), (src), (len) ) :	\
+	  __memcpy ( (dest), (src), (len) ) )
+
+#define __HAVE_ARCH_MEMMOVE
+static inline void * memmove(void * dest,const void * src, size_t n)
+{
+int d0, d1, d2;
+if (dest<src)
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep\n\t"
+	"movsb"
+	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n),"1" (src),"2" (dest)
+	: "memory");
+else
+__asm__ __volatile__(
+	"std\n\t"
+	"rep\n\t"
+	"movsb\n\t"
+	"cld"
+	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
+	:"0" (n),
+	 "1" (n-1+(const char *)src),
+	 "2" (n-1+(char *)dest)
+	:"memory");
+return dest;
+}
+
+#define __HAVE_ARCH_MEMSET
+static inline void * memset(void *s, int c,size_t count)
+{
+int d0, d1;
+__asm__ __volatile__(
+	"cld\n\t"
+	"rep\n\t"
+	"stosb"
+	: "=&c" (d0), "=&D" (d1)
+	:"a" (c),"1" (s),"0" (count)
+	:"memory");
+return s;
+}
+
+#define __HAVE_ARCH_MEMSWAP
+static inline void * memswap(void *dest, void *src, size_t n)
+{
+long d0, d1, d2, d3;
+__asm__ __volatile__(
+	"\n1:\t"
+	"movb (%2),%%al\n\t"
+	"xchgb (%1),%%al\n\t"
+	"inc %1\n\t"
+	"stosb\n\t"
+	"loop 1b"
+	: "=&c" (d0), "=&S" (d1), "=&D" (d2), "=&a" (d3)
+	: "0" (n), "1" (src), "2" (dest)
+	: "memory" );
+return dest;
+}
+
+#define __HAVE_ARCH_STRNCMP
+static inline int strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res;
+int d0, d1, d2;
+__asm__ __volatile__(
+	"1:\tdecl %3\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"scasb\n\t"
+	"jne 3f\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n"
+	"2:\txorl %%eax,%%eax\n\t"
+	"jmp 4f\n"
+	"3:\tsbbl %%eax,%%eax\n\t"
+	"orb $1,%%al\n"
+	"4:"
+		     :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+		     :"1" (cs),"2" (ct),"3" (count));
+return __res;
+}
+
+#define __HAVE_ARCH_STRLEN
+static inline size_t strlen(const char * s)
+{
+int d0;
+register int __res;
+__asm__ __volatile__(
+	"repne\n\t"
+	"scasb\n\t"
+	"notl %0\n\t"
+	"decl %0"
+	:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
+return __res;
+}
+
+#endif /* ETHERBOOT_BITS_STRING_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
new file mode 100644
index 0000000..e85a272
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_EFIX86_NAP_H
+#define _IPXE_EFIX86_NAP_H
+
+/** @file
+ *
+ * EFI CPU sleeping
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef NAP_EFIX86
+#define NAP_PREFIX_efix86
+#else
+#define NAP_PREFIX_efix86 __efix86_
+#endif
+
+#endif /* _IPXE_EFIX86_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
new file mode 100644
index 0000000..36af7fc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
@@ -0,0 +1,135 @@
+#ifndef _IPXE_PCIBIOS_H
+#define _IPXE_PCIBIOS_H
+
+#include <stdint.h>
+
+/** @file
+ *
+ * PCI configuration space access via PCI BIOS
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef PCIAPI_PCBIOS
+#define PCIAPI_PREFIX_pcbios
+#else
+#define PCIAPI_PREFIX_pcbios __pcbios_
+#endif
+
+struct pci_device;
+
+#define PCIBIOS_INSTALLATION_CHECK	0xb1010000
+#define PCIBIOS_READ_CONFIG_BYTE	0xb1080000
+#define PCIBIOS_READ_CONFIG_WORD	0xb1090000
+#define PCIBIOS_READ_CONFIG_DWORD	0xb10a0000
+#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b0000
+#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c0000
+#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d0000
+
+extern int pcibios_read ( struct pci_device *pci, uint32_t command,
+			  uint32_t *value );
+extern int pcibios_write ( struct pci_device *pci, uint32_t command,
+			   uint32_t value );
+
+/**
+ * Read byte from PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_byte ) ( struct pci_device *pci,
+						 unsigned int where,
+						 uint8_t *value ) {
+	uint32_t tmp;
+	int rc;
+
+	rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_BYTE | where, &tmp );
+	*value = tmp;
+	return rc;
+}
+
+/**
+ * Read word from PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_word ) ( struct pci_device *pci,
+						 unsigned int where,
+						 uint16_t *value ) {
+	uint32_t tmp;
+	int rc;
+
+	rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_WORD | where, &tmp );
+	*value = tmp;
+	return rc;
+}
+
+/**
+ * Read dword from PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_dword ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint32_t *value ) {
+	return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value );
+}
+
+/**
+ * Write byte to PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_byte ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint8_t value ) {
+	return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value );
+}
+
+/**
+ * Write word to PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_word ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint16_t value ) {
+	return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value );
+}
+
+/**
+ * Write dword to PCI configuration space via PCI BIOS
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci,
+						   unsigned int where,
+						   uint32_t value ) {
+	return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value);
+}
+
+#endif /* _IPXE_PCIBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
new file mode 100644
index 0000000..7fa7c4f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
@@ -0,0 +1,141 @@
+#ifndef _PCIDIRECT_H
+#define _PCIDIRECT_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/io.h>
+
+#ifdef PCIAPI_DIRECT
+#define PCIAPI_PREFIX_direct
+#else
+#define PCIAPI_PREFIX_direct __direct_
+#endif
+
+/** @file
+ *
+ * PCI configuration space access via Type 1 accesses
+ *
+ */
+
+#define PCIDIRECT_CONFIG_ADDRESS	0xcf8
+#define PCIDIRECT_CONFIG_DATA		0xcfc
+
+struct pci_device;
+
+extern void pcidirect_prepare ( struct pci_device *pci, int where );
+
+/**
+ * Determine number of PCI buses within system
+ *
+ * @ret num_bus		Number of buses
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
+	/* No way to work this out via Type 1 accesses */
+	return 0x100;
+}
+
+/**
+ * Read byte from PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_byte ) ( struct pci_device *pci,
+						 unsigned int where,
+						 uint8_t *value ) {
+	pcidirect_prepare ( pci, where );
+	*value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
+	return 0;
+}
+
+/**
+ * Read word from PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_word ) ( struct pci_device *pci,
+						 unsigned int where,
+						 uint16_t *value ) {
+	pcidirect_prepare ( pci, where );
+	*value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
+	return 0;
+}
+
+/**
+ * Read dword from PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_dword ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint32_t *value ) {
+	pcidirect_prepare ( pci, where );
+	*value = inl ( PCIDIRECT_CONFIG_DATA );
+	return 0;
+}
+
+/**
+ * Write byte to PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_byte ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint8_t value ) {
+	pcidirect_prepare ( pci, where );
+	outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
+	return 0;
+}
+
+/**
+ * Write word to PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_word ) ( struct pci_device *pci,
+						  unsigned int where,
+						  uint16_t value ) {
+	pcidirect_prepare ( pci, where );
+	outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
+	return 0;
+}
+
+/**
+ * Write dword to PCI configuration space via Type 1 access
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci,
+						   unsigned int where,
+						   uint32_t value ) {
+	pcidirect_prepare ( pci, where );
+	outl ( value, PCIDIRECT_CONFIG_DATA );
+	return 0;
+}
+
+#endif /* _PCIDIRECT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
new file mode 100644
index 0000000..e83fd9d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LINUX_DHCP_ARCH_H
+#define _LINUX_DHCP_ARCH_H
+
+/** @file
+ *
+ * Architecture-specific DHCP options
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/dhcp.h>
+
+// Emulate one of the supported arch-platforms
+#include <arch/i386/include/pcbios/ipxe/dhcp_arch.h>
+//#include <arch/i386/include/efi/ipxe/dhcp_arch.h>
+//#include <arch/x86_64/include/efi/ipxe/dhcp_arch.h>
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h
new file mode 100644
index 0000000..46d2343
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h
@@ -0,0 +1,309 @@
+
+/*
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (memcheck.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of MemCheck, a heavyweight Valgrind tool for
+   detecting memory errors.
+
+   Copyright (C) 2000-2010 Julian Seward.  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. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (memcheck.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+#ifndef __MEMCHECK_H
+#define __MEMCHECK_H
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query memory permissions
+   inside your own programs.
+
+   See comment near the top of valgrind.h on how to use them.
+*/
+
+#include "valgrind.h"
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { 
+      VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
+      VG_USERREQ__MAKE_MEM_UNDEFINED,
+      VG_USERREQ__MAKE_MEM_DEFINED,
+      VG_USERREQ__DISCARD,
+      VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
+      VG_USERREQ__CHECK_MEM_IS_DEFINED,
+      VG_USERREQ__DO_LEAK_CHECK,
+      VG_USERREQ__COUNT_LEAKS,
+
+      VG_USERREQ__GET_VBITS,
+      VG_USERREQ__SET_VBITS,
+
+      VG_USERREQ__CREATE_BLOCK,
+
+      VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
+
+      /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
+      VG_USERREQ__COUNT_LEAK_BLOCKS,
+
+      /* This is just for memcheck's internal use - don't use it */
+      _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR 
+         = VG_USERREQ_TOOL_BASE('M','C') + 256
+   } Vg_MemCheckClientRequest;
+
+
+
+/* Client-code macros to manipulate the state of memory. */
+
+/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len)           \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__MAKE_MEM_NOACCESS,       \
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+      
+/* Similarly, mark memory at _qzz_addr as addressable but undefined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len)          \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__MAKE_MEM_UNDEFINED,      \
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+
+/* Similarly, mark memory at _qzz_addr as addressable and defined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len)            \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__MAKE_MEM_DEFINED,        \
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+
+/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
+   not altered: bytes which are addressable are marked as defined,
+   but those which are not addressable are left unchanged. */
+#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+
+/* Create a block-description handle.  The description is an ascii
+   string which is included in any messages pertaining to addresses
+   within the specified memory range.  Has no other effect on the
+   properties of the memory range. */
+#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc)	 \
+	(__extension__({unsigned long _qzz_res;			 \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__CREATE_BLOCK,            \
+                            _qzz_addr, _qzz_len, _qzz_desc,      \
+                            0, 0);                               \
+    _qzz_res;							 \
+   }))
+
+/* Discard a block-description-handle. Returns 1 for an
+   invalid handle, 0 for a valid handle. */
+#define VALGRIND_DISCARD(_qzz_blkindex)                          \
+   (__extension__ ({unsigned long _qzz_res;                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* default return */, \
+                            VG_USERREQ__DISCARD,                 \
+                            0, _qzz_blkindex, 0, 0, 0);          \
+    _qzz_res;                                                    \
+   }))
+
+
+/* Client-code macros to check the state of memory. */
+
+/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
+   If suitable addressibility is not established, Valgrind prints an
+   error message and returns the address of the first offending byte.
+   Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len)    \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,\
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+
+/* Check that memory at _qzz_addr is addressable and defined for
+   _qzz_len bytes.  If suitable addressibility and definedness are not
+   established, Valgrind prints an error message and returns the
+   address of the first offending byte.  Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len)        \
+   (__extension__({unsigned long _qzz_res;                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__CHECK_MEM_IS_DEFINED,    \
+                            _qzz_addr, _qzz_len, 0, 0, 0);       \
+    _qzz_res;                                                    \
+   }))
+
+/* Use this macro to force the definedness and addressibility of an
+   lvalue to be checked.  If suitable addressibility and definedness
+   are not established, Valgrind prints an error message and returns
+   the address of the first offending byte.  Otherwise it returns
+   zero. */
+#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue)                \
+   VALGRIND_CHECK_MEM_IS_DEFINED(                                \
+      (volatile unsigned char *)&(__lvalue),                     \
+                      (unsigned long)(sizeof (__lvalue)))
+
+
+/* Do a full memory leak check (like --leak-check=full) mid-execution. */
+#define VALGRIND_DO_LEAK_CHECK                                   \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 0, 0, 0, 0);                      \
+   }
+
+/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
+#define VALGRIND_DO_QUICK_LEAK_CHECK				 \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            1, 0, 0, 0, 0);                      \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed)     \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAKS,                  \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAK_BLOCKS,            \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+
+/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
+   into the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zzsrc/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes)                 \
+   (__extension__({unsigned long _qzz_res;                       \
+    char* czza     = (char*)zza;                                 \
+    char* czzvbits = (char*)zzvbits;                             \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__GET_VBITS,               \
+                            czza, czzvbits, zznbytes, 0, 0 );    \
+    _qzz_res;                                                    \
+   }))
+
+/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
+   from the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zza/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes)                 \
+   (__extension__({unsigned int _qzz_res;                        \
+    char* czza     = (char*)zza;                                 \
+    char* czzvbits = (char*)zzvbits;                             \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__SET_VBITS,               \
+                            czza, czzvbits, zznbytes, 0, 0 );    \
+    _qzz_res;                                                    \
+   }))
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h
new file mode 100644
index 0000000..d72754b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h
@@ -0,0 +1,4536 @@
+/* -*- c -*-
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (valgrind.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2010 Julian Seward.  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. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (valgrind.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query Valgrind's 
+   execution inside your own programs.
+
+   The resulting executables will still run without Valgrind, just a
+   little bit more slowly than they otherwise would, but otherwise
+   unchanged.  When not running on valgrind, each client request
+   consumes very few (eg. 7) instructions, so the resulting performance
+   loss is negligible unless you plan to execute client requests
+   millions of times per second.  Nevertheless, if that is still a
+   problem, you can compile with the NVALGRIND symbol defined (gcc
+   -DNVALGRIND) so that client requests are not even compiled in.  */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND                                         */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+   conditionally compile based on our version number.  Note that these
+   were introduced at version 3.6 and so do not exist in version 3.5
+   or earlier.  The recommended way to use them to check for "version
+   X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
+    && (__VALGRIND_MAJOR__ > 3                                   \
+        || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__    3
+#define __VALGRIND_MINOR__    6
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi.  So
+   we can't use C++ style "//" comments nor the "asm" keyword (instead
+   use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is.  Note
+   that in this file we're using the compiler's CPP symbols for
+   identifying architectures, which are different to the ones we use
+   within the rest of Valgrind.  Note, __powerpc__ is active for both
+   32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+   latter (on Linux, that is).
+
+   Misc note: how to find out what's predefined in gcc by default:
+   gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_ppc64_aix5
+#undef PLAT_ppc32_aix5
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+
+#if defined(_AIX) && defined(__64BIT__)
+#  define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+#  define PLAT_ppc32_aix5 1
+#elif defined(__APPLE__) && defined(__i386__)
+#  define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+#  define PLAT_amd64_darwin 1
+#elif defined(__linux__) && defined(__i386__)
+#  define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__)
+#  define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+#  define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
+#  define PLAT_ppc64_linux 1
+#elif defined(__linux__) && defined(__arm__)
+#  define PLAT_arm_linux 1
+#else
+/* If we're not compiling for our target platform, don't generate
+   any inline asms.  */
+#  if !defined(NVALGRIND)
+#    define NVALGRIND 1
+#  endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS.  There is nothing */
+/* in here of use to end-users -- skip to the next section.           */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+   from the compiled code (analogous to NDEBUG's effects on
+   assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+   {                                                              \
+      (_zzq_rlval) = (_zzq_default);                              \
+   }
+
+#else  /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+   spots and handles magically.  Don't look too closely at them as
+   they will rot your brain.
+
+   The assembly code sequences for all architectures is in this one
+   file.  This is because this file must be stand-alone, and we don't
+   want to have multiple files.
+
+   For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+   value gets put in the return slot, so that everything works when
+   this is executed not under Valgrind.  Args are passed in a memory
+   block, and so there's no intrinsic limit to the number that could
+   be passed, but it's currently five.
+   
+   The macro args are: 
+      _zzq_rlval    result lvalue
+      _zzq_default  default value (result returned when running on real CPU)
+      _zzq_request  request code
+      _zzq_arg1..5  request params
+
+   The other two macros are used to support function wrapping, and are
+   a lot simpler.  VALGRIND_GET_NR_CONTEXT returns the value of the
+   guest's NRADDR pseudo-register and whatever other information is
+   needed to safely run the call original from the wrapper: on
+   ppc64-linux, the R2 value at the divert point is also needed.  This
+   information is abstracted into a user-visible type, OrigFn.
+
+   VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+   guest, but guarantees that the branch instruction will not be
+   redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+   branch-and-link-to-r11.  VALGRIND_CALL_NOREDIR is just text, not a
+   complete inline asm, since it needs to be combined with more magic
+   inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "roll $3,  %%edi ; roll $13, %%edi\n\t"      \
+                     "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned int _zzq_args[6];                           \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EDX = client_request ( %EAX ) */         \
+                     "xchgl %%ebx,%%ebx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EAX = guest_NRADDR */                    \
+                     "xchgl %%ecx,%%ecx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%EAX */                     \
+                     "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rolq $3,  %%rdi ; rolq $13, %%rdi\n\t"      \
+                     "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned long long int _zzq_args[6];                 \
+    volatile unsigned long long int _zzq_result;                  \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RDX = client_request ( %RAX ) */         \
+                     "xchgq %%rbx,%%rbx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RAX = guest_NRADDR */                    \
+                     "xchgq %%rcx,%%rcx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_RAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%RAX */                     \
+                     "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[6];                          \
+             unsigned int  _zzq_result;                           \
+             unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 3,%1\n\t" /*default*/                    \
+                     "mr 4,%2\n\t" /*ptr*/                        \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"     /*result*/                     \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_default), "b" (_zzq_ptr)         \
+                     : "cc", "memory", "r3", "r4");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[6];                \
+    register unsigned long long int  _zzq_result __asm__("r3");   \
+    register unsigned long long int* _zzq_ptr __asm__("r4");      \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1"                                   \
+                     : "=r" (_zzq_result)                         \
+                     : "0" (_zzq_default), "r" (_zzq_ptr)         \
+                     : "cc", "memory");                           \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr __asm__("r3");         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+            "mov r12, r12, ror #3  ; mov r12, r12, ror #13 \n\t"  \
+            "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  { volatile unsigned int  _zzq_args[6];                          \
+    volatile unsigned int  _zzq_result;                           \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile("mov r3, %1\n\t" /*default*/                 \
+                     "mov r4, %2\n\t" /*ptr*/                     \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = client_request ( R4 ) */             \
+                     "orr r10, r10, r10\n\t"                      \
+                     "mov %0, r3"     /*result*/                  \
+                     : "=r" (_zzq_result)                         \
+                     : "r" (_zzq_default), "r" (&_zzq_args[0])    \
+                     : "cc","memory", "r3", "r4");                \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = guest_NRADDR */                      \
+                     "orr r11, r11, r11\n\t"                      \
+                     "mov %0, r3"                                 \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                    \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R4 */        \
+                     "orr r12, r12, r12\n\t"
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+      unsigned int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[7];                          \
+    register unsigned int  _zzq_result;                           \
+    register unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_args[6] = (unsigned int)(_zzq_default);                  \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "lwz 3, 24(4)\n\t"                           \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[7];                \
+    register unsigned long long int  _zzq_result;                 \
+    register unsigned long long int* _zzq_ptr;                    \
+    _zzq_args[0] = (unsigned int long long)(_zzq_request);        \
+    _zzq_args[1] = (unsigned int long long)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned int long long)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned int long long)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned int long long)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned int long long)(_zzq_arg5);           \
+    _zzq_args[6] = (unsigned int long long)(_zzq_default);        \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "ld 3, 48(4)\n\t"                            \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING.  This is all very        */
+/* ugly.  It's the least-worst tradeoff I can think of.               */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+   guaranteed-no-redirection macros, so as to get from function
+   wrappers to the functions they are wrapping.  The whole point is to
+   construct standard call sequences, but to do the call itself with a
+   special no-redirect call pseudo-instruction that the JIT
+   understands and handles specially.  This section is long and
+   repetitious, and I can't see a way to make it shorter.
+
+   The naming scheme is as follows:
+
+      CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+   'W' stands for "word" and 'v' for "void".  Hence there are
+   different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+   and for each, the possibility of returning a word-typed result, or
+   no result.
+*/
+
+/* Use these to write the name of your wrapper.  NOTE: duplicates
+   VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+   args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname)                    \
+   VG_CONCAT4(_vgwZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname)                    \
+   VG_CONCAT4(_vgwZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+   context (address and possibly other info) of the original function.
+   Once you have that you can then use it in one of the CALL_FN_
+   macros.  The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval)  VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+   returning void. */
+
+#define CALL_FN_v_v(fnptr)                                        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1)                                  \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2)                            \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3)                      \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4)                \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5)             \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6)        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7)   \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+
+/* These regs are trashed by the hidden call.  No need to mention eax
+   as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $4, %%esp\n"                                       \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $8, %%esp\n"                                       \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $12, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $20, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $24, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $28, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $36, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $40, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $44, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "pushl 48(%%eax)\n\t"                                    \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi",       \
+                            "rdi", "r8", "r9", "r10", "r11"
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+   long) == 8. */
+
+/* NB 9 Sept 07.  There is a nasty kludge here in all these CALL_FN_
+   macros.  In order not to trash the stack redzone, we need to drop
+   %rsp by 128 before the hidden call, and restore afterwards.  The
+   nastyness is that it is only by luck that the stack still appears
+   to be unwindable during the hidden call - since then the behaviour
+   of any routine using this macro does not match what the CFI data
+   says.  Sigh.
+
+   Why is this important?  Imagine that a wrapper has a stack
+   allocated local, and passes to the hidden call, a pointer to it.
+   Because gcc does not know about the hidden call, it may allocate
+   that local in the redzone.  Unfortunately the hidden call may then
+   trash it before it comes to use it.  So we must step clear of the
+   redzone, for the duration of the hidden call, to make it safe.
+
+   Probably the same problem afflicts the other redzone-style ABIs too
+   (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+   self describing (none of this CFI nonsense) so at least messing
+   with the stack pointer doesn't give a danger of non-unwindable
+   stack. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $8, %%rsp\n"                                       \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $16, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $24, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $32, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $40, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 96(%%rax)\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $48, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+   extern int f9  ( int,int,int,int,int,int,int,int,int );
+   extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+   extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+   extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+   int g9 ( void ) {
+      return f9(11,22,33,44,55,66,77,88,99);
+   }
+   int g10 ( void ) {
+      return f10(11,22,33,44,55,66,77,88,99,110);
+   }
+   int g11 ( void ) {
+      return f11(11,22,33,44,55,66,77,88,99,110,121);
+   }
+   int g12 ( void ) {
+      return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+   }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux, 
+   sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      _argvec[12] = (unsigned long)arg12;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,20(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",  __CALLER_SAVED_REGS         \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #4 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #8 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #12 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "push {r0, r1, r2, r3} \n\t"                             \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #16 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #20 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #24 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #28 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS           \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "ldr r2, [%1, #48] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #32 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "lwz  3," #_n_fr "(1)\n\t"                               \
+         "stw  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t" /* arg2->r4 */                       \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,68(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "ld   3," #_n_fr "(1)\n\t"                               \
+         "std  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS.               */
+/*                                                                    */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes.  There are many more of these, but most are not
+   exposed to end-user view.  These are the public ones, all of the
+   form 0x1000 + small_number.
+
+   Core ones are in the range 0x00000000--0x0000ffff.  The non-public
+   ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+   embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+   ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+   (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { VG_USERREQ__RUNNING_ON_VALGRIND  = 0x1001,
+          VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+          /* These allow any function to be called from the simulated
+             CPU but run on the real CPU.  Nb: the first arg passed to
+             the function is always the ThreadId of the running
+             thread!  So CLIENT_CALL0 actually requires a 1 arg
+             function, etc. */
+          VG_USERREQ__CLIENT_CALL0 = 0x1101,
+          VG_USERREQ__CLIENT_CALL1 = 0x1102,
+          VG_USERREQ__CLIENT_CALL2 = 0x1103,
+          VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+          /* Can be useful in regression testing suites -- eg. can
+             send Valgrind's output to /dev/null and still count
+             errors. */
+          VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+          /* These are useful and can be interpreted by any tool that
+             tracks malloc() et al, by using vg_replace_malloc.c. */
+          VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+          VG_USERREQ__FREELIKE_BLOCK   = 0x1302,
+          /* Memory pool support. */
+          VG_USERREQ__CREATE_MEMPOOL   = 0x1303,
+          VG_USERREQ__DESTROY_MEMPOOL  = 0x1304,
+          VG_USERREQ__MEMPOOL_ALLOC    = 0x1305,
+          VG_USERREQ__MEMPOOL_FREE     = 0x1306,
+          VG_USERREQ__MEMPOOL_TRIM     = 0x1307,
+          VG_USERREQ__MOVE_MEMPOOL     = 0x1308,
+          VG_USERREQ__MEMPOOL_CHANGE   = 0x1309,
+          VG_USERREQ__MEMPOOL_EXISTS   = 0x130a,
+
+          /* Allow printfs to valgrind log. */
+          /* The first two pass the va_list argument by value, which
+             assumes it is the same size as or smaller than a UWord,
+             which generally isn't the case.  Hence are deprecated.
+             The second two pass the vargs by reference and so are
+             immune to this problem. */
+          /* both :: char* fmt, va_list vargs (DEPRECATED) */
+          VG_USERREQ__PRINTF           = 0x1401,
+          VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+          /* both :: char* fmt, va_list* vargs */
+          VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+          VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+          /* Stack support. */
+          VG_USERREQ__STACK_REGISTER   = 0x1501,
+          VG_USERREQ__STACK_DEREGISTER = 0x1502,
+          VG_USERREQ__STACK_CHANGE     = 0x1503,
+
+          /* Wine support */
+          VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601
+   } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+#  define __extension__ /* */
+#endif
+
+/* Returns the number of Valgrinds this code is running under.  That
+   is, 0 if running natively, 1 if running under Valgrind, 2 if
+   running under Valgrind which is running under another Valgrind,
+   etc. */
+#define RUNNING_ON_VALGRIND  __extension__                        \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */,          \
+                               VG_USERREQ__RUNNING_ON_VALGRIND,   \
+                               0, 0, 0, 0, 0);                    \
+    _qzz_res;                                                     \
+   })
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+   _qzz_len - 1].  Useful if you are debugging a JITter or some such,
+   since it provides a way to make sure valgrind will retranslate the
+   invalidated area.  Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DISCARD_TRANSLATIONS,  \
+                               _qzz_addr, _qzz_len, 0, 0, 0);     \
+   }
+
+
+/* These requests are for getting Valgrind itself to print something.
+   Possibly with a backtrace.  This is a really ugly hack.  The return value
+   is the number of characters printed, excluding the "**<pid>** " part at the
+   start and the backtrace (if present). */
+
+#if defined(NVALGRIND)
+
+#  define VALGRIND_PRINTF(...)
+#  define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+/* Modern GCC will optimize the static routine out if unused,
+   and unused attribute will shut down warnings about it.  */
+static int VALGRIND_PRINTF(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+static int
+VALGRIND_PRINTF(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+static int
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+   real CPU, calling an arbitary function.
+   
+   Note that the current ThreadId is inserted as the first argument.
+   So this call:
+
+     VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+   requires f to have this signature:
+
+     Word f(Word tid, Word arg1, Word arg2)
+
+   where "Word" is a word-sized type.
+
+   Note that these client requests are not entirely reliable.  For example,
+   if you call a function with them that subsequently calls printf(),
+   there's a high chance Valgrind will crash.  Generally, your prospects of
+   these working are made higher if the called function does not refer to
+   any global variables, and does not refer to any libc or other functions
+   (printf et al).  Any kind of entanglement with libc or dynamic linking is
+   likely to have a bad outcome, for tricky reasons which we've grappled
+   with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn)                          \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL0,          \
+                               _qyy_fn,                           \
+                               0, 0, 0, 0);                       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1)               \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL1,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, 0, 0, 0);               \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2)    \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL2,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2, 0, 0);       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL3,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2,              \
+                               _qyy_arg3, 0);                     \
+    _qyy_res;                                                     \
+   })
+
+
+/* Counts the number of errors that have been recorded by a tool.  Nb:
+   the tool must record the errors with VG_(maybe_record_error)() or
+   VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS                                     \
+   __extension__                                                  \
+   ({unsigned int _qyy_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__COUNT_ERRORS,          \
+                               0, 0, 0, 0, 0);                    \
+    _qyy_res;                                                     \
+   })
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+   when heap blocks are allocated in order to give accurate results.  This
+   happens automatically for the standard allocator functions such as
+   malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+   delete[], etc.
+
+   But if your program uses a custom allocator, this doesn't automatically
+   happen, and Valgrind will not do as well.  For example, if you allocate
+   superblocks with mmap() and then allocates chunks of the superblocks, all
+   Valgrind's observations will be at the mmap() level and it won't know that
+   the chunks should be considered separate entities.  In Memcheck's case,
+   that means you probably won't get heap block overrun detection (because
+   there won't be redzones marked as unaddressable) and you definitely won't
+   get any leak detection.
+
+   The following client requests allow a custom allocator to be annotated so
+   that it can be handled accurately by Valgrind.
+
+   VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+   by a malloc()-like function.  For Memcheck (an illustrative case), this
+   does two things:
+
+   - It records that the block has been allocated.  This means any addresses
+     within the block mentioned in error messages will be
+     identified as belonging to the block.  It also means that if the block
+     isn't freed it will be detected by the leak checker.
+
+   - It marks the block as being addressable and undefined (if 'is_zeroed' is
+     not set), or addressable and defined (if 'is_zeroed' is set).  This
+     controls how accesses to the block by the program are handled.
+   
+   'addr' is the start of the usable block (ie. after any
+   redzone), 'sizeB' is its size.  'rzB' is the redzone size if the allocator
+   can apply redzones -- these are blocks of padding at the start and end of
+   each block.  Adding redzones is recommended as it makes it much more likely
+   Valgrind will spot block overruns.  `is_zeroed' indicates if the memory is
+   zeroed (or filled with another predictable value), as is the case for
+   calloc().
+   
+   VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+   heap block -- that will be used by the client program -- is allocated.
+   It's best to put it at the outermost level of the allocator if possible;
+   for example, if you have a function my_alloc() which calls
+   internal_alloc(), and the client request is put inside internal_alloc(),
+   stack traces relating to the heap block will contain entries for both
+   my_alloc() and internal_alloc(), which is probably not what you want.
+
+   For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+   custom blocks from within a heap block, B, that has been allocated with
+   malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+   -- the custom blocks will take precedence.
+
+   VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK.  For
+   Memcheck, it does two things:
+
+   - It records that the block has been deallocated.  This assumes that the
+     block was annotated as having been allocated via
+     VALGRIND_MALLOCLIKE_BLOCK.  Otherwise, an error will be issued.
+
+   - It marks the block as being unaddressable.
+
+   VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+   heap block is deallocated.
+
+   In many cases, these two client requests will not be enough to get your
+   allocator working well with Memcheck.  More specifically, if your allocator
+   writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+   will be necessary to mark the memory as addressable just before the zeroing
+   occurs, otherwise you'll get a lot of invalid write errors.  For example,
+   you'll need to do this if your allocator recycles freed blocks, but it
+   zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+   Alternatively, if your allocator reuses freed blocks for allocator-internal
+   data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+   Really, what's happening is a blurring of the lines between the client
+   program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+   memory should be considered unaddressable to the client program, but the
+   allocator knows more than the rest of the client program and so may be able
+   to safely access it.  Extra client requests are necessary for Valgrind to
+   understand the distinction between the allocator and the rest of the
+   program.
+
+   Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request;  it
+   has to be emulated with MALLOCLIKE/FREELIKE and memory copying.
+   
+   Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)    \
+   {unsigned int __unused _qzz_res;                               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MALLOCLIKE_BLOCK,      \
+                               addr, sizeB, rzB, is_zeroed, 0);   \
+   }
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+   Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB)                        \
+   {unsigned int __unused _qzz_res;                               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__FREELIKE_BLOCK,        \
+                               addr, rzB, 0, 0, 0);               \
+   }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__CREATE_MEMPOOL,        \
+                               pool, rzB, is_zeroed, 0, 0);       \
+   }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool)                            \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DESTROY_MEMPOOL,       \
+                               pool, 0, 0, 0, 0);                 \
+   }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)                  \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_ALLOC,         \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr)                         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_FREE,          \
+                               pool, addr, 0, 0, 0);              \
+   }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size)                   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_TRIM,          \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB)                       \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MOVE_MEMPOOL,          \
+                               poolA, poolB, 0, 0, 0);            \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_CHANGE,        \
+                               pool, addrA, addrB, size, 0);      \
+   }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool)                             \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_EXISTS,        \
+                               pool, 0, 0, 0, 0);                 \
+    _qzz_res;                                                     \
+   })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end)                       \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_REGISTER,        \
+                               start, end, 0, 0, 0);              \
+    _qzz_res;                                                     \
+   })
+
+/* Unmark the piece of memory associated with a stack id as being a
+   stack. */
+#define VALGRIND_STACK_DEREGISTER(id)                             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_DEREGISTER,      \
+                               id, 0, 0, 0, 0);                   \
+   }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end)                     \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_CHANGE,          \
+                               id, start, end, 0, 0);             \
+   }
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta)   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__LOAD_PDB_DEBUGINFO,    \
+                               fd, ptr, total_size, delta, 0);    \
+   }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif   /* __VALGRIND_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
new file mode 100644
index 0000000..b6bee62
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/nap.h>
+#include <ipxe/efi/efi.h>
+
+/** @file
+ *
+ * iPXE CPU sleeping API for EFI
+ *
+ */
+
+/**
+ * Sleep until next interrupt
+ *
+ */
+static void efix86_cpu_nap ( void ) {
+	/*
+	 * I can't find any EFI API that allows us to put the CPU to
+	 * sleep.  The CpuSleep() function is defined in CpuLib.h, but
+	 * isn't part of any exposed protocol so we have no way to
+	 * call it.
+	 *
+	 * The EFI shell doesn't seem to bother sleeping the CPU; it
+	 * just sits there idly burning power.
+	 *
+	 */
+	__asm__ __volatile__ ( "hlt" );
+}
+
+PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
new file mode 100644
index 0000000..a96c5c4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle	Image handle
+ * @v systab		System table
+ * @ret efirc		EFI return status code
+ */
+EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle,
+				  EFI_SYSTEM_TABLE *systab ) {
+	EFI_STATUS efirc;
+
+	/* Initialise EFI environment */
+	if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+		return efirc;
+
+	/* Initialise iPXE environment */
+	initialise();
+	startup();
+
+	return 0;
+}
+
+REQUIRE_OBJECT ( efi_snp );
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efiprefix.c
new file mode 100644
index 0000000..1515c6f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/prefix/efiprefix.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/efi/efi.h>
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle	Image handle
+ * @v systab		System table
+ * @ret efirc		EFI return status code
+ */
+EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
+			       EFI_SYSTEM_TABLE *systab ) {
+	EFI_STATUS efirc;
+
+	/* Initialise EFI environment */
+	if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+		return efirc;
+
+	/* Call to main() */
+	return RC_TO_EFIRC ( main () );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86/scripts/efi.lds b/qemu-0.15.x/roms/ipxe/src/arch/x86/scripts/efi.lds
new file mode 100644
index 0000000..1a16c29
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86/scripts/efi.lds
@@ -0,0 +1,108 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for EFI images
+ *
+ */
+
+SECTIONS {
+
+    /* The file starts at a virtual address of zero, and sections are
+     * contiguous.  Each section is aligned to at least _max_align,
+     * which defaults to 32.  Load addresses are equal to virtual
+     * addresses.
+     */
+
+    _max_align = 32;
+
+    /* Allow plenty of space for file headers */
+    . = 0x1000;
+
+    /*
+     * The text section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .text : {
+	_text = .;
+	*(.text)
+	*(.text.*)
+	_etext = .;
+    }
+
+    /*
+     * The rodata section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .rodata : {
+	_rodata = .;
+	*(.rodata)
+	*(.rodata.*)
+	_erodata = .;
+    }
+
+    /*
+     * The data section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .data : {
+	_data = .;
+	*(.data)
+	*(.data.*)
+	KEEP(*(SORT(.tbl.*)))	/* Various tables.  See include/tables.h */
+	_edata = .;
+    }
+
+    /*
+     * The bss section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .bss : {
+	_bss = .;
+	*(.bss)
+	*(.bss.*)
+	*(COMMON)
+	_ebss = .;
+    }
+
+    /*
+     * Weak symbols that need zero values if not otherwise defined
+     *
+     */
+
+    .weak 0x0 : {
+	_weak = .;
+	*(.weak)
+	*(.weak.*)
+	_eweak = .;
+    }
+    _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+    /*
+     * Dispose of the comment and note sections to make the link map
+     * easier to read
+     *
+     */
+
+    /DISCARD/ : {
+	*(.comment)
+	*(.comment.*)
+	*(.note)
+	*(.note.*)
+	*(.eh_frame)
+	*(.eh_frame.*)
+	*(.rel)
+	*(.rel.*)
+	*(.einfo)
+	*(.einfo.*)
+	*(.discard)
+	*(.discard.*)
+    }
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile
new file mode 100644
index 0000000..d2c2ff5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile
@@ -0,0 +1,41 @@
+# Code size reduction.
+#
+CFLAGS		+= -fstrength-reduce -fomit-frame-pointer
+
+# Code size reduction.  gcc3 needs a different syntax to gcc2 if you
+# want to avoid spurious warnings.
+#
+CFLAGS		+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
+
+# Use %rip-relative addressing wherever possible.
+#
+CFLAGS		+= -fpie
+
+# Force 64-bit code
+#
+CFLAGS		+= -m64
+ASFLAGS		+= --64
+LDFLAGS		+= -m elf_x86_64
+
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
+#
+CFLAGS		+= -fshort-wchar
+
+# We need to undefine the default macro "i386" when compiling .S
+# files, otherwise ".arch i386" translates to ".arch 1"...
+#
+CFLAGS			+= -Ui386
+
+# x86_64-specific directories containing source files
+#
+SRCDIRS		+= arch/x86_64/prefix
+
+# Include common x86 Makefile
+#
+MAKEDEPS	+= arch/x86/Makefile
+include arch/x86/Makefile
+
+# Include platform-specific Makefile
+#
+MAKEDEPS	+= arch/x86_64/Makefile.$(PLATFORM)
+include arch/x86_64/Makefile.$(PLATFORM)
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.efi b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.efi
new file mode 100644
index 0000000..26b7127
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.efi
@@ -0,0 +1,14 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# EFI probably doesn't guarantee us a red zone, so let's not rely on it.
+#
+CFLAGS		+= -mno-red-zone
+
+# Specify EFI image builder
+#
+ELF2EFI		= $(ELF2EFI64)
+
+# Include generic EFI Makefile
+#
+MAKEDEPS	+= arch/x86/Makefile.efi
+include arch/x86/Makefile.efi
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.linux b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.linux
new file mode 100644
index 0000000..154f9d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/Makefile.linux
@@ -0,0 +1,6 @@
+LDSCRIPT = arch/x86_64/scripts/linux.lds
+
+SRCDIRS += arch/x86_64/core/linux
+
+MAKEDEPS += arch/x86/Makefile.linux
+include arch/x86/Makefile.linux
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/core/linux/linux_syscall.S b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/core/linux/linux_syscall.S
new file mode 100644
index 0000000..d2805f9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/core/linux/linux_syscall.S
@@ -0,0 +1,33 @@
+
+	.section ".data"
+	.globl linux_errno
+
+linux_errno:	.int 0
+
+	.section ".text"
+	.code64
+	.globl linux_syscall
+	.type  linux_syscall, @function
+
+linux_syscall:
+	movq	%rdi, %rax    // C arg1 -> syscall number
+	movq	%rsi, %rdi    // C arg2 -> syscall arg1
+	movq	%rdx, %rsi    // C arg3 -> syscall arg2
+	movq	%rcx, %rdx    // C arg4 -> syscall arg3
+	movq	%r8, %r10     // C arg5 -> syscall arg4
+	movq	%r9, %r8      // C arg6 -> syscall arg5
+	movq	8(%rsp), %r9  // C arg7 -> syscall arg6
+
+	syscall
+
+	cmpq	$-4095, %rax
+	jae	1f
+	ret
+
+1:
+	negq	%rax
+	movl	%eax, linux_errno
+	movq	$-1, %rax
+	ret
+
+	.size linux_syscall, . - linux_syscall
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
new file mode 100644
index 0000000..9ed85e8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
@@ -0,0 +1,22 @@
+#ifndef _BITS_BYTESWAP_H
+#define _BITS_BYTESWAP_H
+
+static inline __attribute__ (( always_inline, const )) uint16_t
+__bswap_variable_16 ( uint16_t x ) {
+	__asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) );
+	return x;
+}
+
+static inline __attribute__ (( always_inline, const )) uint32_t
+__bswap_variable_32 ( uint32_t x ) {
+	__asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) );
+	return x;
+}
+
+static inline __attribute__ (( always_inline, const )) uint64_t
+__bswap_variable_64 ( uint64_t x ) {
+	__asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) );
+	return x;
+}
+
+#endif /* _BITS_BYTESWAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/compiler.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
new file mode 100644
index 0000000..51a7eaa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_COMPILER_H
+#define _BITS_COMPILER_H
+
+#ifndef ASSEMBLY
+
+/** Declare a function with standard calling conventions */
+#define __asmcall __attribute__ (( regparm(0) ))
+
+/** Declare a function with libgcc implicit linkage */
+#define __libgcc
+
+#endif /* ASSEMBLY */
+
+#endif /* _BITS_COMPILER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/endian.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/endian.h
new file mode 100644
index 0000000..413e702
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/endian.h
@@ -0,0 +1,6 @@
+#ifndef ETHERBOOT_BITS_ENDIAN_H
+#define ETHERBOOT_BITS_ENDIAN_H
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/errfile.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/errfile.h
new file mode 100644
index 0000000..dcda26b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/errfile.h
@@ -0,0 +1,11 @@
+#ifndef _BITS_ERRFILE_H
+#define _BITS_ERRFILE_H
+
+/**
+ * @addtogroup errfile Error file identifiers
+ * @{
+ */
+
+/** @} */
+
+#endif /* _BITS_ERRFILE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/io.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/io.h
new file mode 100644
index 0000000..921fdcc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/io.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * x86_64-specific I/O API implementations
+ *
+ */
+
+#endif /* _BITS_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/linux_api.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/linux_api.h
new file mode 100644
index 0000000..589fb58
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/linux_api.h
@@ -0,0 +1,6 @@
+#ifndef _X86_64_LINUX_API_H
+#define _X86_64_LINUX_API_H
+
+#define __SYSCALL_mmap __NR_mmap
+
+#endif /* _X86_64_LINUX_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/nap.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/nap.h
new file mode 100644
index 0000000..8b42c0a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/nap.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_NAP_H
+#define _BITS_NAP_H
+
+/** @file
+ *
+ * x86_64-specific CPU sleeping API implementations
+ *
+ */
+
+#include <ipxe/efi/efix86_nap.h>
+
+#endif /* _BITS_MAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
new file mode 100644
index 0000000..d33d03c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_SANBOOT_H
+#define _BITS_SANBOOT_H
+
+/** @file
+ *
+ * x86_64-specific sanboot API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#endif /* _BITS_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/smbios.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/smbios.h
new file mode 100644
index 0000000..2f0118d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/smbios.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_SMBIOS_H
+#define _BITS_SMBIOS_H
+
+/** @file
+ *
+ * i386-specific SMBIOS API implementations
+ *
+ */
+
+#endif /* _BITS_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/stdint.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/stdint.h
new file mode 100644
index 0000000..9eb72e9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/stdint.h
@@ -0,0 +1,21 @@
+#ifndef _BITS_STDINT_H
+#define _BITS_STDINT_H
+
+typedef __SIZE_TYPE__		size_t;
+typedef signed long		ssize_t;
+typedef signed long		off_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short		uint16_t;
+typedef unsigned int		uint32_t;
+typedef unsigned long long	uint64_t;
+
+typedef signed char		int8_t;
+typedef signed short		int16_t;
+typedef signed int		int32_t;
+typedef signed long long	int64_t;
+
+typedef unsigned long		physaddr_t;
+typedef unsigned long		intptr_t;
+
+#endif /* _BITS_STDINT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/timer.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/timer.h
new file mode 100644
index 0000000..dfa6c27
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/timer.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * x86_64-specific timer API implementations
+ *
+ */
+
+#endif /* _BITS_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/uaccess.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/uaccess.h
new file mode 100644
index 0000000..4558292
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/uaccess.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_UACCESS_H
+#define _BITS_UACCESS_H
+
+/** @file
+ *
+ * x86_64-specific user access API implementations
+ *
+ */
+
+#endif /* _BITS_UACCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/umalloc.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/umalloc.h
new file mode 100644
index 0000000..12bf949
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/bits/umalloc.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_UMALLOC_H
+#define _BITS_UMALLOC_H
+
+/** @file
+ *
+ * x86_64-specific user memory allocation API implementations
+ *
+ */
+
+#endif /* _BITS_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
new file mode 100644
index 0000000..af41b19
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DHCP_ARCH_H
+#define _DHCP_ARCH_H
+
+/** @file
+ *
+ * Architecture-specific DHCP options
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/dhcp.h>
+
+#define DHCP_ARCH_VENDOR_CLASS_ID \
+	DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',      \
+		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '7', ':', \
+		      'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
+
+#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 7 )
+
+#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/gdbmach.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/gdbmach.h
new file mode 100644
index 0000000..fcf8e94
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/gdbmach.h
@@ -0,0 +1,51 @@
+#ifndef GDBMACH_H
+#define GDBMACH_H
+
+/** @file
+ *
+ * GDB architecture specifics
+ *
+ * This file declares functions for manipulating the machine state and
+ * debugging context.
+ *
+ */
+
+#include <stdint.h>
+
+typedef unsigned long gdbreg_t;
+
+/* The register snapshot, this must be in sync with interrupt handler and the
+ * GDB protocol. */
+enum {
+	// STUB: don't expect this to work!
+	GDBMACH_EIP,
+	GDBMACH_EFLAGS,
+	GDBMACH_NREGS,
+	GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
+};
+
+/* Breakpoint types */
+enum {
+	GDBMACH_BPMEM,
+	GDBMACH_BPHW,
+	GDBMACH_WATCH,
+	GDBMACH_RWATCH,
+	GDBMACH_AWATCH,
+};
+
+static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
+	regs [ GDBMACH_EIP ] = pc;
+}
+
+static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
+	regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
+	regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
+}
+
+static inline void gdbmach_breakpoint ( void ) {
+	__asm__ __volatile__ ( "int $3\n" );
+}
+
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
+
+#endif /* GDBMACH_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/limits.h b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/limits.h
new file mode 100644
index 0000000..8cf87b4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/include/limits.h
@@ -0,0 +1,59 @@
+#ifndef LIMITS_H
+#define LIMITS_H	1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT	8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN	(-128)
+#define SCHAR_MAX	127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX	255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN	SCHAR_MIN
+#define CHAR_MAX	SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN	(-32768)
+#define SHRT_MAX	32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX	65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN		(-INT_MAX - 1)
+#define INT_MAX		2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX	4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MAX		2147483647
+#define INT_MIN		(-INT_MAX - 1)
+
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX	4294967295U
+
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX	9223372036854775807L
+#define LONG_MIN	(-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX	18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX	9223372036854775807LL
+#define LLONG_MIN	(-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX	18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S
new file mode 100644
index 0000000..713b9e3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S
@@ -0,0 +1,25 @@
+#include <linux/unistd.h>
+
+	.section ".text"
+	.code64
+	.globl _linux_start
+	.type _linux_start, @function
+
+_linux_start:
+	xorq	%rbp, %rbp
+
+	popq	%rdi       // argc -> C arg1
+	movq	%rsp, %rsi // argv -> C arg2
+
+	andq	$~15, %rsp // 16-byte align the stack
+
+	call	save_args
+
+	/* Our main doesn't use any arguments */
+	call	main
+
+	movq	%rax, %rdi // rc -> syscall arg1
+	movq	$__NR_exit, %rax
+	syscall
+
+	.size _start, . - _start
diff --git a/qemu-0.15.x/roms/ipxe/src/arch/x86_64/scripts/linux.lds b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/scripts/linux.lds
new file mode 100644
index 0000000..85e548f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/arch/x86_64/scripts/linux.lds
@@ -0,0 +1,102 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for x86_64 Linux images
+ *
+ */
+
+OUTPUT_FORMAT ( "elf64-x86-64", "elf64-x86-64", "elf64-x86-64" )
+OUTPUT_ARCH ( i386:x86-64 )
+
+SECTIONS {
+	_max_align = 32;
+
+	. = 0x400000;
+
+	/*
+	 * The text section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.text : {
+		_text = .;
+		*(.text)
+		*(.text.*)
+		_etext = .;
+	}
+
+	/*
+	 * The rodata section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.rodata : {
+		_rodata = .;
+		*(.rodata)
+		*(.rodata.*)
+		_erodata = .;
+	}
+
+	/*
+	 * The data section
+	 *
+	 * Adjust the address for the data segment.  We want to adjust up to
+	 * the same address within the page on the next page up.
+	 */
+
+	. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1));
+	. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+	.data : {
+		_data = .;
+		*(.data)
+		*(.data.*)
+		KEEP(*(SORT(.tbl.*)))
+		_edata = .;
+	}
+
+	/*
+	 * The bss section
+	 *
+	 */
+
+	. = ALIGN ( _max_align );
+	.bss : {
+		_bss = .;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		_ebss = .;
+	}
+
+	/*
+	 * Weak symbols that need zero values if not otherwise defined
+	 *
+	 */
+
+	.weak 0x0 : {
+		_weak = .;
+		*(.weak)
+		*(.weak.*)
+		_eweak = .;
+	}
+	_assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+	/*
+	 * Dispose of the comment and note sections to make the link map
+	 * easier to read
+	 *
+	 */
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.comment.*)
+		*(.note)
+		*(.note.*)
+		*(.rel)
+		*(.rel.*)
+		*(.discard)
+		*(.discard.*)
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/config/.gitignore b/qemu-0.15.x/roms/ipxe/src/config/.gitignore
new file mode 100644
index 0000000..8e94f32
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/.gitignore
@@ -0,0 +1 @@
+.buildserial.*
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config.c b/qemu-0.15.x/roms/ipxe/src/config/config.c
new file mode 100644
index 0000000..2c3555e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config.c
@@ -0,0 +1,290 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+#include <config/console.h>
+#include <config/sideband.h>
+
+/** @file
+ *
+ * Configuration options
+ *
+ * This file contains macros that pull various objects into the link
+ * based on definitions in configuration header files. Ideally it
+ * should be the only place in iPXE where one might need to use #ifdef
+ * for compile-time options.
+ *
+ * In the fairly common case where an object should only be considered
+ * for inclusion if the subsystem it depends on is present, its
+ * configuration macros should be placed in a file named
+ * <tt>config_<i>subsystem</i>.c</tt>, where @e subsystem is the
+ * object basename of the main source file for that subsystem. The
+ * build system will pull in that file if @c subsystem.c is included
+ * in the final iPXE executable built.
+ */
+
+/*
+ * Build ID string calculations
+ *
+ */
+#undef XSTR
+#undef STR
+#define XSTR(s) STR(s)
+#define STR(s) #s
+
+#ifdef BUILD_SERIAL
+#include "config/.buildserial.h"
+#define BUILD_SERIAL_STR " #" XSTR(BUILD_SERIAL_NUM)
+#else
+#define BUILD_SERIAL_STR ""
+#endif
+
+#ifdef BUILD_ID
+#define BUILD_ID_STR " " BUILD_ID
+#else
+#define BUILD_ID_STR ""
+#endif
+
+#if defined(BUILD_ID) || defined(BUILD_SERIAL)
+#define BUILD_STRING " [build" BUILD_ID_STR BUILD_SERIAL_STR "]"
+#else
+#define BUILD_STRING ""
+#endif
+
+/*
+ * Drag in all requested console types
+ *
+ */
+
+#ifdef CONSOLE_PCBIOS
+REQUIRE_OBJECT ( bios_console );
+#endif
+#ifdef CONSOLE_SERIAL
+REQUIRE_OBJECT ( serial_console );
+#endif
+#ifdef CONSOLE_DIRECT_VGA
+REQUIRE_OBJECT ( video_subr );
+#endif
+#ifdef CONSOLE_BTEXT
+REQUIRE_OBJECT ( btext );
+#endif
+#ifdef CONSOLE_PC_KBD
+REQUIRE_OBJECT ( pc_kbd );
+#endif
+#ifdef CONSOLE_SYSLOG
+REQUIRE_OBJECT ( syslog );
+#endif
+#ifdef CONSOLE_EFI
+REQUIRE_OBJECT ( efi_console );
+#endif
+#ifdef CONSOLE_LINUX
+REQUIRE_OBJECT ( linux_console );
+#endif
+
+/*
+ * Drag in all requested network protocols
+ *
+ */
+#ifdef NET_PROTO_IPV4
+REQUIRE_OBJECT ( ipv4 );
+#endif
+
+/*
+ * Drag in all requested PXE support
+ *
+ */
+#ifdef PXE_MENU
+REQUIRE_OBJECT ( pxemenu );
+#endif
+#ifdef PXE_STACK
+REQUIRE_OBJECT ( pxe_call );
+#endif
+
+/*
+ * Drag in all requested download protocols
+ *
+ */
+#ifdef DOWNLOAD_PROTO_TFTP
+REQUIRE_OBJECT ( tftp );
+#endif
+#ifdef DOWNLOAD_PROTO_HTTP
+REQUIRE_OBJECT ( http );
+#endif
+#ifdef DOWNLOAD_PROTO_HTTPS
+REQUIRE_OBJECT ( https );
+#endif
+#ifdef DOWNLOAD_PROTO_FTP
+REQUIRE_OBJECT ( ftp );
+#endif
+#ifdef DOWNLOAD_PROTO_TFTM
+REQUIRE_OBJECT ( tftm );
+#endif
+#ifdef DOWNLOAD_PROTO_SLAM
+REQUIRE_OBJECT ( slam );
+#endif
+
+/*
+ * Drag in all requested SAN boot protocols
+ *
+ */
+#ifdef SANBOOT_PROTO_ISCSI
+REQUIRE_OBJECT ( iscsi );
+#endif
+
+/*
+ * Drag in all requested resolvers
+ *
+ */
+#ifdef DNS_RESOLVER
+REQUIRE_OBJECT ( dns );
+#endif
+
+/*
+ * Drag in all requested image formats
+ *
+ */
+#ifdef IMAGE_NBI
+REQUIRE_OBJECT ( nbi );
+#endif
+#ifdef IMAGE_ELF
+REQUIRE_OBJECT ( elfboot );
+#endif
+#ifdef IMAGE_FREEBSD
+REQUIRE_OBJECT ( freebsd );
+#endif
+#ifdef IMAGE_MULTIBOOT
+REQUIRE_OBJECT ( multiboot );
+#endif
+#ifdef IMAGE_AOUT
+REQUIRE_OBJECT ( aout );
+#endif
+#ifdef IMAGE_WINCE
+REQUIRE_OBJECT ( wince );
+#endif
+#ifdef IMAGE_PXE
+REQUIRE_OBJECT ( pxe_image );
+#endif
+#ifdef IMAGE_SCRIPT
+REQUIRE_OBJECT ( script );
+#endif
+#ifdef IMAGE_BZIMAGE
+REQUIRE_OBJECT ( bzimage );
+#endif
+#ifdef IMAGE_ELTORITO
+REQUIRE_OBJECT ( eltorito );
+#endif
+#ifdef IMAGE_COMBOOT
+REQUIRE_OBJECT ( comboot );
+REQUIRE_OBJECT ( com32 );
+REQUIRE_OBJECT ( comboot_call );
+REQUIRE_OBJECT ( com32_call );
+REQUIRE_OBJECT ( com32_wrapper );
+REQUIRE_OBJECT ( comboot_resolv );
+#endif
+#ifdef IMAGE_EFI
+REQUIRE_OBJECT ( efi_image );
+#endif
+
+/*
+ * Drag in all requested commands
+ *
+ */
+#ifdef AUTOBOOT_CMD
+REQUIRE_OBJECT ( autoboot_cmd );
+#endif
+#ifdef NVO_CMD
+REQUIRE_OBJECT ( nvo_cmd );
+#endif
+#ifdef CONFIG_CMD
+REQUIRE_OBJECT ( config_cmd );
+#endif
+#ifdef IFMGMT_CMD
+REQUIRE_OBJECT ( ifmgmt_cmd );
+#endif
+/* IWMGMT_CMD is brought in by net80211.c if requested */
+#ifdef ROUTE_CMD
+REQUIRE_OBJECT ( route_cmd );
+#endif
+#ifdef IMAGE_CMD
+REQUIRE_OBJECT ( image_cmd );
+#endif
+#ifdef DHCP_CMD
+REQUIRE_OBJECT ( dhcp_cmd );
+#endif
+#ifdef SANBOOT_CMD
+REQUIRE_OBJECT ( sanboot_cmd );
+#endif
+#ifdef LOGIN_CMD
+REQUIRE_OBJECT ( login_cmd );
+#endif
+#ifdef TIME_CMD
+REQUIRE_OBJECT ( time_cmd );
+#endif
+#ifdef DIGEST_CMD
+REQUIRE_OBJECT ( digest_cmd );
+#endif
+#ifdef PXE_CMD
+REQUIRE_OBJECT ( pxe_cmd );
+#endif
+#ifdef LOTEST_CMD
+REQUIRE_OBJECT ( lotest_cmd );
+#endif
+#ifdef VLAN_CMD
+REQUIRE_OBJECT ( vlan_cmd );
+#endif
+#ifdef REBOOT_CMD
+REQUIRE_OBJECT ( reboot_cmd );
+#endif
+
+/*
+ * Drag in miscellaneous objects
+ *
+ */
+#ifdef NULL_TRAP
+REQUIRE_OBJECT ( nulltrap );
+#endif
+#ifdef GDBSERIAL
+REQUIRE_OBJECT ( gdbidt );
+REQUIRE_OBJECT ( gdbserial );
+REQUIRE_OBJECT ( gdbstub_cmd );
+#endif
+#ifdef GDBUDP
+REQUIRE_OBJECT ( gdbidt );
+REQUIRE_OBJECT ( gdbudp );
+REQUIRE_OBJECT ( gdbstub_cmd );
+#endif
+
+/*
+ * Drag in objects that are always required, but not dragged in via
+ * symbol dependencies.
+ *
+ */
+REQUIRE_OBJECT ( device );
+REQUIRE_OBJECT ( embedded );
+
+/* linux drivers aren't picked up by the parserom utility so drag them in here */
+#ifdef DRIVERS_LINUX
+REQUIRE_OBJECT ( tap );
+#endif
+
+/*
+ * Drag in relevant BOFM entry points
+ */
+#ifdef CONFIG_BOFM
+#ifdef BOFM_EFI
+REQUIRE_OBJECT ( efi_bofm );
+#endif /* BOFM_EFI */
+#endif /* CONFIG_BOFM */
+
+/*
+ * Drag in selected keyboard map
+ */
+#define REQUIRE_KEYMAP_OBJECT( _map ) REQUIRE_OBJECT ( keymap_ ## _map )
+#define REQUIRE_KEYMAP( _map ) REQUIRE_KEYMAP_OBJECT ( _map )
+REQUIRE_KEYMAP ( KEYBOARD_MAP );
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config_ethernet.c b/qemu-0.15.x/roms/ipxe/src/config/config_ethernet.c
new file mode 100644
index 0000000..d13bd61
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config_ethernet.c
@@ -0,0 +1,26 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * Ethernet configuration options
+ *
+ */
+
+/*
+ * Drag in Ethernet-specific protocols
+ */
+#ifdef SANBOOT_PROTO_AOE
+REQUIRE_OBJECT ( aoe );
+#endif
+#ifdef NET_PROTO_FCOE
+REQUIRE_OBJECT ( fcoe );
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config_fc.c b/qemu-0.15.x/roms/ipxe/src/config/config_fc.c
new file mode 100644
index 0000000..4146469
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config_fc.c
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * Fibre Channel configuration options
+ *
+ */
+
+/*
+ * Drag in Fibre Channel-specific commands
+ *
+ */
+#ifdef FCMGMT_CMD
+REQUIRE_OBJECT ( fcmgmt_cmd );
+#endif
+
+/*
+ * Drag in Fibre Channel-specific protocols
+ */
+#ifdef SANBOOT_PROTO_FCP
+REQUIRE_OBJECT ( fcp );
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config_infiniband.c b/qemu-0.15.x/roms/ipxe/src/config/config_infiniband.c
new file mode 100644
index 0000000..432e621
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config_infiniband.c
@@ -0,0 +1,23 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * Infiniband configuration options
+ *
+ */
+
+/*
+ * Drag in Infiniband-specific protocols
+ */
+#ifdef SANBOOT_PROTO_IB_SRP
+REQUIRE_OBJECT ( ib_srp );
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config_net80211.c b/qemu-0.15.x/roms/ipxe/src/config/config_net80211.c
new file mode 100644
index 0000000..b33c363
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config_net80211.c
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * 802.11 configuration options
+ *
+ */
+
+/*
+ * Drag in 802.11-specific commands
+ *
+ */
+#ifdef IWMGMT_CMD
+REQUIRE_OBJECT ( iwmgmt_cmd );
+#endif
+
+/*
+ * Drag in 802.11 error message tables
+ *
+ */
+#ifdef ERRMSG_80211
+REQUIRE_OBJECT ( wireless_errors );
+#endif
+
+/*
+ * Drag in 802.11 cryptosystems and handshaking protocols
+ *
+ */
+#ifdef CRYPTO_80211_WEP
+REQUIRE_OBJECT ( wep );
+#endif
+
+#ifdef CRYPTO_80211_WPA2
+#define CRYPTO_80211_WPA
+REQUIRE_OBJECT ( wpa_ccmp );
+#endif
+
+#ifdef CRYPTO_80211_WPA
+REQUIRE_OBJECT ( wpa_psk );
+REQUIRE_OBJECT ( wpa_tkip );
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/config/config_romprefix.c b/qemu-0.15.x/roms/ipxe/src/config/config_romprefix.c
new file mode 100644
index 0000000..85f1e78
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/config_romprefix.c
@@ -0,0 +1,24 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * ROM prefix configuration options
+ *
+ */
+
+/*
+ * Provide UNDI loader if PXE stack is requested
+ *
+ */
+#ifdef PXE_STACK
+REQUIRE_OBJECT ( undiloader );
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/config/console.h b/qemu-0.15.x/roms/ipxe/src/config/console.h
new file mode 100644
index 0000000..afc8956
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/console.h
@@ -0,0 +1,28 @@
+#ifndef CONFIG_CONSOLE_H
+#define CONFIG_CONSOLE_H
+
+/** @file
+ *
+ * Console configuration
+ *
+ * These options specify the console types that Etherboot will use for
+ * interaction with the user.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+//#define	CONSOLE_PCBIOS		/* Default BIOS console */
+//#define	CONSOLE_SERIAL		/* Serial port */
+//#define	CONSOLE_DIRECT_VGA	/* Direct access to VGA card */
+//#define	CONSOLE_BTEXT		/* Who knows what this does? */
+//#define	CONSOLE_PC_KBD		/* Direct access to PC keyboard */
+//#define	CONSOLE_SYSLOG		/* Syslog console */
+
+#define	KEYBOARD_MAP	us
+
+#include <config/local/console.h>
+
+#endif /* CONFIG_CONSOLE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/defaults.h b/qemu-0.15.x/roms/ipxe/src/config/defaults.h
new file mode 100644
index 0000000..389c0b0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/defaults.h
@@ -0,0 +1,10 @@
+#ifndef CONFIG_DEFAULTS_H
+#define CONFIG_DEFAULTS_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h>
+
+#include CONFIG_DEFAULTS(PLATFORM)
+
+#endif /* CONFIG_DEFAULTS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/defaults/efi.h b/qemu-0.15.x/roms/ipxe/src/config/defaults/efi.h
new file mode 100644
index 0000000..693f55a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/defaults/efi.h
@@ -0,0 +1,24 @@
+#ifndef CONFIG_DEFAULTS_EFI_H
+#define CONFIG_DEFAULTS_EFI_H
+
+/** @file
+ *
+ * Configuration defaults for EFI
+ *
+ */
+
+#define UACCESS_EFI
+#define IOAPI_EFI
+#define PCIAPI_EFI
+#define CONSOLE_EFI
+#define TIMER_EFI
+#define NAP_EFIX86
+#define UMALLOC_EFI
+#define SMBIOS_EFI
+#define SANBOOT_NULL
+#define BOFM_EFI
+
+#define	IMAGE_EFI		/* EFI image support */
+#define	IMAGE_SCRIPT		/* iPXE script image support */
+
+#endif /* CONFIG_DEFAULTS_EFI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/defaults/linux.h b/qemu-0.15.x/roms/ipxe/src/config/defaults/linux.h
new file mode 100644
index 0000000..647dc0a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/defaults/linux.h
@@ -0,0 +1,22 @@
+#ifndef CONFIG_DEFAULTS_LINUX_H
+#define CONFIG_DEFAULTS_LINUX_H
+
+/** @file
+ *
+ * Configuration defaults for linux
+ *
+ */
+
+#define CONSOLE_LINUX
+#define TIMER_LINUX
+#define UACCESS_LINUX
+#define UMALLOC_LINUX
+#define NAP_LINUX
+#define SMBIOS_LINUX
+#define SANBOOT_NULL
+
+#define DRIVERS_LINUX
+
+#define IMAGE_SCRIPT
+
+#endif /* CONFIG_DEFAULTS_LINUX_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/defaults/pcbios.h b/qemu-0.15.x/roms/ipxe/src/config/defaults/pcbios.h
new file mode 100644
index 0000000..7846f8f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/defaults/pcbios.h
@@ -0,0 +1,37 @@
+#ifndef CONFIG_DEFAULTS_PCBIOS_H
+#define CONFIG_DEFAULTS_PCBIOS_H
+
+/** @file
+ *
+ * Configuration defaults for PCBIOS
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define UACCESS_LIBRM
+#define IOAPI_X86
+#define PCIAPI_PCBIOS
+#define TIMER_PCBIOS
+#define CONSOLE_PCBIOS
+#define NAP_PCBIOS
+#define UMALLOC_MEMTOP
+#define SMBIOS_PCBIOS
+#define SANBOOT_PCBIOS
+
+#define	IMAGE_ELF		/* ELF image support */
+#define	IMAGE_MULTIBOOT		/* MultiBoot image support */
+#define	IMAGE_PXE		/* PXE image support */
+#define IMAGE_SCRIPT		/* iPXE script image support */
+#define IMAGE_BZIMAGE		/* Linux bzImage image support */
+#define IMAGE_COMBOOT		/* SYSLINUX COMBOOT image support */
+
+#define PXE_STACK		/* PXE stack in iPXE - required for PXELINUX */
+#define PXE_MENU		/* PXE menu booting */
+
+#define	SANBOOT_PROTO_ISCSI	/* iSCSI protocol */
+#define	SANBOOT_PROTO_AOE	/* AoE protocol */
+#define	SANBOOT_PROTO_IB_SRP	/* Infiniband SCSI RDMA protocol */
+#define	SANBOOT_PROTO_FCP	/* Fibre Channel protocol */
+
+#endif /* CONFIG_DEFAULTS_PCBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/general.h b/qemu-0.15.x/roms/ipxe/src/config/general.h
new file mode 100644
index 0000000..9eb8865
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/general.h
@@ -0,0 +1,157 @@
+#ifndef CONFIG_GENERAL_H
+#define CONFIG_GENERAL_H
+
+/** @file
+ *
+ * General configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+/*
+ * Branding
+ *
+ * Vendors may use these strings to add their own branding to iPXE.
+ * PRODUCT_NAME is displayed prior to any iPXE branding in startup
+ * messages, and PRODUCT_SHORT_NAME is used where a brief product
+ * label is required (e.g. in BIOS boot selection menus).
+ *
+ * To minimise end-user confusion, it's probably a good idea to either
+ * make PRODUCT_SHORT_NAME a substring of PRODUCT_NAME or leave it as
+ * "iPXE".
+ *
+ */
+#define PRODUCT_NAME ""
+#define PRODUCT_SHORT_NAME "iPXE"
+
+/*
+ * Timer configuration
+ *
+ */
+#define BANNER_TIMEOUT	20	/* Tenths of a second for which the shell
+				   banner should appear */
+
+/*
+ * Network protocols
+ *
+ */
+
+#define	NET_PROTO_IPV4		/* IPv4 protocol */
+#undef	NET_PROTO_FCOE		/* Fibre Channel over Ethernet protocol */
+
+/*
+ * PXE support
+ *
+ */
+//#undef	PXE_STACK		/* PXE stack in iPXE - you want this! */
+//#undef	PXE_MENU		/* PXE menu booting */
+
+/*
+ * Download protocols
+ *
+ */
+
+#define	DOWNLOAD_PROTO_TFTP	/* Trivial File Transfer Protocol */
+#define	DOWNLOAD_PROTO_HTTP	/* Hypertext Transfer Protocol */
+#undef	DOWNLOAD_PROTO_HTTPS	/* Secure Hypertext Transfer Protocol */
+#undef	DOWNLOAD_PROTO_FTP	/* File Transfer Protocol */
+#undef	DOWNLOAD_PROTO_TFTM	/* Multicast Trivial File Transfer Protocol */
+#undef	DOWNLOAD_PROTO_SLAM	/* Scalable Local Area Multicast */
+
+/*
+ * SAN boot protocols
+ *
+ */
+
+//#undef	SANBOOT_PROTO_ISCSI	/* iSCSI protocol */
+//#undef	SANBOOT_PROTO_AOE	/* AoE protocol */
+//#undef	SANBOOT_PROTO_IB_SRP	/* Infiniband SCSI RDMA protocol */
+//#undef	SANBOOT_PROTO_FCP	/* Fibre Channel protocol */
+
+/*
+ * 802.11 cryptosystems and handshaking protocols
+ *
+ */
+#define	CRYPTO_80211_WEP	/* WEP encryption (deprecated and insecure!) */
+#define	CRYPTO_80211_WPA	/* WPA Personal, authenticating with passphrase */
+#define	CRYPTO_80211_WPA2	/* Add support for stronger WPA cryptography */
+
+/*
+ * Name resolution modules
+ *
+ */
+
+#define	DNS_RESOLVER		/* DNS resolver */
+
+/*
+ * Image types
+ *
+ * Etherboot supports various image formats.  Select whichever ones
+ * you want to use.
+ *
+ */
+//#define	IMAGE_NBI		/* NBI image support */
+//#define	IMAGE_ELF		/* ELF image support */
+//#define	IMAGE_FREEBSD		/* FreeBSD kernel image support */
+//#define	IMAGE_MULTIBOOT		/* MultiBoot image support */
+//#define	IMAGE_AOUT		/* a.out image support */
+//#define	IMAGE_WINCE		/* WinCE image support */
+//#define	IMAGE_PXE		/* PXE image support */
+//#define	IMAGE_SCRIPT		/* iPXE script image support */
+//#define	IMAGE_BZIMAGE		/* Linux bzImage image support */
+//#define	IMAGE_COMBOOT		/* SYSLINUX COMBOOT image support */
+//#define	IMAGE_EFI		/* EFI image support */
+
+/*
+ * Command-line commands to include
+ *
+ */
+#define	AUTOBOOT_CMD		/* Automatic booting */
+#define	NVO_CMD			/* Non-volatile option storage commands */
+#define	CONFIG_CMD		/* Option configuration console */
+#define	IFMGMT_CMD		/* Interface management commands */
+#define	IWMGMT_CMD		/* Wireless interface management commands */
+#define FCMGMT_CMD		/* Fibre Channel management commands */
+#define	ROUTE_CMD		/* Routing table management commands */
+#define IMAGE_CMD		/* Image management commands */
+#define DHCP_CMD		/* DHCP management commands */
+#define SANBOOT_CMD		/* SAN boot commands */
+#define LOGIN_CMD		/* Login command */
+#undef	TIME_CMD		/* Time commands */
+#undef	DIGEST_CMD		/* Image crypto digest commands */
+#undef	LOTEST_CMD		/* Loopback testing commands */
+#undef	VLAN_CMD		/* VLAN commands */
+#undef	PXE_CMD			/* PXE commands */
+#undef	REBOOT_CMD		/* Reboot command */
+
+/*
+ * Error message tables to include
+ *
+ */
+#undef	ERRMSG_80211		/* All 802.11 error descriptions (~3.3kb) */
+
+/*
+ * Obscure configuration options
+ *
+ * You probably don't need to touch these.
+ *
+ */
+
+#define	NETDEV_DISCARD_RATE 0	/* Drop every N packets (0=>no drop) */
+#undef	BUILD_SERIAL		/* Include an automatic build serial
+				 * number.  Add "bs" to the list of
+				 * make targets.  For example:
+				 * "make bin/rtl8139.dsk bs" */
+#undef	BUILD_ID		/* Include a custom build ID string,
+				 * e.g "test-foo" */
+#undef	NULL_TRAP		/* Attempt to catch NULL function calls */
+#undef	GDBSERIAL		/* Remote GDB debugging over serial */
+#undef	GDBUDP			/* Remote GDB debugging over UDP
+				 * (both may be set) */
+
+#include <config/local/general.h>
+
+#endif /* CONFIG_GENERAL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/ioapi.h b/qemu-0.15.x/roms/ipxe/src/config/ioapi.h
new file mode 100644
index 0000000..ce19c6d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/ioapi.h
@@ -0,0 +1,19 @@
+#ifndef CONFIG_IOAPI_H
+#define CONFIG_IOAPI_H
+
+/** @file
+ *
+ * I/O API configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+//#undef	PCIAPI_PCBIOS		/* Access via PCI BIOS */
+//#define	PCIAPI_DIRECT		/* Direct access via Type 1 accesses */
+
+#include <config/local/ioapi.h>
+
+#endif /* CONFIG_IOAPI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/isa.h b/qemu-0.15.x/roms/ipxe/src/config/isa.h
new file mode 100644
index 0000000..e2a0505
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/isa.h
@@ -0,0 +1,17 @@
+#ifndef CONFIG_ISA_H
+#define CONFIG_ISA_H
+
+/** @file
+ *
+ * ISA probe address configuration
+ *
+ * You can override the list of addresses that will be probed by any
+ * ISA drivers.
+ *
+ */
+#undef	ISA_PROBE_ADDRS		/* e.g. 0x200, 0x300 */
+#undef	ISA_PROBE_ONLY		/* Do not probe any other addresses */
+
+#include <config/local/isa.h>
+
+#endif /* CONFIG_ISA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/nap.h b/qemu-0.15.x/roms/ipxe/src/config/nap.h
new file mode 100644
index 0000000..187af42
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/nap.h
@@ -0,0 +1,19 @@
+#ifndef CONFIG_NAP_H
+#define CONFIG_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+//#undef		NAP_PCBIOS
+//#define		NAP_NULL
+
+#include <config/local/nap.h>
+
+#endif /* CONFIG_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/sanboot.h b/qemu-0.15.x/roms/ipxe/src/config/sanboot.h
new file mode 100644
index 0000000..1d7f5f1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/sanboot.h
@@ -0,0 +1,16 @@
+#ifndef CONFIG_SANBOOT_H
+#define CONFIG_SANBOOT_H
+
+/** @file
+ *
+ * sanboot API configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+#include <config/local/sanboot.h>
+
+#endif /* CONFIG_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/serial.h b/qemu-0.15.x/roms/ipxe/src/config/serial.h
new file mode 100644
index 0000000..8bb9311
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/serial.h
@@ -0,0 +1,37 @@
+#ifndef CONFIG_SERIAL_H
+#define CONFIG_SERIAL_H
+
+/** @file
+ *
+ * Serial port configuration
+ *
+ * These options affect the operation of the serial console.  They
+ * take effect only if the serial console is included using the
+ * CONSOLE_SERIAL option.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define	COM1		0x3f8
+#define	COM2		0x2f8
+#define	COM3		0x3e8
+#define	COM4		0x2e8
+
+#define	COMCONSOLE	COM1		/* I/O port address */
+
+/* Keep settings from a previous user of the serial port (e.g. lilo or
+ * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
+ */
+#undef	COMPRESERVE
+
+#ifndef COMPRESERVE
+#define	COMSPEED	115200		/* Baud rate */
+#define	COMDATA		8		/* Data bits */
+#define	COMPARITY	0		/* Parity: 0=None, 1=Odd, 2=Even */
+#define	COMSTOP		1		/* Stop bits */
+#endif
+
+#include <config/local/serial.h>
+
+#endif /* CONFIG_SERIAL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/sideband.h b/qemu-0.15.x/roms/ipxe/src/config/sideband.h
new file mode 100644
index 0000000..5385dd7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/sideband.h
@@ -0,0 +1,14 @@
+#ifndef CONFIG_SIDEBAND_H
+#define CONFIG_SIDEBAND_H
+
+/** @file
+ *
+ * Sideband access by platform firmware
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+//#define	CONFIG_BOFM	/* IBM's BladeCenter Open Fabric Manager */
+
+#endif /* CONFIG_SIDEBAND_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/timer.h b/qemu-0.15.x/roms/ipxe/src/config/timer.h
new file mode 100644
index 0000000..abd6698
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/timer.h
@@ -0,0 +1,19 @@
+#ifndef CONFIG_TIMER_H
+#define CONFIG_TIMER_H
+
+/** @file
+ *
+ * Timer configuration.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+//#undef		TIMER_PCBIOS
+//#define		TIMER_RDTSC
+
+#include <config/local/timer.h>
+
+#endif /* CONFIG_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/config/umalloc.h b/qemu-0.15.x/roms/ipxe/src/config/umalloc.h
new file mode 100644
index 0000000..245c6b4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/config/umalloc.h
@@ -0,0 +1,16 @@
+#ifndef CONFIG_UMALLOC_H
+#define CONFIG_UMALLOC_H
+
+/** @file
+ *
+ * User memory allocation API configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+#include <config/local/umalloc.h>
+
+#endif /* CONFIG_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/core/acpi.c b/qemu-0.15.x/roms/ipxe/src/core/acpi.c
new file mode 100644
index 0000000..223765f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/acpi.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/acpi.h>
+#include <ipxe/interface.h>
+
+/** @file
+ *
+ * ACPI support functions
+ *
+ */
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Fix up ACPI table checksum
+ *
+ * @v acpi		ACPI table header
+ */
+void acpi_fix_checksum ( struct acpi_description_header *acpi ) {
+	unsigned int i = 0;
+	uint8_t sum = 0;
+
+	for ( i = 0 ; i < acpi->length ; i++ ) {
+		sum += *( ( ( uint8_t * ) acpi ) + i );
+	}
+	acpi->checksum -= sum;
+}
+
+/******************************************************************************
+ *
+ * Interface methods
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Describe object in an ACPI table
+ *
+ * @v intf		Interface
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+int acpi_describe ( struct interface *intf,
+		    struct acpi_description_header *acpi, size_t len ) {
+	struct interface *dest;
+	acpi_describe_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, acpi_describe, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	if ( op ) {
+		rc = op ( object, acpi, len );
+	} else {
+		/* Default is to fail to describe */
+		rc = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/ansiesc.c b/qemu-0.15.x/roms/ipxe/src/core/ansiesc.c
new file mode 100644
index 0000000..05bbb86
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/ansiesc.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/ansiesc.h>
+
+/** @file
+ *
+ * ANSI escape sequences
+ *
+ */
+
+/**
+ * Call ANSI escape sequence handler
+ *
+ * @v handlers		List of escape sequence handlers
+ * @v function		Control function identifier
+ * @v count		Parameter count
+ * @v params		Parameter list
+ */
+static void ansiesc_call_handler ( struct ansiesc_handler *handlers,
+				   unsigned int function, int count,
+				   int params[] ) {
+	struct ansiesc_handler *handler;
+
+	for ( handler = handlers ; handler->function ; handler++ ) {
+		if ( handler->function == function ) {
+			handler->handle ( count, params );
+			break;
+		}
+	}
+}
+
+/**
+ * Process character that may be part of ANSI escape sequence
+ *
+ * @v ctx		ANSI escape sequence context
+ * @v c			Character
+ * @ret c		Original character if not part of escape sequence
+ * @ret <0		Character was part of escape sequence
+ *
+ * ANSI escape sequences will be plucked out of the character stream
+ * and interpreted; once complete they will be passed to the
+ * appropriate handler if one exists in this ANSI escape sequence
+ * context.
+ *
+ * In the interests of code size, we are rather liberal about the
+ * sequences we are prepared to accept as valid.
+ */
+int ansiesc_process ( struct ansiesc_context *ctx, int c ) {
+	if ( ctx->count == 0 ) {
+		if ( c == ESC ) {
+			/* First byte of CSI : begin escape sequence */
+			ctx->count = 1;
+			memset ( ctx->params, 0xff, sizeof ( ctx->params ) );
+			ctx->function = 0;
+			return -1;
+		} else {
+			/* Normal character */
+			return c;
+		}
+	} else {
+		if ( c == '[' ) {
+			/* Second byte of CSI : do nothing */
+		} else if ( ( c >= '0' ) && ( c <= '9' ) ) {
+			/* Parameter Byte : part of a parameter value */
+			int *param = &ctx->params[ctx->count - 1];
+			if ( *param < 0 )
+				*param = 0;
+			*param = ( ( *param * 10 ) + ( c - '0' ) );
+		} else if ( c == ';' ) {
+			/* Parameter Byte : parameter delimiter */
+			ctx->count++;
+			if ( ctx->count > ( sizeof ( ctx->params ) /
+					    sizeof ( ctx->params[0] ) ) ) {
+				/* Excessive parameters : abort sequence */
+				ctx->count = 0;
+				DBG ( "Too many parameters in ANSI escape "
+				      "sequence\n" );
+			}
+		} else if ( ( c >= 0x20 ) && ( c <= 0x2f ) ) {
+			/* Intermediate Byte */
+			ctx->function <<= 8;
+			ctx->function |= c;
+		} else {
+			/* Treat as Final Byte.  Zero ctx->count before 
+			 * calling handler to avoid potential infinite loops.
+			 */
+			int count = ctx->count;
+			ctx->count = 0;
+			ctx->function <<= 8;
+			ctx->function |= c;
+			ansiesc_call_handler ( ctx->handlers, ctx->function,
+					       count, ctx->params );
+		}
+		return -1;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/asprintf.c b/qemu-0.15.x/roms/ipxe/src/core/asprintf.c
new file mode 100644
index 0000000..03cf45c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/asprintf.c
@@ -0,0 +1,49 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Write a formatted string to newly allocated memory.
+ *
+ * @v strp		Pointer to hold allocated string
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret	len		Length of formatted string
+ */
+int vasprintf ( char **strp, const char *fmt, va_list args ) {
+	size_t len;
+	va_list args_tmp;
+
+	/* Calculate length needed for string */
+	va_copy ( args_tmp, args );
+	len = ( vsnprintf ( NULL, 0, fmt, args_tmp ) + 1 );
+	va_end ( args_tmp );
+
+	/* Allocate and fill string */
+	*strp = malloc ( len );
+	if ( ! *strp )
+		return -ENOMEM;
+	return vsnprintf ( *strp, len, fmt, args );
+}
+
+/**
+ * Write a formatted string to newly allocated memory.
+ *
+ * @v strp		Pointer to hold allocated string
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret	len		Length of formatted string
+ */
+int asprintf ( char **strp, const char *fmt, ... ) {
+	va_list args;
+	int len;
+
+	va_start ( args, fmt );
+	len = vasprintf ( strp, fmt, args );
+	va_end ( args );
+	return len;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/base16.c b/qemu-0.15.x/roms/ipxe/src/core/base16.c
new file mode 100644
index 0000000..14de795
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/base16.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/base16.h>
+
+/** @file
+ *
+ * Base16 encoding
+ *
+ */
+
+/**
+ * Base16-encode data
+ *
+ * @v raw		Raw data
+ * @v len		Length of raw data
+ * @v encoded		Buffer for encoded string
+ *
+ * The buffer must be the correct length for the encoded string.  Use
+ * something like
+ *
+ *     char buf[ base16_encoded_len ( len ) + 1 ];
+ *
+ * (the +1 is for the terminating NUL) to provide a buffer of the
+ * correct size.
+ */
+void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
+	const uint8_t *raw_bytes = raw;
+	char *encoded_bytes = encoded;
+	size_t remaining = len;
+
+	for ( ; remaining-- ; encoded_bytes += 2 ) {
+		sprintf ( encoded_bytes, "%02x", *(raw_bytes++) );
+	}
+
+	DBG ( "Base16-encoded to \"%s\":\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
+}
+
+/**
+ * Base16-decode data
+ *
+ * @v encoded		Encoded string
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ *
+ * The buffer must be large enough to contain the decoded data.  Use
+ * something like
+ *
+ *     char buf[ base16_decoded_max_len ( encoded ) ];
+ *
+ * to provide a buffer of the correct size.
+ */
+int base16_decode ( const char *encoded, uint8_t *raw ) {
+	const char *encoded_bytes = encoded;
+	uint8_t *raw_bytes = raw;
+	char buf[3];
+	char *endp;
+	size_t len;
+
+	while ( encoded_bytes[0] ) {
+		if ( ! encoded_bytes[1] ) {
+			DBG ( "Base16-encoded string \"%s\" has invalid "
+			      "length\n", encoded );
+			return -EINVAL;
+		}
+		memcpy ( buf, encoded_bytes, 2 );
+		buf[2] = '\0';
+		*(raw_bytes++) = strtoul ( buf, &endp, 16 );
+		if ( *endp != '\0' ) {
+			DBG ( "Base16-encoded string \"%s\" has invalid "
+			      "byte \"%s\"\n", encoded, buf );
+			return -EINVAL;
+		}
+		encoded_bytes += 2;
+	}
+	len = ( raw_bytes - raw );
+
+	DBG ( "Base16-decoded \"%s\" to:\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( len <= base16_decoded_max_len ( encoded ) );
+
+	return ( len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/base64.c b/qemu-0.15.x/roms/ipxe/src/core/base64.c
new file mode 100644
index 0000000..7514c1f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/base64.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/base64.h>
+
+/** @file
+ *
+ * Base64 encoding
+ *
+ */
+
+static const char base64[64] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Base64-encode data
+ *
+ * @v raw		Raw data
+ * @v len		Length of raw data
+ * @v encoded		Buffer for encoded string
+ *
+ * The buffer must be the correct length for the encoded string.  Use
+ * something like
+ *
+ *     char buf[ base64_encoded_len ( len ) + 1 ];
+ *
+ * (the +1 is for the terminating NUL) to provide a buffer of the
+ * correct size.
+ */
+void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
+	const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
+	uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
+	size_t raw_bit_len = ( 8 * len );
+	unsigned int bit;
+	unsigned int tmp;
+
+	for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) {
+		tmp = ( ( raw_bytes[ bit / 8 ] << ( bit % 8 ) ) |
+			( raw_bytes[ bit / 8 + 1 ] >> ( 8 - ( bit % 8 ) ) ) );
+		tmp = ( ( tmp >> 2 ) & 0x3f );
+		*(encoded_bytes++) = base64[tmp];
+	}
+	for ( ; ( bit % 8 ) != 0 ; bit += 6 )
+		*(encoded_bytes++) = '=';
+	*(encoded_bytes++) = '\0';
+
+	DBG ( "Base64-encoded to \"%s\":\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( strlen ( encoded ) == base64_encoded_len ( len ) );
+}
+
+/**
+ * Base64-decode string
+ *
+ * @v encoded		Encoded string
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ *
+ * The buffer must be large enough to contain the decoded data.  Use
+ * something like
+ *
+ *     char buf[ base64_decoded_max_len ( encoded ) ];
+ *
+ * to provide a buffer of the correct size.
+ */
+int base64_decode ( const char *encoded, uint8_t *raw ) {
+	const uint8_t *encoded_bytes = ( ( const uint8_t * ) encoded );
+	uint8_t *raw_bytes = ( ( uint8_t * ) raw );
+	uint8_t encoded_byte;
+	char *match;
+	int decoded;
+	unsigned int bit = 0;
+	unsigned int pad_count = 0;
+	size_t len;
+
+	/* Zero the raw data */
+	memset ( raw, 0, base64_decoded_max_len ( encoded ) );
+
+	/* Decode string */
+	while ( ( encoded_byte = *(encoded_bytes++) ) ) {
+
+		/* Ignore whitespace characters */
+		if ( isspace ( encoded_byte ) )
+			continue;
+
+		/* Process pad characters */
+		if ( encoded_byte == '=' ) {
+			if ( pad_count >= 2 ) {
+				DBG ( "Base64-encoded string \"%s\" has too "
+				      "many pad characters\n", encoded );
+				return -EINVAL;
+			}
+			pad_count++;
+			bit -= 2; /* unused_bits = ( 2 * pad_count ) */
+			continue;
+		}
+		if ( pad_count ) {
+			DBG ( "Base64-encoded string \"%s\" has invalid pad "
+			      "sequence\n", encoded );
+			return -EINVAL;
+		}
+
+		/* Process normal characters */
+		match = strchr ( base64, encoded_byte );
+		if ( ! match ) {
+			DBG ( "Base64-encoded string \"%s\" contains invalid "
+			      "character '%c'\n", encoded, encoded_byte );
+			return -EINVAL;
+		}
+		decoded = ( match - base64 );
+
+		/* Add to raw data */
+		decoded <<= 2;
+		raw_bytes[ bit / 8 ] |= ( decoded >> ( bit % 8 ) );
+		raw_bytes[ bit / 8 + 1 ] |= ( decoded << ( 8 - ( bit % 8 ) ) );
+		bit += 6;
+	}
+
+	/* Check that we decoded a whole number of bytes */
+	if ( ( bit % 8 ) != 0 ) {
+		DBG ( "Base64-encoded string \"%s\" has invalid bit length "
+		      "%d\n", encoded, bit );
+		return -EINVAL;
+	}
+	len = ( bit / 8 );
+
+	DBG ( "Base64-decoded \"%s\" to:\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( len <= base64_decoded_max_len ( encoded ) );
+
+	/* Return length in bytes */
+	return ( len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/basename.c b/qemu-0.15.x/roms/ipxe/src/core/basename.c
new file mode 100644
index 0000000..a481c54
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/basename.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Get base name of path
+ *
+ */
+
+#include <string.h>
+#include <libgen.h>
+
+/**
+ * Return base name from path
+ *
+ * @v path		Full path
+ * @ret basename	Base name
+ */
+char * basename ( char *path ) {
+	char *basename;
+
+	basename = strrchr ( path, '/' );
+	return ( basename ? ( basename + 1 ) : path );
+}
+
+/**
+ * Return directory name from path
+ *
+ * @v path		Full path
+ * @ret dirname		Directory name
+ *
+ * Note that this function may modify its argument.
+ */
+char * dirname ( char *path ) {
+	char *separator;
+
+	separator = strrchr ( path, '/' );
+	if ( separator == path ) {
+		return "/";
+	} else if ( separator ) {
+		*separator = 0;
+		return path;
+	} else {
+		return ".";
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/bitmap.c b/qemu-0.15.x/roms/ipxe/src/core/bitmap.c
new file mode 100644
index 0000000..e9b6d90
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/bitmap.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/bitmap.h>
+
+/** @file
+ *
+ * Bitmaps for multicast downloads
+ *
+ */
+
+/**
+ * Resize bitmap
+ *
+ * @v bitmap		Bitmap
+ * @v new_length	New length of bitmap, in bits
+ * @ret rc		Return status code
+ */
+int bitmap_resize ( struct bitmap *bitmap, unsigned int new_length ) {
+	unsigned int old_num_blocks;
+	unsigned int new_num_blocks;
+	size_t new_size;
+	bitmap_block_t *new_blocks;
+
+	old_num_blocks = BITMAP_INDEX ( bitmap->length + BITMAP_BLKSIZE - 1 );
+	new_num_blocks = BITMAP_INDEX ( new_length + BITMAP_BLKSIZE - 1 );
+
+	if ( old_num_blocks != new_num_blocks ) {
+		new_size = ( new_num_blocks * sizeof ( bitmap->blocks[0] ) );
+		new_blocks = realloc ( bitmap->blocks, new_size );
+		if ( ! new_blocks ) {
+			DBGC ( bitmap, "Bitmap %p could not resize to %d "
+			       "bits\n", bitmap, new_length );
+			return -ENOMEM;
+		}
+		bitmap->blocks = new_blocks;
+	}
+	bitmap->length = new_length;
+
+	while ( old_num_blocks < new_num_blocks ) {
+		bitmap->blocks[old_num_blocks++] = 0;
+	}
+
+	DBGC ( bitmap, "Bitmap %p resized to %d bits\n", bitmap, new_length );
+	return 0;
+}
+
+/**
+ * Test bit in bitmap
+ *
+ * @v bitmap		Bitmap
+ * @v bit		Bit index
+ * @ret is_set		Bit is set
+ */
+int bitmap_test ( struct bitmap *bitmap, unsigned int bit ) {
+	unsigned int index = BITMAP_INDEX ( bit );
+        bitmap_block_t mask = BITMAP_MASK ( bit );
+
+	if ( bit >= bitmap->length )
+		return 0;
+	return ( ( bitmap->blocks[index] & mask ) != 0 );
+}
+
+/**
+ * Set bit in bitmap
+ *
+ * @v bitmap		Bitmap
+ * @v bit		Bit index
+ */
+void bitmap_set ( struct bitmap *bitmap, unsigned int bit ) {
+	unsigned int index = BITMAP_INDEX ( bit );
+        bitmap_block_t mask = BITMAP_MASK ( bit );
+
+	DBGC ( bitmap, "Bitmap %p setting bit %d\n", bitmap, bit );
+
+	/* Update bitmap */
+	bitmap->blocks[index] |= mask;
+
+	/* Update first gap counter */
+	while ( bitmap_test ( bitmap, bitmap->first_gap ) ) {
+		bitmap->first_gap++;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/bitops.c b/qemu-0.15.x/roms/ipxe/src/core/bitops.c
new file mode 100644
index 0000000..1bca9e4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/bitops.c
@@ -0,0 +1,13 @@
+#include <strings.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+int __flsl ( long x ) {
+	unsigned long value = x;
+	int ls = 0;
+
+	for ( ls = 0 ; value ; ls++ ) {
+		value >>= 1;
+	}
+	return ls;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/blockdev.c b/qemu-0.15.x/roms/ipxe/src/core/blockdev.c
new file mode 100644
index 0000000..182765e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/blockdev.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/interface.h>
+#include <ipxe/blockdev.h>
+
+/** @file
+ *
+ * Block devices
+ *
+ */
+
+/**
+ * Read from block device
+ *
+ * @v control		Control interface
+ * @v data		Data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of logical blocks
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int block_read ( struct interface *control, struct interface *data,
+		 uint64_t lba, unsigned int count,
+		 userptr_t buffer, size_t len ) {
+	struct interface *dest;
+	block_read_TYPE ( void * ) *op =
+		intf_get_dest_op ( control, block_read, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	if ( op ) {
+		rc = op ( object, data, lba, count, buffer, len );
+	} else {
+		/* Default is to fail to issue the command */
+		rc = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return rc;
+}
+
+/**
+ * Write to block device
+ *
+ * @v control		Control interface
+ * @v data		Data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of logical blocks
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int block_write ( struct interface *control, struct interface *data,
+		  uint64_t lba, unsigned int count,
+		  userptr_t buffer, size_t len ) {
+	struct interface *dest;
+	block_write_TYPE ( void * ) *op =
+		intf_get_dest_op ( control, block_write, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	if ( op ) {
+		rc = op ( object, data, lba, count, buffer, len );
+	} else {
+		/* Default is to fail to issue the command */
+		rc = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return rc;
+}
+
+/**
+ * Read block device capacity
+ *
+ * @v control		Control interface
+ * @v data		Data interface
+ * @ret rc		Return status code
+ */
+int block_read_capacity ( struct interface *control, struct interface *data ) {
+	struct interface *dest;
+	block_read_capacity_TYPE ( void * ) *op =
+		intf_get_dest_op ( control, block_read_capacity, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	if ( op ) {
+		rc = op ( object, data );
+	} else {
+		/* Default is to fail to issue the command */
+		rc = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return rc;
+}
+
+/**
+ * Report block device capacity
+ *
+ * @v intf		Interface
+ * @v capacity		Block device capacity
+ */
+void block_capacity ( struct interface *intf,
+		      struct block_device_capacity *capacity ) {
+	struct interface *dest;
+	block_capacity_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, block_capacity, &dest );
+	void *object = intf_object ( dest );
+
+	if ( op ) {
+		op ( object, capacity );
+	} else {
+		/* Default is to do nothing */
+	}
+
+	intf_put ( dest );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/btext.c b/qemu-0.15.x/roms/ipxe/src/core/btext.c
new file mode 100644
index 0000000..4fb7378
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/btext.c
@@ -0,0 +1,5039 @@
+#if 0
+
+/*
+ * Procedures for drawing on the screen early on in the boot process.
+ *
+ * Benjamin Herrenschmidt <benh at kernel.crashing.org>
+ *
+ *   move to LinuxBIOS by LYH yhlu at tyan.com
+ *   move to Etherboot by LYH
+ */
+
+#include <ipxe/console.h>
+#include <ipxe/init.h>
+#include <ipxe/pci.h>
+
+#undef __BIG_ENDIAN
+#if 0
+#define __LITTLE_ENDIAN 
+#endif
+
+#include "btext.h"
+
+//#define NO_SCROLL
+
+#ifndef NO_SCROLL
+static void scrollscreen(void);
+#endif
+
+static void draw_byte(const unsigned char c, u32 locX, u32 locY);
+#if 0
+static void draw_byte_32(const unsigned char *bits, u32 *base, u32 rb);
+static void draw_byte_16(const unsigned char *bits, u32 *base, u32 rb);
+#endif
+static void draw_byte_8(const unsigned char *bits, u32 *base, u32 rb);
+
+static u32 g_loc_X;
+static u32 g_loc_Y;
+static u32 g_max_loc_X;
+static u32 g_max_loc_Y;
+
+#define CHAR_256 0
+
+#if CHAR_256==1
+#define cmapsz	(16*256)
+#else
+#define cmapsz  (16*96)
+#endif
+
+static const unsigned char vga_font[cmapsz];
+
+u32 boot_text_mapped;
+
+boot_infos_t disp_bi;
+
+#define BTEXT		
+#define BTDATA	
+
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+static void
+btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch,
+		    unsigned long address)
+{
+	boot_infos_t* bi = &disp_bi;
+
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = width / 8;
+	g_max_loc_Y = height / 16;
+//	bi->logicalDisplayBase = (unsigned char *)address;
+	bi->dispDeviceBase = address;
+	bi->dispDeviceRowBytes = pitch;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	boot_text_mapped = 0;
+}
+
+/* Here's a small text engine to use during early boot
+ * or for debugging purposes
+ *
+ * todo:
+ *
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
+static void 
+map_boot_text(void)
+{
+	boot_infos_t *bi = &disp_bi;
+	
+	if (bi->dispDeviceBase == 0)
+		return;
+
+	boot_text_mapped = 0;	
+
+	bi->logicalDisplayBase = phys_to_virt(bi->dispDeviceBase);
+	
+	boot_text_mapped = 1;
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * BTEXT
+calc_base(boot_infos_t *bi, u32 x, u32 y)
+{
+	unsigned char *base;
+	base = bi->logicalDisplayBase;
+#if 0
+	/* Ummm... which moron wrote this? */
+	if (base == 0)
+		base = bi->dispDeviceBase;
+#endif
+	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
+	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
+	return base;
+}
+
+
+static void BTEXT btext_clearscreen(void)
+{
+	boot_infos_t* bi	= &disp_bi;
+	u32 *base	= (u32 *)calc_base(bi, 0, 0);
+	u32 width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	u32 i,j;
+
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		u32 *ptr = base;
+		for(j=width; j; --j)
+			*(ptr++) = 0;
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+#if 0
+__inline__ void dcbst(const void* addr)
+{
+	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
+}
+
+static void BTEXT btext_flushscreen(void)
+{
+	boot_infos_t* bi	= &disp_bi;
+	u32  *base	= (unsigned long *)calc_base(bi, 0, 0);
+	u32 width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	u32 i,j;
+
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		u32 *ptr = base;
+		for(j=width; j>0; j-=8) {
+			dcbst(ptr);
+			ptr += 8;
+		}
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+#endif
+
+
+#ifndef NO_SCROLL
+static BTEXT void
+scrollscreen(void)
+{
+	boot_infos_t* bi		= &disp_bi;
+	u32 *src		= (u32 *)calc_base(bi,0,16);
+	u32 *dst		= (u32 *)calc_base(bi,0,0);
+	u32 width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+						(bi->dispDeviceDepth >> 3)) >> 2;
+	u32 i,j;
+
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
+	{
+		u32 *src_ptr = src;
+		u32 *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = *(src_ptr++);
+		src += (bi->dispDeviceRowBytes >> 2);
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+	for (i=0; i<16; i++)
+	{
+		u32 *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = 0;
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+#endif /* ndef NO_SCROLL */
+
+static void BTEXT btext_drawchar(char c)
+{
+	u32 cline = 0;
+
+	if (!boot_text_mapped)
+		return;
+
+	switch (c) {
+	case '\b':
+		if (g_loc_X > 0)
+			--g_loc_X;
+		break;
+	case '\t':
+		g_loc_X = (g_loc_X & -8) + 8;
+		break;
+	case '\r':
+		g_loc_X = 0;
+		break;
+	case '\n':
+		g_loc_X = 0;
+		g_loc_Y++;
+		cline = 1;
+		break;
+	default:
+		draw_byte(c, g_loc_X++, g_loc_Y);
+	}
+	if (g_loc_X >= g_max_loc_X) {
+		g_loc_X = 0;
+		g_loc_Y++;
+		cline = 1;
+	}
+#ifndef NO_SCROLL
+	while (g_loc_Y >= g_max_loc_Y) {
+		scrollscreen();
+		g_loc_Y--;
+	}
+#else
+	/* wrap around from bottom to top of screen so we don't
+	   waste time scrolling each line.  -- paulus. */
+	if (g_loc_Y >= g_max_loc_Y)
+		g_loc_Y = 0;
+	if (cline) {
+		for (x = 0; x < g_max_loc_X; ++x)
+			draw_byte(' ', x, g_loc_Y);
+	}
+#endif
+}
+#if 0
+static void BTEXT
+btext_drawstring(const char *c)
+{
+	if (!boot_text_mapped)
+		return;
+	while (*c)
+		btext_drawchar(*c++);
+}
+static void BTEXT
+btext_drawhex(u32 v)
+{
+	static char hex_table[] = "0123456789abcdef";
+
+	if (!boot_text_mapped)
+		return;
+	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
+	btext_drawchar(' ');
+}
+#endif
+
+static void BTEXT
+draw_byte(const unsigned char c, u32 locX, u32 locY)
+{
+	boot_infos_t* bi	= &disp_bi;
+	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
+#if CHAR_256==1
+        unsigned const char *font     = &vga_font[(((u32)c)) * 16];
+#else
+	unsigned const char *font	= &vga_font[(((u32)c-0x20)) * 16];
+#endif
+
+	u32 rb			= bi->dispDeviceRowBytes;
+
+	switch(bi->dispDeviceDepth) {
+#if 0
+	case 24:
+	case 32:
+		draw_byte_32(font, (u32 *)base, rb);
+		break;
+	case 15:
+	case 16:
+		draw_byte_16(font, (u32 *)base, rb);
+		break;
+#endif
+	case 8:
+		draw_byte_8(font, (u32 *)base, rb);
+		break;
+	}
+}
+static u32 expand_bits_8[16] BTDATA = {
+#if defined(__BIG_ENDIAN)
+    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000,0xff000000,0x00ff0000,0xffff0000,
+    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif                      
+};
+#if 0
+static const u32 expand_bits_16[4] BTDATA = {
+#if defined(__BIG_ENDIAN)
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+#endif
+#if 0
+static void BTEXT
+draw_byte_32(const unsigned char *font, u32 *base, u32 rb)
+{
+	u32 l, bits;
+	u32 fg = 0xFFFFFFFF;
+	u32 bg = 0x00000000;
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (-(bits >> 7) & fg) ^ bg;
+		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+		base[7] = (-(bits & 1) & fg) ^ bg;
+		base = (u32 *) ((char *)base + rb);
+	}
+}
+
+static void BTEXT
+draw_byte_16(const unsigned char *font, u32 *base, u32 rb)
+{
+	u32 l, bits;
+	u32 fg = 0xFFFFFFFF;
+	u32 bg = 0x00000000;
+	u32 *eb = expand_bits_16;
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 6] & fg) ^ bg;
+		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+		base[3] = (eb[bits & 3] & fg) ^ bg;
+		base = (u32 *) ((char *)base + rb);
+	}
+}
+#endif
+static void BTEXT
+draw_byte_8(const unsigned char *font, u32 *base, u32 rb)
+{
+	u32 l, bits;
+	u32 fg = 0x0F0F0F0F;
+	u32 bg = 0x00000000;
+	u32 *eb = expand_bits_8;
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 4] & fg) ^ bg;
+		base[1] = (eb[bits & 0xf] & fg) ^ bg;
+		base = (u32 *) ((char *)base + rb);
+	}
+}
+
+static void btext_init(void)
+{
+#if 0
+// for debug
+#define frame_buffer 0xfc000000
+#else
+    uint32_t frame_buffer;//  0xfc000000
+
+    struct pci_device dev;
+
+    #warning "pci_find_device_x no longer exists; use find_pci_device instead"
+    /*    pci_find_device_x(0x1002, 0x4752, 0, &dev); */
+    if(dev.vendor==0) return; // no fb
+
+    frame_buffer = (uint32_t)dev.membase;
+#endif
+
+	btext_setup_display(640, 480, 8, 640,frame_buffer);
+	btext_clearscreen();
+	map_boot_text();
+}
+static void btext_putc(int c)
+{	
+        btext_drawchar((unsigned char)c);
+}
+
+struct console_driver btext_console __console_driver = {
+	.putchar = btext_putc,
+	.disabled = 1,
+};
+
+//come from linux/drivers/video/font-8x16.c
+/**********************************************/
+/*                                            */
+/*       Font file generated by cpi2fnt       */
+/*                                            */
+/**********************************************/
+
+
+static const unsigned char vga_font[cmapsz] BTDATA = {
+#if CHAR_256==1
+	/* 0 0x00 '^@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 1 0x01 '^A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x81, /* 10000001 */
+	0xa5, /* 10100101 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 2 0x02 '^B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xdb, /* 11011011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 3 0x03 '^C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 4 0x04 '^D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 5 0x05 '^E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 6 0x06 '^F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 8 0x08 '^H' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xe7, /* 11100111 */
+	0xc3, /* 11000011 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x42, /* 01000010 */
+	0x42, /* 01000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 10 0x0a '^J' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0x99, /* 10011001 */
+	0xbd, /* 10111101 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0xc3, /* 11000011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 11 0x0b '^K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x1a, /* 00011010 */
+	0x32, /* 00110010 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 12 0x0c '^L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 13 0x0d '^M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x33, /* 00110011 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x70, /* 01110000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 14 0x0e '^N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x67, /* 01100111 */
+	0xe7, /* 11100111 */
+	0xe6, /* 11100110 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 15 0x0f '^O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xdb, /* 11011011 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0x3c, /* 00111100 */
+	0xdb, /* 11011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 16 0x10 '^P' */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0xf0, /* 11110000 */
+	0xf8, /* 11111000 */
+	0xfe, /* 11111110 */
+	0xf8, /* 11111000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 17 0x11 '^Q' */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0e, /* 00001110 */
+	0x1e, /* 00011110 */
+	0x3e, /* 00111110 */
+	0xfe, /* 11111110 */
+	0x3e, /* 00111110 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 18 0x12 '^R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 19 0x13 '^S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 20 0x14 '^T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7b, /* 01111011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 21 0x15 '^U' */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 23 0x17 '^W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 24 0x18 '^X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 25 0x19 '^Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xfe, /* 11111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x28, /* 00101000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x28, /* 00101000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 31 0x1f '^_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+#endif
+	/* 32 0x20 ' ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 33 0x21 '!' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 34 0x22 '"' */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 35 0x23 '#' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 36 0x24 '$' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x86, /* 10000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 37 0x25 '%' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 38 0x26 '&' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 39 0x27 ''' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 40 0x28 '(' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 41 0x29 ')' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 42 0x2a '*' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0xff, /* 11111111 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 43 0x2b '+' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 44 0x2c ',' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 45 0x2d '-' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 46 0x2e '.' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 47 0x2f '/' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 48 0x30 '0' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 49 0x31 '1' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x38, /* 00111000 */
+	0x78, /* 01111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 50 0x32 '2' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 51 0x33 '3' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x3c, /* 00111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 52 0x34 '4' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x1c, /* 00011100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 53 0x35 '5' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 54 0x36 '6' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 55 0x37 '7' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 56 0x38 '8' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 57 0x39 '9' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 58 0x3a ':' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 59 0x3b ';' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 60 0x3c '<' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 61 0x3d '=' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 62 0x3e '>' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 63 0x3f '?' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 64 0x40 '@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xdc, /* 11011100 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 65 0x41 'A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 66 0x42 'B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 67 0x43 'C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 68 0x44 'D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 69 0x45 'E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 70 0x46 'F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 71 0x47 'G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xde, /* 11011110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x66, /* 01100110 */
+	0x3a, /* 00111010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 72 0x48 'H' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 73 0x49 'I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 74 0x4a 'J' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 75 0x4b 'K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe6, /* 11100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 76 0x4c 'L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 77 0x4d 'M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xee, /* 11101110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 78 0x4e 'N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 79 0x4f 'O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 80 0x50 'P' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 81 0x51 'Q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xde, /* 11011110 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 82 0x52 'R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 83 0x53 'S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 84 0x54 'T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x5a, /* 01011010 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 85 0x55 'U' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 86 0x56 'V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 87 0x57 'W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0xee, /* 11101110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 88 0x58 'X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 89 0x59 'Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 90 0x5a 'Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 91 0x5b '[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 92 0x5c '\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0x70, /* 01110000 */
+	0x38, /* 00111000 */
+	0x1c, /* 00011100 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 93 0x5d ']' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 94 0x5e '^' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 95 0x5f '_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 96 0x60 '`' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 97 0x61 'a' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 98 0x62 'b' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 99 0x63 'c' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 100 0x64 'd' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 101 0x65 'e' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 102 0x66 'f' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x36, /* 00110110 */
+	0x32, /* 00110010 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 103 0x67 'g' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 104 0x68 'h' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x6c, /* 01101100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 105 0x69 'i' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 106 0x6a 'j' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 107 0x6b 'k' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 108 0x6c 'l' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 112 0x70 'p' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 113 0x71 'q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+
+	/* 114 0x72 'r' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 115 0x73 's' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 116 0x74 't' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0xfc, /* 11111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x36, /* 00110110 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 117 0x75 'u' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 118 0x76 'v' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 119 0x77 'w' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 120 0x78 'x' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 121 0x79 'y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+
+	/* 122 0x7a 'z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 123 0x7b '{' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 124 0x7c '|' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 125 0x7d '}' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 126 0x7e '~' */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 127 0x7f '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+#if CHAR_256256==1
+	/* 128 0x80 '€' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 129 0x81 '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 130 0x82 '‚' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 131 0x83 'ƒ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 132 0x84 '„' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 133 0x85 '…' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 134 0x86 '†' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 135 0x87 '‡' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 136 0x88 'ˆ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 137 0x89 '‰' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 138 0x8a 'Š' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 139 0x8b '‹' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 140 0x8c 'Œ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 141 0x8d '' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 142 0x8e 'Ž' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 143 0x8f '' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 144 0x90 '' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 145 0x91 '‘' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x6e, /* 01101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 146 0x92 '’' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3e, /* 00111110 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xce, /* 11001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 147 0x93 '“' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 148 0x94 '”' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 149 0x95 '•' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 150 0x96 '–' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 151 0x97 '—' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 152 0x98 '˜' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 153 0x99 '™' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 154 0x9a 'š' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 155 0x9b '›' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 156 0x9c 'œ' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x64, /* 01100100 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xe6, /* 11100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 157 0x9d '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 158 0x9e 'ž' */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xf8, /* 11111000 */
+	0xc4, /* 11000100 */
+	0xcc, /* 11001100 */
+	0xde, /* 11011110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 159 0x9f 'Ÿ' */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 160 0xa0 ' ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 161 0xa1 '¡' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 162 0xa2 '¢' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 163 0xa3 '£' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 164 0xa4 '¤' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 165 0xa5 '¥' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 166 0xa6 '¦' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 167 0xa7 '§' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 168 0xa8 '¨' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 169 0xa9 '©' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 170 0xaa 'ª' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 171 0xab '«' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xdc, /* 11011100 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 172 0xac '¬' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x66, /* 01100110 */
+	0xce, /* 11001110 */
+	0x9a, /* 10011010 */
+	0x3f, /* 00111111 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 173 0xad '­' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 174 0xae '®' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 175 0xaf '¯' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 176 0xb0 '°' */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+
+	/* 177 0xb1 '±' */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+
+	/* 178 0xb2 '²' */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+
+	/* 179 0xb3 '³' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 180 0xb4 '´' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 181 0xb5 'µ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 182 0xb6 '¶' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 183 0xb7 '·' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 184 0xb8 '¸' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 185 0xb9 '¹' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 186 0xba 'º' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 187 0xbb '»' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 188 0xbc '¼' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 189 0xbd '½' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 190 0xbe '¾' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 191 0xbf '¿' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 192 0xc0 'À' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 193 0xc1 'Á' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 194 0xc2 'Â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 195 0xc3 'Ã' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 196 0xc4 'Ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 197 0xc5 'Å' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 198 0xc6 'Æ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 199 0xc7 'Ç' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 200 0xc8 'È' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 201 0xc9 'É' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 202 0xca 'Ê' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 203 0xcb 'Ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 204 0xcc 'Ì' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 205 0xcd 'Í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 206 0xce 'Î' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 207 0xcf 'Ï' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 208 0xd0 'Ð' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 209 0xd1 'Ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 210 0xd2 'Ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 211 0xd3 'Ó' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 212 0xd4 'Ô' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 213 0xd5 'Õ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 214 0xd6 'Ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 215 0xd7 '×' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 216 0xd8 'Ø' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 217 0xd9 'Ù' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 218 0xda 'Ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 219 0xdb 'Û' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 220 0xdc 'Ü' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 221 0xdd 'Ý' */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+
+	/* 222 0xde 'Þ' */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+
+	/* 223 0xdf 'ß' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 224 0xe0 'à' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 225 0xe1 'á' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xd8, /* 11011000 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 226 0xe2 'â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 227 0xe3 'ã' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 228 0xe4 'ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 229 0xe5 'å' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 230 0xe6 'æ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+
+	/* 231 0xe7 'ç' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 232 0xe8 'è' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 233 0xe9 'é' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 234 0xea 'ê' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xee, /* 11101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 235 0xeb 'ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x3e, /* 00111110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 236 0xec 'ì' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 237 0xed 'í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x03, /* 00000011 */
+	0x06, /* 00000110 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xf3, /* 11110011 */
+	0x7e, /* 01111110 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 238 0xee 'î' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 239 0xef 'ï' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 240 0xf0 'ð' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 241 0xf1 'ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 242 0xf2 'ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 243 0xf3 'ó' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 244 0xf4 'ô' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 245 0xf5 'õ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 246 0xf6 'ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 247 0xf7 '÷' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 248 0xf8 'ø' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 249 0xf9 'ù' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 250 0xfa 'ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 251 0xfb 'û' */
+	0x00, /* 00000000 */
+	0x0f, /* 00001111 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xec, /* 11101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3c, /* 00111100 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 252 0xfc 'ü' */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 253 0xfd 'ý' */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x32, /* 00110010 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 254 0xfe 'þ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 255 0xff 'ÿ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+#endif
+};
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/core/console.c b/qemu-0.15.x/roms/ipxe/src/core/console.c
new file mode 100644
index 0000000..f27edf4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/console.c
@@ -0,0 +1,130 @@
+#include "stddef.h"
+#include <ipxe/console.h>
+#include <ipxe/process.h>
+#include <ipxe/nap.h>
+
+/** @file */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Write a single character to each console device.
+ *
+ * @v character		Character to be written
+ * @ret None		-
+ * @err None		-
+ *
+ * The character is written out to all enabled console devices, using
+ * each device's console_driver::putchar() method.
+ *
+ */
+void putchar ( int character ) {
+	struct console_driver *console;
+
+	/* Automatic LF -> CR,LF translation */
+	if ( character == '\n' )
+		putchar ( '\r' );
+
+	for_each_table_entry ( console, CONSOLES ) {
+		if ( ( ! console->disabled ) && console->putchar )
+			console->putchar ( character );
+	}
+}
+
+/**
+ * Check to see if any input is available on any console.
+ *
+ * @v None		-
+ * @ret console		Console device that has input available, if any.
+ * @ret NULL		No console device has input available.
+ * @err None		-
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method.  The first
+ * console device that has available input will be returned, if any.
+ *
+ */
+static struct console_driver * has_input ( void ) {
+	struct console_driver *console;
+
+	for_each_table_entry ( console, CONSOLES ) {
+		if ( ( ! console->disabled ) && console->iskey ) {
+			if ( console->iskey () )
+				return console;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Read a single character from any console.
+ *
+ * @v None		-
+ * @ret character	Character read from a console.
+ * @err None		-
+ *
+ * A character will be read from the first enabled console device that
+ * has input available using that console's console_driver::getchar()
+ * method.  If no console has input available to be read, this method
+ * will block.  To perform a non-blocking read, use something like
+ *
+ * @code
+ *
+ *   int key = iskey() ? getchar() : -1;
+ *
+ * @endcode
+ *
+ * The character read will not be echoed back to any console.
+ *
+ */
+int getchar ( void ) {
+	struct console_driver *console;
+	int character;
+
+	while ( 1 ) {
+		console = has_input();
+		if ( console && console->getchar ) {
+			character = console->getchar ();
+			break;
+		}
+
+		/* Doze for a while (until the next interrupt).  This works
+		 * fine, because the keyboard is interrupt-driven, and the
+		 * timer interrupt (approx. every 50msec) takes care of the
+		 * serial port, which is read by polling.  This reduces the
+		 * power dissipation of a modern CPU considerably, and also
+		 * makes Etherboot waiting for user interaction waste a lot
+		 * less CPU time in a VMware session.
+		 */
+		cpu_nap();
+
+		/* Keep processing background tasks while we wait for
+		 * input.
+		 */
+		step();
+	}
+
+	/* CR -> LF translation */
+	if ( character == '\r' )
+		character = '\n';
+
+	return character;
+}
+
+/** Check for available input on any console.
+ *
+ * @v None		-
+ * @ret True		Input is available on a console
+ * @ret False		Input is not available on any console
+ * @err None		-
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method.  If any console
+ * device has input available, this call will return True.  If this
+ * call returns True, you can then safely call getchar() without
+ * blocking.
+ *
+ */
+int iskey ( void ) {
+	return has_input() ? 1 : 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/cpio.c b/qemu-0.15.x/roms/ipxe/src/core/cpio.c
new file mode 100644
index 0000000..5b7b3aa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/cpio.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * CPIO archives
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/cpio.h>
+
+/**
+ * Set field within a CPIO header
+ *
+ * @v field		Field within CPIO header
+ * @v value		Value to set
+ */
+void cpio_set_field ( char *field, unsigned long value ) {
+	char buf[9];
+
+	snprintf ( buf, sizeof ( buf ), "%08lx", value );
+	memcpy ( field, buf, 8 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/ctype.c b/qemu-0.15.x/roms/ipxe/src/core/ctype.c
new file mode 100644
index 0000000..6185bb2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/ctype.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Character types
+ *
+ */
+
+#include <ctype.h>
+
+/**
+ * Check to see if character is a space
+ *
+ * @v c			Character
+ * @ret isspace		Character is a space
+ */
+int isspace ( int c ) {
+	switch ( c ) {
+	case ' ' :
+	case '\f' :
+	case '\n' :
+	case '\r' :
+	case '\t' :
+	case '\v' :
+		return 1;
+	default:
+		return 0;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/cwuri.c b/qemu-0.15.x/roms/ipxe/src/core/cwuri.c
new file mode 100644
index 0000000..893e205
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/cwuri.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <ipxe/uri.h>
+
+/** @file
+ *
+ * Current working URI
+ *
+ * Somewhat analogous to the current working directory in a POSIX
+ * system.
+ */
+
+/** Current working URI */
+struct uri *cwuri = NULL;
+
+/**
+ * Change working URI
+ *
+ * @v uri		New working URI, or NULL
+ */
+void churi ( struct uri *uri ) {
+	struct uri *new_uri = NULL;
+
+	if ( uri )
+		new_uri = resolve_uri ( cwuri, uri );
+
+	uri_put ( cwuri );
+	cwuri = new_uri;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/debug.c b/qemu-0.15.x/roms/ipxe/src/core/debug.c
new file mode 100644
index 0000000..73e74d9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/debug.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <ipxe/io.h>
+#include <ipxe/console.h>
+
+/**
+ * Pause until a key is pressed
+ *
+ */
+void dbg_pause ( void ) {
+	printf ( "\nPress a key..." );
+	getchar();
+	printf ( "\r              \r" );
+}
+
+/**
+ * Indicate more data to follow and pause until a key is pressed
+ *
+ */
+void dbg_more ( void ) {
+	printf ( "---more---" );
+	getchar();
+	printf ( "\r          \r" );
+}
+
+/**
+ * Print row of a hex dump with specified display address
+ *
+ * @v dispaddr		Display address
+ * @v data		Data to print
+ * @v len		Length of data
+ * @v offset		Starting offset within data
+ */
+static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data,
+				  unsigned long len, unsigned int offset ) {
+	const uint8_t *bytes = data;
+	unsigned int i;
+	uint8_t byte;
+
+	printf ( "%08lx :", ( dispaddr + offset ) );
+	for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
+		if ( i >= len ) {
+			printf ( "   " );
+			continue;
+		}
+		printf ( "%c%02x",
+			 ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
+	}
+	printf ( " : " );
+	for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
+		if ( i >= len ) {
+			printf ( " " );
+			continue;
+		}
+		byte = bytes[i];
+		if ( ( byte < 0x20 ) || ( byte >= 0x7f ) )
+			byte = '.';
+		printf ( "%c", byte );
+	}
+	printf ( "\n" );
+}
+
+/**
+ * Print hex dump with specified display address
+ *
+ * @v dispaddr		Display address
+ * @v data		Data to print
+ * @v len		Length of data
+ */
+void dbg_hex_dump_da ( unsigned long dispaddr, const void *data,
+		       unsigned long len ) {
+	unsigned int offset;
+
+	for ( offset = 0 ; offset < len ; offset += 16 ) {
+		dbg_hex_dump_da_row ( dispaddr, data, len, offset );
+	}
+}
+
+/**
+ * Maximum number of separately coloured message streams
+ *
+ * Six is the realistic maximum; there are 8 basic ANSI colours, one
+ * of which will be the terminal default and one of which will be
+ * invisible on the terminal because it matches the background colour.
+ */
+#define NUM_AUTO_COLOURS 6
+
+/** A colour assigned to an autocolourised debug message stream */
+struct autocolour {
+	/** Message stream ID */
+	unsigned long stream;
+	/** Last recorded usage */
+	unsigned long last_used;
+};
+
+/**
+ * Choose colour index for debug autocolourisation
+ *
+ * @v stream		Message stream ID
+ * @ret colour		Colour ID
+ */
+static int dbg_autocolour ( unsigned long stream ) {
+	static struct autocolour acs[NUM_AUTO_COLOURS];
+	static unsigned long use;
+	unsigned int i;
+	unsigned int oldest;
+	unsigned int oldest_last_used;
+
+	/* Increment usage iteration counter */
+	use++;
+
+	/* Scan through list for a currently assigned colour */
+	for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) {
+		if ( acs[i].stream == stream ) {
+			acs[i].last_used = use;
+			return i;
+		}
+	}
+
+	/* No colour found; evict the oldest from the list */
+	oldest = 0;
+	oldest_last_used = use;
+	for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) {
+		if ( acs[i].last_used < oldest_last_used ) {
+			oldest_last_used = acs[i].last_used;
+			oldest = i;
+		}
+	}
+	acs[oldest].stream = stream;
+	acs[oldest].last_used = use;
+	return oldest;
+}
+
+/**
+ * Select automatic colour for debug messages
+ *
+ * @v stream		Message stream ID
+ */
+void dbg_autocolourise ( unsigned long stream ) {
+	printf ( "\033[%dm",
+		 ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
+}
+
+/**
+ * Revert to normal colour
+ *
+ */
+void dbg_decolourise ( void ) {
+	printf ( "\033[0m" );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/debug_md5.c b/qemu-0.15.x/roms/ipxe/src/core/debug_md5.c
new file mode 100644
index 0000000..6214f61
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/debug_md5.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdint.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+
+/**
+ * Print an MD5 checksum with specified display address
+ *
+ * @v dispaddr		Display address
+ * @v data		Data to checksum
+ * @v len		Length of data
+ */
+void dbg_md5_da ( unsigned long dispaddr, const void *data,
+		  unsigned long len ) {
+	struct digest_algorithm *digest = &md5_algorithm;
+	uint8_t digest_ctx[digest->ctxsize];
+	uint8_t digest_out[digest->digestsize];
+	unsigned int i;
+
+	printf ( "md5sum ( %#08lx, %#lx ) = ", dispaddr, len );
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, data, len );
+	digest_final ( digest, digest_ctx, digest_out );
+	for ( i = 0 ; i < sizeof ( digest_out ) ; i++ )
+		printf ( "%02x", digest_out[i] );
+	printf ( "\n" );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/device.c b/qemu-0.15.x/roms/ipxe/src/core/device.c
new file mode 100644
index 0000000..dc182e0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/device.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/init.h>
+#include <ipxe/interface.h>
+#include <ipxe/device.h>
+
+/**
+ * @file
+ *
+ * Device model
+ *
+ */
+
+/** Registered root devices */
+static LIST_HEAD ( devices );
+
+/** Device removal inhibition counter */
+int device_keep_count = 0;
+
+/**
+ * Probe a root device
+ *
+ * @v rootdev		Root device
+ * @ret rc		Return status code
+ */
+static int rootdev_probe ( struct root_device *rootdev ) {
+	int rc;
+
+	DBG ( "Adding %s root bus\n", rootdev->dev.name );
+	if ( ( rc = rootdev->driver->probe ( rootdev ) ) != 0 ) {
+		DBG ( "Failed to add %s root bus: %s\n",
+		      rootdev->dev.name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Remove a root device
+ *
+ * @v rootdev		Root device
+ */
+static void rootdev_remove ( struct root_device *rootdev ) {
+	rootdev->driver->remove ( rootdev );
+	DBG ( "Removed %s root bus\n", rootdev->dev.name );
+}
+
+/**
+ * Probe all devices
+ *
+ * This initiates probing for all devices in the system.  After this
+ * call, the device hierarchy will be populated, and all hardware
+ * should be ready to use.
+ */
+static void probe_devices ( void ) {
+	struct root_device *rootdev;
+	int rc;
+
+	for_each_table_entry ( rootdev, ROOT_DEVICES ) {
+		list_add ( &rootdev->dev.siblings, &devices );
+		INIT_LIST_HEAD ( &rootdev->dev.children );
+		if ( ( rc = rootdev_probe ( rootdev ) ) != 0 )
+			list_del ( &rootdev->dev.siblings );
+	}
+}
+
+/**
+ * Remove all devices
+ *
+ */
+static void remove_devices ( int booting __unused ) {
+	struct root_device *rootdev;
+	struct root_device *tmp;
+
+	if ( device_keep_count != 0 ) {
+		DBG ( "Refusing to remove devices on shutdown\n" );
+		return;
+	}
+
+	list_for_each_entry_safe ( rootdev, tmp, &devices, dev.siblings ) {
+		rootdev_remove ( rootdev );
+		list_del ( &rootdev->dev.siblings );
+	}
+}
+
+struct startup_fn startup_devices __startup_fn ( STARTUP_NORMAL ) = {
+	.startup = probe_devices,
+	.shutdown = remove_devices,
+};
+
+/**
+ * Identify a device behind an interface
+ *
+ * @v intf		Interface
+ * @ret device		Device, or NULL
+ */
+struct device * identify_device ( struct interface *intf ) {
+	struct interface *dest;
+	identify_device_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, identify_device, &dest );
+	void *object = intf_object ( dest );
+	void *device;
+
+	if ( op ) {
+		device = op ( object );
+	} else {
+		/* Default is to return NULL */
+		device = NULL;
+	}
+
+	intf_put ( dest );
+	return device;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/downloader.c b/qemu-0.15.x/roms/ipxe/src/core/downloader.c
new file mode 100644
index 0000000..4dc0aa0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/downloader.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/job.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/image.h>
+#include <ipxe/downloader.h>
+
+/** @file
+ *
+ * Image downloader
+ *
+ */
+
+/** A downloader */
+struct downloader {
+	/** Reference count for this object */
+	struct refcnt refcnt;
+
+	/** Job control interface */
+	struct interface job;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** Image to contain downloaded file */
+	struct image *image;
+	/** Current position within image buffer */
+	size_t pos;
+};
+
+/**
+ * Free downloader object
+ *
+ * @v refcnt		Downloader reference counter
+ */
+static void downloader_free ( struct refcnt *refcnt ) {
+	struct downloader *downloader =
+		container_of ( refcnt, struct downloader, refcnt );
+
+	image_put ( downloader->image );
+	free ( downloader );
+}
+
+/**
+ * Terminate download
+ *
+ * @v downloader	Downloader
+ * @v rc		Reason for termination
+ */
+static void downloader_finished ( struct downloader *downloader, int rc ) {
+
+	/* Shut down interfaces */
+	intf_shutdown ( &downloader->xfer, rc );
+	intf_shutdown ( &downloader->job, rc );
+}
+
+/**
+ * Ensure that download buffer is large enough for the specified size
+ *
+ * @v downloader	Downloader
+ * @v len		Required minimum size
+ * @ret rc		Return status code
+ */
+static int downloader_ensure_size ( struct downloader *downloader,
+				    size_t len ) {
+	userptr_t new_buffer;
+
+	/* If buffer is already large enough, do nothing */
+	if ( len <= downloader->image->len )
+		return 0;
+
+	DBGC ( downloader, "Downloader %p extending to %zd bytes\n",
+	       downloader, len );
+
+	/* Extend buffer */
+	new_buffer = urealloc ( downloader->image->data, len );
+	if ( ! new_buffer ) {
+		DBGC ( downloader, "Downloader %p could not extend buffer to "
+		       "%zd bytes\n", downloader, len );
+		return -ENOBUFS;
+	}
+	downloader->image->data = new_buffer;
+	downloader->image->len = len;
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Job control interface
+ *
+ */
+
+/**
+ * Report progress of download job
+ *
+ * @v downloader	Downloader
+ * @v progress		Progress report to fill in
+ */
+static void downloader_progress ( struct downloader *downloader,
+				  struct job_progress *progress ) {
+
+	/* This is not entirely accurate, since downloaded data may
+	 * arrive out of order (e.g. with multicast protocols), but
+	 * it's a reasonable first approximation.
+	 */
+	progress->completed = downloader->pos;
+	progress->total = downloader->image->len;
+}
+
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
+/**
+ * Handle received data
+ *
+ * @v downloader	Downloader
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int downloader_xfer_deliver ( struct downloader *downloader,
+				     struct io_buffer *iobuf,
+				     struct xfer_metadata *meta ) {
+	size_t len;
+	size_t max;
+	int rc;
+
+	/* Calculate new buffer position */
+	if ( meta->flags & XFER_FL_ABS_OFFSET )
+		downloader->pos = 0;
+	downloader->pos += meta->offset;
+
+	/* Ensure that we have enough buffer space for this data */
+	len = iob_len ( iobuf );
+	max = ( downloader->pos + len );
+	if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
+		goto done;
+
+	/* Copy data to buffer */
+	copy_to_user ( downloader->image->data, downloader->pos,
+		       iobuf->data, len );
+
+	/* Update current buffer position */
+	downloader->pos += len;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** Downloader data transfer interface operations */
+static struct interface_operation downloader_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct downloader *, downloader_xfer_deliver ),
+	INTF_OP ( intf_close, struct downloader *, downloader_finished ),
+};
+
+/** Downloader data transfer interface descriptor */
+static struct interface_descriptor downloader_xfer_desc =
+	INTF_DESC ( struct downloader, xfer, downloader_xfer_operations );
+
+/****************************************************************************
+ *
+ * Job control interface
+ *
+ */
+
+/** Downloader job control interface operations */
+static struct interface_operation downloader_job_op[] = {
+	INTF_OP ( job_progress, struct downloader *, downloader_progress ),
+	INTF_OP ( intf_close, struct downloader *, downloader_finished ),
+};
+
+/** Downloader job control interface descriptor */
+static struct interface_descriptor downloader_job_desc =
+	INTF_DESC ( struct downloader, job, downloader_job_op );
+
+/****************************************************************************
+ *
+ * Instantiator
+ *
+ */
+
+/**
+ * Instantiate a downloader
+ *
+ * @v job		Job control interface
+ * @v image		Image to fill with downloaded file
+ * @v type		Location type to pass to xfer_open()
+ * @v ...		Remaining arguments to pass to xfer_open()
+ * @ret rc		Return status code
+ *
+ * Instantiates a downloader object to download the specified URI into
+ * the specified image object.
+ */
+int create_downloader ( struct interface *job, struct image *image,
+			int type, ... ) {
+	struct downloader *downloader;
+	va_list args;
+	int rc;
+
+	/* Allocate and initialise structure */
+	downloader = zalloc ( sizeof ( *downloader ) );
+	if ( ! downloader )
+		return -ENOMEM;
+	ref_init ( &downloader->refcnt, downloader_free );
+	intf_init ( &downloader->job, &downloader_job_desc,
+		    &downloader->refcnt );
+	intf_init ( &downloader->xfer, &downloader_xfer_desc,
+		    &downloader->refcnt );
+	downloader->image = image_get ( image );
+	va_start ( args, type );
+
+	/* Instantiate child objects and attach to our interfaces */
+	if ( ( rc = xfer_vopen ( &downloader->xfer, type, args ) ) != 0 )
+		goto err;
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &downloader->job, job );
+	ref_put ( &downloader->refcnt );
+	va_end ( args );
+	return 0;
+
+ err:
+	downloader_finished ( downloader, rc );
+	ref_put ( &downloader->refcnt );
+	va_end ( args );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/edd.c b/qemu-0.15.x/roms/ipxe/src/core/edd.c
new file mode 100644
index 0000000..8ba24b1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/edd.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/interface.h>
+#include <ipxe/edd.h>
+
+/** @file
+ *
+ * Enhanced Disk Drive specification
+ *
+ */
+
+/**
+ * Describe a disk device using EDD
+ *
+ * @v intf		Interface
+ * @v type		EDD interface type
+ * @v path		EDD device path
+ * @ret rc		Return status code
+ */
+int edd_describe ( struct interface *intf, struct edd_interface_type *type,
+		   union edd_device_path *path ) {
+	struct interface *dest;
+	edd_describe_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, edd_describe, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	if ( op ) {
+		rc = op ( object, type, path );
+	} else {
+		/* Default is to not support this operation */
+		rc = -ENOTSUP;
+	}
+
+	intf_put ( dest );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/errno.c b/qemu-0.15.x/roms/ipxe/src/core/errno.c
new file mode 100644
index 0000000..b4f44ce
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/errno.c
@@ -0,0 +1,18 @@
+#include <errno.h>
+
+/** @file
+ *
+ * Error codes
+ *
+ * This file provides the global variable #errno.
+ *
+ */
+
+/**
+ * Global "last error" number.
+ *
+ * This is valid only when a function has just returned indicating a
+ * failure.
+ *
+ */
+int errno;
diff --git a/qemu-0.15.x/roms/ipxe/src/core/exec.c b/qemu-0.15.x/roms/ipxe/src/core/exec.c
new file mode 100644
index 0000000..18d3477
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/exec.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/tables.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/settings.h>
+#include <ipxe/shell.h>
+
+/** @file
+ *
+ * Command execution
+ *
+ */
+
+/** Shell stop state */
+static int stop_state;
+
+/**
+ * Execute command
+ *
+ * @v command		Command name
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ *
+ * Execute the named command.  Unlike a traditional POSIX execv(),
+ * this function returns the exit status of the command.
+ */
+int execv ( const char *command, char * const argv[] ) {
+	struct command *cmd;
+	int argc;
+
+	/* Count number of arguments */
+	for ( argc = 0 ; argv[argc] ; argc++ ) {}
+
+	/* An empty command is deemed to do nothing, successfully */
+	if ( command == NULL )
+		return 0;
+
+	/* Sanity checks */
+	if ( argc == 0 ) {
+		DBG ( "%s: empty argument list\n", command );
+		return -EINVAL;
+	}
+
+	/* Reset getopt() library ready for use by the command.  This
+	 * is an artefact of the POSIX getopt() API within the context
+	 * of Etherboot; see the documentation for reset_getopt() for
+	 * details.
+	 */
+	reset_getopt();
+
+	/* Hand off to command implementation */
+	for_each_table_entry ( cmd, COMMANDS ) {
+		if ( strcmp ( command, cmd->name ) == 0 )
+			return cmd->exec ( argc, ( char ** ) argv );
+	}
+
+	printf ( "%s: command not found\n", command );
+	return -ENOEXEC;
+}
+
+/**
+ * Split command line into tokens
+ *
+ * @v command		Command line
+ * @v tokens		Token list to populate, or NULL
+ * @ret count		Number of tokens
+ *
+ * Splits the command line into whitespace-delimited tokens.  If @c
+ * tokens is non-NULL, any whitespace in the command line will be
+ * replaced with NULs.
+ */
+static int split_command ( char *command, char **tokens ) {
+	int count = 0;
+
+	while ( 1 ) {
+		/* Skip over any whitespace / convert to NUL */
+		while ( isspace ( *command ) ) {
+			if ( tokens )
+				*command = '\0';
+			command++;
+		}
+		/* Check for end of line */
+		if ( ! *command )
+			break;
+		/* We have found the start of the next argument */
+		if ( tokens )
+			tokens[count] = command;
+		count++;
+		/* Skip to start of next whitespace, if any */
+		while ( *command && ! isspace ( *command ) ) {
+			command++;
+		}
+	}
+	return count;
+}
+
+/**
+ * Process next command only if previous command succeeded
+ *
+ * @v rc		Status of previous command
+ * @ret process		Process next command
+ */
+static int process_on_success ( int rc ) {
+	return ( rc == 0 );
+}
+
+/**
+ * Process next command only if previous command failed
+ *
+ * @v rc		Status of previous command
+ * @ret process		Process next command
+ */
+static int process_on_failure ( int rc ) {
+	return ( rc != 0 );
+}
+
+/**
+ * Process next command regardless of status from previous command
+ *
+ * @v rc		Status of previous command
+ * @ret process		Process next command
+ */
+static int process_always ( int rc __unused ) {
+	return 1;
+}
+
+/**
+ * Find command terminator
+ *
+ * @v tokens		Token list
+ * @ret process_next	"Should next command be processed?" function
+ * @ret argc		Argument count
+ */
+static int command_terminator ( char **tokens,
+				int ( **process_next ) ( int rc ) ) {
+	unsigned int i;
+
+	/* Find first terminating token */
+	for ( i = 0 ; tokens[i] ; i++ ) {
+		if ( tokens[i][0] == '#' ) {
+			/* Start of a comment */
+			break;
+		} else if ( strcmp ( tokens[i], "||" ) == 0 ) {
+			/* Short-circuit logical OR */
+			*process_next = process_on_failure;
+			return i;
+		} else if ( strcmp ( tokens[i], "&&" ) == 0 ) {
+			/* Short-circuit logical AND */
+			*process_next = process_on_success;
+			return i;
+		} else if ( strcmp ( tokens[i], ";" ) == 0 ) {
+			/* Process next command unconditionally */
+			*process_next = process_always;
+			return i;
+		}
+	}
+
+	/* End of token list */
+	*process_next = NULL;
+	return i;
+}
+
+/**
+ * Set shell stop state
+ *
+ * @v stop		Shell stop state
+ */
+void shell_stop ( int stop ) {
+	stop_state = stop;
+}
+
+/**
+ * Test and consume shell stop state
+ *
+ * @v stop		Shell stop state to consume
+ * @v stopped		Shell had been stopped
+ */
+int shell_stopped ( int stop ) {
+	int stopped;
+
+	/* Test to see if we need to stop */
+	stopped = ( stop_state >= stop );
+
+	/* Consume stop state */
+	if ( stop_state <= stop )
+		stop_state = 0;
+
+	return stopped;
+}
+
+/**
+ * Expand settings within a token list
+ *
+ * @v argc		Argument count
+ * @v tokens		Token list
+ * @v argv		Argument list to fill in
+ * @ret rc		Return status code
+ */
+static int expand_tokens ( int argc, char **tokens, char **argv ) {
+	int i;
+
+	/* Expand each token in turn */
+	for ( i = 0 ; i < argc ; i++ ) {
+		argv[i] = expand_settings ( tokens[i] );
+		if ( ! argv[i] )
+			goto err_expand_settings;
+	}
+
+	return 0;
+
+ err_expand_settings:
+	assert ( argv[i] == NULL );
+	for ( ; i >= 0 ; i-- )
+		free ( argv[i] );
+	return -ENOMEM;
+}
+
+/**
+ * Free an expanded token list
+ *
+ * @v argv		Argument list
+ */
+static void free_tokens ( char **argv ) {
+
+	/* Free each expanded argument */
+	while ( *argv )
+		free ( *(argv++) );
+}
+
+/**
+ * Execute command line
+ *
+ * @v command		Command line
+ * @ret rc		Return status code
+ *
+ * Execute the named command and arguments.
+ */
+int system ( const char *command ) {
+	int count = split_command ( ( char * ) command, NULL );
+	char *all_tokens[ count + 1 ];
+	int ( * process_next ) ( int rc );
+	char *command_copy;
+	char **tokens;
+	int argc;
+	int process;
+	int rc = 0;
+
+	/* Create modifiable copy of command */
+	command_copy = strdup ( command );
+	if ( ! command_copy )
+		return -ENOMEM;
+
+	/* Split command into tokens */
+	split_command ( command_copy, all_tokens );
+	all_tokens[count] = NULL;
+
+	/* Process individual commands */
+	process = 1;
+	for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
+
+		/* Find command terminator */
+		argc = command_terminator ( tokens, &process_next );
+
+		/* Expand tokens and execute command */
+		if ( process ) {
+			char *argv[ argc + 1 ];
+
+			/* Expand tokens */
+			if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
+				break;
+			argv[argc] = NULL;
+
+			/* Execute command */
+			rc = execv ( argv[0], argv );
+
+			/* Free tokens */
+			free_tokens ( argv );
+		}
+
+		/* Stop processing, if applicable */
+		if ( shell_stopped ( SHELL_STOP_COMMAND ) )
+			break;
+
+		/* Stop processing if we have reached the end of the
+		 * command.
+		 */
+		if ( ! process_next )
+			break;
+
+		/* Determine whether or not to process next command */
+		process = process_next ( rc );
+	}
+
+	/* Free modified copy of command */
+	free ( command_copy );
+
+	return rc;
+}
+
+/**
+ * Concatenate arguments
+ *
+ * @v args		Argument list (NULL-terminated)
+ * @ret string		Concatenated arguments
+ *
+ * The returned string is allocated with malloc().  The caller is
+ * responsible for eventually free()ing this string.
+ */
+char * concat_args ( char **args ) {
+	char **arg;
+	size_t len;
+	char *string;
+	char *ptr;
+
+	/* Calculate total string length */
+	len = 1 /* NUL */;
+	for ( arg = args ; *arg ; arg++ )
+		len += ( 1 /* possible space */ + strlen ( *arg ) );
+
+	/* Allocate string */
+	string = zalloc ( len );
+	if ( ! string )
+		return NULL;
+
+	/* Populate string */
+	ptr = string;
+	for ( arg = args ; *arg ; arg++ ) {
+		ptr += sprintf ( ptr, "%s%s",
+				 ( ( ptr == string ) ? "" : " " ), *arg );
+	}
+	assert ( ptr < ( string + len ) );
+
+	return string;
+}
+
+/** "echo" options */
+struct echo_options {
+	/** Do not print trailing newline */
+	int no_newline;
+};
+
+/** "echo" option list */
+static struct option_descriptor echo_opts[] = {
+	OPTION_DESC ( "n", 'n', no_argument,
+		      struct echo_options, no_newline, parse_flag ),
+};
+
+/** "echo" command descriptor */
+static struct command_descriptor echo_cmd =
+	COMMAND_DESC ( struct echo_options, echo_opts, 0, MAX_ARGUMENTS,
+		       "[-n] [...]" );
+
+/**
+ * "echo" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int echo_exec ( int argc, char **argv ) {
+	struct echo_options opts;
+	char *text;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &echo_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse text */
+	text = concat_args ( &argv[optind] );
+	if ( ! text )
+		return -ENOMEM;
+
+	/* Print text */
+	printf ( "%s%s", text, ( opts.no_newline ? "" : "\n" ) );
+
+	free ( text );
+	return 0;
+}
+
+/** "echo" command */
+struct command echo_command __command = {
+	.name = "echo",
+	.exec = echo_exec,
+};
+
+/** "exit" options */
+struct exit_options {};
+
+/** "exit" option list */
+static struct option_descriptor exit_opts[] = {};
+
+/** "exit" command descriptor */
+static struct command_descriptor exit_cmd =
+	COMMAND_DESC ( struct exit_options, exit_opts, 0, 1, "[<status>]" );
+
+/**
+ * "exit" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int exit_exec ( int argc, char **argv ) {
+	struct exit_options opts;
+	unsigned int exit_code = 0;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &exit_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse exit status, if present */
+	if ( optind != argc ) {
+		if ( ( rc = parse_integer ( argv[optind], &exit_code ) ) != 0 )
+			return rc;
+	}
+
+	/* Stop shell processing */
+	shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
+
+	return exit_code;
+}
+
+/** "exit" command */
+struct command exit_command __command = {
+	.name = "exit",
+	.exec = exit_exec,
+};
+
+/** "isset" options */
+struct isset_options {};
+
+/** "isset" option list */
+static struct option_descriptor isset_opts[] = {};
+
+/** "isset" command descriptor */
+static struct command_descriptor isset_cmd =
+	COMMAND_DESC ( struct isset_options, isset_opts, 1, 1, "<value>" );
+
+/**
+ * "isset" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int isset_exec ( int argc, char **argv ) {
+	struct isset_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &isset_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Return success iff argument is non-empty */
+	return ( argv[optind][0] ? 0 : -ENOENT );
+}
+
+/** "isset" command */
+struct command isset_command __command = {
+	.name = "isset",
+	.exec = isset_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/fnrec.c b/qemu-0.15.x/roms/ipxe/src/core/fnrec.c
new file mode 100644
index 0000000..05d63aa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/fnrec.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2010 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/init.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/io.h>
+
+/** @file
+ *
+ * Function trace recorder for crash and hang debugging
+ *
+ */
+
+/** Constant for identifying valid trace buffers */
+#define FNREC_MAGIC ( 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e' )
+
+/** Number of trace buffer entries */
+#define FNREC_NUM_ENTRIES 4096
+
+/** Trace buffer physical address
+ *
+ * Fixed at 17MB
+ */
+#define FNREC_PHYS_ADDRESS ( 17 * 1024 * 1024 )
+
+/** A trace buffer entry */
+struct fnrec_entry {
+	/** Called function address */
+	void *called_fn;
+	/** Call site */
+	void *call_site;
+	/** Entry count */
+	uint16_t entry_count;
+	/** Exit count */
+	uint16_t exit_count;
+	/** Checksum */
+	unsigned long checksum;
+};
+
+/** A trace buffer */
+struct fnrec_buffer {
+	/** Constant for identifying valid trace buffers */
+	uint32_t magic;
+
+	/** Next trace buffer entry to fill */
+	unsigned int idx;
+
+	/** Trace buffer */
+	struct fnrec_entry data[FNREC_NUM_ENTRIES]
+		__attribute__ (( aligned ( 64 ) ));
+};
+
+/** The trace buffer */
+static struct fnrec_buffer *fnrec_buffer;
+
+/**
+ * Test whether the trace buffer is valid
+ *
+ * @ret is_valid	Buffer is valid
+ */
+static int fnrec_is_valid ( void ) {
+	return ( fnrec_buffer && ( fnrec_buffer->magic == FNREC_MAGIC ) );
+}
+
+/**
+ * Invalidate the trace buffer
+ *
+ */
+static void fnrec_invalidate ( void ) {
+	fnrec_buffer->magic = 0;
+}
+
+/**
+ * Reset the trace buffer and clear entries
+ */
+static void fnrec_reset ( void ) {
+	memset ( fnrec_buffer, 0, sizeof ( *fnrec_buffer ) );
+	fnrec_buffer->magic = FNREC_MAGIC;
+}
+
+/**
+ * Append an entry to the trace buffer
+ *
+ * @v called_fn		Called function
+ * @v call_site		Call site
+ * @ret entry		Trace buffer entry
+ */
+static struct fnrec_entry * fnrec_append ( void *called_fn, void *call_site ) {
+	struct fnrec_entry *entry;
+
+	/* Re-use existing entry, if possible */
+	entry = &fnrec_buffer->data[ fnrec_buffer->idx ];
+	if ( ( entry->called_fn == called_fn ) &&
+	     ( entry->call_site == call_site ) &&
+	     ( entry->entry_count >= entry->exit_count ) ) {
+		return entry;
+	}
+
+	/* Otherwise, create a new entry */
+	fnrec_buffer->idx = ( ( fnrec_buffer->idx + 1 ) % FNREC_NUM_ENTRIES );
+	entry = &fnrec_buffer->data[ fnrec_buffer->idx ];
+	entry->called_fn = called_fn;
+	entry->call_site = call_site;
+	entry->entry_count = 0;
+	entry->exit_count = 0;
+	entry->checksum = ( ( ( unsigned long ) called_fn ) ^
+			    ( ( unsigned long ) call_site ) );
+	return entry;
+}
+
+/**
+ * Print the contents of the trace buffer in chronological order
+ */
+static void fnrec_dump ( void ) {
+	struct fnrec_entry *entry;
+	unsigned int i;
+	unsigned int idx;
+	unsigned long checksum;
+
+	printf ( "fnrec buffer dump:\n" );
+	for ( i = 1 ; i <= FNREC_NUM_ENTRIES ; i++ ) {
+		idx = ( ( fnrec_buffer->idx + i ) % FNREC_NUM_ENTRIES );
+		entry = &fnrec_buffer->data[idx];
+		if ( ( entry->entry_count == 0 ) && ( entry->exit_count == 0 ) )
+			continue;
+		checksum = ( ( ( ( unsigned long ) entry->called_fn ) ^
+			       ( ( unsigned long ) entry->call_site ) ) +
+			     entry->entry_count + entry->exit_count );
+		printf ( "%p %p %d %d", entry->called_fn, entry->call_site,
+			 entry->entry_count, entry->exit_count );
+		if ( entry->checksum != checksum ) {
+			printf ( " (checksum wrong at phys %08lx)",
+				 virt_to_phys ( entry ) );
+		}
+		printf ( "\n");
+	}
+}
+
+/**
+ * Function tracer initialisation function
+ */
+static void fnrec_init ( void ) {
+
+	fnrec_buffer = phys_to_virt ( FNREC_PHYS_ADDRESS );
+	if ( fnrec_is_valid() ) {
+		fnrec_invalidate();
+		fnrec_dump();
+	} else {
+		printf ( "fnrec buffer not found\n" );
+	}
+	fnrec_reset();
+}
+
+struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = fnrec_init,
+};
+
+/*
+ * These functions are called from every C function.  The compiler inserts
+ * these calls when -finstrument-functions is used.
+ */
+void __cyg_profile_func_enter ( void *called_fn, void *call_site ) {
+	struct fnrec_entry *entry;
+
+	if ( fnrec_is_valid() ) {
+		entry = fnrec_append ( called_fn, call_site );
+		entry->entry_count++;
+		entry->checksum++;
+		mb();
+	}
+}
+
+void __cyg_profile_func_exit ( void *called_fn, void *call_site ) {
+	struct fnrec_entry *entry;
+
+	if ( fnrec_is_valid() ) {
+		entry = fnrec_append ( called_fn, call_site );
+		entry->exit_count++;
+		entry->checksum++;
+		mb();
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/gdbserial.c b/qemu-0.15.x/roms/ipxe/src/core/gdbserial.c
new file mode 100644
index 0000000..ed217ad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/gdbserial.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <ipxe/serial.h>
+#include <ipxe/gdbstub.h>
+#include <ipxe/gdbserial.h>
+
+struct gdb_transport serial_gdb_transport __gdb_transport;
+
+static size_t gdbserial_recv ( char *buf, size_t len ) {
+	assert ( len > 0 );
+	buf [ 0 ] = serial_getc();
+	return 1;
+}
+
+static void gdbserial_send ( const char *buf, size_t len ) {
+	while ( len-- > 0 ) {
+		serial_putc ( *buf++ );
+	}
+}
+
+struct gdb_transport serial_gdb_transport __gdb_transport = {
+	.name = "serial",
+	.recv = gdbserial_recv,
+	.send = gdbserial_send,
+};
+
+struct gdb_transport *gdbserial_configure ( void ) {
+	return &serial_gdb_transport;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/gdbstub.c b/qemu-0.15.x/roms/ipxe/src/core/gdbstub.c
new file mode 100644
index 0000000..34e6a03
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/gdbstub.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * GDB stub for remote debugging
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <byteswap.h>
+#include <ipxe/gdbstub.h>
+#include "gdbmach.h"
+
+enum {
+	POSIX_EINVAL = 0x1c,  /* used to report bad arguments to GDB */
+	SIZEOF_PAYLOAD = 256, /* buffer size of GDB payload data */
+};
+
+struct gdbstub {
+	struct gdb_transport *trans;
+	int exit_handler; /* leave interrupt handler */
+
+	int signo;
+	gdbreg_t *regs;
+
+	void ( * parse ) ( struct gdbstub *stub, char ch );
+	uint8_t cksum1;
+
+	/* Buffer for payload data when parsing a packet.  Once the
+	 * packet has been received, this buffer is used to hold
+	 * the reply payload. */
+	char buf [ SIZEOF_PAYLOAD + 4 ]; /* $...PAYLOAD...#XX */
+	char *payload;                   /* start of payload */
+	int len;                         /* length of payload */
+};
+
+/* Packet parser states */
+static void gdbstub_state_new ( struct gdbstub *stub, char ch );
+static void gdbstub_state_data ( struct gdbstub *stub, char ch );
+static void gdbstub_state_cksum1 ( struct gdbstub *stub, char ch );
+static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch );
+static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch );
+
+static uint8_t gdbstub_from_hex_digit ( char ch ) {
+	return ( isdigit ( ch ) ? ch - '0' : tolower ( ch ) - 'a' + 0xa ) & 0xf;
+}
+
+static uint8_t gdbstub_to_hex_digit ( uint8_t b ) {
+	b &= 0xf;
+	return ( b < 0xa ? '0' : 'a' - 0xa ) + b;
+}
+
+/*
+ * To make reading/writing device memory atomic, we check for
+ * 2- or 4-byte aligned operations and handle them specially.
+ */
+
+static void gdbstub_from_hex_buf ( char *dst, char *src, int lenbytes ) {
+	if ( lenbytes == 2 && ( ( unsigned long ) dst & 0x1 ) == 0 ) {
+		uint16_t i = gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+			gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+			gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+			gdbstub_from_hex_digit ( src [ 1 ] );
+		* ( uint16_t * ) dst = cpu_to_le16 ( i );
+	} else if ( lenbytes == 4 && ( ( unsigned long ) dst & 0x3 ) == 0 ) {
+		uint32_t i = gdbstub_from_hex_digit ( src [ 6 ] ) << 28 |
+			gdbstub_from_hex_digit ( src [ 7 ] ) << 24 |
+			gdbstub_from_hex_digit ( src [ 4 ] ) << 20 |
+			gdbstub_from_hex_digit ( src [ 5 ] ) << 16 |
+			gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+			gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+			gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+			gdbstub_from_hex_digit ( src [ 1 ] );
+		* ( uint32_t * ) dst = cpu_to_le32 ( i );
+	} else {
+		while ( lenbytes-- > 0 ) {
+			*dst++ = gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+				gdbstub_from_hex_digit ( src [ 1 ] );
+			src += 2;
+		}
+	}
+}
+
+static void gdbstub_to_hex_buf ( char *dst, char *src, int lenbytes ) {
+	if ( lenbytes == 2 && ( ( unsigned long ) src & 0x1 ) == 0 ) {
+		uint16_t i = cpu_to_le16 ( * ( uint16_t * ) src );
+		dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+		dst [ 1 ] = gdbstub_to_hex_digit ( i );
+		dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+		dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+	} else if ( lenbytes == 4 && ( ( unsigned long ) src & 0x3 ) == 0 ) {
+		uint32_t i = cpu_to_le32 ( * ( uint32_t * ) src );
+		dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+		dst [ 1 ] = gdbstub_to_hex_digit ( i );
+		dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+		dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+		dst [ 4 ] = gdbstub_to_hex_digit ( i >> 20 );
+		dst [ 5 ] = gdbstub_to_hex_digit ( i >> 16);
+		dst [ 6 ] = gdbstub_to_hex_digit ( i >> 28 );
+		dst [ 7 ] = gdbstub_to_hex_digit ( i >> 24 );
+	} else {
+		while ( lenbytes-- > 0 ) {
+			*dst++ = gdbstub_to_hex_digit ( *src >> 4 );
+			*dst++ = gdbstub_to_hex_digit ( *src );
+			src++;
+		}
+	}
+}
+
+static uint8_t gdbstub_cksum ( char *data, int len ) {
+	uint8_t cksum = 0;
+	while ( len-- > 0 ) {
+		cksum += ( uint8_t ) *data++;
+	}
+	return cksum;
+}
+
+static void gdbstub_tx_packet ( struct gdbstub *stub ) {
+	uint8_t cksum = gdbstub_cksum ( stub->payload, stub->len );
+	stub->buf [ 0 ] = '$';
+	stub->buf [ stub->len + 1 ] = '#';
+	stub->buf [ stub->len + 2 ] = gdbstub_to_hex_digit ( cksum >> 4 );
+	stub->buf [ stub->len + 3 ] = gdbstub_to_hex_digit ( cksum );
+	stub->trans->send ( stub->buf, stub->len + 4 );
+	stub->parse = gdbstub_state_wait_ack;
+}
+
+/* GDB commands */
+static void gdbstub_send_ok ( struct gdbstub *stub ) {
+	stub->payload [ 0 ] = 'O';
+	stub->payload [ 1 ] = 'K';
+	stub->len = 2;
+	gdbstub_tx_packet ( stub );
+}
+
+static void gdbstub_send_num_packet ( struct gdbstub *stub, char reply, int num ) {
+	stub->payload [ 0 ] = reply;
+	stub->payload [ 1 ] = gdbstub_to_hex_digit ( ( char ) num >> 4 );
+	stub->payload [ 2 ] = gdbstub_to_hex_digit ( ( char ) num );
+	stub->len = 3;
+	gdbstub_tx_packet ( stub );
+}
+
+/* Format is arg1,arg2,...,argn:data where argn are hex integers and data is not an argument */
+static int gdbstub_get_packet_args ( struct gdbstub *stub, unsigned long *args, int nargs, int *stop_idx ) {
+	int i;
+	char ch = 0;
+	int argc = 0;
+	unsigned long val = 0;
+	for ( i = 1; i < stub->len && argc < nargs; i++ ) {
+		ch = stub->payload [ i ];
+		if ( ch == ':' ) {
+			break;
+		} else if ( ch == ',' ) {
+			args [ argc++ ] = val;
+			val = 0;
+		} else {
+			val = ( val << 4 ) | gdbstub_from_hex_digit ( ch );
+		}
+	}
+	if ( stop_idx ) {
+		*stop_idx = i;
+	}
+	if ( argc < nargs ) {
+		args [ argc++ ] = val;
+	}
+	return ( ( i == stub->len || ch == ':' ) && argc == nargs );
+}
+
+static void gdbstub_send_errno ( struct gdbstub *stub, int errno ) {
+	gdbstub_send_num_packet ( stub, 'E', errno );
+}
+
+static void gdbstub_report_signal ( struct gdbstub *stub ) {
+	gdbstub_send_num_packet ( stub, 'S', stub->signo );
+}
+
+static void gdbstub_read_regs ( struct gdbstub *stub ) {
+	gdbstub_to_hex_buf ( stub->payload, ( char * ) stub->regs, GDBMACH_SIZEOF_REGS );
+	stub->len = GDBMACH_SIZEOF_REGS * 2;
+	gdbstub_tx_packet ( stub );
+}
+
+static void gdbstub_write_regs ( struct gdbstub *stub ) {
+	if ( stub->len != 1 + GDBMACH_SIZEOF_REGS * 2 ) {
+		gdbstub_send_errno ( stub, POSIX_EINVAL );
+		return;
+	}
+	gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], GDBMACH_SIZEOF_REGS );
+	gdbstub_send_ok ( stub );
+}
+
+static void gdbstub_read_mem ( struct gdbstub *stub ) {
+	unsigned long args [ 2 ];
+	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], NULL ) ) {
+		gdbstub_send_errno ( stub, POSIX_EINVAL );
+		return;
+	}
+	args [ 1 ] = ( args [ 1 ] < SIZEOF_PAYLOAD / 2 ) ? args [ 1 ] : SIZEOF_PAYLOAD / 2;
+	gdbstub_to_hex_buf ( stub->payload, ( char * ) args [ 0 ], args [ 1 ] );
+	stub->len = args [ 1 ] * 2;
+	gdbstub_tx_packet ( stub );
+}
+
+static void gdbstub_write_mem ( struct gdbstub *stub ) {
+	unsigned long args [ 2 ];
+	int colon;
+	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], &colon ) ||
+			colon >= stub->len || stub->payload [ colon ] != ':' ||
+			( stub->len - colon - 1 ) % 2 != 0 ) {
+		gdbstub_send_errno ( stub, POSIX_EINVAL );
+		return;
+	}
+	gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], ( stub->len - colon - 1 ) / 2 );
+	gdbstub_send_ok ( stub );
+}
+
+static void gdbstub_continue ( struct gdbstub *stub, int single_step ) {
+	gdbreg_t pc;
+	if ( stub->len > 1 && gdbstub_get_packet_args ( stub, &pc, 1, NULL ) ) {
+		gdbmach_set_pc ( stub->regs, pc );
+	}
+	gdbmach_set_single_step ( stub->regs, single_step );
+	stub->exit_handler = 1;
+	/* Reply will be sent when we hit the next breakpoint or interrupt */
+}
+
+static void gdbstub_breakpoint ( struct gdbstub *stub ) {
+	unsigned long args [ 3 ];
+	int enable = stub->payload [ 0 ] == 'Z' ? 1 : 0;
+	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], NULL ) ) {
+		gdbstub_send_errno ( stub, POSIX_EINVAL );
+		return;
+	}
+	if ( gdbmach_set_breakpoint ( args [ 0 ], args [ 1 ], args [ 2 ], enable ) ) {
+		gdbstub_send_ok ( stub );
+	} else {
+		/* Not supported */
+		stub->len = 0;
+		gdbstub_tx_packet ( stub );
+	}
+}
+
+static void gdbstub_rx_packet ( struct gdbstub *stub ) {
+	switch ( stub->payload [ 0 ] ) {
+		case '?':
+			gdbstub_report_signal ( stub );
+			break;
+		case 'g':
+			gdbstub_read_regs ( stub );
+			break;
+		case 'G':
+			gdbstub_write_regs ( stub );
+			break;
+		case 'm':
+			gdbstub_read_mem ( stub );
+			break;
+		case 'M':
+			gdbstub_write_mem ( stub );
+			break;
+		case 'c': /* Continue */
+		case 'k': /* Kill */
+		case 's': /* Step */
+		case 'D': /* Detach */
+			gdbstub_continue ( stub, stub->payload [ 0 ] == 's' );
+			if ( stub->payload [ 0 ] == 'D' ) {
+				gdbstub_send_ok ( stub );
+			}
+			break;
+		case 'Z': /* Insert breakpoint */
+		case 'z': /* Remove breakpoint */
+			gdbstub_breakpoint ( stub );
+			break;
+		default:
+			stub->len = 0;
+			gdbstub_tx_packet ( stub );
+			break;
+	}
+}
+
+/* GDB packet parser */
+static void gdbstub_state_new ( struct gdbstub *stub, char ch ) {
+	if ( ch == '$' ) {
+		stub->len = 0;
+		stub->parse = gdbstub_state_data;
+	}
+}
+
+static void gdbstub_state_data ( struct gdbstub *stub, char ch ) {
+	if ( ch == '#' ) {
+		stub->parse = gdbstub_state_cksum1;
+	} else if ( ch == '$' ) {
+		stub->len = 0; /* retry new packet */
+	} else {
+		/* If the length exceeds our buffer, let the checksum fail */
+		if ( stub->len < SIZEOF_PAYLOAD ) {
+			stub->payload [ stub->len++ ] = ch;
+		}
+	}
+}
+
+static void gdbstub_state_cksum1 ( struct gdbstub *stub, char ch ) {
+	stub->cksum1 = gdbstub_from_hex_digit ( ch ) << 4;
+	stub->parse = gdbstub_state_cksum2;
+}
+
+static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch ) {
+	uint8_t their_cksum;
+	uint8_t our_cksum;
+
+	stub->parse = gdbstub_state_new;
+	their_cksum = stub->cksum1 + gdbstub_from_hex_digit ( ch );
+	our_cksum = gdbstub_cksum ( stub->payload, stub->len );
+	if ( their_cksum == our_cksum ) {
+		stub->trans->send ( "+", 1 );
+		if ( stub->len > 0 ) {
+			gdbstub_rx_packet ( stub );
+		}
+	} else {
+		stub->trans->send ( "-", 1 );
+	}
+}
+
+static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch ) {
+	if ( ch == '+' ) {
+		stub->parse = gdbstub_state_new;
+	} else {
+		/* This retransmit is very aggressive but necessary to keep
+		 * in sync with GDB. */
+		gdbstub_tx_packet ( stub );
+	}
+}
+
+static void gdbstub_parse ( struct gdbstub *stub, char ch ) {
+	stub->parse ( stub, ch );
+}
+
+static struct gdbstub stub = {
+	.parse = gdbstub_state_new
+};
+
+void gdbstub_handler ( int signo, gdbreg_t *regs ) {
+	char packet [ SIZEOF_PAYLOAD + 4 ];
+	size_t len, i;
+
+	/* A transport must be set up */
+	if ( !stub.trans ) {
+		return;
+	}
+
+	stub.signo = signo;
+	stub.regs = regs;
+	stub.exit_handler = 0;
+	gdbstub_report_signal ( &stub );
+	while ( !stub.exit_handler && ( len = stub.trans->recv ( packet, sizeof ( packet ) ) ) > 0 ) {
+		for ( i = 0; i < len; i++ ) {
+			gdbstub_parse ( &stub, packet [ i ] );
+		}
+	}
+}
+
+struct gdb_transport *find_gdb_transport ( const char *name ) {
+	struct gdb_transport *trans;
+
+	for_each_table_entry ( trans, GDB_TRANSPORTS ) {
+		if ( strcmp ( trans->name, name ) == 0 ) {
+			return trans;
+		}
+	}
+	return NULL;
+}
+
+void gdbstub_start ( struct gdb_transport *trans ) {
+	stub.trans = trans;
+	stub.payload = &stub.buf [ 1 ];
+	gdbmach_breakpoint();
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/gdbudp.c b/qemu-0.15.x/roms/ipxe/src/core/gdbudp.c
new file mode 100644
index 0000000..9cb6572
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/gdbudp.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <string.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/in.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ip.h>
+#include <ipxe/udp.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/nap.h>
+#include <ipxe/gdbstub.h>
+#include <ipxe/gdbudp.h>
+
+/** @file
+ *
+ * GDB over UDP transport
+ *
+ */
+
+enum {
+	DEFAULT_PORT = 43770, /* UDP listen port */
+};
+
+struct gdb_transport udp_gdb_transport __gdb_transport;
+
+static struct net_device *netdev;
+static uint8_t dest_eth[ETH_ALEN];
+static struct sockaddr_in dest_addr;
+static struct sockaddr_in source_addr;
+
+static void gdbudp_ensure_netdev_open ( struct net_device *netdev ) {
+	/* The device may have been closed between breakpoints */
+	assert ( netdev );
+	netdev_open ( netdev );
+
+	/* Strictly speaking, we may need to close the device when leaving the interrupt handler */
+}
+
+static size_t gdbudp_recv ( char *buf, size_t len ) {
+	struct io_buffer *iob;
+	struct ethhdr *ethhdr;
+	struct arphdr *arphdr;
+	struct iphdr *iphdr;
+	struct udp_header *udphdr;
+	size_t payload_len;
+
+	gdbudp_ensure_netdev_open ( netdev );
+
+	for ( ; ; ) {
+		netdev_poll ( netdev );
+		while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) {
+			/* Ethernet header */
+			if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) {
+				goto bad_packet;
+			}
+			ethhdr = iob->data;
+			iob_pull ( iob, sizeof ( *ethhdr ) );
+
+			/* Handle ARP requests so the client can find our MAC */
+			if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) {
+				arphdr = iob->data;
+				if ( iob_len ( iob ) < sizeof ( *arphdr ) + 2 * ( ETH_ALEN + sizeof ( struct in_addr ) ) ||
+						arphdr->ar_hrd != htons ( ARPHRD_ETHER ) ||
+						arphdr->ar_pro != htons ( ETH_P_IP ) ||
+						arphdr->ar_hln != ETH_ALEN ||
+						arphdr->ar_pln != sizeof ( struct in_addr ) ||
+						arphdr->ar_op != htons ( ARPOP_REQUEST ) ||
+						* ( uint32_t * ) arp_target_pa ( arphdr ) != source_addr.sin_addr.s_addr ) {
+					goto bad_packet;
+				}
+
+				/* Generate an ARP reply */
+				arphdr->ar_op = htons ( ARPOP_REPLY );
+				memswap ( arp_sender_pa ( arphdr ), arp_target_pa ( arphdr ), sizeof ( struct in_addr ) );
+				memcpy ( arp_target_ha ( arphdr ), arp_sender_ha ( arphdr ), ETH_ALEN );
+				memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, ETH_ALEN );
+
+				/* Fix up ethernet header */
+				ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
+				memcpy ( ethhdr->h_dest, ethhdr->h_source, ETH_ALEN );
+				memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
+
+				netdev_tx ( netdev, iob );
+				continue; /* no need to free iob */
+			}
+
+			if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) {
+				goto bad_packet;
+			}
+
+			/* IP header */
+			if ( iob_len ( iob ) < sizeof ( *iphdr ) ) {
+				goto bad_packet;
+			}
+			iphdr = iob->data;
+			iob_pull ( iob, sizeof ( *iphdr ) );
+			if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) {
+				goto bad_packet;
+			}
+
+			/* UDP header */
+			if ( iob_len ( iob ) < sizeof ( *udphdr ) ) {
+				goto bad_packet;
+			}
+			udphdr = iob->data;
+			if ( udphdr->dest != source_addr.sin_port ) {
+				goto bad_packet;
+			}
+
+			/* Learn the remote connection details */
+			memcpy ( dest_eth, ethhdr->h_source, ETH_ALEN );
+			dest_addr.sin_addr.s_addr = iphdr->src.s_addr;
+			dest_addr.sin_port = udphdr->src;
+
+			/* Payload */
+			payload_len = ntohs ( udphdr->len );
+			if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) {
+				goto bad_packet;
+			}
+			payload_len -= sizeof ( *udphdr );
+			iob_pull ( iob, sizeof ( *udphdr ) );
+			if ( payload_len > len ) {
+				goto bad_packet;
+			}
+			memcpy ( buf, iob->data, payload_len );
+
+			free_iob ( iob );
+			return payload_len;
+
+bad_packet:
+			free_iob ( iob );
+		}
+		cpu_nap();
+	}
+}
+
+static void gdbudp_send ( const char *buf, size_t len ) {
+	struct io_buffer *iob;
+	struct ethhdr *ethhdr;
+	struct iphdr *iphdr;
+	struct udp_header *udphdr;
+
+	/* Check that we are connected */
+	if ( dest_addr.sin_port == 0 ) {
+		return;
+	}
+
+	gdbudp_ensure_netdev_open ( netdev );
+
+	iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len );
+	if ( !iob ) {
+		return;
+	}
+
+	/* Payload */
+	iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) );
+	memcpy ( iob_put ( iob, len ), buf, len );
+
+	/* UDP header */
+	udphdr = iob_push ( iob, sizeof ( *udphdr ) );
+	udphdr->src = source_addr.sin_port;
+	udphdr->dest = dest_addr.sin_port;
+	udphdr->len = htons ( iob_len ( iob ) );
+	udphdr->chksum = 0; /* optional and we are not using it */
+
+	/* IP header */
+	iphdr = iob_push ( iob, sizeof ( *iphdr ) );
+	memset ( iphdr, 0, sizeof ( *iphdr ) );
+	iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
+	iphdr->service = IP_TOS;
+	iphdr->len = htons ( iob_len ( iob ) );	
+	iphdr->ttl = IP_TTL;
+	iphdr->protocol = IP_UDP;
+	iphdr->dest.s_addr = dest_addr.sin_addr.s_addr;
+	iphdr->src.s_addr = source_addr.sin_addr.s_addr;
+	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
+
+	/* Ethernet header */
+	ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
+	memcpy ( ethhdr->h_dest, dest_eth, ETH_ALEN );
+	memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
+	ethhdr->h_protocol = htons ( ETH_P_IP );
+
+	netdev_tx ( netdev, iob );
+}
+
+struct gdb_transport *gdbudp_configure ( const char *name, struct sockaddr_in *addr ) {
+	struct settings *settings;
+
+	/* Release old network device */
+	netdev_put ( netdev );
+
+	netdev = find_netdev ( name );
+	if ( !netdev ) {
+		return NULL;
+	}
+
+	/* Hold network device */
+	netdev_get ( netdev );
+
+	/* Source UDP port */
+	source_addr.sin_port = ( addr && addr->sin_port ) ? addr->sin_port : htons ( DEFAULT_PORT );
+
+	/* Source IP address */
+	if ( addr && addr->sin_addr.s_addr ) {
+		source_addr.sin_addr.s_addr = addr->sin_addr.s_addr;
+	} else {
+		settings = netdev_settings ( netdev );
+		fetch_ipv4_setting ( settings, &ip_setting, &source_addr.sin_addr );
+		if ( source_addr.sin_addr.s_addr == 0 ) {
+			netdev_put ( netdev );
+			netdev = NULL;
+			return NULL;
+		}
+	}
+
+	return &udp_gdb_transport;
+}
+
+static int gdbudp_init ( int argc, char **argv ) {
+	if ( argc != 1 ) {
+		printf ( "udp: missing <interface> argument\n" );
+		return 1;
+	}
+
+	if ( !gdbudp_configure ( argv[0], NULL ) ) {
+		printf ( "%s: device does not exist or has no IP address\n", argv[0] );
+		return 1;
+	}
+	return 0;
+}
+
+struct gdb_transport udp_gdb_transport __gdb_transport = {
+	.name = "udp",
+	.init = gdbudp_init,
+	.send = gdbudp_send,
+	.recv = gdbudp_recv,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/getkey.c b/qemu-0.15.x/roms/ipxe/src/core/getkey.c
new file mode 100644
index 0000000..d692b1b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/getkey.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ctype.h>
+#include <ipxe/console.h>
+#include <ipxe/process.h>
+#include <ipxe/keys.h>
+#include <ipxe/timer.h>
+
+/** @file
+ *
+ * Special key interpretation
+ *
+ */
+
+#define GETKEY_TIMEOUT ( TICKS_PER_SEC / 4 )
+
+/**
+ * Read character from console if available within timeout period
+ *
+ * @v timeout		Timeout period, in ticks (0=indefinite)
+ * @ret character	Character read from console
+ */
+static int getchar_timeout ( unsigned long timeout ) {
+	unsigned long start = currticks();
+
+	while ( ( timeout == 0 ) || ( ( currticks() - start ) < timeout ) ) {
+		step();
+		if ( iskey() )
+			return getchar();
+	}
+
+	return -1;
+}
+
+/**
+ * Get single keypress
+ *
+ * @v timeout		Timeout period, in ticks (0=indefinite)
+ * @ret key		Key pressed
+ *
+ * The returned key will be an ASCII value or a KEY_XXX special
+ * constant.  This function differs from getchar() in that getchar()
+ * will return "special" keys (e.g. cursor keys) as a series of
+ * characters forming an ANSI escape sequence.
+ */
+int getkey ( unsigned long timeout ) {
+	int character;
+	unsigned int n = 0;
+
+	character = getchar_timeout ( timeout );
+	if ( character != ESC )
+		return character;
+
+	while ( ( character = getchar_timeout ( GETKEY_TIMEOUT ) ) >= 0 ) {
+		if ( character == '[' )
+			continue;
+		if ( isdigit ( character ) ) {
+			n = ( ( n * 10 ) + ( character - '0' ) );
+			continue;
+		}
+		if ( character >= 0x40 )
+			return KEY_ANSI ( n, character );
+	}
+
+	return ESC;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/getopt.c b/qemu-0.15.x/roms/ipxe/src/core/getopt.c
new file mode 100644
index 0000000..b67da0c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/getopt.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+
+/** @file
+ *
+ * Parse command-line options
+ *
+ */
+
+/**
+ * Option argument
+ *
+ * This will point to the argument for the most recently returned
+ * option, if applicable.
+ */
+char *optarg;
+
+/**
+ * Current option index
+ *
+ * This is an index into the argv[] array.  When getopt() returns -1,
+ * @c optind is the index to the first element that is not an option.
+ */
+int optind;
+
+/**
+ * Current option character index
+ *
+ * This is an index into the current element of argv[].
+ */
+int nextchar;
+
+/**
+ * Unrecognised option
+ *
+ * When an unrecognised option is encountered, the actual option
+ * character is stored in @c optopt.
+ */
+int optopt;
+
+/**
+ * Get option argument from argv[] array
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret argument	Option argument, or NULL
+ *
+ * Grab the next element of argv[], if it exists and is not an option.
+ */
+static const char * get_argv_argument ( int argc, char * const argv[] ) {
+	char *arg;
+
+	/* Don't overrun argv[] */
+	if ( optind >= argc )
+		return NULL;
+	arg = argv[optind];
+
+	/* If next argv element is an option, then it's not usable as
+	 * an argument.
+	 */
+	if ( *arg == '-' )
+		return NULL;
+
+	/** Consume this argv element, and return it */
+	optind++;
+	return arg;
+}
+
+/**
+ * Match long option
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opttext		Option text within current argv[] element
+ * @v longopt		Long option specification
+ * @ret option		Option to return from getopt()
+ * @ret matched		Found a match for this long option
+ */
+static int match_long_option ( int argc, char * const argv[],
+			       const char *opttext,
+			       const struct option *longopt, int *option ) {
+	size_t optlen;
+	const char *argument = NULL;
+
+	/* Compare option name */
+	optlen = strlen ( longopt->name );
+	if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
+		return 0;
+
+	/* Check for inline argument */
+	if ( opttext[optlen] == '=' ) {
+		argument = &opttext[ optlen + 1 ];
+	} else if ( opttext[optlen] ) {
+		/* Long option with trailing garbage - no match */
+		return 0;
+	}
+
+	/* Consume this argv element */
+	optind++;
+
+	/* If we want an argument but don't have one yet, try to grab
+	 * the next argv element
+	 */
+	if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
+		argument = get_argv_argument ( argc, argv );
+
+	/* If we need an argument but don't have one, sulk */
+	if ( ( longopt->has_arg == required_argument ) && ( ! argument ) ) {
+		printf ( "Option \"%s\" requires an argument\n",
+			 longopt->name );
+		*option = ':';
+		return 1;
+	}
+
+	/* If we have an argument where we shouldn't have one, sulk */
+	if ( ( longopt->has_arg == no_argument ) && argument ) {
+		printf ( "Option \"%s\" takes no argument\n", longopt->name );
+		*option = ':';
+		return 1;
+	}
+
+	/* Store values and return success */
+	optarg = ( char * ) argument;
+	if ( longopt->flag ) {
+		*(longopt->flag) = longopt->val;
+		*option = 0;
+	} else {
+		*option = longopt->val;
+	}
+	return 1;
+}
+
+/**
+ * Match short option
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opttext		Option text within current argv[] element
+ * @v shortopt		Option character from option specification
+ * @ret option		Option to return from getopt()
+ * @ret matched		Found a match for this short option
+ */
+static int match_short_option ( int argc, char * const argv[],
+				const char *opttext, int shortopt,
+				enum getopt_argument_requirement has_arg,
+				int *option ) {
+	const char *argument = NULL;
+
+	/* Compare option character */
+	if ( *opttext != shortopt )
+		return 0;
+
+	/* Consume option character */
+	opttext++;
+	nextchar++;
+	if ( *opttext ) {
+		if ( has_arg != no_argument ) {
+			/* Consume remainder of element as inline argument */
+			argument = opttext;
+			optind++;
+			nextchar = 0;
+		}
+	} else {
+		/* Reached end of argv element */
+		optind++;
+		nextchar = 0;
+	}
+
+	/* If we want an argument but don't have one yet, try to grab
+	 * the next argv element
+	 */
+	if ( ( has_arg != no_argument ) && ( ! argument ) )
+		argument = get_argv_argument ( argc, argv );
+
+	/* If we need an argument but don't have one, sulk */
+	if ( ( has_arg == required_argument ) && ( ! argument ) ) {
+		printf ( "Option \"%c\" requires an argument\n", shortopt );
+		*option = ':';
+		return 1;
+	}
+
+	/* Store values and return success */
+	optarg = ( char * ) argument;
+	*option = shortopt;
+	return 1;
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v optstring		Option specification string
+ * @v longopts		Long option specification table
+ * @ret longindex	Index of long option (or NULL)
+ * @ret option		Option found, or -1 for no more options
+ *
+ * Note that the caller must arrange for reset_getopt() to be called
+ * before each set of calls to getopt_long().  In Etherboot, this is
+ * done automatically by execv().
+ */
+int getopt_long ( int argc, char * const argv[], const char *optstring,
+		  const struct option *longopts, int *longindex ) {
+	const char *opttext = argv[optind];
+	const struct option *longopt;
+	int shortopt;
+	enum getopt_argument_requirement has_arg;
+	int option;
+
+	/* Check for end of argv array */
+	if ( optind >= argc )
+		return -1;
+
+	/* Check for end of options */
+	if ( *(opttext++) != '-' )
+		return -1;
+
+	/* Check for long options */
+	if ( *(opttext++) == '-' ) {
+		for ( longopt = longopts ; longopt->name ; longopt++ ) {
+			if ( ! match_long_option ( argc, argv, opttext,
+						   longopt, &option ) )
+				continue;
+			if ( longindex )
+				*longindex = ( longopt - longopts );
+			return option;
+		}
+		optopt = '?';
+		printf ( "Unrecognised option \"--%s\"\n", opttext );
+		return '?';
+	}
+
+	/* Check for short options */
+	if ( nextchar < 1 )
+		nextchar = 1;
+	opttext = ( argv[optind] + nextchar );
+	while ( ( shortopt = *(optstring++) ) ) {
+		has_arg = no_argument;
+		while ( *optstring == ':' ) {
+			has_arg++;
+			optstring++;
+		}
+		if ( match_short_option ( argc, argv, opttext, shortopt,
+					  has_arg, &option ) ) {
+			return option;
+		}
+	}
+	optopt = *opttext;
+	printf ( "Unrecognised option \"-%c\"\n", optopt );
+	return '?';
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/hw.c b/qemu-0.15.x/roms/ipxe/src/core/hw.c
new file mode 100644
index 0000000..aca5580
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/hw.c
@@ -0,0 +1,66 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/process.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+
+/** @file
+ *
+ * "Hello World" data source
+ *
+ */
+
+struct hw {
+	struct refcnt refcnt;
+	struct interface xfer;
+	struct process process;
+};
+
+static const char hw_msg[] = "Hello world!\n";
+
+static void hw_finished ( struct hw *hw, int rc ) {
+	intf_shutdown ( &hw->xfer, rc );
+	process_del ( &hw->process );
+}
+
+static struct interface_operation hw_xfer_operations[] = {
+	INTF_OP ( intf_close, struct hw *, hw_finished ),
+};
+
+static struct interface_descriptor hw_xfer_desc =
+	INTF_DESC ( struct hw, xfer, hw_xfer_operations );
+
+static void hw_step ( struct process *process ) {
+	struct hw *hw = container_of ( process, struct hw, process );
+	int rc;
+
+	if ( xfer_window ( &hw->xfer ) ) {
+		rc = xfer_deliver_raw ( &hw->xfer, hw_msg, sizeof ( hw_msg ) );
+		hw_finished ( hw, rc );
+	}
+}
+
+static int hw_open ( struct interface *xfer, struct uri *uri __unused ) {
+	struct hw *hw;
+
+	/* Allocate and initialise structure */
+	hw = zalloc ( sizeof ( *hw ) );
+	if ( ! hw )
+		return -ENOMEM;
+	ref_init ( &hw->refcnt, NULL );
+	intf_init ( &hw->xfer, &hw_xfer_desc, &hw->refcnt );
+	process_init ( &hw->process, hw_step, &hw->refcnt );
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &hw->xfer, xfer );
+	ref_put ( &hw->refcnt );
+	return 0;
+}
+
+struct uri_opener hw_uri_opener __uri_opener = {
+	.scheme = "hw",
+	.open = hw_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/i82365.c b/qemu-0.15.x/roms/ipxe/src/core/i82365.c
new file mode 100644
index 0000000..c26639e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/i82365.c
@@ -0,0 +1,656 @@
+#ifdef CONFIG_PCMCIA
+
+/*
+ *	i82365.c
+ *	Support for i82365 and similar ISA-to-PCMCIA bridges
+ *
+ *	Taken from Linux kernel sources, distributed under GPL2
+ *
+ *   Software distributed under the License is distributed on an "AS
+ *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *   implied. See the License for the specific language governing
+ *   rights and limitations under the License.
+ *
+ *   The initial developer of the original code is David A. Hinds
+ *   <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
+ *   are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ *	Ported by: Anselm Martin Hoffmeister, Stockholm Projekt Computer-Service, Sankt Augustin/Bonn, GERMANY
+ */
+
+/*
+ *
+ *
+ *			******************************
+ *			PLEASE DO NOT YET WORK ON THIS
+ *			******************************
+ *
+ *	I'm still fixing it up on every end, so we most probably would interfere
+ *	at some point. If there's anything obvious or better, not-so-obvious,
+ *	please contact me by e-mail: anselm (AT) hoffmeister (DOT) be   *THANKS*
+ */
+#include "../include/pcmcia.h"
+#include "../include/pcmcia-opts.h"
+#include "../include/i82365.h"
+
+#ifndef CONFIG_ISA
+#error	PCMCIA_I82365 only works with ISA defined - set CONFIG_ISA
+#endif
+
+typedef enum pcic_id {
+    IS_I82365A, IS_I82365B, IS_I82365DF,
+    IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
+    IS_PD6710, IS_PD672X, IS_VT83C469,
+} pcic_id;
+
+/* Flags for classifying groups of controllers */
+#define IS_VADEM        0x0001
+#define IS_CIRRUS       0x0002
+#define IS_TI           0x0004
+#define IS_O2MICRO      0x0008
+#define IS_VIA          0x0010
+#define IS_TOPIC        0x0020
+#define IS_RICOH        0x0040
+#define IS_UNKNOWN      0x0400
+#define IS_VG_PWR       0x0800
+#define IS_DF_PWR       0x1000
+#define IS_PCI          0x2000
+#define IS_ALIVE        0x8000
+
+typedef struct pcic_t {
+    char                *name;
+    u_short             flags;
+} pcic_t;
+
+static pcic_t pcic[] = {
+    { "Intel i82365sl A step", 0 },
+    { "Intel i82365sl B step", 0 },
+    { "Intel i82365sl DF", IS_DF_PWR },
+    { "IBM Clone", 0 },
+    { "Ricoh RF5C296/396", 0 },
+    { "VLSI 82C146", 0 },
+    { "Vadem VG-468", IS_VADEM },
+    { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
+    { "Cirrus PD6710", IS_CIRRUS },
+    { "Cirrus PD672x", IS_CIRRUS },
+    { "VIA VT83C469", IS_CIRRUS|IS_VIA },
+};
+
+typedef struct cirrus_state_t {
+    u_char              misc1, misc2;
+    u_char              timer[6];
+} cirrus_state_t;
+
+typedef struct vg46x_state_t {
+    u_char              ctl, ema;
+} vg46x_state_t;
+
+typedef struct socket_info_t {
+    u_short             type, flags;
+    socket_cap_t        cap;
+    ioaddr_t            ioaddr;
+    u_short             psock;
+    u_char              cs_irq, intr;
+    void                (*handler)(void *info, u_int events);
+    void                *info;
+    union {
+        cirrus_state_t          cirrus;
+        vg46x_state_t           vg46x;
+    } state;
+} socket_info_t;
+
+//static socket_info_t socket[8];
+
+int	i365_base = 0x3e0; // Default in Linux kernel
+int	cycle_time = 120; // External clock time in ns, 120ns =~ 8.33 MHz
+int	mydriverid = 0;
+
+void	phex ( unsigned char c );
+/*static int to_cycles(int ns)
+{
+    return ns/cycle_time;
+}
+*/
+/*static int to_ns(int cycles)
+{
+    return cycle_time*cycles;
+}
+*/
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+    //unsigned long flags;
+    //spin_lock_irqsave(&bus_lock,flags);
+    {
+        ioaddr_t port = pccsock[sock].ioaddr;
+        u_char val;
+        reg = I365_REG(pccsock[sock].internalid, reg);
+        outb(reg, port); val = inb(port+1);
+        //spin_unlock_irqrestore(&bus_lock,flags);
+        return val;
+    }
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+    //unsigned long flags;
+    //spin_lock_irqsave(&bus_lock,flags);
+    {
+        ioaddr_t port = pccsock[sock].ioaddr;
+        u_char val = I365_REG(pccsock[sock].internalid, reg);
+        outb(val, port); outb(data, port+1);
+        //spin_unlock_irqrestore(&bus_lock,flags);
+    }
+}
+
+void	add_socket_i365(u_short port, int psock, int type) {
+	pccsock[pccsocks].ioaddr = port;
+	pccsock[pccsocks].internalid = psock;
+	pccsock[pccsocks].type = type;
+	pccsock[pccsocks].flags = pcic[type].flags;
+	pccsock[pccsocks].drivernum = mydriverid;
+	pccsock[pccsocks].configoffset = -1;
+	// Find out if a card in inside that socket
+	pccsock[pccsocks].status = (( 12 == (i365_get(pccsocks,I365_STATUS)&12) )  ?  HASCARD : EMPTY );
+	// *TODO* check if that's all
+	if ( 0 == (psock & 1) ) {
+		printf ( "Found a PCMCIA controller (i82365) at io %x, type '%s'\n", port, pcic[type].name );
+		//	pccsock[pccsocks].status == HASCARD? "holds card":"empty" );
+	}
+	pccsocks++;
+	return;
+}
+
+void	i365_bset(u_short sock, u_short reg, u_char mask) {
+	u_char d = i365_get(sock, reg);
+	d |= mask;
+	i365_set(sock, reg, d);
+}
+
+void	i365_bclr(u_short sock, u_short reg, u_char mask) {
+	u_char d = i365_get(sock, reg);
+	d &= ~mask;
+	i365_set(sock, reg, d);
+}
+
+
+/*static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
+{
+    u_char d = i365_get(sock, reg);
+    if (b)
+        d |= mask;
+    else
+        d &= ~mask;
+    i365_set(sock, reg, d);
+}
+*/
+
+/*
+static u_short i365_get_pair(u_short sock, u_short reg)
+{
+    u_short a, b;
+    a = i365_get(sock, reg);
+    b = i365_get(sock, reg+1);
+    return (a + (b<<8));
+}
+*/
+
+/*
+static void i365_set_pair(u_short sock, u_short reg, u_short data)
+{
+    i365_set(sock, reg, data & 0xff);
+    i365_set(sock, reg+1, data >> 8);
+}
+*/
+int	identify_i365 ( u_short port, u_short sock ) {
+	u_char val;
+	int type = -1;
+	/* Use the next free entry in the socket table */
+	pccsock[pccsocks].ioaddr = port;
+	pccsock[pccsocks].internalid = sock;
+	// *TODO* wakeup a sleepy cirrus controller?
+
+	if ((val = i365_get(pccsocks, I365_IDENT)) & 0x70)
+	    return -1;
+	switch (val) {
+	case 0x82:
+	    type = IS_I82365A; break;
+	case 0x83:
+	    type = IS_I82365B; break;
+	case 0x84:
+	    type = IS_I82365DF; break;
+	case 0x88: case 0x89: case 0x8a:
+	    type = IS_IBM; break;
+	}
+	/* Check for Vadem VG-468 chips */
+	outb(0x0e, port);
+	outb(0x37, port);
+	i365_bset(pccsocks, VG468_MISC, VG468_MISC_VADEMREV);
+	val = i365_get(pccsocks, I365_IDENT);
+	if (val & I365_IDENT_VADEM) {
+	    i365_bclr(pccsocks, VG468_MISC, VG468_MISC_VADEMREV);
+	    type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+	}
+
+	/* Check for Ricoh chips */
+	val = i365_get(pccsocks, RF5C_CHIP_ID);
+	if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) type = IS_RF5Cx96;
+
+	/* Check for Cirrus CL-PD67xx chips */
+	i365_set(pccsocks, PD67_CHIP_INFO, 0);
+	val = i365_get(pccsocks, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	    val = i365_get(pccsocks, PD67_CHIP_INFO);
+	    if ((val & PD67_INFO_CHIP_ID) == 0) {
+		type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+		i365_set(pccsocks, PD67_EXT_INDEX, 0xe5);
+		if (i365_get(pccsocks, PD67_EXT_INDEX) != 0xe5) type = IS_VT83C469;
+	    }
+	}
+    return type;
+}
+
+int	init_i82365(void) {
+	int	i, j, sock, k, ns, id;
+	//unsigned int ui,uj;
+	//unsigned char * upc;
+	ioaddr_t port;
+	int	i82365s = 0;
+	// Change from kernel: No irq init, no check_region, no isapnp support
+	// No ignore socket, no extra sockets to check (so it's easier here :-/)
+	// Probably we don't need any of them; in case YOU do, SHOUT AT ME!
+	id = identify_i365(i365_base, 0);
+	if ((id == IS_I82365DF) && (identify_i365(i365_base, 1) != id)) {
+		for (i = 0; i < 4; i++) {
+		    port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
+		    sock = (i & 1) << 1;
+		    if (identify_i365(port, sock) == IS_I82365DF) {
+			add_socket_i365(port, sock, IS_VLSI);
+		    }
+		}
+	} else {
+	  for (i = 0; i < 4; i += 2) {
+            port = i365_base + 2*(i>>2);
+            sock = (i & 3);
+            id = identify_i365(port, sock);
+            if (id < 0) continue;
+
+            for (j = ns = 0; j < 2; j++) {
+                /* Does the socket exist? */
+                if (identify_i365(port, sock+j) < 0)	continue;
+                /* Check for bad socket decode */
+                for (k = 0; k <= i82365s; k++)
+                    i365_set(k, I365_MEM(0)+I365_W_OFF, k);
+                for (k = 0; k <= i82365s; k++)
+                    if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
+                        break;
+                if (k <= i82365s) break;
+                add_socket_i365(port, sock+j, id); ns++;
+            }
+	  }
+	}
+	return	0;
+
+
+
+
+
+
+
+/*	printf ( "Selecting config 1: io 0x300 @byte 87*2.." );
+	upc[(2*87)] = 2;
+	i365_bclr(1, I365_ADDRWIN, 1 );
+	i365_set(1,I365_INTCTL, 0x65 ); //no-reset, memory-card
+	i365_set(1, I365_IO(0)+0, 0x20 );
+	i365_set(1, I365_IO(0)+1, 0x03 );
+	i365_set(1, I365_IO(0)+2, 0x3f );
+	i365_set(1, I365_IO(0)+3, 0x03 );
+	i365_set(1, 0x3a, 0x05 );
+	i365_set(1, 0x3b, 0x05 );
+	i365_set(1, 0x3c, 0x05 );
+	i365_set(1, 0x3d, 0x05 );
+	i365_set(1, 0x3e, 0x05 );
+	i365_set(1, 0x3f, 0x05 );
+	i365_set(1, 0x07, 0x0a );
+	i365_set(1, I365_ADDRWIN, 0x40 ); // 0x40
+	printf ( "!\n" ); getchar();
+	printf ( "\n" );
+	return 0; */
+}
+
+void	phex ( unsigned char c ) {
+	unsigned char a = 0, b = 0;
+	b = ( c & 0xf );
+	if ( b > 9 ) b += ('a'-'9'-1);
+	b += '0';
+	a = ( c & 0xf0 ) >> 4;
+	if ( a > 9 ) a += ('a'-'9'-1);
+	a += '0';
+	printf ( "%c%c ", a, b );
+	return;
+}
+
+int	deinit_i82365(void) {
+	printf("Deinitializing i82365\n" );
+	return 0;
+}
+
+/*static int i365_get_status(u_short sock, u_int *value)
+{
+    u_int status;
+
+    status = i365_get(sock, I365_STATUS);
+    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+        ? SS_DETECT : 0;
+
+    if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+        *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+    else {
+        *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+        *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+    }
+    *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+    *value |= (status & I365_CS_READY) ? SS_READY : 0;
+    *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+
+#ifdef CONFIG_ISA
+    if (pccsock[sock].type == IS_VG469) {
+        status = i365_get(sock, VG469_VSENSE);
+        if (pccsock[sock].internalid & 1) {
+            *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
+            *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
+        } else {
+            *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
+            *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+        }
+    }
+#endif
+
+    printf("i82365: GetStatus(%d) = %#4.4x\n", sock, *value);
+    return 0;
+} //i365_get_status
+*/
+
+/*static int i365_set_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *t = &socket[sock];
+    u_char reg;
+
+    printf("i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+          "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+          state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+printf ("\nERROR:UNIMPLEMENTED\n" );
+return 0;
+    // First set global controller options 
+    // set_bridge_state(sock); *TODO* check: need this here?
+
+    // IO card, RESET flag, IO interrupt 
+    reg = t->intr;
+    if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq;
+    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+    i365_set(sock, I365_INTCTL, reg);
+
+    reg = I365_PWR_NORESET;
+    if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+    if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+
+    if (t->flags & IS_CIRRUS) {
+        if (state->Vpp != 0) {
+            if (state->Vpp == 120)
+                reg |= I365_VPP1_12V;
+            else if (state->Vpp == state->Vcc)
+                reg |= I365_VPP1_5V;
+            else return -EINVAL;
+        }
+        if (state->Vcc != 0) {
+            reg |= I365_VCC_5V;
+            if (state->Vcc == 33)
+                i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+            else if (state->Vcc == 50)
+                i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+            else return -EINVAL;
+        }
+    } else if (t->flags & IS_VG_PWR) {
+        if (state->Vpp != 0) {
+            if (state->Vpp == 120)
+                reg |= I365_VPP1_12V;
+            else if (state->Vpp == state->Vcc)
+                reg |= I365_VPP1_5V;
+            else return -EINVAL;
+        }
+       if (state->Vcc != 0) {
+            reg |= I365_VCC_5V;
+            if (state->Vcc == 33)
+                i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
+            else if (state->Vcc == 50)
+                i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
+            else return -EINVAL;
+        }
+    } else if (t->flags & IS_DF_PWR) {
+        switch (state->Vcc) {
+        case 0:         break;
+        case 33:        reg |= I365_VCC_3V; break;
+        case 50:        reg |= I365_VCC_5V; break;
+        default:        return -EINVAL;
+        }
+        switch (state->Vpp) {
+        case 0:         break;
+        case 50:        reg |= I365_VPP1_5V; break;
+        case 120:       reg |= I365_VPP1_12V; break;
+        default:        return -EINVAL;
+        }
+    } else {
+        switch (state->Vcc) {
+        case 0:         break;
+        case 50:        reg |= I365_VCC_5V; break;
+        default:        return -EINVAL;
+        }
+        switch (state->Vpp) {
+        case 0:         break;
+        case 50:        reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+        case 120:       reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+        default:        return -EINVAL;
+        }
+    }
+
+    if (reg != i365_get(sock, I365_POWER))
+        i365_set(sock, I365_POWER, reg);
+
+    // Chipset-specific functions 
+    if (t->flags & IS_CIRRUS) {
+        // Speaker control 
+        i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+                   state->flags & SS_SPKR_ENA);
+    }
+
+    // Card status change interrupt mask 
+    reg = t->cs_irq << 4;
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    if (state->flags & SS_IOCARD) {
+        if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+    } else {
+        if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
+        if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
+        if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+    }
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+
+    return 0;
+} // i365_set_socket 
+*/
+
+/*static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl, addr;
+	printf ( "GETIOMAP unimplemented\n" ); return 0;
+    map = io->map;
+    if (map > 1) return -EINVAL;
+    io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
+    io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
+    ioctl = i365_get(sock, I365_IOCTL);
+    addr = i365_get(sock, I365_ADDRWIN);
+    io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
+    io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
+    io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
+    io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
+    io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
+    printf("i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+          "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+          io->start, io->stop);
+    return 0;
+} // i365_get_io_map 
+*/
+
+/*====================================================================*/
+
+/*static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl;
+
+    printf("i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+          "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+          io->speed, io->start, io->stop);
+printf ( "UNIMPLEMENTED\n" );
+	return 0;
+    map = io->map;
+    //if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+    if ((map > 1) ||
+        (io->stop < io->start)) return -EINVAL;
+    // Turn off the window before changing anything 
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+        i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
+    i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
+    ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+    if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
+    if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+    if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+    if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+    i365_set(sock, I365_IOCTL, ioctl);
+    // Turn on the window if necessary 
+    if (io->flags & MAP_ACTIVE)
+        i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    return 0;
+} // i365_set_io_map 
+*/
+
+/*
+static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map;
+
+    printf("i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+          "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
+          mem->sys_start, mem->sys_stop, mem->card_start);
+
+printf ( "UNIMPLEMENTED\n" );
+	return 0;
+    map = mem->map;
+    if ((map > 4) || (mem->card_start > 0x3ffffff) ||
+        (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+        return -EINVAL;
+    if (!(socket[sock].flags & IS_PCI) &&
+        ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)))
+        return -EINVAL;
+
+    // Turn off the window before changing anything 
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+        i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+
+    base = I365_MEM(map);
+    i = (mem->sys_start >> 12) & 0x0fff;
+    if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+    if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+    i365_set_pair(sock, base+I365_W_START, i);
+
+    i = (mem->sys_stop >> 12) & 0x0fff;
+    switch (to_cycles(mem->speed)) {
+    case 0:     break;
+    case 1:     i |= I365_MEM_WS0; break;
+    case 2:     i |= I365_MEM_WS1; break;
+    default:    i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+    }
+    i365_set_pair(sock, base+I365_W_STOP, i);
+
+    i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+    if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+    if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+    i365_set_pair(sock, base+I365_W_OFF, i);
+
+    // Turn on the window if necessary 
+    if (mem->flags & MAP_ACTIVE)
+        i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+    return 0;
+} // i365_set_mem_map 
+*/
+
+
+int	i82365_interfacer ( interface_func_t func, int sockno, int par1, int par2, void* par3 ) {
+	//int	i, j, k;
+	//u_int	ui;
+	u_char *upc;
+	struct pcc_config_t * pccc;
+	switch ( func ) {
+	  case	INIT:
+		mydriverid = par1;
+		return	init_i82365();
+	  case	SHUTDOWN:
+		i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
+		i365_set(sockno, I365_INTCTL, 0x05 );
+		sleepticks(2);
+		i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
+		break;
+	  case	MAPATTRMEM:
+		i365_set(sockno,I365_POWER, 0xb1 );
+		i365_set(sockno, I365_INTCTL, 0x05 );
+		sleepticks(2);
+		i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
+		i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
+		//i365_bclr(sockno, I365_ADDRWIN, 1 );
+		i365_set(sockno, I365_MEM(0)+0, ( par1 >> 12 )& 0xff ); //start
+		i365_set(sockno, I365_MEM(0)+1, ( par1 >> 20 ) & 0x0f );
+		i365_set(sockno, I365_MEM(0)+2, ((par1 + par2 - 1 ) >> 12 ) & 0xff ); //end
+		i365_set(sockno, I365_MEM(0)+3, (( par1 + par2 - 1 ) >> 20 ) & 0x0f  );
+		i365_set(sockno, I365_MEM(0)+4, ((0x4000000 - par1) >> 12) & 0xff ); //offset low
+		i365_set(sockno, I365_MEM(0)+5, 0x40 | (((0x40000000 - par1) >> 12) & 0x3f));
+		i365_bset(sockno, I365_ADDRWIN, 1 );
+		if ( ! ( 1 & i365_get ( sockno, I365_ADDRWIN ) ) ) return 1;
+		break;
+	  case	UNMAPATTRMEM:
+		i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
+		i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
+		break;
+	  case	SELECTCONFIG:	// Params: par1: config number; par3 config pointer pointer
+		if ( 0 > pccsock[sockno].configoffset ) return 1;
+		if ( NULL == (pccc = par3 ) ) return 2;
+		// write config number to 
+		upc = ioremap ( MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN );
+		if ( pccsock[sockno].configoffset > MAP_ATTRMEM_LEN ) return 3;
+		if ( ( par1 & 0x7fffffc0 ) ) return 4;
+		if ( pccc->index != par1 ) return 5;
+		upc[pccsock[sockno].configoffset] = ( upc[pccsock[sockno].configoffset] & 0xc0 ) | ( par1 & 0x3f );
+		i365_set(sockno, I365_IOCTL, (i365_get(sockno, I365_IOCTL) & 0xfe) | 0x20 );	// 16bit autosize
+		i365_set(sockno, I365_IO(0)+0, pccc->iowin & 0xff);
+		i365_set(sockno, I365_IO(0)+1, (pccc->iowin >> 8) & 0xff);
+		i365_set(sockno, I365_IO(0)+2, (pccc->iowin+pccc->iolen - 1) & 0xff);
+		i365_set(sockno, I365_IO(0)+3, ((pccc->iowin+pccc->iolen- 1) >> 8) & 0xff);
+		// Disable mem mapping
+		i365_bclr(sockno, I365_ADDRWIN, 1);
+		i365_set(sockno, I365_INTCTL, 0x65);
+		i365_bset(sockno, I365_ADDRWIN,0x40);
+		break;
+	  default:
+		return	-1; // ERROR: Unknown function called
+	}
+	return	0;
+}
+
+// get_mem_map[1320]
+// cirrus_get_state/set/opts...
+// vg46x_get_state/...
+// get_bridge_state/...
+
+#endif /* CONFIG_PCMCIA */
diff --git a/qemu-0.15.x/roms/ipxe/src/core/image.c b/qemu-0.15.x/roms/ipxe/src/core/image.c
new file mode 100644
index 0000000..86c264c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/image.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <libgen.h>
+#include <ipxe/list.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/uri.h>
+#include <ipxe/image.h>
+
+/** @file
+ *
+ * Executable images
+ *
+ */
+
+/** List of registered images */
+struct list_head images = LIST_HEAD_INIT ( images );
+
+/** Currently-executing image */
+struct image *current_image;
+
+/**
+ * Free executable image
+ *
+ * @v refcnt		Reference counter
+ */
+static void free_image ( struct refcnt *refcnt ) {
+	struct image *image = container_of ( refcnt, struct image, refcnt );
+
+	free ( image->cmdline );
+	uri_put ( image->uri );
+	ufree ( image->data );
+	image_put ( image->replacement );
+	free ( image );
+	DBGC ( image, "IMAGE %s freed\n", image->name );
+}
+
+/**
+ * Allocate executable image
+ *
+ * @ret image		Executable image
+ */
+struct image * alloc_image ( void ) {
+	struct image *image;
+
+	image = zalloc ( sizeof ( *image ) );
+	if ( image ) {
+		ref_init ( &image->refcnt, free_image );
+	}
+	return image;
+}
+
+/**
+ * Set image URI
+ *
+ * @v image		Image
+ * @v URI		New image URI
+ *
+ * If no name is set, the name will be updated to the base name of the
+ * URI path (if any).
+ */
+void image_set_uri ( struct image *image, struct uri *uri ) {
+	const char *path = uri->path;
+
+	/* Replace URI reference */
+	uri_put ( image->uri );
+	image->uri = uri_get ( uri );
+
+	/* Set name if none already specified */
+	if ( path && ( ! image->name[0] ) )
+		image_set_name ( image, basename ( ( char * ) path ) );
+}
+
+/**
+ * Set image command line
+ *
+ * @v image		Image
+ * @v cmdline		New image command line, or NULL
+ * @ret rc		Return status code
+ */
+int image_set_cmdline ( struct image *image, const char *cmdline ) {
+
+	free ( image->cmdline );
+	image->cmdline = NULL;
+	if ( cmdline ) {
+		image->cmdline = strdup ( cmdline );
+		if ( ! image->cmdline )
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/**
+ * Register executable image
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ */
+int register_image ( struct image *image ) {
+	static unsigned int imgindex = 0;
+
+	/* Create image name if it doesn't already have one */
+	if ( ! image->name[0] ) {
+		snprintf ( image->name, sizeof ( image->name ), "img%d",
+			   imgindex++ );
+	}
+
+	/* Avoid ending up with multiple "selected" images on
+	 * re-registration
+	 */
+	if ( image_find_selected() )
+		image->flags &= ~IMAGE_SELECTED;
+
+	/* Add to image list */
+	image_get ( image );
+	image->flags |= IMAGE_REGISTERED;
+	list_add_tail ( &image->list, &images );
+	DBGC ( image, "IMAGE %s at [%lx,%lx) registered\n",
+	       image->name, user_to_phys ( image->data, 0 ),
+	       user_to_phys ( image->data, image->len ) );
+
+	return 0;
+}
+
+/**
+ * Unregister executable image
+ *
+ * @v image		Executable image
+ */
+void unregister_image ( struct image *image ) {
+
+	DBGC ( image, "IMAGE %s unregistered\n", image->name );
+	list_del ( &image->list );
+	image->flags &= ~IMAGE_REGISTERED;
+	image_put ( image );
+}
+
+/**
+ * Find image by name
+ *
+ * @v name		Image name
+ * @ret image		Executable image, or NULL
+ */
+struct image * find_image ( const char *name ) {
+	struct image *image;
+
+	list_for_each_entry ( image, &images, list ) {
+		if ( strcmp ( image->name, name ) == 0 )
+			return image;
+	}
+
+	return NULL;
+}
+
+/**
+ * Determine image type
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ */
+int image_probe ( struct image *image ) {
+	struct image_type *type;
+	int rc;
+
+	/* Succeed if we already have a type */
+	if ( image->type )
+		return 0;
+
+	/* Try each type in turn */
+	for_each_table_entry ( type, IMAGE_TYPES ) {
+		if ( ( rc = type->probe ( image ) ) == 0 ) {
+			image->type = type;
+			DBGC ( image, "IMAGE %s is %s\n",
+			       image->name, type->name );
+			return 0;
+		}
+		DBGC ( image, "IMAGE %s is not %s: %s\n", image->name,
+		       type->name, strerror ( rc ) );
+	}
+
+	DBGC ( image, "IMAGE %s format not recognised\n", image->name );
+	return -ENOEXEC;
+}
+
+/**
+ * Execute image
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ *
+ * The image must already be registered.  Note that executing an image
+ * may cause it to unregister itself.  The caller must therefore
+ * assume that the image pointer becomes invalid.
+ */
+int image_exec ( struct image *image ) {
+	struct image *saved_current_image;
+	struct image *replacement;
+	struct uri *old_cwuri;
+	int rc;
+
+	/* Sanity check */
+	assert ( image->flags & IMAGE_REGISTERED );
+
+	/* Check that this image can be executed */
+	if ( ( rc = image_probe ( image ) ) != 0 )
+		return rc;
+
+	/* Switch current working directory to be that of the image itself */
+	old_cwuri = uri_get ( cwuri );
+	churi ( image->uri );
+
+	/* Preserve record of any currently-running image */
+	saved_current_image = current_image;
+
+	/* Take out a temporary reference to the image.  This allows
+	 * the image to unregister itself if necessary, without
+	 * automatically freeing itself.
+	 */
+	current_image = image_get ( image );
+
+	/* Try executing the image */
+	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
+		DBGC ( image, "IMAGE %s could not execute: %s\n",
+		       image->name, strerror ( rc ) );
+		/* Do not return yet; we still have clean-up to do */
+	}
+
+	/* Pick up replacement image before we drop the original
+	 * image's temporary reference.  The replacement image must
+	 * already be registered, so we don't need to hold a temporary
+	 * reference (which would complicate the tail-recursion).
+	 */
+	replacement = image->replacement;
+	if ( replacement )
+		assert ( replacement->flags & IMAGE_REGISTERED );
+
+	/* Drop temporary reference to the original image */
+	image_put ( image );
+
+	/* Restore previous currently-running image */
+	current_image = saved_current_image;
+
+	/* Reset current working directory */
+	churi ( old_cwuri );
+	uri_put ( old_cwuri );
+
+	/* Tail-recurse into replacement image, if one exists */
+	if ( replacement ) {
+		DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
+		       image->name, replacement->name );
+		if ( ( rc = image_exec ( replacement ) ) != 0 )
+			return rc;
+	}
+
+	return rc;
+}
+
+/**
+ * Set replacement image
+ *
+ * @v replacement	Replacement image
+ * @ret rc		Return status code
+ *
+ * The replacement image must already be registered, and must remain
+ * registered until the currently-executing image returns.
+ */
+int image_replace ( struct image *replacement ) {
+	struct image *image = current_image;
+	int rc;
+
+	/* Sanity check */
+	assert ( replacement->flags & IMAGE_REGISTERED );
+
+	/* Fail unless there is a currently-executing image */
+	if ( ! image ) {
+		rc = -ENOTTY;
+		DBGC ( replacement, "IMAGE %s cannot replace non-existent "
+		       "image: %s\n", replacement->name, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Clear any existing replacement */
+	image_put ( image->replacement );
+
+	/* Set replacement */
+	image->replacement = image_get ( replacement );
+	DBGC ( image, "IMAGE %s will replace self with IMAGE %s\n",
+	       image->name, replacement->name );
+
+	return 0;
+}
+
+/**
+ * Select image for execution
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ */
+int image_select ( struct image *image ) {
+	struct image *tmp;
+	int rc;
+
+	/* Unselect all other images */
+	for_each_image ( tmp )
+		tmp->flags &= ~IMAGE_SELECTED;
+
+	/* Check that this image can be executed */
+	if ( ( rc = image_probe ( image ) ) != 0 )
+		return rc;
+
+	/* Mark image as selected */
+	image->flags |= IMAGE_SELECTED;
+
+	return 0;
+}
+
+/**
+ * Find selected image
+ *
+ * @ret image		Executable image, or NULL
+ */
+struct image * image_find_selected ( void ) {
+	struct image *image;
+
+	for_each_image ( image ) {
+		if ( image->flags & IMAGE_SELECTED )
+			return image;
+	}
+	return NULL;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/init.c b/qemu-0.15.x/roms/ipxe/src/core/init.c
new file mode 100644
index 0000000..4dc706f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/init.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/device.h>
+#include <ipxe/init.h>
+
+/** @file
+ *
+ * Initialisation, startup and shutdown routines
+ *
+ */
+
+/** "startup() has been called" flag */
+static int started = 0;
+
+/**
+ * Initialise iPXE
+ *
+ * This function performs the one-time-only and irreversible
+ * initialisation steps, such as initialising the heap.  It must be
+ * called before (almost) any other function.
+ *
+ * There is, by definition, no counterpart to this function on the
+ * shutdown path.
+ */
+void initialise ( void ) {
+	struct init_fn *init_fn;
+
+	/* Call registered initialisation functions */
+	for_each_table_entry ( init_fn, INIT_FNS )
+		init_fn->initialise ();
+}
+
+/**
+ * Start up iPXE
+ *
+ * This function performs the repeatable initialisation steps, such as
+ * probing devices.  You may call startup() and shutdown() multiple
+ * times (as is done via the PXE API when PXENV_START_UNDI is used).
+ */
+void startup ( void ) {
+	struct startup_fn *startup_fn;
+
+	if ( started )
+		return;
+
+	/* Call registered startup functions */
+	for_each_table_entry ( startup_fn, STARTUP_FNS ) {
+		if ( startup_fn->startup )
+			startup_fn->startup();
+	}
+
+	started = 1;
+}
+
+/**
+ * Shut down iPXE
+ *
+ * @v flags		Shutdown behaviour flags
+ *
+ * This function reverses the actions of startup(), and leaves iPXE in
+ * a state ready to be removed from memory.  You may call startup()
+ * again after calling shutdown().
+ *
+ * Call this function only once, before either exiting main() or
+ * starting up a non-returnable image.
+ */
+void shutdown ( int flags ) {
+	struct startup_fn *startup_fn;
+
+	if ( ! started )
+		return;
+
+	/* Call registered shutdown functions (in reverse order) */
+	for_each_table_entry_reverse ( startup_fn, STARTUP_FNS ) {
+		if ( startup_fn->shutdown )
+			startup_fn->shutdown ( flags );
+	}
+
+	started = 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/interface.c b/qemu-0.15.x/roms/ipxe/src/core/interface.c
new file mode 100644
index 0000000..c69875e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/interface.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/interface.h>
+
+/** @file
+ *
+ * Object interfaces
+ *
+ */
+
+/*****************************************************************************
+ *
+ * The null interface
+ *
+ */
+
+/** Null interface operations */
+static struct interface_operation null_intf_op[] = {};
+
+/** Null interface descriptor */
+struct interface_descriptor null_intf_desc =
+	INTF_DESC_PURE ( null_intf_op );
+
+/** The null interface */
+struct interface null_intf = INTF_INIT ( null_intf_desc );
+
+/*****************************************************************************
+ *
+ * Object interface plumbing
+ *
+ */
+
+/**
+ * Plug an object interface into a new destination object interface
+ *
+ * @v intf		Object interface
+ * @v dest		New destination object interface
+ *
+ * The reference to the existing destination interface is dropped, a
+ * reference to the new destination interface is obtained, and the
+ * interface is updated to point to the new destination interface.
+ *
+ * Note that there is no "unplug" call; instead you must plug the
+ * interface into a null interface.
+ */
+void intf_plug ( struct interface *intf, struct interface *dest ) {
+	DBGC ( INTF_COL ( intf ),
+	       "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n",
+	       INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) );
+	intf_get ( dest );
+	intf_put ( intf->dest );
+	intf->dest = dest;
+}
+
+/**
+ * Plug two object interfaces together
+ *
+ * @v a			Object interface A
+ * @v b			Object interface B
+ *
+ * Plugs interface A into interface B, and interface B into interface
+ * A.  (The basic plug() function is unidirectional; this function is
+ * merely a shorthand for two calls to plug(), hence the name.)
+ */
+void intf_plug_plug ( struct interface *a, struct interface *b ) {
+	intf_plug ( a, b );
+	intf_plug ( b, a );
+}
+
+/**
+ * Unplug an object interface
+ *
+ * @v intf		Object interface
+ */
+void intf_unplug ( struct interface *intf ) {
+	intf_plug ( intf, &null_intf );
+}
+
+/**
+ * Ignore all further operations on an object interface
+ *
+ * @v intf		Object interface
+ */
+void intf_nullify ( struct interface *intf ) {
+	intf->desc = &null_intf_desc;
+}
+
+/**
+ * Increment reference count on an object interface
+ *
+ * @v intf		Object interface
+ * @ret intf		Object interface
+ */
+struct interface * intf_get ( struct interface *intf ) {
+	ref_get ( intf->refcnt );
+	return intf;
+}
+
+/**
+ * Decrement reference count on an object interface
+ *
+ * @v intf		Object interface
+ */
+void intf_put ( struct interface *intf ) {
+	ref_put ( intf->refcnt );
+}
+
+/**
+ * Get pointer to object containing object interface
+ *
+ * @v intf		Object interface
+ * @ret object		Containing object
+ */
+void * intf_object ( struct interface *intf ) {
+	return ( ( ( void * ) intf ) - intf->desc->offset );
+}
+
+/**
+ * Get pass-through interface
+ *
+ * @v intf		Object interface
+ * @ret passthru	Pass-through interface, or NULL
+ */
+static struct interface * intf_get_passthru ( struct interface *intf ) {
+	struct interface_descriptor *desc = intf->desc;
+
+	if ( desc->passthru_offset ) {
+		return ( ( ( void * ) intf ) + desc->passthru_offset );
+	} else {
+		return NULL;
+	}
+}
+
+/**
+ * Get object interface destination and operation method (without pass-through)
+ *
+ * @v intf		Object interface
+ * @v type		Operation type
+ * @ret dest		Destination interface
+ * @ret func		Implementing method, or NULL
+ */
+void * intf_get_dest_op_no_passthru_untyped ( struct interface *intf,
+					      void *type,
+					      struct interface **dest ) {
+	struct interface_descriptor *desc;
+	struct interface_operation *op;
+	unsigned int i;
+
+	*dest = intf_get ( intf->dest );
+	desc = (*dest)->desc;
+	for ( i = desc->num_op, op = desc->op ; i ; i--, op++ ) {
+		if ( op->type == type )
+			return op->func;
+	}
+
+	return NULL;
+}
+
+/**
+ * Get object interface destination and operation method
+ *
+ * @v intf		Object interface
+ * @v type		Operation type
+ * @ret dest		Destination interface
+ * @ret func		Implementing method, or NULL
+ */
+void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
+				  struct interface **dest ) {
+	void *func;
+
+	while ( 1 ) {
+
+		/* Search for an implementing method provided by the
+		 * current destination interface.
+		 */
+		func = intf_get_dest_op_no_passthru_untyped( intf, type, dest );
+		if ( func )
+			return func;
+
+		/* Pass through to the underlying interface, if applicable */
+		if ( ! ( intf = intf_get_passthru ( *dest ) ) )
+			return NULL;
+		intf_put ( *dest );
+	}
+}
+
+/*****************************************************************************
+ *
+ * Generic interface operations
+ *
+ */
+
+/**
+ * Close an object interface
+ *
+ * @v intf		Object interface
+ * @v rc		Reason for close
+ *
+ * Note that this function merely informs the destination object that
+ * the interface is about to be closed; it doesn't actually disconnect
+ * the interface.  In most cases, you probably want to use
+ * intf_shutdown() or intf_restart() instead.
+ */
+void intf_close ( struct interface *intf, int rc ) {
+	struct interface *dest;
+	intf_close_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, intf_close, &dest );
+	void *object = intf_object ( dest );
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " close (%s)\n",
+	       INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
+
+	if ( op ) {
+		op ( object, rc );
+	} else {
+		/* Default is to ignore intf_close() */
+	}
+
+	intf_put ( dest );
+}
+
+/**
+ * Shut down an object interface
+ *
+ * @v intf		Object interface
+ * @v rc		Reason for close
+ *
+ * Blocks further operations from being received via the interface,
+ * executes a close operation on the destination interface, and
+ * unplugs the interface.
+ */
+void intf_shutdown ( struct interface *intf, int rc ) {
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n",
+	       INTF_DBG ( intf ), strerror ( rc ) );
+
+	/* Block further operations */
+	intf_nullify ( intf );
+
+	/* Notify destination of close */
+	intf_close ( intf, rc );
+
+	/* Unplug interface */
+	intf_unplug ( intf );
+}
+
+/**
+ * Shut down and restart an object interface
+ *
+ * @v intf		Object interface
+ * @v rc		Reason for close
+ *
+ * Shuts down the interface, then unblocks operations that were
+ * blocked during shutdown.
+ */
+void intf_restart ( struct interface *intf, int rc ) {
+	struct interface_descriptor *desc = intf->desc;
+
+	/* Shut down the interface */
+	intf_shutdown ( intf, rc );
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " restarting\n",
+	       INTF_DBG ( intf ) );
+
+	/* Restore the interface descriptor.  Must be done after
+	 * shutdown (rather than inhibiting intf_shutdown() from
+	 * nullifying the descriptor) in order to avoid a potential
+	 * infinite loop as the intf_close() operations on each side
+	 * of the link call each other recursively.
+	 */
+	intf->desc = desc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/iobuf.c b/qemu-0.15.x/roms/ipxe/src/core/iobuf.c
new file mode 100644
index 0000000..d776d60
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/iobuf.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+
+/** @file
+ *
+ * I/O buffers
+ *
+ */
+
+/**
+ * Allocate I/O buffer
+ *
+ * @v len	Required length of buffer
+ * @ret iobuf	I/O buffer, or NULL if none available
+ *
+ * The I/O buffer will be physically aligned to a multiple of
+ * @c IOBUF_SIZE.
+ */
+struct io_buffer * alloc_iob ( size_t len ) {
+	struct io_buffer *iobuf = NULL;
+	void *data;
+
+	/* Pad to minimum length */
+	if ( len < IOB_ZLEN )
+		len = IOB_ZLEN;
+
+	/* Align buffer length */
+	len = ( len + __alignof__( *iobuf ) - 1 ) &
+		~( __alignof__( *iobuf ) - 1 );
+	
+	/* Allocate memory for buffer plus descriptor */
+	data = malloc_dma ( len + sizeof ( *iobuf ), IOB_ALIGN );
+	if ( ! data )
+		return NULL;
+
+	iobuf = ( struct io_buffer * ) ( data + len );
+	iobuf->head = iobuf->data = iobuf->tail = data;
+	iobuf->end = iobuf;
+	return iobuf;
+}
+
+/**
+ * Free I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ */
+void free_iob ( struct io_buffer *iobuf ) {
+	if ( iobuf ) {
+		assert ( iobuf->head <= iobuf->data );
+		assert ( iobuf->data <= iobuf->tail );
+		assert ( iobuf->tail <= iobuf->end );
+		free_dma ( iobuf->head,
+			   ( iobuf->end - iobuf->head ) + sizeof ( *iobuf ) );
+	}
+}
+
+/**
+ * Ensure I/O buffer has sufficient headroom
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Required headroom
+ *
+ * This function currently only checks for the required headroom; it
+ * does not reallocate the I/O buffer if required.  If we ever have a
+ * code path that requires this functionality, it's a fairly trivial
+ * change to make.
+ */
+int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
+
+	if ( iob_headroom ( iobuf ) >= len )
+		return 0;
+	return -ENOBUFS;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/core/job.c b/qemu-0.15.x/roms/ipxe/src/core/job.c
new file mode 100644
index 0000000..ac4e43e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/job.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/job.h>
+
+/** @file
+ *
+ * Job control interfaces
+ *
+ */
+
+/**
+ * Get job progress
+ *
+ * @v intf		Object interface
+ * @v progress		Progress data to fill in
+ */
+void job_progress ( struct interface *intf, struct job_progress *progress ) {
+	struct interface *dest;
+	job_progress_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, job_progress, &dest );
+	void *object = intf_object ( dest );
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " job_progress\n",
+	       INTF_INTF_DBG ( intf, dest ) );
+
+	if ( op ) {
+		op ( object, progress );
+	} else {
+		/* Default is to mark progress as zero */
+		memset ( progress, 0, sizeof ( *progress ) );
+	}
+
+	intf_put ( dest );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/linebuf.c b/qemu-0.15.x/roms/ipxe/src/core/linebuf.c
new file mode 100644
index 0000000..f152bcc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/linebuf.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Line buffering
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/linebuf.h>
+
+/**
+ * Retrieve buffered-up line
+ *
+ * @v linebuf		Line buffer
+ * @ret line		Buffered line, or NULL if no line ready to read
+ */
+char * buffered_line ( struct line_buffer *linebuf ) {
+	return ( linebuf->ready ? linebuf->data : NULL );
+}
+
+/**
+ * Discard line buffer contents
+ *
+ * @v linebuf		Line buffer
+ */
+void empty_line_buffer ( struct line_buffer *linebuf ) {
+	free ( linebuf->data );
+	linebuf->data = NULL;
+	linebuf->len = 0;
+	linebuf->ready = 0;
+}
+
+/**
+ * Buffer up received data by lines
+ *
+ * @v linebuf			Line buffer
+ * @v data			New data to add
+ * @v len			Length of new data to add
+ * @ret len			Consumed length, or negative error number
+ *
+ * After calling line_buffer(), use buffered_line() to determine
+ * whether or not a complete line is available.  Carriage returns and
+ * newlines will have been stripped, and the line will be
+ * NUL-terminated.  This buffered line is valid only until the next
+ * call to line_buffer() (or to empty_line_buffer()).
+ *
+ * Note that line buffers use dynamically allocated storage; you
+ * should call empty_line_buffer() before freeing a @c struct @c
+ * line_buffer.
+ */
+ssize_t line_buffer ( struct line_buffer *linebuf,
+		      const char *data, size_t len ) {
+	const char *eol;
+	size_t consume;
+	size_t new_len;
+	char *new_data;
+
+	/* Free any completed line from previous iteration */
+	if ( linebuf->ready )
+		empty_line_buffer ( linebuf );
+
+	/* Search for line terminator */
+	if ( ( eol = memchr ( data, '\n', len ) ) ) {
+		consume = ( eol - data + 1 );
+	} else {
+		consume = len;
+	}
+
+	/* Reallocate data buffer and copy in new data */
+	new_len = ( linebuf->len + consume );
+	new_data = realloc ( linebuf->data, ( new_len + 1 ) );
+	if ( ! new_data )
+		return -ENOMEM;
+	memcpy ( ( new_data + linebuf->len ), data, consume );
+	new_data[new_len] = '\0';
+	linebuf->data = new_data;
+	linebuf->len = new_len;
+
+	/* If we have reached end of line, trim the line and mark as ready */
+	if ( eol ) {
+		linebuf->data[--linebuf->len] = '\0'; /* trim NL */
+		if ( linebuf->data[linebuf->len - 1] == '\r' )
+			linebuf->data[--linebuf->len] = '\0'; /* trim CR */
+		linebuf->ready = 1;
+	}
+
+	return consume;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/main.c b/qemu-0.15.x/roms/ipxe/src/core/main.c
new file mode 100644
index 0000000..9fd4a76
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/main.c
@@ -0,0 +1,118 @@
+/**************************************************************************
+iPXE -  Network Bootstrap Program
+
+Literature dealing with the network protocols:
+	ARP - RFC826
+	RARP - RFC903
+	UDP - RFC768
+	BOOTP - RFC951, RFC2132 (vendor extensions)
+	DHCP - RFC2131, RFC2132 (options)
+	TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
+	RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
+
+**************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ipxe/init.h>
+#include <ipxe/features.h>
+#include <ipxe/shell.h>
+#include <ipxe/image.h>
+#include <ipxe/keys.h>
+#include <usr/prompt.h>
+#include <usr/autoboot.h>
+#include <config/general.h>
+
+#define NORMAL	"\033[0m"
+#define BOLD	"\033[1m"
+#define CYAN	"\033[36m"
+
+/** The "scriptlet" setting */
+struct setting scriptlet_setting __setting ( SETTING_MISC ) = {
+	.name = "scriptlet",
+	.description = "Boot scriptlet",
+	.tag = DHCP_EB_SCRIPTLET,
+	.type = &setting_type_string,
+};
+
+/**
+ * Prompt for shell entry
+ *
+ * @ret	enter_shell		User wants to enter shell
+ */
+static int shell_banner ( void ) {
+
+	/* Skip prompt if timeout is zero */
+	if ( BANNER_TIMEOUT <= 0 )
+		return 0;
+
+	return ( prompt ( "\nPress Ctrl-B for the iPXE command line...",
+			  ( BANNER_TIMEOUT * 100 ), CTRL_B ) == 0 );
+}
+
+/**
+ * Main entry point
+ *
+ * @ret rc		Return status code
+ */
+__asmcall int main ( void ) {
+	struct feature *feature;
+	struct image *image;
+	char *scriptlet;
+
+	/* Some devices take an unreasonably long time to initialise */
+	printf ( PRODUCT_SHORT_NAME " initialising devices..." );
+	initialise();
+	startup();
+	printf ( "ok\n" );
+
+	/*
+	 * Print welcome banner
+	 *
+	 *
+	 * If you wish to brand this build of iPXE, please do so by
+	 * defining the string PRODUCT_NAME in config/general.h.
+	 *
+	 * While nothing in the GPL prevents you from removing all
+	 * references to iPXE or http://ipxe.org, we prefer you not to
+	 * do so.
+	 *
+	 */
+	printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE " VERSION
+		 NORMAL " -- Open Source Network Boot Firmware -- "
+		 CYAN "http://ipxe.org" NORMAL "\n"
+		 "Features:" );
+	for_each_table_entry ( feature, FEATURES )
+		printf ( " %s", feature->name );
+	printf ( "\n" );
+
+	/* Boot system */
+	if ( ( image = first_image() ) != NULL ) {
+		/* We have an embedded image; execute it */
+		image_exec ( image );
+	} else if ( shell_banner() ) {
+		/* User wants shell; just give them a shell */
+		shell();
+	} else {
+		fetch_string_setting_copy ( NULL, &scriptlet_setting,
+					    &scriptlet );
+		if ( scriptlet ) {
+			/* User has defined a scriptlet; execute it */
+			system ( scriptlet );
+			free ( scriptlet );
+		} else {
+			/* Try booting.  If booting fails, offer the
+			 * user another chance to enter the shell.
+			 */
+			autoboot();
+			if ( shell_banner() )
+				shell();
+		}
+	}
+
+	shutdown_exit();
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/malloc.c b/qemu-0.15.x/roms/ipxe/src/core/malloc.c
new file mode 100644
index 0000000..d694f55
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/malloc.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <ipxe/io.h>
+#include <ipxe/list.h>
+#include <ipxe/init.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/malloc.h>
+#include <valgrind/memcheck.h>
+
+/** @file
+ *
+ * Dynamic memory allocation
+ *
+ */
+
+/** A free block of memory */
+struct memory_block {
+	/** Size of this block */
+	size_t size;
+	/** Padding
+	 *
+	 * This padding exists to cover the "count" field of a
+	 * reference counter, in the common case where a reference
+	 * counter is the first element of a dynamically-allocated
+	 * object.  It avoids clobbering the "count" field as soon as
+	 * the memory is freed, and so allows for the possibility of
+	 * detecting reference counting errors.
+	 */
+	char pad[ offsetof ( struct refcnt, count ) +
+		  sizeof ( ( ( struct refcnt * ) NULL )->count ) ];
+	/** List of free blocks */
+	struct list_head list;
+};
+
+#define MIN_MEMBLOCK_SIZE \
+	( ( size_t ) ( 1 << ( fls ( sizeof ( struct memory_block ) - 1 ) ) ) )
+
+/** A block of allocated memory complete with size information */
+struct autosized_block {
+	/** Size of this block */
+	size_t size;
+	/** Remaining data */
+	char data[0];
+};
+
+/**
+ * Address for zero-length memory blocks
+ *
+ * @c malloc(0) or @c realloc(ptr,0) will return the special value @c
+ * NOWHERE.  Calling @c free(NOWHERE) will have no effect.
+ *
+ * This is consistent with the ANSI C standards, which state that
+ * "either NULL or a pointer suitable to be passed to free()" must be
+ * returned in these cases.  Using a special non-NULL value means that
+ * the caller can take a NULL return value to indicate failure,
+ * without first having to check for a requested size of zero.
+ *
+ * Code outside of malloc.c do not ever need to refer to the actual
+ * value of @c NOWHERE; this is an internal definition.
+ */
+#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) )
+
+/** List of free memory blocks */
+static LIST_HEAD ( free_blocks );
+
+/** Total amount of free memory */
+size_t freemem;
+
+/**
+ * Heap size
+ *
+ * Currently fixed at 128kB.
+ */
+#define HEAP_SIZE ( 128 * 1024 )
+
+/** The heap itself */
+static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
+
+/**
+ * Mark all blocks in free list as defined
+ *
+ */
+static inline void valgrind_make_blocks_defined ( void ) {
+	struct memory_block *block;
+
+	if ( RUNNING_ON_VALGRIND > 0 ) {
+		VALGRIND_MAKE_MEM_DEFINED ( &free_blocks,
+					    sizeof ( free_blocks ) );
+		list_for_each_entry ( block, &free_blocks, list )
+			VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
+	}
+}
+
+/**
+ * Mark all blocks in free list as inaccessible
+ *
+ */
+static inline void valgrind_make_blocks_noaccess ( void ) {
+	struct memory_block *block;
+	struct memory_block *tmp;
+
+	if ( RUNNING_ON_VALGRIND > 0 ) {
+		list_for_each_entry_safe ( block, tmp, &free_blocks, list )
+			VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
+		VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks,
+					     sizeof ( free_blocks ) );
+	}
+}
+
+/**
+ * Discard some cached data
+ *
+ * @ret discarded	Number of cached items discarded
+ */
+static unsigned int discard_cache ( void ) {
+	struct cache_discarder *discarder;
+	unsigned int discarded = 0;
+
+	for_each_table_entry ( discarder, CACHE_DISCARDERS ) {
+		discarded += discarder->discard();
+	}
+	return discarded;
+}
+
+/**
+ * Allocate a memory block
+ *
+ * @v size		Requested size
+ * @v align		Physical alignment
+ * @ret ptr		Memory block, or NULL
+ *
+ * Allocates a memory block @b physically aligned as requested.  No
+ * guarantees are provided for the alignment of the virtual address.
+ *
+ * @c align must be a power of two.  @c size may not be zero.
+ */
+void * alloc_memblock ( size_t size, size_t align ) {
+	struct memory_block *block;
+	size_t align_mask;
+	size_t pre_size;
+	ssize_t post_size;
+	struct memory_block *pre;
+	struct memory_block *post;
+	struct memory_block *ptr;
+
+	valgrind_make_blocks_defined();
+
+	/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
+	 * calculate alignment mask.
+	 */
+	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
+	align_mask = ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 );
+
+	DBG ( "Allocating %#zx (aligned %#zx)\n", size, align );
+	while ( 1 ) {
+		/* Search through blocks for the first one with enough space */
+		list_for_each_entry ( block, &free_blocks, list ) {
+			pre_size = ( - virt_to_phys ( block ) ) & align_mask;
+			post_size = block->size - pre_size - size;
+			if ( post_size >= 0 ) {
+				/* Split block into pre-block, block, and
+				 * post-block.  After this split, the "pre"
+				 * block is the one currently linked into the
+				 * free list.
+				 */
+				pre   = block;
+				block = ( ( ( void * ) pre   ) + pre_size );
+				post  = ( ( ( void * ) block ) + size     );
+				DBG ( "[%p,%p) -> [%p,%p) + [%p,%p)\n", pre,
+				      ( ( ( void * ) pre ) + pre->size ),
+				      pre, block, post,
+				      ( ( ( void * ) pre ) + pre->size ) );
+				/* If there is a "post" block, add it in to
+				 * the free list.  Leak it if it is too small
+				 * (which can happen only at the very end of
+				 * the heap).
+				 */
+				if ( (size_t) post_size >= MIN_MEMBLOCK_SIZE ) {
+					VALGRIND_MAKE_MEM_DEFINED ( post,
+							     sizeof ( *post ) );
+					post->size = post_size;
+					list_add ( &post->list, &pre->list );
+				}
+				/* Shrink "pre" block, leaving the main block
+				 * isolated and no longer part of the free
+				 * list.
+				 */
+				pre->size = pre_size;
+				/* If there is no "pre" block, remove it from
+				 * the list.  Also remove it (i.e. leak it) if
+				 * it is too small, which can happen only at
+				 * the very start of the heap.
+				 */
+				if ( pre_size < MIN_MEMBLOCK_SIZE )
+					list_del ( &pre->list );
+				/* Update total free memory */
+				freemem -= size;
+				/* Return allocated block */
+				DBG ( "Allocated [%p,%p)\n", block,
+				      ( ( ( void * ) block ) + size ) );
+				ptr = block;
+				goto done;
+			}
+		}
+
+		/* Try discarding some cached data to free up memory */
+		if ( ! discard_cache() ) {
+			/* Nothing available to discard */
+			DBG ( "Failed to allocate %#zx (aligned %#zx)\n",
+			      size, align );
+			ptr = NULL;
+			goto done;
+		}
+	}
+
+ done:
+	valgrind_make_blocks_noaccess();
+	return ptr;
+}
+
+/**
+ * Free a memory block
+ *
+ * @v ptr		Memory allocated by alloc_memblock(), or NULL
+ * @v size		Size of the memory
+ *
+ * If @c ptr is NULL, no action is taken.
+ */
+void free_memblock ( void *ptr, size_t size ) {
+	struct memory_block *freeing;
+	struct memory_block *block;
+	struct memory_block *tmp;
+	ssize_t gap_before;
+	ssize_t gap_after = -1;
+
+	/* Allow for ptr==NULL */
+	if ( ! ptr )
+		return;
+
+	valgrind_make_blocks_defined();
+
+	/* Round up size to match actual size that alloc_memblock()
+	 * would have used.
+	 */
+	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
+	freeing = ptr;
+	VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
+	freeing->size = size;
+	DBG ( "Freeing [%p,%p)\n", freeing, ( ( ( void * ) freeing ) + size ));
+
+	/* Insert/merge into free list */
+	list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
+		/* Calculate gaps before and after the "freeing" block */
+		gap_before = ( ( ( void * ) freeing ) - 
+			       ( ( ( void * ) block ) + block->size ) );
+		gap_after = ( ( ( void * ) block ) - 
+			      ( ( ( void * ) freeing ) + freeing->size ) );
+		/* Merge with immediately preceding block, if possible */
+		if ( gap_before == 0 ) {
+			DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", block,
+			      ( ( ( void * ) block ) + block->size ), freeing,
+			      ( ( ( void * ) freeing ) + freeing->size ),block,
+			      ( ( ( void * ) freeing ) + freeing->size ) );
+			block->size += size;
+			list_del ( &block->list );
+			freeing = block;
+		}
+		/* Stop processing as soon as we reach a following block */
+		if ( gap_after >= 0 )
+			break;
+	}
+
+	/* Insert before the immediately following block.  If
+	 * possible, merge the following block into the "freeing"
+	 * block.
+	 */
+	DBG ( "[%p,%p)\n", freeing, ( ( ( void * ) freeing ) + freeing->size));
+	list_add_tail ( &freeing->list, &block->list );
+	if ( gap_after == 0 ) {
+		DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", freeing,
+		      ( ( ( void * ) freeing ) + freeing->size ), block,
+		      ( ( ( void * ) block ) + block->size ), freeing,
+		      ( ( ( void * ) block ) + block->size ) );
+		freeing->size += block->size;
+		list_del ( &block->list );
+	}
+
+	/* Update free memory counter */
+	freemem += size;
+
+	valgrind_make_blocks_noaccess();
+}
+
+/**
+ * Reallocate memory
+ *
+ * @v old_ptr		Memory previously allocated by malloc(), or NULL
+ * @v new_size		Requested size
+ * @ret new_ptr		Allocated memory, or NULL
+ *
+ * Allocates memory with no particular alignment requirement.  @c
+ * new_ptr will be aligned to at least a multiple of sizeof(void*).
+ * If @c old_ptr is non-NULL, then the contents of the newly allocated
+ * memory will be the same as the contents of the previously allocated
+ * memory, up to the minimum of the old and new sizes.  The old memory
+ * will be freed.
+ *
+ * If allocation fails the previously allocated block is left
+ * untouched and NULL is returned.
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+void * realloc ( void *old_ptr, size_t new_size ) {
+	struct autosized_block *old_block;
+	struct autosized_block *new_block;
+	size_t old_total_size;
+	size_t new_total_size;
+	size_t old_size;
+	void *new_ptr = NOWHERE;
+
+	/* Allocate new memory if necessary.  If allocation fails,
+	 * return without touching the old block.
+	 */
+	if ( new_size ) {
+		new_total_size = ( new_size +
+				   offsetof ( struct autosized_block, data ) );
+		new_block = alloc_memblock ( new_total_size, 1 );
+		if ( ! new_block )
+			return NULL;
+		VALGRIND_MAKE_MEM_UNDEFINED ( new_block, offsetof ( struct autosized_block, data ) );
+		new_block->size = new_total_size;
+		VALGRIND_MAKE_MEM_NOACCESS ( new_block, offsetof ( struct autosized_block, data ) );
+		new_ptr = &new_block->data;
+		VALGRIND_MALLOCLIKE_BLOCK ( new_ptr, new_size, 0, 0 );
+	}
+	
+	/* Copy across relevant part of the old data region (if any),
+	 * then free it.  Note that at this point either (a) new_ptr
+	 * is valid, or (b) new_size is 0; either way, the memcpy() is
+	 * valid.
+	 */
+	if ( old_ptr && ( old_ptr != NOWHERE ) ) {
+		old_block = container_of ( old_ptr, struct autosized_block,
+					   data );
+		VALGRIND_MAKE_MEM_DEFINED ( old_block, offsetof ( struct autosized_block, data ) );
+		old_total_size = old_block->size;
+		old_size = ( old_total_size -
+			     offsetof ( struct autosized_block, data ) );
+		memcpy ( new_ptr, old_ptr,
+			 ( ( old_size < new_size ) ? old_size : new_size ) );
+		free_memblock ( old_block, old_total_size );
+		VALGRIND_MAKE_MEM_NOACCESS ( old_block, offsetof ( struct autosized_block, data ) );
+		VALGRIND_FREELIKE_BLOCK ( old_ptr, 0 );
+	}
+
+	return new_ptr;
+}
+
+/**
+ * Allocate memory
+ *
+ * @v size		Requested size
+ * @ret ptr		Memory, or NULL
+ *
+ * Allocates memory with no particular alignment requirement.  @c ptr
+ * will be aligned to at least a multiple of sizeof(void*).
+ */
+void * malloc ( size_t size ) {
+	return realloc ( NULL, size );
+}
+
+/**
+ * Free memory
+ *
+ * @v ptr		Memory allocated by malloc(), or NULL
+ *
+ * Memory allocated with malloc_dma() cannot be freed with free(); it
+ * must be freed with free_dma() instead.
+ *
+ * If @c ptr is NULL, no action is taken.
+ */
+void free ( void *ptr ) {
+	realloc ( ptr, 0 );
+}
+
+/**
+ * Allocate cleared memory
+ *
+ * @v size		Requested size
+ * @ret ptr		Allocated memory
+ *
+ * Allocate memory as per malloc(), and zero it.
+ *
+ * This function name is non-standard, but pretty intuitive.
+ * zalloc(size) is always equivalent to calloc(1,size)
+ */
+void * zalloc ( size_t size ) {
+	void *data;
+
+	data = malloc ( size );
+	if ( data )
+		memset ( data, 0, size );
+	return data;
+}
+
+/**
+ * Add memory to allocation pool
+ *
+ * @v start		Start address
+ * @v end		End address
+ *
+ * Adds a block of memory [start,end) to the allocation pool.  This is
+ * a one-way operation; there is no way to reclaim this memory.
+ *
+ * @c start must be aligned to at least a multiple of sizeof(void*).
+ */
+void mpopulate ( void *start, size_t len ) {
+	/* Prevent free_memblock() from rounding up len beyond the end
+	 * of what we were actually given...
+	 */
+	free_memblock ( start, ( len & ~( MIN_MEMBLOCK_SIZE - 1 ) ) );
+}
+
+/**
+ * Initialise the heap
+ *
+ */
+static void init_heap ( void ) {
+	VALGRIND_MAKE_MEM_NOACCESS ( heap, sizeof ( heap ) );
+	mpopulate ( heap, sizeof ( heap ) );
+}
+
+/** Memory allocator initialisation function */
+struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = {
+	.initialise = init_heap,
+};
+
+#if 0
+#include <stdio.h>
+/**
+ * Dump free block list
+ *
+ */
+void mdumpfree ( void ) {
+	struct memory_block *block;
+
+	printf ( "Free block list:\n" );
+	list_for_each_entry ( block, &free_blocks, list ) {
+		printf ( "[%p,%p] (size %#zx)\n", block,
+			 ( ( ( void * ) block ) + block->size ), block->size );
+	}
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/core/misc.c b/qemu-0.15.x/roms/ipxe/src/core/misc.c
new file mode 100644
index 0000000..8f56e1f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/misc.c
@@ -0,0 +1,60 @@
+/**************************************************************************
+MISC Support Routines
+**************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <byteswap.h>
+#include <ipxe/in.h>
+#include <ipxe/timer.h>
+
+/**************************************************************************
+INET_ATON - Convert an ascii x.x.x.x to binary form
+**************************************************************************/
+int inet_aton ( const char *cp, struct in_addr *inp ) {
+	const char *p = cp;
+	const char *digits_start;
+	unsigned long ip = 0;
+	unsigned long val;
+	int j;
+	for(j = 0; j <= 3; j++) {
+		digits_start = p;
+		val = strtoul(p, ( char ** ) &p, 10);
+		if ((p == digits_start) || (val > 255)) return 0;
+		if ( ( j < 3 ) && ( *(p++) != '.' ) ) return 0;
+		ip = (ip << 8) | val;
+	}
+	if ( *p == '\0' ) {
+		inp->s_addr = htonl(ip);
+		return 1;
+	}
+	return 0;
+}
+
+unsigned long strtoul ( const char *p, char **endp, int base ) {
+	unsigned long ret = 0;
+	unsigned int charval;
+
+	base = strtoul_base ( &p, base );
+
+	while ( 1 ) {
+		charval = strtoul_charval ( *p );
+		if ( charval >= ( unsigned int ) base )
+			break;
+		ret = ( ( ret * base ) + charval );
+		p++;
+	}
+
+	if ( endp )
+		*endp = ( char * ) p;
+
+	return ( ret );
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/core/monojob.c b/qemu-0.15.x/roms/ipxe/src/core/monojob.c
new file mode 100644
index 0000000..7431f88
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/monojob.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/process.h>
+#include <ipxe/console.h>
+#include <ipxe/keys.h>
+#include <ipxe/job.h>
+#include <ipxe/monojob.h>
+#include <ipxe/timer.h>
+
+/** @file
+ *
+ * Single foreground job
+ *
+ */
+
+static int monojob_rc;
+
+static void monojob_close ( struct interface *intf, int rc ) {
+	monojob_rc = rc;
+	intf_restart ( intf, rc );
+}
+
+static struct interface_operation monojob_intf_op[] = {
+	INTF_OP ( intf_close, struct interface *, monojob_close ),
+};
+
+static struct interface_descriptor monojob_intf_desc =
+	INTF_DESC_PURE ( monojob_intf_op );
+
+struct interface monojob = INTF_INIT ( monojob_intf_desc );
+
+/**
+ * Wait for single foreground job to complete
+ *
+ * @v string		Job description to display
+ * @ret rc		Job final status code
+ */
+int monojob_wait ( const char *string ) {
+	struct job_progress progress;
+	int key;
+	int rc;
+	unsigned long last_progress;
+	unsigned long elapsed;
+	unsigned long completed;
+	unsigned long total;
+	unsigned int percentage;
+	int shown_percentage = 0;
+
+	printf ( "%s...", string );
+	monojob_rc = -EINPROGRESS;
+	last_progress = currticks();
+	while ( monojob_rc == -EINPROGRESS ) {
+		step();
+		if ( iskey() ) {
+			key = getchar();
+			switch ( key ) {
+			case CTRL_C:
+				monojob_close ( &monojob, -ECANCELED );
+				break;
+			default:
+				break;
+			}
+		}
+		elapsed = ( currticks() - last_progress );
+		if ( elapsed >= TICKS_PER_SEC ) {
+			if ( shown_percentage )
+				printf ( "\b\b\b\b    \b\b\b\b" );
+			job_progress ( &monojob, &progress );
+			/* Normalise progress figures to avoid overflow */
+			completed = ( progress.completed / 128 );
+			total = ( progress.total / 128 );
+			if ( total ) {
+				percentage = ( ( 100 * completed ) / total );
+				printf ( "%3d%%", percentage );
+				shown_percentage = 1;
+			} else {
+				printf ( "." );
+				shown_percentage = 0;
+			}
+			last_progress = currticks();
+		}
+	}
+	rc = monojob_rc;
+
+	if ( shown_percentage )
+		printf ( "\b\b\b\b    \b\b\b\b" );
+
+	if ( rc ) {
+		printf ( " %s\n", strerror ( rc ) );
+	} else {
+		printf ( " ok\n" );
+	}
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/null_nap.c b/qemu-0.15.x/roms/ipxe/src/core/null_nap.c
new file mode 100644
index 0000000..c886f54
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/null_nap.c
@@ -0,0 +1,3 @@
+#include <ipxe/nap.h>
+
+PROVIDE_NAP_INLINE ( null, cpu_nap );
diff --git a/qemu-0.15.x/roms/ipxe/src/core/null_sanboot.c b/qemu-0.15.x/roms/ipxe/src/core/null_sanboot.c
new file mode 100644
index 0000000..9cdb162
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/null_sanboot.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/sanboot.h>
+
+static int null_san_hook ( struct uri *uri __unused,
+			   unsigned int drive __unused ) {
+	return -EOPNOTSUPP;
+}
+
+static void null_san_unhook ( unsigned int drive __unused ) {
+	/* Do nothing */
+}
+
+static int null_san_boot ( unsigned int drive __unused ) {
+	return -EOPNOTSUPP;
+}
+
+static int null_san_describe ( unsigned int drive __unused ) {
+	return -EOPNOTSUPP;
+}
+
+PROVIDE_SANBOOT ( null, san_hook, null_san_hook );
+PROVIDE_SANBOOT ( null, san_unhook, null_san_unhook );
+PROVIDE_SANBOOT ( null, san_boot, null_san_boot );
+PROVIDE_SANBOOT ( null, san_describe, null_san_describe );
diff --git a/qemu-0.15.x/roms/ipxe/src/core/nvo.c b/qemu-0.15.x/roms/ipxe/src/core/nvo.c
new file mode 100644
index 0000000..ea58bad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/nvo.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/nvs.h>
+#include <ipxe/nvo.h>
+
+/** @file
+ *
+ * Non-volatile stored options
+ *
+ */
+
+/**
+ * Calculate checksum over non-volatile stored options
+ *
+ * @v nvo		Non-volatile options block
+ * @ret sum		Checksum
+ */
+static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
+	uint8_t *data = nvo->data;
+	uint8_t sum = 0;
+	unsigned int i;
+
+	for ( i = 0 ; i < nvo->len ; i++ ) {
+		sum += *(data++);
+	}
+	return sum;
+}
+
+/**
+ * Reallocate non-volatile stored options block
+ *
+ * @v nvo		Non-volatile options block
+ * @v len		New length
+ * @ret rc		Return status code
+ */
+static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
+	void *new_data;
+
+	/* Reallocate data */
+	new_data = realloc ( nvo->data, len );
+	if ( ! new_data ) {
+		DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
+		       nvo, len );
+		return -ENOMEM;
+	}
+	nvo->data = new_data;
+	nvo->len = len;
+
+	/* Update DHCP option block */
+	if ( len ) {
+		nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
+		nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
+	} else {
+		nvo->dhcpopts.data = NULL;
+		nvo->dhcpopts.used_len = 0;
+		nvo->dhcpopts.alloc_len = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Reallocate non-volatile stored options DHCP option block
+ *
+ * @v options		DHCP option block
+ * @v len		New length
+ * @ret rc		Return status code
+ */
+static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
+	struct nvo_block *nvo =
+		container_of ( options, struct nvo_block, dhcpopts );
+	int rc;
+
+	/* Refuse to reallocate if we have no way to resize the block */
+	if ( ! nvo->resize )
+		return dhcpopt_no_realloc ( options, len );
+
+	/* Allow one byte for the checksum (if any data is present) */
+	if ( len )
+		len += 1;
+
+	/* Resize underlying non-volatile options block */
+	if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
+		DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
+		       nvo, len, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Reallocate in-memory options block */
+	if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Load non-volatile stored options from non-volatile storage device
+ *
+ * @v nvo		Non-volatile options block
+ * @ret rc		Return status code
+ */
+static int nvo_load ( struct nvo_block *nvo ) {
+	uint8_t *options_data = nvo->dhcpopts.data;
+	int rc;
+
+	/* Skip reading zero-length NVO fields */
+	if ( nvo->len == 0 ) {
+		DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
+		return 0;
+	}
+
+	/* Read data */
+	if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
+			       nvo->len ) ) != 0 ) {
+		DBGC ( nvo, "NVO %p could not read %zd bytes at %#04x: %s\n",
+		       nvo, nvo->len, nvo->address, strerror ( rc ) );
+		return rc;
+	}
+
+	/* If checksum fails, or options data starts with a zero,
+	 * assume the whole block is invalid.  This should capture the
+	 * case of random initial contents.
+	 */
+	if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
+		DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
+		       "assuming empty\n", nvo, nvo_checksum ( nvo ),
+		       options_data[0] );
+		memset ( nvo->data, 0, nvo->len );
+	}
+
+	/* Rescan DHCP option block */
+	dhcpopt_update_used_len ( &nvo->dhcpopts );
+
+	DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
+	return 0;
+}
+
+/**
+ * Save non-volatile stored options back to non-volatile storage device
+ *
+ * @v nvo		Non-volatile options block
+ * @ret rc		Return status code
+ */
+static int nvo_save ( struct nvo_block *nvo ) {
+	uint8_t *checksum = nvo->data;
+	int rc;
+
+	/* Recalculate checksum, if applicable */
+	if ( nvo->len > 0 )
+		*checksum -= nvo_checksum ( nvo );
+
+	/* Write data */
+	if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
+				nvo->len ) ) != 0 ) {
+		DBGC ( nvo, "NVO %p could not write %zd bytes at %#04x: %s\n",
+		       nvo, nvo->len, nvo->address, strerror ( rc ) );
+		return rc;
+	}
+
+	DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo );
+	return 0;
+}
+
+/**
+ * Check applicability of NVO setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int nvo_applies ( struct settings *settings __unused,
+			 struct setting *setting ) {
+
+	return dhcpopt_applies ( setting->tag );
+}
+
+/**
+ * Store value of NVO setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int nvo_store ( struct settings *settings, struct setting *setting,
+		       const void *data, size_t len ) {
+	struct nvo_block *nvo =
+		container_of ( settings, struct nvo_block, settings );
+	int rc;
+
+	/* Update stored options */
+	if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag,
+				    data, len ) ) != 0 ) {
+		DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n",
+		       nvo, len, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Save updated options to NVS */
+	if ( ( rc = nvo_save ( nvo ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Fetch value of NVO setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ *
+ * The actual length of the setting will be returned even if
+ * the buffer was too small.
+ */
+static int nvo_fetch ( struct settings *settings, struct setting *setting,
+		       void *data, size_t len ) {
+	struct nvo_block *nvo =
+		container_of ( settings, struct nvo_block, settings );
+
+	return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len );
+}
+
+/** NVO settings operations */
+static struct settings_operations nvo_settings_operations = {
+	.applies = nvo_applies,
+	.store = nvo_store,
+	.fetch = nvo_fetch,
+};
+
+/**
+ * Initialise non-volatile stored options
+ *
+ * @v nvo		Non-volatile options block
+ * @v nvs		Underlying non-volatile storage device
+ * @v address		Address within NVS device
+ * @v len		Length of non-volatile options data
+ * @v resize		Resize method
+ * @v refcnt		Containing object reference counter, or NULL
+ */
+void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
+		size_t address, size_t len,
+		int ( * resize ) ( struct nvo_block *nvo, size_t len ),
+		struct refcnt *refcnt ) {
+	nvo->nvs = nvs;
+	nvo->address = address;
+	nvo->len = len;
+	nvo->resize = resize;
+	dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt );
+	settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 );
+}
+
+/**
+ * Register non-volatile stored options
+ *
+ * @v nvo		Non-volatile options block
+ * @v parent		Parent settings block, or NULL
+ * @ret rc		Return status code
+ */
+int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
+	int rc;
+
+	/* Allocate memory for options */
+	if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
+		goto err_realloc;
+
+	/* Read data from NVS */
+	if ( ( rc = nvo_load ( nvo ) ) != 0 )
+		goto err_load;
+
+	/* Register settings */
+	if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
+		goto err_register;
+
+	DBGC ( nvo, "NVO %p registered\n", nvo );
+	return 0;
+	
+ err_register:
+ err_load:
+	nvo_realloc ( nvo, 0 );
+ err_realloc:
+	return rc;
+}
+
+/**
+ * Unregister non-volatile stored options
+ *
+ * @v nvo		Non-volatile options block
+ */
+void unregister_nvo ( struct nvo_block *nvo ) {
+	unregister_settings ( &nvo->settings );
+	nvo_realloc ( nvo, 0 );
+	DBGC ( nvo, "NVO %p unregistered\n", nvo );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/open.c b/qemu-0.15.x/roms/ipxe/src/core/open.c
new file mode 100644
index 0000000..b026efc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/open.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/xfer.h>
+#include <ipxe/uri.h>
+#include <ipxe/socket.h>
+#include <ipxe/open.h>
+
+/** @file
+ *
+ * Data transfer interface opening
+ *
+ */
+
+/**
+ * Find opener for URI scheme
+ *
+ * @v scheme		URI scheme
+ * @ret opener		Opener, or NULL
+ */
+struct uri_opener * xfer_uri_opener ( const char *scheme ) {
+	struct uri_opener *opener;
+
+	for_each_table_entry ( opener, URI_OPENERS ) {
+		if ( strcmp ( scheme, opener->scheme ) == 0 )
+			return opener;
+	}
+	return NULL;
+}
+
+/**
+ * Open URI
+ *
+ * @v intf		Data transfer interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ *
+ * The URI will be regarded as being relative to the current working
+ * URI (see churi()).
+ */
+int xfer_open_uri ( struct interface *intf, struct uri *uri ) {
+	struct uri_opener *opener;
+	struct uri *resolved_uri;
+	int rc;
+
+	/* Resolve URI */
+	resolved_uri = resolve_uri ( cwuri, uri );
+	if ( ! resolved_uri ) {
+		rc = -ENOMEM;
+		goto err_resolve_uri;
+	}
+
+	/* Find opener which supports this URI scheme */
+	opener = xfer_uri_opener ( resolved_uri->scheme );
+	if ( ! opener ) {
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
+		       "unsupported URI scheme \"%s\"\n",
+		       INTF_DBG ( intf ), resolved_uri->scheme );
+		rc = -ENOTSUP;
+		goto err_opener;
+	}
+
+	/* Call opener */
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening %s URI\n",
+	       INTF_DBG ( intf ), resolved_uri->scheme );
+	if ( ( rc = opener->open ( intf, resolved_uri ) ) != 0 ) {
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " could not open: "
+		       "%s\n", INTF_DBG ( intf ), strerror ( rc ) );
+		goto err_open;
+	}
+
+ err_open:
+ err_opener:
+	uri_put ( resolved_uri );
+ err_resolve_uri:
+	return rc;
+}
+
+/**
+ * Open URI string
+ *
+ * @v intf		Data transfer interface
+ * @v uri_string	URI string (e.g. "http://ipxe.org/kernel")
+ * @ret rc		Return status code
+ *
+ * The URI will be regarded as being relative to the current working
+ * URI (see churi()).
+ */
+int xfer_open_uri_string ( struct interface *intf,
+			   const char *uri_string ) {
+	struct uri *uri;
+	int rc;
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening URI %s\n",
+	       INTF_DBG ( intf ), uri_string );
+
+	uri = parse_uri ( uri_string );
+	if ( ! uri )
+		return -ENOMEM;
+
+	rc = xfer_open_uri ( intf, uri );
+
+	uri_put ( uri );
+	return rc;
+}
+
+/**
+ * Open socket
+ *
+ * @v intf		Data transfer interface
+ * @v semantics		Communication semantics (e.g. SOCK_STREAM)
+ * @v peer		Peer socket address
+ * @v local		Local socket address, or NULL
+ * @ret rc		Return status code
+ */
+int xfer_open_socket ( struct interface *intf, int semantics,
+		       struct sockaddr *peer, struct sockaddr *local ) {
+	struct socket_opener *opener;
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening (%s,%s) socket\n",
+	       INTF_DBG ( intf ), socket_semantics_name ( semantics ),
+	       socket_family_name ( peer->sa_family ) );
+
+	for_each_table_entry ( opener, SOCKET_OPENERS ) {
+		if ( ( opener->semantics == semantics ) &&
+		     ( opener->family == peer->sa_family ) ) {
+			return opener->open ( intf, peer, local );
+		}
+	}
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
+	       "unsupported socket type (%s,%s)\n",
+	       INTF_DBG ( intf ), socket_semantics_name ( semantics ),
+	       socket_family_name ( peer->sa_family ) );
+	return -ENOTSUP;
+}
+
+/**
+ * Open location
+ *
+ * @v intf		Data transfer interface
+ * @v type		Location type
+ * @v args		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ */
+int xfer_vopen ( struct interface *intf, int type, va_list args ) {
+	switch ( type ) {
+	case LOCATION_URI_STRING: {
+		const char *uri_string = va_arg ( args, const char * );
+
+		return xfer_open_uri_string ( intf, uri_string ); }
+	case LOCATION_URI: {
+		struct uri *uri = va_arg ( args, struct uri * );
+
+		return xfer_open_uri ( intf, uri ); }
+	case LOCATION_SOCKET: {
+		int semantics = va_arg ( args, int );
+		struct sockaddr *peer = va_arg ( args, struct sockaddr * );
+		struct sockaddr *local = va_arg ( args, struct sockaddr * );
+
+		return xfer_open_socket ( intf, semantics, peer, local ); }
+	default:
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to "
+		       "open unsupported location type %d\n",
+		       INTF_DBG ( intf ), type );
+		return -ENOTSUP;
+	}
+}
+
+/**
+ * Open location
+ *
+ * @v intf		Data transfer interface
+ * @v type		Location type
+ * @v ...		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ */
+int xfer_open ( struct interface *intf, int type, ... ) {
+	va_list args;
+	int rc;
+
+	va_start ( args, type );
+	rc = xfer_vopen ( intf, type, args );
+	va_end ( args );
+	return rc;
+}
+
+/**
+ * Reopen location
+ *
+ * @v intf		Data transfer interface
+ * @v type		Location type
+ * @v args		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ *
+ * This will close the existing connection and open a new connection
+ * using xfer_vopen().  It is intended to be used as a .vredirect
+ * method handler.
+ */
+int xfer_vreopen ( struct interface *intf, int type, va_list args ) {
+
+	/* Close existing connection */
+	intf_restart ( intf, 0 );
+
+	/* Open new location */
+	return xfer_vopen ( intf, type, args );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/parseopt.c b/qemu-0.15.x/roms/ipxe/src/core/parseopt.c
new file mode 100644
index 0000000..24a5762
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/parseopt.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/image.h>
+#include <ipxe/parseopt.h>
+
+/** @file
+ *
+ * Command line option parsing
+ *
+ */
+
+/** Return status code for "--help" option */
+#define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
+#define EINFO_ECANCELED_NO_OP \
+	__einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
+
+/**
+* Parse string value
+ *
+ * @v text		Text
+ * @ret value		String value
+ * @ret rc		Return status code
+ */
+int parse_string ( const char *text, const char **value ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Parse string */
+	*value = text;
+
+	return 0;
+}
+
+/**
+ * Parse integer value
+ *
+ * @v text		Text
+ * @ret value		Integer value
+ * @ret rc		Return status code
+ */
+int parse_integer ( const char *text, unsigned int *value ) {
+	char *endp;
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Parse integer */
+	*value = strtoul ( text, &endp, 0 );
+	if ( *endp ) {
+		printf ( "\"%s\": invalid integer value\n", text );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse network device name
+ *
+ * @v text		Text
+ * @ret netdev		Network device
+ * @ret rc		Return status code
+ */
+int parse_netdev ( const char *text, struct net_device **netdev ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Find network device */
+	*netdev = find_netdev ( text );
+	if ( ! *netdev ) {
+		printf ( "\"%s\": no such network device\n", text );
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse image name
+ *
+ * @v text		Text
+ * @ret image		Image
+ * @ret rc		Return status code
+ */
+int parse_image ( const char *text, struct image **image ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Find network device */
+	*image = find_image ( text );
+	if ( ! *image ) {
+		printf ( "\"%s\": no such image\n", text );
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse flag
+ *
+ * @v text		Text (ignored)
+ * @ret flag		Flag to set
+ * @ret rc		Return status code
+ */
+int parse_flag ( const char *text __unused, int *flag ) {
+
+	/* Set flag */
+	*flag = 1;
+
+	return 0;
+}
+
+/**
+ * Print command usage message
+ *
+ * @v cmd		Command descriptor
+ * @v argv		Argument list
+ */
+void print_usage ( struct command_descriptor *cmd, char **argv ) {
+	printf ( "Usage:\n\n  %s %s\n\nSee http://ipxe.org/cmd/%s for further "
+		 "information\n", argv[0], cmd->usage, argv[0] );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v cmd		Command descriptor
+ * @v opts		Options
+ * @ret rc		Return status code
+ */
+int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
+		    void *opts ) {
+	struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
+	char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
+			+ 1 /* NUL */ ];
+	unsigned int shortopt_idx = 0;
+	int ( * parse ) ( const char *text, void *value );
+	void *value;
+	unsigned int i;
+	unsigned int j;
+	unsigned int num_args;
+	int c;
+	int rc;
+
+	/* Construct long and short option lists for getopt_long() */
+	memset ( longopts, 0, sizeof ( longopts ) );
+	for ( i = 0 ; i < cmd->num_options ; i++ ) {
+		longopts[i].name = cmd->options[i].longopt;
+		longopts[i].has_arg = cmd->options[i].has_arg;
+		longopts[i].val = cmd->options[i].shortopt;
+		shortopts[shortopt_idx++] = cmd->options[i].shortopt;
+		assert ( cmd->options[i].has_arg <= optional_argument );
+		for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
+			shortopts[shortopt_idx++] = ':';
+	}
+	longopts[i].name = "help";
+	longopts[i].val = 'h';
+	shortopts[shortopt_idx++] = 'h';
+	shortopts[shortopt_idx++] = '\0';
+	assert ( shortopt_idx <= sizeof ( shortopts ) );
+	DBGC ( cmd,  "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
+	       argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
+
+	/* Clear options */
+	memset ( opts, 0, cmd->len );
+
+	/* Parse options */
+	while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
+				    NULL ) ) >= 0 ) {
+		switch ( c ) {
+		case 'h' :
+			/* Print help */
+			print_usage ( cmd, argv );
+			return -ECANCELED_NO_OP;
+		case '?' :
+		case ':' :
+			/* Print usage message */
+			print_usage ( cmd, argv );
+			return -EINVAL;
+		default:
+			/* Search for an option to parse */
+			for ( i = 0 ; i < cmd->num_options ; i++ ) {
+				if ( c != cmd->options[i].shortopt )
+					continue;
+				parse = cmd->options[i].parse;
+				value = ( opts + cmd->options[i].offset );
+				if ( ( rc = parse ( optarg, value ) ) != 0 )
+					return rc;
+				break;
+			}
+			assert ( i < cmd->num_options );
+		}
+	}
+
+	/* Check remaining arguments */
+	num_args = ( argc - optind );
+	if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
+		print_usage ( cmd, argv );
+		return -ERANGE;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/pc_kbd.c b/qemu-0.15.x/roms/ipxe/src/core/pc_kbd.c
new file mode 100644
index 0000000..42df755
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/pc_kbd.c
@@ -0,0 +1,112 @@
+/* Minimal polling PC keyboard driver
+ * - No interrupt
+ * - No LED
+ * - No special keys
+ *
+ * still Enough For Me to type a filename.
+ *
+ * 2003-07 by SONE Takesh
+ * 2004-04 moved by LYH From filo to Etherboot
+ *		yhlu at tyan.com
+ */
+
+#include <ipxe/io.h>
+#include <ipxe/console.h>
+
+static char key_map[][128] = {
+    {
+	"\0\x1b""1234567890-=\b\t"
+	"qwertyuiop[]\r\0as"
+	"dfghjkl;'`\0\\zxcv"
+	"bnm,./\0*\0 \0\0\0\0\0\0"
+	"\0\0\0\0\0\0\0""789-456+1"
+	"230."
+    },{
+	"\0\x1b""!@#$%^&*()_+\b\t"
+	"QWERTYUIOP{}\r\0AS"
+	"DFGHJKL:\"~\0|ZXCV"
+	"BNM<>?\0\0\0 \0\0\0\0\0\0"
+	"\0\0\0\0\0\0\0""789-456+1"
+	"230."
+    }
+};
+
+static int cur_scan;
+static unsigned int shift_state;
+#define SHIFT 1
+#define CONTROL 2
+#define CAPS 4
+
+static int get_scancode(void)
+{
+    int scan;
+
+    if ((inb(0x64) & 1) == 0)
+	return 0;
+    scan = inb(0x60);
+
+    switch (scan) {
+    case 0x2a:
+    case 0x36:
+	shift_state |= SHIFT;
+	break;
+    case 0xaa:
+    case 0xb6:
+	shift_state &= ~SHIFT;
+	break;
+    case 0x1d:
+	shift_state |= CONTROL;
+	break;
+    case 0x9d:
+	shift_state &= ~CONTROL;
+	break;
+    case 0x3a:
+	shift_state ^= CAPS;
+	break;
+    }
+
+    if (scan & 0x80)
+	return 0; /* ignore break code or 0xe0 etc! */
+    return scan;
+}
+
+static int kbd_havekey(void)
+{
+    if (!cur_scan)
+	cur_scan = get_scancode();
+    return cur_scan != 0;
+}
+
+static int kbd_ischar(void)
+{
+    if (!kbd_havekey())
+	return 0;
+    if (!key_map[shift_state & SHIFT][cur_scan]) {
+	cur_scan = 0;
+	return 0;
+    }
+    return 1;
+}
+
+static int kbd_getc(void)
+{
+    int c;
+
+    while (!kbd_ischar())
+	;
+    c = key_map[shift_state & SHIFT][cur_scan];
+    if (shift_state & (CONTROL | CAPS)) {
+	if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+	    if (shift_state & CONTROL)
+		c &= 0x1f;
+	    else if (shift_state & CAPS)
+		c ^= ('A' ^ 'a');
+	}
+    }
+    cur_scan = 0;
+    return c;
+}
+
+struct console_driver pc_kbd_console __console_driver = {
+	.getchar = kbd_getc,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/pcmcia.c b/qemu-0.15.x/roms/ipxe/src/core/pcmcia.c
new file mode 100644
index 0000000..2d8ceb6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/pcmcia.c
@@ -0,0 +1,270 @@
+#if 0
+
+/*
+ *	pcmcia.c
+ *
+ *	PCMCIA support routines for etherboot - generic stuff
+ *
+ *	This code has partly be taken from the linux kernel sources, .../drivers/pcmcia/
+ *	Started & put together by
+ *		Anselm Martin Hoffmeister
+ *		Stockholm Projekt Computer-Service
+ *		Sankt Augustin / Bonn, Germany
+ *
+ *	Distributed under GPL2
+ */
+
+/*
+ *
+ *
+ *			******************************
+ *			PLEASE DO NOT YET WORK ON THIS
+ *			******************************
+ *
+ *	I'm still fixing it up on every end, so we most probably would interfere
+ *	at some point. If there's anything obvious or better, not-so-obvious,
+ *	please contact me by e-mail: anselm (AT) hoffmeister (DOT) be   *THANKS*
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stdio.h>
+#include <pcmcia.h>
+#include <i82365.h>
+#define CODE_STATUS "alpha"
+#define	CODE_VERSION "0.1.3"
+#include <pcmcia-opts.h>
+#include <ipxe/console.h>
+#include <ipxe/init.h>
+
+int	sockets; /* AHTODO: Phase this out! */
+u_int	pccsocks;
+struct	pccsock_t pccsock[MAXPCCSOCKS];
+int	inited = -1;
+struct	pcc_config_t pccconfig[MAXPCCCONFIGS];
+
+struct	driver_interact_t driver[] = {
+#ifdef	SUPPORT_I82365
+	{ I82365, i82365_interfacer, "Intel_82365" },
+#endif
+};
+
+#define	NUM_DRIVERS (sizeof(driver)/(sizeof(struct driver_interact_t)))
+
+void	sleepticks(int numticks ) {
+	u_int	tmo;
+	for (tmo = currticks()+numticks; currticks() < tmo; ) {
+        }
+	return;
+}
+
+static void pcmcia_init_all(void) {
+	u_int i, j, k, l, m, n, ui, configs = 0;
+	u_int multicard[8];
+	u_char	*uc, upc;
+	if ( PDEBUG > 0 ) printf("Initializing PCMCIA subsystem (code-status: " CODE_STATUS ", Version " CODE_VERSION ")\n");
+	if ( PDEBUG > 2 ) {
+		printf ( "Supporting %d driver(s): ", NUM_DRIVERS );
+		for ( i = 0; i < NUM_DRIVERS; ++i ) {
+			printf ( "[%s] ", driver[i].name );
+		}
+		printf ( "\n" );
+	}
+	pccsocks = 0;
+	sockets = 0;
+	// Init all drivers in the driver[] array:
+	for ( i = 0; i < NUM_DRIVERS; ++i ) {
+		driver[i].f(INIT,0,i,0,0);	// init needs no params. It uses pccsocks and pccsock[].
+						// Only i tells it which driver_id itself is.
+	}
+	for ( i = 0; i < pccsocks; ++i ) {
+		printf ( "Socket %d: ", i );
+		if ( pccsock[i].status != HASCARD ) {
+			printf ( "is %s: skipping\n", pccsock[i].status == EMPTY? "empty":"[status unknown]" );
+			continue;
+		}
+		if ( 0 != driver[pccsock[i].drivernum].f(MAPATTRMEM,pccsock[i].internalid,MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN,0 ) ) {
+			printf ("PCMCIA controller failed to map attribute memory.\n**** SEVERE ERROR CONDITION. Skipping controller.\n" );
+			if ( PDEBUG > 2 ) {
+				printf ( "<press key. THIS CONDITION SHOULD BE REPORTED!>\n" ); getchar();
+			}
+			continue;
+		}
+		// parse configuration information
+		uc = ioremap ( MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN );
+		pccsock[i].stringoffset = pccsock[i].configoffset = pccsock[i].stringlength = 0;
+		pccsock[i].type = 0xff;
+		for ( l = 0; l < 8; ++l ) multicard[l] = 0;
+		sleepticks(2);
+		for ( l = ui = 0; ui < 0x800; ui += uc[(2*ui)+2] + 2 ) {
+			if ( uc[(2*ui)] == 0xff ) {
+				break;
+			}
+			// This loop is complete rubbish AFAICS.
+			// But without it, my test system won't come up.
+			// It's too bad to develop on broken hardware
+			//				- Anselm
+		}
+		sleepticks(2);
+		configs = 0;
+		inited = -1;
+		for ( l = ui = 0; ui < 0x800; ui += uc[(2*ui)+2] + 2 ) {
+			if ( uc[(2*ui)] == 0xff ) break;
+			else if ( uc[2*ui] == 0x15 ) {
+				for ( k = 2 * ( ui + 2 ); ( uc[k] <= ' ' ) && ( k < ( 2 * ( uc[2*(ui+1)] + ui + 2 ) ) ) ; k += 2 ) { ; }
+				pccsock[i].stringoffset = k;
+				pccsock[i].stringlength = ( 2 * ( ui + 2 + uc[(2*ui)+2] ) - k ) / 2;
+			} else if ( uc[2*ui] == 0x21 ) {
+				pccsock[i].type = uc[(2*ui)+4];
+			} else if ( uc[2*ui] == 0x1a ) { // Configuration map
+				printf ( "\nConfig map 0x1a found [" );
+				for ( k = 0; k < uc[2*(ui+1)]; ++k ) {
+					printf ( "%02x ", uc[2*(ui+k+2)] );
+				}
+				printf ( "]\nHighest config available is %d\n", uc[2*(ui+3)] );
+				m = uc[2*(ui+2)];
+				pccsock[i].configoffset = 0;
+				for ( j = 0; j <= (m & 3); ++j ) {
+					pccsock[i].configoffset += uc[2*(ui+4+j)] << (8*j);
+				}
+				pccsock[i].rmask0 = 0;
+				for ( j = 0; j <= ( ( ( m & 0x3c ) >> 2 ) & 3 ); ++j ) {
+					pccsock[i].rmask0 += uc[2*(ui+5+(m&3)+j)] << (8*j);
+				}
+				j = pccsock[i].rmask0;
+				printf ( "Config offset is %x, card has regs: < %s%s%s%s%s>\n", pccsock[i].configoffset,
+					j & 1 ? "COR ":"", j & 2 ? "CCSR ":"", j & 4 ? "PRR ":"", j & 8 ? "SCR ":"", j & 16? "ESR ":"" );
+				printf ( "COR + CCSR contents (si/du) %x %x/%x %x\n", uc[pccsock[i].configoffset+0],
+					uc[pccsock[i].configoffset+2],uc[pccsock[i].configoffset*2],uc[(pccsock[i].configoffset*2)+2] );
+				printf ( "          " );
+			} else if ( uc[2*ui] == 0x1b ) { // Configuration data entry
+				//printf ( "Config data 0x1b found [\n" );getchar();
+				for ( k = 0; k < uc[2*(ui+1)]; ++k ) {
+				//	printf ( "%02x ", uc[2*(ui+k+2)] );
+				}
+				// Parse this tuple into pccconfig[configs]
+				// printf ( "]\n" );
+				if ( configs == MAXPCCCONFIGS ) continue;
+				k = 2*ui+4;
+				pccconfig[configs].index = uc[k] & 0x3f;
+				if ( uc[k] & 0x80 ) {
+				//	printf ( "Special config, unsupp. for now\n" );
+					continue;
+				}
+				k+=2;
+				// printf ( "Features: %2x\n", uc[k] );
+				if ( uc[k] & 0x7 ) {
+					// printf ( "Cannot work with Vcc/Timing configs right now\n" );
+					continue;
+				}
+				pccconfig[configs].iowin = pccconfig[configs].iolen = 0;
+				if ( 0 != ( uc[k] & 0x8 ) ) {
+					k+=2;
+					// printf ( "Reading IO config: " );
+					if ( 0 == ( uc[k] & 0x80 ) ) {
+					//	printf ( "Cannot work with auto/io config\n" );
+						continue;
+					}
+					k+=2;
+					if ( 0 != ( uc[k] & 0x0f ) ) {
+					//	printf ( "Don't support more than 1 iowin right now\n" );
+						continue;
+					}
+					j = (uc[k] & 0x30) >> 4;
+					m = (uc[k] & 0xc0) >> 6;
+					if ( 3 == j ) ++j;
+					if ( 3 == m ) ++m;
+					k += 2;
+					pccconfig[configs].iowin = 0;
+					pccconfig[configs].iolen = 1;
+					for ( n = 0; n < j; ++n, k+=2 ) {
+						pccconfig[configs].iowin += uc[k] << (n*8);
+					}
+					for ( n = 0; n < m; ++n, k+=2 ) {
+						pccconfig[configs].iolen += uc[k] << (n*8);
+					}
+					// printf ( "io %x len %d (%d)\n", pccconfig[configs].iowin, pccconfig[configs].iolen,configs );
+				}
+				for ( j = 0; j < (uc[k] & 3); ++j ) {
+				//	pccconfig[configs].iowin += (uc[k+(2*j)+2]) << (8*j);
+				}
+				++configs;
+			}
+		}
+		if ( pccsock[i].stringoffset > 0 ) {	// If no identifier, it's not a valid CIS (as of documentation...)
+			printf ( "[" );
+			for ( k = 0; ( k <  pccsock[i].stringlength ) && ( k < 64 ); ++k ) {
+				j = uc[pccsock[i].stringoffset + 2 * k];
+				printf ( "%c", (j>=' '? j:' ' ) );
+			}
+			printf ("]\n          is type %d (", pccsock[i].type );
+			switch ( pccsock[i].type ) {
+			  case	0x00:
+				printf ( "MULTI" ); break;
+			  case	0x01:
+				printf ( "Memory" ); break;
+			  case	0x02:
+				printf ( "Serial" ); break;
+			  case	0x03:
+				printf ( "Parallel" ); break;
+			  case	0x04:
+				printf ( "Fixed" ); break;
+			  case	0x05:
+				printf ( "Video" ); break;
+			  case	0x06:
+				printf ( "Network" ); break;
+			  case	0x07:
+				printf ( "AIMS" ); break;
+			  case	0x08:
+				printf ( "SCSI" ); break;
+			  case	0x106: // Special / homebrew to say "Multi/network"
+				printf ( "MULTI, with Network" ); break; // AHTODO find a card for this
+			  default:
+				printf ( "UNSUPPORTED/UNKNOWN" );
+			}
+			printf ( ") with %d possible configuration(s)\n", configs );
+			// Now set dependency: If it's Network or multi->network, accept
+			if ( (inited <= 0 ) && (6 == (0xff & pccsock[i].type) ) && (0 < configs ) ) {
+				printf ( "activating this device with ioport %x-%x (config #%d)\n", 
+				pccconfig[0].iowin, pccconfig[0].iowin+pccconfig[0].iolen-1, pccconfig[0].index );
+				inited = i;
+				// And unmap attrmem ourselves!
+				printf ( "Activating config..." );
+				if ( m=driver[pccsock[i].drivernum].f(SELECTCONFIG,pccsock[i].internalid,pccconfig[0].index,0,&pccconfig[0]) ) {
+					printf ("Failure(%d)!",m); inited = -1;
+		    			driver[pccsock[i].drivernum].f(UNMAPATTRMEM,pccsock[i].internalid,0,0,0);
+				}
+				printf ( "done!\n" );
+				continue;
+			}
+		} else {
+			printf ( "unsupported - no identifier string found in CIS\n" );
+		}
+		// unmap the PCMCIA device
+		if ( i != inited ) {
+		    if ( 0 != driver[pccsock[i].drivernum].f(UNMAPATTRMEM,pccsock[i].internalid,0,0,0) ) {
+			printf ("PCMCIA controller failed to unmap attribute memory.\n**** SEVERE ERROR CONDITION ****\n" );
+			if ( PDEBUG > 2 ) {
+				printf ( "<press key. THIS CONDITION SHOULD BE REPORTED!>\n" ); getchar();
+			}
+			continue;
+		    }
+		}
+	}
+	if ( PDEBUG > 2 ) {
+		printf ( "<press key to exit the pcmcia_init_all routine>\n" );
+		getchar();
+	}
+
+}
+
+static void	pcmcia_shutdown_all(void) {
+	int i;
+	//if ( PDEBUG > 2 ) {printf("<press key to continue>\n" ); getchar(); }
+	for ( i = 0; i < pccsocks; ++i ) {
+ 		driver[pccsock[i].drivernum].f(SHUTDOWN,pccsock[i].internalid,0,0,0);
+	}
+	printf("Shutdown of PCMCIA subsystem completed");
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/core/posix_io.c b/qemu-0.15.x/roms/ipxe/src/core/posix_io.c
new file mode 100644
index 0000000..38bd727
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/posix_io.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/list.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/process.h>
+#include <ipxe/posix_io.h>
+
+/** @file
+ *
+ * POSIX-like I/O
+ *
+ * These functions provide traditional blocking I/O semantics.  They
+ * are designed to be used by the PXE TFTP API.  Because they block,
+ * they may not be used by most other portions of the iPXE codebase.
+ */
+
+/** An open file */
+struct posix_file {
+	/** Reference count for this object */
+	struct refcnt refcnt;
+	/** List of open files */
+	struct list_head list;
+	/** File descriptor */
+	int fd;
+	/** Overall status
+	 *
+	 * Set to -EINPROGRESS while data transfer is in progress.
+	 */
+	int rc;
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Current seek position */
+	size_t pos;
+	/** File size */
+	size_t filesize;
+	/** Received data queue */
+	struct list_head data;
+};
+
+/** List of open files */
+static LIST_HEAD ( posix_files );
+
+/**
+ * Free open file
+ *
+ * @v refcnt		Reference counter
+ */
+static void posix_file_free ( struct refcnt *refcnt ) {
+	struct posix_file *file =
+		container_of ( refcnt, struct posix_file, refcnt );
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
+
+	list_for_each_entry_safe ( iobuf, tmp, &file->data, list ) {
+		list_del ( &iobuf->list );
+		free_iob ( iobuf );
+	}
+	free ( file );
+}
+
+/**
+ * Terminate file data transfer
+ *
+ * @v file		POSIX file
+ * @v rc		Reason for termination
+ */
+static void posix_file_finished ( struct posix_file *file, int rc ) {
+	intf_shutdown ( &file->xfer, rc );
+	file->rc = rc;
+}
+
+/**
+ * Handle deliver_iob() event
+ *
+ * @v file		POSIX file
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int posix_file_xfer_deliver ( struct posix_file *file,
+				     struct io_buffer *iobuf,
+				     struct xfer_metadata *meta ) {
+
+	/* Keep track of file position solely for the filesize */
+	if ( meta->flags & XFER_FL_ABS_OFFSET )
+		file->pos = 0;
+	file->pos += meta->offset;
+	if ( file->filesize < file->pos )
+		file->filesize = file->pos;
+
+	if ( iob_len ( iobuf ) ) {
+		list_add_tail ( &iobuf->list, &file->data );
+	} else {
+		free_iob ( iobuf );
+	}
+
+	return 0;
+}
+
+/** POSIX file data transfer interface operations */
+static struct interface_operation posix_file_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct posix_file *, posix_file_xfer_deliver ),
+	INTF_OP ( intf_close, struct posix_file *, posix_file_finished ),
+};
+
+/** POSIX file data transfer interface descriptor */
+static struct interface_descriptor posix_file_xfer_desc =
+	INTF_DESC ( struct posix_file, xfer, posix_file_xfer_operations );
+
+/**
+ * Identify file by file descriptor
+ *
+ * @v fd		File descriptor
+ * @ret file		Corresponding file, or NULL
+ */
+static struct posix_file * posix_fd_to_file ( int fd ) {
+	struct posix_file *file;
+
+	list_for_each_entry ( file, &posix_files, list ) {
+		if ( file->fd == fd )
+			return file;
+	}
+	return NULL;
+}
+
+/**
+ * Find an available file descriptor
+ *
+ * @ret fd		File descriptor, or negative error number
+ */
+static int posix_find_free_fd ( void ) {
+	int fd;
+
+	for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
+		if ( ! posix_fd_to_file ( fd ) )
+			return fd;
+	}
+	DBG ( "POSIX could not find free file descriptor\n" );
+	return -ENFILE;
+}
+
+/**
+ * Open file
+ *
+ * @v uri_string	URI string
+ * @ret fd		File descriptor, or negative error number
+ */
+int open ( const char *uri_string ) {
+	struct posix_file *file;
+	int fd;
+	int rc;
+
+	/* Find a free file descriptor to use */
+	fd = posix_find_free_fd();
+	if ( fd < 0 )
+		return fd;
+
+	/* Allocate and initialise structure */
+	file = zalloc ( sizeof ( *file ) );
+	if ( ! file )
+		return -ENOMEM;
+	ref_init ( &file->refcnt, posix_file_free );
+	file->fd = fd;
+	file->rc = -EINPROGRESS;
+	intf_init ( &file->xfer, &posix_file_xfer_desc, &file->refcnt );
+	INIT_LIST_HEAD ( &file->data );
+
+	/* Open URI on data transfer interface */
+	if ( ( rc = xfer_open_uri_string ( &file->xfer, uri_string ) ) != 0 )
+		goto err;
+
+	/* Wait for open to succeed or fail */
+	while ( list_empty ( &file->data ) ) {
+		step();
+		if ( file->rc == 0 )
+			break;
+		if ( file->rc != -EINPROGRESS ) {
+			rc = file->rc;
+			goto err;
+		}
+	}
+
+	/* Add to list of open files.  List takes reference ownership. */
+	list_add ( &file->list, &posix_files );
+	DBG ( "POSIX opened %s as file %d\n", uri_string, fd );
+	return fd;
+
+ err:
+	posix_file_finished ( file, rc );
+	ref_put ( &file->refcnt );
+	return rc;
+}
+
+/**
+ * Check file descriptors for readiness
+ *
+ * @v readfds		File descriptors to check
+ * @v wait		Wait until data is ready
+ * @ret nready		Number of ready file descriptors
+ */
+int select ( fd_set *readfds, int wait ) {
+	struct posix_file *file;
+	int fd;
+
+	do {
+		for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
+			if ( ! FD_ISSET ( fd, readfds ) )
+				continue;
+			file = posix_fd_to_file ( fd );
+			if ( ! file )
+				return -EBADF;
+			if ( ( list_empty ( &file->data ) ) &&
+			     ( file->rc == -EINPROGRESS ) )
+				continue;
+			/* Data is available or status has changed */
+			FD_ZERO ( readfds );
+			FD_SET ( fd, readfds );
+			return 1;
+		}
+		step();
+	} while ( wait );
+
+	return 0;
+}
+
+/**
+ * Read data from file
+ *
+ * @v buffer		Data buffer
+ * @v offset		Starting offset within data buffer
+ * @v len		Maximum length to read
+ * @ret len		Actual length read, or negative error number
+ *
+ * This call is non-blocking; if no data is available to read then
+ * -EWOULDBLOCK will be returned.
+ */
+ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
+	struct posix_file *file;
+	struct io_buffer *iobuf;
+	size_t len;
+
+	/* Identify file */
+	file = posix_fd_to_file ( fd );
+	if ( ! file )
+		return -EBADF;
+
+	/* Try to fetch more data if none available */
+	if ( list_empty ( &file->data ) )
+		step();
+
+	/* Dequeue at most one received I/O buffer into user buffer */
+	list_for_each_entry ( iobuf, &file->data, list ) {
+		len = iob_len ( iobuf );
+		if ( len > max_len )
+			len = max_len;
+		copy_to_user ( buffer, offset, iobuf->data, len );
+		iob_pull ( iobuf, len );
+		if ( ! iob_len ( iobuf ) ) {
+			list_del ( &iobuf->list );
+			free_iob ( iobuf );
+		}
+		file->pos += len;
+		assert ( len != 0 );
+		return len;
+	}
+
+	/* If file has completed, return (after returning all data) */
+	if ( file->rc != -EINPROGRESS ) {
+		assert ( list_empty ( &file->data ) );
+		return file->rc;
+	}
+
+	/* No data ready and file still in progress; return -WOULDBLOCK */
+	return -EWOULDBLOCK;
+}
+
+/**
+ * Determine file size
+ *
+ * @v fd		File descriptor
+ * @ret size		File size, or negative error number
+ */
+ssize_t fsize ( int fd ) {
+	struct posix_file *file;
+
+	/* Identify file */
+	file = posix_fd_to_file ( fd );
+	if ( ! file )
+		return -EBADF;
+
+	return file->filesize;
+}
+
+/**
+ * Close file
+ *
+ * @v fd		File descriptor
+ * @ret rc		Return status code
+ */
+int close ( int fd ) {
+	struct posix_file *file;
+
+	/* Identify file */
+	file = posix_fd_to_file ( fd );
+	if ( ! file )
+		return -EBADF;
+
+	/* Terminate data transfer */
+	posix_file_finished ( file, 0 );
+
+	/* Remove from list of open files and drop reference */
+	list_del ( &file->list );
+	ref_put ( &file->refcnt );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/process.c b/qemu-0.15.x/roms/ipxe/src/core/process.c
new file mode 100644
index 0000000..a329785
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/process.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+#include <ipxe/init.h>
+#include <ipxe/process.h>
+
+/** @file
+ *
+ * Processes
+ *
+ * We implement a trivial form of cooperative multitasking, in which
+ * all processes share a single stack and address space.
+ */
+
+/** Process run queue */
+static LIST_HEAD ( run_queue );
+
+/**
+ * Add process to process list
+ *
+ * @v process		Process
+ *
+ * It is safe to call process_add() multiple times; further calls will
+ * have no effect.
+ */
+void process_add ( struct process *process ) {
+	if ( ! process_running ( process ) ) {
+		DBGC ( process, "PROCESS %p (%p) starting\n",
+		       process, process->step );
+		ref_get ( process->refcnt );
+		list_add_tail ( &process->list, &run_queue );
+	} else {
+		DBGC ( process, "PROCESS %p (%p) already started\n",
+		       process, process->step );
+	}
+}
+
+/**
+ * Remove process from process list
+ *
+ * @v process		Process
+ *
+ * It is safe to call process_del() multiple times; further calls will
+ * have no effect.
+ */
+void process_del ( struct process *process ) {
+	if ( process_running ( process ) ) {
+		DBGC ( process, "PROCESS %p (%p) stopping\n",
+		       process, process->step );
+		list_del ( &process->list );
+		INIT_LIST_HEAD ( &process->list );
+		ref_put ( process->refcnt );
+	} else {
+		DBGC ( process, "PROCESS %p (%p) already stopped\n",
+		       process, process->step );
+	}
+}
+
+/**
+ * Single-step a single process
+ *
+ * This executes a single step of the first process in the run queue,
+ * and moves the process to the end of the run queue.
+ */
+void step ( void ) {
+	struct process *process;
+
+	if ( ( process = list_first_entry ( &run_queue, struct process,
+					    list ) ) ) {
+		list_del ( &process->list );
+		list_add_tail ( &process->list, &run_queue );
+		ref_get ( process->refcnt ); /* Inhibit destruction mid-step */
+		DBGC2 ( process, "PROCESS %p (%p) executing\n",
+			process, process->step );
+		process->step ( process );
+		DBGC2 ( process, "PROCESS %p (%p) finished executing\n",
+			process, process->step );
+		ref_put ( process->refcnt ); /* Allow destruction */
+	}
+}
+
+/**
+ * Initialise processes
+ *
+ */
+static void init_processes ( void ) {
+	struct process *process;
+
+	for_each_table_entry ( process, PERMANENT_PROCESSES )
+		process_add ( process );
+}
+
+/** Process initialiser */
+struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = init_processes,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/random.c b/qemu-0.15.x/roms/ipxe/src/core/random.c
new file mode 100644
index 0000000..8824dca
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/random.c
@@ -0,0 +1,41 @@
+/** @file
+ *
+ * Random number generation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/timer.h>
+
+static int32_t rnd_seed = 0;
+
+/**
+ * Seed the pseudo-random number generator
+ *
+ * @v seed		Seed value
+ */
+void srandom ( unsigned int seed ) {
+	rnd_seed = seed;
+}
+
+/**
+ * Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
+ *
+ * @ret rand		Pseudo-random number
+ */
+long int random ( void ) {
+	int32_t q;
+
+	if ( ! rnd_seed ) /* Initialize linear congruential generator */
+		srandom ( currticks() );
+
+	/* simplified version of the LCG given in Bruce Schneier's
+	   "Applied Cryptography" */
+	q = ( rnd_seed / 53668 );
+	rnd_seed = ( 40014 * ( rnd_seed - 53668 * q ) - 12211 * q );
+	if ( rnd_seed < 0 )
+		rnd_seed += 2147483563L;
+	return rnd_seed;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/refcnt.c b/qemu-0.15.x/roms/ipxe/src/core/refcnt.c
new file mode 100644
index 0000000..6117d74
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/refcnt.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/refcnt.h>
+
+/** @file
+ *
+ * Reference counting
+ *
+ */
+
+/**
+ * Increment reference count
+ *
+ * @v refcnt		Reference counter, or NULL
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+void ref_increment ( struct refcnt *refcnt ) {
+
+	if ( refcnt ) {
+		refcnt->count++;
+		DBGC2 ( refcnt, "REFCNT %p incremented to %d\n",
+			refcnt, refcnt->count );
+	}
+}
+
+/**
+ * Decrement reference count
+ *
+ * @v refcnt		Reference counter, or NULL
+ *
+ * If the reference count decreases below zero, the object's free()
+ * method will be called.
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+void ref_decrement ( struct refcnt *refcnt ) {
+
+	if ( ! refcnt )
+		return;
+
+	refcnt->count--;
+	DBGC2 ( refcnt, "REFCNT %p decremented to %d\n",
+		refcnt, refcnt->count );
+
+	if ( refcnt->count >= 0 )
+		return;
+
+	if ( refcnt->count < -1 ) {
+		DBGC ( refcnt, "REFCNT %p decremented too far (%d)!\n",
+		       refcnt, refcnt->count );
+		/* Avoid multiple calls to free(), which typically
+		 * result in memory corruption that is very hard to
+		 * track down.
+		 */
+		return;
+	}
+
+	if ( refcnt->free ) {
+		DBGC ( refcnt, "REFCNT %p being freed via method %p\n",
+		       refcnt, refcnt->free );
+		refcnt->free ( refcnt );
+	} else {
+		DBGC ( refcnt, "REFCNT %p being freed\n", refcnt );
+		free ( refcnt );
+	}
+}
+
+/**
+ * Do not free reference-counted object
+ *
+ * @v refcnt		Reference counter
+ *
+ * This is meant for initializing a reference counter structure in a
+ * statically allocated object.
+ */
+void ref_no_free ( struct refcnt *refcnt __unused ) {
+	/* Do nothing */
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/resolv.c b/qemu-0.15.x/roms/ipxe/src/core/resolv.c
new file mode 100644
index 0000000..91f0c15
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/resolv.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/in.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/process.h>
+#include <ipxe/resolv.h>
+
+/** @file
+ *
+ * Name resolution
+ *
+ */
+
+/***************************************************************************
+ *
+ * Name resolution interfaces
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Name resolved
+ *
+ * @v intf		Object interface
+ * @v sa		Completed socket address (if successful)
+ */
+void resolv_done ( struct interface *intf, struct sockaddr *sa ) {
+	struct interface *dest;
+	resolv_done_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, resolv_done, &dest );
+	void *object = intf_object ( dest );
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " resolv_done\n",
+	       INTF_INTF_DBG ( intf, dest ) );
+
+	if ( op ) {
+		op ( object, sa );
+	} else {
+		/* Default is to ignore resolutions */
+	}
+
+	intf_put ( dest );
+}
+
+/***************************************************************************
+ *
+ * Numeric name resolver
+ *
+ ***************************************************************************
+ */
+
+/** A numeric name resolver */
+struct numeric_resolv {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Name resolution interface */
+	struct interface resolv;
+	/** Process */
+	struct process process;
+	/** Completed socket address */
+	struct sockaddr sa;
+	/** Overall status code */
+	int rc;
+};
+
+static void numeric_step ( struct process *process ) {
+	struct numeric_resolv *numeric =
+		container_of ( process, struct numeric_resolv, process );
+
+	process_del ( process );
+	if ( numeric->rc == 0 )
+		resolv_done ( &numeric->resolv, &numeric->sa );
+	intf_shutdown ( &numeric->resolv, numeric->rc );
+}
+
+static int numeric_resolv ( struct interface *resolv,
+			    const char *name, struct sockaddr *sa ) {
+	struct numeric_resolv *numeric;
+	struct sockaddr_in *sin;
+
+	/* Allocate and initialise structure */
+	numeric = zalloc ( sizeof ( *numeric ) );
+	if ( ! numeric )
+		return -ENOMEM;
+	ref_init ( &numeric->refcnt, NULL );
+	intf_init ( &numeric->resolv, &null_intf_desc, &numeric->refcnt );
+	process_init ( &numeric->process, numeric_step, &numeric->refcnt );
+	memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) );
+
+	DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n",
+	       numeric, name );
+
+	/* Attempt to resolve name */
+	sin = ( ( struct sockaddr_in * ) &numeric->sa );
+	if ( inet_aton ( name, &sin->sin_addr ) != 0 ) {
+		sin->sin_family = AF_INET;
+	} else {
+		numeric->rc = -EINVAL;
+	}
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &numeric->resolv, resolv );
+	ref_put ( &numeric->refcnt );
+	return 0;
+}
+
+struct resolver numeric_resolver __resolver ( RESOLV_NUMERIC ) = {
+	.name = "NUMERIC",
+	.resolv = numeric_resolv,
+};
+
+/***************************************************************************
+ *
+ * Name resolution multiplexer
+ *
+ ***************************************************************************
+ */
+
+/** A name resolution multiplexer */
+struct resolv_mux {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Parent name resolution interface */
+	struct interface parent;
+
+	/** Child name resolution interface */
+	struct interface child;
+	/** Current child resolver */
+	struct resolver *resolver;
+
+	/** Socket address to complete */
+	struct sockaddr sa;
+	/** Name to be resolved
+	 *
+	 * Must be at end of structure
+	 */
+	char name[0];
+};
+
+/**
+ * Try current child name resolver
+ *
+ * @v mux		Name resolution multiplexer
+ * @ret rc		Return status code
+ */
+static int resmux_try ( struct resolv_mux *mux ) {
+	struct resolver *resolver = mux->resolver;
+	int rc;
+
+	DBGC ( mux, "RESOLV %p trying method %s\n", mux, resolver->name );
+
+	if ( ( rc = resolver->resolv ( &mux->child, mux->name,
+				       &mux->sa ) ) != 0 ) {
+		DBGC ( mux, "RESOLV %p could not use method %s: %s\n",
+		       mux, resolver->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Child resolved name
+ *
+ * @v mux		Name resolution multiplexer
+ * @v sa		Completed socket address
+ */
+static void resmux_child_resolv_done ( struct resolv_mux *mux,
+				       struct sockaddr *sa ) {
+
+	DBGC ( mux, "RESOLV %p resolved \"%s\" using method %s\n",
+	       mux, mux->name, mux->resolver->name );
+
+	/* Pass resolution to parent */
+	resolv_done ( &mux->parent, sa );
+}
+
+/**
+ * Child finished resolution
+ *
+ * @v mux		Name resolution multiplexer
+ * @v rc		Return status code
+ */
+static void resmux_child_close ( struct resolv_mux *mux, int rc ) {
+
+	/* Restart child interface */
+	intf_restart ( &mux->child, rc );
+
+	/* If this resolution succeeded, stop now */
+	if ( rc == 0 ) {
+		DBGC ( mux, "RESOLV %p succeeded using method %s\n",
+		       mux, mux->resolver->name );
+		goto finished;
+	}
+
+	/* Attempt next child resolver, if possible */
+	mux->resolver++;
+	if ( mux->resolver >= table_end ( RESOLVERS ) ) {
+		DBGC ( mux, "RESOLV %p failed to resolve name\n", mux );
+		goto finished;
+	}
+	if ( ( rc = resmux_try ( mux ) ) != 0 )
+		goto finished;
+
+	/* Next resolver is now running */
+	return;
+
+ finished:
+	intf_shutdown ( &mux->parent, rc );
+}
+
+/** Name resolution multiplexer child interface operations */
+static struct interface_operation resmux_child_op[] = {
+	INTF_OP ( resolv_done, struct resolv_mux *, resmux_child_resolv_done ),
+	INTF_OP ( intf_close, struct resolv_mux *, resmux_child_close ),
+};
+
+/** Name resolution multiplexer child interface descriptor */
+static struct interface_descriptor resmux_child_desc =
+	INTF_DESC ( struct resolv_mux, child, resmux_child_op );
+
+/**
+ * Start name resolution
+ *
+ * @v resolv		Name resolution interface
+ * @v name		Name to resolve
+ * @v sa		Socket address to complete
+ * @ret rc		Return status code
+ */
+int resolv ( struct interface *resolv, const char *name,
+	     struct sockaddr *sa ) {
+	struct resolv_mux *mux;
+	size_t name_len = ( strlen ( name ) + 1 );
+	int rc;
+
+	/* Allocate and initialise structure */
+	mux = zalloc ( sizeof ( *mux ) + name_len );
+	if ( ! mux )
+		return -ENOMEM;
+	ref_init ( &mux->refcnt, NULL );
+	intf_init ( &mux->parent, &null_intf_desc, &mux->refcnt );
+	intf_init ( &mux->child, &resmux_child_desc, &mux->refcnt );
+	mux->resolver = table_start ( RESOLVERS );
+	if ( sa )
+		memcpy ( &mux->sa, sa, sizeof ( mux->sa ) );
+	memcpy ( mux->name, name, name_len );
+
+	DBGC ( mux, "RESOLV %p attempting to resolve \"%s\"\n", mux, name );
+
+	/* Start first resolver in chain.  There will always be at
+	 * least one resolver (the numeric resolver), so no need to
+	 * check for the zero-resolvers-available case.
+	 */
+	if ( ( rc = resmux_try ( mux ) ) != 0 )
+		goto err;
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &mux->parent, resolv );
+	ref_put ( &mux->refcnt );
+	return 0;
+
+ err:
+	ref_put ( &mux->refcnt );
+	return rc;	
+}
+
+/***************************************************************************
+ *
+ * Named socket opening
+ *
+ ***************************************************************************
+ */
+
+/** A named socket */
+struct named_socket {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Name resolution interface */
+	struct interface resolv;
+	/** Communication semantics (e.g. SOCK_STREAM) */
+	int semantics;
+	/** Stored local socket address, if applicable */
+	struct sockaddr local;
+	/** Stored local socket address exists */
+	int have_local;
+};
+
+/**
+ * Terminate named socket opener
+ *
+ * @v named		Named socket
+ * @v rc		Reason for termination
+ */
+static void named_close ( struct named_socket *named, int rc ) {
+	/* Shut down interfaces */
+	intf_shutdown ( &named->resolv, rc );
+	intf_shutdown ( &named->xfer, rc );
+}
+
+/**
+ * Check flow control window
+ *
+ * @v named		Named socket
+ * @ret len		Length of window
+ */
+static size_t named_window ( struct named_socket *named __unused ) {
+	/* Not ready for data until we have redirected away */
+	return 0;
+}
+
+/** Named socket opener data transfer interface operations */
+static struct interface_operation named_xfer_ops[] = {
+	INTF_OP ( xfer_window, struct named_socket *, named_window ),
+	INTF_OP ( intf_close, struct named_socket *, named_close ),
+};
+
+/** Named socket opener data transfer interface descriptor */
+static struct interface_descriptor named_xfer_desc =
+	INTF_DESC ( struct named_socket, xfer, named_xfer_ops );
+
+/**
+ * Name resolved
+ *
+ * @v named		Named socket
+ * @v sa		Completed socket address
+ */
+static void named_resolv_done ( struct named_socket *named,
+				struct sockaddr *sa ) {
+	int rc;
+
+	/* Nullify data transfer interface */
+	intf_nullify ( &named->xfer );
+
+	/* Redirect data-xfer interface */
+	if ( ( rc = xfer_redirect ( &named->xfer, LOCATION_SOCKET,
+				    named->semantics, sa,
+				    ( named->have_local ?
+				      &named->local : NULL ) ) ) != 0 ) {
+		/* Redirection failed - do not unplug data-xfer interface */
+		DBGC ( named, "NAMED %p could not redirect: %s\n",
+		       named, strerror ( rc ) );
+	} else {
+		/* Redirection succeeded - unplug data-xfer interface */
+		DBGC ( named, "NAMED %p redirected successfully\n", named );
+		intf_unplug ( &named->xfer );
+	}
+
+	/* Terminate named socket opener */
+	named_close ( named, rc );
+}
+
+/** Named socket opener resolver interface operations */
+static struct interface_operation named_resolv_op[] = {
+	INTF_OP ( intf_close, struct named_socket *, named_close ),
+	INTF_OP ( resolv_done, struct named_socket *, named_resolv_done ),
+};
+
+/** Named socket opener resolver interface descriptor */
+static struct interface_descriptor named_resolv_desc =
+	INTF_DESC ( struct named_socket, resolv, named_resolv_op );
+
+/**
+ * Open named socket
+ *
+ * @v semantics		Communication semantics (e.g. SOCK_STREAM)
+ * @v peer		Peer socket address to complete
+ * @v name		Name to resolve
+ * @v local		Local socket address, or NULL
+ * @ret rc		Return status code
+ */
+int xfer_open_named_socket ( struct interface *xfer, int semantics,
+			     struct sockaddr *peer, const char *name,
+			     struct sockaddr *local ) {
+	struct named_socket *named;
+	int rc;
+
+	/* Allocate and initialise structure */
+	named = zalloc ( sizeof ( *named ) );
+	if ( ! named )
+		return -ENOMEM;
+	ref_init ( &named->refcnt, NULL );
+	intf_init ( &named->xfer, &named_xfer_desc, &named->refcnt );
+	intf_init ( &named->resolv, &named_resolv_desc, &named->refcnt );
+	named->semantics = semantics;
+	if ( local ) {
+		memcpy ( &named->local, local, sizeof ( named->local ) );
+		named->have_local = 1;
+	}
+
+	DBGC ( named, "NAMED %p opening \"%s\"\n",
+	       named, name );
+
+	/* Start name resolution */
+	if ( ( rc = resolv ( &named->resolv, name, peer ) ) != 0 )
+		goto err;
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &named->xfer, xfer );
+	ref_put ( &named->refcnt );
+	return 0;
+
+ err:
+	ref_put ( &named->refcnt );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/serial.c b/qemu-0.15.x/roms/ipxe/src/core/serial.c
new file mode 100644
index 0000000..a5551b1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/serial.c
@@ -0,0 +1,254 @@
+/*
+ * The serial port interface routines implement a simple polled i/o
+ * interface to a standard serial port.  Due to the space restrictions
+ * for the boot blocks, no BIOS support is used (since BIOS requires
+ * expensive real/protected mode switches), instead the rudimentary
+ * BIOS support is duplicated here.
+ *
+ * The base address and speed for the i/o port are passed from the
+ * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
+ * line control parameters are currently hard-coded to 8 bits, no
+ * parity, 1 stop bit (8N1).  This can be changed in init_serial().
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "stddef.h"
+#include <ipxe/init.h>
+#include <ipxe/io.h>
+#include <unistd.h>
+#include <ipxe/serial.h>
+#include "config/serial.h"
+
+/* Set default values if none specified */
+
+#ifndef COMCONSOLE
+#define COMCONSOLE	0x3f8
+#endif
+
+#ifndef COMSPEED
+#define COMSPEED	9600
+#endif
+
+#ifndef COMDATA
+#define COMDATA		8
+#endif
+
+#ifndef COMPARITY
+#define COMPARITY	0
+#endif
+
+#ifndef COMSTOP
+#define COMSTOP		1
+#endif
+
+#undef UART_BASE
+#define UART_BASE ( COMCONSOLE )
+
+#undef UART_BAUD
+#define UART_BAUD ( COMSPEED )
+
+#if ((115200%UART_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#define COMBRD (115200/UART_BAUD)
+
+/* Line Control Settings */
+#define UART_LCS ( ( ( (COMDATA) - 5 )	<< 0 ) | \
+		   ( ( (COMPARITY) )	<< 3 ) | \
+		   ( ( (COMSTOP) - 1 )	<< 2 ) )
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define  UART_LSR_TEMPT 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 */
+
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+#if defined(UART_MEM)
+#define uart_readb(addr) readb((addr))
+#define uart_writeb(val,addr) writeb((val),(addr))
+#else
+#define uart_readb(addr) inb((addr))
+#define uart_writeb(val,addr) outb((val),(addr))
+#endif
+
+/*
+ * void serial_putc(int ch);
+ *	Write character `ch' to port UART_BASE.
+ */
+void serial_putc ( int ch ) {
+	int i;
+	int status;
+	i = 1000; /* timeout */
+	while(--i > 0) {
+		status = uart_readb(UART_BASE + UART_LSR);
+		if (status & UART_LSR_THRE) { 
+			/* TX buffer emtpy */
+			uart_writeb(ch, UART_BASE + UART_TBR);
+			break;
+		}
+		mdelay(2);
+	}
+}
+
+/*
+ * int serial_getc(void);
+ *	Read a character from port UART_BASE.
+ */
+int serial_getc ( void ) {
+	int status;
+	int ch;
+	do {
+		status = uart_readb(UART_BASE + UART_LSR);
+	} while((status & 1) == 0);
+	ch = uart_readb(UART_BASE + UART_RBR);	/* fetch (first) character */
+	ch &= 0x7f;				/* remove any parity bits we get */
+	if (ch == 0x7f) {			/* Make DEL... look like BS */
+		ch = 0x08;
+	}
+	return ch;
+}
+
+/*
+ * int serial_ischar(void);
+ *       If there is a character in the input buffer of port UART_BASE,
+ *       return nonzero; otherwise return 0.
+ */
+int serial_ischar ( void ) {
+	int status;
+	status = uart_readb(UART_BASE + UART_LSR);	/* line status reg; */
+	return status & 1;		/* rx char available */
+}
+
+/*
+ * int serial_init(void);
+ *	Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
+ */
+static void serial_init ( void ) {
+	int status;
+	int divisor, lcs;
+
+	DBG ( "Serial port %#x initialising\n", UART_BASE );
+
+	divisor = COMBRD;
+	lcs = UART_LCS;
+
+
+#ifdef COMPRESERVE
+	lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
+	uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
+	divisor = (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + UART_DLL);
+	uart_writeb(lcs, UART_BASE + UART_LCR);
+#endif
+
+	/* Set Baud Rate Divisor to COMSPEED, and test to see if the
+	 * serial port appears to be present.
+	 */
+	uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
+	uart_writeb(0xaa, UART_BASE + UART_DLL);
+	if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
+		DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb(0x55, UART_BASE + UART_DLL);
+	if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
+		DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
+	if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
+		DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb(0xaa, UART_BASE + UART_DLM);
+	if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
+		DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb(0x55, UART_BASE + UART_DLM);
+	if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
+		DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
+	if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
+		DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
+		goto out;
+	}
+	uart_writeb(lcs, UART_BASE + UART_LCR);
+	
+	/* disable interrupts */
+	uart_writeb(0x0, UART_BASE + UART_IER);
+
+	/* disable fifo's */
+	uart_writeb(0x00, UART_BASE + UART_FCR);
+
+	/* Set clear to send, so flow control works... */
+	uart_writeb((1<<1), UART_BASE + UART_MCR);
+
+
+	/* Flush the input buffer. */
+	do {
+		/* rx buffer reg
+		 * throw away (unconditionally the first time)
+		 */
+	        (void) uart_readb(UART_BASE + UART_RBR);
+		/* line status reg */
+		status = uart_readb(UART_BASE + UART_LSR);
+	} while(status & UART_LSR_DR);
+ out:
+	return;
+}
+
+/*
+ * void serial_fini(void);
+ *	Cleanup our use of the serial port, in particular flush the
+ *	output buffer so we don't accidentially lose characters.
+ */
+static void serial_fini ( int flags __unused ) {
+	int i, status;
+	/* Flush the output buffer to avoid dropping characters,
+	 * if we are reinitializing the serial port.
+	 */
+	i = 10000; /* timeout */
+	do {
+		status = uart_readb(UART_BASE + UART_LSR);
+	} while((--i > 0) && !(status & UART_LSR_TEMPT));
+	/* Don't mark it as disabled; it's still usable */
+}
+
+/**
+ * Serial driver initialisation function
+ *
+ * Initialise serial port early on so that it is available to capture
+ * early debug messages.
+ */
+struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
+	.initialise = serial_init,
+};
+
+/** Serial driver startup function */
+struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+	.shutdown = serial_fini,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/serial_console.c b/qemu-0.15.x/roms/ipxe/src/core/serial_console.c
new file mode 100644
index 0000000..b05a06b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/serial_console.c
@@ -0,0 +1,31 @@
+#include <ipxe/init.h>
+#include <ipxe/serial.h>
+#include <ipxe/console.h>
+
+/** @file
+ *
+ * Serial console
+ *
+ */
+
+struct console_driver serial_console __console_driver;
+
+static void serial_console_init ( void ) {
+	/* Serial driver initialization should already be done,
+	 * time to enable the serial console. */
+	serial_console.disabled = 0;
+}
+
+struct console_driver serial_console __console_driver = {
+	.putchar = serial_putc,
+	.getchar = serial_getc,
+	.iskey = serial_ischar,
+	.disabled = 1,
+};
+
+/**
+ * Serial console initialisation function
+ */
+struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = {
+	.initialise = serial_console_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/settings.c b/qemu-0.15.x/roms/ipxe/src/core/settings.c
new file mode 100644
index 0000000..0a8c5f6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/settings.c
@@ -0,0 +1,1744 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/in.h>
+#include <ipxe/vsprintf.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/uuid.h>
+#include <ipxe/uri.h>
+#include <ipxe/settings.h>
+
+/** @file
+ *
+ * Configuration settings
+ *
+ */
+
+/******************************************************************************
+ *
+ * Generic settings blocks
+ *
+ ******************************************************************************
+ */
+
+/**
+ * A generic setting
+ *
+ */
+struct generic_setting {
+	/** List of generic settings */
+	struct list_head list;
+	/** Setting */
+	struct setting setting;
+	/** Size of setting name */
+	size_t name_len;
+	/** Size of setting data */
+	size_t data_len;
+};
+
+/**
+ * Get generic setting name
+ *
+ * @v generic		Generic setting
+ * @ret name		Generic setting name
+ */
+static inline void * generic_setting_name ( struct generic_setting *generic ) {
+	return ( ( ( void * ) generic ) + sizeof ( *generic ) );
+}
+
+/**
+ * Get generic setting data
+ *
+ * @v generic		Generic setting
+ * @ret data		Generic setting data
+ */
+static inline void * generic_setting_data ( struct generic_setting *generic ) {
+	return ( ( ( void * ) generic ) + sizeof ( *generic ) +
+		 generic->name_len );
+}
+
+/**
+ * Find generic setting
+ *
+ * @v generics		Generic settings block
+ * @v setting		Setting to find
+ * @ret generic		Generic setting, or NULL
+ */
+static struct generic_setting *
+find_generic_setting ( struct generic_settings *generics,
+		       struct setting *setting ) {
+	struct generic_setting *generic;
+
+	list_for_each_entry ( generic, &generics->list, list ) {
+		if ( setting_cmp ( &generic->setting, setting ) == 0 )
+			return generic;
+	}
+	return NULL;
+}
+
+/**
+ * Store value of generic setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+int generic_settings_store ( struct settings *settings,
+			     struct setting *setting,
+			     const void *data, size_t len ) {
+	struct generic_settings *generics =
+		container_of ( settings, struct generic_settings, settings );
+	struct generic_setting *old;
+	struct generic_setting *new = NULL;
+	size_t name_len;
+
+	/* Identify existing generic setting, if any */
+	old = find_generic_setting ( generics, setting );
+
+	/* Create new generic setting, if required */
+	if ( len ) {
+		/* Allocate new generic setting */
+		name_len = ( strlen ( setting->name ) + 1 );
+		new = zalloc ( sizeof ( *new ) + name_len + len );
+		if ( ! new )
+			return -ENOMEM;
+
+		/* Populate new generic setting */
+		new->name_len = name_len;
+		new->data_len = len;
+		memcpy ( &new->setting, setting, sizeof ( new->setting ) );
+		new->setting.name = generic_setting_name ( new );
+		memcpy ( generic_setting_name ( new ),
+			 setting->name, name_len );
+		memcpy ( generic_setting_data ( new ), data, len );
+	}
+
+	/* Delete existing generic setting, if any */
+	if ( old ) {
+		list_del ( &old->list );
+		free ( old );
+	}
+
+	/* Add new setting to list, if any */
+	if ( new )
+		list_add ( &new->list, &generics->list );
+
+	return 0;
+}
+
+/**
+ * Fetch value of generic setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+int generic_settings_fetch ( struct settings *settings,
+			     struct setting *setting,
+			     void *data, size_t len ) {
+	struct generic_settings *generics =
+		container_of ( settings, struct generic_settings, settings );
+	struct generic_setting *generic;
+
+	/* Find generic setting */
+	generic = find_generic_setting ( generics, setting );
+	if ( ! generic )
+		return -ENOENT;
+
+	/* Copy out generic setting data */
+	if ( len > generic->data_len )
+		len = generic->data_len;
+	memcpy ( data, generic_setting_data ( generic ), len );
+	return generic->data_len;
+}
+
+/**
+ * Clear generic settings block
+ *
+ * @v settings		Settings block
+ */
+void generic_settings_clear ( struct settings *settings ) {
+	struct generic_settings *generics =
+		container_of ( settings, struct generic_settings, settings );
+	struct generic_setting *generic;
+	struct generic_setting *tmp;
+
+	list_for_each_entry_safe ( generic, tmp, &generics->list, list ) {
+		list_del ( &generic->list );
+		free ( generic );
+	}
+	assert ( list_empty ( &generics->list ) );
+}
+
+/** Generic settings operations */
+struct settings_operations generic_settings_operations = {
+	.store = generic_settings_store,
+	.fetch = generic_settings_fetch,
+	.clear = generic_settings_clear,
+};
+
+/******************************************************************************
+ *
+ * Registered settings blocks
+ *
+ ******************************************************************************
+ */
+
+/** Root generic settings block */
+struct generic_settings generic_settings_root = {
+	.settings = {
+		.refcnt = NULL,
+		.name = "",
+		.siblings =
+		    LIST_HEAD_INIT ( generic_settings_root.settings.siblings ),
+		.children =
+		    LIST_HEAD_INIT ( generic_settings_root.settings.children ),
+		.op = &generic_settings_operations,
+	},
+	.list = LIST_HEAD_INIT ( generic_settings_root.list ),
+};
+
+/** Root settings block */
+#define settings_root generic_settings_root.settings
+
+/** Autovivified settings block */
+struct autovivified_settings {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Generic settings block */
+	struct generic_settings generic;
+};
+
+/**
+ * Free autovivified settings block
+ *
+ * @v refcnt		Reference count
+ */
+static void autovivified_settings_free ( struct refcnt *refcnt ) {
+	struct autovivified_settings *autovivified =
+		container_of ( refcnt, struct autovivified_settings, refcnt );
+
+	generic_settings_clear ( &autovivified->generic.settings );
+	free ( autovivified );
+}
+
+/**
+ * Find child named settings block
+ *
+ * @v parent		Parent settings block
+ * @v name		Name within this parent
+ * @ret settings	Settings block, or NULL
+ */
+static struct settings * find_child_settings ( struct settings *parent,
+					       const char *name ) {
+	struct settings *settings;
+
+	/* Treat empty name as meaning "this block" */
+	if ( ! *name )
+		return parent;
+
+	/* Look for child with matching name */
+	list_for_each_entry ( settings, &parent->children, siblings ) {
+		if ( strcmp ( settings->name, name ) == 0 )
+			return settings;
+	}
+
+	return NULL;
+}
+
+/**
+ * Find or create child named settings block
+ *
+ * @v parent		Parent settings block
+ * @v name		Name within this parent
+ * @ret settings	Settings block, or NULL
+ */
+static struct settings * autovivify_child_settings ( struct settings *parent,
+						     const char *name ) {
+	struct {
+		struct autovivified_settings autovivified;
+		char name[ strlen ( name ) + 1 /* NUL */ ];
+	} *new_child;
+	struct settings *settings;
+
+	/* Return existing settings, if existent */
+	if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
+		return settings;
+
+	/* Create new generic settings block */
+	new_child = zalloc ( sizeof ( *new_child ) );
+	if ( ! new_child ) {
+		DBGC ( parent, "Settings %p could not create child %s\n",
+		       parent, name );
+		return NULL;
+	}
+	memcpy ( new_child->name, name, sizeof ( new_child->name ) );
+	ref_init ( &new_child->autovivified.refcnt,
+		   autovivified_settings_free );
+	generic_settings_init ( &new_child->autovivified.generic,
+				&new_child->autovivified.refcnt );
+	settings = &new_child->autovivified.generic.settings;
+	register_settings ( settings, parent, new_child->name );
+	return settings;
+}
+
+/**
+ * Return settings block name
+ *
+ * @v settings		Settings block
+ * @ret name		Settings block name
+ */
+const char * settings_name ( struct settings *settings ) {
+	static char buf[16];
+	char tmp[ sizeof ( buf ) ];
+
+	for ( buf[2] = buf[0] = 0 ; settings ; settings = settings->parent ) {
+		memcpy ( tmp, buf, sizeof ( tmp ) );
+		snprintf ( buf, sizeof ( buf ), ".%s%s", settings->name, tmp );
+	}
+	return ( buf + 2 );
+}
+
+/**
+ * Parse settings block name
+ *
+ * @v name		Name
+ * @v get_child		Function to find or create child settings block
+ * @ret settings	Settings block, or NULL
+ */
+static struct settings *
+parse_settings_name ( const char *name,
+		      struct settings * ( * get_child ) ( struct settings *,
+							  const char * ) ) {
+	struct settings *settings = &settings_root;
+	char name_copy[ strlen ( name ) + 1 ];
+	char *subname;
+	char *remainder;
+
+	/* Create modifiable copy of name */
+	memcpy ( name_copy, name, sizeof ( name_copy ) );
+	remainder = name_copy;
+
+	/* Parse each name component in turn */
+	while ( remainder ) {
+		struct net_device *netdev;
+
+		subname = remainder;
+		remainder = strchr ( subname, '.' );
+		if ( remainder )
+			*(remainder++) = '\0';
+
+		/* Special case "netX" root settings block */
+		if ( ( subname == name_copy ) && ! strcmp ( subname, "netX" ) &&
+		     ( ( netdev = last_opened_netdev() ) != NULL ) )
+			settings = get_child ( settings, netdev->name );
+		else
+			settings = get_child ( settings, subname );
+
+		if ( ! settings )
+			break;
+	}
+
+	return settings;
+}
+
+/**
+ * Find named settings block
+ *
+ * @v name		Name
+ * @ret settings	Settings block, or NULL
+ */
+struct settings * find_settings ( const char *name ) {
+
+	return parse_settings_name ( name, find_child_settings );
+}
+
+/**
+ * Apply all settings
+ *
+ * @ret rc		Return status code
+ */
+static int apply_settings ( void ) {
+	struct settings_applicator *applicator;
+	int rc;
+
+	/* Call all settings applicators */
+	for_each_table_entry ( applicator, SETTINGS_APPLICATORS ) {
+		if ( ( rc = applicator->apply() ) != 0 ) {
+			DBG ( "Could not apply settings using applicator "
+			      "%p: %s\n", applicator, strerror ( rc ) );
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Reprioritise settings
+ *
+ * @v settings		Settings block
+ *
+ * Reorders the settings block amongst its siblings according to its
+ * priority.
+ */
+static void reprioritise_settings ( struct settings *settings ) {
+	struct settings *parent = settings->parent;
+	long priority;
+	struct settings *tmp;
+	long tmp_priority;
+
+	/* Stop when we reach the top of the tree */
+	if ( ! parent )
+		return;
+
+	/* Read priority, if present */
+	priority = fetch_intz_setting ( settings, &priority_setting );
+
+	/* Remove from siblings list */
+	list_del ( &settings->siblings );
+
+	/* Reinsert after any existing blocks which have a higher priority */
+	list_for_each_entry ( tmp, &parent->children, siblings ) {
+		tmp_priority = fetch_intz_setting ( tmp, &priority_setting );
+		if ( priority > tmp_priority )
+			break;
+	}
+	list_add_tail ( &settings->siblings, &tmp->siblings );
+
+	/* Recurse up the tree */
+	reprioritise_settings ( parent );
+}
+
+/**
+ * Register settings block
+ *
+ * @v settings		Settings block
+ * @v parent		Parent settings block, or NULL
+ * @v name		Settings block name
+ * @ret rc		Return status code
+ */
+int register_settings ( struct settings *settings, struct settings *parent,
+			const char *name ) {
+	struct settings *old_settings;
+
+	/* NULL parent => add to settings root */
+	assert ( settings != NULL );
+	if ( parent == NULL )
+		parent = &settings_root;
+
+	/* Apply settings block name */
+	settings->name = name;
+
+	/* Remove any existing settings with the same name */
+	if ( ( old_settings = find_child_settings ( parent, settings->name ) ))
+		unregister_settings ( old_settings );
+
+	/* Add to list of settings */
+	ref_get ( settings->refcnt );
+	ref_get ( parent->refcnt );
+	settings->parent = parent;
+	list_add_tail ( &settings->siblings, &parent->children );
+	DBGC ( settings, "Settings %p (\"%s\") registered\n",
+	       settings, settings_name ( settings ) );
+
+	/* Fix up settings priority */
+	reprioritise_settings ( settings );
+
+	/* Apply potentially-updated settings */
+	apply_settings();
+
+	return 0;
+}
+
+/**
+ * Unregister settings block
+ *
+ * @v settings		Settings block
+ */
+void unregister_settings ( struct settings *settings ) {
+	struct settings *child;
+	struct settings *tmp;
+
+	/* Unregister child settings */
+	list_for_each_entry_safe ( child, tmp, &settings->children, siblings ) {
+		unregister_settings ( child );
+	}
+
+	DBGC ( settings, "Settings %p (\"%s\") unregistered\n",
+	       settings, settings_name ( settings ) );
+
+	/* Remove from list of settings */
+	ref_put ( settings->parent->refcnt );
+	settings->parent = NULL;
+	list_del ( &settings->siblings );
+	ref_put ( settings->refcnt );
+
+	/* Apply potentially-updated settings */
+	apply_settings();
+}
+
+/******************************************************************************
+ *
+ * Core settings routines
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check applicability of setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+int setting_applies ( struct settings *settings, struct setting *setting ) {
+
+	return ( settings->op->applies ?
+		 settings->op->applies ( settings, setting ) : 1 );
+}
+
+/**
+ * Store value of setting
+ *
+ * @v settings		Settings block, or NULL
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+int store_setting ( struct settings *settings, struct setting *setting,
+		    const void *data, size_t len ) {
+	int rc;
+
+	/* NULL settings implies storing into the global settings root */
+	if ( ! settings )
+		settings = &settings_root;
+
+	/* Fail if tag does not apply to this settings block */
+	if ( ! setting_applies ( settings, setting ) )
+		return -ENOTTY;
+
+	/* Sanity check */
+	if ( ! settings->op->store )
+		return -ENOTSUP;
+
+	/* Store setting */
+	if ( ( rc = settings->op->store ( settings, setting,
+					  data, len ) ) != 0 )
+		return rc;
+
+	/* Reprioritise settings if necessary */
+	if ( setting_cmp ( setting, &priority_setting ) == 0 )
+		reprioritise_settings ( settings );
+
+	/* If these settings are registered, apply potentially-updated
+	 * settings
+	 */
+	for ( ; settings ; settings = settings->parent ) {
+		if ( settings == &settings_root ) {
+			if ( ( rc = apply_settings() ) != 0 )
+				return rc;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Fetch value and origin of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v origin		Origin of setting to fill in
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ *
+ * The actual length of the setting will be returned even if
+ * the buffer was too small.
+ */
+static int fetch_setting_and_origin ( struct settings *settings,
+				      struct setting *setting,
+				      struct settings **origin,
+				      void *data, size_t len ) {
+	struct settings *child;
+	int ret;
+
+	/* Avoid returning uninitialised data on error */
+	memset ( data, 0, len );
+	if ( origin )
+		*origin = NULL;
+
+	/* NULL settings implies starting at the global settings root */
+	if ( ! settings )
+		settings = &settings_root;
+
+	/* Sanity check */
+	if ( ! settings->op->fetch )
+		return -ENOTSUP;
+
+	/* Try this block first, if applicable */
+	if ( setting_applies ( settings, setting ) &&
+	     ( ( ret = settings->op->fetch ( settings, setting,
+					     data, len ) ) >= 0 ) ) {
+		if ( origin )
+			*origin = settings;
+		return ret;
+	}
+
+	/* Recurse into each child block in turn */
+	list_for_each_entry ( child, &settings->children, siblings ) {
+		if ( ( ret = fetch_setting_and_origin ( child, setting, origin,
+							data, len ) ) >= 0 )
+			return ret;
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * Fetch value of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ *
+ * The actual length of the setting will be returned even if
+ * the buffer was too small.
+ */
+int fetch_setting ( struct settings *settings, struct setting *setting,
+		    void *data, size_t len ) {
+	return fetch_setting_and_origin ( settings, setting, NULL, data, len );
+}
+
+/**
+ * Fetch origin of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @ret origin		Origin of setting, or NULL if not found
+ *
+ * This function can also be used as an existence check for the
+ * setting.
+ */
+struct settings * fetch_setting_origin ( struct settings *settings,
+					 struct setting *setting ) {
+	struct settings *origin;
+
+	fetch_setting_and_origin ( settings, setting, &origin, NULL, 0 );
+	return origin;
+}
+
+/**
+ * Fetch length of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @ret len		Length of setting data, or negative error
+ *
+ * This function can also be used as an existence check for the
+ * setting.
+ */
+int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
+	return fetch_setting ( settings, setting, NULL, 0 );
+}
+
+/**
+ * Fetch value of string setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting string data
+ * @v len		Length of buffer
+ * @ret len		Length of string setting, or negative error
+ *
+ * The resulting string is guaranteed to be correctly NUL-terminated.
+ * The returned length will be the length of the underlying setting
+ * data.
+ */
+int fetch_string_setting ( struct settings *settings, struct setting *setting,
+			   char *data, size_t len ) {
+	memset ( data, 0, len );
+	return fetch_setting ( settings, setting, data,
+			       ( ( len > 0 ) ? ( len - 1 ) : 0 ) );
+}
+
+/**
+ * Fetch value of string setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to allocate and fill with setting string data
+ * @ret len		Length of string setting, or negative error
+ *
+ * The resulting string is guaranteed to be correctly NUL-terminated.
+ * The returned length will be the length of the underlying setting
+ * data.  The caller is responsible for eventually freeing the
+ * allocated buffer.
+ *
+ * To allow the caller to distinguish between a non-existent setting
+ * and an error in allocating memory for the copy, this function will
+ * return success (and a NULL buffer pointer) for a non-existent
+ * setting.
+ */
+int fetch_string_setting_copy ( struct settings *settings,
+				struct setting *setting,
+				char **data ) {
+	int len;
+	int check_len = 0;
+
+	/* Avoid returning uninitialised data on error */
+	*data = NULL;
+
+	/* Fetch setting length, and return success if non-existent */
+	len = fetch_setting_len ( settings, setting );
+	if ( len < 0 )
+		return 0;
+
+	/* Allocate string buffer */
+	*data = malloc ( len + 1 );
+	if ( ! *data )
+		return -ENOMEM;
+
+	/* Fetch setting */
+	check_len = fetch_string_setting ( settings, setting, *data,
+					   ( len + 1 ) );
+	assert ( check_len == len );
+	return len;
+}
+
+/**
+ * Fetch value of IPv4 address setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v inp		IPv4 addresses to fill in
+ * @v count		Maximum number of IPv4 addresses
+ * @ret len		Length of setting, or negative error
+ */
+int fetch_ipv4_array_setting ( struct settings *settings,
+			       struct setting *setting,
+			       struct in_addr *inp, unsigned int count ) {
+	int len;
+
+	len = fetch_setting ( settings, setting, inp,
+			      ( sizeof ( *inp ) * count ) );
+	if ( len < 0 )
+		return len;
+	if ( ( len % sizeof ( *inp ) ) != 0 )
+		return -ERANGE;
+	return len;
+}
+
+/**
+ * Fetch value of IPv4 address setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v inp		IPv4 address to fill in
+ * @ret len		Length of setting, or negative error
+ */
+int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
+			 struct in_addr *inp ) {
+	return fetch_ipv4_array_setting ( settings, setting, inp, 1 );
+}
+
+/**
+ * Fetch value of signed integer setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v value		Integer value to fill in
+ * @ret len		Length of setting, or negative error
+ */
+int fetch_int_setting ( struct settings *settings, struct setting *setting,
+			long *value ) {
+	union {
+		uint8_t u8[ sizeof ( long ) ];
+		int8_t s8[ sizeof ( long ) ];
+	} buf;
+	int len;
+	int i;
+
+	/* Avoid returning uninitialised data on error */
+	*value = 0;
+
+	/* Fetch raw (network-ordered, variable-length) setting */
+	len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
+	if ( len < 0 )
+		return len;
+	if ( len > ( int ) sizeof ( buf ) )
+		return -ERANGE;
+
+	/* Convert to host-ordered signed long */
+	*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
+	for ( i = 0 ; i < len ; i++ ) {
+		*value = ( ( *value << 8 ) | buf.u8[i] );
+	}
+
+	return len;
+}
+
+/**
+ * Fetch value of unsigned integer setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v value		Integer value to fill in
+ * @ret len		Length of setting, or negative error
+ */
+int fetch_uint_setting ( struct settings *settings, struct setting *setting,
+			 unsigned long *value ) {
+	long svalue;
+	int len;
+
+	/* Avoid returning uninitialised data on error */
+	*value = 0;
+
+	/* Fetch as a signed long */
+	len = fetch_int_setting ( settings, setting, &svalue );
+	if ( len < 0 )
+		return len;
+
+	/* Mask off sign-extended bits */
+	assert ( len <= ( int ) sizeof ( long ) );
+	*value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) );
+
+	return len;
+}
+
+/**
+ * Fetch value of signed integer setting, or zero
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @ret value		Setting value, or zero
+ */
+long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
+	long value;
+
+	fetch_int_setting ( settings, setting, &value );
+	return value;
+}
+
+/**
+ * Fetch value of unsigned integer setting, or zero
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @ret value		Setting value, or zero
+ */
+unsigned long fetch_uintz_setting ( struct settings *settings,
+				    struct setting *setting ) {
+	unsigned long value;
+
+	fetch_uint_setting ( settings, setting, &value );
+	return value;
+}
+
+/**
+ * Fetch value of UUID setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v uuid		UUID to fill in
+ * @ret len		Length of setting, or negative error
+ */
+int fetch_uuid_setting ( struct settings *settings, struct setting *setting,
+			 union uuid *uuid ) {
+	int len;
+
+	len = fetch_setting ( settings, setting, uuid, sizeof ( *uuid ) );
+	if ( len < 0 )
+		return len;
+	if ( len != sizeof ( *uuid ) )
+		return -ERANGE;
+	return len;
+}
+
+/**
+ * Clear settings block
+ *
+ * @v settings		Settings block
+ */
+void clear_settings ( struct settings *settings ) {
+	if ( settings->op->clear )
+		settings->op->clear ( settings );
+}
+
+/**
+ * Compare two settings
+ *
+ * @v a			Setting to compare
+ * @v b			Setting to compare
+ * @ret 0		Settings are the same
+ * @ret non-zero	Settings are not the same
+ */
+int setting_cmp ( struct setting *a, struct setting *b ) {
+
+	/* If the settings have tags, compare them */
+	if ( a->tag && ( a->tag == b->tag ) )
+		return 0;
+
+	/* Otherwise, if the settings have names, compare them */
+	if ( a->name && b->name && a->name[0] )
+		return strcmp ( a->name, b->name );
+
+	/* Otherwise, return a non-match */
+	return ( ! 0 );
+}
+
+/******************************************************************************
+ *
+ * Formatted setting routines
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Store value of typed setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v type		Settings type
+ * @v value		Formatted setting data, or NULL
+ * @ret rc		Return status code
+ */
+int storef_setting ( struct settings *settings, struct setting *setting,
+		     const char *value ) {
+
+	/* NULL value implies deletion.  Avoid imposing the burden of
+	 * checking for NULL values on each typed setting's storef()
+	 * method.
+	 */
+	if ( ! value )
+		return delete_setting ( settings, setting );
+		
+	return setting->type->storef ( settings, setting, value );
+}
+
+/**
+ * Find named setting
+ *
+ * @v name		Name
+ * @ret setting		Named setting, or NULL
+ */
+struct setting * find_setting ( const char *name ) {
+	struct setting *setting;
+
+	for_each_table_entry ( setting, SETTINGS ) {
+		if ( strcmp ( name, setting->name ) == 0 )
+			return setting;
+	}
+	return NULL;
+}
+
+/**
+ * Parse setting name as tag number
+ *
+ * @v settings		Settings block
+ * @v name		Name
+ * @ret tag		Tag number, or 0 if not a valid number
+ */
+static unsigned int parse_setting_tag ( struct settings *settings,
+					const char *name ) {
+	char *tmp = ( ( char * ) name );
+	unsigned int tag = 0;
+
+	while ( 1 ) {
+		tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) );
+		if ( *tmp == 0 )
+			return ( tag | settings->tag_magic );
+		if ( *tmp != '.' )
+			return 0;
+		tmp++;
+	}
+}
+
+/**
+ * Find setting type
+ *
+ * @v name		Name
+ * @ret type		Setting type, or NULL
+ */
+static struct setting_type * find_setting_type ( const char *name ) {
+	struct setting_type *type;
+
+	for_each_table_entry ( type, SETTING_TYPES ) {
+		if ( strcmp ( name, type->name ) == 0 )
+			return type;
+	}
+	return NULL;
+}
+
+/**
+ * Parse setting name
+ *
+ * @v name		Name of setting
+ * @v get_child		Function to find or create child settings block
+ * @v settings		Settings block to fill in
+ * @v setting		Setting to fill in
+ * @v tmp_name		Buffer for copy of setting name
+ * @ret rc		Return status code
+ *
+ * Interprets a name of the form
+ * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
+ * fields.
+ *
+ * The @c tmp_name buffer must be large enough to hold a copy of the
+ * setting name.
+ */
+static int
+parse_setting_name ( const char *name,
+		     struct settings * ( * get_child ) ( struct settings *,
+							 const char * ),
+		     struct settings **settings, struct setting *setting,
+		     char *tmp_name ) {
+	char *settings_name;
+	char *setting_name;
+	char *type_name;
+	struct setting *named_setting;
+
+	/* Set defaults */
+	*settings = &settings_root;
+	memset ( setting, 0, sizeof ( *setting ) );
+	setting->name = "";
+	setting->type = &setting_type_string;
+
+	/* Split name into "[settings_name/]setting_name[:type_name]" */
+	strcpy ( tmp_name, name );
+	if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) {
+		*(setting_name++) = 0;
+		settings_name = tmp_name;
+	} else {
+		setting_name = tmp_name;
+		settings_name = NULL;
+	}
+	if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL )
+		*(type_name++) = 0;
+
+	/* Identify settings block, if specified */
+	if ( settings_name ) {
+		*settings = parse_settings_name ( settings_name, get_child );
+		if ( *settings == NULL ) {
+			DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
+			      settings_name, name );
+			return -ENODEV;
+		}
+	}
+
+	/* Identify setting */
+	setting->tag = parse_setting_tag ( *settings, setting_name );
+	setting->name = setting_name;
+	for_each_table_entry ( named_setting, SETTINGS ) {
+		/* Matches a defined named setting; use that setting */
+		if ( setting_cmp ( named_setting, setting ) == 0 ) {
+			memcpy ( setting, named_setting, sizeof ( *setting ) );
+			break;
+		}
+	}
+
+	/* Identify setting type, if specified */
+	if ( type_name ) {
+		setting->type = find_setting_type ( type_name );
+		if ( setting->type == NULL ) {
+			DBG ( "Invalid setting type \"%s\" in \"%s\"\n",
+			      type_name, name );
+			return -ENOTSUP;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Return full setting name
+ *
+ * @v settings		Settings block, or NULL
+ * @v setting		Setting
+ * @v buf		Buffer
+ * @v len		Length of buffer
+ * @ret len		Length of setting name, or negative error
+ */
+int setting_name ( struct settings *settings, struct setting *setting,
+		   char *buf, size_t len ) {
+	const char *name;
+
+	if ( ! settings )
+		settings = &settings_root;
+
+	name = settings_name ( settings );
+	return snprintf ( buf, len, "%s%s%s:%s", name, ( name[0] ? "/" : "" ),
+			  setting->name, setting->type->name );
+}
+
+/**
+ * Parse and store value of named setting
+ *
+ * @v name		Name of setting
+ * @v value		Formatted setting data, or NULL
+ * @ret rc		Return status code
+ */
+int storef_named_setting ( const char *name, const char *value ) {
+	struct settings *settings;
+	struct setting setting;
+	char tmp_name[ strlen ( name ) + 1 ];
+	int rc;
+
+	/* Parse setting name */
+	if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
+					 &settings, &setting, tmp_name )) != 0)
+		return rc;
+
+	/* Store setting */
+	if ( ( rc = storef_setting ( settings, &setting, value ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Fetch and format value of named setting
+ *
+ * @v name		Name of setting
+ * @v name_buf		Buffer to contain canonicalised name
+ * @v name_len		Length of canonicalised name buffer
+ * @v value_buf		Buffer to contain formatted value
+ * @v value_len		Length of formatted value buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+int fetchf_named_setting ( const char *name,
+			   char *name_buf, size_t name_len,
+			   char *value_buf, size_t value_len ) {
+	struct settings *settings;
+	struct setting setting;
+	struct settings *origin;
+	char tmp_name[ strlen ( name ) + 1 ];
+	int len;
+	int rc;
+
+	/* Parse setting name */
+	if ( ( rc = parse_setting_name ( name, find_child_settings,
+					 &settings, &setting, tmp_name )) != 0)
+		return rc;
+
+	/* Fetch setting */
+	if ( ( len = fetchf_setting ( settings, &setting, value_buf,
+				     value_len ) ) < 0 )
+		return len;
+
+	/* Construct setting name */
+	origin = fetch_setting_origin ( settings, &setting );
+	assert ( origin != NULL );
+	setting_name ( origin, &setting, name_buf, name_len );
+
+	return len;
+}
+
+/******************************************************************************
+ *
+ * Setting types
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Parse and store value of string setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @ret rc		Return status code
+ */
+static int storef_string ( struct settings *settings, struct setting *setting,
+			   const char *value ) {
+	return store_setting ( settings, setting, value, strlen ( value ) );
+}
+
+/**
+ * Fetch and format value of string setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_string ( struct settings *settings, struct setting *setting,
+			   char *buf, size_t len ) {
+	return fetch_string_setting ( settings, setting, buf, len );
+}
+
+/** A string setting type */
+struct setting_type setting_type_string __setting_type = {
+	.name = "string",
+	.storef = storef_string,
+	.fetchf = fetchf_string,
+};
+
+/**
+ * Parse and store value of URI-encoded string setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @ret rc		Return status code
+ */
+static int storef_uristring ( struct settings *settings,
+			      struct setting *setting,
+			      const char *value ) {
+	char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */
+	size_t len;
+
+	len = uri_decode ( value, buf, sizeof ( buf ) );
+	return store_setting ( settings, setting, buf, len );
+}
+
+/**
+ * Fetch and format value of URI-encoded string setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_uristring ( struct settings *settings,
+			      struct setting *setting,
+			      char *buf, size_t len ) {
+	ssize_t raw_len;
+
+	/* We need to always retrieve the full raw string to know the
+	 * length of the encoded string.
+	 */
+	raw_len = fetch_setting ( settings, setting, NULL, 0 );
+	if ( raw_len < 0 )
+		return raw_len;
+
+	{
+		char raw_buf[ raw_len + 1 ];
+       
+		fetch_string_setting ( settings, setting, raw_buf,
+				       sizeof ( raw_buf ) );
+		return uri_encode ( raw_buf, buf, len, URI_FRAGMENT );
+	}
+}
+
+/** A URI-encoded string setting type */
+struct setting_type setting_type_uristring __setting_type = {
+	.name = "uristring",
+	.storef = storef_uristring,
+	.fetchf = fetchf_uristring,
+};
+
+/**
+ * Parse and store value of IPv4 address setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @ret rc		Return status code
+ */
+static int storef_ipv4 ( struct settings *settings, struct setting *setting,
+			 const char *value ) {
+	struct in_addr ipv4;
+
+	if ( inet_aton ( value, &ipv4 ) == 0 )
+		return -EINVAL;
+	return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
+}
+
+/**
+ * Fetch and format value of IPv4 address setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
+			 char *buf, size_t len ) {
+	struct in_addr ipv4;
+	int raw_len;
+
+	if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0)
+		return raw_len;
+	return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) );
+}
+
+/** An IPv4 address setting type */
+struct setting_type setting_type_ipv4 __setting_type = {
+	.name = "ipv4",
+	.storef = storef_ipv4,
+	.fetchf = fetchf_ipv4,
+};
+
+/**
+ * Parse and store value of integer setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @v size		Integer size, in bytes
+ * @ret rc		Return status code
+ */
+static int storef_int ( struct settings *settings, struct setting *setting,
+			const char *value, unsigned int size ) {
+	union {
+		uint32_t num;
+		uint8_t bytes[4];
+	} u;
+	char *endp;
+
+	u.num = htonl ( strtoul ( value, &endp, 0 ) );
+	if ( *endp )
+		return -EINVAL;
+	return store_setting ( settings, setting, 
+			       &u.bytes[ sizeof ( u ) - size ], size );
+}
+
+/**
+ * Parse and store value of 8-bit integer setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @v size		Integer size, in bytes
+ * @ret rc		Return status code
+ */
+static int storef_int8 ( struct settings *settings, struct setting *setting,
+			 const char *value ) {
+	return storef_int ( settings, setting, value, 1 );
+}
+
+/**
+ * Parse and store value of 16-bit integer setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @v size		Integer size, in bytes
+ * @ret rc		Return status code
+ */
+static int storef_int16 ( struct settings *settings, struct setting *setting,
+			  const char *value ) {
+	return storef_int ( settings, setting, value, 2 );
+}
+
+/**
+ * Parse and store value of 32-bit integer setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @v size		Integer size, in bytes
+ * @ret rc		Return status code
+ */
+static int storef_int32 ( struct settings *settings, struct setting *setting,
+			  const char *value ) {
+	return storef_int ( settings, setting, value, 4 );
+}
+
+/**
+ * Fetch and format value of signed integer setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_int ( struct settings *settings, struct setting *setting,
+			char *buf, size_t len ) {
+	long value;
+	int rc;
+
+	if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
+		return rc;
+	return snprintf ( buf, len, "%ld", value );
+}
+
+/**
+ * Fetch and format value of unsigned integer setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_uint ( struct settings *settings, struct setting *setting,
+			 char *buf, size_t len ) {
+	unsigned long value;
+	int rc;
+
+	if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
+		return rc;
+	return snprintf ( buf, len, "%#lx", value );
+}
+
+/** A signed 8-bit integer setting type */
+struct setting_type setting_type_int8 __setting_type = {
+	.name = "int8",
+	.storef = storef_int8,
+	.fetchf = fetchf_int,
+};
+
+/** A signed 16-bit integer setting type */
+struct setting_type setting_type_int16 __setting_type = {
+	.name = "int16",
+	.storef = storef_int16,
+	.fetchf = fetchf_int,
+};
+
+/** A signed 32-bit integer setting type */
+struct setting_type setting_type_int32 __setting_type = {
+	.name = "int32",
+	.storef = storef_int32,
+	.fetchf = fetchf_int,
+};
+
+/** An unsigned 8-bit integer setting type */
+struct setting_type setting_type_uint8 __setting_type = {
+	.name = "uint8",
+	.storef = storef_int8,
+	.fetchf = fetchf_uint,
+};
+
+/** An unsigned 16-bit integer setting type */
+struct setting_type setting_type_uint16 __setting_type = {
+	.name = "uint16",
+	.storef = storef_int16,
+	.fetchf = fetchf_uint,
+};
+
+/** An unsigned 32-bit integer setting type */
+struct setting_type setting_type_uint32 __setting_type = {
+	.name = "uint32",
+	.storef = storef_int32,
+	.fetchf = fetchf_uint,
+};
+
+/**
+ * Parse and store value of hex string setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @ret rc		Return status code
+ */
+static int storef_hex ( struct settings *settings, struct setting *setting,
+			const char *value ) {
+	char *ptr = ( char * ) value;
+	uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
+	unsigned int len = 0;
+
+	while ( 1 ) {
+		bytes[len++] = strtoul ( ptr, &ptr, 16 );
+		switch ( *ptr ) {
+		case '\0' :
+			return store_setting ( settings, setting, bytes, len );
+		case ':' :
+		case '-' :
+			ptr++;
+			break;
+		default :
+			return -EINVAL;
+		}
+	}
+}
+
+/**
+ * Fetch and format value of hex string setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @v delimiter		Byte delimiter
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_hex ( struct settings *settings, struct setting *setting,
+			char *buf, size_t len, const char *delimiter ) {
+	int raw_len;
+	int check_len;
+	int used = 0;
+	int i;
+
+	raw_len = fetch_setting_len ( settings, setting );
+	if ( raw_len < 0 )
+		return raw_len;
+
+	{
+		uint8_t raw[raw_len];
+
+		check_len = fetch_setting ( settings, setting, raw,
+					    sizeof ( raw ) );
+		if ( check_len < 0 )
+			return check_len;
+		assert ( check_len == raw_len );
+		
+		if ( len )
+			buf[0] = 0; /* Ensure that a terminating NUL exists */
+		for ( i = 0 ; i < raw_len ; i++ ) {
+			used += ssnprintf ( ( buf + used ), ( len - used ),
+					    "%s%02x", ( used ? delimiter : "" ),
+					    raw[i] );
+		}
+		return used;
+	}
+}
+
+/**
+ * Fetch and format value of hex string setting (using colon delimiter)
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_hex_colon ( struct settings *settings,
+			      struct setting *setting,
+			      char *buf, size_t len ) {
+	return fetchf_hex ( settings, setting, buf, len, ":" );
+}
+
+/**
+ * Fetch and format value of hex string setting (using hyphen delimiter)
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_hex_hyphen ( struct settings *settings,
+			       struct setting *setting,
+			       char *buf, size_t len ) {
+	return fetchf_hex ( settings, setting, buf, len, "-" );
+}
+
+/** A hex-string setting (colon-delimited) */
+struct setting_type setting_type_hex __setting_type = {
+	.name = "hex",
+	.storef = storef_hex,
+	.fetchf = fetchf_hex_colon,
+};
+
+/** A hex-string setting (hyphen-delimited) */
+struct setting_type setting_type_hexhyp __setting_type = {
+	.name = "hexhyp",
+	.storef = storef_hex,
+	.fetchf = fetchf_hex_hyphen,
+};
+
+/**
+ * Parse and store value of UUID setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v value		Formatted setting data
+ * @ret rc		Return status code
+ */
+static int storef_uuid ( struct settings *settings __unused,
+			 struct setting *setting __unused,
+			 const char *value __unused ) {
+	return -ENOTSUP;
+}
+
+/**
+ * Fetch and format value of UUID setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static int fetchf_uuid ( struct settings *settings, struct setting *setting,
+			 char *buf, size_t len ) {
+	union uuid uuid;
+	int raw_len;
+
+	if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0)
+		return raw_len;
+	return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
+}
+
+/** UUID setting type */
+struct setting_type setting_type_uuid __setting_type = {
+	.name = "uuid",
+	.storef = storef_uuid,
+	.fetchf = fetchf_uuid,
+};
+
+/******************************************************************************
+ *
+ * Setting expansion
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Expand variables within string
+ *
+ * @v string		String
+ * @ret expstr		Expanded string
+ *
+ * The expanded string is allocated with malloc() and the caller must
+ * eventually free() it.
+ */
+char * expand_settings ( const char *string ) {
+	char *expstr;
+	char *start;
+	char *end;
+	char *head;
+	char *name;
+	char *tail;
+	int setting_len;
+	int new_len;
+	char *tmp;
+
+	/* Obtain temporary modifiable copy of string */
+	expstr = strdup ( string );
+	if ( ! expstr )
+		return NULL;
+
+	/* Expand while expansions remain */
+	while ( 1 ) {
+
+		head = expstr;
+
+		/* Locate setting to be expanded */
+		start = NULL;
+		end = NULL;
+		for ( tmp = expstr ; *tmp ; tmp++ ) {
+			if ( ( tmp[0] == '$' ) && ( tmp[1] == '{' ) )
+				start = tmp;
+			if ( start && ( tmp[0] == '}' ) ) {
+				end = tmp;
+				break;
+			}
+		}
+		if ( ! end )
+			break;
+		*start = '\0';
+		name = ( start + 2 );
+		*end = '\0';
+		tail = ( end + 1 );
+
+		/* Determine setting length */
+		setting_len = fetchf_named_setting ( name, NULL, 0, NULL, 0 );
+		if ( setting_len < 0 )
+			setting_len = 0; /* Treat error as empty setting */
+
+		/* Read setting into temporary buffer */
+		{
+			char setting_buf[ setting_len + 1 ];
+
+			setting_buf[0] = '\0';
+			fetchf_named_setting ( name, NULL, 0, setting_buf,
+					       sizeof ( setting_buf ) );
+
+			/* Construct expanded string and discard old string */
+			tmp = expstr;
+			new_len = asprintf ( &expstr, "%s%s%s",
+					     head, setting_buf, tail );
+			free ( tmp );
+			if ( new_len < 0 )
+				return NULL;
+		}
+	}
+
+	return expstr;
+}
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** Hostname setting */
+struct setting hostname_setting __setting ( SETTING_HOST ) = {
+	.name = "hostname",
+	.description = "Host name",
+	.tag = DHCP_HOST_NAME,
+	.type = &setting_type_string,
+};
+
+/** Filename setting */
+struct setting filename_setting __setting ( SETTING_BOOT ) = {
+	.name = "filename",
+	.description = "Boot filename",
+	.tag = DHCP_BOOTFILE_NAME,
+	.type = &setting_type_string,
+};
+
+/** Root path setting */
+struct setting root_path_setting __setting ( SETTING_SANBOOT ) = {
+	.name = "root-path",
+	.description = "SAN root path",
+	.tag = DHCP_ROOT_PATH,
+	.type = &setting_type_string,
+};
+
+/** Username setting */
+struct setting username_setting __setting ( SETTING_AUTH ) = {
+	.name = "username",
+	.description = "User name",
+	.tag = DHCP_EB_USERNAME,
+	.type = &setting_type_string,
+};
+
+/** Password setting */
+struct setting password_setting __setting ( SETTING_AUTH ) = {
+	.name = "password",
+	.description = "Password",
+	.tag = DHCP_EB_PASSWORD,
+	.type = &setting_type_string,
+};
+
+/** Priority setting */
+struct setting priority_setting __setting ( SETTING_MISC ) = {
+	.name = "priority",
+	.description = "Settings priority",
+	.tag = DHCP_EB_PRIORITY,
+	.type = &setting_type_int8,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/core/string.c b/qemu-0.15.x/roms/ipxe/src/core/string.c
new file mode 100644
index 0000000..190007a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/string.c
@@ -0,0 +1,355 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2004 Tobias Lorenz
+ *
+ *  string handling functions
+ *  based on linux/lib/string.c
+ *
+ * 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.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe at informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+ 
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* *** FROM string.c *** */
+
+#ifndef __HAVE_ARCH_STRCPY
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char * strcpy(char * dest,const char *src)
+{
+	char *tmp = dest;
+
+	while ((*dest++ = *src++) != '\0')
+		/* nothing */;
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char * strncpy(char * dest,const char *src,size_t count)
+{
+	char *tmp = dest;
+
+	while (count-- && (*dest++ = *src++) != '\0')
+		/* nothing */;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ */
+char * strcat(char * dest, const char * src)
+{
+	char *tmp = dest;
+
+	while (*dest)
+		dest++;
+	while ((*dest++ = *src++) != '\0')
+		;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char * cs,const char * ct)
+{
+	register signed char __res;
+
+	while (1) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+	}
+
+	return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+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;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCASECMP
+int strcasecmp(const char *a, const char *b)
+{
+	while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
+	return((*a & ~0x20) - (*b & ~0x20));
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strchr(const char * s, int c)
+{
+	for(; *s != (char) c; ++s)
+		if (*s == '\0')
+			return NULL;
+	return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strrchr(const char * s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char * s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void * memset(void * s,int c,size_t count)
+{
+	char *xs = (char *) s;
+
+	while (count--)
+		*xs++ = c;
+
+	return s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+void * memcpy(void * dest,const void *src,size_t count)
+{
+	char *tmp = (char *) dest, *s = (char *) src;
+
+	while (count--)
+		*tmp++ = *s++;
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+void * memmove(void * dest,const void *src,size_t count)
+{
+	char *tmp, *s;
+
+	if (dest <= src) {
+		tmp = (char *) dest;
+		s = (char *) src;
+		while (count--)
+			*tmp++ = *s++;
+		}
+	else {
+		tmp = (char *) dest + count;
+		s = (char *) src + count;
+		while (count--)
+			*--tmp = *--s;
+		}
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+	const unsigned char *su1, *su2;
+	int res = 0;
+
+	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+		if ((res = *su1 - *su2) != 0)
+			break;
+	return res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+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
+
+#ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void * memchr(const void *s, int c, size_t n)
+{
+	const unsigned char *p = s;
+	while (n-- != 0) {
+        	if ((unsigned char)c == *p++) {
+			return (void *)(p-1);
+		}
+	}
+	return NULL;
+}
+
+#endif
+
+char * strndup(const char *s, size_t n)
+{
+        size_t len = strlen(s);
+        char *new;
+
+        if (len>n)
+                len = n;
+        new = malloc(len+1);
+        if (new) {
+                new[len] = '\0';
+                memcpy(new,s,len);
+        }
+        return new;
+}
+
+char * strdup(const char *s) {
+	return strndup(s, ~((size_t)0));
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/stringextra.c b/qemu-0.15.x/roms/ipxe/src/core/stringextra.c
new file mode 100644
index 0000000..0a50985
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/stringextra.c
@@ -0,0 +1,275 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2004 Tobias Lorenz
+ *
+ *  string handling functions
+ *  based on linux/lib/string.c
+ *
+ * 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.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe at informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+
+/*
+ * these are the standard string functions that are currently not used by
+ * any code in etherboot. put into a separate file to avoid linking them in
+ * with the rest of string.o
+ * if anything ever does want to use a function of these, consider moving
+ * the function in question back into string.c
+ */
+ 
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* *** FROM string.c *** */
+
+#ifndef __HAVE_ARCH_STRNICMP
+/**
+ * strnicmp - Case insensitive, length-limited string comparison
+ * @s1: One string
+ * @s2: The other string
+ * @len: the maximum number of characters to compare
+ */
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+	/* Yes, Virginia, it had better be unsigned */
+	unsigned char c1, c2;
+
+	c1 = 0;	c2 = 0;
+	if (len) {
+		do {
+			c1 = *s1; c2 = *s2;
+			s1++; s2++;
+			if (!c1)
+				break;
+			if (!c2)
+				break;
+			if (c1 == c2)
+				continue;
+			c1 = tolower(c1);
+			c2 = tolower(c2);
+			if (c1 != c2)
+				break;
+		} while (--len);
+	}
+	return (int)c1 - (int)c2;
+}
+#endif
+
+char * ___strtok;
+
+#ifndef __HAVE_ARCH_STRNCAT
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The maximum numbers of bytes to copy
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
+char * strncat(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	if (count) {
+		while (*dest)
+			dest++;
+		while ((*dest++ = *src++)) {
+			if (--count == 0) {
+				*dest = '\0';
+				break;
+			}
+		}
+	}
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+/**
+ * strspn - Calculate the length of the initial substring of @s which only
+ * 	contain letters in @accept
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
+size_t strspn(const char *s, const char *accept)
+{
+	const char *p;
+	const char *a;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (a = accept; *a != '\0'; ++a) {
+			if (*p == *a)
+				break;
+		}
+		if (*a == '\0')
+			return count;
+		++count;
+	}
+
+	return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCSPN
+/**
+ * strcspn - Calculate the length of the initial substring of @s which only
+ * 	contain letters not in @reject
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
+size_t strcspn(const char *s, const char *reject)
+{
+	const char *p;
+	const char *r;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (r = reject; *r != '\0'; ++r) {
+			if (*p == *r)
+				return count;
+		}
+		++count;
+	}
+
+	return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+/**
+ * strpbrk - Find the first occurrence of a set of characters
+ * @cs: The string to be searched
+ * @ct: The characters to search for
+ */
+char * strpbrk(const char * cs,const char * ct)
+{
+	const char *sc1,*sc2;
+
+	for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+		for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+			if (*sc1 == *sc2)
+				return (char *) sc1;
+		}
+	}
+	return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRTOK
+/**
+ * strtok - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * WARNING: strtok is deprecated, use strsep instead.
+ */
+char * strtok(char * s,const char * ct)
+{
+	char *sbegin, *send;
+
+	sbegin  = s ? s : ___strtok;
+	if (!sbegin) {
+		return NULL;
+	}
+	sbegin += strspn(sbegin,ct);
+	if (*sbegin == '\0') {
+		___strtok = NULL;
+		return( NULL );
+	}
+	send = strpbrk( sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	___strtok = send;
+	return (sbegin);
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSEP
+/**
+ * strsep - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * strsep() updates @s to point after the token, ready for the next call.
+ *
+ * It returns empty tokens, too, behaving exactly like the libc function
+ * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
+ * Same semantics, slimmer shape. ;)
+ */
+char * strsep(char **s, const char *ct)
+{
+	char *sbegin = *s, *end;
+
+	if (sbegin == NULL)
+		return NULL;
+
+	end = strpbrk(sbegin, ct);
+	if (end)
+		*end++ = '\0';
+	*s = end;
+
+	return sbegin;
+}
+#endif
+
+#ifndef __HAVE_ARCH_BCOPY
+/**
+ * bcopy - Copy one area of memory to another
+ * @src: Where to copy from
+ * @dest: Where to copy to
+ * @count: The size of the area.
+ *
+ * Note that this is the same as memcpy(), with the arguments reversed.
+ * memcpy() is the standard, bcopy() is a legacy BSD function.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+char * bcopy(const char * src, char * dest, int count)
+{
+	return memmove(dest,src,count);
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSCAN
+/**
+ * memscan - Find a character in an area of memory.
+ * @addr: The memory area
+ * @c: The byte to search for
+ * @size: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
+void * memscan(const void * addr, int c, size_t size)
+{
+	unsigned char * p = (unsigned char *) addr;
+
+	while (size) {
+		if (*p == c)
+			return (void *) p;
+		p++;
+		size--;
+	}
+  	return (void *) p;
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/core/strtoull.c b/qemu-0.15.x/roms/ipxe/src/core/strtoull.c
new file mode 100644
index 0000000..b1ceeb4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/strtoull.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ctype.h>
+
+/*
+ * Despite being exactly the same as strtoul() except the long long instead of
+ * long it ends up being much bigger so provide a separate implementation in a
+ * separate object so that it won't be linked in if not used.
+ */
+unsigned long long strtoull ( const char *p, char **endp, int base ) {
+	unsigned long long ret = 0;
+	unsigned int charval;
+
+	base = strtoul_base ( &p, base );
+
+	while ( 1 ) {
+		charval = strtoul_charval ( *p );
+		if ( charval >= ( unsigned int ) base )
+			break;
+		ret = ( ( ret * base ) + charval );
+		p++;
+	}
+
+	if ( endp )
+		*endp = ( char * ) p;
+
+	return ( ret );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/timer.c b/qemu-0.15.x/roms/ipxe/src/core/timer.c
new file mode 100644
index 0000000..096d07e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/timer.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <unistd.h>
+
+/**
+ * Delay for a fixed number of milliseconds
+ *
+ * @v msecs		Number of milliseconds for which to delay
+ */
+void mdelay ( unsigned long msecs ) {
+	while ( msecs-- )
+		udelay ( 1000 );
+}
+
+/**
+ * Delay for a fixed number of seconds
+ *
+ * @v secs		Number of seconds for which to delay
+ */
+unsigned int sleep ( unsigned int secs ) {
+	while ( secs-- )
+		mdelay ( 1000 );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/uri.c b/qemu-0.15.x/roms/ipxe/src/core/uri.c
new file mode 100644
index 0000000..ff49e47
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/uri.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Uniform Resource Identifiers
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <ipxe/vsprintf.h>
+#include <ipxe/uri.h>
+
+/**
+ * Dump URI for debugging
+ *
+ * @v uri		URI
+ */
+static void dump_uri ( struct uri *uri ) {
+	if ( ! uri )
+		return;
+	if ( uri->scheme )
+		DBG ( " scheme \"%s\"", uri->scheme );
+	if ( uri->opaque )
+		DBG ( " opaque \"%s\"", uri->opaque );
+	if ( uri->user )
+		DBG ( " user \"%s\"", uri->user );
+	if ( uri->password )
+		DBG ( " password \"%s\"", uri->password );
+	if ( uri->host )
+		DBG ( " host \"%s\"", uri->host );
+	if ( uri->port )
+		DBG ( " port \"%s\"", uri->port );
+	if ( uri->path )
+		DBG ( " path \"%s\"", uri->path );
+	if ( uri->query )
+		DBG ( " query \"%s\"", uri->query );
+	if ( uri->fragment )
+		DBG ( " fragment \"%s\"", uri->fragment );
+}
+
+/**
+ * Parse URI
+ *
+ * @v uri_string	URI as a string
+ * @ret uri		URI
+ *
+ * Splits a URI into its component parts.  The return URI structure is
+ * dynamically allocated and must eventually be freed by calling
+ * uri_put().
+ */
+struct uri * parse_uri ( const char *uri_string ) {
+	struct uri *uri;
+	char *raw;
+	char *tmp;
+	char *path;
+	char *authority;
+	int i;
+	size_t raw_len;
+
+	/* Allocate space for URI struct and a copy of the string */
+	raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
+	uri = zalloc ( sizeof ( *uri ) + raw_len );
+	if ( ! uri )
+		return NULL;
+	raw = ( ( ( char * ) uri ) + sizeof ( *uri ) );
+
+	/* Copy in the raw string */
+	memcpy ( raw, uri_string, raw_len );
+
+	/* Start by chopping off the fragment, if it exists */
+	if ( ( tmp = strchr ( raw, '#' ) ) ) {
+		*(tmp++) = '\0';
+		uri->fragment = tmp;
+	}
+
+	/* Identify absolute/relative URI.  We ignore schemes that are
+	 * apparently only a single character long, since otherwise we
+	 * misinterpret a DOS-style path name ("C:\path\to\file") as a
+	 * URI with scheme="C",opaque="\path\to\file".
+	 */
+	if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) {
+		/* Absolute URI: identify hierarchical/opaque */
+		uri->scheme = raw;
+		*(tmp++) = '\0';
+		if ( *tmp == '/' ) {
+			/* Absolute URI with hierarchical part */
+			path = tmp;
+		} else {
+			/* Absolute URI with opaque part */
+			uri->opaque = tmp;
+			path = NULL;
+		}
+	} else {
+		/* Relative URI */
+		path = raw;
+	}
+
+	/* If we don't have a path (i.e. we have an absolute URI with
+	 * an opaque portion, we're already finished processing
+	 */
+	if ( ! path )
+		goto done;
+
+	/* Chop off the query, if it exists */
+	if ( ( tmp = strchr ( path, '?' ) ) ) {
+		*(tmp++) = '\0';
+		uri->query = tmp;
+	}
+
+	/* Identify net/absolute/relative path */
+	if ( strncmp ( path, "//", 2 ) == 0 ) {
+		/* Net path.  If this is terminated by the first '/'
+		 * of an absolute path, then we have no space for a
+		 * terminator after the authority field, so shuffle
+		 * the authority down by one byte, overwriting one of
+		 * the two slashes.
+		 */
+		authority = ( path + 2 );
+		if ( ( tmp = strchr ( authority, '/' ) ) ) {
+			/* Shuffle down */
+			uri->path = tmp;
+			memmove ( ( authority - 1 ), authority,
+				  ( tmp - authority ) );
+			authority--;
+			*(--tmp) = '\0';
+		}
+	} else {
+		/* Absolute/relative path */
+		uri->path = path;
+		authority = NULL;
+	}
+
+	/* If we don't have an authority (i.e. we have a non-net
+	 * path), we're already finished processing
+	 */
+	if ( ! authority )
+		goto done;
+
+	/* Split authority into user[:password] and host[:port] portions */
+	if ( ( tmp = strchr ( authority, '@' ) ) ) {
+		/* Has user[:password] */
+		*(tmp++) = '\0';
+		uri->host = tmp;
+		uri->user = authority;
+		if ( ( tmp = strchr ( authority, ':' ) ) ) {
+			/* Has password */
+			*(tmp++) = '\0';
+			uri->password = tmp;
+		}
+	} else {
+		/* No user:password */
+		uri->host = authority;
+	}
+
+	/* Split host into host[:port] */
+	if ( ( tmp = strchr ( uri->host, ':' ) ) ) {
+		*(tmp++) = '\0';
+		uri->port = tmp;
+	}
+
+	/* Decode fields that should be decoded */
+	for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) {
+		const char *field = uri_get_field ( uri, i );
+		if ( field && ( URI_ENCODED & ( 1 << i ) ) )
+			uri_decode ( field, ( char * ) field,
+				     strlen ( field ) + 1 /* NUL */ );
+	}
+
+ done:
+	DBG ( "URI \"%s\" split into", uri_string );
+	dump_uri ( uri );
+	DBG ( "\n" );
+
+	return uri;
+}
+
+/**
+ * Get port from URI
+ *
+ * @v uri		URI, or NULL
+ * @v default_port	Default port to use if none specified in URI
+ * @ret port		Port
+ */
+unsigned int uri_port ( struct uri *uri, unsigned int default_port ) {
+	if ( ( ! uri ) || ( ! uri->port ) )
+		return default_port;
+	return ( strtoul ( uri->port, NULL, 0 ) );
+}
+
+/**
+ * Unparse URI
+ *
+ * @v buf		Buffer to fill with URI string
+ * @v size		Size of buffer
+ * @v uri		URI to write into buffer, or NULL
+ * @v fields		Bitmask of fields to include in URI string, or URI_ALL
+ * @ret len		Length of URI string
+ */
+int unparse_uri ( char *buf, size_t size, struct uri *uri,
+		  unsigned int fields ) {
+	/* List of characters that typically go before certain fields */
+	static char separators[] = { /* scheme */ 0, /* opaque */ ':',
+				     /* user */ 0, /* password */ ':',
+				     /* host */ '@', /* port */ ':',
+				     /* path */ 0, /* query */ '?',
+				     /* fragment */ '#' };
+	int used = 0;
+	int i;
+
+	DBG ( "URI unparsing" );
+	dump_uri ( uri );
+	DBG ( "\n" );
+
+	/* Ensure buffer is NUL-terminated */
+	if ( size )
+		buf[0] = '\0';
+
+	/* Special-case NULL URI */
+	if ( ! uri )
+		return 0;
+
+	/* Iterate through requested fields */
+	for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) {
+		const char *field = uri_get_field ( uri, i );
+		char sep = separators[i];
+
+		/* Ensure `fields' only contains bits for fields that exist */
+		if ( ! field )
+			fields &= ~( 1 << i );
+
+		/* Store this field if we were asked to */
+		if ( fields & ( 1 << i ) ) {
+			/* Print :// if we're non-opaque and had a scheme */
+			if ( ( fields & URI_SCHEME_BIT ) &&
+			     ( i > URI_OPAQUE ) ) {
+				used += ssnprintf ( buf + used, size - used,
+						    "://" );
+				/* Only print :// once */
+				fields &= ~URI_SCHEME_BIT;
+			}
+
+			/* Only print separator if an earlier field exists */
+			if ( sep && ( fields & ( ( 1 << i ) - 1 ) ) )
+				used += ssnprintf ( buf + used, size - used,
+						    "%c", sep );
+
+			/* Print contents of field, possibly encoded */
+			if ( URI_ENCODED & ( 1 << i ) )
+				used += uri_encode ( field, buf + used,
+						     size - used, i );
+			else
+				used += ssnprintf ( buf + used, size - used,
+						    "%s", field );
+		}
+	}
+
+	return used;
+}
+
+/**
+ * Duplicate URI
+ *
+ * @v uri		URI
+ * @ret uri		Duplicate URI
+ *
+ * Creates a modifiable copy of a URI.
+ */
+struct uri * uri_dup ( struct uri *uri ) {
+	size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 );
+	char buf[len];
+
+	unparse_uri ( buf, len, uri, URI_ALL );
+	return parse_uri ( buf );
+}
+
+/**
+ * Resolve base+relative path
+ *
+ * @v base_uri		Base path
+ * @v relative_uri	Relative path
+ * @ret resolved_uri	Resolved path
+ *
+ * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative
+ * path (e.g. "initrd.gz") and produces a new path
+ * (e.g. "/var/lib/tftpboot/initrd.gz").  Note that any non-directory
+ * portion of the base path will automatically be stripped; this
+ * matches the semantics used when resolving the path component of
+ * URIs.
+ */
+char * resolve_path ( const char *base_path,
+		      const char *relative_path ) {
+	size_t base_len = ( strlen ( base_path ) + 1 );
+	char base_path_copy[base_len];
+	char *base_tmp = base_path_copy;
+	char *resolved;
+
+	/* If relative path is absolute, just re-use it */
+	if ( relative_path[0] == '/' )
+		return strdup ( relative_path );
+
+	/* Create modifiable copy of path for dirname() */
+	memcpy ( base_tmp, base_path, base_len );
+	base_tmp = dirname ( base_tmp );
+
+	/* Process "./" and "../" elements */
+	while ( *relative_path == '.' ) {
+		relative_path++;
+		if ( *relative_path == 0 ) {
+			/* Do nothing */
+		} else if ( *relative_path == '/' ) {
+			relative_path++;
+		} else if ( *relative_path == '.' ) {
+			relative_path++;
+			if ( *relative_path == 0 ) {
+				base_tmp = dirname ( base_tmp );
+			} else if ( *relative_path == '/' ) {
+				base_tmp = dirname ( base_tmp );
+				relative_path++;
+			} else {
+				relative_path -= 2;
+				break;
+			}
+		} else {
+			relative_path--;
+			break;
+		}
+	}
+
+	/* Create and return new path */
+	if ( asprintf ( &resolved, "%s%s%s", base_tmp,
+			( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
+			  "" : "/" ), relative_path ) < 0 )
+		return NULL;
+
+	return resolved;
+}
+
+/**
+ * Resolve base+relative URI
+ *
+ * @v base_uri		Base URI, or NULL
+ * @v relative_uri	Relative URI
+ * @ret resolved_uri	Resolved URI
+ *
+ * Takes a base URI (e.g. "http://ipxe.org/kernels/vmlinuz" and a
+ * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI
+ * (e.g. "http://ipxe.org/initrds/initrd.gz").
+ */
+struct uri * resolve_uri ( struct uri *base_uri,
+			   struct uri *relative_uri ) {
+	struct uri tmp_uri;
+	char *tmp_path = NULL;
+	struct uri *new_uri;
+
+	/* If relative URI is absolute, just re-use it */
+	if ( uri_is_absolute ( relative_uri ) || ( ! base_uri ) )
+		return uri_get ( relative_uri );
+
+	/* Mangle URI */
+	memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
+	if ( relative_uri->path ) {
+		tmp_path = resolve_path ( ( base_uri->path ?
+					    base_uri->path : "/" ),
+					  relative_uri->path );
+		tmp_uri.path = tmp_path;
+		tmp_uri.query = relative_uri->query;
+		tmp_uri.fragment = relative_uri->fragment;
+	} else if ( relative_uri->query ) {
+		tmp_uri.query = relative_uri->query;
+		tmp_uri.fragment = relative_uri->fragment;
+	} else if ( relative_uri->fragment ) {
+		tmp_uri.fragment = relative_uri->fragment;
+	}
+
+	/* Create demangled URI */
+	new_uri = uri_dup ( &tmp_uri );
+	free ( tmp_path );
+	return new_uri;
+}
+
+/**
+ * Test for unreserved URI characters
+ *
+ * @v c			Character to test
+ * @v field		Field of URI in which character lies
+ * @ret is_unreserved	Character is an unreserved character
+ */
+static int is_unreserved_uri_char ( int c, int field ) {
+	/* According to RFC3986, the unreserved character set is
+	 *
+	 * A-Z a-z 0-9 - _ . ~
+	 *
+	 * but we also pass & ; = in queries, / in paths,
+	 * and everything in opaques
+	 */
+	int ok = ( isupper ( c ) || islower ( c ) || isdigit ( c ) ||
+		    ( c == '-' ) || ( c == '_' ) ||
+		    ( c == '.' ) || ( c == '~' ) );
+
+	if ( field == URI_QUERY )
+		ok = ok || ( c == ';' ) || ( c == '&' ) || ( c == '=' );
+
+	if ( field == URI_PATH )
+		ok = ok || ( c == '/' );
+
+	if ( field == URI_OPAQUE )
+		ok = 1;
+
+	return ok;
+}
+
+/**
+ * URI-encode string
+ *
+ * @v raw_string	String to be URI-encoded
+ * @v buf		Buffer to contain encoded string
+ * @v len		Length of buffer
+ * @v field		Field of URI in which string lies
+ * @ret len		Length of encoded string (excluding NUL)
+ */
+size_t uri_encode ( const char *raw_string, char *buf, ssize_t len,
+		    int field ) {
+	ssize_t remaining = len;
+	size_t used;
+	unsigned char c;
+
+	if ( len > 0 )
+		buf[0] = '\0';
+
+	while ( ( c = *(raw_string++) ) ) {
+		if ( is_unreserved_uri_char ( c, field ) ) {
+			used = ssnprintf ( buf, remaining, "%c", c );
+		} else {
+			used = ssnprintf ( buf, remaining, "%%%02X", c );
+		}
+		buf += used;
+		remaining -= used;
+	}
+
+	return ( len - remaining );
+}
+
+/**
+ * Decode URI-encoded string
+ *
+ * @v encoded_string	URI-encoded string
+ * @v buf		Buffer to contain decoded string
+ * @v len		Length of buffer
+ * @ret len		Length of decoded string (excluding NUL)
+ *
+ * This function may be used in-place, with @a buf the same as
+ * @a encoded_string.
+ */
+size_t uri_decode ( const char *encoded_string, char *buf, ssize_t len ) {
+	ssize_t remaining;
+	char hexbuf[3];
+	char *hexbuf_end;
+	unsigned char c;
+
+	for ( remaining = len; *encoded_string; remaining-- ) {
+		if ( *encoded_string == '%' ) {
+			encoded_string++;
+			snprintf ( hexbuf, sizeof ( hexbuf ), "%s",
+				   encoded_string );
+			c = strtoul ( hexbuf, &hexbuf_end, 16 );
+			encoded_string += ( hexbuf_end - hexbuf );
+		} else {
+			c = *(encoded_string++);
+		}
+		if ( remaining > 1 )
+			*buf++ = c;
+	}
+
+	if ( len )
+		*buf = 0;
+
+	return ( len - remaining );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/uuid.c b/qemu-0.15.x/roms/ipxe/src/core/uuid.c
new file mode 100644
index 0000000..d98553f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/uuid.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <ipxe/uuid.h>
+
+/** @file
+ *
+ * Universally unique IDs
+ *
+ */
+
+/**
+ * Convert UUID to printable string
+ *
+ * @v uuid		UUID
+ * @ret string		UUID in canonical form
+ */
+char * uuid_ntoa ( union uuid *uuid ) {
+	static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
+
+	sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+		  be32_to_cpu ( uuid->canonical.a ),
+		  be16_to_cpu ( uuid->canonical.b ),
+		  be16_to_cpu ( uuid->canonical.c ),
+		  be16_to_cpu ( uuid->canonical.d ),
+		  uuid->canonical.e[0], uuid->canonical.e[1],
+		  uuid->canonical.e[2], uuid->canonical.e[3],
+		  uuid->canonical.e[4], uuid->canonical.e[5] );
+	return buf;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/vsprintf.c b/qemu-0.15.x/roms/ipxe/src/core/vsprintf.c
new file mode 100644
index 0000000..b46d9c4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/vsprintf.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ipxe/console.h>
+#include <errno.h>
+#include <ipxe/vsprintf.h>
+
+/** @file */
+
+#define CHAR_LEN	0	/**< "hh" length modifier */
+#define SHORT_LEN	1	/**< "h" length modifier */
+#define INT_LEN		2	/**< no length modifier */
+#define LONG_LEN	3	/**< "l" length modifier */
+#define LONGLONG_LEN	4	/**< "ll" length modifier */
+#define SIZE_T_LEN	5	/**< "z" length modifier */
+
+static uint8_t type_sizes[] = {
+	[CHAR_LEN]	= sizeof ( char ),
+	[SHORT_LEN]	= sizeof ( short ),
+	[INT_LEN]	= sizeof ( int ),
+	[LONG_LEN]	= sizeof ( long ),
+	[LONGLONG_LEN]	= sizeof ( long long ),
+	[SIZE_T_LEN]	= sizeof ( size_t ),
+};
+
+/**
+ * Use lower-case for hexadecimal digits
+ *
+ * Note that this value is set to 0x20 since that makes for very
+ * efficient calculations.  (Bitwise-ORing with @c LCASE converts to a
+ * lower-case character, for example.)
+ */
+#define LCASE 0x20
+
+/**
+ * Use "alternate form"
+ *
+ * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to
+ * the number.
+ */
+#define ALT_FORM 0x02
+
+/**
+ * Format a hexadecimal number
+ *
+ * @v end		End of buffer to contain number
+ * @v num		Number to format
+ * @v width		Minimum field width
+ * @ret ptr		End of buffer
+ *
+ * Fills a buffer in reverse order with a formatted hexadecimal
+ * number.  The number will be zero-padded to the specified width.
+ * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be
+ * set.
+ *
+ * There must be enough space in the buffer to contain the largest
+ * number that this function can format.
+ */
+static char * format_hex ( char *end, unsigned long long num, int width,
+			   int flags ) {
+	char *ptr = end;
+	int case_mod;
+
+	/* Generate the number */
+	case_mod = flags & LCASE;
+	do {
+		*(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
+		num >>= 4;
+	} while ( num );
+
+	/* Zero-pad to width */
+	while ( ( end - ptr ) < width )
+		*(--ptr) = '0';
+
+	/* Add "0x" or "0X" if alternate form specified */
+	if ( flags & ALT_FORM ) {
+		*(--ptr) = 'X' | case_mod;
+		*(--ptr) = '0';
+	}
+
+	return ptr;
+}
+
+/**
+ * Format a decimal number
+ *
+ * @v end		End of buffer to contain number
+ * @v num		Number to format
+ * @v width		Minimum field width
+ * @ret ptr		End of buffer
+ *
+ * Fills a buffer in reverse order with a formatted decimal number.
+ * The number will be space-padded to the specified width.
+ *
+ * There must be enough space in the buffer to contain the largest
+ * number that this function can format.
+ */
+static char * format_decimal ( char *end, signed long num, int width ) {
+	char *ptr = end;
+	int negative = 0;
+
+	/* Generate the number */
+	if ( num < 0 ) {
+		negative = 1;
+		num = -num;
+	}
+	do {
+		*(--ptr) = '0' + ( num % 10 );
+		num /= 10;
+	} while ( num );
+
+	/* Add "-" if necessary */
+	if ( negative )
+		*(--ptr) = '-';
+
+	/* Space-pad to width */
+	while ( ( end - ptr ) < width )
+		*(--ptr) = ' ';
+
+	return ptr;
+}
+
+/**
+ * Print character via a printf context
+ *
+ * @v ctx		Context
+ * @v c			Character
+ *
+ * Call's the printf_context::handler() method and increments
+ * printf_context::len.
+ */
+static inline void cputchar ( struct printf_context *ctx, unsigned int c ) {
+	ctx->handler ( ctx, c );
+	++ctx->len;
+}
+
+/**
+ * Write a formatted string to a printf context
+ *
+ * @v ctx		Context
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
+	int flags;
+	int width;
+	uint8_t *length;
+	char *ptr;
+	char tmp_buf[32]; /* 32 is enough for all numerical formats.
+			   * Insane width fields could overflow this buffer. */
+
+	/* Initialise context */
+	ctx->len = 0;
+
+	for ( ; *fmt ; fmt++ ) {
+		/* Pass through ordinary characters */
+		if ( *fmt != '%' ) {
+			cputchar ( ctx, *fmt );
+			continue;
+		}
+		fmt++;
+		/* Process flag characters */
+		flags = 0;
+		for ( ; ; fmt++ ) {
+			if ( *fmt == '#' ) {
+				flags |= ALT_FORM;
+			} else if ( *fmt == '0' ) {
+				/* We always 0-pad hex and space-pad decimal */
+			} else {
+				/* End of flag characters */
+				break;
+			}
+		}
+		/* Process field width */
+		width = 0;
+		for ( ; ; fmt++ ) {
+			if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
+				width = ( width * 10 ) + ( *fmt - '0' );
+			} else {
+				break;
+			}
+		}
+		/* We don't do floating point */
+		/* Process length modifier */
+		length = &type_sizes[INT_LEN];
+		for ( ; ; fmt++ ) {
+			if ( *fmt == 'h' ) {
+				length--;
+			} else if ( *fmt == 'l' ) {
+				length++;
+			} else if ( *fmt == 'z' ) {
+				length = &type_sizes[SIZE_T_LEN];
+			} else {
+				break;
+			}
+		}
+		/* Process conversion specifier */
+		ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
+		*ptr = '\0';
+		if ( *fmt == 'c' ) {
+			cputchar ( ctx, va_arg ( args, unsigned int ) );
+		} else if ( *fmt == 's' ) {
+			ptr = va_arg ( args, char * );
+			if ( ! ptr )
+				ptr = "<NULL>";
+		} else if ( *fmt == 'p' ) {
+			intptr_t ptrval;
+
+			ptrval = ( intptr_t ) va_arg ( args, void * );
+			ptr = format_hex ( ptr, ptrval, width, 
+					   ( ALT_FORM | LCASE ) );
+		} else if ( ( *fmt & ~0x20 ) == 'X' ) {
+			unsigned long long hex;
+
+			flags |= ( *fmt & 0x20 ); /* LCASE */
+			if ( *length >= sizeof ( unsigned long long ) ) {
+				hex = va_arg ( args, unsigned long long );
+			} else if ( *length >= sizeof ( unsigned long ) ) {
+				hex = va_arg ( args, unsigned long );
+			} else {
+				hex = va_arg ( args, unsigned int );
+			}
+			ptr = format_hex ( ptr, hex, width, flags );
+		} else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){
+			signed long decimal;
+
+			if ( *length >= sizeof ( signed long ) ) {
+				decimal = va_arg ( args, signed long );
+			} else {
+				decimal = va_arg ( args, signed int );
+			}
+			ptr = format_decimal ( ptr, decimal, width );
+		} else {
+			*(--ptr) = *fmt;
+		}
+		/* Write out conversion result */
+		for ( ; *ptr ; ptr++ ) {
+			cputchar ( ctx, *ptr );
+		}
+	}
+
+	return ctx->len;
+}
+
+/** Context used by vsnprintf() and friends */
+struct sputc_context {
+	struct printf_context ctx;
+	/** Buffer for formatted string (used by printf_sputc()) */
+	char *buf;
+	/** Buffer length (used by printf_sputc()) */
+	size_t max_len;	
+};
+
+/**
+ * Write character to buffer
+ *
+ * @v ctx		Context
+ * @v c			Character
+ */
+static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
+	struct sputc_context * sctx =
+		container_of ( ctx, struct sputc_context, ctx );
+
+	if ( ctx->len < sctx->max_len )
+		sctx->buf[ctx->len] = c;
+}
+
+/**
+ * Write a formatted string to a buffer
+ *
+ * @v buf		Buffer into which to write the string
+ * @v size		Size of buffer
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ *
+ * If the buffer is too small to contain the string, the returned
+ * length is the length that would have been written had enough space
+ * been available.
+ */
+int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
+	struct sputc_context sctx;
+	size_t len;
+	size_t end;
+
+	/* Hand off to vcprintf */
+	sctx.ctx.handler = printf_sputc;
+	sctx.buf = buf;
+	sctx.max_len = size;
+	len = vcprintf ( &sctx.ctx, fmt, args );
+
+	/* Add trailing NUL */
+	if ( size ) {
+		end = size - 1;
+		if ( len < end )
+			end = len;
+		buf[end] = '\0';
+	}
+
+	return len;
+}
+
+/**
+ * Write a formatted string to a buffer
+ *
+ * @v buf		Buffer into which to write the string
+ * @v size		Size of buffer
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret len		Length of formatted 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;
+}
+
+/**
+ * Version of vsnprintf() that accepts a signed buffer size
+ *
+ * @v buf		Buffer into which to write the string
+ * @v size		Size of buffer
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
+
+	/* Treat negative buffer size as zero buffer size */
+	if ( ssize < 0 )
+		ssize = 0;
+
+	/* Hand off to vsnprintf */
+	return vsnprintf ( buf, ssize, fmt, args );
+}
+
+/**
+ * Version of vsnprintf() that accepts a signed buffer size
+ *
+ * @v buf		Buffer into which to write the string
+ * @v size		Size of buffer
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
+	va_list args;
+	int len;
+
+	/* Hand off to vssnprintf */
+	va_start ( args, fmt );
+	len = vssnprintf ( buf, ssize, fmt, args );
+	va_end ( args );
+	return len;
+}
+
+/**
+ * Write character to console
+ *
+ * @v ctx		Context
+ * @v c			Character
+ */
+static void printf_putchar ( struct printf_context *ctx __unused,
+			     unsigned int c ) {
+	putchar ( c );
+}
+
+/**
+ * Write a formatted string to the console
+ *
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+int vprintf ( const char *fmt, va_list args ) {
+	struct printf_context ctx;
+
+	/* Hand off to vcprintf */
+	ctx.handler = printf_putchar;	
+	return vcprintf ( &ctx, fmt, args );	
+}
+
+/**
+ * Write a formatted string to the console.
+ *
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret	len		Length of formatted string
+ */
+int printf ( const char *fmt, ... ) {
+	va_list args;
+	int i;
+
+	va_start ( args, fmt );
+	i = vprintf ( fmt, args );
+	va_end ( args );
+	return i;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/core/xfer.c b/qemu-0.15.x/roms/ipxe/src/core/xfer.c
new file mode 100644
index 0000000..a755d43
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/core/xfer.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+
+/** @file
+ *
+ * Data transfer interfaces
+ *
+ */
+
+/**
+ * Dummy transfer metadata
+ *
+ * This gets passed to xfer_interface::deliver() and equivalents when
+ * no metadata is available.
+ */
+static struct xfer_metadata dummy_metadata;
+
+/*****************************************************************************
+ *
+ * Data transfer interface operations
+ *
+ */
+
+/**
+ * Send redirection event
+ *
+ * @v intf		Data transfer interface
+ * @v type		New location type
+ * @v args		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ */
+int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
+	struct interface *dest;
+	xfer_vredirect_TYPE ( void * ) *op =
+		intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect\n",
+	       INTF_INTF_DBG ( intf, dest ) );
+
+	if ( op ) {
+		rc = op ( object, type, args );
+	} else {
+		/* Default is to reopen the interface as instructed */
+		rc = xfer_vreopen ( dest, type, args );
+	}
+
+	if ( rc != 0 ) {
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect "
+		       "failed: %s\n", INTF_INTF_DBG ( intf, dest ),
+		       strerror ( rc ) );
+	}
+
+	intf_put ( dest );
+	return rc;
+}
+
+/**
+ * Check flow control window
+ *
+ * @v intf		Data transfer interface
+ * @ret len		Length of window
+ */
+size_t xfer_window ( struct interface *intf ) {
+	struct interface *dest;
+	xfer_window_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, xfer_window, &dest );
+	void *object = intf_object ( dest );
+	size_t len;
+
+	if ( op ) {
+		len = op ( object );
+	} else {
+		/* Default is to provide an unlimited window */
+		len = ~( ( size_t ) 0 );
+	}
+
+	intf_put ( dest );
+	return len;
+}
+
+/**
+ * Report change of flow control window
+ *
+ * @v intf		Data transfer interface
+ *
+ * Note that this method is used to indicate only unsolicited changes
+ * in the flow control window.  In particular, this method must not be
+ * called as part of the response to xfer_deliver(), since that could
+ * easily lead to an infinite loop.  Callers of xfer_deliver() should
+ * assume that the flow control window will have changed without
+ * generating an xfer_window_changed() message.
+ */
+void xfer_window_changed ( struct interface *intf ) {
+	struct interface *dest;
+	xfer_window_changed_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, xfer_window_changed, &dest );
+	void *object = intf_object ( dest );
+
+	if ( op ) {
+		op ( object );
+	} else {
+		/* Default is to do nothing */
+	}
+
+	intf_put ( dest );
+}
+
+/**
+ * Allocate I/O buffer
+ *
+ * @v intf		Data transfer interface
+ * @v len		I/O buffer payload length
+ * @ret iobuf		I/O buffer
+ */
+struct io_buffer * xfer_alloc_iob ( struct interface *intf, size_t len ) {
+	struct interface *dest;
+	xfer_alloc_iob_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, xfer_alloc_iob, &dest );
+	void *object = intf_object ( dest );
+	struct io_buffer *iobuf;
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob %zd\n",
+	       INTF_INTF_DBG ( intf, dest ), len );
+
+	if ( op ) {
+		iobuf = op ( object, len );
+	} else {
+		/* Default is to allocate an I/O buffer with no
+		 * reserved space.
+		 */
+		iobuf = alloc_iob ( len );
+	}
+
+	if ( ! iobuf ) {
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob "
+		       "failed\n", INTF_INTF_DBG ( intf, dest ) );
+	}
+
+	intf_put ( dest );
+	return iobuf;
+}
+
+/**
+ * Deliver datagram
+ *
+ * @v intf		Data transfer interface
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+int xfer_deliver ( struct interface *intf,
+		   struct io_buffer *iobuf,
+		   struct xfer_metadata *meta ) {
+	struct interface *dest;
+	xfer_deliver_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, xfer_deliver, &dest );
+	void *object = intf_object ( dest );
+	int rc;
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n",
+	       INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) );
+
+	if ( op ) {
+		rc = op ( object, iobuf, meta );
+	} else {
+		/* Default is to discard the I/O buffer */
+		free_iob ( iobuf );
+		rc = -EPIPE;
+	}
+
+	if ( rc != 0 ) {
+		DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT
+		       " deliver failed: %s\n",
+		       INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
+	}
+
+	intf_put ( dest );
+	return rc;
+}
+
+/*****************************************************************************
+ *
+ * Data transfer interface helper functions
+ *
+ */
+
+/**
+ * Send redirection event
+ *
+ * @v intf		Data transfer interface
+ * @v type		New location type
+ * @v ...		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ */
+int xfer_redirect ( struct interface *intf, int type, ... ) {
+	va_list args;
+	int rc;
+
+	va_start ( args, type );
+	rc = xfer_vredirect ( intf, type, args );
+	va_end ( args );
+	return rc;
+}
+
+/**
+ * Deliver datagram as I/O buffer without metadata
+ *
+ * @v intf		Data transfer interface
+ * @v iobuf		Datagram I/O buffer
+ * @ret rc		Return status code
+ */
+int xfer_deliver_iob ( struct interface *intf, struct io_buffer *iobuf ) {
+	return xfer_deliver ( intf, iobuf, &dummy_metadata );
+}
+
+/**
+ * Deliver datagram as raw data
+ *
+ * @v intf		Data transfer interface
+ * @v data		Data
+ * @v len		Length of data
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+int xfer_deliver_raw_meta ( struct interface *intf, const void *data,
+			    size_t len, struct xfer_metadata *meta ) {
+	struct io_buffer *iobuf;
+
+	iobuf = xfer_alloc_iob ( intf, len );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	memcpy ( iob_put ( iobuf, len ), data, len );
+	return xfer_deliver ( intf, iobuf, meta );
+}
+
+/**
+ * Deliver datagram as raw data without metadata
+ *
+ * @v intf		Data transfer interface
+ * @v data		Data
+ * @v len		Length of data
+ * @ret rc		Return status code
+ */
+int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
+	return xfer_deliver_raw_meta ( intf, data, len, &dummy_metadata );
+}
+
+/**
+ * Deliver formatted string
+ *
+ * @v intf		Data transfer interface
+ * @v format		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret rc		Return status code
+ */
+int xfer_vprintf ( struct interface *intf, const char *format,
+		   va_list args ) {
+	size_t len;
+	va_list args_tmp;
+
+	va_copy ( args_tmp, args );
+	len = vsnprintf ( NULL, 0, format, args );
+	{
+		char buf[len + 1];
+		vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
+		va_end ( args_tmp );
+		return xfer_deliver_raw ( intf, buf, len );
+	}
+}
+
+/**
+ * Deliver formatted string
+ *
+ * @v intf		Data transfer interface
+ * @v format		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret rc		Return status code
+ */
+int xfer_printf ( struct interface *intf, const char *format, ... ) {
+	va_list args;
+	int rc;
+
+	va_start ( args, format );
+	rc = xfer_vprintf ( intf, format, args );
+	va_end ( args );
+	return rc;
+}
+
+/**
+ * Seek to position
+ *
+ * @v intf		Data transfer interface
+ * @v offset		Offset to new position
+ * @ret rc		Return status code
+ */
+int xfer_seek ( struct interface *intf, off_t offset ) {
+	struct io_buffer *iobuf;
+	struct xfer_metadata meta = {
+		.flags = XFER_FL_ABS_OFFSET,
+		.offset = offset,
+	};
+
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n",
+	       INTF_DBG ( intf ), offset );
+
+	/* Allocate and send a zero-length data buffer */
+	iobuf = xfer_alloc_iob ( intf, 0 );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	return xfer_deliver ( intf, iobuf, &meta );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/aes_wrap.c b/qemu-0.15.x/roms/ipxe/src/crypto/aes_wrap.c
new file mode 100644
index 0000000..46ef016
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/aes_wrap.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/crypto.h>
+#include <ipxe/aes.h>
+
+/**
+ * Wrap a key or other data using AES Key Wrap (RFC 3394)
+ *
+ * @v kek	Key Encryption Key, 16 bytes
+ * @v src	Data to encrypt
+ * @v nblk	Number of 8-byte blocks in @a data
+ * @ret dest	Encrypted data (8 bytes longer than input)
+ *
+ * The algorithm is implemented such that @a src and @a dest may point
+ * to the same buffer.
+ */
+int aes_wrap ( const void *kek, const void *src, void *dest, int nblk )
+{
+	u8 *A = dest;
+	u8 B[16];
+	u8 *R;
+	int i, j;
+	void *aes_ctx = malloc ( AES_CTX_SIZE );
+
+	if ( ! aes_ctx )
+		return -1;
+
+	cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
+
+	/* Set up */
+	memset ( A, 0xA6, sizeof ( A ) );
+	memmove ( dest + 8, src, nblk * 8 );
+
+	/* Wrap */
+	for ( j = 0; j < 6; j++ ) {
+		R = dest + 8;
+		for ( i = 1; i <= nblk; i++ ) {
+			memcpy ( B, A, 8 );
+			memcpy ( B + 8, R, 8 );
+			cipher_encrypt ( &aes_algorithm, aes_ctx, B, B, 16 );
+			memcpy ( A, B, 8 );
+			A[7] ^= ( nblk * j ) + i;
+			memcpy ( R, B + 8, 8 );
+			R += 8;
+		}
+	}
+
+	free ( aes_ctx );
+	return 0;
+}
+
+/**
+ * Unwrap a key or other data using AES Key Wrap (RFC 3394)
+ *
+ * @v kek	Key Encryption Key, 16 bytes
+ * @v src	Data to decrypt
+ * @v nblk	Number of 8-byte blocks in @e plaintext key
+ * @ret dest	Decrypted data (8 bytes shorter than input)
+ * @ret rc	Zero on success, nonzero on IV mismatch
+ *
+ * The algorithm is implemented such that @a src and @a dest may point
+ * to the same buffer.
+ */
+int aes_unwrap ( const void *kek, const void *src, void *dest, int nblk )
+{
+	u8 A[8], B[16];
+	u8 *R;
+	int i, j;
+	void *aes_ctx = malloc ( AES_CTX_SIZE );
+
+	if ( ! aes_ctx )
+		return -1;
+
+	cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
+
+	/* Set up */
+	memcpy ( A, src, 8 );
+	memmove ( dest, src + 8, nblk * 8 );
+
+	/* Unwrap */
+	for ( j = 5; j >= 0; j-- ) {
+		R = dest + ( nblk - 1 ) * 8;
+		for ( i = nblk; i >= 1; i-- ) {
+			memcpy ( B, A, 8 );
+			memcpy ( B + 8, R, 8 );
+			B[7] ^= ( nblk * j ) + i;
+			cipher_decrypt ( &aes_algorithm, aes_ctx, B, B, 16 );
+			memcpy ( A, B, 8 );
+			memcpy ( R, B + 8, 8 );
+			R -= 8;
+		}
+	}
+
+	free ( aes_ctx );
+
+	/* Check IV */
+	for ( i = 0; i < 8; i++ ) {
+		if ( A[i] != 0xA6 )
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/arc4.c b/qemu-0.15.x/roms/ipxe/src/crypto/arc4.c
new file mode 100644
index 0000000..ab3325c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/arc4.c
@@ -0,0 +1,131 @@
+/*
+ * The ARC4 stream cipher.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crypto.h>
+#include <ipxe/arc4.h>
+
+#define SWAP( ary, i, j )	\
+	({ u8 temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; })
+
+/**
+ * Set ARC4 key
+ *
+ * @v ctxv	ARC4 encryption context
+ * @v keyv	Key to set
+ * @v keylen	Length of key
+ *
+ * If an initialisation vector is to be used, it should be prepended
+ * to the key; ARC4 does not implement the @c setiv function because
+ * there is no standard length for an initialisation vector in the
+ * cipher.
+ */
+static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen )
+{
+	struct arc4_ctx *ctx = ctxv;
+	const u8 *key = keyv;
+	u8 *S = ctx->state;
+	int i, j;
+
+	for ( i = 0; i < 256; i++ ) {
+		S[i] = i;
+	}
+
+	for ( i = j = 0; i < 256; i++ ) {
+		j = ( j + S[i] + key[i % keylen] ) & 0xff;
+		SWAP ( S, i, j );
+	}
+
+	ctx->i = ctx->j = 0;
+	return 0;
+}
+
+/**
+ * Perform ARC4 encryption or decryption
+ *
+ * @v ctxv	ARC4 encryption context
+ * @v srcv	Data to encrypt or decrypt
+ * @v dstv	Location to store encrypted or decrypted data
+ * @v len	Length of data to operate on
+ *
+ * ARC4 is a stream cipher that works by generating a stream of PRNG
+ * data based on the key, and XOR'ing it with the data to be
+ * encrypted. Since XOR is symmetric, encryption and decryption in
+ * ARC4 are the same operation.
+ *
+ * If you pass a @c NULL source or destination pointer, @a len
+ * keystream bytes will be consumed without encrypting any data.
+ */
+static void arc4_xor ( void *ctxv, const void *srcv, void *dstv,
+		       size_t len )
+{
+	struct arc4_ctx *ctx = ctxv;
+	const u8 *src = srcv;
+	u8 *dst = dstv;
+	u8 *S = ctx->state;
+	int i = ctx->i, j = ctx->j;
+
+	while ( len-- ) {
+		i = ( i + 1 ) & 0xff;
+		j = ( j + S[i] ) & 0xff;
+		SWAP ( S, i, j );
+		if ( srcv && dstv )
+			*dst++ = *src++ ^ S[(S[i] + S[j]) & 0xff];
+	}
+
+	ctx->i = i;
+	ctx->j = j;
+}
+
+static void arc4_setiv ( void *ctx __unused, const void *iv __unused )
+{
+	/* ARC4 does not use a fixed-length IV */
+}
+
+
+/**
+ * Perform ARC4 encryption or decryption, skipping initial keystream bytes
+ *
+ * @v key	ARC4 encryption key
+ * @v keylen	Key length
+ * @v skip	Number of bytes of keystream to skip
+ * @v src	Message to encrypt or decrypt
+ * @v msglen	Length of message
+ * @ret dst	Encrypted or decrypted message
+ */
+void arc4_skip ( const void *key, size_t keylen, size_t skip,
+		 const void *src, void *dst, size_t msglen )
+{
+	struct arc4_ctx ctx;
+	arc4_setkey ( &ctx, key, keylen );
+	arc4_xor ( &ctx, NULL, NULL, skip );
+	arc4_xor ( &ctx, src, dst, msglen );
+}
+
+struct cipher_algorithm arc4_algorithm = {
+	.name = "ARC4",
+	.ctxsize = ARC4_CTX_SIZE,
+	.blocksize = 1,
+	.setkey = arc4_setkey,
+	.setiv = arc4_setiv,
+	.encrypt = arc4_xor,
+	.decrypt = arc4_xor,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/asn1.c b/qemu-0.15.x/roms/ipxe/src/crypto/asn1.c
new file mode 100644
index 0000000..a54d31d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/asn1.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+
+/** @file
+ *
+ * ASN.1 encoding
+ *
+ */
+
+/**
+ * Start parsing ASN.1 object
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v type		Expected type
+ * @ret len		Length of object body, or negative error
+ *
+ * The object cursor will be updated to point to the start of the
+ * object body (i.e. the first byte following the length byte(s)), and
+ * the length of the object body (i.e. the number of bytes until the
+ * following object tag, if any) is returned.
+ *
+ * If any error occurs (i.e. if the object is not of the expected
+ * type, or if we overflow beyond the end of the ASN.1 object), then
+ * the cursor will be invalidated and a negative value will be
+ * returned.
+ */
+static int asn1_start ( struct asn1_cursor *cursor,
+			       unsigned int type ) {
+	unsigned int len_len;
+	unsigned int len;
+	int rc;
+
+	/* Sanity check */
+	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
+		if ( cursor->len )
+			DBGC ( cursor, "ASN1 %p too short\n", cursor );
+		rc = -EINVAL;
+		goto notfound;
+	}
+
+	/* Check the tag byte */
+	if ( *( ( uint8_t * ) cursor->data ) != type ) {
+		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
+		       cursor, type, *( ( uint8_t * ) cursor->data ) );
+		rc = -ENXIO;
+		goto notfound;
+	}
+	cursor->data++;
+	cursor->len--;
+
+	/* Extract length of the length field and sanity check */
+	len_len = *( ( uint8_t * ) cursor->data );
+	if ( len_len & 0x80 ) {
+		len_len = ( len_len & 0x7f );
+		cursor->data++;
+		cursor->len--;
+	} else {
+		len_len = 1;
+	}
+	if ( cursor->len < len_len ) {
+		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
+		       "%zd)\n", cursor, len_len, cursor->len );
+		rc = -EINVAL;
+		goto notfound;
+	}
+
+	/* Extract the length and sanity check */
+	for ( len = 0 ; len_len ; len_len-- ) {
+		len <<= 8;
+		len |= *( ( uint8_t * ) cursor->data );
+		cursor->data++;
+		cursor->len--;
+	}
+	if ( cursor->len < len ) {
+		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
+		       cursor, len, cursor->len );
+		rc = -EINVAL;
+		goto notfound;
+	}
+
+	return len;
+
+ notfound:
+	cursor->data = NULL;
+	cursor->len = 0;
+	return rc;
+}
+
+/**
+ * Enter ASN.1 object
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v type		Expected type
+ * @ret rc		Return status code
+ *
+ * The object cursor will be updated to point to the body of the
+ * current ASN.1 object.  If any error occurs, the object cursor will
+ * be invalidated.
+ */
+int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
+	int len;
+
+	len = asn1_start ( cursor, type );
+	if ( len < 0 )
+		return len;
+
+	cursor->len = len;
+	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
+	       cursor, type, len );
+
+	return 0;
+}
+
+/**
+ * Skip ASN.1 object
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v type		Expected type
+ * @ret rc		Return status code
+ *
+ * The object cursor will be updated to point to the next ASN.1
+ * object.  If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
+	int len;
+
+	len = asn1_start ( cursor, type );
+	if ( len < 0 )
+		return len;
+
+	cursor->data += len;
+	cursor->len -= len;
+	DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
+	       cursor, type, len );
+
+	if ( ! cursor->len ) {
+		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
+		cursor->data = NULL;
+		return -ENOENT;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/aes.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/aes.c
new file mode 100644
index 0000000..87faaa1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/aes.c
@@ -0,0 +1,478 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large 
+ * submix tables).
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) <<  8) | ((x) >> 24))
+
+/* 
+ * This cute trick does 4 'mul by two' at once.  Stolen from
+ * Dr B. R. Gladman <brg at gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx   0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000   0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001   0000 0000 we then subtract (c) from (b)
+ * d 0111 1111   0000 0000 and now we and with our mask
+ * e 0001 1011   0000 0000
+ */
+#define mt  0x80808080
+#define ml  0x7f7f7f7f
+#define mh  0xfefefefe
+#define mm  0x1b1b1b1b
+#define mul2(x,t)	((t)=((x)&mt), \
+			((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+			(f2)=mul2(x,f2), \
+			(f4)=mul2(f2,f4), \
+			(f8)=mul2(f4,f8), \
+			(f9)=(x)^(f8), \
+			(f8)=((f2)^(f4)^(f8)), \
+			(f2)^=(f9), \
+			(f4)^=(f9), \
+			(f8)^=rot3(f2), \
+			(f8)^=rot2(f4), \
+			(f8)^rot1(f9))
+
+/* some macros to do endian independent byte extraction */
+#define n2l(c,l) l=ntohl(*c); c++
+#define l2n(l,c) *c++=htonl(l)
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+	0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+	0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+	0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+	0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+	0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+	0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+	0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+	0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+	0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+	0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+	0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+	0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+	0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+	0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+	0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+	0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+	0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+	0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+	0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+	0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+	0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+	0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+	0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+	0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+	0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+	0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+	0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+	0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+	0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+	0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+	0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+	0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] = 
+{
+    0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+    0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+    0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+    0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+    0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+    0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+    0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+    0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+    0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+    0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+    0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+    0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+    0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+    0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+    0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+    0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+    0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+    0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+    0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+    0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+    0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+    0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+    0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+    0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+    0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+    0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+    0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+    0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+    0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+    0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+    0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+    0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+	0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+	0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+	0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+	0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+   x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+	return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key, 
+        const uint8_t *iv, AES_MODE mode)
+{
+    int i, ii;
+    uint32_t *W, tmp, tmp2;
+    const unsigned char *ip;
+    int words;
+
+    switch (mode)
+    {
+        case AES_MODE_128:
+            i = 10;
+            words = 4;
+            break;
+
+        case AES_MODE_256:
+            i = 14;
+            words = 8;
+            break;
+
+        default:        /* fail silently */
+            return;
+    }
+
+    ctx->rounds = i;
+    ctx->key_size = words;
+    W = ctx->ks;
+    for (i = 0; i < words; i+=2)
+    {
+        W[i+0]=	((uint32_t)key[ 0]<<24)|
+            ((uint32_t)key[ 1]<<16)|
+            ((uint32_t)key[ 2]<< 8)|
+            ((uint32_t)key[ 3]    );
+        W[i+1]=	((uint32_t)key[ 4]<<24)|
+            ((uint32_t)key[ 5]<<16)|
+            ((uint32_t)key[ 6]<< 8)|
+            ((uint32_t)key[ 7]    );
+        key += 8;
+    }
+
+    ip = Rcon;
+    ii = 4 * (ctx->rounds+1);
+    for (i = words; i<ii; i++)
+    {
+        tmp = W[i-1];
+
+        if ((i % words) == 0)
+        {
+            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]<< 8;
+            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ];
+            tmp=tmp2^(((unsigned int)*ip)<<24);
+            ip++;
+        }
+
+        if ((words == 8) && ((i % words) == 4))
+        {
+            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]    ;
+            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ]<<24;
+            tmp=tmp2;
+        }
+
+        W[i]=W[i-words]^tmp;
+    }
+
+    /* copy the iv across */
+    memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+    int i;
+    uint32_t *k,w,t1,t2,t3,t4;
+
+    k = ctx->ks;
+    k += 4;
+
+    for (i=ctx->rounds*4; i>4; i--)
+    {
+        w= *k;
+        w = inv_mix_col(w,t1,t2,t3,t4);
+        *k++ =w;
+    }
+}
+
+#if 0
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+    uint32_t tin0, tin1, tin2, tin3;
+    uint32_t tout0, tout1, tout2, tout3;
+    uint32_t tin[4];
+    uint32_t *iv = (uint32_t *)ctx->iv;
+    uint32_t *msg_32 = (uint32_t *)msg;
+    uint32_t *out_32 = (uint32_t *)out;
+
+    n2l(iv, tout0);
+    n2l(iv, tout1);
+    n2l(iv, tout2);
+    n2l(iv, tout3);
+    iv -= 4;
+
+    for (length -= 16; length >= 0; length -= 16)
+    {
+        n2l(msg_32, tin0);
+        n2l(msg_32, tin1);
+        n2l(msg_32, tin2);
+        n2l(msg_32, tin3);
+        tin[0] = tin0^tout0;
+        tin[1] = tin1^tout1;
+        tin[2] = tin2^tout2;
+        tin[3] = tin3^tout3;
+
+        AES_encrypt(ctx, tin);
+
+        tout0 = tin[0]; 
+        l2n(tout0, out_32);
+        tout1 = tin[1]; 
+        l2n(tout1, out_32);
+        tout2 = tin[2]; 
+        l2n(tout2, out_32);
+        tout3 = tin[3]; 
+        l2n(tout3, out_32);
+    }
+
+    l2n(tout0, iv);
+    l2n(tout1, iv);
+    l2n(tout2, iv);
+    l2n(tout3, iv);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+    uint32_t tin0, tin1, tin2, tin3;
+    uint32_t xor0,xor1,xor2,xor3;
+    uint32_t tout0,tout1,tout2,tout3;
+    uint32_t data[4];
+    uint32_t *iv = (uint32_t *)ctx->iv;
+    uint32_t *msg_32 = (uint32_t *)msg;
+    uint32_t *out_32 = (uint32_t *)out;
+
+    n2l(iv ,xor0);
+    n2l(iv, xor1);
+    n2l(iv, xor2);
+    n2l(iv, xor3);
+    iv -= 4;
+
+    for (length-=16; length >= 0; length -= 16)
+    {
+        n2l(msg_32, tin0);
+        n2l(msg_32, tin1);
+        n2l(msg_32, tin2);
+        n2l(msg_32, tin3);
+
+        data[0] = tin0;
+        data[1] = tin1;
+        data[2] = tin2;
+        data[3] = tin3;
+
+        AES_decrypt(ctx, data);
+
+        tout0 = data[0]^xor0;
+        tout1 = data[1]^xor1;
+        tout2 = data[2]^xor2;
+        tout3 = data[3]^xor3;
+
+        xor0 = tin0;
+        xor1 = tin1;
+        xor2 = tin2;
+        xor3 = tin3;
+
+        l2n(tout0, out_32);
+        l2n(tout1, out_32);
+        l2n(tout2, out_32);
+        l2n(tout3, out_32);
+    }
+
+    l2n(xor0, iv);
+    l2n(xor1, iv);
+    l2n(xor2, iv);
+    l2n(xor3, iv);
+}
+#endif
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+    /* To make this code smaller, generate the sbox entries on the fly.
+     * This will have a really heavy effect upon performance.
+     */
+    uint32_t tmp[4];
+    uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+    int curr_rnd;
+    int rounds = ctx->rounds; 
+    const uint32_t *k = ctx->ks;
+
+    /* Pre-round key addition */
+    for (row = 0; row < 4; row++)
+    {
+        data[row] ^= *(k++);
+    }
+
+    /* Encrypt one block. */
+    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+    {
+        /* Perform ByteSub and ShiftRow operations together */
+        for (row = 0; row < 4; row++)
+        {
+            a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+            a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+            a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF]; 
+            a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+            /* Perform MixColumn iff not last round */
+            if (curr_rnd < (rounds - 1))
+            {
+                tmp1 = a0 ^ a1 ^ a2 ^ a3;
+                old_a0 = a0;
+
+                a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+                a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+                a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+                a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+
+            }
+
+            tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+        }
+
+        /* KeyAddition - note that it is vital that this loop is separate from
+           the MixColumn operation, which must be atomic...*/ 
+        for (row = 0; row < 4; row++)
+        {
+            data[row] = tmp[row] ^ *(k++);
+        }
+    }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{ 
+    uint32_t tmp[4];
+    uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+    uint32_t a0, a1, a2, a3, row;
+    int curr_rnd;
+    int rounds = ctx->rounds;
+    uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4);
+
+    /* pre-round key addition */
+    for (row=4; row > 0;row--)
+    {
+        data[row-1] ^= *(--k);
+    }
+
+    /* Decrypt one block */
+    for (curr_rnd=0; curr_rnd < rounds; curr_rnd++)
+    {
+        /* Perform ByteSub and ShiftRow operations together */
+        for (row = 4; row > 0; row--)
+        {
+            a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+            a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+            a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+            a3 = aes_isbox[(data[row%4])&0xFF];
+
+            /* Perform MixColumn iff not last round */
+            if (curr_rnd<(rounds-1))
+            {
+                /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+                   are quite large compared to encryption; this 
+                   operation slows decryption down noticeably. */
+                xt0 = AES_xtime(a0^a1);
+                xt1 = AES_xtime(a1^a2);
+                xt2 = AES_xtime(a2^a3);
+                xt3 = AES_xtime(a3^a0);
+                xt4 = AES_xtime(xt0^xt1);
+                xt5 = AES_xtime(xt1^xt2);
+                xt6 = AES_xtime(xt4^xt5);
+
+                xt0 ^= a1^a2^a3^xt4^xt6;
+                xt1 ^= a0^a2^a3^xt5^xt6;
+                xt2 ^= a0^a1^a3^xt4^xt6;
+                xt3 ^= a0^a1^a2^xt5^xt6;
+                tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+            }
+            else
+                tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+        }
+
+        for (row = 4; row > 0; row--)
+        {
+            data[row-1] = tmp[row-1] ^ *(--k);
+        }
+    }
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.c
new file mode 100644
index 0000000..49cad97
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.c
@@ -0,0 +1,1496 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small 
+ * cache. A bigint context may maintain state by being made "permanent". 
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "bigint.h"
+#include "crypto.h"
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint __malloc *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#endif
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+    /* calloc() sets everything to zero */
+    BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+   
+    /* the radix */
+    ctx->bi_radix = alloc(ctx, 2); 
+    ctx->bi_radix->comps[0] = 0;
+    ctx->bi_radix->comps[1] = 1;
+    bi_permanent(ctx->bi_radix);
+    return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not 
+ * properly freed.
+ * @param ctx [in]   The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+    bigint *p, *pn;
+
+    bi_depermanent(ctx->bi_radix); 
+    bi_free(ctx, ctx->bi_radix);
+
+    if (ctx->active_count != 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_terminate: there were %d un-freed bigints\n",
+                       ctx->active_count);
+#endif
+        abort();
+    }
+
+    for (p = ctx->free_list; p != NULL; p = pn)
+    {
+        pn = p->next;
+        free(p->comps);
+        free(p);
+    }
+
+    free(ctx);
+}
+
+/**
+ * @brief Increment the number of references to this object. 
+ * It does not do a full copy.
+ * @param bi [in]   The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+        bi->refs++;
+    return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in]   The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != 1)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_permanent: refs was not 1\n");
+#endif
+        abort();
+    }
+
+    bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in]   The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_depermanent: bigint was not permanent\n");
+#endif
+        abort();
+    }
+
+    bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again. 
+ *
+ * The memory itself it not actually freed, just tagged as being available 
+ * @param ctx [in]   The bigint session context.
+ * @param bi [in]    The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+    check(bi);
+    if (bi->refs == PERMANENT)
+    {
+        return;
+    }
+
+    if (--bi->refs > 0)
+    {
+        return;
+    }
+
+    bi->next = ctx->free_list;
+    ctx->free_list = bi;
+    ctx->free_count++;
+
+    if (--ctx->active_count < 0)
+    {
+#ifdef CONFIG_SSL_FULL_MODE
+        printf("bi_free: active_count went negative "
+                "- double-freed bigint?\n");
+#endif
+        abort();
+    }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in]   The bigint session context.
+ * @param i [in]     The (unsigned) integer to be converted.
+ * 
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+    bigint *biR = alloc(ctx, 1);
+    biR->comps[0] = i;
+    return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in]   The bigint session context.
+ * @param bi  [in]   The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+    bigint *biR = alloc(ctx, bi->size);
+    check(bi);
+    memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+    return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int n;
+    comp carry = 0;
+    comp *pa, *pb;
+
+    check(bia);
+    check(bib);
+
+    n = max(bia->size, bib->size);
+    more_comps(bia, n+1);
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do
+    {
+        comp  sl, rl, cy1;
+        sl = *pa + *pb++;
+        rl = sl + carry;
+        cy1 = sl < *pa;
+        carry = cy1 | (rl < sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    *pa = carry;                  /* do overflow */
+    bi_free(ctx, bib);
+    return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx, 
+        bigint *bia, bigint *bib, int *is_negative)
+{
+    int n = bia->size;
+    comp *pa, *pb, carry = 0;
+
+    check(bia);
+    check(bib);
+
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do 
+    {
+        comp sl, rl, cy1;
+        sl = *pa - *pb++;
+        rl = sl - carry;
+        cy1 = sl > *pa;
+        carry = cy1 | (rl > sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    if (is_negative)    /* indicate a negative result */
+    {
+        *is_negative = carry;
+    }
+
+    bi_free(ctx, trim(bib));    /* put bib back to the way it was */
+    return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+    int j = 0, n = bia->size;
+    bigint *biR = alloc(ctx, n + 1);
+    comp carry = 0;
+    comp *r = biR->comps;
+    comp *a = bia->comps;
+
+    check(bia);
+
+    /* clear things to start with */
+    memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+    do
+    {
+        long_comp tmp = *r + (long_comp)a[j]*b + carry;
+        *r++ = (comp)tmp;              /* downsize */
+        carry = (comp)(tmp >> COMP_BIT_SIZE);
+    } while (++j < n);
+
+    *r = carry;
+    bi_free(ctx, bia);
+    return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations. 
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param u [in]    A bigint which is the numerator.
+ * @param v [in]    Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return  The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+    int n = v->size, m = u->size-n;
+    int j = 0, orig_u_size = u->size;
+    uint8_t mod_offset = ctx->mod_offset;
+    comp d;
+    bigint *quotient, *tmp_u;
+    comp q_dash;
+
+    check(u);
+    check(v);
+
+    /* if doing reduction and we are < mod, then return mod */
+    if (is_mod && bi_compare(v, u) > 0)
+    {
+        bi_free(ctx, v);
+        return u;
+    }
+
+    quotient = alloc(ctx, m+1);
+    tmp_u = alloc(ctx, n+1);
+    v = trim(v);        /* make sure we have no leading 0's */
+    d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+    /* clear things to start with */
+    memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+    /* normalise */
+    if (d > 1)
+    {
+        u = bi_int_multiply(ctx, u, d);
+
+        if (is_mod)
+        {
+            v = ctx->bi_normalised_mod[mod_offset];
+        }
+        else
+        {
+            v = bi_int_multiply(ctx, v, d);
+        }
+    }
+
+    if (orig_u_size == u->size)  /* new digit position u0 */
+    {
+        more_comps(u, orig_u_size + 1);
+    }
+
+    do
+    {
+        /* get a temporary short version of u */
+        memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+        /* calculate q' */
+        if (U(0) == V1)
+        {
+            q_dash = COMP_RADIX-1;
+        }
+        else
+        {
+            q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+        }
+
+        if (v->size > 1 && V2)
+        {
+            /* we are implementing the following:
+            if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - 
+                    q_dash*V1)*COMP_RADIX) + U(2))) ... */
+            comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - 
+                                        (long_comp)q_dash*V1);
+            if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+            {
+                q_dash--;
+            }
+        }
+
+        /* multiply and subtract */
+        if (q_dash)
+        {
+            int is_negative;
+            tmp_u = bi_subtract(ctx, tmp_u, 
+                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+            more_comps(tmp_u, n+1);
+
+            Q(j) = q_dash; 
+
+            /* add back */
+            if (is_negative)
+            {
+                Q(j)--;
+                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+                /* lop off the carry */
+                tmp_u->size--;
+                v->size--;
+            }
+        }
+        else
+        {
+            Q(j) = 0; 
+        }
+
+        /* copy back to u */
+        memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+    } while (++j <= m);
+
+    bi_free(ctx, tmp_u);
+    bi_free(ctx, v);
+
+    if (is_mod)     /* get the remainder */
+    {
+        bi_free(ctx, quotient);
+        return bi_int_divide(ctx, trim(u), d);
+    }
+    else            /* get the quotient */
+    {
+        bi_free(ctx, u);
+        return trim(quotient);
+    }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom)
+{
+    int i = biR->size - 1;
+    long_comp r = 0;
+
+    check(biR);
+
+    do
+    {
+        r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+        biR->comps[i] = (comp)(r / denom);
+        r %= denom;
+    } while (--i != 0);
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, 
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of 
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the 
+ * simple algorithm from an article by Dusse and Kaliski to efficiently 
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+    int i;
+    comp t = 1;
+    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */
+    long_comp two_2_i = 4;      /* 2^i */
+    comp N = bim->comps[0];
+
+    for (i = 2; i <= COMP_BIT_SIZE; i++)
+    {
+        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+        {
+            t += two_2_i_minus_1;
+        }
+
+        two_2_i_minus_1 <<= 1;
+        two_2_i <<= 1;
+    }
+
+    return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+    defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components) 
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-num_shifts;
+    comp *x = biR->comps;
+    comp *y = &biR->comps[num_shifts];
+
+    check(biR);
+
+    if (i <= 0)     /* have we completely right shifted? */
+    {
+        biR->comps[0] = 0;  /* return 0 */
+        biR->size = 1;
+        return biR;
+    }
+
+    do
+    {
+        *x++ = *y++;
+    } while (--i > 0);
+
+    biR->size -= num_shifts;
+    return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components) 
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+    int i = biR->size-1;
+    comp *x, *y;
+
+    check(biR);
+
+    if (num_shifts <= 0)
+    {
+        return biR;
+    }
+
+    more_comps(biR, biR->size + num_shifts);
+
+    x = &biR->comps[i+num_shifts];
+    y = &biR->comps[i];
+
+    do
+    {
+        *x-- = *y--;
+    } while (i--);
+
+    memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+    return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+    int i, j = 0, offset = 0;
+
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        biR->comps[offset] += data[i] << (j*8);
+
+        if (++j == COMP_BYTE_SIZE)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and 
+ * convert them into bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+    int size = strlen(data);
+    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+    int i, j = 0, offset = 0;
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+        biR->comps[offset] += num << (j*4);
+
+        if (++j == COMP_NUM_NIBBLES)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+    int i, j;
+
+    if (x == NULL)
+    {
+        printf("%s: (null)\n", label);
+        return;
+    }
+
+    printf("%s: (size %d)\n", label, x->size);
+    for (i = x->size-1; i >= 0; i--)
+    {
+        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+        {
+            comp mask = 0x0f << (j*4);
+            comp num = (x->comps[i] & mask) >> (j*4);
+            putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+        }
+    }  
+
+    printf("\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence. 
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in]  The bigint session context.
+ * @param x [in]  The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+    int i, j, k = size-1;
+
+    check(x);
+    memset(data, 0, size);  /* ensure all leading 0's are cleared */
+
+    for (i = 0; i < x->size; i++)
+    {
+        for (j = 0; j < COMP_BYTE_SIZE; j++)
+        {
+            comp mask = 0xff << (j*8);
+            int num = (x->comps[i] & mask) >> (j*8);
+            data[k--] = num;
+
+            if (k < 0)
+            {
+                break;
+            }
+        }
+    }
+
+    bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction. 
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in]  The bigint session context.
+ * @param bim [in]  The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+    int k = bim->size;
+    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    bigint *R, *R2;
+#endif
+
+    ctx->bi_mod[mod_offset] = bim;
+    bi_permanent(ctx->bi_mod[mod_offset]);
+    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+    bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    /* set montgomery variables */
+    R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1);     /* R */
+    R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1);  /* R^2 */
+    ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2);             /* R^2 mod m */
+    ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R);               /* R mod m */
+
+    bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+    ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+    ctx->bi_mu[mod_offset] = 
+        bi_divide(ctx, comp_left_shift(
+            bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+    bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in]  The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+    bi_depermanent(ctx->bi_mod[mod_offset]);
+    bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+    bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+    bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+    bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bi_depermanent(ctx->bi_mu[mod_offset]); 
+    bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); 
+    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/** 
+ * Perform a standard multiplication between two bigints.
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int i, j, i_plus_j;
+    int n = bia->size; 
+    int t = bib->size;
+    bigint *biR = alloc(ctx, n + t);
+    comp *sr = biR->comps;
+    comp *sa = bia->comps;
+    comp *sb = bib->comps;
+
+    check(bia);
+    check(bib);
+
+    /* clear things to start with */
+    memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+    i = 0;
+
+    do 
+    {
+        comp carry = 0;
+        comp b = *sb++;
+        i_plus_j = i;
+        j = 0;
+
+        do
+        {
+            long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry;
+            sr[i_plus_j++] = (comp)tmp;              /* downsize */
+            carry = (comp)(tmp >> COMP_BIT_SIZE);
+        } while (++j < n);
+
+        sr[i_plus_j] = carry;
+    } while (++i < t);
+
+    bi_free(ctx, bia);
+    bi_free(ctx, bib);
+    return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications 
+ * being done instead of 4. The additional additions/subtractions are O(N) 
+ * rather than O(N^2) and so for big numbers it saves on a few operations 
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+    bigint *x0, *x1;
+    bigint *p0, *p1, *p2;
+    int m;
+
+    if (is_square)
+    {
+        m = (bia->size + 1)/2;
+    }
+    else
+    {
+        m = (max(bia->size, bib->size) + 1)/2;
+    }
+
+    x0 = bi_clone(ctx, bia);
+    x0->size = m;
+    x1 = bi_clone(ctx, bia);
+    comp_right_shift(x1, m);
+    bi_free(ctx, bia);
+
+    /* work out the 3 partial products */
+    if (is_square)
+    {
+        p0 = bi_square(ctx, bi_copy(x0));
+        p2 = bi_square(ctx, bi_copy(x1));
+        p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+    }
+    else /* normal multiply */
+    {
+        bigint *y0, *y1;
+        y0 = bi_clone(ctx, bib);
+        y0->size = m;
+        y1 = bi_clone(ctx, bib);
+        comp_right_shift(y1, m);
+        bi_free(ctx, bib);
+
+        p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+        p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+        p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+    }
+
+    p1 = bi_subtract(ctx, 
+            bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+    comp_left_shift(p1, m);
+    comp_left_shift(p2, 2*m);
+    return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    check(bia);
+    check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+    {
+        return regular_multiply(ctx, bia, bib);
+    }
+
+    return karatsuba(ctx, bia, bib, 0);
+#else
+    return regular_multiply(ctx, bia, bib);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+    int t = bi->size;
+    int i = 0, j;
+    bigint *biR = alloc(ctx, t*2);
+    comp *w = biR->comps;
+    comp *x = bi->comps;
+    comp carry;
+
+    memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+    do
+    {
+        long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+        comp u = 0;
+        w[2*i] = (comp)tmp;
+        carry = (comp)(tmp >> COMP_BIT_SIZE);
+
+        for (j = i+1; j < t; j++)
+        {
+            long_comp xx = (long_comp)x[i]*x[j];
+            long_comp blob = (long_comp)w[i+j]+carry;
+
+            if (u)                  /* previous overflow */
+            {
+                blob += COMP_RADIX;
+            }
+
+            u = 0;
+            if (xx & COMP_BIG_MSB)  /* check for overflow */
+            {
+                u = 1;
+            }
+
+            tmp = 2*xx + blob;
+            w[i+j] = (comp)tmp;
+            carry = (comp)(tmp >> COMP_BIT_SIZE);
+        }
+
+        w[i+t] += carry;
+
+        if (u)
+        {
+            w[i+t+1] = 1;   /* add carry */
+        }
+    } while (++i < t);
+
+    bi_free(ctx, bi);
+    return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+    check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+    if (bia->size < SQU_KARATSUBA_THRESH) 
+    {
+        return regular_square(ctx, bia);
+    }
+
+    return karatsuba(ctx, bia, NULL, 1);
+#else
+    return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+    int r, i;
+
+    check(bia);
+    check(bib);
+
+    if (bia->size > bib->size)
+        r = 1;
+    else if (bia->size < bib->size)
+        r = -1;
+    else
+    {
+        comp *a = bia->comps; 
+        comp *b = bib->comps; 
+
+        /* Same number of components.  Compare starting from the high end
+         * and working down. */
+        r = 0;
+        i = bia->size - 1;
+
+        do 
+        {
+            if (a[i] > b[i])
+            { 
+                r = 1;
+                break; 
+            }
+            else if (a[i] < b[i])
+            { 
+                r = -1;
+                break; 
+            }
+        } while (--i >= 0);
+    }
+
+    return r;
+}
+
+/*
+ * Allocate and zero more components.  Does not consume bi. 
+ */
+static void more_comps(bigint *bi, int n)
+{
+    if (n > bi->max_comps)
+    {
+        bi->max_comps = max(bi->max_comps * 2, n);
+        bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+    }
+
+    if (n > bi->size)
+    {
+        memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+    }
+
+    bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+    bigint *biR;
+
+    /* Can we recycle an old bigint? */
+    if (ctx->free_list != NULL)
+    {
+        biR = ctx->free_list;
+        ctx->free_list = biR->next;
+        ctx->free_count--;
+
+        if (biR->refs != 0)
+        {
+#ifdef CONFIG_SSL_FULL_MODE
+            printf("alloc: refs was not 0\n");
+#endif
+            abort();    /* create a stack trace from a core dump */
+        }
+
+        more_comps(biR, size);
+    }
+    else
+    {
+        /* No free bigints available - create a new one. */
+        biR = (bigint *)malloc(sizeof(bigint));
+        biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+        biR->max_comps = size;  /* give some space to spare */
+    }
+
+    biR->size = size;
+    biR->refs = 1;
+    biR->next = NULL;
+    ctx->active_count++;
+    return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+    int i = COMP_BIT_SIZE-1;
+    comp shift = COMP_RADIX/2;
+    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */
+
+    check(biexp);
+
+    do
+    {
+        if (test & shift)
+        {
+            return i+(biexp->size-1)*COMP_BIT_SIZE;
+        }
+
+        shift >>= 1;
+    } while (--i != 0);
+
+    return -1;      /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+    comp test = biexp->comps[offset / COMP_BIT_SIZE];
+    int num_shifts = offset % COMP_BIT_SIZE;
+    comp shift = 1;
+    int i;
+
+    check(biexp);
+
+    for (i = 0; i < num_shifts; i++)
+    {
+        shift <<= 1;
+    }
+
+    return test & shift;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+    if (bi->refs <= 0)
+    {
+        printf("check: zero or negative refs in bigint\n");
+        abort();
+    }
+
+    if (bi->next != NULL)
+    {
+        printf("check: attempt to use a bigint from "
+                "the free list\n");
+        abort();
+    }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+    check(bi);
+
+    while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+    {
+        bi->size--;
+    }
+
+    return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bixy [in]  A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+    int i = 0, n;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    comp mod_inv = ctx->N0_dash[mod_offset];
+
+    check(bixy);
+
+    if (ctx->use_classical)     /* just use classical instead */
+    {
+        return bi_mod(ctx, bixy);
+    }
+
+    n = bim->size;
+
+    do
+    {
+        bixy = bi_add(ctx, bixy, comp_left_shift(
+                    bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+    } while (++i < n);
+
+    comp_right_shift(bixy, n);
+
+    if (bi_compare(bixy, bim) >= 0)
+    {
+        bixy = bi_subtract(ctx, bixy, bim, NULL);
+    }
+
+    return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation 
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+    check(bi);
+
+    if (bi->size > mod)
+    {
+        bi->size = mod;
+    }
+
+    return bi;
+}
+
+/*
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods. 
+ */
+static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, 
+        int inner_partial, int outer_partial)
+{
+    int i = 0, j, n = bia->size, t = bib->size;
+    bigint *biR;
+    comp carry;
+    comp *sr, *sa, *sb;
+
+    check(bia);
+    check(bib);
+
+    biR = alloc(ctx, n + t);
+    sa = bia->comps;
+    sb = bib->comps;
+    sr = biR->comps;
+
+    if (inner_partial)
+    {
+        memset(sr, 0, inner_partial*COMP_BYTE_SIZE); 
+    }
+    else    /* outer partial */
+    {
+        if (n < outer_partial || t < outer_partial) /* should we bother? */
+        {
+            bi_free(ctx, bia);
+            bi_free(ctx, bib);
+            biR->comps[0] = 0;      /* return 0 */
+            biR->size = 1;
+            return biR;
+        }
+
+        memset(&sr[outer_partial], 0, (n+t-outer_partial)*COMP_BYTE_SIZE);
+    }
+
+    do 
+    {
+        comp *a = sa;
+        comp b = *sb++;
+        long_comp tmp;
+        int i_plus_j = i;
+        carry = 0;
+        j = n;
+
+        if (outer_partial && i_plus_j < outer_partial)
+        {
+            i_plus_j = outer_partial;
+            a = &sa[outer_partial-i];
+            j = n-(outer_partial-i);
+        }
+
+        do
+        {
+            if (inner_partial && i_plus_j >= inner_partial) 
+            {
+                break;
+            }
+
+            tmp = sr[i_plus_j] + ((long_comp)*a++)*b + carry;
+            sr[i_plus_j++] = (comp)tmp;              /* downsize */
+            carry = (comp)(tmp >> COMP_BIT_SIZE);
+        } while (--j != 0);
+
+        sr[i_plus_j] = carry;
+    } while (++i < t);
+
+    bi_free(ctx, bia);
+    bi_free(ctx, bib);
+    return trim(biR);
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param bi [in]  A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+    bigint *q1, *q2, *q3, *r1, *r2, *r;
+    uint8_t mod_offset = ctx->mod_offset;
+    bigint *bim = ctx->bi_mod[mod_offset];
+    int k = bim->size;
+
+    check(bi);
+    check(bim);
+
+    /* use Classical method instead  - Barrett cannot help here */
+    if (bi->size > k*2)
+    {
+        return bi_mod(ctx, bi);
+    }
+
+    q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
+
+    /* do outer partial multiply */
+    q2 = partial_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); 
+    q3 = comp_right_shift(q2, k+1);
+    r1 = comp_mod(bi, k+1);
+
+    /* do inner partial multiply */
+    r2 = comp_mod(partial_multiply(ctx, q3, bim, k+1, 0), k+1);
+    r = bi_subtract(ctx, r1, r2, NULL);
+
+    /* if (r >= m) r = r - m; */
+    if (bi_compare(r, bim) >= 0)
+    {
+        r = bi_subtract(ctx, r, bim, NULL);
+    }
+
+    return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm 
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+    int k = 1, i;
+    bigint *g2;
+
+    for (i = 0; i < window-1; i++)   /* compute 2^(window-1) */
+    {
+        k <<= 1;
+    }
+
+    ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, g1);
+    bi_permanent(ctx->g[0]);
+    g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0]));   /* g^2 */
+
+    for (i = 1; i < k; i++)
+    {
+        ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+        bi_permanent(ctx->g[i]);
+    }
+
+    bi_free(ctx, g2);
+    ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is 
+ * one of the optimisations used for performance.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+    int i = find_max_exp_index(biexp), j, window_size = 1;
+    bigint *biR = int_to_bi(ctx, 1);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    uint8_t mod_offset = ctx->mod_offset;
+    if (!ctx->use_classical)
+    {
+        /* preconvert */
+        bi = bi_mont(ctx, 
+                bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset]));    /* x' */
+        bi_free(ctx, biR);
+        biR = ctx->bi_R_mod_m[mod_offset];                              /* A */
+    }
+#endif
+
+    check(bi);
+    check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+    for (j = i; j > 32; j /= 5) /* work out an optimum size */
+        window_size++;
+
+    /* work out the slide constants */
+    precompute_slide_window(ctx, window_size, bi);
+#else   /* just one constant */
+    ctx->g = (bigint **)malloc(sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, bi);
+    ctx->window = 1;
+    bi_permanent(ctx->g[0]);
+#endif
+
+    /* if sliding-window is off, then only one bit will be done at a time and
+     * will reduce to standard left-to-right exponentiation */
+    do
+    {
+        if (exp_bit_is_one(biexp, i))
+        {
+            int l = i-window_size+1;
+            int part_exp = 0;
+
+            if (l < 0)  /* LSB of exponent will always be 1 */
+                l = 0;
+            else
+            {
+                while (exp_bit_is_one(biexp, l) == 0)
+                    l++;    /* go back up */
+            }
+
+            /* build up the section of the exponent */
+            for (j = i; j >= l; j--)
+            {
+                biR = bi_residue(ctx, bi_square(ctx, biR));
+                if (exp_bit_is_one(biexp, j))
+                    part_exp++;
+
+                if (j != l)
+                    part_exp <<= 1;
+            }
+
+            part_exp = (part_exp-1)/2;  /* adjust for array */
+            biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
+            i = l-1;
+        }
+        else    /* square it */
+        {
+            biR = bi_residue(ctx, bi_square(ctx, biR));
+            i--;
+        }
+    } while (i >= 0);
+     
+    /* cleanup */
+    for (i = 0; i < ctx->window; i++)
+    {
+        bi_depermanent(ctx->g[i]);
+        bi_free(ctx, ctx->g[i]);
+    }
+
+    free(ctx->g);
+    bi_free(ctx, bi);
+    bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+    return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+    return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint to perform the exp/mod.
+ * @param bim [in]  The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+    bigint *biR, *tmp_biR;
+
+    /* Set up a temporary bigint context and transfer what we need between
+     * them. We need to do this since we want to keep the original modulus
+     * which is already in this context. This operation is only called when
+     * doing peer verification, and so is not expensive :-) */
+    BI_CTX *tmp_ctx = bi_initialize();
+    bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+    tmp_biR = bi_mod_power(tmp_ctx, 
+                bi_clone(tmp_ctx, bi), 
+                bi_clone(tmp_ctx, biexp));
+    biR = bi_clone(ctx, tmp_biR);
+    bi_free(tmp_ctx, tmp_biR);
+    bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+    bi_terminate(tmp_ctx);
+
+    bi_free(ctx, bi);
+    bi_free(ctx, bim);
+    bi_free(ctx, biexp);
+    return biR;
+}
+#endif
+/** @} */
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.h b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.h
new file mode 100644
index 0000000..f5f3353
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint.h
@@ -0,0 +1,93 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE) 
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+#include "os_port.h"
+#include "bigint_impl.h"
+
+#ifndef CONFIG_BIGINT_CHECK_ON
+#define check(A)                /**< disappears in normal production mode */
+#endif
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia, 
+        bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B)      bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B)         bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B)         bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B)         bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)
+#endif
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint_impl.h b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint_impl.h
new file mode 100644
index 0000000..762a7cc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/bigint_impl.h
@@ -0,0 +1,105 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET     0    /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET     1    /**< p modulo offset. */
+#define BIGINT_Q_OFFSET     2    /**< q module offset. */
+#define BIGINT_NUM_MODS     3    /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS     1    
+#endif
+
+/* Architecture specific functions for big ints */
+#ifdef WIN32
+#define COMP_RADIX          4294967296i64         
+#define COMP_BIG_MSB        0x8000000000000000i64 
+#else
+#define COMP_RADIX          4294967296ULL         /**< Max component + 1 */
+#define COMP_BIG_MSB        0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
+#endif
+#define COMP_BIT_SIZE       32  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */
+
+typedef uint32_t comp;	        /**< A single precision component. */
+typedef uint64_t long_comp;     /**< A double precision component. */
+typedef int64_t slong_comp;     /**< A signed double precision component. */
+
+/**
+ * @struct  _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+    struct _bigint* next;       /**< The next bigint in the cache. */
+    short size;                 /**< The number of components in this bigint. */
+    short max_comps;            /**< The heapsize allocated for this bigint */
+    int refs;                   /**< An internal reference count. */
+    comp* comps;                /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint;  /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in 
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+    bigint *active_list;                    /**< Bigints currently used. */
+    bigint *free_list;                      /**< Bigints not used. */
+    bigint *bi_radix;                       /**< The radix used. */
+    bigint *bi_mod[BIGINT_NUM_MODS];        /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    bigint *bi_RR_mod_m[BIGINT_NUM_MODS];   /**< R^2 mod m */
+    bigint *bi_R_mod_m[BIGINT_NUM_MODS];    /**< R mod m */
+    comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bigint *bi_mu[BIGINT_NUM_MODS];         /**< Storage for mu */
+#endif
+    bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+    bigint **g;                 /**< Used by sliding-window. */
+    int window;                 /**< The size of the sliding window */
+    int active_count;           /**< Number of active bigints. */
+    int free_count;             /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    uint8_t use_classical;      /**< Use classical reduction. */
+#endif
+    uint8_t mod_offset;         /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b))  /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */
+
+#define V1      v->comps[v->size-1]                 /**< v1 for division */
+#define V2      v->comps[v->size-2]                 /**< v2 for division */
+#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */
+#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/crypto.h b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/crypto.h
new file mode 100644
index 0000000..a9893cf
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/crypto.h
@@ -0,0 +1,302 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bigint.h"
+
+/**************************************************************************
+ * AES declarations 
+ **************************************************************************/
+
+#define AES_MAXROUNDS			14
+
+typedef struct aes_key_st 
+{
+    uint16_t rounds;
+    uint16_t key_size;
+    uint32_t ks[(AES_MAXROUNDS+1)*8];
+    uint8_t iv[16];
+} AES_CTX;
+
+typedef enum
+{
+    AES_MODE_128,
+    AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key, 
+        const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, 
+        uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/**************************************************************************
+ * RC4 declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    int x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations 
+ **************************************************************************/
+
+#define SHA1_SIZE   20
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct 
+{
+    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest  */
+    uint32_t Length_Low;            /* Message length in bits      */
+    uint32_t Length_High;           /* Message length in bits      */
+    uint16_t Message_Block_Index;   /* Index into message block array   */
+    uint8_t Message_Block[64];      /* 512-bit message blocks      */
+} SHA1_CTX;
+
+void SHA1Init(SHA1_CTX *);
+void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1Final(SHA1_CTX *, uint8_t *digest);
+
+/**************************************************************************
+ * MD5 declarations 
+ **************************************************************************/
+
+/* MD5 context. */
+
+#define MD5_SIZE    16
+
+typedef struct 
+{
+  uint32_t state[4];        /* state (ABCD) */
+  uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  uint8_t buffer[64];       /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const uint8_t *msg, int len);
+void MD5Final(MD5_CTX *, uint8_t *digest);
+
+/**************************************************************************
+ * HMAC declarations 
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RNG declarations 
+ **************************************************************************/
+void RNG_initialize(const uint8_t *seed_buf, int size);
+void RNG_terminate(void);
+void get_random(int num_rand_bytes, uint8_t *rand_data);
+//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#include <string.h>
+static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
+	memset ( rand_data, 0x01, num_rand_bytes );
+}
+
+/**************************************************************************
+ * RSA declarations 
+ **************************************************************************/
+
+typedef struct 
+{
+    bigint *m;              /* modulus */
+    bigint *e;              /* public exponent */
+    bigint *d;              /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+    bigint *p;              /* p as in m = pq */
+    bigint *q;              /* q as in m = pq */
+    bigint *dP;             /* d mod (p-1) */
+    bigint *dQ;             /* d mod (q-1) */
+    bigint *qInv;           /* q^-1 mod p */
+#endif
+    int num_octets;
+    bigint *sig_m;         /* signature modulus */
+    BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+        );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+        int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * ASN1 declarations 
+ **************************************************************************/
+#define X509_OK                             0
+#define X509_NOT_OK                         -1
+#define X509_VFY_ERROR_NO_TRUSTED_CERT      -2
+#define X509_VFY_ERROR_BAD_SIGNATURE        -3      
+#define X509_VFY_ERROR_NOT_YET_VALID        -4
+#define X509_VFY_ERROR_EXPIRED              -5
+#define X509_VFY_ERROR_SELF_SIGNED          -6
+#define X509_VFY_ERROR_INVALID_CHAIN        -7
+#define X509_VFY_ERROR_UNSUPPORTED_DIGEST   -8
+#define X509_INVALID_PRIV_KEY               -9
+
+/*
+ * The Distinguished Name
+ */
+#define X509_NUM_DN_TYPES                   3
+#define X509_COMMON_NAME                    0
+#define X509_ORGANIZATION                   1
+#define X509_ORGANIZATIONAL_TYPE            2
+
+#define ASN1_INTEGER            0x02
+#define ASN1_BIT_STRING         0x03
+#define ASN1_OCTET_STRING       0x04
+#define ASN1_NULL               0x05
+#define ASN1_OID                0x06
+#define ASN1_PRINTABLE_STR      0x13
+#define ASN1_TELETEX_STR        0x14
+#define ASN1_IA5_STR            0x16
+#define ASN1_UTC_TIME           0x17
+#define ASN1_SEQUENCE           0x30
+#define ASN1_SET                0x31
+#define ASN1_IMPLICIT_TAG       0x80
+#define ASN1_EXPLICIT_TAG       0xa0
+
+#define SALT_SIZE               8
+
+struct _x509_ctx
+{
+    char *ca_cert_dn[X509_NUM_DN_TYPES];
+    char *cert_dn[X509_NUM_DN_TYPES];
+#if defined(_WIN32_WCE)
+    long not_before;
+    long not_after;
+#else
+    time_t not_before;
+    time_t not_after;
+#endif
+    uint8_t *signature;
+    uint16_t sig_len;
+    uint8_t sig_type;
+    RSA_CTX *rsa_ctx;
+    bigint *digest;
+    struct _x509_ctx *next;
+};
+
+typedef struct _x509_ctx X509_CTX;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+typedef struct 
+{
+    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+#endif
+
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len);
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+void x509_display_error(int error);
+#endif
+
+/**************************************************************************
+ * MISC declarations 
+ **************************************************************************/
+
+extern const char * const unsupported_str;
+
+typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
+typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, 
+        int key_len, uint8_t *digest);
+
+typedef struct
+{
+    uint8_t *pre_data;	/* include the ssl record bytes */
+    uint8_t *data;	/* the regular ssl data */
+    int max_len;
+    int index;
+} BUF_MEM;
+
+BUF_MEM buf_new(void);
+void buf_grow(BUF_MEM *bm, int len);
+void buf_free(BUF_MEM *bm);
+int get_file(const char *filename, uint8_t **buf);
+
+#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
+void print_blob(const char *format, const uint8_t *data, int size, ...);
+#else
+    #define print_blob(...)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/os_port.h b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/os_port.h
new file mode 100644
index 0000000..babdbfa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/os_port.h
@@ -0,0 +1,61 @@
+/**
+ * @file os_port.h
+ *
+ * Trick the axtls code into building within our build environment.
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <byteswap.h>
+
+#define STDCALL
+#define EXP_FUNC
+#define TTY_FLUSH()
+
+/** We can't actually abort, since we are effectively a kernel... */
+#define abort() assert ( 0 )
+
+/** crypto_misc.c has a bad #ifdef */
+static inline void close ( int fd __unused ) {
+	/* Do nothing */
+}
+
+typedef void FILE;
+
+static inline FILE * fopen ( const char *filename __unused,
+			     const char *mode __unused ) {
+	return NULL;
+}
+
+static inline int fseek ( FILE *stream __unused, long offset __unused,
+			  int whence __unused ) {
+	return -1;
+}
+
+static inline long ftell ( FILE *stream __unused ) {
+	return -1;
+}
+
+static inline size_t fread ( void *ptr __unused, size_t size __unused,
+			     size_t nmemb __unused, FILE *stream __unused ) {
+	return -1;
+}
+
+static inline int fclose ( FILE *stream __unused ) {
+	return -1;
+}
+
+#define CONFIG_SSL_CERT_VERIFICATION 1
+#define CONFIG_SSL_MAX_CERTS 1
+#define CONFIG_X509_MAX_CA_CERTS 1
+#define CONFIG_SSL_EXPIRY_TIME 24
+#define CONFIG_SSL_ENABLE_CLIENT 1
+#define CONFIG_BIGINT_CLASSICAL 1
+
+#endif 
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/rsa.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/rsa.c
new file mode 100644
index 0000000..389eda5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/rsa.c
@@ -0,0 +1,332 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "crypto.h"
+
+#ifdef CONFIG_BIGINT_CRT
+static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
+#endif
+
+void RSA_priv_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len,
+        const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+      , const uint8_t *p, int p_len,
+        const uint8_t *q, int q_len,
+        const uint8_t *dP, int dP_len,
+        const uint8_t *dQ, int dQ_len,
+        const uint8_t *qInv, int qInv_len
+#endif
+    )
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx;
+    RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+    rsa_ctx = *ctx;
+    bi_ctx = rsa_ctx->bi_ctx;
+    rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+    bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+    rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+    rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+    rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+    rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+    rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+    bi_permanent(rsa_ctx->dP);
+    bi_permanent(rsa_ctx->dQ);
+    bi_permanent(rsa_ctx->qInv);
+    bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+    bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx, 
+        const uint8_t *modulus, int mod_len,
+        const uint8_t *pub_exp, int pub_len)
+{
+    RSA_CTX *rsa_ctx;
+    BI_CTX *bi_ctx = bi_initialize();
+    *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+    rsa_ctx = *ctx;
+    rsa_ctx->bi_ctx = bi_ctx;
+    rsa_ctx->num_octets = (mod_len & 0xFFF0);
+    rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+    bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+    rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+    bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+    BI_CTX *bi_ctx;
+    if (rsa_ctx == NULL)                /* deal with ptrs that are null */
+        return;
+
+    bi_ctx = rsa_ctx->bi_ctx;
+
+    bi_depermanent(rsa_ctx->e);
+    bi_free(bi_ctx, rsa_ctx->e);
+    bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+    if (rsa_ctx->d)
+    {
+        bi_depermanent(rsa_ctx->d);
+        bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+        bi_depermanent(rsa_ctx->dP);
+        bi_depermanent(rsa_ctx->dQ);
+        bi_depermanent(rsa_ctx->qInv);
+        bi_free(bi_ctx, rsa_ctx->dP);
+        bi_free(bi_ctx, rsa_ctx->dQ);
+        bi_free(bi_ctx, rsa_ctx->qInv);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+    }
+
+    bi_terminate(bi_ctx);
+    free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return  The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, 
+                            uint8_t *out_data, int is_decryption)
+{
+    int byte_size = ctx->num_octets;
+    uint8_t *block;
+    int i, size;
+    bigint *decrypted_bi, *dat_bi;
+
+    memset(out_data, 0, byte_size); /* initialise */
+
+    /* decrypt */
+    dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    decrypted_bi = is_decryption ?  /* decrypt or verify? */
+            RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else   /* always a decryption */
+    decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+    /* convert to a normal block */
+    block = (uint8_t *)malloc(byte_size);
+    bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+    i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+    if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+    {
+        while (block[i++] == 0xff && i < byte_size);
+
+        if (block[i-2] != 0xff)
+            i = byte_size;     /*ensure size is 0 */   
+    }
+    else                    /* PKCS1.5 encryption padding is random */
+#endif
+    {
+        while (block[i++] && i < byte_size);
+    }
+    size = byte_size - i;
+
+    /* get only the bit we want */
+    if (size > 0)
+        memcpy(out_data, &block[i], size);
+    
+    free(block);
+    return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+#ifdef CONFIG_BIGINT_CRT
+    return bi_crt(c, bi_msg);
+#else
+    BI_CTX *ctx = c->bi_ctx;
+    ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ * This should really be in bigint.c (and was at one stage), but needs 
+ * access to the RSA_CTX context...
+ */
+static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
+{
+    BI_CTX *ctx = rsa->bi_ctx;
+    bigint *m1, *m2, *h;
+
+    /* Montgomery has a condition the 0 < x, y < m and these products violate
+     * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 1;
+#endif
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP);
+
+    ctx->mod_offset = BIGINT_Q_OFFSET;
+    m2 = bi_mod_power(ctx, bi, rsa->dQ);
+
+    h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL);
+    h = bi_multiply(ctx, h, rsa->qInv);
+    ctx->mod_offset = BIGINT_P_OFFSET;
+    h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    ctx->use_classical = 0;         /* reset for any further operation */
+#endif
+    return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h));
+}
+#endif
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx) 
+{
+    if (rsa_ctx == NULL)
+        return;
+
+    printf("-----------------   RSA DEBUG   ----------------\n");
+    printf("Size:\t%d\n", rsa_ctx->num_octets);
+    bi_print("Modulus", rsa_ctx->m);
+    bi_print("Public Key", rsa_ctx->e);
+    bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+    c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+    return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
+        uint8_t *out_data, int is_signing)
+{
+    int byte_size = ctx->num_octets;
+    int num_pads_needed = byte_size-in_len-3;
+    bigint *dat_bi, *encrypt_bi;
+
+    /* note: in_len+11 must be > byte_size */
+    out_data[0] = 0;     /* ensure encryption block is < modulus */
+
+    if (is_signing)
+    {
+        out_data[1] = 1;        /* PKCS1.5 signing pads with "0xff"'s */
+        memset(&out_data[2], 0xff, num_pads_needed);
+    }
+    else /* randomize the encryption padding with non-zero bytes */   
+    {
+        out_data[1] = 2;
+        get_random_NZ(num_pads_needed, &out_data[2]);
+    }
+
+    out_data[2+num_pads_needed] = 0;
+    memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+    /* now encrypt it */
+    dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+    encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : 
+        RSA_public(ctx, dat_bi);
+    bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+    return byte_size;
+}
+
+#if 0
+/**
+ * Take a signature and decrypt it.
+ */
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+        bigint *modulus, bigint *pub_exp)
+{
+    uint8_t *block;
+    int i, size;
+    bigint *decrypted_bi, *dat_bi;
+    bigint *bir = NULL;
+
+    block = (uint8_t *)malloc(sig_len);
+
+    /* decrypt */
+    dat_bi = bi_import(ctx, sig, sig_len);
+    ctx->mod_offset = BIGINT_M_OFFSET;
+
+    /* convert to a normal block */
+    decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
+
+    bi_export(ctx, decrypted_bi, block, sig_len);
+    ctx->mod_offset = BIGINT_M_OFFSET;
+
+    i = 10; /* start at the first possible non-padded byte */
+    while (block[i++] && i < sig_len);
+    size = sig_len - i;
+
+    /* get only the bit we want */
+    if (size > 0)
+    {
+        int len;
+        const uint8_t *sig_ptr = x509_get_signature(&block[i], &len);
+
+        if (sig_ptr)
+        {
+            bir = bi_import(ctx, sig_ptr, len);
+        }
+    }
+
+    free(block);
+    return bir;
+}
+#endif
+
+#endif  /* CONFIG_SSL_CERT_VERIFICATION */
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls/sha1.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/sha1.c
new file mode 100644
index 0000000..9a42801
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls/sha1.c
@@ -0,0 +1,240 @@
+/*
+ *  Copyright(C) 2006 Cameron Rich
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
+ * This code was originally taken from RFC3174
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/*
+ *  Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+                (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* ----- static functions ----- */
+static void SHA1PadMessage(SHA1_CTX *ctx);
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
+
+/**
+ * Initialize the SHA1 context 
+ */
+void SHA1Init(SHA1_CTX *ctx)
+{
+    ctx->Length_Low             = 0;
+    ctx->Length_High            = 0;
+    ctx->Message_Block_Index    = 0;
+    ctx->Intermediate_Hash[0]   = 0x67452301;
+    ctx->Intermediate_Hash[1]   = 0xEFCDAB89;
+    ctx->Intermediate_Hash[2]   = 0x98BADCFE;
+    ctx->Intermediate_Hash[3]   = 0x10325476;
+    ctx->Intermediate_Hash[4]   = 0xC3D2E1F0;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
+{
+    while (len--)
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
+
+        ctx->Length_Low += 8;
+        if (ctx->Length_Low == 0)
+        {
+            ctx->Length_High++;
+        }
+
+        if (ctx->Message_Block_Index == 64)
+        {
+            SHA1ProcessMessageBlock(ctx);
+        }
+
+        msg++;
+    }
+}
+
+/**
+ * Return the 160-bit message digest into the user's array
+ */
+void SHA1Final(SHA1_CTX *ctx, uint8_t *digest)
+{
+    int i;
+
+    SHA1PadMessage(ctx);
+    memset(ctx->Message_Block, 0, 64);
+    ctx->Length_Low = 0;    /* and clear length */
+    ctx->Length_High = 0;
+
+    for  (i = 0; i < SHA1_SIZE; i++)
+    {
+        digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+    }
+}
+
+/**
+ * Process the next 512 bits of the message stored in the array.
+ */
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+    const uint32_t K[] =    {       /* Constants defined in SHA-1   */
+                            0x5A827999,
+                            0x6ED9EBA1,
+                            0x8F1BBCDC,
+                            0xCA62C1D6
+                            };
+    int        t;                 /* Loop counter                */
+    uint32_t      temp;              /* Temporary word value        */
+    uint32_t      W[80];             /* Word sequence               */
+    uint32_t      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     *  Initialize the first 16 words in the array W
+     */
+    for  (t = 0; t < 16; t++)
+    {
+        W[t] = ctx->Message_Block[t * 4] << 24;
+        W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+        W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+        W[t] |= ctx->Message_Block[t * 4 + 3];
+    }
+
+    for (t = 16; t < 80; t++)
+    {
+       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->Intermediate_Hash[0];
+    B = ctx->Intermediate_Hash[1];
+    C = ctx->Intermediate_Hash[2];
+    D = ctx->Intermediate_Hash[3];
+    E = ctx->Intermediate_Hash[4];
+
+    for (t = 0; t < 20; t++)
+    {
+        temp =  SHA1CircularShift(5,A) +
+                ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+
+        B = A;
+        A = temp;
+    }
+
+    for (t = 20; t < 40; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 40; t < 60; t++)
+    {
+        temp = SHA1CircularShift(5,A) +
+               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for (t = 60; t < 80; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    ctx->Intermediate_Hash[0] += A;
+    ctx->Intermediate_Hash[1] += B;
+    ctx->Intermediate_Hash[2] += C;
+    ctx->Intermediate_Hash[3] += D;
+    ctx->Intermediate_Hash[4] += E;
+    ctx->Message_Block_Index = 0;
+}
+
+/*
+ * According to the standard, the message must be padded to an even
+ * 512 bits.  The first padding bit must be a '1'.  The last 64
+ * bits represent the length of the original message.  All bits in
+ * between should be 0.  This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly.  It will also call the ProcessMessageBlock function
+ * provided appropriately.  When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * @param ctx [in, out] The SHA1 context
+ */
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+    /*
+     *  Check to see if the current message block is too small to hold
+     *  the initial padding bits and length.  If so, we will pad the
+     *  block, process it, and then continue padding into a second
+     *  block.
+     */
+    if (ctx->Message_Block_Index > 55)
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+        while(ctx->Message_Block_Index < 64)
+        {
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+
+        SHA1ProcessMessageBlock(ctx);
+
+        while (ctx->Message_Block_Index < 56)
+        {
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+    }
+    else
+    {
+        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+        while(ctx->Message_Block_Index < 56)
+        {
+
+            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+        }
+    }
+
+    /*
+     *  Store the message length as the last 8 octets
+     */
+    ctx->Message_Block[56] = ctx->Length_High >> 24;
+    ctx->Message_Block[57] = ctx->Length_High >> 16;
+    ctx->Message_Block[58] = ctx->Length_High >> 8;
+    ctx->Message_Block[59] = ctx->Length_High;
+    ctx->Message_Block[60] = ctx->Length_Low >> 24;
+    ctx->Message_Block[61] = ctx->Length_Low >> 16;
+    ctx->Message_Block[62] = ctx->Length_Low >> 8;
+    ctx->Message_Block[63] = ctx->Length_Low;
+    SHA1ProcessMessageBlock(ctx);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls_aes.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls_aes.c
new file mode 100644
index 0000000..b73a572
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls_aes.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/cbc.h>
+#include <ipxe/aes.h>
+#include "crypto/axtls/crypto.h"
+
+/** @file
+ *
+ * AES algorithm
+ *
+ */
+
+/**
+ * Set key
+ *
+ * @v ctx		Context
+ * @v key		Key
+ * @v keylen		Key length
+ * @ret rc		Return status code
+ */
+static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
+	struct aes_context *aes_ctx = ctx;
+	AES_MODE mode;
+	void *iv;
+
+	switch ( keylen ) {
+	case ( 128 / 8 ):
+		mode = AES_MODE_128;
+		break;
+	case ( 256 / 8 ):
+		mode = AES_MODE_256;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* IV is not a relevant concept at this stage; use a dummy
+	 * value that will have no side-effects.
+	 */
+	iv = &aes_ctx->axtls_ctx.iv;
+
+	AES_set_key ( &aes_ctx->axtls_ctx, key, iv, mode );
+
+	aes_ctx->decrypting = 0;
+
+	return 0;
+}
+
+/**
+ * Set initialisation vector
+ *
+ * @v ctx		Context
+ * @v iv		Initialisation vector
+ */
+static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
+	/* Nothing to do */
+}
+
+/**
+ * Call AXTLS' AES_encrypt() or AES_decrypt() functions
+ *
+ * @v axtls_ctx		AXTLS AES context
+ * @v src		Data to process
+ * @v dst		Buffer for output
+ * @v func		AXTLS AES function to call
+ */
+static void aes_call_axtls ( AES_CTX *axtls_ctx, const void *src, void *dst,
+			     void ( * func ) ( const AES_CTX *axtls_ctx,
+					       uint32_t *data ) ){
+	const uint32_t *srcl = src;
+	uint32_t *dstl = dst;
+	unsigned int i;
+
+	/* AXTLS' AES_encrypt() and AES_decrypt() functions both
+	 * expect to deal with an array of four dwords in host-endian
+	 * order.
+	 */
+	for ( i = 0 ; i < 4 ; i++ )
+		dstl[i] = ntohl ( srcl[i] );
+	func ( axtls_ctx, dstl );
+	for ( i = 0 ; i < 4 ; i++ )
+		dstl[i] = htonl ( dstl[i] );
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx		Context
+ * @v src		Data to encrypt
+ * @v dst		Buffer for encrypted data
+ * @v len		Length of data
+ */
+static void aes_encrypt ( void *ctx, const void *src, void *dst,
+			  size_t len ) {
+	struct aes_context *aes_ctx = ctx;
+
+	assert ( len == AES_BLOCKSIZE );
+	if ( aes_ctx->decrypting )
+		assert ( 0 );
+	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt );
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx		Context
+ * @v src		Data to decrypt
+ * @v dst		Buffer for decrypted data
+ * @v len		Length of data
+ */
+static void aes_decrypt ( void *ctx, const void *src, void *dst,
+			  size_t len ) {
+	struct aes_context *aes_ctx = ctx;
+
+	assert ( len == AES_BLOCKSIZE );
+	if ( ! aes_ctx->decrypting ) {
+		AES_convert_key ( &aes_ctx->axtls_ctx );
+		aes_ctx->decrypting = 1;
+	}
+	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt );
+}
+
+/** Basic AES algorithm */
+struct cipher_algorithm aes_algorithm = {
+	.name = "aes",
+	.ctxsize = sizeof ( struct aes_context ),
+	.blocksize = AES_BLOCKSIZE,
+	.setkey = aes_setkey,
+	.setiv = aes_setiv,
+	.encrypt = aes_encrypt,
+	.decrypt = aes_decrypt,
+};
+
+/* AES with cipher-block chaining */
+CBC_CIPHER ( aes_cbc, aes_cbc_algorithm,
+	     aes_algorithm, struct aes_context, AES_BLOCKSIZE );
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/axtls_sha1.c b/qemu-0.15.x/roms/ipxe/src/crypto/axtls_sha1.c
new file mode 100644
index 0000000..3eb8912
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/axtls_sha1.c
@@ -0,0 +1,25 @@
+#include "crypto/axtls/crypto.h"
+#include <ipxe/crypto.h>
+#include <ipxe/sha1.h>
+
+static void sha1_init ( void *ctx ) {
+	SHA1Init ( ctx );
+}
+
+static void sha1_update ( void *ctx, const void *data, size_t len ) {
+	SHA1Update ( ctx, data, len );
+}
+
+static void sha1_final ( void *ctx, void *out ) {
+	SHA1Final ( ctx, out );
+}
+
+struct digest_algorithm sha1_algorithm = {
+	.name		= "sha1",
+	.ctxsize	= SHA1_CTX_SIZE,
+	.blocksize	= 64,
+	.digestsize	= SHA1_DIGEST_SIZE,
+	.init		= sha1_init,
+	.update		= sha1_update,
+	.final		= sha1_final,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/cbc.c b/qemu-0.15.x/roms/ipxe/src/crypto/cbc.c
new file mode 100644
index 0000000..c00ebb0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/cbc.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/cbc.h>
+
+/** @file
+ *
+ * Cipher-block chaining
+ *
+ */
+
+/**
+ * XOR data blocks
+ *
+ * @v src		Input data
+ * @v dst		Second input data and output data buffer
+ * @v len		Length of data
+ */
+static void cbc_xor ( const void *src, void *dst, size_t len ) {
+	const uint32_t *srcl = src;
+	uint32_t *dstl = dst;
+	unsigned int i;
+
+	/* Assume that block sizes will always be dword-aligned, for speed */
+	assert ( ( len % sizeof ( *srcl ) ) == 0 );
+
+	for ( i = 0 ; i < ( len / sizeof ( *srcl ) ) ; i++ )
+		dstl[i] ^= srcl[i];
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx		Context
+ * @v src		Data to encrypt
+ * @v dst		Buffer for encrypted data
+ * @v len		Length of data
+ * @v raw_cipher	Underlying cipher algorithm
+ * @v cbc_ctx		CBC context
+ */
+void cbc_encrypt ( void *ctx, const void *src, void *dst, size_t len,
+		   struct cipher_algorithm *raw_cipher, void *cbc_ctx ) {
+	size_t blocksize = raw_cipher->blocksize;
+
+	assert ( ( len % blocksize ) == 0 );
+
+	while ( len ) {
+		cbc_xor ( src, cbc_ctx, blocksize );
+		cipher_encrypt ( raw_cipher, ctx, cbc_ctx, dst, blocksize );
+		memcpy ( cbc_ctx, dst, blocksize );
+		dst += blocksize;
+		src += blocksize;
+		len -= blocksize;
+	}
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx		Context
+ * @v src		Data to decrypt
+ * @v dst		Buffer for decrypted data
+ * @v len		Length of data
+ * @v raw_cipher	Underlying cipher algorithm
+ * @v cbc_ctx		CBC context
+ */
+void cbc_decrypt ( void *ctx, const void *src, void *dst, size_t len,
+		   struct cipher_algorithm *raw_cipher, void *cbc_ctx ) {
+	size_t blocksize = raw_cipher->blocksize;
+
+	assert ( ( len % blocksize ) == 0 );
+
+	while ( len ) {
+		cipher_decrypt ( raw_cipher, ctx, src, dst, blocksize );
+		cbc_xor ( cbc_ctx, dst, blocksize );
+		memcpy ( cbc_ctx, src, blocksize );
+		dst += blocksize;
+		src += blocksize;
+		len -= blocksize;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/chap.c b/qemu-0.15.x/roms/ipxe/src/crypto/chap.c
new file mode 100644
index 0000000..492d221
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/chap.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/chap.h>
+
+/** @file
+ *
+ * CHAP protocol
+ *
+ */
+
+/**
+ * Initialise CHAP challenge/response
+ *
+ * @v chap		CHAP challenge/response
+ * @v digest		Digest algorithm to use
+ * @ret rc		Return status code
+ *
+ * Initialises a CHAP challenge/response structure.  This routine
+ * allocates memory, and so may fail.  The allocated memory must
+ * eventually be freed by a call to chap_finish().
+ */
+int chap_init ( struct chap_response *chap,
+		struct digest_algorithm *digest ) {
+	size_t state_len;
+	void *state;
+
+	assert ( chap->digest == NULL );
+	assert ( chap->digest_context == NULL );
+	assert ( chap->response == NULL );
+
+	DBG ( "CHAP %p initialising with %s digest\n", chap, digest->name );
+
+	state_len = ( digest->ctxsize + digest->digestsize );
+	state = malloc ( state_len );
+	if ( ! state ) {
+		DBG ( "CHAP %p could not allocate %zd bytes for state\n",
+		      chap, state_len );
+		return -ENOMEM;
+	}
+	
+	chap->digest = digest;
+	chap->digest_context = state;
+	chap->response = ( state + digest->ctxsize );
+	chap->response_len = digest->digestsize;
+	digest_init ( chap->digest, chap->digest_context );
+	return 0;
+}
+
+/**
+ * Add data to the CHAP challenge
+ *
+ * @v chap		CHAP response
+ * @v data		Data to add
+ * @v len		Length of data to add
+ */
+void chap_update ( struct chap_response *chap, const void *data,
+		   size_t len ) {
+	assert ( chap->digest != NULL );
+	assert ( chap->digest_context != NULL );
+
+	if ( ! chap->digest )
+		return;
+
+	digest_update ( chap->digest, chap->digest_context, data, len );
+}
+
+/**
+ * Respond to the CHAP challenge
+ *
+ * @v chap		CHAP response
+ *
+ * Calculates the final CHAP response value, and places it in @c
+ * chap->response, with a length of @c chap->response_len.
+ */
+void chap_respond ( struct chap_response *chap ) {
+	assert ( chap->digest != NULL );
+	assert ( chap->digest_context != NULL );
+	assert ( chap->response != NULL );
+
+	DBG ( "CHAP %p responding to challenge\n", chap );
+
+	if ( ! chap->digest )
+		return;
+
+	digest_final ( chap->digest, chap->digest_context, chap->response );
+}
+
+/**
+ * Free resources used by a CHAP response
+ *
+ * @v chap		CHAP response
+ */
+void chap_finish ( struct chap_response *chap ) {
+	void *state = chap->digest_context;
+
+	DBG ( "CHAP %p finished\n", chap );
+
+	free ( state );
+	memset ( chap, 0, sizeof ( *chap ) );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/crandom.c b/qemu-0.15.x/roms/ipxe/src/crypto/crandom.c
new file mode 100644
index 0000000..1886f9b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/crandom.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Cryptographically strong random number generator
+ *
+ * Currently the cryptographic part is not implemented, and this just
+ * uses random().
+ */
+
+#include <ipxe/crypto.h>
+#include <stdlib.h>
+
+/**
+ * Get cryptographically strong random bytes
+ *
+ * @v buf	Buffer in which to store random bytes
+ * @v len	Number of random bytes to generate
+ *
+ * @b WARNING: This function is currently underimplemented, and does
+ * not give numbers any stronger than random()!
+ */
+void get_random_bytes ( void *buf, size_t len )
+{
+	u8 *bufp = buf;
+
+	/*
+	 * Somewhat arbitrarily, choose the 0x00FF0000-masked byte
+	 * returned by random() as having good entropy. PRNGs often
+	 * don't provide good entropy in lower bits, and the top byte
+	 * might show a pattern because of sign issues.
+	 */
+
+	while ( len-- ) {
+		*bufp++ = ( random() >> 16 ) & 0xFF;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/crc32.c b/qemu-0.15.x/roms/ipxe/src/crypto/crc32.c
new file mode 100644
index 0000000..71ec1d6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/crc32.c
@@ -0,0 +1,54 @@
+/*
+ * Little-endian CRC32 implementation.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crc32.h>
+
+#define CRCPOLY		0xedb88320
+
+/**
+ * Calculate 32-bit little-endian CRC checksum
+ *
+ * @v seed	Initial value
+ * @v data	Data to checksum
+ * @v len	Length of data
+ *
+ * Usually @a seed is initially zero or all one bits, depending on the
+ * protocol. To continue a CRC checksum over multiple calls, pass the
+ * return value from one call as the @a seed parameter to the next.
+ */
+u32 crc32_le ( u32 seed, const void *data, size_t len )
+{
+	u32 crc = seed;
+	const u8 *src = data;
+	u32 mult;
+	int i;
+
+	while ( len-- ) {
+		crc ^= *src++;
+		for ( i = 0; i < 8; i++ ) {
+			mult = ( crc & 1 ) ? CRCPOLY : 0;
+			crc = ( crc >> 1 ) ^ mult;
+		}
+	}
+
+	return crc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/crypto_null.c b/qemu-0.15.x/roms/ipxe/src/crypto/crypto_null.c
new file mode 100644
index 0000000..c9c32ae
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/crypto_null.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Null crypto algorithm
+ */
+
+#include <string.h>
+#include <ipxe/crypto.h>
+
+static void digest_null_init ( void *ctx __unused ) {
+	/* Do nothing */
+}
+
+static void digest_null_update ( void *ctx __unused, const void *src __unused,
+				 size_t len __unused ) {
+	/* Do nothing */
+}
+
+static void digest_null_final ( void *ctx __unused, void *out __unused ) {
+	/* Do nothing */
+}
+
+struct digest_algorithm digest_null = {
+	.name = "null",
+	.ctxsize = 0,
+	.blocksize = 1,
+	.digestsize = 0,
+	.init = digest_null_init,
+	.update = digest_null_update,
+	.final = digest_null_final,
+};
+
+static int cipher_null_setkey ( void *ctx __unused, const void *key __unused,
+				size_t keylen __unused ) {
+	/* Do nothing */
+	return 0;
+}
+
+static void cipher_null_setiv ( void *ctx __unused,
+				const void *iv __unused ) {
+	/* Do nothing */
+}
+
+static void cipher_null_encrypt ( void *ctx __unused, const void *src,
+				  void *dst, size_t len ) {
+	memcpy ( dst, src, len );
+}
+
+static void cipher_null_decrypt ( void *ctx __unused, const void *src,
+				  void *dst, size_t len ) {
+	memcpy ( dst, src, len );
+}
+
+struct cipher_algorithm cipher_null = {
+	.name = "null",
+	.ctxsize = 0,
+	.blocksize = 1,
+	.setkey = cipher_null_setkey,
+	.setiv = cipher_null_setiv,
+	.encrypt = cipher_null_encrypt,
+	.decrypt = cipher_null_decrypt,
+};
+
+struct pubkey_algorithm pubkey_null = {
+	.name = "null",
+	.ctxsize = 0,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/hmac.c b/qemu-0.15.x/roms/ipxe/src/crypto/hmac.c
new file mode 100644
index 0000000..6b61dc4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/hmac.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Keyed-Hashing for Message Authentication
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+
+/**
+ * Reduce HMAC key length
+ *
+ * @v digest		Digest algorithm to use
+ * @v digest_ctx	Digest context
+ * @v key		Key
+ * @v key_len		Length of key
+ */
+static void hmac_reduce_key ( struct digest_algorithm *digest,
+			      void *key, size_t *key_len ) {
+	uint8_t digest_ctx[digest->ctxsize];
+
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, key, *key_len );
+	digest_final ( digest, digest_ctx, key );
+	*key_len = digest->digestsize;
+}
+
+/**
+ * Initialise HMAC
+ *
+ * @v digest		Digest algorithm to use
+ * @v digest_ctx	Digest context
+ * @v key		Key
+ * @v key_len		Length of key
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used.  (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
+		 void *key, size_t *key_len ) {
+	unsigned char k_ipad[digest->blocksize];
+	unsigned int i;
+
+	/* Reduce key if necessary */
+	if ( *key_len > sizeof ( k_ipad ) )
+		hmac_reduce_key ( digest, key, key_len );
+
+	/* Construct input pad */
+	memset ( k_ipad, 0, sizeof ( k_ipad ) );
+	memcpy ( k_ipad, key, *key_len );
+	for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
+		k_ipad[i] ^= 0x36;
+	}
+	
+	/* Start inner hash */
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
+}
+
+/**
+ * Finalise HMAC
+ *
+ * @v digest		Digest algorithm to use
+ * @v digest_ctx	Digest context
+ * @v key		Key
+ * @v key_len		Length of key
+ * @v hmac		HMAC digest to fill in
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used.  (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
+		  void *key, size_t *key_len, void *hmac ) {
+	unsigned char k_opad[digest->blocksize];
+	unsigned int i;
+
+	/* Reduce key if necessary */
+	if ( *key_len > sizeof ( k_opad ) )
+		hmac_reduce_key ( digest, key, key_len );
+
+	/* Construct output pad */
+	memset ( k_opad, 0, sizeof ( k_opad ) );
+	memcpy ( k_opad, key, *key_len );
+	for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
+		k_opad[i] ^= 0x5c;
+	}
+	
+	/* Finish inner hash */
+	digest_final ( digest, digest_ctx, hmac );
+
+	/* Perform outer hash */
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
+	digest_update ( digest, digest_ctx, hmac, digest->digestsize );
+	digest_final ( digest, digest_ctx, hmac );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/md5.c b/qemu-0.15.x/roms/ipxe/src/crypto/md5.c
new file mode 100644
index 0000000..ef322ad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/md5.c
@@ -0,0 +1,234 @@
+/* 
+ * Cryptographic API.
+ *
+ * MD5 Message Digest Algorithm (RFC1321).
+ *
+ * Derived from cryptoapi implementation, originally based on the
+ * public domain implementation written by Colin Plumb in 1993.
+ *
+ * Reduced object size by around 50% compared to the original Linux
+ * version for use in Etherboot by Michael Brown.
+ *
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 James Morris <jmorris at intercode.com.au>
+ * Copyright (c) 2006 Michael Brown <mbrown at fensystems.co.uk>
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+
+struct md5_step {
+	u32 ( * f ) ( u32 b, u32 c, u32 d );
+	u8 coefficient;
+	u8 constant;
+};
+
+static u32 f1(u32 b, u32 c, u32 d)
+{
+	return ( d ^ ( b & ( c ^ d ) ) );
+}
+
+static u32 f2(u32 b, u32 c, u32 d)
+{
+	return ( c ^ ( d & ( b ^ c ) ) );
+}
+
+static u32 f3(u32 b, u32 c, u32 d)
+{
+	return ( b ^ c ^ d );
+}
+
+static u32 f4(u32 b, u32 c, u32 d)
+{
+	return ( c ^ ( b | ~d ) );
+}
+
+static struct md5_step md5_steps[4] = {
+	{
+		.f = f1,
+		.coefficient = 1,
+		.constant = 0,
+	},
+	{
+		.f = f2,
+		.coefficient = 5,
+		.constant = 1,
+	},
+	{
+		.f = f3,
+		.coefficient = 3,
+		.constant = 5,
+	},
+	{
+		.f = f4,
+		.coefficient = 7,
+		.constant = 0,
+	}
+};
+
+static const u8 r[64] = {
+	7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+	5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+	4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+	6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const u32 k[64] = {
+	0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
+	0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+	0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
+	0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+	0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
+	0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+	0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
+	0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+	0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
+	0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+	0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
+	0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+	0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
+	0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+	0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
+	0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
+};
+
+static void md5_transform(u32 *hash, const u32 *in)
+{
+	u32 a, b, c, d, f, g, temp;
+	int i;
+	struct md5_step *step;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	for ( i = 0 ; i < 64 ; i++ ) {
+		step = &md5_steps[i >> 4];
+		f = step->f ( b, c, d );
+		g = ( ( i * step->coefficient + step->constant ) & 0xf );
+		temp = d;
+		d = c;
+		c = b;
+		a += ( f + k[i] + in[g] );
+		a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
+		b += a;
+		a = temp;
+	}
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
+{
+	while (words--) {
+		le32_to_cpus(buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
+{
+	while (words--) {
+		cpu_to_le32s(buf);
+		buf++;
+	}
+}
+
+static inline void md5_transform_helper(struct md5_ctx *ctx)
+{
+	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
+	md5_transform(ctx->hash, ctx->block);
+}
+
+static void md5_init(void *context)
+{
+	struct md5_ctx *mctx = context;
+
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+}
+
+static void md5_update(void *context, const void *data, size_t len)
+{
+	struct md5_ctx *mctx = context;
+	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+	       data, avail);
+
+	md5_transform_helper(mctx);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		memcpy(mctx->block, data, sizeof(mctx->block));
+		md5_transform_helper(mctx);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	memcpy(mctx->block, data, len);
+}
+
+static void md5_final(void *context, void *out)
+{
+	struct md5_ctx *mctx = context;
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof (u64));
+		md5_transform_helper(mctx);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+	                  sizeof(u64)) / sizeof(u32));
+	md5_transform(mctx->hash, mctx->block);
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
+	memcpy(out, mctx->hash, sizeof(mctx->hash));
+	memset(mctx, 0, sizeof(*mctx));
+}
+
+struct digest_algorithm md5_algorithm = {
+	.name		= "md5",
+	.ctxsize	= MD5_CTX_SIZE,
+	.blocksize	= ( MD5_BLOCK_WORDS * 4 ),
+	.digestsize	= MD5_DIGEST_SIZE,
+	.init		= md5_init,
+	.update		= md5_update,
+	.final		= md5_final,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/sha1extra.c b/qemu-0.15.x/roms/ipxe/src/crypto/sha1extra.c
new file mode 100644
index 0000000..74445e9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/sha1extra.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crypto.h>
+#include <ipxe/sha1.h>
+#include <ipxe/hmac.h>
+#include <stdint.h>
+#include <byteswap.h>
+
+/**
+ * SHA1 pseudorandom function for creating derived keys
+ *
+ * @v key	Master key with which this call is associated
+ * @v key_len	Length of key
+ * @v label	NUL-terminated ASCII string describing purpose of PRF data
+ * @v data	Further data that should be included in the PRF
+ * @v data_len	Length of further PRF data
+ * @v prf_len	Bytes of PRF to generate
+ * @ret prf	Pseudorandom function bytes
+ *
+ * This is the PRF variant used by 802.11, defined in IEEE 802.11-2007
+ * 8.5.5.1. EAP-FAST uses a different SHA1-based PRF, and TLS uses an
+ * MD5-based PRF.
+ */
+void prf_sha1 ( const void *key, size_t key_len, const char *label,
+		const void *data, size_t data_len, void *prf, size_t prf_len )
+{
+	u32 blk;
+	u8 keym[key_len];	/* modifiable copy of key */
+	u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
+	u8 *in_blknr;		/* pointer to last byte of in, block number */
+	u8 out[SHA1_SIZE];	/* HMAC-SHA1 result */
+	u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
+	const size_t label_len = strlen ( label );
+
+	/* The HMAC-SHA-1 is calculated using the given key on the
+	   message text `label', followed by a NUL, followed by one
+	   byte indicating the block number (0 for first). */
+
+	memcpy ( keym, key, key_len );
+
+	memcpy ( in, label, strlen ( label ) + 1 );
+	memcpy ( in + label_len + 1, data, data_len );
+	in_blknr = in + label_len + 1 + data_len;
+
+	for ( blk = 0 ;; blk++ ) {
+		*in_blknr = blk;
+
+		hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
+		hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
+		hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
+
+		if ( prf_len <= SHA1_SIZE ) {
+			memcpy ( prf, out, prf_len );
+			break;
+		}
+
+		memcpy ( prf, out, SHA1_SIZE );
+		prf_len -= SHA1_SIZE;
+		prf += SHA1_SIZE;
+	}
+}
+
+/**
+ * PBKDF2 key derivation function inner block operation
+ *
+ * @v passphrase	Passphrase from which to derive key
+ * @v pass_len		Length of passphrase
+ * @v salt		Salt to include in key
+ * @v salt_len		Length of salt
+ * @v iterations	Number of iterations of SHA1 to perform
+ * @v blocknr		Index of this block, starting at 1
+ * @ret block		SHA1_SIZE bytes of PBKDF2 data
+ *
+ * The operation of this function is described in RFC 2898.
+ */
+static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
+			    const void *salt, size_t salt_len,
+			    int iterations, u32 blocknr, u8 *block )
+{
+	u8 pass[pass_len];	/* modifiable passphrase */
+	u8 in[salt_len + 4];	/* input buffer to first round */
+	u8 last[SHA1_SIZE];	/* output of round N, input of N+1 */
+	u8 sha1_ctx[SHA1_CTX_SIZE];
+	u8 *next_in = in;	/* changed to `last' after first round */
+	int next_size = sizeof ( in );
+	int i, j;
+
+	blocknr = htonl ( blocknr );
+
+	memcpy ( pass, passphrase, pass_len );
+	memcpy ( in, salt, salt_len );
+	memcpy ( in + salt_len, &blocknr, 4 );
+	memset ( block, 0, SHA1_SIZE );
+
+	for ( i = 0; i < iterations; i++ ) {
+		hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
+		hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
+		hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
+
+		for ( j = 0; j < SHA1_SIZE; j++ ) {
+			block[j] ^= last[j];
+		}
+
+		next_in = last;
+		next_size = SHA1_SIZE;
+	}
+}
+
+/**
+ * PBKDF2 key derivation function using SHA1
+ *
+ * @v passphrase	Passphrase from which to derive key
+ * @v pass_len		Length of passphrase
+ * @v salt		Salt to include in key
+ * @v salt_len		Length of salt
+ * @v iterations	Number of iterations of SHA1 to perform
+ * @v key_len		Length of key to generate
+ * @ret key		Generated key bytes
+ *
+ * This is used most notably in 802.11 WPA passphrase hashing, in
+ * which case the salt is the SSID, 4096 iterations are used, and a
+ * 32-byte key is generated that serves as the Pairwise Master Key for
+ * EAPOL authentication.
+ *
+ * The operation of this function is further described in RFC 2898.
+ */
+void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
+		   const void *salt, size_t salt_len,
+		   int iterations, void *key, size_t key_len )
+{
+	u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
+	u32 blk;
+	u8 buf[SHA1_SIZE];
+
+	for ( blk = 1; blk <= blocks; blk++ ) {
+		pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
+				iterations, blk, buf );
+		if ( key_len <= SHA1_SIZE ) {
+			memcpy ( key, buf, key_len );
+			break;
+		}
+
+		memcpy ( key, buf, SHA1_SIZE );
+		key_len -= SHA1_SIZE;
+		key += SHA1_SIZE;
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/crypto/x509.c b/qemu-0.15.x/roms/ipxe/src/crypto/x509.c
new file mode 100644
index 0000000..49bc2b8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/crypto/x509.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+
+/** @file
+ *
+ * X.509 certificates
+ *
+ * The structure of X.509v3 certificates is concisely documented in
+ * RFC5280 section 4.1.  The structure of RSA public keys is
+ * documented in RFC2313.
+ */
+
+/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
+static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+					      0x0d, 0x01, 0x01, 0x01 };
+
+/**
+ * Identify X.509 certificate public key
+ *
+ * @v certificate	Certificate
+ * @v algorithm		Public key algorithm to fill in
+ * @v pubkey		Public key value to fill in
+ * @ret rc		Return status code
+ */
+static int x509_public_key ( const struct asn1_cursor *certificate,
+			     struct asn1_cursor *algorithm,
+			     struct asn1_cursor *pubkey ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Locate subjectPublicKeyInfo */
+	memcpy ( &cursor, certificate, sizeof ( cursor ) );
+	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
+	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
+	       asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
+	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
+	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
+	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
+	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
+	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
+	       asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return rc;
+	}
+
+	/* Locate algorithm */
+	memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
+	rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate algorithm in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return rc;
+	}
+
+	/* Locate subjectPublicKey */
+	memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
+	rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
+	       asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate subjectPublicKey in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Identify X.509 certificate RSA modulus and public exponent
+ *
+ * @v certificate	Certificate
+ * @v rsa		RSA public key to fill in
+ * @ret rc		Return status code
+ *
+ * The caller is responsible for eventually calling
+ * x509_free_rsa_public_key() to free the storage allocated to hold
+ * the RSA modulus and exponent.
+ */
+int x509_rsa_public_key ( const struct asn1_cursor *certificate,
+			  struct x509_rsa_public_key *rsa_pubkey ) {
+	struct asn1_cursor algorithm;
+	struct asn1_cursor pubkey;
+	struct asn1_cursor modulus;
+	struct asn1_cursor exponent;
+	int rc;
+
+	/* First, extract the public key algorithm and key data */
+	if ( ( rc = x509_public_key ( certificate, &algorithm,
+				      &pubkey ) ) != 0 )
+		return rc;
+
+	/* Check that algorithm is RSA */
+	rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate algorithm:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+	return rc;
+	}
+	if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
+	     ( memcmp ( algorithm.data, &oid_rsa_encryption,
+			sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
+		DBG ( "algorithm is not rsaEncryption in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return -ENOTSUP;
+	}
+
+	/* Check that public key is a byte string, i.e. that the
+	 * "unused bits" byte contains zero.
+	 */
+	if ( ( pubkey.len < 1 ) ||
+	     ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
+		DBG ( "subjectPublicKey is not a byte string in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return -ENOTSUP;
+	}
+	pubkey.data++;
+	pubkey.len--;
+
+	/* Pick out the modulus and exponent */
+	rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate RSAPublicKey in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return -ENOTSUP;
+	}
+	memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
+	rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate modulus in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return -ENOTSUP;
+	}
+	memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
+	rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
+	       asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
+	if ( rc != 0 ) {
+		DBG ( "Cannot locate publicExponent in:\n" );
+		DBG_HDA ( 0, certificate->data, certificate->len );
+		return -ENOTSUP;
+	}
+
+	/* Allocate space and copy out modulus and exponent */
+	rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
+	if ( ! rsa_pubkey->modulus )
+		return -ENOMEM;
+	rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
+	memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
+	rsa_pubkey->modulus_len = modulus.len;
+	memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
+	rsa_pubkey->exponent_len = exponent.len;
+
+	DBG2 ( "RSA modulus:\n" );
+	DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
+	DBG2 ( "RSA exponent:\n" );
+	DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/doc/build_sys.dox b/qemu-0.15.x/roms/ipxe/src/doc/build_sys.dox
new file mode 100644
index 0000000..9466f66
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/doc/build_sys.dox
@@ -0,0 +1,419 @@
+/** @page build_sys Build system
+
+ at section overview Overview
+
+Building an Etherboot image consists of three stages:
+
+  -# @ref compilation : Compiling all the source files into object files
+  -# @ref linking : Linking a particular image from selected object files
+  -# @ref finalisation : Producing the final output binary
+
+Though this is a remarkably complex process, it is important to note
+that it all happens automatically.  Whatever state your build tree is
+in, you can always type, for example
+
+ at code
+
+	make bin/rtl8139.dsk
+
+ at endcode
+
+and know that you will get a floppy disk image with an RTL8139 driver
+built from the current sources.
+
+ at section compilation Compilation
+
+ at subsection comp_overview Overview
+
+Each source file (a @c .c or a @c .S file) is compiled into a @c .o
+file in the @c bin/ directory.  Etherboot makes minimal use of
+conditional compilation (see @ref ifdef_harmful), and so you will find
+that all objects get built, even the objects that correspond to
+features that you are not intending to include in your image.  For
+example, all network card drivers will be compiled even if you are
+just building a ROM for a 3c509 card.  This is a deliberate design
+decision; please do @b not attempt to "fix" the build system to avoid
+doing this.
+
+Source files are defined to be any @c .c or @c .S files found in a
+directory listed in the Makefile variable #SRCDIRS.  You therefore do
+ at b not need to edit the Makefile just because you have added a new
+source file (although you will need to edit the Makefile if you have
+added a new source directory).  To see a list of all source
+directories and source files that the build system currently knows
+about, you can use the commands
+
+ at code
+
+	make srcdirs
+	make srcs
+
+ at endcode
+
+Rules for compiling @c .c and @c .S files are defined in the Makefile
+variables #RULE_c and #RULE_S.  Makefile rules are automatically
+generated for each source file using these rules.  The generated rules
+can be found in the @c .d file corresponding to each source file;
+these are located in <tt>bin/deps/</tt>.  For example, the rules
+generated for <tt>drivers/net/rtl8139.c</tt> can be found in
+<tt>bin/deps/drivers/net/rtl8139.c.d</tt>.  These rules allow you to
+type, for example
+
+ at code
+
+	make bin/rtl8139.o
+
+ at endcode
+
+and have <tt>rtl8139.o</tt> be built from
+<tt>drivers/net/rtl8139.c</tt> using the generic rule #RULE_c for
+compiling @c .c files.
+
+You can see the full list of object files that will be built using
+
+ at code
+
+	make bobjs
+
+ at endcode
+
+ at subsection comp_ar After compilation
+
+Once all objects have been compiled, they will be collected into a
+build library ("blib") in <tt>bin/blib.a</tt>.
+
+ at subsection comp_custom Customising compilation
+
+The Makefile rules for a particular object can be customised to a
+certain extent by defining the Makefile variable CFLAGS_@<object@>.
+For example, if you were to set
+
+ at code
+
+	CFLAGS_rtl8139 = -DFOO
+
+ at endcode
+
+then <tt>bin/rtl8139.o</tt> would be compiled with the additional
+flags <tt>-DFOO</tt>.  To see the flags that will be used when
+compiling a particular object, you can use e.g.
+
+ at code
+
+	make bin/rtl8139.flags
+
+ at endcode
+
+If you need more flexibility than the CFLAGS_@<object@> mechanism
+provides, then you can exclude source files from the automatic rule
+generation process by listing them in the Makefile variable
+#NON_AUTO_SRCS.  The command
+
+ at code
+
+	make autosrcs
+
+ at endcode
+
+will show you which files are currently part of the automatic rule
+generation process.
+
+ at subsection comp_multiobj Multiple objects
+
+A single source file can be used to generate multiple object files.
+This is used, for example, to generate the decompressing and the
+non-decompressing prefixes from the same source files.
+
+By default, a single object will be built from each source file.  To
+override the list of objects for a source file, you can define the
+Makefile variable OBJS_@<object@>.  For example, the
+<tt>arch/i386/prefix/dskprefix.S</tt> source file is built into two
+objects, <tt>bin/dskprefix.o</tt> and <tt>zdskprefix.o</tt> by
+defining the Makefile variable
+
+ at code
+
+	OBJS_dskprefix = dskprefix zdskprefix
+
+ at endcode
+
+Since there would be little point in building two identical objects,
+customised compilation flags (see @ref comp_custom) are defined as
+
+ at code
+
+	CFLAGS_zdskprefix = -DCOMPRESS
+
+ at endcode
+
+Thus, <tt>arch/i386/prefix/dskprefix.S</tt> is built into @c
+dskprefix.o using the normal set of flags, and into @c zdskprefix.o
+using the normal set of flags plus <tt>-DCOMPRESS</tt>.
+
+ at subsection comp_debug Special debugging targets
+
+In addition to the basic rules #RULE_c and #RULE_S for compiling
+source files into object files, there are various other rules that can
+be useful for debugging.
+
+ at subsubsection comp_debug_c_to_c Preprocessed C
+
+You can see the results of preprocessing a @c .c file (including the
+per-object flags defined via CFLAGS_@<object@> if applicable) using
+e.g.
+
+ at code
+
+	make bin/rtl8139.c
+
+ at endcode
+
+and examining the resulting file (<tt>bin/rtl8139.c</tt> in this
+case).
+
+ at subsubsection comp_debug_x_to_s Assembler
+
+You can see the results of assembling a @c .c file, or of
+preprocessing a @c .S file, using e.g.
+
+ at code
+
+	make bin/rtl8139.s
+	make bin/zdskprefix.s
+
+ at endcode
+
+ at subsubsection comp_debug_dbg Debugging-enabled targets
+
+You can build targets with debug messages (DBG()) enabled using e.g.
+
+ at code
+
+	make bin/rtl8139.dbg.o
+	make bin/rtl8139.dbg2.o
+
+ at endcode
+
+You will probably not need to use these targets directly, since a
+mechanism exists to select debugging levels at build time; see @ref
+debug.
+
+ at section linking Linking
+
+ at subsection link_overview Overview
+
+Etherboot is designed to be small and extremely customisable.  This is
+achieved by linking in only the features that are really wanted in any
+particular build.
+
+There are two places from which the list of desired features is
+obtained:
+
+  -# @ref link_config_h
+  -# @ref link_cmdline
+
+ at subsection link_config_h config.h
+
+The config.h file is used to define global build options that are
+likely to apply to all images that you build, such as the console
+types, supported download protocols etc.  See the documentation for
+config.h for more details.
+
+ at subsection link_cmdline The make command line
+
+When you type a command such as
+
+ at code
+
+	make bin/dfe538.zrom
+
+ at endcode
+
+it is used to derive the following information:
+
+   - We are building a compressed ROM image
+   - The DFE538 is a PCI NIC, so we need the decompressing PCI ROM prefix
+   - The PCI IDs for the DFE538 are 1186:1300
+   - The DFE538 is an rtl8139-based card, therefore we need the rtl8139 driver
+
+You can see this process in action using the command
+
+ at code
+
+	make bin/dfe538.zrom.info
+
+ at endcode
+
+which will print
+
+ at code
+
+	Elements             : dfe538
+	Prefix               : zrom
+	Drivers              : rtl8139
+	ROM name             : dfe538
+	Media                : rom
+
+	ROM type             : pci
+	PCI vendor           : 0x1186
+	PCI device           : 0x1300
+
+	LD driver symbols    : obj_rtl8139
+	LD prefix symbols    : obj_zpciprefix
+	LD ID symbols        : pci_vendor_id=0x1186 pci_device_id=0x1300
+
+	LD target flags      :  -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix   -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139   -u obj_config --defsym check_obj_config=obj_config  --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+ at endcode
+
+This should be interpreted as follows:
+
+ at code
+
+	Elements             : dfe538
+	Prefix               : zrom
+
+ at endcode
+
+"Elements" is the list of components preceding the first dot in the
+target name.  "Prefix" is the component following the first dot in the
+target name.  (It's called a "prefix" because the code that makes it a
+ at c .zrom (rather than a @c .dsk, @c .zpxe or any other type of target)
+usually ends up at the start of the resulting binary image.)
+
+ at code
+
+	Drivers              : rtl8139
+
+ at endcode
+
+"Drivers" is the list of drivers corresponding to the "Elements".
+Most drivers support several network cards.  The PCI_ROM() and
+ISA_ROM() macros are used in the driver source files to list the cards
+that a particular driver can support.
+
+ at code
+
+	ROM name             : dfe538
+
+ at endcode
+
+"ROM name" is the first element in the "Elements" list.  It is used to
+select the PCI IDs for a PCI ROM.
+
+ at code
+
+	Media                : rom
+
+ at endcode
+
+"Media" is the "Prefix" minus the leading @c z, if any.
+
+ at code
+
+	ROM type             : pci
+	PCI vendor           : 0x1186
+	PCI device           : 0x1300
+
+ at endcode
+
+These are derived from the "ROM name" and the PCI_ROM() or ISA_ROM()
+macros in the driver source files.
+
+ at code
+
+	LD driver symbols    : obj_rtl8139
+	LD prefix symbols    : obj_zpciprefix
+
+ at endcode
+
+This is the interesting part.  At this point, we have established that
+we need the rtl8139 driver (i.e. @c rtl8139.o) and the decompressing
+PCI prefix (i.e. @c zpciprefix.o).  Our build system (via the
+compiler.h header file) arranges that every object exports a symbol
+obj_@<object@>; this can be seen by e.g.
+
+ at code
+
+	objdump -t bin/rtl8139.o
+
+ at endcode
+
+which will show the line
+
+ at code
+
+	00000000 g       *ABS*  00000000 obj_rtl8139
+
+ at endcode
+
+By instructing the linker that we need the symbols @c obj_rtl8139 and
+ at c obj_zpciprefix, we can therefore ensure that these two objects are
+included in our build.  (The linker will also include any objects that
+these two objects require, since that's the whole purpose of the
+linker.)
+
+In a similar way, we always instruct the linker that we need the
+symbol @c obj_config, in order to include the object @c config.o.  @c
+config.o is used to drag in the objects that were specified via
+config.h; see @ref link_config_h.
+
+ at code
+
+	LD target flags      :  -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix   -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139   -u obj_config --defsym check_obj_config=obj_config  --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+ at endcode
+
+These are the flags that we pass to the linker in order to include the
+objects that we want in our build, and to check that they really get
+included.  (This latter check is needed to work around what seems to
+be a bug in @c ld).
+
+The linker does its job of linking all the required objects together
+into a coherent build.  The best way to see what is happening is to
+look at one of the resulting linker maps; try, for example
+
+ at code
+
+	make bin/dfe538.dsk.map
+
+ at endcode
+
+The linker map includes, amongst others:
+
+  - A list of which objects are included in the build, and why.
+  - The results of processing the linker script, line-by-line.
+  - A complete symbol table of the resulting build.
+
+It is worth spending time examining the linker map to see how an
+Etherboot image is assembled.
+
+Whatever format is selected, the Etherboot image is built into an ELF
+file, simply because this is the default format used by @c ld.
+
+ at section finalisation Finalisation
+
+ at subsection final_overview Overview
+
+The ELF file resulting from @ref linking "linking" needs to be
+converted into the final binary image.  Usually, this is just a case
+of running
+
+ at code
+
+	objcopy -O binary <elf file> <output file>
+
+ at endcode
+
+to convert the ELF file into a raw binary image.  Certain image
+formats require special additional treatment.
+
+ at subsection final_rom ROM images
+
+ROM images must be rounded up to a suitable ROM size (e.g. 16kB or
+32kB), and certain header information such as checksums needs to be
+filled in.  This is done by the @c makerom.pl program.
+
+ at section debug Debugging-enabled builds
+
+*/
diff --git a/qemu-0.15.x/roms/ipxe/src/doc/pxe_extensions b/qemu-0.15.x/roms/ipxe/src/doc/pxe_extensions
new file mode 100644
index 0000000..2411486
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/doc/pxe_extensions
@@ -0,0 +1,312 @@
+FILE OPEN
+
+Op-Code:	PXENV_FILE_OPEN (00e0h)
+
+Input:		Far pointer to a t_PXENV_FILE_OPEN parameter structure
+		that has been initialised by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Opens a file specified by a URL for reading.  Multiple
+		files may be opened and used concurrently.
+
+
+typedef struct s_PXENV_FILE_OPEN {
+	PXENV_STATUS Status;
+	UINT16 FileHandle;
+	SEGOFF16 FileName;
+	UINT32 Reserved;
+} t_PXENV_FILE_OPEN;
+
+
+Set before calling API service:
+
+FileName:	URL of file to be opened.  Null terminated.
+
+Reserved:	Must be zero.
+
+
+Returned from API service:
+
+FileHandle:	Handle for use in subsequent PXE FILE API calls.
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+FILE CLOSE
+
+Op-Code:	PXENV_FILE_CLOSE (00e1h)
+
+Input:		Far pointer to a t_PXENV_FILE_CLOSE parameter structure
+		that has been initialised by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Closes a previously opened file.
+
+
+typedef struct s_PXENV_FILE_CLOSE {
+	PXENV_STATUS Status;
+	UINT16 FileHandle;
+} t_PXENV_FILE_CLOSE;
+
+
+Set before calling API service:
+
+FileHandle:	Handle obtained when file was opened.
+
+
+Returned from API service:
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+FILE SELECT
+
+Op-Code:	PXENV_FILE_SELECT (00e2h)
+
+Input:		Far pointer to a t_PXENV_FILE_SELECT parameter structure
+		that has been initialised by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Check a previously opened file's readiness for I/O.
+
+
+typedef struct s_PXENV_FILE_SELECT {
+	PXENV_STATUS Status;
+	UINT16 FileHandle;
+	UINT16 Ready;
+#define RDY_READ 0x0001
+} t_PXENV_FILE_SELECT;
+
+
+Set before calling API service:
+
+FileHandle:	Handle obtained when file was opened.
+
+
+Returned from API service:
+
+Ready:		Indication of readiness.  This can be zero, or more,
+		of the RDY_xxx constants.  Multiple values are
+		arithmetically or-ed together.
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+FILE READ
+
+Op-Code:	PXENV_FILE_READ (00e3h)
+
+Input:		Far pointer to a t_PXENV_FILE_READ parameter structure
+		that has been initialised by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+		This API function is non-blocking.  PXENV_EXIT_SUCCESS
+		and PXENV_STATUS_SUCCESS is returned if a data block
+		has been transferred into the caller's buffer.
+		PXENV_EXIT_FAILURE and PXENV_STATUS_TFTP_OPEN is
+		returned if no data is available to transfer; any
+		other status code reflects an error.
+
+Description:	Read from a previously opened file.
+
+
+typedef struct s_PXENV_FILE_READ {
+	PXENV_STATUS Status;
+	UINT16 FileHandle;
+	UINT16 BufferSize;
+	SEGOFF16 Buffer;
+} t_PXENV_FILE_READ;
+
+
+Set before calling API service:
+
+FileHandle:	Handle obtained when file was opened.
+
+BufferSize:	Maximum number of data bytes that can be copied into
+		Buffer.
+
+Buffer:		Segment:Offset address of data buffer.
+
+
+Returned from API service:
+
+BufferSize:	Number of bytes written to the data buffer.  End of
+		file if this is zero.
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+GET FILE SIZE
+
+Op-Code:	PXENV_GET_FILE_SIZE (00e4h)
+
+Input:		Far pointer to a t_PXENV_GET_FILE_SIZE parameter
+		structure that has been initialised by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Determine size of a previously opened file.
+
+
+typedef struct s_PXENV_GET_FILE_SIZE {
+	PXENV_STATUS Status;
+	UINT16 FileHandle;
+	UINT32 FileSize;
+} t_PXENV_GET_FILE_SIZE;
+
+
+Set before calling API service:
+
+FileHandle:	Handle obtained when file was opened.
+
+
+Returned from API service:
+
+FileSize:	Size of the file in bytes.
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+FILE EXEC
+
+Op-Code:	PXENV_FILE_EXEC (00e5h)
+
+Input:		Far pointer to a t_PXENV_FILE_EXEC parameter
+		structure that has been initialized by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The Status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Execute a iPXE command.
+
+typedef struct s_PXENV_FILE_EXEC {
+        PXENV_STATUS_t Status;
+        SEGOFF16_t Command;
+} t_PXENV_FILE_EXEC;
+
+
+Set before calling API service:
+
+Command:	Command to execute.  Null terminated.
+
+
+Returned from API service:
+
+Status:		See PXENV_STATUS_xxx constants.
+
+
+
+
+FILE API CHECK
+
+Op-Code:	PXENV_FILE_API_CHECK (00e6h)
+
+Input:		Far pointer to a t_PXENV_FILE_CHECK_API parameter
+		structure that has been initialized by the caller.
+
+		On entry, the Magic field should contain the number
+		0x91d447b2 or the call will fail.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The Status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+		If this API is present and the Magic field contains the
+		proper value on entry, AX will contain PXENV_EXIT_SUCCESS,
+		the Status field PXENV_STATUS_SUCCESS, and the Magic field
+		the number 0xe9c17b20.  Any other combination should be
+		considered a failure.
+
+Description:	Detect presence of this API.
+
+
+typedef struct s_PXENV_FILE_CHECK_API {
+	PXENV_STATUS Status;
+	UINT16 Size;
+	UINT32 Magic;
+	UINT32 Provider;
+	UINT32 APIMask;
+	UINT32 Flags;
+} t_PXENV_FILE_CHECK_API;
+
+Set before calling API service:
+
+Size:		Set to sizeof(t_PXENV_FILE_CHECK_API) (20).
+Magic:		Set to 0x91d447b2.
+
+
+Returned from API service:
+
+Size:		Set to the number of bytes filled in (20).
+Magic:		Set to 0xe9c17b20.
+Provider:	Set to 0x45585067 ("iPXE").  Another implementation of this
+		API can use another value, e.g. to indicate a different
+		command set supported by FILE EXEC.
+APIMask:	Bitmask of supported API functions (one bit for each function
+		in the range 00e0h to 00ffh).
+Flags:		Set to zero, reserved for future use.
+
+
+
+
+FILE EXIT HOOK
+
+Op-Code:	PXENV_FILE_EXIT_HOOK (00e7h)
+
+Input:		Far pointer to a t_PXENV_FILE_EXIT_HOOK parameter
+		structure that has been initialized by the caller.
+
+Output:		PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+		returned in AX.  The Status field in the parameter
+		structure must be set to one of the values represented
+		by the PXENV_STATUS_xxx constants.
+
+Description:	Modify the exit path to jump to the specified code.
+		Only valid for pxeprefix-based builds.
+
+typedef struct s_PXENV_FILE_EXIT_HOOK {
+        PXENV_STATUS_t Status;
+        SEGOFF16_t Hook;
+} t_PXENV_FILE_EXIT_HOOK;
+
+
+Set before calling API service:
+
+Hook:		The SEG16:OFF16 of the code to jump to.
+
+
+Returned from API service:
+
+Status:		See PXENV_STATUS_xxx constants.
diff --git a/qemu-0.15.x/roms/ipxe/src/doxygen.cfg b/qemu-0.15.x/roms/ipxe/src/doxygen.cfg
new file mode 100644
index 0000000..4fc9f1e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/doxygen.cfg
@@ -0,0 +1,1486 @@
+# Doxyfile 1.5.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = iPXE
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @BIN@/doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = v=@param \
+                         ret=@retval \
+                         err=@exception
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = YES
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
+# doxygen. The layout file controls the global structure of the generated output files 
+# in an output format independent way. The create the layout file that represents 
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
+# of the layout file.
+
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = 
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = @SRCDIRS@ \
+                         @INCDIRS@ \
+                         config \
+                         doc
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c \
+                         *.h \
+                         *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = 
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = 
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = YES
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
+# are set, an additional index file will be generated that can be used as input for 
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file .
+
+QHG_LOCATION           = 
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW      = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = 
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = YES
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = YES
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = 
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = 
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = 
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = @INCDIRS@
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = DOXYGEN=1
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = __attribute__ \
+                         __unused \
+                         __used \
+                         __aligned \
+                         __table \
+                         __table_start \
+                         __table_end
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/bitbash.c b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/bitbash.c
new file mode 100644
index 0000000..ac91407
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/bitbash.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bitbash.h>
+
+/** @file
+ *
+ * Bit-bashing interfaces
+ *
+ */
+
+/**
+ * Set/clear output bit
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @v data		Value to write
+ * 
+ * If @c data is 0, a logic 0 will be written.  If @c data is
+ * non-zero, a logic 1 will be written.
+ */
+void write_bit ( struct bit_basher *basher, unsigned int bit_id,
+		 unsigned long data ) {
+	basher->op->write ( basher, bit_id, ( data ? -1UL : 0 ) );
+}
+
+/**
+ * Read input bit
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @ret data		Value read
+ *
+ * @c data will always be either 0 or -1UL.  The idea is that the
+ * caller can simply binary-AND the returned value with whatever mask
+ * it needs to apply.
+ */
+int read_bit ( struct bit_basher *basher, unsigned int bit_id ) {
+	return ( basher->op->read ( basher, bit_id ) ? -1UL : 0 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/i2c_bit.c b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/i2c_bit.c
new file mode 100644
index 0000000..ccf82db
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/i2c_bit.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ipxe/bitbash.h>
+#include <ipxe/i2c.h>
+
+/** @file
+ *
+ * I2C bit-bashing interface
+ *
+ * This implements a simple I2C master via a bit-bashing interface
+ * that provides two lines: SCL (clock) and SDA (data).
+ */
+
+/**
+ * Delay between output state changes
+ *
+ * Max rated i2c speed (for the basic i2c protocol) is 100kbps,
+ * i.e. 200k clock transitions per second.
+ */
+static void i2c_delay ( void ) {
+	udelay ( I2C_UDELAY );
+}
+
+/**
+ * Set state of I2C SCL line
+ *
+ * @v basher		Bit-bashing interface
+ * @v state		New state of SCL
+ */
+static void setscl ( struct bit_basher *basher, int state ) {
+	DBG2 ( "%c", ( state ? '/' : '\\' ) );
+	write_bit ( basher, I2C_BIT_SCL, state );
+	i2c_delay();
+}
+
+/**
+ * Set state of I2C SDA line
+ *
+ * @v basher		Bit-bashing interface
+ * @v state		New state of SDA
+ */
+static void setsda ( struct bit_basher *basher, int state ) {
+	DBG2 ( "%c", ( state ? '1' : '0' ) );
+	write_bit ( basher, I2C_BIT_SDA, state );
+	i2c_delay();
+}
+
+/**
+ * Get state of I2C SDA line
+ *
+ * @v basher		Bit-bashing interface
+ * @ret state		State of SDA
+ */
+static int getsda ( struct bit_basher *basher ) {
+	int state;
+	state = read_bit ( basher, I2C_BIT_SDA );
+	DBG2 ( "%c", ( state ? '+' : '-' ) );
+	return state;
+}
+
+/**
+ * Send an I2C start condition
+ *
+ * @v basher		Bit-bashing interface
+ */
+static void i2c_start ( struct bit_basher *basher ) {
+	setscl ( basher, 1 );
+	setsda ( basher, 0 );
+	setscl ( basher, 0 );
+	setsda ( basher, 1 );
+}
+
+/**
+ * Send an I2C data bit
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit		Bit to send
+ */
+static void i2c_send_bit ( struct bit_basher *basher, int bit ) {
+	setsda ( basher, bit );
+	setscl ( basher, 1 );
+	setscl ( basher, 0 );
+	setsda ( basher, 1 );
+}
+
+/**
+ * Receive an I2C data bit
+ *
+ * @v basher		Bit-bashing interface
+ * @ret bit		Received bit
+ */
+static int i2c_recv_bit ( struct bit_basher *basher ) {
+	int bit;
+
+	setscl ( basher, 1 );
+	bit = getsda ( basher );
+	setscl ( basher, 0 );
+	return bit;
+}
+
+/**
+ * Send an I2C stop condition
+ *
+ * @v basher		Bit-bashing interface
+ */
+static void i2c_stop ( struct bit_basher *basher ) {
+	setsda ( basher, 0 );
+	setscl ( basher, 1 );
+	setsda ( basher, 1 );
+}
+
+/**
+ * Send byte via I2C bus and check for acknowledgement
+ *
+ * @v basher		Bit-bashing interface
+ * @v byte		Byte to send
+ * @ret rc		Return status code
+ *
+ * Sends a byte via the I2C bus and checks for an acknowledgement from
+ * the slave device.
+ */
+static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
+	int i;
+	int ack;
+
+	/* Send byte */
+	DBG2 ( "[send %02x]", byte );
+	for ( i = 8 ; i ; i-- ) {
+		i2c_send_bit ( basher, byte & 0x80 );
+		byte <<= 1;
+	}
+
+	/* Check for acknowledgement from slave */
+	ack = ( i2c_recv_bit ( basher ) == 0 );
+	DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) );
+
+	return ( ack ? 0 : -EIO );
+}
+
+/**
+ * Receive byte via I2C bus
+ *
+ * @v basher		Bit-bashing interface
+ * @ret byte		Received byte
+ *
+ * Receives a byte via the I2C bus and sends NACK to the slave device.
+ */
+static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
+	uint8_t byte = 0;
+	int i;
+
+	/* Receive byte */
+	for ( i = 8 ; i ; i-- ) {
+		byte <<= 1;
+		byte |= ( i2c_recv_bit ( basher ) & 0x1 );
+	}
+
+	/* Send NACK */
+	i2c_send_bit ( basher, 1 );
+
+	DBG2 ( "[rcvd %02x]", byte );
+	return byte;
+}
+
+/**
+ * Select I2C device for reading or writing
+ *
+ * @v basher		Bit-bashing interface
+ * @v i2cdev		I2C device
+ * @v offset		Starting offset within the device
+ * @v direction		I2C_READ or I2C_WRITE
+ * @ret rc		Return status code
+ */
+static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
+			unsigned int offset, unsigned int direction ) {
+	unsigned int address;
+	int shift;
+	unsigned int byte;
+	int rc;
+
+	i2c_start ( basher );
+
+	/* Calculate address to appear on bus */
+	address = ( ( ( i2cdev->dev_addr |
+			( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 )
+		    | direction );
+
+	/* Send address a byte at a time */
+	for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ;
+	      shift >= 0 ; shift -= 8 ) {
+		byte = ( ( address >> shift ) & 0xff );
+		if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Reset I2C bus
+ *
+ * @v basher		Bit-bashing interface
+ * @ret rc		Return status code
+ *
+ * i2c devices often don't have a reset line, so even a reboot or
+ * system power cycle is sometimes not enough to bring them back to a
+ * known state.
+ */
+static int i2c_reset ( struct bit_basher *basher ) {
+	unsigned int i;
+	int sda;
+
+	/* Clock through several cycles, waiting for an opportunity to
+	 * pull SDA low while SCL is high (which creates a start
+	 * condition).
+	 */
+	setscl ( basher, 0 );
+	setsda ( basher, 1 );
+	for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) {
+		setscl ( basher, 1 );
+		sda = getsda ( basher );
+		if ( sda ) {
+			/* Now that the device will see a start, issue it */
+			i2c_start ( basher );
+			/* Stop the bus to leave it in a known good state */
+			i2c_stop ( basher );
+			DBGC ( basher, "I2CBIT %p reset after %d attempts\n",
+			       basher, ( i + 1 ) );
+			return 0;
+		}
+		setscl ( basher, 0 );
+	}
+
+	DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n",
+	       basher, i );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Read data from I2C device via bit-bashing interface
+ *
+ * @v i2c		I2C interface
+ * @v i2cdev		I2C device
+ * @v offset		Starting offset within the device
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ *
+ * Note that attempting to read zero bytes of data is a valid way to
+ * check for I2C device presence.
+ */
+static int i2c_bit_read ( struct i2c_interface *i2c,
+			  struct i2c_device *i2cdev, unsigned int offset,
+			  uint8_t *data, unsigned int len ) {
+	struct i2c_bit_basher *i2cbit
+		= container_of ( i2c, struct i2c_bit_basher, i2c );
+	struct bit_basher *basher = &i2cbit->basher;
+	int rc = 0;
+
+	DBGC ( basher, "I2CBIT %p reading from device %x: ",
+	       basher, i2cdev->dev_addr );
+
+	for ( ; ; data++, offset++ ) {
+
+		/* Select device for writing */
+		if ( ( rc = i2c_select ( basher, i2cdev, offset,
+					 I2C_WRITE ) ) != 0 )
+			break;
+
+		/* Abort at end of data */
+		if ( ! ( len-- ) )
+			break;
+
+		/* Select offset */
+		if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
+			break;
+		
+		/* Select device for reading */
+		if ( ( rc = i2c_select ( basher, i2cdev, offset,
+					 I2C_READ ) ) != 0 )
+			break;
+
+		/* Read byte */
+		*data = i2c_recv_byte ( basher );
+		DBGC ( basher, "%02x ", *data );
+	}
+	
+	DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
+	i2c_stop ( basher );
+	return rc;
+}
+
+/**
+ * Write data to I2C device via bit-bashing interface
+ *
+ * @v i2c		I2C interface
+ * @v i2cdev		I2C device
+ * @v offset		Starting offset within the device
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ *
+ * Note that attempting to write zero bytes of data is a valid way to
+ * check for I2C device presence.
+ */
+static int i2c_bit_write ( struct i2c_interface *i2c,
+			   struct i2c_device *i2cdev, unsigned int offset,
+			   const uint8_t *data, unsigned int len ) {
+	struct i2c_bit_basher *i2cbit
+		= container_of ( i2c, struct i2c_bit_basher, i2c );
+	struct bit_basher *basher = &i2cbit->basher;
+	int rc = 0;
+
+	DBGC ( basher, "I2CBIT %p writing to device %x: ",
+	       basher, i2cdev->dev_addr );
+
+	for ( ; ; data++, offset++ ) {
+
+		/* Select device for writing */
+		if ( ( rc = i2c_select ( basher, i2cdev, offset,
+					 I2C_WRITE ) ) != 0 )
+			break;
+		
+		/* Abort at end of data */
+		if ( ! ( len-- ) )
+			break;
+
+		/* Select offset */
+		if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
+			break;
+		
+		/* Write data to device */
+		DBGC ( basher, "%02x ", *data );
+		if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 )
+			break;
+	}
+	
+	DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
+	i2c_stop ( basher );
+	return rc;
+}
+
+/**
+ * Initialise I2C bit-bashing interface
+ *
+ * @v i2cbit		I2C bit-bashing interface
+ * @v bash_op		Bit-basher operations
+ */
+int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+			  struct bit_basher_operations *bash_op ) {
+	struct bit_basher *basher = &i2cbit->basher;
+	int rc;
+
+	/* Initialise data structures */
+	basher->op = bash_op;
+	assert ( basher->op->read != NULL );
+	assert ( basher->op->write != NULL );
+	i2cbit->i2c.read = i2c_bit_read;
+	i2cbit->i2c.write = i2c_bit_write;
+
+	/* Reset I2C bus */
+	if ( ( rc = i2c_reset ( basher ) ) != 0 ) {
+		DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n",
+		       basher, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/spi_bit.c b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/spi_bit.c
new file mode 100644
index 0000000..b64ffb8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bitbash/spi_bit.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ipxe/bitbash.h>
+#include <ipxe/spi_bit.h>
+
+/** @file
+ *
+ * SPI bit-bashing interface
+ *
+ */
+
+/** Delay between SCLK changes and around SS changes */
+static void spi_bit_delay ( void ) {
+	udelay ( SPI_BIT_UDELAY );
+}
+
+/** Chip select line will be asserted */
+#define SELECT_SLAVE 0
+
+/** Chip select line will be deasserted */
+#define DESELECT_SLAVE SPI_MODE_SSPOL
+
+/**
+ * Select/deselect slave
+ *
+ * @v spibit		SPI bit-bashing interface
+ * @v slave		Slave number
+ * @v state		Slave select state
+ *
+ * @c state must be @c SELECT_SLAVE or @c DESELECT_SLAVE.
+ */
+static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
+				       unsigned int slave,
+				       unsigned int state ) {
+	struct bit_basher *basher = &spibit->basher;
+
+	state ^= ( spibit->bus.mode & SPI_MODE_SSPOL );
+	DBGC2 ( spibit, "SPIBIT %p setting slave %d select %s\n",
+		spibit, slave, ( state ? "high" : "low" ) );
+
+	spi_bit_delay();
+	write_bit ( basher, SPI_BIT_SS ( slave ), state );
+	spi_bit_delay();
+}
+
+/**
+ * Transfer bits over SPI bit-bashing bus
+ *
+ * @v bus		SPI bus
+ * @v data_out		TX data buffer (or NULL)
+ * @v data_in		RX data buffer (or NULL)
+ * @v len		Length of transfer (in @b bits)
+ * @v endianness	Endianness of this data transfer
+ *
+ * This issues @c len clock cycles on the SPI bus, shifting out data
+ * from the @c data_out buffer to the MOSI line and shifting in data
+ * from the MISO line to the @c data_in buffer.  If @c data_out is
+ * NULL, then the data sent will be all zeroes.  If @c data_in is
+ * NULL, then the incoming data will be discarded.
+ */
+static void spi_bit_transfer ( struct spi_bit_basher *spibit,
+			       const void *data_out, void *data_in,
+			       unsigned int len, int endianness ) {
+	struct spi_bus *bus = &spibit->bus;
+	struct bit_basher *basher = &spibit->basher;
+	unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 );
+	unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 );
+	unsigned int bit_offset;
+	unsigned int byte_offset;
+	unsigned int byte_mask;
+	unsigned int bit;
+	unsigned int step;
+
+	DBGC2 ( spibit, "SPIBIT %p transferring %d bits in mode %#x\n",
+		spibit, len, bus->mode );
+
+	for ( step = 0 ; step < ( len * 2 ) ; step++ ) {
+		/* Calculate byte offset and byte mask */
+		bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ?
+			       ( len - ( step / 2 ) - 1 ) : ( step / 2 ) );
+		byte_offset = ( bit_offset / 8 );
+		byte_mask = ( 1 << ( bit_offset % 8 ) );
+
+		/* Shift data in or out */
+		if ( sclk == cpha ) {
+			const uint8_t *byte;
+
+			/* Shift data out */
+			if ( data_out ) {
+				byte = ( data_out + byte_offset );
+				bit = ( *byte & byte_mask );
+				DBGCP ( spibit, "SPIBIT %p wrote bit %d\n",
+					spibit, ( bit ? 1 : 0 ) );
+			} else {
+				bit = 0;
+			}
+			write_bit ( basher, SPI_BIT_MOSI, bit );
+		} else {
+			uint8_t *byte;
+
+			/* Shift data in */
+			bit = read_bit ( basher, SPI_BIT_MISO );
+			if ( data_in ) {
+				DBGCP ( spibit, "SPIBIT %p read bit %d\n",
+					spibit, ( bit ? 1 : 0 ) );
+				byte = ( data_in + byte_offset );
+				*byte &= ~byte_mask;
+				*byte |= ( bit & byte_mask );
+			}
+		}
+
+		/* Toggle clock line */
+		spi_bit_delay();
+		sclk ^= 1;
+		write_bit ( basher, SPI_BIT_SCLK, sclk );
+	}
+}
+
+/**
+ * Read/write data via SPI bit-bashing bus
+ *
+ * @v bus		SPI bus
+ * @v device		SPI device
+ * @v command		Command
+ * @v address		Address to read/write (<0 for no address)
+ * @v data_out		TX data buffer (or NULL)
+ * @v data_in		RX data buffer (or NULL)
+ * @v len		Length of transfer
+ * @ret rc		Return status code
+ */
+static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
+			unsigned int command, int address,
+			const void *data_out, void *data_in, size_t len ) {
+	struct spi_bit_basher *spibit
+		= container_of ( bus, struct spi_bit_basher, bus );
+	uint32_t tmp_command;
+	uint32_t tmp_address;
+	uint32_t tmp_address_detect;
+
+	/* Deassert chip select to reset specified slave */
+	spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
+
+	/* Set clock line to idle state */
+	write_bit ( &spibit->basher, SPI_BIT_SCLK, 
+		    ( bus->mode & SPI_MODE_CPOL ) );
+
+	/* Assert chip select on specified slave */
+	spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE );
+
+	/* Transmit command */
+	assert ( device->command_len <= ( 8 * sizeof ( tmp_command ) ) );
+	tmp_command = cpu_to_le32 ( command );
+	spi_bit_transfer ( spibit, &tmp_command, NULL, device->command_len,
+			   SPI_BIT_BIG_ENDIAN );
+
+	/* Transmit address, if present */
+	if ( address >= 0 ) {
+		assert ( device->address_len <= ( 8 * sizeof ( tmp_address )));
+		tmp_address = cpu_to_le32 ( address );
+		if ( device->address_len == SPI_AUTODETECT_ADDRESS_LEN ) {
+			/* Autodetect address length.  This relies on
+			 * the device responding with a dummy zero
+			 * data bit before the first real data bit.
+			 */
+			DBGC ( spibit, "SPIBIT %p autodetecting device "
+			       "address length\n", spibit );
+			assert ( address == 0 );
+			device->address_len = 0;
+			do {
+				spi_bit_transfer ( spibit, &tmp_address,
+						   &tmp_address_detect, 1,
+						   SPI_BIT_BIG_ENDIAN );
+				device->address_len++;
+			} while ( le32_to_cpu ( tmp_address_detect ) & 1 );
+			DBGC ( spibit, "SPIBIT %p autodetected device address "
+			       "length %d\n", spibit, device->address_len );
+		} else {
+			spi_bit_transfer ( spibit, &tmp_address, NULL,
+					   device->address_len,
+					   SPI_BIT_BIG_ENDIAN );
+		}
+	}
+
+	/* Transmit/receive data */
+	spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ),
+			   spibit->endianness );
+
+	/* Deassert chip select on specified slave */
+	spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
+
+	return 0;
+}
+
+/**
+ * Initialise SPI bit-bashing interface
+ *
+ * @v spibit		SPI bit-bashing interface
+ */
+void init_spi_bit_basher ( struct spi_bit_basher *spibit ) {
+	assert ( &spibit->basher.op->read != NULL );
+	assert ( &spibit->basher.op->write != NULL );
+	spibit->bus.rw = spi_bit_rw;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/block/ata.c b/qemu-0.15.x/roms/ipxe/src/drivers/block/ata.c
new file mode 100644
index 0000000..5674001
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/block/ata.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/list.h>
+#include <ipxe/interface.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/edd.h>
+#include <ipxe/ata.h>
+
+/** @file
+ *
+ * ATA block device
+ *
+ */
+
+/******************************************************************************
+ *
+ * Interface methods
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Issue ATA command
+ *
+ * @v control		ATA control interface
+ * @v data		ATA data interface
+ * @v command		ATA command
+ * @ret tag		Command tag, or negative error
+ */
+int ata_command ( struct interface *control, struct interface *data,
+		  struct ata_cmd *command ) {
+	struct interface *dest;
+	ata_command_TYPE ( void * ) *op =
+		intf_get_dest_op ( control, ata_command, &dest );
+	void *object = intf_object ( dest );
+	int tag;
+
+	if ( op ) {
+		tag = op ( object, data, command );
+	} else {
+		/* Default is to fail to issue the command */
+		tag = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return tag;
+}
+
+/******************************************************************************
+ *
+ * ATA devices and commands
+ *
+ ******************************************************************************
+ */
+
+/** List of all ATA commands */
+static LIST_HEAD ( ata_commands );
+
+/** An ATA device */
+struct ata_device {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Block control interface */
+	struct interface block;
+	/** ATA control interface */
+	struct interface ata;
+
+	/** Device number
+	 *
+	 * Must be ATA_DEV_MASTER or ATA_DEV_SLAVE.
+	 */
+	unsigned int device;
+	/** Maximum number of blocks per single transfer */
+	unsigned int max_count;
+	/** Device uses LBA48 extended addressing */
+	int lba48;
+};
+
+/** An ATA command */
+struct ata_command {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** ATA device */
+	struct ata_device *atadev;
+	/** List of ATA commands */
+	struct list_head list;
+
+	/** Block data interface */
+	struct interface block;
+	/** ATA data interface */
+	struct interface ata;
+
+	/** Command type */
+	struct ata_command_type *type;
+	/** Command tag */
+	uint32_t tag;
+
+	/** Private data */
+	uint8_t priv[0];
+};
+
+/** An ATA command type */
+struct ata_command_type {
+	/** Name */
+	const char *name;
+	/** Additional working space */
+	size_t priv_len;
+	/** Command for non-LBA48-capable devices */
+	uint8_t cmd_lba;
+	/** Command for LBA48-capable devices */
+	uint8_t cmd_lba48;
+	/**
+	 * Calculate data-in buffer
+	 *
+	 * @v atacmd		ATA command
+	 * @v buffer		Available buffer
+	 * @v len		Available buffer length
+	 * @ret data_in		Data-in buffer
+	 * @ret data_in_len	Data-in buffer length
+	 */
+	void ( * data_in ) ( struct ata_command *atacmd, userptr_t buffer,
+			     size_t len, userptr_t *data_in,
+			     size_t *data_in_len );
+	/**
+	 * Calculate data-out buffer
+	 *
+	 *
+	 * @v atacmd		ATA command
+	 * @v buffer		Available buffer
+	 * @v len		Available buffer length
+	 * @ret data_out	Data-out buffer
+	 * @ret data_out_len	Data-out buffer length
+	 */
+	void ( * data_out ) ( struct ata_command *atacmd, userptr_t buffer,
+			      size_t len, userptr_t *data_out,
+			      size_t *data_out_len );
+	/**
+	 * Handle ATA command completion
+	 *
+	 * @v atacmd		ATA command
+	 * @v rc		Reason for completion
+	 */
+	void ( * done ) ( struct ata_command *atacmd, int rc );
+};
+
+/**
+ * Get reference to ATA device
+ *
+ * @v atadev		ATA device
+ * @ret atadev		ATA device
+ */
+static inline __attribute__ (( always_inline )) struct ata_device *
+atadev_get ( struct ata_device *atadev ) {
+	ref_get ( &atadev->refcnt );
+	return atadev;
+}
+
+/**
+ * Drop reference to ATA device
+ *
+ * @v atadev		ATA device
+ */
+static inline __attribute__ (( always_inline )) void
+atadev_put ( struct ata_device *atadev ) {
+	ref_put ( &atadev->refcnt );
+}
+
+/**
+ * Get reference to ATA command
+ *
+ * @v atacmd		ATA command
+ * @ret atacmd		ATA command
+ */
+static inline __attribute__ (( always_inline )) struct ata_command *
+atacmd_get ( struct ata_command *atacmd ) {
+	ref_get ( &atacmd->refcnt );
+	return atacmd;
+}
+
+/**
+ * Drop reference to ATA command
+ *
+ * @v atacmd		ATA command
+ */
+static inline __attribute__ (( always_inline )) void
+atacmd_put ( struct ata_command *atacmd ) {
+	ref_put ( &atacmd->refcnt );
+}
+
+/**
+ * Get ATA command private data
+ *
+ * @v atacmd		ATA command
+ * @ret priv		Private data
+ */
+static inline __attribute__ (( always_inline )) void *
+atacmd_priv ( struct ata_command *atacmd ) {
+	return atacmd->priv;
+}
+
+/**
+ * Free ATA command
+ *
+ * @v refcnt		Reference count
+ */
+static void atacmd_free ( struct refcnt *refcnt ) {
+	struct ata_command *atacmd =
+		container_of ( refcnt, struct ata_command, refcnt );
+
+	/* Remove from list of commands */
+	list_del ( &atacmd->list );
+	atadev_put ( atacmd->atadev );
+
+	/* Free command */
+	free ( atacmd );
+}
+
+/**
+ * Close ATA command
+ *
+ * @v atacmd		ATA command
+ * @v rc		Reason for close
+ */
+static void atacmd_close ( struct ata_command *atacmd, int rc ) {
+	struct ata_device *atadev = atacmd->atadev;
+
+	if ( rc != 0 ) {
+		DBGC ( atadev, "ATA %p tag %08x closed: %s\n",
+		       atadev, atacmd->tag, strerror ( rc ) );
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &atacmd->ata, rc );
+	intf_shutdown ( &atacmd->block, rc );
+}
+
+/**
+ * Handle ATA command completion
+ *
+ * @v atacmd		ATA command
+ * @v rc		Reason for close
+ */
+static void atacmd_done ( struct ata_command *atacmd, int rc ) {
+
+	/* Hand over to the command completion handler */
+	atacmd->type->done ( atacmd, rc );
+}
+
+/**
+ * Use provided data buffer for ATA command
+ *
+ * @v atacmd		ATA command
+ * @v buffer		Available buffer
+ * @v len		Available buffer length
+ * @ret data		Data buffer
+ * @ret data_len	Data buffer length
+ */
+static void atacmd_data_buffer ( struct ata_command *atacmd __unused,
+				 userptr_t buffer, size_t len,
+				 userptr_t *data, size_t *data_len ) {
+	*data = buffer;
+	*data_len = len;
+}
+
+/**
+ * Use no data buffer for ATA command
+ *
+ * @v atacmd		ATA command
+ * @v buffer		Available buffer
+ * @v len		Available buffer length
+ * @ret data		Data buffer
+ * @ret data_len	Data buffer length
+ */
+static void atacmd_data_none ( struct ata_command *atacmd __unused,
+			       userptr_t buffer __unused, size_t len __unused,
+			       userptr_t *data __unused,
+			       size_t *data_len __unused ) {
+	/* Nothing to do */
+}
+
+/**
+ * Use private data buffer for ATA command
+ *
+ * @v atacmd		ATA command
+ * @v buffer		Available buffer
+ * @v len		Available buffer length
+ * @ret data		Data buffer
+ * @ret data_len	Data buffer length
+ */
+static void atacmd_data_priv ( struct ata_command *atacmd,
+			       userptr_t buffer __unused, size_t len __unused,
+			       userptr_t *data, size_t *data_len ) {
+	*data = virt_to_user ( atacmd_priv ( atacmd ) );
+	*data_len = atacmd->type->priv_len;
+}
+
+/** ATA READ command type */
+static struct ata_command_type atacmd_read = {
+	.name = "READ",
+	.cmd_lba = ATA_CMD_READ,
+	.cmd_lba48 = ATA_CMD_READ_EXT,
+	.data_in = atacmd_data_buffer,
+	.data_out = atacmd_data_none,
+	.done = atacmd_close,
+};
+
+/** ATA WRITE command type */
+static struct ata_command_type atacmd_write = {
+	.name = "WRITE",
+	.cmd_lba = ATA_CMD_WRITE,
+	.cmd_lba48 = ATA_CMD_WRITE_EXT,
+	.data_in = atacmd_data_none,
+	.data_out = atacmd_data_buffer,
+	.done = atacmd_close,
+};
+
+/** ATA IDENTIFY private data */
+struct ata_identify_private {
+	/** Identity data */
+	struct ata_identity identity;
+};
+
+/**
+ * Return ATA model string (for debugging)
+ *
+ * @v identify		ATA identity data
+ * @ret model		Model string
+ */
+static const char * ata_model ( struct ata_identity *identity ) {
+	static union {
+		uint16_t words[ sizeof ( identity->model ) / 2 ];
+		char text[ sizeof ( identity->model ) + 1 /* NUL */ ];
+	} buf;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( identity->model ) / 2 ) ; i++ )
+		buf.words[i] = bswap_16 ( identity->model[i] );
+
+	return buf.text;
+}
+
+/**
+ * Handle ATA IDENTIFY command completion
+ *
+ * @v atacmd		ATA command
+ * @v rc		Reason for completion
+ */
+static void atacmd_identify_done ( struct ata_command *atacmd, int rc ) {
+	struct ata_device *atadev = atacmd->atadev;
+	struct ata_identify_private *priv = atacmd_priv ( atacmd );
+	struct ata_identity *identity = &priv->identity;
+	struct block_device_capacity capacity;
+
+	/* Close if command failed */
+	if ( rc != 0 ) {
+		atacmd_close ( atacmd, rc );
+		return;
+	}
+
+	/* Extract capacity */
+	if ( identity->supports_lba48 & cpu_to_le16 ( ATA_SUPPORTS_LBA48 ) ) {
+		atadev->lba48 = 1;
+		capacity.blocks = le64_to_cpu ( identity->lba48_sectors );
+	} else {
+		capacity.blocks = le32_to_cpu ( identity->lba_sectors );
+	}
+	capacity.blksize = ATA_SECTOR_SIZE;
+	capacity.max_count = atadev->max_count;
+	DBGC ( atadev, "ATA %p is a %s\n", atadev, ata_model ( identity ) );
+	DBGC ( atadev, "ATA %p has %#llx blocks (%ld MB) and uses %s\n",
+	       atadev, capacity.blocks,
+	       ( ( signed long ) ( capacity.blocks >> 11 ) ),
+	       ( atadev->lba48 ? "LBA48" : "LBA" ) );
+
+	/* Return capacity to caller */
+	block_capacity ( &atacmd->block, &capacity );
+
+	/* Close command */
+	atacmd_close ( atacmd, 0 );
+}
+
+/** ATA IDENTITY command type */
+static struct ata_command_type atacmd_identify = {
+	.name = "IDENTIFY",
+	.priv_len = sizeof ( struct ata_identify_private ),
+	.cmd_lba = ATA_CMD_IDENTIFY,
+	.cmd_lba48 = ATA_CMD_IDENTIFY,
+	.data_in = atacmd_data_priv,
+	.data_out = atacmd_data_none,
+	.done = atacmd_identify_done,
+};
+
+/** ATA command block interface operations */
+static struct interface_operation atacmd_block_op[] = {
+	INTF_OP ( intf_close, struct ata_command *, atacmd_close ),
+};
+
+/** ATA command block interface descriptor */
+static struct interface_descriptor atacmd_block_desc =
+	INTF_DESC_PASSTHRU ( struct ata_command, block,
+			     atacmd_block_op, ata );
+
+/** ATA command ATA interface operations */
+static struct interface_operation atacmd_ata_op[] = {
+	INTF_OP ( intf_close, struct ata_command *, atacmd_done ),
+};
+
+/** ATA command ATA interface descriptor */
+static struct interface_descriptor atacmd_ata_desc =
+	INTF_DESC_PASSTHRU ( struct ata_command, ata,
+			     atacmd_ata_op, block );
+
+/**
+ * Create ATA command
+ *
+ * @v atadev		ATA device
+ * @v block		Block data interface
+ * @v type		ATA command type
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int atadev_command ( struct ata_device *atadev,
+			    struct interface *block,
+			    struct ata_command_type *type,
+			    uint64_t lba, unsigned int count,
+			    userptr_t buffer, size_t len ) {
+	struct ata_command *atacmd;
+	struct ata_cmd command;
+	int tag;
+	int rc;
+
+	/* Allocate and initialise structure */
+	atacmd = zalloc ( sizeof ( *atacmd ) + type->priv_len );
+	if ( ! atacmd ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &atacmd->refcnt, atacmd_free );
+	intf_init ( &atacmd->block, &atacmd_block_desc, &atacmd->refcnt );
+	intf_init ( &atacmd->ata, &atacmd_ata_desc,
+		    &atacmd->refcnt );
+	atacmd->atadev = atadev_get ( atadev );
+	list_add ( &atacmd->list, &ata_commands );
+	atacmd->type = type;
+
+	/* Sanity check */
+	if ( len != ( count * ATA_SECTOR_SIZE ) ) {
+		DBGC ( atadev, "ATA %p tag %08x buffer length mismatch (count "
+		       "%d len %zd)\n", atadev, atacmd->tag, count, len );
+		rc = -EINVAL;
+		goto err_len;
+	}
+
+	/* Construct command */
+	memset ( &command, 0, sizeof ( command ) );
+	command.cb.lba.native = lba;
+	command.cb.count.native = count;
+	command.cb.device = ( atadev->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
+	command.cb.lba48 = atadev->lba48;
+	if ( ! atadev->lba48 )
+		command.cb.device |= command.cb.lba.bytes.low_prev;
+	command.cb.cmd_stat =
+		( atadev->lba48 ? type->cmd_lba48 : type->cmd_lba );
+	type->data_in ( atacmd, buffer, len,
+			&command.data_in, &command.data_in_len );
+	type->data_out ( atacmd, buffer, len,
+			 &command.data_out, &command.data_out_len );
+
+	/* Issue command */
+	if ( ( tag = ata_command ( &atadev->ata, &atacmd->ata,
+				   &command ) ) < 0 ) {
+		rc = tag;
+		DBGC ( atadev, "ATA %p tag %08x could not issue command: %s\n",
+		       atadev, atacmd->tag, strerror ( rc ) );
+		goto err_command;
+	}
+	atacmd->tag = tag;
+
+	DBGC2 ( atadev, "ATA %p tag %08x %s cmd %02x dev %02x LBA%s %08llx "
+		"count %04x\n", atadev, atacmd->tag, atacmd->type->name,
+		command.cb.cmd_stat, command.cb.device,
+		( command.cb.lba48 ? "48" : "" ),
+		( unsigned long long ) command.cb.lba.native,
+		command.cb.count.native );
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &atacmd->block, block );
+	ref_put ( &atacmd->refcnt );
+	return 0;
+
+ err_command:
+ err_len:
+	atacmd_close ( atacmd, rc );
+	ref_put ( &atacmd->refcnt );
+ err_zalloc:
+	return rc;
+}
+
+/**
+ * Issue ATA block read
+ *
+ * @v atadev		ATA device
+ * @v block		Block data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+
+ */
+static int atadev_read ( struct ata_device *atadev,
+			 struct interface *block,
+			 uint64_t lba, unsigned int count,
+			 userptr_t buffer, size_t len ) {
+	return atadev_command ( atadev, block, &atacmd_read,
+				lba, count, buffer, len );
+}
+
+/**
+ * Issue ATA block write
+ *
+ * @v atadev		ATA device
+ * @v block		Block data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int atadev_write ( struct ata_device *atadev,
+			  struct interface *block,
+			  uint64_t lba, unsigned int count,
+			  userptr_t buffer, size_t len ) {
+	return atadev_command ( atadev, block, &atacmd_write,
+				lba, count, buffer, len );
+}
+
+/**
+ * Read ATA device capacity
+ *
+ * @v atadev		ATA device
+ * @v block		Block data interface
+ * @ret rc		Return status code
+ */
+static int atadev_read_capacity ( struct ata_device *atadev,
+				  struct interface *block ) {
+	struct ata_identity *identity;
+
+	assert ( atacmd_identify.priv_len == sizeof ( *identity ) );
+	assert ( atacmd_identify.priv_len == ATA_SECTOR_SIZE );
+	return atadev_command ( atadev, block, &atacmd_identify,
+				0, 1, UNULL, ATA_SECTOR_SIZE );
+}
+
+/**
+ * Close ATA device
+ *
+ * @v atadev		ATA device
+ * @v rc		Reason for close
+ */
+static void atadev_close ( struct ata_device *atadev, int rc ) {
+	struct ata_command *atacmd;
+	struct ata_command *tmp;
+
+	/* Shut down interfaces */
+	intf_shutdown ( &atadev->block, rc );
+	intf_shutdown ( &atadev->ata, rc );
+
+	/* Shut down any remaining commands */
+	list_for_each_entry_safe ( atacmd, tmp, &ata_commands, list ) {
+		if ( atacmd->atadev != atadev )
+			continue;
+		atacmd_get ( atacmd );
+		atacmd_close ( atacmd, rc );
+		atacmd_put ( atacmd );
+	}
+}
+
+/**
+ * Describe ATA device using EDD
+ *
+ * @v atadev		ATA device
+ * @v type		EDD interface type
+ * @v path		EDD device path
+ * @ret rc		Return status code
+ */
+static int atadev_edd_describe ( struct ata_device *atadev,
+				 struct edd_interface_type *type,
+				 union edd_device_path *path ) {
+
+	type->type = cpu_to_le64 ( EDD_INTF_TYPE_ATA );
+	path->ata.slave = ( ( atadev->device == ATA_DEV_SLAVE ) ? 0x01 : 0x00 );
+	return 0;
+}
+
+/** ATA device block interface operations */
+static struct interface_operation atadev_block_op[] = {
+	INTF_OP ( block_read, struct ata_device *, atadev_read ),
+	INTF_OP ( block_write, struct ata_device *, atadev_write ),
+	INTF_OP ( block_read_capacity, struct ata_device *,
+		  atadev_read_capacity ),
+	INTF_OP ( intf_close, struct ata_device *, atadev_close ),
+	INTF_OP ( edd_describe, struct ata_device *, atadev_edd_describe ),
+};
+
+/** ATA device block interface descriptor */
+static struct interface_descriptor atadev_block_desc =
+	INTF_DESC_PASSTHRU ( struct ata_device, block,
+			     atadev_block_op, ata );
+
+/** ATA device ATA interface operations */
+static struct interface_operation atadev_ata_op[] = {
+	INTF_OP ( intf_close, struct ata_device *, atadev_close ),
+};
+
+/** ATA device ATA interface descriptor */
+static struct interface_descriptor atadev_ata_desc =
+	INTF_DESC_PASSTHRU ( struct ata_device, ata,
+			     atadev_ata_op, block );
+
+/**
+ * Open ATA device
+ *
+ * @v block		Block control interface
+ * @v ata		ATA control interface
+ * @v device		ATA device number
+ * @v max_count		Maximum number of blocks per single transfer
+ * @ret rc		Return status code
+ */
+int ata_open ( struct interface *block, struct interface *ata,
+	       unsigned int device, unsigned int max_count ) {
+	struct ata_device *atadev;
+
+	/* Allocate and initialise structure */
+	atadev = zalloc ( sizeof ( *atadev ) );
+	if ( ! atadev )
+		return -ENOMEM;
+	ref_init ( &atadev->refcnt, NULL );
+	intf_init ( &atadev->block, &atadev_block_desc, &atadev->refcnt );
+	intf_init ( &atadev->ata, &atadev_ata_desc, &atadev->refcnt );
+	atadev->device = device;
+	atadev->max_count = max_count;
+
+	/* Attach to ATA and parent and interfaces, mortalise self,
+	 * and return
+	 */
+	intf_plug_plug ( &atadev->ata, ata );
+	intf_plug_plug ( &atadev->block, block );
+	ref_put ( &atadev->refcnt );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/block/ibft.c b/qemu-0.15.x/roms/ipxe/src/drivers/block/ibft.c
new file mode 100644
index 0000000..f160963
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/block/ibft.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright Fen Systems Ltd. 2007.  Portions of this code are derived
+ * from IBM Corporation Sample Programs.  Copyright IBM Corporation
+ * 2004, 2007.  All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/acpi.h>
+#include <ipxe/in.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/iscsi.h>
+#include <ipxe/ibft.h>
+
+/** @file
+ *
+ * iSCSI boot firmware table
+ *
+ * The information in this file is derived from the document "iSCSI
+ * Boot Firmware Table (iBFT)" as published by IBM at
+ *
+ * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
+ *
+ */
+
+/**
+ * An iBFT created by iPXE
+ *
+ */
+struct ipxe_ibft {
+	/** The fixed section */
+	struct ibft_table table;
+	/** The Initiator section */
+	struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
+	/** The NIC section */
+	struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
+	/** The Target section */
+	struct ibft_target target __attribute__ (( aligned ( 16 ) ));
+	/** Strings block */
+	char strings[0];
+} __attribute__ (( packed, aligned ( 16 ) ));
+
+/**
+ * iSCSI string block descriptor
+ *
+ * This is an internal structure that we use to keep track of the
+ * allocation of string data.
+ */
+struct ibft_strings {
+	/** The iBFT containing these strings */
+	struct ibft_table *table;
+	/** Offset of first free byte within iBFT */
+	size_t offset;
+	/** Total length of the iBFT */
+	size_t len;
+};
+
+/**
+ * Fill in an IP address field within iBFT
+ *
+ * @v ipaddr		IP address field
+ * @v in		IPv4 address
+ */
+static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
+	memset ( ipaddr, 0, sizeof ( *ipaddr ) );
+	if ( in.s_addr ) {
+		ipaddr->in = in;
+		ipaddr->ones = 0xffff;
+	}
+}
+
+/**
+ * Fill in an IP address within iBFT from configuration setting
+ *
+ * @v ipaddr		IP address field
+ * @v setting		Configuration setting
+ * @v count		Maximum number of IP addresses
+ */
+static void ibft_set_ipaddr_setting ( struct ibft_ipaddr *ipaddr,
+				      struct setting *setting,
+				      unsigned int count ) {
+	struct in_addr in[count];
+	unsigned int i;
+
+	fetch_ipv4_array_setting ( NULL, setting, in, count );
+	for ( i = 0 ; i < count ; i++ ) {
+		ibft_set_ipaddr ( &ipaddr[i], in[i] );
+	}
+}
+
+/**
+ * Read IP address from iBFT (for debugging)
+ *
+ * @v strings		iBFT string block descriptor
+ * @v string		String field
+ * @ret ipaddr		IP address string
+ */
+static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
+	return inet_ntoa ( ipaddr->in );
+}
+
+/**
+ * Allocate a string within iBFT
+ *
+ * @v strings		iBFT string block descriptor
+ * @v string		String field to fill in
+ * @v len		Length of string to allocate (excluding NUL)
+ * @ret dest		String destination, or NULL
+ */
+static char * ibft_alloc_string ( struct ibft_strings *strings,
+				  struct ibft_string *string, size_t len ) {
+
+	if ( ( strings->offset + len ) >= strings->len )
+		return NULL;
+
+	string->offset = cpu_to_le16 ( strings->offset );
+	string->len = cpu_to_le16 ( len );
+	strings->offset += ( len + 1 );
+
+	return ( ( ( char * ) strings->table ) + string->offset );
+}
+
+/**
+ * Fill in a string field within iBFT
+ *
+ * @v strings		iBFT string block descriptor
+ * @v string		String field
+ * @v data		String to fill in, or NULL
+ * @ret rc		Return status code
+ */
+static int ibft_set_string ( struct ibft_strings *strings,
+			     struct ibft_string *string, const char *data ) {
+	char *dest;
+
+	if ( ! data )
+		return 0;
+
+	dest = ibft_alloc_string ( strings, string, strlen ( data ) );
+	if ( ! dest )
+		return -ENOBUFS;
+	strcpy ( dest, data );
+
+	return 0;
+}
+
+/**
+ * Fill in a string field within iBFT from configuration setting
+ *
+ * @v strings		iBFT string block descriptor
+ * @v string		String field
+ * @v setting		Configuration setting
+ * @ret rc		Return status code
+ */
+static int ibft_set_string_setting ( struct ibft_strings *strings,
+				     struct ibft_string *string,
+				     struct setting *setting ) {
+	int len;
+	char *dest;
+
+	len = fetch_setting_len ( NULL, setting );
+	if ( len < 0 ) {
+		string->offset = 0;
+		string->len = 0;
+		return 0;
+	}
+
+	dest = ibft_alloc_string ( strings, string, len );
+	if ( ! dest )
+		return -ENOBUFS;
+	fetch_string_setting ( NULL, setting, dest, ( len + 1 ) );
+
+	return 0;
+}
+
+/**
+ * Read string from iBFT (for debugging)
+ *
+ * @v strings		iBFT string block descriptor
+ * @v string		String field
+ * @ret data		String content (or "<empty>")
+ */
+static const char * ibft_string ( struct ibft_strings *strings,
+				  struct ibft_string *string ) {
+	return ( string->offset ?
+		 ( ( ( char * ) strings->table ) + string->offset ) : NULL );
+}
+
+/**
+ * Fill in NIC portion of iBFT
+ *
+ * @v nic		NIC portion of iBFT
+ * @v strings		iBFT string block descriptor
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int ibft_fill_nic ( struct ibft_nic *nic,
+			   struct ibft_strings *strings,
+			   struct net_device *netdev ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct in_addr netmask_addr = { 0 };
+	unsigned int netmask_count = 0;
+	int rc;
+
+	/* Fill in common header */
+	nic->header.structure_id = IBFT_STRUCTURE_ID_NIC;
+	nic->header.version = 1;
+	nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
+	nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
+			      IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
+
+	/* Extract values from configuration settings */
+	ibft_set_ipaddr_setting ( &nic->ip_address, &ip_setting, 1 );
+	DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
+	ibft_set_ipaddr_setting ( &nic->gateway, &gateway_setting, 1 );
+	DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
+	ibft_set_ipaddr_setting ( &nic->dns[0], &dns_setting,
+				  ( sizeof ( nic->dns ) /
+				    sizeof ( nic->dns[0] ) ) );
+	DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
+	DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
+	if ( ( rc = ibft_set_string_setting ( strings, &nic->hostname,
+					      &hostname_setting ) ) != 0 )
+		return rc;
+	DBG ( "iBFT NIC hostname = %s\n",
+	      ibft_string ( strings, &nic->hostname ) );
+
+	/* Derive subnet mask prefix from subnet mask */
+	fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
+	while ( netmask_addr.s_addr ) {
+		if ( netmask_addr.s_addr & 0x1 )
+			netmask_count++;
+		netmask_addr.s_addr >>= 1;
+	}
+	nic->subnet_mask_prefix = netmask_count;
+	DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
+
+	/* Extract values from net-device configuration */
+	if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
+					    nic->mac_address ) ) != 0 ) {
+		DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
+		return rc;
+	}
+	DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
+	nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
+	DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) );
+
+	return 0;
+}
+
+/**
+ * Fill in Initiator portion of iBFT
+ *
+ * @v initiator		Initiator portion of iBFT
+ * @v strings		iBFT string block descriptor
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int ibft_fill_initiator ( struct ibft_initiator *initiator,
+				 struct ibft_strings *strings,
+				 struct iscsi_session *iscsi ) {
+	int rc;
+
+	/* Fill in common header */
+	initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR;
+	initiator->header.version = 1;
+	initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) );
+	initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
+				    IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
+
+	/* Fill in hostname */
+	if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
+				      iscsi->initiator_iqn ) ) != 0 )
+		return rc;
+	DBG ( "iBFT initiator hostname = %s\n",
+	      ibft_string ( strings, &initiator->initiator_name ) );
+
+	return 0;
+}
+
+/**
+ * Fill in Target CHAP portion of iBFT
+ *
+ * @v target		Target portion of iBFT
+ * @v strings		iBFT string block descriptor
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int ibft_fill_target_chap ( struct ibft_target *target,
+				   struct ibft_strings *strings,
+				   struct iscsi_session *iscsi ) {
+	int rc;
+
+	if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
+		return 0;
+
+	assert ( iscsi->initiator_username );
+	assert ( iscsi->initiator_password );
+
+	target->chap_type = IBFT_CHAP_ONE_WAY;
+	if ( ( rc = ibft_set_string ( strings, &target->chap_name,
+				      iscsi->initiator_username ) ) != 0 )
+		return rc;
+	DBG ( "iBFT target username = %s\n",
+	      ibft_string ( strings, &target->chap_name ) );
+	if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
+				      iscsi->initiator_password ) ) != 0 )
+		return rc;
+	DBG ( "iBFT target password = <redacted>\n" );
+
+	return 0;
+}
+
+/**
+ * Fill in Target Reverse CHAP portion of iBFT
+ *
+ * @v target		Target portion of iBFT
+ * @v strings		iBFT string block descriptor
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
+					   struct ibft_strings *strings,
+					   struct iscsi_session *iscsi ) {
+	int rc;
+
+	if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
+		return 0;
+
+	assert ( iscsi->initiator_username );
+	assert ( iscsi->initiator_password );
+	assert ( iscsi->target_username );
+	assert ( iscsi->target_password );
+
+	target->chap_type = IBFT_CHAP_MUTUAL;
+	if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
+				      iscsi->target_username ) ) != 0 )
+		return rc;
+	DBG ( "iBFT target reverse username = %s\n",
+	      ibft_string ( strings, &target->chap_name ) );
+	if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
+				      iscsi->target_password ) ) != 0 )
+		return rc;
+	DBG ( "iBFT target reverse password = <redacted>\n" );
+
+	return 0;
+}
+
+/**
+ * Fill in Target portion of iBFT
+ *
+ * @v target		Target portion of iBFT
+ * @v strings		iBFT string block descriptor
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int ibft_fill_target ( struct ibft_target *target,
+			      struct ibft_strings *strings,
+			      struct iscsi_session *iscsi ) {
+	struct sockaddr_in *sin_target =
+		( struct sockaddr_in * ) &iscsi->target_sockaddr;
+	int rc;
+
+	/* Fill in common header */
+	target->header.structure_id = IBFT_STRUCTURE_ID_TARGET;
+	target->header.version = 1;
+	target->header.length = cpu_to_le16 ( sizeof ( *target ) );
+	target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID |
+				 IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED );
+
+	/* Fill in Target values */
+	ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
+	DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
+	target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) );
+	DBG ( "iBFT target port = %d\n", target->socket );
+	memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
+	DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n",
+	      SCSI_LUN_DATA ( target->boot_lun ) );
+	if ( ( rc = ibft_set_string ( strings, &target->target_name,
+				      iscsi->target_iqn ) ) != 0 )
+		return rc;
+	DBG ( "iBFT target name = %s\n",
+	      ibft_string ( strings, &target->target_name ) );
+	if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
+		return rc;
+	if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
+						    iscsi ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Fill in iBFT
+ *
+ * @v iscsi		iSCSI session
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+int ibft_describe ( struct iscsi_session *iscsi,
+		    struct acpi_description_header *acpi,
+		    size_t len ) {
+	struct ipxe_ibft *ibft =
+		container_of ( acpi, struct ipxe_ibft, table.acpi );
+	struct ibft_strings strings = {
+		.table = &ibft->table,
+		.offset = offsetof ( typeof ( *ibft ), strings ),
+		.len = len,
+	};
+	struct net_device *netdev;
+	int rc;
+
+	/* Ugly hack.  Now that we have a generic interface mechanism
+	 * that can support ioctls, we can potentially eliminate this.
+	 */
+	netdev = last_opened_netdev();
+	if ( ! netdev ) {
+		DBGC ( iscsi, "iSCSI %p cannot guess network device\n",
+		       iscsi );
+		return -ENODEV;
+	}
+
+	/* Fill in ACPI header */
+	ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG );
+	ibft->table.acpi.length = cpu_to_le32 ( len );
+	ibft->table.acpi.revision = 1;
+
+	/* Fill in Control block */
+	ibft->table.control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
+	ibft->table.control.header.version = 1;
+	ibft->table.control.header.length =
+		cpu_to_le16 ( sizeof ( ibft->table.control ) );
+	ibft->table.control.initiator =
+		cpu_to_le16 ( offsetof ( typeof ( *ibft ), initiator ) );
+	ibft->table.control.nic_0 =
+		cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic ) );
+	ibft->table.control.target_0 =
+		cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) );
+
+	/* Fill in NIC, Initiator and Target blocks */
+	if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, netdev ) ) != 0 )
+		return rc;
+	if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings,
+					  iscsi ) ) != 0 )
+		return rc;
+	if ( ( rc = ibft_fill_target ( &ibft->target, &strings,
+				       iscsi ) ) != 0 )
+		return rc;
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/block/scsi.c b/qemu-0.15.x/roms/ipxe/src/drivers/block/scsi.c
new file mode 100644
index 0000000..d141651
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/block/scsi.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+#include <ipxe/xfer.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/scsi.h>
+
+/** @file
+ *
+ * SCSI block device
+ *
+ */
+
+/** Maximum number of command retries */
+#define SCSICMD_MAX_RETRIES 10
+
+/* Error numbers generated by SCSI sense data */
+#define EIO_NO_SENSE __einfo_error ( EINFO_EIO_NO_SENSE )
+#define EINFO_EIO_NO_SENSE \
+	__einfo_uniqify ( EINFO_EIO, 0x00, "No sense" )
+#define EIO_RECOVERED_ERROR __einfo_error ( EINFO_EIO_RECOVERED_ERROR )
+#define EINFO_EIO_RECOVERED_ERROR \
+	__einfo_uniqify ( EINFO_EIO, 0x01, "Recovered error" )
+#define EIO_NOT_READY __einfo_error ( EINFO_EIO_NOT_READY )
+#define EINFO_EIO_NOT_READY \
+	__einfo_uniqify ( EINFO_EIO, 0x02, "Not ready" )
+#define EIO_MEDIUM_ERROR __einfo_error ( EINFO_EIO_MEDIUM_ERROR )
+#define EINFO_EIO_MEDIUM_ERROR \
+	__einfo_uniqify ( EINFO_EIO, 0x03, "Medium error" )
+#define EIO_HARDWARE_ERROR __einfo_error ( EINFO_EIO_HARDWARE_ERROR )
+#define EINFO_EIO_HARDWARE_ERROR \
+	__einfo_uniqify ( EINFO_EIO, 0x04, "Hardware error" )
+#define EIO_ILLEGAL_REQUEST __einfo_error ( EINFO_EIO_ILLEGAL_REQUEST )
+#define EINFO_EIO_ILLEGAL_REQUEST \
+	__einfo_uniqify ( EINFO_EIO, 0x05, "Illegal request" )
+#define EIO_UNIT_ATTENTION __einfo_error ( EINFO_EIO_UNIT_ATTENTION )
+#define EINFO_EIO_UNIT_ATTENTION \
+	__einfo_uniqify ( EINFO_EIO, 0x06, "Unit attention" )
+#define EIO_DATA_PROTECT __einfo_error ( EINFO_EIO_DATA_PROTECT )
+#define EINFO_EIO_DATA_PROTECT \
+	__einfo_uniqify ( EINFO_EIO, 0x07, "Data protect" )
+#define EIO_BLANK_CHECK __einfo_error ( EINFO_EIO_BLANK_CHECK )
+#define EINFO_EIO_BLANK_CHECK \
+	__einfo_uniqify ( EINFO_EIO, 0x08, "Blank check" )
+#define EIO_VENDOR_SPECIFIC __einfo_error ( EINFO_EIO_VENDOR_SPECIFIC )
+#define EINFO_EIO_VENDOR_SPECIFIC \
+	__einfo_uniqify ( EINFO_EIO, 0x09, "Vendor specific" )
+#define EIO_COPY_ABORTED __einfo_error ( EINFO_EIO_COPY_ABORTED )
+#define EINFO_EIO_COPY_ABORTED \
+	__einfo_uniqify ( EINFO_EIO, 0x0a, "Copy aborted" )
+#define EIO_ABORTED_COMMAND __einfo_error ( EINFO_EIO_ABORTED_COMMAND )
+#define EINFO_EIO_ABORTED_COMMAND \
+	__einfo_uniqify ( EINFO_EIO, 0x0b, "Aborted command" )
+#define EIO_RESERVED __einfo_error ( EINFO_EIO_RESERVED )
+#define EINFO_EIO_RESERVED \
+	__einfo_uniqify ( EINFO_EIO, 0x0c, "Reserved" )
+#define EIO_VOLUME_OVERFLOW __einfo_error ( EINFO_EIO_VOLUME_OVERFLOW )
+#define EINFO_EIO_VOLUME_OVERFLOW \
+	__einfo_uniqify ( EINFO_EIO, 0x0d, "Volume overflow" )
+#define EIO_MISCOMPARE __einfo_error ( EINFO_EIO_MISCOMPARE )
+#define EINFO_EIO_MISCOMPARE \
+	__einfo_uniqify ( EINFO_EIO, 0x0e, "Miscompare" )
+#define EIO_COMPLETED __einfo_error ( EINFO_EIO_COMPLETED )
+#define EINFO_EIO_COMPLETED \
+	__einfo_uniqify ( EINFO_EIO, 0x0f, "Completed" )
+#define EIO_SENSE( key )						\
+	EUNIQ ( EIO, (key), EIO_NO_SENSE, EIO_RECOVERED_ERROR,		\
+		EIO_NOT_READY, EIO_MEDIUM_ERROR, EIO_HARDWARE_ERROR,	\
+		EIO_ILLEGAL_REQUEST, EIO_UNIT_ATTENTION,		\
+		EIO_DATA_PROTECT, EIO_BLANK_CHECK, EIO_VENDOR_SPECIFIC,	\
+		EIO_COPY_ABORTED, EIO_ABORTED_COMMAND, EIO_RESERVED,	\
+		EIO_VOLUME_OVERFLOW, EIO_MISCOMPARE, EIO_COMPLETED )
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Parse SCSI LUN
+ *
+ * @v lun_string	LUN string representation
+ * @v lun		LUN to fill in
+ * @ret rc		Return status code
+ */
+int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) {
+	char *p;
+	int i;
+
+	memset ( lun, 0, sizeof ( *lun ) );
+	if ( lun_string ) {
+		p = ( char * ) lun_string;
+		for ( i = 0 ; i < 4 ; i++ ) {
+			lun->u16[i] = htons ( strtoul ( p, &p, 16 ) );
+			if ( *p == '\0' )
+				break;
+			if ( *p != '-' )
+				return -EINVAL;
+			p++;
+		}
+		if ( *p )
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Interface methods
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Issue SCSI command
+ *
+ * @v control		SCSI control interface
+ * @v data		SCSI data interface
+ * @v command		SCSI command
+ * @ret tag		Command tag, or negative error
+ */
+int scsi_command ( struct interface *control, struct interface *data,
+		   struct scsi_cmd *command ) {
+	struct interface *dest;
+	scsi_command_TYPE ( void * ) *op =
+		intf_get_dest_op ( control, scsi_command, &dest );
+	void *object = intf_object ( dest );
+	int tap;
+
+	if ( op ) {
+		tap = op ( object, data, command );
+	} else {
+		/* Default is to fail to issue the command */
+		tap = -EOPNOTSUPP;
+	}
+
+	intf_put ( dest );
+	return tap;
+}
+
+/**
+ * Report SCSI response
+ *
+ * @v interface		SCSI command interface
+ * @v response		SCSI response
+ */
+void scsi_response ( struct interface *intf, struct scsi_rsp *response ) {
+	struct interface *dest;
+	scsi_response_TYPE ( void * ) *op =
+		intf_get_dest_op ( intf, scsi_response, &dest );
+	void *object = intf_object ( dest );
+
+	if ( op ) {
+		op ( object, response );
+	} else {
+		/* Default is to ignore the response */
+	}
+
+	intf_put ( dest );
+}
+
+/******************************************************************************
+ *
+ * SCSI devices and commands
+ *
+ ******************************************************************************
+ */
+
+/** A SCSI device */
+struct scsi_device {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Block control interface */
+	struct interface block;
+	/** SCSI control interface */
+	struct interface scsi;
+
+	/** SCSI LUN */
+	struct scsi_lun lun;
+	/** Flags */
+	unsigned int flags;
+
+	/** TEST UNIT READY interface */
+	struct interface ready;
+	/** TEST UNIT READY process */
+	struct process process;
+
+	/** List of commands */
+	struct list_head cmds;
+};
+
+/** SCSI device flags */
+enum scsi_device_flags {
+	/** Unit is ready */
+	SCSIDEV_UNIT_READY = 0x0001,
+};
+
+/** A SCSI command */
+struct scsi_command {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** SCSI device */
+	struct scsi_device *scsidev;
+	/** List of SCSI commands */
+	struct list_head list;
+
+	/** Block data interface */
+	struct interface block;
+	/** SCSI data interface */
+	struct interface scsi;
+
+	/** Command type */
+	struct scsi_command_type *type;
+	/** Starting logical block address */
+	uint64_t lba;
+	/** Number of blocks */
+	unsigned int count;
+	/** Data buffer */
+	userptr_t buffer;
+	/** Length of data buffer */
+	size_t len;
+	/** Command tag */
+	uint32_t tag;
+
+	/** Retry count */
+	unsigned int retries;
+
+	/** Private data */
+	uint8_t priv[0];
+};
+
+/** A SCSI command type */
+struct scsi_command_type {
+	/** Name */
+	const char *name;
+	/** Additional working space */
+	size_t priv_len;
+	/**
+	 * Construct SCSI command IU
+	 *
+	 * @v scsicmd		SCSI command
+	 * @v command		SCSI command IU
+	 */
+	void ( * cmd ) ( struct scsi_command *scsicmd,
+			 struct scsi_cmd *command );
+	/**
+	 * Handle SCSI command completion
+	 *
+	 * @v scsicmd		SCSI command
+	 * @v rc		Reason for completion
+	 */
+	void ( * done ) ( struct scsi_command *scsicmd, int rc );
+};
+
+/**
+ * Get reference to SCSI device
+ *
+ * @v scsidev		SCSI device
+ * @ret scsidev		SCSI device
+ */
+static inline __attribute__ (( always_inline )) struct scsi_device *
+scsidev_get ( struct scsi_device *scsidev ) {
+	ref_get ( &scsidev->refcnt );
+	return scsidev;
+}
+
+/**
+ * Drop reference to SCSI device
+ *
+ * @v scsidev		SCSI device
+ */
+static inline __attribute__ (( always_inline )) void
+scsidev_put ( struct scsi_device *scsidev ) {
+	ref_put ( &scsidev->refcnt );
+}
+
+/**
+ * Get reference to SCSI command
+ *
+ * @v scsicmd		SCSI command
+ * @ret scsicmd		SCSI command
+ */
+static inline __attribute__ (( always_inline )) struct scsi_command *
+scsicmd_get ( struct scsi_command *scsicmd ) {
+	ref_get ( &scsicmd->refcnt );
+	return scsicmd;
+}
+
+/**
+ * Drop reference to SCSI command
+ *
+ * @v scsicmd		SCSI command
+ */
+static inline __attribute__ (( always_inline )) void
+scsicmd_put ( struct scsi_command *scsicmd ) {
+	ref_put ( &scsicmd->refcnt );
+}
+
+/**
+ * Get SCSI command private data
+ *
+ * @v scsicmd		SCSI command
+ * @ret priv		Private data
+ */
+static inline __attribute__ (( always_inline )) void *
+scsicmd_priv ( struct scsi_command *scsicmd ) {
+	return scsicmd->priv;
+}
+
+/**
+ * Free SCSI command
+ *
+ * @v refcnt		Reference count
+ */
+static void scsicmd_free ( struct refcnt *refcnt ) {
+	struct scsi_command *scsicmd =
+		container_of ( refcnt, struct scsi_command, refcnt );
+
+	/* Remove from list of commands */
+	list_del ( &scsicmd->list );
+	scsidev_put ( scsicmd->scsidev );
+
+	/* Free command */
+	free ( scsicmd );
+}
+
+/**
+ * Close SCSI command
+ *
+ * @v scsicmd		SCSI command
+ * @v rc		Reason for close
+ */
+static void scsicmd_close ( struct scsi_command *scsicmd, int rc ) {
+	struct scsi_device *scsidev = scsicmd->scsidev;
+
+	if ( rc != 0 ) {
+		DBGC ( scsidev, "SCSI %p tag %08x closed: %s\n",
+		       scsidev, scsicmd->tag, strerror ( rc ) );
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &scsicmd->scsi, rc );
+	intf_shutdown ( &scsicmd->block, rc );
+}
+
+/**
+ * Construct and issue SCSI command
+ *
+ * @ret rc		Return status code
+ */
+static int scsicmd_command ( struct scsi_command *scsicmd ) {
+	struct scsi_device *scsidev = scsicmd->scsidev;
+	struct scsi_cmd command;
+	int tag;
+	int rc;
+
+	/* Construct command */
+	memset ( &command, 0, sizeof ( command ) );
+	memcpy ( &command.lun, &scsidev->lun, sizeof ( command.lun ) );
+	scsicmd->type->cmd ( scsicmd, &command );
+
+	/* Issue command */
+	if ( ( tag = scsi_command ( &scsidev->scsi, &scsicmd->scsi,
+				    &command ) ) < 0 ) {
+		rc = tag;
+		DBGC ( scsidev, "SCSI %p could not issue command: %s\n",
+		       scsidev, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Record tag */
+	if ( scsicmd->tag ) {
+		DBGC ( scsidev, "SCSI %p tag %08x is now tag %08x\n",
+		       scsidev, scsicmd->tag, tag );
+	}
+	scsicmd->tag = tag;
+	DBGC2 ( scsidev, "SCSI %p tag %08x %s " SCSI_CDB_FORMAT "\n",
+		scsidev, scsicmd->tag, scsicmd->type->name,
+		SCSI_CDB_DATA ( command.cdb ) );
+
+	return 0;
+}
+
+/**
+ * Handle SCSI command completion
+ *
+ * @v scsicmd		SCSI command
+ * @v rc		Reason for close
+ */
+static void scsicmd_done ( struct scsi_command *scsicmd, int rc ) {
+	struct scsi_device *scsidev = scsicmd->scsidev;
+
+	/* Restart SCSI interface */
+	intf_restart ( &scsicmd->scsi, rc );
+
+	/* SCSI targets have an annoying habit of returning occasional
+	 * pointless "error" messages such as "power-on occurred", so
+	 * we have to be prepared to retry commands.
+	 */
+	if ( ( rc != 0 ) && ( scsicmd->retries++ < SCSICMD_MAX_RETRIES ) ) {
+		/* Retry command */
+		DBGC ( scsidev, "SCSI %p tag %08x failed: %s\n",
+		       scsidev, scsicmd->tag, strerror ( rc ) );
+		DBGC ( scsidev, "SCSI %p tag %08x retrying (retry %d)\n",
+		       scsidev, scsicmd->tag, scsicmd->retries );
+		if ( ( rc = scsicmd_command ( scsicmd ) ) == 0 )
+			return;
+	}
+
+	/* If we didn't (successfully) reissue the command, hand over
+	 * to the command completion handler.
+	 */
+	scsicmd->type->done ( scsicmd, rc );
+}
+
+/**
+ * Handle SCSI response
+ *
+ * @v scsicmd		SCSI command
+ * @v response		SCSI response
+ */
+static void scsicmd_response ( struct scsi_command *scsicmd,
+			       struct scsi_rsp *response ) {
+	struct scsi_device *scsidev = scsicmd->scsidev;
+	size_t overrun;
+	size_t underrun;
+	int rc;
+
+	if ( response->status == 0 ) {
+		scsicmd_done ( scsicmd, 0 );
+	} else {
+		DBGC ( scsidev, "SCSI %p tag %08x status %02x",
+		       scsidev, scsicmd->tag, response->status );
+		if ( response->overrun > 0 ) {
+			overrun = response->overrun;
+			DBGC ( scsidev, " overrun +%zd", overrun );
+		} else if ( response->overrun < 0 ) {
+			underrun = -(response->overrun);
+			DBGC ( scsidev, " underrun -%zd", underrun );
+		}
+		DBGC ( scsidev, " sense %02x:%02x:%08x\n",
+		       response->sense.code, response->sense.key,
+		       ntohl ( response->sense.info ) );
+
+		/* Construct error number from sense data */
+		rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK );
+		scsicmd_done ( scsicmd, rc );
+	}
+}
+
+/**
+ * Construct SCSI READ command
+ *
+ * @v scsicmd		SCSI command
+ * @v command		SCSI command IU
+ */
+static void scsicmd_read_cmd ( struct scsi_command *scsicmd,
+			       struct scsi_cmd *command ) {
+
+	if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
+		/* Use READ (16) */
+		command->cdb.read16.opcode = SCSI_OPCODE_READ_16;
+		command->cdb.read16.lba = cpu_to_be64 ( scsicmd->lba );
+		command->cdb.read16.len = cpu_to_be32 ( scsicmd->count );
+	} else {
+		/* Use READ (10) */
+		command->cdb.read10.opcode = SCSI_OPCODE_READ_10;
+		command->cdb.read10.lba = cpu_to_be32 ( scsicmd->lba );
+		command->cdb.read10.len = cpu_to_be16 ( scsicmd->count );
+	}
+	command->data_in = scsicmd->buffer;
+	command->data_in_len = scsicmd->len;
+}
+
+/** SCSI READ command type */
+static struct scsi_command_type scsicmd_read = {
+	.name = "READ",
+	.cmd = scsicmd_read_cmd,
+	.done = scsicmd_close,
+};
+
+/**
+ * Construct SCSI WRITE command
+ *
+ * @v scsicmd		SCSI command
+ * @v command		SCSI command IU
+ */
+static void scsicmd_write_cmd ( struct scsi_command *scsicmd,
+				struct scsi_cmd *command ) {
+
+	if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
+		/* Use WRITE (16) */
+		command->cdb.write16.opcode = SCSI_OPCODE_WRITE_16;
+		command->cdb.write16.lba = cpu_to_be64 ( scsicmd->lba );
+		command->cdb.write16.len = cpu_to_be32 ( scsicmd->count );
+	} else {
+		/* Use WRITE (10) */
+		command->cdb.write10.opcode = SCSI_OPCODE_WRITE_10;
+		command->cdb.write10.lba = cpu_to_be32 ( scsicmd->lba );
+		command->cdb.write10.len = cpu_to_be16 ( scsicmd->count );
+	}
+	command->data_out = scsicmd->buffer;
+	command->data_out_len = scsicmd->len;
+}
+
+/** SCSI WRITE command type */
+static struct scsi_command_type scsicmd_write = {
+	.name = "WRITE",
+	.cmd = scsicmd_write_cmd,
+	.done = scsicmd_close,
+};
+
+/** SCSI READ CAPACITY private data */
+struct scsi_read_capacity_private {
+	/** Use READ CAPACITY (16) */
+	int use16;
+	/** Data buffer for READ CAPACITY commands */
+	union {
+		/** Data buffer for READ CAPACITY (10) */
+		struct scsi_capacity_10 capacity10;
+		/** Data buffer for READ CAPACITY (16) */
+		struct scsi_capacity_16 capacity16;
+	} capacity;
+};
+
+/**
+ * Construct SCSI READ CAPACITY command
+ *
+ * @v scsicmd		SCSI command
+ * @v command		SCSI command IU
+ */
+static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
+					struct scsi_cmd *command ) {
+	struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
+	struct scsi_cdb_read_capacity_16 *readcap16 = &command->cdb.readcap16;
+	struct scsi_cdb_read_capacity_10 *readcap10 = &command->cdb.readcap10;
+	struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
+	struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
+
+	if ( priv->use16 ) {
+		/* Use READ CAPACITY (16) */
+		readcap16->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
+		readcap16->service_action =
+			SCSI_SERVICE_ACTION_READ_CAPACITY_16;
+		readcap16->len = cpu_to_be32 ( sizeof ( *capacity16 ) );
+		command->data_in = virt_to_user ( capacity16 );
+		command->data_in_len = sizeof ( *capacity16 );
+	} else {
+		/* Use READ CAPACITY (10) */
+		readcap10->opcode = SCSI_OPCODE_READ_CAPACITY_10;
+		command->data_in = virt_to_user ( capacity10 );
+		command->data_in_len = sizeof ( *capacity10 );
+	}
+}
+
+/**
+ * Handle SCSI READ CAPACITY command completion
+ *
+ * @v scsicmd		SCSI command
+ * @v rc		Reason for completion
+ */
+static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
+					 int rc ) {
+	struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
+	struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
+	struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
+	struct block_device_capacity capacity;
+
+	/* Close if command failed */
+	if ( rc != 0 ) {
+		scsicmd_close ( scsicmd, rc );
+		return;
+	}
+
+	/* Extract capacity */
+	if ( priv->use16 ) {
+		capacity.blocks = ( be64_to_cpu ( capacity16->lba ) + 1 );
+		capacity.blksize = be32_to_cpu ( capacity16->blksize );
+	} else {
+		capacity.blocks = ( be32_to_cpu ( capacity10->lba ) + 1 );
+		capacity.blksize = be32_to_cpu ( capacity10->blksize );
+
+		/* If capacity range was exceeded (i.e. capacity.lba
+		 * was 0xffffffff, meaning that blockdev->blocks is
+		 * now zero), use READ CAPACITY (16) instead.  READ
+		 * CAPACITY (16) is not mandatory, so we can't just
+		 * use it straight off.
+		 */
+		if ( capacity.blocks == 0 ) {
+			priv->use16 = 1;
+			if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 ) {
+				scsicmd_close ( scsicmd, rc );
+				return;
+			}
+			return;
+		}
+	}
+	capacity.max_count = -1U;
+
+	/* Return capacity to caller */
+	block_capacity ( &scsicmd->block, &capacity );
+
+	/* Close command */
+	scsicmd_close ( scsicmd, 0 );
+}
+
+/** SCSI READ CAPACITY command type */
+static struct scsi_command_type scsicmd_read_capacity = {
+	.name = "READ CAPACITY",
+	.priv_len = sizeof ( struct scsi_read_capacity_private ),
+	.cmd = scsicmd_read_capacity_cmd,
+	.done = scsicmd_read_capacity_done,
+};
+
+/**
+ * Construct SCSI TEST UNIT READY command
+ *
+ * @v scsicmd		SCSI command
+ * @v command		SCSI command IU
+ */
+static void scsicmd_test_unit_ready_cmd ( struct scsi_command *scsicmd __unused,
+					  struct scsi_cmd *command ) {
+	struct scsi_cdb_test_unit_ready *testready = &command->cdb.testready;
+
+	testready->opcode = SCSI_OPCODE_TEST_UNIT_READY;
+}
+
+/** SCSI TEST UNIT READY command type */
+static struct scsi_command_type scsicmd_test_unit_ready = {
+	.name = "TEST UNIT READY",
+	.cmd = scsicmd_test_unit_ready_cmd,
+	.done = scsicmd_close,
+};
+
+/** SCSI command block interface operations */
+static struct interface_operation scsicmd_block_op[] = {
+	INTF_OP ( intf_close, struct scsi_command *, scsicmd_close ),
+};
+
+/** SCSI command block interface descriptor */
+static struct interface_descriptor scsicmd_block_desc =
+	INTF_DESC_PASSTHRU ( struct scsi_command, block,
+			     scsicmd_block_op, scsi );
+
+/** SCSI command SCSI interface operations */
+static struct interface_operation scsicmd_scsi_op[] = {
+	INTF_OP ( intf_close, struct scsi_command *, scsicmd_done ),
+	INTF_OP ( scsi_response, struct scsi_command *, scsicmd_response ),
+};
+
+/** SCSI command SCSI interface descriptor */
+static struct interface_descriptor scsicmd_scsi_desc =
+	INTF_DESC_PASSTHRU ( struct scsi_command, scsi,
+			     scsicmd_scsi_op, block );
+
+/**
+ * Create SCSI command
+ *
+ * @v scsidev		SCSI device
+ * @v block		Block data interface
+ * @v type		SCSI command type
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int scsidev_command ( struct scsi_device *scsidev,
+			     struct interface *block,
+			     struct scsi_command_type *type,
+			     uint64_t lba, unsigned int count,
+			     userptr_t buffer, size_t len ) {
+	struct scsi_command *scsicmd;
+	int rc;
+
+	/* Allocate and initialise structure */
+	scsicmd = zalloc ( sizeof ( *scsicmd ) + type->priv_len );
+	if ( ! scsicmd ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &scsicmd->refcnt, scsicmd_free );
+	intf_init ( &scsicmd->block, &scsicmd_block_desc, &scsicmd->refcnt );
+	intf_init ( &scsicmd->scsi, &scsicmd_scsi_desc,
+		    &scsicmd->refcnt );
+	scsicmd->scsidev = scsidev_get ( scsidev );
+	list_add ( &scsicmd->list, &scsidev->cmds );
+	scsicmd->type = type;
+	scsicmd->lba = lba;
+	scsicmd->count = count;
+	scsicmd->buffer = buffer;
+	scsicmd->len = len;
+
+	/* Issue SCSI command */
+	if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 )
+		goto err_command;
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &scsicmd->block, block );
+	ref_put ( &scsicmd->refcnt );
+	return 0;
+
+ err_command:
+	scsicmd_close ( scsicmd, rc );
+	ref_put ( &scsicmd->refcnt );
+ err_zalloc:
+	return rc;
+}
+
+/**
+ * Issue SCSI block read
+ *
+ * @v scsidev		SCSI device
+ * @v block		Block data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+
+ */
+static int scsidev_read ( struct scsi_device *scsidev,
+			  struct interface *block,
+			  uint64_t lba, unsigned int count,
+			  userptr_t buffer, size_t len ) {
+	return scsidev_command ( scsidev, block, &scsicmd_read,
+				 lba, count, buffer, len );
+}
+
+/**
+ * Issue SCSI block write
+ *
+ * @v scsidev		SCSI device
+ * @v block		Block data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int scsidev_write ( struct scsi_device *scsidev,
+			   struct interface *block,
+			   uint64_t lba, unsigned int count,
+			   userptr_t buffer, size_t len ) {
+	return scsidev_command ( scsidev, block, &scsicmd_write,
+				 lba, count, buffer, len );
+}
+
+/**
+ * Read SCSI device capacity
+ *
+ * @v scsidev		SCSI device
+ * @v block		Block data interface
+ * @ret rc		Return status code
+ */
+static int scsidev_read_capacity ( struct scsi_device *scsidev,
+				   struct interface *block ) {
+	return scsidev_command ( scsidev, block, &scsicmd_read_capacity,
+				 0, 0, UNULL, 0 );
+}
+
+/**
+ * Test to see if SCSI device is ready
+ *
+ * @v scsidev		SCSI device
+ * @v block		Block data interface
+ * @ret rc		Return status code
+ */
+static int scsidev_test_unit_ready ( struct scsi_device *scsidev,
+				     struct interface *block ) {
+	return scsidev_command ( scsidev, block, &scsicmd_test_unit_ready,
+				 0, 0, UNULL, 0 );
+}
+
+/**
+ * Check SCSI device flow-control window
+ *
+ * @v scsidev		SCSI device
+ * @ret len		Length of window
+ */
+static size_t scsidev_window ( struct scsi_device *scsidev ) {
+
+	/* Refuse commands until unit is confirmed ready */
+	if ( ! ( scsidev->flags & SCSIDEV_UNIT_READY ) )
+		return 0;
+
+	return xfer_window ( &scsidev->scsi );
+}
+
+/**
+ * Close SCSI device
+ *
+ * @v scsidev		SCSI device
+ * @v rc		Reason for close
+ */
+static void scsidev_close ( struct scsi_device *scsidev, int rc ) {
+	struct scsi_command *scsicmd;
+	struct scsi_command *tmp;
+
+	/* Stop process */
+	process_del ( &scsidev->process );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &scsidev->block, rc );
+	intf_shutdown ( &scsidev->scsi, rc );
+	intf_shutdown ( &scsidev->ready, rc );
+
+	/* Shut down any remaining commands */
+	list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
+		scsicmd_get ( scsicmd );
+		scsicmd_close ( scsicmd, rc );
+		scsicmd_put ( scsicmd );
+	}
+}
+
+/** SCSI device block interface operations */
+static struct interface_operation scsidev_block_op[] = {
+	INTF_OP ( xfer_window, struct scsi_device *, scsidev_window ),
+	INTF_OP ( block_read, struct scsi_device *, scsidev_read ),
+	INTF_OP ( block_write, struct scsi_device *, scsidev_write ),
+	INTF_OP ( block_read_capacity, struct scsi_device *,
+		  scsidev_read_capacity ),
+	INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
+};
+
+/** SCSI device block interface descriptor */
+static struct interface_descriptor scsidev_block_desc =
+	INTF_DESC_PASSTHRU ( struct scsi_device, block,
+			     scsidev_block_op, scsi );
+
+/**
+ * Handle SCSI TEST UNIT READY response
+ *
+ * @v scsidev		SCSI device
+ * @v rc		Reason for close
+ */
+static void scsidev_ready ( struct scsi_device *scsidev, int rc ) {
+
+	/* Shut down interface */
+	intf_shutdown ( &scsidev->ready, rc );
+
+	/* Close device on failure */
+	if ( rc != 0 ) {
+		DBGC ( scsidev, "SCSI %p not ready: %s\n",
+		       scsidev, strerror ( rc ) );
+		scsidev_close ( scsidev, rc );
+		return;
+	}
+
+	/* Mark device as ready */
+	scsidev->flags |= SCSIDEV_UNIT_READY;
+	xfer_window_changed ( &scsidev->block );
+	DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
+}
+
+/** SCSI device TEST UNIT READY interface operations */
+static struct interface_operation scsidev_ready_op[] = {
+	INTF_OP ( intf_close, struct scsi_device *, scsidev_ready ),
+};
+
+/** SCSI device TEST UNIT READY interface descriptor */
+static struct interface_descriptor scsidev_ready_desc =
+	INTF_DESC ( struct scsi_device, ready, scsidev_ready_op );
+
+/**
+ * SCSI TEST UNIT READY process
+ *
+ * @v process		Process
+ */
+static void scsidev_step ( struct process *process ) {
+	struct scsi_device *scsidev =
+		container_of ( process, struct scsi_device, process );
+	int rc;
+
+	/* Wait until underlying SCSI device is ready */
+	if ( xfer_window ( &scsidev->scsi ) == 0 )
+		return;
+
+	/* Stop process */
+	process_del ( &scsidev->process );
+
+	DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
+	       scsidev );
+
+	/* Issue TEST UNIT READY command */
+	if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
+		scsidev_close ( scsidev, rc );
+		return;
+	}
+}
+
+/** SCSI device SCSI interface operations */
+static struct interface_operation scsidev_scsi_op[] = {
+	INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
+};
+
+/** SCSI device SCSI interface descriptor */
+static struct interface_descriptor scsidev_scsi_desc =
+	INTF_DESC_PASSTHRU ( struct scsi_device, scsi,
+			     scsidev_scsi_op, block );
+
+/**
+ * Open SCSI device
+ *
+ * @v block		Block control interface
+ * @v scsi		SCSI control interface
+ * @v lun		SCSI LUN
+ * @ret rc		Return status code
+ */
+int scsi_open ( struct interface *block, struct interface *scsi,
+		struct scsi_lun *lun ) {
+	struct scsi_device *scsidev;
+
+	/* Allocate and initialise structure */
+	scsidev = zalloc ( sizeof ( *scsidev ) );
+	if ( ! scsidev )
+		return -ENOMEM;
+	ref_init ( &scsidev->refcnt, NULL );
+	intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
+	intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
+	intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
+	process_init ( &scsidev->process, scsidev_step, &scsidev->refcnt );
+	INIT_LIST_HEAD ( &scsidev->cmds );
+	memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
+	DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
+	       scsidev, SCSI_LUN_DATA ( scsidev->lun ) );
+
+	/* Attach to SCSI and parent interfaces, mortalise self, and return */
+	intf_plug_plug ( &scsidev->scsi, scsi );
+	intf_plug_plug ( &scsidev->block, block );
+	ref_put ( &scsidev->refcnt );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/block/srp.c b/qemu-0.15.x/roms/ipxe/src/drivers/block/srp.c
new file mode 100644
index 0000000..098a973
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/block/srp.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright (C) 2009 Fen Systems Ltd <mbrown at fensystems.co.uk>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   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 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 THE
+ * COPYRIGHT HOLDER 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.
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/scsi.h>
+#include <ipxe/xfer.h>
+#include <ipxe/features.h>
+#include <ipxe/srp.h>
+
+/**
+ * @file
+ *
+ * SCSI RDMA Protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
+
+/** Maximum length of any initiator-to-target IU that we will send
+ *
+ * The longest IU is a SRP_CMD with no additional CDB and two direct
+ * data buffer descriptors, which comes to 80 bytes.
+ */
+#define SRP_MAX_I_T_IU_LEN 80
+
+/* Error numbers generated by SRP login rejection */
+#define EINFO_SRP_LOGIN_REJ( reason, desc )				      \
+	__einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
+#define EPERM_UNKNOWN							      \
+	__einfo_error ( EINFO_EPERM_UNKNOWN )
+#define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ (			      \
+	SRP_LOGIN_REJ_REASON_UNKNOWN,					      \
+	"Unable to establish RDMA channel, no reason specified" )
+#define EPERM_INSUFFICIENT_RESOURCES					      \
+	__einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
+#define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ (	      \
+	SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES,			      \
+	"Insufficient RDMA channel resources" )
+#define EPERM_BAD_MAX_I_T_IU_LEN					      \
+	__einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
+#define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ (		      \
+	SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN,			      \
+	"Requested maximum initiator to target IU length value too large" )
+#define EPERM_CANNOT_ASSOCIATE						      \
+	__einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
+#define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ (		      \
+	SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE,				      \
+	"Unable to associate RDMA channel with specified I_T nexus" )
+#define EPERM_UNSUPPORTED_BUFFER_FORMAT					      \
+	__einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
+#define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ (	      \
+	SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT,			      \
+	"One or more requested data buffer descriptor formats not supported" )
+#define EPERM_NO_MULTIPLE_CHANNELS					      \
+	__einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
+#define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ (		      \
+	SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS,			      \
+	"SRP target does not support multiple RDMA channels per I_T nexus" )
+#define EPERM_NO_MORE_CHANNELS						      \
+	__einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
+#define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ (		      \
+	SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS,				      \
+	"RDMA channel limit reached for this initiator" )
+#define EPERM_LOGIN_REJ( reason_nibble )				      \
+	EUNIQ ( EPERM, (reason_nibble), EPERM_UNKNOWN,			      \
+		EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN,	      \
+		EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT,      \
+		EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
+
+/** An SRP device */
+struct srp_device {
+	/** Reference count */
+	struct refcnt refcnt;
+
+	/** SCSI command issuing interface */
+	struct interface scsi;
+	/** Underlying data transfer interface */
+	struct interface socket;
+
+	/** RDMA memory handle */
+	uint32_t memory_handle;
+	/** Login completed successfully */
+	int logged_in;
+
+	/** Initiator port ID (for boot firmware table) */
+	union srp_port_id initiator;
+	/** Target port ID (for boot firmware table) */
+	union srp_port_id target;
+	/** SCSI LUN (for boot firmware table) */
+	struct scsi_lun lun;
+
+	/** List of active commands */
+	struct list_head commands;
+};
+
+/** An SRP command */
+struct srp_command {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** SRP device */
+	struct srp_device *srpdev;
+	/** List of active commands */
+	struct list_head list;
+
+	/** SCSI command interface */
+	struct interface scsi;
+	/** Command tag */
+	uint32_t tag;
+};
+
+/**
+ * Get reference to SRP device
+ *
+ * @v srpdev		SRP device
+ * @ret srpdev		SRP device
+ */
+static inline __attribute__ (( always_inline )) struct srp_device *
+srpdev_get ( struct srp_device *srpdev ) {
+	ref_get ( &srpdev->refcnt );
+	return srpdev;
+}
+
+/**
+ * Drop reference to SRP device
+ *
+ * @v srpdev		SRP device
+ */
+static inline __attribute__ (( always_inline )) void
+srpdev_put ( struct srp_device *srpdev ) {
+	ref_put ( &srpdev->refcnt );
+}
+
+/**
+ * Get reference to SRP command
+ *
+ * @v srpcmd		SRP command
+ * @ret srpcmd		SRP command
+ */
+static inline __attribute__ (( always_inline )) struct srp_command *
+srpcmd_get ( struct srp_command *srpcmd ) {
+	ref_get ( &srpcmd->refcnt );
+	return srpcmd;
+}
+
+/**
+ * Drop reference to SRP command
+ *
+ * @v srpcmd		SRP command
+ */
+static inline __attribute__ (( always_inline )) void
+srpcmd_put ( struct srp_command *srpcmd ) {
+	ref_put ( &srpcmd->refcnt );
+}
+
+/**
+ * Free SRP command
+ *
+ * @v refcnt		Reference count
+ */
+static void srpcmd_free ( struct refcnt *refcnt ) {
+	struct srp_command *srpcmd =
+		container_of ( refcnt, struct srp_command, refcnt );
+
+	assert ( list_empty ( &srpcmd->list ) );
+
+	srpdev_put ( srpcmd->srpdev );
+	free ( srpcmd );
+}
+
+/**
+ * Close SRP command
+ *
+ * @v srpcmd		SRP command
+ * @v rc		Reason for close
+ */
+static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
+	struct srp_device *srpdev = srpcmd->srpdev;
+
+	if ( rc != 0 ) {
+		DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
+		       srpdev, srpcmd->tag, strerror ( rc ) );
+	}
+
+	/* Remove from list of commands */
+	if ( ! list_empty ( &srpcmd->list ) ) {
+		list_del ( &srpcmd->list );
+		INIT_LIST_HEAD ( &srpcmd->list );
+		srpcmd_put ( srpcmd );
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &srpcmd->scsi, rc );
+}
+
+/**
+ * Close SRP device
+ *
+ * @v srpdev		SRP device
+ * @v rc		Reason for close
+ */
+static void srpdev_close ( struct srp_device *srpdev, int rc ) {
+	struct srp_command *srpcmd;
+	struct srp_command *tmp;
+
+	if ( rc != 0 ) {
+		DBGC ( srpdev, "SRP %p closed: %s\n",
+		       srpdev, strerror ( rc ) );
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &srpdev->socket, rc );
+	intf_shutdown ( &srpdev->scsi, rc );
+
+	/* Shut down any active commands */
+	list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
+		srpcmd_get ( srpcmd );
+		srpcmd_close ( srpcmd, rc );
+		srpcmd_put ( srpcmd );
+	}
+}
+
+/**
+ * Identify SRP command by tag
+ *
+ * @v srpdev		SRP device
+ * @v tag		Command tag
+ * @ret srpcmd		SRP command, or NULL
+ */
+static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
+					   uint32_t tag ) {
+	struct srp_command *srpcmd;
+
+	list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
+		if ( srpcmd->tag == tag )
+			return srpcmd;
+	}
+	return NULL;
+}
+
+/**
+ * Choose an SRP command tag
+ *
+ * @v srpdev		SRP device
+ * @ret tag		New tag, or negative error
+ */
+static int srp_new_tag ( struct srp_device *srpdev ) {
+	static uint16_t tag_idx;
+	unsigned int i;
+
+	for ( i = 0 ; i < 65536 ; i++ ) {
+		tag_idx++;
+		if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
+			return tag_idx;
+	}
+	return -EADDRINUSE;
+}
+
+/**
+ * Transmit SRP login request
+ *
+ * @v srpdev		SRP device
+ * @v initiator		Initiator port ID
+ * @v target		Target port ID
+ * @v tag		Command tag
+ * @ret rc		Return status code
+ */
+static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
+		       union srp_port_id *target, uint32_t tag ) {
+	struct io_buffer *iobuf;
+	struct srp_login_req *login_req;
+	int rc;
+
+	/* Allocate I/O buffer */
+	iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Construct login request IU */
+	login_req = iob_put ( iobuf, sizeof ( *login_req ) );
+	memset ( login_req, 0, sizeof ( *login_req ) );
+	login_req->type = SRP_LOGIN_REQ;
+	login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
+	login_req->tag.dwords[1] = htonl ( tag );
+	login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
+	login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
+	memcpy ( &login_req->initiator, initiator,
+		 sizeof ( login_req->initiator ) );
+	memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
+
+	DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
+	DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
+
+	/* Send login request IU */
+	if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
+		DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
+		       "%s\n", srpdev, tag, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive SRP login response
+ *
+ * @v srpdev		SRP device
+ * @v data		SRP IU
+ * @v len		Length of SRP IU
+ * @ret rc		Return status code
+ */
+static int srp_login_rsp ( struct srp_device *srpdev,
+			   const void *data, size_t len ) {
+	const struct srp_login_rsp *login_rsp = data;
+
+	/* Sanity check */
+	if ( len < sizeof ( *login_rsp ) ) {
+		DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
+		       srpdev, len );
+		return -EINVAL;
+	}
+	DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
+	       srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
+	DBGC_HDA ( srpdev, 0, data, len );
+
+	/* Mark as logged in */
+	srpdev->logged_in = 1;
+	DBGC ( srpdev, "SRP %p logged in\n", srpdev );
+
+	/* Notify of window change */
+	xfer_window_changed ( &srpdev->scsi );
+
+	return 0;
+}
+
+/**
+ * Receive SRP login rejection
+ *
+ * @v srpdev		SRP device
+ * @v data		SRP IU
+ * @v len		Length of SRP IU
+ * @ret rc		Return status code
+ */
+static int srp_login_rej ( struct srp_device *srpdev,
+			   const void *data, size_t len ) {
+	const struct srp_login_rej *login_rej = data;
+	uint32_t reason;
+
+	/* Sanity check */
+	if ( len < sizeof ( *login_rej ) ) {
+		DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
+		       srpdev, len );
+		return -EINVAL;
+	}
+	reason = ntohl ( login_rej->reason );
+	DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
+	       srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
+	DBGC_HDA ( srpdev, 0, data, len );
+
+	/* Login rejection always indicates an error */
+	return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
+		 -EPERM_LOGIN_REJ ( reason ) : -EACCES );
+}
+
+/**
+ * Transmit SRP SCSI command
+ *
+ * @v srpdev		SRP device
+ * @v command		SCSI command
+ * @v tag		Command tag
+ * @ret rc		Return status code
+ */
+static int srp_cmd ( struct srp_device *srpdev,
+		     struct scsi_cmd *command,
+		     uint32_t tag ) {
+	struct io_buffer *iobuf;
+	struct srp_cmd *cmd;
+	struct srp_memory_descriptor *data_out;
+	struct srp_memory_descriptor *data_in;
+	int rc;
+
+	/* Sanity check */
+	if ( ! srpdev->logged_in ) {
+		DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
+		       "login completes\n", srpdev, tag );
+		return -EBUSY;
+	}
+
+	/* Allocate I/O buffer */
+	iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Construct base portion */
+	cmd = iob_put ( iobuf, sizeof ( *cmd ) );
+	memset ( cmd, 0, sizeof ( *cmd ) );
+	cmd->type = SRP_CMD;
+	cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
+	cmd->tag.dwords[1] = htonl ( tag );
+	memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
+	memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
+
+	/* Construct data-out descriptor, if present */
+	if ( command->data_out ) {
+		cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
+		data_out = iob_put ( iobuf, sizeof ( *data_out ) );
+		data_out->address =
+		    cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
+		data_out->handle = ntohl ( srpdev->memory_handle );
+		data_out->len = ntohl ( command->data_out_len );
+	}
+
+	/* Construct data-in descriptor, if present */
+	if ( command->data_in ) {
+		cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
+		data_in = iob_put ( iobuf, sizeof ( *data_in ) );
+		data_in->address =
+		     cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
+		data_in->handle = ntohl ( srpdev->memory_handle );
+		data_in->len = ntohl ( command->data_in_len );
+	}
+
+	DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
+		srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
+
+	/* Send IU */
+	if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
+		DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
+		       srpdev, tag, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive SRP SCSI response
+ *
+ * @v srpdev		SRP device
+ * @v data		SRP IU
+ * @v len		Length of SRP IU
+ * @ret rc		Returns status code
+ */
+static int srp_rsp ( struct srp_device *srpdev,
+		     const void *data, size_t len ) {
+	const struct srp_rsp *rsp = data;
+	struct srp_command *srpcmd;
+	struct scsi_rsp response;
+	const void *sense;
+	ssize_t data_out_residual_count;
+	ssize_t data_in_residual_count;
+
+	/* Sanity check */
+	if ( len < sizeof ( *rsp ) ) {
+		DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
+		       srpdev, len );
+		return -EINVAL;
+	}
+	DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
+		"%08x valid %02x%s%s%s%s%s%s\n",
+		srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
+		ntohl ( rsp->data_out_residual_count ),
+		ntohl ( rsp->data_in_residual_count ), rsp->valid,
+		( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
+		( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
+		( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
+		( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
+		( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
+		( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
+
+	/* Identify command by tag */
+	srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
+	if ( ! srpcmd ) {
+		DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
+		       srpdev, ntohl ( rsp->tag.dwords[1] ) );
+		return -ENOENT;
+	}
+
+	/* Hold command reference for remainder of function */
+	srpcmd_get ( srpcmd );
+
+	/* Build SCSI response */
+	memset ( &response, 0, sizeof ( response ) );
+	response.status = rsp->status;
+	data_out_residual_count = ntohl ( rsp->data_out_residual_count );
+	data_in_residual_count = ntohl ( rsp->data_in_residual_count );
+	if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
+		response.overrun = data_out_residual_count;
+	} else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
+		response.overrun = -(data_out_residual_count);
+	} else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
+		response.overrun = data_in_residual_count;
+	} else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
+		response.overrun = -(data_in_residual_count);
+	}
+	sense = srp_rsp_sense_data ( rsp );
+	if ( sense )
+		memcpy ( &response.sense, sense, sizeof ( response.sense ) );
+
+	/* Report SCSI response */
+	scsi_response ( &srpcmd->scsi, &response );
+
+	/* Close SCSI command */
+	srpcmd_close ( srpcmd, 0 );
+
+	/* Drop temporary command reference */
+	srpcmd_put ( srpcmd );
+
+	return 0;
+}
+
+/**
+ * Receive SRP unrecognised response IU
+ *
+ * @v srpdev		SRP device
+ * @v data		SRP IU
+ * @v len		Length of SRP IU
+ * @ret rc		Returns status code
+ */
+static int srp_unrecognised ( struct srp_device *srpdev,
+			      const void *data, size_t len ) {
+	const struct srp_common *common = data;
+
+	DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
+	       srpdev, ntohl ( common->tag.dwords[1] ), common->type );
+	DBGC_HDA ( srpdev, 0, data, len );
+
+	return -ENOTSUP;
+}
+
+/** SRP command SCSI interface operations */
+static struct interface_operation srpcmd_scsi_op[] = {
+	INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
+};
+
+/** SRP command SCSI interface descriptor */
+static struct interface_descriptor srpcmd_scsi_desc =
+	INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
+
+/**
+ * Issue SRP SCSI command
+ *
+ * @v srpdev		SRP device
+ * @v parent		Parent interface
+ * @v command		SCSI command
+ * @ret tag		Command tag, or negative error
+ */
+static int srpdev_scsi_command ( struct srp_device *srpdev,
+				 struct interface *parent,
+				 struct scsi_cmd *command ) {
+	struct srp_command *srpcmd;
+	int tag;
+	int rc;
+
+	/* Allocate command tag */
+	tag = srp_new_tag ( srpdev );
+	if ( tag < 0 ) {
+		rc = tag;
+		goto err_tag;
+	}
+
+	/* Allocate and initialise structure */
+	srpcmd = zalloc ( sizeof ( *srpcmd ) );
+	if ( ! srpcmd ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &srpcmd->refcnt, srpcmd_free );
+	intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
+	srpcmd->srpdev = srpdev_get ( srpdev );
+	list_add ( &srpcmd->list, &srpdev->commands );
+	srpcmd->tag = tag;
+
+	/* Send command IU */
+	if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
+		goto err_cmd;
+
+	/* Attach to parent interface, leave reference with command
+	 * list, and return.
+	 */
+	intf_plug_plug ( &srpcmd->scsi, parent );
+	return srpcmd->tag;
+
+ err_cmd:
+	srpcmd_close ( srpcmd, rc );
+ err_zalloc:
+ err_tag:
+	return rc;
+}
+
+/**
+ * Receive data from SRP socket
+ *
+ * @v srpdev		SRP device
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int srpdev_deliver ( struct srp_device *srpdev,
+			    struct io_buffer *iobuf,
+			    struct xfer_metadata *meta __unused ) {
+	struct srp_common *common = iobuf->data;
+	int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
+		DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
+		       srpdev, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Determine IU type */
+	switch ( common->type ) {
+	case SRP_LOGIN_RSP:
+		type = srp_login_rsp;
+		break;
+	case SRP_LOGIN_REJ:
+		type = srp_login_rej;
+		break;
+	case SRP_RSP:
+		type = srp_rsp;
+		break;
+	default:
+		type = srp_unrecognised;
+		break;
+	}
+
+	/* Handle IU */
+	if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
+		goto err;
+
+	free_iob ( iobuf );
+	return 0;
+
+ err:
+	DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
+	       srpdev, strerror ( rc ) );
+	DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
+	free_iob ( iobuf );
+	srpdev_close ( srpdev, rc );
+	return rc;
+}
+
+/**
+ * Check SRP device flow-control window
+ *
+ * @v srpdev		SRP device
+ * @ret len		Length of window
+ */
+static size_t srpdev_window ( struct srp_device *srpdev ) {
+	return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
+}
+
+/**
+ * A (transport-independent) sBFT created by iPXE
+ */
+struct ipxe_sbft {
+	/** The table header */
+	struct sbft_table table;
+	/** The SCSI subtable */
+	struct sbft_scsi_subtable scsi;
+	/** The SRP subtable */
+	struct sbft_srp_subtable srp;
+} __attribute__ (( packed, aligned ( 16 ) ));
+
+/**
+ * Describe SRP device in an ACPI table
+ *
+ * @v srpdev		SRP device
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+static int srpdev_describe ( struct srp_device *srpdev,
+			     struct acpi_description_header *acpi,
+			     size_t len ) {
+	struct ipxe_sbft *sbft =
+		container_of ( acpi, struct ipxe_sbft, table.acpi );
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *sbft ) )
+		return -ENOBUFS;
+
+	/* Populate table */
+	sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
+	sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
+	sbft->table.acpi.revision = 1;
+	sbft->table.scsi_offset =
+		cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
+	memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
+	sbft->table.srp_offset =
+		cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
+	memcpy ( &sbft->srp.initiator, &srpdev->initiator,
+		 sizeof ( sbft->srp.initiator ) );
+	memcpy ( &sbft->srp.target, &srpdev->target,
+		 sizeof ( sbft->srp.target ) );
+
+	/* Ask transport layer to describe transport-specific portions */
+	if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
+		DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
+		       srpdev, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** SRP device socket interface operations */
+static struct interface_operation srpdev_socket_op[] = {
+	INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
+	INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
+};
+
+/** SRP device socket interface descriptor */
+static struct interface_descriptor srpdev_socket_desc =
+	INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
+			     scsi );
+
+/** SRP device SCSI interface operations */
+static struct interface_operation srpdev_scsi_op[] = {
+	INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
+	INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
+	INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
+	INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
+};
+
+/** SRP device SCSI interface descriptor */
+static struct interface_descriptor srpdev_scsi_desc =
+	INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket  );
+
+/**
+ * Open SRP device
+ *
+ * @v block		Block control interface
+ * @v socket		Socket interface
+ * @v initiator		Initiator port ID
+ * @v target		Target port ID
+ * @v memory_handle	RDMA memory handle
+ * @v lun		SCSI LUN
+ * @ret rc		Return status code
+ */
+int srp_open ( struct interface *block, struct interface *socket,
+	       union srp_port_id *initiator, union srp_port_id *target,
+	       uint32_t memory_handle, struct scsi_lun *lun ) {
+	struct srp_device *srpdev;
+	int tag;
+	int rc;
+
+	/* Allocate and initialise structure */
+	srpdev = zalloc ( sizeof ( *srpdev ) );
+	if ( ! srpdev ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &srpdev->refcnt, NULL );
+	intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
+	intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
+	INIT_LIST_HEAD ( &srpdev->commands );
+	srpdev->memory_handle = memory_handle;
+	DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
+	       ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
+	       ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
+	       ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
+	       ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
+
+	/* Preserve parameters required for boot firmware table */
+	memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
+	memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
+	memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
+
+	/* Attach to socket interface and initiate login */
+	intf_plug_plug ( &srpdev->socket, socket );
+	tag = srp_new_tag ( srpdev );
+	assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
+	if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
+		goto err_login;
+
+	/* Attach SCSI device to parent interface */
+	if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
+		DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
+		       srpdev, strerror ( rc ) );
+		goto err_scsi_open;
+	}
+
+	/* Mortalise self and return */
+	ref_put ( &srpdev->refcnt );
+	return 0;
+
+ err_scsi_open:
+ err_login:
+	srpdev_close ( srpdev, rc );
+	ref_put ( &srpdev->refcnt );
+ err_zalloc:
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/eisa.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/eisa.c
new file mode 100644
index 0000000..a4efe26
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/eisa.c
@@ -0,0 +1,182 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <unistd.h>
+#include <ipxe/eisa.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+static void eisabus_remove ( struct root_device *rootdev );
+
+/**
+ * Reset and enable/disable an EISA device
+ *
+ * @v eisa		EISA device
+ * @v enabled		1=enable, 0=disable
+ */
+void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) {
+	/* Set reset line high for 1000 µs.  Spec says 500 µs, but
+	 * this doesn't work for all cards, so we are conservative.
+	 */
+	outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
+	udelay ( 1000 ); /* Must wait 800 */
+
+	/* Set reset low and write a 1 to ENABLE.  Delay again, in
+	 * case the card takes a while to wake up.
+	 */
+	outb ( enabled ? EISA_CMD_ENABLE : 0,
+	       eisa->ioaddr + EISA_GLOBAL_CONFIG );
+	udelay ( 1000 ); /* Must wait 800 */
+
+	DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ),
+	      eisa->slot );
+}
+
+/**
+ * Probe an EISA device
+ *
+ * @v eisa		EISA device
+ * @ret rc		Return status code
+ *
+ * Searches for a driver for the EISA device.  If a driver is found,
+ * its probe() routine is called.
+ */
+static int eisa_probe ( struct eisa_device *eisa ) {
+	struct eisa_driver *driver;
+	struct eisa_device_id *id;
+	unsigned int i;
+	int rc;
+
+	DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n",
+	      eisa->slot, eisa->vendor_id, eisa->prod_id,
+	      isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr );
+
+	for_each_table_entry ( driver, EISA_DRIVERS ) {
+		for ( i = 0 ; i < driver->id_count ; i++ ) {
+			id = &driver->ids[i];
+			if ( id->vendor_id != eisa->vendor_id )
+				continue;
+			if ( ISA_PROD_ID ( id->prod_id ) !=
+			     ISA_PROD_ID ( eisa->prod_id ) )
+				continue;
+			eisa->driver = driver;
+			eisa->dev.driver_name = id->name;
+			DBG ( "...using driver %s\n", eisa->dev.driver_name );
+			if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) {
+				DBG ( "......probe failed\n" );
+				continue;
+			}
+			return 0;
+		}
+	}
+
+	DBG ( "...no driver found\n" );
+	return -ENOTTY;
+}
+
+/**
+ * Remove an EISA device
+ *
+ * @v eisa		EISA device
+ */
+static void eisa_remove ( struct eisa_device *eisa ) {
+	eisa->driver->remove ( eisa );
+	DBG ( "Removed EISA device %02x\n", eisa->slot );
+}
+
+/**
+ * Probe EISA root bus
+ *
+ * @v rootdev		EISA bus root device
+ *
+ * Scans the EISA bus for devices and registers all devices it can
+ * find.
+ */
+static int eisabus_probe ( struct root_device *rootdev ) {
+	struct eisa_device *eisa = NULL;
+	unsigned int slot;
+	int rc;
+
+	for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
+		/* Allocate struct eisa_device */
+		if ( ! eisa )
+			eisa = malloc ( sizeof ( *eisa ) );
+		if ( ! eisa ) {
+			rc = -ENOMEM;
+			goto err;
+		}
+		memset ( eisa, 0, sizeof ( *eisa ) );
+		eisa->slot = slot;
+		eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
+
+		/* Test for board present */
+		outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID );
+		eisa->vendor_id =
+			le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) );
+		eisa->prod_id =
+			le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) );
+		if ( eisa->vendor_id & 0x80 ) {
+			/* No board present */
+			continue;
+		}
+
+		/* Add to device hierarchy */
+		snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ),
+			   "EISA%02x", slot );
+		eisa->dev.desc.bus_type = BUS_TYPE_EISA;
+		eisa->dev.desc.vendor = eisa->vendor_id;
+		eisa->dev.desc.device = eisa->prod_id;
+		eisa->dev.parent = &rootdev->dev;
+		list_add ( &eisa->dev.siblings, &rootdev->dev.children );
+		INIT_LIST_HEAD ( &eisa->dev.children );
+
+		/* Look for a driver */
+		if ( eisa_probe ( eisa ) == 0 ) {
+			/* eisadev registered, we can drop our ref */
+			eisa = NULL;
+		} else {
+			/* Not registered; re-use struct */
+			list_del ( &eisa->dev.siblings );
+		}
+	}
+
+	free ( eisa );
+	return 0;
+
+ err:
+	free ( eisa );
+	eisabus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove EISA root bus
+ *
+ * @v rootdev		EISA bus root device
+ */
+static void eisabus_remove ( struct root_device *rootdev ) {
+	struct eisa_device *eisa;
+	struct eisa_device *tmp;
+
+	list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		eisa_remove ( eisa );
+		list_del ( &eisa->dev.siblings );
+		free ( eisa );
+	}
+}
+
+/** EISA bus root device driver */
+static struct root_driver eisa_root_driver = {
+	.probe = eisabus_probe,
+	.remove = eisabus_remove,
+};
+
+/** EISA bus root device */
+struct root_device eisa_root_device __root_device = {
+	.dev = { .name = "EISA" },
+	.driver = &eisa_root_driver,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa.c
new file mode 100644
index 0000000..9b562c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa.c
@@ -0,0 +1,173 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <ipxe/isa.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * isa.c implements a "classical" port-scanning method of ISA device
+ * detection.  The driver must provide a list of probe addresses
+ * (probe_addrs), together with a function (probe_addr) that can be
+ * used to test for the physical presence of a device at any given
+ * address.
+ *
+ * Note that this should probably be considered the "last resort" for
+ * device probing.  If the card supports ISAPnP or EISA, use that
+ * instead.  Some cards (e.g. the 3c509) implement a proprietary
+ * ISAPnP-like mechanism.
+ *
+ * The ISA probe address list can be overridden by config.h; if the
+ * user specifies ISA_PROBE_ADDRS then that list will be used first.
+ * (If ISA_PROBE_ONLY is defined, the driver's own list will never be
+ * used).
+ */
+
+/*
+ * User-supplied probe address list
+ *
+ */
+static isa_probe_addr_t isa_extra_probe_addrs[] = {
+#ifdef ISA_PROBE_ADDRS
+	ISA_PROBE_ADDRS
+#endif
+};
+#define ISA_EXTRA_PROBE_ADDR_COUNT \
+     ( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) )
+
+#define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT )
+#ifdef ISA_PROBE_ONLY
+#define ISA_IOIDX_MAX( driver ) ( -1 )
+#else
+#define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 )
+#endif
+
+#define ISA_IOADDR( driver, ioidx )					  \
+	( ( (ioidx) < 0 ) ?						  \
+	  isa_extra_probe_addrs[ (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ] : \
+	  (driver)->probe_addrs[(ioidx)] )
+
+static void isabus_remove ( struct root_device *rootdev );
+
+/**
+ * Probe an ISA device
+ *
+ * @v isa		ISA device
+ * @ret rc		Return status code
+ */
+static int isa_probe ( struct isa_device *isa ) {
+	int rc;
+
+	DBG ( "Trying ISA driver %s at I/O %04x\n",
+	      isa->driver->name, isa->ioaddr );
+
+	if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) {
+		DBG ( "...probe failed\n" );
+		return rc;
+	}
+
+	DBG ( "...device found\n" );
+	return 0;
+}
+
+/**
+ * Remove an ISA device
+ *
+ * @v isa		ISA device
+ */
+static void isa_remove ( struct isa_device *isa ) {
+	isa->driver->remove ( isa );
+	DBG ( "Removed ISA%04x\n", isa->ioaddr );
+}
+
+/**
+ * Probe ISA root bus
+ *
+ * @v rootdev		ISA bus root device
+ *
+ * Scans the ISA bus for devices and registers all devices it can
+ * find.
+ */
+static int isabus_probe ( struct root_device *rootdev ) {
+	struct isa_device *isa = NULL;
+	struct isa_driver *driver;
+	int ioidx;
+	int rc;
+
+	for_each_table_entry ( driver, ISA_DRIVERS ) {
+		for ( ioidx = ISA_IOIDX_MIN ( driver ) ;
+		      ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) {
+			/* Allocate struct isa_device */
+			if ( ! isa )
+				isa = malloc ( sizeof ( *isa ) );
+			if ( ! isa ) {
+				rc = -ENOMEM;
+				goto err;
+			}
+			memset ( isa, 0, sizeof ( *isa ) );
+			isa->driver = driver;
+			isa->ioaddr = ISA_IOADDR ( driver, ioidx );
+
+			/* Add to device hierarchy */
+			snprintf ( isa->dev.name, sizeof ( isa->dev.name ),
+				   "ISA%04x", isa->ioaddr );
+			isa->dev.driver_name = driver->name;
+			isa->dev.desc.bus_type = BUS_TYPE_ISA;
+			isa->dev.desc.vendor = driver->vendor_id;
+			isa->dev.desc.device = driver->prod_id;
+			isa->dev.parent = &rootdev->dev;
+			list_add ( &isa->dev.siblings,
+				   &rootdev->dev.children );
+			INIT_LIST_HEAD ( &isa->dev.children );
+
+			/* Try probing at this I/O address */
+			if ( isa_probe ( isa ) == 0 ) {
+				/* isadev registered, we can drop our ref */
+				isa = NULL;
+			} else {
+				/* Not registered; re-use struct */
+				list_del ( &isa->dev.siblings );
+			}
+		}
+	}
+
+	free ( isa );
+	return 0;
+
+ err:
+	free ( isa );
+	isabus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove ISA root bus
+ *
+ * @v rootdev		ISA bus root device
+ */
+static void isabus_remove ( struct root_device *rootdev ) {
+	struct isa_device *isa;
+	struct isa_device *tmp;
+
+	list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		isa_remove ( isa );
+		list_del ( &isa->dev.siblings );
+		free ( isa );
+	}
+}
+
+/** ISA bus root device driver */
+static struct root_driver isa_root_driver = {
+	.probe = isabus_probe,
+	.remove = isabus_remove,
+};
+
+/** ISA bus root device */
+struct root_device isa_root_device __root_device = {
+	.dev = { .name = "ISA" },
+	.driver = &isa_root_driver,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa_ids.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa_ids.c
new file mode 100644
index 0000000..e72b233
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isa_ids.c
@@ -0,0 +1,26 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <ipxe/isa_ids.h>
+
+/* 
+ * EISA and ISAPnP IDs are actually mildly human readable, though in a
+ * somewhat brain-damaged way.
+ *
+ */
+char * isa_id_string ( unsigned int vendor, unsigned int product ) {
+	static char buf[7];
+	int i;
+
+	/* Vendor ID is a compressed ASCII string */
+	vendor = bswap_16 ( vendor );
+	for ( i = 2 ; i >= 0 ; i-- ) {
+		buf[i] = ( 'A' - 1 + ( vendor & 0x1f ) );
+		vendor >>= 5;
+	}
+	
+	/* Product ID is a 4-digit hex string */
+	sprintf ( &buf[3], "%04x", bswap_16 ( product ) );
+
+	return buf;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/isapnp.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isapnp.c
new file mode 100644
index 0000000..f7845d3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/isapnp.c
@@ -0,0 +1,755 @@
+/**************************************************************************
+*
+*    isapnp.c -- Etherboot isapnp support for the 3Com 3c515
+*    Written 2002-2003 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code:
+*	Copyright (C) 2001  P.J.H.Fox (fox at roestock.demon.co.uk)
+*
+*
+*    REVISION HISTORY:
+*    ================
+*    Version 0.1 April 26, 2002 TJL
+*    Version 0.2 01/08/2003	TJL Moved outside the 3c515.c driver file
+*    Version 0.3 Sept 23, 2003	timlegge Change delay to currticks
+*		
+*
+*    Generalised into an ISAPnP bus that can be used by more than just
+*    the 3c515 by Michael Brown <mbrown at fensystems.co.uk>
+*
+***************************************************************************/
+
+/** @file
+ *
+ * ISAPnP bus support
+ *
+ * Etherboot orignally gained ISAPnP support in a very limited way for
+ * the 3c515 NIC.  The current implementation is almost a complete
+ * rewrite based on the ISAPnP specification, with passing reference
+ * to the Linux ISAPnP code.
+ *
+ * There can be only one ISAPnP bus in a system.  Once the read port
+ * is known and all cards have been allocated CSNs, there's nothing to
+ * be gained by re-scanning for cards.
+ *
+ * External code (e.g. the ISAPnP ROM prefix) may already know the
+ * read port address, in which case it can store it in
+ * #isapnp_read_port.  Note that setting the read port address in this
+ * way will prevent further isolation from taking place; you should
+ * set the read port address only if you know that devices have
+ * already been allocated CSNs.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <unistd.h>
+#include <ipxe/isapnp.h>
+
+/**
+ * ISAPnP Read Port address.
+ *
+ * ROM prefix may be able to set this address, which is why this is
+ * non-static.
+ */
+uint16_t isapnp_read_port;
+
+static void isapnpbus_remove ( struct root_device *rootdev );
+
+/*
+ * ISAPnP utility functions
+ *
+ */
+
+#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
+#define ISAPNP_CARD_ID_DATA(identifier)					  \
+	(identifier)->vendor_id, (identifier)->prod_id,			  \
+	isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
+	(identifier)->serial
+#define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")"
+#define ISAPNP_DEV_ID_DATA(isapnp)					  \
+	(isapnp)->vendor_id, (isapnp)->prod_id,				  \
+	isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id )
+
+static inline void isapnp_write_address ( unsigned int address ) {
+	outb ( address, ISAPNP_ADDRESS );
+}
+
+static inline void isapnp_write_data ( unsigned int data ) {
+	outb ( data, ISAPNP_WRITE_DATA );
+}
+
+static inline unsigned int isapnp_read_data ( void ) {
+	return inb ( isapnp_read_port );
+}
+
+static inline void isapnp_write_byte ( unsigned int address,
+				       unsigned int value ) {
+	isapnp_write_address ( address );
+	isapnp_write_data ( value );
+}
+
+static inline unsigned int isapnp_read_byte ( unsigned int address ) {
+	isapnp_write_address ( address );
+	return isapnp_read_data ();
+}
+
+static inline unsigned int isapnp_read_word ( unsigned int address ) {
+	/* Yes, they're in big-endian order */
+	return ( ( isapnp_read_byte ( address ) << 8 )
+		 | isapnp_read_byte ( address + 1 ) );
+}
+
+/** Inform cards of a new read port address */
+static inline void isapnp_set_read_port ( void ) {
+	isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) );
+}
+
+/**
+ * Enter the Isolation state.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ */
+static inline void isapnp_serialisolation ( void ) {
+	isapnp_write_address ( ISAPNP_SERIALISOLATION );
+}
+
+/**
+ * Enter the Wait for Key state.
+ *
+ * All cards will respond to this command, regardless of their current
+ * state.
+ */
+static inline void isapnp_wait_for_key ( void ) {
+	isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
+}
+
+/**
+ * Reset (i.e. remove) Card Select Number.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ */
+static inline void isapnp_reset_csn ( void ) {
+	isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
+}
+
+/**
+ * Place a specified card into the Config state.
+ *
+ * @v csn		Card Select Number
+ * @ret None		-
+ * @err None		-
+ *
+ * Only cards currently in the Sleep, Isolation, or Config states will
+ * respond to this command.  The card that has the specified CSN will
+ * enter the Config state, all other cards will enter the Sleep state.
+ */
+static inline void isapnp_wake ( uint8_t csn ) {
+	isapnp_write_byte ( ISAPNP_WAKE, csn );
+}
+
+static inline unsigned int isapnp_read_resourcedata ( void ) {
+	return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
+}
+
+static inline unsigned int isapnp_read_status ( void ) {
+	return isapnp_read_byte ( ISAPNP_STATUS );
+}
+
+/**
+ * Assign a Card Select Number to a card, and enter the Config state.
+ *
+ * @v csn		Card Select Number
+ *
+ * Only cards in the Isolation state will respond to this command.
+ * The isolation protocol is designed so that only one card will
+ * remain in the Isolation state by the time the isolation protocol
+ * completes.
+ */
+static inline void isapnp_write_csn ( unsigned int csn ) {
+	isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
+}
+
+static inline void isapnp_logicaldevice ( unsigned int logdev ) {
+	isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
+}
+
+static inline void isapnp_activate ( unsigned int logdev ) {
+	isapnp_logicaldevice ( logdev );
+	isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
+}
+
+static inline void isapnp_deactivate ( unsigned int logdev ) {
+	isapnp_logicaldevice ( logdev );
+	isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
+}
+
+static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
+	return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
+}
+
+static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
+	return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
+}
+
+static void isapnp_delay ( void ) {
+	udelay ( 1000 );
+}
+
+/**
+ * Linear feedback shift register.
+ *
+ * @v lfsr		Current value of the LFSR
+ * @v input_bit		Current input bit to the LFSR
+ * @ret lfsr		Next value of the LFSR
+ *
+ * This routine implements the linear feedback shift register as
+ * described in Appendix B of the PnP ISA spec.  The hardware
+ * implementation uses eight D-type latches and two XOR gates.  I
+ * think this is probably the smallest possible implementation in
+ * software.  Six instructions when input_bit is a constant 0 (for
+ * isapnp_send_key).  :)
+ */
+static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr,
+					      unsigned int input_bit ) {
+	register uint8_t lfsr_next;
+
+	lfsr_next = lfsr >> 1;
+	lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
+	return lfsr_next;
+}
+
+/**
+ * Send the ISAPnP initiation key.
+ *
+ * Sending the key causes all ISAPnP cards that are currently in the
+ * Wait for Key state to transition into the Sleep state.
+ */
+static void isapnp_send_key ( void ) {
+	unsigned int i;
+	unsigned int lfsr;
+
+	isapnp_delay();
+	isapnp_write_address ( 0x00 );
+	isapnp_write_address ( 0x00 );
+
+	lfsr = ISAPNP_LFSR_SEED;
+	for ( i = 0 ; i < 32 ; i++ ) {
+		isapnp_write_address ( lfsr );
+		lfsr = isapnp_lfsr_next ( lfsr, 0 );
+	}
+}
+
+/**
+ * Compute ISAPnP identifier checksum
+ *
+ * @v identifier	ISAPnP identifier
+ * @ret checksum	Expected checksum value
+ */
+static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) {
+	unsigned int i, j;
+	unsigned int lfsr;
+	unsigned int byte;
+
+	lfsr = ISAPNP_LFSR_SEED;
+	for ( i = 0 ; i < 8 ; i++ ) {
+		byte = * ( ( ( uint8_t * ) identifier ) + i );
+		for ( j = 0 ; j < 8 ; j++ ) {
+			lfsr = isapnp_lfsr_next ( lfsr, byte );
+			byte >>= 1;
+		}
+	}
+	return lfsr;
+}
+
+/*
+ * Read a byte of resource data from the current location
+ *
+ * @ret byte		Byte of resource data
+ */
+static inline unsigned int isapnp_peek_byte ( void ) {
+	unsigned int i;
+
+	/* Wait for data to be ready */
+	for ( i = 0 ; i < 20 ; i++ ) {
+		if ( isapnp_read_status() & 0x01 ) {
+			/* Byte ready - read it */
+			return isapnp_read_resourcedata();
+		}
+		isapnp_delay();
+	}
+	/* Data never became ready - return 0xff */
+	return 0xff;
+}
+
+/**
+ * Read resource data.
+ *
+ * @v buf		Buffer in which to store data, or NULL
+ * @v bytes		Number of bytes to read
+ *
+ * Resource data is read from the current location.  If #buf is NULL,
+ * the data is discarded.
+ */
+static void isapnp_peek ( void *buf, size_t len ) {
+	unsigned int i;
+	unsigned int byte;
+
+	for ( i = 0 ; i < len ; i++) {
+		byte = isapnp_peek_byte();
+		if ( buf )
+			* ( ( uint8_t * ) buf + i ) = byte;
+	}
+}
+
+/**
+ * Find a tag within the resource data.
+ *
+ * @v wanted_tag	The tag that we're looking for
+ * @v buf		Buffer in which to store the tag's contents
+ * @v len		Length of buffer
+ * @ret rc		Return status code
+ *
+ * Scan through the resource data until we find a particular tag, and
+ * read its contents into a buffer.
+ */
+static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) {
+	unsigned int tag;
+	unsigned int tag_len;
+
+	DBG2 ( "ISAPnP read tag" );
+	do {
+		tag = isapnp_peek_byte();
+		if ( ISAPNP_IS_SMALL_TAG ( tag ) ) {
+			tag_len = ISAPNP_SMALL_TAG_LEN ( tag );
+			tag = ISAPNP_SMALL_TAG_NAME ( tag );
+		} else {
+			tag_len = ( isapnp_peek_byte() +
+				    ( isapnp_peek_byte() << 8 ) );
+			tag = ISAPNP_LARGE_TAG_NAME ( tag );
+		}
+		DBG2 ( " %02x (%02x)", tag, tag_len );
+		if ( tag == wanted_tag ) {
+			if ( len > tag_len )
+				len = tag_len;
+			isapnp_peek ( buf, len );
+			DBG2 ( "\n" );
+			return 0;
+		} else {
+			isapnp_peek ( NULL, tag_len );
+		}
+	} while ( tag != ISAPNP_TAG_END );
+	DBG2 ( "\n" );
+	return -ENOENT;
+}
+
+/**
+ * Find specified Logical Device ID tag
+ *
+ * @v logdev		Logical device ID
+ * @v logdevid		Logical device ID structure to fill in
+ * @ret rc		Return status code
+ */
+static int isapnp_find_logdevid ( unsigned int logdev,
+				  struct isapnp_logdevid *logdevid ) {
+	unsigned int i;
+	int rc;
+
+	for ( i = 0 ; i <= logdev ; i++ ) {
+		if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid,
+					      sizeof ( *logdevid ) ) ) != 0 )
+			return rc;
+	}
+	return 0;
+}
+
+/**
+ * Try isolating ISAPnP cards at the current read port.
+ *
+ * @ret \>0		Number of ISAPnP cards found
+ * @ret 0		There are no ISAPnP cards in the system
+ * @ret \<0		A conflict was detected; try a new read port
+ * @err None		-
+ *
+ * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
+ * gives the best overview of what happens here.
+ */
+static int isapnp_try_isolate ( void ) {
+	struct isapnp_identifier identifier;
+	unsigned int i, j;
+	unsigned int seen_55aa, seen_life;
+	unsigned int csn = 0;
+	unsigned int data;
+	unsigned int byte;
+
+	DBG ( "ISAPnP attempting isolation at read port %04x\n",
+	      isapnp_read_port );
+
+	/* Place all cards into the Sleep state, whatever state
+	 * they're currently in.
+	 */
+	isapnp_wait_for_key();
+	isapnp_send_key();
+
+	/* Reset all assigned CSNs */
+	isapnp_reset_csn();
+	isapnp_delay();
+	isapnp_delay();
+	
+	/* Place all cards into the Isolation state */
+	isapnp_wait_for_key ();
+	isapnp_send_key();
+	isapnp_wake ( 0x00 );
+	
+	/* Set the read port */
+	isapnp_set_read_port();
+	isapnp_delay();
+
+	while ( 1 ) {
+
+		/* All cards that do not have assigned CSNs are
+		 * currently in the Isolation state, each time we go
+		 * through this loop.
+		 */
+
+		/* Initiate serial isolation */
+		isapnp_serialisolation();
+		isapnp_delay();
+
+		/* Read identifier serially via the ISAPnP read port. */
+		memset ( &identifier, 0, sizeof ( identifier ) );
+		seen_55aa = seen_life = 0;
+		for ( i = 0 ; i < 9 ; i++ ) {
+			byte = 0;
+			for ( j = 0 ; j < 8 ; j++ ) {
+				data = isapnp_read_data();
+				isapnp_delay();
+				data = ( ( data << 8 ) | isapnp_read_data() );
+				isapnp_delay();
+				byte >>= 1;
+				if (  data != 0xffff ) {
+					seen_life++;
+					if ( data == 0x55aa ) {
+						byte |= 0x80;
+						seen_55aa++;
+					}
+				}
+			}
+			*( ( ( uint8_t * ) &identifier ) + i ) = byte;
+		}
+
+		/* If we didn't see any 55aa patterns, stop here */
+		if ( ! seen_55aa ) {
+			if ( csn ) {
+				DBG ( "ISAPnP found no more cards\n" );
+			} else {
+				if ( seen_life ) {
+					DBG ( "ISAPnP saw life but no cards, "
+					      "trying new read port\n" );
+					csn = -1;
+				} else {
+					DBG ( "ISAPnP saw no signs of life, "
+					      "abandoning isolation\n" );
+				}
+			}
+			break;
+		}
+
+		/* If the checksum was invalid stop here */
+		if ( identifier.checksum != isapnp_checksum ( &identifier) ) {
+			DBG ( "ISAPnP found malformed card "
+			      ISAPNP_CARD_ID_FMT "\n  with checksum %02x "
+			      "(should be %02x), trying new read port\n",
+			      ISAPNP_CARD_ID_DATA ( &identifier ),
+			      identifier.checksum,
+			      isapnp_checksum ( &identifier) );
+			csn = -1;
+			break;
+		}
+
+		/* Give the device a CSN */
+		csn++;
+		DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT
+		      ", assigning CSN %02x\n",
+		      ISAPNP_CARD_ID_DATA ( &identifier ), csn );
+		
+		isapnp_write_csn ( csn );
+		isapnp_delay();
+
+		/* Send this card back to Sleep and force all cards
+		 * without a CSN into Isolation state
+		 */
+		isapnp_wake ( 0x00 );
+		isapnp_delay();
+	}
+
+	/* Place all cards in Wait for Key state */
+	isapnp_wait_for_key();
+
+	/* Return number of cards found */
+	if ( csn > 0 ) {
+		DBG ( "ISAPnP found %d cards at read port %04x\n",
+		      csn, isapnp_read_port );
+	}
+	return csn;
+}
+
+/**
+ * Find a valid read port and isolate all ISAPnP cards.
+ *
+ */
+static void isapnp_isolate ( void ) {
+	for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
+	      isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
+	      isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
+		/* Avoid problematic locations such as the NE2000
+		 * probe space
+		 */
+		if ( ( isapnp_read_port >= 0x280 ) &&
+		     ( isapnp_read_port <= 0x380 ) )
+			continue;
+		
+		/* If we detect any ISAPnP cards at this location, stop */
+		if ( isapnp_try_isolate() >= 0 )
+			return;
+	}
+}
+
+/**
+ * Activate or deactivate an ISAPnP device.
+ *
+ * @v isapnp		ISAPnP device
+ * @v activation	True to enable, False to disable the device
+ * @ret None		-
+ * @err None		-
+ *
+ * This routine simply activates the device in its current
+ * configuration, or deactivates the device.  It does not attempt any
+ * kind of resource arbitration.
+ *
+ */
+void isapnp_device_activation ( struct isapnp_device *isapnp,
+				int activation ) {
+	/* Wake the card and select the logical device */
+	isapnp_wait_for_key ();
+	isapnp_send_key ();
+	isapnp_wake ( isapnp->csn );
+	isapnp_logicaldevice ( isapnp->logdev );
+
+	/* Activate/deactivate the logical device */
+	isapnp_activate ( activation );
+	isapnp_delay();
+
+	/* Return all cards to Wait for Key state */
+	isapnp_wait_for_key ();
+
+	DBG ( "ISAPnP %s device %02x:%02x\n",
+	      ( activation ? "activated" : "deactivated" ),
+	      isapnp->csn, isapnp->logdev );
+}
+
+/**
+ * Probe an ISAPnP device
+ *
+ * @v isapnp		ISAPnP device
+ * @ret rc		Return status code
+ *
+ * Searches for a driver for the ISAPnP device.  If a driver is found,
+ * its probe() routine is called.
+ */
+static int isapnp_probe ( struct isapnp_device *isapnp ) {
+	struct isapnp_driver *driver;
+	struct isapnp_device_id *id;
+	unsigned int i;
+	int rc;
+
+	DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") "
+	      "io %x irq %d)\n", isapnp->csn, isapnp->logdev,
+	      isapnp->vendor_id, isapnp->prod_id,
+	      isa_id_string ( isapnp->vendor_id, isapnp->prod_id ),
+	      isapnp->ioaddr, isapnp->irqno );
+
+	for_each_table_entry ( driver, ISAPNP_DRIVERS ) {
+		for ( i = 0 ; i < driver->id_count ; i++ ) {
+			id = &driver->ids[i];
+			if ( id->vendor_id != isapnp->vendor_id )
+				continue;
+			if ( ISA_PROD_ID ( id->prod_id ) !=
+			     ISA_PROD_ID ( isapnp->prod_id ) )
+				continue;
+			isapnp->driver = driver;
+			isapnp->dev.driver_name = id->name;
+			DBG ( "...using driver %s\n", isapnp->dev.driver_name );
+			if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) {
+				DBG ( "......probe failed\n" );
+				continue;
+			}
+			return 0;
+		}
+	}
+
+	DBG ( "...no driver found\n" );
+	return -ENOTTY;
+}
+
+/**
+ * Remove an ISAPnP device
+ *
+ * @v isapnp		ISAPnP device
+ */
+static void isapnp_remove ( struct isapnp_device *isapnp ) {
+	isapnp->driver->remove ( isapnp );
+	DBG ( "Removed ISAPnP device %02x:%02x\n",
+	      isapnp->csn, isapnp->logdev );
+}
+
+/**
+ * Probe ISAPnP root bus
+ *
+ * @v rootdev		ISAPnP bus root device
+ *
+ * Scans the ISAPnP bus for devices and registers all devices it can
+ * find.
+ */
+static int isapnpbus_probe ( struct root_device *rootdev ) {
+	struct isapnp_device *isapnp = NULL;
+	struct isapnp_identifier identifier;
+	struct isapnp_logdevid logdevid;
+	unsigned int csn;
+	unsigned int logdev;
+	int rc;
+
+	/* Perform isolation if it hasn't yet been done */
+	if ( ! isapnp_read_port )
+		isapnp_isolate();
+
+	for ( csn = 1 ; csn <= 0xff ; csn++ ) {
+		for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) {
+
+			/* Allocate struct isapnp_device */
+			if ( ! isapnp )
+				isapnp = malloc ( sizeof ( *isapnp ) );
+			if ( ! isapnp ) {
+				rc = -ENOMEM;
+				goto err;
+			}
+			memset ( isapnp, 0, sizeof ( *isapnp ) );
+			isapnp->csn = csn;
+			isapnp->logdev = logdev;
+
+			/* Wake the card */
+			isapnp_wait_for_key();
+			isapnp_send_key();
+			isapnp_wake ( csn );
+
+			/* Read the card identifier */
+			isapnp_peek ( &identifier, sizeof ( identifier ) );
+			
+			/* No card with this CSN; stop here */
+			if ( identifier.vendor_id & 0x80 )
+				goto done;
+
+			/* Find the Logical Device ID tag */
+			if ( ( rc = isapnp_find_logdevid ( logdev,
+							   &logdevid ) ) != 0){
+				/* No more logical devices; go to next CSN */
+				break;
+			}
+			
+			/* Select the logical device */
+			isapnp_logicaldevice ( logdev );
+
+			/* Populate struct isapnp_device */
+			isapnp->vendor_id = logdevid.vendor_id;
+			isapnp->prod_id = logdevid.prod_id;
+			isapnp->ioaddr = isapnp_read_iobase ( 0 );
+			isapnp->irqno = isapnp_read_irqno ( 0 );
+
+			/* Return all cards to Wait for Key state */
+			isapnp_wait_for_key();
+
+			/* Add to device hierarchy */
+			snprintf ( isapnp->dev.name,
+				   sizeof ( isapnp->dev.name ),
+				   "ISAPnP%02x:%02x", csn, logdev );
+			isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP;
+			isapnp->dev.desc.vendor = isapnp->vendor_id;
+			isapnp->dev.desc.device = isapnp->prod_id;
+			isapnp->dev.desc.ioaddr = isapnp->ioaddr;
+			isapnp->dev.desc.irq = isapnp->irqno;
+			isapnp->dev.parent = &rootdev->dev;
+			list_add ( &isapnp->dev.siblings,
+				   &rootdev->dev.children );
+			INIT_LIST_HEAD ( &isapnp->dev.children );
+			
+			/* Look for a driver */
+			if ( isapnp_probe ( isapnp ) == 0 ) {
+				/* isapnpdev registered, we can drop our ref */
+				isapnp = NULL;
+			} else {
+				/* Not registered; re-use struct */
+				list_del ( &isapnp->dev.siblings );
+			}
+		}
+	}
+
+ done:
+	free ( isapnp );
+	return 0;
+
+ err:
+	free ( isapnp );
+	isapnpbus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove ISAPnP root bus
+ *
+ * @v rootdev		ISAPnP bus root device
+ */
+static void isapnpbus_remove ( struct root_device *rootdev ) {
+	struct isapnp_device *isapnp;
+	struct isapnp_device *tmp;
+
+	list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		isapnp_remove ( isapnp );
+		list_del ( &isapnp->dev.siblings );
+		free ( isapnp );
+	}
+}
+
+/** ISAPnP bus root device driver */
+static struct root_driver isapnp_root_driver = {
+	.probe = isapnpbus_probe,
+	.remove = isapnpbus_remove,
+};
+
+/** ISAPnP bus root device */
+struct root_device isapnp_root_device __root_device = {
+	.dev = { .name = "ISAPnP" },
+	.driver = &isapnp_root_driver,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/mca.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/mca.c
new file mode 100644
index 0000000..0405c3b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/mca.c
@@ -0,0 +1,177 @@
+/*
+ * MCA bus driver code
+ *
+ * Abstracted from 3c509.c.
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <ipxe/mca.h>
+
+static void mcabus_remove ( struct root_device *rootdev );
+
+/**
+ * Probe an MCA device
+ *
+ * @v mca		MCA device
+ * @ret rc		Return status code
+ *
+ * Searches for a driver for the MCA device.  If a driver is found,
+ * its probe() routine is called.
+ */
+static int mca_probe ( struct mca_device *mca ) {
+	struct mca_driver *driver;
+	struct mca_device_id *id;
+	unsigned int i;
+	int rc;
+
+	DBG ( "Adding MCA slot %02x (ID %04x POS "
+	      "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)\n",
+	      mca->slot, MCA_ID ( mca ),
+	      mca->pos[0], mca->pos[1], mca->pos[2], mca->pos[3],
+	      mca->pos[4], mca->pos[5], mca->pos[6], mca->pos[7] );
+
+	for_each_table_entry ( driver, MCA_DRIVERS ) {
+		for ( i = 0 ; i < driver->id_count ; i++ ) {
+			id = &driver->ids[i];
+			if ( id->id != MCA_ID ( mca ) )
+				continue;
+			mca->driver = driver;
+			mca->dev.driver_name = id->name;
+			DBG ( "...using driver %s\n", mca->dev.driver_name );
+			if ( ( rc = driver->probe ( mca, id ) ) != 0 ) {
+				DBG ( "......probe failed\n" );
+				continue;
+			}
+			return 0;
+		}
+	}
+
+	DBG ( "...no driver found\n" );
+	return -ENOTTY;
+}
+
+/**
+ * Remove an MCA device
+ *
+ * @v mca		MCA device
+ */
+static void mca_remove ( struct mca_device *mca ) {
+	mca->driver->remove ( mca );
+	DBG ( "Removed MCA device %02x\n", mca->slot );
+}
+
+/**
+ * Probe MCA root bus
+ *
+ * @v rootdev		MCA bus root device
+ *
+ * Scans the MCA bus for devices and registers all devices it can
+ * find.
+ */
+static int mcabus_probe ( struct root_device *rootdev ) {
+	struct mca_device *mca = NULL;
+	unsigned int slot;
+	int seen_non_ff;
+	unsigned int i;
+	int rc;
+
+	for ( slot = 0 ; slot <= MCA_MAX_SLOT_NR ; slot++ ) {
+		/* Allocate struct mca_device */
+		if ( ! mca )
+			mca = malloc ( sizeof ( *mca ) );
+		if ( ! mca ) {
+			rc = -ENOMEM;
+			goto err;
+		}
+		memset ( mca, 0, sizeof ( *mca ) );
+		mca->slot = slot;
+
+		/* Make sure motherboard setup is off */
+		outb_p ( 0xff, MCA_MOTHERBOARD_SETUP_REG );
+
+		/* Select the slot */
+		outb_p ( 0x8 | ( mca->slot & 0xf ), MCA_ADAPTER_SETUP_REG );
+
+		/* Read the POS registers */
+		seen_non_ff = 0;
+		for ( i = 0 ; i < ( sizeof ( mca->pos ) /
+				    sizeof ( mca->pos[0] ) ) ; i++ ) {
+			mca->pos[i] = inb_p ( MCA_POS_REG ( i ) );
+			if ( mca->pos[i] != 0xff )
+				seen_non_ff = 1;
+		}
+	
+		/* Kill all setup modes */
+		outb_p ( 0, MCA_ADAPTER_SETUP_REG );
+
+		/* If all POS registers are 0xff, this means there's no device
+		 * present
+		 */
+		if ( ! seen_non_ff )
+			continue;
+
+		/* Add to device hierarchy */
+		snprintf ( mca->dev.name, sizeof ( mca->dev.name ),
+			   "MCA%02x", slot );
+		mca->dev.desc.bus_type = BUS_TYPE_MCA;
+		mca->dev.desc.vendor = GENERIC_MCA_VENDOR;
+		mca->dev.desc.device = MCA_ID ( mca );
+		mca->dev.parent = &rootdev->dev;
+		list_add ( &mca->dev.siblings, &rootdev->dev.children );
+		INIT_LIST_HEAD ( &mca->dev.children );
+
+		/* Look for a driver */
+		if ( mca_probe ( mca ) == 0 ) {
+			/* mcadev registered, we can drop our ref */
+			mca = NULL;
+		} else {
+			/* Not registered; re-use struct */
+			list_del ( &mca->dev.siblings );
+		}
+	}
+
+	free ( mca );
+	return 0;
+
+ err:
+	free ( mca );
+	mcabus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove MCA root bus
+ *
+ * @v rootdev		MCA bus root device
+ */
+static void mcabus_remove ( struct root_device *rootdev ) {
+	struct mca_device *mca;
+	struct mca_device *tmp;
+
+	list_for_each_entry_safe ( mca, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		mca_remove ( mca );
+		list_del ( &mca->dev.siblings );
+		free ( mca );
+	}
+}
+
+/** MCA bus root device driver */
+static struct root_driver mca_root_driver = {
+	.probe = mcabus_probe,
+	.remove = mcabus_remove,
+};
+
+/** MCA bus root device */
+struct root_device mca_root_device __root_device = {
+	.dev = { .name = "MCA" },
+	.driver = &mca_root_driver,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/pci.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pci.c
new file mode 100644
index 0000000..3ae17e5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pci.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * Based in part on pci.c from Etherboot 5.4, by Ken Yap and David
+ * Munro, in turn based on the Linux kernel's PCI implementation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/tables.h>
+#include <ipxe/device.h>
+#include <ipxe/pci.h>
+
+/** @file
+ *
+ * PCI bus
+ *
+ */
+
+static void pcibus_remove ( struct root_device *rootdev );
+
+/**
+ * Read PCI BAR
+ *
+ * @v pci		PCI device
+ * @v reg		PCI register number
+ * @ret bar		Base address register
+ *
+ * Reads the specified PCI base address register, including the flags
+ * portion.  64-bit BARs will be handled automatically.  If the value
+ * of the 64-bit BAR exceeds the size of an unsigned long (i.e. if the
+ * high dword is non-zero on a 32-bit platform), then the value
+ * returned will be zero plus the flags for a 64-bit BAR.  Unreachable
+ * 64-bit BARs are therefore returned as uninitialised 64-bit BARs.
+ */
+static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) {
+	uint32_t low;
+	uint32_t high;
+
+	pci_read_config_dword ( pci, reg, &low );
+	if ( ( low & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK) )
+	     == (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64) ){
+		pci_read_config_dword ( pci, reg + 4, &high );
+		if ( high ) {
+			if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
+				return ( ( ( uint64_t ) high << 32 ) | low );
+			} else {
+				DBGC ( pci, PCI_FMT " unhandled 64-bit BAR "
+				       "%08x%08x\n",
+				       PCI_ARGS ( pci ), high, low );
+				return PCI_BASE_ADDRESS_MEM_TYPE_64;
+			}
+		}
+	}
+	return low;
+}
+
+/**
+ * Find the start of a PCI BAR
+ *
+ * @v pci		PCI device
+ * @v reg		PCI register number
+ * @ret start		BAR start address
+ *
+ * Reads the specified PCI base address register, and returns the
+ * address portion of the BAR (i.e. without the flags).
+ *
+ * If the address exceeds the size of an unsigned long (i.e. if a
+ * 64-bit BAR has a non-zero high dword on a 32-bit machine), the
+ * return value will be zero.
+ */
+unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ) {
+	unsigned long bar;
+
+	bar = pci_bar ( pci, reg );
+	if ( (bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY ){
+		return ( bar & PCI_BASE_ADDRESS_MEM_MASK );
+	} else {
+		return ( bar & PCI_BASE_ADDRESS_IO_MASK );
+	}
+}
+
+/**
+ * Read membase and ioaddr for a PCI device
+ *
+ * @v pci		PCI device
+ *
+ * This scans through all PCI BARs on the specified device.  The first
+ * valid memory BAR is recorded as pci_device::membase, and the first
+ * valid IO BAR is recorded as pci_device::ioaddr.
+ *
+ * 64-bit BARs are handled automatically.  On a 32-bit platform, if a
+ * 64-bit BAR has a non-zero high dword, it will be regarded as
+ * invalid.
+ */
+static void pci_read_bases ( struct pci_device *pci ) {
+	unsigned long bar;
+	int reg;
+
+	for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
+		bar = pci_bar ( pci, reg );
+		if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
+			if ( ! pci->ioaddr )
+				pci->ioaddr = 
+					( bar & PCI_BASE_ADDRESS_IO_MASK );
+		} else {
+			if ( ! pci->membase )
+				pci->membase =
+					( bar & PCI_BASE_ADDRESS_MEM_MASK );
+			/* Skip next BAR if 64-bit */
+			if ( bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
+				reg += 4;
+		}
+	}
+}
+
+/**
+ * Enable PCI device
+ *
+ * @v pci		PCI device
+ *
+ * Set device to be a busmaster in case BIOS neglected to do so.  Also
+ * adjust PCI latency timer to a reasonable value, 32.
+ */
+void adjust_pci_device ( struct pci_device *pci ) {
+	unsigned short new_command, pci_command;
+	unsigned char pci_latency;
+
+	pci_read_config_word ( pci, PCI_COMMAND, &pci_command );
+	new_command = ( pci_command | PCI_COMMAND_MASTER |
+			PCI_COMMAND_MEM | PCI_COMMAND_IO );
+	if ( pci_command != new_command ) {
+		DBGC ( pci, PCI_FMT " device not enabled by BIOS! Updating "
+		       "PCI command %04x->%04x\n",
+		       PCI_ARGS ( pci ), pci_command, new_command );
+		pci_write_config_word ( pci, PCI_COMMAND, new_command );
+	}
+
+	pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency);
+	if ( pci_latency < 32 ) {
+		DBGC ( pci, PCI_FMT " latency timer is unreasonably low at "
+		       "%d. Setting to 32.\n", PCI_ARGS ( pci ), pci_latency );
+		pci_write_config_byte ( pci, PCI_LATENCY_TIMER, 32);
+	}
+}
+
+/**
+ * Read PCI device configuration
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+int pci_read_config ( struct pci_device *pci ) {
+	uint32_t tmp;
+
+	/* Check for physical device presence */
+	pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
+	if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
+		return -ENODEV;
+
+	/* Populate struct pci_device */
+	pci->vendor = ( tmp & 0xffff );
+	pci->device = ( tmp >> 16 );
+	pci_read_config_dword ( pci, PCI_REVISION, &tmp );
+	pci->class = ( tmp >> 8 );
+	pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
+	pci_read_bases ( pci );
+
+	/* Initialise generic device component */
+	snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
+		   "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ),
+		   PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
+	pci->dev.desc.bus_type = BUS_TYPE_PCI;
+	pci->dev.desc.location = pci->busdevfn;
+	pci->dev.desc.vendor = pci->vendor;
+	pci->dev.desc.device = pci->device;
+	pci->dev.desc.class = pci->class;
+	pci->dev.desc.ioaddr = pci->ioaddr;
+	pci->dev.desc.irq = pci->irq;
+	INIT_LIST_HEAD ( &pci->dev.siblings );
+	INIT_LIST_HEAD ( &pci->dev.children );
+
+	return 0;
+}
+
+/**
+ * Find driver for PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+int pci_find_driver ( struct pci_device *pci ) {
+	struct pci_driver *driver;
+	struct pci_device_id *id;
+	unsigned int i;
+
+	for_each_table_entry ( driver, PCI_DRIVERS ) {
+		for ( i = 0 ; i < driver->id_count ; i++ ) {
+			id = &driver->ids[i];
+			if ( ( id->vendor != PCI_ANY_ID ) &&
+			     ( id->vendor != pci->vendor ) )
+				continue;
+			if ( ( id->device != PCI_ANY_ID ) &&
+			     ( id->device != pci->device ) )
+				continue;
+			pci_set_driver ( pci, driver, id );
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * Probe a PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ *
+ * Searches for a driver for the PCI device.  If a driver is found,
+ * its probe() routine is called.
+ */
+int pci_probe ( struct pci_device *pci ) {
+	int rc;
+
+	DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n",
+	       PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name );
+	DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n",
+	       PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq );
+
+	if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " probe failed: %s\n",
+		       PCI_ARGS ( pci ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Remove a PCI device
+ *
+ * @v pci		PCI device
+ */
+void pci_remove ( struct pci_device *pci ) {
+	pci->driver->remove ( pci );
+	DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
+}
+
+/**
+ * Probe PCI root bus
+ *
+ * @v rootdev		PCI bus root device
+ *
+ * Scans the PCI bus for devices and registers all devices it can
+ * find.
+ */
+static int pcibus_probe ( struct root_device *rootdev ) {
+	struct pci_device *pci = NULL;
+	unsigned int num_bus;
+	unsigned int busdevfn;
+	uint8_t hdrtype = 0;
+	int rc;
+
+	num_bus = pci_num_bus();
+	for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ;
+	      busdevfn++ ) {
+
+		/* Allocate struct pci_device */
+		if ( ! pci )
+			pci = malloc ( sizeof ( *pci ) );
+		if ( ! pci ) {
+			rc = -ENOMEM;
+			goto err;
+		}
+		memset ( pci, 0, sizeof ( *pci ) );
+		pci_init ( pci, busdevfn );
+			
+		/* Skip all but the first function on
+		 * non-multifunction cards
+		 */
+		if ( PCI_FUNC ( busdevfn ) == 0 ) {
+			pci_read_config_byte ( pci, PCI_HEADER_TYPE,
+					       &hdrtype );
+		} else if ( ! ( hdrtype & 0x80 ) ) {
+			continue;
+		}
+
+		/* Read device configuration */
+		if ( ( rc = pci_read_config ( pci ) ) != 0 )
+			continue;
+
+		/* Look for a driver */
+		if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
+			DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
+			       PCI_ARGS ( pci ), pci->vendor, pci->device );
+			continue;
+		}
+
+		/* Add to device hierarchy */
+		pci->dev.parent = &rootdev->dev;
+		list_add ( &pci->dev.siblings, &rootdev->dev.children);
+
+		/* Look for a driver */
+		if ( ( rc = pci_probe ( pci ) ) == 0 ) {
+			/* pcidev registered, we can drop our ref */
+			pci = NULL;
+		} else {
+			/* Not registered; re-use struct pci_device */
+			list_del ( &pci->dev.siblings );
+		}
+	}
+
+	free ( pci );
+	return 0;
+
+ err:
+	free ( pci );
+	pcibus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove PCI root bus
+ *
+ * @v rootdev		PCI bus root device
+ */
+static void pcibus_remove ( struct root_device *rootdev ) {
+	struct pci_device *pci;
+	struct pci_device *tmp;
+
+	list_for_each_entry_safe ( pci, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		pci_remove ( pci );
+		list_del ( &pci->dev.siblings );
+		free ( pci );
+	}
+}
+
+/** PCI bus root device driver */
+static struct root_driver pci_root_driver = {
+	.probe = pcibus_probe,
+	.remove = pcibus_remove,
+};
+
+/** PCI bus root device */
+struct root_device pci_root_device __root_device = {
+	.dev = { .name = "PCI" },
+	.driver = &pci_root_driver,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcibackup.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcibackup.c
new file mode 100644
index 0000000..6719c53
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcibackup.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/pci.h>
+#include <ipxe/pcibackup.h>
+
+/** @file
+ *
+ * PCI configuration space backup and restoration
+ *
+ */
+
+/**
+ * Check PCI configuration space offset against exclusion list
+ *
+ * @v pci		PCI device
+ * @v offset		Offset within PCI configuration space
+ * @v exclude		PCI configuration space backup exclusion list, or NULL
+ */
+static int
+pci_backup_excluded ( struct pci_device *pci, unsigned int offset,
+		      const uint8_t *exclude ) {
+
+	if ( ! exclude )
+		return 0;
+	for ( ; *exclude != PCI_CONFIG_BACKUP_EXCLUDE_END ; exclude++ ) {
+		if ( offset == *exclude ) {
+			DBGC ( pci, "PCI %p skipping configuration offset "
+			       "%02x\n", pci, offset );
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Back up PCI configuration space
+ *
+ * @v pci		PCI device
+ * @v backup		PCI configuration space backup
+ * @v exclude		PCI configuration space backup exclusion list, or NULL
+ */
+void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup,
+		  const uint8_t *exclude ) {
+	unsigned int offset;
+	uint32_t *dword;
+
+	for ( offset = 0, dword = backup->dwords ; offset < 0x100 ;
+	      offset += sizeof ( *dword ) , dword++ ) {
+		if ( ! pci_backup_excluded ( pci, offset, exclude ) )
+			pci_read_config_dword ( pci, offset, dword );
+	}
+}
+
+/**
+ * Restore PCI configuration space
+ *
+ * @v pci		PCI device
+ * @v backup		PCI configuration space backup
+ * @v exclude		PCI configuration space backup exclusion list, or NULL
+ */
+void pci_restore ( struct pci_device *pci, struct pci_config_backup *backup,
+		   const uint8_t *exclude ) {
+	unsigned int offset;
+	uint32_t *dword;
+
+	for ( offset = 0, dword = backup->dwords ; offset < 0x100 ;
+	      offset += sizeof ( *dword ) , dword++ ) {
+		if ( ! pci_backup_excluded ( pci, offset, exclude ) )
+			pci_write_config_dword ( pci, offset, *dword );
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/pciextra.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pciextra.c
new file mode 100644
index 0000000..c4417e0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pciextra.c
@@ -0,0 +1,86 @@
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/pci.h>
+
+/**
+ * Look for a PCI capability
+ *
+ * @v pci		PCI device to query
+ * @v cap		Capability code
+ * @ret address		Address of capability, or 0 if not found
+ *
+ * Determine whether or not a device supports a given PCI capability.
+ * Returns the address of the requested capability structure within
+ * the device's PCI configuration space, or 0 if the device does not
+ * support it.
+ */
+int pci_find_capability ( struct pci_device *pci, int cap ) {
+	uint16_t status;
+	uint8_t pos, id;
+	uint8_t hdr_type;
+	int ttl = 48;
+
+	pci_read_config_word ( pci, PCI_STATUS, &status );
+	if ( ! ( status & PCI_STATUS_CAP_LIST ) )
+		return 0;
+
+	pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type );
+	switch ( hdr_type & 0x7F ) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+	default:
+		pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos );
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos );
+		break;
+	}
+	while ( ttl-- && pos >= 0x40 ) {
+		pos &= ~3;
+		pci_read_config_byte ( pci, pos + PCI_CAP_LIST_ID, &id );
+		DBG ( "PCI Capability: %d\n", id );
+		if ( id == 0xff )
+			break;
+		if ( id == cap )
+			return pos;
+		pci_read_config_byte ( pci, pos + PCI_CAP_LIST_NEXT, &pos );
+	}
+	return 0;
+}
+
+/**
+ * Find the size of a PCI BAR
+ *
+ * @v pci		PCI device
+ * @v reg		PCI register number
+ * @ret size		BAR size
+ *
+ * It should not be necessary for any Etherboot code to call this
+ * function.
+ */
+unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
+	uint16_t cmd;
+	uint32_t start, size;
+
+	/* Save the original command register */
+	pci_read_config_word ( pci, PCI_COMMAND, &cmd );
+	/* Save the original bar */
+	pci_read_config_dword ( pci, reg, &start );
+	/* Compute which bits can be set */
+	pci_write_config_dword ( pci, reg, ~0 );
+	pci_read_config_dword ( pci, reg, &size );
+	/* Restore the original size */
+	pci_write_config_dword ( pci, reg, start );
+	/* Find the significant bits */
+	/* Restore the original command register. This reenables decoding. */
+	pci_write_config_word ( pci, PCI_COMMAND, cmd );
+	if ( start & PCI_BASE_ADDRESS_SPACE_IO ) {
+		size &= PCI_BASE_ADDRESS_IO_MASK;
+	} else {
+		size &= PCI_BASE_ADDRESS_MEM_MASK;
+	}
+	/* Find the lowest bit set */
+	size = size & ~( size - 1 );
+	return size;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcivpd.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcivpd.c
new file mode 100644
index 0000000..15cf905
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/pcivpd.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/isapnp.h>
+#include <ipxe/pcivpd.h>
+
+/** @file
+ *
+ * PCI Vital Product Data
+ *
+ */
+
+/**
+ * Initialise PCI Vital Product Data
+ *
+ * @v vpd		PCI VPD
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci ) {
+
+	/* Initialise structure */
+	vpd->pci = pci;
+	pci_vpd_invalidate_cache ( vpd );
+
+	/* Locate VPD capability */
+	vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD );
+	if ( ! vpd->cap ) {
+		DBGC ( vpd, PCI_FMT " does not support VPD\n",
+		       PCI_ARGS ( pci ) );
+		return -ENOTTY;
+	}
+
+	DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n",
+	       PCI_ARGS ( pci ), vpd->cap );
+	return 0;
+}
+
+/**
+ * Read one dword of PCI Vital Product Data
+ *
+ * @v vpd		PCI VPD
+ * @v address		Address to read
+ * @ret data		Read data
+ * @ret rc		Return status code
+ */
+static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address,
+				uint32_t *data ) {
+	struct pci_device *pci = vpd->pci;
+	unsigned int cap = vpd->cap;
+	unsigned int retries;
+	uint16_t flag;
+
+	/* Fail if no VPD present */
+	if ( ! cap )
+		return -ENOTTY;
+
+	/* Return cached value, if present */
+	if ( pci_vpd_cache_is_valid ( vpd ) &&
+	     ( vpd->cache.address == address ) ) {
+		*data = vpd->cache.data;
+		return 0;
+	}
+
+	/* Initiate read */
+	pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address );
+
+	/* Wait for read to complete */
+	for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
+
+		/* Check if data is ready */
+		pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
+		if ( flag & PCI_VPD_FLAG ) {
+
+			/* Read data */
+			pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ),
+						data );
+			DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n",
+				PCI_ARGS ( pci ), address, htonl ( *data ) );
+
+			/* Populate cache */
+			vpd->cache.address = address;
+			vpd->cache.data = *data;
+
+			return 0;
+		}
+
+		/* Wait 1ms before retrying */
+		mdelay ( 1 );
+	}
+
+	DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n",
+	       PCI_ARGS ( pci ), address, cap );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Write one dword of PCI Vital Product Data
+ *
+ * @v vpd		PCI VPD
+ * @v address		Address to write
+ * @v data		Data to write
+ * @ret rc		Return status code
+ */
+static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address,
+				 uint32_t data ) {
+	struct pci_device *pci = vpd->pci;
+	unsigned int cap = vpd->cap;
+	unsigned int retries;
+	uint16_t flag;
+
+	/* Fail if no VPD present */
+	if ( ! cap )
+		return -ENOTTY;
+
+	/* Invalidate cache */
+	pci_vpd_invalidate_cache ( vpd );
+
+	DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n",
+		PCI_ARGS ( pci ), address, htonl ( data ) );
+
+	/* Write data */
+	pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data );
+
+	/* Initiate write */
+	pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ),
+				( address | PCI_VPD_FLAG ) );
+
+	/* Wait for write to complete */
+	for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
+
+		/* Check if write has completed */
+		pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
+		if ( ! ( flag & PCI_VPD_FLAG ) )
+			return 0;
+
+		/* Wait 1ms before retrying */
+		mdelay ( 1 );
+	}
+
+	DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n",
+	       PCI_ARGS ( pci ), address, cap );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Read PCI VPD
+ *
+ * @v vpd		PCI VPD
+ * @v address		Starting address
+ * @v buf		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address, void *buf,
+		   size_t len ) {
+	uint8_t *bytes = buf;
+	uint32_t data;
+	size_t skip_len;
+	unsigned int i;
+	int rc;
+
+	/* Calculate length to skip at start of data */
+	skip_len = ( address & 0x03 );
+
+	/* Read data, a dword at a time */
+	for ( address &= ~0x03 ; len ; address += 4 ) {
+
+		/* Read whole dword */
+		if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 )
+			return rc;
+
+		/* Copy data to buffer */
+		for ( i = 4 ; i ; i-- ) {
+			if ( skip_len ) {
+				skip_len--;
+			} else if ( len ) {
+				*(bytes++) = data;
+				len--;
+			}
+			data = ( ( data << 24 ) | ( data >> 8 ) );
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Write PCI VPD
+ *
+ * @v vpd		PCI VPD
+ * @v address		Starting address
+ * @v buf		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address, const void *buf,
+		    size_t len ) {
+	const uint8_t *bytes = buf;
+	uint32_t data;
+	size_t skip_len;
+	unsigned int i;
+	int rc;
+
+	/* Calculate length to skip at start of data */
+	skip_len = ( address & 0x03 );
+
+	/* Write data, a dword at a time */
+	for ( address &= ~0x03 ; len ; address += 4 ) {
+
+		/* Read existing dword, if necessary */
+		if ( skip_len || ( len <= 0x03 ) ) {
+			if ( ( rc = pci_vpd_read_dword ( vpd, address,
+							 &data ) ) != 0 )
+				return rc;
+		}
+
+		/* Copy data from buffer */
+		for ( i = 4 ; i ; i-- ) {
+			if ( skip_len ) {
+				skip_len--;
+			} else if ( len ) {
+				data = ( ( data & ~0xff ) | *(bytes++) );
+				len--;
+			}
+			data = ( ( data << 24 ) | ( data >> 8 ) );
+		}
+
+		/* Write whole dword */
+		if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 )
+			return rc;
+	}
+	return 0;
+}
+
+/**
+ * Dump PCI VPD region (for debugging)
+ *
+ * @v vpd		PCI VPD
+ * @v address		Starting address
+ * @v len		Length of data
+ */
+static void pci_vpd_dump ( struct pci_vpd *vpd, unsigned int address,
+			   size_t len ) {
+	int rc;
+
+	/* Do nothing in non-debug builds */
+	if ( ! DBG_LOG )
+		return;
+
+	/* Read data */
+	{
+		char buf[len];
+		if ( ( rc = pci_vpd_read ( vpd, address, buf,
+					   sizeof ( buf ) ) ) != 0 )
+			return;
+		DBGC_HDA ( vpd, address, buf, sizeof ( buf ) );
+	}
+}
+
+/**
+ * Locate PCI VPD tag
+ *
+ * @v vpd		PCI VPD
+ * @v tag		ISAPnP tag
+ * @ret address		Address of tag body
+ * @ret len		Length of tag body
+ * @ret rc		Return status code
+ */
+static int pci_vpd_find_tag ( struct pci_vpd *vpd, unsigned int tag,
+			      unsigned int *address, size_t *len ) {
+	uint8_t read_tag;
+	uint16_t read_len;
+	int rc;
+
+	/* Scan through tags looking for a match */
+	*address = 0;
+	do {
+		/* Read tag byte */
+		if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag,
+					   sizeof ( read_tag ) ) ) != 0 )
+			return rc;
+
+		/* Extract tag and length */
+		if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) {
+			if ( ( rc = pci_vpd_read ( vpd, *address, &read_len,
+						   sizeof ( read_len ) ) ) != 0)
+				return rc;
+			*address += sizeof ( read_len );
+			read_len = le16_to_cpu ( read_len );
+			read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag );
+		} else {
+			read_len = ISAPNP_SMALL_TAG_LEN ( read_tag );
+			read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag );
+		}
+
+		/* Check for tag match */
+		if ( tag == read_tag ) {
+			*len = read_len;
+			DBGC ( vpd, PCI_FMT " VPD tag %02x is at "
+			       "[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag,
+			       *address, ( *address + *len ) );
+			return 0;
+		}
+
+		/* Move to next tag */
+		*address += read_len;
+
+	} while ( read_tag != ISAPNP_TAG_END );
+
+	DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n",
+	       PCI_ARGS ( vpd->pci ), tag );
+	return -ENOENT;
+}
+
+/**
+ * Locate PCI VPD field
+ *
+ * @v vpd		PCI VPD
+ * @v field		VPD field descriptor
+ * @ret address		Address of field body
+ * @ret len		Length of field body
+ * @ret rc		Return status code
+ */
+int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
+		   unsigned int *address, size_t *len ) {
+	struct pci_vpd_field read_field;
+	int rc;
+
+	/* Locate containing tag */
+	if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ),
+				       address, len ) ) != 0 )
+		return rc;
+
+	/* Return immediately if we are searching for a whole-tag field */
+	if ( ! PCI_VPD_KEYWORD ( field ) ) {
+		pci_vpd_dump ( vpd, *address, *len );
+		return 0;
+	}
+
+	/* Scan through fields looking for a match */
+	while ( *len >= sizeof ( read_field ) ) {
+
+		/* Read field header */
+		if ( ( rc = pci_vpd_read ( vpd, *address, &read_field,
+					   sizeof ( read_field ) ) ) != 0 )
+			return rc;
+		*address += sizeof ( read_field );
+		*len -= sizeof ( read_field );
+
+		/* Check for keyword match */
+		if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) {
+			*len = read_field.len;
+			DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
+			       " is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ),
+			       PCI_VPD_FIELD_ARGS ( field ),
+			       *address, ( *address + *len ) );
+			pci_vpd_dump ( vpd, *address, *len );
+			return 0;
+		}
+
+		/* Move to next field */
+		if ( read_field.len > *len )
+			break;
+		*address += read_field.len;
+		*len -= read_field.len;
+	}
+
+	DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n",
+	       PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
+	return -ENOENT;
+}
+
+/**
+ * Resize VPD field
+ *
+ * @v vpd		PCI VPD
+ * @v field		VPD field descriptor
+ * @v len		New length of field body
+ * @ret address		Address of field body
+ * @ret rc		Return status code
+ */
+int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field, size_t len,
+		     unsigned int *address ) {
+	struct pci_vpd_field rw_field;
+	struct pci_vpd_field old_field;
+	struct pci_vpd_field new_field;
+	unsigned int rw_address;
+	unsigned int old_address;
+	unsigned int copy_address;
+	unsigned int dst_address;
+	unsigned int dump_address;
+	size_t rw_len;
+	size_t old_len;
+	size_t available_len;
+	size_t copy_len;
+	size_t dump_len;
+	void *copy;
+	int rc;
+
+	/* Sanity checks */
+	assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW );
+	assert ( PCI_VPD_KEYWORD ( field ) != 0 );
+	assert ( field != PCI_VPD_FIELD_RW );
+
+	/* Locate 'RW' field */
+	if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address,
+				   &rw_len ) ) != 0 )
+		goto err_no_rw;
+
+	/* Locate old field, if any */
+	if ( ( rc = pci_vpd_find ( vpd, field, &old_address,
+				   &old_len ) ) == 0 ) {
+
+		/* Field already exists */
+		if ( old_address > rw_address ) {
+			DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
+			       " at [%04x,%04zx) is after field "
+			       PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
+			       PCI_ARGS ( vpd->pci ),
+			       PCI_VPD_FIELD_ARGS ( field ),
+			       old_address, ( old_address + old_len ),
+			       PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ),
+			       rw_address, ( rw_address + rw_len ) );
+			rc = -ENXIO;
+			goto err_after_rw;
+		}
+		dst_address = ( old_address - sizeof ( old_field ) );
+		copy_address = ( old_address + old_len );
+		copy_len = ( rw_address - sizeof ( rw_field ) - copy_address );
+
+		/* Calculate available length */
+		available_len = ( rw_len + old_len );
+
+	} else {
+
+		/* Field does not yet exist */
+		dst_address = ( rw_address - sizeof ( rw_field ) );
+		copy_address = dst_address;
+		copy_len = 0;
+
+		/* Calculate available length */
+		available_len = ( ( rw_len > sizeof ( new_field ) ) ?
+				  ( rw_len - sizeof ( new_field ) ) : 0 );
+	}
+
+	/* Dump region before changes */
+	dump_address = dst_address;
+	dump_len = ( rw_address + rw_len - dump_address );
+	DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT
+	       " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
+	       PCI_VPD_FIELD_ARGS ( field ), len );
+	pci_vpd_dump ( vpd, dump_address, dump_len );
+
+	/* Check available length */
+	if ( available_len > PCI_VPD_MAX_LEN )
+		available_len = PCI_VPD_MAX_LEN;
+	if ( len > available_len ) {
+		DBGC ( vpd, PCI_FMT " VPD no space for field "
+		       PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n",
+		       PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ),
+		       len, available_len );
+		rc = -ENOSPC;
+		goto err_no_space;
+	}
+
+	/* Preserve intermediate fields, if any */
+	copy = malloc ( copy_len );
+	if ( ! copy ) {
+		rc = -ENOMEM;
+		goto err_copy_alloc;
+	}
+	if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 )
+		goto err_copy_read;
+
+	/* Create new field, if applicable */
+	if ( len ) {
+		new_field.keyword = PCI_VPD_KEYWORD ( field );
+		new_field.len = len;
+		if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field,
+					    sizeof ( new_field ) ) ) != 0 )
+			goto err_new_write;
+		dst_address += sizeof ( new_field );
+		*address = dst_address;
+		DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
+		       "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
+		       PCI_VPD_FIELD_ARGS ( field ), dst_address,
+		       ( dst_address + new_field.len ) );
+		dst_address += len;
+	} else {
+		DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
+		       " no longer exists\n", PCI_ARGS ( vpd->pci ),
+		       PCI_VPD_FIELD_ARGS ( field ) );
+	}
+
+	/* Restore intermediate fields, if any */
+	if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 )
+		goto err_copy_write;
+	dst_address += copy_len;
+
+	/* Create 'RW' field */
+	rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW );
+	rw_field.len = ( rw_len +
+			 ( rw_address - sizeof ( rw_field ) ) - dst_address );
+	if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field,
+				    sizeof ( rw_field ) ) ) != 0 )
+		goto err_rw_write;
+	dst_address += sizeof ( rw_field );
+	DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
+	       "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
+	       PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address,
+	       ( dst_address + rw_field.len ) );
+
+	/* Dump region after changes */
+	DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT
+	       " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
+	       PCI_VPD_FIELD_ARGS ( field ), len );
+	pci_vpd_dump ( vpd, dump_address, dump_len );
+
+	rc = 0;
+
+ err_rw_write:
+ err_new_write:
+ err_copy_write:
+ err_copy_read:
+	free ( copy );
+ err_copy_alloc:
+ err_no_space:
+ err_after_rw:
+ err_no_rw:
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-pci.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-pci.c
new file mode 100644
index 0000000..fbef067
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-pci.c
@@ -0,0 +1,64 @@
+/* virtio-pci.c - pci interface for virtio interface
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ *  Copyright IBM Corp. 2007
+ *  Authors: Anthony Liguori  <aliguori at us.ibm.com>
+ *
+ */
+
+#include "etherboot.h"
+#include "ipxe/io.h"
+#include "ipxe/virtio-ring.h"
+#include "ipxe/virtio-pci.h"
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq)
+{
+   struct vring * vr = &vq->vring;
+   u16 num;
+
+   /* select the queue */
+
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+   /* check if the queue is available */
+
+   num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+   if (!num) {
+           printf("ERROR: queue size is 0\n");
+           return -1;
+   }
+
+   if (num > MAX_QUEUE_NUM) {
+           printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+           return -1;
+   }
+
+   /* check if the queue is already active */
+
+   if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+           printf("ERROR: queue already active\n");
+           return -1;
+   }
+
+   vq->queue_index = queue_index;
+
+   /* initialize the queue */
+
+   vring_init(vr, num, (unsigned char*)&vq->queue);
+
+   /* activate the queue
+    *
+    * NOTE: vr->desc is initialized by vring_init()
+    */
+
+   outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+        ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+   return num;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-ring.c b/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-ring.c
new file mode 100644
index 0000000..e55b6d0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/bus/virtio-ring.c
@@ -0,0 +1,136 @@
+/* virtio-pci.c - virtio ring management
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ *  some parts from Linux Virtio Ring
+ *
+ *  Copyright Rusty Russell IBM Corporation 2007
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "etherboot.h"
+#include "ipxe/io.h"
+#include "ipxe/virtio-ring.h"
+#include "ipxe/virtio-pci.h"
+
+#define BUG() do { \
+   printf("BUG: failure at %s:%d/%s()!\n", \
+          __FILE__, __LINE__, __FUNCTION__); \
+   while(1); \
+} while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+
+/*
+ * vring_free
+ *
+ * put at the begin of the free list the current desc[head]
+ */
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head)
+{
+   struct vring *vr = &vq->vring;
+   unsigned int i;
+
+   /* find end of given descriptor */
+
+   i = head;
+   while (vr->desc[i].flags & VRING_DESC_F_NEXT)
+           i = vr->desc[i].next;
+
+   /* link it with free list and point to it */
+
+   vr->desc[i].next = vq->free_head;
+   wmb();
+   vq->free_head = head;
+}
+
+/*
+ * vring_get_buf
+ *
+ * get a buffer from the used list
+ *
+ */
+
+void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
+{
+   struct vring *vr = &vq->vring;
+   struct vring_used_elem *elem;
+   u32 id;
+   void *opaque;
+
+   BUG_ON(!vring_more_used(vq));
+
+   elem = &vr->used->ring[vq->last_used_idx % vr->num];
+   wmb();
+   id = elem->id;
+   if (len != NULL)
+           *len = elem->len;
+
+   opaque = vq->vdata[id];
+
+   vring_detach(vq, id);
+
+   vq->last_used_idx++;
+
+   return opaque;
+}
+
+void vring_add_buf(struct vring_virtqueue *vq,
+		   struct vring_list list[],
+		   unsigned int out, unsigned int in,
+		   void *opaque, int num_added)
+{
+   struct vring *vr = &vq->vring;
+   int i, avail, head, prev;
+
+   BUG_ON(out + in == 0);
+
+   prev = 0;
+   head = vq->free_head;
+   for (i = head; out; i = vr->desc[i].next, out--) {
+
+           vr->desc[i].flags = VRING_DESC_F_NEXT;
+           vr->desc[i].addr = (u64)virt_to_phys(list->addr);
+           vr->desc[i].len = list->length;
+           prev = i;
+           list++;
+   }
+   for ( ; in; i = vr->desc[i].next, in--) {
+
+           vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+           vr->desc[i].addr = (u64)virt_to_phys(list->addr);
+           vr->desc[i].len = list->length;
+           prev = i;
+           list++;
+   }
+   vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
+
+   vq->free_head = i;
+
+   vq->vdata[head] = opaque;
+
+   avail = (vr->avail->idx + num_added) % vr->num;
+   vr->avail->ring[avail] = head;
+   wmb();
+}
+
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+{
+   struct vring *vr = &vq->vring;
+
+   wmb();
+   vr->avail->idx += num_added;
+
+   mb();
+   if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
+           vp_notify(ioaddr, vq->queue_index);
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25218_PRM.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25218_PRM.h
new file mode 100644
index 0000000..4011bd0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25218_PRM.h
@@ -0,0 +1,3460 @@
+/*
+  This software is available to you under a choice of one of two
+  licenses.  You may choose to be licensed under the terms of the GNU
+  General Public License (GPL) Version 2, available at
+  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+  license, available in the LICENSE.TXT file accompanying this
+  software.  These details are also available at
+  <http://openib.org/license.html>.
+
+  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.
+
+  Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
+*/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/***
+ *** This file was generated at "Tue Nov 22 15:21:23 2005"
+ *** by:
+ ***    % csp_bf -copyright=/mswg/misc/license-header.txt -prefix arbelprm_ -bits -fixnames MT25218_PRM.csp
+ ***/
+
+#ifndef H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H
+#define H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H
+
+/* UD Address Vector */
+
+struct arbelprm_ud_address_vector_st {	/* Little Endian */
+    pseudo_bit_t	pd[0x00018];           /* Protection Domain */
+    pseudo_bit_t	port_number[0x00002];  /* Port number
+                                                 1 - Port 1
+                                                 2 - Port 2
+                                                 other - reserved */
+    pseudo_bit_t	reserved0[0x00006];
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (Destination) LID */
+    pseudo_bit_t	my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+    pseudo_bit_t	g[0x00001];            /* Global address enable - if set, GRH will be formed for packet header */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	hop_limit[0x00008];    /* IPv6 hop limit */
+    pseudo_bit_t	max_stat_rate[0x00003];/* Maximum static rate control. 
+                                                 0 - 4X injection rate
+                                                 1 - 1X injection rate
+                                                 other - reserved
+                                                  */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	msg[0x00002];          /* Max Message size, size is 256*2^MSG bytes */
+    pseudo_bit_t	reserved3[0x00002];
+    pseudo_bit_t	mgid_index[0x00006];   /* Index to port GID table
+                                                 mgid_index = (port_number-1) * 2^log_max_gid + gid_index
+                                                 Where:
+                                                 1. log_max_gid is taken from QUERY_DEV_LIM command
+                                                 2. gid_index is the index to the GID table */
+    pseudo_bit_t	reserved4[0x0000a];
+/* -------------- */
+    pseudo_bit_t	flow_label[0x00014];   /* IPv6 flow label */
+    pseudo_bit_t	tclass[0x00008];       /* IPv6 TClass */
+    pseudo_bit_t	sl[0x00004];           /* InfiniBand Service Level (SL) */
+/* -------------- */
+    pseudo_bit_t	rgid_127_96[0x00020];  /* Remote GID[127:96] */
+/* -------------- */
+    pseudo_bit_t	rgid_95_64[0x00020];   /* Remote GID[95:64] */
+/* -------------- */
+    pseudo_bit_t	rgid_63_32[0x00020];   /* Remote GID[63:32] */
+/* -------------- */
+    pseudo_bit_t	rgid_31_0[0x00020];    /* Remote GID[31:0] if G bit is set. Must be set to 0x2 if G bit is cleared. */
+/* -------------- */
+}; 
+
+/* Send doorbell */
+
+struct arbelprm_send_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	nopcode[0x00005];      /* Opcode of descriptor to be executed */
+    pseudo_bit_t	f[0x00001];            /* Fence bit. If set, descriptor is fenced */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	wqe_counter[0x00010];  /* Modulo-64K counter of WQEs posted to the QP since its creation excluding the newly posted WQEs in this doorbell. Should be zero for the first doorbell on the QP */
+    pseudo_bit_t	wqe_cnt[0x00008];      /* Number of WQEs posted with this doorbell. Must be grater then zero. */
+/* -------------- */
+    pseudo_bit_t	nds[0x00006];          /* Next descriptor size (in 16-byte chunks) */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	qpn[0x00018];          /* QP number this doorbell is rung on */
+/* -------------- */
+}; 
+
+/* ACCESS_LAM_inject_errors_input_modifier */
+
+struct arbelprm_access_lam_inject_errors_input_modifier_st {	/* Little Endian */
+    pseudo_bit_t	index3[0x00007];
+    pseudo_bit_t	q3[0x00001];
+    pseudo_bit_t	index2[0x00007];
+    pseudo_bit_t	q2[0x00001];
+    pseudo_bit_t	index1[0x00007];
+    pseudo_bit_t	q1[0x00001];
+    pseudo_bit_t	index0[0x00007];
+    pseudo_bit_t	q0[0x00001];
+/* -------------- */
+}; 
+
+/* ACCESS_LAM_inject_errors_input_parameter */
+
+struct arbelprm_access_lam_inject_errors_input_parameter_st {	/* Little Endian */
+    pseudo_bit_t	ba[0x00002];           /* Bank Address */
+    pseudo_bit_t	da[0x00002];           /* Dimm Address */
+    pseudo_bit_t	reserved0[0x0001c];
+/* -------------- */
+    pseudo_bit_t	ra[0x00010];           /* Row Address */
+    pseudo_bit_t	ca[0x00010];           /* Column Address */
+/* -------------- */
+}; 
+
+/*  */
+
+struct arbelprm_recv_wqe_segment_next_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	nda_31_6[0x0001a];     /* Next WQE address, low 32 bit. WQE address must be aligned to 64-byte boundary (6 LSB are forced ZERO). */
+/* -------------- */
+    pseudo_bit_t	nds[0x00006];          /* Next WQE size in OctoWords (16 bytes). 
+                                                 Zero value in NDS field signals end of WQEs? chain.
+                                                  */
+    pseudo_bit_t	reserved1[0x0001a];
+/* -------------- */
+}; 
+
+/* Send wqe segment data inline */
+
+struct arbelprm_wqe_segment_data_inline_st {	/* Little Endian */
+    pseudo_bit_t	byte_count[0x0000a];   /* Not including padding for 16Byte chunks */
+    pseudo_bit_t	reserved0[0x00015];
+    pseudo_bit_t	always1[0x00001];
+/* -------------- */
+    pseudo_bit_t	data[0x00018];         /* Data may be more this segment size - in 16Byte chunks */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment data ptr */
+
+struct arbelprm_wqe_segment_data_ptr_st {	/* Little Endian */
+    pseudo_bit_t	byte_count[0x0001f];
+    pseudo_bit_t	always0[0x00001];
+/* -------------- */
+    pseudo_bit_t	l_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	local_address_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	local_address_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment rd */
+
+struct arbelprm_local_invalidate_segment_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00018];
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x000a0];
+/* -------------- */
+}; 
+
+/* Fast_Registration_Segment */
+
+struct arbelprm_fast_registration_segment_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x0001b];
+    pseudo_bit_t	lr[0x00001];           /* If set - Local Read access will be enabled */
+    pseudo_bit_t	lw[0x00001];           /* If set - Local Write access will be enabled */
+    pseudo_bit_t	rr[0x00001];           /* If set - Remote Read access will be enabled */
+    pseudo_bit_t	rw[0x00001];           /* If set - Remote Write access will be enabled */
+    pseudo_bit_t	a[0x00001];            /* If set - Remote Atomic access will be enabled */
+/* -------------- */
+    pseudo_bit_t	pbl_ptr_63_32[0x00020];/* Physical address pointer [63:32] to the physical buffer list */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* Memory Key on which the fast registration is executed on. */
+/* -------------- */
+    pseudo_bit_t	page_size[0x00005];    /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+                                                 page_size should be less than 20. */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	zb[0x00001];           /* Zero Based Region */
+    pseudo_bit_t	pbl_ptr_31_8[0x00018]; /* Physical address pointer [31:8] to the physical buffer list */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region starts */
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region starts */
+/* -------------- */
+    pseudo_bit_t	reg_len_h[0x00020];    /* Region Length[63:32] */
+/* -------------- */
+    pseudo_bit_t	reg_len_l[0x00020];    /* Region Length[31:0] */
+/* -------------- */
+}; 
+
+/* Send wqe segment atomic */
+
+struct arbelprm_wqe_segment_atomic_st {	/* Little Endian */
+    pseudo_bit_t	swap_add_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	swap_add_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	compare_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	compare_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment remote address */
+
+struct arbelprm_wqe_segment_remote_address_st {	/* Little Endian */
+    pseudo_bit_t	remote_virt_addr_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	remote_virt_addr_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	rkey[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/* end wqe segment bind */
+
+struct arbelprm_wqe_segment_bind_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x0001d];
+    pseudo_bit_t	rr[0x00001];           /* If set, Remote Read Enable for bound window. */
+    pseudo_bit_t	rw[0x00001];           /* If set, Remote Write Enable for bound window.
+                                                  */
+    pseudo_bit_t	a[0x00001];            /* If set, Atomic Enable for bound window. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x0001e];
+    pseudo_bit_t	zb[0x00001];           /* If set, Window is Zero Based. */
+    pseudo_bit_t	type[0x00001];         /* Window type.
+                                                 0 - Type one window
+                                                 1 - Type two window
+                                                  */
+/* -------------- */
+    pseudo_bit_t	new_rkey[0x00020];     /* The new RKey of window to bind */
+/* -------------- */
+    pseudo_bit_t	region_lkey[0x00020];  /* Local key of region, which window will be bound to */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	length_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	length_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment ud */
+
+struct arbelprm_wqe_segment_ud_st {	/* Little Endian */
+    struct arbelprm_ud_address_vector_st	ud_address_vector;/* UD Address Vector */
+/* -------------- */
+    pseudo_bit_t	destination_qp[0x00018];
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment rd */
+
+struct arbelprm_wqe_segment_rd_st {	/* Little Endian */
+    pseudo_bit_t	destination_qp[0x00018];
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment ctrl */
+
+struct arbelprm_wqe_segment_ctrl_send_st {	/* Little Endian */
+    pseudo_bit_t	always1[0x00001];
+    pseudo_bit_t	s[0x00001];            /* Solicited Event bit. If set, SE (Solicited Event) bit is set in the (last packet of) message. */
+    pseudo_bit_t	e[0x00001];            /* Event bit. If set, event is generated upon WQE?s completion, if QP is allowed to generate an event. Every WQE with E-bit set generates an event. The C bit must be set on unsignalled QPs if the E bit is set. */
+    pseudo_bit_t	c[0x00001];            /* Completion Queue bit. Valid for unsignalled QPs only. If set, the CQ is updated upon WQE?s completion */
+    pseudo_bit_t	ip[0x00001];           /* When set, InfiniHost III Ex will calculate the IP checksum of the IP header that is present immediately after the IPoverIB encapsulation header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first IP header following the IPoverIB encapsulation header. Not Valid for IPv6 packets */
+    pseudo_bit_t	tcp_udp[0x00001];      /* When set, InfiniHost III Ex will calculate the TCP/UDP checksum of the packet that is present immediately after the IP header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first TCP header following the IP header. This bit may be set only if the entire TCP/UDP segment is present in one IB packet */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	so[0x00001];           /* Strong Ordering - when set, the WQE will be executed only after all previous WQEs have been executed. Can be set for RC WQEs only. This bit must be set in type two BIND, Fast Registration and Local invalidate operations. */
+    pseudo_bit_t	reserved1[0x00018];
+/* -------------- */
+    pseudo_bit_t	immediate[0x00020];    /* If the OpCode encodes an operation with Immediate (RDMA-write/SEND), This field will hold the Immediate data to be sent. If the OpCode encodes send and invalidate operations, this field holds the Invalidation key to be inserted into the packet; otherwise, this field is reserved. */
+/* -------------- */
+}; 
+
+/* Send wqe segment next */
+
+struct arbelprm_wqe_segment_next_st {	/* Little Endian */
+    pseudo_bit_t	nopcode[0x00005];      /* Next Opcode: OpCode to be used in the next WQE. Encodes the type of operation to be executed on the QP:
+                                                 ?00000? - NOP. WQE with this opcode creates a completion, but does nothing else
+                                                 ?01000? - RDMA-write
+                                                 ?01001? - RDMA-Write with Immediate 
+                                                 ?10000? - RDMA-read  
+                                                 ?10001? - Atomic Compare & swap
+                                                 ?10010? - Atomic Fetch & Add
+                                                 ?11000? - Bind memory window
+                                                 
+                                                 The encoding for the following operations depends on the QP type:
+                                                 For RC, UC and RD QP:
+                                                 ?01010? - SEND
+                                                 ?01011? - SEND with Immediate
+                                                 
+                                                 For UD QP: 
+                                                 the encoding depends on the values of bit[31] of the Q_key field in the Datagram Segment (see Table 39, ?Unreliable Datagram Segment Format - Pointers,? on page 101) of
+                                                 both  the current WQE and the next WQE, as follows:
+                                                 
+                                                 If  the last WQE Q_Key bit[31] is clear and the next WQE Q_key bit[31] is set :
+                                                 ?01000? - SEND
+                                                 ?01001? - SEND with Immediate
+                                                 
+                                                 otherwise (if the next WQE Q_key bit[31] is cleared, or the last WQE Q_Key bit[31] is set):
+                                                 ?01010? - SEND
+                                                 ?01011? - SEND with Immediate
+                                                 
+                                                 All other opcode values are RESERVED, and will result in invalid operation execution. */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	nda_31_6[0x0001a];     /* Next WQE address, low 32 bit. WQE address must be aligned to 64-byte boundary (6 LSB are forced ZERO). */
+/* -------------- */
+    pseudo_bit_t	nds[0x00006];          /* Next WQE size in OctoWords (16 bytes). 
+                                                 Zero value in NDS field signals end of WQEs? chain.
+                                                  */
+    pseudo_bit_t	f[0x00001];            /* Fence bit. If set, next WQE will start execution only after all previous Read/Atomic WQEs complete. */
+    pseudo_bit_t	always1[0x00001];
+    pseudo_bit_t	reserved1[0x00018];
+/* -------------- */
+}; 
+
+/* Address Path */
+
+struct arbelprm_address_path_st {	/* Little Endian */
+    pseudo_bit_t	pkey_index[0x00007];   /* PKey table index */
+    pseudo_bit_t	reserved0[0x00011];
+    pseudo_bit_t	port_number[0x00002];  /* Specific port associated with this QP/EE.
+                                                 1 - Port 1
+                                                 2 - Port 2
+                                                 other - reserved */
+    pseudo_bit_t	reserved1[0x00006];
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (Destination) LID */
+    pseudo_bit_t	my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+    pseudo_bit_t	g[0x00001];            /* Global address enable - if set, GRH will be formed for packet header */
+    pseudo_bit_t	reserved2[0x00005];
+    pseudo_bit_t	rnr_retry[0x00003];    /* RNR retry count (see C9-132 in IB spec Vol 1)
+                                                 0-6 - number of retries
+                                                 7    - infinite */
+/* -------------- */
+    pseudo_bit_t	hop_limit[0x00008];    /* IPv6 hop limit */
+    pseudo_bit_t	max_stat_rate[0x00003];/* Maximum static rate control. 
+                                                 0 - 100% injection rate 
+                                                 1 - 25% injection rate
+                                                 2 - 12.5% injection rate
+                                                 3 - 50% injection rate
+                                                 other - reserved */
+    pseudo_bit_t	reserved3[0x00005];
+    pseudo_bit_t	mgid_index[0x00006];   /* Index to port GID table */
+    pseudo_bit_t	reserved4[0x00005];
+    pseudo_bit_t	ack_timeout[0x00005];  /* Local ACK timeout - Transport timer for activation of retransmission mechanism. Refer to IB spec Vol1 9.7.6.1.3 for further details.
+                                                 The transport timer is set to 4.096us*2^ack_timeout, if ack_timeout is 0 then transport timer is disabled. */
+/* -------------- */
+    pseudo_bit_t	flow_label[0x00014];   /* IPv6 flow label */
+    pseudo_bit_t	tclass[0x00008];       /* IPv6 TClass */
+    pseudo_bit_t	sl[0x00004];           /* InfiniBand Service Level (SL) */
+/* -------------- */
+    pseudo_bit_t	rgid_127_96[0x00020];  /* Remote GID[127:96] */
+/* -------------- */
+    pseudo_bit_t	rgid_95_64[0x00020];   /* Remote GID[95:64] */
+/* -------------- */
+    pseudo_bit_t	rgid_63_32[0x00020];   /* Remote GID[63:32] */
+/* -------------- */
+    pseudo_bit_t	rgid_31_0[0x00020];    /* Remote GID[31:0] */
+/* -------------- */
+}; 
+
+/* HCA Command Register (HCR) */
+
+struct arbelprm_hca_command_register_st {	/* Little Endian */
+    pseudo_bit_t	in_param_h[0x00020];   /* Input Parameter: parameter[63:32] or pointer[63:32] to input mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	in_param_l[0x00020];   /* Input Parameter: parameter[31:0] or pointer[31:0] to input mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	input_modifier[0x00020];/* Input Parameter Modifier */
+/* -------------- */
+    pseudo_bit_t	out_param_h[0x00020];  /* Output Parameter: parameter[63:32] or pointer[63:32] to output mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	out_param_l[0x00020];  /* Output Parameter: parameter[31:0] or pointer[31:0] to output mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00010];
+    pseudo_bit_t	token[0x00010];        /* Software assigned token to the command, to uniquely identify it. The token is returned to the software in the EQE reported. */
+/* -------------- */
+    pseudo_bit_t	opcode[0x0000c];       /* Command opcode */
+    pseudo_bit_t	opcode_modifier[0x00004];/* Opcode Modifier, see specific description for each command. */
+    pseudo_bit_t	reserved1[0x00006];
+    pseudo_bit_t	e[0x00001];            /* Event Request
+                                                 0 - Don't report event (software will poll the GO bit)
+                                                 1 - Report event to EQ when the command completes */
+    pseudo_bit_t	go[0x00001];           /* Go (0=Software ownership for the HCR, 1=Hardware ownership for the HCR)
+                                                 Software can write to the HCR only if Go bit is cleared.
+                                                 Software must set the Go bit to trigger the HW to execute the command. Software must not write to this register value other than 1 for the Go bit. */
+    pseudo_bit_t	status[0x00008];       /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared)
+                                                 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */
+/* -------------- */
+}; 
+
+/* CQ Doorbell */
+
+struct arbelprm_cq_cmd_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number accessed */
+    pseudo_bit_t	cmd[0x00003];          /* Command to be executed on CQ
+                                                 0x0 - Reserved
+                                                 0x1 - Request notification for next Solicited completion event. CQ_param specifies the current CQ Consumer Counter.
+                                                 0x2 - Request notification for next Solicited or Unsolicited completion event. CQ_param specifies the current CQ Consumer Counter.
+                                                 0x3 - Request notification for multiple completions (Arm-N). CQ_param specifies the value of the CQ Counter that when reached by HW (i.e. HW generates a CQE into this Counter) Event will be generated
+                                                 Other - Reserved */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	cmd_sn[0x00002];       /* Command Sequence Number - This field should be incremented upon receiving completion notification of the respective CQ.
+                                                 This transition is done by ringing Request notification for next Solicited, Request notification for next Solicited or Unsolicited 
+                                                 completion or Request notification for multiple completions doorbells after receiving completion notification.
+                                                 This field is initialized to Zero */
+    pseudo_bit_t	reserved1[0x00002];
+/* -------------- */
+    pseudo_bit_t	cq_param[0x00020];     /* parameter to be used by CQ command */
+/* -------------- */
+}; 
+
+/* RD-send doorbell */
+
+struct arbelprm_rd_send_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	een[0x00018];          /* End-to-end context number (reliable datagram)
+                                                 Must be zero for Nop and Bind operations */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00008];
+    pseudo_bit_t	qpn[0x00018];          /* QP number this doorbell is rung on */
+/* -------------- */
+    struct arbelprm_send_doorbell_st	send_doorbell;/* Send Parameters */
+/* -------------- */
+}; 
+
+/* Multicast Group Member QP */
+
+struct arbelprm_mgmqp_st {	/* Little Endian */
+    pseudo_bit_t	qpn_i[0x00018];        /* QPN_i: QP number which is a member in this multicast group. Valid only if Qi bit is set. Length of the QPN_i list is set in INIT_HCA */
+    pseudo_bit_t	reserved0[0x00007];
+    pseudo_bit_t	qi[0x00001];           /* Qi: QPN_i is valid */
+/* -------------- */
+}; 
+
+/* vsd */
+
+struct arbelprm_vsd_st {	/* Little Endian */
+    pseudo_bit_t	vsd_dw0[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw1[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw2[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw3[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw4[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw5[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw6[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw7[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw8[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw9[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw10[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw11[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw12[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw13[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw14[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw15[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw16[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw17[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw18[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw19[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw20[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw21[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw22[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw23[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw24[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw25[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw26[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw27[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw28[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw29[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw30[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw31[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw32[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw33[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw34[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw35[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw36[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw37[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw38[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw39[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw40[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw41[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw42[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw43[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw44[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw45[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw46[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw47[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw48[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw49[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw50[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw51[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw52[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw53[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw54[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw55[0x00020];
+/* -------------- */
+}; 
+
+/* ACCESS_LAM_inject_errors */
+
+struct arbelprm_access_lam_inject_errors_st {	/* Little Endian */
+    struct arbelprm_access_lam_inject_errors_input_parameter_st	access_lam_inject_errors_input_parameter;
+/* -------------- */
+    struct arbelprm_access_lam_inject_errors_input_modifier_st	access_lam_inject_errors_input_modifier;
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/* Logical DIMM Information */
+
+struct arbelprm_dimminfo_st {	/* Little Endian */
+    pseudo_bit_t	dimmsize[0x00010];     /* Size of DIMM in units of 2^20 Bytes. This value is valid only when DIMMStatus is 0. */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	dimmstatus[0x00001];   /* DIMM Status
+                                                 0 - Enabled
+                                                 1 - Disabled
+                                                  */
+    pseudo_bit_t	dh[0x00001];           /* When set, the DIMM is Hidden and can not be accessed from the PCI bus. */
+    pseudo_bit_t	wo[0x00001];           /* When set, the DIMM is write only.
+                                                 If data integrity is configured (other than none), the DIMM must be
+                                                 only targeted by write transactions where the address and size are multiples of 16 bytes. */
+    pseudo_bit_t	reserved1[0x00005];
+/* -------------- */
+    pseudo_bit_t	spd[0x00001];          /* 0 - DIMM SPD was read from DIMM
+                                                 1 - DIMM SPD was read from InfiniHost-III-EX NVMEM */
+    pseudo_bit_t	sladr[0x00003];        /* SPD Slave Address 3 LSBits. 
+                                                 Valid only if spd bit is 0. */
+    pseudo_bit_t	sock_num[0x00002];     /* DIMM socket number (for double sided DIMM one of the two numbers will be reported) */
+    pseudo_bit_t	syn[0x00004];          /* Error syndrome (valid regardless of status value)
+                                                 0 - DIMM has no error
+                                                 1 - SPD error (e.g. checksum error, no response, error while reading)
+                                                 2 - DIMM out of bounds (e.g. DIMM rows number is not between 7 and 14, DIMM type is not 2)
+                                                 3 - DIMM conflict (e.g. mix of registered and unbuffered DIMMs, CAS latency conflict)
+                                                 5 - DIMM size trimmed due to configuration (size exceeds)
+                                                 other - Error, reserved
+                                                  */
+    pseudo_bit_t	reserved2[0x00016];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00040];
+/* -------------- */
+    pseudo_bit_t	dimm_start_adr_h[0x00020];/* DIMM memory start address [63:32]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+    pseudo_bit_t	dimm_start_adr_l[0x00020];/* DIMM memory start address [31:0]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00040];
+/* -------------- */
+}; 
+
+/* UAR Parameters */
+
+struct arbelprm_uar_params_st {	/* Little Endian */
+    pseudo_bit_t	uar_base_addr_h[0x00020];/* UAR Base (pyhsical) Address [63:32] (QUERY_HCA only) */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00014];
+    pseudo_bit_t	uar_base_addr_l[0x0000c];/* UAR Base (pyhsical) Address [31:20] (QUERY_HCA only) */
+/* -------------- */
+    pseudo_bit_t	uar_page_sz[0x00008];  /* This field defines the size of each UAR page.
+                                                 Size of UAR Page is 4KB*2^UAR_Page_Size */
+    pseudo_bit_t	log_max_uars[0x00004]; /* Number of UARs supported is 2^log_max_UARs */
+    pseudo_bit_t	reserved1[0x00004];
+    pseudo_bit_t	log_uar_entry_sz[0x00006];/* Size of UAR Context entry is 2^log_uar_sz in 4KByte pages */
+    pseudo_bit_t	reserved2[0x0000a];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	uar_scratch_base_addr_h[0x00020];/* Base address of UAR scratchpad [63:32].
+                                                 Number of entries in table is 2^log_max_uars.
+                                                 Table must be aligned to its size */
+/* -------------- */
+    pseudo_bit_t	uar_scratch_base_addr_l[0x00020];/* Base address of UAR scratchpad [31:0].
+                                                 Number of entries in table is 2^log_max_uars. 
+                                                 Table must be aligned to its size. */
+/* -------------- */
+    pseudo_bit_t	uar_context_base_addr_h[0x00020];/* Base address of UAR Context [63:32].
+                                                 Number of entries in table is 2^log_max_uars.
+                                                 Table must be aligned to its size. */
+/* -------------- */
+    pseudo_bit_t	uar_context_base_addr_l[0x00020];/* Base address of UAR Context [31:0].
+                                                 Number of entries in table is 2^log_max_uars. 
+                                                 Table must be aligned to its size. */
+/* -------------- */
+}; 
+
+/* Translation and Protection Tables Parameters */
+
+struct arbelprm_tptparams_st {	/* Little Endian */
+    pseudo_bit_t	mpt_base_adr_h[0x00020];/* MPT - Memory Protection Table base physical address [63:32].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	mpt_base_adr_l[0x00020];/* MPT - Memory Protection Table base physical address [31:0].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	log_mpt_sz[0x00006];   /* Log (base 2) of the number of region/windows entries in the MPT table. */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	pfto[0x00005];         /* Page Fault RNR Timeout - 
+                                                 The field returned in RNR Naks generated when a page fault is detected.
+                                                 It has no effect when on-demand-paging is not used. */
+    pseudo_bit_t	reserved1[0x00013];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00020];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00020];/* MTT - Memory Translation table base physical address [63:32].
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_l[0x00020];/* MTT - Memory Translation table base physical address [31:0].
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00040];
+/* -------------- */
+}; 
+
+/* Multicast Support Parameters */
+
+struct arbelprm_multicastparam_st {	/* Little Endian */
+    pseudo_bit_t	mc_base_addr_h[0x00020];/* Base Address of the Multicast Table [63:32].
+                                                 The base address must be aligned to the entry size.
+                                                 Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+    pseudo_bit_t	mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0]. 
+                                                 The base address must be aligned to the entry size.
+                                                 Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	log_mc_table_entry_sz[0x00010];/* Log2 of the Size of multicast group member (MGM) entry.
+                                                 Must be greater than 5 (to allow CTRL and GID sections). 
+                                                 That implies the number of QPs per MC table entry. */
+    pseudo_bit_t	reserved1[0x00010];
+/* -------------- */
+    pseudo_bit_t	mc_table_hash_sz[0x00011];/* Number of entries in multicast DGID hash table (must be power of 2)
+                                                 INIT_HCA - the required number of entries
+                                                 QUERY_HCA - the actual number of entries assigned by firmware (will be less than or equal to the amount required in INIT_HCA) */
+    pseudo_bit_t	reserved2[0x0000f];
+/* -------------- */
+    pseudo_bit_t	log_mc_table_sz[0x00005];/* Log2 of the overall number of MC entries in the MCG table (includes both hash and auxiliary tables) */
+    pseudo_bit_t	reserved3[0x00013];
+    pseudo_bit_t	mc_hash_fn[0x00003];   /* Multicast hash function
+                                                 0 - Default hash function
+                                                 other - reserved */
+    pseudo_bit_t	reserved4[0x00005];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+}; 
+
+/* QPC/EEC/CQC/EQC/RDB Parameters */
+
+struct arbelprm_qpcbaseaddr_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	qpc_base_addr_h[0x00020];/* QPC Base Address [63:32]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	log_num_of_qp[0x00005];/* Log base 2 of number of supported QPs */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	qpc_base_addr_l[0x00019];/* QPC Base Address [31:7]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	eec_base_addr_h[0x00020];/* EEC Base Address [63:32]
+                                                 Table must be aligned on its size.
+                                                 Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+    pseudo_bit_t	log_num_of_ee[0x00005];/* Log base 2 of number of supported EEs. */
+    pseudo_bit_t	reserved3[0x00002];
+    pseudo_bit_t	eec_base_addr_l[0x00019];/* EEC Base Address [31:7]
+                                                 Table must be aligned on its size
+                                                 Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+    pseudo_bit_t	srqc_base_addr_h[0x00020];/* SRQ Context Base Address [63:32]
+                                                 Table must be aligned on its size
+                                                 Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+    pseudo_bit_t	log_num_of_srq[0x00005];/* Log base 2 of number of supported SRQs. */
+    pseudo_bit_t	srqc_base_addr_l[0x0001b];/* SRQ Context Base Address [31:5]
+                                                 Table must be aligned on its size
+                                                 Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+    pseudo_bit_t	cqc_base_addr_h[0x00020];/* CQC Base Address [63:32]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	log_num_of_cq[0x00005];/* Log base 2 of number of supported CQs. */
+    pseudo_bit_t	reserved4[0x00001];
+    pseudo_bit_t	cqc_base_addr_l[0x0001a];/* CQC Base Address [31:6]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00040];
+/* -------------- */
+    pseudo_bit_t	eqpc_base_addr_h[0x00020];/* Extended QPC Base Address [63:32]
+                                                 Table has same number of entries as QPC table.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	eqpc_base_addr_l[0x00020];/* Extended QPC Base Address [31:0]
+                                                 Table has same number of entries as QPC table.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00040];
+/* -------------- */
+    pseudo_bit_t	eeec_base_addr_h[0x00020];/* Extended EEC Base Address [63:32]
+                                                 Table has same number of entries as EEC table.
+                                                 Table must be aligned to entry size.
+                                                 Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+    pseudo_bit_t	eeec_base_addr_l[0x00020];/* Extended EEC Base Address [31:0]
+                                                 Table has same number of entries as EEC table.
+                                                 Table must be aligned to entry size.
+                                                 Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00040];
+/* -------------- */
+    pseudo_bit_t	eqc_base_addr_h[0x00020];/* EQC Base Address [63:32]
+                                                 Address may be set to 0xFFFFFFFF if EQs are not supported.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	log_num_eq[0x00004];   /* Log base 2 of number of supported EQs.
+                                                 Must be 6 or less in InfiniHost-III-EX. */
+    pseudo_bit_t	reserved8[0x00002];
+    pseudo_bit_t	eqc_base_addr_l[0x0001a];/* EQC Base Address [31:6]
+                                                 Address may be set to 0xFFFFFFFF if EQs are not supported.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00040];
+/* -------------- */
+    pseudo_bit_t	rdb_base_addr_h[0x00020];/* Base address of table that holds remote read and remote atomic requests [63:32]. 
+                                                 Address may be set to 0xFFFFFFFF if remote RDMA reads are not supported.
+                                                 Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+    pseudo_bit_t	rdb_base_addr_l[0x00020];/* Base address of table that holds remote read and remote atomic requests [31:0]. 
+                                                 Table must be aligned to RDB entry size (32 bytes).
+                                                 Address may be set to zero if remote RDMA reads are not supported.
+                                                 Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00040];
+/* -------------- */
+}; 
+
+/* Header_Log_Register */
+
+struct arbelprm_header_log_register_st {	/* Little Endian */
+    pseudo_bit_t	place_holder[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00060];
+/* -------------- */
+}; 
+
+/* Performance Monitors */
+
+struct arbelprm_performance_monitors_st {	/* Little Endian */
+    pseudo_bit_t	e0[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	e1[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	e2[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	r0[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	r1[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	r2[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	reserved1[0x00001];
+    pseudo_bit_t	i0[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	i1[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	i2[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	f0[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	f1[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	f2[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	reserved3[0x00001];
+    pseudo_bit_t	ev_cnt1[0x00005];      /* Specifies event to be counted by Event_counter1 See XXX for events' definition. */
+    pseudo_bit_t	reserved4[0x00003];
+    pseudo_bit_t	ev_cnt2[0x00005];      /* Specifies event to be counted by Event_counter2 See XXX for events' definition. */
+    pseudo_bit_t	reserved5[0x00003];
+/* -------------- */
+    pseudo_bit_t	clock_counter[0x00020];
+/* -------------- */
+    pseudo_bit_t	event_counter1[0x00020];
+/* -------------- */
+    pseudo_bit_t	event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */
+/* -------------- */
+}; 
+
+/* Receive segment format */
+
+struct arbelprm_wqe_segment_ctrl_recv_st {	/* Little Endian */
+    struct arbelprm_recv_wqe_segment_next_st	wqe_segment_next;
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	reserved1[0x00001];
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	reserved3[0x0001c];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+}; 
+
+/* MLX WQE segment format */
+
+struct arbelprm_wqe_segment_ctrl_mlx_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	e[0x00001];            /* WQE event */
+    pseudo_bit_t	c[0x00001];            /* Create CQE (for "requested signalling" QP) */
+    pseudo_bit_t	icrc[0x00002];         /* icrc field detemines what to do with the last dword of the packet: 0 - Calculate ICRC and put it instead of last dword. Last dword must be 0x0. 1,2 - reserved.  3 - Leave last dword as is. Last dword must not be 0x0. */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	sl[0x00004];
+    pseudo_bit_t	max_statrate[0x00004];
+    pseudo_bit_t	slr[0x00001];          /* 0= take slid from port. 1= take slid from given headers */
+    pseudo_bit_t	v15[0x00001];          /* Send packet over VL15 */
+    pseudo_bit_t	reserved2[0x0000e];
+/* -------------- */
+    pseudo_bit_t	vcrc[0x00010];         /* Packet's VCRC (if not 0 - otherwise computed by HW) */
+    pseudo_bit_t	rlid[0x00010];         /* Destination LID (must match given headers) */
+/* -------------- */
+}; 
+
+/* Send WQE segment format */
+
+struct arbelprm_send_wqe_segment_st {	/* Little Endian */
+    struct arbelprm_wqe_segment_next_st	wqe_segment_next;/* Send wqe segment next */
+/* -------------- */
+    struct arbelprm_wqe_segment_ctrl_send_st	wqe_segment_ctrl_send;/* Send wqe segment ctrl */
+/* -------------- */
+    struct arbelprm_wqe_segment_rd_st	wqe_segment_rd;/* Send wqe segment rd */
+/* -------------- */
+    struct arbelprm_wqe_segment_ud_st	wqe_segment_ud;/* Send wqe segment ud */
+/* -------------- */
+    struct arbelprm_wqe_segment_bind_st	wqe_segment_bind;/* Send wqe segment bind */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00180];
+/* -------------- */
+    struct arbelprm_wqe_segment_remote_address_st	wqe_segment_remote_address;/* Send wqe segment remote address */
+/* -------------- */
+    struct arbelprm_wqe_segment_atomic_st	wqe_segment_atomic;/* Send wqe segment atomic */
+/* -------------- */
+    struct arbelprm_fast_registration_segment_st	fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+    struct arbelprm_local_invalidate_segment_st	local_invalidate_segment;/* local invalidate segment */
+/* -------------- */
+    struct arbelprm_wqe_segment_data_ptr_st	wqe_segment_data_ptr;/* Send wqe segment data ptr */
+/* -------------- */
+    struct arbelprm_wqe_segment_data_inline_st	wqe_segment_data_inline;/* Send wqe segment data inline */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00200];
+/* -------------- */
+}; 
+
+/* QP and EE Context Entry */
+
+struct arbelprm_queue_pair_ee_context_entry_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	de[0x00001];           /* Send/Receive Descriptor Event enable - if set, events can be generated upon descriptors' completion on send/receive queue (controlled by E bit in WQE). Invalid in EE context */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	pm_state[0x00002];     /* Path migration state (Migrated, Armed or Rearm)
+                                                 11-Migrated
+                                                 00-Armed
+                                                 01-Rearm
+                                                 10-Reserved
+                                                 Should be set to 11 for UD QPs and for QPs which do not support APM */
+    pseudo_bit_t	reserved2[0x00003];
+    pseudo_bit_t	st[0x00003];           /* Service type (invalid in EE context):
+                                                 000-Reliable Connection
+                                                 001-Unreliable Connection
+                                                 010-Reliable Datagram 
+                                                 011-Unreliable Datagram
+                                                 111-MLX transport (raw bits injection). Used for management QPs and RAW */
+    pseudo_bit_t	reserved3[0x00009];
+    pseudo_bit_t	state[0x00004];        /* QP/EE state:
+                                                 0 - RST
+                                                 1 - INIT
+                                                 2 - RTR
+                                                 3 - RTS
+                                                 4 - SQEr
+                                                 5 - SQD (Send Queue Drained)
+                                                 6 - ERR
+                                                 7 - Send Queue Draining
+                                                 8 - Reserved
+                                                 9 - Suspended
+                                                 A- F - Reserved
+                                                 (Valid for QUERY_QPEE and ERR2RST_QPEE commands only) */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	sched_queue[0x00004];  /* Schedule queue to be used for WQE scheduling to execution. Determines QOS for this QP. */
+    pseudo_bit_t	rlky[0x00001];         /* When set this QP can use the Reserved L_Key */
+    pseudo_bit_t	reserved5[0x00003];
+    pseudo_bit_t	log_sq_stride[0x00003];/* Stride on the send queue. WQ entry is 16*(2^log_SQ_stride) bytes.
+                                                 Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+    pseudo_bit_t	log_sq_size[0x00004];  /* Log2 of the Number of WQEs in the Send Queue. */
+    pseudo_bit_t	reserved6[0x00001];
+    pseudo_bit_t	log_rq_stride[0x00003];/* Stride on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes.
+                                                 Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+    pseudo_bit_t	log_rq_size[0x00004];  /* Log2 of the Number of WQEs in the Receive Queue. */
+    pseudo_bit_t	reserved7[0x00001];
+    pseudo_bit_t	msg_max[0x00005];      /* Max message size allowed on the QP. Maximum message size is 2^msg_Max.
+                                                 Must be equal to MTU for UD and MLX QPs. */
+    pseudo_bit_t	mtu[0x00003];          /* MTU of the QP (Must be the same for both paths: primary and alternative):
+                                                 0x1 - 256 bytes
+                                                 0x2 - 512
+                                                 0x3 - 1024
+                                                 0x4 - 2048
+                                                 other - reserved
+                                                 
+                                                 Should be configured to 0x4 for UD and MLX QPs. */
+/* -------------- */
+    pseudo_bit_t	usr_page[0x00018];     /* QP (see "non_privileged Access to the HCA Hardware"). Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved8[0x00008];
+/* -------------- */
+    pseudo_bit_t	local_qpn_een[0x00018];/* Local QP/EE number Lower bits determine position of this record in QPC table, and - thus - constrained
+                                                 This field is valid for QUERY and ERR2RST commands only. */
+    pseudo_bit_t	reserved9[0x00008];
+/* -------------- */
+    pseudo_bit_t	remote_qpn_een[0x00018];/* Remote QP/EE number */
+    pseudo_bit_t	reserved10[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00040];
+/* -------------- */
+    struct arbelprm_address_path_st	primary_address_path;/* Primary address path for the QP/EE */
+/* -------------- */
+    struct arbelprm_address_path_st	alternative_address_path;/* Alternate address path for the QP/EE */
+/* -------------- */
+    pseudo_bit_t	rdd[0x00018];          /* Reliable Datagram Domain */
+    pseudo_bit_t	reserved12[0x00008];
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* QP protection domain. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved13[0x00008];
+/* -------------- */
+    pseudo_bit_t	wqe_base_adr_h[0x00020];/* Bits 63:32 of WQE address for both SQ and RQ. 
+                                                 Reserved for EE context. */
+/* -------------- */
+    pseudo_bit_t	wqe_lkey[0x00020];     /* memory key (L-Key) to be used to access WQEs. Not valid (reserved) in EE context. */
+/* -------------- */
+    pseudo_bit_t	reserved14[0x00003];
+    pseudo_bit_t	ssc[0x00001];          /* Send Signaled Completion
+                                                 1 - all send WQEs generate CQEs. 
+                                                 0 - only send WQEs with C bit set generate completion. 
+                                                 Not valid (reserved) in EE context. */
+    pseudo_bit_t	sic[0x00001];          /* If set - Ignore end to end credits on send queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	cur_retry_cnt[0x00003];/* Current transport retry counter (QUERY_QPEE only).
+                                                 The current transport retry counter can vary from retry_count down to 1, where 1 means that the last retry attempt is currently executing. */
+    pseudo_bit_t	cur_rnr_retry[0x00003];/* Current RNR retry counter (QUERY_QPEE only).
+                                                 The current RNR retry counter can vary from rnr_retry to 1, where 1 means that the last retry attempt is currently executing. */
+    pseudo_bit_t	fre[0x00001];          /* Fast Registration Work Request Enabled. (Reserved for EE) */
+    pseudo_bit_t	reserved15[0x00001];
+    pseudo_bit_t	sae[0x00001];          /* If set - Atomic operations enabled on send queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	swe[0x00001];          /* If set - RDMA - write enabled on send queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	sre[0x00001];          /* If set - RDMA - read enabled on send queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	retry_count[0x00003];  /* Transport timeout Retry count */
+    pseudo_bit_t	reserved16[0x00002];
+    pseudo_bit_t	sra_max[0x00003];      /* Maximum number of outstanding RDMA-read/Atomic operations allowed in the send queue. Maximum number is 2^SRA_Max. Must be zero in EE context. */
+    pseudo_bit_t	flight_lim[0x00004];   /* Number of outstanding (in-flight) messages on the wire allowed for this send queue. 
+                                                 Number of outstanding messages is 2^Flight_Lim. 
+                                                 Use 0xF for unlimited number of outstanding messages. */
+    pseudo_bit_t	ack_req_freq[0x00004]; /* ACK required frequency. ACK required bit will be set in every 2^AckReqFreq packets at least. Not valid for RD QP. */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x00020];
+/* -------------- */
+    pseudo_bit_t	next_send_psn[0x00018];/* Next PSN to be sent */
+    pseudo_bit_t	reserved18[0x00008];
+/* -------------- */
+    pseudo_bit_t	cqn_snd[0x00018];      /* CQ number completions from the send queue to be reported to. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved19[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved20[0x00006];
+    pseudo_bit_t	snd_wqe_base_adr_l[0x0001a];/* While opening (creating) the WQ, this field should contain the address of first descriptor to be posted. Not valid (reserved) in EE context. */
+/* -------------- */
+    pseudo_bit_t	snd_db_record_index[0x00020];/* Index in the UAR Context Table Entry.
+                                                 HW uses this index as an offset from the UAR Context Table Entry in order to read this SQ doorbell record.
+                                                 The entry is obtained via the usr_page field.
+                                                 Not valid for EE. */
+/* -------------- */
+    pseudo_bit_t	last_acked_psn[0x00018];/* The last acknowledged PSN for the requester (QUERY_QPEE only) */
+    pseudo_bit_t	reserved21[0x00008];
+/* -------------- */
+    pseudo_bit_t	ssn[0x00018];          /* Requester Send Sequence Number (QUERY_QPEE only) */
+    pseudo_bit_t	reserved22[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved23[0x00003];
+    pseudo_bit_t	rsc[0x00001];          /* 1 - all receive WQEs generate CQEs. 
+                                                 0 - only receive WQEs with C bit set generate completion. 
+                                                 Not valid (reserved) in EE context.
+                                                  */
+    pseudo_bit_t	ric[0x00001];          /* Invalid Credits. 
+                                                 1 - place "Invalid Credits" to ACKs sent from this queue.
+                                                 0 - ACKs report the actual number of end to end credits on the connection.
+                                                 Not valid (reserved) in EE context.
+                                                 Must be set to 1 on QPs which are attached to SRQ. */
+    pseudo_bit_t	reserved24[0x00008];
+    pseudo_bit_t	rae[0x00001];          /* If set - Atomic operations enabled. on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	rwe[0x00001];          /* If set - RDMA - write enabled on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	rre[0x00001];          /* If set - RDMA - read enabled on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved25[0x00005];
+    pseudo_bit_t	rra_max[0x00003];      /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max. 
+                                                 Must be 0 for EE context. */
+    pseudo_bit_t	reserved26[0x00008];
+/* -------------- */
+    pseudo_bit_t	next_rcv_psn[0x00018]; /* Next (expected) PSN on receive */
+    pseudo_bit_t	min_rnr_nak[0x00005];  /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8). 
+                                                 Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved27[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved28[0x00005];
+    pseudo_bit_t	ra_buff_indx[0x0001b]; /* Index to outstanding read/atomic buffer. 
+                                                 This field constructs the address to the RDB for maintaining the incoming RDMA read and atomic requests. */
+/* -------------- */
+    pseudo_bit_t	cqn_rcv[0x00018];      /* CQ number completions from receive queue to be reported to. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved29[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved30[0x00006];
+    pseudo_bit_t	rcv_wqe_base_adr_l[0x0001a];/* While opening (creating) the WQ, this field should contain the address of first descriptor to be posted. Not valid (reserved) in EE context. */
+/* -------------- */
+    pseudo_bit_t	rcv_db_record_index[0x00020];/* Index in the UAR Context Table Entry containing the doorbell record for the receive queue. 
+                                                 HW uses this index as an offset from the UAR Context Table Entry in order to read this RQ doorbell record.
+                                                 The entry is obtained via the usr_page field.
+                                                 Not valid for EE. */
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];        /* Q_Key to be validated against received datagrams.
+                                                 On send datagrams, if Q_Key[31] specified in the WQE is set, then this Q_Key will be transmitted in the outgoing message.
+                                                 Not valid (reserved) in EE context. */
+/* -------------- */
+    pseudo_bit_t	srqn[0x00018];         /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors. 
+                                                 SRQN is valid only if SRQ bit is set. Not valid (reserved) in EE context. */
+    pseudo_bit_t	srq[0x00001];          /* SRQ - Shared Receive Queue. If this bit is set, then the QP is associated with a SRQ. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved31[0x00007];
+/* -------------- */
+    pseudo_bit_t	rmsn[0x00018];         /* Responder current message sequence number (QUERY_QPEE only) */
+    pseudo_bit_t	reserved32[0x00008];
+/* -------------- */
+    pseudo_bit_t	sq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the SQ.
+                                                 Must be 0x0 in SQ initialization.
+                                                 (QUERY_QPEE only). */
+    pseudo_bit_t	rq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the RQ.
+                                                 Must be 0x0 in RQ initialization.
+                                                 (QUERY_QPEE only). */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x00040];
+/* -------------- */
+}; 
+
+/* Clear Interrupt [63:0] */
+
+struct arbelprm_clr_int_st {	/* Little Endian */
+    pseudo_bit_t	clr_int_h[0x00020];    /* Clear Interrupt [63:32]
+                                                 Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. 
+                                                 This register is write-only. Reading from this register will cause undefined result
+                                                  */
+/* -------------- */
+    pseudo_bit_t	clr_int_l[0x00020];    /* Clear Interrupt [31:0]
+                                                 Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. 
+                                                 This register is write-only. Reading from this register will cause undefined result */
+/* -------------- */
+}; 
+
+/* EQ_Arm_DB_Region */
+
+struct arbelprm_eq_arm_db_region_st {	/* Little Endian */
+    pseudo_bit_t	eq_x_arm_h[0x00020];   /* EQ[63:32]  X state.
+                                                 This register is used to Arm EQs when setting the appropriate bits. */
+/* -------------- */
+    pseudo_bit_t	eq_x_arm_l[0x00020];   /* EQ[31:0]  X state.
+                                                 This register is used to Arm EQs when setting the appropriate bits. */
+/* -------------- */
+}; 
+
+/* EQ Set CI DBs Table */
+
+struct arbelprm_eq_set_ci_table_st {	/* Little Endian */
+    pseudo_bit_t	eq0_set_ci[0x00020];   /* EQ0_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq1_set_ci[0x00020];   /* EQ1_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq2_set_ci[0x00020];   /* EQ2_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq3_set_ci[0x00020];   /* EQ3_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq4_set_ci[0x00020];   /* EQ4_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq5_set_ci[0x00020];   /* EQ5_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq6_set_ci[0x00020];   /* EQ6_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq7_set_ci[0x00020];   /* EQ7_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq8_set_ci[0x00020];   /* EQ8_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq9_set_ci[0x00020];   /* EQ9_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq10_set_ci[0x00020];  /* EQ10_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq11_set_ci[0x00020];  /* EQ11_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq12_set_ci[0x00020];  /* EQ12_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq13_set_ci[0x00020];  /* EQ13_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved13[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq14_set_ci[0x00020];  /* EQ14_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved14[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq15_set_ci[0x00020];  /* EQ15_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq16_set_ci[0x00020];  /* EQ16_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved16[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq17_set_ci[0x00020];  /* EQ17_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq18_set_ci[0x00020];  /* EQ18_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved18[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq19_set_ci[0x00020];  /* EQ19_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved19[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq20_set_ci[0x00020];  /* EQ20_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved20[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq21_set_ci[0x00020];  /* EQ21_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved21[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq22_set_ci[0x00020];  /* EQ22_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved22[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq23_set_ci[0x00020];  /* EQ23_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved23[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq24_set_ci[0x00020];  /* EQ24_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved24[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq25_set_ci[0x00020];  /* EQ25_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved25[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq26_set_ci[0x00020];  /* EQ26_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved26[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq27_set_ci[0x00020];  /* EQ27_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved27[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq28_set_ci[0x00020];  /* EQ28_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved28[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq29_set_ci[0x00020];  /* EQ29_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved29[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq30_set_ci[0x00020];  /* EQ30_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved30[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq31_set_ci[0x00020];  /* EQ31_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved31[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq32_set_ci[0x00020];  /* EQ32_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved32[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq33_set_ci[0x00020];  /* EQ33_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq34_set_ci[0x00020];  /* EQ34_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved34[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq35_set_ci[0x00020];  /* EQ35_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved35[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq36_set_ci[0x00020];  /* EQ36_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved36[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq37_set_ci[0x00020];  /* EQ37_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved37[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq38_set_ci[0x00020];  /* EQ38_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved38[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq39_set_ci[0x00020];  /* EQ39_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved39[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq40_set_ci[0x00020];  /* EQ40_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved40[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq41_set_ci[0x00020];  /* EQ41_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved41[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq42_set_ci[0x00020];  /* EQ42_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved42[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq43_set_ci[0x00020];  /* EQ43_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved43[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq44_set_ci[0x00020];  /* EQ44_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved44[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq45_set_ci[0x00020];  /* EQ45_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved45[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq46_set_ci[0x00020];  /* EQ46_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved46[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq47_set_ci[0x00020];  /* EQ47_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved47[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq48_set_ci[0x00020];  /* EQ48_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved48[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq49_set_ci[0x00020];  /* EQ49_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved49[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq50_set_ci[0x00020];  /* EQ50_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved50[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq51_set_ci[0x00020];  /* EQ51_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved51[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq52_set_ci[0x00020];  /* EQ52_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved52[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq53_set_ci[0x00020];  /* EQ53_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved53[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq54_set_ci[0x00020];  /* EQ54_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved54[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq55_set_ci[0x00020];  /* EQ55_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved55[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq56_set_ci[0x00020];  /* EQ56_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved56[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq57_set_ci[0x00020];  /* EQ57_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved57[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq58_set_ci[0x00020];  /* EQ58_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved58[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq59_set_ci[0x00020];  /* EQ59_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved59[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq60_set_ci[0x00020];  /* EQ60_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved60[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq61_set_ci[0x00020];  /* EQ61_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved61[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq62_set_ci[0x00020];  /* EQ62_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved62[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq63_set_ci[0x00020];  /* EQ63_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved63[0x00020];
+/* -------------- */
+}; 
+
+/* InfiniHost-III-EX Configuration Registers */
+
+struct arbelprm_configuration_registers_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x403400];
+/* -------------- */
+    struct arbelprm_hca_command_register_st	hca_command_interface_register;/* HCA Command Register */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x3fcb20];
+/* -------------- */
+}; 
+
+/* QP_DB_Record */
+
+struct arbelprm_qp_db_record_st {	/* Little Endian */
+    pseudo_bit_t	counter[0x00010];      /* Modulo-64K counter of WQEs posted to the QP since its creation. Should be initialized to zero. */
+    pseudo_bit_t	reserved0[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	res[0x00003];          /* 0x3 for SQ
+                                                 0x4 for RQ 
+                                                 0x5 for SRQ */
+    pseudo_bit_t	qp_number[0x00018];    /* QP number */
+/* -------------- */
+}; 
+
+/* CQ_ARM_DB_Record */
+
+struct arbelprm_cq_arm_db_record_st {	/* Little Endian */
+    pseudo_bit_t	counter[0x00020];      /* CQ counter for the arming request */
+/* -------------- */
+    pseudo_bit_t	cmd[0x00003];          /* 0x0 - No command
+                                                 0x1 - Request notification for next Solicited completion event. Counter filed specifies the current CQ Consumer Counter.
+                                                 0x2 - Request notification for next Solicited or Unsolicited completion event. Counter filed specifies the current CQ Consumer counter.
+                                                 0x3 - Request notification for multiple completions (Arm-N). Counter filed specifies the value of the CQ Index that when reached by HW (i.e. HW generates a CQE into this Index) Event will be generated
+                                                 Other - Reserved */
+    pseudo_bit_t	cmd_sn[0x00002];       /* Command Sequence Number - See Table 35, "CQ Doorbell Layout" for definition of this filed */
+    pseudo_bit_t	res[0x00003];          /* Must be 0x2 */
+    pseudo_bit_t	cq_number[0x00018];    /* CQ number */
+/* -------------- */
+}; 
+
+/* CQ_CI_DB_Record */
+
+struct arbelprm_cq_ci_db_record_st {	/* Little Endian */
+    pseudo_bit_t	counter[0x00020];      /* CQ counter */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	res[0x00003];          /* Must be 0x1 */
+    pseudo_bit_t	cq_number[0x00018];    /* CQ number */
+/* -------------- */
+}; 
+
+/* Virtual_Physical_Mapping */
+
+struct arbelprm_virtual_physical_mapping_st {	/* Little Endian */
+    pseudo_bit_t	va_h[0x00020];         /* Virtual Address[63:32]. Valid only for MAP_ICM command. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x0000c];
+    pseudo_bit_t	va_l[0x00014];         /* Virtual Address[31:12]. Valid only for MAP_ICM command. */
+/* -------------- */
+    pseudo_bit_t	pa_h[0x00020];         /* Physical Address[63:32] */
+/* -------------- */
+    pseudo_bit_t	log2size[0x00006];     /* Log2 of the size in 4KB pages of the physical and virtual contiguous memory that starts at PA_L/H and VA_L/H */
+    pseudo_bit_t	reserved1[0x00006];
+    pseudo_bit_t	pa_l[0x00014];         /* Physical Address[31:12] */
+/* -------------- */
+}; 
+
+/* MOD_STAT_CFG */
+
+struct arbelprm_mod_stat_cfg_st {	/* Little Endian */
+    pseudo_bit_t	log_max_srqs[0x00005]; /* Log (base 2) of the number of SRQs to allocate (0 if no SRQs are required), valid only if srq bit is set. */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	srq[0x00001];          /* When set SRQs are supported */
+    pseudo_bit_t	srq_m[0x00001];        /* Modify SRQ parameters */
+    pseudo_bit_t	reserved1[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x007e0];
+/* -------------- */
+}; 
+
+/* SRQ Context */
+
+struct arbelprm_srq_context_st {	/* Little Endian */
+    pseudo_bit_t	srqn[0x00018];         /* SRQ number */
+    pseudo_bit_t	log_srq_size[0x00004]; /* Log2 of the Number of WQEs in the Receive Queue.
+                                                 Maximum value is 0x10, i.e. 16M WQEs. */
+    pseudo_bit_t	state[0x00004];        /* SRQ State:
+                                                 1111 - SW Ownership
+                                                 0000 - HW Ownership
+                                                 0001 - Error
+                                                 Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+    pseudo_bit_t	l_key[0x00020];        /* memory key (L-Key) to be used to access WQEs. */
+/* -------------- */
+    pseudo_bit_t	srq_db_record_index[0x00020];/* Index in the UAR Context Table Entry containing the doorbell record for the receive queue. 
+                                                 HW uses this index as an offset from the UAR Context Table Entry in order to read this SRQ doorbell record.
+                                                 The entry is obtained via the usr_page field. */
+/* -------------- */
+    pseudo_bit_t	usr_page[0x00018];     /* Index (offset) of user page allocated for this SRQ (see "non_privileged Access to the HCA Hardware"). Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	log_rq_stride[0x00003];/* Stride (max WQE size) on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes. */
+/* -------------- */
+    pseudo_bit_t	wqe_addr_h[0x00020];   /* Bits 63:32 of WQE address (WQE base address) */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00006];
+    pseudo_bit_t	srq_wqe_base_adr_l[0x0001a];/* While opening (creating) the SRQ, this field should contain the address of first descriptor to be posted. */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* SRQ protection domain. */
+    pseudo_bit_t	reserved2[0x00008];
+/* -------------- */
+    pseudo_bit_t	wqe_cnt[0x00010];      /* WQE count on the SRQ.
+                                                 Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+    pseudo_bit_t	lwm[0x00010];          /* Limit Water Mark - if the LWM is not zero, and the wqe_cnt drops below LWM when a WQE is dequeued from the SRQ, then a SRQ limit event is fired and the LWM is set to zero. */
+/* -------------- */
+    pseudo_bit_t	srq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the SQ.
+                                                 Must be 0x0 in SRQ initialization.
+                                                 (QUERY_SRQ only). */
+    pseudo_bit_t	reserved3[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00060];
+/* -------------- */
+}; 
+
+/* PBL */
+
+struct arbelprm_pbl_st {	/* Little Endian */
+    pseudo_bit_t	mtt_0_h[0x00020];      /* First MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_0_l[0x00020];      /* First MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_1_h[0x00020];      /* Second MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_1_l[0x00020];      /* Second MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_2_h[0x00020];      /* Third MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_2_l[0x00020];      /* Third MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_3_h[0x00020];      /* Fourth MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_3_l[0x00020];      /* Fourth MTT[31:0] */
+/* -------------- */
+}; 
+
+/* Performance Counters */
+
+struct arbelprm_performance_counters_st {	/* Little Endian */
+    pseudo_bit_t	sqpc_access_cnt[0x00020];/* SQPC cache access count */
+/* -------------- */
+    pseudo_bit_t	sqpc_miss_cnt[0x00020];/* SQPC cache miss count */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	rqpc_access_cnt[0x00020];/* RQPC cache access count */
+/* -------------- */
+    pseudo_bit_t	rqpc_miss_cnt[0x00020];/* RQPC cache miss count */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+    pseudo_bit_t	cqc_access_cnt[0x00020];/* CQC cache access count */
+/* -------------- */
+    pseudo_bit_t	cqc_miss_cnt[0x00020]; /* CQC cache miss count */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	tpt_access_cnt[0x00020];/* TPT cache access count */
+/* -------------- */
+    pseudo_bit_t	mpt_miss_cnt[0x00020]; /* MPT cache miss count */
+/* -------------- */
+    pseudo_bit_t	mtt_miss_cnt[0x00020]; /* MTT cache miss count */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00620];
+/* -------------- */
+}; 
+
+/* Transport and CI Error Counters */
+
+struct arbelprm_transport_and_ci_error_counters_st {	/* Little Endian */
+    pseudo_bit_t	rq_num_lle[0x00020];   /* Responder - number of local length errors */
+/* -------------- */
+    pseudo_bit_t	sq_num_lle[0x00020];   /* Requester - number of local length errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_lqpoe[0x00020]; /* Responder - number local QP operation error */
+/* -------------- */
+    pseudo_bit_t	sq_num_lqpoe[0x00020]; /* Requester - number local QP operation error */
+/* -------------- */
+    pseudo_bit_t	rq_num_leeoe[0x00020]; /* Responder - number local EE operation error */
+/* -------------- */
+    pseudo_bit_t	sq_num_leeoe[0x00020]; /* Requester - number local EE operation error */
+/* -------------- */
+    pseudo_bit_t	rq_num_lpe[0x00020];   /* Responder - number of local protection errors */
+/* -------------- */
+    pseudo_bit_t	sq_num_lpe[0x00020];   /* Requester - number of local protection errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_wrfe[0x00020];  /* Responder - number of CQEs with error. 
+                                                 Incremented each time a CQE with error is generated */
+/* -------------- */
+    pseudo_bit_t	sq_num_wrfe[0x00020];  /* Requester - number of CQEs with error. 
+                                                 Incremented each time a CQE with error is generated */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_mwbe[0x00020];  /* Requester - number of memory window bind errors */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_bre[0x00020];   /* Requester - number of bad response errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_lae[0x00020];   /* Responder - number of local access errors */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	sq_num_rire[0x00020];  /* Requester - number of remote invalid request errors
+                                                 NAK-Invalid Request on:
+                                                 1. Unsupported OpCode: Responder detected an unsupported OpCode.
+                                                 2. Unexpected OpCode: Responder detected an error in the sequence of OpCodes, such
+                                                 as a missing "Last" packet.
+                                                 Note: there is no PSN error, thus this does not indicate a dropped packet. */
+/* -------------- */
+    pseudo_bit_t	rq_num_rire[0x00020];  /* Responder - number of remote invalid request errors.
+                                                 NAK may or may not be sent.
+                                                 1. QP Async Affiliated Error: Unsupported or Reserved OpCode (RC,RD only):
+                                                 Inbound request OpCode was either reserved, or was for a function not supported by this
+                                                 QP. (E.g. RDMA or ATOMIC on QP not set up for this).
+                                                 2. Misaligned ATOMIC: VA does not point to an aligned address on an atomic opera-tion.
+                                                 3. Too many RDMA READ or ATOMIC Requests: There were more requests received
+                                                 and not ACKed than allowed for the connection.
+                                                 4. Out of Sequence OpCode, current packet is "First" or "Only": The Responder
+                                                 detected an error in the sequence of OpCodes; a missing "Last" packet
+                                                 5. Out of Sequence OpCode, current packet is not "First" or "Only": The Responder
+                                                 detected an error in the sequence of OpCodes; a missing "First" packet
+                                                 6. Local Length Error: Inbound "Send" request message exceeded the responder.s avail-able
+                                                 buffer space.
+                                                 7. Length error: RDMA WRITE request message contained too much or too little pay-load
+                                                 data compared to the DMA length advertised in the first or only packet.
+                                                 8. Length error: Payload length was not consistent with the opcode:
+                                                 a: 0 byte <= "only" <= PMTU bytes
+                                                 b: ("first" or "middle") == PMTU bytes
+                                                 c: 1byte <= "last" <= PMTU bytes
+                                                 9. Length error: Inbound message exceeded the size supported by the CA port. */
+/* -------------- */
+    pseudo_bit_t	sq_num_rae[0x00020];   /* Requester - number of remote access errors.
+                                                 NAK-Remote Access Error on:
+                                                 R_Key Violation: Responder detected an invalid R_Key while executing an RDMA
+                                                 Request. */
+/* -------------- */
+    pseudo_bit_t	rq_num_rae[0x00020];   /* Responder - number of remote access errors.
+                                                 R_Key Violation Responder detected an R_Key violation while executing an RDMA
+                                                 request.
+                                                 NAK may or may not be sent. */
+/* -------------- */
+    pseudo_bit_t	sq_num_roe[0x00020];   /* Requester - number of remote operation errors.
+                                                 NAK-Remote Operation Error on:
+                                                 Remote Operation Error: Responder encountered an error, (local to the responder),
+                                                 which prevented it from completing the request. */
+/* -------------- */
+    pseudo_bit_t	rq_num_roe[0x00020];   /* Responder - number of remote operation errors.
+                                                 NAK-Remote Operation Error on:
+                                                 1. Malformed WQE: Responder detected a malformed Receive Queue WQE while pro-cessing
+                                                 the packet.
+                                                 2. Remote Operation Error: Responder encountered an error, (local to the responder),
+                                                 which prevented it from completing the request. */
+/* -------------- */
+    pseudo_bit_t	sq_num_tree[0x00020];  /* Requester - number of transport retries exceeded errors */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_rree[0x00020];  /* Requester - number of RNR nak retries exceeded errors */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_lrdve[0x00020]; /* Requester - number of local RDD violation errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_rirdre[0x00020];/* Responder - number of remote invalid RD request errors */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00040];
+/* -------------- */
+    pseudo_bit_t	sq_num_rabrte[0x00020];/* Requester - number of remote aborted errors */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_ieecne[0x00020];/* Requester - number of invalid EE context number errors */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_ieecse[0x00020];/* Requester - invalid EE context state errors */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00380];
+/* -------------- */
+    pseudo_bit_t	rq_num_oos[0x00020];   /* Responder - number of out of sequence requests received */
+/* -------------- */
+    pseudo_bit_t	sq_num_oos[0x00020];   /* Requester - number of out of sequence Naks received */
+/* -------------- */
+    pseudo_bit_t	rq_num_mce[0x00020];   /* Responder - number of bad multicast packets received */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	rq_num_rsync[0x00020]; /* Responder - number of RESYNC operations */
+/* -------------- */
+    pseudo_bit_t	sq_num_rsync[0x00020]; /* Requester - number of RESYNC operations */
+/* -------------- */
+    pseudo_bit_t	rq_num_udsdprd[0x00020];/* The number of UD packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00020];
+/* -------------- */
+    pseudo_bit_t	rq_num_ucsdprd[0x00020];/* The number of UC packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+    pseudo_bit_t	reserved11[0x003e0];
+/* -------------- */
+    pseudo_bit_t	num_cqovf[0x00020];    /* Number of CQ overflows */
+/* -------------- */
+    pseudo_bit_t	num_eqovf[0x00020];    /* Number of EQ overflows */
+/* -------------- */
+    pseudo_bit_t	num_baddb[0x00020];    /* Number of bad doorbells */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x002a0];
+/* -------------- */
+}; 
+
+/* Event_data Field - HCR Completion Event */
+
+struct arbelprm_hcr_completion_event_st {	/* Little Endian */
+    pseudo_bit_t	token[0x00010];        /* HCR Token */
+    pseudo_bit_t	reserved0[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	status[0x00008];       /* HCR Status */
+    pseudo_bit_t	reserved2[0x00018];
+/* -------------- */
+    pseudo_bit_t	out_param_h[0x00020];  /* HCR Output Parameter [63:32] */
+/* -------------- */
+    pseudo_bit_t	out_param_l[0x00020];  /* HCR Output Parameter [31:0] */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+}; 
+
+/* Completion with Error CQE */
+
+struct arbelprm_completion_with_error_st {	/* Little Endian */
+    pseudo_bit_t	myqpn[0x00018];        /* Indicates the QP for which completion is being reported */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00060];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00010];
+    pseudo_bit_t	vendor_code[0x00008];
+    pseudo_bit_t	syndrome[0x00008];     /* Completion with error syndrome:
+                                                         0x01 - Local Length Error
+                                                         0x02 - Local QP Operation Error
+                                                         0x03 - Local EE Context Operation Error
+                                                         0x04 - Local Protection Error
+                                                         0x05 - Work Request Flushed Error 
+                                                         0x06 - Memory Window Bind Error
+                                                         0x10 - Bad Response Error
+                                                         0x11 - Local Access Error
+                                                         0x12 - Remote Invalid Request Error
+                                                         0x13 - Remote Access Error
+                                                         0x14 - Remote Operation Error
+                                                         0x15 - Transport Retry Counter Exceeded
+                                                         0x16 - RNR Retry Counter Exceeded
+                                                         0x20 - Local RDD Violation Error
+                                                         0x21 - Remote Invalid RD Request
+                                                         0x22 - Remote Aborted Error
+                                                         0x23 - Invalid EE Context Number
+                                                         0x24 - Invalid EE Context State
+                                                         other - Reserved
+                                                 Syndrome is defined according to the IB specification volume 1. For detailed explanation of the syndromes, refer to chapters 10-11 of the IB specification rev 1.1. */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00006];
+    pseudo_bit_t	wqe_addr[0x0001a];     /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00007];
+    pseudo_bit_t	owner[0x00001];        /* Owner field. Zero value of this field means SW ownership of CQE. */
+    pseudo_bit_t	reserved6[0x00010];
+    pseudo_bit_t	opcode[0x00008];       /* The opcode of WQE completion is reported for.
+                                                 
+                                                 The following values are reported in case of completion with error:
+                                                 0xFE - For completion with error on Receive Queues
+                                                 0xFF - For completion with error on Send Queues */
+/* -------------- */
+}; 
+
+/* Resize CQ Input Mailbox */
+
+struct arbelprm_resize_cq_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    pseudo_bit_t	start_addr_h[0x00020]; /* Start address of CQ[63:32]. 
+                                                 Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+    pseudo_bit_t	start_addr_l[0x00020]; /* Start address of CQ[31:0]. 
+                                                 Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00018];
+    pseudo_bit_t	log_cq_size[0x00005];  /* Log (base 2) of the CQ size (in entries) */
+    pseudo_bit_t	reserved2[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+    pseudo_bit_t	l_key[0x00020];        /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00100];
+/* -------------- */
+}; 
+
+/* MAD_IFC Input Modifier */
+
+struct arbelprm_mad_ifc_input_modifier_st {	/* Little Endian */
+    pseudo_bit_t	port_number[0x00008];  /* The packet reception port number (1 or 2). */
+    pseudo_bit_t	mad_extended_info[0x00001];/* Mad_Extended_Info valid bit (MAD_IFC Input Mailbox data from offset 00100h and down). MAD_Extended_Info is read only if this bit is set.
+                                                 Required for trap generation when BKey check is enabled and for global routed packets. */
+    pseudo_bit_t	reserved0[0x00007];
+    pseudo_bit_t	rlid[0x00010];         /* Remote (source) LID  from the received MAD.
+                                                 This field is required for trap generation upon MKey/BKey validation. */
+/* -------------- */
+}; 
+
+/* MAD_IFC Input Mailbox */
+
+struct arbelprm_mad_ifc_st {	/* Little Endian */
+    pseudo_bit_t	request_mad_packet[64][0x00020];/* Request MAD Packet (256bytes) */
+/* -------------- */
+    pseudo_bit_t	my_qpn[0x00018];       /* Destination QP number from the received MAD. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	rqpn[0x00018];         /* Remote (source) QP number  from the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (source) LID  from the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	ml_path[0x00007];      /* My (destination) LID path bits  from the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	g[0x00001];            /* If set, the GRH field in valid. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved2[0x00004];
+    pseudo_bit_t	sl[0x00004];           /* Service Level of the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+/* -------------- */
+    pseudo_bit_t	pkey_indx[0x00010];    /* Index in PKey table that matches PKey of the received MAD. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved3[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00180];
+/* -------------- */
+    pseudo_bit_t	grh[10][0x00020];      /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list. 
+                                                 Valid if Mad_extended_info bit (in the input modifier) and g bit are set. 
+                                                 Otherwise this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x004c0];
+/* -------------- */
+}; 
+
+/* Query Debug Message */
+
+struct arbelprm_query_debug_msg_st {	/* Little Endian */
+    pseudo_bit_t	phy_addr_h[0x00020];   /* Translation of the address in firmware area. High 32 bits. */
+/* -------------- */
+    pseudo_bit_t	v[0x00001];            /* Physical translation is valid */
+    pseudo_bit_t	reserved0[0x0000b];
+    pseudo_bit_t	phy_addr_l[0x00014];   /* Translation of the address in firmware area. Low 32 bits. */
+/* -------------- */
+    pseudo_bit_t	fw_area_base[0x00020]; /* Firmware area base address. The format strings and the trace buffers may be located starting from this address. */
+/* -------------- */
+    pseudo_bit_t	fw_area_size[0x00020]; /* Firmware area size */
+/* -------------- */
+    pseudo_bit_t	trc_hdr_sz[0x00020];   /* Trace message header size in dwords. */
+/* -------------- */
+    pseudo_bit_t	trc_arg_num[0x00020];  /* The number of arguments per trace message. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x000c0];
+/* -------------- */
+    pseudo_bit_t	dbg_msk_h[0x00020];    /* Debug messages mask [63:32] */
+/* -------------- */
+    pseudo_bit_t	dbg_msk_l[0x00020];    /* Debug messages mask [31:0] */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	buff0_addr[0x00020];   /* Address in firmware area of Trace Buffer 0 */
+/* -------------- */
+    pseudo_bit_t	buff0_size[0x00020];   /* Size of Trace Buffer 0 */
+/* -------------- */
+    pseudo_bit_t	buff1_addr[0x00020];   /* Address in firmware area of Trace Buffer 1 */
+/* -------------- */
+    pseudo_bit_t	buff1_size[0x00020];   /* Size of Trace Buffer 1 */
+/* -------------- */
+    pseudo_bit_t	buff2_addr[0x00020];   /* Address in firmware area of Trace Buffer 2 */
+/* -------------- */
+    pseudo_bit_t	buff2_size[0x00020];   /* Size of Trace Buffer 2 */
+/* -------------- */
+    pseudo_bit_t	buff3_addr[0x00020];   /* Address in firmware area of Trace Buffer 3 */
+/* -------------- */
+    pseudo_bit_t	buff3_size[0x00020];   /* Size of Trace Buffer 3 */
+/* -------------- */
+    pseudo_bit_t	buff4_addr[0x00020];   /* Address in firmware area of Trace Buffer 4 */
+/* -------------- */
+    pseudo_bit_t	buff4_size[0x00020];   /* Size of Trace Buffer 4 */
+/* -------------- */
+    pseudo_bit_t	buff5_addr[0x00020];   /* Address in firmware area of Trace Buffer 5 */
+/* -------------- */
+    pseudo_bit_t	buff5_size[0x00020];   /* Size of Trace Buffer 5 */
+/* -------------- */
+    pseudo_bit_t	buff6_addr[0x00020];   /* Address in firmware area of Trace Buffer 6 */
+/* -------------- */
+    pseudo_bit_t	buff6_size[0x00020];   /* Size of Trace Buffer 6 */
+/* -------------- */
+    pseudo_bit_t	buff7_addr[0x00020];   /* Address in firmware area of Trace Buffer 7 */
+/* -------------- */
+    pseudo_bit_t	buff7_size[0x00020];   /* Size of Trace Buffer 7 */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00400];
+/* -------------- */
+}; 
+
+/* User Access Region */
+
+struct arbelprm_uar_st {	/* Little Endian */
+    struct arbelprm_rd_send_doorbell_st	rd_send_doorbell;/* Reliable Datagram send doorbell */
+/* -------------- */
+    struct arbelprm_send_doorbell_st	send_doorbell;/* Send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    struct arbelprm_cq_cmd_doorbell_st	cq_command_doorbell;/* CQ Doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x03ec0];
+/* -------------- */
+}; 
+
+/* Receive doorbell */
+
+struct arbelprm_receive_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	wqe_counter[0x00010];  /* Modulo-64K counter of WQEs posted on this queue since its creation. Should be zero for the first doorbell on the QP */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00005];
+    pseudo_bit_t	srq[0x00001];          /* If set, this is a Shared Receive Queue */
+    pseudo_bit_t	reserved3[0x00002];
+    pseudo_bit_t	qpn[0x00018];          /* QP number or SRQ number this doorbell is rung on */
+/* -------------- */
+}; 
+
+/* SET_IB Parameters */
+
+struct arbelprm_set_ib_st {	/* Little Endian */
+    pseudo_bit_t	rqk[0x00001];          /* Reset QKey Violation Counter */
+    pseudo_bit_t	reserved0[0x00011];
+    pseudo_bit_t	sig[0x00001];          /* Set System Image GUID to system_image_guid specified.
+                                                 system_image_guid and sig must be the same for all ports. */
+    pseudo_bit_t	reserved1[0x0000d];
+/* -------------- */
+    pseudo_bit_t	capability_mask[0x00020];/* PortInfo Capability Mask */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00180];
+/* -------------- */
+}; 
+
+/* Multicast Group Member */
+
+struct arbelprm_mgm_entry_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	next_gid_index[0x0001a];/* Index of next Multicast Group Member whose GID maps to same MGID_HASH number.
+                                                 The index is into the Multicast Group Table, which is the comprised the MGHT and AMGM tables.
+                                                 next_gid_index=0 means end of the chain. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00060];
+/* -------------- */
+    pseudo_bit_t	mgid_128_96[0x00020];  /* Multicast group GID[128:96] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_95_64[0x00020];   /* Multicast group GID[95:64] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_63_32[0x00020];   /* Multicast group GID[63:32] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_31_0[0x00020];    /* Multicast group GID[31:0] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_0;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_1;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_2;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_3;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_4;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_5;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_6;   /* Multicast Group Member QP */
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp_7;   /* Multicast Group Member QP */
+/* -------------- */
+}; 
+
+/* INIT_IB Parameters */
+
+struct arbelprm_init_ib_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00004];
+    pseudo_bit_t	vl_cap[0x00004];       /* Maximum VLs supported on the port, excluding VL15.
+                                                 Legal values are 1,2,4 and 8. */
+    pseudo_bit_t	port_width_cap[0x00004];/* IB Port Width
+                                                 1   - 1x
+                                                 3   - 1x, 4x
+                                                 11 - 1x, 4x or 12x (must not be used in InfiniHost-III-EX MT25208)
+                                                 else - Reserved */
+    pseudo_bit_t	mtu_cap[0x00004];      /* Maximum MTU Supported
+                                                 0x0 - Reserved
+                                                 0x1 - 256
+                                                 0x2 - 512
+                                                 0x3 - 1024
+                                                 0x4 - 2048
+                                                 0x5 - 0xF Reserved */
+    pseudo_bit_t	g0[0x00001];           /* Set port GUID0 to GUID0 specified */
+    pseudo_bit_t	ng[0x00001];           /* Set node GUID to node_guid specified.
+                                                 node_guid and ng must be the same for all ports. */
+    pseudo_bit_t	sig[0x00001];          /* Set System Image GUID to system_image_guid specified.
+                                                 system_image_guid and sig must be the same for all ports. */
+    pseudo_bit_t	reserved1[0x0000d];
+/* -------------- */
+    pseudo_bit_t	max_gid[0x00010];      /* Maximum number of GIDs for the port */
+    pseudo_bit_t	reserved2[0x00010];
+/* -------------- */
+    pseudo_bit_t	max_pkey[0x00010];     /* Maximum pkeys for the port.
+                                                 Must be the same for both ports. */
+    pseudo_bit_t	reserved3[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	guid0_h[0x00020];      /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 63:32) */
+/* -------------- */
+    pseudo_bit_t	guid0_l[0x00020];      /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 31:0) */
+/* -------------- */
+    pseudo_bit_t	node_guid_h[0x00020];  /* Node GUID[63:32], takes effect only if the NG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	node_guid_l[0x00020];  /* Node GUID[31:0], takes effect only if the NG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x006c0];
+/* -------------- */
+}; 
+
+/* Query Device Limitations */
+
+struct arbelprm_query_dev_lim_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	log_max_qp[0x00005];   /* Log2 of the Maximum number of QPs supported */
+    pseudo_bit_t	reserved1[0x00003];
+    pseudo_bit_t	log2_rsvd_qps[0x00004];/* Log (base 2) of the number of QPs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_qps-1 */
+    pseudo_bit_t	reserved2[0x00004];
+    pseudo_bit_t	log_max_qp_sz[0x00008];/* The maximum number of WQEs allowed on the RQ or the SQ is 2^log_max_qp_sz-1 */
+    pseudo_bit_t	log_max_srq_sz[0x00008];/* The maximum number of WQEs allowed on the SRQ is 2^log_max_srq_sz-1 */
+/* -------------- */
+    pseudo_bit_t	log_max_ee[0x00005];   /* Log2 of the Maximum number of EE contexts supported */
+    pseudo_bit_t	reserved3[0x00003];
+    pseudo_bit_t	log2_rsvd_ees[0x00004];/* Log (base 2) of the number of EECs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_ees-1 */
+    pseudo_bit_t	reserved4[0x00004];
+    pseudo_bit_t	log_max_srqs[0x00005]; /* Log base 2 of the maximum number of SRQs supported, valid only if SRQ bit is set.
+                                                  */
+    pseudo_bit_t	reserved5[0x00007];
+    pseudo_bit_t	log2_rsvd_srqs[0x00004];/* Log (base 2) of the number of reserved SRQs for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_srqs-1
+                                                 This parameter is valid only if the SRQ bit is set. */
+/* -------------- */
+    pseudo_bit_t	log_max_cq[0x00005];   /* Log2 of the Maximum number of CQs supported */
+    pseudo_bit_t	reserved6[0x00003];
+    pseudo_bit_t	log2_rsvd_cqs[0x00004];/* Log (base 2) of the number of CQs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsrvd_cqs-1 */
+    pseudo_bit_t	reserved7[0x00004];
+    pseudo_bit_t	log_max_cq_sz[0x00008];/* Log2 of the Maximum CQEs allowed in a CQ */
+    pseudo_bit_t	reserved8[0x00008];
+/* -------------- */
+    pseudo_bit_t	log_max_eq[0x00003];   /* Log2 of the Maximum number of EQs */
+    pseudo_bit_t	reserved9[0x00005];
+    pseudo_bit_t	num_rsvd_eqs[0x00004]; /* The number of EQs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_rsvd_eqs-1
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	reserved10[0x00004];
+    pseudo_bit_t	log_max_mpts[0x00006]; /* Log (base 2) of the maximum number of MPT entries (the number of Regions/Windows) */
+    pseudo_bit_t	reserved11[0x00002];
+    pseudo_bit_t	log_max_eq_sz[0x00008];/* Log2 of the Maximum EQEs allowed in a EQ */
+/* -------------- */
+    pseudo_bit_t	log_max_mtts[0x00006]; /* Log2 of the Maximum number of MTT entries */
+    pseudo_bit_t	reserved12[0x00002];
+    pseudo_bit_t	log2_rsvd_mrws[0x00004];/* Log (base 2) of the number of MPTs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_mrws-1 */
+    pseudo_bit_t	reserved13[0x00004];
+    pseudo_bit_t	log_max_mrw_sz[0x00008];/* Log2 of the Maximum Size of Memory Region/Window */
+    pseudo_bit_t	reserved14[0x00004];
+    pseudo_bit_t	log2_rsvd_mtts[0x00004];/* Log (base 2) of the number of MTT entries reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_mtts-1
+                                                  */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00020];
+/* -------------- */
+    pseudo_bit_t	log_max_ra_res_qp[0x00006];/* Log2 of the Maximum number of outstanding RDMA read/Atomic per QP as a responder */
+    pseudo_bit_t	reserved16[0x0000a];
+    pseudo_bit_t	log_max_ra_req_qp[0x00006];/* Log2 of the maximum number of outstanding RDMA read/Atomic per QP as a requester */
+    pseudo_bit_t	reserved17[0x0000a];
+/* -------------- */
+    pseudo_bit_t	log_max_ra_res_global[0x00006];/* Log2 of the maximum number of RDMA read/atomic operations the HCA responder can support globally. That implies the RDB table size. */
+    pseudo_bit_t	reserved18[0x00016];
+    pseudo_bit_t	log2_rsvd_rdbs[0x00004];/* Log (base 2) of the number of RDB entries reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_rdbs-1 */
+/* -------------- */
+    pseudo_bit_t	rsz_srq[0x00001];      /* Ability to modify the maximum number of WRs per SRQ. */
+    pseudo_bit_t	reserved19[0x0001f];
+/* -------------- */
+    pseudo_bit_t	num_ports[0x00004];    /* Number of IB ports. */
+    pseudo_bit_t	max_vl[0x00004];       /* Maximum VLs supported on each port, excluding VL15 */
+    pseudo_bit_t	max_port_width[0x00004];/* IB Port Width
+                                                 1   - 1x
+                                                 3   - 1x, 4x
+                                                 11 - 1x, 4x or 12x
+                                                 else - Reserved */
+    pseudo_bit_t	max_mtu[0x00004];      /* Maximum MTU Supported
+                                                 0x0 - Reserved
+                                                 0x1 - 256
+                                                 0x2 - 512
+                                                 0x3 - 1024
+                                                 0x4 - 2048
+                                                 0x5 - 0xF Reserved */
+    pseudo_bit_t	local_ca_ack_delay[0x00005];/* The Local CA ACK Delay. This is the value recommended to be returned in Query HCA verb.
+                                                 The delay value in microseconds is computed using 4.096us * 2^(local_ca_ack_delay). */
+    pseudo_bit_t	reserved20[0x0000b];
+/* -------------- */
+    pseudo_bit_t	log_max_gid[0x00004];  /* Log2 of the maximum number of GIDs per port */
+    pseudo_bit_t	reserved21[0x0001c];
+/* -------------- */
+    pseudo_bit_t	log_max_pkey[0x00004]; /* Log2 of the max PKey Table Size (per IB port) */
+    pseudo_bit_t	reserved22[0x0000c];
+    pseudo_bit_t	stat_rate_support[0x00010];/* bit mask of stat rate supported
+                                                 bit 0 - full bw
+                                                 bit 1 - 1/4 bw
+                                                 bit 2 - 1/8 bw
+                                                 bit 3 - 1/2 bw; */
+/* -------------- */
+    pseudo_bit_t	reserved23[0x00020];
+/* -------------- */
+    pseudo_bit_t	rc[0x00001];           /* RC Transport supported */
+    pseudo_bit_t	uc[0x00001];           /* UC Transport Supported */
+    pseudo_bit_t	ud[0x00001];           /* UD Transport Supported */
+    pseudo_bit_t	rd[0x00001];           /* RD Transport Supported */
+    pseudo_bit_t	raw_ipv6[0x00001];     /* Raw IPv6 Transport Supported */
+    pseudo_bit_t	raw_ether[0x00001];    /* Raw Ethertype Transport Supported */
+    pseudo_bit_t	srq[0x00001];          /* SRQ is supported
+                                                  */
+    pseudo_bit_t	ipo_ib_checksum[0x00001];/* IP over IB checksum is supported */
+    pseudo_bit_t	pkv[0x00001];          /* PKey Violation Counter Supported */
+    pseudo_bit_t	qkv[0x00001];          /* QKey Violation Coutner Supported */
+    pseudo_bit_t	reserved24[0x00006];
+    pseudo_bit_t	mw[0x00001];           /* Memory windows supported */
+    pseudo_bit_t	apm[0x00001];          /* Automatic Path Migration Supported */
+    pseudo_bit_t	atm[0x00001];          /* Atomic operations supported (atomicity is guaranteed between QPs on this HCA) */
+    pseudo_bit_t	rm[0x00001];           /* Raw Multicast Supported */
+    pseudo_bit_t	avp[0x00001];          /* Address Vector Port checking supported */
+    pseudo_bit_t	udm[0x00001];          /* UD Multicast Supported */
+    pseudo_bit_t	reserved25[0x00002];
+    pseudo_bit_t	pg[0x00001];           /* Paging on demand supported */
+    pseudo_bit_t	r[0x00001];            /* Router mode supported */
+    pseudo_bit_t	reserved26[0x00006];
+/* -------------- */
+    pseudo_bit_t	log_pg_sz[0x00008];    /* Minimum system page size supported (log2).
+                                                 For proper operation it must be less than or equal the hosting platform (CPU) minimum page size. */
+    pseudo_bit_t	reserved27[0x00008];
+    pseudo_bit_t	uar_sz[0x00006];       /* UAR Area Size = 1MB * 2^uar_sz */
+    pseudo_bit_t	reserved28[0x00006];
+    pseudo_bit_t	num_rsvd_uars[0x00004];/* The number of UARs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_uars-1
+                                                 Note that UAR number num_reserved_uars is always for the kernel. */
+/* -------------- */
+    pseudo_bit_t	reserved29[0x00020];
+/* -------------- */
+    pseudo_bit_t	max_desc_sz_sq[0x00010];/* Max descriptor size in bytes for the send queue */
+    pseudo_bit_t	max_sg_sq[0x00008];    /* The maximum S/G list elements in a SQ WQE (max_desc_sz/16 - 3) */
+    pseudo_bit_t	reserved30[0x00008];
+/* -------------- */
+    pseudo_bit_t	max_desc_sz_rq[0x00010];/* Max descriptor size in bytes for the receive queue */
+    pseudo_bit_t	max_sg_rq[0x00008];    /* The maximum S/G list elements in a RQ WQE (max_desc_sz/16 - 3) */
+    pseudo_bit_t	reserved31[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved32[0x00040];
+/* -------------- */
+    pseudo_bit_t	log_max_mcg[0x00008];  /* Log2 of the maximum number of multicast groups */
+    pseudo_bit_t	num_rsvd_mcgs[0x00004];/* The number of MGMs reserved for firmware use in the MGHT.
+                                                 The reserved resources are numbered from 0 to num_reserved_mcgs-1
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	reserved33[0x00004];
+    pseudo_bit_t	log_max_qp_mcg[0x00008];/* Log2 of the maximum number of QPs per multicast group */
+    pseudo_bit_t	reserved34[0x00008];
+/* -------------- */
+    pseudo_bit_t	log_max_rdds[0x00006]; /* Log2 of the maximum number of RDDs */
+    pseudo_bit_t	reserved35[0x00006];
+    pseudo_bit_t	num_rsvd_rdds[0x00004];/* The number of RDDs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_rdds-1.
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	log_max_pd[0x00006];   /* Log2 of the maximum number of PDs */
+    pseudo_bit_t	reserved36[0x00006];
+    pseudo_bit_t	num_rsvd_pds[0x00004]; /* The number of PDs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_pds-1
+                                                 If 0 - no resources are reserved. */
+/* -------------- */
+    pseudo_bit_t	reserved37[0x000c0];
+/* -------------- */
+    pseudo_bit_t	qpc_entry_sz[0x00010]; /* QPC Entry Size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+    pseudo_bit_t	eec_entry_sz[0x00010]; /* EEC Entry Size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+/* -------------- */
+    pseudo_bit_t	eqpc_entry_sz[0x00010];/* Extended QPC entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+    pseudo_bit_t	eeec_entry_sz[0x00010];/* Extended EEC entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+/* -------------- */
+    pseudo_bit_t	cqc_entry_sz[0x00010]; /* CQC entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+    pseudo_bit_t	eqc_entry_sz[0x00010]; /* EQ context entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+/* -------------- */
+    pseudo_bit_t	uar_scratch_entry_sz[0x00010];/* UAR Scratchpad Entry Size
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+    pseudo_bit_t	srq_entry_sz[0x00010]; /* SRQ context entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+/* -------------- */
+    pseudo_bit_t	mpt_entry_sz[0x00010]; /* MPT entry size in Bytes for the device.
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+    pseudo_bit_t	mtt_entry_sz[0x00010]; /* MTT entry size in Bytes for the device.
+                                                 For the InfiniHost-III-EX MT25208 entry size is 8 bytes */
+/* -------------- */
+    pseudo_bit_t	bmme[0x00001];         /* Base Memory Management Extension Support */
+    pseudo_bit_t	win_type[0x00001];     /* Bound Type 2 Memory Window Association mechanism:
+                                                 0 - Type 2A - QP Number Association; or
+                                                 1 - Type 2B - QP Number and PD Association. */
+    pseudo_bit_t	mps[0x00001];          /* Ability of this HCA to support multiple page sizes per Memory Region. */
+    pseudo_bit_t	bl[0x00001];           /* Ability of this HCA to support Block List Physical Buffer Lists. (The device does not supports Block List) */
+    pseudo_bit_t	zb[0x00001];           /* Zero Based region/windows supported */
+    pseudo_bit_t	lif[0x00001];          /* Ability of this HCA to support Local Invalidate Fencing. */
+    pseudo_bit_t	reserved38[0x00002];
+    pseudo_bit_t	log_pbl_sz[0x00006];   /* Log2 of the Maximum Physical Buffer List size in Bytes supported by this HCA when invoking the Allocate L_Key verb.
+                                                  */
+    pseudo_bit_t	reserved39[0x00012];
+/* -------------- */
+    pseudo_bit_t	resd_lkey[0x00020];    /* The value of the reserved Lkey for Base Memory Management Extension */
+/* -------------- */
+    pseudo_bit_t	lamr[0x00001];         /* When set the device requires local attached memory in order to operate.
+                                                 When set,  ICM pages, Firmware Area and ICM auxiliary pages must be allocated in the local attached memory. */
+    pseudo_bit_t	reserved40[0x0001f];
+/* -------------- */
+    pseudo_bit_t	max_icm_size_h[0x00020];/* Bits [63:32] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+    pseudo_bit_t	max_icm_size_l[0x00020];/* Bits [31:0] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+    pseudo_bit_t	reserved41[0x002c0];
+/* -------------- */
+}; 
+
+/* QUERY_ADAPTER Parameters Block */
+
+struct arbelprm_query_adapter_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00018];
+    pseudo_bit_t	intapin[0x00008];      /* Driver should set this field to INTR value in the event queue in order to get Express interrupt messages. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00060];
+/* -------------- */
+    struct arbelprm_vsd_st	vsd;
+/* -------------- */
+}; 
+
+/* QUERY_FW Parameters Block */
+
+struct arbelprm_query_fw_st {	/* Little Endian */
+    pseudo_bit_t	fw_rev_major[0x00010]; /* Firmware Revision - Major */
+    pseudo_bit_t	fw_pages[0x00010];     /* Amount of physical memory to be allocated for FW usage is in 4KByte pages. */
+/* -------------- */
+    pseudo_bit_t	fw_rev_minor[0x00010]; /* Firmware Revision - Minor */
+    pseudo_bit_t	fw_rev_subminor[0x00010];/* Firmware Sub-minor version (Patch level). */
+/* -------------- */
+    pseudo_bit_t	cmd_interface_rev[0x00010];/* Command Interface Interpreter Revision ID */
+    pseudo_bit_t	reserved0[0x0000e];
+    pseudo_bit_t	wqe_h_mode[0x00001];   /* Hermon mode. If '1', then WQE and AV format is the advanced format */
+    pseudo_bit_t	zb_wq_cq[0x00001];     /* If '1', then ZB mode of WQ and CQ are enabled (i.e. real Memfree PRM is supported) */
+/* -------------- */
+    pseudo_bit_t	log_max_outstanding_cmd[0x00008];/* Log2 of the maximum number of commands the HCR can support simultaneously */
+    pseudo_bit_t	reserved1[0x00017];
+    pseudo_bit_t	dt[0x00001];           /* Debug Trace Support
+                                                 0 - Debug trace is not supported 
+                                                 1 - Debug trace is supported */
+/* -------------- */
+    pseudo_bit_t	cmd_interface_db[0x00001];/* Set if the device accepts commands by means of special doorbells */
+    pseudo_bit_t	reserved2[0x0001f];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+    pseudo_bit_t	clr_int_base_addr_h[0x00020];/* Bits [63:32] of Clear interrupt register physical address. 
+                                                 Points to 64 bit register. */
+/* -------------- */
+    pseudo_bit_t	clr_int_base_addr_l[0x00020];/* Bits [31:0] of Clear interrupt register physical address. 
+                                                 Points to 64 bit register. */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00040];
+/* -------------- */
+    pseudo_bit_t	error_buf_start_h[0x00020];/* Read Only buffer for catastrophic error reports (physical address) */
+/* -------------- */
+    pseudo_bit_t	error_buf_start_l[0x00020];/* Read Only buffer for catastrophic error reports (physical address) */
+/* -------------- */
+    pseudo_bit_t	error_buf_size[0x00020];/* Size in words */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq_arm_base_addr_h[0x00020];/* Bits [63:32] of EQ Arm DBs physical address. 
+                                                 Points to 64 bit register.
+                                                 Setting bit x in the offset, arms EQ number x.
+                                                  */
+/* -------------- */
+    pseudo_bit_t	eq_arm_base_addr_l[0x00020];/* Bits [31:0] of EQ Arm DBs physical address. 
+                                                 Points to 64 bit register.
+                                                 Setting bit x in the offset, arms EQ number x. */
+/* -------------- */
+    pseudo_bit_t	eq_set_ci_base_addr_h[0x00020];/* Bits [63:32] of EQ Set CI DBs Table physical address.
+                                                 Points to a the EQ Set CI DBs Table base address. */
+/* -------------- */
+    pseudo_bit_t	eq_set_ci_base_addr_l[0x00020];/* Bits [31:0] of EQ Set CI DBs Table physical address.
+                                                 Points to a the EQ Set CI DBs Table base address. */
+/* -------------- */
+    pseudo_bit_t	cmd_db_dw1[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 1 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+    pseudo_bit_t	cmd_db_dw0[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 0 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	cmd_db_dw3[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 3 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+    pseudo_bit_t	cmd_db_dw2[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 2 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	cmd_db_dw5[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 5 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+    pseudo_bit_t	cmd_db_dw4[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 4 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	cmd_db_dw7[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 7 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+    pseudo_bit_t	cmd_db_dw6[0x00010];   /* offset in bytes from cmd_db_addr_base where DWord 6 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	cmd_db_addr_base_h[0x00020];/* High bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	cmd_db_addr_base_l[0x00020];/* Low  bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x004c0];
+/* -------------- */
+}; 
+
+/* ACCESS_LAM */
+
+struct arbelprm_access_lam_st {	/* Little Endian */
+    struct arbelprm_access_lam_inject_errors_st	access_lam_inject_errors;
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+}; 
+
+/* ENABLE_LAM Parameters Block */
+
+struct arbelprm_enable_lam_st {	/* Little Endian */
+    pseudo_bit_t	lam_start_adr_h[0x00020];/* LAM start address [63:32] */
+/* -------------- */
+    pseudo_bit_t	lam_start_adr_l[0x00020];/* LAM start address [31:0] */
+/* -------------- */
+    pseudo_bit_t	lam_end_adr_h[0x00020];/* LAM end address [63:32] */
+/* -------------- */
+    pseudo_bit_t	lam_end_adr_l[0x00020];/* LAM end address [31:0] */
+/* -------------- */
+    pseudo_bit_t	di[0x00002];           /* Data Integrity Configuration:
+                                                 00 - none
+                                                 01 - Parity
+                                                 10 - ECC Detection Only
+                                                 11 - ECC With Correction */
+    pseudo_bit_t	ap[0x00002];           /* Auto Precharge Mode
+                                                 00 - No auto precharge
+                                                 01 - Auto precharge per transaction
+                                                 10 - Auto precharge per 64 bytes
+                                                 11 - reserved */
+    pseudo_bit_t	dh[0x00001];           /* When set, LAM is Hidden and can not be accessed directly from the PCI bus. */
+    pseudo_bit_t	reserved0[0x0001b];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00160];
+/* -------------- */
+    struct arbelprm_dimminfo_st	dimm0;  /* Logical DIMM 0 Parameters */
+/* -------------- */
+    struct arbelprm_dimminfo_st	dimm1;  /* Logical DIMM 1 Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00400];
+/* -------------- */
+}; 
+
+/* Memory Access Parameters for UD Address Vector Table */
+
+struct arbelprm_udavtable_memory_parameters_st {	/* Little Endian */
+    pseudo_bit_t	l_key[0x00020];        /* L_Key used to access TPT */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* PD used by TPT for matching against PD of region entry being accessed. */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	xlation_en[0x00001];   /* When cleared, address is physical address and no translation will be done. When set, address is virtual. */
+    pseudo_bit_t	reserved1[0x00002];
+/* -------------- */
+}; 
+
+/* INIT_HCA & QUERY_HCA Parameters Block */
+
+struct arbelprm_init_hca_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00060];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00010];
+    pseudo_bit_t	time_stamp_granularity[0x00008];/* This field controls the granularity in which CQE Timestamp counter is incremented.
+                                                 The TimeStampGranularity units is 1/4 of a microseconds. (e.g is TimeStampGranularity is configured to 0x2, CQE Timestamp will be incremented every one microsecond)
+                                                 When sets to Zero, timestamp reporting in the CQE is disabled.
+                                                 This feature is currently not supported.
+                                                  */
+    pseudo_bit_t	hca_core_clock[0x00008];/* Internal Clock Period (in units of 1/16 ns) (QUERY_HCA only) */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00008];
+    pseudo_bit_t	router_qp[0x00010];    /* Upper 16 bit to be used as a QP number for router mode. Low order 8 bits are taken from the TClass field of the incoming packet.
+                                                 Valid only if RE bit is set */
+    pseudo_bit_t	reserved3[0x00007];
+    pseudo_bit_t	re[0x00001];           /* Router Mode Enable
+                                                 If this bit is set, entire packet (including all headers and ICRC) will be considered as a data payload and will be scattered to memory as specified in the descriptor that is posted on the QP matching the TClass field of packet. */
+/* -------------- */
+    pseudo_bit_t	udp[0x00001];          /* UD Port Check Enable
+                                                 0 - Port field in Address Vector is ignored
+                                                 1 - HCA will check the port field in AV entry (fetched for UD descriptor) against the Port of the UD QP executing the descriptor. */
+    pseudo_bit_t	he[0x00001];           /* Host Endianess - Used for Atomic Operations
+                                                 0 - Host is Little Endian
+                                                 1 - Host is Big endian
+                                                  */
+    pseudo_bit_t	reserved4[0x00001];
+    pseudo_bit_t	ce[0x00001];           /* Checksum Enabled - when Set IPoverIB checksum generation & checking is enabled */
+    pseudo_bit_t	sph[0x00001];          /* 0 - SW calculates TCP/UDP Pseudo-Header checksum and inserts it into the TCP/UDP checksum field when sending a packet
+                                                 1 - HW calculates TCP/UDP Pseudo-Header checksum when sending a packet
+                                                  */
+    pseudo_bit_t	rph[0x00001];          /* 0 - Not HW calculation of TCP/UDP Pseudo-Header checksum are done when receiving a packet
+                                                 1 - HW calculates TCP/UDP Pseudo-Header checksum when receiving a packet
+                                                  */
+    pseudo_bit_t	reserved5[0x00002];
+    pseudo_bit_t	responder_exu[0x00004];/* Indicate the relation between the execution enegines allocation dedicated for responder versus the engines dedicated for reqvester .
+                                                 responder_exu/16 = (number of responder exu engines)/(total number of engines)
+                                                 Legal values are 0x0-0xF. 0 is "auto".
+                                                 
+                                                  */
+    pseudo_bit_t	reserved6[0x00004];
+    pseudo_bit_t	wqe_quota[0x0000f];    /* Maximum number of WQEs that are executed prior to preemption of execution unit. 0 - reserved. */
+    pseudo_bit_t	wqe_quota_en[0x00001]; /* If set - wqe_quota field is used. If cleared - WQE quota is set to "auto" value */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00040];
+/* -------------- */
+    struct arbelprm_qpcbaseaddr_st	qpc_eec_cqc_eqc_rdb_parameters;
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00100];
+/* -------------- */
+    struct arbelprm_multicastparam_st	multicast_parameters;
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00080];
+/* -------------- */
+    struct arbelprm_tptparams_st	tpt_parameters;
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00080];
+/* -------------- */
+    struct arbelprm_uar_params_st	uar_parameters;/* UAR Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00600];
+/* -------------- */
+}; 
+
+/* Event Queue Context Table Entry */
+
+struct arbelprm_eqc_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	st[0x00004];           /* Event delivery state machine
+                                                 0x9 - Armed
+                                                 0xA - Fired
+                                                 0xB - Always_Armed (auto-rearm)
+                                                 other - reserved */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	oi[0x00001];           /* Oerrun ignore.
+                                                 If set, HW will not check EQ full condition when writing new EQEs. */
+    pseudo_bit_t	tr[0x00001];           /* Translation Required. If set - EQ access undergo address translation. */
+    pseudo_bit_t	reserved2[0x00005];
+    pseudo_bit_t	owner[0x00004];        /* 0 - SW ownership
+                                                 1 - HW ownership
+                                                 Valid for the QUERY_EQ and HW2SW_EQ commands only */
+    pseudo_bit_t	status[0x00004];       /* EQ status:
+                                                 0000 - OK
+                                                 1010 - EQ write failure
+                                                 Valid for the QUERY_EQ and HW2SW_EQ commands only */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];/* Start Address of Event Queue[63:32]. */
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];/* Start Address of Event Queue[31:0]. 
+                                                 Must be aligned on 32-byte boundary */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00018];
+    pseudo_bit_t	log_eq_size[0x00005];  /* Amount of entries in this EQ is 2^log_eq_size.
+                                                 Log_eq_size must be bigger than 1.
+                                                 Maximum EQ size is 2^17 EQEs (max Log_eq_size is 17). */
+    pseudo_bit_t	reserved4[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	intr[0x00008];         /* Interrupt (message) to be generated to report event to INT layer.
+                                                 00iiiiii - set to INTA given in QUERY_ADAPTER in order to generate INTA messages on Express.
+                                                 10jjjjjj - specificies type of interrupt message to be generated (total 64 different messages supported).
+                                                 All other values are reserved and should not be used.
+                                                 
+                                                 If interrupt generation is not required, ST field must be set upon creation to Fired state. No EQ arming doorbell should be performed. In this case hardware will not generate any interrupt. */
+    pseudo_bit_t	reserved6[0x00018];
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* PD to be used to access EQ */
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	lkey[0x00020];         /* Memory key (L-Key) to be used to access EQ */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00040];
+/* -------------- */
+    pseudo_bit_t	consumer_indx[0x00020];/* Contains next entry to be read upon polling the event queue.
+                                                 Must be initalized to zero while opening EQ */
+/* -------------- */
+    pseudo_bit_t	producer_indx[0x00020];/* Contains next entry in EQ to be written by the HCA.
+                                                 Must be initalized to zero while opening EQ. */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00080];
+/* -------------- */
+}; 
+
+/* Memory Translation Table (MTT) Entry */
+
+struct arbelprm_mtt_st {	/* Little Endian */
+    pseudo_bit_t	ptag_h[0x00020];       /* High-order bits of physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+    pseudo_bit_t	p[0x00001];            /* Present bit. If set, page entry is valid. If cleared, access to this page will generate non-present page access fault. */
+    pseudo_bit_t	reserved0[0x0000b];
+    pseudo_bit_t	ptag_l[0x00014];       /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+}; 
+
+/* Memory Protection Table (MPT) Entry */
+
+struct arbelprm_mpt_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	r_w[0x00001];          /* Defines whether this entry is Region (1) or Window (0) */
+    pseudo_bit_t	pa[0x00001];           /* Physical address. If set, no virtual-to-physical address translation will be performed for this region */
+    pseudo_bit_t	lr[0x00001];           /* If set - local read access enabled */
+    pseudo_bit_t	lw[0x00001];           /* If set - local write access enabled */
+    pseudo_bit_t	rr[0x00001];           /* If set - remote read access enabled. */
+    pseudo_bit_t	rw[0x00001];           /* If set - remote write access enabled */
+    pseudo_bit_t	a[0x00001];            /* If set - remote Atomic access is enabled */
+    pseudo_bit_t	eb[0x00001];           /* If set - Bind is enabled. Valid for region entry only. */
+    pseudo_bit_t	reserved1[0x0000c];
+    pseudo_bit_t	status[0x00004];       /* Region/Window Status
+                                                 0xF - not valid (SW ownership)
+                                                 0x3 - FREE state
+                                                 else - HW ownership
+                                                 Unbound Type I windows are doneted reg_wnd_len field equals zero.
+                                                 Unbound Type II windows are donated by Status=FREE. */
+/* -------------- */
+    pseudo_bit_t	page_size[0x00005];    /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+                                                 page_size should be less than 20. */
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	type[0x00001];         /* Applicable for windows only, must be zero for regions
+                                                 0 - Type one window
+                                                 1 - Type two window */
+    pseudo_bit_t	qpn[0x00018];          /* QP number this MW is attached to. Valid for type2 memory windows and on QUERY_MPT only */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* The memory Key. The field holds the mem_key field in the following semantics: {key[7:0],key[31:8]}.
+                                                  */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* Protection Domain */
+    pseudo_bit_t	reserved3[0x00001];
+    pseudo_bit_t	ei[0x00001];           /* Enable Invalidation - When set, Local/Remote invalidation can be executed on this window/region. 
+                                                 Must be set for type2 windows and non-shared physical memory regions.
+                                                 Must be clear for regions that are used to access Work Queues, Completion Queues and Event Queues */
+    pseudo_bit_t	zb[0x00001];           /* When set, this region is Zero Based Region */
+    pseudo_bit_t	fre[0x00001];          /* When set, Fast Registration Operations can be executed on this region */
+    pseudo_bit_t	rae[0x00001];          /* When set, remote access can be enabled on this region.
+                                                 Used when executing Fast Registration Work Request to validate that remote access rights can be granted to this MPT. 
+                                                 If the bit is cleared, Fast Registration Work Request requesting remote access rights will fail.
+                                                  */
+    pseudo_bit_t	reserved4[0x00003];
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region/window starts */
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region/window starts */
+/* -------------- */
+    pseudo_bit_t	reg_wnd_len_h[0x00020];/* Region/Window Length[63:32] */
+/* -------------- */
+    pseudo_bit_t	reg_wnd_len_l[0x00020];/* Region/Window Length[31:0] */
+/* -------------- */
+    pseudo_bit_t	lkey[0x00020];         /* Must be 0 for SW2HW_MPT.
+                                                 On QUERY_MPT and HW2SW_MPT commands for Memory Window it reflects the LKey of the Region that the Window is bound to.
+                                                 The field holds the lkey field in the following semantics: {key[7:0],key[31:8]}. */
+/* -------------- */
+    pseudo_bit_t	win_cnt[0x00020];      /* Number of windows bound to this region. Valid for regions only.
+                                                 The field is valid only for the QUERY_MPT and HW2SW_MPT commands. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	mtt_adr_h[0x00006];    /* Base (first) address of the MTT relative to MTT base in the ICM */
+    pseudo_bit_t	reserved6[0x0001a];
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00003];
+    pseudo_bit_t	mtt_adr_l[0x0001d];    /* Base (first) address of the MTT relative to MTT base address in the ICM. Must be aligned on 8 bytes. */
+/* -------------- */
+    pseudo_bit_t	mtt_sz[0x00020];       /* Number of MTT entries allocated for this MR.
+                                                 When Fast Registration Operations can not be executed on this region (FRE bit is zero) this field is reserved.
+                                                 When Fast Registration Operation is enabled (FRE bit is set) this field indicates the number of MTTs allocated for this MR. If mtt_sz value  is zero, there is no limit for the numbers of MTTs and the HCA does not check this field when executing fast register WQE. */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00040];
+/* -------------- */
+}; 
+
+/* Completion Queue Context Table Entry */
+
+struct arbelprm_completion_queue_context_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	st[0x00004];           /* Event delivery state machine
+                                                 0x0 - reserved
+                                                 0x9 - ARMED (Request for Notification)
+                                                 0x6 - ARMED SOLICITED (Request Solicited Notification)
+                                                 0xA - FIRED
+                                                 other - reserved
+                                                 
+                                                 Must be 0x0 in CQ initialization.
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only. */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	oi[0x00001];           /* When set, overrun ignore is enabled.
+                                                 When set, Updates of CQ consumer counter (poll for completion) or Request completion notifications (Arm CQ) doorbells should not be rang on that CQ. */
+    pseudo_bit_t	reserved2[0x0000a];
+    pseudo_bit_t	status[0x00004];       /* CQ status
+                                                 0000 - OK
+                                                 1001 - CQ overflow
+                                                 1010 - CQ write failure
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];/* Start address of CQ[63:32]. 
+                                                 Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];/* Start address of CQ[31:0]. 
+                                                 Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+    pseudo_bit_t	usr_page[0x00018];     /* UAR page this CQ can be accessed through (ringinig CQ doorbells) */
+    pseudo_bit_t	log_cq_size[0x00005];  /* Log (base 2) of the CQ size (in entries).
+                                                 Maximum CQ size is 2^17 CQEs (max log_cq_size is 17) */
+    pseudo_bit_t	reserved3[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	c_eqn[0x00008];        /* Event Queue this CQ reports completion events to.
+                                                 Valid values are 0 to 63
+                                                 If configured to value other than 0-63, completion events will not be reported on the CQ. */
+    pseudo_bit_t	reserved5[0x00018];
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* Protection Domain to be used to access CQ.
+                                                 Must be the same PD of the CQ L_Key. */
+    pseudo_bit_t	reserved6[0x00008];
+/* -------------- */
+    pseudo_bit_t	l_key[0x00020];        /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+    pseudo_bit_t	last_notified_indx[0x00020];/* Maintained by HW.
+                                                 Valid for QUERY_CQ and HW2SW_CQ commands only. */
+/* -------------- */
+    pseudo_bit_t	solicit_producer_indx[0x00020];/* Maintained by HW.
+                                                 Valid for QUERY_CQ and HW2SW_CQ commands only. 
+                                                  */
+/* -------------- */
+    pseudo_bit_t	consumer_counter[0x00020];/* Consumer counter is a 32bits counter that is incremented for each CQE pooled from the CQ.
+                                                 Must be 0x0 in CQ initialization.
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only. */
+/* -------------- */
+    pseudo_bit_t	producer_counter[0x00020];/* Producer counter is a 32bits counter that is incremented for each CQE that is written by the HW to the CQ.
+                                                 CQ overrun is reported if Producer_counter + 1 equals to Consumer_counter and a CQE needs to be added..
+                                                 Maintained by HW (valid for the QUERY_CQ and HW2SW_CQ commands only) */
+/* -------------- */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number. Least significant bits are constrained by the position of this CQ in CQC table
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only */
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	cq_ci_db_record[0x00020];/* Index in the UAR Context Table Entry.
+                                                 HW uses this index as an offset from the UAR Context Table Entry in order to read this CQ Consumer Counter doorbell record.
+                                                 This value can be retrieved from the HW in the QUERY_CQ command. */
+/* -------------- */
+    pseudo_bit_t	cq_state_db_record[0x00020];/* Index in the UAR Context Table Entry.
+                                                 HW uses this index as an offset from the UAR Context Table Entry in order to read this CQ state doorbell record.
+                                                 This value can be retrieved from the HW in the QUERY_CQ command. */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00020];
+/* -------------- */
+}; 
+
+/* GPIO_event_data */
+
+struct arbelprm_gpio_event_data_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00060];
+/* -------------- */
+    pseudo_bit_t	gpio_event_hi[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+    pseudo_bit_t	gpio_event_lo[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+}; 
+
+/* Event_data Field - QP/EE Events */
+
+struct arbelprm_qp_ee_event_st {	/* Little Endian */
+    pseudo_bit_t	qpn_een[0x00018];      /* QP/EE/SRQ number event is reported for */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x0001c];
+    pseudo_bit_t	e_q[0x00001];          /* If set - EEN if cleared - QP in the QPN/EEN field
+                                                 Not valid on SRQ events */
+    pseudo_bit_t	reserved3[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00060];
+/* -------------- */
+}; 
+
+/* InfiniHost-III-EX Type0 Configuration Header */
+
+struct arbelprm_mt25208_type0_st {	/* Little Endian */
+    pseudo_bit_t	vendor_id[0x00010];    /* Hardwired to 0x15B3 */
+    pseudo_bit_t	device_id[0x00010];    /* 25208 (decimal) - InfiniHost-III compatible mode
+                                                 25218 (decimal) - InfiniHost-III EX mode (the mode described in this manual)
+                                                 25209 (decimal) - Flash burner mode - see Flash burning application note for further details on this mode
+                                                  */
+/* -------------- */
+    pseudo_bit_t	command[0x00010];      /* PCI Command Register */
+    pseudo_bit_t	status[0x00010];       /* PCI Status Register */
+/* -------------- */
+    pseudo_bit_t	revision_id[0x00008];
+    pseudo_bit_t	class_code_hca_class_code[0x00018];
+/* -------------- */
+    pseudo_bit_t	cache_line_size[0x00008];/* Cache Line Size */
+    pseudo_bit_t	latency_timer[0x00008];
+    pseudo_bit_t	header_type[0x00008];  /* hardwired to zero */
+    pseudo_bit_t	bist[0x00008];
+/* -------------- */
+    pseudo_bit_t	bar0_ctrl[0x00004];    /* hard-wired to 0100 */
+    pseudo_bit_t	reserved0[0x00010];
+    pseudo_bit_t	bar0_l[0x0000c];       /* Lower bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+    pseudo_bit_t	bar0_h[0x00020];       /* Upper 32 bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+    pseudo_bit_t	bar1_ctrl[0x00004];    /* Hardwired to 1100 */
+    pseudo_bit_t	reserved1[0x00010];
+    pseudo_bit_t	bar1_l[0x0000c];       /* Lower bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+    pseudo_bit_t	bar1_h[0x00020];       /* upper 32 bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+    pseudo_bit_t	bar2_ctrl[0x00004];    /* Hardwired to 1100 */
+    pseudo_bit_t	reserved2[0x00010];
+    pseudo_bit_t	bar2_l[0x0000c];       /* Lower bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+    pseudo_bit_t	bar2_h[0x00020];       /* Upper 32 bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+    pseudo_bit_t	cardbus_cis_pointer[0x00020];
+/* -------------- */
+    pseudo_bit_t	subsystem_vendor_id[0x00010];/* Specified by the device NVMEM configuration */
+    pseudo_bit_t	subsystem_id[0x00010]; /* Specified by the device NVMEM configuration */
+/* -------------- */
+    pseudo_bit_t	expansion_rom_enable[0x00001];/* Expansion ROM Enable. Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+    pseudo_bit_t	reserved3[0x0000a];
+    pseudo_bit_t	expansion_rom_base_address[0x00015];/* Expansion ROM Base Address (upper 21 bit). Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+/* -------------- */
+    pseudo_bit_t	capabilities_pointer[0x00008];/* Specified by the device NVMEM configuration */
+    pseudo_bit_t	reserved4[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	interrupt_line[0x00008];
+    pseudo_bit_t	interrupt_pin[0x00008];
+    pseudo_bit_t	min_gnt[0x00008];
+    pseudo_bit_t	max_latency[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00100];
+/* -------------- */
+    pseudo_bit_t	msi_cap_id[0x00008];
+    pseudo_bit_t	msi_next_cap_ptr[0x00008];
+    pseudo_bit_t	msi_en[0x00001];
+    pseudo_bit_t	multiple_msg_cap[0x00003];
+    pseudo_bit_t	multiple_msg_en[0x00003];
+    pseudo_bit_t	cap_64_bit_addr[0x00001];
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	msg_addr_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	msg_addr_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	msg_data[0x00010];
+    pseudo_bit_t	reserved8[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00080];
+/* -------------- */
+    pseudo_bit_t	pm_cap_id[0x00008];    /* Power management capability ID - 01h */
+    pseudo_bit_t	pm_next_cap_ptr[0x00008];
+    pseudo_bit_t	pm_cap[0x00010];       /* [2:0] Version - 02h
+                                                 [3] PME clock - 0h
+                                                 [4] RsvP
+                                                 [5] Device specific initialization - 0h
+                                                 [8:6] AUX current - 0h
+                                                 [9] D1 support - 0h
+                                                 [10] D2 support - 0h
+                                                 [15:11] PME support - 0h */
+/* -------------- */
+    pseudo_bit_t	pm_status_control[0x00010];/* [14:13] - Data scale - 0h */
+    pseudo_bit_t	pm_control_status_brdg_ext[0x00008];
+    pseudo_bit_t	data[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00040];
+/* -------------- */
+    pseudo_bit_t	vpd_cap_id[0x00008];   /* 03h */
+    pseudo_bit_t	vpd_next_cap_id[0x00008];
+    pseudo_bit_t	vpd_address[0x0000f];
+    pseudo_bit_t	f[0x00001];
+/* -------------- */
+    pseudo_bit_t	vpd_data[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00040];
+/* -------------- */
+    pseudo_bit_t	pciex_cap_id[0x00008]; /* PCI-Express capability ID - 10h */
+    pseudo_bit_t	pciex_next_cap_ptr[0x00008];
+    pseudo_bit_t	pciex_cap[0x00010];    /* [3:0] Capability version - 1h
+                                                 [7:4] Device/Port Type - 0h
+                                                 [8] Slot implemented - 0h
+                                                 [13:9] Interrupt message number
+                                                  */
+/* -------------- */
+    pseudo_bit_t	device_cap[0x00020];   /* [2:0] Max_Payload_Size supported - 2h
+                                                 [4:3] Phantom Function supported - 0h
+                                                 [5] Extended Tag Filed supported - 0h
+                                                 [8:6] Endpoint L0s Acceptable Latency - TBD
+                                                 [11:9] Endpoint L1 Acceptable Latency - TBD
+                                                 [12] Attention Button Present - configured through InfiniBurn
+                                                 [13] Attention Indicator Present - configured through InfiniBurn
+                                                 [14] Power Indicator Present - configured through InfiniBurn
+                                                 [25:18] Captured Slot Power Limit Value
+                                                 [27:26] Captured Slot Power Limit Scale */
+/* -------------- */
+    pseudo_bit_t	device_control[0x00010];
+    pseudo_bit_t	device_status[0x00010];
+/* -------------- */
+    pseudo_bit_t	link_cap[0x00020];     /* [3:0] Maximum Link Speed - 1h
+                                                 [9:4] Maximum Link Width - 8h
+                                                 [11:10] Active State Power Management Support - 3h
+                                                 [14:12] L0s Exit Latency - TBD
+                                                 [17:15] L1 Exit Latency - TBD
+                                                 [31:24] Port Number - 0h */
+/* -------------- */
+    pseudo_bit_t	link_control[0x00010];
+    pseudo_bit_t	link_status[0x00010];  /* [3:0] Link Speed - 1h
+                                                 [9:4] Negotiated Link Width
+                                                 [12] Slot clock configuration - 1h */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x00260];
+/* -------------- */
+    pseudo_bit_t	advanced_error_reporting_cap_id[0x00010];/* 0001h. */
+    pseudo_bit_t	capability_version[0x00004];/* 1h */
+    pseudo_bit_t	next_capability_offset[0x0000c];/* 0h */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_error_status_register[0x00020];/* 0 Training Error Status
+                                                 4 Data Link Protocol Error Status
+                                                 12 Poisoned TLP Status 
+                                                 13 Flow Control Protocol Error Status 
+                                                 14 Completion Timeout Status 
+                                                 15 Completer Abort Status 
+                                                 16 Unexpected Completion Status 
+                                                 17 Receiver Overflow Status 
+                                                 18 Malformed TLP Status 
+                                                 19 ECRC Error Status 
+                                                 20 Unsupported Request Error Status */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_error_mask_register[0x00020];/* 0 Training Error Mask
+                                                 4 Data Link Protocol Error Mask
+                                                 12 Poisoned TLP Mask 
+                                                 13 Flow Control Protocol Error Mask
+                                                 14 Completion Timeout Mask
+                                                 15 Completer Abort Mask
+                                                 16 Unexpected Completion Mask
+                                                 17 Receiver Overflow Mask
+                                                 18 Malformed TLP Mask
+                                                 19 ECRC Error Mask
+                                                 20 Unsupported Request Error Mask */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_severity_mask_register[0x00020];/* 0 Training Error Severity
+                                                 4 Data Link Protocol Error Severity
+                                                 12 Poisoned TLP Severity
+                                                 13 Flow Control Protocol Error Severity
+                                                 14 Completion Timeout Severity
+                                                 15 Completer Abort Severity
+                                                 16 Unexpected Completion Severity
+                                                 17 Receiver Overflow Severity
+                                                 18 Malformed TLP Severity
+                                                 19 ECRC Error Severity
+                                                 20 Unsupported Request Error Severity */
+/* -------------- */
+    pseudo_bit_t	correctable_error_status_register[0x00020];/* 0 Receiver Error Status
+                                                 6 Bad TLP Status
+                                                 7 Bad DLLP Status
+                                                 8 REPLAY_NUM Rollover Status
+                                                 12 Replay Timer Timeout Status */
+/* -------------- */
+    pseudo_bit_t	correctable_error_mask_register[0x00020];/* 0 Receiver Error Mask
+                                                 6 Bad TLP Mask
+                                                 7 Bad DLLP Mask
+                                                 8 REPLAY_NUM Rollover Mask
+                                                 12 Replay Timer Timeout Mask */
+/* -------------- */
+    pseudo_bit_t	advance_error_capabilities_and_control_register[0x00020];
+/* -------------- */
+    struct arbelprm_header_log_register_st	header_log_register;
+/* -------------- */
+    pseudo_bit_t	reserved13[0x006a0];
+/* -------------- */
+}; 
+
+/* Event Data Field - Performance Monitor */
+
+struct arbelprm_performance_monitor_event_st {	/* Little Endian */
+    struct arbelprm_performance_monitors_st	performance_monitor_snapshot;/* Performance monitor snapshot */
+/* -------------- */
+    pseudo_bit_t	monitor_number[0x00008];/* 0x01 - SQPC
+                                                 0x02 - RQPC
+                                                 0x03 - CQC
+                                                 0x04 - Rkey
+                                                 0x05 - TLB
+                                                 0x06 - port0
+                                                 0x07 - port1 */
+    pseudo_bit_t	reserved0[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Event_data Field - Page Faults */
+
+struct arbelprm_page_fault_event_data_st {	/* Little Endian */
+    pseudo_bit_t	va_h[0x00020];         /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	va_l[0x00020];         /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* Memory Key this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	qp[0x00018];           /* QP this page fault is reported on */
+    pseudo_bit_t	reserved0[0x00003];
+    pseudo_bit_t	a[0x00001];            /* If set the memory access that caused the page fault was atomic */
+    pseudo_bit_t	lw[0x00001];           /* If set the memory access that caused the page fault was local write */
+    pseudo_bit_t	lr[0x00001];           /* If set the memory access that caused the page fault was local read */
+    pseudo_bit_t	rw[0x00001];           /* If set the memory access that caused the page fault was remote write */
+    pseudo_bit_t	rr[0x00001];           /* If set the memory access that caused the page fault was remote read */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* PD this page fault is reported on */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	prefetch_len[0x00020]; /* Indicates how many subsequent pages in the same memory region/window will be accessed by the following transaction after this page fault is resolved. measured in bytes. SW can use this information in order to page-in the subsequent pages if they are not present. */
+/* -------------- */
+}; 
+
+/* WQE segments format */
+
+struct arbelprm_wqe_segment_st {	/* Little Endian */
+    struct arbelprm_send_wqe_segment_st	send_wqe_segment;/* Send WQE segment format */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00280];
+/* -------------- */
+    struct arbelprm_wqe_segment_ctrl_mlx_st	mlx_wqe_segment_ctrl;/* MLX WQE segment format */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00100];
+/* -------------- */
+    struct arbelprm_wqe_segment_ctrl_recv_st	recv_wqe_segment_ctrl;/* Receive segment format */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00080];
+/* -------------- */
+}; 
+
+/* Event_data Field - Port State Change */
+
+struct arbelprm_port_state_change_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x0001c];
+    pseudo_bit_t	p[0x00002];            /* Port number (1 or 2) */
+    pseudo_bit_t	reserved2[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+}; 
+
+/* Event_data Field - Completion Queue Error */
+
+struct arbelprm_completion_queue_error_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number event is reported for */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	syndrome[0x00008];     /* Error syndrome
+                                                 0x01 - CQ overrun
+                                                 0x02 - CQ access violation error */
+    pseudo_bit_t	reserved2[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+}; 
+
+/* Event_data Field - Completion Event */
+
+struct arbelprm_completion_event_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number event is reported for */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x000a0];
+/* -------------- */
+}; 
+
+/* Event Queue Entry */
+
+struct arbelprm_event_queue_entry_st {	/* Little Endian */
+    pseudo_bit_t	event_sub_type[0x00008];/* Event Sub Type. 
+                                                 Defined for events which have sub types, zero elsewhere. */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	event_type[0x00008];   /* Event Type */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	event_data[6][0x00020];/* Delivers auxilary data to handle event. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00007];
+    pseudo_bit_t	owner[0x00001];        /* Owner of the entry 
+                                                 0 SW 
+                                                 1 HW */
+    pseudo_bit_t	reserved3[0x00018];
+/* -------------- */
+}; 
+
+/* QP/EE State Transitions Command Parameters */
+
+struct arbelprm_qp_ee_state_transitions_st {	/* Little Endian */
+    pseudo_bit_t	opt_param_mask[0x00020];/* This field defines which optional parameters are passed. Each bit specifies whether optional parameter is passed (set) or not (cleared). The optparammask is defined for each QP/EE command. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    struct arbelprm_queue_pair_ee_context_entry_st	qpc_eec_data;/* QPC/EEC data */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x009c0];
+/* -------------- */
+}; 
+
+/* Completion Queue Entry Format */
+
+struct arbelprm_completion_queue_entry_st {	/* Little Endian */
+    pseudo_bit_t	my_qpn[0x00018];       /* Indicates the QP for which completion is being reported */
+    pseudo_bit_t	reserved0[0x00004];
+    pseudo_bit_t	ver[0x00004];          /* CQE version. 
+                                                 0 for InfiniHost-III-EX */
+/* -------------- */
+    pseudo_bit_t	my_ee[0x00018];        /* EE context (for RD only).
+                                                 Invalid for Bind and Nop operation on RD.
+                                                 For non RD services this filed reports the CQE timestamp. The Timestamp is a free running counter that is incremented every TimeStampGranularity tick. The counter rolls-over when it reaches saturation. TimeStampGranularity is configured in the INIT_HCA command. This feature is currently not supported.
+                                                  */
+    pseudo_bit_t	checksum_15_8[0x00008];/* Checksum[15:8] - See IPoverIB checksum offloading chapter */
+/* -------------- */
+    pseudo_bit_t	rqpn[0x00018];         /* Remote (source) QP number. Valid in Responder CQE only for Datagram QP. */
+    pseudo_bit_t	checksum_7_0[0x00008]; /* Checksum[7:0] - See IPoverIB checksum offloading chapter */
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (source) LID of the message. Valid in Responder of UD QP CQE only. */
+    pseudo_bit_t	ml_path[0x00007];      /* My (destination) LID path bits - these are the lowemost LMC bits of the DLID in an incoming UD packet, higher bits of this field, that are not part of the LMC bits are zeroed by HW.
+                                                 Valid in responder of UD QP CQE only.
+                                                 Invalid if incoming message DLID is the permissive LID or incoming message is multicast. */
+    pseudo_bit_t	g[0x00001];            /* GRH present indicator. Valid in Responder of UD QP CQE only. */
+    pseudo_bit_t	ipok[0x00001];         /* IP OK - See IPoverIB checksum offloading chapter */
+    pseudo_bit_t	reserved1[0x00003];
+    pseudo_bit_t	sl[0x00004];           /* Service Level of the message. Valid in Responder of UD QP CQE only. */
+/* -------------- */
+    pseudo_bit_t	immediate_ethertype_pkey_indx_eecredits[0x00020];/* Valid for receive queue completion only. 
+                                                 If Opcode field indicates that this was send/write with immediate, this field contains immediate field of the packet. 
+                                                 If completion corresponds to RAW receive queue, bits 15:0 contain Ethertype field of the packet. 
+                                                 If completion corresponds to GSI receive queue, bits 31:16 contain index in PKey table that matches PKey of the message arrived. 
+                                                 If Opcode field indicates that this was send and invalidate, this field contains the key that was invalidated.
+                                                 For CQE of send queue of the reliable connection service (but send and invalide), bits [4:0] of this field contain the encoded EEcredits received in last ACK of the message. */
+/* -------------- */
+    pseudo_bit_t	byte_cnt[0x00020];     /* Byte count of data actually transferred (valid for receive queue completions only) */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00006];
+    pseudo_bit_t	wqe_adr[0x0001a];      /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00007];
+    pseudo_bit_t	owner[0x00001];        /* Owner field. Zero value of this field means SW ownership of CQE. */
+    pseudo_bit_t	reserved4[0x0000f];
+    pseudo_bit_t	s[0x00001];            /* If set, completion is reported for Send queue, if cleared - receive queue. */
+    pseudo_bit_t	opcode[0x00008];       /* The opcode of WQE completion is reported for.
+                                                 For CQEs corresponding to send completion, NOPCODE field of the WQE is copied to this field.
+                                                 For CQEs corresponding to receive completions, opcode field of last packet in the message copied to this field.
+                                                 For CQEs corresponding to the receive queue of QPs mapped to QP1, the opcode will be SEND with Immediate (messages are guaranteed to be SEND only)
+                                                 
+                                                 The following values are reported in case of completion with error:
+                                                 0xFE - For completion with error on Receive Queues
+                                                 0xFF - For completion with error on Send Queues */
+/* -------------- */
+}; 
+
+/*  */
+
+struct arbelprm_ecc_detect_event_data_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	cause_lsb[0x00001];
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	cause_msb[0x00001];
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	err_rmw[0x00001];
+    pseudo_bit_t	err_src_id[0x00003];
+    pseudo_bit_t	err_da[0x00002];
+    pseudo_bit_t	err_ba[0x00002];
+    pseudo_bit_t	reserved3[0x00011];
+    pseudo_bit_t	overflow[0x00001];
+/* -------------- */
+    pseudo_bit_t	err_ra[0x00010];
+    pseudo_bit_t	err_ca[0x00010];
+/* -------------- */
+}; 
+
+/* Event_data Field - ECC Detection Event */
+
+struct arbelprm_scrubbing_event_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	cause_lsb[0x00001];    /* data integrity error cause:
+                                                 single ECC error in the 64bit lsb data, on the rise edge of the clock */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	cause_msb[0x00001];    /* data integrity error cause:
+                                                 single ECC error in the 64bit msb data, on the fall edge of the clock */
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	err_rmw[0x00001];      /* transaction type:
+                                                 0 - read
+                                                 1 - read/modify/write */
+    pseudo_bit_t	err_src_id[0x00003];   /* source of the transaction: 0x4 - PCI, other - internal or IB */
+    pseudo_bit_t	err_da[0x00002];       /* Error DIMM address */
+    pseudo_bit_t	err_ba[0x00002];       /* Error bank address */
+    pseudo_bit_t	reserved3[0x00011];
+    pseudo_bit_t	overflow[0x00001];     /* Fatal: ECC error FIFO overflow - ECC errors were detected, which may or may not have been corrected by InfiniHost-III-EX */
+/* -------------- */
+    pseudo_bit_t	err_ra[0x00010];       /* Error row address */
+    pseudo_bit_t	err_ca[0x00010];       /* Error column address */
+/* -------------- */
+}; 
+
+/* Miscellaneous Counters */
+
+struct arbelprm_misc_counters_st {	/* Little Endian */
+    pseudo_bit_t	ddr_scan_cnt[0x00020]; /* Number of times whole of LAM was scanned */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x007e0];
+/* -------------- */
+}; 
+
+/* LAM_EN Output Parameter */
+
+struct arbelprm_lam_en_out_param_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+}; 
+
+/* Extended_Completion_Queue_Entry */
+
+struct arbelprm_extended_completion_queue_entry_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/*  */
+
+struct arbelprm_eq_cmd_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/* 0 */
+
+struct arbelprm_arbel_prm_st {	/* Little Endian */
+    struct arbelprm_completion_queue_entry_st	completion_queue_entry;/* Completion Queue Entry Format */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x7ff00];
+/* -------------- */
+    struct arbelprm_qp_ee_state_transitions_st	qp_ee_state_transitions;/* QP/EE State Transitions Command Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x7f000];
+/* -------------- */
+    struct arbelprm_event_queue_entry_st	event_queue_entry;/* Event Queue Entry */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x7ff00];
+/* -------------- */
+    struct arbelprm_completion_event_st	completion_event;/* Event_data Field - Completion Event */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x7ff40];
+/* -------------- */
+    struct arbelprm_completion_queue_error_st	completion_queue_error;/* Event_data Field - Completion Queue Error */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x7ff40];
+/* -------------- */
+    struct arbelprm_port_state_change_st	port_state_change;/* Event_data Field - Port State Change */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x7ff40];
+/* -------------- */
+    struct arbelprm_wqe_segment_st	wqe_segment;/* WQE segments format */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x7f000];
+/* -------------- */
+    struct arbelprm_page_fault_event_data_st	page_fault_event_data;/* Event_data Field - Page Faults */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x7ff40];
+/* -------------- */
+    struct arbelprm_performance_monitor_event_st	performance_monitor_event;/* Event Data Field - Performance Monitor */
+/* -------------- */
+    pseudo_bit_t	reserved8[0xfff20];
+/* -------------- */
+    struct arbelprm_mt25208_type0_st	mt25208_type0;/* InfiniHost-III-EX Type0 Configuration Header */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x7f000];
+/* -------------- */
+    struct arbelprm_qp_ee_event_st	qp_ee_event;/* Event_data Field - QP/EE Events */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00040];
+/* -------------- */
+    struct arbelprm_gpio_event_data_st	gpio_event_data;
+/* -------------- */
+    pseudo_bit_t	reserved11[0x7fe40];
+/* -------------- */
+    struct arbelprm_ud_address_vector_st	ud_address_vector;/* UD Address Vector */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x7ff00];
+/* -------------- */
+    struct arbelprm_queue_pair_ee_context_entry_st	queue_pair_ee_context_entry;/* QP and EE Context Entry */
+/* -------------- */
+    pseudo_bit_t	reserved13[0x7fa00];
+/* -------------- */
+    struct arbelprm_address_path_st	address_path;/* Address Path */
+/* -------------- */
+    pseudo_bit_t	reserved14[0x7ff00];
+/* -------------- */
+    struct arbelprm_completion_queue_context_st	completion_queue_context;/* Completion Queue Context Table Entry */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x7fe00];
+/* -------------- */
+    struct arbelprm_mpt_st	mpt;         /* Memory Protection Table (MPT) Entry */
+/* -------------- */
+    pseudo_bit_t	reserved16[0x7fe00];
+/* -------------- */
+    struct arbelprm_mtt_st	mtt;         /* Memory Translation Table (MTT) Entry */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x7ffc0];
+/* -------------- */
+    struct arbelprm_eqc_st	eqc;         /* Event Queue Context Table Entry */
+/* -------------- */
+    pseudo_bit_t	reserved18[0x7fe00];
+/* -------------- */
+    struct arbelprm_performance_monitors_st	performance_monitors;/* Performance Monitors */
+/* -------------- */
+    pseudo_bit_t	reserved19[0x7ff80];
+/* -------------- */
+    struct arbelprm_hca_command_register_st	hca_command_register;/* HCA Command Register (HCR) */
+/* -------------- */
+    pseudo_bit_t	reserved20[0xfff20];
+/* -------------- */
+    struct arbelprm_init_hca_st	init_hca;/* INIT_HCA & QUERY_HCA Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved21[0x7f000];
+/* -------------- */
+    struct arbelprm_qpcbaseaddr_st	qpcbaseaddr;/* QPC/EEC/CQC/EQC/RDB Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved22[0x7fc00];
+/* -------------- */
+    struct arbelprm_udavtable_memory_parameters_st	udavtable_memory_parameters;/* Memory Access Parameters for UD Address Vector Table */
+/* -------------- */
+    pseudo_bit_t	reserved23[0x7ffc0];
+/* -------------- */
+    struct arbelprm_multicastparam_st	multicastparam;/* Multicast Support Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved24[0x7ff00];
+/* -------------- */
+    struct arbelprm_tptparams_st	tptparams;/* Translation and Protection Tables Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved25[0x7ff00];
+/* -------------- */
+    struct arbelprm_enable_lam_st	enable_lam;/* ENABLE_LAM Parameters Block */
+/* -------------- */
+    struct arbelprm_access_lam_st	access_lam;
+/* -------------- */
+    pseudo_bit_t	reserved26[0x7f700];
+/* -------------- */
+    struct arbelprm_dimminfo_st	dimminfo;/* Logical DIMM Information */
+/* -------------- */
+    pseudo_bit_t	reserved27[0x7ff00];
+/* -------------- */
+    struct arbelprm_query_fw_st	query_fw;/* QUERY_FW Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved28[0x7f800];
+/* -------------- */
+    struct arbelprm_query_adapter_st	query_adapter;/* QUERY_ADAPTER Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved29[0x7f800];
+/* -------------- */
+    struct arbelprm_query_dev_lim_st	query_dev_lim;/* Query Device Limitations */
+/* -------------- */
+    pseudo_bit_t	reserved30[0x7f800];
+/* -------------- */
+    struct arbelprm_uar_params_st	uar_params;/* UAR Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved31[0x7ff00];
+/* -------------- */
+    struct arbelprm_init_ib_st	init_ib; /* INIT_IB Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved32[0x7f800];
+/* -------------- */
+    struct arbelprm_mgm_entry_st	mgm_entry;/* Multicast Group Member */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x7fe00];
+/* -------------- */
+    struct arbelprm_set_ib_st	set_ib;   /* SET_IB Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved34[0x7fe00];
+/* -------------- */
+    struct arbelprm_rd_send_doorbell_st	rd_send_doorbell;/* RD-send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved35[0x7ff80];
+/* -------------- */
+    struct arbelprm_send_doorbell_st	send_doorbell;/* Send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved36[0x7ffc0];
+/* -------------- */
+    struct arbelprm_receive_doorbell_st	receive_doorbell;/* Receive doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved37[0x7ffc0];
+/* -------------- */
+    struct arbelprm_cq_cmd_doorbell_st	cq_cmd_doorbell;/* CQ Doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved38[0xfffc0];
+/* -------------- */
+    struct arbelprm_uar_st	uar;         /* User Access Region */
+/* -------------- */
+    pseudo_bit_t	reserved39[0x7c000];
+/* -------------- */
+    struct arbelprm_mgmqp_st	mgmqp;     /* Multicast Group Member QP */
+/* -------------- */
+    pseudo_bit_t	reserved40[0x7ffe0];
+/* -------------- */
+    struct arbelprm_query_debug_msg_st	query_debug_msg;/* Query Debug Message */
+/* -------------- */
+    pseudo_bit_t	reserved41[0x7f800];
+/* -------------- */
+    struct arbelprm_mad_ifc_st	mad_ifc; /* MAD_IFC Input Mailbox */
+/* -------------- */
+    pseudo_bit_t	reserved42[0x00900];
+/* -------------- */
+    struct arbelprm_mad_ifc_input_modifier_st	mad_ifc_input_modifier;/* MAD_IFC Input Modifier */
+/* -------------- */
+    pseudo_bit_t	reserved43[0x7e6e0];
+/* -------------- */
+    struct arbelprm_resize_cq_st	resize_cq;/* Resize CQ Input Mailbox */
+/* -------------- */
+    pseudo_bit_t	reserved44[0x7fe00];
+/* -------------- */
+    struct arbelprm_completion_with_error_st	completion_with_error;/* Completion with Error CQE */
+/* -------------- */
+    pseudo_bit_t	reserved45[0x7ff00];
+/* -------------- */
+    struct arbelprm_hcr_completion_event_st	hcr_completion_event;/* Event_data Field - HCR Completion Event */
+/* -------------- */
+    pseudo_bit_t	reserved46[0x7ff40];
+/* -------------- */
+    struct arbelprm_transport_and_ci_error_counters_st	transport_and_ci_error_counters;/* Transport and CI Error Counters */
+/* -------------- */
+    pseudo_bit_t	reserved47[0x7f000];
+/* -------------- */
+    struct arbelprm_performance_counters_st	performance_counters;/* Performance Counters */
+/* -------------- */
+    pseudo_bit_t	reserved48[0x9ff800];
+/* -------------- */
+    struct arbelprm_fast_registration_segment_st	fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+    pseudo_bit_t	reserved49[0x7ff00];
+/* -------------- */
+    struct arbelprm_pbl_st	pbl;         /* Physical Buffer List */
+/* -------------- */
+    pseudo_bit_t	reserved50[0x7ff00];
+/* -------------- */
+    struct arbelprm_srq_context_st	srq_context;/* SRQ Context */
+/* -------------- */
+    pseudo_bit_t	reserved51[0x7fe80];
+/* -------------- */
+    struct arbelprm_mod_stat_cfg_st	mod_stat_cfg;/* MOD_STAT_CFG */
+/* -------------- */
+    pseudo_bit_t	reserved52[0x7f800];
+/* -------------- */
+    struct arbelprm_virtual_physical_mapping_st	virtual_physical_mapping;/* Virtual and Physical Mapping */
+/* -------------- */
+    pseudo_bit_t	reserved53[0x7ff80];
+/* -------------- */
+    struct arbelprm_cq_ci_db_record_st	cq_ci_db_record;/* CQ_CI_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved54[0x7ffc0];
+/* -------------- */
+    struct arbelprm_cq_arm_db_record_st	cq_arm_db_record;/* CQ_ARM_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved55[0x7ffc0];
+/* -------------- */
+    struct arbelprm_qp_db_record_st	qp_db_record;/* QP_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved56[0x1fffc0];
+/* -------------- */
+    struct arbelprm_configuration_registers_st	configuration_registers;/* InfiniHost III EX Configuration Registers */
+/* -------------- */
+    struct arbelprm_eq_set_ci_table_st	eq_set_ci_table;/* EQ Set CI DBs Table */
+/* -------------- */
+    pseudo_bit_t	reserved57[0x01000];
+/* -------------- */
+    struct arbelprm_eq_arm_db_region_st	eq_arm_db_region;/* EQ Arm Doorbell Region */
+/* -------------- */
+    pseudo_bit_t	reserved58[0x00fc0];
+/* -------------- */
+    struct arbelprm_clr_int_st	clr_int; /* Clear Interrupt Register */
+/* -------------- */
+    pseudo_bit_t	reserved59[0xffcfc0];
+/* -------------- */
+}; 
+#endif /* H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25408_PRM.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25408_PRM.h
new file mode 100644
index 0000000..cc248da
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/MT25408_PRM.h
@@ -0,0 +1,3404 @@
+/*
+  This software is available to you under a choice of one of two
+  licenses.  You may choose to be licensed under the terms of the GNU
+  General Public License (GPL) Version 2, available at
+  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+  license, available in the LICENSE.TXT file accompanying this
+  software.  These details are also available at
+  <http://openib.org/license.html>.
+
+  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.
+
+  Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
+*/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/***
+ *** This file was generated at "Mon Apr 16 23:22:02 2007"
+ *** by:
+ ***    % csp_bf -copyright=/mswg/misc/license-header.txt -prefix hermonprm_ -bits -fixnames MT25408_PRM.csp
+ ***/
+
+#ifndef H_prefix_hermonprm_bits_fixnames_MT25408_PRM_csp_H
+#define H_prefix_hermonprm_bits_fixnames_MT25408_PRM_csp_H
+
+/* UD Address Vector */
+
+struct hermonprm_ud_address_vector_st {	/* Little Endian */
+    pseudo_bit_t	pd[0x00018];           /* Protection Domain */
+    pseudo_bit_t	port_number[0x00002];  /* Port number
+                                                 1 - Port 1
+                                                 2 - Port 2
+                                                 other - reserved */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	fl[0x00001];           /* force loopback */
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (Destination) LID */
+    pseudo_bit_t	my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+    pseudo_bit_t	g[0x00001];            /* Global address enable - if set, GRH will be formed for packet header */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	hop_limit[0x00008];    /* IPv6 hop limit */
+    pseudo_bit_t	max_stat_rate[0x00004];/* Maximum static rate control. 
+                                                 0 - 4X injection rate
+                                                 1 - 1X injection rate
+                                                 other - reserved
+                                                  */
+    pseudo_bit_t	reserved2[0x00004];
+    pseudo_bit_t	mgid_index[0x00007];   /* Index to port GID table
+                                                 mgid_index = (port_number-1) * 2^log_max_gid + gid_index
+                                                 Where:
+                                                 1. log_max_gid is taken from QUERY_DEV_CAP command
+                                                 2. gid_index is the index to the GID table */
+    pseudo_bit_t	reserved3[0x00009];
+/* -------------- */
+    pseudo_bit_t	flow_label[0x00014];   /* IPv6 flow label */
+    pseudo_bit_t	tclass[0x00008];       /* IPv6 TClass */
+    pseudo_bit_t	sl[0x00004];           /* InfiniBand Service Level (SL) */
+/* -------------- */
+    pseudo_bit_t	rgid_127_96[0x00020];  /* Remote GID[127:96] */
+/* -------------- */
+    pseudo_bit_t	rgid_95_64[0x00020];   /* Remote GID[95:64] */
+/* -------------- */
+    pseudo_bit_t	rgid_63_32[0x00020];   /* Remote GID[63:32] */
+/* -------------- */
+    pseudo_bit_t	rgid_31_0[0x00020];    /* Remote GID[31:0] if G bit is set. Must be set to 0x2 if G bit is cleared. */
+/* -------------- */
+}; 
+
+/* Send doorbell */
+
+struct hermonprm_send_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	nopcode[0x00005];      /* Opcode of descriptor to be executed */
+    pseudo_bit_t	f[0x00001];            /* Fence bit. If set, descriptor is fenced */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	wqe_counter[0x00010];  /* Modulo-64K counter of WQEs posted to the QP since its creation excluding the newly posted WQEs in this doorbell. Should be zero for the first doorbell on the QP */
+    pseudo_bit_t	wqe_cnt[0x00008];      /* Number of WQEs posted with this doorbell. Must be grater then zero. */
+/* -------------- */
+    pseudo_bit_t	nds[0x00006];          /* Next descriptor size (in 16-byte chunks) */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	qpn[0x00018];          /* QP number this doorbell is rung on */
+/* -------------- */
+}; 
+
+/* Send wqe segment data inline */
+
+struct hermonprm_wqe_segment_data_inline_st {	/* Little Endian */
+    pseudo_bit_t	byte_count[0x0000a];   /* Not including padding for 16Byte chunks */
+    pseudo_bit_t	reserved0[0x00015];
+    pseudo_bit_t	always1[0x00001];
+/* -------------- */
+    pseudo_bit_t	data[0x00018];         /* Data may be more this segment size - in 16Byte chunks */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment data ptr */
+
+struct hermonprm_wqe_segment_data_ptr_st {	/* Little Endian */
+    pseudo_bit_t	byte_count[0x0001f];
+    pseudo_bit_t	always0[0x00001];
+/* -------------- */
+    pseudo_bit_t	l_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	local_address_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	local_address_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment rd */
+
+struct hermonprm_local_invalidate_segment_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00018];
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x000a0];
+/* -------------- */
+}; 
+
+/* Fast_Registration_Segment   ####michal - doesn't match PRM (fields were added, see below) new table size in bytes -  0x30 */
+
+struct hermonprm_fast_registration_segment_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x0001b];
+    pseudo_bit_t	lr[0x00001];           /* If set - Local Read access will be enabled */
+    pseudo_bit_t	lw[0x00001];           /* If set - Local Write access will be enabled */
+    pseudo_bit_t	rr[0x00001];           /* If set - Remote Read access will be enabled */
+    pseudo_bit_t	rw[0x00001];           /* If set - Remote Write access will be enabled */
+    pseudo_bit_t	a[0x00001];            /* If set - Remote Atomic access will be enabled */
+/* -------------- */
+    pseudo_bit_t	pbl_ptr_63_32[0x00020];/* Physical address pointer [63:32] to the physical buffer list  ### michal - this field is replaced with mem_key .32 */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* Memory Key on which the fast registration is executed on. ###michal-this field is replaced with pbl_ptr_63_32 */
+/* -------------- */
+    pseudo_bit_t	page_size[0x00005];    /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+                                                 page_size should be less than 20. ###michal - field doesn't exsist (see replacement above) */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	zb[0x00001];           /* Zero Based Region               ###michal - field doesn't exsist (see replacement above) */
+    pseudo_bit_t	pbl_ptr_31_8[0x00018]; /* Physical address pointer [31:8] to the physical buffer list    ###michal - field doesn't exsist (see replacement above) */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region starts */
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region starts */
+/* -------------- */
+    pseudo_bit_t	reg_len_h[0x00020];    /* Region Length[63:32] */
+/* -------------- */
+    pseudo_bit_t	reg_len_l[0x00020];    /* Region Length[31:0] */
+/* -------------- */
+}; 
+
+/* Send wqe segment atomic */
+
+struct hermonprm_wqe_segment_atomic_st {	/* Little Endian */
+    pseudo_bit_t	swap_add_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	swap_add_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	compare_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	compare_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment remote address */
+
+struct hermonprm_wqe_segment_remote_address_st {	/* Little Endian */
+    pseudo_bit_t	remote_virt_addr_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	remote_virt_addr_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	rkey[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/* end wqe segment bind */
+
+struct hermonprm_wqe_segment_bind_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x0001d];
+    pseudo_bit_t	rr[0x00001];           /* If set, Remote Read Enable for bound window. */
+    pseudo_bit_t	rw[0x00001];           /* If set, Remote Write Enable for bound window.
+                                                  */
+    pseudo_bit_t	a[0x00001];            /* If set, Atomic Enable for bound window. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x0001e];
+    pseudo_bit_t	zb[0x00001];           /* If set, Window is Zero Based. */
+    pseudo_bit_t	type[0x00001];         /* Window type.
+                                                 0 - Type one window
+                                                 1 - Type two window
+                                                  */
+/* -------------- */
+    pseudo_bit_t	new_rkey[0x00020];     /* The new RKey of window to bind */
+/* -------------- */
+    pseudo_bit_t	region_lkey[0x00020];  /* Local key of region, which window will be bound to */
+/* -------------- */
+    pseudo_bit_t	start_address_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	start_address_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	length_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	length_l[0x00020];
+/* -------------- */
+}; 
+
+/* Send wqe segment ud */
+
+struct hermonprm_wqe_segment_ud_st {	/* Little Endian */
+    struct hermonprm_ud_address_vector_st	ud_address_vector;/* UD Address Vector */
+/* -------------- */
+    pseudo_bit_t	destination_qp[0x00018];
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment rd */
+
+struct hermonprm_wqe_segment_rd_st {	/* Little Endian */
+    pseudo_bit_t	destination_qp[0x00018];
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Send wqe segment ctrl */
+
+struct hermonprm_wqe_segment_ctrl_send_st {	/* Little Endian */
+    pseudo_bit_t	opcode[0x00005];
+    pseudo_bit_t	reserved0[0x0001a];
+    pseudo_bit_t	owner[0x00001];
+/* -------------- */
+    pseudo_bit_t	ds[0x00006];           /* descriptor (wqe) size in 16bytes chunk */
+    pseudo_bit_t	f[0x00001];            /* fence */
+    pseudo_bit_t	reserved1[0x00019];
+/* -------------- */
+    pseudo_bit_t	fl[0x00001];           /* Force LoopBack */
+    pseudo_bit_t	s[0x00001];            /* Remote Solicited Event */
+    pseudo_bit_t	c[0x00002];            /* completion required: 0b00 - no   0b11 - yes */
+    pseudo_bit_t	ip[0x00001];           /* When set, InfiniHost III Ex will calculate the IP checksum of the IP header that is present immediately after the IPoverIB encapsulation header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first IP header following the IPoverIB encapsulation header. Not Valid for IPv6 packets */
+    pseudo_bit_t	tcp_udp[0x00001];      /* When set, InfiniHost III Ex will calculate the TCP/UDP checksum of the packet that is present immediately after the IP header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first TCP header following the IP header. This bit may be set only if the entire TCP/UDP segment is present in one IB packet */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	so[0x00001];           /* Strong Ordering - when set, the WQE will be executed only after all previous WQEs have been executed. Can be set for RC WQEs only. This bit must be set in type two BIND, Fast Registration and Local invalidate operations. */
+    pseudo_bit_t	src_remote_buf[0x00018];
+/* -------------- */
+    pseudo_bit_t	immediate[0x00020];    /* If the OpCode encodes an operation with Immediate (RDMA-write/SEND), This field will hold the Immediate data to be sent. If the OpCode encodes send and invalidate operations, this field holds the Invalidation key to be inserted into the packet; otherwise, this field is reserved. */
+/* -------------- */
+}; 
+
+/* Address Path	# ###michal - match to PRM */
+
+struct hermonprm_address_path_st {	/* Little Endian */
+    pseudo_bit_t	pkey_index[0x00007];   /* PKey table index */
+    pseudo_bit_t	reserved0[0x00016];
+    pseudo_bit_t	sv[0x00001];           /* Service  VLAN on QP */
+    pseudo_bit_t	cv[0x00001];           /* Customer VLAN in QP */
+    pseudo_bit_t	fl[0x00001];           /* Force LoopBack */
+/* -------------- */
+    pseudo_bit_t	rlid[0x00010];         /* Remote (Destination) LID */
+    pseudo_bit_t	my_lid_smac_idx[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+    pseudo_bit_t	grh_ip[0x00001];       /* Global address enable - if set, GRH will be formed for packet header */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	hop_limit[0x00008];    /* IPv6 hop limit */
+    pseudo_bit_t	max_stat_rate[0x00004];/* Maximum static rate control. 
+                                                 0 - 100% injection rate 
+                                                 1 - 25% injection rate
+                                                 2 - 12.5% injection rate
+                                                 3 - 50% injection rate
+                                                 7: 2.5 Gb/s. 
+                                                 8: 10 Gb/s. 
+                                                 9: 30 Gb/s. 
+                                                 10: 5 Gb/s. 
+                                                 11: 20 Gb/s.
+                                                 12: 40 Gb/s. 
+                                                 13: 60 Gb/s. 
+                                                 14: 80 Gb/s. 
+                                                 15: 120 Gb/s. */
+    pseudo_bit_t	reserved2[0x00004];
+    pseudo_bit_t	mgid_index[0x00007];   /* Index to port GID table */
+    pseudo_bit_t	reserved3[0x00004];
+    pseudo_bit_t	ack_timeout[0x00005];  /* Local ACK timeout - Transport timer for activation of retransmission mechanism. Refer to IB spec Vol1 9.7.6.1.3 for further details.
+                                                 The transport timer is set to 4.096us*2^ack_timeout, if ack_timeout is 0 then transport timer is disabled. */
+/* -------------- */
+    pseudo_bit_t	flow_label[0x00014];   /* IPv6 flow label */
+    pseudo_bit_t	tclass[0x00008];       /* IPv6 TClass */
+    pseudo_bit_t	reserved4[0x00004];
+/* -------------- */
+    pseudo_bit_t	rgid_127_96[0x00020];  /* Remote GID[127:96] */
+/* -------------- */
+    pseudo_bit_t	rgid_95_64[0x00020];   /* Remote GID[95:64] */
+/* -------------- */
+    pseudo_bit_t	rgid_63_32[0x00020];   /* Remote GID[63:32] */
+/* -------------- */
+    pseudo_bit_t	rgid_31_0[0x00020];    /* Remote GID[31:0] */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00008];
+    pseudo_bit_t	sp[0x00001];           /* if set, spoofing protection is enforced on this QP and Ethertype headers are restricted */
+    pseudo_bit_t	reserved6[0x00002];
+    pseudo_bit_t	fvl[0x00001];          /* force VLAN */
+    pseudo_bit_t	fsip[0x00001];         /* force source IP */
+    pseudo_bit_t	fsm[0x00001];          /* force source MAC */
+    pseudo_bit_t	reserved7[0x0000a];
+    pseudo_bit_t	sched_queue[0x00008];
+/* -------------- */
+    pseudo_bit_t	dmac_47_32[0x00010];
+    pseudo_bit_t	vlan_index[0x00007];
+    pseudo_bit_t	reserved8[0x00001];
+    pseudo_bit_t	counter_index[0x00008];/* Index to a table of counters that counts egress packets and bytes, 0xFF not valid */
+/* -------------- */
+    pseudo_bit_t	dmac_31_0[0x00020];
+/* -------------- */
+}; 
+
+/* HCA Command Register (HCR)    #### michal - match PRM */
+
+struct hermonprm_hca_command_register_st {	/* Little Endian */
+    pseudo_bit_t	in_param_h[0x00020];   /* Input Parameter: parameter[63:32] or pointer[63:32] to input mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	in_param_l[0x00020];   /* Input Parameter: parameter[31:0] or pointer[31:0] to input mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	input_modifier[0x00020];/* Input Parameter Modifier */
+/* -------------- */
+    pseudo_bit_t	out_param_h[0x00020];  /* Output Parameter: parameter[63:32] or pointer[63:32] to output mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	out_param_l[0x00020];  /* Output Parameter: parameter[31:0] or pointer[31:0] to output mailbox (see command description) */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00010];
+    pseudo_bit_t	token[0x00010];        /* Software assigned token to the command, to uniquely identify it. The token is returned to the software in the EQE reported. */
+/* -------------- */
+    pseudo_bit_t	opcode[0x0000c];       /* Command opcode */
+    pseudo_bit_t	opcode_modifier[0x00004];/* Opcode Modifier, see specific description for each command. */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	t[0x00001];	       /* Toggle */
+    pseudo_bit_t	e[0x00001];            /* Event Request
+                                                 0 - Don't report event (software will poll the GO bit)
+                                                 1 - Report event to EQ when the command completes */
+    pseudo_bit_t	go[0x00001];           /* Go (0=Software ownership for the HCR, 1=Hardware ownership for the HCR)
+                                                 Software can write to the HCR only if Go bit is cleared.
+                                                 Software must set the Go bit to trigger the HW to execute the command. Software must not write to this register value other than 1 for the Go bit. */
+    pseudo_bit_t	status[0x00008];       /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared)
+                                                 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */
+/* -------------- */
+}; 
+
+/* CQ Doorbell */
+
+struct hermonprm_cq_cmd_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number accessed */
+    pseudo_bit_t	cmd[0x00003];          /* Command to be executed on CQ
+                                                 0x0 - Reserved
+                                                 0x1 - Request notification for next Solicited completion event. CQ_param specifies the current CQ Consumer Counter.
+                                                 0x2 - Request notification for next Solicited or Unsolicited completion event. CQ_param specifies the current CQ Consumer Counter.
+                                                 0x3 - Request notification for multiple completions (Arm-N). CQ_param specifies the value of the CQ Counter that when reached by HW (i.e. HW generates a CQE into this Counter) Event will be generated
+                                                 Other - Reserved */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	cmd_sn[0x00002];       /* Command Sequence Number - This field should be incremented upon receiving completion notification of the respective CQ.
+                                                 This transition is done by ringing Request notification for next Solicited, Request notification for next Solicited or Unsolicited 
+                                                 completion or Request notification for multiple completions doorbells after receiving completion notification.
+                                                 This field is initialized to Zero */
+    pseudo_bit_t	reserved1[0x00002];
+/* -------------- */
+    pseudo_bit_t	cq_param[0x00020];     /* parameter to be used by CQ command */
+/* -------------- */
+}; 
+
+/* RD-send doorbell */
+
+struct hermonprm_rd_send_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	een[0x00018];          /* End-to-end context number (reliable datagram)
+                                                 Must be zero for Nop and Bind operations */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00008];
+    pseudo_bit_t	qpn[0x00018];          /* QP number this doorbell is rung on */
+/* -------------- */
+    struct hermonprm_send_doorbell_st	send_doorbell;/* Send Parameters */
+/* -------------- */
+}; 
+
+/* Multicast Group Member QP   #### michal - match PRM */
+
+struct hermonprm_mgmqp_st {	/* Little Endian */
+    pseudo_bit_t	qpn_i[0x00018];        /* QPN_i: QP number which is a member in this multicast group. Valid only if Qi bit is set. Length of the QPN_i list is set in INIT_HCA */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	blck_lb[0x00001];      /* Block self-loopback messages arriving to this qp */
+    pseudo_bit_t	qi[0x00001];           /* Qi: QPN_i is valid */
+/* -------------- */
+}; 
+
+/* vsd */
+
+struct hermonprm_vsd_st {	/* Little Endian */
+    pseudo_bit_t	vsd_dw0[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw1[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw2[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw3[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw4[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw5[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw6[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw7[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw8[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw9[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw10[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw11[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw12[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw13[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw14[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw15[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw16[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw17[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw18[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw19[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw20[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw21[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw22[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw23[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw24[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw25[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw26[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw27[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw28[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw29[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw30[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw31[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw32[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw33[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw34[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw35[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw36[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw37[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw38[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw39[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw40[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw41[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw42[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw43[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw44[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw45[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw46[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw47[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw48[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw49[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw50[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw51[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw52[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw53[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw54[0x00020];
+/* -------------- */
+    pseudo_bit_t	vsd_dw55[0x00020];
+/* -------------- */
+}; 
+
+/* UAR Parameters */
+
+struct hermonprm_uar_params_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	uar_page_sz[0x00008];  /* This field defines the size of each UAR page.
+                                                 Size of UAR Page is 4KB*2^UAR_Page_Size */
+    pseudo_bit_t	log_max_uars[0x00004]; /* Number of UARs supported is 2^log_max_UARs */
+    pseudo_bit_t	reserved1[0x00014];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x000a0];
+/* -------------- */
+}; 
+
+/* Translation and Protection Tables Parameters */
+
+struct hermonprm_tptparams_st {	/* Little Endian */
+    pseudo_bit_t	dmpt_base_adr_h[0x00020];/* dMPT - Memory Protection Table base physical address [63:32].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	dmpt_base_adr_l[0x00020];/* dMPT - Memory Protection Table base physical address [31:0].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	log_dmpt_sz[0x00006];  /* Log (base 2) of the number of region/windows entries in the dMPT table. */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	pfto[0x00005];         /* Page Fault RNR Timeout - 
+                                                 The field returned in RNR Naks generated when a page fault is detected.
+                                                 It has no effect when on-demand-paging is not used. */
+    pseudo_bit_t	reserved1[0x00013];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00020];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00020];/* MTT - Memory Translation table base physical address [63:32].
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_l[0x00020];/* MTT - Memory Translation table base physical address [31:0].
+                                                 Table must be aligned to its size.
+                                                 Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+    pseudo_bit_t	cmpt_base_adr_h[0x00020];/* cMPT - Memory Protection Table base physical address [63:32].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size. */
+/* -------------- */
+    pseudo_bit_t	cmpt_base_adr_l[0x00020];/* cMPT - Memory Protection Table base physical address [31:0].
+                                                 Entry size is 64 bytes.
+                                                 Table must be aligned to its size. */
+/* -------------- */
+}; 
+
+/* Multicast Support Parameters   #### michal - match PRM */
+
+struct hermonprm_multicastparam_st {	/* Little Endian */
+    pseudo_bit_t	mc_base_addr_h[0x00020];/* Base Address of the Multicast Table [63:32].
+                                                 The base address must be aligned to the entry size.
+                                                 Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+    pseudo_bit_t	mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0]. 
+                                                 The base address must be aligned to the entry size.
+                                                 Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	log_mc_table_entry_sz[0x00005];/* Log2 of the Size of multicast group member (MGM) entry.
+                                                 Must be greater than 5 (to allow CTRL and GID sections). 
+                                                 That implies the number of QPs per MC table entry. */
+    pseudo_bit_t	reserved1[0x0000b];
+    pseudo_bit_t	reserved2[0x00010];
+/* -------------- */
+    pseudo_bit_t	log_mc_table_hash_sz[0x00005];/* Number of entries in multicast DGID hash table (must be power of 2)
+                                                 INIT_HCA - the required number of entries
+                                                 QUERY_HCA - the actual number of entries assigned by firmware (will be less than or equal to the amount required in INIT_HCA) */
+    pseudo_bit_t	reserved3[0x0001b];
+/* -------------- */
+    pseudo_bit_t	log_mc_table_sz[0x00005];/* Log2 of the overall number of MC entries in the MCG table (includes both hash and auxiliary tables) */
+    pseudo_bit_t	reserved4[0x00013];
+    pseudo_bit_t	mc_hash_fn[0x00003];   /* Multicast hash function
+                                                 0 - Default hash function
+                                                 other - reserved */
+    pseudo_bit_t	uc_group_steering[0x00001];
+    pseudo_bit_t	reserved5[0x00004];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+}; 
+
+/* QPC/EEC/CQC/EQC/RDB Parameters   #### michal - doesn't match PRM (field name are differs. see below) */
+
+struct hermonprm_qpcbaseaddr_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	qpc_base_addr_h[0x00020];/* QPC Base Address [63:32]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	log_num_of_qp[0x00005];/* Log base 2 of number of supported QPs */
+    pseudo_bit_t	qpc_base_addr_l[0x0001b];/* QPC Base Address [31:7]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	srqc_base_addr_h[0x00020];/* SRQ Context Base Address [63:32]
+                                                 Table must be aligned on its size
+                                                 Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+    pseudo_bit_t	log_num_of_srq[0x00005];/* Log base 2 of number of supported SRQs. */
+    pseudo_bit_t	srqc_base_addr_l[0x0001b];/* SRQ Context Base Address [31:5]
+                                                 Table must be aligned on its size
+                                                 Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+    pseudo_bit_t	cqc_base_addr_h[0x00020];/* CQC Base Address [63:32]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	log_num_of_cq[0x00005];/* Log base 2 of number of supported CQs. */
+    pseudo_bit_t	cqc_base_addr_l[0x0001b];/* CQC Base Address [31:6]
+                                                 Table must be aligned on its size */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00040];
+/* -------------- */
+    pseudo_bit_t	altc_base_addr_h[0x00020];/* AltC Base Address (altc_base_addr_h) [63:32]
+                                                 Table has same number of entries as QPC table.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	altc_base_addr_l[0x00020];/* AltC Base Address (altc_base_addr_l) [31:0]
+                                                 Table has same number of entries as QPC table.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00040];
+/* -------------- */
+    pseudo_bit_t	auxc_base_addr_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	auxc_base_addr_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00040];
+/* -------------- */
+    pseudo_bit_t	eqc_base_addr_h[0x00020];/* EQC Base Address [63:32]
+                                                 Address may be set to 0xFFFFFFFF if EQs are not supported.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	log_num_of_eq[0x00005];/* Log base 2 of number of supported EQs.
+                                                 Must be 6 or less in InfiniHost-III-EX. */
+    pseudo_bit_t	eqc_base_addr_l[0x0001b];/* EQC Base Address [31:6]
+                                                 Address may be set to 0xFFFFFFFF if EQs are not supported.
+                                                 Table must be aligned to entry size. */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00040];
+/* -------------- */
+    pseudo_bit_t	rdmardc_base_addr_h[0x00020];/* rdmardc_base_addr_h: Base address of table that holds remote read and remote atomic requests [63:32]. */
+/* -------------- */
+    pseudo_bit_t	log_num_rd[0x00003];   /* Log (base 2) of the maximum number of RdmaRdC entries per QP. This denotes the maximum number of outstanding reads/atomics as a responder. */
+    pseudo_bit_t	reserved7[0x00002];
+    pseudo_bit_t	rdmardc_base_addr_l[0x0001b];/* rdmardc_base_addr_l: Base address of table that holds remote read and remote atomic requests [31:0]. 
+                                                 Table must be aligned to RDB entry size (32 bytes). */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00040];
+/* -------------- */
+}; 
+
+/* Header_Log_Register */
+
+struct hermonprm_header_log_register_st {	/* Little Endian */
+    pseudo_bit_t	place_holder[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00060];
+/* -------------- */
+}; 
+
+/* Performance Monitors */
+
+struct hermonprm_performance_monitors_st {	/* Little Endian */
+    pseudo_bit_t	e0[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	e1[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	e2[0x00001];           /* Enables counting of respective performance counter */
+    pseudo_bit_t	reserved0[0x00001];
+    pseudo_bit_t	r0[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	r1[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	r2[0x00001];           /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+    pseudo_bit_t	reserved1[0x00001];
+    pseudo_bit_t	i0[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	i1[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	i2[0x00001];           /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	f0[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	f1[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	f2[0x00001];           /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+    pseudo_bit_t	reserved3[0x00001];
+    pseudo_bit_t	ev_cnt1[0x00005];      /* Specifies event to be counted by Event_counter1 See XXX for events' definition. */
+    pseudo_bit_t	reserved4[0x00003];
+    pseudo_bit_t	ev_cnt2[0x00005];      /* Specifies event to be counted by Event_counter2 See XXX for events' definition. */
+    pseudo_bit_t	reserved5[0x00003];
+/* -------------- */
+    pseudo_bit_t	clock_counter[0x00020];
+/* -------------- */
+    pseudo_bit_t	event_counter1[0x00020];
+/* -------------- */
+    pseudo_bit_t	event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */
+/* -------------- */
+}; 
+
+/* MLX WQE segment format */
+
+struct hermonprm_wqe_segment_ctrl_mlx_st {	/* Little Endian */
+    pseudo_bit_t	opcode[0x00005];       /* must be 0xA = SEND */
+    pseudo_bit_t	reserved0[0x0001a];
+    pseudo_bit_t	owner[0x00001];
+/* -------------- */
+    pseudo_bit_t	ds[0x00006];           /* Descriptor Size */
+    pseudo_bit_t	reserved1[0x0001a];
+/* -------------- */
+    pseudo_bit_t	fl[0x00001];           /* Force LoopBack */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	c[0x00002];            /* Create CQE (for "requested signalling" QP) */
+    pseudo_bit_t	icrc[0x00001];         /* last dword of the packet: 0 - Calculate ICRC and put it instead of last dword. 1 - Leave last dword as is. */
+    pseudo_bit_t	reserved3[0x00003];
+    pseudo_bit_t	sl[0x00004];
+    pseudo_bit_t	max_statrate[0x00004];
+    pseudo_bit_t	slr[0x00001];          /* 0= take slid from port. 1= take slid from given headers */
+    pseudo_bit_t	v15[0x00001];          /* Send packet over VL15 */
+    pseudo_bit_t	reserved4[0x0000e];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00010];
+    pseudo_bit_t	rlid[0x00010];         /* Destination LID (must match given headers) */
+/* -------------- */
+}; 
+
+/* Send WQE segment format */
+
+struct hermonprm_send_wqe_segment_st {	/* Little Endian */
+    struct hermonprm_wqe_segment_ctrl_send_st	wqe_segment_ctrl_send;/* Send wqe segment ctrl */
+/* -------------- */
+    struct hermonprm_wqe_segment_rd_st	wqe_segment_rd;/* Send wqe segment rd */
+/* -------------- */
+    struct hermonprm_wqe_segment_ud_st	wqe_segment_ud;/* Send wqe segment ud */
+/* -------------- */
+    struct hermonprm_wqe_segment_bind_st	wqe_segment_bind;/* Send wqe segment bind */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00180];
+/* -------------- */
+    struct hermonprm_wqe_segment_remote_address_st	wqe_segment_remote_address;/* Send wqe segment remote address */
+/* -------------- */
+    struct hermonprm_wqe_segment_atomic_st	wqe_segment_atomic;/* Send wqe segment atomic */
+/* -------------- */
+    struct hermonprm_fast_registration_segment_st	fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+    struct hermonprm_local_invalidate_segment_st	local_invalidate_segment;/* local invalidate segment */
+/* -------------- */
+    struct hermonprm_wqe_segment_data_ptr_st	wqe_segment_data_ptr;/* Send wqe segment data ptr */
+/* -------------- */
+    struct hermonprm_wqe_segment_data_inline_st	wqe_segment_data_inline;/* Send wqe segment data inline */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00200];
+/* -------------- */
+}; 
+
+/* QP and EE Context Entry */
+
+struct hermonprm_queue_pair_ee_context_entry_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	reserved1[0x00001];
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	pm_state[0x00002];     /* Path migration state (Migrated, Armed or Rearm)
+                                                 11-Migrated
+                                                 00-Armed
+                                                 01-Rearm
+                                                 10-Reserved
+                                                 Should be set to 11 for UD QPs and for QPs which do not support APM */
+    pseudo_bit_t	reserved3[0x00003];
+    pseudo_bit_t	st[0x00004];           /* Transport Service Type: RC: 0, UC: 1, RD: 2, UD: 3, FCMND:4, FEXCH:5, SRC:6, MLX 7, Raw Eth 11 */
+    pseudo_bit_t	reserved4[0x00008];
+    pseudo_bit_t	state[0x00004];        /* QP/EE state:
+                                                 0 - RST
+                                                 1 - INIT
+                                                 2 - RTR
+                                                 3 - RTS
+                                                 4 - SQEr
+                                                 5 - SQD (Send Queue Drained)
+                                                 6 - ERR
+                                                 7 - Send Queue Draining
+                                                 8 - Reserved
+                                                 9 - Suspended
+                                                 A- F - Reserved
+                                                 (Valid for QUERY_QPEE and ERR2RST_QPEE commands only) */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];
+    pseudo_bit_t	reserved5[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00004];
+    pseudo_bit_t	rlky[0x00001];         /* When set this QP can use the Reserved L_Key */
+    pseudo_bit_t	reserved7[0x00003];
+    pseudo_bit_t	log_sq_stride[0x00003];/* Stride on the send queue. WQ entry is 16*(2^log_SQ_stride) bytes.
+                                                 Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+    pseudo_bit_t	log_sq_size[0x00004];  /* Log2 of the Number of WQEs in the Send Queue. */
+    pseudo_bit_t	reserved8[0x00001];
+    pseudo_bit_t	log_rq_stride[0x00003];/* Stride on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes.
+                                                 Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+    pseudo_bit_t	log_rq_size[0x00004];  /* Log2 of the Number of WQEs in the Receive Queue. */
+    pseudo_bit_t	reserved9[0x00001];
+    pseudo_bit_t	msg_max[0x00005];      /* Max message size allowed on the QP. Maximum message size is 2^msg_Max.
+                                                 Must be equal to MTU for UD and MLX QPs. */
+    pseudo_bit_t	mtu[0x00003];          /* MTU of the QP (Must be the same for both paths: primary and alternative):
+                                                 0x1 - 256 bytes
+                                                 0x2 - 512
+                                                 0x3 - 1024
+                                                 0x4 - 2048
+                                                 other - reserved
+                                                 
+                                                 Should be configured to 0x4 for UD and MLX QPs. */
+/* -------------- */
+    pseudo_bit_t	usr_page[0x00018];     /* UAR number to ring doorbells for this QP (aliased to doorbell and Blue Flame pages) */
+    pseudo_bit_t	reserved10[0x00008];
+/* -------------- */
+    pseudo_bit_t	local_qpn_een[0x00018];/* Local QP/EE number Lower bits determine position of this record in QPC table, and - thus - constrained
+                                                 This field is valid for QUERY and ERR2RST commands only. */
+    pseudo_bit_t	reserved11[0x00008];
+/* -------------- */
+    pseudo_bit_t	remote_qpn_een[0x00018];/* Remote QP/EE number */
+    pseudo_bit_t	reserved12[0x00008];
+/* -------------- */
+    struct hermonprm_address_path_st	primary_address_path;/* Primary address path for the QP/EE */
+/* -------------- */
+    struct hermonprm_address_path_st	alternative_address_path;/* Alternate address path for the QP/EE */
+/* -------------- */
+    pseudo_bit_t	reserved13[0x00003];
+    pseudo_bit_t	reserved14[0x00001];
+    pseudo_bit_t	reserved15[0x00001];
+    pseudo_bit_t	cur_retry_cnt[0x00003];/* Current transport retry counter (QUERY_QPEE only).
+                                                 The current transport retry counter can vary from retry_count down to 1, where 1 means that the last retry attempt is currently executing. */
+    pseudo_bit_t	cur_rnr_retry[0x00003];/* Current RNR retry counter (QUERY_QPEE only).
+                                                 The current RNR retry counter can vary from rnr_retry to 1, where 1 means that the last retry attempt is currently executing. */
+    pseudo_bit_t	fre[0x00001];          /* Fast Registration Work Request Enabled. (Reserved for EE) */
+    pseudo_bit_t	reserved16[0x00001];
+    pseudo_bit_t	rnr_retry[0x00003];
+    pseudo_bit_t	retry_count[0x00003];  /* Transport timeout Retry count */
+    pseudo_bit_t	reserved17[0x00002];
+    pseudo_bit_t	sra_max[0x00003];      /* Maximum number of outstanding RDMA-read/Atomic operations allowed in the send queue. Maximum number is 2^SRA_Max. Must be zero in EE context. */
+    pseudo_bit_t	reserved18[0x00004];
+    pseudo_bit_t	ack_req_freq[0x00004]; /* ACK required frequency. ACK required bit will be set in every 2^AckReqFreq packets at least. Not valid for RD QP. */
+/* -------------- */
+    pseudo_bit_t	reserved19[0x00020];
+/* -------------- */
+    pseudo_bit_t	next_send_psn[0x00018];/* Next PSN to be sent */
+    pseudo_bit_t	reserved20[0x00008];
+/* -------------- */
+    pseudo_bit_t	cqn_snd[0x00018];      /* CQ number completions from the send queue to be reported to. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved21[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved22[0x00040];
+/* -------------- */
+    pseudo_bit_t	last_acked_psn[0x00018];/* The last acknowledged PSN for the requester (QUERY_QPEE only) */
+    pseudo_bit_t	reserved23[0x00008];
+/* -------------- */
+    pseudo_bit_t	ssn[0x00018];          /* Requester Send Sequence Number (QUERY_QPEE only) */
+    pseudo_bit_t	reserved24[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved25[0x00004];
+    pseudo_bit_t	ric[0x00001];          /* Invalid Credits. 
+                                                 1 - place "Invalid Credits" to ACKs sent from this queue.
+                                                 0 - ACKs report the actual number of end to end credits on the connection.
+                                                 Not valid (reserved) in EE context.
+                                                 Must be set to 1 on QPs which are attached to SRQ. */
+    pseudo_bit_t	reserved26[0x00001];
+    pseudo_bit_t	page_offset[0x00006];  /* start address of wqes in first page (11:6), bits [5:0] reserved */
+    pseudo_bit_t	reserved27[0x00001];
+    pseudo_bit_t	rae[0x00001];          /* If set - Atomic operations enabled. on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	rwe[0x00001];          /* If set - RDMA - write enabled on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	rre[0x00001];          /* If set - RDMA - read enabled on receive queue. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved28[0x00005];
+    pseudo_bit_t	rra_max[0x00003];      /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max. 
+                                                 Must be 0 for EE context. */
+    pseudo_bit_t	physical_function[0x00008];
+/* -------------- */
+    pseudo_bit_t	next_rcv_psn[0x00018]; /* Next (expected) PSN on receive */
+    pseudo_bit_t	min_rnr_nak[0x00005];  /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8). 
+                                                 Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved30[0x00003];
+/* -------------- */
+    pseudo_bit_t	srcd[0x00010];         /* Scalable Reliable Connection Domain. Valid for SRC transport service */
+    pseudo_bit_t	reserved31[0x00010];
+/* -------------- */
+    pseudo_bit_t	cqn_rcv[0x00018];      /* CQ number completions from receive queue to be reported to. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved32[0x00008];
+/* -------------- */
+    pseudo_bit_t	db_record_addr_h[0x00020];/* QP DB Record physical address */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x00002];
+    pseudo_bit_t	db_record_addr_l[0x0001e];/* QP DB Record physical address */
+/* -------------- */
+    pseudo_bit_t	q_key[0x00020];        /* Q_Key to be validated against received datagrams.
+                                                 On send datagrams, if Q_Key[31] specified in the WQE is set, then this Q_Key will be transmitted in the outgoing message.
+                                                 Not valid (reserved) in EE context. */
+/* -------------- */
+    pseudo_bit_t	srqn[0x00018];         /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors. 
+                                                 SRQN is valid only if SRQ bit is set. Not valid (reserved) in EE context. */
+    pseudo_bit_t	srq[0x00001];          /* SRQ - Shared Receive Queue. If this bit is set, then the QP is associated with a SRQ. Not valid (reserved) in EE context. */
+    pseudo_bit_t	reserved34[0x00007];
+/* -------------- */
+    pseudo_bit_t	rmsn[0x00018];         /* Responder current message sequence number (QUERY_QPEE only) */
+    pseudo_bit_t	reserved35[0x00008];
+/* -------------- */
+    pseudo_bit_t	sq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the SQ.
+                                                 Must be 0x0 in SQ initialization.
+                                                 (QUERY_QPEE only). */
+    pseudo_bit_t	rq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the RQ.
+                                                 Must be 0x0 in RQ initialization.
+                                                 (QUERY_QPEE only). */
+/* -------------- */
+    pseudo_bit_t	reserved36[0x00040];
+/* -------------- */
+    pseudo_bit_t	rmc_parent_qpn[0x00018];/* reliable multicast parent queue number */
+    pseudo_bit_t	hs[0x00001];           /* Header Separation. If set, the byte count of the first scatter entry will be ignored. The buffer specified by the first scatter entry will contain packet headers (up to TCP). CQE will report number of bytes scattered to the first scatter entry. Intended for use on IPoverIB on UD QP or Raw Ethernet QP. */
+    pseudo_bit_t	is[0x00001];           /* when set - inline scatter is enabled for this RQ */
+    pseudo_bit_t	reserved37[0x00001];
+    pseudo_bit_t	rme[0x00002];          /* Reliable Multicast
+                                                 00 - disabled
+                                                 01 - parent QP (requester)
+                                                 10 - child QP (requester)
+                                                 11 - responder QP
+                                                 Note that Reliable Multicast is a preliminary definition which can be subject to change. */
+    pseudo_bit_t	reserved38[0x00002];
+    pseudo_bit_t	mkey_rmp[0x00001];     /* If set, MKey used to access TPT for incoming RDMA-write request is calculated by adding MKey from the packet to base_MKey field in the QPC. Can be set only for QPs that are not target for RDMA-read request. */
+/* -------------- */
+    pseudo_bit_t	base_mkey[0x00018];    /* Base Mkey bits [31:8]. Lower 8 bits must be zero. */
+    pseudo_bit_t	num_rmc_peers[0x00008];/* Number of remote peers in Reliable Multicast group */
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00008];/* MTT Base Address [39:32] in ICM relative to INIT_HCA.mtt_base_addr */
+    pseudo_bit_t	reserved39[0x00010];
+    pseudo_bit_t	log2_page_size[0x00006];/* Log (base 2) of MTT page size in units of 4KByte */
+    pseudo_bit_t	reserved40[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved41[0x00003];
+    pseudo_bit_t	mtt_base_addr_l[0x0001d];/* MTT Base Address [31:3] in ICM relative to INIT_HCA.mtt_base_addr */
+/* -------------- */
+    pseudo_bit_t	vft_lan[0x0000c];
+    pseudo_bit_t	vft_prio[0x00003];     /* The Priority filed in the VFT header for FCP */
+    pseudo_bit_t	reserved42[0x00001];
+    pseudo_bit_t	cs_ctl[0x00009];       /* The Priority filed in the VFT header for FCP */
+    pseudo_bit_t	reserved43[0x00006];
+    pseudo_bit_t	ve[0x00001];           /* Should we add/check the VFT header */
+/* -------------- */
+    pseudo_bit_t	exch_base[0x00010];    /* For init QP only - The base exchanges */
+    pseudo_bit_t	reserved44[0x00008];
+    pseudo_bit_t	exch_size[0x00004];    /* For CMMD QP only - The size (from base) exchanges is 2exchanges_size */
+    pseudo_bit_t	reserved45[0x00003];
+    pseudo_bit_t	fc[0x00001];           /* When set it mean that this QP is used for FIBRE CHANNEL. */
+/* -------------- */
+    pseudo_bit_t	remote_id[0x00018];    /* Peer NX port ID */
+    pseudo_bit_t	reserved46[0x00008];
+/* -------------- */
+    pseudo_bit_t	fcp_mtu[0x0000a];      /* In 4*Bytes units. The MTU Size */
+    pseudo_bit_t	reserved47[0x00006];
+    pseudo_bit_t	my_id_indx[0x00008];   /* Index to My NX port ID table */
+    pseudo_bit_t	vft_hop_count[0x00008];/* HopCnt value for the VFT header */
+/* -------------- */
+    pseudo_bit_t	reserved48[0x000c0];
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_mcg_qp_dw_st {	/* Little Endian */
+    pseudo_bit_t	qpn[0x00018];
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	blck_lb[0x00001];
+    pseudo_bit_t	reserved1[0x00001];
+/* -------------- */
+}; 
+
+/* Clear Interrupt [63:0]              #### michal - match to PRM */
+
+struct hermonprm_clr_int_st {	/* Little Endian */
+    pseudo_bit_t	clr_int_h[0x00020];    /* Clear Interrupt [63:32]
+                                                 Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. 
+                                                 This register is write-only. Reading from this register will cause undefined result
+                                                  */
+/* -------------- */
+    pseudo_bit_t	clr_int_l[0x00020];    /* Clear Interrupt [31:0]
+                                                 Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. 
+                                                 This register is write-only. Reading from this register will cause undefined result */
+/* -------------- */
+}; 
+
+/* EQ Set CI DBs Table */
+
+struct hermonprm_eq_set_ci_table_st {	/* Little Endian */
+    pseudo_bit_t	eq0_set_ci[0x00020];   /* EQ0_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq1_set_ci[0x00020];   /* EQ1_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq2_set_ci[0x00020];   /* EQ2_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq3_set_ci[0x00020];   /* EQ3_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq4_set_ci[0x00020];   /* EQ4_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq5_set_ci[0x00020];   /* EQ5_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq6_set_ci[0x00020];   /* EQ6_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq7_set_ci[0x00020];   /* EQ7_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq8_set_ci[0x00020];   /* EQ8_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq9_set_ci[0x00020];   /* EQ9_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq10_set_ci[0x00020];  /* EQ10_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq11_set_ci[0x00020];  /* EQ11_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq12_set_ci[0x00020];  /* EQ12_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq13_set_ci[0x00020];  /* EQ13_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved13[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq14_set_ci[0x00020];  /* EQ14_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved14[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq15_set_ci[0x00020];  /* EQ15_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq16_set_ci[0x00020];  /* EQ16_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved16[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq17_set_ci[0x00020];  /* EQ17_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq18_set_ci[0x00020];  /* EQ18_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved18[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq19_set_ci[0x00020];  /* EQ19_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved19[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq20_set_ci[0x00020];  /* EQ20_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved20[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq21_set_ci[0x00020];  /* EQ21_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved21[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq22_set_ci[0x00020];  /* EQ22_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved22[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq23_set_ci[0x00020];  /* EQ23_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved23[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq24_set_ci[0x00020];  /* EQ24_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved24[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq25_set_ci[0x00020];  /* EQ25_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved25[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq26_set_ci[0x00020];  /* EQ26_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved26[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq27_set_ci[0x00020];  /* EQ27_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved27[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq28_set_ci[0x00020];  /* EQ28_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved28[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq29_set_ci[0x00020];  /* EQ29_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved29[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq30_set_ci[0x00020];  /* EQ30_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved30[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq31_set_ci[0x00020];  /* EQ31_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved31[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq32_set_ci[0x00020];  /* EQ32_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved32[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq33_set_ci[0x00020];  /* EQ33_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq34_set_ci[0x00020];  /* EQ34_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved34[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq35_set_ci[0x00020];  /* EQ35_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved35[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq36_set_ci[0x00020];  /* EQ36_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved36[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq37_set_ci[0x00020];  /* EQ37_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved37[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq38_set_ci[0x00020];  /* EQ38_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved38[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq39_set_ci[0x00020];  /* EQ39_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved39[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq40_set_ci[0x00020];  /* EQ40_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved40[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq41_set_ci[0x00020];  /* EQ41_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved41[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq42_set_ci[0x00020];  /* EQ42_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved42[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq43_set_ci[0x00020];  /* EQ43_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved43[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq44_set_ci[0x00020];  /* EQ44_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved44[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq45_set_ci[0x00020];  /* EQ45_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved45[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq46_set_ci[0x00020];  /* EQ46_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved46[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq47_set_ci[0x00020];  /* EQ47_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved47[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq48_set_ci[0x00020];  /* EQ48_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved48[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq49_set_ci[0x00020];  /* EQ49_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved49[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq50_set_ci[0x00020];  /* EQ50_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved50[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq51_set_ci[0x00020];  /* EQ51_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved51[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq52_set_ci[0x00020];  /* EQ52_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved52[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq53_set_ci[0x00020];  /* EQ53_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved53[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq54_set_ci[0x00020];  /* EQ54_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved54[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq55_set_ci[0x00020];  /* EQ55_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved55[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq56_set_ci[0x00020];  /* EQ56_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved56[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq57_set_ci[0x00020];  /* EQ57_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved57[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq58_set_ci[0x00020];  /* EQ58_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved58[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq59_set_ci[0x00020];  /* EQ59_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved59[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq60_set_ci[0x00020];  /* EQ60_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved60[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq61_set_ci[0x00020];  /* EQ61_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved61[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq62_set_ci[0x00020];  /* EQ62_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved62[0x00020];
+/* -------------- */
+    pseudo_bit_t	eq63_set_ci[0x00020];  /* EQ63_Set_CI */
+/* -------------- */
+    pseudo_bit_t	reserved63[0x00020];
+/* -------------- */
+}; 
+
+/* InfiniHost-III-EX Configuration Registers     #### michal - match to PRM */
+
+struct hermonprm_configuration_registers_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x403400];
+/* -------------- */
+    struct hermonprm_hca_command_register_st	hca_command_interface_register;/* HCA Command Register */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x3fcb20];
+/* -------------- */
+}; 
+
+/* QP_DB_Record         ### michal = gdror fixed */
+
+struct hermonprm_qp_db_record_st {	/* Little Endian */
+    pseudo_bit_t	receive_wqe_counter[0x00010];/* Modulo-64K counter of WQEs posted to the QP since its creation. Should be initialized to zero. */
+    pseudo_bit_t	reserved0[0x00010];
+/* -------------- */
+}; 
+
+/* CQ_ARM_DB_Record */
+
+struct hermonprm_cq_arm_db_record_st {	/* Little Endian */
+    pseudo_bit_t	counter[0x00020];      /* CQ counter for the arming request */
+/* -------------- */
+    pseudo_bit_t	cmd[0x00003];          /* 0x0 - No command
+                                                 0x1 - Request notification for next Solicited completion event. Counter filed specifies the current CQ Consumer Counter.
+                                                 0x2 - Request notification for next Solicited or Unsolicited completion event. Counter filed specifies the current CQ Consumer counter.
+                                                 0x3 - Request notification for multiple completions (Arm-N). Counter filed specifies the value of the CQ Index that when reached by HW (i.e. HW generates a CQE into this Index) Event will be generated
+                                                 Other - Reserved */
+    pseudo_bit_t	cmd_sn[0x00002];       /* Command Sequence Number - See Table 35, "CQ Doorbell Layout" for definition of this filed */
+    pseudo_bit_t	res[0x00003];          /* Must be 0x2 */
+    pseudo_bit_t	cq_number[0x00018];    /* CQ number */
+/* -------------- */
+}; 
+
+/* CQ_CI_DB_Record */
+
+struct hermonprm_cq_ci_db_record_st {	/* Little Endian */
+    pseudo_bit_t	counter[0x00020];      /* CQ counter */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	res[0x00003];          /* Must be 0x1 */
+    pseudo_bit_t	cq_number[0x00018];    /* CQ number */
+/* -------------- */
+}; 
+
+/* Virtual_Physical_Mapping */
+
+struct hermonprm_virtual_physical_mapping_st {	/* Little Endian */
+    pseudo_bit_t	va_h[0x00020];         /* Virtual Address[63:32]. Valid only for MAP_ICM command. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x0000c];
+    pseudo_bit_t	va_l[0x00014];         /* Virtual Address[31:12]. Valid only for MAP_ICM command. */
+/* -------------- */
+    pseudo_bit_t	pa_h[0x00020];         /* Physical Address[63:32] */
+/* -------------- */
+    pseudo_bit_t	log2size[0x00006];     /* Log2 of the size in 4KB pages of the physical and virtual contiguous memory that starts at PA_L/H and VA_L/H */
+    pseudo_bit_t	reserved1[0x00006];
+    pseudo_bit_t	pa_l[0x00014];         /* Physical Address[31:12] */
+/* -------------- */
+}; 
+
+/* MOD_STAT_CFG            #### michal - gdror fix */
+
+struct hermonprm_mod_stat_cfg_st {	/* Little Endian */
+    pseudo_bit_t	log_pg_sz[0x00008];
+    pseudo_bit_t	log_pg_sz_m[0x00001];
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	dife[0x00001];
+    pseudo_bit_t	dife_m[0x00001];
+    pseudo_bit_t	rx_options[0x00004];   /* number of RX options to sweep when doing SerDes parameters AutoNegotiation. */
+    pseudo_bit_t	reserved1[0x00003];
+    pseudo_bit_t	rx_options_m[0x00001]; /* Modify rx_options */
+    pseudo_bit_t	tx_options[0x00004];   /* number of TX options to sweep when doing SerDes parameters AutoNegotiation. */
+    pseudo_bit_t	reserved2[0x00003];
+    pseudo_bit_t	tx_options_m[0x00001]; /* Modify tx_options */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00010];
+    pseudo_bit_t	qdr_rx_options[0x00004];
+    pseudo_bit_t	reserved4[0x00003];
+    pseudo_bit_t	qdr_rx_options_m[0x00001];
+    pseudo_bit_t	qdr_tx_options[0x00004];
+    pseudo_bit_t	reserved5[0x00003];
+    pseudo_bit_t	qdr_tx_options_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	lid[0x00010];          /* default LID */
+    pseudo_bit_t	lid_m[0x00001];        /* Modify default LID */
+    pseudo_bit_t	reserved7[0x00003];
+    pseudo_bit_t	port_en[0x00001];      /* enable port (E_Key) */
+    pseudo_bit_t	port_en_m[0x00001];    /* Modify  port_en */
+    pseudo_bit_t	reserved8[0x00002];
+    pseudo_bit_t	port_pause_mode[0x00002];
+    pseudo_bit_t	reserved9[0x00001];
+    pseudo_bit_t	port_pause_mode_m[0x00001];
+    pseudo_bit_t	reserved10[0x00004];
+/* -------------- */
+    pseudo_bit_t	reserved11[0x0001f];
+    pseudo_bit_t	guid_hi_m[0x00001];    /* Modify guid_hi */
+/* -------------- */
+    pseudo_bit_t	guid_hi[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved12[0x0001f];
+    pseudo_bit_t	guid_lo_m[0x00001];    /* Modify guid_lo */
+/* -------------- */
+    pseudo_bit_t	guid_lo[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved13[0x0001f];
+    pseudo_bit_t	nodeguid_hi_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	nodeguid_hi[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved14[0x0001f];
+    pseudo_bit_t	nodeguid_lo_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	nodeguid_lo[0x00020];
+/* -------------- */
+    pseudo_bit_t	ob_preemp_pre[0x00005];
+    pseudo_bit_t	reserved15[0x00003];
+    pseudo_bit_t	ob_preemp_post[0x00005];
+    pseudo_bit_t	reserved16[0x00003];
+    pseudo_bit_t	ob_preemp_main[0x00005];
+    pseudo_bit_t	reserved17[0x00003];
+    pseudo_bit_t	ob_preemp[0x00005];
+    pseudo_bit_t	reserved18[0x00002];
+    pseudo_bit_t	serdes_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	inbuf_ind_en[0x00003];
+    pseudo_bit_t	reserved19[0x00001];
+    pseudo_bit_t	sd_main[0x00004];
+    pseudo_bit_t	reserved20[0x00004];
+    pseudo_bit_t	sd_equal[0x00004];
+    pseudo_bit_t	reserved21[0x00004];
+    pseudo_bit_t	sd_mux_main[0x00002];
+    pseudo_bit_t	reserved22[0x00002];
+    pseudo_bit_t	mux_eq[0x00002];
+    pseudo_bit_t	reserved23[0x00002];
+    pseudo_bit_t	sigdet_th[0x00003];
+    pseudo_bit_t	reserved24[0x00001];
+/* -------------- */
+    pseudo_bit_t	reserved25[0x00040];
+/* -------------- */
+    pseudo_bit_t	port_protocol[0x00008];
+    pseudo_bit_t	port_dual[0x00001];
+    pseudo_bit_t	reserved26[0x00006];
+    pseudo_bit_t	port_protocol_m[0x00001];
+    pseudo_bit_t	num_port[0x00008];
+    pseudo_bit_t	reserved27[0x00008];
+/* -------------- */
+    pseudo_bit_t	port_protocol_vpi[0x00008];
+    pseudo_bit_t	reserved28[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved29[0x00180];
+/* -------------- */
+    pseudo_bit_t	fw_rev_major[0x00010];
+    pseudo_bit_t	reserved30[0x0000f];
+    pseudo_bit_t	fw_rev_support[0x00001];
+/* -------------- */
+    pseudo_bit_t	fw_rev_minor[0x00010];
+    pseudo_bit_t	fw_rev_subminor[0x00010];
+/* -------------- */
+    pseudo_bit_t	cmd_interface_rev[0x00010];
+    pseudo_bit_t	reserved31[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved32[0x00060];
+/* -------------- */
+    pseudo_bit_t	mac_high[0x00010];
+    pseudo_bit_t	reserved33[0x0000f];
+    pseudo_bit_t	mac_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	mac_low[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved34[0x00010];
+    pseudo_bit_t	num_veps[0x00008];
+    pseudo_bit_t	num_vep_groups[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved35[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved36[0x00018];
+    pseudo_bit_t	outer_vlan_en[0x00001];
+    pseudo_bit_t	reserved37[0x00002];
+    pseudo_bit_t	outer_vlan_en_m[0x00001];
+    pseudo_bit_t	port_net_boot[0x00001];
+    pseudo_bit_t	reserved38[0x00002];
+    pseudo_bit_t	port_net_boot_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	reserved39[0x00060];
+/* -------------- */
+    pseudo_bit_t	port_eth_mode_capability[0x0001f];
+    pseudo_bit_t	reserved40[0x00001];
+/* -------------- */
+    pseudo_bit_t	port_eth_mode_enabled[0x0001f];
+    pseudo_bit_t	port_eth_mod_m[0x00001];
+/* -------------- */
+    pseudo_bit_t	port_eth_mode_current[0x0001f];
+    pseudo_bit_t	reserved41[0x00001];
+/* -------------- */
+    pseudo_bit_t	reserved42[0x00220];
+};
+
+/* SRQ Context */
+
+struct hermonprm_srq_context_st {	/* Little Endian */
+    pseudo_bit_t	srqn[0x00018];         /* SRQ number */
+    pseudo_bit_t	log_srq_size[0x00004]; /* Log2 of the Number of WQEs in the Receive Queue.
+                                                 Maximum value is 0x10, i.e. 16M WQEs. */
+    pseudo_bit_t	state[0x00004];        /* SRQ State:
+                                                 1111 - SW Ownership
+                                                 0000 - HW Ownership
+                                                 0001 - Error
+                                                 Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+    pseudo_bit_t	src_domain[0x00010];   /* The Scalable RC Domain. Messages coming to receive ports specifying this SRQ as receive queue will be served only if SRC_Domain of the SRQ matches SRC_Domain of the transport QP of this message. */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	log_srq_stride[0x00003];/* Stride (max WQE size) on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes. */
+    pseudo_bit_t	reserved1[0x00005];
+/* -------------- */
+    pseudo_bit_t	cqn[0x00018];          /* Completion Queue to report SRC messages directed to this SRQ. */
+    pseudo_bit_t	page_offset[0x00006];  /* The offset of the first WQE from the beginning of 4Kbyte page (Figure 52,“Work Queue Buffer Structure”) */
+    pseudo_bit_t	reserved2[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00008];/* MTT Base Address [39:32] in ICM relative to INIT_HCA.mtt_base_addr */
+    pseudo_bit_t	reserved4[0x00010];
+    pseudo_bit_t	log2_page_size[0x00006];/* Log (base 2) of MTT page size in units of 4KByte */
+    pseudo_bit_t	reserved5[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00003];
+    pseudo_bit_t	mtt_base_addr_l[0x0001d];/* MTT Base Address [31:3] in ICM relative to INIT_HCA.mtt_base_addr */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* SRQ protection domain */
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	wqe_cnt[0x00010];      /* WQE count on the SRQ. Valid only upon QUERY_SRQ and HW2SW_SRQ commands. */
+    pseudo_bit_t	lwm[0x00010];          /* Limit Water Mark - if the LWM is not zero, and the wqe_cnt drops below LWM when a WQE is dequeued from the SRQ, then an SRQ limit event is fired and the LWM is set to zero. Valid only upon QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+    pseudo_bit_t	srq_wqe_counter[0x00010];/* A 16-bit counter incremented for each WQE posted to the SRQ. Must be 0x0 in SRQ initialization. Valid only upon the QUERY_SRQ command. */
+    pseudo_bit_t	reserved8[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	db_record_addr_h[0x00020];/* SRQ DB Record physical address [63:32] */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00002];
+    pseudo_bit_t	db_record_addr_l[0x0001e];/* SRQ DB Record physical address [31:2] */
+/* -------------- */
+}; 
+
+/* PBL */
+
+struct hermonprm_pbl_st {	/* Little Endian */
+    pseudo_bit_t	mtt_0_h[0x00020];      /* First MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_0_l[0x00020];      /* First MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_1_h[0x00020];      /* Second MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_1_l[0x00020];      /* Second MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_2_h[0x00020];      /* Third MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_2_l[0x00020];      /* Third MTT[31:0] */
+/* -------------- */
+    pseudo_bit_t	mtt_3_h[0x00020];      /* Fourth MTT[63:32] */
+/* -------------- */
+    pseudo_bit_t	mtt_3_l[0x00020];      /* Fourth MTT[31:0] */
+/* -------------- */
+}; 
+
+/* Performance Counters   #### michal - gdror fixed */
+
+struct hermonprm_performance_counters_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00080];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00080];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00620];
+/* -------------- */
+}; 
+
+/* Transport and CI Error Counters */
+
+struct hermonprm_transport_and_ci_error_counters_st {	/* Little Endian */
+    pseudo_bit_t	rq_num_lle[0x00020];   /* Responder - number of local length errors */
+/* -------------- */
+    pseudo_bit_t	sq_num_lle[0x00020];   /* Requester - number of local length errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_lqpoe[0x00020]; /* Responder - number local QP operation error */
+/* -------------- */
+    pseudo_bit_t	sq_num_lqpoe[0x00020]; /* Requester - number local QP operation error */
+/* -------------- */
+    pseudo_bit_t	rq_num_leeoe[0x00020]; /* Responder - number local EE operation error */
+/* -------------- */
+    pseudo_bit_t	sq_num_leeoe[0x00020]; /* Requester - number local EE operation error */
+/* -------------- */
+    pseudo_bit_t	rq_num_lpe[0x00020];   /* Responder - number of local protection errors */
+/* -------------- */
+    pseudo_bit_t	sq_num_lpe[0x00020];   /* Requester - number of local protection errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_wrfe[0x00020];  /* Responder - number of CQEs with error. 
+                                                 Incremented each time a CQE with error is generated */
+/* -------------- */
+    pseudo_bit_t	sq_num_wrfe[0x00020];  /* Requester - number of CQEs with error. 
+                                                 Incremented each time a CQE with error is generated */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_mwbe[0x00020];  /* Requester - number of memory window bind errors */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_bre[0x00020];   /* Requester - number of bad response errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_lae[0x00020];   /* Responder - number of local access errors */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	sq_num_rire[0x00020];  /* Requester - number of remote invalid request errors
+                                                 NAK-Invalid Request on:
+                                                 1. Unsupported OpCode: Responder detected an unsupported OpCode.
+                                                 2. Unexpected OpCode: Responder detected an error in the sequence of OpCodes, such
+                                                 as a missing "Last" packet.
+                                                 Note: there is no PSN error, thus this does not indicate a dropped packet. */
+/* -------------- */
+    pseudo_bit_t	rq_num_rire[0x00020];  /* Responder - number of remote invalid request errors.
+                                                 NAK may or may not be sent.
+                                                 1. QP Async Affiliated Error: Unsupported or Reserved OpCode (RC,RD only):
+                                                 Inbound request OpCode was either reserved, or was for a function not supported by this
+                                                 QP. (E.g. RDMA or ATOMIC on QP not set up for this).
+                                                 2. Misaligned ATOMIC: VA does not point to an aligned address on an atomic opera-tion.
+                                                 3. Too many RDMA READ or ATOMIC Requests: There were more requests received
+                                                 and not ACKed than allowed for the connection.
+                                                 4. Out of Sequence OpCode, current packet is "First" or "Only": The Responder
+                                                 detected an error in the sequence of OpCodes; a missing "Last" packet
+                                                 5. Out of Sequence OpCode, current packet is not "First" or "Only": The Responder
+                                                 detected an error in the sequence of OpCodes; a missing "First" packet
+                                                 6. Local Length Error: Inbound "Send" request message exceeded the responder.s avail-able
+                                                 buffer space.
+                                                 7. Length error: RDMA WRITE request message contained too much or too little pay-load
+                                                 data compared to the DMA length advertised in the first or only packet.
+                                                 8. Length error: Payload length was not consistent with the opcode:
+                                                 a: 0 byte <= "only" <= PMTU bytes
+                                                 b: ("first" or "middle") == PMTU bytes
+                                                 c: 1byte <= "last" <= PMTU bytes
+                                                 9. Length error: Inbound message exceeded the size supported by the CA port. */
+/* -------------- */
+    pseudo_bit_t	sq_num_rae[0x00020];   /* Requester - number of remote access errors.
+                                                 NAK-Remote Access Error on:
+                                                 R_Key Violation: Responder detected an invalid R_Key while executing an RDMA
+                                                 Request. */
+/* -------------- */
+    pseudo_bit_t	rq_num_rae[0x00020];   /* Responder - number of remote access errors.
+                                                 R_Key Violation Responder detected an R_Key violation while executing an RDMA
+                                                 request.
+                                                 NAK may or may not be sent. */
+/* -------------- */
+    pseudo_bit_t	sq_num_roe[0x00020];   /* Requester - number of remote operation errors.
+                                                 NAK-Remote Operation Error on:
+                                                 Remote Operation Error: Responder encountered an error, (local to the responder),
+                                                 which prevented it from completing the request. */
+/* -------------- */
+    pseudo_bit_t	rq_num_roe[0x00020];   /* Responder - number of remote operation errors.
+                                                 NAK-Remote Operation Error on:
+                                                 1. Malformed WQE: Responder detected a malformed Receive Queue WQE while pro-cessing
+                                                 the packet.
+                                                 2. Remote Operation Error: Responder encountered an error, (local to the responder),
+                                                 which prevented it from completing the request. */
+/* -------------- */
+    pseudo_bit_t	sq_num_tree[0x00020];  /* Requester - number of transport retries exceeded errors */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_rree[0x00020];  /* Requester - number of RNR nak retries exceeded errors */
+/* -------------- */
+    pseudo_bit_t	rq_num_rnr[0x00020];   /* Responder - the number of RNR Naks sent */
+/* -------------- */
+    pseudo_bit_t	sq_num_rnr[0x00020];   /* Requester - the number of RNR Naks received */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_rabrte[0x00020];/* Requester - number of remote aborted errors */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_ieecne[0x00020];/* Requester - number of invalid EE context number errors */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00020];
+/* -------------- */
+    pseudo_bit_t	sq_num_ieecse[0x00020];/* Requester - invalid EE context state errors */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00380];
+/* -------------- */
+    pseudo_bit_t	rq_num_oos[0x00020];   /* Responder - number of out of sequence requests received */
+/* -------------- */
+    pseudo_bit_t	sq_num_oos[0x00020];   /* Requester - number of out of sequence Naks received */
+/* -------------- */
+    pseudo_bit_t	rq_num_mce[0x00020];   /* Responder - number of bad multicast packets received */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	rq_num_rsync[0x00020]; /* Responder - number of RESYNC operations */
+/* -------------- */
+    pseudo_bit_t	sq_num_rsync[0x00020]; /* Requester - number of RESYNC operations */
+/* -------------- */
+    pseudo_bit_t	rq_num_udsdprd[0x00020];/* The number of UD packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00020];
+/* -------------- */
+    pseudo_bit_t	rq_num_ucsdprd[0x00020];/* The number of UC packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+    pseudo_bit_t	reserved11[0x003e0];
+/* -------------- */
+    pseudo_bit_t	num_cqovf[0x00020];    /* Number of CQ overflows */
+/* -------------- */
+    pseudo_bit_t	num_eqovf[0x00020];    /* Number of EQ overflows */
+/* -------------- */
+    pseudo_bit_t	num_baddb[0x00020];    /* Number of bad doorbells */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x002a0];
+/* -------------- */
+}; 
+
+/* Event_data Field - HCR Completion Event   #### michal - match PRM */
+
+struct hermonprm_hcr_completion_event_st {	/* Little Endian */
+    pseudo_bit_t	token[0x00010];        /* HCR Token */
+    pseudo_bit_t	reserved0[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	status[0x00008];       /* HCR Status */
+    pseudo_bit_t	reserved2[0x00018];
+/* -------------- */
+    pseudo_bit_t	out_param_h[0x00020];  /* HCR Output Parameter [63:32] */
+/* -------------- */
+    pseudo_bit_t	out_param_l[0x00020];  /* HCR Output Parameter [31:0] */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+}; 
+
+/* Completion with Error CQE             #### michal - gdror fixed */
+
+struct hermonprm_completion_with_error_st {	/* Little Endian */
+    pseudo_bit_t	qpn[0x00018];          /* Indicates the QP for which completion is being reported */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x000a0];
+/* -------------- */
+    pseudo_bit_t	syndrome[0x00008];     /* Completion with error syndrome:
+                                                         0x01 - Local Length Error
+                                                         0x02 - Local QP Operation Error
+                                                         0x03 - Local EE Context Operation Error
+                                                         0x04 - Local Protection Error
+                                                         0x05 - Work Request Flushed Error 
+                                                         0x06 - Memory Window Bind Error
+                                                         0x10 - Bad Response Error
+                                                         0x11 - Local Access Error
+                                                         0x12 - Remote Invalid Request Error
+                                                         0x13 - Remote Access Error
+                                                         0x14 - Remote Operation Error
+                                                         0x15 - Transport Retry Counter Exceeded
+                                                         0x16 - RNR Retry Counter Exceeded
+                                                         0x20 - Local RDD Violation Error
+                                                         0x21 - Remote Invalid RD Request
+                                                         0x22 - Remote Aborted Error
+                                                         0x23 - Invalid EE Context Number
+                                                         0x24 - Invalid EE Context State
+                                                         other - Reserved
+                                                 Syndrome is defined according to the IB specification volume 1. For detailed explanation of the syndromes, refer to chapters 10-11 of the IB specification rev 1.1. */
+    pseudo_bit_t	vendor_error_syndrome[0x00008];
+    pseudo_bit_t	wqe_counter[0x00010];
+/* -------------- */
+    pseudo_bit_t	opcode[0x00005];       /* The opcode of WQE completion is reported for.
+                                                 
+                                                 The following values are reported in case of completion with error:
+                                                 0xFE - For completion with error on Receive Queues
+                                                 0xFF - For completion with error on Send Queues */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	s_r[0x00001];          /* send 1 / receive 0 */
+    pseudo_bit_t	owner[0x00001];        /* HW Flips this bit for every CQ warp around. Initialized to Zero. */
+    pseudo_bit_t	reserved3[0x00018];
+/* -------------- */
+}; 
+
+/* Resize CQ Input Mailbox */
+
+struct hermonprm_resize_cq_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00006];
+    pseudo_bit_t	page_offset[0x00006];
+    pseudo_bit_t	reserved2[0x00014];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00018];
+    pseudo_bit_t	log_cq_size[0x00005];  /* Log (base 2) of the CQ size (in entries) */
+    pseudo_bit_t	reserved4[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00008];
+    pseudo_bit_t	reserved6[0x00010];
+    pseudo_bit_t	log2_page_size[0x00006];
+    pseudo_bit_t	reserved7[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00003];
+    pseudo_bit_t	mtt_base_addr_l[0x0001d];
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00100];
+/* -------------- */
+}; 
+
+/* MAD_IFC Input Modifier */
+
+struct hermonprm_mad_ifc_input_modifier_st {	/* Little Endian */
+    pseudo_bit_t	port_number[0x00008];  /* The packet reception port number (1 or 2). */
+    pseudo_bit_t	mad_extended_info[0x00001];/* Mad_Extended_Info valid bit (MAD_IFC Input Mailbox data from offset 00100h and down). MAD_Extended_Info is read only if this bit is set.
+                                                 Required for trap generation when BKey check is enabled and for global routed packets. */
+    pseudo_bit_t	reserved0[0x00007];
+    pseudo_bit_t	rlid[0x00010];         /* Remote (source) LID  from the received MAD.
+                                                 This field is required for trap generation upon MKey/BKey validation. */
+/* -------------- */
+}; 
+
+/* MAD_IFC Input Mailbox     ###michal -gdror fixed */
+
+struct hermonprm_mad_ifc_st {	/* Little Endian */
+    pseudo_bit_t	request_mad_packet[64][0x00020];/* Request MAD Packet (256bytes) */
+/* -------------- */
+    pseudo_bit_t	my_qpn[0x00018];       /* Destination QP number from the received MAD. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	rqpn[0x00018];         /* Remote (source) QP number  from the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved2[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00010];
+    pseudo_bit_t	ml_path[0x00007];      /* My (destination) LID path bits  from the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	g[0x00001];            /* If set, the GRH field in valid. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved4[0x00004];
+    pseudo_bit_t	sl[0x00004];           /* Service Level of the received MAD.
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+/* -------------- */
+    pseudo_bit_t	pkey_indx[0x00010];    /* Index in PKey table that matches PKey of the received MAD. 
+                                                 This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+    pseudo_bit_t	reserved5[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00160];
+/* -------------- */
+    pseudo_bit_t	grh[10][0x00020];      /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list. 
+                                                 Valid if Mad_extended_info bit (in the input modifier) and g bit are set. 
+                                                 Otherwise this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x004c0];
+/* -------------- */
+}; 
+
+/* Query Debug Message     #### michal - gdror fixed */
+
+struct hermonprm_query_debug_msg_st {	/* Little Endian */
+    pseudo_bit_t	phy_addr_h[0x00020];   /* Translation of the address in firmware area. High 32 bits. */
+/* -------------- */
+    pseudo_bit_t	v[0x00001];            /* Physical translation is valid */
+    pseudo_bit_t	reserved0[0x0000b];
+    pseudo_bit_t	phy_addr_l[0x00014];   /* Translation of the address in firmware area. Low 32 bits. */
+/* -------------- */
+    pseudo_bit_t	fw_area_base[0x00020]; /* Firmware area base address. The format strings and the trace buffers may be located starting from this address. */
+/* -------------- */
+    pseudo_bit_t	fw_area_size[0x00020]; /* Firmware area size */
+/* -------------- */
+    pseudo_bit_t	trc_hdr_sz[0x00020];   /* Trace message header size in dwords. */
+/* -------------- */
+    pseudo_bit_t	trc_arg_num[0x00020];  /* The number of arguments per trace message. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x000c0];
+/* -------------- */
+    pseudo_bit_t	dbg_msk_h[0x00020];    /* Debug messages mask [63:32] */
+/* -------------- */
+    pseudo_bit_t	dbg_msk_l[0x00020];    /* Debug messages mask [31:0] */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00040];
+/* -------------- */
+    pseudo_bit_t	buff0_addr[0x00020];   /* Address in firmware area of Trace Buffer 0 */
+/* -------------- */
+    pseudo_bit_t	buff0_size[0x00020];   /* Size of Trace Buffer 0 */
+/* -------------- */
+    pseudo_bit_t	buff1_addr[0x00020];   /* Address in firmware area of Trace Buffer 1 */
+/* -------------- */
+    pseudo_bit_t	buff1_size[0x00020];   /* Size of Trace Buffer 1 */
+/* -------------- */
+    pseudo_bit_t	buff2_addr[0x00020];   /* Address in firmware area of Trace Buffer 2 */
+/* -------------- */
+    pseudo_bit_t	buff2_size[0x00020];   /* Size of Trace Buffer 2 */
+/* -------------- */
+    pseudo_bit_t	buff3_addr[0x00020];   /* Address in firmware area of Trace Buffer 3 */
+/* -------------- */
+    pseudo_bit_t	buff3_size[0x00020];   /* Size of Trace Buffer 3 */
+/* -------------- */
+    pseudo_bit_t	buff4_addr[0x00020];   /* Address in firmware area of Trace Buffer 4 */
+/* -------------- */
+    pseudo_bit_t	buff4_size[0x00020];   /* Size of Trace Buffer 4 */
+/* -------------- */
+    pseudo_bit_t	buff5_addr[0x00020];   /* Address in firmware area of Trace Buffer 5 */
+/* -------------- */
+    pseudo_bit_t	buff5_size[0x00020];   /* Size of Trace Buffer 5 */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00080];
+/* -------------- */
+    pseudo_bit_t	hw_buff_addr[0x00020]; /* Dror Mux Bohrer tracer */
+/* -------------- */
+    pseudo_bit_t	hw_buff_size[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x003c0];
+/* -------------- */
+}; 
+
+/* User Access Region */
+
+struct hermonprm_uar_st {	/* Little Endian */
+    struct hermonprm_rd_send_doorbell_st	rd_send_doorbell;/* Reliable Datagram send doorbell */
+/* -------------- */
+    struct hermonprm_send_doorbell_st	send_doorbell;/* Send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    struct hermonprm_cq_cmd_doorbell_st	cq_command_doorbell;/* CQ Doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x03ec0];
+/* -------------- */
+}; 
+
+/* Receive doorbell */
+
+struct hermonprm_receive_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	wqe_counter[0x00010];  /* Modulo-64K counter of WQEs posted on this queue since its creation. Should be zero for the first doorbell on the QP */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00005];
+    pseudo_bit_t	srq[0x00001];          /* If set, this is a Shared Receive Queue */
+    pseudo_bit_t	reserved3[0x00002];
+    pseudo_bit_t	qpn[0x00018];          /* QP number or SRQ number this doorbell is rung on */
+/* -------------- */
+}; 
+
+/* SET_IB Parameters */
+
+struct hermonprm_set_ib_st {	/* Little Endian */
+    pseudo_bit_t	rqk[0x00001];          /* Reset QKey Violation Counter */
+    pseudo_bit_t	reserved0[0x00011];
+    pseudo_bit_t	sig[0x00001];          /* Set System Image GUID to system_image_guid specified.
+                                                 system_image_guid and sig must be the same for all ports. */
+    pseudo_bit_t	reserved1[0x0000d];
+/* -------------- */
+    pseudo_bit_t	capability_mask[0x00020];/* PortInfo Capability Mask */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00180];
+/* -------------- */
+}; 
+
+/* Multicast Group Member    #### michal - gdror fixed */
+
+struct hermonprm_mgm_entry_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	next_gid_index[0x0001a];/* Index of next Multicast Group Member whose GID maps to same MGID_HASH number.
+                                                 The index is into the Multicast Group Table, which is the comprised the MGHT and AMGM tables.
+                                                 next_gid_index=0 means end of the chain. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00060];
+/* -------------- */
+    pseudo_bit_t	mgid_128_96[0x00020];  /* Multicast group GID[128:96] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_95_64[0x00020];   /* Multicast group GID[95:64] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_63_32[0x00020];   /* Multicast group GID[63:32] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    pseudo_bit_t	mgid_31_0[0x00020];    /* Multicast group GID[31:0] in big endian format.
+                                                 Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_0;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_1;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_2;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_3;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_4;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_5;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_6;   /* Multicast Group Member QP */
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp_7;   /* Multicast Group Member QP */
+/* -------------- */
+}; 
+
+/* INIT_PORT Parameters    #### michal - match PRM */
+
+struct hermonprm_init_port_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00004];
+    pseudo_bit_t	vl_cap[0x00004];       /* Maximum VLs supported on the port, excluding VL15.
+                                                 Legal values are 1,2,4 and 8. */
+    pseudo_bit_t	port_width_cap[0x00004];/* IB Port Width
+                                                 1   - 1x
+                                                 3   - 1x, 4x
+                                                 11 - 1x, 4x or 12x (must not be used in InfiniHost-III-EX MT25208)
+                                                 else - Reserved */
+    pseudo_bit_t	reserved1[0x00004];
+    pseudo_bit_t	g0[0x00001];           /* Set port GUID0 to GUID0 specified */
+    pseudo_bit_t	ng[0x00001];           /* Set node GUID to node_guid specified.
+                                                 node_guid and ng must be the same for all ports. */
+    pseudo_bit_t	sig[0x00001];          /* Set System Image GUID to system_image_guid specified.
+                                                 system_image_guid and sig must be the same for all ports. */
+    pseudo_bit_t	reserved2[0x0000d];
+/* -------------- */
+    pseudo_bit_t	max_gid[0x00010];      /* Maximum number of GIDs for the port */
+    pseudo_bit_t	mtu[0x00010];          /* Maximum MTU Supported in bytes
+                                                 must be: 256, 512, 1024, 2048 or 4096
+                                                 For Eth port, can be any
+                                                 Field must not cross device capabilities as reported
+                                                  */
+/* -------------- */
+    pseudo_bit_t	max_pkey[0x00010];     /* Maximum pkeys for the port.
+                                                 Must be the same for both ports. */
+    pseudo_bit_t	reserved3[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00020];
+/* -------------- */
+    pseudo_bit_t	guid0_h[0x00020];      /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 63:32) */
+/* -------------- */
+    pseudo_bit_t	guid0_l[0x00020];      /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 31:0) */
+/* -------------- */
+    pseudo_bit_t	node_guid_h[0x00020];  /* Node GUID[63:32], takes effect only if the NG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	node_guid_l[0x00020];  /* Node GUID[31:0], takes effect only if the NG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+                                                 Must be the same for both ports. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x006c0];
+/* -------------- */
+}; 
+
+/* Query Device Capablities     #### michal - gdror fixed */
+
+struct hermonprm_query_dev_cap_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	log_max_qp[0x00005];   /* Log2 of the Maximum number of QPs supported */
+    pseudo_bit_t	reserved1[0x00003];
+    pseudo_bit_t	log2_rsvd_qps[0x00004];/* Log (base 2) of the number of QPs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_qps-1 */
+    pseudo_bit_t	reserved2[0x00004];
+    pseudo_bit_t	log_max_qp_sz[0x00008];/* The maximum number of WQEs allowed on the RQ or the SQ is 2^log_max_qp_sz-1 */
+    pseudo_bit_t	log_max_srq_sz[0x00008];/* The maximum number of WQEs allowed on the SRQ is 2^log_max_srq_sz-1 */
+/* -------------- */
+    pseudo_bit_t	log_max_scqs[0x00004]; /* log base 2 of number of supported schedule queues */
+    pseudo_bit_t	reserved3[0x00004];
+    pseudo_bit_t	num_rsvd_scqs[0x00006];
+    pseudo_bit_t	reserved4[0x00002];
+    pseudo_bit_t	log_max_srqs[0x00005];
+    pseudo_bit_t	reserved5[0x00007];
+    pseudo_bit_t	log2_rsvd_srqs[0x00004];
+/* -------------- */
+    pseudo_bit_t	log_max_cq[0x00005];   /* Log2 of the Maximum number of CQs supported */
+    pseudo_bit_t	reserved6[0x00003];
+    pseudo_bit_t	log2_rsvd_cqs[0x00004];/* Log (base 2) of the number of CQs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsrvd_cqs-1 */
+    pseudo_bit_t	reserved7[0x00004];
+    pseudo_bit_t	log_max_cq_sz[0x00008];/* Log2 of the Maximum CQEs allowed in a CQ */
+    pseudo_bit_t	num_rsvd_eqs[0x00008]; /* The number of EQs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_rsvd_eqs-1
+                                                 If 0 - no resources are reserved. */
+/* -------------- */
+    pseudo_bit_t	log_max_eq[0x00004];   /* Log2 of the Maximum number of EQs */
+    pseudo_bit_t	reserved9[0x00004];
+    pseudo_bit_t	log2_rsvd_eqs[0x00004]; /* The number of EQs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_rsvd_eqs-1
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	reserved10[0x00004];
+    pseudo_bit_t	log_max_d_mpts[0x00006];/* Log (base 2) of the maximum number of data MPT entries (the number of Regions/Windows) */
+    pseudo_bit_t	reserved11[0x00002];
+    pseudo_bit_t	log_max_eq_sz[0x00008];/* Log2 of the Maximum EQEs allowed in a EQ */
+/* -------------- */
+    pseudo_bit_t	log_max_mtts[0x00006]; /* Log2 of the Maximum number of MTT entries */
+    pseudo_bit_t	reserved12[0x00002];
+    pseudo_bit_t	log2_rsvd_mrws[0x00004];/* Log (base 2) of the number of MPTs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_mrws-1 */
+    pseudo_bit_t	reserved13[0x00004];
+    pseudo_bit_t	log_max_mrw_sz[0x00007];/* Log2 of the Maximum Size of Memory Region/Window. is it in PRM layout? */
+    pseudo_bit_t	reserved14[0x00005];
+    pseudo_bit_t	log2_rsvd_mtts[0x00004];/* Log (base 2) of the number of MTT entries reserved for firmware use
+                                                 The reserved resources are numbered from 0 to 2^log2_rsvd_mtts-1
+                                                  */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00020];
+/* -------------- */
+    pseudo_bit_t	log_max_ra_res_qp[0x00006];/* Log2 of the Maximum number of outstanding RDMA read/Atomic per QP as a responder */
+    pseudo_bit_t	reserved16[0x0000a];
+    pseudo_bit_t	log_max_ra_req_qp[0x00006];/* Log2 of the maximum number of outstanding RDMA read/Atomic per QP as a requester */
+    pseudo_bit_t	reserved17[0x0000a];
+/* -------------- */
+    pseudo_bit_t	log_max_ra_res_global[0x00006];/* Log2 of the maximum number of RDMA read/atomic operations the HCA responder can support globally. That implies the RDB table size. */
+    pseudo_bit_t	reserved18[0x0001a];
+/* -------------- */
+    pseudo_bit_t	rsz_srq[0x00001];      /* Ability to modify the maximum number of WRs per SRQ. */
+    pseudo_bit_t	reserved19[0x0001f];
+/* -------------- */
+    pseudo_bit_t	num_ports[0x00004];    /* Number of IB ports. */
+    pseudo_bit_t	reserved47[0x00004];
+    pseudo_bit_t	pci_pf_num[0x00008];    /* Number of supported physical functions */
+    pseudo_bit_t	local_ca_ack_delay[0x00005];/* The Local CA ACK Delay. This is the value recommended to be returned in Query HCA verb.
+                                                 The delay value in microseconds is computed using 4.096us * 2^(local_ca_ack_delay). */
+    pseudo_bit_t	port_type[0x00004];    /* Hermon New. bit per port. bit0 is first port. value '1' is ehternet. '0' is IB */
+    pseudo_bit_t	reserved20[0x00004];
+    pseudo_bit_t	w[0x00001];            /* Hermon New. 10GB eth support */
+    pseudo_bit_t	j[0x00001];            /* Hermon New. Jumbo frame support */
+    pseudo_bit_t	reserved21[0x00001];
+/* -------------- */
+    pseudo_bit_t	log_max_gid[0x00004];  /* Log2 of the maximum number of GIDs per port */
+    pseudo_bit_t	reserved22[0x00004];
+    pseudo_bit_t	log_ethtype[0x00004];  /* Hermon New. log2 eth type table size */
+    pseudo_bit_t	reserved23[0x00004];
+    pseudo_bit_t	log_drain_size[0x00008];/* Log (base 2) of minimum size of the NoDropVLDrain buffer, specified in 4Kpages units */
+    pseudo_bit_t	log_max_msg[0x00005];  /* Log (base 2) of the maximum message size supported by the device */
+    pseudo_bit_t	reserved24[0x00003];
+/* -------------- */
+    pseudo_bit_t	log_max_pkey[0x00004]; /* Log2 of the max PKey Table Size (per IB port) */
+    pseudo_bit_t	reserved25[0x0000c];
+    pseudo_bit_t	stat_rate_support[0x00010];/* bit mask of stat rate supported
+                                                 bit 0 - full bw
+                                                 bit 1 - 1/4 bw
+                                                 bit 2 - 1/8 bw
+                                                 bit 3 - 1/2 bw; */
+/* -------------- */
+    pseudo_bit_t	reserved26[0x00008];
+    pseudo_bit_t	rss_udp[0x00001];
+    pseudo_bit_t	vep_uc_steering[0x00001];
+    pseudo_bit_t	vep_mc_steering[0x00001];
+    pseudo_bit_t	reserved27[0x00015];
+
+/* -------------- */
+    pseudo_bit_t	rc[0x00001];           /* RC Transport supported */
+    pseudo_bit_t	uc[0x00001];           /* UC Transport Supported */
+    pseudo_bit_t	ud[0x00001];           /* UD Transport Supported */
+    pseudo_bit_t	src[0x00001];          /* SRC Transport Supported. Hermon New instead of RD. */
+    pseudo_bit_t	rcm[0x00001];          /* Reliable Multicast support. Hermon New instead of IPv6 Transport Supported */
+    pseudo_bit_t	fcoib[0x00001];        /* Hermon New */
+    pseudo_bit_t	srq[0x00001];          /* SRQ is supported
+                                                  */
+    pseudo_bit_t	checksum[0x00001];     /* IP over IB checksum is supported */
+    pseudo_bit_t	pkv[0x00001];          /* PKey Violation Counter Supported */
+    pseudo_bit_t	qkv[0x00001];          /* QKey Violation Coutner Supported */
+    pseudo_bit_t	vmm[0x00001];          /* Hermon New */
+    pseudo_bit_t	fcoe[0x00001];
+    pseudo_bit_t	dpdp[0x00001];	       /* Dual Port Different Protocols */
+    pseudo_bit_t	raw_ethertype[0x00001];
+    pseudo_bit_t	raw_ipv6[0x00001];
+    pseudo_bit_t	blh[0x00001];
+    pseudo_bit_t	mw[0x00001];           /* Memory windows supported */
+    pseudo_bit_t	apm[0x00001];          /* Automatic Path Migration Supported */
+    pseudo_bit_t	atm[0x00001];          /* Atomic operations supported (atomicity is guaranteed between QPs on this HCA) */
+    pseudo_bit_t	rm[0x00001];           /* Raw Multicast Supported */
+    pseudo_bit_t	avp[0x00001];          /* Address Vector Port checking supported */
+    pseudo_bit_t	udm[0x00001];          /* UD Multicast Supported */
+    pseudo_bit_t	reserved28[0x00002];
+    pseudo_bit_t	pg[0x00001];           /* Paging on demand supported */
+    pseudo_bit_t	r[0x00001];            /* Router mode supported */
+    pseudo_bit_t	reserved29[0x00006];
+/* -------------- */
+    pseudo_bit_t	log_pg_sz[0x00008];    /* Minimum system page size supported (log2).
+                                                 For proper operation it must be less than or equal the hosting platform (CPU) minimum page size. */
+    pseudo_bit_t	reserved30[0x00008];
+    pseudo_bit_t	uar_sz[0x00006];       /* UAR Area Size = 1MB * 2^uar_sz */
+    pseudo_bit_t	reserved31[0x00006];
+    pseudo_bit_t	num_rsvd_uars[0x00004];/* The number of UARs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_uars-1
+                                                 Note that UAR number num_reserved_uars is always for the kernel. */
+/* -------------- */
+    pseudo_bit_t	log_max_bf_pages[0x00006];/* Maximum number of BlueFlame pages is 2^log_max_bf_pages */
+    pseudo_bit_t	reserved32[0x00002];
+    pseudo_bit_t	log_max_bf_regs_per_page[0x00006];/* Maximum number of BlueFlame registers per page is 2^log_max_bf_regs_per_page. It may be that only the beginning of a page contains BlueFlame registers. */
+    pseudo_bit_t	reserved33[0x00002];
+    pseudo_bit_t	log_bf_reg_size[0x00005];/* BlueFlame register size in bytes is 2^log_bf_reg_size */
+    pseudo_bit_t	reserved34[0x0000a];
+    pseudo_bit_t	bf[0x00001];           /* If set to "1" then BlueFlame may be used. */
+/* -------------- */
+    pseudo_bit_t	max_desc_sz_sq[0x00010];/* Max descriptor size in bytes for the send queue */
+    pseudo_bit_t	max_sg_sq[0x00008];    /* The maximum S/G list elements in a SQ WQE (max_desc_sz/16 - 3) */
+    pseudo_bit_t	reserved35[0x00008];
+/* -------------- */
+    pseudo_bit_t	max_desc_sz_rq[0x00010];/* Max descriptor size in bytes for the receive queue */
+    pseudo_bit_t	max_sg_rq[0x00008];    /* The maximum S/G list elements in a RQ WQE (max_desc_sz/16 - 3) */
+    pseudo_bit_t	reserved36[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved37[0x00001];
+    pseudo_bit_t	fexch_base_mpt_31_25[0x00007];/* Hermon New. FC mpt base mpt number */
+    pseudo_bit_t	fcp_ud_base_23_8[0x00010];/* Hermon New. FC ud QP  base QPN */
+    pseudo_bit_t	fexch_base_qp_23_16[0x00008];/* Hermon New. FC Exchange QP base QPN */
+/* -------------- */
+    pseudo_bit_t	reserved38[0x00020];
+/* -------------- */
+    pseudo_bit_t	log_max_mcg[0x00008];  /* Log2 of the maximum number of multicast groups */
+    pseudo_bit_t	num_rsvd_mcgs[0x00004];/* The number of MGMs reserved for firmware use in the MGHT.
+                                                 The reserved resources are numbered from 0 to num_reserved_mcgs-1
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	reserved39[0x00004];
+    pseudo_bit_t	log_max_qp_mcg[0x00008];/* Log2 of the maximum number of QPs per multicast group */
+    pseudo_bit_t	reserved40[0x00008];
+/* -------------- */
+    pseudo_bit_t	log_max_srcds[0x00004];/* Log2 of the maximum number of SRC Domains */
+    pseudo_bit_t	reserved41[0x00008];
+    pseudo_bit_t	num_rsvd_scrds[0x00004];/* The number of SRCDs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_rdds-1.
+                                                 If 0 - no resources are reserved. */
+    pseudo_bit_t	log_max_pd[0x00005];   /* Log2 of the maximum number of PDs */
+    pseudo_bit_t	reserved42[0x00007];
+    pseudo_bit_t	num_rsvd_pds[0x00004]; /* The number of PDs reserved for firmware use
+                                                 The reserved resources are numbered from 0 to num_reserved_pds-1
+                                                 If 0 - no resources are reserved. */
+/* -------------- */
+    pseudo_bit_t	reserved43[0x000c0];
+/* -------------- */
+    pseudo_bit_t	qpc_entry_sz[0x00010]; /* QPC Entry Size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+    pseudo_bit_t	rdmardc_entry_sz[0x00010];/* RdmaRdC Entry Size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+/* -------------- */
+    pseudo_bit_t	altc_entry_sz[0x00010];/* Extended QPC entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+    pseudo_bit_t	aux_entry_sz[0x00010]; /* Auxilary context entry size */
+/* -------------- */
+    pseudo_bit_t	cqc_entry_sz[0x00010]; /* CQC entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+    pseudo_bit_t	eqc_entry_sz[0x00010]; /* EQ context entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+/* -------------- */
+    pseudo_bit_t	c_mpt_entry_sz[0x00010];/* cMPT entry size in Bytes for the device.
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+    pseudo_bit_t	srq_entry_sz[0x00010]; /* SRQ context entry size for the device
+                                                 For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+/* -------------- */
+    pseudo_bit_t	d_mpt_entry_sz[0x00010];/* dMPT entry size in Bytes for the device.
+                                                 For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+    pseudo_bit_t	mtt_entry_sz[0x00010]; /* MTT entry size in Bytes for the device.
+                                                 For the InfiniHost-III-EX MT25208 entry size is 8 bytes */
+/* -------------- */
+    pseudo_bit_t	bmme[0x00001];         /* Base Memory Management Extension Support */
+    pseudo_bit_t	win_type[0x00001];     /* Bound Type 2 Memory Window Association mechanism:
+                                                 0 - Type 2A - QP Number Association; or
+                                                 1 - Type 2B - QP Number and PD Association. */
+    pseudo_bit_t	mps[0x00001];          /* Ability of this HCA to support multiple page sizes per Memory Region. */
+    pseudo_bit_t	bl[0x00001];           /* Ability of this HCA to support Block List Physical Buffer Lists. */
+    pseudo_bit_t	zb[0x00001];           /* Zero Based region/windows supported */
+    pseudo_bit_t	lif[0x00001];          /* Ability of this HCA to support Local Invalidate Fencing. */
+    pseudo_bit_t	reserved44[0x0001a];
+/* -------------- */
+    pseudo_bit_t	resd_lkey[0x00020];    /* The value of the reserved Lkey for Base Memory Management Extension */
+/* -------------- */
+    pseudo_bit_t	reserved45[0x00020];
+/* -------------- */
+    pseudo_bit_t	max_icm_size_h[0x00020];/* Bits [63:32] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+    pseudo_bit_t	max_icm_size_l[0x00020];/* Bits [31:0] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+    pseudo_bit_t	reserved46[0x002c0];
+/* -------------- */
+}; 
+
+/* QUERY_ADAPTER Parameters Block    #### michal - gdror fixed */
+
+struct hermonprm_query_adapter_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00018];
+    pseudo_bit_t	intapin[0x00008];      /* Driver should set this field to INTR value in the event queue in order to get Express interrupt messages. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00060];
+/* -------------- */
+    struct hermonprm_vsd_st	vsd;         /* ###michal- this field was replaced by 2 fields : vsd .1664; vsd(continued/psid .128; */
+/* -------------- */
+}; 
+
+/* QUERY_FW Parameters Block      #### michal - doesn't match PRM */
+
+struct hermonprm_query_fw_st {	/* Little Endian */
+    pseudo_bit_t	fw_rev_major[0x00010]; /* Firmware Revision - Major */
+    pseudo_bit_t	fw_pages[0x00010];     /* Amount of physical memory to be allocated for FW usage is in 4KByte pages. */
+/* -------------- */
+    pseudo_bit_t	fw_rev_minor[0x00010]; /* Firmware Revision - Minor */
+    pseudo_bit_t	fw_rev_subminor[0x00010];/* Firmware Sub-minor version (Patch level). */
+/* -------------- */
+    pseudo_bit_t	cmd_interface_rev[0x00010];/* Command Interface Interpreter Revision ID */
+    pseudo_bit_t	reserved0[0x00010];
+/* -------------- */
+    pseudo_bit_t	log_max_outstanding_cmd[0x00008];/* Log2 of the maximum number of commands the HCR can support simultaneously */
+    pseudo_bit_t	reserved1[0x00017];
+    pseudo_bit_t	dt[0x00001];           /* Debug Trace Support
+                                                 0 - Debug trace is not supported 
+                                                 1 - Debug trace is supported */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00001];
+    pseudo_bit_t	ccq[0x00001];          /* CCQ support */
+    pseudo_bit_t	reserved3[0x00006];
+    pseudo_bit_t	fw_seconds[0x00008];   /* FW timestamp - seconds. Dispalyed as Hexadecimal number */
+    pseudo_bit_t	fw_minutes[0x00008];   /* FW timestamp - minutes. Dispalyed as Hexadecimal number */
+    pseudo_bit_t	fw_hour[0x00008];      /* FW timestamp - hour.    Dispalyed as Hexadecimal number */
+/* -------------- */
+    pseudo_bit_t	fw_day[0x00008];       /* FW timestamp - day.     Dispalyed as Hexadecimal number */
+    pseudo_bit_t	fw_month[0x00008];     /* FW timestamp - month.   Dispalyed as Hexadecimal number */
+    pseudo_bit_t	fw_year[0x00010];      /* FW timestamp - year.    Dispalyed as Hexadecimal number (e.g. 0x2005) */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00040];
+/* -------------- */
+    pseudo_bit_t	clr_int_base_offset_h[0x00020];/* Bits [63:32] of the Clear Interrupt registerÂ’s offset from clr_int_bar register in PCIaddress space. Points to a 64-bit register. */
+/* -------------- */
+    pseudo_bit_t	clr_int_base_offset_l[0x00020];/* Bits [31:0] of the Clear Interrupt registerÂ’s offset from clr_int_bar register in PCIaddress space. Points to a 64-bit register. */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x0001e];
+    pseudo_bit_t	clr_int_bar[0x00002];  /* PCI base address register (BAR) where clr_int register is located.
+                                                 00 - BAR 0-1
+                                                 01 - BAR 2-3
+                                                 10 - BAR 4-5
+                                                 11 - Reserved
+                                                 The PCI BARs of ConnectX are 64 bit BARs.
+                                                 In ConnectX, clr_int register is located on BAR 0-1. */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00020];
+/* -------------- */
+    pseudo_bit_t	error_buf_offset_h[0x00020];/* Read Only buffer for catastrophic error reports (bits [63:32] of offset from error_buf_bar register in PCI address space.) */
+/* -------------- */
+    pseudo_bit_t	error_buf_offset_l[0x00020];/* Read Only buffer for catastrophic error reports (bits [31:0]  of offset from error_buf_bar register in PCI address space.) */
+/* -------------- */
+    pseudo_bit_t	error_buf_size[0x00020];/* Size in words */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x0001e];
+    pseudo_bit_t	error_buf_bar[0x00002];/* PCI base address register (BAR) where error_buf register is located.
+                                                 00 - BAR 0-1
+                                                 01 - BAR 2-3
+                                                 10 - BAR 4-5
+                                                 11 - Reserved
+                                                 The PCI BARs of ConnectX are 64 bit BARs.
+                                                 In ConnectX, error_buf register is located on BAR 0-1. */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00600];
+/* -------------- */
+}; 
+
+/* Memory Access Parameters for UD Address Vector Table */
+
+struct hermonprm_udavtable_memory_parameters_st {	/* Little Endian */
+    pseudo_bit_t	l_key[0x00020];        /* L_Key used to access TPT */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* PD used by TPT for matching against PD of region entry being accessed. */
+    pseudo_bit_t	reserved0[0x00005];
+    pseudo_bit_t	xlation_en[0x00001];   /* When cleared, address is physical address and no translation will be done. When set, address is virtual. */
+    pseudo_bit_t	reserved1[0x00002];
+/* -------------- */
+}; 
+
+/* INIT_HCA & QUERY_HCA Parameters Block ####michal-doesn't match PRM (see differs below) new size in bytes:0x300 */
+
+struct hermonprm_init_hca_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00018];
+    pseudo_bit_t	version[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00010];
+    pseudo_bit_t	hca_core_clock[0x00010];/* Internal Clock freq in MHz */
+/* -------------- */
+    pseudo_bit_t	router_qp[0x00018];    /* QP number for router mode (8 LSBits should be 0). Low order 8 bits are taken from the TClass field of the incoming packet.
+                                                 Valid only if RE bit is set */
+    pseudo_bit_t	reserved3[0x00005];
+    pseudo_bit_t	ipr2[0x00001];         /* Hermon New. IP router on port 2 */
+    pseudo_bit_t	ipr1[0x00001];         /* Hermon New. IP router on port 1 */
+    pseudo_bit_t	ibr[0x00001];          /* InfiniBand Router Mode */
+/* -------------- */
+    pseudo_bit_t	udp[0x00001];          /* UD Port Check Enable
+                                                 0 - Port field in Address Vector is ignored
+                                                 1 - HCA will check the port field in AV entry (fetched for UD descriptor) against the Port of the UD QP executing the descriptor. */
+    pseudo_bit_t	he[0x00001];           /* Host Endianess - Used for Atomic Operations
+                                                 0 - Host is Little Endian
+                                                 1 - Host is Big endian
+                                                  */
+    pseudo_bit_t	reserved4[0x00001];
+    pseudo_bit_t	ce[0x00001];           /* Checksum Enabled - when Set IPoverIB checksum generation & checking is enabled */
+    pseudo_bit_t	reserved5[0x0001c];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00040];
+/* -------------- */
+    struct hermonprm_qpcbaseaddr_st	qpc_eec_cqc_eqc_rdb_parameters;/* ## michal - this field has chenged to - "qpc_cqc_eqc_parameters" - gdror, this is ok for now */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x00100];
+/* -------------- */
+    struct hermonprm_multicastparam_st	multicast_parameters;/* ##michal- this field has chenged to - "IBUD/IPv6_multicast_parameters" - gdror - this is OK for now */
+/* -------------- */
+    pseudo_bit_t	reserved8[0x00080];
+/* -------------- */
+    struct hermonprm_tptparams_st	tpt_parameters;
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00080];
+/* -------------- */
+    struct hermonprm_uar_params_st	uar_parameters;/* UAR Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00600];
+/* -------------- */
+}; 
+
+/* Event Queue Context Table Entry     #### michal - gdror fixed */
+
+struct hermonprm_eqc_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	st[0x00004];           /* Event delivery state machine
+                                                 0x9 - Armed
+                                                 0xA - Fired
+                                                 0xB - Always_Armed (auto-rearm)
+                                                 other - reserved */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	oi[0x00001];           /* Oerrun ignore.
+                                                 If set, HW will not check EQ full condition when writing new EQEs. */
+    pseudo_bit_t	ec[0x00001];           /* is set, all EQEs are written (coalesced) to first EQ entry */
+    pseudo_bit_t	reserved2[0x00009];
+    pseudo_bit_t	status[0x00004];       /* EQ status:
+                                                 0000 - OK
+                                                 1010 - EQ write failure
+                                                 Valid for the QUERY_EQ and HW2SW_EQ commands only */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00005];
+    pseudo_bit_t	page_offset[0x00007];  /* offset bits[11:5] of first EQE in the EQ relative to the first page in memory region mapping this EQ */
+    pseudo_bit_t	reserved5[0x00014];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00018];
+    pseudo_bit_t	log_eq_size[0x00005];  /* Log (base 2) of the EQ size (in entries).  Maximum EQ size is 2^22 EQEs (max log_eq_size is 22) */
+    pseudo_bit_t	reserved7[0x00003];
+/* -------------- */
+    pseudo_bit_t	eq_max_count[0x00010]; /* Event Generation Moderation counter */
+    pseudo_bit_t	eq_period[0x00010];    /* Event Generation moderation timed, microseconds */
+/* -------------- */
+    pseudo_bit_t	intr[0x0000a];         /* MSI-X table entry index to be used to signal interrupts on this EQ.  Reserved if MSI-X are not enabled in the PCI configuration header. */
+    pseudo_bit_t	reserved8[0x00016];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00008];/* MTT Base Address [39:32] relative to INIT_HCA.mtt_base_addr */
+    pseudo_bit_t	reserved9[0x00010];
+    pseudo_bit_t	log2_page_size[0x00006];/* Log (base 2) of MTT page size in units of 4KByte */
+    pseudo_bit_t	reserved10[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00003];
+    pseudo_bit_t	mtt_base_addr_l[0x0001d];/* MTT Base Address [31:3] relative to INIT_HCA.mtt_base_addr */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x00040];
+/* -------------- */
+    pseudo_bit_t	consumer_counter[0x00018];/* Consumer counter. The counter is incremented for each EQE polled from the EQ. 
+                                                  Must be 0x0 in EQ initialization. 
+                                                  Maintained by HW (valid for the QUERY_EQ command only). */
+    pseudo_bit_t	reserved13[0x00008];
+/* -------------- */
+    pseudo_bit_t	producer_counter[0x00018];/* Producer Coutner. The counter is incremented for each EQE that is written by the HW to the EQ. 
+                                                  EQ overrun is reported if Producer_counter + 1 equals to Consumer_counter and a EQE needs to be added.
+                                                  Maintained by HW (valid for the QUERY_EQ command only) */
+    pseudo_bit_t	reserved14[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00080];
+/* -------------- */
+}; 
+
+/* Memory Translation Table (MTT) Entry     #### michal - match to PRM */
+
+struct hermonprm_mtt_st {	/* Little Endian */
+    pseudo_bit_t	ptag_h[0x00020];       /* High-order bits of physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+    pseudo_bit_t	p[0x00001];            /* Present bit. If set, page entry is valid. If cleared, access to this page will generate non-present page access fault. */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	ptag_l[0x0001d];       /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+}; 
+
+/* Memory Protection Table (MPT) Entry   ### doesn't match PRM (new fields were added). new size in bytes : 0x54 */
+
+struct hermonprm_mpt_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	r_w[0x00001];          /* Defines whether this entry is Region (1) or Window (0) */
+    pseudo_bit_t	pa[0x00001];           /* Physical address. If set, no virtual-to-physical address translation is performed for this region */
+    pseudo_bit_t	lr[0x00001];           /* If set - local read access is enabled. Must be set for all MPT Entries. */
+    pseudo_bit_t	lw[0x00001];           /* If set - local write access is enabled */
+    pseudo_bit_t	rr[0x00001];           /* If set - remote read access is enabled. */
+    pseudo_bit_t	rw[0x00001];           /* If set - remote write access is enabled */
+    pseudo_bit_t	atomic[0x00001];       /* If set - remote Atomic access is allowed. */
+    pseudo_bit_t	eb[0x00001];           /* If set - bind is enabled. Valid only for regions. */
+    pseudo_bit_t	atc_req[0x00001];      /* If set, second hop of address translation (PA to MA) to be performed in the device prior to issuing the uplink request. */
+    pseudo_bit_t	atc_xlated[0x00001];   /* If set, uplink cycle to be issues with “ATC_translated” indicator to force bypass of the chipset IOMMU. */
+    pseudo_bit_t	reserved1[0x00001];
+    pseudo_bit_t	no_snoop[0x00001];     /* If set, issue PCIe cycle with ûno Snoopÿ attribute - cycle not to be snooped in CPU caches */
+    pseudo_bit_t	reserved2[0x00008];
+    pseudo_bit_t	status[0x00004];       /* 0xF - Not Valid 0x3 - Free. else - HW ownership.Unbound Type1 windows are denoted by reg_wnd_len=0. Unbound Type II windows are denoted by Status = Free. */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00007];
+    pseudo_bit_t	bqp[0x00001];          /* 0 - not bound to qp (type 1 window, MR)1 - bound to qp (type 2 window) */
+    pseudo_bit_t	qpn[0x00018];          /* QP number this MW is attached to. Valid for type2 memory windows and on QUERY_MPT only */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* The memory Key. The field holds the mem_key field in the following semantics: {key[7:0],key[31:8]}. */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* Protection Domain. If VMM support is enabled PD[17:23] specify Guest VM Identifier */
+    pseudo_bit_t	en_rinv[0x00001];      /* Enable remote invalidation */
+    pseudo_bit_t	ei[0x00001];           /* Enable Invalidation - When set, Local/Remote invalidation can be executed on this window/region. Must be set for type2 windows and non-shared physical memory regions. Must be clear for regions that are used to access Work Queues, Completion Queues and Event Queues */
+    pseudo_bit_t	nce[0x00001];          /* Data can be cached in Network Cache (see ûNetwork Cacheÿ on page 81) */
+    pseudo_bit_t	fre[0x00001];          /* When set, Fast Registration Operations can be executed on this region */
+    pseudo_bit_t	rae[0x00001];          /* When set, remote access can be enabled on this region. Used when executing Fast Registration Work Request to validate that remote access rights can be granted to this MPT. If the bit is cleared, Fast Registration Work Request requesting remote access rights will fail */
+    pseudo_bit_t	w_dif[0x00001];        /* Wire space contains dif */
+    pseudo_bit_t	m_dif[0x00001];        /* Memory space contains dif */
+    pseudo_bit_t	reserved4[0x00001];
+/* -------------- */
+    pseudo_bit_t	start_addr_h[0x00020]; /* Start Address - Virtual Address where this region/window starts */
+/* -------------- */
+    pseudo_bit_t	start_addr_l[0x00020]; /* Start Address - Virtual Address where this region/window starts */
+/* -------------- */
+    pseudo_bit_t	len_h[0x00020];        /* Region/Window Length */
+/* -------------- */
+    pseudo_bit_t	len_l[0x00020];        /* Region/Window Length */
+/* -------------- */
+    pseudo_bit_t	lkey[0x00020];         /* Must be 0 for SW2HW_MPT. On QUERY_MPT and HW2SW_MPT commands for Memory Window it reflects the LKey of the Region that the Window is bound to.The field holds the lkey field in the following semantics: {key[7:0],key[31:8]}. */
+/* -------------- */
+    pseudo_bit_t	win_cnt[0x00018];      /* Number of windows bound to this region. Valid for regions only.The field is valid only for the QUERY_MPT and HW2SW_MPT commands. */
+    pseudo_bit_t	reserved5[0x00008];
+/* -------------- */
+    pseudo_bit_t	mtt_rep[0x00004];      /* Log (base 2) of the number of time an MTT is replicated.E.g. for 64KB virtual blocks from 512B blocks, a replication factor of 2^7 is needed (MTT_REPLICATION_FACTOR=7).Up to 1MB of replicated block works */
+    pseudo_bit_t	reserved6[0x00011];
+    pseudo_bit_t	block_mode[0x00001];   /* If set, the page size is not power of two, and entity_size is in bytes. */
+    pseudo_bit_t	len64[0x00001];        /* Region/Window Length[64]. This bit added to enable registering 2^64 bytes per region */
+    pseudo_bit_t	fbo_en[0x00001];       /* If set, mtt_fbo field is valid, otherwise it is calculated from least significant bytes of the address. Must be set when mtt_rep is used or MPT is block-mode region */
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	mtt_adr_h[0x00008];    /* Offset to MTT list for this region. Must be aligned on 8 bytes. */
+    pseudo_bit_t	reserved8[0x00018];
+/* -------------- */
+    pseudo_bit_t	mtt_adr_l[0x00020];    /* Offset to MTT list for this region. Must be aligned on 8 bytes.###michal-relpaced with: RESERVED .3;mtt_adr_l .29; gdror - this is OK to leave it this way. */
+/* -------------- */
+    pseudo_bit_t	mtt_size[0x00020];     /* Number of MTT entries allocated for this MR.When Fast Registration Operations cannot be executed on this region (FRE bit is zero) this field is reserved.When Fast Registration Operation is enabled (FRE bit is set) this field indicates the number of MTTs allocated for this MR. If mtt_sz value cannot be zero. */
+/* -------------- */
+    pseudo_bit_t	entity_size[0x00015];  /* Page/block size. If MPT maps pages, the page size is 2entiry_size. If MPT maps blocks, the entity_size field specifies block size in bytes. The minimum amount of memory that can be mapped with single MTT is 512 bytes. */
+    pseudo_bit_t	reserved9[0x0000b];
+/* -------------- */
+    pseudo_bit_t	mtt_fbo[0x00015];      /* First byte offset in the zero-based region - the first byte within the first block/page start address refers to. When mtt_rep is being used, fbo points within the replicated block (i.e. block-size x 2^mtt_rep) */
+    pseudo_bit_t	reserved10[0x0000b];
+/* -------------- */
+}; 
+
+/* Completion Queue Context Table Entry	#### michal - match PRM */
+
+struct hermonprm_completion_queue_context_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	st[0x00004];           /* Event delivery state machine
+                                                 0x0 - reserved
+                                                 0x9 - ARMED (Request for Notification)
+                                                 0x6 - ARMED SOLICITED (Request Solicited Notification)
+                                                 0xA - FIRED
+                                                 other - reserved
+                                                 
+                                                 Must be 0x0 in CQ initialization.
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only. */
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	oi[0x00001];           /* When set, overrun ignore is enabled.
+                                                 When set, Updates of CQ consumer counter (poll for completion) or Request completion notifications (Arm CQ) doorbells should not be rang on that CQ. */
+    pseudo_bit_t	cc[0x00001];           /* is set, all CQEs are written (coalesced) to first CQ entry */
+    pseudo_bit_t	reserved2[0x00009];
+    pseudo_bit_t	status[0x00004];       /* CQ status
+                                                 0000 - OK
+                                                 1001 - CQ overflow
+                                                 1010 - CQ write failure
+                                                 Valid for the QUERY_CQ and HW2SW_CQ commands only */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00005];
+    pseudo_bit_t	page_offset[0x00007];  /* offset of first CQE in the CQ relative to the first page in memory region mapping this CQ */
+    pseudo_bit_t	reserved5[0x00014];
+/* -------------- */
+    pseudo_bit_t	usr_page[0x00018];     /* UAR page this CQ can be accessed through (ringinig CQ doorbells) */
+    pseudo_bit_t	log_cq_size[0x00005];  /* Log (base 2) of the CQ size (in entries).
+                                                 Maximum CQ size is 2^17 CQEs (max log_cq_size is 17) */
+    pseudo_bit_t	reserved6[0x00003];
+/* -------------- */
+    pseudo_bit_t	cq_max_count[0x00010]; /* Event Generation Moderation counter */
+    pseudo_bit_t	cq_period[0x00010];    /* Event Generation moderation timed, microseconds */
+/* -------------- */
+    pseudo_bit_t	c_eqn[0x00009];        /* Event Queue this CQ reports completion events to.
+                                                 Valid values are 0 to 63
+                                                 If configured to value other than 0-63, completion events will not be reported on the CQ. */
+    pseudo_bit_t	reserved7[0x00017];
+/* -------------- */
+    pseudo_bit_t	mtt_base_addr_h[0x00008];/* MTT Base Address [39:32] in ICM relative to INIT_HCA.mtt_base_addr */
+    pseudo_bit_t	reserved8[0x00010];
+    pseudo_bit_t	log2_page_size[0x00006];
+    pseudo_bit_t	reserved9[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00003];
+    pseudo_bit_t	mtt_base_addr_l[0x0001d];/* MTT Base Address [31:3] in ICM relative to INIT_HCA.mtt_base_addr */
+/* -------------- */
+    pseudo_bit_t	last_notified_indx[0x00018];/* Maintained by HW.
+                                                 Valid for QUERY_CQ and HW2SW_CQ commands only. */
+    pseudo_bit_t	reserved11[0x00008];
+/* -------------- */
+    pseudo_bit_t	solicit_producer_indx[0x00018];/* Maintained by HW.
+                                                 Valid for QUERY_CQ and HW2SW_CQ commands only. 
+                                                  */
+    pseudo_bit_t	reserved12[0x00008];
+/* -------------- */
+    pseudo_bit_t	consumer_counter[0x00018];/* Consumer counter is a 32bits counter that is incremented for each CQE pooled from the CQ.
+                                                  */
+    pseudo_bit_t	reserved13[0x00008];
+/* -------------- */
+    pseudo_bit_t	producer_counter[0x00018];/* Producer counter is a 32bits counter that is incremented for each CQE that is written by the HW to the CQ.
+                                                 CQ overrun is reported if Producer_counter + 1 equals to Consumer_counter and a CQE needs to be added..
+                                                 Maintained by HW (valid for the QUERY_CQ and HW2SW_CQ commands only) */
+    pseudo_bit_t	reserved14[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved15[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved16[0x00020];
+/* -------------- */
+    pseudo_bit_t	db_record_addr_h[0x00020];/* CQ DB Record physical address [63:32] */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x00003];
+    pseudo_bit_t	db_record_addr_l[0x0001d];/* CQ DB Record physical address [31:3] */
+/* -------------- */
+}; 
+
+/* GPIO_event_data   #### michal - gdror fixed */
+
+struct hermonprm_gpio_event_data_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00060];
+/* -------------- */
+    pseudo_bit_t	gpio_event_hi[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+    pseudo_bit_t	gpio_event_lo[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+}; 
+
+/* Event_data Field - QP/EE Events     #### michal - doesn't match PRM */
+
+struct hermonprm_qp_ee_event_st {	/* Little Endian */
+    pseudo_bit_t	qpn_een[0x00018];      /* QP/EE/SRQ number event is reported for  ###michal - field changed to QP number */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x0001c];
+    pseudo_bit_t	e_q[0x00001];          /* If set - EEN if cleared - QP in the QPN/EEN field
+                                                 Not valid on SRQ events  ###michal - field replaced with RESERVED */
+    pseudo_bit_t	reserved3[0x00003];
+/* -------------- */
+    pseudo_bit_t	reserved4[0x00060];
+/* -------------- */
+}; 
+
+/* InfiniHost-III-EX Type0 Configuration Header   ####michal - doesn't match PRM (new fields added, see below) */
+
+struct hermonprm_mt25208_type0_st {	/* Little Endian */
+    pseudo_bit_t	vendor_id[0x00010];    /* Hardwired to 0x15B3 */
+    pseudo_bit_t	device_id[0x00010];    /* 25208 (decimal) - InfiniHost-III compatible mode
+                                                 25408 (decimal) - InfiniHost-III EX mode (the mode described in this manual)
+                                                 25209 (decimal) - Flash burner mode - see Flash burning application note for further details on this mode
+                                                  */
+/* -------------- */
+    pseudo_bit_t	command[0x00010];      /* PCI Command Register */
+    pseudo_bit_t	status[0x00010];       /* PCI Status Register */
+/* -------------- */
+    pseudo_bit_t	revision_id[0x00008];
+    pseudo_bit_t	class_code_hca_class_code[0x00018];
+/* -------------- */
+    pseudo_bit_t	cache_line_size[0x00008];/* Cache Line Size */
+    pseudo_bit_t	latency_timer[0x00008];
+    pseudo_bit_t	header_type[0x00008];  /* hardwired to zero */
+    pseudo_bit_t	bist[0x00008];
+/* -------------- */
+    pseudo_bit_t	bar0_ctrl[0x00004];    /* hard-wired to 0100 */
+    pseudo_bit_t	reserved0[0x00010];
+    pseudo_bit_t	bar0_l[0x0000c];       /* Lower bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+    pseudo_bit_t	bar0_h[0x00020];       /* Upper 32 bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+    pseudo_bit_t	bar1_ctrl[0x00004];    /* Hardwired to 1100 */
+    pseudo_bit_t	reserved1[0x00010];
+    pseudo_bit_t	bar1_l[0x0000c];       /* Lower bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+    pseudo_bit_t	bar1_h[0x00020];       /* upper 32 bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+    pseudo_bit_t	bar2_ctrl[0x00004];    /* Hardwired to 1100 */
+    pseudo_bit_t	reserved2[0x00010];
+    pseudo_bit_t	bar2_l[0x0000c];       /* Lower bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+    pseudo_bit_t	bar2_h[0x00020];       /* Upper 32 bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+    pseudo_bit_t	cardbus_cis_pointer[0x00020];
+/* -------------- */
+    pseudo_bit_t	subsystem_vendor_id[0x00010];/* Specified by the device NVMEM configuration */
+    pseudo_bit_t	subsystem_id[0x00010]; /* Specified by the device NVMEM configuration */
+/* -------------- */
+    pseudo_bit_t	expansion_rom_enable[0x00001];/* Expansion ROM Enable. Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+    pseudo_bit_t	reserved3[0x0000a];
+    pseudo_bit_t	expansion_rom_base_address[0x00015];/* Expansion ROM Base Address (upper 21 bit). Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+/* -------------- */
+    pseudo_bit_t	capabilities_pointer[0x00008];/* Specified by the device NVMEM configuration */
+    pseudo_bit_t	reserved4[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved5[0x00020];
+/* -------------- */
+    pseudo_bit_t	interrupt_line[0x00008];
+    pseudo_bit_t	interrupt_pin[0x00008];
+    pseudo_bit_t	min_gnt[0x00008];
+    pseudo_bit_t	max_latency[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved6[0x00100];
+/* -------------- */
+    pseudo_bit_t	msi_cap_id[0x00008];
+    pseudo_bit_t	msi_next_cap_ptr[0x00008];
+    pseudo_bit_t	msi_en[0x00001];
+    pseudo_bit_t	multiple_msg_cap[0x00003];
+    pseudo_bit_t	multiple_msg_en[0x00003];
+    pseudo_bit_t	cap_64_bit_addr[0x00001];
+    pseudo_bit_t	reserved7[0x00008];
+/* -------------- */
+    pseudo_bit_t	msg_addr_l[0x00020];
+/* -------------- */
+    pseudo_bit_t	msg_addr_h[0x00020];
+/* -------------- */
+    pseudo_bit_t	msg_data[0x00010];
+    pseudo_bit_t	reserved8[0x00010];
+/* -------------- */
+    pseudo_bit_t	reserved9[0x00080];
+/* -------------- */
+    pseudo_bit_t	pm_cap_id[0x00008];    /* Power management capability ID - 01h */
+    pseudo_bit_t	pm_next_cap_ptr[0x00008];
+    pseudo_bit_t	pm_cap[0x00010];       /* [2:0] Version - 02h
+                                                 [3] PME clock - 0h
+                                                 [4] RsvP
+                                                 [5] Device specific initialization - 0h
+                                                 [8:6] AUX current - 0h
+                                                 [9] D1 support - 0h
+                                                 [10] D2 support - 0h
+                                                 [15:11] PME support - 0h */
+/* -------------- */
+    pseudo_bit_t	pm_status_control[0x00010];/* [14:13] - Data scale - 0h */
+    pseudo_bit_t	pm_control_status_brdg_ext[0x00008];
+    pseudo_bit_t	data[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00040];
+/* -------------- */
+    pseudo_bit_t	vpd_cap_id[0x00008];   /* 03h */
+    pseudo_bit_t	vpd_next_cap_id[0x00008];
+    pseudo_bit_t	vpd_address[0x0000f];
+    pseudo_bit_t	f[0x00001];
+/* -------------- */
+    pseudo_bit_t	vpd_data[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved11[0x00040];
+/* -------------- */
+    pseudo_bit_t	pciex_cap_id[0x00008]; /* PCI-Express capability ID - 10h */
+    pseudo_bit_t	pciex_next_cap_ptr[0x00008];
+    pseudo_bit_t	pciex_cap[0x00010];    /* [3:0] Capability version - 1h
+                                                 [7:4] Device/Port Type - 0h
+                                                 [8] Slot implemented - 0h
+                                                 [13:9] Interrupt message number
+                                                  */
+/* -------------- */
+    pseudo_bit_t	device_cap[0x00020];   /* [2:0] Max_Payload_Size supported - 2h
+                                                 [4:3] Phantom Function supported - 0h
+                                                 [5] Extended Tag Filed supported - 0h
+                                                 [8:6] Endpoint L0s Acceptable Latency - TBD
+                                                 [11:9] Endpoint L1 Acceptable Latency - TBD
+                                                 [12] Attention Button Present - configured through InfiniBurn
+                                                 [13] Attention Indicator Present - configured through InfiniBurn
+                                                 [14] Power Indicator Present - configured through InfiniBurn
+                                                 [25:18] Captured Slot Power Limit Value
+                                                 [27:26] Captured Slot Power Limit Scale */
+/* -------------- */
+    pseudo_bit_t	device_control[0x00010];
+    pseudo_bit_t	device_status[0x00010];
+/* -------------- */
+    pseudo_bit_t	link_cap[0x00020];     /* [3:0] Maximum Link Speed - 1h
+                                                 [9:4] Maximum Link Width - 8h
+                                                 [11:10] Active State Power Management Support - 3h
+                                                 [14:12] L0s Exit Latency - TBD
+                                                 [17:15] L1 Exit Latency - TBD
+                                                 [31:24] Port Number - 0h */
+/* -------------- */
+    pseudo_bit_t	link_control[0x00010];
+    pseudo_bit_t	link_status[0x00010];  /* [3:0] Link Speed - 1h
+                                                 [9:4] Negotiated Link Width
+                                                 [12] Slot clock configuration - 1h */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x00260];
+/* -------------- */
+    pseudo_bit_t	advanced_error_reporting_cap_id[0x00010];/* 0001h. */
+    pseudo_bit_t	capability_version[0x00004];/* 1h */
+    pseudo_bit_t	next_capability_offset[0x0000c];/* 0h */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_error_status_register[0x00020];/* 0 Training Error Status
+                                                 4 Data Link Protocol Error Status
+                                                 12 Poisoned TLP Status 
+                                                 13 Flow Control Protocol Error Status 
+                                                 14 Completion Timeout Status 
+                                                 15 Completer Abort Status 
+                                                 16 Unexpected Completion Status 
+                                                 17 Receiver Overflow Status 
+                                                 18 Malformed TLP Status 
+                                                 19 ECRC Error Status 
+                                                 20 Unsupported Request Error Status */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_error_mask_register[0x00020];/* 0 Training Error Mask
+                                                 4 Data Link Protocol Error Mask
+                                                 12 Poisoned TLP Mask 
+                                                 13 Flow Control Protocol Error Mask
+                                                 14 Completion Timeout Mask
+                                                 15 Completer Abort Mask
+                                                 16 Unexpected Completion Mask
+                                                 17 Receiver Overflow Mask
+                                                 18 Malformed TLP Mask
+                                                 19 ECRC Error Mask
+                                                 20 Unsupported Request Error Mask */
+/* -------------- */
+    pseudo_bit_t	uncorrectable_severity_mask_register[0x00020];/* 0 Training Error Severity
+                                                 4 Data Link Protocol Error Severity
+                                                 12 Poisoned TLP Severity
+                                                 13 Flow Control Protocol Error Severity
+                                                 14 Completion Timeout Severity
+                                                 15 Completer Abort Severity
+                                                 16 Unexpected Completion Severity
+                                                 17 Receiver Overflow Severity
+                                                 18 Malformed TLP Severity
+                                                 19 ECRC Error Severity
+                                                 20 Unsupported Request Error Severity */
+/* -------------- */
+    pseudo_bit_t	correctable_error_status_register[0x00020];/* 0 Receiver Error Status
+                                                 6 Bad TLP Status
+                                                 7 Bad DLLP Status
+                                                 8 REPLAY_NUM Rollover Status
+                                                 12 Replay Timer Timeout Status */
+/* -------------- */
+    pseudo_bit_t	correctable_error_mask_register[0x00020];/* 0 Receiver Error Mask
+                                                 6 Bad TLP Mask
+                                                 7 Bad DLLP Mask
+                                                 8 REPLAY_NUM Rollover Mask
+                                                 12 Replay Timer Timeout Mask */
+/* -------------- */
+    pseudo_bit_t	advance_error_capabilities_and_control_register[0x00020];
+/* -------------- */
+    struct hermonprm_header_log_register_st	header_log_register;
+/* -------------- */
+    pseudo_bit_t	reserved13[0x006a0];
+/* -------------- */
+}; 
+
+/* Event Data Field - Performance Monitor */
+
+struct hermonprm_performance_monitor_event_st {	/* Little Endian */
+    struct hermonprm_performance_monitors_st	performance_monitor_snapshot;/* Performance monitor snapshot */
+/* -------------- */
+    pseudo_bit_t	monitor_number[0x00008];/* 0x01 - SQPC
+                                                 0x02 - RQPC
+                                                 0x03 - CQC
+                                                 0x04 - Rkey
+                                                 0x05 - TLB
+                                                 0x06 - port0
+                                                 0x07 - port1 */
+    pseudo_bit_t	reserved0[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00040];
+/* -------------- */
+}; 
+
+/* Event_data Field - Page Faults */
+
+struct hermonprm_page_fault_event_data_st {	/* Little Endian */
+    pseudo_bit_t	va_h[0x00020];         /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	va_l[0x00020];         /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	mem_key[0x00020];      /* Memory Key this page fault is reported on */
+/* -------------- */
+    pseudo_bit_t	qp[0x00018];           /* QP this page fault is reported on */
+    pseudo_bit_t	reserved0[0x00003];
+    pseudo_bit_t	a[0x00001];            /* If set the memory access that caused the page fault was atomic */
+    pseudo_bit_t	lw[0x00001];           /* If set the memory access that caused the page fault was local write */
+    pseudo_bit_t	lr[0x00001];           /* If set the memory access that caused the page fault was local read */
+    pseudo_bit_t	rw[0x00001];           /* If set the memory access that caused the page fault was remote write */
+    pseudo_bit_t	rr[0x00001];           /* If set the memory access that caused the page fault was remote read */
+/* -------------- */
+    pseudo_bit_t	pd[0x00018];           /* PD this page fault is reported on */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	prefetch_len[0x00020]; /* Indicates how many subsequent pages in the same memory region/window will be accessed by the following transaction after this page fault is resolved. measured in bytes. SW can use this information in order to page-in the subsequent pages if they are not present. */
+/* -------------- */
+}; 
+
+/* WQE segments format */
+
+struct hermonprm_wqe_segment_st {	/* Little Endian */
+    struct hermonprm_send_wqe_segment_st	send_wqe_segment;/* Send WQE segment format */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00280];
+/* -------------- */
+    struct hermonprm_wqe_segment_ctrl_mlx_st	mlx_wqe_segment_ctrl;/* MLX WQE segment format */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00100];
+/* -------------- */
+    pseudo_bit_t	recv_wqe_segment_ctrl[4][0x00020];/* Receive segment format */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00080];
+/* -------------- */
+}; 
+
+/* Event_data Field - Port State Change   #### michal - match PRM */
+
+struct hermonprm_port_state_change_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x0001c];
+    pseudo_bit_t	p[0x00002];            /* Port number (1 or 2) */
+    pseudo_bit_t	reserved2[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+}; 
+
+/* Event_data Field - Completion Queue Error     #### michal - match PRM */
+
+struct hermonprm_completion_queue_error_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number event is reported for */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00020];
+/* -------------- */
+    pseudo_bit_t	syndrome[0x00008];     /* Error syndrome
+                                                 0x01 - CQ overrun
+                                                 0x02 - CQ access violation error */
+    pseudo_bit_t	reserved2[0x00018];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00060];
+/* -------------- */
+}; 
+
+/* Event_data Field - Completion Event	#### michal - match PRM */
+
+struct hermonprm_completion_event_st {	/* Little Endian */
+    pseudo_bit_t	cqn[0x00018];          /* CQ number event is reported for */
+    pseudo_bit_t	reserved0[0x00008];
+/* -------------- */
+    pseudo_bit_t	reserved1[0x000a0];
+/* -------------- */
+}; 
+
+/* Event Queue Entry         #### michal - match to PRM */
+
+struct hermonprm_event_queue_entry_st {	/* Little Endian */
+    pseudo_bit_t	event_sub_type[0x00008];/* Event Sub Type. 
+                                                 Defined for events which have sub types, zero elsewhere. */
+    pseudo_bit_t	reserved0[0x00008];
+    pseudo_bit_t	event_type[0x00008];   /* Event Type */
+    pseudo_bit_t	reserved1[0x00008];
+/* -------------- */
+    pseudo_bit_t	event_data[6][0x00020];/* Delivers auxilary data to handle event. */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00007];
+    pseudo_bit_t	owner[0x00001];        /* Owner of the entry 
+                                                 0 SW 
+                                                 1 HW */
+    pseudo_bit_t	reserved3[0x00018];
+/* -------------- */
+}; 
+
+/* QP/EE State Transitions Command Parameters  ###michal - doesn't match PRM (field name changed) */
+
+struct hermonprm_qp_ee_state_transitions_st {	/* Little Endian */
+    pseudo_bit_t	opt_param_mask[0x00020];/* This field defines which optional parameters are passed. Each bit specifies whether optional parameter is passed (set) or not (cleared). The optparammask is defined for each QP/EE command. */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+    struct hermonprm_queue_pair_ee_context_entry_st	qpc_eec_data;/* QPC/EEC data  ###michal - field has replaced with "qpc_data" (size .1948) */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x00800];
+/* -------------- */
+}; 
+
+/* Completion Queue Entry Format        #### michal - fixed by gdror */
+
+struct hermonprm_completion_queue_entry_st {	/* Little Endian */
+    pseudo_bit_t	qpn[0x00018];          /* Indicates the QP for which completion is being reported */
+    pseudo_bit_t	reserved0[0x00002];
+    pseudo_bit_t	d2s[0x00001];          /* Duplicate to Sniffer. This bit is set if both Send and Receive queues are subject for sniffer queue. The HW delivers
+                                                 packet only to send-associated sniffer receive queue. */
+    pseudo_bit_t	fcrc_sd[0x00001];      /* FCRC: If set, FC CRC is correct in FC frame encapsulated in payload. Valid for Raw Frame FC receive queue only.
+                                                 SD: CQ associated with Sniffer receive queue. If set, packets were skipped due to lack of receive buffers on the Sniffer receive queue */
+    pseudo_bit_t	fl[0x00001];           /* Force Loopback Valid for responder RawEth and UD only. */
+    pseudo_bit_t	vlan[0x00002];         /* Valid for RawEth and UD over Ethernet only. Applicable for RawEth and UD over Ethernet Receive queue
+                                                  00 - No VLAN header was present in the packet
+                                                 01 - C-VLAN (802.1q) Header was present in the frame.
+                                                 10 - S-VLAN (802.1ad) Header was present in the frame. */
+    pseudo_bit_t	dife[0x00001];         /* DIF Error */
+/* -------------- */
+    pseudo_bit_t	immediate_rssvalue_invalidatekey[0x00020];/* For a responder CQE, if completed WQE Opcode is Send With Immediate or Write With Immediate, this field contains immediate field of the received message.
+                                                 For a responder CQE, if completed WQE Opcode is Send With Invalidate, this field contains the R_key that was invalidated.
+                                                 For a responder CQE of a GSI packet this filed contains the Pkey Index of the packet.
+                                                 For IPoIB (UD) and RawEth CQEs this field contains the RSS hash function value.
+                                                 Otherwise, this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	srq_rqpn[0x00018];     /* For Responder UD QPs, Remote (source) QP number. 
+                                                 For Responder SRC QPs, SRQ number.
+                                                 Otherwise, this field is reserved. */
+    pseudo_bit_t	ml_path_mac_index[0x00007];/* For responder UD over IB CQE: These are the lower LMC bits of the DLID in an incoming UD packet, higher bits of this field, that are not part of the LMC bits are zeroed by HW. Invalid if incoming message DLID is the permissive LID or incoming message is multicast.
+                                                  For responder UD over Ethernet and RawEth CQEs: Index of the MAC Table entry that the packet DMAC was matched against.
+                                                  Otherwise, this field is reserved. */
+    pseudo_bit_t	g[0x00001];            /* For responder UD over IB CQE this bit indicates the presence of a GRH
+                                                 For responder UD over Ethernet CQE this bit is set if IPv6 L3 header was present in the packet, this bit is cleared if IPv4 L3 Header was present in the packet.
+                                                 Otherwise, this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	slid_smac47_32[0x00010];/* For responder UD over IB CQE it is the source LID of the packet.
+                                                 For responder UD over Ethernet and RawEth CQEs it is the source-MAC[47:32] of the packet.
+                                                 Otherwise, this field is reserved. */
+    pseudo_bit_t	vid[0x0000c];          /* Frame VID, valid for Responder Raw Ethernet and UD over Ethernet QP. Otherwise, this field is reserved. */
+    pseudo_bit_t	sl[0x00004];           /* For responder UD over IB - the Service Level of the packet.
+                                                  For responder UD over Ethernet and RawEth - it is VLAN-header[15:12]
+                                                  Otherwise, this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	smac31_0_rawether_ipoib_status[0x00020];/* For responder UD over Ethernet - source MAC[31:0] of the packet. 
+                                                  For responder RawEth and UD over IB - RawEth-IPoIB status {3 reserved, ipok,udp,tcp,ipv4opt,ipv6,ipv4vf,ipv4,rht(6),ipv6extmask(6),reserved(2),l2am,reserved(2),bfcs,reserved(2),enc} 
+                                                  Otherwise, this field is reserved. */
+/* -------------- */
+    pseudo_bit_t	byte_cnt[0x00020];     /* Byte count of data transferred. Applicable for RDMA-read, Atomic and all receive operations. completions. 
+                                                 For Receive Queue that is subject for headers. separation, byte_cnt[31:24] specify number of bytes scattered to the first scatter entry (headers. length). Byte_cnt[23:0] specify total byte count received (including headers). */
+/* -------------- */
+    pseudo_bit_t	checksum[0x00010];     /* Valid for RawEth and IPoIB only. */
+    pseudo_bit_t	wqe_counter[0x00010];
+/* -------------- */
+    pseudo_bit_t	opcode[0x00005];       /* Send completions - same encoding as WQE. 
+                                                  Error coding is 0x1F
+                                                  Receive:
+                                                  0x0 - RDMA-Write with Immediate
+                                                  0x1 - Send
+                                                  0x2 - Send with Immediate
+                                                  0x3 - Send & Invalidate
+                                                  */
+    pseudo_bit_t	is[0x00001];           /* inline scatter */
+    pseudo_bit_t	s_r[0x00001];          /* send 1 / receive 0 */
+    pseudo_bit_t	owner[0x00001];        /* HW Flips this bit for every CQ warp around. Initialized to Zero. */
+    pseudo_bit_t	reserved1[0x00010];
+    pseudo_bit_t	reserved2[0x00008];
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_mcg_qps_st {	/* Little Endian */
+    struct hermonprm_mcg_qp_dw_st	dw[128];
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_mcg_hdr_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	next_mcg[0x0001a];
+/* -------------- */
+    pseudo_bit_t	members_count[0x00018];
+    pseudo_bit_t	member_remove[0x00001];
+    pseudo_bit_t	reserved1[0x00005];
+    pseudo_bit_t	protocol[0x00002];
+/* -------------- */
+    pseudo_bit_t	reserved2[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved3[0x00020];
+/* -------------- */
+    pseudo_bit_t	gid3[0x00020];
+/* -------------- */
+    pseudo_bit_t	gid2[0x00020];
+/* -------------- */
+    pseudo_bit_t	gid1[0x00020];
+/* -------------- */
+    pseudo_bit_t	gid0[0x00020];
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_sched_queue_context_st {	/* Little Endian */
+    pseudo_bit_t	policy[0x00003];       /* Schedule Queue Policy - 0 - LLSQ, 1 - GBSQ, 2 - BESQ */
+    pseudo_bit_t	vl15[0x00001];
+    pseudo_bit_t	sl[0x00004];           /* SL this Schedule Queue is associated with (if vl15 bit is 0) */
+    pseudo_bit_t	port[0x00002];         /* Port this Schedule Queue is associated with */
+    pseudo_bit_t	reserved0[0x00006];
+    pseudo_bit_t	weight[0x00010];       /* Weight of this SchQ */
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_ecc_detect_event_data_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	cause_lsb[0x00001];
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	cause_msb[0x00001];
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	err_rmw[0x00001];
+    pseudo_bit_t	err_src_id[0x00003];
+    pseudo_bit_t	err_da[0x00002];
+    pseudo_bit_t	err_ba[0x00002];
+    pseudo_bit_t	reserved3[0x00011];
+    pseudo_bit_t	overflow[0x00001];
+/* -------------- */
+    pseudo_bit_t	err_ra[0x00010];
+    pseudo_bit_t	err_ca[0x00010];
+/* -------------- */
+}; 
+
+/* Event_data Field - ECC Detection Event */
+
+struct hermonprm_scrubbing_event_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00080];
+/* -------------- */
+    pseudo_bit_t	cause_lsb[0x00001];    /* data integrity error cause:
+                                                 single ECC error in the 64bit lsb data, on the rise edge of the clock */
+    pseudo_bit_t	reserved1[0x00002];
+    pseudo_bit_t	cause_msb[0x00001];    /* data integrity error cause:
+                                                 single ECC error in the 64bit msb data, on the fall edge of the clock */
+    pseudo_bit_t	reserved2[0x00002];
+    pseudo_bit_t	err_rmw[0x00001];      /* transaction type:
+                                                 0 - read
+                                                 1 - read/modify/write */
+    pseudo_bit_t	err_src_id[0x00003];   /* source of the transaction: 0x4 - PCI, other - internal or IB */
+    pseudo_bit_t	err_da[0x00002];       /* Error DIMM address */
+    pseudo_bit_t	err_ba[0x00002];       /* Error bank address */
+    pseudo_bit_t	reserved3[0x00011];
+    pseudo_bit_t	overflow[0x00001];     /* Fatal: ECC error FIFO overflow - ECC errors were detected, which may or may not have been corrected by InfiniHost-III-EX */
+/* -------------- */
+    pseudo_bit_t	err_ra[0x00010];       /* Error row address */
+    pseudo_bit_t	err_ca[0x00010];       /* Error column address */
+/* -------------- */
+}; 
+
+/*  */
+
+struct hermonprm_eq_cmd_doorbell_st {	/* Little Endian */
+    pseudo_bit_t	reserved0[0x00020];
+/* -------------- */
+}; 
+
+/* 0 */
+
+struct hermonprm_hermon_prm_st {	/* Little Endian */
+    struct hermonprm_completion_queue_entry_st	completion_queue_entry;/* Completion Queue Entry Format */
+/* -------------- */
+    pseudo_bit_t	reserved0[0x7ff00];
+/* -------------- */
+    struct hermonprm_qp_ee_state_transitions_st	qp_ee_state_transitions;/* QP/EE State Transitions Command Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved1[0x7f000];
+/* -------------- */
+    struct hermonprm_event_queue_entry_st	event_queue_entry;/* Event Queue Entry */
+/* -------------- */
+    pseudo_bit_t	reserved2[0x7ff00];
+/* -------------- */
+    struct hermonprm_completion_event_st	completion_event;/* Event_data Field - Completion Event */
+/* -------------- */
+    pseudo_bit_t	reserved3[0x7ff40];
+/* -------------- */
+    struct hermonprm_completion_queue_error_st	completion_queue_error;/* Event_data Field - Completion Queue Error */
+/* -------------- */
+    pseudo_bit_t	reserved4[0x7ff40];
+/* -------------- */
+    struct hermonprm_port_state_change_st	port_state_change;/* Event_data Field - Port State Change */
+/* -------------- */
+    pseudo_bit_t	reserved5[0x7ff40];
+/* -------------- */
+    struct hermonprm_wqe_segment_st	wqe_segment;/* WQE segments format */
+/* -------------- */
+    pseudo_bit_t	reserved6[0x7f000];
+/* -------------- */
+    struct hermonprm_page_fault_event_data_st	page_fault_event_data;/* Event_data Field - Page Faults */
+/* -------------- */
+    pseudo_bit_t	reserved7[0x7ff40];
+/* -------------- */
+    struct hermonprm_performance_monitor_event_st	performance_monitor_event;/* Event Data Field - Performance Monitor */
+/* -------------- */
+    pseudo_bit_t	reserved8[0xfff20];
+/* -------------- */
+    struct hermonprm_mt25208_type0_st	mt25208_type0;/* InfiniHost-III-EX Type0 Configuration Header */
+/* -------------- */
+    pseudo_bit_t	reserved9[0x7f000];
+/* -------------- */
+    struct hermonprm_qp_ee_event_st	qp_ee_event;/* Event_data Field - QP/EE Events */
+/* -------------- */
+    pseudo_bit_t	reserved10[0x00040];
+/* -------------- */
+    struct hermonprm_gpio_event_data_st	gpio_event_data;
+/* -------------- */
+    pseudo_bit_t	reserved11[0x7fe40];
+/* -------------- */
+    struct hermonprm_ud_address_vector_st	ud_address_vector;/* UD Address Vector */
+/* -------------- */
+    pseudo_bit_t	reserved12[0x7ff00];
+/* -------------- */
+    struct hermonprm_queue_pair_ee_context_entry_st	queue_pair_ee_context_entry;/* QP and EE Context Entry */
+/* -------------- */
+    pseudo_bit_t	reserved13[0x7f840];
+/* -------------- */
+    struct hermonprm_address_path_st	address_path;/* Address Path */
+/* -------------- */
+    pseudo_bit_t	reserved14[0x7fea0];
+/* -------------- */
+    struct hermonprm_completion_queue_context_st	completion_queue_context;/* Completion Queue Context Table Entry */
+/* -------------- */
+    pseudo_bit_t	reserved15[0x7fe00];
+/* -------------- */
+    struct hermonprm_mpt_st	mpt;         /* Memory Protection Table (MPT) Entry */
+/* -------------- */
+    pseudo_bit_t	reserved16[0x7fe00];
+/* -------------- */
+    struct hermonprm_mtt_st	mtt;         /* Memory Translation Table (MTT) Entry */
+/* -------------- */
+    pseudo_bit_t	reserved17[0x7ffc0];
+/* -------------- */
+    struct hermonprm_eqc_st	eqc;         /* Event Queue Context Table Entry */
+/* -------------- */
+    pseudo_bit_t	reserved18[0x7fe00];
+/* -------------- */
+    struct hermonprm_performance_monitors_st	performance_monitors;/* Performance Monitors */
+/* -------------- */
+    pseudo_bit_t	reserved19[0x7ff80];
+/* -------------- */
+    struct hermonprm_hca_command_register_st	hca_command_register;/* HCA Command Register (HCR) */
+/* -------------- */
+    pseudo_bit_t	reserved20[0xfff20];
+/* -------------- */
+    struct hermonprm_init_hca_st	init_hca;/* INIT_HCA & QUERY_HCA Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved21[0x7f000];
+/* -------------- */
+    struct hermonprm_qpcbaseaddr_st	qpcbaseaddr;/* QPC/EEC/CQC/EQC/RDB Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved22[0x7fc00];
+/* -------------- */
+    struct hermonprm_udavtable_memory_parameters_st	udavtable_memory_parameters;/* Memory Access Parameters for UD Address Vector Table */
+/* -------------- */
+    pseudo_bit_t	reserved23[0x7ffc0];
+/* -------------- */
+    struct hermonprm_multicastparam_st	multicastparam;/* Multicast Support Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved24[0x7ff00];
+/* -------------- */
+    struct hermonprm_tptparams_st	tptparams;/* Translation and Protection Tables Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved25[0x7ff00];
+/* -------------- */
+    pseudo_bit_t	reserved26[0x00800];
+/* -------------- */
+    pseudo_bit_t	reserved27[0x00100];
+/* -------------- */
+    pseudo_bit_t	reserved28[0x7f700];
+/* -------------- */
+    pseudo_bit_t	reserved29[0x00100];
+/* -------------- */
+    pseudo_bit_t	reserved30[0x7ff00];
+/* -------------- */
+    struct hermonprm_query_fw_st	query_fw;/* QUERY_FW Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved31[0x7f800];
+/* -------------- */
+    struct hermonprm_query_adapter_st	query_adapter;/* QUERY_ADAPTER Parameters Block */
+/* -------------- */
+    pseudo_bit_t	reserved32[0x7f800];
+/* -------------- */
+    struct hermonprm_query_dev_cap_st	query_dev_cap;/* Query Device Limitations */
+/* -------------- */
+    pseudo_bit_t	reserved33[0x7f800];
+/* -------------- */
+    struct hermonprm_uar_params_st	uar_params;/* UAR Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved34[0x7ff00];
+/* -------------- */
+    struct hermonprm_init_port_st	init_port;/* INIT_PORT Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved35[0x7f800];
+/* -------------- */
+    struct hermonprm_mgm_entry_st	mgm_entry;/* Multicast Group Member */
+/* -------------- */
+    pseudo_bit_t	reserved36[0x7fe00];
+/* -------------- */
+    struct hermonprm_set_ib_st	set_ib;   /* SET_IB Parameters */
+/* -------------- */
+    pseudo_bit_t	reserved37[0x7fe00];
+/* -------------- */
+    struct hermonprm_rd_send_doorbell_st	rd_send_doorbell;/* RD-send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved38[0x7ff80];
+/* -------------- */
+    struct hermonprm_send_doorbell_st	send_doorbell;/* Send doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved39[0x7ffc0];
+/* -------------- */
+    struct hermonprm_receive_doorbell_st	receive_doorbell;/* Receive doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved40[0x7ffc0];
+/* -------------- */
+    struct hermonprm_cq_cmd_doorbell_st	cq_cmd_doorbell;/* CQ Doorbell */
+/* -------------- */
+    pseudo_bit_t	reserved41[0xfffc0];
+/* -------------- */
+    struct hermonprm_uar_st	uar;         /* User Access Region */
+/* -------------- */
+    pseudo_bit_t	reserved42[0x7c000];
+/* -------------- */
+    struct hermonprm_mgmqp_st	mgmqp;     /* Multicast Group Member QP */
+/* -------------- */
+    pseudo_bit_t	reserved43[0x7ffe0];
+/* -------------- */
+    struct hermonprm_query_debug_msg_st	query_debug_msg;/* Query Debug Message */
+/* -------------- */
+    pseudo_bit_t	reserved44[0x7f800];
+/* -------------- */
+    struct hermonprm_mad_ifc_st	mad_ifc; /* MAD_IFC Input Mailbox */
+/* -------------- */
+    pseudo_bit_t	reserved45[0x00900];
+/* -------------- */
+    struct hermonprm_mad_ifc_input_modifier_st	mad_ifc_input_modifier;/* MAD_IFC Input Modifier */
+/* -------------- */
+    pseudo_bit_t	reserved46[0x7e6e0];
+/* -------------- */
+    struct hermonprm_resize_cq_st	resize_cq;/* Resize CQ Input Mailbox */
+/* -------------- */
+    pseudo_bit_t	reserved47[0x7fe00];
+/* -------------- */
+    struct hermonprm_completion_with_error_st	completion_with_error;/* Completion with Error CQE */
+/* -------------- */
+    pseudo_bit_t	reserved48[0x7ff00];
+/* -------------- */
+    struct hermonprm_hcr_completion_event_st	hcr_completion_event;/* Event_data Field - HCR Completion Event */
+/* -------------- */
+    pseudo_bit_t	reserved49[0x7ff40];
+/* -------------- */
+    struct hermonprm_transport_and_ci_error_counters_st	transport_and_ci_error_counters;/* Transport and CI Error Counters */
+/* -------------- */
+    pseudo_bit_t	reserved50[0x7f000];
+/* -------------- */
+    struct hermonprm_performance_counters_st	performance_counters;/* Performance Counters */
+/* -------------- */
+    pseudo_bit_t	reserved51[0x9ff800];
+/* -------------- */
+    struct hermonprm_fast_registration_segment_st	fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+    pseudo_bit_t	reserved52[0x7ff00];
+/* -------------- */
+    struct hermonprm_pbl_st	pbl;         /* Physical Buffer List */
+/* -------------- */
+    pseudo_bit_t	reserved53[0x7ff00];
+/* -------------- */
+    struct hermonprm_srq_context_st	srq_context;/* SRQ Context */
+/* -------------- */
+    pseudo_bit_t	reserved54[0x7fe80];
+/* -------------- */
+    struct hermonprm_mod_stat_cfg_st	mod_stat_cfg;/* MOD_STAT_CFG */
+/* -------------- */
+    pseudo_bit_t	reserved55[0x7f800];
+/* -------------- */
+    struct hermonprm_virtual_physical_mapping_st	virtual_physical_mapping;/* Virtual and Physical Mapping */
+/* -------------- */
+    pseudo_bit_t	reserved56[0x7ff80];
+/* -------------- */
+    struct hermonprm_cq_ci_db_record_st	cq_ci_db_record;/* CQ_CI_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved57[0x7ffc0];
+/* -------------- */
+    struct hermonprm_cq_arm_db_record_st	cq_arm_db_record;/* CQ_ARM_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved58[0x7ffc0];
+/* -------------- */
+    struct hermonprm_qp_db_record_st	qp_db_record;/* QP_DB_Record */
+/* -------------- */
+    pseudo_bit_t	reserved59[0x00020];
+/* -------------- */
+    pseudo_bit_t	reserved60[0x1fffc0];
+/* -------------- */
+    struct hermonprm_configuration_registers_st	configuration_registers;/* InfiniHost III EX Configuration Registers */
+/* -------------- */
+    struct hermonprm_eq_set_ci_table_st	eq_set_ci_table;/* EQ Set CI DBs Table */
+/* -------------- */
+    pseudo_bit_t	reserved61[0x01000];
+/* -------------- */
+    pseudo_bit_t	reserved62[0x00040];
+/* -------------- */
+    pseudo_bit_t	reserved63[0x00fc0];
+/* -------------- */
+    struct hermonprm_clr_int_st	clr_int; /* Clear Interrupt Register */
+/* -------------- */
+    pseudo_bit_t	reserved64[0xffcfc0];
+/* -------------- */
+}; 
+#endif /* H_prefix_hermonprm_bits_fixnames_MT25408_PRM_csp_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.c b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.c
new file mode 100644
index 0000000..c121bfd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.c
@@ -0,0 +1,2839 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * Based in part upon the original driver by Mellanox Technologies
+ * Ltd.  Portions may be Copyright (c) Mellanox Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_smc.h>
+#include "arbel.h"
+
+/**
+ * @file
+ *
+ * Mellanox Arbel Infiniband HCA
+ *
+ */
+
+/***************************************************************************
+ *
+ * Queue number allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate offset within usage bitmask
+ *
+ * @v bits		Usage bitmask
+ * @v bits_len		Length of usage bitmask
+ * @ret bit		First free bit within bitmask, or negative error
+ */
+static int arbel_bitmask_alloc ( arbel_bitmask_t *bits,
+				 unsigned int bits_len ) {
+	unsigned int bit = 0;
+	arbel_bitmask_t mask = 1;
+
+	while ( bit < bits_len ) {
+		if ( ( mask & *bits ) == 0 ) {
+			*bits |= mask;
+			return bit;
+		}
+		bit++;
+		mask = ( mask << 1 ) | ( mask >> ( 8 * sizeof ( mask ) - 1 ) );
+		if ( mask == 1 )
+			bits++;
+	}
+	return -ENFILE;
+}
+
+/**
+ * Free offset within usage bitmask
+ *
+ * @v bits		Usage bitmask
+ * @v bit		Bit within bitmask
+ */
+static void arbel_bitmask_free ( arbel_bitmask_t *bits, int bit ) {
+	arbel_bitmask_t mask;
+
+	mask = ( 1 << ( bit % ( 8 * sizeof ( mask ) ) ) );
+	bits += ( bit / ( 8 * sizeof ( mask ) ) );
+	*bits &= ~mask;
+}
+
+/***************************************************************************
+ *
+ * HCA commands
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Wait for Arbel command completion
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_cmd_wait ( struct arbel *arbel,
+			    struct arbelprm_hca_command_register *hcr ) {
+	unsigned int wait;
+
+	for ( wait = ARBEL_HCR_MAX_WAIT_MS ; wait ; wait-- ) {
+		hcr->u.dwords[6] =
+			readl ( arbel->config + ARBEL_HCR_REG ( 6 ) );
+		if ( MLX_GET ( hcr, go ) == 0 )
+			return 0;
+		mdelay ( 1 );
+	}
+	return -EBUSY;
+}
+
+/**
+ * Issue HCA command
+ *
+ * @v arbel		Arbel device
+ * @v command		Command opcode, flags and input/output lengths
+ * @v op_mod		Opcode modifier (0 if no modifier applicable)
+ * @v in		Input parameters
+ * @v in_mod		Input modifier (0 if no modifier applicable)
+ * @v out		Output parameters
+ * @ret rc		Return status code
+ */
+static int arbel_cmd ( struct arbel *arbel, unsigned long command,
+		       unsigned int op_mod, const void *in,
+		       unsigned int in_mod, void *out ) {
+	struct arbelprm_hca_command_register hcr;
+	unsigned int opcode = ARBEL_HCR_OPCODE ( command );
+	size_t in_len = ARBEL_HCR_IN_LEN ( command );
+	size_t out_len = ARBEL_HCR_OUT_LEN ( command );
+	void *in_buffer;
+	void *out_buffer;
+	unsigned int status;
+	unsigned int i;
+	int rc;
+
+	assert ( in_len <= ARBEL_MBOX_SIZE );
+	assert ( out_len <= ARBEL_MBOX_SIZE );
+
+	DBGC2 ( arbel, "Arbel %p command %02x in %zx%s out %zx%s\n",
+		arbel, opcode, in_len,
+		( ( command & ARBEL_HCR_IN_MBOX ) ? "(mbox)" : "" ), out_len,
+		( ( command & ARBEL_HCR_OUT_MBOX ) ? "(mbox)" : "" ) );
+
+	/* Check that HCR is free */
+	if ( ( rc = arbel_cmd_wait ( arbel, &hcr ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p command interface locked\n", arbel );
+		return rc;
+	}
+
+	/* Prepare HCR */
+	memset ( &hcr, 0, sizeof ( hcr ) );
+	in_buffer = &hcr.u.dwords[0];
+	if ( in_len && ( command & ARBEL_HCR_IN_MBOX ) ) {
+		in_buffer = arbel->mailbox_in;
+		MLX_FILL_H ( &hcr, 0, in_param_h, virt_to_bus ( in_buffer ) );
+		MLX_FILL_1 ( &hcr, 1, in_param_l, virt_to_bus ( in_buffer ) );
+	}
+	memcpy ( in_buffer, in, in_len );
+	MLX_FILL_1 ( &hcr, 2, input_modifier, in_mod );
+	out_buffer = &hcr.u.dwords[3];
+	if ( out_len && ( command & ARBEL_HCR_OUT_MBOX ) ) {
+		out_buffer = arbel->mailbox_out;
+		MLX_FILL_H ( &hcr, 3, out_param_h,
+			     virt_to_bus ( out_buffer ) );
+		MLX_FILL_1 ( &hcr, 4, out_param_l,
+			     virt_to_bus ( out_buffer ) );
+	}
+	MLX_FILL_3 ( &hcr, 6,
+		     opcode, opcode,
+		     opcode_modifier, op_mod,
+		     go, 1 );
+	DBGC ( arbel, "Arbel %p issuing command %04x\n", arbel, opcode );
+	DBGC2_HDA ( arbel, virt_to_phys ( arbel->config + ARBEL_HCR_BASE ),
+		    &hcr, sizeof ( hcr ) );
+	if ( in_len && ( command & ARBEL_HCR_IN_MBOX ) ) {
+		DBGC2 ( arbel, "Input mailbox:\n" );
+		DBGC2_HDA ( arbel, virt_to_phys ( in_buffer ), in_buffer,
+			    ( ( in_len < 512 ) ? in_len : 512 ) );
+	}
+
+	/* Issue command */
+	for ( i = 0 ; i < ( sizeof ( hcr ) / sizeof ( hcr.u.dwords[0] ) ) ;
+	      i++ ) {
+		writel ( hcr.u.dwords[i],
+			 arbel->config + ARBEL_HCR_REG ( i ) );
+		barrier();
+	}
+
+	/* Wait for command completion */
+	if ( ( rc = arbel_cmd_wait ( arbel, &hcr ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p timed out waiting for command:\n",
+		       arbel );
+		DBGC_HD ( arbel, &hcr, sizeof ( hcr ) );
+		return rc;
+	}
+
+	/* Check command status */
+	status = MLX_GET ( &hcr, status );
+	if ( status != 0 ) {
+		DBGC ( arbel, "Arbel %p command failed with status %02x:\n",
+		       arbel, status );
+		DBGC_HD ( arbel, &hcr, sizeof ( hcr ) );
+		return -EIO;
+	}
+
+	/* Read output parameters, if any */
+	hcr.u.dwords[3] = readl ( arbel->config + ARBEL_HCR_REG ( 3 ) );
+	hcr.u.dwords[4] = readl ( arbel->config + ARBEL_HCR_REG ( 4 ) );
+	memcpy ( out, out_buffer, out_len );
+	if ( out_len ) {
+		DBGC2 ( arbel, "Output%s:\n",
+			( command & ARBEL_HCR_OUT_MBOX ) ? " mailbox" : "" );
+		DBGC2_HDA ( arbel, virt_to_phys ( out_buffer ), out_buffer,
+			    ( ( out_len < 512 ) ? out_len : 512 ) );
+	}
+
+	return 0;
+}
+
+static inline int
+arbel_cmd_query_dev_lim ( struct arbel *arbel,
+			  struct arbelprm_query_dev_lim *dev_lim ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_DEV_LIM,
+					       1, sizeof ( *dev_lim ) ),
+			   0, NULL, 0, dev_lim );
+}
+
+static inline int
+arbel_cmd_query_fw ( struct arbel *arbel, struct arbelprm_query_fw *fw ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_FW, 
+					       1, sizeof ( *fw ) ),
+			   0, NULL, 0, fw );
+}
+
+static inline int
+arbel_cmd_init_hca ( struct arbel *arbel,
+		     const struct arbelprm_init_hca *init_hca ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT_HCA,
+					      1, sizeof ( *init_hca ) ),
+			   0, init_hca, 0, NULL );
+}
+
+static inline int
+arbel_cmd_close_hca ( struct arbel *arbel ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CLOSE_HCA ),
+			   0, NULL, 0, NULL );
+}
+
+static inline int
+arbel_cmd_init_ib ( struct arbel *arbel, unsigned int port,
+		    const struct arbelprm_init_ib *init_ib ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT_IB,
+					      1, sizeof ( *init_ib ) ),
+			   0, init_ib, port, NULL );
+}
+
+static inline int
+arbel_cmd_close_ib ( struct arbel *arbel, unsigned int port ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CLOSE_IB ),
+			   0, NULL, port, NULL );
+}
+
+static inline int
+arbel_cmd_sw2hw_mpt ( struct arbel *arbel, unsigned int index,
+		      const struct arbelprm_mpt *mpt ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_MPT,
+					      1, sizeof ( *mpt ) ),
+			   0, mpt, index, NULL );
+}
+
+static inline int
+arbel_cmd_map_eq ( struct arbel *arbel, unsigned long index_map,
+		   const struct arbelprm_event_mask *mask ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_EQ,
+					      0, sizeof ( *mask ) ),
+			   0, mask, index_map, NULL );
+}
+
+static inline int
+arbel_cmd_sw2hw_eq ( struct arbel *arbel, unsigned int index,
+		     const struct arbelprm_eqc *eqctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_EQ,
+					      1, sizeof ( *eqctx ) ),
+			   0, eqctx, index, NULL );
+}
+
+static inline int
+arbel_cmd_hw2sw_eq ( struct arbel *arbel, unsigned int index,
+		     struct arbelprm_eqc *eqctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_HW2SW_EQ,
+					       1, sizeof ( *eqctx ) ),
+			   1, NULL, index, eqctx );
+}
+
+static inline int
+arbel_cmd_sw2hw_cq ( struct arbel *arbel, unsigned long cqn,
+		     const struct arbelprm_completion_queue_context *cqctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_CQ,
+					      1, sizeof ( *cqctx ) ),
+			   0, cqctx, cqn, NULL );
+}
+
+static inline int
+arbel_cmd_hw2sw_cq ( struct arbel *arbel, unsigned long cqn,
+		     struct arbelprm_completion_queue_context *cqctx) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_HW2SW_CQ,
+					       1, sizeof ( *cqctx ) ),
+			   0, NULL, cqn, cqctx );
+}
+
+static inline int
+arbel_cmd_query_cq ( struct arbel *arbel, unsigned long cqn,
+		     struct arbelprm_completion_queue_context *cqctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_CQ,
+					       1, sizeof ( *cqctx ) ),
+			   0, NULL, cqn, cqctx );
+}
+
+static inline int
+arbel_cmd_rst2init_qpee ( struct arbel *arbel, unsigned long qpn,
+			  const struct arbelprm_qp_ee_state_transitions *ctx ){
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_RST2INIT_QPEE,
+					      1, sizeof ( *ctx ) ),
+			   0, ctx, qpn, NULL );
+}
+
+static inline int
+arbel_cmd_init2rtr_qpee ( struct arbel *arbel, unsigned long qpn,
+			  const struct arbelprm_qp_ee_state_transitions *ctx ){
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT2RTR_QPEE,
+					      1, sizeof ( *ctx ) ),
+			   0, ctx, qpn, NULL );
+}
+
+static inline int
+arbel_cmd_rtr2rts_qpee ( struct arbel *arbel, unsigned long qpn,
+			 const struct arbelprm_qp_ee_state_transitions *ctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_RTR2RTS_QPEE,
+					      1, sizeof ( *ctx ) ),
+			   0, ctx, qpn, NULL );
+}
+
+static inline int
+arbel_cmd_rts2rts_qpee ( struct arbel *arbel, unsigned long qpn,
+			 const struct arbelprm_qp_ee_state_transitions *ctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_RTS2RTS_QPEE,
+					      1, sizeof ( *ctx ) ),
+			   0, ctx, qpn, NULL );
+}
+
+static inline int
+arbel_cmd_2rst_qpee ( struct arbel *arbel, unsigned long qpn ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_2RST_QPEE ),
+			   0x03, NULL, qpn, NULL );
+}
+
+static inline int
+arbel_cmd_query_qpee ( struct arbel *arbel, unsigned long qpn,
+		       struct arbelprm_qp_ee_state_transitions *ctx ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_QPEE,
+					       1, sizeof ( *ctx ) ),
+			   0, NULL, qpn, ctx );
+}
+
+static inline int
+arbel_cmd_conf_special_qp ( struct arbel *arbel, unsigned int qp_type,
+			    unsigned long base_qpn ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CONF_SPECIAL_QP ),
+			   qp_type, NULL, base_qpn, NULL );
+}
+
+static inline int
+arbel_cmd_mad_ifc ( struct arbel *arbel, unsigned int port,
+		    union arbelprm_mad *mad ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_MAD_IFC,
+						 1, sizeof ( *mad ),
+						 1, sizeof ( *mad ) ),
+			   0x03, mad, port, mad );
+}
+
+static inline int
+arbel_cmd_read_mgm ( struct arbel *arbel, unsigned int index,
+		     struct arbelprm_mgm_entry *mgm ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_READ_MGM,
+					       1, sizeof ( *mgm ) ),
+			   0, NULL, index, mgm );
+}
+
+static inline int
+arbel_cmd_write_mgm ( struct arbel *arbel, unsigned int index,
+		      const struct arbelprm_mgm_entry *mgm ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_WRITE_MGM,
+					      1, sizeof ( *mgm ) ),
+			   0, mgm, index, NULL );
+}
+
+static inline int
+arbel_cmd_mgid_hash ( struct arbel *arbel, const union ib_gid *gid,
+		      struct arbelprm_mgm_hash *hash ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_MGID_HASH,
+						 1, sizeof ( *gid ),
+						 0, sizeof ( *hash ) ),
+			   0, gid, 0, hash );
+}
+
+static inline int
+arbel_cmd_run_fw ( struct arbel *arbel ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_RUN_FW ),
+			   0, NULL, 0, NULL );
+}
+
+static inline int
+arbel_cmd_disable_lam ( struct arbel *arbel ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_DISABLE_LAM ),
+			   0, NULL, 0, NULL );
+}
+
+static inline int
+arbel_cmd_enable_lam ( struct arbel *arbel, struct arbelprm_access_lam *lam ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_OUT_CMD ( ARBEL_HCR_ENABLE_LAM,
+					       1, sizeof ( *lam ) ),
+			   1, NULL, 0, lam );
+}
+
+static inline int
+arbel_cmd_unmap_icm ( struct arbel *arbel, unsigned int page_count,
+		      const struct arbelprm_scalar_parameter *offset ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_UNMAP_ICM, 0,
+					      sizeof ( *offset ) ),
+			   0, offset, page_count, NULL );
+}
+
+static inline int
+arbel_cmd_map_icm ( struct arbel *arbel,
+		    const struct arbelprm_virtual_physical_mapping *map ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_ICM,
+					      1, sizeof ( *map ) ),
+			   0, map, 1, NULL );
+}
+
+static inline int
+arbel_cmd_unmap_icm_aux ( struct arbel *arbel ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_UNMAP_ICM_AUX ),
+			   0, NULL, 0, NULL );
+}
+
+static inline int
+arbel_cmd_map_icm_aux ( struct arbel *arbel,
+			const struct arbelprm_virtual_physical_mapping *map ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_ICM_AUX,
+					      1, sizeof ( *map ) ),
+			   0, map, 1, NULL );
+}
+
+static inline int
+arbel_cmd_set_icm_size ( struct arbel *arbel,
+			 const struct arbelprm_scalar_parameter *icm_size,
+			 struct arbelprm_scalar_parameter *icm_aux_size ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_SET_ICM_SIZE,
+						 0, sizeof ( *icm_size ),
+						 0, sizeof ( *icm_aux_size ) ),
+			   0, icm_size, 0, icm_aux_size );
+}
+
+static inline int
+arbel_cmd_unmap_fa ( struct arbel *arbel ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_VOID_CMD ( ARBEL_HCR_UNMAP_FA ),
+			   0, NULL, 0, NULL );
+}
+
+static inline int
+arbel_cmd_map_fa ( struct arbel *arbel,
+		   const struct arbelprm_virtual_physical_mapping *map ) {
+	return arbel_cmd ( arbel,
+			   ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_FA,
+					      1, sizeof ( *map ) ),
+			   0, map, 1, NULL );
+}
+
+/***************************************************************************
+ *
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Management datagram
+ * @ret rc		Return status code
+ */
+static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	union arbelprm_mad mad_ifc;
+	int rc;
+
+	linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+			mad_size_mismatch );
+
+	/* Copy in request packet */
+	memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+	/* Issue MAD */
+	if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port,
+					&mad_ifc ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d could not issue MAD IFC: %s\n",
+		       arbel, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Copy out reply packet */
+	memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+	if ( mad->hdr.status != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d MAD IFC status %04x\n",
+		       arbel, ibdev->port, ntohs ( mad->hdr.status ) );
+		return -EIO;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Dump completion queue context (for debugging only)
+ *
+ * @v arbel		Arbel device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static __attribute__ (( unused )) int
+arbel_dump_cqctx ( struct arbel *arbel, struct ib_completion_queue *cq ) {
+	struct arbelprm_completion_queue_context cqctx;
+	int rc;
+
+	memset ( &cqctx, 0, sizeof ( cqctx ) );
+	if ( ( rc = arbel_cmd_query_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p CQN %#lx QUERY_CQ failed: %s\n",
+		       arbel, cq->cqn, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( arbel, "Arbel %p CQN %#lx context:\n", arbel, cq->cqn );
+	DBGC_HDA ( arbel, 0, &cqctx, sizeof ( cqctx ) );
+
+	return 0;
+}
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static int arbel_create_cq ( struct ib_device *ibdev,
+			     struct ib_completion_queue *cq ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_completion_queue *arbel_cq;
+	struct arbelprm_completion_queue_context cqctx;
+	struct arbelprm_cq_ci_db_record *ci_db_rec;
+	struct arbelprm_cq_arm_db_record *arm_db_rec;
+	int cqn_offset;
+	unsigned int i;
+	int rc;
+
+	/* Find a free completion queue number */
+	cqn_offset = arbel_bitmask_alloc ( arbel->cq_inuse, ARBEL_MAX_CQS );
+	if ( cqn_offset < 0 ) {
+		DBGC ( arbel, "Arbel %p out of completion queues\n", arbel );
+		rc = cqn_offset;
+		goto err_cqn_offset;
+	}
+	cq->cqn = ( arbel->limits.reserved_cqs + cqn_offset );
+
+	/* Allocate control structures */
+	arbel_cq = zalloc ( sizeof ( *arbel_cq ) );
+	if ( ! arbel_cq ) {
+		rc = -ENOMEM;
+		goto err_arbel_cq;
+	}
+	arbel_cq->ci_doorbell_idx = arbel_cq_ci_doorbell_idx ( arbel, cq );
+	arbel_cq->arm_doorbell_idx = arbel_cq_arm_doorbell_idx ( arbel, cq );
+
+	/* Allocate completion queue itself */
+	arbel_cq->cqe_size = ( cq->num_cqes * sizeof ( arbel_cq->cqe[0] ) );
+	arbel_cq->cqe = malloc_dma ( arbel_cq->cqe_size,
+				     sizeof ( arbel_cq->cqe[0] ) );
+	if ( ! arbel_cq->cqe ) {
+		rc = -ENOMEM;
+		goto err_cqe;
+	}
+	memset ( arbel_cq->cqe, 0, arbel_cq->cqe_size );
+	for ( i = 0 ; i < cq->num_cqes ; i++ ) {
+		MLX_FILL_1 ( &arbel_cq->cqe[i].normal, 7, owner, 1 );
+	}
+	barrier();
+
+	/* Initialise doorbell records */
+	ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci;
+	MLX_FILL_1 ( ci_db_rec, 0, counter, 0 );
+	MLX_FILL_2 ( ci_db_rec, 1,
+		     res, ARBEL_UAR_RES_CQ_CI,
+		     cq_number, cq->cqn );
+	arm_db_rec = &arbel->db_rec[arbel_cq->arm_doorbell_idx].cq_arm;
+	MLX_FILL_1 ( arm_db_rec, 0, counter, 0 );
+	MLX_FILL_2 ( arm_db_rec, 1,
+		     res, ARBEL_UAR_RES_CQ_ARM,
+		     cq_number, cq->cqn );
+
+	/* Hand queue over to hardware */
+	memset ( &cqctx, 0, sizeof ( cqctx ) );
+	MLX_FILL_1 ( &cqctx, 0, st, 0xa /* "Event fired" */ );
+	MLX_FILL_H ( &cqctx, 1, start_address_h,
+		     virt_to_bus ( arbel_cq->cqe ) );
+	MLX_FILL_1 ( &cqctx, 2, start_address_l,
+		     virt_to_bus ( arbel_cq->cqe ) );
+	MLX_FILL_2 ( &cqctx, 3,
+		     usr_page, arbel->limits.reserved_uars,
+		     log_cq_size, fls ( cq->num_cqes - 1 ) );
+	MLX_FILL_1 ( &cqctx, 5, c_eqn, arbel->eq.eqn );
+	MLX_FILL_1 ( &cqctx, 6, pd, ARBEL_GLOBAL_PD );
+	MLX_FILL_1 ( &cqctx, 7, l_key, arbel->lkey );
+	MLX_FILL_1 ( &cqctx, 12, cqn, cq->cqn );
+	MLX_FILL_1 ( &cqctx, 13,
+		     cq_ci_db_record, arbel_cq->ci_doorbell_idx );
+	MLX_FILL_1 ( &cqctx, 14,
+		     cq_state_db_record, arbel_cq->arm_doorbell_idx );
+	if ( ( rc = arbel_cmd_sw2hw_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p CQN %#lx SW2HW_CQ failed: %s\n",
+		       arbel, cq->cqn, strerror ( rc ) );
+		goto err_sw2hw_cq;
+	}
+
+	DBGC ( arbel, "Arbel %p CQN %#lx ring [%08lx,%08lx), doorbell %08lx\n",
+	       arbel, cq->cqn, virt_to_phys ( arbel_cq->cqe ),
+	       ( virt_to_phys ( arbel_cq->cqe ) + arbel_cq->cqe_size ),
+	       virt_to_phys ( ci_db_rec ) );
+	ib_cq_set_drvdata ( cq, arbel_cq );
+	return 0;
+
+ err_sw2hw_cq:
+	MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+	MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+	free_dma ( arbel_cq->cqe, arbel_cq->cqe_size );
+ err_cqe:
+	free ( arbel_cq );
+ err_arbel_cq:
+	arbel_bitmask_free ( arbel->cq_inuse, cqn_offset );
+ err_cqn_offset:
+	return rc;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void arbel_destroy_cq ( struct ib_device *ibdev,
+			       struct ib_completion_queue *cq ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq );
+	struct arbelprm_completion_queue_context cqctx;
+	struct arbelprm_cq_ci_db_record *ci_db_rec;
+	struct arbelprm_cq_arm_db_record *arm_db_rec;
+	int cqn_offset;
+	int rc;
+
+	/* Take ownership back from hardware */
+	if ( ( rc = arbel_cmd_hw2sw_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p CQN %#lx FATAL HW2SW_CQ failed: "
+		       "%s\n", arbel, cq->cqn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Clear doorbell records */
+	ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci;
+	arm_db_rec = &arbel->db_rec[arbel_cq->arm_doorbell_idx].cq_arm;
+	MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+	MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+
+	/* Free memory */
+	free_dma ( arbel_cq->cqe, arbel_cq->cqe_size );
+	free ( arbel_cq );
+
+	/* Mark queue number as free */
+	cqn_offset = ( cq->cqn - arbel->limits.reserved_cqs );
+	arbel_bitmask_free ( arbel->cq_inuse, cqn_offset );
+
+	ib_cq_set_drvdata ( cq, NULL );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Assign queue pair number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int arbel_alloc_qpn ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	unsigned int port_offset;
+	int qpn_offset;
+
+	/* Calculate queue pair number */
+	port_offset = ( ibdev->port - ARBEL_PORT_BASE );
+
+	switch ( qp->type ) {
+	case IB_QPT_SMI:
+		qp->qpn = ( arbel->special_qpn_base + port_offset );
+		return 0;
+	case IB_QPT_GSI:
+		qp->qpn = ( arbel->special_qpn_base + 2 + port_offset );
+		return 0;
+	case IB_QPT_UD:
+		/* Find a free queue pair number */
+		qpn_offset = arbel_bitmask_alloc ( arbel->qp_inuse,
+						   ARBEL_MAX_QPS );
+		if ( qpn_offset < 0 ) {
+			DBGC ( arbel, "Arbel %p out of queue pairs\n",
+			       arbel );
+			return qpn_offset;
+		}
+		qp->qpn = ( ( random() & ARBEL_QPN_RANDOM_MASK ) |
+			    ( arbel->qpn_base + qpn_offset ) );
+		return 0;
+	default:
+		DBGC ( arbel, "Arbel %p unsupported QP type %d\n",
+		       arbel, qp->type );
+		return -ENOTSUP;
+	}
+}
+
+/**
+ * Free queue pair number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void arbel_free_qpn ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	int qpn_offset;
+
+	qpn_offset = ( ( qp->qpn & ~ARBEL_QPN_RANDOM_MASK ) - arbel->qpn_base );
+	if ( qpn_offset >= 0 )
+		arbel_bitmask_free ( arbel->qp_inuse, qpn_offset );
+}
+
+/**
+ * Calculate transmission rate
+ *
+ * @v av		Address vector
+ * @ret arbel_rate	Arbel rate
+ */
+static unsigned int arbel_rate ( struct ib_address_vector *av ) {
+	return ( ( ( av->rate >= IB_RATE_2_5 ) && ( av->rate <= IB_RATE_120 ) )
+		 ? ( av->rate + 5 ) : 0 );
+}
+
+/** Queue pair transport service type map */
+static uint8_t arbel_qp_st[] = {
+	[IB_QPT_SMI] = ARBEL_ST_MLX,
+	[IB_QPT_GSI] = ARBEL_ST_MLX,
+	[IB_QPT_UD] = ARBEL_ST_UD,
+};
+
+/**
+ * Dump queue pair context (for debugging only)
+ *
+ * @v arbel		Arbel device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static __attribute__ (( unused )) int
+arbel_dump_qpctx ( struct arbel *arbel, struct ib_queue_pair *qp ) {
+	struct arbelprm_qp_ee_state_transitions qpctx;
+	int rc;
+
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	if ( ( rc = arbel_cmd_query_qpee ( arbel, qp->qpn, &qpctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p QPN %#lx QUERY_QPEE failed: %s\n",
+		       arbel, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( arbel, "Arbel %p QPN %#lx context:\n", arbel, qp->qpn );
+	DBGC_HDA ( arbel, 0, &qpctx.u.dwords[2], ( sizeof ( qpctx ) - 8 ) );
+
+	return 0;
+}
+
+/**
+ * Create send work queue
+ *
+ * @v arbel_send_wq	Send work queue
+ * @v num_wqes		Number of work queue entries
+ * @ret rc		Return status code
+ */
+static int arbel_create_send_wq ( struct arbel_send_work_queue *arbel_send_wq,
+				  unsigned int num_wqes ) {
+	union arbel_send_wqe *wqe;
+	union arbel_send_wqe *next_wqe;
+	unsigned int wqe_idx_mask;
+	unsigned int i;
+
+	/* Allocate work queue */
+	arbel_send_wq->wqe_size = ( num_wqes *
+				    sizeof ( arbel_send_wq->wqe[0] ) );
+	arbel_send_wq->wqe = malloc_dma ( arbel_send_wq->wqe_size,
+					  sizeof ( arbel_send_wq->wqe[0] ) );
+	if ( ! arbel_send_wq->wqe )
+		return -ENOMEM;
+	memset ( arbel_send_wq->wqe, 0, arbel_send_wq->wqe_size );
+
+	/* Link work queue entries */
+	wqe_idx_mask = ( num_wqes - 1 );
+	for ( i = 0 ; i < num_wqes ; i++ ) {
+		wqe = &arbel_send_wq->wqe[i];
+		next_wqe = &arbel_send_wq->wqe[ ( i + 1 ) & wqe_idx_mask ];
+		MLX_FILL_1 ( &wqe->next, 0, nda_31_6,
+			     ( virt_to_bus ( next_wqe ) >> 6 ) );
+		MLX_FILL_1 ( &wqe->next, 1, always1, 1 );
+	}
+	
+	return 0;
+}
+
+/**
+ * Create receive work queue
+ *
+ * @v arbel_recv_wq	Receive work queue
+ * @v num_wqes		Number of work queue entries
+ * @ret rc		Return status code
+ */
+static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq,
+				  unsigned int num_wqes ) {
+	struct arbelprm_recv_wqe *wqe;
+	struct arbelprm_recv_wqe *next_wqe;
+	unsigned int wqe_idx_mask;
+	size_t nds;
+	unsigned int i;
+	unsigned int j;
+
+	/* Allocate work queue */
+	arbel_recv_wq->wqe_size = ( num_wqes *
+				    sizeof ( arbel_recv_wq->wqe[0] ) );
+	arbel_recv_wq->wqe = malloc_dma ( arbel_recv_wq->wqe_size,
+					  sizeof ( arbel_recv_wq->wqe[0] ) );
+	if ( ! arbel_recv_wq->wqe )
+		return -ENOMEM;
+	memset ( arbel_recv_wq->wqe, 0, arbel_recv_wq->wqe_size );
+
+	/* Link work queue entries */
+	wqe_idx_mask = ( num_wqes - 1 );
+	nds = ( ( offsetof ( typeof ( *wqe ), data ) +
+		  sizeof ( wqe->data[0] ) ) >> 4 );
+	for ( i = 0 ; i < num_wqes ; i++ ) {
+		wqe = &arbel_recv_wq->wqe[i].recv;
+		next_wqe = &arbel_recv_wq->wqe[( i + 1 ) & wqe_idx_mask].recv;
+		MLX_FILL_1 ( &wqe->next, 0, nda_31_6,
+			     ( virt_to_bus ( next_wqe ) >> 6 ) );
+		MLX_FILL_1 ( &wqe->next, 1, nds, nds );
+		for ( j = 0 ; ( ( ( void * ) &wqe->data[j] ) <
+				( ( void * ) ( wqe + 1 ) ) ) ; j++ ) {
+			MLX_FILL_1 ( &wqe->data[j], 1,
+				     l_key, ARBEL_INVALID_LKEY );
+		}
+	}
+	
+	return 0;
+}
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int arbel_create_qp ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_queue_pair *arbel_qp;
+	struct arbelprm_qp_ee_state_transitions qpctx;
+	struct arbelprm_qp_db_record *send_db_rec;
+	struct arbelprm_qp_db_record *recv_db_rec;
+	physaddr_t send_wqe_base_adr;
+	physaddr_t recv_wqe_base_adr;
+	physaddr_t wqe_base_adr;
+	int rc;
+
+	/* Calculate queue pair number */
+	if ( ( rc = arbel_alloc_qpn ( ibdev, qp ) ) != 0 )
+		goto err_alloc_qpn;
+
+	/* Allocate control structures */
+	arbel_qp = zalloc ( sizeof ( *arbel_qp ) );
+	if ( ! arbel_qp ) {
+		rc = -ENOMEM;
+		goto err_arbel_qp;
+	}
+	arbel_qp->send.doorbell_idx = arbel_send_doorbell_idx ( arbel, qp );
+	arbel_qp->recv.doorbell_idx = arbel_recv_doorbell_idx ( arbel, qp );
+
+	/* Create send and receive work queues */
+	if ( ( rc = arbel_create_send_wq ( &arbel_qp->send,
+					   qp->send.num_wqes ) ) != 0 )
+		goto err_create_send_wq;
+	if ( ( rc = arbel_create_recv_wq ( &arbel_qp->recv,
+					   qp->recv.num_wqes ) ) != 0 )
+		goto err_create_recv_wq;
+
+	/* Send and receive work queue entries must be within the same 4GB */
+	send_wqe_base_adr = virt_to_bus ( arbel_qp->send.wqe );
+	recv_wqe_base_adr = virt_to_bus ( arbel_qp->recv.wqe );
+	if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
+	     ( ( ( ( uint64_t ) send_wqe_base_adr ) >> 32 ) !=
+	       ( ( ( uint64_t ) recv_wqe_base_adr ) >> 32 ) ) ) {
+		DBGC ( arbel, "Arbel %p QPN %#lx cannot support send %08lx "
+		       "recv %08lx\n", arbel, qp->qpn,
+		       send_wqe_base_adr, recv_wqe_base_adr );
+		rc = -ENOTSUP;
+		goto err_unsupported_address_split;
+	}
+	wqe_base_adr = send_wqe_base_adr;
+
+	/* Initialise doorbell records */
+	send_db_rec = &arbel->db_rec[arbel_qp->send.doorbell_idx].qp;
+	MLX_FILL_1 ( send_db_rec, 0, counter, 0 );
+	MLX_FILL_2 ( send_db_rec, 1,
+		     res, ARBEL_UAR_RES_SQ,
+		     qp_number, qp->qpn );
+	recv_db_rec = &arbel->db_rec[arbel_qp->recv.doorbell_idx].qp;
+	MLX_FILL_1 ( recv_db_rec, 0, counter, 0 );
+	MLX_FILL_2 ( recv_db_rec, 1,
+		     res, ARBEL_UAR_RES_RQ,
+		     qp_number, qp->qpn );
+
+	/* Transition queue to INIT state */
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	MLX_FILL_3 ( &qpctx, 2,
+		     qpc_eec_data.de, 1,
+		     qpc_eec_data.pm_state, ARBEL_PM_STATE_MIGRATED,
+		     qpc_eec_data.st, arbel_qp_st[qp->type] );
+	MLX_FILL_4 ( &qpctx, 4,
+		     qpc_eec_data.log_rq_size, fls ( qp->recv.num_wqes - 1 ),
+		     qpc_eec_data.log_rq_stride,
+		     ( fls ( sizeof ( arbel_qp->recv.wqe[0] ) - 1 ) - 4 ),
+		     qpc_eec_data.log_sq_size, fls ( qp->send.num_wqes - 1 ),
+		     qpc_eec_data.log_sq_stride,
+		     ( fls ( sizeof ( arbel_qp->send.wqe[0] ) - 1 ) - 4 ) );
+	MLX_FILL_1 ( &qpctx, 5,
+		     qpc_eec_data.usr_page, arbel->limits.reserved_uars );
+	MLX_FILL_1 ( &qpctx, 10, qpc_eec_data.primary_address_path.port_number,
+		     ibdev->port );
+	MLX_FILL_1 ( &qpctx, 27, qpc_eec_data.pd, ARBEL_GLOBAL_PD );
+	MLX_FILL_H ( &qpctx, 28, qpc_eec_data.wqe_base_adr_h, wqe_base_adr );
+	MLX_FILL_1 ( &qpctx, 29, qpc_eec_data.wqe_lkey, arbel->lkey );
+	MLX_FILL_1 ( &qpctx, 30, qpc_eec_data.ssc, 1 );
+	MLX_FILL_1 ( &qpctx, 33, qpc_eec_data.cqn_snd, qp->send.cq->cqn );
+	MLX_FILL_1 ( &qpctx, 34, qpc_eec_data.snd_wqe_base_adr_l,
+		     ( send_wqe_base_adr >> 6 ) );
+	MLX_FILL_1 ( &qpctx, 35, qpc_eec_data.snd_db_record_index,
+		     arbel_qp->send.doorbell_idx );
+	MLX_FILL_1 ( &qpctx, 38, qpc_eec_data.rsc, 1 );
+	MLX_FILL_1 ( &qpctx, 41, qpc_eec_data.cqn_rcv, qp->recv.cq->cqn );
+	MLX_FILL_1 ( &qpctx, 42, qpc_eec_data.rcv_wqe_base_adr_l,
+		     ( recv_wqe_base_adr >> 6 ) );
+	MLX_FILL_1 ( &qpctx, 43, qpc_eec_data.rcv_db_record_index,
+		     arbel_qp->recv.doorbell_idx );
+	if ( ( rc = arbel_cmd_rst2init_qpee ( arbel, qp->qpn, &qpctx )) != 0 ){
+		DBGC ( arbel, "Arbel %p QPN %#lx RST2INIT_QPEE failed: %s\n",
+		       arbel, qp->qpn, strerror ( rc ) );
+		goto err_rst2init_qpee;
+	}
+	arbel_qp->state = ARBEL_QP_ST_INIT;
+
+	DBGC ( arbel, "Arbel %p QPN %#lx send ring [%08lx,%08lx), doorbell "
+	       "%08lx\n", arbel, qp->qpn, virt_to_phys ( arbel_qp->send.wqe ),
+	       ( virt_to_phys ( arbel_qp->send.wqe ) +
+		 arbel_qp->send.wqe_size ),
+	       virt_to_phys ( send_db_rec ) );
+	DBGC ( arbel, "Arbel %p QPN %#lx receive ring [%08lx,%08lx), doorbell "
+	       "%08lx\n", arbel, qp->qpn, virt_to_phys ( arbel_qp->recv.wqe ),
+	       ( virt_to_phys ( arbel_qp->recv.wqe ) +
+		 arbel_qp->recv.wqe_size ),
+	       virt_to_phys ( recv_db_rec ) );
+	DBGC ( arbel, "Arbel %p QPN %#lx send CQN %#lx receive CQN %#lx\n",
+	       arbel, qp->qpn, qp->send.cq->cqn, qp->recv.cq->cqn );
+	ib_qp_set_drvdata ( qp, arbel_qp );
+	return 0;
+
+	arbel_cmd_2rst_qpee ( arbel, qp->qpn );
+ err_rst2init_qpee:
+	MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+	MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+ err_unsupported_address_split:
+	free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size );
+ err_create_recv_wq:
+	free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size );
+ err_create_send_wq:
+	free ( arbel_qp );
+ err_arbel_qp:
+	arbel_free_qpn ( ibdev, qp );
+ err_alloc_qpn:
+	return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int arbel_modify_qp ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp );
+	struct arbelprm_qp_ee_state_transitions qpctx;
+	int rc;
+
+	/* Transition queue to RTR state, if applicable */
+	if ( arbel_qp->state < ARBEL_QP_ST_RTR ) {
+		memset ( &qpctx, 0, sizeof ( qpctx ) );
+		MLX_FILL_2 ( &qpctx, 4,
+			     qpc_eec_data.mtu, ARBEL_MTU_2048,
+			     qpc_eec_data.msg_max, 11 /* 2^11 = 2048 */ );
+		if ( ( rc = arbel_cmd_init2rtr_qpee ( arbel, qp->qpn,
+						      &qpctx ) ) != 0 ) {
+			DBGC ( arbel, "Arbel %p QPN %#lx INIT2RTR_QPEE failed:"
+			       " %s\n", arbel, qp->qpn, strerror ( rc ) );
+			return rc;
+		}
+		arbel_qp->state = ARBEL_QP_ST_RTR;
+	}
+
+	/* Transition queue to RTS state, if applicable */
+	if ( arbel_qp->state < ARBEL_QP_ST_RTS ) {
+		memset ( &qpctx, 0, sizeof ( qpctx ) );
+		MLX_FILL_1 ( &qpctx, 32,
+			     qpc_eec_data.next_send_psn, qp->send.psn );
+		if ( ( rc = arbel_cmd_rtr2rts_qpee ( arbel, qp->qpn,
+						     &qpctx ) ) != 0 ) {
+			DBGC ( arbel, "Arbel %p QPN %#lx RTR2RTS_QPEE failed: "
+			       "%s\n", arbel, qp->qpn, strerror ( rc ) );
+			return rc;
+		}
+		arbel_qp->state = ARBEL_QP_ST_RTS;
+	}
+
+	/* Update parameters in RTS state */
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	MLX_FILL_1 ( &qpctx, 0, opt_param_mask, ARBEL_QPEE_OPT_PARAM_QKEY );
+	MLX_FILL_1 ( &qpctx, 44, qpc_eec_data.q_key, qp->qkey );
+	if ( ( rc = arbel_cmd_rts2rts_qpee ( arbel, qp->qpn, &qpctx ) ) != 0 ){
+		DBGC ( arbel, "Arbel %p QPN %#lx RTS2RTS_QPEE failed: %s\n",
+		       arbel, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void arbel_destroy_qp ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp );
+	struct arbelprm_qp_db_record *send_db_rec;
+	struct arbelprm_qp_db_record *recv_db_rec;
+	int rc;
+
+	/* Take ownership back from hardware */
+	if ( ( rc = arbel_cmd_2rst_qpee ( arbel, qp->qpn ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p QPN %#lx FATAL 2RST_QPEE failed: "
+		       "%s\n", arbel, qp->qpn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Clear doorbell records */
+	send_db_rec = &arbel->db_rec[arbel_qp->send.doorbell_idx].qp;
+	recv_db_rec = &arbel->db_rec[arbel_qp->recv.doorbell_idx].qp;
+	MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+	MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE );
+
+	/* Free memory */
+	free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size );
+	free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size );
+	free ( arbel_qp );
+
+	/* Mark queue number as free */
+	arbel_free_qpn ( ibdev, qp );
+
+	ib_qp_set_drvdata ( qp, NULL );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Ring doorbell register in UAR
+ *
+ * @v arbel		Arbel device
+ * @v db_reg		Doorbell register structure
+ * @v offset		Address of doorbell
+ */
+static void arbel_ring_doorbell ( struct arbel *arbel,
+				  union arbelprm_doorbell_register *db_reg,
+				  unsigned int offset ) {
+
+	DBGC2 ( arbel, "Arbel %p ringing doorbell %08x:%08x at %lx\n",
+		arbel, ntohl ( db_reg->dword[0] ), ntohl ( db_reg->dword[1] ),
+		virt_to_phys ( arbel->uar + offset ) );
+
+	barrier();
+	writel ( db_reg->dword[0], ( arbel->uar + offset + 0 ) );
+	barrier();
+	writel ( db_reg->dword[1], ( arbel->uar + offset + 4 ) );
+}
+
+/** GID used for GID-less send work queue entries */
+static const union ib_gid arbel_no_gid = {
+	.bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
+};
+
+/**
+ * Construct UD send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret nds		Work queue entry size
+ */
+static size_t arbel_fill_ud_send_wqe ( struct ib_device *ibdev,
+				       struct ib_queue_pair *qp __unused,
+				       struct ib_address_vector *av,
+				       struct io_buffer *iobuf,
+				       union arbel_send_wqe *wqe ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	const union ib_gid *gid;
+
+	/* Construct this work queue entry */
+	MLX_FILL_1 ( &wqe->ud.ctrl, 0, always1, 1 );
+	MLX_FILL_2 ( &wqe->ud.ud, 0,
+		     ud_address_vector.pd, ARBEL_GLOBAL_PD,
+		     ud_address_vector.port_number, ibdev->port );
+	MLX_FILL_2 ( &wqe->ud.ud, 1,
+		     ud_address_vector.rlid, av->lid,
+		     ud_address_vector.g, av->gid_present );
+	MLX_FILL_2 ( &wqe->ud.ud, 2,
+		     ud_address_vector.max_stat_rate, arbel_rate ( av ),
+		     ud_address_vector.msg, 3 );
+	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, av->sl );
+	gid = ( av->gid_present ? &av->gid : &arbel_no_gid );
+	memcpy ( &wqe->ud.ud.u.dwords[4], gid, sizeof ( *gid ) );
+	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, av->qpn );
+	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, av->qkey );
+	MLX_FILL_1 ( &wqe->ud.data[0], 0, byte_count, iob_len ( iobuf ) );
+	MLX_FILL_1 ( &wqe->ud.data[0], 1, l_key, arbel->lkey );
+	MLX_FILL_H ( &wqe->ud.data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->ud.data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+
+	return ( offsetof ( typeof ( wqe->ud ), data[1] ) >> 4 );
+}
+
+/**
+ * Construct MLX send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @v next		Previous work queue entry's "next" field
+ * @ret nds		Work queue entry size
+ */
+static size_t arbel_fill_mlx_send_wqe ( struct ib_device *ibdev,
+					struct ib_queue_pair *qp,
+					struct ib_address_vector *av,
+					struct io_buffer *iobuf,
+					union arbel_send_wqe *wqe ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct io_buffer headers;
+
+	/* Construct IB headers */
+	iob_populate ( &headers, &wqe->mlx.headers, 0,
+		       sizeof ( wqe->mlx.headers ) );
+	iob_reserve ( &headers, sizeof ( wqe->mlx.headers ) );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+	/* Construct this work queue entry */
+	MLX_FILL_5 ( &wqe->mlx.ctrl, 0,
+		     c, 1 /* generate completion */,
+		     icrc, 0 /* generate ICRC */,
+		     max_statrate, arbel_rate ( av ),
+		     slr, 0,
+		     v15, ( ( qp->ext_qpn == IB_QPN_SMI ) ? 1 : 0 ) );
+	MLX_FILL_1 ( &wqe->mlx.ctrl, 1, rlid, av->lid );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 0,
+		     byte_count, iob_len ( &headers ) );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 1, l_key, arbel->lkey );
+	MLX_FILL_H ( &wqe->mlx.data[0], 2,
+		     local_address_h, virt_to_bus ( headers.data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 3,
+		     local_address_l, virt_to_bus ( headers.data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 0,
+		     byte_count, ( iob_len ( iobuf ) + 4 /* ICRC */ ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 1, l_key, arbel->lkey );
+	MLX_FILL_H ( &wqe->mlx.data[1], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+
+	return ( offsetof ( typeof ( wqe->mlx ), data[2] ) >> 4 );
+}
+
+/** Work queue entry constructors */
+static size_t
+( * arbel_fill_send_wqe[] ) ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct ib_address_vector *av,
+			      struct io_buffer *iobuf,
+			      union arbel_send_wqe *wqe ) = {
+	[IB_QPT_SMI] = arbel_fill_mlx_send_wqe,
+	[IB_QPT_GSI] = arbel_fill_mlx_send_wqe,
+	[IB_QPT_UD] = arbel_fill_ud_send_wqe,
+};
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int arbel_post_send ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp,
+			     struct ib_address_vector *av,
+			     struct io_buffer *iobuf ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp );
+	struct ib_work_queue *wq = &qp->send;
+	struct arbel_send_work_queue *arbel_send_wq = &arbel_qp->send;
+	union arbel_send_wqe *prev_wqe;
+	union arbel_send_wqe *wqe;
+	struct arbelprm_qp_db_record *qp_db_rec;
+	union arbelprm_doorbell_register db_reg;
+	unsigned long wqe_idx_mask;
+	size_t nds;
+
+	/* Allocate work queue entry */
+	wqe_idx_mask = ( wq->num_wqes - 1 );
+	if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
+		DBGC ( arbel, "Arbel %p QPN %#lx send queue full",
+		       arbel, qp->qpn );
+		return -ENOBUFS;
+	}
+	wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
+	prev_wqe = &arbel_send_wq->wqe[(wq->next_idx - 1) & wqe_idx_mask];
+	wqe = &arbel_send_wq->wqe[wq->next_idx & wqe_idx_mask];
+
+	/* Construct work queue entry */
+	memset ( ( ( ( void * ) wqe ) + sizeof ( wqe->next ) ), 0,
+		 ( sizeof ( *wqe ) - sizeof ( wqe->next ) ) );
+	assert ( qp->type < ( sizeof ( arbel_fill_send_wqe ) /
+			      sizeof ( arbel_fill_send_wqe[0] ) ) );
+	assert ( arbel_fill_send_wqe[qp->type] != NULL );
+	nds = arbel_fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf, wqe );
+	DBGCP ( arbel, "Arbel %p QPN %#lx posting send WQE %#lx:\n",
+		arbel, qp->qpn, ( wq->next_idx & wqe_idx_mask ) );
+	DBGCP_HDA ( arbel, virt_to_phys ( wqe ), wqe, sizeof ( *wqe ) );
+
+	/* Update previous work queue entry's "next" field */
+	MLX_SET ( &prev_wqe->next, nopcode, ARBEL_OPCODE_SEND );
+	MLX_FILL_3 ( &prev_wqe->next, 1,
+		     nds, nds,
+		     f, 0,
+		     always1, 1 );
+
+	/* Update doorbell record */
+	barrier();
+	qp_db_rec = &arbel->db_rec[arbel_send_wq->doorbell_idx].qp;
+	MLX_FILL_1 ( qp_db_rec, 0,
+		     counter, ( ( wq->next_idx + 1 ) & 0xffff ) );
+
+	/* Ring doorbell register */
+	MLX_FILL_4 ( &db_reg.send, 0,
+		     nopcode, ARBEL_OPCODE_SEND,
+		     f, 0,
+		     wqe_counter, ( wq->next_idx & 0xffff ),
+		     wqe_cnt, 1 );
+	MLX_FILL_2 ( &db_reg.send, 1,
+		     nds, nds,
+		     qpn, qp->qpn );
+	arbel_ring_doorbell ( arbel, &db_reg, ARBEL_DB_POST_SND_OFFSET );
+
+	/* Update work queue's index */
+	wq->next_idx++;
+
+	return 0;
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int arbel_post_recv ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp,
+			     struct io_buffer *iobuf ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp );
+	struct ib_work_queue *wq = &qp->recv;
+	struct arbel_recv_work_queue *arbel_recv_wq = &arbel_qp->recv;
+	struct arbelprm_recv_wqe *wqe;
+	union arbelprm_doorbell_record *db_rec;
+	unsigned int wqe_idx_mask;
+
+	/* Allocate work queue entry */
+	wqe_idx_mask = ( wq->num_wqes - 1 );
+	if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
+		DBGC ( arbel, "Arbel %p QPN %#lx receive queue full\n",
+		       arbel, qp->qpn );
+		return -ENOBUFS;
+	}
+	wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
+	wqe = &arbel_recv_wq->wqe[wq->next_idx & wqe_idx_mask].recv;
+
+	/* Construct work queue entry */
+	MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
+	MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->lkey );
+	MLX_FILL_H ( &wqe->data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+
+	/* Update doorbell record */
+	barrier();
+	db_rec = &arbel->db_rec[arbel_recv_wq->doorbell_idx];
+	MLX_FILL_1 ( &db_rec->qp, 0,
+		     counter, ( ( wq->next_idx + 1 ) & 0xffff ) );	
+
+	/* Update work queue's index */
+	wq->next_idx++;
+
+	return 0;	
+}
+
+/**
+ * Handle completion
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @v cqe		Hardware completion queue entry
+ * @ret rc		Return status code
+ */
+static int arbel_complete ( struct ib_device *ibdev,
+			    struct ib_completion_queue *cq,
+			    union arbelprm_completion_entry *cqe ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq;
+	struct ib_queue_pair *qp;
+	struct arbel_queue_pair *arbel_qp;
+	struct arbel_send_work_queue *arbel_send_wq;
+	struct arbel_recv_work_queue *arbel_recv_wq;
+	struct arbelprm_recv_wqe *recv_wqe;
+	struct io_buffer *iobuf;
+	struct ib_address_vector recv_av;
+	struct ib_global_route_header *grh;
+	struct ib_address_vector *av;
+	unsigned int opcode;
+	unsigned long qpn;
+	int is_send;
+	unsigned long wqe_adr;
+	unsigned long wqe_idx;
+	size_t len;
+	int rc = 0;
+
+	/* Parse completion */
+	qpn = MLX_GET ( &cqe->normal, my_qpn );
+	is_send = MLX_GET ( &cqe->normal, s );
+	wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 );
+	opcode = MLX_GET ( &cqe->normal, opcode );
+	if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) {
+		/* "s" field is not valid for error opcodes */
+		is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR );
+		DBGC ( arbel, "Arbel %p CQN %#lx %s QPN %#lx syndrome %#x "
+		       "vendor %#x\n", arbel, cq->cqn,
+		       ( is_send ? "send" : "recv" ), qpn,
+		       MLX_GET ( &cqe->error, syndrome ),
+		       MLX_GET ( &cqe->error, vendor_code ) );
+		DBGC_HDA ( arbel, virt_to_phys ( cqe ), cqe, sizeof ( *cqe ) );
+		rc = -EIO;
+		/* Don't return immediately; propagate error to completer */
+	}
+
+	/* Identify work queue */
+	wq = ib_find_wq ( cq, qpn, is_send );
+	if ( ! wq ) {
+		DBGC ( arbel, "Arbel %p CQN %#lx unknown %s QPN %#lx\n",
+		       arbel, cq->cqn, ( is_send ? "send" : "recv" ), qpn );
+		return -EIO;
+	}
+	qp = wq->qp;
+	arbel_qp = ib_qp_get_drvdata ( qp );
+	arbel_send_wq = &arbel_qp->send;
+	arbel_recv_wq = &arbel_qp->recv;
+
+	/* Identify work queue entry index */
+	if ( is_send ) {
+		wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_send_wq->wqe ) ) /
+			    sizeof ( arbel_send_wq->wqe[0] ) );
+		assert ( wqe_idx < qp->send.num_wqes );
+	} else {
+		wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_recv_wq->wqe ) ) /
+			    sizeof ( arbel_recv_wq->wqe[0] ) );
+		assert ( wqe_idx < qp->recv.num_wqes );
+	}
+	DBGCP ( arbel, "Arbel %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n",
+		arbel, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ),
+		wqe_idx );
+	DBGCP_HDA ( arbel, virt_to_phys ( cqe ), cqe, sizeof ( *cqe ) );
+
+	/* Identify I/O buffer */
+	iobuf = wq->iobufs[wqe_idx];
+	if ( ! iobuf ) {
+		DBGC ( arbel, "Arbel %p CQN %#lx QPN %#lx empty %s WQE %#lx\n",
+		       arbel, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ),
+		       wqe_idx );
+		return -EIO;
+	}
+	wq->iobufs[wqe_idx] = NULL;
+
+	if ( is_send ) {
+		/* Hand off to completion handler */
+		ib_complete_send ( ibdev, qp, iobuf, rc );
+	} else {
+		/* Set received length */
+		len = MLX_GET ( &cqe->normal, byte_cnt );
+		recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv;
+		assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) ==
+			 virt_to_bus ( iobuf->data ) );
+		assert ( MLX_GET ( &recv_wqe->data[0], byte_count ) ==
+			 iob_tailroom ( iobuf ) );
+		MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 );
+		MLX_FILL_1 ( &recv_wqe->data[0], 1,
+			     l_key, ARBEL_INVALID_LKEY );
+		assert ( len <= iob_tailroom ( iobuf ) );
+		iob_put ( iobuf, len );
+		switch ( qp->type ) {
+		case IB_QPT_SMI:
+		case IB_QPT_GSI:
+		case IB_QPT_UD:
+			assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+			grh = iobuf->data;
+			iob_pull ( iobuf, sizeof ( *grh ) );
+			/* Construct address vector */
+			av = &recv_av;
+			memset ( av, 0, sizeof ( *av ) );
+			av->qpn = MLX_GET ( &cqe->normal, rqpn );
+			av->lid = MLX_GET ( &cqe->normal, rlid );
+			av->sl = MLX_GET ( &cqe->normal, sl );
+			av->gid_present = MLX_GET ( &cqe->normal, g );
+			memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+			break;
+		default:
+			assert ( 0 );
+			return -EINVAL;
+		}
+		/* Hand off to completion handler */
+		ib_complete_recv ( ibdev, qp, av, iobuf, rc );
+	}
+
+	return rc;
+}			     
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void arbel_poll_cq ( struct ib_device *ibdev,
+			    struct ib_completion_queue *cq ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq );
+	struct arbelprm_cq_ci_db_record *ci_db_rec;
+	union arbelprm_completion_entry *cqe;
+	unsigned int cqe_idx_mask;
+	int rc;
+
+	while ( 1 ) {
+		/* Look for completion entry */
+		cqe_idx_mask = ( cq->num_cqes - 1 );
+		cqe = &arbel_cq->cqe[cq->next_idx & cqe_idx_mask];
+		if ( MLX_GET ( &cqe->normal, owner ) != 0 ) {
+			/* Entry still owned by hardware; end of poll */
+			break;
+		}
+
+		/* Handle completion */
+		if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) {
+			DBGC ( arbel, "Arbel %p CQN %#lx failed to complete: "
+			       "%s\n", arbel, cq->cqn, strerror ( rc ) );
+			DBGC_HD ( arbel, cqe, sizeof ( *cqe ) );
+		}
+
+		/* Return ownership to hardware */
+		MLX_FILL_1 ( &cqe->normal, 7, owner, 1 );
+		barrier();
+		/* Update completion queue's index */
+		cq->next_idx++;
+		/* Update doorbell record */
+		ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci;
+		MLX_FILL_1 ( ci_db_rec, 0,
+			     counter, ( cq->next_idx & 0xffffffffUL ) );
+	}
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create event queue
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_create_eq ( struct arbel *arbel ) {
+	struct arbel_event_queue *arbel_eq = &arbel->eq;
+	struct arbelprm_eqc eqctx;
+	struct arbelprm_event_mask mask;
+	unsigned int i;
+	int rc;
+
+	/* Select event queue number */
+	arbel_eq->eqn = arbel->limits.reserved_eqs;
+
+	/* Calculate doorbell address */
+	arbel_eq->doorbell = ( arbel->eq_ci_doorbells +
+			       ARBEL_DB_EQ_OFFSET ( arbel_eq->eqn ) );
+
+	/* Allocate event queue itself */
+	arbel_eq->eqe_size =
+		( ARBEL_NUM_EQES * sizeof ( arbel_eq->eqe[0] ) );
+	arbel_eq->eqe = malloc_dma ( arbel_eq->eqe_size,
+				     sizeof ( arbel_eq->eqe[0] ) );
+	if ( ! arbel_eq->eqe ) {
+		rc = -ENOMEM;
+		goto err_eqe;
+	}
+	memset ( arbel_eq->eqe, 0, arbel_eq->eqe_size );
+	for ( i = 0 ; i < ARBEL_NUM_EQES ; i++ ) {
+		MLX_FILL_1 ( &arbel_eq->eqe[i].generic, 7, owner, 1 );
+	}
+	barrier();
+
+	/* Hand queue over to hardware */
+	memset ( &eqctx, 0, sizeof ( eqctx ) );
+	MLX_FILL_1 ( &eqctx, 0, st, 0xa /* "Fired" */ );
+	MLX_FILL_H ( &eqctx, 1,
+		     start_address_h, virt_to_phys ( arbel_eq->eqe ) );
+	MLX_FILL_1 ( &eqctx, 2,
+		     start_address_l, virt_to_phys ( arbel_eq->eqe ) );
+	MLX_FILL_1 ( &eqctx, 3, log_eq_size, fls ( ARBEL_NUM_EQES - 1 ) );
+	MLX_FILL_1 ( &eqctx, 6, pd, ARBEL_GLOBAL_PD );
+	MLX_FILL_1 ( &eqctx, 7, lkey, arbel->lkey );
+	if ( ( rc = arbel_cmd_sw2hw_eq ( arbel, arbel_eq->eqn,
+					 &eqctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p EQN %#lx SW2HW_EQ failed: %s\n",
+		       arbel, arbel_eq->eqn, strerror ( rc ) );
+		goto err_sw2hw_eq;
+	}
+
+	/* Map events to this event queue */
+	memset ( &mask, 0xff, sizeof ( mask ) );
+	if ( ( rc = arbel_cmd_map_eq ( arbel,
+				       ( ARBEL_MAP_EQ | arbel_eq->eqn ),
+				       &mask ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p EQN %#lx MAP_EQ failed: %s\n",
+		       arbel, arbel_eq->eqn, strerror ( rc )  );
+		goto err_map_eq;
+	}
+
+	DBGC ( arbel, "Arbel %p EQN %#lx ring [%08lx,%08lx), doorbell %08lx\n",
+	       arbel, arbel_eq->eqn, virt_to_phys ( arbel_eq->eqe ),
+	       ( virt_to_phys ( arbel_eq->eqe ) + arbel_eq->eqe_size ),
+	       virt_to_phys ( arbel_eq->doorbell ) );
+	return 0;
+
+ err_map_eq:
+	arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, &eqctx );
+ err_sw2hw_eq:
+	free_dma ( arbel_eq->eqe, arbel_eq->eqe_size );
+ err_eqe:
+	memset ( arbel_eq, 0, sizeof ( *arbel_eq ) );
+	return rc;
+}
+
+/**
+ * Destroy event queue
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_destroy_eq ( struct arbel *arbel ) {
+	struct arbel_event_queue *arbel_eq = &arbel->eq;
+	struct arbelprm_eqc eqctx;
+	struct arbelprm_event_mask mask;
+	int rc;
+
+	/* Unmap events from event queue */
+	memset ( &mask, 0, sizeof ( mask ) );
+	MLX_FILL_1 ( &mask, 1, port_state_change, 1 );
+	if ( ( rc = arbel_cmd_map_eq ( arbel,
+				       ( ARBEL_UNMAP_EQ | arbel_eq->eqn ),
+				       &mask ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p EQN %#lx FATAL MAP_EQ failed to "
+		       "unmap: %s\n", arbel, arbel_eq->eqn, strerror ( rc ) );
+		/* Continue; HCA may die but system should survive */
+	}
+
+	/* Take ownership back from hardware */
+	if ( ( rc = arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn,
+					 &eqctx ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p EQN %#lx FATAL HW2SW_EQ failed: %s\n",
+		       arbel, arbel_eq->eqn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Free memory */
+	free_dma ( arbel_eq->eqe, arbel_eq->eqe_size );
+	memset ( arbel_eq, 0, sizeof ( *arbel_eq ) );
+}
+
+/**
+ * Handle port state event
+ *
+ * @v arbel		Arbel device
+ * @v eqe		Port state change event queue entry
+ */
+static void arbel_event_port_state_change ( struct arbel *arbel,
+					    union arbelprm_event_entry *eqe){
+	unsigned int port;
+	int link_up;
+
+	/* Get port and link status */
+	port = ( MLX_GET ( &eqe->port_state_change, data.p ) - 1 );
+	link_up = ( MLX_GET ( &eqe->generic, event_sub_type ) & 0x04 );
+	DBGC ( arbel, "Arbel %p port %d link %s\n", arbel, ( port + 1 ),
+	       ( link_up ? "up" : "down" ) );
+
+	/* Sanity check */
+	if ( port >= ARBEL_NUM_PORTS ) {
+		DBGC ( arbel, "Arbel %p port %d does not exist!\n",
+		       arbel, ( port + 1 ) );
+		return;
+	}
+
+	/* Update MAD parameters */
+	ib_smc_update ( arbel->ibdev[port], arbel_mad );
+}
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev		Infiniband device
+ */
+static void arbel_poll_eq ( struct ib_device *ibdev ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbel_event_queue *arbel_eq = &arbel->eq;
+	union arbelprm_event_entry *eqe;
+	union arbelprm_eq_doorbell_register db_reg;
+	unsigned int eqe_idx_mask;
+	unsigned int event_type;
+
+	/* No event is generated upon reaching INIT, so we must poll
+	 * separately for link state changes while we remain DOWN.
+	 */
+	if ( ib_is_open ( ibdev ) &&
+	     ( ibdev->port_state == IB_PORT_STATE_DOWN ) ) {
+		ib_smc_update ( ibdev, arbel_mad );
+	}
+
+	/* Poll event queue */
+	while ( 1 ) {
+		/* Look for event entry */
+		eqe_idx_mask = ( ARBEL_NUM_EQES - 1 );
+		eqe = &arbel_eq->eqe[arbel_eq->next_idx & eqe_idx_mask];
+		if ( MLX_GET ( &eqe->generic, owner ) != 0 ) {
+			/* Entry still owned by hardware; end of poll */
+			break;
+		}
+		DBGCP ( arbel, "Arbel %p EQN %#lx event:\n",
+			arbel, arbel_eq->eqn );
+		DBGCP_HDA ( arbel, virt_to_phys ( eqe ),
+			    eqe, sizeof ( *eqe ) );
+
+		/* Handle event */
+		event_type = MLX_GET ( &eqe->generic, event_type );
+		switch ( event_type ) {
+		case ARBEL_EV_PORT_STATE_CHANGE:
+			arbel_event_port_state_change ( arbel, eqe );
+			break;
+		default:
+			DBGC ( arbel, "Arbel %p EQN %#lx unrecognised event "
+			       "type %#x:\n",
+			       arbel, arbel_eq->eqn, event_type );
+			DBGC_HDA ( arbel, virt_to_phys ( eqe ),
+				   eqe, sizeof ( *eqe ) );
+			break;
+		}
+
+		/* Return ownership to hardware */
+		MLX_FILL_1 ( &eqe->generic, 7, owner, 1 );
+		barrier();
+
+		/* Update event queue's index */
+		arbel_eq->next_idx++;
+
+		/* Ring doorbell */
+		MLX_FILL_1 ( &db_reg.ci, 0, ci, arbel_eq->next_idx );
+		writel ( db_reg.dword[0], arbel_eq->doorbell );
+	}
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int arbel_open ( struct ib_device *ibdev ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_init_ib init_ib;
+	int rc;
+
+	memset ( &init_ib, 0, sizeof ( init_ib ) );
+	MLX_FILL_3 ( &init_ib, 0,
+		     mtu_cap, ARBEL_MTU_2048,
+		     port_width_cap, 3,
+		     vl_cap, 1 );
+	MLX_FILL_1 ( &init_ib, 1, max_gid, 1 );
+	MLX_FILL_1 ( &init_ib, 2, max_pkey, 64 );
+	if ( ( rc = arbel_cmd_init_ib ( arbel, ibdev->port,
+					&init_ib ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n",
+		       arbel, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, arbel_mad );
+
+	return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ */
+static void arbel_close ( struct ib_device *ibdev ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	int rc;
+
+	if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n",
+		       arbel, ibdev->port, strerror ( rc ) );
+		/* Nothing we can do about this */
+	}
+}
+
+/**
+ * Inform embedded subnet management agent of a received MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		MAD
+ * @ret rc		Return status code
+ */
+static int arbel_inform_sma ( struct ib_device *ibdev, union ib_mad *mad ) {
+	int rc;
+
+	/* Send the MAD to the embedded SMA */
+	if ( ( rc = arbel_mad ( ibdev, mad ) ) != 0 )
+		return rc;
+
+	/* Update parameters held in software */
+	ib_smc_update ( ibdev, arbel_mad );
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ * @ret rc		Return status code
+ */
+static int arbel_mcast_attach ( struct ib_device *ibdev,
+				struct ib_queue_pair *qp,
+				union ib_gid *gid ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_mgm_hash hash;
+	struct arbelprm_mgm_entry mgm;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Check for existing hash table entry */
+	if ( ( rc = arbel_cmd_read_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not read MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return rc;
+	}
+	if ( MLX_GET ( &mgm, mgmqp_0.qi ) != 0 ) {
+		/* FIXME: this implementation allows only a single QP
+		 * per multicast group, and doesn't handle hash
+		 * collisions.  Sufficient for IPoIB but may need to
+		 * be extended in future.
+		 */
+		DBGC ( arbel, "Arbel %p MGID index %#x already in use\n",
+		       arbel, index );
+		return -EBUSY;
+	}
+
+	/* Update hash table entry */
+	MLX_FILL_2 ( &mgm, 8,
+		     mgmqp_0.qpn_i, qp->qpn,
+		     mgmqp_0.qi, 1 );
+	memcpy ( &mgm.u.dwords[4], gid, sizeof ( *gid ) );
+	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void arbel_mcast_detach ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp __unused,
+				 union ib_gid *gid ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_mgm_hash hash;
+	struct arbelprm_mgm_entry mgm;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
+		       arbel, strerror ( rc ) );
+		return;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Clear hash table entry */
+	memset ( &mgm, 0, sizeof ( mgm ) );
+	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return;
+	}
+}
+
+/** Arbel Infiniband operations */
+static struct ib_device_operations arbel_ib_operations = {
+	.create_cq	= arbel_create_cq,
+	.destroy_cq	= arbel_destroy_cq,
+	.create_qp	= arbel_create_qp,
+	.modify_qp	= arbel_modify_qp,
+	.destroy_qp	= arbel_destroy_qp,
+	.post_send	= arbel_post_send,
+	.post_recv	= arbel_post_recv,
+	.poll_cq	= arbel_poll_cq,
+	.poll_eq	= arbel_poll_eq,
+	.open		= arbel_open,
+	.close		= arbel_close,
+	.mcast_attach	= arbel_mcast_attach,
+	.mcast_detach	= arbel_mcast_detach,
+	.set_port_info	= arbel_inform_sma,
+	.set_pkey_table	= arbel_inform_sma,
+};
+
+/***************************************************************************
+ *
+ * Firmware control
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Map virtual to physical address for firmware usage
+ *
+ * @v arbel		Arbel device
+ * @v map		Mapping function
+ * @v va		Virtual address
+ * @v pa		Physical address
+ * @v len		Length of region
+ * @ret rc		Return status code
+ */
+static int arbel_map_vpm ( struct arbel *arbel,
+			   int ( *map ) ( struct arbel *arbel,
+			     const struct arbelprm_virtual_physical_mapping* ),
+			   uint64_t va, physaddr_t pa, size_t len ) {
+	struct arbelprm_virtual_physical_mapping mapping;
+	physaddr_t start;
+	physaddr_t low;
+	physaddr_t high;
+	physaddr_t end;
+	size_t size;
+	int rc;
+
+	/* Sanity checks */
+	assert ( ( va & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( pa & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( len & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 );
+
+	/* Calculate starting points */
+	start = pa;
+	end = ( start + len );
+	size = ( 1UL << ( fls ( start ^ end ) - 1 ) );
+	low = high = ( end & ~( size - 1 ) );
+	assert ( start < low );
+	assert ( high <= end );
+
+	/* These mappings tend to generate huge volumes of
+	 * uninteresting debug data, which basically makes it
+	 * impossible to use debugging otherwise.
+	 */
+	DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+
+	/* Map blocks in descending order of size */
+	while ( size >= ARBEL_PAGE_SIZE ) {
+
+		/* Find the next candidate block */
+		if ( ( low - size ) >= start ) {
+			low -= size;
+			pa = low;
+		} else if ( ( high + size ) <= end ) {
+			pa = high;
+			high += size;
+		} else {
+			size >>= 1;
+			continue;
+		}
+		assert ( ( va & ( size - 1 ) ) == 0 );
+		assert ( ( pa & ( size - 1 ) ) == 0 );
+
+		/* Map this block */
+		memset ( &mapping, 0, sizeof ( mapping ) );
+		MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
+		MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
+		MLX_FILL_H ( &mapping, 2, pa_h, pa );
+		MLX_FILL_2 ( &mapping, 3,
+			     log2size, ( ( fls ( size ) - 1 ) - 12 ),
+			     pa_l, ( pa >> 12 ) );
+		if ( ( rc = map ( arbel, &mapping ) ) != 0 ) {
+			DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+			DBGC ( arbel, "Arbel %p could not map %08llx+%zx to "
+			       "%08lx: %s\n",
+			       arbel, va, size, pa, strerror ( rc ) );
+			return rc;
+		}
+		va += size;
+	}
+	assert ( low == start );
+	assert ( high == end );
+
+	DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+	return 0;
+}
+
+/**
+ * Start firmware running
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_start_firmware ( struct arbel *arbel ) {
+	struct arbelprm_query_fw fw;
+	struct arbelprm_access_lam lam;
+	unsigned int fw_pages;
+	size_t fw_size;
+	physaddr_t fw_base;
+	uint64_t eq_set_ci_base_addr;
+	int rc;
+
+	/* Get firmware parameters */
+	if ( ( rc = arbel_cmd_query_fw ( arbel, &fw ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not query firmware: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_query_fw;
+	}
+	DBGC ( arbel, "Arbel %p firmware version %d.%d.%d\n", arbel,
+	       MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
+	       MLX_GET ( &fw, fw_rev_subminor ) );
+	fw_pages = MLX_GET ( &fw, fw_pages );
+	DBGC ( arbel, "Arbel %p requires %d kB for firmware\n",
+	       arbel, ( fw_pages * 4 ) );
+	eq_set_ci_base_addr =
+		( ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_h ) << 32 ) |
+		  ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_l ) ) );
+	arbel->eq_ci_doorbells = ioremap ( eq_set_ci_base_addr, 0x200 );
+
+	/* Enable locally-attached memory.  Ignore failure; there may
+	 * be no attached memory.
+	 */
+	arbel_cmd_enable_lam ( arbel, &lam );
+
+	/* Allocate firmware pages and map firmware area */
+	fw_size = ( fw_pages * ARBEL_PAGE_SIZE );
+	arbel->firmware_area = umalloc ( fw_size );
+	if ( ! arbel->firmware_area ) {
+		rc = -ENOMEM;
+		goto err_alloc_fa;
+	}
+	fw_base = user_to_phys ( arbel->firmware_area, 0 );
+	DBGC ( arbel, "Arbel %p firmware area at [%08lx,%08lx)\n",
+	       arbel, fw_base, ( fw_base + fw_size ) );
+	if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_fa,
+				    0, fw_base, fw_size ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not map firmware: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_map_fa;
+	}
+
+	/* Start firmware */
+	if ( ( rc = arbel_cmd_run_fw ( arbel ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not run firmware: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_run_fw;
+	}
+
+	DBGC ( arbel, "Arbel %p firmware started\n", arbel );
+	return 0;
+
+ err_run_fw:
+	arbel_cmd_unmap_fa ( arbel );
+ err_map_fa:
+	ufree ( arbel->firmware_area );
+	arbel->firmware_area = UNULL;
+ err_alloc_fa:
+ err_query_fw:
+	return rc;
+}
+
+/**
+ * Stop firmware running
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_stop_firmware ( struct arbel *arbel ) {
+	int rc;
+
+	if ( ( rc = arbel_cmd_unmap_fa ( arbel ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n",
+		       arbel, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+	ufree ( arbel->firmware_area );
+	arbel->firmware_area = UNULL;
+}
+
+/***************************************************************************
+ *
+ * Infinihost Context Memory management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Get device limits
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_get_limits ( struct arbel *arbel ) {
+	struct arbelprm_query_dev_lim dev_lim;
+	int rc;
+
+	if ( ( rc = arbel_cmd_query_dev_lim ( arbel, &dev_lim ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not get device limits: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+
+	arbel->limits.reserved_qps =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_qps ) );
+	arbel->limits.qpc_entry_size = MLX_GET ( &dev_lim, qpc_entry_sz );
+	arbel->limits.eqpc_entry_size = MLX_GET ( &dev_lim, eqpc_entry_sz );
+	arbel->limits.reserved_srqs =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_srqs ) );
+	arbel->limits.srqc_entry_size = MLX_GET ( &dev_lim, srq_entry_sz );
+	arbel->limits.reserved_ees =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_ees ) );
+	arbel->limits.eec_entry_size = MLX_GET ( &dev_lim, eec_entry_sz );
+	arbel->limits.eeec_entry_size = MLX_GET ( &dev_lim, eeec_entry_sz );
+	arbel->limits.reserved_cqs =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_cqs ) );
+	arbel->limits.cqc_entry_size = MLX_GET ( &dev_lim, cqc_entry_sz );
+	arbel->limits.reserved_mtts =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_mtts ) );
+	arbel->limits.mtt_entry_size = MLX_GET ( &dev_lim, mtt_entry_sz );
+	arbel->limits.reserved_mrws =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_mrws ) );
+	arbel->limits.mpt_entry_size = MLX_GET ( &dev_lim, mpt_entry_sz );
+	arbel->limits.reserved_rdbs =
+		( 1 << MLX_GET ( &dev_lim, log2_rsvd_rdbs ) );
+	arbel->limits.reserved_eqs = MLX_GET ( &dev_lim, num_rsvd_eqs );
+	arbel->limits.eqc_entry_size = MLX_GET ( &dev_lim, eqc_entry_sz );
+	arbel->limits.reserved_uars = MLX_GET ( &dev_lim, num_rsvd_uars );
+	arbel->limits.uar_scratch_entry_size =
+		MLX_GET ( &dev_lim, uar_scratch_entry_sz );
+
+	DBGC ( arbel, "Arbel %p reserves %d x %#zx QPC, %d x %#zx EQPC, "
+	       "%d x %#zx SRQC\n", arbel,
+	       arbel->limits.reserved_qps, arbel->limits.qpc_entry_size,
+	       arbel->limits.reserved_qps, arbel->limits.eqpc_entry_size,
+	       arbel->limits.reserved_srqs, arbel->limits.srqc_entry_size );
+	DBGC ( arbel, "Arbel %p reserves %d x %#zx EEC, %d x %#zx EEEC, "
+	       "%d x %#zx CQC\n", arbel,
+	       arbel->limits.reserved_ees, arbel->limits.eec_entry_size,
+	       arbel->limits.reserved_ees, arbel->limits.eeec_entry_size,
+	       arbel->limits.reserved_cqs, arbel->limits.cqc_entry_size );
+	DBGC ( arbel, "Arbel %p reserves %d x %#zx EQC, %d x %#zx MTT, "
+	       "%d x %#zx MPT\n", arbel,
+	       arbel->limits.reserved_eqs, arbel->limits.eqc_entry_size,
+	       arbel->limits.reserved_mtts, arbel->limits.mtt_entry_size,
+	       arbel->limits.reserved_mrws, arbel->limits.mpt_entry_size );
+	DBGC ( arbel, "Arbel %p reserves %d x %#zx RDB, %d x %#zx UAR, "
+	       "%d x %#zx UAR scratchpad\n", arbel,
+	       arbel->limits.reserved_rdbs, ARBEL_RDB_ENTRY_SIZE,
+	       arbel->limits.reserved_uars, ARBEL_PAGE_SIZE,
+	       arbel->limits.reserved_uars,
+	       arbel->limits.uar_scratch_entry_size );
+
+	return 0;
+}
+
+/**
+ * Align ICM table
+ *
+ * @v icm_offset	Current ICM offset
+ * @v len		ICM table length
+ * @ret icm_offset	ICM offset
+ */
+static size_t icm_align ( size_t icm_offset, size_t len ) {
+
+	/* Round up to a multiple of the table size */
+	assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) );
+	return ( ( icm_offset + len - 1 ) & ~( len - 1 ) );
+}
+
+/**
+ * Allocate ICM
+ *
+ * @v arbel		Arbel device
+ * @v init_hca		INIT_HCA structure to fill in
+ * @ret rc		Return status code
+ */
+static int arbel_alloc_icm ( struct arbel *arbel,
+			     struct arbelprm_init_hca *init_hca ) {
+	struct arbelprm_scalar_parameter icm_size;
+	struct arbelprm_scalar_parameter icm_aux_size;
+	struct arbelprm_scalar_parameter unmap_icm;
+	union arbelprm_doorbell_record *db_rec;
+	size_t icm_offset = 0;
+	unsigned int log_num_uars, log_num_qps, log_num_srqs, log_num_ees;
+	unsigned int log_num_cqs, log_num_mtts, log_num_mpts, log_num_rdbs;
+	unsigned int log_num_eqs, log_num_mcs;
+	size_t len;
+	physaddr_t icm_phys;
+	int rc;
+
+	/* Calculate number of each object type within ICM */
+	log_num_qps = fls ( arbel->limits.reserved_qps +
+			    ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS - 1 );
+	log_num_srqs = fls ( arbel->limits.reserved_srqs - 1 );
+	log_num_ees = fls ( arbel->limits.reserved_ees - 1 );
+	log_num_cqs = fls ( arbel->limits.reserved_cqs + ARBEL_MAX_CQS - 1 );
+	log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 );
+	log_num_mtts = fls ( arbel->limits.reserved_mtts - 1 );
+	log_num_mpts = fls ( arbel->limits.reserved_mrws + 1 - 1 );
+	log_num_rdbs = fls ( arbel->limits.reserved_rdbs - 1 );
+	log_num_uars = fls ( arbel->limits.reserved_uars +
+			     1 /* single UAR used */ - 1 );
+	log_num_mcs = ARBEL_LOG_MULTICAST_HASH_SIZE;
+
+	/* Queue pair contexts */
+	len = ( ( 1 << log_num_qps ) * arbel->limits.qpc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_2 ( init_hca, 13,
+		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l,
+		     ( icm_offset >> 7 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp,
+		     log_num_qps );
+	DBGC ( arbel, "Arbel %p ICM QPC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_qps ), arbel->limits.qpc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Extended queue pair contexts */
+	len = ( ( 1 << log_num_qps ) * arbel->limits.eqpc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 25,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqpc_base_addr_l,
+		     icm_offset );
+	DBGC ( arbel, "Arbel %p ICM EQPC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_qps ), arbel->limits.eqpc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Completion queue contexts */
+	len = ( ( 1 << log_num_cqs ) * arbel->limits.cqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_2 ( init_hca, 21,
+		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l,
+		     ( icm_offset >> 6 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq,
+		     log_num_cqs );
+	DBGC ( arbel, "Arbel %p ICM CQC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_cqs ), arbel->limits.cqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Event queue contexts */
+	len = ( ( 1 << log_num_eqs ) * arbel->limits.eqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_2 ( init_hca, 33,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
+		     ( icm_offset >> 6 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_eq,
+		     log_num_eqs );
+	DBGC ( arbel, "Arbel %p ICM EQC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_eqs ), arbel->limits.eqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* End-to-end contexts */
+	len = ( ( 1 << log_num_ees ) * arbel->limits.eec_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_2 ( init_hca, 17,
+		     qpc_eec_cqc_eqc_rdb_parameters.eec_base_addr_l,
+		     ( icm_offset >> 7 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee,
+		     log_num_ees );
+	DBGC ( arbel, "Arbel %p ICM EEC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_ees ), arbel->limits.eec_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Shared receive queue contexts */
+	len = ( ( 1 << log_num_srqs ) * arbel->limits.srqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_2 ( init_hca, 19,
+		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq,
+		     log_num_srqs );
+	DBGC ( arbel, "Arbel %p ICM SRQC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_srqs ), arbel->limits.srqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Memory protection table */
+	len = ( ( 1 << log_num_mpts ) * arbel->limits.mpt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 61,
+		     tpt_parameters.mpt_base_adr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 62,
+		     tpt_parameters.log_mpt_sz, log_num_mpts );
+	DBGC ( arbel, "Arbel %p ICM MPT is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_mpts ), arbel->limits.mpt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Remote read data base table */
+	len = ( ( 1 << log_num_rdbs ) * ARBEL_RDB_ENTRY_SIZE );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 37,
+		     qpc_eec_cqc_eqc_rdb_parameters.rdb_base_addr_l,
+		     icm_offset );
+	DBGC ( arbel, "Arbel %p ICM RDB is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_rdbs ), ARBEL_RDB_ENTRY_SIZE,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Extended end-to-end contexts */
+	len = ( ( 1 << log_num_ees ) * arbel->limits.eeec_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 29,
+		     qpc_eec_cqc_eqc_rdb_parameters.eeec_base_addr_l,
+		     icm_offset );
+	DBGC ( arbel, "Arbel %p ICM EEEC is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_ees ), arbel->limits.eeec_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Multicast table */
+	len = ( ( 1 << log_num_mcs ) * sizeof ( struct arbelprm_mgm_entry ) );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 49,
+		     multicast_parameters.mc_base_addr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 52,
+		     multicast_parameters.log_mc_table_entry_sz,
+		     fls ( sizeof ( struct arbelprm_mgm_entry ) - 1 ) );
+	MLX_FILL_1 ( init_hca, 53,
+		     multicast_parameters.mc_table_hash_sz,
+		     ( 1 << log_num_mcs ) );
+	MLX_FILL_1 ( init_hca, 54,
+		     multicast_parameters.log_mc_table_sz,
+		     log_num_mcs /* Only one entry per hash */ );
+	DBGC ( arbel, "Arbel %p ICM MC is %d x %#zx at [%zx,%zx)\n", arbel,
+	       ( 1 << log_num_mcs ), sizeof ( struct arbelprm_mgm_entry ),
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Memory translation table */
+	len = ( ( 1 << log_num_mtts ) * arbel->limits.mtt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 65,
+		     tpt_parameters.mtt_base_addr_l, icm_offset );
+	DBGC ( arbel, "Arbel %p ICM MTT is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_mtts ), arbel->limits.mtt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* User access region scratchpads */
+	len = ( ( 1 << log_num_uars ) * arbel->limits.uar_scratch_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 77,
+		     uar_parameters.uar_scratch_base_addr_l, icm_offset );
+	DBGC ( arbel, "Arbel %p UAR scratchpad is %d x %#zx at [%zx,%zx)\n",
+	       arbel, ( 1 << log_num_uars ),
+	       arbel->limits.uar_scratch_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Record amount of ICM to be allocated */
+	icm_offset = icm_align ( icm_offset, ARBEL_PAGE_SIZE );
+	arbel->icm_len = icm_offset;
+
+	/* User access region contexts
+	 *
+	 * The reserved UAR(s) do not need to be backed by physical
+	 * memory, and our UAR is allocated separately; neither are
+	 * part of the umalloc()ed ICM block, but both contribute to
+	 * the total length of ICM virtual address space.
+	 */
+	len = ( ( 1 << log_num_uars ) * ARBEL_PAGE_SIZE );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 74, uar_parameters.log_max_uars, log_num_uars );
+	MLX_FILL_1 ( init_hca, 79,
+		     uar_parameters.uar_context_base_addr_l, icm_offset );
+	arbel->db_rec_offset =
+		( icm_offset +
+		  ( arbel->limits.reserved_uars * ARBEL_PAGE_SIZE ) );
+	DBGC ( arbel, "Arbel %p UAR is %d x %#zx at [%zx,%zx), doorbells "
+	       "[%zx,%zx)\n", arbel, ( 1 << log_num_uars ), ARBEL_PAGE_SIZE,
+	       icm_offset, ( icm_offset + len ), arbel->db_rec_offset,
+	       ( arbel->db_rec_offset + ARBEL_PAGE_SIZE ) );
+	icm_offset += len;
+
+	/* Get ICM auxiliary area size */
+	memset ( &icm_size, 0, sizeof ( icm_size ) );
+	MLX_FILL_1 ( &icm_size, 1, value, arbel->icm_len );
+	if ( ( rc = arbel_cmd_set_icm_size ( arbel, &icm_size,
+					     &icm_aux_size ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not set ICM size: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_set_icm_size;
+	}
+	arbel->icm_aux_len =
+		( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
+
+	/* Allocate ICM data and auxiliary area */
+	DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n",
+	       arbel, ( arbel->icm_len / 1024 ),
+	       ( arbel->icm_aux_len / 1024 ) );
+	arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len );
+	if ( ! arbel->icm ) {
+		rc = -ENOMEM;
+		goto err_alloc_icm;
+	}
+	icm_phys = user_to_phys ( arbel->icm, 0 );
+
+	/* Allocate doorbell UAR */
+	arbel->db_rec = malloc_dma ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE );
+	if ( ! arbel->db_rec ) {
+		rc = -ENOMEM;
+		goto err_alloc_doorbell;
+	}
+
+	/* Map ICM auxiliary area */
+	DBGC ( arbel, "Arbel %p ICM AUX at [%08lx,%08lx)\n",
+	       arbel, icm_phys, ( icm_phys + arbel->icm_aux_len ) );
+	if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm_aux,
+				    0, icm_phys, arbel->icm_aux_len ) ) != 0 ){
+		DBGC ( arbel, "Arbel %p could not map AUX ICM: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_map_icm_aux;
+	}
+	icm_phys += arbel->icm_aux_len;
+
+	/* Map ICM area */
+	DBGC ( arbel, "Arbel %p ICM at [%08lx,%08lx)\n",
+	       arbel, icm_phys, ( icm_phys + arbel->icm_len ) );
+	if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm,
+				    0, icm_phys, arbel->icm_len ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not map ICM: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_map_icm;
+	}
+	icm_phys += arbel->icm_len;
+
+	/* Map doorbell UAR */
+	DBGC ( arbel, "Arbel %p UAR at [%08lx,%08lx)\n",
+	       arbel, virt_to_phys ( arbel->db_rec ),
+	       ( virt_to_phys ( arbel->db_rec ) + ARBEL_PAGE_SIZE ) );
+	if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm,
+				    arbel->db_rec_offset,
+				    virt_to_phys ( arbel->db_rec ),
+				    ARBEL_PAGE_SIZE ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not map doorbell UAR: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_map_doorbell;
+	}
+
+	/* Initialise doorbell records */
+	memset ( arbel->db_rec, 0, ARBEL_PAGE_SIZE );
+	db_rec = &arbel->db_rec[ARBEL_GROUP_SEPARATOR_DOORBELL];
+	MLX_FILL_1 ( &db_rec->qp, 1, res, ARBEL_UAR_RES_GROUP_SEP );
+
+	return 0;
+
+	memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+	MLX_FILL_1 ( &unmap_icm, 1, value, arbel->db_rec_offset );
+	arbel_cmd_unmap_icm ( arbel, 1, &unmap_icm );
+ err_map_doorbell:
+	memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+	arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ),
+			      &unmap_icm );
+ err_map_icm:
+	arbel_cmd_unmap_icm_aux ( arbel );
+ err_map_icm_aux:
+	free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
+	arbel->db_rec= NULL;
+ err_alloc_doorbell:
+	ufree ( arbel->icm );
+	arbel->icm = UNULL;
+ err_alloc_icm:
+ err_set_icm_size:
+	return rc;
+}
+
+/**
+ * Free ICM
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_free_icm ( struct arbel *arbel ) {
+	struct arbelprm_scalar_parameter unmap_icm;
+
+	memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+	MLX_FILL_1 ( &unmap_icm, 1, value, arbel->db_rec_offset );
+	arbel_cmd_unmap_icm ( arbel, 1, &unmap_icm );
+	memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+	arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ),
+			      &unmap_icm );
+	arbel_cmd_unmap_icm_aux ( arbel );
+	free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
+	arbel->db_rec = NULL;
+	ufree ( arbel->icm );
+	arbel->icm = UNULL;
+}
+
+/***************************************************************************
+ *
+ * PCI interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Set up memory protection table
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_setup_mpt ( struct arbel *arbel ) {
+	struct arbelprm_mpt mpt;
+	uint32_t key;
+	int rc;
+
+	/* Derive key */
+	key = ( arbel->limits.reserved_mrws | ARBEL_MKEY_PREFIX );
+	arbel->lkey = ( ( key << 8 ) | ( key >> 24 ) );
+
+	/* Initialise memory protection table */
+	memset ( &mpt, 0, sizeof ( mpt ) );
+	MLX_FILL_4 ( &mpt, 0,
+		     r_w, 1,
+		     pa, 1,
+		     lr, 1,
+		     lw, 1 );
+	MLX_FILL_1 ( &mpt, 2, mem_key, key );
+	MLX_FILL_1 ( &mpt, 3, pd, ARBEL_GLOBAL_PD );
+	MLX_FILL_1 ( &mpt, 6, reg_wnd_len_h, 0xffffffffUL );
+	MLX_FILL_1 ( &mpt, 7, reg_wnd_len_l, 0xffffffffUL );
+	if ( ( rc = arbel_cmd_sw2hw_mpt ( arbel, arbel->limits.reserved_mrws,
+					  &mpt ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not set up MPT: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Configure special queue pairs
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_configure_special_qps ( struct arbel *arbel ) {
+	unsigned int smi_qpn_base;
+	unsigned int gsi_qpn_base;
+	int rc;
+
+	/* Special QP block must be aligned on an even number */
+	arbel->special_qpn_base = ( ( arbel->limits.reserved_qps + 1 ) & ~1 );
+	arbel->qpn_base = ( arbel->special_qpn_base +
+			    ARBEL_NUM_SPECIAL_QPS );
+	DBGC ( arbel, "Arbel %p special QPs at [%lx,%lx]\n", arbel,
+	       arbel->special_qpn_base, ( arbel->qpn_base - 1 ) );
+	smi_qpn_base = arbel->special_qpn_base;
+	gsi_qpn_base = ( smi_qpn_base + 2 );
+
+	/* Issue commands to configure special QPs */
+	if ( ( rc = arbel_cmd_conf_special_qp ( arbel, 0,
+						smi_qpn_base ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not configure SMI QPs: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+	if ( ( rc = arbel_cmd_conf_special_qp ( arbel, 1,
+						gsi_qpn_base ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not configure GSI QPs: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int arbel_probe ( struct pci_device *pci ) {
+	struct arbel *arbel;
+	struct ib_device *ibdev;
+	struct arbelprm_init_hca init_hca;
+	int i;
+	int rc;
+
+	/* Allocate Arbel device */
+	arbel = zalloc ( sizeof ( *arbel ) );
+	if ( ! arbel ) {
+		rc = -ENOMEM;
+		goto err_alloc_arbel;
+	}
+	pci_set_drvdata ( pci, arbel );
+
+	/* Allocate Infiniband devices */
+	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
+		ibdev = alloc_ibdev ( 0 );
+		if ( ! ibdev ) {
+			rc = -ENOMEM;
+			goto err_alloc_ibdev;
+		}
+		arbel->ibdev[i] = ibdev;
+		ibdev->op = &arbel_ib_operations;
+		ibdev->dev = &pci->dev;
+		ibdev->port = ( ARBEL_PORT_BASE + i );
+		ib_set_drvdata ( ibdev, arbel );
+	}
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Get PCI BARs */
+	arbel->config = ioremap ( pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ),
+				  ARBEL_PCI_CONFIG_BAR_SIZE );
+	arbel->uar = ioremap ( ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) +
+				 ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
+			       ARBEL_PCI_UAR_SIZE );
+
+	/* Allocate space for mailboxes */
+	arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
+	if ( ! arbel->mailbox_in ) {
+		rc = -ENOMEM;
+		goto err_mailbox_in;
+	}
+	arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
+	if ( ! arbel->mailbox_out ) {
+		rc = -ENOMEM;
+		goto err_mailbox_out;
+	}
+
+	/* Start firmware */
+	if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
+		goto err_start_firmware;
+
+	/* Get device limits */
+	if ( ( rc = arbel_get_limits ( arbel ) ) != 0 )
+		goto err_get_limits;
+
+	/* Allocate ICM */
+	memset ( &init_hca, 0, sizeof ( init_hca ) );
+	if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 )
+		goto err_alloc_icm;
+
+	/* Initialise HCA */
+	if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_init_hca;
+	}
+
+	/* Set up memory protection */
+	if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
+		goto err_setup_mpt;
+
+	/* Set up event queue */
+	if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
+		goto err_create_eq;
+
+	/* Configure special QPs */
+	if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 )
+		goto err_conf_special_qps;
+
+	/* Initialise parameters using SMC */
+	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
+		ib_smc_init ( arbel->ibdev[i], arbel_mad );
+
+	/* Register Infiniband devices */
+	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
+		if ( ( rc = register_ibdev ( arbel->ibdev[i] ) ) != 0 ) {
+			DBGC ( arbel, "Arbel %p port %d could not register IB "
+			       "device: %s\n", arbel,
+			       arbel->ibdev[i]->port, strerror ( rc ) );
+			goto err_register_ibdev;
+		}
+	}
+
+	return 0;
+
+	i = ARBEL_NUM_PORTS;
+ err_register_ibdev:
+	for ( i-- ; i >= 0 ; i-- )
+		unregister_ibdev ( arbel->ibdev[i] );
+ err_conf_special_qps:
+	arbel_destroy_eq ( arbel );
+ err_create_eq:
+ err_setup_mpt:
+	arbel_cmd_close_hca ( arbel );
+ err_init_hca:
+	arbel_free_icm ( arbel );
+ err_alloc_icm:
+ err_get_limits:
+	arbel_stop_firmware ( arbel );
+ err_start_firmware:
+	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
+ err_mailbox_out:
+	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
+ err_mailbox_in:
+	i = ARBEL_NUM_PORTS;
+ err_alloc_ibdev:
+	for ( i-- ; i >= 0 ; i-- )
+		ibdev_put ( arbel->ibdev[i] );
+	free ( arbel );
+ err_alloc_arbel:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void arbel_remove ( struct pci_device *pci ) {
+	struct arbel *arbel = pci_get_drvdata ( pci );
+	int i;
+
+	for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
+		unregister_ibdev ( arbel->ibdev[i] );
+	arbel_destroy_eq ( arbel );
+	arbel_cmd_close_hca ( arbel );
+	arbel_free_icm ( arbel );
+	arbel_stop_firmware ( arbel );
+	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
+	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
+	for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
+		ibdev_put ( arbel->ibdev[i] );
+	free ( arbel );
+}
+
+static struct pci_device_id arbel_nics[] = {
+	PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6274, "mt25204", "MT25204 HCA driver", 0 ),
+};
+
+struct pci_driver arbel_driver __pci_driver = {
+	.ids = arbel_nics,
+	.id_count = ( sizeof ( arbel_nics ) / sizeof ( arbel_nics[0] ) ),
+	.probe = arbel_probe,
+	.remove = arbel_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.h
new file mode 100644
index 0000000..5341157
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/arbel.h
@@ -0,0 +1,623 @@
+#ifndef _ARBEL_H
+#define _ARBEL_H
+
+/** @file
+ *
+ * Mellanox Arbel Infiniband HCA driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/ib_packet.h>
+#include "mlx_bitops.h"
+#include "MT25218_PRM.h"
+
+/*
+ * Hardware constants
+ *
+ */
+
+/* Ports in existence */
+#define ARBEL_NUM_PORTS			2
+#define ARBEL_PORT_BASE			1
+
+/* PCI BARs */
+#define ARBEL_PCI_CONFIG_BAR		PCI_BASE_ADDRESS_0
+#define ARBEL_PCI_CONFIG_BAR_SIZE	0x100000
+#define ARBEL_PCI_UAR_BAR		PCI_BASE_ADDRESS_2
+#define ARBEL_PCI_UAR_IDX		1
+#define ARBEL_PCI_UAR_SIZE		0x1000
+
+/* UAR context table (UCE) resource types */
+#define ARBEL_UAR_RES_NONE		0x00
+#define ARBEL_UAR_RES_CQ_CI		0x01
+#define ARBEL_UAR_RES_CQ_ARM		0x02
+#define ARBEL_UAR_RES_SQ		0x03
+#define ARBEL_UAR_RES_RQ		0x04
+#define ARBEL_UAR_RES_GROUP_SEP		0x07
+
+/* Work queue entry and completion queue entry opcodes */
+#define ARBEL_OPCODE_SEND		0x0a
+#define ARBEL_OPCODE_RECV_ERROR		0xfe
+#define ARBEL_OPCODE_SEND_ERROR		0xff
+
+/* HCA command register opcodes */
+#define ARBEL_HCR_QUERY_DEV_LIM		0x0003
+#define ARBEL_HCR_QUERY_FW		0x0004
+#define ARBEL_HCR_INIT_HCA		0x0007
+#define ARBEL_HCR_CLOSE_HCA		0x0008
+#define ARBEL_HCR_INIT_IB		0x0009
+#define ARBEL_HCR_CLOSE_IB		0x000a
+#define ARBEL_HCR_SW2HW_MPT		0x000d
+#define ARBEL_HCR_MAP_EQ		0x0012
+#define ARBEL_HCR_SW2HW_EQ		0x0013
+#define ARBEL_HCR_HW2SW_EQ		0x0014
+#define ARBEL_HCR_SW2HW_CQ		0x0016
+#define ARBEL_HCR_HW2SW_CQ		0x0017
+#define ARBEL_HCR_QUERY_CQ		0x0018
+#define ARBEL_HCR_RST2INIT_QPEE		0x0019
+#define ARBEL_HCR_INIT2RTR_QPEE		0x001a
+#define ARBEL_HCR_RTR2RTS_QPEE		0x001b
+#define ARBEL_HCR_RTS2RTS_QPEE		0x001c
+#define ARBEL_HCR_2RST_QPEE		0x0021
+#define ARBEL_HCR_QUERY_QPEE		0x0022
+#define ARBEL_HCR_CONF_SPECIAL_QP	0x0023
+#define ARBEL_HCR_MAD_IFC		0x0024
+#define ARBEL_HCR_READ_MGM		0x0025
+#define ARBEL_HCR_WRITE_MGM		0x0026
+#define ARBEL_HCR_MGID_HASH		0x0027
+#define ARBEL_HCR_RUN_FW		0x0ff6
+#define ARBEL_HCR_DISABLE_LAM		0x0ff7
+#define ARBEL_HCR_ENABLE_LAM		0x0ff8
+#define ARBEL_HCR_UNMAP_ICM		0x0ff9
+#define ARBEL_HCR_MAP_ICM		0x0ffa
+#define ARBEL_HCR_UNMAP_ICM_AUX		0x0ffb
+#define ARBEL_HCR_MAP_ICM_AUX		0x0ffc
+#define ARBEL_HCR_SET_ICM_SIZE		0x0ffd
+#define ARBEL_HCR_UNMAP_FA		0x0ffe
+#define ARBEL_HCR_MAP_FA		0x0fff
+
+/* Service types */
+#define ARBEL_ST_UD			0x03
+#define ARBEL_ST_MLX			0x07
+
+/* MTUs */
+#define ARBEL_MTU_2048			0x04
+
+#define ARBEL_NO_EQ			64
+
+#define ARBEL_INVALID_LKEY		0x00000100UL
+
+#define ARBEL_PAGE_SIZE			( ( size_t ) 4096 )
+
+#define ARBEL_RDB_ENTRY_SIZE		( ( size_t ) 32 )
+
+#define ARBEL_DB_POST_SND_OFFSET	0x10
+#define ARBEL_DB_EQ_OFFSET(_eqn)	( 0x08 * (_eqn) )
+
+#define ARBEL_QPEE_OPT_PARAM_QKEY	0x00000020UL
+
+#define ARBEL_MAP_EQ			( 0UL << 31 )
+#define ARBEL_UNMAP_EQ			( 1UL << 31 )
+
+#define ARBEL_EV_PORT_STATE_CHANGE	0x09
+
+#define ARBEL_LOG_MULTICAST_HASH_SIZE	3
+
+#define ARBEL_PM_STATE_ARMED		0x00
+#define ARBEL_PM_STATE_REARM		0x01
+#define ARBEL_PM_STATE_MIGRATED		0x03
+
+/*
+ * Datatypes that seem to be missing from the autogenerated documentation
+ *
+ */
+struct arbelprm_mgm_hash_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t hash[0x00010];
+	pseudo_bit_t reserved1[0x00010];
+} __attribute__ (( packed ));
+
+struct arbelprm_scalar_parameter_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t value[0x00020];
+} __attribute__ (( packed ));
+
+struct arbelprm_event_mask_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t completion[0x00001];
+	pseudo_bit_t path_migration_succeeded[0x00001];
+	pseudo_bit_t communication_established[0x00001];
+	pseudo_bit_t send_queue_drained[0x00001];
+	pseudo_bit_t cq_error[0x00001];
+	pseudo_bit_t wq_catastrophe[0x00001];
+	pseudo_bit_t qpc_catastrophe[0x00001];
+	pseudo_bit_t path_migration_failed[0x00001];
+	pseudo_bit_t reserved1[0x00001];
+	pseudo_bit_t port_state_change[0x00001];
+	pseudo_bit_t command_done[0x00001];
+	pseudo_bit_t reserved2[0x00005];
+	pseudo_bit_t wq_invalid_request[0x00001];
+	pseudo_bit_t wq_access_violation[0x00001];
+	pseudo_bit_t srq_catastrophe[0x00001];
+	pseudo_bit_t srq_last_wqe[0x00001];
+	pseudo_bit_t srq_rq_limit[0x00001];
+	pseudo_bit_t gpio[0x00001];
+	pseudo_bit_t clientreregister[0x00001];
+	pseudo_bit_t path_migration_armed[0x00001];
+	pseudo_bit_t reserved3[0x00008];
+} __attribute__ (( packed ));
+
+struct arbelprm_eq_set_ci_st {
+	pseudo_bit_t ci[0x00020];
+} __attribute__ (( packed ));
+
+struct arbelprm_port_state_change_event_st {
+	pseudo_bit_t reserved[0x00020];
+	struct arbelprm_port_state_change_st data;
+} __attribute__ (( packed ));
+
+/*
+ * Wrapper structures for hardware datatypes
+ *
+ */
+
+struct MLX_DECLARE_STRUCT ( arbelprm_access_lam );
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_queue_context );
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_queue_entry );
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_with_error );
+struct MLX_DECLARE_STRUCT ( arbelprm_cq_arm_db_record );
+struct MLX_DECLARE_STRUCT ( arbelprm_cq_ci_db_record );
+struct MLX_DECLARE_STRUCT ( arbelprm_event_mask );
+struct MLX_DECLARE_STRUCT ( arbelprm_event_queue_entry );
+struct MLX_DECLARE_STRUCT ( arbelprm_eq_set_ci );
+struct MLX_DECLARE_STRUCT ( arbelprm_eqc );
+struct MLX_DECLARE_STRUCT ( arbelprm_hca_command_register );
+struct MLX_DECLARE_STRUCT ( arbelprm_init_hca );
+struct MLX_DECLARE_STRUCT ( arbelprm_init_ib );
+struct MLX_DECLARE_STRUCT ( arbelprm_mad_ifc );
+struct MLX_DECLARE_STRUCT ( arbelprm_mgm_entry );
+struct MLX_DECLARE_STRUCT ( arbelprm_mgm_hash );
+struct MLX_DECLARE_STRUCT ( arbelprm_mpt );
+struct MLX_DECLARE_STRUCT ( arbelprm_port_state_change_event );
+struct MLX_DECLARE_STRUCT ( arbelprm_qp_db_record );
+struct MLX_DECLARE_STRUCT ( arbelprm_qp_ee_state_transitions );
+struct MLX_DECLARE_STRUCT ( arbelprm_query_dev_lim );
+struct MLX_DECLARE_STRUCT ( arbelprm_query_fw );
+struct MLX_DECLARE_STRUCT ( arbelprm_queue_pair_ee_context_entry );
+struct MLX_DECLARE_STRUCT ( arbelprm_recv_wqe_segment_next );
+struct MLX_DECLARE_STRUCT ( arbelprm_scalar_parameter );
+struct MLX_DECLARE_STRUCT ( arbelprm_send_doorbell );
+struct MLX_DECLARE_STRUCT ( arbelprm_ud_address_vector );
+struct MLX_DECLARE_STRUCT ( arbelprm_virtual_physical_mapping );
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_ctrl_mlx );
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_ctrl_send );
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_data_ptr );
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_next );
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_ud );
+
+/*
+ * Composite hardware datatypes
+ *
+ */
+
+#define ARBEL_MAX_GATHER 2
+
+struct arbelprm_ud_send_wqe {
+	struct arbelprm_wqe_segment_next next;
+	struct arbelprm_wqe_segment_ctrl_send ctrl;
+	struct arbelprm_wqe_segment_ud ud;
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_GATHER];
+} __attribute__ (( packed ));
+
+struct arbelprm_mlx_send_wqe {
+	struct arbelprm_wqe_segment_next next;
+	struct arbelprm_wqe_segment_ctrl_mlx ctrl;
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_GATHER];
+	uint8_t headers[IB_MAX_HEADER_SIZE];
+} __attribute__ (( packed ));
+
+#define ARBEL_MAX_SCATTER 1
+
+struct arbelprm_recv_wqe {
+	/* The autogenerated header is inconsistent between send and
+	 * receive WQEs.  The "ctrl" structure for receive WQEs is
+	 * defined to include the "next" structure.  Since the "ctrl"
+	 * part of the "ctrl" structure contains only "reserved, must
+	 * be zero" bits, we ignore its definition and provide
+	 * something more usable.
+	 */
+	struct arbelprm_recv_wqe_segment_next next;
+	uint32_t ctrl[2]; /* All "reserved, must be zero" */
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_SCATTER];
+} __attribute__ (( packed ));
+
+union arbelprm_completion_entry {
+	struct arbelprm_completion_queue_entry normal;
+	struct arbelprm_completion_with_error error;
+} __attribute__ (( packed ));
+
+union arbelprm_event_entry {
+	struct arbelprm_event_queue_entry generic;
+	struct arbelprm_port_state_change_event port_state_change;
+} __attribute__ (( packed ));
+
+union arbelprm_doorbell_record {
+	struct arbelprm_cq_arm_db_record cq_arm;
+	struct arbelprm_cq_ci_db_record cq_ci;
+	struct arbelprm_qp_db_record qp;
+} __attribute__ (( packed ));
+
+union arbelprm_doorbell_register {
+	struct arbelprm_send_doorbell send;
+	uint32_t dword[2];
+} __attribute__ (( packed ));
+
+union arbelprm_eq_doorbell_register {
+	struct arbelprm_eq_set_ci ci;
+	uint32_t dword[1];
+} __attribute__ (( packed ));
+
+union arbelprm_mad {
+	struct arbelprm_mad_ifc ifc;
+	union ib_mad mad;
+} __attribute__ (( packed ));
+
+/*
+ * iPXE-specific definitions
+ *
+ */
+
+/** Arbel device limits */
+struct arbel_dev_limits {
+	/** Number of reserved QPs */
+	unsigned int reserved_qps;
+	/** QP context entry size */
+	size_t qpc_entry_size;
+	/** Extended QP context entry size */
+	size_t eqpc_entry_size;
+	/** Number of reserved SRQs */
+	unsigned int reserved_srqs;
+	/** SRQ context entry size */
+	size_t srqc_entry_size;
+	/** Number of reserved EEs */
+	unsigned int reserved_ees;
+	/** EE context entry size */
+	size_t eec_entry_size;
+	/** Extended EE context entry size */
+	size_t eeec_entry_size;
+	/** Number of reserved CQs */
+	unsigned int reserved_cqs;
+	/** CQ context entry size */
+	size_t cqc_entry_size;
+	/** Number of reserved EQs */
+	unsigned int reserved_eqs;
+	/** Number of reserved MTTs */
+	unsigned int reserved_mtts;
+	/** MTT entry size */
+	size_t mtt_entry_size;
+	/** Number of reserved MRWs */
+	unsigned int reserved_mrws;
+	/** MPT entry size */
+	size_t mpt_entry_size;
+	/** Number of reserved RDBs */
+	unsigned int reserved_rdbs;
+	/** EQ context entry size */
+	size_t eqc_entry_size;
+	/** Number of reserved UARs */
+	unsigned int reserved_uars;
+	/** UAR scratchpad entry size */
+	size_t uar_scratch_entry_size;
+};
+
+/** Alignment of Arbel send work queue entries */
+#define ARBEL_SEND_WQE_ALIGN 128
+
+/** An Arbel send work queue entry */
+union arbel_send_wqe {
+	struct arbelprm_wqe_segment_next next;
+	struct arbelprm_ud_send_wqe ud;
+	struct arbelprm_mlx_send_wqe mlx;
+	uint8_t force_align[ARBEL_SEND_WQE_ALIGN];
+} __attribute__ (( packed ));
+
+/** An Arbel send work queue */
+struct arbel_send_work_queue {
+	/** Doorbell record number */
+	unsigned int doorbell_idx;
+	/** Work queue entries */
+	union arbel_send_wqe *wqe;
+	/** Size of work queue */
+	size_t wqe_size;
+};
+
+/** Alignment of Arbel receive work queue entries */
+#define ARBEL_RECV_WQE_ALIGN 64
+
+/** An Arbel receive work queue entry */
+union arbel_recv_wqe {
+	struct arbelprm_recv_wqe recv;
+	uint8_t force_align[ARBEL_RECV_WQE_ALIGN];
+} __attribute__ (( packed ));
+
+/** An Arbel receive work queue */
+struct arbel_recv_work_queue {
+	/** Doorbell record number */
+	unsigned int doorbell_idx;
+	/** Work queue entries */
+	union arbel_recv_wqe *wqe;
+	/** Size of work queue */
+	size_t wqe_size;
+};
+
+/** Number of special queue pairs */
+#define ARBEL_NUM_SPECIAL_QPS 4
+
+/** Number of queue pairs reserved for the "special QP" block
+ *
+ * The special QPs must be in (2n,2n+1) pairs, hence we need to
+ * reserve one extra QP to allow for alignment.
+ */
+#define ARBEL_RSVD_SPECIAL_QPS	( ARBEL_NUM_SPECIAL_QPS + 1 )
+
+/** Maximum number of allocatable queue pairs
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define ARBEL_MAX_QPS		8
+
+/** Queue pair number randomisation mask */
+#define ARBEL_QPN_RANDOM_MASK 0xfff000
+
+/** Arbel queue pair state */
+enum arbel_queue_pair_state {
+	ARBEL_QP_ST_RST = 0,
+	ARBEL_QP_ST_INIT,
+	ARBEL_QP_ST_RTR,
+	ARBEL_QP_ST_RTS,
+};
+
+/** An Arbel queue pair */
+struct arbel_queue_pair {
+	/** Send work queue */
+	struct arbel_send_work_queue send;
+	/** Receive work queue */
+	struct arbel_recv_work_queue recv;
+	/** Queue state */
+	enum arbel_queue_pair_state state;
+};
+
+/** Maximum number of allocatable completion queues
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define ARBEL_MAX_CQS		8
+
+/** An Arbel completion queue */
+struct arbel_completion_queue {
+	/** Consumer counter doorbell record number */
+	unsigned int ci_doorbell_idx;
+	/** Arm queue doorbell record number */
+	unsigned int arm_doorbell_idx;
+	/** Completion queue entries */
+	union arbelprm_completion_entry *cqe;
+	/** Size of completion queue */
+	size_t cqe_size;
+};
+
+/** Maximum number of allocatable event queues
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define ARBEL_MAX_EQS		64
+
+/** A Arbel event queue */
+struct arbel_event_queue {
+	/** Event queue entries */
+	union arbelprm_event_entry *eqe;
+	/** Size of event queue */
+	size_t eqe_size;
+	/** Event queue number */
+	unsigned long eqn;
+	/** Next event queue entry index */
+	unsigned long next_idx;
+	/** Doorbell register */
+	void *doorbell;
+};
+
+/** Number of event queue entries
+ *
+ * This is a policy decision.
+ */
+#define ARBEL_NUM_EQES		4
+
+
+/** An Arbel resource bitmask */
+typedef uint32_t arbel_bitmask_t;
+
+/** Size of an Arbel resource bitmask */
+#define ARBEL_BITMASK_SIZE(max_entries)					     \
+	( ( (max_entries) + ( 8 * sizeof ( arbel_bitmask_t ) ) - 1 ) /	     \
+	  ( 8 * sizeof ( arbel_bitmask_t ) ) )
+
+/** An Arbel device */
+struct arbel {
+	/** PCI configuration registers */
+	void *config;
+	/** PCI user Access Region */
+	void *uar;
+	/** Event queue consumer index doorbells */
+	void *eq_ci_doorbells;
+
+	/** Command input mailbox */
+	void *mailbox_in;
+	/** Command output mailbox */
+	void *mailbox_out;
+
+	/** Firmware area in external memory */
+	userptr_t firmware_area;
+	/** ICM size */
+	size_t icm_len;
+	/** ICM AUX size */
+	size_t icm_aux_len;
+	/** ICM area */
+	userptr_t icm;
+	/** Offset within ICM of doorbell records */
+	size_t db_rec_offset;
+	/** Doorbell records */
+	union arbelprm_doorbell_record *db_rec;
+	/** Event queue */
+	struct arbel_event_queue eq;
+	/** Unrestricted LKey
+	 *
+	 * Used to get unrestricted memory access.
+	 */
+	unsigned long lkey;
+
+	/** Completion queue in-use bitmask */
+	arbel_bitmask_t cq_inuse[ ARBEL_BITMASK_SIZE ( ARBEL_MAX_CQS ) ];
+	/** Queue pair in-use bitmask */
+	arbel_bitmask_t qp_inuse[ ARBEL_BITMASK_SIZE ( ARBEL_MAX_QPS ) ];
+	
+	/** Device limits */
+	struct arbel_dev_limits limits;
+	/** Special QPN base */
+	unsigned long special_qpn_base;
+	/** QPN base */
+	unsigned long qpn_base;
+
+	/** Infiniband devices */
+	struct ib_device *ibdev[ARBEL_NUM_PORTS];
+};
+
+/** Global protection domain */
+#define ARBEL_GLOBAL_PD			0x123456
+
+/** Memory key prefix */
+#define ARBEL_MKEY_PREFIX		0x77000000UL
+
+/*
+ * HCA commands
+ *
+ */
+
+#define ARBEL_HCR_BASE			0x80680
+#define ARBEL_HCR_REG(x)		( ARBEL_HCR_BASE + 4 * (x) )
+#define ARBEL_HCR_MAX_WAIT_MS		2000
+#define ARBEL_MBOX_ALIGN		4096
+#define ARBEL_MBOX_SIZE			512
+
+/* HCA command is split into
+ *
+ * bits  11:0	Opcode
+ * bit     12	Input uses mailbox
+ * bit     13	Output uses mailbox
+ * bits 22:14	Input parameter length (in dwords)
+ * bits 31:23	Output parameter length (in dwords)
+ *
+ * Encoding the information in this way allows us to cut out several
+ * parameters to the arbel_command() call.
+ */
+#define ARBEL_HCR_IN_MBOX		0x00001000UL
+#define ARBEL_HCR_OUT_MBOX		0x00002000UL
+#define ARBEL_HCR_OPCODE( _command )	( (_command) & 0xfff )
+#define ARBEL_HCR_IN_LEN( _command )	( ( (_command) >> 12 ) & 0x7fc )
+#define ARBEL_HCR_OUT_LEN( _command )	( ( (_command) >> 21 ) & 0x7fc )
+
+/** Build HCR command from component parts */
+#define ARBEL_HCR_INOUT_CMD( _opcode, _in_mbox, _in_len,		     \
+			     _out_mbox, _out_len )			     \
+	( (_opcode) |							     \
+	  ( (_in_mbox) ? ARBEL_HCR_IN_MBOX : 0 ) |			     \
+	  ( ( (_in_len) / 4 ) << 14 ) |					     \
+	  ( (_out_mbox) ? ARBEL_HCR_OUT_MBOX : 0 ) |			     \
+	  ( ( (_out_len) / 4 ) << 23 ) )
+
+#define ARBEL_HCR_IN_CMD( _opcode, _in_mbox, _in_len )			     \
+	ARBEL_HCR_INOUT_CMD ( _opcode, _in_mbox, _in_len, 0, 0 )
+
+#define ARBEL_HCR_OUT_CMD( _opcode, _out_mbox, _out_len )		     \
+	ARBEL_HCR_INOUT_CMD ( _opcode, 0, 0, _out_mbox, _out_len )
+
+#define ARBEL_HCR_VOID_CMD( _opcode )					     \
+	ARBEL_HCR_INOUT_CMD ( _opcode, 0, 0, 0, 0 )
+
+/*
+ * Doorbell record allocation
+ *
+ * The doorbell record map looks like:
+ *
+ *    ARBEL_MAX_CQS * Arm completion queue doorbell
+ *    ARBEL_MAX_QPS * Send work request doorbell
+ *    Group separator
+ *    ...(empty space)...
+ *    ARBEL_MAX_QPS * Receive work request doorbell
+ *    ARBEL_MAX_CQS * Completion queue consumer counter update doorbell
+ */
+
+#define ARBEL_MAX_DOORBELL_RECORDS 512
+#define ARBEL_GROUP_SEPARATOR_DOORBELL \
+	( ARBEL_MAX_CQS + ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS )
+
+/**
+ * Get arm completion queue doorbell index
+ *
+ * @v arbel		Arbel device
+ * @v cq		Completion queue
+ * @ret doorbell_idx	Doorbell index
+ */
+static inline unsigned int
+arbel_cq_arm_doorbell_idx ( struct arbel *arbel,
+			    struct ib_completion_queue *cq ) {
+	return ( cq->cqn - arbel->limits.reserved_cqs );
+}
+
+/**
+ * Get send work request doorbell index
+ *
+ * @v arbel		Arbel device
+ * @v qp		Queue pair
+ * @ret doorbell_idx	Doorbell index
+ */
+static inline unsigned int
+arbel_send_doorbell_idx ( struct arbel *arbel, struct ib_queue_pair *qp ) {
+	return ( ARBEL_MAX_CQS +
+		 ( ( qp->qpn & ~ARBEL_QPN_RANDOM_MASK ) -
+		   arbel->special_qpn_base ) );
+}
+
+/**
+ * Get receive work request doorbell index
+ *
+ * @v arbel		Arbel device
+ * @v qp		Queue pair
+ * @ret doorbell_idx	Doorbell index
+ */
+static inline unsigned int
+arbel_recv_doorbell_idx ( struct arbel *arbel, struct ib_queue_pair *qp ) {
+	return ( ARBEL_MAX_DOORBELL_RECORDS - ARBEL_MAX_CQS -
+		 ( ( qp->qpn & ~ARBEL_QPN_RANDOM_MASK ) -
+		   arbel->special_qpn_base ) - 1 );
+}
+
+/**
+ * Get completion queue consumer counter doorbell index
+ *
+ * @v arbel		Arbel device
+ * @v cq		Completion queue
+ * @ret doorbell_idx	Doorbell index
+ */
+static inline unsigned int
+arbel_cq_ci_doorbell_idx ( struct arbel *arbel,
+			   struct ib_completion_queue *cq ) {
+	return ( ARBEL_MAX_DOORBELL_RECORDS -
+		 ( cq->cqn - arbel->limits.reserved_cqs ) - 1 );
+}
+
+#endif /* _ARBEL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.c b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.c
new file mode 100644
index 0000000..f44166f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.c
@@ -0,0 +1,3854 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ * Copyright (C) 2008 Mellanox Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/pcibackup.h>
+#include <ipxe/malloc.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_smc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/fcoe.h>
+#include <ipxe/vlan.h>
+#include <ipxe/bofm.h>
+#include "hermon.h"
+
+/**
+ * @file
+ *
+ * Mellanox Hermon Infiniband HCA
+ *
+ */
+
+/***************************************************************************
+ *
+ * Queue number allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate offsets within usage bitmask
+ *
+ * @v bits		Usage bitmask
+ * @v bits_len		Length of usage bitmask
+ * @v num_bits		Number of contiguous bits to allocate within bitmask
+ * @ret bit		First free bit within bitmask, or negative error
+ */
+static int hermon_bitmask_alloc ( hermon_bitmask_t *bits,
+				  unsigned int bits_len,
+				  unsigned int num_bits ) {
+	unsigned int bit = 0;
+	hermon_bitmask_t mask = 1;
+	unsigned int found = 0;
+
+	/* Search bits for num_bits contiguous free bits */
+	while ( bit < bits_len ) {
+		if ( ( mask & *bits ) == 0 ) {
+			if ( ++found == num_bits )
+				goto found;
+		} else {
+			found = 0;
+		}
+		bit++;
+		mask = ( mask << 1 ) | ( mask >> ( 8 * sizeof ( mask ) - 1 ) );
+		if ( mask == 1 )
+			bits++;
+	}
+	return -ENFILE;
+
+ found:
+	/* Mark bits as in-use */
+	do {
+		*bits |= mask;
+		if ( mask == 1 )
+			bits--;
+		mask = ( mask >> 1 ) | ( mask << ( 8 * sizeof ( mask ) - 1 ) );
+	} while ( --found );
+
+	return ( bit - num_bits + 1 );
+}
+
+/**
+ * Free offsets within usage bitmask
+ *
+ * @v bits		Usage bitmask
+ * @v bit		Starting bit within bitmask
+ * @v num_bits		Number of contiguous bits to free within bitmask
+ */
+static void hermon_bitmask_free ( hermon_bitmask_t *bits,
+				  int bit, unsigned int num_bits ) {
+	hermon_bitmask_t mask;
+
+	for ( ; num_bits ; bit++, num_bits-- ) {
+		mask = ( 1 << ( bit % ( 8 * sizeof ( mask ) ) ) );
+		bits[ ( bit / ( 8 * sizeof ( mask ) ) ) ] &= ~mask;
+	}
+}
+
+/***************************************************************************
+ *
+ * HCA commands
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Wait for Hermon command completion
+ *
+ * @v hermon		Hermon device
+ * @v hcr		HCA command registers
+ * @ret rc		Return status code
+ */
+static int hermon_cmd_wait ( struct hermon *hermon,
+			     struct hermonprm_hca_command_register *hcr ) {
+	unsigned int wait;
+
+	for ( wait = HERMON_HCR_MAX_WAIT_MS ; wait ; wait-- ) {
+		hcr->u.dwords[6] =
+			readl ( hermon->config + HERMON_HCR_REG ( 6 ) );
+		if ( ( MLX_GET ( hcr, go ) == 0 ) &&
+		     ( MLX_GET ( hcr, t ) == hermon->toggle ) )
+			return 0;
+		mdelay ( 1 );
+	}
+	return -EBUSY;
+}
+
+/**
+ * Issue HCA command
+ *
+ * @v hermon		Hermon device
+ * @v command		Command opcode, flags and input/output lengths
+ * @v op_mod		Opcode modifier (0 if no modifier applicable)
+ * @v in		Input parameters
+ * @v in_mod		Input modifier (0 if no modifier applicable)
+ * @v out		Output parameters
+ * @ret rc		Return status code
+ */
+static int hermon_cmd ( struct hermon *hermon, unsigned long command,
+			unsigned int op_mod, const void *in,
+			unsigned int in_mod, void *out ) {
+	struct hermonprm_hca_command_register hcr;
+	unsigned int opcode = HERMON_HCR_OPCODE ( command );
+	size_t in_len = HERMON_HCR_IN_LEN ( command );
+	size_t out_len = HERMON_HCR_OUT_LEN ( command );
+	void *in_buffer;
+	void *out_buffer;
+	unsigned int status;
+	unsigned int i;
+	int rc;
+
+	assert ( in_len <= HERMON_MBOX_SIZE );
+	assert ( out_len <= HERMON_MBOX_SIZE );
+
+	DBGC2 ( hermon, "Hermon %p command %02x in %zx%s out %zx%s\n",
+		hermon, opcode, in_len,
+		( ( command & HERMON_HCR_IN_MBOX ) ? "(mbox)" : "" ), out_len,
+		( ( command & HERMON_HCR_OUT_MBOX ) ? "(mbox)" : "" ) );
+
+	/* Check that HCR is free */
+	if ( ( rc = hermon_cmd_wait ( hermon, &hcr ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p command interface locked\n",
+		       hermon );
+		return rc;
+	}
+
+	/* Flip HCR toggle */
+	hermon->toggle = ( 1 - hermon->toggle );
+
+	/* Prepare HCR */
+	memset ( &hcr, 0, sizeof ( hcr ) );
+	in_buffer = &hcr.u.dwords[0];
+	if ( in_len && ( command & HERMON_HCR_IN_MBOX ) ) {
+		memset ( hermon->mailbox_in, 0, HERMON_MBOX_SIZE );
+		in_buffer = hermon->mailbox_in;
+		MLX_FILL_H ( &hcr, 0, in_param_h, virt_to_bus ( in_buffer ) );
+		MLX_FILL_1 ( &hcr, 1, in_param_l, virt_to_bus ( in_buffer ) );
+	}
+	memcpy ( in_buffer, in, in_len );
+	MLX_FILL_1 ( &hcr, 2, input_modifier, in_mod );
+	out_buffer = &hcr.u.dwords[3];
+	if ( out_len && ( command & HERMON_HCR_OUT_MBOX ) ) {
+		out_buffer = hermon->mailbox_out;
+		MLX_FILL_H ( &hcr, 3, out_param_h,
+			     virt_to_bus ( out_buffer ) );
+		MLX_FILL_1 ( &hcr, 4, out_param_l,
+			     virt_to_bus ( out_buffer ) );
+	}
+	MLX_FILL_4 ( &hcr, 6,
+		     opcode, opcode,
+		     opcode_modifier, op_mod,
+		     go, 1,
+		     t, hermon->toggle );
+	DBGC ( hermon, "Hermon %p issuing command %04x\n",
+	       hermon, opcode );
+	DBGC2_HDA ( hermon, virt_to_phys ( hermon->config + HERMON_HCR_BASE ),
+		    &hcr, sizeof ( hcr ) );
+	if ( in_len && ( command & HERMON_HCR_IN_MBOX ) ) {
+		DBGC2 ( hermon, "Input mailbox:\n" );
+		DBGC2_HDA ( hermon, virt_to_phys ( in_buffer ), in_buffer,
+			    ( ( in_len < 512 ) ? in_len : 512 ) );
+	}
+
+	/* Issue command */
+	for ( i = 0 ; i < ( sizeof ( hcr ) / sizeof ( hcr.u.dwords[0] ) ) ;
+	      i++ ) {
+		writel ( hcr.u.dwords[i],
+			 hermon->config + HERMON_HCR_REG ( i ) );
+		barrier();
+	}
+
+	/* Wait for command completion */
+	if ( ( rc = hermon_cmd_wait ( hermon, &hcr ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p timed out waiting for command:\n",
+		       hermon );
+		DBGC_HDA ( hermon,
+			   virt_to_phys ( hermon->config + HERMON_HCR_BASE ),
+			   &hcr, sizeof ( hcr ) );
+		return rc;
+	}
+
+	/* Check command status */
+	status = MLX_GET ( &hcr, status );
+	if ( status != 0 ) {
+		DBGC ( hermon, "Hermon %p command failed with status %02x:\n",
+		       hermon, status );
+		DBGC_HDA ( hermon,
+			   virt_to_phys ( hermon->config + HERMON_HCR_BASE ),
+			   &hcr, sizeof ( hcr ) );
+		return -EIO;
+	}
+
+	/* Read output parameters, if any */
+	hcr.u.dwords[3] = readl ( hermon->config + HERMON_HCR_REG ( 3 ) );
+	hcr.u.dwords[4] = readl ( hermon->config + HERMON_HCR_REG ( 4 ) );
+	memcpy ( out, out_buffer, out_len );
+	if ( out_len ) {
+		DBGC2 ( hermon, "Output%s:\n",
+			( command & HERMON_HCR_OUT_MBOX ) ? " mailbox" : "" );
+		DBGC2_HDA ( hermon, virt_to_phys ( out_buffer ), out_buffer,
+			    ( ( out_len < 512 ) ? out_len : 512 ) );
+	}
+
+	return 0;
+}
+
+static inline int
+hermon_cmd_query_dev_cap ( struct hermon *hermon,
+			   struct hermonprm_query_dev_cap *dev_cap ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_DEV_CAP,
+						 1, sizeof ( *dev_cap ) ),
+			    0, NULL, 0, dev_cap );
+}
+
+static inline int
+hermon_cmd_query_fw ( struct hermon *hermon, struct hermonprm_query_fw *fw ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_FW,
+						 1, sizeof ( *fw ) ),
+			    0, NULL, 0, fw );
+}
+
+static inline int
+hermon_cmd_init_hca ( struct hermon *hermon,
+		      const struct hermonprm_init_hca *init_hca ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_INIT_HCA,
+						1, sizeof ( *init_hca ) ),
+			    0, init_hca, 0, NULL );
+}
+
+static inline int
+hermon_cmd_close_hca ( struct hermon *hermon ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_CLOSE_HCA ),
+			    0, NULL, 0, NULL );
+}
+
+static inline int
+hermon_cmd_init_port ( struct hermon *hermon, unsigned int port ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_INIT_PORT ),
+			    0, NULL, port, NULL );
+}
+
+static inline int
+hermon_cmd_close_port ( struct hermon *hermon, unsigned int port ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_CLOSE_PORT ),
+			    0, NULL, port, NULL );
+}
+
+static inline int
+hermon_cmd_set_port ( struct hermon *hermon, int is_ethernet,
+		      unsigned int port_selector,
+		      const union hermonprm_set_port *set_port ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_SET_PORT,
+						1, sizeof ( *set_port ) ),
+			    is_ethernet, set_port, port_selector, NULL );
+}
+
+static inline int
+hermon_cmd_sw2hw_mpt ( struct hermon *hermon, unsigned int index,
+		       const struct hermonprm_mpt *mpt ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_SW2HW_MPT,
+						1, sizeof ( *mpt ) ),
+			    0, mpt, index, NULL );
+}
+
+static inline int
+hermon_cmd_write_mtt ( struct hermon *hermon,
+		       const struct hermonprm_write_mtt *write_mtt ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_WRITE_MTT,
+						1, sizeof ( *write_mtt ) ),
+			    0, write_mtt, 1, NULL );
+}
+
+static inline int
+hermon_cmd_map_eq ( struct hermon *hermon, unsigned long index_map,
+		    const struct hermonprm_event_mask *mask ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_MAP_EQ,
+						0, sizeof ( *mask ) ),
+			    0, mask, index_map, NULL );
+}
+
+static inline int
+hermon_cmd_sw2hw_eq ( struct hermon *hermon, unsigned int index,
+		      const struct hermonprm_eqc *eqctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_SW2HW_EQ,
+						1, sizeof ( *eqctx ) ),
+			    0, eqctx, index, NULL );
+}
+
+static inline int
+hermon_cmd_hw2sw_eq ( struct hermon *hermon, unsigned int index,
+		      struct hermonprm_eqc *eqctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_HW2SW_EQ,
+						 1, sizeof ( *eqctx ) ),
+			    1, NULL, index, eqctx );
+}
+
+static inline int
+hermon_cmd_query_eq ( struct hermon *hermon, unsigned int index,
+		      struct hermonprm_eqc *eqctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_EQ,
+						 1, sizeof ( *eqctx ) ),
+			    0, NULL, index, eqctx );
+}
+
+static inline int
+hermon_cmd_sw2hw_cq ( struct hermon *hermon, unsigned long cqn,
+		      const struct hermonprm_completion_queue_context *cqctx ){
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_SW2HW_CQ,
+						1, sizeof ( *cqctx ) ),
+			    0, cqctx, cqn, NULL );
+}
+
+static inline int
+hermon_cmd_hw2sw_cq ( struct hermon *hermon, unsigned long cqn,
+		      struct hermonprm_completion_queue_context *cqctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_HW2SW_CQ,
+						 1, sizeof ( *cqctx ) ),
+			    0, NULL, cqn, cqctx );
+}
+
+static inline int
+hermon_cmd_query_cq ( struct hermon *hermon, unsigned long cqn,
+		      struct hermonprm_completion_queue_context *cqctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_CQ,
+						 1, sizeof ( *cqctx ) ),
+			    0, NULL, cqn, cqctx );
+}
+
+static inline int
+hermon_cmd_rst2init_qp ( struct hermon *hermon, unsigned long qpn,
+			 const struct hermonprm_qp_ee_state_transitions *ctx ){
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_RST2INIT_QP,
+						1, sizeof ( *ctx ) ),
+			    0, ctx, qpn, NULL );
+}
+
+static inline int
+hermon_cmd_init2rtr_qp ( struct hermon *hermon, unsigned long qpn,
+			 const struct hermonprm_qp_ee_state_transitions *ctx ){
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_INIT2RTR_QP,
+						1, sizeof ( *ctx ) ),
+			    0, ctx, qpn, NULL );
+}
+
+static inline int
+hermon_cmd_rtr2rts_qp ( struct hermon *hermon, unsigned long qpn,
+			const struct hermonprm_qp_ee_state_transitions *ctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_RTR2RTS_QP,
+						1, sizeof ( *ctx ) ),
+			    0, ctx, qpn, NULL );
+}
+
+static inline int
+hermon_cmd_rts2rts_qp ( struct hermon *hermon, unsigned long qpn,
+			const struct hermonprm_qp_ee_state_transitions *ctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_RTS2RTS_QP,
+						1, sizeof ( *ctx ) ),
+			    0, ctx, qpn, NULL );
+}
+
+static inline int
+hermon_cmd_2rst_qp ( struct hermon *hermon, unsigned long qpn ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_2RST_QP ),
+			    0x03, NULL, qpn, NULL );
+}
+
+static inline int
+hermon_cmd_query_qp ( struct hermon *hermon, unsigned long qpn,
+		      struct hermonprm_qp_ee_state_transitions *ctx ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_QP,
+						 1, sizeof ( *ctx ) ),
+			    0, NULL, qpn, ctx );
+}
+
+static inline int
+hermon_cmd_conf_special_qp ( struct hermon *hermon, unsigned int internal_qps,
+			     unsigned long base_qpn ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_CONF_SPECIAL_QP ),
+			    internal_qps, NULL, base_qpn, NULL );
+}
+
+static inline int
+hermon_cmd_mad_ifc ( struct hermon *hermon, unsigned int port,
+		     union hermonprm_mad *mad ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_INOUT_CMD ( HERMON_HCR_MAD_IFC,
+						   1, sizeof ( *mad ),
+						   1, sizeof ( *mad ) ),
+			    0x03, mad, port, mad );
+}
+
+static inline int
+hermon_cmd_read_mcg ( struct hermon *hermon, unsigned int index,
+		      struct hermonprm_mcg_entry *mcg ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_READ_MCG,
+						 1, sizeof ( *mcg ) ),
+			    0, NULL, index, mcg );
+}
+
+static inline int
+hermon_cmd_write_mcg ( struct hermon *hermon, unsigned int index,
+		       const struct hermonprm_mcg_entry *mcg ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_WRITE_MCG,
+						1, sizeof ( *mcg ) ),
+			    0, mcg, index, NULL );
+}
+
+static inline int
+hermon_cmd_mgid_hash ( struct hermon *hermon, const union ib_gid *gid,
+		       struct hermonprm_mgm_hash *hash ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_INOUT_CMD ( HERMON_HCR_MGID_HASH,
+						   1, sizeof ( *gid ),
+						   0, sizeof ( *hash ) ),
+			    0, gid, 0, hash );
+}
+
+static inline int
+hermon_cmd_mod_stat_cfg ( struct hermon *hermon, unsigned int mode,
+			  unsigned int input_mod,
+			  struct hermonprm_scalar_parameter *portion ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_INOUT_CMD ( HERMON_HCR_MOD_STAT_CFG,
+						   0, sizeof ( *portion ),
+						   0, sizeof ( *portion ) ),
+			    mode, portion, input_mod, portion );
+}
+
+static inline int
+hermon_cmd_query_port ( struct hermon *hermon, unsigned int port,
+			struct hermonprm_query_port_cap *query_port ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_QUERY_PORT,
+						 1, sizeof ( *query_port ) ),
+			    0, NULL, port, query_port );
+}
+
+static inline int
+hermon_cmd_sense_port ( struct hermon *hermon, unsigned int port,
+			struct hermonprm_sense_port *port_type ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_OUT_CMD ( HERMON_HCR_SENSE_PORT,
+						 0, sizeof ( *port_type ) ),
+			    0, NULL, port, port_type );
+}
+
+static inline int
+hermon_cmd_run_fw ( struct hermon *hermon ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_RUN_FW ),
+			    0, NULL, 0, NULL );
+}
+
+static inline int
+hermon_cmd_unmap_icm ( struct hermon *hermon, unsigned int page_count,
+		       const struct hermonprm_scalar_parameter *offset ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_UNMAP_ICM,
+						0, sizeof ( *offset ) ),
+			    0, offset, page_count, NULL );
+}
+
+static inline int
+hermon_cmd_map_icm ( struct hermon *hermon,
+		     const struct hermonprm_virtual_physical_mapping *map ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_MAP_ICM,
+						1, sizeof ( *map ) ),
+			    0, map, 1, NULL );
+}
+
+static inline int
+hermon_cmd_unmap_icm_aux ( struct hermon *hermon ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_UNMAP_ICM_AUX ),
+			    0, NULL, 0, NULL );
+}
+
+static inline int
+hermon_cmd_map_icm_aux ( struct hermon *hermon,
+		       const struct hermonprm_virtual_physical_mapping *map ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_MAP_ICM_AUX,
+						1, sizeof ( *map ) ),
+			    0, map, 1, NULL );
+}
+
+static inline int
+hermon_cmd_set_icm_size ( struct hermon *hermon,
+			  const struct hermonprm_scalar_parameter *icm_size,
+			  struct hermonprm_scalar_parameter *icm_aux_size ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_INOUT_CMD ( HERMON_HCR_SET_ICM_SIZE,
+						   0, sizeof ( *icm_size ),
+						   0, sizeof (*icm_aux_size) ),
+			    0, icm_size, 0, icm_aux_size );
+}
+
+static inline int
+hermon_cmd_unmap_fa ( struct hermon *hermon ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_VOID_CMD ( HERMON_HCR_UNMAP_FA ),
+			    0, NULL, 0, NULL );
+}
+
+static inline int
+hermon_cmd_map_fa ( struct hermon *hermon,
+		    const struct hermonprm_virtual_physical_mapping *map ) {
+	return hermon_cmd ( hermon,
+			    HERMON_HCR_IN_CMD ( HERMON_HCR_MAP_FA,
+						1, sizeof ( *map ) ),
+			    0, map, 1, NULL );
+}
+
+/***************************************************************************
+ *
+ * Memory translation table operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate MTT entries
+ *
+ * @v hermon		Hermon device
+ * @v memory		Memory to map into MTT
+ * @v len		Length of memory to map
+ * @v mtt		MTT descriptor to fill in
+ * @ret rc		Return status code
+ */
+static int hermon_alloc_mtt ( struct hermon *hermon,
+			      const void *memory, size_t len,
+			      struct hermon_mtt *mtt ) {
+	struct hermonprm_write_mtt write_mtt;
+	physaddr_t start;
+	physaddr_t addr;
+	unsigned int page_offset;
+	unsigned int num_pages;
+	int mtt_offset;
+	unsigned int mtt_base_addr;
+	unsigned int i;
+	int rc;
+
+	/* Find available MTT entries */
+	start = virt_to_phys ( memory );
+	page_offset = ( start & ( HERMON_PAGE_SIZE - 1 ) );
+	start -= page_offset;
+	len += page_offset;
+	num_pages = ( ( len + HERMON_PAGE_SIZE - 1 ) / HERMON_PAGE_SIZE );
+	mtt_offset = hermon_bitmask_alloc ( hermon->mtt_inuse, HERMON_MAX_MTTS,
+					    num_pages );
+	if ( mtt_offset < 0 ) {
+		DBGC ( hermon, "Hermon %p could not allocate %d MTT entries\n",
+		       hermon, num_pages );
+		rc = mtt_offset;
+		goto err_mtt_offset;
+	}
+	mtt_base_addr = ( ( hermon->cap.reserved_mtts + mtt_offset ) *
+			  hermon->cap.mtt_entry_size );
+	addr = start;
+
+	/* Fill in MTT structure */
+	mtt->mtt_offset = mtt_offset;
+	mtt->num_pages = num_pages;
+	mtt->mtt_base_addr = mtt_base_addr;
+	mtt->page_offset = page_offset;
+
+	/* Construct and issue WRITE_MTT commands */
+	for ( i = 0 ; i < num_pages ; i++ ) {
+		memset ( &write_mtt, 0, sizeof ( write_mtt ) );
+		MLX_FILL_1 ( &write_mtt.mtt_base_addr, 1,
+			     value, mtt_base_addr );
+		MLX_FILL_H ( &write_mtt.mtt, 0, ptag_h, addr );
+		MLX_FILL_2 ( &write_mtt.mtt, 1,
+			     p, 1,
+			     ptag_l, ( addr >> 3 ) );
+		if ( ( rc = hermon_cmd_write_mtt ( hermon,
+						   &write_mtt ) ) != 0 ) {
+			DBGC ( hermon, "Hermon %p could not write MTT at %x\n",
+			       hermon, mtt_base_addr );
+			goto err_write_mtt;
+		}
+		addr += HERMON_PAGE_SIZE;
+		mtt_base_addr += hermon->cap.mtt_entry_size;
+	}
+
+	DBGC ( hermon, "Hermon %p MTT entries [%#x,%#x] for "
+	       "[%08lx,%08lx,%08lx,%08lx)\n", hermon, mtt->mtt_offset,
+	       ( mtt->mtt_offset + mtt->num_pages - 1 ), start,
+	       ( start + page_offset ), ( start + len ), addr );
+
+	return 0;
+
+ err_write_mtt:
+	hermon_bitmask_free ( hermon->mtt_inuse, mtt_offset, num_pages );
+ err_mtt_offset:
+	return rc;
+}
+
+/**
+ * Free MTT entries
+ *
+ * @v hermon		Hermon device
+ * @v mtt		MTT descriptor
+ */
+static void hermon_free_mtt ( struct hermon *hermon,
+			      struct hermon_mtt *mtt ) {
+
+	DBGC ( hermon, "Hermon %p MTT entries [%#x,%#x] freed\n",
+	       hermon, mtt->mtt_offset,
+	       ( mtt->mtt_offset + mtt->num_pages - 1 ) );
+	hermon_bitmask_free ( hermon->mtt_inuse, mtt->mtt_offset,
+			      mtt->num_pages );
+}
+
+/***************************************************************************
+ *
+ * Static configuration operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Calculate offset within static configuration
+ *
+ * @v field		Field
+ * @ret offset		Offset
+ */
+#define HERMON_MOD_STAT_CFG_OFFSET( field )				     \
+	( ( MLX_BIT_OFFSET ( struct hermonprm_mod_stat_cfg_st, field ) / 8 ) \
+	  & ~( sizeof ( struct hermonprm_scalar_parameter ) - 1 ) )
+
+/**
+ * Query or modify static configuration
+ *
+ * @v hermon		Hermon device
+ * @v port		Port
+ * @v mode		Command mode
+ * @v offset		Offset within static configuration
+ * @v stat_cfg		Static configuration
+ * @ret rc		Return status code
+ */
+static int hermon_mod_stat_cfg ( struct hermon *hermon, unsigned int port,
+				 unsigned int mode, unsigned int offset,
+				 struct hermonprm_mod_stat_cfg *stat_cfg ) {
+	struct hermonprm_scalar_parameter *portion =
+		( ( void * ) &stat_cfg->u.bytes[offset] );
+	struct hermonprm_mod_stat_cfg_input_mod mod;
+	int rc;
+
+	/* Sanity check */
+	assert ( ( offset % sizeof ( *portion ) ) == 0 );
+
+	/* Construct input modifier */
+	memset ( &mod, 0, sizeof ( mod ) );
+	MLX_FILL_2 ( &mod, 0,
+		     portnum, port,
+		     offset, offset );
+
+	/* Issue command */
+	if ( ( rc = hermon_cmd_mod_stat_cfg ( hermon, mode,
+					      be32_to_cpu ( mod.u.dwords[0] ),
+					      portion ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Management datagram
+ * @ret rc		Return status code
+ */
+static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	union hermonprm_mad mad_ifc;
+	int rc;
+
+	linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+			mad_size_mismatch );
+
+	/* Copy in request packet */
+	memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+	/* Issue MAD */
+	if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
+					 &mad_ifc ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not issue MAD IFC: "
+		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Copy out reply packet */
+	memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+	if ( mad->hdr.status != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d MAD IFC status %04x\n",
+		       hermon, ibdev->port, ntohs ( mad->hdr.status ) );
+		return -EIO;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Dump completion queue context (for debugging only)
+ *
+ * @v hermon		Hermon device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static __attribute__ (( unused )) int
+hermon_dump_cqctx ( struct hermon *hermon, struct ib_completion_queue *cq ) {
+	struct hermonprm_completion_queue_context cqctx;
+	int rc;
+
+	memset ( &cqctx, 0, sizeof ( cqctx ) );
+	if ( ( rc = hermon_cmd_query_cq ( hermon, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p CQN %#lx QUERY_CQ failed: %s\n",
+		       hermon, cq->cqn, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( hermon, "Hermon %p CQN %#lx context:\n", hermon, cq->cqn );
+	DBGC_HDA ( hermon, 0, &cqctx, sizeof ( cqctx ) );
+
+	return 0;
+}
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static int hermon_create_cq ( struct ib_device *ibdev,
+			      struct ib_completion_queue *cq ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_completion_queue *hermon_cq;
+	struct hermonprm_completion_queue_context cqctx;
+	int cqn_offset;
+	unsigned int i;
+	int rc;
+
+	/* Find a free completion queue number */
+	cqn_offset = hermon_bitmask_alloc ( hermon->cq_inuse,
+					    HERMON_MAX_CQS, 1 );
+	if ( cqn_offset < 0 ) {
+		DBGC ( hermon, "Hermon %p out of completion queues\n",
+		       hermon );
+		rc = cqn_offset;
+		goto err_cqn_offset;
+	}
+	cq->cqn = ( hermon->cap.reserved_cqs + cqn_offset );
+
+	/* Allocate control structures */
+	hermon_cq = zalloc ( sizeof ( *hermon_cq ) );
+	if ( ! hermon_cq ) {
+		rc = -ENOMEM;
+		goto err_hermon_cq;
+	}
+
+	/* Allocate doorbell */
+	hermon_cq->doorbell = malloc_dma ( sizeof ( hermon_cq->doorbell[0] ),
+					   sizeof ( hermon_cq->doorbell[0] ) );
+	if ( ! hermon_cq->doorbell ) {
+		rc = -ENOMEM;
+		goto err_doorbell;
+	}
+	memset ( hermon_cq->doorbell, 0, sizeof ( hermon_cq->doorbell[0] ) );
+
+	/* Allocate completion queue itself */
+	hermon_cq->cqe_size = ( cq->num_cqes * sizeof ( hermon_cq->cqe[0] ) );
+	hermon_cq->cqe = malloc_dma ( hermon_cq->cqe_size,
+				      sizeof ( hermon_cq->cqe[0] ) );
+	if ( ! hermon_cq->cqe ) {
+		rc = -ENOMEM;
+		goto err_cqe;
+	}
+	memset ( hermon_cq->cqe, 0, hermon_cq->cqe_size );
+	for ( i = 0 ; i < cq->num_cqes ; i++ ) {
+		MLX_FILL_1 ( &hermon_cq->cqe[i].normal, 7, owner, 1 );
+	}
+	barrier();
+
+	/* Allocate MTT entries */
+	if ( ( rc = hermon_alloc_mtt ( hermon, hermon_cq->cqe,
+				       hermon_cq->cqe_size,
+				       &hermon_cq->mtt ) ) != 0 )
+		goto err_alloc_mtt;
+
+	/* Hand queue over to hardware */
+	memset ( &cqctx, 0, sizeof ( cqctx ) );
+	MLX_FILL_1 ( &cqctx, 0, st, 0xa /* "Event fired" */ );
+	MLX_FILL_1 ( &cqctx, 2,
+		     page_offset, ( hermon_cq->mtt.page_offset >> 5 ) );
+	MLX_FILL_2 ( &cqctx, 3,
+		     usr_page, HERMON_UAR_NON_EQ_PAGE,
+		     log_cq_size, fls ( cq->num_cqes - 1 ) );
+	MLX_FILL_1 ( &cqctx, 5, c_eqn, hermon->eq.eqn );
+	MLX_FILL_H ( &cqctx, 6, mtt_base_addr_h,
+		     hermon_cq->mtt.mtt_base_addr );
+	MLX_FILL_1 ( &cqctx, 7, mtt_base_addr_l,
+		     ( hermon_cq->mtt.mtt_base_addr >> 3 ) );
+	MLX_FILL_H ( &cqctx, 14, db_record_addr_h,
+		     virt_to_phys ( hermon_cq->doorbell ) );
+	MLX_FILL_1 ( &cqctx, 15, db_record_addr_l,
+		     ( virt_to_phys ( hermon_cq->doorbell ) >> 3 ) );
+	if ( ( rc = hermon_cmd_sw2hw_cq ( hermon, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p CQN %#lx SW2HW_CQ failed: %s\n",
+		       hermon, cq->cqn, strerror ( rc ) );
+		goto err_sw2hw_cq;
+	}
+
+	DBGC ( hermon, "Hermon %p CQN %#lx ring [%08lx,%08lx), doorbell "
+	       "%08lx\n", hermon, cq->cqn, virt_to_phys ( hermon_cq->cqe ),
+	       ( virt_to_phys ( hermon_cq->cqe ) + hermon_cq->cqe_size ),
+	       virt_to_phys ( hermon_cq->doorbell ) );
+	ib_cq_set_drvdata ( cq, hermon_cq );
+	return 0;
+
+ err_sw2hw_cq:
+	hermon_free_mtt ( hermon, &hermon_cq->mtt );
+ err_alloc_mtt:
+	free_dma ( hermon_cq->cqe, hermon_cq->cqe_size );
+ err_cqe:
+	free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) );
+ err_doorbell:
+	free ( hermon_cq );
+ err_hermon_cq:
+	hermon_bitmask_free ( hermon->cq_inuse, cqn_offset, 1 );
+ err_cqn_offset:
+	return rc;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void hermon_destroy_cq ( struct ib_device *ibdev,
+				struct ib_completion_queue *cq ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
+	struct hermonprm_completion_queue_context cqctx;
+	int cqn_offset;
+	int rc;
+
+	/* Take ownership back from hardware */
+	if ( ( rc = hermon_cmd_hw2sw_cq ( hermon, cq->cqn, &cqctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p CQN %#lx FATAL HW2SW_CQ failed: "
+		       "%s\n", hermon, cq->cqn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Free MTT entries */
+	hermon_free_mtt ( hermon, &hermon_cq->mtt );
+
+	/* Free memory */
+	free_dma ( hermon_cq->cqe, hermon_cq->cqe_size );
+	free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) );
+	free ( hermon_cq );
+
+	/* Mark queue number as free */
+	cqn_offset = ( cq->cqn - hermon->cap.reserved_cqs );
+	hermon_bitmask_free ( hermon->cq_inuse, cqn_offset, 1 );
+
+	ib_cq_set_drvdata ( cq, NULL );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Assign queue pair number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int hermon_alloc_qpn ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	unsigned int port_offset;
+	int qpn_offset;
+
+	/* Calculate queue pair number */
+	port_offset = ( ibdev->port - HERMON_PORT_BASE );
+
+	switch ( qp->type ) {
+	case IB_QPT_SMI:
+		qp->qpn = ( hermon->special_qpn_base + port_offset );
+		return 0;
+	case IB_QPT_GSI:
+		qp->qpn = ( hermon->special_qpn_base + 2 + port_offset );
+		return 0;
+	case IB_QPT_UD:
+	case IB_QPT_RC:
+	case IB_QPT_ETH:
+		/* Find a free queue pair number */
+		qpn_offset = hermon_bitmask_alloc ( hermon->qp_inuse,
+						    HERMON_MAX_QPS, 1 );
+		if ( qpn_offset < 0 ) {
+			DBGC ( hermon, "Hermon %p out of queue pairs\n",
+			       hermon );
+			return qpn_offset;
+		}
+		qp->qpn = ( ( random() & HERMON_QPN_RANDOM_MASK ) |
+			    ( hermon->qpn_base + qpn_offset ) );
+		return 0;
+	default:
+		DBGC ( hermon, "Hermon %p unsupported QP type %d\n",
+		       hermon, qp->type );
+		return -ENOTSUP;
+	}
+}
+
+/**
+ * Free queue pair number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void hermon_free_qpn ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	int qpn_offset;
+
+	qpn_offset = ( ( qp->qpn & ~HERMON_QPN_RANDOM_MASK )
+		       - hermon->qpn_base );
+	if ( qpn_offset >= 0 )
+		hermon_bitmask_free ( hermon->qp_inuse, qpn_offset, 1 );
+}
+
+/**
+ * Calculate transmission rate
+ *
+ * @v av		Address vector
+ * @ret hermon_rate	Hermon rate
+ */
+static unsigned int hermon_rate ( struct ib_address_vector *av ) {
+	return ( ( ( av->rate >= IB_RATE_2_5 ) && ( av->rate <= IB_RATE_120 ) )
+		 ? ( av->rate + 5 ) : 0 );
+}
+
+/**
+ * Calculate schedule queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret sched_queue	Schedule queue
+ */
+static unsigned int hermon_sched_queue ( struct ib_device *ibdev,
+					 struct ib_queue_pair *qp ) {
+	return ( ( ( qp->type == IB_QPT_SMI ) ?
+		   HERMON_SCHED_QP0 : HERMON_SCHED_DEFAULT ) |
+		 ( ( ibdev->port - 1 ) << 6 ) );
+}
+
+/** Queue pair transport service type map */
+static uint8_t hermon_qp_st[] = {
+	[IB_QPT_SMI] = HERMON_ST_MLX,
+	[IB_QPT_GSI] = HERMON_ST_MLX,
+	[IB_QPT_UD] = HERMON_ST_UD,
+	[IB_QPT_RC] = HERMON_ST_RC,
+	[IB_QPT_ETH] = HERMON_ST_MLX,
+};
+
+/**
+ * Dump queue pair context (for debugging only)
+ *
+ * @v hermon		Hermon device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static __attribute__ (( unused )) int
+hermon_dump_qpctx ( struct hermon *hermon, struct ib_queue_pair *qp ) {
+	struct hermonprm_qp_ee_state_transitions qpctx;
+	int rc;
+
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	if ( ( rc = hermon_cmd_query_qp ( hermon, qp->qpn, &qpctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p QPN %#lx QUERY_QP failed: %s\n",
+		       hermon, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( hermon, "Hermon %p QPN %#lx context:\n", hermon, qp->qpn );
+	DBGC_HDA ( hermon, 0, &qpctx.u.dwords[2], ( sizeof ( qpctx ) - 8 ) );
+
+	return 0;
+}
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int hermon_create_qp ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_queue_pair *hermon_qp;
+	struct hermonprm_qp_ee_state_transitions qpctx;
+	int rc;
+
+	/* Calculate queue pair number */
+	if ( ( rc = hermon_alloc_qpn ( ibdev, qp ) ) != 0 )
+		goto err_alloc_qpn;
+
+	/* Allocate control structures */
+	hermon_qp = zalloc ( sizeof ( *hermon_qp ) );
+	if ( ! hermon_qp ) {
+		rc = -ENOMEM;
+		goto err_hermon_qp;
+	}
+
+	/* Allocate doorbells */
+	hermon_qp->recv.doorbell =
+		malloc_dma ( sizeof ( hermon_qp->recv.doorbell[0] ),
+			     sizeof ( hermon_qp->recv.doorbell[0] ) );
+	if ( ! hermon_qp->recv.doorbell ) {
+		rc = -ENOMEM;
+		goto err_recv_doorbell;
+	}
+	memset ( hermon_qp->recv.doorbell, 0,
+		 sizeof ( hermon_qp->recv.doorbell[0] ) );
+	hermon_qp->send.doorbell =
+		( hermon->uar + HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE +
+		  HERMON_DB_POST_SND_OFFSET );
+
+	/* Allocate work queue buffer */
+	hermon_qp->send.num_wqes = ( qp->send.num_wqes /* headroom */ + 1 +
+				( 2048 / sizeof ( hermon_qp->send.wqe[0] ) ) );
+	hermon_qp->send.num_wqes =
+		( 1 << fls ( hermon_qp->send.num_wqes - 1 ) ); /* round up */
+	hermon_qp->send.wqe_size = ( hermon_qp->send.num_wqes *
+				     sizeof ( hermon_qp->send.wqe[0] ) );
+	hermon_qp->recv.wqe_size = ( qp->recv.num_wqes *
+				     sizeof ( hermon_qp->recv.wqe[0] ) );
+	hermon_qp->wqe_size = ( hermon_qp->send.wqe_size +
+				hermon_qp->recv.wqe_size );
+	hermon_qp->wqe = malloc_dma ( hermon_qp->wqe_size,
+				      sizeof ( hermon_qp->send.wqe[0] ) );
+	if ( ! hermon_qp->wqe ) {
+		rc = -ENOMEM;
+		goto err_alloc_wqe;
+	}
+	hermon_qp->send.wqe = hermon_qp->wqe;
+	memset ( hermon_qp->send.wqe, 0xff, hermon_qp->send.wqe_size );
+	hermon_qp->recv.wqe = ( hermon_qp->wqe + hermon_qp->send.wqe_size );
+	memset ( hermon_qp->recv.wqe, 0, hermon_qp->recv.wqe_size );
+
+	/* Allocate MTT entries */
+	if ( ( rc = hermon_alloc_mtt ( hermon, hermon_qp->wqe,
+				       hermon_qp->wqe_size,
+				       &hermon_qp->mtt ) ) != 0 ) {
+		goto err_alloc_mtt;
+	}
+
+	/* Transition queue to INIT state */
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	MLX_FILL_2 ( &qpctx, 2,
+		     qpc_eec_data.pm_state, HERMON_PM_STATE_MIGRATED,
+		     qpc_eec_data.st, hermon_qp_st[qp->type] );
+	MLX_FILL_1 ( &qpctx, 3, qpc_eec_data.pd, HERMON_GLOBAL_PD );
+	MLX_FILL_4 ( &qpctx, 4,
+		     qpc_eec_data.log_rq_size, fls ( qp->recv.num_wqes - 1 ),
+		     qpc_eec_data.log_rq_stride,
+		     ( fls ( sizeof ( hermon_qp->recv.wqe[0] ) - 1 ) - 4 ),
+		     qpc_eec_data.log_sq_size,
+		     fls ( hermon_qp->send.num_wqes - 1 ),
+		     qpc_eec_data.log_sq_stride,
+		     ( fls ( sizeof ( hermon_qp->send.wqe[0] ) - 1 ) - 4 ) );
+	MLX_FILL_1 ( &qpctx, 5,
+		     qpc_eec_data.usr_page, HERMON_UAR_NON_EQ_PAGE );
+	MLX_FILL_1 ( &qpctx, 33, qpc_eec_data.cqn_snd, qp->send.cq->cqn );
+	MLX_FILL_4 ( &qpctx, 38,
+		     qpc_eec_data.rre, 1,
+		     qpc_eec_data.rwe, 1,
+		     qpc_eec_data.rae, 1,
+		     qpc_eec_data.page_offset,
+		     ( hermon_qp->mtt.page_offset >> 6 ) );
+	MLX_FILL_1 ( &qpctx, 41, qpc_eec_data.cqn_rcv, qp->recv.cq->cqn );
+	MLX_FILL_H ( &qpctx, 42, qpc_eec_data.db_record_addr_h,
+		     virt_to_phys ( hermon_qp->recv.doorbell ) );
+	MLX_FILL_1 ( &qpctx, 43, qpc_eec_data.db_record_addr_l,
+		     ( virt_to_phys ( hermon_qp->recv.doorbell ) >> 2 ) );
+	MLX_FILL_H ( &qpctx, 52, qpc_eec_data.mtt_base_addr_h,
+		     hermon_qp->mtt.mtt_base_addr );
+	MLX_FILL_1 ( &qpctx, 53, qpc_eec_data.mtt_base_addr_l,
+		     ( hermon_qp->mtt.mtt_base_addr >> 3 ) );
+	if ( ( rc = hermon_cmd_rst2init_qp ( hermon, qp->qpn,
+					     &qpctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p QPN %#lx RST2INIT_QP failed: %s\n",
+		       hermon, qp->qpn, strerror ( rc ) );
+		goto err_rst2init_qp;
+	}
+	hermon_qp->state = HERMON_QP_ST_INIT;
+
+	DBGC ( hermon, "Hermon %p QPN %#lx send ring [%08lx,%08lx), doorbell "
+	       "%08lx\n", hermon, qp->qpn,
+	       virt_to_phys ( hermon_qp->send.wqe ),
+	       ( virt_to_phys ( hermon_qp->send.wqe ) +
+		 hermon_qp->send.wqe_size ),
+	       virt_to_phys ( hermon_qp->send.doorbell ) );
+	DBGC ( hermon, "Hermon %p QPN %#lx receive ring [%08lx,%08lx), "
+	       "doorbell %08lx\n", hermon, qp->qpn,
+	       virt_to_phys ( hermon_qp->recv.wqe ),
+	       ( virt_to_phys ( hermon_qp->recv.wqe ) +
+		 hermon_qp->recv.wqe_size ),
+	       virt_to_phys ( hermon_qp->recv.doorbell ) );
+	DBGC ( hermon, "Hermon %p QPN %#lx send CQN %#lx receive CQN %#lx\n",
+	       hermon, qp->qpn, qp->send.cq->cqn, qp->recv.cq->cqn );
+	ib_qp_set_drvdata ( qp, hermon_qp );
+	return 0;
+
+	hermon_cmd_2rst_qp ( hermon, qp->qpn );
+ err_rst2init_qp:
+	hermon_free_mtt ( hermon, &hermon_qp->mtt );
+ err_alloc_mtt:
+	free_dma ( hermon_qp->wqe, hermon_qp->wqe_size );
+ err_alloc_wqe:
+	free_dma ( hermon_qp->recv.doorbell,
+		   sizeof ( hermon_qp->recv.doorbell[0] ) );
+ err_recv_doorbell:
+	free ( hermon_qp );
+ err_hermon_qp:
+	hermon_free_qpn ( ibdev, qp );
+ err_alloc_qpn:
+	return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int hermon_modify_qp ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
+	struct hermonprm_qp_ee_state_transitions qpctx;
+	int rc;
+
+	/* Transition queue to RTR state, if applicable */
+	if ( hermon_qp->state < HERMON_QP_ST_RTR ) {
+		memset ( &qpctx, 0, sizeof ( qpctx ) );
+		MLX_FILL_2 ( &qpctx, 4,
+			     qpc_eec_data.mtu,
+			     ( ( qp->type == IB_QPT_ETH ) ?
+			       HERMON_MTU_ETH : HERMON_MTU_2048 ),
+			     qpc_eec_data.msg_max, 31 );
+		MLX_FILL_1 ( &qpctx, 7,
+			     qpc_eec_data.remote_qpn_een, qp->av.qpn );
+		MLX_FILL_1 ( &qpctx, 9,
+			     qpc_eec_data.primary_address_path.rlid,
+			     qp->av.lid );
+		MLX_FILL_1 ( &qpctx, 10,
+			     qpc_eec_data.primary_address_path.max_stat_rate,
+			     hermon_rate ( &qp->av ) );
+		memcpy ( &qpctx.u.dwords[12], &qp->av.gid,
+			 sizeof ( qp->av.gid ) );
+		MLX_FILL_1 ( &qpctx, 16,
+			     qpc_eec_data.primary_address_path.sched_queue,
+			     hermon_sched_queue ( ibdev, qp ) );
+		MLX_FILL_1 ( &qpctx, 39,
+			     qpc_eec_data.next_rcv_psn, qp->recv.psn );
+		if ( ( rc = hermon_cmd_init2rtr_qp ( hermon, qp->qpn,
+						     &qpctx ) ) != 0 ) {
+			DBGC ( hermon, "Hermon %p QPN %#lx INIT2RTR_QP failed:"
+			       " %s\n", hermon, qp->qpn, strerror ( rc ) );
+			return rc;
+		}
+		hermon_qp->state = HERMON_QP_ST_RTR;
+	}
+
+	/* Transition queue to RTS state */
+	if ( hermon_qp->state < HERMON_QP_ST_RTS ) {
+		memset ( &qpctx, 0, sizeof ( qpctx ) );
+		MLX_FILL_1 ( &qpctx, 10,
+			     qpc_eec_data.primary_address_path.ack_timeout,
+			     14 /* 4.096us * 2^(14) = 67ms */ );
+		MLX_FILL_2 ( &qpctx, 30,
+			     qpc_eec_data.retry_count, HERMON_RETRY_MAX,
+			     qpc_eec_data.rnr_retry, HERMON_RETRY_MAX );
+		MLX_FILL_1 ( &qpctx, 32,
+			     qpc_eec_data.next_send_psn, qp->send.psn );
+		if ( ( rc = hermon_cmd_rtr2rts_qp ( hermon, qp->qpn,
+						    &qpctx ) ) != 0 ) {
+			DBGC ( hermon, "Hermon %p QPN %#lx RTR2RTS_QP failed: "
+			       "%s\n", hermon, qp->qpn, strerror ( rc ) );
+			return rc;
+		}
+		hermon_qp->state = HERMON_QP_ST_RTS;
+	}
+
+	/* Update parameters in RTS state */
+	memset ( &qpctx, 0, sizeof ( qpctx ) );
+	MLX_FILL_1 ( &qpctx, 0, opt_param_mask, HERMON_QP_OPT_PARAM_QKEY );
+	MLX_FILL_1 ( &qpctx, 44, qpc_eec_data.q_key, qp->qkey );
+	if ( ( rc = hermon_cmd_rts2rts_qp ( hermon, qp->qpn, &qpctx ) ) != 0 ){
+		DBGC ( hermon, "Hermon %p QPN %#lx RTS2RTS_QP failed: %s\n",
+		       hermon, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void hermon_destroy_qp ( struct ib_device *ibdev,
+				struct ib_queue_pair *qp ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
+	int rc;
+
+	/* Take ownership back from hardware */
+	if ( ( rc = hermon_cmd_2rst_qp ( hermon, qp->qpn ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p QPN %#lx FATAL 2RST_QP failed: %s\n",
+		       hermon, qp->qpn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Free MTT entries */
+	hermon_free_mtt ( hermon, &hermon_qp->mtt );
+
+	/* Free memory */
+	free_dma ( hermon_qp->wqe, hermon_qp->wqe_size );
+	free_dma ( hermon_qp->recv.doorbell,
+		   sizeof ( hermon_qp->recv.doorbell[0] ) );
+	free ( hermon_qp );
+
+	/* Mark queue number as free */
+	hermon_free_qpn ( ibdev, qp );
+
+	ib_qp_set_drvdata ( qp, NULL );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Construct UD send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret opcode		Control opcode
+ */
+static __attribute__ (( unused )) unsigned int
+hermon_fill_nop_send_wqe ( struct ib_device *ibdev __unused,
+			   struct ib_queue_pair *qp __unused,
+			   struct ib_address_vector *av __unused,
+			   struct io_buffer *iobuf __unused,
+			   union hermon_send_wqe *wqe ) {
+
+	MLX_FILL_1 ( &wqe->ctrl, 1, ds, ( sizeof ( wqe->ctrl ) / 16 ) );
+	MLX_FILL_1 ( &wqe->ctrl, 2, c, 0x03 /* generate completion */ );
+	return HERMON_OPCODE_NOP;
+}
+
+/**
+ * Construct UD send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret opcode		Control opcode
+ */
+static unsigned int
+hermon_fill_ud_send_wqe ( struct ib_device *ibdev,
+			  struct ib_queue_pair *qp __unused,
+			  struct ib_address_vector *av,
+			  struct io_buffer *iobuf,
+			  union hermon_send_wqe *wqe ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+
+	MLX_FILL_1 ( &wqe->ud.ctrl, 1, ds,
+		     ( ( offsetof ( typeof ( wqe->ud ), data[1] ) / 16 ) ) );
+	MLX_FILL_1 ( &wqe->ud.ctrl, 2, c, 0x03 /* generate completion */ );
+	MLX_FILL_2 ( &wqe->ud.ud, 0,
+		     ud_address_vector.pd, HERMON_GLOBAL_PD,
+		     ud_address_vector.port_number, ibdev->port );
+	MLX_FILL_2 ( &wqe->ud.ud, 1,
+		     ud_address_vector.rlid, av->lid,
+		     ud_address_vector.g, av->gid_present );
+	MLX_FILL_1 ( &wqe->ud.ud, 2,
+		     ud_address_vector.max_stat_rate, hermon_rate ( av ) );
+	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, av->sl );
+	memcpy ( &wqe->ud.ud.u.dwords[4], &av->gid, sizeof ( av->gid ) );
+	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, av->qpn );
+	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, av->qkey );
+	MLX_FILL_1 ( &wqe->ud.data[0], 0, byte_count, iob_len ( iobuf ) );
+	MLX_FILL_1 ( &wqe->ud.data[0], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->ud.data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->ud.data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+	return HERMON_OPCODE_SEND;
+}
+
+/**
+ * Construct MLX send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret opcode		Control opcode
+ */
+static unsigned int
+hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
+			   struct ib_queue_pair *qp,
+			   struct ib_address_vector *av,
+			   struct io_buffer *iobuf,
+			   union hermon_send_wqe *wqe ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct io_buffer headers;
+
+	/* Construct IB headers */
+	iob_populate ( &headers, &wqe->mlx.headers, 0,
+		       sizeof ( wqe->mlx.headers ) );
+	iob_reserve ( &headers, sizeof ( wqe->mlx.headers ) );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+	/* Fill work queue entry */
+	MLX_FILL_1 ( &wqe->mlx.ctrl, 1, ds,
+		     ( ( offsetof ( typeof ( wqe->mlx ), data[2] ) / 16 ) ) );
+	MLX_FILL_5 ( &wqe->mlx.ctrl, 2,
+		     c, 0x03 /* generate completion */,
+		     icrc, 0 /* generate ICRC */,
+		     max_statrate, hermon_rate ( av ),
+		     slr, 0,
+		     v15, ( ( qp->ext_qpn == IB_QPN_SMI ) ? 1 : 0 ) );
+	MLX_FILL_1 ( &wqe->mlx.ctrl, 3, rlid, av->lid );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 0,
+		     byte_count, iob_len ( &headers ) );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->mlx.data[0], 2,
+		     local_address_h, virt_to_bus ( headers.data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[0], 3,
+		     local_address_l, virt_to_bus ( headers.data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 0,
+		     byte_count, ( iob_len ( iobuf ) + 4 /* ICRC */ ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->mlx.data[1], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->mlx.data[1], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+	return HERMON_OPCODE_SEND;
+}
+
+/**
+ * Construct RC send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret opcode		Control opcode
+ */
+static unsigned int
+hermon_fill_rc_send_wqe ( struct ib_device *ibdev,
+			  struct ib_queue_pair *qp __unused,
+			  struct ib_address_vector *av __unused,
+			  struct io_buffer *iobuf,
+			  union hermon_send_wqe *wqe ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+
+	MLX_FILL_1 ( &wqe->rc.ctrl, 1, ds,
+		     ( ( offsetof ( typeof ( wqe->rc ), data[1] ) / 16 ) ) );
+	MLX_FILL_1 ( &wqe->rc.ctrl, 2, c, 0x03 /* generate completion */ );
+	MLX_FILL_1 ( &wqe->rc.data[0], 0, byte_count, iob_len ( iobuf ) );
+	MLX_FILL_1 ( &wqe->rc.data[0], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->rc.data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->rc.data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+	return HERMON_OPCODE_SEND;
+}
+
+/**
+ * Construct Ethernet send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret opcode		Control opcode
+ */
+static unsigned int
+hermon_fill_eth_send_wqe ( struct ib_device *ibdev,
+			   struct ib_queue_pair *qp __unused,
+			   struct ib_address_vector *av __unused,
+			   struct io_buffer *iobuf,
+			   union hermon_send_wqe *wqe ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+
+	/* Fill work queue entry */
+	MLX_FILL_1 ( &wqe->eth.ctrl, 1, ds,
+		     ( ( offsetof ( typeof ( wqe->mlx ), data[1] ) / 16 ) ) );
+	MLX_FILL_2 ( &wqe->eth.ctrl, 2,
+		     c, 0x03 /* generate completion */,
+		     s, 1 /* inhibit ICRC */ );
+	MLX_FILL_1 ( &wqe->eth.data[0], 0,
+		     byte_count, iob_len ( iobuf ) );
+	MLX_FILL_1 ( &wqe->eth.data[0], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->eth.data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->eth.data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+	return HERMON_OPCODE_SEND;
+}
+
+/** Work queue entry constructors */
+static unsigned int
+( * hermon_fill_send_wqe[] ) ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp,
+			       struct ib_address_vector *av,
+			       struct io_buffer *iobuf,
+			       union hermon_send_wqe *wqe ) = {
+	[IB_QPT_SMI] = hermon_fill_mlx_send_wqe,
+	[IB_QPT_GSI] = hermon_fill_mlx_send_wqe,
+	[IB_QPT_UD] = hermon_fill_ud_send_wqe,
+	[IB_QPT_RC] = hermon_fill_rc_send_wqe,
+	[IB_QPT_ETH] = hermon_fill_eth_send_wqe,
+};
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int hermon_post_send ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct ib_address_vector *av,
+			      struct io_buffer *iobuf ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
+	struct ib_work_queue *wq = &qp->send;
+	struct hermon_send_work_queue *hermon_send_wq = &hermon_qp->send;
+	union hermon_send_wqe *wqe;
+	union hermonprm_doorbell_register db_reg;
+	unsigned long wqe_idx_mask;
+	unsigned long wqe_idx;
+	unsigned int owner;
+	unsigned int opcode;
+
+	/* Allocate work queue entry */
+	wqe_idx = ( wq->next_idx & ( hermon_send_wq->num_wqes - 1 ) );
+	owner = ( ( wq->next_idx & hermon_send_wq->num_wqes ) ? 1 : 0 );
+	wqe_idx_mask = ( wq->num_wqes - 1 );
+	if ( wq->iobufs[ wqe_idx & wqe_idx_mask ] ) {
+		DBGC ( hermon, "Hermon %p QPN %#lx send queue full",
+		       hermon, qp->qpn );
+		return -ENOBUFS;
+	}
+	wq->iobufs[ wqe_idx & wqe_idx_mask ] = iobuf;
+	wqe = &hermon_send_wq->wqe[wqe_idx];
+
+	/* Construct work queue entry */
+	memset ( ( ( ( void * ) wqe ) + 4 /* avoid ctrl.owner */ ), 0,
+		   ( sizeof ( *wqe ) - 4 ) );
+	assert ( qp->type < ( sizeof ( hermon_fill_send_wqe ) /
+			      sizeof ( hermon_fill_send_wqe[0] ) ) );
+	assert ( hermon_fill_send_wqe[qp->type] != NULL );
+	opcode = hermon_fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf, wqe );
+	barrier();
+	MLX_FILL_2 ( &wqe->ctrl, 0,
+		     opcode, opcode,
+		     owner, owner );
+	DBGCP ( hermon, "Hermon %p QPN %#lx posting send WQE %#lx:\n",
+		hermon, qp->qpn, wqe_idx );
+	DBGCP_HDA ( hermon, virt_to_phys ( wqe ), wqe, sizeof ( *wqe ) );
+
+	/* Ring doorbell register */
+	MLX_FILL_1 ( &db_reg.send, 0, qn, qp->qpn );
+	barrier();
+	writel ( db_reg.dword[0], hermon_send_wq->doorbell );
+
+	/* Update work queue's index */
+	wq->next_idx++;
+
+	return 0;
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int hermon_post_recv ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct io_buffer *iobuf ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
+	struct ib_work_queue *wq = &qp->recv;
+	struct hermon_recv_work_queue *hermon_recv_wq = &hermon_qp->recv;
+	struct hermonprm_recv_wqe *wqe;
+	unsigned int wqe_idx_mask;
+
+	/* Allocate work queue entry */
+	wqe_idx_mask = ( wq->num_wqes - 1 );
+	if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
+		DBGC ( hermon, "Hermon %p QPN %#lx receive queue full",
+		       hermon, qp->qpn );
+		return -ENOBUFS;
+	}
+	wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
+	wqe = &hermon_recv_wq->wqe[wq->next_idx & wqe_idx_mask].recv;
+
+	/* Construct work queue entry */
+	MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
+	MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->lkey );
+	MLX_FILL_H ( &wqe->data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+
+	/* Update work queue's index */
+	wq->next_idx++;
+
+	/* Update doorbell record */
+	barrier();
+	MLX_FILL_1 ( hermon_recv_wq->doorbell, 0, receive_wqe_counter,
+		     ( wq->next_idx & 0xffff ) );
+
+	return 0;
+}
+
+/**
+ * Handle completion
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @v cqe		Hardware completion queue entry
+ * @ret rc		Return status code
+ */
+static int hermon_complete ( struct ib_device *ibdev,
+			     struct ib_completion_queue *cq,
+			     union hermonprm_completion_entry *cqe ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq;
+	struct ib_queue_pair *qp;
+	struct io_buffer *iobuf;
+	struct ib_address_vector recv_av;
+	struct ib_global_route_header *grh;
+	struct ib_address_vector *av;
+	unsigned int opcode;
+	unsigned long qpn;
+	int is_send;
+	unsigned long wqe_idx;
+	unsigned long wqe_idx_mask;
+	size_t len;
+	int rc = 0;
+
+	/* Parse completion */
+	qpn = MLX_GET ( &cqe->normal, qpn );
+	is_send = MLX_GET ( &cqe->normal, s_r );
+	opcode = MLX_GET ( &cqe->normal, opcode );
+	if ( opcode >= HERMON_OPCODE_RECV_ERROR ) {
+		/* "s" field is not valid for error opcodes */
+		is_send = ( opcode == HERMON_OPCODE_SEND_ERROR );
+		DBGC ( hermon, "Hermon %p CQN %#lx syndrome %x vendor %x\n",
+		       hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
+		       MLX_GET ( &cqe->error, vendor_error_syndrome ) );
+		rc = -EIO;
+		/* Don't return immediately; propagate error to completer */
+	}
+
+	/* Identify work queue */
+	wq = ib_find_wq ( cq, qpn, is_send );
+	if ( ! wq ) {
+		DBGC ( hermon, "Hermon %p CQN %#lx unknown %s QPN %#lx\n",
+		       hermon, cq->cqn, ( is_send ? "send" : "recv" ), qpn );
+		return -EIO;
+	}
+	qp = wq->qp;
+
+	/* Identify work queue entry */
+	wqe_idx = MLX_GET ( &cqe->normal, wqe_counter );
+	wqe_idx_mask = ( wq->num_wqes - 1 );
+	DBGCP ( hermon, "Hermon %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n",
+		hermon, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ),
+		wqe_idx );
+	DBGCP_HDA ( hermon, virt_to_phys ( cqe ), cqe, sizeof ( *cqe ) );
+
+	/* Identify I/O buffer */
+	iobuf = wq->iobufs[ wqe_idx & wqe_idx_mask ];
+	if ( ! iobuf ) {
+		DBGC ( hermon, "Hermon %p CQN %#lx QPN %#lx empty %s WQE "
+		       "%#lx\n", hermon, cq->cqn, qp->qpn,
+		       ( is_send ? "send" : "recv" ), wqe_idx );
+		return -EIO;
+	}
+	wq->iobufs[ wqe_idx & wqe_idx_mask ] = NULL;
+
+	if ( is_send ) {
+		/* Hand off to completion handler */
+		ib_complete_send ( ibdev, qp, iobuf, rc );
+	} else {
+		/* Set received length */
+		len = MLX_GET ( &cqe->normal, byte_cnt );
+		assert ( len <= iob_tailroom ( iobuf ) );
+		iob_put ( iobuf, len );
+		memset ( &recv_av, 0, sizeof ( recv_av ) );
+		switch ( qp->type ) {
+		case IB_QPT_SMI:
+		case IB_QPT_GSI:
+		case IB_QPT_UD:
+			assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+			grh = iobuf->data;
+			iob_pull ( iobuf, sizeof ( *grh ) );
+			/* Construct address vector */
+			av = &recv_av;
+			av->qpn = MLX_GET ( &cqe->normal, srq_rqpn );
+			av->lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
+			av->sl = MLX_GET ( &cqe->normal, sl );
+			av->gid_present = MLX_GET ( &cqe->normal, g );
+			memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+			break;
+		case IB_QPT_RC:
+			av = &qp->av;
+			break;
+		case IB_QPT_ETH:
+			/* Construct address vector */
+			av = &recv_av;
+			av->vlan_present = MLX_GET ( &cqe->normal, vlan );
+			av->vlan = MLX_GET ( &cqe->normal, vid );
+			break;
+		default:
+			assert ( 0 );
+			return -EINVAL;
+		}
+		/* Hand off to completion handler */
+		ib_complete_recv ( ibdev, qp, av, iobuf, rc );
+	}
+
+	return rc;
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void hermon_poll_cq ( struct ib_device *ibdev,
+			     struct ib_completion_queue *cq ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
+	union hermonprm_completion_entry *cqe;
+	unsigned int cqe_idx_mask;
+	int rc;
+
+	while ( 1 ) {
+		/* Look for completion entry */
+		cqe_idx_mask = ( cq->num_cqes - 1 );
+		cqe = &hermon_cq->cqe[cq->next_idx & cqe_idx_mask];
+		if ( MLX_GET ( &cqe->normal, owner ) ^
+		     ( ( cq->next_idx & cq->num_cqes ) ? 1 : 0 ) ) {
+			/* Entry still owned by hardware; end of poll */
+			break;
+		}
+
+		/* Handle completion */
+		if ( ( rc = hermon_complete ( ibdev, cq, cqe ) ) != 0 ) {
+			DBGC ( hermon, "Hermon %p CQN %#lx failed to complete:"
+			       " %s\n", hermon, cq->cqn, strerror ( rc ) );
+			DBGC_HDA ( hermon, virt_to_phys ( cqe ),
+				   cqe, sizeof ( *cqe ) );
+		}
+
+		/* Update completion queue's index */
+		cq->next_idx++;
+
+		/* Update doorbell record */
+		MLX_FILL_1 ( hermon_cq->doorbell, 0, update_ci,
+			     ( cq->next_idx & 0x00ffffffUL ) );
+	}
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create event queue
+ *
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
+ */
+static int hermon_create_eq ( struct hermon *hermon ) {
+	struct hermon_event_queue *hermon_eq = &hermon->eq;
+	struct hermonprm_eqc eqctx;
+	struct hermonprm_event_mask mask;
+	unsigned int i;
+	int rc;
+
+	/* Select event queue number */
+	hermon_eq->eqn = ( 4 * hermon->cap.reserved_uars );
+	if ( hermon_eq->eqn < hermon->cap.reserved_eqs )
+		hermon_eq->eqn = hermon->cap.reserved_eqs;
+
+	/* Calculate doorbell address */
+	hermon_eq->doorbell =
+		( hermon->uar + HERMON_DB_EQ_OFFSET ( hermon_eq->eqn ) );
+
+	/* Allocate event queue itself */
+	hermon_eq->eqe_size =
+		( HERMON_NUM_EQES * sizeof ( hermon_eq->eqe[0] ) );
+	hermon_eq->eqe = malloc_dma ( hermon_eq->eqe_size,
+				      sizeof ( hermon_eq->eqe[0] ) );
+	if ( ! hermon_eq->eqe ) {
+		rc = -ENOMEM;
+		goto err_eqe;
+	}
+	memset ( hermon_eq->eqe, 0, hermon_eq->eqe_size );
+	for ( i = 0 ; i < HERMON_NUM_EQES ; i++ ) {
+		MLX_FILL_1 ( &hermon_eq->eqe[i].generic, 7, owner, 1 );
+	}
+	barrier();
+
+	/* Allocate MTT entries */
+	if ( ( rc = hermon_alloc_mtt ( hermon, hermon_eq->eqe,
+				       hermon_eq->eqe_size,
+				       &hermon_eq->mtt ) ) != 0 )
+		goto err_alloc_mtt;
+
+	/* Hand queue over to hardware */
+	memset ( &eqctx, 0, sizeof ( eqctx ) );
+	MLX_FILL_2 ( &eqctx, 0,
+		     st, 0xa /* "Fired" */,
+		     oi, 1 );
+	MLX_FILL_1 ( &eqctx, 2,
+		     page_offset, ( hermon_eq->mtt.page_offset >> 5 ) );
+	MLX_FILL_1 ( &eqctx, 3, log_eq_size, fls ( HERMON_NUM_EQES - 1 ) );
+	MLX_FILL_H ( &eqctx, 6, mtt_base_addr_h,
+		     hermon_eq->mtt.mtt_base_addr );
+	MLX_FILL_1 ( &eqctx, 7, mtt_base_addr_l,
+		     ( hermon_eq->mtt.mtt_base_addr >> 3 ) );
+	if ( ( rc = hermon_cmd_sw2hw_eq ( hermon, hermon_eq->eqn,
+					  &eqctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p EQN %#lx SW2HW_EQ failed: %s\n",
+		       hermon, hermon_eq->eqn, strerror ( rc ) );
+		goto err_sw2hw_eq;
+	}
+
+	/* Map all events to this event queue */
+	memset ( &mask, 0xff, sizeof ( mask ) );
+	if ( ( rc = hermon_cmd_map_eq ( hermon,
+					( HERMON_MAP_EQ | hermon_eq->eqn ),
+					&mask ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p EQN %#lx MAP_EQ failed: %s\n",
+		       hermon, hermon_eq->eqn, strerror ( rc )  );
+		goto err_map_eq;
+	}
+
+	DBGC ( hermon, "Hermon %p EQN %#lx ring [%08lx,%08lx), doorbell "
+	       "%08lx\n", hermon, hermon_eq->eqn,
+	       virt_to_phys ( hermon_eq->eqe ),
+	       ( virt_to_phys ( hermon_eq->eqe ) + hermon_eq->eqe_size ),
+	       virt_to_phys ( hermon_eq->doorbell ) );
+	return 0;
+
+ err_map_eq:
+	hermon_cmd_hw2sw_eq ( hermon, hermon_eq->eqn, &eqctx );
+ err_sw2hw_eq:
+	hermon_free_mtt ( hermon, &hermon_eq->mtt );
+ err_alloc_mtt:
+	free_dma ( hermon_eq->eqe, hermon_eq->eqe_size );
+ err_eqe:
+	memset ( hermon_eq, 0, sizeof ( *hermon_eq ) );
+	return rc;
+}
+
+/**
+ * Destroy event queue
+ *
+ * @v hermon		Hermon device
+ */
+static void hermon_destroy_eq ( struct hermon *hermon ) {
+	struct hermon_event_queue *hermon_eq = &hermon->eq;
+	struct hermonprm_eqc eqctx;
+	struct hermonprm_event_mask mask;
+	int rc;
+
+	/* Unmap events from event queue */
+	memset ( &mask, 0xff, sizeof ( mask ) );
+	if ( ( rc = hermon_cmd_map_eq ( hermon,
+					( HERMON_UNMAP_EQ | hermon_eq->eqn ),
+					&mask ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p EQN %#lx FATAL MAP_EQ failed to "
+		       "unmap: %s\n", hermon, hermon_eq->eqn, strerror ( rc ) );
+		/* Continue; HCA may die but system should survive */
+	}
+
+	/* Take ownership back from hardware */
+	if ( ( rc = hermon_cmd_hw2sw_eq ( hermon, hermon_eq->eqn,
+					  &eqctx ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p EQN %#lx FATAL HW2SW_EQ failed: %s\n",
+		       hermon, hermon_eq->eqn, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+
+	/* Free MTT entries */
+	hermon_free_mtt ( hermon, &hermon_eq->mtt );
+
+	/* Free memory */
+	free_dma ( hermon_eq->eqe, hermon_eq->eqe_size );
+	memset ( hermon_eq, 0, sizeof ( *hermon_eq ) );
+}
+
+/**
+ * Handle port state event
+ *
+ * @v hermon		Hermon device
+ * @v eqe		Port state change event queue entry
+ */
+static void hermon_event_port_state_change ( struct hermon *hermon,
+					     union hermonprm_event_entry *eqe){
+	unsigned int port;
+	int link_up;
+
+	/* Get port and link status */
+	port = ( MLX_GET ( &eqe->port_state_change, data.p ) - 1 );
+	link_up = ( MLX_GET ( &eqe->generic, event_sub_type ) & 0x04 );
+	DBGC ( hermon, "Hermon %p port %d link %s\n", hermon, ( port + 1 ),
+	       ( link_up ? "up" : "down" ) );
+
+	/* Sanity check */
+	if ( port >= hermon->cap.num_ports ) {
+		DBGC ( hermon, "Hermon %p port %d does not exist!\n",
+		       hermon, ( port + 1 ) );
+		return;
+	}
+
+	/* Notify device of port state change */
+	hermon->port[port].type->state_change ( hermon, &hermon->port[port],
+						link_up );
+}
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev		Infiniband device
+ */
+static void hermon_poll_eq ( struct ib_device *ibdev ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermon_event_queue *hermon_eq = &hermon->eq;
+	union hermonprm_event_entry *eqe;
+	union hermonprm_doorbell_register db_reg;
+	unsigned int eqe_idx_mask;
+	unsigned int event_type;
+
+	/* No event is generated upon reaching INIT, so we must poll
+	 * separately for link state changes while we remain DOWN.
+	 */
+	if ( ib_is_open ( ibdev ) &&
+	     ( ibdev->port_state == IB_PORT_STATE_DOWN ) ) {
+		ib_smc_update ( ibdev, hermon_mad );
+	}
+
+	/* Poll event queue */
+	while ( 1 ) {
+		/* Look for event entry */
+		eqe_idx_mask = ( HERMON_NUM_EQES - 1 );
+		eqe = &hermon_eq->eqe[hermon_eq->next_idx & eqe_idx_mask];
+		if ( MLX_GET ( &eqe->generic, owner ) ^
+		     ( ( hermon_eq->next_idx & HERMON_NUM_EQES ) ? 1 : 0 ) ) {
+			/* Entry still owned by hardware; end of poll */
+			break;
+		}
+		DBGCP ( hermon, "Hermon %p EQN %#lx event:\n",
+			hermon, hermon_eq->eqn );
+		DBGCP_HDA ( hermon, virt_to_phys ( eqe ),
+			    eqe, sizeof ( *eqe ) );
+
+		/* Handle event */
+		event_type = MLX_GET ( &eqe->generic, event_type );
+		switch ( event_type ) {
+		case HERMON_EV_PORT_STATE_CHANGE:
+			hermon_event_port_state_change ( hermon, eqe );
+			break;
+		default:
+			DBGC ( hermon, "Hermon %p EQN %#lx unrecognised event "
+			       "type %#x:\n",
+			       hermon, hermon_eq->eqn, event_type );
+			DBGC_HDA ( hermon, virt_to_phys ( eqe ),
+				   eqe, sizeof ( *eqe ) );
+			break;
+		}
+
+		/* Update event queue's index */
+		hermon_eq->next_idx++;
+
+		/* Ring doorbell */
+		MLX_FILL_1 ( &db_reg.event, 0,
+			     ci, ( hermon_eq->next_idx & 0x00ffffffUL ) );
+		writel ( db_reg.dword[0], hermon_eq->doorbell );
+	}
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int hermon_open ( struct ib_device *ibdev ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	union hermonprm_set_port set_port;
+	int rc;
+
+	/* Set port parameters */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_8 ( &set_port.ib, 0,
+		     mmc, 1,
+		     mvc, 1,
+		     mp, 1,
+		     mg, 1,
+		     mtu_cap, IB_MTU_2048,
+		     vl_cap, IB_VL_0,
+		     rcm, 1,
+		     lss, 1 );
+	MLX_FILL_2 ( &set_port.ib, 10,
+		     max_pkey, 1,
+		     max_gid, 1 );
+	MLX_FILL_1 ( &set_port.ib, 28,
+		     link_speed_supported, 1 );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 0, ibdev->port,
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Initialise port */
+	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
+		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, hermon_mad );
+
+	return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ */
+static void hermon_close ( struct ib_device *ibdev ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	int rc;
+
+	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		/* Nothing we can do about this */
+	}
+}
+
+/**
+ * Inform embedded subnet management agent of a received MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		MAD
+ * @ret rc		Return status code
+ */
+static int hermon_inform_sma ( struct ib_device *ibdev,
+			       union ib_mad *mad ) {
+	int rc;
+
+	/* Send the MAD to the embedded SMA */
+	if ( ( rc = hermon_mad ( ibdev, mad ) ) != 0 )
+		return rc;
+
+	/* Update parameters held in software */
+	ib_smc_update ( ibdev, hermon_mad );
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ * @ret rc		Return status code
+ */
+static int hermon_mcast_attach ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp,
+				 union ib_gid *gid ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermonprm_mgm_hash hash;
+	struct hermonprm_mcg_entry mcg;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+		       hermon, strerror ( rc ) );
+		return rc;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Check for existing hash table entry */
+	if ( ( rc = hermon_cmd_read_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not read MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return rc;
+	}
+	if ( MLX_GET ( &mcg, hdr.members_count ) != 0 ) {
+		/* FIXME: this implementation allows only a single QP
+		 * per multicast group, and doesn't handle hash
+		 * collisions.  Sufficient for IPoIB but may need to
+		 * be extended in future.
+		 */
+		DBGC ( hermon, "Hermon %p MGID index %#x already in use\n",
+		       hermon, index );
+		return -EBUSY;
+	}
+
+	/* Update hash table entry */
+	MLX_FILL_1 ( &mcg, 1, hdr.members_count, 1 );
+	MLX_FILL_1 ( &mcg, 8, qp[0].qpn, qp->qpn );
+	memcpy ( &mcg.u.dwords[4], gid, sizeof ( *gid ) );
+	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void hermon_mcast_detach ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp __unused,
+				  union ib_gid *gid ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermonprm_mgm_hash hash;
+	struct hermonprm_mcg_entry mcg;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+		       hermon, strerror ( rc ) );
+		return;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Clear hash table entry */
+	memset ( &mcg, 0, sizeof ( mcg ) );
+	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return;
+	}
+}
+
+/** Hermon Infiniband operations */
+static struct ib_device_operations hermon_ib_operations = {
+	.create_cq	= hermon_create_cq,
+	.destroy_cq	= hermon_destroy_cq,
+	.create_qp	= hermon_create_qp,
+	.modify_qp	= hermon_modify_qp,
+	.destroy_qp	= hermon_destroy_qp,
+	.post_send	= hermon_post_send,
+	.post_recv	= hermon_post_recv,
+	.poll_cq	= hermon_poll_cq,
+	.poll_eq	= hermon_poll_eq,
+	.open		= hermon_open,
+	.close		= hermon_close,
+	.mcast_attach	= hermon_mcast_attach,
+	.mcast_detach	= hermon_mcast_detach,
+	.set_port_info	= hermon_inform_sma,
+	.set_pkey_table	= hermon_inform_sma,
+};
+
+/**
+ * Register Hermon Infiniband device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
+ */
+static int hermon_register_ibdev ( struct hermon *hermon,
+				   struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	int rc;
+
+	/* Initialise parameters using SMC */
+	ib_smc_init ( ibdev, hermon_mad );
+
+	/* Register Infiniband device */
+	if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not register IB "
+		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle Hermon Infiniband device port state change
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @v link_up		Link is up
+ */
+static void hermon_state_change_ibdev ( struct hermon *hermon __unused,
+					struct hermon_port *port,
+					int link_up __unused ) {
+	struct ib_device *ibdev = port->ibdev;
+
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, hermon_mad );
+}
+
+/**
+ * Unregister Hermon Infiniband device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ */
+static void hermon_unregister_ibdev ( struct hermon *hermon __unused,
+				      struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+
+	unregister_ibdev ( ibdev );
+}
+
+/** Hermon Infiniband port type */
+static struct hermon_port_type hermon_port_type_ib = {
+	.register_dev = hermon_register_ibdev,
+	.state_change = hermon_state_change_ibdev,
+	.unregister_dev = hermon_unregister_ibdev,
+};
+
+/***************************************************************************
+ *
+ * Ethernet operation
+ *
+ ***************************************************************************
+ */
+
+/** Number of Hermon Ethernet send work queue entries */
+#define HERMON_ETH_NUM_SEND_WQES 2
+
+/** Number of Hermon Ethernet receive work queue entries */
+#define HERMON_ETH_NUM_RECV_WQES 4
+
+/** Number of Hermon Ethernet completion entries */
+#define HERMON_ETH_NUM_CQES 8
+
+/**
+ * Transmit packet via Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int hermon_eth_transmit ( struct net_device *netdev,
+				 struct io_buffer *iobuf ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	int rc;
+
+	/* Transmit packet */
+	if ( ( rc = ib_post_send ( ibdev, port->eth_qp, NULL,
+				   iobuf ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not transmit: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle Hermon Ethernet device send completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void hermon_eth_complete_send ( struct ib_device *ibdev __unused,
+				       struct ib_queue_pair *qp,
+				       struct io_buffer *iobuf, int rc ) {
+	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
+
+	netdev_tx_complete_err ( netdev, iobuf, rc );
+}
+
+/**
+ * Handle Hermon Ethernet device receive completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector, or NULL
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void hermon_eth_complete_recv ( struct ib_device *ibdev __unused,
+				       struct ib_queue_pair *qp,
+				       struct ib_address_vector *av,
+				       struct io_buffer *iobuf, int rc ) {
+	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
+	struct net_device *vlan;
+
+	/* Find VLAN device, if applicable */
+	if ( av->vlan_present ) {
+		if ( ( vlan = vlan_find ( netdev, av->vlan ) ) != NULL ) {
+			netdev = vlan;
+		} else if ( rc == 0 ) {
+			rc = -ENODEV;
+		}
+	}
+
+	/* Hand off to network layer */
+	if ( rc == 0 ) {
+		netdev_rx ( netdev, iobuf );
+	} else {
+		netdev_rx_err ( netdev, iobuf, rc );
+	}
+}
+
+/** Hermon Ethernet device completion operations */
+static struct ib_completion_queue_operations hermon_eth_cq_op = {
+	.complete_send = hermon_eth_complete_send,
+	.complete_recv = hermon_eth_complete_recv,
+};
+
+/**
+ * Poll Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ */
+static void hermon_eth_poll ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+
+	ib_poll_eq ( ibdev );
+}
+
+/**
+ * Open Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int hermon_eth_open ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	union hermonprm_set_port set_port;
+	int rc;
+
+	/* Allocate completion queue */
+	port->eth_cq = ib_create_cq ( ibdev, HERMON_ETH_NUM_CQES,
+				      &hermon_eth_cq_op );
+	if ( ! port->eth_cq ) {
+		DBGC ( hermon, "Hermon %p port %d could not create completion "
+		       "queue\n", hermon, ibdev->port );
+		rc = -ENOMEM;
+		goto err_create_cq;
+	}
+
+	/* Allocate queue pair */
+	port->eth_qp = ib_create_qp ( ibdev, IB_QPT_ETH,
+				      HERMON_ETH_NUM_SEND_WQES, port->eth_cq,
+				      HERMON_ETH_NUM_RECV_WQES, port->eth_cq );
+	if ( ! port->eth_qp ) {
+		DBGC ( hermon, "Hermon %p port %d could not create queue "
+		       "pair\n", hermon, ibdev->port );
+		rc = -ENOMEM;
+		goto err_create_qp;
+	}
+	ib_qp_set_ownerdata ( port->eth_qp, netdev );
+
+	/* Activate queue pair */
+	if ( ( rc = ib_modify_qp ( ibdev, port->eth_qp ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not modify queue "
+		       "pair: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_modify_qp;
+	}
+
+	/* Fill receive rings */
+	ib_refill_recv ( ibdev, port->eth_qp );
+
+	/* Set port general parameters */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_3 ( &set_port.general, 0,
+		     v_mtu, 1,
+		     v_pprx, 1,
+		     v_pptx, 1 );
+	MLX_FILL_1 ( &set_port.general, 1,
+		     mtu, ( ETH_FRAME_LEN + 40 /* Used by card */ ) );
+	MLX_FILL_1 ( &set_port.general, 2,
+		     pfctx, ( 1 << FCOE_VLAN_PRIORITY ) );
+	MLX_FILL_1 ( &set_port.general, 3,
+		     pfcrx, ( 1 << FCOE_VLAN_PRIORITY ) );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
+					  ( HERMON_SET_PORT_GENERAL_PARAM |
+					    ibdev->port ),
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port general "
+		       "parameters: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		goto err_set_port_general_params;
+	}
+
+	/* Set port receive QP */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_1 ( &set_port.rqp_calc, 0, base_qpn, port->eth_qp->qpn );
+	MLX_FILL_1 ( &set_port.rqp_calc, 2,
+		     mac_miss_index, 128 /* MAC misses go to promisc QP */ );
+	MLX_FILL_2 ( &set_port.rqp_calc, 3,
+		     vlan_miss_index, 127 /* VLAN misses go to promisc QP */,
+		     no_vlan_index, 126 /* VLAN-free go to promisc QP */ );
+	MLX_FILL_2 ( &set_port.rqp_calc, 5,
+		     promisc_qpn, port->eth_qp->qpn,
+		     en_uc_promisc, 1 );
+	MLX_FILL_2 ( &set_port.rqp_calc, 6,
+		     def_mcast_qpn, port->eth_qp->qpn,
+		     mc_promisc_mode, 2 /* Receive all multicasts */ );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
+					  ( HERMON_SET_PORT_RECEIVE_QP |
+					    ibdev->port ),
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port receive "
+		       "QP: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_set_port_receive_qp;
+	}
+
+	/* Initialise port */
+	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
+		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_init_port;
+	}
+
+	return 0;
+
+ err_init_port:
+ err_set_port_receive_qp:
+ err_set_port_general_params:
+ err_modify_qp:
+	ib_destroy_qp ( ibdev, port->eth_qp );
+ err_create_qp:
+	ib_destroy_cq ( ibdev, port->eth_cq );
+ err_create_cq:
+	return rc;
+}
+
+/**
+ * Close Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ */
+static void hermon_eth_close ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	int rc;
+
+	/* Close port */
+	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		/* Nothing we can do about this */
+	}
+
+	/* Tear down the queues */
+	ib_destroy_qp ( ibdev, port->eth_qp );
+	ib_destroy_cq ( ibdev, port->eth_cq );
+}
+
+/** Hermon Ethernet network device operations */
+static struct net_device_operations hermon_eth_operations = {
+	.open		= hermon_eth_open,
+	.close		= hermon_eth_close,
+	.transmit	= hermon_eth_transmit,
+	.poll		= hermon_eth_poll,
+};
+
+/**
+ * Register Hermon Ethernet device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
+ */
+static int hermon_register_netdev ( struct hermon *hermon,
+				    struct hermon_port *port ) {
+	struct net_device *netdev = port->netdev;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_query_port_cap query_port;
+	union {
+		uint8_t bytes[8];
+		uint32_t dwords[2];
+	} mac;
+	int rc;
+
+	/* Retrieve MAC address */
+	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
+					    &query_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+	mac.dwords[0] = htonl ( MLX_GET ( &query_port, mac_47_32 ) );
+	mac.dwords[1] = htonl ( MLX_GET ( &query_port, mac_31_0 ) );
+	memcpy ( netdev->hw_addr,
+		 &mac.bytes[ sizeof ( mac.bytes ) - ETH_ALEN ], ETH_ALEN );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not register network "
+		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle Hermon Ethernet device port state change
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @v link_up		Link is up
+ */
+static void hermon_state_change_netdev ( struct hermon *hermon __unused,
+					 struct hermon_port *port,
+					 int link_up ) {
+	struct net_device *netdev = port->netdev;
+
+	if ( link_up ) {
+		netdev_link_up ( netdev );
+	} else {
+		netdev_link_down ( netdev );
+	}
+}
+
+/**
+ * Unregister Hermon Ethernet device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ */
+static void hermon_unregister_netdev ( struct hermon *hermon __unused,
+				       struct hermon_port *port ) {
+	struct net_device *netdev = port->netdev;
+
+	unregister_netdev ( netdev );
+}
+
+/** Hermon Ethernet port type */
+static struct hermon_port_type hermon_port_type_eth = {
+	.register_dev = hermon_register_netdev,
+	.state_change = hermon_state_change_netdev,
+	.unregister_dev = hermon_unregister_netdev,
+};
+
+/***************************************************************************
+ *
+ * Port type detection
+ *
+ ***************************************************************************
+ */
+
+/** Timeout for port sensing */
+#define HERMON_SENSE_PORT_TIMEOUT ( TICKS_PER_SEC / 2 )
+
+/**
+ * Name port type
+ *
+ * @v port_type		Port type
+ * @v port_type_name	Port type name
+ */
+static inline const char * hermon_name_port_type ( unsigned int port_type ) {
+	switch ( port_type ) {
+	case HERMON_PORT_TYPE_UNKNOWN:	return "unknown";
+	case HERMON_PORT_TYPE_IB:	return "Infiniband";
+	case HERMON_PORT_TYPE_ETH:	return "Ethernet";
+	default:			return "INVALID";
+	}
+}
+
+/**
+ * Sense port type
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret port_type	Port type, or negative error
+ */
+static int hermon_sense_port_type ( struct hermon *hermon,
+				    struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_sense_port sense_port;
+	int port_type;
+	int rc;
+
+	/* If DPDP is not supported, always assume Infiniband */
+	if ( ! hermon->cap.dpdp ) {
+		port_type = HERMON_PORT_TYPE_IB;
+		DBGC ( hermon, "Hermon %p port %d does not support DPDP; "
+		       "assuming an %s network\n", hermon, ibdev->port,
+		       hermon_name_port_type ( port_type ) );
+		return port_type;
+	}
+
+	/* Sense the port type */
+	if ( ( rc = hermon_cmd_sense_port ( hermon, ibdev->port,
+					    &sense_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d sense failed: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+	port_type = MLX_GET ( &sense_port, port_type );
+
+	DBGC ( hermon, "Hermon %p port %d sensed an %s network\n",
+	       hermon, ibdev->port, hermon_name_port_type ( port_type ) );
+	return port_type;
+}
+
+/**
+ * Set port type
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
+ */
+static int hermon_set_port_type ( struct hermon *hermon,
+				  struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_query_port_cap query_port;
+	int ib_supported;
+	int eth_supported;
+	int port_type;
+	unsigned long start;
+	unsigned long elapsed;
+	int rc;
+
+	/* Check to see which types are supported */
+	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
+					    &query_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+	ib_supported = MLX_GET ( &query_port, ib );
+	eth_supported = MLX_GET ( &query_port, eth );
+	DBGC ( hermon, "Hermon %p port %d supports%s%s%s\n",
+	       hermon, ibdev->port, ( ib_supported ? " Infiniband" : "" ),
+	       ( ( ib_supported && eth_supported ) ? " and" : "" ),
+	       ( eth_supported ? " Ethernet" : "" ) );
+
+	/* Sense network, if applicable */
+	if ( ib_supported && eth_supported ) {
+
+		/* Both types are supported; try sensing network */
+		start = currticks();
+		do {
+			/* Try sensing port */
+			port_type = hermon_sense_port_type ( hermon, port );
+			if ( port_type < 0 ) {
+				rc = port_type;
+				return rc;
+			}
+		} while ( ( port_type == HERMON_PORT_TYPE_UNKNOWN ) &&
+			  ( ( elapsed = ( currticks() - start ) ) <
+			    HERMON_SENSE_PORT_TIMEOUT ) );
+
+		/* Set port type based on sensed network, defaulting
+		 * to Infiniband if nothing was sensed.
+		 */
+		switch ( port_type ) {
+		case HERMON_PORT_TYPE_ETH:
+			port->type = &hermon_port_type_eth;
+			break;
+		case HERMON_PORT_TYPE_IB:
+		case HERMON_PORT_TYPE_UNKNOWN:
+			port->type = &hermon_port_type_ib;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+	} else if ( eth_supported ) {
+		port->type = &hermon_port_type_eth;
+	} else {
+		port->type = &hermon_port_type_ib;
+	}
+
+	assert ( port->type != NULL );
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Firmware control
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Map virtual to physical address for firmware usage
+ *
+ * @v hermon		Hermon device
+ * @v map		Mapping function
+ * @v va		Virtual address
+ * @v pa		Physical address
+ * @v len		Length of region
+ * @ret rc		Return status code
+ */
+static int hermon_map_vpm ( struct hermon *hermon,
+			    int ( *map ) ( struct hermon *hermon,
+			    const struct hermonprm_virtual_physical_mapping* ),
+			    uint64_t va, physaddr_t pa, size_t len ) {
+	struct hermonprm_virtual_physical_mapping mapping;
+	physaddr_t start;
+	physaddr_t low;
+	physaddr_t high;
+	physaddr_t end;
+	size_t size;
+	int rc;
+
+	/* Sanity checks */
+	assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( len & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
+
+	/* Calculate starting points */
+	start = pa;
+	end = ( start + len );
+	size = ( 1UL << ( fls ( start ^ end ) - 1 ) );
+	low = high = ( end & ~( size - 1 ) );
+	assert ( start < low );
+	assert ( high <= end );
+
+	/* These mappings tend to generate huge volumes of
+	 * uninteresting debug data, which basically makes it
+	 * impossible to use debugging otherwise.
+	 */
+	DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+
+	/* Map blocks in descending order of size */
+	while ( size >= HERMON_PAGE_SIZE ) {
+
+		/* Find the next candidate block */
+		if ( ( low - size ) >= start ) {
+			low -= size;
+			pa = low;
+		} else if ( ( high + size ) <= end ) {
+			pa = high;
+			high += size;
+		} else {
+			size >>= 1;
+			continue;
+		}
+		assert ( ( va & ( size - 1 ) ) == 0 );
+		assert ( ( pa & ( size - 1 ) ) == 0 );
+
+		/* Map this block */
+		memset ( &mapping, 0, sizeof ( mapping ) );
+		MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
+		MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
+		MLX_FILL_H ( &mapping, 2, pa_h, pa );
+		MLX_FILL_2 ( &mapping, 3,
+			     log2size, ( ( fls ( size ) - 1 ) - 12 ),
+			     pa_l, ( pa >> 12 ) );
+		if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
+			DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+			DBGC ( hermon, "Hermon %p could not map %08llx+%zx to "
+			       "%08lx: %s\n",
+			       hermon, va, size, pa, strerror ( rc ) );
+			return rc;
+		}
+		va += size;
+	}
+	assert ( low == start );
+	assert ( high == end );
+
+	DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+	return 0;
+}
+
+/**
+ * Start firmware running
+ *
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
+ */
+static int hermon_start_firmware ( struct hermon *hermon ) {
+	struct hermonprm_query_fw fw;
+	unsigned int fw_pages;
+	size_t fw_size;
+	physaddr_t fw_base;
+	int rc;
+
+	/* Get firmware parameters */
+	if ( ( rc = hermon_cmd_query_fw ( hermon, &fw ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not query firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_query_fw;
+	}
+	DBGC ( hermon, "Hermon %p firmware version %d.%d.%d\n", hermon,
+	       MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
+	       MLX_GET ( &fw, fw_rev_subminor ) );
+	fw_pages = MLX_GET ( &fw, fw_pages );
+	DBGC ( hermon, "Hermon %p requires %d pages (%d kB) for firmware\n",
+	       hermon, fw_pages, ( fw_pages * 4 ) );
+
+	/* Allocate firmware pages and map firmware area */
+	fw_size = ( fw_pages * HERMON_PAGE_SIZE );
+	hermon->firmware_area = umalloc ( fw_size );
+	if ( ! hermon->firmware_area ) {
+		rc = -ENOMEM;
+		goto err_alloc_fa;
+	}
+	fw_base = user_to_phys ( hermon->firmware_area, 0 );
+	DBGC ( hermon, "Hermon %p firmware area at physical [%08lx,%08lx)\n",
+	       hermon, fw_base, ( fw_base + fw_size ) );
+	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_fa,
+				     0, fw_base, fw_size ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not map firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_map_fa;
+	}
+
+	/* Start firmware */
+	if ( ( rc = hermon_cmd_run_fw ( hermon ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not run firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_run_fw;
+	}
+
+	DBGC ( hermon, "Hermon %p firmware started\n", hermon );
+	return 0;
+
+ err_run_fw:
+ err_map_fa:
+	hermon_cmd_unmap_fa ( hermon );
+	ufree ( hermon->firmware_area );
+	hermon->firmware_area = UNULL;
+ err_alloc_fa:
+ err_query_fw:
+	return rc;
+}
+
+/**
+ * Stop firmware running
+ *
+ * @v hermon		Hermon device
+ */
+static void hermon_stop_firmware ( struct hermon *hermon ) {
+	int rc;
+
+	if ( ( rc = hermon_cmd_unmap_fa ( hermon ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p FATAL could not stop firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		return;
+	}
+	ufree ( hermon->firmware_area );
+	hermon->firmware_area = UNULL;
+}
+
+/***************************************************************************
+ *
+ * Infinihost Context Memory management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Get device limits
+ *
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
+ */
+static int hermon_get_cap ( struct hermon *hermon ) {
+	struct hermonprm_query_dev_cap dev_cap;
+	int rc;
+
+	if ( ( rc = hermon_cmd_query_dev_cap ( hermon, &dev_cap ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not get device limits: %s\n",
+		       hermon, strerror ( rc ) );
+		return rc;
+	}
+
+	hermon->cap.cmpt_entry_size = MLX_GET ( &dev_cap, c_mpt_entry_sz );
+	hermon->cap.reserved_qps =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_qps ) );
+	hermon->cap.qpc_entry_size = MLX_GET ( &dev_cap, qpc_entry_sz );
+	hermon->cap.altc_entry_size = MLX_GET ( &dev_cap, altc_entry_sz );
+	hermon->cap.auxc_entry_size = MLX_GET ( &dev_cap, aux_entry_sz );
+	hermon->cap.reserved_srqs =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_srqs ) );
+	hermon->cap.srqc_entry_size = MLX_GET ( &dev_cap, srq_entry_sz );
+	hermon->cap.reserved_cqs =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_cqs ) );
+	hermon->cap.cqc_entry_size = MLX_GET ( &dev_cap, cqc_entry_sz );
+	hermon->cap.reserved_eqs = MLX_GET ( &dev_cap, num_rsvd_eqs );
+	if ( hermon->cap.reserved_eqs == 0 ) {
+		/* Backward compatibility */
+		hermon->cap.reserved_eqs =
+			( 1 << MLX_GET ( &dev_cap, log2_rsvd_eqs ) );
+	}
+	hermon->cap.eqc_entry_size = MLX_GET ( &dev_cap, eqc_entry_sz );
+	hermon->cap.reserved_mtts =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mtts ) );
+	hermon->cap.mtt_entry_size = MLX_GET ( &dev_cap, mtt_entry_sz );
+	hermon->cap.reserved_mrws =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mrws ) );
+	hermon->cap.dmpt_entry_size = MLX_GET ( &dev_cap, d_mpt_entry_sz );
+	hermon->cap.reserved_uars = MLX_GET ( &dev_cap, num_rsvd_uars );
+	hermon->cap.num_ports = MLX_GET ( &dev_cap, num_ports );
+	hermon->cap.dpdp = MLX_GET ( &dev_cap, dpdp );
+
+	/* Sanity check */
+	if ( hermon->cap.num_ports > HERMON_MAX_PORTS ) {
+		DBGC ( hermon, "Hermon %p has %d ports (only %d supported)\n",
+		       hermon, hermon->cap.num_ports, HERMON_MAX_PORTS );
+		hermon->cap.num_ports = HERMON_MAX_PORTS;
+	}
+
+	return 0;
+}
+
+/**
+ * Align ICM table
+ *
+ * @v icm_offset	Current ICM offset
+ * @v len		ICM table length
+ * @ret icm_offset	ICM offset
+ */
+static uint64_t icm_align ( uint64_t icm_offset, size_t len ) {
+
+	/* Round up to a multiple of the table size */
+	assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) );
+	return ( ( icm_offset + len - 1 ) & ~( ( ( uint64_t ) len ) - 1 ) );
+}
+
+/**
+ * Allocate ICM
+ *
+ * @v hermon		Hermon device
+ * @v init_hca		INIT_HCA structure to fill in
+ * @ret rc		Return status code
+ */
+static int hermon_alloc_icm ( struct hermon *hermon,
+			      struct hermonprm_init_hca *init_hca ) {
+	struct hermonprm_scalar_parameter icm_size;
+	struct hermonprm_scalar_parameter icm_aux_size;
+	uint64_t icm_offset = 0;
+	unsigned int log_num_qps, log_num_srqs, log_num_cqs, log_num_eqs;
+	unsigned int log_num_mtts, log_num_mpts, log_num_mcs;
+	size_t cmpt_max_len;
+	size_t icm_len, icm_aux_len;
+	size_t len;
+	physaddr_t icm_phys;
+	int i;
+	int rc;
+
+	/*
+	 * Start by carving up the ICM virtual address space
+	 *
+	 */
+
+	/* Calculate number of each object type within ICM */
+	log_num_qps = fls ( hermon->cap.reserved_qps +
+			    HERMON_RSVD_SPECIAL_QPS + HERMON_MAX_QPS - 1 );
+	log_num_srqs = fls ( hermon->cap.reserved_srqs - 1 );
+	log_num_cqs = fls ( hermon->cap.reserved_cqs + HERMON_MAX_CQS - 1 );
+	log_num_eqs = fls ( hermon->cap.reserved_eqs + HERMON_MAX_EQS - 1 );
+	log_num_mtts = fls ( hermon->cap.reserved_mtts + HERMON_MAX_MTTS - 1 );
+	log_num_mpts = fls ( hermon->cap.reserved_mrws + 1 - 1 );
+	log_num_mcs = HERMON_LOG_MULTICAST_HASH_SIZE;
+
+	/* ICM starts with the cMPT tables, which are sparse */
+	cmpt_max_len = ( HERMON_CMPT_MAX_ENTRIES *
+			 ( ( uint64_t ) hermon->cap.cmpt_entry_size ) );
+	len = ( ( ( ( 1 << log_num_qps ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_QP_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_QP_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_srqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_SRQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_SRQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_cqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_CQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_CQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_eqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_EQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_EQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+
+	hermon->icm_map[HERMON_ICM_OTHER].offset = icm_offset;
+
+	/* Queue pair contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.qpc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 12,
+		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 13,
+		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp,
+		     log_num_qps );
+	DBGC ( hermon, "Hermon %p ICM QPC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.qpc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Extended alternate path contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.altc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 24,
+		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 25,
+		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_l,
+		     icm_offset );
+	DBGC ( hermon, "Hermon %p ICM ALTC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.altc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Extended auxiliary contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.auxc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 28,
+		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 29,
+		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_l,
+		     icm_offset );
+	DBGC ( hermon, "Hermon %p ICM AUXC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.auxc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Shared receive queue contexts */
+	len = ( ( 1 << log_num_srqs ) * hermon->cap.srqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 18,
+		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 19,
+		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq,
+		     log_num_srqs );
+	DBGC ( hermon, "Hermon %p ICM SRQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_srqs ), hermon->cap.srqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Completion queue contexts */
+	len = ( ( 1 << log_num_cqs ) * hermon->cap.cqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 20,
+		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 21,
+		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq,
+		     log_num_cqs );
+	DBGC ( hermon, "Hermon %p ICM CQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_cqs ), hermon->cap.cqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Event queue contexts */
+	len = ( ( 1 << log_num_eqs ) * hermon->cap.eqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 32,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 33,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_eq,
+		     log_num_eqs );
+	DBGC ( hermon, "Hermon %p ICM EQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_eqs ), hermon->cap.eqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Memory translation table */
+	len = ( ( 1 << log_num_mtts ) * hermon->cap.mtt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 64,
+		     tpt_parameters.mtt_base_addr_h, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 65,
+		     tpt_parameters.mtt_base_addr_l, icm_offset );
+	DBGC ( hermon, "Hermon %p ICM MTT is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mtts ), hermon->cap.mtt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Memory protection table */
+	len = ( ( 1 << log_num_mpts ) * hermon->cap.dmpt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 60,
+		     tpt_parameters.dmpt_base_adr_h, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 61,
+		     tpt_parameters.dmpt_base_adr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 62,
+		     tpt_parameters.log_dmpt_sz, log_num_mpts );
+	DBGC ( hermon, "Hermon %p ICM DMPT is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mpts ), hermon->cap.dmpt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+	/* Multicast table */
+	len = ( ( 1 << log_num_mcs ) * sizeof ( struct hermonprm_mcg_entry ) );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 48,
+		     multicast_parameters.mc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 49,
+		     multicast_parameters.mc_base_addr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 52,
+		     multicast_parameters.log_mc_table_entry_sz,
+		     fls ( sizeof ( struct hermonprm_mcg_entry ) - 1 ) );
+	MLX_FILL_1 ( init_hca, 53,
+		     multicast_parameters.log_mc_table_hash_sz, log_num_mcs );
+	MLX_FILL_1 ( init_hca, 54,
+		     multicast_parameters.log_mc_table_sz, log_num_mcs );
+	DBGC ( hermon, "Hermon %p ICM MC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mcs ),
+	       sizeof ( struct hermonprm_mcg_entry ),
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+
+	hermon->icm_map[HERMON_ICM_OTHER].len =
+		( icm_offset - hermon->icm_map[HERMON_ICM_OTHER].offset );
+
+	/*
+	 * Allocate and map physical memory for (portions of) ICM
+	 *
+	 * Map is:
+	 *   ICM AUX area (aligned to its own size)
+	 *   cMPT areas
+	 *   Other areas
+	 */
+
+	/* Calculate physical memory required for ICM */
+	icm_len = 0;
+	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
+		icm_len += hermon->icm_map[i].len;
+	}
+
+	/* Get ICM auxiliary area size */
+	memset ( &icm_size, 0, sizeof ( icm_size ) );
+	MLX_FILL_1 ( &icm_size, 0, value_hi, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( &icm_size, 1, value, icm_offset );
+	if ( ( rc = hermon_cmd_set_icm_size ( hermon, &icm_size,
+					      &icm_aux_size ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not set ICM size: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_set_icm_size;
+	}
+	icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * HERMON_PAGE_SIZE );
+
+	/* Allocate ICM data and auxiliary area */
+	DBGC ( hermon, "Hermon %p requires %zd kB ICM and %zd kB AUX ICM\n",
+	       hermon, ( icm_len / 1024 ), ( icm_aux_len / 1024 ) );
+	hermon->icm = umalloc ( icm_aux_len + icm_len );
+	if ( ! hermon->icm ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	icm_phys = user_to_phys ( hermon->icm, 0 );
+
+	/* Map ICM auxiliary area */
+	DBGC ( hermon, "Hermon %p mapping ICM AUX => %08lx\n",
+	       hermon, icm_phys );
+	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm_aux,
+				     0, icm_phys, icm_aux_len ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not map AUX ICM: %s\n",
+		       hermon, strerror ( rc ) );		
+		goto err_map_icm_aux;
+	}
+	icm_phys += icm_aux_len;
+
+	/* MAP ICM area */
+	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
+		DBGC ( hermon, "Hermon %p mapping ICM %llx+%zx => %08lx\n",
+		       hermon, hermon->icm_map[i].offset,
+		       hermon->icm_map[i].len, icm_phys );
+		if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm,
+					     hermon->icm_map[i].offset,
+					     icm_phys,
+					     hermon->icm_map[i].len ) ) != 0 ){
+			DBGC ( hermon, "Hermon %p could not map ICM: %s\n",
+			       hermon, strerror ( rc ) );
+			goto err_map_icm;
+		}
+		icm_phys += hermon->icm_map[i].len;
+	}
+
+	return 0;
+
+ err_map_icm:
+	assert ( i == 0 ); /* We don't handle partial failure at present */
+ err_map_icm_aux:
+	hermon_cmd_unmap_icm_aux ( hermon );
+	ufree ( hermon->icm );
+	hermon->icm = UNULL;
+ err_alloc:
+ err_set_icm_size:
+	return rc;
+}
+
+/**
+ * Free ICM
+ *
+ * @v hermon		Hermon device
+ */
+static void hermon_free_icm ( struct hermon *hermon ) {
+	struct hermonprm_scalar_parameter unmap_icm;
+	int i;
+
+	for ( i = ( HERMON_ICM_NUM_REGIONS - 1 ) ; i >= 0 ; i-- ) {
+		memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+		MLX_FILL_1 ( &unmap_icm, 0, value_hi,
+			     ( hermon->icm_map[i].offset >> 32 ) );
+		MLX_FILL_1 ( &unmap_icm, 1, value,
+			     hermon->icm_map[i].offset );
+		hermon_cmd_unmap_icm ( hermon,
+				       ( 1 << fls ( ( hermon->icm_map[i].len /
+						      HERMON_PAGE_SIZE ) - 1)),
+				       &unmap_icm );
+	}
+	hermon_cmd_unmap_icm_aux ( hermon );
+	ufree ( hermon->icm );
+	hermon->icm = UNULL;
+}
+
+/***************************************************************************
+ *
+ * BOFM interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Harvest Ethernet MAC for BOFM
+ *
+ * @v bofm		BOFM device
+ * @v mport		Multi-port index
+ * @v mac		MAC to fill in
+ * @ret rc		Return status code
+ */
+static int hermon_bofm_harvest ( struct bofm_device *bofm, unsigned int mport,
+				 uint8_t *mac ) {
+	struct hermon *hermon = container_of ( bofm, struct hermon, bofm );
+	struct hermonprm_mod_stat_cfg stat_cfg;
+	union {
+		uint8_t bytes[8];
+		uint32_t dwords[2];
+	} buf;
+	int rc;
+
+	/* Query static configuration */
+	if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
+					  HERMON_MOD_STAT_CFG_QUERY,
+					  HERMON_MOD_STAT_CFG_OFFSET ( mac_m ),
+					  &stat_cfg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not query "
+		       "configuration: %s\n", hermon, mport, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Retrieve MAC address */
+	buf.dwords[0] = htonl ( MLX_GET ( &stat_cfg, mac_high ) );
+	buf.dwords[1] = htonl ( MLX_GET ( &stat_cfg, mac_low ) );
+	memcpy ( mac, &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ],
+		 ETH_ALEN );
+
+	DBGC ( hermon, "Hermon %p port %d harvested MAC address %s\n",
+	       hermon, mport, eth_ntoa ( mac ) );
+
+	return 0;
+}
+
+/**
+ * Update Ethernet MAC for BOFM
+ *
+ * @v bofm		BOFM device
+ * @v mport		Multi-port index
+ * @v mac		MAC to fill in
+ * @ret rc		Return status code
+ */
+static int hermon_bofm_update ( struct bofm_device *bofm, unsigned int mport,
+				const uint8_t *mac ) {
+	struct hermon *hermon = container_of ( bofm, struct hermon, bofm );
+	struct hermonprm_mod_stat_cfg stat_cfg;
+	union {
+		uint8_t bytes[8];
+		uint32_t dwords[2];
+		uint64_t qword;
+	} buf;
+	uint8_t *mac_copy = &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ];
+	int rc;
+
+	/* Prepare MAC address */
+	memset ( &buf, 0, sizeof ( buf ) );
+	memcpy ( mac_copy, mac, ETH_ALEN );
+
+	/* Current BOFM versions are unable to create entries with
+	 * mport>1, which means that only the port 1 MAC address can
+	 * be explicitly specified.  Work around this by using the
+	 * provided MAC address as a base address for all subsequent
+	 * ports.  For example, if BOFM assigns the address
+	 *
+	 *    00:1A:64:76:00:09 for port 1
+	 *
+	 * then we will assign the addresses
+	 *
+	 *    00:1A:64:76:00:09 for port 1
+	 *    00:1A:64:76:00:0a for port 2
+	 *
+	 * Note that hermon->cap.num_ports is not yet defined at this
+	 * point.
+	 */
+	for ( ; mport <= HERMON_MAX_PORTS ; mport++ ) {
+
+		/* Modify static configuration */
+		memset ( &stat_cfg, 0, sizeof ( stat_cfg ) );
+		MLX_FILL_2 ( &stat_cfg, 36,
+			     mac_m, 1,
+			     mac_high, ntohl ( buf.dwords[0] ) );
+		MLX_FILL_1 ( &stat_cfg, 37, mac_low, ntohl ( buf.dwords[1] ) );
+		if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
+					  HERMON_MOD_STAT_CFG_SET,
+					  HERMON_MOD_STAT_CFG_OFFSET ( mac_m ),
+					  &stat_cfg ) ) != 0 ) {
+			DBGC ( hermon, "Hermon %p port %d could not modify "
+			       "configuration: %s\n",
+			       hermon, mport, strerror ( rc ) );
+			return rc;
+		}
+
+		DBGC ( hermon, "Hermon %p port %d updated MAC address to %s\n",
+		       hermon, mport, eth_ntoa ( mac_copy ) );
+
+		/* Increment MAC address */
+		buf.qword = cpu_to_be64 ( be64_to_cpu ( buf.qword ) + 1 );
+	}
+
+	return 0;
+}
+
+/** Hermon BOFM operations */
+static struct bofm_operations hermon_bofm_operations = {
+	.harvest = hermon_bofm_harvest,
+	.update = hermon_bofm_update,
+};
+
+/***************************************************************************
+ *
+ * PCI interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Set up memory protection table
+ *
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
+ */
+static int hermon_setup_mpt ( struct hermon *hermon ) {
+	struct hermonprm_mpt mpt;
+	uint32_t key;
+	int rc;
+
+	/* Derive key */
+	key = ( hermon->cap.reserved_mrws | HERMON_MKEY_PREFIX );
+	hermon->lkey = ( ( key << 8 ) | ( key >> 24 ) );
+
+	/* Initialise memory protection table */
+	memset ( &mpt, 0, sizeof ( mpt ) );
+	MLX_FILL_7 ( &mpt, 0,
+		     atomic, 1,
+		     rw, 1,
+		     rr, 1,
+		     lw, 1,
+		     lr, 1,
+		     pa, 1,
+		     r_w, 1 );
+	MLX_FILL_1 ( &mpt, 2, mem_key, key );
+	MLX_FILL_1 ( &mpt, 3,
+		     pd, HERMON_GLOBAL_PD );
+	MLX_FILL_1 ( &mpt, 10, len64, 1 );
+	if ( ( rc = hermon_cmd_sw2hw_mpt ( hermon,
+					   hermon->cap.reserved_mrws,
+					   &mpt ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not set up MPT: %s\n",
+		       hermon, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Configure special queue pairs
+ *
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
+ */
+static int hermon_configure_special_qps ( struct hermon *hermon ) {
+	int rc;
+
+	/* Special QP block must be aligned on its own size */
+	hermon->special_qpn_base = ( ( hermon->cap.reserved_qps +
+				       HERMON_NUM_SPECIAL_QPS - 1 )
+				     & ~( HERMON_NUM_SPECIAL_QPS - 1 ) );
+	hermon->qpn_base = ( hermon->special_qpn_base +
+			     HERMON_NUM_SPECIAL_QPS );
+	DBGC ( hermon, "Hermon %p special QPs at [%lx,%lx]\n", hermon,
+	       hermon->special_qpn_base, ( hermon->qpn_base - 1 ) );
+
+	/* Issue command to configure special QPs */
+	if ( ( rc = hermon_cmd_conf_special_qp ( hermon, 0x00,
+					  hermon->special_qpn_base ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not configure special QPs: "
+		       "%s\n", hermon, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Reset device
+ *
+ * @v hermon		Hermon device
+ * @v pci		PCI device
+ */
+static void hermon_reset ( struct hermon *hermon,
+			   struct pci_device *pci ) {
+	struct pci_config_backup backup;
+	static const uint8_t backup_exclude[] =
+		PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
+
+	pci_backup ( pci, &backup, backup_exclude );
+	writel ( HERMON_RESET_MAGIC,
+		 ( hermon->config + HERMON_RESET_OFFSET ) );
+	mdelay ( HERMON_RESET_WAIT_TIME_MS );
+	pci_restore ( pci, &backup, backup_exclude );
+}
+
+/**
+ * Allocate Hermon device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static struct hermon * hermon_alloc ( void ) {
+	struct hermon *hermon;
+
+	/* Allocate Hermon device */
+	hermon = zalloc ( sizeof ( *hermon ) );
+	if ( ! hermon )
+		goto err_hermon;
+
+	/* Allocate space for mailboxes */
+	hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
+					  HERMON_MBOX_ALIGN );
+	if ( ! hermon->mailbox_in )
+		goto err_mailbox_in;
+	hermon->mailbox_out = malloc_dma ( HERMON_MBOX_SIZE,
+					   HERMON_MBOX_ALIGN );
+	if ( ! hermon->mailbox_out )
+		goto err_mailbox_out;
+
+	return hermon;
+
+	free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
+ err_mailbox_out:
+	free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
+ err_mailbox_in:
+	free ( hermon );
+ err_hermon:
+	return NULL;
+}
+
+/**
+ * Free Hermon device
+ *
+ * @v hermon		Hermon device
+ */
+static void hermon_free ( struct hermon *hermon ) {
+
+	free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
+	free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
+	free ( hermon );
+}
+
+/**
+ * Initialise Hermon PCI parameters
+ *
+ * @v hermon		Hermon device
+ * @v pci		PCI device
+ */
+static void hermon_pci_init ( struct hermon *hermon, struct pci_device *pci ) {
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Get PCI BARs */
+	hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR),
+				   HERMON_PCI_CONFIG_BAR_SIZE );
+	hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ),
+				HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int hermon_probe ( struct pci_device *pci ) {
+	struct hermon *hermon;
+	struct ib_device *ibdev;
+	struct net_device *netdev;
+	struct hermon_port *port;
+	struct hermonprm_init_hca init_hca;
+	unsigned int i;
+	int rc;
+
+	/* Allocate Hermon device */
+	hermon = hermon_alloc();
+	if ( ! hermon ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	pci_set_drvdata ( pci, hermon );
+
+	/* Initialise PCI parameters */
+	hermon_pci_init ( hermon, pci );
+
+	/* Reset device */
+	hermon_reset ( hermon, pci );
+
+	/* Start firmware */
+	if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 )
+		goto err_start_firmware;
+
+	/* Get device limits */
+	if ( ( rc = hermon_get_cap ( hermon ) ) != 0 )
+		goto err_get_cap;
+
+	/* Allocate Infiniband devices */
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
+	        ibdev = alloc_ibdev ( 0 );
+		if ( ! ibdev ) {
+			rc = -ENOMEM;
+			goto err_alloc_ibdev;
+		}
+		hermon->port[i].ibdev = ibdev;
+		ibdev->op = &hermon_ib_operations;
+		ibdev->dev = &pci->dev;
+		ibdev->port = ( HERMON_PORT_BASE + i );
+		ib_set_drvdata ( ibdev, hermon );
+	}
+
+	/* Allocate network devices */
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
+		netdev = alloc_etherdev ( 0 );
+		if ( ! netdev ) {
+			rc = -ENOMEM;
+			goto err_alloc_netdev;
+		}
+		hermon->port[i].netdev = netdev;
+		netdev_init ( netdev, &hermon_eth_operations );
+		netdev->dev = &pci->dev;
+		netdev->priv = &hermon->port[i];
+	}
+
+	/* Allocate ICM */
+	memset ( &init_hca, 0, sizeof ( init_hca ) );
+	if ( ( rc = hermon_alloc_icm ( hermon, &init_hca ) ) != 0 )
+		goto err_alloc_icm;
+
+	/* Initialise HCA */
+	MLX_FILL_1 ( &init_hca, 0, version, 0x02 /* "Must be 0x02" */ );
+	MLX_FILL_1 ( &init_hca, 5, udp, 1 );
+	MLX_FILL_1 ( &init_hca, 74, uar_parameters.log_max_uars, 8 );
+	if ( ( rc = hermon_cmd_init_hca ( hermon, &init_hca ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not initialise HCA: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_init_hca;
+	}
+
+	/* Set up memory protection */
+	if ( ( rc = hermon_setup_mpt ( hermon ) ) != 0 )
+		goto err_setup_mpt;
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ )
+		hermon->port[i].ibdev->rdma_key = hermon->lkey;
+
+	/* Set up event queue */
+	if ( ( rc = hermon_create_eq ( hermon ) ) != 0 )
+		goto err_create_eq;
+
+	/* Configure special QPs */
+	if ( ( rc = hermon_configure_special_qps ( hermon ) ) != 0 )
+		goto err_conf_special_qps;
+
+	/* Determine port types */
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
+		port = &hermon->port[i];
+		if ( ( rc = hermon_set_port_type ( hermon, port ) ) != 0 )
+			goto err_set_port_type;
+	}
+
+	/* Register devices */
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
+		port = &hermon->port[i];
+		if ( ( rc = port->type->register_dev ( hermon, port ) ) != 0 )
+			goto err_register;
+	}
+
+	return 0;
+
+	i = hermon->cap.num_ports;
+ err_register:
+	for ( i-- ; ( signed int ) i >= 0 ; i-- ) {
+		port = &hermon->port[i];
+		port->type->unregister_dev ( hermon, port );
+	}
+ err_set_port_type:
+ err_conf_special_qps:
+	hermon_destroy_eq ( hermon );
+ err_create_eq:
+ err_setup_mpt:
+	hermon_cmd_close_hca ( hermon );
+ err_init_hca:
+	hermon_free_icm ( hermon );
+ err_alloc_icm:
+	i = hermon->cap.num_ports;
+ err_alloc_netdev:
+	for ( i-- ; ( signed int ) i >= 0 ; i-- ) {
+		netdev_nullify ( hermon->port[i].netdev );
+		netdev_put ( hermon->port[i].netdev );
+	}
+	i = hermon->cap.num_ports;
+ err_alloc_ibdev:
+	for ( i-- ; ( signed int ) i >= 0 ; i-- )
+		ibdev_put ( hermon->port[i].ibdev );
+ err_get_cap:
+	hermon_stop_firmware ( hermon );
+ err_start_firmware:
+	hermon_free ( hermon );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void hermon_remove ( struct pci_device *pci ) {
+	struct hermon *hermon = pci_get_drvdata ( pci );
+	struct hermon_port *port;
+	int i;
+
+	for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- ) {
+		port = &hermon->port[i];
+		port->type->unregister_dev ( hermon, port );
+	}
+	hermon_destroy_eq ( hermon );
+	hermon_cmd_close_hca ( hermon );
+	hermon_free_icm ( hermon );
+	hermon_stop_firmware ( hermon );
+	for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- ) {
+		netdev_nullify ( hermon->port[i].netdev );
+		netdev_put ( hermon->port[i].netdev );
+	}
+	for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- )
+		ibdev_put ( hermon->port[i].ibdev );
+	hermon_free ( hermon );
+}
+
+/**
+ * Probe PCI device for BOFM
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int hermon_bofm_probe ( struct pci_device *pci ) {
+	struct hermon *hermon;
+	int rc;
+
+	/* Allocate Hermon device */
+	hermon = hermon_alloc();
+	if ( ! hermon ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	pci_set_drvdata ( pci, hermon );
+
+	/* Initialise PCI parameters */
+	hermon_pci_init ( hermon, pci );
+
+	/* Initialise BOFM device */
+	bofm_init ( &hermon->bofm, pci, &hermon_bofm_operations );
+
+	/* Register BOFM device */
+	if ( ( rc = bofm_register ( &hermon->bofm ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not register BOFM device: "
+		       "%s\n", hermon, strerror ( rc ) );
+		goto err_bofm_register;
+	}
+
+	return 0;
+
+ err_bofm_register:
+	hermon_free ( hermon );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device for BOFM
+ *
+ * @v pci		PCI device
+ */
+static void hermon_bofm_remove ( struct pci_device *pci ) {
+	struct hermon *hermon = pci_get_drvdata ( pci );
+
+	bofm_unregister ( &hermon->bofm );
+	hermon_free ( hermon );
+}
+
+static struct pci_device_id hermon_nics[] = {
+	PCI_ROM ( 0x15b3, 0x6340, "mt25408", "MT25408 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x634a, "mt25418", "MT25418 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6732, "mt26418", "MT26418 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x673c, "mt26428", "MT26428 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6746, "mt26438", "MT26438 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6778, "mt26488", "MT26488 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6368, "mt25448", "MT25448 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6750, "mt26448", "MT26448 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6372, "mt25458", "MT25458 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x675a, "mt26458", "MT26458 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x6764, "mt26468", "MT26468 HCA driver", 0 ),
+	PCI_ROM ( 0x15b3, 0x676e, "mt26478", "MT26478 HCA driver", 0 ),
+};
+
+struct pci_driver hermon_driver __pci_driver = {
+	.ids = hermon_nics,
+	.id_count = ( sizeof ( hermon_nics ) / sizeof ( hermon_nics[0] ) ),
+	.probe = hermon_probe,
+	.remove = hermon_remove,
+};
+
+struct pci_driver hermon_bofm_driver __bofm_driver = {
+	.ids = hermon_nics,
+	.id_count = ( sizeof ( hermon_nics ) / sizeof ( hermon_nics[0] ) ),
+	.probe = hermon_bofm_probe,
+	.remove = hermon_bofm_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.h
new file mode 100644
index 0000000..1c86230
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/hermon.h
@@ -0,0 +1,932 @@
+#ifndef _HERMON_H
+#define _HERMON_H
+
+/** @file
+ *
+ * Mellanox Hermon Infiniband HCA driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/ib_packet.h>
+#include <ipxe/bofm.h>
+#include "mlx_bitops.h"
+#include "MT25408_PRM.h"
+
+/*
+ * Hardware constants
+ *
+ */
+
+/* Ports in existence */
+#define HERMON_MAX_PORTS		2
+#define HERMON_PORT_BASE		1
+
+/* PCI BARs */
+#define HERMON_PCI_CONFIG_BAR		PCI_BASE_ADDRESS_0
+#define HERMON_PCI_CONFIG_BAR_SIZE	0x100000
+#define HERMON_PCI_UAR_BAR		PCI_BASE_ADDRESS_2
+
+/* Device reset */
+#define HERMON_RESET_OFFSET		0x0f0010
+#define HERMON_RESET_MAGIC		0x01000000UL
+#define HERMON_RESET_WAIT_TIME_MS	1000
+
+/* Work queue entry and completion queue entry opcodes */
+#define HERMON_OPCODE_NOP		0x00
+#define HERMON_OPCODE_SEND		0x0a
+#define HERMON_OPCODE_RECV_ERROR	0xfe
+#define HERMON_OPCODE_SEND_ERROR	0xff
+
+/* HCA command register opcodes */
+#define HERMON_HCR_QUERY_DEV_CAP	0x0003
+#define HERMON_HCR_QUERY_FW		0x0004
+#define HERMON_HCR_INIT_HCA		0x0007
+#define HERMON_HCR_CLOSE_HCA		0x0008
+#define HERMON_HCR_INIT_PORT		0x0009
+#define HERMON_HCR_CLOSE_PORT		0x000a
+#define HERMON_HCR_SET_PORT		0x000c
+#define HERMON_HCR_SW2HW_MPT		0x000d
+#define HERMON_HCR_WRITE_MTT		0x0011
+#define HERMON_HCR_MAP_EQ		0x0012
+#define HERMON_HCR_SW2HW_EQ		0x0013
+#define HERMON_HCR_HW2SW_EQ		0x0014
+#define HERMON_HCR_QUERY_EQ		0x0015
+#define HERMON_HCR_SW2HW_CQ		0x0016
+#define HERMON_HCR_HW2SW_CQ		0x0017
+#define HERMON_HCR_QUERY_CQ		0x0018
+#define HERMON_HCR_RST2INIT_QP		0x0019
+#define HERMON_HCR_INIT2RTR_QP		0x001a
+#define HERMON_HCR_RTR2RTS_QP		0x001b
+#define HERMON_HCR_RTS2RTS_QP		0x001c
+#define HERMON_HCR_2RST_QP		0x0021
+#define HERMON_HCR_QUERY_QP		0x0022
+#define HERMON_HCR_CONF_SPECIAL_QP	0x0023
+#define HERMON_HCR_MAD_IFC		0x0024
+#define HERMON_HCR_READ_MCG		0x0025
+#define HERMON_HCR_WRITE_MCG		0x0026
+#define HERMON_HCR_MGID_HASH		0x0027
+#define HERMON_HCR_MOD_STAT_CFG		0x0034
+#define HERMON_HCR_QUERY_PORT		0x0043
+#define HERMON_HCR_SENSE_PORT		0x004d
+#define HERMON_HCR_RUN_FW		0x0ff6
+#define HERMON_HCR_DISABLE_LAM		0x0ff7
+#define HERMON_HCR_ENABLE_LAM		0x0ff8
+#define HERMON_HCR_UNMAP_ICM		0x0ff9
+#define HERMON_HCR_MAP_ICM		0x0ffa
+#define HERMON_HCR_UNMAP_ICM_AUX	0x0ffb
+#define HERMON_HCR_MAP_ICM_AUX		0x0ffc
+#define HERMON_HCR_SET_ICM_SIZE		0x0ffd
+#define HERMON_HCR_UNMAP_FA		0x0ffe
+#define HERMON_HCR_MAP_FA		0x0fff
+
+/* Service types */
+#define HERMON_ST_RC			0x00
+#define HERMON_ST_UD			0x03
+#define HERMON_ST_MLX			0x07
+
+/* Port types */
+#define HERMON_PORT_TYPE_UNKNOWN	0
+#define HERMON_PORT_TYPE_IB		1
+#define HERMON_PORT_TYPE_ETH		2
+
+/* MTUs */
+#define HERMON_MTU_2048			0x04
+#define HERMON_MTU_ETH			0x07
+
+#define HERMON_INVALID_LKEY		0x00000100UL
+
+#define HERMON_PAGE_SIZE		( ( size_t ) 4096 )
+
+#define HERMON_DB_POST_SND_OFFSET	0x14
+#define HERMON_DB_EQ_OFFSET(_eqn)	\
+	( 0x800 + HERMON_PAGE_SIZE * ( (_eqn) / 4 ) + 0x08 * ( (_eqn) % 4 ) )
+
+#define HERMON_QP_OPT_PARAM_PM_STATE	0x00000400UL
+#define HERMON_QP_OPT_PARAM_QKEY	0x00000020UL
+#define HERMON_QP_OPT_PARAM_ALT_PATH	0x00000001UL
+
+#define HERMON_MAP_EQ			( 0UL << 31 )
+#define HERMON_UNMAP_EQ			( 1UL << 31 )
+
+#define HERMON_SET_PORT_GENERAL_PARAM	0x0000
+#define HERMON_SET_PORT_RECEIVE_QP	0x0100
+#define HERMON_SET_PORT_MAC_TABLE	0x0200
+#define HERMON_SET_PORT_VLAN_TABLE	0x0300
+#define HERMON_SET_PORT_PRIORITY_TABLE	0x0400
+#define HERMON_SET_PORT_GID_TABLE	0x0500
+
+#define HERMON_EV_PORT_STATE_CHANGE	0x09
+
+#define HERMON_SCHED_QP0		0x3f
+#define HERMON_SCHED_DEFAULT		0x83
+
+#define HERMON_LOG_MULTICAST_HASH_SIZE	7
+
+#define HERMON_PM_STATE_ARMED		0x00
+#define HERMON_PM_STATE_REARM		0x01
+#define HERMON_PM_STATE_MIGRATED	0x03
+
+#define HERMON_RETRY_MAX		0x07
+
+#define HERMON_MOD_STAT_CFG_SET		0x01
+#define HERMON_MOD_STAT_CFG_QUERY	0x03
+
+/*
+ * Datatypes that seem to be missing from the autogenerated documentation
+ *
+ */
+struct hermonprm_mgm_hash_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t hash[0x00010];
+	pseudo_bit_t reserved1[0x00010];
+} __attribute__ (( packed ));
+
+struct hermonprm_mcg_entry_st {
+	struct hermonprm_mcg_hdr_st hdr;
+	struct hermonprm_mcg_qp_dw_st qp[8];
+} __attribute__ (( packed ));
+
+struct hermonprm_cq_db_record_st {
+	pseudo_bit_t update_ci[0x00018];
+	pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+	pseudo_bit_t arm_ci[0x00018];
+	pseudo_bit_t cmd[0x00003];
+	pseudo_bit_t reserved1[0x00001];
+	pseudo_bit_t cmd_sn[0x00002];
+	pseudo_bit_t reserved2[0x00002];
+} __attribute__ (( packed ));
+
+struct hermonprm_send_db_register_st {
+	pseudo_bit_t reserved[0x00008];
+	pseudo_bit_t qn[0x00018];
+} __attribute__ (( packed ));
+
+struct hermonprm_event_db_register_st {
+	pseudo_bit_t ci[0x00018];
+	pseudo_bit_t reserver[0x00007];
+	pseudo_bit_t a[0x00001];
+} __attribute__ (( packed ));
+
+struct hermonprm_scalar_parameter_st {
+	pseudo_bit_t value_hi[0x00020];
+/* -------------- */
+	pseudo_bit_t value[0x00020];
+} __attribute__ (( packed ));
+
+struct hermonprm_event_mask_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t completion[0x00001];
+	pseudo_bit_t path_migration_succeeded[0x00001];
+	pseudo_bit_t communication_established[0x00001];
+	pseudo_bit_t send_queue_drained[0x00001];
+	pseudo_bit_t cq_error[0x00001];
+	pseudo_bit_t wq_catastrophe[0x00001];
+	pseudo_bit_t qpc_catastrophe[0x00001];
+	pseudo_bit_t path_migration_failed[0x00001];
+	pseudo_bit_t internal_error[0x00001];
+	pseudo_bit_t port_state_change[0x00001];
+	pseudo_bit_t command_done[0x00001];
+	pseudo_bit_t fexch_error[0x00001];
+	pseudo_bit_t reserved1[0x00004];
+	pseudo_bit_t wq_invalid_request[0x00001];
+	pseudo_bit_t wq_access_violation[0x00001];
+	pseudo_bit_t srq_catastrophe[0x00001];
+	pseudo_bit_t srq_last_wqe[0x00001];
+	pseudo_bit_t srq_rq_limit[0x00001];
+	pseudo_bit_t gpio[0x00001];
+	pseudo_bit_t clientreregister[0x00001];
+	pseudo_bit_t reserved2[0x00009];
+} __attribute__ (( packed ));
+
+struct hermonprm_port_state_change_event_st {
+	pseudo_bit_t reserved[0x00020];
+/* -------------- */
+	struct hermonprm_port_state_change_st data;
+} __attribute__ (( packed ));
+
+struct hermonprm_sense_port_st {
+	pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+	pseudo_bit_t port_type[0x00002];
+	pseudo_bit_t reserved1[0x0001e];
+} __attribute__ (( packed ));
+
+struct hermonprm_set_port_ib_st {
+	pseudo_bit_t rqk[0x00001];
+	pseudo_bit_t rcm[0x00001];
+	pseudo_bit_t reserved0[0x00002];
+	pseudo_bit_t vl_cap[0x00004];
+	pseudo_bit_t reserved1[0x00004];
+	pseudo_bit_t mtu_cap[0x00004];
+	pseudo_bit_t g0[0x00001];
+	pseudo_bit_t ng[0x00001];
+	pseudo_bit_t sig[0x00001];
+	pseudo_bit_t mg[0x00001];
+	pseudo_bit_t mp[0x00001];
+	pseudo_bit_t mvc[0x00001];
+	pseudo_bit_t mmc[0x00001];
+	pseudo_bit_t reserved2[0x00004];
+	pseudo_bit_t lws[0x00001];
+	pseudo_bit_t lss[0x00001];
+	pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+	pseudo_bit_t capability_mask[0x00020];
+/* -------------- */
+	pseudo_bit_t system_image_guid_h[0x00020];
+/* -------------- */
+	pseudo_bit_t system_image_guid_l[0x00020];
+/* -------------- */
+	pseudo_bit_t guid0_h[0x00020];
+/* -------------- */
+	pseudo_bit_t guid0_l[0x00020];
+/* -------------- */
+	pseudo_bit_t node_guid_h[0x00020];
+/* -------------- */
+	pseudo_bit_t node_guid_l[0x00020];
+/* -------------- */
+	pseudo_bit_t egress_sniff_qpn[0x00018];
+	pseudo_bit_t egress_sniff_mode[0x00002];
+	pseudo_bit_t reserved4[0x00006];
+/* -------------- */
+	pseudo_bit_t ingress_sniff_qpn[0x00018];
+	pseudo_bit_t ingress_sniff_mode[0x00002];
+	pseudo_bit_t reserved5[0x00006];
+/* -------------- */
+	pseudo_bit_t max_gid[0x00010];
+	pseudo_bit_t max_pkey[0x00010];
+/* -------------- */
+	pseudo_bit_t reserved6[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved7[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved8[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved9[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved10[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved11[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved12[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved13[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved14[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved15[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved16[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved17[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved18[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved19[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved20[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved21[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved22[0x00020];
+/* -------------- */
+	pseudo_bit_t link_width_supported[0x00004];
+	pseudo_bit_t link_speed_supported[0x00004];
+	pseudo_bit_t reserved23[0x00018];
+/* -------------- */
+} __attribute__ (( packed ));
+
+struct hermonprm_query_port_cap_st {
+	pseudo_bit_t eth_mtu[0x00010];
+	pseudo_bit_t ib_mtu[0x00004];
+	pseudo_bit_t reserved0[0x00004];
+	pseudo_bit_t ib[0x00001];
+	pseudo_bit_t eth[0x00001];
+	pseudo_bit_t reserved1[0x00005];
+	pseudo_bit_t link_state[0x00001];
+/* -------------- */
+	pseudo_bit_t log_max_pkey[0x00004];
+	pseudo_bit_t log_max_gid[0x00004];
+	pseudo_bit_t ib_port_width[0x00004];
+	pseudo_bit_t reserved2[0x00004];
+	pseudo_bit_t eth_link_speed[0x00004];
+	pseudo_bit_t reserved3[0x00004];
+	pseudo_bit_t ib_link_speed[0x00004];
+	pseudo_bit_t reserved4[0x00004];
+/* -------------- */
+	pseudo_bit_t max_vl_ib[0x00004];
+	pseudo_bit_t reserved5[0x00004];
+	pseudo_bit_t log_max_mac[0x00004];
+	pseudo_bit_t log_max_vlan[0x00004];
+	pseudo_bit_t reserved6[0x00010];
+/* -------------- */
+	pseudo_bit_t reserved7[0x00020];
+/* -------------- */
+	pseudo_bit_t mac_47_32[0x00010];
+	pseudo_bit_t reserved8[0x00010];
+/* -------------- */
+	pseudo_bit_t mac_31_0[0x00020];
+/* -------------- */
+	pseudo_bit_t vendor_oui[0x00018];
+	pseudo_bit_t transceiver_type[0x00008];
+/* -------------- */
+	pseudo_bit_t reserved9[0x00010];
+	pseudo_bit_t wavelength[0x00010];
+/* -------------- */
+	pseudo_bit_t transceiver_code_hi[0x00020];
+/* -------------- */
+	pseudo_bit_t transceiver_code_lo[0x00020];
+/* -------------- */
+	pseudo_bit_t reserved10[0x000c0];
+} __attribute__ (( packed ));
+
+struct hermonprm_set_port_general_context_st {
+	pseudo_bit_t v_mtu[0x00001];
+	pseudo_bit_t v_pprx[0x00001];
+	pseudo_bit_t v_pptx[0x00001];
+	pseudo_bit_t reserved0[0x0001d];
+/* -------------- */
+	pseudo_bit_t mtu[0x00010];
+	pseudo_bit_t reserved1[0x00010];
+/* -------------- */
+	pseudo_bit_t reserved2[0x00010];
+	pseudo_bit_t pfctx[0x00008];
+	pseudo_bit_t reserved3[0x00007];
+	pseudo_bit_t pptx[0x00001];
+/* -------------- */
+	pseudo_bit_t reserved4[0x00010];
+	pseudo_bit_t pfcrx[0x00008];
+	pseudo_bit_t reserved5[0x00007];
+	pseudo_bit_t pprx[0x00001];
+/* -------------- */
+} __attribute__ (( packed ));
+
+struct hermonprm_set_port_rqp_calc_st {
+	pseudo_bit_t base_qpn[0x00018];
+	pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+	pseudo_bit_t n_p[0x00002];
+	pseudo_bit_t reserved1[0x00006];
+	pseudo_bit_t n_v[0x00003];
+	pseudo_bit_t reserved2[0x00005];
+	pseudo_bit_t n_m[0x00004];
+	pseudo_bit_t reserved3[0x0000c];
+/* -------------- */
+	pseudo_bit_t mac_miss_index[0x00008];
+	pseudo_bit_t reserved4[0x00018];
+/* -------------- */
+	pseudo_bit_t vlan_miss_index[0x00007];
+	pseudo_bit_t reserved5[0x00008];
+	pseudo_bit_t intra_miss[0x00001];
+	pseudo_bit_t no_vlan_index[0x00007];
+	pseudo_bit_t reserved6[0x00008];
+	pseudo_bit_t intra_no_vlan[0x00001];
+/* -------------- */
+	pseudo_bit_t no_vlan_prio[0x00003];
+	pseudo_bit_t reserved7[0x0001d];
+/* -------------- */
+	pseudo_bit_t promisc_qpn[0x00018];
+	pseudo_bit_t reserved8[0x00007];
+	pseudo_bit_t en_uc_promisc[0x00001];
+/* -------------- */
+	pseudo_bit_t def_mcast_qpn[0x00018];
+	pseudo_bit_t reserved9[0x00005];
+	pseudo_bit_t mc_by_vlan[0x00001];
+	pseudo_bit_t mc_promisc_mode[0x00002];
+/* -------------- */
+	pseudo_bit_t reserved10[0x00020];
+/* -------------- */
+} __attribute__ (( packed ));
+
+struct hermonprm_set_port_mac_table_st {
+	pseudo_bit_t mac_h[0x00010];
+	pseudo_bit_t reserved0[0x0000f];
+	pseudo_bit_t v[0x00001];
+/* -------------- */
+	pseudo_bit_t mac_l[0x00020];
+/* -------------- */
+} __attribute__ (( packed ));
+
+struct hermonprm_set_port_vlan_st {
+	pseudo_bit_t vlan_id[0x0000c];
+	pseudo_bit_t reserved0[0x00012];
+	pseudo_bit_t intra[0x00001];
+	pseudo_bit_t v[0x00001];
+/* -------------- */
+} __attribute__ (( packed ));
+
+struct hermonprm_mod_stat_cfg_input_mod_st {
+	pseudo_bit_t offset[0x00008];
+	pseudo_bit_t portnum[0x00008];
+	pseudo_bit_t xnum[0x00004];
+	pseudo_bit_t linkspeed[0x00003];
+	pseudo_bit_t autoneg[0x00001];
+	pseudo_bit_t reserved[0x00004];
+	pseudo_bit_t setup_mode[0x00004];
+} __attribute__ (( packed ));
+
+/*
+ * Wrapper structures for hardware datatypes
+ *
+ */
+
+struct MLX_DECLARE_STRUCT ( hermonprm_completion_queue_context );
+struct MLX_DECLARE_STRUCT ( hermonprm_completion_queue_entry );
+struct MLX_DECLARE_STRUCT ( hermonprm_completion_with_error );
+struct MLX_DECLARE_STRUCT ( hermonprm_cq_db_record );
+struct MLX_DECLARE_STRUCT ( hermonprm_eqc );
+struct MLX_DECLARE_STRUCT ( hermonprm_event_db_register );
+struct MLX_DECLARE_STRUCT ( hermonprm_event_mask );
+struct MLX_DECLARE_STRUCT ( hermonprm_event_queue_entry );
+struct MLX_DECLARE_STRUCT ( hermonprm_hca_command_register );
+struct MLX_DECLARE_STRUCT ( hermonprm_init_hca );
+struct MLX_DECLARE_STRUCT ( hermonprm_mad_ifc );
+struct MLX_DECLARE_STRUCT ( hermonprm_mcg_entry );
+struct MLX_DECLARE_STRUCT ( hermonprm_mgm_hash );
+struct MLX_DECLARE_STRUCT ( hermonprm_mod_stat_cfg );
+struct MLX_DECLARE_STRUCT ( hermonprm_mod_stat_cfg_input_mod );
+struct MLX_DECLARE_STRUCT ( hermonprm_mpt );
+struct MLX_DECLARE_STRUCT ( hermonprm_mtt );
+struct MLX_DECLARE_STRUCT ( hermonprm_port_state_change_event );
+struct MLX_DECLARE_STRUCT ( hermonprm_qp_db_record );
+struct MLX_DECLARE_STRUCT ( hermonprm_qp_ee_state_transitions );
+struct MLX_DECLARE_STRUCT ( hermonprm_query_dev_cap );
+struct MLX_DECLARE_STRUCT ( hermonprm_query_fw );
+struct MLX_DECLARE_STRUCT ( hermonprm_query_port_cap );
+struct MLX_DECLARE_STRUCT ( hermonprm_queue_pair_ee_context_entry );
+struct MLX_DECLARE_STRUCT ( hermonprm_scalar_parameter );
+struct MLX_DECLARE_STRUCT ( hermonprm_sense_port );
+struct MLX_DECLARE_STRUCT ( hermonprm_send_db_register );
+struct MLX_DECLARE_STRUCT ( hermonprm_set_port_ib );
+struct MLX_DECLARE_STRUCT ( hermonprm_set_port_general_context );
+struct MLX_DECLARE_STRUCT ( hermonprm_set_port_mac_table );
+struct MLX_DECLARE_STRUCT ( hermonprm_set_port_rqp_calc );
+struct MLX_DECLARE_STRUCT ( hermonprm_set_port_vlan );
+struct MLX_DECLARE_STRUCT ( hermonprm_ud_address_vector );
+struct MLX_DECLARE_STRUCT ( hermonprm_virtual_physical_mapping );
+struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ctrl_mlx );
+struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ctrl_send );
+struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_data_ptr );
+struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ud );
+
+/*
+ * Composite hardware datatypes
+ *
+ */
+
+struct hermonprm_write_mtt {
+	struct hermonprm_scalar_parameter mtt_base_addr;
+	struct hermonprm_scalar_parameter reserved;
+	struct hermonprm_mtt mtt;
+} __attribute__ (( packed ));
+
+#define HERMON_MAX_GATHER 2
+
+struct hermonprm_ud_send_wqe {
+	struct hermonprm_wqe_segment_ctrl_send ctrl;
+	struct hermonprm_wqe_segment_ud ud;
+	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
+} __attribute__ (( packed ));
+
+struct hermonprm_mlx_send_wqe {
+	struct hermonprm_wqe_segment_ctrl_mlx ctrl;
+	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
+	uint8_t headers[IB_MAX_HEADER_SIZE];
+} __attribute__ (( packed ));
+
+struct hermonprm_rc_send_wqe {
+	struct hermonprm_wqe_segment_ctrl_send ctrl;
+	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
+} __attribute__ (( packed ));
+
+struct hermonprm_eth_send_wqe {
+	struct hermonprm_wqe_segment_ctrl_send ctrl;
+	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
+} __attribute__ (( packed ));
+
+#define HERMON_MAX_SCATTER 1
+
+struct hermonprm_recv_wqe {
+	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_SCATTER];
+} __attribute__ (( packed ));
+
+union hermonprm_completion_entry {
+	struct hermonprm_completion_queue_entry normal;
+	struct hermonprm_completion_with_error error;
+} __attribute__ (( packed ));
+
+union hermonprm_event_entry {
+	struct hermonprm_event_queue_entry generic;
+	struct hermonprm_port_state_change_event port_state_change;
+} __attribute__ (( packed ));
+
+union hermonprm_doorbell_register {
+	struct hermonprm_send_db_register send;
+	struct hermonprm_event_db_register event;
+	uint32_t dword[1];
+} __attribute__ (( packed ));
+
+union hermonprm_mad {
+	struct hermonprm_mad_ifc ifc;
+	union ib_mad mad;
+} __attribute__ (( packed ));
+
+union hermonprm_set_port {
+	struct hermonprm_set_port_ib ib;
+	struct hermonprm_set_port_general_context general;
+	struct hermonprm_set_port_rqp_calc rqp_calc;
+	struct hermonprm_set_port_mac_table mac_table[128];
+	struct hermonprm_set_port_vlan vlan;
+} __attribute__ (( packed ));
+
+/*
+ * iPXE-specific definitions
+ *
+ */
+
+/** Hermon device capabilitiess */
+struct hermon_dev_cap {
+	/** CMPT entry size */
+	size_t cmpt_entry_size;
+	/** Number of reserved QPs */
+	unsigned int reserved_qps;
+	/** QP context entry size */
+	size_t qpc_entry_size;
+	/** Alternate path context entry size */
+	size_t altc_entry_size;
+	/** Auxiliary context entry size */
+	size_t auxc_entry_size;
+	/** Number of reserved SRQs */
+	unsigned int reserved_srqs;
+	/** SRQ context entry size */
+	size_t srqc_entry_size;
+	/** Number of reserved CQs */
+	unsigned int reserved_cqs;
+	/** CQ context entry size */
+	size_t cqc_entry_size;
+	/** Number of reserved EQs */
+	unsigned int reserved_eqs;
+	/** EQ context entry size */
+	size_t eqc_entry_size;
+	/** Number of reserved MTTs */
+	unsigned int reserved_mtts;
+	/** MTT entry size */
+	size_t mtt_entry_size;
+	/** Number of reserved MRWs */
+	unsigned int reserved_mrws;
+	/** DMPT entry size */
+	size_t dmpt_entry_size;
+	/** Number of reserved UARs */
+	unsigned int reserved_uars;
+	/** Number of ports */
+	unsigned int num_ports;
+	/** Dual-port different protocol */
+	int dpdp;
+};
+
+/** Number of cMPT entries of each type */
+#define HERMON_CMPT_MAX_ENTRIES ( 1 << 24 )
+
+/** Hermon ICM memory map entry */
+struct hermon_icm_map {
+	/** Offset (virtual address within ICM) */
+	uint64_t offset;
+	/** Length */
+	size_t len;
+};
+
+/** Discontiguous regions within Hermon ICM */
+enum hermon_icm_map_regions {
+	HERMON_ICM_QP_CMPT = 0,
+	HERMON_ICM_SRQ_CMPT,
+	HERMON_ICM_CQ_CMPT,
+	HERMON_ICM_EQ_CMPT,
+	HERMON_ICM_OTHER,
+	HERMON_ICM_NUM_REGIONS
+};
+
+/** UAR page for doorbell accesses
+ *
+ * Pages 0-127 are reserved for event queue doorbells only, so we use
+ * page 128.
+ */
+#define HERMON_UAR_NON_EQ_PAGE	128
+
+/** Maximum number of allocatable MTT entries
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define HERMON_MAX_MTTS		64
+
+/** A Hermon MTT descriptor */
+struct hermon_mtt {
+	/** MTT offset */
+	unsigned int mtt_offset;
+	/** Number of pages */
+	unsigned int num_pages;
+	/** MTT base address */
+	unsigned int mtt_base_addr;
+	/** Offset within page */
+	unsigned int page_offset;
+};
+
+/** Alignment of Hermon send work queue entries */
+#define HERMON_SEND_WQE_ALIGN 128
+
+/** A Hermon send work queue entry */
+union hermon_send_wqe {
+	struct hermonprm_wqe_segment_ctrl_send ctrl;
+	struct hermonprm_ud_send_wqe ud;
+	struct hermonprm_mlx_send_wqe mlx;
+	struct hermonprm_rc_send_wqe rc;
+	struct hermonprm_eth_send_wqe eth;
+	uint8_t force_align[HERMON_SEND_WQE_ALIGN];
+} __attribute__ (( packed ));
+
+/** A Hermon send work queue */
+struct hermon_send_work_queue {
+	/** Number of work queue entries, including headroom
+	 *
+	 * Hermon requires us to leave unused space within the send
+	 * WQ, so we create a send WQ with more entries than are
+	 * requested in the create_qp() call.
+	 */
+	unsigned int num_wqes;
+	/** Work queue entries */
+	union hermon_send_wqe *wqe;
+	/** Size of work queue */
+	size_t wqe_size;
+	/** Doorbell register */
+	void *doorbell;
+};
+
+/** Alignment of Hermon receive work queue entries */
+#define HERMON_RECV_WQE_ALIGN 16
+
+/** A Hermon receive work queue entry */
+union hermon_recv_wqe {
+	struct hermonprm_recv_wqe recv;
+	uint8_t force_align[HERMON_RECV_WQE_ALIGN];
+} __attribute__ (( packed ));
+
+/** A Hermon receive work queue */
+struct hermon_recv_work_queue {
+	/** Work queue entries */
+	union hermon_recv_wqe *wqe;
+	/** Size of work queue */
+	size_t wqe_size;
+	/** Doorbell record */
+	struct hermonprm_qp_db_record *doorbell;
+};
+
+/** Number of special queue pairs */
+#define HERMON_NUM_SPECIAL_QPS 8
+
+/** Number of queue pairs reserved for the "special QP" block
+ *
+ * The special QPs must be within a contiguous block aligned on its
+ * own size.
+ */
+#define HERMON_RSVD_SPECIAL_QPS	( ( HERMON_NUM_SPECIAL_QPS << 1 ) - 1 )
+
+/** Maximum number of allocatable queue pairs
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define HERMON_MAX_QPS		8
+
+/** Queue pair number randomisation mask */
+#define HERMON_QPN_RANDOM_MASK 0xfff000
+
+/** Hermon queue pair state */
+enum hermon_queue_pair_state {
+	HERMON_QP_ST_RST = 0,
+	HERMON_QP_ST_INIT,
+	HERMON_QP_ST_RTR,
+	HERMON_QP_ST_RTS,
+};
+
+/** A Hermon queue pair */
+struct hermon_queue_pair {
+	/** Work queue buffer */
+	void *wqe;
+	/** Size of work queue buffer */
+	size_t wqe_size;
+	/** MTT descriptor */
+	struct hermon_mtt mtt;
+	/** Send work queue */
+	struct hermon_send_work_queue send;
+	/** Receive work queue */
+	struct hermon_recv_work_queue recv;
+	/** Queue state */
+	enum hermon_queue_pair_state state;
+};
+
+/** Maximum number of allocatable completion queues
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define HERMON_MAX_CQS		8
+
+/** A Hermon completion queue */
+struct hermon_completion_queue {
+	/** Completion queue entries */
+	union hermonprm_completion_entry *cqe;
+	/** Size of completion queue */
+	size_t cqe_size;
+	/** MTT descriptor */
+	struct hermon_mtt mtt;
+	/** Doorbell record */
+	struct hermonprm_cq_db_record *doorbell;
+};
+
+/** Maximum number of allocatable event queues
+ *
+ * This is a policy decision, not a device limit.
+ */
+#define HERMON_MAX_EQS		8
+
+/** A Hermon event queue */
+struct hermon_event_queue {
+	/** Event queue entries */
+	union hermonprm_event_entry *eqe;
+	/** Size of event queue */
+	size_t eqe_size;
+	/** MTT descriptor */
+	struct hermon_mtt mtt;
+	/** Event queue number */
+	unsigned long eqn;
+	/** Next event queue entry index */
+	unsigned long next_idx;
+	/** Doorbell register */
+	void *doorbell;
+};
+
+/** Number of event queue entries
+ *
+ * This is a policy decision.
+ */
+#define HERMON_NUM_EQES		8
+
+/** A Hermon resource bitmask */
+typedef uint32_t hermon_bitmask_t;
+
+/** Size of a hermon resource bitmask */
+#define HERMON_BITMASK_SIZE(max_entries)				     \
+	( ( (max_entries) + ( 8 * sizeof ( hermon_bitmask_t ) ) - 1 ) /	     \
+	  ( 8 * sizeof ( hermon_bitmask_t ) ) )
+
+struct hermon;
+struct hermon_port;
+
+/** A Hermon port type */
+struct hermon_port_type {
+	/** Register port
+	 *
+	 * @v hermon		Hermon device
+	 * @v port		Hermon port
+	 * @ret rc		Return status code
+	 */
+	int ( * register_dev ) ( struct hermon *hermon,
+				 struct hermon_port *port );
+	/** Port state changed
+	 *
+	 * @v hermon		Hermon device
+	 * @v port		Hermon port
+	 * @v link_up		Link is up
+	 */
+	void ( * state_change ) ( struct hermon *hermon,
+				  struct hermon_port *port,
+				  int link_up );
+	/** Unregister port
+	 *
+	 * @v hermon		Hermon device
+	 * @v port		Hermon port
+	 */
+	void ( * unregister_dev ) ( struct hermon *hermon,
+				    struct hermon_port *port );
+};
+
+/** A Hermon port */
+struct hermon_port {
+	/** Infiniband device */
+	struct ib_device *ibdev;
+	/** Network device */
+	struct net_device *netdev;
+	/** Ethernet completion queue */
+	struct ib_completion_queue *eth_cq;
+	/** Ethernet queue pair */
+	struct ib_queue_pair *eth_qp;
+	/** Port type */
+	struct hermon_port_type *type;
+};
+
+/** A Hermon device */
+struct hermon {
+	/** PCI configuration registers */
+	void *config;
+	/** PCI user Access Region */
+	void *uar;
+
+	/** Command toggle */
+	unsigned int toggle;
+	/** Command input mailbox */
+	void *mailbox_in;
+	/** Command output mailbox */
+	void *mailbox_out;
+
+	/** Firmware area in external memory */
+	userptr_t firmware_area;
+	/** ICM map */
+	struct hermon_icm_map icm_map[HERMON_ICM_NUM_REGIONS];
+	/** ICM area */
+	userptr_t icm;
+
+	/** Event queue */
+	struct hermon_event_queue eq;
+	/** Unrestricted LKey
+	 *
+	 * Used to get unrestricted memory access.
+	 */
+	unsigned long lkey;
+
+	/** Completion queue in-use bitmask */
+	hermon_bitmask_t cq_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_CQS ) ];
+	/** Queue pair in-use bitmask */
+	hermon_bitmask_t qp_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_QPS ) ];
+	/** MTT entry in-use bitmask */
+	hermon_bitmask_t mtt_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_MTTS ) ];
+
+	/** Device capabilities */
+	struct hermon_dev_cap cap;
+	/** Special QPN base */
+	unsigned long special_qpn_base;
+	/** QPN base */
+	unsigned long qpn_base;
+
+	/** Ports */
+	struct hermon_port port[HERMON_MAX_PORTS];
+
+	/** BOFM device */
+	struct bofm_device bofm;
+};
+
+/** Global protection domain */
+#define HERMON_GLOBAL_PD		0x123456
+
+/** Memory key prefix */
+#define HERMON_MKEY_PREFIX		0x77000000UL
+
+/*
+ * HCA commands
+ *
+ */
+
+#define HERMON_HCR_BASE			0x80680
+#define HERMON_HCR_REG(x)		( HERMON_HCR_BASE + 4 * (x) )
+#define HERMON_HCR_MAX_WAIT_MS		2000
+#define HERMON_MBOX_ALIGN		4096
+#define HERMON_MBOX_SIZE		1024
+
+/* HCA command is split into
+ *
+ * bits  11:0	Opcode
+ * bit     12	Input uses mailbox
+ * bit     13	Output uses mailbox
+ * bits 22:14	Input parameter length (in dwords)
+ * bits 31:23	Output parameter length (in dwords)
+ *
+ * Encoding the information in this way allows us to cut out several
+ * parameters to the hermon_command() call.
+ */
+#define HERMON_HCR_IN_MBOX		0x00001000UL
+#define HERMON_HCR_OUT_MBOX		0x00002000UL
+#define HERMON_HCR_OPCODE( _command )	( (_command) & 0xfff )
+#define HERMON_HCR_IN_LEN( _command )	( ( (_command) >> 12 ) & 0x7fc )
+#define HERMON_HCR_OUT_LEN( _command )	( ( (_command) >> 21 ) & 0x7fc )
+
+/** Build HCR command from component parts */
+#define HERMON_HCR_INOUT_CMD( _opcode, _in_mbox, _in_len,		     \
+			     _out_mbox, _out_len )			     \
+	( (_opcode) |							     \
+	  ( (_in_mbox) ? HERMON_HCR_IN_MBOX : 0 ) |			     \
+	  ( ( (_in_len) / 4 ) << 14 ) |					     \
+	  ( (_out_mbox) ? HERMON_HCR_OUT_MBOX : 0 ) |			     \
+	  ( ( (_out_len) / 4 ) << 23 ) )
+
+#define HERMON_HCR_IN_CMD( _opcode, _in_mbox, _in_len )			     \
+	HERMON_HCR_INOUT_CMD ( _opcode, _in_mbox, _in_len, 0, 0 )
+
+#define HERMON_HCR_OUT_CMD( _opcode, _out_mbox, _out_len )		     \
+	HERMON_HCR_INOUT_CMD ( _opcode, 0, 0, _out_mbox, _out_len )
+
+#define HERMON_HCR_VOID_CMD( _opcode )					     \
+	HERMON_HCR_INOUT_CMD ( _opcode, 0, 0, 0, 0 )
+
+#endif /* _HERMON_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.c b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.c
new file mode 100644
index 0000000..6a6a2ec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.c
@@ -0,0 +1,2430 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/i2c.h>
+#include <ipxe/bitbash.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+#include "linda.h"
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+/** A Linda send work queue */
+struct linda_send_work_queue {
+	/** Send buffer usage */
+	uint8_t *send_buf;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
+};
+
+/** A Linda receive work queue */
+struct linda_recv_work_queue {
+	/** Receive header ring */
+	void *header;
+	/** Receive header producer offset (written by hardware) */
+	struct QIB_7220_scalar header_prod;
+	/** Receive header consumer offset */
+	unsigned int header_cons;
+	/** Offset within register space of the eager array */
+	unsigned long eager_array;
+	/** Number of entries in eager array */
+	unsigned int eager_entries;
+	/** Eager array producer index */
+	unsigned int eager_prod;
+	/** Eager array consumer index */
+	unsigned int eager_cons;
+};
+
+/** A Linda HCA */
+struct linda {
+	/** Registers */
+	void *regs;
+
+	/** In-use contexts */
+	uint8_t used_ctx[LINDA_NUM_CONTEXTS];
+	/** Send work queues */
+	struct linda_send_work_queue send_wq[LINDA_NUM_CONTEXTS];
+	/** Receive work queues */
+	struct linda_recv_work_queue recv_wq[LINDA_NUM_CONTEXTS];
+
+	/** Offset within register space of the first send buffer */
+	unsigned long send_buffer_base;
+	/** Send buffer availability (reported by hardware) */
+	struct QIB_7220_SendBufAvail *sendbufavail;
+	/** Send buffer availability (maintained by software) */
+	uint8_t send_buf[LINDA_MAX_SEND_BUFS];
+	/** Send buffer availability producer counter */
+	unsigned int send_buf_prod;
+	/** Send buffer availability consumer counter */
+	unsigned int send_buf_cons;
+	/** Number of reserved send buffers (across all QPs) */
+	unsigned int reserved_send_bufs;
+
+	/** I2C bit-bashing interface */
+	struct i2c_bit_basher i2c;
+	/** I2C serial EEPROM */
+	struct i2c_device eeprom;
+};
+
+/***************************************************************************
+ *
+ * Linda register access
+ *
+ ***************************************************************************
+ *
+ * This card requires atomic 64-bit accesses.  Strange things happen
+ * if you try to use 32-bit accesses; sometimes they work, sometimes
+ * they don't, sometimes you get random data.
+ *
+ * These accessors use the "movq" MMX instruction, and so won't work
+ * on really old Pentiums (which won't have PCIe anyway, so this is
+ * something of a moot point).
+ */
+
+/**
+ * Read Linda qword register
+ *
+ * @v linda		Linda device
+ * @v dwords		Register buffer to read into
+ * @v offset		Register offset
+ */
+static void linda_readq ( struct linda *linda, uint32_t *dwords,
+			  unsigned long offset ) {
+	void *addr = ( linda->regs + offset );
+
+	__asm__ __volatile__ ( "movq (%1), %%mm0\n\t"
+			       "movq %%mm0, (%0)\n\t"
+			       : : "r" ( dwords ), "r" ( addr ) : "memory" );
+
+	DBGIO ( "[%08lx] => %08x%08x\n",
+		virt_to_phys ( addr ), dwords[1], dwords[0] );
+}
+#define linda_readq( _linda, _ptr, _offset ) \
+	linda_readq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_readq_array8b( _linda, _ptr, _offset, _idx ) \
+	linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_readq_array64k( _linda, _ptr, _offset, _idx ) \
+	linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda qword register
+ *
+ * @v linda		Linda device
+ * @v dwords		Register buffer to write
+ * @v offset		Register offset
+ */
+static void linda_writeq ( struct linda *linda, const uint32_t *dwords,
+			   unsigned long offset ) {
+	void *addr = ( linda->regs + offset );
+
+	DBGIO ( "[%08lx] <= %08x%08x\n",
+		virt_to_phys ( addr ), dwords[1], dwords[0] );
+
+	__asm__ __volatile__ ( "movq (%0), %%mm0\n\t"
+			       "movq %%mm0, (%1)\n\t"
+			       : : "r" ( dwords ), "r" ( addr ) : "memory" );
+}
+#define linda_writeq( _linda, _ptr, _offset ) \
+	linda_writeq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_writeq_array8b( _linda, _ptr, _offset, _idx ) \
+	linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_writeq_array64k( _linda, _ptr, _offset, _idx ) \
+	linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda dword register
+ *
+ * @v linda		Linda device
+ * @v dword		Value to write
+ * @v offset		Register offset
+ */
+static void linda_writel ( struct linda *linda, uint32_t dword,
+			   unsigned long offset ) {
+	writel ( dword, ( linda->regs + offset ) );
+}
+
+/***************************************************************************
+ *
+ * Link state management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Textual representation of link state
+ *
+ * @v link_state	Link state
+ * @ret link_text	Link state text
+ */
+static const char * linda_link_state_text ( unsigned int link_state ) {
+	switch ( link_state ) {
+	case LINDA_LINK_STATE_DOWN:	return "DOWN";
+	case LINDA_LINK_STATE_INIT:	return "INIT";
+	case LINDA_LINK_STATE_ARM:	return "ARM";
+	case LINDA_LINK_STATE_ACTIVE:	return "ACTIVE";
+	case LINDA_LINK_STATE_ACT_DEFER:return "ACT_DEFER";
+	default:			return "UNKNOWN";
+	}
+}
+
+/**
+ * Handle link state change
+ *
+ * @v linda		Linda device
+ */
+static void linda_link_state_changed ( struct ib_device *ibdev ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct QIB_7220_IBCStatus ibcstatus;
+	struct QIB_7220_EXTCtrl extctrl;
+	unsigned int link_state;
+	unsigned int link_width;
+	unsigned int link_speed;
+
+	/* Read link state */
+	linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset );
+	link_state = BIT_GET ( &ibcstatus, LinkState );
+	link_width = BIT_GET ( &ibcstatus, LinkWidthActive );
+	link_speed = BIT_GET ( &ibcstatus, LinkSpeedActive );
+	DBGC ( linda, "Linda %p link state %s (%s %s)\n", linda,
+	       linda_link_state_text ( link_state ),
+	       ( link_speed ? "DDR" : "SDR" ), ( link_width ? "x4" : "x1" ) );
+
+	/* Set LEDs according to link state */
+	linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+	BIT_SET ( &extctrl, LEDPriPortGreenOn,
+		  ( ( link_state >= LINDA_LINK_STATE_INIT ) ? 1 : 0 ) );
+	BIT_SET ( &extctrl, LEDPriPortYellowOn,
+		  ( ( link_state >= LINDA_LINK_STATE_ACTIVE ) ? 1 : 0 ) );
+	linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+
+	/* Notify Infiniband core of link state change */
+	ibdev->port_state = ( link_state + 1 );
+	ibdev->link_width_active =
+		( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X );
+	ibdev->link_speed_active =
+		( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR );
+	ib_link_state_changed ( ibdev );
+}
+
+/**
+ * Wait for link state change to take effect
+ *
+ * @v linda		Linda device
+ * @v new_link_state	Expected link state
+ * @ret rc		Return status code
+ */
+static int linda_link_state_check ( struct linda *linda,
+				    unsigned int new_link_state ) {
+	struct QIB_7220_IBCStatus ibcstatus;
+	unsigned int link_state;
+	unsigned int i;
+
+	for ( i = 0 ; i < LINDA_LINK_STATE_MAX_WAIT_US ; i++ ) {
+		linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset );
+		link_state = BIT_GET ( &ibcstatus, LinkState );
+		if ( link_state == new_link_state )
+			return 0;
+		udelay ( 1 );
+	}
+
+	DBGC ( linda, "Linda %p timed out waiting for link state %s\n",
+	       linda, linda_link_state_text ( link_state ) );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set port information MAD
+ */
+static int linda_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+	struct QIB_7220_IBCCtrl ibcctrl;
+	unsigned int port_state;
+	unsigned int link_state;
+
+	/* Set new link state */
+	port_state = ( port_info->link_speed_supported__port_state & 0xf );
+	if ( port_state ) {
+		link_state = ( port_state - 1 );
+		DBGC ( linda, "Linda %p set link state to %s (%x)\n", linda,
+		       linda_link_state_text ( link_state ), link_state );
+		linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+		BIT_SET ( &ibcctrl, LinkCmd, link_state );
+		linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+
+		/* Wait for link state change to take effect.  Ignore
+		 * errors; the current link state will be returned via
+		 * the GetResponse MAD.
+		 */
+		linda_link_state_check ( linda, link_state );
+	}
+
+	/* Detect and report link state change */
+	linda_link_state_changed ( ibdev );
+
+	return 0;
+}
+
+/**
+ * Set partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set partition key table MAD
+ */
+static int linda_set_pkey_table ( struct ib_device *ibdev __unused,
+				  union ib_mad *mad __unused ) {
+	/* Nothing to do */
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Context allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Map context number to QPN
+ *
+ * @v ctx		Context index
+ * @ret qpn		Queue pair number
+ */
+static int linda_ctx_to_qpn ( unsigned int ctx ) {
+	/* This mapping is fixed by hardware */
+	return ( ctx * 2 );
+}
+
+/**
+ * Map QPN to context number
+ *
+ * @v qpn		Queue pair number
+ * @ret ctx		Context index
+ */
+static int linda_qpn_to_ctx ( unsigned int qpn ) {
+	/* This mapping is fixed by hardware */
+	return ( qpn / 2 );
+}
+
+/**
+ * Allocate a context
+ *
+ * @v linda		Linda device
+ * @ret ctx		Context index, or negative error
+ */
+static int linda_alloc_ctx ( struct linda *linda ) {
+	unsigned int ctx;
+
+	for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+
+		if ( ! linda->used_ctx[ctx] ) {
+			linda->used_ctx[ctx ] = 1;
+			DBGC2 ( linda, "Linda %p CTX %d allocated\n",
+				linda, ctx );
+			return ctx;
+		}
+	}
+
+	DBGC ( linda, "Linda %p out of available contexts\n", linda );
+	return -ENOENT;
+}
+
+/**
+ * Free a context
+ *
+ * @v linda		Linda device
+ * @v ctx		Context index
+ */
+static void linda_free_ctx ( struct linda *linda, unsigned int ctx ) {
+
+	linda->used_ctx[ctx] = 0;
+	DBGC2 ( linda, "Linda %p CTX %d freed\n", linda, ctx );
+}
+
+/***************************************************************************
+ *
+ * Send datapath
+ *
+ ***************************************************************************
+ */
+
+/** Send buffer toggle bit
+ *
+ * We encode send buffers as 7 bits of send buffer index plus a single
+ * bit which should match the "check" bit in the SendBufAvail array.
+ */
+#define LINDA_SEND_BUF_TOGGLE 0x80
+
+/**
+ * Allocate a send buffer
+ *
+ * @v linda		Linda device
+ * @ret send_buf	Send buffer
+ *
+ * You must guarantee that a send buffer is available.  This is done
+ * by refusing to allocate more TX WQEs in total than the number of
+ * available send buffers.
+ */
+static unsigned int linda_alloc_send_buf ( struct linda *linda ) {
+	unsigned int send_buf;
+
+	send_buf = linda->send_buf[linda->send_buf_cons];
+	send_buf ^= LINDA_SEND_BUF_TOGGLE;
+	linda->send_buf_cons = ( ( linda->send_buf_cons + 1 ) %
+				 LINDA_MAX_SEND_BUFS );
+	return send_buf;
+}
+
+/**
+ * Free a send buffer
+ *
+ * @v linda		Linda device
+ * @v send_buf		Send buffer
+ */
+static void linda_free_send_buf ( struct linda *linda,
+				  unsigned int send_buf ) {
+	linda->send_buf[linda->send_buf_prod] = send_buf;
+	linda->send_buf_prod = ( ( linda->send_buf_prod + 1 ) %
+				 LINDA_MAX_SEND_BUFS );
+}
+
+/**
+ * Check to see if send buffer is in use
+ *
+ * @v linda		Linda device
+ * @v send_buf		Send buffer
+ * @ret in_use		Send buffer is in use
+ */
+static int linda_send_buf_in_use ( struct linda *linda,
+				   unsigned int send_buf ) {
+	unsigned int send_idx;
+	unsigned int send_check;
+	unsigned int inusecheck;
+	unsigned int inuse;
+	unsigned int check;
+
+	send_idx = ( send_buf & ~LINDA_SEND_BUF_TOGGLE );
+	send_check = ( !! ( send_buf & LINDA_SEND_BUF_TOGGLE ) );
+	inusecheck = BIT_GET ( linda->sendbufavail, InUseCheck[send_idx] );
+	inuse = ( !! ( inusecheck & 0x02 ) );
+	check = ( !! ( inusecheck & 0x01 ) );
+	return ( inuse || ( check != send_check ) );
+}
+
+/**
+ * Calculate starting offset for send buffer
+ *
+ * @v linda		Linda device
+ * @v send_buf		Send buffer
+ * @ret offset		Starting offset
+ */
+static unsigned long linda_send_buffer_offset ( struct linda *linda,
+						unsigned int send_buf ) {
+	return ( linda->send_buffer_base +
+		 ( ( send_buf & ~LINDA_SEND_BUF_TOGGLE ) *
+		   LINDA_SEND_BUF_SIZE ) );
+}
+
+/**
+ * Create send work queue
+ *
+ * @v linda		Linda device
+ * @v qp		Queue pair
+ */
+static int linda_create_send_wq ( struct linda *linda,
+				  struct ib_queue_pair *qp ) {
+	struct ib_work_queue *wq = &qp->send;
+	struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	int rc;
+
+	/* Reserve send buffers */
+	if ( ( linda->reserved_send_bufs + qp->send.num_wqes ) >
+	     LINDA_MAX_SEND_BUFS ) {
+		DBGC ( linda, "Linda %p out of send buffers (have %d, used "
+		       "%d, need %d)\n", linda, LINDA_MAX_SEND_BUFS,
+		       linda->reserved_send_bufs, qp->send.num_wqes );
+		rc = -ENOBUFS;
+		goto err_reserve_bufs;
+	}
+	linda->reserved_send_bufs += qp->send.num_wqes;
+
+	/* Reset work queue */
+	linda_wq->prod = 0;
+	linda_wq->cons = 0;
+
+	/* Allocate space for send buffer uasge list */
+	linda_wq->send_buf = zalloc ( qp->send.num_wqes *
+				      sizeof ( linda_wq->send_buf[0] ) );
+	if ( ! linda_wq->send_buf ) {
+		rc = -ENOBUFS;
+		goto err_alloc_send_buf;
+	}
+
+	return 0;
+
+	free ( linda_wq->send_buf );
+ err_alloc_send_buf:
+	linda->reserved_send_bufs -= qp->send.num_wqes;
+ err_reserve_bufs:
+	return rc;
+}
+
+/**
+ * Destroy send work queue
+ *
+ * @v linda		Linda device
+ * @v qp		Queue pair
+ */
+static void linda_destroy_send_wq ( struct linda *linda,
+				    struct ib_queue_pair *qp ) {
+	struct ib_work_queue *wq = &qp->send;
+	struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+
+	free ( linda_wq->send_buf );
+	linda->reserved_send_bufs -= qp->send.num_wqes;
+}
+
+/**
+ * Initialise send datapath
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_init_send ( struct linda *linda ) {
+	struct QIB_7220_SendBufBase sendbufbase;
+	struct QIB_7220_SendBufAvailAddr sendbufavailaddr;
+	struct QIB_7220_SendCtrl sendctrl;
+	unsigned int i;
+	int rc;
+
+	/* Retrieve SendBufBase */
+	linda_readq ( linda, &sendbufbase, QIB_7220_SendBufBase_offset );
+	linda->send_buffer_base = BIT_GET ( &sendbufbase,
+					    BaseAddr_SmallPIO );
+	DBGC ( linda, "Linda %p send buffers at %lx\n",
+	       linda, linda->send_buffer_base );
+
+	/* Initialise the send_buf[] array */
+	for ( i = 0 ; i < LINDA_MAX_SEND_BUFS ; i++ )
+		linda->send_buf[i] = i;
+
+	/* Allocate space for the SendBufAvail array */
+	linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ),
+					   LINDA_SENDBUFAVAIL_ALIGN );
+	if ( ! linda->sendbufavail ) {
+		rc = -ENOMEM;
+		goto err_alloc_sendbufavail;
+	}
+	memset ( linda->sendbufavail, 0, sizeof ( linda->sendbufavail ) );
+
+	/* Program SendBufAvailAddr into the hardware */
+	memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) );
+	BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr,
+		     ( virt_to_bus ( linda->sendbufavail ) >> 6 ) );
+	linda_writeq ( linda, &sendbufavailaddr,
+		       QIB_7220_SendBufAvailAddr_offset );
+
+	/* Enable sending and DMA of SendBufAvail */
+	memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+	BIT_FILL_2 ( &sendctrl,
+		     SendBufAvailUpd, 1,
+		     SPioEnable, 1 );
+	linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+	return 0;
+
+	free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+ err_alloc_sendbufavail:
+	return rc;
+}
+
+/**
+ * Shut down send datapath
+ *
+ * @v linda		Linda device
+ */
+static void linda_fini_send ( struct linda *linda ) {
+	struct QIB_7220_SendCtrl sendctrl;
+
+	/* Disable sending and DMA of SendBufAvail */
+	memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+	linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+	mb();
+
+	/* Ensure hardware has seen this disable */
+	linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+	free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+}
+
+/***************************************************************************
+ *
+ * Receive datapath
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create receive work queue
+ *
+ * @v linda		Linda device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int linda_create_recv_wq ( struct linda *linda,
+				  struct ib_queue_pair *qp ) {
+	struct ib_work_queue *wq = &qp->recv;
+	struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_RcvHdrAddr0 rcvhdraddr;
+	struct QIB_7220_RcvHdrTailAddr0 rcvhdrtailaddr;
+	struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+	struct QIB_7220_scalar rcvegrindexhead;
+	struct QIB_7220_RcvCtrl rcvctrl;
+	unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+	int rc;
+
+	/* Reset context information */
+	memset ( &linda_wq->header_prod, 0,
+		 sizeof ( linda_wq->header_prod ) );
+	linda_wq->header_cons = 0;
+	linda_wq->eager_prod = 0;
+	linda_wq->eager_cons = 0;
+
+	/* Allocate receive header buffer */
+	linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE,
+					LINDA_RECV_HEADERS_ALIGN );
+	if ( ! linda_wq->header ) {
+		rc = -ENOMEM;
+		goto err_alloc_header;
+	}
+
+	/* Enable context in hardware */
+	memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) );
+	BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr0,
+		     ( virt_to_bus ( linda_wq->header ) >> 2 ) );
+	linda_writeq_array8b ( linda, &rcvhdraddr,
+			       QIB_7220_RcvHdrAddr0_offset, ctx );
+	memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) );
+	BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr0,
+		     ( virt_to_bus ( &linda_wq->header_prod ) >> 2 ) );
+	linda_writeq_array8b ( linda, &rcvhdrtailaddr,
+			       QIB_7220_RcvHdrTailAddr0_offset, ctx );
+	memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+	BIT_FILL_1 ( &rcvhdrhead, counter, 1 );
+	linda_writeq_array64k ( linda, &rcvhdrhead,
+				QIB_7220_RcvHdrHead0_offset, ctx );
+	memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+	BIT_FILL_1 ( &rcvegrindexhead, Value, 1 );
+	linda_writeq_array64k ( linda, &rcvegrindexhead,
+				QIB_7220_RcvEgrIndexHead0_offset, ctx );
+	linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+	BIT_SET ( &rcvctrl, PortEnable[ctx], 1 );
+	BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 );
+	linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+	DBGC ( linda, "Linda %p QPN %ld CTX %d hdrs [%lx,%lx) prod %lx\n",
+	       linda, qp->qpn, ctx, virt_to_bus ( linda_wq->header ),
+	       ( virt_to_bus ( linda_wq->header ) + LINDA_RECV_HEADERS_SIZE ),
+	       virt_to_bus ( &linda_wq->header_prod ) );
+	return 0;
+
+	free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+ err_alloc_header:
+	return rc;
+}
+
+/**
+ * Destroy receive work queue
+ *
+ * @v linda		Linda device
+ * @v qp		Queue pair
+ */
+static void linda_destroy_recv_wq ( struct linda *linda,
+				    struct ib_queue_pair *qp ) {
+	struct ib_work_queue *wq = &qp->recv;
+	struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_RcvCtrl rcvctrl;
+	unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+
+	/* Disable context in hardware */
+	linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+	BIT_SET ( &rcvctrl, PortEnable[ctx], 0 );
+	BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 );
+	linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+	/* Make sure the hardware has seen that the context is disabled */
+	linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+	mb();
+
+	/* Free headers ring */
+	free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+
+	/* Free context */
+	linda_free_ctx ( linda, ctx );
+}
+
+/**
+ * Initialise receive datapath
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_init_recv ( struct linda *linda ) {
+	struct QIB_7220_RcvCtrl rcvctrl;
+	struct QIB_7220_scalar rcvegrbase;
+	struct QIB_7220_scalar rcvhdrentsize;
+	struct QIB_7220_scalar rcvhdrcnt;
+	struct QIB_7220_RcvBTHQP rcvbthqp;
+	unsigned int portcfg;
+	unsigned long egrbase;
+	unsigned int eager_array_size_0;
+	unsigned int eager_array_size_other;
+	unsigned int ctx;
+
+	/* Select configuration based on number of contexts */
+	switch ( LINDA_NUM_CONTEXTS ) {
+	case 5:
+		portcfg = LINDA_PORTCFG_5CTX;
+		eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_5CTX_0;
+		eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER;
+		break;
+	case 9:
+		portcfg = LINDA_PORTCFG_9CTX;
+		eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_9CTX_0;
+		eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER;
+		break;
+	case 17:
+		portcfg = LINDA_PORTCFG_17CTX;
+		eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_17CTX_0;
+		eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER;
+		break;
+	default:
+		linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS );
+		return -EINVAL;
+	}
+
+	/* Configure number of contexts */
+	memset ( &rcvctrl, 0, sizeof ( rcvctrl ) );
+	BIT_FILL_3 ( &rcvctrl,
+		     TailUpd, 1,
+		     PortCfg, portcfg,
+		     RcvQPMapEnable, 1 );
+	linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+	/* Configure receive header buffer sizes */
+	memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) );
+	BIT_FILL_1 ( &rcvhdrcnt, Value, LINDA_RECV_HEADER_COUNT );
+	linda_writeq ( linda, &rcvhdrcnt, QIB_7220_RcvHdrCnt_offset );
+	memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) );
+	BIT_FILL_1 ( &rcvhdrentsize, Value, ( LINDA_RECV_HEADER_SIZE >> 2 ) );
+	linda_writeq ( linda, &rcvhdrentsize, QIB_7220_RcvHdrEntSize_offset );
+
+	/* Calculate eager array start addresses for each context */
+	linda_readq ( linda, &rcvegrbase, QIB_7220_RcvEgrBase_offset );
+	egrbase = BIT_GET ( &rcvegrbase, Value );
+	linda->recv_wq[0].eager_array = egrbase;
+	linda->recv_wq[0].eager_entries = eager_array_size_0;
+	egrbase += ( eager_array_size_0 * sizeof ( struct QIB_7220_RcvEgr ) );
+	for ( ctx = 1 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+		linda->recv_wq[ctx].eager_array = egrbase;
+		linda->recv_wq[ctx].eager_entries = eager_array_size_other;
+		egrbase += ( eager_array_size_other *
+			     sizeof ( struct QIB_7220_RcvEgr ) );
+	}
+	for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+		DBGC ( linda, "Linda %p CTX %d eager array at %lx (%d "
+		       "entries)\n", linda, ctx,
+		       linda->recv_wq[ctx].eager_array,
+		       linda->recv_wq[ctx].eager_entries );
+	}
+
+	/* Set the BTH QP for Infinipath packets to an unused value */
+	memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) );
+	BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, LINDA_QP_IDETH );
+	linda_writeq ( linda, &rcvbthqp, QIB_7220_RcvBTHQP_offset );
+
+	return 0;
+}
+
+/**
+ * Shut down receive datapath
+ *
+ * @v linda		Linda device
+ */
+static void linda_fini_recv ( struct linda *linda __unused ) {
+	/* Nothing to do; all contexts were already disabled when the
+	 * queue pairs were destroyed
+	 */
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static int linda_create_cq ( struct ib_device *ibdev,
+			     struct ib_completion_queue *cq ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	static int cqn;
+
+	/* The hardware has no concept of completion queues.  We
+	 * simply use the association between CQs and WQs (already
+	 * handled by the IB core) to decide which WQs to poll.
+	 *
+	 * We do set a CQN, just to avoid confusing debug messages
+	 * from the IB core.
+	 */
+	cq->cqn = ++cqn;
+	DBGC ( linda, "Linda %p CQN %ld created\n", linda, cq->cqn );
+
+	return 0;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void linda_destroy_cq ( struct ib_device *ibdev,
+			       struct ib_completion_queue *cq ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	/* Nothing to do */
+	DBGC ( linda, "Linda %p CQN %ld destroyed\n", linda, cq->cqn );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int linda_create_qp ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	int ctx;
+	int rc;
+
+	/* Locate an available context */
+	ctx = linda_alloc_ctx ( linda );
+	if ( ctx < 0 ) {
+		rc = ctx;
+		goto err_alloc_ctx;
+	}
+
+	/* Set queue pair number based on context index */
+	qp->qpn = linda_ctx_to_qpn ( ctx );
+
+	/* Set work-queue private data pointers */
+	ib_wq_set_drvdata ( &qp->send, &linda->send_wq[ctx] );
+	ib_wq_set_drvdata ( &qp->recv, &linda->recv_wq[ctx] );
+
+	/* Create receive work queue */
+	if ( ( rc = linda_create_recv_wq ( linda, qp ) ) != 0 )
+		goto err_create_recv_wq;
+
+	/* Create send work queue */
+	if ( ( rc = linda_create_send_wq ( linda, qp ) ) != 0 )
+		goto err_create_send_wq;
+
+	return 0;
+
+	linda_destroy_send_wq ( linda, qp );
+ err_create_send_wq:
+	linda_destroy_recv_wq ( linda, qp );
+ err_create_recv_wq:
+	linda_free_ctx ( linda, ctx );
+ err_alloc_ctx:
+	return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int linda_modify_qp ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	/* Nothing to do; the hardware doesn't have a notion of queue
+	 * keys
+	 */
+	DBGC ( linda, "Linda %p QPN %ld modified\n", linda, qp->qpn );
+	return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void linda_destroy_qp ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	linda_destroy_send_wq ( linda, qp );
+	linda_destroy_recv_wq ( linda, qp );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int linda_post_send ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp,
+			     struct ib_address_vector *av,
+			     struct io_buffer *iobuf ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_SendPbc sendpbc;
+	uint8_t header_buf[IB_MAX_HEADER_SIZE];
+	struct io_buffer headers;
+	unsigned int send_buf;
+	unsigned long start_offset;
+	unsigned long offset;
+	size_t len;
+	ssize_t frag_len;
+	uint32_t *data;
+
+	/* Allocate send buffer and calculate offset */
+	send_buf = linda_alloc_send_buf ( linda );
+	start_offset = offset = linda_send_buffer_offset ( linda, send_buf );
+
+	/* Store I/O buffer and send buffer index */
+	assert ( wq->iobufs[linda_wq->prod] == NULL );
+	wq->iobufs[linda_wq->prod] = iobuf;
+	linda_wq->send_buf[linda_wq->prod] = send_buf;
+
+	/* Construct headers */
+	iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) );
+	iob_reserve ( &headers, sizeof ( header_buf ) );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+	/* Calculate packet length */
+	len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
+		  iob_len ( iobuf ) + 3 ) & ~3 );
+
+	/* Construct send per-buffer control word */
+	memset ( &sendpbc, 0, sizeof ( sendpbc ) );
+	BIT_FILL_2 ( &sendpbc,
+		     LengthP1_toibc, ( ( len >> 2 ) - 1 ),
+		     VL15, 1 );
+
+	/* Write SendPbc */
+	DBG_DISABLE ( DBGLVL_IO );
+	linda_writeq ( linda, &sendpbc, offset );
+	offset += sizeof ( sendpbc );
+
+	/* Write headers */
+	for ( data = headers.data, frag_len = iob_len ( &headers ) ;
+	      frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+		linda_writel ( linda, *data, offset );
+	}
+
+	/* Write data */
+	for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ;
+	      frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+		linda_writel ( linda, *data, offset );
+	}
+	DBG_ENABLE ( DBGLVL_IO );
+
+	assert ( ( start_offset + len ) == offset );
+	DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) posted [%lx,%lx)\n",
+		linda, qp->qpn, send_buf, linda_wq->prod,
+		start_offset, offset );
+
+	/* Increment producer counter */
+	linda_wq->prod = ( ( linda_wq->prod + 1 ) & ( wq->num_wqes - 1 ) );
+
+	return 0;
+}
+
+/**
+ * Complete send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v wqe_idx		Work queue entry index
+ */
+static void linda_complete_send ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp,
+				  unsigned int wqe_idx ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct io_buffer *iobuf;
+	unsigned int send_buf;
+
+	/* Parse completion */
+	send_buf = linda_wq->send_buf[wqe_idx];
+	DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) complete\n",
+		linda, qp->qpn, send_buf, wqe_idx );
+
+	/* Complete work queue entry */
+	iobuf = wq->iobufs[wqe_idx];
+	assert ( iobuf != NULL );
+	ib_complete_send ( ibdev, qp, iobuf, 0 );
+	wq->iobufs[wqe_idx] = NULL;
+
+	/* Free send buffer */
+	linda_free_send_buf ( linda, send_buf );
+}
+
+/**
+ * Poll send work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void linda_poll_send_wq ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	unsigned int send_buf;
+
+	/* Look for completions */
+	while ( wq->fill ) {
+
+		/* Check to see if send buffer has completed */
+		send_buf = linda_wq->send_buf[linda_wq->cons];
+		if ( linda_send_buf_in_use ( linda, send_buf ) )
+			break;
+
+		/* Complete this buffer */
+		linda_complete_send ( ibdev, qp, linda_wq->cons );
+
+		/* Increment consumer counter */
+		linda_wq->cons = ( ( linda_wq->cons + 1 ) &
+				   ( wq->num_wqes - 1 ) );
+	}
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int linda_post_recv ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp,
+			     struct io_buffer *iobuf ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_RcvEgr rcvegr;
+	struct QIB_7220_scalar rcvegrindexhead;
+	unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+	physaddr_t addr;
+	size_t len;
+	unsigned int wqe_idx;
+	unsigned int bufsize;
+
+	/* Sanity checks */
+	addr = virt_to_bus ( iobuf->data );
+	len = iob_tailroom ( iobuf );
+	if ( addr & ( LINDA_EAGER_BUFFER_ALIGN - 1 ) ) {
+		DBGC ( linda, "Linda %p QPN %ld misaligned RX buffer "
+		       "(%08lx)\n", linda, qp->qpn, addr );
+		return -EINVAL;
+	}
+	if ( len != LINDA_RECV_PAYLOAD_SIZE ) {
+		DBGC ( linda, "Linda %p QPN %ld wrong RX buffer size (%zd)\n",
+		       linda, qp->qpn, len );
+		return -EINVAL;
+	}
+
+	/* Calculate eager producer index and WQE index */
+	wqe_idx = ( linda_wq->eager_prod & ( wq->num_wqes - 1 ) );
+	assert ( wq->iobufs[wqe_idx] == NULL );
+
+	/* Store I/O buffer */
+	wq->iobufs[wqe_idx] = iobuf;
+
+	/* Calculate buffer size */
+	switch ( LINDA_RECV_PAYLOAD_SIZE ) {
+	case 2048:  bufsize = LINDA_EAGER_BUFFER_2K;  break;
+	case 4096:  bufsize = LINDA_EAGER_BUFFER_4K;  break;
+	case 8192:  bufsize = LINDA_EAGER_BUFFER_8K;  break;
+	case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break;
+	case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break;
+	case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break;
+	default:    linker_assert ( 0, invalid_rx_payload_size );
+		    bufsize = LINDA_EAGER_BUFFER_NONE;
+	}
+
+	/* Post eager buffer */
+	memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+	BIT_FILL_2 ( &rcvegr,
+		     Addr, ( addr >> 11 ),
+		     BufSize, bufsize );
+	linda_writeq_array8b ( linda, &rcvegr,
+			       linda_wq->eager_array, linda_wq->eager_prod );
+	DBGC2 ( linda, "Linda %p QPN %ld RX egr %d(%d) posted [%lx,%lx)\n",
+		linda, qp->qpn, linda_wq->eager_prod, wqe_idx,
+		addr, ( addr + len ) );
+
+	/* Increment producer index */
+	linda_wq->eager_prod = ( ( linda_wq->eager_prod + 1 ) &
+				 ( linda_wq->eager_entries - 1 ) );
+
+	/* Update head index */
+	memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+	BIT_FILL_1 ( &rcvegrindexhead,
+		     Value, ( ( linda_wq->eager_prod + 1 ) &
+			      ( linda_wq->eager_entries - 1 ) ) );
+	linda_writeq_array64k ( linda, &rcvegrindexhead,
+				QIB_7220_RcvEgrIndexHead0_offset, ctx );
+
+	return 0;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v header_offs	Header offset
+ */
+static void linda_complete_recv ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp,
+				  unsigned int header_offs ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_RcvHdrFlags *rcvhdrflags;
+	struct QIB_7220_RcvEgr rcvegr;
+	struct io_buffer headers;
+	struct io_buffer *iobuf;
+	struct ib_queue_pair *intended_qp;
+	struct ib_address_vector av;
+	unsigned int rcvtype;
+	unsigned int pktlen;
+	unsigned int egrindex;
+	unsigned int useegrbfr;
+	unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr;
+	unsigned int lenerr, parityerr, vcrcerr, icrcerr;
+	unsigned int err;
+	unsigned int hdrqoffset;
+	unsigned int header_len;
+	unsigned int padded_payload_len;
+	unsigned int wqe_idx;
+	size_t payload_len;
+	int qp0;
+	int rc;
+
+	/* RcvHdrFlags are at the end of the header entry */
+	rcvhdrflags = ( linda_wq->header + header_offs +
+			LINDA_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) );
+	rcvtype = BIT_GET ( rcvhdrflags, RcvType );
+	pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 );
+	egrindex = BIT_GET ( rcvhdrflags, EgrIndex );
+	useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr );
+	hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 );
+	iberr = BIT_GET ( rcvhdrflags, IBErr );
+	mkerr = BIT_GET ( rcvhdrflags, MKErr );
+	tiderr = BIT_GET ( rcvhdrflags, TIDErr );
+	khdrerr = BIT_GET ( rcvhdrflags, KHdrErr );
+	mtuerr = BIT_GET ( rcvhdrflags, MTUErr );
+	lenerr = BIT_GET ( rcvhdrflags, LenErr );
+	parityerr = BIT_GET ( rcvhdrflags, ParityErr );
+	vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr );
+	icrcerr = BIT_GET ( rcvhdrflags, ICRCErr );
+	header_len = ( LINDA_RECV_HEADER_SIZE - hdrqoffset -
+		       sizeof ( *rcvhdrflags ) );
+	padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ );
+	err = ( iberr | mkerr | tiderr | khdrerr | mtuerr |
+		lenerr | parityerr | vcrcerr | icrcerr );
+	/* IB header is placed immediately before RcvHdrFlags */
+	iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ),
+		       header_len, header_len );
+
+	/* Dump diagnostic information */
+	if ( err || ( ! useegrbfr ) ) {
+		DBGC ( linda, "Linda %p QPN %ld RX egr %d%s hdr %d type %d "
+		       "len %d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", linda,
+		       qp->qpn, egrindex, ( useegrbfr ? "" : "(unused)" ),
+		       ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+		       pktlen, header_len, padded_payload_len,
+		       ( err ? " [Err" : "" ), ( iberr ? " IB" : "" ),
+		       ( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ),
+		       ( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ),
+		       ( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""),
+		       ( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ),
+		       ( err ? "]" : "" ) );
+	} else {
+		DBGC2 ( linda, "Linda %p QPN %ld RX egr %d hdr %d type %d "
+			"len %d(%d+%d+4)\n", linda, qp->qpn, egrindex,
+			( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+			pktlen, header_len, padded_payload_len );
+	}
+	DBGCP_HDA ( linda, hdrqoffset, headers.data,
+		    ( header_len + sizeof ( *rcvhdrflags ) ) );
+
+	/* Parse header to generate address vector */
+	qp0 = ( qp->qpn == 0 );
+	intended_qp = NULL;
+	if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
+			      &payload_len, &av ) ) != 0 ) {
+		DBGC ( linda, "Linda %p could not parse headers: %s\n",
+		       linda, strerror ( rc ) );
+		err = 1;
+	}
+	if ( ! intended_qp )
+		intended_qp = qp;
+
+	/* Complete this buffer and any skipped buffers.  Note that
+	 * when the hardware runs out of buffers, it will repeatedly
+	 * report the same buffer (the tail) as a TID error, and that
+	 * it also has a habit of sometimes skipping over several
+	 * buffers at once.
+	 */
+	while ( 1 ) {
+
+		/* If we have caught up to the producer counter, stop.
+		 * This will happen when the hardware first runs out
+		 * of buffers and starts reporting TID errors against
+		 * the eager buffer it wants to use next.
+		 */
+		if ( linda_wq->eager_cons == linda_wq->eager_prod )
+			break;
+
+		/* If we have caught up to where we should be after
+		 * completing this egrindex, stop.  We phrase the test
+		 * this way to avoid completing the entire ring when
+		 * we receive the same egrindex twice in a row.
+		 */
+		if ( ( linda_wq->eager_cons ==
+		       ( ( egrindex + 1 ) & ( linda_wq->eager_entries - 1 ) )))
+			break;
+
+		/* Identify work queue entry and corresponding I/O
+		 * buffer.
+		 */
+		wqe_idx = ( linda_wq->eager_cons & ( wq->num_wqes - 1 ) );
+		iobuf = wq->iobufs[wqe_idx];
+		assert ( iobuf != NULL );
+		wq->iobufs[wqe_idx] = NULL;
+
+		/* Complete the eager buffer */
+		if ( linda_wq->eager_cons == egrindex ) {
+			/* Completing the eager buffer described in
+			 * this header entry.
+			 */
+			iob_put ( iobuf, payload_len );
+			rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) );
+			/* Redirect to target QP if necessary */
+			if ( qp != intended_qp ) {
+				DBGC ( linda, "Linda %p redirecting QPN %ld "
+				       "=> %ld\n",
+				       linda, qp->qpn, intended_qp->qpn );
+				/* Compensate for incorrect fill levels */
+				qp->recv.fill--;
+				intended_qp->recv.fill++;
+			}
+			ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+		} else {
+			/* Completing on a skipped-over eager buffer */
+			ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+		}
+
+		/* Clear eager buffer */
+		memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+		linda_writeq_array8b ( linda, &rcvegr, linda_wq->eager_array,
+				       linda_wq->eager_cons );
+
+		/* Increment consumer index */
+		linda_wq->eager_cons = ( ( linda_wq->eager_cons + 1 ) &
+					 ( linda_wq->eager_entries - 1 ) );
+	}
+}
+
+/**
+ * Poll receive work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void linda_poll_recv_wq ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+	unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+	unsigned int header_prod;
+
+	/* Check for received packets */
+	header_prod = ( BIT_GET ( &linda_wq->header_prod, Value ) << 2 );
+	if ( header_prod == linda_wq->header_cons )
+		return;
+
+	/* Process all received packets */
+	while ( linda_wq->header_cons != header_prod ) {
+
+		/* Complete the receive */
+		linda_complete_recv ( ibdev, qp, linda_wq->header_cons );
+
+		/* Increment the consumer offset */
+		linda_wq->header_cons += LINDA_RECV_HEADER_SIZE;
+		linda_wq->header_cons %= LINDA_RECV_HEADERS_SIZE;
+	}
+
+	/* Update consumer offset */
+	memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+	BIT_FILL_2 ( &rcvhdrhead,
+		     RcvHeadPointer, ( linda_wq->header_cons >> 2 ),
+		     counter, 1 );
+	linda_writeq_array64k ( linda, &rcvhdrhead,
+				QIB_7220_RcvHdrHead0_offset, ctx );
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void linda_poll_cq ( struct ib_device *ibdev,
+			    struct ib_completion_queue *cq ) {
+	struct ib_work_queue *wq;
+
+	/* Poll associated send and receive queues */
+	list_for_each_entry ( wq, &cq->work_queues, list ) {
+		if ( wq->is_send ) {
+			linda_poll_send_wq ( ibdev, wq->qp );
+		} else {
+			linda_poll_recv_wq ( ibdev, wq->qp );
+		}
+	}
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev		Infiniband device
+ */
+static void linda_poll_eq ( struct ib_device *ibdev ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct QIB_7220_ErrStatus errstatus;
+	struct QIB_7220_ErrClear errclear;
+
+	/* Check for link status changes */
+	DBG_DISABLE ( DBGLVL_IO );
+	linda_readq ( linda, &errstatus, QIB_7220_ErrStatus_offset );
+	DBG_ENABLE ( DBGLVL_IO );
+	if ( BIT_GET ( &errstatus, IBStatusChanged ) ) {
+		linda_link_state_changed ( ibdev );
+		memset ( &errclear, 0, sizeof ( errclear ) );
+		BIT_FILL_1 ( &errclear, IBStatusChangedClear, 1 );
+		linda_writeq ( linda, &errclear, QIB_7220_ErrClear_offset );
+	}
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int linda_open ( struct ib_device *ibdev ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct QIB_7220_Control control;
+
+	/* Disable link */
+	linda_readq ( linda, &control, QIB_7220_Control_offset );
+	BIT_SET ( &control, LinkEn, 1 );
+	linda_writeq ( linda, &control, QIB_7220_Control_offset );
+	return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ */
+static void linda_close ( struct ib_device *ibdev ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+	struct QIB_7220_Control control;
+
+	/* Disable link */
+	linda_readq ( linda, &control, QIB_7220_Control_offset );
+	BIT_SET ( &control, LinkEn, 0 );
+	linda_writeq ( linda, &control, QIB_7220_Control_offset );
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ * @ret rc		Return status code
+ */
+static int linda_mcast_attach ( struct ib_device *ibdev,
+				struct ib_queue_pair *qp,
+				union ib_gid *gid ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	( void ) linda;
+	( void ) qp;
+	( void ) gid;
+	return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void linda_mcast_detach ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp,
+				 union ib_gid *gid ) {
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	( void ) linda;
+	( void ) qp;
+	( void ) gid;
+}
+
+/** Linda Infiniband operations */
+static struct ib_device_operations linda_ib_operations = {
+	.create_cq	= linda_create_cq,
+	.destroy_cq	= linda_destroy_cq,
+	.create_qp	= linda_create_qp,
+	.modify_qp	= linda_modify_qp,
+	.destroy_qp	= linda_destroy_qp,
+	.post_send	= linda_post_send,
+	.post_recv	= linda_post_recv,
+	.poll_cq	= linda_poll_cq,
+	.poll_eq	= linda_poll_eq,
+	.open		= linda_open,
+	.close		= linda_close,
+	.mcast_attach	= linda_mcast_attach,
+	.mcast_detach	= linda_mcast_detach,
+	.set_port_info	= linda_set_port_info,
+	.set_pkey_table	= linda_set_pkey_table,
+};
+
+/***************************************************************************
+ *
+ * I2C bus operations
+ *
+ ***************************************************************************
+ */
+
+/** Linda I2C bit to GPIO mappings */
+static unsigned int linda_i2c_bits[] = {
+	[I2C_BIT_SCL] = ( 1 << LINDA_GPIO_SCL ),
+	[I2C_BIT_SDA] = ( 1 << LINDA_GPIO_SDA ),
+};
+
+/**
+ * Read Linda I2C line status
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @ret zero		Input is a logic 0
+ * @ret non-zero	Input is a logic 1
+ */
+static int linda_i2c_read_bit ( struct bit_basher *basher,
+				unsigned int bit_id ) {
+	struct linda *linda =
+		container_of ( basher, struct linda, i2c.basher );
+	struct QIB_7220_EXTStatus extstatus;
+	unsigned int status;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	linda_readq ( linda, &extstatus, QIB_7220_EXTStatus_offset );
+	status = ( BIT_GET ( &extstatus, GPIOIn ) & linda_i2c_bits[bit_id] );
+
+	DBG_ENABLE ( DBGLVL_IO );
+
+	return status;
+}
+
+/**
+ * Write Linda I2C line status
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @v data		Value to write
+ */
+static void linda_i2c_write_bit ( struct bit_basher *basher,
+				  unsigned int bit_id, unsigned long data ) {
+	struct linda *linda =
+		container_of ( basher, struct linda, i2c.basher );
+	struct QIB_7220_EXTCtrl extctrl;
+	struct QIB_7220_GPIO gpioout;
+	unsigned int bit = linda_i2c_bits[bit_id];
+	unsigned int outputs = 0;
+	unsigned int output_enables = 0;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	/* Read current GPIO mask and outputs */
+	linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+	linda_readq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+
+	/* Update outputs and output enables.  I2C lines are tied
+	 * high, so we always set the output to 0 and use the output
+	 * enable to control the line.
+	 */
+	output_enables = BIT_GET ( &extctrl, GPIOOe );
+	output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) );
+	outputs = BIT_GET ( &gpioout, GPIO );
+	outputs = ( outputs & ~bit );
+	BIT_SET ( &extctrl, GPIOOe, output_enables );
+	BIT_SET ( &gpioout, GPIO, outputs );
+
+	/* Write the output enable first; that way we avoid logic
+	 * hazards.
+	 */
+	linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+	linda_writeq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+	mb();
+
+	DBG_ENABLE ( DBGLVL_IO );
+}
+
+/** Linda I2C bit-bashing interface operations */
+static struct bit_basher_operations linda_i2c_basher_ops = {
+	.read	= linda_i2c_read_bit,
+	.write	= linda_i2c_write_bit,
+};
+
+/**
+ * Initialise Linda I2C subsystem
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_init_i2c ( struct linda *linda ) {
+	static int try_eeprom_address[] = { 0x51, 0x50 };
+	unsigned int i;
+	int rc;
+
+	/* Initialise bus */
+	if ( ( rc = init_i2c_bit_basher ( &linda->i2c,
+					  &linda_i2c_basher_ops ) ) != 0 ) {
+		DBGC ( linda, "Linda %p could not initialise I2C bus: %s\n",
+		       linda, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Probe for devices */
+	for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) /
+			    sizeof ( try_eeprom_address[0] ) ) ; i++ ) {
+		init_i2c_eeprom ( &linda->eeprom, try_eeprom_address[i] );
+		if ( ( rc = i2c_check_presence ( &linda->i2c.i2c,
+						 &linda->eeprom ) ) == 0 ) {
+			DBGC2 ( linda, "Linda %p found EEPROM at %02x\n",
+				linda, try_eeprom_address[i] );
+			return 0;
+		}
+	}
+
+	DBGC ( linda, "Linda %p could not find EEPROM\n", linda );
+	return -ENODEV;
+}
+
+/**
+ * Read EEPROM parameters
+ *
+ * @v linda		Linda device
+ * @v guid		GUID to fill in
+ * @ret rc		Return status code
+ */
+static int linda_read_eeprom ( struct linda *linda, union ib_guid *guid ) {
+	struct i2c_interface *i2c = &linda->i2c.i2c;
+	int rc;
+
+	/* Read GUID */
+	if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET,
+				guid->bytes, sizeof ( *guid ) ) ) != 0 ) {
+		DBGC ( linda, "Linda %p could not read GUID: %s\n",
+		       linda, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( linda, "Linda %p has GUID " IB_GUID_FMT "\n",
+		linda, IB_GUID_ARGS ( guid ) );
+
+	/* Read serial number (debug only) */
+	if ( DBG_LOG ) {
+		uint8_t serial[LINDA_EEPROM_SERIAL_SIZE + 1];
+
+		serial[ sizeof ( serial ) - 1 ] = '\0';
+		if ( ( rc = i2c->read ( i2c, &linda->eeprom,
+					LINDA_EEPROM_SERIAL_OFFSET, serial,
+					( sizeof ( serial ) - 1 ) ) ) != 0 ) {
+			DBGC ( linda, "Linda %p could not read serial: %s\n",
+			       linda, strerror ( rc ) );
+			return rc;
+		}
+		DBGC2 ( linda, "Linda %p has serial number \"%s\"\n",
+			linda, serial );
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * External parallel bus access
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Request ownership of the IB external parallel bus
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_ib_epb_request ( struct linda *linda ) {
+	struct QIB_7220_ibsd_epb_access_ctrl access;
+	unsigned int i;
+
+	/* Request ownership */
+	memset ( &access, 0, sizeof ( access ) );
+	BIT_FILL_1 ( &access, sw_ib_epb_req, 1 );
+	linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+
+	/* Wait for ownership to be granted */
+	for ( i = 0 ; i < LINDA_EPB_REQUEST_MAX_WAIT_US ; i++ ) {
+		linda_readq ( linda, &access,
+			      QIB_7220_ibsd_epb_access_ctrl_offset );
+		if ( BIT_GET ( &access, sw_ib_epb_req_granted ) )
+			return 0;
+		udelay ( 1 );
+	}
+
+	DBGC ( linda, "Linda %p timed out waiting for IB EPB request\n",
+	       linda );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Wait for IB external parallel bus transaction to complete
+ *
+ * @v linda		Linda device
+ * @v xact		Buffer to hold transaction result
+ * @ret rc		Return status code
+ */
+static int linda_ib_epb_wait ( struct linda *linda,
+			    struct QIB_7220_ibsd_epb_transaction_reg *xact ) {
+	unsigned int i;
+
+	/* Discard first read to allow for signals crossing clock domains */
+	linda_readq ( linda, xact, QIB_7220_ibsd_epb_transaction_reg_offset );
+
+	for ( i = 0 ; i < LINDA_EPB_XACT_MAX_WAIT_US ; i++ ) {
+		linda_readq ( linda, xact,
+			      QIB_7220_ibsd_epb_transaction_reg_offset );
+		if ( BIT_GET ( xact, ib_epb_rdy ) ) {
+			if ( BIT_GET ( xact, ib_epb_req_error ) ) {
+				DBGC ( linda, "Linda %p EPB transaction "
+				       "failed\n", linda );
+				return -EIO;
+			} else {
+				return 0;
+			}
+		}
+		udelay ( 1 );
+	}
+
+	DBGC ( linda, "Linda %p timed out waiting for IB EPB transaction\n",
+	       linda );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Release ownership of the IB external parallel bus
+ *
+ * @v linda		Linda device
+ */
+static void linda_ib_epb_release ( struct linda *linda ) {
+	struct QIB_7220_ibsd_epb_access_ctrl access;
+
+	memset ( &access, 0, sizeof ( access ) );
+	BIT_FILL_1 ( &access, sw_ib_epb_req, 0 );
+	linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+}
+
+/**
+ * Read data via IB external parallel bus
+ *
+ * @v linda		Linda device
+ * @v location		EPB location
+ * @ret data		Data read, or negative error
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_read ( struct linda *linda, unsigned int location ) {
+	struct QIB_7220_ibsd_epb_transaction_reg xact;
+	unsigned int data;
+	int rc;
+
+	/* Ensure no transaction is currently in progress */
+	if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+		return rc;
+
+	/* Process data */
+	memset ( &xact, 0, sizeof ( xact ) );
+	BIT_FILL_3 ( &xact,
+		     ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+		     ib_epb_read_write, LINDA_EPB_READ,
+		     ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+	linda_writeq ( linda, &xact,
+		       QIB_7220_ibsd_epb_transaction_reg_offset );
+
+	/* Wait for transaction to complete */
+	if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+		return rc;
+
+	data = BIT_GET ( &xact, ib_epb_data );
+	return data;
+}
+
+/**
+ * Write data via IB external parallel bus
+ *
+ * @v linda		Linda device
+ * @v location		EPB location
+ * @v data		Data to write
+ * @ret rc		Return status code
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_write ( struct linda *linda, unsigned int location,
+				unsigned int data ) {
+	struct QIB_7220_ibsd_epb_transaction_reg xact;
+	int rc;
+
+	/* Ensure no transaction is currently in progress */
+	if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+		return rc;
+
+	/* Process data */
+	memset ( &xact, 0, sizeof ( xact ) );
+	BIT_FILL_4 ( &xact,
+		     ib_epb_data, data,
+		     ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+		     ib_epb_read_write, LINDA_EPB_WRITE,
+		     ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+	linda_writeq ( linda, &xact,
+		       QIB_7220_ibsd_epb_transaction_reg_offset );
+
+	/* Wait for transaction to complete */
+	if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Read/modify/write EPB register
+ *
+ * @v linda		Linda device
+ * @v cs		Chip select
+ * @v channel		Channel
+ * @v element		Element
+ * @v reg		Register
+ * @v value		Value to set
+ * @v mask		Mask to apply to old value
+ * @ret rc		Return status code
+ */
+static int linda_ib_epb_mod_reg ( struct linda *linda, unsigned int cs,
+				  unsigned int channel, unsigned int element,
+				  unsigned int reg, unsigned int value,
+				  unsigned int mask ) {
+	unsigned int location;
+	int old_value;
+	int rc;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	/* Sanity check */
+	assert ( ( value & mask ) == value );
+
+	/* Acquire bus ownership */
+	if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+		goto out;
+
+	/* Read existing value, if necessary */
+	location = LINDA_EPB_LOC ( cs, channel, element, reg );
+	if ( (~mask) & 0xff ) {
+		old_value = linda_ib_epb_read ( linda, location );
+		if ( old_value < 0 ) {
+			rc = old_value;
+			goto out_release;
+		}
+	} else {
+		old_value = 0;
+	}
+
+	/* Update value */
+	value = ( ( old_value & ~mask ) | value );
+	DBGCP ( linda, "Linda %p CS %d EPB(%d,%d,%#02x) %#02x => %#02x\n",
+		linda, cs, channel, element, reg, old_value, value );
+	if ( ( rc = linda_ib_epb_write ( linda, location, value ) ) != 0 )
+		goto out_release;
+
+ out_release:
+	/* Release bus */
+	linda_ib_epb_release ( linda );
+ out:
+	DBG_ENABLE ( DBGLVL_IO );
+	return rc;
+}
+
+/**
+ * Transfer data to/from microcontroller RAM
+ *
+ * @v linda		Linda device
+ * @v address		Starting address
+ * @v write		Data to write, or NULL
+ * @v read		Data to read, or NULL
+ * @v len		Length of data
+ * @ret rc		Return status code
+ */
+static int linda_ib_epb_ram_xfer ( struct linda *linda, unsigned int address,
+				   const void *write, void *read,
+				   size_t len ) {
+	unsigned int control;
+	unsigned int address_hi;
+	unsigned int address_lo;
+	int data;
+	int rc;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	assert ( ! ( write && read ) );
+	assert ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+	assert ( ( len % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+
+	/* Acquire bus ownership */
+	if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+		goto out;
+
+	/* Process data */
+	while ( len ) {
+
+		/* Reset the address for each new chunk */
+		if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+
+			/* Write the control register */
+			control = ( read ? LINDA_EPB_UC_CTL_READ :
+				    LINDA_EPB_UC_CTL_WRITE );
+			if ( ( rc = linda_ib_epb_write ( linda,
+							 LINDA_EPB_UC_CTL,
+							 control ) ) != 0 )
+				break;
+
+			/* Write the address registers */
+			address_hi = ( address >> 8 );
+			if ( ( rc = linda_ib_epb_write ( linda,
+							 LINDA_EPB_UC_ADDR_HI,
+							 address_hi ) ) != 0 )
+				break;
+			address_lo = ( address & 0xff );
+			if ( ( rc = linda_ib_epb_write ( linda,
+							 LINDA_EPB_UC_ADDR_LO,
+							 address_lo ) ) != 0 )
+				break;
+		}
+
+		/* Read or write the data */
+		if ( read ) {
+			data = linda_ib_epb_read ( linda, LINDA_EPB_UC_DATA );
+			if ( data < 0 ) {
+				rc = data;
+				break;
+			}
+			*( ( uint8_t * ) read++ ) = data;
+		} else {
+			data = *( ( uint8_t * ) write++ );
+			if ( ( rc = linda_ib_epb_write ( linda,
+							 LINDA_EPB_UC_DATA,
+							 data ) ) != 0 )
+				break;
+		}
+		address++;
+		len--;
+
+		/* Reset the control byte after each chunk */
+		if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+			if ( ( rc = linda_ib_epb_write ( linda,
+							 LINDA_EPB_UC_CTL,
+							 0 ) ) != 0 )
+				break;
+		}
+	}
+
+	/* Release bus */
+	linda_ib_epb_release ( linda );
+
+ out:
+	DBG_ENABLE ( DBGLVL_IO );
+	return rc;
+}
+
+/***************************************************************************
+ *
+ * Infiniband SerDes initialisation
+ *
+ ***************************************************************************
+ */
+
+/** A Linda SerDes parameter */
+struct linda_serdes_param {
+	/** EPB address as constructed by LINDA_EPB_ADDRESS() */
+	uint16_t address;
+	/** Value to set */
+	uint8_t value;
+	/** Mask to apply to old value */
+	uint8_t mask;
+} __packed;
+
+/** Magic "all channels" channel number */
+#define LINDA_EPB_ALL_CHANNELS 31
+
+/** End of SerDes parameter list marker */
+#define LINDA_SERDES_PARAM_END { 0, 0, 0 }
+
+/**
+ * Program IB SerDes register(s)
+ *
+ * @v linda		Linda device
+ * @v param		SerDes parameter
+ * @ret rc		Return status code
+ */
+static int linda_set_serdes_param ( struct linda *linda,
+				    struct linda_serdes_param *param ) {
+	unsigned int channel;
+	unsigned int channel_start;
+	unsigned int channel_end;
+	unsigned int element;
+	unsigned int reg;
+	int rc;
+
+	/* Break down the EPB address and determine channels */
+	channel = LINDA_EPB_ADDRESS_CHANNEL ( param->address );
+	element = LINDA_EPB_ADDRESS_ELEMENT ( param->address );
+	reg = LINDA_EPB_ADDRESS_REG ( param->address );
+	if ( channel == LINDA_EPB_ALL_CHANNELS ) {
+		channel_start = 0;
+		channel_end = 3;
+	} else {
+		channel_start = channel_end = channel;
+	}
+
+	/* Modify register for each specified channel */
+	for ( channel = channel_start ; channel <= channel_end ; channel++ ) {
+		if ( ( rc = linda_ib_epb_mod_reg ( linda, LINDA_EPB_CS_SERDES,
+						   channel, element, reg,
+						   param->value,
+						   param->mask ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Program IB SerDes registers
+ *
+ * @v linda		Linda device
+ * @v param		SerDes parameters
+ * @v count		Number of parameters
+ * @ret rc		Return status code
+ */
+static int linda_set_serdes_params ( struct linda *linda,
+				     struct linda_serdes_param *params ) {
+	int rc;
+
+	for ( ; params->mask != 0 ; params++ ){
+		if ( ( rc = linda_set_serdes_param ( linda,
+							 params ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+#define LINDA_DDS_VAL( amp_d, main_d, ipst_d, ipre_d,			\
+		       amp_s, main_s, ipst_s, ipre_s )			\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x00 ),	\
+	  ( ( ( amp_d & 0x1f ) << 1 ) | 1 ), 0xff },			\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x01 ),	\
+	  ( ( ( amp_s & 0x1f ) << 1 ) | 1 ), 0xff },			\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x09 ),	\
+	  ( ( main_d << 3 ) | 4 | ( ipre_d >> 2 ) ), 0xff },		\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x0a ),	\
+	  ( ( main_s << 3 ) | 4 | ( ipre_s >> 2 ) ), 0xff },		\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x06 ),	\
+	  ( ( ( ipst_d & 0xf ) << 1 ) |					\
+	    ( ( ipre_d & 3 ) << 6 ) | 0x21 ), 0xff },			\
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x07 ),	\
+	  ( ( ( ipst_s & 0xf ) << 1 ) |					\
+	    ( ( ipre_s & 3 ) << 6) | 0x21 ), 0xff }
+
+/**
+ * Linda SerDes default parameters
+ *
+ * These magic start-of-day values are taken from the Linux driver.
+ */
+static struct linda_serdes_param linda_serdes_defaults1[] = {
+	/* RXHSCTRL0 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x00 ), 0xd4, 0xff },
+	/* VCDL_DAC2 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x05 ), 0x2d, 0xff },
+	/* VCDL_CTRL2 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x08 ), 0x03, 0x0f },
+	/* START_EQ1 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+	/* START_EQ2 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x28 ), 0x30, 0xff },
+	/* BACTRL */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0e ), 0x40, 0xff },
+	/* LDOUTCTRL1 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x04, 0xff },
+	/* RXHSSTATUS */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0f ), 0x04, 0xff },
+	/* End of this block */
+	LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults2[] = {
+	/* LDOUTCTRL1 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x00, 0xff },
+	/* DDS values */
+	LINDA_DDS_VAL ( 31, 19, 12, 0, 29, 22, 9, 0 ),
+	/* Set Rcv Eq. to Preset node */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+	/* DFELTHFDR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x08 ), 0x00, 0xff },
+	/* DFELTHHDR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x21 ), 0x00, 0xff },
+	/* TLTHFDR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x09 ), 0x02, 0xff },
+	/* TLTHHDR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x23 ), 0x02, 0xff },
+	/* ZFR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1b ), 0x0c, 0xff },
+	/* ZCNT) */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1c ), 0x0c, 0xff },
+	/* GFR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1e ), 0x10, 0xff },
+	/* GHR */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1f ), 0x10, 0xff },
+	/* VCDL_CTRL0 toggle */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x20, 0xff },
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x00, 0xff },
+	/* CMUCTRL5 */
+	{ LINDA_EPB_ADDRESS (			   7, 0, 0x15 ), 0x80, 0xff },
+	/* End of this block */
+	LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults3[] = {
+	/* START_EQ1 */
+	{ LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x00, 0x38 },
+	/* End of this block */
+	LINDA_SERDES_PARAM_END
+};
+
+/**
+ * Program the microcontroller RAM
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_program_uc_ram ( struct linda *linda ) {
+	int rc;
+
+	if ( ( rc = linda_ib_epb_ram_xfer ( linda, 0, linda_ib_fw, NULL,
+					    sizeof ( linda_ib_fw ) ) ) != 0 ){
+		DBGC ( linda, "Linda %p could not load IB firmware: %s\n",
+		       linda, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Verify the microcontroller RAM
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_verify_uc_ram ( struct linda *linda ) {
+	uint8_t verify[LINDA_EPB_UC_CHUNK_SIZE];
+	unsigned int offset;
+	int rc;
+
+	for ( offset = 0 ; offset < sizeof ( linda_ib_fw );
+	      offset += sizeof ( verify ) ) {
+		if ( ( rc = linda_ib_epb_ram_xfer ( linda, offset,
+						    NULL, verify,
+						    sizeof (verify) )) != 0 ){
+			DBGC ( linda, "Linda %p could not read back IB "
+			       "firmware: %s\n", linda, strerror ( rc ) );
+			return rc;
+		}
+		if ( memcmp ( ( linda_ib_fw + offset ), verify,
+			      sizeof ( verify ) ) != 0 ) {
+			DBGC ( linda, "Linda %p firmware verification failed "
+			       "at offset %#x\n", linda, offset );
+			DBGC_HDA ( linda, offset, ( linda_ib_fw + offset ),
+				   sizeof ( verify ) );
+			DBGC_HDA ( linda, offset, verify, sizeof ( verify ) );
+			return -EIO;
+		}
+	}
+
+	DBGC2 ( linda, "Linda %p firmware verified ok\n", linda );
+	return 0;
+}
+
+/**
+ * Use the microcontroller to trim the IB link
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_trim_ib ( struct linda *linda ) {
+	struct QIB_7220_IBSerDesCtrl ctrl;
+	struct QIB_7220_IntStatus intstatus;
+	unsigned int i;
+	int rc;
+
+	/* Bring the microcontroller out of reset */
+	linda_readq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+	BIT_SET ( &ctrl, ResetIB_uC_Core, 0 );
+	linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+	/* Wait for the "trim done" signal */
+	for ( i = 0 ; i < LINDA_TRIM_DONE_MAX_WAIT_MS ; i++ ) {
+		linda_readq ( linda, &intstatus, QIB_7220_IntStatus_offset );
+		if ( BIT_GET ( &intstatus, IBSerdesTrimDone ) ) {
+			rc = 0;
+			goto out_reset;
+		}
+		mdelay ( 1 );
+	}
+
+	DBGC ( linda, "Linda %p timed out waiting for trim done\n", linda );
+	rc = -ETIMEDOUT;
+ out_reset:
+	/* Put the microcontroller back into reset */
+	BIT_SET ( &ctrl, ResetIB_uC_Core, 1 );
+	linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+	return rc;
+}
+
+/**
+ * Initialise the IB SerDes
+ *
+ * @v linda		Linda device
+ * @ret rc		Return status code
+ */
+static int linda_init_ib_serdes ( struct linda *linda ) {
+	struct QIB_7220_Control control;
+	struct QIB_7220_IBCCtrl ibcctrl;
+	struct QIB_7220_IBCDDRCtrl ibcddrctrl;
+	struct QIB_7220_XGXSCfg xgxscfg;
+	int rc;
+
+	/* Disable link */
+	linda_readq ( linda, &control, QIB_7220_Control_offset );
+	BIT_SET ( &control, LinkEn, 0 );
+	linda_writeq ( linda, &control, QIB_7220_Control_offset );
+
+	/* Configure sensible defaults for IBC */
+	memset ( &ibcctrl, 0, sizeof ( ibcctrl ) );
+	BIT_FILL_6 ( &ibcctrl, /* Tuning values taken from Linux driver */
+		     FlowCtrlPeriod, 0x03,
+		     FlowCtrlWaterMark, 0x05,
+		     MaxPktLen, ( ( LINDA_RECV_HEADER_SIZE +
+				    LINDA_RECV_PAYLOAD_SIZE +
+				    4 /* ICRC */ ) >> 2 ),
+		     PhyerrThreshold, 0xf,
+		     OverrunThreshold, 0xf,
+		     CreditScale, 0x4 );
+	linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+
+	/* Force SDR only to avoid needing all the DDR tuning,
+	 * Mellanox compatibility hacks etc.  SDR is plenty for
+	 * boot-time operation.
+	 */
+	linda_readq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+	BIT_SET ( &ibcddrctrl, IB_ENHANCED_MODE, 0 );
+	BIT_SET ( &ibcddrctrl, SD_SPEED_SDR, 1 );
+	BIT_SET ( &ibcddrctrl, SD_SPEED_DDR, 0 );
+	BIT_SET ( &ibcddrctrl, SD_SPEED_QDR, 0 );
+	BIT_SET ( &ibcddrctrl, HRTBT_ENB, 0 );
+	BIT_SET ( &ibcddrctrl, HRTBT_AUTO, 0 );
+	linda_writeq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+
+	/* Set default SerDes parameters */
+	if ( ( rc = linda_set_serdes_params ( linda,
+					      linda_serdes_defaults1 ) ) != 0 )
+		return rc;
+	udelay ( 415 ); /* Magic delay while SerDes sorts itself out */
+	if ( ( rc = linda_set_serdes_params ( linda,
+					      linda_serdes_defaults2 ) ) != 0 )
+		return rc;
+
+	/* Program the microcontroller RAM */
+	if ( ( rc = linda_program_uc_ram ( linda ) ) != 0 )
+		return rc;
+
+	/* Verify the microcontroller RAM contents */
+	if ( DBGLVL_LOG ) {
+		if ( ( rc = linda_verify_uc_ram ( linda ) ) != 0 )
+			return rc;
+	}
+
+	/* More SerDes tuning */
+	if ( ( rc = linda_set_serdes_params ( linda,
+					      linda_serdes_defaults3 ) ) != 0 )
+		return rc;
+
+	/* Use the microcontroller to trim the IB link */
+	if ( ( rc = linda_trim_ib ( linda ) ) != 0 )
+		return rc;
+
+	/* Bring XGXS out of reset */
+	linda_readq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+	BIT_SET ( &xgxscfg, tx_rx_reset, 0 );
+	BIT_SET ( &xgxscfg, xcv_reset, 0 );
+	linda_writeq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+
+	return rc;
+}
+
+/***************************************************************************
+ *
+ * PCI layer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int linda_probe ( struct pci_device *pci ) {
+	struct ib_device *ibdev;
+	struct linda *linda;
+	struct QIB_7220_Revision revision;
+	int rc;
+
+	/* Allocate Infiniband device */
+	ibdev = alloc_ibdev ( sizeof ( *linda ) );
+	if ( ! ibdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_ibdev;
+	}
+	pci_set_drvdata ( pci, ibdev );
+	linda = ib_get_drvdata ( ibdev );
+	ibdev->op = &linda_ib_operations;
+	ibdev->dev = &pci->dev;
+	ibdev->port = 1;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Get PCI BARs */
+	linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE );
+	DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase );
+
+	/* Print some general data */
+	linda_readq ( linda, &revision, QIB_7220_Revision_offset );
+	DBGC2 ( linda, "Linda %p board %02lx v%ld.%ld.%ld.%ld\n", linda,
+		BIT_GET ( &revision, BoardID ),
+		BIT_GET ( &revision, R_SW ),
+		BIT_GET ( &revision, R_Arch ),
+		BIT_GET ( &revision, R_ChipRevMajor ),
+		BIT_GET ( &revision, R_ChipRevMinor ) );
+
+	/* Record link capabilities.  Note that we force SDR only to
+	 * avoid having to carry extra code for DDR tuning etc.
+	 */
+	ibdev->link_width_enabled = ibdev->link_width_supported =
+		( IB_LINK_WIDTH_4X | IB_LINK_WIDTH_1X );
+	ibdev->link_speed_enabled = ibdev->link_speed_supported =
+		IB_LINK_SPEED_SDR;
+
+	/* Initialise I2C subsystem */
+	if ( ( rc = linda_init_i2c ( linda ) ) != 0 )
+		goto err_init_i2c;
+
+	/* Read EEPROM parameters */
+	if ( ( rc = linda_read_eeprom ( linda, &ibdev->node_guid ) ) != 0 )
+		goto err_read_eeprom;
+	memcpy ( &ibdev->gid.s.guid, &ibdev->node_guid,
+		 sizeof ( ibdev->gid.s.guid ) );
+
+	/* Initialise send datapath */
+	if ( ( rc = linda_init_send ( linda ) ) != 0 )
+		goto err_init_send;
+
+	/* Initialise receive datapath */
+	if ( ( rc = linda_init_recv ( linda ) ) != 0 )
+		goto err_init_recv;
+
+	/* Initialise the IB SerDes */
+	if ( ( rc = linda_init_ib_serdes ( linda ) ) != 0 )
+		goto err_init_ib_serdes;
+
+	/* Register Infiniband device */
+	if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
+		DBGC ( linda, "Linda %p could not register IB "
+		       "device: %s\n", linda, strerror ( rc ) );
+		goto err_register_ibdev;
+	}
+
+	return 0;
+
+	unregister_ibdev ( ibdev );
+ err_register_ibdev:
+	linda_fini_recv ( linda );
+ err_init_recv:
+	linda_fini_send ( linda );
+ err_init_send:
+ err_init_ib_serdes:
+ err_read_eeprom:
+ err_init_i2c:
+	ibdev_put ( ibdev );
+ err_alloc_ibdev:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void linda_remove ( struct pci_device *pci ) {
+	struct ib_device *ibdev = pci_get_drvdata ( pci );
+	struct linda *linda = ib_get_drvdata ( ibdev );
+
+	unregister_ibdev ( ibdev );
+	linda_fini_recv ( linda );
+	linda_fini_send ( linda );
+	ibdev_put ( ibdev );
+}
+
+static struct pci_device_id linda_nics[] = {
+	PCI_ROM ( 0x1077, 0x7220, "iba7220", "QLE7240/7280 HCA driver", 0 ),
+};
+
+struct pci_driver linda_driver __pci_driver = {
+	.ids = linda_nics,
+	.id_count = ( sizeof ( linda_nics ) / sizeof ( linda_nics[0] ) ),
+	.probe = linda_probe,
+	.remove = linda_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.h
new file mode 100644
index 0000000..1450a6a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda.h
@@ -0,0 +1,276 @@
+#ifndef _LINDA_H
+#define _LINDA_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+#define BITOPS_LITTLE_ENDIAN
+#include <ipxe/bitops.h>
+#include "qib_7220_regs.h"
+
+struct ib_device;
+
+/** A Linda GPIO register */
+struct QIB_7220_GPIO_pb {
+	pseudo_bit_t GPIO[16];
+	pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_GPIO {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIO_pb );
+};
+
+/** A Linda general scalar register */
+struct QIB_7220_scalar_pb {
+	pseudo_bit_t Value[64];
+};
+struct QIB_7220_scalar {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_scalar_pb );
+};
+
+/** Linda send per-buffer control word */
+struct QIB_7220_SendPbc_pb {
+	pseudo_bit_t LengthP1_toibc[11];
+	pseudo_bit_t Reserved1[4];
+	pseudo_bit_t LengthP1_trigger[11];
+	pseudo_bit_t Reserved2[3];
+	pseudo_bit_t TestEbp[1];
+	pseudo_bit_t Test[1];
+	pseudo_bit_t Intr[1];
+	pseudo_bit_t Reserved3[31];
+	pseudo_bit_t VL15[1];
+};
+struct QIB_7220_SendPbc {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendPbc_pb );
+};
+
+/** Linda send buffer availability */
+struct QIB_7220_SendBufAvail_pb {
+	pseudo_bit_t InUseCheck[144][2];
+	pseudo_bit_t Reserved[32];
+};
+struct QIB_7220_SendBufAvail {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail_pb );
+};
+
+/** DMA alignment for send buffer availability */
+#define LINDA_SENDBUFAVAIL_ALIGN 64
+
+/** A Linda eager receive descriptor */
+struct QIB_7220_RcvEgr_pb {
+	pseudo_bit_t Addr[37];
+	pseudo_bit_t BufSize[3];
+	pseudo_bit_t Reserved[24];
+};
+struct QIB_7220_RcvEgr {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvEgr_pb );
+};
+
+/** Linda receive header flags */
+struct QIB_7220_RcvHdrFlags_pb {
+	pseudo_bit_t PktLen[11];
+	pseudo_bit_t RcvType[3];
+	pseudo_bit_t SoftB[1];
+	pseudo_bit_t SoftA[1];
+	pseudo_bit_t EgrIndex[12];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t UseEgrBfr[1];
+	pseudo_bit_t RcvSeq[4];
+	pseudo_bit_t HdrqOffset[11];
+	pseudo_bit_t Reserved2[8];
+	pseudo_bit_t IBErr[1];
+	pseudo_bit_t MKErr[1];
+	pseudo_bit_t TIDErr[1];
+	pseudo_bit_t KHdrErr[1];
+	pseudo_bit_t MTUErr[1];
+	pseudo_bit_t LenErr[1];
+	pseudo_bit_t ParityErr[1];
+	pseudo_bit_t VCRCErr[1];
+	pseudo_bit_t ICRCErr[1];
+};
+struct QIB_7220_RcvHdrFlags {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrFlags_pb );
+};
+
+/** Linda memory BAR size */
+#define LINDA_BAR0_SIZE 0x400000
+
+/** Linda I2C SCL line GPIO number */
+#define LINDA_GPIO_SCL 0
+
+/** Linda I2C SDA line GPIO number */
+#define LINDA_GPIO_SDA 1
+
+/** GUID offset within EEPROM */
+#define LINDA_EEPROM_GUID_OFFSET 3
+
+/** GUID size within EEPROM */
+#define LINDA_EEPROM_GUID_SIZE 8
+
+/** Board serial number offset within EEPROM */
+#define LINDA_EEPROM_SERIAL_OFFSET 12
+
+/** Board serial number size within EEPROM */
+#define LINDA_EEPROM_SERIAL_SIZE 12
+
+/** Maximum number of send buffers used
+ *
+ * This is a policy decision.  Must be less than or equal to the total
+ * number of send buffers supported by the hardware (128).
+ */
+#define LINDA_MAX_SEND_BUFS 32
+
+/** Linda send buffer size */
+#define LINDA_SEND_BUF_SIZE 4096
+
+/** Number of contexts (including kernel context)
+ *
+ * This is a policy decision.  Must be 5, 9 or 17.
+ */
+#define LINDA_NUM_CONTEXTS 5
+
+/** PortCfg values for different numbers of contexts */
+enum linda_portcfg {
+	LINDA_PORTCFG_5CTX = 0,
+	LINDA_PORTCFG_9CTX = 1,
+	LINDA_PORTCFG_17CTX = 2,
+};
+
+/** PortCfg values for different numbers of contexts */
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER 4096
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER 1024
+
+/** Eager buffer required alignment */
+#define LINDA_EAGER_BUFFER_ALIGN 2048
+
+/** Eager buffer size encodings */
+enum linda_eager_buffer_size {
+	LINDA_EAGER_BUFFER_NONE = 0,
+	LINDA_EAGER_BUFFER_2K = 1,
+	LINDA_EAGER_BUFFER_4K = 2,
+	LINDA_EAGER_BUFFER_8K = 3,
+	LINDA_EAGER_BUFFER_16K = 4,
+	LINDA_EAGER_BUFFER_32K = 5,
+	LINDA_EAGER_BUFFER_64K = 6,
+};
+
+/** Number of RX headers per context
+ *
+ * This is a policy decision.
+ */
+#define LINDA_RECV_HEADER_COUNT 8
+
+/** Maximum size of each RX header
+ *
+ * This is a policy decision.  Must be divisible by 4.
+ */
+#define LINDA_RECV_HEADER_SIZE 96
+
+/** Total size of an RX header ring */
+#define LINDA_RECV_HEADERS_SIZE \
+	( LINDA_RECV_HEADER_SIZE * LINDA_RECV_HEADER_COUNT )
+
+/** RX header alignment */
+#define LINDA_RECV_HEADERS_ALIGN 64
+
+/** RX payload size
+ *
+ * This is a policy decision.  Must be a valid eager buffer size.
+ */
+#define LINDA_RECV_PAYLOAD_SIZE 2048
+
+/** QPN used for Infinipath Packets
+ *
+ * This is a policy decision.  Must have bit 0 clear.  Must not be a
+ * QPN that we will use.
+ */
+#define LINDA_QP_IDETH 0xdead0
+
+/** Maximum time for wait for external parallel bus request, in us */
+#define LINDA_EPB_REQUEST_MAX_WAIT_US 500
+
+/** Maximum time for wait for external parallel bus transaction, in us */
+#define LINDA_EPB_XACT_MAX_WAIT_US 500
+
+/** Linda external parallel bus chip selects */
+#define LINDA_EPB_CS_SERDES 1
+#define LINDA_EPB_CS_UC 2
+
+/** Linda external parallel bus read/write operations */
+#define LINDA_EPB_WRITE 0
+#define LINDA_EPB_READ 1
+
+/** Linda external parallel bus register addresses */
+#define LINDA_EPB_ADDRESS( _channel, _element, _reg ) \
+	( (_element) | ( (_channel) << 4 ) | ( (_reg) << 9 ) )
+#define LINDA_EPB_ADDRESS_CHANNEL( _address )	( ( (_address) >> 4 ) & 0x1f )
+#define LINDA_EPB_ADDRESS_ELEMENT( _address )	( ( (_address) >> 0 ) & 0x0f )
+#define LINDA_EPB_ADDRESS_REG( _address )	( ( (_address) >> 9 ) & 0x3f )
+
+/** Linda external parallel bus locations
+ *
+ * The location is used by the driver to encode both the chip select
+ * and the EPB address.
+ */
+#define LINDA_EPB_LOC( _cs, _channel, _element, _reg) \
+	( ( (_cs) << 16 ) | LINDA_EPB_ADDRESS ( _channel, _element, _reg ) )
+#define LINDA_EPB_LOC_ADDRESS( _loc )	( (_loc) & 0xffff )
+#define LINDA_EPB_LOC_CS( _loc )	( (_loc) >> 16 )
+
+/** Linda external parallel bus microcontroller register addresses */
+#define LINDA_EPB_UC_CHANNEL 6
+#define LINDA_EPB_UC_LOC( _reg ) \
+	LINDA_EPB_LOC ( LINDA_EPB_CS_UC, LINDA_EPB_UC_CHANNEL, 0, (_reg) )
+#define LINDA_EPB_UC_CTL	LINDA_EPB_UC_LOC ( 0 )
+#define LINDA_EPB_UC_CTL_WRITE	1
+#define LINDA_EPB_UC_CTL_READ	2
+#define LINDA_EPB_UC_ADDR_LO	LINDA_EPB_UC_LOC ( 2 )
+#define LINDA_EPB_UC_ADDR_HI	LINDA_EPB_UC_LOC ( 3 )
+#define LINDA_EPB_UC_DATA	LINDA_EPB_UC_LOC ( 4 )
+#define LINDA_EPB_UC_CHUNK_SIZE	64
+
+extern uint8_t linda_ib_fw[8192];
+
+/** Maximum time to wait for "trim done" signal, in ms */
+#define LINDA_TRIM_DONE_MAX_WAIT_MS 1000
+
+/** Linda link states */
+enum linda_link_state {
+	LINDA_LINK_STATE_DOWN = 0,
+	LINDA_LINK_STATE_INIT = 1,
+	LINDA_LINK_STATE_ARM = 2,
+	LINDA_LINK_STATE_ACTIVE = 3,
+	LINDA_LINK_STATE_ACT_DEFER = 4,
+};
+
+/** Maximum time to wait for link state changes, in us */
+#define LINDA_LINK_STATE_MAX_WAIT_US 20
+
+#endif /* _LINDA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda_fw.c b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda_fw.c
new file mode 100644
index 0000000..968a5f8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/linda_fw.c
@@ -0,0 +1,1069 @@
+/*
+ * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * 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.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * This file contains the memory image from the vendor, to be copied into
+ * the IB SERDES of the IBA7220 during initialization.
+ * The file also includes the two functions which use this image.
+ */
+
+#include <stdint.h>
+#include "linda.h"
+
+uint8_t linda_ib_fw[8192] = {
+/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6,
+	0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01,
+	0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08,
+/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08,
+	0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2,
+/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7,
+	0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00,
+/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75,
+	0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5,
+/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38,
+	0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94,
+/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36,
+	0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74,
+/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90,
+	0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20,
+/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3,
+	0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12,
+/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04,
+	0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09,
+/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00,
+	0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2,
+/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09,
+	0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83,
+	0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3,
+/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0,
+	0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03,
+/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4,
+	0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E,
+/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82,
+	0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44,
+/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40,
+	0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54,
+/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+	0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08,
+/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF,
+	0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40,
+/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75,
+	0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E,
+/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD,
+	0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81,
+/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED,
+	0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF,
+/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0,
+	0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12,
+/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32,
+	0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74,
+/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83,
+	0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0,
+/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19,
+	0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE,
+/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03,
+	0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0,
+/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83,
+	0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12,
+/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3,
+	0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A,
+/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF,
+	0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19,
+/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30,
+	0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C,
+	0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60,
+/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44,
+	0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02,
+/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7,
+	0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0,
+/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04,
+	0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01,
+/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40,
+	0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12,
+/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32,
+	0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0,
+	0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5,
+/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40,
+	0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07,
+/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F,
+	0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D,
+/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A,
+	0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74,
+/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12,
+	0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90,
+/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE,
+	0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5,
+/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02,
+	0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82,
+/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A,
+	0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04,
+/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82,
+	0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A,
+/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04,
+	0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82,
+/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92,
+	0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A,
+/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2,
+	0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F,
+/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20,
+	0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12,
+/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30,
+	0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06,
+/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D,
+	0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0,
+/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43,
+	0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04,
+/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A,
+	0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+	0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+	0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17,
+/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44,
+	0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12,
+/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12,
+	0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74,
+/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0,
+	0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44,
+/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07,
+	0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE,
+/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12,
+	0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10,
+/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12,
+	0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF,
+/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30,
+	0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B,
+	0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5,
+/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09,
+	0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82,
+/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F,
+	0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3,
+/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02,
+	0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E,
+/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09,
+	0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1,
+/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B,
+	0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75,
+/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73,
+	0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0,
+/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47,
+	0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F,
+/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07,
+	0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80,
+/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74,
+	0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F,
+/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83,
+	0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08,
+/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12,
+	0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B,
+/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36,
+	0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12,
+	0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0,
+/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5,
+	0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33,
+/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4,
+	0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4,
+/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E,
+	0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12,
+/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF,
+	0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D,
+/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02,
+	0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01,
+/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06,
+	0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF,
+/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80,
+	0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04,
+/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E,
+	0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5,
+/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60,
+	0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46,
+/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76,
+	0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F,
+/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95,
+	0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5,
+/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01,
+	0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80,
+/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95,
+	0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+	0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F,
+/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46,
+	0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75,
+/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E,
+	0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5,
+/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5,
+	0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F,
+/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5,
+	0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5,
+/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04,
+	0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80,
+/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F,
+	0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5,
+/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D,
+	0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70,
+/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5,
+	0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C,
+/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E,
+	0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79,
+/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85,
+	0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50,
+/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78,
+	0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30,
+/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E,
+	0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19,
+/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+	0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F,
+	0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14,
+/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19,
+	0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75,
+	0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C,
+/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E,
+	0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80,
+/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5,
+	0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB,
+	0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0,
+/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44,
+	0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0,
+/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA,
+	0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC,
+/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5,
+	0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0,
+/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83,
+	0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44,
+/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54,
+	0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3,
+	0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42,
+/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74,
+	0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5,
+/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5,
+	0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5,
+/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C,
+	0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80,
+/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22,
+	0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5,
+/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07,
+	0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C,
+/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44,
+	0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85,
+/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A,
+	0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E,
+/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED,
+	0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22,
+/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02,
+	0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11,
+/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22,
+	0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11,
+	0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+	0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11,
+/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+	0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5,
+	0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF,
+/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+	0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5,
+/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25,
+	0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+	0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25,
+/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83,
+	0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD,
+	0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41,
+/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22,
+	0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00,
+/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+	0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5,
+/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42,
+	0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C,
+/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75,
+	0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3,
+/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E,
+	0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5,
+/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00,
+	0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5,
+/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07,
+	0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95,
+/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4,
+	0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0,
+/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+	0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82,
+/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4,
+	0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41,
+/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60,
+	0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37,
+/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD,
+	0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28,
+/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8,
+	0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F,
+/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0,
+	0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54,
+/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF,
+	0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26,
+/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4,
+	0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89,
+/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12,
+	0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08,
+/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24,
+	0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12,
+/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E,
+	0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01,
+	0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78,
+/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF,
+	0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0,
+/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07,
+	0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF,
+/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24,
+	0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC,
+	0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12,
+/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08,
+	0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4,
+/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08,
+	0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41,
+/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0,
+	0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D,
+/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0,
+	0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4,
+/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5,
+	0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5,
+/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6,
+	0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78,
+/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE,
+	0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8,
+/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5,
+	0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1,
+/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00,
+	0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3,
+/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43,
+	0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83,
+/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0,
+	0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0,
+/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55,
+	0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6,
+/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3,
+	0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33,
+/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40,
+	0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF,
+/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10,
+	0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E,
+/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F,
+	0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93,
+/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25,
+	0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C,
+/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4,
+	0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D,
+/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66,
+	0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90,
+/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4,
+	0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12,
+/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+	0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8,
+	0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12,
+/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05,
+	0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55,
+/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70,
+	0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5,
+/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+	0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12,
+/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+	0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+	0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12,
+/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12,
+	0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E,
+/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44,
+	0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3,
+/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68,
+	0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14,
+/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA,
+	0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74,
+/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80,
+	0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5,
+/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95,
+	0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70,
+/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12,
+	0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80,
+/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D,
+	0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85,
+/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F,
+	0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07,
+/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5,
+	0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F,
+/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12,
+	0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12,
+/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C,
+	0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38,
+/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80,
+	0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08,
+/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D,
+	0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39,
+/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38,
+	0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F,
+/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12,
+	0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A,
+/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12,
+	0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5,
+/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75,
+	0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12,
+/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0,
+	0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06,
+/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5,
+	0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13,
+/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09,
+	0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40,
+/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E,
+	0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+	0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+	0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F,
+/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04,
+	0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5,
+/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80,
+	0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0,
+/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74,
+	0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17,
+/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07,
+	0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90,
+/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44,
+	0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54,
+/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F,
+	0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07,
+/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82,
+	0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED,
+/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF,
+	0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54,
+/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91,
+	0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30,
+/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92,
+	0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4,
+/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75,
+	0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A,
+/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0,
+	0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E,
+/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E,
+	0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0,
+/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75,
+	0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75,
+/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07,
+	0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10,
+/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF,
+	0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82,
+/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5,
+	0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75,
+/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44,
+	0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0,
+	0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34,
+/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22,
+	0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1,
+/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25,
+	0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4,
+/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85,
+	0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0,
+/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00,
+	0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00,
+/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22,
+	0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5,
+/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30,
+	0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC,
+/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B,
+	0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28,
+/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07,
+	0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24,
+/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70,
+	0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07,
+/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0,
+	0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12,
+/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41,
+	0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12,
+/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04,
+	0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64,
+/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02,
+	0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07,
+/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07,
+	0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF,
+/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0,
+	0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0,
+	0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07,
+/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12,
+	0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E,
+	0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70,
+/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43,
+	0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10,
+/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+	0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52,
+/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08,
+	0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B,
+/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00,
+	0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12,
+	0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51,
+/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1,
+	0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1,
+/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80,
+	0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01,
+/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40,
+	0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12,
+	0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22,
+/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10,
+	0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12,
+	0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10,
+/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12,
+	0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0,
+/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07,
+	0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07,
+/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00,
+	0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90,
+	0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56,
+/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12,
+	0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5,
+/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA,
+	0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12,
+/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F,
+	0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22,
+/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74,
+	0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57,
+/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01,
+	0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04,
+/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4,
+	0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0,
+/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94,
+	0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12,
+/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5,
+	0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5,
+/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56,
+	0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80,
+/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40,
+	0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22,
+/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93,
+	0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5,
+/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22,
+	0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5,
+/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93,
+	0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6,
+/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED,
+	0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5,
+/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01,
+	0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00,
+/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D,
+	0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01,
+/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12,
+	0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4,
+/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85,
+	0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5,
+/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07,
+	0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12,
+/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E,
+	0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45,
+/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08,
+	0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00,
+/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5,
+	0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05,
+/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC,
+	0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11,
+/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0,
+	0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE,
+/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83,
+	0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58,
+/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75,
+	0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75,
+/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08,
+	0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF,
+/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90,
+	0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35,
+/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF,
+	0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45,
+/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+	0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E,
+/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60,
+	0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5,
+/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE,
+	0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58,
+/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12,
+	0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00,
+/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07,
+	0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B,
+/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12,
+	0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12,
+/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64,
+	0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E,
+/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95,
+	0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40,
+/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05,
+	0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39,
+/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12,
+	0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B,
+/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07,
+	0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F,
+/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5,
+	0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C,
+/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39,
+	0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12,
+/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5,
+	0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38,
+/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C,
+	0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C,
+/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09,
+	0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40,
+/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E,
+	0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38,
+/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80,
+	0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07,
+/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F,
+	0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63,
+/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12,
+	0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5,
+/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38,
+	0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60,
+/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39,
+	0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C,
+/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12,
+	0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5,
+/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08,
+	0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15,
+/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17,
+	0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80,
+/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94,
+	0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31,
+/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15,
+	0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01,
+/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04,
+	0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A,
+/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77,
+	0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15,
+/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04,
+	0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15,
+/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E,
+	0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22,
+/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15,
+	0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A,
+/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29,
+	0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13,
+/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24,
+	0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63,
+/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6,
+	0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22,
+/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3,
+	0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5,
+/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74,
+	0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74,
+/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20,
+	0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8,
+/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44,
+	0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF,
+/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6,
+	0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3,
+/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E,
+	0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A,
+/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5,
+	0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3,
+/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07,
+	0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70,
+/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5,
+	0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5,
+/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5,
+	0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5,
+/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+	0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80,
+/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF,
+	0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12,
+/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D,
+	0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02,
+/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B,
+	0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B,
+/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B,
+	0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5,
+/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60,
+	0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12,
+/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E,
+	0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6,
+/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8,
+	0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA,
+/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5,
+	0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80,
+/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5,
+	0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4,
+/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29,
+	0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F,
+/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E,
+	0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B,
+/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11,
+	0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12,
+/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A,
+	0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5,
+/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13,
+	0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3,
+/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12,
+	0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE,
+/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19,
+	0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E,
+/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75,
+	0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D,
+/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12,
+	0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94,
+/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83,
+	0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0,
+/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+	0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F,
+	0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75,
+/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21,
+	0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44,
+/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF,
+	0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75,
+/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29,
+	0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07,
+/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12,
+	0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10,
+/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44,
+	0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0,
+/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12,
+	0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58,
+/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC,
+	0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+	0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+	0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+	0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2,
+	0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4,
+/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12,
+	0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07,
+/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58,
+	0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A,
+/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7,
+	0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09,
+/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0,
+	0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54,
+/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78,
+	0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9,
+/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B,
+	0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33,
+/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83,
+	0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83,
+/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E,
+	0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3,
+/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00,
+	0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02,
+/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58,
+	0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12,
+/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54,
+	0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E,
+/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04,
+	0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE,
+/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05,
+	0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33,
+/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C,
+	0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02,
+/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12,
+	0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12,
+/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2,
+	0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3,
+/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41,
+	0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5,
+/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07,
+	0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C,
+/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B,
+	0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60,
+/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41,
+	0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B,
+/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00,
+	0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02,
+/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41,
+	0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40,
+/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1,
+	0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F,
+/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70,
+	0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2,
+	0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E,
+/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5,
+	0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5,
+/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0,
+	0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05,
+/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70,
+	0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA,
+/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F,
+	0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0,
+/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5,
+	0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01,
+/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D,
+	0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32,
+/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04,
+	0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82,
+/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01,
+	0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15,
+/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05,
+	0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43,
+/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E,
+	0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83,
+	0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0,
+/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34,
+	0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12,
+/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0,
+	0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0,
+/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04,
+	0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80,
+/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0,
+	0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83,
+/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12,
+	0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33,
+/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E,
+	0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15,
+/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75,
+	0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12,
+/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80,
+	0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12,
+/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20,
+	0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C,
+/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80,
+	0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF,
+/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25,
+	0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07,
+/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08,
+	0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0,
+/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+	0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E,
+/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+	0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94,
+/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04,
+	0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83,
+/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5,
+	0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07,
+/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75,
+	0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29,
+/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12,
+	0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0,
+/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70,
+	0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90,
+/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0,
+	0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF,
+/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5,
+	0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07,
+/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22,
+	0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90,
+/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94,
+	0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98,
+/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C,
+	0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0,
+/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4,
+	0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8,
+/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC,
+	0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0,
+/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6,
+	0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB,
+/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4,
+	0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5,
+/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08,
+	0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5,
+/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29,
+	0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80,
+/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5,
+	0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35,
+/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83,
+	0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12,
+/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26,
+	0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75,
+/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17,
+	0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4,
+/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93,
+	0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5,
+/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10,
+	0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54,
+/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06,
+	0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00,
+/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00,
+	0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0,
+/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75,
+	0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0,
+/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14,
+	0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70,
+/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7,
+	0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74,
+/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44,
+	0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12,
+/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0,
+	0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12,
+/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE,
+	0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B,
+/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4,
+	0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF,
+/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F,
+	0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70,
+/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41,
+	0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5,
+/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A,
+	0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5,
+/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5,
+	0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5,
+/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0,
+	0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C,
+/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80,
+	0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04,
+/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F,
+	0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A,
+/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41,
+	0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01,
+/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54,
+	0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F,
+/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58,
+	0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59,
+/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85,
+	0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59,
+/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15,
+	0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A,
+/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5,
+	0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2,
+/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20,
+	0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12,
+/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94,
+	0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9,
+/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9,
+	0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00,
+/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83,
+	0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12,
+/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02,
+	0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83,
+/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75,
+	0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94,
+/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A,
+	0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74,
+/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE,
+	0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08,
+/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85,
+	0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0,
+/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01,
+	0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC,
+/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E,
+	0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00,
+/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+	0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56,
+/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE,
+	0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12,
+/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E,
+	0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44,
+/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4,
+	0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08,
+/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82,
+	0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3,
+/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E,
+	0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC,
+	0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD,
+/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02,
+	0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09,
+/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42,
+	0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3,
+/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C,
+	0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F,
+/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84,
+	0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82,
+/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0,
+	0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22,
+/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75,
+	0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12,
+/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20,
+	0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26,
+/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41,
+	0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40,
+/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12,
+	0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56,
+/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42,
+	0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39,
+/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5,
+	0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F,
+/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB,
+	0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00,
+/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/mlx_bitops.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/mlx_bitops.h
new file mode 100644
index 0000000..490d5e3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/mlx_bitops.h
@@ -0,0 +1,245 @@
+#ifndef _MLX_BITOPS_H
+#define _MLX_BITOPS_H
+
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Mellanox bit operations
+ *
+ */
+
+/* Datatype used to represent a bit in the Mellanox autogenerated headers */
+typedef unsigned char pseudo_bit_t;
+
+/**
+ * Wrapper structure for pseudo_bit_t structures
+ *
+ * This structure provides a wrapper around the autogenerated
+ * pseudo_bit_t structures.  It has the correct size, and also
+ * encapsulates type information about the underlying pseudo_bit_t
+ * structure, which allows the MLX_FILL etc. macros to work without
+ * requiring explicit type information.
+ */
+#define MLX_DECLARE_STRUCT( _structure )				     \
+	_structure {							     \
+	    union {							     \
+		uint8_t bytes[ sizeof ( struct _structure ## _st ) / 8 ];    \
+		uint32_t dwords[ sizeof ( struct _structure ## _st ) / 32 ]; \
+		struct _structure ## _st *dummy[0];			     \
+	    } __attribute__ (( packed )) u;				     \
+	} __attribute__ (( packed ))
+
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
+#define MLX_PSEUDO_STRUCT( _ptr )					     \
+	typeof ( *((_ptr)->u.dummy[0]) )
+
+/** Bit offset of a field within a pseudo_bit_t structure */
+#define MLX_BIT_OFFSET( _structure_st, _field )				     \
+	offsetof ( _structure_st, _field )
+
+/** Dword offset of a field within a pseudo_bit_t structure */
+#define MLX_DWORD_OFFSET( _structure_st, _field )			     \
+	( MLX_BIT_OFFSET ( _structure_st, _field ) / 32 )
+
+/** Dword bit offset of a field within a pseudo_bit_t structure
+ *
+ * Yes, using mod-32 would work, but would lose the check for the
+ * error of specifying a mismatched field name and dword index.
+ */
+#define MLX_DWORD_BIT_OFFSET( _structure_st, _index, _field )		     \
+	( MLX_BIT_OFFSET ( _structure_st, _field ) - ( 32 * (_index) ) )
+
+/** Bit width of a field within a pseudo_bit_t structure */
+#define MLX_BIT_WIDTH( _structure_st, _field )				     \
+	sizeof ( ( ( _structure_st * ) NULL )->_field )
+
+/** Bit mask for a field within a pseudo_bit_t structure */
+#define MLX_BIT_MASK( _structure_st, _field )				     \
+	( ( ~( ( uint32_t ) 0 ) ) >>					     \
+	  ( 32 - MLX_BIT_WIDTH ( _structure_st, _field ) ) )
+
+/*
+ * Assemble native-endian dword from named fields and values
+ *
+ */
+
+#define MLX_ASSEMBLE_1( _structure_st, _index, _field, _value )		     \
+	( (_value) << MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
+
+#define MLX_ASSEMBLE_2( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_1 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_3( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_2 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_4( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_3 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_5( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_4 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_6( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_5 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_7( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_6 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_ASSEMBLE_8( _structure_st, _index, _field, _value, ... )	     \
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
+	  MLX_ASSEMBLE_7 ( _structure_st, _index, __VA_ARGS__ ) )
+
+/*
+ * Build native-endian (positive) dword bitmasks from named fields
+ *
+ */
+
+#define MLX_MASK_1( _structure_st, _index, _field )			     \
+	( MLX_BIT_MASK ( _structure_st, _field ) <<			     \
+	  MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
+
+#define MLX_MASK_2( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_1 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_3( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_2 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_4( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_3 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_5( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_4 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_6( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_5 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_7( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_6 ( _structure_st, _index, __VA_ARGS__ ) )
+
+#define MLX_MASK_8( _structure_st, _index, _field, ... )		     \
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
+	  MLX_MASK_7 ( _structure_st, _index, __VA_ARGS__ ) )
+
+/*
+ * Populate big-endian dwords from named fields and values
+ *
+ */
+
+#define MLX_FILL( _ptr, _index, _assembled )				     \
+	do {								     \
+		uint32_t *__ptr = &(_ptr)->u.dwords[(_index)];		     \
+		uint32_t __assembled = (_assembled);			     \
+		*__ptr = cpu_to_be32 ( __assembled );			     \
+	} while ( 0 )
+
+#define MLX_FILL_1( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_2( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_2 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_3( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_3 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_4( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_4 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_5( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_5 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_6( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_6 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_7( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_7 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+#define MLX_FILL_8( _ptr, _index, ... )					     \
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_8 ( MLX_PSEUDO_STRUCT ( _ptr ),\
+						  _index, __VA_ARGS__ ) )
+
+/*
+ * Modify big-endian dword using named field and value
+ *
+ */
+
+#define MLX_SET( _ptr, _field, _value )					     \
+	do {								     \
+		unsigned int __index = 					     \
+		    MLX_DWORD_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ), _field ); \
+		uint32_t *__ptr = &(_ptr)->u.dwords[__index];		     \
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
+		__value &= ~( MLX_MASK_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
+					   __index, _field ) );		     \
+		__value |= MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
+					    __index, _field, _value );	     \
+		*__ptr = cpu_to_be32 ( __value );			     \
+	} while ( 0 )
+
+/*
+ * Extract value of named field
+ *
+ */
+
+#define MLX_GET( _ptr, _field )						     \
+	( {								     \
+		unsigned int __index = 					     \
+		    MLX_DWORD_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ), _field ); \
+		uint32_t *__ptr = &(_ptr)->u.dwords[__index];		     \
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
+		__value >>=						     \
+		    MLX_DWORD_BIT_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
+					    __index, _field );		     \
+		__value &=						     \
+		    MLX_BIT_MASK ( MLX_PSEUDO_STRUCT ( _ptr ), _field );     \
+		__value;						     \
+	} )
+
+/*
+ * Fill high dword of physical address, if necessary
+ *
+ */
+#define MLX_FILL_H( _structure_st, _index, _field, _address ) do {	     \
+	if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {		     \
+		MLX_FILL_1 ( _structure_st, _index, _field,		     \
+			     ( ( ( uint64_t ) (_address) ) >> 32 ) );	     \
+	} } while ( 0 )
+
+#endif /* _MLX_BITOPS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.c b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.c
new file mode 100644
index 0000000..b66f8ef
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.c
@@ -0,0 +1,2428 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/i2c.h>
+#include <ipxe/bitbash.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/pcibackup.h>
+#include "qib7322.h"
+
+/**
+ * @file
+ *
+ * QLogic QIB7322 Infiniband HCA
+ *
+ */
+
+/** A QIB7322 send buffer set */
+struct qib7322_send_buffers {
+	/** Offset within register space of the first send buffer */
+	unsigned long base;
+	/** Send buffer size */
+	unsigned int size;
+	/** Index of first send buffer */
+	unsigned int start;
+	/** Number of send buffers
+	 *
+	 * Must be a power of two.
+	 */
+	unsigned int count;
+	/** Send buffer availability producer counter */
+	unsigned int prod;
+	/** Send buffer availability consumer counter */
+	unsigned int cons;
+	/** Send buffer availability */
+	uint16_t avail[0];
+};
+
+/** A QIB7322 send work queue */
+struct qib7322_send_work_queue {
+	/** Send buffer set */
+	struct qib7322_send_buffers *send_bufs;
+	/** Send buffer usage */
+	uint16_t *used;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
+};
+
+/** A QIB7322 receive work queue */
+struct qib7322_recv_work_queue {
+	/** Receive header ring */
+	void *header;
+	/** Receive header producer offset (written by hardware) */
+	struct QIB_7322_scalar header_prod;
+	/** Receive header consumer offset */
+	unsigned int header_cons;
+	/** Offset within register space of the eager array */
+	unsigned long eager_array;
+	/** Number of entries in eager array */
+	unsigned int eager_entries;
+	/** Eager array producer index */
+	unsigned int eager_prod;
+	/** Eager array consumer index */
+	unsigned int eager_cons;
+};
+
+/** A QIB7322 HCA */
+struct qib7322 {
+	/** Registers */
+	void *regs;
+
+	/** In-use contexts */
+	uint8_t used_ctx[QIB7322_NUM_CONTEXTS];
+	/** Send work queues */
+	struct qib7322_send_work_queue send_wq[QIB7322_NUM_CONTEXTS];
+	/** Receive work queues */
+	struct qib7322_recv_work_queue recv_wq[QIB7322_NUM_CONTEXTS];
+
+	/** Send buffer availability (reported by hardware) */
+	struct QIB_7322_SendBufAvail *sendbufavail;
+	/** Small send buffers */
+	struct qib7322_send_buffers *send_bufs_small;
+	/** VL15 port 0 send buffers */
+	struct qib7322_send_buffers *send_bufs_vl15_port0;
+	/** VL15 port 1 send buffers */
+	struct qib7322_send_buffers *send_bufs_vl15_port1;
+
+	/** I2C bit-bashing interface */
+	struct i2c_bit_basher i2c;
+	/** I2C serial EEPROM */
+	struct i2c_device eeprom;
+
+	/** Base GUID */
+	union ib_guid guid;
+	/** Infiniband devices */
+	struct ib_device *ibdev[QIB7322_MAX_PORTS];
+};
+
+/***************************************************************************
+ *
+ * QIB7322 register access
+ *
+ ***************************************************************************
+ *
+ * This card requires atomic 64-bit accesses.  Strange things happen
+ * if you try to use 32-bit accesses; sometimes they work, sometimes
+ * they don't, sometimes you get random data.
+ *
+ * These accessors use the "movq" MMX instruction, and so won't work
+ * on really old Pentiums (which won't have PCIe anyway, so this is
+ * something of a moot point).
+ */
+
+/**
+ * Read QIB7322 qword register
+ *
+ * @v qib7322		QIB7322 device
+ * @v dwords		Register buffer to read into
+ * @v offset		Register offset
+ */
+static void qib7322_readq ( struct qib7322 *qib7322, uint32_t *dwords,
+			    unsigned long offset ) {
+	void *addr = ( qib7322->regs + offset );
+
+	__asm__ __volatile__ ( "movq (%1), %%mm0\n\t"
+			       "movq %%mm0, (%0)\n\t"
+			       : : "r" ( dwords ), "r" ( addr ) : "memory" );
+
+	DBGIO ( "[%08lx] => %08x%08x\n",
+		virt_to_phys ( addr ), dwords[1], dwords[0] );
+}
+#define qib7322_readq( _qib7322, _ptr, _offset ) \
+	qib7322_readq ( (_qib7322), (_ptr)->u.dwords, (_offset) )
+#define qib7322_readq_array8b( _qib7322, _ptr, _offset, _idx ) \
+	qib7322_readq ( (_qib7322), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define qib7322_readq_array64k( _qib7322, _ptr, _offset, _idx ) \
+	qib7322_readq ( (_qib7322), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+#define qib7322_readq_port( _qib7322, _ptr, _offset, _port ) \
+	qib7322_readq ( (_qib7322), (_ptr), ( (_offset) + ( (_port) * 4096 ) ) )
+
+/**
+ * Write QIB7322 qword register
+ *
+ * @v qib7322		QIB7322 device
+ * @v dwords		Register buffer to write
+ * @v offset		Register offset
+ */
+static void qib7322_writeq ( struct qib7322 *qib7322, const uint32_t *dwords,
+			     unsigned long offset ) {
+	void *addr = ( qib7322->regs + offset );
+
+	DBGIO ( "[%08lx] <= %08x%08x\n",
+		virt_to_phys ( addr ), dwords[1], dwords[0] );
+
+	__asm__ __volatile__ ( "movq (%0), %%mm0\n\t"
+			       "movq %%mm0, (%1)\n\t"
+			       : : "r" ( dwords ), "r" ( addr ) : "memory" );
+}
+#define qib7322_writeq( _qib7322, _ptr, _offset ) \
+	qib7322_writeq ( (_qib7322), (_ptr)->u.dwords, (_offset) )
+#define qib7322_writeq_array8b( _qib7322, _ptr, _offset, _idx ) \
+	qib7322_writeq ( (_qib7322), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define qib7322_writeq_array64k( _qib7322, _ptr, _offset, _idx ) \
+	qib7322_writeq ( (_qib7322), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ))
+#define qib7322_writeq_port( _qib7322, _ptr, _offset, _port ) \
+	qib7322_writeq ( (_qib7322), (_ptr), ( (_offset) + ( (_port) * 4096 ) ))
+
+/**
+ * Write QIB7322 dword register
+ *
+ * @v qib7322		QIB7322 device
+ * @v dword		Value to write
+ * @v offset		Register offset
+ */
+static void qib7322_writel ( struct qib7322 *qib7322, uint32_t dword,
+			     unsigned long offset ) {
+	writel ( dword, ( qib7322->regs + offset ) );
+}
+
+/***************************************************************************
+ *
+ * Link state management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Textual representation of link state
+ *
+ * @v link_state	Link state
+ * @ret link_text	Link state text
+ */
+static const char * qib7322_link_state_text ( unsigned int link_state ) {
+	switch ( link_state ) {
+	case QIB7322_LINK_STATE_DOWN:		return "DOWN";
+	case QIB7322_LINK_STATE_INIT:		return "INIT";
+	case QIB7322_LINK_STATE_ARM:		return "ARM";
+	case QIB7322_LINK_STATE_ACTIVE:		return "ACTIVE";
+	case QIB7322_LINK_STATE_ACT_DEFER:	return "ACT_DEFER";
+	default:				return "UNKNOWN";
+	}
+}
+
+/**
+ * Handle link state change
+ *
+ * @v qib7322		QIB7322 device
+ */
+static void qib7322_link_state_changed ( struct ib_device *ibdev ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct QIB_7322_IBCStatusA_0 ibcstatusa;
+	struct QIB_7322_EXTCtrl extctrl;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int link_training_state;
+	unsigned int link_state;
+	unsigned int link_width;
+	unsigned int link_speed;
+	unsigned int link_speed_qdr;
+	unsigned int green;
+	unsigned int yellow;
+
+	/* Read link state */
+	qib7322_readq_port ( qib7322, &ibcstatusa,
+			     QIB_7322_IBCStatusA_0_offset, port );
+	link_training_state = BIT_GET ( &ibcstatusa, LinkTrainingState );
+	link_state = BIT_GET ( &ibcstatusa, LinkState );
+	link_width = BIT_GET ( &ibcstatusa, LinkWidthActive );
+	link_speed = BIT_GET ( &ibcstatusa, LinkSpeedActive );
+	link_speed_qdr = BIT_GET ( &ibcstatusa, LinkSpeedQDR );
+	DBGC ( qib7322, "QIB7322 %p port %d training state %#x link state %s "
+	       "(%s %s)\n", qib7322, port, link_training_state,
+	       qib7322_link_state_text ( link_state ),
+	       ( link_speed_qdr ? "QDR" : ( link_speed ? "DDR" : "SDR" ) ),
+	       ( link_width ? "x4" : "x1" ) );
+
+	/* Set LEDs according to link state */
+	qib7322_readq ( qib7322, &extctrl, QIB_7322_EXTCtrl_offset );
+	green = ( ( link_state >= QIB7322_LINK_STATE_INIT ) ? 1 : 0 );
+	yellow = ( ( link_state >= QIB7322_LINK_STATE_ACTIVE ) ? 1 : 0 );
+	if ( port == 0 ) {
+		BIT_SET ( &extctrl, LEDPort0GreenOn, green );
+		BIT_SET ( &extctrl, LEDPort0YellowOn, yellow );
+	} else {
+		BIT_SET ( &extctrl, LEDPort1GreenOn, green );
+		BIT_SET ( &extctrl, LEDPort1YellowOn, yellow );
+	}
+	qib7322_writeq ( qib7322, &extctrl, QIB_7322_EXTCtrl_offset );
+
+	/* Notify Infiniband core of link state change */
+	ibdev->port_state = ( link_state + 1 );
+	ibdev->link_width_active =
+		( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X );
+	ibdev->link_speed_active =
+		( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR );
+	ib_link_state_changed ( ibdev );
+}
+
+/**
+ * Wait for link state change to take effect
+ *
+ * @v ibdev		Infiniband device
+ * @v new_link_state	Expected link state
+ * @ret rc		Return status code
+ */
+static int qib7322_link_state_check ( struct ib_device *ibdev,
+				      unsigned int new_link_state ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct QIB_7322_IBCStatusA_0 ibcstatusa;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int link_state;
+	unsigned int i;
+
+	for ( i = 0 ; i < QIB7322_LINK_STATE_MAX_WAIT_US ; i++ ) {
+		qib7322_readq_port ( qib7322, &ibcstatusa,
+				     QIB_7322_IBCStatusA_0_offset, port );
+		link_state = BIT_GET ( &ibcstatusa, LinkState );
+		if ( link_state == new_link_state )
+			return 0;
+		udelay ( 1 );
+	}
+
+	DBGC ( qib7322, "QIB7322 %p port %d timed out waiting for link state "
+	       "%s\n", qib7322, port, qib7322_link_state_text ( link_state ) );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set port information MAD
+ */
+static int qib7322_set_port_info ( struct ib_device *ibdev,
+				   union ib_mad *mad ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+	struct QIB_7322_IBCCtrlA_0 ibcctrla;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int port_state;
+	unsigned int link_state;
+
+	/* Set new link state */
+	port_state = ( port_info->link_speed_supported__port_state & 0xf );
+	if ( port_state ) {
+		link_state = ( port_state - 1 );
+		DBGC ( qib7322, "QIB7322 %p set link state to %s (%x)\n",
+		       qib7322, qib7322_link_state_text ( link_state ),
+		       link_state );
+		qib7322_readq_port ( qib7322, &ibcctrla,
+				     QIB_7322_IBCCtrlA_0_offset, port );
+		BIT_SET ( &ibcctrla, LinkCmd, link_state );
+		qib7322_writeq_port ( qib7322, &ibcctrla,
+				      QIB_7322_IBCCtrlA_0_offset, port );
+
+		/* Wait for link state change to take effect.  Ignore
+		 * errors; the current link state will be returned via
+		 * the GetResponse MAD.
+		 */
+		qib7322_link_state_check ( ibdev, link_state );
+	}
+
+	/* Detect and report link state change */
+	qib7322_link_state_changed ( ibdev );
+
+	return 0;
+}
+
+/**
+ * Set partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set partition key table MAD
+ */
+static int qib7322_set_pkey_table ( struct ib_device *ibdev __unused,
+				    union ib_mad *mad __unused ) {
+	/* Nothing to do */
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Context allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate a context and set queue pair number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int qib7322_alloc_ctx ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int ctx;
+
+	for ( ctx = port ; ctx < QIB7322_NUM_CONTEXTS ; ctx += 2 ) {
+
+		if ( ! qib7322->used_ctx[ctx] ) {
+			qib7322->used_ctx[ctx] = 1;
+			qp->qpn = ( ctx & ~0x01 );
+			DBGC2 ( qib7322, "QIB7322 %p port %d QPN %ld is CTX "
+				"%d\n", qib7322, port, qp->qpn, ctx );
+			return 0;
+		}
+	}
+
+	DBGC ( qib7322, "QIB7322 %p port %d out of available contexts\n",
+	       qib7322, port );
+	return -ENOENT;
+}
+
+/**
+ * Get queue pair context number
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret ctx		Context index
+ */
+static unsigned int qib7322_ctx ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp ) {
+	return ( qp->qpn + ( ibdev->port - QIB7322_PORT_BASE ) );
+}
+
+/**
+ * Free a context
+ *
+ * @v qib7322		QIB7322 device
+ * @v ctx		Context index
+ */
+static void qib7322_free_ctx ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int ctx = qib7322_ctx ( ibdev, qp );
+
+	qib7322->used_ctx[ctx] = 0;
+	DBGC2 ( qib7322, "QIB7322 %p port %d CTX %d freed\n",
+		qib7322, port, ctx );
+}
+
+/***************************************************************************
+ *
+ * Send datapath
+ *
+ ***************************************************************************
+ */
+
+/** Send buffer toggle bit
+ *
+ * We encode send buffers as 15 bits of send buffer index plus a
+ * single bit which should match the "check" bit in the SendBufAvail
+ * array.
+ */
+#define QIB7322_SEND_BUF_TOGGLE 0x8000
+
+/**
+ * Create send buffer set
+ *
+ * @v qib7322		QIB7322 device
+ * @v base		Send buffer base offset
+ * @v size		Send buffer size
+ * @v start		Index of first send buffer
+ * @v count		Number of send buffers
+ * @ret send_bufs	Send buffer set
+ */
+static struct qib7322_send_buffers *
+qib7322_create_send_bufs ( struct qib7322 *qib7322, unsigned long base,
+			   unsigned int size, unsigned int start,
+			   unsigned int count ) {
+	struct qib7322_send_buffers *send_bufs;
+	unsigned int i;
+
+	/* Allocate send buffer set */
+	send_bufs = zalloc ( sizeof ( *send_bufs ) +
+			     ( count * sizeof ( send_bufs->avail[0] ) ) );
+	if ( ! send_bufs )
+		return NULL;
+
+	/* Populate send buffer set */
+	send_bufs->base = base;
+	send_bufs->size = size;
+	send_bufs->start = start;
+	send_bufs->count = count;
+	for ( i = 0 ; i < count ; i++ )
+		send_bufs->avail[i] = ( start + i );
+
+	DBGC2 ( qib7322, "QIB7322 %p send buffer set %p [%d,%d] at %lx\n",
+		qib7322, send_bufs, start, ( start + count - 1 ),
+		send_bufs->base );
+
+	return send_bufs;
+}
+
+/**
+ * Destroy send buffer set
+ *
+ * @v qib7322		QIB7322 device
+ * @v send_bufs		Send buffer set
+ */
+static void
+qib7322_destroy_send_bufs ( struct qib7322 *qib7322 __unused,
+			    struct qib7322_send_buffers *send_bufs ) {
+	free ( send_bufs );
+}
+
+/**
+ * Allocate a send buffer
+ *
+ * @v qib7322		QIB7322 device
+ * @v send_bufs		Send buffer set
+ * @ret send_buf	Send buffer, or negative error
+ */
+static int qib7322_alloc_send_buf ( struct qib7322 *qib7322,
+				    struct qib7322_send_buffers *send_bufs ) {
+	unsigned int used;
+	unsigned int mask;
+	unsigned int send_buf;
+
+	used = ( send_bufs->cons - send_bufs->prod );
+	if ( used >= send_bufs->count ) {
+		DBGC ( qib7322, "QIB7322 %p send buffer set %p out of "
+		       "buffers\n", qib7322, send_bufs );
+		return -ENOBUFS;
+	}
+
+	mask = ( send_bufs->count - 1 );
+	send_buf = send_bufs->avail[ send_bufs->cons++ & mask ];
+	send_buf ^= QIB7322_SEND_BUF_TOGGLE;
+	return send_buf;
+}
+
+/**
+ * Free a send buffer
+ *
+ * @v qib7322		QIB7322 device
+ * @v send_bufs		Send buffer set
+ * @v send_buf		Send buffer
+ */
+static void qib7322_free_send_buf ( struct qib7322 *qib7322 __unused,
+				    struct qib7322_send_buffers *send_bufs,
+				    unsigned int send_buf ) {
+	unsigned int mask;
+
+	mask = ( send_bufs->count - 1 );
+	send_bufs->avail[ send_bufs->prod++ & mask ] = send_buf;
+}
+
+/**
+ * Check to see if send buffer is in use
+ *
+ * @v qib7322		QIB7322 device
+ * @v send_buf		Send buffer
+ * @ret in_use		Send buffer is in use
+ */
+static int qib7322_send_buf_in_use ( struct qib7322 *qib7322,
+				     unsigned int send_buf ) {
+	unsigned int send_idx;
+	unsigned int send_check;
+	unsigned int inusecheck;
+	unsigned int inuse;
+	unsigned int check;
+
+	send_idx = ( send_buf & ~QIB7322_SEND_BUF_TOGGLE );
+	send_check = ( !! ( send_buf & QIB7322_SEND_BUF_TOGGLE ) );
+	inusecheck = BIT_GET ( qib7322->sendbufavail, InUseCheck[send_idx] );
+	inuse = ( !! ( inusecheck & 0x02 ) );
+	check = ( !! ( inusecheck & 0x01 ) );
+	return ( inuse || ( check != send_check ) );
+}
+
+/**
+ * Calculate starting offset for send buffer
+ *
+ * @v qib7322		QIB7322 device
+ * @v send_buf		Send buffer
+ * @ret offset		Starting offset
+ */
+static unsigned long
+qib7322_send_buffer_offset ( struct qib7322 *qib7322 __unused,
+			     struct qib7322_send_buffers *send_bufs,
+			     unsigned int send_buf ) {
+	unsigned int index;
+
+	index = ( ( send_buf & ~QIB7322_SEND_BUF_TOGGLE ) - send_bufs->start );
+	return ( send_bufs->base + ( index * send_bufs->size ) );
+}
+
+/**
+ * Create send work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static int qib7322_create_send_wq ( struct ib_device *ibdev,
+				    struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct qib7322_send_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+
+	/* Select send buffer set */
+	if ( qp->type == IB_QPT_SMI ) {
+		if ( port == 0 ) {
+			qib7322_wq->send_bufs = qib7322->send_bufs_vl15_port0;
+		} else {
+			qib7322_wq->send_bufs = qib7322->send_bufs_vl15_port1;
+		}
+	} else {
+		qib7322_wq->send_bufs = qib7322->send_bufs_small;
+	}
+
+	/* Allocate space for send buffer usage list */
+	qib7322_wq->used = zalloc ( qp->send.num_wqes *
+				    sizeof ( qib7322_wq->used[0] ) );
+	if ( ! qib7322_wq->used )
+		return -ENOMEM;
+
+	/* Reset work queue */
+	qib7322_wq->prod = 0;
+	qib7322_wq->cons = 0;
+
+	return 0;
+}
+
+/**
+ * Destroy send work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void qib7322_destroy_send_wq ( struct ib_device *ibdev __unused,
+				      struct ib_queue_pair *qp ) {
+	struct ib_work_queue *wq = &qp->send;
+	struct qib7322_send_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+
+	free ( qib7322_wq->used );
+}
+
+/**
+ * Initialise send datapath
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_init_send ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_SendBufBase sendbufbase;
+	struct QIB_7322_SendBufAvailAddr sendbufavailaddr;
+	struct QIB_7322_SendCtrl sendctrl;
+	struct QIB_7322_SendCtrl_0 sendctrlp;
+	unsigned long baseaddr_smallpio;
+	unsigned long baseaddr_largepio;
+	unsigned long baseaddr_vl15_port0;
+	unsigned long baseaddr_vl15_port1;
+	int rc;
+
+	/* Create send buffer sets */
+	qib7322_readq ( qib7322, &sendbufbase, QIB_7322_SendBufBase_offset );
+	baseaddr_smallpio = BIT_GET ( &sendbufbase, BaseAddr_SmallPIO );
+	baseaddr_largepio = BIT_GET ( &sendbufbase, BaseAddr_LargePIO );
+	baseaddr_vl15_port0 = ( baseaddr_largepio +
+				( QIB7322_LARGE_SEND_BUF_SIZE *
+				  QIB7322_LARGE_SEND_BUF_COUNT ) );
+	baseaddr_vl15_port1 = ( baseaddr_vl15_port0 +
+				QIB7322_VL15_PORT0_SEND_BUF_SIZE );
+	qib7322->send_bufs_small =
+		qib7322_create_send_bufs ( qib7322, baseaddr_smallpio,
+					   QIB7322_SMALL_SEND_BUF_SIZE,
+					   QIB7322_SMALL_SEND_BUF_START,
+					   QIB7322_SMALL_SEND_BUF_USED );
+	if ( ! qib7322->send_bufs_small ) {
+		rc = -ENOMEM;
+		goto err_create_send_bufs_small;
+	}
+	qib7322->send_bufs_vl15_port0 =
+		qib7322_create_send_bufs ( qib7322, baseaddr_vl15_port0,
+					   QIB7322_VL15_PORT0_SEND_BUF_SIZE,
+					   QIB7322_VL15_PORT0_SEND_BUF_START,
+					   QIB7322_VL15_PORT0_SEND_BUF_COUNT );
+	if ( ! qib7322->send_bufs_vl15_port0 ) {
+		rc = -ENOMEM;
+		goto err_create_send_bufs_vl15_port0;
+	}
+	qib7322->send_bufs_vl15_port1 =
+		qib7322_create_send_bufs ( qib7322, baseaddr_vl15_port1,
+					   QIB7322_VL15_PORT1_SEND_BUF_SIZE,
+					   QIB7322_VL15_PORT1_SEND_BUF_START,
+					   QIB7322_VL15_PORT1_SEND_BUF_COUNT );
+	if ( ! qib7322->send_bufs_vl15_port1 ) {
+		rc = -ENOMEM;
+		goto err_create_send_bufs_vl15_port1;
+	}
+
+	/* Allocate space for the SendBufAvail array */
+	qib7322->sendbufavail = malloc_dma ( sizeof ( *qib7322->sendbufavail ),
+					     QIB7322_SENDBUFAVAIL_ALIGN );
+	if ( ! qib7322->sendbufavail ) {
+		rc = -ENOMEM;
+		goto err_alloc_sendbufavail;
+	}
+	memset ( qib7322->sendbufavail, 0, sizeof ( qib7322->sendbufavail ) );
+
+	/* Program SendBufAvailAddr into the hardware */
+	memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) );
+	BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr,
+		     ( virt_to_bus ( qib7322->sendbufavail ) >> 6 ) );
+	qib7322_writeq ( qib7322, &sendbufavailaddr,
+			 QIB_7322_SendBufAvailAddr_offset );
+
+	/* Enable sending */
+	memset ( &sendctrlp, 0, sizeof ( sendctrlp ) );
+	BIT_FILL_1 ( &sendctrlp, SendEnable, 1 );
+	qib7322_writeq ( qib7322, &sendctrlp, QIB_7322_SendCtrl_0_offset );
+	qib7322_writeq ( qib7322, &sendctrlp, QIB_7322_SendCtrl_1_offset );
+
+	/* Enable DMA of SendBufAvail */
+	memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+	BIT_FILL_1 ( &sendctrl, SendBufAvailUpd, 1 );
+	qib7322_writeq ( qib7322, &sendctrl, QIB_7322_SendCtrl_offset );
+
+	return 0;
+
+	free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) );
+ err_alloc_sendbufavail:
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 );
+ err_create_send_bufs_vl15_port1:
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port0 );
+ err_create_send_bufs_vl15_port0:
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_small );
+ err_create_send_bufs_small:
+	return rc;
+}
+
+/**
+ * Shut down send datapath
+ *
+ * @v qib7322		QIB7322 device
+ */
+static void qib7322_fini_send ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_SendCtrl sendctrl;
+
+	/* Disable sending and DMA of SendBufAvail */
+	memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+	qib7322_writeq ( qib7322, &sendctrl, QIB_7322_SendCtrl_offset );
+	mb();
+
+	/* Ensure hardware has seen this disable */
+	qib7322_readq ( qib7322, &sendctrl, QIB_7322_SendCtrl_offset );
+
+	free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) );
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 );
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port0 );
+	qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_small );
+}
+
+/***************************************************************************
+ *
+ * Receive datapath
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create receive work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int qib7322_create_recv_wq ( struct ib_device *ibdev,
+				    struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct qib7322_recv_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_RcvHdrAddr0 rcvhdraddr;
+	struct QIB_7322_RcvHdrTailAddr0 rcvhdrtailaddr;
+	struct QIB_7322_RcvHdrHead0 rcvhdrhead;
+	struct QIB_7322_scalar rcvegrindexhead;
+	struct QIB_7322_RcvCtrl rcvctrl;
+	struct QIB_7322_RcvCtrl_P rcvctrlp;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int ctx = qib7322_ctx ( ibdev, qp );
+	int rc;
+
+	/* Reset context information */
+	memset ( &qib7322_wq->header_prod, 0,
+		 sizeof ( qib7322_wq->header_prod ) );
+	qib7322_wq->header_cons = 0;
+	qib7322_wq->eager_prod = 0;
+	qib7322_wq->eager_cons = 0;
+
+	/* Allocate receive header buffer */
+	qib7322_wq->header = malloc_dma ( QIB7322_RECV_HEADERS_SIZE,
+					  QIB7322_RECV_HEADERS_ALIGN );
+	if ( ! qib7322_wq->header ) {
+		rc = -ENOMEM;
+		goto err_alloc_header;
+	}
+
+	/* Enable context in hardware */
+	memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) );
+	BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr,
+		     ( virt_to_bus ( qib7322_wq->header ) >> 2 ) );
+	qib7322_writeq_array8b ( qib7322, &rcvhdraddr,
+				 QIB_7322_RcvHdrAddr0_offset, ctx );
+	memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) );
+	BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr,
+		     ( virt_to_bus ( &qib7322_wq->header_prod ) >> 2 ) );
+	qib7322_writeq_array8b ( qib7322, &rcvhdrtailaddr,
+				 QIB_7322_RcvHdrTailAddr0_offset, ctx );
+	memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+	BIT_FILL_1 ( &rcvhdrhead, counter, 1 );
+	qib7322_writeq_array64k ( qib7322, &rcvhdrhead,
+				  QIB_7322_RcvHdrHead0_offset, ctx );
+	memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+	BIT_FILL_1 ( &rcvegrindexhead, Value, 1 );
+	qib7322_writeq_array64k ( qib7322, &rcvegrindexhead,
+				  QIB_7322_RcvEgrIndexHead0_offset, ctx );
+	qib7322_readq_port ( qib7322, &rcvctrlp,
+			     QIB_7322_RcvCtrl_0_offset, port );
+	BIT_SET ( &rcvctrlp, ContextEnable[ctx], 1 );
+	qib7322_writeq_port ( qib7322, &rcvctrlp,
+			      QIB_7322_RcvCtrl_0_offset, port );
+	qib7322_readq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+	BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 );
+	qib7322_writeq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+
+	DBGC ( qib7322, "QIB7322 %p port %d QPN %ld CTX %d hdrs [%lx,%lx) prod "
+	       "%lx\n", qib7322, port, qp->qpn, ctx,
+	       virt_to_bus ( qib7322_wq->header ),
+	       ( virt_to_bus ( qib7322_wq->header )
+		 + QIB7322_RECV_HEADERS_SIZE ),
+	       virt_to_bus ( &qib7322_wq->header_prod ) );
+	return 0;
+
+	free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE );
+ err_alloc_header:
+	return rc;
+}
+
+/**
+ * Destroy receive work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void qib7322_destroy_recv_wq ( struct ib_device *ibdev,
+				      struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct qib7322_recv_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_RcvCtrl rcvctrl;
+	struct QIB_7322_RcvCtrl_P rcvctrlp;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	unsigned int ctx = qib7322_ctx ( ibdev, qp );
+
+	/* Disable context in hardware */
+	qib7322_readq_port ( qib7322, &rcvctrlp,
+			     QIB_7322_RcvCtrl_0_offset, port );
+	BIT_SET ( &rcvctrlp, ContextEnable[ctx], 0 );
+	qib7322_writeq_port ( qib7322, &rcvctrlp,
+			      QIB_7322_RcvCtrl_0_offset, port );
+	qib7322_readq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+	BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 );
+	qib7322_writeq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+
+	/* Make sure the hardware has seen that the context is disabled */
+	qib7322_readq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+	mb();
+
+	/* Free headers ring */
+	free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE );
+}
+
+/**
+ * Initialise receive datapath
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_init_recv ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_RcvCtrl rcvctrl;
+	struct QIB_7322_RcvCtrl_0 rcvctrlp;
+	struct QIB_7322_RcvQPMapTableA_0 rcvqpmaptablea0;
+	struct QIB_7322_RcvQPMapTableB_0 rcvqpmaptableb0;
+	struct QIB_7322_RcvQPMapTableA_1 rcvqpmaptablea1;
+	struct QIB_7322_RcvQPMapTableB_1 rcvqpmaptableb1;
+	struct QIB_7322_RcvQPMulticastContext_0 rcvqpmcastctx0;
+	struct QIB_7322_RcvQPMulticastContext_1 rcvqpmcastctx1;
+	struct QIB_7322_scalar rcvegrbase;
+	struct QIB_7322_scalar rcvhdrentsize;
+	struct QIB_7322_scalar rcvhdrcnt;
+	struct QIB_7322_RcvBTHQP_0 rcvbthqp;
+	struct QIB_7322_RxCreditVL0_0 rxcreditvl;
+	unsigned int contextcfg;
+	unsigned long egrbase;
+	unsigned int eager_array_size_kernel;
+	unsigned int eager_array_size_user;
+	unsigned int ctx;
+
+	/* Select configuration based on number of contexts */
+	switch ( QIB7322_NUM_CONTEXTS ) {
+	case 6:
+		contextcfg = QIB7322_CONTEXTCFG_6CTX;
+		eager_array_size_kernel = QIB7322_EAGER_ARRAY_SIZE_6CTX_KERNEL;
+		eager_array_size_user = QIB7322_EAGER_ARRAY_SIZE_6CTX_USER;
+		break;
+	case 10:
+		contextcfg = QIB7322_CONTEXTCFG_10CTX;
+		eager_array_size_kernel = QIB7322_EAGER_ARRAY_SIZE_10CTX_KERNEL;
+		eager_array_size_user = QIB7322_EAGER_ARRAY_SIZE_10CTX_USER;
+		break;
+	case 18:
+		contextcfg = QIB7322_CONTEXTCFG_18CTX;
+		eager_array_size_kernel = QIB7322_EAGER_ARRAY_SIZE_18CTX_KERNEL;
+		eager_array_size_user = QIB7322_EAGER_ARRAY_SIZE_18CTX_USER;
+		break;
+	default:
+		linker_assert ( 0, invalid_QIB7322_NUM_CONTEXTS );
+		return -EINVAL;
+	}
+
+	/* Configure number of contexts */
+	memset ( &rcvctrl, 0, sizeof ( rcvctrl ) );
+	BIT_FILL_2 ( &rcvctrl,
+		     TailUpd, 1,
+		     ContextCfg, contextcfg );
+	qib7322_writeq ( qib7322, &rcvctrl, QIB_7322_RcvCtrl_offset );
+
+	/* Map QPNs to contexts */
+	memset ( &rcvctrlp, 0, sizeof ( rcvctrlp ) );
+	BIT_FILL_3 ( &rcvctrlp,
+		     RcvIBPortEnable, 1,
+		     RcvQPMapEnable, 1,
+		     RcvPartitionKeyDisable, 1 );
+	qib7322_writeq ( qib7322, &rcvctrlp, QIB_7322_RcvCtrl_0_offset );
+	qib7322_writeq ( qib7322, &rcvctrlp, QIB_7322_RcvCtrl_1_offset );
+	memset ( &rcvqpmaptablea0, 0, sizeof ( rcvqpmaptablea0 ) );
+	BIT_FILL_6 ( &rcvqpmaptablea0,
+		     RcvQPMapContext0, 0,
+		     RcvQPMapContext1, 2,
+		     RcvQPMapContext2, 4,
+		     RcvQPMapContext3, 6,
+		     RcvQPMapContext4, 8,
+		     RcvQPMapContext5, 10 );
+	qib7322_writeq ( qib7322, &rcvqpmaptablea0,
+			 QIB_7322_RcvQPMapTableA_0_offset );
+	memset ( &rcvqpmaptableb0, 0, sizeof ( rcvqpmaptableb0 ) );
+	BIT_FILL_3 ( &rcvqpmaptableb0,
+		     RcvQPMapContext6, 12,
+		     RcvQPMapContext7, 14,
+		     RcvQPMapContext8, 16 );
+	qib7322_writeq ( qib7322, &rcvqpmaptableb0,
+			 QIB_7322_RcvQPMapTableB_0_offset );
+	memset ( &rcvqpmaptablea1, 0, sizeof ( rcvqpmaptablea1 ) );
+	BIT_FILL_6 ( &rcvqpmaptablea1,
+		     RcvQPMapContext0, 1,
+		     RcvQPMapContext1, 3,
+		     RcvQPMapContext2, 5,
+		     RcvQPMapContext3, 7,
+		     RcvQPMapContext4, 9,
+		     RcvQPMapContext5, 11 );
+	qib7322_writeq ( qib7322, &rcvqpmaptablea1,
+			 QIB_7322_RcvQPMapTableA_1_offset );
+	memset ( &rcvqpmaptableb1, 0, sizeof ( rcvqpmaptableb1 ) );
+	BIT_FILL_3 ( &rcvqpmaptableb1,
+		     RcvQPMapContext6, 13,
+		     RcvQPMapContext7, 15,
+		     RcvQPMapContext8, 17 );
+	qib7322_writeq ( qib7322, &rcvqpmaptableb1,
+			 QIB_7322_RcvQPMapTableB_1_offset );
+
+	/* Map multicast QPNs to contexts */
+	memset ( &rcvqpmcastctx0, 0, sizeof ( rcvqpmcastctx0 ) );
+	BIT_FILL_1 ( &rcvqpmcastctx0, RcvQpMcContext, 0 );
+	qib7322_writeq ( qib7322, &rcvqpmcastctx0,
+			 QIB_7322_RcvQPMulticastContext_0_offset );
+	memset ( &rcvqpmcastctx1, 0, sizeof ( rcvqpmcastctx1 ) );
+	BIT_FILL_1 ( &rcvqpmcastctx1, RcvQpMcContext, 1 );
+	qib7322_writeq ( qib7322, &rcvqpmcastctx1,
+			 QIB_7322_RcvQPMulticastContext_1_offset );
+
+	/* Configure receive header buffer sizes */
+	memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) );
+	BIT_FILL_1 ( &rcvhdrcnt, Value, QIB7322_RECV_HEADER_COUNT );
+	qib7322_writeq ( qib7322, &rcvhdrcnt, QIB_7322_RcvHdrCnt_offset );
+	memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) );
+	BIT_FILL_1 ( &rcvhdrentsize, Value, ( QIB7322_RECV_HEADER_SIZE >> 2 ) );
+	qib7322_writeq ( qib7322, &rcvhdrentsize,
+			 QIB_7322_RcvHdrEntSize_offset );
+
+	/* Calculate eager array start addresses for each context */
+	qib7322_readq ( qib7322, &rcvegrbase, QIB_7322_RcvEgrBase_offset );
+	egrbase = BIT_GET ( &rcvegrbase, Value );
+	for ( ctx = 0 ; ctx < QIB7322_MAX_PORTS ; ctx++ ) {
+		qib7322->recv_wq[ctx].eager_array = egrbase;
+		qib7322->recv_wq[ctx].eager_entries = eager_array_size_kernel;
+		egrbase += ( eager_array_size_kernel *
+			     sizeof ( struct QIB_7322_RcvEgr ) );
+	}
+	for ( ; ctx < QIB7322_NUM_CONTEXTS ; ctx++ ) {
+		qib7322->recv_wq[ctx].eager_array = egrbase;
+		qib7322->recv_wq[ctx].eager_entries = eager_array_size_user;
+		egrbase += ( eager_array_size_user *
+			     sizeof ( struct QIB_7322_RcvEgr ) );
+	}
+	for ( ctx = 0 ; ctx < QIB7322_NUM_CONTEXTS ; ctx++ ) {
+		DBGC ( qib7322, "QIB7322 %p CTX %d eager array at %lx (%d "
+		       "entries)\n", qib7322, ctx,
+		       qib7322->recv_wq[ctx].eager_array,
+		       qib7322->recv_wq[ctx].eager_entries );
+	}
+
+	/* Set the BTH QP for Infinipath packets to an unused value */
+	memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) );
+	BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, QIB7322_QP_IDETH );
+	qib7322_writeq ( qib7322, &rcvbthqp, QIB_7322_RcvBTHQP_0_offset );
+	qib7322_writeq ( qib7322, &rcvbthqp, QIB_7322_RcvBTHQP_1_offset );
+
+	/* Assign initial credits */
+	memset ( &rxcreditvl, 0, sizeof ( rxcreditvl ) );
+	BIT_FILL_1 ( &rxcreditvl, RxMaxCreditVL, QIB7322_MAX_CREDITS_VL0 );
+	qib7322_writeq_array8b ( qib7322, &rxcreditvl,
+				 QIB_7322_RxCreditVL0_0_offset, 0 );
+	qib7322_writeq_array8b ( qib7322, &rxcreditvl,
+				 QIB_7322_RxCreditVL0_1_offset, 0 );
+	BIT_FILL_1 ( &rxcreditvl, RxMaxCreditVL, QIB7322_MAX_CREDITS_VL15 );
+	qib7322_writeq_array8b ( qib7322, &rxcreditvl,
+				 QIB_7322_RxCreditVL0_0_offset, 15 );
+	qib7322_writeq_array8b ( qib7322, &rxcreditvl,
+				 QIB_7322_RxCreditVL0_1_offset, 15 );
+
+	return 0;
+}
+
+/**
+ * Shut down receive datapath
+ *
+ * @v qib7322		QIB7322 device
+ */
+static void qib7322_fini_recv ( struct qib7322 *qib7322 __unused ) {
+	/* Nothing to do; all contexts were already disabled when the
+	 * queue pairs were destroyed
+	 */
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ * @ret rc		Return status code
+ */
+static int qib7322_create_cq ( struct ib_device *ibdev,
+			       struct ib_completion_queue *cq ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	static int cqn;
+
+	/* The hardware has no concept of completion queues.  We
+	 * simply use the association between CQs and WQs (already
+	 * handled by the IB core) to decide which WQs to poll.
+	 *
+	 * We do set a CQN, just to avoid confusing debug messages
+	 * from the IB core.
+	 */
+	cq->cqn = ++cqn;
+	DBGC ( qib7322, "QIB7322 %p CQN %ld created\n", qib7322, cq->cqn );
+
+	return 0;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void qib7322_destroy_cq ( struct ib_device *ibdev,
+				 struct ib_completion_queue *cq ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+
+	/* Nothing to do */
+	DBGC ( qib7322, "QIB7322 %p CQN %ld destroyed\n", qib7322, cq->cqn );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int qib7322_create_qp ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	unsigned int ctx;
+	int rc;
+
+	/* Allocate a context and QPN */
+	if ( ( rc = qib7322_alloc_ctx ( ibdev, qp ) ) != 0 )
+		goto err_alloc_ctx;
+	ctx = qib7322_ctx ( ibdev, qp );
+
+	/* Set work-queue private data pointers */
+	ib_wq_set_drvdata ( &qp->send, &qib7322->send_wq[ctx] );
+	ib_wq_set_drvdata ( &qp->recv, &qib7322->recv_wq[ctx] );
+
+	/* Create receive work queue */
+	if ( ( rc = qib7322_create_recv_wq ( ibdev, qp ) ) != 0 )
+		goto err_create_recv_wq;
+
+	/* Create send work queue */
+	if ( ( rc = qib7322_create_send_wq ( ibdev, qp ) ) != 0 )
+		goto err_create_send_wq;
+
+	return 0;
+
+	qib7322_destroy_send_wq ( ibdev, qp );
+ err_create_send_wq:
+	qib7322_destroy_recv_wq ( ibdev, qp );
+ err_create_recv_wq:
+	qib7322_free_ctx ( ibdev, qp );
+ err_alloc_ctx:
+	return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @ret rc		Return status code
+ */
+static int qib7322_modify_qp ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+
+	/* Nothing to do; the hardware doesn't have a notion of queue
+	 * keys
+	 */
+	DBGC2 ( qib7322, "QIB7322 %p QPN %ld modified\n", qib7322, qp->qpn );
+	return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void qib7322_destroy_qp ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp ) {
+
+	qib7322_destroy_send_wq ( ibdev, qp );
+	qib7322_destroy_recv_wq ( ibdev, qp );
+	qib7322_free_ctx ( ibdev, qp );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int qib7322_post_send ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp,
+			       struct ib_address_vector *av,
+			       struct io_buffer *iobuf ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct qib7322_send_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_SendPbc sendpbc;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+	uint8_t header_buf[IB_MAX_HEADER_SIZE];
+	struct io_buffer headers;
+	int send_buf;
+	unsigned long start_offset;
+	unsigned long offset;
+	size_t len;
+	ssize_t frag_len;
+	uint32_t *data;
+
+	/* Allocate send buffer and calculate offset */
+	send_buf = qib7322_alloc_send_buf ( qib7322, qib7322_wq->send_bufs );
+	if ( send_buf < 0 )
+		return send_buf;
+	start_offset = offset =
+		qib7322_send_buffer_offset ( qib7322, qib7322_wq->send_bufs,
+					     send_buf );
+
+	/* Store I/O buffer and send buffer index */
+	assert ( wq->iobufs[qib7322_wq->prod] == NULL );
+	wq->iobufs[qib7322_wq->prod] = iobuf;
+	qib7322_wq->used[qib7322_wq->prod] = send_buf;
+
+	/* Construct headers */
+	iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) );
+	iob_reserve ( &headers, sizeof ( header_buf ) );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+	/* Calculate packet length */
+	len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
+		  iob_len ( iobuf ) + 3 ) & ~3 );
+
+	/* Construct send per-buffer control word */
+	memset ( &sendpbc, 0, sizeof ( sendpbc ) );
+	BIT_FILL_3 ( &sendpbc,
+		     LengthP1_toibc, ( ( len >> 2 ) - 1 ),
+		     Port, port,
+		     VL15, ( ( qp->type == IB_QPT_SMI ) ? 1 : 0 ) );
+
+	/* Write SendPbc */
+	DBG_DISABLE ( DBGLVL_IO );
+	qib7322_writeq ( qib7322, &sendpbc, offset );
+	offset += sizeof ( sendpbc );
+
+	/* Write headers */
+	for ( data = headers.data, frag_len = iob_len ( &headers ) ;
+	      frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+		qib7322_writel ( qib7322, *data, offset );
+	}
+
+	/* Write data */
+	for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ;
+	      frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+		qib7322_writel ( qib7322, *data, offset );
+	}
+	DBG_ENABLE ( DBGLVL_IO );
+
+	assert ( ( start_offset + len ) == offset );
+	DBGC2 ( qib7322, "QIB7322 %p QPN %ld TX %04x(%04x) posted [%lx,%lx)\n",
+		qib7322, qp->qpn, send_buf, qib7322_wq->prod,
+		start_offset, offset );
+
+	/* Increment producer counter */
+	qib7322_wq->prod = ( ( qib7322_wq->prod + 1 ) & ( wq->num_wqes - 1 ) );
+
+	return 0;
+}
+
+/**
+ * Complete send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v wqe_idx		Work queue entry index
+ */
+static void qib7322_complete_send ( struct ib_device *ibdev,
+				    struct ib_queue_pair *qp,
+				    unsigned int wqe_idx ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct qib7322_send_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct io_buffer *iobuf;
+	unsigned int send_buf;
+
+	/* Parse completion */
+	send_buf = qib7322_wq->used[wqe_idx];
+	DBGC2 ( qib7322, "QIB7322 %p QPN %ld TX %04x(%04x) complete\n",
+		qib7322, qp->qpn, send_buf, wqe_idx );
+
+	/* Complete work queue entry */
+	iobuf = wq->iobufs[wqe_idx];
+	assert ( iobuf != NULL );
+	ib_complete_send ( ibdev, qp, iobuf, 0 );
+	wq->iobufs[wqe_idx] = NULL;
+
+	/* Free send buffer */
+	qib7322_free_send_buf ( qib7322, qib7322_wq->send_bufs, send_buf );
+}
+
+/**
+ * Poll send work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void qib7322_poll_send_wq ( struct ib_device *ibdev,
+				   struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->send;
+	struct qib7322_send_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	unsigned int send_buf;
+
+	/* Look for completions */
+	while ( wq->fill ) {
+
+		/* Check to see if send buffer has completed */
+		send_buf = qib7322_wq->used[qib7322_wq->cons];
+		if ( qib7322_send_buf_in_use ( qib7322, send_buf ) )
+			break;
+
+		/* Complete this buffer */
+		qib7322_complete_send ( ibdev, qp, qib7322_wq->cons );
+
+		/* Increment consumer counter */
+		qib7322_wq->cons = ( ( qib7322_wq->cons + 1 ) &
+				     ( wq->num_wqes - 1 ) );
+	}
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int qib7322_post_recv ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp,
+			       struct io_buffer *iobuf ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct qib7322_recv_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_RcvEgr rcvegr;
+	struct QIB_7322_scalar rcvegrindexhead;
+	unsigned int ctx = qib7322_ctx ( ibdev, qp );
+	physaddr_t addr;
+	size_t len;
+	unsigned int wqe_idx;
+	unsigned int bufsize;
+
+	/* Sanity checks */
+	addr = virt_to_bus ( iobuf->data );
+	len = iob_tailroom ( iobuf );
+	if ( addr & ( QIB7322_EAGER_BUFFER_ALIGN - 1 ) ) {
+		DBGC ( qib7322, "QIB7322 %p QPN %ld misaligned RX buffer "
+		       "(%08lx)\n", qib7322, qp->qpn, addr );
+		return -EINVAL;
+	}
+	if ( len != QIB7322_RECV_PAYLOAD_SIZE ) {
+		DBGC ( qib7322, "QIB7322 %p QPN %ld wrong RX buffer size "
+		       "(%zd)\n", qib7322, qp->qpn, len );
+		return -EINVAL;
+	}
+
+	/* Calculate eager producer index and WQE index */
+	wqe_idx = ( qib7322_wq->eager_prod & ( wq->num_wqes - 1 ) );
+	assert ( wq->iobufs[wqe_idx] == NULL );
+
+	/* Store I/O buffer */
+	wq->iobufs[wqe_idx] = iobuf;
+
+	/* Calculate buffer size */
+	switch ( QIB7322_RECV_PAYLOAD_SIZE ) {
+	case 2048:  bufsize = QIB7322_EAGER_BUFFER_2K;  break;
+	case 4096:  bufsize = QIB7322_EAGER_BUFFER_4K;  break;
+	case 8192:  bufsize = QIB7322_EAGER_BUFFER_8K;  break;
+	case 16384: bufsize = QIB7322_EAGER_BUFFER_16K; break;
+	case 32768: bufsize = QIB7322_EAGER_BUFFER_32K; break;
+	case 65536: bufsize = QIB7322_EAGER_BUFFER_64K; break;
+	default:    linker_assert ( 0, invalid_rx_payload_size );
+		    bufsize = QIB7322_EAGER_BUFFER_NONE;
+	}
+
+	/* Post eager buffer */
+	memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+	BIT_FILL_2 ( &rcvegr,
+		     Addr, ( addr >> 11 ),
+		     BufSize, bufsize );
+	qib7322_writeq_array8b ( qib7322, &rcvegr, qib7322_wq->eager_array,
+				 qib7322_wq->eager_prod );
+	DBGC2 ( qib7322, "QIB7322 %p QPN %ld RX egr %04x(%04x) posted "
+		"[%lx,%lx)\n", qib7322, qp->qpn, qib7322_wq->eager_prod,
+		wqe_idx, addr, ( addr + len ) );
+
+	/* Increment producer index */
+	qib7322_wq->eager_prod = ( ( qib7322_wq->eager_prod + 1 ) &
+				   ( qib7322_wq->eager_entries - 1 ) );
+
+	/* Update head index */
+	memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+	BIT_FILL_1 ( &rcvegrindexhead,
+		     Value, ( ( qib7322_wq->eager_prod + 1 ) &
+			      ( qib7322_wq->eager_entries - 1 ) ) );
+	qib7322_writeq_array64k ( qib7322, &rcvegrindexhead,
+				  QIB_7322_RcvEgrIndexHead0_offset, ctx );
+
+	return 0;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v header_offs	Header offset
+ */
+static void qib7322_complete_recv ( struct ib_device *ibdev,
+				    struct ib_queue_pair *qp,
+				    unsigned int header_offs ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct qib7322_recv_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_RcvHdrFlags *rcvhdrflags;
+	struct QIB_7322_RcvEgr rcvegr;
+	struct io_buffer headers;
+	struct io_buffer *iobuf;
+	struct ib_queue_pair *intended_qp;
+	struct ib_address_vector av;
+	unsigned int rcvtype;
+	unsigned int pktlen;
+	unsigned int egrindex;
+	unsigned int useegrbfr;
+	unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr;
+	unsigned int lenerr, parityerr, vcrcerr, icrcerr;
+	unsigned int err;
+	unsigned int hdrqoffset;
+	unsigned int header_len;
+	unsigned int padded_payload_len;
+	unsigned int wqe_idx;
+	size_t payload_len;
+	int qp0;
+	int rc;
+
+	/* RcvHdrFlags are at the end of the header entry */
+	rcvhdrflags = ( qib7322_wq->header + header_offs +
+			QIB7322_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) );
+	rcvtype = BIT_GET ( rcvhdrflags, RcvType );
+	pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 );
+	egrindex = BIT_GET ( rcvhdrflags, EgrIndex );
+	useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr );
+	hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 );
+	iberr = BIT_GET ( rcvhdrflags, IBErr );
+	mkerr = BIT_GET ( rcvhdrflags, MKErr );
+	tiderr = BIT_GET ( rcvhdrflags, TIDErr );
+	khdrerr = BIT_GET ( rcvhdrflags, KHdrErr );
+	mtuerr = BIT_GET ( rcvhdrflags, MTUErr );
+	lenerr = BIT_GET ( rcvhdrflags, LenErr );
+	parityerr = BIT_GET ( rcvhdrflags, ParityErr );
+	vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr );
+	icrcerr = BIT_GET ( rcvhdrflags, ICRCErr );
+	header_len = ( QIB7322_RECV_HEADER_SIZE - hdrqoffset -
+		       sizeof ( *rcvhdrflags ) );
+	padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ );
+	err = ( iberr | mkerr | tiderr | khdrerr | mtuerr |
+		lenerr | parityerr | vcrcerr | icrcerr );
+	/* IB header is placed immediately before RcvHdrFlags */
+	iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ),
+		       header_len, header_len );
+
+	/* Dump diagnostic information */
+	DBGC2 ( qib7322, "QIB7322 %p QPN %ld RX egr %04x%s hdr %d type %d len "
+		"%d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", qib7322, qp->qpn,
+		egrindex, ( useegrbfr ? "" : "(unused)" ),
+		( header_offs / QIB7322_RECV_HEADER_SIZE ),
+		rcvtype, pktlen, header_len, padded_payload_len,
+		( err ? " [Err" : "" ), ( iberr ? " IB" : "" ),
+		( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ),
+		( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ),
+		( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""),
+		( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ),
+		( err ? "]" : "" ) );
+	DBGCP_HDA ( qib7322, hdrqoffset, headers.data,
+		    ( header_len + sizeof ( *rcvhdrflags ) ) );
+
+	/* Parse header to generate address vector */
+	qp0 = ( qp->qpn == 0 );
+	intended_qp = NULL;
+	if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
+			      &payload_len, &av ) ) != 0 ) {
+		DBGC ( qib7322, "QIB7322 %p could not parse headers: %s\n",
+		       qib7322, strerror ( rc ) );
+		err = 1;
+	}
+	if ( ! intended_qp )
+		intended_qp = qp;
+
+	/* Complete this buffer and any skipped buffers.  Note that
+	 * when the hardware runs out of buffers, it will repeatedly
+	 * report the same buffer (the tail) as a TID error, and that
+	 * it also has a habit of sometimes skipping over several
+	 * buffers at once.
+	 */
+	while ( 1 ) {
+
+		/* If we have caught up to the producer counter, stop.
+		 * This will happen when the hardware first runs out
+		 * of buffers and starts reporting TID errors against
+		 * the eager buffer it wants to use next.
+		 */
+		if ( qib7322_wq->eager_cons == qib7322_wq->eager_prod )
+			break;
+
+		/* If we have caught up to where we should be after
+		 * completing this egrindex, stop.  We phrase the test
+		 * this way to avoid completing the entire ring when
+		 * we receive the same egrindex twice in a row.
+		 */
+		if ( ( qib7322_wq->eager_cons ==
+		       ( ( egrindex + 1 ) & ( qib7322_wq->eager_entries - 1 ))))
+			break;
+
+		/* Identify work queue entry and corresponding I/O
+		 * buffer.
+		 */
+		wqe_idx = ( qib7322_wq->eager_cons & ( wq->num_wqes - 1 ) );
+		iobuf = wq->iobufs[wqe_idx];
+		assert ( iobuf != NULL );
+		wq->iobufs[wqe_idx] = NULL;
+
+		/* Complete the eager buffer */
+		if ( qib7322_wq->eager_cons == egrindex ) {
+			/* Completing the eager buffer described in
+			 * this header entry.
+			 */
+			iob_put ( iobuf, payload_len );
+			rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) );
+			/* Redirect to target QP if necessary */
+			if ( qp != intended_qp ) {
+				DBGC2 ( qib7322, "QIB7322 %p redirecting QPN "
+					"%ld => %ld\n",
+					qib7322, qp->qpn, intended_qp->qpn );
+				/* Compensate for incorrect fill levels */
+				qp->recv.fill--;
+				intended_qp->recv.fill++;
+			}
+			ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+		} else {
+			/* Completing on a skipped-over eager buffer */
+			ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+		}
+
+		/* Clear eager buffer */
+		memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+		qib7322_writeq_array8b ( qib7322, &rcvegr,
+					 qib7322_wq->eager_array,
+					 qib7322_wq->eager_cons );
+
+		/* Increment consumer index */
+		qib7322_wq->eager_cons = ( ( qib7322_wq->eager_cons + 1 ) &
+					   ( qib7322_wq->eager_entries - 1 ) );
+	}
+}
+
+/**
+ * Poll receive work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+static void qib7322_poll_recv_wq ( struct ib_device *ibdev,
+				   struct ib_queue_pair *qp ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct ib_work_queue *wq = &qp->recv;
+	struct qib7322_recv_work_queue *qib7322_wq = ib_wq_get_drvdata ( wq );
+	struct QIB_7322_RcvHdrHead0 rcvhdrhead;
+	unsigned int ctx = qib7322_ctx ( ibdev, qp );
+	unsigned int header_prod;
+
+	/* Check for received packets */
+	header_prod = ( BIT_GET ( &qib7322_wq->header_prod, Value ) << 2 );
+	if ( header_prod == qib7322_wq->header_cons )
+		return;
+
+	/* Process all received packets */
+	while ( qib7322_wq->header_cons != header_prod ) {
+
+		/* Complete the receive */
+		qib7322_complete_recv ( ibdev, qp, qib7322_wq->header_cons );
+
+		/* Increment the consumer offset */
+		qib7322_wq->header_cons += QIB7322_RECV_HEADER_SIZE;
+		qib7322_wq->header_cons %= QIB7322_RECV_HEADERS_SIZE;
+
+		/* QIB7322 has only one send buffer per port for VL15,
+		 * which almost always leads to send buffer exhaustion
+		 * and dropped MADs.  Mitigate this by refusing to
+		 * process more than one VL15 MAD per poll, which will
+		 * enforce interleaved TX/RX polls.
+		 */
+		if ( qp->type == IB_QPT_SMI )
+			break;
+	}
+
+	/* Update consumer offset */
+	memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+	BIT_FILL_2 ( &rcvhdrhead,
+		     RcvHeadPointer, ( qib7322_wq->header_cons >> 2 ),
+		     counter, 1 );
+	qib7322_writeq_array64k ( qib7322, &rcvhdrhead,
+				  QIB_7322_RcvHdrHead0_offset, ctx );
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+static void qib7322_poll_cq ( struct ib_device *ibdev,
+			      struct ib_completion_queue *cq ) {
+	struct ib_work_queue *wq;
+
+	/* Poll associated send and receive queues */
+	list_for_each_entry ( wq, &cq->work_queues, list ) {
+		if ( wq->is_send ) {
+			qib7322_poll_send_wq ( ibdev, wq->qp );
+		} else {
+			qib7322_poll_recv_wq ( ibdev, wq->qp );
+		}
+	}
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev		Infiniband device
+ */
+static void qib7322_poll_eq ( struct ib_device *ibdev ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct QIB_7322_ErrStatus_0 errstatus;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+
+	/* Check for and clear status bits */
+	DBG_DISABLE ( DBGLVL_IO );
+	qib7322_readq_port ( qib7322, &errstatus,
+			     QIB_7322_ErrStatus_0_offset, port );
+	if ( errstatus.u.qwords[0] ) {
+		DBGC ( qib7322, "QIB7322 %p port %d status %08x%08x\n", qib7322,
+		       port, errstatus.u.dwords[1],  errstatus.u.dwords[0] );
+		qib7322_writeq_port ( qib7322, &errstatus,
+				      QIB_7322_ErrClear_0_offset, port );
+	}
+	DBG_ENABLE ( DBGLVL_IO );
+
+	/* Check for link status changes */
+	if ( BIT_GET ( &errstatus, IBStatusChanged ) )
+		qib7322_link_state_changed ( ibdev );
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Determine supported link speeds
+ *
+ * @v qib7322		QIB7322 device
+ * @ret supported	Supported link speeds
+ */
+static unsigned int qib7322_link_speed_supported ( struct qib7322 *qib7322,
+						   unsigned int port ) {
+	struct QIB_7322_feature_mask features;
+	struct QIB_7322_Revision revision;
+	unsigned int supported;
+	unsigned int boardid;
+
+	/* Read the active feature mask */
+	qib7322_readq ( qib7322, &features,
+			QIB_7322_active_feature_mask_offset );
+	switch ( port ) {
+	case 0 :
+		supported = BIT_GET ( &features, Port0_Link_Speed_Supported );
+		break;
+	case 1 :
+		supported = BIT_GET ( &features, Port1_Link_Speed_Supported );
+		break;
+	default:
+		DBGC ( qib7322, "QIB7322 %p port %d is invalid\n",
+		       qib7322, port );
+		supported = 0;
+		break;
+	}
+
+	/* Apply hacks for specific board IDs */
+	qib7322_readq ( qib7322, &revision, QIB_7322_Revision_offset );
+	boardid = BIT_GET ( &revision, BoardID );
+	switch ( boardid ) {
+	case QIB7322_BOARD_QMH7342 :
+		DBGC2 ( qib7322, "QIB7322 %p is a QMH7342; forcing QDR-only\n",
+			qib7322 );
+		supported = IB_LINK_SPEED_QDR;
+		break;
+	default:
+		/* Do nothing */
+		break;
+	}
+
+	DBGC2 ( qib7322, "QIB7322 %p port %d %s%s%s%s\n", qib7322, port,
+		( supported ? "supports" : "disabled" ),
+		( ( supported & IB_LINK_SPEED_SDR ) ? " SDR" : "" ),
+		( ( supported & IB_LINK_SPEED_DDR ) ? " DDR" : "" ),
+		( ( supported & IB_LINK_SPEED_QDR ) ? " QDR" : "" ) );
+	return supported;
+}
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int qib7322_open ( struct ib_device *ibdev ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct QIB_7322_IBCCtrlA_0 ibcctrla;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+
+	/* Enable link */
+	qib7322_readq_port ( qib7322, &ibcctrla,
+			     QIB_7322_IBCCtrlA_0_offset, port );
+	BIT_SET ( &ibcctrla, IBLinkEn, 1 );
+	qib7322_writeq_port ( qib7322, &ibcctrla,
+			      QIB_7322_IBCCtrlA_0_offset, port );
+
+	return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ */
+static void qib7322_close ( struct ib_device *ibdev ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+	struct QIB_7322_IBCCtrlA_0 ibcctrla;
+	unsigned int port = ( ibdev->port - QIB7322_PORT_BASE );
+
+	/* Disable link */
+	qib7322_readq_port ( qib7322, &ibcctrla,
+			     QIB_7322_IBCCtrlA_0_offset, port );
+	BIT_SET ( &ibcctrla, IBLinkEn, 0 );
+	qib7322_writeq_port ( qib7322, &ibcctrla,
+			      QIB_7322_IBCCtrlA_0_offset, port );
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ * @ret rc		Return status code
+ */
+static int qib7322_mcast_attach ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp,
+				  union ib_gid *gid ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+
+	( void ) qib7322;
+	( void ) qp;
+	( void ) gid;
+	return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void qib7322_mcast_detach ( struct ib_device *ibdev,
+				   struct ib_queue_pair *qp,
+				   union ib_gid *gid ) {
+	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
+
+	( void ) qib7322;
+	( void ) qp;
+	( void ) gid;
+ }
+
+/** QIB7322 Infiniband operations */
+static struct ib_device_operations qib7322_ib_operations = {
+	.create_cq	= qib7322_create_cq,
+	.destroy_cq	= qib7322_destroy_cq,
+	.create_qp	= qib7322_create_qp,
+	.modify_qp	= qib7322_modify_qp,
+	.destroy_qp	= qib7322_destroy_qp,
+	.post_send	= qib7322_post_send,
+	.post_recv	= qib7322_post_recv,
+	.poll_cq	= qib7322_poll_cq,
+	.poll_eq	= qib7322_poll_eq,
+	.open		= qib7322_open,
+	.close		= qib7322_close,
+	.mcast_attach	= qib7322_mcast_attach,
+	.mcast_detach	= qib7322_mcast_detach,
+	.set_port_info	= qib7322_set_port_info,
+	.set_pkey_table	= qib7322_set_pkey_table,
+};
+
+/***************************************************************************
+ *
+ * I2C bus operations
+ *
+ ***************************************************************************
+ */
+
+/** QIB7322 I2C bit to GPIO mappings */
+static unsigned int qib7322_i2c_bits[] = {
+	[I2C_BIT_SCL] = ( 1 << QIB7322_GPIO_SCL ),
+	[I2C_BIT_SDA] = ( 1 << QIB7322_GPIO_SDA ),
+};
+
+/**
+ * Read QIB7322 I2C line status
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @ret zero		Input is a logic 0
+ * @ret non-zero	Input is a logic 1
+ */
+static int qib7322_i2c_read_bit ( struct bit_basher *basher,
+				  unsigned int bit_id ) {
+	struct qib7322 *qib7322 =
+		container_of ( basher, struct qib7322, i2c.basher );
+	struct QIB_7322_EXTStatus extstatus;
+	unsigned int status;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	qib7322_readq ( qib7322, &extstatus, QIB_7322_EXTStatus_offset );
+	status = ( BIT_GET ( &extstatus, GPIOIn ) & qib7322_i2c_bits[bit_id] );
+
+	DBG_ENABLE ( DBGLVL_IO );
+
+	return status;
+}
+
+/**
+ * Write QIB7322 I2C line status
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @v data		Value to write
+ */
+static void qib7322_i2c_write_bit ( struct bit_basher *basher,
+				    unsigned int bit_id, unsigned long data ) {
+	struct qib7322 *qib7322 =
+		container_of ( basher, struct qib7322, i2c.basher );
+	struct QIB_7322_EXTCtrl extctrl;
+	struct QIB_7322_GPIO gpioout;
+	unsigned int bit = qib7322_i2c_bits[bit_id];
+	unsigned int outputs = 0;
+	unsigned int output_enables = 0;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	/* Read current GPIO mask and outputs */
+	qib7322_readq ( qib7322, &extctrl, QIB_7322_EXTCtrl_offset );
+	qib7322_readq ( qib7322, &gpioout, QIB_7322_GPIOOut_offset );
+
+	/* Update outputs and output enables.  I2C lines are tied
+	 * high, so we always set the output to 0 and use the output
+	 * enable to control the line.
+	 */
+	output_enables = BIT_GET ( &extctrl, GPIOOe );
+	output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) );
+	outputs = BIT_GET ( &gpioout, GPIO );
+	outputs = ( outputs & ~bit );
+	BIT_SET ( &extctrl, GPIOOe, output_enables );
+	BIT_SET ( &gpioout, GPIO, outputs );
+
+	/* Write the output enable first; that way we avoid logic
+	 * hazards.
+	 */
+	qib7322_writeq ( qib7322, &extctrl, QIB_7322_EXTCtrl_offset );
+	qib7322_writeq ( qib7322, &gpioout, QIB_7322_GPIOOut_offset );
+	mb();
+
+	DBG_ENABLE ( DBGLVL_IO );
+}
+
+/** QIB7322 I2C bit-bashing interface operations */
+static struct bit_basher_operations qib7322_i2c_basher_ops = {
+	.read	= qib7322_i2c_read_bit,
+	.write	= qib7322_i2c_write_bit,
+};
+
+/**
+ * Initialise QIB7322 I2C subsystem
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_init_i2c ( struct qib7322 *qib7322 ) {
+	static int try_eeprom_address[] = { 0x51, 0x50 };
+	unsigned int i;
+	int rc;
+
+	/* Initialise bus */
+	if ( ( rc = init_i2c_bit_basher ( &qib7322->i2c,
+					  &qib7322_i2c_basher_ops ) ) != 0 ) {
+		DBGC ( qib7322, "QIB7322 %p could not initialise I2C bus: %s\n",
+		       qib7322, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Probe for devices */
+	for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) /
+			    sizeof ( try_eeprom_address[0] ) ) ; i++ ) {
+		init_i2c_eeprom ( &qib7322->eeprom, try_eeprom_address[i] );
+		if ( ( rc = i2c_check_presence ( &qib7322->i2c.i2c,
+						 &qib7322->eeprom ) ) == 0 ) {
+			DBGC2 ( qib7322, "QIB7322 %p found EEPROM at %02x\n",
+				qib7322, try_eeprom_address[i] );
+			return 0;
+		}
+	}
+
+	DBGC ( qib7322, "QIB7322 %p could not find EEPROM\n", qib7322 );
+	return -ENODEV;
+}
+
+/**
+ * Read EEPROM parameters
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_read_eeprom ( struct qib7322 *qib7322 ) {
+	struct i2c_interface *i2c = &qib7322->i2c.i2c;
+	union ib_guid *guid = &qib7322->guid;
+	int rc;
+
+	/* Read GUID */
+	if ( ( rc = i2c->read ( i2c, &qib7322->eeprom,
+				QIB7322_EEPROM_GUID_OFFSET, guid->bytes,
+				sizeof ( *guid ) ) ) != 0 ) {
+		DBGC ( qib7322, "QIB7322 %p could not read GUID: %s\n",
+		       qib7322, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( qib7322, "QIB7322 %p has GUID " IB_GUID_FMT "\n",
+		qib7322, IB_GUID_ARGS ( guid ) );
+
+	/* Read serial number (debug only) */
+	if ( DBG_LOG ) {
+		uint8_t serial[QIB7322_EEPROM_SERIAL_SIZE + 1];
+
+		serial[ sizeof ( serial ) - 1 ] = '\0';
+		if ( ( rc = i2c->read ( i2c, &qib7322->eeprom,
+					QIB7322_EEPROM_SERIAL_OFFSET, serial,
+					( sizeof ( serial ) - 1 ) ) ) != 0 ) {
+			DBGC ( qib7322, "QIB7322 %p could not read serial: "
+			       "%s\n", qib7322, strerror ( rc ) );
+			return rc;
+		}
+		DBGC2 ( qib7322, "QIB7322 %p has serial number \"%s\"\n",
+			qib7322, serial );
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Advanced High-performance Bus (AHB) access
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Wait for AHB transaction to complete
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_ahb_wait ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_ahb_transaction_reg transaction;
+	unsigned int i;
+
+	/* Wait for Ready bit to be asserted */
+	for ( i = 0 ; i < QIB7322_AHB_MAX_WAIT_US ; i++ ) {
+		qib7322_readq ( qib7322, &transaction,
+				QIB_7322_ahb_transaction_reg_offset );
+		if ( BIT_GET ( &transaction, ahb_rdy ) )
+			return 0;
+		udelay ( 1 );
+	}
+
+	DBGC ( qib7322, "QIB7322 %p timed out waiting for AHB transaction\n",
+	       qib7322 );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Request ownership of the AHB
+ *
+ * @v qib7322		QIB7322 device
+ * @v location		AHB location
+ * @ret rc		Return status code
+ */
+static int qib7322_ahb_request ( struct qib7322 *qib7322,
+				 unsigned int location ) {
+	struct QIB_7322_ahb_access_ctrl access;
+	int rc;
+
+	/* Request ownership */
+	memset ( &access, 0, sizeof ( access ) );
+	BIT_FILL_2 ( &access,
+		     sw_ahb_sel, 1,
+		     sw_sel_ahb_trgt, QIB7322_AHB_LOC_TARGET ( location ) );
+	qib7322_writeq ( qib7322, &access, QIB_7322_ahb_access_ctrl_offset );
+
+	/* Wait for ownership to be granted */
+	if ( ( rc = qib7322_ahb_wait ( qib7322 ) ) != 0 )  {
+		DBGC ( qib7322, "QIB7322 %p could not obtain AHB ownership: "
+		       "%s\n", qib7322, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Release ownership of the AHB
+ *
+ * @v qib7322		QIB7322 device
+ */
+static void qib7322_ahb_release ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_ahb_access_ctrl access;
+
+	memset ( &access, 0, sizeof ( access ) );
+	qib7322_writeq ( qib7322, &access, QIB_7322_ahb_access_ctrl_offset );
+}
+
+/**
+ * Read data via AHB
+ *
+ * @v qib7322		QIB7322 device
+ * @v location		AHB location
+ * @v data		Data to read
+ * @ret rc		Return status code
+ *
+ * You must have already acquired ownership of the AHB.
+ */
+static int qib7322_ahb_read ( struct qib7322 *qib7322, unsigned int location,
+			      uint32_t *data ) {
+	struct QIB_7322_ahb_transaction_reg xact;
+	int rc;
+
+	/* Initiate transaction */
+	memset ( &xact, 0, sizeof ( xact ) );
+	BIT_FILL_2 ( &xact,
+		     ahb_address, QIB7322_AHB_LOC_ADDRESS ( location ),
+		     write_not_read, 0 );
+	qib7322_writeq ( qib7322, &xact, QIB_7322_ahb_transaction_reg_offset );
+
+	/* Wait for transaction to complete */
+	if ( ( rc = qib7322_ahb_wait ( qib7322 ) ) != 0 )
+		return rc;
+
+	/* Read transaction data */
+	qib7322_readq ( qib7322, &xact, QIB_7322_ahb_transaction_reg_offset );
+	*data = BIT_GET ( &xact, ahb_data );
+	return 0;
+}
+
+/**
+ * Write data via AHB
+ *
+ * @v qib7322		QIB7322 device
+ * @v location		AHB location
+ * @v data		Data to write
+ * @ret rc		Return status code
+ *
+ * You must have already acquired ownership of the AHB.
+ */
+static int qib7322_ahb_write ( struct qib7322 *qib7322, unsigned int location,
+			       uint32_t data ) {
+	struct QIB_7322_ahb_transaction_reg xact;
+	int rc;
+
+	/* Initiate transaction */
+	memset ( &xact, 0, sizeof ( xact ) );
+	BIT_FILL_3 ( &xact,
+		     ahb_address, QIB7322_AHB_LOC_ADDRESS ( location ),
+		     write_not_read, 1,
+		     ahb_data, data );
+	qib7322_writeq ( qib7322, &xact, QIB_7322_ahb_transaction_reg_offset );
+
+	/* Wait for transaction to complete */
+	if ( ( rc = qib7322_ahb_wait ( qib7322 ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Read/modify/write AHB register
+ *
+ * @v qib7322		QIB7322 device
+ * @v location		AHB location
+ * @v value		Value to set
+ * @v mask		Mask to apply to old value
+ * @ret rc		Return status code
+ */
+static int qib7322_ahb_mod_reg ( struct qib7322 *qib7322, unsigned int location,
+				 uint32_t value, uint32_t mask ) {
+	uint32_t old_value;
+	uint32_t new_value;
+	int rc;
+
+	DBG_DISABLE ( DBGLVL_IO );
+
+	/* Sanity check */
+	assert ( ( value & mask ) == value );
+
+	/* Acquire bus ownership */
+	if ( ( rc = qib7322_ahb_request ( qib7322, location ) ) != 0 )
+		goto out;
+
+	/* Read existing value */
+	if ( ( rc = qib7322_ahb_read ( qib7322, location, &old_value ) ) != 0 )
+		goto out_release;
+
+	/* Update value */
+	new_value = ( ( old_value & ~mask ) | value );
+	DBGCP ( qib7322, "QIB7322 %p AHB %x %#08x => %#08x\n",
+		qib7322, location, old_value, new_value );
+	if ( ( rc = qib7322_ahb_write ( qib7322, location, new_value ) ) != 0 )
+		goto out_release;
+
+ out_release:
+	/* Release bus */
+	qib7322_ahb_release ( qib7322 );
+ out:
+	DBG_ENABLE ( DBGLVL_IO );
+	return rc;
+}
+
+/**
+ * Read/modify/write AHB register across all ports and channels
+ *
+ * @v qib7322		QIB7322 device
+ * @v reg		AHB register
+ * @v value		Value to set
+ * @v mask		Mask to apply to old value
+ * @ret rc		Return status code
+ */
+static int qib7322_ahb_mod_reg_all ( struct qib7322 *qib7322, unsigned int reg,
+				     uint32_t value, uint32_t mask ) {
+	unsigned int port;
+	unsigned int channel;
+	unsigned int location;
+	int rc;
+
+	for ( port = 0 ; port < QIB7322_MAX_PORTS ; port++ ) {
+		for ( channel = 0 ; channel < QIB7322_MAX_WIDTH ; channel++ ) {
+			location = QIB7322_AHB_LOCATION ( port, channel, reg );
+			if ( ( rc = qib7322_ahb_mod_reg ( qib7322, location,
+							  value, mask ) ) != 0 )
+				return rc;
+		}
+	}
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Infiniband SerDes initialisation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise the IB SerDes
+ *
+ * @v qib7322		QIB7322 device
+ * @ret rc		Return status code
+ */
+static int qib7322_init_ib_serdes ( struct qib7322 *qib7322 ) {
+	struct QIB_7322_IBCCtrlA_0 ibcctrla;
+	struct QIB_7322_IBCCtrlB_0 ibcctrlb;
+	struct QIB_7322_IBPCSConfig_0 ibpcsconfig;
+
+	/* Configure sensible defaults for IBC */
+	memset ( &ibcctrla, 0, sizeof ( ibcctrla ) );
+	BIT_FILL_5 ( &ibcctrla, /* Tuning values taken from Linux driver */
+		     FlowCtrlPeriod, 0x03,
+		     FlowCtrlWaterMark, 0x05,
+		     MaxPktLen, ( ( QIB7322_RECV_HEADER_SIZE +
+				    QIB7322_RECV_PAYLOAD_SIZE +
+				    4 /* ICRC */ ) >> 2 ),
+		     PhyerrThreshold, 0xf,
+		     OverrunThreshold, 0xf );
+	qib7322_writeq ( qib7322, &ibcctrla, QIB_7322_IBCCtrlA_0_offset );
+	qib7322_writeq ( qib7322, &ibcctrla, QIB_7322_IBCCtrlA_1_offset );
+
+	/* Force SDR only to avoid needing all the DDR tuning,
+	 * Mellanox compatibility hacks etc.  SDR is plenty for
+	 * boot-time operation.
+	 */
+	qib7322_readq ( qib7322, &ibcctrlb, QIB_7322_IBCCtrlB_0_offset );
+	BIT_SET ( &ibcctrlb, IB_ENHANCED_MODE, 0 );
+	BIT_SET ( &ibcctrlb, SD_SPEED_SDR, 1 );
+	BIT_SET ( &ibcctrlb, SD_SPEED_DDR, 0 );
+	BIT_SET ( &ibcctrlb, SD_SPEED_QDR, 0 );
+	BIT_SET ( &ibcctrlb, IB_NUM_CHANNELS, 1 ); /* 4X only */
+	BIT_SET ( &ibcctrlb, IB_LANE_REV_SUPPORTED, 0 );
+	BIT_SET ( &ibcctrlb, HRTBT_ENB, 0 );
+	BIT_SET ( &ibcctrlb, HRTBT_AUTO, 0 );
+	qib7322_writeq ( qib7322, &ibcctrlb, QIB_7322_IBCCtrlB_0_offset );
+	qib7322_writeq ( qib7322, &ibcctrlb, QIB_7322_IBCCtrlB_1_offset );
+
+	/* Tune SerDes */
+	qib7322_ahb_mod_reg_all ( qib7322, 2, 0, 0x00000e00UL );
+
+	/* Bring XGXS out of reset */
+	memset ( &ibpcsconfig, 0, sizeof ( ibpcsconfig ) );
+	qib7322_writeq ( qib7322, &ibpcsconfig, QIB_7322_IBPCSConfig_0_offset );
+	qib7322_writeq ( qib7322, &ibpcsconfig, QIB_7322_IBPCSConfig_1_offset );
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * PCI layer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Reset QIB7322
+ *
+ * @v qib7322		QIB7322 device
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static void qib7322_reset ( struct qib7322 *qib7322, struct pci_device *pci ) {
+	struct QIB_7322_Control control;
+	struct pci_config_backup backup;
+
+	/* Back up PCI configuration space */
+	pci_backup ( pci, &backup, NULL );
+
+	/* Assert reset */
+	memset ( &control, 0, sizeof ( control ) );
+	BIT_FILL_1 ( &control, SyncReset, 1 );
+	qib7322_writeq ( qib7322, &control, QIB_7322_Control_offset );
+
+	/* Wait for reset to complete */
+	mdelay ( 1000 );
+
+	/* Restore PCI configuration space */
+	pci_restore ( pci, &backup, NULL );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int qib7322_probe ( struct pci_device *pci ) {
+	struct qib7322 *qib7322;
+	struct QIB_7322_Revision revision;
+	struct ib_device *ibdev;
+	unsigned int link_speed_supported;
+	int i;
+	int rc;
+
+	/* Allocate QIB7322 device */
+	qib7322 = zalloc ( sizeof ( *qib7322 ) );
+	if ( ! qib7322 ) {
+		rc = -ENOMEM;
+		goto err_alloc_qib7322;
+	}
+	pci_set_drvdata ( pci, qib7322 );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Get PCI BARs */
+	qib7322->regs = ioremap ( pci->membase, QIB7322_BAR0_SIZE );
+	DBGC2 ( qib7322, "QIB7322 %p has BAR at %08lx\n",
+		qib7322, pci->membase );
+
+	/* Reset device */
+	qib7322_reset ( qib7322, pci );
+
+	/* Print some general data */
+	qib7322_readq ( qib7322, &revision, QIB_7322_Revision_offset );
+	DBGC2 ( qib7322, "QIB7322 %p board %02lx v%ld.%ld.%ld.%ld\n", qib7322,
+		BIT_GET ( &revision, BoardID ),
+		BIT_GET ( &revision, R_SW ),
+		BIT_GET ( &revision, R_Arch ),
+		BIT_GET ( &revision, R_ChipRevMajor ),
+		BIT_GET ( &revision, R_ChipRevMinor ) );
+
+	/* Initialise I2C subsystem */
+	if ( ( rc = qib7322_init_i2c ( qib7322 ) ) != 0 )
+		goto err_init_i2c;
+
+	/* Read EEPROM parameters */
+	if ( ( rc = qib7322_read_eeprom ( qib7322 ) ) != 0 )
+		goto err_read_eeprom;
+
+	/* Initialise send datapath */
+	if ( ( rc = qib7322_init_send ( qib7322 ) ) != 0 )
+		goto err_init_send;
+
+	/* Initialise receive datapath */
+	if ( ( rc = qib7322_init_recv ( qib7322 ) ) != 0 )
+		goto err_init_recv;
+
+	/* Initialise the IB SerDes */
+	if ( ( rc = qib7322_init_ib_serdes ( qib7322 ) ) != 0 )
+		goto err_init_ib_serdes;
+
+	/* Allocate Infiniband devices */
+	for ( i = 0 ; i < QIB7322_MAX_PORTS ; i++ ) {
+		link_speed_supported =
+			qib7322_link_speed_supported ( qib7322, i );
+		if ( ! link_speed_supported )
+			continue;
+		ibdev = alloc_ibdev ( 0 );
+		if ( ! ibdev ) {
+			rc = -ENOMEM;
+			goto err_alloc_ibdev;
+		}
+		qib7322->ibdev[i] = ibdev;
+		ibdev->dev = &pci->dev;
+		ibdev->op = &qib7322_ib_operations;
+		ibdev->port = ( QIB7322_PORT_BASE + i );
+		ibdev->link_width_enabled = ibdev->link_width_supported =
+			IB_LINK_WIDTH_4X; /* 1x does not work */
+		ibdev->link_speed_enabled = ibdev->link_speed_supported =
+			IB_LINK_SPEED_SDR; /* to avoid need for link tuning */
+		memcpy ( &ibdev->node_guid, &qib7322->guid,
+			 sizeof ( ibdev->node_guid ) );
+		memcpy ( &ibdev->gid.s.guid, &qib7322->guid,
+			 sizeof ( ibdev->gid.s.guid ) );
+		assert ( ( ibdev->gid.s.guid.bytes[7] & i ) == 0 );
+		ibdev->gid.s.guid.bytes[7] |= i;
+		ib_set_drvdata ( ibdev, qib7322 );
+	}
+
+	/* Register Infiniband devices */
+	for ( i = 0 ; i < QIB7322_MAX_PORTS ; i++ ) {
+		if ( ! qib7322->ibdev[i] )
+			continue;
+		if ( ( rc = register_ibdev ( qib7322->ibdev[i] ) ) != 0 ) {
+			DBGC ( qib7322, "QIB7322 %p port %d could not register "
+			       "IB device: %s\n", qib7322, i, strerror ( rc ) );
+			goto err_register_ibdev;
+		}
+	}
+
+	return 0;
+
+	i = QIB7322_MAX_PORTS;
+ err_register_ibdev:
+	for ( i-- ; i >= 0 ; i-- ) {
+		if ( qib7322->ibdev[i] )
+			unregister_ibdev ( qib7322->ibdev[i] );
+	}
+	i = QIB7322_MAX_PORTS;
+ err_alloc_ibdev:
+	for ( i-- ; i >= 0 ; i-- )
+		ibdev_put ( qib7322->ibdev[i] );
+ err_init_ib_serdes:
+	qib7322_fini_send ( qib7322 );
+ err_init_send:
+	qib7322_fini_recv ( qib7322 );
+ err_init_recv:
+ err_read_eeprom:
+ err_init_i2c:
+	free ( qib7322 );
+ err_alloc_qib7322:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void qib7322_remove ( struct pci_device *pci ) {
+	struct qib7322 *qib7322 = pci_get_drvdata ( pci );
+	int i;
+
+	for ( i = ( QIB7322_MAX_PORTS - 1 ) ; i >= 0 ; i-- ) {
+		if ( qib7322->ibdev[i] )
+			unregister_ibdev ( qib7322->ibdev[i] );
+	}
+	for ( i = ( QIB7322_MAX_PORTS - 1 ) ; i >= 0 ; i-- )
+		ibdev_put ( qib7322->ibdev[i] );
+	qib7322_fini_send ( qib7322 );
+	qib7322_fini_recv ( qib7322 );
+	free ( qib7322 );
+}
+
+static struct pci_device_id qib7322_nics[] = {
+	PCI_ROM ( 0x1077, 0x7322, "iba7322", "IBA7322 QDR InfiniBand HCA", 0 ),
+};
+
+struct pci_driver qib7322_driver __pci_driver = {
+	.ids = qib7322_nics,
+	.id_count = ( sizeof ( qib7322_nics ) / sizeof ( qib7322_nics[0] ) ),
+	.probe = qib7322_probe,
+	.remove = qib7322_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.h
new file mode 100644
index 0000000..0dac09e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib7322.h
@@ -0,0 +1,364 @@
+#ifndef _QIB7322_H
+#define _QIB7322_H
+
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * QLogic QIB7322 Infiniband HCA
+ *
+ */
+
+#define BITOPS_LITTLE_ENDIAN
+#include <ipxe/bitops.h>
+#include "qib_7322_regs.h"
+
+/** A QIB7322 GPIO register */
+struct QIB_7322_GPIO_pb {
+	pseudo_bit_t GPIO[16];
+	pseudo_bit_t Reserved[48];
+};
+struct QIB_7322_GPIO {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_GPIO_pb );
+};
+
+/** A QIB7322 general scalar register */
+struct QIB_7322_scalar_pb {
+	pseudo_bit_t Value[64];
+};
+struct QIB_7322_scalar {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_scalar_pb );
+};
+
+/** QIB7322 feature mask */
+struct QIB_7322_feature_mask_pb {
+	pseudo_bit_t Port0_Link_Speed_Supported[3];
+	pseudo_bit_t Port1_Link_Speed_Supported[3];
+	pseudo_bit_t _unused_0[58];
+};
+struct QIB_7322_feature_mask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_feature_mask_pb );
+};
+
+/** QIB7322 send per-buffer control word */
+struct QIB_7322_SendPbc_pb {
+	pseudo_bit_t LengthP1_toibc[11];
+	pseudo_bit_t Reserved1[4];
+	pseudo_bit_t LengthP1_trigger[11];
+	pseudo_bit_t Reserved2[3];
+	pseudo_bit_t TestEbp[1];
+	pseudo_bit_t Test[1];
+	pseudo_bit_t Intr[1];
+	pseudo_bit_t StaticRateControlCnt[14];
+	pseudo_bit_t Reserved3[12];
+	pseudo_bit_t Port[1];
+	pseudo_bit_t VLane[3];
+	pseudo_bit_t Reserved4[1];
+	pseudo_bit_t VL15[1];
+};
+struct QIB_7322_SendPbc {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendPbc_pb );
+};
+
+/** QIB7322 send buffer availability */
+struct QIB_7322_SendBufAvail_pb {
+	pseudo_bit_t InUseCheck[162][2];
+	pseudo_bit_t Reserved[60];
+};
+struct QIB_7322_SendBufAvail {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufAvail_pb );
+};
+
+/** DMA alignment for send buffer availability */
+#define QIB7322_SENDBUFAVAIL_ALIGN 64
+
+/** QIB7322 port-specific receive control */
+struct QIB_7322_RcvCtrl_P_pb {
+	pseudo_bit_t ContextEnable[18];
+	pseudo_bit_t _unused_1[21];
+	pseudo_bit_t RcvIBPortEnable[1];
+	pseudo_bit_t RcvQPMapEnable[1];
+	pseudo_bit_t RcvPartitionKeyDisable[1];
+	pseudo_bit_t RcvResetCredit[1];
+	pseudo_bit_t _unused_2[21];
+};
+struct QIB_7322_RcvCtrl_P {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvCtrl_P_pb );
+};
+
+/** A QIB7322 eager receive descriptor */
+struct QIB_7322_RcvEgr_pb {
+	pseudo_bit_t Addr[37];
+	pseudo_bit_t BufSize[3];
+	pseudo_bit_t Reserved[24];
+};
+struct QIB_7322_RcvEgr {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvEgr_pb );
+};
+
+/** QIB7322 receive header flags */
+struct QIB_7322_RcvHdrFlags_pb {
+	pseudo_bit_t PktLen[11];
+	pseudo_bit_t RcvType[3];
+	pseudo_bit_t SoftB[1];
+	pseudo_bit_t SoftA[1];
+	pseudo_bit_t EgrIndex[12];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t UseEgrBfr[1];
+	pseudo_bit_t RcvSeq[4];
+	pseudo_bit_t HdrqOffset[11];
+	pseudo_bit_t Reserved2[8];
+	pseudo_bit_t IBErr[1];
+	pseudo_bit_t MKErr[1];
+	pseudo_bit_t TIDErr[1];
+	pseudo_bit_t KHdrErr[1];
+	pseudo_bit_t MTUErr[1];
+	pseudo_bit_t LenErr[1];
+	pseudo_bit_t ParityErr[1];
+	pseudo_bit_t VCRCErr[1];
+	pseudo_bit_t ICRCErr[1];
+};
+struct QIB_7322_RcvHdrFlags {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrFlags_pb );
+};
+
+/** QIB7322 DDS tuning parameters */
+struct QIB_7322_IBSD_DDS_MAP_TABLE_pb {
+	pseudo_bit_t Pre[3];
+	pseudo_bit_t PreXtra[2];
+	pseudo_bit_t Post[4];
+	pseudo_bit_t Main[5];
+	pseudo_bit_t Amp[4];
+	pseudo_bit_t _unused_0[46];
+};
+struct QIB_7322_IBSD_DDS_MAP_TABLE {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBSD_DDS_MAP_TABLE_pb );
+};
+
+/** QIB7322 memory BAR size */
+#define QIB7322_BAR0_SIZE 0x400000
+
+/** QIB7322 base port number */
+#define QIB7322_PORT_BASE 1
+
+/** QIB7322 maximum number of ports */
+#define QIB7322_MAX_PORTS 2
+
+/** QIB7322 maximum width */
+#define QIB7322_MAX_WIDTH 4
+
+/** QIB7322 board identifiers */
+enum qib7322_board_id {
+	QIB7322_BOARD_QLE7342_EMULATION = 0,
+	QIB7322_BOARD_QLE7340 = 1,
+	QIB7322_BOARD_QLE7342 = 2,
+	QIB7322_BOARD_QMI7342 = 3,
+	QIB7322_BOARD_QMH7342_UNSUPPORTED = 4,
+	QIB7322_BOARD_QME7342 = 5,
+	QIB7322_BOARD_QMH7342 = 6,
+	QIB7322_BOARD_QLE7342_TEST = 15,
+};
+
+/** QIB7322 I2C SCL line GPIO number */
+#define QIB7322_GPIO_SCL 0
+
+/** QIB7322 I2C SDA line GPIO number */
+#define QIB7322_GPIO_SDA 1
+
+/** GUID offset within EEPROM */
+#define QIB7322_EEPROM_GUID_OFFSET 3
+
+/** GUID size within EEPROM */
+#define QIB7322_EEPROM_GUID_SIZE 8
+
+/** Board serial number offset within EEPROM */
+#define QIB7322_EEPROM_SERIAL_OFFSET 12
+
+/** Board serial number size within EEPROM */
+#define QIB7322_EEPROM_SERIAL_SIZE 12
+
+/** QIB7322 small send buffer size */
+#define QIB7322_SMALL_SEND_BUF_SIZE 4096
+
+/** QIB7322 small send buffer starting index */
+#define QIB7322_SMALL_SEND_BUF_START 0
+
+/** QIB7322 small send buffer count */
+#define QIB7322_SMALL_SEND_BUF_COUNT 128
+
+/** QIB7322 large send buffer size */
+#define QIB7322_LARGE_SEND_BUF_SIZE 8192
+
+/** QIB7322 large send buffer starting index */
+#define QIB7322_LARGE_SEND_BUF_START 128
+
+/** QIB7322 large send buffer count */
+#define QIB7322_LARGE_SEND_BUF_COUNT 32
+
+/** QIB7322 VL15 port 0 send buffer starting index */
+#define QIB7322_VL15_PORT0_SEND_BUF_START 160
+
+/** QIB7322 VL15 port 0 send buffer count */
+#define QIB7322_VL15_PORT0_SEND_BUF_COUNT 1
+
+/** QIB7322 VL15 port 0 send buffer size */
+#define QIB7322_VL15_PORT0_SEND_BUF_SIZE 8192
+
+/** QIB7322 VL15 port 0 send buffer starting index */
+#define QIB7322_VL15_PORT1_SEND_BUF_START 161
+
+/** QIB7322 VL15 port 0 send buffer count */
+#define QIB7322_VL15_PORT1_SEND_BUF_COUNT 1
+
+/** QIB7322 VL15 port 0 send buffer size */
+#define QIB7322_VL15_PORT1_SEND_BUF_SIZE 8192
+
+/** Number of small send buffers used
+ *
+ * This is a policy decision.  Must be less than or equal to the total
+ * number of small send buffers supported by the hardware
+ * (QIB7322_SMALL_SEND_BUF_COUNT).
+ */
+#define QIB7322_SMALL_SEND_BUF_USED 32
+
+/** Number of contexts (including kernel context)
+ *
+ * This is a policy decision.  Must be 6, 10 or 18.
+ */
+#define QIB7322_NUM_CONTEXTS 6
+
+/** ContextCfg values for different numbers of contexts */
+enum qib7322_contextcfg {
+	QIB7322_CONTEXTCFG_6CTX = 0,
+	QIB7322_CONTEXTCFG_10CTX = 1,
+	QIB7322_CONTEXTCFG_18CTX = 2,
+};
+
+/** ContextCfg values for different numbers of contexts */
+#define QIB7322_EAGER_ARRAY_SIZE_6CTX_KERNEL 1024
+#define QIB7322_EAGER_ARRAY_SIZE_6CTX_USER 4096
+#define QIB7322_EAGER_ARRAY_SIZE_10CTX_KERNEL 1024
+#define QIB7322_EAGER_ARRAY_SIZE_10CTX_USER 2048
+#define QIB7322_EAGER_ARRAY_SIZE_18CTX_KERNEL 1024
+#define QIB7322_EAGER_ARRAY_SIZE_18CTX_USER 1024
+
+/** Eager buffer required alignment */
+#define QIB7322_EAGER_BUFFER_ALIGN 2048
+
+/** Eager buffer size encodings */
+enum qib7322_eager_buffer_size {
+	QIB7322_EAGER_BUFFER_NONE = 0,
+	QIB7322_EAGER_BUFFER_2K = 1,
+	QIB7322_EAGER_BUFFER_4K = 2,
+	QIB7322_EAGER_BUFFER_8K = 3,
+	QIB7322_EAGER_BUFFER_16K = 4,
+	QIB7322_EAGER_BUFFER_32K = 5,
+	QIB7322_EAGER_BUFFER_64K = 6,
+};
+
+/** Number of RX headers per context
+ *
+ * This is a policy decision.
+ */
+#define QIB7322_RECV_HEADER_COUNT 8
+
+/** Maximum size of each RX header
+ *
+ * This is a policy decision.  Must be divisible by 4.
+ */
+#define QIB7322_RECV_HEADER_SIZE 96
+
+/** Total size of an RX header ring */
+#define QIB7322_RECV_HEADERS_SIZE \
+	( QIB7322_RECV_HEADER_SIZE * QIB7322_RECV_HEADER_COUNT )
+
+/** RX header alignment */
+#define QIB7322_RECV_HEADERS_ALIGN 64
+
+/** RX payload size
+ *
+ * This is a policy decision.  Must be a valid eager buffer size.
+ */
+#define QIB7322_RECV_PAYLOAD_SIZE 2048
+
+/** Maximum number of credits per port
+ *
+ * 64kB of internal RX buffer space, in units of 64 bytes, split
+ * between two ports.
+ */
+#define QIB7322_MAX_CREDITS ( ( 65536 / 64 ) / QIB7322_MAX_PORTS )
+
+/** Number of credits to advertise for VL15
+ *
+ * This is a policy decision.  Using 9 credits allows for 9*64=576
+ * bytes, which is enough for two MADs.
+ */
+#define QIB7322_MAX_CREDITS_VL15 9
+
+/** Number of credits to advertise for VL0
+ *
+ * This is a policy decision.
+ */
+#define QIB7322_MAX_CREDITS_VL0 \
+	( QIB7322_MAX_CREDITS - QIB7322_MAX_CREDITS_VL15 )
+
+/** QPN used for Infinipath Packets
+ *
+ * This is a policy decision.  Must have bit 0 clear.  Must not be a
+ * QPN that we will use.
+ */
+#define QIB7322_QP_IDETH 0xdead0
+
+/** Maximum time for wait for AHB, in us */
+#define QIB7322_AHB_MAX_WAIT_US 500
+
+/** QIB7322 AHB locations */
+#define QIB7322_AHB_LOC_ADDRESS( _location ) ( (_location) & 0xffff )
+#define QIB7322_AHB_LOC_TARGET( _location ) ( (_location) >> 16 )
+#define QIB7322_AHB_CHAN_0 0
+#define QIB7322_AHB_CHAN_1 1
+#define QIB7322_AHB_PLL 2
+#define QIB7322_AHB_CHAN_2 3
+#define QIB7322_AHB_CHAN_3 4
+#define QIB7322_AHB_SUBSYS 5
+#define QIB7322_AHB_CHAN( _channel ) ( (_channel) + ( (_channel) >> 1 ) )
+#define QIB7322_AHB_TARGET_0 2
+#define QIB7322_AHB_TARGET_1 3
+#define QIB7322_AHB_TARGET( _port ) ( (_port) + 2 )
+#define QIB7322_AHB_LOCATION( _port, _channel, _register )	\
+	( ( QIB7322_AHB_TARGET(_port) << 16 ) |			\
+	  ( QIB7322_AHB_CHAN(_channel) << 7 ) |			\
+	  ( (_register) << 1 ) )
+
+/** QIB7322 link states */
+enum qib7322_link_state {
+	QIB7322_LINK_STATE_DOWN = 0,
+	QIB7322_LINK_STATE_INIT = 1,
+	QIB7322_LINK_STATE_ARM = 2,
+	QIB7322_LINK_STATE_ACTIVE = 3,
+	QIB7322_LINK_STATE_ACT_DEFER = 4,
+};
+
+/** Maximum time to wait for link state changes, in us */
+#define QIB7322_LINK_STATE_MAX_WAIT_US 20
+
+#endif /* _QIB7322_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7220_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7220_regs.h
new file mode 100644
index 0000000..0637ec8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7220_regs.h
@@ -0,0 +1,1762 @@
+/*
+ * Copyright (c) 2008, 2009 QLogic Corporation. All rights reserved.
+ *
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * 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.
+ *
+ */
+/* This file is mechanically generated from RTL. Any hand-edits will be lost! */
+
+/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#define QIB_7220_Revision_offset 0x00000000UL
+struct QIB_7220_Revision_pb {
+	pseudo_bit_t R_ChipRevMinor[8];
+	pseudo_bit_t R_ChipRevMajor[8];
+	pseudo_bit_t R_Arch[8];
+	pseudo_bit_t R_SW[8];
+	pseudo_bit_t BoardID[8];
+	pseudo_bit_t R_Emulation_Revcode[22];
+	pseudo_bit_t R_Emulation[1];
+	pseudo_bit_t R_Simulator[1];
+};
+struct QIB_7220_Revision {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_Revision_pb );
+};
+
+#define QIB_7220_Control_offset 0x00000008UL
+struct QIB_7220_Control_pb {
+	pseudo_bit_t SyncReset[1];
+	pseudo_bit_t FreezeMode[1];
+	pseudo_bit_t LinkEn[1];
+	pseudo_bit_t PCIERetryBufDiagEn[1];
+	pseudo_bit_t TxLatency[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t PCIECplQDiagEn[1];
+	pseudo_bit_t SyncResetExceptPcieIRAMRST[1];
+	pseudo_bit_t _unused_0[56];
+};
+struct QIB_7220_Control {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_Control_pb );
+};
+
+#define QIB_7220_PageAlign_offset 0x00000010UL
+
+#define QIB_7220_PortCnt_offset 0x00000018UL
+
+#define QIB_7220_DbgPortSel_offset 0x00000020UL
+struct QIB_7220_DbgPortSel_pb {
+	pseudo_bit_t NibbleSel0[4];
+	pseudo_bit_t NibbleSel1[4];
+	pseudo_bit_t NibbleSel2[4];
+	pseudo_bit_t NibbleSel3[4];
+	pseudo_bit_t NibbleSel4[4];
+	pseudo_bit_t NibbleSel5[4];
+	pseudo_bit_t NibbleSel6[4];
+	pseudo_bit_t NibbleSel7[4];
+	pseudo_bit_t SrcMuxSel[14];
+	pseudo_bit_t DbgClkPortSel[5];
+	pseudo_bit_t EnDbgPort[1];
+	pseudo_bit_t EnEnhancedDebugMode[1];
+	pseudo_bit_t EnhMode_SrcMuxSelIndex[10];
+	pseudo_bit_t EnhMode_SrcMuxSelWrEn[1];
+};
+struct QIB_7220_DbgPortSel {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_DbgPortSel_pb );
+};
+
+#define QIB_7220_DebugSigsIntSel_offset 0x00000028UL
+struct QIB_7220_DebugSigsIntSel_pb {
+	pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3];
+	pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3];
+	pseudo_bit_t debug_port_sel_pcs_sdout[1];
+	pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4];
+	pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[4];
+	pseudo_bit_t debug_port_sel_pcie_rx_tx[1];
+	pseudo_bit_t debug_port_sel_xgxs[4];
+	pseudo_bit_t debug_port_sel_epb_pcie[1];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7220_DebugSigsIntSel {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_DebugSigsIntSel_pb );
+};
+
+#define QIB_7220_SendRegBase_offset 0x00000030UL
+
+#define QIB_7220_UserRegBase_offset 0x00000038UL
+
+#define QIB_7220_CntrRegBase_offset 0x00000040UL
+
+#define QIB_7220_Scratch_offset 0x00000048UL
+
+#define QIB_7220_REG_000050_offset 0x00000050UL
+
+#define QIB_7220_IntBlocked_offset 0x00000060UL
+struct QIB_7220_IntBlocked_pb {
+	pseudo_bit_t RcvAvail0IntBlocked[1];
+	pseudo_bit_t RcvAvail1IntBlocked[1];
+	pseudo_bit_t RcvAvail2IntBlocked[1];
+	pseudo_bit_t RcvAvail3IntBlocked[1];
+	pseudo_bit_t RcvAvail4IntBlocked[1];
+	pseudo_bit_t RcvAvail5IntBlocked[1];
+	pseudo_bit_t RcvAvail6IntBlocked[1];
+	pseudo_bit_t RcvAvail7IntBlocked[1];
+	pseudo_bit_t RcvAvail8IntBlocked[1];
+	pseudo_bit_t RcvAvail9IntBlocked[1];
+	pseudo_bit_t RcvAvail10IntBlocked[1];
+	pseudo_bit_t RcvAvail11IntBlocked[1];
+	pseudo_bit_t RcvAvail12IntBlocked[1];
+	pseudo_bit_t RcvAvail13IntBlocked[1];
+	pseudo_bit_t RcvAvail14IntBlocked[1];
+	pseudo_bit_t RcvAvail15IntBlocked[1];
+	pseudo_bit_t RcvAvail16IntBlocked[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t JIntBlocked[1];
+	pseudo_bit_t IBSerdesTrimDoneIntBlocked[1];
+	pseudo_bit_t assertGPIOIntBlocked[1];
+	pseudo_bit_t PioBufAvailIntBlocked[1];
+	pseudo_bit_t PioSetIntBlocked[1];
+	pseudo_bit_t ErrorIntBlocked[1];
+	pseudo_bit_t RcvUrg0IntBlocked[1];
+	pseudo_bit_t RcvUrg1IntBlocked[1];
+	pseudo_bit_t RcvUrg2IntBlocked[1];
+	pseudo_bit_t RcvUrg3IntBlocked[1];
+	pseudo_bit_t RcvUrg4IntBlocked[1];
+	pseudo_bit_t RcvUrg5IntBlocked[1];
+	pseudo_bit_t RcvUrg6IntBlocked[1];
+	pseudo_bit_t RcvUrg7IntBlocked[1];
+	pseudo_bit_t RcvUrg8IntBlocked[1];
+	pseudo_bit_t RcvUrg9IntBlocked[1];
+	pseudo_bit_t RcvUrg10IntBlocked[1];
+	pseudo_bit_t RcvUrg11IntBlocked[1];
+	pseudo_bit_t RcvUrg12IntBlocked[1];
+	pseudo_bit_t RcvUrg13IntBlocked[1];
+	pseudo_bit_t RcvUrg14IntBlocked[1];
+	pseudo_bit_t RcvUrg15IntBlocked[1];
+	pseudo_bit_t RcvUrg16IntBlocked[1];
+	pseudo_bit_t Reserved[13];
+	pseudo_bit_t SDmaDisabledBlocked[1];
+	pseudo_bit_t SDmaIntBlocked[1];
+};
+struct QIB_7220_IntBlocked {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IntBlocked_pb );
+};
+
+#define QIB_7220_IntMask_offset 0x00000068UL
+struct QIB_7220_IntMask_pb {
+	pseudo_bit_t RcvAvail0IntMask[1];
+	pseudo_bit_t RcvAvail1IntMask[1];
+	pseudo_bit_t RcvAvail2IntMask[1];
+	pseudo_bit_t RcvAvail3IntMask[1];
+	pseudo_bit_t RcvAvail4IntMask[1];
+	pseudo_bit_t RcvAvail5IntMask[1];
+	pseudo_bit_t RcvAvail6IntMask[1];
+	pseudo_bit_t RcvAvail7IntMask[1];
+	pseudo_bit_t RcvAvail8IntMask[1];
+	pseudo_bit_t RcvAvail9IntMask[1];
+	pseudo_bit_t RcvAvail10IntMask[1];
+	pseudo_bit_t RcvAvail11IntMask[1];
+	pseudo_bit_t RcvAvail12IntMask[1];
+	pseudo_bit_t RcvAvail13IntMask[1];
+	pseudo_bit_t RcvAvail14IntMask[1];
+	pseudo_bit_t RcvAvail15IntMask[1];
+	pseudo_bit_t RcvAvail16IntMask[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t JIntMask[1];
+	pseudo_bit_t IBSerdesTrimDoneIntMask[1];
+	pseudo_bit_t assertGPIOIntMask[1];
+	pseudo_bit_t PioBufAvailIntMask[1];
+	pseudo_bit_t PioSetIntMask[1];
+	pseudo_bit_t ErrorIntMask[1];
+	pseudo_bit_t RcvUrg0IntMask[1];
+	pseudo_bit_t RcvUrg1IntMask[1];
+	pseudo_bit_t RcvUrg2IntMask[1];
+	pseudo_bit_t RcvUrg3IntMask[1];
+	pseudo_bit_t RcvUrg4IntMask[1];
+	pseudo_bit_t RcvUrg5IntMask[1];
+	pseudo_bit_t RcvUrg6IntMask[1];
+	pseudo_bit_t RcvUrg7IntMask[1];
+	pseudo_bit_t RcvUrg8IntMask[1];
+	pseudo_bit_t RcvUrg9IntMask[1];
+	pseudo_bit_t RcvUrg10IntMask[1];
+	pseudo_bit_t RcvUrg11IntMask[1];
+	pseudo_bit_t RcvUrg12IntMask[1];
+	pseudo_bit_t RcvUrg13IntMask[1];
+	pseudo_bit_t RcvUrg14IntMask[1];
+	pseudo_bit_t RcvUrg15IntMask[1];
+	pseudo_bit_t RcvUrg16IntMask[1];
+	pseudo_bit_t Reserved[13];
+	pseudo_bit_t SDmaDisabledMasked[1];
+	pseudo_bit_t SDmaIntMask[1];
+};
+struct QIB_7220_IntMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IntMask_pb );
+};
+
+#define QIB_7220_IntStatus_offset 0x00000070UL
+struct QIB_7220_IntStatus_pb {
+	pseudo_bit_t RcvAvail0[1];
+	pseudo_bit_t RcvAvail1[1];
+	pseudo_bit_t RcvAvail2[1];
+	pseudo_bit_t RcvAvail3[1];
+	pseudo_bit_t RcvAvail4[1];
+	pseudo_bit_t RcvAvail5[1];
+	pseudo_bit_t RcvAvail6[1];
+	pseudo_bit_t RcvAvail7[1];
+	pseudo_bit_t RcvAvail8[1];
+	pseudo_bit_t RcvAvail9[1];
+	pseudo_bit_t RcvAvail10[1];
+	pseudo_bit_t RcvAvail11[1];
+	pseudo_bit_t RcvAvail12[1];
+	pseudo_bit_t RcvAvail13[1];
+	pseudo_bit_t RcvAvail14[1];
+	pseudo_bit_t RcvAvail15[1];
+	pseudo_bit_t RcvAvail16[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t JInt[1];
+	pseudo_bit_t IBSerdesTrimDone[1];
+	pseudo_bit_t assertGPIO[1];
+	pseudo_bit_t PioBufAvail[1];
+	pseudo_bit_t PioSent[1];
+	pseudo_bit_t Error[1];
+	pseudo_bit_t RcvUrg0[1];
+	pseudo_bit_t RcvUrg1[1];
+	pseudo_bit_t RcvUrg2[1];
+	pseudo_bit_t RcvUrg3[1];
+	pseudo_bit_t RcvUrg4[1];
+	pseudo_bit_t RcvUrg5[1];
+	pseudo_bit_t RcvUrg6[1];
+	pseudo_bit_t RcvUrg7[1];
+	pseudo_bit_t RcvUrg8[1];
+	pseudo_bit_t RcvUrg9[1];
+	pseudo_bit_t RcvUrg10[1];
+	pseudo_bit_t RcvUrg11[1];
+	pseudo_bit_t RcvUrg12[1];
+	pseudo_bit_t RcvUrg13[1];
+	pseudo_bit_t RcvUrg14[1];
+	pseudo_bit_t RcvUrg15[1];
+	pseudo_bit_t RcvUrg16[1];
+	pseudo_bit_t Reserved[13];
+	pseudo_bit_t SDmaDisabled[1];
+	pseudo_bit_t SDmaInt[1];
+};
+struct QIB_7220_IntStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IntStatus_pb );
+};
+
+#define QIB_7220_IntClear_offset 0x00000078UL
+struct QIB_7220_IntClear_pb {
+	pseudo_bit_t RcvAvail0IntClear[1];
+	pseudo_bit_t RcvAvail1IntClear[1];
+	pseudo_bit_t RcvAvail2IntClear[1];
+	pseudo_bit_t RcvAvail3IntClear[1];
+	pseudo_bit_t RcvAvail4IntClear[1];
+	pseudo_bit_t RcvAvail5IntClear[1];
+	pseudo_bit_t RcvAvail6IntClear[1];
+	pseudo_bit_t RcvAvail7IntClear[1];
+	pseudo_bit_t RcvAvail8IntClear[1];
+	pseudo_bit_t RcvAvail9IntClear[1];
+	pseudo_bit_t RcvAvail10IntClear[1];
+	pseudo_bit_t RcvAvail11IntClear[1];
+	pseudo_bit_t RcvAvail12IntClear[1];
+	pseudo_bit_t RcvAvail13IntClear[1];
+	pseudo_bit_t RcvAvail14IntClear[1];
+	pseudo_bit_t RcvAvail15IntClear[1];
+	pseudo_bit_t RcvAvail16IntClear[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t JIntClear[1];
+	pseudo_bit_t IBSerdesTrimDoneClear[1];
+	pseudo_bit_t assertGPIOIntClear[1];
+	pseudo_bit_t PioBufAvailIntClear[1];
+	pseudo_bit_t PioSetIntClear[1];
+	pseudo_bit_t ErrorIntClear[1];
+	pseudo_bit_t RcvUrg0IntClear[1];
+	pseudo_bit_t RcvUrg1IntClear[1];
+	pseudo_bit_t RcvUrg2IntClear[1];
+	pseudo_bit_t RcvUrg3IntClear[1];
+	pseudo_bit_t RcvUrg4IntClear[1];
+	pseudo_bit_t RcvUrg5IntClear[1];
+	pseudo_bit_t RcvUrg6IntClear[1];
+	pseudo_bit_t RcvUrg7IntClear[1];
+	pseudo_bit_t RcvUrg8IntClear[1];
+	pseudo_bit_t RcvUrg9IntClear[1];
+	pseudo_bit_t RcvUrg10IntClear[1];
+	pseudo_bit_t RcvUrg11IntClear[1];
+	pseudo_bit_t RcvUrg12IntClear[1];
+	pseudo_bit_t RcvUrg13IntClear[1];
+	pseudo_bit_t RcvUrg14IntClear[1];
+	pseudo_bit_t RcvUrg15IntClear[1];
+	pseudo_bit_t RcvUrg16IntClear[1];
+	pseudo_bit_t Reserved[13];
+	pseudo_bit_t SDmaDisabledClear[1];
+	pseudo_bit_t SDmaIntClear[1];
+};
+struct QIB_7220_IntClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IntClear_pb );
+};
+
+#define QIB_7220_ErrMask_offset 0x00000080UL
+struct QIB_7220_ErrMask_pb {
+	pseudo_bit_t RcvFormatErrMask[1];
+	pseudo_bit_t RcvVCRCErrMask[1];
+	pseudo_bit_t RcvICRCErrMask[1];
+	pseudo_bit_t RcvMinPktLenErrMask[1];
+	pseudo_bit_t RcvMaxPktLenErrMask[1];
+	pseudo_bit_t RcvLongPktLenErrMask[1];
+	pseudo_bit_t RcvShortPktLenErrMask[1];
+	pseudo_bit_t RcvUnexpectedCharErrMask[1];
+	pseudo_bit_t RcvUnsupportedVLErrMask[1];
+	pseudo_bit_t RcvEBPErrMask[1];
+	pseudo_bit_t RcvIBFlowErrMask[1];
+	pseudo_bit_t RcvBadVersionErrMask[1];
+	pseudo_bit_t RcvEgrFullErrMask[1];
+	pseudo_bit_t RcvHdrFullErrMask[1];
+	pseudo_bit_t RcvBadTidErrMask[1];
+	pseudo_bit_t RcvHdrLenErrMask[1];
+	pseudo_bit_t RcvHdrErrMask[1];
+	pseudo_bit_t RcvIBLostLinkErrMask[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t SendSpecialTriggerErrMask[1];
+	pseudo_bit_t SDmaDisabledErrMask[1];
+	pseudo_bit_t SendMinPktLenErrMask[1];
+	pseudo_bit_t SendMaxPktLenErrMask[1];
+	pseudo_bit_t SendUnderRunErrMask[1];
+	pseudo_bit_t SendPktLenErrMask[1];
+	pseudo_bit_t SendDroppedSmpPktErrMask[1];
+	pseudo_bit_t SendDroppedDataPktErrMask[1];
+	pseudo_bit_t SendPioArmLaunchErrMask[1];
+	pseudo_bit_t SendUnexpectedPktNumErrMask[1];
+	pseudo_bit_t SendUnsupportedVLErrMask[1];
+	pseudo_bit_t SendBufMisuseErrMask[1];
+	pseudo_bit_t SDmaGenMismatchErrMask[1];
+	pseudo_bit_t SDmaOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaBaseErrMask[1];
+	pseudo_bit_t SDma1stDescErrMask[1];
+	pseudo_bit_t SDmaRpyTagErrMask[1];
+	pseudo_bit_t SDmaDwEnErrMask[1];
+	pseudo_bit_t SDmaMissingDwErrMask[1];
+	pseudo_bit_t SDmaUnexpDataErrMask[1];
+	pseudo_bit_t IBStatusChangedMask[1];
+	pseudo_bit_t InvalidAddrErrMask[1];
+	pseudo_bit_t ResetNegatedMask[1];
+	pseudo_bit_t HardwareErrMask[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrMask[1];
+	pseudo_bit_t InvalidEEPCmdMask[1];
+	pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrMask_pb );
+};
+
+#define QIB_7220_ErrStatus_offset 0x00000088UL
+struct QIB_7220_ErrStatus_pb {
+	pseudo_bit_t RcvFormatErr[1];
+	pseudo_bit_t RcvVCRCErr[1];
+	pseudo_bit_t RcvICRCErr[1];
+	pseudo_bit_t RcvMinPktLenErr[1];
+	pseudo_bit_t RcvMaxPktLenErr[1];
+	pseudo_bit_t RcvLongPktLenErr[1];
+	pseudo_bit_t RcvShortPktLenErr[1];
+	pseudo_bit_t RcvUnexpectedCharErr[1];
+	pseudo_bit_t RcvUnsupportedVLErr[1];
+	pseudo_bit_t RcvEBPErr[1];
+	pseudo_bit_t RcvIBFlowErr[1];
+	pseudo_bit_t RcvBadVersionErr[1];
+	pseudo_bit_t RcvEgrFullErr[1];
+	pseudo_bit_t RcvHdrFullErr[1];
+	pseudo_bit_t RcvBadTidErr[1];
+	pseudo_bit_t RcvHdrLenErr[1];
+	pseudo_bit_t RcvHdrErr[1];
+	pseudo_bit_t RcvIBLostLinkErr[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t SendSpecialTriggerErr[1];
+	pseudo_bit_t SDmaDisabledErr[1];
+	pseudo_bit_t SendMinPktLenErr[1];
+	pseudo_bit_t SendMaxPktLenErr[1];
+	pseudo_bit_t SendUnderRunErr[1];
+	pseudo_bit_t SendPktLenErr[1];
+	pseudo_bit_t SendDroppedSmpPktErr[1];
+	pseudo_bit_t SendDroppedDataPktErr[1];
+	pseudo_bit_t SendPioArmLaunchErr[1];
+	pseudo_bit_t SendUnexpectedPktNumErr[1];
+	pseudo_bit_t SendUnsupportedVLErr[1];
+	pseudo_bit_t SendBufMisuseErr[1];
+	pseudo_bit_t SDmaGenMismatchErr[1];
+	pseudo_bit_t SDmaOutOfBoundErr[1];
+	pseudo_bit_t SDmaTailOutOfBoundErr[1];
+	pseudo_bit_t SDmaBaseErr[1];
+	pseudo_bit_t SDma1stDescErr[1];
+	pseudo_bit_t SDmaRpyTagErr[1];
+	pseudo_bit_t SDmaDwEnErr[1];
+	pseudo_bit_t SDmaMissingDwErr[1];
+	pseudo_bit_t SDmaUnexpDataErr[1];
+	pseudo_bit_t IBStatusChanged[1];
+	pseudo_bit_t InvalidAddrErr[1];
+	pseudo_bit_t ResetNegated[1];
+	pseudo_bit_t HardwareErr[1];
+	pseudo_bit_t SDmaDescAddrMisalignErr[1];
+	pseudo_bit_t InvalidEEPCmdErr[1];
+	pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrStatus_pb );
+};
+
+#define QIB_7220_ErrClear_offset 0x00000090UL
+struct QIB_7220_ErrClear_pb {
+	pseudo_bit_t RcvFormatErrClear[1];
+	pseudo_bit_t RcvVCRCErrClear[1];
+	pseudo_bit_t RcvICRCErrClear[1];
+	pseudo_bit_t RcvMinPktLenErrClear[1];
+	pseudo_bit_t RcvMaxPktLenErrClear[1];
+	pseudo_bit_t RcvLongPktLenErrClear[1];
+	pseudo_bit_t RcvShortPktLenErrClear[1];
+	pseudo_bit_t RcvUnexpectedCharErrClear[1];
+	pseudo_bit_t RcvUnsupportedVLErrClear[1];
+	pseudo_bit_t RcvEBPErrClear[1];
+	pseudo_bit_t RcvIBFlowErrClear[1];
+	pseudo_bit_t RcvBadVersionErrClear[1];
+	pseudo_bit_t RcvEgrFullErrClear[1];
+	pseudo_bit_t RcvHdrFullErrClear[1];
+	pseudo_bit_t RcvBadTidErrClear[1];
+	pseudo_bit_t RcvHdrLenErrClear[1];
+	pseudo_bit_t RcvHdrErrClear[1];
+	pseudo_bit_t RcvIBLostLinkErrClear[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t SendSpecialTriggerErrClear[1];
+	pseudo_bit_t SDmaDisabledErrClear[1];
+	pseudo_bit_t SendMinPktLenErrClear[1];
+	pseudo_bit_t SendMaxPktLenErrClear[1];
+	pseudo_bit_t SendUnderRunErrClear[1];
+	pseudo_bit_t SendPktLenErrClear[1];
+	pseudo_bit_t SendDroppedSmpPktErrClear[1];
+	pseudo_bit_t SendDroppedDataPktErrClear[1];
+	pseudo_bit_t SendPioArmLaunchErrClear[1];
+	pseudo_bit_t SendUnexpectedPktNumErrClear[1];
+	pseudo_bit_t SendUnsupportedVLErrClear[1];
+	pseudo_bit_t SendBufMisuseErrClear[1];
+	pseudo_bit_t SDmaGenMismatchErrClear[1];
+	pseudo_bit_t SDmaOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaBaseErrClear[1];
+	pseudo_bit_t SDma1stDescErrClear[1];
+	pseudo_bit_t SDmaRpyTagErrClear[1];
+	pseudo_bit_t SDmaDwEnErrClear[1];
+	pseudo_bit_t SDmaMissingDwErrClear[1];
+	pseudo_bit_t SDmaUnexpDataErrClear[1];
+	pseudo_bit_t IBStatusChangedClear[1];
+	pseudo_bit_t InvalidAddrErrClear[1];
+	pseudo_bit_t ResetNegatedClear[1];
+	pseudo_bit_t HardwareErrClear[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrClear[1];
+	pseudo_bit_t InvalidEEPCmdErrClear[1];
+	pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrClear_pb );
+};
+
+#define QIB_7220_HwErrMask_offset 0x00000098UL
+struct QIB_7220_HwErrMask_pb {
+	pseudo_bit_t PCIeMemParityErrMask[8];
+	pseudo_bit_t Reserved3[20];
+	pseudo_bit_t SDmaMemReadErrMask[1];
+	pseudo_bit_t PoisonedTLPMask[1];
+	pseudo_bit_t PcieCplTimeoutMask[1];
+	pseudo_bit_t PCIeBusParityErrMask[3];
+	pseudo_bit_t Reserved2[2];
+	pseudo_bit_t PCIEOct0_uC_MemoryParityErrMask[1];
+	pseudo_bit_t PCIEOct1_uC_MemoryParityErrMask[1];
+	pseudo_bit_t IB_uC_MemoryParityErrMask[1];
+	pseudo_bit_t DDSRXEQMemoryParityErrMask[1];
+	pseudo_bit_t TXEMemParityErrMask[4];
+	pseudo_bit_t RXEMemParityErrMask[7];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t PowerOnBISTFailedMask[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t PCIESerdesQ0PClkNotDetectMask[1];
+	pseudo_bit_t PCIESerdesQ1PClkNotDetectMask[1];
+	pseudo_bit_t PCIESerdesQ2PClkNotDetectMask[1];
+	pseudo_bit_t PCIESerdesQ3PClkNotDetectMask[1];
+	pseudo_bit_t IBSerdesPClkNotDetectMask[1];
+	pseudo_bit_t Clk_uC_PLLNotLockedMask[1];
+	pseudo_bit_t IBCBusToSPCParityErrMask[1];
+	pseudo_bit_t IBCBusFromSPCParityErrMask[1];
+};
+struct QIB_7220_HwErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrMask_pb );
+};
+
+#define QIB_7220_HwErrStatus_offset 0x000000a0UL
+struct QIB_7220_HwErrStatus_pb {
+	pseudo_bit_t PCIeMemParity[8];
+	pseudo_bit_t Reserved3[20];
+	pseudo_bit_t SDmaMemReadErr[1];
+	pseudo_bit_t PoisenedTLP[1];
+	pseudo_bit_t PcieCplTimeout[1];
+	pseudo_bit_t PCIeBusParity[3];
+	pseudo_bit_t Reserved2[2];
+	pseudo_bit_t PCIE_uC_Oct0MemoryParityErr[1];
+	pseudo_bit_t PCIE_uC_Oct1MemoryParityErr[1];
+	pseudo_bit_t IB_uC_MemoryParityErr[1];
+	pseudo_bit_t DDSRXEQMemoryParityErr[1];
+	pseudo_bit_t TXEMemParity[4];
+	pseudo_bit_t RXEMemParity[7];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t PowerOnBISTFailed[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t PCIESerdesQ0PClkNotDetect[1];
+	pseudo_bit_t PCIESerdesQ1PClkNotDetect[1];
+	pseudo_bit_t PCIESerdesQ2PClkNotDetect[1];
+	pseudo_bit_t PCIESerdesQ3PClkNotDetect[1];
+	pseudo_bit_t IBSerdesPClkNotDetect[1];
+	pseudo_bit_t Clk_uC_PLLNotLocked[1];
+	pseudo_bit_t IBCBusToSPCParityErr[1];
+	pseudo_bit_t IBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrStatus_pb );
+};
+
+#define QIB_7220_HwErrClear_offset 0x000000a8UL
+struct QIB_7220_HwErrClear_pb {
+	pseudo_bit_t PCIeMemParityClr[8];
+	pseudo_bit_t Reserved3[20];
+	pseudo_bit_t SDmaMemReadErrClear[1];
+	pseudo_bit_t PoisonedTLPClear[1];
+	pseudo_bit_t PcieCplTimeoutClear[1];
+	pseudo_bit_t PCIeBusParityClr[3];
+	pseudo_bit_t Reserved2[2];
+	pseudo_bit_t PCIE_uC_Oct0MemoryParityErrClear[1];
+	pseudo_bit_t PCIE_uC_Oct1MemoryParityErrClear[1];
+	pseudo_bit_t IB_uC_MemoryParityErrClear[1];
+	pseudo_bit_t DDSRXEQMemoryParityErrClear[1];
+	pseudo_bit_t TXEMemParityClear[4];
+	pseudo_bit_t RXEMemParityClear[7];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t PowerOnBISTFailedClear[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t PCIESerdesQ0PClkNotDetectClear[1];
+	pseudo_bit_t PCIESerdesQ1PClkNotDetectClear[1];
+	pseudo_bit_t PCIESerdesQ2PClkNotDetectClear[1];
+	pseudo_bit_t PCIESerdesQ3PClkNotDetectClear[1];
+	pseudo_bit_t IBSerdesPClkNotDetectClear[1];
+	pseudo_bit_t Clk_uC_PLLNotLockedClear[1];
+	pseudo_bit_t IBCBusToSPCparityErrClear[1];
+	pseudo_bit_t IBCBusFromSPCParityErrClear[1];
+};
+struct QIB_7220_HwErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrClear_pb );
+};
+
+#define QIB_7220_HwDiagCtrl_offset 0x000000b0UL
+struct QIB_7220_HwDiagCtrl_pb {
+	pseudo_bit_t forcePCIeMemParity[8];
+	pseudo_bit_t Reserved2[23];
+	pseudo_bit_t forcePCIeBusParity[4];
+	pseudo_bit_t Reserved1[1];
+	pseudo_bit_t ForcePCIE_uC_Oct0MemoryParityErr[1];
+	pseudo_bit_t ForcePCIE_uC_Oct1MemoryParityErr[1];
+	pseudo_bit_t ForceIB_uC_MemoryParityErr[1];
+	pseudo_bit_t ForceDDSRXEQMemoryParityErr[1];
+	pseudo_bit_t ForceTxMemparityErr[4];
+	pseudo_bit_t ForceRxMemParityErr[7];
+	pseudo_bit_t Reserved[9];
+	pseudo_bit_t CounterDisable[1];
+	pseudo_bit_t CounterWrEnable[1];
+	pseudo_bit_t ForceIBCBusToSPCParityErr[1];
+	pseudo_bit_t ForceIBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwDiagCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_HwDiagCtrl_pb );
+};
+
+#define QIB_7220_REG_0000B8_offset 0x000000b8UL
+
+#define QIB_7220_IBCStatus_offset 0x000000c0UL
+struct QIB_7220_IBCStatus_pb {
+	pseudo_bit_t LinkTrainingState[5];
+	pseudo_bit_t LinkState[3];
+	pseudo_bit_t LinkSpeedActive[1];
+	pseudo_bit_t LinkWidthActive[1];
+	pseudo_bit_t DDS_RXEQ_FAIL[1];
+	pseudo_bit_t IB_SERDES_TRIM_DONE[1];
+	pseudo_bit_t IBRxLaneReversed[1];
+	pseudo_bit_t IBTxLaneReversed[1];
+	pseudo_bit_t Reserved[16];
+	pseudo_bit_t TxReady[1];
+	pseudo_bit_t TxCreditOk[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_IBCStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCStatus_pb );
+};
+
+#define QIB_7220_IBCCtrl_offset 0x000000c8UL
+struct QIB_7220_IBCCtrl_pb {
+	pseudo_bit_t FlowCtrlPeriod[8];
+	pseudo_bit_t FlowCtrlWaterMark[8];
+	pseudo_bit_t LinkInitCmd[3];
+	pseudo_bit_t LinkCmd[2];
+	pseudo_bit_t MaxPktLen[11];
+	pseudo_bit_t PhyerrThreshold[4];
+	pseudo_bit_t OverrunThreshold[4];
+	pseudo_bit_t CreditScale[3];
+	pseudo_bit_t Reserved[19];
+	pseudo_bit_t LinkDownDefaultState[1];
+	pseudo_bit_t Loopback[1];
+};
+struct QIB_7220_IBCCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCCtrl_pb );
+};
+
+#define QIB_7220_EXTStatus_offset 0x000000d0UL
+struct QIB_7220_EXTStatus_pb {
+	pseudo_bit_t Reserved2[14];
+	pseudo_bit_t MemBISTEndTest[1];
+	pseudo_bit_t MemBISTDisabled[1];
+	pseudo_bit_t Reserved1[16];
+	pseudo_bit_t Reserved[16];
+	pseudo_bit_t GPIOIn[16];
+};
+struct QIB_7220_EXTStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTStatus_pb );
+};
+
+#define QIB_7220_EXTCtrl_offset 0x000000d8UL
+struct QIB_7220_EXTCtrl_pb {
+	pseudo_bit_t LEDGblErrRedOff[1];
+	pseudo_bit_t LEDGblOkGreenOn[1];
+	pseudo_bit_t LEDPriPortYellowOn[1];
+	pseudo_bit_t LEDPriPortGreenOn[1];
+	pseudo_bit_t Reserved[28];
+	pseudo_bit_t GPIOInvert[16];
+	pseudo_bit_t GPIOOe[16];
+};
+struct QIB_7220_EXTCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTCtrl_pb );
+};
+
+#define QIB_7220_GPIOOut_offset 0x000000e0UL
+
+#define QIB_7220_GPIOMask_offset 0x000000e8UL
+
+#define QIB_7220_GPIOStatus_offset 0x000000f0UL
+
+#define QIB_7220_GPIOClear_offset 0x000000f8UL
+
+#define QIB_7220_RcvCtrl_offset 0x00000100UL
+struct QIB_7220_RcvCtrl_pb {
+	pseudo_bit_t PortEnable[17];
+	pseudo_bit_t IntrAvail[17];
+	pseudo_bit_t RcvPartitionKeyDisable[1];
+	pseudo_bit_t TailUpd[1];
+	pseudo_bit_t PortCfg[2];
+	pseudo_bit_t RcvQPMapEnable[1];
+	pseudo_bit_t Reserved[25];
+};
+struct QIB_7220_RcvCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvCtrl_pb );
+};
+
+#define QIB_7220_RcvBTHQP_offset 0x00000108UL
+struct QIB_7220_RcvBTHQP_pb {
+	pseudo_bit_t RcvBTHQP[24];
+	pseudo_bit_t Reserved[8];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_RcvBTHQP {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvBTHQP_pb );
+};
+
+#define QIB_7220_RcvHdrSize_offset 0x00000110UL
+
+#define QIB_7220_RcvHdrCnt_offset 0x00000118UL
+
+#define QIB_7220_RcvHdrEntSize_offset 0x00000120UL
+
+#define QIB_7220_RcvTIDBase_offset 0x00000128UL
+
+#define QIB_7220_RcvTIDCnt_offset 0x00000130UL
+
+#define QIB_7220_RcvEgrBase_offset 0x00000138UL
+
+#define QIB_7220_RcvEgrCnt_offset 0x00000140UL
+
+#define QIB_7220_RcvBufBase_offset 0x00000148UL
+
+#define QIB_7220_RcvBufSize_offset 0x00000150UL
+
+#define QIB_7220_RxIntMemBase_offset 0x00000158UL
+
+#define QIB_7220_RxIntMemSize_offset 0x00000160UL
+
+#define QIB_7220_RcvPartitionKey_offset 0x00000168UL
+
+#define QIB_7220_RcvQPMulticastPort_offset 0x00000170UL
+struct QIB_7220_RcvQPMulticastPort_pb {
+	pseudo_bit_t RcvQpMcPort[5];
+	pseudo_bit_t Reserved[59];
+};
+struct QIB_7220_RcvQPMulticastPort {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvQPMulticastPort_pb );
+};
+
+#define QIB_7220_RcvPktLEDCnt_offset 0x00000178UL
+struct QIB_7220_RcvPktLEDCnt_pb {
+	pseudo_bit_t OFFperiod[32];
+	pseudo_bit_t ONperiod[32];
+};
+struct QIB_7220_RcvPktLEDCnt {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvPktLEDCnt_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl_offset 0x00000180UL
+struct QIB_7220_IBCDDRCtrl_pb {
+	pseudo_bit_t IB_ENHANCED_MODE[1];
+	pseudo_bit_t SD_SPEED[1];
+	pseudo_bit_t SD_SPEED_SDR[1];
+	pseudo_bit_t SD_SPEED_DDR[1];
+	pseudo_bit_t SD_SPEED_QDR[1];
+	pseudo_bit_t IB_NUM_CHANNELS[2];
+	pseudo_bit_t IB_POLARITY_REV_SUPP[1];
+	pseudo_bit_t IB_LANE_REV_SUPPORTED[1];
+	pseudo_bit_t SD_RX_EQUAL_ENABLE[1];
+	pseudo_bit_t SD_ADD_ENB[1];
+	pseudo_bit_t SD_DDSV[1];
+	pseudo_bit_t SD_DDS[4];
+	pseudo_bit_t HRTBT_ENB[1];
+	pseudo_bit_t HRTBT_AUTO[1];
+	pseudo_bit_t HRTBT_PORT[8];
+	pseudo_bit_t HRTBT_REQ[1];
+	pseudo_bit_t Reserved[5];
+	pseudo_bit_t IB_DLID[16];
+	pseudo_bit_t IB_DLID_MASK[16];
+};
+struct QIB_7220_IBCDDRCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl_pb );
+};
+
+#define QIB_7220_HRTBT_GUID_offset 0x00000188UL
+
+#define QIB_7220_IB_SDTEST_IF_TX_offset 0x00000190UL
+struct QIB_7220_IB_SDTEST_IF_TX_pb {
+	pseudo_bit_t TS_T_TX_VALID[1];
+	pseudo_bit_t TS_3_TX_VALID[1];
+	pseudo_bit_t Reserved1[9];
+	pseudo_bit_t TS_TX_OPCODE[2];
+	pseudo_bit_t TS_TX_SPEED[3];
+	pseudo_bit_t Reserved[16];
+	pseudo_bit_t TS_TX_TX_CFG[16];
+	pseudo_bit_t TS_TX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_TX {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_TX_pb );
+};
+
+#define QIB_7220_IB_SDTEST_IF_RX_offset 0x00000198UL
+struct QIB_7220_IB_SDTEST_IF_RX_pb {
+	pseudo_bit_t TS_T_RX_VALID[1];
+	pseudo_bit_t TS_3_RX_VALID[1];
+	pseudo_bit_t Reserved[14];
+	pseudo_bit_t TS_RX_A[8];
+	pseudo_bit_t TS_RX_B[8];
+	pseudo_bit_t TS_RX_TX_CFG[16];
+	pseudo_bit_t TS_RX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_RX {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_RX_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl2_offset 0x000001a0UL
+struct QIB_7220_IBCDDRCtrl2_pb {
+	pseudo_bit_t IB_FRONT_PORCH[5];
+	pseudo_bit_t IB_BACK_PORCH[5];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_IBCDDRCtrl2 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl2_pb );
+};
+
+#define QIB_7220_IBCDDRStatus_offset 0x000001a8UL
+struct QIB_7220_IBCDDRStatus_pb {
+	pseudo_bit_t LinkRoundTripLatency[26];
+	pseudo_bit_t ReqDDSLocalFromRmt[4];
+	pseudo_bit_t RxEqLocalDevice[2];
+	pseudo_bit_t heartbeat_crosstalk[4];
+	pseudo_bit_t heartbeat_timed_out[1];
+	pseudo_bit_t _unused_0[27];
+};
+struct QIB_7220_IBCDDRStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRStatus_pb );
+};
+
+#define QIB_7220_JIntReload_offset 0x000001b0UL
+struct QIB_7220_JIntReload_pb {
+	pseudo_bit_t J_reload[16];
+	pseudo_bit_t J_limit_reload[16];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_JIntReload {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_JIntReload_pb );
+};
+
+#define QIB_7220_IBNCModeCtrl_offset 0x000001b8UL
+struct QIB_7220_IBNCModeCtrl_pb {
+	pseudo_bit_t TSMEnable_send_TS1[1];
+	pseudo_bit_t TSMEnable_send_TS2[1];
+	pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1];
+	pseudo_bit_t Reserved1[5];
+	pseudo_bit_t TSMCode_TS1[9];
+	pseudo_bit_t TSMCode_TS2[9];
+	pseudo_bit_t Reserved[38];
+};
+struct QIB_7220_IBNCModeCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBNCModeCtrl_pb );
+};
+
+#define QIB_7220_SendCtrl_offset 0x000001c0UL
+struct QIB_7220_SendCtrl_pb {
+	pseudo_bit_t Abort[1];
+	pseudo_bit_t SendIntBufAvail[1];
+	pseudo_bit_t SendBufAvailUpd[1];
+	pseudo_bit_t SPioEnable[1];
+	pseudo_bit_t SSpecialTriggerEn[1];
+	pseudo_bit_t Reserved2[4];
+	pseudo_bit_t SDmaIntEnable[1];
+	pseudo_bit_t SDmaSingleDescriptor[1];
+	pseudo_bit_t SDmaEnable[1];
+	pseudo_bit_t SDmaHalt[1];
+	pseudo_bit_t Reserved1[3];
+	pseudo_bit_t DisarmPIOBuf[8];
+	pseudo_bit_t AvailUpdThld[5];
+	pseudo_bit_t Reserved[2];
+	pseudo_bit_t Disarm[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_SendCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendCtrl_pb );
+};
+
+#define QIB_7220_SendBufBase_offset 0x000001c8UL
+struct QIB_7220_SendBufBase_pb {
+	pseudo_bit_t BaseAddr_SmallPIO[21];
+	pseudo_bit_t Reserved1[11];
+	pseudo_bit_t BaseAddr_LargePIO[21];
+	pseudo_bit_t Reserved[11];
+};
+struct QIB_7220_SendBufBase {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufBase_pb );
+};
+
+#define QIB_7220_SendBufSize_offset 0x000001d0UL
+struct QIB_7220_SendBufSize_pb {
+	pseudo_bit_t Size_SmallPIO[12];
+	pseudo_bit_t Reserved1[20];
+	pseudo_bit_t Size_LargePIO[13];
+	pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_SendBufSize {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufSize_pb );
+};
+
+#define QIB_7220_SendBufCnt_offset 0x000001d8UL
+struct QIB_7220_SendBufCnt_pb {
+	pseudo_bit_t Num_SmallBuffers[9];
+	pseudo_bit_t Reserved1[23];
+	pseudo_bit_t Num_LargeBuffers[4];
+	pseudo_bit_t Reserved[28];
+};
+struct QIB_7220_SendBufCnt {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufCnt_pb );
+};
+
+#define QIB_7220_SendBufAvailAddr_offset 0x000001e0UL
+struct QIB_7220_SendBufAvailAddr_pb {
+	pseudo_bit_t Reserved[6];
+	pseudo_bit_t SendBufAvailAddr[34];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_SendBufAvailAddr {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvailAddr_pb );
+};
+
+#define QIB_7220_TxIntMemBase_offset 0x000001e8UL
+
+#define QIB_7220_TxIntMemSize_offset 0x000001f0UL
+
+#define QIB_7220_SendDmaBase_offset 0x000001f8UL
+struct QIB_7220_SendDmaBase_pb {
+	pseudo_bit_t SendDmaBase[48];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaBase {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBase_pb );
+};
+
+#define QIB_7220_SendDmaLenGen_offset 0x00000200UL
+struct QIB_7220_SendDmaLenGen_pb {
+	pseudo_bit_t Length[16];
+	pseudo_bit_t Generation[3];
+	pseudo_bit_t Reserved[45];
+};
+struct QIB_7220_SendDmaLenGen {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaLenGen_pb );
+};
+
+#define QIB_7220_SendDmaTail_offset 0x00000208UL
+struct QIB_7220_SendDmaTail_pb {
+	pseudo_bit_t SendDmaTail[16];
+	pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_SendDmaTail {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaTail_pb );
+};
+
+#define QIB_7220_SendDmaHead_offset 0x00000210UL
+struct QIB_7220_SendDmaHead_pb {
+	pseudo_bit_t SendDmaHead[16];
+	pseudo_bit_t Reserved1[16];
+	pseudo_bit_t InternalSendDmaHead[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHead {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHead_pb );
+};
+
+#define QIB_7220_SendDmaHeadAddr_offset 0x00000218UL
+struct QIB_7220_SendDmaHeadAddr_pb {
+	pseudo_bit_t SendDmaHeadAddr[48];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHeadAddr {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHeadAddr_pb );
+};
+
+#define QIB_7220_SendDmaBufMask0_offset 0x00000220UL
+struct QIB_7220_SendDmaBufMask0_pb {
+	pseudo_bit_t BufMask_63_0[0];
+	pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufMask0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufMask0_pb );
+};
+
+#define QIB_7220_SendDmaStatus_offset 0x00000238UL
+struct QIB_7220_SendDmaStatus_pb {
+	pseudo_bit_t SplFifoDescIndex[16];
+	pseudo_bit_t SplFifoBufNum[8];
+	pseudo_bit_t SplFifoFull[1];
+	pseudo_bit_t SplFifoEmpty[1];
+	pseudo_bit_t SplFifoDisarmed[1];
+	pseudo_bit_t SplFifoReadyToGo[1];
+	pseudo_bit_t ScbFetchDescFlag[1];
+	pseudo_bit_t ScbEntryValid[1];
+	pseudo_bit_t ScbEmpty[1];
+	pseudo_bit_t ScbFull[1];
+	pseudo_bit_t RpyTag_7_0[8];
+	pseudo_bit_t RpyLowAddr_6_0[7];
+	pseudo_bit_t ScbDescIndex_13_0[14];
+	pseudo_bit_t InternalSDmaEnable[1];
+	pseudo_bit_t AbortInProg[1];
+	pseudo_bit_t ScoreBoardDrainInProg[1];
+};
+struct QIB_7220_SendDmaStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaStatus_pb );
+};
+
+#define QIB_7220_SendBufErr0_offset 0x00000240UL
+struct QIB_7220_SendBufErr0_pb {
+	pseudo_bit_t SendBufErr_63_0[0];
+	pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufErr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufErr0_pb );
+};
+
+#define QIB_7220_REG_000258_offset 0x00000258UL
+
+#define QIB_7220_AvailUpdCount_offset 0x00000268UL
+struct QIB_7220_AvailUpdCount_pb {
+	pseudo_bit_t AvailUpdCount[5];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7220_AvailUpdCount {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_AvailUpdCount_pb );
+};
+
+#define QIB_7220_RcvHdrAddr0_offset 0x00000270UL
+struct QIB_7220_RcvHdrAddr0_pb {
+	pseudo_bit_t Reserved[2];
+	pseudo_bit_t RcvHdrAddr0[38];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrAddr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrAddr0_pb );
+};
+
+#define QIB_7220_REG_0002F8_offset 0x000002f8UL
+
+#define QIB_7220_RcvHdrTailAddr0_offset 0x00000300UL
+struct QIB_7220_RcvHdrTailAddr0_pb {
+	pseudo_bit_t Reserved[2];
+	pseudo_bit_t RcvHdrTailAddr0[38];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrTailAddr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrTailAddr0_pb );
+};
+
+#define QIB_7220_REG_000388_offset 0x00000388UL
+
+#define QIB_7220_ibsd_epb_access_ctrl_offset 0x000003c0UL
+struct QIB_7220_ibsd_epb_access_ctrl_pb {
+	pseudo_bit_t sw_ib_epb_req[1];
+	pseudo_bit_t Reserved[7];
+	pseudo_bit_t sw_ib_epb_req_granted[1];
+	pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_ibsd_epb_access_ctrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_ibsd_epb_transaction_reg_offset 0x000003c8UL
+struct QIB_7220_ibsd_epb_transaction_reg_pb {
+	pseudo_bit_t ib_epb_data[8];
+	pseudo_bit_t ib_epb_address[15];
+	pseudo_bit_t Reserved2[1];
+	pseudo_bit_t ib_epb_read_write[1];
+	pseudo_bit_t ib_epb_cs[2];
+	pseudo_bit_t Reserved1[1];
+	pseudo_bit_t mem_data_parity[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t ib_epb_req_error[1];
+	pseudo_bit_t ib_epb_rdy[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_ibsd_epb_transaction_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_REG_0003D0_offset 0x000003d0UL
+
+#define QIB_7220_XGXSCfg_offset 0x000003d8UL
+struct QIB_7220_XGXSCfg_pb {
+	pseudo_bit_t tx_rx_reset[1];
+	pseudo_bit_t Reserved2[1];
+	pseudo_bit_t xcv_reset[1];
+	pseudo_bit_t Reserved1[6];
+	pseudo_bit_t link_sync_mask[10];
+	pseudo_bit_t Reserved[44];
+	pseudo_bit_t sel_link_down_for_fctrl_lane_sync_reset[1];
+};
+struct QIB_7220_XGXSCfg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_XGXSCfg_pb );
+};
+
+#define QIB_7220_IBSerDesCtrl_offset 0x000003e0UL
+struct QIB_7220_IBSerDesCtrl_pb {
+	pseudo_bit_t ResetIB_uC_Core[1];
+	pseudo_bit_t Reserved2[7];
+	pseudo_bit_t NumSerDesRegsToWrForDDS[5];
+	pseudo_bit_t NumSerDesRegsToWrForRXEQ[5];
+	pseudo_bit_t Reserved1[14];
+	pseudo_bit_t TXINV[1];
+	pseudo_bit_t RXINV[1];
+	pseudo_bit_t RXIDLE[1];
+	pseudo_bit_t TWC[1];
+	pseudo_bit_t TXOBPD[1];
+	pseudo_bit_t PLLM[3];
+	pseudo_bit_t PLLN[2];
+	pseudo_bit_t CKSEL_uC[2];
+	pseudo_bit_t INT_uC[1];
+	pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_IBSerDesCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_IBSerDesCtrl_pb );
+};
+
+#define QIB_7220_EEPCtlStat_offset 0x000003e8UL
+struct QIB_7220_EEPCtlStat_pb {
+	pseudo_bit_t EPAccEn[2];
+	pseudo_bit_t EPReset[1];
+	pseudo_bit_t ByteProg[1];
+	pseudo_bit_t PageMode[1];
+	pseudo_bit_t LstDatWr[1];
+	pseudo_bit_t CmdWrErr[1];
+	pseudo_bit_t Reserved[24];
+	pseudo_bit_t CtlrStat[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPCtlStat {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPCtlStat_pb );
+};
+
+#define QIB_7220_EEPAddrCmd_offset 0x000003f0UL
+struct QIB_7220_EEPAddrCmd_pb {
+	pseudo_bit_t EPAddr[24];
+	pseudo_bit_t EPCmd[8];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPAddrCmd {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPAddrCmd_pb );
+};
+
+#define QIB_7220_EEPData_offset 0x000003f8UL
+
+#define QIB_7220_pciesd_epb_access_ctrl_offset 0x00000400UL
+struct QIB_7220_pciesd_epb_access_ctrl_pb {
+	pseudo_bit_t sw_pcie_epb_req[1];
+	pseudo_bit_t sw_pcieepb_star_en[2];
+	pseudo_bit_t Reserved[5];
+	pseudo_bit_t sw_pcie_epb_req_granted[1];
+	pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_pciesd_epb_access_ctrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_pciesd_epb_transaction_reg_offset 0x00000408UL
+struct QIB_7220_pciesd_epb_transaction_reg_pb {
+	pseudo_bit_t pcie_epb_data[8];
+	pseudo_bit_t pcie_epb_address[15];
+	pseudo_bit_t Reserved1[1];
+	pseudo_bit_t pcie_epb_read_write[1];
+	pseudo_bit_t pcie_epb_cs[3];
+	pseudo_bit_t mem_data_parity[1];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t pcie_epb_req_error[1];
+	pseudo_bit_t pcie_epb_rdy[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_pciesd_epb_transaction_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_efuse_control_reg_offset 0x00000410UL
+struct QIB_7220_efuse_control_reg_pb {
+	pseudo_bit_t start_op[1];
+	pseudo_bit_t operation[1];
+	pseudo_bit_t read_valid[1];
+	pseudo_bit_t req_error[1];
+	pseudo_bit_t Reserved[27];
+	pseudo_bit_t rdy[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_efuse_control_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_efuse_control_reg_pb );
+};
+
+#define QIB_7220_efuse_rddata0_reg_offset 0x00000418UL
+
+#define QIB_7220_procmon_register_offset 0x00000438UL
+struct QIB_7220_procmon_register_pb {
+	pseudo_bit_t interval_time[12];
+	pseudo_bit_t Reserved1[2];
+	pseudo_bit_t clear_counter[1];
+	pseudo_bit_t start_counter[1];
+	pseudo_bit_t procmon_count[9];
+	pseudo_bit_t Reserved[6];
+	pseudo_bit_t procmon_count_valid[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_procmon_register {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_procmon_register_pb );
+};
+
+#define QIB_7220_PcieRbufTestReg0_offset 0x00000440UL
+
+#define QIB_7220_PcieRBufTestReg1_offset 0x00000448UL
+
+#define QIB_7220_SPC_JTAG_ACCESS_REG_offset 0x00000460UL
+struct QIB_7220_SPC_JTAG_ACCESS_REG_pb {
+	pseudo_bit_t rdy[1];
+	pseudo_bit_t tdo[1];
+	pseudo_bit_t tdi[1];
+	pseudo_bit_t opcode[2];
+	pseudo_bit_t bist_en[5];
+	pseudo_bit_t SPC_JTAG_ACCESS_EN[1];
+	pseudo_bit_t _unused_0[53];
+};
+struct QIB_7220_SPC_JTAG_ACCESS_REG {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SPC_JTAG_ACCESS_REG_pb );
+};
+
+#define QIB_7220_LAControlReg_offset 0x00000468UL
+struct QIB_7220_LAControlReg_pb {
+	pseudo_bit_t Finished[1];
+	pseudo_bit_t Address[8];
+	pseudo_bit_t Mode[2];
+	pseudo_bit_t Delay[20];
+	pseudo_bit_t Reserved[1];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_LAControlReg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_LAControlReg_pb );
+};
+
+#define QIB_7220_GPIODebugSelReg_offset 0x00000470UL
+struct QIB_7220_GPIODebugSelReg_pb {
+	pseudo_bit_t GPIOSourceSelDebug[16];
+	pseudo_bit_t SelPulse[16];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_GPIODebugSelReg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIODebugSelReg_pb );
+};
+
+#define QIB_7220_DebugPortValueReg_offset 0x00000478UL
+
+#define QIB_7220_SendDmaBufUsed0_offset 0x00000480UL
+struct QIB_7220_SendDmaBufUsed0_pb {
+	pseudo_bit_t BufUsed_63_0[0];
+	pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufUsed0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufUsed0_pb );
+};
+
+#define QIB_7220_SendDmaReqTagUsed_offset 0x00000498UL
+struct QIB_7220_SendDmaReqTagUsed_pb {
+	pseudo_bit_t ReqTagUsed_7_0[8];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_SendDmaReqTagUsed {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaReqTagUsed_pb );
+};
+
+#define QIB_7220_efuse_pgm_data0_offset 0x000004a0UL
+
+#define QIB_7220_MEM_0004B0_offset 0x000004b0UL
+
+#define QIB_7220_SerDes_DDSRXEQ0_offset 0x00000500UL
+struct QIB_7220_SerDes_DDSRXEQ0_pb {
+	pseudo_bit_t element_num[4];
+	pseudo_bit_t reg_addr[6];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_SerDes_DDSRXEQ0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SerDes_DDSRXEQ0_pb );
+};
+
+#define QIB_7220_MEM_0005F0_offset 0x000005f0UL
+
+#define QIB_7220_LAMemory_offset 0x00000600UL
+
+#define QIB_7220_MEM_0007F0_offset 0x000007f0UL
+
+#define QIB_7220_SendBufAvail0_offset 0x00001000UL
+struct QIB_7220_SendBufAvail0_pb {
+	pseudo_bit_t SendBuf_31_0[0];
+	pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufAvail0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail0_pb );
+};
+
+#define QIB_7220_MEM_001028_offset 0x00001028UL
+
+#define QIB_7220_LBIntCnt_offset 0x00013000UL
+
+#define QIB_7220_LBFlowStallCnt_offset 0x00013008UL
+
+#define QIB_7220_TxSDmaDescCnt_offset 0x00013010UL
+
+#define QIB_7220_TxUnsupVLErrCnt_offset 0x00013018UL
+
+#define QIB_7220_TxDataPktCnt_offset 0x00013020UL
+
+#define QIB_7220_TxFlowPktCnt_offset 0x00013028UL
+
+#define QIB_7220_TxDwordCnt_offset 0x00013030UL
+
+#define QIB_7220_TxLenErrCnt_offset 0x00013038UL
+
+#define QIB_7220_TxMaxMinLenErrCnt_offset 0x00013040UL
+
+#define QIB_7220_TxUnderrunCnt_offset 0x00013048UL
+
+#define QIB_7220_TxFlowStallCnt_offset 0x00013050UL
+
+#define QIB_7220_TxDroppedPktCnt_offset 0x00013058UL
+
+#define QIB_7220_RxDroppedPktCnt_offset 0x00013060UL
+
+#define QIB_7220_RxDataPktCnt_offset 0x00013068UL
+
+#define QIB_7220_RxFlowPktCnt_offset 0x00013070UL
+
+#define QIB_7220_RxDwordCnt_offset 0x00013078UL
+
+#define QIB_7220_RxLenErrCnt_offset 0x00013080UL
+
+#define QIB_7220_RxMaxMinLenErrCnt_offset 0x00013088UL
+
+#define QIB_7220_RxICRCErrCnt_offset 0x00013090UL
+
+#define QIB_7220_RxVCRCErrCnt_offset 0x00013098UL
+
+#define QIB_7220_RxFlowCtrlViolCnt_offset 0x000130a0UL
+
+#define QIB_7220_RxVersionErrCnt_offset 0x000130a8UL
+
+#define QIB_7220_RxLinkMalformCnt_offset 0x000130b0UL
+
+#define QIB_7220_RxEBPCnt_offset 0x000130b8UL
+
+#define QIB_7220_RxLPCRCErrCnt_offset 0x000130c0UL
+
+#define QIB_7220_RxBufOvflCnt_offset 0x000130c8UL
+
+#define QIB_7220_RxTIDFullErrCnt_offset 0x000130d0UL
+
+#define QIB_7220_RxTIDValidErrCnt_offset 0x000130d8UL
+
+#define QIB_7220_RxPKeyMismatchCnt_offset 0x000130e0UL
+
+#define QIB_7220_RxP0HdrEgrOvflCnt_offset 0x000130e8UL
+
+#define QIB_7220_IBStatusChangeCnt_offset 0x00013170UL
+
+#define QIB_7220_IBLinkErrRecoveryCnt_offset 0x00013178UL
+
+#define QIB_7220_IBLinkDownedCnt_offset 0x00013180UL
+
+#define QIB_7220_IBSymbolErrCnt_offset 0x00013188UL
+
+#define QIB_7220_RxVL15DroppedPktCnt_offset 0x00013190UL
+
+#define QIB_7220_RxOtherLocalPhyErrCnt_offset 0x00013198UL
+
+#define QIB_7220_PcieRetryBufDiagQwordCnt_offset 0x000131a0UL
+
+#define QIB_7220_ExcessBufferOvflCnt_offset 0x000131a8UL
+
+#define QIB_7220_LocalLinkIntegrityErrCnt_offset 0x000131b0UL
+
+#define QIB_7220_RxVlErrCnt_offset 0x000131b8UL
+
+#define QIB_7220_RxDlidFltrCnt_offset 0x000131c0UL
+
+#define QIB_7220_CNT_0131C8_offset 0x000131c8UL
+
+#define QIB_7220_PSStat_offset 0x00013200UL
+
+#define QIB_7220_PSStart_offset 0x00013208UL
+
+#define QIB_7220_PSInterval_offset 0x00013210UL
+
+#define QIB_7220_PSRcvDataCount_offset 0x00013218UL
+
+#define QIB_7220_PSRcvPktsCount_offset 0x00013220UL
+
+#define QIB_7220_PSXmitDataCount_offset 0x00013228UL
+
+#define QIB_7220_PSXmitPktsCount_offset 0x00013230UL
+
+#define QIB_7220_PSXmitWaitCount_offset 0x00013238UL
+
+#define QIB_7220_CNT_013240_offset 0x00013240UL
+
+#define QIB_7220_RcvEgrArray_offset 0x00014000UL
+
+#define QIB_7220_MEM_038000_offset 0x00038000UL
+
+#define QIB_7220_RcvTIDArray0_offset 0x00053000UL
+
+#define QIB_7220_PIOLaunchFIFO_offset 0x00064000UL
+
+#define QIB_7220_MEM_064480_offset 0x00064480UL
+
+#define QIB_7220_SendPIOpbcCache_offset 0x00064800UL
+
+#define QIB_7220_MEM_064C80_offset 0x00064c80UL
+
+#define QIB_7220_PreLaunchFIFO_offset 0x00065000UL
+
+#define QIB_7220_MEM_065080_offset 0x00065080UL
+
+#define QIB_7220_ScoreBoard_offset 0x00065400UL
+
+#define QIB_7220_MEM_065440_offset 0x00065440UL
+
+#define QIB_7220_DescriptorFIFO_offset 0x00065800UL
+
+#define QIB_7220_MEM_065880_offset 0x00065880UL
+
+#define QIB_7220_RcvBuf1_offset 0x00072000UL
+
+#define QIB_7220_MEM_074800_offset 0x00074800UL
+
+#define QIB_7220_RcvBuf2_offset 0x00075000UL
+
+#define QIB_7220_MEM_076400_offset 0x00076400UL
+
+#define QIB_7220_RcvFlags_offset 0x00077000UL
+
+#define QIB_7220_MEM_078400_offset 0x00078400UL
+
+#define QIB_7220_RcvLookupBuf1_offset 0x00079000UL
+
+#define QIB_7220_MEM_07A400_offset 0x0007a400UL
+
+#define QIB_7220_RcvDMADatBuf_offset 0x0007b000UL
+
+#define QIB_7220_RcvDMAHdrBuf_offset 0x0007b800UL
+
+#define QIB_7220_MiscRXEIntMem_offset 0x0007c000UL
+
+#define QIB_7220_MEM_07D400_offset 0x0007d400UL
+
+#define QIB_7220_PCIERcvBuf_offset 0x00080000UL
+
+#define QIB_7220_PCIERetryBuf_offset 0x00084000UL
+
+#define QIB_7220_PCIERcvBufRdToWrAddr_offset 0x00088000UL
+
+#define QIB_7220_PCIECplBuf_offset 0x00090000UL
+
+#define QIB_7220_IBSerDesMappTable_offset 0x00094000UL
+
+#define QIB_7220_MEM_095000_offset 0x00095000UL
+
+#define QIB_7220_SendBuf0_MA_offset 0x00100000UL
+
+#define QIB_7220_MEM_1A0000_offset 0x001a0000UL
+
+#define QIB_7220_RcvHdrTail0_offset 0x00200000UL
+
+#define QIB_7220_RcvHdrHead0_offset 0x00200008UL
+struct QIB_7220_RcvHdrHead0_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead0_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail0_offset 0x00200010UL
+
+#define QIB_7220_RcvEgrIndexHead0_offset 0x00200018UL
+
+#define QIB_7220_MEM_200020_offset 0x00200020UL
+
+#define QIB_7220_RcvHdrTail1_offset 0x00210000UL
+
+#define QIB_7220_RcvHdrHead1_offset 0x00210008UL
+struct QIB_7220_RcvHdrHead1_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead1_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail1_offset 0x00210010UL
+
+#define QIB_7220_RcvEgrIndexHead1_offset 0x00210018UL
+
+#define QIB_7220_MEM_210020_offset 0x00210020UL
+
+#define QIB_7220_RcvHdrTail2_offset 0x00220000UL
+
+#define QIB_7220_RcvHdrHead2_offset 0x00220008UL
+struct QIB_7220_RcvHdrHead2_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead2 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead2_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail2_offset 0x00220010UL
+
+#define QIB_7220_RcvEgrIndexHead2_offset 0x00220018UL
+
+#define QIB_7220_MEM_220020_offset 0x00220020UL
+
+#define QIB_7220_RcvHdrTail3_offset 0x00230000UL
+
+#define QIB_7220_RcvHdrHead3_offset 0x00230008UL
+struct QIB_7220_RcvHdrHead3_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead3 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead3_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail3_offset 0x00230010UL
+
+#define QIB_7220_RcvEgrIndexHead3_offset 0x00230018UL
+
+#define QIB_7220_MEM_230020_offset 0x00230020UL
+
+#define QIB_7220_RcvHdrTail4_offset 0x00240000UL
+
+#define QIB_7220_RcvHdrHead4_offset 0x00240008UL
+struct QIB_7220_RcvHdrHead4_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead4 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead4_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail4_offset 0x00240010UL
+
+#define QIB_7220_RcvEgrIndexHead4_offset 0x00240018UL
+
+#define QIB_7220_MEM_240020_offset 0x00240020UL
+
+#define QIB_7220_RcvHdrTail5_offset 0x00250000UL
+
+#define QIB_7220_RcvHdrHead5_offset 0x00250008UL
+struct QIB_7220_RcvHdrHead5_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead5 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead5_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail5_offset 0x00250010UL
+
+#define QIB_7220_RcvEgrIndexHead5_offset 0x00250018UL
+
+#define QIB_7220_MEM_250020_offset 0x00250020UL
+
+#define QIB_7220_RcvHdrTail6_offset 0x00260000UL
+
+#define QIB_7220_RcvHdrHead6_offset 0x00260008UL
+struct QIB_7220_RcvHdrHead6_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead6 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead6_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail6_offset 0x00260010UL
+
+#define QIB_7220_RcvEgrIndexHead6_offset 0x00260018UL
+
+#define QIB_7220_MEM_260020_offset 0x00260020UL
+
+#define QIB_7220_RcvHdrTail7_offset 0x00270000UL
+
+#define QIB_7220_RcvHdrHead7_offset 0x00270008UL
+struct QIB_7220_RcvHdrHead7_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead7 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead7_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail7_offset 0x00270010UL
+
+#define QIB_7220_RcvEgrIndexHead7_offset 0x00270018UL
+
+#define QIB_7220_MEM_270020_offset 0x00270020UL
+
+#define QIB_7220_RcvHdrTail8_offset 0x00280000UL
+
+#define QIB_7220_RcvHdrHead8_offset 0x00280008UL
+struct QIB_7220_RcvHdrHead8_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead8 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead8_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail8_offset 0x00280010UL
+
+#define QIB_7220_RcvEgrIndexHead8_offset 0x00280018UL
+
+#define QIB_7220_MEM_280020_offset 0x00280020UL
+
+#define QIB_7220_RcvHdrTail9_offset 0x00290000UL
+
+#define QIB_7220_RcvHdrHead9_offset 0x00290008UL
+struct QIB_7220_RcvHdrHead9_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead9 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead9_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail9_offset 0x00290010UL
+
+#define QIB_7220_RcvEgrIndexHead9_offset 0x00290018UL
+
+#define QIB_7220_MEM_290020_offset 0x00290020UL
+
+#define QIB_7220_RcvHdrTail10_offset 0x002a0000UL
+
+#define QIB_7220_RcvHdrHead10_offset 0x002a0008UL
+struct QIB_7220_RcvHdrHead10_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead10 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead10_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail10_offset 0x002a0010UL
+
+#define QIB_7220_RcvEgrIndexHead10_offset 0x002a0018UL
+
+#define QIB_7220_MEM_2A0020_offset 0x002a0020UL
+
+#define QIB_7220_RcvHdrTail11_offset 0x002b0000UL
+
+#define QIB_7220_RcvHdrHead11_offset 0x002b0008UL
+struct QIB_7220_RcvHdrHead11_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead11 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead11_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail11_offset 0x002b0010UL
+
+#define QIB_7220_RcvEgrIndexHead11_offset 0x002b0018UL
+
+#define QIB_7220_MEM_2B0020_offset 0x002b0020UL
+
+#define QIB_7220_RcvHdrTail12_offset 0x002c0000UL
+
+#define QIB_7220_RcvHdrHead12_offset 0x002c0008UL
+struct QIB_7220_RcvHdrHead12_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead12 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead12_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail12_offset 0x002c0010UL
+
+#define QIB_7220_RcvEgrIndexHead12_offset 0x002c0018UL
+
+#define QIB_7220_MEM_2C0020_offset 0x002c0020UL
+
+#define QIB_7220_RcvHdrTail13_offset 0x002d0000UL
+
+#define QIB_7220_RcvHdrHead13_offset 0x002d0008UL
+struct QIB_7220_RcvHdrHead13_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead13 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead13_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail13_offset 0x002d0010UL
+
+#define QIB_7220_RcvEgrIndexHead13_offset 0x002d0018UL
+
+#define QIB_7220_MEM_2D0020_offset 0x002d0020UL
+
+#define QIB_7220_RcvHdrTail14_offset 0x002e0000UL
+
+#define QIB_7220_RcvHdrHead14_offset 0x002e0008UL
+struct QIB_7220_RcvHdrHead14_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead14 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead14_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail14_offset 0x002e0010UL
+
+#define QIB_7220_RcvEgrIndexHead14_offset 0x002e0018UL
+
+#define QIB_7220_MEM_2E0020_offset 0x002e0020UL
+
+#define QIB_7220_RcvHdrTail15_offset 0x002f0000UL
+
+#define QIB_7220_RcvHdrHead15_offset 0x002f0008UL
+struct QIB_7220_RcvHdrHead15_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead15 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead15_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail15_offset 0x002f0010UL
+
+#define QIB_7220_RcvEgrIndexHead15_offset 0x002f0018UL
+
+#define QIB_7220_MEM_2F0020_offset 0x002f0020UL
+
+#define QIB_7220_RcvHdrTail16_offset 0x00300000UL
+
+#define QIB_7220_RcvHdrHead16_offset 0x00300008UL
+struct QIB_7220_RcvHdrHead16_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead16 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead16_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail16_offset 0x00300010UL
+
+#define QIB_7220_RcvEgrIndexHead16_offset 0x00300018UL
+
+#define QIB_7220_MEM_300020_offset 0x00300020UL
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7322_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7322_regs.h
new file mode 100644
index 0000000..06c4676
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_7322_regs.h
@@ -0,0 +1,7261 @@
+/*
+ * Copyright (c) 2008, 2009 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * 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.
+ */
+/* This file is mechanically generated from RTL. Any hand-edits will be lost! */
+
+/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#define QIB_7322_Revision_offset 0x00000000UL
+struct QIB_7322_Revision_pb {
+	pseudo_bit_t R_ChipRevMinor[8];
+	pseudo_bit_t R_ChipRevMajor[8];
+	pseudo_bit_t R_Arch[8];
+	pseudo_bit_t R_SW[8];
+	pseudo_bit_t BoardID[8];
+	pseudo_bit_t R_Emulation_Revcode[22];
+	pseudo_bit_t R_Emulation[1];
+	pseudo_bit_t R_Simulator[1];
+};
+struct QIB_7322_Revision {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_Revision_pb );
+};
+/* Default value: 0x0000000002010601 */
+
+#define QIB_7322_Control_offset 0x00000008UL
+struct QIB_7322_Control_pb {
+	pseudo_bit_t SyncReset[1];
+	pseudo_bit_t FreezeMode[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t PCIERetryBufDiagEn[1];
+	pseudo_bit_t SDmaDescFetchPriorityEn[1];
+	pseudo_bit_t PCIEPostQDiagEn[1];
+	pseudo_bit_t PCIECplQDiagEn[1];
+	pseudo_bit_t _unused_1[57];
+};
+struct QIB_7322_Control {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_Control_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PageAlign_offset 0x00000010UL
+/* Default value: 0x0000000000001000 */
+
+#define QIB_7322_ContextCnt_offset 0x00000018UL
+/* Default value: 0x0000000000000012 */
+
+#define QIB_7322_Scratch_offset 0x00000020UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_CntrRegBase_offset 0x00000028UL
+/* Default value: 0x0000000000011000 */
+
+#define QIB_7322_SendRegBase_offset 0x00000030UL
+/* Default value: 0x0000000000003000 */
+
+#define QIB_7322_UserRegBase_offset 0x00000038UL
+/* Default value: 0x0000000000200000 */
+
+#define QIB_7322_DebugPortSel_offset 0x00000040UL
+struct QIB_7322_DebugPortSel_pb {
+	pseudo_bit_t DebugOutMuxSel[2];
+	pseudo_bit_t _unused_0[28];
+	pseudo_bit_t SrcMuxSel0[8];
+	pseudo_bit_t SrcMuxSel1[8];
+	pseudo_bit_t DbgClkPortSel[5];
+	pseudo_bit_t EnDbgPort[1];
+	pseudo_bit_t EnEnhancedDebugMode[1];
+	pseudo_bit_t EnhMode_SrcMuxSelIndex[10];
+	pseudo_bit_t EnhMode_SrcMuxSelWrEn[1];
+};
+struct QIB_7322_DebugPortSel {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DebugPortSel_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DebugPortNibbleSel_offset 0x00000048UL
+struct QIB_7322_DebugPortNibbleSel_pb {
+	pseudo_bit_t NibbleSel0[4];
+	pseudo_bit_t NibbleSel1[4];
+	pseudo_bit_t NibbleSel2[4];
+	pseudo_bit_t NibbleSel3[4];
+	pseudo_bit_t NibbleSel4[4];
+	pseudo_bit_t NibbleSel5[4];
+	pseudo_bit_t NibbleSel6[4];
+	pseudo_bit_t NibbleSel7[4];
+	pseudo_bit_t NibbleSel8[4];
+	pseudo_bit_t NibbleSel9[4];
+	pseudo_bit_t NibbleSel10[4];
+	pseudo_bit_t NibbleSel11[4];
+	pseudo_bit_t NibbleSel12[4];
+	pseudo_bit_t NibbleSel13[4];
+	pseudo_bit_t NibbleSel14[4];
+	pseudo_bit_t NibbleSel15[4];
+};
+struct QIB_7322_DebugPortNibbleSel {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DebugPortNibbleSel_pb );
+};
+/* Default value: 0xFEDCBA9876543210 */
+
+#define QIB_7322_DebugSigsIntSel_offset 0x00000050UL
+struct QIB_7322_DebugSigsIntSel_pb {
+	pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3];
+	pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3];
+	pseudo_bit_t debug_port_sel_pcs_sdout[1];
+	pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4];
+	pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[3];
+	pseudo_bit_t EnableSDma_SelfDrain[1];
+	pseudo_bit_t debug_port_sel_pcie_rx_tx[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t debug_port_sel_tx_ibport[1];
+	pseudo_bit_t debug_port_sel_tx_sdma[1];
+	pseudo_bit_t debug_port_sel_rx_ibport[1];
+	pseudo_bit_t _unused_1[12];
+	pseudo_bit_t debug_port_sel_xgxs_0[4];
+	pseudo_bit_t debug_port_sel_credit_a_0[3];
+	pseudo_bit_t debug_port_sel_credit_b_0[3];
+	pseudo_bit_t debug_port_sel_xgxs_1[4];
+	pseudo_bit_t debug_port_sel_credit_a_1[3];
+	pseudo_bit_t debug_port_sel_credit_b_1[3];
+	pseudo_bit_t _unused_2[12];
+};
+struct QIB_7322_DebugSigsIntSel {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DebugSigsIntSel_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DebugPortValueReg_offset 0x00000058UL
+
+#define QIB_7322_IntBlocked_offset 0x00000060UL
+struct QIB_7322_IntBlocked_pb {
+	pseudo_bit_t RcvAvail0IntBlocked[1];
+	pseudo_bit_t RcvAvail1IntBlocked[1];
+	pseudo_bit_t RcvAvail2IntBlocked[1];
+	pseudo_bit_t RcvAvail3IntBlocked[1];
+	pseudo_bit_t RcvAvail4IntBlocked[1];
+	pseudo_bit_t RcvAvail5IntBlocked[1];
+	pseudo_bit_t RcvAvail6IntBlocked[1];
+	pseudo_bit_t RcvAvail7IntBlocked[1];
+	pseudo_bit_t RcvAvail8IntBlocked[1];
+	pseudo_bit_t RcvAvail9IntBlocked[1];
+	pseudo_bit_t RcvAvail10IntBlocked[1];
+	pseudo_bit_t RcvAvail11IntBlocked[1];
+	pseudo_bit_t RcvAvail12IntBlocked[1];
+	pseudo_bit_t RcvAvail13IntBlocked[1];
+	pseudo_bit_t RcvAvail14IntBlocked[1];
+	pseudo_bit_t RcvAvail15IntBlocked[1];
+	pseudo_bit_t RcvAvail16IntBlocked[1];
+	pseudo_bit_t RcvAvail17IntBlocked[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t SendBufAvailIntBlocked[1];
+	pseudo_bit_t SendDoneIntBlocked_0[1];
+	pseudo_bit_t SendDoneIntBlocked_1[1];
+	pseudo_bit_t _unused_1[2];
+	pseudo_bit_t AssertGPIOIntBlocked[1];
+	pseudo_bit_t ErrIntBlocked[1];
+	pseudo_bit_t ErrIntBlocked_0[1];
+	pseudo_bit_t ErrIntBlocked_1[1];
+	pseudo_bit_t RcvUrg0IntBlocked[1];
+	pseudo_bit_t RcvUrg1IntBlocked[1];
+	pseudo_bit_t RcvUrg2IntBlocked[1];
+	pseudo_bit_t RcvUrg3IntBlocked[1];
+	pseudo_bit_t RcvUrg4IntBlocked[1];
+	pseudo_bit_t RcvUrg5IntBlocked[1];
+	pseudo_bit_t RcvUrg6IntBlocked[1];
+	pseudo_bit_t RcvUrg7IntBlocked[1];
+	pseudo_bit_t RcvUrg8IntBlocked[1];
+	pseudo_bit_t RcvUrg9IntBlocked[1];
+	pseudo_bit_t RcvUrg10IntBlocked[1];
+	pseudo_bit_t RcvUrg11IntBlocked[1];
+	pseudo_bit_t RcvUrg12IntBlocked[1];
+	pseudo_bit_t RcvUrg13IntBlocked[1];
+	pseudo_bit_t RcvUrg14IntBlocked[1];
+	pseudo_bit_t RcvUrg15IntBlocked[1];
+	pseudo_bit_t RcvUrg16IntBlocked[1];
+	pseudo_bit_t RcvUrg17IntBlocked[1];
+	pseudo_bit_t _unused_2[6];
+	pseudo_bit_t SDmaCleanupDoneBlocked_0[1];
+	pseudo_bit_t SDmaCleanupDoneBlocked_1[1];
+	pseudo_bit_t SDmaIdleIntBlocked_0[1];
+	pseudo_bit_t SDmaIdleIntBlocked_1[1];
+	pseudo_bit_t SDmaProgressIntBlocked_0[1];
+	pseudo_bit_t SDmaProgressIntBlocked_1[1];
+	pseudo_bit_t SDmaIntBlocked_0[1];
+	pseudo_bit_t SDmaIntBlocked_1[1];
+};
+struct QIB_7322_IntBlocked {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IntBlocked_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IntMask_offset 0x00000068UL
+struct QIB_7322_IntMask_pb {
+	pseudo_bit_t RcvAvail0IntMask[1];
+	pseudo_bit_t RcvAvail1IntMask[1];
+	pseudo_bit_t RcvAvail2IntMask[1];
+	pseudo_bit_t RcvAvail3IntMask[1];
+	pseudo_bit_t RcvAvail4IntMask[1];
+	pseudo_bit_t RcvAvail5IntMask[1];
+	pseudo_bit_t RcvAvail6IntMask[1];
+	pseudo_bit_t RcvAvail7IntMask[1];
+	pseudo_bit_t RcvAvail8IntMask[1];
+	pseudo_bit_t RcvAvail9IntMask[1];
+	pseudo_bit_t RcvAvail10IntMask[1];
+	pseudo_bit_t RcvAvail11IntMask[1];
+	pseudo_bit_t RcvAvail12IntMask[1];
+	pseudo_bit_t RcvAvail13IntMask[1];
+	pseudo_bit_t RcvAvail14IntMask[1];
+	pseudo_bit_t RcvAvail15IntMask[1];
+	pseudo_bit_t RcvAvail16IntMask[1];
+	pseudo_bit_t RcvAvail17IntMask[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t SendBufAvailIntMask[1];
+	pseudo_bit_t SendDoneIntMask_0[1];
+	pseudo_bit_t SendDoneIntMask_1[1];
+	pseudo_bit_t _unused_1[2];
+	pseudo_bit_t AssertGPIOIntMask[1];
+	pseudo_bit_t ErrIntMask[1];
+	pseudo_bit_t ErrIntMask_0[1];
+	pseudo_bit_t ErrIntMask_1[1];
+	pseudo_bit_t RcvUrg0IntMask[1];
+	pseudo_bit_t RcvUrg1IntMask[1];
+	pseudo_bit_t RcvUrg2IntMask[1];
+	pseudo_bit_t RcvUrg3IntMask[1];
+	pseudo_bit_t RcvUrg4IntMask[1];
+	pseudo_bit_t RcvUrg5IntMask[1];
+	pseudo_bit_t RcvUrg6IntMask[1];
+	pseudo_bit_t RcvUrg7IntMask[1];
+	pseudo_bit_t RcvUrg8IntMask[1];
+	pseudo_bit_t RcvUrg9IntMask[1];
+	pseudo_bit_t RcvUrg10IntMask[1];
+	pseudo_bit_t RcvUrg11IntMask[1];
+	pseudo_bit_t RcvUrg12IntMask[1];
+	pseudo_bit_t RcvUrg13IntMask[1];
+	pseudo_bit_t RcvUrg14IntMask[1];
+	pseudo_bit_t RcvUrg15IntMask[1];
+	pseudo_bit_t RcvUrg16IntMask[1];
+	pseudo_bit_t RcvUrg17IntMask[1];
+	pseudo_bit_t _unused_2[6];
+	pseudo_bit_t SDmaCleanupDoneMask_0[1];
+	pseudo_bit_t SDmaCleanupDoneMask_1[1];
+	pseudo_bit_t SDmaIdleIntMask_0[1];
+	pseudo_bit_t SDmaIdleIntMask_1[1];
+	pseudo_bit_t SDmaProgressIntMask_0[1];
+	pseudo_bit_t SDmaProgressIntMask_1[1];
+	pseudo_bit_t SDmaIntMask_0[1];
+	pseudo_bit_t SDmaIntMask_1[1];
+};
+struct QIB_7322_IntMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IntMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IntStatus_offset 0x00000070UL
+struct QIB_7322_IntStatus_pb {
+	pseudo_bit_t RcvAvail0[1];
+	pseudo_bit_t RcvAvail1[1];
+	pseudo_bit_t RcvAvail2[1];
+	pseudo_bit_t RcvAvail3[1];
+	pseudo_bit_t RcvAvail4[1];
+	pseudo_bit_t RcvAvail5[1];
+	pseudo_bit_t RcvAvail6[1];
+	pseudo_bit_t RcvAvail7[1];
+	pseudo_bit_t RcvAvail8[1];
+	pseudo_bit_t RcvAvail9[1];
+	pseudo_bit_t RcvAvail10[1];
+	pseudo_bit_t RcvAvail11[1];
+	pseudo_bit_t RcvAvail12[1];
+	pseudo_bit_t RcvAvail13[1];
+	pseudo_bit_t RcvAvail14[1];
+	pseudo_bit_t RcvAvail15[1];
+	pseudo_bit_t RcvAvail16[1];
+	pseudo_bit_t RcvAvail17[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t SendBufAvail[1];
+	pseudo_bit_t SendDone_0[1];
+	pseudo_bit_t SendDone_1[1];
+	pseudo_bit_t _unused_1[2];
+	pseudo_bit_t AssertGPIO[1];
+	pseudo_bit_t Err[1];
+	pseudo_bit_t Err_0[1];
+	pseudo_bit_t Err_1[1];
+	pseudo_bit_t RcvUrg0[1];
+	pseudo_bit_t RcvUrg1[1];
+	pseudo_bit_t RcvUrg2[1];
+	pseudo_bit_t RcvUrg3[1];
+	pseudo_bit_t RcvUrg4[1];
+	pseudo_bit_t RcvUrg5[1];
+	pseudo_bit_t RcvUrg6[1];
+	pseudo_bit_t RcvUrg7[1];
+	pseudo_bit_t RcvUrg8[1];
+	pseudo_bit_t RcvUrg9[1];
+	pseudo_bit_t RcvUrg10[1];
+	pseudo_bit_t RcvUrg11[1];
+	pseudo_bit_t RcvUrg12[1];
+	pseudo_bit_t RcvUrg13[1];
+	pseudo_bit_t RcvUrg14[1];
+	pseudo_bit_t RcvUrg15[1];
+	pseudo_bit_t RcvUrg16[1];
+	pseudo_bit_t RcvUrg17[1];
+	pseudo_bit_t _unused_2[6];
+	pseudo_bit_t SDmaCleanupDone_0[1];
+	pseudo_bit_t SDmaCleanupDone_1[1];
+	pseudo_bit_t SDmaIdleInt_0[1];
+	pseudo_bit_t SDmaIdleInt_1[1];
+	pseudo_bit_t SDmaProgressInt_0[1];
+	pseudo_bit_t SDmaProgressInt_1[1];
+	pseudo_bit_t SDmaInt_0[1];
+	pseudo_bit_t SDmaInt_1[1];
+};
+struct QIB_7322_IntStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IntStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IntClear_offset 0x00000078UL
+struct QIB_7322_IntClear_pb {
+	pseudo_bit_t RcvAvail0IntClear[1];
+	pseudo_bit_t RcvAvail1IntClear[1];
+	pseudo_bit_t RcvAvail2IntClear[1];
+	pseudo_bit_t RcvAvail3IntClear[1];
+	pseudo_bit_t RcvAvail4IntClear[1];
+	pseudo_bit_t RcvAvail5IntClear[1];
+	pseudo_bit_t RcvAvail6IntClear[1];
+	pseudo_bit_t RcvAvail7IntClear[1];
+	pseudo_bit_t RcvAvail8IntClear[1];
+	pseudo_bit_t RcvAvail9IntClear[1];
+	pseudo_bit_t RcvAvail10IntClear[1];
+	pseudo_bit_t RcvAvail11IntClear[1];
+	pseudo_bit_t RcvAvail12IntClear[1];
+	pseudo_bit_t RcvAvail13IntClear[1];
+	pseudo_bit_t RcvAvail14IntClear[1];
+	pseudo_bit_t RcvAvail15IntClear[1];
+	pseudo_bit_t RcvAvail16IntClear[1];
+	pseudo_bit_t RcvAvail17IntClear[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t SendBufAvailIntClear[1];
+	pseudo_bit_t SendDoneIntClear_0[1];
+	pseudo_bit_t SendDoneIntClear_1[1];
+	pseudo_bit_t _unused_1[2];
+	pseudo_bit_t AssertGPIOIntClear[1];
+	pseudo_bit_t ErrIntClear[1];
+	pseudo_bit_t ErrIntClear_0[1];
+	pseudo_bit_t ErrIntClear_1[1];
+	pseudo_bit_t RcvUrg0IntClear[1];
+	pseudo_bit_t RcvUrg1IntClear[1];
+	pseudo_bit_t RcvUrg2IntClear[1];
+	pseudo_bit_t RcvUrg3IntClear[1];
+	pseudo_bit_t RcvUrg4IntClear[1];
+	pseudo_bit_t RcvUrg5IntClear[1];
+	pseudo_bit_t RcvUrg6IntClear[1];
+	pseudo_bit_t RcvUrg7IntClear[1];
+	pseudo_bit_t RcvUrg8IntClear[1];
+	pseudo_bit_t RcvUrg9IntClear[1];
+	pseudo_bit_t RcvUrg10IntClear[1];
+	pseudo_bit_t RcvUrg11IntClear[1];
+	pseudo_bit_t RcvUrg12IntClear[1];
+	pseudo_bit_t RcvUrg13IntClear[1];
+	pseudo_bit_t RcvUrg14IntClear[1];
+	pseudo_bit_t RcvUrg15IntClear[1];
+	pseudo_bit_t RcvUrg16IntClear[1];
+	pseudo_bit_t RcvUrg17IntClear[1];
+	pseudo_bit_t _unused_2[6];
+	pseudo_bit_t SDmaCleanupDoneClear_0[1];
+	pseudo_bit_t SDmaCleanupDoneClear_1[1];
+	pseudo_bit_t SDmaIdleIntClear_0[1];
+	pseudo_bit_t SDmaIdleIntClear_1[1];
+	pseudo_bit_t SDmaProgressIntClear_0[1];
+	pseudo_bit_t SDmaProgressIntClear_1[1];
+	pseudo_bit_t SDmaIntClear_0[1];
+	pseudo_bit_t SDmaIntClear_1[1];
+};
+struct QIB_7322_IntClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IntClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrMask_offset 0x00000080UL
+struct QIB_7322_ErrMask_pb {
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t RcvEgrFullErrMask[1];
+	pseudo_bit_t RcvHdrFullErrMask[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaBufMaskDuplicateErrMask[1];
+	pseudo_bit_t SDmaWrongPortErrMask[1];
+	pseudo_bit_t SendSpecialTriggerErrMask[1];
+	pseudo_bit_t _unused_2[7];
+	pseudo_bit_t SendArmLaunchErrMask[1];
+	pseudo_bit_t SendVLMismatchErrMask[1];
+	pseudo_bit_t _unused_3[15];
+	pseudo_bit_t RcvContextShareErrMask[1];
+	pseudo_bit_t InvalidEEPCmdMask[1];
+	pseudo_bit_t _unused_4[1];
+	pseudo_bit_t SBufVL15MisUseErrMask[1];
+	pseudo_bit_t SDmaVL15ErrMask[1];
+	pseudo_bit_t _unused_5[4];
+	pseudo_bit_t InvalidAddrErrMask[1];
+	pseudo_bit_t HardwareErrMask[1];
+	pseudo_bit_t ResetNegatedMask[1];
+};
+struct QIB_7322_ErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrStatus_offset 0x00000088UL
+struct QIB_7322_ErrStatus_pb {
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t RcvEgrFullErr[1];
+	pseudo_bit_t RcvHdrFullErr[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaBufMaskDuplicateErr[1];
+	pseudo_bit_t SDmaWrongPortErr[1];
+	pseudo_bit_t SendSpecialTriggerErr[1];
+	pseudo_bit_t _unused_2[7];
+	pseudo_bit_t SendArmLaunchErr[1];
+	pseudo_bit_t SendVLMismatchErr[1];
+	pseudo_bit_t _unused_3[15];
+	pseudo_bit_t RcvContextShareErr[1];
+	pseudo_bit_t InvalidEEPCmdErr[1];
+	pseudo_bit_t _unused_4[1];
+	pseudo_bit_t SBufVL15MisUseErr[1];
+	pseudo_bit_t SDmaVL15Err[1];
+	pseudo_bit_t _unused_5[4];
+	pseudo_bit_t InvalidAddrErr[1];
+	pseudo_bit_t HardwareErr[1];
+	pseudo_bit_t ResetNegated[1];
+};
+struct QIB_7322_ErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrClear_offset 0x00000090UL
+struct QIB_7322_ErrClear_pb {
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t RcvEgrFullErrClear[1];
+	pseudo_bit_t RcvHdrFullErrClear[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaBufMaskDuplicateErrClear[1];
+	pseudo_bit_t SDmaWrongPortErrClear[1];
+	pseudo_bit_t SendSpecialTriggerErrClear[1];
+	pseudo_bit_t _unused_2[7];
+	pseudo_bit_t SendArmLaunchErrClear[1];
+	pseudo_bit_t SendVLMismatchErrMask[1];
+	pseudo_bit_t _unused_3[15];
+	pseudo_bit_t RcvContextShareErrClear[1];
+	pseudo_bit_t InvalidEEPCmdErrClear[1];
+	pseudo_bit_t _unused_4[1];
+	pseudo_bit_t SBufVL15MisUseErrClear[1];
+	pseudo_bit_t SDmaVL15ErrClear[1];
+	pseudo_bit_t _unused_5[4];
+	pseudo_bit_t InvalidAddrErrClear[1];
+	pseudo_bit_t HardwareErrClear[1];
+	pseudo_bit_t ResetNegatedClear[1];
+};
+struct QIB_7322_ErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HwErrMask_offset 0x00000098UL
+struct QIB_7322_HwErrMask_pb {
+	pseudo_bit_t _unused_0[11];
+	pseudo_bit_t LATriggeredMask[1];
+	pseudo_bit_t statusValidNoEopMask_0[1];
+	pseudo_bit_t IBCBusFromSPCParityErrMask_0[1];
+	pseudo_bit_t statusValidNoEopMask_1[1];
+	pseudo_bit_t IBCBusFromSPCParityErrMask_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaMemReadErrMask_0[1];
+	pseudo_bit_t SDmaMemReadErrMask_1[1];
+	pseudo_bit_t PciePoisonedTLPMask[1];
+	pseudo_bit_t PcieCplTimeoutMask[1];
+	pseudo_bit_t PCIeBusParityErrMask[3];
+	pseudo_bit_t pcie_phy_txParityErr[1];
+	pseudo_bit_t _unused_2[13];
+	pseudo_bit_t MemoryErrMask[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t TempsenseTholdReachedMask[1];
+	pseudo_bit_t PowerOnBISTFailedMask[1];
+	pseudo_bit_t PCIESerdesPClkNotDetectMask[1];
+	pseudo_bit_t _unused_4[6];
+	pseudo_bit_t IBSerdesPClkNotDetectMask_0[1];
+	pseudo_bit_t IBSerdesPClkNotDetectMask_1[1];
+};
+struct QIB_7322_HwErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HwErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HwErrStatus_offset 0x000000a0UL
+struct QIB_7322_HwErrStatus_pb {
+	pseudo_bit_t _unused_0[11];
+	pseudo_bit_t LATriggered[1];
+	pseudo_bit_t statusValidNoEop_0[1];
+	pseudo_bit_t IBCBusFromSPCParityErr_0[1];
+	pseudo_bit_t statusValidNoEop_1[1];
+	pseudo_bit_t IBCBusFromSPCParityErr_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaMemReadErr_0[1];
+	pseudo_bit_t SDmaMemReadErr_1[1];
+	pseudo_bit_t PciePoisonedTLP[1];
+	pseudo_bit_t PcieCplTimeout[1];
+	pseudo_bit_t PCIeBusParity[3];
+	pseudo_bit_t pcie_phy_txParityErr[1];
+	pseudo_bit_t _unused_2[13];
+	pseudo_bit_t MemoryErr[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t TempsenseTholdReached[1];
+	pseudo_bit_t PowerOnBISTFailed[1];
+	pseudo_bit_t PCIESerdesPClkNotDetect[1];
+	pseudo_bit_t _unused_4[6];
+	pseudo_bit_t IBSerdesPClkNotDetect_0[1];
+	pseudo_bit_t IBSerdesPClkNotDetect_1[1];
+};
+struct QIB_7322_HwErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HwErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HwErrClear_offset 0x000000a8UL
+struct QIB_7322_HwErrClear_pb {
+	pseudo_bit_t _unused_0[11];
+	pseudo_bit_t LATriggeredClear[1];
+	pseudo_bit_t IBCBusToSPCparityErrClear_0[1];
+	pseudo_bit_t IBCBusFromSPCParityErrClear_0[1];
+	pseudo_bit_t IBCBusToSPCparityErrClear_1[1];
+	pseudo_bit_t IBCBusFromSPCParityErrClear_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SDmaMemReadErrClear_0[1];
+	pseudo_bit_t SDmaMemReadErrClear_1[1];
+	pseudo_bit_t PciePoisonedTLPClear[1];
+	pseudo_bit_t PcieCplTimeoutClear[1];
+	pseudo_bit_t PCIeBusParityClear[3];
+	pseudo_bit_t pcie_phy_txParityErr[1];
+	pseudo_bit_t _unused_2[13];
+	pseudo_bit_t MemoryErrClear[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t TempsenseTholdReachedClear[1];
+	pseudo_bit_t PowerOnBISTFailedClear[1];
+	pseudo_bit_t PCIESerdesPClkNotDetectClear[1];
+	pseudo_bit_t _unused_4[6];
+	pseudo_bit_t IBSerdesPClkNotDetectClear_0[1];
+	pseudo_bit_t IBSerdesPClkNotDetectClear_1[1];
+};
+struct QIB_7322_HwErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HwErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HwDiagCtrl_offset 0x000000b0UL
+struct QIB_7322_HwDiagCtrl_pb {
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t ForcestatusValidNoEop_0[1];
+	pseudo_bit_t ForceIBCBusFromSPCParityErr_0[1];
+	pseudo_bit_t ForcestatusValidNoEop_1[1];
+	pseudo_bit_t ForceIBCBusFromSPCParityErr_1[1];
+	pseudo_bit_t _unused_1[15];
+	pseudo_bit_t forcePCIeBusParity[4];
+	pseudo_bit_t _unused_2[25];
+	pseudo_bit_t CounterDisable[1];
+	pseudo_bit_t CounterWrEnable[1];
+	pseudo_bit_t _unused_3[1];
+	pseudo_bit_t Diagnostic[1];
+};
+struct QIB_7322_HwDiagCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HwDiagCtrl_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_EXTStatus_offset 0x000000c0UL
+struct QIB_7322_EXTStatus_pb {
+	pseudo_bit_t _unused_0[14];
+	pseudo_bit_t MemBISTEndTest[1];
+	pseudo_bit_t MemBISTDisabled[1];
+	pseudo_bit_t _unused_1[32];
+	pseudo_bit_t GPIOIn[16];
+};
+struct QIB_7322_EXTStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_EXTStatus_pb );
+};
+/* Default value: 0x000000000000X000 */
+
+#define QIB_7322_EXTCtrl_offset 0x000000c8UL
+struct QIB_7322_EXTCtrl_pb {
+	pseudo_bit_t LEDPort0YellowOn[1];
+	pseudo_bit_t LEDPort0GreenOn[1];
+	pseudo_bit_t LEDPort1YellowOn[1];
+	pseudo_bit_t LEDPort1GreenOn[1];
+	pseudo_bit_t _unused_0[28];
+	pseudo_bit_t GPIOInvert[16];
+	pseudo_bit_t GPIOOe[16];
+};
+struct QIB_7322_EXTCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_EXTCtrl_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_GPIODebugSelReg_offset 0x000000d8UL
+struct QIB_7322_GPIODebugSelReg_pb {
+	pseudo_bit_t GPIOSourceSelDebug[16];
+	pseudo_bit_t SelPulse[16];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7322_GPIODebugSelReg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_GPIODebugSelReg_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_GPIOOut_offset 0x000000e0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_GPIOMask_offset 0x000000e8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_GPIOStatus_offset 0x000000f0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_GPIOClear_offset 0x000000f8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvCtrl_offset 0x00000100UL
+struct QIB_7322_RcvCtrl_pb {
+	pseudo_bit_t dontDropRHQFull[18];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t IntrAvail[18];
+	pseudo_bit_t _unused_1[3];
+	pseudo_bit_t ContextCfg[2];
+	pseudo_bit_t TidFlowEnable[1];
+	pseudo_bit_t XrcTypeCode[3];
+	pseudo_bit_t TailUpd[1];
+	pseudo_bit_t TidReDirect[16];
+};
+struct QIB_7322_RcvCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvCtrl_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrSize_offset 0x00000110UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrCnt_offset 0x00000118UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrEntSize_offset 0x00000120UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDBase_offset 0x00000128UL
+/* Default value: 0x0000000000050000 */
+
+#define QIB_7322_RcvTIDCnt_offset 0x00000130UL
+/* Default value: 0x0000000000000200 */
+
+#define QIB_7322_RcvEgrBase_offset 0x00000138UL
+/* Default value: 0x0000000000014000 */
+
+#define QIB_7322_RcvEgrCnt_offset 0x00000140UL
+/* Default value: 0x0000000000001000 */
+
+#define QIB_7322_RcvBufBase_offset 0x00000148UL
+/* Default value: 0x0000000000080000 */
+
+#define QIB_7322_RcvBufSize_offset 0x00000150UL
+/* Default value: 0x0000000000005000 */
+
+#define QIB_7322_RxIntMemBase_offset 0x00000158UL
+/* Default value: 0x0000000000077000 */
+
+#define QIB_7322_RxIntMemSize_offset 0x00000160UL
+/* Default value: 0x0000000000007000 */
+
+#define QIB_7322_encryption_key_low_offset 0x00000180UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_encryption_key_high_offset 0x00000188UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_feature_mask_offset 0x00000190UL
+/* Default value: 0x00000000000000XX */
+
+#define QIB_7322_active_feature_mask_offset 0x00000198UL
+struct QIB_7322_active_feature_mask_pb {
+	pseudo_bit_t Port0_SDR_Enabled[1];
+	pseudo_bit_t Port0_DDR_Enabled[1];
+	pseudo_bit_t Port0_QDR_Enabled[1];
+	pseudo_bit_t Port1_SDR_Enabled[1];
+	pseudo_bit_t Port1_DDR_Enabled[1];
+	pseudo_bit_t Port1_QDR_Enabled[1];
+	pseudo_bit_t _unused_0[58];
+};
+struct QIB_7322_active_feature_mask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_active_feature_mask_pb );
+};
+/* Default value: 0x00000000000000XX */
+
+#define QIB_7322_SendCtrl_offset 0x000001c0UL
+struct QIB_7322_SendCtrl_pb {
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t SendIntBufAvail[1];
+	pseudo_bit_t SendBufAvailUpd[1];
+	pseudo_bit_t _unused_1[1];
+	pseudo_bit_t SpecialTriggerEn[1];
+	pseudo_bit_t _unused_2[11];
+	pseudo_bit_t DisarmSendBuf[8];
+	pseudo_bit_t AvailUpdThld[5];
+	pseudo_bit_t SendBufAvailPad64Byte[1];
+	pseudo_bit_t _unused_3[1];
+	pseudo_bit_t Disarm[1];
+	pseudo_bit_t _unused_4[32];
+};
+struct QIB_7322_SendCtrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCtrl_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufBase_offset 0x000001c8UL
+struct QIB_7322_SendBufBase_pb {
+	pseudo_bit_t BaseAddr_SmallPIO[21];
+	pseudo_bit_t _unused_0[11];
+	pseudo_bit_t BaseAddr_LargePIO[21];
+	pseudo_bit_t _unused_1[11];
+};
+struct QIB_7322_SendBufBase {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufBase_pb );
+};
+/* Default value: 0x0018000000100000 */
+
+#define QIB_7322_SendBufSize_offset 0x000001d0UL
+struct QIB_7322_SendBufSize_pb {
+	pseudo_bit_t Size_SmallPIO[12];
+	pseudo_bit_t _unused_0[20];
+	pseudo_bit_t Size_LargePIO[13];
+	pseudo_bit_t _unused_1[19];
+};
+struct QIB_7322_SendBufSize {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufSize_pb );
+};
+/* Default value: 0x0000108000000880 */
+
+#define QIB_7322_SendBufCnt_offset 0x000001d8UL
+struct QIB_7322_SendBufCnt_pb {
+	pseudo_bit_t Num_SmallBuffers[9];
+	pseudo_bit_t _unused_0[23];
+	pseudo_bit_t Num_LargeBuffers[6];
+	pseudo_bit_t _unused_1[26];
+};
+struct QIB_7322_SendBufCnt {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufCnt_pb );
+};
+/* Default value: 0x0000002000000080 */
+
+#define QIB_7322_SendBufAvailAddr_offset 0x000001e0UL
+struct QIB_7322_SendBufAvailAddr_pb {
+	pseudo_bit_t _unused_0[6];
+	pseudo_bit_t SendBufAvailAddr[34];
+	pseudo_bit_t _unused_1[24];
+};
+struct QIB_7322_SendBufAvailAddr {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufAvailAddr_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxIntMemBase_offset 0x000001e8UL
+/* Default value: 0x0000000000064000 */
+
+#define QIB_7322_TxIntMemSize_offset 0x000001f0UL
+/* Default value: 0x000000000000C000 */
+
+#define QIB_7322_SendBufErr0_offset 0x00000240UL
+struct QIB_7322_SendBufErr0_pb {
+	pseudo_bit_t SendBufErr_63_0[64];
+};
+struct QIB_7322_SendBufErr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufErr0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_AvailUpdCount_offset 0x00000268UL
+struct QIB_7322_AvailUpdCount_pb {
+	pseudo_bit_t AvailUpdCount[5];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_AvailUpdCount {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_AvailUpdCount_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrAddr0_offset 0x00000280UL
+struct QIB_7322_RcvHdrAddr0_pb {
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvHdrAddr[38];
+	pseudo_bit_t _unused_1[24];
+};
+struct QIB_7322_RcvHdrAddr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrAddr0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTailAddr0_offset 0x00000340UL
+struct QIB_7322_RcvHdrTailAddr0_pb {
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvHdrTailAddr[38];
+	pseudo_bit_t _unused_1[24];
+};
+struct QIB_7322_RcvHdrTailAddr0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrTailAddr0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_EEPCtlStat_offset 0x000003e8UL
+struct QIB_7322_EEPCtlStat_pb {
+	pseudo_bit_t EPAccEn[2];
+	pseudo_bit_t EPReset[1];
+	pseudo_bit_t ByteProg[1];
+	pseudo_bit_t PageMode[1];
+	pseudo_bit_t LstDatWr[1];
+	pseudo_bit_t CmdWrErr[1];
+	pseudo_bit_t _unused_0[24];
+	pseudo_bit_t CtlrStat[1];
+	pseudo_bit_t _unused_1[32];
+};
+struct QIB_7322_EEPCtlStat {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_EEPCtlStat_pb );
+};
+/* Default value: 0x0000000000000002 */
+
+#define QIB_7322_EEPAddrCmd_offset 0x000003f0UL
+struct QIB_7322_EEPAddrCmd_pb {
+	pseudo_bit_t EPAddr[24];
+	pseudo_bit_t EPCmd[8];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7322_EEPAddrCmd {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_EEPAddrCmd_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_EEPData_offset 0x000003f8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_efuse_control_reg_offset 0x00000410UL
+struct QIB_7322_efuse_control_reg_pb {
+	pseudo_bit_t address[11];
+	pseudo_bit_t last_program_address[11];
+	pseudo_bit_t operation[2];
+	pseudo_bit_t start_operation[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t req_err[1];
+	pseudo_bit_t read_data_valid[1];
+	pseudo_bit_t rdy[1];
+	pseudo_bit_t _unused_1[32];
+};
+struct QIB_7322_efuse_control_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_efuse_control_reg_pb );
+};
+/* Default value: 0x0000000080000000 */
+
+#define QIB_7322_efuse_data_reg_offset 0x00000418UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_voltage_margin_reg_offset 0x00000428UL
+struct QIB_7322_voltage_margin_reg_pb {
+	pseudo_bit_t voltage_margin_settings_enable[1];
+	pseudo_bit_t voltage_margin_settings[2];
+	pseudo_bit_t _unused_0[61];
+};
+struct QIB_7322_voltage_margin_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_voltage_margin_reg_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_VTSense_reg_offset 0x00000430UL
+struct QIB_7322_VTSense_reg_pb {
+	pseudo_bit_t temp_sense_select[3];
+	pseudo_bit_t adc_mode[1];
+	pseudo_bit_t start_busy[1];
+	pseudo_bit_t power_down[1];
+	pseudo_bit_t threshold[10];
+	pseudo_bit_t sensor_output_data[10];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t threshold_limbit[1];
+	pseudo_bit_t _unused_1[3];
+	pseudo_bit_t output_valid[1];
+	pseudo_bit_t _unused_2[32];
+};
+struct QIB_7322_VTSense_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_VTSense_reg_pb );
+};
+/* Default value: 0x0000000000000020 */
+
+#define QIB_7322_procmon_reg_offset 0x00000438UL
+struct QIB_7322_procmon_reg_pb {
+	pseudo_bit_t ring_osc_select[3];
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t start_counter[1];
+	pseudo_bit_t procmon_count[12];
+	pseudo_bit_t _unused_1[3];
+	pseudo_bit_t procmon_count_valid[1];
+	pseudo_bit_t _unused_2[32];
+};
+struct QIB_7322_procmon_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_procmon_reg_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRbufTestReg0_offset 0x00000440UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ahb_access_ctrl_offset 0x00000460UL
+struct QIB_7322_ahb_access_ctrl_pb {
+	pseudo_bit_t sw_ahb_sel[1];
+	pseudo_bit_t sw_sel_ahb_trgt[2];
+	pseudo_bit_t _unused_0[61];
+};
+struct QIB_7322_ahb_access_ctrl {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ahb_access_ctrl_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ahb_transaction_reg_offset 0x00000468UL
+struct QIB_7322_ahb_transaction_reg_pb {
+	pseudo_bit_t _unused_0[16];
+	pseudo_bit_t ahb_address[11];
+	pseudo_bit_t write_not_read[1];
+	pseudo_bit_t _unused_1[2];
+	pseudo_bit_t ahb_req_err[1];
+	pseudo_bit_t ahb_rdy[1];
+	pseudo_bit_t ahb_data[32];
+};
+struct QIB_7322_ahb_transaction_reg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ahb_transaction_reg_pb );
+};
+/* Default value: 0x0000000080000000 */
+
+#define QIB_7322_SPC_JTAG_ACCESS_REG_offset 0x00000470UL
+struct QIB_7322_SPC_JTAG_ACCESS_REG_pb {
+	pseudo_bit_t rdy[1];
+	pseudo_bit_t tdo[1];
+	pseudo_bit_t tdi[1];
+	pseudo_bit_t opcode[2];
+	pseudo_bit_t bist_en[5];
+	pseudo_bit_t SPC_JTAG_ACCESS_EN[1];
+	pseudo_bit_t _unused_0[53];
+};
+struct QIB_7322_SPC_JTAG_ACCESS_REG {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SPC_JTAG_ACCESS_REG_pb );
+};
+/* Default value: 0x0000000000000001 */
+
+#define QIB_7322_LAControlReg_offset 0x00000478UL
+struct QIB_7322_LAControlReg_pb {
+	pseudo_bit_t Finished[1];
+	pseudo_bit_t Address[9];
+	pseudo_bit_t Mode[2];
+	pseudo_bit_t Delay[20];
+	pseudo_bit_t Finished_sc[1];
+	pseudo_bit_t Address_sc[9];
+	pseudo_bit_t Mode_sc[2];
+	pseudo_bit_t Delay_sc[20];
+};
+struct QIB_7322_LAControlReg {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LAControlReg_pb );
+};
+/* Default value: 0x0000000100000001 */
+
+#define QIB_7322_PcieRhdrTestReg0_offset 0x00000480UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendCheckMask0_offset 0x000004c0UL
+struct QIB_7322_SendCheckMask0_pb {
+	pseudo_bit_t SendCheckMask_63_32[64];
+};
+struct QIB_7322_SendCheckMask0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCheckMask0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendGRHCheckMask0_offset 0x000004e0UL
+struct QIB_7322_SendGRHCheckMask0_pb {
+	pseudo_bit_t SendGRHCheckMask_63_32[64];
+};
+struct QIB_7322_SendGRHCheckMask0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendGRHCheckMask0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendIBPacketMask0_offset 0x00000500UL
+struct QIB_7322_SendIBPacketMask0_pb {
+	pseudo_bit_t SendIBPacketMask_63_32[64];
+};
+struct QIB_7322_SendIBPacketMask0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendIBPacketMask0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IntRedirect0_offset 0x00000540UL
+struct QIB_7322_IntRedirect0_pb {
+	pseudo_bit_t vec0[5];
+	pseudo_bit_t vec1[5];
+	pseudo_bit_t vec2[5];
+	pseudo_bit_t vec3[5];
+	pseudo_bit_t vec4[5];
+	pseudo_bit_t vec5[5];
+	pseudo_bit_t vec6[5];
+	pseudo_bit_t vec7[5];
+	pseudo_bit_t vec8[5];
+	pseudo_bit_t vec9[5];
+	pseudo_bit_t vec10[5];
+	pseudo_bit_t vec11[5];
+	pseudo_bit_t _unused_0[4];
+};
+struct QIB_7322_IntRedirect0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IntRedirect0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_Int_Granted_offset 0x00000570UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_vec_clr_without_int_offset 0x00000578UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlA_offset 0x00000580UL
+struct QIB_7322_DCACtrlA_pb {
+	pseudo_bit_t RcvHdrqDCAEnable[1];
+	pseudo_bit_t EagerDCAEnable[1];
+	pseudo_bit_t RcvTailUpdDCAEnable[1];
+	pseudo_bit_t SendDMAHead0DCAEnable[1];
+	pseudo_bit_t SendDMAHead1DCAEnable[1];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_DCACtrlA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlB_offset 0x00000588UL
+struct QIB_7322_DCACtrlB_pb {
+	pseudo_bit_t RcvHdrq0DCAOPH[8];
+	pseudo_bit_t RcvHdrq0DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq1DCAOPH[8];
+	pseudo_bit_t RcvHdrq1DCAXfrCnt[6];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RcvHdrq2DCAOPH[8];
+	pseudo_bit_t RcvHdrq2DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq3DCAOPH[8];
+	pseudo_bit_t RcvHdrq3DCAXfrCnt[6];
+	pseudo_bit_t _unused_1[4];
+};
+struct QIB_7322_DCACtrlB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlC_offset 0x00000590UL
+struct QIB_7322_DCACtrlC_pb {
+	pseudo_bit_t RcvHdrq4DCAOPH[8];
+	pseudo_bit_t RcvHdrq4DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq5DCAOPH[8];
+	pseudo_bit_t RcvHdrq5DCAXfrCnt[6];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RcvHdrq6DCAOPH[8];
+	pseudo_bit_t RcvHdrq6DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq7DCAOPH[8];
+	pseudo_bit_t RcvHdrq7DCAXfrCnt[6];
+	pseudo_bit_t _unused_1[4];
+};
+struct QIB_7322_DCACtrlC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlD_offset 0x00000598UL
+struct QIB_7322_DCACtrlD_pb {
+	pseudo_bit_t RcvHdrq8DCAOPH[8];
+	pseudo_bit_t RcvHdrq8DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq9DCAOPH[8];
+	pseudo_bit_t RcvHdrq9DCAXfrCnt[6];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RcvHdrq10DCAOPH[8];
+	pseudo_bit_t RcvHdrq10DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq11DCAOPH[8];
+	pseudo_bit_t RcvHdrq11DCAXfrCnt[6];
+	pseudo_bit_t _unused_1[4];
+};
+struct QIB_7322_DCACtrlD {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlD_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlE_offset 0x000005a0UL
+struct QIB_7322_DCACtrlE_pb {
+	pseudo_bit_t RcvHdrq12DCAOPH[8];
+	pseudo_bit_t RcvHdrq12DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq13DCAOPH[8];
+	pseudo_bit_t RcvHdrq13DCAXfrCnt[6];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RcvHdrq14DCAOPH[8];
+	pseudo_bit_t RcvHdrq14DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq15DCAOPH[8];
+	pseudo_bit_t RcvHdrq15DCAXfrCnt[6];
+	pseudo_bit_t _unused_1[4];
+};
+struct QIB_7322_DCACtrlE {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlE_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DCACtrlF_offset 0x000005a8UL
+struct QIB_7322_DCACtrlF_pb {
+	pseudo_bit_t RcvHdrq16DCAOPH[8];
+	pseudo_bit_t RcvHdrq16DCAXfrCnt[6];
+	pseudo_bit_t RcvHdrq17DCAOPH[8];
+	pseudo_bit_t RcvHdrq17DCAXfrCnt[6];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SendDma0DCAOPH[8];
+	pseudo_bit_t SendDma1DCAOPH[8];
+	pseudo_bit_t _unused_1[16];
+};
+struct QIB_7322_DCACtrlF {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_DCACtrlF_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemErrCtrlA_offset 0x00000600UL
+struct QIB_7322_MemErrCtrlA_pb {
+	pseudo_bit_t FSSUncErrRcvBuf_0[1];
+	pseudo_bit_t FSSUncErrRcvFlags_0[1];
+	pseudo_bit_t FSSUncErrLookupiqBuf_0[1];
+	pseudo_bit_t FSSUncErrRcvDMAHdrBuf_0[1];
+	pseudo_bit_t FSSUncErrRcvDMADataBuf_0[1];
+	pseudo_bit_t FSSUncErrRcvBuf_1[1];
+	pseudo_bit_t FSSUncErrRcvFlags_1[1];
+	pseudo_bit_t FSSUncErrLookupiqBuf_1[1];
+	pseudo_bit_t FSSUncErrRcvDMAHdrBuf_1[1];
+	pseudo_bit_t FSSUncErrRcvDMADataBuf_1[1];
+	pseudo_bit_t FSSUncErrRcvTIDArray[1];
+	pseudo_bit_t FSSUncErrRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t FSSUncErrSendBufVL15[1];
+	pseudo_bit_t FSSUncErrSendBufMain[1];
+	pseudo_bit_t FSSUncErrSendBufExtra[1];
+	pseudo_bit_t FSSUncErrSendPbcArray[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO0_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO1_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO2_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO3_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO4_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO5_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO6_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO7_0[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO0_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO1_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO2_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO3_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO4_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO5_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO6_1[1];
+	pseudo_bit_t FSSUncErrSendLaFIFO7_1[1];
+	pseudo_bit_t FSSUncErrSendRmFIFO_0[1];
+	pseudo_bit_t FSSUncErrSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t FSSUncErrPCIeRetryBuf[1];
+	pseudo_bit_t FSSUncErrPCIePostHdrBuf[1];
+	pseudo_bit_t FSSUncErrPCIePostDataBuf[1];
+	pseudo_bit_t FSSUncErrPCIeCompHdrBuf[1];
+	pseudo_bit_t FSSUncErrPCIeCompDataBuf[1];
+	pseudo_bit_t FSSUncErrMsixTable0[1];
+	pseudo_bit_t FSSUncErrMsixTable1[1];
+	pseudo_bit_t FSSUncErrMsixTable2[1];
+	pseudo_bit_t _unused_2[4];
+	pseudo_bit_t SwapEccDataMsixBits[1];
+	pseudo_bit_t SwapEccDataExtraBits[1];
+	pseudo_bit_t DisableEccCorrection[1];
+	pseudo_bit_t SwapEccDataBits[1];
+};
+struct QIB_7322_MemErrCtrlA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemErrCtrlA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemErrCtrlB_offset 0x00000608UL
+struct QIB_7322_MemErrCtrlB_pb {
+	pseudo_bit_t FSSCorErrRcvBuf_0[1];
+	pseudo_bit_t FSSCorErrRcvFlags_0[1];
+	pseudo_bit_t FSSCorErrLookupiqBuf_0[1];
+	pseudo_bit_t FSSCorErrRcvDMAHdrBuf_0[1];
+	pseudo_bit_t FSSCorErrRcvDMADataBuf_0[1];
+	pseudo_bit_t FSSCorErrRcvBuf_1[1];
+	pseudo_bit_t FSSCorErrRcvFlags_1[1];
+	pseudo_bit_t FSSCorErrLookupiqBuf_1[1];
+	pseudo_bit_t FSSCorErrRcvDMAHdrBuf_1[1];
+	pseudo_bit_t FSSCorErrRcvDMADataBuf_1[1];
+	pseudo_bit_t FSSCorErrRcvTIDArray[1];
+	pseudo_bit_t FSSCorErrRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t FSSCorErrSendBufVL15[1];
+	pseudo_bit_t FSSCorErrSendBufMain[1];
+	pseudo_bit_t FSSCorErrSendBufExtra[1];
+	pseudo_bit_t FSSCorErrSendPbcArray[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO0_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO1_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO2_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO3_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO4_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO5_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO6_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO7_0[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO0_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO1_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO2_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO3_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO4_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO5_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO6_1[1];
+	pseudo_bit_t FSSCorErrSendLaFIFO7_1[1];
+	pseudo_bit_t FSSCorErrSendRmFIFO_0[1];
+	pseudo_bit_t FSSCorErrSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t FSSCorErrPCIeRetryBuf[1];
+	pseudo_bit_t FSSCorErrPCIePostHdrBuf[1];
+	pseudo_bit_t FSSCorErrPCIePostDataBuf[1];
+	pseudo_bit_t FSSCorErrPCIeCompHdrBuf[1];
+	pseudo_bit_t FSSCorErrPCIeCompDataBuf[1];
+	pseudo_bit_t FSSCorErrMsixTable0[1];
+	pseudo_bit_t FSSCorErrMsixTable1[1];
+	pseudo_bit_t FSSCorErrMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemErrCtrlB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemErrCtrlB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiUnCorErrMask_offset 0x00000610UL
+struct QIB_7322_MemMultiUnCorErrMask_pb {
+	pseudo_bit_t MulUncErrMskRcvBuf_0[1];
+	pseudo_bit_t MulUncErrMskRcvFlags_0[1];
+	pseudo_bit_t MulUncErrMskLookupiqBuf_0[1];
+	pseudo_bit_t MulUncErrMskRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulUncErrMskRcvDMADataBuf_0[1];
+	pseudo_bit_t MulUncErrMskRcvBuf_1[1];
+	pseudo_bit_t MulUncErrMskRcvFlags_1[1];
+	pseudo_bit_t MulUncErrMskLookupiqBuf_1[1];
+	pseudo_bit_t MulUncErrMskRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulUncErrMskRcvDMADataBuf_1[1];
+	pseudo_bit_t MulUncErrMskRcvTIDArray[1];
+	pseudo_bit_t MulUncErrMskRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulUncErrMskSendBufVL15[1];
+	pseudo_bit_t MulUncErrMskSendBufMain[1];
+	pseudo_bit_t MulUncErrMskSendBufExtra[1];
+	pseudo_bit_t MulUncErrMskSendPbcArray[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO0_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO1_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO2_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO3_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO4_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO5_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO6_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO7_0[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO0_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO1_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO2_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO3_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO4_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO5_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO6_1[1];
+	pseudo_bit_t MulUncErrMskSendLaFIFO7_1[1];
+	pseudo_bit_t MulUncErrMskSendRmFIFO_0[1];
+	pseudo_bit_t MulUncErrMskSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulUncErrMskPCIeRetryBuf[1];
+	pseudo_bit_t MulUncErrMskPCIePostHdrBuf[1];
+	pseudo_bit_t MulUncErrMskPCIePostDataBuf[1];
+	pseudo_bit_t MulUncErrMskPCIeCompHdrBuf[1];
+	pseudo_bit_t MulUncErrMskPCIeCompDataBuf[1];
+	pseudo_bit_t MulUncErrMskMsixTable0[1];
+	pseudo_bit_t MulUncErrMskMsixTable1[1];
+	pseudo_bit_t MulUncErrMskMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiUnCorErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiUnCorErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiUnCorErrStatus_offset 0x00000618UL
+struct QIB_7322_MemMultiUnCorErrStatus_pb {
+	pseudo_bit_t MulUncErrStatusRcvBuf_0[1];
+	pseudo_bit_t MulUncErrStatusRcvFlags_0[1];
+	pseudo_bit_t MulUncErrStatusLookupiqBuf_0[1];
+	pseudo_bit_t MulUncErrStatusRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulUncErrStatusRcvDMADataBuf_0[1];
+	pseudo_bit_t MulUncErrStatusRcvBuf_1[1];
+	pseudo_bit_t MulUncErrStatusRcvFlags_1[1];
+	pseudo_bit_t MulUncErrStatusLookupiqBuf_1[1];
+	pseudo_bit_t MulUncErrStatusRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulUncErrStatusRcvDMADataBuf_1[1];
+	pseudo_bit_t MulUncErrStatusRcvTIDArray[1];
+	pseudo_bit_t MulUncErrStatusRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulUncErrStatusSendBufVL15[1];
+	pseudo_bit_t MulUncErrStatusSendBufMain[1];
+	pseudo_bit_t MulUncErrStatusSendBufExtra[1];
+	pseudo_bit_t MulUncErrStatusSendPbcArray[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO0_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO1_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO2_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO3_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO4_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO5_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO6_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO7_0[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO0_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO1_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO2_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO3_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO4_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO5_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO6_1[1];
+	pseudo_bit_t MulUncErrStatusSendLaFIFO7_1[1];
+	pseudo_bit_t MulUncErrStatusSendRmFIFO_0[1];
+	pseudo_bit_t MulUncErrStatusSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulUncErrStatusPCIeRetryBuf[1];
+	pseudo_bit_t MulUncErrStatusPCIePostHdrBuf[1];
+	pseudo_bit_t MulUncErrStatusPCIePostDataBuf[1];
+	pseudo_bit_t MulUncErrStatusPCIeCompHdrBuf[1];
+	pseudo_bit_t MulUncErrStatusPCIeCompDataBuf[1];
+	pseudo_bit_t MulUncErrStatusMsixTable0[1];
+	pseudo_bit_t MulUncErrStatusMsixTable1[1];
+	pseudo_bit_t MulUncErrStatusMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiUnCorErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiUnCorErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiUnCorErrClear_offset 0x00000620UL
+struct QIB_7322_MemMultiUnCorErrClear_pb {
+	pseudo_bit_t MulUncErrClearRcvBuf_0[1];
+	pseudo_bit_t MulUncErrClearRcvFlags_0[1];
+	pseudo_bit_t MulUncErrClearLookupiqBuf_0[1];
+	pseudo_bit_t MulUncErrClearRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulUncErrClearRcvDMADataBuf_0[1];
+	pseudo_bit_t MulUncErrClearRcvBuf_1[1];
+	pseudo_bit_t MulUncErrClearRcvFlags_1[1];
+	pseudo_bit_t MulUncErrClearLookupiqBuf_1[1];
+	pseudo_bit_t MulUncErrClearRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulUncErrClearRcvDMADataBuf_1[1];
+	pseudo_bit_t MulUncErrClearRcvTIDArray[1];
+	pseudo_bit_t MulUncErrClearRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulUncErrClearSendBufVL15[1];
+	pseudo_bit_t MulUncErrClearSendBufMain[1];
+	pseudo_bit_t MulUncErrClearSendBufExtra[1];
+	pseudo_bit_t MulUncErrClearSendPbcArray[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO0_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO1_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO2_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO3_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO4_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO5_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO6_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO7_0[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO0_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO1_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO2_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO3_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO4_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO5_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO6_1[1];
+	pseudo_bit_t MulUncErrClearSendLaFIFO7_1[1];
+	pseudo_bit_t MulUncErrClearSendRmFIFO_0[1];
+	pseudo_bit_t MulUncErrClearSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulUncErrClearPCIeRetryBuf[1];
+	pseudo_bit_t MulUncErrClearPCIePostHdrBuf[1];
+	pseudo_bit_t MulUncErrClearPCIePostDataBuf[1];
+	pseudo_bit_t MulUncErrClearPCIeCompHdrBuf[1];
+	pseudo_bit_t MulUncErrClearPCIeCompDataBuf[1];
+	pseudo_bit_t MulUncErrClearMsixTable0[1];
+	pseudo_bit_t MulUncErrClearMsixTable1[1];
+	pseudo_bit_t MulUncErrClearMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiUnCorErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiUnCorErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemUnCorErrMask_offset 0x00000628UL
+struct QIB_7322_MemUnCorErrMask_pb {
+	pseudo_bit_t UncErrMskRcvBuf_0[1];
+	pseudo_bit_t UncErrMskRcvFlags_0[1];
+	pseudo_bit_t UncErrMskLookupiqBuf_0[1];
+	pseudo_bit_t UncErrMskRcvDMAHdrBuf_0[1];
+	pseudo_bit_t UncErrMskRcvDMADataBuf_0[1];
+	pseudo_bit_t UncErrMskRcvBuf_1[1];
+	pseudo_bit_t UncErrMskRcvFlags_1[1];
+	pseudo_bit_t UncErrMskLookupiqBuf_1[1];
+	pseudo_bit_t UncErrMskRcvDMAHdrBuf_1[1];
+	pseudo_bit_t UncErrMskRcvDMADataBuf_1[1];
+	pseudo_bit_t UncErrMskRcvTIDArray[1];
+	pseudo_bit_t UncErrMskRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t UncErrMskSendBufVL15[1];
+	pseudo_bit_t UncErrMskSendBufMain[1];
+	pseudo_bit_t UncErrMskSendBufExtra[1];
+	pseudo_bit_t UncErrMskSendPbcArray[1];
+	pseudo_bit_t UncErrMskSendLaFIFO0_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO1_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO2_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO3_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO4_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO5_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO6_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO7_0[1];
+	pseudo_bit_t UncErrMskSendLaFIFO0_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO1_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO2_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO3_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO4_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO5_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO6_1[1];
+	pseudo_bit_t UncErrMskSendLaFIFO7_1[1];
+	pseudo_bit_t UncErrMskSendRmFIFO_0[1];
+	pseudo_bit_t UncErrMskSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t UncErrMskPCIeRetryBuf[1];
+	pseudo_bit_t UncErrMskPCIePostHdrBuf[1];
+	pseudo_bit_t UncErrMskPCIePostDataBuf[1];
+	pseudo_bit_t UncErrMskPCIeCompHdrBuf[1];
+	pseudo_bit_t UncErrMskPCIeCompDataBuf[1];
+	pseudo_bit_t UncErrMskMsixTable0[1];
+	pseudo_bit_t UncErrMskMsixTable1[1];
+	pseudo_bit_t UncErrMskMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemUnCorErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemUnCorErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemUnCorErrStatus_offset 0x00000630UL
+struct QIB_7322_MemUnCorErrStatus_pb {
+	pseudo_bit_t UncErrStatusRcvBuf_0[1];
+	pseudo_bit_t UncErrStatusRcvFlags_0[1];
+	pseudo_bit_t UncErrStatusLookupiqBuf_0[1];
+	pseudo_bit_t UncErrStatusRcvDMAHdrBuf_0[1];
+	pseudo_bit_t UncErrStatusRcvDMADataBuf_0[1];
+	pseudo_bit_t UncErrStatusRcvBuf_1[1];
+	pseudo_bit_t UncErrStatusRcvFlags_1[1];
+	pseudo_bit_t UncErrStatusLookupiqBuf_1[1];
+	pseudo_bit_t UncErrStatusRcvDMAHdrBuf_1[1];
+	pseudo_bit_t UncErrStatusRcvDMADataBuf_1[1];
+	pseudo_bit_t UncErrStatusRcvTIDArray[1];
+	pseudo_bit_t UncErrStatusRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t UncErrStatusSendBufVL15[1];
+	pseudo_bit_t UncErrStatusSendBufMain[1];
+	pseudo_bit_t UncErrStatusSendBufExtra[1];
+	pseudo_bit_t UncErrStatusSendPbcArray[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO0_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO1_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO2_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO3_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO4_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO5_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO6_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO7_0[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO0_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO1_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO2_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO3_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO4_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO5_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO6_1[1];
+	pseudo_bit_t UncErrStatusSendLaFIFO7_1[1];
+	pseudo_bit_t UncErrStatusSendRmFIFO_0[1];
+	pseudo_bit_t UncErrStatusSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t UncErrStatusPCIeRetryBuf[1];
+	pseudo_bit_t UncErrStatusPCIePostHdrBuf[1];
+	pseudo_bit_t UncErrStatusPCIePostDataBuf[1];
+	pseudo_bit_t UncErrStatusPCIeCompHdrBuf[1];
+	pseudo_bit_t UncErrStatusPCIeCompDataBuf[1];
+	pseudo_bit_t UncErrStatusMsixTable0[1];
+	pseudo_bit_t UncErrStatusMsixTable1[1];
+	pseudo_bit_t UncErrStatusMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemUnCorErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemUnCorErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemUnCorErrClear_offset 0x00000638UL
+struct QIB_7322_MemUnCorErrClear_pb {
+	pseudo_bit_t UncErrClearRcvBuf_0[1];
+	pseudo_bit_t UncErrClearRcvFlags_0[1];
+	pseudo_bit_t UncErrClearLookupiqBuf_0[1];
+	pseudo_bit_t UncErrClearRcvDMAHdrBuf_0[1];
+	pseudo_bit_t UncErrClearRcvDMADataBuf_0[1];
+	pseudo_bit_t UncErrClearRcvBuf_1[1];
+	pseudo_bit_t UncErrClearRcvFlags_1[1];
+	pseudo_bit_t UncErrClearLookupiqBuf_1[1];
+	pseudo_bit_t UncErrClearRcvDMAHdrBuf_1[1];
+	pseudo_bit_t UncErrClearRcvDMADataBuf_1[1];
+	pseudo_bit_t UncErrClearRcvTIDArray[1];
+	pseudo_bit_t UncErrClearRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t UncErrClearSendBufVL15[1];
+	pseudo_bit_t UncErrClearSendBufMain[1];
+	pseudo_bit_t UncErrClearSendBufExtra[1];
+	pseudo_bit_t UncErrClearSendPbcArray[1];
+	pseudo_bit_t UncErrClearSendLaFIFO0_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO1_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO2_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO3_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO4_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO5_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO6_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO7_0[1];
+	pseudo_bit_t UncErrClearSendLaFIFO0_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO1_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO2_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO3_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO4_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO5_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO6_1[1];
+	pseudo_bit_t UncErrClearSendLaFIFO7_1[1];
+	pseudo_bit_t UncErrClearSendRmFIFO_0[1];
+	pseudo_bit_t UncErrClearSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t UncErrClearPCIeRetryBuf[1];
+	pseudo_bit_t UncErrClearPCIePostHdrBuf[1];
+	pseudo_bit_t UncErrClearPCIePostDataBuf[1];
+	pseudo_bit_t UncErrClearPCIeCompHdrBuf[1];
+	pseudo_bit_t UncErrClearPCIeCompDataBuf[1];
+	pseudo_bit_t UncErrClearMsixTable0[1];
+	pseudo_bit_t UncErrClearMsixTable1[1];
+	pseudo_bit_t UncErrClearMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemUnCorErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemUnCorErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiCorErrMask_offset 0x00000640UL
+struct QIB_7322_MemMultiCorErrMask_pb {
+	pseudo_bit_t MulCorErrMskRcvBuf_0[1];
+	pseudo_bit_t MulCorErrMskRcvFlags_0[1];
+	pseudo_bit_t MulCorErrMskLookupiqBuf_0[1];
+	pseudo_bit_t MulCorErrMskRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulCorErrMskRcvDMADataBuf_0[1];
+	pseudo_bit_t MulCorErrMskRcvBuf_1[1];
+	pseudo_bit_t MulCorErrMskRcvFlags_1[1];
+	pseudo_bit_t MulCorErrMskLookupiqBuf_1[1];
+	pseudo_bit_t MulCorErrMskRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulCorErrMskRcvDMADataBuf_1[1];
+	pseudo_bit_t MulCorErrMskRcvTIDArray[1];
+	pseudo_bit_t MulCorErrMskRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulCorErrMskSendBufVL15[1];
+	pseudo_bit_t MulCorErrMskSendBufMain[1];
+	pseudo_bit_t MulCorErrMskSendBufExtra[1];
+	pseudo_bit_t MulCorErrMskSendPbcArray[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO0_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO1_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO2_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO3_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO4_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO5_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO6_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO7_0[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO0_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO1_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO2_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO3_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO4_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO5_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO6_1[1];
+	pseudo_bit_t MulCorErrMskSendLaFIFO7_1[1];
+	pseudo_bit_t MulCorErrMskSendRmFIFO_0[1];
+	pseudo_bit_t MulCorErrMskSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulCorErrMskPCIeRetryBuf[1];
+	pseudo_bit_t MulCorErrMskPCIePostHdrBuf[1];
+	pseudo_bit_t MulCorErrMskPCIePostDataBuf[1];
+	pseudo_bit_t MulCorErrMskPCIeCompHdrBuf[1];
+	pseudo_bit_t MulCorErrMskPCIeCompDataBuf[1];
+	pseudo_bit_t MulCorErrMskMsixTable0[1];
+	pseudo_bit_t MulCorErrMskMsixTable1[1];
+	pseudo_bit_t MulCorErrMskMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiCorErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiCorErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiCorErrStatus_offset 0x00000648UL
+struct QIB_7322_MemMultiCorErrStatus_pb {
+	pseudo_bit_t MulCorErrStatusRcvBuf_0[1];
+	pseudo_bit_t MulCorErrStatusRcvFlags_0[1];
+	pseudo_bit_t MulCorErrStatusLookupiqBuf_0[1];
+	pseudo_bit_t MulCorErrStatusRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulCorErrStatusRcvDMADataBuf_0[1];
+	pseudo_bit_t MulCorErrStatusRcvBuf_1[1];
+	pseudo_bit_t MulCorErrStatusRcvFlags_1[1];
+	pseudo_bit_t MulCorErrStatusLookupiqBuf_1[1];
+	pseudo_bit_t MulCorErrStatusRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulCorErrStatusRcvDMADataBuf_1[1];
+	pseudo_bit_t MulCorErrStatusRcvTIDArray[1];
+	pseudo_bit_t MulCorErrStatusRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulCorErrStatusSendBufVL15[1];
+	pseudo_bit_t MulCorErrStatusSendBufMain[1];
+	pseudo_bit_t MulCorErrStatusSendBufExtra[1];
+	pseudo_bit_t MulCorErrStatusSendPbcArray[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO0_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO1_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO2_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO3_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO4_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO5_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO6_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO7_0[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO0_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO1_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO2_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO3_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO4_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO5_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO6_1[1];
+	pseudo_bit_t MulCorErrStatusSendLaFIFO7_1[1];
+	pseudo_bit_t MulCorErrStatusSendRmFIFO_0[1];
+	pseudo_bit_t MulCorErrStatusSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulCorErrStatusPCIeRetryBuf[1];
+	pseudo_bit_t MulCorErrStatusPCIePostHdrBuf[1];
+	pseudo_bit_t MulCorErrStatusPCIePostDataBuf[1];
+	pseudo_bit_t MulCorErrStatusPCIeCompHdrBuf[1];
+	pseudo_bit_t MulCorErrStatusPCIeCompDataBuf[1];
+	pseudo_bit_t MulCorErrStatusMsixTable0[1];
+	pseudo_bit_t MulCorErrStatusMsixTable1[1];
+	pseudo_bit_t MulCorErrStatusMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiCorErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiCorErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemMultiCorErrClear_offset 0x00000650UL
+struct QIB_7322_MemMultiCorErrClear_pb {
+	pseudo_bit_t MulCorErrClearRcvBuf_0[1];
+	pseudo_bit_t MulCorErrClearRcvFlags_0[1];
+	pseudo_bit_t MulCorErrClearLookupiqBuf_0[1];
+	pseudo_bit_t MulCorErrClearRcvDMAHdrBuf_0[1];
+	pseudo_bit_t MulCorErrClearRcvDMADataBuf_0[1];
+	pseudo_bit_t MulCorErrClearRcvBuf_1[1];
+	pseudo_bit_t MulCorErrClearRcvFlags_1[1];
+	pseudo_bit_t MulCorErrClearLookupiqBuf_1[1];
+	pseudo_bit_t MulCorErrClearRcvDMAHdrBuf_1[1];
+	pseudo_bit_t MulCorErrClearRcvDMADataBuf_1[1];
+	pseudo_bit_t MulCorErrClearRcvTIDArray[1];
+	pseudo_bit_t MulCorErrClearRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t MulCorErrClearSendBufVL15[1];
+	pseudo_bit_t MulCorErrClearSendBufMain[1];
+	pseudo_bit_t MulCorErrClearSendBufExtra[1];
+	pseudo_bit_t MulCorErrClearSendPbcArray[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO0_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO1_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO2_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO3_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO4_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO5_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO6_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO7_0[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO0_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO1_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO2_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO3_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO4_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO5_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO6_1[1];
+	pseudo_bit_t MulCorErrClearSendLaFIFO7_1[1];
+	pseudo_bit_t MulCorErrClearSendRmFIFO_0[1];
+	pseudo_bit_t MulCorErrClearSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t MulCorErrClearPCIeRetryBuf[1];
+	pseudo_bit_t MulCorErrClearPCIePostHdrBuf[1];
+	pseudo_bit_t MulCorErrClearPCIePostDataBuf[1];
+	pseudo_bit_t MulCorErrClearPCIeCompHdrBuf[1];
+	pseudo_bit_t MulCorErrClearPCIeCompDataBuf[1];
+	pseudo_bit_t MulCorErrClearMsixTable0[1];
+	pseudo_bit_t MulCorErrClearMsixTable1[1];
+	pseudo_bit_t MulCorErrClearMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemMultiCorErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemMultiCorErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemCorErrMask_offset 0x00000658UL
+struct QIB_7322_MemCorErrMask_pb {
+	pseudo_bit_t CorErrMskRcvBuf_0[1];
+	pseudo_bit_t CorErrMskRcvFlags_0[1];
+	pseudo_bit_t CorErrMskLookupiqBuf_0[1];
+	pseudo_bit_t CorErrMskRcvDMAHdrBuf_0[1];
+	pseudo_bit_t CorErrMskRcvDMADataBuf_0[1];
+	pseudo_bit_t CorErrMskRcvBuf_1[1];
+	pseudo_bit_t CorErrMskRcvFlags_1[1];
+	pseudo_bit_t CorErrMskLookupiqBuf_1[1];
+	pseudo_bit_t CorErrMskRcvDMAHdrBuf_1[1];
+	pseudo_bit_t CorErrMskRcvDMADataBuf_1[1];
+	pseudo_bit_t CorErrMskRcvTIDArray[1];
+	pseudo_bit_t CorErrMskRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t CorErrMskSendBufVL15[1];
+	pseudo_bit_t CorErrMskSendBufMain[1];
+	pseudo_bit_t CorErrMskSendBufExtra[1];
+	pseudo_bit_t CorErrMskSendPbcArray[1];
+	pseudo_bit_t CorErrMskSendLaFIFO0_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO1_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO2_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO3_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO4_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO5_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO6_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO7_0[1];
+	pseudo_bit_t CorErrMskSendLaFIFO0_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO1_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO2_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO3_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO4_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO5_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO6_1[1];
+	pseudo_bit_t CorErrMskSendLaFIFO7_1[1];
+	pseudo_bit_t CorErrMskSendRmFIFO_0[1];
+	pseudo_bit_t CorErrMskSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t CorErrMskPCIeRetryBuf[1];
+	pseudo_bit_t CorErrMskPCIePostHdrBuf[1];
+	pseudo_bit_t CorErrMskPCIePostDataBuf[1];
+	pseudo_bit_t CorErrMskPCIeCompHdrBuf[1];
+	pseudo_bit_t CorErrMskPCIeCompDataBuf[1];
+	pseudo_bit_t CorErrMskMsixTable0[1];
+	pseudo_bit_t CorErrMskMsixTable1[1];
+	pseudo_bit_t CorErrMskMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemCorErrMask {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemCorErrMask_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemCorErrStatus_offset 0x00000660UL
+struct QIB_7322_MemCorErrStatus_pb {
+	pseudo_bit_t CorErrStatusRcvBuf_0[1];
+	pseudo_bit_t CorErrStatusRcvFlags_0[1];
+	pseudo_bit_t CorErrStatusLookupiqBuf_0[1];
+	pseudo_bit_t CorErrStatusRcvDMAHdrBuf_0[1];
+	pseudo_bit_t CorErrStatusRcvDMADataBuf_0[1];
+	pseudo_bit_t CorErrStatusRcvBuf_1[1];
+	pseudo_bit_t CorErrStatusRcvFlags_1[1];
+	pseudo_bit_t CorErrStatusLookupiqBuf_1[1];
+	pseudo_bit_t CorErrStatusRcvDMAHdrBuf_1[1];
+	pseudo_bit_t CorErrStatusRcvDMADataBuf_1[1];
+	pseudo_bit_t CorErrStatusRcvTIDArray[1];
+	pseudo_bit_t CorErrStatusRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t CorErrStatusSendBufVL15[1];
+	pseudo_bit_t CorErrStatusSendBufMain[1];
+	pseudo_bit_t CorErrStatusSendBufExtra[1];
+	pseudo_bit_t CorErrStatusSendPbcArray[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO0_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO1_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO2_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO3_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO4_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO5_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO6_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO7_0[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO0_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO1_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO2_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO3_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO4_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO5_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO6_1[1];
+	pseudo_bit_t CorErrStatusSendLaFIFO7_1[1];
+	pseudo_bit_t CorErrStatusSendRmFIFO_0[1];
+	pseudo_bit_t CorErrStatusSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t CorErrStatusPCIeRetryBuf[1];
+	pseudo_bit_t CorErrStatusPCIePostHdrBuf[1];
+	pseudo_bit_t CorErrStatusPCIePostDataBuf[1];
+	pseudo_bit_t CorErrStatusPCIeCompHdrBuf[1];
+	pseudo_bit_t CorErrStatusPCIeCompDataBuf[1];
+	pseudo_bit_t CorErrStatusMsixTable0[1];
+	pseudo_bit_t CorErrStatusMsixTable1[1];
+	pseudo_bit_t CorErrStatusMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemCorErrStatus {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemCorErrStatus_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MemCorErrClear_offset 0x00000668UL
+struct QIB_7322_MemCorErrClear_pb {
+	pseudo_bit_t CorErrClearRcvBuf_0[1];
+	pseudo_bit_t CorErrClearRcvFlags_0[1];
+	pseudo_bit_t CorErrClearLookupiqBuf_0[1];
+	pseudo_bit_t CorErrClearRcvDMAHdrBuf_0[1];
+	pseudo_bit_t CorErrClearRcvDMADataBuf_0[1];
+	pseudo_bit_t CorErrClearRcvBuf_1[1];
+	pseudo_bit_t CorErrClearRcvFlags_1[1];
+	pseudo_bit_t CorErrClearLookupiqBuf_1[1];
+	pseudo_bit_t CorErrClearRcvDMAHdrBuf_1[1];
+	pseudo_bit_t CorErrClearRcvDMADataBuf_1[1];
+	pseudo_bit_t CorErrClearRcvTIDArray[1];
+	pseudo_bit_t CorErrClearRcvEgrArray[1];
+	pseudo_bit_t _unused_0[3];
+	pseudo_bit_t CorErrClearSendBufVL15[1];
+	pseudo_bit_t CorErrClearSendBufMain[1];
+	pseudo_bit_t CorErrClearSendBufExtra[1];
+	pseudo_bit_t CorErrClearSendPbcArray[1];
+	pseudo_bit_t CorErrClearSendLaFIFO0_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO1_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO2_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO3_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO4_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO5_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO6_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO7_0[1];
+	pseudo_bit_t CorErrClearSendLaFIFO0_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO1_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO2_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO3_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO4_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO5_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO6_1[1];
+	pseudo_bit_t CorErrClearSendLaFIFO7_1[1];
+	pseudo_bit_t CorErrClearSendRmFIFO_0[1];
+	pseudo_bit_t CorErrClearSendRmFIFO_1[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t CorErrClearPCIeRetryBuf[1];
+	pseudo_bit_t CorErrClearPCIePostHdrBuf[1];
+	pseudo_bit_t CorErrClearPCIePostDataBuf[1];
+	pseudo_bit_t CorErrClearPCIeCompHdrBuf[1];
+	pseudo_bit_t CorErrClearPCIeCompDataBuf[1];
+	pseudo_bit_t CorErrClearMsixTable0[1];
+	pseudo_bit_t CorErrClearMsixTable1[1];
+	pseudo_bit_t CorErrClearMsixTable2[1];
+	pseudo_bit_t _unused_2[8];
+};
+struct QIB_7322_MemCorErrClear {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MemCorErrClear_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableUnCorErrLogA_offset 0x00000680UL
+struct QIB_7322_MsixTableUnCorErrLogA_pb {
+	pseudo_bit_t MsixTable_1_0_UnCorErrData[64];
+};
+struct QIB_7322_MsixTableUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableUnCorErrLogB_offset 0x00000688UL
+struct QIB_7322_MsixTableUnCorErrLogB_pb {
+	pseudo_bit_t MsixTable_2_UnCorErrData[32];
+	pseudo_bit_t MsixTable_0_UnCorErrCheckBits[7];
+	pseudo_bit_t MsixTable_1_UnCorErrCheckBits[7];
+	pseudo_bit_t MsixTable_2_UnCorErrCheckBits[7];
+	pseudo_bit_t _unused_0[11];
+};
+struct QIB_7322_MsixTableUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableUnCorErrLogC_offset 0x00000690UL
+struct QIB_7322_MsixTableUnCorErrLogC_pb {
+	pseudo_bit_t MsixTable_0_UnCorErrAddr[7];
+	pseudo_bit_t MsixTable_1_UnCorErrAddr[7];
+	pseudo_bit_t MsixTable_2_UnCorErrAddr[7];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_MsixTableUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixEntryWithUncorErr_offset 0x00000698UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableCorErrLogA_offset 0x000006a0UL
+struct QIB_7322_MsixTableCorErrLogA_pb {
+	pseudo_bit_t MsixTable_1_0_CorErrData[64];
+};
+struct QIB_7322_MsixTableCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableCorErrLogB_offset 0x000006a8UL
+struct QIB_7322_MsixTableCorErrLogB_pb {
+	pseudo_bit_t MsixTable_2_CorErrData[32];
+	pseudo_bit_t MsixTable_0_CorErrCheckBits[7];
+	pseudo_bit_t MsixTable_1_CorErrCheckBits[7];
+	pseudo_bit_t MsixTable_2_CorErrCheckBits[7];
+	pseudo_bit_t _unused_0[11];
+};
+struct QIB_7322_MsixTableCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTableCorErrLogC_offset 0x000006b0UL
+struct QIB_7322_MsixTableCorErrLogC_pb {
+	pseudo_bit_t MsixTable_0_CorErrAddr[7];
+	pseudo_bit_t MsixTable_1_CorErrAddr[7];
+	pseudo_bit_t MsixTable_2_CorErrAddr[7];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_MsixTableCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_MsixTableCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrUnCorErrLogA_offset 0x00000700UL
+struct QIB_7322_PcieCplDataBufrUnCorErrLogA_pb {
+	pseudo_bit_t PcieCplDataBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_PcieCplDataBufrUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrUnCorErrLogB_offset 0x00000708UL
+struct QIB_7322_PcieCplDataBufrUnCorErrLogB_pb {
+	pseudo_bit_t PcieCplDataBufrUnCorErrData_127_64[64];
+};
+struct QIB_7322_PcieCplDataBufrUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrUnCorErrLogC_offset 0x00000710UL
+struct QIB_7322_PcieCplDataBufrUnCorErrLogC_pb {
+	pseudo_bit_t PcieCplDataBufrUnCorErrData_136_128[9];
+	pseudo_bit_t PcieCplDataBufrUnCorErrCheckBit_21_0[22];
+	pseudo_bit_t PcieCplDataBufrUnCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[19];
+};
+struct QIB_7322_PcieCplDataBufrUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrUnCorErrLogA_offset 0x00000720UL
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogA_pb {
+	pseudo_bit_t PcieCplHdrBufrUnCorErrHdr_63_0[64];
+};
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrUnCorErrLogB_offset 0x00000728UL
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogB_pb {
+	pseudo_bit_t PcieCplHdrBufrUnCorErrHdr_103_64[40];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrUnCorErrLogC_offset 0x00000730UL
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogC_pb {
+	pseudo_bit_t PcieCplHdrBufrUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t PcieCplHdrBufrUnCorErrAddr_8_0[9];
+	pseudo_bit_t _unused_0[39];
+};
+struct QIB_7322_PcieCplHdrBufrUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrUnCorErrLogA_offset 0x00000740UL
+struct QIB_7322_PciePDataBufrUnCorErrLogA_pb {
+	pseudo_bit_t PciePDataBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_PciePDataBufrUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrUnCorErrLogB_offset 0x00000748UL
+struct QIB_7322_PciePDataBufrUnCorErrLogB_pb {
+	pseudo_bit_t PciePDataBufrUnCorErrData_127_64[64];
+};
+struct QIB_7322_PciePDataBufrUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrUnCorErrLogC_offset 0x00000750UL
+struct QIB_7322_PciePDataBufrUnCorErrLogC_pb {
+	pseudo_bit_t PciePDataBufrUnCorErrData_136_128[9];
+	pseudo_bit_t PciePDataBufrUnCorErrCheckBit_21_0[22];
+	pseudo_bit_t PciePDataBufrUnCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[19];
+};
+struct QIB_7322_PciePDataBufrUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrUnCorErrLogA_offset 0x00000760UL
+struct QIB_7322_PciePHdrBufrUnCorErrLogA_pb {
+	pseudo_bit_t PciePHdrBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_PciePHdrBufrUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrUnCorErrLogB_offset 0x00000768UL
+struct QIB_7322_PciePHdrBufrUnCorErrLogB_pb {
+	pseudo_bit_t PciePHdrBufrUnCorErrData_107_64[44];
+	pseudo_bit_t _unused_0[20];
+};
+struct QIB_7322_PciePHdrBufrUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrUnCorErrLogC_offset 0x00000770UL
+struct QIB_7322_PciePHdrBufrUnCorErrLogC_pb {
+	pseudo_bit_t PciePHdrBufrUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t PciePHdrBufrUnCorErrAddr_8_0[9];
+	pseudo_bit_t _unused_0[39];
+};
+struct QIB_7322_PciePHdrBufrUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrUnCorErrLogA_offset 0x00000780UL
+struct QIB_7322_PcieRetryBufrUnCorErrLogA_pb {
+	pseudo_bit_t PcieRetryBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_PcieRetryBufrUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrUnCorErrLogB_offset 0x00000788UL
+struct QIB_7322_PcieRetryBufrUnCorErrLogB_pb {
+	pseudo_bit_t PcieRetryBufrUnCorErrData_127_64[64];
+};
+struct QIB_7322_PcieRetryBufrUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrUnCorErrLogC_offset 0x00000790UL
+struct QIB_7322_PcieRetryBufrUnCorErrLogC_pb {
+	pseudo_bit_t PcieRetryBufrUnCorErrData_133_128[6];
+	pseudo_bit_t PcieRetryBufrUnCorErrCheckBit_20_0[21];
+	pseudo_bit_t PcieRetryBufrUnCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[23];
+};
+struct QIB_7322_PcieRetryBufrUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDArrayUnCorErrLogA_offset 0x00000800UL
+struct QIB_7322_RxTIDArrayUnCorErrLogA_pb {
+	pseudo_bit_t RxTIDArrayUnCorErrData_39_0[40];
+	pseudo_bit_t RxTIDArrayUnCorErrCheckBit_11_0[12];
+	pseudo_bit_t _unused_0[12];
+};
+struct QIB_7322_RxTIDArrayUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxTIDArrayUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDArrayUnCorErrLogB_offset 0x00000808UL
+struct QIB_7322_RxTIDArrayUnCorErrLogB_pb {
+	pseudo_bit_t RxTIDArrayUnCorErrAddr_16_0[17];
+	pseudo_bit_t _unused_0[47];
+};
+struct QIB_7322_RxTIDArrayUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxTIDArrayUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEagerArrayUnCorErrLogA_offset 0x00000810UL
+struct QIB_7322_RxEagerArrayUnCorErrLogA_pb {
+	pseudo_bit_t RxEagerArrayUnCorErrData_39_0[40];
+	pseudo_bit_t RxEagerArrayUnCorErrCheckBit_11_0[12];
+	pseudo_bit_t _unused_0[12];
+};
+struct QIB_7322_RxEagerArrayUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxEagerArrayUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEagerArrayUnCorErrLogB_offset 0x00000818UL
+struct QIB_7322_RxEagerArrayUnCorErrLogB_pb {
+	pseudo_bit_t RxEagerArrayUnCorErrAddr_17_0[18];
+	pseudo_bit_t _unused_0[46];
+};
+struct QIB_7322_RxEagerArrayUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxEagerArrayUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayUnCorErrLogA_offset 0x00000880UL
+struct QIB_7322_SBufMainArrayUnCorErrLogA_pb {
+	pseudo_bit_t SBufMainArrayUnCorErrData_63_0[64];
+};
+struct QIB_7322_SBufMainArrayUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayUnCorErrLogB_offset 0x00000888UL
+struct QIB_7322_SBufMainArrayUnCorErrLogB_pb {
+	pseudo_bit_t SBufMainArrayUnCorErrData_127_64[64];
+};
+struct QIB_7322_SBufMainArrayUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayUnCorErrLogC_offset 0x00000890UL
+struct QIB_7322_SBufMainArrayUnCorErrLogC_pb {
+	pseudo_bit_t SBufMainArrayUnCorErrCheckBit_27_0[28];
+	pseudo_bit_t SBufMainArrayUnCorErrAddr_18_0[19];
+	pseudo_bit_t _unused_0[13];
+	pseudo_bit_t SBufMainArrayUnCorErrDword_3_0[4];
+};
+struct QIB_7322_SBufMainArrayUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayUnCorErrLogA_offset 0x00000898UL
+struct QIB_7322_SBufExtraArrayUnCorErrLogA_pb {
+	pseudo_bit_t SBufExtraArrayUnCorErrData_63_0[64];
+};
+struct QIB_7322_SBufExtraArrayUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayUnCorErrLogB_offset 0x000008a0UL
+struct QIB_7322_SBufExtraArrayUnCorErrLogB_pb {
+	pseudo_bit_t SBufExtraArrayUnCorErrData_127_64[64];
+};
+struct QIB_7322_SBufExtraArrayUnCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayUnCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayUnCorErrLogC_offset 0x000008a8UL
+struct QIB_7322_SBufExtraArrayUnCorErrLogC_pb {
+	pseudo_bit_t SBufExtraArrayUnCorErrCheckBit_27_0[28];
+	pseudo_bit_t SBufExtraArrayUnCorErrAddr_14_0[15];
+	pseudo_bit_t _unused_0[17];
+	pseudo_bit_t SBufExtraArrayUnCorErrAdd_3_0[4];
+};
+struct QIB_7322_SBufExtraArrayUnCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayUnCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendPbcArrayUnCorErrLog_offset 0x000008b0UL
+struct QIB_7322_SendPbcArrayUnCorErrLog_pb {
+	pseudo_bit_t SendPbcArrayUnCorErrData_21_0[22];
+	pseudo_bit_t SendPbcArrayUnCorErrCheckBit_6_0[7];
+	pseudo_bit_t SendPbcArrayUnCorErrAddr_9_0[10];
+	pseudo_bit_t _unused_0[25];
+};
+struct QIB_7322_SendPbcArrayUnCorErrLog {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendPbcArrayUnCorErrLog_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufVL15ArrayUnCorErrLogA_offset 0x000008c0UL
+struct QIB_7322_SBufVL15ArrayUnCorErrLogA_pb {
+	pseudo_bit_t SBufVL15ArrayUnCorErrData_63_0[64];
+};
+struct QIB_7322_SBufVL15ArrayUnCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufVL15ArrayUnCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrCorErrLogA_offset 0x00000900UL
+struct QIB_7322_PcieCplDataBufrCorErrLogA_pb {
+	pseudo_bit_t PcieCplDataBufrCorErrData_63_0[64];
+};
+struct QIB_7322_PcieCplDataBufrCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrCorErrLogB_offset 0x00000908UL
+struct QIB_7322_PcieCplDataBufrCorErrLogB_pb {
+	pseudo_bit_t PcieCplDataBufrCorErrData_127_64[64];
+};
+struct QIB_7322_PcieCplDataBufrCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplDataBufrCorErrLogC_offset 0x00000910UL
+struct QIB_7322_PcieCplDataBufrCorErrLogC_pb {
+	pseudo_bit_t PcieCplDataBufrCorErrData_136_128[9];
+	pseudo_bit_t PcieCplDataBufrCorErrCheckBit_21_0[22];
+	pseudo_bit_t PcieCplDataBufrCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[19];
+};
+struct QIB_7322_PcieCplDataBufrCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplDataBufrCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrCorErrLogA_offset 0x00000920UL
+struct QIB_7322_PcieCplHdrBufrCorErrLogA_pb {
+	pseudo_bit_t PcieCplHdrBufrCorErrHdr_63_0[64];
+};
+struct QIB_7322_PcieCplHdrBufrCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrCorErrLogB_offset 0x00000928UL
+struct QIB_7322_PcieCplHdrBufrCorErrLogB_pb {
+	pseudo_bit_t PcieCplHdrBufrCorErrHdr_103_64[40];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_PcieCplHdrBufrCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieCplHdrBufrCorErrLogC_offset 0x00000930UL
+struct QIB_7322_PcieCplHdrBufrCorErrLogC_pb {
+	pseudo_bit_t PcieCplHdrBufrCorErrCheckBit_15_0[16];
+	pseudo_bit_t PcieCplHdrBufrCorErrAddr_8_0[9];
+	pseudo_bit_t _unused_0[39];
+};
+struct QIB_7322_PcieCplHdrBufrCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieCplHdrBufrCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrCorErrLogA_offset 0x00000940UL
+struct QIB_7322_PciePDataBufrCorErrLogA_pb {
+	pseudo_bit_t PciePDataBufrCorErrData_63_0[64];
+};
+struct QIB_7322_PciePDataBufrCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrCorErrLogB_offset 0x00000948UL
+struct QIB_7322_PciePDataBufrCorErrLogB_pb {
+	pseudo_bit_t PciePDataBufrCorErrData_127_64[64];
+};
+struct QIB_7322_PciePDataBufrCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePDataBufrCorErrLogC_offset 0x00000950UL
+struct QIB_7322_PciePDataBufrCorErrLogC_pb {
+	pseudo_bit_t PciePDataBufrCorErrData_136_128[9];
+	pseudo_bit_t PciePDataBufrCorErrCheckBit_21_0[22];
+	pseudo_bit_t PciePDataBufrCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[19];
+};
+struct QIB_7322_PciePDataBufrCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePDataBufrCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrCorErrLogA_offset 0x00000960UL
+struct QIB_7322_PciePHdrBufrCorErrLogA_pb {
+	pseudo_bit_t PciePHdrBufrCorErrData_63_0[64];
+};
+struct QIB_7322_PciePHdrBufrCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrCorErrLogB_offset 0x00000968UL
+struct QIB_7322_PciePHdrBufrCorErrLogB_pb {
+	pseudo_bit_t PciePHdrBufrCorErrData_107_64[44];
+	pseudo_bit_t _unused_0[20];
+};
+struct QIB_7322_PciePHdrBufrCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PciePHdrBufrCorErrLogC_offset 0x00000970UL
+struct QIB_7322_PciePHdrBufrCorErrLogC_pb {
+	pseudo_bit_t PciePHdrBufrCorErrCheckBit_15_0[16];
+	pseudo_bit_t PciePHdrBufrCorErrAddr_8_0[9];
+	pseudo_bit_t _unused_0[39];
+};
+struct QIB_7322_PciePHdrBufrCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PciePHdrBufrCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrCorErrLogA_offset 0x00000980UL
+struct QIB_7322_PcieRetryBufrCorErrLogA_pb {
+	pseudo_bit_t PcieRetryBufrCorErrData_63_0[64];
+};
+struct QIB_7322_PcieRetryBufrCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrCorErrLogB_offset 0x00000988UL
+struct QIB_7322_PcieRetryBufrCorErrLogB_pb {
+	pseudo_bit_t PcieRetryBufrCorErrData_127_64[64];
+};
+struct QIB_7322_PcieRetryBufrCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufrCorErrLogC_offset 0x00000990UL
+struct QIB_7322_PcieRetryBufrCorErrLogC_pb {
+	pseudo_bit_t PcieRetryBufrCorErrData_133_128[6];
+	pseudo_bit_t PcieRetryBufrCorErrCheckBit_20_0[21];
+	pseudo_bit_t PcieRetryBufrCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[23];
+};
+struct QIB_7322_PcieRetryBufrCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_PcieRetryBufrCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDArrayCorErrLogA_offset 0x00000a00UL
+struct QIB_7322_RxTIDArrayCorErrLogA_pb {
+	pseudo_bit_t RxTIDArrayCorErrData_39_0[40];
+	pseudo_bit_t RxTIDArrayCorErrCheckBit_11_0[12];
+	pseudo_bit_t _unused_0[12];
+};
+struct QIB_7322_RxTIDArrayCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxTIDArrayCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDArrayCorErrLogB_offset 0x00000a08UL
+struct QIB_7322_RxTIDArrayCorErrLogB_pb {
+	pseudo_bit_t RxTIDArrayCorErrAddr_16_0[17];
+	pseudo_bit_t _unused_0[47];
+};
+struct QIB_7322_RxTIDArrayCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxTIDArrayCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEagerArrayCorErrLogA_offset 0x00000a10UL
+struct QIB_7322_RxEagerArrayCorErrLogA_pb {
+	pseudo_bit_t RxEagerArrayCorErrData_39_0[40];
+	pseudo_bit_t RxEagerArrayCorErrCheckBit_11_0[12];
+	pseudo_bit_t _unused_0[12];
+};
+struct QIB_7322_RxEagerArrayCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxEagerArrayCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEagerArrayCorErrLogB_offset 0x00000a18UL
+struct QIB_7322_RxEagerArrayCorErrLogB_pb {
+	pseudo_bit_t RxEagerArrayCorErrAddr_17_0[18];
+	pseudo_bit_t _unused_0[46];
+};
+struct QIB_7322_RxEagerArrayCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxEagerArrayCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayCorErrLogA_offset 0x00000a80UL
+struct QIB_7322_SBufMainArrayCorErrLogA_pb {
+	pseudo_bit_t SBufMainArrayCorErrData_63_0[64];
+};
+struct QIB_7322_SBufMainArrayCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayCorErrLogB_offset 0x00000a88UL
+struct QIB_7322_SBufMainArrayCorErrLogB_pb {
+	pseudo_bit_t SBufMainArrayCorErrData_127_64[64];
+};
+struct QIB_7322_SBufMainArrayCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufMainArrayCorErrLogC_offset 0x00000a90UL
+struct QIB_7322_SBufMainArrayCorErrLogC_pb {
+	pseudo_bit_t SBufMainArrayCorErrCheckBit_27_0[28];
+	pseudo_bit_t SBufMainArrayCorErrAddr_18_0[19];
+	pseudo_bit_t _unused_0[13];
+	pseudo_bit_t SBufMainArrayCorErrDword_3_0[4];
+};
+struct QIB_7322_SBufMainArrayCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufMainArrayCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayCorErrLogA_offset 0x00000a98UL
+struct QIB_7322_SBufExtraArrayCorErrLogA_pb {
+	pseudo_bit_t SBufExtraArrayCorErrData_63_0[64];
+};
+struct QIB_7322_SBufExtraArrayCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayCorErrLogB_offset 0x00000aa0UL
+struct QIB_7322_SBufExtraArrayCorErrLogB_pb {
+	pseudo_bit_t SBufExtraArrayCorErrData_127_64[64];
+};
+struct QIB_7322_SBufExtraArrayCorErrLogB {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayCorErrLogB_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufExtraArrayCorErrLogC_offset 0x00000aa8UL
+struct QIB_7322_SBufExtraArrayCorErrLogC_pb {
+	pseudo_bit_t SBufExtraArrayCorErrCheckBit_27_0[28];
+	pseudo_bit_t SBufExtraArrayCorErrAddr_14_0[15];
+	pseudo_bit_t _unused_0[17];
+	pseudo_bit_t SBufExtraArrayCorErrAdd_3_0[4];
+};
+struct QIB_7322_SBufExtraArrayCorErrLogC {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufExtraArrayCorErrLogC_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendPbcArrayCorErrLog_offset 0x00000ab0UL
+struct QIB_7322_SendPbcArrayCorErrLog_pb {
+	pseudo_bit_t SendPbcArrayCorErrData_21_0[22];
+	pseudo_bit_t SendPbcArrayCorErrCheckBit_6_0[7];
+	pseudo_bit_t SendPbcArrayCorErrAddr_9_0[10];
+	pseudo_bit_t _unused_0[25];
+};
+struct QIB_7322_SendPbcArrayCorErrLog {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendPbcArrayCorErrLog_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SBufVL15ArrayCorErrLogA_offset 0x00000ac0UL
+struct QIB_7322_SBufVL15ArrayCorErrLogA_pb {
+	pseudo_bit_t SBufVL15ArrayCorErrData_63_0[64];
+};
+struct QIB_7322_SBufVL15ArrayCorErrLogA {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SBufVL15ArrayCorErrLogA_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvAvailTimeOut0_offset 0x00000c00UL
+struct QIB_7322_RcvAvailTimeOut0_pb {
+	pseudo_bit_t RcvAvailTOReload[16];
+	pseudo_bit_t RcvAvailTOCount[16];
+	pseudo_bit_t _unused_0[32];
+};
+struct QIB_7322_RcvAvailTimeOut0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvAvailTimeOut0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_CntrRegBase_0_offset 0x00001028UL
+/* Default value: 0x0000000000012000 */
+
+#define QIB_7322_ErrMask_0_offset 0x00001080UL
+struct QIB_7322_ErrMask_0_pb {
+	pseudo_bit_t RcvFormatErrMask[1];
+	pseudo_bit_t RcvVCRCErrMask[1];
+	pseudo_bit_t RcvICRCErrMask[1];
+	pseudo_bit_t RcvMinPktLenErrMask[1];
+	pseudo_bit_t RcvMaxPktLenErrMask[1];
+	pseudo_bit_t RcvLongPktLenErrMask[1];
+	pseudo_bit_t RcvShortPktLenErrMask[1];
+	pseudo_bit_t RcvUnexpectedCharErrMask[1];
+	pseudo_bit_t RcvUnsupportedVLErrMask[1];
+	pseudo_bit_t RcvEBPErrMask[1];
+	pseudo_bit_t RcvIBFlowErrMask[1];
+	pseudo_bit_t RcvBadVersionErrMask[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErrMask[1];
+	pseudo_bit_t RcvHdrLenErrMask[1];
+	pseudo_bit_t RcvHdrErrMask[1];
+	pseudo_bit_t RcvIBLostLinkErrMask[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErrMask[1];
+	pseudo_bit_t SendMaxPktLenErrMask[1];
+	pseudo_bit_t SendUnderRunErrMask[1];
+	pseudo_bit_t SendPktLenErrMask[1];
+	pseudo_bit_t SendDroppedSmpPktErrMask[1];
+	pseudo_bit_t SendDroppedDataPktErrMask[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErrMask[1];
+	pseudo_bit_t SendUnsupportedVLErrMask[1];
+	pseudo_bit_t SendBufMisuseErrMask[1];
+	pseudo_bit_t SDmaGenMismatchErrMask[1];
+	pseudo_bit_t SDmaOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaBaseErrMask[1];
+	pseudo_bit_t SDma1stDescErrMask[1];
+	pseudo_bit_t SDmaRpyTagErrMask[1];
+	pseudo_bit_t SDmaDwEnErrMask[1];
+	pseudo_bit_t SDmaMissingDwErrMask[1];
+	pseudo_bit_t SDmaUnexpDataErrMask[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrMask[1];
+	pseudo_bit_t SDmaHaltErrMask[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErrMask[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErrMask[1];
+	pseudo_bit_t IBStatusChangedMask[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrMask_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrMask_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrStatus_0_offset 0x00001088UL
+struct QIB_7322_ErrStatus_0_pb {
+	pseudo_bit_t RcvFormatErr[1];
+	pseudo_bit_t RcvVCRCErr[1];
+	pseudo_bit_t RcvICRCErr[1];
+	pseudo_bit_t RcvMinPktLenErr[1];
+	pseudo_bit_t RcvMaxPktLenErr[1];
+	pseudo_bit_t RcvLongPktLenErr[1];
+	pseudo_bit_t RcvShortPktLenErr[1];
+	pseudo_bit_t RcvUnexpectedCharErr[1];
+	pseudo_bit_t RcvUnsupportedVLErr[1];
+	pseudo_bit_t RcvEBPErr[1];
+	pseudo_bit_t RcvIBFlowErr[1];
+	pseudo_bit_t RcvBadVersionErr[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErr[1];
+	pseudo_bit_t RcvHdrLenErr[1];
+	pseudo_bit_t RcvHdrErr[1];
+	pseudo_bit_t RcvIBLostLinkErr[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErr[1];
+	pseudo_bit_t SendMaxPktLenErr[1];
+	pseudo_bit_t SendUnderRunErr[1];
+	pseudo_bit_t SendPktLenErr[1];
+	pseudo_bit_t SendDroppedSmpPktErr[1];
+	pseudo_bit_t SendDroppedDataPktErr[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErr[1];
+	pseudo_bit_t SendUnsupportedVLErr[1];
+	pseudo_bit_t SendBufMisuseErr[1];
+	pseudo_bit_t SDmaGenMismatchErr[1];
+	pseudo_bit_t SDmaOutOfBoundErr[1];
+	pseudo_bit_t SDmaTailOutOfBoundErr[1];
+	pseudo_bit_t SDmaBaseErr[1];
+	pseudo_bit_t SDma1stDescErr[1];
+	pseudo_bit_t SDmaRpyTagErr[1];
+	pseudo_bit_t SDmaDwEnErr[1];
+	pseudo_bit_t SDmaMissingDwErr[1];
+	pseudo_bit_t SDmaUnexpDataErr[1];
+	pseudo_bit_t SDmaDescAddrMisalignErr[1];
+	pseudo_bit_t SDmaHaltErr[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErr[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErr[1];
+	pseudo_bit_t IBStatusChanged[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrStatus_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrStatus_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrClear_0_offset 0x00001090UL
+struct QIB_7322_ErrClear_0_pb {
+	pseudo_bit_t RcvFormatErrClear[1];
+	pseudo_bit_t RcvVCRCErrClear[1];
+	pseudo_bit_t RcvICRCErrClear[1];
+	pseudo_bit_t RcvMinPktLenErrClear[1];
+	pseudo_bit_t RcvMaxPktLenErrClear[1];
+	pseudo_bit_t RcvLongPktLenErrClear[1];
+	pseudo_bit_t RcvShortPktLenErrClear[1];
+	pseudo_bit_t RcvUnexpectedCharErrClear[1];
+	pseudo_bit_t RcvUnsupportedVLErrClear[1];
+	pseudo_bit_t RcvEBPErrClear[1];
+	pseudo_bit_t RcvIBFlowErrClear[1];
+	pseudo_bit_t RcvBadVersionErrClear[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErrClear[1];
+	pseudo_bit_t RcvHdrLenErrClear[1];
+	pseudo_bit_t RcvHdrErrClear[1];
+	pseudo_bit_t RcvIBLostLinkErrClear[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErrClear[1];
+	pseudo_bit_t SendMaxPktLenErrClear[1];
+	pseudo_bit_t SendUnderRunErrClear[1];
+	pseudo_bit_t SendPktLenErrClear[1];
+	pseudo_bit_t SendDroppedSmpPktErrClear[1];
+	pseudo_bit_t SendDroppedDataPktErrClear[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErrClear[1];
+	pseudo_bit_t SendUnsupportedVLErrClear[1];
+	pseudo_bit_t SendBufMisuseErrClear[1];
+	pseudo_bit_t SDmaGenMismatchErrClear[1];
+	pseudo_bit_t SDmaOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaBaseErrClear[1];
+	pseudo_bit_t SDma1stDescErrClear[1];
+	pseudo_bit_t SDmaRpyTagErrClear[1];
+	pseudo_bit_t SDmaDwEnErrClear[1];
+	pseudo_bit_t SDmaMissingDwErrClear[1];
+	pseudo_bit_t SDmaUnexpDataErrClear[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrClear[1];
+	pseudo_bit_t SDmaHaltErrClear[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErrClear[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErrClear[1];
+	pseudo_bit_t IBStatusChangedClear[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrClear_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrClear_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TXEStatus_0_offset 0x000010b8UL
+struct QIB_7322_TXEStatus_0_pb {
+	pseudo_bit_t LaFifoEmpty_VL0[1];
+	pseudo_bit_t LaFifoEmpty_VL1[1];
+	pseudo_bit_t LaFifoEmpty_VL2[1];
+	pseudo_bit_t LaFifoEmpty_VL3[1];
+	pseudo_bit_t LaFifoEmpty_VL4[1];
+	pseudo_bit_t LaFifoEmpty_VL5[1];
+	pseudo_bit_t LaFifoEmpty_VL6[1];
+	pseudo_bit_t LaFifoEmpty_VL7[1];
+	pseudo_bit_t _unused_0[7];
+	pseudo_bit_t LaFifoEmpty_VL15[1];
+	pseudo_bit_t _unused_1[14];
+	pseudo_bit_t RmFifoEmpty[1];
+	pseudo_bit_t TXE_IBC_Idle[1];
+	pseudo_bit_t _unused_2[32];
+};
+struct QIB_7322_TXEStatus_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_TXEStatus_0_pb );
+};
+/* Default value: 0x0000000XC00080FF */
+
+#define QIB_7322_RcvCtrl_0_offset 0x00001100UL
+struct QIB_7322_RcvCtrl_0_pb {
+	pseudo_bit_t ContextEnableKernel[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t ContextEnableUser[16];
+	pseudo_bit_t _unused_1[21];
+	pseudo_bit_t RcvIBPortEnable[1];
+	pseudo_bit_t RcvQPMapEnable[1];
+	pseudo_bit_t RcvPartitionKeyDisable[1];
+	pseudo_bit_t RcvResetCredit[1];
+	pseudo_bit_t _unused_2[21];
+};
+struct QIB_7322_RcvCtrl_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvCtrl_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBTHQP_0_offset 0x00001108UL
+struct QIB_7322_RcvBTHQP_0_pb {
+	pseudo_bit_t RcvBTHQP[24];
+	pseudo_bit_t _unused_0[40];
+};
+struct QIB_7322_RcvBTHQP_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvBTHQP_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableA_0_offset 0x00001110UL
+struct QIB_7322_RcvQPMapTableA_0_pb {
+	pseudo_bit_t RcvQPMapContext0[5];
+	pseudo_bit_t RcvQPMapContext1[5];
+	pseudo_bit_t RcvQPMapContext2[5];
+	pseudo_bit_t RcvQPMapContext3[5];
+	pseudo_bit_t RcvQPMapContext4[5];
+	pseudo_bit_t RcvQPMapContext5[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableB_0_offset 0x00001118UL
+struct QIB_7322_RcvQPMapTableB_0_pb {
+	pseudo_bit_t RcvQPMapContext6[5];
+	pseudo_bit_t RcvQPMapContext7[5];
+	pseudo_bit_t RcvQPMapContext8[5];
+	pseudo_bit_t RcvQPMapContext9[5];
+	pseudo_bit_t RcvQPMapContext10[5];
+	pseudo_bit_t RcvQPMapContext11[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableC_0_offset 0x00001120UL
+struct QIB_7322_RcvQPMapTableC_0_pb {
+	pseudo_bit_t RcvQPMapContext12[5];
+	pseudo_bit_t RcvQPMapContext13[5];
+	pseudo_bit_t RcvQPMapContext14[5];
+	pseudo_bit_t RcvQPMapContext15[5];
+	pseudo_bit_t RcvQPMapContext16[5];
+	pseudo_bit_t RcvQPMapContext17[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableD_0_offset 0x00001128UL
+struct QIB_7322_RcvQPMapTableD_0_pb {
+	pseudo_bit_t RcvQPMapContext18[5];
+	pseudo_bit_t RcvQPMapContext19[5];
+	pseudo_bit_t RcvQPMapContext20[5];
+	pseudo_bit_t RcvQPMapContext21[5];
+	pseudo_bit_t RcvQPMapContext22[5];
+	pseudo_bit_t RcvQPMapContext23[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableD_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableD_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableE_0_offset 0x00001130UL
+struct QIB_7322_RcvQPMapTableE_0_pb {
+	pseudo_bit_t RcvQPMapContext24[5];
+	pseudo_bit_t RcvQPMapContext25[5];
+	pseudo_bit_t RcvQPMapContext26[5];
+	pseudo_bit_t RcvQPMapContext27[5];
+	pseudo_bit_t RcvQPMapContext28[5];
+	pseudo_bit_t RcvQPMapContext29[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableE_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableE_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableF_0_offset 0x00001138UL
+struct QIB_7322_RcvQPMapTableF_0_pb {
+	pseudo_bit_t RcvQPMapContext30[5];
+	pseudo_bit_t RcvQPMapContext31[5];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7322_RcvQPMapTableF_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableF_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSStat_0_offset 0x00001140UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSStart_0_offset 0x00001148UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSInterval_0_offset 0x00001150UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvStatus_0_offset 0x00001160UL
+struct QIB_7322_RcvStatus_0_pb {
+	pseudo_bit_t RxPktInProgress[1];
+	pseudo_bit_t DmaeqBlockingContext[5];
+	pseudo_bit_t _unused_0[58];
+};
+struct QIB_7322_RcvStatus_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvStatus_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvPartitionKey_0_offset 0x00001168UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMulticastContext_0_offset 0x00001170UL
+struct QIB_7322_RcvQPMulticastContext_0_pb {
+	pseudo_bit_t RcvQpMcContext[5];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_RcvQPMulticastContext_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMulticastContext_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvPktLEDCnt_0_offset 0x00001178UL
+struct QIB_7322_RcvPktLEDCnt_0_pb {
+	pseudo_bit_t OFFperiod[32];
+	pseudo_bit_t ONperiod[32];
+};
+struct QIB_7322_RcvPktLEDCnt_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvPktLEDCnt_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaIdleCnt_0_offset 0x00001180UL
+struct QIB_7322_SendDmaIdleCnt_0_pb {
+	pseudo_bit_t SendDmaIdleCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaIdleCnt_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaIdleCnt_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaReloadCnt_0_offset 0x00001188UL
+struct QIB_7322_SendDmaReloadCnt_0_pb {
+	pseudo_bit_t SendDmaReloadCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaReloadCnt_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaReloadCnt_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaDescCnt_0_offset 0x00001190UL
+struct QIB_7322_SendDmaDescCnt_0_pb {
+	pseudo_bit_t SendDmaDescCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaDescCnt_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaDescCnt_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendCtrl_0_offset 0x000011c0UL
+struct QIB_7322_SendCtrl_0_pb {
+	pseudo_bit_t TxeAbortIbc[1];
+	pseudo_bit_t TxeBypassIbc[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t SendEnable[1];
+	pseudo_bit_t _unused_1[3];
+	pseudo_bit_t ForceCreditUpToDate[1];
+	pseudo_bit_t SDmaCleanup[1];
+	pseudo_bit_t SDmaIntEnable[1];
+	pseudo_bit_t SDmaSingleDescriptor[1];
+	pseudo_bit_t SDmaEnable[1];
+	pseudo_bit_t SDmaHalt[1];
+	pseudo_bit_t TxeDrainLaFifo[1];
+	pseudo_bit_t TxeDrainRmFifo[1];
+	pseudo_bit_t IBVLArbiterEn[1];
+	pseudo_bit_t _unused_2[48];
+};
+struct QIB_7322_SendCtrl_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCtrl_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBase_0_offset 0x000011f8UL
+struct QIB_7322_SendDmaBase_0_pb {
+	pseudo_bit_t SendDmaBase[48];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_SendDmaBase_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBase_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaLenGen_0_offset 0x00001200UL
+struct QIB_7322_SendDmaLenGen_0_pb {
+	pseudo_bit_t Length[16];
+	pseudo_bit_t Generation[3];
+	pseudo_bit_t _unused_0[45];
+};
+struct QIB_7322_SendDmaLenGen_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaLenGen_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaTail_0_offset 0x00001208UL
+struct QIB_7322_SendDmaTail_0_pb {
+	pseudo_bit_t SendDmaTail[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaTail_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaTail_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaHead_0_offset 0x00001210UL
+struct QIB_7322_SendDmaHead_0_pb {
+	pseudo_bit_t SendDmaHead[16];
+	pseudo_bit_t _unused_0[16];
+	pseudo_bit_t InternalSendDmaHead[16];
+	pseudo_bit_t _unused_1[16];
+};
+struct QIB_7322_SendDmaHead_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaHead_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaHeadAddr_0_offset 0x00001218UL
+struct QIB_7322_SendDmaHeadAddr_0_pb {
+	pseudo_bit_t SendDmaHeadAddr[48];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_SendDmaHeadAddr_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaHeadAddr_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBufMask0_0_offset 0x00001220UL
+struct QIB_7322_SendDmaBufMask0_0_pb {
+	pseudo_bit_t BufMask_63_0[64];
+};
+struct QIB_7322_SendDmaBufMask0_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBufMask0_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaStatus_0_offset 0x00001238UL
+struct QIB_7322_SendDmaStatus_0_pb {
+	pseudo_bit_t SplFifoDescIndex[16];
+	pseudo_bit_t SplFifoBufNum[8];
+	pseudo_bit_t SplFifoFull[1];
+	pseudo_bit_t SplFifoEmpty[1];
+	pseudo_bit_t SplFifoDisarmed[1];
+	pseudo_bit_t SplFifoReadyToGo[1];
+	pseudo_bit_t ScbFetchDescFlag[1];
+	pseudo_bit_t ScbEntryValid[1];
+	pseudo_bit_t ScbEmpty[1];
+	pseudo_bit_t ScbFull[1];
+	pseudo_bit_t RpyTag_7_0[8];
+	pseudo_bit_t RpyLowAddr_6_0[7];
+	pseudo_bit_t ScbDescIndex_13_0[14];
+	pseudo_bit_t InternalSDmaHalt[1];
+	pseudo_bit_t HaltInProg[1];
+	pseudo_bit_t ScoreBoardDrainInProg[1];
+};
+struct QIB_7322_SendDmaStatus_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaStatus_0_pb );
+};
+/* Default value: 0x0000000042000000 */
+
+#define QIB_7322_SendDmaPriorityThld_0_offset 0x00001258UL
+struct QIB_7322_SendDmaPriorityThld_0_pb {
+	pseudo_bit_t PriorityThreshold[4];
+	pseudo_bit_t _unused_0[60];
+};
+struct QIB_7322_SendDmaPriorityThld_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaPriorityThld_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendHdrErrSymptom_0_offset 0x00001260UL
+struct QIB_7322_SendHdrErrSymptom_0_pb {
+	pseudo_bit_t PacketTooSmall[1];
+	pseudo_bit_t RawIPV6[1];
+	pseudo_bit_t SLIDFail[1];
+	pseudo_bit_t QPFail[1];
+	pseudo_bit_t PkeyFail[1];
+	pseudo_bit_t GRHFail[1];
+	pseudo_bit_t NonKeyPacket[1];
+	pseudo_bit_t _unused_0[57];
+};
+struct QIB_7322_SendHdrErrSymptom_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendHdrErrSymptom_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxCreditVL0_0_offset 0x00001280UL
+struct QIB_7322_RxCreditVL0_0_pb {
+	pseudo_bit_t RxMaxCreditVL[12];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RxBufrConsumedVL[12];
+	pseudo_bit_t _unused_1[36];
+};
+struct QIB_7322_RxCreditVL0_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxCreditVL0_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBufUsed0_0_offset 0x00001480UL
+struct QIB_7322_SendDmaBufUsed0_0_pb {
+	pseudo_bit_t BufUsed_63_0[64];
+};
+struct QIB_7322_SendDmaBufUsed0_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBufUsed0_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaReqTagUsed_0_offset 0x00001498UL
+struct QIB_7322_SendDmaReqTagUsed_0_pb {
+	pseudo_bit_t ReqTagUsed_7_0[8];
+	pseudo_bit_t _unused_0[56];
+};
+struct QIB_7322_SendDmaReqTagUsed_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaReqTagUsed_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendCheckControl_0_offset 0x000014a8UL
+struct QIB_7322_SendCheckControl_0_pb {
+	pseudo_bit_t PacketTooSmall_En[1];
+	pseudo_bit_t RawIPV6_En[1];
+	pseudo_bit_t SLID_En[1];
+	pseudo_bit_t BTHQP_En[1];
+	pseudo_bit_t PKey_En[1];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_SendCheckControl_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCheckControl_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendIBSLIDMask_0_offset 0x000014b0UL
+struct QIB_7322_SendIBSLIDMask_0_pb {
+	pseudo_bit_t SendIBSLIDMask_15_0[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendIBSLIDMask_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendIBSLIDMask_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendIBSLIDAssign_0_offset 0x000014b8UL
+struct QIB_7322_SendIBSLIDAssign_0_pb {
+	pseudo_bit_t SendIBSLIDAssign_15_0[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendIBSLIDAssign_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendIBSLIDAssign_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBCStatusA_0_offset 0x00001540UL
+struct QIB_7322_IBCStatusA_0_pb {
+	pseudo_bit_t LinkTrainingState[5];
+	pseudo_bit_t LinkState[3];
+	pseudo_bit_t LinkSpeedActive[1];
+	pseudo_bit_t LinkWidthActive[1];
+	pseudo_bit_t DDS_RXEQ_FAIL[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t IBRxLaneReversed[1];
+	pseudo_bit_t IBTxLaneReversed[1];
+	pseudo_bit_t ScrambleEn[1];
+	pseudo_bit_t ScrambleCapRemote[1];
+	pseudo_bit_t _unused_1[13];
+	pseudo_bit_t LinkSpeedQDR[1];
+	pseudo_bit_t TxReady[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t TxCreditOk_VL0[1];
+	pseudo_bit_t TxCreditOk_VL1[1];
+	pseudo_bit_t TxCreditOk_VL2[1];
+	pseudo_bit_t TxCreditOk_VL3[1];
+	pseudo_bit_t TxCreditOk_VL4[1];
+	pseudo_bit_t TxCreditOk_VL5[1];
+	pseudo_bit_t TxCreditOk_VL6[1];
+	pseudo_bit_t TxCreditOk_VL7[1];
+	pseudo_bit_t _unused_3[24];
+};
+struct QIB_7322_IBCStatusA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCStatusA_0_pb );
+};
+/* Default value: 0x0000000000000X02 */
+
+#define QIB_7322_IBCStatusB_0_offset 0x00001548UL
+struct QIB_7322_IBCStatusB_0_pb {
+	pseudo_bit_t LinkRoundTripLatency[26];
+	pseudo_bit_t ReqDDSLocalFromRmt[4];
+	pseudo_bit_t RxEqLocalDevice[2];
+	pseudo_bit_t heartbeat_crosstalk[4];
+	pseudo_bit_t heartbeat_timed_out[1];
+	pseudo_bit_t ibsd_adaptation_timer_started[1];
+	pseudo_bit_t ibsd_adaptation_timer_reached_threshold[1];
+	pseudo_bit_t ibsd_adaptation_timer_debug[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_IBCStatusB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCStatusB_0_pb );
+};
+/* Default value: 0x00000000XXXXXXXX */
+
+#define QIB_7322_IBCCtrlA_0_offset 0x00001560UL
+struct QIB_7322_IBCCtrlA_0_pb {
+	pseudo_bit_t FlowCtrlPeriod[8];
+	pseudo_bit_t FlowCtrlWaterMark[8];
+	pseudo_bit_t LinkInitCmd[3];
+	pseudo_bit_t LinkCmd[2];
+	pseudo_bit_t MaxPktLen[11];
+	pseudo_bit_t PhyerrThreshold[4];
+	pseudo_bit_t OverrunThreshold[4];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t NumVLane[3];
+	pseudo_bit_t _unused_1[9];
+	pseudo_bit_t IBStatIntReductionEn[1];
+	pseudo_bit_t IBLinkEn[1];
+	pseudo_bit_t LinkDownDefaultState[1];
+	pseudo_bit_t Loopback[1];
+};
+struct QIB_7322_IBCCtrlA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBCCtrlB_0_offset 0x00001568UL
+struct QIB_7322_IBCCtrlB_0_pb {
+	pseudo_bit_t IB_ENHANCED_MODE[1];
+	pseudo_bit_t SD_SPEED[1];
+	pseudo_bit_t SD_SPEED_SDR[1];
+	pseudo_bit_t SD_SPEED_DDR[1];
+	pseudo_bit_t SD_SPEED_QDR[1];
+	pseudo_bit_t IB_NUM_CHANNELS[2];
+	pseudo_bit_t IB_POLARITY_REV_SUPP[1];
+	pseudo_bit_t IB_LANE_REV_SUPPORTED[1];
+	pseudo_bit_t SD_RX_EQUAL_ENABLE[1];
+	pseudo_bit_t SD_ADD_ENB[1];
+	pseudo_bit_t SD_DDSV[1];
+	pseudo_bit_t SD_DDS[4];
+	pseudo_bit_t HRTBT_ENB[1];
+	pseudo_bit_t HRTBT_AUTO[1];
+	pseudo_bit_t HRTBT_PORT[8];
+	pseudo_bit_t HRTBT_REQ[1];
+	pseudo_bit_t IB_ENABLE_FILT_DPKT[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t IB_DLID[16];
+	pseudo_bit_t IB_DLID_MASK[16];
+};
+struct QIB_7322_IBCCtrlB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlB_0_pb );
+};
+/* Default value: 0x00000000000305FF */
+
+#define QIB_7322_IBCCtrlC_0_offset 0x00001570UL
+struct QIB_7322_IBCCtrlC_0_pb {
+	pseudo_bit_t IB_FRONT_PORCH[5];
+	pseudo_bit_t IB_BACK_PORCH[5];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7322_IBCCtrlC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlC_0_pb );
+};
+/* Default value: 0x0000000000000301 */
+
+#define QIB_7322_HRTBT_GUID_0_offset 0x00001588UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IB_SDTEST_IF_TX_0_offset 0x00001590UL
+struct QIB_7322_IB_SDTEST_IF_TX_0_pb {
+	pseudo_bit_t TS_T_TX_VALID[1];
+	pseudo_bit_t TS_3_TX_VALID[1];
+	pseudo_bit_t VL_CAP[2];
+	pseudo_bit_t CREDIT_CHANGE[1];
+	pseudo_bit_t _unused_0[6];
+	pseudo_bit_t TS_TX_OPCODE[2];
+	pseudo_bit_t TS_TX_SPEED[3];
+	pseudo_bit_t _unused_1[16];
+	pseudo_bit_t TS_TX_TX_CFG[16];
+	pseudo_bit_t TS_TX_RX_CFG[16];
+};
+struct QIB_7322_IB_SDTEST_IF_TX_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IB_SDTEST_IF_TX_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IB_SDTEST_IF_RX_0_offset 0x00001598UL
+struct QIB_7322_IB_SDTEST_IF_RX_0_pb {
+	pseudo_bit_t TS_T_RX_VALID[1];
+	pseudo_bit_t TS_3_RX_VALID[1];
+	pseudo_bit_t _unused_0[14];
+	pseudo_bit_t TS_RX_A[8];
+	pseudo_bit_t TS_RX_B[8];
+	pseudo_bit_t TS_RX_TX_CFG[16];
+	pseudo_bit_t TS_RX_RX_CFG[16];
+};
+struct QIB_7322_IB_SDTEST_IF_RX_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IB_SDTEST_IF_RX_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBNCModeCtrl_0_offset 0x000015b8UL
+struct QIB_7322_IBNCModeCtrl_0_pb {
+	pseudo_bit_t TSMEnable_send_TS1[1];
+	pseudo_bit_t TSMEnable_send_TS2[1];
+	pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t TSMCode_TS1[9];
+	pseudo_bit_t TSMCode_TS2[9];
+	pseudo_bit_t _unused_1[6];
+	pseudo_bit_t ScrambleCapLocal[1];
+	pseudo_bit_t ScrambleCapRemoteMask[1];
+	pseudo_bit_t ScrambleCapRemoteForce[1];
+	pseudo_bit_t _unused_2[29];
+};
+struct QIB_7322_IBNCModeCtrl_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBNCModeCtrl_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBSerdesStatus_0_offset 0x000015d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBPCSConfig_0_offset 0x000015d8UL
+struct QIB_7322_IBPCSConfig_0_pb {
+	pseudo_bit_t tx_rx_reset[1];
+	pseudo_bit_t xcv_treset[1];
+	pseudo_bit_t xcv_rreset[1];
+	pseudo_bit_t _unused_0[6];
+	pseudo_bit_t link_sync_mask[10];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_IBPCSConfig_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBPCSConfig_0_pb );
+};
+/* Default value: 0x0000000000000007 */
+
+#define QIB_7322_IBSerdesCtrl_0_offset 0x000015e0UL
+struct QIB_7322_IBSerdesCtrl_0_pb {
+	pseudo_bit_t CMODE[7];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t TXIDLE[1];
+	pseudo_bit_t RXPD[1];
+	pseudo_bit_t TXPD[1];
+	pseudo_bit_t PLLPD[1];
+	pseudo_bit_t LPEN[1];
+	pseudo_bit_t RXLOSEN[1];
+	pseudo_bit_t _unused_1[1];
+	pseudo_bit_t IB_LAT_MODE[1];
+	pseudo_bit_t CGMODE[4];
+	pseudo_bit_t CHANNEL_RESET_N[4];
+	pseudo_bit_t DISABLE_RXLATOFF_SDR[1];
+	pseudo_bit_t DISABLE_RXLATOFF_DDR[1];
+	pseudo_bit_t DISABLE_RXLATOFF_QDR[1];
+	pseudo_bit_t _unused_2[37];
+};
+struct QIB_7322_IBSerdesCtrl_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBSerdesCtrl_0_pb );
+};
+/* Default value: 0x0000000000FFA00F */
+
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_offset 0x00001600UL
+struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_pb {
+	pseudo_bit_t txcn1_ena[3];
+	pseudo_bit_t txcn1_xtra_emph0[2];
+	pseudo_bit_t txcp1_ena[4];
+	pseudo_bit_t txc0_ena[5];
+	pseudo_bit_t txampcntl_d2a[4];
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t reset_tx_deemphasis_override[1];
+	pseudo_bit_t tx_override_deemphasis_select[1];
+	pseudo_bit_t _unused_1[32];
+};
+struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_offset 0x00001640UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_pb {
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_sdr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_offset 0x00001648UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_offset 0x00001650UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_pb {
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_ddr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_offset 0x00001658UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_offset 0x00001660UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_pb {
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_qdr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_offset 0x00001668UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_TIMER_THRESHOLD_0_offset 0x00001670UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogA_0_offset 0x00001800UL
+struct QIB_7322_RxBufrUnCorErrLogA_0_pb {
+	pseudo_bit_t RxBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogB_0_offset 0x00001808UL
+struct QIB_7322_RxBufrUnCorErrLogB_0_pb {
+	pseudo_bit_t RxBufrUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogC_0_offset 0x00001810UL
+struct QIB_7322_RxBufrUnCorErrLogC_0_pb {
+	pseudo_bit_t RxBufrUnCorErrData_191_128[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogD_0_offset 0x00001818UL
+struct QIB_7322_RxBufrUnCorErrLogD_0_pb {
+	pseudo_bit_t RxBufrUnCorErrData_255_192[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogD_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogD_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogE_0_offset 0x00001820UL
+struct QIB_7322_RxBufrUnCorErrLogE_0_pb {
+	pseudo_bit_t RxBufrUnCorErrData_258_256[3];
+	pseudo_bit_t RxBufrUnCorErrCheckBit_36_0[37];
+	pseudo_bit_t RxBufrUnCorErrAddr_15_0[16];
+	pseudo_bit_t _unused_0[8];
+};
+struct QIB_7322_RxBufrUnCorErrLogE_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogE_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagUnCorErrLogA_0_offset 0x00001828UL
+struct QIB_7322_RxFlagUnCorErrLogA_0_pb {
+	pseudo_bit_t RxFlagUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxFlagUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagUnCorErrLogB_0_offset 0x00001830UL
+struct QIB_7322_RxFlagUnCorErrLogB_0_pb {
+	pseudo_bit_t RxFlagUnCorErrCheckBit_7_0[8];
+	pseudo_bit_t RxFlagUnCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_RxFlagUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqUnCorErrLogA_0_offset 0x00001840UL
+struct QIB_7322_RxLkupiqUnCorErrLogA_0_pb {
+	pseudo_bit_t RxLkupiqUnCorErrData_45_0[46];
+	pseudo_bit_t RxLkupiqUnCorErrCheckBit_7_0[8];
+	pseudo_bit_t _unused_0[10];
+};
+struct QIB_7322_RxLkupiqUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqUnCorErrLogB_0_offset 0x00001848UL
+struct QIB_7322_RxLkupiqUnCorErrLogB_0_pb {
+	pseudo_bit_t RxLkupiqUnCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[51];
+};
+struct QIB_7322_RxLkupiqUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogA_0_offset 0x00001850UL
+struct QIB_7322_RxHdrFifoUnCorErrLogA_0_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogB_0_offset 0x00001858UL
+struct QIB_7322_RxHdrFifoUnCorErrLogB_0_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogC_0_offset 0x00001860UL
+struct QIB_7322_RxHdrFifoUnCorErrLogC_0_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxHdrFifoUnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogA_0_offset 0x00001868UL
+struct QIB_7322_RxDataFifoUnCorErrLogA_0_pb {
+	pseudo_bit_t RxDataFifoUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogB_0_offset 0x00001870UL
+struct QIB_7322_RxDataFifoUnCorErrLogB_0_pb {
+	pseudo_bit_t RxDataFifoUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogC_0_offset 0x00001878UL
+struct QIB_7322_RxDataFifoUnCorErrLogC_0_pb {
+	pseudo_bit_t RxDataFifoUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxDataFifoUnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaFifoArray0UnCorErrLog_0_offset 0x00001880UL
+struct QIB_7322_LaFifoArray0UnCorErrLog_0_pb {
+	pseudo_bit_t LaFifoArray0UnCorErrData_34_0[35];
+	pseudo_bit_t LaFifoArray0UnCorErrCheckBit_10_0[11];
+	pseudo_bit_t LaFifoArray0UnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[7];
+};
+struct QIB_7322_LaFifoArray0UnCorErrLog_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LaFifoArray0UnCorErrLog_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogA_0_offset 0x000018c0UL
+struct QIB_7322_RmFifoArrayUnCorErrLogA_0_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrData_63_0[64];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogB_0_offset 0x000018c8UL
+struct QIB_7322_RmFifoArrayUnCorErrLogB_0_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrData_127_64[64];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogC_0_offset 0x000018d0UL
+struct QIB_7322_RmFifoArrayUnCorErrLogC_0_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrCheckBit_27_0[28];
+	pseudo_bit_t RmFifoArrayUnCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[18];
+	pseudo_bit_t RmFifoArrayUnCorErrDword_3_0[4];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogA_0_offset 0x00001900UL
+struct QIB_7322_RxBufrCorErrLogA_0_pb {
+	pseudo_bit_t RxBufrCorErrData_63_0[64];
+};
+struct QIB_7322_RxBufrCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogB_0_offset 0x00001908UL
+struct QIB_7322_RxBufrCorErrLogB_0_pb {
+	pseudo_bit_t RxBufrCorErrData_127_64[64];
+};
+struct QIB_7322_RxBufrCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogC_0_offset 0x00001910UL
+struct QIB_7322_RxBufrCorErrLogC_0_pb {
+	pseudo_bit_t RxBufrCorErrData_191_128[64];
+};
+struct QIB_7322_RxBufrCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogD_0_offset 0x00001918UL
+struct QIB_7322_RxBufrCorErrLogD_0_pb {
+	pseudo_bit_t RxBufrCorErrData_255_192[64];
+};
+struct QIB_7322_RxBufrCorErrLogD_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogD_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogE_0_offset 0x00001920UL
+struct QIB_7322_RxBufrCorErrLogE_0_pb {
+	pseudo_bit_t RxBufrCorErrData_258_256[3];
+	pseudo_bit_t RxBufrCorErrCheckBit_36_0[37];
+	pseudo_bit_t RxBufrCorErrAddr_15_0[16];
+	pseudo_bit_t _unused_0[8];
+};
+struct QIB_7322_RxBufrCorErrLogE_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogE_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagCorErrLogA_0_offset 0x00001928UL
+struct QIB_7322_RxFlagCorErrLogA_0_pb {
+	pseudo_bit_t RxFlagCorErrData_63_0[64];
+};
+struct QIB_7322_RxFlagCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagCorErrLogB_0_offset 0x00001930UL
+struct QIB_7322_RxFlagCorErrLogB_0_pb {
+	pseudo_bit_t RxFlagCorErrCheckBit_7_0[8];
+	pseudo_bit_t RxFlagCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_RxFlagCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqCorErrLogA_0_offset 0x00001940UL
+struct QIB_7322_RxLkupiqCorErrLogA_0_pb {
+	pseudo_bit_t RxLkupiqCorErrData_45_0[46];
+	pseudo_bit_t RxLkupiqCorErrCheckBit_7_0[8];
+	pseudo_bit_t _unused_0[10];
+};
+struct QIB_7322_RxLkupiqCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqCorErrLogB_0_offset 0x00001948UL
+struct QIB_7322_RxLkupiqCorErrLogB_0_pb {
+	pseudo_bit_t RxLkupiqCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[51];
+};
+struct QIB_7322_RxLkupiqCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogA_0_offset 0x00001950UL
+struct QIB_7322_RxHdrFifoCorErrLogA_0_pb {
+	pseudo_bit_t RxHdrFifoCorErrData_63_0[64];
+};
+struct QIB_7322_RxHdrFifoCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogB_0_offset 0x00001958UL
+struct QIB_7322_RxHdrFifoCorErrLogB_0_pb {
+	pseudo_bit_t RxHdrFifoCorErrData_127_64[64];
+};
+struct QIB_7322_RxHdrFifoCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogC_0_offset 0x00001960UL
+struct QIB_7322_RxHdrFifoCorErrLogC_0_pb {
+	pseudo_bit_t RxHdrFifoCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxHdrFifoCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxHdrFifoCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogA_0_offset 0x00001968UL
+struct QIB_7322_RxDataFifoCorErrLogA_0_pb {
+	pseudo_bit_t RxDataFifoCorErrData_63_0[64];
+};
+struct QIB_7322_RxDataFifoCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogB_0_offset 0x00001970UL
+struct QIB_7322_RxDataFifoCorErrLogB_0_pb {
+	pseudo_bit_t RxDataFifoCorErrData_127_64[64];
+};
+struct QIB_7322_RxDataFifoCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogC_0_offset 0x00001978UL
+struct QIB_7322_RxDataFifoCorErrLogC_0_pb {
+	pseudo_bit_t RxDataFifoCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxDataFifoCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxDataFifoCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaFifoArray0CorErrLog_0_offset 0x00001980UL
+struct QIB_7322_LaFifoArray0CorErrLog_0_pb {
+	pseudo_bit_t LaFifoArray0CorErrData_34_0[35];
+	pseudo_bit_t LaFifoArray0CorErrCheckBit_10_0[11];
+	pseudo_bit_t LaFifoArray0CorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[7];
+};
+struct QIB_7322_LaFifoArray0CorErrLog_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LaFifoArray0CorErrLog_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogA_0_offset 0x000019c0UL
+struct QIB_7322_RmFifoArrayCorErrLogA_0_pb {
+	pseudo_bit_t RmFifoArrayCorErrData_63_0[64];
+};
+struct QIB_7322_RmFifoArrayCorErrLogA_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogA_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogB_0_offset 0x000019c8UL
+struct QIB_7322_RmFifoArrayCorErrLogB_0_pb {
+	pseudo_bit_t RmFifoArrayCorErrData_127_64[64];
+};
+struct QIB_7322_RmFifoArrayCorErrLogB_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogB_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogC_0_offset 0x000019d0UL
+struct QIB_7322_RmFifoArrayCorErrLogC_0_pb {
+	pseudo_bit_t RmFifoArrayCorErrCheckBit_27_0[28];
+	pseudo_bit_t RmFifoArrayCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[18];
+	pseudo_bit_t RmFifoArrayCorErrDword_3_0[4];
+};
+struct QIB_7322_RmFifoArrayCorErrLogC_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogC_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HighPriorityLimit_0_offset 0x00001bc0UL
+struct QIB_7322_HighPriorityLimit_0_pb {
+	pseudo_bit_t Limit[8];
+	pseudo_bit_t _unused_0[56];
+};
+struct QIB_7322_HighPriorityLimit_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HighPriorityLimit_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LowPriority0_0_offset 0x00001c00UL
+struct QIB_7322_LowPriority0_0_pb {
+	pseudo_bit_t Weight[8];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t VirtualLane[3];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_LowPriority0_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LowPriority0_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HighPriority0_0_offset 0x00001e00UL
+struct QIB_7322_HighPriority0_0_pb {
+	pseudo_bit_t Weight[8];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t VirtualLane[3];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_HighPriority0_0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HighPriority0_0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_CntrRegBase_1_offset 0x00002028UL
+/* Default value: 0x0000000000013000 */
+
+#define QIB_7322_ErrMask_1_offset 0x00002080UL
+struct QIB_7322_ErrMask_1_pb {
+	pseudo_bit_t RcvFormatErrMask[1];
+	pseudo_bit_t RcvVCRCErrMask[1];
+	pseudo_bit_t RcvICRCErrMask[1];
+	pseudo_bit_t RcvMinPktLenErrMask[1];
+	pseudo_bit_t RcvMaxPktLenErrMask[1];
+	pseudo_bit_t RcvLongPktLenErrMask[1];
+	pseudo_bit_t RcvShortPktLenErrMask[1];
+	pseudo_bit_t RcvUnexpectedCharErrMask[1];
+	pseudo_bit_t RcvUnsupportedVLErrMask[1];
+	pseudo_bit_t RcvEBPErrMask[1];
+	pseudo_bit_t RcvIBFlowErrMask[1];
+	pseudo_bit_t RcvBadVersionErrMask[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErrMask[1];
+	pseudo_bit_t RcvHdrLenErrMask[1];
+	pseudo_bit_t RcvHdrErrMask[1];
+	pseudo_bit_t RcvIBLostLinkErrMask[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErrMask[1];
+	pseudo_bit_t SendMaxPktLenErrMask[1];
+	pseudo_bit_t SendUnderRunErrMask[1];
+	pseudo_bit_t SendPktLenErrMask[1];
+	pseudo_bit_t SendDroppedSmpPktErrMask[1];
+	pseudo_bit_t SendDroppedDataPktErrMask[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErrMask[1];
+	pseudo_bit_t SendUnsupportedVLErrMask[1];
+	pseudo_bit_t SendBufMisuseErrMask[1];
+	pseudo_bit_t SDmaGenMismatchErrMask[1];
+	pseudo_bit_t SDmaOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrMask[1];
+	pseudo_bit_t SDmaBaseErrMask[1];
+	pseudo_bit_t SDma1stDescErrMask[1];
+	pseudo_bit_t SDmaRpyTagErrMask[1];
+	pseudo_bit_t SDmaDwEnErrMask[1];
+	pseudo_bit_t SDmaMissingDwErrMask[1];
+	pseudo_bit_t SDmaUnexpDataErrMask[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrMask[1];
+	pseudo_bit_t SDmaHaltErrMask[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErrMask[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErrMask[1];
+	pseudo_bit_t IBStatusChangedMask[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrMask_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrMask_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrStatus_1_offset 0x00002088UL
+struct QIB_7322_ErrStatus_1_pb {
+	pseudo_bit_t RcvFormatErr[1];
+	pseudo_bit_t RcvVCRCErr[1];
+	pseudo_bit_t RcvICRCErr[1];
+	pseudo_bit_t RcvMinPktLenErr[1];
+	pseudo_bit_t RcvMaxPktLenErr[1];
+	pseudo_bit_t RcvLongPktLenErr[1];
+	pseudo_bit_t RcvShortPktLenErr[1];
+	pseudo_bit_t RcvUnexpectedCharErr[1];
+	pseudo_bit_t RcvUnsupportedVLErr[1];
+	pseudo_bit_t RcvEBPErr[1];
+	pseudo_bit_t RcvIBFlowErr[1];
+	pseudo_bit_t RcvBadVersionErr[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErr[1];
+	pseudo_bit_t RcvHdrLenErr[1];
+	pseudo_bit_t RcvHdrErr[1];
+	pseudo_bit_t RcvIBLostLinkErr[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErr[1];
+	pseudo_bit_t SendMaxPktLenErr[1];
+	pseudo_bit_t SendUnderRunErr[1];
+	pseudo_bit_t SendPktLenErr[1];
+	pseudo_bit_t SendDroppedSmpPktErr[1];
+	pseudo_bit_t SendDroppedDataPktErr[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErr[1];
+	pseudo_bit_t SendUnsupportedVLErr[1];
+	pseudo_bit_t SendBufMisuseErr[1];
+	pseudo_bit_t SDmaGenMismatchErr[1];
+	pseudo_bit_t SDmaOutOfBoundErr[1];
+	pseudo_bit_t SDmaTailOutOfBoundErr[1];
+	pseudo_bit_t SDmaBaseErr[1];
+	pseudo_bit_t SDma1stDescErr[1];
+	pseudo_bit_t SDmaRpyTagErr[1];
+	pseudo_bit_t SDmaDwEnErr[1];
+	pseudo_bit_t SDmaMissingDwErr[1];
+	pseudo_bit_t SDmaUnexpDataErr[1];
+	pseudo_bit_t SDmaDescAddrMisalignErr[1];
+	pseudo_bit_t SDmaHaltErr[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErr[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErr[1];
+	pseudo_bit_t IBStatusChanged[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrStatus_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrStatus_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ErrClear_1_offset 0x00002090UL
+struct QIB_7322_ErrClear_1_pb {
+	pseudo_bit_t RcvFormatErrClear[1];
+	pseudo_bit_t RcvVCRCErrClear[1];
+	pseudo_bit_t RcvICRCErrClear[1];
+	pseudo_bit_t RcvMinPktLenErrClear[1];
+	pseudo_bit_t RcvMaxPktLenErrClear[1];
+	pseudo_bit_t RcvLongPktLenErrClear[1];
+	pseudo_bit_t RcvShortPktLenErrClear[1];
+	pseudo_bit_t RcvUnexpectedCharErrClear[1];
+	pseudo_bit_t RcvUnsupportedVLErrClear[1];
+	pseudo_bit_t RcvEBPErrClear[1];
+	pseudo_bit_t RcvIBFlowErrClear[1];
+	pseudo_bit_t RcvBadVersionErrClear[1];
+	pseudo_bit_t _unused_0[2];
+	pseudo_bit_t RcvBadTidErrClear[1];
+	pseudo_bit_t RcvHdrLenErrClear[1];
+	pseudo_bit_t RcvHdrErrClear[1];
+	pseudo_bit_t RcvIBLostLinkErrClear[1];
+	pseudo_bit_t _unused_1[11];
+	pseudo_bit_t SendMinPktLenErrClear[1];
+	pseudo_bit_t SendMaxPktLenErrClear[1];
+	pseudo_bit_t SendUnderRunErrClear[1];
+	pseudo_bit_t SendPktLenErrClear[1];
+	pseudo_bit_t SendDroppedSmpPktErrClear[1];
+	pseudo_bit_t SendDroppedDataPktErrClear[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t SendUnexpectedPktNumErrClear[1];
+	pseudo_bit_t SendUnsupportedVLErrClear[1];
+	pseudo_bit_t SendBufMisuseErrClear[1];
+	pseudo_bit_t SDmaGenMismatchErrClear[1];
+	pseudo_bit_t SDmaOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaTailOutOfBoundErrClear[1];
+	pseudo_bit_t SDmaBaseErrClear[1];
+	pseudo_bit_t SDma1stDescErrClear[1];
+	pseudo_bit_t SDmaRpyTagErrClear[1];
+	pseudo_bit_t SDmaDwEnErrClear[1];
+	pseudo_bit_t SDmaMissingDwErrClear[1];
+	pseudo_bit_t SDmaUnexpDataErrClear[1];
+	pseudo_bit_t SDmaDescAddrMisalignErrClear[1];
+	pseudo_bit_t SDmaHaltErrClear[1];
+	pseudo_bit_t _unused_3[4];
+	pseudo_bit_t VL15BufMisuseErrClear[1];
+	pseudo_bit_t _unused_4[2];
+	pseudo_bit_t SHeadersErrClear[1];
+	pseudo_bit_t IBStatusChangedClear[1];
+	pseudo_bit_t _unused_5[5];
+};
+struct QIB_7322_ErrClear_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ErrClear_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TXEStatus_1_offset 0x000020b8UL
+struct QIB_7322_TXEStatus_1_pb {
+	pseudo_bit_t LaFifoEmpty_VL0[1];
+	pseudo_bit_t LaFifoEmpty_VL1[1];
+	pseudo_bit_t LaFifoEmpty_VL2[1];
+	pseudo_bit_t LaFifoEmpty_VL3[1];
+	pseudo_bit_t LaFifoEmpty_VL4[1];
+	pseudo_bit_t LaFifoEmpty_VL5[1];
+	pseudo_bit_t LaFifoEmpty_VL6[1];
+	pseudo_bit_t LaFifoEmpty_VL7[1];
+	pseudo_bit_t _unused_0[7];
+	pseudo_bit_t LaFifoEmpty_VL15[1];
+	pseudo_bit_t _unused_1[14];
+	pseudo_bit_t RmFifoEmpty[1];
+	pseudo_bit_t TXE_IBC_Idle[1];
+	pseudo_bit_t _unused_2[32];
+};
+struct QIB_7322_TXEStatus_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_TXEStatus_1_pb );
+};
+/* Default value: 0x0000000XC00080FF */
+
+#define QIB_7322_RcvCtrl_1_offset 0x00002100UL
+struct QIB_7322_RcvCtrl_1_pb {
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t ContextEnableKernel[1];
+	pseudo_bit_t ContextEnableUser[16];
+	pseudo_bit_t _unused_1[21];
+	pseudo_bit_t RcvIBPortEnable[1];
+	pseudo_bit_t RcvQPMapEnable[1];
+	pseudo_bit_t RcvPartitionKeyDisable[1];
+	pseudo_bit_t RcvResetCredit[1];
+	pseudo_bit_t _unused_2[21];
+};
+struct QIB_7322_RcvCtrl_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvCtrl_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBTHQP_1_offset 0x00002108UL
+struct QIB_7322_RcvBTHQP_1_pb {
+	pseudo_bit_t RcvBTHQP[24];
+	pseudo_bit_t _unused_0[40];
+};
+struct QIB_7322_RcvBTHQP_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvBTHQP_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableA_1_offset 0x00002110UL
+struct QIB_7322_RcvQPMapTableA_1_pb {
+	pseudo_bit_t RcvQPMapContext0[5];
+	pseudo_bit_t RcvQPMapContext1[5];
+	pseudo_bit_t RcvQPMapContext2[5];
+	pseudo_bit_t RcvQPMapContext3[5];
+	pseudo_bit_t RcvQPMapContext4[5];
+	pseudo_bit_t RcvQPMapContext5[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableB_1_offset 0x00002118UL
+struct QIB_7322_RcvQPMapTableB_1_pb {
+	pseudo_bit_t RcvQPMapContext6[5];
+	pseudo_bit_t RcvQPMapContext7[5];
+	pseudo_bit_t RcvQPMapContext8[5];
+	pseudo_bit_t RcvQPMapContext9[5];
+	pseudo_bit_t RcvQPMapContext10[5];
+	pseudo_bit_t RcvQPMapContext11[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableC_1_offset 0x00002120UL
+struct QIB_7322_RcvQPMapTableC_1_pb {
+	pseudo_bit_t RcvQPMapContext12[5];
+	pseudo_bit_t RcvQPMapContext13[5];
+	pseudo_bit_t RcvQPMapContext14[5];
+	pseudo_bit_t RcvQPMapContext15[5];
+	pseudo_bit_t RcvQPMapContext16[5];
+	pseudo_bit_t RcvQPMapContext17[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableD_1_offset 0x00002128UL
+struct QIB_7322_RcvQPMapTableD_1_pb {
+	pseudo_bit_t RcvQPMapContext18[5];
+	pseudo_bit_t RcvQPMapContext19[5];
+	pseudo_bit_t RcvQPMapContext20[5];
+	pseudo_bit_t RcvQPMapContext21[5];
+	pseudo_bit_t RcvQPMapContext22[5];
+	pseudo_bit_t RcvQPMapContext23[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableD_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableD_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableE_1_offset 0x00002130UL
+struct QIB_7322_RcvQPMapTableE_1_pb {
+	pseudo_bit_t RcvQPMapContext24[5];
+	pseudo_bit_t RcvQPMapContext25[5];
+	pseudo_bit_t RcvQPMapContext26[5];
+	pseudo_bit_t RcvQPMapContext27[5];
+	pseudo_bit_t RcvQPMapContext28[5];
+	pseudo_bit_t RcvQPMapContext29[5];
+	pseudo_bit_t _unused_0[34];
+};
+struct QIB_7322_RcvQPMapTableE_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableE_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMapTableF_1_offset 0x00002138UL
+struct QIB_7322_RcvQPMapTableF_1_pb {
+	pseudo_bit_t RcvQPMapContext30[5];
+	pseudo_bit_t RcvQPMapContext31[5];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7322_RcvQPMapTableF_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMapTableF_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSStat_1_offset 0x00002140UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSStart_1_offset 0x00002148UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSInterval_1_offset 0x00002150UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvStatus_1_offset 0x00002160UL
+struct QIB_7322_RcvStatus_1_pb {
+	pseudo_bit_t RxPktInProgress[1];
+	pseudo_bit_t DmaeqBlockingContext[5];
+	pseudo_bit_t _unused_0[58];
+};
+struct QIB_7322_RcvStatus_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvStatus_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvPartitionKey_1_offset 0x00002168UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvQPMulticastContext_1_offset 0x00002170UL
+struct QIB_7322_RcvQPMulticastContext_1_pb {
+	pseudo_bit_t RcvQpMcContext[5];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_RcvQPMulticastContext_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvQPMulticastContext_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvPktLEDCnt_1_offset 0x00002178UL
+struct QIB_7322_RcvPktLEDCnt_1_pb {
+	pseudo_bit_t OFFperiod[32];
+	pseudo_bit_t ONperiod[32];
+};
+struct QIB_7322_RcvPktLEDCnt_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvPktLEDCnt_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaIdleCnt_1_offset 0x00002180UL
+struct QIB_7322_SendDmaIdleCnt_1_pb {
+	pseudo_bit_t SendDmaIdleCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaIdleCnt_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaIdleCnt_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaReloadCnt_1_offset 0x00002188UL
+struct QIB_7322_SendDmaReloadCnt_1_pb {
+	pseudo_bit_t SendDmaReloadCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaReloadCnt_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaReloadCnt_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaDescCnt_1_offset 0x00002190UL
+struct QIB_7322_SendDmaDescCnt_1_pb {
+	pseudo_bit_t SendDmaDescCnt[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaDescCnt_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaDescCnt_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendCtrl_1_offset 0x000021c0UL
+struct QIB_7322_SendCtrl_1_pb {
+	pseudo_bit_t TxeAbortIbc[1];
+	pseudo_bit_t TxeBypassIbc[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t SendEnable[1];
+	pseudo_bit_t _unused_1[3];
+	pseudo_bit_t ForceCreditUpToDate[1];
+	pseudo_bit_t SDmaCleanup[1];
+	pseudo_bit_t SDmaIntEnable[1];
+	pseudo_bit_t SDmaSingleDescriptor[1];
+	pseudo_bit_t SDmaEnable[1];
+	pseudo_bit_t SDmaHalt[1];
+	pseudo_bit_t TxeDrainLaFifo[1];
+	pseudo_bit_t TxeDrainRmFifo[1];
+	pseudo_bit_t IBVLArbiterEn[1];
+	pseudo_bit_t _unused_2[48];
+};
+struct QIB_7322_SendCtrl_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCtrl_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBase_1_offset 0x000021f8UL
+struct QIB_7322_SendDmaBase_1_pb {
+	pseudo_bit_t SendDmaBase[48];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_SendDmaBase_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBase_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaLenGen_1_offset 0x00002200UL
+struct QIB_7322_SendDmaLenGen_1_pb {
+	pseudo_bit_t Length[16];
+	pseudo_bit_t Generation[3];
+	pseudo_bit_t _unused_0[45];
+};
+struct QIB_7322_SendDmaLenGen_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaLenGen_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaTail_1_offset 0x00002208UL
+struct QIB_7322_SendDmaTail_1_pb {
+	pseudo_bit_t SendDmaTail[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendDmaTail_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaTail_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaHead_1_offset 0x00002210UL
+struct QIB_7322_SendDmaHead_1_pb {
+	pseudo_bit_t SendDmaHead[16];
+	pseudo_bit_t _unused_0[16];
+	pseudo_bit_t InternalSendDmaHead[16];
+	pseudo_bit_t _unused_1[16];
+};
+struct QIB_7322_SendDmaHead_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaHead_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaHeadAddr_1_offset 0x00002218UL
+struct QIB_7322_SendDmaHeadAddr_1_pb {
+	pseudo_bit_t SendDmaHeadAddr[48];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_SendDmaHeadAddr_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaHeadAddr_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBufMask0_1_offset 0x00002220UL
+struct QIB_7322_SendDmaBufMask0_1_pb {
+	pseudo_bit_t BufMask_63_0[64];
+};
+struct QIB_7322_SendDmaBufMask0_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBufMask0_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaStatus_1_offset 0x00002238UL
+struct QIB_7322_SendDmaStatus_1_pb {
+	pseudo_bit_t SplFifoDescIndex[16];
+	pseudo_bit_t SplFifoBufNum[8];
+	pseudo_bit_t SplFifoFull[1];
+	pseudo_bit_t SplFifoEmpty[1];
+	pseudo_bit_t SplFifoDisarmed[1];
+	pseudo_bit_t SplFifoReadyToGo[1];
+	pseudo_bit_t ScbFetchDescFlag[1];
+	pseudo_bit_t ScbEntryValid[1];
+	pseudo_bit_t ScbEmpty[1];
+	pseudo_bit_t ScbFull[1];
+	pseudo_bit_t RpyTag_7_0[8];
+	pseudo_bit_t RpyLowAddr_6_0[7];
+	pseudo_bit_t ScbDescIndex_13_0[14];
+	pseudo_bit_t InternalSDmaHalt[1];
+	pseudo_bit_t HaltInProg[1];
+	pseudo_bit_t ScoreBoardDrainInProg[1];
+};
+struct QIB_7322_SendDmaStatus_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaStatus_1_pb );
+};
+/* Default value: 0x0000000042000000 */
+
+#define QIB_7322_SendDmaPriorityThld_1_offset 0x00002258UL
+struct QIB_7322_SendDmaPriorityThld_1_pb {
+	pseudo_bit_t PriorityThreshold[4];
+	pseudo_bit_t _unused_0[60];
+};
+struct QIB_7322_SendDmaPriorityThld_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaPriorityThld_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendHdrErrSymptom_1_offset 0x00002260UL
+struct QIB_7322_SendHdrErrSymptom_1_pb {
+	pseudo_bit_t PacketTooSmall[1];
+	pseudo_bit_t RawIPV6[1];
+	pseudo_bit_t SLIDFail[1];
+	pseudo_bit_t QPFail[1];
+	pseudo_bit_t PkeyFail[1];
+	pseudo_bit_t GRHFail[1];
+	pseudo_bit_t NonKeyPacket[1];
+	pseudo_bit_t _unused_0[57];
+};
+struct QIB_7322_SendHdrErrSymptom_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendHdrErrSymptom_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxCreditVL0_1_offset 0x00002280UL
+struct QIB_7322_RxCreditVL0_1_pb {
+	pseudo_bit_t RxMaxCreditVL[12];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t RxBufrConsumedVL[12];
+	pseudo_bit_t _unused_1[36];
+};
+struct QIB_7322_RxCreditVL0_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxCreditVL0_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaBufUsed0_1_offset 0x00002480UL
+struct QIB_7322_SendDmaBufUsed0_1_pb {
+	pseudo_bit_t BufUsed_63_0[64];
+};
+struct QIB_7322_SendDmaBufUsed0_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaBufUsed0_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendDmaReqTagUsed_1_offset 0x00002498UL
+struct QIB_7322_SendDmaReqTagUsed_1_pb {
+	pseudo_bit_t ReqTagUsed_7_0[8];
+	pseudo_bit_t _unused_0[56];
+};
+struct QIB_7322_SendDmaReqTagUsed_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendDmaReqTagUsed_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendCheckControl_1_offset 0x000024a8UL
+struct QIB_7322_SendCheckControl_1_pb {
+	pseudo_bit_t PacketTooSmall_En[1];
+	pseudo_bit_t RawIPV6_En[1];
+	pseudo_bit_t SLID_En[1];
+	pseudo_bit_t BTHQP_En[1];
+	pseudo_bit_t PKey_En[1];
+	pseudo_bit_t _unused_0[59];
+};
+struct QIB_7322_SendCheckControl_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendCheckControl_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendIBSLIDMask_1_offset 0x000024b0UL
+struct QIB_7322_SendIBSLIDMask_1_pb {
+	pseudo_bit_t SendIBSLIDMask_15_0[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendIBSLIDMask_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendIBSLIDMask_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendIBSLIDAssign_1_offset 0x000024b8UL
+struct QIB_7322_SendIBSLIDAssign_1_pb {
+	pseudo_bit_t SendIBSLIDAssign_15_0[16];
+	pseudo_bit_t _unused_0[48];
+};
+struct QIB_7322_SendIBSLIDAssign_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendIBSLIDAssign_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBCStatusA_1_offset 0x00002540UL
+struct QIB_7322_IBCStatusA_1_pb {
+	pseudo_bit_t LinkTrainingState[5];
+	pseudo_bit_t LinkState[3];
+	pseudo_bit_t LinkSpeedActive[1];
+	pseudo_bit_t LinkWidthActive[1];
+	pseudo_bit_t DDS_RXEQ_FAIL[1];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t IBRxLaneReversed[1];
+	pseudo_bit_t IBTxLaneReversed[1];
+	pseudo_bit_t ScrambleEn[1];
+	pseudo_bit_t ScrambleCapRemote[1];
+	pseudo_bit_t _unused_1[13];
+	pseudo_bit_t LinkSpeedQDR[1];
+	pseudo_bit_t TxReady[1];
+	pseudo_bit_t _unused_2[1];
+	pseudo_bit_t TxCreditOk_VL0[1];
+	pseudo_bit_t TxCreditOk_VL1[1];
+	pseudo_bit_t TxCreditOk_VL2[1];
+	pseudo_bit_t TxCreditOk_VL3[1];
+	pseudo_bit_t TxCreditOk_VL4[1];
+	pseudo_bit_t TxCreditOk_VL5[1];
+	pseudo_bit_t TxCreditOk_VL6[1];
+	pseudo_bit_t TxCreditOk_VL7[1];
+	pseudo_bit_t _unused_3[24];
+};
+struct QIB_7322_IBCStatusA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCStatusA_1_pb );
+};
+/* Default value: 0x0000000000000X02 */
+
+#define QIB_7322_IBCStatusB_1_offset 0x00002548UL
+struct QIB_7322_IBCStatusB_1_pb {
+	pseudo_bit_t LinkRoundTripLatency[26];
+	pseudo_bit_t ReqDDSLocalFromRmt[4];
+	pseudo_bit_t RxEqLocalDevice[2];
+	pseudo_bit_t heartbeat_crosstalk[4];
+	pseudo_bit_t heartbeat_timed_out[1];
+	pseudo_bit_t _unused_0[27];
+};
+struct QIB_7322_IBCStatusB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCStatusB_1_pb );
+};
+/* Default value: 0x00000000XXXXXXXX */
+
+#define QIB_7322_IBCCtrlA_1_offset 0x00002560UL
+struct QIB_7322_IBCCtrlA_1_pb {
+	pseudo_bit_t FlowCtrlPeriod[8];
+	pseudo_bit_t FlowCtrlWaterMark[8];
+	pseudo_bit_t LinkInitCmd[3];
+	pseudo_bit_t LinkCmd[2];
+	pseudo_bit_t MaxPktLen[11];
+	pseudo_bit_t PhyerrThreshold[4];
+	pseudo_bit_t OverrunThreshold[4];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t NumVLane[3];
+	pseudo_bit_t _unused_1[9];
+	pseudo_bit_t IBStatIntReductionEn[1];
+	pseudo_bit_t IBLinkEn[1];
+	pseudo_bit_t LinkDownDefaultState[1];
+	pseudo_bit_t Loopback[1];
+};
+struct QIB_7322_IBCCtrlA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBCCtrlB_1_offset 0x00002568UL
+struct QIB_7322_IBCCtrlB_1_pb {
+	pseudo_bit_t IB_ENHANCED_MODE[1];
+	pseudo_bit_t SD_SPEED[1];
+	pseudo_bit_t SD_SPEED_SDR[1];
+	pseudo_bit_t SD_SPEED_DDR[1];
+	pseudo_bit_t SD_SPEED_QDR[1];
+	pseudo_bit_t IB_NUM_CHANNELS[2];
+	pseudo_bit_t IB_POLARITY_REV_SUPP[1];
+	pseudo_bit_t IB_LANE_REV_SUPPORTED[1];
+	pseudo_bit_t SD_RX_EQUAL_ENABLE[1];
+	pseudo_bit_t SD_ADD_ENB[1];
+	pseudo_bit_t SD_DDSV[1];
+	pseudo_bit_t SD_DDS[4];
+	pseudo_bit_t HRTBT_ENB[1];
+	pseudo_bit_t HRTBT_AUTO[1];
+	pseudo_bit_t HRTBT_PORT[8];
+	pseudo_bit_t HRTBT_REQ[1];
+	pseudo_bit_t IB_ENABLE_FILT_DPKT[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t IB_DLID[16];
+	pseudo_bit_t IB_DLID_MASK[16];
+};
+struct QIB_7322_IBCCtrlB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlB_1_pb );
+};
+/* Default value: 0x00000000000305FF */
+
+#define QIB_7322_IBCCtrlC_1_offset 0x00002570UL
+struct QIB_7322_IBCCtrlC_1_pb {
+	pseudo_bit_t IB_FRONT_PORCH[5];
+	pseudo_bit_t IB_BACK_PORCH[5];
+	pseudo_bit_t _unused_0[54];
+};
+struct QIB_7322_IBCCtrlC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBCCtrlC_1_pb );
+};
+/* Default value: 0x0000000000000301 */
+
+#define QIB_7322_HRTBT_GUID_1_offset 0x00002588UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IB_SDTEST_IF_TX_1_offset 0x00002590UL
+struct QIB_7322_IB_SDTEST_IF_TX_1_pb {
+	pseudo_bit_t TS_T_TX_VALID[1];
+	pseudo_bit_t TS_3_TX_VALID[1];
+	pseudo_bit_t VL_CAP[2];
+	pseudo_bit_t CREDIT_CHANGE[1];
+	pseudo_bit_t _unused_0[6];
+	pseudo_bit_t TS_TX_OPCODE[2];
+	pseudo_bit_t TS_TX_SPEED[3];
+	pseudo_bit_t _unused_1[16];
+	pseudo_bit_t TS_TX_TX_CFG[16];
+	pseudo_bit_t TS_TX_RX_CFG[16];
+};
+struct QIB_7322_IB_SDTEST_IF_TX_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IB_SDTEST_IF_TX_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IB_SDTEST_IF_RX_1_offset 0x00002598UL
+struct QIB_7322_IB_SDTEST_IF_RX_1_pb {
+	pseudo_bit_t TS_T_RX_VALID[1];
+	pseudo_bit_t TS_3_RX_VALID[1];
+	pseudo_bit_t _unused_0[14];
+	pseudo_bit_t TS_RX_A[8];
+	pseudo_bit_t TS_RX_B[8];
+	pseudo_bit_t TS_RX_TX_CFG[16];
+	pseudo_bit_t TS_RX_RX_CFG[16];
+};
+struct QIB_7322_IB_SDTEST_IF_RX_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IB_SDTEST_IF_RX_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBNCModeCtrl_1_offset 0x000025b8UL
+struct QIB_7322_IBNCModeCtrl_1_pb {
+	pseudo_bit_t TSMEnable_send_TS1[1];
+	pseudo_bit_t TSMEnable_send_TS2[1];
+	pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1];
+	pseudo_bit_t _unused_0[5];
+	pseudo_bit_t TSMCode_TS1[9];
+	pseudo_bit_t TSMCode_TS2[9];
+	pseudo_bit_t _unused_1[6];
+	pseudo_bit_t ScrambleCapLocal[1];
+	pseudo_bit_t ScrambleCapRemoteMask[1];
+	pseudo_bit_t ScrambleCapRemoteForce[1];
+	pseudo_bit_t _unused_2[29];
+};
+struct QIB_7322_IBNCModeCtrl_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBNCModeCtrl_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBSerdesStatus_1_offset 0x000025d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBPCSConfig_1_offset 0x000025d8UL
+struct QIB_7322_IBPCSConfig_1_pb {
+	pseudo_bit_t tx_rx_reset[1];
+	pseudo_bit_t xcv_treset[1];
+	pseudo_bit_t xcv_rreset[1];
+	pseudo_bit_t _unused_0[6];
+	pseudo_bit_t link_sync_mask[10];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_IBPCSConfig_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBPCSConfig_1_pb );
+};
+/* Default value: 0x0000000000000007 */
+
+#define QIB_7322_IBSerdesCtrl_1_offset 0x000025e0UL
+struct QIB_7322_IBSerdesCtrl_1_pb {
+	pseudo_bit_t CMODE[7];
+	pseudo_bit_t _unused_0[1];
+	pseudo_bit_t TXIDLE[1];
+	pseudo_bit_t RXPD[1];
+	pseudo_bit_t TXPD[1];
+	pseudo_bit_t PLLPD[1];
+	pseudo_bit_t LPEN[1];
+	pseudo_bit_t RXLOSEN[1];
+	pseudo_bit_t _unused_1[1];
+	pseudo_bit_t IB_LAT_MODE[1];
+	pseudo_bit_t CGMODE[4];
+	pseudo_bit_t CHANNEL_RESET_N[4];
+	pseudo_bit_t DISABLE_RXLATOFF_SDR[1];
+	pseudo_bit_t DISABLE_RXLATOFF_DDR[1];
+	pseudo_bit_t DISABLE_RXLATOFF_QDR[1];
+	pseudo_bit_t _unused_2[37];
+};
+struct QIB_7322_IBSerdesCtrl_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBSerdesCtrl_1_pb );
+};
+/* Default value: 0x0000000000FFA00F */
+
+#define QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_1_offset 0x00002600UL
+struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_1_pb {
+	pseudo_bit_t txcn1_ena[3];
+	pseudo_bit_t txcn1_xtra_emph0[2];
+	pseudo_bit_t txcp1_ena[4];
+	pseudo_bit_t txc0_ena[5];
+	pseudo_bit_t txampcntl_d2a[4];
+	pseudo_bit_t _unused_0[12];
+	pseudo_bit_t reset_tx_deemphasis_override[1];
+	pseudo_bit_t tx_override_deemphasis_select[1];
+	pseudo_bit_t _unused_1[32];
+};
+struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_IBSD_TX_DEEMPHASIS_OVERRIDE_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_SDR_1_offset 0x00002640UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_1_pb {
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_sdr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_sdr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_sdr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_sdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_SDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_1_offset 0x00002648UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_1_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_sdr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_sdr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_sdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_SDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_DDR_1_offset 0x00002650UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_1_pb {
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_ddr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_ddr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_ddr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_ddr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_DDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_1_offset 0x00002658UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_1_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_ddr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_ddr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_ddr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_DDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_STATIC_QDR_1_offset 0x00002660UL
+struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_1_pb {
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch0[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch1[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch2[8];
+	pseudo_bit_t static_disable_rxenadfe_qdr_ch3[8];
+	pseudo_bit_t static_disable_rxenale_qdr_ch0[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch1[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch2[1];
+	pseudo_bit_t static_disable_rxenale_qdr_ch3[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch0[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch1[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch2[1];
+	pseudo_bit_t static_disable_rxenagain_qdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_STATIC_QDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_1_offset 0x00002668UL
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_1_pb {
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch0[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch1[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch2[8];
+	pseudo_bit_t dyn_disable_rxenadfe_qdr_ch3[8];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenale_qdr_ch3[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch0[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch1[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch2[1];
+	pseudo_bit_t dyn_disable_rxenagain_qdr_ch3[1];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_ADAPT_DISABLE_DYNAMIC_QDR_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ADAPT_DISABLE_TIMER_THRESHOLD_1_offset 0x00002670UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogA_1_offset 0x00002800UL
+struct QIB_7322_RxBufrUnCorErrLogA_1_pb {
+	pseudo_bit_t RxBufrUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogB_1_offset 0x00002808UL
+struct QIB_7322_RxBufrUnCorErrLogB_1_pb {
+	pseudo_bit_t RxBufrUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogC_1_offset 0x00002810UL
+struct QIB_7322_RxBufrUnCorErrLogC_1_pb {
+	pseudo_bit_t RxBufrUnCorErrData_191_128[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogD_1_offset 0x00002818UL
+struct QIB_7322_RxBufrUnCorErrLogD_1_pb {
+	pseudo_bit_t RxBufrUnCorErrData_255_192[64];
+};
+struct QIB_7322_RxBufrUnCorErrLogD_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogD_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrUnCorErrLogE_1_offset 0x00002820UL
+struct QIB_7322_RxBufrUnCorErrLogE_1_pb {
+	pseudo_bit_t RxBufrUnCorErrData_258_256[3];
+	pseudo_bit_t RxBufrUnCorErrCheckBit_36_0[37];
+	pseudo_bit_t RxBufrUnCorErrAddr_15_0[16];
+	pseudo_bit_t _unused_0[8];
+};
+struct QIB_7322_RxBufrUnCorErrLogE_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrUnCorErrLogE_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagUnCorErrLogA_1_offset 0x00002828UL
+struct QIB_7322_RxFlagUnCorErrLogA_1_pb {
+	pseudo_bit_t RxFlagUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxFlagUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagUnCorErrLogB_1_offset 0x00002830UL
+struct QIB_7322_RxFlagUnCorErrLogB_1_pb {
+	pseudo_bit_t RxFlagUnCorErrCheckBit_7_0[8];
+	pseudo_bit_t RxFlagUnCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_RxFlagUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqUnCorErrLogA_1_offset 0x00002840UL
+struct QIB_7322_RxLkupiqUnCorErrLogA_1_pb {
+	pseudo_bit_t RxLkupiqUnCorErrData_45_0[46];
+	pseudo_bit_t RxLkupiqUnCorErrCheckBit_7_0[8];
+	pseudo_bit_t _unused_0[10];
+};
+struct QIB_7322_RxLkupiqUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqUnCorErrLogB_1_offset 0x00002848UL
+struct QIB_7322_RxLkupiqUnCorErrLogB_1_pb {
+	pseudo_bit_t RxLkupiqUnCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[51];
+};
+struct QIB_7322_RxLkupiqUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogA_1_offset 0x00002850UL
+struct QIB_7322_RxHdrFifoUnCorErrLogA_1_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogB_1_offset 0x00002858UL
+struct QIB_7322_RxHdrFifoUnCorErrLogB_1_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoUnCorErrLogC_1_offset 0x00002860UL
+struct QIB_7322_RxHdrFifoUnCorErrLogC_1_pb {
+	pseudo_bit_t RxHdrFifoUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxHdrFifoUnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxHdrFifoUnCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoUnCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogA_1_offset 0x00002868UL
+struct QIB_7322_RxDataFifoUnCorErrLogA_1_pb {
+	pseudo_bit_t RxDataFifoUnCorErrData_63_0[64];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogB_1_offset 0x00002870UL
+struct QIB_7322_RxDataFifoUnCorErrLogB_1_pb {
+	pseudo_bit_t RxDataFifoUnCorErrData_127_64[64];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoUnCorErrLogC_1_offset 0x00002878UL
+struct QIB_7322_RxDataFifoUnCorErrLogC_1_pb {
+	pseudo_bit_t RxDataFifoUnCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxDataFifoUnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxDataFifoUnCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoUnCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaFifoArray0UnCorErrLog_1_offset 0x00002880UL
+struct QIB_7322_LaFifoArray0UnCorErrLog_1_pb {
+	pseudo_bit_t LaFifoArray0UnCorErrData_34_0[35];
+	pseudo_bit_t LaFifoArray0UnCorErrCheckBit_10_0[11];
+	pseudo_bit_t LaFifoArray0UnCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[7];
+};
+struct QIB_7322_LaFifoArray0UnCorErrLog_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LaFifoArray0UnCorErrLog_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogA_1_offset 0x000028c0UL
+struct QIB_7322_RmFifoArrayUnCorErrLogA_1_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrData_63_0[64];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogB_1_offset 0x000028c8UL
+struct QIB_7322_RmFifoArrayUnCorErrLogB_1_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrData_127_64[64];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayUnCorErrLogC_1_offset 0x000028d0UL
+struct QIB_7322_RmFifoArrayUnCorErrLogC_1_pb {
+	pseudo_bit_t RmFifoArrayUnCorErrCheckBit_27_0[28];
+	pseudo_bit_t RmFifoArrayUnCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[18];
+	pseudo_bit_t RmFifoArrayUnCorErrDword_3_0[4];
+};
+struct QIB_7322_RmFifoArrayUnCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayUnCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogA_1_offset 0x00002900UL
+struct QIB_7322_RxBufrCorErrLogA_1_pb {
+	pseudo_bit_t RxBufrCorErrData_63_0[64];
+};
+struct QIB_7322_RxBufrCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogB_1_offset 0x00002908UL
+struct QIB_7322_RxBufrCorErrLogB_1_pb {
+	pseudo_bit_t RxBufrCorErrData_127_64[64];
+};
+struct QIB_7322_RxBufrCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogC_1_offset 0x00002910UL
+struct QIB_7322_RxBufrCorErrLogC_1_pb {
+	pseudo_bit_t RxBufrCorErrData_191_128[64];
+};
+struct QIB_7322_RxBufrCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogD_1_offset 0x00002918UL
+struct QIB_7322_RxBufrCorErrLogD_1_pb {
+	pseudo_bit_t RxBufrCorErrData_255_192[64];
+};
+struct QIB_7322_RxBufrCorErrLogD_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogD_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufrCorErrLogE_1_offset 0x00002920UL
+struct QIB_7322_RxBufrCorErrLogE_1_pb {
+	pseudo_bit_t RxBufrCorErrData_258_256[3];
+	pseudo_bit_t RxBufrCorErrCheckBit_36_0[37];
+	pseudo_bit_t RxBufrCorErrAddr_15_0[16];
+	pseudo_bit_t _unused_0[8];
+};
+struct QIB_7322_RxBufrCorErrLogE_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxBufrCorErrLogE_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagCorErrLogA_1_offset 0x00002928UL
+struct QIB_7322_RxFlagCorErrLogA_1_pb {
+	pseudo_bit_t RxFlagCorErrData_63_0[64];
+};
+struct QIB_7322_RxFlagCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlagCorErrLogB_1_offset 0x00002930UL
+struct QIB_7322_RxFlagCorErrLogB_1_pb {
+	pseudo_bit_t RxFlagCorErrCheckBit_7_0[8];
+	pseudo_bit_t RxFlagCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[43];
+};
+struct QIB_7322_RxFlagCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxFlagCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqCorErrLogA_1_offset 0x00002940UL
+struct QIB_7322_RxLkupiqCorErrLogA_1_pb {
+	pseudo_bit_t RxLkupiqCorErrData_45_0[46];
+	pseudo_bit_t RxLkupiqCorErrCheckBit_7_0[8];
+	pseudo_bit_t _unused_0[10];
+};
+struct QIB_7322_RxLkupiqCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLkupiqCorErrLogB_1_offset 0x00002948UL
+struct QIB_7322_RxLkupiqCorErrLogB_1_pb {
+	pseudo_bit_t RxLkupiqCorErrAddr_12_0[13];
+	pseudo_bit_t _unused_0[51];
+};
+struct QIB_7322_RxLkupiqCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxLkupiqCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogA_1_offset 0x00002950UL
+struct QIB_7322_RxHdrFifoCorErrLogA_1_pb {
+	pseudo_bit_t RxHdrFifoCorErrData_63_0[64];
+};
+struct QIB_7322_RxHdrFifoCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogB_1_offset 0x00002958UL
+struct QIB_7322_RxHdrFifoCorErrLogB_1_pb {
+	pseudo_bit_t RxHdrFifoCorErrData_127_64[64];
+};
+struct QIB_7322_RxHdrFifoCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxHdrFifoCorErrLogC_1_offset 0x00002960UL
+struct QIB_7322_RxHdrFifoCorErrLogC_1_pb {
+	pseudo_bit_t RxHdrFifoCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxHdrFifoCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxHdrFifoCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxHdrFifoCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogA_1_offset 0x00002968UL
+struct QIB_7322_RxDataFifoCorErrLogA_1_pb {
+	pseudo_bit_t RxDataFifoCorErrData_63_0[64];
+};
+struct QIB_7322_RxDataFifoCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogB_1_offset 0x00002970UL
+struct QIB_7322_RxDataFifoCorErrLogB_1_pb {
+	pseudo_bit_t RxDataFifoCorErrData_127_64[64];
+};
+struct QIB_7322_RxDataFifoCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataFifoCorErrLogC_1_offset 0x00002978UL
+struct QIB_7322_RxDataFifoCorErrLogC_1_pb {
+	pseudo_bit_t RxDataFifoCorErrCheckBit_15_0[16];
+	pseudo_bit_t RxDataFifoCorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[37];
+};
+struct QIB_7322_RxDataFifoCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RxDataFifoCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaFifoArray0CorErrLog_1_offset 0x00002980UL
+struct QIB_7322_LaFifoArray0CorErrLog_1_pb {
+	pseudo_bit_t LaFifoArray0CorErrData_34_0[35];
+	pseudo_bit_t LaFifoArray0CorErrCheckBit_10_0[11];
+	pseudo_bit_t LaFifoArray0CorErrAddr_10_0[11];
+	pseudo_bit_t _unused_0[7];
+};
+struct QIB_7322_LaFifoArray0CorErrLog_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LaFifoArray0CorErrLog_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogA_1_offset 0x000029c0UL
+struct QIB_7322_RmFifoArrayCorErrLogA_1_pb {
+	pseudo_bit_t RmFifoArrayCorErrData_63_0[64];
+};
+struct QIB_7322_RmFifoArrayCorErrLogA_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogA_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogB_1_offset 0x000029c8UL
+struct QIB_7322_RmFifoArrayCorErrLogB_1_pb {
+	pseudo_bit_t RmFifoArrayCorErrData_127_64[64];
+};
+struct QIB_7322_RmFifoArrayCorErrLogB_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogB_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RmFifoArrayCorErrLogC_1_offset 0x000029d0UL
+struct QIB_7322_RmFifoArrayCorErrLogC_1_pb {
+	pseudo_bit_t RmFifoArrayCorErrCheckBit_27_0[28];
+	pseudo_bit_t RmFifoArrayCorErrAddr_13_0[14];
+	pseudo_bit_t _unused_0[18];
+	pseudo_bit_t RmFifoArrayCorErrDword_3_0[4];
+};
+struct QIB_7322_RmFifoArrayCorErrLogC_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RmFifoArrayCorErrLogC_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HighPriorityLimit_1_offset 0x00002bc0UL
+struct QIB_7322_HighPriorityLimit_1_pb {
+	pseudo_bit_t Limit[8];
+	pseudo_bit_t _unused_0[56];
+};
+struct QIB_7322_HighPriorityLimit_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HighPriorityLimit_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LowPriority0_1_offset 0x00002c00UL
+struct QIB_7322_LowPriority0_1_pb {
+	pseudo_bit_t Weight[8];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t VirtualLane[3];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_LowPriority0_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_LowPriority0_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_HighPriority0_1_offset 0x00002e00UL
+struct QIB_7322_HighPriority0_1_pb {
+	pseudo_bit_t Weight[8];
+	pseudo_bit_t _unused_0[8];
+	pseudo_bit_t VirtualLane[3];
+	pseudo_bit_t _unused_1[45];
+};
+struct QIB_7322_HighPriority0_1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_HighPriority0_1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufAvail0_offset 0x00003000UL
+struct QIB_7322_SendBufAvail0_pb {
+	pseudo_bit_t SendBuf_31_0[64];
+};
+struct QIB_7322_SendBufAvail0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_SendBufAvail0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixTable_offset 0x00008000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_MsixPba_offset 0x00009000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LAMemory_offset 0x0000a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LBIntCnt_offset 0x00011000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LBFlowStallCnt_offset 0x00011008UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDFullErrCnt_offset 0x000110d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTIDValidErrCnt_offset 0x000110d8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxP0HdrEgrOvflCnt_offset 0x000110e8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PcieRetryBufDiagQwordCnt_offset 0x000111a0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxTidFlowDropCnt_offset 0x000111e0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LBIntCnt_0_offset 0x00012000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxCreditUpToDateTimeOut_0_offset 0x00012008UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxSDmaDescCnt_0_offset 0x00012010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxUnsupVLErrCnt_0_offset 0x00012018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDataPktCnt_0_offset 0x00012020UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxFlowPktCnt_0_offset 0x00012028UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDwordCnt_0_offset 0x00012030UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxLenErrCnt_0_offset 0x00012038UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxMaxMinLenErrCnt_0_offset 0x00012040UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxUnderrunCnt_0_offset 0x00012048UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxFlowStallCnt_0_offset 0x00012050UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDroppedPktCnt_0_offset 0x00012058UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDroppedPktCnt_0_offset 0x00012060UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataPktCnt_0_offset 0x00012068UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlowPktCnt_0_offset 0x00012070UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDwordCnt_0_offset 0x00012078UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLenErrCnt_0_offset 0x00012080UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxMaxMinLenErrCnt_0_offset 0x00012088UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxICRCErrCnt_0_offset 0x00012090UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVCRCErrCnt_0_offset 0x00012098UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlowCtrlViolCnt_0_offset 0x000120a0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVersionErrCnt_0_offset 0x000120a8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLinkMalformCnt_0_offset 0x000120b0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEBPCnt_0_offset 0x000120b8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLPCRCErrCnt_0_offset 0x000120c0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufOvflCnt_0_offset 0x000120c8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLenTruncateCnt_0_offset 0x000120d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxPKeyMismatchCnt_0_offset 0x000120e0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBLinkDownedCnt_0_offset 0x00012180UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBSymbolErrCnt_0_offset 0x00012188UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBStatusChangeCnt_0_offset 0x00012190UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBLinkErrRecoveryCnt_0_offset 0x00012198UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ExcessBufferOvflCnt_0_offset 0x000121a8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LocalLinkIntegrityErrCnt_0_offset 0x000121b0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVlErrCnt_0_offset 0x000121b8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDlidFltrCnt_0_offset 0x000121c0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVL15DroppedPktCnt_0_offset 0x000121c8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxOtherLocalPhyErrCnt_0_offset 0x000121d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxQPInvalidContextCnt_0_offset 0x000121d8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxHeadersErrCnt_0_offset 0x000121f8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSRcvDataCount_0_offset 0x00012218UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSRcvPktsCount_0_offset 0x00012220UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitDataCount_0_offset 0x00012228UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitPktsCount_0_offset 0x00012230UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitWaitCount_0_offset 0x00012238UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LBIntCnt_1_offset 0x00013000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxCreditUpToDateTimeOut_1_offset 0x00013008UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxSDmaDescCnt_1_offset 0x00013010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxUnsupVLErrCnt_1_offset 0x00013018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDataPktCnt_1_offset 0x00013020UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxFlowPktCnt_1_offset 0x00013028UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDwordCnt_1_offset 0x00013030UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxLenErrCnt_1_offset 0x00013038UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxMaxMinLenErrCnt_1_offset 0x00013040UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxUnderrunCnt_1_offset 0x00013048UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxFlowStallCnt_1_offset 0x00013050UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxDroppedPktCnt_1_offset 0x00013058UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDroppedPktCnt_1_offset 0x00013060UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDataPktCnt_1_offset 0x00013068UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlowPktCnt_1_offset 0x00013070UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDwordCnt_1_offset 0x00013078UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLenErrCnt_1_offset 0x00013080UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxMaxMinLenErrCnt_1_offset 0x00013088UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxICRCErrCnt_1_offset 0x00013090UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVCRCErrCnt_1_offset 0x00013098UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxFlowCtrlViolCnt_1_offset 0x000130a0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVersionErrCnt_1_offset 0x000130a8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLinkMalformCnt_1_offset 0x000130b0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxEBPCnt_1_offset 0x000130b8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLPCRCErrCnt_1_offset 0x000130c0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxBufOvflCnt_1_offset 0x000130c8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxLenTruncateCnt_1_offset 0x000130d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxPKeyMismatchCnt_1_offset 0x000130e0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBLinkDownedCnt_1_offset 0x00013180UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBSymbolErrCnt_1_offset 0x00013188UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBStatusChangeCnt_1_offset 0x00013190UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBLinkErrRecoveryCnt_1_offset 0x00013198UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ExcessBufferOvflCnt_1_offset 0x000131a8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LocalLinkIntegrityErrCnt_1_offset 0x000131b0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVlErrCnt_1_offset 0x000131b8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxDlidFltrCnt_1_offset 0x000131c0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxVL15DroppedPktCnt_1_offset 0x000131c8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxOtherLocalPhyErrCnt_1_offset 0x000131d0UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RxQPInvalidContextCnt_1_offset 0x000131d8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_TxHeadersErrCnt_1_offset 0x000131f8UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSRcvDataCount_1_offset 0x00013218UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSRcvPktsCount_1_offset 0x00013220UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitDataCount_1_offset 0x00013228UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitPktsCount_1_offset 0x00013230UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PSXmitWaitCount_1_offset 0x00013238UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrArray_offset 0x00014000UL
+struct QIB_7322_RcvEgrArray_pb {
+	pseudo_bit_t RT_Addr[37];
+	pseudo_bit_t RT_BufSize[3];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_RcvEgrArray {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvEgrArray_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDArray0_offset 0x00050000UL
+struct QIB_7322_RcvTIDArray0_pb {
+	pseudo_bit_t RT_Addr[37];
+	pseudo_bit_t RT_BufSize[3];
+	pseudo_bit_t _unused_0[24];
+};
+struct QIB_7322_RcvTIDArray0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDArray0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendPbcCache_offset 0x00070000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaunchFIFO_v0p0_offset 0x00072000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaunchElement_v15p0_offset 0x00076000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PreLaunchFIFO_0_offset 0x00076100UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ScoreBoard_0_offset 0x00076200UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DescriptorFIFO_0_offset 0x00076300UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaunchFIFO_v0p1_offset 0x00078000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_LaunchElement_v15p1_offset 0x0007c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PreLaunchFIFO_1_offset 0x0007c100UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_ScoreBoard_1_offset 0x0007c200UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_DescriptorFIFO_1_offset 0x0007c300UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBufA_0_offset 0x00080000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBufB_0_offset 0x00088000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvFlags_0_offset 0x0008a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvLookupiqBuf_0_offset 0x0008c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvDMADatBuf_0_offset 0x0008e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvDMAHdrBuf_0_offset 0x0008e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBufA_1_offset 0x00090000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvBufB_1_offset 0x00098000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvFlags_1_offset 0x0009a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvLookupiqBuf_1_offset 0x0009c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvDMADatBuf_1_offset 0x0009e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvDMAHdrBuf_1_offset 0x0009e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIERcvBuf_offset 0x000a0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIERetryBuf_offset 0x000a4000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIERcvBufRdToWrAddr_offset 0x000a8000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIERcvHdrRdToWrAddr_offset 0x000b0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIECplBuf_offset 0x000b8000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIECplHdr_offset 0x000bc000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_PCIERcvHdr_offset 0x000bc200UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_IBSD_DDS_MAP_TABLE_0_offset 0x000d0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_0_offset 0x00100000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_0_offset 0x00100800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_1_offset 0x00101000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_1_offset 0x00101800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_2_offset 0x00102000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_2_offset 0x00102800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_3_offset 0x00103000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_3_offset 0x00103800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_4_offset 0x00104000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_4_offset 0x00104800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_5_offset 0x00105000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_5_offset 0x00105800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_6_offset 0x00106000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_6_offset 0x00106800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_7_offset 0x00107000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_7_offset 0x00107800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_8_offset 0x00108000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_8_offset 0x00108800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_9_offset 0x00109000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_9_offset 0x00109800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_10_offset 0x0010a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_10_offset 0x0010a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_11_offset 0x0010b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_11_offset 0x0010b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_12_offset 0x0010c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_12_offset 0x0010c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_13_offset 0x0010d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_13_offset 0x0010d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_14_offset 0x0010e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_14_offset 0x0010e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_15_offset 0x0010f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_15_offset 0x0010f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_16_offset 0x00110000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_16_offset 0x00110800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_17_offset 0x00111000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_17_offset 0x00111800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_18_offset 0x00112000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_18_offset 0x00112800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_19_offset 0x00113000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_19_offset 0x00113800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_20_offset 0x00114000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_20_offset 0x00114800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_21_offset 0x00115000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_21_offset 0x00115800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_22_offset 0x00116000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_22_offset 0x00116800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_23_offset 0x00117000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_23_offset 0x00117800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_24_offset 0x00118000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_24_offset 0x00118800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_25_offset 0x00119000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_25_offset 0x00119800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_26_offset 0x0011a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_26_offset 0x0011a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_27_offset 0x0011b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_27_offset 0x0011b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_28_offset 0x0011c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_28_offset 0x0011c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_29_offset 0x0011d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_29_offset 0x0011d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_30_offset 0x0011e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_30_offset 0x0011e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_31_offset 0x0011f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_31_offset 0x0011f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_32_offset 0x00120000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_32_offset 0x00120800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_33_offset 0x00121000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_33_offset 0x00121800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_34_offset 0x00122000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_34_offset 0x00122800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_35_offset 0x00123000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_35_offset 0x00123800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_36_offset 0x00124000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_36_offset 0x00124800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_37_offset 0x00125000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_37_offset 0x00125800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_38_offset 0x00126000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_38_offset 0x00126800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_39_offset 0x00127000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_39_offset 0x00127800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_40_offset 0x00128000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_40_offset 0x00128800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_41_offset 0x00129000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_41_offset 0x00129800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_42_offset 0x0012a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_42_offset 0x0012a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_43_offset 0x0012b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_43_offset 0x0012b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_44_offset 0x0012c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_44_offset 0x0012c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_45_offset 0x0012d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_45_offset 0x0012d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_46_offset 0x0012e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_46_offset 0x0012e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_47_offset 0x0012f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_47_offset 0x0012f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_48_offset 0x00130000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_48_offset 0x00130800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_49_offset 0x00131000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_49_offset 0x00131800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_50_offset 0x00132000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_50_offset 0x00132800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_51_offset 0x00133000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_51_offset 0x00133800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_52_offset 0x00134000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_52_offset 0x00134800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_53_offset 0x00135000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_53_offset 0x00135800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_54_offset 0x00136000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_54_offset 0x00136800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_55_offset 0x00137000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_55_offset 0x00137800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_56_offset 0x00138000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_56_offset 0x00138800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_57_offset 0x00139000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_57_offset 0x00139800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_58_offset 0x0013a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_58_offset 0x0013a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_59_offset 0x0013b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_59_offset 0x0013b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_60_offset 0x0013c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_60_offset 0x0013c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_61_offset 0x0013d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_61_offset 0x0013d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_62_offset 0x0013e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_62_offset 0x0013e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_63_offset 0x0013f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_63_offset 0x0013f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_64_offset 0x00140000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_64_offset 0x00140800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_65_offset 0x00141000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_65_offset 0x00141800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_66_offset 0x00142000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_66_offset 0x00142800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_67_offset 0x00143000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_67_offset 0x00143800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_68_offset 0x00144000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_68_offset 0x00144800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_69_offset 0x00145000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_69_offset 0x00145800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_70_offset 0x00146000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_70_offset 0x00146800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_71_offset 0x00147000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_71_offset 0x00147800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_72_offset 0x00148000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_72_offset 0x00148800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_73_offset 0x00149000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_73_offset 0x00149800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_74_offset 0x0014a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_74_offset 0x0014a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_75_offset 0x0014b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_75_offset 0x0014b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_76_offset 0x0014c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_76_offset 0x0014c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_77_offset 0x0014d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_77_offset 0x0014d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_78_offset 0x0014e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_78_offset 0x0014e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_79_offset 0x0014f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_79_offset 0x0014f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_80_offset 0x00150000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_80_offset 0x00150800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_81_offset 0x00151000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_81_offset 0x00151800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_82_offset 0x00152000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_82_offset 0x00152800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_83_offset 0x00153000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_83_offset 0x00153800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_84_offset 0x00154000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_84_offset 0x00154800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_85_offset 0x00155000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_85_offset 0x00155800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_86_offset 0x00156000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_86_offset 0x00156800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_87_offset 0x00157000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_87_offset 0x00157800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_88_offset 0x00158000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_88_offset 0x00158800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_89_offset 0x00159000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_89_offset 0x00159800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_90_offset 0x0015a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_90_offset 0x0015a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_91_offset 0x0015b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_91_offset 0x0015b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_92_offset 0x0015c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_92_offset 0x0015c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_93_offset 0x0015d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_93_offset 0x0015d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_94_offset 0x0015e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_94_offset 0x0015e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_95_offset 0x0015f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_95_offset 0x0015f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_96_offset 0x00160000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_96_offset 0x00160800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_97_offset 0x00161000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_97_offset 0x00161800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_98_offset 0x00162000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_98_offset 0x00162800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_99_offset 0x00163000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_99_offset 0x00163800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_100_offset 0x00164000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_100_offset 0x00164800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_101_offset 0x00165000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_101_offset 0x00165800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_102_offset 0x00166000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_102_offset 0x00166800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_103_offset 0x00167000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_103_offset 0x00167800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_104_offset 0x00168000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_104_offset 0x00168800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_105_offset 0x00169000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_105_offset 0x00169800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_106_offset 0x0016a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_106_offset 0x0016a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_107_offset 0x0016b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_107_offset 0x0016b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_108_offset 0x0016c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_108_offset 0x0016c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_109_offset 0x0016d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_109_offset 0x0016d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_110_offset 0x0016e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_110_offset 0x0016e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_111_offset 0x0016f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_111_offset 0x0016f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_112_offset 0x00170000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_112_offset 0x00170800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_113_offset 0x00171000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_113_offset 0x00171800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_114_offset 0x00172000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_114_offset 0x00172800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_115_offset 0x00173000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_115_offset 0x00173800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_116_offset 0x00174000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_116_offset 0x00174800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_117_offset 0x00175000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_117_offset 0x00175800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_118_offset 0x00176000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_118_offset 0x00176800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_119_offset 0x00177000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_119_offset 0x00177800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_120_offset 0x00178000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_120_offset 0x00178800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_121_offset 0x00179000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_121_offset 0x00179800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_122_offset 0x0017a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_122_offset 0x0017a800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_123_offset 0x0017b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_123_offset 0x0017b800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_124_offset 0x0017c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_124_offset 0x0017c800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_125_offset 0x0017d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_125_offset 0x0017d800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_126_offset 0x0017e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_126_offset 0x0017e800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_127_offset 0x0017f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_127_offset 0x0017f800UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_128_offset 0x00180000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_128_offset 0x00181000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_129_offset 0x00182000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_129_offset 0x00183000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_130_offset 0x00184000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_130_offset 0x00185000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_131_offset 0x00186000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_131_offset 0x00187000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_132_offset 0x00188000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_132_offset 0x00189000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_133_offset 0x0018a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_133_offset 0x0018b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_134_offset 0x0018c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_134_offset 0x0018d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_135_offset 0x0018e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_135_offset 0x0018f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_136_offset 0x00190000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_136_offset 0x00191000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_137_offset 0x00192000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_137_offset 0x00193000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_138_offset 0x00194000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_138_offset 0x00195000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_139_offset 0x00196000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_139_offset 0x00197000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_140_offset 0x00198000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_140_offset 0x00199000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_141_offset 0x0019a000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_141_offset 0x0019b000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_142_offset 0x0019c000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_142_offset 0x0019d000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_143_offset 0x0019e000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_143_offset 0x0019f000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_144_offset 0x001a0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_144_offset 0x001a1000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_145_offset 0x001a2000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_145_offset 0x001a3000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_146_offset 0x001a4000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_146_offset 0x001a5000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_147_offset 0x001a6000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_147_offset 0x001a7000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_148_offset 0x001a8000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_148_offset 0x001a9000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_149_offset 0x001aa000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_149_offset 0x001ab000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_150_offset 0x001ac000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_150_offset 0x001ad000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_151_offset 0x001ae000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_151_offset 0x001af000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_152_offset 0x001b0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_152_offset 0x001b1000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_153_offset 0x001b2000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_153_offset 0x001b3000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_154_offset 0x001b4000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_154_offset 0x001b5000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_155_offset 0x001b6000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_155_offset 0x001b7000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_156_offset 0x001b8000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_156_offset 0x001b9000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_157_offset 0x001ba000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_157_offset 0x001bb000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_158_offset 0x001bc000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_158_offset 0x001bd000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufMA_159_offset 0x001be000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufEA_159_offset 0x001bf000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_SendBufVL15_0_offset 0x001c0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail0_offset 0x00200000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead0_offset 0x00200008UL
+struct QIB_7322_RcvHdrHead0_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail0_offset 0x00200010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead0_offset 0x00200018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable0_offset 0x00201000UL
+struct QIB_7322_RcvTIDFlowTable0_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable0 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable0_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail1_offset 0x00210000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead1_offset 0x00210008UL
+struct QIB_7322_RcvHdrHead1_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail1_offset 0x00210010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead1_offset 0x00210018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable1_offset 0x00211000UL
+struct QIB_7322_RcvTIDFlowTable1_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable1 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable1_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail2_offset 0x00220000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead2_offset 0x00220008UL
+struct QIB_7322_RcvHdrHead2_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead2 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead2_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail2_offset 0x00220010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead2_offset 0x00220018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable2_offset 0x00221000UL
+struct QIB_7322_RcvTIDFlowTable2_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable2 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable2_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail3_offset 0x00230000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead3_offset 0x00230008UL
+struct QIB_7322_RcvHdrHead3_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead3 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead3_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail3_offset 0x00230010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead3_offset 0x00230018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable3_offset 0x00231000UL
+struct QIB_7322_RcvTIDFlowTable3_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable3 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable3_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail4_offset 0x00240000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead4_offset 0x00240008UL
+struct QIB_7322_RcvHdrHead4_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead4 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead4_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail4_offset 0x00240010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead4_offset 0x00240018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable4_offset 0x00241000UL
+struct QIB_7322_RcvTIDFlowTable4_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable4 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable4_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail5_offset 0x00250000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead5_offset 0x00250008UL
+struct QIB_7322_RcvHdrHead5_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead5 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead5_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail5_offset 0x00250010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead5_offset 0x00250018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable5_offset 0x00251000UL
+struct QIB_7322_RcvTIDFlowTable5_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable5 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable5_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail6_offset 0x00260000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead6_offset 0x00260008UL
+struct QIB_7322_RcvHdrHead6_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead6 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead6_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail6_offset 0x00260010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead6_offset 0x00260018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable6_offset 0x00261000UL
+struct QIB_7322_RcvTIDFlowTable6_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable6 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable6_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail7_offset 0x00270000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead7_offset 0x00270008UL
+struct QIB_7322_RcvHdrHead7_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead7 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead7_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail7_offset 0x00270010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead7_offset 0x00270018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable7_offset 0x00271000UL
+struct QIB_7322_RcvTIDFlowTable7_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable7 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable7_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail8_offset 0x00280000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead8_offset 0x00280008UL
+struct QIB_7322_RcvHdrHead8_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead8 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead8_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail8_offset 0x00280010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead8_offset 0x00280018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable8_offset 0x00281000UL
+struct QIB_7322_RcvTIDFlowTable8_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable8 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable8_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail9_offset 0x00290000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead9_offset 0x00290008UL
+struct QIB_7322_RcvHdrHead9_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead9 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead9_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail9_offset 0x00290010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead9_offset 0x00290018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable9_offset 0x00291000UL
+struct QIB_7322_RcvTIDFlowTable9_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable9 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable9_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail10_offset 0x002a0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead10_offset 0x002a0008UL
+struct QIB_7322_RcvHdrHead10_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead10 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead10_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail10_offset 0x002a0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead10_offset 0x002a0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable10_offset 0x002a1000UL
+struct QIB_7322_RcvTIDFlowTable10_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable10 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable10_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail11_offset 0x002b0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead11_offset 0x002b0008UL
+struct QIB_7322_RcvHdrHead11_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead11 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead11_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail11_offset 0x002b0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead11_offset 0x002b0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable11_offset 0x002b1000UL
+struct QIB_7322_RcvTIDFlowTable11_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable11 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable11_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail12_offset 0x002c0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead12_offset 0x002c0008UL
+struct QIB_7322_RcvHdrHead12_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead12 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead12_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail12_offset 0x002c0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead12_offset 0x002c0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable12_offset 0x002c1000UL
+struct QIB_7322_RcvTIDFlowTable12_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable12 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable12_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail13_offset 0x002d0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead13_offset 0x002d0008UL
+struct QIB_7322_RcvHdrHead13_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead13 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead13_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail13_offset 0x002d0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead13_offset 0x002d0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable13_offset 0x002d1000UL
+struct QIB_7322_RcvTIDFlowTable13_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable13 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable13_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail14_offset 0x002e0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead14_offset 0x002e0008UL
+struct QIB_7322_RcvHdrHead14_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead14 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead14_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail14_offset 0x002e0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead14_offset 0x002e0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable14_offset 0x002e1000UL
+struct QIB_7322_RcvTIDFlowTable14_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable14 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable14_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail15_offset 0x002f0000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead15_offset 0x002f0008UL
+struct QIB_7322_RcvHdrHead15_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead15 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead15_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail15_offset 0x002f0010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead15_offset 0x002f0018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable15_offset 0x002f1000UL
+struct QIB_7322_RcvTIDFlowTable15_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable15 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable15_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail16_offset 0x00300000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead16_offset 0x00300008UL
+struct QIB_7322_RcvHdrHead16_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead16 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead16_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail16_offset 0x00300010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead16_offset 0x00300018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable16_offset 0x00301000UL
+struct QIB_7322_RcvTIDFlowTable16_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable16 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable16_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrTail17_offset 0x00310000UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvHdrHead17_offset 0x00310008UL
+struct QIB_7322_RcvHdrHead17_pb {
+	pseudo_bit_t RcvHeadPointer[32];
+	pseudo_bit_t counter[16];
+	pseudo_bit_t _unused_0[16];
+};
+struct QIB_7322_RcvHdrHead17 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvHdrHead17_pb );
+};
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexTail17_offset 0x00310010UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvEgrIndexHead17_offset 0x00310018UL
+/* Default value: 0x0000000000000000 */
+
+#define QIB_7322_RcvTIDFlowTable17_offset 0x00311000UL
+struct QIB_7322_RcvTIDFlowTable17_pb {
+	pseudo_bit_t SeqNum[11];
+	pseudo_bit_t GenVal[8];
+	pseudo_bit_t FlowValid[1];
+	pseudo_bit_t HdrSuppEnabled[1];
+	pseudo_bit_t KeepAfterSeqErr[1];
+	pseudo_bit_t KeepOnGenErr[1];
+	pseudo_bit_t _unused_0[4];
+	pseudo_bit_t SeqMismatch[1];
+	pseudo_bit_t GenMismatch[1];
+	pseudo_bit_t _unused_1[35];
+};
+struct QIB_7322_RcvTIDFlowTable17 {
+	PSEUDO_BIT_STRUCT ( struct QIB_7322_RcvTIDFlowTable17_pb );
+};
+/* Default value: 0x0000000000000000 */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_genbits.pl b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_genbits.pl
new file mode 100755
index 0000000..1d5eede
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/infiniband/qib_genbits.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+my $offsets = {};
+my $defaults = {};
+my $structures = {};
+my $structure = "";
+
+while ( <> ) {
+  chomp;
+  if ( /^\#define (\S+)_OFFS (\S+)$/ ) {
+    $structure = $1;
+    $offsets->{$structure} = $2;
+  } elsif ( /^\#define ${structure}_DEF (\S+)$/ ) {
+    $defaults->{$structure} = $1;
+  } elsif ( /^\#define ${structure}_(\S+)_LSB (\S+)$/ ) {
+    $structures->{$structure}->{$1}->{LSB} = $2;
+  } elsif ( /^\#define ${structure}_(\S+)_MSB (\S+)$/ ) {
+    $structures->{$structure}->{$1}->{MSB} = $2;
+  } elsif ( /^\#define ${structure}_(\S+)_RMASK (\S+)$/ ) {
+    $structures->{$structure}->{$1}->{RMASK} = $2;
+  } elsif ( /^\s*$/ ) {
+    # Do nothing
+  } else {
+    print "$_\n";
+  }
+}
+
+my $data = [ map { { name => $_, offset => $offsets->{$_},
+		     default => $defaults->{$_} }; }
+	     sort { hex ( $offsets->{$a} ) <=> hex ( $offsets->{$b} ) }
+	     keys %$offsets ];
+
+foreach my $datum ( @$data ) {
+  next unless exists $structures->{$datum->{name}};
+  $structure = $structures->{$datum->{name}};
+  my $fields = [ map { { name => $_, lsb => $structure->{$_}->{LSB},
+			 msb => $structure->{$_}->{MSB},
+			 rmask => $structure->{$_}->{RMASK} }; }
+		 sort { hex ( $structure->{$a}->{LSB} ) <=>
+			    hex ( $structure->{$b}->{LSB} ) }
+		 keys %$structure ];
+  $datum->{fields} = $fields;
+}
+
+print "\n/* This file has been further processed by $0 */\n\n";
+print "FILE_LICENCE ( GPL2_ONLY );\n\n";
+
+foreach my $datum ( @$data ) {
+  printf "#define %s_offset 0x%08xUL\n",
+      $datum->{name}, hex ( $datum->{offset} );
+  if ( exists $datum->{fields} ) {
+    my $lsb = 0;
+    my $reserved_idx = 0;
+    printf "struct %s_pb {\n", $datum->{name};
+    foreach my $field ( @{$datum->{fields}} ) {
+      my $pad_width = ( hex ( $field->{lsb} ) - $lsb );
+      die "Inconsistent LSB/RMASK in $datum->{name} before $field->{name}\n"
+	  if $pad_width < 0;
+      printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+	  if $pad_width;
+      $lsb += $pad_width;
+      # Damn Perl can't cope with 64-bit hex constants
+      my $width = 0;
+      die "Missing RMASK in $datum->{name}.$field->{name}\n"
+	  unless defined $field->{rmask};
+      my $rmask = $field->{rmask};
+      while ( $rmask =~ /^(0x.+)f$/i ) {
+	$width += 4;
+	$rmask = $1;
+      }
+      $rmask = hex ( $rmask );
+      while ( $rmask ) {
+	$width++;
+	$rmask >>= 1;
+      }
+      if ( defined $field->{msb} ) {
+	my $msb_width = ( hex ( $field->{msb} ) - $lsb + 1 );
+	$width ||= $msb_width;
+	die "Inconsistent LSB/MSB/RMASK in $datum->{name}.$field->{name}\n"
+	    unless $width == $msb_width;
+      }
+      printf "\tpseudo_bit_t %s[%u];\n", $field->{name}, $width;
+      $lsb += $width;
+    }
+    my $pad_width = ( 64 - $lsb );
+    die "Inconsistent LSB/RMASK in $datum->{name} final field\n"
+	if $pad_width < 0;
+    printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+	if $pad_width;
+    printf "};\n";
+    printf "struct %s {\n\tPSEUDO_BIT_STRUCT ( struct %s_pb );\n};\n",
+	$datum->{name}, $datum->{name};
+  }
+  printf "/* Default value: %s */\n", $datum->{default}
+      if defined $datum->{default};
+  print "\n";
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/linux/linux.c b/qemu-0.15.x/roms/ipxe/src/drivers/linux/linux.c
new file mode 100644
index 0000000..83546b2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/linux/linux.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * Linux root_device and root_driver.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/linux.h>
+#include <ipxe/malloc.h>
+#include <ipxe/settings.h>
+
+LIST_HEAD(linux_device_requests);
+LIST_HEAD(linux_global_settings);
+
+/** Go over the device requests looking for a matching linux driver to handle them. */
+static int linux_probe(struct root_device *rootdev)
+{
+	struct linux_device_request *request;
+	struct linux_driver *driver;
+	struct linux_device *device = NULL;
+	int rc;
+
+	/* Apply global settings */
+	linux_apply_settings(&linux_global_settings, NULL);
+
+	list_for_each_entry(request, &linux_device_requests, list) {
+		if (! device)
+			device = zalloc(sizeof(*device));
+
+		if (! device)
+			return -ENOMEM;
+
+		rc = 1;
+
+		for_each_table_entry(driver, LINUX_DRIVERS) {
+			if ((rc = strcmp(driver->name, request->driver)) == 0)
+				break;
+		}
+
+		if (rc != 0) {
+			printf("Linux driver '%s' not found\n", request->driver);
+			continue;
+		}
+
+		if (! driver->can_probe) {
+			printf("Driver '%s' cannot handle any more devices\n", driver->name);
+			continue;
+		}
+
+		/* We found a matching driver so add the device to the hierarchy */
+		list_add(&device->dev.siblings, &rootdev->dev.children);
+		device->dev.parent = &rootdev->dev;
+		INIT_LIST_HEAD(&device->dev.children);
+
+		if (driver->probe(device, request) == 0) {
+			device->driver = driver;
+			device->dev.driver_name = driver->name;
+			/* Driver handled the device so release ownership */
+			device = NULL;
+		} else {
+			/* Driver failed to handle the device so remove it from the hierarchy
+			 * and reuse the object */
+			list_del(&device->dev.siblings);
+		}
+	};
+
+	free(device);
+
+	return 0;
+}
+
+/** Remove all the linux devices registered in probe() */
+static void linux_remove(struct root_device *rootdev)
+{
+	struct linux_device *device;
+	struct linux_device *tmp;
+
+	list_for_each_entry_safe(device, tmp, &rootdev->dev.children, dev.siblings) {
+		list_del(&device->dev.siblings);
+		device->driver->remove(device);
+		free(device);
+	}
+}
+
+/** Linux root driver */
+static struct root_driver linux_root_driver = {
+	.probe = linux_probe,
+	.remove = linux_remove,
+};
+
+/** Linux root device */
+struct root_device linux_root_device __root_device = {
+	.dev = { .name = "linux" },
+	.driver = &linux_root_driver,
+};
+
+struct linux_setting *linux_find_setting(char *name, struct list_head *settings)
+{
+	struct linux_setting *setting;
+	struct linux_setting *result = NULL;
+
+	/* Find the last occurrence of a setting with the specified name */
+	list_for_each_entry(setting, settings, list) {
+		if (strcmp(setting->name, name) == 0) {
+			result = setting;
+		}
+	}
+
+	return result;
+}
+
+void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block)
+{
+	struct linux_setting *setting;
+	int rc;
+
+	list_for_each_entry(setting, new_settings, list) {
+		/* Skip already applied settings */
+		if (setting->applied)
+			continue;
+
+		struct setting *s = find_setting(setting->name);
+		if (s) {
+			rc = storef_setting(settings_block, find_setting(setting->name), setting->value);
+			if (rc != 0)
+				DBG("linux storing setting '%s' = '%s' failed\n", setting->name, setting->value);
+			setting->applied = 1;
+		} else {
+			DBG("linux unknown setting '%s'\n", setting->name);
+		}
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/linux/tap.c b/qemu-0.15.x/roms/ipxe/src/drivers/linux/tap.c
new file mode 100644
index 0000000..53bb16a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/linux/tap.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <linux_api.h>
+#include <ipxe/list.h>
+#include <ipxe/linux.h>
+#include <ipxe/malloc.h>
+#include <ipxe/device.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/settings.h>
+#include <ipxe/socket.h>
+
+/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
+#define __GLIBC__ 2
+#include <linux/socket.h>
+#undef __GLIBC__
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+
+#define RX_BUF_SIZE 1536
+
+/** @file
+ *
+ * The TAP driver.
+ *
+ * The TAP is a Virtual Ethernet network device.
+ */
+
+struct tap_nic {
+	/** Tap interface name */
+	char * interface;
+	/** File descriptor of the opened tap device */
+	int fd;
+};
+
+/** Open the TAP device */
+static int tap_open(struct net_device * netdev)
+{
+	struct tap_nic * nic = netdev->priv;
+	struct ifreq ifr;
+	int ret;
+
+	nic->fd = linux_open("/dev/net/tun", O_RDWR);
+	if (nic->fd < 0) {
+		DBGC(nic, "tap %p open('/dev/net/tun') = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno));
+		return nic->fd;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	/* IFF_NO_PI for no extra packet information */
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+	strncpy(ifr.ifr_name, nic->interface, IFNAMSIZ);
+	DBGC(nic, "tap %p interface = '%s'\n", nic, nic->interface);
+
+	ret = linux_ioctl(nic->fd, TUNSETIFF, &ifr);
+
+	if (ret != 0) {
+		DBGC(nic, "tap %p ioctl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
+		linux_close(nic->fd);
+		return ret;
+	}
+
+	/* Set nonblocking mode to make tap_poll easier */
+	ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
+
+	if (ret != 0) {
+		DBGC(nic, "tap %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
+		linux_close(nic->fd);
+		return ret;
+	}
+
+	return 0;
+}
+
+/** Close the TAP device */
+static void tap_close(struct net_device *netdev)
+{
+	struct tap_nic * nic = netdev->priv;
+	linux_close(nic->fd);
+}
+
+/**
+ * Transmit an ethernet packet.
+ *
+ * The packet can be written to the TAP device and marked as complete immediately.
+ */
+static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
+{
+	struct tap_nic * nic = netdev->priv;
+	int rc;
+
+	/* Pad and align packet */
+	iob_pad(iobuf, ETH_ZLEN);
+
+	rc = linux_write(nic->fd, iobuf->data, iobuf->tail - iobuf->data);
+	DBGC2(nic, "tap %p wrote %d bytes\n", nic, rc);
+	netdev_tx_complete(netdev, iobuf);
+
+	return 0;
+}
+
+/** Poll for new packets */
+static void tap_poll(struct net_device *netdev)
+{
+	struct tap_nic * nic = netdev->priv;
+	struct pollfd pfd;
+	struct io_buffer * iobuf;
+	int r;
+
+	pfd.fd = nic->fd;
+	pfd.events = POLLIN;
+	if (linux_poll(&pfd, 1, 0) == -1) {
+		DBGC(nic, "tap %p poll failed (%s)\n", nic, linux_strerror(linux_errno));
+		return;
+	}
+	if ((pfd.revents & POLLIN) == 0)
+		return;
+
+	/* At this point we know there is at least one new packet to be read */
+
+	iobuf = alloc_iob(RX_BUF_SIZE);
+	if (! iobuf)
+		goto allocfail;
+
+	while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
+		DBGC2(nic, "tap %p read %d bytes\n", nic, r);
+
+		iob_put(iobuf, r);
+		netdev_rx(netdev, iobuf);
+
+		iobuf = alloc_iob(RX_BUF_SIZE);
+		if (! iobuf)
+			goto allocfail;
+	}
+
+	free_iob(iobuf);
+	return;
+
+allocfail:
+	DBGC(nic, "tap %p alloc_iob failed\n", nic);
+}
+
+/**
+ * Set irq.
+ *
+ * Not used on linux, provide a dummy implementation.
+ */
+static void tap_irq(struct net_device *netdev, int enable)
+{
+	struct tap_nic *nic = netdev->priv;
+
+	DBGC(nic, "tap %p irq enable = %d\n", nic, enable);
+}
+
+/** Tap operations */
+static struct net_device_operations tap_operations = {
+	.open		= tap_open,
+	.close		= tap_close,
+	.transmit	= tap_transmit,
+	.poll		= tap_poll,
+	.irq		= tap_irq,
+};
+
+/** Handle a device request for the tap driver */
+static int tap_probe(struct linux_device *device, struct linux_device_request *request)
+{
+	struct linux_setting *if_setting;
+	struct net_device *netdev;
+	struct tap_nic *nic;
+	int rc;
+
+	netdev = alloc_etherdev(sizeof(*nic));
+	if (! netdev)
+		return -ENOMEM;
+
+	netdev_init(netdev, &tap_operations);
+	nic = netdev->priv;
+	linux_set_drvdata(device, netdev);
+	netdev->dev = &device->dev;
+	memset(nic, 0, sizeof(*nic));
+
+	if ((rc = register_netdev(netdev)) != 0)
+		goto err_register;
+
+	netdev_link_up(netdev);
+
+	/* Look for the mandatory if setting */
+	if_setting = linux_find_setting("if", &request->settings);
+
+	/* No if setting */
+	if (! if_setting) {
+		printf("tap missing a mandatory if setting\n");
+		rc = -EINVAL;
+		goto err_settings;
+	}
+
+	nic->interface = if_setting->value;
+	if_setting->applied = 1;
+
+	/* Apply rest of the settings */
+	linux_apply_settings(&request->settings, &netdev->settings.settings);
+
+	return 0;
+
+err_settings:
+	unregister_netdev(netdev);
+err_register:
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+	return rc;
+}
+
+/** Remove the device */
+static void tap_remove(struct linux_device *device)
+{
+	struct net_device *netdev = linux_get_drvdata(device);
+	unregister_netdev(netdev);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+/** Tap linux_driver */
+struct linux_driver tap_driver __linux_driver = {
+	.name = "tap",
+	.probe = tap_probe,
+	.remove = tap_remove,
+	.can_probe = 1,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c503.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c503.c
new file mode 100644
index 0000000..1704dcd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c503.c
@@ -0,0 +1,5 @@
+/* 3Com 3c503, a memory-mapped NS8390-based card */
+#if 0 /* Currently broken! */
+#define INCLUDE_3C503
+#include "ns8390.c"
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509-eisa.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509-eisa.c
new file mode 100644
index 0000000..195a844
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509-eisa.c
@@ -0,0 +1,49 @@
+/*
+ * Split out from 3c509.c, since EISA cards are relatively rare, and
+ * ROM space in 3c509s is very limited.
+ *
+ */
+
+#include <ipxe/eisa.h>
+#include <ipxe/isa.h>
+#include <ipxe/console.h>
+#include "3c509.h"
+
+/*
+ * The EISA probe function
+ *
+ */
+static int el3_eisa_probe ( struct nic *nic, struct eisa_device *eisa ) {
+	
+
+        nic->ioaddr = eisa->ioaddr;
+        nic->irqno = 0;
+        enable_eisa_device ( eisa );
+        
+	/* Hand off to generic t5x9 probe routine */
+	return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
+}
+
+static void el3_eisa_disable ( struct nic *nic, struct eisa_device *eisa ) {
+	t5x9_disable ( nic );
+	disable_eisa_device ( eisa );
+}
+
+static struct eisa_device_id el3_eisa_adapters[] = {
+	{ "3Com 3c509 EtherLink III (EISA)", MFG_ID, PROD_ID },
+};
+
+EISA_DRIVER ( el3_eisa_driver, el3_eisa_adapters );
+
+DRIVER ( "3c509 (EISA)", nic_driver, eisa_driver, el3_eisa_driver,
+	 el3_eisa_probe, el3_eisa_disable );
+
+ISA_ROM ( "3c509-eisa","3c509 (EISA)" );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.c
new file mode 100644
index 0000000..4326a83
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.c
@@ -0,0 +1,432 @@
+/*
+ * Split out into 3c509.c and 3c5x9.c, to make it possible to build a
+ * 3c529 module without including ISA, ISAPnP and EISA code.
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <unistd.h>
+#include <ipxe/device.h>
+#include <ipxe/isa.h>
+#include "3c509.h"
+
+/*
+ * 3c509 cards have their own method of contention resolution; this
+ * effectively defines another bus type similar to ISAPnP.  Even the
+ * original ISA cards can be programatically mapped to any I/O address
+ * in the range 0x200-0x3e0.
+ * 
+ * However, there is a small problem: once you've activated a card,
+ * the only ways to deactivate it will also wipe its tag, meaning that
+ * you won't be able to subsequently reactivate it without going
+ * through the whole ID sequence again.  The solution we adopt is to
+ * isolate and tag all cards at the start, and to immediately
+ * re-isolate and re-tag a card after disabling it.
+ *
+ */
+
+static void t509bus_remove ( struct root_device *rootdev );
+
+static unsigned int t509_id_port = 0;
+static unsigned int t509_max_tag = 0;
+
+/** A 3c509 device */
+struct t509_device {
+	/** Generic device */
+	struct device dev;
+	/** Tag */
+	unsigned int tag;
+	/** I/O address */
+	uint16_t ioaddr;
+	/** Driver-private data
+	 *
+	 * Use t509_set_drvdata() and t509_get_drvdata() to access
+	 * this field.
+	 */
+	void *priv;
+};
+
+/**
+ * Set 3c509 driver-private data
+ *
+ * @v t509		3c509 device
+ * @v priv		Private data
+ */
+static inline void t509_set_drvdata ( struct t509_device *t509, void *priv ) {
+	t509->priv = priv;
+}
+
+/**
+ * Get 3c509 driver-private data
+ *
+ * @v t509		3c509 device
+ * @ret priv		Private data
+ */
+static inline void * t509_get_drvdata ( struct t509_device *t509 ) {
+	return t509->priv;
+}
+
+/*
+ * t509 utility functions
+ *
+ */
+
+static inline void t509_set_id_port ( void ) {
+	outb ( 0x00, t509_id_port );
+}
+
+static inline void t509_wait_for_id_sequence ( void ) {
+	outb ( 0x00, t509_id_port );
+}
+
+static inline void t509_global_reset ( void ) {
+	outb ( 0xc0, t509_id_port );
+}
+
+static inline void t509_reset_tag ( void ) {
+	outb ( 0xd0, t509_id_port );
+}
+
+static inline void t509_set_tag ( uint8_t tag ) {
+	outb ( 0xd0 | tag, t509_id_port );
+}
+
+static inline void t509_select_tag ( uint8_t tag ) {
+	outb ( 0xd8 | tag, t509_id_port );
+}
+
+static inline void t509_activate ( uint16_t ioaddr ) {
+	outb ( 0xe0 | ( ioaddr >> 4 ), t509_id_port );
+}
+
+static inline void t509_deactivate_and_reset_tag ( uint16_t ioaddr ) {
+	outb ( GLOBAL_RESET, ioaddr + EP_COMMAND );
+}
+
+static inline void t509_load_eeprom_word ( uint8_t offset ) {
+	outb ( 0x80 | offset, t509_id_port );
+}
+
+/*
+ * Find a suitable ID port
+ *
+ */
+static inline int t509_find_id_port ( void ) {
+
+	for ( t509_id_port = EP_ID_PORT_START ;
+	      t509_id_port < EP_ID_PORT_END ;
+	      t509_id_port += EP_ID_PORT_INC ) {
+		t509_set_id_port ();
+		/* See if anything's listening */
+		outb ( 0xff, t509_id_port );
+		if ( inb ( t509_id_port ) & 0x01 ) {
+			/* Found a suitable port */
+			DBG ( "T509 using ID port at %04x\n", t509_id_port );
+			return 0;
+		}
+	}
+	/* No id port available */
+	DBG ( "T509 found no available ID port\n" );
+	return -ENOENT;
+}
+
+/*
+ * Send ID sequence to the ID port
+ *
+ */
+static void t509_send_id_sequence ( void ) {
+	unsigned short lrs_state, i;
+
+	t509_set_id_port ();
+	/* Reset IDS on cards */
+	t509_wait_for_id_sequence ();
+	lrs_state = 0xff;
+        for ( i = 0; i < 255; i++ ) {
+                outb ( lrs_state, t509_id_port );
+                lrs_state <<= 1;
+                lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
+        }
+}
+
+/*
+ * We get eeprom data from the id_port given an offset into the eeprom.
+ * Basically; after the ID_sequence is sent to all of the cards; they enter
+ * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
+ * the eeprom data.  We then read the port 16 times and with every read; the
+ * cards check for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
+ * compares the data on the bus; if there is a difference then that card goes
+ * into ID_WAIT state again). In the meantime; one bit of data is returned in
+ * the AX register which is conveniently returned to us by inb().  Hence; we
+ * read 16 times getting one bit of data with each read.
+ */
+static uint16_t t509_id_read_eeprom ( int offset ) {
+	int i, data = 0;
+
+	t509_load_eeprom_word ( offset );
+	/* Do we really need this wait? Won't be noticeable anyway */
+	udelay(10000);
+
+	for ( i = 0; i < 16; i++ ) {
+		data = ( data << 1 ) | ( inw ( t509_id_port ) & 1 );
+	}
+	return data;
+}
+
+/*
+ * Isolate and tag all t509 cards
+ *
+ */
+static int t509_isolate ( void ) {
+	unsigned int i;
+	uint16_t contend[3];
+	int rc;
+
+	/* Find a suitable ID port */
+	if ( ( rc = t509_find_id_port() ) != 0 )
+		return rc;
+
+	while ( 1 ) {
+
+		/* All cards are in ID_WAIT state each time we go
+		 * through this loop.
+		 */
+
+		/* Send the ID sequence */
+		t509_send_id_sequence();
+
+		/* First time through, reset all tags.  On subsequent
+		 * iterations, kill off any already-tagged cards
+		 */
+		if ( t509_max_tag == 0 ) {
+			t509_reset_tag();
+		} else {
+			t509_select_tag ( 0 );
+		}
+	
+		/* Read the manufacturer ID, to see if there are any
+		 * more cards
+		 */
+		if ( t509_id_read_eeprom ( EEPROM_MFG_ID ) != MFG_ID ) {
+			DBG ( "T509 saw %s signs of life\n",
+			      t509_max_tag ? "no further" : "no" );
+			break;
+		}
+
+		/* Perform contention selection on the MAC address */
+		for ( i = 0 ; i < 3 ; i++ ) {
+			contend[i] = t509_id_read_eeprom ( i );
+		}
+
+		/* Only one device will still be left alive.  Tag it. */
+		++t509_max_tag;
+		DBG ( "T509 found card %04x%04x%04x, assigning tag %02x\n",
+		      contend[0], contend[1], contend[2], t509_max_tag );
+		t509_set_tag ( t509_max_tag );
+
+		/* Return all cards back to ID_WAIT state */
+		t509_wait_for_id_sequence();
+	}
+
+	DBG ( "T509 found %d cards using ID port %04x\n",
+	      t509_max_tag, t509_id_port );
+	return 0;
+}
+
+/*
+ * Activate a T509 device
+ *
+ * The device will be enabled at whatever ioaddr is specified in the
+ * struct t509_device; there is no need to stick with the default
+ * ioaddr read from the EEPROM.
+ *
+ */
+static inline void activate_t509_device ( struct t509_device *t509 ) {
+	t509_send_id_sequence ();
+	t509_select_tag ( t509->tag );
+	t509_activate ( t509->ioaddr );
+	DBG ( "T509 activated device %02x at ioaddr %04x\n",
+	      t509->tag, t509->ioaddr );
+}
+
+/*
+ * Deactivate a T509 device
+ *
+ * Disabling also clears the tag, so we immediately isolate and re-tag
+ * this card.
+ *
+ */
+static inline void deactivate_t509_device ( struct t509_device *t509 ) {
+	t509_deactivate_and_reset_tag ( t509->ioaddr );
+	udelay ( 1000 );
+	t509_send_id_sequence ();
+	t509_select_tag ( 0 );
+	t509_set_tag ( t509->tag );
+	t509_wait_for_id_sequence ();
+	DBG ( "T509 deactivated device at %04x and re-tagged as %02x\n",
+	      t509->ioaddr, t509->tag );
+}
+
+/*
+ * The ISA probe function
+ *
+ */
+static int legacy_t509_probe ( struct nic *nic, void *hwdev ) {
+	struct t509_device *t509 = hwdev;
+
+	/* We could change t509->ioaddr if we wanted to */
+	activate_t509_device ( t509 );
+	nic->ioaddr = t509->ioaddr;
+
+	/* Hand off to generic t5x9 probe routine */
+	return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
+}
+
+static void legacy_t509_disable ( struct nic *nic, void *hwdev ) {
+	struct t509_device *t509 = hwdev;
+
+	t5x9_disable ( nic );
+	deactivate_t509_device ( t509 );
+}
+
+static inline void legacy_t509_set_drvdata ( void *hwdev, void *priv ) {
+	t509_set_drvdata ( hwdev, priv );
+}
+
+static inline void * legacy_t509_get_drvdata ( void *hwdev ) {
+	return t509_get_drvdata ( hwdev );
+}
+
+/**
+ * Probe a 3c509 device
+ *
+ * @v t509		3c509 device
+ * @ret rc		Return status code
+ *
+ * Searches for a driver for the 3c509 device.  If a driver is found,
+ * its probe() routine is called.
+ */
+static int t509_probe ( struct t509_device *t509 ) {
+	DBG ( "Adding 3c509 device %02x (I/O %04x)\n",
+	      t509->tag, t509->ioaddr );
+	return legacy_probe ( t509, legacy_t509_set_drvdata, &t509->dev,
+			      legacy_t509_probe, legacy_t509_disable );
+}
+
+/**
+ * Remove a 3c509 device
+ *
+ * @v t509		3c509 device
+ */
+static void t509_remove ( struct t509_device *t509 ) {
+	legacy_remove ( t509, legacy_t509_get_drvdata, legacy_t509_disable );
+	DBG ( "Removed 3c509 device %02x\n", t509->tag );
+}
+
+/**
+ * Probe 3c509 root bus
+ *
+ * @v rootdev		3c509 bus root device
+ *
+ * Scans the 3c509 bus for devices and registers all devices it can
+ * find.
+ */
+static int t509bus_probe ( struct root_device *rootdev ) {
+	struct t509_device *t509 = NULL;
+	unsigned int tag;
+	unsigned int iobase;
+	int rc;
+
+	/* Perform isolation and tagging */
+	if ( ( rc = t509_isolate() ) != 0 )
+		return rc;
+
+	for ( tag = 1 ; tag <= t509_max_tag ; tag++ ) {
+		/* Allocate struct t509_device */
+		if ( ! t509 )
+			t509 = malloc ( sizeof ( *t509 ) );
+		if ( ! t509 ) {
+			rc = -ENOMEM;
+			goto err;
+		}
+		memset ( t509, 0, sizeof ( *t509 ) );
+		t509->tag = tag;
+
+		/* Send the ID sequence */
+		t509_send_id_sequence ();
+
+		/* Select the specified tag */
+		t509_select_tag ( t509->tag );
+
+		/* Read the default I/O address */
+		iobase = t509_id_read_eeprom ( EEPROM_ADDR_CFG );
+		t509->ioaddr = 0x200 + ( ( iobase & 0x1f ) << 4 );
+
+		/* Send card back to ID_WAIT */
+		t509_wait_for_id_sequence();
+
+		/* Add to device hierarchy */
+		snprintf ( t509->dev.name, sizeof ( t509->dev.name ),
+			   "t509%02x", tag );
+		t509->dev.desc.bus_type = BUS_TYPE_ISA;
+		t509->dev.desc.vendor = MFG_ID;
+		t509->dev.desc.device = PROD_ID;
+		t509->dev.parent = &rootdev->dev;
+		list_add ( &t509->dev.siblings, &rootdev->dev.children );
+		INIT_LIST_HEAD ( &t509->dev.children );
+			
+		/* Look for a driver */
+		if ( t509_probe ( t509 ) == 0 ) {
+			/* t509dev registered, we can drop our ref */
+			t509 = NULL;
+		} else {
+			/* Not registered; re-use struct */
+			list_del ( &t509->dev.siblings );
+		}
+	}
+
+	free ( t509 );
+	return 0;
+
+ err:
+	free ( t509 );
+	t509bus_remove ( rootdev );
+	return rc;
+}
+
+/**
+ * Remove 3c509 root bus
+ *
+ * @v rootdev		3c509 bus root device
+ */
+static void t509bus_remove ( struct root_device *rootdev ) {
+	struct t509_device *t509;
+	struct t509_device *tmp;
+
+	list_for_each_entry_safe ( t509, tmp, &rootdev->dev.children,
+				   dev.siblings ) {
+		t509_remove ( t509 );
+		list_del ( &t509->dev.siblings );
+		free ( t509 );
+	}
+}
+
+/** 3c509 bus root device driver */
+static struct root_driver t509_root_driver = {
+	.probe = t509bus_probe,
+	.remove = t509bus_remove,
+};
+
+/** 3c509 bus root device */
+struct root_device t509_root_device __root_device = {
+	.dev = { .name = "3c509" },
+	.driver = &t509_root_driver,
+};
+
+ISA_ROM ( "3c509", "3c509" );
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.h
new file mode 100644
index 0000000..f030d4b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c509.h
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl at novatel.ca) 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. The name
+ * of the author may not be used to endorse or promote products derived from
+ * this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by:
+ *
+ October 2, 1994
+
+ Modified by: Andres Vega Garcia
+
+ INRIA - Sophia Antipolis, France
+ e-mail: avega at sophia.inria.fr
+ finger: avega at pax.inria.fr
+
+ */
+
+FILE_LICENCE ( BSD3 );
+
+#include "nic.h"
+
+/*
+ * Ethernet software status per interface.
+ */
+/*
+ * Some global constants
+ */
+
+#define TX_INIT_RATE		16
+#define TX_INIT_MAX_RATE	64
+#define RX_INIT_LATENCY		64
+#define RX_INIT_EARLY_THRESH	64
+#define MIN_RX_EARLY_THRESHF	16	/* not less than ether_header */
+#define MIN_RX_EARLY_THRESHL	4
+
+#define EEPROMSIZE	0x40
+#define MAX_EEPROMBUSY	1000
+#define EP_ID_PORT_START 0x110  /* avoid 0x100 to avoid conflict with SB16 */
+#define EP_ID_PORT_INC 0x10
+#define EP_ID_PORT_END 0x200
+#define EP_TAG_MAX		0x7 /* must be 2^n - 1 */
+
+/*
+ * Commands to read/write EEPROM trough EEPROM command register (Window 0,
+ * Offset 0xa)
+ */
+#define EEPROM_CMD_RD	0x0080	/* Read:  Address required (5 bits) */
+#define EEPROM_CMD_WR	0x0040	/* Write: Address required (5 bits) */
+#define EEPROM_CMD_ERASE 0x00c0	/* Erase: Address required (5 bits) */
+#define EEPROM_CMD_EWEN	0x0030	/* Erase/Write Enable: No data required */
+
+#define EEPROM_BUSY		(1<<15)
+#define EEPROM_TST_MODE		(1<<14)
+
+/*
+ * Some short functions, worth to let them be a macro
+ */
+#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY)
+#define GO_WINDOW(b,x)	outw(WINDOW_SELECT|(x), (b)+EP_COMMAND)
+
+/**************************************************************************
+ *
+ * These define the EEPROM data structure.  They are used in the probe
+ * function to verify the existance of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0	0x0	/* Word */
+#define EEPROM_NODE_ADDR_1	0x1	/* Word */
+#define EEPROM_NODE_ADDR_2	0x2	/* Word */
+#define EEPROM_PROD_ID		0x3	/* 0x9[0-f]50 */
+#define EEPROM_MFG_ID		0x7	/* 0x6d50 */
+#define EEPROM_ADDR_CFG		0x8	/* Base addr */
+#define EEPROM_RESOURCE_CFG	0x9	/* IRQ. Bits 12-15 */
+
+/**************************************************************************
+ *
+ * These are the registers for the 3Com 3c509 and their bit patterns when
+ * applicable.  They have been taken out the the "EtherLink III Parallel
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual
+ * from 3com.
+ *
+ * Getting this document out of 3Com is almost impossible.  However,
+ * archived copies are available at
+ * http://www.osdever.net/cottontail/downloads/docs/3c5x9b.zip and
+ * several other places on the web (search for 3c5x9b.pdf).
+ *
+ **************************************************************************/
+
+#define EP_COMMAND		0x0e	/* Write. BASE+0x0e is always a
+					 * command reg. */
+#define EP_STATUS		0x0e	/* Read. BASE+0x0e is always status
+					 * reg. */
+#define EP_WINDOW		0x0f	/* Read. BASE+0x0f is always window
+					 * reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+/* Write */
+#define EP_W0_EEPROM_DATA	0x0c
+#define EP_W0_EEPROM_COMMAND	0x0a
+#define EP_W0_RESOURCE_CFG	0x08
+#define EP_W0_ADDRESS_CFG	0x06
+#define EP_W0_CONFIG_CTRL	0x04
+/* Read */
+#define EP_W0_PRODUCT_ID	0x02
+#define EP_W0_MFG_ID		0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+/* Write */
+#define EP_W1_TX_PIO_WR_2	0x02
+#define EP_W1_TX_PIO_WR_1	0x00
+/* Read */
+#define EP_W1_FREE_TX		0x0c
+#define EP_W1_TX_STATUS		0x0b	/* byte */
+#define EP_W1_TIMER		0x0a	/* byte */
+#define EP_W1_RX_STATUS		0x08
+#define EP_W1_RX_PIO_RD_2	0x02
+#define EP_W1_RX_PIO_RD_1	0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+/* Read/Write */
+#define EP_W2_ADDR_5		0x05
+#define EP_W2_ADDR_4		0x04
+#define EP_W2_ADDR_3		0x03
+#define EP_W2_ADDR_2		0x02
+#define EP_W2_ADDR_1		0x01
+#define EP_W2_ADDR_0		0x00
+
+/*
+ * Window 3 registers.  FIFO Management.
+ */
+/* Read */
+#define EP_W3_FREE_TX		0x0c
+#define EP_W3_FREE_RX		0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+/* Read/Write */
+#define EP_W4_MEDIA_TYPE	0x0a
+#define EP_W4_CTRLR_STATUS	0x08
+#define EP_W4_NET_DIAG		0x06
+#define EP_W4_FIFO_DIAG		0x04
+#define EP_W4_HOST_DIAG		0x02
+#define EP_W4_TX_DIAG		0x00
+
+/*
+ * Window 5 Registers.  Results and Internal status.
+ */
+/* Read */
+#define EP_W5_READ_0_MASK	0x0c
+#define EP_W5_INTR_MASK		0x0a
+#define EP_W5_RX_FILTER		0x08
+#define EP_W5_RX_EARLY_THRESH	0x06
+#define EP_W5_TX_AVAIL_THRESH	0x02
+#define EP_W5_TX_START_THRESH	0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+/* Read/Write */
+#define TX_TOTAL_OK		0x0c
+#define RX_TOTAL_OK		0x0a
+#define TX_DEFERRALS		0x08
+#define RX_FRAMES_OK		0x07
+#define TX_FRAMES_OK		0x06
+#define RX_OVERRUNS		0x05
+#define TX_COLLISIONS		0x04
+#define TX_AFTER_1_COLLISION	0x03
+#define TX_AFTER_X_COLLISIONS	0x02
+#define TX_NO_SQE		0x01
+#define TX_CD_LOST		0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ *     15-11:  5-bit code for command to be executed.
+ *     10-0:   11-bit arg if any. For commands with no args;
+ *	      this can be set to anything.
+ */
+#define GLOBAL_RESET		(unsigned short) 0x0000	/* Wait at least 1ms
+							 * after issuing */
+#define WINDOW_SELECT		(unsigned short) (0x1<<11)
+#define START_TRANSCEIVER	(unsigned short) (0x2<<11)	/* Read ADDR_CFG reg to
+							 * determine whether
+							 * this is needed. If
+							 * so; wait 800 uSec
+							 * before using trans-
+							 * ceiver. */
+#define RX_DISABLE		(unsigned short) (0x3<<11)	/* state disabled on
+							 * power-up */
+#define RX_ENABLE		(unsigned short) (0x4<<11)
+#define RX_RESET		(unsigned short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK	(unsigned short) (0x8<<11)
+#define TX_ENABLE		(unsigned short) (0x9<<11)
+#define TX_DISABLE		(unsigned short) (0xa<<11)
+#define TX_RESET		(unsigned short) (0xb<<11)
+#define REQ_INTR		(unsigned short) (0xc<<11)
+#define SET_INTR_MASK		(unsigned short) (0xe<<11)
+#define SET_RD_0_MASK		(unsigned short) (0xf<<11)
+#define SET_RX_FILTER		(unsigned short) (0x10<<11)
+#define FIL_INDIVIDUAL	(unsigned short) (0x1)
+#define FIL_GROUP		(unsigned short) (0x2)
+#define FIL_BRDCST	(unsigned short) (0x4)
+#define FIL_ALL		(unsigned short) (0x8)
+#define SET_RX_EARLY_THRESH	(unsigned short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH	(unsigned short) (0x12<<11)
+#define SET_TX_START_THRESH	(unsigned short) (0x13<<11)
+#define STATS_ENABLE		(unsigned short) (0x15<<11)
+#define STATS_DISABLE		(unsigned short) (0x16<<11)
+#define STOP_TRANSCEIVER	(unsigned short) (0x17<<11)
+/*
+ * The following C_* acknowledge the various interrupts. Some of them don't
+ * do anything.  See the manual.
+ */
+#define ACK_INTR		(unsigned short) (0x6800)
+#define C_INTR_LATCH	(unsigned short) (ACK_INTR|0x1)
+#define C_CARD_FAILURE	(unsigned short) (ACK_INTR|0x2)
+#define C_TX_COMPLETE	(unsigned short) (ACK_INTR|0x4)
+#define C_TX_AVAIL	(unsigned short) (ACK_INTR|0x8)
+#define C_RX_COMPLETE	(unsigned short) (ACK_INTR|0x10)
+#define C_RX_EARLY	(unsigned short) (ACK_INTR|0x20)
+#define C_INT_RQD		(unsigned short) (ACK_INTR|0x40)
+#define C_UPD_STATS	(unsigned short) (ACK_INTR|0x80)
+
+/*
+ * Status register. All windows.
+ *
+ *     15-13:  Window number(0-7).
+ *     12:     Command_in_progress.
+ *     11:     reserved.
+ *     10:     reserved.
+ *     9:      reserved.
+ *     8:      reserved.
+ *     7:      Update Statistics.
+ *     6:      Interrupt Requested.
+ *     5:      RX Early.
+ *     4:      RX Complete.
+ *     3:      TX Available.
+ *     2:      TX Complete.
+ *     1:      Adapter Failure.
+ *     0:      Interrupt Latch.
+ */
+#define S_INTR_LATCH		(unsigned short) (0x1)
+#define S_CARD_FAILURE		(unsigned short) (0x2)
+#define S_TX_COMPLETE		(unsigned short) (0x4)
+#define S_TX_AVAIL		(unsigned short) (0x8)
+#define S_RX_COMPLETE		(unsigned short) (0x10)
+#define S_RX_EARLY		(unsigned short) (0x20)
+#define S_INT_RQD		(unsigned short) (0x40)
+#define S_UPD_STATS		(unsigned short) (0x80)
+#define S_5_INTS		(S_CARD_FAILURE|S_TX_COMPLETE|\
+				 S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY)
+#define S_COMMAND_IN_PROGRESS	(unsigned short) (0x1000)
+
+/*
+ * FIFO Registers.
+ * RX Status. Window 1/Port 08
+ *
+ *     15:     Incomplete or FIFO empty.
+ *     14:     1: Error in RX Packet   0: Incomplete or no error.
+ *     13-11:  Type of error.
+ *	      1000 = Overrun.
+ *	      1011 = Run Packet Error.
+ *	      1100 = Alignment Error.
+ *	      1101 = CRC Error.
+ *	      1001 = Oversize Packet Error (>1514 bytes)
+ *	      0010 = Dribble Bits.
+ *	      (all other error codes, no errors.)
+ *
+ *     10-0:   RX Bytes (0-1514)
+ */
+#define ERR_RX_INCOMPLETE	(unsigned short) (0x1<<15)
+#define ERR_RX			(unsigned short) (0x1<<14)
+#define ERR_RX_OVERRUN		(unsigned short) (0x8<<11)
+#define ERR_RX_RUN_PKT		(unsigned short) (0xb<<11)
+#define ERR_RX_ALIGN		(unsigned short) (0xc<<11)
+#define ERR_RX_CRC		(unsigned short) (0xd<<11)
+#define ERR_RX_OVERSIZE		(unsigned short) (0x9<<11)
+#define ERR_RX_DRIBBLE		(unsigned short) (0x2<<11)
+
+/*
+ * FIFO Registers.
+ * TX Status. Window 1/Port 0B
+ *
+ *   Reports the transmit status of a completed transmission. Writing this
+ *   register pops the transmit completion stack.
+ *
+ *   Window 1/Port 0x0b.
+ *
+ *     7:      Complete
+ *     6:      Interrupt on successful transmission requested.
+ *     5:      Jabber Error (TP Only, TX Reset required. )
+ *     4:      Underrun (TX Reset required. )
+ *     3:      Maximum Collisions.
+ *     2:      TX Status Overflow.
+ *     1-0:    Undefined.
+ *
+ */
+#define TXS_COMPLETE		0x80
+#define TXS_SUCCES_INTR_REQ		0x40
+#define TXS_JABBER		0x20
+#define TXS_UNDERRUN		0x10
+#define TXS_MAX_COLLISION	0x8
+#define TXS_STATUS_OVERFLOW	0x4
+
+/*
+ * Configuration control register.
+ * Window 0/Port 04
+ */
+/* Read */
+#define IS_AUI				(1<<13)
+#define IS_BNC				(1<<12)
+#define IS_UTP				(1<<9)
+/* Write */
+#define ENABLE_DRQ_IRQ			0x0001
+#define W0_P4_CMD_RESET_ADAPTER		0x4
+#define W0_P4_CMD_ENABLE_ADAPTER	0x1
+/*
+ * Media type and status.
+ * Window 4/Port 0A
+ */
+#define ENABLE_UTP			0xc0
+#define DISABLE_UTP			0x0
+
+/*
+ * Resource control register
+ */
+
+#define SET_IRQ(i)	( ((i)<<12) | 0xF00) /* set IRQ i */
+
+/*
+ * Receive status register
+ */
+
+#define RX_BYTES_MASK			(unsigned short) (0x07ff)
+#define RX_ERROR	0x4000
+#define RX_INCOMPLETE	0x8000
+
+/*
+ * Misc defines for various things.
+ */
+#define MFG_ID				0x6d50 /* in EEPROM and W0 ADDR_CONFIG */
+#define PROD_ID				0x9150
+
+#define AUI				0x1
+#define BNC				0x2
+#define UTP				0x4
+
+#define RX_BYTES_MASK			(unsigned short) (0x07ff)
+
+/*
+ * Function shared between 3c509.c and 3c529.c
+ */
+extern int t5x9_probe ( struct nic *nic,
+			uint16_t prod_id_check, uint16_t prod_id_mask );
+extern void t5x9_disable ( struct nic *nic );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.c
new file mode 100644
index 0000000..2b86069
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.c
@@ -0,0 +1,763 @@
+/*
+*    3c515.c -- 3COM 3C515 Fast Etherlink ISA 10/100BASE-TX driver for etherboot
+*    Copyright (C) 2002 Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+* Portions of this code:
+* Copyright (C) 1997-2002 Donald Becker  3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux.
+* Copyright (C) 2001 P.J.H.Fox (fox at roestock.demon.co.uk) ISAPNP Tools
+* Copyright (c) 2002 Jaroslav Kysela <perex at suse.cz>  ISA Plug & Play support Linux Kernel
+* Copyright (C) 2000 Shusuke Nisiyama <shu at athena.qe.eng.hokudai.ac.jp> etherboot-5.0.5 3c595.c
+* Coptright (C) 1995 Martin Renters etherboot-5.0.5 3c509.c
+* Copyright (C) 1999 LightSys Technology Services, Inc. etherboot-5.0.5 3c90x.c
+* Portions Copyright (C) 1999 Steve Smith etherboot-5.0.5 3c90x.c
+*
+* The probe and reset functions and defines are direct copies from the
+* Becker code modified where necessary to make it work for etherboot
+*
+* The poll and transmit functions either contain code from or were written by referencing
+* the above referenced etherboot drivers.  This driver would not have been
+* possible without this prior work
+*
+* REVISION HISTORY:
+* ================
+* v0.10	4-17-2002	TJL	Initial implementation.
+* v0.11 4-17-2002       TJL     Cleanup of the code
+* v0.12 4-26-2002       TJL     Added ISA Plug and Play for Non-PNP Bioses
+* v0.13 6-10-2002       TJL     Fixed ISA_PNP MAC Address problem
+* v0.14 9-23-2003	TJL	Replaced delay with currticks
+*
+* Indent Options: indent -kr -i8
+* *********************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+#include <ipxe/isapnp.h>
+#include <ipxe/isa.h> /* for ISA_ROM */
+#include <ipxe/ethernet.h>
+
+static void t3c515_wait(unsigned int nticks)
+{
+	unsigned int to = currticks() + nticks;
+	while (currticks() < to)
+		/* wait */ ;
+}
+
+/* TJL definations */
+#define HZ      100
+static int if_port;
+static struct corkscrew_private *vp;
+/* Brought directly from 3c515.c by Becker */
+#define CORKSCREW 1
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt.
+static int max_interrupt_work = 20;
+*/
+
+/* Enable the automatic media selection code -- usually set. */
+#define AUTOMEDIA 1
+
+/* Allow the use of fragment bus master transfers instead of only
+   programmed-I/O for Vortex cards.  Full-bus-master transfers are always
+   enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
+   the feature may be turned on using 'options'. */
+#define VORTEX_BUS_MASTER
+
+/* A few values that may be tweaked. */
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	16
+#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
+
+/* "Knobs" for adjusting internal parameters. */
+/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
+#define DRIVER_DEBUG 1
+/* Some values here only for performance evaluation and path-coverage
+   debugging.
+static int rx_nocopy, rx_copy, queued_packet;
+*/
+
+#define CORKSCREW_ID 10
+
+#define EL3WINDOW(win_num) \
+	outw(SelectWindow + (win_num), nic->ioaddr + EL3_CMD)
+#define EL3_CMD 0x0e
+#define EL3_STATUS 0x0e
+#define RX_BYTES_MASK			(unsigned short) (0x07ff)
+
+enum corkscrew_cmd {
+	TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
+	RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
+	UpStall = 6 << 11, UpUnstall = (6 << 11) + 1,
+	DownStall = (6 << 11) + 2, DownUnstall = (6 << 11) + 3,
+	RxDiscard = 8 << 11, TxEnable = 9 << 11, TxDisable =
+	    10 << 11, TxReset = 11 << 11,
+	FakeIntr = 12 << 11, AckIntr = 13 << 11, SetIntrEnb = 14 << 11,
+	SetStatusEnb = 15 << 11, SetRxFilter = 16 << 11, SetRxThreshold =
+	    17 << 11,
+	SetTxThreshold = 18 << 11, SetTxStart = 19 << 11,
+	StartDMAUp = 20 << 11, StartDMADown = (20 << 11) + 1, StatsEnable =
+	    21 << 11,
+	StatsDisable = 22 << 11, StopCoax = 23 << 11,
+};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+/* Bits in the general status register. */
+enum corkscrew_status {
+	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+	IntReq = 0x0040, StatsFull = 0x0080,
+	DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
+	DMAInProgress = 1 << 11,	/* DMA controller is still busy. */
+	CmdInProgress = 1 << 12,	/* EL3_CMD is still busy. */
+};
+
+/* Register window 1 offsets, the window used in normal operation.
+   On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
+enum Window1 {
+	TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
+	RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
+	TxFree = 0x1C,		/* Remaining free bytes in Tx buffer. */
+};
+enum Window0 {
+	Wn0IRQ = 0x08,
+#if defined(CORKSCREW)
+	Wn0EepromCmd = 0x200A,	/* Corkscrew EEPROM command register. */
+	Wn0EepromData = 0x200C,	/* Corkscrew EEPROM results register. */
+#else
+	Wn0EepromCmd = 10,	/* Window 0: EEPROM command register. */
+	Wn0EepromData = 12,	/* Window 0: EEPROM results register. */
+#endif
+};
+enum Win0_EEPROM_bits {
+	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
+	EEPROM_EWENB = 0x30,	/* Enable erasing/writing for 10 msec. */
+	EEPROM_EWDIS = 0x00,	/* Disable EWENB before 10 msec timeout. */
+};
+
+enum Window3 {			/* Window 3: MAC/config bits. */
+	Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
+};
+union wn3_config {
+	int i;
+	struct w3_config_fields {
+		unsigned int ram_size:3, ram_width:1, ram_speed:2,
+		    rom_size:2;
+		int pad8:8;
+		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1,
+		    autoselect:1;
+		int pad24:7;
+	} u;
+};
+
+enum Window4 {
+	Wn4_NetDiag = 6, Wn4_Media = 10,	/* Window 4: Xcvr/media bits. */
+};
+enum Win4_Media_bits {
+	Media_SQE = 0x0008,	/* Enable SQE error counting for AUI. */
+	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
+	Media_Lnk = 0x0080,	/* Enable just link beat for 100TX/100FX. */
+	Media_LnkBeat = 0x0800,
+};
+enum Window7 {			/* Window 7: Bus Master control. */
+	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
+};
+
+/* Boomerang-style bus master control registers.  Note ISA aliases! */
+enum MasterCtrl {
+	PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
+	    0x40c,
+	TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
+};
+
+/* The Rx and Tx descriptor lists.
+   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
+   alignment contraint on tx_ring[] and rx_ring[]. */
+struct boom_rx_desc {
+	u32 next;
+	s32 status;
+	u32 addr;
+	s32 length;
+};
+
+/* Values for the Rx status entry. */
+enum rx_desc_status {
+	RxDComplete = 0x00008000, RxDError = 0x4000,
+	/* See boomerang_rx() for actual error bits */
+};
+
+struct boom_tx_desc {
+	u32 next;
+	s32 status;
+	u32 addr;
+	s32 length;
+};
+
+struct corkscrew_private {
+	const char *product_name;
+	struct net_device *next_module;
+	/* The Rx and Tx rings are here to keep them quad-word-aligned. */
+	struct boom_rx_desc rx_ring[RX_RING_SIZE];
+	struct boom_tx_desc tx_ring[TX_RING_SIZE];
+	/* The addresses of transmit- and receive-in-place skbuffs. */
+	struct sk_buff *rx_skbuff[RX_RING_SIZE];
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	unsigned int cur_rx, cur_tx;	/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	struct sk_buff *tx_skb;	/* Packet being eaten by bus master ctrl.  */
+	int capabilities;	/* Adapter capabilities word. */
+	int options;		/* User-settable misc. driver options. */
+	int last_rx_packets;	/* For media autoselection. */
+	unsigned int available_media:8,	/* From Wn3_Options */
+	 media_override:3,	/* Passed-in media type. */
+	 default_media:3,	/* Read from the EEPROM. */
+	 full_duplex:1, autoselect:1, bus_master:1,	/* Vortex can only do a fragment bus-m. */
+	 full_bus_master_tx:1, full_bus_master_rx:1,	/* Boomerang  */
+	 tx_full:1;
+};
+
+/* The action to take with a media selection timer tick.
+   Note that we deviate from the 3Com order by checking 10base2 before AUI.
+ */
+enum xcvr_types {
+	XCVR_10baseT =
+	    0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+	XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
+};
+
+static struct media_table {
+	char *name;
+	unsigned int media_bits:16,	/* Bits to set in Wn4_Media register. */
+	 mask:8,		/* The transceiver-present bit in Wn3_Config. */
+	 next:8;		/* The media type to try next. */
+	short wait;		/* Time before we check media status. */
+} media_tbl[] = {
+	{
+	"10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10}
+	, {
+	"10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}
+	, {
+	"undefined", 0, 0x80, XCVR_10baseT, 10000}
+	, {
+	"10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}
+	, {
+	"100baseTX", Media_Lnk, 0x02, XCVR_100baseFx,
+		    (14 * HZ) / 10}
+	, {
+	"100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}
+	, {
+	"MII", 0, 0x40, XCVR_10baseT, 3 * HZ}
+	, {
+	"undefined", 0, 0x01, XCVR_10baseT, 10000}
+	, {
+	"Default", 0, 0xFF, XCVR_10baseT, 10000}
+,};
+
+/* TILEG Modified to remove reference to dev */
+static int corkscrew_found_device(int ioaddr, int irq, int product_index,
+				  int options, struct nic *nic);
+static int corkscrew_probe1(int ioaddr, int irq, int product_index,
+			    struct nic *nic);
+
+/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
+/* Note: this is the only limit on the number of cards supported!! */
+static int options = -1;
+
+/* End Brought directly from 3c515.c by Becker */
+
+/**************************************************************************
+RESET - Reset adapter
+***************************************************************************/
+static void t515_reset(struct nic *nic)
+{
+	union wn3_config config;
+	int i;
+
+	/* Before initializing select the active media port. */
+	EL3WINDOW(3);
+	if (vp->full_duplex)
+		outb(0x20, nic->ioaddr + Wn3_MAC_Ctrl);	/* Set the full-duplex bit. */
+	config.i = inl(nic->ioaddr + Wn3_Config);
+
+	if (vp->media_override != 7) {
+		DBG ( "Media override to transceiver %d (%s).\n",
+		      vp->media_override,
+		      media_tbl[vp->media_override].name);
+		if_port = vp->media_override;
+	} else if (vp->autoselect) {
+		/* Find first available media type, starting with 100baseTx. */
+		if_port = 4;
+		while (!(vp->available_media & media_tbl[if_port].mask))
+			if_port = media_tbl[if_port].next;
+
+		DBG ( "Initial media type %s.\n",
+		      media_tbl[if_port].name);
+	} else
+		if_port = vp->default_media;
+
+	config.u.xcvr = if_port;
+	outl(config.i, nic->ioaddr + Wn3_Config);
+
+	DBG ( "corkscrew_open() InternalConfig 0x%hX.\n",
+	      config.i);
+
+	outw(TxReset, nic->ioaddr + EL3_CMD);
+	for (i = 20; i >= 0; i--)
+		if (!(inw(nic->ioaddr + EL3_STATUS) & CmdInProgress))
+			break;
+
+	outw(RxReset, nic->ioaddr + EL3_CMD);
+	/* Wait a few ticks for the RxReset command to complete. */
+	for (i = 20; i >= 0; i--)
+		if (!(inw(nic->ioaddr + EL3_STATUS) & CmdInProgress))
+			break;
+
+	outw(SetStatusEnb | 0x00, nic->ioaddr + EL3_CMD);
+
+#ifdef debug_3c515
+		EL3WINDOW(4);
+		DBG ( "FIXME: fix print for irq, not 9" );
+		DBG ( "corkscrew_open() irq %d media status 0x%hX.\n",
+		      9, inw(nic->ioaddr + Wn4_Media) );
+#endif
+
+	/* Set the station address and mask in window 2 each time opened. */
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(nic->node_addr[i], nic->ioaddr + i);
+	for (; i < 12; i += 2)
+		outw(0, nic->ioaddr + i);
+
+	if (if_port == 3)
+		/* Start the thinnet transceiver. We should really wait 50ms... */
+		outw(StartCoax, nic->ioaddr + EL3_CMD);
+	EL3WINDOW(4);
+	outw((inw(nic->ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
+	     media_tbl[if_port].media_bits, nic->ioaddr + Wn4_Media);
+
+	/* Switch to the stats window, and clear all stats by reading. */
+/*	outw(StatsDisable, nic->ioaddr + EL3_CMD);*/
+	EL3WINDOW(6);
+	for (i = 0; i < 10; i++)
+		inb(nic->ioaddr + i);
+	inw(nic->ioaddr + 10);
+	inw(nic->ioaddr + 12);
+	/* New: On the Vortex we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(nic->ioaddr + 12);
+	/* ..and on the Boomerang we enable the extra statistics bits. */
+	outw(0x0040, nic->ioaddr + Wn4_NetDiag);
+
+	/* Switch to register set 7 for normal use. */
+	EL3WINDOW(7);
+
+	/* Temporarily left in place.  If these FIXMEs are printed
+	   it meand that special logic for that card may need to be added
+	   see Becker's 3c515.c driver */
+	if (vp->full_bus_master_rx) {	/* Boomerang bus master. */
+		printf("FIXME: Is this if necessary");
+		vp->cur_rx = vp->dirty_rx = 0;
+		DBG ( "   Filling in the Rx ring.\n" );
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			printf("FIXME: Is this if necessary");
+		}
+	}
+	if (vp->full_bus_master_tx) {	/* Boomerang bus master Tx. */
+		vp->cur_tx = vp->dirty_tx = 0;
+		outb(PKT_BUF_SZ >> 8, nic->ioaddr + TxFreeThreshold);	/* Room for a packet. */
+		/* Clear the Tx ring. */
+		for (i = 0; i < TX_RING_SIZE; i++)
+			vp->tx_skbuff[i] = 0;
+		outl(0, nic->ioaddr + DownListPtr);
+	}
+	/* Set receiver mode: presumably accept b-case and phys addr only. */
+	outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
+	     nic->ioaddr + EL3_CMD);
+
+	outw(RxEnable, nic->ioaddr + EL3_CMD);	/* Enable the receiver. */
+	outw(TxEnable, nic->ioaddr + EL3_CMD);	/* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
+	     (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+	     (vp->full_bus_master_rx ? UpComplete : RxComplete) |
+	     (vp->bus_master ? DMADone : 0), nic->ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+	     nic->ioaddr + EL3_CMD);
+	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+	     | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
+	     nic->ioaddr + EL3_CMD);
+
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int t515_poll(struct nic *nic, int retrieve)
+{
+	short status, cst;
+	register short rx_fifo;
+
+	cst = inw(nic->ioaddr + EL3_STATUS);
+
+	if ((cst & RxComplete) == 0) {
+		/* Ack all pending events, and set active indicator mask. */
+		outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		     nic->ioaddr + EL3_CMD);
+		outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+		     StatsFull | (vp->
+				  bus_master ? DMADone : 0) | UpComplete |
+		     DownComplete, nic->ioaddr + EL3_CMD);
+		return 0;
+	}
+	status = inw(nic->ioaddr + RxStatus);
+
+	if (status & RxDError) {
+		printf("RxDError\n");
+		outw(RxDiscard, nic->ioaddr + EL3_CMD);
+		return 0;
+	}
+
+	rx_fifo = status & RX_BYTES_MASK;
+	if (rx_fifo == 0)
+		return 0;
+
+	if ( ! retrieve ) return 1;
+
+	DBG ( "[l=%d", rx_fifo );
+	insw(nic->ioaddr + RX_FIFO, nic->packet, rx_fifo / 2);
+	if (rx_fifo & 1)
+		nic->packet[rx_fifo - 1] = inb(nic->ioaddr + RX_FIFO);
+	nic->packetlen = rx_fifo;
+
+	while (1) {
+		status = inw(nic->ioaddr + RxStatus);
+		DBG ( "0x%hX*", status );
+		rx_fifo = status & RX_BYTES_MASK;
+
+		if (rx_fifo > 0) {
+			insw(nic->ioaddr + RX_FIFO, nic->packet + nic->packetlen,
+			     rx_fifo / 2);
+			if (rx_fifo & 1)
+				nic->packet[nic->packetlen + rx_fifo - 1] =
+				    inb(nic->ioaddr + RX_FIFO);
+			nic->packetlen += rx_fifo;
+			DBG ( "+%d", rx_fifo );
+		}
+		if ((status & RxComplete) == 0) {
+			DBG ( "=%d", nic->packetlen );
+			break;
+		}
+		udelay(1000);
+	}
+
+	/* acknowledge reception of packet */
+	outw(RxDiscard, nic->ioaddr + EL3_CMD);
+	while (inw(nic->ioaddr + EL3_STATUS) & CmdInProgress);
+#ifdef debug_3c515
+	{
+		unsigned short type = 0;
+		type = (nic->packet[12] << 8) | nic->packet[13];
+		if (nic->packet[0] + nic->packet[1] + nic->packet[2] +
+		    nic->packet[3] + nic->packet[4] + nic->packet[5] ==
+		    0xFF * ETH_ALEN)
+			DBG ( ",t=0x%hX,b]", type );
+		else
+			DBG ( ",t=0x%hX]", type );
+	}
+#endif
+
+	return 1;
+}
+
+/*************************************************************************
+	3Com 515 - specific routines
+**************************************************************************/
+static char padmap[] = {
+	0, 3, 2, 1
+};
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void t515_transmit(struct nic *nic, const char *d,	/* Destination */
+			  unsigned int t,	/* Type */
+			  unsigned int s,	/* size */
+			  const char *p)
+{				/* Packet */
+	register int len;
+	int pad;
+	int status;
+
+	DBG ( "{l=%d,t=0x%hX}", s + ETH_HLEN, t );
+
+	/* swap bytes of type */
+	t = htons(t);
+
+	len = s + ETH_HLEN;	/* actual length of packet */
+	pad = padmap[len & 3];
+
+	/*
+	 * The 3c515 automatically pads short packets to minimum ethernet length,
+	 * but we drop packets that are too large. Perhaps we should truncate
+	 * them instead?
+	 Copied from 3c595.  Is this true for the 3c515?
+	 */
+	if (len + pad > ETH_FRAME_LEN) {
+		return;
+	}
+	/* drop acknowledgements */
+	while ((status = inb(nic->ioaddr + TxStatus)) & TxComplete) {
+		/*if(status & (TXS_UNDERRUN|0x88|TXS_STATUS_OVERFLOW)) { */
+		outw(TxReset, nic->ioaddr + EL3_CMD);
+		outw(TxEnable, nic->ioaddr + EL3_CMD);
+/*		}                                                          */
+
+		outb(0x0, nic->ioaddr + TxStatus);
+	}
+
+	while (inw(nic->ioaddr + TxFree) < len + pad + 4) {
+		/* no room in FIFO */
+	}
+
+	outw(len, nic->ioaddr + TX_FIFO);
+	outw(0x0, nic->ioaddr + TX_FIFO);	/* Second dword meaningless */
+
+	/* write packet */
+	outsw(nic->ioaddr + TX_FIFO, d, ETH_ALEN / 2);
+	outsw(nic->ioaddr + TX_FIFO, nic->node_addr, ETH_ALEN / 2);
+	outw(t, nic->ioaddr + TX_FIFO);
+	outsw(nic->ioaddr + TX_FIFO, p, s / 2);
+
+	if (s & 1)
+		outb(*(p + s - 1), nic->ioaddr + TX_FIFO);
+
+	while (pad--)
+		outb(0, nic->ioaddr + TX_FIFO);	/* Padding */
+
+	/* wait for Tx complete */
+	while ((inw(nic->ioaddr + EL3_STATUS) & CmdInProgress) != 0);
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void t515_disable ( struct nic *nic,
+			   struct isapnp_device *isapnp ) {
+
+	t515_reset(nic);
+
+	/* This is a hack.  Since ltsp worked on my
+	   system without any disable functionality I
+	   have no way to determine if this works */
+
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, nic->ioaddr + EL3_CMD);
+	outw(TxDisable, nic->ioaddr + EL3_CMD);
+
+	if (if_port == XCVR_10base2)
+		/* Turn off thinnet power.  Green! */
+		outw(StopCoax, nic->ioaddr + EL3_CMD);
+
+
+	outw(SetIntrEnb | 0x0000, nic->ioaddr + EL3_CMD);
+
+	deactivate_isapnp_device ( isapnp );
+	return;
+}
+
+static void t515_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations t515_operations = {
+	.connect	= dummy_connect,
+	.poll		= t515_poll,
+	.transmit	= t515_transmit,
+	.irq		= t515_irq,
+
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+You should omit the last argument struct pci_device * for a non-PCI NIC
+***************************************************************************/
+static int t515_probe ( struct nic *nic, struct isapnp_device *isapnp ) {
+
+	/* Direct copy from Beckers 3c515.c removing any ISAPNP sections */
+
+	nic->ioaddr = isapnp->ioaddr;
+	nic->irqno = isapnp->irqno;
+	activate_isapnp_device ( isapnp );
+
+	/* Check the resource configuration for a matching ioaddr. */
+	if ((unsigned)(inw(nic->ioaddr + 0x2002) & 0x1f0)
+	    != (nic->ioaddr & 0x1f0)) {
+		DBG ( "3c515 ioaddr mismatch\n" );
+		return 0;
+	}
+
+	/* Verify by reading the device ID from the EEPROM. */
+	{
+		int timer;
+		outw(EEPROM_Read + 7, nic->ioaddr + Wn0EepromCmd);
+		/* Pause for at least 162 us. for the read to take place. */
+		for (timer = 4; timer >= 0; timer--) {
+			t3c515_wait(1);
+			if ((inw(nic->ioaddr + Wn0EepromCmd) & 0x0200) == 0)
+				break;
+		}
+		if (inw(nic->ioaddr + Wn0EepromData) != 0x6d50) {
+			DBG ( "3c515 read incorrect vendor ID from EEPROM" );
+			return 0;
+		}
+
+	}
+	DBG ( "3c515 Resource configuration register 0x%X, DCR 0x%hX.\n",
+	      inl(nic->ioaddr + 0x2002), inw(nic->ioaddr + 0x2000) );
+	corkscrew_found_device(nic->ioaddr, nic->irqno, CORKSCREW_ID,
+			       options, nic);
+	
+	t515_reset(nic);	
+	nic->nic_op	= &t515_operations;
+	return 1;
+}
+
+static int
+corkscrew_found_device(int ioaddr, int irq,
+		       int product_index, int options, struct nic *nic)
+{
+	/* Direct copy from Becker 3c515.c with unecessary parts removed */
+	vp->product_name = "3c515";
+	vp->options = options;
+	if (options >= 0) {
+		vp->media_override =
+		    ((options & 7) == 2) ? 0 : options & 7;
+		vp->full_duplex = (options & 8) ? 1 : 0;
+		vp->bus_master = (options & 16) ? 1 : 0;
+	} else {
+		vp->media_override = 7;
+		vp->full_duplex = 0;
+		vp->bus_master = 0;
+	}
+
+	corkscrew_probe1(ioaddr, irq, product_index, nic);
+	return 0;
+}
+
+static int
+corkscrew_probe1(int ioaddr, int irq, int product_index __unused,
+		 struct nic *nic)
+{
+	unsigned int eeprom[0x40], checksum = 0;	/* EEPROM contents */
+	int i;
+
+	printf("3Com %s at 0x%hX, ", vp->product_name, ioaddr);
+
+	/* Read the station address from the EEPROM. */
+	EL3WINDOW(0);
+	for (i = 0; i < 0x18; i++) {
+		short *phys_addr = (short *) nic->node_addr;
+		int timer;
+		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
+		/* Pause for at least 162 us. for the read to take place. */
+		for (timer = 4; timer >= 0; timer--) {
+			t3c515_wait(1);
+			if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
+				break;
+		}
+		eeprom[i] = inw(ioaddr + Wn0EepromData);
+		DBG ( "Value %d: %hX        ", i, eeprom[i] );
+		checksum ^= eeprom[i];
+		if (i < 3)
+			phys_addr[i] = htons(eeprom[i]);
+	}
+	checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	if (checksum != 0x00)
+		printf(" ***INVALID CHECKSUM 0x%hX*** ", checksum);
+
+        DBG ( "%s", eth_ntoa ( nic->node_addr ) );
+
+	if (eeprom[16] == 0x11c7) {	/* Corkscrew */
+
+	}
+	printf(", IRQ %d\n", irq);
+	/* Tell them about an invalid IRQ. */
+	if ( (irq <= 0 || irq > 15) ) {
+		DBG (" *** Warning: this IRQ is unlikely to work! ***\n" );
+	}
+
+	{
+		char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
+		union wn3_config config;
+		EL3WINDOW(3);
+		vp->available_media = inw(ioaddr + Wn3_Options);
+		config.i = inl(ioaddr + Wn3_Config);
+		DBG ( "  Internal config register is %4.4x, "
+		      "transceivers 0x%hX.\n",
+		      config.i, inw(ioaddr + Wn3_Options) );
+		printf
+		    ("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+		     8 << config.u.ram_size,
+		     config.u.ram_width ? "word" : "byte",
+		     ram_split[config.u.ram_split],
+		     config.u.autoselect ? "autoselect/" : "",
+		     media_tbl[config.u.xcvr].name);
+		if_port = config.u.xcvr;
+		vp->default_media = config.u.xcvr;
+		vp->autoselect = config.u.autoselect;
+	}
+	if (vp->media_override != 7) {
+		printf("  Media override to transceiver type %d (%s).\n",
+		       vp->media_override,
+		       media_tbl[vp->media_override].name);
+		if_port = vp->media_override;
+	}
+
+	vp->capabilities = eeprom[16];
+	vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
+	/* Rx is broken at 10mbps, so we always disable it. */
+	/* vp->full_bus_master_rx = 0; */
+	vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
+
+	return 0;
+}
+
+static struct isapnp_device_id t515_adapters[] = {
+	{ "3c515 (ISAPnP)", ISAPNP_VENDOR('T','C','M'), 0x5051 },
+};
+
+ISAPNP_DRIVER ( t515_driver, t515_adapters );
+
+DRIVER ( "3c515", nic_driver, isapnp_driver, t515_driver,
+	 t515_probe, t515_disable );
+
+ISA_ROM ( "3c515", "3c515 Fast EtherLink ISAPnP" );
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.txt b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.txt
new file mode 100644
index 0000000..8f7b3a7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c515.txt
@@ -0,0 +1,31 @@
+3c515.c -- 3COM 3C515 Fast Etherlink ISA 10/100BASE-TX driver for etherboot
+Copyright (C) 2002 Timothy Legge <tlegge at rogers.com>
+
+This driver is for the 3COM 3C515 Fast Etherlink ISA 10/100BASE-TX
+
+REVISION HISTORY:
+================
+v0.10 4-17-2002       TJL       Initial implementation.
+v0.11 4-17-2002       TJL       Cleanup of the code
+v0.12 4-26-2002       TJL       Added ISA Plug and Play for Non-PNP Bioses
+v0.13 3-31-2003	      TJL	Fixed issue 1 and 2 below
+
+The driver is heavily based on the work of others are referenced in the 3c515.c file.
+
+ISA Plug and Play (ISAPNP) support has been added for Non-PNP Bioses.  The ISAPNP code requires the defination of ISA_PNP as:
+
+#define ISA_PNP
+
+Issues:
+=======
+1) RESOLVED - When ISAPNP is defined, the etherboot probe is unable to find the card during the first probe.  This is true even though the ISA PNP code actually found and activated the driver.
+
+2) RESOLVED - When ISA_PNP is defined, the etherboot probe finds the incorrect MAC address for the card. However, when the linux kernel boots and loads the linux 3c515 driver the correct MAC address is found. This means that with ISA_PNP defined, you require both MAC addresses defined in the /etc/dhcpd.conf file.  The first MAC address allows the driver to load the LTSP Linux kernel.  The second allows the Linux dhclient to resolve its IP address.
+
+3) Although the ISA PNP docs specify that the IRQ, DMA and IO Address needs to be assigned to the card before it is activated, Etherboot does not seem to care.  Therefore the code does not assign the card with these values.
+
+If you can help address any of thse issues, please feel free.
+
+Timothy Legge
+timlegge at users.sourceforge.net
+April 9, 2003
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c529.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c529.c
new file mode 100644
index 0000000..d68f28e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c529.c
@@ -0,0 +1,62 @@
+/*
+ * Split out from 3c509.c to make build process more sane
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include "etherboot.h"
+#include <ipxe/mca.h>
+#include <ipxe/isa.h> /* for ISA_ROM */
+#include "nic.h"
+#include "3c509.h"
+
+/*
+ * Several other pieces of the MCA support code were shamelessly
+ * borrowed from the Linux kernel source.
+ *
+ * MCA support added by Adam Fritzler (mid at auk.cx)
+ *
+ * Generalised out of the 3c529 driver and into a bus type by Michael
+ * Brown <mbrown at fensystems.co.uk>
+ *
+ */
+
+static int t529_probe ( struct nic *nic, struct mca_device *mca ) {
+
+	/* Retrieve NIC parameters from MCA device parameters */
+	nic->ioaddr = ( ( mca->pos[4] & 0xfc ) | 0x02 ) << 8;
+	nic->irqno = mca->pos[5] & 0x0f;
+	printf ( "3c529 board found on MCA at %#hx IRQ %d -",
+		 nic->ioaddr, nic->irqno );
+
+	/* Hand off to generic t5x9 probe routine */
+	return t5x9_probe ( nic, MCA_ID ( mca ), 0xffff );
+}
+
+static void t529_disable ( struct nic *nic, struct mca_device *mca __unused ) {
+	t5x9_disable ( nic );
+}
+
+static struct mca_device_id el3_mca_adapters[] = {
+        { "3Com 3c529 EtherLink III (10base2)", 0x627c },
+        { "3Com 3c529 EtherLink III (10baseT)", 0x627d },
+        { "3Com 3c529 EtherLink III (test mode)", 0x62db },
+        { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
+        { "3Com 3c529 EtherLink III (TP)", 0x62f7 },
+};
+
+MCA_DRIVER ( t529_driver, el3_mca_adapters );
+
+DRIVER ( "3c529", nic_driver, mca_driver, t529_driver,
+	 t529_probe, t529_disable );
+
+ISA_ROM( "3c529", "3c529 == MCA 3c509" );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.c
new file mode 100644
index 0000000..3178178
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.c
@@ -0,0 +1,553 @@
+/*
+* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
+*
+* Copyright (C) 2000 Shusuke Nisiyama <shu at athena.qe.eng.hokudai.ac.jp>
+* All rights reserved.
+* Mar. 14, 2000
+*
+*  This software may be used, modified, copied, distributed, and sold, in
+*  both source and binary form provided that the above copyright and these
+*  terms are retained. Under no circumstances are the authors responsible for
+*  the proper functioning of this software, nor do the authors assume any
+*  responsibility for damages incurred with its use.
+*
+* This code is based on Martin Renters' etherboot-4.4.3 3c509.c and 
+* Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
+*
+*  Copyright (C) 1993-1994, David Greenman, Martin Renters.
+*  Copyright (C) 1993-1995, Andres Vega Garcia.
+*  Copyright (C) 1995, Serge Babkin.
+*
+*  Copyright (c) 1994 Herb Peyerl <hpeyerl at novatel.ca>
+*
+* timlegge	08-24-2003	Add Multicast Support
+*/
+
+FILE_LICENCE ( BSD2 );
+
+/* #define EDEBUG */
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include "3c595.h"
+
+static struct nic_operations t595_operations;
+
+static unsigned short	eth_nic_base;
+static unsigned short	vx_connector, vx_connectors;
+
+static struct connector_entry {
+  int bit;
+  char *name;
+} conn_tab[VX_CONNECTORS] = {
+#define CONNECTOR_UTP   0
+  { 0x08, "utp"},
+#define CONNECTOR_AUI   1
+  { 0x20, "aui"},
+/* dummy */
+  { 0, "???"},
+#define CONNECTOR_BNC   3
+  { 0x10, "bnc"},
+#define CONNECTOR_TX    4
+  { 0x02, "tx"},
+#define CONNECTOR_FX    5
+  { 0x04, "fx"},
+#define CONNECTOR_MII   6
+  { 0x40, "mii"},
+  { 0, "???"}
+};
+
+static void vxgetlink(void);
+static void vxsetlink(void);
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+***************************************************************************/
+static void t595_reset(struct nic *nic)
+{
+	int i;
+
+	/***********************************************************
+			Reset 3Com 595 card
+	*************************************************************/
+
+	/* stop card */
+	outw(RX_DISABLE, BASE + VX_COMMAND);
+	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+	outw(TX_DISABLE, BASE + VX_COMMAND);
+	outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
+	udelay(8000);
+	outw(RX_RESET, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+	outw(TX_RESET, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+	outw(C_INTR_LATCH, BASE + VX_COMMAND);
+	outw(SET_RD_0_MASK, BASE + VX_COMMAND);
+	outw(SET_INTR_MASK, BASE + VX_COMMAND);
+	outw(SET_RX_FILTER, BASE + VX_COMMAND);
+
+	/*
+	* initialize card
+	*/
+	VX_BUSY_WAIT;
+
+	GO_WINDOW(0);
+
+	/* Disable the card */
+/*	outw(0, BASE + VX_W0_CONFIG_CTRL); */
+
+	/* Configure IRQ to none */
+/*	outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
+
+	/* Enable the card */
+/*	outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
+
+	GO_WINDOW(2);
+
+	/* Reload the ether_addr. */
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
+
+	outw(RX_RESET, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+	outw(TX_RESET, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+	/* Window 1 is operating window */
+	GO_WINDOW(1);
+	for (i = 0; i < 31; i++)
+		inb(BASE + VX_W1_TX_STATUS);
+
+	outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
+	outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
+
+/*
+ * Attempt to get rid of any stray interrupts that occured during
+ * configuration.  On the i386 this isn't possible because one may
+ * already be queued.  However, a single stray interrupt is
+ * unimportant.
+ */
+
+	outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
+
+	outw(SET_RX_FILTER | FIL_INDIVIDUAL |
+	    FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND);
+
+	vxsetlink();
+/*{
+	int i,j;
+	i = CONNECTOR_TX;
+	GO_WINDOW(3);
+	j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
+	outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
+        GO_WINDOW(4);
+        outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
+        GO_WINDOW(1);
+}*/
+
+	/* start tranciever and receiver */
+	outw(RX_ENABLE, BASE + VX_COMMAND);
+	outw(TX_ENABLE, BASE + VX_COMMAND);
+
+}
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+***************************************************************************/
+static char padmap[] = {
+	0, 3, 2, 1};
+
+static void t595_transmit(
+struct nic *nic,
+const char *d,			/* Destination */
+unsigned int t,			/* Type */
+unsigned int s,			/* size */
+const char *p)			/* Packet */
+{
+	register int len;
+	int pad;
+	int status;
+
+#ifdef EDEBUG
+	printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
+#endif
+
+	/* swap bytes of type */
+	t= htons(t);
+
+	len=s+ETH_HLEN; /* actual length of packet */
+	pad = padmap[len & 3];
+
+	/*
+	* The 3c595 automatically pads short packets to minimum ethernet length,
+	* but we drop packets that are too large. Perhaps we should truncate
+	* them instead?
+	*/
+	if (len + pad > ETH_FRAME_LEN) {
+		return;
+	}
+
+	/* drop acknowledgements */
+	while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
+		if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
+			outw(TX_RESET, BASE + VX_COMMAND);
+			outw(TX_ENABLE, BASE + VX_COMMAND);
+		}
+
+		outb(0x0, BASE + VX_W1_TX_STATUS);
+	}
+
+	while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
+		/* no room in FIFO */
+	}
+
+	outw(len, BASE + VX_W1_TX_PIO_WR_1);
+	outw(0x0, BASE + VX_W1_TX_PIO_WR_1);	/* Second dword meaningless */
+
+	/* write packet */
+	outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
+	outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
+	outw(t, BASE + VX_W1_TX_PIO_WR_1);
+	outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
+	if (s & 1)
+		outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
+
+	while (pad--)
+		outb(0, BASE + VX_W1_TX_PIO_WR_1);	/* Padding */
+
+        /* wait for Tx complete */
+        while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
+                ;
+}
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+***************************************************************************/
+static int t595_poll(struct nic *nic, int retrieve)
+{
+	/* common variables */
+	/* variables for 3C595 */
+	short status, cst;
+	register short rx_fifo;
+
+	cst=inw(BASE + VX_STATUS);
+
+#ifdef EDEBUG
+	if(cst & 0x1FFF)
+		printf("-%hX-",cst);
+#endif
+
+	if( (cst & S_RX_COMPLETE)==0 ) {
+		/* acknowledge  everything */
+		outw(ACK_INTR | cst, BASE + VX_COMMAND);
+		outw(C_INTR_LATCH, BASE + VX_COMMAND);
+
+		return 0;
+	}
+
+	status = inw(BASE + VX_W1_RX_STATUS);
+#ifdef EDEBUG
+	printf("*%hX*",status);
+#endif
+
+	if (status & ERR_RX) {
+		outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
+		return 0;
+	}
+
+	rx_fifo = status & RX_BYTES_MASK;
+	if (rx_fifo==0)
+		return 0;
+
+	if ( ! retrieve ) return 1;
+
+		/* read packet */
+#ifdef EDEBUG
+	printf("[l=%d",rx_fifo);
+#endif
+	insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
+	if(rx_fifo & 1)
+		nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
+	nic->packetlen=rx_fifo;
+
+	while(1) {
+		status = inw(BASE + VX_W1_RX_STATUS);
+#ifdef EDEBUG
+		printf("*%hX*",status);
+#endif
+		rx_fifo = status & RX_BYTES_MASK;
+
+		if(rx_fifo>0) {
+			insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
+			if(rx_fifo & 1)
+				nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
+			nic->packetlen+=rx_fifo;
+#ifdef EDEBUG
+			printf("+%d",rx_fifo);
+#endif
+		}
+		if(( status & RX_INCOMPLETE )==0) {
+#ifdef EDEBUG
+			printf("=%d",nic->packetlen);
+#endif
+			break;
+		}
+		udelay(1000);
+	}
+
+	/* acknowledge reception of packet */
+	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
+	while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
+#ifdef EDEBUG
+{
+	unsigned short type = 0;	/* used by EDEBUG */
+	type = (nic->packet[12]<<8) | nic->packet[13];
+	if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
+	    nic->packet[5] == 0xFF*ETH_ALEN)
+		printf(",t=%hX,b]",type);
+	else
+		printf(",t=%hX]",type);
+}
+#endif
+	return 1;
+}
+
+
+/*************************************************************************
+	3Com 595 - specific routines
+**************************************************************************/
+
+static int
+eeprom_rdy()
+{
+	int i;
+
+	for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
+		udelay(1000);
+	if (i >= MAX_EEPROMBUSY) {
+	        /* printf("3c595: eeprom failed to come ready.\n"); */
+		printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * get_e: gets a 16 bits word from the EEPROM. we must have set the window
+ * before
+ */
+static int
+get_e(offset)
+int offset;
+{
+	if (!eeprom_rdy())
+		return (0xffff);
+	outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
+	if (!eeprom_rdy())
+		return (0xffff);
+	return (inw(BASE + VX_W0_EEPROM_DATA));
+}
+
+static void            
+vxgetlink(void)
+{
+    int n, k;
+
+    GO_WINDOW(3);
+    vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
+    for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
+      if (vx_connectors & conn_tab[k].bit) {
+        if (n > 0) {
+          printf("/");
+	}
+        printf("%s", conn_tab[k].name );
+        n++;
+      }
+    }
+    if (vx_connectors == 0) {
+        printf("no connectors!");
+        return;
+    }
+    GO_WINDOW(3);
+    vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 
+                        & INTERNAL_CONNECTOR_MASK) 
+                        >> INTERNAL_CONNECTOR_BITS;
+    if (vx_connector & 0x10) {
+        vx_connector &= 0x0f;
+        printf("[*%s*]", conn_tab[vx_connector].name);
+        printf(": disable 'auto select' with DOS util!");
+    } else {
+        printf("[*%s*]", conn_tab[vx_connector].name);
+    }
+}
+
+static void            
+vxsetlink(void)
+{       
+    int i, j;
+    char *reason, *warning;
+    static char prev_conn = -1;
+
+    if (prev_conn == -1) {
+        prev_conn = vx_connector;
+    }
+
+    i = vx_connector;       /* default in EEPROM */
+    reason = "default";
+    warning = 0;
+
+    if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
+        warning = "strange connector type in EEPROM.";
+        reason = "forced";
+        i = CONNECTOR_UTP;
+    }
+
+        if (warning != 0) {
+            printf("warning: %s\n", warning);
+        }
+        printf("selected %s. (%s)\n", conn_tab[i].name, reason);
+
+    /* Set the selected connector. */
+    GO_WINDOW(3);
+    j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
+    outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
+
+    /* First, disable all. */
+    outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
+    udelay(8000);
+    GO_WINDOW(4);
+    outw(0, BASE + VX_W4_MEDIA_TYPE);
+
+    /* Second, enable the selected one. */
+    switch(i) {
+      case CONNECTOR_UTP:
+        GO_WINDOW(4);
+        outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
+        break;
+      case CONNECTOR_BNC:
+        outw(START_TRANSCEIVER,BASE + VX_COMMAND);
+        udelay(8000);
+        break;
+      case CONNECTOR_TX:
+      case CONNECTOR_FX:
+        GO_WINDOW(4);
+        outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
+        break;
+      default:  /* AUI and MII fall here */
+        break;
+    }
+    GO_WINDOW(1); 
+}
+
+static void t595_disable ( struct nic *nic ) {
+
+	t595_reset(nic);
+
+	outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
+	udelay(8000);
+	GO_WINDOW(4);
+	outw(0, BASE + VX_W4_MEDIA_TYPE);
+	GO_WINDOW(1);
+}
+
+static void t595_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+***************************************************************************/
+static int t595_probe ( struct nic *nic, struct pci_device *pci ) {
+
+	int i;
+	unsigned short *p;
+
+	if (pci->ioaddr == 0)
+		return 0;
+	eth_nic_base = pci->ioaddr;
+
+	nic->irqno  = 0;
+	nic->ioaddr = pci->ioaddr;
+
+	GO_WINDOW(0);
+	outw(GLOBAL_RESET, BASE + VX_COMMAND);
+	VX_BUSY_WAIT;
+
+	vxgetlink();
+
+/*
+	printf("\nEEPROM:");
+	for (i = 0; i < (EEPROMSIZE/2); i++) {
+	  printf("%hX:", get_e(i));
+	}
+	printf("\n");
+*/
+	/*
+	* Read the station address from the eeprom
+	*/
+	p = (unsigned short *) nic->node_addr;
+	for (i = 0; i < 3; i++) {
+		GO_WINDOW(0);
+		p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
+		GO_WINDOW(2);
+		outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
+	}
+
+	DBG ( "Ethernet address: %s\n", eth_ntoa (nic->node_addr) );
+
+	t595_reset(nic);
+	nic->nic_op	= &t595_operations;
+	return 1;
+
+}
+
+static struct nic_operations t595_operations = {
+	.connect	= dummy_connect,
+	.poll		= t595_poll,
+	.transmit	= t595_transmit,
+	.irq		= t595_irq,
+
+};
+
+static struct pci_device_id t595_nics[] = {
+PCI_ROM(0x10b7, 0x5900, "3c590",           "3Com590", 0),		/* Vortex 10Mbps */
+PCI_ROM(0x10b7, 0x5950, "3c595",           "3Com595", 0),		/* Vortex 100baseTx */
+PCI_ROM(0x10b7, 0x5951, "3c595-1",         "3Com595", 0),		/* Vortex 100baseT4 */
+PCI_ROM(0x10b7, 0x5952, "3c595-2",         "3Com595", 0),		/* Vortex 100base-MII */
+PCI_ROM(0x10b7, 0x9000, "3c900-tpo",       "3Com900-TPO", 0),	/* 10 Base TPO */
+PCI_ROM(0x10b7, 0x9001, "3c900-t4",        "3Com900-Combo", 0),	/* 10/100 T4 */
+PCI_ROM(0x10b7, 0x9004, "3c900b-tpo",      "3Com900B-TPO", 0),	/* 10 Base TPO */
+PCI_ROM(0x10b7, 0x9005, "3c900b-combo",    "3Com900B-Combo", 0),	/* 10 Base Combo */
+PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2",     "3Com900B-2/T", 0),	/* 10 Base TP and Base2 */
+PCI_ROM(0x10b7, 0x900a, "3c900b-fl",       "3Com900B-FL", 0),	/* 10 Base F */
+PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone", 0),	/* Cyclone */
+PCI_ROM(0x10b7, 0x9805, "3c9805-1",        "3Com9805", 0),		/* Dual Port Server Cyclone */
+PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1",  "3CSOHO100-TX", 0),	/* Hurricane */
+PCI_ROM(0x10b7, 0x4500, "3c450-1",         "3Com450 HomePNA Tornado", 0),
+};
+
+PCI_DRIVER ( t595_driver, t595_nics, PCI_NO_CLASS );
+
+DRIVER ( "3C595", nic_driver, pci_driver, t595_driver,
+	 t595_probe, t595_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.h
new file mode 100644
index 0000000..e27d204
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c595.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl at novatel.ca) 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. The name
+ * of the author may not be used to endorse or promote products derived from
+ * this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ October 2, 1994
+
+ Modified by: Andres Vega Garcia
+
+ INRIA - Sophia Antipolis, France
+ e-mail: avega at sophia.inria.fr
+ finger: avega at pax.inria.fr
+
+ */
+
+FILE_LICENCE ( BSD3 );
+
+/*
+ * Created from if_epreg.h by Fred Gray (fgray at rice.edu) to support the
+ * 3c590 family.
+ */
+
+/*
+ * Modified by Shusuke Nisiyama <shu at athena.qe.eng.hokudai.ac.jp>
+ * for etherboot
+ * Mar. 14, 2000
+*/
+
+/*
+ * Ethernet software status per interface.
+ */
+
+/*
+ * Some global constants
+ */
+
+#define TX_INIT_RATE         16
+#define TX_INIT_MAX_RATE     64
+#define RX_INIT_LATENCY      64
+#define RX_INIT_EARLY_THRESH 64
+#define MIN_RX_EARLY_THRESHF   16 /* not less than ether_header */
+#define MIN_RX_EARLY_THRESHL   4
+
+#define EEPROMSIZE      0x40
+#define MAX_EEPROMBUSY  1000
+#define VX_LAST_TAG     0xd7
+#define VX_MAX_BOARDS   16
+#define VX_ID_PORT      0x100
+
+/*
+ * some macros to acces long named fields
+ */
+#define BASE 	(eth_nic_base)
+
+/*
+ * Commands to read/write EEPROM trough EEPROM command register (Window 0,
+ * Offset 0xa)
+ */
+#define EEPROM_CMD_RD    0x0080	/* Read:  Address required (5 bits) */
+#define EEPROM_CMD_WR    0x0040	/* Write: Address required (5 bits) */
+#define EEPROM_CMD_ERASE 0x00c0	/* Erase: Address required (5 bits) */
+#define EEPROM_CMD_EWEN  0x0030	/* Erase/Write Enable: No data required */
+
+#define EEPROM_BUSY		(1<<15)
+
+/*
+ * Some short functions, worth to let them be a macro
+ */
+
+/**************************************************************************
+ *									  *
+ * These define the EEPROM data structure.  They are used in the probe
+ * function to verify the existence of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0	0x0	/* Word */
+#define EEPROM_NODE_ADDR_1	0x1	/* Word */
+#define EEPROM_NODE_ADDR_2	0x2	/* Word */
+#define EEPROM_PROD_ID		0x3	/* 0x9[0-f]50 */
+#define EEPROM_MFG_ID		0x7	/* 0x6d50 */
+#define EEPROM_ADDR_CFG		0x8	/* Base addr */
+#define EEPROM_RESOURCE_CFG	0x9	/* IRQ. Bits 12-15 */
+#define EEPROM_OEM_ADDR_0	0xa	/* Word */
+#define EEPROM_OEM_ADDR_1	0xb	/* Word */
+#define EEPROM_OEM_ADDR_2	0xc	/* Word */
+#define EEPROM_SOFT_INFO_2	0xf     /* Software information 2 */
+
+#define NO_RX_OVN_ANOMALY       (1<<5)
+
+/**************************************************************************
+ *										  *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable.  They have been taken out the the "EtherLink III Parallel  *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com.								  *
+ *										  *
+ **************************************************************************/
+
+#define VX_COMMAND		0x0e	/* Write. BASE+0x0e is always a
+					 * command reg. */
+#define VX_STATUS		0x0e	/* Read. BASE+0x0e is always status
+					 * reg. */
+#define VX_WINDOW		0x0f	/* Read. BASE+0x0f is always window
+					 * reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+/* Write */
+#define VX_W0_EEPROM_DATA	0x0c
+#define VX_W0_EEPROM_COMMAND	0x0a
+#define VX_W0_RESOURCE_CFG	0x08
+#define VX_W0_ADDRESS_CFG	0x06 
+#define VX_W0_CONFIG_CTRL	0x04
+        /* Read */
+#define VX_W0_PRODUCT_ID	0x02
+#define VX_W0_MFG_ID		0x00
+
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+/* Write */
+#define VX_W1_TX_PIO_WR_2	0x02
+#define VX_W1_TX_PIO_WR_1	0x00
+/* Read */
+#define VX_W1_FREE_TX		0x0c
+#define VX_W1_TX_STATUS		0x0b	/* byte */
+#define VX_W1_TIMER		0x0a	/* byte */
+#define VX_W1_RX_STATUS		0x08
+#define VX_W1_RX_PIO_RD_2	0x02
+#define VX_W1_RX_PIO_RD_1	0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+/* Read/Write */
+#define VX_W2_ADDR_5		0x05
+#define VX_W2_ADDR_4		0x04
+#define VX_W2_ADDR_3		0x03
+#define VX_W2_ADDR_2		0x02
+#define VX_W2_ADDR_1		0x01
+#define VX_W2_ADDR_0		0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+/* Read */
+#define VX_W3_INTERNAL_CFG	0x00
+#define VX_W3_RESET_OPT		0x08
+#define VX_W3_FREE_TX		0x0c
+#define VX_W3_FREE_RX		0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+/* Read/Write */
+#define VX_W4_MEDIA_TYPE	0x0a
+#define VX_W4_CTRLR_STATUS	0x08
+#define VX_W4_NET_DIAG		0x06
+#define VX_W4_FIFO_DIAG		0x04
+#define VX_W4_HOST_DIAG		0x02
+#define VX_W4_TX_DIAG		0x00
+
+/*
+ * Window 5 Registers.  Results and Internal status.
+ */
+/* Read */
+#define VX_W5_READ_0_MASK	0x0c
+#define VX_W5_INTR_MASK		0x0a
+#define VX_W5_RX_FILTER		0x08
+#define VX_W5_RX_EARLY_THRESH	0x06
+#define VX_W5_TX_AVAIL_THRESH	0x02
+#define VX_W5_TX_START_THRESH	0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+/* Read/Write */
+#define TX_TOTAL_OK		0x0c
+#define RX_TOTAL_OK		0x0a
+#define TX_DEFERRALS		0x08
+#define RX_FRAMES_OK		0x07
+#define TX_FRAMES_OK		0x06
+#define RX_OVERRUNS		0x05
+#define TX_COLLISIONS		0x04
+#define TX_AFTER_1_COLLISION	0x03
+#define TX_AFTER_X_COLLISIONS	0x02
+#define TX_NO_SQE		0x01
+#define TX_CD_LOST		0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ *     15-11:  5-bit code for command to be executed.
+ *     10-0:   11-bit arg if any. For commands with no args;
+ *	      this can be set to anything.
+ */
+#define GLOBAL_RESET		(unsigned short) 0x0000	/* Wait at least 1ms
+							 * after issuing */
+#define WINDOW_SELECT		(unsigned short) (0x1<<11)
+#define START_TRANSCEIVER	(unsigned short) (0x2<<11)	/* Read ADDR_CFG reg to
+							 * determine whether
+							 * this is needed. If
+							 * so; wait 800 uSec
+							 * before using trans-
+							 * ceiver. */
+#define RX_DISABLE		(unsigned short) (0x3<<11)	/* state disabled on
+							 * power-up */
+#define RX_ENABLE		(unsigned short) (0x4<<11)
+#define RX_RESET		(unsigned short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK	(unsigned short) (0x8<<11)
+#define TX_ENABLE		(unsigned short) (0x9<<11)
+#define TX_DISABLE		(unsigned short) (0xa<<11)
+#define TX_RESET		(unsigned short) (0xb<<11)
+#define REQ_INTR		(unsigned short) (0xc<<11)
+/*
+ * The following C_* acknowledge the various interrupts. Some of them don't
+ * do anything.  See the manual.
+ */
+#define ACK_INTR		(unsigned short) (0x6800)
+#	define C_INTR_LATCH	(unsigned short) (ACK_INTR|0x1)
+#	define C_CARD_FAILURE	(unsigned short) (ACK_INTR|0x2)
+#	define C_TX_COMPLETE	(unsigned short) (ACK_INTR|0x4)
+#	define C_TX_AVAIL	(unsigned short) (ACK_INTR|0x8)
+#	define C_RX_COMPLETE	(unsigned short) (ACK_INTR|0x10)
+#	define C_RX_EARLY	(unsigned short) (ACK_INTR|0x20)
+#	define C_INT_RQD		(unsigned short) (ACK_INTR|0x40)
+#	define C_UPD_STATS	(unsigned short) (ACK_INTR|0x80)
+#define SET_INTR_MASK		(unsigned short) (0xe<<11)
+#define SET_RD_0_MASK		(unsigned short) (0xf<<11)
+#define SET_RX_FILTER		(unsigned short) (0x10<<11)
+#	define FIL_INDIVIDUAL	(unsigned short) (0x1)
+#	define FIL_MULTICAST     (unsigned short) (0x02)
+#	define FIL_BRDCST        (unsigned short) (0x04)
+#	define FIL_PROMISC       (unsigned short) (0x08)
+#define SET_RX_EARLY_THRESH	(unsigned short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH	(unsigned short) (0x12<<11)
+#define SET_TX_START_THRESH	(unsigned short) (0x13<<11)
+#define STATS_ENABLE		(unsigned short) (0x15<<11)
+#define STATS_DISABLE		(unsigned short) (0x16<<11)
+#define STOP_TRANSCEIVER	(unsigned short) (0x17<<11)
+
+/*
+ * Status register. All windows.
+ *
+ *     15-13:  Window number(0-7).
+ *     12:     Command_in_progress.
+ *     11:     reserved.
+ *     10:     reserved.
+ *     9:      reserved.
+ *     8:      reserved.
+ *     7:      Update Statistics.
+ *     6:      Interrupt Requested.
+ *     5:      RX Early.
+ *     4:      RX Complete.
+ *     3:      TX Available.
+ *     2:      TX Complete.
+ *     1:      Adapter Failure.
+ *     0:      Interrupt Latch.
+ */
+#define S_INTR_LATCH		(unsigned short) (0x1)
+#define S_CARD_FAILURE		(unsigned short) (0x2)
+#define S_TX_COMPLETE		(unsigned short) (0x4)
+#define S_TX_AVAIL		(unsigned short) (0x8)
+#define S_RX_COMPLETE		(unsigned short) (0x10)
+#define S_RX_EARLY		(unsigned short) (0x20)
+#define S_INT_RQD		(unsigned short) (0x40)
+#define S_UPD_STATS		(unsigned short) (0x80)
+#define S_COMMAND_IN_PROGRESS	(unsigned short) (0x1000)
+
+#define VX_BUSY_WAIT while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS)
+
+/* Address Config. Register.    
+ * Window 0/Port 06
+ */
+
+#define ACF_CONNECTOR_BITS	14  
+#define ACF_CONNECTOR_UTP	0
+#define ACF_CONNECTOR_AUI	1
+#define ACF_CONNECTOR_BNC	3
+   
+#define INTERNAL_CONNECTOR_BITS 20
+#define INTERNAL_CONNECTOR_MASK 0x01700000
+
+/*
+ * FIFO Registers. RX Status.
+ *
+ *     15:     Incomplete or FIFO empty.
+ *     14:     1: Error in RX Packet   0: Incomplete or no error.
+ *     13-11:  Type of error.
+ *	      1000 = Overrun.
+ *	      1011 = Run Packet Error.
+ *	      1100 = Alignment Error.
+ *	      1101 = CRC Error.
+ *	      1001 = Oversize Packet Error (>1514 bytes)
+ *	      0010 = Dribble Bits.
+ *	      (all other error codes, no errors.)
+ *
+ *     10-0:   RX Bytes (0-1514)
+ */
+#define ERR_INCOMPLETE  (unsigned short) (0x8000)
+#define ERR_RX          (unsigned short) (0x4000)
+#define ERR_MASK        (unsigned short) (0x7800)
+#define ERR_OVERRUN     (unsigned short) (0x4000)
+#define ERR_RUNT        (unsigned short) (0x5800)
+#define ERR_ALIGNMENT   (unsigned short) (0x6000)
+#define ERR_CRC         (unsigned short) (0x6800)
+#define ERR_OVERSIZE    (unsigned short) (0x4800)
+#define ERR_DRIBBLE     (unsigned short) (0x1000)
+
+/*
+ * TX Status. 
+ *
+ *   Reports the transmit status of a completed transmission. Writing this
+ *   register pops the transmit completion stack.
+ *
+ *   Window 1/Port 0x0b.
+ *
+ *     7:      Complete
+ *     6:      Interrupt on successful transmission requested.
+ *     5:      Jabber Error (TP Only, TX Reset required. )
+ *     4:      Underrun (TX Reset required. )
+ *     3:      Maximum Collisions.
+ *     2:      TX Status Overflow.
+ *     1-0:    Undefined.
+ *
+ */
+#define TXS_COMPLETE		0x80
+#define TXS_INTR_REQ		0x40
+#define TXS_JABBER		0x20
+#define TXS_UNDERRUN		0x10
+#define TXS_MAX_COLLISION	0x8
+#define TXS_STATUS_OVERFLOW	0x4
+
+#define RS_AUI			(1<<5)
+#define RS_BNC			(1<<4)
+#define RS_UTP			(1<<3)
+#define	RS_T4			(1<<0)
+#define	RS_TX			(1<<1)
+#define	RS_FX			(1<<2)
+#define	RS_MII			(1<<6)
+
+
+/*
+ * FIFO Status (Window 4)
+ *
+ *   Supports FIFO diagnostics
+ *
+ *   Window 4/Port 0x04.1
+ *
+ *     15:	1=RX receiving (RO). Set when a packet is being received
+ *		into the RX FIFO.
+ *     14:	Reserved
+ *     13:	1=RX underrun (RO). Generates Adapter Failure interrupt.
+ *		Requires RX Reset or Global Reset command to recover.
+ *		It is generated when you read past the end of a packet -
+ *		reading past what has been received so far will give bad
+ *		data.
+ *     12:	1=RX status overrun (RO). Set when there are already 8
+ *		packets in the RX FIFO. While this bit is set, no additional
+ *		packets are received. Requires no action on the part of
+ *		the host. The condition is cleared once a packet has been
+ *		read out of the RX FIFO.
+ *     11:	1=RX overrun (RO). Set when the RX FIFO is full (there
+ *		may not be an overrun packet yet). While this bit is set,
+ *		no additional packets will be received (some additional
+ *		bytes can still be pending between the wire and the RX
+ *		FIFO). Requires no action on the part of the host. The
+ *		condition is cleared once a few bytes have been read out
+ *		from the RX FIFO.
+ *     10:	1=TX overrun (RO). Generates adapter failure interrupt.
+ *		Requires TX Reset or Global Reset command to recover.
+ *		Disables Transmitter.
+ *     9-8:	Unassigned.
+ *     7-0:	Built in self test bits for the RX and TX FIFO's.
+ */
+#define FIFOS_RX_RECEIVING	(unsigned short) 0x8000
+#define FIFOS_RX_UNDERRUN	(unsigned short) 0x2000
+#define FIFOS_RX_STATUS_OVERRUN	(unsigned short) 0x1000
+#define FIFOS_RX_OVERRUN	(unsigned short) 0x0800
+#define FIFOS_TX_OVERRUN	(unsigned short) 0x0400
+
+/*
+ * Misc defines for various things.
+ */
+#define TAG_ADAPTER                     0xd0
+#define ACTIVATE_ADAPTER_TO_CONFIG      0xff
+#define ENABLE_DRQ_IRQ                  0x0001
+#define MFG_ID                          0x506d  /* `TCM' */
+#define PROD_ID                         0x5090
+#define GO_WINDOW(x)		outw(WINDOW_SELECT|(x),BASE+VX_COMMAND)
+#define JABBER_GUARD_ENABLE	0x40
+#define LINKBEAT_ENABLE		0x80
+#define	ENABLE_UTP		(JABBER_GUARD_ENABLE | LINKBEAT_ENABLE)
+#define DISABLE_UTP		0x0
+#define RX_BYTES_MASK		(unsigned short) (0x07ff)
+#define RX_ERROR        0x4000
+#define RX_INCOMPLETE   0x8000
+#define TX_INDICATE		1<<15
+#define is_eeprom_busy(b)	(inw((b)+VX_W0_EEPROM_COMMAND)&EEPROM_BUSY)
+
+#define	VX_IOSIZE	0x20
+
+#define VX_CONNECTORS 8
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c5x9.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c5x9.c
new file mode 100644
index 0000000..4d9bc8d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c5x9.c
@@ -0,0 +1,416 @@
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters.
+  Date: Mar 22 1995
+
+ This code is based heavily on David Greenman's if_ed.c driver and
+  Andres Vega Garcia's if_ep.c driver.
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ Copyright (C) 1993-1995, Andres Vega Garcia.
+ Copyright (C) 1995, Serge Babkin.
+  This software may be used, modified, copied, distributed, and sold, in
+  both source and binary form provided that the above copyright and these
+  terms are retained. Under no circumstances are the authors responsible for
+  the proper functioning of this software, nor do the authors assume any
+  responsibility for damages incurred with its use.
+
+3c509 support added by Serge Babkin (babkin at hq.icb.chel.su)
+
+$Id$
+
+***************************************************************************/
+
+FILE_LICENCE ( BSD2 );
+
+/* #define EDEBUG */
+
+#include <ipxe/ethernet.h>
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/isa.h>
+#include "3c509.h"
+
+static enum { none, bnc, utp } connector = none;	/* for 3C509 */
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+***************************************************************************/
+void t5x9_disable ( struct nic *nic ) {
+	/* stop card */
+	outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
+	outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
+	while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+		;
+	outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
+	outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
+	udelay(1000);
+	outw(RX_RESET, nic->ioaddr + EP_COMMAND);
+	outw(TX_RESET, nic->ioaddr + EP_COMMAND);
+	outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
+	outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
+	outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
+	outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);
+
+	/*
+	 * wait for reset to complete
+	 */
+	while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+		;
+
+	GO_WINDOW(nic->ioaddr,0);
+
+	/* Disable the card */
+	outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);
+
+	/* Configure IRQ to none */
+	outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
+}
+
+static void t509_enable ( struct nic *nic ) {
+	int i;
+
+	/* Enable the card */
+	GO_WINDOW(nic->ioaddr,0);
+	outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);
+
+	GO_WINDOW(nic->ioaddr,2);
+
+	/* Reload the ether_addr. */
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);
+
+	outw(RX_RESET, nic->ioaddr + EP_COMMAND);
+	outw(TX_RESET, nic->ioaddr + EP_COMMAND);
+
+	/* Window 1 is operating window */
+	GO_WINDOW(nic->ioaddr,1);
+	for (i = 0; i < 31; i++)
+		inb(nic->ioaddr + EP_W1_TX_STATUS);
+
+	/* get rid of stray intr's */
+	outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
+
+	outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);
+
+	outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
+
+	outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
+	     nic->ioaddr + EP_COMMAND);
+
+	/* configure BNC */
+	if (connector == bnc) {
+		outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
+		udelay(1000);
+	}
+	/* configure UTP */
+	else if (connector == utp) {
+		GO_WINDOW(nic->ioaddr,4);
+		outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
+		sleep(2);	/* Give time for media to negotiate */
+		GO_WINDOW(nic->ioaddr,1);
+	}
+
+	/* start transceiver and receiver */
+	outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
+	outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
+
+	/* set early threshold for minimal packet length */
+	outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
+	outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
+}
+
+static void t509_reset ( struct nic *nic ) {
+	t5x9_disable ( nic );
+	t509_enable ( nic );
+}    
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+***************************************************************************/
+static char padmap[] = {
+	0, 3, 2, 1};
+
+static void t509_transmit(
+struct nic *nic,
+const char *d,			/* Destination */
+unsigned int t,			/* Type */
+unsigned int s,			/* size */
+const char *p)			/* Packet */
+{
+	register unsigned int len;
+	int pad;
+	int status;
+
+#ifdef	EDEBUG
+	printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
+#endif
+
+	/* swap bytes of type */
+	t= htons(t);
+
+	len=s+ETH_HLEN; /* actual length of packet */
+	pad = padmap[len & 3];
+
+	/*
+	* The 3c509 automatically pads short packets to minimum ethernet length,
+	* but we drop packets that are too large. Perhaps we should truncate
+	* them instead?
+	*/
+	if (len + pad > ETH_FRAME_LEN) {
+		return;
+	}
+
+	/* drop acknowledgements */
+	while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
+		if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
+			outw(TX_RESET, nic->ioaddr + EP_COMMAND);
+			outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
+		}
+		outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
+	}
+
+	while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
+		; /* no room in FIFO */
+
+	outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
+	outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1);	/* Second dword meaningless */
+
+	/* write packet */
+	outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
+	outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
+	outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
+	outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
+	if (s & 1)
+		outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);
+
+	while (pad--)
+		outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1);	/* Padding */
+
+	/* wait for Tx complete */
+	while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
+		;
+}
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+***************************************************************************/
+static int t509_poll(struct nic *nic, int retrieve)
+{
+	/* common variables */
+	/* variables for 3C509 */
+	short status, cst;
+	register short rx_fifo;
+
+	cst=inw(nic->ioaddr + EP_STATUS);
+
+#ifdef	EDEBUG
+	if(cst & 0x1FFF)
+		printf("-%hX-",cst);
+#endif
+
+	if( (cst & S_RX_COMPLETE)==0 ) {
+		/* acknowledge  everything */
+		outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
+		outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
+
+		return 0;
+	}
+
+	status = inw(nic->ioaddr + EP_W1_RX_STATUS);
+#ifdef	EDEBUG
+	printf("*%hX*",status);
+#endif
+
+	if (status & ERR_RX) {
+		outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
+		return 0;
+	}
+
+	rx_fifo = status & RX_BYTES_MASK;
+	if (rx_fifo==0)
+		return 0;
+
+	if ( ! retrieve ) return 1;
+
+		/* read packet */
+#ifdef	EDEBUG
+	printf("[l=%d",rx_fifo);
+#endif
+	insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
+	if(rx_fifo & 1)
+		nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
+	nic->packetlen=rx_fifo;
+
+	while(1) {
+		status = inw(nic->ioaddr + EP_W1_RX_STATUS);
+#ifdef	EDEBUG
+		printf("*%hX*",status);
+#endif
+		rx_fifo = status & RX_BYTES_MASK;
+		if(rx_fifo>0) {
+			insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
+			if(rx_fifo & 1)
+				nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
+			nic->packetlen+=rx_fifo;
+#ifdef	EDEBUG
+			printf("+%d",rx_fifo);
+#endif
+		}
+		if(( status & RX_INCOMPLETE )==0) {
+#ifdef	EDEBUG
+			printf("=%d",nic->packetlen);
+#endif
+			break;
+		}
+		udelay(1000);	/* if incomplete wait 1 ms */
+	}
+	/* acknowledge reception of packet */
+	outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
+	while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+		;
+#ifdef	EDEBUG
+{
+	unsigned short type = 0;	/* used by EDEBUG */
+	type = (nic->packet[12]<<8) | nic->packet[13];
+	if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
+	    nic->packet[5] == 0xFF*ETH_ALEN)
+		printf(",t=%hX,b]",type);
+	else
+		printf(",t=%hX]",type);
+}
+#endif
+	return (1);
+}
+
+/**************************************************************************
+ETH_IRQ - interrupt handling
+***************************************************************************/
+static void t509_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+/*************************************************************************
+	3Com 509 - specific routines
+**************************************************************************/
+
+static int eeprom_rdy ( uint16_t ioaddr ) {
+	int i;
+
+	for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
+	if (i >= MAX_EEPROMBUSY) {
+		/* printf("3c509: eeprom failed to come ready.\n"); */
+		/* memory in EPROM is tight */
+		/* printf("3c509: eeprom busy.\n"); */
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * get_e: gets a 16 bits word from the EEPROM.
+ */
+static int get_e ( uint16_t ioaddr, int offset ) {
+	GO_WINDOW(ioaddr,0);
+	if (!eeprom_rdy(ioaddr))
+		return (0xffff);
+	outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
+	if (!eeprom_rdy(ioaddr))
+		return (0xffff);
+	return (inw(ioaddr + EP_W0_EEPROM_DATA));
+}
+
+static struct nic_operations t509_operations = {
+	.connect	= dummy_connect,
+	.poll		= t509_poll,
+	.transmit	= t509_transmit,
+	.irq		= t509_irq,
+};
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+***************************************************************************/
+int t5x9_probe ( struct nic *nic,
+		 uint16_t prod_id_check, uint16_t prod_id_mask ) {
+	uint16_t prod_id;
+	int i,j;
+	unsigned short *p;
+	
+	/* Check product ID */
+	prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
+	if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
+		printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
+			 prod_id, prod_id_mask, prod_id_check );
+		return 0;
+	}
+
+	/* test for presence of connectors */
+	GO_WINDOW(nic->ioaddr,0);
+	i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
+	j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
+
+	switch(j) {
+	case 0:
+		if (i & IS_UTP) {
+			printf("10baseT\n");
+			connector = utp;
+		} else {
+			printf("10baseT not present\n");
+			return 0;
+		}
+		break;
+	case 1:
+		if (i & IS_AUI) {
+			printf("10base5\n");
+		} else {
+			printf("10base5 not present\n");
+			return 0;
+		}
+		break;
+	case 3:
+		if (i & IS_BNC) {
+			printf("10base2\n");
+			connector = bnc;
+		} else {
+			printf("10base2 not present\n");
+			return 0;
+		}
+		break;
+	default:
+		printf("unknown connector\n");
+		return 0;
+	}
+
+	/*
+	* Read the station address from the eeprom
+	*/
+	p = (unsigned short *) nic->node_addr;
+	for (i = 0; i < ETH_ALEN / 2; i++) {
+		p[i] = htons(get_e(nic->ioaddr,i));
+		GO_WINDOW(nic->ioaddr,2);
+		outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
+	}
+
+	DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) );
+
+	t509_reset(nic);
+
+	nic->nic_op = &t509_operations;
+	return 1;
+
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.c
new file mode 100644
index 0000000..c190057
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.c
@@ -0,0 +1,988 @@
+/*
+ * 3c90x.c -- This file implements a iPXE API 3c90x driver
+ *
+ * Originally written for etherboot by:
+ *   Greg Beeley, Greg.Beeley at LightSys.org
+ * Modified by Steve Smith,
+ *   Steve.Smith at Juno.Com. Alignment bug fix Neil Newell (nn at icenoir.net).
+ * Almost totally Rewritten to use iPXE API, implementation of tx/rx ring support
+ *   by Thomas Miletich, thomas.miletich at gmail.com
+ *   Thanks to Marty Connor and Stefan Hajnoczi for their help and feedback,
+ *   and to Daniel Verkamp for his help with testing.
+ *
+ * Copyright (c) 2009 Thomas Miletich
+ *
+ * Copyright (c) 1999 LightSys Technology Services, Inc.
+ * Portions Copyright (c) 1999 Steve Smith
+ *
+ * This program may be re-distributed in source or binary form, modified,
+ * sold, or copied for any purpose, provided that the above copyright message
+ * and this text are included with all source copies or derivative works, and
+ * provided that the above copyright message and this text are included in the
+ * documentation of any binary-only distributions.  This program is distributed
+ * WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR A PARTICULAR
+ * PURPOSE or MERCHANTABILITY.  Please read the associated documentation
+ * "3c90x.txt" before compiling and using this driver.
+ *
+ * [ --mdc 20090313 The 3c90x.txt file is now at:
+ *   http://etherboot.org/wiki/appnotes/3c90x_issues ]
+ *
+ * This program was written with the assistance of the 3com documentation for
+ * the 3c905B-TX card, as well as with some assistance from the 3c59x
+ * driver Donald Becker wrote for the Linux kernel, and with some assistance
+ * from the remainder of the Etherboot distribution.
+ *
+ * Indented with unix 'indent' command: 
+ *   $ indent -kr -i8 3c90x.c
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+#include <ipxe/nvs.h>
+
+#include "3c90x.h"
+
+/**
+ * a3c90x_internal_IssueCommand: sends a command to the 3c90x card
+ * and waits for it's completion
+ *
+ * @v ioaddr	IOAddress of the NIC
+ * @v cmd	Command to be issued
+ * @v param	Command parameter
+ */
+static void a3c90x_internal_IssueCommand(int ioaddr, int cmd, int param)
+{
+	unsigned int val = (cmd << 11) | param;
+	int cnt = 0;
+
+	DBGP("a3c90x_internal_IssueCommand\n");
+
+	/* Send the cmd to the cmd register */
+	outw(val, ioaddr + regCommandIntStatus_w);
+
+	/* Wait for the cmd to complete */
+	for (cnt = 0; cnt < 100000; cnt++) {
+		if (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) {
+			continue;
+		} else {
+			DBG2("Command 0x%04X finished in time. cnt = %d.\n", cmd, cnt);
+			return;
+		}
+	}
+
+	DBG("Command 0x%04X DID NOT finish in time. cnt = %d.\n", cmd, cnt);
+}
+
+/**
+ * a3c90x_internal_SetWindow: selects a register window set.
+ *
+ * @v inf_3c90x	private NIC data
+ * @v window	window to be selected
+ */
+static void a3c90x_internal_SetWindow(struct INF_3C90X *inf_3c90x, int window)
+{
+	DBGP("a3c90x_internal_SetWindow\n");
+	/* Window already as set? */
+	if (inf_3c90x->CurrentWindow == window)
+		return;
+
+	/* Issue the window command. */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdSelectRegisterWindow, window);
+	inf_3c90x->CurrentWindow = window;
+
+	return;
+}
+
+static void a3c90x_internal_WaitForEeprom(struct INF_3C90X *inf_3c90x)
+{
+	int cnt = 0;
+
+	DBGP("a3c90x_internal_WaitForEeprom\n");
+
+	while (eepromBusy & inw(inf_3c90x->IOAddr + regEepromCommand_0_w)) {
+		if (cnt == EEPROM_TIMEOUT) {
+			DBG("Read from eeprom failed: timeout\n");
+			return;
+		}
+		udelay(1);
+		cnt++;
+	}
+}
+
+/**
+ * a3c90x_internal_ReadEeprom - nvs routine to read eeprom data
+ * We only support reading one word(2 byte). The nvs subsystem will make sure
+ * that the routine will never be called with len != 2.
+ *
+ * @v nvs	nvs data.
+ * @v address	eeprom address to read data from.
+ * @v data	data is put here.
+ * @v len	number of bytes to read.
+ */
+static int
+a3c90x_internal_ReadEeprom(struct nvs_device *nvs, unsigned int address, void *data, size_t len)
+{
+	unsigned short *dest = (unsigned short *) data;
+	struct INF_3C90X *inf_3c90x =
+	    container_of(nvs, struct INF_3C90X, nvs);
+
+	DBGP("a3c90x_internal_ReadEeprom\n");
+
+	/* we support reading 2 bytes only */
+	assert(len == 2);
+
+	/* Select correct window */
+	a3c90x_internal_SetWindow(inf_3c90x, winEepromBios0);
+
+	/* set eepromRead bits in command sent to NIC */
+	address += (inf_3c90x->is3c556 ? eepromRead_556 : eepromRead);
+
+	a3c90x_internal_WaitForEeprom(inf_3c90x);
+	/* send address to NIC */
+	outw(address, inf_3c90x->IOAddr + regEepromCommand_0_w);
+	a3c90x_internal_WaitForEeprom(inf_3c90x);
+
+	/* read value */
+	*dest = inw(inf_3c90x->IOAddr + regEepromData_0_w);
+
+	return 0;
+}
+
+/**
+ * a3c90x_internal_WriteEeprom - nvs routine to write eeprom data
+ * currently not implemented
+ *
+ * @v nvs	nvs data.
+ * @v address	eeprom address to read data from.
+ * @v data	data is put here.
+ * @v len	number of bytes to read.
+ */
+static int
+a3c90x_internal_WriteEeprom(struct nvs_device *nvs __unused,
+			    unsigned int address __unused,
+			    const void *data __unused, size_t len __unused)
+{
+	return -ENOTSUP;
+}
+
+static void a3c90x_internal_ReadEepromContents(struct INF_3C90X *inf_3c90x)
+{
+	int eeprom_size = (inf_3c90x->isBrev ? 0x20 : 0x17) * 2;
+
+	DBGP("a3c90x_internal_ReadEepromContents\n");
+
+	nvs_read(&inf_3c90x->nvs, 0, inf_3c90x->eeprom, eeprom_size);
+}
+
+/**
+ * a3c90x_reset: exported function that resets the card to its default
+ * state.  This is so the Linux driver can re-set the card up the way
+ * it wants to.  If CFG_3C90X_PRESERVE_XCVR is defined, then the reset will
+ * not alter the selected transceiver that we used to download the boot
+ * image.
+ *
+ * @v inf_3c90x	Private NIC data
+ */
+static void a3c90x_reset(struct INF_3C90X *inf_3c90x)
+{
+	DBGP("a3c90x_reset\n");
+	/* Send the reset command to the card */
+	DBG2("3c90x: Issuing RESET\n");
+
+	/* reset of the receiver on B-revision cards re-negotiates the link
+	 * takes several seconds (a computer eternity), so we don't reset
+	 * it here.
+	 */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdGlobalReset,
+				     globalResetMaskNetwork);
+
+	/* global reset command resets station mask, non-B revision cards
+	 * require explicit reset of values
+	 */
+	a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
+	outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 0);
+	outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 2);
+	outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 4);
+
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);
+
+	/* enable rxComplete and txComplete indications */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdSetIndicationEnable,
+				     INT_TXCOMPLETE | INT_UPCOMPLETE);
+
+	/* acknowledge any pending status flags */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdAcknowledgeInterrupt, 0x661);
+
+	return;
+}
+
+/**
+ * a3c90x_setup_tx_ring - Allocates TX ring, initialize tx_desc values
+ *
+ * @v p	Private NIC data
+ *
+ * @ret Returns 0 on success, negative on failure
+ */
+static int a3c90x_setup_tx_ring(struct INF_3C90X *p)
+{
+	DBGP("a3c90x_setup_tx_ring\n");
+	p->tx_ring =
+	    malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN);
+
+	if (!p->tx_ring) {
+		DBG("Could not allocate TX-ring\n");
+		return -ENOMEM;
+	}
+
+	memset(p->tx_ring, 0, TX_RING_SIZE * sizeof(struct TXD));
+	p->tx_cur = 0;
+	p->tx_cnt = 0;
+	p->tx_tail = 0;
+
+	return 0;
+}
+
+/**
+ * a3c90x_process_tx_packets - Checks for successfully sent packets,
+ * reports them to iPXE with netdev_tx_complete();
+ *
+ * @v netdev	Network device info
+ */
+static void a3c90x_process_tx_packets(struct net_device *netdev)
+{
+	struct INF_3C90X *p = netdev_priv(netdev);
+	unsigned int downlist_ptr;
+
+	DBGP("a3c90x_process_tx_packets\n");
+
+	DBG2("    tx_cnt: %d\n", p->tx_cnt);
+
+	while (p->tx_tail != p->tx_cur) {
+
+		downlist_ptr = inl(p->IOAddr + regDnListPtr_l);
+
+		DBG2("    downlist_ptr: %#08x\n", downlist_ptr);
+		DBG2("    tx_tail: %d tx_cur: %d\n", p->tx_tail, p->tx_cur);
+
+		/* NIC is currently working on this tx desc */
+		if(downlist_ptr == virt_to_bus(p->tx_ring + p->tx_tail))
+			return;
+
+		netdev_tx_complete(netdev, p->tx_iobuf[p->tx_tail]);
+
+		DBG2("transmitted packet\n");
+		DBG2("    size: %zd\n", iob_len(p->tx_iobuf[p->tx_tail]));
+
+		p->tx_tail = (p->tx_tail + 1) % TX_RING_SIZE;
+		p->tx_cnt--;
+	}
+}
+
+static void a3c90x_free_tx_ring(struct INF_3C90X *p)
+{
+	DBGP("a3c90x_free_tx_ring\n");
+
+	free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD));
+	p->tx_ring = NULL;
+	/* io_buffers are free()ed by netdev_tx_complete[,_err]() */
+}
+
+/**
+ * a3c90x_transmit - Transmits a packet.
+ *
+ * @v netdev	Network device info
+ * @v iob		io_buffer containing the data to be send
+ *
+ * @ret	Returns 0 on success, negative on failure
+ */
+static int a3c90x_transmit(struct net_device *netdev,
+			   struct io_buffer *iob)
+{
+	struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
+	struct TXD *tx_cur_desc;
+	struct TXD *tx_prev_desc;
+
+	unsigned int len;
+	unsigned int downlist_ptr;
+
+	DBGP("a3c90x_transmit\n");
+
+	if (inf_3c90x->tx_cnt == TX_RING_SIZE) {
+		DBG("TX-Ring overflow\n");
+		return -ENOBUFS;
+	}
+
+	inf_3c90x->tx_iobuf[inf_3c90x->tx_cur] = iob;
+	tx_cur_desc = inf_3c90x->tx_ring + inf_3c90x->tx_cur;
+
+	tx_prev_desc = inf_3c90x->tx_ring +
+	    (((inf_3c90x->tx_cur + TX_RING_SIZE) - 1) % TX_RING_SIZE);
+
+	len = iob_len(iob);
+
+	/* Setup the DPD (download descriptor) */
+	tx_cur_desc->DnNextPtr = 0;
+
+	/* FrameStartHeader differs in 90x and >= 90xB
+	 * It contains length in 90x and a round up boundary and packet ID for
+	 * 90xB and 90xC. We can leave this to 0 for 90xB and 90xC.
+	 */
+	tx_cur_desc->FrameStartHeader =
+	    fshTxIndicate | (inf_3c90x->isBrev ? 0x00 : len);
+
+	tx_cur_desc->DataAddr = virt_to_bus(iob->data);
+	tx_cur_desc->DataLength = len | downLastFrag;
+
+	/* We have to stall the download engine, so the NIC won't access the
+	 * tx descriptor while we modify it. There is a way around this
+	 * from revision B and upwards. To stay compatible with older revisions
+	 * we don't use it here.
+	 */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
+				     dnStall);
+
+	tx_prev_desc->DnNextPtr = virt_to_bus(tx_cur_desc);
+
+	downlist_ptr = inl(inf_3c90x->IOAddr + regDnListPtr_l);
+	if (downlist_ptr == 0) {
+		/* currently no DownList, sending a new one */
+		outl(virt_to_bus(tx_cur_desc),
+		     inf_3c90x->IOAddr + regDnListPtr_l);
+	}
+
+	/* End Stall */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
+				     dnUnStall);
+
+	inf_3c90x->tx_cur = (inf_3c90x->tx_cur + 1) % TX_RING_SIZE;
+	inf_3c90x->tx_cnt++;
+
+	return 0;
+}
+
+/**
+ * a3c90x_prepare_rx_desc - fills the rx desc with initial data
+ *
+ * @v p		NIC private data
+ * @v index	Index for rx_iobuf and rx_ring array
+ */
+
+static void a3c90x_prepare_rx_desc(struct INF_3C90X *p, unsigned int index)
+{
+	DBGP("a3c90x_prepare_rx_desc\n");
+	DBG2("Populating rx_desc %d\n", index);
+
+	/* We have to stall the upload engine, so the NIC won't access the
+	 * rx descriptor while we modify it. There is a way around this
+	 * from revision B and upwards. To stay compatible with older revisions
+	 * we don't use it here.
+	 */
+	a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upStall);
+
+	p->rx_ring[index].DataAddr = virt_to_bus(p->rx_iobuf[index]->data);
+	p->rx_ring[index].DataLength = RX_BUF_SIZE | upLastFrag;
+	p->rx_ring[index].UpPktStatus = 0;
+
+	/* unstall upload engine */
+	a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upUnStall);
+}
+
+/**
+ * a3c90x_refill_rx_ring -checks every entry in the rx ring and reallocates
+ * them as necessary. Then it calls a3c90x_prepare_rx_desc to fill the rx desc
+ * with initial data.
+ *
+ * @v p		NIC private data
+ */
+static void a3c90x_refill_rx_ring(struct INF_3C90X *p)
+{
+	int i;
+	unsigned int status;
+	struct RXD *rx_cur_desc;
+
+	DBGP("a3c90x_refill_rx_ring\n");
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_cur_desc = p->rx_ring + i;
+		status = rx_cur_desc->UpPktStatus;
+
+		/* only refill used descriptor */
+		if (!(status & upComplete))
+			continue;
+
+		/* we still need to process this descriptor */
+		if (p->rx_iobuf[i] != NULL)
+			continue;
+
+		p->rx_iobuf[i] = alloc_iob(RX_BUF_SIZE);
+		if (p->rx_iobuf[i] == NULL) {
+			DBG("alloc_iob() failed\n");
+			break;
+		}
+
+		a3c90x_prepare_rx_desc(p, i);
+	}
+}
+
+/**
+ * a3c90x_setup_rx_ring - Allocates RX ring, initialize rx_desc values
+ *
+ * @v p	Private NIC data
+ *
+ * @ret Returns 0 on success, negative on failure
+ */
+static int a3c90x_setup_rx_ring(struct INF_3C90X *p)
+{
+	int i;
+
+	DBGP("a3c90x_setup_rx_ring\n");
+
+	p->rx_ring =
+	    malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN);
+
+	if (!p->rx_ring) {
+		DBG("Could not allocate RX-ring\n");
+		return -ENOMEM;
+	}
+
+	p->rx_cur = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		p->rx_ring[i].UpNextPtr =
+		    virt_to_bus(p->rx_ring + (i + 1));
+
+		/* these are needed so refill_rx_ring initializes the ring */
+		p->rx_ring[i].UpPktStatus = upComplete;
+		p->rx_iobuf[i] = NULL;
+	}
+
+	/* Loop the ring */
+	p->rx_ring[i - 1].UpNextPtr = virt_to_bus(p->rx_ring);
+
+	a3c90x_refill_rx_ring(p);
+
+	return 0;
+}
+
+static void a3c90x_free_rx_ring(struct INF_3C90X *p)
+{
+	DBGP("a3c90x_free_rx_ring\n");
+
+	free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD));
+	p->rx_ring = NULL;
+}
+
+static void a3c90x_free_rx_iobuf(struct INF_3C90X *p)
+{
+	int i;
+
+	DBGP("a3c90x_free_rx_iobuf\n");
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		free_iob(p->rx_iobuf[i]);
+		p->rx_iobuf[i] = NULL;
+	}
+}
+
+/**
+ * a3c90x_process_rx_packets - Checks for received packets,
+ * reports them to iPXE with netdev_rx() or netdev_rx_err() if there was an
+ * error while receiving the packet
+ *
+ * @v netdev	Network device info
+ */
+static void a3c90x_process_rx_packets(struct net_device *netdev)
+{
+	int i;
+	unsigned int rx_status;
+	struct INF_3C90X *p = netdev_priv(netdev);
+	struct RXD *rx_cur_desc;
+
+	DBGP("a3c90x_process_rx_packets\n");
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_cur_desc = p->rx_ring + p->rx_cur;
+		rx_status = rx_cur_desc->UpPktStatus;
+
+		if (!(rx_status & upComplete) && !(rx_status & upError))
+			break;
+
+		if (p->rx_iobuf[p->rx_cur] == NULL)
+			break;
+
+		if (rx_status & upError) {
+			DBG("Corrupted packet received: %#x\n", rx_status);
+			netdev_rx_err(netdev, p->rx_iobuf[p->rx_cur],
+				      -EINVAL);
+		} else {
+			/* if we're here, we've got good packet */
+			int packet_len;
+
+			packet_len = rx_status & 0x1FFF;
+			iob_put(p->rx_iobuf[p->rx_cur], packet_len);
+
+			DBG2("received packet\n");
+			DBG2("    size: %d\n", packet_len);
+
+			netdev_rx(netdev, p->rx_iobuf[p->rx_cur]);
+		}
+
+		p->rx_iobuf[p->rx_cur] = NULL;	/* invalidate rx desc */
+		p->rx_cur = (p->rx_cur + 1) % RX_RING_SIZE;
+	}
+	a3c90x_refill_rx_ring(p);
+
+}
+
+/**
+ * a3c90x_poll - Routine that gets called periodically.
+ * Here we hanle transmitted and received packets.
+ * We could also check the link status from time to time, which we
+ * currently don't do.
+ *
+ * @v netdev	Network device info
+ */
+static void a3c90x_poll(struct net_device *netdev)
+{
+	struct INF_3C90X *p = netdev_priv(netdev);
+	uint16_t raw_status, int_status;
+
+	DBGP("a3c90x_poll\n");
+
+	raw_status = inw(p->IOAddr + regCommandIntStatus_w);
+	int_status = (raw_status & 0x0FFF);
+
+	if ( int_status == 0 )
+		return;
+
+	a3c90x_internal_IssueCommand(p->IOAddr, cmdAcknowledgeInterrupt,
+				     int_status);
+
+	if (int_status & INT_TXCOMPLETE)
+		outb(0x00, p->IOAddr + regTxStatus_b);
+
+	DBG2("poll: status = %#04x\n", raw_status);
+
+	a3c90x_process_tx_packets(netdev);
+
+	a3c90x_process_rx_packets(netdev);
+}
+
+
+
+static void a3c90x_free_resources(struct INF_3C90X *p)
+{
+	DBGP("a3c90x_free_resources\n");
+
+	a3c90x_free_tx_ring(p);
+	a3c90x_free_rx_ring(p);
+	a3c90x_free_rx_iobuf(p);
+}
+
+/**
+ * a3c90x_remove - Routine to remove the card. Unregisters
+ * the NIC from iPXE, disables RX/TX and resets the card.
+ *
+ * @v pci	PCI device info
+ */
+static void a3c90x_remove(struct pci_device *pci)
+{
+	struct net_device *netdev = pci_get_drvdata(pci);
+	struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
+
+	DBGP("a3c90x_remove\n");
+
+	a3c90x_reset(inf_3c90x);
+
+	/* Disable the receiver and transmitter. */
+	outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
+	outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
+
+	unregister_netdev(netdev);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+static void a3c90x_irq(struct net_device *netdev, int enable)
+{
+	struct INF_3C90X *p = netdev_priv(netdev);
+
+	DBGP("a3c90x_irq\n");
+
+	if (enable == 0) {
+		/* disable interrupts */
+		a3c90x_internal_IssueCommand(p->IOAddr,
+					     cmdSetInterruptEnable, 0);
+	} else {
+		a3c90x_internal_IssueCommand(p->IOAddr,
+					     cmdSetInterruptEnable,
+					     INT_TXCOMPLETE |
+					     INT_UPCOMPLETE);
+		a3c90x_internal_IssueCommand(p->IOAddr,
+					     cmdAcknowledgeInterrupt,
+					     0x661);
+	}
+}
+
+/**
+ * a3c90x_hw_start - Initialize hardware, copy MAC address
+ * to NIC registers, set default receiver
+ */
+static void a3c90x_hw_start(struct net_device *netdev)
+{
+	int i, c;
+	unsigned int cfg;
+	unsigned int mopt;
+	unsigned short linktype;
+	struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
+
+	DBGP("a3c90x_hw_start\n");
+
+	/* 3C556: Invert MII power */
+	if (inf_3c90x->is3c556) {
+		unsigned int tmp;
+		a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
+		tmp = inw(inf_3c90x->IOAddr + regResetOptions_2_w);
+		tmp |= 0x4000;
+		outw(tmp, inf_3c90x->IOAddr + regResetOptions_2_w);
+	}
+
+	/* Copy MAC address into the NIC registers */
+	a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(netdev->ll_addr[i],
+		     inf_3c90x->IOAddr + regStationAddress_2_3w + i);
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(0, inf_3c90x->IOAddr + regStationMask_2_3w + i);
+
+	/* Read the media options register, print a message and set default
+	* xcvr.
+	*
+	* Uses Media Option command on B revision, Reset Option on non-B
+	* revision cards -- same register address
+	*/
+	a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
+	mopt = inw(inf_3c90x->IOAddr + regResetMediaOptions_3_w);
+
+	/* mask out VCO bit that is defined as 10baseFL bit on B-rev cards */
+	if (!inf_3c90x->isBrev) {
+		mopt &= 0x7F;
+	}
+
+	DBG2("Connectors present: ");
+	c = 0;
+	linktype = 0x0008;
+	if (mopt & 0x01) {
+		DBG2("%s100Base-T4", (c++) ? ", " : "");
+		linktype = linkMII;
+	}
+	if (mopt & 0x04) {
+		DBG2("%s100Base-FX", (c++) ? ", " : "");
+		linktype = link100BaseFX;
+	}
+	if (mopt & 0x10) {
+		DBG2("%s10Base-2", (c++) ? ", " : "");
+		linktype = link10Base2;
+	}
+	if (mopt & 0x20) {
+		DBG2("%sAUI", (c++) ? ", " : "");
+		linktype = linkAUI;
+	}
+	if (mopt & 0x40) {
+		DBG2("%sMII", (c++) ? ", " : "");
+		linktype = linkMII;
+	}
+	if ((mopt & 0xA) == 0xA) {
+		DBG2("%s10Base-T / 100Base-TX", (c++) ? ", " : "");
+		linktype = linkAutoneg;
+	} else if ((mopt & 0xA) == 0x2) {
+		DBG2("%s100Base-TX", (c++) ? ", " : "");
+		linktype = linkAutoneg;
+	} else if ((mopt & 0xA) == 0x8) {
+		DBG2("%s10Base-T", (c++) ? ", " : "");
+		linktype = linkAutoneg;
+	}
+	DBG2(".\n");
+
+	/* Determine transceiver type to use, depending on value stored in
+	* eeprom 0x16
+	*/
+	if (inf_3c90x->isBrev) {
+		if ((inf_3c90x->eeprom[0x16] & 0xFF00) == XCVR_MAGIC) {
+			/* User-defined */
+			linktype = inf_3c90x->eeprom[0x16] & 0x000F;
+		}
+	} else {
+		/* I don't know what MII MAC only mode is!!! */
+		if (linktype == linkExternalMII) {
+			if (inf_3c90x->isBrev)
+				DBG("WARNING: MII External MAC Mode only supported on B-revision " "cards!!!!\nFalling Back to MII Mode\n");
+			linktype = linkMII;
+		}
+	}
+
+	/* enable DC converter for 10-Base-T */
+	if (linktype == link10Base2) {
+		a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+					     cmdEnableDcConverter, 0);
+	}
+
+	/* Set the link to the type we just determined. */
+	a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
+	cfg = inl(inf_3c90x->IOAddr + regInternalConfig_3_l);
+	cfg &= ~(0xF << 20);
+	cfg |= (linktype << 20);
+
+	DBG2("Setting internal cfg register: 0x%08X (linktype: 0x%02X)\n",
+	    cfg, linktype);
+
+	outl(cfg, inf_3c90x->IOAddr + regInternalConfig_3_l);
+
+	/* Now that we set the xcvr type, reset the Tx and Rx */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0x00);
+
+	if (!inf_3c90x->isBrev)
+		outb(0x01, inf_3c90x->IOAddr + regTxFreeThresh_b);
+
+	/* Set the RX filter = receive only individual pkts & multicast & bcast. */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdSetRxFilter,
+				     0x01 + 0x02 + 0x04);
+
+
+	/*
+	* set Indication and Interrupt flags , acknowledge any IRQ's
+	*/
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdSetInterruptEnable,
+	 INT_TXCOMPLETE | INT_UPCOMPLETE);
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdSetIndicationEnable,
+	 INT_TXCOMPLETE | INT_UPCOMPLETE);
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
+				     cmdAcknowledgeInterrupt, 0x661);
+}
+
+/**
+ * a3c90x_open - Routine to initialize the card. Initialize hardware,
+ * allocate TX and RX ring, send RX ring address to the NIC.
+ *
+ * @v netdev	Network device info
+ *
+ * @ret Returns 0 on success, negative on failure
+ */
+static int a3c90x_open(struct net_device *netdev)
+{
+	int rc;
+	struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
+
+	DBGP("a3c90x_open\n");
+
+	a3c90x_hw_start(netdev);
+
+	rc = a3c90x_setup_tx_ring(inf_3c90x);
+	if (rc != 0) {
+		DBG("Error setting up TX Ring\n");
+		goto error;
+	}
+
+	rc = a3c90x_setup_rx_ring(inf_3c90x);
+	if (rc != 0) {
+		DBG("Error setting up RX Ring\n");
+		goto error;
+	}
+
+	/* send rx_ring address to NIC */
+	outl(virt_to_bus(inf_3c90x->rx_ring),
+	     inf_3c90x->IOAddr + regUpListPtr_l);
+
+	/* enable packet transmission and reception */
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
+	a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);
+
+	return 0;
+
+      error:
+	a3c90x_free_resources(inf_3c90x);
+	a3c90x_reset(inf_3c90x);
+	return rc;
+}
+
+/**
+ * a3c90x_close - free()s TX and RX ring, disablex RX/TX, resets NIC
+ *
+ * @v netdev	Network device info
+ */
+static void a3c90x_close(struct net_device *netdev)
+{
+	struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
+
+	DBGP("a3c90x_close\n");
+
+	a3c90x_reset(inf_3c90x);
+	outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
+	outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
+	a3c90x_free_resources(inf_3c90x);
+}
+
+static struct net_device_operations a3c90x_operations = {
+	.open = a3c90x_open,
+	.close = a3c90x_close,
+	.poll = a3c90x_poll,
+	.transmit = a3c90x_transmit,
+	.irq = a3c90x_irq,
+};
+
+/**
+ * a3c90x_probe: exported routine to probe for the 3c905 card.
+ * If this routine is called, the pci functions did find the
+ * card.  We read the eeprom here and get the MAC address.
+ * Initialization is done in a3c90x_open().
+ *
+ * @v pci	PCI device info
+ * @ pci_id	PCI device IDs
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int a3c90x_probe(struct pci_device *pci)
+{
+
+	struct net_device *netdev;
+	struct INF_3C90X *inf_3c90x;
+	unsigned char *HWAddr;
+	int rc;
+
+	DBGP("a3c90x_probe\n");
+
+	if (pci->ioaddr == 0)
+		return -EINVAL;
+
+	netdev = alloc_etherdev(sizeof(*inf_3c90x));
+	if (!netdev)
+		return -ENOMEM;
+
+	netdev_init(netdev, &a3c90x_operations);
+	pci_set_drvdata(pci, netdev);
+	netdev->dev = &pci->dev;
+
+	inf_3c90x = netdev_priv(netdev);
+	memset(inf_3c90x, 0, sizeof(*inf_3c90x));
+
+	adjust_pci_device(pci);
+
+	inf_3c90x->is3c556 = (pci->device == 0x6055);
+	inf_3c90x->IOAddr = pci->ioaddr;
+	inf_3c90x->CurrentWindow = winNone;
+
+	inf_3c90x->isBrev = 1;
+	switch (pci->device) {
+	case 0x9000:		/* 10 Base TPO             */
+	case 0x9001:		/* 10/100 T4               */
+	case 0x9050:		/* 10/100 TPO              */
+	case 0x9051:		/* 10 Base Combo           */
+		inf_3c90x->isBrev = 0;
+		break;
+	}
+
+	DBG2("[3c90x]: found NIC(0x%04X, 0x%04X), isBrev=%d, is3c556=%d\n",
+	    pci->vendor, pci->device, inf_3c90x->isBrev,
+	    inf_3c90x->is3c556);
+
+	/* initialize nvs device */
+	inf_3c90x->nvs.word_len_log2 = 1;	/* word */
+	inf_3c90x->nvs.size = (inf_3c90x->isBrev ? 0x20 : 0x17);
+	inf_3c90x->nvs.block_size = 1;
+	inf_3c90x->nvs.read = a3c90x_internal_ReadEeprom;
+	inf_3c90x->nvs.write = a3c90x_internal_WriteEeprom;
+
+	/* reset NIC before accessing any data from it */
+	a3c90x_reset(inf_3c90x);
+
+	/* load eeprom contents to inf_3c90x->eeprom */
+	a3c90x_internal_ReadEepromContents(inf_3c90x);
+
+	HWAddr = netdev->hw_addr;
+
+	/* Retrieve the Hardware address */
+	HWAddr[0] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] >> 8;
+	HWAddr[1] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] & 0xFF;
+	HWAddr[2] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] >> 8;
+	HWAddr[3] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] & 0xFF;
+	HWAddr[4] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] >> 8;
+	HWAddr[5] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] & 0xFF;
+
+	if ((rc = register_netdev(netdev)) != 0) {
+		DBG("3c90x: register_netdev() failed\n");
+		netdev_put(netdev);
+		return rc;
+	}
+
+	/* we don't handle linkstates yet, so we're always up */
+	netdev_link_up(netdev);
+
+	return 0;
+}
+
+static struct pci_device_id a3c90x_nics[] = {
+/* Original 90x revisions: */
+	PCI_ROM(0x10b7, 0x6055, "3c556", "3C556", 0),	/* Huricane */
+	PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO", 0),	/* 10 Base TPO */
+	PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo", 0),	/* 10/100 T4 */
+	PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0),	/* 100 Base TX / 10/100 TPO */
+	PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0),	/* 100 Base T4 / 10 Base Combo */
+/* Newer 90xB revisions: */
+	PCI_ROM(0x10b7, 0x9004, "3c905b-tpo", "3Com900B-TPO", 0),	/* 10 Base TPO */
+	PCI_ROM(0x10b7, 0x9005, "3c905b-combo", "3Com900B-Combo", 0),	/* 10 Base Combo */
+	PCI_ROM(0x10b7, 0x9006, "3c905b-tpb2", "3Com900B-2/T", 0),	/* 10 Base TP and Base2 */
+	PCI_ROM(0x10b7, 0x900a, "3c905b-fl", "3Com900B-FL", 0),	/* 10 Base FL */
+	PCI_ROM(0x10b7, 0x9055, "3c905b-tpo100", "3Com905B-TX", 0),	/* 10/100 TPO */
+	PCI_ROM(0x10b7, 0x9056, "3c905b-t4", "3Com905B-T4", 0),	/* 10/100 T4 */
+	PCI_ROM(0x10b7, 0x9058, "3c905b-9058", "3Com905B-9058", 0),	/* Cyclone 10/100/BNC */
+	PCI_ROM(0x10b7, 0x905a, "3c905b-fx", "3Com905B-FL", 0),	/* 100 Base FX / 10 Base FX */
+/* Newer 90xC revision: */
+	PCI_ROM(0x10b7, 0x9200, "3c905c-tpo", "3Com905C-TXM", 0),	/* 10/100 TPO (3C905C-TXM) */
+	PCI_ROM(0x10b7, 0x9202, "3c920b-emb-ati", "3c920B-EMB-WNM (ATI Radeon 9100 IGP)", 0),	/* 3c920B-EMB-WNM (ATI Radeon 9100 IGP) */
+	PCI_ROM(0x10b7, 0x9210, "3c920b-emb-wnm", "3Com20B-EMB WNM", 0),
+	PCI_ROM(0x10b7, 0x9800, "3c980", "3Com980-Cyclone", 0),	/* Cyclone */
+	PCI_ROM(0x10b7, 0x9805, "3c9805", "3Com9805", 0),	/* Dual Port Server Cyclone */
+	PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0),	/* Hurricane */
+	PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0),
+	PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0),
+	PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0),
+};
+
+struct pci_driver a3c90x_driver __pci_driver = {
+	.ids = a3c90x_nics,
+	.id_count = (sizeof(a3c90x_nics) / sizeof(a3c90x_nics[0])),
+	.probe = a3c90x_probe,
+	.remove = a3c90x_remove,
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.h
new file mode 100644
index 0000000..53fc522
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/3c90x.h
@@ -0,0 +1,308 @@
+/*
+ * 3c90x.c -- This file implements the 3c90x driver for etherboot.  Written
+ * by Greg Beeley, Greg.Beeley at LightSys.org.  Modified by Steve Smith,
+ * Steve.Smith at Juno.Com. Alignment bug fix Neil Newell (nn at icenoir.net).
+ *
+ * Port from etherboot to iPXE API, implementation of tx/rx ring support
+ * by Thomas Miletich, thomas.miletich at gmail.com
+ * Thanks to Marty Connor and Stefan Hajnoczi for their help and feedback.
+ *
+ * This program Copyright (C) 1999 LightSys Technology Services, Inc.
+ * Portions Copyright (C) 1999 Steve Smith
+ *
+ * This program may be re-distributed in source or binary form, modified,
+ * sold, or copied for any purpose, provided that the above copyright message
+ * and this text are included with all source copies or derivative works, and
+ * provided that the above copyright message and this text are included in the
+ * documentation of any binary-only distributions.  This program is distributed
+ * WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR A PARTICULAR
+ * PURPOSE or MERCHANTABILITY.  Please read the associated documentation
+ * "3c90x.txt" before compiling and using this driver.
+ *
+ * --------
+ *
+ * Program written with the assistance of the 3com documentation for
+ * the 3c905B-TX card, as well as with some assistance from the 3c59x
+ * driver Donald Becker wrote for the Linux kernel, and with some assistance
+ * from the remainder of the Etherboot distribution.
+ *
+ * REVISION HISTORY:
+ *
+ * v0.10	1-26-1998	GRB	Initial implementation.
+ * v0.90	1-27-1998	GRB	System works.
+ * v1.00pre1	2-11-1998	GRB	Got prom boot issue fixed.
+ * v2.0		9-24-1999	SCS	Modified for 3c905 (from 3c905b code)
+ *					Re-wrote poll and transmit for
+ *					better error recovery and heavy
+ *					network traffic operation
+ * v2.01    5-26-2003 NN Fixed driver alignment issue which
+ *                  caused system lockups if driver structures
+ *                  not 8-byte aligned.
+ * v2.02   11-28-2007 GSt Got polling working again by replacing
+ * 			"for(i=0;i<40000;i++);" with "mdelay(1);"
+ *
+ *
+ * indent options: indent -kr -i8 3c90x.c
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#ifndef __3C90X_H_
+#define __3C90X_H_
+
+static struct net_device_operations a3c90x_operations;
+
+#define	XCVR_MAGIC	(0x5A00)
+
+/* Register definitions for the 3c905 */
+enum Registers {
+	regPowerMgmtCtrl_w = 0x7c,	/* 905B Revision Only                 */
+	regUpMaxBurst_w = 0x7a,	/* 905B Revision Only                 */
+	regDnMaxBurst_w = 0x78,	/* 905B Revision Only                 */
+	regDebugControl_w = 0x74,	/* 905B Revision Only                 */
+	regDebugData_l = 0x70,	/* 905B Revision Only                 */
+	regRealTimeCnt_l = 0x40,	/* Universal                          */
+	regUpBurstThresh_b = 0x3e,	/* 905B Revision Only                 */
+	regUpPoll_b = 0x3d,	/* 905B Revision Only                 */
+	regUpPriorityThresh_b = 0x3c,	/* 905B Revision Only                 */
+	regUpListPtr_l = 0x38,	/* Universal                          */
+	regCountdown_w = 0x36,	/* Universal                          */
+	regFreeTimer_w = 0x34,	/* Universal                          */
+	regUpPktStatus_l = 0x30,	/* Universal with Exception, pg 130   */
+	regTxFreeThresh_b = 0x2f,	/* 90X Revision Only                  */
+	regDnPoll_b = 0x2d,	/* 905B Revision Only                 */
+	regDnPriorityThresh_b = 0x2c,	/* 905B Revision Only                 */
+	regDnBurstThresh_b = 0x2a,	/* 905B Revision Only                 */
+	regDnListPtr_l = 0x24,	/* Universal with Exception, pg 107   */
+	regDmaCtrl_l = 0x20,	/* Universal with Exception, pg 106   */
+	/*                                    */
+	regIntStatusAuto_w = 0x1e,	/* 905B Revision Only                 */
+	regTxStatus_b = 0x1b,	/* Universal with Exception, pg 113   */
+	regTimer_b = 0x1a,	/* Universal                          */
+	regTxPktId_b = 0x18,	/* 905B Revision Only                 */
+	regCommandIntStatus_w = 0x0e,	/* Universal (Command Variations)     */
+};
+
+/* following are windowed registers */
+enum Registers7 {
+	regPowerMgmtEvent_7_w = 0x0c,	/* 905B Revision Only                 */
+	regVlanEtherType_7_w = 0x04,	/* 905B Revision Only                 */
+	regVlanMask_7_w = 0x00,	/* 905B Revision Only                 */
+};
+
+enum Registers6 {
+	regBytesXmittedOk_6_w = 0x0c,	/* Universal                          */
+	regBytesRcvdOk_6_w = 0x0a,	/* Universal                          */
+	regUpperFramesOk_6_b = 0x09,	/* Universal                          */
+	regFramesDeferred_6_b = 0x08,	/* Universal                          */
+	regFramesRecdOk_6_b = 0x07,	/* Universal with Exceptions, pg 142  */
+	regFramesXmittedOk_6_b = 0x06,	/* Universal                          */
+	regRxOverruns_6_b = 0x05,	/* Universal                          */
+	regLateCollisions_6_b = 0x04,	/* Universal                          */
+	regSingleCollisions_6_b = 0x03,	/* Universal                          */
+	regMultipleCollisions_6_b = 0x02,	/* Universal                          */
+	regSqeErrors_6_b = 0x01,	/* Universal                          */
+	regCarrierLost_6_b = 0x00,	/* Universal                          */
+};
+
+enum Registers5 {
+	regIndicationEnable_5_w = 0x0c,	/* Universal                          */
+	regInterruptEnable_5_w = 0x0a,	/* Universal                          */
+	regTxReclaimThresh_5_b = 0x09,	/* 905B Revision Only                 */
+	regRxFilter_5_b = 0x08,	/* Universal                          */
+	regRxEarlyThresh_5_w = 0x06,	/* Universal                          */
+	regTxStartThresh_5_w = 0x00,	/* Universal                          */
+};
+
+enum Registers4 {
+	regUpperBytesOk_4_b = 0x0d,	/* Universal                          */
+	regBadSSD_4_b = 0x0c,	/* Universal                          */
+	regMediaStatus_4_w = 0x0a,	/* Universal with Exceptions, pg 201  */
+	regPhysicalMgmt_4_w = 0x08,	/* Universal                          */
+	regNetworkDiagnostic_4_w = 0x06,	/* Universal with Exceptions, pg 203  */
+	regFifoDiagnostic_4_w = 0x04,	/* Universal with Exceptions, pg 196  */
+	regVcoDiagnostic_4_w = 0x02,	/* Undocumented?                      */
+};
+
+enum Registers3 {
+	regTxFree_3_w = 0x0c,	/* Universal                          */
+	regRxFree_3_w = 0x0a,	/* Universal with Exceptions, pg 125  */
+	regResetMediaOptions_3_w = 0x08,	/* Media Options on B Revision,       */
+	/* Reset Options on Non-B Revision    */
+	regMacControl_3_w = 0x06,	/* Universal with Exceptions, pg 199  */
+	regMaxPktSize_3_w = 0x04,	/* 905B Revision Only                 */
+	regInternalConfig_3_l = 0x00,	/* Universal, different bit           */
+	/* definitions, pg 59                 */
+};
+
+enum Registers2 {
+	regResetOptions_2_w = 0x0c,	/* 905B Revision Only                 */
+	regStationMask_2_3w = 0x06,	/* Universal with Exceptions, pg 127  */
+	regStationAddress_2_3w = 0x00,	/* Universal with Exceptions, pg 127  */
+};
+
+enum Registers1 {
+	regRxStatus_1_w = 0x0a,	/* 90X Revision Only, Pg 126          */
+};
+
+enum Registers0 {
+	regEepromData_0_w = 0x0c,	/* Universal                          */
+	regEepromCommand_0_w = 0x0a,	/* Universal                          */
+	regBiosRomData_0_b = 0x08,	/* 905B Revision Only                 */
+	regBiosRomAddr_0_l = 0x04,	/* 905B Revision Only                 */
+};
+
+
+/* The names for the eight register windows */
+enum Windows {
+	winNone = 0xff,
+	winPowerVlan7 = 0x07,
+	winStatistics6 = 0x06,
+	winTxRxControl5 = 0x05,
+	winDiagnostics4 = 0x04,
+	winTxRxOptions3 = 0x03,
+	winAddressing2 = 0x02,
+	winUnused1 = 0x01,
+	winEepromBios0 = 0x00,
+};
+
+
+/* Command definitions for the 3c90X */
+enum Commands {
+	cmdGlobalReset = 0x00,	/* Universal with Exceptions, pg 151 */
+	cmdSelectRegisterWindow = 0x01,	/* Universal                         */
+	cmdEnableDcConverter = 0x02,	/*                                   */
+	cmdRxDisable = 0x03,	/*                                   */
+	cmdRxEnable = 0x04,	/* Universal                         */
+	cmdRxReset = 0x05,	/* Universal                         */
+	cmdStallCtl = 0x06,	/* Universal                         */
+	cmdTxEnable = 0x09,	/* Universal                         */
+	cmdTxDisable = 0x0A,	/*                                   */
+	cmdTxReset = 0x0B,	/* Universal                         */
+	cmdRequestInterrupt = 0x0C,	/*                                   */
+	cmdAcknowledgeInterrupt = 0x0D,	/* Universal                         */
+	cmdSetInterruptEnable = 0x0E,	/* Universal                         */
+	cmdSetIndicationEnable = 0x0F,	/* Universal                         */
+	cmdSetRxFilter = 0x10,	/* Universal                         */
+	cmdSetRxEarlyThresh = 0x11,	/*                                   */
+	cmdSetTxStartThresh = 0x13,	/*                                   */
+	cmdStatisticsEnable = 0x15,	/*                                   */
+	cmdStatisticsDisable = 0x16,	/*                                   */
+	cmdDisableDcConverter = 0x17,	/*                                   */
+	cmdSetTxReclaimThresh = 0x18,	/*                                   */
+	cmdSetHashFilterBit = 0x19,	/*                                   */
+};
+
+enum GlobalResetParams {
+	globalResetAll = 0,
+	globalResetMaskNetwork = (1<<2),
+	globalResetMaskAll = 0x1ff,
+};
+
+enum FrameStartHeader {
+	fshTxIndicate = 0x8000,
+	fshDnComplete = 0x10000,
+};
+
+enum UpDownDesc {
+	upLastFrag = (1 << 31),
+	downLastFrag = (1 << 31),
+};
+
+enum UpPktStatus {
+	upComplete = (1 << 15),
+	upError = (1 << 14),
+};
+
+enum Stalls {
+	upStall = 0x00,
+	upUnStall = 0x01,
+
+	dnStall = 0x02,
+	dnUnStall = 0x03,
+};
+
+enum Resources {
+	resRxRing = 0x00,
+	resTxRing = 0x02,
+	resRxIOBuf = 0x04
+};
+
+enum eeprom {
+	eepromBusy = (1 << 15),
+	eepromRead = ((0x02) << 6),
+	eepromRead_556 = 0x230,
+	eepromHwAddrOffset = 0x0a,
+};
+
+/* Bit 4 is only used in revison B and upwards */
+enum linktype {
+	link10BaseT = 0x00,
+	linkAUI = 0x01,
+	link10Base2 = 0x03,
+	link100BaseFX = 0x05,
+	linkMII = 0x06,
+	linkAutoneg = 0x08,
+	linkExternalMII = 0x09,
+};
+
+/* Values for int status register bitmask */
+#define	INT_INTERRUPTLATCH	(1<<0)
+#define INT_HOSTERROR		(1<<1)
+#define INT_TXCOMPLETE		(1<<2)
+#define INT_RXCOMPLETE		(1<<4)
+#define INT_RXEARLY		(1<<5)
+#define INT_INTREQUESTED	(1<<6)
+#define INT_UPDATESTATS		(1<<7)
+#define INT_LINKEVENT		(1<<8)
+#define INT_DNCOMPLETE		(1<<9)
+#define INT_UPCOMPLETE		(1<<10)
+#define INT_CMDINPROGRESS	(1<<12)
+#define INT_WINDOWNUMBER	(7<<13)
+
+/* Buffer sizes */
+#define TX_RING_SIZE 8
+#define RX_RING_SIZE 8
+#define TX_RING_ALIGN 16
+#define RX_RING_ALIGN 16
+#define RX_BUF_SIZE 1536
+
+/* Timeouts for eeprom and command completion */
+/* Timeout 1 second, to be save */
+#define EEPROM_TIMEOUT		1 * 1000 * 1000
+
+/* TX descriptor */
+struct TXD {
+	volatile unsigned int DnNextPtr;
+	volatile unsigned int FrameStartHeader;
+	volatile unsigned int DataAddr;
+	volatile unsigned int DataLength;
+} __attribute__ ((aligned(8)));	/* 64-bit aligned for bus mastering */
+
+/* RX descriptor */
+struct RXD {
+	volatile unsigned int UpNextPtr;
+	volatile unsigned int UpPktStatus;
+	volatile unsigned int DataAddr;
+	volatile unsigned int DataLength;
+} __attribute__ ((aligned(8)));	/* 64-bit aligned for bus mastering */
+
+/* Private NIC dats */
+struct INF_3C90X {
+	unsigned int is3c556;
+	unsigned char isBrev;
+	unsigned char CurrentWindow;
+	unsigned int IOAddr;
+	unsigned short eeprom[0x21];
+	unsigned int tx_cur;	/* current entry in tx_ring */
+	unsigned int tx_cnt;	/* current number of used tx descriptors */
+	unsigned int tx_tail;	/* entry of last finished packet */
+	unsigned int rx_cur;
+	struct TXD *tx_ring;
+	struct RXD *rx_ring;
+	struct io_buffer *tx_iobuf[TX_RING_SIZE];
+	struct io_buffer *rx_iobuf[RX_RING_SIZE];
+	struct nvs_device nvs;
+};
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.c
new file mode 100644
index 0000000..476d530
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.c
@@ -0,0 +1,693 @@
+/* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2004 Advanced Micro Devices 
+ * Copyright (C) 2005 Liu Tao <liutao1980 at gmail.com> [etherboot port]
+ * 
+ * Copyright 2001,2002 Jeff Garzik <jgarzik at mandrakesoft.com> [ 8139cp.c,tg3.c ]
+ * Copyright (C) 2001, 2002 David S. Miller (davem at redhat.com)[ tg3.c]
+ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
+ * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ *	Director, National Security Agency.[ pcnet32.c ]
+ * Carsten Langgaard, carstenl at mips.com [ pcnet32.c ]
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * USA
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "etherboot.h"
+#include "nic.h"
+#include "mii.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include "string.h"
+#include "stdint.h"
+#include "amd8111e.h"
+
+
+/* driver definitions */
+#define NUM_TX_SLOTS	2
+#define NUM_RX_SLOTS	4
+#define TX_SLOTS_MASK	1
+#define RX_SLOTS_MASK	3
+
+#define TX_BUF_LEN	1536
+#define RX_BUF_LEN	1536
+
+#define TX_PKT_LEN_MAX	(ETH_FRAME_LEN - ETH_HLEN)
+#define RX_PKT_LEN_MIN	60
+#define RX_PKT_LEN_MAX	ETH_FRAME_LEN
+
+#define TX_TIMEOUT	3000
+#define TX_PROCESS_TIME	10
+#define TX_RETRY	(TX_TIMEOUT / TX_PROCESS_TIME)
+
+#define PHY_RW_RETRY	10
+
+
+struct amd8111e_tx_desc {
+	u16 buf_len;
+	u16 tx_flags;
+	u16 tag_ctrl_info;
+	u16 tag_ctrl_cmd;
+	u32 buf_phy_addr;
+	u32 reserved;
+}; 
+
+struct amd8111e_rx_desc {
+	u32 reserved;
+	u16 msg_len;
+	u16 tag_ctrl_info; 
+	u16 buf_len;
+	u16 rx_flags;
+	u32 buf_phy_addr;
+};
+
+struct eth_frame {
+	u8 dst_addr[ETH_ALEN];
+	u8 src_addr[ETH_ALEN];
+	u16 type;
+	u8 data[ETH_FRAME_LEN - ETH_HLEN];
+} __attribute__((packed));
+
+struct amd8111e_priv {
+	struct amd8111e_tx_desc tx_ring[NUM_TX_SLOTS];
+	struct amd8111e_rx_desc rx_ring[NUM_RX_SLOTS];
+	unsigned char tx_buf[NUM_TX_SLOTS][TX_BUF_LEN];
+	unsigned char rx_buf[NUM_RX_SLOTS][RX_BUF_LEN];
+	unsigned long tx_idx, rx_idx;
+	int tx_consistent;
+
+	char opened;
+	char link;
+	char speed;
+	char duplex;
+	int ext_phy_addr;
+	u32 ext_phy_id;
+
+	struct pci_device *pdev;
+	struct nic *nic;
+	void *mmio;
+};
+
+static struct amd8111e_priv amd8111e;
+
+
+/********************************************************
+ * 		locale functions			*
+ ********************************************************/
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp);
+static int amd8111e_start(struct amd8111e_priv *lp);
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val);
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val);
+#endif
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp);
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp);
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp);
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp);
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp);
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index);
+static void amd8111e_wait_link(struct amd8111e_priv *lp);
+static void amd8111e_poll_link(struct amd8111e_priv *lp);
+static void amd8111e_restart(struct amd8111e_priv *lp);
+
+
+/* 
+ * This function clears necessary the device registers. 
+ */	
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp)
+{
+	unsigned int reg_val;
+	void *mmio = lp->mmio;
+
+        /* stop the chip */
+	writel(RUN, mmio + CMD0);
+
+	/* Clear RCV_RING_BASE_ADDR */
+	writel(0, mmio + RCV_RING_BASE_ADDR0);
+
+	/* Clear XMT_RING_BASE_ADDR */
+	writel(0, mmio + XMT_RING_BASE_ADDR0);
+	writel(0, mmio + XMT_RING_BASE_ADDR1);
+	writel(0, mmio + XMT_RING_BASE_ADDR2);
+	writel(0, mmio + XMT_RING_BASE_ADDR3);
+
+	/* Clear CMD0  */
+	writel(CMD0_CLEAR, mmio + CMD0);
+	
+	/* Clear CMD2 */
+	writel(CMD2_CLEAR, mmio + CMD2);
+
+	/* Clear CMD7 */
+	writel(CMD7_CLEAR, mmio + CMD7);
+
+	/* Clear DLY_INT_A and DLY_INT_B */
+	writel(0x0, mmio + DLY_INT_A);
+	writel(0x0, mmio + DLY_INT_B);
+
+	/* Clear FLOW_CONTROL */
+	writel(0x0, mmio + FLOW_CONTROL);
+
+	/* Clear INT0  write 1 to clear register */
+	reg_val = readl(mmio + INT0);
+	writel(reg_val, mmio + INT0);
+
+	/* Clear STVAL */
+	writel(0x0, mmio + STVAL);
+
+	/* Clear INTEN0 */
+	writel(INTEN0_CLEAR, mmio + INTEN0);
+
+	/* Clear LADRF */
+	writel(0x0, mmio + LADRF);
+
+	/* Set SRAM_SIZE & SRAM_BOUNDARY registers  */
+	writel(0x80010, mmio + SRAM_SIZE);
+
+	/* Clear RCV_RING0_LEN */
+	writel(0x0, mmio +  RCV_RING_LEN0);
+
+	/* Clear XMT_RING0/1/2/3_LEN */
+	writel(0x0, mmio +  XMT_RING_LEN0);
+	writel(0x0, mmio +  XMT_RING_LEN1);
+	writel(0x0, mmio +  XMT_RING_LEN2);
+	writel(0x0, mmio +  XMT_RING_LEN3);
+
+	/* Clear XMT_RING_LIMIT */
+	writel(0x0, mmio + XMT_RING_LIMIT);
+
+	/* Clear MIB */
+	writew(MIB_CLEAR, mmio + MIB_ADDR);
+
+	/* Clear LARF */
+	writel( 0, mmio + LADRF);
+	writel( 0, mmio + LADRF + 4);
+
+	/* SRAM_SIZE register */
+	reg_val = readl(mmio + SRAM_SIZE);
+	
+	/* Set default value to CTRL1 Register */
+	writel(CTRL1_DEFAULT, mmio + CTRL1);
+
+	/* To avoid PCI posting bug */
+	readl(mmio + CMD2);
+}
+
+/* 
+ * This function initializes the device registers  and starts the device.  
+ */
+static int amd8111e_start(struct amd8111e_priv *lp)
+{
+	struct nic *nic = lp->nic;
+	void *mmio = lp->mmio;
+	int i, reg_val;
+
+	/* stop the chip */
+	writel(RUN, mmio + CMD0);
+
+	/* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
+	writew(0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
+
+	/* enable the port manager and set auto negotiation always */
+	writel(VAL1 | EN_PMGR, mmio + CMD3 );
+	writel(XPHYANE | XPHYRST, mmio + CTRL2); 
+
+	/* set control registers */
+	reg_val = readl(mmio + CTRL1);
+	reg_val &= ~XMTSP_MASK;
+	writel(reg_val | XMTSP_128 | CACHE_ALIGN, mmio + CTRL1);
+
+	/* initialize tx and rx ring base addresses */
+	amd8111e_init_tx_ring(lp);
+	amd8111e_init_rx_ring(lp);
+	writel(virt_to_bus(lp->tx_ring), mmio + XMT_RING_BASE_ADDR0);
+	writel(virt_to_bus(lp->rx_ring), mmio + RCV_RING_BASE_ADDR0);
+	writew(NUM_TX_SLOTS, mmio + XMT_RING_LEN0);
+	writew(NUM_RX_SLOTS, mmio + RCV_RING_LEN0);
+	
+	/* set default IPG to 96 */
+	writew(DEFAULT_IPG, mmio + IPG);
+	writew(DEFAULT_IPG - IFS1_DELTA, mmio + IFS1); 
+
+	/* AutoPAD transmit, Retransmit on Underflow */
+	writel(VAL0 | APAD_XMT | REX_RTRY | REX_UFLO, mmio + CMD2);
+	
+	/* JUMBO disabled */
+	writel(JUMBO, mmio + CMD3);
+
+	/* Setting the MAC address to the device */
+	for(i = 0; i < ETH_ALEN; i++)
+		writeb(nic->node_addr[i], mmio + PADR + i); 
+
+	/* set RUN bit to start the chip, interrupt not enabled */
+	writel(VAL2 | RDMD0 | VAL0 | RUN, mmio + CMD0);
+	
+	/* To avoid PCI posting bug */
+	readl(mmio + CMD0);
+	return 0;
+}
+
+/* 
+This function will read the PHY registers.
+*/
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val)
+{
+	void *mmio = lp->mmio;
+	unsigned int reg_val;
+	unsigned int retry = PHY_RW_RETRY;
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl(mmio + PHY_ACCESS);
+
+	writel(PHY_RD_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16),
+		mmio + PHY_ACCESS);
+	do {
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write data */
+	} while (--retry && (reg_val & PHY_CMD_ACTIVE));
+
+	if (reg_val & PHY_RD_ERR) {
+		*val = 0;
+		return -1;
+	}
+	
+	*val = reg_val & 0xffff;
+	return 0;
+}
+
+/* 
+This function will write into PHY registers. 
+*/
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val)
+{
+	void *mmio = lp->mmio;
+	unsigned int reg_val;
+	unsigned int retry = PHY_RW_RETRY;
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl(mmio + PHY_ACCESS);
+
+	writel(PHY_WR_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16) | val,
+		mmio + PHY_ACCESS);
+	do {
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write the data */
+	} while (--retry && (reg_val & PHY_CMD_ACTIVE));
+	
+	if(reg_val & PHY_RD_ERR)
+		return -1;
+
+	return 0;
+}
+#endif
+
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp)
+{
+	int i;
+
+	lp->ext_phy_id = 0;
+	lp->ext_phy_addr = 1;
+	
+	for (i = 0x1e; i >= 0; i--) {
+		u32 id1, id2;
+
+		if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
+			continue;
+		if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
+			continue;
+		lp->ext_phy_id = (id1 << 16) | id2;
+		lp->ext_phy_addr = i;
+		break;
+	}
+
+	if (lp->ext_phy_id)
+		printf("Found MII PHY ID 0x%08x at address 0x%02x\n",
+		       (unsigned int) lp->ext_phy_id, lp->ext_phy_addr);
+	else
+		printf("Couldn't detect MII PHY, assuming address 0x01\n");
+}
+
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp)
+{
+	void *mmio = lp->mmio;
+	unsigned int int0;
+
+	writel(INTREN, mmio + CMD0);
+	writel(INTEN0_CLEAR, mmio + INTEN0);
+	int0 = readl(mmio + INT0);
+	writel(int0, mmio + INT0);
+	readl(mmio + INT0);
+}
+
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp)
+{
+	void *mmio = lp->mmio;
+
+	writel(VAL3 | LCINTEN | VAL1 | TINTEN0 | VAL0 | RINTEN0, mmio + INTEN0);
+	writel(VAL0 | INTREN, mmio + CMD0);
+	readl(mmio + CMD0);
+}
+
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp)
+{
+	void *mmio = lp->mmio;
+
+	writel(VAL0 | UINTCMD, mmio + CMD0);
+	readl(mmio + CMD0);
+}
+
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp)
+{
+	struct nic *nic = lp->nic;
+	void *mmio = lp->mmio;
+	int i;
+
+	/* BIOS should have set mac address to PADR register,
+	 * so we read PADR to get it.
+	 */
+	for (i = 0; i < ETH_ALEN; i++)
+		nic->node_addr[i] = readb(mmio + PADR + i);
+
+	DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
+
+	return 0;
+}
+
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp)
+{
+	int i;
+
+	lp->rx_idx = 0;
+	
+        /* Initilaizing receive descriptors */
+	for (i = 0; i < NUM_RX_SLOTS; i++) {
+		lp->rx_ring[i].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[i]));
+		lp->rx_ring[i].buf_len = cpu_to_le16(RX_BUF_LEN);
+		wmb();
+		lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
+	}
+
+	return 0;
+}
+
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp)
+{
+	int i;
+
+	lp->tx_idx = 0;
+	lp->tx_consistent = 1;
+	
+	/* Initializing transmit descriptors */
+	for (i = 0; i < NUM_TX_SLOTS; i++) {
+		lp->tx_ring[i].tx_flags = 0;
+		lp->tx_ring[i].buf_phy_addr = 0;
+		lp->tx_ring[i].buf_len = 0;
+	}
+
+	return 0;
+}
+
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index)
+{
+	volatile u16 status;
+	int retry = TX_RETRY;
+
+	status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+	while (--retry && (status & OWN_BIT)) {
+		mdelay(TX_PROCESS_TIME);
+		status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+	}
+	if (status & OWN_BIT) {
+		printf("Error: tx slot %d timeout, stat = 0x%x\n", index, status);
+		amd8111e_restart(lp);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void amd8111e_wait_link(struct amd8111e_priv *lp)
+{
+	unsigned int status;
+	u32 reg_val;
+
+	do {
+		/* read phy to update STAT0 register */
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+		status = readl(lp->mmio + STAT0);
+	} while (!(status & AUTONEG_COMPLETE) || !(status & LINK_STATS));
+}
+
+static void amd8111e_poll_link(struct amd8111e_priv *lp)
+{
+	unsigned int status, speed;
+	u32 reg_val;
+
+	if (!lp->link) {
+		/* read phy to update STAT0 register */
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+		amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+		status = readl(lp->mmio + STAT0);
+
+		if (status & LINK_STATS) {
+			lp->link = 1;
+			speed = (status & SPEED_MASK) >> 7;
+			if (speed == PHY_SPEED_100)
+				lp->speed = 1;
+			else
+				lp->speed = 0;
+			if (status & FULL_DPLX)
+				lp->duplex = 1;
+			else
+				lp->duplex = 0;
+
+			printf("Link is up: %s Mbps %s duplex\n",
+				lp->speed ? "100" : "10", lp->duplex ? "full" : "half");
+		}
+	} else {
+		status = readl(lp->mmio + STAT0);
+		if (!(status & LINK_STATS)) {
+			lp->link = 0;
+			printf("Link is down\n");
+		}
+	}
+}
+
+static void amd8111e_restart(struct amd8111e_priv *lp)
+{
+	printf("\nStarting nic...\n");
+	amd8111e_disable_interrupt(lp);
+	amd8111e_init_hw_default(lp);
+	amd8111e_probe_ext_phy(lp);
+	amd8111e_get_mac_address(lp);
+	amd8111e_start(lp);
+
+	printf("Waiting link up...\n");
+	lp->link = 0;
+	amd8111e_wait_link(lp);
+	amd8111e_poll_link(lp);
+}
+
+
+/********************************************************
+ * 		Interface Functions			*
+ ********************************************************/
+
+static void amd8111e_transmit(struct nic *nic, const char *dst_addr,
+		unsigned int type, unsigned int size, const char *packet)
+{
+	struct amd8111e_priv *lp = nic->priv_data;
+	struct eth_frame *frame;
+	unsigned int index;
+
+	/* check packet size */
+	if (size > TX_PKT_LEN_MAX) {
+		printf("amd8111e_transmit(): too large packet, drop\n");
+		return;
+	}
+
+	/* get tx slot */
+	index = lp->tx_idx;
+	if (amd8111e_wait_tx_ring(lp, index))
+		return;
+
+	/* fill frame */
+	frame = (struct eth_frame *)lp->tx_buf[index];
+	memset(frame->data, 0, TX_PKT_LEN_MAX);
+	memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
+	memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
+	frame->type = htons(type);
+	memcpy(frame->data, packet, size);
+
+	/* start xmit */
+	lp->tx_ring[index].buf_len = cpu_to_le16(ETH_HLEN + size);
+	lp->tx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(frame));
+	wmb();
+	lp->tx_ring[index].tx_flags = 
+		cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT | ADD_FCS_BIT | LTINT_BIT);
+	writel(VAL1 | TDMD0, lp->mmio + CMD0);
+	readl(lp->mmio + CMD0);
+
+	/* update slot pointer */
+	lp->tx_idx = (lp->tx_idx + 1) & TX_SLOTS_MASK;
+}
+
+static int amd8111e_poll(struct nic *nic, int retrieve)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+
+	struct amd8111e_priv *lp = nic->priv_data;
+	u16 status, pkt_len;
+	unsigned int index, pkt_ok;
+
+	amd8111e_poll_link(lp);
+
+	index = lp->rx_idx;
+	status = le16_to_cpu(lp->rx_ring[index].rx_flags);
+	pkt_len = le16_to_cpu(lp->rx_ring[index].msg_len) - 4;	/* remove 4bytes FCS */
+	
+	if (status & OWN_BIT)
+		return 0;
+
+	if (status & ERR_BIT)
+		pkt_ok = 0;
+	else if (!(status & STP_BIT))
+		pkt_ok = 0;
+	else if (!(status & ENP_BIT))
+		pkt_ok = 0;
+	else if (pkt_len < RX_PKT_LEN_MIN)
+		pkt_ok = 0;
+	else if (pkt_len > RX_PKT_LEN_MAX)
+		pkt_ok = 0;
+	else
+		pkt_ok = 1;
+
+	if (pkt_ok) {
+		if (!retrieve)
+			return 1;
+		nic->packetlen = pkt_len;
+		memcpy(nic->packet, lp->rx_buf[index], nic->packetlen);
+	}
+
+	lp->rx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[index]));
+	lp->rx_ring[index].buf_len = cpu_to_le16(RX_BUF_LEN);
+	wmb();
+	lp->rx_ring[index].rx_flags = cpu_to_le16(OWN_BIT);
+	writel(VAL2 | RDMD0, lp->mmio + CMD0);
+	readl(lp->mmio + CMD0);
+
+	lp->rx_idx = (lp->rx_idx + 1) & RX_SLOTS_MASK;
+	return pkt_ok;
+}
+
+static void amd8111e_disable(struct nic *nic)
+{
+	struct amd8111e_priv *lp = nic->priv_data;
+
+	/* disable interrupt */
+	amd8111e_disable_interrupt(lp);
+
+	/* stop chip */
+	amd8111e_init_hw_default(lp);
+
+	/* unmap mmio */
+	iounmap(lp->mmio);
+
+	/* update status */
+	lp->opened = 0;
+}
+
+static void amd8111e_irq(struct nic *nic, irq_action_t action)
+{
+	struct amd8111e_priv *lp = nic->priv_data;
+		
+	switch (action) {
+	case DISABLE:
+		amd8111e_disable_interrupt(lp);
+		break;
+	case ENABLE:
+		amd8111e_enable_interrupt(lp);
+		break;
+	case FORCE:
+		amd8111e_force_interrupt(lp);
+		break;
+	}
+}
+
+static struct nic_operations amd8111e_operations = {
+	.connect	= dummy_connect,
+	.poll		= amd8111e_poll,
+	.transmit	= amd8111e_transmit,
+	.irq		= amd8111e_irq,
+};
+
+static int amd8111e_probe(struct nic *nic, struct pci_device *pdev)
+{
+	struct amd8111e_priv *lp = &amd8111e;
+	unsigned long mmio_start, mmio_len;
+
+        nic->ioaddr = pdev->ioaddr;
+        nic->irqno  = pdev->irq;
+	
+	mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
+
+	memset(lp, 0, sizeof(*lp));
+	lp->pdev = pdev;
+	lp->nic = nic;
+	lp->mmio = ioremap(mmio_start, mmio_len);
+	lp->opened = 1;
+	adjust_pci_device(pdev);
+
+	nic->priv_data = lp;
+
+	amd8111e_restart(lp);
+
+	nic->nic_op	= &amd8111e_operations;
+	return 1;
+}
+
+static struct pci_device_id amd8111e_nics[] = {
+	PCI_ROM(0x1022, 0x7462, "amd8111e",	"AMD8111E", 0),
+};
+
+PCI_DRIVER ( amd8111e_driver, amd8111e_nics, PCI_NO_CLASS );
+
+DRIVER ( "AMD8111E", nic_driver, pci_driver, amd8111e_driver,
+	 amd8111e_probe, amd8111e_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.h
new file mode 100644
index 0000000..a402a63
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/amd8111e.h
@@ -0,0 +1,631 @@
+/*
+ * Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2003 Advanced Micro Devices 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * USA
+
+Module Name:
+
+    amd8111e.h
+
+Abstract:
+	
+ 	 AMD8111 based 10/100 Ethernet Controller driver definitions. 
+
+Environment:
+    
+	Kernel Mode
+
+Revision History:
+ 	3.0.0
+	   Initial Revision.
+	3.0.1
+*/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _AMD811E_H
+#define _AMD811E_H
+
+/* Command style register access
+
+Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the  value bit that specifies the value that will be written into the selected bits of register. 
+
+eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
+
+*/
+
+/*  Offset for Memory Mapped Registers. */
+/* 32 bit registers */
+
+#define  ASF_STAT		0x00	/* ASF status register */
+#define CHIPID			0x04	/* Chip ID regsiter */
+#define	MIB_DATA		0x10	/* MIB data register */
+#define MIB_ADDR		0x14	/* MIB address register */
+#define STAT0			0x30	/* Status0 register */
+#define INT0			0x38	/* Interrupt0 register */
+#define INTEN0			0x40	/* Interrupt0  enable register*/
+#define CMD0			0x48	/* Command0 register */
+#define CMD2			0x50	/* Command2 register */
+#define CMD3			0x54	/* Command3 resiter */
+#define CMD7			0x64	/* Command7 register */
+
+#define CTRL1 			0x6C	/* Control1 register */
+#define CTRL2 			0x70	/* Control2 register */
+
+#define XMT_RING_LIMIT		0x7C	/* Transmit ring limit register */
+
+#define AUTOPOLL0		0x88	/* Auto-poll0 register */
+#define AUTOPOLL1		0x8A	/* Auto-poll1 register */
+#define AUTOPOLL2		0x8C	/* Auto-poll2 register */
+#define AUTOPOLL3		0x8E	/* Auto-poll3 register */
+#define AUTOPOLL4		0x90	/* Auto-poll4 register */
+#define	AUTOPOLL5		0x92	/* Auto-poll5 register */
+
+#define AP_VALUE		0x98	/* Auto-poll value register */
+#define DLY_INT_A		0xA8	/* Group A delayed interrupt register */
+#define DLY_INT_B		0xAC	/* Group B delayed interrupt register */
+
+#define FLOW_CONTROL		0xC8	/* Flow control register */
+#define PHY_ACCESS		0xD0	/* PHY access register */
+
+#define STVAL			0xD8	/* Software timer value register */
+
+#define XMT_RING_BASE_ADDR0	0x100	/* Transmit ring0 base addr register */
+#define XMT_RING_BASE_ADDR1	0x108	/* Transmit ring1 base addr register */
+#define XMT_RING_BASE_ADDR2	0x110	/* Transmit ring2 base addr register */
+#define XMT_RING_BASE_ADDR3	0x118	/* Transmit ring2 base addr register */
+
+#define RCV_RING_BASE_ADDR0	0x120	/* Transmit ring0 base addr register */
+
+#define PMAT0			0x190	/* OnNow pattern register0 */
+#define PMAT1			0x194	/* OnNow pattern register1 */
+
+/* 16bit registers */
+
+#define XMT_RING_LEN0		0x140	/* Transmit Ring0 length register */
+#define XMT_RING_LEN1		0x144	/* Transmit Ring1 length register */
+#define XMT_RING_LEN2		0x148 	/* Transmit Ring2 length register */
+#define XMT_RING_LEN3		0x14C	/* Transmit Ring3 length register */
+
+#define RCV_RING_LEN0		0x150	/* Receive Ring0 length register */
+
+#define SRAM_SIZE		0x178	/* SRAM size register */
+#define SRAM_BOUNDARY		0x17A	/* SRAM boundary register */
+
+/* 48bit register */
+
+#define PADR			0x160	/* Physical address register */
+
+#define IFS1			0x18C	/* Inter-frame spacing Part1 register */
+#define IFS			0x18D	/* Inter-frame spacing register */
+#define IPG			0x18E	/* Inter-frame gap register */
+/* 64bit register */
+
+#define LADRF			0x168	/* Logical address filter register */
+
+
+/* Register Bit Definitions */
+typedef enum {
+
+	ASF_INIT_DONE		= (1 << 1),
+	ASF_INIT_PRESENT	= (1 << 0),
+
+}STAT_ASF_BITS; 
+   
+typedef enum {
+
+	MIB_CMD_ACTIVE		= (1 << 15 ),
+	MIB_RD_CMD		= (1 << 13 ),
+	MIB_CLEAR		= (1 << 12 ),
+	MIB_ADDRESS		= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
+					(1 << 4) | (1 << 5),
+}MIB_ADDR_BITS;
+
+
+typedef enum {
+	
+	PMAT_DET		= (1 << 12),
+	MP_DET		        = (1 << 11),
+	LC_DET			= (1 << 10),
+	SPEED_MASK		= (1 << 9)|(1 << 8)|(1 << 7),
+	FULL_DPLX		= (1 << 6),
+	LINK_STATS		= (1 << 5),
+	AUTONEG_COMPLETE	= (1 << 4),
+	MIIPD			= (1 << 3),
+	RX_SUSPENDED		= (1 << 2),
+	TX_SUSPENDED		= (1 << 1),
+	RUNNING			= (1 << 0),
+
+}STAT0_BITS;
+
+#define PHY_SPEED_10		0x2
+#define PHY_SPEED_100		0x3
+
+/* INT0				0x38, 32bit register */
+typedef enum {
+
+	INTR			= (1 << 31),
+	PCSINT			= (1 << 28), 
+	LCINT			= (1 << 27),
+	APINT5			= (1 << 26),
+	APINT4			= (1 << 25),
+	APINT3			= (1 << 24),
+	TINT_SUM		= (1 << 23),
+	APINT2			= (1 << 22),
+	APINT1			= (1 << 21),
+	APINT0			= (1 << 20),
+	MIIPDTINT		= (1 << 19),
+	MCCINT			= (1 << 17),
+	MREINT			= (1 << 16),
+	RINT_SUM		= (1 << 15),
+	SPNDINT			= (1 << 14),
+	MPINT			= (1 << 13),
+	SINT			= (1 << 12),
+	TINT3			= (1 << 11),
+	TINT2			= (1 << 10),
+	TINT1			= (1 << 9),
+	TINT0			= (1 << 8),
+	UINT			= (1 << 7),
+	STINT			= (1 << 4),
+	RINT0			= (1 << 0),
+
+}INT0_BITS;
+
+typedef enum {
+
+	VAL3			= (1 << 31),   /* VAL bit for byte 3 */
+	VAL2			= (1 << 23),   /* VAL bit for byte 2 */
+	VAL1			= (1 << 15),   /* VAL bit for byte 1 */
+	VAL0			= (1 << 7),    /* VAL bit for byte 0 */
+
+}VAL_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	LCINTEN			= (1 << 27),
+	APINT5EN		= (1 << 26),
+	APINT4EN		= (1 << 25),
+	APINT3EN		= (1 << 24),
+	/* VAL2 */
+	APINT2EN		= (1 << 22),
+	APINT1EN		= (1 << 21),
+	APINT0EN		= (1 << 20),
+	MIIPDTINTEN		= (1 << 19),
+	MCCIINTEN		= (1 << 18),
+	MCCINTEN		= (1 << 17),
+	MREINTEN		= (1 << 16),
+	/* VAL1 */
+	SPNDINTEN		= (1 << 14),
+	MPINTEN			= (1 << 13),
+	TINTEN3			= (1 << 11),
+	SINTEN			= (1 << 12),
+	TINTEN2			= (1 << 10),
+	TINTEN1			= (1 << 9),
+	TINTEN0			= (1 << 8),
+	/* VAL0 */
+	STINTEN			= (1 << 4),
+	RINTEN0			= (1 << 0),
+
+	INTEN0_CLEAR 		= 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;		
+
+typedef enum {
+	/* VAL2 */
+	RDMD0			= (1 << 16),
+	/* VAL1 */
+	TDMD3			= (1 << 11),
+	TDMD2			= (1 << 10),
+	TDMD1			= (1 << 9),
+	TDMD0			= (1 << 8),
+	/* VAL0 */
+	UINTCMD			= (1 << 6),
+	RX_FAST_SPND		= (1 << 5),
+	TX_FAST_SPND		= (1 << 4),
+	RX_SPND			= (1 << 3),
+	TX_SPND			= (1 << 2),
+	INTREN			= (1 << 1),
+	RUN			= (1 << 0),
+
+	CMD0_CLEAR 		= 0x000F0F7F,   /* Command style register */	
+
+}CMD0_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	CONDUIT_MODE		= (1 << 29),
+	/* VAL2 */
+	RPA			= (1 << 19),
+	DRCVPA			= (1 << 18),
+	DRCVBC			= (1 << 17),
+	PROM			= (1 << 16),
+	/* VAL1 */
+	ASTRP_RCV		= (1 << 13),
+	RCV_DROP0	  	= (1 << 12),
+	EMBA			= (1 << 11),
+	DXMT2PD			= (1 << 10),
+	LTINTEN			= (1 << 9),
+	DXMTFCS			= (1 << 8),
+	/* VAL0 */
+	APAD_XMT		= (1 << 6),
+	DRTY			= (1 << 5),
+	INLOOP			= (1 << 4),
+	EXLOOP			= (1 << 3),
+	REX_RTRY		= (1 << 2),
+	REX_UFLO		= (1 << 1),
+	REX_LCOL		= (1 << 0),
+
+	CMD2_CLEAR 		= 0x3F7F3F7F,   /* Command style register */
+
+}CMD2_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	ASF_INIT_DONE_ALIAS	= (1 << 29),
+	/* VAL2 */
+	JUMBO			= (1 << 21),
+	VSIZE			= (1 << 20),	
+	VLONLY			= (1 << 19),
+	VL_TAG_DEL		= (1 << 18),	
+	/* VAL1 */
+	EN_PMGR			= (1 << 14),			
+	INTLEVEL		= (1 << 13),
+	FORCE_FULL_DUPLEX	= (1 << 12),	
+	FORCE_LINK_STATUS	= (1 << 11),	
+	APEP			= (1 << 10),	
+	MPPLBA			= (1 << 9),	
+	/* VAL0 */
+	RESET_PHY_PULSE		= (1 << 2),	
+	RESET_PHY		= (1 << 1),	
+	PHY_RST_POL		= (1 << 0),	
+
+}CMD3_BITS;
+
+
+typedef enum {
+
+	/* VAL0 */
+	PMAT_SAVE_MATCH		= (1 << 4),
+	PMAT_MODE		= (1 << 3),
+	MPEN_SW			= (1 << 1),
+	LCMODE_SW		= (1 << 0),
+
+	CMD7_CLEAR  		= 0x0000001B	/* Command style register */
+
+}CMD7_BITS;
+
+
+typedef enum {
+
+	RESET_PHY_WIDTH		= (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
+	XMTSP_MASK		= (1 << 9) | (1 << 8),	/* 9:8 */
+	XMTSP_128		= (1 << 9),	/* 9 */	
+	XMTSP_64		= (1 << 8),
+	CACHE_ALIGN		= (1 << 4),
+	BURST_LIMIT_MASK	= (0xF << 0 ),
+	CTRL1_DEFAULT		= 0x00010111,
+
+}CTRL1_BITS;
+
+typedef enum {
+
+	FMDC_MASK		= (1 << 9)|(1 << 8),	/* 9:8 */
+	XPHYRST			= (1 << 7),
+	XPHYANE			= (1 << 6),
+	XPHYFD			= (1 << 5),
+	XPHYSP			= (1 << 4) | (1 << 3),	/* 4:3 */
+	APDW_MASK		= (1 <<	2) | (1 << 1) | (1 << 0), /* 2:0 */
+
+}CTRL2_BITS;
+
+/* XMT_RING_LIMIT		0x7C, 32bit register */
+typedef enum {
+
+	XMT_RING2_LIMIT		= (0xFF << 16),	/* 23:16 */
+	XMT_RING1_LIMIT		= (0xFF << 8),	/* 15:8 */
+	XMT_RING0_LIMIT		= (0xFF << 0), 	/* 7:0 */
+
+}XMT_RING_LIMIT_BITS;
+
+typedef enum {
+
+	AP_REG0_EN		= (1 << 15),
+	AP_REG0_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PHY0_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL0_BITS;
+
+/* AUTOPOLL1			0x8A, 16bit register */
+typedef enum {
+
+	AP_REG1_EN		= (1 << 15),
+	AP_REG1_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP1		= (1 << 6),
+	AP_PHY1_DFLT		= (1 << 5),
+	AP_PHY1_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL1_BITS;
+
+
+typedef enum {
+
+	AP_REG2_EN		= (1 << 15),
+	AP_REG2_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP2		= (1 << 6),
+	AP_PHY2_DFLT		= (1 << 5),
+	AP_PHY2_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL2_BITS;
+
+typedef enum {
+
+	AP_REG3_EN		= (1 << 15),
+	AP_REG3_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP3		= (1 << 6),
+	AP_PHY3_DFLT		= (1 << 5),
+	AP_PHY3_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL3_BITS;
+
+
+typedef enum {
+
+	AP_REG4_EN		= (1 << 15),
+	AP_REG4_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP4		= (1 << 6),
+	AP_PHY4_DFLT		= (1 << 5),
+	AP_PHY4_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL4_BITS;
+
+
+typedef enum {
+
+	AP_REG5_EN		= (1 << 15),
+	AP_REG5_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP5		= (1 << 6),
+	AP_PHY5_DFLT		= (1 << 5),
+	AP_PHY5_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL5_BITS;
+
+
+
+
+/* AP_VALUE 			0x98, 32bit ragister */
+typedef enum {
+
+	AP_VAL_ACTIVE		= (1 << 31),
+	AP_VAL_RD_CMD		= ( 1 << 29),
+	AP_ADDR			= (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
+	AP_VAL			= (0xF << 0) | (0xF << 4) |( 0xF << 8) |
+				  (0xF << 12),	/* 15:0 */
+
+}AP_VALUE_BITS;
+
+typedef enum {
+
+	DLY_INT_A_R3		= (1 << 31),
+	DLY_INT_A_R2		= (1 << 30),
+	DLY_INT_A_R1		= (1 << 29),
+	DLY_INT_A_R0		= (1 << 28),
+	DLY_INT_A_T3		= (1 << 27),
+	DLY_INT_A_T2		= (1 << 26),
+	DLY_INT_A_T1		= (1 << 25),
+	DLY_INT_A_T0		= ( 1 << 24),
+	EVENT_COUNT_A		= (0xF << 16) | (0x1 << 20),/* 20:16 */
+	MAX_DELAY_TIME_A	= (0xF << 0) | (0xF << 4) | (1 << 8)|
+				  (1 << 9) | (1 << 10),	/* 10:0 */
+
+}DLY_INT_A_BITS;
+
+typedef enum {
+
+	DLY_INT_B_R3		= (1 << 31),
+	DLY_INT_B_R2		= (1 << 30),
+	DLY_INT_B_R1		= (1 << 29),
+	DLY_INT_B_R0		= (1 << 28),
+	DLY_INT_B_T3		= (1 << 27),
+	DLY_INT_B_T2		= (1 << 26),
+	DLY_INT_B_T1		= (1 << 25),
+	DLY_INT_B_T0		= ( 1 << 24),
+	EVENT_COUNT_B		= (0xF << 16) | (0x1 << 20),/* 20:16 */
+	MAX_DELAY_TIME_B	= (0xF << 0) | (0xF << 4) | (1 << 8)| 
+				  (1 << 9) | (1 << 10),	/* 10:0 */
+}DLY_INT_B_BITS;
+
+
+/* FLOW_CONTROL 		0xC8, 32bit register */
+typedef enum {
+
+	PAUSE_LEN_CHG		= (1 << 30),
+	FTPE			= (1 << 22),
+	FRPE			= (1 << 21),
+	NAPA			= (1 << 20),
+	NPA			= (1 << 19),
+	FIXP			= ( 1 << 18),
+	FCCMD			= ( 1 << 16),
+	PAUSE_LEN		= (0xF << 0) | (0xF << 4) |( 0xF << 8) |	 				  (0xF << 12),	/* 15:0 */
+
+}FLOW_CONTROL_BITS;
+
+/* PHY_ ACCESS			0xD0, 32bit register */
+typedef enum {
+
+	PHY_CMD_ACTIVE		= (1 << 31),
+	PHY_WR_CMD		= (1 << 30),
+	PHY_RD_CMD		= (1 << 29),
+	PHY_RD_ERR		= (1 << 28),
+	PHY_PRE_SUP		= (1 << 27),
+	PHY_ADDR		= (1 << 21) | (1 << 22) | (1 << 23)|
+				  	(1 << 24) |(1 << 25),/* 25:21 */
+	PHY_REG_ADDR		= (1 << 16) | (1 << 17) | (1 << 18)|	 			  	   	  	(1 << 19) | (1 << 20),/* 20:16 */
+	PHY_DATA		= (0xF << 0)|(0xF << 4) |(0xF << 8)|
+					(0xF << 12),/* 15:0 */
+
+}PHY_ACCESS_BITS;
+
+
+/* PMAT0			0x190,	 32bit register */
+typedef enum {
+	PMR_ACTIVE		= (1 << 31),
+	PMR_WR_CMD		= (1 << 30),
+	PMR_RD_CMD		= (1 << 29),
+	PMR_BANK		= (1 <<28),
+	PMR_ADDR		= (0xF << 16)|(1 << 20)|(1 << 21)|
+				  	(1 << 22),/* 22:16 */
+	PMR_B4			= (0xF << 0) | (0xF << 4),/* 15:0 */
+}PMAT0_BITS;
+
+
+/* PMAT1			0x194,	 32bit register */
+typedef enum {
+	PMR_B3			= (0xF << 24) | (0xF <<28),/* 31:24 */
+	PMR_B2			= (0xF << 16) |(0xF << 20),/* 23:16 */
+	PMR_B1			= (0xF << 8) | (0xF <<12), /* 15:8 */
+	PMR_B0			= (0xF << 0)|(0xF << 4),/* 7:0 */
+}PMAT1_BITS;
+
+/************************************************************************/
+/*                                                                      */
+/*                      MIB counter definitions                         */
+/*                                                                      */
+/************************************************************************/
+
+#define rcv_miss_pkts				0x00
+#define rcv_octets				0x01
+#define rcv_broadcast_pkts			0x02
+#define rcv_multicast_pkts			0x03
+#define rcv_undersize_pkts			0x04
+#define rcv_oversize_pkts			0x05
+#define rcv_fragments				0x06
+#define rcv_jabbers				0x07
+#define rcv_unicast_pkts			0x08
+#define rcv_alignment_errors			0x09
+#define rcv_fcs_errors				0x0A
+#define rcv_good_octets				0x0B
+#define rcv_mac_ctrl				0x0C
+#define rcv_flow_ctrl				0x0D
+#define rcv_pkts_64_octets			0x0E
+#define rcv_pkts_65to127_octets			0x0F
+#define rcv_pkts_128to255_octets		0x10
+#define rcv_pkts_256to511_octets		0x11
+#define rcv_pkts_512to1023_octets		0x12
+#define rcv_pkts_1024to1518_octets		0x13
+#define rcv_unsupported_opcode			0x14
+#define rcv_symbol_errors			0x15
+#define rcv_drop_pkts_ring1			0x16
+#define rcv_drop_pkts_ring2			0x17
+#define rcv_drop_pkts_ring3			0x18
+#define rcv_drop_pkts_ring4			0x19
+#define rcv_jumbo_pkts				0x1A
+
+#define xmt_underrun_pkts			0x20
+#define xmt_octets				0x21
+#define xmt_packets				0x22
+#define xmt_broadcast_pkts			0x23
+#define xmt_multicast_pkts			0x24
+#define xmt_collisions				0x25
+#define xmt_unicast_pkts			0x26
+#define xmt_one_collision			0x27
+#define xmt_multiple_collision			0x28
+#define xmt_deferred_transmit			0x29
+#define xmt_late_collision			0x2A
+#define xmt_excessive_defer			0x2B
+#define xmt_loss_carrier			0x2C
+#define xmt_excessive_collision			0x2D
+#define xmt_back_pressure			0x2E
+#define xmt_flow_ctrl				0x2F
+#define xmt_pkts_64_octets			0x30
+#define xmt_pkts_65to127_octets			0x31
+#define xmt_pkts_128to255_octets		0x32
+#define xmt_pkts_256to511_octets		0x33
+#define xmt_pkts_512to1023_octets		0x34
+#define xmt_pkts_1024to1518_octet		0x35
+#define xmt_oversize_pkts			0x36
+#define xmt_jumbo_pkts				0x37
+
+/* ipg parameters */
+#define DEFAULT_IPG			0x60
+#define IFS1_DELTA			36
+#define	IPG_CONVERGE_JIFFIES (HZ/2)
+#define	IPG_STABLE_TIME	5
+#define	MIN_IPG	96
+#define	MAX_IPG	255
+#define IPG_STEP	16
+#define CSTATE  1 
+#define SSTATE  2 
+
+/* amd8111e decriptor flag definitions */
+typedef enum {
+
+	OWN_BIT		=	(1 << 15),
+	ADD_FCS_BIT	=	(1 << 13),
+	LTINT_BIT	=	(1 << 12),
+	STP_BIT		=	(1 << 9),
+	ENP_BIT		=	(1 << 8),
+	KILL_BIT	= 	(1 << 6),
+	TCC_VLAN_INSERT	=	(1 << 1),
+	TCC_VLAN_REPLACE =	(1 << 1) |( 1<< 0),
+
+}TX_FLAG_BITS;
+
+typedef enum {
+	ERR_BIT 	=	(1 << 14),
+	FRAM_BIT	=  	(1 << 13),
+	OFLO_BIT	=       (1 << 12),
+	CRC_BIT		=	(1 << 11),
+	PAM_BIT		=	(1 << 6),
+	LAFM_BIT	= 	(1 << 5),
+	BAM_BIT		=	(1 << 4),
+	TT_VLAN_TAGGED	= 	(1 << 3) |(1 << 2),/* 0x000 */
+	TT_PRTY_TAGGED	=	(1 << 3),/* 0x0008 */
+
+}RX_FLAG_BITS;
+
+#define RESET_RX_FLAGS		0x0000
+#define TT_MASK			0x000c
+#define TCC_MASK		0x0003
+
+/* driver ioctl parameters */
+#define AMD8111E_REG_DUMP_LEN	 13*sizeof(u32) 
+
+/* crc generator constants */
+#define CRC32 0xedb88320
+#define INITCRC 0xFFFFFFFF
+
+/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
+BUG? */
+#define  amd8111e_writeq(_UlData,_memMap)   \
+		writel(*(u32*)(&_UlData), _memMap);	\
+		writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)	
+
+/* maps the external speed options to internal value */
+typedef enum {
+	SPEED_AUTONEG,
+	SPEED10_HALF,
+	SPEED10_FULL,
+	SPEED100_HALF,
+	SPEED100_FULL,
+}EXT_PHY_OPTION;
+
+
+#endif /* _AMD8111E_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.c
new file mode 100644
index 0000000..92c4ffd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.c
@@ -0,0 +1,1698 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+FILE_LICENCE ( BSD3 );
+
+#include <stdlib.h>
+#include <ipxe/malloc.h>
+#include <ipxe/timer.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/pci_io.h>
+
+#include "base.h"
+#include "reg.h"
+
+#define ATH5K_CALIB_INTERVAL	10 /* Calibrate PHY every 10 seconds */
+#define ATH5K_RETRIES		4  /* Number of times to retry packet sends */
+#define ATH5K_DESC_ALIGN	16 /* Alignment for TX/RX descriptors */
+
+/******************\
+* Internal defines *
+\******************/
+
+/* Known PCI ids */
+static struct pci_device_id ath5k_nics[] = {
+	PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210),
+	PCI_ROM(0x168c, 0x0007, "ath5210", "Atheros 5210", AR5K_AR5210),
+	PCI_ROM(0x168c, 0x0011, "ath5311", "Atheros 5311 (AHB)", AR5K_AR5211),
+	PCI_ROM(0x168c, 0x0012, "ath5211", "Atheros 5211", AR5K_AR5211),
+	PCI_ROM(0x168c, 0x0013, "ath5212", "Atheros 5212", AR5K_AR5212),
+	PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212),
+	PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0014, "ath5212x14", "Atheros 5212 x14", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0015, "ath5212x15", "Atheros 5212 x15", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0016, "ath5212x16", "Atheros 5212 x16", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0017, "ath5212x17", "Atheros 5212 x17", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0018, "ath5212x18", "Atheros 5212 x18", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0019, "ath5212x19", "Atheros 5212 x19", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001a, "ath2413", "Atheros 2413 Griffin", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001b, "ath5413", "Atheros 5413 Eagle", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001c, "ath5212e", "Atheros 5212 PCI-E", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001d, "ath2417", "Atheros 2417 Nala", AR5K_AR5212),
+};
+
+/* Known SREVs */
+static const struct ath5k_srev_name srev_names[] = {
+	{ "5210",	AR5K_VERSION_MAC,	AR5K_SREV_AR5210 },
+	{ "5311",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311 },
+	{ "5311A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311A },
+	{ "5311B",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311B },
+	{ "5211",	AR5K_VERSION_MAC,	AR5K_SREV_AR5211 },
+	{ "5212",	AR5K_VERSION_MAC,	AR5K_SREV_AR5212 },
+	{ "5213",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213 },
+	{ "5213A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213A },
+	{ "2413",	AR5K_VERSION_MAC,	AR5K_SREV_AR2413 },
+	{ "2414",	AR5K_VERSION_MAC,	AR5K_SREV_AR2414 },
+	{ "5424",	AR5K_VERSION_MAC,	AR5K_SREV_AR5424 },
+	{ "5413",	AR5K_VERSION_MAC,	AR5K_SREV_AR5413 },
+	{ "5414",	AR5K_VERSION_MAC,	AR5K_SREV_AR5414 },
+	{ "2415",	AR5K_VERSION_MAC,	AR5K_SREV_AR2415 },
+	{ "5416",	AR5K_VERSION_MAC,	AR5K_SREV_AR5416 },
+	{ "5418",	AR5K_VERSION_MAC,	AR5K_SREV_AR5418 },
+	{ "2425",	AR5K_VERSION_MAC,	AR5K_SREV_AR2425 },
+	{ "2417",	AR5K_VERSION_MAC,	AR5K_SREV_AR2417 },
+	{ "xxxxx",	AR5K_VERSION_MAC,	AR5K_SREV_UNKNOWN },
+	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
+	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
+	{ "5111A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111A },
+	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
+	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
+	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
+	{ "5112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112B },
+	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
+	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
+	{ "2112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112B },
+	{ "2413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2413 },
+	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
+	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
+	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
+	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
+	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
+	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
+};
+
+#define ATH5K_SPMBL_NO   1
+#define ATH5K_SPMBL_YES  2
+#define ATH5K_SPMBL_BOTH 3
+
+static const struct {
+	u16 bitrate;
+	u8 short_pmbl;
+	u8 hw_code;
+} ath5k_rates[] = {
+	{ 10, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_1M },
+	{ 20, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_2M },
+	{ 55, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_5_5M },
+	{ 110, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_11M },
+	{ 60, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_6M },
+	{ 90, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_9M },
+	{ 120, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_12M },
+	{ 180, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_18M },
+	{ 240, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_24M },
+	{ 360, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_36M },
+	{ 480, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_48M },
+	{ 540, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_54M },
+	{ 20, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE },
+	{ 55, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE },
+	{ 110, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE },
+	{ 0, 0, 0 },
+};
+
+#define ATH5K_NR_RATES 15
+
+/*
+ * Prototypes - PCI stack related functions
+ */
+static int 		ath5k_probe(struct pci_device *pdev);
+static void		ath5k_remove(struct pci_device *pdev);
+
+struct pci_driver ath5k_pci_driver __pci_driver = {
+	.ids		= ath5k_nics,
+	.id_count	= sizeof(ath5k_nics) / sizeof(ath5k_nics[0]),
+	.probe		= ath5k_probe,
+	.remove		= ath5k_remove,
+};
+
+
+
+/*
+ * Prototypes - MAC 802.11 stack related functions
+ */
+static int ath5k_tx(struct net80211_device *dev, struct io_buffer *skb);
+static int ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan);
+static int ath5k_reset_wake(struct ath5k_softc *sc);
+static int ath5k_start(struct net80211_device *dev);
+static void ath5k_stop(struct net80211_device *dev);
+static int ath5k_config(struct net80211_device *dev, int changed);
+static void ath5k_poll(struct net80211_device *dev);
+static void ath5k_irq(struct net80211_device *dev, int enable);
+
+static struct net80211_device_operations ath5k_ops = {
+	.open		= ath5k_start,
+	.close		= ath5k_stop,
+	.transmit	= ath5k_tx,
+	.poll		= ath5k_poll,
+	.irq		= ath5k_irq,
+	.config		= ath5k_config,
+};
+
+/*
+ * Prototypes - Internal functions
+ */
+/* Attach detach */
+static int 	ath5k_attach(struct net80211_device *dev);
+static void 	ath5k_detach(struct net80211_device *dev);
+/* Channel/mode setup */
+static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
+				struct net80211_channel *channels,
+				unsigned int mode,
+				unsigned int max);
+static int 	ath5k_setup_bands(struct net80211_device *dev);
+static int 	ath5k_chan_set(struct ath5k_softc *sc,
+				struct net80211_channel *chan);
+static void	ath5k_setcurmode(struct ath5k_softc *sc,
+				unsigned int mode);
+static void	ath5k_mode_setup(struct ath5k_softc *sc);
+
+/* Descriptor setup */
+static int	ath5k_desc_alloc(struct ath5k_softc *sc);
+static void	ath5k_desc_free(struct ath5k_softc *sc);
+/* Buffers setup */
+static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
+static int 	ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
+
+static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+				    struct ath5k_buf *bf)
+{
+	if (!bf->iob)
+		return;
+
+	net80211_tx_complete(sc->dev, bf->iob, 0, ECANCELED);
+	bf->iob = NULL;
+}
+
+static inline void ath5k_rxbuf_free(struct ath5k_softc *sc __unused,
+				    struct ath5k_buf *bf)
+{
+	free_iob(bf->iob);
+	bf->iob = NULL;
+}
+
+/* Queues setup */
+static int 	ath5k_txq_setup(struct ath5k_softc *sc,
+					   int qtype, int subtype);
+static void 	ath5k_txq_drainq(struct ath5k_softc *sc,
+				 struct ath5k_txq *txq);
+static void 	ath5k_txq_cleanup(struct ath5k_softc *sc);
+static void 	ath5k_txq_release(struct ath5k_softc *sc);
+/* Rx handling */
+static int 	ath5k_rx_start(struct ath5k_softc *sc);
+static void 	ath5k_rx_stop(struct ath5k_softc *sc);
+/* Tx handling */
+static void 	ath5k_tx_processq(struct ath5k_softc *sc,
+				  struct ath5k_txq *txq);
+
+/* Interrupt handling */
+static int 	ath5k_init(struct ath5k_softc *sc);
+static int 	ath5k_stop_hw(struct ath5k_softc *sc);
+
+static void 	ath5k_calibrate(struct ath5k_softc *sc);
+
+/* Filter */
+static void	ath5k_configure_filter(struct ath5k_softc *sc);
+
+/********************\
+* PCI Initialization *
+\********************/
+
+#if DBGLVL_MAX
+static const char *
+ath5k_chip_name(enum ath5k_srev_type type, u16 val)
+{
+	const char *name = "xxxxx";
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
+		if (srev_names[i].sr_type != type)
+			continue;
+
+		if ((val & 0xf0) == srev_names[i].sr_val)
+			name = srev_names[i].sr_name;
+
+		if ((val & 0xff) == srev_names[i].sr_val) {
+			name = srev_names[i].sr_name;
+			break;
+		}
+	}
+
+	return name;
+}
+#endif
+
+static int ath5k_probe(struct pci_device *pdev)
+{
+	void *mem;
+	struct ath5k_softc *sc;
+	struct net80211_device *dev;
+	int ret;
+	u8 csz;
+
+	adjust_pci_device(pdev);
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+	if (csz == 0) {
+		/*
+		 * We must have this setup properly for rx buffer
+		 * DMA to work so force a reasonable value here if it
+		 * comes up zero.
+		 */
+		csz = 16;
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+	}
+	/*
+	 * The default setting of latency timer yields poor results,
+	 * set it to the value used by other systems.  It may be worth
+	 * tweaking this setting more.
+	 */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+	/*
+	 * Disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	mem = ioremap(pdev->membase, 0x10000);
+	if (!mem) {
+		DBG("ath5k: cannot remap PCI memory region\n");
+		ret = -EIO;
+		goto err;
+	}
+
+	/*
+	 * Allocate dev (net80211 main struct)
+	 * and dev->priv (driver private data)
+	 */
+	dev = net80211_alloc(sizeof(*sc));
+	if (!dev) {
+		DBG("ath5k: cannot allocate 802.11 device\n");
+		ret = -ENOMEM;
+		goto err_map;
+	}
+
+	/* Initialize driver private data */
+	sc = dev->priv;
+	sc->dev = dev;
+	sc->pdev = pdev;
+
+	sc->hwinfo = zalloc(sizeof(*sc->hwinfo));
+	if (!sc->hwinfo) {
+		DBG("ath5k: cannot allocate 802.11 hardware info structure\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	sc->hwinfo->flags = NET80211_HW_RX_HAS_FCS;
+	sc->hwinfo->signal_type = NET80211_SIGNAL_DB;
+	sc->hwinfo->signal_max = 40; /* 35dB should give perfect 54Mbps */
+	sc->hwinfo->channel_change_time = 5000;
+
+	/* Avoid working with the device until setup is complete */
+	sc->status |= ATH_STAT_INVALID;
+
+	sc->iobase = mem;
+	sc->cachelsz = csz * 4; /* convert to bytes */
+
+	DBG("ath5k: register base at %p (%08lx)\n", sc->iobase, pdev->membase);
+	DBG("ath5k: cache line size %d\n", sc->cachelsz);
+
+	/* Set private data */
+	pci_set_drvdata(pdev, dev);
+	dev->netdev->dev = (struct device *)pdev;
+
+	/* Initialize device */
+	ret = ath5k_hw_attach(sc, pdev->id->driver_data, &sc->ah);
+	if (ret)
+		goto err_free_hwinfo;
+
+	/* Finish private driver data initialization */
+	ret = ath5k_attach(dev);
+	if (ret)
+		goto err_ah;
+
+#if DBGLVL_MAX
+	DBG("Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+	    ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
+	    sc->ah->ah_mac_srev, sc->ah->ah_phy_revision);
+
+	if (!sc->ah->ah_single_chip) {
+		/* Single chip radio (!RF5111) */
+		if (sc->ah->ah_radio_5ghz_revision &&
+		    !sc->ah->ah_radio_2ghz_revision) {
+			/* No 5GHz support -> report 2GHz radio */
+			if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A)) {
+				DBG("RF%s 2GHz radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			/* No 2GHz support (5110 and some
+			 * 5Ghz only cards) -> report 5Ghz radio */
+			} else if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B)) {
+				DBG("RF%s 5GHz radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			/* Multiband radio */
+			} else {
+				DBG("RF%s multiband radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			}
+		}
+		/* Multi chip radio (RF5111 - RF2111) ->
+		 * report both 2GHz/5GHz radios */
+		else if (sc->ah->ah_radio_5ghz_revision &&
+			 sc->ah->ah_radio_2ghz_revision) {
+			DBG("RF%s 5GHz radio found (0x%x)\n",
+			    ath5k_chip_name(AR5K_VERSION_RAD,
+					    sc->ah->ah_radio_5ghz_revision),
+			    sc->ah->ah_radio_5ghz_revision);
+			DBG("RF%s 2GHz radio found (0x%x)\n",
+			    ath5k_chip_name(AR5K_VERSION_RAD,
+					    sc->ah->ah_radio_2ghz_revision),
+			    sc->ah->ah_radio_2ghz_revision);
+		}
+	}
+#endif
+
+	/* Ready to go */
+	sc->status &= ~ATH_STAT_INVALID;
+
+	return 0;
+err_ah:
+	ath5k_hw_detach(sc->ah);
+err_free_hwinfo:
+	free(sc->hwinfo);
+err_free:
+	net80211_free(dev);
+err_map:
+	iounmap(mem);
+err:
+	return ret;
+}
+
+static void ath5k_remove(struct pci_device *pdev)
+{
+	struct net80211_device *dev = pci_get_drvdata(pdev);
+	struct ath5k_softc *sc = dev->priv;
+
+	ath5k_detach(dev);
+	ath5k_hw_detach(sc->ah);
+	iounmap(sc->iobase);
+	free(sc->hwinfo);
+	net80211_free(dev);
+}
+
+
+/***********************\
+* Driver Initialization *
+\***********************/
+
+static int
+ath5k_attach(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	/*
+	 * Collect the channel list.  The 802.11 layer
+	 * is resposible for filtering this list based
+	 * on settings like the phy mode and regulatory
+	 * domain restrictions.
+	 */
+	ret = ath5k_setup_bands(dev);
+	if (ret) {
+		DBG("ath5k: can't get channels\n");
+		goto err;
+	}
+
+	/* NB: setup here so ath5k_rate_update is happy */
+	if (ah->ah_modes & AR5K_MODE_BIT_11A)
+		ath5k_setcurmode(sc, AR5K_MODE_11A);
+	else
+		ath5k_setcurmode(sc, AR5K_MODE_11B);
+
+	/*
+	 * Allocate tx+rx descriptors and populate the lists.
+	 */
+	ret = ath5k_desc_alloc(sc);
+	if (ret) {
+		DBG("ath5k: can't allocate descriptors\n");
+		goto err;
+	}
+
+	/*
+	 * Allocate hardware transmit queues. Note that hw functions
+	 * handle reseting these queues at the needed time.
+	 */
+	ret = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
+	if (ret) {
+		DBG("ath5k: can't setup xmit queue\n");
+		goto err_desc;
+	}
+
+	sc->last_calib_ticks = currticks();
+
+	ret = ath5k_eeprom_read_mac(ah, sc->hwinfo->hwaddr);
+	if (ret) {
+		DBG("ath5k: unable to read address from EEPROM: 0x%04x\n",
+		    sc->pdev->device);
+		goto err_queues;
+	}
+
+	memset(sc->bssidmask, 0xff, ETH_ALEN);
+	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+
+	ret = net80211_register(sc->dev, &ath5k_ops, sc->hwinfo);
+	if (ret) {
+		DBG("ath5k: can't register ieee80211 hw\n");
+		goto err_queues;
+	}
+
+	return 0;
+err_queues:
+	ath5k_txq_release(sc);
+err_desc:
+	ath5k_desc_free(sc);
+err:
+	return ret;
+}
+
+static void
+ath5k_detach(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+
+	net80211_unregister(dev);
+	ath5k_desc_free(sc);
+	ath5k_txq_release(sc);
+}
+
+
+
+
+/********************\
+* Channel/mode setup *
+\********************/
+
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static inline short
+ath5k_ieee2mhz(short chan)
+{
+	if (chan < 14)
+		return 2407 + 5 * chan;
+	if (chan == 14)
+		return 2484;
+	if (chan < 27)
+		return 2212 + 20 * chan;
+	return 5000 + 5 * chan;
+}
+
+static unsigned int
+ath5k_copy_channels(struct ath5k_hw *ah,
+		    struct net80211_channel *channels,
+		    unsigned int mode, unsigned int max)
+{
+	unsigned int i, count, size, chfreq, freq, ch;
+
+	if (!(ah->ah_modes & (1 << mode)))
+		return 0;
+
+	switch (mode) {
+	case AR5K_MODE_11A:
+	case AR5K_MODE_11A_TURBO:
+		/* 1..220, but 2GHz frequencies are filtered by check_channel */
+		size = 220;
+		chfreq = CHANNEL_5GHZ;
+		break;
+	case AR5K_MODE_11B:
+	case AR5K_MODE_11G:
+	case AR5K_MODE_11G_TURBO:
+		size = 26;
+		chfreq = CHANNEL_2GHZ;
+		break;
+	default:
+		return 0;
+	}
+
+	for (i = 0, count = 0; i < size && max > 0; i++) {
+		ch = i + 1 ;
+		freq = ath5k_ieee2mhz(ch);
+
+		/* Check if channel is supported by the chipset */
+		if (!ath5k_channel_ok(ah, freq, chfreq))
+			continue;
+
+		/* Write channel info and increment counter */
+		channels[count].center_freq = freq;
+		channels[count].maxpower = 0; /* use regulatory */
+		channels[count].band = (chfreq == CHANNEL_2GHZ) ?
+			NET80211_BAND_2GHZ : NET80211_BAND_5GHZ;
+		switch (mode) {
+		case AR5K_MODE_11A:
+		case AR5K_MODE_11G:
+			channels[count].hw_value = chfreq | CHANNEL_OFDM;
+			break;
+		case AR5K_MODE_11A_TURBO:
+		case AR5K_MODE_11G_TURBO:
+			channels[count].hw_value = chfreq |
+				CHANNEL_OFDM | CHANNEL_TURBO;
+			break;
+		case AR5K_MODE_11B:
+			channels[count].hw_value = CHANNEL_B;
+		}
+
+		count++;
+		max--;
+	}
+
+	return count;
+}
+
+static int
+ath5k_setup_bands(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int max_c, count_c = 0;
+	int i;
+	int band;
+
+	max_c = sizeof(sc->hwinfo->channels) / sizeof(sc->hwinfo->channels[0]);
+
+	/* 2GHz band */
+	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11G) {
+		/* G mode */
+		band = NET80211_BAND_2GHZ;
+		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
+		sc->hwinfo->modes = (NET80211_MODE_G | NET80211_MODE_B);
+
+		for (i = 0; i < 12; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
+		sc->hwinfo->nr_rates[band] = 12;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11G, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	} else if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B) {
+		/* B mode */
+		band = NET80211_BAND_2GHZ;
+		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
+		sc->hwinfo->modes = NET80211_MODE_B;
+
+		for (i = 0; i < 4; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
+		sc->hwinfo->nr_rates[band] = 4;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11B, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	}
+
+	/* 5GHz band, A mode */
+	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A) {
+		band = NET80211_BAND_5GHZ;
+		sc->hwinfo->bands |= NET80211_BAND_BIT_5GHZ;
+		sc->hwinfo->modes |= NET80211_MODE_A;
+
+		for (i = 0; i < 8; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i+4].bitrate;
+		sc->hwinfo->nr_rates[band] = 8;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11B, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	}
+
+	return 0;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed,
+ * it's done by reseting the chip.  To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * ath5k_init.
+ */
+static int
+ath5k_chan_set(struct ath5k_softc *sc, struct net80211_channel *chan)
+{
+	if (chan->center_freq != sc->curchan->center_freq ||
+	    chan->hw_value != sc->curchan->hw_value) {
+		/*
+		 * To switch channels clear any pending DMA operations;
+		 * wait long enough for the RX fifo to drain, reset the
+		 * hardware at the new frequency, and then re-enable
+		 * the relevant bits of the h/w.
+		 */
+		DBG2("ath5k: resetting for channel change (%d -> %d MHz)\n",
+		     sc->curchan->center_freq, chan->center_freq);
+		return ath5k_reset(sc, chan);
+	}
+
+	return 0;
+}
+
+static void
+ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
+{
+	sc->curmode = mode;
+
+	if (mode == AR5K_MODE_11A) {
+		sc->curband = NET80211_BAND_5GHZ;
+	} else {
+		sc->curband = NET80211_BAND_2GHZ;
+	}
+}
+
+static void
+ath5k_mode_setup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 rfilt;
+
+	/* configure rx filter */
+	rfilt = sc->filter_flags;
+	ath5k_hw_set_rx_filter(ah, rfilt);
+
+	if (ath5k_hw_hasbssidmask(ah))
+		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+
+	/* configure operational mode */
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_set_mcast_filter(ah, 0, 0);
+}
+
+static inline int
+ath5k_hw_rix_to_bitrate(int hw_rix)
+{
+	int i;
+
+	for (i = 0; i < ATH5K_NR_RATES; i++) {
+		if (ath5k_rates[i].hw_code == hw_rix)
+			return ath5k_rates[i].bitrate;
+	}
+
+	DBG("ath5k: invalid rix %02x\n", hw_rix);
+	return 10;		/* use lowest rate */
+}
+
+int ath5k_bitrate_to_hw_rix(int bitrate)
+{
+	int i;
+
+	for (i = 0; i < ATH5K_NR_RATES; i++) {
+		if (ath5k_rates[i].bitrate == bitrate)
+			return ath5k_rates[i].hw_code;
+	}
+
+	DBG("ath5k: invalid bitrate %d\n", bitrate);
+	return ATH5K_RATE_CODE_1M; /* use lowest rate */
+}
+
+/***************\
+* Buffers setup *
+\***************/
+
+static struct io_buffer *
+ath5k_rx_iob_alloc(struct ath5k_softc *sc, u32 *iob_addr)
+{
+	struct io_buffer *iob;
+	unsigned int off;
+
+	/*
+	 * Allocate buffer with headroom_needed space for the
+	 * fake physical layer header at the start.
+	 */
+	iob = alloc_iob(sc->rxbufsize + sc->cachelsz - 1);
+
+	if (!iob) {
+		DBG("ath5k: can't alloc iobuf of size %d\n",
+		    sc->rxbufsize + sc->cachelsz - 1);
+		return NULL;
+	}
+
+	*iob_addr = virt_to_bus(iob->data);
+
+	/*
+	 * Cache-line-align.  This is important (for the
+	 * 5210 at least) as not doing so causes bogus data
+	 * in rx'd frames.
+	 */
+	off = *iob_addr % sc->cachelsz;
+	if (off != 0) {
+		iob_reserve(iob, sc->cachelsz - off);
+		*iob_addr += sc->cachelsz - off;
+	}
+
+	return iob;
+}
+
+static int
+ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct io_buffer *iob = bf->iob;
+	struct ath5k_desc *ds;
+
+	if (!iob) {
+		iob = ath5k_rx_iob_alloc(sc, &bf->iobaddr);
+		if (!iob)
+			return -ENOMEM;
+		bf->iob = iob;
+	}
+
+	/*
+	 * Setup descriptors.  For receive we always terminate
+	 * the descriptor list with a self-linked entry so we'll
+	 * not get overrun under high load (as can happen with a
+	 * 5212 when ANI processing enables PHY error frames).
+	 *
+	 * To insure the last descriptor is self-linked we create
+	 * each descriptor as self-linked and add it to the end.  As
+	 * each additional descriptor is added the previous self-linked
+	 * entry is ``fixed'' naturally.  This should be safe even
+	 * if DMA is happening.  When processing RX interrupts we
+	 * never remove/process the last, self-linked, entry on the
+	 * descriptor list.  This insures the hardware always has
+	 * someplace to write a new frame.
+	 */
+	ds = bf->desc;
+	ds->ds_link = bf->daddr;	/* link to self */
+	ds->ds_data = bf->iobaddr;
+	if (ah->ah_setup_rx_desc(ah, ds,
+				 iob_tailroom(iob),	/* buffer size */
+				 0) != 0) {
+		DBG("ath5k: error setting up RX descriptor for %zd bytes\n", iob_tailroom(iob));
+		return -EINVAL;
+	}
+
+	if (sc->rxlink != NULL)
+		*sc->rxlink = bf->daddr;
+	sc->rxlink = &ds->ds_link;
+	return 0;
+}
+
+static int
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq = &sc->txq;
+	struct ath5k_desc *ds = bf->desc;
+	struct io_buffer *iob = bf->iob;
+	unsigned int pktlen, flags;
+	int ret;
+	u16 duration = 0;
+	u16 cts_rate = 0;
+
+	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
+	bf->iobaddr = virt_to_bus(iob->data);
+	pktlen = iob_len(iob);
+
+	/* FIXME: If we are in g mode and rate is a CCK rate
+	 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
+	 * from tx power (value is in dB units already) */
+	if (sc->dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
+		struct net80211_device *dev = sc->dev;
+
+		flags |= AR5K_TXDESC_CTSENA;
+		cts_rate = sc->hw_rtscts_rate;
+		duration = net80211_cts_duration(dev, pktlen);
+	}
+	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
+				   IEEE80211_TYP_FRAME_HEADER_LEN,
+				   AR5K_PKT_TYPE_NORMAL, sc->power_level * 2,
+				   sc->hw_rate, ATH5K_RETRIES,
+				   AR5K_TXKEYIX_INVALID, 0, flags,
+				   cts_rate, duration);
+	if (ret)
+		return ret;
+
+	ds->ds_link = 0;
+	ds->ds_data = bf->iobaddr;
+
+	list_add_tail(&bf->list, &txq->q);
+	if (txq->link == NULL) /* is this first packet? */
+		ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
+	else /* no, so only link it */
+		*txq->link = bf->daddr;
+
+	txq->link = &ds->ds_link;
+	ath5k_hw_start_tx_dma(ah, txq->qnum);
+	mb();
+
+	return 0;
+}
+
+/*******************\
+* Descriptors setup *
+\*******************/
+
+static int
+ath5k_desc_alloc(struct ath5k_softc *sc)
+{
+	struct ath5k_desc *ds;
+	struct ath5k_buf *bf;
+	u32 da;
+	unsigned int i;
+	int ret;
+
+	/* allocate descriptors */
+	sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1);
+	sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN);
+	if (sc->desc == NULL) {
+		DBG("ath5k: can't allocate descriptors\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	memset(sc->desc, 0, sc->desc_len);
+	sc->desc_daddr = virt_to_bus(sc->desc);
+
+	ds = sc->desc;
+	da = sc->desc_daddr;
+
+	bf = calloc(ATH_TXBUF + ATH_RXBUF + 1, sizeof(struct ath5k_buf));
+	if (bf == NULL) {
+		DBG("ath5k: can't allocate buffer pointers\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+	sc->bufptr = bf;
+
+	INIT_LIST_HEAD(&sc->rxbuf);
+	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->rxbuf);
+	}
+
+	INIT_LIST_HEAD(&sc->txbuf);
+	sc->txbuf_len = ATH_TXBUF;
+	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->txbuf);
+	}
+
+	return 0;
+
+err_free:
+	free_dma(sc->desc, sc->desc_len);
+err:
+	sc->desc = NULL;
+	return ret;
+}
+
+static void
+ath5k_desc_free(struct ath5k_softc *sc)
+{
+	struct ath5k_buf *bf;
+
+	list_for_each_entry(bf, &sc->txbuf, list)
+		ath5k_txbuf_free(sc, bf);
+	list_for_each_entry(bf, &sc->rxbuf, list)
+		ath5k_rxbuf_free(sc, bf);
+
+	/* Free memory associated with all descriptors */
+	free_dma(sc->desc, sc->desc_len);
+
+	free(sc->bufptr);
+	sc->bufptr = NULL;
+}
+
+
+
+
+
+/**************\
+* Queues setup *
+\**************/
+
+static int
+ath5k_txq_setup(struct ath5k_softc *sc, int qtype, int subtype)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq;
+	struct ath5k_txq_info qi = {
+		.tqi_subtype = subtype,
+		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_max = AR5K_TXQ_USEDEFAULT
+	};
+	int qnum;
+
+	/*
+	 * Enable interrupts only for EOL and DESC conditions.
+	 * We mark tx descriptors to receive a DESC interrupt
+	 * when a tx queue gets deep; otherwise waiting for the
+	 * EOL to reap descriptors.  Note that this is done to
+	 * reduce interrupt load and this only defers reaping
+	 * descriptors, never transmitting frames.  Aside from
+	 * reducing interrupts this also permits more concurrency.
+	 * The only potential downside is if the tx queue backs
+	 * up in which case the top half of the kernel may backup
+	 * due to a lack of tx descriptors.
+	 */
+	qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
+				AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
+	qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
+	if (qnum < 0) {
+		DBG("ath5k: can't set up a TX queue\n");
+		return -EIO;
+	}
+
+	txq = &sc->txq;
+	if (!txq->setup) {
+		txq->qnum = qnum;
+		txq->link = NULL;
+		INIT_LIST_HEAD(&txq->q);
+		txq->setup = 1;
+	}
+	return 0;
+}
+
+static void
+ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ath5k_buf *bf, *bf0;
+
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ath5k_txbuf_free(sc, bf);
+
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+	}
+	txq->link = NULL;
+}
+
+/*
+ * Drain the transmit queues and reclaim resources.
+ */
+static void
+ath5k_txq_cleanup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		/* don't touch the hardware if marked invalid */
+		if (sc->txq.setup) {
+			ath5k_hw_stop_tx_dma(ah, sc->txq.qnum);
+			DBG("ath5k: txq [%d] %x, link %p\n",
+			    sc->txq.qnum,
+			    ath5k_hw_get_txdp(ah, sc->txq.qnum),
+			    sc->txq.link);
+		}
+	}
+
+	if (sc->txq.setup)
+		ath5k_txq_drainq(sc, &sc->txq);
+}
+
+static void
+ath5k_txq_release(struct ath5k_softc *sc)
+{
+	if (sc->txq.setup) {
+		ath5k_hw_release_tx_queue(sc->ah);
+		sc->txq.setup = 0;
+	}
+}
+
+
+
+
+/*************\
+* RX Handling *
+\*************/
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath5k_rx_start(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_buf *bf;
+	int ret;
+
+	sc->rxbufsize = IEEE80211_MAX_LEN;
+	if (sc->rxbufsize % sc->cachelsz != 0)
+		sc->rxbufsize += sc->cachelsz - (sc->rxbufsize % sc->cachelsz);
+
+	sc->rxlink = NULL;
+
+	list_for_each_entry(bf, &sc->rxbuf, list) {
+		ret = ath5k_rxbuf_setup(sc, bf);
+		if (ret != 0)
+			return ret;
+	}
+
+	bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
+
+	ath5k_hw_set_rxdp(ah, bf->daddr);
+	ath5k_hw_start_rx_dma(ah);	/* enable recv descriptors */
+	ath5k_mode_setup(sc);		/* set filters, etc. */
+	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
+
+	return 0;
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath5k_rx_stop(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	ath5k_hw_stop_rx_pcu(ah);	/* disable PCU */
+	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
+	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
+
+	sc->rxlink = NULL;		/* just in case */
+}
+
+static void
+ath5k_handle_rx(struct ath5k_softc *sc)
+{
+	struct ath5k_rx_status rs;
+	struct io_buffer *iob, *next_iob;
+	u32 next_iob_addr;
+	struct ath5k_buf *bf, *bf_last;
+	struct ath5k_desc *ds;
+	int ret;
+
+	memset(&rs, 0, sizeof(rs));
+
+	if (list_empty(&sc->rxbuf)) {
+		DBG("ath5k: empty rx buf pool\n");
+		return;
+	}
+
+	bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
+
+	do {
+		bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
+		assert(bf->iob != NULL);
+		iob = bf->iob;
+		ds = bf->desc;
+
+		/*
+		 * last buffer must not be freed to ensure proper hardware
+		 * function. When the hardware finishes also a packet next to
+		 * it, we are sure, it doesn't use it anymore and we can go on.
+		 */
+		if (bf_last == bf)
+			bf->flags |= 1;
+		if (bf->flags) {
+			struct ath5k_buf *bf_next = list_entry(bf->list.next,
+					struct ath5k_buf, list);
+			ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
+					&rs);
+			if (ret)
+				break;
+			bf->flags &= ~1;
+			/* skip the overwritten one (even status is martian) */
+			goto next;
+		}
+
+		ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
+		if (ret) {
+			if (ret != -EINPROGRESS) {
+				DBG("ath5k: error in processing rx desc: %s\n",
+				    strerror(ret));
+				net80211_rx_err(sc->dev, NULL, -ret);
+			} else {
+				/* normal return, reached end of
+				   available descriptors */
+			}
+			return;
+		}
+
+		if (rs.rs_more) {
+			DBG("ath5k: unsupported fragmented rx\n");
+			goto next;
+		}
+
+		if (rs.rs_status) {
+			if (rs.rs_status & AR5K_RXERR_PHY) {
+				/* These are uncommon, and may indicate a real problem. */
+				net80211_rx_err(sc->dev, NULL, EIO);
+				goto next;
+			}
+			if (rs.rs_status & AR5K_RXERR_CRC) {
+				/* These occur *all the time*. */
+				goto next;
+			}
+			if (rs.rs_status & AR5K_RXERR_DECRYPT) {
+				/*
+				 * Decrypt error.  If the error occurred
+				 * because there was no hardware key, then
+				 * let the frame through so the upper layers
+				 * can process it.  This is necessary for 5210
+				 * parts which have no way to setup a ``clear''
+				 * key cache entry.
+				 *
+				 * XXX do key cache faulting
+				 */
+				if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
+				    !(rs.rs_status & AR5K_RXERR_CRC))
+					goto accept;
+			}
+
+			/* any other error, unhandled */
+			DBG("ath5k: packet rx status %x\n", rs.rs_status);
+			goto next;
+		}
+accept:
+		next_iob = ath5k_rx_iob_alloc(sc, &next_iob_addr);
+
+		/*
+		 * If we can't replace bf->iob with a new iob under memory
+		 * pressure, just skip this packet
+		 */
+		if (!next_iob) {
+			DBG("ath5k: dropping packet under memory pressure\n");
+			goto next;
+		}
+
+		iob_put(iob, rs.rs_datalen);
+
+		/* The MAC header is padded to have 32-bit boundary if the
+		 * packet payload is non-zero. However, iPXE only
+		 * supports standard 802.11 packets with 24-byte
+		 * header, so no padding correction should be needed.
+		 */
+
+		DBG2("ath5k: rx %d bytes, signal %d\n", rs.rs_datalen,
+		     rs.rs_rssi);
+
+		net80211_rx(sc->dev, iob, rs.rs_rssi,
+			    ath5k_hw_rix_to_bitrate(rs.rs_rate));
+
+		bf->iob = next_iob;
+		bf->iobaddr = next_iob_addr;
+next:
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->rxbuf);
+	} while (ath5k_rxbuf_setup(sc, bf) == 0);
+}
+
+
+
+
+/*************\
+* TX Handling *
+\*************/
+
+static void
+ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ath5k_tx_status ts;
+	struct ath5k_buf *bf, *bf0;
+	struct ath5k_desc *ds;
+	struct io_buffer *iob;
+	int ret;
+
+	memset(&ts, 0, sizeof(ts));
+
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ds = bf->desc;
+
+		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
+		if (ret) {
+			if (ret != -EINPROGRESS) {
+				DBG("ath5k: error in processing tx desc: %s\n",
+				    strerror(ret));
+			} else {
+				/* normal return, reached end of tx completions */
+			}
+			break;
+		}
+
+		iob = bf->iob;
+		bf->iob = NULL;
+
+		DBG2("ath5k: tx %zd bytes complete, %d retries\n",
+		     iob_len(iob), ts.ts_retry[0]);
+
+		net80211_tx_complete(sc->dev, iob, ts.ts_retry[0],
+				     ts.ts_status ? EIO : 0);
+
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+	}
+
+	if (list_empty(&txq->q))
+		txq->link = NULL;
+}
+
+static void
+ath5k_handle_tx(struct ath5k_softc *sc)
+{
+	ath5k_tx_processq(sc, &sc->txq);
+}
+
+
+/********************\
+* Interrupt handling *
+\********************/
+
+static void
+ath5k_irq(struct net80211_device *dev, int enable)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+
+	sc->irq_ena = enable;
+	ah->ah_ier = enable ? AR5K_IER_ENABLE : AR5K_IER_DISABLE;
+
+	ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
+	ath5k_hw_set_imr(ah, sc->imask);
+}
+
+static int
+ath5k_init(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	int ret, i;
+
+	/*
+	 * Stop anything previously setup.  This is safe
+	 * no matter this is the first time through or not.
+	 */
+	ath5k_stop_hw(sc);
+
+	/*
+	 * The basic interface to setting the hardware in a good
+	 * state is ``reset''.  On return the hardware is known to
+	 * be powered up and with interrupts disabled.  This must
+	 * be followed by initialization of the appropriate bits
+	 * and then setup of the interrupt mask.
+	 */
+	sc->curchan = sc->dev->channels + sc->dev->channel;
+	sc->curband = sc->curchan->band;
+	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
+		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
+		AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+	ret = ath5k_reset(sc, NULL);
+	if (ret)
+		goto done;
+
+	ath5k_rfkill_hw_start(ah);
+
+	/*
+	 * Reset the key cache since some parts do not reset the
+	 * contents on initial power up or resume from suspend.
+	 */
+	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
+		ath5k_hw_reset_key(ah, i);
+
+	/* Set ack to be sent at low bit-rates */
+	ath5k_hw_set_ack_bitrate_high(ah, 0);
+
+	ret = 0;
+done:
+	mb();
+	return ret;
+}
+
+static int
+ath5k_stop_hw(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	/*
+	 * Shutdown the hardware and driver:
+	 *    stop output from above
+	 *    disable interrupts
+	 *    turn off timers
+	 *    turn off the radio
+	 *    clear transmit machinery
+	 *    clear receive machinery
+	 *    drain and release tx queues
+	 *    reclaim beacon resources
+	 *    power down hardware
+	 *
+	 * Note that some of this work is not possible if the
+	 * hardware is gone (invalid).
+	 */
+
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		ath5k_hw_set_imr(ah, 0);
+	}
+	ath5k_txq_cleanup(sc);
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		ath5k_rx_stop(sc);
+		ath5k_hw_phy_disable(ah);
+	} else
+		sc->rxlink = NULL;
+
+	ath5k_rfkill_hw_stop(sc->ah);
+
+	return 0;
+}
+
+static void
+ath5k_poll(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	enum ath5k_int status;
+	unsigned int counter = 1000;
+
+	if (currticks() - sc->last_calib_ticks >
+	    ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
+		ath5k_calibrate(sc);
+		sc->last_calib_ticks = currticks();
+	}
+
+	if ((sc->status & ATH_STAT_INVALID) ||
+	    (sc->irq_ena && !ath5k_hw_is_intr_pending(ah)))
+		return;
+
+	do {
+		ath5k_hw_get_isr(ah, &status);		/* NB: clears IRQ too */
+		DBGP("ath5k: status %#x/%#x\n", status, sc->imask);
+		if (status & AR5K_INT_FATAL) {
+			/*
+			 * Fatal errors are unrecoverable.
+			 * Typically these are caused by DMA errors.
+			 */
+			DBG("ath5k: fatal error, resetting\n");
+			ath5k_reset_wake(sc);
+		} else if (status & AR5K_INT_RXORN) {
+			DBG("ath5k: rx overrun, resetting\n");
+			ath5k_reset_wake(sc);
+		} else {
+			if (status & AR5K_INT_RXEOL) {
+				/*
+				 * NB: the hardware should re-read the link when
+				 *     RXE bit is written, but it doesn't work at
+				 *     least on older hardware revs.
+				 */
+				DBG("ath5k: rx EOL\n");
+				sc->rxlink = NULL;
+			}
+			if (status & AR5K_INT_TXURN) {
+				/* bump tx trigger level */
+				DBG("ath5k: tx underrun\n");
+				ath5k_hw_update_tx_triglevel(ah, 1);
+			}
+			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
+				ath5k_handle_rx(sc);
+			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+				      | AR5K_INT_TXERR | AR5K_INT_TXEOL))
+				ath5k_handle_tx(sc);
+		}
+	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
+
+	if (!counter)
+		DBG("ath5k: too many interrupts, giving up for now\n");
+}
+
+/*
+ * Periodically recalibrate the PHY to account
+ * for temperature/environment changes.
+ */
+static void
+ath5k_calibrate(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+		/*
+		 * Rfgain is out of bounds, reset the chip
+		 * to load new gain values.
+		 */
+		DBG("ath5k: resetting for calibration\n");
+		ath5k_reset_wake(sc);
+	}
+	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+		DBG("ath5k: calibration of channel %d failed\n",
+		    sc->curchan->channel_nr);
+}
+
+
+/********************\
+* Net80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct net80211_device *dev, struct io_buffer *iob)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_buf *bf;
+	int rc;
+
+	/*
+	 * The hardware expects the header padded to 4 byte boundaries.
+	 * iPXE only ever sends 24-byte headers, so no action necessary.
+	 */
+
+	if (list_empty(&sc->txbuf)) {
+		DBG("ath5k: dropping packet because no tx bufs available\n");
+		return -ENOBUFS;
+	}
+
+	bf = list_entry(sc->txbuf.next, struct ath5k_buf, list);
+	list_del(&bf->list);
+	sc->txbuf_len--;
+
+	bf->iob = iob;
+
+	if ((rc = ath5k_txbuf_setup(sc, bf)) != 0) {
+		bf->iob = NULL;
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+		return rc;
+	}
+	return 0;
+}
+
+/*
+ * Reset the hardware.  If chan is not NULL, then also pause rx/tx
+ * and change to the given channel.
+ */
+static int
+ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan)
+{
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	if (chan) {
+		ath5k_hw_set_imr(ah, 0);
+		ath5k_txq_cleanup(sc);
+		ath5k_rx_stop(sc);
+
+		sc->curchan = chan;
+		sc->curband = chan->band;
+	}
+
+	ret = ath5k_hw_reset(ah, sc->curchan, 1);
+	if (ret) {
+		DBG("ath5k: can't reset hardware: %s\n", strerror(ret));
+		return ret;
+	}
+
+	ret = ath5k_rx_start(sc);
+	if (ret) {
+		DBG("ath5k: can't start rx logic: %s\n", strerror(ret));
+		return ret;
+	}
+
+	/*
+	 * Change channels and update the h/w rate map if we're switching;
+	 * e.g. 11a to 11b/g.
+	 *
+	 * We may be doing a reset in response to an ioctl that changes the
+	 * channel so update any state that might change as a result.
+	 *
+	 * XXX needed?
+	 */
+/*	ath5k_chan_change(sc, c); */
+
+	/* Reenable interrupts if necessary */
+	ath5k_irq(sc->dev, sc->irq_ena);
+
+	return 0;
+}
+
+static int ath5k_reset_wake(struct ath5k_softc *sc)
+{
+	return ath5k_reset(sc, sc->curchan);
+}
+
+static int ath5k_start(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	int ret;
+
+	if ((ret = ath5k_init(sc)) != 0)
+		return ret;
+
+	sc->assoc = 0;
+	ath5k_configure_filter(sc);
+	ath5k_hw_set_lladdr(sc->ah, dev->netdev->ll_addr);
+
+	return 0;
+}
+
+static void ath5k_stop(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	u8 mac[ETH_ALEN] = {};
+
+	ath5k_hw_set_lladdr(sc->ah, mac);
+
+	ath5k_stop_hw(sc);
+}
+
+static int
+ath5k_config(struct net80211_device *dev, int changed)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	struct net80211_channel *chan = &dev->channels[dev->channel];
+	int ret;
+
+	if (changed & NET80211_CFG_CHANNEL) {
+		sc->power_level = chan->maxpower;
+		if ((ret = ath5k_chan_set(sc, chan)) != 0)
+			return ret;
+	}
+
+	if ((changed & NET80211_CFG_RATE) ||
+	    (changed & NET80211_CFG_PHY_PARAMS)) {
+		int spmbl = ATH5K_SPMBL_NO;
+		u16 rate = dev->rates[dev->rate];
+		u16 slowrate = dev->rates[dev->rtscts_rate];
+		int i;
+
+		if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
+			spmbl = ATH5K_SPMBL_YES;
+
+		for (i = 0; i < ATH5K_NR_RATES; i++) {
+			if (ath5k_rates[i].bitrate == rate &&
+			    (ath5k_rates[i].short_pmbl & spmbl))
+				sc->hw_rate = ath5k_rates[i].hw_code;
+
+			if (ath5k_rates[i].bitrate == slowrate &&
+			    (ath5k_rates[i].short_pmbl & spmbl))
+				sc->hw_rtscts_rate = ath5k_rates[i].hw_code;
+		}
+	}
+
+	if (changed & NET80211_CFG_ASSOC) {
+		sc->assoc = !!(dev->state & NET80211_ASSOCIATED);
+		if (sc->assoc) {
+			memcpy(ah->ah_bssid, dev->bssid, ETH_ALEN);
+		} else {
+			memset(ah->ah_bssid, 0xff, ETH_ALEN);
+		}
+		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	}
+
+	return 0;
+}
+
+/*
+ * o always accept unicast, broadcast, and multicast traffic
+ * o multicast traffic for all BSSIDs will be enabled if mac80211
+ *   says it should be
+ * o maintain current state of phy ofdm or phy cck error reception.
+ *   If the hardware detects any of these type of errors then
+ *   ath5k_hw_get_rx_filter() will pass to us the respective
+ *   hardware filters to be able to receive these type of frames.
+ * o probe request frames are accepted only when operating in
+ *   hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ *   - when operating in adhoc mode so the 802.11 layer creates
+ *     node table entries for peers,
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
+ *   - when scanning
+ */
+static void ath5k_configure_filter(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 mfilt[2], rfilt;
+
+	/* Enable all multicast */
+	mfilt[0] = ~0;
+	mfilt[1] = ~0;
+
+	/* Enable data frames and beacons */
+	rfilt = (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
+		 AR5K_RX_FILTER_MCAST | AR5K_RX_FILTER_BEACON);
+
+	/* Set filters */
+	ath5k_hw_set_rx_filter(ah, rfilt);
+
+	/* Set multicast bits */
+	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
+
+	/* Set the cached hw filter flags, this will alter actually
+	 * be set in HW */
+	sc->filter_flags = rfilt;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.h
new file mode 100644
index 0000000..30e2024
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k.h
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ATH5K_H
+#define _ATH5K_H
+
+FILE_LICENCE ( MIT );
+
+#include <stddef.h>
+#include <byteswap.h>
+#include <ipxe/io.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/net80211.h>
+#include <errno.h>
+
+/* Keep all ath5k files under one errfile ID */
+#undef ERRFILE
+#define ERRFILE ERRFILE_ath5k
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+/* RX/TX descriptor hw structs */
+#include "desc.h"
+
+/* EEPROM structs/offsets */
+#include "eeprom.h"
+
+/* PCI IDs */
+#define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
+#define PCI_DEVICE_ID_ATHEROS_AR5311 		0x0011 /* AR5311 */
+#define PCI_DEVICE_ID_ATHEROS_AR5211 		0x0012 /* AR5211 */
+#define PCI_DEVICE_ID_ATHEROS_AR5212 		0x0013 /* AR5212 */
+#define PCI_DEVICE_ID_3COM_3CRDAG675 		0x0013 /* 3CRDAG675 (Atheros AR5212) */
+#define PCI_DEVICE_ID_3COM_2_3CRPAG175 		0x0013 /* 3CRPAG175 (Atheros AR5212) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 	0x0207 /* AR5210 (Early) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM	0x1014 /* AR5212 (IBM MiniPCI) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 	0x1107 /* AR5210 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 	0x1113 /* AR5212 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 	0x1112 /* AR5211 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 	0xf013 /* AR5212 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 	0xff12 /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 	0xf11b /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 	0x0052 /* AR5312 WMAC (AP31) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 	0x0057 /* AR5312 WMAC (AP30-040) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 	0x0058 /* AR5312 WMAC (AP43-030) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 	0x0014 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 	0x0015 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 	0x0016 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 	0x0017 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 	0x0018 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 	0x0019 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR2413 		0x001a /* AR2413 (Griffin-lite) */
+#define PCI_DEVICE_ID_ATHEROS_AR5413 		0x001b /* AR5413 (Eagle) */
+#define PCI_DEVICE_ID_ATHEROS_AR5424 		0x001c /* AR5424 (Condor PCI-E) */
+#define PCI_DEVICE_ID_ATHEROS_AR5416 		0x0023 /* AR5416 */
+#define PCI_DEVICE_ID_ATHEROS_AR5418 		0x0024 /* AR5418 */
+
+/****************************\
+  GENERIC DRIVER DEFINITIONS
+\****************************/
+
+/*
+ * AR5K REGISTER ACCESS
+ */
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define AR5K_REG_SM(_val, _flags)					\
+	(((_val) << _flags##_S) & (_flags))
+
+/* First mask, then shift */
+#define AR5K_REG_MS(_val, _flags)					\
+	(((_val) & (_flags)) >> _flags##_S)
+
+/* Some registers can hold multiple values of interest. For this
+ * reason when we want to write to these registers we must first
+ * retrieve the values which we do not want to clear (lets call this
+ * old_data) and then set the register with this and our new_value:
+ * ( old_data | new_value) */
+#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
+	    (((_val) << _flags##_S) & (_flags)), _reg)
+
+#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
+			(_mask)) | (_flags), _reg)
+
+#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
+
+#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
+
+/* Access to PHY registers */
+#define AR5K_PHY_READ(ah, _reg)					\
+	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_PHY_WRITE(ah, _reg, _val)					\
+	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
+
+/* Access QCU registers per queue */
+#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
+	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
+
+#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
+	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
+
+#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
+	_reg |= 1 << _queue;						\
+} while (0)
+
+#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
+	_reg &= ~(1 << _queue);						\
+} while (0)
+
+/* Used while writing initvals */
+#define AR5K_REG_WAIT(_i) do {						\
+	if (_i % 64)							\
+		udelay(1);						\
+} while (0)
+
+/* Register dumps are done per operation mode */
+#define AR5K_INI_RFGAIN_5GHZ		0
+#define AR5K_INI_RFGAIN_2GHZ		1
+
+/* TODO: Clean this up */
+#define AR5K_INI_VAL_11A		0
+#define AR5K_INI_VAL_11A_TURBO		1
+#define AR5K_INI_VAL_11B		2
+#define AR5K_INI_VAL_11G		3
+#define AR5K_INI_VAL_11G_TURBO		4
+#define AR5K_INI_VAL_XR			0
+#define AR5K_INI_VAL_MAX		5
+
+/* Used for BSSID etc manipulation */
+#define AR5K_LOW_ID(_a)(				\
+(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
+)
+
+#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
+
+#define IEEE80211_MAX_LEN	2352
+
+/*
+ * Some tuneable values (these should be changeable by the user)
+ */
+#define AR5K_TUNE_DMA_BEACON_RESP		2
+#define AR5K_TUNE_SW_BEACON_RESP		10
+#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
+#define AR5K_TUNE_RADAR_ALERT			0
+#define AR5K_TUNE_MIN_TX_FIFO_THRES		1
+#define AR5K_TUNE_MAX_TX_FIFO_THRES		((IEEE80211_MAX_LEN / 64) + 1)
+#define AR5K_TUNE_REGISTER_TIMEOUT		20000
+/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
+ * be the max value. */
+#define AR5K_TUNE_RSSI_THRES			129
+/* This must be set when setting the RSSI threshold otherwise it can
+ * prevent a reset. If AR5K_RSSI_THR is read after writing to it
+ * the BMISS_THRES will be seen as 0, seems harware doesn't keep
+ * track of it. Max value depends on harware. For AR5210 this is just 7.
+ * For AR5211+ this seems to be up to 255. */
+#define AR5K_TUNE_BMISS_THRES			7
+#define AR5K_TUNE_REGISTER_DWELL_TIME		20000
+#define AR5K_TUNE_BEACON_INTERVAL		100
+#define AR5K_TUNE_AIFS				2
+#define AR5K_TUNE_AIFS_11B			2
+#define AR5K_TUNE_AIFS_XR			0
+#define AR5K_TUNE_CWMIN				15
+#define AR5K_TUNE_CWMIN_11B			31
+#define AR5K_TUNE_CWMIN_XR			3
+#define AR5K_TUNE_CWMAX				1023
+#define AR5K_TUNE_CWMAX_11B			1023
+#define AR5K_TUNE_CWMAX_XR			7
+#define AR5K_TUNE_NOISE_FLOOR			-72
+#define AR5K_TUNE_MAX_TXPOWER			63
+#define AR5K_TUNE_DEFAULT_TXPOWER		25
+#define AR5K_TUNE_TPC_TXPOWER			0
+#define AR5K_TUNE_ANT_DIVERSITY			1
+#define AR5K_TUNE_HWTXTRIES			4
+
+#define AR5K_INIT_CARR_SENSE_EN			1
+
+/*Swap RX/TX Descriptor for big endian archs*/
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define AR5K_INIT_CFG	(		\
+	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
+)
+#else
+#define AR5K_INIT_CFG	0x00000000
+#endif
+
+/* Initial values */
+#define	AR5K_INIT_CYCRSSI_THR1			2
+#define AR5K_INIT_TX_LATENCY			502
+#define AR5K_INIT_USEC				39
+#define AR5K_INIT_USEC_TURBO			79
+#define AR5K_INIT_USEC_32			31
+#define AR5K_INIT_SLOT_TIME			396
+#define AR5K_INIT_SLOT_TIME_TURBO		480
+#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
+#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
+#define AR5K_INIT_PROG_IFS			920
+#define AR5K_INIT_PROG_IFS_TURBO		960
+#define AR5K_INIT_EIFS				3440
+#define AR5K_INIT_EIFS_TURBO			6880
+#define AR5K_INIT_SIFS				560
+#define AR5K_INIT_SIFS_TURBO			480
+#define AR5K_INIT_SH_RETRY			10
+#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
+#define AR5K_INIT_SSH_RETRY			32
+#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
+#define AR5K_INIT_TX_RETRY			10
+
+#define AR5K_INIT_TRANSMIT_LATENCY		(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC)						\
+)
+#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC_TURBO)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
+	(AR5K_INIT_PROG_IFS)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
+	(AR5K_INIT_PROG_IFS_TURBO)					\
+)
+
+/* token to use for aifs, cwmin, cwmax in MadWiFi */
+#define	AR5K_TXQ_USEDEFAULT	((u32) -1)
+
+/* GENERIC CHIPSET DEFINITIONS */
+
+/* MAC Chips */
+enum ath5k_version {
+	AR5K_AR5210	= 0,
+	AR5K_AR5211	= 1,
+	AR5K_AR5212	= 2,
+};
+
+/* PHY Chips */
+enum ath5k_radio {
+	AR5K_RF5110	= 0,
+	AR5K_RF5111	= 1,
+	AR5K_RF5112	= 2,
+	AR5K_RF2413	= 3,
+	AR5K_RF5413	= 4,
+	AR5K_RF2316	= 5,
+	AR5K_RF2317	= 6,
+	AR5K_RF2425	= 7,
+};
+
+/*
+ * Common silicon revision/version values
+ */
+
+enum ath5k_srev_type {
+	AR5K_VERSION_MAC,
+	AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+	const char		*sr_name;
+	enum ath5k_srev_type	sr_type;
+	unsigned		sr_val;
+};
+
+#define AR5K_SREV_UNKNOWN	0xffff
+
+#define AR5K_SREV_AR5210	0x00 /* Crete */
+#define AR5K_SREV_AR5311	0x10 /* Maui 1 */
+#define AR5K_SREV_AR5311A	0x20 /* Maui 2 */
+#define AR5K_SREV_AR5311B	0x30 /* Spirit */
+#define AR5K_SREV_AR5211	0x40 /* Oahu */
+#define AR5K_SREV_AR5212	0x50 /* Venice */
+#define AR5K_SREV_AR5213	0x55 /* ??? */
+#define AR5K_SREV_AR5213A	0x59 /* Hainan */
+#define AR5K_SREV_AR2413	0x78 /* Griffin lite */
+#define AR5K_SREV_AR2414	0x70 /* Griffin */
+#define AR5K_SREV_AR5424	0x90 /* Condor */
+#define AR5K_SREV_AR5413	0xa4 /* Eagle lite */
+#define AR5K_SREV_AR5414	0xa0 /* Eagle */
+#define AR5K_SREV_AR2415	0xb0 /* Talon */
+#define AR5K_SREV_AR5416	0xc0 /* PCI-E */
+#define AR5K_SREV_AR5418	0xca /* PCI-E */
+#define AR5K_SREV_AR2425	0xe0 /* Swan */
+#define AR5K_SREV_AR2417	0xf0 /* Nala */
+
+#define AR5K_SREV_RAD_5110	0x00
+#define AR5K_SREV_RAD_5111	0x10
+#define AR5K_SREV_RAD_5111A	0x15
+#define AR5K_SREV_RAD_2111	0x20
+#define AR5K_SREV_RAD_5112	0x30
+#define AR5K_SREV_RAD_5112A	0x35
+#define	AR5K_SREV_RAD_5112B	0x36
+#define AR5K_SREV_RAD_2112	0x40
+#define AR5K_SREV_RAD_2112A	0x45
+#define	AR5K_SREV_RAD_2112B	0x46
+#define AR5K_SREV_RAD_2413	0x50
+#define AR5K_SREV_RAD_5413	0x60
+#define AR5K_SREV_RAD_2316	0x70 /* Cobra SoC */
+#define AR5K_SREV_RAD_2317	0x80
+#define AR5K_SREV_RAD_5424	0xa0 /* Mostly same as 5413 */
+#define AR5K_SREV_RAD_2425	0xa2
+#define AR5K_SREV_RAD_5133	0xc0
+
+#define AR5K_SREV_PHY_5211	0x30
+#define AR5K_SREV_PHY_5212	0x41
+#define	AR5K_SREV_PHY_5212A	0x42
+#define AR5K_SREV_PHY_5212B	0x43
+#define AR5K_SREV_PHY_2413	0x45
+#define AR5K_SREV_PHY_5413	0x61
+#define AR5K_SREV_PHY_2425	0x70
+
+/*
+ * Some of this information is based on Documentation from:
+ *
+ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
+ *
+ * Modulation for Atheros' eXtended Range - range enhancing extension that is
+ * supposed to double the distance an Atheros client device can keep a
+ * connection with an Atheros access point. This is achieved by increasing
+ * the receiver sensitivity up to, -105dBm, which is about 20dB above what
+ * the 802.11 specifications demand. In addition, new (proprietary) data rates
+ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
+ *
+ * Please note that can you either use XR or TURBO but you cannot use both,
+ * they are exclusive.
+ *
+ */
+#define MODULATION_XR 		0x00000200
+
+/*
+ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
+ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
+ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
+ * channels. To use this feature your Access Point must also suport it.
+ * There is also a distinction between "static" and "dynamic" turbo modes:
+ *
+ * - Static: is the dumb version: devices set to this mode stick to it until
+ *     the mode is turned off.
+ * - Dynamic: is the intelligent version, the network decides itself if it
+ *     is ok to use turbo. As soon as traffic is detected on adjacent channels
+ *     (which would get used in turbo mode), or when a non-turbo station joins
+ *     the network, turbo mode won't be used until the situation changes again.
+ *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
+ *     monitors the used radio band in order to decide whether turbo mode may
+ *     be used or not.
+ *
+ * This article claims Super G sticks to bonding of channels 5 and 6 for
+ * USA:
+ *
+ * http://www.pcworld.com/article/id,113428-page,1/article.html
+ *
+ * The channel bonding seems to be driver specific though. In addition to
+ * deciding what channels will be used, these "Turbo" modes are accomplished
+ * by also enabling the following features:
+ *
+ * - Bursting: allows multiple frames to be sent at once, rather than pausing
+ *     after each frame. Bursting is a standards-compliant feature that can be
+ *     used with any Access Point.
+ * - Fast frames: increases the amount of information that can be sent per
+ *     frame, also resulting in a reduction of transmission overhead. It is a
+ *     proprietary feature that needs to be supported by the Access Point.
+ * - Compression: data frames are compressed in real time using a Lempel Ziv
+ *     algorithm. This is done transparently. Once this feature is enabled,
+ *     compression and decompression takes place inside the chipset, without
+ *     putting additional load on the host CPU.
+ *
+ */
+#define MODULATION_TURBO	0x00000080
+
+enum ath5k_driver_mode {
+	AR5K_MODE_11A		= 0,
+	AR5K_MODE_11A_TURBO	= 1,
+	AR5K_MODE_11B		= 2,
+	AR5K_MODE_11G		= 3,
+	AR5K_MODE_11G_TURBO	= 4,
+	AR5K_MODE_XR		= 5,
+};
+
+enum {
+	AR5K_MODE_BIT_11A	= (1 << AR5K_MODE_11A),
+	AR5K_MODE_BIT_11A_TURBO	= (1 << AR5K_MODE_11A_TURBO),
+	AR5K_MODE_BIT_11B	= (1 << AR5K_MODE_11B),
+	AR5K_MODE_BIT_11G	= (1 << AR5K_MODE_11G),
+	AR5K_MODE_BIT_11G_TURBO	= (1 << AR5K_MODE_11G_TURBO),
+	AR5K_MODE_BIT_XR	= (1 << AR5K_MODE_XR),
+};
+
+/****************\
+  TX DEFINITIONS
+\****************/
+
+/*
+ * TX Status descriptor
+ */
+struct ath5k_tx_status {
+	u16	ts_seqnum;
+	u16	ts_tstamp;
+	u8	ts_status;
+	u8	ts_rate[4];
+	u8	ts_retry[4];
+	u8	ts_final_idx;
+	s8	ts_rssi;
+	u8	ts_shortretry;
+	u8	ts_longretry;
+	u8	ts_virtcol;
+	u8	ts_antenna;
+} __attribute__ ((packed));
+
+#define AR5K_TXSTAT_ALTRATE	0x80
+#define AR5K_TXERR_XRETRY	0x01
+#define AR5K_TXERR_FILT		0x02
+#define AR5K_TXERR_FIFO		0x04
+
+/**
+ * enum ath5k_tx_queue - Queue types used to classify tx queues.
+ * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
+ * @AR5K_TX_QUEUE_DATA: A normal data queue
+ * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
+ * @AR5K_TX_QUEUE_BEACON: The beacon queue
+ * @AR5K_TX_QUEUE_CAB: The after-beacon queue
+ * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
+ */
+enum ath5k_tx_queue {
+	AR5K_TX_QUEUE_INACTIVE = 0,
+	AR5K_TX_QUEUE_DATA,
+	AR5K_TX_QUEUE_XR_DATA,
+	AR5K_TX_QUEUE_BEACON,
+	AR5K_TX_QUEUE_CAB,
+	AR5K_TX_QUEUE_UAPSD,
+};
+
+/*
+ * Queue syb-types to classify normal data queues.
+ * These are the 4 Access Categories as defined in
+ * WME spec. 0 is the lowest priority and 4 is the
+ * highest. Normal data that hasn't been classified
+ * goes to the Best Effort AC.
+ */
+enum ath5k_tx_queue_subtype {
+	AR5K_WME_AC_BK = 0,	/*Background traffic*/
+	AR5K_WME_AC_BE, 	/*Best-effort (normal) traffic)*/
+	AR5K_WME_AC_VI, 	/*Video traffic*/
+	AR5K_WME_AC_VO, 	/*Voice traffic*/
+};
+
+/*
+ * Queue ID numbers as returned by the hw functions, each number
+ * represents a hw queue. If hw does not support hw queues
+ * (eg 5210) all data goes in one queue. These match
+ * d80211 definitions (net80211/MadWiFi don't use them).
+ */
+enum ath5k_tx_queue_id {
+	AR5K_TX_QUEUE_ID_NOQCU_DATA	= 0,
+	AR5K_TX_QUEUE_ID_NOQCU_BEACON	= 1,
+	AR5K_TX_QUEUE_ID_DATA_MIN	= 0, /*IEEE80211_TX_QUEUE_DATA0*/
+	AR5K_TX_QUEUE_ID_DATA_MAX	= 4, /*IEEE80211_TX_QUEUE_DATA4*/
+	AR5K_TX_QUEUE_ID_DATA_SVP	= 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
+	AR5K_TX_QUEUE_ID_CAB		= 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
+	AR5K_TX_QUEUE_ID_BEACON		= 7, /*IEEE80211_TX_QUEUE_BEACON*/
+	AR5K_TX_QUEUE_ID_UAPSD		= 8,
+	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
+};
+
+/*
+ * Flags to set hw queue's parameters...
+ */
+#define AR5K_TXQ_FLAG_TXOKINT_ENABLE		0x0001	/* Enable TXOK interrupt */
+#define AR5K_TXQ_FLAG_TXERRINT_ENABLE		0x0002	/* Enable TXERR interrupt */
+#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
+#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE		0x0020	/* Enable CBRORN interrupt */
+#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE		0x0040	/* Enable CBRURN interrupt */
+#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE		0x0080	/* Enable QTRIG interrupt */
+#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE		0x0100	/* Enable TXNOFRM interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0200	/* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0300	/* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0800	/* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x1000	/* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x2000	/* Enable hw compression -not implemented-*/
+
+/*
+ * A struct to hold tx queue's parameters
+ */
+struct ath5k_txq_info {
+	enum ath5k_tx_queue tqi_type;
+	enum ath5k_tx_queue_subtype tqi_subtype;
+	u16	tqi_flags;	/* Tx queue flags (see above) */
+	u32	tqi_aifs;	/* Arbitrated Interframe Space */
+	s32	tqi_cw_min;	/* Minimum Contention Window */
+	s32	tqi_cw_max;	/* Maximum Contention Window */
+	u32	tqi_cbr_period; /* Constant bit rate period */
+	u32	tqi_cbr_overflow_limit;
+	u32	tqi_burst_time;
+	u32	tqi_ready_time; /* Not used */
+};
+
+/*
+ * Transmit packet types.
+ * used on tx control descriptor
+ * TODO: Use them inside base.c corectly
+ */
+enum ath5k_pkt_type {
+	AR5K_PKT_TYPE_NORMAL		= 0,
+	AR5K_PKT_TYPE_ATIM		= 1,
+	AR5K_PKT_TYPE_PSPOLL		= 2,
+	AR5K_PKT_TYPE_BEACON		= 3,
+	AR5K_PKT_TYPE_PROBE_RESP	= 4,
+	AR5K_PKT_TYPE_PIFS		= 5,
+};
+
+/*
+ * TX power and TPC settings
+ */
+#define AR5K_TXPOWER_OFDM(_r, _v)	(			\
+	((0 & 1) << ((_v) + 6)) |				\
+	(((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v))	\
+)
+
+#define AR5K_TXPOWER_CCK(_r, _v)	(			\
+	(ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v)	\
+)
+
+/*
+ * DMA size definitions (2^n+2)
+ */
+enum ath5k_dmasize {
+	AR5K_DMASIZE_4B	= 0,
+	AR5K_DMASIZE_8B,
+	AR5K_DMASIZE_16B,
+	AR5K_DMASIZE_32B,
+	AR5K_DMASIZE_64B,
+	AR5K_DMASIZE_128B,
+	AR5K_DMASIZE_256B,
+	AR5K_DMASIZE_512B
+};
+
+
+/****************\
+  RX DEFINITIONS
+\****************/
+
+/*
+ * RX Status descriptor
+ */
+struct ath5k_rx_status {
+	u16	rs_datalen;
+	u16	rs_tstamp;
+	u8	rs_status;
+	u8	rs_phyerr;
+	s8	rs_rssi;
+	u8	rs_keyix;
+	u8	rs_rate;
+	u8	rs_antenna;
+	u8	rs_more;
+};
+
+#define AR5K_RXERR_CRC		0x01
+#define AR5K_RXERR_PHY		0x02
+#define AR5K_RXERR_FIFO		0x04
+#define AR5K_RXERR_DECRYPT	0x08
+#define AR5K_RXERR_MIC		0x10
+#define AR5K_RXKEYIX_INVALID	((u8) - 1)
+#define AR5K_TXKEYIX_INVALID	((u32) - 1)
+
+
+/*
+ * TSF to TU conversion:
+ *
+ * TSF is a 64bit value in usec (microseconds).
+ * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of
+ * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024).
+ */
+#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
+
+
+/*******************************\
+  GAIN OPTIMIZATION DEFINITIONS
+\*******************************/
+
+enum ath5k_rfgain {
+	AR5K_RFGAIN_INACTIVE = 0,
+	AR5K_RFGAIN_ACTIVE,
+	AR5K_RFGAIN_READ_REQUESTED,
+	AR5K_RFGAIN_NEED_CHANGE,
+};
+
+struct ath5k_gain {
+	u8			g_step_idx;
+	u8			g_current;
+	u8			g_target;
+	u8			g_low;
+	u8			g_high;
+	u8			g_f_corr;
+	u8			g_state;
+};
+
+/********************\
+  COMMON DEFINITIONS
+\********************/
+
+#define AR5K_SLOT_TIME_9	396
+#define AR5K_SLOT_TIME_20	880
+#define AR5K_SLOT_TIME_MAX	0xffff
+
+/* channel_flags */
+#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
+#define	CHANNEL_TURBO	0x0010	/* Turbo Channel */
+#define	CHANNEL_CCK	0x0020	/* CCK channel */
+#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
+#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
+#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
+#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
+#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
+#define	CHANNEL_XR	0x0800	/* XR channel */
+
+#define	CHANNEL_A	(CHANNEL_5GHZ|CHANNEL_OFDM)
+#define	CHANNEL_B	(CHANNEL_2GHZ|CHANNEL_CCK)
+#define	CHANNEL_G	(CHANNEL_2GHZ|CHANNEL_OFDM)
+#define	CHANNEL_T	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_TG	(CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_108A	CHANNEL_T
+#define	CHANNEL_108G	CHANNEL_TG
+#define	CHANNEL_X	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+
+#define	CHANNEL_ALL 	(CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
+		CHANNEL_TURBO)
+
+#define	CHANNEL_ALL_NOTURBO 	(CHANNEL_ALL & ~CHANNEL_TURBO)
+#define CHANNEL_MODES		CHANNEL_ALL
+
+/*
+ * Used internaly for reset_tx_queue).
+ * Also see struct struct net80211_channel.
+ */
+#define IS_CHAN_XR(_c)	((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c)	((_c->hw_value & CHANNEL_B) != 0)
+
+/*
+ * The following structure is used to map 2GHz channels to
+ * 5GHz Atheros channels.
+ * TODO: Clean up
+ */
+struct ath5k_athchan_2ghz {
+	u32	a2_flags;
+	u16	a2_athchan;
+};
+
+
+/******************\
+  RATE DEFINITIONS
+\******************/
+
+/**
+ * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
+ *
+ * The rate code is used to get the RX rate or set the TX rate on the
+ * hardware descriptors. It is also used for internal modulation control
+ * and settings.
+ *
+ * This is the hardware rate map we are aware of:
+ *
+ * rate_code   0x01    0x02    0x03    0x04    0x05    0x06    0x07    0x08
+ * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
+ *
+ * rate_code   0x09    0x0A    0x0B    0x0C    0x0D    0x0E    0x0F    0x10
+ * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
+ *
+ * rate_code   17      18      19      20      21      22      23      24
+ * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
+ *
+ * rate_code   25      26      27      28      29      30      31      32
+ * rate_kbps   5500    2000    1000    11000S  5500S   2000S   ?       ?
+ *
+ * "S" indicates CCK rates with short preamble.
+ *
+ * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
+ * lowest 4 bits, so they are the same as below with a 0xF mask.
+ * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
+ * We handle this in ath5k_setup_bands().
+ */
+#define AR5K_MAX_RATES 32
+
+/* B */
+#define ATH5K_RATE_CODE_1M	0x1B
+#define ATH5K_RATE_CODE_2M	0x1A
+#define ATH5K_RATE_CODE_5_5M	0x19
+#define ATH5K_RATE_CODE_11M	0x18
+/* A and G */
+#define ATH5K_RATE_CODE_6M	0x0B
+#define ATH5K_RATE_CODE_9M	0x0F
+#define ATH5K_RATE_CODE_12M	0x0A
+#define ATH5K_RATE_CODE_18M	0x0E
+#define ATH5K_RATE_CODE_24M	0x09
+#define ATH5K_RATE_CODE_36M	0x0D
+#define ATH5K_RATE_CODE_48M	0x08
+#define ATH5K_RATE_CODE_54M	0x0C
+/* XR */
+#define ATH5K_RATE_CODE_XR_500K	0x07
+#define ATH5K_RATE_CODE_XR_1M	0x02
+#define ATH5K_RATE_CODE_XR_2M	0x06
+#define ATH5K_RATE_CODE_XR_3M	0x01
+
+/* adding this flag to rate_code enables short preamble */
+#define AR5K_SET_SHORT_PREAMBLE 0x04
+
+/*
+ * Crypto definitions
+ */
+
+#define AR5K_KEYCACHE_SIZE	8
+
+/***********************\
+ HW RELATED DEFINITIONS
+\***********************/
+
+/*
+ * Misc definitions
+ */
+#define	AR5K_RSSI_EP_MULTIPLIER	(1<<7)
+
+#define AR5K_ASSERT_ENTRY(_e, _s) do {		\
+	if (_e >= _s)				\
+		return 0;			\
+} while (0)
+
+/*
+ * Hardware interrupt abstraction
+ */
+
+/**
+ * enum ath5k_int - Hardware interrupt masks helpers
+ *
+ * @AR5K_INT_RX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_RXOK or AR5K_ISR_RXERR
+ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
+ * @AR5K_INT_RXNOFRM: No frame received (?)
+ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
+ * 	Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
+ * 	LinkPtr is NULL. For more details, refer to:
+ * 	http://www.freepatentsonline.com/20030225739.html
+ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
+ * 	Note that Rx overrun is not always fatal, on some chips we can continue
+ * 	operation without reseting the card, that's why int_fatal is not
+ * 	common for all chips.
+ * @AR5K_INT_TX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_TXOK or AR5K_ISR_TXERR
+ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
+ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
+ * 	We currently do increments on interrupt by
+ * 	(AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
+ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
+ * 	checked. We should do this with ath5k_hw_update_mib_counters() but
+ * 	it seems we should also then do some noise immunity work.
+ * @AR5K_INT_RXPHY: RX PHY Error
+ * @AR5K_INT_RXKCM: RX Key cache miss
+ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
+ * 	beacon that must be handled in software. The alternative is if you
+ * 	have VEOL support, in that case you let the hardware deal with things.
+ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
+ * 	beacons from the AP have associated with, we should probably try to
+ * 	reassociate. When in IBSS mode this might mean we have not received
+ * 	any beacons from any local stations. Note that every station in an
+ * 	IBSS schedules to send beacons at the Target Beacon Transmission Time
+ * 	(TBTT) with a random backoff.
+ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
+ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
+ * 	until properly handled
+ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
+ * 	errors. These types of errors we can enable seem to be of type
+ * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ * @AR5K_INT_GLOBAL: Used to clear and set the IER
+ * @AR5K_INT_NOCARD: signals the card has been removed
+ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
+ * 	bit value
+ *
+ * These are mapped to take advantage of some common bits
+ * between the MACs, to be able to set intr properties
+ * easier. Some of them are not used yet inside hw.c. Most map
+ * to the respective hw interrupt value as they are common amogst different
+ * MACs.
+ */
+enum ath5k_int {
+	AR5K_INT_RXOK	= 0x00000001,
+	AR5K_INT_RXDESC	= 0x00000002,
+	AR5K_INT_RXERR	= 0x00000004,
+	AR5K_INT_RXNOFRM = 0x00000008,
+	AR5K_INT_RXEOL	= 0x00000010,
+	AR5K_INT_RXORN	= 0x00000020,
+	AR5K_INT_TXOK	= 0x00000040,
+	AR5K_INT_TXDESC	= 0x00000080,
+	AR5K_INT_TXERR	= 0x00000100,
+	AR5K_INT_TXNOFRM = 0x00000200,
+	AR5K_INT_TXEOL	= 0x00000400,
+	AR5K_INT_TXURN	= 0x00000800,
+	AR5K_INT_MIB	= 0x00001000,
+	AR5K_INT_SWI	= 0x00002000,
+	AR5K_INT_RXPHY	= 0x00004000,
+	AR5K_INT_RXKCM	= 0x00008000,
+	AR5K_INT_SWBA	= 0x00010000,
+	AR5K_INT_BRSSI	= 0x00020000,
+	AR5K_INT_BMISS	= 0x00040000,
+	AR5K_INT_FATAL	= 0x00080000, /* Non common */
+	AR5K_INT_BNR	= 0x00100000, /* Non common */
+	AR5K_INT_TIM	= 0x00200000, /* Non common */
+	AR5K_INT_DTIM	= 0x00400000, /* Non common */
+	AR5K_INT_DTIM_SYNC =	0x00800000, /* Non common */
+	AR5K_INT_GPIO	=	0x01000000,
+	AR5K_INT_BCN_TIMEOUT =	0x02000000, /* Non common */
+	AR5K_INT_CAB_TIMEOUT =	0x04000000, /* Non common */
+	AR5K_INT_RX_DOPPLER =	0x08000000, /* Non common */
+	AR5K_INT_QCBRORN =	0x10000000, /* Non common */
+	AR5K_INT_QCBRURN =	0x20000000, /* Non common */
+	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
+	AR5K_INT_GLOBAL =	0x80000000,
+
+	AR5K_INT_COMMON  = AR5K_INT_RXOK
+		| AR5K_INT_RXDESC
+		| AR5K_INT_RXERR
+		| AR5K_INT_RXNOFRM
+		| AR5K_INT_RXEOL
+		| AR5K_INT_RXORN
+		| AR5K_INT_TXOK
+		| AR5K_INT_TXDESC
+		| AR5K_INT_TXERR
+		| AR5K_INT_TXNOFRM
+		| AR5K_INT_TXEOL
+		| AR5K_INT_TXURN
+		| AR5K_INT_MIB
+		| AR5K_INT_SWI
+		| AR5K_INT_RXPHY
+		| AR5K_INT_RXKCM
+		| AR5K_INT_SWBA
+		| AR5K_INT_BRSSI
+		| AR5K_INT_BMISS
+		| AR5K_INT_GPIO
+		| AR5K_INT_GLOBAL,
+
+	AR5K_INT_NOCARD	= 0xffffffff
+};
+
+/*
+ * Power management
+ */
+enum ath5k_power_mode {
+	AR5K_PM_UNDEFINED = 0,
+	AR5K_PM_AUTO,
+	AR5K_PM_AWAKE,
+	AR5K_PM_FULL_SLEEP,
+	AR5K_PM_NETWORK_SLEEP,
+};
+
+/* GPIO-controlled software LED */
+#define AR5K_SOFTLED_PIN	0
+#define AR5K_SOFTLED_ON		0
+#define AR5K_SOFTLED_OFF	1
+
+/*
+ * Chipset capabilities -see ath5k_hw_get_capability-
+ * get_capability function is not yet fully implemented
+ * in ath5k so most of these don't work yet...
+ * TODO: Implement these & merge with _TUNE_ stuff above
+ */
+enum ath5k_capability_type {
+	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
+	AR5K_CAP_TKIP_MIC		= 2,	/* Can handle TKIP MIC in hardware */
+	AR5K_CAP_TKIP_SPLIT		= 3,	/* TKIP uses split keys */
+	AR5K_CAP_PHYCOUNTERS		= 4,	/* PHY error counters */
+	AR5K_CAP_DIVERSITY		= 5,	/* Supports fast diversity */
+	AR5K_CAP_NUM_TXQUEUES		= 6,	/* Used to get max number of hw txqueues */
+	AR5K_CAP_VEOL			= 7,	/* Supports virtual EOL */
+	AR5K_CAP_COMPRESSION		= 8,	/* Supports compression */
+	AR5K_CAP_BURST			= 9,	/* Supports packet bursting */
+	AR5K_CAP_FASTFRAME		= 10,	/* Supports fast frames */
+	AR5K_CAP_TXPOW			= 11,	/* Used to get global tx power limit */
+	AR5K_CAP_TPC			= 12,	/* Can do per-packet tx power control (needed for 802.11a) */
+	AR5K_CAP_BSSIDMASK		= 13,	/* Supports bssid mask */
+	AR5K_CAP_MCAST_KEYSRCH		= 14,	/* Supports multicast key search */
+	AR5K_CAP_TSF_ADJUST		= 15,	/* Supports beacon tsf adjust */
+	AR5K_CAP_XR			= 16,	/* Supports XR mode */
+	AR5K_CAP_WME_TKIPMIC 		= 17,	/* Supports TKIP MIC when using WMM */
+	AR5K_CAP_CHAN_HALFRATE 		= 18,	/* Supports half rate channels */
+	AR5K_CAP_CHAN_QUARTERRATE 	= 19,	/* Supports quarter rate channels */
+	AR5K_CAP_RFSILENT		= 20,	/* Supports RFsilent */
+};
+
+
+/* XXX: we *may* move cap_range stuff to struct wiphy */
+struct ath5k_capabilities {
+	/*
+	 * Supported PHY modes
+	 * (ie. CHANNEL_A, CHANNEL_B, ...)
+	 */
+	u16 cap_mode;
+
+	/*
+	 * Frequency range (without regulation restrictions)
+	 */
+	struct {
+		u16	range_2ghz_min;
+		u16	range_2ghz_max;
+		u16	range_5ghz_min;
+		u16	range_5ghz_max;
+	} cap_range;
+
+	/*
+	 * Values stored in the EEPROM (some of them...)
+	 */
+	struct ath5k_eeprom_info	cap_eeprom;
+
+	/*
+	 * Queue information
+	 */
+	struct {
+		u8	q_tx_num;
+	} cap_queues;
+};
+
+
+/***************************************\
+  HARDWARE ABSTRACTION LAYER STRUCTURE
+\***************************************/
+
+/*
+ * Misc defines
+ */
+
+#define AR5K_MAX_GPIO		10
+#define AR5K_MAX_RF_BANKS	8
+
+/* TODO: Clean up and merge with ath5k_softc */
+struct ath5k_hw {
+	struct ath5k_softc	*ah_sc;
+	void			*ah_iobase;
+
+	enum ath5k_int		ah_imr;
+	int			ah_ier;
+
+	struct net80211_channel	*ah_current_channel;
+	int			ah_turbo;
+	int			ah_calibration;
+	int			ah_running;
+	int			ah_single_chip;
+	int			ah_combined_mic;
+
+	u32			ah_mac_srev;
+	u16			ah_mac_version;
+	u16			ah_mac_revision;
+	u16			ah_phy_revision;
+	u16			ah_radio_5ghz_revision;
+	u16			ah_radio_2ghz_revision;
+
+	enum ath5k_version	ah_version;
+	enum ath5k_radio	ah_radio;
+	u32			ah_phy;
+
+	int			ah_5ghz;
+	int			ah_2ghz;
+
+#define ah_regdomain		ah_capabilities.cap_regdomain.reg_current
+#define ah_regdomain_hw		ah_capabilities.cap_regdomain.reg_hw
+#define ah_modes		ah_capabilities.cap_mode
+#define ah_ee_version		ah_capabilities.cap_eeprom.ee_version
+
+	u32			ah_atim_window;
+	u32			ah_aifs;
+	u32			ah_cw_min;
+	u32			ah_cw_max;
+	int			ah_software_retry;
+	u32			ah_limit_tx_retries;
+
+	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+	int			ah_ant_diversity;
+
+	u8			ah_sta_id[ETH_ALEN];
+
+	/* Current BSSID we are trying to assoc to / create.
+	 * This is passed by mac80211 on config_interface() and cached here for
+	 * use in resets */
+	u8			ah_bssid[ETH_ALEN];
+	u8			ah_bssid_mask[ETH_ALEN];
+
+	u32			ah_gpio[AR5K_MAX_GPIO];
+	int			ah_gpio_npins;
+
+	struct ath5k_capabilities ah_capabilities;
+
+	struct ath5k_txq_info	ah_txq;
+	u32			ah_txq_status;
+	u32			ah_txq_imr_txok;
+	u32			ah_txq_imr_txerr;
+	u32			ah_txq_imr_txurn;
+	u32			ah_txq_imr_txdesc;
+	u32			ah_txq_imr_txeol;
+	u32			ah_txq_imr_cbrorn;
+	u32			ah_txq_imr_cbrurn;
+	u32			ah_txq_imr_qtrig;
+	u32			ah_txq_imr_nofrm;
+	u32			ah_txq_isr;
+	u32			*ah_rf_banks;
+	size_t			ah_rf_banks_size;
+	size_t			ah_rf_regs_count;
+	struct ath5k_gain	ah_gain;
+	u8			ah_offset[AR5K_MAX_RF_BANKS];
+
+
+	struct {
+		/* Temporary tables used for interpolation */
+		u8		tmpL[AR5K_EEPROM_N_PD_GAINS]
+					[AR5K_EEPROM_POWER_TABLE_SIZE];
+		u8		tmpR[AR5K_EEPROM_N_PD_GAINS]
+					[AR5K_EEPROM_POWER_TABLE_SIZE];
+		u8		txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2];
+		u16		txp_rates_power_table[AR5K_MAX_RATES];
+		u8		txp_min_idx;
+		int		txp_tpc;
+		/* Values in 0.25dB units */
+		s16		txp_min_pwr;
+		s16		txp_max_pwr;
+		s16		txp_offset;
+		s16		txp_ofdm;
+		/* Values in dB units */
+		s16		txp_cck_ofdm_pwr_delta;
+		s16		txp_cck_ofdm_gainf_delta;
+	} ah_txpower;
+
+	/* noise floor from last periodic calibration */
+	s32			ah_noise_floor;
+
+	/*
+	 * Function pointers
+	 */
+	int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
+				u32 size, unsigned int flags);
+	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+		unsigned int, unsigned int, unsigned int, unsigned int,
+		unsigned int, unsigned int, unsigned int);
+	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		struct ath5k_tx_status *);
+	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		struct ath5k_rx_status *);
+};
+
+/*
+ * Prototypes
+ */
+
+extern int ath5k_bitrate_to_hw_rix(int bitrate);
+
+/* Attach/Detach Functions */
+extern int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version, struct ath5k_hw **ah);
+extern void ath5k_hw_detach(struct ath5k_hw *ah);
+
+/* LED functions */
+extern int ath5k_init_leds(struct ath5k_softc *sc);
+extern void ath5k_led_enable(struct ath5k_softc *sc);
+extern void ath5k_led_off(struct ath5k_softc *sc);
+extern void ath5k_unregister_leds(struct ath5k_softc *sc);
+
+/* Reset Functions */
+extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial);
+extern int ath5k_hw_reset(struct ath5k_hw *ah, struct net80211_channel *channel, int change_channel);
+/* Power management functions */
+extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, int set_chip, u16 sleep_duration);
+
+/* DMA Related Functions */
+extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
+extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
+extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
+				u32 phys_addr);
+extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase);
+/* Interrupt handling */
+extern int ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
+extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
+extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+
+/* EEPROM access functions */
+extern int ath5k_eeprom_init(struct ath5k_hw *ah);
+extern void ath5k_eeprom_detach(struct ath5k_hw *ah);
+extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
+
+/* Protocol Control Unit Functions */
+extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+/* BSSID Functions */
+extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+/* Receive start/stop functions */
+extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
+/* RX Filter functions */
+extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
+extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* ACK bit rate */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high);
+/* ACK/CTS Timeouts */
+extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
+extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Key table (WEP) functions */
+extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
+
+/* Queue Control Unit, DFS Control Unit Functions */
+extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, const struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
+				enum ath5k_tx_queue queue_type,
+				struct ath5k_txq_info *queue_info);
+extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah);
+extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah);
+extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah);
+extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+
+/* Hardware Descriptor Functions */
+extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+
+/* GPIO Functions */
+extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
+extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
+extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
+
+/* rfkill Functions */
+extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
+extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
+
+/* Misc functions */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
+extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
+extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
+
+/* Initial register settings functions */
+extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel);
+
+/* Initialize RF */
+extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+				struct net80211_channel *channel,
+				unsigned int mode);
+extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
+extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
+/* PHY/RF channel functions */
+extern int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+extern int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel);
+/* PHY calibration */
+extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct net80211_channel *channel);
+extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+/* Misc PHY functions */
+extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
+extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
+extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* TX power setup */
+extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel, u8 ee_mode, u8 txpower);
+extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower);
+
+/*
+ * Functions used internaly
+ */
+
+/*
+ * Translate usec to hw clock units
+ * TODO: Half/quarter rate
+ */
+static inline unsigned int ath5k_hw_htoclock(unsigned int usec, int turbo)
+{
+	return turbo ? (usec * 80) : (usec * 40);
+}
+
+/*
+ * Translate hw clock units to usec
+ * TODO: Half/quarter rate
+ */
+static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, int turbo)
+{
+	return turbo ? (clock / 80) : (clock / 40);
+}
+
+/*
+ * Read from a register
+ */
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+	return readl(ah->ah_iobase + reg);
+}
+
+/*
+ * Write to a register
+ */
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+	writel(val, ah->ah_iobase + reg);
+}
+
+#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
+/*
+ * Check if a register write has been completed
+ */
+static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
+		u32 val, int is_set)
+{
+	int i;
+	u32 data;
+
+	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+		data = ath5k_hw_reg_read(ah, reg);
+		if (is_set && (data & flag))
+			break;
+		else if ((data & flag) == val)
+			break;
+		udelay(15);
+	}
+
+	return (i <= 0) ? -EAGAIN : 0;
+}
+
+/*
+ * Convert channel frequency to channel number
+ */
+static inline int ath5k_freq_to_channel(int freq)
+{
+	if (freq == 2484)
+		return 14;
+
+	if (freq < 2484)
+		return (freq - 2407) / 5;
+
+	return freq/5 - 1000;
+}
+
+#endif
+
+static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
+{
+	u32 retval = 0, bit, i;
+
+	for (i = 0; i < bits; i++) {
+		bit = (val >> i) & 1;
+		retval = (retval << 1) | bit;
+	}
+
+	return retval;
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c
new file mode 100644
index 0000000..302536d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* Attach/Detach Functions and helpers *
+\*************************************/
+
+#include <ipxe/pci.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/**
+ * ath5k_hw_post - Power On Self Test helper function
+ *
+ * @ah: The &struct ath5k_hw
+ */
+static int ath5k_hw_post(struct ath5k_hw *ah)
+{
+
+	static const u32 static_pattern[4] = {
+		0x55555555,	0xaaaaaaaa,
+		0x66666666,	0x99999999
+	};
+	static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
+	int i, c;
+	u16 cur_reg;
+	u32 var_pattern;
+	u32 init_val;
+	u32 cur_val;
+
+	for (c = 0; c < 2; c++) {
+
+		cur_reg = regs[c];
+
+		/* Save previous value */
+		init_val = ath5k_hw_reg_read(ah, cur_reg);
+
+		for (i = 0; i < 256; i++) {
+			var_pattern = i << 16 | i;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				DBG("ath5k: POST failed!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x0039080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		for (i = 0; i < 4; i++) {
+			var_pattern = static_pattern[i];
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				DBG("ath5k: POST failed!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x003b080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		/* Restore previous value */
+		ath5k_hw_reg_write(ah, init_val, cur_reg);
+
+	}
+
+	return 0;
+
+}
+
+/**
+ * ath5k_hw_attach - Check if hw is supported and init the needed structs
+ *
+ * @sc: The &struct ath5k_softc we got from the driver's attach function
+ * @mac_version: The mac version id (check out ath5k.h) based on pci id
+ * @hw: Returned newly allocated hardware structure, on success
+ *
+ * Check if the device is supported, perform a POST and initialize the needed
+ * structs. Returns -ENOMEM if we don't have memory for the needed structs,
+ * -ENODEV if the device is not supported or prints an error msg if something
+ * else went wrong.
+ */
+int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version,
+		    struct ath5k_hw **hw)
+{
+	struct ath5k_hw *ah;
+	struct pci_device *pdev = sc->pdev;
+	int ret;
+	u32 srev;
+
+	ah = zalloc(sizeof(struct ath5k_hw));
+	if (ah == NULL) {
+		ret = -ENOMEM;
+		DBG("ath5k: out of memory\n");
+		goto err;
+	}
+
+	ah->ah_sc = sc;
+	ah->ah_iobase = sc->iobase;
+
+	/*
+	 * HW information
+	 */
+	ah->ah_turbo = 0;
+	ah->ah_txpower.txp_tpc = 0;
+	ah->ah_imr = 0;
+	ah->ah_atim_window = 0;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+	ah->ah_software_retry = 0;
+	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+	/*
+	 * Set the mac version based on the pci id
+	 */
+	ah->ah_version = mac_version;
+
+	/*Fill the ath5k_hw struct with the needed functions*/
+	ret = ath5k_hw_init_desc_functions(ah);
+	if (ret)
+		goto err_free;
+
+	/* Bring device out of sleep and reset it's units */
+	ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, 1);
+	if (ret)
+		goto err_free;
+
+	/* Get MAC, PHY and RADIO revisions */
+	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+	ah->ah_mac_srev = srev;
+	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID);
+	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ);
+	ah->ah_phy = AR5K_PHY(0);
+
+	/* Try to identify radio chip based on it's srev */
+	switch (ah->ah_radio_5ghz_revision & 0xf0) {
+	case AR5K_SREV_RAD_5111:
+		ah->ah_radio = AR5K_RF5111;
+		ah->ah_single_chip = 0;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		break;
+	case AR5K_SREV_RAD_5112:
+	case AR5K_SREV_RAD_2112:
+		ah->ah_radio = AR5K_RF5112;
+		ah->ah_single_chip = 0;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		break;
+	case AR5K_SREV_RAD_2413:
+		ah->ah_radio = AR5K_RF2413;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_5413:
+		ah->ah_radio = AR5K_RF5413;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_2316:
+		ah->ah_radio = AR5K_RF2316;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_2317:
+		ah->ah_radio = AR5K_RF2317;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_5424:
+		if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
+		    ah->ah_mac_version == AR5K_SREV_AR2417) {
+			ah->ah_radio = AR5K_RF2425;
+		} else {
+			ah->ah_radio = AR5K_RF5413;
+		}
+		ah->ah_single_chip = 1;
+		break;
+	default:
+		/* Identify radio based on mac/phy srev */
+		if (ah->ah_version == AR5K_AR5210) {
+			ah->ah_radio = AR5K_RF5110;
+			ah->ah_single_chip = 0;
+		} else if (ah->ah_version == AR5K_AR5211) {
+			ah->ah_radio = AR5K_RF5111;
+			ah->ah_single_chip = 0;
+			ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+								CHANNEL_2GHZ);
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
+			   ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
+			ah->ah_radio = AR5K_RF2425;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
+		} else if (srev == AR5K_SREV_AR5213A &&
+			   ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
+			ah->ah_radio = AR5K_RF5112;
+			ah->ah_single_chip = 0;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
+			ah->ah_radio = AR5K_RF2316;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
+			ah->ah_radio = AR5K_RF5413;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
+			ah->ah_radio = AR5K_RF2413;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
+		} else {
+			DBG("ath5k: Couldn't identify radio revision.\n");
+			ret = -ENOTSUP;
+			goto err_free;
+		}
+	}
+
+	/* Return on unsuported chips (unsupported eeprom etc) */
+	if ((srev >= AR5K_SREV_AR5416) &&
+	    (srev < AR5K_SREV_AR2425)) {
+		DBG("ath5k: Device not yet supported.\n");
+		ret = -ENOTSUP;
+		goto err_free;
+	}
+
+	/*
+	 * Write PCI-E power save settings
+	 */
+	if ((ah->ah_version == AR5K_AR5212) &&
+	    pci_find_capability(pdev, PCI_CAP_ID_EXP)) {
+		ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
+		/* Shut off RX when elecidle is asserted */
+		ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
+		/* TODO: EEPROM work */
+		ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
+		/* Shut off PLL and CLKREQ active in L1 */
+		ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
+		/* Preserce other settings */
+		ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
+		/* Reset SERDES to load new settings */
+		ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
+		mdelay(1);
+	}
+
+	/*
+	 * POST
+	 */
+	ret = ath5k_hw_post(ah);
+	if (ret)
+		goto err_free;
+
+	/* Enable pci core retry fix on Hainan (5213A) and later chips */
+	if (srev >= AR5K_SREV_AR5213A)
+		ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
+
+	/*
+	 * Get card capabilities, calibration values etc
+	 * TODO: EEPROM work
+	 */
+	ret = ath5k_eeprom_init(ah);
+	if (ret) {
+		DBG("ath5k: unable to init EEPROM\n");
+		goto err_free;
+	}
+
+	/* Get misc capabilities */
+	ret = ath5k_hw_set_capabilities(ah);
+	if (ret) {
+		DBG("ath5k: unable to get device capabilities: 0x%04x\n",
+		    sc->pdev->device);
+		goto err_free;
+	}
+
+	if (srev >= AR5K_SREV_AR2414) {
+		ah->ah_combined_mic = 1;
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
+				     AR5K_MISC_MODE_COMBINED_MIC);
+	}
+
+	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
+	memset(ah->ah_bssid, 0xff, ETH_ALEN);
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_rfgain_opt_init(ah);
+
+	*hw = ah;
+	return 0;
+err_free:
+	free(ah);
+err:
+	return ret;
+}
+
+/**
+ * ath5k_hw_detach - Free the ath5k_hw struct
+ *
+ * @ah: The &struct ath5k_hw
+ */
+void ath5k_hw_detach(struct ath5k_hw *ah)
+{
+	free(ah->ah_rf_banks);
+	ath5k_eeprom_detach(ah);
+	free(ah);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c
new file mode 100644
index 0000000..9c00d15
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/**************\
+* Capabilities *
+\**************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Fill the capabilities struct
+ * TODO: Merge this with EEPROM code when we are done with it
+ */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
+{
+	u16 ee_header;
+
+	/* Capabilities stored in the EEPROM */
+	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Set radio capabilities
+		 * (The AR5110 only supports the middle 5GHz band)
+		 */
+		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
+		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
+		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
+		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
+
+		/* Set supported modes */
+		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
+		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
+	} else {
+		/*
+		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+		 * XXX and from 2312 to 2732GHz. There are problems with the
+		 * XXX current ieee80211 implementation because the IEEE
+		 * XXX channel mapping does not support negative channel
+		 * XXX numbers (2312MHz is channel -19). Of course, this
+		 * XXX doesn't matter because these channels are out of range
+		 * XXX but some regulation domains like MKK (Japan) will
+		 * XXX support frequencies somewhere around 4.8GHz.
+		 */
+
+		/*
+		 * Set radio capabilities
+		 */
+
+		if (AR5K_EEPROM_HDR_11A(ee_header)) {
+			/* 4920 */
+			ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
+			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+			/* Set supported modes */
+			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
+			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
+			if (ah->ah_version == AR5K_AR5212)
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11G_TURBO;
+		}
+
+		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
+		 * connected */
+		if (AR5K_EEPROM_HDR_11B(ee_header) ||
+		    (AR5K_EEPROM_HDR_11G(ee_header) &&
+		     ah->ah_version != AR5K_AR5211)) {
+			/* 2312 */
+			ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
+			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+			if (AR5K_EEPROM_HDR_11B(ee_header))
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11B;
+
+			if (AR5K_EEPROM_HDR_11G(ee_header) &&
+			    ah->ah_version != AR5K_AR5211)
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11G;
+		}
+	}
+
+	/* GPIO */
+	ah->ah_gpio_npins = AR5K_NUM_GPIO;
+
+	/* Set number of supported TX queues */
+	ah->ah_capabilities.cap_queues.q_tx_num = 1;
+
+	return 0;
+}
+
+/* Main function used by the driver part to check caps */
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+		enum ath5k_capability_type cap_type,
+		u32 capability __unused, u32 *result)
+{
+	switch (cap_type) {
+	case AR5K_CAP_NUM_TXQUEUES:
+		if (result) {
+			*result = 1;
+			goto yes;
+		}
+	case AR5K_CAP_VEOL:
+		goto yes;
+	case AR5K_CAP_COMPRESSION:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_BURST:
+		goto yes;
+	case AR5K_CAP_TPC:
+		goto yes;
+	case AR5K_CAP_BSSIDMASK:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_XR:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	default:
+		goto no;
+	}
+
+no:
+	return -EINVAL;
+yes:
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c
new file mode 100644
index 0000000..30fe1c7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski at gnu.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/******************************\
+ Hardware Descriptor Functions
+\******************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * TX Descriptors
+ */
+
+#define FCS_LEN	4
+
+/*
+ * Initialize the 2-word tx control descriptor on 5210/5211
+ */
+static int
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+	unsigned int tx_power __unused, unsigned int tx_rate0, unsigned int tx_tries0,
+	unsigned int key_index __unused, unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate __unused, unsigned int rtscts_duration)
+{
+	u32 frame_type;
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (tx_tries0 == 0) {
+		DBG("ath5k: zero retries\n");
+		return -EINVAL;
+	}
+	if (tx_rate0 == 0) {
+		DBG("ath5k: zero rate\n");
+		return -EINVAL;
+	}
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	frame_len = pkt_len + FCS_LEN;
+
+	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+	/*
+	 * Verify and set header length
+	 * XXX: I only found that on 5210 code, does it work on 5211 ?
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+			return -EINVAL;
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+	}
+
+	/*Diferences between 5210-5211*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (type) {
+		case AR5K_PKT_TYPE_BEACON:
+		case AR5K_PKT_TYPE_PROBE_RESP:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+		case AR5K_PKT_TYPE_PIFS:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+		default:
+			frame_type = type /*<< 2 ?*/;
+		}
+
+		tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+
+	} else {
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
+			AR5K_REG_SM(antenna_mode,
+				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
+		tx_ctl->tx_control_1 |=
+			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+	}
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * RTS/CTS Duration [5210 ?]
+	 */
+	if ((ah->ah_version == AR5K_AR5210) &&
+			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+		tx_ctl->tx_control_1 |= rtscts_duration &
+				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+	return 0;
+}
+
+/*
+ * Initialize the 4-word tx control descriptor on 5212
+ */
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len __unused,
+	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
+	unsigned int tx_tries0, unsigned int key_index __unused,
+	unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate,
+	unsigned int rtscts_duration)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (tx_tries0 == 0) {
+		DBG("ath5k: zero retries\n");
+		return -EINVAL;
+	}
+	if (tx_rate0 == 0) {
+		DBG("ath5k: zero rate\n");
+		return -EINVAL;
+	}
+
+	tx_power += ah->ah_txpower.txp_offset;
+	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
+		tx_power = AR5K_TUNE_MAX_TXPOWER;
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	frame_len = pkt_len + FCS_LEN;
+
+	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+	tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
+					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(0, CTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * RTS/CTS
+	 */
+	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
+		if ((flags & AR5K_TXDESC_RTSENA) &&
+				(flags & AR5K_TXDESC_CTSENA))
+			return -EINVAL;
+		tx_ctl->tx_control_2 |= rtscts_duration &
+				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the tx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+	tx_status = &desc->ud.ds_tx5210.tx_stat;
+
+	/* No frame has been send or error */
+	if ((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	/*TODO: ts->ts_virtcol + test*/
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = 1;
+	ts->ts_status = 0;
+	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
+		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+	ts->ts_retry[0] = ts->ts_longretry;
+	ts->ts_final_idx = 0;
+
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess a tx status descriptor on 5212
+ */
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+	tx_status = &desc->ud.ds_tx5212.tx_stat;
+
+	/* No frame has been send or error */
+	if (!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = (tx_status->tx_status_1 &
+		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+	ts->ts_status = 0;
+
+	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
+			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
+
+	ts->ts_retry[0] = ts->ts_longretry;
+	ts->ts_rate[0] = tx_ctl->tx_control_3 &
+		AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+	/* TX error */
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * RX Descriptors
+ */
+
+/*
+ * Initialize an rx control descriptor
+ */
+static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah __unused,
+				  struct ath5k_desc *desc,
+				  u32 size, unsigned int flags)
+{
+	struct ath5k_hw_rx_ctl *rx_ctl;
+
+	rx_ctl = &desc->ud.ds_rx.rx_ctl;
+
+	/*
+	 * Clear the descriptor
+	 * If we don't clean the status descriptor,
+	 * while scanning we get too many results,
+	 * most of them virtual, after some secs
+	 * of scanning system hangs. M.F.
+	*/
+	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
+
+	/* Setup descriptor */
+	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+	if (rx_ctl->rx_control_1 != size)
+		return -EINVAL;
+
+	if (flags & AR5K_RXDESC_INTREQ)
+		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* No frame received / not ready */
+	if (!(rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA);
+	rs->rs_more = !!(rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_MORE);
+	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	      AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+			rs->rs_status |= AR5K_RXERR_FIFO;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5212
+ */
+static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+	struct ath5k_hw_rx_error *rx_err;
+
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* Overlay on error */
+	rx_err = &desc->ud.ds_rx.u.rx_err;
+
+	/* No frame received / not ready */
+	if (!(rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
+	rs->rs_more = !!(rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_MORE);
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	      AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
+					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+			rs->rs_status |= AR5K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+/*
+ * Init function pointers inside ath5k_hw struct
+ */
+int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
+{
+
+	if (ah->ah_version != AR5K_AR5210 &&
+	    ah->ah_version != AR5K_AR5211 &&
+	    ah->ah_version != AR5K_AR5212)
+		return -ENOTSUP;
+
+	if (ah->ah_version == AR5K_AR5212) {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
+	} else {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+	}
+
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
+	else if (ah->ah_version <= AR5K_AR5211)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
+
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c
new file mode 100644
index 0000000..fa1e0d0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* DMA and interrupt masking functions *
+\*************************************/
+
+/*
+ * dma.c - DMA and interrupt masking functions
+ *
+ * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
+ * handle queue setup for 5210 chipset (rest are handled on qcu.c).
+ * Also we setup interrupt mask register (IMR) and read the various iterrupt
+ * status registers (ISR).
+ *
+ * TODO: Handle SISR on 5211+ and introduce a function to return the queue
+ * number that resulted the interrupt.
+ */
+
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*********\
+* Receive *
+\*********/
+
+/**
+ * ath5k_hw_start_rx_dma - Start DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
+{
+	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+	ath5k_hw_reg_read(ah, AR5K_CR);
+}
+
+/**
+ * ath5k_hw_stop_rx_dma - Stop DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+{
+	unsigned int i;
+
+	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
+
+	/*
+	 * It may take some time to disable the DMA receive unit
+	 */
+	for (i = 1000; i > 0 &&
+			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
+			i--)
+		udelay(10);
+
+	return i ? 0 : -EBUSY;
+}
+
+/**
+ * ath5k_hw_get_rxdp - Get RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * XXX: Is RXDP read and clear ?
+ */
+u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_RXDP);
+}
+
+/**
+ * ath5k_hw_set_rxdp - Set RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ * @phys_addr: RX descriptor address
+ *
+ * XXX: Should we check if rx is enabled before setting rxdp ?
+ */
+void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+{
+	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+}
+
+
+/**********\
+* Transmit *
+\**********/
+
+/**
+ * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Start DMA transmit for a specific queue and since 5210 doesn't have
+ * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
+ * queue for normal data and one queue for beacons). For queue setup
+ * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
+ * of range or if queue is already disabled.
+ *
+ * NOTE: Must be called after setting up tx control descriptor for that
+ * queue (see below).
+ */
+int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 tx_queue;
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/* Assume always a data queue */
+		tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
+
+		/* Start queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/* Return if queue is disabled */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
+			return -EIO;
+
+		/* Start queue */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
+	}
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Stop DMA transmit on a specific hw queue and drain queue so we don't
+ * have any pending frames. Returns -EBUSY if we still have pending frames,
+ * -EINVAL if queue number is out of range.
+ *
+ */
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	unsigned int i = 40;
+	u32 tx_queue, pending;
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/* Assume a data queue */
+		tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
+
+		/* Stop queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/*
+		 * Schedule TX disable and wait until queue is empty
+		 */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
+
+		/*Check for pending frames*/
+		do {
+			pending = ath5k_hw_reg_read(ah,
+				AR5K_QUEUE_STATUS(queue)) &
+				AR5K_QCU_STS_FRMPENDCNT;
+			udelay(100);
+		} while (--i && pending);
+
+		/* For 2413+ order PCU to drop packets using
+		 * QUIET mechanism */
+		if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && pending) {
+			/* Set periodicity and duration */
+			ath5k_hw_reg_write(ah,
+				AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
+				AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
+				AR5K_QUIET_CTL2);
+
+			/* Enable quiet period for current TSF */
+			ath5k_hw_reg_write(ah,
+				AR5K_QUIET_CTL1_QT_EN |
+				AR5K_REG_SM(ath5k_hw_reg_read(ah,
+						AR5K_TSF_L32_5211) >> 10,
+						AR5K_QUIET_CTL1_NEXT_QT_TSF),
+				AR5K_QUIET_CTL1);
+
+			/* Force channel idle high */
+			AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+
+			/* Wait a while and disable mechanism */
+			udelay(200);
+			AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
+						AR5K_QUIET_CTL1_QT_EN);
+
+			/* Re-check for pending frames */
+			i = 40;
+			do {
+				pending = ath5k_hw_reg_read(ah,
+					AR5K_QUEUE_STATUS(queue)) &
+					AR5K_QCU_STS_FRMPENDCNT;
+				udelay(100);
+			} while (--i && pending);
+
+			AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+		}
+
+		/* Clear register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+		if (pending)
+			return -EBUSY;
+	}
+
+	/* TODO: Check for success on 5210 else return error */
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Get TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and use tx queue type since we only have 2 queues.
+ * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just read the corresponding TXDP register.
+ *
+ * XXX: Is TXDP read and clear ?
+ */
+u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
+{
+	u16 tx_reg;
+
+	/*
+	 * Get the transmit queue descriptor pointer from the selected queue
+	 */
+	/*5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Assume a data queue */
+		tx_reg = AR5K_NOQCU_TXDP0;
+	} else {
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	return ath5k_hw_reg_read(ah, tx_reg);
+}
+
+/**
+ * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Set TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and we use tx queue type since we only have 2 queues
+ * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just set the corresponding TXDP register.
+ * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
+ * active.
+ */
+int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+{
+	u16 tx_reg;
+
+	/*
+	 * Set the transmit queue descriptor pointer register by type
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Assume a data queue */
+		tx_reg = AR5K_NOQCU_TXDP0;
+	} else {
+		/*
+		 * Set the transmit queue descriptor pointer for
+		 * the selected queue on QCU for 5211+
+		 * (this won't work if the queue is still active)
+		 */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+			return -EIO;
+
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	/* Set descriptor pointer */
+	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_update_tx_triglevel - Update tx trigger level
+ *
+ * @ah: The &struct ath5k_hw
+ * @increase: Flag to force increase of trigger level
+ *
+ * This function increases/decreases the tx trigger level for the tx fifo
+ * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
+ * the buffer and transmits it's data. Lowering this results sending small
+ * frames more quickly but can lead to tx underruns, raising it a lot can
+ * result other problems (i think bmiss is related). Right now we start with
+ * the lowest possible (64Bytes) and if we get tx underrun we increase it using
+ * the increase flag. Returns -EIO if we have have reached maximum/minimum.
+ *
+ * XXX: Link this with tx DMA size ?
+ * XXX: Use it to save interrupts ?
+ * TODO: Needs testing, i think it's related to bmiss...
+ */
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase)
+{
+	u32 trigger_level, imr;
+	int ret = -EIO;
+
+	/*
+	 * Disable interrupts by setting the mask
+	 */
+	imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
+
+	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
+			AR5K_TXCFG_TXFULL);
+
+	if (!increase) {
+		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
+			goto done;
+	} else
+		trigger_level +=
+			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
+
+	/*
+	 * Update trigger level on success
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_TXFULL, trigger_level);
+
+	ret = 0;
+
+done:
+	/*
+	 * Restore interrupt mask
+	 */
+	ath5k_hw_set_imr(ah, imr);
+
+	return ret;
+}
+
+/*******************\
+* Interrupt masking *
+\*******************/
+
+/**
+ * ath5k_hw_is_intr_pending - Check if we have pending interrupts
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Check if we have pending interrupts to process. Returns 1 if we
+ * have pending interrupts and 0 if we haven't.
+ */
+int ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
+}
+
+/**
+ * ath5k_hw_get_isr - Get interrupt status
+ *
+ * @ah: The @struct ath5k_hw
+ * @interrupt_mask: Driver's interrupt mask used to filter out
+ * interrupts in sw.
+ *
+ * This function is used inside our interrupt handler to determine the reason
+ * for the interrupt by reading Primary Interrupt Status Register. Returns an
+ * abstract interrupt status mask which is mostly ISR with some uncommon bits
+ * being mapped on some standard non hw-specific positions
+ * (check out &ath5k_int).
+ *
+ * NOTE: We use read-and-clear register, so after this function is called ISR
+ * is zeroed.
+ */
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+{
+	u32 data;
+
+	/*
+	 * Read interrupt status from the Interrupt Status register
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_ISR);
+		if (data == AR5K_INT_NOCARD) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	} else {
+		/*
+		 * Read interrupt status from Interrupt
+		 * Status Register shadow copy (Read And Clear)
+		 *
+		 * Note: PISR/SISR Not available on 5210
+		 */
+		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+		if (data == AR5K_INT_NOCARD) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	}
+
+	/*
+	 * Get abstract interrupt mask (driver-compatible)
+	 */
+	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
+
+		/*HIU = Host Interface Unit (PCI etc)*/
+		if (data & (AR5K_ISR_HIUERR))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*Beacon Not Ready*/
+		if (data & (AR5K_ISR_BNR))
+			*interrupt_mask |= AR5K_INT_BNR;
+
+		if (sisr2 & (AR5K_SISR2_SSERR | AR5K_SISR2_DPERR |
+			     AR5K_SISR2_MCABT))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		if (data & AR5K_ISR_TIM)
+			*interrupt_mask |= AR5K_INT_TIM;
+
+		if (data & AR5K_ISR_BCNMISC) {
+			if (sisr2 & AR5K_SISR2_TIM)
+				*interrupt_mask |= AR5K_INT_TIM;
+			if (sisr2 & AR5K_SISR2_DTIM)
+				*interrupt_mask |= AR5K_INT_DTIM;
+			if (sisr2 & AR5K_SISR2_DTIM_SYNC)
+				*interrupt_mask |= AR5K_INT_DTIM_SYNC;
+			if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
+			if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
+		}
+
+		if (data & AR5K_ISR_RXDOPPLER)
+			*interrupt_mask |= AR5K_INT_RX_DOPPLER;
+		if (data & AR5K_ISR_QCBRORN) {
+			*interrupt_mask |= AR5K_INT_QCBRORN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRORN);
+		}
+		if (data & AR5K_ISR_QCBRURN) {
+			*interrupt_mask |= AR5K_INT_QCBRURN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRURN);
+		}
+		if (data & AR5K_ISR_QTRIG) {
+			*interrupt_mask |= AR5K_INT_QTRIG;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
+					AR5K_SISR4_QTRIG);
+		}
+
+		if (data & AR5K_ISR_TXOK)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXOK);
+
+		if (data & AR5K_ISR_TXDESC)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXDESC);
+
+		if (data & AR5K_ISR_TXERR)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXERR);
+
+		if (data & AR5K_ISR_TXEOL)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXEOL);
+
+		if (data & AR5K_ISR_TXURN)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
+					AR5K_SISR2_QCU_TXURN);
+	} else {
+		if (data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT |
+			    AR5K_ISR_HIUERR | AR5K_ISR_DPERR))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*
+		 * XXX: BMISS interrupts may occur after association.
+		 * I found this on 5210 code but it needs testing. If this is
+		 * true we should disable them before assoc and re-enable them
+		 * after a successful assoc + some jiffies.
+			interrupt_mask &= ~AR5K_INT_BMISS;
+		 */
+	}
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_imr - Set interrupt mask
+ *
+ * @ah: The &struct ath5k_hw
+ * @new_mask: The new interrupt mask to be set
+ *
+ * Set the interrupt mask in hw to save interrupts. We do that by mapping
+ * ath5k_int bits to hw-specific bits to remove abstraction and writing
+ * Interrupt Mask Register.
+ */
+enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+{
+	enum ath5k_int old_mask, int_mask;
+
+	old_mask = ah->ah_imr;
+
+	/*
+	 * Disable card interrupts to prevent any race conditions
+	 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
+	 * is set again on the new mask).
+	 */
+	if (old_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
+
+	/*
+	 * Add additional, chipset-dependent interrupt mask flags
+	 * and write them to the IMR (interrupt mask register).
+	 */
+	int_mask = new_mask & AR5K_INT_COMMON;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/* Preserve per queue TXURN interrupt mask */
+		u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
+				& AR5K_SIMR2_QCU_TXURN;
+
+		if (new_mask & AR5K_INT_FATAL) {
+			int_mask |= AR5K_IMR_HIUERR;
+			simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
+				| AR5K_SIMR2_DPERR);
+		}
+
+		/*Beacon Not Ready*/
+		if (new_mask & AR5K_INT_BNR)
+			int_mask |= AR5K_INT_BNR;
+
+		if (new_mask & AR5K_INT_TIM)
+			int_mask |= AR5K_IMR_TIM;
+
+		if (new_mask & AR5K_INT_TIM)
+			simr2 |= AR5K_SISR2_TIM;
+		if (new_mask & AR5K_INT_DTIM)
+			simr2 |= AR5K_SISR2_DTIM;
+		if (new_mask & AR5K_INT_DTIM_SYNC)
+			simr2 |= AR5K_SISR2_DTIM_SYNC;
+		if (new_mask & AR5K_INT_BCN_TIMEOUT)
+			simr2 |= AR5K_SISR2_BCN_TIMEOUT;
+		if (new_mask & AR5K_INT_CAB_TIMEOUT)
+			simr2 |= AR5K_SISR2_CAB_TIMEOUT;
+
+		if (new_mask & AR5K_INT_RX_DOPPLER)
+			int_mask |= AR5K_IMR_RXDOPPLER;
+
+		/* Note: Per queue interrupt masks
+		 * are set via reset_tx_queue (qcu.c) */
+		ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+		ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
+
+	} else {
+		if (new_mask & AR5K_INT_FATAL)
+			int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
+				| AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
+
+		ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
+	}
+
+	/* If RXNOFRM interrupt is masked disable it
+	 * by setting AR5K_RXNOFRM to zero */
+	if (!(new_mask & AR5K_INT_RXNOFRM))
+		ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
+
+	/* Store new interrupt mask */
+	ah->ah_imr = new_mask;
+
+	/* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
+	if (new_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
+
+	return old_mask;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c
new file mode 100644
index 0000000..983d206
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c
@@ -0,0 +1,1760 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2008-2009 Felix Fietkau <nbd at openwrt.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* EEPROM access functions and helpers *
+\*************************************/
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Read from eeprom
+ */
+static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
+{
+	u32 status, timeout;
+
+	/*
+	 * Initialize EEPROM access
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+	} else {
+		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_READ);
+	}
+
+	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+		if (status & AR5K_EEPROM_STAT_RDDONE) {
+			if (status & AR5K_EEPROM_STAT_RDERR)
+				return -EIO;
+			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+					0xffff);
+			return 0;
+		}
+		udelay(15);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Translate binary channel representation in EEPROM to frequency
+ */
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+                                 unsigned int mode)
+{
+	u16 val;
+
+	if (bin == AR5K_EEPROM_CHANNEL_DIS)
+		return bin;
+
+	if (mode == AR5K_EEPROM_MODE_11A) {
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = (5 * bin) + 4800;
+		else
+			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
+				(bin * 10) + 5100;
+	} else {
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = bin + 2300;
+		else
+			val = bin + 2400;
+	}
+
+	return val;
+}
+
+/*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int ret;
+	u16 val;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+
+		/* XXX: Don't know which versions include these two */
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val);
+
+	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val)
+		ee->ee_is_hb63 = 1;
+	else
+		ee->ee_is_hb63 = 0;
+
+	AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val);
+	ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
+	ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? 1 : 0;
+
+	return 0;
+}
+
+
+/*
+ * Read antenna infos from eeprom
+ */
+static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret, i = 0;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
+	ee->ee_atn_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
+	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	/* Get antenna modes */
+	ah->ah_antenna[mode][0] =
+	    (ee->ee_ant_control[mode][0] << 4);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
+	     ee->ee_ant_control[mode][1] 	|
+	    (ee->ee_ant_control[mode][2] << 6) 	|
+	    (ee->ee_ant_control[mode][3] << 12) |
+	    (ee->ee_ant_control[mode][4] << 18) |
+	    (ee->ee_ant_control[mode][5] << 24);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
+	     ee->ee_ant_control[mode][6] 	|
+	    (ee->ee_ant_control[mode][7] << 6) 	|
+	    (ee->ee_ant_control[mode][8] << 12) |
+	    (ee->ee_ant_control[mode][9] << 18) |
+	    (ee->ee_ant_control[mode][10] << 24);
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read supported modes and some mode-specific calibration data
+ * from eeprom
+ */
+static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	ee->ee_n_piers[mode] = 0;
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_ob[mode][3]	= (val >> 5) & 0x7;
+		ee->ee_db[mode][3]	= (val >> 2) & 0x7;
+		ee->ee_ob[mode][2]	= (val << 1) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_ob[mode][2]	|= (val >> 15) & 0x1;
+		ee->ee_db[mode][2]	= (val >> 12) & 0x7;
+		ee->ee_ob[mode][1]	= (val >> 9) & 0x7;
+		ee->ee_db[mode][1]	= (val >> 6) & 0x7;
+		ee->ee_ob[mode][0]	= (val >> 3) & 0x7;
+		ee->ee_db[mode][0]	= val & 0x7;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+	case AR5K_EEPROM_MODE_11B:
+		ee->ee_ob[mode][1]	= (val >> 4) & 0x7;
+		ee->ee_db[mode][1]	= val & 0x7;
+		break;
+	}
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
+	ee->ee_thr_62[mode]		= val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
+	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
+
+	if ((val & 0xff) & 0x80)
+		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
+	else
+		ee->ee_noise_floor_thr[mode] = val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_noise_floor_thr[mode] =
+		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
+	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
+	ee->ee_xpd[mode]		= val & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
+
+		if (mode == AR5K_EEPROM_MODE_11A)
+			ee->ee_xr_power[mode] = val & 0x3f;
+		else {
+			ee->ee_ob[mode][0] = val & 0x7;
+			ee->ee_db[mode][0] = (val >> 3) & 0x7;
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
+		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
+		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
+	} else {
+		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
+
+		if (mode == AR5K_EEPROM_MODE_11G) {
+			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+			if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+				ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+		}
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+			mode == AR5K_EEPROM_MODE_11A) {
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+		goto done;
+
+	/* Note: >= v5 have bg freq piers on another location
+	 * so these freq piers are ignored for >= v5 (should be 0xff
+	 * anyway) */
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+			break;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_b[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_b[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_b[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_g[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_g[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_g[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(o++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+		break;
+	}
+
+done:
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read turbo mode information on newer EEPROM versions
+ */
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+			      u32 *offset, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+		return 0;
+
+	switch (mode){
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+		if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+			ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+		break;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/* Read mode-specific data (except power calibration data) */
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 mode_offset[3];
+	unsigned int mode;
+	u32 offset;
+	int ret;
+
+	/*
+	 * Get values for all modes
+	 */
+	mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+		AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		offset = mode_offset[mode];
+
+		ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+	}
+
+	/* override for older eeprom versions for better performance */
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
+	}
+
+	return 0;
+}
+
+/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
+ * frequency mask) */
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+			struct ath5k_chan_pcal_info *pc, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int o = *offset;
+	int i = 0;
+	u8 freq1, freq2;
+	int ret;
+	u16 val;
+
+	ee->ee_n_piers[mode] = 0;
+	while(i < max) {
+		AR5K_EEPROM_READ(o++, val);
+
+		freq1 = val & 0xff;
+		if (!freq1)
+			break;
+
+		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
+				freq1, mode);
+		ee->ee_n_piers[mode]++;
+
+		freq2 = (val >> 8) & 0xff;
+		if (!freq2)
+			break;
+
+		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
+				freq2, mode);
+		ee->ee_n_piers[mode]++;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/* Read frequency piers for 802.11a */
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+	int i, ret;
+	u16 val;
+	u8 mask;
+
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		ath5k_eeprom_read_freq_list(ah, &offset,
+			AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+			AR5K_EEPROM_MODE_11A);
+	} else {
+		mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[0].freq  = (val >> 9) & mask;
+		pcal[1].freq  = (val >> 2) & mask;
+		pcal[2].freq  = (val << 5) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[2].freq |= (val >> 11) & 0x1f;
+		pcal[3].freq  = (val >> 4) & mask;
+		pcal[4].freq  = (val << 3) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[4].freq |= (val >> 13) & 0x7;
+		pcal[5].freq  = (val >> 6) & mask;
+		pcal[6].freq  = (val << 1) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[6].freq |= (val >> 15) & 0x1;
+		pcal[7].freq  = (val >> 8) & mask;
+		pcal[8].freq  = (val >> 1) & mask;
+		pcal[9].freq  = (val << 6) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[9].freq |= (val >> 10) & 0x3f;
+
+		/* Fixed number of piers */
+		ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
+
+		for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
+			pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, AR5K_EEPROM_MODE_11A);
+		}
+	}
+
+	return 0;
+}
+
+/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11B:
+		pcal = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		pcal = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ath5k_eeprom_read_freq_list(ah, &offset,
+		AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+		mode);
+
+	return 0;
+}
+
+/*
+ * Read power calibration for RF5111 chips
+ *
+ * For RF5111 we have an XPD -eXternal Power Detector- curve
+ * for each calibrated channel. Each curve has 0,5dB Power steps
+ * on x axis and PCDAC steps (offsets) on y axis and looks like an
+ * exponential function. To recreate the curve we read 11 points
+ * here and interpolate later.
+ */
+
+/* Used to match PCDAC steps with power values on RF5111 chips
+ * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
+ * steps that match with the power values we read from eeprom. On
+ * older eeprom versions (< 3.2) these steps are equaly spaced at
+ * 10% of the pcdac curve -until the curve reaches it's maximum-
+ * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
+ * these 11 steps are spaced in a different way. This function returns
+ * the pcdac steps based on eeprom version and curve min/max so that we
+ * can have pcdac/pwr points.
+ */
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+	static const u16 intercepts3[] =
+		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+	static const u16 intercepts3_2[] =
+		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+	const u16 *ip;
+	unsigned i;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+		ip = intercepts3_2;
+	else
+		ip = intercepts3;
+
+	for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+		vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
+
+/* Convert RF5111 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5111 *pcinfo;
+	struct ath5k_pdgain_info *pd;
+	u8 pier, point, idx;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf5111_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+			calloc(AR5K_EEPROM_N_PD_CURVES,
+			       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Only one curve for RF5111
+		 * find out which one and place
+		 * in in pd_curves.
+		 * Note: ee_x_gain is reversed here */
+		for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
+
+			if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {
+				pdgain_idx[0] = idx;
+				break;
+			}
+		}
+
+		ee->ee_pd_gains[mode] = 1;
+
+		pd = &chinfo[pier].pd_curves[idx];
+
+		pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;
+
+		/* Allocate pd points for this curve */
+		pd->pd_step = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8));
+		if (!pd->pd_step)
+			return -ENOMEM;
+
+		pd->pd_pwr = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16));
+		if (!pd->pd_pwr)
+			return -ENOMEM;
+
+		/* Fill raw dataset
+		 * (convert power to 0.25dB units
+		 * for RF5112 combatibility) */
+		for (point = 0; point < pd->pd_points; point++) {
+
+			/* Absolute values */
+			pd->pd_pwr[point] = 2 * pcinfo->pwr[point];
+
+			/* Already sorted */
+			pd->pd_step[point] = pcinfo->pcdac[point];
+		}
+
+		/* Set min/max pwr */
+		chinfo[pier].min_pwr = pd->pd_pwr[0];
+		chinfo[pier].max_pwr = pd->pd_pwr[10];
+
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int offset, ret;
+	int i;
+	u16 val;
+
+	offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+			offset + AR5K_EEPROM_GROUP1_OFFSET);
+		if (ret < 0)
+			return ret;
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		pcal = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+		    !AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_b;
+		offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2412;
+		pcal[1].freq = 2447;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_g;
+		offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2312;
+		pcal[1].freq = 2412;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		struct ath5k_chan_pcal_info_rf5111 *cdata =
+			&pcal[i].rf5111_info;
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+		cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+		cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[0] |= ((val >> 14) & 0x3);
+		cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[3] |= ((val >> 12) & 0xf);
+		cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[8] |= ((val >> 14) & 0x3);
+		cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+		ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+			cdata->pcdac_max, cdata->pcdac);
+	}
+
+	return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);
+}
+
+
+/*
+ * Read power calibration for RF5112 chips
+ *
+ * For RF5112 we have 4 XPD -eXternal Power Detector- curves
+ * for each calibrated channel on 0, -6, -12 and -18dbm but we only
+ * use the higher (3) and the lower (0) curves. Each curve has 0.5dB
+ * power steps on x axis and PCDAC steps on y axis and looks like a
+ * linear function. To recreate the curve and pass the power values
+ * on hw, we read 4 points for xpd 0 (lower gain -> max power)
+ * and 3 points for xpd 3 (higher gain -> lower power) here and
+ * interpolate later.
+ *
+ * Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
+ */
+
+/* Convert RF5112 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *pcinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	unsigned int pier, pdg, point;
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf5112_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+				calloc(AR5K_EEPROM_N_PD_CURVES,
+				       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Fill pd_curves */
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+
+			u8 idx = pdgain_idx[pdg];
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[idx];
+
+			/* Lowest gain curve (max power) */
+			if (pdg == 0) {
+				/* One more point for better accuracy */
+				pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;
+
+				/* Allocate pd points for this curve */
+				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+				if (!pd->pd_step)
+					return -ENOMEM;
+
+				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+				if (!pd->pd_pwr)
+					return -ENOMEM;
+
+
+				/* Fill raw dataset
+				 * (all power levels are in 0.25dB units) */
+				pd->pd_step[0] = pcinfo->pcdac_x0[0];
+				pd->pd_pwr[0] = pcinfo->pwr_x0[0];
+
+				for (point = 1; point < pd->pd_points;
+				point++) {
+					/* Absolute values */
+					pd->pd_pwr[point] =
+						pcinfo->pwr_x0[point];
+
+					/* Deltas */
+					pd->pd_step[point] =
+						pd->pd_step[point - 1] +
+						pcinfo->pcdac_x0[point];
+				}
+
+				/* Set min power for this frequency */
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+
+			/* Highest gain curve (min power) */
+			} else if (pdg == 1) {
+
+				pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;
+
+				/* Allocate pd points for this curve */
+				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+				if (!pd->pd_step)
+					return -ENOMEM;
+
+				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+				if (!pd->pd_pwr)
+					return -ENOMEM;
+
+				/* Fill raw dataset
+				 * (all power levels are in 0.25dB units) */
+				for (point = 0; point < pd->pd_points;
+				point++) {
+					/* Absolute values */
+					pd->pd_pwr[point] =
+						pcinfo->pwr_x3[point];
+
+					/* Fixed points */
+					pd->pd_step[point] =
+						pcinfo->pcdac_x3[point];
+				}
+
+				/* Since we have a higher gain curve
+				 * override min power */
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	u32 offset;
+	u8 i, c;
+	u16 val;
+	int ret;
+	u8 pd_gains = 0;
+
+	/* Count how many curves we have and
+	 * identify them (which one of the 4
+	 * available curves we have on each count).
+	 * Curves are stored from lower (x0) to
+	 * higher (x3) gain */
+	for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {
+		/* ee_x_gain[mode] is x gain mask */
+		if ((ee->ee_x_gain[mode] >> i) & 0x1)
+			pdgain_idx[pd_gains++] = i;
+	}
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	if (pd_gains == 0 || pd_gains > 2)
+		return -EINVAL;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		/*
+		 * Read 5GHz EEPROM channels
+		 */
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP4_OFFSET;
+		else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf5112_info;
+
+		/* Power values in quarter dB
+		 * for the lower xpd gain curve
+		 * (0 dBm -> higher output power) */
+		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);
+			chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);
+		}
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+		chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+		chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
+
+		/* Power values in quarter dB
+		 * for the higher xpd gain curve
+		 * (18 dBm -> lower output power) */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);
+		chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements (fixed) */
+		chan_pcal_info->pcdac_x3[0] = 20;
+		chan_pcal_info->pcdac_x3[1] = 35;
+		chan_pcal_info->pcdac_x3[2] = 63;
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+			chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);
+
+			/* Last xpd0 power level is also channel maximum */
+			gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+		} else {
+			chan_pcal_info->pcdac_x0[0] = 1;
+			gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);
+		}
+
+	}
+
+	return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);
+}
+
+
+/*
+ * Read power calibration for RF2413 chips
+ *
+ * For RF2413 we have a Power to PDDAC table (Power Detector)
+ * instead of a PCDAC and 4 pd gain curves for each calibrated channel.
+ * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y
+ * axis and looks like an exponential function like the RF5111 curve.
+ *
+ * To recreate the curves we read here the points and interpolate
+ * later. Note that in most cases only 2 (higher and lower) curves are
+ * used (like RF5112) but vendors have the oportunity to include all
+ * 4 curves on eeprom. The final curve (higher power) has an extra
+ * point for better accuracy like RF5112.
+ */
+
+/* For RF2413 power calibration data doesn't start on a fixed location and
+ * if a mode is not supported, it's section is missing -not zeroed-.
+ * So we need to calculate the starting offset for each section by using
+ * these two functions */
+
+/* Return the size of each section based on the mode and the number of pd
+ * gains available (maximum 4). */
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+	static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+	unsigned int sz;
+
+	sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+	sz *= ee->ee_n_piers[mode];
+
+	return sz;
+}
+
+/* Return the starting offset for a section based on the modes supported
+ * and each section's size. */
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+	u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11G:
+		if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee,
+					AR5K_EEPROM_MODE_11B) +
+					AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11B:
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee,
+					AR5K_EEPROM_MODE_11A) +
+					AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11A:
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+/* Convert RF2413 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	unsigned int pier, point;
+	int pdg;
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf2413_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+				calloc(AR5K_EEPROM_N_PD_CURVES,
+				       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Fill pd_curves */
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+
+			u8 idx = pdgain_idx[pdg];
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[idx];
+
+			/* One more point for the highest power
+			 * curve (lowest gain) */
+			if (pdg == ee->ee_pd_gains[mode] - 1)
+				pd->pd_points = AR5K_EEPROM_N_PD_POINTS;
+			else
+				pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;
+
+			/* Allocate pd points for this curve */
+			pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+			if (!pd->pd_step)
+				return -ENOMEM;
+
+			pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+			if (!pd->pd_pwr)
+				return -ENOMEM;
+
+			/* Fill raw dataset
+			 * convert all pwr levels to
+			 * quarter dB for RF5112 combatibility */
+			pd->pd_step[0] = pcinfo->pddac_i[pdg];
+			pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
+
+			for (point = 1; point < pd->pd_points; point++) {
+
+				pd->pd_pwr[point] = pd->pd_pwr[point - 1] +
+					2 * pcinfo->pwr[pdg][point - 1];
+
+				pd->pd_step[point] = pd->pd_step[point - 1] +
+						pcinfo->pddac[pdg][point - 1];
+
+			}
+
+			/* Highest gain curve -> min power */
+			if (pdg == 0)
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+
+			/* Lowest gain curve -> max power */
+			if (pdg == ee->ee_pd_gains[mode] - 1)
+				chinfo[pier].max_pwr =
+					pd->pd_pwr[pd->pd_points - 1];
+		}
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
+	struct ath5k_chan_pcal_info *chinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	u32 offset;
+	int idx, i, ret;
+	u16 val;
+	u8 pd_gains = 0;
+
+	/* Count how many curves we have and
+	 * identify them (which one of the 4
+	 * available curves we have on each count).
+	 * Curves are stored from higher to
+	 * lower gain so we go backwards */
+	for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {
+		/* ee_x_gain[mode] is x gain mask */
+		if ((ee->ee_x_gain[mode] >> idx) & 0x1)
+			pdgain_idx[pd_gains++] = idx;
+
+	}
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	if (pd_gains == 0)
+		return -EINVAL;
+
+	offset = ath5k_cal_data_offset_2413(ee, mode);
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+		offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		chinfo = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		chinfo = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		chinfo = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		pcinfo = &chinfo[i].rf2413_info;
+
+		/*
+		 * Read pwr_i, pddac_i and the first
+		 * 2 pd points (pwr, pddac)
+		 */
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pwr_i[0] = val & 0x1f;
+		pcinfo->pddac_i[0] = (val >> 5) & 0x7f;
+		pcinfo->pwr[0][0] = (val >> 12) & 0xf;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pddac[0][0] = val & 0x3f;
+		pcinfo->pwr[0][1] = (val >> 6) & 0xf;
+		pcinfo->pddac[0][1] = (val >> 10) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pwr[0][2] = val & 0xf;
+		pcinfo->pddac[0][2] = (val >> 4) & 0x3f;
+
+		pcinfo->pwr[0][3] = 0;
+		pcinfo->pddac[0][3] = 0;
+
+		if (pd_gains > 1) {
+			/*
+			 * Pd gain 0 is not the last pd gain
+			 * so it only has 2 pd points.
+			 * Continue wih pd gain 1.
+			 */
+			pcinfo->pwr_i[1] = (val >> 10) & 0x1f;
+
+			pcinfo->pddac_i[1] = (val >> 15) & 0x1;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac_i[1] |= (val & 0x3F) << 1;
+
+			pcinfo->pwr[1][0] = (val >> 6) & 0xf;
+			pcinfo->pddac[1][0] = (val >> 10) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[1][1] = val & 0xf;
+			pcinfo->pddac[1][1] = (val >> 4) & 0x3f;
+			pcinfo->pwr[1][2] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[1][2] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[1][2] |= (val & 0xF) << 2;
+
+			pcinfo->pwr[1][3] = 0;
+			pcinfo->pddac[1][3] = 0;
+		} else if (pd_gains == 1) {
+			/*
+			 * Pd gain 0 is the last one so
+			 * read the extra point.
+			 */
+			pcinfo->pwr[0][3] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[0][3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[0][3] |= (val & 0xF) << 2;
+		}
+
+		/*
+		 * Proceed with the other pd_gains
+		 * as above.
+		 */
+		if (pd_gains > 2) {
+			pcinfo->pwr_i[2] = (val >> 4) & 0x1f;
+			pcinfo->pddac_i[2] = (val >> 9) & 0x7f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[2][0] = (val >> 0) & 0xf;
+			pcinfo->pddac[2][0] = (val >> 4) & 0x3f;
+			pcinfo->pwr[2][1] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[2][1] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[2][1] |= (val & 0xF) << 2;
+
+			pcinfo->pwr[2][2] = (val >> 4) & 0xf;
+			pcinfo->pddac[2][2] = (val >> 8) & 0x3f;
+
+			pcinfo->pwr[2][3] = 0;
+			pcinfo->pddac[2][3] = 0;
+		} else if (pd_gains == 2) {
+			pcinfo->pwr[1][3] = (val >> 4) & 0xf;
+			pcinfo->pddac[1][3] = (val >> 8) & 0x3f;
+		}
+
+		if (pd_gains > 3) {
+			pcinfo->pwr_i[3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+			pcinfo->pddac_i[3] = (val >> 3) & 0x7f;
+			pcinfo->pwr[3][0] = (val >> 10) & 0xf;
+			pcinfo->pddac[3][0] = (val >> 14) & 0x3;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[3][0] |= (val & 0xF) << 2;
+			pcinfo->pwr[3][1] = (val >> 4) & 0xf;
+			pcinfo->pddac[3][1] = (val >> 8) & 0x3f;
+
+			pcinfo->pwr[3][2] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;
+
+			pcinfo->pddac[3][2] = (val >> 2) & 0x3f;
+			pcinfo->pwr[3][3] = (val >> 8) & 0xf;
+
+			pcinfo->pddac[3][3] = (val >> 12) & 0xF;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;
+		} else if (pd_gains == 3) {
+			pcinfo->pwr[2][3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;
+
+			pcinfo->pddac[2][3] = (val >> 2) & 0x3f;
+		}
+	}
+
+	return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);
+}
+
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int
+ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rate_pcal_info;
+	u8 *rate_target_pwr_num;
+	u32 offset;
+	u16 val;
+	int ret, i;
+
+	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+	rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_a;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_b;
+		ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_g;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Different freq mask for older eeproms (<= v3.2) */
+	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+		}
+	} else {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+			rate_pcal_info[i].target_power_54 = (val & 0x3f);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Read per channel calibration info from EEPROM
+ *
+ * This info is used to calibrate the baseband power table. Imagine
+ * that for each channel there is a power curve that's hw specific
+ * (depends on amplifier etc) and we try to "correct" this curve using
+ * offests we pass on to phy chip (baseband -> before amplifier) so that
+ * it can use accurate power values when setting tx power (takes amplifier's
+ * performance on each channel into account).
+ *
+ * EEPROM provides us with the offsets for some pre-calibrated channels
+ * and we have to interpolate to create the full table for these channels and
+ * also the table for any channel.
+ */
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int (*read_pcal)(struct ath5k_hw *hw, int mode);
+	int mode;
+	int err;
+
+	if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+		read_pcal = ath5k_eeprom_read_pcal_info_5112;
+	else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+		read_pcal = ath5k_eeprom_read_pcal_info_2413;
+	else
+		read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;
+	mode++) {
+		err = read_pcal(ah, mode);
+		if (err)
+			return err;
+
+		err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *chinfo;
+	u8 pier, pdg;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+		if (!chinfo[pier].pd_curves)
+			continue;
+
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[pdg];
+
+			if (pd != NULL) {
+				free(pd->pd_step);
+				free(pd->pd_pwr);
+			}
+		}
+
+		free(chinfo[pier].pd_curves);
+	}
+
+	return 0;
+}
+
+void
+ath5k_eeprom_detach(struct ath5k_hw *ah)
+{
+	u8 mode;
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
+		ath5k_eeprom_free_pcal_info(ah, mode);
+}
+
+/* Read conformance test limits used for regulatory control */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep;
+	unsigned int fmask, pmask;
+	unsigned int ctl_mode;
+	int ret, i, j;
+	u32 offset;
+	u16 val;
+
+	pmask = AR5K_EEPROM_POWER_M;
+	fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+	offset = AR5K_EEPROM_CTL(ee->ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+	for (i = 0; i < ee->ee_ctls; i += 2) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_ctl[i] = (val >> 8) & 0xff;
+		ee->ee_ctl[i + 1] = val & 0xff;
+	}
+
+	offset = AR5K_EEPROM_GROUP8_OFFSET;
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+		offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+			AR5K_EEPROM_GROUP5_OFFSET;
+	else
+		offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
+
+	rep = ee->ee_ctl_pwr;
+	for(i = 0; i < ee->ee_ctls; i++) {
+		switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+		case AR5K_CTL_11A:
+		case AR5K_CTL_TURBO:
+			ctl_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			ctl_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		}
+		if (ee->ee_ctl[i] == 0) {
+			if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+				offset += 8;
+			else
+				offset += 7;
+			rep += AR5K_EEPROM_N_EDGES;
+			continue;
+		}
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].freq = (val >> 8) & fmask;
+				rep[j + 1].freq = val & fmask;
+			}
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].edge = (val >> 8) & pmask;
+				rep[j].flag = (val >> 14) & 1;
+				rep[j + 1].edge = val & pmask;
+				rep[j + 1].flag = (val >> 6) & 1;
+			}
+		} else {
+			AR5K_EEPROM_READ(offset++, val);
+			rep[0].freq = (val >> 9) & fmask;
+			rep[1].freq = (val >> 2) & fmask;
+			rep[2].freq = (val << 5) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[2].freq |= (val >> 11) & 0x1f;
+			rep[3].freq = (val >> 4) & fmask;
+			rep[4].freq = (val << 3) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].freq |= (val >> 13) & 0x7;
+			rep[5].freq = (val >> 6) & fmask;
+			rep[6].freq = (val << 1) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].freq |= (val >> 15) & 0x1;
+			rep[7].freq = (val >> 8) & fmask;
+
+			rep[0].edge = (val >> 2) & pmask;
+			rep[1].edge = (val << 4) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[1].edge |= (val >> 12) & 0xf;
+			rep[2].edge = (val >> 6) & pmask;
+			rep[3].edge = val & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].edge = (val >> 10) & pmask;
+			rep[5].edge = (val >> 4) & pmask;
+			rep[6].edge = (val << 2) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].edge |= (val >> 14) & 0x3;
+			rep[7].edge = (val >> 8) & pmask;
+		}
+		for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+			rep[j].freq = ath5k_eeprom_bin2freq(ee,
+				rep[j].freq, ctl_mode);
+		}
+		rep += AR5K_EEPROM_N_EDGES;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	int err;
+
+	err = ath5k_eeprom_init_header(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_init_modes(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_pcal_info(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_ctl_info(ah);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * Read the MAC address from eeprom
+ */
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	u8 mac_d[ETH_ALEN] = {};
+	u32 total, offset;
+	u16 data;
+	int octet, ret;
+
+	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
+	if (ret)
+		return ret;
+
+	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+		ret = ath5k_hw_eeprom_read(ah, offset, &data);
+		if (ret)
+			return ret;
+
+		total += data;
+		mac_d[octet + 1] = data & 0xff;
+		mac_d[octet] = data >> 8;
+		octet += 2;
+	}
+
+	if (!total || total == 3 * 0xffff)
+		return -EINVAL;
+
+	memcpy(mac, mac_d, ETH_ALEN);
+
+	return 0;
+}
+
+int ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
+{
+	u16 data;
+
+	ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
+
+	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
+		return 1;
+	else
+		return 0;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c
new file mode 100644
index 0000000..2301ec7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/****************\
+  GPIO Functions
+\****************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Set GPIO inputs
+ */
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Set GPIO outputs
+ */
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Get GPIO state
+ */
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return 0xffffffff;
+
+	/* GPIO input magic */
+	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
+		0x1;
+}
+
+/*
+ * Set GPIO state
+ */
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+{
+	u32 data;
+
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	/* GPIO output magic */
+	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	data &= ~(1 << gpio);
+	data |= (val & 1) << gpio;
+
+	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
+
+	return 0;
+}
+
+/*
+ * Initialize the GPIO interrupt (RFKill switch)
+ */
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+		u32 interrupt_level)
+{
+	u32 data;
+
+	if (gpio >= AR5K_NUM_GPIO)
+		return;
+
+	/*
+	 * Set the GPIO interrupt
+	 */
+	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
+		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
+		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
+		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
+
+	ath5k_hw_reg_write(ah, interrupt_level ? data :
+		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
+
+	ah->ah_imr |= AR5K_IMR_GPIO;
+
+	/* Enable GPIO interrupts */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c
new file mode 100644
index 0000000..8f3bd20
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c
@@ -0,0 +1,1560 @@
+/*
+ * Initial register settings functions
+ *
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Mode-independent initial register writes
+ */
+
+struct ath5k_ini {
+	u16	ini_register;
+	u32	ini_value;
+
+	enum {
+		AR5K_INI_WRITE = 0,	/* Default */
+		AR5K_INI_READ = 1,	/* Cleared on read */
+	} ini_mode;
+};
+
+/*
+ * Mode specific initial register values
+ */
+
+struct ath5k_ini_mode {
+	u16	mode_register;
+	u32	mode_value[5];
+};
+
+/* Initial register settings for AR5210 */
+static const struct ath5k_ini ar5210_ini[] = {
+	/* PCU and MAC registers */
+	{ AR5K_NOQCU_TXDP0,	0, AR5K_INI_WRITE },
+	{ AR5K_NOQCU_TXDP1,	0, AR5K_INI_WRITE },
+	{ AR5K_RXDP,		0, AR5K_INI_WRITE },
+	{ AR5K_CR,		0, AR5K_INI_WRITE },
+	{ AR5K_ISR,		0, AR5K_INI_READ },
+	{ AR5K_IMR,		0, AR5K_INI_WRITE },
+	{ AR5K_IER,		AR5K_IER_DISABLE, AR5K_INI_WRITE },
+	{ AR5K_BSR,		0, AR5K_INI_READ },
+	{ AR5K_TXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
+	{ AR5K_CFG,		AR5K_INIT_CFG, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		8, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		8, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0, AR5K_INI_WRITE },
+	{ AR5K_SFR,		0, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0, AR5K_INI_WRITE },
+	{ AR5K_MISC,		0, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER0_5210, 0, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER1_5210, 0, AR5K_INI_WRITE },
+	{ AR5K_TX_MASK0,	0, AR5K_INI_WRITE },
+	{ AR5K_TX_MASK1,	0, AR5K_INI_WRITE },
+	{ AR5K_CLR_TMASK,	0, AR5K_INI_WRITE },
+	{ AR5K_TRIG_LVL,	AR5K_TUNE_MIN_TX_FIFO_THRES, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_RSSI_THR,	AR5K_TUNE_RSSI_THRES, AR5K_INI_WRITE },
+	{ AR5K_TSF_L32_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5210,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5210,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5210,	1, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5210,	0, AR5K_INI_WRITE },
+	/* PHY registers */
+	{ AR5K_PHY(0),	0x00000047, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(3),	0x09848ea6, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),	0x3d32e000, AR5K_INI_WRITE },
+	{ AR5K_PHY(5),	0x0000076b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,	AR5K_PHY_ACT_DISABLE, AR5K_INI_WRITE },
+	{ AR5K_PHY(8),	0x02020200, AR5K_INI_WRITE },
+	{ AR5K_PHY(9),	0x00000e0e, AR5K_INI_WRITE },
+	{ AR5K_PHY(10),	0x0a020201, AR5K_INI_WRITE },
+	{ AR5K_PHY(11),	0x00036ffc, AR5K_INI_WRITE },
+	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(13),	0x00000e0e, AR5K_INI_WRITE },
+	{ AR5K_PHY(14),	0x00000007, AR5K_INI_WRITE },
+	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),	0x89630000, AR5K_INI_WRITE },
+	{ AR5K_PHY(17),	0x1372169c, AR5K_INI_WRITE },
+	{ AR5K_PHY(18),	0x0018b633, AR5K_INI_WRITE },
+	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY(20),	0x0de8b8e0, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),	0x00074859, AR5K_INI_WRITE },
+	{ AR5K_PHY(22),	0x7e80beba, AR5K_INI_WRITE },
+	{ AR5K_PHY(23),	0x313a665e, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGCCTL, 0x00001d08, AR5K_INI_WRITE },
+	{ AR5K_PHY(25),	0x0001ce00, AR5K_INI_WRITE },
+	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },
+	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY(30),	0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(31),	0x00000018, AR5K_INI_WRITE }, 	/* 0x987c */
+	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE }, 	/* 0x9900 */
+	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY(68),	0x00000003, AR5K_INI_WRITE },
+	/* BB gain table (64bytes) */
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000007, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000027, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000017, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x00000037, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x0000002f, AR5K_INI_WRITE },
+	/* 5110 RF gain table (64btes) */
+	{ AR5K_RF_GAIN(0), 0x0000001d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(1), 0x0000005d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(2), 0x0000009d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(3), 0x000000dd, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(4), 0x0000011d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(5), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(6), 0x00000061, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(7), 0x000000a1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(8), 0x000000e1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(9), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(10), 0x00000071, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(11), 0x000000b1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(12), 0x0000001c, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(13), 0x0000005c, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(14), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(15), 0x00000069, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(16), 0x000000a9, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(17), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(18), 0x00000019, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(19), 0x00000059, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(20), 0x00000099, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(21), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(22), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(23), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(24), 0x00000065, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(25), 0x000000a5, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(26), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(27), 0x00000068, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(28), 0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(29), 0x0000001e, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(30), 0x00000018, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(31), 0x00000058, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(32), 0x00000098, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(33), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(34), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(35), 0x00000044, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(36), 0x00000084, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(37), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(38), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(39), 0x00000052, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(40), 0x00000092, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(41), 0x000000d2, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(43), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(44), 0x0000006a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(45), 0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(46), 0x0000001b, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(47), 0x0000001a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(48), 0x0000005a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(49), 0x0000009a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(50), 0x000000da, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(51), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(52), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(53), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(54), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(55), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(56), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(57), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(58), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(59), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(60), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(61), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(62), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(63), 0x00000006, AR5K_INI_WRITE },
+	/* PHY activation */
+	{ AR5K_PHY(53), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_PHY(51), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(50), 0x00060106, AR5K_INI_WRITE },
+	{ AR5K_PHY(39), 0x0000006d, AR5K_INI_WRITE },
+	{ AR5K_PHY(48), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(52), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE, AR5K_INI_WRITE },
+};
+
+/* Initial register settings for AR5211 */
+static const struct ath5k_ini ar5211_ini[] = {
+	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RTSD0,		0x84849c9c, AR5K_INI_WRITE },
+	{ AR5K_RTSD1,		0x7c7c7c7c, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RSSI_THR,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER0_5211, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER1_5211, 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
+	/* PHY registers */
+	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(3),	0x2d849093, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),	0x7d32e000, AR5K_INI_WRITE },
+	{ AR5K_PHY(5),	0x00000f6b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(11),	0x00026ffe, AR5K_INI_WRITE },
+	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),	0x206a017a, AR5K_INI_WRITE },
+	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),	0x00000859, AR5K_INI_WRITE },
+	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },	/* 0x9868 */
+	{ AR5K_PHY(27),	0x050cb081, AR5K_INI_WRITE },
+	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY(30),	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY(68),	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY(71),	0x0000092a, AR5K_INI_WRITE },
+	{ AR5K_PHY_IQ,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(73),	0x00058a05, AR5K_INI_WRITE },
+	{ AR5K_PHY(74),	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY(75),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(77),	0x00000000, AR5K_INI_WRITE },	/* 0x9934 */
+	{ AR5K_PHY(78),	0x00000000, AR5K_INI_WRITE },	/* 0x9938 */
+	{ AR5K_PHY(79),	0x0000003f, AR5K_INI_WRITE },	/* 0x993c */
+	{ AR5K_PHY(80),	0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(82),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(83),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(84),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_RADAR, 0x5d50f14c, AR5K_INI_WRITE },
+	{ AR5K_PHY(86),	0x00000018, AR5K_INI_WRITE },
+	{ AR5K_PHY(87),	0x004b6a8e, AR5K_INI_WRITE },
+	/* Initial Power table (32bytes)
+	 * common on all cards/modes.
+	 * Note: Table is rewritten during
+	 * txpower setup later using calibration
+	 * data etc. so next write is non-common */
+	{ AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCKTXCTL, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(642), 0x503e4646, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c, AR5K_INI_WRITE },
+	{ AR5K_PHY(644), 0x0199a003, AR5K_INI_WRITE },
+	{ AR5K_PHY(645), 0x044cd610, AR5K_INI_WRITE },
+	{ AR5K_PHY(646), 0x13800040, AR5K_INI_WRITE },
+	{ AR5K_PHY(647), 0x1be00060, AR5K_INI_WRITE },
+	{ AR5K_PHY(648), 0x0c53800a, AR5K_INI_WRITE },
+	{ AR5K_PHY(649), 0x0014df3b, AR5K_INI_WRITE },
+	{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },
+	{ AR5K_PHY(651), 0x00000020, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5211
+ * 5211 supports OFDM-only g (draft g) but we
+ * need to test it !
+ */
+static const struct ath5k_ini_mode ar5211_ini_mode[] = {
+	{ AR5K_TXCFG,
+	/*	  a	    aTurbo	  b	  g (OFDM)    */
+	   { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+	   { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
+	{ AR5K_TIME_OUT,
+	   { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
+	{ AR5K_USEC_5211,
+	   { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(8),
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
+	{ AR5K_PHY(9),
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
+	{ AR5K_PHY(10),
+	   { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
+	{ AR5K_PHY(13),
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY(17),
+	   { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
+	{ AR5K_PHY(18),
+	   { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
+	{ AR5K_PHY(20),
+	   { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
+	{ AR5K_PHY_AGCCTL,
+	   { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
+	{ AR5K_PHY_NF,
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
+	{ AR5K_PHY(70),
+	   { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
+	{ AR5K_PHY_PCDAC_TXPOWER_BASE,
+	   { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
+	{ AR5K_RF_BUFFER_CONTROL_4,
+	   { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
+};
+
+/* Initial register settings for AR5212 */
+static const struct ath5k_ini ar5212_ini_common_start[] = {
+	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TXP,		0x00000000, AR5K_INI_WRITE },
+	/* Tx filter table 0 (32 entries) */
+	{ AR5K_DCU_TX_FILTER_0(0),  0x00000000, AR5K_INI_WRITE }, /* DCU 0 */
+	{ AR5K_DCU_TX_FILTER_0(1),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(2),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(3),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(4),  0x00000000, AR5K_INI_WRITE }, /* DCU 1 */
+	{ AR5K_DCU_TX_FILTER_0(5),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(6),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(7),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(8),  0x00000000, AR5K_INI_WRITE }, /* DCU 2 */
+	{ AR5K_DCU_TX_FILTER_0(9),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(10), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(11), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(12), 0x00000000, AR5K_INI_WRITE }, /* DCU 3 */
+	{ AR5K_DCU_TX_FILTER_0(13), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(14), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(15), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(16), 0x00000000, AR5K_INI_WRITE }, /* DCU 4 */
+	{ AR5K_DCU_TX_FILTER_0(17), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(18), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(19), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(20), 0x00000000, AR5K_INI_WRITE }, /* DCU 5 */
+	{ AR5K_DCU_TX_FILTER_0(21), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(22), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(23), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(24), 0x00000000, AR5K_INI_WRITE }, /* DCU 6 */
+	{ AR5K_DCU_TX_FILTER_0(25), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(26), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(27), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(28), 0x00000000, AR5K_INI_WRITE }, /* DCU 7 */
+	{ AR5K_DCU_TX_FILTER_0(29), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(30), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(31), 0x00000000, AR5K_INI_WRITE },
+	/* Tx filter table 1 (16 entries) */
+	{ AR5K_DCU_TX_FILTER_1(0),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(1),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(2),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(3),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(4),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(5),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(6),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(7),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(8),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(9),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(10), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(11), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(12), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(13), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(14), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(15), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BEACON_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5211, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_FRAME_CTL_QOSM, 	0x000fc78f, AR5K_INI_WRITE },
+	{ AR5K_XRMODE,		0x2a82301a, AR5K_INI_WRITE },
+	{ AR5K_XRDELAY,		0x05dc01e0, AR5K_INI_WRITE },
+	{ AR5K_XRTIMEOUT,	0x1f402710, AR5K_INI_WRITE },
+	{ AR5K_XRCHIRP,		0x01f40000, AR5K_INI_WRITE },
+	{ AR5K_XRSTOMP,		0x00001e1c, AR5K_INI_WRITE },
+	{ AR5K_SLEEP0,		0x0002aaaa, AR5K_INI_WRITE },
+	{ AR5K_SLEEP1,		0x02005555, AR5K_INI_WRITE },
+	{ AR5K_SLEEP2,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_IDM0,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_BSS_IDM1,	0x0000ffff, AR5K_INI_WRITE },
+	{ AR5K_TXPC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_TX,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_RX,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_RXCLR,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_CYCLE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUIET_CTL1,	0x00000088, AR5K_INI_WRITE },
+	/* Initial rate duration table (32 entries )*/
+	{ AR5K_RATE_DUR(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(1),	0x0000008c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(2),	0x000000e4, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(3),	0x000002d5, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(6),	0x000000a0, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(7),	0x000001c9, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(8),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(9),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(10),	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(11),	0x0000003c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(12),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(13),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(14),	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(15),	0x0000003c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(16),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(17),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(18),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(19),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(20),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(21),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(22),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(23),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(24),	0x000000d5, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(25),	0x000000df, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(26),	0x00000102, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(27),	0x0000013a, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(28),	0x00000075, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(29),	0x0000007f, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(30),	0x000000a2, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(31),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUIET_CTL2,	0x00010002, AR5K_INI_WRITE },
+	{ AR5K_TSF_PARM,	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_QOS_NOACK,	0x000000c0, AR5K_INI_WRITE },
+	{ AR5K_PHY_ERR_FIL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_XRLAT_TX,	0x00000168, AR5K_INI_WRITE },
+	{ AR5K_ACKSIFS,		0x00000000, AR5K_INI_WRITE },
+	/* Rate -> db table
+	 * notice ...03<-02<-01<-00 ! */
+	{ AR5K_RATE2DB(0),	0x03020100, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(1),	0x07060504, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(2),	0x0b0a0908, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(3),	0x0f0e0d0c, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(4),	0x13121110, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(5),	0x17161514, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(6),	0x1b1a1918, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(7),	0x1f1e1d1c, AR5K_INI_WRITE },
+	/* Db -> Rate table */
+	{ AR5K_DB2RATE(0),	0x03020100, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(1),	0x07060504, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(2),	0x0b0a0908, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(3),	0x0f0e0d0c, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(4),	0x13121110, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(5),	0x17161514, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(6),	0x1b1a1918, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(7),	0x1f1e1d1c, AR5K_INI_WRITE },
+	/* PHY registers (Common settings
+	 * for all chips/modes) */
+	{ AR5K_PHY(3),		0xad848e19, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),		0x7d28e000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_3,	0x9c0a9f6b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),		0x206a017a, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),		0x00000859, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_3,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_CTL, 0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ANT_CTL,	0x00000001, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(71), 0x0000092a, AR5K_INI_WRITE },*/ /* Old value */
+	{ AR5K_PHY_MAX_RX_LEN,	0x00000c80, AR5K_INI_WRITE },
+	{ AR5K_PHY_IQ,		0x05100000, AR5K_INI_WRITE },
+	{ AR5K_PHY_WARM_RESET,	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY_CTL,		0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f, AR5K_INI_WRITE },
+	{ AR5K_PHY(82),		0x9280b212, AR5K_INI_WRITE },
+	{ AR5K_PHY_RADAR,	0x5d50e188, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(86), 0x000000ff, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(87),		0x004b6a8e, AR5K_INI_WRITE },
+	{ AR5K_PHY_NFTHRES,	0x000003ce, AR5K_INI_WRITE },
+	{ AR5K_PHY_RESTART,	0x192fb515, AR5K_INI_WRITE },
+	{ AR5K_PHY(94),		0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY_RFBUS_REQ,	0x00000000, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(644), 0x0080a333, AR5K_INI_WRITE },*/ /* Old value */
+	/*{ AR5K_PHY(645), 0x00206c10, AR5K_INI_WRITE },*/ /* Old value */
+	{ AR5K_PHY(644),	0x00806333, AR5K_INI_WRITE },
+	{ AR5K_PHY(645),	0x00106c10, AR5K_INI_WRITE },
+	{ AR5K_PHY(646),	0x009c4060, AR5K_INI_WRITE },
+	/* { AR5K_PHY(647), 0x1483800a, AR5K_INI_WRITE }, */
+	/* { AR5K_PHY(648), 0x01831061, AR5K_INI_WRITE }, */ /* Old value */
+	{ AR5K_PHY(648),	0x018830c6, AR5K_INI_WRITE },
+	{ AR5K_PHY(649),	0x00000400, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(651),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x20202020, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(655), 0x13c889af, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(656),	0x38490a20, AR5K_INI_WRITE },
+	{ AR5K_PHY(657),	0x00007bb6, AR5K_INI_WRITE },
+	{ AR5K_PHY(658),	0x0fff3ffc, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
+static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+	   { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+	{ AR5K_TIME_OUT,
+	   { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+	{ AR5K_PHY(8),
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+	{ AR5K_PHY_RF_CTL2,
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+	{ AR5K_PHY_AGCCTL,
+	   { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
+	{ AR5K_PHY_NF,
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
+	   { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+	{ AR5K_PHY(70),
+	   { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+	{ AR5K_PHY_OFDM_SELFCORR,
+	   { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+	{ 0xa230,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5111_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC, 	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL, 	0x00022ffe, AR5K_INI_WRITE },
+	{ 0x983c, 		0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004883, AR5K_INI_WRITE },
+	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000018, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCKTXCTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCK_CROSSCORR, 0xd03e6788, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5112_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x00022ffe, AR5K_INI_WRITE },
+	{ 0x983c,		0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004882, AR5K_INI_WRITE },
+	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	{ 0xa300,
+	   { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+	{ 0xa304,
+	   { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+	{ 0xa308,
+	   { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+	{ 0xa30c,
+	   { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+	{ 0xa310,
+	   { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+	{ 0xa314,
+	   { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+	{ 0xa318,
+	   { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+	{ 0xa31c,
+	   { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+	{ 0xa320,
+	   { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+	{ 0xa324,
+	   { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+	{ 0xa328,
+	   { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+	{ 0xa32c,
+	   { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+	{ 0xa330,
+	   { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+	{ 0xa334,
+	   { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+};
+
+static const struct ath5k_ini rf5413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_5414_CBCFG,	0x00000010, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
+	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL, 0x000009b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x081b7caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */
+/* XXX: a mode ? */
+static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf2413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800000a8, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x001b7caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa300, 0x18010000, AR5K_INI_WRITE },
+	{ 0xa304, 0x30032602, AR5K_INI_WRITE },
+	{ 0xa308, 0x48073e06, AR5K_INI_WRITE },
+	{ 0xa30c, 0x560b4c0a, AR5K_INI_WRITE },
+	{ 0xa310, 0x641a600f, AR5K_INI_WRITE },
+	{ 0xa314, 0x784f6e1b, AR5K_INI_WRITE },
+	{ 0xa318, 0x868f7c5a, AR5K_INI_WRITE },
+	{ 0xa31c, 0x8ecf865b, AR5K_INI_WRITE },
+	{ 0xa320, 0x9d4f970f, AR5K_INI_WRITE },
+	{ 0xa324, 0xa5cfa18f, AR5K_INI_WRITE },
+	{ 0xa328, 0xb55faf1f, AR5K_INI_WRITE },
+	{ 0xa32c, 0xbddfb99f, AR5K_INI_WRITE },
+	{ 0xa330, 0xcd7fc73f, AR5K_INI_WRITE },
+	{ 0xa334, 0xd5ffd1bf, AR5K_INI_WRITE },
+	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */
+/* XXX: a mode ? */
+static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	{ 0xa324,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa328,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa32c,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa330,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa334,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+};
+
+static const struct ath5k_ini rf2425_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
+	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ 0x99dc,		0xfebadbe8, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE4, 0x20202020, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c166, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x081a3caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa300, 0x16010000, AR5K_INI_WRITE },
+	{ 0xa304, 0x2c032402, AR5K_INI_WRITE },
+	{ 0xa308, 0x48433e42, AR5K_INI_WRITE },
+	{ 0xa30c, 0x5a0f500b, AR5K_INI_WRITE },
+	{ 0xa310, 0x6c4b624a, AR5K_INI_WRITE },
+	{ 0xa314, 0x7e8b748a, AR5K_INI_WRITE },
+	{ 0xa318, 0x96cf8ccb, AR5K_INI_WRITE },
+	{ 0xa31c, 0xa34f9d0f, AR5K_INI_WRITE },
+	{ 0xa320, 0xa7cfa58f, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/*
+ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
+ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
+ */
+
+/* RF5111 Initial BaseBand Gain settings */
+static const struct ath5k_ini rf5111_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000026, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x00000016, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x00000036, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x0000000e, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x0000002e, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x00000016, AR5K_INI_WRITE },
+};
+
+/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414+) */
+static const struct ath5k_ini rf5112_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x00000018, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000019, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x0000001a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x0000001b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x0000001c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x0000001d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x0000001a, AR5K_INI_WRITE },
+};
+
+
+/*
+ * Write initial register dump
+ */
+static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
+		const struct ath5k_ini *ini_regs, int change_channel)
+{
+	unsigned int i;
+
+	/* Write initial registers */
+	for (i = 0; i < size; i++) {
+		/* On channel change there is
+		 * no need to mess with PCU */
+		if (change_channel &&
+				ini_regs[i].ini_register >= AR5K_PCU_MIN &&
+				ini_regs[i].ini_register <= AR5K_PCU_MAX)
+			continue;
+
+		switch (ini_regs[i].ini_mode) {
+		case AR5K_INI_READ:
+			/* Cleared on read */
+			ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
+			break;
+		case AR5K_INI_WRITE:
+		default:
+			AR5K_REG_WAIT(i);
+			ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
+					ini_regs[i].ini_register);
+		}
+	}
+}
+
+static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
+		unsigned int size, const struct ath5k_ini_mode *ini_mode,
+		u8 mode)
+{
+	unsigned int i;
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
+			(u32)ini_mode[i].mode_register);
+	}
+}
+
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel)
+{
+	/*
+	 * Write initial register settings
+	 */
+
+	/* For AR5212 and combatible */
+	if (ah->ah_version == AR5K_AR5212) {
+
+		/* First set of mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah,
+			ARRAY_SIZE(ar5212_ini_mode_start),
+			ar5212_ini_mode_start, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
+				ar5212_ini_common_start, change_channel);
+
+		/* Second set of mode-specific settings */
+		switch (ah->ah_radio) {
+		case AR5K_RF5111:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5111_ini_mode_end),
+					rf5111_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_common_end),
+					rf5111_ini_common_end, change_channel);
+
+			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_bbgain),
+					rf5111_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF5112:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5112_ini_mode_end),
+					rf5112_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_common_end),
+					rf5112_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF5413:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5413_ini_mode_end),
+					rf5413_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5413_ini_common_end),
+					rf5413_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF2316:
+		case AR5K_RF2413:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf2413_ini_mode_end),
+					rf2413_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2413_ini_common_end),
+					rf2413_ini_common_end, change_channel);
+
+			/* Override settings from rf2413_ini_common_end */
+			if (ah->ah_radio == AR5K_RF2316) {
+				ath5k_hw_reg_write(ah, 0x00004000,
+							AR5K_PHY_AGC);
+				ath5k_hw_reg_write(ah, 0x081b7caa,
+							0xa274);
+			}
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+			break;
+		case AR5K_RF2317:
+		case AR5K_RF2425:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf2425_ini_mode_end),
+					rf2425_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2425_ini_common_end),
+					rf2425_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+			break;
+		default:
+			return -EINVAL;
+
+		}
+
+	/* For AR5211 */
+	} else if (ah->ah_version == AR5K_AR5211) {
+
+		/* AR5K_MODE_11B */
+		if (mode > 2) {
+			DBG("ath5k: unsupported channel mode %d\n", mode);
+			return -EINVAL;
+		}
+
+		/* Mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
+				ar5211_ini_mode, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
+				ar5211_ini, change_channel);
+
+		/* AR5211 only comes with 5111 */
+
+		/* Baseband gain table */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
+				rf5111_ini_bbgain, change_channel);
+	/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
+	} else if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
+				ar5210_ini, change_channel);
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c
new file mode 100644
index 0000000..c8165da
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Matthew W. S. Bell  <mentor at madwifi.org>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof at winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski at gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*********************************\
+* Protocol Control Unit Functions *
+\*********************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*******************\
+* Generic functions *
+\*******************/
+
+/**
+ * ath5k_hw_set_opmode - Set PCU operating mode
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Initialize PCU for the various operating modes (AP/STA etc)
+ *
+ * For iPXE we always assume STA mode.
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+{
+	u32 pcu_reg, beacon_reg, low_id, high_id;
+
+
+	/* Preserve rest settings */
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+			| AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
+			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
+	beacon_reg = 0;
+
+	pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+		| (ah->ah_version == AR5K_AR5210 ?
+		   AR5K_STA_ID1_PWR_SV : 0);
+
+	/*
+	 * Set PCU registers
+	 */
+	low_id = AR5K_LOW_ID(ah->ah_sta_id);
+	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	/*
+	 * Set Beacon Control Register on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ *
+ * @ah: The &struct ath5k_hw
+ * @high: Flag to determine if we want to use high transmition rate
+ * for ACKs or not
+ *
+ * If high flag is set, we tell hw to use a set of control rates based on
+ * the current transmition rate (check out control_rates array inside reset.c).
+ * If not hw just uses the lowest rate available for the current modulation
+ * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
+ */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high)
+{
+	if (ah->ah_version != AR5K_AR5212)
+		return;
+	else {
+		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+		if (high)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+	}
+}
+
+
+/******************\
+* ACK/CTS Timeouts *
+\******************/
+
+/**
+ * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
+{
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
+		ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
+{
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
+			ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+
+/****************\
+* BSSID handling *
+\****************/
+
+/**
+ * ath5k_hw_get_lladdr - Get station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Initialize ah->ah_sta_id using the mac address provided
+ * (just a memcpy).
+ *
+ * TODO: Remove it once we merge ath5k_softc and ath5k_hw
+ */
+void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
+{
+	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
+}
+
+/**
+ * ath5k_hw_set_lladdr - Set station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Set station id on hw using the provided mac address
+ */
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+{
+	u32 low_id, high_id;
+	u32 pcu_reg;
+
+	/* Set new station ID */
+	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+
+	low_id = AR5K_LOW_ID(mac);
+	high_id = AR5K_HIGH_ID(mac);
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_associd - Set BSSID for association
+ *
+ * @ah: The &struct ath5k_hw
+ * @bssid: BSSID
+ * @assoc_id: Assoc id
+ *
+ * Sets the BSSID which trigers the "SME Join" operation
+ */
+void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+{
+	u32 low_id, high_id;
+
+	/*
+	 * Set simple BSSID mask on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM1);
+	}
+
+	/*
+	 * Set BSSID which triggers the "SME Join" operation
+	 */
+	low_id = AR5K_LOW_ID(bssid);
+	high_id = AR5K_HIGH_ID(bssid);
+	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
+	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
+				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
+}
+
+/**
+ * ath5k_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @ah: the &struct ath5k_hw
+ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ */
+/*
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:                0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1001)
+ *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (0001 & 1010) == 1010
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0010) == (0010)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+{
+	u32 low_id, high_id;
+
+	/* Cache bssid mask so that we can restore it
+	 * on reset */
+	memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
+	if (ah->ah_version == AR5K_AR5212) {
+		low_id = AR5K_LOW_ID(mask);
+		high_id = AR5K_HIGH_ID(mask);
+
+		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+
+/************\
+* RX Control *
+\************/
+
+/**
+ * ath5k_hw_start_rx_pcu - Start RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Starts RX engine on PCU so that hw can process RXed frames
+ * (ACK etc).
+ *
+ * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
+ * TODO: Init ANI here
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * at5k_hw_stop_rx_pcu - Stop RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stops RX engine on PCU
+ *
+ * TODO: Detach ANI here
+ */
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+{
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Set multicast filter
+ */
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+{
+	/* Set the multicat filter */
+	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
+	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
+}
+
+/**
+ * ath5k_hw_get_rx_filter - Get current rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Returns the RX filter by reading rx filter and
+ * phy error filter registers. RX filter is used
+ * to set the allowed frame types that PCU will accept
+ * and pass to the driver. For a list of frame types
+ * check out reg.h.
+ */
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+{
+	u32 data, filter = 0;
+
+	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
+
+	/*Radar detection for 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
+
+		if (data & AR5K_PHY_ERR_FIL_RADAR)
+			filter |= AR5K_RX_FILTER_RADARERR;
+		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
+			filter |= AR5K_RX_FILTER_PHYERR;
+	}
+
+	return filter;
+}
+
+/**
+ * ath5k_hw_set_rx_filter - Set rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ * @filter: RX filter mask (see reg.h)
+ *
+ * Sets RX filter register and also handles PHY error filter
+ * register on 5212 and newer chips so that we have proper PHY
+ * error reporting.
+ */
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+{
+	u32 data = 0;
+
+	/* Set PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		if (filter & AR5K_RX_FILTER_RADARERR)
+			data |= AR5K_PHY_ERR_FIL_RADAR;
+		if (filter & AR5K_RX_FILTER_PHYERR)
+			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
+	}
+
+	/*
+	 * The AR5210 uses promiscous mode to detect radar activity
+	 */
+	if (ah->ah_version == AR5K_AR5210 &&
+			(filter & AR5K_RX_FILTER_RADARERR)) {
+		filter &= ~AR5K_RX_FILTER_RADARERR;
+		filter |= AR5K_RX_FILTER_PROM;
+	}
+
+	/*Zero length DMA (phy error reporting) */
+	if (data)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+
+	/*Write RX Filter register*/
+	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
+
+	/*Write PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212)
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
+
+}
+
+/*********************\
+* Key table functions *
+\*********************/
+
+/*
+ * Reset a key entry on the table
+ */
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+{
+	unsigned int i, type;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+
+	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
+	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+
+	/* Reset associated MIC entry if TKIP
+	 * is enabled located at offset (entry + 64) */
+	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+			ath5k_hw_reg_write(ah, 0,
+				AR5K_KEYTABLE_OFF(micentry, i));
+	}
+
+	/*
+	 * Set NULL encryption on AR5212+
+	 *
+	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
+	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
+	 *
+	 * Note2: Windows driver (ndiswrapper) sets this to
+	 *        0x00000714 instead of 0x00000007
+	 */
+	if (ah->ah_version >= AR5K_AR5211) {
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(entry));
+
+		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(micentry));
+		}
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c
new file mode 100644
index 0000000..7891d39
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c
@@ -0,0 +1,2581 @@
+/*
+ * PHY functions
+ *
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby at gmail.com>
+ * Copyright (c) 2008-2009 Felix Fietkau <nbd at openwrt.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#define _ATH5K_PHY
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+#include "rfbuffer.h"
+#include "rfgain.h"
+
+static inline int min(int x, int y)
+{
+	return (x < y) ? x : y;
+}
+
+static inline int max(int x, int y)
+{
+	return (x > y) ? x : y;
+}
+
+/*
+ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
+ */
+static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
+					const struct ath5k_rf_reg *rf_regs,
+					u32 val, u8 reg_id, int set)
+{
+	const struct ath5k_rf_reg *rfreg = NULL;
+	u8 offset, bank, num_bits, col, position;
+	u16 entry;
+	u32 mask, data, last_bit, bits_shifted, first_bit;
+	u32 *rfb;
+	s32 bits_left;
+	unsigned i;
+
+	data = 0;
+	rfb = ah->ah_rf_banks;
+
+	for (i = 0; i < ah->ah_rf_regs_count; i++) {
+		if (rf_regs[i].index == reg_id) {
+			rfreg = &rf_regs[i];
+			break;
+		}
+	}
+
+	if (rfb == NULL || rfreg == NULL) {
+		DBG("ath5k: RF register not found!\n");
+		/* should not happen */
+		return 0;
+	}
+
+	bank = rfreg->bank;
+	num_bits = rfreg->field.len;
+	first_bit = rfreg->field.pos;
+	col = rfreg->field.col;
+
+	/* first_bit is an offset from bank's
+	 * start. Since we have all banks on
+	 * the same array, we use this offset
+	 * to mark each bank's start */
+	offset = ah->ah_offset[bank];
+
+	/* Boundary check */
+	if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
+		DBG("ath5k: RF invalid values at offset %d\n", offset);
+		return 0;
+	}
+
+	entry = ((first_bit - 1) / 8) + offset;
+	position = (first_bit - 1) % 8;
+
+	if (set)
+		data = ath5k_hw_bitswap(val, num_bits);
+
+	for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
+	position = 0, entry++) {
+
+		last_bit = (position + bits_left > 8) ? 8 :
+					position + bits_left;
+
+		mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
+								(col * 8);
+
+		if (set) {
+			rfb[entry] &= ~mask;
+			rfb[entry] |= ((data << position) << (col * 8)) & mask;
+			data >>= (8 - position);
+		} else {
+			data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
+				<< bits_shifted;
+			bits_shifted += last_bit - position;
+		}
+
+		bits_left -= 8 - position;
+	}
+
+	data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
+
+	return data;
+}
+
+/**********************\
+* RF Gain optimization *
+\**********************/
+
+/*
+ * This code is used to optimize rf gain on different environments
+ * (temprature mostly) based on feedback from a power detector.
+ *
+ * It's only used on RF5111 and RF5112, later RF chips seem to have
+ * auto adjustment on hw -notice they have a much smaller BANK 7 and
+ * no gain optimization ladder-.
+ *
+ * For more infos check out this patent doc
+ * http://www.freepatentsonline.com/7400691.html
+ *
+ * This paper describes power drops as seen on the receiver due to
+ * probe packets
+ * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
+ * %20of%20Power%20Control.pdf
+ *
+ * And this is the MadWiFi bug entry related to the above
+ * http://madwifi-project.org/ticket/1659
+ * with various measurements and diagrams
+ *
+ * TODO: Deal with power drops due to probes by setting an apropriate
+ * tx power on the probe packets ! Make this part of the calibration process.
+ */
+
+/* Initialize ah_gain durring attach */
+int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
+{
+	/* Initialize the gain optimization values */
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 35;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	case AR5K_RF5112:
+		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 85;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Schedule a gain probe check on the next transmited packet.
+ * That means our next packet is going to be sent with lower
+ * tx power and a Peak to Average Power Detector (PAPD) will try
+ * to measure the gain.
+ *
+ * TODO: Use propper tx power setting for the probe packet so
+ * that we don't observe a serious power drop on the receiver
+ *
+ * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
+ * just after we enable the probe so that we don't mess with
+ * standard traffic ? Maybe it's time to use sw interrupts and
+ * a probe tasklet !!!
+ */
+static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
+{
+
+	/* Skip if gain calibration is inactive or
+	 * we already handle a probe request */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
+		return;
+
+	/* Send the packet with 2dB below max power as
+	 * patent doc suggest */
+	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4,
+			AR5K_PHY_PAPD_PROBE_TXPOWER) |
+			AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
+
+	ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
+
+}
+
+/* Calculate gain_F measurement correction
+ * based on the current step for RF5112 rev. 2 */
+static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
+{
+	u32 mix, step;
+	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
+	const struct ath5k_rf_reg *rf_regs;
+
+	/* Only RF5112 Rev. 2 supports it */
+	if ((ah->ah_radio != AR5K_RF5112) ||
+	(ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
+		return 0;
+
+	go = &rfgain_opt_5112;
+	rf_regs = rf_regs_5112a;
+	ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	if (ah->ah_rf_banks == NULL)
+		return 0;
+
+	ah->ah_gain.g_f_corr = 0;
+
+	/* No VGA (Variable Gain Amplifier) override, skip */
+	if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1)
+		return 0;
+
+	/* Mix gain stepping */
+	step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0);
+
+	/* Mix gain override */
+	mix = g_step->gos_param[0];
+
+	switch (mix) {
+	case 3:
+		ah->ah_gain.g_f_corr = step * 2;
+		break;
+	case 2:
+		ah->ah_gain.g_f_corr = (step - 5) * 2;
+		break;
+	case 1:
+		ah->ah_gain.g_f_corr = step;
+		break;
+	default:
+		ah->ah_gain.g_f_corr = 0;
+		break;
+	}
+
+	return ah->ah_gain.g_f_corr;
+}
+
+/* Check if current gain_F measurement is in the range of our
+ * power detector windows. If we get a measurement outside range
+ * we know it's not accurate (detectors can't measure anything outside
+ * their detection window) so we must ignore it */
+static int ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
+{
+	const struct ath5k_rf_reg *rf_regs;
+	u32 step, mix_ovr, level[4];
+
+	if (ah->ah_rf_banks == NULL)
+		return 0;
+
+	if (ah->ah_radio == AR5K_RF5111) {
+
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+
+		step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
+			0);
+
+		level[0] = 0;
+		level[1] = (step == 63) ? 50 : step + 4;
+		level[2] = (step != 63) ? 64 : level[0];
+		level[3] = level[2] + 50 ;
+
+		ah->ah_gain.g_high = level[3] -
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+		ah->ah_gain.g_low = level[0] +
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+	} else {
+
+		rf_regs = rf_regs_5112;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+
+		mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
+			0);
+
+		level[0] = level[2] = 0;
+
+		if (mix_ovr == 1) {
+			level[1] = level[3] = 83;
+		} else {
+			level[1] = level[3] = 107;
+			ah->ah_gain.g_high = 55;
+		}
+	}
+
+	return (ah->ah_gain.g_current >= level[0] &&
+			ah->ah_gain.g_current <= level[1]) ||
+		(ah->ah_gain.g_current >= level[2] &&
+			ah->ah_gain.g_current <= level[3]);
+}
+
+/* Perform gain_F adjustment by choosing the right set
+ * of parameters from rf gain optimization ladder */
+static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
+{
+	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
+	int ret = 0;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		go = &rfgain_opt_5111;
+		break;
+	case AR5K_RF5112:
+		go = &rfgain_opt_5112;
+		break;
+	default:
+		return 0;
+	}
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+
+		/* Reached maximum */
+		if (ah->ah_gain.g_step_idx == 0)
+			return -1;
+
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
+				ah->ah_gain.g_step_idx > 0;
+				g_step = &go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
+			    g_step->gos_gain);
+
+		ret = 1;
+		goto done;
+	}
+
+	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+
+		/* Reached minimum */
+		if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
+			return -2;
+
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target <= ah->ah_gain.g_low &&
+				ah->ah_gain.g_step_idx < go->go_steps_count-1;
+				g_step = &go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
+			    g_step->gos_gain);
+
+		ret = 2;
+		goto done;
+	}
+
+done:
+	DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, "
+	     "target gain %d\n", ret, ah->ah_gain.g_step_idx,
+	     ah->ah_gain.g_current, ah->ah_gain.g_target);
+
+	return ret;
+}
+
+/* Main callback for thermal rf gain calibration engine
+ * Check for a new gain reading and schedule an adjustment
+ * if needed.
+ *
+ * TODO: Use sw interrupt to schedule reset if gain_F needs
+ * adjustment */
+enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
+{
+	u32 data, type;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+	if (ah->ah_rf_banks == NULL ||
+	ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
+		return AR5K_RFGAIN_INACTIVE;
+
+	/* No check requested, either engine is inactive
+	 * or an adjustment is already requested */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
+		goto done;
+
+	/* Read the PAPD (Peak to Average Power Detector)
+	 * register */
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+	/* No probe is scheduled, read gain_F measurement */
+	if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
+		ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
+		type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
+
+		/* If tx packet is CCK correct the gain_F measurement
+		 * by cck ofdm gain delta */
+		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
+			if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+				ah->ah_gain.g_current +=
+					ee->ee_cck_ofdm_gain_delta;
+			else
+				ah->ah_gain.g_current +=
+					AR5K_GAIN_CCK_PROBE_CORR;
+		}
+
+		/* Further correct gain_F measurement for
+		 * RF5112A radios */
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			ath5k_hw_rf_gainf_corr(ah);
+			ah->ah_gain.g_current =
+				ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
+				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+				0;
+		}
+
+		/* Check if measurement is ok and if we need
+		 * to adjust gain, schedule a gain adjustment,
+		 * else switch back to the acive state */
+		if (ath5k_hw_rf_check_gainf_readback(ah) &&
+		AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+		ath5k_hw_rf_gainf_adjust(ah)) {
+			ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
+		} else {
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
+	}
+
+done:
+	return ah->ah_gain.g_state;
+}
+
+/* Write initial rf gain table to set the RF sensitivity
+ * this one works on all RF chips and has nothing to do
+ * with gain_F calibration */
+int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
+{
+	const struct ath5k_ini_rfgain *ath5k_rfg;
+	unsigned int i, size;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ath5k_rfg = rfgain_5111;
+		size = ARRAY_SIZE(rfgain_5111);
+		break;
+	case AR5K_RF5112:
+		ath5k_rfg = rfgain_5112;
+		size = ARRAY_SIZE(rfgain_5112);
+		break;
+	case AR5K_RF2413:
+		ath5k_rfg = rfgain_2413;
+		size = ARRAY_SIZE(rfgain_2413);
+		break;
+	case AR5K_RF2316:
+		ath5k_rfg = rfgain_2316;
+		size = ARRAY_SIZE(rfgain_2316);
+		break;
+	case AR5K_RF5413:
+		ath5k_rfg = rfgain_5413;
+		size = ARRAY_SIZE(rfgain_5413);
+		break;
+	case AR5K_RF2317:
+	case AR5K_RF2425:
+		ath5k_rfg = rfgain_2425;
+		size = ARRAY_SIZE(rfgain_2425);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case AR5K_INI_RFGAIN_2GHZ:
+	case AR5K_INI_RFGAIN_5GHZ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+			(u32)ath5k_rfg[i].rfg_register);
+	}
+
+	return 0;
+}
+
+
+
+/********************\
+* RF Registers setup *
+\********************/
+
+
+/*
+ * Setup RF registers by writing rf buffer on hw
+ */
+int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct net80211_channel *channel,
+		unsigned int mode)
+{
+	const struct ath5k_rf_reg *rf_regs;
+	const struct ath5k_ini_rfbuffer *ini_rfb;
+	const struct ath5k_gain_opt *go = NULL;
+	const struct ath5k_gain_opt_step *g_step;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u8 ee_mode = 0;
+	u32 *rfb;
+	int obdb = -1, bank = -1;
+	unsigned i;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+		ini_rfb = rfb_5111;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
+		go = &rfgain_opt_5111;
+		break;
+	case AR5K_RF5112:
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			rf_regs = rf_regs_5112a;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+			ini_rfb = rfb_5112a;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
+		} else {
+			rf_regs = rf_regs_5112;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+			ini_rfb = rfb_5112;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
+		}
+		go = &rfgain_opt_5112;
+		break;
+	case AR5K_RF2413:
+		rf_regs = rf_regs_2413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
+		ini_rfb = rfb_2413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
+		break;
+	case AR5K_RF2316:
+		rf_regs = rf_regs_2316;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
+		ini_rfb = rfb_2316;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
+		break;
+	case AR5K_RF5413:
+		rf_regs = rf_regs_5413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
+		ini_rfb = rfb_5413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
+		break;
+	case AR5K_RF2317:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		ini_rfb = rfb_2317;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
+		break;
+	case AR5K_RF2425:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
+			ini_rfb = rfb_2425;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
+		} else {
+			ini_rfb = rfb_2417;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* If it's the first time we set rf buffer, allocate
+	 * ah->ah_rf_banks based on ah->ah_rf_banks_size
+	 * we set above */
+	if (ah->ah_rf_banks == NULL) {
+		ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size);
+		if (ah->ah_rf_banks == NULL) {
+			return -ENOMEM;
+		}
+	}
+
+	/* Copy values to modify them */
+	rfb = ah->ah_rf_banks;
+
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
+			DBG("ath5k: invalid RF register bank\n");
+			return -EINVAL;
+		}
+
+		/* Bank changed, write down the offset */
+		if (bank != ini_rfb[i].rfb_bank) {
+			bank = ini_rfb[i].rfb_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rfb[i] = ini_rfb[i].rfb_mode_data[mode];
+	}
+
+	/* Set Output and Driver bias current (OB/DB) */
+	if (channel->hw_value & CHANNEL_2GHZ) {
+
+		if (channel->hw_value & CHANNEL_CCK)
+			ee_mode = AR5K_EEPROM_MODE_11B;
+		else
+			ee_mode = AR5K_EEPROM_MODE_11G;
+
+		/* For RF511X/RF211X combination we
+		 * use b_OB and b_DB parameters stored
+		 * in eeprom on ee->ee_ob[ee_mode][0]
+		 *
+		 * For all other chips we use OB/DB for 2Ghz
+		 * stored in the b/g modal section just like
+		 * 802.11a on ee->ee_ob[ee_mode][1] */
+		if ((ah->ah_radio == AR5K_RF5111) ||
+		(ah->ah_radio == AR5K_RF5112))
+			obdb = 0;
+		else
+			obdb = 1;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_2GHZ, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_2GHZ, 1);
+
+	/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
+	} else if ((channel->hw_value & CHANNEL_5GHZ) ||
+			(ah->ah_radio == AR5K_RF5111)) {
+
+		/* For 11a, Turbo and XR we need to choose
+		 * OB/DB based on frequency range */
+		ee_mode = AR5K_EEPROM_MODE_11A;
+		obdb =	 channel->center_freq >= 5725 ? 3 :
+			(channel->center_freq >= 5500 ? 2 :
+			(channel->center_freq >= 5260 ? 1 :
+			 (channel->center_freq > 4000 ? 0 : -1)));
+
+		if (obdb < 0)
+			return -EINVAL;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_5GHZ, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_5GHZ, 1);
+	}
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	/* Bank Modifications (chip-specific) */
+	if (ah->ah_radio == AR5K_RF5111) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+					AR5K_PHY_FRAME_CTL_TX_CLIP,
+					g_step->gos_param[0]);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+							AR5K_RF_PWD_90, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+							AR5K_RF_PWD_84, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_RFGAIN_SEL, 1);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
+						AR5K_RF_PWD_XPD, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_PLO_SEL, 1);
+
+		/* TODO: Half/quarter channel support */
+	}
+
+	if (ah->ah_radio == AR5K_RF5112) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
+						AR5K_RF_MIXGAIN_OVR, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+						AR5K_RF_PWD_138, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+						AR5K_RF_PWD_137, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_PWD_136, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
+						AR5K_RF_PWD_132, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
+						AR5K_RF_PWD_131, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
+						AR5K_RF_PWD_130, 1);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_XPD_SEL, 1);
+
+		if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
+			/* Rev. 1 supports only one xpd */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, 1);
+
+		} else {
+			/* TODO: Set high and low gain bits */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_LO, 1);
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_HI, 1);
+
+			/* Lower synth voltage on Rev 2 */
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_HIGH_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_MID_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_LOW_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_PUSH_UP, 1);
+
+			/* Decrease power consumption on 5213+ BaseBand */
+			if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PAD2GND, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB2_LVL, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB5_LVL, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_167, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_166, 1);
+			}
+		}
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, 1);
+
+		/* TODO: Half/quarter channel support */
+
+	}
+
+	if (ah->ah_radio == AR5K_RF5413 &&
+	channel->hw_value & CHANNEL_2GHZ) {
+
+		ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
+									1);
+
+		/* Set optimum value for early revisions (on pci-e chips) */
+		if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
+		ah->ah_mac_srev < AR5K_SREV_AR5413)
+			ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
+						AR5K_RF_PWD_ICLOBUF_2G, 1);
+
+	}
+
+	/* Write RF banks on hw */
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
+	}
+
+	return 0;
+}
+
+
+/**************************\
+  PHY/RF channel functions
+\**************************/
+
+/*
+ * Check if a channel is supported
+ */
+int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+	/* Check if the channel is in our supported range */
+	if (flags & CHANNEL_2GHZ) {
+		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+			return 1;
+	} else if (flags & CHANNEL_5GHZ)
+		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+			return 1;
+
+	return 0;
+}
+
+/*
+ * Convertion needed for RF5110
+ */
+static u32 ath5k_hw_rf5110_chan2athchan(struct net80211_channel *channel)
+{
+	u32 athchan;
+
+	/*
+	 * Convert IEEE channel/MHz to an internal channel value used
+	 * by the AR5210 chipset. This has not been verified with
+	 * newer chipsets like the AR5212A who have a completely
+	 * different RF/PHY part.
+	 */
+	athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq)
+				     - 24) / 2, 5) << 1)
+		| (1 << 6) | 0x1;
+	return athchan;
+}
+
+/*
+ * Set channel on RF5110
+ */
+static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data;
+
+	/*
+	 * Set the channel and wait
+	 */
+	data = ath5k_hw_rf5110_chan2athchan(channel);
+	ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
+	mdelay(1);
+
+	return 0;
+}
+
+/*
+ * Convertion needed for 5111
+ */
+static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
+		struct ath5k_athchan_2ghz *athchan)
+{
+	int channel;
+
+	/* Cast this value to catch negative channel numbers (>= -19) */
+	channel = (int)ieee;
+
+	/*
+	 * Map 2GHz IEEE channel to 5GHz Atheros channel
+	 */
+	if (channel <= 13) {
+		athchan->a2_athchan = 115 + channel;
+		athchan->a2_flags = 0x46;
+	} else if (channel == 14) {
+		athchan->a2_athchan = 124;
+		athchan->a2_flags = 0x44;
+	} else if (channel >= 15 && channel <= 26) {
+		athchan->a2_athchan = ((channel - 14) * 4) + 132;
+		athchan->a2_flags = 0x46;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Set channel on 5111
+ */
+static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	struct ath5k_athchan_2ghz ath5k_channel_2ghz;
+	unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq);
+	u32 data0, data1, clock;
+	int ret;
+
+	/*
+	 * Set the channel on the RF5111 radio
+	 */
+	data0 = data1 = 0;
+
+	if (channel->hw_value & CHANNEL_2GHZ) {
+		/* Map 2GHz channel to 5GHz Atheros channel ID */
+		ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel,
+						   &ath5k_channel_2ghz);
+		if (ret)
+			return ret;
+
+		ath5k_channel = ath5k_channel_2ghz.a2_athchan;
+		data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
+		    << 5) | (1 << 4);
+	}
+
+	if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
+		clock = 1;
+		data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
+			(clock << 1) | (1 << 10) | 1;
+	} else {
+		clock = 0;
+		data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
+			<< 2) | (clock << 1) | (1 << 10) | 1;
+	}
+
+	ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
+			AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
+			AR5K_RF_BUFFER_CONTROL_3);
+
+	return 0;
+}
+
+/*
+ * Set channel on 5112 and newer
+ */
+static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data, data0, data1, data2;
+	u16 c;
+
+	data = data0 = data1 = data2 = 0;
+	c = channel->center_freq;
+
+	if (c < 4800) {
+		if (!((c - 2224) % 5)) {
+			data0 = ((2 * (c - 704)) - 3040) / 10;
+			data1 = 1;
+		} else if (!((c - 2192) % 5)) {
+			data0 = ((2 * (c - 672)) - 3040) / 10;
+			data1 = 0;
+		} else
+			return -EINVAL;
+
+		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
+		if (!(c % 20) && c >= 5120) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+			data2 = ath5k_hw_bitswap(3, 2);
+		} else if (!(c % 10)) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+			data2 = ath5k_hw_bitswap(2, 2);
+		} else if (!(c % 5)) {
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+			data2 = ath5k_hw_bitswap(1, 2);
+		} else
+			return -EINVAL;
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
+	}
+
+	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
+/*
+ * Set the channel on the RF2425
+ */
+static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data, data0, data2;
+	u16 c;
+
+	data = data0 = data2 = 0;
+	c = channel->center_freq;
+
+	if (c < 4800) {
+		data0 = ath5k_hw_bitswap((c - 2272), 8);
+		data2 = 0;
+	/* ? 5GHz ? */
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
+		if (!(c % 20) && c < 5120)
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+		else if (!(c % 10))
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+		else if (!(c % 5))
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+		else
+			return -EINVAL;
+		data2 = ath5k_hw_bitswap(1, 2);
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
+	}
+
+	data = (data0 << 4) | data2 << 2 | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
+/*
+ * Set a channel on the radio chip
+ */
+int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel)
+{
+	int ret;
+	/*
+	 * Check bounds supported by the PHY (we don't care about regultory
+	 * restrictions at this point). Note: hw_value already has the band
+	 * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
+	 * of the band by that */
+	if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
+		DBG("ath5k: channel frequency (%d MHz) out of supported "
+		    "range\n", channel->center_freq);
+		return -EINVAL;
+	}
+
+	/*
+	 * Set the channel and wait
+	 */
+	switch (ah->ah_radio) {
+	case AR5K_RF5110:
+		ret = ath5k_hw_rf5110_channel(ah, channel);
+		break;
+	case AR5K_RF5111:
+		ret = ath5k_hw_rf5111_channel(ah, channel);
+		break;
+	case AR5K_RF2425:
+		ret = ath5k_hw_rf2425_channel(ah, channel);
+		break;
+	default:
+		ret = ath5k_hw_rf5112_channel(ah, channel);
+		break;
+	}
+
+	if (ret) {
+		DBG("ath5k: setting channel failed: %s\n", strerror(ret));
+		return ret;
+	}
+
+	/* Set JAPAN setting for channel 14 */
+	if (channel->center_freq == 2484) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_JAPAN);
+	} else {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_WORLD);
+	}
+
+	ah->ah_current_channel = channel;
+	ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0);
+
+	return 0;
+}
+
+/*****************\
+  PHY calibration
+\*****************/
+
+/**
+ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
+ *
+ * @ah: struct ath5k_hw pointer we are operating on
+ * @freq: the channel frequency, just used for error logging
+ *
+ * This function performs a noise floor calibration of the PHY and waits for
+ * it to complete. Then the noise floor value is compared to some maximum
+ * noise floor we consider valid.
+ *
+ * Note that this is different from what the madwifi HAL does: it reads the
+ * noise floor and afterwards initiates the calibration. Since the noise floor
+ * calibration can take some time to finish, depending on the current channel
+ * use, that avoids the occasional timeout warnings we are seeing now.
+ *
+ * See the following link for an Atheros patent on noise floor calibration:
+ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
+ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+ *
+ * XXX: Since during noise floor calibration antennas are detached according to
+ * the patent, we should stop tx queues here.
+ */
+int
+ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+{
+	int ret;
+	unsigned int i;
+	s32 noise_floor;
+
+	/*
+	 * Enable noise floor calibration
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_NF);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_NF, 0, 0);
+
+	if (ret) {
+		DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq);
+		return -EAGAIN;
+	}
+
+	/* Wait until the noise floor is calibrated and read the value */
+	for (i = 20; i > 0; i--) {
+		mdelay(1);
+		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
+		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
+			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
+
+			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
+				break;
+		}
+	}
+
+	DBG2("ath5k: noise floor %d\n", noise_floor);
+
+	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
+		DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq);
+		return -EAGAIN;
+	}
+
+	ah->ah_noise_floor = noise_floor;
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5110
+ * -Fix BPSK/QAM Constellation (I/Q correction)
+ * -Calculate Noise Floor
+ */
+static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 phy_sig, phy_agc, phy_sat, beacon;
+	int ret;
+
+	/*
+	 * Disable beacons and RX/TX queues, wait
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
+	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
+
+	mdelay(2);
+
+	/*
+	 * Set the channel (with AGC turned off)
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ret = ath5k_hw_channel(ah, channel);
+
+	/*
+	 * Activate PHY and wait
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+	mdelay(1);
+
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * Calibrate the radio chip
+	 */
+
+	/* Remember normal state */
+	phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
+	phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
+	phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
+
+	/* Update radio registers */
+	ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
+		AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
+
+	ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
+			AR5K_PHY_AGCCOARSE_LO)) |
+		AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
+		AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
+
+	ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
+			AR5K_PHY_ADCSAT_THR)) |
+		AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
+		AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
+
+	udelay(20);
+
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	mdelay(1);
+
+	/*
+	 * Enable calibration and wait until completion
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, 0);
+
+	/* Reset to normal state */
+	ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
+	ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
+	ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
+
+	if (ret) {
+		DBG("ath5k: calibration timeout (%d MHz)\n",
+		    channel->center_freq);
+		return ret;
+	}
+
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+	/*
+	 * Re-enable RX/TX and beacons
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5111/5112 and newer chips
+ */
+static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 i_pwr, q_pwr;
+	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+	int i;
+
+	if (!ah->ah_calibration ||
+		ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+		goto done;
+
+	/* Calibration has finished, get the results and re-run */
+	for (i = 0; i <= 10; i++) {
+		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+	}
+
+	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
+	q_coffd = q_pwr >> 7;
+
+	/* No correction */
+	if (i_coffd == 0 || q_coffd == 0)
+		goto done;
+
+	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
+
+	/* Boundary check */
+	if (i_coff > 31)
+		i_coff = 31;
+	if (i_coff < -32)
+		i_coff = -32;
+
+	q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
+
+	/* Boundary check */
+	if (q_coff > 15)
+		q_coff = 15;
+	if (q_coff < -16)
+		q_coff = -16;
+
+	/* Commit new I/Q value */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
+		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+
+	/* Re-enable calibration -if we don't we'll commit
+	 * the same values again and again */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+			AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
+
+done:
+
+	/* TODO: Separate noise floor calibration from I/Q calibration
+	 * since noise floor calibration interrupts rx path while I/Q
+	 * calibration doesn't. We don't need to run noise floor calibration
+	 * as often as I/Q calibration.*/
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+	/* Initiate a gain_F calibration */
+	ath5k_hw_request_rfgain_probe(ah);
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration
+ */
+int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	int ret;
+
+	if (ah->ah_radio == AR5K_RF5110)
+		ret = ath5k_hw_rf5110_calibrate(ah, channel);
+	else
+		ret = ath5k_hw_rf511x_calibrate(ah, channel);
+
+	return ret;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+	return 0;
+}
+
+/********************\
+  Misc PHY functions
+\********************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+	unsigned int i;
+	u32 srev;
+	u16 ret;
+
+	/*
+	 * Set the radio chip access register
+	 */
+	switch (chan) {
+	case CHANNEL_2GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+		break;
+	case CHANNEL_5GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+		break;
+	default:
+		return 0;
+	}
+
+	mdelay(2);
+
+	/* ...wait until PHY is ready and read the selected radio revision */
+	ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+	for (i = 0; i < 8; i++)
+		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+	if (ah->ah_version == AR5K_AR5210) {
+		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+	} else {
+		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+		ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+				((srev & 0x0f) << 4), 8);
+	}
+
+	/* Reset to the 5GHz mode */
+	ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+	return ret;
+}
+
+void /*TODO:Boundary check*/
+ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
+{
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
+}
+
+unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
+{
+	if (ah->ah_version != AR5K_AR5210)
+		return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+	return 0; /*XXX: What do we return for 5210 ?*/
+}
+
+
+/****************\
+* TX power setup *
+\****************/
+
+/*
+ * Helper functions
+ */
+
+/*
+ * Do linear interpolation between two given (x, y) points
+ */
+static s16
+ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
+					s16 y_left, s16 y_right)
+{
+	s16 ratio, result;
+
+	/* Avoid divide by zero and skip interpolation
+	 * if we have the same point */
+	if ((x_left == x_right) || (y_left == y_right))
+		return y_left;
+
+	/*
+	 * Since we use ints and not fps, we need to scale up in
+	 * order to get a sane ratio value (or else we 'll eg. get
+	 * always 1 instead of 1.25, 1.75 etc). We scale up by 100
+	 * to have some accuracy both for 0.5 and 0.25 steps.
+	 */
+	ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
+
+	/* Now scale down to be in range */
+	result = y_left + (ratio * (target - x_left) / 100);
+
+	return result;
+}
+
+/*
+ * Find vertical boundary (min pwr) for the linear PCDAC curve.
+ *
+ * Since we have the top of the curve and we draw the line below
+ * until we reach 1 (1 pcdac step) we need to know which point
+ * (x value) that is so that we don't go below y axis and have negative
+ * pcdac values when creating the curve, or fill the table with zeroes.
+ */
+static s16
+ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
+				const s16 *pwrL, const s16 *pwrR)
+{
+	s8 tmp;
+	s16 min_pwrL, min_pwrR;
+	s16 pwr_i;
+
+	if (pwrL[0] == pwrL[1])
+		min_pwrL = pwrL[0];
+	else {
+		pwr_i = pwrL[0];
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrL[0], pwrL[1],
+							stepL[0], stepL[1]);
+		} while (tmp > 1);
+
+		min_pwrL = pwr_i;
+	}
+
+	if (pwrR[0] == pwrR[1])
+		min_pwrR = pwrR[0];
+	else {
+		pwr_i = pwrR[0];
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrR[0], pwrR[1],
+							stepR[0], stepR[1]);
+		} while (tmp > 1);
+
+		min_pwrR = pwr_i;
+	}
+
+	/* Keep the right boundary so that it works for both curves */
+	return max(min_pwrL, min_pwrR);
+}
+
+/*
+ * Interpolate (pwr,vpd) points to create a Power to PDADC or a
+ * Power to PCDAC curve.
+ *
+ * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC
+ * steps (offsets) on y axis. Power can go up to 31.5dB and max
+ * PCDAC/PDADC step for each curve is 64 but we can write more than
+ * one curves on hw so we can go up to 128 (which is the max step we
+ * can write on the final table).
+ *
+ * We write y values (PCDAC/PDADC steps) on hw.
+ */
+static void
+ath5k_create_power_curve(s16 pmin, s16 pmax,
+			const s16 *pwr, const u8 *vpd,
+			u8 num_points,
+			u8 *vpd_table, u8 type)
+{
+	u8 idx[2] = { 0, 1 };
+	s16 pwr_i = 2*pmin;
+	int i;
+
+	if (num_points < 2)
+		return;
+
+	/* We want the whole line, so adjust boundaries
+	 * to cover the entire power range. Note that
+	 * power values are already 0.25dB so no need
+	 * to multiply pwr_i by 2 */
+	if (type == AR5K_PWRTABLE_LINEAR_PCDAC) {
+		pwr_i = pmin;
+		pmin = 0;
+		pmax = 63;
+	}
+
+	/* Find surrounding turning points (TPs)
+	 * and interpolate between them */
+	for (i = 0; (i <= (u16) (pmax - pmin)) &&
+	(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
+
+		/* We passed the right TP, move to the next set of TPs
+		 * if we pass the last TP, extrapolate above using the last
+		 * two TPs for ratio */
+		if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) {
+			idx[0]++;
+			idx[1]++;
+		}
+
+		vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i,
+						pwr[idx[0]], pwr[idx[1]],
+						vpd[idx[0]], vpd[idx[1]]);
+
+		/* Increase by 0.5dB
+		 * (0.25 dB units) */
+		pwr_i += 2;
+	}
+}
+
+/*
+ * Get the surrounding per-channel power calibration piers
+ * for a given frequency so that we can interpolate between
+ * them and come up with an apropriate dataset for our current
+ * channel.
+ */
+static void
+ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			struct ath5k_chan_pcal_info **pcinfo_l,
+			struct ath5k_chan_pcal_info **pcinfo_r)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcinfo;
+	u8 idx_l, idx_r;
+	u8 mode, max, i;
+	u32 target = channel->center_freq;
+
+	idx_l = 0;
+	idx_r = 0;
+
+	if (!(channel->hw_value & CHANNEL_OFDM)) {
+		pcinfo = ee->ee_pwr_cal_b;
+		mode = AR5K_EEPROM_MODE_11B;
+	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		pcinfo = ee->ee_pwr_cal_g;
+		mode = AR5K_EEPROM_MODE_11G;
+	} else {
+		pcinfo = ee->ee_pwr_cal_a;
+		mode = AR5K_EEPROM_MODE_11A;
+	}
+	max = ee->ee_n_piers[mode] - 1;
+
+	/* Frequency is below our calibrated
+	 * range. Use the lowest power curve
+	 * we have */
+	if (target < pcinfo[0].freq) {
+		idx_l = idx_r = 0;
+		goto done;
+	}
+
+	/* Frequency is above our calibrated
+	 * range. Use the highest power curve
+	 * we have */
+	if (target > pcinfo[max].freq) {
+		idx_l = idx_r = max;
+		goto done;
+	}
+
+	/* Frequency is inside our calibrated
+	 * channel range. Pick the surrounding
+	 * calibration piers so that we can
+	 * interpolate */
+	for (i = 0; i <= max; i++) {
+
+		/* Frequency matches one of our calibration
+		 * piers, no need to interpolate, just use
+		 * that calibration pier */
+		if (pcinfo[i].freq == target) {
+			idx_l = idx_r = i;
+			goto done;
+		}
+
+		/* We found a calibration pier that's above
+		 * frequency, use this pier and the previous
+		 * one to interpolate */
+		if (target < pcinfo[i].freq) {
+			idx_r = i;
+			idx_l = idx_r - 1;
+			goto done;
+		}
+	}
+
+done:
+	*pcinfo_l = &pcinfo[idx_l];
+	*pcinfo_r = &pcinfo[idx_r];
+
+	return;
+}
+
+/*
+ * Get the surrounding per-rate power calibration data
+ * for a given frequency and interpolate between power
+ * values to set max target power supported by hw for
+ * each rate.
+ */
+static void
+ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			struct ath5k_rate_pcal_info *rates)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rpinfo;
+	u8 idx_l, idx_r;
+	u8 mode, max, i;
+	u32 target = channel->center_freq;
+
+	idx_l = 0;
+	idx_r = 0;
+
+	if (!(channel->hw_value & CHANNEL_OFDM)) {
+		rpinfo = ee->ee_rate_tpwr_b;
+		mode = AR5K_EEPROM_MODE_11B;
+	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		rpinfo = ee->ee_rate_tpwr_g;
+		mode = AR5K_EEPROM_MODE_11G;
+	} else {
+		rpinfo = ee->ee_rate_tpwr_a;
+		mode = AR5K_EEPROM_MODE_11A;
+	}
+	max = ee->ee_rate_target_pwr_num[mode] - 1;
+
+	/* Get the surrounding calibration
+	 * piers - same as above */
+	if (target < rpinfo[0].freq) {
+		idx_l = idx_r = 0;
+		goto done;
+	}
+
+	if (target > rpinfo[max].freq) {
+		idx_l = idx_r = max;
+		goto done;
+	}
+
+	for (i = 0; i <= max; i++) {
+
+		if (rpinfo[i].freq == target) {
+			idx_l = idx_r = i;
+			goto done;
+		}
+
+		if (target < rpinfo[i].freq) {
+			idx_r = i;
+			idx_l = idx_r - 1;
+			goto done;
+		}
+	}
+
+done:
+	/* Now interpolate power value, based on the frequency */
+	rates->freq = target;
+
+	rates->target_power_6to24 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_6to24,
+					rpinfo[idx_r].target_power_6to24);
+
+	rates->target_power_36 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_36,
+					rpinfo[idx_r].target_power_36);
+
+	rates->target_power_48 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_48,
+					rpinfo[idx_r].target_power_48);
+
+	rates->target_power_54 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_54,
+					rpinfo[idx_r].target_power_54);
+}
+
+/*
+ * Get the max edge power for this channel if
+ * we have such data from EEPROM's Conformance Test
+ * Limits (CTL), and limit max power if needed.
+ *
+ * FIXME: Only works for world regulatory domains
+ */
+static void
+ath5k_get_max_ctl_power(struct ath5k_hw *ah,
+			struct net80211_channel *channel)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
+	u8 *ctl_val = ee->ee_ctl;
+	s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4;
+	s16 edge_pwr = 0;
+	u8 rep_idx;
+	u8 i, ctl_mode;
+	u8 ctl_idx = 0xFF;
+	u32 target = channel->center_freq;
+
+	/* Find out a CTL for our mode that's not mapped
+	 * on a specific reg domain.
+	 *
+	 * TODO: Map our current reg domain to one of the 3 available
+	 * reg domain ids so that we can support more CTLs. */
+	switch (channel->hw_value & CHANNEL_MODES) {
+	case CHANNEL_A:
+		ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_G:
+		ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_B:
+		ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_T:
+		ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_TG:
+		ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_XR:
+		/* Fall through */
+	default:
+		return;
+	}
+
+	for (i = 0; i < ee->ee_ctls; i++) {
+		if (ctl_val[i] == ctl_mode) {
+			ctl_idx = i;
+			break;
+		}
+	}
+
+	/* If we have a CTL dataset available grab it and find the
+	 * edge power for our frequency */
+	if (ctl_idx == 0xFF)
+		return;
+
+	/* Edge powers are sorted by frequency from lower
+	 * to higher. Each CTL corresponds to 8 edge power
+	 * measurements. */
+	rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES;
+
+	/* Don't do boundaries check because we
+	 * might have more that one bands defined
+	 * for this mode */
+
+	/* Get the edge power that's closer to our
+	 * frequency */
+	for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) {
+		rep_idx += i;
+		if (target <= rep[rep_idx].freq)
+			edge_pwr = (s16) rep[rep_idx].edge;
+	}
+
+	if (edge_pwr) {
+		ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
+	}
+}
+
+
+/*
+ * Power to PCDAC table functions
+ */
+
+/*
+ * Fill Power to PCDAC table on RF5111
+ *
+ * No further processing is needed for RF5111, the only thing we have to
+ * do is fill the values below and above calibration range since eeprom data
+ * may not cover the entire PCDAC table.
+ */
+static void
+ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
+							s16 *table_max)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	u8	*pcdac_tmp = ah->ah_txpower.tmpL[0];
+	u8	pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
+	s16	min_pwr, max_pwr;
+
+	/* Get table boundaries */
+	min_pwr = table_min[0];
+	pcdac_0 = pcdac_tmp[0];
+
+	max_pwr = table_max[0];
+	pcdac_n = pcdac_tmp[table_max[0] - table_min[0]];
+
+	/* Extrapolate below minimum using pcdac_0 */
+	pcdac_i = 0;
+	for (i = 0; i < min_pwr; i++)
+		pcdac_out[pcdac_i++] = pcdac_0;
+
+	/* Copy values from pcdac_tmp */
+	pwr_idx = min_pwr;
+	for (i = 0 ; pwr_idx <= max_pwr &&
+	pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
+		pcdac_out[pcdac_i++] = pcdac_tmp[i];
+		pwr_idx++;
+	}
+
+	/* Extrapolate above maximum */
+	while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE)
+		pcdac_out[pcdac_i++] = pcdac_n;
+
+}
+
+/*
+ * Combine available XPD Curves and fill Linear Power to PCDAC table
+ * on RF5112
+ *
+ * RFX112 can have up to 2 curves (one for low txpower range and one for
+ * higher txpower range). We need to put them both on pcdac_out and place
+ * them in the correct location. In case we only have one curve available
+ * just fit it on pcdac_out (it's supposed to cover the entire range of
+ * available pwr levels since it's always the higher power curve). Extrapolate
+ * below and above final table if needed.
+ */
+static void
+ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
+						s16 *table_max, u8 pdcurves)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	u8	*pcdac_low_pwr;
+	u8	*pcdac_high_pwr;
+	u8	*pcdac_tmp;
+	u8	pwr;
+	s16	max_pwr_idx;
+	s16	min_pwr_idx;
+	s16	mid_pwr_idx = 0;
+	/* Edge flag turs on the 7nth bit on the PCDAC
+	 * to delcare the higher power curve (force values
+	 * to be greater than 64). If we only have one curve
+	 * we don't need to set this, if we have 2 curves and
+	 * fill the table backwards this can also be used to
+	 * switch from higher power curve to lower power curve */
+	u8	edge_flag;
+	int	i;
+
+	/* When we have only one curve available
+	 * that's the higher power curve. If we have
+	 * two curves the first is the high power curve
+	 * and the next is the low power curve. */
+	if (pdcurves > 1) {
+		pcdac_low_pwr = ah->ah_txpower.tmpL[1];
+		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
+		mid_pwr_idx = table_max[1] - table_min[1] - 1;
+		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
+
+		/* If table size goes beyond 31.5dB, keep the
+		 * upper 31.5dB range when setting tx power.
+		 * Note: 126 = 31.5 dB in quarter dB steps */
+		if (table_max[0] - table_min[1] > 126)
+			min_pwr_idx = table_max[0] - 126;
+		else
+			min_pwr_idx = table_min[1];
+
+		/* Since we fill table backwards
+		 * start from high power curve */
+		pcdac_tmp = pcdac_high_pwr;
+
+		edge_flag = 0x40;
+	} else {
+		pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
+		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
+		min_pwr_idx = table_min[0];
+		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
+		pcdac_tmp = pcdac_high_pwr;
+		edge_flag = 0;
+	}
+
+	/* This is used when setting tx power*/
+	ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
+
+	/* Fill Power to PCDAC table backwards */
+	pwr = max_pwr_idx;
+	for (i = 63; i >= 0; i--) {
+		/* Entering lower power range, reset
+		 * edge flag and set pcdac_tmp to lower
+		 * power curve.*/
+		if (edge_flag == 0x40 &&
+		(2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
+			edge_flag = 0x00;
+			pcdac_tmp = pcdac_low_pwr;
+			pwr = mid_pwr_idx/2;
+		}
+
+		/* Don't go below 1, extrapolate below if we have
+		 * already swithced to the lower power curve -or
+		 * we only have one curve and edge_flag is zero
+		 * anyway */
+		if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
+			while (i >= 0) {
+				pcdac_out[i] = pcdac_out[i + 1];
+				i--;
+			}
+			break;
+		}
+
+		pcdac_out[i] = pcdac_tmp[pwr] | edge_flag;
+
+		/* Extrapolate above if pcdac is greater than
+		 * 126 -this can happen because we OR pcdac_out
+		 * value with edge_flag on high power curve */
+		if (pcdac_out[i] > 126)
+			pcdac_out[i] = 126;
+
+		/* Decrease by a 0.5dB step */
+		pwr--;
+	}
+}
+
+/* Write PCDAC values on hw */
+static void
+ath5k_setup_pcdac_table(struct ath5k_hw *ah)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	int	i;
+
+	/*
+	 * Write TX power values
+	 */
+	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+		ath5k_hw_reg_write(ah,
+			(((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
+			(((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
+			AR5K_PHY_PCDAC_TXPOWER(i));
+	}
+}
+
+
+/*
+ * Power to PDADC table functions
+ */
+
+/*
+ * Set the gain boundaries and create final Power to PDADC table
+ *
+ * We can have up to 4 pd curves, we need to do a simmilar process
+ * as we do for RF5112. This time we don't have an edge_flag but we
+ * set the gain boundaries on a separate register.
+ */
+static void
+ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
+			s16 *pwr_min, s16 *pwr_max, u8 pdcurves)
+{
+	u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS];
+	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
+	u8 *pdadc_tmp;
+	s16 pdadc_0;
+	u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size;
+	u8 pd_gain_overlap;
+
+	/* Note: Register value is initialized on initvals
+	 * there is no feedback from hw.
+	 * XXX: What about pd_gain_overlap from EEPROM ? */
+	pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) &
+		AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP;
+
+	/* Create final PDADC table */
+	for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) {
+		pdadc_tmp = ah->ah_txpower.tmpL[pdg];
+
+		if (pdg == pdcurves - 1)
+			/* 2 dB boundary stretch for last
+			 * (higher power) curve */
+			gain_boundaries[pdg] = pwr_max[pdg] + 4;
+		else
+			/* Set gain boundary in the middle
+			 * between this curve and the next one */
+			gain_boundaries[pdg] =
+				(pwr_max[pdg] + pwr_min[pdg + 1]) / 2;
+
+		/* Sanity check in case our 2 db stretch got out of
+		 * range. */
+		if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER)
+			gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER;
+
+		/* For the first curve (lower power)
+		 * start from 0 dB */
+		if (pdg == 0)
+			pdadc_0 = 0;
+		else
+			/* For the other curves use the gain overlap */
+			pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) -
+							pd_gain_overlap;
+
+		/* Force each power step to be at least 0.5 dB */
+		if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1)
+			pwr_step = pdadc_tmp[1] - pdadc_tmp[0];
+		else
+			pwr_step = 1;
+
+		/* If pdadc_0 is negative, we need to extrapolate
+		 * below this pdgain by a number of pwr_steps */
+		while ((pdadc_0 < 0) && (pdadc_i < 128)) {
+			s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step;
+			pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp;
+			pdadc_0++;
+		}
+
+		/* Set last pwr level, using gain boundaries */
+		pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg];
+		/* Limit it to be inside pwr range */
+		table_size = pwr_max[pdg] - pwr_min[pdg];
+		max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
+
+		/* Fill pdadc_out table */
+		while (pdadc_0 < max_idx)
+			pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
+
+		/* Need to extrapolate above this pdgain? */
+		if (pdadc_n <= max_idx)
+			continue;
+
+		/* Force each power step to be at least 0.5 dB */
+		if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1)
+			pwr_step = pdadc_tmp[table_size - 1] -
+						pdadc_tmp[table_size - 2];
+		else
+			pwr_step = 1;
+
+		/* Extrapolate above */
+		while ((pdadc_0 < (s16) pdadc_n) &&
+		(pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) {
+			s16 tmp = pdadc_tmp[table_size - 1] +
+					(pdadc_0 - max_idx) * pwr_step;
+			pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp;
+			pdadc_0++;
+		}
+	}
+
+	while (pdg < AR5K_EEPROM_N_PD_GAINS) {
+		gain_boundaries[pdg] = gain_boundaries[pdg - 1];
+		pdg++;
+	}
+
+	while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) {
+		pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1];
+		pdadc_i++;
+	}
+
+	/* Set gain boundaries */
+	ath5k_hw_reg_write(ah,
+		AR5K_REG_SM(pd_gain_overlap,
+			AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) |
+		AR5K_REG_SM(gain_boundaries[0],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) |
+		AR5K_REG_SM(gain_boundaries[1],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) |
+		AR5K_REG_SM(gain_boundaries[2],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) |
+		AR5K_REG_SM(gain_boundaries[3],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4),
+		AR5K_PHY_TPC_RG5);
+
+	/* Used for setting rate power table */
+	ah->ah_txpower.txp_min_idx = pwr_min[0];
+
+}
+
+/* Write PDADC values on hw */
+static void
+ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah,
+			u8 pdcurves, u8 *pdg_to_idx)
+{
+	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
+	u32 reg;
+	u8 i;
+
+	/* Select the right pdgain curves */
+
+	/* Clear current settings */
+	reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1);
+	reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 |
+		AR5K_PHY_TPC_RG1_PDGAIN_2 |
+		AR5K_PHY_TPC_RG1_PDGAIN_3 |
+		AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
+
+	/*
+	 * Use pd_gains curve from eeprom
+	 *
+	 * This overrides the default setting from initvals
+	 * in case some vendors (e.g. Zcomax) don't use the default
+	 * curves. If we don't honor their settings we 'll get a
+	 * 5dB (1 * gain overlap ?) drop.
+	 */
+	reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
+
+	switch (pdcurves) {
+	case 3:
+		reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3);
+		/* Fall through */
+	case 2:
+		reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2);
+		/* Fall through */
+	case 1:
+		reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1);
+		break;
+	}
+	ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1);
+
+	/*
+	 * Write TX power values
+	 */
+	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+		ath5k_hw_reg_write(ah,
+			((pdadc_out[4*i + 0] & 0xff) << 0) |
+			((pdadc_out[4*i + 1] & 0xff) << 8) |
+			((pdadc_out[4*i + 2] & 0xff) << 16) |
+			((pdadc_out[4*i + 3] & 0xff) << 24),
+			AR5K_PHY_PDADC_TXPOWER(i));
+	}
+}
+
+
+/*
+ * Common code for PCDAC/PDADC tables
+ */
+
+/*
+ * This is the main function that uses all of the above
+ * to set PCDAC/PDADC table on hw for the current channel.
+ * This table is used for tx power calibration on the basband,
+ * without it we get weird tx power levels and in some cases
+ * distorted spectral mask
+ */
+static int
+ath5k_setup_channel_powertable(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			u8 ee_mode, u8 type)
+{
+	struct ath5k_pdgain_info *pdg_L, *pdg_R;
+	struct ath5k_chan_pcal_info *pcinfo_L;
+	struct ath5k_chan_pcal_info *pcinfo_R;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
+	s16 table_min[AR5K_EEPROM_N_PD_GAINS];
+	s16 table_max[AR5K_EEPROM_N_PD_GAINS];
+	u8 *tmpL;
+	u8 *tmpR;
+	u32 target = channel->center_freq;
+	int pdg, i;
+
+	/* Get surounding freq piers for this channel */
+	ath5k_get_chan_pcal_surrounding_piers(ah, channel,
+						&pcinfo_L,
+						&pcinfo_R);
+
+	/* Loop over pd gain curves on
+	 * surounding freq piers by index */
+	for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) {
+
+		/* Fill curves in reverse order
+		 * from lower power (max gain)
+		 * to higher power. Use curve -> idx
+		 * backmaping we did on eeprom init */
+		u8 idx = pdg_curve_to_idx[pdg];
+
+		/* Grab the needed curves by index */
+		pdg_L = &pcinfo_L->pd_curves[idx];
+		pdg_R = &pcinfo_R->pd_curves[idx];
+
+		/* Initialize the temp tables */
+		tmpL = ah->ah_txpower.tmpL[pdg];
+		tmpR = ah->ah_txpower.tmpR[pdg];
+
+		/* Set curve's x boundaries and create
+		 * curves so that they cover the same
+		 * range (if we don't do that one table
+		 * will have values on some range and the
+		 * other one won't have any so interpolation
+		 * will fail) */
+		table_min[pdg] = min(pdg_L->pd_pwr[0],
+					pdg_R->pd_pwr[0]) / 2;
+
+		table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
+				pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2;
+
+		/* Now create the curves on surrounding channels
+		 * and interpolate if needed to get the final
+		 * curve for this gain on this channel */
+		switch (type) {
+		case AR5K_PWRTABLE_LINEAR_PCDAC:
+			/* Override min/max so that we don't loose
+			 * accuracy (don't divide by 2) */
+			table_min[pdg] = min(pdg_L->pd_pwr[0],
+						pdg_R->pd_pwr[0]);
+
+			table_max[pdg] =
+				max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
+					pdg_R->pd_pwr[pdg_R->pd_points - 1]);
+
+			/* Override minimum so that we don't get
+			 * out of bounds while extrapolating
+			 * below. Don't do this when we have 2
+			 * curves and we are on the high power curve
+			 * because table_min is ok in this case */
+			if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) {
+
+				table_min[pdg] =
+					ath5k_get_linear_pcdac_min(pdg_L->pd_step,
+								pdg_R->pd_step,
+								pdg_L->pd_pwr,
+								pdg_R->pd_pwr);
+
+				/* Don't go too low because we will
+				 * miss the upper part of the curve.
+				 * Note: 126 = 31.5dB (max power supported)
+				 * in 0.25dB units */
+				if (table_max[pdg] - table_min[pdg] > 126)
+					table_min[pdg] = table_max[pdg] - 126;
+			}
+
+			/* Fall through */
+		case AR5K_PWRTABLE_PWR_TO_PCDAC:
+		case AR5K_PWRTABLE_PWR_TO_PDADC:
+
+			ath5k_create_power_curve(table_min[pdg],
+						table_max[pdg],
+						pdg_L->pd_pwr,
+						pdg_L->pd_step,
+						pdg_L->pd_points, tmpL, type);
+
+			/* We are in a calibration
+			 * pier, no need to interpolate
+			 * between freq piers */
+			if (pcinfo_L == pcinfo_R)
+				continue;
+
+			ath5k_create_power_curve(table_min[pdg],
+						table_max[pdg],
+						pdg_R->pd_pwr,
+						pdg_R->pd_step,
+						pdg_R->pd_points, tmpR, type);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Interpolate between curves
+		 * of surounding freq piers to
+		 * get the final curve for this
+		 * pd gain. Re-use tmpL for interpolation
+		 * output */
+		for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) &&
+		(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
+			tmpL[i] = (u8) ath5k_get_interpolated_value(target,
+							(s16) pcinfo_L->freq,
+							(s16) pcinfo_R->freq,
+							(s16) tmpL[i],
+							(s16) tmpR[i]);
+		}
+	}
+
+	/* Now we have a set of curves for this
+	 * channel on tmpL (x range is table_max - table_min
+	 * and y values are tmpL[pdg][]) sorted in the same
+	 * order as EEPROM (because we've used the backmaping).
+	 * So for RF5112 it's from higher power to lower power
+	 * and for RF2413 it's from lower power to higher power.
+	 * For RF5111 we only have one curve. */
+
+	/* Fill min and max power levels for this
+	 * channel by interpolating the values on
+	 * surounding channels to complete the dataset */
+	ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target,
+					(s16) pcinfo_L->freq,
+					(s16) pcinfo_R->freq,
+					pcinfo_L->min_pwr, pcinfo_R->min_pwr);
+
+	ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target,
+					(s16) pcinfo_L->freq,
+					(s16) pcinfo_R->freq,
+					pcinfo_L->max_pwr, pcinfo_R->max_pwr);
+
+	/* We are ready to go, fill PCDAC/PDADC
+	 * table and write settings on hardware */
+	switch (type) {
+	case AR5K_PWRTABLE_LINEAR_PCDAC:
+		/* For RF5112 we can have one or two curves
+		 * and each curve covers a certain power lvl
+		 * range so we need to do some more processing */
+		ath5k_combine_linear_pcdac_curves(ah, table_min, table_max,
+						ee->ee_pd_gains[ee_mode]);
+
+		/* Set txp.offset so that we can
+		 * match max power value with max
+		 * table index */
+		ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
+
+		/* Write settings on hw */
+		ath5k_setup_pcdac_table(ah);
+		break;
+	case AR5K_PWRTABLE_PWR_TO_PCDAC:
+		/* We are done for RF5111 since it has only
+		 * one curve, just fit the curve on the table */
+		ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max);
+
+		/* No rate powertable adjustment for RF5111 */
+		ah->ah_txpower.txp_min_idx = 0;
+		ah->ah_txpower.txp_offset = 0;
+
+		/* Write settings on hw */
+		ath5k_setup_pcdac_table(ah);
+		break;
+	case AR5K_PWRTABLE_PWR_TO_PDADC:
+		/* Set PDADC boundaries and fill
+		 * final PDADC table */
+		ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
+						ee->ee_pd_gains[ee_mode]);
+
+		/* Write settings on hw */
+		ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
+
+		/* Set txp.offset, note that table_min
+		 * can be negative */
+		ah->ah_txpower.txp_offset = table_min[0];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Per-rate tx power setting
+ *
+ * This is the code that sets the desired tx power (below
+ * maximum) on hw for each rate (we also have TPC that sets
+ * power per packet). We do that by providing an index on the
+ * PCDAC/PDADC table we set up.
+ */
+
+/*
+ * Set rate power table
+ *
+ * For now we only limit txpower based on maximum tx power
+ * supported by hw (what's inside rate_info). We need to limit
+ * this even more, based on regulatory domain etc.
+ *
+ * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps)
+ * and is indexed as follows:
+ * rates[0] - rates[7] -> OFDM rates
+ * rates[8] - rates[14] -> CCK rates
+ * rates[15] -> XR rates (they all have the same power)
+ */
+static void
+ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
+			struct ath5k_rate_pcal_info *rate_info,
+			u8 ee_mode)
+{
+	unsigned int i;
+	u16 *rates;
+
+	/* max_pwr is power level we got from driver/user in 0.5dB
+	 * units, switch to 0.25dB units so we can compare */
+	max_pwr *= 2;
+	max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2;
+
+	/* apply rate limits */
+	rates = ah->ah_txpower.txp_rates_power_table;
+
+	/* OFDM rates 6 to 24Mb/s */
+	for (i = 0; i < 5; i++)
+		rates[i] = min(max_pwr, rate_info->target_power_6to24);
+
+	/* Rest OFDM rates */
+	rates[5] = min(rates[0], rate_info->target_power_36);
+	rates[6] = min(rates[0], rate_info->target_power_48);
+	rates[7] = min(rates[0], rate_info->target_power_54);
+
+	/* CCK rates */
+	/* 1L */
+	rates[8] = min(rates[0], rate_info->target_power_6to24);
+	/* 2L */
+	rates[9] = min(rates[0], rate_info->target_power_36);
+	/* 2S */
+	rates[10] = min(rates[0], rate_info->target_power_36);
+	/* 5L */
+	rates[11] = min(rates[0], rate_info->target_power_48);
+	/* 5S */
+	rates[12] = min(rates[0], rate_info->target_power_48);
+	/* 11L */
+	rates[13] = min(rates[0], rate_info->target_power_54);
+	/* 11S */
+	rates[14] = min(rates[0], rate_info->target_power_54);
+
+	/* XR rates */
+	rates[15] = min(rates[0], rate_info->target_power_6to24);
+
+	/* CCK rates have different peak to average ratio
+	 * so we have to tweak their power so that gainf
+	 * correction works ok. For this we use OFDM to
+	 * CCK delta from eeprom */
+	if ((ee_mode == AR5K_EEPROM_MODE_11G) &&
+	(ah->ah_phy_revision < AR5K_SREV_PHY_5212A))
+		for (i = 8; i <= 15; i++)
+			rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
+
+	ah->ah_txpower.txp_min_pwr = rates[7];
+	ah->ah_txpower.txp_max_pwr = rates[0];
+	ah->ah_txpower.txp_ofdm = rates[7];
+}
+
+
+/*
+ * Set transmition power
+ */
+int
+ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel,
+		u8 ee_mode, u8 txpower)
+{
+	struct ath5k_rate_pcal_info rate_info;
+	u8 type;
+	int ret;
+
+	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
+		DBG("ath5k: invalid tx power %d\n", txpower);
+		return -EINVAL;
+	}
+	if (txpower == 0)
+		txpower = AR5K_TUNE_DEFAULT_TXPOWER;
+
+	/* Reset TX power values */
+	memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+	ah->ah_txpower.txp_min_pwr = 0;
+	ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
+
+	/* Initialize TX power table */
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		type = AR5K_PWRTABLE_PWR_TO_PCDAC;
+		break;
+	case AR5K_RF5112:
+		type = AR5K_PWRTABLE_LINEAR_PCDAC;
+		break;
+	case AR5K_RF2413:
+	case AR5K_RF5413:
+	case AR5K_RF2316:
+	case AR5K_RF2317:
+	case AR5K_RF2425:
+		type = AR5K_PWRTABLE_PWR_TO_PDADC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME: Only on channel/mode change */
+	ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
+	if (ret)
+		return ret;
+
+	/* Limit max power if we have a CTL available */
+	ath5k_get_max_ctl_power(ah, channel);
+
+	/* FIXME: Tx power limit for this regdomain
+	 * XXX: Mac80211/CRDA will do that anyway ? */
+
+	/* FIXME: Antenna reduction stuff */
+
+	/* FIXME: Limit power on turbo modes */
+
+	/* FIXME: TPC scale reduction */
+
+	/* Get surounding channels for per-rate power table
+	 * calibration */
+	ath5k_get_rate_pcal_data(ah, channel, &rate_info);
+
+	/* Setup rate power table */
+	ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode);
+
+	/* Write rate power table on hw */
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
+		AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
+		AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
+		AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
+		AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
+		AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
+		AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
+		AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
+		AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
+
+	/* FIXME: TPC support */
+	if (ah->ah_txpower.txp_tpc) {
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) |
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) |
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
+			AR5K_TPC);
+	} else {
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+	}
+
+	return 0;
+}
+
+int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower)
+{
+	struct net80211_channel *channel = ah->ah_current_channel;
+
+	DBG2("ath5k: changing txpower to %d\n", txpower);
+
+	return ath5k_hw_txpower(ah, channel, mode, txpower);
+}
+
+#undef _ATH5K_PHY
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c
new file mode 100644
index 0000000..e38dba9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/********************************************\
+Queue Control Unit, DFS Control Unit Functions
+\********************************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Set properties for a transmit queue
+ */
+int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah,
+				const struct ath5k_txq_info *queue_info)
+{
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	memcpy(&ah->ah_txq, queue_info, sizeof(struct ath5k_txq_info));
+
+	/*XXX: Is this supported on 5210 ?*/
+	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
+			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
+			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
+			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
+		ah->ah_txq.tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+
+	return 0;
+}
+
+/*
+ * Initialize a transmit queue
+ */
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+		struct ath5k_txq_info *queue_info)
+{
+	int ret;
+
+	/*
+	 * Setup internal queue structure
+	 */
+	memset(&ah->ah_txq, 0, sizeof(struct ath5k_txq_info));
+	ah->ah_txq.tqi_type = queue_type;
+
+	if (queue_info != NULL) {
+		queue_info->tqi_type = queue_type;
+		ret = ath5k_hw_set_tx_queueprops(ah, queue_info);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * We use ah_txq_status to hold a temp value for
+	 * the Secondary interrupt mask registers on 5211+
+	 * check out ath5k_hw_reset_tx_queue
+	 */
+	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, 0);
+
+	return 0;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah)
+{
+	/* This queue will be skipped in further operations */
+	ah->ah_txq.tqi_type = AR5K_TX_QUEUE_INACTIVE;
+	/*For SIMR setup*/
+	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, 0);
+}
+
+/*
+ * Set DFS properties for a transmit queue on DCU
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah)
+{
+	u32 cw_min, cw_max, retry_lg, retry_sh;
+	struct ath5k_txq_info *tq = &ah->ah_txq;
+	const int queue = 0;
+
+	tq = &ah->ah_txq;
+
+	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return 0;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Only handle data queues, others will be ignored */
+		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
+			return 0;
+
+		/* Set Slot time */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
+			AR5K_SLOT_TIME);
+		/* Set ACK_CTS timeout */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
+			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
+		/* Set Transmit Latency */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+
+		/* Set IFS0 */
+		if (ah->ah_turbo) {
+			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME_TURBO) <<
+				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
+				AR5K_IFS0);
+		} else {
+			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+				AR5K_INIT_SIFS, AR5K_IFS0);
+		}
+
+		/* Set IFS1 */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
+			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
+		/* Set AR5K_PHY_SETTLING */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x38 :
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x1C,
+			AR5K_PHY_SETTLING);
+		/* Set Frame Control Register */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+			AR5K_PHY_TURBO_SHORT | 0x2020) :
+			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
+			AR5K_PHY_FRAME_CTL_5210);
+	}
+
+	/*
+	 * Calculate cwmin/max by channel mode
+	 */
+	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	/*XR is only supported on 5212*/
+	if (IS_CHAN_XR(ah->ah_current_channel) &&
+			ah->ah_version == AR5K_AR5212) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
+		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
+	/*B mode is not supported on 5210*/
+	} else if (IS_CHAN_B(ah->ah_current_channel) &&
+			ah->ah_version != AR5K_AR5210) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
+		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
+	}
+
+	cw_min = 1;
+	while (cw_min < ah->ah_cw_min)
+		cw_min = (cw_min << 1) | 1;
+
+	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
+		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
+	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
+		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
+
+	/*
+	 * Calculate and set retry limits
+	 */
+	if (ah->ah_software_retry) {
+		/* XXX Need to test this */
+		retry_lg = ah->ah_limit_tx_retries;
+		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
+	} else {
+		retry_lg = AR5K_INIT_LG_RETRY;
+		retry_sh = AR5K_INIT_SH_RETRY;
+	}
+
+	/*No QCU/DCU [5210]*/
+	if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_reg_write(ah,
+			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
+			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
+			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
+			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
+			AR5K_NODCU_RETRY_LMT);
+	} else {
+		/*QCU/DCU [5211+]*/
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
+			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
+			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
+			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
+			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+
+	/*===Rest is also for QCU/DCU only [5211+]===*/
+
+		/*
+		 * Set initial content window (cw_min/cw_max)
+		 * and arbitrated interframe space (aifs)...
+		 */
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
+				AR5K_DCU_LCL_IFS_AIFS),
+			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+		/*
+		 * Set misc registers
+		 */
+		/* Enable DCU early termination for this queue */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_DCU_EARLY);
+
+		/* Enable DCU to wait for next fragment from QCU */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+					AR5K_DCU_MISC_FRAG_WAIT);
+
+		/* On Maui and Spirit use the global seqnum on DCU */
+		if (ah->ah_mac_version < AR5K_SREV_AR5211)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+						AR5K_DCU_MISC_SEQNUM_CTL);
+
+		if (tq->tqi_cbr_period) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+				AR5K_QCU_CBRCFG_INTVAL) |
+				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+				AR5K_QCU_CBRCFG_ORN_THRES),
+				AR5K_QUEUE_CBRCFG(queue));
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_CBR);
+			if (tq->tqi_cbr_overflow_limit)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_CBR_THRES_ENABLE);
+		}
+
+		if (tq->tqi_ready_time &&
+		(tq->tqi_type != AR5K_TX_QUEUE_CAB))
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+				AR5K_QCU_RDYTIMECFG_INTVAL) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+
+		if (tq->tqi_burst_time) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+				AR5K_DCU_CHAN_TIME_DUR) |
+				AR5K_DCU_CHAN_TIME_ENABLE,
+				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+			if (tq->tqi_flags
+			& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_RDY_VEOL_POLICY);
+		}
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		/* TODO: Handle frame compression */
+
+		/*
+		 * Enable interrupts for this tx queue
+		 * in the secondary interrupt mask registers
+		 */
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
+
+		/* Update secondary interrupt mask registers */
+
+		/* Filter out inactive queues */
+		ah->ah_txq_imr_txok &= ah->ah_txq_status;
+		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
+		ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+			AR5K_SIMR0_QCU_TXOK) |
+			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+			AR5K_SIMR1_QCU_TXERR) |
+			AR5K_REG_SM(ah->ah_txq_imr_txeol,
+			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
+		/* Update simr2 but don't overwrite rest simr2 settings */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
+			AR5K_REG_SM(ah->ah_txq_imr_txurn,
+			AR5K_SIMR2_QCU_TXURN));
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
+			AR5K_SIMR3_QCBRORN) |
+			AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
+			AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
+			AR5K_SIMR4_QTRIG), AR5K_SIMR4);
+		/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
+			AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
+		/* No queue has TXNOFRM enabled, disable the interrupt
+		 * by setting AR5K_TXNOFRM to zero */
+		if (ah->ah_txq_imr_nofrm == 0)
+			ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
+
+		/* Set QCU mask for this DCU to save power */
+		AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
+	}
+
+	return 0;
+}
+
+/*
+ * Set slot time on DCU
+ */
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+{
+	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+		return -EINVAL;
+
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
+				ah->ah_turbo), AR5K_SLOT_TIME);
+	else
+		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c
new file mode 100644
index 0000000..2f36a4e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof at winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski at gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby at gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#define _ATH5K_RESET
+
+/*****************************\
+  Reset functions and helpers
+\*****************************/
+
+#include <ipxe/pci.h> 		/* To determine if a card is pci-e */
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/* Find last set bit; fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32 */
+static int fls(int x)
+{
+        int r = 32;
+
+        if (!x)
+                return 0;
+        if (!(x & 0xffff0000u)) {
+                x <<= 16;
+                r -= 16;
+        }
+        if (!(x & 0xff000000u)) {
+                x <<= 8;
+                r -= 8;
+        }
+        if (!(x & 0xf0000000u)) {
+                x <<= 4;
+                r -= 4;
+        }
+        if (!(x & 0xc0000000u)) {
+                x <<= 2;
+                r -= 2;
+        }
+        if (!(x & 0x80000000u)) {
+                x <<= 1;
+                r -= 1;
+        }
+        return r;
+}
+
+
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
+ *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
+ */
+static int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+	struct net80211_channel *channel)
+{
+	/* Get exponent and mantissa and set it */
+	u32 coef_scaled, coef_exp, coef_man,
+		ds_coef_exp, ds_coef_man, clock;
+
+	if (!(ah->ah_version == AR5K_AR5212) ||
+	    !(channel->hw_value & CHANNEL_OFDM)) {
+		DBG("ath5k: attempt to set OFDM timings on non-OFDM channel\n");
+		return -EFAULT;
+	}
+
+	/* Get coefficient
+	 * ALGO: coef = (5 * clock * carrier_freq) / 2)
+	 * we scale coef by shifting clock value by 24 for
+	 * better precision since we use integers */
+	/* TODO: Half/quarter rate */
+	clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
+
+	coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
+
+	/* Get exponent
+	 * ALGO: coef_exp = 14 - highest set bit position */
+	coef_exp = fls(coef_scaled) - 1;
+
+	/* Doesn't make sense if it's zero*/
+	if (!coef_scaled || !coef_exp)
+		return -EINVAL;
+
+	/* Note: we've shifted coef_scaled by 24 */
+	coef_exp = 14 - (coef_exp - 24);
+
+
+	/* Get mantissa (significant digits)
+	 * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
+	coef_man = coef_scaled +
+		(1 << (24 - coef_exp - 1));
+
+	/* Calculate delta slope coefficient exponent
+	 * and mantissa (remove scaling) and set them on hw */
+	ds_coef_man = coef_man >> (24 - coef_exp);
+	ds_coef_exp = coef_exp - 16;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+	return 0;
+}
+
+
+/*
+ * index into rates for control rates, we can set it up like this because
+ * this is only used for AR5212 and we know it supports G mode
+ */
+static const unsigned int control_rates[] =
+	{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
+
+/**
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
+ *
+ * @ah: the &struct ath5k_hw
+ * @mode: one of enum ath5k_driver_mode
+ *
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preample
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
+ * quarter rate mode, we need to use another set of bitrates (that's why we
+ * need the mode parameter) but we don't handle these proprietary modes yet.
+ */
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+       unsigned int mode __unused)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+	u16 rate;
+	int i;
+
+	/* Write rate duration table */
+	for (i = 0; i < sc->hwinfo->nr_rates[NET80211_BAND_2GHZ]; i++) {
+		u32 reg;
+		u16 tx_time;
+
+		rate = sc->hwinfo->rates[NET80211_BAND_2GHZ][i];
+
+		/* Set ACK timeout */
+		reg = AR5K_RATE_DUR(ath5k_bitrate_to_hw_rix(rate));
+
+		/* An ACK frame consists of 10 bytes. If you add the FCS,
+		 * it's 14 bytes. Note we use the control rate and not the
+		 * actual rate for this rate. See mac80211 tx.c
+		 * ieee80211_duration() for a brief description of
+		 * what rate we should choose to TX ACKs. */
+		tx_time = net80211_duration(sc->dev, 14, rate);
+
+		ath5k_hw_reg_write(ah, tx_time, reg);
+
+		if (rate != 20 && rate != 55 && rate != 110)
+			continue;
+
+		/*
+		 * We're not distinguishing short preamble here,
+		 * This is true, all we'll get is a longer value here
+		 * which is not necessarilly bad.
+		 */
+		ath5k_hw_reg_write(ah, tx_time,
+			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+	}
+}
+
+/*
+ * Reset chipset
+ */
+static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+{
+	int ret;
+	u32 mask = val ? val : ~0U;
+
+	/* Read-and-clear RX Descriptor Pointer*/
+	ath5k_hw_reg_read(ah, AR5K_RXDP);
+
+	/*
+	 * Reset the device and wait until success
+	 */
+	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
+
+	/* Wait at least 128 PCI clocks */
+	udelay(15);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+	} else {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+	}
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, 0);
+
+	/*
+	 * Reset configuration register (for hw byte-swap). Note that this
+	 * is only set for big endian. We do the necessary magic in
+	 * AR5K_INIT_CFG.
+	 */
+	if ((val & AR5K_RESET_CTL_PCU) == 0)
+		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+	return ret;
+}
+
+/*
+ * Sleep control
+ */
+int ath5k_hw_wake(struct ath5k_hw *ah)
+{
+	unsigned int i;
+	u32 staid, data;
+
+	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
+	staid &= ~AR5K_STA_ID1_PWR_SV;
+
+	/* Preserve sleep duration */
+	data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+	if (data & 0xffc00000)
+		data = 0;
+	else
+		data = data & 0xfffcffff;
+
+	ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+	udelay(15);
+
+	for (i = 50; i > 0; i--) {
+		/* Check if the chip did wake up */
+		if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+		     AR5K_PCICFG_SPWR_DN) == 0)
+			break;
+
+		/* Wait a bit and retry */
+		udelay(200);
+		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+	}
+
+	/* Fail if the chip didn't wake up */
+	if (i <= 0)
+		return -EIO;
+
+	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/*
+ * Bring up MAC + PHY Chips and program PLL
+ * TODO: Half/Quarter rate support
+ */
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial __unused)
+{
+	struct pci_device *pdev = ah->ah_sc->pdev;
+	u32 turbo, mode, clock, bus_flags;
+	int ret;
+
+	turbo = 0;
+	mode = 0;
+	clock = 0;
+
+	/* Wakeup the device */
+	ret = ath5k_hw_wake(ah);
+	if (ret) {
+		DBG("ath5k: failed to wake up the MAC chip\n");
+		return ret;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Get channel mode flags
+		 */
+
+		if (ah->ah_radio >= AR5K_RF5112) {
+			mode = AR5K_PHY_MODE_RAD_RF5112;
+			clock = AR5K_PHY_PLL_RF5112;
+		} else {
+			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
+			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
+		}
+
+		if (flags & CHANNEL_2GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+			clock |= AR5K_PHY_PLL_44MHZ;
+
+			if (flags & CHANNEL_CCK) {
+				mode |= AR5K_PHY_MODE_MOD_CCK;
+			} else if (flags & CHANNEL_OFDM) {
+				/* XXX Dynamic OFDM/CCK is not supported by the
+				 * AR5211 so we set MOD_OFDM for plain g (no
+				 * CCK headers) operation. We need to test
+				 * this, 5211 might support ofdm-only g after
+				 * all, there are also initial register values
+				 * in the code for g mode (see initvals.c). */
+				if (ah->ah_version == AR5K_AR5211)
+					mode |= AR5K_PHY_MODE_MOD_OFDM;
+				else
+					mode |= AR5K_PHY_MODE_MOD_DYN;
+			} else {
+				DBG("ath5k: invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else if (flags & CHANNEL_5GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+
+			if (ah->ah_radio == AR5K_RF5413)
+				clock = AR5K_PHY_PLL_40MHZ_5413;
+			else
+				clock |= AR5K_PHY_PLL_40MHZ;
+
+			if (flags & CHANNEL_OFDM)
+				mode |= AR5K_PHY_MODE_MOD_OFDM;
+			else {
+				DBG("ath5k: invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else {
+			DBG("ath5k: invalid radio frequency mode\n");
+			return -EINVAL;
+		}
+
+		if (flags & CHANNEL_TURBO)
+			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+	} else { /* Reset the device */
+
+		/* ...enable Atheros turbo mode if requested */
+		if (flags & CHANNEL_TURBO)
+			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
+					AR5K_PHY_TURBO);
+	}
+
+	/* reseting PCI on PCI-E cards results card to hang
+	 * and always return 0xffff... so we ingore that flag
+	 * for PCI-E cards */
+	if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
+		bus_flags = 0;
+	else
+		bus_flags = AR5K_RESET_CTL_PCI;
+
+	/* Reset chipset */
+	if (ah->ah_version == AR5K_AR5210) {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+		mdelay(2);
+	} else {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_BASEBAND | bus_flags);
+	}
+	if (ret) {
+		DBG("ath5k: failed to reset the MAC chip\n");
+		return -EIO;
+	}
+
+	/* ...wakeup again!*/
+	ret = ath5k_hw_wake(ah);
+	if (ret) {
+		DBG("ath5k: failed to resume the MAC chip\n");
+		return ret;
+	}
+
+	/* ...final warm reset */
+	if (ath5k_hw_nic_reset(ah, 0)) {
+		DBG("ath5k: failed to warm reset the MAC chip\n");
+		return -EIO;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+
+		/* ...update PLL if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
+			ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+			udelay(300);
+		}
+
+		/* ...set the PHY operating mode */
+		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
+		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
+	}
+
+	return 0;
+}
+
+static int ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+				struct net80211_channel *channel)
+{
+	u8 refclk_freq;
+
+	if ((ah->ah_radio == AR5K_RF5112) ||
+	(ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+		refclk_freq = 40;
+	else
+		refclk_freq = 32;
+
+	if ((channel->center_freq % refclk_freq != 0) &&
+	((channel->center_freq % refclk_freq < 10) ||
+	(channel->center_freq % refclk_freq > 22)))
+		return 1;
+	else
+		return 0;
+}
+
+/* TODO: Half/Quarter rate */
+static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
+				struct net80211_channel *channel)
+{
+	if (ah->ah_version == AR5K_AR5212 &&
+	    ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+
+		/* Setup ADC control */
+		ath5k_hw_reg_write(ah,
+				(AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
+				AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
+				AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
+				AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
+				AR5K_PHY_ADC_CTL);
+
+
+
+		/* Disable barker RSSI threshold */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+				AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+			AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
+
+		/* Set the mute mask */
+		ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
+	}
+
+	/* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
+
+	/* Enable DCU double buffering */
+	if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_DCU_DBL_BUF_DIS);
+
+	/* Set DAC/ADC delays */
+	if (ah->ah_version == AR5K_AR5212) {
+		u32 scal;
+		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+			scal = AR5K_PHY_SCAL_32MHZ_2417;
+		else if (ath5k_eeprom_is_hb63(ah))
+			scal = AR5K_PHY_SCAL_32MHZ_HB63;
+		else
+			scal = AR5K_PHY_SCAL_32MHZ;
+		ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+	}
+
+	/* Set fast ADC */
+	if ((ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+		u32 fast_adc = 1;
+
+		if (channel->center_freq == 2462 ||
+		channel->center_freq == 2467)
+			fast_adc = 0;
+
+		/* Only update if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
+				ath5k_hw_reg_write(ah, fast_adc,
+						AR5K_PHY_FAST_ADC);
+	}
+
+	/* Fix for first revision of the RF5112 RF chipset */
+	if (ah->ah_radio == AR5K_RF5112 &&
+			ah->ah_radio_5ghz_revision <
+			AR5K_SREV_RAD_5112A) {
+		u32 data;
+		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+				AR5K_PHY_CCKTXCTL);
+		if (channel->hw_value & CHANNEL_5GHZ)
+			data = 0xffb81020;
+		else
+			data = 0xffb80d20;
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+	}
+
+	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+		u32 usec_reg;
+		/* 5311 has different tx/rx latency masks
+		 * from 5211, since we deal 5311 the same
+		 * as 5211 when setting initvals, shift
+		 * values here to their proper locations */
+		usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+		ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
+				AR5K_USEC_32 |
+				AR5K_USEC_TX_LATENCY_5211 |
+				AR5K_REG_SM(29,
+				AR5K_USEC_RX_LATENCY_5210)),
+				AR5K_USEC_5211);
+		/* Clear QCU/DCU clock gating register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
+		/* Set DAC/ADC delays */
+		ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+		/* Enable PCU FIFO corruption ECO */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_ECO_ENABLE);
+	}
+}
+
+static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
+		struct net80211_channel *channel, u8 *ant, u8 ee_mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	s16 cck_ofdm_pwr_delta;
+
+	/* Adjust power delta for channel 14 */
+	if (channel->center_freq == 2484)
+		cck_ofdm_pwr_delta =
+			((ee->ee_cck_ofdm_power_delta -
+			ee->ee_scaled_cck_delta) * 2) / 10;
+	else
+		cck_ofdm_pwr_delta =
+			(ee->ee_cck_ofdm_power_delta * 2) / 10;
+
+	/* Set CCK to OFDM power delta on tx power
+	 * adjustment register */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+		if (channel->hw_value == CHANNEL_G)
+			ath5k_hw_reg_write(ah,
+			AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
+			AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
+				AR5K_PHY_TX_PWR_ADJ);
+		else
+			ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
+	} else {
+		/* For older revs we scale power on sw during tx power
+		 * setup */
+		ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta;
+		ah->ah_txpower.txp_cck_ofdm_gainf_delta =
+						ee->ee_cck_ofdm_gain_delta;
+	}
+
+	/* Set antenna idle switch table */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+			(ah->ah_antenna[ee_mode][0] |
+			AR5K_PHY_ANT_CTL_TXRX_EN));
+
+	/* Set antenna switch table */
+	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+		AR5K_PHY_ANT_SWITCH_TABLE_0);
+	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+		AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+	/* Noise floor threshold */
+	ath5k_hw_reg_write(ah,
+		AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+		AR5K_PHY_NFTHRES);
+
+	if ((channel->hw_value & CHANNEL_TURBO) &&
+	(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
+		/* Switch settling time (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling_turbo[ee_mode]);
+
+		/* Tx/Rx attenuation (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx_turbo[ee_mode]);
+
+		/* ADC/PGA desired size (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size_turbo[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size_turbo[ee_mode]);
+
+		/* Tx/Rx margin (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx_turbo[ee_mode]);
+
+	} else {
+		/* Switch settling time */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling[ee_mode]);
+
+		/* Tx/Rx attenuation */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx[ee_mode]);
+
+		/* ADC/PGA desired size */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size[ee_mode]);
+
+		/* Tx/Rx margin */
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx[ee_mode]);
+	}
+
+	/* XPA delays */
+	ath5k_hw_reg_write(ah,
+		(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+		(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+		(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+		(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
+
+	/* XLNA delay */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
+			AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
+			ee->ee_tx_end2xlna_enable[ee_mode]);
+
+	/* Thresh64 (ANI) */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
+			AR5K_PHY_NF_THRESH62,
+			ee->ee_thr_62[ee_mode]);
+
+
+	/* False detect backoff for channels
+	 * that have spur noise. Write the new
+	 * cyclic power RSSI threshold. */
+	if (ath5k_hw_chan_has_spur_noise(ah, channel))
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1 +
+				ee->ee_false_detect[ee_mode]);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1);
+
+	/* I/Q correction
+	 * TODO: Per channel i/q infos ? */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+		AR5K_PHY_IQ_CORR_ENABLE |
+		(ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+		ee->ee_q_cal[ee_mode]);
+
+	/* Heavy clipping -disable for now */
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
+
+	return;
+}
+
+/*
+ * Main reset function
+ */
+int ath5k_hw_reset(struct ath5k_hw *ah,
+	struct net80211_channel *channel, int change_channel)
+{
+	u32 s_seq[10], s_ant, s_led[3], staid1_flags;
+	u32 phy_tst1;
+	u8 mode, freq, ee_mode, ant[2];
+	int i, ret;
+
+	s_ant = 0;
+	ee_mode = 0;
+	staid1_flags = 0;
+	freq = 0;
+	mode = 0;
+
+	/*
+	 * Save some registers before a reset
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+
+		switch (channel->hw_value & CHANNEL_MODES) {
+		case CHANNEL_A:
+			mode = AR5K_MODE_11A;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		case CHANNEL_G:
+			mode = AR5K_MODE_11G;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_B:
+			mode = AR5K_MODE_11B;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11B;
+			break;
+		case CHANNEL_T:
+			mode = AR5K_MODE_11A_TURBO;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		case CHANNEL_TG:
+			if (ah->ah_version == AR5K_AR5211) {
+				DBG("ath5k: TurboG not available on 5211\n");
+				return -EINVAL;
+			}
+			mode = AR5K_MODE_11G_TURBO;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_XR:
+			if (ah->ah_version == AR5K_AR5211) {
+				DBG("ath5k: XR mode not available on 5211\n");
+				return -EINVAL;
+			}
+			mode = AR5K_MODE_XR;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			DBG("ath5k: invalid channel (%d MHz)\n",
+			    channel->center_freq);
+			return -EINVAL;
+		}
+
+		if (change_channel) {
+			/*
+			 * Save frame sequence count
+			 * For revs. after Oahu, only save
+			 * seq num for DCU 0 (Global seq num)
+			 */
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+
+				for (i = 0; i < 10; i++)
+					s_seq[i] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(i));
+
+			} else {
+				s_seq[0] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+		}
+
+		/* Save default antenna */
+		s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+		if (ah->ah_version == AR5K_AR5212) {
+			/* Since we are going to write rf buffer
+			 * check if we have any pending gain_F
+			 * optimization settings */
+			if (change_channel && ah->ah_rf_banks != NULL)
+				ath5k_hw_gainf_calibrate(ah);
+		}
+	}
+
+	/*GPIOs*/
+	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+					AR5K_PCICFG_LEDSTATE;
+	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	/* AR5K_STA_ID1 flags, only preserve antenna
+	 * settings and ack/cts rate mode */
+	staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
+			(AR5K_STA_ID1_DEFAULT_ANTENNA |
+			AR5K_STA_ID1_DESC_ANTENNA |
+			AR5K_STA_ID1_RTS_DEF_ANTENNA |
+			AR5K_STA_ID1_ACKCTS_6MB |
+			AR5K_STA_ID1_BASE_RATE_11B |
+			AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+	/* Wakeup the device */
+	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, 0);
+	if (ret)
+		return ret;
+
+	/* PHY access enable */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+	else
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
+							AR5K_PHY(0));
+
+	/* Write initial settings */
+	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * 5211/5212 Specific
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+
+		/*
+		 * Write initial RF gain settings
+		 * This should work for both 5111/5112
+		 */
+		ret = ath5k_hw_rfgain_init(ah, freq);
+		if (ret)
+			return ret;
+
+		mdelay(1);
+
+		/*
+		 * Tweak initval settings for revised
+		 * chipsets and add some more config
+		 * bits
+		 */
+		ath5k_hw_tweak_initval_settings(ah, channel);
+
+		/*
+		 * Set TX power (FIXME)
+		 */
+		ret = ath5k_hw_txpower(ah, channel, ee_mode,
+					AR5K_TUNE_DEFAULT_TXPOWER);
+		if (ret)
+			return ret;
+
+		/* Write rate duration table only on AR5212 */
+		if (ah->ah_version == AR5K_AR5212)
+			ath5k_hw_write_rate_duration(ah, mode);
+
+		/*
+		 * Write RF buffer
+		 */
+		ret = ath5k_hw_rfregs_init(ah, channel, mode);
+		if (ret)
+			return ret;
+
+
+		/* Write OFDM timings on 5212*/
+		if (ah->ah_version == AR5K_AR5212 &&
+			channel->hw_value & CHANNEL_OFDM) {
+			ret = ath5k_hw_write_ofdm_timings(ah, channel);
+			if (ret)
+				return ret;
+		}
+
+		/*Enable/disable 802.11b mode on 5111
+		(enable 2111 frequency converter + CCK)*/
+		if (ah->ah_radio == AR5K_RF5111) {
+			if (mode == AR5K_MODE_11B)
+				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+			else
+				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+		}
+
+		/*
+		 * In case a fixed antenna was set as default
+		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
+		 * registers.
+		 */
+		if (s_ant != 0) {
+			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+			else	/* 2 - Aux */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+		} else {
+			ant[0] = AR5K_ANT_FIXED_A;
+			ant[1] = AR5K_ANT_FIXED_B;
+		}
+
+		/* Commit values from EEPROM */
+		ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
+
+	} else {
+		/*
+		 * For 5210 we do all initialization using
+		 * initvals, so we don't have to modify
+		 * any settings (5210 also only supports
+		 * a/aturbo modes)
+		 */
+		mdelay(1);
+		/* Disable phy and wait */
+		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+		mdelay(1);
+	}
+
+	/*
+	 * Restore saved values
+	 */
+
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+
+		if (change_channel) {
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+				for (i = 0; i < 10; i++)
+					ath5k_hw_reg_write(ah, s_seq[i],
+						AR5K_QUEUE_DCU_SEQNUM(i));
+			} else {
+				ath5k_hw_reg_write(ah, s_seq[0],
+					AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+		}
+
+		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
+	}
+
+	/* Ledstate */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+
+	/* Gpio settings */
+	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
+	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
+
+	/* Restore sta_id flags and preserve our mac address*/
+	ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
+						AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
+						AR5K_STA_ID1);
+
+
+	/*
+	 * Configure PCU
+	 */
+
+	/* Restore bssid and bssid mask */
+	/* XXX: add ah->aid once mac80211 gives this to us */
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+
+	/* Set PCU config */
+	ath5k_hw_set_opmode(ah);
+
+	/* Clear any pending interrupts
+	 * PISR/SISR Not available on 5210 */
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+
+	/* Set RSSI/BRSSI thresholds
+	 *
+	 * Note: If we decide to set this value
+	 * dynamicaly, have in mind that when AR5K_RSSI_THR
+	 * register is read it might return 0x40 if we haven't
+	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
+	 * So doing a save/restore procedure here isn't the right
+	 * choice. Instead store it on ath5k_hw */
+	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+				AR5K_TUNE_BMISS_THRES <<
+				AR5K_RSSI_THR_BMISS_S),
+				AR5K_RSSI_THR);
+
+	/* MIC QoS support */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
+	}
+
+	/* QoS NOACK Policy */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
+			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+			AR5K_QOS_NOACK);
+	}
+
+
+	/*
+	 * Configure PHY
+	 */
+
+	/* Set channel on PHY */
+	ret = ath5k_hw_channel(ah, channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * Enable the PHY and wait until completion
+	 * This includes BaseBand and Synthesizer
+	 * activation.
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+	/*
+	 * On 5211+ read activation -> rx delay
+	 * and use it.
+	 *
+	 * TODO: Half/quarter rate support
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		u32 delay;
+		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+			AR5K_PHY_RX_DELAY_M;
+		delay = (channel->hw_value & CHANNEL_CCK) ?
+			((delay << 2) / 22) : (delay / 10);
+
+		udelay(100 + (2 * delay));
+	} else {
+		mdelay(1);
+	}
+
+	/*
+	 * Perform ADC test to see if baseband is ready
+	 * Set tx hold and check adc test register
+	 */
+	phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+	for (i = 0; i <= 20; i++) {
+		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+			break;
+		udelay(200);
+	}
+	ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+
+	/*
+	 * Start automatic gain control calibration
+	 *
+	 * During AGC calibration RX path is re-routed to
+	 * a power detector so we don't receive anything.
+	 *
+	 * This method is used to calibrate some static offsets
+	 * used together with on-the fly I/Q calibration (the
+	 * one performed via ath5k_hw_phy_calibrate), that doesn't
+	 * interrupt rx path.
+	 *
+	 * While rx path is re-routed to the power detector we also
+	 * start a noise floor calibration, to measure the
+	 * card's noise floor (the noise we measure when we are not
+	 * transmiting or receiving anything).
+	 *
+	 * If we are in a noisy environment AGC calibration may time
+	 * out and/or noise floor calibration might timeout.
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_CAL);
+
+	/* At the same time start I/Q calibration for QAM constellation
+	 * -no need for CCK- */
+	ah->ah_calibration = 0;
+	if (!(mode == AR5K_MODE_11B)) {
+		ah->ah_calibration = 1;
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_RUN);
+	}
+
+	/* Wait for gain calibration to finish (we check for I/Q calibration
+	 * during ath5k_phy_calibrate) */
+	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, 0)) {
+		DBG("ath5k: gain calibration timeout (%d MHz)\n",
+		    channel->center_freq);
+	}
+
+	/*
+	 * If we run NF calibration before AGC, it always times out.
+	 * Binary HAL starts NF and AGC calibration at the same time
+	 * and only waits for AGC to finish. Also if AGC or NF cal.
+	 * times out, reset doesn't fail on binary HAL. I believe
+	 * that's wrong because since rx path is routed to a detector,
+	 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
+	 * enables noise floor calibration after offset calibration and if noise
+	 * floor calibration fails, reset fails. I believe that's
+	 * a better approach, we just need to find a polling interval
+	 * that suits best, even if reset continues we need to make
+	 * sure that rx path is ready.
+	 */
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+
+	/*
+	 * Configure QCUs/DCUs
+	 */
+
+	/* TODO: HW Compression support for data queues */
+	/* TODO: Burst prefetch for data queues */
+
+	/*
+	 * Reset queues and start beacon timers at the end of the reset routine
+	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+	 * Note: If we want we can assign multiple qcus on one dcu.
+	 */
+	ret = ath5k_hw_reset_tx_queue(ah);
+	if (ret) {
+		DBG("ath5k: failed to reset TX queue\n");
+		return ret;
+	}
+
+	/*
+	 * Configure DMA/Interrupts
+	 */
+
+	/*
+	 * Set Rx/Tx DMA Configuration
+	 *
+	 * Set standard DMA size (128). Note that
+	 * a DMA size of 512 causes rx overruns and tx errors
+	 * on pci-e cards (tested on 5424 but since rx overruns
+	 * also occur on 5416/5418 with madwifi we set 128
+	 * for all PCI-E cards to be safe).
+	 *
+	 * XXX: need to check 5210 for this
+	 * TODO: Check out tx triger level, it's always 64 on dumps but I
+	 * guess we can tweak it and see how it goes ;-)
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+	}
+
+	/* Pre-enable interrupts on 5211/5212*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_set_imr(ah, ah->ah_imr);
+
+	/*
+	 * Setup RFKill interrupt if rfkill flag is set on eeprom.
+	 * TODO: Use gpio pin and polarity infos from eeprom
+	 * TODO: Handle this in ath5k_intr because it'll result
+	 * 	 a nasty interrupt storm.
+	 */
+#if 0
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
+		ath5k_hw_set_gpio_input(ah, 0);
+		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
+		if (ah->ah_gpio[0] == 0)
+			ath5k_hw_set_gpio_intr(ah, 0, 1);
+		else
+			ath5k_hw_set_gpio_intr(ah, 0, 0);
+	}
+#endif
+
+	/*
+	 * Disable beacons and reset the register
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
+			AR5K_BEACON_RESET_TSF);
+
+	return 0;
+}
+
+#undef _ATH5K_RESET
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c
new file mode 100644
index 0000000..752ef70
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c
@@ -0,0 +1,107 @@
+/*
+ * RFKILL support for ath5k
+ *
+ * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel at gmail.com>
+ * Lightly modified for iPXE, Sep 2008 by Joshua Oreman <oremanj at rwcr.net>
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+FILE_LICENCE ( MIT );
+
+#include "base.h"
+
+
+static inline void ath5k_rfkill_disable(struct ath5k_softc *sc)
+{
+	DBG("ath5k: rfkill disable (gpio:%d polarity:%d)\n",
+	    sc->rf_kill.gpio, sc->rf_kill.polarity);
+	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity);
+}
+
+
+static inline void ath5k_rfkill_enable(struct ath5k_softc *sc)
+{
+	DBG("ath5k: rfkill enable (gpio:%d polarity:%d)\n",
+	    sc->rf_kill.gpio, sc->rf_kill.polarity);
+	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity);
+}
+
+static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, int enable)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 curval;
+
+	ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio);
+	curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ?
+			       !!curval : !curval);
+}
+
+static int __unused
+ath5k_is_rfkill_set(struct ath5k_softc *sc)
+{
+	/* configuring GPIO for input for some reason disables rfkill */
+	/*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/
+	return (ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) ==
+		sc->rf_kill.polarity);
+}
+
+void
+ath5k_rfkill_hw_start(struct ath5k_hw *ah)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+
+	/* read rfkill GPIO configuration from EEPROM header */
+	sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin;
+	sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol;
+
+	ath5k_rfkill_disable(sc);
+
+	/* enable interrupt for rfkill switch */
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+		ath5k_rfkill_set_intr(sc, 1);
+}
+
+
+void
+ath5k_rfkill_hw_stop(struct ath5k_hw *ah)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+
+	/* disable interrupt for rfkill switch */
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+		ath5k_rfkill_set_intr(sc, 0);
+
+	/* enable RFKILL when stopping HW so Wifi LED is turned off */
+	ath5k_rfkill_enable(sc);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/base.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/base.h
new file mode 100644
index 0000000..976a3f3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/base.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj at rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHVAR_H
+#define _DEV_ATH_ATHVAR_H
+
+FILE_LICENCE ( BSD3 );
+
+#include "ath5k.h"
+#include <ipxe/iobuf.h>
+
+#define	ATH_RXBUF	16		/* number of RX buffers */
+#define	ATH_TXBUF	16		/* number of TX buffers */
+
+struct ath5k_buf {
+	struct list_head	list;
+	unsigned int		flags;	/* rx descriptor flags */
+	struct ath5k_desc	*desc;	/* virtual addr of desc */
+	u32			daddr;	/* physical addr of desc */
+	struct io_buffer	*iob;	/* I/O buffer for buf */
+	u32			iobaddr;/* physical addr of iob data */
+};
+
+/*
+ * Data transmit queue state.  One of these exists for each
+ * hardware transmit queue.  Packets sent to us from above
+ * are assigned to queues based on their priority.  Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath5k_txq {
+	unsigned int		qnum;	/* hardware q number */
+	u32			*link;	/* link ptr in last TX desc */
+	struct list_head	q;	/* transmit queue */
+	int			setup;
+};
+
+#if CHAN_DEBUG
+#define ATH_CHAN_MAX	(26+26+26+200+200)
+#else
+#define ATH_CHAN_MAX	(14+14+14+252+20)
+#endif
+
+/* Software Carrier, keeps track of the driver state
+ * associated with an instance of a device */
+struct ath5k_softc {
+	struct pci_device	*pdev;		/* for dma mapping */
+	void			*iobase;	/* address of the device */
+	struct net80211_device	*dev;		/* IEEE 802.11 common */
+	struct ath5k_hw		*ah;		/* Atheros HW */
+	struct net80211_hw_info	*hwinfo;
+	int			curband;
+	int			irq_ena; 	/* interrupts enabled */
+
+	struct ath5k_buf	*bufptr;	/* allocated buffer ptr */
+	struct ath5k_desc	*desc;		/* TX/RX descriptors */
+	u32			desc_daddr;	/* DMA (physical) address */
+	size_t			desc_len;	/* size of TX/RX descriptors */
+	u16			cachelsz;	/* cache line size */
+
+	int			status;
+#define ATH_STAT_INVALID	0x01		/* disable hardware accesses */
+#define ATH_STAT_MRRETRY	0x02		/* multi-rate retry support */
+#define ATH_STAT_PROMISC	0x04
+#define ATH_STAT_LEDSOFT	0x08		/* enable LED gpio status */
+#define ATH_STAT_STARTED	0x10		/* opened & irqs enabled */
+
+	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
+	unsigned int		curmode;	/* current phy mode */
+	struct net80211_channel	*curchan;	/* current h/w channel */
+
+	enum ath5k_int		imask;		/* interrupt mask copy */
+
+	u8			bssidmask[ETH_ALEN];
+
+	unsigned int		rxbufsize;	/* rx size based on mtu */
+	struct list_head	rxbuf;		/* receive buffer */
+	u32			*rxlink;	/* link ptr in last RX desc */
+
+	struct list_head	txbuf;		/* transmit buffer */
+	unsigned int		txbuf_len;	/* buf count in txbuf list */
+	struct ath5k_txq	txq;		/* tx queue */
+
+	struct {
+		u16 gpio;
+		unsigned polarity;
+	} rf_kill;
+
+	int			last_calib_ticks;
+
+	int 			power_level;	/* Requested tx power in dbm */
+	int			assoc;		/* assocate state */
+
+	int			hw_rate;	/* Hardware tx rate code */
+	int			hw_rtscts_rate;	/* Hardware rts/cts rate code */
+};
+
+#define ath5k_hw_hasbssidmask(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
+#define ath5k_hw_hasveol(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/desc.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/desc.h
new file mode 100644
index 0000000..6e11b0d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/desc.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Internal RX/TX descriptor structures
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+/*
+ * common hardware RX control descriptor
+ */
+struct ath5k_hw_rx_ctl {
+	u32	rx_control_0; /* RX control word 0 */
+	u32	rx_control_1; /* RX control word 1 */
+} __attribute__ ((packed));
+
+/* RX control word 0 field/sflags */
+#define AR5K_DESC_RX_CTL0			0x00000000
+
+/* RX control word 1 fields/flags */
+#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
+#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
+
+/*
+ * common hardware RX status descriptor
+ * 5210/11 and 5212 differ only in the flags defined below
+ */
+struct ath5k_hw_rx_status {
+	u32	rx_status_0; /* RX status word 0 */
+	u32	rx_status_1; /* RX status word 1 */
+} __attribute__ ((packed));
+
+/* 5210/5211 */
+/* RX status word 0 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
+
+/* RX status word 1 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
+
+/* 5212 */
+/* RX status word 0 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
+
+/* RX status word 1 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
+
+/*
+ * common hardware RX error descriptor
+ */
+struct ath5k_hw_rx_error {
+	u32	rx_error_0; /* RX status word 0 */
+	u32	rx_error_1; /* RX status word 1 */
+} __attribute__ ((packed));
+
+/* RX error word 0 fields/flags */
+#define AR5K_RX_DESC_ERROR0			0x00000000
+
+/* RX error word 1 fields/flags */
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
+
+/* PHY Error codes */
+#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
+#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
+#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
+#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
+#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
+#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
+#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
+#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
+
+/*
+ * 5210/5211 hardware 2-word TX control descriptor
+ */
+struct ath5k_hw_2w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+	u32	tx_control_1; /* TX control word 1 */
+} __attribute__ ((packed));
+
+/* TX control word 0 fields/flags */
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
+#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT			\
+		(ah->ah_version == AR5K_AR5210 ?		\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 :	\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+
+/* TX control word 1 fields/flags */
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX				\
+			(ah->ah_version == AR5K_AR5210 ?		\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 :	\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
+
+/* Frame types */
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+
+/*
+ * 5212 hardware 4-word TX control descriptor
+ */
+struct ath5k_hw_4w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
+
+	u32	tx_control_1; /* TX control word 1 */
+
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
+
+	u32	tx_control_2; /* TX control word 2 */
+
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
+
+	u32	tx_control_3; /* TX control word 3 */
+
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
+} __attribute__ ((packed));
+
+/*
+ * Common TX status descriptor
+ */
+struct ath5k_hw_tx_status {
+	u32	tx_status_0; /* TX status word 0 */
+	u32	tx_status_1; /* TX status word 1 */
+} __attribute__ ((packed));
+
+/* TX status word 0 fields/flags */
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
+#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
+/*???
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
+*/
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
+/*???
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
+*/
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
+
+/* TX status word 1 fields/flags */
+#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
+
+/*
+ * 5210/5211 hardware TX descriptor
+ */
+struct ath5k_hw_5210_tx_desc {
+	struct ath5k_hw_2w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __attribute__ ((packed));
+
+/*
+ * 5212 hardware TX descriptor
+ */
+struct ath5k_hw_5212_tx_desc {
+	struct ath5k_hw_4w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __attribute__ ((packed));
+
+/*
+ * common hardware RX descriptor
+ */
+struct ath5k_hw_all_rx_desc {
+	struct ath5k_hw_rx_ctl			rx_ctl;
+	union {
+		struct ath5k_hw_rx_status	rx_stat;
+		struct ath5k_hw_rx_error	rx_err;
+	} u;
+} __attribute__ ((packed));
+
+/*
+ * Atheros hardware descriptor
+ * This is read and written to by the hardware
+ */
+struct ath5k_desc {
+	u32	ds_link;	/* physical address of the next descriptor */
+	u32	ds_data;	/* physical address of data buffer (skb) */
+
+	union {
+		struct ath5k_hw_5210_tx_desc	ds_tx5210;
+		struct ath5k_hw_5212_tx_desc	ds_tx5212;
+		struct ath5k_hw_all_rx_desc	ds_rx;
+	} ud;
+} __attribute__ ((packed));
+
+#define AR5K_RXDESC_INTREQ	0x0020
+
+#define AR5K_TXDESC_CLRDMASK	0x0001
+#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
+#define AR5K_TXDESC_RTSENA	0x0004
+#define AR5K_TXDESC_CTSENA	0x0008
+#define AR5K_TXDESC_INTREQ	0x0010
+#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/eeprom.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/eeprom.h
new file mode 100644
index 0000000..da45433
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/eeprom.h
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
+ */
+#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
+#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
+#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
+#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
+#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
+
+#define	AR5K_EEPROM_IS_HB63		0x000b	/* Talon detect */
+
+#define AR5K_EEPROM_RFKILL		0x0f
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
+#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM		0xffff
+#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3		0x4003	/* power calibration changes */
+#define AR5K_EEPROM_VERSION_4_4		0x4004
+#define AR5K_EEPROM_VERSION_4_5		0x4005
+#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7		0x3007	/* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9		0x4009	/* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0		0x5000	/* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1		0x5001	/* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3		0x5003	/* Has spur mitigation tables */
+
+#define AR5K_EEPROM_MODE_11A		0
+#define AR5K_EEPROM_MODE_11B		1
+#define AR5K_EEPROM_MODE_11G		2
+
+#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1			AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)		((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)		(((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)	(((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2			AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v)	(((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3		AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v)	(((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4		AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v)	(((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v)		(((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v)		((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5		AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v)	((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v)		(((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v)		(((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v)	(((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v)		(((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)	(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v)	(((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6		AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS	((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS	(((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN		(((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN	(((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN		(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN	(((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN	(((_v) >> 10) & 0x1)
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET	0x0
+#define AR5K_EEPROM_GROUP2_OFFSET	0x5
+#define AR5K_EEPROM_GROUP3_OFFSET	0x37
+#define AR5K_EEPROM_GROUP4_OFFSET	0x46
+#define AR5K_EEPROM_GROUP5_OFFSET	0x55
+#define AR5K_EEPROM_GROUP6_OFFSET	0x65
+#define AR5K_EEPROM_GROUP7_OFFSET	0x69
+#define AR5K_EEPROM_GROUP8_OFFSET	0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
+
+#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
+
+/* Some EEPROM defines */
+#define AR5K_EEPROM_EEP_SCALE		100
+#define AR5K_EEPROM_EEP_DELTA		10
+#define AR5K_EEPROM_N_MODES		3
+#define AR5K_EEPROM_N_5GHZ_CHAN		10
+#define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413	4
+#define	AR5K_EEPROM_N_2GHZ_CHAN_MAX	4
+#define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PWR_POINTS_5111	11
+#define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_PHASE_CAL		5
+#define AR5K_EEPROM_N_TEST_FREQ		8
+#define AR5K_EEPROM_N_EDGES		8
+#define AR5K_EEPROM_N_INTERCEPTS	11
+#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
+#define AR5K_EEPROM_PCDAC_M		0x3f
+#define AR5K_EEPROM_PCDAC_START		1
+#define AR5K_EEPROM_PCDAC_STOP		63
+#define AR5K_EEPROM_PCDAC_STEP		1
+#define AR5K_EEPROM_NON_EDGE_M		0x40
+#define AR5K_EEPROM_CHANNEL_POWER	8
+#define AR5K_EEPROM_N_OBDB		4
+#define AR5K_EEPROM_OBDB_DIS		0xffff
+#define AR5K_EEPROM_CHANNEL_DIS		0xff
+#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
+#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
+#define AR5K_EEPROM_MAX_CTLS		32
+#define AR5K_EEPROM_N_PD_CURVES		4
+#define AR5K_EEPROM_N_XPD0_POINTS	4
+#define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_PD_GAINS		4
+#define AR5K_EEPROM_N_PD_POINTS		5
+#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
+#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
+#define AR5K_EEPROM_POWER_M		0x3f
+#define AR5K_EEPROM_POWER_MIN		0
+#define AR5K_EEPROM_POWER_MAX		3150
+#define AR5K_EEPROM_POWER_STEP		50
+#define AR5K_EEPROM_POWER_TABLE_SIZE	64
+#define AR5K_EEPROM_N_POWER_LOC_11B	4
+#define AR5K_EEPROM_N_POWER_LOC_11G	6
+#define AR5K_EEPROM_I_GAIN		10
+#define AR5K_EEPROM_CCK_OFDM_DELTA	15
+#define AR5K_EEPROM_N_IQ_CAL		2
+
+#define AR5K_EEPROM_READ(_o, _v) do {			\
+	ret = ath5k_hw_eeprom_read(ah, (_o), &(_v));	\
+	if (ret)					\
+		return ret;				\
+} while (0)
+
+#define AR5K_EEPROM_READ_HDR(_o, _v)					\
+	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
+
+enum ath5k_ant_setting {
+	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
+	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
+	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
+	AR5K_ANT_MAX		= 3,
+};
+
+enum ath5k_ctl_mode {
+	AR5K_CTL_11A = 0,
+	AR5K_CTL_11B = 1,
+	AR5K_CTL_11G = 2,
+	AR5K_CTL_TURBO = 3,
+	AR5K_CTL_TURBOG = 4,
+	AR5K_CTL_2GHT20 = 5,
+	AR5K_CTL_5GHT20 = 6,
+	AR5K_CTL_2GHT40 = 7,
+	AR5K_CTL_5GHT40 = 8,
+	AR5K_CTL_MODE_M = 15,
+};
+
+/* Default CTL ids for the 3 main reg domains.
+ * Atheros only uses these by default but vendors
+ * can have up to 32 different CTLs for different
+ * scenarios. Note that theese values are ORed with
+ * the mode id (above) so we can have up to 24 CTL
+ * datasets out of these 3 main regdomains. That leaves
+ * 8 ids that can be used by vendors and since 0x20 is
+ * missing from HAL sources i guess this is the set of
+ * custom CTLs vendors can use. */
+#define	AR5K_CTL_FCC	0x10
+#define	AR5K_CTL_CUSTOM	0x20
+#define	AR5K_CTL_ETSI	0x30
+#define	AR5K_CTL_MKK	0x40
+
+/* Indicates a CTL with only mode set and
+ * no reg domain mapping, such CTLs are used
+ * for world roaming domains or simply when
+ * a reg domain is not set */
+#define	AR5K_CTL_NO_REGDOMAIN	0xf0
+
+/* Indicates an empty (invalid) CTL */
+#define AR5K_CTL_NO_CTL		0xff
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+	/* Power levels in half dbm units
+	 * for one power curve. */
+	u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* PCDAC table steps
+	 * for the above values */
+	u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* Starting PCDAC step */
+	u8 pcdac_min;
+	/* Final PCDAC step */
+	u8 pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+	/* Power levels in quarter dBm units
+	 * for lower (0) and higher (3)
+	 * level curves in 0.25dB units */
+	s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+	/* PCDAC table steps
+	 * for the above values */
+	u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+	/* Starting pwr/pddac values */
+	s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
+	u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
+	/* (pwr,pddac) points
+	 * power levels in 0.5dB units */
+	s8 pwr[AR5K_EEPROM_N_PD_GAINS]
+		[AR5K_EEPROM_N_PD_POINTS];
+	u8 pddac[AR5K_EEPROM_N_PD_GAINS]
+		[AR5K_EEPROM_N_PD_POINTS];
+};
+
+enum ath5k_powertable_type {
+	AR5K_PWRTABLE_PWR_TO_PCDAC = 0,
+	AR5K_PWRTABLE_LINEAR_PCDAC = 1,
+	AR5K_PWRTABLE_PWR_TO_PDADC = 2,
+};
+
+struct ath5k_pdgain_info {
+	u8 pd_points;
+	u8 *pd_step;
+	/* Power values are in
+	 * 0.25dB units */
+	s16 *pd_pwr;
+};
+
+struct ath5k_chan_pcal_info {
+	/* Frequency */
+	u16	freq;
+	/* Tx power boundaries */
+	s16	max_pwr;
+	s16	min_pwr;
+	union {
+		struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+		struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+		struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+	};
+	/* Raw values used by phy code
+	 * Curves are stored in order from lower
+	 * gain to higher gain (max txpower -> min txpower) */
+	struct ath5k_pdgain_info *pd_curves;
+};
+
+/* Per rate calibration data for each mode,
+ * used for rate power table setup.
+ * Note: Values in 0.5dB units */
+struct ath5k_rate_pcal_info {
+	u16	freq; /* Frequency */
+	/* Power level for 6-24Mbit/s rates or
+	 * 1Mb rate */
+	u16	target_power_6to24;
+	/* Power level for 36Mbit rate or
+	 * 2Mb rate */
+	u16	target_power_36;
+	/* Power level for 48Mbit rate or
+	 * 5.5Mbit rate */
+	u16	target_power_48;
+	/* Power level for 54Mbit rate or
+	 * 11Mbit rate */
+	u16	target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+	u16 freq;
+	u16 edge; /* in half dBm */
+	int flag;
+};
+
+/* EEPROM calibration data */
+struct ath5k_eeprom_info {
+
+	/* Header information */
+	u16	ee_magic;
+	u16	ee_protect;
+	u16	ee_regdomain;
+	u16	ee_version;
+	u16	ee_header;
+	u16	ee_ant_gain;
+	u8	ee_rfkill_pin;
+	int	ee_rfkill_pol;
+	int	ee_is_hb63;
+	u16	ee_misc0;
+	u16	ee_misc1;
+	u16	ee_misc2;
+	u16	ee_misc3;
+	u16	ee_misc4;
+	u16	ee_misc5;
+	u16	ee_misc6;
+	u16	ee_cck_ofdm_gain_delta;
+	u16	ee_cck_ofdm_power_delta;
+	u16	ee_scaled_cck_delta;
+
+	/* RF Calibration settings (reset, rfregs) */
+	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
+	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
+	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
+	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
+	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_xpd[AR5K_EEPROM_N_MODES];
+	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+
+	/* Power calibration data */
+	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
+
+	/* Number of pd gain curves per mode */
+	u8	ee_pd_gains[AR5K_EEPROM_N_MODES];
+	/* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */
+	u8	ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS];
+
+	u8	ee_n_piers[AR5K_EEPROM_N_MODES];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+
+	/* Per rate target power levels */
+	u8	ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+
+	/* Conformance test limits (Unused) */
+	u8	ee_ctls;
+	u8	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+	struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
+
+	/* Noise Floor Calibration settings */
+	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pd_gain_overlap;
+
+	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/reg.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/reg.h
new file mode 100644
index 0000000..7070d15
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/reg.h
@@ -0,0 +1,2589 @@
+/*
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm at gmail.com>
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2007-2008 Michael Taylor <mike.taylor at apprion.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
+ * maintained by Reyk Floeter
+ *
+ * I tried to document those registers by looking at ar5k code, some
+ * 802.11 (802.11e mostly) papers and by reading various public available
+ * Atheros presentations and papers like these:
+ *
+ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
+ *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
+ *
+ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
+ *
+ * This file also contains register values found on a memory dump of
+ * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal
+ * released by Atheros and on various debug messages found on the net.
+ */
+
+
+
+/*====MAC DMA REGISTERS====*/
+
+/*
+ * AR5210-Specific TXDP registers
+ * 5210 has only 2 transmit queues so no DCU/QCU, just
+ * 2 transmit descriptor pointers...
+ */
+#define AR5K_NOQCU_TXDP0	0x0000		/* Queue 0 - data */
+#define AR5K_NOQCU_TXDP1	0x0004		/* Queue 1 - beacons */
+
+/*
+ * Mac Control Register
+ */
+#define	AR5K_CR		0x0008			/* Register Address */
+#define AR5K_CR_TXE0	0x00000001	/* TX Enable for queue 0 on 5210 */
+#define AR5K_CR_TXE1	0x00000002	/* TX Enable for queue 1 on 5210 */
+#define	AR5K_CR_RXE	0x00000004	/* RX Enable */
+#define AR5K_CR_TXD0	0x00000008	/* TX Disable for queue 0 on 5210 */
+#define AR5K_CR_TXD1	0x00000010	/* TX Disable for queue 1 on 5210 */
+#define	AR5K_CR_RXD	0x00000020	/* RX Disable */
+#define	AR5K_CR_SWI	0x00000040	/* Software Interrupt */
+
+/*
+ * RX Descriptor Pointer register
+ */
+#define	AR5K_RXDP	0x000c
+
+/*
+ * Configuration and status register
+ */
+#define	AR5K_CFG		0x0014			/* Register Address */
+#define	AR5K_CFG_SWTD		0x00000001	/* Byte-swap TX descriptor (for big endian archs) */
+#define	AR5K_CFG_SWTB		0x00000002	/* Byte-swap TX buffer */
+#define	AR5K_CFG_SWRD		0x00000004	/* Byte-swap RX descriptor */
+#define	AR5K_CFG_SWRB		0x00000008	/* Byte-swap RX buffer */
+#define	AR5K_CFG_SWRG		0x00000010	/* Byte-swap Register access */
+#define AR5K_CFG_IBSS		0x00000020 	/* 0-BSS, 1-IBSS [5211+] */
+#define AR5K_CFG_PHY_OK		0x00000100	/* [5211+] */
+#define AR5K_CFG_EEBS		0x00000200	/* EEPROM is busy */
+#define	AR5K_CFG_CLKGD		0x00000400	/* Clock gated (Disable dynamic clock) */
+#define AR5K_CFG_TXCNT		0x00007800	/* Tx frame count (?) [5210] */
+#define AR5K_CFG_TXCNT_S	11
+#define AR5K_CFG_TXFSTAT	0x00008000	/* Tx frame status (?) [5210] */
+#define AR5K_CFG_TXFSTRT	0x00010000	/* [5210] */
+#define	AR5K_CFG_PCI_THRES	0x00060000	/* PCI Master req q threshold [5211+] */
+#define	AR5K_CFG_PCI_THRES_S	17
+
+/*
+ * Interrupt enable register
+ */
+#define AR5K_IER		0x0024		/* Register Address */
+#define AR5K_IER_DISABLE	0x00000000	/* Disable card interrupts */
+#define AR5K_IER_ENABLE		0x00000001	/* Enable card interrupts */
+
+
+/*
+ * 0x0028 is Beacon Control Register on 5210
+ * and first RTS duration register on 5211
+ */
+
+/*
+ * Beacon control register [5210]
+ */
+#define AR5K_BCR		0x0028		/* Register Address */
+#define AR5K_BCR_AP		0x00000000	/* AP mode */
+#define AR5K_BCR_ADHOC		0x00000001	/* Ad-Hoc mode */
+#define AR5K_BCR_BDMAE		0x00000002	/* DMA enable */
+#define AR5K_BCR_TQ1FV		0x00000004	/* Use Queue1 for CAB traffic */
+#define AR5K_BCR_TQ1V		0x00000008	/* Use Queue1 for Beacon traffic */
+#define AR5K_BCR_BCGET		0x00000010
+
+/*
+ * First RTS duration register [5211]
+ */
+#define AR5K_RTSD0		0x0028		/* Register Address */
+#define	AR5K_RTSD0_6		0x000000ff	/* 6Mb RTS duration mask (?) */
+#define	AR5K_RTSD0_6_S		0		/* 6Mb RTS duration shift (?) */
+#define	AR5K_RTSD0_9		0x0000ff00	/* 9Mb*/
+#define	AR5K_RTSD0_9_S		8
+#define	AR5K_RTSD0_12		0x00ff0000	/* 12Mb*/
+#define	AR5K_RTSD0_12_S		16
+#define	AR5K_RTSD0_18		0xff000000	/* 16Mb*/
+#define	AR5K_RTSD0_18_S		24
+
+
+/*
+ * 0x002c is Beacon Status Register on 5210
+ * and second RTS duration register on 5211
+ */
+
+/*
+ * Beacon status register [5210]
+ *
+ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
+ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
+ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
+ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
+ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
+ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
+ */
+#define AR5K_BSR		0x002c			/* Register Address */
+#define AR5K_BSR_BDLYSW		0x00000001	/* SW Beacon delay (?) */
+#define AR5K_BSR_BDLYDMA	0x00000002	/* DMA Beacon delay (?) */
+#define AR5K_BSR_TXQ1F		0x00000004	/* Beacon queue (1) finished */
+#define AR5K_BSR_ATIMDLY	0x00000008	/* ATIM delay (?) */
+#define AR5K_BSR_SNPADHOC	0x00000100	/* Ad-hoc mode set (?) */
+#define AR5K_BSR_SNPBDMAE	0x00000200	/* Beacon DMA enabled (?) */
+#define AR5K_BSR_SNPTQ1FV	0x00000400	/* Queue1 is used for CAB traffic (?) */
+#define AR5K_BSR_SNPTQ1V	0x00000800	/* Queue1 is used for Beacon traffic (?) */
+#define AR5K_BSR_SNAPSHOTSVALID	0x00001000	/* BCR snapshots are valid (?) */
+#define AR5K_BSR_SWBA_CNT	0x00ff0000
+
+/*
+ * Second RTS duration register [5211]
+ */
+#define AR5K_RTSD1		0x002c			/* Register Address */
+#define	AR5K_RTSD1_24		0x000000ff	/* 24Mb */
+#define	AR5K_RTSD1_24_S		0
+#define	AR5K_RTSD1_36		0x0000ff00	/* 36Mb */
+#define	AR5K_RTSD1_36_S		8
+#define	AR5K_RTSD1_48		0x00ff0000	/* 48Mb */
+#define	AR5K_RTSD1_48_S		16
+#define	AR5K_RTSD1_54		0xff000000	/* 54Mb */
+#define	AR5K_RTSD1_54_S		24
+
+
+/*
+ * Transmit configuration register
+ */
+#define AR5K_TXCFG			0x0030			/* Register Address */
+#define AR5K_TXCFG_SDMAMR		0x00000007	/* DMA size (read) */
+#define AR5K_TXCFG_SDMAMR_S		0
+#define AR5K_TXCFG_B_MODE		0x00000008	/* Set b mode for 5111 (enable 2111) */
+#define AR5K_TXCFG_TXFSTP		0x00000008	/* TX DMA full Stop [5210] */
+#define AR5K_TXCFG_TXFULL		0x000003f0	/* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL_S		4
+#define AR5K_TXCFG_TXFULL_0B		0x00000000
+#define AR5K_TXCFG_TXFULL_64B		0x00000010
+#define AR5K_TXCFG_TXFULL_128B		0x00000020
+#define AR5K_TXCFG_TXFULL_192B		0x00000030
+#define AR5K_TXCFG_TXFULL_256B		0x00000040
+#define AR5K_TXCFG_TXCONT_EN		0x00000080
+#define AR5K_TXCFG_DMASIZE		0x00000100	/* Flag for passing DMA size [5210] */
+#define AR5K_TXCFG_JUMBO_DESC_EN	0x00000400	/* Enable jumbo tx descriptors [5211+] */
+#define AR5K_TXCFG_ADHOC_BCN_ATIM	0x00000800	/* Adhoc Beacon ATIM Policy */
+#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS	0x00001000	/* Disable ATIM window defer [5211+] */
+#define AR5K_TXCFG_RTSRND		0x00001000	/* [5211+] */
+#define AR5K_TXCFG_FRMPAD_DIS		0x00002000	/* [5211+] */
+#define AR5K_TXCFG_RDY_CBR_DIS		0x00004000	/* Ready time CBR disable [5211+] */
+#define AR5K_TXCFG_JUMBO_FRM_MODE	0x00008000	/* Jumbo frame mode [5211+] */
+#define	AR5K_TXCFG_DCU_DBL_BUF_DIS	0x00008000	/* Disable double buffering on DCU */
+#define AR5K_TXCFG_DCU_CACHING_DIS	0x00010000	/* Disable DCU caching */
+
+/*
+ * Receive configuration register
+ */
+#define AR5K_RXCFG		0x0034			/* Register Address */
+#define AR5K_RXCFG_SDMAMW	0x00000007	/* DMA size (write) */
+#define AR5K_RXCFG_SDMAMW_S	0
+#define AR5K_RXCFG_ZLFDMA	0x00000008	/* Enable Zero-length frame DMA */
+#define	AR5K_RXCFG_DEF_ANTENNA	0x00000010	/* Default antenna (?) */
+#define AR5K_RXCFG_JUMBO_RXE	0x00000020	/* Enable jumbo rx descriptors [5211+] */
+#define AR5K_RXCFG_JUMBO_WRAP	0x00000040	/* Wrap jumbo frames [5211+] */
+#define AR5K_RXCFG_SLE_ENTRY	0x00000080	/* Sleep entry policy */
+
+/*
+ * Receive jumbo descriptor last address register
+ * Only found in 5211 (?)
+ */
+#define AR5K_RXJLA		0x0038
+
+/*
+ * MIB control register
+ */
+#define AR5K_MIBC		0x0040			/* Register Address */
+#define AR5K_MIBC_COW		0x00000001	/* Warn test indicator */
+#define AR5K_MIBC_FMC		0x00000002	/* Freeze MIB Counters  */
+#define AR5K_MIBC_CMC		0x00000004	/* Clean MIB Counters  */
+#define AR5K_MIBC_MCS		0x00000008	/* MIB counter strobe */
+
+/*
+ * Timeout prescale register
+ */
+#define AR5K_TOPS		0x0044
+#define	AR5K_TOPS_M		0x0000ffff
+
+/*
+ * Receive timeout register (no frame received)
+ */
+#define AR5K_RXNOFRM		0x0048
+#define	AR5K_RXNOFRM_M		0x000003ff
+
+/*
+ * Transmit timeout register (no frame sent)
+ */
+#define AR5K_TXNOFRM		0x004c
+#define	AR5K_TXNOFRM_M		0x000003ff
+#define	AR5K_TXNOFRM_QCU	0x000ffc00
+#define	AR5K_TXNOFRM_QCU_S	10
+
+/*
+ * Receive frame gap timeout register
+ */
+#define AR5K_RPGTO		0x0050
+#define AR5K_RPGTO_M		0x000003ff
+
+/*
+ * Receive frame count limit register
+ */
+#define AR5K_RFCNT		0x0054
+#define AR5K_RFCNT_M		0x0000001f	/* [5211+] (?) */
+#define AR5K_RFCNT_RFCL		0x0000000f	/* [5210] */
+
+/*
+ * Misc settings register
+ * (reserved0-3)
+ */
+#define AR5K_MISC		0x0058			/* Register Address */
+#define	AR5K_MISC_DMA_OBS_M	0x000001e0
+#define	AR5K_MISC_DMA_OBS_S	5
+#define	AR5K_MISC_MISC_OBS_M	0x00000e00
+#define	AR5K_MISC_MISC_OBS_S	9
+#define	AR5K_MISC_MAC_OBS_LSB_M	0x00007000
+#define	AR5K_MISC_MAC_OBS_LSB_S	12
+#define	AR5K_MISC_MAC_OBS_MSB_M	0x00038000
+#define	AR5K_MISC_MAC_OBS_MSB_S	15
+#define AR5K_MISC_LED_DECAY	0x001c0000	/* [5210] */
+#define AR5K_MISC_LED_BLINK	0x00e00000	/* [5210] */
+
+/*
+ * QCU/DCU clock gating register (5311)
+ * (reserved4-5)
+ */
+#define	AR5K_QCUDCU_CLKGT	0x005c			/* Register Address (?) */
+#define	AR5K_QCUDCU_CLKGT_QCU	0x0000ffff	/* Mask for QCU clock */
+#define	AR5K_QCUDCU_CLKGT_DCU	0x07ff0000	/* Mask for DCU clock */
+
+/*
+ * Interrupt Status Registers
+ *
+ * For 5210 there is only one status register but for
+ * 5211/5212 we have one primary and 4 secondary registers.
+ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
+ * Most of these bits are common for all chipsets.
+ */
+#define AR5K_ISR		0x001c			/* Register Address [5210] */
+#define AR5K_PISR		0x0080			/* Register Address [5211+] */
+#define AR5K_ISR_RXOK		0x00000001	/* Frame successfuly recieved */
+#define AR5K_ISR_RXDESC		0x00000002	/* RX descriptor request */
+#define AR5K_ISR_RXERR		0x00000004	/* Receive error */
+#define AR5K_ISR_RXNOFRM	0x00000008	/* No frame received (receive timeout) */
+#define AR5K_ISR_RXEOL		0x00000010	/* Empty RX descriptor */
+#define AR5K_ISR_RXORN		0x00000020	/* Receive FIFO overrun */
+#define AR5K_ISR_TXOK		0x00000040	/* Frame successfuly transmited */
+#define AR5K_ISR_TXDESC		0x00000080	/* TX descriptor request */
+#define AR5K_ISR_TXERR		0x00000100	/* Transmit error */
+#define AR5K_ISR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout) */
+#define AR5K_ISR_TXEOL		0x00000400	/* Empty TX descriptor */
+#define AR5K_ISR_TXURN		0x00000800	/* Transmit FIFO underrun */
+#define AR5K_ISR_MIB		0x00001000	/* Update MIB counters */
+#define AR5K_ISR_SWI		0x00002000	/* Software interrupt */
+#define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
+#define AR5K_ISR_RXKCM		0x00008000	/* RX Key cache miss */
+#define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
+#define AR5K_ISR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
+#define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
+#define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_ISR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
+#define AR5K_ISR_RXCHIRP	0x00200000	/* CHIRP Received [5212+] */
+#define AR5K_ISR_SSERR		0x00200000	/* Signaled System Error [5210] */
+#define AR5K_ISR_DPERR		0x00400000	/* Det par Error (?) [5210] */
+#define AR5K_ISR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
+#define AR5K_ISR_TIM		0x00800000	/* [5211+] */
+#define AR5K_ISR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill) */
+#define AR5K_ISR_QCBRORN	0x02000000	/* QCU CBR overrun [5211+] */
+#define AR5K_ISR_QCBRURN	0x04000000	/* QCU CBR underrun [5211+] */
+#define AR5K_ISR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
+
+/*
+ * Secondary status registers [5211+] (0 - 4)
+ *
+ * These give the status for each QCU, only QCUs 0-9 are
+ * represented.
+ */
+#define AR5K_SISR0		0x0084			/* Register Address [5211+] */
+#define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SISR0_QCU_TXOK_S	0
+#define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SISR0_QCU_TXDESC_S	16
+
+#define AR5K_SISR1		0x0088			/* Register Address [5211+] */
+#define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SISR1_QCU_TXERR_S	0
+#define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SISR1_QCU_TXEOL_S	16
+
+#define AR5K_SISR2		0x008c			/* Register Address [5211+] */
+#define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define	AR5K_SISR2_QCU_TXURN_S	0
+#define	AR5K_SISR2_MCABT	0x00100000	/* Master Cycle Abort */
+#define	AR5K_SISR2_SSERR	0x00200000	/* Signaled System Error */
+#define	AR5K_SISR2_DPERR	0x00400000	/* Bus parity error */
+#define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* DTIM sync lost [5212+] */
+#define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
+#define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
+#define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SISR2_TSFOOR	0x80000000	/* TSF OOR (?) */
+
+#define AR5K_SISR3		0x0090			/* Register Address [5211+] */
+#define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SISR3_QCBRORN_S	0
+#define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SISR3_QCBRURN_S	16
+
+#define AR5K_SISR4		0x0094			/* Register Address [5211+] */
+#define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SISR4_QTRIG_S	0
+
+/*
+ * Shadow read-and-clear interrupt status registers [5211+]
+ */
+#define AR5K_RAC_PISR		0x00c0		/* Read and clear PISR */
+#define AR5K_RAC_SISR0		0x00c4		/* Read and clear SISR0 */
+#define AR5K_RAC_SISR1		0x00c8		/* Read and clear SISR1 */
+#define AR5K_RAC_SISR2		0x00cc		/* Read and clear SISR2 */
+#define AR5K_RAC_SISR3		0x00d0		/* Read and clear SISR3 */
+#define AR5K_RAC_SISR4		0x00d4		/* Read and clear SISR4 */
+
+/*
+ * Interrupt Mask Registers
+ *
+ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
+ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
+ */
+#define	AR5K_IMR		0x0020			/* Register Address [5210] */
+#define AR5K_PIMR		0x00a0			/* Register Address [5211+] */
+#define AR5K_IMR_RXOK		0x00000001	/* Frame successfuly recieved*/
+#define AR5K_IMR_RXDESC		0x00000002	/* RX descriptor request*/
+#define AR5K_IMR_RXERR		0x00000004	/* Receive error*/
+#define AR5K_IMR_RXNOFRM	0x00000008	/* No frame received (receive timeout)*/
+#define AR5K_IMR_RXEOL		0x00000010	/* Empty RX descriptor*/
+#define AR5K_IMR_RXORN		0x00000020	/* Receive FIFO overrun*/
+#define AR5K_IMR_TXOK		0x00000040	/* Frame successfuly transmited*/
+#define AR5K_IMR_TXDESC		0x00000080	/* TX descriptor request*/
+#define AR5K_IMR_TXERR		0x00000100	/* Transmit error*/
+#define AR5K_IMR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout)*/
+#define AR5K_IMR_TXEOL		0x00000400	/* Empty TX descriptor*/
+#define AR5K_IMR_TXURN		0x00000800	/* Transmit FIFO underrun*/
+#define AR5K_IMR_MIB		0x00001000	/* Update MIB counters*/
+#define AR5K_IMR_SWI		0x00002000	/* Software interrupt */
+#define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
+#define AR5K_IMR_RXKCM		0x00008000	/* RX Key cache miss */
+#define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
+#define AR5K_IMR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
+#define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
+#define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_IMR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
+#define AR5K_IMR_RXCHIRP	0x00200000	/* CHIRP Received [5212+]*/
+#define AR5K_IMR_SSERR		0x00200000	/* Signaled System Error [5210] */
+#define AR5K_IMR_DPERR		0x00400000	/* Det par Error (?) [5210] */
+#define AR5K_IMR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
+#define AR5K_IMR_TIM		0x00800000	/* [5211+] */
+#define AR5K_IMR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
+#define AR5K_IMR_QCBRORN	0x02000000	/* QCU CBR overrun (?) [5211+] */
+#define AR5K_IMR_QCBRURN	0x04000000	/* QCU CBR underrun (?) [5211+] */
+#define AR5K_IMR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
+
+/*
+ * Secondary interrupt mask registers [5211+] (0 - 4)
+ */
+#define AR5K_SIMR0		0x00a4			/* Register Address [5211+] */
+#define AR5K_SIMR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SIMR0_QCU_TXOK_S	0
+#define AR5K_SIMR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SIMR0_QCU_TXDESC_S	16
+
+#define AR5K_SIMR1		0x00a8			/* Register Address [5211+] */
+#define AR5K_SIMR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SIMR1_QCU_TXERR_S	0
+#define AR5K_SIMR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SIMR1_QCU_TXEOL_S	16
+
+#define AR5K_SIMR2		0x00ac			/* Register Address [5211+] */
+#define AR5K_SIMR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define AR5K_SIMR2_QCU_TXURN_S	0
+#define	AR5K_SIMR2_MCABT	0x00100000	/* Master Cycle Abort */
+#define	AR5K_SIMR2_SSERR	0x00200000	/* Signaled System Error */
+#define	AR5K_SIMR2_DPERR	0x00400000	/* Bus parity error */
+#define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* DTIM Sync lost [5212+] */
+#define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
+#define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
+#define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SIMR2_TSFOOR	0x80000000	/* TSF OOR (?) */
+
+#define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
+#define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SIMR3_QCBRORN_S	0
+#define AR5K_SIMR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SIMR3_QCBRURN_S	16
+
+#define AR5K_SIMR4		0x00b4			/* Register Address [5211+] */
+#define AR5K_SIMR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SIMR4_QTRIG_S	0
+
+/*
+ * DMA Debug registers 0-7
+ * 0xe0 - 0xfc
+ */
+
+/*
+ * Decompression mask registers [5212+]
+ */
+#define AR5K_DCM_ADDR		0x0400		/*Decompression mask address (index) */
+#define AR5K_DCM_DATA		0x0404		/*Decompression mask data */
+
+/*
+ * Wake On Wireless pattern control register [5212+]
+ */
+#define	AR5K_WOW_PCFG			0x0410			/* Register Address */
+#define	AR5K_WOW_PCFG_PAT_MATCH_EN	0x00000001	/* Pattern match enable */
+#define	AR5K_WOW_PCFG_LONG_FRAME_POL	0x00000002	/* Long frame policy */
+#define	AR5K_WOW_PCFG_WOBMISS		0x00000004	/* Wake on bea(con) miss (?) */
+#define	AR5K_WOW_PCFG_PAT_0_EN		0x00000100	/* Enable pattern 0 */
+#define	AR5K_WOW_PCFG_PAT_1_EN		0x00000200	/* Enable pattern 1 */
+#define	AR5K_WOW_PCFG_PAT_2_EN		0x00000400	/* Enable pattern 2 */
+#define	AR5K_WOW_PCFG_PAT_3_EN		0x00000800	/* Enable pattern 3 */
+#define	AR5K_WOW_PCFG_PAT_4_EN		0x00001000	/* Enable pattern 4 */
+#define	AR5K_WOW_PCFG_PAT_5_EN		0x00002000	/* Enable pattern 5 */
+
+/*
+ * Wake On Wireless pattern index register (?) [5212+]
+ */
+#define	AR5K_WOW_PAT_IDX	0x0414
+
+/*
+ * Wake On Wireless pattern data register [5212+]
+ */
+#define	AR5K_WOW_PAT_DATA	0x0418			/* Register Address */
+#define	AR5K_WOW_PAT_DATA_0_3_V	0x00000001	/* Pattern 0, 3 value */
+#define	AR5K_WOW_PAT_DATA_1_4_V	0x00000100	/* Pattern 1, 4 value */
+#define	AR5K_WOW_PAT_DATA_2_5_V	0x00010000	/* Pattern 2, 5 value */
+#define	AR5K_WOW_PAT_DATA_0_3_M	0x01000000	/* Pattern 0, 3 mask */
+#define	AR5K_WOW_PAT_DATA_1_4_M	0x04000000	/* Pattern 1, 4 mask */
+#define	AR5K_WOW_PAT_DATA_2_5_M	0x10000000	/* Pattern 2, 5 mask */
+
+/*
+ * Decompression configuration registers [5212+]
+ */
+#define AR5K_DCCFG		0x0420			/* Register Address */
+#define AR5K_DCCFG_GLOBAL_EN	0x00000001	/* Enable decompression on all queues */
+#define AR5K_DCCFG_BYPASS_EN	0x00000002	/* Bypass decompression */
+#define AR5K_DCCFG_BCAST_EN	0x00000004	/* Enable decompression for bcast frames */
+#define AR5K_DCCFG_MCAST_EN	0x00000008	/* Enable decompression for mcast frames */
+
+/*
+ * Compression configuration registers [5212+]
+ */
+#define AR5K_CCFG		0x0600			/* Register Address */
+#define	AR5K_CCFG_WINDOW_SIZE	0x00000007	/* Compression window size */
+#define	AR5K_CCFG_CPC_EN	0x00000008	/* Enable performance counters */
+
+#define AR5K_CCFG_CCU		0x0604			/* Register Address */
+#define AR5K_CCFG_CCU_CUP_EN	0x00000001	/* CCU Catchup enable */
+#define AR5K_CCFG_CCU_CREDIT	0x00000002	/* CCU Credit (field) */
+#define AR5K_CCFG_CCU_CD_THRES	0x00000080	/* CCU Cyc(lic?) debt threshold (field) */
+#define AR5K_CCFG_CCU_CUP_LCNT	0x00010000	/* CCU Catchup lit(?) count */
+#define	AR5K_CCFG_CCU_INIT	0x00100200	/* Initial value during reset */
+
+/*
+ * Compression performance counter registers [5212+]
+ */
+#define AR5K_CPC0		0x0610		/* Compression performance counter 0 */
+#define AR5K_CPC1		0x0614		/* Compression performance counter 1*/
+#define AR5K_CPC2		0x0618		/* Compression performance counter 2 */
+#define AR5K_CPC3		0x061c		/* Compression performance counter 3 */
+#define AR5K_CPCOVF		0x0620		/* Compression performance overflow */
+
+
+/*
+ * Queue control unit (QCU) registers [5211+]
+ *
+ * Card has 12 TX Queues but i see that only 0-9 are used (?)
+ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
+ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
+ * configuration register (0x08c0 - 0x08ec), a ready time configuration
+ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
+ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
+ * global registers, QCU transmit enable/disable and "one shot arm (?)"
+ * set/clear, which contain status for all queues (we shift by 1 for each
+ * queue). To access these registers easily we define some macros here
+ * that are used inside HAL. For more infos check out *_tx_queue functs.
+ */
+
+/*
+ * Generic QCU Register access macros
+ */
+#define	AR5K_QUEUE_REG(_r, _q)		(((_q) << 2) + _r)
+#define AR5K_QCU_GLOBAL_READ(_r, _q)	(AR5K_REG_READ(_r) & (1 << _q))
+#define AR5K_QCU_GLOBAL_WRITE(_r, _q)	AR5K_REG_WRITE(_r, (1 << _q))
+
+/*
+ * QCU Transmit descriptor pointer registers
+ */
+#define AR5K_QCU_TXDP_BASE	0x0800		/* Register Address - Queue0 TXDP */
+#define AR5K_QUEUE_TXDP(_q)	AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
+
+/*
+ * QCU Transmit enable register
+ */
+#define AR5K_QCU_TXE		0x0840
+#define AR5K_ENABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
+#define AR5K_QUEUE_ENABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
+
+/*
+ * QCU Transmit disable register
+ */
+#define AR5K_QCU_TXD		0x0880
+#define AR5K_DISABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
+#define AR5K_QUEUE_DISABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
+
+/*
+ * QCU Constant Bit Rate configuration registers
+ */
+#define	AR5K_QCU_CBRCFG_BASE		0x08c0	/* Register Address - Queue0 CBRCFG */
+#define	AR5K_QCU_CBRCFG_INTVAL		0x00ffffff	/* CBR Interval mask */
+#define AR5K_QCU_CBRCFG_INTVAL_S	0
+#define	AR5K_QCU_CBRCFG_ORN_THRES	0xff000000	/* CBR overrun threshold mask */
+#define AR5K_QCU_CBRCFG_ORN_THRES_S	24
+#define	AR5K_QUEUE_CBRCFG(_q)		AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
+
+/*
+ * QCU Ready time configuration registers
+ */
+#define	AR5K_QCU_RDYTIMECFG_BASE	0x0900	/* Register Address - Queue0 RDYTIMECFG */
+#define	AR5K_QCU_RDYTIMECFG_INTVAL	0x00ffffff	/* Ready time interval mask */
+#define AR5K_QCU_RDYTIMECFG_INTVAL_S	0
+#define	AR5K_QCU_RDYTIMECFG_ENABLE	0x01000000	/* Ready time enable mask */
+#define AR5K_QUEUE_RDYTIMECFG(_q)	AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
+
+/*
+ * QCU one shot arm set registers
+ */
+#define	AR5K_QCU_ONESHOTARM_SET		0x0940	/* Register Address -QCU "one shot arm set (?)" */
+#define	AR5K_QCU_ONESHOTARM_SET_M	0x0000ffff
+
+/*
+ * QCU one shot arm clear registers
+ */
+#define	AR5K_QCU_ONESHOTARM_CLEAR	0x0980	/* Register Address -QCU "one shot arm clear (?)" */
+#define	AR5K_QCU_ONESHOTARM_CLEAR_M	0x0000ffff
+
+/*
+ * QCU misc registers
+ */
+#define AR5K_QCU_MISC_BASE		0x09c0			/* Register Address -Queue0 MISC */
+#define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
+#define	AR5K_QCU_MISC_FRSHED_ASAP		0	/* ASAP */
+#define	AR5K_QCU_MISC_FRSHED_CBR		1	/* Constant Bit Rate */
+#define	AR5K_QCU_MISC_FRSHED_DBA_GT		2	/* DMA Beacon alert gated */
+#define	AR5K_QCU_MISC_FRSHED_TIM_GT		3	/* TIMT gated */
+#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated */
+#define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
+#define	AR5K_QCU_MISC_CBREXP_DIS	0x00000020	/* Disable CBR expired counter (normal queue) */
+#define	AR5K_QCU_MISC_CBREXP_BCN_DIS	0x00000040	/* Disable CBR expired counter (beacon queue) */
+#define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Enable Beacon use */
+#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR expired threshold enabled */
+#define	AR5K_QCU_MISC_RDY_VEOL_POLICY	0x00000200	/* TXE reset when RDYTIME expired or VEOL */
+#define	AR5K_QCU_MISC_CBR_RESET_CNT	0x00000400	/* CBR threshold (counter) reset */
+#define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU early termination */
+#define AR5K_QCU_MISC_DCU_CMP_EN	0x00001000	/* Enable frame compression */
+#define AR5K_QUEUE_MISC(_q)		AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
+
+
+/*
+ * QCU status registers
+ */
+#define AR5K_QCU_STS_BASE	0x0a00			/* Register Address - Queue0 STS */
+#define	AR5K_QCU_STS_FRMPENDCNT	0x00000003	/* Frames pending counter */
+#define	AR5K_QCU_STS_CBREXPCNT	0x0000ff00	/* CBR expired counter */
+#define	AR5K_QUEUE_STATUS(_q)	AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
+
+/*
+ * QCU ready time shutdown register
+ */
+#define AR5K_QCU_RDYTIMESHDN	0x0a40
+#define AR5K_QCU_RDYTIMESHDN_M	0x000003ff
+
+/*
+ * QCU compression buffer base registers [5212+]
+ */
+#define AR5K_QCU_CBB_SELECT	0x0b00
+#define AR5K_QCU_CBB_ADDR	0x0b04
+#define AR5K_QCU_CBB_ADDR_S	9
+
+/*
+ * QCU compression buffer configuration register [5212+]
+ * (buffer size)
+ */
+#define AR5K_QCU_CBCFG		0x0b08
+
+
+
+/*
+ * Distributed Coordination Function (DCF) control unit (DCU)
+ * registers [5211+]
+ *
+ * These registers control the various characteristics of each queue
+ * for 802.11e (WME) combatibility so they go together with
+ * QCU registers in pairs. For each queue we have a QCU mask register,
+ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
+ * a retry limit register (0x1080 - 0x10ac), a channel time register
+ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
+ * a sequence number register (0x1140 - 0x116c). It seems that "global"
+ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
+ * We use the same macros here for easier register access.
+ *
+ */
+
+/*
+ * DCU QCU mask registers
+ */
+#define AR5K_DCU_QCUMASK_BASE	0x1000		/* Register Address -Queue0 DCU_QCUMASK */
+#define AR5K_DCU_QCUMASK_M	0x000003ff
+#define AR5K_QUEUE_QCUMASK(_q)	AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
+
+/*
+ * DCU local Inter Frame Space settings register
+ */
+#define AR5K_DCU_LCL_IFS_BASE		0x1040			/* Register Address -Queue0 DCU_LCL_IFS */
+#define	AR5K_DCU_LCL_IFS_CW_MIN	        0x000003ff	/* Minimum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MIN_S	0
+#define	AR5K_DCU_LCL_IFS_CW_MAX	        0x000ffc00	/* Maximum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
+#define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
+#define	AR5K_DCU_LCL_IFS_AIFS_S		20
+#define	AR5K_DCU_LCL_IFS_AIFS_MAX	0xfc		/* Anything above that can cause DCU to hang */
+#define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
+
+/*
+ * DCU retry limit registers
+ */
+#define AR5K_DCU_RETRY_LMT_BASE		0x1080			/* Register Address -Queue0 DCU_RETRY_LMT */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_DCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry limit mask */
+#define AR5K_DCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S	14
+#define	AR5K_QUEUE_DFS_RETRY_LIMIT(_q)	AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
+
+/*
+ * DCU channel time registers
+ */
+#define AR5K_DCU_CHAN_TIME_BASE		0x10c0			/* Register Address -Queue0 DCU_CHAN_TIME */
+#define	AR5K_DCU_CHAN_TIME_DUR		0x000fffff	/* Channel time duration */
+#define	AR5K_DCU_CHAN_TIME_DUR_S	0
+#define	AR5K_DCU_CHAN_TIME_ENABLE	0x00100000	/* Enable channel time */
+#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)	AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
+
+/*
+ * DCU misc registers [5211+]
+ *
+ * Note: Arbiter lockout control controls the
+ * behaviour on low priority queues when we have multiple queues
+ * with pending frames. Intra-frame lockout means we wait until
+ * the queue's current frame transmits (with post frame backoff and bursting)
+ * before we transmit anything else and global lockout means we
+ * wait for the whole queue to finish before higher priority queues
+ * can transmit (this is used on beacon and CAB queues).
+ * No lockout means there is no special handling.
+ */
+#define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
+#define	AR5K_DCU_MISC_BACKOFF		0x0000003f	/* Mask for backoff threshold */
+#define	AR5K_DCU_MISC_ETS_RTS_POL	0x00000040	/* End of transmission series
+							station RTS/data failure count
+							reset policy (?) */
+#define AR5K_DCU_MISC_ETS_CW_POL	0x00000080	/* End of transmission series
+							CW reset policy */
+#define	AR5K_DCU_MISC_FRAG_WAIT		0x00000100	/* Wait for next fragment */
+#define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
+#define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll enable */
+#define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff */
+#define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch */
+#define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
+#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
+#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	1
+#define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Enable Beacon use */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_NONE		0	/* No arbiter lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM	1	/* Intra-frame lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL	2	/* Global lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_IGNORE	0x00080000	/* Ignore Arbiter lockout */
+#define	AR5K_DCU_MISC_SEQ_NUM_INCR_DIS	0x00100000	/* Disable sequence number increment */
+#define	AR5K_DCU_MISC_POST_FR_BKOFF_DIS	0x00200000	/* Disable post-frame backoff */
+#define	AR5K_DCU_MISC_VIRT_COLL_POLICY	0x00400000	/* Virtual Collision cw policy */
+#define	AR5K_DCU_MISC_BLOWN_IFS_POLICY	0x00800000	/* Blown IFS policy (?) */
+#define	AR5K_DCU_MISC_SEQNUM_CTL	0x01000000	/* Sequence number control (?) */
+#define AR5K_QUEUE_DFS_MISC(_q)		AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
+
+/*
+ * DCU frame sequence number registers
+ */
+#define AR5K_DCU_SEQNUM_BASE		0x1140
+#define	AR5K_DCU_SEQNUM_M		0x00000fff
+#define	AR5K_QUEUE_DCU_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
+
+/*
+ * DCU global IFS SIFS register
+ */
+#define AR5K_DCU_GBL_IFS_SIFS	0x1030
+#define AR5K_DCU_GBL_IFS_SIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS slot interval register
+ */
+#define AR5K_DCU_GBL_IFS_SLOT	0x1070
+#define AR5K_DCU_GBL_IFS_SLOT_M	0x0000ffff
+
+/*
+ * DCU global IFS EIFS register
+ */
+#define AR5K_DCU_GBL_IFS_EIFS	0x10b0
+#define AR5K_DCU_GBL_IFS_EIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS misc register
+ *
+ * LFSR stands for Linear Feedback Shift Register
+ * and it's used for generating pseudo-random
+ * number sequences.
+ *
+ * (If i understand corectly, random numbers are
+ * used for idle sensing -multiplied with cwmin/max etc-)
+ */
+#define AR5K_DCU_GBL_IFS_MISC			0x10f0			/* Register Address */
+#define	AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE	0x00000007	/* LFSR Slice Select */
+#define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode */
+#define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00	/* USEC Duration mask */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S	10
+#define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000	/* DCU Arbiter delay mask */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST	0x00400000	/* SIFS cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST	0x00800000	/* AIFS cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS	0x01000000	/* Disable random LFSR slice */
+
+/*
+ * DCU frame prefetch control register
+ */
+#define AR5K_DCU_FP			0x1230			/* Register Address */
+#define AR5K_DCU_FP_NOBURST_DCU_EN	0x00000001	/* Enable non-burst prefetch on DCU (?) */
+#define AR5K_DCU_FP_NOBURST_EN		0x00000010	/* Enable non-burst prefetch (?) */
+#define AR5K_DCU_FP_BURST_DCU_EN	0x00000020	/* Enable burst prefetch on DCU (?) */
+
+/*
+ * DCU transmit pause control/status register
+ */
+#define AR5K_DCU_TXP		0x1270			/* Register Address */
+#define	AR5K_DCU_TXP_M		0x000003ff	/* Tx pause mask */
+#define	AR5K_DCU_TXP_STATUS	0x00010000	/* Tx pause status */
+
+/*
+ * DCU transmit filter table 0 (32 entries)
+ * each entry contains a 32bit slice of the
+ * 128bit tx filter for each DCU (4 slices per DCU)
+ */
+#define AR5K_DCU_TX_FILTER_0_BASE	0x1038
+#define	AR5K_DCU_TX_FILTER_0(_n)	(AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
+
+/*
+ * DCU transmit filter table 1 (16 entries)
+ */
+#define AR5K_DCU_TX_FILTER_1_BASE	0x103c
+#define	AR5K_DCU_TX_FILTER_1(_n)	(AR5K_DCU_TX_FILTER_1_BASE + (_n * 64))
+
+/*
+ * DCU clear transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_CLR	0x143c
+
+/*
+ * DCU set transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_SET	0x147c
+
+/*
+ * Reset control register
+ */
+#define AR5K_RESET_CTL		0x4000			/* Register Address */
+#define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
+#define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset [5210] */
+#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset [5211+] */
+#define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
+#define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
+#define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
+
+/*
+ * Sleep control register
+ */
+#define AR5K_SLEEP_CTL			0x4004			/* Register Address */
+#define AR5K_SLEEP_CTL_SLDUR		0x0000ffff	/* Sleep duration mask */
+#define AR5K_SLEEP_CTL_SLDUR_S		0
+#define AR5K_SLEEP_CTL_SLE		0x00030000	/* Sleep enable mask */
+#define AR5K_SLEEP_CTL_SLE_S		16
+#define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
+#define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
+#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000	/* Normal sleep policy */
+#define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
+#define AR5K_SLEEP_CTL_DUR_TIM_POL	0x00040000	/* Sleep duration timing policy */
+#define AR5K_SLEEP_CTL_DUR_WRITE_POL	0x00080000	/* Sleep duration write policy */
+#define AR5K_SLEEP_CTL_SLE_POL		0x00100000	/* Sleep policy mode */
+
+/*
+ * Interrupt pending register
+ */
+#define AR5K_INTPEND	0x4008
+#define AR5K_INTPEND_M	0x00000001
+
+/*
+ * Sleep force register
+ */
+#define AR5K_SFR	0x400c
+#define AR5K_SFR_EN	0x00000001
+
+/*
+ * PCI configuration register
+ * TODO: Fix LED stuff
+ */
+#define AR5K_PCICFG			0x4010			/* Register Address */
+#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
+#define AR5K_PCICFG_SLEEP_CLOCK_EN	0x00000002	/* Enable sleep clock */
+#define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
+#define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
+#define AR5K_PCICFG_EESIZE_S		3
+#define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
+#define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
+#define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
+#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size [5211+] */
+#define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
+#define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
+#define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
+#define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
+#define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
+#define AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix */
+#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep */
+#define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
+#define AR5K_PCICFG_RETRY_FIX		0x00001000	/* Enable pci core retry fix */
+#define AR5K_PCICFG_SL_INPEN		0x00002000	/* Sleep even whith pending interrupts*/
+#define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
+#define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROM	0x00020000	/* Default mode (blink on any traffic) [5211+] */
+#define AR5K_PCICFG_LEDMODE_PWR		0x00040000	/* Some other blinking mode  (?) [5211+] */
+#define AR5K_PCICFG_LEDMODE_RAND	0x00060000	/* Random blinking (?) [5211+] */
+#define AR5K_PCICFG_LEDBLINK		0x00700000	/* Led blink rate */
+#define AR5K_PCICFG_LEDBLINK_S		20
+#define AR5K_PCICFG_LEDSLOW		0x00800000	/* Slowest led blink rate [5211+] */
+#define AR5K_PCICFG_LEDSTATE				\
+	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
+	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE	0x03000000	/* Sleep clock rate */
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE_S	24
+
+/*
+ * "General Purpose Input/Output" (GPIO) control register
+ *
+ * I'm not sure about this but after looking at the code
+ * for all chipsets here is what i got.
+ *
+ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
+ * Mode 0 -> always input
+ * Mode 1 -> output when GPIODO for this GPIO is set to 0
+ * Mode 2 -> output when GPIODO for this GPIO is set to 1
+ * Mode 3 -> always output
+ *
+ * For more infos check out get_gpio/set_gpio and
+ * set_gpio_input/set_gpio_output functs.
+ * For more infos on gpio interrupt check out set_gpio_intr.
+ */
+#define AR5K_NUM_GPIO	6
+
+#define AR5K_GPIOCR		0x4014				/* Register Address */
+#define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
+#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is low */
+#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is high */
+#define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
+#define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
+#define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
+#define AR5K_GPIOCR_OUT(n)	(3 << ((n) * 2))	/* Mode 3 for pin n */
+#define AR5K_GPIOCR_INT_SEL(n)	((n) << 12)		/* Interrupt for GPIO pin n */
+
+/*
+ * "General Purpose Input/Output" (GPIO) data output register
+ */
+#define AR5K_GPIODO	0x4018
+
+/*
+ * "General Purpose Input/Output" (GPIO) data input register
+ */
+#define AR5K_GPIODI	0x401c
+#define AR5K_GPIODI_M	0x0000002f
+
+/*
+ * Silicon revision register
+ */
+#define AR5K_SREV		0x4020			/* Register Address */
+#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
+#define AR5K_SREV_REV_S		0
+#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
+#define AR5K_SREV_VER_S		4
+
+/*
+ * TXE write posting register
+ */
+#define	AR5K_TXEPOST	0x4028
+
+/*
+ * QCU sleep mask
+ */
+#define	AR5K_QCU_SLEEP_MASK	0x402c
+
+/* 0x4068 is compression buffer configuration
+ * register on 5414 and pm configuration register
+ * on 5424 and newer pci-e chips. */
+
+/*
+ * Compression buffer configuration
+ * register (enable/disable) [5414]
+ */
+#define AR5K_5414_CBCFG		0x4068
+#define AR5K_5414_CBCFG_BUF_DIS	0x10	/* Disable buffer */
+
+/*
+ * PCI-E Power managment configuration
+ * and status register [5424+]
+ */
+#define	AR5K_PCIE_PM_CTL		0x4068			/* Register address */
+/* Only 5424 */
+#define	AR5K_PCIE_PM_CTL_L1_WHEN_D2	0x00000001	/* enable PCIe core enter L1
+							when d2_sleep_en is asserted */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_CLEAR	0x00000002	/* Clear L0 and L0S counters */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_EN	0x00000004	/* Start L0 nd L0S counters */
+#define	AR5K_PCIE_PM_CTL_LDRESET_EN	0x00000008	/* Enable reset when link goes
+							down */
+/* Wake On Wireless */
+#define	AR5K_PCIE_PM_CTL_PME_EN		0x00000010	/* PME Enable */
+#define	AR5K_PCIE_PM_CTL_AUX_PWR_DET	0x00000020	/* Aux power detect */
+#define	AR5K_PCIE_PM_CTL_PME_CLEAR	0x00000040	/* Clear PME */
+#define	AR5K_PCIE_PM_CTL_PSM_D0		0x00000080
+#define	AR5K_PCIE_PM_CTL_PSM_D1		0x00000100
+#define	AR5K_PCIE_PM_CTL_PSM_D2		0x00000200
+#define	AR5K_PCIE_PM_CTL_PSM_D3		0x00000400
+
+/*
+ * PCI-E Workaround enable register
+ */
+#define	AR5K_PCIE_WAEN	0x407c
+
+/*
+ * PCI-E Serializer/Desirializer
+ * registers
+ */
+#define	AR5K_PCIE_SERDES	0x4080
+#define	AR5K_PCIE_SERDES_RESET	0x4084
+
+/*====EEPROM REGISTERS====*/
+
+/*
+ * EEPROM access registers
+ *
+ * Here we got a difference between 5210/5211-12
+ * read data register for 5210 is at 0x6800 and
+ * status register is at 0x6c00. There is also
+ * no eeprom command register on 5210 and the
+ * offsets are different.
+ *
+ * To read eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        read AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * 5211 - write offset to AR5K_EEPROM_BASE
+ * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * To write eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        write data to AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
+ * 5212   write offset to AR5K_EEPROM_BASE
+ *        write data to data register
+ *	  write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *
+ * For more infos check eeprom_* functs and the ar5k.c
+ * file posted in madwifi-devel mailing list.
+ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
+ *
+ */
+#define AR5K_EEPROM_BASE	0x6000
+
+/*
+ * EEPROM data register
+ */
+#define AR5K_EEPROM_DATA_5211	0x6004
+#define AR5K_EEPROM_DATA_5210	0x6800
+#define	AR5K_EEPROM_DATA	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+
+/*
+ * EEPROM command register
+ */
+#define AR5K_EEPROM_CMD		0x6008			/* Register Addres */
+#define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
+#define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
+#define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
+
+/*
+ * EEPROM status register
+ */
+#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
+#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
+#define	AR5K_EEPROM_STATUS	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+#define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
+#define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
+#define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
+#define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
+
+/*
+ * EEPROM config register
+ */
+#define AR5K_EEPROM_CFG			0x6010			/* Register Addres */
+#define AR5K_EEPROM_CFG_SIZE		0x00000003		/* Size determination override */
+#define AR5K_EEPROM_CFG_SIZE_AUTO	0
+#define AR5K_EEPROM_CFG_SIZE_4KBIT	1
+#define AR5K_EEPROM_CFG_SIZE_8KBIT	2
+#define AR5K_EEPROM_CFG_SIZE_16KBIT	3
+#define AR5K_EEPROM_CFG_WR_WAIT_DIS	0x00000004	/* Disable write wait */
+#define AR5K_EEPROM_CFG_CLK_RATE	0x00000018	/* Clock rate */
+#define AR5K_EEPROM_CFG_CLK_RATE_S		3
+#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ	0
+#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ	1
+#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ	2
+#define AR5K_EEPROM_CFG_PROT_KEY	0x00ffff00      /* Protection key */
+#define AR5K_EEPROM_CFG_PROT_KEY_S	8
+#define AR5K_EEPROM_CFG_LIND_EN		0x01000000	/* Enable length indicator (?) */
+
+
+/*
+ * TODO: Wake On Wireless registers
+ * Range 0x7000 - 0x7ce0
+ */
+
+/*
+ * Protocol Control Unit (PCU) registers
+ */
+/*
+ * Used for checking initial register writes
+ * during channel reset (see reset func)
+ */
+#define AR5K_PCU_MIN	0x8000
+#define AR5K_PCU_MAX	0x8fff
+
+/*
+ * First station id register (Lower 32 bits of MAC address)
+ */
+#define AR5K_STA_ID0		0x8000
+#define	AR5K_STA_ID0_ARRD_L32	0xffffffff
+
+/*
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
+ */
+#define AR5K_STA_ID1			0x8004			/* Register Address */
+#define	AR5K_STA_ID1_ADDR_U16		0x0000ffff	/* Upper 16 bits of MAC addres */
+#define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
+#define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
+#define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting */
+#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000	/* No key search */
+#define AR5K_STA_ID1_NO_PSPOLL		0x00100000	/* No power save polling [5210] */
+#define AR5K_STA_ID1_PCF_5211		0x00100000	/* Enable PCF on [5211+] */
+#define AR5K_STA_ID1_PCF_5210		0x00200000	/* Enable PCF on [5210]*/
+#define	AR5K_STA_ID1_PCF		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
+#define AR5K_STA_ID1_DEFAULT_ANTENNA	0x00200000	/* Use default antenna */
+#define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
+#define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS */
+#define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS */
+#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate for ACK/CTS [5211+] */
+#define AR5K_STA_ID1_SELFGEN_DEF_ANT	0x04000000	/* Use def. antenna for self generated frames */
+#define AR5K_STA_ID1_CRYPT_MIC_EN	0x08000000	/* Enable MIC */
+#define AR5K_STA_ID1_KEYSRCH_MODE	0x10000000	/* Look up key when key id != 0 */
+#define AR5K_STA_ID1_PRESERVE_SEQ_NUM	0x20000000	/* Preserve sequence number */
+#define AR5K_STA_ID1_CBCIV_ENDIAN	0x40000000	/* ??? */
+#define AR5K_STA_ID1_KEYSRCH_MCAST	0x80000000	/* Do key cache search for mcast frames */
+
+/*
+ * First BSSID register (MAC address, lower 32bits)
+ */
+#define AR5K_BSS_ID0	0x8008
+
+/*
+ * Second BSSID register (MAC address in upper 16 bits)
+ *
+ * AID: Association ID
+ */
+#define AR5K_BSS_ID1		0x800c
+#define AR5K_BSS_ID1_AID	0xffff0000
+#define AR5K_BSS_ID1_AID_S	16
+
+/*
+ * Backoff slot time register
+ */
+#define AR5K_SLOT_TIME	0x8010
+
+/*
+ * ACK/CTS timeout register
+ */
+#define AR5K_TIME_OUT		0x8014			/* Register Address */
+#define AR5K_TIME_OUT_ACK	0x00001fff	/* ACK timeout mask */
+#define AR5K_TIME_OUT_ACK_S	0
+#define AR5K_TIME_OUT_CTS	0x1fff0000	/* CTS timeout mask */
+#define AR5K_TIME_OUT_CTS_S	16
+
+/*
+ * RSSI threshold register
+ */
+#define AR5K_RSSI_THR			0x8018		/* Register Address */
+#define AR5K_RSSI_THR_M			0x000000ff	/* Mask for RSSI threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5210	0x00000700	/* Mask for Beacon Missed threshold [5210] */
+#define AR5K_RSSI_THR_BMISS_5210_S	8
+#define AR5K_RSSI_THR_BMISS_5211	0x0000ff00	/* Mask for Beacon Missed threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5211_S	8
+#define	AR5K_RSSI_THR_BMISS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
+#define	AR5K_RSSI_THR_BMISS_S		8
+
+/*
+ * 5210 has more PCU registers because there is no QCU/DCU
+ * so queue parameters are set here, this way a lot common
+ * registers have different address for 5210. To make things
+ * easier we define a macro based on ah->ah_version for common
+ * registers with different addresses and common flags.
+ */
+
+/*
+ * Retry limit register
+ *
+ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
+ */
+#define AR5K_NODCU_RETRY_LMT		0x801c			/* Register Address */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry mask */
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S	14
+#define AR5K_NODCU_RETRY_LMT_CW_MIN	0x3ff00000	/* Minimum contention window mask */
+#define AR5K_NODCU_RETRY_LMT_CW_MIN_S	20
+
+/*
+ * Transmit latency register
+ */
+#define AR5K_USEC_5210			0x8020			/* Register Address [5210] */
+#define AR5K_USEC_5211			0x801c			/* Register Address [5211+] */
+#define AR5K_USEC			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_USEC_5210 : AR5K_USEC_5211)
+#define AR5K_USEC_1			0x0000007f	/* clock cycles for 1us */
+#define AR5K_USEC_1_S			0
+#define AR5K_USEC_32			0x00003f80	/* clock cycles for 1us while on 32Mhz clock */
+#define AR5K_USEC_32_S			7
+#define AR5K_USEC_TX_LATENCY_5211	0x007fc000
+#define AR5K_USEC_TX_LATENCY_5211_S	14
+#define AR5K_USEC_RX_LATENCY_5211	0x1f800000
+#define AR5K_USEC_RX_LATENCY_5211_S	23
+#define AR5K_USEC_TX_LATENCY_5210	0x000fc000	/* also for 5311 */
+#define AR5K_USEC_TX_LATENCY_5210_S	14
+#define AR5K_USEC_RX_LATENCY_5210	0x03f00000	/* also for 5311 */
+#define AR5K_USEC_RX_LATENCY_5210_S	20
+
+/*
+ * PCU beacon control register
+ */
+#define AR5K_BEACON_5210	0x8024			/*Register Address [5210] */
+#define AR5K_BEACON_5211	0x8020			/*Register Address [5211+] */
+#define AR5K_BEACON		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_5210 : AR5K_BEACON_5211)
+#define AR5K_BEACON_PERIOD	0x0000ffff	/* Mask for beacon period */
+#define AR5K_BEACON_PERIOD_S	0
+#define AR5K_BEACON_TIM		0x007f0000	/* Mask for TIM offset */
+#define AR5K_BEACON_TIM_S	16
+#define AR5K_BEACON_ENABLE	0x00800000	/* Enable beacons */
+#define AR5K_BEACON_RESET_TSF	0x01000000	/* Force TSF reset */
+
+/*
+ * CFP period register
+ */
+#define AR5K_CFP_PERIOD_5210	0x8028
+#define AR5K_CFP_PERIOD_5211	0x8024
+#define AR5K_CFP_PERIOD		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
+
+/*
+ * Next beacon time register
+ */
+#define AR5K_TIMER0_5210	0x802c
+#define AR5K_TIMER0_5211	0x8028
+#define AR5K_TIMER0		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
+
+/*
+ * Next DMA beacon alert register
+ */
+#define AR5K_TIMER1_5210	0x8030
+#define AR5K_TIMER1_5211	0x802c
+#define AR5K_TIMER1		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
+
+/*
+ * Next software beacon alert register
+ */
+#define AR5K_TIMER2_5210	0x8034
+#define AR5K_TIMER2_5211	0x8030
+#define AR5K_TIMER2		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
+
+/*
+ * Next ATIM window time register
+ */
+#define AR5K_TIMER3_5210	0x8038
+#define AR5K_TIMER3_5211	0x8034
+#define AR5K_TIMER3		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
+
+
+/*
+ * 5210 First inter frame spacing register (IFS)
+ */
+#define AR5K_IFS0		0x8040
+#define AR5K_IFS0_SIFS		0x000007ff
+#define AR5K_IFS0_SIFS_S	0
+#define AR5K_IFS0_DIFS		0x007ff800
+#define AR5K_IFS0_DIFS_S	11
+
+/*
+ * 5210 Second inter frame spacing register (IFS)
+ */
+#define AR5K_IFS1		0x8044
+#define AR5K_IFS1_PIFS		0x00000fff
+#define AR5K_IFS1_PIFS_S	0
+#define AR5K_IFS1_EIFS		0x03fff000
+#define AR5K_IFS1_EIFS_S	12
+#define AR5K_IFS1_CS_EN		0x04000000
+
+
+/*
+ * CFP duration register
+ */
+#define AR5K_CFP_DUR_5210	0x8048
+#define AR5K_CFP_DUR_5211	0x8038
+#define AR5K_CFP_DUR		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
+
+/*
+ * Receive filter register
+ */
+#define AR5K_RX_FILTER_5210	0x804c			/* Register Address [5210] */
+#define AR5K_RX_FILTER_5211	0x803c			/* Register Address [5211+] */
+#define AR5K_RX_FILTER		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
+#define	AR5K_RX_FILTER_UCAST 	0x00000001	/* Don't filter unicast frames */
+#define	AR5K_RX_FILTER_MCAST 	0x00000002	/* Don't filter multicast frames */
+#define	AR5K_RX_FILTER_BCAST 	0x00000004	/* Don't filter broadcast frames */
+#define	AR5K_RX_FILTER_CONTROL 	0x00000008	/* Don't filter control frames */
+#define	AR5K_RX_FILTER_BEACON 	0x00000010	/* Don't filter beacon frames */
+#define	AR5K_RX_FILTER_PROM 	0x00000020	/* Set promiscuous mode */
+#define	AR5K_RX_FILTER_XRPOLL 	0x00000040	/* Don't filter XR poll frame [5212+] */
+#define	AR5K_RX_FILTER_PROBEREQ 0x00000080	/* Don't filter probe requests [5212+] */
+#define	AR5K_RX_FILTER_PHYERR_5212	0x00000100	/* Don't filter phy errors [5212+] */
+#define	AR5K_RX_FILTER_RADARERR_5212 	0x00000200	/* Don't filter phy radar errors [5212+] */
+#define AR5K_RX_FILTER_PHYERR_5211	0x00000040	/* [5211] */
+#define AR5K_RX_FILTER_RADARERR_5211	0x00000080	/* [5211] */
+#define AR5K_RX_FILTER_PHYERR  \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
+#define        AR5K_RX_FILTER_RADARERR \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
+
+/*
+ * Multicast filter register (lower 32 bits)
+ */
+#define AR5K_MCAST_FILTER0_5210	0x8050
+#define AR5K_MCAST_FILTER0_5211	0x8040
+#define AR5K_MCAST_FILTER0	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
+
+/*
+ * Multicast filter register (higher 16 bits)
+ */
+#define AR5K_MCAST_FILTER1_5210	0x8054
+#define AR5K_MCAST_FILTER1_5211	0x8044
+#define AR5K_MCAST_FILTER1	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
+
+
+/*
+ * Transmit mask register (lower 32 bits) [5210]
+ */
+#define AR5K_TX_MASK0	0x8058
+
+/*
+ * Transmit mask register (higher 16 bits) [5210]
+ */
+#define AR5K_TX_MASK1	0x805c
+
+/*
+ * Clear transmit mask [5210]
+ */
+#define AR5K_CLR_TMASK	0x8060
+
+/*
+ * Trigger level register (before transmission) [5210]
+ */
+#define AR5K_TRIG_LVL	0x8064
+
+
+/*
+ * PCU control register
+ *
+ * Only DIS_RX is used in the code, the rest i guess are
+ * for tweaking/diagnostics.
+ */
+#define AR5K_DIAG_SW_5210		0x8068			/* Register Address [5210] */
+#define AR5K_DIAG_SW_5211		0x8048			/* Register Address [5211+] */
+#define AR5K_DIAG_SW			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
+#define AR5K_DIAG_SW_DIS_WEP_ACK	0x00000001	/* Disable ACKs if WEP key is invalid */
+#define AR5K_DIAG_SW_DIS_ACK		0x00000002	/* Disable ACKs */
+#define AR5K_DIAG_SW_DIS_CTS		0x00000004	/* Disable CTSs */
+#define AR5K_DIAG_SW_DIS_ENC		0x00000008	/* Disable encryption */
+#define AR5K_DIAG_SW_DIS_DEC		0x00000010	/* Disable decryption */
+#define AR5K_DIAG_SW_DIS_TX		0x00000020	/* Disable transmit [5210] */
+#define AR5K_DIAG_SW_DIS_RX_5210	0x00000040	/* Disable recieve */
+#define AR5K_DIAG_SW_DIS_RX_5211	0x00000020
+#define	AR5K_DIAG_SW_DIS_RX		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
+#define AR5K_DIAG_SW_LOOP_BACK_5210	0x00000080	/* Loopback (i guess it goes with DIS_TX) [5210] */
+#define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
+#define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
+#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100	/* Corrupted FCS */
+#define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
+#define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
+#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200	/* Dump channel info */
+#define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
+#define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400	/* Enable fixed scrambler seed */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200
+#define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
+#define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
+#define AR5K_DIAG_SW_SCVRAM_SEED	0x0003f800	/* [5210] */
+#define AR5K_DIAG_SW_SCRAM_SEED_M	0x0001fc00	/* Scrambler seed mask */
+#define AR5K_DIAG_SW_SCRAM_SEED_S	10
+#define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
+#define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
+#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000	/* Accept frames of non-zero protocol number */
+#define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
+#define AR5K_DIAG_SW_OBSPT_M		0x000c0000	/* Observation point select (?) */
+#define AR5K_DIAG_SW_OBSPT_S		18
+#define AR5K_DIAG_SW_RX_CLEAR_HIGH	0x0010000	/* Force RX Clear high */
+#define AR5K_DIAG_SW_IGNORE_CARR_SENSE	0x0020000	/* Ignore virtual carrier sense */
+#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH	0x0040000	/* Force channel idle high */
+#define AR5K_DIAG_SW_PHEAR_ME		0x0080000	/* ??? */
+
+/*
+ * TSF (clock) register (lower 32 bits)
+ */
+#define AR5K_TSF_L32_5210	0x806c
+#define AR5K_TSF_L32_5211	0x804c
+#define	AR5K_TSF_L32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
+
+/*
+ * TSF (clock) register (higher 32 bits)
+ */
+#define AR5K_TSF_U32_5210	0x8070
+#define AR5K_TSF_U32_5211	0x8050
+#define	AR5K_TSF_U32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
+
+/*
+ * Last beacon timestamp register (Read Only)
+ */
+#define AR5K_LAST_TSTP	0x8080
+
+/*
+ * ADDAC test register [5211+]
+ */
+#define AR5K_ADDAC_TEST			0x8054			/* Register Address */
+#define AR5K_ADDAC_TEST_TXCONT 		0x00000001	/* Test continuous tx */
+#define AR5K_ADDAC_TEST_TST_MODE	0x00000002	/* Test mode */
+#define AR5K_ADDAC_TEST_LOOP_EN		0x00000004	/* Enable loop */
+#define AR5K_ADDAC_TEST_LOOP_LEN	0x00000008	/* Loop length (field) */
+#define AR5K_ADDAC_TEST_USE_U8		0x00004000	/* Use upper 8 bits */
+#define AR5K_ADDAC_TEST_MSB		0x00008000	/* State of MSB */
+#define AR5K_ADDAC_TEST_TRIG_SEL	0x00010000	/* Trigger select */
+#define AR5K_ADDAC_TEST_TRIG_PTY	0x00020000	/* Trigger polarity */
+#define AR5K_ADDAC_TEST_RXCONT		0x00040000	/* Continuous capture */
+#define AR5K_ADDAC_TEST_CAPTURE		0x00080000	/* Begin capture */
+#define AR5K_ADDAC_TEST_TST_ARM		0x00100000	/* ARM rx buffer for capture */
+
+/*
+ * Default antenna register [5211+]
+ */
+#define AR5K_DEFAULT_ANTENNA	0x8058
+
+/*
+ * Frame control QoS mask register (?) [5211+]
+ * (FC_QOS_MASK)
+ */
+#define AR5K_FRAME_CTL_QOSM	0x805c
+
+/*
+ * Seq mask register (?) [5211+]
+ */
+#define AR5K_SEQ_MASK	0x8060
+
+/*
+ * Retry count register [5210]
+ */
+#define AR5K_RETRY_CNT		0x8084			/* Register Address [5210] */
+#define AR5K_RETRY_CNT_SSH	0x0000003f	/* Station short retry count (?) */
+#define AR5K_RETRY_CNT_SLG	0x00000fc0	/* Station long retry count (?) */
+
+/*
+ * Back-off status register [5210]
+ */
+#define AR5K_BACKOFF		0x8088			/* Register Address [5210] */
+#define AR5K_BACKOFF_CW		0x000003ff	/* Backoff Contention Window (?) */
+#define AR5K_BACKOFF_CNT	0x03ff0000	/* Backoff count (?) */
+
+
+
+/*
+ * NAV register (current)
+ */
+#define AR5K_NAV_5210		0x808c
+#define AR5K_NAV_5211		0x8084
+#define	AR5K_NAV		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_NAV_5210 : AR5K_NAV_5211)
+
+/*
+ * RTS success register
+ */
+#define AR5K_RTS_OK_5210	0x8090
+#define AR5K_RTS_OK_5211	0x8088
+#define	AR5K_RTS_OK		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
+
+/*
+ * RTS failure register
+ */
+#define AR5K_RTS_FAIL_5210	0x8094
+#define AR5K_RTS_FAIL_5211	0x808c
+#define	AR5K_RTS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
+
+/*
+ * ACK failure register
+ */
+#define AR5K_ACK_FAIL_5210	0x8098
+#define AR5K_ACK_FAIL_5211	0x8090
+#define	AR5K_ACK_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
+
+/*
+ * FCS failure register
+ */
+#define AR5K_FCS_FAIL_5210	0x809c
+#define AR5K_FCS_FAIL_5211	0x8094
+#define	AR5K_FCS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
+
+/*
+ * Beacon count register
+ */
+#define AR5K_BEACON_CNT_5210	0x80a0
+#define AR5K_BEACON_CNT_5211	0x8098
+#define	AR5K_BEACON_CNT		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
+
+
+/*===5212 Specific PCU registers===*/
+
+/*
+ * Transmit power control register
+ */
+#define AR5K_TPC			0x80e8
+#define AR5K_TPC_ACK			0x0000003f	/* ack frames */
+#define AR5K_TPC_ACK_S			0
+#define AR5K_TPC_CTS			0x00003f00	/* cts frames */
+#define AR5K_TPC_CTS_S			8
+#define AR5K_TPC_CHIRP			0x003f0000	/* chirp frames */
+#define AR5K_TPC_CHIRP_S		16
+#define AR5K_TPC_DOPPLER		0x0f000000	/* doppler chirp span */
+#define AR5K_TPC_DOPPLER_S		24
+
+/*
+ * XR (eXtended Range) mode register
+ */
+#define AR5K_XRMODE			0x80c0			/* Register Address */
+#define	AR5K_XRMODE_POLL_TYPE_M		0x0000003f	/* Mask for Poll type (?) */
+#define	AR5K_XRMODE_POLL_TYPE_S		0
+#define	AR5K_XRMODE_POLL_SUBTYPE_M	0x0000003c	/* Mask for Poll subtype (?) */
+#define	AR5K_XRMODE_POLL_SUBTYPE_S	2
+#define	AR5K_XRMODE_POLL_WAIT_ALL	0x00000080	/* Wait for poll */
+#define	AR5K_XRMODE_SIFS_DELAY		0x000fff00	/* Mask for SIFS delay */
+#define	AR5K_XRMODE_FRAME_HOLD_M	0xfff00000	/* Mask for frame hold (?) */
+#define	AR5K_XRMODE_FRAME_HOLD_S	20
+
+/*
+ * XR delay register
+ */
+#define AR5K_XRDELAY			0x80c4			/* Register Address */
+#define AR5K_XRDELAY_SLOT_DELAY_M	0x0000ffff	/* Mask for slot delay */
+#define AR5K_XRDELAY_SLOT_DELAY_S	0
+#define AR5K_XRDELAY_CHIRP_DELAY_M	0xffff0000	/* Mask for CHIRP data delay */
+#define AR5K_XRDELAY_CHIRP_DELAY_S	16
+
+/*
+ * XR timeout register
+ */
+#define AR5K_XRTIMEOUT			0x80c8			/* Register Address */
+#define AR5K_XRTIMEOUT_CHIRP_M		0x0000ffff	/* Mask for CHIRP timeout */
+#define AR5K_XRTIMEOUT_CHIRP_S		0
+#define AR5K_XRTIMEOUT_POLL_M		0xffff0000	/* Mask for Poll timeout */
+#define AR5K_XRTIMEOUT_POLL_S		16
+
+/*
+ * XR chirp register
+ */
+#define AR5K_XRCHIRP			0x80cc			/* Register Address */
+#define AR5K_XRCHIRP_SEND		0x00000001	/* Send CHIRP */
+#define AR5K_XRCHIRP_GAP		0xffff0000	/* Mask for CHIRP gap (?) */
+
+/*
+ * XR stomp register
+ */
+#define AR5K_XRSTOMP			0x80d0			/* Register Address */
+#define AR5K_XRSTOMP_TX			0x00000001	/* Stomp Tx (?) */
+#define AR5K_XRSTOMP_RX			0x00000002	/* Stomp Rx (?) */
+#define AR5K_XRSTOMP_TX_RSSI		0x00000004	/* Stomp Tx RSSI (?) */
+#define AR5K_XRSTOMP_TX_BSSID		0x00000008	/* Stomp Tx BSSID (?) */
+#define AR5K_XRSTOMP_DATA		0x00000010	/* Stomp data (?)*/
+#define AR5K_XRSTOMP_RSSI_THRES		0x0000ff00	/* Mask for XR RSSI threshold */
+
+/*
+ * First enhanced sleep register
+ */
+#define AR5K_SLEEP0			0x80d4			/* Register Address */
+#define AR5K_SLEEP0_NEXT_DTIM		0x0007ffff	/* Mask for next DTIM (?) */
+#define AR5K_SLEEP0_NEXT_DTIM_S		0
+#define AR5K_SLEEP0_ASSUME_DTIM		0x00080000	/* Assume DTIM */
+#define AR5K_SLEEP0_ENH_SLEEP_EN	0x00100000	/* Enable enchanced sleep control */
+#define AR5K_SLEEP0_CABTO		0xff000000	/* Mask for CAB Time Out */
+#define AR5K_SLEEP0_CABTO_S		24
+
+/*
+ * Second enhanced sleep register
+ */
+#define AR5K_SLEEP1			0x80d8			/* Register Address */
+#define AR5K_SLEEP1_NEXT_TIM		0x0007ffff	/* Mask for next TIM (?) */
+#define AR5K_SLEEP1_NEXT_TIM_S		0
+#define AR5K_SLEEP1_BEACON_TO		0xff000000	/* Mask for Beacon Time Out */
+#define AR5K_SLEEP1_BEACON_TO_S		24
+
+/*
+ * Third enhanced sleep register
+ */
+#define AR5K_SLEEP2			0x80dc			/* Register Address */
+#define AR5K_SLEEP2_TIM_PER		0x0000ffff	/* Mask for TIM period (?) */
+#define AR5K_SLEEP2_TIM_PER_S		0
+#define AR5K_SLEEP2_DTIM_PER		0xffff0000	/* Mask for DTIM period (?) */
+#define AR5K_SLEEP2_DTIM_PER_S		16
+
+/*
+ * BSSID mask registers
+ */
+#define AR5K_BSS_IDM0			0x80e0	/* Upper bits */
+#define AR5K_BSS_IDM1			0x80e4	/* Lower bits */
+
+/*
+ * TX power control (TPC) register
+ *
+ * XXX: PCDAC steps (0.5dbm) or DBM ?
+ *
+ */
+#define AR5K_TXPC			0x80e8			/* Register Address */
+#define AR5K_TXPC_ACK_M			0x0000003f	/* ACK tx power */
+#define AR5K_TXPC_ACK_S			0
+#define AR5K_TXPC_CTS_M			0x00003f00	/* CTS tx power */
+#define AR5K_TXPC_CTS_S			8
+#define AR5K_TXPC_CHIRP_M		0x003f0000	/* CHIRP tx power */
+#define AR5K_TXPC_CHIRP_S		16
+#define AR5K_TXPC_DOPPLER		0x0f000000	/* Doppler chirp span (?) */
+#define AR5K_TXPC_DOPPLER_S		24
+
+/*
+ * Profile count registers
+ */
+#define AR5K_PROFCNT_TX			0x80ec	/* Tx count */
+#define AR5K_PROFCNT_RX			0x80f0	/* Rx count */
+#define AR5K_PROFCNT_RXCLR		0x80f4	/* Clear Rx count */
+#define AR5K_PROFCNT_CYCLE		0x80f8	/* Cycle count (?) */
+
+/*
+ * Quiet period control registers
+ */
+#define AR5K_QUIET_CTL1			0x80fc			/* Register Address */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF	0x0000ffff	/* Next quiet period TSF (TU) */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S	0
+#define AR5K_QUIET_CTL1_QT_EN		0x00010000	/* Enable quiet period */
+#define AR5K_QUIET_CTL1_ACK_CTS_EN	0x00020000	/* Send ACK/CTS during quiet period */
+
+#define AR5K_QUIET_CTL2			0x8100			/* Register Address */
+#define AR5K_QUIET_CTL2_QT_PER		0x0000ffff	/* Mask for quiet period periodicity */
+#define AR5K_QUIET_CTL2_QT_PER_S	0
+#define AR5K_QUIET_CTL2_QT_DUR		0xffff0000	/* Mask for quiet period duration */
+#define AR5K_QUIET_CTL2_QT_DUR_S	16
+
+/*
+ * TSF parameter register
+ */
+#define AR5K_TSF_PARM			0x8104			/* Register Address */
+#define AR5K_TSF_PARM_INC		0x000000ff	/* Mask for TSF increment */
+#define AR5K_TSF_PARM_INC_S		0
+
+/*
+ * QoS NOACK policy
+ */
+#define AR5K_QOS_NOACK			0x8108			/* Register Address */
+#define AR5K_QOS_NOACK_2BIT_VALUES	0x0000000f	/* ??? */
+#define AR5K_QOS_NOACK_2BIT_VALUES_S	0
+#define AR5K_QOS_NOACK_BIT_OFFSET	0x00000070	/* ??? */
+#define AR5K_QOS_NOACK_BIT_OFFSET_S	4
+#define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000180	/* ??? */
+#define AR5K_QOS_NOACK_BYTE_OFFSET_S	7
+
+/*
+ * PHY error filter register
+ */
+#define AR5K_PHY_ERR_FIL		0x810c
+#define AR5K_PHY_ERR_FIL_RADAR		0x00000020	/* Radar signal */
+#define AR5K_PHY_ERR_FIL_OFDM		0x00020000	/* OFDM false detect (ANI) */
+#define AR5K_PHY_ERR_FIL_CCK		0x02000000	/* CCK false detect (ANI) */
+
+/*
+ * XR latency register
+ */
+#define AR5K_XRLAT_TX		0x8110
+
+/*
+ * ACK SIFS register
+ */
+#define AR5K_ACKSIFS		0x8114			/* Register Address */
+#define AR5K_ACKSIFS_INC	0x00000000	/* ACK SIFS Increment (field) */
+
+/*
+ * MIC QoS control register (?)
+ */
+#define	AR5K_MIC_QOS_CTL		0x8118			/* Register Address */
+#define	AR5K_MIC_QOS_CTL_OFF(_n)	(1 << (_n * 2))
+#define	AR5K_MIC_QOS_CTL_MQ_EN		0x00010000	/* Enable MIC QoS */
+
+/*
+ * MIC QoS select register (?)
+ */
+#define	AR5K_MIC_QOS_SEL		0x811c
+#define	AR5K_MIC_QOS_SEL_OFF(_n)	(1 << (_n * 4))
+
+/*
+ * Misc mode control register (?)
+ */
+#define	AR5K_MISC_MODE			0x8120			/* Register Address */
+#define	AR5K_MISC_MODE_FBSSID_MATCH	0x00000001	/* Force BSSID match */
+#define	AR5K_MISC_MODE_ACKSIFS_MEM	0x00000002	/* ACK SIFS memory (?) */
+#define	AR5K_MISC_MODE_COMBINED_MIC	0x00000004	/* use rx/tx MIC key */
+/* more bits */
+
+/*
+ * OFDM Filter counter
+ */
+#define	AR5K_OFDM_FIL_CNT		0x8124
+
+/*
+ * CCK Filter counter
+ */
+#define	AR5K_CCK_FIL_CNT		0x8128
+
+/*
+ * PHY Error Counters (?)
+ */
+#define	AR5K_PHYERR_CNT1		0x812c
+#define	AR5K_PHYERR_CNT1_MASK		0x8130
+
+#define	AR5K_PHYERR_CNT2		0x8134
+#define	AR5K_PHYERR_CNT2_MASK		0x8138
+
+/*
+ * TSF Threshold register (?)
+ */
+#define	AR5K_TSF_THRES			0x813c
+
+/*
+ * TODO: Wake On Wireless registers
+ * Range: 0x8147 - 0x818c
+ */
+
+/*
+ * Rate -> ACK SIFS mapping table (32 entries)
+ */
+#define	AR5K_RATE_ACKSIFS_BASE		0x8680			/* Register Address */
+#define	AR5K_RATE_ACKSIFS(_n)		(AR5K_RATE_ACKSIFS_BSE + ((_n) << 2))
+#define	AR5K_RATE_ACKSIFS_NORMAL	0x00000001	/* Normal SIFS (field) */
+#define	AR5K_RATE_ACKSIFS_TURBO		0x00000400	/* Turbo SIFS (field) */
+
+/*
+ * Rate -> duration mapping table (32 entries)
+ */
+#define AR5K_RATE_DUR_BASE		0x8700
+#define AR5K_RATE_DUR(_n)		(AR5K_RATE_DUR_BASE + ((_n) << 2))
+
+/*
+ * Rate -> db mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_RATE2DB_BASE		0x87c0
+#define AR5K_RATE2DB(_n)		(AR5K_RATE2DB_BASE + ((_n) << 2))
+
+/*
+ * db -> Rate mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_DB2RATE_BASE		0x87e0
+#define AR5K_DB2RATE(_n)		(AR5K_DB2RATE_BASE + ((_n) << 2))
+
+/*===5212 end===*/
+
+/*
+ * Key table (WEP) register
+ */
+#define AR5K_KEYTABLE_0_5210		0x9000
+#define AR5K_KEYTABLE_0_5211		0x8800
+#define AR5K_KEYTABLE_5210(_n)		(AR5K_KEYTABLE_0_5210 + ((_n) << 5))
+#define AR5K_KEYTABLE_5211(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
+#define	AR5K_KEYTABLE(_n)		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
+#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + (x << 2))
+#define AR5K_KEYTABLE_TYPE(_n)		AR5K_KEYTABLE_OFF(_n, 5)
+#define AR5K_KEYTABLE_TYPE_40		0x00000000
+#define AR5K_KEYTABLE_TYPE_104		0x00000001
+#define AR5K_KEYTABLE_TYPE_128		0x00000003
+#define AR5K_KEYTABLE_TYPE_TKIP		0x00000004	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_AES		0x00000005	/* [5211+] */
+#define AR5K_KEYTABLE_TYPE_CCM		0x00000006	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_NULL		0x00000007	/* [5211+] */
+#define AR5K_KEYTABLE_ANTENNA		0x00000008	/* [5212+] */
+#define AR5K_KEYTABLE_MAC0(_n)		AR5K_KEYTABLE_OFF(_n, 6)
+#define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
+#define AR5K_KEYTABLE_VALID		0x00008000
+
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define	AR5K_KEYTABLE_MIC_OFFSET	64
+
+/* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
+ * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
+ * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
+ *
+ * Some vendors have introduced bigger WEP keys to address
+ * security vulnerabilities in WEP. This includes:
+ *
+ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
+ *
+ * We can expand this if we find ar5k Atheros cards with a larger
+ * key table size.
+ */
+#define AR5K_KEYTABLE_SIZE_5210		64
+#define AR5K_KEYTABLE_SIZE_5211		128
+#define	AR5K_KEYTABLE_SIZE		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
+
+
+/*===PHY REGISTERS===*/
+
+/*
+ * PHY registers start
+ */
+#define	AR5K_PHY_BASE			0x9800
+#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
+
+/*
+ * TST_2 (Misc config parameters)
+ */
+#define	AR5K_PHY_TST2			0x9800			/* Register Address */
+#define AR5K_PHY_TST2_TRIG_SEL		0x00000007	/* Trigger select (?)*/
+#define AR5K_PHY_TST2_TRIG		0x00000010	/* Trigger (?) */
+#define AR5K_PHY_TST2_CBUS_MODE		0x00000060	/* Cardbus mode (?) */
+#define AR5K_PHY_TST2_CLK32		0x00000400	/* CLK_OUT is CLK32 (32Khz external) */
+#define AR5K_PHY_TST2_CHANCOR_DUMP_EN	0x00000800	/* Enable Chancor dump (?) */
+#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP	0x00001000	/* Even Chancor dump (?) */
+#define AR5K_PHY_TST2_RFSILENT_EN	0x00002000	/* Enable RFSILENT */
+#define AR5K_PHY_TST2_ALT_RFDATA	0x00004000	/* Alternate RFDATA (5-2GHz switch ?) */
+#define AR5K_PHY_TST2_MINI_OBS_EN	0x00008000	/* Enable mini OBS (?) */
+#define AR5K_PHY_TST2_RX2_IS_RX5_INV	0x00010000	/* 2GHz rx path is the 5GHz path inverted (?) */
+#define AR5K_PHY_TST2_SLOW_CLK160	0x00020000	/* Slow CLK160 (?) */
+#define AR5K_PHY_TST2_AGC_OBS_SEL_3	0x00040000	/* AGC OBS Select 3 (?) */
+#define AR5K_PHY_TST2_BBB_OBS_SEL	0x00080000	/* BB OBS Select (field ?) */
+#define AR5K_PHY_TST2_ADC_OBS_SEL	0x00800000	/* ADC OBS Select (field ?) */
+#define AR5K_PHY_TST2_RX_CLR_SEL	0x08000000	/* RX Clear Select (?) */
+#define AR5K_PHY_TST2_FORCE_AGC_CLR	0x10000000	/* Force AGC clear (?) */
+#define AR5K_PHY_SHIFT_2GHZ		0x00004007	/* Used to access 2GHz radios */
+#define AR5K_PHY_SHIFT_5GHZ		0x00000007	/* Used to access 5GHz radios (default) */
+
+/*
+ * PHY frame control register [5110] /turbo mode register [5111+]
+ *
+ * There is another frame control register for [5111+]
+ * at address 0x9944 (see below) but the 2 first flags
+ * are common here between 5110 frame control register
+ * and [5111+] turbo mode register, so this also works as
+ * a "turbo mode register" for 5110. We treat this one as
+ * a frame control register for 5110 below.
+ */
+#define	AR5K_PHY_TURBO			0x9804			/* Register Address */
+#define	AR5K_PHY_TURBO_MODE		0x00000001	/* Enable turbo mode */
+#define	AR5K_PHY_TURBO_SHORT		0x00000002	/* Set short symbols to turbo mode */
+#define	AR5K_PHY_TURBO_MIMO		0x00000004	/* Set turbo for mimo mimo */
+
+/*
+ * PHY agility command register
+ * (aka TST_1)
+ */
+#define	AR5K_PHY_AGC			0x9808			/* Register Address */
+#define	AR5K_PHY_TST1			0x9808
+#define	AR5K_PHY_AGC_DISABLE		0x08000000	/* Disable AGC to A2 (?)*/
+#define	AR5K_PHY_TST1_TXHOLD		0x00003800	/* Set tx hold (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC		0x00000002	/* Used with bit 7 (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC_S	1
+#define	AR5K_PHY_TST1_TXSRC_ALT		0x00000080	/* Set input to tsdac (?) */
+#define	AR5K_PHY_TST1_TXSRC_ALT_S	7
+
+
+/*
+ * PHY timing register 3 [5112+]
+ */
+#define	AR5K_PHY_TIMING_3		0x9814
+#define	AR5K_PHY_TIMING_3_DSC_MAN	0xfffe0000
+#define	AR5K_PHY_TIMING_3_DSC_MAN_S	17
+#define	AR5K_PHY_TIMING_3_DSC_EXP	0x0001e000
+#define	AR5K_PHY_TIMING_3_DSC_EXP_S	13
+
+/*
+ * PHY chip revision register
+ */
+#define	AR5K_PHY_CHIP_ID		0x9818
+
+/*
+ * PHY activation register
+ */
+#define	AR5K_PHY_ACT			0x981c			/* Register Address */
+#define	AR5K_PHY_ACT_ENABLE		0x00000001	/* Activate PHY */
+#define	AR5K_PHY_ACT_DISABLE		0x00000002	/* Deactivate PHY */
+
+/*
+ * PHY RF control registers
+ */
+#define AR5K_PHY_RF_CTL2		0x9824			/* Register Address */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START	0x0000000f	/* TX frame to TX data start */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START_S	0
+
+#define AR5K_PHY_RF_CTL3		0x9828			/* Register Address */
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000ff00	/* TX end to XLNA on */
+#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	8
+
+#define	AR5K_PHY_ADC_CTL			0x982c
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF		0x00000003
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S	0
+#define	AR5K_PHY_ADC_CTL_PWD_DAC_OFF		0x00002000
+#define	AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF	0x00004000
+#define	AR5K_PHY_ADC_CTL_PWD_ADC_OFF		0x00008000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON		0x00030000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S		16
+
+#define AR5K_PHY_RF_CTL4		0x9834			/* Register Address */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON	0x00000001	/* TX frame to XPA A on (field) */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON	0x00000100	/* TX frame to XPA B on (field) */
+#define	AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF	0x00010000	/* TX end to XPA A off (field) */
+#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF	0x01000000	/* TX end to XPA B off (field) */
+
+/*
+ * Pre-Amplifier control register
+ * (XPA -> external pre-amplifier)
+ */
+#define	AR5K_PHY_PA_CTL			0x9838			/* Register Address */
+#define	AR5K_PHY_PA_CTL_XPA_A_HI	0x00000001	/* XPA A high (?) */
+#define	AR5K_PHY_PA_CTL_XPA_B_HI	0x00000002	/* XPA B high (?) */
+#define	AR5K_PHY_PA_CTL_XPA_A_EN	0x00000004	/* Enable XPA A */
+#define	AR5K_PHY_PA_CTL_XPA_B_EN	0x00000008	/* Enable XPA B */
+
+/*
+ * PHY settling register
+ */
+#define AR5K_PHY_SETTLING		0x9844			/* Register Address */
+#define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* AGC settling time */
+#define	AR5K_PHY_SETTLING_AGC_S		0
+#define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Switch settlig time */
+#define	AR5K_PHY_SETTLING_SWITCH_S	7
+
+/*
+ * PHY Gain registers
+ */
+#define AR5K_PHY_GAIN			0x9848			/* Register Address */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN	0x0003f000	/* TX-RX Attenuation */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN_S	12
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX	0x007c0000
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX_S	18
+
+#define	AR5K_PHY_GAIN_OFFSET		0x984c			/* Register Address */
+#define	AR5K_PHY_GAIN_OFFSET_RXTX_FLAG	0x00020000	/* RX-TX flag (?) */
+
+/*
+ * Desired ADC/PGA size register
+ * (for more infos read ANI patent)
+ */
+#define AR5K_PHY_DESIRED_SIZE		0x9850			/* Register Address */
+#define	AR5K_PHY_DESIRED_SIZE_ADC	0x000000ff	/* ADC desired size */
+#define	AR5K_PHY_DESIRED_SIZE_ADC_S	0
+#define	AR5K_PHY_DESIRED_SIZE_PGA	0x0000ff00	/* PGA desired size */
+#define	AR5K_PHY_DESIRED_SIZE_PGA_S	8
+#define	AR5K_PHY_DESIRED_SIZE_TOT	0x0ff00000	/* Total desired size */
+#define	AR5K_PHY_DESIRED_SIZE_TOT_S	20
+
+/*
+ * PHY signal register
+ * (for more infos read ANI patent)
+ */
+#define	AR5K_PHY_SIG			0x9858			/* Register Address */
+#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000	/* FIRSTEP */
+#define	AR5K_PHY_SIG_FIRSTEP_S		12
+#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000	/* FIPWR */
+#define	AR5K_PHY_SIG_FIRPWR_S		18
+
+/*
+ * PHY coarse agility control register
+ * (for more infos read ANI patent)
+ */
+#define	AR5K_PHY_AGCCOARSE		0x985c			/* Register Address */
+#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80	/* AGC Coarse low */
+#define	AR5K_PHY_AGCCOARSE_LO_S		7
+#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000	/* AGC Coarse high */
+#define	AR5K_PHY_AGCCOARSE_HI_S		15
+
+/*
+ * PHY agility control register
+ */
+#define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
+#define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
+#define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
+#define	AR5K_PHY_AGCCTL_NF_EN		0x00008000	/* Enable nf calibration to happen (?) */
+#define	AR5K_PHY_AGCCTL_NF_NOUPDATE	0x00020000	/* Don't update nf automaticaly */
+
+/*
+ * PHY noise floor status register
+ */
+#define AR5K_PHY_NF			0x9864			/* Register address */
+#define AR5K_PHY_NF_M			0x000001ff	/* Noise floor mask */
+#define AR5K_PHY_NF_ACTIVE		0x00000100	/* Noise floor calibration still active */
+#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
+#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
+#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
+#define	AR5K_PHY_NF_THRESH62		0x0007f000	/* Thresh62 -check ANI patent- (field) */
+#define	AR5K_PHY_NF_THRESH62_S		12
+#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* ??? */
+#define	AR5K_PHY_NF_MINCCA_PWR_S	19
+
+/*
+ * PHY ADC saturation register [5110]
+ */
+#define	AR5K_PHY_ADCSAT			0x9868
+#define	AR5K_PHY_ADCSAT_ICNT		0x0001f800
+#define	AR5K_PHY_ADCSAT_ICNT_S		11
+#define	AR5K_PHY_ADCSAT_THR		0x000007e0
+#define	AR5K_PHY_ADCSAT_THR_S		5
+
+/*
+ * PHY Weak ofdm signal detection threshold registers (ANI) [5212+]
+ */
+
+/* High thresholds */
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR		0x9868
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT	0x0000001f
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S	0
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1		0x00fe0000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S	17
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2		0x7f000000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S	24
+
+/* Low thresholds */
+#define AR5K_PHY_WEAK_OFDM_LOW_THR 		0x986c
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN	0x00000001
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT	0x00003f00
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S	8
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1		0x001fc000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S		14
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2		0x0fe00000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S		21
+
+
+/*
+ * PHY sleep registers [5112+]
+ */
+#define AR5K_PHY_SCR			0x9870
+
+#define AR5K_PHY_SLMT			0x9874
+#define AR5K_PHY_SLMT_32MHZ		0x0000007f
+
+#define AR5K_PHY_SCAL			0x9878
+#define AR5K_PHY_SCAL_32MHZ		0x0000000e
+#define	AR5K_PHY_SCAL_32MHZ_2417	0x0000000a
+#define	AR5K_PHY_SCAL_32MHZ_HB63	0x00000032
+
+/*
+ * PHY PLL (Phase Locked Loop) control register
+ */
+#define	AR5K_PHY_PLL			0x987c
+#define	AR5K_PHY_PLL_20MHZ		0x00000013	/* For half rate (?) */
+/* 40MHz -> 5GHz band */
+#define	AR5K_PHY_PLL_40MHZ_5211		0x00000018
+#define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
+#define	AR5K_PHY_PLL_40MHZ_5413		0x00000004
+#define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
+/* 44MHz -> 2.4GHz band */
+#define	AR5K_PHY_PLL_44MHZ_5211		0x00000019
+#define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
+#define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
+
+#define AR5K_PHY_PLL_RF5111		0x00000000
+#define AR5K_PHY_PLL_RF5112		0x00000040
+#define	AR5K_PHY_PLL_HALF_RATE		0x00000100
+#define	AR5K_PHY_PLL_QUARTER_RATE	0x00000200
+
+/*
+ * RF Buffer register
+ *
+ * It's obvious from the code that 0x989c is the buffer register but
+ * for the other special registers that we write to after sending each
+ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
+ * for now. It's interesting that they are also used for some other operations.
+ */
+
+#define AR5K_RF_BUFFER			0x989c
+#define AR5K_RF_BUFFER_CONTROL_0	0x98c0	/* Channel on 5110 */
+#define AR5K_RF_BUFFER_CONTROL_1	0x98c4	/* Bank 7 on 5112 */
+#define AR5K_RF_BUFFER_CONTROL_2	0x98cc	/* Bank 7 on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_3	0x98d0	/* Bank 2 on 5112 */
+						/* Channel set on 5111 */
+						/* Used to read radio revision*/
+
+#define AR5K_RF_BUFFER_CONTROL_4	0x98d4  /* RF Stage register on 5110 */
+						/* Bank 0,1,2,6 on 5111 */
+						/* Bank 1 on 5112 */
+						/* Used during activation on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_5	0x98d8	/* Bank 3 on 5111 */
+						/* Used during activation on 5111 */
+						/* Channel on 5112 */
+						/* Bank 6 on 5112 */
+
+#define AR5K_RF_BUFFER_CONTROL_6	0x98dc	/* Bank 3 on 5112 */
+
+/*
+ * PHY RF stage register [5210]
+ */
+#define AR5K_PHY_RFSTG			0x98d4
+#define AR5K_PHY_RFSTG_DISABLE		0x00000021
+
+/*
+ * BIN masks (?)
+ */
+#define	AR5K_PHY_BIN_MASK_1	0x9900
+#define	AR5K_PHY_BIN_MASK_2	0x9904
+#define	AR5K_PHY_BIN_MASK_3	0x9908
+
+#define	AR5K_PHY_BIN_MASK_CTL		0x990c
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4	0x00003fff
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4_S	0
+#define	AR5K_PHY_BIN_MASK_CTL_RATE	0xff000000
+#define	AR5K_PHY_BIN_MASK_CTL_RATE_S	24
+
+/*
+ * PHY Antenna control register
+ */
+#define AR5K_PHY_ANT_CTL		0x9910			/* Register Address */
+#define	AR5K_PHY_ANT_CTL_TXRX_EN	0x00000001	/* Enable TX/RX (?) */
+#define	AR5K_PHY_ANT_CTL_SECTORED_ANT	0x00000004	/* Sectored Antenna */
+#define	AR5K_PHY_ANT_CTL_HITUNE5	0x00000008	/* Hitune5 (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE	0x000003f0	/* Switch table idle (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S	4
+
+/*
+ * PHY receiver delay register [5111+]
+ */
+#define	AR5K_PHY_RX_DELAY		0x9914			/* Register Address */
+#define	AR5K_PHY_RX_DELAY_M		0x00003fff	/* Mask for RX activate to receive delay (/100ns) */
+
+/*
+ * PHY max rx length register (?) [5111]
+ */
+#define	AR5K_PHY_MAX_RX_LEN		0x991c
+
+/*
+ * PHY timing register 4
+ * I(nphase)/Q(adrature) calibration register [5111+]
+ */
+#define	AR5K_PHY_IQ			0x9920			/* Register Address */
+#define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
+#define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX	0x0000f000	/* Mask for max number of samples in log scale */
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S	12
+#define	AR5K_PHY_IQ_RUN			0x00010000	/* Run i/q calibration */
+#define	AR5K_PHY_IQ_USE_PT_DF		0x00020000	/* Use pilot track df (?) */
+#define	AR5K_PHY_IQ_EARLY_TRIG_THR	0x00200000	/* Early trigger threshold (?) (field) */
+#define	AR5K_PHY_IQ_PILOT_MASK_EN	0x10000000	/* Enable pilot mask (?) */
+#define	AR5K_PHY_IQ_CHAN_MASK_EN	0x20000000	/* Enable channel mask (?) */
+#define	AR5K_PHY_IQ_SPUR_FILT_EN	0x40000000	/* Enable spur filter */
+#define	AR5K_PHY_IQ_SPUR_RSSI_EN	0x80000000	/* Enable spur rssi */
+
+/*
+ * PHY timing register 5
+ * OFDM Self-correlator Cyclic RSSI threshold params
+ * (Check out bb_cycpwr_thr1 on ANI patent)
+ */
+#define	AR5K_PHY_OFDM_SELFCORR			0x9924			/* Register Address */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN	0x00000001	/* Enable cyclic RSSI thr 1 */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1	0x000000fe	/* Mask for Cyclic RSSI threshold 1 */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	1
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3	0x00000100	/* Cyclic RSSI threshold 3 (field) (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN	0x00008000	/* Enable 1A RSSI threshold (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR	0x00010000	/* 1A RSSI threshold (field) (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI	0x00800000	/* Long sc threshold hi rssi (?) */
+
+/*
+ * PHY-only warm reset register
+ */
+#define	AR5K_PHY_WARM_RESET		0x9928
+
+/*
+ * PHY-only control register
+ */
+#define AR5K_PHY_CTL			0x992c			/* Register Address */
+#define	AR5K_PHY_CTL_RX_DRAIN_RATE	0x00000001	/* RX drain rate (?) */
+#define	AR5K_PHY_CTL_LATE_TX_SIG_SYM	0x00000002	/* Late tx signal symbol (?) */
+#define	AR5K_PHY_CTL_GEN_SCRAMBLER	0x00000004	/* Generate scrambler */
+#define	AR5K_PHY_CTL_TX_ANT_SEL		0x00000008	/* TX antenna select */
+#define	AR5K_PHY_CTL_TX_ANT_STATIC	0x00000010	/* Static TX antenna */
+#define	AR5K_PHY_CTL_RX_ANT_SEL		0x00000020	/* RX antenna select */
+#define	AR5K_PHY_CTL_RX_ANT_STATIC	0x00000040	/* Static RX antenna */
+#define	AR5K_PHY_CTL_LOW_FREQ_SLE_EN	0x00000080	/* Enable low freq sleep */
+
+/*
+ * PHY PAPD probe register [5111+]
+ */
+#define	AR5K_PHY_PAPD_PROBE		0x9930
+#define	AR5K_PHY_PAPD_PROBE_SH_HI_PAR	0x00000001
+#define	AR5K_PHY_PAPD_PROBE_PCDAC_BIAS	0x00000002
+#define	AR5K_PHY_PAPD_PROBE_COMP_GAIN	0x00000040
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER	0x00007e00
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER_S	9
+#define	AR5K_PHY_PAPD_PROBE_TX_NEXT	0x00008000
+#define	AR5K_PHY_PAPD_PROBE_PREDIST_EN	0x00010000
+#define	AR5K_PHY_PAPD_PROBE_TYPE	0x01800000	/* [5112+] */
+#define	AR5K_PHY_PAPD_PROBE_TYPE_S	23
+#define	AR5K_PHY_PAPD_PROBE_TYPE_OFDM	0
+#define	AR5K_PHY_PAPD_PROBE_TYPE_XR	1
+#define	AR5K_PHY_PAPD_PROBE_TYPE_CCK	2
+#define	AR5K_PHY_PAPD_PROBE_GAINF	0xfe000000
+#define	AR5K_PHY_PAPD_PROBE_GAINF_S	25
+#define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
+#define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
+
+/*
+ * PHY TX rate power registers [5112+]
+ */
+#define	AR5K_PHY_TXPOWER_RATE1			0x9934
+#define	AR5K_PHY_TXPOWER_RATE2			0x9938
+#define	AR5K_PHY_TXPOWER_RATE_MAX		0x993c
+#define	AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE	0x00000040
+#define	AR5K_PHY_TXPOWER_RATE3			0xa234
+#define	AR5K_PHY_TXPOWER_RATE4			0xa238
+
+/*
+ * PHY frame control register [5111+]
+ */
+#define	AR5K_PHY_FRAME_CTL_5210		0x9804
+#define	AR5K_PHY_FRAME_CTL_5211		0x9944
+#define	AR5K_PHY_FRAME_CTL		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
+/*---[5111+]---*/
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038	/* Mask for tx clip (?) */
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
+#define	AR5K_PHY_FRAME_CTL_PREP_CHINFO	0x00010000	/* Prepend chan info */
+#define	AR5K_PHY_FRAME_CTL_EMU		0x80000000
+#define	AR5K_PHY_FRAME_CTL_EMU_S	31
+/*---[5110/5111]---*/
+#define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000	/* PHY timing error */
+#define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000	/* Parity error */
+#define	AR5K_PHY_FRAME_CTL_ILLRATE_ERR	0x04000000	/* Illegal rate */
+#define	AR5K_PHY_FRAME_CTL_ILLLEN_ERR	0x08000000	/* Illegal length */
+#define	AR5K_PHY_FRAME_CTL_SERVICE_ERR	0x20000000
+#define	AR5K_PHY_FRAME_CTL_TXURN_ERR	0x40000000	/* TX underrun */
+#define AR5K_PHY_FRAME_CTL_INI		AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
+			AR5K_PHY_FRAME_CTL_TXURN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
+			AR5K_PHY_FRAME_CTL_PARITY_ERR | \
+			AR5K_PHY_FRAME_CTL_TIMING_ERR
+
+/*
+ * PHY Tx Power adjustment register [5212A+]
+ */
+#define	AR5K_PHY_TX_PWR_ADJ			0x994c
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA	0x00000fc0
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S	6
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX	0x00fc0000
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S	18
+
+/*
+ * PHY radar detection register [5111+]
+ */
+#define	AR5K_PHY_RADAR			0x9954
+#define	AR5K_PHY_RADAR_ENABLE		0x00000001
+#define	AR5K_PHY_RADAR_DISABLE		0x00000000
+#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e	/* Inband threshold
+							5-bits, units unknown {0..31}
+							(? MHz ?) */
+#define AR5K_PHY_RADAR_INBANDTHR_S	1
+
+#define AR5K_PHY_RADAR_PRSSI_THR    	0x00000fc0	/* Pulse RSSI/SNR threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PRSSI_THR_S	6
+
+#define AR5K_PHY_RADAR_PHEIGHT_THR   	0x0003f000	/* Pulse height threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PHEIGHT_THR_S	12
+
+#define AR5K_PHY_RADAR_RSSI_THR    	0x00fc0000	/* Radar RSSI/SNR threshold.
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_RSSI_THR_S	18
+
+#define AR5K_PHY_RADAR_FIRPWR_THR	0x7f000000	/* Finite Impulse Response
+							filter power out threshold.
+							7-bits, standard power range
+							{0..127} in 1/2 dBm units. */
+#define AR5K_PHY_RADAR_FIRPWR_THRS	24
+
+/*
+ * PHY antenna switch table registers
+ */
+#define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
+#define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
+
+/*
+ * PHY Noise floor threshold
+ */
+#define AR5K_PHY_NFTHRES		0x9968
+
+/*
+ * Sigma Delta register (?) [5213]
+ */
+#define AR5K_PHY_SIGMA_DELTA		0x996C
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL	0x00000003
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S	0
+#define AR5K_PHY_SIGMA_DELTA_FILT2	0x000000f8
+#define AR5K_PHY_SIGMA_DELTA_FILT2_S	3
+#define AR5K_PHY_SIGMA_DELTA_FILT1	0x00001f00
+#define AR5K_PHY_SIGMA_DELTA_FILT1_S	8
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ffe000
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S	13
+
+/*
+ * RF restart register [5112+] (?)
+ */
+#define AR5K_PHY_RESTART		0x9970		/* restart */
+#define AR5K_PHY_RESTART_DIV_GC		0x001c0000	/* Fast diversity gc_limit (?) */
+#define AR5K_PHY_RESTART_DIV_GC_S	18
+
+/*
+ * RF Bus access request register (for synth-oly channel switching)
+ */
+#define AR5K_PHY_RFBUS_REQ		0x997C
+#define AR5K_PHY_RFBUS_REQ_REQUEST	0x00000001
+
+/*
+ * Spur mitigation masks (?)
+ */
+#define AR5K_PHY_TIMING_7		0x9980
+#define AR5K_PHY_TIMING_8		0x9984
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S	0
+
+#define AR5K_PHY_BIN_MASK2_1		0x9988
+#define AR5K_PHY_BIN_MASK2_2		0x998c
+#define AR5K_PHY_BIN_MASK2_3		0x9990
+
+#define AR5K_PHY_BIN_MASK2_4		0x9994
+#define AR5K_PHY_BIN_MASK2_4_MASK_4	0x00003fff
+#define AR5K_PHY_BIN_MASK2_4_MASK_4_S	0
+
+#define AR5K_PHY_TIMING_9			0x9998
+#define AR5K_PHY_TIMING_10			0x999c
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S	0
+
+/*
+ * Spur mitigation control
+ */
+#define AR5K_PHY_TIMING_11			0x99a0		/* Register address */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S	20
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
+
+/*
+ * Gain tables
+ */
+#define	AR5K_BB_GAIN_BASE		0x9b00	/* BaseBand Amplifier Gain table base address */
+#define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
+#define	AR5K_RF_GAIN_BASE		0x9a00	/* RF Amplrifier Gain table base address */
+#define AR5K_RF_GAIN(_n)		(AR5K_RF_GAIN_BASE + ((_n) << 2))
+
+/*
+ * PHY timing IQ calibration result register [5111+]
+ */
+#define	AR5K_PHY_IQRES_CAL_PWR_I	0x9c10	/* I (Inphase) power value */
+#define	AR5K_PHY_IQRES_CAL_PWR_Q	0x9c14	/* Q (Quadrature) power value */
+#define	AR5K_PHY_IQRES_CAL_CORR		0x9c18	/* I/Q Correlation */
+
+/*
+ * PHY current RSSI register [5111+]
+ */
+#define	AR5K_PHY_CURRENT_RSSI	0x9c1c
+
+/*
+ * PHY RF Bus grant register
+ */
+#define	AR5K_PHY_RFBUS_GRANT	0x9c20
+#define	AR5K_PHY_RFBUS_GRANT_OK	0x00000001
+
+/*
+ * PHY ADC test register
+ */
+#define	AR5K_PHY_ADC_TEST	0x9c24
+#define	AR5K_PHY_ADC_TEST_I	0x00000001
+#define	AR5K_PHY_ADC_TEST_Q	0x00000200
+
+/*
+ * PHY DAC test register
+ */
+#define	AR5K_PHY_DAC_TEST	0x9c28
+#define	AR5K_PHY_DAC_TEST_I	0x00000001
+#define	AR5K_PHY_DAC_TEST_Q	0x00000200
+
+/*
+ * PHY PTAT register (?)
+ */
+#define	AR5K_PHY_PTAT		0x9c2c
+
+/*
+ * PHY Illegal TX rate register [5112+]
+ */
+#define	AR5K_PHY_BAD_TX_RATE	0x9c30
+
+/*
+ * PHY SPUR Power register [5112+]
+ */
+#define	AR5K_PHY_SPUR_PWR	0x9c34			/* Register Address */
+#define	AR5K_PHY_SPUR_PWR_I	0x00000001	/* SPUR Power estimate for I (field) */
+#define	AR5K_PHY_SPUR_PWR_Q	0x00000100	/* SPUR Power estimate for Q (field) */
+#define	AR5K_PHY_SPUR_PWR_FILT	0x00010000	/* Power with SPUR removed (field) */
+
+/*
+ * PHY Channel status register [5112+] (?)
+ */
+#define	AR5K_PHY_CHAN_STATUS		0x9c38
+#define	AR5K_PHY_CHAN_STATUS_BT_ACT	0x00000001
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_RAW	0x00000002
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_MAC	0x00000004
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_PAP	0x00000008
+
+/*
+ * Heavy clip enable register
+ */
+#define	AR5K_PHY_HEAVY_CLIP_ENABLE	0x99e0
+
+/*
+ * PHY clock sleep registers [5112+]
+ */
+#define AR5K_PHY_SCLOCK			0x99f0
+#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
+#define AR5K_PHY_SDELAY			0x99f4
+#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
+#define AR5K_PHY_SPENDING		0x99f8
+
+
+/*
+ * PHY PAPD I (power?) table (?)
+ * (92! entries)
+ */
+#define	AR5K_PHY_PAPD_I_BASE	0xa000
+#define	AR5K_PHY_PAPD_I(_n)	(AR5K_PHY_PAPD_I_BASE + ((_n) << 2))
+
+/*
+ * PHY PCDAC TX power table
+ */
+#define	AR5K_PHY_PCDAC_TXPOWER_BASE	0xa180
+#define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * PHY mode register [5111+]
+ */
+#define	AR5K_PHY_MODE			0x0a200			/* Register Address */
+#define	AR5K_PHY_MODE_MOD		0x00000001	/* PHY Modulation bit */
+#define AR5K_PHY_MODE_MOD_OFDM		0
+#define AR5K_PHY_MODE_MOD_CCK		1
+#define AR5K_PHY_MODE_FREQ		0x00000002	/* Freq mode bit */
+#define	AR5K_PHY_MODE_FREQ_5GHZ		0
+#define	AR5K_PHY_MODE_FREQ_2GHZ		2
+#define AR5K_PHY_MODE_MOD_DYN		0x00000004	/* Enable Dynamic OFDM/CCK mode [5112+] */
+#define AR5K_PHY_MODE_RAD		0x00000008	/* [5212+] */
+#define AR5K_PHY_MODE_RAD_RF5111	0
+#define AR5K_PHY_MODE_RAD_RF5112	8
+#define AR5K_PHY_MODE_XR		0x00000010	/* Enable XR mode [5112+] */
+#define	AR5K_PHY_MODE_HALF_RATE		0x00000020	/* Enable Half rate (test) */
+#define	AR5K_PHY_MODE_QUARTER_RATE	0x00000040	/* Enable Quarter rat (test) */
+
+/*
+ * PHY CCK transmit control register [5111+ (?)]
+ */
+#define AR5K_PHY_CCKTXCTL		0xa204
+#define AR5K_PHY_CCKTXCTL_WORLD		0x00000000
+#define AR5K_PHY_CCKTXCTL_JAPAN		0x00000010
+#define	AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS	0x00000001
+#define	AR5K_PHY_CCKTXCTK_DAC_SCALE	0x00000004
+
+/*
+ * PHY CCK Cross-correlator Barker RSSI threshold register [5212+]
+ */
+#define AR5K_PHY_CCK_CROSSCORR			0xa208
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR	0x0000000f
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S	0
+
+/* Same address is used for antenna diversity activation */
+#define	AR5K_PHY_FAST_ANT_DIV		0xa208
+#define	AR5K_PHY_FAST_ANT_DIV_EN	0x00002000
+
+/*
+ * PHY 2GHz gain register [5111+]
+ */
+#define	AR5K_PHY_GAIN_2GHZ			0xa20c
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX		0x00fc0000
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
+#define	AR5K_PHY_GAIN_2GHZ_INI_5111		0x6480416c
+
+#define	AR5K_PHY_CCK_RX_CTL_4			0xa21c
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT	0x01f80000
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S	19
+
+#define	AR5K_PHY_DAG_CCK_CTL			0xa228
+#define	AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR	0x00000200
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR		0x0001fc00
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S		10
+
+#define	AR5K_PHY_FAST_ADC	0xa24c
+
+#define	AR5K_PHY_BLUETOOTH	0xa254
+
+/*
+ * Transmit Power Control register
+ * [2413+]
+ */
+#define	AR5K_PHY_TPC_RG1		0xa258
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN	0x0000c000
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S	14
+#define AR5K_PHY_TPC_RG1_PDGAIN_1	0x00030000
+#define AR5K_PHY_TPC_RG1_PDGAIN_1_S	16
+#define AR5K_PHY_TPC_RG1_PDGAIN_2	0x000c0000
+#define AR5K_PHY_TPC_RG1_PDGAIN_2_S	18
+#define AR5K_PHY_TPC_RG1_PDGAIN_3	0x00300000
+#define AR5K_PHY_TPC_RG1_PDGAIN_3_S	20
+
+#define	AR5K_PHY_TPC_RG5			0xa26C
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP	0x0000000F
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S	0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1	0x000003F0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S	4
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2	0x0000FC00
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S	10
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3	0x003F0000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S	16
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4	0x0FC00000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S	22
+
+/*
+ * PHY PDADC Tx power table
+ */
+#define AR5K_PHY_PDADC_TXPOWER_BASE	0xa280
+#define	AR5K_PHY_PDADC_TXPOWER(_n)	(AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h
new file mode 100644
index 0000000..e50baff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h
@@ -0,0 +1,1181 @@
+/*
+ * RF Buffer handling functions
+ *
+ * Copyright (c) 2009 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+
+/*
+ * There are some special registers on the RF chip
+ * that control various operation settings related mostly to
+ * the analog parts (channel, gain adjustment etc).
+ *
+ * We don't write on those registers directly but
+ * we send a data packet on the chip, using a special register,
+ * that holds all the settings we need. After we 've sent the
+ * data packet, we write on another special register to notify hw
+ * to apply the settings. This is done so that control registers
+ * can be dynamicaly programmed during operation and the settings
+ * are applied faster on the hw.
+ *
+ * We call each data packet an "RF Bank" and all the data we write
+ * (all RF Banks) "RF Buffer". This file holds initial RF Buffer
+ * data for the different RF chips, and various info to match RF
+ * Buffer offsets with specific RF registers so that we can access
+ * them. We tweak these settings on rfregs_init function.
+ *
+ * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer
+ * registers and control registers):
+ *
+ * http://www.google.com/patents?id=qNURAAAAEBAJ
+ */
+
+
+/*
+ * Struct to hold default mode specific RF
+ * register values (RF Banks)
+ */
+struct ath5k_ini_rfbuffer {
+	u8	rfb_bank;		/* RF Bank number */
+	u16	rfb_ctrl_register;	/* RF Buffer control register */
+	u32	rfb_mode_data[5];	/* RF Buffer data for each mode */
+};
+
+/*
+ * Struct to hold RF Buffer field
+ * infos used to access certain RF
+ * analog registers
+ */
+struct ath5k_rfb_field {
+	u8	len;	/* Field length */
+	u16	pos;	/* Offset on the raw packet */
+	u8	col;	/* Column -used for shifting */
+};
+
+/*
+ * RF analog register definition
+ */
+struct ath5k_rf_reg {
+	u8			bank;	/* RF Buffer Bank number */
+	u8			index;	/* Register's index on rf_regs_idx */
+	struct ath5k_rfb_field	field;	/* RF Buffer field for this register */
+};
+
+/* Map RF registers to indexes
+ * We do this to handle common bits and make our
+ * life easier by using an index for each register
+ * instead of a full rfb_field */
+enum ath5k_rf_regs_idx {
+	/* BANK 6 */
+	AR5K_RF_OB_2GHZ = 0,
+	AR5K_RF_OB_5GHZ,
+	AR5K_RF_DB_2GHZ,
+	AR5K_RF_DB_5GHZ,
+	AR5K_RF_FIXED_BIAS_A,
+	AR5K_RF_FIXED_BIAS_B,
+	AR5K_RF_PWD_XPD,
+	AR5K_RF_XPD_SEL,
+	AR5K_RF_XPD_GAIN,
+	AR5K_RF_PD_GAIN_LO,
+	AR5K_RF_PD_GAIN_HI,
+	AR5K_RF_HIGH_VC_CP,
+	AR5K_RF_MID_VC_CP,
+	AR5K_RF_LOW_VC_CP,
+	AR5K_RF_PUSH_UP,
+	AR5K_RF_PAD2GND,
+	AR5K_RF_XB2_LVL,
+	AR5K_RF_XB5_LVL,
+	AR5K_RF_PWD_ICLOBUF_2G,
+	AR5K_RF_PWD_84,
+	AR5K_RF_PWD_90,
+	AR5K_RF_PWD_130,
+	AR5K_RF_PWD_131,
+	AR5K_RF_PWD_132,
+	AR5K_RF_PWD_136,
+	AR5K_RF_PWD_137,
+	AR5K_RF_PWD_138,
+	AR5K_RF_PWD_166,
+	AR5K_RF_PWD_167,
+	AR5K_RF_DERBY_CHAN_SEL_MODE,
+	/* BANK 7 */
+	AR5K_RF_GAIN_I,
+	AR5K_RF_PLO_SEL,
+	AR5K_RF_RFGAIN_SEL,
+	AR5K_RF_RFGAIN_STEP,
+	AR5K_RF_WAIT_S,
+	AR5K_RF_WAIT_I,
+	AR5K_RF_MAX_TIME,
+	AR5K_RF_MIXVGA_OVR,
+	AR5K_RF_MIXGAIN_OVR,
+	AR5K_RF_MIXGAIN_STEP,
+	AR5K_RF_PD_DELAY_A,
+	AR5K_RF_PD_DELAY_B,
+	AR5K_RF_PD_DELAY_XR,
+	AR5K_RF_PD_PERIOD_A,
+	AR5K_RF_PD_PERIOD_B,
+	AR5K_RF_PD_PERIOD_XR,
+};
+
+
+/*******************\
+* RF5111 (Sombrero) *
+\*******************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5111_OB_2GHZ		{ 3, 119, 0 }
+#define	AR5K_RF5111_DB_2GHZ		{ 3, 122, 0 }
+
+#define	AR5K_RF5111_OB_5GHZ		{ 3, 104, 0 }
+#define	AR5K_RF5111_DB_5GHZ		{ 3, 107, 0 }
+
+#define	AR5K_RF5111_PWD_XPD		{ 1, 95,  0 }
+#define	AR5K_RF5111_XPD_GAIN		{ 4, 96,  0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5111_PWD(_n)		{ 1, (135 - _n), 3 }
+
+/* BANK 7				len  pos col */
+#define	AR5K_RF5111_GAIN_I		{ 6, 29,  0 }
+#define	AR5K_RF5111_PLO_SEL		{ 1, 4,   0 }
+#define	AR5K_RF5111_RFGAIN_SEL		{ 1, 36,  0 }
+#define AR5K_RF5111_RFGAIN_STEP		{ 6, 37,  0 }
+/* Only on AR5212 BaseBand and up */
+#define	AR5K_RF5111_WAIT_S		{ 5, 19,  0 }
+#define	AR5K_RF5111_WAIT_I		{ 5, 24,  0 }
+#define	AR5K_RF5111_MAX_TIME		{ 2, 49,  0 }
+
+static const struct ath5k_rf_reg rf_regs_5111[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5111_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5111_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5111_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5111_DB_5GHZ},
+	{6, AR5K_RF_PWD_XPD,		AR5K_RF5111_PWD_XPD},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5111_XPD_GAIN},
+	{6, AR5K_RF_PWD_84,		AR5K_RF5111_PWD(84)},
+	{6, AR5K_RF_PWD_90,		AR5K_RF5111_PWD(90)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5111_GAIN_I},
+	{7, AR5K_RF_PLO_SEL,		AR5K_RF5111_PLO_SEL},
+	{7, AR5K_RF_RFGAIN_SEL,		AR5K_RF5111_RFGAIN_SEL},
+	{7, AR5K_RF_RFGAIN_STEP,	AR5K_RF5111_RFGAIN_STEP},
+	{7, AR5K_RF_WAIT_S,		AR5K_RF5111_WAIT_S},
+	{7, AR5K_RF_WAIT_I,		AR5K_RF5111_WAIT_I},
+	{7, AR5K_RF_MAX_TIME,		AR5K_RF5111_MAX_TIME}
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5111[] = {
+	{ 0, 0x989c,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
+	{ 0, 0x989c,
+	    { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
+	{ 0, 0x98d4,
+	    { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
+	{ 1, 0x98d4,
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d4,
+	    { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
+	{ 3, 0x98d8,
+	    { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
+	{ 6, 0x989c,
+	    { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
+	{ 6, 0x989c,
+	    { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
+	{ 6, 0x989c,
+	    { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
+	{ 6, 0x989c,
+	    { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
+	{ 6, 0x98d4,
+	    { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
+	{ 7, 0x989c,
+	    { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
+	{ 7, 0x989c,
+	    { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+	{ 7, 0x989c,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 7, 0x989c,
+	    { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
+	{ 7, 0x989c,
+	    { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
+	{ 7, 0x989c,
+	    { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
+	{ 7, 0x989c,
+	    { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***********************\
+* RF5112/RF2112 (Derby) *
+\***********************/
+
+/* BANK 7 (Common)			len  pos col */
+#define	AR5K_RF5112X_GAIN_I		{ 6, 14,  0 }
+#define	AR5K_RF5112X_MIXVGA_OVR		{ 1, 36,  0 }
+#define	AR5K_RF5112X_MIXGAIN_OVR	{ 2, 37,  0 }
+#define AR5K_RF5112X_MIXGAIN_STEP	{ 4, 32,  0 }
+#define	AR5K_RF5112X_PD_DELAY_A		{ 4, 58,  0 }
+#define	AR5K_RF5112X_PD_DELAY_B		{ 4, 62,  0 }
+#define	AR5K_RF5112X_PD_DELAY_XR	{ 4, 66,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_A	{ 4, 70,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_B	{ 4, 74,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_XR	{ 4, 78,  0 }
+
+/* RFX112 (Derby 1) */
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF5112_OB_2GHZ		{ 3, 269, 0 }
+#define	AR5K_RF5112_DB_2GHZ		{ 3, 272, 0 }
+
+#define	AR5K_RF5112_OB_5GHZ		{ 3, 261, 0 }
+#define	AR5K_RF5112_DB_5GHZ		{ 3, 264, 0 }
+
+#define	AR5K_RF5112_FIXED_BIAS_A	{ 1, 260, 0 }
+#define	AR5K_RF5112_FIXED_BIAS_B	{ 1, 259, 0 }
+
+#define	AR5K_RF5112_XPD_SEL		{ 1, 284, 0 }
+#define	AR5K_RF5112_XPD_GAIN		{ 2, 252, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112_PWD(_n)		{ 1, (302 - _n), 3 }
+
+static const struct ath5k_rf_reg rf_regs_5112[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112_XPD_SEL},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5112_XPD_GAIN},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112_PWD(138)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5112[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
+	{ 6, 0x989c,
+	    { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
+	{ 6, 0x989c,
+	    { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
+	{ 6, 0x989c,
+	    { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
+	{ 6, 0x989c,
+	    { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
+	{ 6, 0x989c,
+	    { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
+	{ 6, 0x989c,
+	    { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
+	{ 6, 0x989c,
+	    { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
+	{ 6, 0x989c,
+	    { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
+	{ 6, 0x989c,
+	    { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
+	{ 6, 0x989c,
+	    { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
+	{ 6, 0x989c,
+	    { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
+	{ 6, 0x98d0,
+	    { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
+	{ 7, 0x989c,
+	    { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RFX112A (Derby 2) */
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5112A_OB_2GHZ		{ 3, 287, 0 }
+#define	AR5K_RF5112A_DB_2GHZ		{ 3, 290, 0 }
+
+#define	AR5K_RF5112A_OB_5GHZ		{ 3, 279, 0 }
+#define	AR5K_RF5112A_DB_5GHZ		{ 3, 282, 0 }
+
+#define	AR5K_RF5112A_FIXED_BIAS_A	{ 1, 278, 0 }
+#define	AR5K_RF5112A_FIXED_BIAS_B	{ 1, 277, 0 }
+
+#define	AR5K_RF5112A_XPD_SEL		{ 1, 302, 0 }
+#define	AR5K_RF5112A_PDGAINLO		{ 2, 270, 0 }
+#define	AR5K_RF5112A_PDGAINHI		{ 2, 257, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112A_PWD(_n)		{ 1, (306 - _n), 3 }
+
+/* Voltage regulators */
+#define	AR5K_RF5112A_HIGH_VC_CP		{ 2, 90,  2 }
+#define	AR5K_RF5112A_MID_VC_CP		{ 2, 92,  2 }
+#define	AR5K_RF5112A_LOW_VC_CP		{ 2, 94,  2 }
+#define	AR5K_RF5112A_PUSH_UP		{ 1, 254,  2 }
+
+/* Power consumption */
+#define	AR5K_RF5112A_PAD2GND		{ 1, 281, 1 }
+#define	AR5K_RF5112A_XB2_LVL		{ 2, 1,	  3 }
+#define	AR5K_RF5112A_XB5_LVL		{ 2, 3,	  3 }
+
+static const struct ath5k_rf_reg rf_regs_5112a[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112A_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112A_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112A_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112A_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112A_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112A_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112A_XPD_SEL},
+	{6, AR5K_RF_PD_GAIN_LO,		AR5K_RF5112A_PDGAINLO},
+	{6, AR5K_RF_PD_GAIN_HI,		AR5K_RF5112A_PDGAINHI},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112A_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112A_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112A_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112A_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112A_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112A_PWD(138)},
+	{6, AR5K_RF_PWD_166,		AR5K_RF5112A_PWD(166)},
+	{6, AR5K_RF_PWD_167,		AR5K_RF5112A_PWD(167)},
+	{6, AR5K_RF_HIGH_VC_CP,		AR5K_RF5112A_HIGH_VC_CP},
+	{6, AR5K_RF_MID_VC_CP,		AR5K_RF5112A_MID_VC_CP},
+	{6, AR5K_RF_LOW_VC_CP,		AR5K_RF5112A_LOW_VC_CP},
+	{6, AR5K_RF_PUSH_UP,		AR5K_RF5112A_PUSH_UP},
+	{6, AR5K_RF_PAD2GND,		AR5K_RF5112A_PAD2GND},
+	{6, AR5K_RF_XB2_LVL,		AR5K_RF5112A_XB2_LVL},
+	{6, AR5K_RF_XB5_LVL,		AR5K_RF5112A_XB5_LVL},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
+	{ 6, 0x989c,
+	    { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
+	{ 6, 0x989c,
+	    { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
+	{ 6, 0x989c,
+	    { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
+	{ 6, 0x989c,
+	    { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
+	{ 6, 0x989c,
+	    { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
+	{ 6, 0x989c,
+	    { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
+	{ 6, 0x989c,
+	    { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
+	{ 6, 0x989c,
+	    { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
+	{ 6, 0x989c,
+	    { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
+	{ 6, 0x989c,
+	    { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
+	{ 6, 0x989c,
+	    { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
+	{ 6, 0x989c,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
+	{ 6, 0x989c,
+	    { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
+	{ 6, 0x989c,
+	    { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
+	{ 6, 0x989c,
+	    { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
+	{ 6, 0x989c,
+	    { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
+	{ 6, 0x98d8,
+	    { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
+	{ 7, 0x989c,
+	    { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+
+
+/******************\
+* RF2413 (Griffin) *
+\******************/
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF2413_OB_2GHZ		{ 3, 168, 0 }
+#define	AR5K_RF2413_DB_2GHZ		{ 3, 165, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2413[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2413_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ???
+ */
+static const struct ath5k_ini_rfbuffer rfb_2413[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
+	{ 6, 0x989c,
+	    { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
+	{ 6, 0x989c,
+	    { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
+	{ 6, 0x989c,
+	    { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
+	{ 6, 0x989c,
+	    { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
+	{ 6, 0x989c,
+	    { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
+	{ 6, 0x989c,
+	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
+	{ 6, 0x989c,
+	    { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
+	{ 6, 0x989c,
+	    { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
+	{ 6, 0x989c,
+	    { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
+	{ 6, 0x989c,
+	    { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
+	{ 6, 0x989c,
+	    { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
+	{ 6, 0x989c,
+	    { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
+	{ 6, 0x98d8,
+	    { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***************************\
+* RF2315/RF2316 (Cobra SoC) *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2316_OB_2GHZ		{ 3, 178, 0 }
+#define	AR5K_RF2316_DB_2GHZ		{ 3, 175, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2316[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2316_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2316_DB_2GHZ},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_2316[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
+	{ 6, 0x989c,
+	    { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
+	{ 6, 0x989c,
+	    { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
+	{ 6, 0x989c,
+	    { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
+	{ 6, 0x989c,
+	    { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
+	{ 6, 0x989c,
+	    { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
+	{ 6, 0x989c,
+	    { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
+	{ 6, 0x989c,
+	    { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
+	{ 6, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 6, 0x989c,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 6, 0x989c,
+	    { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
+	{ 6, 0x989c,
+	    { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
+	{ 6, 0x98c0,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/******************************\
+* RF5413/RF5424 (Eagle/Condor) *
+\******************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5413_OB_2GHZ		{ 3, 241, 0 }
+#define	AR5K_RF5413_DB_2GHZ		{ 3, 238, 0 }
+
+#define	AR5K_RF5413_OB_5GHZ		{ 3, 247, 0 }
+#define	AR5K_RF5413_DB_5GHZ		{ 3, 244, 0 }
+
+#define	AR5K_RF5413_PWD_ICLOBUF2G	{ 3, 131, 3 }
+#define	AR5K_RF5413_DERBY_CHAN_SEL_MODE	{ 1, 291, 2 }
+
+static const struct ath5k_rf_reg rf_regs_5413[] = {
+	{6, AR5K_RF_OB_2GHZ,		 AR5K_RF5413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		 AR5K_RF5413_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		 AR5K_RF5413_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		 AR5K_RF5413_DB_5GHZ},
+	{6, AR5K_RF_PWD_ICLOBUF_2G,	 AR5K_RF5413_PWD_ICLOBUF2G},
+	{6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5413[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 3, 0x98dc,
+	    { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
+	{ 6, 0x989c,
+	    { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
+	{ 6, 0x989c,
+	    { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
+	{ 6, 0x989c,
+	    { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
+	{ 6, 0x989c,
+	    { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
+	{ 6, 0x989c,
+	    { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+	{ 6, 0x989c,
+	    { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
+	{ 6, 0x989c,
+	    { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
+	{ 6, 0x989c,
+	    { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
+	{ 6, 0x989c,
+	    { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
+	{ 6, 0x989c,
+	    { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
+	{ 6, 0x989c,
+	    { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
+	{ 6, 0x989c,
+	    { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } },
+	{ 6, 0x989c,
+	    { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
+	{ 6, 0x989c,
+	    { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } },
+	{ 6, 0x98c8,
+	    { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***************************\
+* RF2425/RF2417 (Swan/Nala) *
+* AR2317 (Spider SoC)       *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2425_OB_2GHZ		{ 3, 193, 0 }
+#define	AR5K_RF2425_DB_2GHZ		{ 3, 190, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2425[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2425_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2425_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2425[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ */
+static const struct ath5k_ini_rfbuffer rfb_2317[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2417[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfgain.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfgain.h
new file mode 100644
index 0000000..1354d8c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ath5k/rfgain.h
@@ -0,0 +1,516 @@
+/*
+ * RF Gain optimization
+ *
+ * Copyright (c) 2004-2009 Reyk Floeter <reyk at openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm at gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Mode-specific RF Gain table (64bytes) for RF5111/5112
+ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
+ * RF Gain values are included in AR5K_AR5210_INI)
+ */
+struct ath5k_ini_rfgain {
+	u16	rfg_register;	/* RF Gain register address */
+	u32	rfg_value[2];	/* [freq (see below)] */
+};
+
+/* Initial RF Gain settings for RF5111 */
+static const struct ath5k_ini_rfgain rfgain_5111[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x000001a9, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x000001e9, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000029, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000069, 0x00000150 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000199, 0x00000190 } },
+	{ AR5K_RF_GAIN(5),	{ 0x000001d9, 0x000001d0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000019, 0x00000010 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000059, 0x00000044 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000099, 0x00000084 } },
+	{ AR5K_RF_GAIN(9),	{ 0x000001a5, 0x00000148 } },
+	{ AR5K_RF_GAIN(10),	{ 0x000001e5, 0x00000188 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000025, 0x000001c8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001c8, 0x00000014 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000008, 0x00000042 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000048, 0x00000082 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000088, 0x00000178 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000198, 0x000001b8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001d8, 0x000001f8 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000018, 0x00000012 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000058, 0x00000052 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000098, 0x00000092 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001a4, 0x0000017c } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001e4, 0x000001bc } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000024, 0x000001fc } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000064, 0x0000000a } },
+	{ AR5K_RF_GAIN(25),	{ 0x000000a4, 0x0000004a } },
+	{ AR5K_RF_GAIN(26),	{ 0x000000e4, 0x0000008a } },
+	{ AR5K_RF_GAIN(27),	{ 0x0000010a, 0x0000015a } },
+	{ AR5K_RF_GAIN(28),	{ 0x0000014a, 0x0000019a } },
+	{ AR5K_RF_GAIN(29),	{ 0x0000018a, 0x000001da } },
+	{ AR5K_RF_GAIN(30),	{ 0x000001ca, 0x0000000e } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000000a, 0x0000004e } },
+	{ AR5K_RF_GAIN(32),	{ 0x0000004a, 0x0000008e } },
+	{ AR5K_RF_GAIN(33),	{ 0x0000008a, 0x0000015e } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ba, 0x0000019e } },
+	{ AR5K_RF_GAIN(35),	{ 0x000001fa, 0x000001de } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000009 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000049 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000186, 0x00000089 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001c6, 0x00000179 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000006, 0x000001b9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000046, 0x000001f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000086, 0x00000039 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000c6, 0x00000079 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000c6, 0x000000b9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000c6, 0x000001bd } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000c6, 0x000001fd } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000c6, 0x0000003d } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000c6, 0x0000007d } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000c6, 0x000000bd } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000c6, 0x000000fd } },
+};
+
+/* Initial RF Gain settings for RF5112 */
+static const struct ath5k_ini_rfgain rfgain_5112[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000007, 0x00000007 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000047, 0x00000047 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000087, 0x00000087 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a0, 0x000001a0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e0, 0x000001e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000020, 0x00000020 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000060, 0x00000060 } },
+	{ AR5K_RF_GAIN(7),	{ 0x000001a1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001e1, 0x000001e1 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000021, 0x00000021 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000061, 0x00000061 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000162, 0x00000162 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a2, 0x000001a2 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e2, 0x000001e2 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000022, 0x00000022 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000062, 0x00000062 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000163, 0x00000163 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001a3, 0x000001a3 } },
+	{ AR5K_RF_GAIN(18),	{ 0x000001e3, 0x000001e3 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000023, 0x00000023 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000063, 0x00000063 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000184, 0x00000184 } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001c4, 0x000001c4 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000004, 0x00000004 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001ea, 0x0000000b } },
+	{ AR5K_RF_GAIN(25),	{ 0x0000002a, 0x0000004b } },
+	{ AR5K_RF_GAIN(26),	{ 0x0000006a, 0x0000008b } },
+	{ AR5K_RF_GAIN(27),	{ 0x000000aa, 0x000001ac } },
+	{ AR5K_RF_GAIN(28),	{ 0x000001ab, 0x000001ec } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001eb, 0x0000002c } },
+	{ AR5K_RF_GAIN(30),	{ 0x0000002b, 0x00000012 } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000006b, 0x00000052 } },
+	{ AR5K_RF_GAIN(32),	{ 0x000000ab, 0x00000092 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000001ac, 0x00000193 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ec, 0x000001d3 } },
+	{ AR5K_RF_GAIN(35),	{ 0x0000002c, 0x00000013 } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000053 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000093 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000ba, 0x00000194 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001bb, 0x000001d4 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000001fb, 0x00000014 } },
+	{ AR5K_RF_GAIN(41),	{ 0x0000003b, 0x0000003a } },
+	{ AR5K_RF_GAIN(42),	{ 0x0000007b, 0x0000007a } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000bb, 0x000000ba } },
+	{ AR5K_RF_GAIN(44),	{ 0x000001bc, 0x000001bb } },
+	{ AR5K_RF_GAIN(45),	{ 0x000001fc, 0x000001fb } },
+	{ AR5K_RF_GAIN(46),	{ 0x0000003c, 0x0000003b } },
+	{ AR5K_RF_GAIN(47),	{ 0x0000007c, 0x0000007b } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000bc, 0x000000bb } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000fc, 0x000001bc } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000fc, 0x000001fc } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000fc, 0x0000003c } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000fc, 0x0000007c } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000fc, 0x000000bc } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000fc, 0x000000fc } },
+};
+
+/* Initial RF Gain settings for RF2413 */
+static const struct ath5k_ini_rfgain rfgain_2413[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000191 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001d1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000011 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000051 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x00000091 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x00000178 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x00000199 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000001d9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000019 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x00000059 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x00000099 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000d9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+/* Initial RF Gain settings for AR2316 */
+static const struct ath5k_ini_rfgain rfgain_2316[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x000000c0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000000a8 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x00000170 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000000b0 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f0 } },
+};
+
+
+/* Initial RF Gain settings for RF5413 */
+static const struct ath5k_ini_rfgain rfgain_5413[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000040, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000080, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a1, 0x00000161 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000021, 0x000001e1 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000061, 0x00000021 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000188, 0x00000061 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001c8, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000008, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000048, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000088, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a9, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e9, 0x00000169 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000029, 0x000001a9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000069, 0x000001e9 } },
+	{ AR5K_RF_GAIN(16),	{ 0x000001d0, 0x00000029 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000010, 0x00000069 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000050, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000090, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x000001b1, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001f1, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000031, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000071, 0x00000171 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001b8, 0x000001b1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x000001f8, 0x000001f1 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000038, 0x00000031 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000078, 0x00000071 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000199, 0x00000198 } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001d9, 0x000001d8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000019, 0x00000018 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000059, 0x00000058 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000099, 0x00000098 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000000d9, 0x00000179 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000000f9, 0x000001b9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x000000f9, 0x000001f9 } },
+	{ AR5K_RF_GAIN(36),	{ 0x000000f9, 0x00000039 } },
+	{ AR5K_RF_GAIN(37),	{ 0x000000f9, 0x00000079 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000f9, 0x000000b9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000f9, 0x000000f9 } },
+};
+
+
+/* Initial RF Gain settings for RF2425 */
+static const struct ath5k_ini_rfgain rfgain_2425[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000171 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x000001b1 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001f1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000031 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000071 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000b8 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000001b9 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000001f9 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x00000039 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000079 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000b9 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+#define AR5K_GAIN_CRN_FIX_BITS_5111		4
+#define AR5K_GAIN_CRN_FIX_BITS_5112		7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
+#define AR5K_GAIN_CCK_PROBE_CORR		5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
+#define AR5K_GAIN_STEP_COUNT			10
+
+/* Check if our current measurement is inside our
+ * current variable attenuation window */
+#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
+	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+	s8				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+	s8				gos_gain;
+};
+
+struct ath5k_gain_opt {
+	u8				go_default;
+	u8				go_steps_count;
+	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Tx clip PHY register
+ * 2) PWD 90 RF register
+ * 3) PWD 84 RF register
+ * 4) RFGainSel RF register
+ */
+static const struct ath5k_gain_opt rfgain_opt_5111 = {
+	4,
+	9,
+	{
+		{ { 4, 1, 1, 1 }, 6 },
+		{ { 4, 0, 1, 1 }, 4 },
+		{ { 3, 1, 1, 1 }, 3 },
+		{ { 4, 0, 0, 1 }, 1 },
+		{ { 4, 1, 1, 0 }, 0 },
+		{ { 4, 0, 1, 0 }, -2 },
+		{ { 3, 1, 1, 0 }, -3 },
+		{ { 4, 0, 0, 0 }, -4 },
+		{ { 2, 1, 1, 0 }, -6 }
+	}
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Mixgain ovr RF register
+ * 2) PWD 138 RF register
+ * 3) PWD 137 RF register
+ * 4) PWD 136 RF register
+ * 5) PWD 132 RF register
+ * 6) PWD 131 RF register
+ * 7) PWD 130 RF register
+ */
+static const struct ath5k_gain_opt rfgain_opt_5112 = {
+	1,
+	8,
+	{
+		{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
+		{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
+		{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
+		{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
+		{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
+		{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
+		{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
+		{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
+	}
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.c
new file mode 100644
index 0000000..e4dd5c9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.c
@@ -0,0 +1,1749 @@
+/*
+ * Copyright(c) 2007 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * Modified for iPXE, October 2009 by Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "atl1e.h"
+
+/* User-tweakable parameters: */
+#define TX_DESC_COUNT	32	/* TX descriptors, minimum 32 */
+#define RX_MEM_SIZE	8192	/* RX area size, minimum 8kb */
+#define MAX_FRAME_SIZE	1500	/* Maximum MTU supported, minimum 1500 */
+
+/* Arcane parameters: */
+#define PREAMBLE_LEN	7
+#define RX_JUMBO_THRESH	((MAX_FRAME_SIZE + ETH_HLEN + \
+			  VLAN_HLEN + ETH_FCS_LEN + 7) >> 3)
+#define IMT_VAL		100	/* interrupt moderator timer, us */
+#define ICT_VAL		50000	/* interrupt clear timer, us */
+#define SMB_TIMER	200000
+#define RRD_THRESH	1	/* packets to queue before interrupt */
+#define TPD_BURST	5
+#define TPD_THRESH	(TX_DESC_COUNT / 2)
+#define RX_COUNT_DOWN	4
+#define TX_COUNT_DOWN	(IMT_VAL * 4 / 3)
+#define DMAR_DLY_CNT	15
+#define DMAW_DLY_CNT	4
+
+#define PCI_DEVICE_ID_ATTANSIC_L1E      0x1026
+
+/*
+ * atl1e_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id atl1e_pci_tbl[] = {
+	PCI_ROM(0x1969, 0x1026, "atl1e_26", "Attansic L1E 0x1026", 0),
+	PCI_ROM(0x1969, 0x1066, "atl1e_66", "Attansic L1E 0x1066", 0),
+};
+
+static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter);
+
+static const u16
+atl1e_rx_page_vld_regs[AT_PAGE_NUM_PER_QUEUE] =
+{
+	REG_HOST_RXF0_PAGE0_VLD, REG_HOST_RXF0_PAGE1_VLD
+};
+
+static const u16
+atl1e_rx_page_lo_addr_regs[AT_PAGE_NUM_PER_QUEUE] =
+{
+	REG_HOST_RXF0_PAGE0_LO, REG_HOST_RXF0_PAGE1_LO
+};
+
+static const u16
+atl1e_rx_page_write_offset_regs[AT_PAGE_NUM_PER_QUEUE] =
+{
+	REG_HOST_RXF0_MB0_LO,  REG_HOST_RXF0_MB1_LO
+};
+
+static const u16 atl1e_pay_load_size[] = {
+	128, 256, 512, 1024, 2048, 4096,
+};
+
+/*
+ * atl1e_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static inline void atl1e_irq_enable(struct atl1e_adapter *adapter)
+{
+	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
+	AT_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK);
+	AT_WRITE_FLUSH(&adapter->hw);
+}
+
+/*
+ * atl1e_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1e_irq_disable(struct atl1e_adapter *adapter)
+{
+	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+	AT_WRITE_FLUSH(&adapter->hw);
+}
+
+/*
+ * atl1e_irq_reset - reset interrupt confiure on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1e_irq_reset(struct atl1e_adapter *adapter)
+{
+	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
+	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+	AT_WRITE_FLUSH(&adapter->hw);
+}
+
+static void atl1e_reset(struct atl1e_adapter *adapter)
+{
+	atl1e_down(adapter);
+	atl1e_up(adapter);
+}
+
+static int atl1e_check_link(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int err = 0;
+	u16 speed, duplex, phy_data;
+
+	/* MII_BMSR must read twise */
+	atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
+	atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
+
+	if ((phy_data & BMSR_LSTATUS) == 0) {
+		/* link down */
+		if (netdev_link_ok(netdev)) { /* old link state: Up */
+			u32 value;
+			/* disable rx */
+			value = AT_READ_REG(hw, REG_MAC_CTRL);
+			value &= ~MAC_CTRL_RX_EN;
+			AT_WRITE_REG(hw, REG_MAC_CTRL, value);
+			adapter->link_speed = SPEED_0;
+
+			DBG("atl1e: %s link is down\n", netdev->name);
+			netdev_link_down(netdev);
+		}
+	} else {
+		/* Link Up */
+		err = atl1e_get_speed_and_duplex(hw, &speed, &duplex);
+		if (err)
+			return err;
+
+		/* link result is our setting */
+		if (adapter->link_speed != speed ||
+		    adapter->link_duplex != duplex) {
+			adapter->link_speed  = speed;
+			adapter->link_duplex = duplex;
+			atl1e_setup_mac_ctrl(adapter);
+
+			DBG("atl1e: %s link is up, %d Mbps, %s duplex\n",
+			    netdev->name, adapter->link_speed,
+			    adapter->link_duplex == FULL_DUPLEX ?
+			    "full" : "half");
+			netdev_link_up(netdev);
+		}
+	}
+	return 0;
+}
+
+static int atl1e_mdio_read(struct net_device *netdev, int phy_id __unused,
+			   int reg_num)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+	u16 result;
+
+	atl1e_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result);
+	return result;
+}
+
+static void atl1e_mdio_write(struct net_device *netdev, int phy_id __unused,
+			     int reg_num, int val)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+
+	atl1e_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val);
+}
+
+static void atl1e_setup_pcicmd(struct pci_device *pdev)
+{
+	u16 cmd;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd |=  (PCI_COMMAND_MEM | PCI_COMMAND_MASTER);
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	/*
+	 * some motherboards BIOS(PXE/EFI) driver may set PME
+	 * while they transfer control to OS (Windows/Linux)
+	 * so we should clear this bit before NIC work normally
+	 */
+	pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0);
+	mdelay(1);
+}
+
+/*
+ * atl1e_sw_init - Initialize general software structures (struct atl1e_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1e_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int atl1e_sw_init(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = &adapter->hw;
+	struct pci_device *pdev = adapter->pdev;
+	u32 phy_status_data = 0;
+	u8 rev_id = 0;
+
+	adapter->link_speed = SPEED_0;   /* hardware init */
+	adapter->link_duplex = FULL_DUPLEX;
+
+	/* PCI config space info */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+	phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS);
+	/* nic type */
+	if (rev_id >= 0xF0) {
+		hw->nic_type = athr_l2e_revB;
+	} else {
+		if (phy_status_data & PHY_STATUS_100M)
+			hw->nic_type = athr_l1e;
+		else
+			hw->nic_type = athr_l2e_revA;
+	}
+
+	phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS);
+
+	hw->emi_ca = !!(phy_status_data & PHY_STATUS_EMI_CA);
+
+	hw->phy_configured = 0;
+
+	/* need confirm */
+
+	hw->dmar_block = atl1e_dma_req_1024;
+	hw->dmaw_block = atl1e_dma_req_1024;
+
+	return 0;
+}
+
+/*
+ * atl1e_clean_tx_ring - free all Tx buffers for device close
+ * @adapter: board private structure
+ */
+static void atl1e_clean_tx_ring(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *)
+				&adapter->tx_ring;
+	struct atl1e_tx_buffer *tx_buffer = NULL;
+	u16 index, ring_count = tx_ring->count;
+
+	if (tx_ring->desc == NULL || tx_ring->tx_buffer == NULL)
+		return;
+
+	for (index = 0; index < ring_count; index++) {
+		tx_buffer = &tx_ring->tx_buffer[index];
+		if (tx_buffer->iob) {
+			netdev_tx_complete(adapter->netdev, tx_buffer->iob);
+			tx_buffer->dma = 0;
+			tx_buffer->iob = NULL;
+		}
+	}
+
+	/* Zero out Tx-buffers */
+	memset(tx_ring->desc, 0, sizeof(struct atl1e_tpd_desc) *
+	       ring_count);
+	memset(tx_ring->tx_buffer, 0, sizeof(struct atl1e_tx_buffer) *
+	       ring_count);
+}
+
+/*
+ * atl1e_clean_rx_ring - Free rx-reservation iobs
+ * @adapter: board private structure
+ */
+static void atl1e_clean_rx_ring(struct atl1e_adapter *adapter)
+{
+	struct atl1e_rx_ring *rx_ring =
+		(struct atl1e_rx_ring *)&adapter->rx_ring;
+	struct atl1e_rx_page_desc *rx_page_desc = &rx_ring->rx_page_desc;
+	u16 j;
+
+	if (adapter->ring_vir_addr == NULL)
+		return;
+
+	/* Zero out the descriptor ring */
+	for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
+		if (rx_page_desc->rx_page[j].addr != NULL) {
+			memset(rx_page_desc->rx_page[j].addr, 0,
+			       rx_ring->real_page_size);
+		}
+	}
+}
+
+static void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size)
+{
+	*ring_size = ((u32)(adapter->tx_ring.count *
+		     sizeof(struct atl1e_tpd_desc) + 7
+			/* tx ring, qword align */
+		     + adapter->rx_ring.real_page_size * AT_PAGE_NUM_PER_QUEUE
+		     + 31
+			/* rx ring,  32 bytes align */
+		     + (1 + AT_PAGE_NUM_PER_QUEUE) *
+			sizeof(u32) + 3));
+			/* tx, rx cmd, dword align   */
+}
+
+static void atl1e_init_ring_resources(struct atl1e_adapter *adapter)
+{
+	struct atl1e_rx_ring *rx_ring = &adapter->rx_ring;
+
+	rx_ring->real_page_size = adapter->rx_ring.page_size
+				 + MAX_FRAME_SIZE
+				 + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+	rx_ring->real_page_size = (rx_ring->real_page_size + 31) & ~31;
+	atl1e_cal_ring_size(adapter, &adapter->ring_size);
+
+	adapter->ring_vir_addr = NULL;
+	adapter->rx_ring.desc = NULL;
+
+	return;
+}
+
+/*
+ * Read / Write Ptr Initialize:
+ */
+static void atl1e_init_ring_ptrs(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring = NULL;
+	struct atl1e_rx_ring *rx_ring = NULL;
+	struct atl1e_rx_page_desc *rx_page_desc = NULL;
+	int j;
+
+	tx_ring = &adapter->tx_ring;
+	rx_ring = &adapter->rx_ring;
+	rx_page_desc = &rx_ring->rx_page_desc;
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	rx_page_desc->rx_using  = 0;
+	rx_page_desc->rx_nxseq = 0;
+	for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
+		*rx_page_desc->rx_page[j].write_offset_addr = 0;
+		rx_page_desc->rx_page[j].read_offset = 0;
+	}
+}
+
+/*
+ * atl1e_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void atl1e_free_ring_resources(struct atl1e_adapter *adapter)
+{
+	atl1e_clean_tx_ring(adapter);
+	atl1e_clean_rx_ring(adapter);
+
+	if (adapter->ring_vir_addr) {
+		free_dma(adapter->ring_vir_addr, adapter->ring_size);
+		adapter->ring_vir_addr = NULL;
+		adapter->ring_dma = 0;
+	}
+
+	if (adapter->tx_ring.tx_buffer) {
+		free(adapter->tx_ring.tx_buffer);
+		adapter->tx_ring.tx_buffer = NULL;
+	}
+}
+
+/*
+ * atl1e_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring;
+	struct atl1e_rx_ring *rx_ring;
+	struct atl1e_rx_page_desc  *rx_page_desc;
+	int size, j;
+	u32 offset = 0;
+	int err = 0;
+
+	if (adapter->ring_vir_addr != NULL)
+		return 0; /* alloced already */
+
+	tx_ring = &adapter->tx_ring;
+	rx_ring = &adapter->rx_ring;
+
+	/* real ring DMA buffer */
+
+	size = adapter->ring_size;
+	adapter->ring_vir_addr = malloc_dma(adapter->ring_size, 32);
+
+	if (adapter->ring_vir_addr == NULL) {
+		DBG("atl1e: out of memory allocating %d bytes for %s ring\n",
+		    adapter->ring_size, adapter->netdev->name);
+		return -ENOMEM;
+	}
+
+	adapter->ring_dma = virt_to_bus(adapter->ring_vir_addr);
+	memset(adapter->ring_vir_addr, 0, adapter->ring_size);
+
+	rx_page_desc = &rx_ring->rx_page_desc;
+
+	/* Init TPD Ring */
+	tx_ring->dma = (adapter->ring_dma + 7) & ~7;
+	offset = tx_ring->dma - adapter->ring_dma;
+	tx_ring->desc = (struct atl1e_tpd_desc *)
+			(adapter->ring_vir_addr + offset);
+	size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count);
+	tx_ring->tx_buffer = zalloc(size);
+	if (tx_ring->tx_buffer == NULL) {
+		DBG("atl1e: out of memory allocating %d bytes for %s txbuf\n",
+		    size, adapter->netdev->name);
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	/* Init RXF-Pages */
+	offset += (sizeof(struct atl1e_tpd_desc) * tx_ring->count);
+	offset = (offset + 31) & ~31;
+
+	for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
+		rx_page_desc->rx_page[j].dma =
+			adapter->ring_dma + offset;
+		rx_page_desc->rx_page[j].addr =
+			adapter->ring_vir_addr + offset;
+		offset += rx_ring->real_page_size;
+	}
+
+	/* Init CMB dma address */
+	tx_ring->cmb_dma = adapter->ring_dma + offset;
+	tx_ring->cmb     = (u32 *)(adapter->ring_vir_addr + offset);
+	offset += sizeof(u32);
+
+	for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
+		rx_page_desc->rx_page[j].write_offset_dma =
+			adapter->ring_dma + offset;
+		rx_page_desc->rx_page[j].write_offset_addr =
+			adapter->ring_vir_addr + offset;
+		offset += sizeof(u32);
+	}
+
+	if (offset > adapter->ring_size) {
+		DBG("atl1e: ring miscalculation! need %d > %d bytes\n",
+		    offset, adapter->ring_size);
+		err = -EINVAL;
+		goto failed;
+	}
+
+	return 0;
+failed:
+	atl1e_free_ring_resources(adapter);
+	return err;
+}
+
+static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter)
+{
+
+	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
+	struct atl1e_rx_ring *rx_ring =
+			(struct atl1e_rx_ring *)&adapter->rx_ring;
+	struct atl1e_tx_ring *tx_ring =
+			(struct atl1e_tx_ring *)&adapter->tx_ring;
+	struct atl1e_rx_page_desc *rx_page_desc = NULL;
+	int j;
+
+	AT_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, 0);
+	AT_WRITE_REG(hw, REG_TPD_BASE_ADDR_LO, tx_ring->dma);
+	AT_WRITE_REG(hw, REG_TPD_RING_SIZE, (u16)(tx_ring->count));
+	AT_WRITE_REG(hw, REG_HOST_TX_CMB_LO, tx_ring->cmb_dma);
+
+	rx_page_desc = &rx_ring->rx_page_desc;
+
+	/* RXF Page Physical address / Page Length */
+	AT_WRITE_REG(hw, REG_RXF0_BASE_ADDR_HI, 0);
+
+	for (j = 0; j < AT_PAGE_NUM_PER_QUEUE; j++) {
+		u32 page_phy_addr;
+		u32 offset_phy_addr;
+
+		page_phy_addr = rx_page_desc->rx_page[j].dma;
+		offset_phy_addr = rx_page_desc->rx_page[j].write_offset_dma;
+
+		AT_WRITE_REG(hw, atl1e_rx_page_lo_addr_regs[j], page_phy_addr);
+		AT_WRITE_REG(hw, atl1e_rx_page_write_offset_regs[j],
+			     offset_phy_addr);
+		AT_WRITE_REGB(hw, atl1e_rx_page_vld_regs[j], 1);
+	}
+
+	/* Page Length */
+	AT_WRITE_REG(hw, REG_HOST_RXFPAGE_SIZE, rx_ring->page_size);
+	/* Load all of base address above */
+	AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
+
+	return;
+}
+
+static inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
+	u32 dev_ctrl_data = 0;
+	u32 max_pay_load = 0;
+	u32 jumbo_thresh = 0;
+	u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
+
+	/* configure TXQ param */
+	if (hw->nic_type != athr_l2e_revB) {
+		extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+		jumbo_thresh = MAX_FRAME_SIZE + extra_size;
+		AT_WRITE_REG(hw, REG_TX_EARLY_TH, (jumbo_thresh + 7) >> 3);
+	}
+
+	dev_ctrl_data = AT_READ_REG(hw, REG_DEVICE_CTRL);
+
+	max_pay_load  = ((dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT)) &
+			DEVICE_CTRL_MAX_PAYLOAD_MASK;
+	if (max_pay_load < hw->dmaw_block)
+		hw->dmaw_block = max_pay_load;
+
+	max_pay_load  = ((dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT)) &
+			DEVICE_CTRL_MAX_RREQ_SZ_MASK;
+	if (max_pay_load < hw->dmar_block)
+		hw->dmar_block = max_pay_load;
+
+	if (hw->nic_type != athr_l2e_revB)
+		AT_WRITE_REGW(hw, REG_TXQ_CTRL + 2,
+			      atl1e_pay_load_size[hw->dmar_block]);
+	/* enable TXQ */
+	AT_WRITE_REGW(hw, REG_TXQ_CTRL,
+			((TPD_BURST & TXQ_CTRL_NUM_TPD_BURST_MASK)
+			 << TXQ_CTRL_NUM_TPD_BURST_SHIFT)
+			| TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN);
+	return;
+}
+
+static inline void atl1e_configure_rx(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = (struct atl1e_hw *)&adapter->hw;
+	u32 rxf_len  = 0;
+	u32 rxf_low  = 0;
+	u32 rxf_high = 0;
+	u32 rxf_thresh_data = 0;
+	u32 rxq_ctrl_data = 0;
+
+	if (hw->nic_type != athr_l2e_revB) {
+		AT_WRITE_REGW(hw, REG_RXQ_JMBOSZ_RRDTIM,
+			      (u16)((RX_JUMBO_THRESH & RXQ_JMBOSZ_TH_MASK) <<
+			      RXQ_JMBOSZ_TH_SHIFT |
+			      (1 & RXQ_JMBO_LKAH_MASK) <<
+			      RXQ_JMBO_LKAH_SHIFT));
+
+		rxf_len  = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
+		rxf_high = rxf_len * 4 / 5;
+		rxf_low  = rxf_len / 5;
+		rxf_thresh_data = ((rxf_high  & RXQ_RXF_PAUSE_TH_HI_MASK)
+				  << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+				  ((rxf_low & RXQ_RXF_PAUSE_TH_LO_MASK)
+				  << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+
+		AT_WRITE_REG(hw, REG_RXQ_RXF_PAUSE_THRESH, rxf_thresh_data);
+	}
+
+	/* RRS */
+	AT_WRITE_REG(hw, REG_IDT_TABLE, 0);
+	AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, 0);
+
+	rxq_ctrl_data |= RXQ_CTRL_PBA_ALIGN_32 |
+			 RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+
+	AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
+	return;
+}
+
+static inline void atl1e_configure_dma(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = &adapter->hw;
+	u32 dma_ctrl_data = 0;
+
+	dma_ctrl_data = DMA_CTRL_RXCMB_EN;
+	dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+		<< DMA_CTRL_DMAR_BURST_LEN_SHIFT;
+	dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK)
+		<< DMA_CTRL_DMAW_BURST_LEN_SHIFT;
+	dma_ctrl_data |= DMA_CTRL_DMAR_REQ_PRI | DMA_CTRL_DMAR_OUT_ORDER;
+	dma_ctrl_data |= (DMAR_DLY_CNT & DMA_CTRL_DMAR_DLY_CNT_MASK)
+		<< DMA_CTRL_DMAR_DLY_CNT_SHIFT;
+	dma_ctrl_data |= (DMAW_DLY_CNT & DMA_CTRL_DMAW_DLY_CNT_MASK)
+		<< DMA_CTRL_DMAW_DLY_CNT_SHIFT;
+
+	AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
+	return;
+}
+
+static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter)
+{
+	u32 value;
+	struct atl1e_hw *hw = &adapter->hw;
+
+	/* Config MAC CTRL Register */
+	value = MAC_CTRL_TX_EN |
+		MAC_CTRL_RX_EN ;
+
+	if (FULL_DUPLEX == adapter->link_duplex)
+		value |= MAC_CTRL_DUPLX;
+
+	value |= ((u32)((SPEED_1000 == adapter->link_speed) ?
+			  MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
+			  MAC_CTRL_SPEED_SHIFT);
+	value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+
+	value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+	value |= ((PREAMBLE_LEN & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+
+	value |= MAC_CTRL_BC_EN;
+	value |= MAC_CTRL_MC_ALL_EN;
+
+	AT_WRITE_REG(hw, REG_MAC_CTRL, value);
+}
+
+/*
+ * atl1e_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static int atl1e_configure(struct atl1e_adapter *adapter)
+{
+	struct atl1e_hw *hw = &adapter->hw;
+	u32 intr_status_data = 0;
+
+	/* clear interrupt status */
+	AT_WRITE_REG(hw, REG_ISR, ~0);
+
+	/* 1. set MAC Address */
+	atl1e_hw_set_mac_addr(hw);
+
+	/* 2. Init the Multicast HASH table (clear) */
+	AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+	/* 3. Clear any WOL status */
+	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+
+	/* 4. Descripter Ring BaseMem/Length/Read ptr/Write ptr
+	 *    TPD Ring/SMB/RXF0 Page CMBs, they use the same
+	 *    High 32bits memory */
+	atl1e_configure_des_ring(adapter);
+
+	/* 5. set Interrupt Moderator Timer */
+	AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, IMT_VAL);
+	AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER2_INIT, IMT_VAL);
+	AT_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_LED_MODE |
+			MASTER_CTRL_ITIMER_EN | MASTER_CTRL_ITIMER2_EN);
+
+	/* 6. rx/tx threshold to trig interrupt */
+	AT_WRITE_REGW(hw, REG_TRIG_RRD_THRESH, RRD_THRESH);
+	AT_WRITE_REGW(hw, REG_TRIG_TPD_THRESH, TPD_THRESH);
+	AT_WRITE_REGW(hw, REG_TRIG_RXTIMER, RX_COUNT_DOWN);
+	AT_WRITE_REGW(hw, REG_TRIG_TXTIMER, TX_COUNT_DOWN);
+
+	/* 7. set Interrupt Clear Timer */
+	AT_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, ICT_VAL);
+
+	/* 8. set MTU */
+	AT_WRITE_REG(hw, REG_MTU, MAX_FRAME_SIZE + ETH_HLEN +
+			VLAN_HLEN + ETH_FCS_LEN);
+
+	/* 9. config TXQ early tx threshold */
+	atl1e_configure_tx(adapter);
+
+	/* 10. config RXQ */
+	atl1e_configure_rx(adapter);
+
+	/* 11. config  DMA Engine */
+	atl1e_configure_dma(adapter);
+
+	/* 12. smb timer to trig interrupt */
+	AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, SMB_TIMER);
+
+	intr_status_data = AT_READ_REG(hw, REG_ISR);
+	if ((intr_status_data & ISR_PHY_LINKDOWN) != 0) {
+		DBG("atl1e: configure failed, PCIE phy link down\n");
+		return -1;
+	}
+
+	AT_WRITE_REG(hw, REG_ISR, 0x7fffffff);
+	return 0;
+}
+
+static inline void atl1e_clear_phy_int(struct atl1e_adapter *adapter)
+{
+	u16 phy_data;
+
+	atl1e_read_phy_reg(&adapter->hw, MII_INT_STATUS, &phy_data);
+}
+
+static int atl1e_clean_tx_irq(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring = (struct atl1e_tx_ring *)
+					&adapter->tx_ring;
+	struct atl1e_tx_buffer *tx_buffer = NULL;
+	u16 hw_next_to_clean = AT_READ_REGW(&adapter->hw, REG_TPD_CONS_IDX);
+	u16 next_to_clean = tx_ring->next_to_clean;
+
+	while (next_to_clean != hw_next_to_clean) {
+		tx_buffer = &tx_ring->tx_buffer[next_to_clean];
+
+		tx_buffer->dma = 0;
+		if (tx_buffer->iob) {
+			netdev_tx_complete(adapter->netdev, tx_buffer->iob);
+			tx_buffer->iob = NULL;
+		}
+
+		if (++next_to_clean == tx_ring->count)
+			next_to_clean = 0;
+	}
+
+	tx_ring->next_to_clean = next_to_clean;
+
+	return 1;
+}
+
+static struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter)
+{
+	struct atl1e_rx_page_desc *rx_page_desc =
+		(struct atl1e_rx_page_desc *) &adapter->rx_ring.rx_page_desc;
+	u8 rx_using = rx_page_desc->rx_using;
+
+	return (struct atl1e_rx_page *)&(rx_page_desc->rx_page[rx_using]);
+}
+
+static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter)
+{
+	struct net_device *netdev  = adapter->netdev;
+	struct atl1e_rx_ring *rx_ring = (struct atl1e_rx_ring *)
+					 &adapter->rx_ring;
+	struct atl1e_rx_page_desc *rx_page_desc =
+		(struct atl1e_rx_page_desc *) &rx_ring->rx_page_desc;
+	struct io_buffer *iob = NULL;
+	struct atl1e_rx_page *rx_page = atl1e_get_rx_page(adapter);
+	u32 packet_size, write_offset;
+	struct atl1e_recv_ret_status *prrs;
+
+	write_offset = *(rx_page->write_offset_addr);
+	if (rx_page->read_offset >= write_offset)
+		return;
+
+	do {
+		/* get new packet's  rrs */
+		prrs = (struct atl1e_recv_ret_status *) (rx_page->addr +
+							 rx_page->read_offset);
+		/* check sequence number */
+		if (prrs->seq_num != rx_page_desc->rx_nxseq) {
+			DBG("atl1e %s: RX sequence number error (%d != %d)\n",
+			    netdev->name, prrs->seq_num,
+			    rx_page_desc->rx_nxseq);
+			rx_page_desc->rx_nxseq++;
+			goto fatal_err;
+		}
+
+		rx_page_desc->rx_nxseq++;
+
+		/* error packet */
+		if (prrs->pkt_flag & RRS_IS_ERR_FRAME) {
+			if (prrs->err_flag & (RRS_ERR_BAD_CRC |
+					      RRS_ERR_DRIBBLE | RRS_ERR_CODE |
+					      RRS_ERR_TRUNC)) {
+				/* hardware error, discard this
+				   packet */
+				netdev_rx_err(netdev, NULL, EIO);
+				goto skip_pkt;
+			}
+		}
+
+		packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
+			       RRS_PKT_SIZE_MASK) - ETH_FCS_LEN;
+		iob = alloc_iob(packet_size + NET_IP_ALIGN);
+		if (iob == NULL) {
+			DBG("atl1e %s: dropping packet under memory pressure\n",
+			    netdev->name);
+			goto skip_pkt;
+		}
+		iob_reserve(iob, NET_IP_ALIGN);
+		memcpy(iob->data, (u8 *)(prrs + 1), packet_size);
+		iob_put(iob, packet_size);
+
+		netdev_rx(netdev, iob);
+
+skip_pkt:
+		/* skip current packet whether it's ok or not. */
+		rx_page->read_offset +=
+			(((u32)((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
+				RRS_PKT_SIZE_MASK) +
+			  sizeof(struct atl1e_recv_ret_status) + 31) &
+			 0xFFFFFFE0);
+
+		if (rx_page->read_offset >= rx_ring->page_size) {
+			/* mark this page clean */
+			u16 reg_addr;
+			u8  rx_using;
+
+			rx_page->read_offset =
+				*(rx_page->write_offset_addr) = 0;
+			rx_using = rx_page_desc->rx_using;
+			reg_addr =
+				atl1e_rx_page_vld_regs[rx_using];
+			AT_WRITE_REGB(&adapter->hw, reg_addr, 1);
+			rx_page_desc->rx_using ^= 1;
+			rx_page = atl1e_get_rx_page(adapter);
+		}
+		write_offset = *(rx_page->write_offset_addr);
+	} while (rx_page->read_offset < write_offset);
+
+	return;
+
+fatal_err:
+	if (!netdev_link_ok(adapter->netdev))
+		atl1e_reset(adapter);
+}
+
+/*
+ * atl1e_poll - poll for completed transmissions and received packets
+ * @netdev: network device
+ */
+static void atl1e_poll(struct net_device *netdev)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+	struct atl1e_hw *hw = &adapter->hw;
+	int max_ints = 64;
+	u32 status;
+
+	do {
+		status = AT_READ_REG(hw, REG_ISR);
+		if ((status & IMR_NORMAL_MASK) == 0)
+			break;
+
+		/* link event */
+		if (status & ISR_GPHY)
+			atl1e_clear_phy_int(adapter);
+		/* Ack ISR */
+		AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
+
+		/* check if PCIE PHY Link down */
+		if (status & ISR_PHY_LINKDOWN) {
+			DBG("atl1e: PCI-E PHY link down: %x\n", status);
+			if (netdev_link_ok(adapter->netdev)) {
+				/* reset MAC */
+				atl1e_irq_reset(adapter);
+				atl1e_reset(adapter);
+				break;
+			}
+		}
+
+		/* check if DMA read/write error */
+		if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+			DBG("atl1e: PCI-E DMA RW error: %x\n", status);
+			atl1e_irq_reset(adapter);
+			atl1e_reset(adapter);
+			break;
+		}
+
+		/* link event */
+		if (status & (ISR_GPHY | ISR_MANUAL)) {
+			atl1e_check_link(adapter);
+			break;
+		}
+
+		/* transmit event */
+		if (status & ISR_TX_EVENT)
+			atl1e_clean_tx_irq(adapter);
+
+		if (status & ISR_RX_EVENT)
+			atl1e_clean_rx_irq(adapter);
+	} while (--max_ints > 0);
+
+	/* re-enable Interrupt*/
+	AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
+
+	return;
+}
+
+static inline u16 atl1e_tpd_avail(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
+	u16 next_to_use = 0;
+	u16 next_to_clean = 0;
+
+	next_to_clean = tx_ring->next_to_clean;
+	next_to_use   = tx_ring->next_to_use;
+
+	return (u16)(next_to_clean > next_to_use) ?
+		(next_to_clean - next_to_use - 1) :
+		(tx_ring->count + next_to_clean - next_to_use - 1);
+}
+
+/*
+ * get next usable tpd
+ * Note: should call atl1e_tdp_avail to make sure
+ * there is enough tpd to use
+ */
+static struct atl1e_tpd_desc *atl1e_get_tpd(struct atl1e_adapter *adapter)
+{
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
+	u16 next_to_use = 0;
+
+	next_to_use = tx_ring->next_to_use;
+	if (++tx_ring->next_to_use == tx_ring->count)
+		tx_ring->next_to_use = 0;
+
+	memset(&tx_ring->desc[next_to_use], 0, sizeof(struct atl1e_tpd_desc));
+	return (struct atl1e_tpd_desc *)&tx_ring->desc[next_to_use];
+}
+
+static struct atl1e_tx_buffer *
+atl1e_get_tx_buffer(struct atl1e_adapter *adapter, struct atl1e_tpd_desc *tpd)
+{
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
+
+	return &tx_ring->tx_buffer[tpd - tx_ring->desc];
+}
+
+static void atl1e_tx_map(struct atl1e_adapter *adapter,
+		      struct io_buffer *iob, struct atl1e_tpd_desc *tpd)
+{
+	struct atl1e_tx_buffer *tx_buffer = NULL;
+	u16 buf_len = iob_len(iob);
+
+	tx_buffer = atl1e_get_tx_buffer(adapter, tpd);
+	tx_buffer->iob = iob;
+	tx_buffer->length = buf_len;
+	tx_buffer->dma = virt_to_bus(iob->data);
+	tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
+	tpd->word2 = ((tpd->word2 & ~TPD_BUFLEN_MASK) |
+		      ((cpu_to_le32(buf_len) & TPD_BUFLEN_MASK) <<
+		       TPD_BUFLEN_SHIFT));
+	tpd->word3 |= 1 << TPD_EOP_SHIFT;
+}
+
+static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count __unused,
+			   struct atl1e_tpd_desc *tpd __unused)
+{
+	struct atl1e_tx_ring *tx_ring = &adapter->tx_ring;
+	wmb();
+	AT_WRITE_REG(&adapter->hw, REG_MB_TPD_PROD_IDX, tx_ring->next_to_use);
+}
+
+static int atl1e_xmit_frame(struct net_device *netdev, struct io_buffer *iob)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+	u16 tpd_req = 1;
+	struct atl1e_tpd_desc *tpd;
+
+	if (!netdev_link_ok(netdev)) {
+		return -EINVAL;
+	}
+
+	if (atl1e_tpd_avail(adapter) < tpd_req) {
+		return -EBUSY;
+	}
+
+	tpd = atl1e_get_tpd(adapter);
+
+	atl1e_tx_map(adapter, iob, tpd);
+	atl1e_tx_queue(adapter, tpd_req, tpd);
+
+	return 0;
+}
+
+int atl1e_up(struct atl1e_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err = 0;
+	u32 val;
+
+	/* hardware has been reset, we need to reload some things */
+	err = atl1e_init_hw(&adapter->hw);
+	if (err) {
+		return -EIO;
+	}
+	atl1e_init_ring_ptrs(adapter);
+
+	memcpy(adapter->hw.mac_addr, netdev->ll_addr, ETH_ALEN);
+
+	if (atl1e_configure(adapter) != 0) {
+		return -EIO;
+	}
+
+	atl1e_irq_disable(adapter);
+
+	val = AT_READ_REG(&adapter->hw, REG_MASTER_CTRL);
+	AT_WRITE_REG(&adapter->hw, REG_MASTER_CTRL,
+		      val | MASTER_CTRL_MANUAL_INT);
+
+	return err;
+}
+
+void atl1e_irq(struct net_device *netdev, int enable)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+
+	if (enable)
+		atl1e_irq_enable(adapter);
+	else
+		atl1e_irq_disable(adapter);
+}
+
+void atl1e_down(struct atl1e_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	/* reset MAC to disable all RX/TX */
+	atl1e_reset_hw(&adapter->hw);
+	mdelay(1);
+
+	netdev_link_down(netdev);
+	adapter->link_speed = SPEED_0;
+	adapter->link_duplex = -1;
+
+	atl1e_clean_tx_ring(adapter);
+	atl1e_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1e_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1e_open(struct net_device *netdev)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	/* allocate rx/tx dma buffer & descriptors */
+	atl1e_init_ring_resources(adapter);
+	err = atl1e_setup_ring_resources(adapter);
+	if (err)
+		return err;
+
+	err = atl1e_up(adapter);
+	if (err)
+		goto err_up;
+
+	return 0;
+
+err_up:
+	atl1e_free_ring_resources(adapter);
+	atl1e_reset_hw(&adapter->hw);
+
+	return err;
+}
+
+/*
+ * atl1e_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static void atl1e_close(struct net_device *netdev)
+{
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+
+	atl1e_down(adapter);
+	atl1e_free_ring_resources(adapter);
+}
+
+static struct net_device_operations atl1e_netdev_ops = {
+	.open		= atl1e_open,
+	.close		= atl1e_close,
+	.transmit	= atl1e_xmit_frame,
+	.poll		= atl1e_poll,
+	.irq		= atl1e_irq,
+};
+
+static void atl1e_init_netdev(struct net_device *netdev, struct pci_device *pdev)
+{
+	netdev_init(netdev, &atl1e_netdev_ops);
+
+	netdev->dev = &pdev->dev;
+	pci_set_drvdata(pdev, netdev);
+}
+
+/*
+ * atl1e_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1e_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1e_probe initializes an adapter identified by a pci_device structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int atl1e_probe(struct pci_device *pdev)
+{
+	struct net_device *netdev;
+	struct atl1e_adapter *adapter = NULL;
+	static int cards_found;
+
+	int err = 0;
+
+	adjust_pci_device(pdev);
+
+	netdev = alloc_etherdev(sizeof(struct atl1e_adapter));
+	if (netdev == NULL) {
+		err = -ENOMEM;
+		DBG("atl1e: out of memory allocating net_device\n");
+		goto err;
+	}
+
+	atl1e_init_netdev(netdev, pdev);
+
+	adapter = netdev_priv(netdev);
+	adapter->bd_number = cards_found;
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->hw.adapter = adapter;
+	if (!pdev->membase) {
+		err = -EIO;
+		DBG("atl1e: cannot map device registers\n");
+		goto err_free_netdev;
+	}
+	adapter->hw.hw_addr = bus_to_virt(pdev->membase);
+
+	/* init mii data */
+	adapter->mii.dev = netdev;
+	adapter->mii.mdio_read  = atl1e_mdio_read;
+	adapter->mii.mdio_write = atl1e_mdio_write;
+	adapter->mii.phy_id_mask = 0x1f;
+	adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK;
+
+	/* get user settings */
+	adapter->tx_ring.count = TX_DESC_COUNT;
+	adapter->rx_ring.page_size = RX_MEM_SIZE;
+
+	atl1e_setup_pcicmd(pdev);
+
+	/* setup the private structure */
+	err = atl1e_sw_init(adapter);
+	if (err) {
+		DBG("atl1e: private data init failed\n");
+		goto err_free_netdev;
+	}
+
+	/* Init GPHY as early as possible due to power saving issue  */
+	atl1e_phy_init(&adapter->hw);
+
+	/* reset the controller to
+	 * put the device in a known good starting state */
+	err = atl1e_reset_hw(&adapter->hw);
+	if (err) {
+		err = -EIO;
+		goto err_free_netdev;
+	}
+
+	/* This may have been run by a zero-wait timer around
+	   now... unclear. */
+	atl1e_restart_autoneg(&adapter->hw);
+
+	if (atl1e_read_mac_addr(&adapter->hw) != 0) {
+		DBG("atl1e: cannot read MAC address from EEPROM\n");
+		err = -EIO;
+		goto err_free_netdev;
+	}
+
+	memcpy(netdev->hw_addr, adapter->hw.perm_mac_addr, ETH_ALEN);
+	memcpy(netdev->ll_addr, adapter->hw.mac_addr, ETH_ALEN);
+	DBG("atl1e: Attansic L1E Ethernet controller on %s, "
+	    "%02x:%02x:%02x:%02x:%02x:%02x\n", adapter->netdev->name,
+	    adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
+	    adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
+	    adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+
+	err = register_netdev(netdev);
+	if (err) {
+		DBG("atl1e: cannot register network device\n");
+		goto err_free_netdev;
+	}
+
+	cards_found++;
+	return 0;
+
+err_free_netdev:
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+err:
+	return err;
+}
+
+/*
+ * atl1e_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1e_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void atl1e_remove(struct pci_device *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+	atl1e_free_ring_resources(adapter);
+	atl1e_force_ps(&adapter->hw);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+struct pci_driver atl1e_driver __pci_driver = {
+	.ids      = atl1e_pci_tbl,
+	.id_count = (sizeof(atl1e_pci_tbl) / sizeof(atl1e_pci_tbl[0])),
+	.probe    = atl1e_probe,
+	.remove   = atl1e_remove,
+};
+
+/********** Hardware-level functions: **********/
+
+/*
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+int atl1e_check_eeprom_exist(struct atl1e_hw *hw)
+{
+	u32 value;
+
+	value = AT_READ_REG(hw, REG_SPI_FLASH_CTRL);
+	if (value & SPI_FLASH_CTRL_EN_VPD) {
+		value &= ~SPI_FLASH_CTRL_EN_VPD;
+		AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
+	}
+	value = AT_READ_REGW(hw, REG_PCIE_CAP_LIST);
+	return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+void atl1e_hw_set_mac_addr(struct atl1e_hw *hw)
+{
+	u32 value;
+	/*
+	 * 00-0B-6A-F6-00-DC
+	 * 0:  6AF600DC 1: 000B
+	 * low dword
+	 */
+	value = (((u32)hw->mac_addr[2]) << 24) |
+		(((u32)hw->mac_addr[3]) << 16) |
+		(((u32)hw->mac_addr[4]) << 8)  |
+		(((u32)hw->mac_addr[5])) ;
+	AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
+	/* hight dword */
+	value = (((u32)hw->mac_addr[0]) << 8) |
+		(((u32)hw->mac_addr[1])) ;
+	AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
+}
+
+/*
+ * atl1e_get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int atl1e_get_permanent_address(struct atl1e_hw *hw)
+{
+	union {
+		u32 dword[2];
+		u8 byte[8];
+	} hw_addr;
+	u32 i;
+	u32 twsi_ctrl_data;
+	u8  eth_addr[ETH_ALEN];
+
+	if (!atl1e_check_eeprom_exist(hw)) {
+		/* eeprom exist */
+		twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL);
+		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
+		AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
+		for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
+			mdelay(10);
+			twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL);
+			if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
+				break;
+		}
+		if (i >= AT_TWSI_EEPROM_TIMEOUT)
+			return AT_ERR_TIMEOUT;
+	}
+
+	/* maybe MAC-address is from BIOS */
+	hw_addr.dword[0] = AT_READ_REG(hw, REG_MAC_STA_ADDR);
+	hw_addr.dword[1] = AT_READ_REG(hw, REG_MAC_STA_ADDR + 4);
+	for (i = 0; i < ETH_ALEN; i++) {
+		eth_addr[ETH_ALEN - i - 1] = hw_addr.byte[i];
+	}
+
+	memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+	return 0;
+}
+
+void atl1e_force_ps(struct atl1e_hw *hw)
+{
+	AT_WRITE_REGW(hw, REG_GPHY_CTRL,
+			GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET);
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+int atl1e_read_mac_addr(struct atl1e_hw *hw)
+{
+	int err = 0;
+
+	err = atl1e_get_permanent_address(hw);
+	if (err)
+		return AT_ERR_EEPROM;
+	memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
+	return 0;
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+int atl1e_read_phy_reg(struct atl1e_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+	u32 val;
+	int i;
+
+	val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+		MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW |
+		MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+
+	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+	wmb();
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = AT_READ_REG(hw, REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+		wmb();
+	}
+	if (!(val & (MDIO_START | MDIO_BUSY))) {
+		*phy_data = (u16)val;
+		return 0;
+	}
+
+	return AT_ERR_PHY;
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+int atl1e_write_phy_reg(struct atl1e_hw *hw, u32 reg_addr, u16 phy_data)
+{
+	int i;
+	u32 val;
+
+	val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+	       (reg_addr&MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+	       MDIO_SUP_PREAMBLE |
+	       MDIO_START |
+	       MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+
+	AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+	wmb();
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = AT_READ_REG(hw, REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+		wmb();
+	}
+
+	if (!(val & (MDIO_START | MDIO_BUSY)))
+		return 0;
+
+	return AT_ERR_PHY;
+}
+
+/*
+ * atl1e_init_pcie - init PCIE module
+ */
+static void atl1e_init_pcie(struct atl1e_hw *hw)
+{
+	u32 value;
+	/* comment 2lines below to save more power when sususpend
+	   value = LTSSM_TEST_MODE_DEF;
+	   AT_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value);
+	 */
+
+	/* pcie flow control mode change */
+	value = AT_READ_REG(hw, 0x1008);
+	value |= 0x8000;
+	AT_WRITE_REG(hw, 0x1008, value);
+}
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw)
+{
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg;
+
+	if (0 != hw->mii_autoneg_adv_reg)
+		return 0;
+	/* Read the MII Auto-Neg Advertisement Register (Address 4/9). */
+	mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+	mii_1000t_ctrl_reg  = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+	mii_1000t_ctrl_reg  &= ~MII_AT001_CR_1000T_SPEED_MASK;
+
+	/* Assume auto-detect media type */
+	mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS   |
+				MII_AR_10T_FD_CAPS   |
+				MII_AR_100TX_HD_CAPS |
+				MII_AR_100TX_FD_CAPS);
+	if (hw->nic_type == athr_l1e) {
+		mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+	}
+
+	/* flow control fixed to enable all */
+	mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+	hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+	hw->mii_1000t_ctrl_reg  = mii_1000t_ctrl_reg;
+
+	ret_val = atl1e_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+	if (ret_val)
+		return ret_val;
+
+	if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) {
+		ret_val = atl1e_write_phy_reg(hw, MII_AT001_CR,
+					   mii_1000t_ctrl_reg);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Resets the PHY and make all config validate
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII control regiser (for F001 bug)
+ */
+int atl1e_phy_commit(struct atl1e_hw *hw)
+{
+	int ret_val;
+	u16 phy_data;
+
+	phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
+
+	ret_val = atl1e_write_phy_reg(hw, MII_BMCR, phy_data);
+	if (ret_val) {
+		u32 val;
+		int i;
+		/**************************************
+		 * pcie serdes link may be down !
+		 **************************************/
+		for (i = 0; i < 25; i++) {
+			mdelay(1);
+			val = AT_READ_REG(hw, REG_MDIO_CTRL);
+			if (!(val & (MDIO_START | MDIO_BUSY)))
+				break;
+		}
+
+		if (0 != (val & (MDIO_START | MDIO_BUSY))) {
+			DBG("atl1e: PCI-E link down for at least 25ms\n");
+			return ret_val;
+		}
+
+		DBG("atl1e: PCI-E link up after %d ms\n", i);
+	}
+	return 0;
+}
+
+int atl1e_phy_init(struct atl1e_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_val;
+
+	if (hw->phy_configured) {
+		if (hw->re_autoneg) {
+			hw->re_autoneg = 0;
+			return atl1e_restart_autoneg(hw);
+		}
+		return 0;
+	}
+
+	/* RESET GPHY Core */
+	AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT);
+	mdelay(2);
+	AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
+		      GPHY_CTRL_EXT_RESET);
+	mdelay(2);
+
+	/* patches */
+	/* p1. eable hibernation mode */
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0xB);
+	if (ret_val)
+		return ret_val;
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0xBC00);
+	if (ret_val)
+		return ret_val;
+	/* p2. set Class A/B for all modes */
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0);
+	if (ret_val)
+		return ret_val;
+	phy_val = 0x02ef;
+	/* remove Class AB */
+	/* phy_val = hw->emi_ca ? 0x02ef : 0x02df; */
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, phy_val);
+	if (ret_val)
+		return ret_val;
+	/* p3. 10B ??? */
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x12);
+	if (ret_val)
+		return ret_val;
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x4C04);
+	if (ret_val)
+		return ret_val;
+	/* p4. 1000T power */
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x4);
+	if (ret_val)
+		return ret_val;
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x8BBB);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x5);
+	if (ret_val)
+		return ret_val;
+	ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x2C46);
+	if (ret_val)
+		return ret_val;
+
+	mdelay(1);
+
+	/*Enable PHY LinkChange Interrupt */
+	ret_val = atl1e_write_phy_reg(hw, MII_INT_CTRL, 0xC00);
+	if (ret_val) {
+		DBG("atl1e: Error enable PHY linkChange Interrupt\n");
+		return ret_val;
+	}
+	/* setup AutoNeg parameters */
+	ret_val = atl1e_phy_setup_autoneg_adv(hw);
+	if (ret_val) {
+		DBG("atl1e: Error Setting up Auto-Negotiation\n");
+		return ret_val;
+	}
+	/* SW.Reset & En-Auto-Neg to restart Auto-Neg*/
+	DBG("atl1e: Restarting Auto-Neg");
+	ret_val = atl1e_phy_commit(hw);
+	if (ret_val) {
+		DBG("atl1e: Error Resetting the phy");
+		return ret_val;
+	}
+
+	hw->phy_configured = 1;
+
+	return 0;
+}
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+int atl1e_reset_hw(struct atl1e_hw *hw)
+{
+	struct atl1e_adapter *adapter = hw->adapter;
+	struct pci_device *pdev = adapter->pdev;
+	int timeout = 0;
+	u32 idle_status_data = 0;
+	u16 pci_cfg_cmd_word = 0;
+
+	/* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_cfg_cmd_word);
+	if ((pci_cfg_cmd_word & (PCI_COMMAND_IO | PCI_COMMAND_MEM |
+				 PCI_COMMAND_MASTER))
+			!= (PCI_COMMAND_IO | PCI_COMMAND_MEM |
+			    PCI_COMMAND_MASTER)) {
+		pci_cfg_cmd_word |= (PCI_COMMAND_IO | PCI_COMMAND_MEM |
+				     PCI_COMMAND_MASTER);
+		pci_write_config_word(pdev, PCI_COMMAND, pci_cfg_cmd_word);
+	}
+
+	/*
+	 * Issue Soft Reset to the MAC.  This will reset the chip's
+	 * transmit, receive, DMA.  It will not effect
+	 * the current PCI configuration.  The global reset bit is self-
+	 * clearing, and should clear within a microsecond.
+	 */
+	AT_WRITE_REG(hw, REG_MASTER_CTRL,
+			MASTER_CTRL_LED_MODE | MASTER_CTRL_SOFT_RST);
+	wmb();
+	mdelay(1);
+
+	/* Wait at least 10ms for All module to be Idle */
+	for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+		idle_status_data = AT_READ_REG(hw, REG_IDLE_STATUS);
+		if (idle_status_data == 0)
+			break;
+		mdelay(1);
+	}
+
+	if (timeout >= AT_HW_MAX_IDLE_DELAY) {
+		DBG("atl1e: MAC reset timeout\n");
+		return AT_ERR_TIMEOUT;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes multicast table,
+ * and  Calls routines to setup link
+ * Leaves the transmit and receive units disabled and uninitialized.
+ */
+int atl1e_init_hw(struct atl1e_hw *hw)
+{
+	s32 ret_val = 0;
+
+	atl1e_init_pcie(hw);
+
+	/* Zero out the Multicast HASH table */
+	/* clear the old settings from the multicast hash table */
+	AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+	AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+	ret_val = atl1e_phy_init(hw);
+
+	return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+int atl1e_get_speed_and_duplex(struct atl1e_hw *hw, u16 *speed, u16 *duplex)
+{
+	int err;
+	u16 phy_data;
+
+	/* Read   PHY Specific Status Register (17) */
+	err = atl1e_read_phy_reg(hw, MII_AT001_PSSR, &phy_data);
+	if (err)
+		return err;
+
+	if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED))
+		return AT_ERR_PHY_RES;
+
+	switch (phy_data & MII_AT001_PSSR_SPEED) {
+	case MII_AT001_PSSR_1000MBS:
+		*speed = SPEED_1000;
+		break;
+	case MII_AT001_PSSR_100MBS:
+		*speed = SPEED_100;
+		break;
+	case MII_AT001_PSSR_10MBS:
+		*speed = SPEED_10;
+		break;
+	default:
+		return AT_ERR_PHY_SPEED;
+		break;
+	}
+
+	if (phy_data & MII_AT001_PSSR_DPLX)
+		*duplex = FULL_DUPLEX;
+	else
+		*duplex = HALF_DUPLEX;
+
+	return 0;
+}
+
+int atl1e_restart_autoneg(struct atl1e_hw *hw)
+{
+	int err = 0;
+
+	err = atl1e_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+	if (err)
+		return err;
+
+	if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) {
+		err = atl1e_write_phy_reg(hw, MII_AT001_CR,
+				       hw->mii_1000t_ctrl_reg);
+		if (err)
+			return err;
+	}
+
+	err = atl1e_write_phy_reg(hw, MII_BMCR,
+			MII_CR_RESET | MII_CR_AUTO_NEG_EN |
+			MII_CR_RESTART_AUTO_NEG);
+	return err;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.h
new file mode 100644
index 0000000..e759ea4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/atl1e.h
@@ -0,0 +1,1033 @@
+/*
+ * Copyright(c) 2007 Atheros Corporation. All rights reserved.
+ * Copyright(c) 2007 xiong huang <xiong.huang at atheros.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * Modified for iPXE, October 2009 by Joshua Oreman <oremanj at rwcr.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _ATL1E_H_
+#define _ATL1E_H_
+
+#include <mii.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/pci_io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+
+#define ETH_FCS_LEN	4
+#define VLAN_HLEN	4
+#define NET_IP_ALIGN	2
+
+#define SPEED_0		   0xffff
+#define SPEED_10	   10
+#define SPEED_100	   100
+#define SPEED_1000	   1000
+#define HALF_DUPLEX        1
+#define FULL_DUPLEX        2
+
+/* Error Codes */
+#define AT_ERR_EEPROM      1
+#define AT_ERR_PHY         2
+#define AT_ERR_CONFIG      3
+#define AT_ERR_PARAM       4
+#define AT_ERR_MAC_TYPE    5
+#define AT_ERR_PHY_TYPE    6
+#define AT_ERR_PHY_SPEED   7
+#define AT_ERR_PHY_RES     8
+#define AT_ERR_TIMEOUT     9
+
+#define AT_MAX_RECEIVE_QUEUE    4
+#define AT_PAGE_NUM_PER_QUEUE   2
+
+#define AT_TWSI_EEPROM_TIMEOUT 	100
+#define AT_HW_MAX_IDLE_DELAY 	10
+
+#define AT_REGS_LEN	75
+#define AT_EEPROM_LEN 	512
+
+/* tpd word 2 */
+#define TPD_BUFLEN_MASK 	0x3FFF
+#define TPD_BUFLEN_SHIFT        0
+
+/* tpd word 3 bits 0:4 */
+#define TPD_EOP_MASK            0x0001
+#define TPD_EOP_SHIFT           0
+
+struct atl1e_tpd_desc {
+	u64 buffer_addr;
+	u32 word2;
+	u32 word3;
+};
+
+#define MAX_TX_BUF_LEN      0x2000
+#define MAX_TX_BUF_SHIFT    13
+
+/* rrs word 1 bit 0:31 */
+#define RRS_RX_CSUM_MASK	0xFFFF
+#define RRS_RX_CSUM_SHIFT	0
+#define RRS_PKT_SIZE_MASK	0x3FFF
+#define RRS_PKT_SIZE_SHIFT	16
+#define RRS_CPU_NUM_MASK	0x0003
+#define	RRS_CPU_NUM_SHIFT	30
+
+#define	RRS_IS_RSS_IPV4		0x0001
+#define RRS_IS_RSS_IPV4_TCP	0x0002
+#define RRS_IS_RSS_IPV6		0x0004
+#define RRS_IS_RSS_IPV6_TCP	0x0008
+#define RRS_IS_IPV6		0x0010
+#define RRS_IS_IP_FRAG		0x0020
+#define RRS_IS_IP_DF		0x0040
+#define RRS_IS_802_3		0x0080
+#define RRS_IS_VLAN_TAG		0x0100
+#define RRS_IS_ERR_FRAME	0x0200
+#define RRS_IS_IPV4		0x0400
+#define RRS_IS_UDP		0x0800
+#define RRS_IS_TCP		0x1000
+#define RRS_IS_BCAST		0x2000
+#define RRS_IS_MCAST		0x4000
+#define RRS_IS_PAUSE		0x8000
+
+#define RRS_ERR_BAD_CRC		0x0001
+#define RRS_ERR_CODE		0x0002
+#define RRS_ERR_DRIBBLE		0x0004
+#define RRS_ERR_RUNT		0x0008
+#define RRS_ERR_RX_OVERFLOW	0x0010
+#define RRS_ERR_TRUNC		0x0020
+#define RRS_ERR_IP_CSUM		0x0040
+#define RRS_ERR_L4_CSUM		0x0080
+#define RRS_ERR_LENGTH		0x0100
+#define RRS_ERR_DES_ADDR	0x0200
+
+struct atl1e_recv_ret_status {
+	u16 seq_num;
+	u16 hash_lo;
+	u32 word1;
+	u16 pkt_flag;
+	u16 err_flag;
+	u16 hash_hi;
+	u16 vtag;
+};
+
+enum atl1e_dma_req_block {
+	atl1e_dma_req_128 = 0,
+	atl1e_dma_req_256 = 1,
+	atl1e_dma_req_512 = 2,
+	atl1e_dma_req_1024 = 3,
+	atl1e_dma_req_2048 = 4,
+	atl1e_dma_req_4096 = 5
+};
+
+enum atl1e_nic_type {
+	athr_l1e = 0,
+	athr_l2e_revA = 1,
+	athr_l2e_revB = 2
+};
+
+struct atl1e_hw {
+	u8 *hw_addr;            /* inner register address */
+	struct atl1e_adapter *adapter;
+	enum atl1e_nic_type  nic_type;
+	u8 mac_addr[ETH_ALEN];
+	u8 perm_mac_addr[ETH_ALEN];
+
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg;
+
+	enum atl1e_dma_req_block dmar_block;
+	enum atl1e_dma_req_block dmaw_block;
+
+	int phy_configured;
+	int re_autoneg;
+	int emi_ca;
+};
+
+/*
+ * wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct atl1e_tx_buffer {
+	struct io_buffer *iob;
+	u16 length;
+	u32 dma;
+};
+
+struct atl1e_rx_page {
+	u32		dma;    /* receive rage DMA address */
+	u8		*addr;   /* receive rage virtual address */
+	u32		write_offset_dma;  /* the DMA address which contain the
+					      receive data offset in the page */
+	u32		*write_offset_addr; /* the virtaul address which contain
+					     the receive data offset in the page */
+	u32		read_offset;       /* the offset where we have read */
+};
+
+struct atl1e_rx_page_desc {
+	struct atl1e_rx_page   rx_page[AT_PAGE_NUM_PER_QUEUE];
+	u8  rx_using;
+	u16 rx_nxseq;
+};
+
+/* transmit packet descriptor (tpd) ring */
+struct atl1e_tx_ring {
+	struct atl1e_tpd_desc *desc;  /* descriptor ring virtual address  */
+	u32		   dma;    /* descriptor ring physical address */
+	u16       	   count;  /* the count of transmit rings  */
+	u16		   next_to_use;
+	u16		   next_to_clean;
+	struct atl1e_tx_buffer *tx_buffer;
+	u32		   cmb_dma;
+	u32		   *cmb;
+};
+
+/* receive packet descriptor ring */
+struct atl1e_rx_ring {
+	void        	*desc;
+	u32	  	dma;
+	int         	size;
+	u32	    	page_size; /* bytes length of rxf page */
+	u32		real_page_size; /* real_page_size = page_size + jumbo + aliagn */
+	struct atl1e_rx_page_desc rx_page_desc;
+};
+
+/* board specific private data structure */
+struct atl1e_adapter {
+	struct net_device   *netdev;
+	struct pci_device   *pdev;
+	struct mii_if_info  mii;    /* MII interface info */
+	struct atl1e_hw        hw;
+
+	u16 link_speed;
+	u16 link_duplex;
+
+	/* All Descriptor memory */
+	u32	  	ring_dma;
+	void     	*ring_vir_addr;
+	u32             ring_size;
+
+	struct atl1e_tx_ring tx_ring;
+	struct atl1e_rx_ring rx_ring;
+
+	int bd_number;     /* board number;*/
+};
+
+#define AT_WRITE_REG(a, reg, value) \
+		writel((value), ((a)->hw_addr + reg))
+
+#define AT_WRITE_FLUSH(a) \
+		readl((a)->hw_addr)
+
+#define AT_READ_REG(a, reg) \
+		readl((a)->hw_addr + reg)
+
+#define AT_WRITE_REGB(a, reg, value) \
+		writeb((value), ((a)->hw_addr + reg))
+
+#define AT_READ_REGB(a, reg) \
+		readb((a)->hw_addr + reg)
+
+#define AT_WRITE_REGW(a, reg, value) \
+		writew((value), ((a)->hw_addr + reg))
+
+#define AT_READ_REGW(a, reg) \
+		readw((a)->hw_addr + reg)
+
+#define AT_WRITE_REG_ARRAY(a, reg, offset, value) \
+		writel((value), (((a)->hw_addr + reg) + ((offset) << 2)))
+
+#define AT_READ_REG_ARRAY(a, reg, offset) \
+		readl(((a)->hw_addr + reg) + ((offset) << 2))
+
+extern int atl1e_up(struct atl1e_adapter *adapter);
+extern void atl1e_down(struct atl1e_adapter *adapter);
+extern s32 atl1e_reset_hw(struct atl1e_hw *hw);
+
+/********** Hardware-level functionality: **********/
+
+/* function prototype */
+s32 atl1e_reset_hw(struct atl1e_hw *hw);
+s32 atl1e_read_mac_addr(struct atl1e_hw *hw);
+s32 atl1e_init_hw(struct atl1e_hw *hw);
+s32 atl1e_phy_commit(struct atl1e_hw *hw);
+s32 atl1e_get_speed_and_duplex(struct atl1e_hw *hw, u16 *speed, u16 *duplex);
+u32 atl1e_auto_get_fc(struct atl1e_adapter *adapter, u16 duplex);
+s32 atl1e_read_phy_reg(struct atl1e_hw *hw, u16 reg_addr, u16 *phy_data);
+s32 atl1e_write_phy_reg(struct atl1e_hw *hw, u32 reg_addr, u16 phy_data);
+s32 atl1e_validate_mdi_setting(struct atl1e_hw *hw);
+void atl1e_hw_set_mac_addr(struct atl1e_hw *hw);
+s32 atl1e_phy_enter_power_saving(struct atl1e_hw *hw);
+s32 atl1e_phy_leave_power_saving(struct atl1e_hw *hw);
+s32 atl1e_phy_init(struct atl1e_hw *hw);
+int atl1e_check_eeprom_exist(struct atl1e_hw *hw);
+void atl1e_force_ps(struct atl1e_hw *hw);
+s32 atl1e_restart_autoneg(struct atl1e_hw *hw);
+
+/* register definition */
+#define REG_PM_CTRLSTAT             0x44
+
+#define REG_PCIE_CAP_LIST           0x58
+
+#define REG_DEVICE_CAP              0x5C
+#define     DEVICE_CAP_MAX_PAYLOAD_MASK     0x7
+#define     DEVICE_CAP_MAX_PAYLOAD_SHIFT    0
+
+#define REG_DEVICE_CTRL             0x60
+#define     DEVICE_CTRL_MAX_PAYLOAD_MASK    0x7
+#define     DEVICE_CTRL_MAX_PAYLOAD_SHIFT   5
+#define     DEVICE_CTRL_MAX_RREQ_SZ_MASK    0x7
+#define     DEVICE_CTRL_MAX_RREQ_SZ_SHIFT   12
+
+#define REG_VPD_CAP                 0x6C
+#define     VPD_CAP_ID_MASK                 0xff
+#define     VPD_CAP_ID_SHIFT                0
+#define     VPD_CAP_NEXT_PTR_MASK           0xFF
+#define     VPD_CAP_NEXT_PTR_SHIFT          8
+#define     VPD_CAP_VPD_ADDR_MASK           0x7FFF
+#define     VPD_CAP_VPD_ADDR_SHIFT          16
+#define     VPD_CAP_VPD_FLAG                0x80000000
+
+#define REG_VPD_DATA                0x70
+
+#define REG_SPI_FLASH_CTRL          0x200
+#define     SPI_FLASH_CTRL_STS_NON_RDY      0x1
+#define     SPI_FLASH_CTRL_STS_WEN          0x2
+#define     SPI_FLASH_CTRL_STS_WPEN         0x80
+#define     SPI_FLASH_CTRL_DEV_STS_MASK     0xFF
+#define     SPI_FLASH_CTRL_DEV_STS_SHIFT    0
+#define     SPI_FLASH_CTRL_INS_MASK         0x7
+#define     SPI_FLASH_CTRL_INS_SHIFT        8
+#define     SPI_FLASH_CTRL_START            0x800
+#define     SPI_FLASH_CTRL_EN_VPD           0x2000
+#define     SPI_FLASH_CTRL_LDSTART          0x8000
+#define     SPI_FLASH_CTRL_CS_HI_MASK       0x3
+#define     SPI_FLASH_CTRL_CS_HI_SHIFT      16
+#define     SPI_FLASH_CTRL_CS_HOLD_MASK     0x3
+#define     SPI_FLASH_CTRL_CS_HOLD_SHIFT    18
+#define     SPI_FLASH_CTRL_CLK_LO_MASK      0x3
+#define     SPI_FLASH_CTRL_CLK_LO_SHIFT     20
+#define     SPI_FLASH_CTRL_CLK_HI_MASK      0x3
+#define     SPI_FLASH_CTRL_CLK_HI_SHIFT     22
+#define     SPI_FLASH_CTRL_CS_SETUP_MASK    0x3
+#define     SPI_FLASH_CTRL_CS_SETUP_SHIFT   24
+#define     SPI_FLASH_CTRL_EROM_PGSZ_MASK   0x3
+#define     SPI_FLASH_CTRL_EROM_PGSZ_SHIFT  26
+#define     SPI_FLASH_CTRL_WAIT_READY       0x10000000
+
+#define REG_SPI_ADDR                0x204
+
+#define REG_SPI_DATA                0x208
+
+#define REG_SPI_FLASH_CONFIG        0x20C
+#define     SPI_FLASH_CONFIG_LD_ADDR_MASK   0xFFFFFF
+#define     SPI_FLASH_CONFIG_LD_ADDR_SHIFT  0
+#define     SPI_FLASH_CONFIG_VPD_ADDR_MASK  0x3
+#define     SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24
+#define     SPI_FLASH_CONFIG_LD_EXIST       0x4000000
+
+
+#define REG_SPI_FLASH_OP_PROGRAM    0x210
+#define REG_SPI_FLASH_OP_SC_ERASE   0x211
+#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212
+#define REG_SPI_FLASH_OP_RDID       0x213
+#define REG_SPI_FLASH_OP_WREN       0x214
+#define REG_SPI_FLASH_OP_RDSR       0x215
+#define REG_SPI_FLASH_OP_WRSR       0x216
+#define REG_SPI_FLASH_OP_READ       0x217
+
+#define REG_TWSI_CTRL               0x218
+#define     TWSI_CTRL_LD_OFFSET_MASK        0xFF
+#define     TWSI_CTRL_LD_OFFSET_SHIFT       0
+#define     TWSI_CTRL_LD_SLV_ADDR_MASK      0x7
+#define     TWSI_CTRL_LD_SLV_ADDR_SHIFT     8
+#define     TWSI_CTRL_SW_LDSTART            0x800
+#define     TWSI_CTRL_HW_LDSTART            0x1000
+#define     TWSI_CTRL_SMB_SLV_ADDR_MASK     0x0x7F
+#define     TWSI_CTRL_SMB_SLV_ADDR_SHIFT    15
+#define     TWSI_CTRL_LD_EXIST              0x400000
+#define     TWSI_CTRL_READ_FREQ_SEL_MASK    0x3
+#define     TWSI_CTRL_READ_FREQ_SEL_SHIFT   23
+#define     TWSI_CTRL_FREQ_SEL_100K         0
+#define     TWSI_CTRL_FREQ_SEL_200K         1
+#define     TWSI_CTRL_FREQ_SEL_300K         2
+#define     TWSI_CTRL_FREQ_SEL_400K         3
+#define     TWSI_CTRL_SMB_SLV_ADDR
+#define     TWSI_CTRL_WRITE_FREQ_SEL_MASK   0x3
+#define     TWSI_CTRL_WRITE_FREQ_SEL_SHIFT  24
+
+
+#define REG_PCIE_DEV_MISC_CTRL      0x21C
+#define     PCIE_DEV_MISC_CTRL_EXT_PIPE     0x2
+#define     PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1
+#define     PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4
+#define     PCIE_DEV_MISC_CTRL_SERDES_ENDIAN    0x8
+#define     PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN   0x10
+
+#define REG_PCIE_PHYMISC	    0x1000
+#define PCIE_PHYMISC_FORCE_RCV_DET	0x4
+
+#define REG_LTSSM_TEST_MODE         0x12FC
+#define         LTSSM_TEST_MODE_DEF     0xE000
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL             0x1400
+#define     MASTER_CTRL_SOFT_RST            0x1
+#define     MASTER_CTRL_MTIMER_EN           0x2
+#define     MASTER_CTRL_ITIMER_EN           0x4
+#define     MASTER_CTRL_MANUAL_INT          0x8
+#define     MASTER_CTRL_ITIMER2_EN          0x20
+#define     MASTER_CTRL_INT_RDCLR           0x40
+#define     MASTER_CTRL_LED_MODE	    0x200
+#define     MASTER_CTRL_REV_NUM_SHIFT       16
+#define     MASTER_CTRL_REV_NUM_MASK        0xff
+#define     MASTER_CTRL_DEV_ID_SHIFT        24
+#define     MASTER_CTRL_DEV_ID_MASK         0xff
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT       0x1404
+
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODU_TIMER_INIT     0x1408   /* w */
+#define REG_IRQ_MODU_TIMER2_INIT    0x140A   /* w */
+
+
+#define REG_GPHY_CTRL               0x140C
+#define     GPHY_CTRL_EXT_RESET         1
+#define     GPHY_CTRL_PIPE_MOD          2
+#define     GPHY_CTRL_TEST_MODE_MASK    3
+#define     GPHY_CTRL_TEST_MODE_SHIFT   2
+#define     GPHY_CTRL_BERT_START        0x10
+#define     GPHY_CTRL_GATE_25M_EN       0x20
+#define     GPHY_CTRL_LPW_EXIT          0x40
+#define     GPHY_CTRL_PHY_IDDQ          0x80
+#define     GPHY_CTRL_PHY_IDDQ_DIS      0x100
+#define     GPHY_CTRL_PCLK_SEL_DIS      0x200
+#define     GPHY_CTRL_HIB_EN            0x400
+#define     GPHY_CTRL_HIB_PULSE         0x800
+#define     GPHY_CTRL_SEL_ANA_RST       0x1000
+#define     GPHY_CTRL_PHY_PLL_ON        0x2000
+#define     GPHY_CTRL_PWDOWN_HW		0x4000
+#define     GPHY_CTRL_DEFAULT (\
+		GPHY_CTRL_PHY_PLL_ON	|\
+		GPHY_CTRL_SEL_ANA_RST	|\
+		GPHY_CTRL_HIB_PULSE	|\
+		GPHY_CTRL_HIB_EN)
+
+#define     GPHY_CTRL_PW_WOL_DIS (\
+		GPHY_CTRL_PHY_PLL_ON	|\
+		GPHY_CTRL_SEL_ANA_RST	|\
+		GPHY_CTRL_HIB_PULSE	|\
+		GPHY_CTRL_HIB_EN	|\
+		GPHY_CTRL_PWDOWN_HW	|\
+		GPHY_CTRL_PCLK_SEL_DIS	|\
+		GPHY_CTRL_PHY_IDDQ)
+
+/* IRQ Anti-Lost Timer Initial Value Register */
+#define REG_CMBDISDMA_TIMER         0x140E
+
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS  	0x1410
+#define     IDLE_STATUS_RXMAC       1    /* 1: RXMAC state machine is in non-IDLE state. 0: RXMAC is idling */
+#define     IDLE_STATUS_TXMAC       2    /* 1: TXMAC state machine is in non-IDLE state. 0: TXMAC is idling */
+#define     IDLE_STATUS_RXQ         4    /* 1: RXQ state machine is in non-IDLE state.   0: RXQ is idling   */
+#define     IDLE_STATUS_TXQ         8    /* 1: TXQ state machine is in non-IDLE state.   0: TXQ is idling   */
+#define     IDLE_STATUS_DMAR        0x10 /* 1: DMAR state machine is in non-IDLE state.  0: DMAR is idling  */
+#define     IDLE_STATUS_DMAW        0x20 /* 1: DMAW state machine is in non-IDLE state.  0: DMAW is idling  */
+#define     IDLE_STATUS_SMB         0x40 /* 1: SMB state machine is in non-IDLE state.   0: SMB is idling   */
+#define     IDLE_STATUS_CMB         0x80 /* 1: CMB state machine is in non-IDLE state.   0: CMB is idling   */
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL           0x1414
+#define     MDIO_DATA_MASK          0xffff  /* On MDIO write, the 16-bit control data to write to PHY MII management register */
+#define     MDIO_DATA_SHIFT         0       /* On MDIO read, the 16-bit status data that was read from the PHY MII management register*/
+#define     MDIO_REG_ADDR_MASK      0x1f    /* MDIO register address */
+#define     MDIO_REG_ADDR_SHIFT     16
+#define     MDIO_RW                 0x200000      /* 1: read, 0: write */
+#define     MDIO_SUP_PREAMBLE       0x400000      /* Suppress preamble */
+#define     MDIO_START              0x800000      /* Write 1 to initiate the MDIO master. And this bit is self cleared after one cycle*/
+#define     MDIO_CLK_SEL_SHIFT      24
+#define     MDIO_CLK_25_4           0
+#define     MDIO_CLK_25_6           2
+#define     MDIO_CLK_25_8           3
+#define     MDIO_CLK_25_10          4
+#define     MDIO_CLK_25_14          5
+#define     MDIO_CLK_25_20          6
+#define     MDIO_CLK_25_28          7
+#define     MDIO_BUSY               0x8000000
+#define     MDIO_AP_EN              0x10000000
+#define MDIO_WAIT_TIMES         10
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS           0x1418
+#define     PHY_STATUS_100M	      0x20000
+#define     PHY_STATUS_EMI_CA	      0x40000
+
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL              0x141c
+#define     BIST0_NOW                   0x1 /* 1: To trigger BIST0 logic. This bit stays high during the */
+/* BIST process and reset to zero when BIST is done */
+#define     BIST0_SRAM_FAIL             0x2 /* 1: The SRAM failure is un-repairable because it has address */
+/* decoder failure or more than 1 cell stuck-to-x failure */
+#define     BIST0_FUSE_FLAG             0x4 /* 1: Indicating one cell has been fixed */
+
+/* BIST Control and Status Register1(for the retry buffer of PCI Express) */
+#define REG_BIST1_CTRL              0x1420
+#define     BIST1_NOW                   0x1 /* 1: To trigger BIST0 logic. This bit stays high during the */
+/* BIST process and reset to zero when BIST is done */
+#define     BIST1_SRAM_FAIL             0x2 /* 1: The SRAM failure is un-repairable because it has address */
+/* decoder failure or more than 1 cell stuck-to-x failure.*/
+#define     BIST1_FUSE_FLAG             0x4
+
+/* SerDes Lock Detect Control and Status Register */
+#define REG_SERDES_LOCK             0x1424
+#define     SERDES_LOCK_DETECT          1  /* 1: SerDes lock detected . This signal comes from Analog SerDes */
+#define     SERDES_LOCK_DETECT_EN       2  /* 1: Enable SerDes Lock detect function */
+
+/* MAC Control Register  */
+#define REG_MAC_CTRL                0x1480
+#define     MAC_CTRL_TX_EN              1  /* 1: Transmit Enable */
+#define     MAC_CTRL_RX_EN              2  /* 1: Receive Enable */
+#define     MAC_CTRL_TX_FLOW            4  /* 1: Transmit Flow Control Enable */
+#define     MAC_CTRL_RX_FLOW            8  /* 1: Receive Flow Control Enable */
+#define     MAC_CTRL_LOOPBACK           0x10      /* 1: Loop back at G/MII Interface */
+#define     MAC_CTRL_DUPLX              0x20      /* 1: Full-duplex mode  0: Half-duplex mode */
+#define     MAC_CTRL_ADD_CRC            0x40      /* 1: Instruct MAC to attach CRC on all egress Ethernet frames */
+#define     MAC_CTRL_PAD                0x80      /* 1: Instruct MAC to pad short frames to 60-bytes, and then attach CRC. This bit has higher priority over CRC_EN */
+#define     MAC_CTRL_LENCHK             0x100     /* 1: Instruct MAC to check if length field matches the real packet length */
+#define     MAC_CTRL_HUGE_EN            0x200     /* 1: receive Jumbo frame enable */
+#define     MAC_CTRL_PRMLEN_SHIFT       10        /* Preamble length */
+#define     MAC_CTRL_PRMLEN_MASK        0xf
+#define     MAC_CTRL_RMV_VLAN           0x4000    /* 1: to remove VLAN Tag automatically from all receive packets */
+#define     MAC_CTRL_PROMIS_EN          0x8000    /* 1: Promiscuous Mode Enable */
+#define     MAC_CTRL_TX_PAUSE           0x10000   /* 1: transmit test pause */
+#define     MAC_CTRL_SCNT               0x20000   /* 1: shortcut slot time counter */
+#define     MAC_CTRL_SRST_TX            0x40000   /* 1: synchronized reset Transmit MAC module */
+#define     MAC_CTRL_TX_SIMURST         0x80000   /* 1: transmit simulation reset */
+#define     MAC_CTRL_SPEED_SHIFT        20        /* 10: gigabit 01:10M/100M */
+#define     MAC_CTRL_SPEED_MASK         0x300000
+#define     MAC_CTRL_SPEED_1000         2
+#define     MAC_CTRL_SPEED_10_100       1
+#define     MAC_CTRL_DBG_TX_BKPRESURE   0x400000  /* 1: transmit maximum backoff (half-duplex test bit) */
+#define     MAC_CTRL_TX_HUGE            0x800000  /* 1: transmit huge enable */
+#define     MAC_CTRL_RX_CHKSUM_EN       0x1000000 /* 1: RX checksum enable */
+#define     MAC_CTRL_MC_ALL_EN          0x2000000 /* 1: upload all multicast frame without error to system */
+#define     MAC_CTRL_BC_EN              0x4000000 /* 1: upload all broadcast frame without error to system */
+#define     MAC_CTRL_DBG                0x8000000 /* 1: upload all received frame to system (Debug Mode) */
+
+/* MAC IPG/IFG Control Register  */
+#define REG_MAC_IPG_IFG             0x1484
+#define     MAC_IPG_IFG_IPGT_SHIFT      0     /* Desired back to back inter-packet gap. The default is 96-bit time */
+#define     MAC_IPG_IFG_IPGT_MASK       0x7f
+#define     MAC_IPG_IFG_MIFG_SHIFT      8     /* Minimum number of IFG to enforce in between RX frames */
+#define     MAC_IPG_IFG_MIFG_MASK       0xff  /* Frame gap below such IFP is dropped */
+#define     MAC_IPG_IFG_IPGR1_SHIFT     16    /* 64bit Carrier-Sense window */
+#define     MAC_IPG_IFG_IPGR1_MASK      0x7f
+#define     MAC_IPG_IFG_IPGR2_SHIFT     24    /* 96-bit IPG window */
+#define     MAC_IPG_IFG_IPGR2_MASK      0x7f
+
+/* MAC STATION ADDRESS  */
+#define REG_MAC_STA_ADDR            0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE           0x1490
+
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL     0x1498
+#define     MAC_HALF_DUPLX_CTRL_LCOL_SHIFT   0      /* Collision Window */
+#define     MAC_HALF_DUPLX_CTRL_LCOL_MASK    0x3ff
+#define     MAC_HALF_DUPLX_CTRL_RETRY_SHIFT  12     /* Retransmission maximum, afterwards the packet will be discarded */
+#define     MAC_HALF_DUPLX_CTRL_RETRY_MASK   0xf
+#define     MAC_HALF_DUPLX_CTRL_EXC_DEF_EN   0x10000 /* 1: Allow the transmission of a packet which has been excessively deferred */
+#define     MAC_HALF_DUPLX_CTRL_NO_BACK_C    0x20000 /* 1: No back-off on collision, immediately start the retransmission */
+#define     MAC_HALF_DUPLX_CTRL_NO_BACK_P    0x40000 /* 1: No back-off on backpressure, immediately start the transmission after back pressure */
+#define     MAC_HALF_DUPLX_CTRL_ABEBE        0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */
+#define     MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT  20      /* Maximum binary exponential number */
+#define     MAC_HALF_DUPLX_CTRL_ABEBT_MASK   0xf
+#define     MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24      /* IPG to start JAM for collision based flow control in half-duplex */
+#define     MAC_HALF_DUPLX_CTRL_JAMIPG_MASK  0xf     /* mode. In unit of 8-bit time */
+
+/* Maximum Frame Length Control Register   */
+#define REG_MTU                     0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL                0x14a0
+#define     WOL_PATTERN_EN                  0x00000001
+#define     WOL_PATTERN_PME_EN              0x00000002
+#define     WOL_MAGIC_EN                    0x00000004
+#define     WOL_MAGIC_PME_EN                0x00000008
+#define     WOL_LINK_CHG_EN                 0x00000010
+#define     WOL_LINK_CHG_PME_EN             0x00000020
+#define     WOL_PATTERN_ST                  0x00000100
+#define     WOL_MAGIC_ST                    0x00000200
+#define     WOL_LINKCHG_ST                  0x00000400
+#define     WOL_CLK_SWITCH_EN               0x00008000
+#define     WOL_PT0_EN                      0x00010000
+#define     WOL_PT1_EN                      0x00020000
+#define     WOL_PT2_EN                      0x00040000
+#define     WOL_PT3_EN                      0x00080000
+#define     WOL_PT4_EN                      0x00100000
+#define     WOL_PT5_EN                      0x00200000
+#define     WOL_PT6_EN                      0x00400000
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN         0x14a4
+#define     WOL_PT_LEN_MASK                 0x7f
+#define     WOL_PT0_LEN_SHIFT               0
+#define     WOL_PT1_LEN_SHIFT               8
+#define     WOL_PT2_LEN_SHIFT               16
+#define     WOL_PT3_LEN_SHIFT               24
+#define     WOL_PT4_LEN_SHIFT               0
+#define     WOL_PT5_LEN_SHIFT               8
+#define     WOL_PT6_LEN_SHIFT               16
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_TRD_ADDR           0x1518
+#define REG_SRAM_TRD_LEN            0x151C
+#define REG_SRAM_RXF_ADDR           0x1520
+#define REG_SRAM_RXF_LEN            0x1524
+#define REG_SRAM_TXF_ADDR           0x1528
+#define REG_SRAM_TXF_LEN            0x152C
+#define REG_SRAM_TCPH_ADDR          0x1530
+#define REG_SRAM_PKTH_ADDR          0x1532
+
+/* Load Ptr Register */
+#define REG_LOAD_PTR                0x1534  /* Software sets this bit after the initialization of the head and tail */
+
+/*
+ * addresses of all descriptors, as well as the following descriptor
+ * control register, which triggers each function block to load the head
+ * pointer to prepare for the operation. This bit is then self-cleared
+ * after one cycle.
+ */
+
+/* Descriptor Control register  */
+#define REG_RXF3_BASE_ADDR_HI           0x153C
+#define REG_DESC_BASE_ADDR_HI           0x1540
+#define REG_RXF0_BASE_ADDR_HI           0x1540 /* share with DESC BASE ADDR HI */
+#define REG_HOST_RXF0_PAGE0_LO          0x1544
+#define REG_HOST_RXF0_PAGE1_LO          0x1548
+#define REG_TPD_BASE_ADDR_LO            0x154C
+#define REG_RXF1_BASE_ADDR_HI           0x1550
+#define REG_RXF2_BASE_ADDR_HI           0x1554
+#define REG_HOST_RXFPAGE_SIZE           0x1558
+#define REG_TPD_RING_SIZE               0x155C
+/* RSS about */
+#define REG_RSS_KEY0                    0x14B0
+#define REG_RSS_KEY1                    0x14B4
+#define REG_RSS_KEY2                    0x14B8
+#define REG_RSS_KEY3                    0x14BC
+#define REG_RSS_KEY4                    0x14C0
+#define REG_RSS_KEY5                    0x14C4
+#define REG_RSS_KEY6                    0x14C8
+#define REG_RSS_KEY7                    0x14CC
+#define REG_RSS_KEY8                    0x14D0
+#define REG_RSS_KEY9                    0x14D4
+#define REG_IDT_TABLE4                  0x14E0
+#define REG_IDT_TABLE5                  0x14E4
+#define REG_IDT_TABLE6                  0x14E8
+#define REG_IDT_TABLE7                  0x14EC
+#define REG_IDT_TABLE0                  0x1560
+#define REG_IDT_TABLE1                  0x1564
+#define REG_IDT_TABLE2                  0x1568
+#define REG_IDT_TABLE3                  0x156C
+#define REG_IDT_TABLE                   REG_IDT_TABLE0
+#define REG_RSS_HASH_VALUE              0x1570
+#define REG_RSS_HASH_FLAG               0x1574
+#define REG_BASE_CPU_NUMBER             0x157C
+
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL                0x1580
+#define     TXQ_CTRL_NUM_TPD_BURST_MASK     0xF
+#define     TXQ_CTRL_NUM_TPD_BURST_SHIFT    0
+#define     TXQ_CTRL_EN                     0x20  /* 1: Enable TXQ */
+#define     TXQ_CTRL_ENH_MODE               0x40  /* Performance enhancement mode, in which up to two back-to-back DMA read commands might be dispatched. */
+#define     TXQ_CTRL_TXF_BURST_NUM_SHIFT    16    /* Number of data byte to read in a cache-aligned burst. Each SRAM entry is 8-byte in length. */
+#define     TXQ_CTRL_TXF_BURST_NUM_MASK     0xffff
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_EARLY_TH                     0x1584 /* Jumbo frame threshold in QWORD unit. Packet greater than */
+/* JUMBO_TASK_OFFLOAD_THRESHOLD will not be task offloaded. */
+#define     TX_TX_EARLY_TH_MASK             0x7ff
+#define     TX_TX_EARLY_TH_SHIFT            0
+
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL                0x15A0
+#define         RXQ_CTRL_PBA_ALIGN_32                   0   /* rx-packet alignment */
+#define         RXQ_CTRL_PBA_ALIGN_64                   1
+#define         RXQ_CTRL_PBA_ALIGN_128                  2
+#define         RXQ_CTRL_PBA_ALIGN_256                  3
+#define         RXQ_CTRL_Q1_EN				0x10
+#define         RXQ_CTRL_Q2_EN				0x20
+#define         RXQ_CTRL_Q3_EN				0x40
+#define         RXQ_CTRL_IPV6_XSUM_VERIFY_EN		0x80
+#define         RXQ_CTRL_HASH_TLEN_SHIFT                8
+#define         RXQ_CTRL_HASH_TLEN_MASK                 0xFF
+#define         RXQ_CTRL_HASH_TYPE_IPV4                 0x10000
+#define         RXQ_CTRL_HASH_TYPE_IPV4_TCP             0x20000
+#define         RXQ_CTRL_HASH_TYPE_IPV6                 0x40000
+#define         RXQ_CTRL_HASH_TYPE_IPV6_TCP             0x80000
+#define         RXQ_CTRL_RSS_MODE_DISABLE               0
+#define         RXQ_CTRL_RSS_MODE_SQSINT                0x4000000
+#define         RXQ_CTRL_RSS_MODE_MQUESINT              0x8000000
+#define         RXQ_CTRL_RSS_MODE_MQUEMINT              0xC000000
+#define         RXQ_CTRL_NIP_QUEUE_SEL_TBL              0x10000000
+#define         RXQ_CTRL_HASH_ENABLE                    0x20000000
+#define         RXQ_CTRL_CUT_THRU_EN                    0x40000000
+#define         RXQ_CTRL_EN                             0x80000000
+
+/* Rx jumbo packet threshold and rrd  retirement timer  */
+#define REG_RXQ_JMBOSZ_RRDTIM       0x15A4
+/*
+ * Jumbo packet threshold for non-VLAN packet, in QWORD (64-bit) unit.
+ * When the packet length greater than or equal to this value, RXQ
+ * shall start cut-through forwarding of the received packet.
+ */
+#define         RXQ_JMBOSZ_TH_MASK      0x7ff
+#define         RXQ_JMBOSZ_TH_SHIFT         0  /* RRD retirement timer. Decrement by 1 after every 512ns passes*/
+#define         RXQ_JMBO_LKAH_MASK          0xf
+#define         RXQ_JMBO_LKAH_SHIFT         11
+
+/* RXF flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH    0x15A8
+#define     RXQ_RXF_PAUSE_TH_HI_SHIFT       0
+#define     RXQ_RXF_PAUSE_TH_HI_MASK        0xfff
+#define     RXQ_RXF_PAUSE_TH_LO_SHIFT       16
+#define     RXQ_RXF_PAUSE_TH_LO_MASK        0xfff
+
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL                0x15C0
+#define     DMA_CTRL_DMAR_IN_ORDER          0x1
+#define     DMA_CTRL_DMAR_ENH_ORDER         0x2
+#define     DMA_CTRL_DMAR_OUT_ORDER         0x4
+#define     DMA_CTRL_RCB_VALUE              0x8
+#define     DMA_CTRL_DMAR_BURST_LEN_SHIFT   4
+#define     DMA_CTRL_DMAR_BURST_LEN_MASK    7
+#define     DMA_CTRL_DMAW_BURST_LEN_SHIFT   7
+#define     DMA_CTRL_DMAW_BURST_LEN_MASK    7
+#define     DMA_CTRL_DMAR_REQ_PRI           0x400
+#define     DMA_CTRL_DMAR_DLY_CNT_MASK      0x1F
+#define     DMA_CTRL_DMAR_DLY_CNT_SHIFT     11
+#define     DMA_CTRL_DMAW_DLY_CNT_MASK      0xF
+#define     DMA_CTRL_DMAW_DLY_CNT_SHIFT     16
+#define     DMA_CTRL_TXCMB_EN               0x100000
+#define     DMA_CTRL_RXCMB_EN				0x200000
+
+
+/* CMB/SMB Control Register */
+#define REG_SMB_STAT_TIMER                      0x15C4
+#define REG_TRIG_RRD_THRESH                     0x15CA
+#define REG_TRIG_TPD_THRESH                     0x15C8
+#define REG_TRIG_TXTIMER                        0x15CC
+#define REG_TRIG_RXTIMER                        0x15CE
+
+/* HOST RXF Page 1,2,3 address */
+#define REG_HOST_RXF1_PAGE0_LO                  0x15D0
+#define REG_HOST_RXF1_PAGE1_LO                  0x15D4
+#define REG_HOST_RXF2_PAGE0_LO                  0x15D8
+#define REG_HOST_RXF2_PAGE1_LO                  0x15DC
+#define REG_HOST_RXF3_PAGE0_LO                  0x15E0
+#define REG_HOST_RXF3_PAGE1_LO                  0x15E4
+
+/* Mail box */
+#define REG_MB_RXF1_RADDR                       0x15B4
+#define REG_MB_RXF2_RADDR                       0x15B8
+#define REG_MB_RXF3_RADDR                       0x15BC
+#define REG_MB_TPD_PROD_IDX                     0x15F0
+
+/* RXF-Page 0-3  PageNo & Valid bit */
+#define REG_HOST_RXF0_PAGE0_VLD     0x15F4
+#define     HOST_RXF_VALID              1
+#define     HOST_RXF_PAGENO_SHIFT       1
+#define     HOST_RXF_PAGENO_MASK        0x7F
+#define REG_HOST_RXF0_PAGE1_VLD     0x15F5
+#define REG_HOST_RXF1_PAGE0_VLD     0x15F6
+#define REG_HOST_RXF1_PAGE1_VLD     0x15F7
+#define REG_HOST_RXF2_PAGE0_VLD     0x15F8
+#define REG_HOST_RXF2_PAGE1_VLD     0x15F9
+#define REG_HOST_RXF3_PAGE0_VLD     0x15FA
+#define REG_HOST_RXF3_PAGE1_VLD     0x15FB
+
+/* Interrupt Status Register */
+#define REG_ISR    0x1600
+#define  ISR_SMB   		1
+#define  ISR_TIMER		2       /* Interrupt when Timer is counted down to zero */
+/*
+ * Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set
+ * in Table 51 Selene Master Control Register (Offset 0x1400).
+ */
+#define  ISR_MANUAL         	4
+#define  ISR_HW_RXF_OV          8        /* RXF overflow interrupt */
+#define  ISR_HOST_RXF0_OV       0x10
+#define  ISR_HOST_RXF1_OV       0x20
+#define  ISR_HOST_RXF2_OV       0x40
+#define  ISR_HOST_RXF3_OV       0x80
+#define  ISR_TXF_UN             0x100
+#define  ISR_RX0_PAGE_FULL      0x200
+#define  ISR_DMAR_TO_RST        0x400
+#define  ISR_DMAW_TO_RST        0x800
+#define  ISR_GPHY               0x1000
+#define  ISR_TX_CREDIT          0x2000
+#define  ISR_GPHY_LPW           0x4000    /* GPHY low power state interrupt */
+#define  ISR_RX_PKT             0x10000   /* One packet received, triggered by RFD */
+#define  ISR_TX_PKT             0x20000   /* One packet transmitted, triggered by TPD */
+#define  ISR_TX_DMA             0x40000
+#define  ISR_RX_PKT_1           0x80000
+#define  ISR_RX_PKT_2           0x100000
+#define  ISR_RX_PKT_3           0x200000
+#define  ISR_MAC_RX             0x400000
+#define  ISR_MAC_TX             0x800000
+#define  ISR_UR_DETECTED        0x1000000
+#define  ISR_FERR_DETECTED      0x2000000
+#define  ISR_NFERR_DETECTED     0x4000000
+#define  ISR_CERR_DETECTED      0x8000000
+#define  ISR_PHY_LINKDOWN       0x10000000
+#define  ISR_DIS_INT            0x80000000
+
+
+/* Interrupt Mask Register */
+#define REG_IMR 0x1604
+
+
+#define IMR_NORMAL_MASK (\
+		ISR_SMB	        |\
+		ISR_TXF_UN      |\
+		ISR_HW_RXF_OV   |\
+		ISR_HOST_RXF0_OV|\
+		ISR_MANUAL      |\
+		ISR_GPHY        |\
+		ISR_GPHY_LPW    |\
+		ISR_DMAR_TO_RST |\
+		ISR_DMAW_TO_RST |\
+		ISR_PHY_LINKDOWN|\
+		ISR_RX_PKT      |\
+		ISR_TX_PKT)
+
+#define ISR_TX_EVENT (ISR_TXF_UN | ISR_TX_PKT)
+#define ISR_RX_EVENT (ISR_HOST_RXF0_OV | ISR_HW_RXF_OV | ISR_RX_PKT)
+
+#define REG_MAC_RX_STATUS_BIN 0x1700
+#define REG_MAC_RX_STATUS_END 0x175c
+#define REG_MAC_TX_STATUS_BIN 0x1760
+#define REG_MAC_TX_STATUS_END 0x17c0
+
+/* Hardware Offset Register */
+#define REG_HOST_RXF0_PAGEOFF 0x1800
+#define REG_TPD_CONS_IDX      0x1804
+#define REG_HOST_RXF1_PAGEOFF 0x1808
+#define REG_HOST_RXF2_PAGEOFF 0x180C
+#define REG_HOST_RXF3_PAGEOFF 0x1810
+
+/* RXF-Page 0-3 Offset DMA Address */
+#define REG_HOST_RXF0_MB0_LO  0x1820
+#define REG_HOST_RXF0_MB1_LO  0x1824
+#define REG_HOST_RXF1_MB0_LO  0x1828
+#define REG_HOST_RXF1_MB1_LO  0x182C
+#define REG_HOST_RXF2_MB0_LO  0x1830
+#define REG_HOST_RXF2_MB1_LO  0x1834
+#define REG_HOST_RXF3_MB0_LO  0x1838
+#define REG_HOST_RXF3_MB1_LO  0x183C
+
+/* Tpd CMB DMA Address */
+#define REG_HOST_TX_CMB_LO    0x1840
+#define REG_HOST_SMB_ADDR_LO  0x1844
+
+/* DEBUG ADDR */
+#define REG_DEBUG_DATA0 0x1900
+#define REG_DEBUG_DATA1 0x1904
+
+/***************************** MII definition ***************************************/
+/* PHY Common Register */
+#define MII_BMCR                        0x00
+#define MII_BMSR                        0x01
+#define MII_PHYSID1                     0x02
+#define MII_PHYSID2                     0x03
+#define MII_ADVERTISE                   0x04
+#define MII_LPA                         0x05
+#define MII_EXPANSION                   0x06
+#define MII_AT001_CR                    0x09
+#define MII_AT001_SR                    0x0A
+#define MII_AT001_ESR                   0x0F
+#define MII_AT001_PSCR                  0x10
+#define MII_AT001_PSSR                  0x11
+#define MII_INT_CTRL                    0x12
+#define MII_INT_STATUS                  0x13
+#define MII_SMARTSPEED                  0x14
+#define MII_RERRCOUNTER                 0x15
+#define MII_SREVISION                   0x16
+#define MII_RESV1                       0x17
+#define MII_LBRERROR                    0x18
+#define MII_PHYADDR                     0x19
+#define MII_RESV2                       0x1a
+#define MII_TPISTATUS                   0x1b
+#define MII_NCONFIG                     0x1c
+
+#define MII_DBG_ADDR			0x1D
+#define MII_DBG_DATA			0x1E
+
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB                  0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE                  0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX                       0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG                  0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE                           0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN                        0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN                       0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB                  0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK                          0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET                             0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_MASK                        0x2040
+#define MII_CR_SPEED_1000                        0x0040
+#define MII_CR_SPEED_100                         0x2000
+#define MII_CR_SPEED_10                          0x0000
+
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS                     0x0001  /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT                     0x0002  /* Jabber Detected */
+#define MII_SR_LINK_STATUS                       0x0004  /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS                      0x0008  /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT                      0x0010  /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE                  0x0020  /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS                 0x0040  /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS                   0x0100  /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS                     0x0200  /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS                     0x0400  /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS                       0x0800  /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS                       0x1000  /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS                      0x2000  /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS                      0x4000  /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS                        0x8000  /* 100T4 Capable */
+
+/* Link partner ability register. */
+#define MII_LPA_SLCT                             0x001f  /* Same as advertise selector  */
+#define MII_LPA_10HALF                           0x0020  /* Can do 10mbps half-duplex   */
+#define MII_LPA_10FULL                           0x0040  /* Can do 10mbps full-duplex   */
+#define MII_LPA_100HALF                          0x0080  /* Can do 100mbps half-duplex  */
+#define MII_LPA_100FULL                          0x0100  /* Can do 100mbps full-duplex  */
+#define MII_LPA_100BASE4                         0x0200  /* 100BASE-T4  */
+#define MII_LPA_PAUSE                            0x0400  /* PAUSE */
+#define MII_LPA_ASYPAUSE                         0x0800  /* Asymmetrical PAUSE */
+#define MII_LPA_RFAULT                           0x2000  /* Link partner faulted        */
+#define MII_LPA_LPACK                            0x4000  /* Link partner acked us       */
+#define MII_LPA_NPAGE                            0x8000  /* Next page bit               */
+
+/* Autoneg Advertisement Register */
+#define MII_AR_SELECTOR_FIELD                   0x0001  /* indicates IEEE 802.3 CSMA/CD */
+#define MII_AR_10T_HD_CAPS                      0x0020  /* 10T   Half Duplex Capable */
+#define MII_AR_10T_FD_CAPS                      0x0040  /* 10T   Full Duplex Capable */
+#define MII_AR_100TX_HD_CAPS                    0x0080  /* 100TX Half Duplex Capable */
+#define MII_AR_100TX_FD_CAPS                    0x0100  /* 100TX Full Duplex Capable */
+#define MII_AR_100T4_CAPS                       0x0200  /* 100T4 Capable */
+#define MII_AR_PAUSE                            0x0400  /* Pause operation desired */
+#define MII_AR_ASM_DIR                          0x0800  /* Asymmetric Pause Direction bit */
+#define MII_AR_REMOTE_FAULT                     0x2000  /* Remote Fault detected */
+#define MII_AR_NEXT_PAGE                        0x8000  /* Next Page ability supported */
+#define MII_AR_SPEED_MASK                       0x01E0
+#define MII_AR_DEFAULT_CAP_MASK                 0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_AT001_CR_1000T_HD_CAPS              0x0100  /* Advertise 1000T HD capability */
+#define MII_AT001_CR_1000T_FD_CAPS              0x0200  /* Advertise 1000T FD capability  */
+#define MII_AT001_CR_1000T_REPEATER_DTE         0x0400  /* 1=Repeater/switch device port */
+/* 0=DTE device */
+#define MII_AT001_CR_1000T_MS_VALUE             0x0800  /* 1=Configure PHY as Master */
+/* 0=Configure PHY as Slave */
+#define MII_AT001_CR_1000T_MS_ENABLE            0x1000  /* 1=Master/Slave manual config value */
+/* 0=Automatic Master/Slave config */
+#define MII_AT001_CR_1000T_TEST_MODE_NORMAL     0x0000  /* Normal Operation */
+#define MII_AT001_CR_1000T_TEST_MODE_1          0x2000  /* Transmit Waveform test */
+#define MII_AT001_CR_1000T_TEST_MODE_2          0x4000  /* Master Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_3          0x6000  /* Slave Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_4          0x8000  /* Transmitter Distortion test */
+#define MII_AT001_CR_1000T_SPEED_MASK           0x0300
+#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK     0x0300
+
+/* 1000BASE-T Status Register */
+#define MII_AT001_SR_1000T_LP_HD_CAPS           0x0400  /* LP is 1000T HD capable */
+#define MII_AT001_SR_1000T_LP_FD_CAPS           0x0800  /* LP is 1000T FD capable */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS     0x1000  /* Remote receiver OK */
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS      0x2000  /* Local receiver OK */
+#define MII_AT001_SR_1000T_MS_CONFIG_RES        0x4000  /* 1=Local TX is Master, 0=Slave */
+#define MII_AT001_SR_1000T_MS_CONFIG_FAULT      0x8000  /* Master/Slave config fault */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT   12
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT    13
+
+/* Extended Status Register */
+#define MII_AT001_ESR_1000T_HD_CAPS             0x1000  /* 1000T HD capable */
+#define MII_AT001_ESR_1000T_FD_CAPS             0x2000  /* 1000T FD capable */
+#define MII_AT001_ESR_1000X_HD_CAPS             0x4000  /* 1000X HD capable */
+#define MII_AT001_ESR_1000X_FD_CAPS             0x8000  /* 1000X FD capable */
+
+/* AT001 PHY Specific Control Register */
+#define MII_AT001_PSCR_JABBER_DISABLE           0x0001  /* 1=Jabber Function disabled */
+#define MII_AT001_PSCR_POLARITY_REVERSAL        0x0002  /* 1=Polarity Reversal enabled */
+#define MII_AT001_PSCR_SQE_TEST                 0x0004  /* 1=SQE Test enabled */
+#define MII_AT001_PSCR_MAC_POWERDOWN            0x0008
+#define MII_AT001_PSCR_CLK125_DISABLE           0x0010  /* 1=CLK125 low,
+							 * 0=CLK125 toggling
+							 */
+#define MII_AT001_PSCR_MDI_MANUAL_MODE          0x0000  /* MDI Crossover Mode bits 6:5 */
+/* Manual MDI configuration */
+#define MII_AT001_PSCR_MDIX_MANUAL_MODE         0x0020  /* Manual MDIX configuration */
+#define MII_AT001_PSCR_AUTO_X_1000T             0x0040  /* 1000BASE-T: Auto crossover,
+							 *  100BASE-TX/10BASE-T:
+							 *  MDI Mode
+							 */
+#define MII_AT001_PSCR_AUTO_X_MODE              0x0060  /* Auto crossover enabled
+							 * all speeds.
+							 */
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE     0x0080
+/* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+#define MII_AT001_PSCR_MII_5BIT_ENABLE          0x0100
+/* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define MII_AT001_PSCR_SCRAMBLER_DISABLE        0x0200  /* 1=Scrambler disable */
+#define MII_AT001_PSCR_FORCE_LINK_GOOD          0x0400  /* 1=Force link good */
+#define MII_AT001_PSCR_ASSERT_CRS_ON_TX         0x0800  /* 1=Assert CRS on Transmit */
+#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT          5
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+/* AT001 PHY Specific Status Register */
+#define MII_AT001_PSSR_SPD_DPLX_RESOLVED        0x0800  /* 1=Speed & Duplex resolved */
+#define MII_AT001_PSSR_DPLX                     0x2000  /* 1=Duplex 0=Half Duplex */
+#define MII_AT001_PSSR_SPEED                    0xC000  /* Speed, bits 14:15 */
+#define MII_AT001_PSSR_10MBS                    0x0000  /* 00=10Mbs */
+#define MII_AT001_PSSR_100MBS                   0x4000  /* 01=100Mbs */
+#define MII_AT001_PSSR_1000MBS                  0x8000  /* 10=1000Mbs */
+
+
+#endif /* _ATL1_E_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.c
new file mode 100644
index 0000000..66fa8ea
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.c
@@ -0,0 +1,953 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha at gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem at redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp at ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/io.h>
+#include <mii.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include "b44.h"
+
+
+static inline int ring_next(int index)
+{
+	/* B44_RING_SIZE is a power of 2 :) */
+	return (index + 1) & (B44_RING_SIZE - 1);
+}
+
+
+/* Memory-mapped I/O wrappers */
+
+static inline u32 br32(const struct b44_private *bp, u32 reg)
+{
+	return readl(bp->regs + reg);
+}
+
+
+static inline void bw32(const struct b44_private *bp, u32 reg, u32 val)
+{
+	writel(val, bp->regs + reg);
+}
+
+
+static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout)
+{
+	readl(bp->regs + reg);
+	udelay(timeout);
+}
+
+
+#define VIRT_TO_B44(addr)	( virt_to_bus(addr) + SB_PCI_DMA )
+
+
+/**
+ * Return non-zero if the installed RAM is within
+ * the limit given and zero if it is outside.
+ * Hopefully will be removed soon.
+ */
+int phys_ram_within_limit(u64 limit)
+{
+	struct memory_map memmap;
+	struct memory_region *highest = NULL;
+	get_memmap(&memmap);
+
+	if (memmap.count == 0)
+		return 0;
+	highest = &memmap.regions[memmap.count - 1];
+
+	return (highest->end < limit);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'tx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_tx_index(struct b44_private *bp)
+{
+	u32 pending = br32(bp, B44_DMATX_STAT);
+	pending &= DMATX_STAT_CDMASK;
+
+	pending /= sizeof(struct dma_desc);
+	return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'rx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_rx_index(struct b44_private *bp)
+{
+	u32 pending = br32(bp, B44_DMARX_STAT);
+	pending &= DMARX_STAT_CDMASK;
+
+	pending /= sizeof(struct dma_desc);
+	return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Wait until the given bit is set/cleared.
+ */
+static int b44_wait_bit(struct b44_private *bp, unsigned long reg, u32 bit,
+			            unsigned long timeout, const int clear)
+{
+	unsigned long i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 val = br32(bp, reg);
+
+		if (clear && !(val & bit))
+			break;
+
+		if (!clear && (val & bit))
+			break;
+
+		udelay(10);
+	}
+	if (i == timeout) {
+		return -ENODEV;
+	}
+	return 0;
+}
+
+
+/*
+ * Sonics Silicon Backplane support. SSB is a mini-bus interconnecting
+ * so-called IP Cores. One of those cores implements the Fast Ethernet
+ * functionality and another one the PCI engine.
+ *
+ * You need to switch to the core you want to talk to before actually
+ * sending commands.
+ *
+ * See: http://bcm-v4.sipsolutions.net/Backplane for (reverse-engineered)
+ * specs.
+ */
+
+static inline u32 ssb_get_core_rev(struct b44_private *bp)
+{
+	return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
+}
+
+
+static inline int ssb_is_core_up(struct b44_private *bp)
+{
+	return ((br32(bp, B44_SBTMSLOW) & (SSB_CORE_DOWN | SBTMSLOW_CLOCK))
+	                                                == SBTMSLOW_CLOCK);
+}
+
+
+static u32 ssb_pci_setup(struct b44_private *bp, u32 cores)
+{
+	u32 bar_orig, pci_rev, val;
+
+	pci_read_config_dword(bp->pci, SSB_BAR0_WIN, &bar_orig);
+	pci_write_config_dword(bp->pci, SSB_BAR0_WIN,
+	                       BCM4400_PCI_CORE_ADDR);
+	pci_rev = ssb_get_core_rev(bp);
+
+	val = br32(bp, B44_SBINTVEC);
+	val |= cores;
+	bw32(bp, B44_SBINTVEC, val);
+
+	val = br32(bp, SSB_PCI_TRANS_2);
+	val |= SSB_PCI_PREF | SSB_PCI_BURST;
+	bw32(bp, SSB_PCI_TRANS_2, val);
+
+	pci_write_config_dword(bp->pci, SSB_BAR0_WIN, bar_orig);
+
+	return pci_rev;
+}
+
+
+static void ssb_core_disable(struct b44_private *bp)
+{
+	if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
+		return;
+
+	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
+	b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
+	b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
+
+	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
+	                                        SSB_CORE_DOWN));
+	bflush(bp, B44_SBTMSLOW, 1);
+
+	bw32(bp, B44_SBTMSLOW, SSB_CORE_DOWN);
+	bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+static void ssb_core_reset(struct b44_private *bp)
+{
+	u32 val;
+	const u32 mask = (SBTMSLOW_CLOCK | SBTMSLOW_FGC | SBTMSLOW_RESET);
+
+	ssb_core_disable(bp);
+
+	bw32(bp, B44_SBTMSLOW, mask);
+	bflush(bp, B44_SBTMSLOW, 1);
+
+	/* Clear SERR if set, this is a hw bug workaround.  */
+	if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
+		bw32(bp, B44_SBTMSHIGH, 0);
+
+	val = br32(bp, B44_SBIMSTATE);
+	if (val & (SBIMSTATE_BAD)) {
+		bw32(bp, B44_SBIMSTATE, val & ~SBIMSTATE_BAD);
+	}
+
+	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+	bflush(bp, B44_SBTMSLOW, 1);
+
+	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
+	bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+/*
+ * Driver helper functions
+ */
+
+/*
+ * Chip reset provides power to the b44 MAC & PCI cores, which
+ * is necessary for MAC register access. We only do a partial
+ * reset in case of transmit/receive errors (ISTAT_ERRORS) to
+ * avoid the chip being hung for an unnecessary long time in
+ * this case.
+ *
+ * Called-by: b44_close, b44_halt, b44_inithw(b44_open), b44_probe
+ */
+static void b44_chip_reset(struct b44_private *bp, int reset_kind)
+{
+	if (ssb_is_core_up(bp)) {
+		bw32(bp, B44_RCV_LAZY, 0);
+
+		bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
+
+		b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
+
+		bw32(bp, B44_DMATX_CTRL, 0);
+
+		bp->tx_dirty = bp->tx_cur = 0;
+
+		if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK)
+			b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
+			                                          100, 0);
+
+		bw32(bp, B44_DMARX_CTRL, 0);
+
+		bp->rx_cur = 0;
+	} else {
+		ssb_pci_setup(bp, SBINTVEC_ENET0);
+	}
+
+	ssb_core_reset(bp);
+
+	/* Don't enable PHY if we are only doing a partial reset. */
+	if (reset_kind == B44_CHIP_RESET_PARTIAL)
+		return;
+
+	/* Make PHY accessible. */
+	bw32(bp, B44_MDIO_CTRL,
+	     (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK)));
+	bflush(bp, B44_MDIO_CTRL, 1);
+
+	/* Enable internal or external PHY */
+	if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
+		bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
+		bflush(bp, B44_ENET_CTRL, 1);
+	} else {
+		u32 val = br32(bp, B44_DEVCTRL);
+		if (val & DEVCTRL_EPR) {
+			bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR));
+			bflush(bp, B44_DEVCTRL, 100);
+		}
+	}
+}
+
+
+/**
+ * called by b44_poll in the error path
+ */
+static void b44_halt(struct b44_private *bp)
+{
+	/* disable ints */
+	bw32(bp, B44_IMASK, 0);
+	bflush(bp, B44_IMASK, 1);
+
+	DBG("b44: powering down PHY\n");
+	bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
+
+	/*
+	 * Now reset the chip, but without enabling
+	 * the MAC&PHY part of it.
+	 * This has to be done _after_ we shut down the PHY
+	 */
+	b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+}
+
+
+
+/*
+ * Called at device open time to get the chip ready for
+ * packet processing.
+ *
+ * Called-by: b44_open
+ */
+static void b44_init_hw(struct b44_private *bp, int reset_kind)
+{
+	u32 val;
+#define CTRL_MASK (DMARX_CTRL_ENABLE | (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT))
+
+	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+	if (reset_kind == B44_FULL_RESET) {
+		b44_phy_reset(bp);
+	}
+
+	/* Enable CRC32, set proper LED modes and power on PHY */
+	bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
+	bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
+
+	/* This sets the MAC address too.  */
+	b44_set_rx_mode(bp->netdev);
+
+	/* MTU + eth header + possible VLAN tag + struct rx_header */
+	bw32(bp, B44_RXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+	bw32(bp, B44_TXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+
+	bw32(bp, B44_TX_HIWMARK, TX_HIWMARK_DEFLT);
+	if (reset_kind == B44_PARTIAL_RESET) {
+		bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+	} else {
+		bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+		bw32(bp, B44_DMATX_ADDR, VIRT_TO_B44(bp->tx));
+
+		bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+		bw32(bp, B44_DMARX_ADDR, VIRT_TO_B44(bp->rx));
+		bw32(bp, B44_DMARX_PTR, B44_RX_RING_LEN_BYTES);
+
+		bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+	}
+
+	val = br32(bp, B44_ENET_CTRL);
+	bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
+#undef CTRL_MASK
+}
+
+
+/***  Management of ring descriptors  ***/
+
+
+static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx)
+{
+	struct rx_header *rh;
+	u32 ctrl, addr;
+
+	rh = bp->rx_iobuf[idx]->data;
+	rh->len = 0;
+	rh->flags = 0;
+	ctrl = DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET);
+	if (idx == B44_RING_LAST) {
+		ctrl |= DESC_CTRL_EOT;
+	}
+	addr = VIRT_TO_B44(bp->rx_iobuf[idx]->data);
+
+	bp->rx[idx].ctrl = cpu_to_le32(ctrl);
+	bp->rx[idx].addr = cpu_to_le32(addr);
+	bw32(bp, B44_DMARX_PTR, idx * sizeof(struct dma_desc));
+}
+
+
+/*
+ * Refill RX ring descriptors with buffers. This is needed
+ * because during rx we are passing ownership of descriptor
+ * buffers to the network stack.
+ */
+static void b44_rx_refill(struct b44_private *bp, u32 pending)
+{
+	u32 i;
+
+	// skip pending
+	for (i = pending + 1; i != bp->rx_cur; i = ring_next(i)) {
+		if (bp->rx_iobuf[i] != NULL)
+			continue;
+
+		bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ);
+		if (!bp->rx_iobuf[i]) {
+			DBG("Refill rx ring failed!!\n");
+			break;
+		}
+
+		b44_populate_rx_descriptor(bp, i);
+	}
+}
+
+
+static void b44_free_rx_ring(struct b44_private *bp)
+{
+	u32 i;
+
+	if (bp->rx) {
+		for (i = 0; i < B44_RING_SIZE; i++) {
+			free_iob(bp->rx_iobuf[i]);
+			bp->rx_iobuf[i] = NULL;
+		}
+		free_dma(bp->rx, B44_RX_RING_LEN_BYTES);
+		bp->rx = NULL;
+	}
+}
+
+
+static int b44_init_rx_ring(struct b44_private *bp)
+{
+	b44_free_rx_ring(bp);
+
+	bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+	if (!bp->rx)
+		return -ENOMEM;
+
+	memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf));
+
+	bp->rx_iobuf[0] = alloc_iob(RX_PKT_BUF_SZ);
+	b44_populate_rx_descriptor(bp, 0);
+	b44_rx_refill(bp, 0);
+
+	DBG("Init RX rings: rx=0x%08lx\n", VIRT_TO_B44(bp->rx));
+	return 0;
+}
+
+
+static void b44_free_tx_ring(struct b44_private *bp)
+{
+	if (bp->tx) {
+		free_dma(bp->tx, B44_TX_RING_LEN_BYTES);
+		bp->tx = NULL;
+	}
+}
+
+
+static int b44_init_tx_ring(struct b44_private *bp)
+{
+	b44_free_tx_ring(bp);
+
+	bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+	if (!bp->tx)
+		return -ENOMEM;
+
+	memset(bp->tx, 0, B44_TX_RING_LEN_BYTES);
+	memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf));
+
+	DBG("Init TX rings: tx=0x%08lx\n", VIRT_TO_B44(bp->tx));
+	return 0;
+}
+
+
+/*** Interaction with the PHY ***/
+
+
+static int b44_phy_read(struct b44_private *bp, int reg, u32 * val)
+{
+	int err;
+
+	u32 arg1 = (MDIO_OP_READ << MDIO_DATA_OP_SHIFT);
+	u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+	u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+	u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+	u32 argv = arg1 | arg2 | arg3 | arg4;
+
+	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+	err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+	*val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA;
+
+	return err;
+}
+
+
+static int b44_phy_write(struct b44_private *bp, int reg, u32 val)
+{
+	u32 arg1 = (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT);
+	u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+	u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+	u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+	u32 arg5 = (val & MDIO_DATA_DATA);
+	u32 argv = arg1 | arg2 | arg3 | arg4 | arg5;
+
+
+	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+	return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+}
+
+
+static int b44_phy_reset(struct b44_private *bp)
+{
+	u32 val;
+	int err;
+
+	err = b44_phy_write(bp, MII_BMCR, BMCR_RESET);
+	if (err)
+		return err;
+
+	udelay(100);
+	err = b44_phy_read(bp, MII_BMCR, &val);
+	if (!err) {
+		if (val & BMCR_RESET) {
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * The BCM44xx CAM (Content Addressable Memory) stores the MAC
+ * and PHY address.
+ */
+static void b44_cam_write(struct b44_private *bp, unsigned char *data,
+			                                    int index)
+{
+	u32 val;
+
+	val  = ((u32) data[2]) << 24;
+	val |= ((u32) data[3]) << 16;
+	val |= ((u32) data[4]) << 8;
+	val |= ((u32) data[5]) << 0;
+	bw32(bp, B44_CAM_DATA_LO, val);
+
+
+	val = (CAM_DATA_HI_VALID |
+	       (((u32) data[0]) << 8) | (((u32) data[1]) << 0));
+
+	bw32(bp, B44_CAM_DATA_HI, val);
+
+	val = CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT);
+	bw32(bp, B44_CAM_CTRL, val);
+
+	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
+}
+
+
+static void b44_set_mac_addr(struct b44_private *bp)
+{
+	u32 val;
+	bw32(bp, B44_CAM_CTRL, 0);
+	b44_cam_write(bp, bp->netdev->ll_addr, 0);
+	val = br32(bp, B44_CAM_CTRL);
+	bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/* Read 128-bytes of EEPROM. */
+static void b44_read_eeprom(struct b44_private *bp, u8 * data)
+{
+	long i;
+	u16 *ptr = (u16 *) data;
+
+	for (i = 0; i < 128; i += 2)
+		ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
+}
+
+
+static void b44_load_mac_and_phy_addr(struct b44_private *bp)
+{
+	u8 eeprom[128];
+
+	/* Load MAC address, note byteswapping */
+	b44_read_eeprom(bp, &eeprom[0]);
+	bp->netdev->hw_addr[0] = eeprom[79];
+	bp->netdev->hw_addr[1] = eeprom[78];
+	bp->netdev->hw_addr[2] = eeprom[81];
+	bp->netdev->hw_addr[3] = eeprom[80];
+	bp->netdev->hw_addr[4] = eeprom[83];
+	bp->netdev->hw_addr[5] = eeprom[82];
+
+	/* Load PHY address */
+	bp->phy_addr = eeprom[90] & 0x1f;
+}
+
+
+static void b44_set_rx_mode(struct net_device *netdev)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+	unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 };
+	u32 val;
+	int i;
+
+	val = br32(bp, B44_RXCONFIG);
+	val &= ~RXCONFIG_PROMISC;
+	val |= RXCONFIG_ALLMULTI;
+
+	b44_set_mac_addr(bp);
+
+	for (i = 1; i < 64; i++)
+		b44_cam_write(bp, zero, i);
+
+	bw32(bp, B44_RXCONFIG, val);
+	val = br32(bp, B44_CAM_CTRL);
+	bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/*** Implementation of iPXE driver callbacks ***/
+
+/**
+ * Probe device
+ *
+ * @v pci	PCI device
+ * @v id	Matching entry in ID table
+ * @ret rc	Return status code
+ */
+static int b44_probe(struct pci_device *pci)
+{
+	struct net_device *netdev;
+	struct b44_private *bp;
+	int rc;
+
+	/*
+	 * Bail out if more than 1GB of physical RAM is installed.
+	 * This limitation will be removed later when dma mapping
+	 * is merged into mainline.
+	 */
+	if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) {
+		DBG("Sorry, this version of the driver does not\n"
+		    "support systems with more than 1GB of RAM.\n");
+		return -ENOMEM;
+	}
+
+	/* Set up netdev */
+	netdev = alloc_etherdev(sizeof(*bp));
+	if (!netdev)
+		return -ENOMEM;
+
+	netdev_init(netdev, &b44_operations);
+	pci_set_drvdata(pci, netdev);
+	netdev->dev = &pci->dev;
+
+	/* Set up private data */
+	bp = netdev_priv(netdev);
+	memset(bp, 0, sizeof(*bp));
+	bp->netdev = netdev;
+	bp->pci = pci;
+
+	/* Map device registers */
+	bp->regs = ioremap(pci->membase, B44_REGS_SIZE);
+	if (!bp->regs) {
+		netdev_put(netdev);
+		return -ENOMEM;
+	}
+
+	/* Enable PCI bus mastering */
+	adjust_pci_device(pci);
+
+	b44_load_mac_and_phy_addr(bp);
+
+	rc = register_netdev(netdev);
+	if (rc != 0) {
+		iounmap(bp->regs);
+		netdev_put(netdev);
+		return rc;
+	}
+
+	/* Link management currently not implemented */
+	netdev_link_up(netdev);
+
+	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+
+	DBG("b44 %s (%04x:%04x) regs=%p MAC=%s\n", pci->id->name,
+	    pci->id->vendor, pci->id->device, bp->regs,
+	    eth_ntoa(netdev->ll_addr));
+
+	return 0;
+}
+
+
+/**
+ * Remove device
+ *
+ * @v pci	PCI device
+ */
+static void b44_remove(struct pci_device *pci)
+{
+	struct net_device *netdev = pci_get_drvdata(pci);
+	struct b44_private *bp = netdev_priv(netdev);
+
+	ssb_core_disable(bp);
+	unregister_netdev(netdev);
+	iounmap(bp->regs);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+
+/** Enable or disable interrupts
+ *
+ * @v netdev	Network device
+ * @v enable	Interrupts should be enabled
+ */
+static void b44_irq(struct net_device *netdev, int enable)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+
+	/* Interrupt mask specifies which events generate interrupts */
+	bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE);
+}
+
+
+/** Open network device
+ *
+ * @v netdev	Network device
+ * @ret rc	Return status code
+ */
+static int b44_open(struct net_device *netdev)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+	int rc;
+
+	rc = b44_init_tx_ring(bp);
+	if (rc != 0)
+		return rc;
+
+	rc = b44_init_rx_ring(bp);
+	if (rc != 0)
+		return rc;
+
+	b44_init_hw(bp, B44_FULL_RESET);
+
+	/* Disable interrupts */
+	b44_irq(netdev, 0);
+
+	return 0;
+}
+
+
+/** Close network device
+ *
+ * @v netdev	Network device
+ */
+static void b44_close(struct net_device *netdev)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+
+	b44_chip_reset(bp, B44_FULL_RESET);
+	b44_free_tx_ring(bp);
+	b44_free_rx_ring(bp);
+}
+
+
+/** Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+	u32 cur = bp->tx_cur;
+	u32 ctrl;
+
+	/* Check for TX ring overflow */
+	if (bp->tx[cur].ctrl) {
+		DBG("tx overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Will call netdev_tx_complete() on the iobuf later */
+	bp->tx_iobuf[cur] = iobuf;
+
+	/* Set up TX descriptor */
+	ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) |
+	    DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
+
+	if (cur == B44_RING_LAST)
+		ctrl |= DESC_CTRL_EOT;
+
+	bp->tx[cur].ctrl = cpu_to_le32(ctrl);
+	bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data));
+
+	/* Update next available descriptor index */
+	cur = ring_next(cur);
+	bp->tx_cur = cur;
+	wmb();
+
+	/* Tell card that a new TX descriptor is ready */
+	bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc));
+	return 0;
+}
+
+
+/** Recycles sent TX descriptors and notifies network stack
+ *
+ * @v bp Driver state
+ */
+static void b44_tx_complete(struct b44_private *bp)
+{
+	u32 cur, i;
+
+	cur = pending_tx_index(bp);
+
+	for (i = bp->tx_dirty; i != cur; i = ring_next(i)) {
+		/* Free finished frame */
+		netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]);
+		bp->tx_iobuf[i] = NULL;
+
+		/* Clear TX descriptor */
+		bp->tx[i].ctrl = 0;
+		bp->tx[i].addr = 0;
+	}
+	bp->tx_dirty = cur;
+}
+
+
+static void b44_process_rx_packets(struct b44_private *bp)
+{
+	struct io_buffer *iob;	/* received data */
+	struct rx_header *rh;
+	u32 pending, i;
+	u16 len;
+
+	pending = pending_rx_index(bp);
+
+	for (i = bp->rx_cur; i != pending; i = ring_next(i)) {
+		iob = bp->rx_iobuf[i];
+		if (iob == NULL)
+			break;
+
+		rh = iob->data;
+		len = le16_to_cpu(rh->len);
+
+		/*
+		 * Guard against incompletely written RX descriptors.
+		 * Without this, things can get really slow!
+		 */
+		if (len == 0)
+			break;
+
+		/* Discard CRC that is generated by the card */
+		len -= 4;
+
+		/* Check for invalid packets and errors */
+		if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET ||
+		    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
+			DBG("rx error len=%d flags=%04x\n", len,
+			                 cpu_to_le16(rh->flags));
+			rh->len = 0;
+			rh->flags = 0;
+			netdev_rx_err(bp->netdev, iob, -EINVAL);
+			continue;
+		}
+
+		/* Clear RX descriptor */
+		rh->len = 0;
+		rh->flags = 0;
+		bp->rx_iobuf[i] = NULL;
+
+		/* Hand off the IO buffer to the network stack */
+		iob_reserve(iob, RX_PKT_OFFSET);
+		iob_put(iob, len);
+		netdev_rx(bp->netdev, iob);
+	}
+	bp->rx_cur = i;
+	b44_rx_refill(bp, pending_rx_index(bp));
+}
+
+
+/** Poll for completed and received packets
+ *
+ * @v netdev	Network device
+ */
+static void b44_poll(struct net_device *netdev)
+{
+	struct b44_private *bp = netdev_priv(netdev);
+	u32 istat;
+
+	/* Interrupt status */
+	istat = br32(bp, B44_ISTAT);
+	istat &= IMASK_DEF;	/* only the events we care about */
+
+	if (!istat)
+		return;
+	if (istat & ISTAT_TX)
+		b44_tx_complete(bp);
+	if (istat & ISTAT_RX)
+		b44_process_rx_packets(bp);
+	if (istat & ISTAT_ERRORS) {
+		DBG("b44 error istat=0x%08x\n", istat);
+
+		/* Reset B44 core partially to avoid long waits */
+		b44_irq(bp->netdev, 0);
+		b44_halt(bp);
+		b44_init_tx_ring(bp);
+		b44_init_rx_ring(bp);
+		b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
+	}
+
+	/* Acknowledge interrupt */
+	bw32(bp, B44_ISTAT, 0);
+	bflush(bp, B44_ISTAT, 1);
+}
+
+
+static struct net_device_operations b44_operations = {
+	.open = b44_open,
+	.close = b44_close,
+	.transmit = b44_transmit,
+	.poll = b44_poll,
+	.irq = b44_irq,
+};
+
+
+static struct pci_device_id b44_nics[] = {
+	PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401", 0),
+	PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0", 0),
+	PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1", 0),
+};
+
+
+struct pci_driver b44_driver __pci_driver = {
+	.ids = b44_nics,
+	.id_count = sizeof b44_nics / sizeof b44_nics[0],
+	.probe = b44_probe,
+	.remove = b44_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.h
new file mode 100644
index 0000000..2d1f206
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/b44.h
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha at gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem at redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp at ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _B44_H
+#define _B44_H
+
+/* BCM44xx Register layout */
+#define	B44_DEVCTRL		0x0000UL /* Device Control */
+#define  DEVCTRL_MPM		0x00000040 /* MP PME Enable (B0 only) */
+#define  DEVCTRL_PFE		0x00000080 /* Pattern Filtering Enable */
+#define  DEVCTRL_IPP		0x00000400 /* Internal EPHY Present */
+#define  DEVCTRL_EPR		0x00008000 /* EPHY Reset */
+#define  DEVCTRL_PME		0x00001000 /* PHY Mode Enable */
+#define  DEVCTRL_PMCE		0x00002000 /* PHY Mode Clocks Enable */
+#define  DEVCTRL_PADDR		0x0007c000 /* PHY Address */
+#define  DEVCTRL_PADDR_SHIFT	18
+#define B44_BIST_STAT		0x000CUL /* Built-In Self-Test Status */
+#define B44_WKUP_LEN		0x0010UL /* Wakeup Length */
+#define  WKUP_LEN_P0_MASK	0x0000007f /* Pattern 0 */
+#define  WKUP_LEN_D0		0x00000080
+#define  WKUP_LEN_P1_MASK	0x00007f00 /* Pattern 1 */
+#define  WKUP_LEN_P1_SHIFT	8
+#define  WKUP_LEN_D1		0x00008000
+#define  WKUP_LEN_P2_MASK	0x007f0000 /* Pattern 2 */
+#define  WKUP_LEN_P2_SHIFT	16
+#define  WKUP_LEN_D2		0x00000000
+#define  WKUP_LEN_P3_MASK	0x7f000000 /* Pattern 3 */
+#define  WKUP_LEN_P3_SHIFT	24
+#define  WKUP_LEN_D3		0x80000000
+#define  WKUP_LEN_DISABLE	0x80808080
+#define  WKUP_LEN_ENABLE_TWO	0x80800000
+#define  WKUP_LEN_ENABLE_THREE	0x80000000
+#define B44_ISTAT		0x0020UL /* Interrupt Status */
+#define  ISTAT_LS		0x00000020 /* Link Change (B0 only) */
+#define  ISTAT_PME		0x00000040 /* Power Management Event */
+#define  ISTAT_TO		0x00000080 /* General Purpose Timeout */
+#define  ISTAT_DSCE		0x00000400 /* Descriptor Error */
+#define  ISTAT_DATAE		0x00000800 /* Data Error */
+#define  ISTAT_DPE		0x00001000 /* Descr. Protocol Error */
+#define  ISTAT_RDU		0x00002000 /* Receive Descr. Underflow */
+#define  ISTAT_RFO		0x00004000 /* Receive FIFO Overflow */
+#define  ISTAT_TFU		0x00008000 /* Transmit FIFO Underflow */
+#define  ISTAT_RX		0x00010000 /* RX Interrupt */
+#define  ISTAT_TX		0x01000000 /* TX Interrupt */
+#define  ISTAT_EMAC		0x04000000 /* EMAC Interrupt */
+#define  ISTAT_MII_WRITE	0x08000000 /* MII Write Interrupt */
+#define  ISTAT_MII_READ		0x10000000 /* MII Read Interrupt */
+#define  ISTAT_ERRORS           (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|\
+                                 ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)
+#define B44_IMASK		0x0024UL /* Interrupt Mask */
+#define  IMASK_DEF		(ISTAT_ERRORS | ISTAT_RX | ISTAT_TX)
+#define  IMASK_DISABLE          0
+#define B44_GPTIMER		0x0028UL /* General Purpose Timer */
+#define B44_ADDR_LO		0x0088UL /* ENET Address Lo (B0 only) */
+#define B44_ADDR_HI		0x008CUL /* ENET Address Hi (B0 only) */
+#define B44_FILT_ADDR		0x0090UL /* ENET Filter Address */
+#define B44_FILT_DATA		0x0094UL /* ENET Filter Data */
+#define B44_TXBURST		0x00A0UL /* TX Max Burst Length */
+#define B44_RXBURST		0x00A4UL /* RX Max Burst Length */
+#define B44_MAC_CTRL		0x00A8UL /* MAC Control */
+#define  MAC_CTRL_CRC32_ENAB	0x00000001 /* CRC32 Generation Enable */
+#define  MAC_CTRL_PHY_PDOWN	0x00000004 /* Onchip EPHY Powerdown */
+#define  MAC_CTRL_PHY_EDET	0x00000008 /* Onchip EPHY Energy Detected*/
+#define  MAC_CTRL_PHY_LEDCTRL	0x000000e0 /* Onchip EPHY LED Control */
+#define  MAC_CTRL_PHY_LEDCTRL_SHIFT 5
+#define B44_MAC_FLOW		0x00ACUL /* MAC Flow Control */
+#define  MAC_FLOW_RX_HI_WATER	0x000000ff /* Receive FIFO HI Water Mark */
+#define  MAC_FLOW_PAUSE_ENAB	0x00008000 /* Enbl Pause Frm Generation */
+#define B44_RCV_LAZY		0x0100UL /* Lazy Interrupt Control */
+#define  RCV_LAZY_TO_MASK	0x00ffffff /* Timeout */
+#define  RCV_LAZY_FC_MASK	0xff000000 /* Frame Count */
+#define  RCV_LAZY_FC_SHIFT	24
+#define B44_DMATX_CTRL		0x0200UL /* DMA TX Control */
+#define  DMATX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMATX_CTRL_SUSPEND	0x00000002 /* Suepend Request */
+#define  DMATX_CTRL_LPBACK	0x00000004 /* Loopback Enable */
+#define  DMATX_CTRL_FAIRPRIOR	0x00000008 /* Fair Priority */
+#define  DMATX_CTRL_FLUSH	0x00000010 /* Flush Request */
+#define B44_DMATX_ADDR		0x0204UL /* DMA TX Descriptor Ring Addr */
+#define B44_DMATX_PTR		0x0208UL /* DMA TX Last Posted Desc. */
+#define B44_DMATX_STAT		0x020CUL /* DMA TX Cur Actve Desc. + Sts */
+#define  DMATX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMATX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMATX_STAT_SDISABLED	0x00000000 /* State Disabled */
+#define  DMATX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMATX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMATX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMATX_STAT_SSUSP	0x00004000 /* State Suspend Pending */
+#define  DMATX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMATX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMATX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMATX_STAT_EDFU	0x00020000 /* Error Data FIFO Underrun */
+#define  DMATX_STAT_EBEBR	0x00030000 /* Bus Error on Buffer Read */
+#define  DMATX_STAT_EBEDA	0x00040000 /* Bus Error on Desc. Access */
+#define  DMATX_STAT_FLUSHED	0x00100000 /* Flushed */
+#define B44_DMARX_CTRL		0x0210UL /* DMA RX Control */
+#define  DMARX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMARX_CTRL_ROMASK	0x000000fe /* Receive Offset Mask */
+#define  DMARX_CTRL_ROSHIFT	1 	   /* Receive Offset Shift */
+#define B44_DMARX_ADDR		0x0214UL /* DMA RX Descriptor Ring Addr */
+#define B44_DMARX_PTR		0x0218UL /* DMA RX Last Posted Desc */
+#define B44_DMARX_STAT		0x021CUL /* Cur Active Desc. + Status */
+#define  DMARX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMARX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMARX_STAT_SDISABLED	0x00000000 /* State Disbaled */
+#define  DMARX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMARX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMARX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMARX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMARX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMARX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMARX_STAT_EDFO	0x00020000 /* Error Data FIFO Overflow */
+#define  DMARX_STAT_EBEBW	0x00030000 /* Error on Buffer Write */
+#define  DMARX_STAT_EBEDA	0x00040000 /* Bus Error on Desc. Access */
+#define B44_DMAFIFO_AD		0x0220UL /* DMA FIFO Diag Address */
+#define  DMAFIFO_AD_OMASK	0x0000ffff /* Offset Mask */
+#define  DMAFIFO_AD_SMASK	0x000f0000 /* Select Mask */
+#define  DMAFIFO_AD_SXDD	0x00000000 /* Select Transmit DMA Data */
+#define  DMAFIFO_AD_SXDP	0x00010000 /* Sel Transmit DMA Pointers */
+#define  DMAFIFO_AD_SRDD	0x00040000 /* Select Receive DMA Data */
+#define  DMAFIFO_AD_SRDP	0x00050000 /* Sel Receive DMA Pointers */
+#define  DMAFIFO_AD_SXFD	0x00080000 /* Select Transmit FIFO Data */
+#define  DMAFIFO_AD_SXFP	0x00090000 /* Sel Transmit FIFO Pointers */
+#define  DMAFIFO_AD_SRFD	0x000c0000 /* Select Receive FIFO Data */
+#define  DMAFIFO_AD_SRFP	0x000c0000 /* Sel Receive FIFO Pointers */
+#define B44_DMAFIFO_LO		0x0224UL /* DMA FIFO Diag Low Data */
+#define B44_DMAFIFO_HI		0x0228UL /* DMA FIFO Diag High Data */
+#define B44_RXCONFIG		0x0400UL /* EMAC RX Config */
+#define  RXCONFIG_DBCAST	0x00000001 /* Disable Broadcast */
+#define  RXCONFIG_ALLMULTI	0x00000002 /* Accept All Multicast */
+#define  RXCONFIG_NORX_WHILE_TX	0x00000004 /* Rcv Disble While TX */
+#define  RXCONFIG_PROMISC	0x00000008 /* Promiscuous Enable */
+#define  RXCONFIG_LPBACK	0x00000010 /* Loopback Enable */
+#define  RXCONFIG_FLOW		0x00000020 /* Flow Control Enable */
+#define  RXCONFIG_FLOW_ACCEPT	0x00000040 /* Accept UFC Frame */
+#define  RXCONFIG_RFILT		0x00000080 /* Reject Filter */
+#define B44_RXMAXLEN		0x0404UL /* EMAC RX Max Packet Length */
+#define B44_TXMAXLEN		0x0408UL /* EMAC TX Max Packet Length */
+#define B44_MDIO_CTRL		0x0410UL /* EMAC MDIO Control */
+#define  MDIO_CTRL_MAXF_MASK	0x0000007f /* MDC Frequency */
+#define  MDIO_CTRL_PREAMBLE	0x00000080 /* MII Preamble Enable */
+#define B44_MDIO_DATA		0x0414UL /* EMAC MDIO Data */
+#define  MDIO_DATA_DATA		0x0000ffff /* R/W Data */
+#define  MDIO_DATA_TA_MASK	0x00030000 /* Turnaround Value */
+#define  MDIO_DATA_TA_SHIFT	16
+#define  MDIO_TA_VALID		2
+#define  MDIO_DATA_RA_MASK	0x007c0000 /* Register Address */
+#define  MDIO_DATA_RA_SHIFT	18
+#define  MDIO_DATA_PMD_MASK	0x0f800000 /* Physical Media Device */
+#define  MDIO_DATA_PMD_SHIFT	23
+#define  MDIO_DATA_OP_MASK	0x30000000 /* Opcode */
+#define  MDIO_DATA_OP_SHIFT	28
+#define  MDIO_OP_WRITE		1
+#define  MDIO_OP_READ		2
+#define  MDIO_DATA_SB_MASK	0xc0000000 /* Start Bits */
+#define  MDIO_DATA_SB_SHIFT	30
+#define  MDIO_DATA_SB_START	0x40000000 /* Start Of Frame */
+#define B44_EMAC_IMASK		0x0418UL /* EMAC Interrupt Mask */
+#define B44_EMAC_ISTAT		0x041CUL /* EMAC Interrupt Status */
+#define  EMAC_INT_MII		0x00000001 /* MII MDIO Interrupt */
+#define  EMAC_INT_MIB		0x00000002 /* MIB Interrupt */
+#define  EMAC_INT_FLOW		0x00000003 /* Flow Control Interrupt */
+#define B44_CAM_DATA_LO		0x0420UL /* EMAC CAM Data Low */
+#define B44_CAM_DATA_HI		0x0424UL /* EMAC CAM Data High */
+#define  CAM_DATA_HI_VALID	0x00010000 /* Valid Bit */
+#define B44_CAM_CTRL		0x0428UL /* EMAC CAM Control */
+#define  CAM_CTRL_ENABLE	0x00000001 /* CAM Enable */
+#define  CAM_CTRL_MSEL		0x00000002 /* Mask Select */
+#define  CAM_CTRL_READ		0x00000004 /* Read */
+#define  CAM_CTRL_WRITE		0x00000008 /* Read */
+#define  CAM_CTRL_INDEX_MASK	0x003f0000 /* Index Mask */
+#define  CAM_CTRL_INDEX_SHIFT	16
+#define  CAM_CTRL_BUSY		0x80000000 /* CAM Busy */
+#define B44_ENET_CTRL		0x042CUL /* EMAC ENET Control */
+#define  ENET_CTRL_ENABLE	0x00000001 /* EMAC Enable */
+#define  ENET_CTRL_DISABLE	0x00000002 /* EMAC Disable */
+#define  ENET_CTRL_SRST		0x00000004 /* EMAC Soft Reset */
+#define  ENET_CTRL_EPSEL	0x00000008 /* External PHY Select */
+#define B44_TX_CTRL		0x0430UL /* EMAC TX Control */
+#define  TX_CTRL_DUPLEX		0x00000001 /* Full Duplex */
+#define  TX_CTRL_FMODE		0x00000002 /* Flow Mode */
+#define  TX_CTRL_SBENAB		0x00000004 /* Single Backoff Enable */
+#define  TX_CTRL_SMALL_SLOT	0x00000008 /* Small Slottime */
+#define B44_TX_HIWMARK		0x0434UL /* EMAC TX High Watermark */
+#define  TX_HIWMARK_DEFLT	56  /* Default used in all drivers */
+#define B44_MIB_CTRL		0x0438UL /* EMAC MIB Control */
+#define  MIB_CTRL_CLR_ON_READ	0x00000001 /* Autoclear on Read */
+#define B44_TX_GOOD_O		0x0500UL /* MIB TX Good Octets */
+#define B44_TX_GOOD_P		0x0504UL /* MIB TX Good Packets */
+#define B44_TX_O		0x0508UL /* MIB TX Octets */
+#define B44_TX_P		0x050CUL /* MIB TX Packets */
+#define B44_TX_BCAST		0x0510UL /* MIB TX Broadcast Packets */
+#define B44_TX_MCAST		0x0514UL /* MIB TX Multicast Packets */
+#define B44_TX_64		0x0518UL /* MIB TX <= 64 byte Packets */
+#define B44_TX_65_127		0x051CUL /* MIB TX 65 to 127 byte Pkts */
+#define B44_TX_128_255		0x0520UL /* MIB TX 128 to 255 byte Pkts */
+#define B44_TX_256_511		0x0524UL /* MIB TX 256 to 511 byte Pkts */
+#define B44_TX_512_1023		0x0528UL /* MIB TX 512 to 1023 byte Pkts */
+#define B44_TX_1024_MAX		0x052CUL /* MIB TX 1024 to max byte Pkts */
+#define B44_TX_JABBER		0x0530UL /* MIB TX Jabber Packets */
+#define B44_TX_OSIZE		0x0534UL /* MIB TX Oversize Packets */
+#define B44_TX_FRAG		0x0538UL /* MIB TX Fragment Packets */
+#define B44_TX_URUNS		0x053CUL /* MIB TX Underruns */
+#define B44_TX_TCOLS		0x0540UL /* MIB TX Total Collisions */
+#define B44_TX_SCOLS		0x0544UL /* MIB TX Single Collisions */
+#define B44_TX_MCOLS		0x0548UL /* MIB TX Multiple Collisions */
+#define B44_TX_ECOLS		0x054CUL /* MIB TX Excessive Collisions */
+#define B44_TX_LCOLS		0x0550UL /* MIB TX Late Collisions */
+#define B44_TX_DEFERED		0x0554UL /* MIB TX Defered Packets */
+#define B44_TX_CLOST		0x0558UL /* MIB TX Carrier Lost */
+#define B44_TX_PAUSE		0x055CUL /* MIB TX Pause Packets */
+#define B44_RX_GOOD_O		0x0580UL /* MIB RX Good Octets */
+#define B44_RX_GOOD_P		0x0584UL /* MIB RX Good Packets */
+#define B44_RX_O		0x0588UL /* MIB RX Octets */
+#define B44_RX_P		0x058CUL /* MIB RX Packets */
+#define B44_RX_BCAST		0x0590UL /* MIB RX Broadcast Packets */
+#define B44_RX_MCAST		0x0594UL /* MIB RX Multicast Packets */
+#define B44_RX_64		0x0598UL /* MIB RX <= 64 byte Packets */
+#define B44_RX_65_127		0x059CUL /* MIB RX 65 to 127 byte Pkts */
+#define B44_RX_128_255		0x05A0UL /* MIB RX 128 to 255 byte Pkts */
+#define B44_RX_256_511		0x05A4UL /* MIB RX 256 to 511 byte Pkts */
+#define B44_RX_512_1023		0x05A8UL /* MIB RX 512 to 1023 byte Pkts */
+#define B44_RX_1024_MAX		0x05ACUL /* MIB RX 1024 to max byte Pkts */
+#define B44_RX_JABBER		0x05B0UL /* MIB RX Jabber Packets */
+#define B44_RX_OSIZE		0x05B4UL /* MIB RX Oversize Packets */
+#define B44_RX_FRAG		0x05B8UL /* MIB RX Fragment Packets */
+#define B44_RX_MISS		0x05BCUL /* MIB RX Missed Packets */
+#define B44_RX_CRCA		0x05C0UL /* MIB RX CRC Align Errors */
+#define B44_RX_USIZE		0x05C4UL /* MIB RX Undersize Packets */
+#define B44_RX_CRC		0x05C8UL /* MIB RX CRC Errors */
+#define B44_RX_ALIGN		0x05CCUL /* MIB RX Align Errors */
+#define B44_RX_SYM		0x05D0UL /* MIB RX Symbol Errors */
+#define B44_RX_PAUSE		0x05D4UL /* MIB RX Pause Packets */
+#define B44_RX_NPAUSE		0x05D8UL /* MIB RX Non-Pause Packets */
+
+/* Sonics Silicon backplane register definitions */
+#define B44_SBIMSTATE		0x0F90UL /* SB Initiator Agent State */
+#define  SBIMSTATE_PC		0x0000000f /* Pipe Count */
+#define  SBIMSTATE_AP_MASK	0x00000030 /* Arbitration Priority */
+#define  SBIMSTATE_AP_BOTH	0x00000000 /* both timeslices and token */
+#define  SBIMSTATE_AP_TS	0x00000010 /* Use timeslices only */
+#define  SBIMSTATE_AP_TK	0x00000020 /* Use token only */
+#define  SBIMSTATE_AP_RSV	0x00000030 /* Reserved */
+#define  SBIMSTATE_IBE		0x00020000 /* In Band Error */
+#define  SBIMSTATE_TO		0x00040000 /* Timeout */
+#define  SBIMSTATE_BAD      ( SBIMSTATE_IBE | SBIMSTATE_TO )
+#define B44_SBINTVEC		0x0F94UL /* SB Interrupt Mask */
+#define  SBINTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+#define  SBINTVEC_ENET0		0x00000002 /* Enable ints for enet 0 */
+#define  SBINTVEC_ILINE20	0x00000004 /* Enable ints for iline20 */
+#define  SBINTVEC_CODEC		0x00000008 /* Enable ints for v90 codec */
+#define  SBINTVEC_USB		0x00000010 /* Enable intts for usb */
+#define  SBINTVEC_EXTIF		0x00000020 /* Enable ints for ext i/f */
+#define  SBINTVEC_ENET1		0x00000040 /* Enable ints for enet 1 */
+#define B44_SBTMSLOW		0x0F98UL /* SB Target State Low */
+#define  SBTMSLOW_RESET		0x00000001 /* Reset */
+#define  SBTMSLOW_REJECT	0x00000002 /* Reject */
+#define  SBTMSLOW_CLOCK		0x00010000 /* Clock Enable */
+#define  SBTMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+#define  SBTMSLOW_PE		0x40000000 /* Power Management Enable */
+#define  SBTMSLOW_BE		0x80000000 /* BIST Enable */
+#define B44_SBTMSHIGH		0x0F9CUL /* SB Target State High */
+#define  SBTMSHIGH_SERR		0x00000001 /* S-error */
+#define  SBTMSHIGH_INT		0x00000002 /* Interrupt */
+#define  SBTMSHIGH_BUSY		0x00000004 /* Busy */
+#define  SBTMSHIGH_GCR		0x20000000 /* Gated Clock Request */
+#define  SBTMSHIGH_BISTF	0x40000000 /* BIST Failed */
+#define  SBTMSHIGH_BISTD	0x80000000 /* BIST Done */
+#define B44_SBIDHIGH		0x0FFCUL /* SB Identification High */
+#define  SBIDHIGH_RC_MASK	0x0000000f /* Revision Code */
+#define  SBIDHIGH_CC_MASK	0x0000fff0 /* Core Code */
+#define  SBIDHIGH_CC_SHIFT	4
+#define  SBIDHIGH_VC_MASK	0xffff0000 /* Vendor Code */
+#define  SBIDHIGH_VC_SHIFT	16
+
+/* SSB PCI config space registers.  */
+#define SSB_PMCSR		0x44
+#define  SSB_PE			0x100
+#define	SSB_BAR0_WIN		0x80
+#define	SSB_BAR1_WIN		0x84
+#define	SSB_SPROM_CONTROL	0x88
+#define	SSB_BAR1_CONTROL	0x8c
+
+/* SSB core and host control registers.  */
+#define SSB_CONTROL		0x0000UL
+#define SSB_ARBCONTROL		0x0010UL
+#define SSB_ISTAT		0x0020UL
+#define SSB_IMASK		0x0024UL
+#define SSB_MBOX		0x0028UL
+#define SSB_BCAST_ADDR		0x0050UL
+#define SSB_BCAST_DATA		0x0054UL
+#define SSB_PCI_TRANS_0		0x0100UL
+#define SSB_PCI_TRANS_1		0x0104UL
+#define SSB_PCI_TRANS_2		0x0108UL
+#define SSB_SPROM		0x0800UL
+
+#define SSB_PCI_MEM		0x00000000
+#define SSB_PCI_IO		0x00000001
+#define SSB_PCI_CFG0		0x00000002
+#define SSB_PCI_CFG1		0x00000003
+#define SSB_PCI_PREF		0x00000004
+#define SSB_PCI_BURST		0x00000008
+#define SSB_PCI_MASK0		0xfc000000
+#define SSB_PCI_MASK1		0xfc000000
+#define SSB_PCI_MASK2		0xc0000000
+
+/* 4400 PHY registers */
+#define B44_MII_AUXCTRL		24	/* Auxiliary Control */
+#define  MII_AUXCTRL_DUPLEX	0x0001  /* Full Duplex */
+#define  MII_AUXCTRL_SPEED	0x0002  /* 1=100Mbps, 0=10Mbps */
+#define  MII_AUXCTRL_FORCED	0x0004	/* Forced 10/100 */
+#define B44_MII_ALEDCTRL	26	/* Activity LED */
+#define  MII_ALEDCTRL_ALLMSK	0x7fff
+#define B44_MII_TLEDCTRL	27	/* Traffic Meter LED */
+#define  MII_TLEDCTRL_ENABLE	0x0040
+
+/* RX/TX descriptor */
+struct dma_desc {
+	u32 ctrl; /* length of data and flags */
+	u32 addr; /* address of data */
+};
+
+/* There are only 12 bits in the DMA engine for descriptor offsetting
+ * so the table must be aligned on a boundary of this.
+ */
+#define B44_DMA_ALIGNMENT	4096
+
+/* The DMA engine can only address the first gigabyte of address space
+ */
+#define B44_30BIT_DMA_MASK	0x3fffffff
+
+#define DESC_CTRL_LEN		0x00001fff
+#define DESC_CTRL_CMASK		0x0ff00000 /* Core specific bits */
+#define DESC_CTRL_EOT		0x10000000 /* End of Table */
+#define DESC_CTRL_IOC		0x20000000 /* Interrupt On Completion */
+#define DESC_CTRL_EOF		0x40000000 /* End of Frame */
+#define DESC_CTRL_SOF		0x80000000 /* Start of Frame */
+
+struct rx_header {
+	u16 len;
+	u16 flags;
+	u16 pad[12];
+};
+#define RX_HEADER_LEN	28
+
+#define RX_FLAG_OFIFO	0x00000001 /* FIFO Overflow */
+#define RX_FLAG_CRCERR	0x00000002 /* CRC Error */
+#define RX_FLAG_SERR	0x00000004 /* Receive Symbol Error */
+#define RX_FLAG_ODD	0x00000008 /* Frame has odd number of nibbles */
+#define RX_FLAG_LARGE	0x00000010 /* Frame is > RX MAX Length */
+#define RX_FLAG_MCAST	0x00000020 /* Dest is Multicast Address */
+#define RX_FLAG_BCAST	0x00000040 /* Dest is Broadcast Address */
+#define RX_FLAG_MISS	0x00000080 /* Received due to promisc mode */
+#define RX_FLAG_LAST	0x00000800 /* Last buffer in frame */
+#define RX_FLAG_ERRORS	(RX_FLAG_ODD | RX_FLAG_SERR |\
+                         RX_FLAG_CRCERR | RX_FLAG_OFIFO)
+
+/* Client Mode PCI memory access space (1 GB) */
+#define SB_PCI_DMA              0x40000000
+
+ /* Address of PCI core on BCM4400 cards */
+#define BCM4400_PCI_CORE_ADDR   0x18002000
+
+/* Hardware minimum and maximum for a single frame's data payload */
+#define B44_MIN_MTU		60
+#define B44_MAX_MTU		1500
+
+#define B44_RING_SIZE           8
+#define B44_RING_LAST           ( B44_RING_SIZE - 1 )
+
+#define B44_RX_RING_LEN_BYTES	( sizeof bp->rx[0] * B44_RING_SIZE )
+#define B44_TX_RING_LEN_BYTES	( sizeof bp->tx[0] * B44_RING_SIZE )
+
+#define RX_PKT_OFFSET		30
+#define RX_PKT_BUF_SZ		(1536 + RX_PKT_OFFSET + 64)
+
+#define B44_FULL_RESET		1
+#define B44_FULL_RESET_SKIP_PHY	2
+#define B44_PARTIAL_RESET	3
+#define B44_CHIP_RESET_FULL     4
+#define B44_CHIP_RESET_PARTIAL  5
+
+#define SSB_CORE_DOWN           ( SBTMSLOW_RESET | SBTMSLOW_REJECT )
+
+#define B44_REGS_SIZE           8192
+
+/** Driver private state */
+struct b44_private {
+	struct net_device *netdev;
+	struct pci_device *pci;
+	u8 *regs; /* memory-mapped registers */
+	u8 phy_addr;
+
+	struct dma_desc *tx;
+	struct io_buffer *tx_iobuf[B44_RING_SIZE];
+	u32 tx_cur; /* next available descriptor */
+	u32 tx_dirty; /* oldest pending descriptor */
+
+	struct dma_desc *rx;
+	struct io_buffer *rx_iobuf[B44_RING_SIZE];
+	u32 rx_cur; /* next descriptor to read */
+};
+
+
+static void ssb_core_reset ( struct b44_private *bp );
+static void ssb_core_disable ( struct b44_private *bp );
+static u32 ssb_pci_setup ( struct b44_private *bp, u32 cores );
+
+static void b44_chip_reset ( struct b44_private *bp, int reset_kind );
+static void b44_init_hw ( struct b44_private *bp, int reset_kind );
+static void b44_cam_write ( struct b44_private *bp, u8 *data, int index );
+static void b44_set_mac_addr ( struct b44_private *bp );
+static void b44_set_rx_mode ( struct net_device *netdev );
+static void b44_halt(struct b44_private *);
+
+static int b44_phy_reset ( struct b44_private *bp );
+static int b44_phy_write ( struct b44_private *bp, int reg, u32 val );
+static int b44_phy_read ( struct b44_private *bp, int reg, u32 *val );
+
+static int b44_init_tx_ring ( struct b44_private *bp );
+static void b44_free_tx_ring ( struct b44_private *bp );
+static int b44_init_rx_ring ( struct b44_private *bp );
+static void b44_free_rx_ring ( struct b44_private *bp );
+static void b44_rx_refill ( struct b44_private *bp, u32 pending );
+static void b44_populate_rx_descriptor (struct b44_private *bp, u32 index);
+
+static int b44_probe ( struct pci_device *pci );
+static void b44_remove ( struct pci_device *pci );
+
+static int b44_open ( struct net_device *netdev );
+static void b44_close ( struct net_device *netdev );
+static void b44_irq ( struct net_device *netdev, int enable );
+static void b44_poll ( struct net_device *netdev );
+static void b44_process_rx_packets ( struct b44_private *bp );
+static int b44_transmit ( struct net_device *netdev,
+                          struct io_buffer *iobuf );
+
+static struct net_device_operations b44_operations;
+
+#endif /* _B44_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.c
new file mode 100644
index 0000000..a986bde
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.c
@@ -0,0 +1,2697 @@
+/* bnx2.c: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Michael Chan  (mchan at broadcom.com)
+ *
+ * Etherboot port by Ryan Jackson (rjackson at lnxi.com), based on driver
+ * version 1.4.40 from linux 2.6.17
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#include "etherboot.h"
+#include "nic.h"
+#include <errno.h>
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include "string.h"
+#include <mii.h>
+#include "bnx2.h"
+#include "bnx2_fw.h"
+
+#if 0
+/* Dummy defines for error handling */
+#define EBUSY  1
+#define ENODEV 2
+#define EINVAL 3
+#define ENOMEM 4
+#define EIO    5
+#endif
+
+/* The bnx2 seems to be picky about the alignment of the receive buffers
+ * and possibly the status block.
+ */
+static struct bss {
+	struct tx_bd tx_desc_ring[TX_DESC_CNT];
+	struct rx_bd rx_desc_ring[RX_DESC_CNT];
+	unsigned char rx_buf[RX_BUF_CNT][RX_BUF_SIZE];
+	struct status_block status_blk;
+	struct statistics_block stats_blk;
+} bnx2_bss;
+
+static struct bnx2 bnx2;
+
+static struct flash_spec flash_table[] =
+{
+	/* Slow EEPROM */
+	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
+	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
+	 "EEPROM - slow"},
+	/* Expansion entry 0001 */
+	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 0001"},
+	/* Saifun SA25F010 (non-buffered flash) */
+	/* strap, cfg1, & write1 need updates */
+	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
+	 "Non-buffered flash (128kB)"},
+	/* Saifun SA25F020 (non-buffered flash) */
+	/* strap, cfg1, & write1 need updates */
+	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
+	 "Non-buffered flash (256kB)"},
+	/* Expansion entry 0100 */
+	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 0100"},
+	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
+	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,        
+	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
+	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
+	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
+	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
+	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
+	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
+	/* Saifun SA25F005 (non-buffered flash) */
+	/* strap, cfg1, & write1 need updates */
+	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
+	 "Non-buffered flash (64kB)"},
+	/* Fast EEPROM */
+	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
+	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
+	 "EEPROM - fast"},
+	/* Expansion entry 1001 */
+	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 1001"},
+	/* Expansion entry 1010 */
+	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 1010"},
+	/* ATMEL AT45DB011B (buffered flash) */
+	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
+	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
+	 "Buffered flash (128kB)"},
+	/* Expansion entry 1100 */
+	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 1100"},
+	/* Expansion entry 1101 */
+	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
+	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 1101"},
+	/* Ateml Expansion entry 1110 */
+	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
+	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
+	 "Entry 1110 (Atmel)"},
+	/* ATMEL AT45DB021B (buffered flash) */
+	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
+	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
+	 "Buffered flash (256kB)"},
+};
+
+static u32
+bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
+{
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
+	return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
+}
+
+static void
+bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
+{
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
+	REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
+}
+
+static void
+bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
+{
+	offset += cid_addr;
+	REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
+	REG_WR(bp, BNX2_CTX_DATA, val);
+}
+
+static int
+bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
+{
+	u32 val1;
+	int i, ret;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	val1 = (bp->phy_addr << 21) | (reg << 16) |
+		BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
+		BNX2_EMAC_MDIO_COMM_START_BUSY;
+	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+
+			val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+			val1 &= BNX2_EMAC_MDIO_COMM_DATA;
+
+			break;
+		}
+	}
+
+	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
+		*val = 0x0;
+		ret = -EBUSY;
+	}
+	else {
+		*val = val1;
+		ret = 0;
+	}
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	return ret;
+}
+
+static int
+bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
+{
+	u32 val1;
+	int i, ret;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	val1 = (bp->phy_addr << 21) | (reg << 16) | val |
+		BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
+		BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
+	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
+    
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
+		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+			break;
+		}
+	}
+
+	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
+        	ret = -EBUSY;
+	else
+		ret = 0;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
+
+		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
+		REG_RD(bp, BNX2_EMAC_MDIO_MODE);
+
+		udelay(40);
+	}
+
+	return ret;
+}
+
+static void
+bnx2_disable_int(struct bnx2 *bp)
+{
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+	REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
+
+}
+
+static int
+bnx2_alloc_mem(struct bnx2 *bp)
+{
+	bp->tx_desc_ring = bnx2_bss.tx_desc_ring;
+	bp->tx_desc_mapping = virt_to_bus(bp->tx_desc_ring);
+
+	bp->rx_desc_ring = bnx2_bss.rx_desc_ring;
+	memset(bp->rx_desc_ring, 0, sizeof(struct rx_bd) * RX_DESC_CNT);
+	bp->rx_desc_mapping = virt_to_bus(bp->rx_desc_ring);
+
+	memset(&bnx2_bss.status_blk, 0, sizeof(struct status_block));
+	bp->status_blk = &bnx2_bss.status_blk;
+	bp->status_blk_mapping = virt_to_bus(&bnx2_bss.status_blk);
+
+	bp->stats_blk = &bnx2_bss.stats_blk;
+	memset(&bnx2_bss.stats_blk, 0, sizeof(struct statistics_block));
+	bp->stats_blk_mapping = virt_to_bus(&bnx2_bss.stats_blk);
+
+	return 0;
+}
+
+static void
+bnx2_report_fw_link(struct bnx2 *bp)
+{
+	u32 fw_link_status = 0;
+
+	if (bp->link_up) {
+		u32 bmsr;
+
+		switch (bp->line_speed) {
+		case SPEED_10:
+			if (bp->duplex == DUPLEX_HALF)
+				fw_link_status = BNX2_LINK_STATUS_10HALF;
+			else
+				fw_link_status = BNX2_LINK_STATUS_10FULL;
+			break;
+		case SPEED_100:
+			if (bp->duplex == DUPLEX_HALF)
+				fw_link_status = BNX2_LINK_STATUS_100HALF;
+			else
+				fw_link_status = BNX2_LINK_STATUS_100FULL;
+			break;
+		case SPEED_1000:
+			if (bp->duplex == DUPLEX_HALF)
+				fw_link_status = BNX2_LINK_STATUS_1000HALF;
+			else
+				fw_link_status = BNX2_LINK_STATUS_1000FULL;
+			break;
+		case SPEED_2500:
+			if (bp->duplex == DUPLEX_HALF)
+				fw_link_status = BNX2_LINK_STATUS_2500HALF;
+			else
+				fw_link_status = BNX2_LINK_STATUS_2500FULL;
+			break;
+		}
+
+		fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
+
+		if (bp->autoneg) {
+			fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
+
+			bnx2_read_phy(bp, MII_BMSR, &bmsr);
+			bnx2_read_phy(bp, MII_BMSR, &bmsr);
+
+			if (!(bmsr & BMSR_ANEGCOMPLETE) ||
+			    bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
+				fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
+			else
+				fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
+		}
+	}
+	else
+		fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
+
+	REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
+}
+
+static void
+bnx2_report_link(struct bnx2 *bp)
+{
+	if (bp->link_up) {
+		printf("NIC Link is Up, ");
+
+		printf("%d Mbps ", bp->line_speed);
+
+		if (bp->duplex == DUPLEX_FULL)
+			printf("full duplex");
+		else
+			printf("half duplex");
+
+		if (bp->flow_ctrl) {
+			if (bp->flow_ctrl & FLOW_CTRL_RX) {
+				printf(", receive ");
+				if (bp->flow_ctrl & FLOW_CTRL_TX)
+					printf("& transmit ");
+			}
+			else {
+				printf(", transmit ");
+			}
+			printf("flow control ON");
+		}
+		printf("\n");
+	}
+	else {
+		printf("NIC Link is Down\n");
+	}
+
+	bnx2_report_fw_link(bp);
+}
+
+static void
+bnx2_resolve_flow_ctrl(struct bnx2 *bp)
+{
+	u32 local_adv, remote_adv;
+
+	bp->flow_ctrl = 0;
+	if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) != 
+		(AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
+
+		if (bp->duplex == DUPLEX_FULL) {
+			bp->flow_ctrl = bp->req_flow_ctrl;
+		}
+		return;
+	}
+
+	if (bp->duplex != DUPLEX_FULL) {
+		return;
+	}
+
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5708)) {
+		u32 val;
+
+		bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
+		if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
+			bp->flow_ctrl |= FLOW_CTRL_TX;
+		if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
+			bp->flow_ctrl |= FLOW_CTRL_RX;
+		return;
+	}
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		u32 new_local_adv = 0;
+		u32 new_remote_adv = 0;
+
+		if (local_adv & ADVERTISE_1000XPAUSE)
+			new_local_adv |= ADVERTISE_PAUSE_CAP;
+		if (local_adv & ADVERTISE_1000XPSE_ASYM)
+			new_local_adv |= ADVERTISE_PAUSE_ASYM;
+		if (remote_adv & ADVERTISE_1000XPAUSE)
+			new_remote_adv |= ADVERTISE_PAUSE_CAP;
+		if (remote_adv & ADVERTISE_1000XPSE_ASYM)
+			new_remote_adv |= ADVERTISE_PAUSE_ASYM;
+
+		local_adv = new_local_adv;
+		remote_adv = new_remote_adv;
+	}
+
+	/* See Table 28B-3 of 802.3ab-1999 spec. */
+	if (local_adv & ADVERTISE_PAUSE_CAP) {
+		if(local_adv & ADVERTISE_PAUSE_ASYM) {
+	                if (remote_adv & ADVERTISE_PAUSE_CAP) {
+				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			}
+			else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
+				bp->flow_ctrl = FLOW_CTRL_RX;
+			}
+		}
+		else {
+			if (remote_adv & ADVERTISE_PAUSE_CAP) {
+				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			}
+		}
+	}
+	else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+		if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
+			(remote_adv & ADVERTISE_PAUSE_ASYM)) {
+
+			bp->flow_ctrl = FLOW_CTRL_TX;
+		}
+	}
+}
+
+static int
+bnx2_5708s_linkup(struct bnx2 *bp)
+{
+	u32 val;
+
+	bp->link_up = 1;
+	bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
+	switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
+		case BCM5708S_1000X_STAT1_SPEED_10:
+			bp->line_speed = SPEED_10;
+			break;
+		case BCM5708S_1000X_STAT1_SPEED_100:
+			bp->line_speed = SPEED_100;
+			break;
+		case BCM5708S_1000X_STAT1_SPEED_1G:
+			bp->line_speed = SPEED_1000;
+			break;
+		case BCM5708S_1000X_STAT1_SPEED_2G5:
+			bp->line_speed = SPEED_2500;
+			break;
+	}
+	if (val & BCM5708S_1000X_STAT1_FD)
+		bp->duplex = DUPLEX_FULL;
+	else
+		bp->duplex = DUPLEX_HALF;
+
+	return 0;
+}
+
+static int
+bnx2_5706s_linkup(struct bnx2 *bp)
+{
+	u32 bmcr, local_adv, remote_adv, common;
+
+	bp->link_up = 1;
+	bp->line_speed = SPEED_1000;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	if (bmcr & BMCR_FULLDPLX) {
+		bp->duplex = DUPLEX_FULL;
+	}
+	else {
+		bp->duplex = DUPLEX_HALF;
+	}
+
+	if (!(bmcr & BMCR_ANENABLE)) {
+		return 0;
+	}
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+	common = local_adv & remote_adv;
+	if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
+
+		if (common & ADVERTISE_1000XFULL) {
+			bp->duplex = DUPLEX_FULL;
+		}
+		else {
+			bp->duplex = DUPLEX_HALF;
+		}
+	}
+
+	return 0;
+}
+
+static int
+bnx2_copper_linkup(struct bnx2 *bp)
+{
+	u32 bmcr;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	if (bmcr & BMCR_ANENABLE) {
+		u32 local_adv, remote_adv, common;
+
+		bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
+		bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
+
+		common = local_adv & (remote_adv >> 2);
+		if (common & ADVERTISE_1000FULL) {
+			bp->line_speed = SPEED_1000;
+			bp->duplex = DUPLEX_FULL;
+		}
+		else if (common & ADVERTISE_1000HALF) {
+			bp->line_speed = SPEED_1000;
+			bp->duplex = DUPLEX_HALF;
+		}
+		else {
+			bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
+			bnx2_read_phy(bp, MII_LPA, &remote_adv);
+
+			common = local_adv & remote_adv;
+			if (common & ADVERTISE_100FULL) {
+				bp->line_speed = SPEED_100;
+				bp->duplex = DUPLEX_FULL;
+			}
+			else if (common & ADVERTISE_100HALF) {
+				bp->line_speed = SPEED_100;
+				bp->duplex = DUPLEX_HALF;
+			}
+			else if (common & ADVERTISE_10FULL) {
+				bp->line_speed = SPEED_10;
+				bp->duplex = DUPLEX_FULL;
+			}
+			else if (common & ADVERTISE_10HALF) {
+				bp->line_speed = SPEED_10;
+				bp->duplex = DUPLEX_HALF;
+			}
+			else {
+				bp->line_speed = 0;
+				bp->link_up = 0;
+			}
+		}
+	}
+	else {
+		if (bmcr & BMCR_SPEED100) {
+			bp->line_speed = SPEED_100;
+		}
+		else {
+			bp->line_speed = SPEED_10;
+		}
+		if (bmcr & BMCR_FULLDPLX) {
+			bp->duplex = DUPLEX_FULL;
+		}
+		else {
+			bp->duplex = DUPLEX_HALF;
+		}
+	}
+
+	return 0;
+}
+
+static int
+bnx2_set_mac_link(struct bnx2 *bp)
+{
+	u32 val;
+
+	REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
+	if (bp->link_up && (bp->line_speed == SPEED_1000) &&
+		(bp->duplex == DUPLEX_HALF)) {
+		REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
+	}
+
+	/* Configure the EMAC mode register. */
+	val = REG_RD(bp, BNX2_EMAC_MODE);
+
+	val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
+		BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
+		BNX2_EMAC_MODE_25G);
+
+	if (bp->link_up) {
+		switch (bp->line_speed) {
+			case SPEED_10:
+				if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+					val |= BNX2_EMAC_MODE_PORT_MII_10;
+					break;
+				}
+				/* fall through */
+			case SPEED_100:
+				val |= BNX2_EMAC_MODE_PORT_MII;
+				break;
+			case SPEED_2500:
+				val |= BNX2_EMAC_MODE_25G;
+				/* fall through */
+			case SPEED_1000:
+				val |= BNX2_EMAC_MODE_PORT_GMII;
+				break;
+		}
+	}
+	else {
+		val |= BNX2_EMAC_MODE_PORT_GMII;
+	}
+
+	/* Set the MAC to operate in the appropriate duplex mode. */
+	if (bp->duplex == DUPLEX_HALF)
+		val |= BNX2_EMAC_MODE_HALF_DUPLEX;
+	REG_WR(bp, BNX2_EMAC_MODE, val);
+
+	/* Enable/disable rx PAUSE. */
+	bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
+
+	if (bp->flow_ctrl & FLOW_CTRL_RX)
+		bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
+	REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
+
+	/* Enable/disable tx PAUSE. */
+	val = REG_RD(bp, BNX2_EMAC_TX_MODE);
+	val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
+
+	if (bp->flow_ctrl & FLOW_CTRL_TX)
+		val |= BNX2_EMAC_TX_MODE_FLOW_EN;
+	REG_WR(bp, BNX2_EMAC_TX_MODE, val);
+
+	/* Acknowledge the interrupt. */
+	REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
+
+	return 0;
+}
+
+static int
+bnx2_set_link(struct bnx2 *bp)
+{
+	u32 bmsr;
+	u8 link_up;
+
+	if (bp->loopback == MAC_LOOPBACK) {
+		bp->link_up = 1;
+		return 0;
+	}
+
+	link_up = bp->link_up;
+
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
+		u32 val;
+
+		val = REG_RD(bp, BNX2_EMAC_STATUS);
+		if (val & BNX2_EMAC_STATUS_LINK)
+			bmsr |= BMSR_LSTATUS;
+		else
+			bmsr &= ~BMSR_LSTATUS;
+	}
+
+	if (bmsr & BMSR_LSTATUS) {
+		bp->link_up = 1;
+
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			if (CHIP_NUM(bp) == CHIP_NUM_5706)
+				bnx2_5706s_linkup(bp);
+			else if (CHIP_NUM(bp) == CHIP_NUM_5708)
+				bnx2_5708s_linkup(bp);
+		}
+		else {
+			bnx2_copper_linkup(bp);
+		}
+		bnx2_resolve_flow_ctrl(bp);
+	}
+	else {
+		if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+			(bp->autoneg & AUTONEG_SPEED)) {
+
+			u32 bmcr;
+
+			bnx2_read_phy(bp, MII_BMCR, &bmcr);
+			if (!(bmcr & BMCR_ANENABLE)) {
+				bnx2_write_phy(bp, MII_BMCR, bmcr |
+					BMCR_ANENABLE);
+			}
+		}
+		bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+		bp->link_up = 0;
+	}
+
+	if (bp->link_up != link_up) {
+		bnx2_report_link(bp);
+	}
+
+	bnx2_set_mac_link(bp);
+
+	return 0;
+}
+
+static int
+bnx2_reset_phy(struct bnx2 *bp)
+{
+	int i;
+	u32 reg;
+
+        bnx2_write_phy(bp, MII_BMCR, BMCR_RESET);
+
+#define PHY_RESET_MAX_WAIT 100
+	for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
+		udelay(10);
+
+		bnx2_read_phy(bp, MII_BMCR, &reg);
+		if (!(reg & BMCR_RESET)) {
+			udelay(20);
+			break;
+		}
+	}
+	if (i == PHY_RESET_MAX_WAIT) {
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static u32
+bnx2_phy_get_pause_adv(struct bnx2 *bp)
+{
+	u32 adv = 0;
+
+	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
+		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {
+
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPAUSE;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_CAP;
+		}
+	}
+	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPSE_ASYM;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_ASYM;
+		}
+	}
+	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
+		if (bp->phy_flags & PHY_SERDES_FLAG) {
+			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+		}
+		else {
+			adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+		}
+	}
+	return adv;
+}
+
+static int
+bnx2_setup_serdes_phy(struct bnx2 *bp)
+{
+	u32 adv, bmcr, up1;
+	u32 new_adv = 0;
+
+	if (!(bp->autoneg & AUTONEG_SPEED)) {
+		u32 new_bmcr;
+		int force_link_down = 0;
+
+		if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+			bnx2_read_phy(bp, BCM5708S_UP1, &up1);
+			if (up1 & BCM5708S_UP1_2G5) {
+				up1 &= ~BCM5708S_UP1_2G5;
+				bnx2_write_phy(bp, BCM5708S_UP1, up1);
+				force_link_down = 1;
+			}
+		}
+
+		bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+		adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
+
+		bnx2_read_phy(bp, MII_BMCR, &bmcr);
+		new_bmcr = bmcr & ~BMCR_ANENABLE;
+		new_bmcr |= BMCR_SPEED1000;
+		if (bp->req_duplex == DUPLEX_FULL) {
+			adv |= ADVERTISE_1000XFULL;
+			new_bmcr |= BMCR_FULLDPLX;
+		}
+		else {
+			adv |= ADVERTISE_1000XHALF;
+			new_bmcr &= ~BMCR_FULLDPLX;
+		}
+		if ((new_bmcr != bmcr) || (force_link_down)) {
+			/* Force a link down visible on the other side */
+			if (bp->link_up) {
+				bnx2_write_phy(bp, MII_ADVERTISE, adv &
+					       ~(ADVERTISE_1000XFULL |
+						 ADVERTISE_1000XHALF));
+				bnx2_write_phy(bp, MII_BMCR, bmcr |
+					BMCR_ANRESTART | BMCR_ANENABLE);
+
+				bp->link_up = 0;
+				bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+			}
+			bnx2_write_phy(bp, MII_ADVERTISE, adv);
+			bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+		}
+		return 0;
+	}
+
+	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
+		bnx2_read_phy(bp, BCM5708S_UP1, &up1);
+		up1 |= BCM5708S_UP1_2G5;
+		bnx2_write_phy(bp, BCM5708S_UP1, up1);
+	}
+
+	if (bp->advertising & ADVERTISED_1000baseT_Full)
+		new_adv |= ADVERTISE_1000XFULL;
+
+	new_adv |= bnx2_phy_get_pause_adv(bp);
+
+	bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+
+	bp->serdes_an_pending = 0;
+	if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
+		/* Force a link down visible on the other side */
+		if (bp->link_up) {
+			int i;
+
+			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			for (i = 0; i < 110; i++) {
+				udelay(100);
+			}
+		}
+
+		bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
+		bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
+			BMCR_ANENABLE);
+#if 0
+		if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+			/* Speed up link-up time when the link partner
+			 * does not autonegotiate which is very common
+			 * in blade servers. Some blade servers use
+			 * IPMI for kerboard input and it's important
+			 * to minimize link disruptions. Autoneg. involves
+			 * exchanging base pages plus 3 next pages and
+			 * normally completes in about 120 msec.
+			 */
+			bp->current_interval = SERDES_AN_TIMEOUT;
+			bp->serdes_an_pending = 1;
+			mod_timer(&bp->timer, jiffies + bp->current_interval);
+		}
+#endif
+	}
+
+	return 0;
+}
+
+#define ETHTOOL_ALL_FIBRE_SPEED						\
+	(ADVERTISED_1000baseT_Full)
+
+#define ETHTOOL_ALL_COPPER_SPEED					\
+	(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |		\
+	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |		\
+	ADVERTISED_1000baseT_Full)
+
+#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+	ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
+	
+#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
+
+static int
+bnx2_setup_copper_phy(struct bnx2 *bp)
+{
+	u32 bmcr;
+	u32 new_bmcr;
+
+	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+
+	if (bp->autoneg & AUTONEG_SPEED) {
+		u32 adv_reg, adv1000_reg;
+		u32 new_adv_reg = 0;
+		u32 new_adv1000_reg = 0;
+
+		bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg);
+		adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
+			ADVERTISE_PAUSE_ASYM);
+
+		bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
+		adv1000_reg &= PHY_ALL_1000_SPEED;
+
+		if (bp->advertising & ADVERTISED_10baseT_Half)
+			new_adv_reg |= ADVERTISE_10HALF;
+		if (bp->advertising & ADVERTISED_10baseT_Full)
+			new_adv_reg |= ADVERTISE_10FULL;
+		if (bp->advertising & ADVERTISED_100baseT_Half)
+			new_adv_reg |= ADVERTISE_100HALF;
+		if (bp->advertising & ADVERTISED_100baseT_Full)
+			new_adv_reg |= ADVERTISE_100FULL;
+		if (bp->advertising & ADVERTISED_1000baseT_Full)
+			new_adv1000_reg |= ADVERTISE_1000FULL;
+		
+		new_adv_reg |= ADVERTISE_CSMA;
+
+		new_adv_reg |= bnx2_phy_get_pause_adv(bp);
+
+		if ((adv1000_reg != new_adv1000_reg) ||
+			(adv_reg != new_adv_reg) ||
+			((bmcr & BMCR_ANENABLE) == 0)) {
+
+			bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg);
+			bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
+			bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART |
+				BMCR_ANENABLE);
+		}
+		else if (bp->link_up) {
+			/* Flow ctrl may have changed from auto to forced */
+			/* or vice-versa. */
+
+			bnx2_resolve_flow_ctrl(bp);
+			bnx2_set_mac_link(bp);
+		}
+		return 0;
+	}
+
+	new_bmcr = 0;
+	if (bp->req_line_speed == SPEED_100) {
+		new_bmcr |= BMCR_SPEED100;
+	}
+	if (bp->req_duplex == DUPLEX_FULL) {
+		new_bmcr |= BMCR_FULLDPLX;
+	}
+	if (new_bmcr != bmcr) {
+		u32 bmsr;
+		int i = 0;
+
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		
+		if (bmsr & BMSR_LSTATUS) {
+			/* Force link down */
+			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			do {
+				udelay(100);
+				bnx2_read_phy(bp, MII_BMSR, &bmsr);
+				bnx2_read_phy(bp, MII_BMSR, &bmsr);
+				i++;
+			} while ((bmsr & BMSR_LSTATUS) && (i < 620));
+		}
+
+		bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+
+		/* Normally, the new speed is setup after the link has
+		 * gone down and up again. In some cases, link will not go
+		 * down so we need to set up the new speed here.
+		 */
+		if (bmsr & BMSR_LSTATUS) {
+			bp->line_speed = bp->req_line_speed;
+			bp->duplex = bp->req_duplex;
+			bnx2_resolve_flow_ctrl(bp);
+			bnx2_set_mac_link(bp);
+		}
+	}
+	return 0;
+}
+
+static int
+bnx2_setup_phy(struct bnx2 *bp)
+{
+	if (bp->loopback == MAC_LOOPBACK)
+		return 0;
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		return (bnx2_setup_serdes_phy(bp));
+	}
+	else {
+		return (bnx2_setup_copper_phy(bp));
+	}
+}
+
+static int
+bnx2_init_5708s_phy(struct bnx2 *bp)
+{
+	u32 val;
+
+	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
+	bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
+	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
+
+	bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
+	val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
+	bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
+
+	bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
+	val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
+	bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
+
+	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
+		bnx2_read_phy(bp, BCM5708S_UP1, &val);
+		val |= BCM5708S_UP1_2G5;
+		bnx2_write_phy(bp, BCM5708S_UP1, val);
+	}
+
+	if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
+	    (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
+	    (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
+		/* increase tx signal amplitude */
+		bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
+			       BCM5708S_BLK_ADDR_TX_MISC);
+		bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
+		val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
+		bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
+		bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
+	}
+
+	val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
+	      BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
+
+	if (val) {
+		u32 is_backplane;
+
+		is_backplane = REG_RD_IND(bp, bp->shmem_base +
+					  BNX2_SHARED_HW_CFG_CONFIG);
+		if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
+			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
+				       BCM5708S_BLK_ADDR_TX_MISC);
+			bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
+			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
+				       BCM5708S_BLK_ADDR_DIG);
+		}
+	}
+	return 0;
+}
+
+static int
+bnx2_init_5706s_phy(struct bnx2 *bp)
+{
+	u32 val;
+
+	bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+        	REG_WR(bp, BNX2_MISC_UNUSED0, 0x300);
+	}
+
+
+	bnx2_write_phy(bp, 0x18, 0x7);
+	bnx2_read_phy(bp, 0x18, &val);
+	bnx2_write_phy(bp, 0x18, val & ~0x4007);
+
+	bnx2_write_phy(bp, 0x1c, 0x6c00);
+	bnx2_read_phy(bp, 0x1c, &val);
+	bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
+
+	return 0;
+}
+
+static int
+bnx2_init_copper_phy(struct bnx2 *bp)
+{
+	u32 val;
+
+	bp->phy_flags |= PHY_CRC_FIX_FLAG;
+
+	if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
+		bnx2_write_phy(bp, 0x18, 0x0c00);
+		bnx2_write_phy(bp, 0x17, 0x000a);
+		bnx2_write_phy(bp, 0x15, 0x310b);
+		bnx2_write_phy(bp, 0x17, 0x201f);
+		bnx2_write_phy(bp, 0x15, 0x9506);
+		bnx2_write_phy(bp, 0x17, 0x401f);
+		bnx2_write_phy(bp, 0x15, 0x14e2);
+		bnx2_write_phy(bp, 0x18, 0x0400);
+	}
+
+	bnx2_write_phy(bp, 0x18, 0x7);
+	bnx2_read_phy(bp, 0x18, &val);
+	bnx2_write_phy(bp, 0x18, val & ~0x4007);
+
+	bnx2_read_phy(bp, 0x10, &val);
+	bnx2_write_phy(bp, 0x10, val & ~0x1);
+
+	/* ethernet at wirespeed */
+	bnx2_write_phy(bp, 0x18, 0x7007);
+	bnx2_read_phy(bp, 0x18, &val);
+	bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
+	return 0;
+}
+
+static int
+bnx2_init_phy(struct bnx2 *bp)
+{
+	u32 val;
+	int rc = 0;
+
+	bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
+	bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
+
+        REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+
+	bnx2_reset_phy(bp);
+
+	bnx2_read_phy(bp, MII_PHYSID1, &val);
+	bp->phy_id = val << 16;
+	bnx2_read_phy(bp, MII_PHYSID2, &val);
+	bp->phy_id |= val & 0xffff;
+
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		if (CHIP_NUM(bp) == CHIP_NUM_5706)
+			rc = bnx2_init_5706s_phy(bp);
+		else if (CHIP_NUM(bp) == CHIP_NUM_5708)
+			rc = bnx2_init_5708s_phy(bp);
+	}
+	else {
+		rc = bnx2_init_copper_phy(bp);
+	}
+
+	bnx2_setup_phy(bp);
+
+	return rc;
+}
+
+static int
+bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
+{
+	int i;
+	u32 val;
+
+	bp->fw_wr_seq++;
+	msg_data |= bp->fw_wr_seq;
+
+	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
+
+	/* wait for an acknowledgement. */
+	for (i = 0; i < (FW_ACK_TIME_OUT_MS / 50); i++) {
+		mdelay(50);
+
+		val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
+
+		if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
+			break;
+	}
+	if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
+		return 0;
+
+	/* If we timed out, inform the firmware that this is the case. */
+	if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
+		if (!silent)
+		  printf("fw sync timeout, reset code = %x\n", (unsigned int) msg_data);
+
+		msg_data &= ~BNX2_DRV_MSG_CODE;
+		msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
+
+		REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
+
+		return -EBUSY;
+	}
+
+	if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
+		return -EIO;
+
+	return 0;
+}
+
+static void
+bnx2_init_context(struct bnx2 *bp)
+{
+	u32 vcid;
+
+	vcid = 96;
+	while (vcid) {
+		u32 vcid_addr, pcid_addr, offset;
+
+		vcid--;
+
+		if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+			u32 new_vcid;
+
+			vcid_addr = GET_PCID_ADDR(vcid);
+			if (vcid & 0x8) {
+				new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
+			}
+			else {
+				new_vcid = vcid;
+			}
+			pcid_addr = GET_PCID_ADDR(new_vcid);
+		}
+		else {
+	    		vcid_addr = GET_CID_ADDR(vcid);
+			pcid_addr = vcid_addr;
+		}
+
+		REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
+		REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+
+		/* Zero out the context. */
+		for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
+			CTX_WR(bp, 0x00, offset, 0);
+		}
+
+		REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
+		REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+	}
+}
+
+static int
+bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+{
+	u16 good_mbuf[512];
+	u32 good_mbuf_cnt;
+	u32 val;
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
+		BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
+
+	good_mbuf_cnt = 0;
+
+	/* Allocate a bunch of mbufs and save the good ones in an array. */
+	val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+	while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
+		REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
+
+		val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
+
+		val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
+
+		/* The addresses with Bit 9 set are bad memory blocks. */
+		if (!(val & (1 << 9))) {
+			good_mbuf[good_mbuf_cnt] = (u16) val;
+			good_mbuf_cnt++;
+		}
+
+		val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+	}
+
+	/* Free the good ones back to the mbuf pool thus discarding
+	 * all the bad ones. */
+	while (good_mbuf_cnt) {
+		good_mbuf_cnt--;
+
+		val = good_mbuf[good_mbuf_cnt];
+		val = (val << 9) | val | 1;
+
+		REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
+	}
+	return 0;
+}
+
+static void
+bnx2_set_mac_addr(struct bnx2 *bp) 
+{
+	u32 val;
+	u8 *mac_addr = bp->nic->node_addr;
+
+	val = (mac_addr[0] << 8) | mac_addr[1];
+
+	REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
+
+	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | 
+		(mac_addr[4] << 8) | mac_addr[5];
+
+	REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
+}
+
+static void
+bnx2_set_rx_mode(struct nic *nic __unused)
+{
+	struct bnx2 *bp = &bnx2;
+	u32 rx_mode, sort_mode;
+	int i;
+
+	rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
+				  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
+	sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
+
+	if (!(bp->flags & ASF_ENABLE_FLAG)) {
+		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
+	}
+
+	/* Accept all multicasts */
+	for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
+		REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
+		       0xffffffff);
+       	}
+	sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
+
+	if (rx_mode != bp->rx_mode) {
+		bp->rx_mode = rx_mode;
+		REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
+	}
+
+	REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
+	REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
+	REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
+}
+
+static void
+load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, u32 rv2p_proc)
+{
+	unsigned int i;
+	u32 val;
+
+
+	for (i = 0; i < rv2p_code_len; i += 8) {
+		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code);
+		rv2p_code++;
+		REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code);
+		rv2p_code++;
+
+		if (rv2p_proc == RV2P_PROC1) {
+			val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
+			REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
+		}
+		else {
+			val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
+			REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
+		}
+	}
+
+	/* Reset the processor, un-stall is done later. */
+	if (rv2p_proc == RV2P_PROC1) {
+		REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
+	}
+	else {
+		REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
+	}
+}
+
+static void
+load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+{
+	u32 offset;
+	u32 val;
+
+	/* Halt the CPU. */
+	val = REG_RD_IND(bp, cpu_reg->mode);
+	val |= cpu_reg->mode_value_halt;
+	REG_WR_IND(bp, cpu_reg->mode, val);
+	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+
+	/* Load the Text area. */
+	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
+	if (fw->text) {
+		unsigned int j;
+
+		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->text[j]);
+	        }
+	}
+
+	/* Load the Data area. */
+	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
+	if (fw->data) {
+		unsigned int j;
+
+		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->data[j]);
+		}
+	}
+
+	/* Load the SBSS area. */
+	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
+	if (fw->sbss) {
+		unsigned int j;
+
+		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->sbss[j]);
+		}
+	}
+
+	/* Load the BSS area. */
+	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
+	if (fw->bss) {
+		unsigned int j;
+
+		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->bss[j]);
+		}
+	}
+
+	/* Load the Read-Only area. */
+	offset = cpu_reg->spad_base +
+		(fw->rodata_addr - cpu_reg->mips_view_base);
+	if (fw->rodata) {
+		unsigned int j;
+
+		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
+			REG_WR_IND(bp, offset, fw->rodata[j]);
+		}
+	}
+
+	/* Clear the pre-fetch instruction. */
+	REG_WR_IND(bp, cpu_reg->inst, 0);
+	REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
+
+	/* Start the CPU. */
+	val = REG_RD_IND(bp, cpu_reg->mode);
+	val &= ~cpu_reg->mode_value_halt;
+	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+	REG_WR_IND(bp, cpu_reg->mode, val);
+}
+
+static void
+bnx2_init_cpus(struct bnx2 *bp)
+{
+	struct cpu_reg cpu_reg;
+	struct fw_info fw;
+
+	/* Unfortunately, it looks like we need to load the firmware
+	 * before the card will work properly.  That means this driver
+	 * will be huge by Etherboot standards (approx. 50K compressed).
+	 */
+
+	/* Initialize the RV2P processor. */
+	load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1);
+	load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2);
+
+	/* Initialize the RX Processor. */
+	cpu_reg.mode = BNX2_RXP_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_RXP_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_RXP_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+
+	fw.ver_major = bnx2_RXP_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_RXP_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_RXP_b06FwReleaseFix;
+	fw.start_addr = bnx2_RXP_b06FwStartAddr;
+
+	fw.text_addr = bnx2_RXP_b06FwTextAddr;
+	fw.text_len = bnx2_RXP_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_RXP_b06FwText;
+
+	fw.data_addr = bnx2_RXP_b06FwDataAddr;
+	fw.data_len = bnx2_RXP_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_RXP_b06FwData;
+
+	fw.sbss_addr = bnx2_RXP_b06FwSbssAddr;
+	fw.sbss_len = bnx2_RXP_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_RXP_b06FwSbss;
+
+	fw.bss_addr = bnx2_RXP_b06FwBssAddr;
+	fw.bss_len = bnx2_RXP_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_RXP_b06FwBss;
+
+	fw.rodata_addr = bnx2_RXP_b06FwRodataAddr;
+	fw.rodata_len = bnx2_RXP_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_RXP_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the TX Processor. */
+	cpu_reg.mode = BNX2_TXP_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_TXP_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_TXP_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_TXP_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_TXP_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_TXP_b06FwReleaseFix;
+	fw.start_addr = bnx2_TXP_b06FwStartAddr;
+
+	fw.text_addr = bnx2_TXP_b06FwTextAddr;
+	fw.text_len = bnx2_TXP_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_TXP_b06FwText;
+
+	fw.data_addr = bnx2_TXP_b06FwDataAddr;
+	fw.data_len = bnx2_TXP_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_TXP_b06FwData;
+
+	fw.sbss_addr = bnx2_TXP_b06FwSbssAddr;
+	fw.sbss_len = bnx2_TXP_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_TXP_b06FwSbss;
+
+	fw.bss_addr = bnx2_TXP_b06FwBssAddr;
+	fw.bss_len = bnx2_TXP_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_TXP_b06FwBss;
+
+	fw.rodata_addr = bnx2_TXP_b06FwRodataAddr;
+	fw.rodata_len = bnx2_TXP_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_TXP_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the TX Patch-up Processor. */
+	cpu_reg.mode = BNX2_TPAT_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_TPAT_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_TPAT_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_TPAT_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_TPAT_b06FwReleaseFix;
+	fw.start_addr = bnx2_TPAT_b06FwStartAddr;
+
+	fw.text_addr = bnx2_TPAT_b06FwTextAddr;
+	fw.text_len = bnx2_TPAT_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_TPAT_b06FwText;
+
+	fw.data_addr = bnx2_TPAT_b06FwDataAddr;
+	fw.data_len = bnx2_TPAT_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_TPAT_b06FwData;
+
+	fw.sbss_addr = bnx2_TPAT_b06FwSbssAddr;
+	fw.sbss_len = bnx2_TPAT_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_TPAT_b06FwSbss;
+
+	fw.bss_addr = bnx2_TPAT_b06FwBssAddr;
+	fw.bss_len = bnx2_TPAT_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_TPAT_b06FwBss;
+
+	fw.rodata_addr = bnx2_TPAT_b06FwRodataAddr;
+	fw.rodata_len = bnx2_TPAT_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_TPAT_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+	/* Initialize the Completion Processor. */
+	cpu_reg.mode = BNX2_COM_CPU_MODE;
+	cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
+	cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
+	cpu_reg.state = BNX2_COM_CPU_STATE;
+	cpu_reg.state_value_clear = 0xffffff;
+	cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
+	cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
+	cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
+	cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
+	cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
+	cpu_reg.spad_base = BNX2_COM_SCRATCH;
+	cpu_reg.mips_view_base = 0x8000000;
+    
+	fw.ver_major = bnx2_COM_b06FwReleaseMajor;
+	fw.ver_minor = bnx2_COM_b06FwReleaseMinor;
+	fw.ver_fix = bnx2_COM_b06FwReleaseFix;
+	fw.start_addr = bnx2_COM_b06FwStartAddr;
+
+	fw.text_addr = bnx2_COM_b06FwTextAddr;
+	fw.text_len = bnx2_COM_b06FwTextLen;
+	fw.text_index = 0;
+	fw.text = bnx2_COM_b06FwText;
+
+	fw.data_addr = bnx2_COM_b06FwDataAddr;
+	fw.data_len = bnx2_COM_b06FwDataLen;
+	fw.data_index = 0;
+	fw.data = bnx2_COM_b06FwData;
+
+	fw.sbss_addr = bnx2_COM_b06FwSbssAddr;
+	fw.sbss_len = bnx2_COM_b06FwSbssLen;
+	fw.sbss_index = 0;
+	fw.sbss = bnx2_COM_b06FwSbss;
+
+	fw.bss_addr = bnx2_COM_b06FwBssAddr;
+	fw.bss_len = bnx2_COM_b06FwBssLen;
+	fw.bss_index = 0;
+	fw.bss = bnx2_COM_b06FwBss;
+
+	fw.rodata_addr = bnx2_COM_b06FwRodataAddr;
+	fw.rodata_len = bnx2_COM_b06FwRodataLen;
+	fw.rodata_index = 0;
+	fw.rodata = bnx2_COM_b06FwRodata;
+
+	load_cpu_fw(bp, &cpu_reg, &fw);
+
+}
+
+static int
+bnx2_set_power_state_0(struct bnx2 *bp)
+{
+	u16 pmcsr;
+	u32 val;
+
+	pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+
+	pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+		(pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
+		PCI_PM_CTRL_PME_STATUS);
+
+	if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+		/* delay required during transition out of D3hot */
+		mdelay(20);
+
+	val = REG_RD(bp, BNX2_EMAC_MODE);
+	val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
+	val &= ~BNX2_EMAC_MODE_MPKT;
+	REG_WR(bp, BNX2_EMAC_MODE, val);
+
+	val = REG_RD(bp, BNX2_RPM_CONFIG);
+	val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
+	REG_WR(bp, BNX2_RPM_CONFIG, val);
+		
+	return 0;
+}
+
+static void
+bnx2_enable_nvram_access(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+	/* Enable both bits, even on read. */
+	REG_WR(bp, BNX2_NVM_ACCESS_ENABLE, 
+	       val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
+}
+
+static void
+bnx2_disable_nvram_access(struct bnx2 *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
+	/* Disable both bits, even after read. */
+	REG_WR(bp, BNX2_NVM_ACCESS_ENABLE, 
+		val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
+			BNX2_NVM_ACCESS_ENABLE_WR_EN));
+}
+
+static int
+bnx2_init_nvram(struct bnx2 *bp)
+{
+	u32 val;
+	int j, entry_count, rc;
+	struct flash_spec *flash;
+
+	/* Determine the selected interface. */
+	val = REG_RD(bp, BNX2_NVM_CFG1);
+
+	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
+
+	rc = 0;
+	if (val & 0x40000000) {
+		/* Flash interface has been reconfigured */
+		for (j = 0, flash = &flash_table[0]; j < entry_count;
+		     j++, flash++) {
+			if ((val & FLASH_BACKUP_STRAP_MASK) ==
+			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
+				bp->flash_info = flash;
+				break;
+			}
+		}
+	}
+	else {
+		u32 mask;
+		/* Not yet been reconfigured */
+
+		if (val & (1 << 23))
+			mask = FLASH_BACKUP_STRAP_MASK;
+		else
+			mask = FLASH_STRAP_MASK;
+
+		for (j = 0, flash = &flash_table[0]; j < entry_count;
+			j++, flash++) {
+
+			if ((val & mask) == (flash->strapping & mask)) {
+				bp->flash_info = flash;
+
+				/* Enable access to flash interface */
+				bnx2_enable_nvram_access(bp);
+
+				/* Reconfigure the flash interface */
+				REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
+				REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
+				REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
+				REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
+
+				/* Disable access to flash interface */
+				bnx2_disable_nvram_access(bp);
+
+				break;
+			}
+		}
+	} /* if (val & 0x40000000) */
+
+	if (j == entry_count) {
+		bp->flash_info = NULL;
+		printf("Unknown flash/EEPROM type.\n");
+		return -ENODEV;
+	}
+
+	val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
+	val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
+	if (val) {
+		bp->flash_size = val;
+	}
+	else {
+		bp->flash_size = bp->flash_info->total_size;
+	}
+
+	return rc;
+}
+
+static int
+bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+{
+	u32 val;
+	int i, rc = 0;
+
+	/* Wait for the current PCI transaction to complete before
+	 * issuing a reset. */
+	REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
+	       BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
+	       BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
+	val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
+	udelay(5);
+
+
+	/* Wait for the firmware to tell us it is ok to issue a reset. */
+	bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
+
+	/* Deposit a driver reset signature so the firmware knows that
+	 * this is a soft reset. */
+	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
+		   BNX2_DRV_RESET_SIGNATURE_MAGIC);
+
+	/* Do a dummy read to force the chip to complete all current transaction
+	 * before we issue a reset. */
+	val = REG_RD(bp, BNX2_MISC_ID);
+
+	val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+	      BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
+	      BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
+
+	/* Chip reset. */
+	REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
+
+	if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
+	    (CHIP_ID(bp) == CHIP_ID_5706_A1))
+		mdelay(15);
+
+	/* Reset takes approximate 30 usec */
+	for (i = 0; i < 10; i++) {
+		val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
+		if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+			    BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
+			break;
+		}
+		udelay(10);
+	}
+
+	if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
+		   BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
+		printf("Chip reset did not complete\n");
+		return -EBUSY;
+	}
+
+	/* Make sure byte swapping is properly configured. */
+	val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
+	if (val != 0x01020304) {
+		printf("Chip not in correct endian mode\n");
+		return -ENODEV;
+	}
+
+	/* Wait for the firmware to finish its initialization. */
+	rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
+	if (rc) {
+		return rc;
+	}
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		/* Adjust the voltage regular to two steps lower.  The default
+		 * of this register is 0x0000000e. */
+		REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
+
+		/* Remove bad rbuf memory from the free pool. */
+		rc = bnx2_alloc_bad_rbuf(bp);
+	}
+
+	return rc;
+}
+
+static void
+bnx2_disable(struct nic *nic __unused)
+{
+	struct bnx2* bp = &bnx2;
+
+	if (bp->regview) {
+		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_UNLOAD);
+		iounmap(bp->regview);
+	}
+}
+
+static int
+bnx2_init_chip(struct bnx2 *bp)
+{
+	u32 val;
+	int rc;
+
+	/* Make sure the interrupt is not active. */
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+
+	val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
+	      BNX2_DMA_CONFIG_DATA_WORD_SWAP |
+#if __BYTE_ORDER ==  __BIG_ENDIAN
+	      BNX2_DMA_CONFIG_CNTL_BYTE_SWAP | 
+#endif
+	      BNX2_DMA_CONFIG_CNTL_WORD_SWAP | 
+	      DMA_READ_CHANS << 12 |
+	      DMA_WRITE_CHANS << 16;
+
+	val |= (0x2 << 20) | (1 << 11);
+
+	if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
+		val |= (1 << 23);
+
+	if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
+	    (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
+		val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
+
+	REG_WR(bp, BNX2_DMA_CONFIG, val);
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		val = REG_RD(bp, BNX2_TDMA_CONFIG);
+		val |= BNX2_TDMA_CONFIG_ONE_DMA;
+		REG_WR(bp, BNX2_TDMA_CONFIG, val);
+	}
+
+	if (bp->flags & PCIX_FLAG) {
+		u16 val16;
+
+		pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
+				     &val16);
+		pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
+				      val16 & ~PCI_X_CMD_ERO);
+	}
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
+	       BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
+	       BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
+	       BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
+
+	/* Initialize context mapping and zero out the quick contexts.  The
+	 * context block must have already been enabled. */
+	bnx2_init_context(bp);
+
+	bnx2_init_nvram(bp);
+	bnx2_init_cpus(bp);
+
+	bnx2_set_mac_addr(bp);
+
+	val = REG_RD(bp, BNX2_MQ_CONFIG);
+	val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
+	val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
+	REG_WR(bp, BNX2_MQ_CONFIG, val);
+
+	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
+	REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
+	REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
+
+	val = (BCM_PAGE_BITS - 8) << 24;
+	REG_WR(bp, BNX2_RV2P_CONFIG, val);
+
+	/* Configure page size. */
+	val = REG_RD(bp, BNX2_TBDR_CONFIG);
+	val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
+	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
+	REG_WR(bp, BNX2_TBDR_CONFIG, val);
+
+	val = bp->mac_addr[0] +
+	      (bp->mac_addr[1] << 8) +
+	      (bp->mac_addr[2] << 16) +
+	      bp->mac_addr[3] +
+	      (bp->mac_addr[4] << 8) +
+	      (bp->mac_addr[5] << 16);
+	REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
+
+	/* Program the MTU.  Also include 4 bytes for CRC32. */
+	val = ETH_MAX_MTU + ETH_HLEN + 4;
+	if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
+		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
+	REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
+
+	bp->last_status_idx = 0;
+	bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
+
+	/* Set up how to generate a link change interrupt. */
+	REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+
+	REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
+	       (u64) bp->status_blk_mapping & 0xffffffff);
+	REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
+
+	REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
+	       (u64) bp->stats_blk_mapping & 0xffffffff);
+	REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
+	       (u64) bp->stats_blk_mapping >> 32);
+
+	REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP, 
+	       (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
+
+	REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
+	       (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
+
+	REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
+	       (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
+
+	REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
+
+	REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
+
+	REG_WR(bp, BNX2_HC_COM_TICKS,
+	       (bp->com_ticks_int << 16) | bp->com_ticks);
+
+	REG_WR(bp, BNX2_HC_CMD_TICKS,
+	       (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
+
+	REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+	REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A1)
+		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
+	else {
+		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
+		       BNX2_HC_CONFIG_TX_TMR_MODE |
+		       BNX2_HC_CONFIG_COLLECT_STATS);
+	}
+
+	/* Clear internal stats counters. */
+	REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
+
+	REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
+
+	if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
+	    BNX2_PORT_FEATURE_ASF_ENABLED)
+		bp->flags |= ASF_ENABLE_FLAG;
+
+	/* Initialize the receive filter. */
+	bnx2_set_rx_mode(bp->nic);
+
+	rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
+			  0);
+
+	REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 0x5ffffff);
+	REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
+
+	udelay(20);
+
+	bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
+
+	return rc;
+}
+
+static void
+bnx2_init_tx_ring(struct bnx2 *bp)
+{
+	struct tx_bd *txbd;
+	u32 val;
+
+	txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
+		
+	/* Etherboot lives below 4GB, so hi is always 0 */
+	txbd->tx_bd_haddr_hi = 0;
+	txbd->tx_bd_haddr_lo = bp->tx_desc_mapping;
+
+	bp->tx_prod = 0;
+	bp->tx_cons = 0;
+	bp->hw_tx_cons = 0;
+	bp->tx_prod_bseq = 0;
+	
+	val = BNX2_L2CTX_TYPE_TYPE_L2;
+	val |= BNX2_L2CTX_TYPE_SIZE_L2;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TYPE, val);
+
+	val = BNX2_L2CTX_CMD_TYPE_TYPE_L2;
+	val |= 8 << 16;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_CMD_TYPE, val);
+
+	/* Etherboot lives below 4GB, so hi is always 0 */
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_HI, 0);
+
+	val = (u64) bp->tx_desc_mapping & 0xffffffff;
+	CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_LO, val);
+}
+
+static void
+bnx2_init_rx_ring(struct bnx2 *bp)
+{
+	struct rx_bd *rxbd;
+	unsigned int i;
+	u16 prod, ring_prod;
+	u32 val;
+
+	bp->rx_buf_use_size = RX_BUF_USE_SIZE;
+	bp->rx_buf_size = RX_BUF_SIZE;
+
+	ring_prod = prod = bp->rx_prod = 0;
+	bp->rx_cons = 0;
+	bp->hw_rx_cons = 0;
+	bp->rx_prod_bseq = 0;
+
+	memset(bnx2_bss.rx_buf, 0, sizeof(bnx2_bss.rx_buf));
+		
+	rxbd = &bp->rx_desc_ring[0];
+	for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
+		rxbd->rx_bd_len = bp->rx_buf_use_size;
+		rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+	}
+	rxbd->rx_bd_haddr_hi = 0;
+	rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+
+	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
+	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
+	val |= 0x02 << 8;
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
+
+	/* Etherboot doesn't use memory above 4GB, so this is always 0 */
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, 0);
+
+	val = bp->rx_desc_mapping & 0xffffffff;
+	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
+
+	for (i = 0; (int) i < bp->rx_ring_size; i++) {
+		rxbd = &bp->rx_desc_ring[RX_RING_IDX(ring_prod)];
+		rxbd->rx_bd_haddr_hi = 0;
+		rxbd->rx_bd_haddr_lo = virt_to_bus(&bnx2_bss.rx_buf[ring_prod][0]);
+		bp->rx_prod_bseq += bp->rx_buf_use_size;
+		prod = NEXT_RX_BD(prod);
+		ring_prod = RX_RING_IDX(prod);
+	}
+	bp->rx_prod = prod;
+
+	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, bp->rx_prod);
+
+	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+}
+
+static int
+bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
+{
+	int rc;
+
+	rc = bnx2_reset_chip(bp, reset_code);
+	if (rc) {
+		return rc;
+	}
+
+	bnx2_init_chip(bp);
+	bnx2_init_tx_ring(bp);
+	bnx2_init_rx_ring(bp);
+	return 0;
+}
+
+static int
+bnx2_init_nic(struct bnx2 *bp)
+{
+	int rc;
+
+	if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
+		return rc;
+
+	bnx2_init_phy(bp);
+	bnx2_set_link(bp);
+	return 0;
+}
+
+static int
+bnx2_init_board(struct pci_device *pdev, struct nic *nic)
+{
+	unsigned long bnx2reg_base, bnx2reg_len;
+	struct bnx2 *bp = &bnx2;
+	int rc;
+	u32 reg;
+
+	bp->flags = 0;
+	bp->phy_flags = 0;
+
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	adjust_pci_device(pdev);
+
+	nic->ioaddr = pdev->ioaddr & ~3;
+	nic->irqno = 0;
+
+	rc = 0;
+	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (bp->pm_cap == 0) {
+		printf("Cannot find power management capability, aborting.\n");
+		rc = -EIO;
+		goto err_out_disable;
+	}
+
+	bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
+	if (bp->pcix_cap == 0) {
+		printf("Cannot find PCIX capability, aborting.\n");
+		rc = -EIO;
+		goto err_out_disable;
+	}
+
+	bp->pdev = pdev;
+	bp->nic = nic;
+
+	bnx2reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	bnx2reg_len = MB_GET_CID_ADDR(17);
+
+	bp->regview = ioremap(bnx2reg_base, bnx2reg_len);
+
+	if (!bp->regview) {
+		printf("Cannot map register space, aborting.\n");
+		rc = -EIO;
+		goto err_out_disable;
+	}
+
+	/* Configure byte swap and enable write to the reg_window registers.
+	 * Rely on CPU to do target byte swapping on big endian systems
+	 * The chip's target access swapping will not swap all accesses
+	 */
+	pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
+			       BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
+			       BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
+
+	bnx2_set_power_state_0(bp);
+
+	bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
+
+	/* Get bus information. */
+	reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
+	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
+		u32 clkreg;
+
+		bp->flags |= PCIX_FLAG;
+
+		clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
+		
+		clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
+		switch (clkreg) {
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
+			bp->bus_speed_mhz = 133;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
+			bp->bus_speed_mhz = 100;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
+			bp->bus_speed_mhz = 66;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
+			bp->bus_speed_mhz = 50;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
+			bp->bus_speed_mhz = 33;
+			break;
+		}
+	}
+	else {
+		if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
+			bp->bus_speed_mhz = 66;
+		else
+			bp->bus_speed_mhz = 33;
+	}
+
+	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
+		bp->flags |= PCI_32BIT_FLAG;
+
+	/* 5706A0 may falsely detect SERR and PERR. */
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		reg = REG_RD(bp, PCI_COMMAND);
+		reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+		REG_WR(bp, PCI_COMMAND, reg);
+	}
+	else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
+		!(bp->flags & PCIX_FLAG)) {
+
+		printf("5706 A1 can only be used in a PCIX bus, aborting.\n");
+		goto err_out_disable;
+	}
+
+	bnx2_init_nvram(bp);
+
+	reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
+
+	if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
+	    BNX2_SHM_HDR_SIGNATURE_SIG)
+		bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0);
+	else
+		bp->shmem_base = HOST_VIEW_SHMEM_BASE;
+
+	/* Get the permanent MAC address.  First we need to make sure the
+	 * firmware is actually running.
+	 */
+	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
+
+	if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
+	    BNX2_DEV_INFO_SIGNATURE_MAGIC) {
+		printf("Firmware not running, aborting.\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	bp->fw_ver = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
+
+	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
+	bp->mac_addr[0] = (u8) (reg >> 8);
+	bp->mac_addr[1] = (u8) reg;
+
+	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
+	bp->mac_addr[2] = (u8) (reg >> 24);
+	bp->mac_addr[3] = (u8) (reg >> 16);
+	bp->mac_addr[4] = (u8) (reg >> 8);
+	bp->mac_addr[5] = (u8) reg;
+
+	bp->tx_ring_size = MAX_TX_DESC_CNT;
+	bp->rx_ring_size = RX_BUF_CNT;
+	bp->rx_max_ring_idx = MAX_RX_DESC_CNT;
+
+	bp->rx_offset = RX_OFFSET;
+
+	bp->tx_quick_cons_trip_int = 20;
+	bp->tx_quick_cons_trip = 20;
+	bp->tx_ticks_int = 80;
+	bp->tx_ticks = 80;
+		
+	bp->rx_quick_cons_trip_int = 6;
+	bp->rx_quick_cons_trip = 6;
+	bp->rx_ticks_int = 18;
+	bp->rx_ticks = 18;
+
+	bp->stats_ticks = 1000000 & 0xffff00;
+
+	bp->phy_addr = 1;
+
+	/* No need for WOL support in Etherboot */
+	bp->flags |= NO_WOL_FLAG;
+
+	/* Disable WOL support if we are running on a SERDES chip. */
+	if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
+		bp->phy_flags |= PHY_SERDES_FLAG;
+		if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+			bp->phy_addr = 2;
+			reg = REG_RD_IND(bp, bp->shmem_base +
+					 BNX2_SHARED_HW_CFG_CONFIG);
+			if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
+				bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
+		}
+	}
+
+	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
+		bp->tx_quick_cons_trip_int =
+			bp->tx_quick_cons_trip;
+		bp->tx_ticks_int = bp->tx_ticks;
+		bp->rx_quick_cons_trip_int =
+			bp->rx_quick_cons_trip;
+		bp->rx_ticks_int = bp->rx_ticks;
+		bp->comp_prod_trip_int = bp->comp_prod_trip;
+		bp->com_ticks_int = bp->com_ticks;
+		bp->cmd_ticks_int = bp->cmd_ticks;
+	}
+
+	bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
+	bp->req_line_speed = 0;
+	if (bp->phy_flags & PHY_SERDES_FLAG) {
+		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
+
+		reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
+		reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
+		if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
+			bp->autoneg = 0;
+			bp->req_line_speed = bp->line_speed = SPEED_1000;
+			bp->req_duplex = DUPLEX_FULL;
+		}
+	}
+	else {
+		bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
+	}
+
+	bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
+
+	/* Disable driver heartbeat checking */
+	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB,
+			BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE);
+	REG_RD_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB);
+
+	return 0;
+
+err_out_disable:
+	bnx2_disable(nic);
+
+	return rc;
+}
+
+static void
+bnx2_transmit(struct nic *nic, const char *dst_addr,
+		unsigned int type, unsigned int size, const char *packet)
+{
+	/* Sometimes the nic will be behind by a frame.  Using two transmit
+	 * buffers prevents us from timing out in that case.
+	 */
+	static struct eth_frame {
+		uint8_t  dst_addr[ETH_ALEN];
+		uint8_t  src_addr[ETH_ALEN];
+		uint16_t type;
+		uint8_t  data [ETH_FRAME_LEN - ETH_HLEN];
+	} frame[2];
+	static int frame_idx = 0;
+	
+	/* send the packet to destination */
+	struct tx_bd *txbd;
+	struct bnx2 *bp = &bnx2;
+	u16 prod, ring_prod;
+	u16 hw_cons;
+	int i = 0;
+
+	prod = bp->tx_prod;
+	ring_prod = TX_RING_IDX(prod);
+	hw_cons = bp->status_blk->status_tx_quick_consumer_index0;
+	if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
+		hw_cons++;
+	}
+
+	while((hw_cons != prod) && (hw_cons != (PREV_TX_BD(prod)))) {
+		mdelay(10);	/* give the nic a chance */
+		//poll_interruptions();
+		if (++i > 500) { /* timeout 5s for transmit */
+			printf("transmit timed out\n");
+			bnx2_disable(bp->nic);
+			bnx2_init_board(bp->pdev, bp->nic);
+			return;
+		}
+	}
+	if (i != 0) {
+		printf("#");
+	}
+
+	/* Copy the packet to the our local buffer */
+	memcpy(&frame[frame_idx].dst_addr, dst_addr, ETH_ALEN);
+	memcpy(&frame[frame_idx].src_addr, nic->node_addr, ETH_ALEN);
+	frame[frame_idx].type = htons(type);
+	memset(&frame[frame_idx].data, 0, sizeof(frame[frame_idx].data));
+	memcpy(&frame[frame_idx].data, packet, size);
+
+	/* Setup the ring buffer entry to transmit */
+	txbd = &bp->tx_desc_ring[ring_prod];
+	txbd->tx_bd_haddr_hi = 0; /* Etherboot runs under 4GB */
+	txbd->tx_bd_haddr_lo = virt_to_bus(&frame[frame_idx]);
+	txbd->tx_bd_mss_nbytes = (size + ETH_HLEN);
+	txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
+
+	/* Advance to the next entry */
+	prod = NEXT_TX_BD(prod);
+	frame_idx ^= 1;
+
+	bp->tx_prod_bseq += (size + ETH_HLEN);
+
+	REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod);
+	REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
+
+	wmb();
+
+	bp->tx_prod = prod;
+}
+
+static int
+bnx2_poll_link(struct bnx2 *bp)
+{
+	u32 new_link_state, old_link_state, emac_status;
+
+	new_link_state = bp->status_blk->status_attn_bits &
+		STATUS_ATTN_BITS_LINK_STATE;
+
+	old_link_state = bp->status_blk->status_attn_bits_ack &
+		STATUS_ATTN_BITS_LINK_STATE;
+
+	if (!new_link_state && !old_link_state) {
+		/* For some reason the card doesn't always update the link
+		 * status bits properly.  Kick the stupid thing and try again.
+		 */
+		u32 bmsr;
+
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+
+		if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+		    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
+			REG_RD(bp, BNX2_EMAC_STATUS);
+		}
+
+		new_link_state = bp->status_blk->status_attn_bits &
+			STATUS_ATTN_BITS_LINK_STATE;
+
+		old_link_state = bp->status_blk->status_attn_bits_ack &
+			STATUS_ATTN_BITS_LINK_STATE;
+
+		/* Okay, for some reason the above doesn't work with some
+		 * switches (like HP ProCurve). If the above doesn't work,
+		 * check the MAC directly to see if we have a link.  Perhaps we
+		 * should always check the MAC instead probing the MII.
+		 */
+		if (!new_link_state && !old_link_state) {
+			emac_status = REG_RD(bp, BNX2_EMAC_STATUS);
+			if (emac_status & BNX2_EMAC_STATUS_LINK_CHANGE) {
+				/* Acknowledge the link change */
+				REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
+			} else if (emac_status & BNX2_EMAC_STATUS_LINK) {
+				new_link_state = !old_link_state;
+			}
+		}
+
+	}
+
+	if (new_link_state != old_link_state) {
+		if (new_link_state) {
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
+				STATUS_ATTN_BITS_LINK_STATE);
+		}
+		else {
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
+				STATUS_ATTN_BITS_LINK_STATE);
+		}
+
+		bnx2_set_link(bp);
+
+		/* This is needed to take care of transient status
+		 * during link changes.
+		 */
+
+		REG_WR(bp, BNX2_HC_COMMAND,
+		       bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+		REG_RD(bp, BNX2_HC_COMMAND);
+
+	}
+
+	return bp->link_up;
+}
+
+static int
+bnx2_poll(struct nic* nic, int retrieve)
+{
+	struct bnx2 *bp = &bnx2;
+	struct rx_bd *cons_bd, *prod_bd;
+	u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
+	struct l2_fhdr *rx_hdr;
+	int result = 0;
+	unsigned int len;
+	unsigned char *data;
+	u32 status;
+	
+#if 0
+	if ((bp->status_blk->status_idx == bp->last_status_idx) &&
+	    (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
+	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE)) {
+
+		bp->last_status_idx = bp->status_blk->status_idx;
+		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
+	       bp->last_status_idx);
+		return 0;
+	}
+#endif
+
+	if ((bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) && !retrieve)
+		return 1;
+
+	if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) {
+
+		hw_cons = bp->hw_rx_cons = bp->status_blk->status_rx_quick_consumer_index0;
+		if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
+			hw_cons++;
+		}
+		sw_cons = bp->rx_cons;
+		sw_prod = bp->rx_prod;
+
+		rmb();
+		if (sw_cons != hw_cons) {
+
+			sw_ring_cons = RX_RING_IDX(sw_cons);
+			sw_ring_prod = RX_RING_IDX(sw_prod);
+
+			data = bus_to_virt(bp->rx_desc_ring[sw_ring_cons].rx_bd_haddr_lo);
+
+			rx_hdr = (struct l2_fhdr *)data;
+			len = rx_hdr->l2_fhdr_pkt_len - 4;
+			if ((len > (ETH_MAX_MTU + ETH_HLEN)) ||
+				((status = rx_hdr->l2_fhdr_status) &
+				(L2_FHDR_ERRORS_BAD_CRC |
+				L2_FHDR_ERRORS_PHY_DECODE |
+				L2_FHDR_ERRORS_ALIGNMENT |
+				L2_FHDR_ERRORS_TOO_SHORT |
+				L2_FHDR_ERRORS_GIANT_FRAME))) {
+				result = 0;
+			}
+			else
+			{
+				nic->packetlen = len;
+				memcpy(nic->packet, data + bp->rx_offset, len);
+				result = 1;
+			}
+
+			/* Reuse the buffer */
+			bp->rx_prod_bseq += bp->rx_buf_use_size;
+			if (sw_cons != sw_prod) {
+				cons_bd = &bp->rx_desc_ring[sw_ring_cons];
+				prod_bd = &bp->rx_desc_ring[sw_ring_prod];
+				prod_bd->rx_bd_haddr_hi = 0; /* Etherboot runs under 4GB */
+				prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
+			}
+
+			sw_cons = NEXT_RX_BD(sw_cons);
+			sw_prod = NEXT_RX_BD(sw_prod);
+
+		}
+
+		bp->rx_cons = sw_cons;
+		bp->rx_prod = sw_prod;
+
+		REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, bp->rx_prod);
+
+		REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+
+		wmb();
+
+	}
+
+	bnx2_poll_link(bp);
+
+#if 0
+	bp->last_status_idx = bp->status_blk->status_idx;
+	rmb();
+
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
+	       bp->last_status_idx);
+
+	REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+#endif
+
+	return result;
+}
+
+static void
+bnx2_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+	switch ( action ) {
+		case DISABLE: break;
+		case ENABLE: break;
+		case FORCE: break;
+	}
+}
+
+static struct nic_operations bnx2_operations = {
+	.connect	= dummy_connect,
+	.poll		= bnx2_poll,
+	.transmit	= bnx2_transmit,
+	.irq		= bnx2_irq,
+};
+
+static int
+bnx2_probe(struct nic *nic, struct pci_device *pdev)
+{
+	struct bnx2 *bp = &bnx2;
+	int i, rc;
+
+	if (pdev == 0)
+		return 0;
+
+	memset(bp, 0, sizeof(*bp));
+
+	rc = bnx2_init_board(pdev, nic);
+	if (rc < 0) {
+		return 0;
+	}
+
+	/*
+	nic->disable = bnx2_disable;
+	nic->transmit = bnx2_transmit;
+	nic->poll = bnx2_poll;
+	nic->irq = bnx2_irq;
+	*/
+	
+	nic->nic_op	= &bnx2_operations;
+
+	memcpy(nic->node_addr, bp->mac_addr, ETH_ALEN);
+	printf("Ethernet addr: %s\n", eth_ntoa( nic->node_addr ) );
+	printf("Broadcom NetXtreme II (%c%d) PCI%s %s %dMHz\n",
+	        (int) ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
+	        (int) ((CHIP_ID(bp) & 0x0ff0) >> 4),
+		((bp->flags & PCIX_FLAG) ? "-X" : ""),
+		((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
+		bp->bus_speed_mhz);
+
+	bnx2_set_power_state_0(bp);
+	bnx2_disable_int(bp);
+
+	bnx2_alloc_mem(bp);
+
+	rc = bnx2_init_nic(bp);
+	if (rc) {
+		return 0;
+	}
+
+	bnx2_poll_link(bp);
+	for(i = 0; !bp->link_up && (i < VALID_LINK_TIMEOUT*100); i++) {
+		mdelay(1);
+		bnx2_poll_link(bp);
+	}
+#if 1
+	if (!bp->link_up){
+		printf("Valid link not established\n");
+		goto err_out_disable;
+	}
+#endif
+	
+	return 1;
+
+err_out_disable:
+	bnx2_disable(nic);
+	return 0;
+}
+
+static struct pci_device_id bnx2_nics[] = {
+	PCI_ROM(0x14e4, 0x164a, "bnx2-5706",        "Broadcom NetXtreme II BCM5706", 0),
+	PCI_ROM(0x14e4, 0x164c, "bnx2-5708",        "Broadcom NetXtreme II BCM5708", 0),
+	PCI_ROM(0x14e4, 0x16aa, "bnx2-5706S",       "Broadcom NetXtreme II BCM5706S", 0),
+	PCI_ROM(0x14e4, 0x16ac, "bnx2-5708S",       "Broadcom NetXtreme II BCM5708S", 0),
+};
+
+PCI_DRIVER ( bnx2_driver, bnx2_nics, PCI_NO_CLASS );
+
+DRIVER ( "BNX2", nic_driver, pci_driver, bnx2_driver, bnx2_probe, bnx2_disable );
+
+/*
+static struct pci_driver bnx2_driver __pci_driver = {
+	.type     = NIC_DRIVER,
+	.name     = "BNX2",              
+	.probe    = bnx2_probe,
+	.ids      = bnx2_nics,                  
+	.id_count = sizeof(bnx2_nics)/sizeof(bnx2_nics[0]), 
+	.class    = 0,    
+};
+*/
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.h
new file mode 100644
index 0000000..9267868
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2.h
@@ -0,0 +1,4598 @@
+/* bnx2.h: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Michael Chan  (mchan at broadcom.com)
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#ifndef BNX2_H
+#define BNX2_H
+
+#define L1_CACHE_BYTES 128 /* Rough approximaition of the cache line size */
+#define L1_CACHE_ALIGN(X) (((X) + L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES -1))
+
+typedef unsigned long dma_addr_t;
+
+/* From pci.h */
+typedef int pci_power_t;
+
+#define PCI_D0          ((pci_power_t) 0)
+#define PCI_D1          ((pci_power_t) 1)
+#define PCI_D2          ((pci_power_t) 2)
+#define PCI_D3hot       ((pci_power_t) 3)
+#define PCI_D3cold      ((pci_power_t) 4)
+#define PCI_UNKNOWN     ((pci_power_t) 5)
+#define PCI_POWER_ERROR ((pci_power_t) -1)
+
+/* From pci_regs.h */
+
+#define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_X_CMD		2	/* Modes & Features */
+#define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
+
+/* From mii.h */
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
+#define ADVERTISED_100baseT_Half	(1 << 2)
+#define ADVERTISED_100baseT_Full	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+#define ADVERTISED_Autoneg		(1 << 6)
+#define ADVERTISED_TP			(1 << 7)
+#define ADVERTISED_AUI			(1 << 8)
+#define ADVERTISED_MII			(1 << 9)
+#define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_BNC			(1 << 11)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+#define DUPLEX_INVALID          0x02
+
+/* Which connector port. */
+#define PORT_TP			0x00
+#define PORT_AUI		0x01
+#define PORT_MII		0x02
+#define PORT_FIBRE		0x03
+#define PORT_BNC		0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL		0x00
+#define XCVR_EXTERNAL		0x01
+#define XCVR_DUMMY1		0x02
+#define XCVR_DUMMY2		0x03
+#define XCVR_DUMMY3		0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY		(1 << 0)
+#define WAKE_UCAST		(1 << 1)
+#define WAKE_MCAST		(1 << 2)
+#define WAKE_BCAST		(1 << 3)
+#define WAKE_ARP		(1 << 4)
+#define WAKE_MAGIC		(1 << 5)
+#define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* The following are all involved in forcing a particular link
+ *  * mode for the device for setting things.  When getting the
+ *   * devices settings, these indicate the current mode and whether
+ *    * it was foced up into this mode or autonegotiated.
+ *     */
+
+/* The forced speed, 10Mb, 100Mb, gigabit. */
+#define SPEED_10                10
+#define SPEED_100               100
+#define SPEED_1000              1000
+#define SPEED_2500		2500
+#define SPEED_INVALID           0 /* XXX was 3 */
+
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF             0x00
+#define DUPLEX_FULL             0x01
+#define DUPLEX_INVALID          0x02
+
+/* Which connector port. */
+#define PORT_TP                 0x00
+#define PORT_AUI                0x01
+#define PORT_MII                0x02
+#define PORT_FIBRE              0x03
+#define PORT_BNC                0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL           0x00
+#define XCVR_EXTERNAL           0x01
+#define XCVR_DUMMY1             0x02
+#define XCVR_DUMMY2             0x03
+#define XCVR_DUMMY3             0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ *  * the forced link modes above are completely ignored.
+ *   */
+#define AUTONEG_DISABLE         0x00
+#define AUTONEG_ENABLE          0x01
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY                (1 << 0)
+#define WAKE_UCAST              (1 << 1)
+#define WAKE_MCAST              (1 << 2)
+#define WAKE_BCAST              (1 << 3)
+#define WAKE_ARP                (1 << 4)
+#define WAKE_MAGIC              (1 << 5)
+#define WAKE_MAGICSECURE        (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* Hardware data structures and register definitions automatically
+ * generated from RTL code. Do not modify.
+ */
+
+/*
+ *  tx_bd definition
+ */
+struct tx_bd {
+	u32 tx_bd_haddr_hi;
+	u32 tx_bd_haddr_lo;                                   
+	u32 tx_bd_mss_nbytes;                                     
+	u32 tx_bd_vlan_tag_flags;                                      
+		#define TX_BD_FLAGS_CONN_FAULT		(1<<0)
+		#define TX_BD_FLAGS_TCP_UDP_CKSUM	(1<<1)
+		#define TX_BD_FLAGS_IP_CKSUM		(1<<2)
+		#define TX_BD_FLAGS_VLAN_TAG		(1<<3)
+		#define TX_BD_FLAGS_COAL_NOW		(1<<4)
+		#define TX_BD_FLAGS_DONT_GEN_CRC	(1<<5)
+		#define TX_BD_FLAGS_END			(1<<6)
+		#define TX_BD_FLAGS_START		(1<<7)
+		#define TX_BD_FLAGS_SW_OPTION_WORD	(0x1f<<8)
+		#define TX_BD_FLAGS_SW_FLAGS		(1<<13)
+		#define TX_BD_FLAGS_SW_SNAP		(1<<14)
+		#define TX_BD_FLAGS_SW_LSO		(1<<15)
+
+};
+
+
+/*
+ *  rx_bd definition
+ */
+struct rx_bd {
+	u32 rx_bd_haddr_hi;
+	u32 rx_bd_haddr_lo;
+	u32 rx_bd_len;
+	u32 rx_bd_flags;
+		#define RX_BD_FLAGS_NOPUSH		(1<<0)
+		#define RX_BD_FLAGS_DUMMY		(1<<1)
+		#define RX_BD_FLAGS_END			(1<<2)
+		#define RX_BD_FLAGS_START		(1<<3)
+
+};
+
+
+/*
+ *  status_block definition
+ */
+struct status_block {
+	u32 status_attn_bits;
+		#define STATUS_ATTN_BITS_LINK_STATE		(1L<<0)
+		#define STATUS_ATTN_BITS_TX_SCHEDULER_ABORT	(1L<<1)
+		#define STATUS_ATTN_BITS_TX_BD_READ_ABORT	(1L<<2)
+		#define STATUS_ATTN_BITS_TX_BD_CACHE_ABORT	(1L<<3)
+		#define STATUS_ATTN_BITS_TX_PROCESSOR_ABORT	(1L<<4)
+		#define STATUS_ATTN_BITS_TX_DMA_ABORT		(1L<<5)
+		#define STATUS_ATTN_BITS_TX_PATCHUP_ABORT	(1L<<6)
+		#define STATUS_ATTN_BITS_TX_ASSEMBLER_ABORT	(1L<<7)
+		#define STATUS_ATTN_BITS_RX_PARSER_MAC_ABORT	(1L<<8)
+		#define STATUS_ATTN_BITS_RX_PARSER_CATCHUP_ABORT	(1L<<9)
+		#define STATUS_ATTN_BITS_RX_MBUF_ABORT		(1L<<10)
+		#define STATUS_ATTN_BITS_RX_LOOKUP_ABORT	(1L<<11)
+		#define STATUS_ATTN_BITS_RX_PROCESSOR_ABORT	(1L<<12)
+		#define STATUS_ATTN_BITS_RX_V2P_ABORT		(1L<<13)
+		#define STATUS_ATTN_BITS_RX_BD_CACHE_ABORT	(1L<<14)
+		#define STATUS_ATTN_BITS_RX_DMA_ABORT		(1L<<15)
+		#define STATUS_ATTN_BITS_COMPLETION_ABORT	(1L<<16)
+		#define STATUS_ATTN_BITS_HOST_COALESCE_ABORT	(1L<<17)
+		#define STATUS_ATTN_BITS_MAILBOX_QUEUE_ABORT	(1L<<18)
+		#define STATUS_ATTN_BITS_CONTEXT_ABORT		(1L<<19)
+		#define STATUS_ATTN_BITS_CMD_SCHEDULER_ABORT	(1L<<20)
+		#define STATUS_ATTN_BITS_CMD_PROCESSOR_ABORT	(1L<<21)
+		#define STATUS_ATTN_BITS_MGMT_PROCESSOR_ABORT	(1L<<22)
+		#define STATUS_ATTN_BITS_MAC_ABORT		(1L<<23)
+		#define STATUS_ATTN_BITS_TIMER_ABORT		(1L<<24)
+		#define STATUS_ATTN_BITS_DMAE_ABORT		(1L<<25)
+		#define STATUS_ATTN_BITS_FLSH_ABORT		(1L<<26)
+		#define STATUS_ATTN_BITS_GRC_ABORT		(1L<<27)
+		#define STATUS_ATTN_BITS_PARITY_ERROR		(1L<<31)
+
+	u32 status_attn_bits_ack;
+#if __BYTE_ORDER == __BIG_ENDIAN
+	u16 status_tx_quick_consumer_index0;
+	u16 status_tx_quick_consumer_index1;
+	u16 status_tx_quick_consumer_index2;
+	u16 status_tx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index0;
+	u16 status_rx_quick_consumer_index1;
+	u16 status_rx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index4;
+	u16 status_rx_quick_consumer_index5;
+	u16 status_rx_quick_consumer_index6;
+	u16 status_rx_quick_consumer_index7;
+	u16 status_rx_quick_consumer_index8;
+	u16 status_rx_quick_consumer_index9;
+	u16 status_rx_quick_consumer_index10;
+	u16 status_rx_quick_consumer_index11;
+	u16 status_rx_quick_consumer_index12;
+	u16 status_rx_quick_consumer_index13;
+	u16 status_rx_quick_consumer_index14;
+	u16 status_rx_quick_consumer_index15;
+	u16 status_completion_producer_index;
+	u16 status_cmd_consumer_index;
+	u16 status_idx;
+	u16 status_unused;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+	u16 status_tx_quick_consumer_index1;
+	u16 status_tx_quick_consumer_index0;
+	u16 status_tx_quick_consumer_index3;
+	u16 status_tx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index1;
+	u16 status_rx_quick_consumer_index0;
+	u16 status_rx_quick_consumer_index3;
+	u16 status_rx_quick_consumer_index2;
+	u16 status_rx_quick_consumer_index5;
+	u16 status_rx_quick_consumer_index4;
+	u16 status_rx_quick_consumer_index7;
+	u16 status_rx_quick_consumer_index6;
+	u16 status_rx_quick_consumer_index9;
+	u16 status_rx_quick_consumer_index8;
+	u16 status_rx_quick_consumer_index11;
+	u16 status_rx_quick_consumer_index10;
+	u16 status_rx_quick_consumer_index13;
+	u16 status_rx_quick_consumer_index12;
+	u16 status_rx_quick_consumer_index15;
+	u16 status_rx_quick_consumer_index14;
+	u16 status_cmd_consumer_index;
+	u16 status_completion_producer_index;
+	u16 status_unused;
+	u16 status_idx;
+#endif
+};
+
+
+/*
+ *  statistics_block definition
+ */
+struct statistics_block {
+	u32 stat_IfHCInOctets_hi;
+	u32 stat_IfHCInOctets_lo;
+	u32 stat_IfHCInBadOctets_hi;
+	u32 stat_IfHCInBadOctets_lo;
+	u32 stat_IfHCOutOctets_hi;
+	u32 stat_IfHCOutOctets_lo;
+	u32 stat_IfHCOutBadOctets_hi;
+	u32 stat_IfHCOutBadOctets_lo;
+	u32 stat_IfHCInUcastPkts_hi;
+	u32 stat_IfHCInUcastPkts_lo;
+	u32 stat_IfHCInMulticastPkts_hi;
+	u32 stat_IfHCInMulticastPkts_lo;
+	u32 stat_IfHCInBroadcastPkts_hi;
+	u32 stat_IfHCInBroadcastPkts_lo;
+	u32 stat_IfHCOutUcastPkts_hi;
+	u32 stat_IfHCOutUcastPkts_lo;
+	u32 stat_IfHCOutMulticastPkts_hi;
+	u32 stat_IfHCOutMulticastPkts_lo;
+	u32 stat_IfHCOutBroadcastPkts_hi;
+	u32 stat_IfHCOutBroadcastPkts_lo;
+	u32 stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
+	u32 stat_Dot3StatsCarrierSenseErrors;
+	u32 stat_Dot3StatsFCSErrors;
+	u32 stat_Dot3StatsAlignmentErrors;
+	u32 stat_Dot3StatsSingleCollisionFrames;
+	u32 stat_Dot3StatsMultipleCollisionFrames;
+	u32 stat_Dot3StatsDeferredTransmissions;
+	u32 stat_Dot3StatsExcessiveCollisions;
+	u32 stat_Dot3StatsLateCollisions;
+	u32 stat_EtherStatsCollisions;
+	u32 stat_EtherStatsFragments;
+	u32 stat_EtherStatsJabbers;
+	u32 stat_EtherStatsUndersizePkts;
+	u32 stat_EtherStatsOverrsizePkts;
+	u32 stat_EtherStatsPktsRx64Octets;
+	u32 stat_EtherStatsPktsRx65Octetsto127Octets;
+	u32 stat_EtherStatsPktsRx128Octetsto255Octets;
+	u32 stat_EtherStatsPktsRx256Octetsto511Octets;
+	u32 stat_EtherStatsPktsRx512Octetsto1023Octets;
+	u32 stat_EtherStatsPktsRx1024Octetsto1522Octets;
+	u32 stat_EtherStatsPktsRx1523Octetsto9022Octets;
+	u32 stat_EtherStatsPktsTx64Octets;
+	u32 stat_EtherStatsPktsTx65Octetsto127Octets;
+	u32 stat_EtherStatsPktsTx128Octetsto255Octets;
+	u32 stat_EtherStatsPktsTx256Octetsto511Octets;
+	u32 stat_EtherStatsPktsTx512Octetsto1023Octets;
+	u32 stat_EtherStatsPktsTx1024Octetsto1522Octets;
+	u32 stat_EtherStatsPktsTx1523Octetsto9022Octets;
+	u32 stat_XonPauseFramesReceived;
+	u32 stat_XoffPauseFramesReceived;
+	u32 stat_OutXonSent;
+	u32 stat_OutXoffSent;
+	u32 stat_FlowControlDone;
+	u32 stat_MacControlFramesReceived;
+	u32 stat_XoffStateEntered;
+	u32 stat_IfInFramesL2FilterDiscards;
+	u32 stat_IfInRuleCheckerDiscards;
+	u32 stat_IfInFTQDiscards;
+	u32 stat_IfInMBUFDiscards;
+	u32 stat_IfInRuleCheckerP4Hit;
+	u32 stat_CatchupInRuleCheckerDiscards;
+	u32 stat_CatchupInFTQDiscards;
+	u32 stat_CatchupInMBUFDiscards;
+	u32 stat_CatchupInRuleCheckerP4Hit;
+	u32 stat_GenStat00;
+	u32 stat_GenStat01;
+	u32 stat_GenStat02;
+	u32 stat_GenStat03;
+	u32 stat_GenStat04;
+	u32 stat_GenStat05;
+	u32 stat_GenStat06;
+	u32 stat_GenStat07;
+	u32 stat_GenStat08;
+	u32 stat_GenStat09;
+	u32 stat_GenStat10;
+	u32 stat_GenStat11;
+	u32 stat_GenStat12;
+	u32 stat_GenStat13;
+	u32 stat_GenStat14;
+	u32 stat_GenStat15;
+};
+
+
+/*
+ *  l2_fhdr definition
+ */
+struct l2_fhdr {
+	u32 l2_fhdr_status;
+		#define L2_FHDR_STATUS_RULE_CLASS	(0x7<<0)
+		#define L2_FHDR_STATUS_RULE_P2		(1<<3)
+		#define L2_FHDR_STATUS_RULE_P3		(1<<4)
+		#define L2_FHDR_STATUS_RULE_P4		(1<<5)
+		#define L2_FHDR_STATUS_L2_VLAN_TAG	(1<<6)
+		#define L2_FHDR_STATUS_L2_LLC_SNAP	(1<<7)
+		#define L2_FHDR_STATUS_RSS_HASH		(1<<8)
+		#define L2_FHDR_STATUS_IP_DATAGRAM	(1<<13)
+		#define L2_FHDR_STATUS_TCP_SEGMENT	(1<<14)
+		#define L2_FHDR_STATUS_UDP_DATAGRAM	(1<<15)
+
+		#define L2_FHDR_ERRORS_BAD_CRC		(1<<17)
+		#define L2_FHDR_ERRORS_PHY_DECODE	(1<<18)
+		#define L2_FHDR_ERRORS_ALIGNMENT	(1<<19)
+		#define L2_FHDR_ERRORS_TOO_SHORT	(1<<20)
+		#define L2_FHDR_ERRORS_GIANT_FRAME	(1<<21)
+		#define L2_FHDR_ERRORS_TCP_XSUM		(1<<28)
+		#define L2_FHDR_ERRORS_UDP_XSUM		(1<<31)
+
+	u32 l2_fhdr_hash;
+#if __BYTE_ORDER == __BIG_ENDIAN
+	u16 l2_fhdr_pkt_len;
+	u16 l2_fhdr_vlan_tag;
+	u16 l2_fhdr_ip_xsum;
+	u16 l2_fhdr_tcp_udp_xsum;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+	u16 l2_fhdr_vlan_tag;
+	u16 l2_fhdr_pkt_len;
+	u16 l2_fhdr_tcp_udp_xsum;
+	u16 l2_fhdr_ip_xsum;
+#endif
+};
+
+
+/*
+ *  l2_context definition
+ */
+#define BNX2_L2CTX_TYPE					0x00000000
+#define BNX2_L2CTX_TYPE_SIZE_L2				 ((0xc0/0x20)<<16)
+#define BNX2_L2CTX_TYPE_TYPE				 (0xf<<28)
+#define BNX2_L2CTX_TYPE_TYPE_EMPTY			 (0<<28)
+#define BNX2_L2CTX_TYPE_TYPE_L2				 (1<<28)
+
+#define BNX2_L2CTX_TX_HOST_BIDX				0x00000088
+#define BNX2_L2CTX_EST_NBD				0x00000088
+#define BNX2_L2CTX_CMD_TYPE				0x00000088
+#define BNX2_L2CTX_CMD_TYPE_TYPE			 (0xf<<24)
+#define BNX2_L2CTX_CMD_TYPE_TYPE_L2			 (0<<24)
+#define BNX2_L2CTX_CMD_TYPE_TYPE_TCP			 (1<<24)
+
+#define BNX2_L2CTX_TX_HOST_BSEQ				0x00000090
+#define BNX2_L2CTX_TSCH_BSEQ				0x00000094
+#define BNX2_L2CTX_TBDR_BSEQ				0x00000098
+#define BNX2_L2CTX_TBDR_BOFF				0x0000009c
+#define BNX2_L2CTX_TBDR_BIDX				0x0000009c
+#define BNX2_L2CTX_TBDR_BHADDR_HI			0x000000a0
+#define BNX2_L2CTX_TBDR_BHADDR_LO			0x000000a4
+#define BNX2_L2CTX_TXP_BOFF				0x000000a8
+#define BNX2_L2CTX_TXP_BIDX				0x000000a8
+#define BNX2_L2CTX_TXP_BSEQ				0x000000ac
+
+
+/*
+ *  l2_bd_chain_context definition
+ */
+#define BNX2_L2CTX_BD_PRE_READ				0x00000000
+#define BNX2_L2CTX_CTX_SIZE				0x00000000
+#define BNX2_L2CTX_CTX_TYPE				0x00000000
+#define BNX2_L2CTX_CTX_TYPE_SIZE_L2			 ((0x20/20)<<16)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE		 (0xf<<28)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_UNDEFINED	 (0<<28)
+#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE	 (1<<28)
+
+#define BNX2_L2CTX_HOST_BDIDX				0x00000004
+#define BNX2_L2CTX_HOST_BSEQ				0x00000008
+#define BNX2_L2CTX_NX_BSEQ				0x0000000c
+#define BNX2_L2CTX_NX_BDHADDR_HI			0x00000010
+#define BNX2_L2CTX_NX_BDHADDR_LO			0x00000014
+#define BNX2_L2CTX_NX_BDIDX				0x00000018
+
+
+/*
+ *  pci_config_l definition
+ *  offset: 0000
+ */
+#define BNX2_PCICFG_MISC_CONFIG				0x00000068
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_BYTE_SWAP	 (1L<<2)
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP	 (1L<<3)
+#define BNX2_PCICFG_MISC_CONFIG_CLOCK_CTL_ENA		 (1L<<5)
+#define BNX2_PCICFG_MISC_CONFIG_TARGET_GRC_WORD_SWAP	 (1L<<6)
+#define BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA		 (1L<<7)
+#define BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ		 (1L<<8)
+#define BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY		 (1L<<9)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_METAL_REV		 (0xffL<<16)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_BASE_REV		 (0xfL<<24)
+#define BNX2_PCICFG_MISC_CONFIG_ASIC_ID			 (0xfL<<28)
+
+#define BNX2_PCICFG_MISC_STATUS				0x0000006c
+#define BNX2_PCICFG_MISC_STATUS_INTA_VALUE		 (1L<<0)
+#define BNX2_PCICFG_MISC_STATUS_32BIT_DET		 (1L<<1)
+#define BNX2_PCICFG_MISC_STATUS_M66EN			 (1L<<2)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_DET		 (1L<<3)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED		 (0x3L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_66		 (0L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_100		 (1L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_133		 (2L<<4)
+#define BNX2_PCICFG_MISC_STATUS_PCIX_SPEED_PCI_MODE	 (3L<<4)
+
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS		0x00000070
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET	 (0xfL<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ	 (0L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ	 (1L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ	 (2L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ	 (3L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ	 (4L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ	 (5L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ	 (6L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ	 (7L<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW	 (0xfL<<0)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE	 (1L<<6)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT	 (1L<<7)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC	 (0x7L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_UNDEF	 (0L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12	 (1L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_6	 (2L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_62	 (4L<<8)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PLAY_DEAD	 (1L<<11)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED	 (0xfL<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_100	 (0L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_80	 (1L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_50	 (2L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_40	 (4L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_25	 (8L<<12)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_CORE_CLK_PLL_STOP	 (1L<<16)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_PLL_STOP	 (1L<<17)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_RESERVED_18	 (1L<<18)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_USE_SPD_DET	 (1L<<19)
+#define BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_RESERVED	 (0xfffL<<20)
+
+#define BNX2_PCICFG_REG_WINDOW_ADDRESS			0x00000078
+#define BNX2_PCICFG_REG_WINDOW				0x00000080
+#define BNX2_PCICFG_INT_ACK_CMD				0x00000084
+#define BNX2_PCICFG_INT_ACK_CMD_INDEX			 (0xffffL<<0)
+#define BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID		 (1L<<16)
+#define BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM	 (1L<<17)
+#define BNX2_PCICFG_INT_ACK_CMD_MASK_INT		 (1L<<18)
+
+#define BNX2_PCICFG_STATUS_BIT_SET_CMD			0x00000088
+#define BNX2_PCICFG_STATUS_BIT_CLEAR_CMD		0x0000008c
+#define BNX2_PCICFG_MAILBOX_QUEUE_ADDR			0x00000090
+#define BNX2_PCICFG_MAILBOX_QUEUE_DATA			0x00000094
+
+
+/*
+ *  pci_reg definition
+ *  offset: 0x400
+ */
+#define BNX2_PCI_GRC_WINDOW_ADDR			0x00000400
+#define BNX2_PCI_GRC_WINDOW_ADDR_PCI_GRC_WINDOW_ADDR_VALUE	 (0x3ffffL<<8)
+
+#define BNX2_PCI_CONFIG_1				0x00000404
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY			 (0x7L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_OFF		 (0L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_16		 (1L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_32		 (2L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_64		 (3L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_128		 (4L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_256		 (5L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_512		 (6L<<8)
+#define BNX2_PCI_CONFIG_1_READ_BOUNDARY_1024		 (7L<<8)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY		 (0x7L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_OFF		 (0L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_16		 (1L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_32		 (2L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_64		 (3L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_128		 (4L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_256		 (5L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_512		 (6L<<11)
+#define BNX2_PCI_CONFIG_1_WRITE_BOUNDARY_1024		 (7L<<11)
+
+#define BNX2_PCI_CONFIG_2				0x00000408
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE			 (0xfL<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_DISABLED		 (0L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_64K			 (1L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_128K		 (2L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_256K		 (3L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_512K		 (4L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_1M			 (5L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_2M			 (6L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_4M			 (7L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_8M			 (8L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_16M			 (9L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_32M			 (10L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_64M			 (11L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_128M		 (12L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_256M		 (13L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_512M		 (14L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_SIZE_1G			 (15L<<0)
+#define BNX2_PCI_CONFIG_2_BAR1_64ENA			 (1L<<4)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_RETRY			 (1L<<5)
+#define BNX2_PCI_CONFIG_2_CFG_CYCLE_RETRY		 (1L<<6)
+#define BNX2_PCI_CONFIG_2_FIRST_CFG_DONE		 (1L<<7)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE			 (0xffL<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_DISABLED		 (0L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_1K		 (1L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_2K		 (2L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_4K		 (3L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_8K		 (4L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_16K		 (5L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_32K		 (6L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_64K		 (7L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_128K		 (8L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_256K		 (9L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_512K		 (10L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_1M		 (11L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_2M		 (12L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_4M		 (13L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_8M		 (14L<<8)
+#define BNX2_PCI_CONFIG_2_EXP_ROM_SIZE_16M		 (15L<<8)
+#define BNX2_PCI_CONFIG_2_MAX_SPLIT_LIMIT		 (0x1fL<<16)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT		 (0x3L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_512		 (0L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_1K		 (1L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_2K		 (2L<<21)
+#define BNX2_PCI_CONFIG_2_MAX_READ_LIMIT_4K		 (3L<<21)
+#define BNX2_PCI_CONFIG_2_FORCE_32_BIT_MSTR		 (1L<<23)
+#define BNX2_PCI_CONFIG_2_FORCE_32_BIT_TGT		 (1L<<24)
+#define BNX2_PCI_CONFIG_2_KEEP_REQ_ASSERT		 (1L<<25)
+
+#define BNX2_PCI_CONFIG_3				0x0000040c
+#define BNX2_PCI_CONFIG_3_STICKY_BYTE			 (0xffL<<0)
+#define BNX2_PCI_CONFIG_3_FORCE_PME			 (1L<<24)
+#define BNX2_PCI_CONFIG_3_PME_STATUS			 (1L<<25)
+#define BNX2_PCI_CONFIG_3_PME_ENABLE			 (1L<<26)
+#define BNX2_PCI_CONFIG_3_PM_STATE			 (0x3L<<27)
+#define BNX2_PCI_CONFIG_3_VAUX_PRESET			 (1L<<30)
+#define BNX2_PCI_CONFIG_3_PCI_POWER			 (1L<<31)
+
+#define BNX2_PCI_PM_DATA_A				0x00000410
+#define BNX2_PCI_PM_DATA_A_PM_DATA_0_PRG		 (0xffL<<0)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_1_PRG		 (0xffL<<8)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_2_PRG		 (0xffL<<16)
+#define BNX2_PCI_PM_DATA_A_PM_DATA_3_PRG		 (0xffL<<24)
+
+#define BNX2_PCI_PM_DATA_B				0x00000414
+#define BNX2_PCI_PM_DATA_B_PM_DATA_4_PRG		 (0xffL<<0)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_5_PRG		 (0xffL<<8)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_6_PRG		 (0xffL<<16)
+#define BNX2_PCI_PM_DATA_B_PM_DATA_7_PRG		 (0xffL<<24)
+
+#define BNX2_PCI_SWAP_DIAG0				0x00000418
+#define BNX2_PCI_SWAP_DIAG1				0x0000041c
+#define BNX2_PCI_EXP_ROM_ADDR				0x00000420
+#define BNX2_PCI_EXP_ROM_ADDR_ADDRESS			 (0x3fffffL<<2)
+#define BNX2_PCI_EXP_ROM_ADDR_REQ			 (1L<<31)
+
+#define BNX2_PCI_EXP_ROM_DATA				0x00000424
+#define BNX2_PCI_VPD_INTF				0x00000428
+#define BNX2_PCI_VPD_INTF_INTF_REQ			 (1L<<0)
+
+#define BNX2_PCI_VPD_ADDR_FLAG				0x0000042c
+#define BNX2_PCI_VPD_ADDR_FLAG_ADDRESS			 (0x1fff<<2)
+#define BNX2_PCI_VPD_ADDR_FLAG_WR			 (1<<15)
+
+#define BNX2_PCI_VPD_DATA				0x00000430
+#define BNX2_PCI_ID_VAL1				0x00000434
+#define BNX2_PCI_ID_VAL1_DEVICE_ID			 (0xffffL<<0)
+#define BNX2_PCI_ID_VAL1_VENDOR_ID			 (0xffffL<<16)
+
+#define BNX2_PCI_ID_VAL2				0x00000438
+#define BNX2_PCI_ID_VAL2_SUBSYSTEM_VENDOR_ID		 (0xffffL<<0)
+#define BNX2_PCI_ID_VAL2_SUBSYSTEM_ID			 (0xffffL<<16)
+
+#define BNX2_PCI_ID_VAL3				0x0000043c
+#define BNX2_PCI_ID_VAL3_CLASS_CODE			 (0xffffffL<<0)
+#define BNX2_PCI_ID_VAL3_REVISION_ID			 (0xffL<<24)
+
+#define BNX2_PCI_ID_VAL4				0x00000440
+#define BNX2_PCI_ID_VAL4_CAP_ENA			 (0xfL<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_0			 (0L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_1			 (1L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_2			 (2L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_3			 (3L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_4			 (4L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_5			 (5L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_6			 (6L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_7			 (7L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_8			 (8L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_9			 (9L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_10			 (10L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_11			 (11L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_12			 (12L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_13			 (13L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_14			 (14L<<0)
+#define BNX2_PCI_ID_VAL4_CAP_ENA_15			 (15L<<0)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG			 (0x3L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_0			 (0L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_1			 (1L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_2			 (2L<<6)
+#define BNX2_PCI_ID_VAL4_PM_SCALE_PRG_3			 (3L<<6)
+#define BNX2_PCI_ID_VAL4_MSI_LIMIT			 (0x7L<<9)
+#define BNX2_PCI_ID_VAL4_MSI_ADVERTIZE			 (0x7L<<12)
+#define BNX2_PCI_ID_VAL4_MSI_ENABLE			 (1L<<15)
+#define BNX2_PCI_ID_VAL4_MAX_64_ADVERTIZE		 (1L<<16)
+#define BNX2_PCI_ID_VAL4_MAX_133_ADVERTIZE		 (1L<<17)
+#define BNX2_PCI_ID_VAL4_MAX_MEM_READ_SIZE		 (0x3L<<21)
+#define BNX2_PCI_ID_VAL4_MAX_SPLIT_SIZE			 (0x7L<<23)
+#define BNX2_PCI_ID_VAL4_MAX_CUMULATIVE_SIZE		 (0x7L<<26)
+
+#define BNX2_PCI_ID_VAL5				0x00000444
+#define BNX2_PCI_ID_VAL5_D1_SUPPORT			 (1L<<0)
+#define BNX2_PCI_ID_VAL5_D2_SUPPORT			 (1L<<1)
+#define BNX2_PCI_ID_VAL5_PME_IN_D0			 (1L<<2)
+#define BNX2_PCI_ID_VAL5_PME_IN_D1			 (1L<<3)
+#define BNX2_PCI_ID_VAL5_PME_IN_D2			 (1L<<4)
+#define BNX2_PCI_ID_VAL5_PME_IN_D3_HOT			 (1L<<5)
+
+#define BNX2_PCI_PCIX_EXTENDED_STATUS			0x00000448
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_NO_SNOOP		 (1L<<8)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_LONG_BURST	 (1L<<9)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_SPLIT_COMP_MSG_CLASS	 (0xfL<<16)
+#define BNX2_PCI_PCIX_EXTENDED_STATUS_SPLIT_COMP_MSG_IDX	 (0xffL<<24)
+
+#define BNX2_PCI_ID_VAL6				0x0000044c
+#define BNX2_PCI_ID_VAL6_MAX_LAT			 (0xffL<<0)
+#define BNX2_PCI_ID_VAL6_MIN_GNT			 (0xffL<<8)
+#define BNX2_PCI_ID_VAL6_BIST				 (0xffL<<16)
+
+#define BNX2_PCI_MSI_DATA				0x00000450
+#define BNX2_PCI_MSI_DATA_PCI_MSI_DATA			 (0xffffL<<0)
+
+#define BNX2_PCI_MSI_ADDR_H				0x00000454
+#define BNX2_PCI_MSI_ADDR_L				0x00000458
+
+
+/*
+ *  misc_reg definition
+ *  offset: 0x800
+ */
+#define BNX2_MISC_COMMAND				0x00000800
+#define BNX2_MISC_COMMAND_ENABLE_ALL			 (1L<<0)
+#define BNX2_MISC_COMMAND_DISABLE_ALL			 (1L<<1)
+#define BNX2_MISC_COMMAND_CORE_RESET			 (1L<<4)
+#define BNX2_MISC_COMMAND_HARD_RESET			 (1L<<5)
+#define BNX2_MISC_COMMAND_PAR_ERROR			 (1L<<8)
+#define BNX2_MISC_COMMAND_PAR_ERR_RAM			 (0x7fL<<16)
+
+#define BNX2_MISC_CFG					0x00000804
+#define BNX2_MISC_CFG_PCI_GRC_TMOUT			 (1L<<0)
+#define BNX2_MISC_CFG_NVM_WR_EN				 (0x3L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_PROTECT			 (0L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_PCI			 (1L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_ALLOW			 (2L<<1)
+#define BNX2_MISC_CFG_NVM_WR_EN_ALLOW2			 (3L<<1)
+#define BNX2_MISC_CFG_BIST_EN				 (1L<<3)
+#define BNX2_MISC_CFG_CK25_OUT_ALT_SRC			 (1L<<4)
+#define BNX2_MISC_CFG_BYPASS_BSCAN			 (1L<<5)
+#define BNX2_MISC_CFG_BYPASS_EJTAG			 (1L<<6)
+#define BNX2_MISC_CFG_CLK_CTL_OVERRIDE			 (1L<<7)
+#define BNX2_MISC_CFG_LEDMODE				 (0x3L<<8)
+#define BNX2_MISC_CFG_LEDMODE_MAC			 (0L<<8)
+#define BNX2_MISC_CFG_LEDMODE_GPHY1			 (1L<<8)
+#define BNX2_MISC_CFG_LEDMODE_GPHY2			 (2L<<8)
+
+#define BNX2_MISC_ID					0x00000808
+#define BNX2_MISC_ID_BOND_ID				 (0xfL<<0)
+#define BNX2_MISC_ID_CHIP_METAL				 (0xffL<<4)
+#define BNX2_MISC_ID_CHIP_REV				 (0xfL<<12)
+#define BNX2_MISC_ID_CHIP_NUM				 (0xffffL<<16)
+
+#define BNX2_MISC_ENABLE_STATUS_BITS			0x0000080c
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_DMA_ENABLE	 (1L<<4)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_STATUS_BITS_EMAC_ENABLE	 (1L<<9)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE	 (1L<<15)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_STATUS_BITS_RX_DMA_ENABLE	 (1L<<17)
+#define BNX2_MISC_ENABLE_STATUS_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_STATUS_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_STATUS_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_STATUS_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_STATUS_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_STATUS_BITS_TIMER_ENABLE	 (1L<<25)
+#define BNX2_MISC_ENABLE_STATUS_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_STATUS_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ENABLE_SET_BITS			0x00000810
+#define BNX2_MISC_ENABLE_SET_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_SET_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_SET_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_ENABLE_SET_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_SET_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_SET_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_SET_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_SET_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_SET_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_SET_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_ENABLE_SET_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_SET_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ENABLE_CLR_BITS			0x00000814
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_ENABLE_CLR_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_ENABLE_CLR_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_MBUF_ENABLE	 (1L<<12)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_ENABLE_CLR_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_ENABLE_CLR_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_ENABLE_CLR_BITS_CONTEXT_ENABLE	 (1L<<21)
+#define BNX2_MISC_ENABLE_CLR_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_ENABLE_CLR_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_ENABLE_CLR_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_ENABLE_CLR_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_ENABLE_CLR_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_CLOCK_CONTROL_BITS			0x00000818
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET	 (0xfL<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ	 (0L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ	 (1L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ	 (2L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ	 (3L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ	 (4L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ	 (5L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ	 (6L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ	 (7L<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW	 (0xfL<<0)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE	 (1L<<6)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT	 (1L<<7)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC	 (0x7L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_UNDEF	 (0L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12	 (1L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_6	 (2L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_62	 (4L<<8)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PLAY_DEAD		 (1L<<11)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED	 (0xfL<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_100	 (0L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_80	 (1L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_50	 (2L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_40	 (4L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_SPEED_25	 (8L<<12)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_CORE_CLK_PLL_STOP	 (1L<<16)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_PCI_PLL_STOP	 (1L<<17)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_RESERVED_18	 (1L<<18)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_USE_SPD_DET	 (1L<<19)
+#define BNX2_MISC_CLOCK_CONTROL_BITS_RESERVED		 (0xfffL<<20)
+
+#define BNX2_MISC_GPIO					0x0000081c
+#define BNX2_MISC_GPIO_VALUE				 (0xffL<<0)
+#define BNX2_MISC_GPIO_SET				 (0xffL<<8)
+#define BNX2_MISC_GPIO_CLR				 (0xffL<<16)
+#define BNX2_MISC_GPIO_FLOAT				 (0xffL<<24)
+
+#define BNX2_MISC_GPIO_INT				0x00000820
+#define BNX2_MISC_GPIO_INT_INT_STATE			 (0xfL<<0)
+#define BNX2_MISC_GPIO_INT_OLD_VALUE			 (0xfL<<8)
+#define BNX2_MISC_GPIO_INT_OLD_SET			 (0xfL<<16)
+#define BNX2_MISC_GPIO_INT_OLD_CLR			 (0xfL<<24)
+
+#define BNX2_MISC_CONFIG_LFSR				0x00000824
+#define BNX2_MISC_CONFIG_LFSR_DIV			 (0xffffL<<0)
+
+#define BNX2_MISC_LFSR_MASK_BITS			0x00000828
+#define BNX2_MISC_LFSR_MASK_BITS_TX_SCHEDULER_ENABLE	 (1L<<0)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_BD_READ_ENABLE	 (1L<<1)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_BD_CACHE_ENABLE	 (1L<<2)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PROCESSOR_ENABLE	 (1L<<3)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_DMA_ENABLE		 (1L<<4)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PATCHUP_ENABLE	 (1L<<5)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_PAYLOAD_Q_ENABLE	 (1L<<6)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_HEADER_Q_ENABLE	 (1L<<7)
+#define BNX2_MISC_LFSR_MASK_BITS_TX_ASSEMBLER_ENABLE	 (1L<<8)
+#define BNX2_MISC_LFSR_MASK_BITS_EMAC_ENABLE		 (1L<<9)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PARSER_MAC_ENABLE	 (1L<<10)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PARSER_CATCHUP_ENABLE	 (1L<<11)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_MBUF_ENABLE		 (1L<<12)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_LOOKUP_ENABLE	 (1L<<13)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_PROCESSOR_ENABLE	 (1L<<14)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_V2P_ENABLE		 (1L<<15)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_BD_CACHE_ENABLE	 (1L<<16)
+#define BNX2_MISC_LFSR_MASK_BITS_RX_DMA_ENABLE		 (1L<<17)
+#define BNX2_MISC_LFSR_MASK_BITS_COMPLETION_ENABLE	 (1L<<18)
+#define BNX2_MISC_LFSR_MASK_BITS_HOST_COALESCE_ENABLE	 (1L<<19)
+#define BNX2_MISC_LFSR_MASK_BITS_MAILBOX_QUEUE_ENABLE	 (1L<<20)
+#define BNX2_MISC_LFSR_MASK_BITS_CONTEXT_ENABLE		 (1L<<21)
+#define BNX2_MISC_LFSR_MASK_BITS_CMD_SCHEDULER_ENABLE	 (1L<<22)
+#define BNX2_MISC_LFSR_MASK_BITS_CMD_PROCESSOR_ENABLE	 (1L<<23)
+#define BNX2_MISC_LFSR_MASK_BITS_MGMT_PROCESSOR_ENABLE	 (1L<<24)
+#define BNX2_MISC_LFSR_MASK_BITS_TIMER_ENABLE		 (1L<<25)
+#define BNX2_MISC_LFSR_MASK_BITS_DMA_ENGINE_ENABLE	 (1L<<26)
+#define BNX2_MISC_LFSR_MASK_BITS_UMP_ENABLE		 (1L<<27)
+
+#define BNX2_MISC_ARB_REQ0				0x0000082c
+#define BNX2_MISC_ARB_REQ1				0x00000830
+#define BNX2_MISC_ARB_REQ2				0x00000834
+#define BNX2_MISC_ARB_REQ3				0x00000838
+#define BNX2_MISC_ARB_REQ4				0x0000083c
+#define BNX2_MISC_ARB_FREE0				0x00000840
+#define BNX2_MISC_ARB_FREE1				0x00000844
+#define BNX2_MISC_ARB_FREE2				0x00000848
+#define BNX2_MISC_ARB_FREE3				0x0000084c
+#define BNX2_MISC_ARB_FREE4				0x00000850
+#define BNX2_MISC_ARB_REQ_STATUS0			0x00000854
+#define BNX2_MISC_ARB_REQ_STATUS1			0x00000858
+#define BNX2_MISC_ARB_REQ_STATUS2			0x0000085c
+#define BNX2_MISC_ARB_REQ_STATUS3			0x00000860
+#define BNX2_MISC_ARB_REQ_STATUS4			0x00000864
+#define BNX2_MISC_ARB_GNT0				0x00000868
+#define BNX2_MISC_ARB_GNT0_0				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT0_1				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT0_2				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT0_3				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT0_4				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT0_5				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT0_6				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT0_7				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT1				0x0000086c
+#define BNX2_MISC_ARB_GNT1_8				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT1_9				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT1_10				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT1_11				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT1_12				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT1_13				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT1_14				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT1_15				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT2				0x00000870
+#define BNX2_MISC_ARB_GNT2_16				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT2_17				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT2_18				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT2_19				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT2_20				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT2_21				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT2_22				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT2_23				 (0x7L<<28)
+
+#define BNX2_MISC_ARB_GNT3				0x00000874
+#define BNX2_MISC_ARB_GNT3_24				 (0x7L<<0)
+#define BNX2_MISC_ARB_GNT3_25				 (0x7L<<4)
+#define BNX2_MISC_ARB_GNT3_26				 (0x7L<<8)
+#define BNX2_MISC_ARB_GNT3_27				 (0x7L<<12)
+#define BNX2_MISC_ARB_GNT3_28				 (0x7L<<16)
+#define BNX2_MISC_ARB_GNT3_29				 (0x7L<<20)
+#define BNX2_MISC_ARB_GNT3_30				 (0x7L<<24)
+#define BNX2_MISC_ARB_GNT3_31				 (0x7L<<28)
+
+#define BNX2_MISC_PRBS_CONTROL				0x00000878
+#define BNX2_MISC_PRBS_CONTROL_EN			 (1L<<0)
+#define BNX2_MISC_PRBS_CONTROL_RSTB			 (1L<<1)
+#define BNX2_MISC_PRBS_CONTROL_INV			 (1L<<2)
+#define BNX2_MISC_PRBS_CONTROL_ERR_CLR			 (1L<<3)
+#define BNX2_MISC_PRBS_CONTROL_ORDER			 (0x3L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_7TH		 (0L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_15TH		 (1L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_23RD		 (2L<<4)
+#define BNX2_MISC_PRBS_CONTROL_ORDER_31ST		 (3L<<4)
+
+#define BNX2_MISC_PRBS_STATUS				0x0000087c
+#define BNX2_MISC_PRBS_STATUS_LOCK			 (1L<<0)
+#define BNX2_MISC_PRBS_STATUS_STKY			 (1L<<1)
+#define BNX2_MISC_PRBS_STATUS_ERRORS			 (0x3fffL<<2)
+#define BNX2_MISC_PRBS_STATUS_STATE			 (0xfL<<16)
+
+#define BNX2_MISC_SM_ASF_CONTROL			0x00000880
+#define BNX2_MISC_SM_ASF_CONTROL_ASF_RST		 (1L<<0)
+#define BNX2_MISC_SM_ASF_CONTROL_TSC_EN			 (1L<<1)
+#define BNX2_MISC_SM_ASF_CONTROL_WG_TO			 (1L<<2)
+#define BNX2_MISC_SM_ASF_CONTROL_HB_TO			 (1L<<3)
+#define BNX2_MISC_SM_ASF_CONTROL_PA_TO			 (1L<<4)
+#define BNX2_MISC_SM_ASF_CONTROL_PL_TO			 (1L<<5)
+#define BNX2_MISC_SM_ASF_CONTROL_RT_TO			 (1L<<6)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EVENT		 (1L<<7)
+#define BNX2_MISC_SM_ASF_CONTROL_RES			 (0xfL<<8)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EN			 (1L<<12)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_BB_EN		 (1L<<13)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_NO_ADDR_FILT	 (1L<<14)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_AUTOREAD		 (1L<<15)
+#define BNX2_MISC_SM_ASF_CONTROL_NIC_SMB_ADDR1		 (0x3fL<<16)
+#define BNX2_MISC_SM_ASF_CONTROL_NIC_SMB_ADDR2		 (0x3fL<<24)
+#define BNX2_MISC_SM_ASF_CONTROL_EN_NIC_SMB_ADDR_0	 (1L<<30)
+#define BNX2_MISC_SM_ASF_CONTROL_SMB_EARLY_ATTN		 (1L<<31)
+
+#define BNX2_MISC_SMB_IN				0x00000884
+#define BNX2_MISC_SMB_IN_DAT_IN				 (0xffL<<0)
+#define BNX2_MISC_SMB_IN_RDY				 (1L<<8)
+#define BNX2_MISC_SMB_IN_DONE				 (1L<<9)
+#define BNX2_MISC_SMB_IN_FIRSTBYTE			 (1L<<10)
+#define BNX2_MISC_SMB_IN_STATUS				 (0x7L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_OK			 (0x0L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_PEC			 (0x1L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_OFLOW			 (0x2L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_STOP			 (0x3L<<11)
+#define BNX2_MISC_SMB_IN_STATUS_TIMEOUT			 (0x4L<<11)
+
+#define BNX2_MISC_SMB_OUT				0x00000888
+#define BNX2_MISC_SMB_OUT_DAT_OUT			 (0xffL<<0)
+#define BNX2_MISC_SMB_OUT_RDY				 (1L<<8)
+#define BNX2_MISC_SMB_OUT_START				 (1L<<9)
+#define BNX2_MISC_SMB_OUT_LAST				 (1L<<10)
+#define BNX2_MISC_SMB_OUT_ACC_TYPE			 (1L<<11)
+#define BNX2_MISC_SMB_OUT_ENB_PEC			 (1L<<12)
+#define BNX2_MISC_SMB_OUT_GET_RX_LEN			 (1L<<13)
+#define BNX2_MISC_SMB_OUT_SMB_READ_LEN			 (0x3fL<<14)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS		 (0xfL<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_OK		 (0L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_FIRST_NACK	 (1L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_SUB_NACK	 (9L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_UFLOW		 (2L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_STOP		 (3L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_TIMEOUT	 (4L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_FIRST_LOST	 (5L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_SUB_LOST	 (0xdL<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_STATUS_BADACK		 (0x6L<<20)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_SLAVEMODE		 (1L<<24)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_DAT_EN		 (1L<<25)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_DAT_IN		 (1L<<26)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_CLK_EN		 (1L<<27)
+#define BNX2_MISC_SMB_OUT_SMB_OUT_CLK_IN		 (1L<<28)
+
+#define BNX2_MISC_SMB_WATCHDOG				0x0000088c
+#define BNX2_MISC_SMB_WATCHDOG_WATCHDOG			 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_HEARTBEAT				0x00000890
+#define BNX2_MISC_SMB_HEARTBEAT_HEARTBEAT		 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_POLL_ASF				0x00000894
+#define BNX2_MISC_SMB_POLL_ASF_POLL_ASF			 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_POLL_LEGACY			0x00000898
+#define BNX2_MISC_SMB_POLL_LEGACY_POLL_LEGACY		 (0xffffL<<0)
+
+#define BNX2_MISC_SMB_RETRAN				0x0000089c
+#define BNX2_MISC_SMB_RETRAN_RETRAN			 (0xffL<<0)
+
+#define BNX2_MISC_SMB_TIMESTAMP				0x000008a0
+#define BNX2_MISC_SMB_TIMESTAMP_TIMESTAMP		 (0xffffffffL<<0)
+
+#define BNX2_MISC_PERR_ENA0				0x000008a4
+#define BNX2_MISC_PERR_ENA0_COM_MISC_CTXC		 (1L<<0)
+#define BNX2_MISC_PERR_ENA0_COM_MISC_REGF		 (1L<<1)
+#define BNX2_MISC_PERR_ENA0_COM_MISC_SCPAD		 (1L<<2)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_CTXC		 (1L<<3)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_REGF		 (1L<<4)
+#define BNX2_MISC_PERR_ENA0_CP_MISC_SCPAD		 (1L<<5)
+#define BNX2_MISC_PERR_ENA0_CS_MISC_TMEM		 (1L<<6)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM0		 (1L<<7)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM1		 (1L<<8)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM2		 (1L<<9)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM3		 (1L<<10)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM4		 (1L<<11)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_ACCM5		 (1L<<12)
+#define BNX2_MISC_PERR_ENA0_CTX_MISC_PGTBL		 (1L<<13)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR0		 (1L<<14)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR1		 (1L<<15)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR2		 (1L<<16)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR3		 (1L<<17)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DR4		 (1L<<18)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW0		 (1L<<19)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW1		 (1L<<20)
+#define BNX2_MISC_PERR_ENA0_DMAE_MISC_DW2		 (1L<<21)
+#define BNX2_MISC_PERR_ENA0_HC_MISC_DMA			 (1L<<22)
+#define BNX2_MISC_PERR_ENA0_MCP_MISC_REGF		 (1L<<23)
+#define BNX2_MISC_PERR_ENA0_MCP_MISC_SCPAD		 (1L<<24)
+#define BNX2_MISC_PERR_ENA0_MQ_MISC_CTX			 (1L<<25)
+#define BNX2_MISC_PERR_ENA0_RBDC_MISC			 (1L<<26)
+#define BNX2_MISC_PERR_ENA0_RBUF_MISC_MB		 (1L<<27)
+#define BNX2_MISC_PERR_ENA0_RBUF_MISC_PTR		 (1L<<28)
+#define BNX2_MISC_PERR_ENA0_RDE_MISC_RPC		 (1L<<29)
+#define BNX2_MISC_PERR_ENA0_RDE_MISC_RPM		 (1L<<30)
+#define BNX2_MISC_PERR_ENA0_RV2P_MISC_CB0REGS		 (1L<<31)
+
+#define BNX2_MISC_PERR_ENA1				0x000008a8
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_CB1REGS		 (1L<<0)
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_P1IRAM		 (1L<<1)
+#define BNX2_MISC_PERR_ENA1_RV2P_MISC_P2IRAM		 (1L<<2)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_CTXC		 (1L<<3)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_REGF		 (1L<<4)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_SCPAD		 (1L<<5)
+#define BNX2_MISC_PERR_ENA1_RXP_MISC_RBUFC		 (1L<<6)
+#define BNX2_MISC_PERR_ENA1_TBDC_MISC			 (1L<<7)
+#define BNX2_MISC_PERR_ENA1_TDMA_MISC			 (1L<<8)
+#define BNX2_MISC_PERR_ENA1_THBUF_MISC_MB0		 (1L<<9)
+#define BNX2_MISC_PERR_ENA1_THBUF_MISC_MB1		 (1L<<10)
+#define BNX2_MISC_PERR_ENA1_TPAT_MISC_REGF		 (1L<<11)
+#define BNX2_MISC_PERR_ENA1_TPAT_MISC_SCPAD		 (1L<<12)
+#define BNX2_MISC_PERR_ENA1_TPBUF_MISC_MB		 (1L<<13)
+#define BNX2_MISC_PERR_ENA1_TSCH_MISC_LR		 (1L<<14)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_CTXC		 (1L<<15)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_REGF		 (1L<<16)
+#define BNX2_MISC_PERR_ENA1_TXP_MISC_SCPAD		 (1L<<17)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_FIORX		 (1L<<18)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_FIOTX		 (1L<<19)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_RX			 (1L<<20)
+#define BNX2_MISC_PERR_ENA1_UMP_MISC_TX			 (1L<<21)
+#define BNX2_MISC_PERR_ENA1_RDMAQ_MISC			 (1L<<22)
+#define BNX2_MISC_PERR_ENA1_CSQ_MISC			 (1L<<23)
+#define BNX2_MISC_PERR_ENA1_CPQ_MISC			 (1L<<24)
+#define BNX2_MISC_PERR_ENA1_MCPQ_MISC			 (1L<<25)
+#define BNX2_MISC_PERR_ENA1_RV2PMQ_MISC			 (1L<<26)
+#define BNX2_MISC_PERR_ENA1_RV2PPQ_MISC			 (1L<<27)
+#define BNX2_MISC_PERR_ENA1_RV2PTQ_MISC			 (1L<<28)
+#define BNX2_MISC_PERR_ENA1_RXPQ_MISC			 (1L<<29)
+#define BNX2_MISC_PERR_ENA1_RXPCQ_MISC			 (1L<<30)
+#define BNX2_MISC_PERR_ENA1_RLUPQ_MISC			 (1L<<31)
+
+#define BNX2_MISC_PERR_ENA2				0x000008ac
+#define BNX2_MISC_PERR_ENA2_COMQ_MISC			 (1L<<0)
+#define BNX2_MISC_PERR_ENA2_COMXQ_MISC			 (1L<<1)
+#define BNX2_MISC_PERR_ENA2_COMTQ_MISC			 (1L<<2)
+#define BNX2_MISC_PERR_ENA2_TSCHQ_MISC			 (1L<<3)
+#define BNX2_MISC_PERR_ENA2_TBDRQ_MISC			 (1L<<4)
+#define BNX2_MISC_PERR_ENA2_TXPQ_MISC			 (1L<<5)
+#define BNX2_MISC_PERR_ENA2_TDMAQ_MISC			 (1L<<6)
+#define BNX2_MISC_PERR_ENA2_TPATQ_MISC			 (1L<<7)
+#define BNX2_MISC_PERR_ENA2_TASQ_MISC			 (1L<<8)
+
+#define BNX2_MISC_DEBUG_VECTOR_SEL			0x000008b0
+#define BNX2_MISC_DEBUG_VECTOR_SEL_0			 (0xfffL<<0)
+#define BNX2_MISC_DEBUG_VECTOR_SEL_1			 (0xfffL<<12)
+
+#define BNX2_MISC_VREG_CONTROL				0x000008b4
+#define BNX2_MISC_VREG_CONTROL_1_2			 (0xfL<<0)
+#define BNX2_MISC_VREG_CONTROL_2_5			 (0xfL<<4)
+
+#define BNX2_MISC_FINAL_CLK_CTL_VAL			0x000008b8
+#define BNX2_MISC_FINAL_CLK_CTL_VAL_MISC_FINAL_CLK_CTL_VAL	 (0x3ffffffL<<6)
+
+#define BNX2_MISC_UNUSED0				0x000008bc
+
+
+/*
+ *  nvm_reg definition
+ *  offset: 0x6400
+ */
+#define BNX2_NVM_COMMAND				0x00006400
+#define BNX2_NVM_COMMAND_RST				 (1L<<0)
+#define BNX2_NVM_COMMAND_DONE				 (1L<<3)
+#define BNX2_NVM_COMMAND_DOIT				 (1L<<4)
+#define BNX2_NVM_COMMAND_WR				 (1L<<5)
+#define BNX2_NVM_COMMAND_ERASE				 (1L<<6)
+#define BNX2_NVM_COMMAND_FIRST				 (1L<<7)
+#define BNX2_NVM_COMMAND_LAST				 (1L<<8)
+#define BNX2_NVM_COMMAND_WREN				 (1L<<16)
+#define BNX2_NVM_COMMAND_WRDI				 (1L<<17)
+#define BNX2_NVM_COMMAND_EWSR				 (1L<<18)
+#define BNX2_NVM_COMMAND_WRSR				 (1L<<19)
+
+#define BNX2_NVM_STATUS					0x00006404
+#define BNX2_NVM_STATUS_PI_FSM_STATE			 (0xfL<<0)
+#define BNX2_NVM_STATUS_EE_FSM_STATE			 (0xfL<<4)
+#define BNX2_NVM_STATUS_EQ_FSM_STATE			 (0xfL<<8)
+
+#define BNX2_NVM_WRITE					0x00006408
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE			 (0xffffffffL<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SO		 (16L<<0)
+#define BNX2_NVM_WRITE_NVM_WRITE_VALUE_SI		 (32L<<0)
+
+#define BNX2_NVM_ADDR					0x0000640c
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE			 (0xffffffL<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SO			 (16L<<0)
+#define BNX2_NVM_ADDR_NVM_ADDR_VALUE_SI			 (32L<<0)
+
+#define BNX2_NVM_READ					0x00006410
+#define BNX2_NVM_READ_NVM_READ_VALUE			 (0xffffffffL<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_BIT_BANG		 (0L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_EECLK		 (1L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_EEDATA		 (2L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SCLK		 (4L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_CS_B		 (8L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SO			 (16L<<0)
+#define BNX2_NVM_READ_NVM_READ_VALUE_SI			 (32L<<0)
+
+#define BNX2_NVM_CFG1					0x00006414
+#define BNX2_NVM_CFG1_FLASH_MODE			 (1L<<0)
+#define BNX2_NVM_CFG1_BUFFER_MODE			 (1L<<1)
+#define BNX2_NVM_CFG1_PASS_MODE				 (1L<<2)
+#define BNX2_NVM_CFG1_BITBANG_MODE			 (1L<<3)
+#define BNX2_NVM_CFG1_STATUS_BIT			 (0x7L<<4)
+#define BNX2_NVM_CFG1_STATUS_BIT_FLASH_RDY		 (0L<<4)
+#define BNX2_NVM_CFG1_STATUS_BIT_BUFFER_RDY		 (7L<<4)
+#define BNX2_NVM_CFG1_SPI_CLK_DIV			 (0xfL<<7)
+#define BNX2_NVM_CFG1_SEE_CLK_DIV			 (0x7ffL<<11)
+#define BNX2_NVM_CFG1_PROTECT_MODE			 (1L<<24)
+#define BNX2_NVM_CFG1_FLASH_SIZE			 (1L<<25)
+#define BNX2_NVM_CFG1_COMPAT_BYPASSS			 (1L<<31)
+
+#define BNX2_NVM_CFG2					0x00006418
+#define BNX2_NVM_CFG2_ERASE_CMD				 (0xffL<<0)
+#define BNX2_NVM_CFG2_DUMMY				 (0xffL<<8)
+#define BNX2_NVM_CFG2_STATUS_CMD			 (0xffL<<16)
+
+#define BNX2_NVM_CFG3					0x0000641c
+#define BNX2_NVM_CFG3_BUFFER_RD_CMD			 (0xffL<<0)
+#define BNX2_NVM_CFG3_WRITE_CMD				 (0xffL<<8)
+#define BNX2_NVM_CFG3_BUFFER_WRITE_CMD			 (0xffL<<16)
+#define BNX2_NVM_CFG3_READ_CMD				 (0xffL<<24)
+
+#define BNX2_NVM_SW_ARB					0x00006420
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET0			 (1L<<0)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET1			 (1L<<1)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET2			 (1L<<2)
+#define BNX2_NVM_SW_ARB_ARB_REQ_SET3			 (1L<<3)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR0			 (1L<<4)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR1			 (1L<<5)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR2			 (1L<<6)
+#define BNX2_NVM_SW_ARB_ARB_REQ_CLR3			 (1L<<7)
+#define BNX2_NVM_SW_ARB_ARB_ARB0			 (1L<<8)
+#define BNX2_NVM_SW_ARB_ARB_ARB1			 (1L<<9)
+#define BNX2_NVM_SW_ARB_ARB_ARB2			 (1L<<10)
+#define BNX2_NVM_SW_ARB_ARB_ARB3			 (1L<<11)
+#define BNX2_NVM_SW_ARB_REQ0				 (1L<<12)
+#define BNX2_NVM_SW_ARB_REQ1				 (1L<<13)
+#define BNX2_NVM_SW_ARB_REQ2				 (1L<<14)
+#define BNX2_NVM_SW_ARB_REQ3				 (1L<<15)
+
+#define BNX2_NVM_ACCESS_ENABLE				0x00006424
+#define BNX2_NVM_ACCESS_ENABLE_EN			 (1L<<0)
+#define BNX2_NVM_ACCESS_ENABLE_WR_EN			 (1L<<1)
+
+#define BNX2_NVM_WRITE1					0x00006428
+#define BNX2_NVM_WRITE1_WREN_CMD			 (0xffL<<0)
+#define BNX2_NVM_WRITE1_WRDI_CMD			 (0xffL<<8)
+#define BNX2_NVM_WRITE1_SR_DATA				 (0xffL<<16)
+
+
+
+/*
+ *  dma_reg definition
+ *  offset: 0xc00
+ */
+#define BNX2_DMA_COMMAND				0x00000c00
+#define BNX2_DMA_COMMAND_ENABLE				 (1L<<0)
+
+#define BNX2_DMA_STATUS					0x00000c04
+#define BNX2_DMA_STATUS_PAR_ERROR_STATE			 (1L<<0)
+#define BNX2_DMA_STATUS_READ_TRANSFERS_STAT		 (1L<<16)
+#define BNX2_DMA_STATUS_READ_DELAY_PCI_CLKS_STAT	 (1L<<17)
+#define BNX2_DMA_STATUS_BIG_READ_TRANSFERS_STAT		 (1L<<18)
+#define BNX2_DMA_STATUS_BIG_READ_DELAY_PCI_CLKS_STAT	 (1L<<19)
+#define BNX2_DMA_STATUS_BIG_READ_RETRY_AFTER_DATA_STAT	 (1L<<20)
+#define BNX2_DMA_STATUS_WRITE_TRANSFERS_STAT		 (1L<<21)
+#define BNX2_DMA_STATUS_WRITE_DELAY_PCI_CLKS_STAT	 (1L<<22)
+#define BNX2_DMA_STATUS_BIG_WRITE_TRANSFERS_STAT	 (1L<<23)
+#define BNX2_DMA_STATUS_BIG_WRITE_DELAY_PCI_CLKS_STAT	 (1L<<24)
+#define BNX2_DMA_STATUS_BIG_WRITE_RETRY_AFTER_DATA_STAT	 (1L<<25)
+
+#define BNX2_DMA_CONFIG					0x00000c08
+#define BNX2_DMA_CONFIG_DATA_BYTE_SWAP			 (1L<<0)
+#define BNX2_DMA_CONFIG_DATA_WORD_SWAP			 (1L<<1)
+#define BNX2_DMA_CONFIG_CNTL_BYTE_SWAP			 (1L<<4)
+#define BNX2_DMA_CONFIG_CNTL_WORD_SWAP			 (1L<<5)
+#define BNX2_DMA_CONFIG_ONE_DMA				 (1L<<6)
+#define BNX2_DMA_CONFIG_CNTL_TWO_DMA			 (1L<<7)
+#define BNX2_DMA_CONFIG_CNTL_FPGA_MODE			 (1L<<8)
+#define BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA		 (1L<<10)
+#define BNX2_DMA_CONFIG_CNTL_PCI_COMP_DLY		 (1L<<11)
+#define BNX2_DMA_CONFIG_NO_RCHANS_IN_USE		 (0xfL<<12)
+#define BNX2_DMA_CONFIG_NO_WCHANS_IN_USE		 (0xfL<<16)
+#define BNX2_DMA_CONFIG_PCI_CLK_CMP_BITS		 (0x7L<<20)
+#define BNX2_DMA_CONFIG_PCI_FAST_CLK_CMP		 (1L<<23)
+#define BNX2_DMA_CONFIG_BIG_SIZE			 (0xfL<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_NONE			 (0x0L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_64			 (0x1L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_128			 (0x2L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_256			 (0x4L<<24)
+#define BNX2_DMA_CONFIG_BIG_SIZE_512			 (0x8L<<24)
+
+#define BNX2_DMA_BLACKOUT				0x00000c0c
+#define BNX2_DMA_BLACKOUT_RD_RETRY_BLACKOUT		 (0xffL<<0)
+#define BNX2_DMA_BLACKOUT_2ND_RD_RETRY_BLACKOUT		 (0xffL<<8)
+#define BNX2_DMA_BLACKOUT_WR_RETRY_BLACKOUT		 (0xffL<<16)
+
+#define BNX2_DMA_RCHAN_STAT				0x00000c30
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_0			 (0x7L<<0)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_0			 (1L<<3)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_1			 (0x7L<<4)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_1			 (1L<<7)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_2			 (0x7L<<8)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_2			 (1L<<11)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_3			 (0x7L<<12)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_3			 (1L<<15)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_4			 (0x7L<<16)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_4			 (1L<<19)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_5			 (0x7L<<20)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_5			 (1L<<23)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_6			 (0x7L<<24)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_6			 (1L<<27)
+#define BNX2_DMA_RCHAN_STAT_COMP_CODE_7			 (0x7L<<28)
+#define BNX2_DMA_RCHAN_STAT_PAR_ERR_7			 (1L<<31)
+
+#define BNX2_DMA_WCHAN_STAT				0x00000c34
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_0			 (0x7L<<0)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_0			 (1L<<3)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_1			 (0x7L<<4)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_1			 (1L<<7)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_2			 (0x7L<<8)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_2			 (1L<<11)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_3			 (0x7L<<12)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_3			 (1L<<15)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_4			 (0x7L<<16)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_4			 (1L<<19)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_5			 (0x7L<<20)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_5			 (1L<<23)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_6			 (0x7L<<24)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_6			 (1L<<27)
+#define BNX2_DMA_WCHAN_STAT_COMP_CODE_7			 (0x7L<<28)
+#define BNX2_DMA_WCHAN_STAT_PAR_ERR_7			 (1L<<31)
+
+#define BNX2_DMA_RCHAN_ASSIGNMENT			0x00000c38
+#define BNX2_DMA_RCHAN_ASSIGNMENT_0			 (0xfL<<0)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_1			 (0xfL<<4)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_2			 (0xfL<<8)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_3			 (0xfL<<12)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_4			 (0xfL<<16)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_5			 (0xfL<<20)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_6			 (0xfL<<24)
+#define BNX2_DMA_RCHAN_ASSIGNMENT_7			 (0xfL<<28)
+
+#define BNX2_DMA_WCHAN_ASSIGNMENT			0x00000c3c
+#define BNX2_DMA_WCHAN_ASSIGNMENT_0			 (0xfL<<0)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_1			 (0xfL<<4)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_2			 (0xfL<<8)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_3			 (0xfL<<12)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_4			 (0xfL<<16)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_5			 (0xfL<<20)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_6			 (0xfL<<24)
+#define BNX2_DMA_WCHAN_ASSIGNMENT_7			 (0xfL<<28)
+
+#define BNX2_DMA_RCHAN_STAT_00				0x00000c40
+#define BNX2_DMA_RCHAN_STAT_00_RCHAN_STA_HOST_ADDR_LOW	 (0xffffffffL<<0)
+
+#define BNX2_DMA_RCHAN_STAT_01				0x00000c44
+#define BNX2_DMA_RCHAN_STAT_01_RCHAN_STA_HOST_ADDR_HIGH	 (0xffffffffL<<0)
+
+#define BNX2_DMA_RCHAN_STAT_02				0x00000c48
+#define BNX2_DMA_RCHAN_STAT_02_LENGTH			 (0xffffL<<0)
+#define BNX2_DMA_RCHAN_STAT_02_WORD_SWAP		 (1L<<16)
+#define BNX2_DMA_RCHAN_STAT_02_BYTE_SWAP		 (1L<<17)
+#define BNX2_DMA_RCHAN_STAT_02_PRIORITY_LVL		 (1L<<18)
+
+#define BNX2_DMA_RCHAN_STAT_10				0x00000c4c
+#define BNX2_DMA_RCHAN_STAT_11				0x00000c50
+#define BNX2_DMA_RCHAN_STAT_12				0x00000c54
+#define BNX2_DMA_RCHAN_STAT_20				0x00000c58
+#define BNX2_DMA_RCHAN_STAT_21				0x00000c5c
+#define BNX2_DMA_RCHAN_STAT_22				0x00000c60
+#define BNX2_DMA_RCHAN_STAT_30				0x00000c64
+#define BNX2_DMA_RCHAN_STAT_31				0x00000c68
+#define BNX2_DMA_RCHAN_STAT_32				0x00000c6c
+#define BNX2_DMA_RCHAN_STAT_40				0x00000c70
+#define BNX2_DMA_RCHAN_STAT_41				0x00000c74
+#define BNX2_DMA_RCHAN_STAT_42				0x00000c78
+#define BNX2_DMA_RCHAN_STAT_50				0x00000c7c
+#define BNX2_DMA_RCHAN_STAT_51				0x00000c80
+#define BNX2_DMA_RCHAN_STAT_52				0x00000c84
+#define BNX2_DMA_RCHAN_STAT_60				0x00000c88
+#define BNX2_DMA_RCHAN_STAT_61				0x00000c8c
+#define BNX2_DMA_RCHAN_STAT_62				0x00000c90
+#define BNX2_DMA_RCHAN_STAT_70				0x00000c94
+#define BNX2_DMA_RCHAN_STAT_71				0x00000c98
+#define BNX2_DMA_RCHAN_STAT_72				0x00000c9c
+#define BNX2_DMA_WCHAN_STAT_00				0x00000ca0
+#define BNX2_DMA_WCHAN_STAT_00_WCHAN_STA_HOST_ADDR_LOW	 (0xffffffffL<<0)
+
+#define BNX2_DMA_WCHAN_STAT_01				0x00000ca4
+#define BNX2_DMA_WCHAN_STAT_01_WCHAN_STA_HOST_ADDR_HIGH	 (0xffffffffL<<0)
+
+#define BNX2_DMA_WCHAN_STAT_02				0x00000ca8
+#define BNX2_DMA_WCHAN_STAT_02_LENGTH			 (0xffffL<<0)
+#define BNX2_DMA_WCHAN_STAT_02_WORD_SWAP		 (1L<<16)
+#define BNX2_DMA_WCHAN_STAT_02_BYTE_SWAP		 (1L<<17)
+#define BNX2_DMA_WCHAN_STAT_02_PRIORITY_LVL		 (1L<<18)
+
+#define BNX2_DMA_WCHAN_STAT_10				0x00000cac
+#define BNX2_DMA_WCHAN_STAT_11				0x00000cb0
+#define BNX2_DMA_WCHAN_STAT_12				0x00000cb4
+#define BNX2_DMA_WCHAN_STAT_20				0x00000cb8
+#define BNX2_DMA_WCHAN_STAT_21				0x00000cbc
+#define BNX2_DMA_WCHAN_STAT_22				0x00000cc0
+#define BNX2_DMA_WCHAN_STAT_30				0x00000cc4
+#define BNX2_DMA_WCHAN_STAT_31				0x00000cc8
+#define BNX2_DMA_WCHAN_STAT_32				0x00000ccc
+#define BNX2_DMA_WCHAN_STAT_40				0x00000cd0
+#define BNX2_DMA_WCHAN_STAT_41				0x00000cd4
+#define BNX2_DMA_WCHAN_STAT_42				0x00000cd8
+#define BNX2_DMA_WCHAN_STAT_50				0x00000cdc
+#define BNX2_DMA_WCHAN_STAT_51				0x00000ce0
+#define BNX2_DMA_WCHAN_STAT_52				0x00000ce4
+#define BNX2_DMA_WCHAN_STAT_60				0x00000ce8
+#define BNX2_DMA_WCHAN_STAT_61				0x00000cec
+#define BNX2_DMA_WCHAN_STAT_62				0x00000cf0
+#define BNX2_DMA_WCHAN_STAT_70				0x00000cf4
+#define BNX2_DMA_WCHAN_STAT_71				0x00000cf8
+#define BNX2_DMA_WCHAN_STAT_72				0x00000cfc
+#define BNX2_DMA_ARB_STAT_00				0x00000d00
+#define BNX2_DMA_ARB_STAT_00_MASTER			 (0xffffL<<0)
+#define BNX2_DMA_ARB_STAT_00_MASTER_ENC			 (0xffL<<16)
+#define BNX2_DMA_ARB_STAT_00_CUR_BINMSTR		 (0xffL<<24)
+
+#define BNX2_DMA_ARB_STAT_01				0x00000d04
+#define BNX2_DMA_ARB_STAT_01_LPR_RPTR			 (0xfL<<0)
+#define BNX2_DMA_ARB_STAT_01_LPR_WPTR			 (0xfL<<4)
+#define BNX2_DMA_ARB_STAT_01_LPB_RPTR			 (0xfL<<8)
+#define BNX2_DMA_ARB_STAT_01_LPB_WPTR			 (0xfL<<12)
+#define BNX2_DMA_ARB_STAT_01_HPR_RPTR			 (0xfL<<16)
+#define BNX2_DMA_ARB_STAT_01_HPR_WPTR			 (0xfL<<20)
+#define BNX2_DMA_ARB_STAT_01_HPB_RPTR			 (0xfL<<24)
+#define BNX2_DMA_ARB_STAT_01_HPB_WPTR			 (0xfL<<28)
+
+#define BNX2_DMA_FUSE_CTRL0_CMD				0x00000f00
+#define BNX2_DMA_FUSE_CTRL0_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL0_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL0_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL0_DATA			0x00000f04
+#define BNX2_DMA_FUSE_CTRL1_CMD				0x00000f08
+#define BNX2_DMA_FUSE_CTRL1_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL1_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL1_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL1_DATA			0x00000f0c
+#define BNX2_DMA_FUSE_CTRL2_CMD				0x00000f10
+#define BNX2_DMA_FUSE_CTRL2_CMD_PWRUP_DONE		 (1L<<0)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SHIFT_DONE		 (1L<<1)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SHIFT			 (1L<<2)
+#define BNX2_DMA_FUSE_CTRL2_CMD_LOAD			 (1L<<3)
+#define BNX2_DMA_FUSE_CTRL2_CMD_SEL			 (0xfL<<8)
+
+#define BNX2_DMA_FUSE_CTRL2_DATA			0x00000f14
+
+
+/*
+ *  context_reg definition
+ *  offset: 0x1000
+ */
+#define BNX2_CTX_COMMAND				0x00001000
+#define BNX2_CTX_COMMAND_ENABLED			 (1L<<0)
+
+#define BNX2_CTX_STATUS					0x00001004
+#define BNX2_CTX_STATUS_LOCK_WAIT			 (1L<<0)
+#define BNX2_CTX_STATUS_READ_STAT			 (1L<<16)
+#define BNX2_CTX_STATUS_WRITE_STAT			 (1L<<17)
+#define BNX2_CTX_STATUS_ACC_STALL_STAT			 (1L<<18)
+#define BNX2_CTX_STATUS_LOCK_STALL_STAT			 (1L<<19)
+
+#define BNX2_CTX_VIRT_ADDR				0x00001008
+#define BNX2_CTX_VIRT_ADDR_VIRT_ADDR			 (0x7fffL<<6)
+
+#define BNX2_CTX_PAGE_TBL				0x0000100c
+#define BNX2_CTX_PAGE_TBL_PAGE_TBL			 (0x3fffL<<6)
+
+#define BNX2_CTX_DATA_ADR				0x00001010
+#define BNX2_CTX_DATA_ADR_DATA_ADR			 (0x7ffffL<<2)
+
+#define BNX2_CTX_DATA					0x00001014
+#define BNX2_CTX_LOCK					0x00001018
+#define BNX2_CTX_LOCK_TYPE				 (0x7L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_VOID		 (0x0L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_COMPLETE		 (0x7L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_PROTOCOL		 (0x1L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_TX			 (0x2L<<0)
+#define BNX2_CTX_LOCK_TYPE_LOCK_TYPE_TIMER		 (0x4L<<0)
+#define BNX2_CTX_LOCK_CID_VALUE				 (0x3fffL<<7)
+#define BNX2_CTX_LOCK_GRANTED				 (1L<<26)
+#define BNX2_CTX_LOCK_MODE				 (0x7L<<27)
+#define BNX2_CTX_LOCK_MODE_UNLOCK			 (0x0L<<27)
+#define BNX2_CTX_LOCK_MODE_IMMEDIATE			 (0x1L<<27)
+#define BNX2_CTX_LOCK_MODE_SURE				 (0x2L<<27)
+#define BNX2_CTX_LOCK_STATUS				 (1L<<30)
+#define BNX2_CTX_LOCK_REQ				 (1L<<31)
+
+#define BNX2_CTX_ACCESS_STATUS				0x00001040
+#define BNX2_CTX_ACCESS_STATUS_MASTERENCODED		 (0xfL<<0)
+#define BNX2_CTX_ACCESS_STATUS_ACCESSMEMORYSM		 (0x3L<<10)
+#define BNX2_CTX_ACCESS_STATUS_PAGETABLEINITSM		 (0x3L<<12)
+#define BNX2_CTX_ACCESS_STATUS_ACCESSMEMORYINITSM	 (0x3L<<14)
+#define BNX2_CTX_ACCESS_STATUS_QUALIFIED_REQUEST	 (0x7ffL<<17)
+
+#define BNX2_CTX_DBG_LOCK_STATUS			0x00001044
+#define BNX2_CTX_DBG_LOCK_STATUS_SM			 (0x3ffL<<0)
+#define BNX2_CTX_DBG_LOCK_STATUS_MATCH			 (0x3ffL<<22)
+
+#define BNX2_CTX_CHNL_LOCK_STATUS_0			0x00001080
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_CID			 (0x3fffL<<0)
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_TYPE		 (0x3L<<14)
+#define BNX2_CTX_CHNL_LOCK_STATUS_0_MODE		 (1L<<16)
+
+#define BNX2_CTX_CHNL_LOCK_STATUS_1			0x00001084
+#define BNX2_CTX_CHNL_LOCK_STATUS_2			0x00001088
+#define BNX2_CTX_CHNL_LOCK_STATUS_3			0x0000108c
+#define BNX2_CTX_CHNL_LOCK_STATUS_4			0x00001090
+#define BNX2_CTX_CHNL_LOCK_STATUS_5			0x00001094
+#define BNX2_CTX_CHNL_LOCK_STATUS_6			0x00001098
+#define BNX2_CTX_CHNL_LOCK_STATUS_7			0x0000109c
+#define BNX2_CTX_CHNL_LOCK_STATUS_8			0x000010a0
+
+
+/*
+ *  emac_reg definition
+ *  offset: 0x1400
+ */
+#define BNX2_EMAC_MODE					0x00001400
+#define BNX2_EMAC_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_MODE_HALF_DUPLEX			 (1L<<1)
+#define BNX2_EMAC_MODE_PORT				 (0x3L<<2)
+#define BNX2_EMAC_MODE_PORT_NONE			 (0L<<2)
+#define BNX2_EMAC_MODE_PORT_MII				 (1L<<2)
+#define BNX2_EMAC_MODE_PORT_GMII			 (2L<<2)
+#define BNX2_EMAC_MODE_PORT_MII_10			 (3L<<2)
+#define BNX2_EMAC_MODE_MAC_LOOP				 (1L<<4)
+#define BNX2_EMAC_MODE_25G				 (1L<<5)
+#define BNX2_EMAC_MODE_TAGGED_MAC_CTL			 (1L<<7)
+#define BNX2_EMAC_MODE_TX_BURST				 (1L<<8)
+#define BNX2_EMAC_MODE_MAX_DEFER_DROP_ENA		 (1L<<9)
+#define BNX2_EMAC_MODE_EXT_LINK_POL			 (1L<<10)
+#define BNX2_EMAC_MODE_FORCE_LINK			 (1L<<11)
+#define BNX2_EMAC_MODE_MPKT				 (1L<<18)
+#define BNX2_EMAC_MODE_MPKT_RCVD			 (1L<<19)
+#define BNX2_EMAC_MODE_ACPI_RCVD			 (1L<<20)
+
+#define BNX2_EMAC_STATUS				0x00001404
+#define BNX2_EMAC_STATUS_LINK				 (1L<<11)
+#define BNX2_EMAC_STATUS_LINK_CHANGE			 (1L<<12)
+#define BNX2_EMAC_STATUS_MI_COMPLETE			 (1L<<22)
+#define BNX2_EMAC_STATUS_MI_INT				 (1L<<23)
+#define BNX2_EMAC_STATUS_AP_ERROR			 (1L<<24)
+#define BNX2_EMAC_STATUS_PARITY_ERROR_STATE		 (1L<<31)
+
+#define BNX2_EMAC_ATTENTION_ENA				0x00001408
+#define BNX2_EMAC_ATTENTION_ENA_LINK			 (1L<<11)
+#define BNX2_EMAC_ATTENTION_ENA_MI_COMPLETE		 (1L<<22)
+#define BNX2_EMAC_ATTENTION_ENA_MI_INT			 (1L<<23)
+#define BNX2_EMAC_ATTENTION_ENA_AP_ERROR		 (1L<<24)
+
+#define BNX2_EMAC_LED					0x0000140c
+#define BNX2_EMAC_LED_OVERRIDE				 (1L<<0)
+#define BNX2_EMAC_LED_1000MB_OVERRIDE			 (1L<<1)
+#define BNX2_EMAC_LED_100MB_OVERRIDE			 (1L<<2)
+#define BNX2_EMAC_LED_10MB_OVERRIDE			 (1L<<3)
+#define BNX2_EMAC_LED_TRAFFIC_OVERRIDE			 (1L<<4)
+#define BNX2_EMAC_LED_BLNK_TRAFFIC			 (1L<<5)
+#define BNX2_EMAC_LED_TRAFFIC				 (1L<<6)
+#define BNX2_EMAC_LED_1000MB				 (1L<<7)
+#define BNX2_EMAC_LED_100MB				 (1L<<8)
+#define BNX2_EMAC_LED_10MB				 (1L<<9)
+#define BNX2_EMAC_LED_TRAFFIC_STAT			 (1L<<10)
+#define BNX2_EMAC_LED_BLNK_RATE				 (0xfffL<<19)
+#define BNX2_EMAC_LED_BLNK_RATE_ENA			 (1L<<31)
+
+#define BNX2_EMAC_MAC_MATCH0				0x00001410
+#define BNX2_EMAC_MAC_MATCH1				0x00001414
+#define BNX2_EMAC_MAC_MATCH2				0x00001418
+#define BNX2_EMAC_MAC_MATCH3				0x0000141c
+#define BNX2_EMAC_MAC_MATCH4				0x00001420
+#define BNX2_EMAC_MAC_MATCH5				0x00001424
+#define BNX2_EMAC_MAC_MATCH6				0x00001428
+#define BNX2_EMAC_MAC_MATCH7				0x0000142c
+#define BNX2_EMAC_MAC_MATCH8				0x00001430
+#define BNX2_EMAC_MAC_MATCH9				0x00001434
+#define BNX2_EMAC_MAC_MATCH10				0x00001438
+#define BNX2_EMAC_MAC_MATCH11				0x0000143c
+#define BNX2_EMAC_MAC_MATCH12				0x00001440
+#define BNX2_EMAC_MAC_MATCH13				0x00001444
+#define BNX2_EMAC_MAC_MATCH14				0x00001448
+#define BNX2_EMAC_MAC_MATCH15				0x0000144c
+#define BNX2_EMAC_MAC_MATCH16				0x00001450
+#define BNX2_EMAC_MAC_MATCH17				0x00001454
+#define BNX2_EMAC_MAC_MATCH18				0x00001458
+#define BNX2_EMAC_MAC_MATCH19				0x0000145c
+#define BNX2_EMAC_MAC_MATCH20				0x00001460
+#define BNX2_EMAC_MAC_MATCH21				0x00001464
+#define BNX2_EMAC_MAC_MATCH22				0x00001468
+#define BNX2_EMAC_MAC_MATCH23				0x0000146c
+#define BNX2_EMAC_MAC_MATCH24				0x00001470
+#define BNX2_EMAC_MAC_MATCH25				0x00001474
+#define BNX2_EMAC_MAC_MATCH26				0x00001478
+#define BNX2_EMAC_MAC_MATCH27				0x0000147c
+#define BNX2_EMAC_MAC_MATCH28				0x00001480
+#define BNX2_EMAC_MAC_MATCH29				0x00001484
+#define BNX2_EMAC_MAC_MATCH30				0x00001488
+#define BNX2_EMAC_MAC_MATCH31				0x0000148c
+#define BNX2_EMAC_BACKOFF_SEED				0x00001498
+#define BNX2_EMAC_BACKOFF_SEED_EMAC_BACKOFF_SEED	 (0x3ffL<<0)
+
+#define BNX2_EMAC_RX_MTU_SIZE				0x0000149c
+#define BNX2_EMAC_RX_MTU_SIZE_MTU_SIZE			 (0xffffL<<0)
+#define BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA			 (1L<<31)
+
+#define BNX2_EMAC_SERDES_CNTL				0x000014a4
+#define BNX2_EMAC_SERDES_CNTL_RXR			 (0x7L<<0)
+#define BNX2_EMAC_SERDES_CNTL_RXG			 (0x3L<<3)
+#define BNX2_EMAC_SERDES_CNTL_RXCKSEL			 (1L<<6)
+#define BNX2_EMAC_SERDES_CNTL_TXBIAS			 (0x7L<<7)
+#define BNX2_EMAC_SERDES_CNTL_BGMAX			 (1L<<10)
+#define BNX2_EMAC_SERDES_CNTL_BGMIN			 (1L<<11)
+#define BNX2_EMAC_SERDES_CNTL_TXMODE			 (1L<<12)
+#define BNX2_EMAC_SERDES_CNTL_TXEDGE			 (1L<<13)
+#define BNX2_EMAC_SERDES_CNTL_SERDES_MODE		 (1L<<14)
+#define BNX2_EMAC_SERDES_CNTL_PLLTEST			 (1L<<15)
+#define BNX2_EMAC_SERDES_CNTL_CDET_EN			 (1L<<16)
+#define BNX2_EMAC_SERDES_CNTL_TBI_LBK			 (1L<<17)
+#define BNX2_EMAC_SERDES_CNTL_REMOTE_LBK		 (1L<<18)
+#define BNX2_EMAC_SERDES_CNTL_REV_PHASE			 (1L<<19)
+#define BNX2_EMAC_SERDES_CNTL_REGCTL12			 (0x3L<<20)
+#define BNX2_EMAC_SERDES_CNTL_REGCTL25			 (0x3L<<22)
+
+#define BNX2_EMAC_SERDES_STATUS				0x000014a8
+#define BNX2_EMAC_SERDES_STATUS_RX_STAT			 (0xffL<<0)
+#define BNX2_EMAC_SERDES_STATUS_COMMA_DET		 (1L<<8)
+
+#define BNX2_EMAC_MDIO_COMM				0x000014ac
+#define BNX2_EMAC_MDIO_COMM_DATA			 (0xffffL<<0)
+#define BNX2_EMAC_MDIO_COMM_REG_ADDR			 (0x1fL<<16)
+#define BNX2_EMAC_MDIO_COMM_PHY_ADDR			 (0x1fL<<21)
+#define BNX2_EMAC_MDIO_COMM_COMMAND			 (0x3L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_UNDEFINED_0		 (0L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_WRITE		 (1L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_READ		 (2L<<26)
+#define BNX2_EMAC_MDIO_COMM_COMMAND_UNDEFINED_3		 (3L<<26)
+#define BNX2_EMAC_MDIO_COMM_FAIL			 (1L<<28)
+#define BNX2_EMAC_MDIO_COMM_START_BUSY			 (1L<<29)
+#define BNX2_EMAC_MDIO_COMM_DISEXT			 (1L<<30)
+
+#define BNX2_EMAC_MDIO_STATUS				0x000014b0
+#define BNX2_EMAC_MDIO_STATUS_LINK			 (1L<<0)
+#define BNX2_EMAC_MDIO_STATUS_10MB			 (1L<<1)
+
+#define BNX2_EMAC_MDIO_MODE				0x000014b4
+#define BNX2_EMAC_MDIO_MODE_SHORT_PREAMBLE		 (1L<<1)
+#define BNX2_EMAC_MDIO_MODE_AUTO_POLL			 (1L<<4)
+#define BNX2_EMAC_MDIO_MODE_BIT_BANG			 (1L<<8)
+#define BNX2_EMAC_MDIO_MODE_MDIO			 (1L<<9)
+#define BNX2_EMAC_MDIO_MODE_MDIO_OE			 (1L<<10)
+#define BNX2_EMAC_MDIO_MODE_MDC				 (1L<<11)
+#define BNX2_EMAC_MDIO_MODE_MDINT			 (1L<<12)
+#define BNX2_EMAC_MDIO_MODE_CLOCK_CNT			 (0x1fL<<16)
+
+#define BNX2_EMAC_MDIO_AUTO_STATUS			0x000014b8
+#define BNX2_EMAC_MDIO_AUTO_STATUS_AUTO_ERR		 (1L<<0)
+
+#define BNX2_EMAC_TX_MODE				0x000014bc
+#define BNX2_EMAC_TX_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_TX_MODE_EXT_PAUSE_EN			 (1L<<3)
+#define BNX2_EMAC_TX_MODE_FLOW_EN			 (1L<<4)
+#define BNX2_EMAC_TX_MODE_BIG_BACKOFF			 (1L<<5)
+#define BNX2_EMAC_TX_MODE_LONG_PAUSE			 (1L<<6)
+#define BNX2_EMAC_TX_MODE_LINK_AWARE			 (1L<<7)
+
+#define BNX2_EMAC_TX_STATUS				0x000014c0
+#define BNX2_EMAC_TX_STATUS_XOFFED			 (1L<<0)
+#define BNX2_EMAC_TX_STATUS_XOFF_SENT			 (1L<<1)
+#define BNX2_EMAC_TX_STATUS_XON_SENT			 (1L<<2)
+#define BNX2_EMAC_TX_STATUS_LINK_UP			 (1L<<3)
+#define BNX2_EMAC_TX_STATUS_UNDERRUN			 (1L<<4)
+
+#define BNX2_EMAC_TX_LENGTHS				0x000014c4
+#define BNX2_EMAC_TX_LENGTHS_SLOT			 (0xffL<<0)
+#define BNX2_EMAC_TX_LENGTHS_IPG			 (0xfL<<8)
+#define BNX2_EMAC_TX_LENGTHS_IPG_CRS			 (0x3L<<12)
+
+#define BNX2_EMAC_RX_MODE				0x000014c8
+#define BNX2_EMAC_RX_MODE_RESET				 (1L<<0)
+#define BNX2_EMAC_RX_MODE_FLOW_EN			 (1L<<2)
+#define BNX2_EMAC_RX_MODE_KEEP_MAC_CONTROL		 (1L<<3)
+#define BNX2_EMAC_RX_MODE_KEEP_PAUSE			 (1L<<4)
+#define BNX2_EMAC_RX_MODE_ACCEPT_OVERSIZE		 (1L<<5)
+#define BNX2_EMAC_RX_MODE_ACCEPT_RUNTS			 (1L<<6)
+#define BNX2_EMAC_RX_MODE_LLC_CHK			 (1L<<7)
+#define BNX2_EMAC_RX_MODE_PROMISCUOUS			 (1L<<8)
+#define BNX2_EMAC_RX_MODE_NO_CRC_CHK			 (1L<<9)
+#define BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG			 (1L<<10)
+#define BNX2_EMAC_RX_MODE_FILT_BROADCAST		 (1L<<11)
+#define BNX2_EMAC_RX_MODE_SORT_MODE			 (1L<<12)
+
+#define BNX2_EMAC_RX_STATUS				0x000014cc
+#define BNX2_EMAC_RX_STATUS_FFED			 (1L<<0)
+#define BNX2_EMAC_RX_STATUS_FF_RECEIVED			 (1L<<1)
+#define BNX2_EMAC_RX_STATUS_N_RECEIVED			 (1L<<2)
+
+#define BNX2_EMAC_MULTICAST_HASH0			0x000014d0
+#define BNX2_EMAC_MULTICAST_HASH1			0x000014d4
+#define BNX2_EMAC_MULTICAST_HASH2			0x000014d8
+#define BNX2_EMAC_MULTICAST_HASH3			0x000014dc
+#define BNX2_EMAC_MULTICAST_HASH4			0x000014e0
+#define BNX2_EMAC_MULTICAST_HASH5			0x000014e4
+#define BNX2_EMAC_MULTICAST_HASH6			0x000014e8
+#define BNX2_EMAC_MULTICAST_HASH7			0x000014ec
+#define BNX2_EMAC_RX_STAT_IFHCINOCTETS			0x00001500
+#define BNX2_EMAC_RX_STAT_IFHCINBADOCTETS		0x00001504
+#define BNX2_EMAC_RX_STAT_ETHERSTATSFRAGMENTS		0x00001508
+#define BNX2_EMAC_RX_STAT_IFHCINUCASTPKTS		0x0000150c
+#define BNX2_EMAC_RX_STAT_IFHCINMULTICASTPKTS		0x00001510
+#define BNX2_EMAC_RX_STAT_IFHCINBROADCASTPKTS		0x00001514
+#define BNX2_EMAC_RX_STAT_DOT3STATSFCSERRORS		0x00001518
+#define BNX2_EMAC_RX_STAT_DOT3STATSALIGNMENTERRORS	0x0000151c
+#define BNX2_EMAC_RX_STAT_DOT3STATSCARRIERSENSEERRORS	0x00001520
+#define BNX2_EMAC_RX_STAT_XONPAUSEFRAMESRECEIVED	0x00001524
+#define BNX2_EMAC_RX_STAT_XOFFPAUSEFRAMESRECEIVED	0x00001528
+#define BNX2_EMAC_RX_STAT_MACCONTROLFRAMESRECEIVED	0x0000152c
+#define BNX2_EMAC_RX_STAT_XOFFSTATEENTERED		0x00001530
+#define BNX2_EMAC_RX_STAT_DOT3STATSFRAMESTOOLONG	0x00001534
+#define BNX2_EMAC_RX_STAT_ETHERSTATSJABBERS		0x00001538
+#define BNX2_EMAC_RX_STAT_ETHERSTATSUNDERSIZEPKTS	0x0000153c
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS64OCTETS	0x00001540
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS65OCTETSTO127OCTETS	0x00001544
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS128OCTETSTO255OCTETS	0x00001548
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS256OCTETSTO511OCTETS	0x0000154c
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS512OCTETSTO1023OCTETS	0x00001550
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS1024OCTETSTO1522OCTETS	0x00001554
+#define BNX2_EMAC_RX_STAT_ETHERSTATSPKTS1523OCTETSTO9022OCTETS	0x00001558
+#define BNX2_EMAC_RXMAC_DEBUG0				0x0000155c
+#define BNX2_EMAC_RXMAC_DEBUG1				0x00001560
+#define BNX2_EMAC_RXMAC_DEBUG1_LENGTH_NE_BYTE_COUNT	 (1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG1_LENGTH_OUT_RANGE		 (1L<<1)
+#define BNX2_EMAC_RXMAC_DEBUG1_BAD_CRC			 (1L<<2)
+#define BNX2_EMAC_RXMAC_DEBUG1_RX_ERROR			 (1L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG1_ALIGN_ERROR		 (1L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG1_LAST_DATA		 (1L<<5)
+#define BNX2_EMAC_RXMAC_DEBUG1_ODD_BYTE_START		 (1L<<6)
+#define BNX2_EMAC_RXMAC_DEBUG1_BYTE_COUNT		 (0xffffL<<7)
+#define BNX2_EMAC_RXMAC_DEBUG1_SLOT_TIME		 (0xffL<<23)
+
+#define BNX2_EMAC_RXMAC_DEBUG2				0x00001564
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE			 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SFD		 (0x1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_DATA		 (0x2L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SKEEP		 (0x3L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_EXT		 (0x4L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_DROP		 (0x5L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_SDROP		 (0x6L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_SM_STATE_FC		 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE		 (0xfL<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_IDLE		 (0x0L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA0		 (0x1L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA1		 (0x2L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA2		 (0x3L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_DATA3		 (0x4L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_ABORT		 (0x5L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_WAIT		 (0x6L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_STATUS		 (0x7L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_IDI_STATE_LAST		 (0x8L<<3)
+#define BNX2_EMAC_RXMAC_DEBUG2_BYTE_IN			 (0xffL<<7)
+#define BNX2_EMAC_RXMAC_DEBUG2_FALSEC			 (1L<<15)
+#define BNX2_EMAC_RXMAC_DEBUG2_TAGGED			 (1L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE		 (1L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE_IDLE		 (0L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_PAUSE_STATE_PAUSED	 (1L<<18)
+#define BNX2_EMAC_RXMAC_DEBUG2_SE_COUNTER		 (0xfL<<19)
+#define BNX2_EMAC_RXMAC_DEBUG2_QUANTA			 (0x1fL<<23)
+
+#define BNX2_EMAC_RXMAC_DEBUG3				0x00001568
+#define BNX2_EMAC_RXMAC_DEBUG3_PAUSE_CTR		 (0xffffL<<0)
+#define BNX2_EMAC_RXMAC_DEBUG3_TMP_PAUSE_CTR		 (0xffffL<<16)
+
+#define BNX2_EMAC_RXMAC_DEBUG4				0x0000156c
+#define BNX2_EMAC_RXMAC_DEBUG4_TYPE_FIELD		 (0xffffL<<0)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE		 (0x3fL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_IDLE		 (0x0L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UMAC2		 (0x1L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UMAC3		 (0x2L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UNI		 (0x3L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MMAC2		 (0x7L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MMAC3		 (0x5L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA1		 (0x6L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA2		 (0x7L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PSA3		 (0x8L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC2		 (0x9L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC3		 (0xaL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MWAIT1	 (0xeL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MWAIT2	 (0xfL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MCHECK	 (0x10L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MC		 (0x11L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC2		 (0x12L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC3		 (0x13L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA1		 (0x14L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA2		 (0x15L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BSA3		 (0x16L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BTYPE		 (0x17L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_BC		 (0x18L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PTYPE		 (0x19L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_CMD		 (0x1aL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MAC		 (0x1bL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_LATCH		 (0x1cL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_XOFF		 (0x1dL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_XON		 (0x1eL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_PAUSED	 (0x1fL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_NPAUSED	 (0x20L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_TTYPE		 (0x21L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_TVAL		 (0x22L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA1		 (0x23L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA2		 (0x24L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_USA3		 (0x25L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTYPE		 (0x26L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTTYPE	 (0x27L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_UTVAL		 (0x28L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_MTYPE		 (0x29L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_FILT_STATE_DROP		 (0x2aL<<16)
+#define BNX2_EMAC_RXMAC_DEBUG4_DROP_PKT			 (1L<<22)
+#define BNX2_EMAC_RXMAC_DEBUG4_SLOT_FILLED		 (1L<<23)
+#define BNX2_EMAC_RXMAC_DEBUG4_FALSE_CARRIER		 (1L<<24)
+#define BNX2_EMAC_RXMAC_DEBUG4_LAST_DATA		 (1L<<25)
+#define BNX2_EMAC_RXMAC_DEBUG4_sfd_FOUND		 (1L<<26)
+#define BNX2_EMAC_RXMAC_DEBUG4_ADVANCE			 (1L<<27)
+#define BNX2_EMAC_RXMAC_DEBUG4_START			 (1L<<28)
+
+#define BNX2_EMAC_RXMAC_DEBUG5				0x00001570
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM			 (0x7L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_IDLE		 (0L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_WAIT_EOF	 (1L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_WAIT_STAT	 (2L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4FCRC	 (3L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4RDE	 (4L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_SET_EOF4ALL	 (5L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_PS_IDISM_1WD_WAIT_STAT	 (6L<<0)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1		 (0x7L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_VDW		 (0x0L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_STAT		 (0x1L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_AEOF		 (0x2L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_NEOF		 (0x3L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SOF		 (0x4L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SAEOF		 (0x6L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF1_SNEOF		 (0x7L<<4)
+#define BNX2_EMAC_RXMAC_DEBUG5_EOF_DETECTED		 (1L<<7)
+#define BNX2_EMAC_RXMAC_DEBUG5_CCODE_BUF0		 (0x7L<<8)
+#define BNX2_EMAC_RXMAC_DEBUG5_RPM_IDI_FIFO_FULL	 (1L<<11)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_CCODE		 (1L<<12)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_DATA		 (1L<<13)
+#define BNX2_EMAC_RXMAC_DEBUG5_LOAD_STAT		 (1L<<14)
+#define BNX2_EMAC_RXMAC_DEBUG5_CLR_STAT			 (1L<<15)
+#define BNX2_EMAC_RXMAC_DEBUG5_IDI_RPM_CCODE		 (0x3L<<16)
+#define BNX2_EMAC_RXMAC_DEBUG5_IDI_RPM_ACCEPT		 (1L<<19)
+#define BNX2_EMAC_RXMAC_DEBUG5_FMLEN			 (0xfffL<<20)
+
+#define BNX2_EMAC_RX_STAT_AC0				0x00001580
+#define BNX2_EMAC_RX_STAT_AC1				0x00001584
+#define BNX2_EMAC_RX_STAT_AC2				0x00001588
+#define BNX2_EMAC_RX_STAT_AC3				0x0000158c
+#define BNX2_EMAC_RX_STAT_AC4				0x00001590
+#define BNX2_EMAC_RX_STAT_AC5				0x00001594
+#define BNX2_EMAC_RX_STAT_AC6				0x00001598
+#define BNX2_EMAC_RX_STAT_AC7				0x0000159c
+#define BNX2_EMAC_RX_STAT_AC8				0x000015a0
+#define BNX2_EMAC_RX_STAT_AC9				0x000015a4
+#define BNX2_EMAC_RX_STAT_AC10				0x000015a8
+#define BNX2_EMAC_RX_STAT_AC11				0x000015ac
+#define BNX2_EMAC_RX_STAT_AC12				0x000015b0
+#define BNX2_EMAC_RX_STAT_AC13				0x000015b4
+#define BNX2_EMAC_RX_STAT_AC14				0x000015b8
+#define BNX2_EMAC_RX_STAT_AC15				0x000015bc
+#define BNX2_EMAC_RX_STAT_AC16				0x000015c0
+#define BNX2_EMAC_RX_STAT_AC17				0x000015c4
+#define BNX2_EMAC_RX_STAT_AC18				0x000015c8
+#define BNX2_EMAC_RX_STAT_AC19				0x000015cc
+#define BNX2_EMAC_RX_STAT_AC20				0x000015d0
+#define BNX2_EMAC_RX_STAT_AC21				0x000015d4
+#define BNX2_EMAC_RX_STAT_AC22				0x000015d8
+#define BNX2_EMAC_RXMAC_SUC_DBG_OVERRUNVEC		0x000015dc
+#define BNX2_EMAC_TX_STAT_IFHCOUTOCTETS			0x00001600
+#define BNX2_EMAC_TX_STAT_IFHCOUTBADOCTETS		0x00001604
+#define BNX2_EMAC_TX_STAT_ETHERSTATSCOLLISIONS		0x00001608
+#define BNX2_EMAC_TX_STAT_OUTXONSENT			0x0000160c
+#define BNX2_EMAC_TX_STAT_OUTXOFFSENT			0x00001610
+#define BNX2_EMAC_TX_STAT_FLOWCONTROLDONE		0x00001614
+#define BNX2_EMAC_TX_STAT_DOT3STATSSINGLECOLLISIONFRAMES	0x00001618
+#define BNX2_EMAC_TX_STAT_DOT3STATSMULTIPLECOLLISIONFRAMES	0x0000161c
+#define BNX2_EMAC_TX_STAT_DOT3STATSDEFERREDTRANSMISSIONS	0x00001620
+#define BNX2_EMAC_TX_STAT_DOT3STATSEXCESSIVECOLLISIONS	0x00001624
+#define BNX2_EMAC_TX_STAT_DOT3STATSLATECOLLISIONS	0x00001628
+#define BNX2_EMAC_TX_STAT_IFHCOUTUCASTPKTS		0x0000162c
+#define BNX2_EMAC_TX_STAT_IFHCOUTMULTICASTPKTS		0x00001630
+#define BNX2_EMAC_TX_STAT_IFHCOUTBROADCASTPKTS		0x00001634
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS64OCTETS	0x00001638
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS65OCTETSTO127OCTETS	0x0000163c
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS128OCTETSTO255OCTETS	0x00001640
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS256OCTETSTO511OCTETS	0x00001644
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS512OCTETSTO1023OCTETS	0x00001648
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS1024OCTETSTO1522OCTETS	0x0000164c
+#define BNX2_EMAC_TX_STAT_ETHERSTATSPKTS1523OCTETSTO9022OCTETS	0x00001650
+#define BNX2_EMAC_TX_STAT_DOT3STATSINTERNALMACTRANSMITERRORS	0x00001654
+#define BNX2_EMAC_TXMAC_DEBUG0				0x00001658
+#define BNX2_EMAC_TXMAC_DEBUG1				0x0000165c
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE		 (0xfL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_START0		 (0x1L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA0		 (0x4L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA1		 (0x5L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA2		 (0x6L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_DATA3		 (0x7L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_WAIT0		 (0x8L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_ODI_STATE_WAIT1		 (0x9L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG1_CRS_ENABLE		 (1L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG1_BAD_CRC			 (1L<<5)
+#define BNX2_EMAC_TXMAC_DEBUG1_SE_COUNTER		 (0xfL<<6)
+#define BNX2_EMAC_TXMAC_DEBUG1_SEND_PAUSE		 (1L<<10)
+#define BNX2_EMAC_TXMAC_DEBUG1_LATE_COLLISION		 (1L<<11)
+#define BNX2_EMAC_TXMAC_DEBUG1_MAX_DEFER		 (1L<<12)
+#define BNX2_EMAC_TXMAC_DEBUG1_DEFERRED			 (1L<<13)
+#define BNX2_EMAC_TXMAC_DEBUG1_ONE_BYTE			 (1L<<14)
+#define BNX2_EMAC_TXMAC_DEBUG1_IPG_TIME			 (0xfL<<15)
+#define BNX2_EMAC_TXMAC_DEBUG1_SLOT_TIME		 (0xffL<<19)
+
+#define BNX2_EMAC_TXMAC_DEBUG2				0x00001660
+#define BNX2_EMAC_TXMAC_DEBUG2_BACK_OFF			 (0x3ffL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG2_BYTE_COUNT		 (0xffffL<<10)
+#define BNX2_EMAC_TXMAC_DEBUG2_COL_COUNT		 (0x1fL<<26)
+#define BNX2_EMAC_TXMAC_DEBUG2_COL_BIT			 (1L<<31)
+
+#define BNX2_EMAC_TXMAC_DEBUG3				0x00001664
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE			 (0xfL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_IDLE		 (0x0L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_PRE1		 (0x1L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_PRE2		 (0x2L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_SFD		 (0x3L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_DATA		 (0x4L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_CRC1		 (0x5L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_CRC2		 (0x6L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_EXT		 (0x7L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_STATB		 (0x8L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_STATG		 (0x9L<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_JAM		 (0xaL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_EJAM		 (0xbL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_BJAM		 (0xcL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_SWAIT		 (0xdL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_SM_STATE_BACKOFF		 (0xeL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE		 (0x7L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_IDLE		 (0x0L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_WAIT		 (0x1L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_UNI		 (0x2L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_MC		 (0x3L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC2		 (0x4L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC3		 (0x5L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_FILT_STATE_BC		 (0x6L<<4)
+#define BNX2_EMAC_TXMAC_DEBUG3_CRS_DONE			 (1L<<7)
+#define BNX2_EMAC_TXMAC_DEBUG3_XOFF			 (1L<<8)
+#define BNX2_EMAC_TXMAC_DEBUG3_SE_COUNTER		 (0xfL<<9)
+#define BNX2_EMAC_TXMAC_DEBUG3_QUANTA_COUNTER		 (0x1fL<<13)
+
+#define BNX2_EMAC_TXMAC_DEBUG4				0x00001668
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_COUNTER		 (0xffffL<<0)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE		 (0xfL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_IDLE		 (0x0L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA1		 (0x2L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA2		 (0x3L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_MCA3		 (0x6L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC1		 (0x7L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC2		 (0x5L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_SRC3		 (0x4L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_TYPE		 (0xcL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CMD		 (0xeL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_TIME		 (0xaL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CRC1		 (0x8L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_CRC2		 (0x9L<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_PAUSE_STATE_WAIT		 (0xdL<<16)
+#define BNX2_EMAC_TXMAC_DEBUG4_STATS0_VALID		 (1L<<20)
+#define BNX2_EMAC_TXMAC_DEBUG4_APPEND_CRC		 (1L<<21)
+#define BNX2_EMAC_TXMAC_DEBUG4_SLOT_FILLED		 (1L<<22)
+#define BNX2_EMAC_TXMAC_DEBUG4_MAX_DEFER		 (1L<<23)
+#define BNX2_EMAC_TXMAC_DEBUG4_SEND_EXTEND		 (1L<<24)
+#define BNX2_EMAC_TXMAC_DEBUG4_SEND_PADDING		 (1L<<25)
+#define BNX2_EMAC_TXMAC_DEBUG4_EOF_LOC			 (1L<<26)
+#define BNX2_EMAC_TXMAC_DEBUG4_COLLIDING		 (1L<<27)
+#define BNX2_EMAC_TXMAC_DEBUG4_COL_IN			 (1L<<28)
+#define BNX2_EMAC_TXMAC_DEBUG4_BURSTING			 (1L<<29)
+#define BNX2_EMAC_TXMAC_DEBUG4_ADVANCE			 (1L<<30)
+#define BNX2_EMAC_TXMAC_DEBUG4_GO			 (1L<<31)
+
+#define BNX2_EMAC_TX_STAT_AC0				0x00001680
+#define BNX2_EMAC_TX_STAT_AC1				0x00001684
+#define BNX2_EMAC_TX_STAT_AC2				0x00001688
+#define BNX2_EMAC_TX_STAT_AC3				0x0000168c
+#define BNX2_EMAC_TX_STAT_AC4				0x00001690
+#define BNX2_EMAC_TX_STAT_AC5				0x00001694
+#define BNX2_EMAC_TX_STAT_AC6				0x00001698
+#define BNX2_EMAC_TX_STAT_AC7				0x0000169c
+#define BNX2_EMAC_TX_STAT_AC8				0x000016a0
+#define BNX2_EMAC_TX_STAT_AC9				0x000016a4
+#define BNX2_EMAC_TX_STAT_AC10				0x000016a8
+#define BNX2_EMAC_TX_STAT_AC11				0x000016ac
+#define BNX2_EMAC_TX_STAT_AC12				0x000016b0
+#define BNX2_EMAC_TX_STAT_AC13				0x000016b4
+#define BNX2_EMAC_TX_STAT_AC14				0x000016b8
+#define BNX2_EMAC_TX_STAT_AC15				0x000016bc
+#define BNX2_EMAC_TX_STAT_AC16				0x000016c0
+#define BNX2_EMAC_TX_STAT_AC17				0x000016c4
+#define BNX2_EMAC_TX_STAT_AC18				0x000016c8
+#define BNX2_EMAC_TX_STAT_AC19				0x000016cc
+#define BNX2_EMAC_TX_STAT_AC20				0x000016d0
+#define BNX2_EMAC_TX_STAT_AC21				0x000016d4
+#define BNX2_EMAC_TXMAC_SUC_DBG_OVERRUNVEC		0x000016d8
+
+
+/*
+ *  rpm_reg definition
+ *  offset: 0x1800
+ */
+#define BNX2_RPM_COMMAND				0x00001800
+#define BNX2_RPM_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RPM_COMMAND_OVERRUN_ABORT			 (1L<<4)
+
+#define BNX2_RPM_STATUS					0x00001804
+#define BNX2_RPM_STATUS_MBUF_WAIT			 (1L<<0)
+#define BNX2_RPM_STATUS_FREE_WAIT			 (1L<<1)
+
+#define BNX2_RPM_CONFIG					0x00001808
+#define BNX2_RPM_CONFIG_NO_PSD_HDR_CKSUM		 (1L<<0)
+#define BNX2_RPM_CONFIG_ACPI_ENA			 (1L<<1)
+#define BNX2_RPM_CONFIG_ACPI_KEEP			 (1L<<2)
+#define BNX2_RPM_CONFIG_MP_KEEP				 (1L<<3)
+#define BNX2_RPM_CONFIG_SORT_VECT_VAL			 (0xfL<<4)
+#define BNX2_RPM_CONFIG_IGNORE_VLAN			 (1L<<31)
+
+#define BNX2_RPM_VLAN_MATCH0				0x00001810
+#define BNX2_RPM_VLAN_MATCH0_RPM_VLAN_MTCH0_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH1				0x00001814
+#define BNX2_RPM_VLAN_MATCH1_RPM_VLAN_MTCH1_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH2				0x00001818
+#define BNX2_RPM_VLAN_MATCH2_RPM_VLAN_MTCH2_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_VLAN_MATCH3				0x0000181c
+#define BNX2_RPM_VLAN_MATCH3_RPM_VLAN_MTCH3_VALUE	 (0xfffL<<0)
+
+#define BNX2_RPM_SORT_USER0				0x00001820
+#define BNX2_RPM_SORT_USER0_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER0_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER0_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER0_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER0_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER0_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER0_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER0_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER1				0x00001824
+#define BNX2_RPM_SORT_USER1_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER1_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER1_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER1_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER1_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER1_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER1_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER1_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER2				0x00001828
+#define BNX2_RPM_SORT_USER2_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER2_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER2_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER2_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER2_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER2_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER2_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER2_ENA				 (1L<<31)
+
+#define BNX2_RPM_SORT_USER3				0x0000182c
+#define BNX2_RPM_SORT_USER3_PM_EN			 (0xffffL<<0)
+#define BNX2_RPM_SORT_USER3_BC_EN			 (1L<<16)
+#define BNX2_RPM_SORT_USER3_MC_EN			 (1L<<17)
+#define BNX2_RPM_SORT_USER3_MC_HSH_EN			 (1L<<18)
+#define BNX2_RPM_SORT_USER3_PROM_EN			 (1L<<19)
+#define BNX2_RPM_SORT_USER3_VLAN_EN			 (0xfL<<20)
+#define BNX2_RPM_SORT_USER3_PROM_VLAN			 (1L<<24)
+#define BNX2_RPM_SORT_USER3_ENA				 (1L<<31)
+
+#define BNX2_RPM_STAT_L2_FILTER_DISCARDS		0x00001840
+#define BNX2_RPM_STAT_RULE_CHECKER_DISCARDS		0x00001844
+#define BNX2_RPM_STAT_IFINFTQDISCARDS			0x00001848
+#define BNX2_RPM_STAT_IFINMBUFDISCARD			0x0000184c
+#define BNX2_RPM_STAT_RULE_CHECKER_P4_HIT		0x00001850
+#define BNX2_RPM_STAT_AC0				0x00001880
+#define BNX2_RPM_STAT_AC1				0x00001884
+#define BNX2_RPM_STAT_AC2				0x00001888
+#define BNX2_RPM_STAT_AC3				0x0000188c
+#define BNX2_RPM_STAT_AC4				0x00001890
+#define BNX2_RPM_RC_CNTL_0				0x00001900
+#define BNX2_RPM_RC_CNTL_0_OFFSET			 (0xffL<<0)
+#define BNX2_RPM_RC_CNTL_0_CLASS			 (0x7L<<8)
+#define BNX2_RPM_RC_CNTL_0_PRIORITY			 (1L<<11)
+#define BNX2_RPM_RC_CNTL_0_P4				 (1L<<12)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE			 (0x7L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_START		 (0L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_IP			 (1L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_TCP			 (2L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_UDP			 (3L<<13)
+#define BNX2_RPM_RC_CNTL_0_HDR_TYPE_DATA		 (4L<<13)
+#define BNX2_RPM_RC_CNTL_0_COMP				 (0x3L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_EQUAL			 (0L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_NEQUAL			 (1L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_GREATER			 (2L<<16)
+#define BNX2_RPM_RC_CNTL_0_COMP_LESS			 (3L<<16)
+#define BNX2_RPM_RC_CNTL_0_SBIT				 (1L<<19)
+#define BNX2_RPM_RC_CNTL_0_CMDSEL			 (0xfL<<20)
+#define BNX2_RPM_RC_CNTL_0_MAP				 (1L<<24)
+#define BNX2_RPM_RC_CNTL_0_DISCARD			 (1L<<25)
+#define BNX2_RPM_RC_CNTL_0_MASK				 (1L<<26)
+#define BNX2_RPM_RC_CNTL_0_P1				 (1L<<27)
+#define BNX2_RPM_RC_CNTL_0_P2				 (1L<<28)
+#define BNX2_RPM_RC_CNTL_0_P3				 (1L<<29)
+#define BNX2_RPM_RC_CNTL_0_NBIT				 (1L<<30)
+
+#define BNX2_RPM_RC_VALUE_MASK_0			0x00001904
+#define BNX2_RPM_RC_VALUE_MASK_0_VALUE			 (0xffffL<<0)
+#define BNX2_RPM_RC_VALUE_MASK_0_MASK			 (0xffffL<<16)
+
+#define BNX2_RPM_RC_CNTL_1				0x00001908
+#define BNX2_RPM_RC_CNTL_1_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_1_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_1			0x0000190c
+#define BNX2_RPM_RC_CNTL_2				0x00001910
+#define BNX2_RPM_RC_CNTL_2_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_2_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_2			0x00001914
+#define BNX2_RPM_RC_CNTL_3				0x00001918
+#define BNX2_RPM_RC_CNTL_3_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_3_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_3			0x0000191c
+#define BNX2_RPM_RC_CNTL_4				0x00001920
+#define BNX2_RPM_RC_CNTL_4_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_4_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_4			0x00001924
+#define BNX2_RPM_RC_CNTL_5				0x00001928
+#define BNX2_RPM_RC_CNTL_5_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_5_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_5			0x0000192c
+#define BNX2_RPM_RC_CNTL_6				0x00001930
+#define BNX2_RPM_RC_CNTL_6_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_6_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_6			0x00001934
+#define BNX2_RPM_RC_CNTL_7				0x00001938
+#define BNX2_RPM_RC_CNTL_7_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_7_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_7			0x0000193c
+#define BNX2_RPM_RC_CNTL_8				0x00001940
+#define BNX2_RPM_RC_CNTL_8_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_8_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_8			0x00001944
+#define BNX2_RPM_RC_CNTL_9				0x00001948
+#define BNX2_RPM_RC_CNTL_9_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_9_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_9			0x0000194c
+#define BNX2_RPM_RC_CNTL_10				0x00001950
+#define BNX2_RPM_RC_CNTL_10_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_10_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_10			0x00001954
+#define BNX2_RPM_RC_CNTL_11				0x00001958
+#define BNX2_RPM_RC_CNTL_11_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_11_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_11			0x0000195c
+#define BNX2_RPM_RC_CNTL_12				0x00001960
+#define BNX2_RPM_RC_CNTL_12_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_12_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_12			0x00001964
+#define BNX2_RPM_RC_CNTL_13				0x00001968
+#define BNX2_RPM_RC_CNTL_13_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_13_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_13			0x0000196c
+#define BNX2_RPM_RC_CNTL_14				0x00001970
+#define BNX2_RPM_RC_CNTL_14_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_14_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_14			0x00001974
+#define BNX2_RPM_RC_CNTL_15				0x00001978
+#define BNX2_RPM_RC_CNTL_15_A				 (0x3ffffL<<0)
+#define BNX2_RPM_RC_CNTL_15_B				 (0xfffL<<19)
+
+#define BNX2_RPM_RC_VALUE_MASK_15			0x0000197c
+#define BNX2_RPM_RC_CONFIG				0x00001980
+#define BNX2_RPM_RC_CONFIG_RULE_ENABLE			 (0xffffL<<0)
+#define BNX2_RPM_RC_CONFIG_DEF_CLASS			 (0x7L<<24)
+
+#define BNX2_RPM_DEBUG0					0x00001984
+#define BNX2_RPM_DEBUG0_FM_BCNT				 (0xffffL<<0)
+#define BNX2_RPM_DEBUG0_T_DATA_OFST_VLD			 (1L<<16)
+#define BNX2_RPM_DEBUG0_T_UDP_OFST_VLD			 (1L<<17)
+#define BNX2_RPM_DEBUG0_T_TCP_OFST_VLD			 (1L<<18)
+#define BNX2_RPM_DEBUG0_T_IP_OFST_VLD			 (1L<<19)
+#define BNX2_RPM_DEBUG0_IP_MORE_FRGMT			 (1L<<20)
+#define BNX2_RPM_DEBUG0_T_IP_NO_TCP_UDP_HDR		 (1L<<21)
+#define BNX2_RPM_DEBUG0_LLC_SNAP			 (1L<<22)
+#define BNX2_RPM_DEBUG0_FM_STARTED			 (1L<<23)
+#define BNX2_RPM_DEBUG0_DONE				 (1L<<24)
+#define BNX2_RPM_DEBUG0_WAIT_4_DONE			 (1L<<25)
+#define BNX2_RPM_DEBUG0_USE_TPBUF_CKSUM			 (1L<<26)
+#define BNX2_RPM_DEBUG0_RX_NO_PSD_HDR_CKSUM		 (1L<<27)
+#define BNX2_RPM_DEBUG0_IGNORE_VLAN			 (1L<<28)
+#define BNX2_RPM_DEBUG0_RP_ENA_ACTIVE			 (1L<<31)
+
+#define BNX2_RPM_DEBUG1					0x00001988
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IDLE			 (0L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B6_ALL		 (1L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B2_IPLLC	 (2L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B6_IP		 (4L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ETYPE_B2_IP		 (8L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IP_START		 (16L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_IP			 (32L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_TCP			 (64L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_UDP			 (128L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_AH			 (256L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ESP			 (512L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ESP_PAYLOAD		 (1024L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_DATA			 (2048L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ADD_CARRY		 (0x2000L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_ADD_CARRYOUT		 (0x4000L<<0)
+#define BNX2_RPM_DEBUG1_FSM_CUR_ST_LATCH_RESULT		 (0x8000L<<0)
+#define BNX2_RPM_DEBUG1_HDR_BCNT			 (0x7ffL<<16)
+#define BNX2_RPM_DEBUG1_UNKNOWN_ETYPE_D			 (1L<<28)
+#define BNX2_RPM_DEBUG1_VLAN_REMOVED_D2			 (1L<<29)
+#define BNX2_RPM_DEBUG1_VLAN_REMOVED_D1			 (1L<<30)
+#define BNX2_RPM_DEBUG1_EOF_0XTRA_WD			 (1L<<31)
+
+#define BNX2_RPM_DEBUG2					0x0000198c
+#define BNX2_RPM_DEBUG2_CMD_HIT_VEC			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG2_IP_BCNT				 (0xffL<<16)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M4			 (1L<<24)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M3			 (1L<<25)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M2			 (1L<<26)
+#define BNX2_RPM_DEBUG2_THIS_CMD_M1			 (1L<<27)
+#define BNX2_RPM_DEBUG2_IPIPE_EMPTY			 (1L<<28)
+#define BNX2_RPM_DEBUG2_FM_DISCARD			 (1L<<29)
+#define BNX2_RPM_DEBUG2_LAST_RULE_IN_FM_D2		 (1L<<30)
+#define BNX2_RPM_DEBUG2_LAST_RULE_IN_FM_D1		 (1L<<31)
+
+#define BNX2_RPM_DEBUG3					0x00001990
+#define BNX2_RPM_DEBUG3_AVAIL_MBUF_PTR			 (0x1ffL<<0)
+#define BNX2_RPM_DEBUG3_RDE_RLUPQ_WR_REQ_INT		 (1L<<9)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_WR_LAST_INT		 (1L<<10)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_WR_REQ_INT		 (1L<<11)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_FREE_REQ		 (1L<<12)
+#define BNX2_RPM_DEBUG3_RDE_RBUF_ALLOC_REQ		 (1L<<13)
+#define BNX2_RPM_DEBUG3_DFSM_MBUF_NOTAVAIL		 (1L<<14)
+#define BNX2_RPM_DEBUG3_RBUF_RDE_SOF_DROP		 (1L<<15)
+#define BNX2_RPM_DEBUG3_DFIFO_VLD_ENTRY_CT		 (0xfL<<16)
+#define BNX2_RPM_DEBUG3_RDE_SRC_FIFO_ALMFULL		 (1L<<21)
+#define BNX2_RPM_DEBUG3_DROP_NXT_VLD			 (1L<<22)
+#define BNX2_RPM_DEBUG3_DROP_NXT			 (1L<<23)
+#define BNX2_RPM_DEBUG3_FTQ_FSM				 (0x3L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_IDLE			 (0x0L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_WAIT_ACK		 (0x1L<<24)
+#define BNX2_RPM_DEBUG3_FTQ_FSM_WAIT_FREE		 (0x2L<<24)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM			 (0x3L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_SOF		 (0x0L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_GET_MBUF		 (0x1L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_DMA_DATA		 (0x2L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_DATA		 (0x3L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_EOF		 (0x4L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_MF_ACK		 (0x5L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_WAIT_DROP_NXT_VLD	 (0x6L<<26)
+#define BNX2_RPM_DEBUG3_MBWRITE_FSM_DONE		 (0x7L<<26)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM			 (1L<<29)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM_IDLE			 (0L<<29)
+#define BNX2_RPM_DEBUG3_MBFREE_FSM_WAIT_ACK		 (1L<<29)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM			 (1L<<30)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM_ET_MBUF		 (0x0L<<30)
+#define BNX2_RPM_DEBUG3_MBALLOC_FSM_IVE_MBUF		 (0x1L<<30)
+#define BNX2_RPM_DEBUG3_CCODE_EOF_ERROR			 (1L<<31)
+
+#define BNX2_RPM_DEBUG4					0x00001994
+#define BNX2_RPM_DEBUG4_DFSM_MBUF_CLUSTER		 (0x1ffffffL<<0)
+#define BNX2_RPM_DEBUG4_DFIFO_CUR_CCODE			 (0x7L<<25)
+#define BNX2_RPM_DEBUG4_MBWRITE_FSM			 (0x7L<<28)
+#define BNX2_RPM_DEBUG4_DFIFO_EMPTY			 (1L<<31)
+
+#define BNX2_RPM_DEBUG5					0x00001998
+#define BNX2_RPM_DEBUG5_RDROP_WPTR			 (0x1fL<<0)
+#define BNX2_RPM_DEBUG5_RDROP_ACPI_RPTR			 (0x1fL<<5)
+#define BNX2_RPM_DEBUG5_RDROP_MC_RPTR			 (0x1fL<<10)
+#define BNX2_RPM_DEBUG5_RDROP_RC_RPTR			 (0x1fL<<15)
+#define BNX2_RPM_DEBUG5_RDROP_ACPI_EMPTY		 (1L<<20)
+#define BNX2_RPM_DEBUG5_RDROP_MC_EMPTY			 (1L<<21)
+#define BNX2_RPM_DEBUG5_RDROP_AEOF_VEC_AT_RDROP_MC_RPTR	 (1L<<22)
+#define BNX2_RPM_DEBUG5_HOLDREG_WOL_DROP_INT		 (1L<<23)
+#define BNX2_RPM_DEBUG5_HOLDREG_DISCARD			 (1L<<24)
+#define BNX2_RPM_DEBUG5_HOLDREG_MBUF_NOTAVAIL		 (1L<<25)
+#define BNX2_RPM_DEBUG5_HOLDREG_MC_EMPTY		 (1L<<26)
+#define BNX2_RPM_DEBUG5_HOLDREG_RC_EMPTY		 (1L<<27)
+#define BNX2_RPM_DEBUG5_HOLDREG_FC_EMPTY		 (1L<<28)
+#define BNX2_RPM_DEBUG5_HOLDREG_ACPI_EMPTY		 (1L<<29)
+#define BNX2_RPM_DEBUG5_HOLDREG_FULL_T			 (1L<<30)
+#define BNX2_RPM_DEBUG5_HOLDREG_RD			 (1L<<31)
+
+#define BNX2_RPM_DEBUG6					0x0000199c
+#define BNX2_RPM_DEBUG6_ACPI_VEC			 (0xffffL<<0)
+#define BNX2_RPM_DEBUG6_VEC				 (0xffffL<<16)
+
+#define BNX2_RPM_DEBUG7					0x000019a0
+#define BNX2_RPM_DEBUG7_RPM_DBG7_LAST_CRC		 (0xffffffffL<<0)
+
+#define BNX2_RPM_DEBUG8					0x000019a4
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM			 (0xfL<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_IDLE		 (0L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W1_ADDR		 (1L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W2_ADDR		 (2L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_W3_ADDR		 (3L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_SOF_WAIT_THBUF	 (4L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W3_DATA		 (5L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W0_ADDR		 (6L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W1_ADDR		 (7L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W2_ADDR		 (8L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_W3_ADDR		 (9L<<0)
+#define BNX2_RPM_DEBUG8_PS_ACPI_FSM_WAIT_THBUF		 (10L<<0)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_W0			 (1L<<4)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_W3_DATA		 (1L<<5)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_WAIT		 (1L<<6)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_W3		 (1L<<7)
+#define BNX2_RPM_DEBUG8_COMPARE_AT_SOF_W2		 (1L<<8)
+#define BNX2_RPM_DEBUG8_EOF_W_LTEQ6_VLDBYTES		 (1L<<9)
+#define BNX2_RPM_DEBUG8_EOF_W_LTEQ4_VLDBYTES		 (1L<<10)
+#define BNX2_RPM_DEBUG8_NXT_EOF_W_12_VLDBYTES		 (1L<<11)
+#define BNX2_RPM_DEBUG8_EOF_DET				 (1L<<12)
+#define BNX2_RPM_DEBUG8_SOF_DET				 (1L<<13)
+#define BNX2_RPM_DEBUG8_WAIT_4_SOF			 (1L<<14)
+#define BNX2_RPM_DEBUG8_ALL_DONE			 (1L<<15)
+#define BNX2_RPM_DEBUG8_THBUF_ADDR			 (0x7fL<<16)
+#define BNX2_RPM_DEBUG8_BYTE_CTR			 (0xffL<<24)
+
+#define BNX2_RPM_DEBUG9					0x000019a8
+#define BNX2_RPM_DEBUG9_OUTFIFO_COUNT			 (0x7L<<0)
+#define BNX2_RPM_DEBUG9_RDE_ACPI_RDY			 (1L<<3)
+#define BNX2_RPM_DEBUG9_VLD_RD_ENTRY_CT			 (0x7L<<4)
+#define BNX2_RPM_DEBUG9_OUTFIFO_OVERRUN_OCCURRED	 (1L<<28)
+#define BNX2_RPM_DEBUG9_INFIFO_OVERRUN_OCCURRED		 (1L<<29)
+#define BNX2_RPM_DEBUG9_ACPI_MATCH_INT			 (1L<<30)
+#define BNX2_RPM_DEBUG9_ACPI_ENABLE_SYN			 (1L<<31)
+
+#define BNX2_RPM_ACPI_DBG_BUF_W00			0x000019c0
+#define BNX2_RPM_ACPI_DBG_BUF_W01			0x000019c4
+#define BNX2_RPM_ACPI_DBG_BUF_W02			0x000019c8
+#define BNX2_RPM_ACPI_DBG_BUF_W03			0x000019cc
+#define BNX2_RPM_ACPI_DBG_BUF_W10			0x000019d0
+#define BNX2_RPM_ACPI_DBG_BUF_W11			0x000019d4
+#define BNX2_RPM_ACPI_DBG_BUF_W12			0x000019d8
+#define BNX2_RPM_ACPI_DBG_BUF_W13			0x000019dc
+#define BNX2_RPM_ACPI_DBG_BUF_W20			0x000019e0
+#define BNX2_RPM_ACPI_DBG_BUF_W21			0x000019e4
+#define BNX2_RPM_ACPI_DBG_BUF_W22			0x000019e8
+#define BNX2_RPM_ACPI_DBG_BUF_W23			0x000019ec
+#define BNX2_RPM_ACPI_DBG_BUF_W30			0x000019f0
+#define BNX2_RPM_ACPI_DBG_BUF_W31			0x000019f4
+#define BNX2_RPM_ACPI_DBG_BUF_W32			0x000019f8
+#define BNX2_RPM_ACPI_DBG_BUF_W33			0x000019fc
+
+
+/*
+ *  rbuf_reg definition
+ *  offset: 0x200000
+ */
+#define BNX2_RBUF_COMMAND				0x00200000
+#define BNX2_RBUF_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RBUF_COMMAND_FREE_INIT			 (1L<<1)
+#define BNX2_RBUF_COMMAND_RAM_INIT			 (1L<<2)
+#define BNX2_RBUF_COMMAND_OVER_FREE			 (1L<<4)
+#define BNX2_RBUF_COMMAND_ALLOC_REQ			 (1L<<5)
+
+#define BNX2_RBUF_STATUS1				0x00200004
+#define BNX2_RBUF_STATUS1_FREE_COUNT			 (0x3ffL<<0)
+
+#define BNX2_RBUF_STATUS2				0x00200008
+#define BNX2_RBUF_STATUS2_FREE_TAIL			 (0x3ffL<<0)
+#define BNX2_RBUF_STATUS2_FREE_HEAD			 (0x3ffL<<16)
+
+#define BNX2_RBUF_CONFIG				0x0020000c
+#define BNX2_RBUF_CONFIG_XOFF_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG_XON_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_FW_BUF_ALLOC				0x00200010
+#define BNX2_RBUF_FW_BUF_ALLOC_VALUE			 (0x1ffL<<7)
+
+#define BNX2_RBUF_FW_BUF_FREE				0x00200014
+#define BNX2_RBUF_FW_BUF_FREE_COUNT			 (0x7fL<<0)
+#define BNX2_RBUF_FW_BUF_FREE_TAIL			 (0x1ffL<<7)
+#define BNX2_RBUF_FW_BUF_FREE_HEAD			 (0x1ffL<<16)
+
+#define BNX2_RBUF_FW_BUF_SEL				0x00200018
+#define BNX2_RBUF_FW_BUF_SEL_COUNT			 (0x7fL<<0)
+#define BNX2_RBUF_FW_BUF_SEL_TAIL			 (0x1ffL<<7)
+#define BNX2_RBUF_FW_BUF_SEL_HEAD			 (0x1ffL<<16)
+
+#define BNX2_RBUF_CONFIG2				0x0020001c
+#define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_CONFIG3				0x00200020
+#define BNX2_RBUF_CONFIG3_CU_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP			 (0x3ffL<<16)
+
+#define BNX2_RBUF_PKT_DATA				0x00208000
+#define BNX2_RBUF_CLIST_DATA				0x00210000
+#define BNX2_RBUF_BUF_DATA				0x00220000
+
+
+/*
+ *  rv2p_reg definition
+ *  offset: 0x2800
+ */
+#define BNX2_RV2P_COMMAND				0x00002800
+#define BNX2_RV2P_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_RV2P_COMMAND_PROC1_INTRPT			 (1L<<1)
+#define BNX2_RV2P_COMMAND_PROC2_INTRPT			 (1L<<2)
+#define BNX2_RV2P_COMMAND_ABORT0			 (1L<<4)
+#define BNX2_RV2P_COMMAND_ABORT1			 (1L<<5)
+#define BNX2_RV2P_COMMAND_ABORT2			 (1L<<6)
+#define BNX2_RV2P_COMMAND_ABORT3			 (1L<<7)
+#define BNX2_RV2P_COMMAND_ABORT4			 (1L<<8)
+#define BNX2_RV2P_COMMAND_ABORT5			 (1L<<9)
+#define BNX2_RV2P_COMMAND_PROC1_RESET			 (1L<<16)
+#define BNX2_RV2P_COMMAND_PROC2_RESET			 (1L<<17)
+#define BNX2_RV2P_COMMAND_CTXIF_RESET			 (1L<<18)
+
+#define BNX2_RV2P_STATUS				0x00002804
+#define BNX2_RV2P_STATUS_ALWAYS_0			 (1L<<0)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT0_CNT		 (1L<<8)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT1_CNT		 (1L<<9)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT2_CNT		 (1L<<10)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT3_CNT		 (1L<<11)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT4_CNT		 (1L<<12)
+#define BNX2_RV2P_STATUS_RV2P_GEN_STAT5_CNT		 (1L<<13)
+
+#define BNX2_RV2P_CONFIG				0x00002808
+#define BNX2_RV2P_CONFIG_STALL_PROC1			 (1L<<0)
+#define BNX2_RV2P_CONFIG_STALL_PROC2			 (1L<<1)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT0		 (1L<<8)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT1		 (1L<<9)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT2		 (1L<<10)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT3		 (1L<<11)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT4		 (1L<<12)
+#define BNX2_RV2P_CONFIG_PROC1_STALL_ON_ABORT5		 (1L<<13)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT0		 (1L<<16)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT1		 (1L<<17)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT2		 (1L<<18)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT3		 (1L<<19)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT4		 (1L<<20)
+#define BNX2_RV2P_CONFIG_PROC2_STALL_ON_ABORT5		 (1L<<21)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE			 (0xfL<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_256			 (0L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_512			 (1L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_1K			 (2L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_2K			 (3L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_4K			 (4L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_8K			 (5L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_16K			 (6L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_32K			 (7L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_64K			 (8L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_128K			 (9L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_256K			 (10L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_512K			 (11L<<24)
+#define BNX2_RV2P_CONFIG_PAGE_SIZE_1M			 (12L<<24)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_0			0x00002810
+#define BNX2_RV2P_GEN_BFR_ADDR_0_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_1			0x00002814
+#define BNX2_RV2P_GEN_BFR_ADDR_1_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_2			0x00002818
+#define BNX2_RV2P_GEN_BFR_ADDR_2_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_GEN_BFR_ADDR_3			0x0000281c
+#define BNX2_RV2P_GEN_BFR_ADDR_3_VALUE			 (0xffffL<<16)
+
+#define BNX2_RV2P_INSTR_HIGH				0x00002830
+#define BNX2_RV2P_INSTR_HIGH_HIGH			 (0x1fL<<0)
+
+#define BNX2_RV2P_INSTR_LOW				0x00002834
+#define BNX2_RV2P_PROC1_ADDR_CMD			0x00002838
+#define BNX2_RV2P_PROC1_ADDR_CMD_ADD			 (0x3ffL<<0)
+#define BNX2_RV2P_PROC1_ADDR_CMD_RDWR			 (1L<<31)
+
+#define BNX2_RV2P_PROC2_ADDR_CMD			0x0000283c
+#define BNX2_RV2P_PROC2_ADDR_CMD_ADD			 (0x3ffL<<0)
+#define BNX2_RV2P_PROC2_ADDR_CMD_RDWR			 (1L<<31)
+
+#define BNX2_RV2P_PROC1_GRC_DEBUG			0x00002840
+#define BNX2_RV2P_PROC2_GRC_DEBUG			0x00002844
+#define BNX2_RV2P_GRC_PROC_DEBUG			0x00002848
+#define BNX2_RV2P_DEBUG_VECT_PEEK			0x0000284c
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_RV2P_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+#define BNX2_RV2P_PFTQ_DATA				0x00002b40
+#define BNX2_RV2P_PFTQ_CMD				0x00002b78
+#define BNX2_RV2P_PFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_PFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_PFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_PFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_PFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_PFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_PFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_PFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_PFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_PFTQ_CTL				0x00002b7c
+#define BNX2_RV2P_PFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_PFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_PFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_PFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_PFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RV2P_TFTQ_DATA				0x00002b80
+#define BNX2_RV2P_TFTQ_CMD				0x00002bb8
+#define BNX2_RV2P_TFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_TFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_TFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_TFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_TFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_TFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_TFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_TFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_TFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_TFTQ_CTL				0x00002bbc
+#define BNX2_RV2P_TFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_TFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_TFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_TFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_TFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RV2P_MFTQ_DATA				0x00002bc0
+#define BNX2_RV2P_MFTQ_CMD				0x00002bf8
+#define BNX2_RV2P_MFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RV2P_MFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RV2P_MFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RV2P_MFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RV2P_MFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RV2P_MFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RV2P_MFTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_RV2P_MFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RV2P_MFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RV2P_MFTQ_CTL				0x00002bfc
+#define BNX2_RV2P_MFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RV2P_MFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RV2P_MFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RV2P_MFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RV2P_MFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  mq_reg definition
+ *  offset: 0x3c00
+ */
+#define BNX2_MQ_COMMAND					0x00003c00
+#define BNX2_MQ_COMMAND_ENABLED				 (1L<<0)
+#define BNX2_MQ_COMMAND_OVERFLOW			 (1L<<4)
+#define BNX2_MQ_COMMAND_WR_ERROR			 (1L<<5)
+#define BNX2_MQ_COMMAND_RD_ERROR			 (1L<<6)
+
+#define BNX2_MQ_STATUS					0x00003c04
+#define BNX2_MQ_STATUS_CTX_ACCESS_STAT			 (1L<<16)
+#define BNX2_MQ_STATUS_CTX_ACCESS64_STAT		 (1L<<17)
+#define BNX2_MQ_STATUS_PCI_STALL_STAT			 (1L<<18)
+
+#define BNX2_MQ_CONFIG					0x00003c08
+#define BNX2_MQ_CONFIG_TX_HIGH_PRI			 (1L<<0)
+#define BNX2_MQ_CONFIG_HALT_DIS				 (1L<<1)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE			 (0x7L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256		 (0L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_512		 (1L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_1K		 (2L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_2K		 (3L<<4)
+#define BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_4K		 (4L<<4)
+#define BNX2_MQ_CONFIG_MAX_DEPTH			 (0x7fL<<8)
+#define BNX2_MQ_CONFIG_CUR_DEPTH			 (0x7fL<<20)
+
+#define BNX2_MQ_ENQUEUE1				0x00003c0c
+#define BNX2_MQ_ENQUEUE1_OFFSET				 (0x3fL<<2)
+#define BNX2_MQ_ENQUEUE1_CID				 (0x3fffL<<8)
+#define BNX2_MQ_ENQUEUE1_BYTE_MASK			 (0xfL<<24)
+#define BNX2_MQ_ENQUEUE1_KNL_MODE			 (1L<<28)
+
+#define BNX2_MQ_ENQUEUE2				0x00003c10
+#define BNX2_MQ_BAD_WR_ADDR				0x00003c14
+#define BNX2_MQ_BAD_RD_ADDR				0x00003c18
+#define BNX2_MQ_KNL_BYP_WIND_START			0x00003c1c
+#define BNX2_MQ_KNL_BYP_WIND_START_VALUE		 (0xfffffL<<12)
+
+#define BNX2_MQ_KNL_WIND_END				0x00003c20
+#define BNX2_MQ_KNL_WIND_END_VALUE			 (0xffffffL<<8)
+
+#define BNX2_MQ_KNL_WRITE_MASK1				0x00003c24
+#define BNX2_MQ_KNL_TX_MASK1				0x00003c28
+#define BNX2_MQ_KNL_CMD_MASK1				0x00003c2c
+#define BNX2_MQ_KNL_COND_ENQUEUE_MASK1			0x00003c30
+#define BNX2_MQ_KNL_RX_V2P_MASK1			0x00003c34
+#define BNX2_MQ_KNL_WRITE_MASK2				0x00003c38
+#define BNX2_MQ_KNL_TX_MASK2				0x00003c3c
+#define BNX2_MQ_KNL_CMD_MASK2				0x00003c40
+#define BNX2_MQ_KNL_COND_ENQUEUE_MASK2			0x00003c44
+#define BNX2_MQ_KNL_RX_V2P_MASK2			0x00003c48
+#define BNX2_MQ_KNL_BYP_WRITE_MASK1			0x00003c4c
+#define BNX2_MQ_KNL_BYP_TX_MASK1			0x00003c50
+#define BNX2_MQ_KNL_BYP_CMD_MASK1			0x00003c54
+#define BNX2_MQ_KNL_BYP_COND_ENQUEUE_MASK1		0x00003c58
+#define BNX2_MQ_KNL_BYP_RX_V2P_MASK1			0x00003c5c
+#define BNX2_MQ_KNL_BYP_WRITE_MASK2			0x00003c60
+#define BNX2_MQ_KNL_BYP_TX_MASK2			0x00003c64
+#define BNX2_MQ_KNL_BYP_CMD_MASK2			0x00003c68
+#define BNX2_MQ_KNL_BYP_COND_ENQUEUE_MASK2		0x00003c6c
+#define BNX2_MQ_KNL_BYP_RX_V2P_MASK2			0x00003c70
+#define BNX2_MQ_MEM_WR_ADDR				0x00003c74
+#define BNX2_MQ_MEM_WR_ADDR_VALUE			 (0x3fL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA0				0x00003c78
+#define BNX2_MQ_MEM_WR_DATA0_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA1				0x00003c7c
+#define BNX2_MQ_MEM_WR_DATA1_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_WR_DATA2				0x00003c80
+#define BNX2_MQ_MEM_WR_DATA2_VALUE			 (0x3fffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_ADDR				0x00003c84
+#define BNX2_MQ_MEM_RD_ADDR_VALUE			 (0x3fL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA0				0x00003c88
+#define BNX2_MQ_MEM_RD_DATA0_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA1				0x00003c8c
+#define BNX2_MQ_MEM_RD_DATA1_VALUE			 (0xffffffffL<<0)
+
+#define BNX2_MQ_MEM_RD_DATA2				0x00003c90
+#define BNX2_MQ_MEM_RD_DATA2_VALUE			 (0x3fffffffL<<0)
+
+
+
+/*
+ *  tbdr_reg definition
+ *  offset: 0x5000
+ */
+#define BNX2_TBDR_COMMAND				0x00005000
+#define BNX2_TBDR_COMMAND_ENABLE			 (1L<<0)
+#define BNX2_TBDR_COMMAND_SOFT_RST			 (1L<<1)
+#define BNX2_TBDR_COMMAND_MSTR_ABORT			 (1L<<4)
+
+#define BNX2_TBDR_STATUS				0x00005004
+#define BNX2_TBDR_STATUS_DMA_WAIT			 (1L<<0)
+#define BNX2_TBDR_STATUS_FTQ_WAIT			 (1L<<1)
+#define BNX2_TBDR_STATUS_FIFO_OVERFLOW			 (1L<<2)
+#define BNX2_TBDR_STATUS_FIFO_UNDERFLOW			 (1L<<3)
+#define BNX2_TBDR_STATUS_SEARCHMISS_ERROR		 (1L<<4)
+#define BNX2_TBDR_STATUS_FTQ_ENTRY_CNT			 (1L<<5)
+#define BNX2_TBDR_STATUS_BURST_CNT			 (1L<<6)
+
+#define BNX2_TBDR_CONFIG				0x00005008
+#define BNX2_TBDR_CONFIG_MAX_BDS			 (0xffL<<0)
+#define BNX2_TBDR_CONFIG_SWAP_MODE			 (1L<<8)
+#define BNX2_TBDR_CONFIG_PRIORITY			 (1L<<9)
+#define BNX2_TBDR_CONFIG_CACHE_NEXT_PAGE_PTRS		 (1L<<10)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE			 (0xfL<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_256			 (0L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_512			 (1L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_1K			 (2L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_2K			 (3L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_4K			 (4L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_8K			 (5L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_16K			 (6L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_32K			 (7L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_64K			 (8L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_128K			 (9L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_256K			 (10L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_512K			 (11L<<24)
+#define BNX2_TBDR_CONFIG_PAGE_SIZE_1M			 (12L<<24)
+
+#define BNX2_TBDR_DEBUG_VECT_PEEK			0x0000500c
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TBDR_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+#define BNX2_TBDR_FTQ_DATA				0x000053c0
+#define BNX2_TBDR_FTQ_CMD				0x000053f8
+#define BNX2_TBDR_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TBDR_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TBDR_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TBDR_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TBDR_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TBDR_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TBDR_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TBDR_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TBDR_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TBDR_FTQ_CTL				0x000053fc
+#define BNX2_TBDR_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TBDR_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TBDR_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TBDR_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TBDR_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  tdma_reg definition
+ *  offset: 0x5c00
+ */
+#define BNX2_TDMA_COMMAND				0x00005c00
+#define BNX2_TDMA_COMMAND_ENABLED			 (1L<<0)
+#define BNX2_TDMA_COMMAND_MASTER_ABORT			 (1L<<4)
+#define BNX2_TDMA_COMMAND_BAD_L2_LENGTH_ABORT		 (1L<<7)
+
+#define BNX2_TDMA_STATUS				0x00005c04
+#define BNX2_TDMA_STATUS_DMA_WAIT			 (1L<<0)
+#define BNX2_TDMA_STATUS_PAYLOAD_WAIT			 (1L<<1)
+#define BNX2_TDMA_STATUS_PATCH_FTQ_WAIT			 (1L<<2)
+#define BNX2_TDMA_STATUS_LOCK_WAIT			 (1L<<3)
+#define BNX2_TDMA_STATUS_FTQ_ENTRY_CNT			 (1L<<16)
+#define BNX2_TDMA_STATUS_BURST_CNT			 (1L<<17)
+
+#define BNX2_TDMA_CONFIG				0x00005c08
+#define BNX2_TDMA_CONFIG_ONE_DMA			 (1L<<0)
+#define BNX2_TDMA_CONFIG_ONE_RECORD			 (1L<<1)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ			 (0xfL<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_64			 (0L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_128			 (0x4L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_256			 (0x6L<<4)
+#define BNX2_TDMA_CONFIG_LIMIT_SZ_512			 (0x8L<<4)
+#define BNX2_TDMA_CONFIG_LINE_SZ			 (0xfL<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_64			 (0L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_128			 (4L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_256			 (6L<<8)
+#define BNX2_TDMA_CONFIG_LINE_SZ_512			 (8L<<8)
+#define BNX2_TDMA_CONFIG_ALIGN_ENA			 (1L<<15)
+#define BNX2_TDMA_CONFIG_CHK_L2_BD			 (1L<<16)
+#define BNX2_TDMA_CONFIG_FIFO_CMP			 (0xfL<<20)
+
+#define BNX2_TDMA_PAYLOAD_PROD				0x00005c0c
+#define BNX2_TDMA_PAYLOAD_PROD_VALUE			 (0x1fffL<<3)
+
+#define BNX2_TDMA_DBG_WATCHDOG				0x00005c10
+#define BNX2_TDMA_DBG_TRIGGER				0x00005c14
+#define BNX2_TDMA_DMAD_FSM				0x00005c80
+#define BNX2_TDMA_DMAD_FSM_BD_INVLD			 (1L<<0)
+#define BNX2_TDMA_DMAD_FSM_PUSH				 (0xfL<<4)
+#define BNX2_TDMA_DMAD_FSM_ARB_TBDC			 (0x3L<<8)
+#define BNX2_TDMA_DMAD_FSM_ARB_CTX			 (1L<<12)
+#define BNX2_TDMA_DMAD_FSM_DR_INTF			 (1L<<16)
+#define BNX2_TDMA_DMAD_FSM_DMAD				 (0x7L<<20)
+#define BNX2_TDMA_DMAD_FSM_BD				 (0xfL<<24)
+
+#define BNX2_TDMA_DMAD_STATUS				0x00005c84
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_PUSH_ENTRY		 (0x3L<<0)
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_DMAD_ENTRY		 (0x3L<<4)
+#define BNX2_TDMA_DMAD_STATUS_RHOLD_BD_ENTRY		 (0x3L<<8)
+#define BNX2_TDMA_DMAD_STATUS_IFTQ_ENUM			 (0xfL<<12)
+
+#define BNX2_TDMA_DR_INTF_FSM				0x00005c88
+#define BNX2_TDMA_DR_INTF_FSM_L2_COMP			 (0x3L<<0)
+#define BNX2_TDMA_DR_INTF_FSM_TPATQ			 (0x7L<<4)
+#define BNX2_TDMA_DR_INTF_FSM_TPBUF			 (0x3L<<8)
+#define BNX2_TDMA_DR_INTF_FSM_DR_BUF			 (0x7L<<12)
+#define BNX2_TDMA_DR_INTF_FSM_DMAD			 (0x7L<<16)
+
+#define BNX2_TDMA_DR_INTF_STATUS			0x00005c8c
+#define BNX2_TDMA_DR_INTF_STATUS_HOLE_PHASE		 (0x7L<<0)
+#define BNX2_TDMA_DR_INTF_STATUS_DATA_AVAIL		 (0x3L<<4)
+#define BNX2_TDMA_DR_INTF_STATUS_SHIFT_ADDR		 (0x7L<<8)
+#define BNX2_TDMA_DR_INTF_STATUS_NXT_PNTR		 (0xfL<<12)
+#define BNX2_TDMA_DR_INTF_STATUS_BYTE_COUNT		 (0x7L<<16)
+
+#define BNX2_TDMA_FTQ_DATA				0x00005fc0
+#define BNX2_TDMA_FTQ_CMD				0x00005ff8
+#define BNX2_TDMA_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TDMA_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TDMA_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TDMA_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TDMA_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TDMA_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TDMA_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TDMA_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TDMA_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TDMA_FTQ_CTL				0x00005ffc
+#define BNX2_TDMA_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TDMA_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TDMA_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TDMA_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TDMA_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+
+
+/*
+ *  hc_reg definition
+ *  offset: 0x6800
+ */
+#define BNX2_HC_COMMAND					0x00006800
+#define BNX2_HC_COMMAND_ENABLE				 (1L<<0)
+#define BNX2_HC_COMMAND_SKIP_ABORT			 (1L<<4)
+#define BNX2_HC_COMMAND_COAL_NOW			 (1L<<16)
+#define BNX2_HC_COMMAND_COAL_NOW_WO_INT			 (1L<<17)
+#define BNX2_HC_COMMAND_STATS_NOW			 (1L<<18)
+#define BNX2_HC_COMMAND_FORCE_INT			 (0x3L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_NULL			 (0L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_HIGH			 (1L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_LOW			 (2L<<19)
+#define BNX2_HC_COMMAND_FORCE_INT_FREE			 (3L<<19)
+#define BNX2_HC_COMMAND_CLR_STAT_NOW			 (1L<<21)
+
+#define BNX2_HC_STATUS					0x00006804
+#define BNX2_HC_STATUS_MASTER_ABORT			 (1L<<0)
+#define BNX2_HC_STATUS_PARITY_ERROR_STATE		 (1L<<1)
+#define BNX2_HC_STATUS_PCI_CLK_CNT_STAT			 (1L<<16)
+#define BNX2_HC_STATUS_CORE_CLK_CNT_STAT		 (1L<<17)
+#define BNX2_HC_STATUS_NUM_STATUS_BLOCKS_STAT		 (1L<<18)
+#define BNX2_HC_STATUS_NUM_INT_GEN_STAT			 (1L<<19)
+#define BNX2_HC_STATUS_NUM_INT_MBOX_WR_STAT		 (1L<<20)
+#define BNX2_HC_STATUS_CORE_CLKS_TO_HW_INTACK_STAT	 (1L<<23)
+#define BNX2_HC_STATUS_CORE_CLKS_TO_SW_INTACK_STAT	 (1L<<24)
+#define BNX2_HC_STATUS_CORE_CLKS_DURING_SW_INTACK_STAT	 (1L<<25)
+
+#define BNX2_HC_CONFIG					0x00006808
+#define BNX2_HC_CONFIG_COLLECT_STATS			 (1L<<0)
+#define BNX2_HC_CONFIG_RX_TMR_MODE			 (1L<<1)
+#define BNX2_HC_CONFIG_TX_TMR_MODE			 (1L<<2)
+#define BNX2_HC_CONFIG_COM_TMR_MODE			 (1L<<3)
+#define BNX2_HC_CONFIG_CMD_TMR_MODE			 (1L<<4)
+#define BNX2_HC_CONFIG_STATISTIC_PRIORITY		 (1L<<5)
+#define BNX2_HC_CONFIG_STATUS_PRIORITY			 (1L<<6)
+#define BNX2_HC_CONFIG_STAT_MEM_ADDR			 (0xffL<<8)
+
+#define BNX2_HC_ATTN_BITS_ENABLE			0x0000680c
+#define BNX2_HC_STATUS_ADDR_L				0x00006810
+#define BNX2_HC_STATUS_ADDR_H				0x00006814
+#define BNX2_HC_STATISTICS_ADDR_L			0x00006818
+#define BNX2_HC_STATISTICS_ADDR_H			0x0000681c
+#define BNX2_HC_TX_QUICK_CONS_TRIP			0x00006820
+#define BNX2_HC_TX_QUICK_CONS_TRIP_VALUE		 (0xffL<<0)
+#define BNX2_HC_TX_QUICK_CONS_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_COMP_PROD_TRIP				0x00006824
+#define BNX2_HC_COMP_PROD_TRIP_VALUE			 (0xffL<<0)
+#define BNX2_HC_COMP_PROD_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_RX_QUICK_CONS_TRIP			0x00006828
+#define BNX2_HC_RX_QUICK_CONS_TRIP_VALUE		 (0xffL<<0)
+#define BNX2_HC_RX_QUICK_CONS_TRIP_INT			 (0xffL<<16)
+
+#define BNX2_HC_RX_TICKS				0x0000682c
+#define BNX2_HC_RX_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_RX_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_TX_TICKS				0x00006830
+#define BNX2_HC_TX_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_TX_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_COM_TICKS				0x00006834
+#define BNX2_HC_COM_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_COM_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_CMD_TICKS				0x00006838
+#define BNX2_HC_CMD_TICKS_VALUE				 (0x3ffL<<0)
+#define BNX2_HC_CMD_TICKS_INT				 (0x3ffL<<16)
+
+#define BNX2_HC_PERIODIC_TICKS				0x0000683c
+#define BNX2_HC_PERIODIC_TICKS_HC_PERIODIC_TICKS	 (0xffffL<<0)
+
+#define BNX2_HC_STAT_COLLECT_TICKS			0x00006840
+#define BNX2_HC_STAT_COLLECT_TICKS_HC_STAT_COLL_TICKS	 (0xffL<<4)
+
+#define BNX2_HC_STATS_TICKS				0x00006844
+#define BNX2_HC_STATS_TICKS_HC_STAT_TICKS		 (0xffffL<<8)
+
+#define BNX2_HC_STAT_MEM_DATA				0x0000684c
+#define BNX2_HC_STAT_GEN_SEL_0				0x00006850
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT0	 (0L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT1	 (1L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT2	 (2L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT3	 (3L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT4	 (4L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT5	 (5L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT6	 (6L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT7	 (7L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT8	 (8L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT9	 (9L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT10	 (10L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXP_STAT11	 (11L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT0	 (12L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT1	 (13L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT2	 (14L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT3	 (15L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT4	 (16L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT5	 (17L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT6	 (18L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXP_STAT7	 (19L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT0	 (20L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT1	 (21L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT2	 (22L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT3	 (23L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT4	 (24L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT5	 (25L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT6	 (26L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT7	 (27L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT8	 (28L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT9	 (29L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT10	 (30L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COM_STAT11	 (31L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT0	 (32L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT1	 (33L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT2	 (34L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPAT_STAT3	 (35L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT0	 (36L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT1	 (37L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT2	 (38L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT3	 (39L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT4	 (40L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT5	 (41L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT6	 (42L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CP_STAT7	 (43L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT0	 (44L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT1	 (45L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT2	 (46L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT3	 (47L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT4	 (48L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT5	 (49L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT6	 (50L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MCP_STAT7	 (51L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_PCI_CLK_CNT	 (52L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CORE_CLK_CNT	 (53L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_STATUS_BLOCKS	 (54L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_INT_GEN	 (55L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_NUM_INT_MBOX_WR	 (56L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_TO_HW_INTACK	 (59L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_TO_SW_INTACK	 (60L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_HC_CORE_CLKS_DURING_SW_INTACK	 (61L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCH_CMD_CNT	 (62L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCH_SLOT_CNT	 (63L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSCH_CMD_CNT	 (64L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSCH_SLOT_CNT	 (65L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUPQ_VALID_CNT	 (66L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPQ_VALID_CNT	 (67L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPCQ_VALID_CNT	 (68L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PPQ_VALID_CNT	 (69L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PMQ_VALID_CNT	 (70L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PTQ_VALID_CNT	 (71L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMAQ_VALID_CNT	 (72L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCHQ_VALID_CNT	 (73L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDRQ_VALID_CNT	 (74L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXPQ_VALID_CNT	 (75L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMAQ_VALID_CNT	 (76L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPATQ_VALID_CNT	 (77L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TASQ_VALID_CNT	 (78L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSQ_VALID_CNT	 (79L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CPQ_VALID_CNT	 (80L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMXQ_VALID_CNT	 (81L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMTQ_VALID_CNT	 (82L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMQ_VALID_CNT	 (83L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MGMQ_VALID_CNT	 (84L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_READ_TRANSFERS_CNT	 (85L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_READ_DELAY_PCI_CLKS_CNT	 (86L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_TRANSFERS_CNT	 (87L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_DELAY_PCI_CLKS_CNT	 (88L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_READ_RETRY_AFTER_DATA_CNT	 (89L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_WRITE_TRANSFERS_CNT	 (90L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_WRITE_DELAY_PCI_CLKS_CNT	 (91L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_TRANSFERS_CNT	 (92L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_DELAY_PCI_CLKS_CNT	 (93L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_DMAE_BIG_WRITE_RETRY_AFTER_DATA_CNT	 (94L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_WR_CNT64	 (95L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_RD_CNT64	 (96L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_ACC_STALL_CLKS	 (97L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_CTX_LOCK_STALL_CLKS	 (98L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_CTX_ACCESS_STAT	 (99L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_CTX_ACCESS64_STAT	 (100L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_MBQ_PCI_STALL_STAT	 (101L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDR_FTQ_ENTRY_CNT	 (102L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDR_BURST_CNT	 (103L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMA_FTQ_ENTRY_CNT	 (104L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMA_BURST_CNT	 (105L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMA_FTQ_ENTRY_CNT	 (106L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMA_BURST_CNT	 (107L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUP_MATCH_CNT	 (108L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_POLL_PASS_CNT	 (109L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR1_CNT	 (110L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR2_CNT	 (111L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR3_CNT	 (112L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR4_CNT	 (113L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_TMR_TMR5_CNT	 (114L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT0	 (115L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT1	 (116L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT2	 (117L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT3	 (118L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT4	 (119L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2P_STAT5	 (120L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_PROC1_MISS	 (121L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_PROC2_MISS	 (122L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_0_RBDC_BURST_CNT	 (127L<<0)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_1		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_2		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_0_GEN_SEL_3		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_1				0x00006854
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_4		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_5		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_6		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_1_GEN_SEL_7		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_2				0x00006858
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_8		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_9		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_10		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_2_GEN_SEL_11		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_SEL_3				0x0000685c
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_12		 (0x7fL<<0)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_13		 (0x7fL<<8)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_14		 (0x7fL<<16)
+#define BNX2_HC_STAT_GEN_SEL_3_GEN_SEL_15		 (0x7fL<<24)
+
+#define BNX2_HC_STAT_GEN_STAT0				0x00006888
+#define BNX2_HC_STAT_GEN_STAT1				0x0000688c
+#define BNX2_HC_STAT_GEN_STAT2				0x00006890
+#define BNX2_HC_STAT_GEN_STAT3				0x00006894
+#define BNX2_HC_STAT_GEN_STAT4				0x00006898
+#define BNX2_HC_STAT_GEN_STAT5				0x0000689c
+#define BNX2_HC_STAT_GEN_STAT6				0x000068a0
+#define BNX2_HC_STAT_GEN_STAT7				0x000068a4
+#define BNX2_HC_STAT_GEN_STAT8				0x000068a8
+#define BNX2_HC_STAT_GEN_STAT9				0x000068ac
+#define BNX2_HC_STAT_GEN_STAT10				0x000068b0
+#define BNX2_HC_STAT_GEN_STAT11				0x000068b4
+#define BNX2_HC_STAT_GEN_STAT12				0x000068b8
+#define BNX2_HC_STAT_GEN_STAT13				0x000068bc
+#define BNX2_HC_STAT_GEN_STAT14				0x000068c0
+#define BNX2_HC_STAT_GEN_STAT15				0x000068c4
+#define BNX2_HC_STAT_GEN_STAT_AC0			0x000068c8
+#define BNX2_HC_STAT_GEN_STAT_AC1			0x000068cc
+#define BNX2_HC_STAT_GEN_STAT_AC2			0x000068d0
+#define BNX2_HC_STAT_GEN_STAT_AC3			0x000068d4
+#define BNX2_HC_STAT_GEN_STAT_AC4			0x000068d8
+#define BNX2_HC_STAT_GEN_STAT_AC5			0x000068dc
+#define BNX2_HC_STAT_GEN_STAT_AC6			0x000068e0
+#define BNX2_HC_STAT_GEN_STAT_AC7			0x000068e4
+#define BNX2_HC_STAT_GEN_STAT_AC8			0x000068e8
+#define BNX2_HC_STAT_GEN_STAT_AC9			0x000068ec
+#define BNX2_HC_STAT_GEN_STAT_AC10			0x000068f0
+#define BNX2_HC_STAT_GEN_STAT_AC11			0x000068f4
+#define BNX2_HC_STAT_GEN_STAT_AC12			0x000068f8
+#define BNX2_HC_STAT_GEN_STAT_AC13			0x000068fc
+#define BNX2_HC_STAT_GEN_STAT_AC14			0x00006900
+#define BNX2_HC_STAT_GEN_STAT_AC15			0x00006904
+#define BNX2_HC_VIS					0x00006908
+#define BNX2_HC_VIS_STAT_BUILD_STATE			 (0xfL<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_IDLE		 (0L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_START		 (1L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_REQUEST		 (2L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE64		 (3L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE32		 (4L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_UPDATE_DONE	 (5L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_DMA		 (6L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_CONTROL	 (7L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_LOW		 (8L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_HIGH		 (9L<<0)
+#define BNX2_HC_VIS_STAT_BUILD_STATE_MSI_DATA		 (10L<<0)
+#define BNX2_HC_VIS_DMA_STAT_STATE			 (0xfL<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_IDLE			 (0L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATUS_PARAM		 (1L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATUS_DMA		 (2L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP		 (3L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_COMP			 (4L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATISTIC_PARAM	 (5L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_STATISTIC_DMA	 (6L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP_1		 (7L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WRITE_COMP_2		 (8L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_WAIT			 (9L<<8)
+#define BNX2_HC_VIS_DMA_STAT_STATE_ABORT		 (15L<<8)
+#define BNX2_HC_VIS_DMA_MSI_STATE			 (0x7L<<12)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE		 (0x3L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_IDLE		 (0L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_COUNT	 (1L<<15)
+#define BNX2_HC_VIS_STATISTIC_DMA_EN_STATE_START	 (2L<<15)
+
+#define BNX2_HC_VIS_1					0x0000690c
+#define BNX2_HC_VIS_1_HW_INTACK_STATE			 (1L<<4)
+#define BNX2_HC_VIS_1_HW_INTACK_STATE_IDLE		 (0L<<4)
+#define BNX2_HC_VIS_1_HW_INTACK_STATE_COUNT		 (1L<<4)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE			 (1L<<5)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE_IDLE		 (0L<<5)
+#define BNX2_HC_VIS_1_SW_INTACK_STATE_COUNT		 (1L<<5)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE		 (1L<<6)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE_IDLE	 (0L<<6)
+#define BNX2_HC_VIS_1_DURING_SW_INTACK_STATE_COUNT	 (1L<<6)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE		 (1L<<7)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE_IDLE		 (0L<<7)
+#define BNX2_HC_VIS_1_MAILBOX_COUNT_STATE_COUNT		 (1L<<7)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE			 (0xfL<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_IDLE		 (0L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_DMA		 (1L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_UPDATE		 (2L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_ASSIGN		 (3L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_WAIT		 (4L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_UPDATE	 (5L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_ASSIGN	 (6L<<17)
+#define BNX2_HC_VIS_1_RAM_RD_ARB_STATE_REG_WAIT		 (7L<<17)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE			 (0x3L<<21)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE_NORMAL		 (0L<<21)
+#define BNX2_HC_VIS_1_RAM_WR_ARB_STATE_CLEAR		 (1L<<21)
+#define BNX2_HC_VIS_1_INT_GEN_STATE			 (1L<<23)
+#define BNX2_HC_VIS_1_INT_GEN_STATE_DLE			 (0L<<23)
+#define BNX2_HC_VIS_1_INT_GEN_STATE_NTERRUPT		 (1L<<23)
+#define BNX2_HC_VIS_1_STAT_CHAN_ID			 (0x7L<<24)
+#define BNX2_HC_VIS_1_INT_B				 (1L<<27)
+
+#define BNX2_HC_DEBUG_VECT_PEEK				0x00006910
+#define BNX2_HC_DEBUG_VECT_PEEK_1_VALUE			 (0x7ffL<<0)
+#define BNX2_HC_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_HC_DEBUG_VECT_PEEK_1_SEL			 (0xfL<<12)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_VALUE			 (0x7ffL<<16)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_HC_DEBUG_VECT_PEEK_2_SEL			 (0xfL<<28)
+
+
+
+/*
+ *  txp_reg definition
+ *  offset: 0x40000
+ */
+#define BNX2_TXP_CPU_MODE				0x00045000
+#define BNX2_TXP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_TXP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_TXP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_TXP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_TXP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_TXP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_TXP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_TXP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_TXP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_TXP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_TXP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_TXP_CPU_STATE				0x00045004
+#define BNX2_TXP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_TXP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_TXP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_TXP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_TXP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_TXP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_TXP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_TXP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_TXP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_TXP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_TXP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_TXP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_TXP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_TXP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_TXP_CPU_EVENT_MASK				0x00045008
+#define BNX2_TXP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_TXP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_TXP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_TXP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_TXP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_TXP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_TXP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_TXP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_TXP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_TXP_CPU_PROGRAM_COUNTER			0x0004501c
+#define BNX2_TXP_CPU_INSTRUCTION			0x00045020
+#define BNX2_TXP_CPU_DATA_ACCESS			0x00045024
+#define BNX2_TXP_CPU_INTERRUPT_ENABLE			0x00045028
+#define BNX2_TXP_CPU_INTERRUPT_VECTOR			0x0004502c
+#define BNX2_TXP_CPU_INTERRUPT_SAVED_PC			0x00045030
+#define BNX2_TXP_CPU_HW_BREAKPOINT			0x00045034
+#define BNX2_TXP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_TXP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK			0x00045038
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TXP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR			0x00045048
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_TXP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_TXP_CPU_REG_FILE				0x00045200
+#define BNX2_TXP_FTQ_DATA				0x000453c0
+#define BNX2_TXP_FTQ_CMD				0x000453f8
+#define BNX2_TXP_FTQ_CMD_OFFSET				 (0x3ffL<<0)
+#define BNX2_TXP_FTQ_CMD_WR_TOP				 (1L<<10)
+#define BNX2_TXP_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TXP_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TXP_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TXP_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TXP_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TXP_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TXP_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TXP_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TXP_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TXP_FTQ_CTL				0x000453fc
+#define BNX2_TXP_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TXP_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TXP_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TXP_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TXP_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_TXP_SCRATCH				0x00060000
+
+
+/*
+ *  tpat_reg definition
+ *  offset: 0x80000
+ */
+#define BNX2_TPAT_CPU_MODE				0x00085000
+#define BNX2_TPAT_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_TPAT_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_TPAT_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_TPAT_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_TPAT_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_TPAT_CPU_MODE_INTERRUPT_ENA		 (1L<<7)
+#define BNX2_TPAT_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_TPAT_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_TPAT_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_TPAT_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_TPAT_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_TPAT_CPU_STATE				0x00085004
+#define BNX2_TPAT_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_TPAT_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_TPAT_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_TPAT_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_TPAT_CPU_STATE_BAD_DATA_ADDR_HALTED	 (1L<<5)
+#define BNX2_TPAT_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_TPAT_CPU_STATE_ALIGN_HALTED		 (1L<<7)
+#define BNX2_TPAT_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_TPAT_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_TPAT_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_TPAT_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_TPAT_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_TPAT_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_TPAT_CPU_STATE_BLOCKED_READ		 (1L<<31)
+
+#define BNX2_TPAT_CPU_EVENT_MASK			0x00085008
+#define BNX2_TPAT_CPU_EVENT_MASK_BREAKPOINT_MASK	 (1L<<0)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_TPAT_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_TPAT_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_TPAT_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_TPAT_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_TPAT_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_TPAT_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_TPAT_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_TPAT_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_TPAT_CPU_PROGRAM_COUNTER			0x0008501c
+#define BNX2_TPAT_CPU_INSTRUCTION			0x00085020
+#define BNX2_TPAT_CPU_DATA_ACCESS			0x00085024
+#define BNX2_TPAT_CPU_INTERRUPT_ENABLE			0x00085028
+#define BNX2_TPAT_CPU_INTERRUPT_VECTOR			0x0008502c
+#define BNX2_TPAT_CPU_INTERRUPT_SAVED_PC		0x00085030
+#define BNX2_TPAT_CPU_HW_BREAKPOINT			0x00085034
+#define BNX2_TPAT_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_TPAT_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK			0x00085038
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_TPAT_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR			0x00085048
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE_JUMP	 (0L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_TPAT_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_TPAT_CPU_REG_FILE				0x00085200
+#define BNX2_TPAT_FTQ_DATA				0x000853c0
+#define BNX2_TPAT_FTQ_CMD				0x000853f8
+#define BNX2_TPAT_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_TPAT_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_TPAT_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_TPAT_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_TPAT_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_TPAT_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_TPAT_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_TPAT_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_TPAT_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_TPAT_FTQ_CTL				0x000853fc
+#define BNX2_TPAT_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_TPAT_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_TPAT_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_TPAT_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_TPAT_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_TPAT_SCRATCH				0x000a0000
+
+
+/*
+ *  rxp_reg definition
+ *  offset: 0xc0000
+ */
+#define BNX2_RXP_CPU_MODE				0x000c5000
+#define BNX2_RXP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_RXP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_RXP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_RXP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_RXP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_RXP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_RXP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_RXP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_RXP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_RXP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_RXP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_RXP_CPU_STATE				0x000c5004
+#define BNX2_RXP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_RXP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_RXP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_RXP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_RXP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_RXP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_RXP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_RXP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_RXP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_RXP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_RXP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_RXP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_RXP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_RXP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_RXP_CPU_EVENT_MASK				0x000c5008
+#define BNX2_RXP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_RXP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_RXP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_RXP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_RXP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_RXP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_RXP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_RXP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_RXP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_RXP_CPU_PROGRAM_COUNTER			0x000c501c
+#define BNX2_RXP_CPU_INSTRUCTION			0x000c5020
+#define BNX2_RXP_CPU_DATA_ACCESS			0x000c5024
+#define BNX2_RXP_CPU_INTERRUPT_ENABLE			0x000c5028
+#define BNX2_RXP_CPU_INTERRUPT_VECTOR			0x000c502c
+#define BNX2_RXP_CPU_INTERRUPT_SAVED_PC			0x000c5030
+#define BNX2_RXP_CPU_HW_BREAKPOINT			0x000c5034
+#define BNX2_RXP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_RXP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK			0x000c5038
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_RXP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR			0x000c5048
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_RXP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_RXP_CPU_REG_FILE				0x000c5200
+#define BNX2_RXP_CFTQ_DATA				0x000c5380
+#define BNX2_RXP_CFTQ_CMD				0x000c53b8
+#define BNX2_RXP_CFTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RXP_CFTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RXP_CFTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RXP_CFTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RXP_CFTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RXP_CFTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RXP_CFTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_RXP_CFTQ_CMD_POP				 (1L<<30)
+#define BNX2_RXP_CFTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RXP_CFTQ_CTL				0x000c53bc
+#define BNX2_RXP_CFTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RXP_CFTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RXP_CFTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RXP_CFTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RXP_CFTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RXP_FTQ_DATA				0x000c53c0
+#define BNX2_RXP_FTQ_CMD				0x000c53f8
+#define BNX2_RXP_FTQ_CMD_OFFSET				 (0x3ffL<<0)
+#define BNX2_RXP_FTQ_CMD_WR_TOP				 (1L<<10)
+#define BNX2_RXP_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_RXP_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_RXP_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_RXP_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_RXP_FTQ_CMD_ADD_INTERVEN			 (1L<<27)
+#define BNX2_RXP_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_RXP_FTQ_CMD_INTERVENE_CLR			 (1L<<29)
+#define BNX2_RXP_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_RXP_FTQ_CMD_BUSY				 (1L<<31)
+
+#define BNX2_RXP_FTQ_CTL				0x000c53fc
+#define BNX2_RXP_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_RXP_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_RXP_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_RXP_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_RXP_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_RXP_SCRATCH				0x000e0000
+
+
+/*
+ *  com_reg definition
+ *  offset: 0x100000
+ */
+#define BNX2_COM_CPU_MODE				0x00105000
+#define BNX2_COM_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_COM_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_COM_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_COM_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_COM_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_COM_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_COM_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_COM_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_COM_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_COM_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_COM_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_COM_CPU_STATE				0x00105004
+#define BNX2_COM_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_COM_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_COM_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_COM_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_COM_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_COM_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_COM_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_COM_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_COM_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_COM_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_COM_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_COM_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_COM_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_COM_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_COM_CPU_EVENT_MASK				0x00105008
+#define BNX2_COM_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_COM_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_COM_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_COM_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_COM_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_COM_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_COM_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_COM_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_COM_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_COM_CPU_PROGRAM_COUNTER			0x0010501c
+#define BNX2_COM_CPU_INSTRUCTION			0x00105020
+#define BNX2_COM_CPU_DATA_ACCESS			0x00105024
+#define BNX2_COM_CPU_INTERRUPT_ENABLE			0x00105028
+#define BNX2_COM_CPU_INTERRUPT_VECTOR			0x0010502c
+#define BNX2_COM_CPU_INTERRUPT_SAVED_PC			0x00105030
+#define BNX2_COM_CPU_HW_BREAKPOINT			0x00105034
+#define BNX2_COM_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_COM_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK			0x00105038
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_COM_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR			0x00105048
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_COM_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_COM_CPU_REG_FILE				0x00105200
+#define BNX2_COM_COMXQ_FTQ_DATA				0x00105340
+#define BNX2_COM_COMXQ_FTQ_CMD				0x00105378
+#define BNX2_COM_COMXQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMXQ_FTQ_CMD_SFT_RESET		 (1L<<25)
+#define BNX2_COM_COMXQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMXQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMXQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMXQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMXQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMXQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMXQ_FTQ_CTL				0x0010537c
+#define BNX2_COM_COMXQ_FTQ_CTL_INTERVENE		 (1L<<0)
+#define BNX2_COM_COMXQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMXQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMXQ_FTQ_CTL_MAX_DEPTH		 (0x3ffL<<12)
+#define BNX2_COM_COMXQ_FTQ_CTL_CUR_DEPTH		 (0x3ffL<<22)
+
+#define BNX2_COM_COMTQ_FTQ_DATA				0x00105380
+#define BNX2_COM_COMTQ_FTQ_CMD				0x001053b8
+#define BNX2_COM_COMTQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMTQ_FTQ_CMD_SFT_RESET		 (1L<<25)
+#define BNX2_COM_COMTQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMTQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMTQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMTQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMTQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMTQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMTQ_FTQ_CTL				0x001053bc
+#define BNX2_COM_COMTQ_FTQ_CTL_INTERVENE		 (1L<<0)
+#define BNX2_COM_COMTQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMTQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMTQ_FTQ_CTL_MAX_DEPTH		 (0x3ffL<<12)
+#define BNX2_COM_COMTQ_FTQ_CTL_CUR_DEPTH		 (0x3ffL<<22)
+
+#define BNX2_COM_COMQ_FTQ_DATA				0x001053c0
+#define BNX2_COM_COMQ_FTQ_CMD				0x001053f8
+#define BNX2_COM_COMQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_COM_COMQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_COM_COMQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_COM_COMQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_COM_COMQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_COM_COMQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_COM_COMQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_COM_COMQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_COM_COMQ_FTQ_CTL				0x001053fc
+#define BNX2_COM_COMQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_COM_COMQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_COM_COMQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_COM_COMQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_COM_COMQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_COM_SCRATCH				0x00120000
+
+
+/*
+ *  cp_reg definition
+ *  offset: 0x180000
+ */
+#define BNX2_CP_CPU_MODE				0x00185000
+#define BNX2_CP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_CP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_CP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_CP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_CP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_CP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_CP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_CP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_CP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_CP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_CP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_CP_CPU_STATE				0x00185004
+#define BNX2_CP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_CP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_CP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_CP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_CP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_CP_CPU_STATE_BAD_pc_HALTED			 (1L<<6)
+#define BNX2_CP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_CP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_CP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_CP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_CP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_CP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_CP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_CP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_CP_CPU_EVENT_MASK				0x00185008
+#define BNX2_CP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_CP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_CP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_CP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_CP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_CP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_CP_CPU_EVENT_MASK_SOFT_HALTED_MASK		 (1L<<10)
+#define BNX2_CP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_CP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_CP_CPU_PROGRAM_COUNTER			0x0018501c
+#define BNX2_CP_CPU_INSTRUCTION				0x00185020
+#define BNX2_CP_CPU_DATA_ACCESS				0x00185024
+#define BNX2_CP_CPU_INTERRUPT_ENABLE			0x00185028
+#define BNX2_CP_CPU_INTERRUPT_VECTOR			0x0018502c
+#define BNX2_CP_CPU_INTERRUPT_SAVED_PC			0x00185030
+#define BNX2_CP_CPU_HW_BREAKPOINT			0x00185034
+#define BNX2_CP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_CP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK			0x00185038
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_CP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR			0x00185048
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_CP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_CP_CPU_REG_FILE				0x00185200
+#define BNX2_CP_CPQ_FTQ_DATA				0x001853c0
+#define BNX2_CP_CPQ_FTQ_CMD				0x001853f8
+#define BNX2_CP_CPQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_CP_CPQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_CP_CPQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_CP_CPQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_CP_CPQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_CP_CPQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_CP_CPQ_FTQ_CMD_POP				 (1L<<30)
+#define BNX2_CP_CPQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_CP_CPQ_FTQ_CTL				0x001853fc
+#define BNX2_CP_CPQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_CP_CPQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_CP_CPQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_CP_CPQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_CP_CPQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_CP_SCRATCH					0x001a0000
+
+
+/*
+ *  mcp_reg definition
+ *  offset: 0x140000
+ */
+#define BNX2_MCP_CPU_MODE				0x00145000
+#define BNX2_MCP_CPU_MODE_LOCAL_RST			 (1L<<0)
+#define BNX2_MCP_CPU_MODE_STEP_ENA			 (1L<<1)
+#define BNX2_MCP_CPU_MODE_PAGE_0_DATA_ENA		 (1L<<2)
+#define BNX2_MCP_CPU_MODE_PAGE_0_INST_ENA		 (1L<<3)
+#define BNX2_MCP_CPU_MODE_MSG_BIT1			 (1L<<6)
+#define BNX2_MCP_CPU_MODE_INTERRUPT_ENA			 (1L<<7)
+#define BNX2_MCP_CPU_MODE_SOFT_HALT			 (1L<<10)
+#define BNX2_MCP_CPU_MODE_BAD_DATA_HALT_ENA		 (1L<<11)
+#define BNX2_MCP_CPU_MODE_BAD_INST_HALT_ENA		 (1L<<12)
+#define BNX2_MCP_CPU_MODE_FIO_ABORT_HALT_ENA		 (1L<<13)
+#define BNX2_MCP_CPU_MODE_SPAD_UNDERFLOW_HALT_ENA	 (1L<<15)
+
+#define BNX2_MCP_CPU_STATE				0x00145004
+#define BNX2_MCP_CPU_STATE_BREAKPOINT			 (1L<<0)
+#define BNX2_MCP_CPU_STATE_BAD_INST_HALTED		 (1L<<2)
+#define BNX2_MCP_CPU_STATE_PAGE_0_DATA_HALTED		 (1L<<3)
+#define BNX2_MCP_CPU_STATE_PAGE_0_INST_HALTED		 (1L<<4)
+#define BNX2_MCP_CPU_STATE_BAD_DATA_ADDR_HALTED		 (1L<<5)
+#define BNX2_MCP_CPU_STATE_BAD_pc_HALTED		 (1L<<6)
+#define BNX2_MCP_CPU_STATE_ALIGN_HALTED			 (1L<<7)
+#define BNX2_MCP_CPU_STATE_FIO_ABORT_HALTED		 (1L<<8)
+#define BNX2_MCP_CPU_STATE_SOFT_HALTED			 (1L<<10)
+#define BNX2_MCP_CPU_STATE_SPAD_UNDERFLOW		 (1L<<11)
+#define BNX2_MCP_CPU_STATE_INTERRRUPT			 (1L<<12)
+#define BNX2_MCP_CPU_STATE_DATA_ACCESS_STALL		 (1L<<14)
+#define BNX2_MCP_CPU_STATE_INST_FETCH_STALL		 (1L<<15)
+#define BNX2_MCP_CPU_STATE_BLOCKED_READ			 (1L<<31)
+
+#define BNX2_MCP_CPU_EVENT_MASK				0x00145008
+#define BNX2_MCP_CPU_EVENT_MASK_BREAKPOINT_MASK		 (1L<<0)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_INST_HALTED_MASK	 (1L<<2)
+#define BNX2_MCP_CPU_EVENT_MASK_PAGE_0_DATA_HALTED_MASK	 (1L<<3)
+#define BNX2_MCP_CPU_EVENT_MASK_PAGE_0_INST_HALTED_MASK	 (1L<<4)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_DATA_ADDR_HALTED_MASK	 (1L<<5)
+#define BNX2_MCP_CPU_EVENT_MASK_BAD_PC_HALTED_MASK	 (1L<<6)
+#define BNX2_MCP_CPU_EVENT_MASK_ALIGN_HALTED_MASK	 (1L<<7)
+#define BNX2_MCP_CPU_EVENT_MASK_FIO_ABORT_MASK		 (1L<<8)
+#define BNX2_MCP_CPU_EVENT_MASK_SOFT_HALTED_MASK	 (1L<<10)
+#define BNX2_MCP_CPU_EVENT_MASK_SPAD_UNDERFLOW_MASK	 (1L<<11)
+#define BNX2_MCP_CPU_EVENT_MASK_INTERRUPT_MASK		 (1L<<12)
+
+#define BNX2_MCP_CPU_PROGRAM_COUNTER			0x0014501c
+#define BNX2_MCP_CPU_INSTRUCTION			0x00145020
+#define BNX2_MCP_CPU_DATA_ACCESS			0x00145024
+#define BNX2_MCP_CPU_INTERRUPT_ENABLE			0x00145028
+#define BNX2_MCP_CPU_INTERRUPT_VECTOR			0x0014502c
+#define BNX2_MCP_CPU_INTERRUPT_SAVED_PC			0x00145030
+#define BNX2_MCP_CPU_HW_BREAKPOINT			0x00145034
+#define BNX2_MCP_CPU_HW_BREAKPOINT_DISABLE		 (1L<<0)
+#define BNX2_MCP_CPU_HW_BREAKPOINT_ADDRESS		 (0x3fffffffL<<2)
+
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK			0x00145038
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_VALUE		 (0x7ffL<<0)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_PEEK_EN		 (1L<<11)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_1_SEL		 (0xfL<<12)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_VALUE		 (0x7ffL<<16)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_PEEK_EN		 (1L<<27)
+#define BNX2_MCP_CPU_DEBUG_VECT_PEEK_2_SEL		 (0xfL<<28)
+
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR			0x00145048
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE		 (1L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE_JUMP		 (0L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_TYPE_BRANCH	 (1L<<1)
+#define BNX2_MCP_CPU_LAST_BRANCH_ADDR_LBA		 (0x3fffffffL<<2)
+
+#define BNX2_MCP_CPU_REG_FILE				0x00145200
+#define BNX2_MCP_MCPQ_FTQ_DATA				0x001453c0
+#define BNX2_MCP_MCPQ_FTQ_CMD				0x001453f8
+#define BNX2_MCP_MCPQ_FTQ_CMD_OFFSET			 (0x3ffL<<0)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP			 (1L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP_0			 (0L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_WR_TOP_1			 (1L<<10)
+#define BNX2_MCP_MCPQ_FTQ_CMD_SFT_RESET			 (1L<<25)
+#define BNX2_MCP_MCPQ_FTQ_CMD_RD_DATA			 (1L<<26)
+#define BNX2_MCP_MCPQ_FTQ_CMD_ADD_INTERVEN		 (1L<<27)
+#define BNX2_MCP_MCPQ_FTQ_CMD_ADD_DATA			 (1L<<28)
+#define BNX2_MCP_MCPQ_FTQ_CMD_INTERVENE_CLR		 (1L<<29)
+#define BNX2_MCP_MCPQ_FTQ_CMD_POP			 (1L<<30)
+#define BNX2_MCP_MCPQ_FTQ_CMD_BUSY			 (1L<<31)
+
+#define BNX2_MCP_MCPQ_FTQ_CTL				0x001453fc
+#define BNX2_MCP_MCPQ_FTQ_CTL_INTERVENE			 (1L<<0)
+#define BNX2_MCP_MCPQ_FTQ_CTL_OVERFLOW			 (1L<<1)
+#define BNX2_MCP_MCPQ_FTQ_CTL_FORCE_INTERVENE		 (1L<<2)
+#define BNX2_MCP_MCPQ_FTQ_CTL_MAX_DEPTH			 (0x3ffL<<12)
+#define BNX2_MCP_MCPQ_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
+
+#define BNX2_MCP_ROM					0x00150000
+#define BNX2_MCP_SCRATCH				0x00160000
+
+#define BNX2_SHM_HDR_SIGNATURE				BNX2_MCP_SCRATCH
+#define BNX2_SHM_HDR_SIGNATURE_SIG_MASK			 0xffff0000
+#define BNX2_SHM_HDR_SIGNATURE_SIG			 0x53530000
+#define BNX2_SHM_HDR_SIGNATURE_VER_MASK			 0x000000ff
+#define BNX2_SHM_HDR_SIGNATURE_VER_ONE			 0x00000001
+
+#define BNX2_SHM_HDR_ADDR_0				BNX2_MCP_SCRATCH + 4
+#define BNX2_SHM_HDR_ADDR_1				BNX2_MCP_SCRATCH + 8
+
+
+#define NUM_MC_HASH_REGISTERS   8
+
+
+/* PHY_ID1: bits 31-16; PHY_ID2: bits 15-0.  */
+#define PHY_BCM5706_PHY_ID                          0x00206160
+
+#define PHY_ID(id)                                  ((id) & 0xfffffff0)
+#define PHY_REV_ID(id)                              ((id) & 0xf)
+
+/* 5708 Serdes PHY registers */
+
+#define BCM5708S_UP1				0xb
+
+#define BCM5708S_UP1_2G5			0x1
+
+#define BCM5708S_BLK_ADDR			0x1f
+
+#define BCM5708S_BLK_ADDR_DIG			0x0000
+#define BCM5708S_BLK_ADDR_DIG3			0x0002
+#define BCM5708S_BLK_ADDR_TX_MISC		0x0005
+
+/* Digital Block */
+#define BCM5708S_1000X_CTL1			0x10
+
+#define BCM5708S_1000X_CTL1_FIBER_MODE		0x0001
+#define BCM5708S_1000X_CTL1_AUTODET_EN		0x0010
+
+#define BCM5708S_1000X_CTL2			0x11
+
+#define BCM5708S_1000X_CTL2_PLLEL_DET_EN	0x0001
+
+#define BCM5708S_1000X_STAT1			0x14
+
+#define BCM5708S_1000X_STAT1_SGMII		0x0001
+#define BCM5708S_1000X_STAT1_LINK		0x0002
+#define BCM5708S_1000X_STAT1_FD			0x0004
+#define BCM5708S_1000X_STAT1_SPEED_MASK		0x0018
+#define BCM5708S_1000X_STAT1_SPEED_10		0x0000
+#define BCM5708S_1000X_STAT1_SPEED_100		0x0008
+#define BCM5708S_1000X_STAT1_SPEED_1G		0x0010
+#define BCM5708S_1000X_STAT1_SPEED_2G5		0x0018
+#define BCM5708S_1000X_STAT1_TX_PAUSE		0x0020
+#define BCM5708S_1000X_STAT1_RX_PAUSE		0x0040
+
+/* Digital3 Block */
+#define BCM5708S_DIG_3_0			0x10
+
+#define BCM5708S_DIG_3_0_USE_IEEE		0x0001
+
+/* Tx/Misc Block */
+#define BCM5708S_TX_ACTL1			0x15
+
+#define BCM5708S_TX_ACTL1_DRIVER_VCM		0x30
+
+#define BCM5708S_TX_ACTL3			0x17
+
+#define MIN_ETHERNET_PACKET_SIZE	60
+#define MAX_ETHERNET_PACKET_SIZE	1514
+#define MAX_ETHERNET_JUMBO_PACKET_SIZE	9014
+
+#define RX_COPY_THRESH			92
+
+#define DMA_READ_CHANS	5
+#define DMA_WRITE_CHANS	3
+
+#define BCM_PAGE_BITS	12
+#define BCM_PAGE_SIZE	(1 << BCM_PAGE_BITS)
+
+#define TX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct tx_bd))
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
+
+#define MAX_RX_RINGS	4
+#define RX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct rx_bd))
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
+#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
+
+#define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
+		(MAX_TX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define PREV_TX_BD(x) ((((x)-1) & (MAX_TX_DESC_CNT)) ==			\
+		(MAX_TX_DESC_CNT)) ?				\
+	(x) - 2 : (x) - 1
+
+#define TX_RING_IDX(x) ((x) & MAX_TX_DESC_CNT)
+
+#define NEXT_RX_BD(x) (((x) & (MAX_RX_DESC_CNT - 1)) ==			\
+		(MAX_RX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
+
+//#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8)
+#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
+
+/* Context size. */
+#define CTX_SHIFT                   7
+#define CTX_SIZE                    (1 << CTX_SHIFT)
+#define CTX_MASK                    (CTX_SIZE - 1)
+#define GET_CID_ADDR(_cid)          ((_cid) << CTX_SHIFT)
+#define GET_CID(_cid_addr)          ((_cid_addr) >> CTX_SHIFT)
+
+#define PHY_CTX_SHIFT               6
+#define PHY_CTX_SIZE                (1 << PHY_CTX_SHIFT)
+#define PHY_CTX_MASK                (PHY_CTX_SIZE - 1)
+#define GET_PCID_ADDR(_pcid)        ((_pcid) << PHY_CTX_SHIFT)
+#define GET_PCID(_pcid_addr)        ((_pcid_addr) >> PHY_CTX_SHIFT)
+
+#define MB_KERNEL_CTX_SHIFT         8
+#define MB_KERNEL_CTX_SIZE          (1 << MB_KERNEL_CTX_SHIFT)
+#define MB_KERNEL_CTX_MASK          (MB_KERNEL_CTX_SIZE - 1)
+#define MB_GET_CID_ADDR(_cid)       (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT))
+
+#define MAX_CID_CNT                 0x4000
+#define MAX_CID_ADDR                (GET_CID_ADDR(MAX_CID_CNT))
+#define INVALID_CID_ADDR            0xffffffff
+
+#define TX_CID		16
+#define RX_CID		0
+
+#define MB_TX_CID_ADDR	MB_GET_CID_ADDR(TX_CID)
+#define MB_RX_CID_ADDR	MB_GET_CID_ADDR(RX_CID)
+
+#if 0
+struct sw_bd {
+	struct sk_buff		*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+#endif
+
+/* Buffered flash (Atmel: AT45DB011B) specific information */
+#define SEEPROM_PAGE_BITS			2
+#define SEEPROM_PHY_PAGE_SIZE			(1 << SEEPROM_PAGE_BITS)
+#define SEEPROM_BYTE_ADDR_MASK			(SEEPROM_PHY_PAGE_SIZE-1)
+#define SEEPROM_PAGE_SIZE			4
+#define SEEPROM_TOTAL_SIZE			65536
+
+#define BUFFERED_FLASH_PAGE_BITS		9
+#define BUFFERED_FLASH_PHY_PAGE_SIZE		(1 << BUFFERED_FLASH_PAGE_BITS)
+#define BUFFERED_FLASH_BYTE_ADDR_MASK		(BUFFERED_FLASH_PHY_PAGE_SIZE-1)
+#define BUFFERED_FLASH_PAGE_SIZE		264
+#define BUFFERED_FLASH_TOTAL_SIZE		0x21000
+
+#define SAIFUN_FLASH_PAGE_BITS			8
+#define SAIFUN_FLASH_PHY_PAGE_SIZE		(1 << SAIFUN_FLASH_PAGE_BITS)
+#define SAIFUN_FLASH_BYTE_ADDR_MASK		(SAIFUN_FLASH_PHY_PAGE_SIZE-1)
+#define SAIFUN_FLASH_PAGE_SIZE			256
+#define SAIFUN_FLASH_BASE_TOTAL_SIZE		65536
+
+#define ST_MICRO_FLASH_PAGE_BITS		8
+#define ST_MICRO_FLASH_PHY_PAGE_SIZE		(1 << ST_MICRO_FLASH_PAGE_BITS)
+#define ST_MICRO_FLASH_BYTE_ADDR_MASK		(ST_MICRO_FLASH_PHY_PAGE_SIZE-1)
+#define ST_MICRO_FLASH_PAGE_SIZE		256
+#define ST_MICRO_FLASH_BASE_TOTAL_SIZE		65536
+
+#define NVRAM_TIMEOUT_COUNT			30000
+
+
+#define FLASH_STRAP_MASK			(BNX2_NVM_CFG1_FLASH_MODE   | \
+						 BNX2_NVM_CFG1_BUFFER_MODE  | \
+						 BNX2_NVM_CFG1_PROTECT_MODE | \
+						 BNX2_NVM_CFG1_FLASH_SIZE)
+
+#define FLASH_BACKUP_STRAP_MASK			(0xf << 26)
+
+struct flash_spec {
+	u32 strapping;
+	u32 config1;
+	u32 config2;
+	u32 config3;
+	u32 write1;
+	u32 buffered;
+	u32 page_bits;
+	u32 page_size;
+	u32 addr_mask;
+	u32 total_size;
+	char  *name;
+};
+
+struct bnx2 {
+	/* Fields used in the tx and intr/napi performance paths are grouped */
+	/* together in the beginning of the structure. */
+	void /*__iomem*/		*regview;
+
+	struct nic		*nic;
+	struct pci_device	*pdev;
+
+	/* atomic_t		intr_sem; */
+
+	struct status_block	*status_blk;
+	u32 			last_status_idx;
+
+	u32			flags;
+#define PCIX_FLAG			1
+#define PCI_32BIT_FLAG			2
+#define ONE_TDMA_FLAG			4	/* no longer used */
+#define NO_WOL_FLAG			8
+#define USING_DAC_FLAG			0x10
+#define USING_MSI_FLAG			0x20
+#define ASF_ENABLE_FLAG			0x40
+
+	/* Put tx producer and consumer fields in separate cache lines. */
+	u32		tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES)));
+	u16		tx_prod;
+
+	struct tx_bd	*tx_desc_ring;
+	struct sw_bd	*tx_buf_ring;
+	int		tx_ring_size;
+
+	u16		tx_cons __attribute__((aligned(L1_CACHE_BYTES))); 
+	u16		hw_tx_cons;
+
+#ifdef BCM_VLAN 
+	struct			vlan_group *vlgrp;
+#endif
+
+	u32			rx_offset;
+	u32			rx_buf_use_size;	/* useable size */
+	u32			rx_buf_size;		/* with alignment */
+	u32			rx_max_ring_idx;
+
+	u32			rx_prod_bseq;
+	u16			rx_prod;
+	u16			rx_cons;
+	u16			hw_rx_cons;
+
+	u32			rx_csum;
+
+#if 0
+	struct rx_bd		*rx_desc_ring[MAX_RX_RINGS];
+#endif
+	struct rx_bd		*rx_desc_ring;
+
+	/* End of fields used in the performance code paths. */
+
+	char			*name;
+
+#if 0
+	int			timer_interval;
+	int			current_interval;
+	struct			timer_list timer;
+	struct work_struct	reset_task;
+	int			in_reset_task;
+
+	/* Used to synchronize phy accesses. */
+	spinlock_t		phy_lock;
+#endif
+
+	u32			phy_flags;
+#define PHY_SERDES_FLAG			1
+#define PHY_CRC_FIX_FLAG		2
+#define PHY_PARALLEL_DETECT_FLAG	4
+#define PHY_2_5G_CAPABLE_FLAG		8
+#define PHY_INT_MODE_MASK_FLAG		0x300
+#define PHY_INT_MODE_AUTO_POLLING_FLAG	0x100
+#define PHY_INT_MODE_LINK_READY_FLAG	0x200
+
+	u32			chip_id;
+	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+#define CHIP_NUM(bp)			(((bp)->chip_id) & 0xffff0000)
+#define CHIP_NUM_5706			0x57060000
+#define CHIP_NUM_5708			0x57080000
+
+#define CHIP_REV(bp)			(((bp)->chip_id) & 0x0000f000)
+#define CHIP_REV_Ax			0x00000000
+#define CHIP_REV_Bx			0x00001000
+#define CHIP_REV_Cx			0x00002000
+    
+#define CHIP_METAL(bp)			(((bp)->chip_id) & 0x00000ff0)
+#define CHIP_BONDING(bp)		(((bp)->chip_id) & 0x0000000f)
+
+#define CHIP_ID(bp)			(((bp)->chip_id) & 0xfffffff0)
+#define CHIP_ID_5706_A0			0x57060000
+#define CHIP_ID_5706_A1			0x57060010
+#define CHIP_ID_5706_A2			0x57060020
+#define CHIP_ID_5708_A0			0x57080000
+#define CHIP_ID_5708_B0			0x57081000
+#define CHIP_ID_5708_B1			0x57081010
+
+#define CHIP_BOND_ID(bp)		(((bp)->chip_id) & 0xf)
+
+/* A serdes chip will have the first bit of the bond id set. */
+#define CHIP_BOND_ID_SERDES_BIT		0x01
+
+	u32			phy_addr;
+	u32			phy_id;
+	
+	u16			bus_speed_mhz;
+	u8			wol;
+
+	u8			pad;
+
+	u16			fw_wr_seq;
+	u16			fw_drv_pulse_wr_seq;
+
+	dma_addr_t		tx_desc_mapping;
+
+
+	int			rx_max_ring;
+	int			rx_ring_size;
+#if 0
+	dma_addr_t		rx_desc_mapping[MAX_RX_RINGS];
+#endif
+	dma_addr_t		rx_desc_mapping;
+
+	u16			tx_quick_cons_trip;
+	u16			tx_quick_cons_trip_int;
+	u16			rx_quick_cons_trip;
+	u16			rx_quick_cons_trip_int;
+	u16			comp_prod_trip;
+	u16			comp_prod_trip_int;
+	u16			tx_ticks;
+	u16			tx_ticks_int;
+	u16			com_ticks;
+	u16			com_ticks_int;
+	u16			cmd_ticks;
+	u16			cmd_ticks_int;
+	u16			rx_ticks;
+	u16			rx_ticks_int;
+
+	u32			stats_ticks;
+
+	dma_addr_t		status_blk_mapping;
+
+	struct statistics_block	*stats_blk;
+	dma_addr_t		stats_blk_mapping;
+
+	u32			hc_cmd;
+	u32			rx_mode;
+
+	u16			req_line_speed;
+	u8			req_duplex;
+
+	u8			link_up;
+
+	u16			line_speed;
+	u8			duplex;
+	u8			flow_ctrl;	/* actual flow ctrl settings */
+						/* may be different from     */
+						/* req_flow_ctrl if autoneg  */
+#define FLOW_CTRL_TX		1
+#define FLOW_CTRL_RX		2
+
+	u32			advertising;
+
+	u8			req_flow_ctrl;	/* flow ctrl advertisement */ 
+						/* settings or forced      */
+						/* settings                */
+	u8			autoneg;
+#define AUTONEG_SPEED		1
+#define AUTONEG_FLOW_CTRL	2
+
+	u8			loopback;
+#define MAC_LOOPBACK		1
+#define PHY_LOOPBACK		2
+
+	u8			serdes_an_pending;
+#define SERDES_AN_TIMEOUT	(HZ / 3)
+
+	u8			mac_addr[8];
+
+	u32			shmem_base;
+
+	u32			fw_ver;
+
+	int			pm_cap;
+	int			pcix_cap;
+
+	/* struct net_device_stats net_stats; */
+
+	struct flash_spec	*flash_info;
+	u32			flash_size;
+
+	int			status_stats_size;
+};
+
+static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
+static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
+
+#define REG_RD(bp, offset)					\
+	readl(bp->regview + offset)
+
+#define REG_WR(bp, offset, val)					\
+	writel(val, bp->regview + offset)
+
+#define REG_WR16(bp, offset, val)				\
+	writew(val, bp->regview + offset)
+
+#define REG_RD_IND(bp, offset)					\
+	bnx2_reg_rd_ind(bp, offset)
+
+#define REG_WR_IND(bp, offset, val)				\
+	bnx2_reg_wr_ind(bp, offset, val)
+
+/* Indirect context access.  Unlike the MBQ_WR, these macros will not
+ * trigger a chip event. */
+static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val);
+
+#define CTX_WR(bp, cid_addr, offset, val)			\
+	bnx2_ctx_wr(bp, cid_addr, offset, val)
+
+struct cpu_reg {
+	u32 mode;
+	u32 mode_value_halt;
+	u32 mode_value_sstep;
+
+	u32 state;
+	u32 state_value_clear;
+
+	u32 gpr0;
+	u32 evmask;
+	u32 pc;
+	u32 inst;
+	u32 bp;
+
+	u32 spad_base;
+
+	u32 mips_view_base;
+};
+
+struct fw_info {
+	u32 ver_major;
+	u32 ver_minor;
+	u32 ver_fix;
+
+	u32 start_addr;
+
+	/* Text section. */
+	u32 text_addr;
+	u32 text_len;
+	u32 text_index;
+	u32 *text;
+
+	/* Data section. */
+	u32 data_addr;
+	u32 data_len;
+	u32 data_index;
+	u32 *data;
+
+	/* SBSS section. */
+	u32 sbss_addr;
+	u32 sbss_len;
+	u32 sbss_index;
+	u32 *sbss;
+
+	/* BSS section. */
+	u32 bss_addr;
+	u32 bss_len;
+	u32 bss_index;
+	u32 *bss;
+
+	/* Read-only section. */
+	u32 rodata_addr;
+	u32 rodata_len;
+	u32 rodata_index;
+	u32 *rodata;
+};
+
+#define RV2P_PROC1                              0
+#define RV2P_PROC2                              1
+
+
+/* This value (in milliseconds) determines the frequency of the driver
+ * issuing the PULSE message code.  The firmware monitors this periodic
+ * pulse to determine when to switch to an OS-absent mode. */
+#define DRV_PULSE_PERIOD_MS                 250
+
+/* This value (in milliseconds) determines how long the driver should
+ * wait for an acknowledgement from the firmware before timing out.  Once
+ * the firmware has timed out, the driver will assume there is no firmware
+ * running and there won't be any firmware-driver synchronization during a
+ * driver reset. */
+#define FW_ACK_TIME_OUT_MS                  100
+
+
+#define BNX2_DRV_RESET_SIGNATURE		0x00000000
+#define BNX2_DRV_RESET_SIGNATURE_MAGIC		 0x4841564b /* HAVK */
+//#define DRV_RESET_SIGNATURE_MAGIC		 0x47495352 /* RSIG */
+
+#define BNX2_DRV_MB				0x00000004
+#define BNX2_DRV_MSG_CODE			 0xff000000
+#define BNX2_DRV_MSG_CODE_RESET			 0x01000000
+#define BNX2_DRV_MSG_CODE_UNLOAD		 0x02000000
+#define BNX2_DRV_MSG_CODE_SHUTDOWN		 0x03000000
+#define BNX2_DRV_MSG_CODE_SUSPEND_WOL		 0x04000000
+#define BNX2_DRV_MSG_CODE_FW_TIMEOUT		 0x05000000
+#define BNX2_DRV_MSG_CODE_PULSE			 0x06000000
+#define BNX2_DRV_MSG_CODE_DIAG			 0x07000000
+#define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL	 0x09000000
+
+#define BNX2_DRV_MSG_DATA			 0x00ff0000
+#define BNX2_DRV_MSG_DATA_WAIT0			 0x00010000
+#define BNX2_DRV_MSG_DATA_WAIT1			 0x00020000
+#define BNX2_DRV_MSG_DATA_WAIT2			 0x00030000
+#define BNX2_DRV_MSG_DATA_WAIT3			 0x00040000
+        
+#define BNX2_DRV_MSG_SEQ			 0x0000ffff
+
+#define BNX2_FW_MB				0x00000008
+#define BNX2_FW_MSG_ACK				 0x0000ffff
+#define BNX2_FW_MSG_STATUS_MASK			 0x00ff0000
+#define BNX2_FW_MSG_STATUS_OK			 0x00000000
+#define BNX2_FW_MSG_STATUS_FAILURE		 0x00ff0000
+
+#define BNX2_LINK_STATUS			0x0000000c
+#define BNX2_LINK_STATUS_INIT_VALUE		 0xffffffff 
+#define BNX2_LINK_STATUS_LINK_UP		 0x1 
+#define BNX2_LINK_STATUS_LINK_DOWN		 0x0 
+#define BNX2_LINK_STATUS_SPEED_MASK		 0x1e
+#define BNX2_LINK_STATUS_AN_INCOMPLETE		 (0<<1) 
+#define BNX2_LINK_STATUS_10HALF			 (1<<1) 
+#define BNX2_LINK_STATUS_10FULL			 (2<<1) 
+#define BNX2_LINK_STATUS_100HALF		 (3<<1) 
+#define BNX2_LINK_STATUS_100BASE_T4		 (4<<1) 
+#define BNX2_LINK_STATUS_100FULL		 (5<<1) 
+#define BNX2_LINK_STATUS_1000HALF		 (6<<1) 
+#define BNX2_LINK_STATUS_1000FULL		 (7<<1) 
+#define BNX2_LINK_STATUS_2500HALF		 (8<<1) 
+#define BNX2_LINK_STATUS_2500FULL		 (9<<1) 
+#define BNX2_LINK_STATUS_AN_ENABLED		 (1<<5) 
+#define BNX2_LINK_STATUS_AN_COMPLETE		 (1<<6) 
+#define BNX2_LINK_STATUS_PARALLEL_DET		 (1<<7) 
+#define BNX2_LINK_STATUS_RESERVED		 (1<<8) 
+#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL	 (1<<9) 
+#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF	 (1<<10) 
+#define BNX2_LINK_STATUS_PARTNER_AD_100BT4	 (1<<11) 
+#define BNX2_LINK_STATUS_PARTNER_AD_100FULL	 (1<<12) 
+#define BNX2_LINK_STATUS_PARTNER_AD_100HALF	 (1<<13) 
+#define BNX2_LINK_STATUS_PARTNER_AD_10FULL	 (1<<14) 
+#define BNX2_LINK_STATUS_PARTNER_AD_10HALF	 (1<<15) 
+#define BNX2_LINK_STATUS_TX_FC_ENABLED		 (1<<16) 
+#define BNX2_LINK_STATUS_RX_FC_ENABLED		 (1<<17) 
+#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP	 (1<<18) 
+#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP	 (1<<19) 
+#define BNX2_LINK_STATUS_SERDES_LINK		 (1<<20) 
+#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL	 (1<<21) 
+#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF	 (1<<22) 
+
+#define BNX2_DRV_PULSE_MB			0x00000010
+#define BNX2_DRV_PULSE_SEQ_MASK			 0x00007fff
+
+/* Indicate to the firmware not to go into the
+ * OS absent when it is not getting driver pulse.
+ * This is used for debugging. */
+#define BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE	 0x00080000
+
+#define BNX2_DEV_INFO_SIGNATURE			0x00000020
+#define BNX2_DEV_INFO_SIGNATURE_MAGIC		 0x44564900
+#define BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK	 0xffffff00
+#define BNX2_DEV_INFO_FEATURE_CFG_VALID		 0x01
+#define BNX2_DEV_INFO_SECONDARY_PORT		 0x80
+#define BNX2_DEV_INFO_DRV_ALWAYS_ALIVE		 0x40
+
+#define BNX2_SHARED_HW_CFG_PART_NUM		0x00000024
+
+#define BNX2_SHARED_HW_CFG_POWER_DISSIPATED	0x00000034
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D3_MASK	 0xff000000
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D2_MASK	 0xff0000
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D1_MASK	 0xff00
+#define BNX2_SHARED_HW_CFG_POWER_STATE_D0_MASK	 0xff
+
+#define BNX2_SHARED_HW_CFG POWER_CONSUMED	0x00000038
+#define BNX2_SHARED_HW_CFG_CONFIG		0x0000003c
+#define BNX2_SHARED_HW_CFG_DESIGN_NIC		 0
+#define BNX2_SHARED_HW_CFG_DESIGN_LOM		 0x1
+#define BNX2_SHARED_HW_CFG_PHY_COPPER		 0
+#define BNX2_SHARED_HW_CFG_PHY_FIBER		 0x2
+#define BNX2_SHARED_HW_CFG_PHY_2_5G		 0x20
+#define BNX2_SHARED_HW_CFG_PHY_BACKPLANE	 0x40
+#define BNX2_SHARED_HW_CFG_LED_MODE_SHIFT_BITS	 8
+#define BNX2_SHARED_HW_CFG_LED_MODE_MASK	 0x300
+#define BNX2_SHARED_HW_CFG_LED_MODE_MAC		 0
+#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1	 0x100
+#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2	 0x200
+
+#define BNX2_SHARED_HW_CFG_CONFIG2		0x00000040
+#define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK	 0x00fff000
+
+#define BNX2_DEV_INFO_BC_REV			0x0000004c
+
+#define BNX2_PORT_HW_CFG_MAC_UPPER		0x00000050
+#define BNX2_PORT_HW_CFG_UPPERMAC_MASK		 0xffff
+
+#define BNX2_PORT_HW_CFG_MAC_LOWER		0x00000054
+#define BNX2_PORT_HW_CFG_CONFIG			0x00000058
+#define BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK	 0x0000ffff
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK	 0x001f0000
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_AN	 0x00000000
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G	 0x00030000
+#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_2_5G	 0x00040000
+
+#define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER	0x00000068
+#define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER	0x0000006c
+#define BNX2_PORT_HW_CFG_IMD_MAC_B_UPPER	0x00000070
+#define BNX2_PORT_HW_CFG_IMD_MAC_B_LOWER	0x00000074
+#define BNX2_PORT_HW_CFG_ISCSI_MAC_UPPER	0x00000078
+#define BNX2_PORT_HW_CFG_ISCSI_MAC_LOWER	0x0000007c
+
+#define BNX2_DEV_INFO_PER_PORT_HW_CONFIG2	0x000000b4
+
+#define BNX2_DEV_INFO_FORMAT_REV		0x000000c4
+#define BNX2_DEV_INFO_FORMAT_REV_MASK		 0xff000000
+#define BNX2_DEV_INFO_FORMAT_REV_ID		 ('A' << 24)
+
+#define BNX2_SHARED_FEATURE			0x000000c8
+#define BNX2_SHARED_FEATURE_MASK		 0xffffffff
+
+#define BNX2_PORT_FEATURE			0x000000d8
+#define BNX2_PORT2_FEATURE			0x00000014c
+#define BNX2_PORT_FEATURE_WOL_ENABLED		 0x01000000
+#define BNX2_PORT_FEATURE_MBA_ENABLED		 0x02000000
+#define BNX2_PORT_FEATURE_ASF_ENABLED		 0x04000000
+#define BNX2_PORT_FEATURE_IMD_ENABLED		 0x08000000
+#define BNX2_PORT_FEATURE_BAR1_SIZE_MASK	 0xf
+#define BNX2_PORT_FEATURE_BAR1_SIZE_DISABLED	 0x0
+#define BNX2_PORT_FEATURE_BAR1_SIZE_64K		 0x1
+#define BNX2_PORT_FEATURE_BAR1_SIZE_128K	 0x2
+#define BNX2_PORT_FEATURE_BAR1_SIZE_256K	 0x3
+#define BNX2_PORT_FEATURE_BAR1_SIZE_512K	 0x4
+#define BNX2_PORT_FEATURE_BAR1_SIZE_1M		 0x5
+#define BNX2_PORT_FEATURE_BAR1_SIZE_2M		 0x6
+#define BNX2_PORT_FEATURE_BAR1_SIZE_4M		 0x7
+#define BNX2_PORT_FEATURE_BAR1_SIZE_8M		 0x8
+#define BNX2_PORT_FEATURE_BAR1_SIZE_16M		 0x9
+#define BNX2_PORT_FEATURE_BAR1_SIZE_32M		 0xa
+#define BNX2_PORT_FEATURE_BAR1_SIZE_64M		 0xb
+#define BNX2_PORT_FEATURE_BAR1_SIZE_128M	 0xc
+#define BNX2_PORT_FEATURE_BAR1_SIZE_256M	 0xd
+#define BNX2_PORT_FEATURE_BAR1_SIZE_512M	 0xe
+#define BNX2_PORT_FEATURE_BAR1_SIZE_1G		 0xf
+
+#define BNX2_PORT_FEATURE_WOL			0xdc
+#define BNX2_PORT2_FEATURE_WOL			0x150
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_SHIFT_BITS	 4
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MASK	 0x30
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_DISABLE	 0
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MAGIC	 0x10
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_ACPI	 0x20
+#define BNX2_PORT_FEATURE_WOL_DEFAULT_MAGIC_AND_ACPI	 0x30
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_MASK	 0xf
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_AUTONEG	 0
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_10HALF	 1
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_10FULL	 2
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_100HALF 3
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_100FULL 4
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_1000HALF	 5
+#define BNX2_PORT_FEATURE_WOL_LINK_SPEED_1000FULL	 6
+#define BNX2_PORT_FEATURE_WOL_AUTONEG_ADVERTISE_1000	 0x40
+#define BNX2_PORT_FEATURE_WOL_RESERVED_PAUSE_CAP 0x400
+#define BNX2_PORT_FEATURE_WOL_RESERVED_ASYM_PAUSE_CAP	 0x800
+
+#define BNX2_PORT_FEATURE_MBA			0xe0
+#define BNX2_PORT2_FEATURE_MBA			0x154
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_SHIFT_BITS	 0
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK	 0x3
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE	 0
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_RPL	 1
+#define BNX2_PORT_FEATURE_MBA_BOOT_AGENT_TYPE_BOOTP	 2
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_SHIFT_BITS	 2
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_MASK	 0x3c
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_AUTONEG	 0
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_10HALF	 0x4
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_10FULL	 0x8
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_100HALF	 0xc
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_100FULL	 0x10
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_1000HALF	 0x14
+#define BNX2_PORT_FEATURE_MBA_LINK_SPEED_1000FULL	 0x18
+#define BNX2_PORT_FEATURE_MBA_SETUP_PROMPT_ENABLE	 0x40
+#define BNX2_PORT_FEATURE_MBA_HOTKEY_CTRL_S	 0
+#define BNX2_PORT_FEATURE_MBA_HOTKEY_CTRL_B	 0x80
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_SHIFT_BITS	 8
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_MASK	 0xff00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_DISABLED	 0
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_1K	 0x100
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_2K	 0x200
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_4K	 0x300
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_8K	 0x400
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_16K	 0x500
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_32K	 0x600
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_64K	 0x700
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_128K	 0x800
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_256K	 0x900
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_512K	 0xa00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_1M	 0xb00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_2M	 0xc00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_4M	 0xd00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_8M	 0xe00
+#define BNX2_PORT_FEATURE_MBA_EXP_ROM_SIZE_16M	 0xf00
+#define BNX2_PORT_FEATURE_MBA_MSG_TIMEOUT_SHIFT_BITS	 16
+#define BNX2_PORT_FEATURE_MBA_MSG_TIMEOUT_MASK	 0xf0000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_SHIFT_BITS	 20
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_MASK	 0x300000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_AUTO	 0
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_BBS	 0x100000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT18H	 0x200000
+#define BNX2_PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT19H	 0x300000
+
+#define BNX2_PORT_FEATURE_IMD			0xe4
+#define BNX2_PORT2_FEATURE_IMD			0x158
+#define BNX2_PORT_FEATURE_IMD_LINK_OVERRIDE_DEFAULT	 0
+#define BNX2_PORT_FEATURE_IMD_LINK_OVERRIDE_ENABLE	 1
+
+#define BNX2_PORT_FEATURE_VLAN			0xe8
+#define BNX2_PORT2_FEATURE_VLAN			0x15c
+#define BNX2_PORT_FEATURE_MBA_VLAN_TAG_MASK	 0xffff
+#define BNX2_PORT_FEATURE_MBA_VLAN_ENABLE	 0x10000
+
+#define BNX2_BC_STATE_RESET_TYPE		0x000001c0
+#define BNX2_BC_STATE_RESET_TYPE_SIG		 0x00005254
+#define BNX2_BC_STATE_RESET_TYPE_SIG_MASK	 0x0000ffff
+#define BNX2_BC_STATE_RESET_TYPE_NONE	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00010000)
+#define BNX2_BC_STATE_RESET_TYPE_PCI	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00020000)
+#define BNX2_BC_STATE_RESET_TYPE_VAUX	 (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  0x00030000)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK	 DRV_MSG_CODE         
+#define BNX2_BC_STATE_RESET_TYPE_DRV_RESET (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					    DRV_MSG_CODE_RESET)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_UNLOAD (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					     DRV_MSG_CODE_UNLOAD)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_SHUTDOWN (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					       DRV_MSG_CODE_SHUTDOWN)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_WOL (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					  DRV_MSG_CODE_WOL)
+#define BNX2_BC_STATE_RESET_TYPE_DRV_DIAG (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					   DRV_MSG_CODE_DIAG)
+#define BNX2_BC_STATE_RESET_TYPE_VALUE(msg) (BNX2_BC_STATE_RESET_TYPE_SIG | \
+					     (msg))
+
+#define BNX2_BC_STATE				0x000001c4
+#define BNX2_BC_STATE_ERR_MASK			 0x0000ff00
+#define BNX2_BC_STATE_SIGN			 0x42530000
+#define BNX2_BC_STATE_SIGN_MASK			 0xffff0000
+#define BNX2_BC_STATE_BC1_START			 (BNX2_BC_STATE_SIGN | 0x1)
+#define BNX2_BC_STATE_GET_NVM_CFG1		 (BNX2_BC_STATE_SIGN | 0x2)
+#define BNX2_BC_STATE_PROG_BAR			 (BNX2_BC_STATE_SIGN | 0x3)
+#define BNX2_BC_STATE_INIT_VID			 (BNX2_BC_STATE_SIGN | 0x4)
+#define BNX2_BC_STATE_GET_NVM_CFG2		 (BNX2_BC_STATE_SIGN | 0x5)
+#define BNX2_BC_STATE_APPLY_WKARND		 (BNX2_BC_STATE_SIGN | 0x6)
+#define BNX2_BC_STATE_LOAD_BC2			 (BNX2_BC_STATE_SIGN | 0x7)
+#define BNX2_BC_STATE_GOING_BC2			 (BNX2_BC_STATE_SIGN | 0x8)
+#define BNX2_BC_STATE_GOING_DIAG		 (BNX2_BC_STATE_SIGN | 0x9)
+#define BNX2_BC_STATE_RT_FINAL_INIT		 (BNX2_BC_STATE_SIGN | 0x81)
+#define BNX2_BC_STATE_RT_WKARND			 (BNX2_BC_STATE_SIGN | 0x82)
+#define BNX2_BC_STATE_RT_DRV_PULSE		 (BNX2_BC_STATE_SIGN | 0x83)
+#define BNX2_BC_STATE_RT_FIOEVTS		 (BNX2_BC_STATE_SIGN | 0x84)
+#define BNX2_BC_STATE_RT_DRV_CMD		 (BNX2_BC_STATE_SIGN | 0x85)
+#define BNX2_BC_STATE_RT_LOW_POWER		 (BNX2_BC_STATE_SIGN | 0x86)
+#define BNX2_BC_STATE_RT_SET_WOL		 (BNX2_BC_STATE_SIGN | 0x87)
+#define BNX2_BC_STATE_RT_OTHER_FW		 (BNX2_BC_STATE_SIGN | 0x88)
+#define BNX2_BC_STATE_RT_GOING_D3		 (BNX2_BC_STATE_SIGN | 0x89)
+#define BNX2_BC_STATE_ERR_BAD_VERSION		 (BNX2_BC_STATE_SIGN | 0x0100)
+#define BNX2_BC_STATE_ERR_BAD_BC2_CRC		 (BNX2_BC_STATE_SIGN | 0x0200)
+#define BNX2_BC_STATE_ERR_BC1_LOOP		 (BNX2_BC_STATE_SIGN | 0x0300)
+#define BNX2_BC_STATE_ERR_UNKNOWN_CMD		 (BNX2_BC_STATE_SIGN | 0x0400)
+#define BNX2_BC_STATE_ERR_DRV_DEAD		 (BNX2_BC_STATE_SIGN | 0x0500)
+#define BNX2_BC_STATE_ERR_NO_RXP		 (BNX2_BC_STATE_SIGN | 0x0600)
+#define BNX2_BC_STATE_ERR_TOO_MANY_RBUF		 (BNX2_BC_STATE_SIGN | 0x0700)
+	
+#define BNX2_BC_STATE_DEBUG_CMD			0x1dc
+#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE	 0x42440000
+#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE_MASK	 0xffff0000
+#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_CNT_MASK	 0xffff
+#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_INFINITE	 0xffff
+
+#define HOST_VIEW_SHMEM_BASE			0x167c00
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+#define RX_OFFSET		(sizeof(struct l2_fhdr) + 2)
+
+#define RX_BUF_CNT		20
+
+/* 8 for CRC and VLAN */
+#define RX_BUF_USE_SIZE		(ETH_MAX_MTU + ETH_HLEN + RX_OFFSET + 8)
+
+/* 8 for alignment */
+//#define RX_BUF_SIZE		(RX_BUF_USE_SIZE + 8)
+#define RX_BUF_SIZE		(L1_CACHE_ALIGN(RX_BUF_USE_SIZE + 8))
+
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2_fw.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2_fw.h
new file mode 100644
index 0000000..8158974
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/bnx2_fw.h
@@ -0,0 +1,3494 @@
+/* bnx2_fw.h: Broadcom NX2 network driver.
+ *
+ * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, except as noted below.
+ *
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004, 2005 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
+
+static const int bnx2_COM_b06FwReleaseMajor = 0x1;
+static const int bnx2_COM_b06FwReleaseMinor = 0x0;
+static const int bnx2_COM_b06FwReleaseFix = 0x0;
+static const u32 bnx2_COM_b06FwStartAddr = 0x080008b4;
+static const u32 bnx2_COM_b06FwTextAddr = 0x08000000;
+static const int bnx2_COM_b06FwTextLen = 0x57bc;
+static const u32 bnx2_COM_b06FwDataAddr = 0x08005840;
+static const int bnx2_COM_b06FwDataLen = 0x0;
+static const u32 bnx2_COM_b06FwRodataAddr = 0x080057c0;
+static const int bnx2_COM_b06FwRodataLen = 0x58;
+static const u32 bnx2_COM_b06FwBssAddr = 0x08005860;
+static const int bnx2_COM_b06FwBssLen = 0x88;
+static const u32 bnx2_COM_b06FwSbssAddr = 0x08005840;
+static const int bnx2_COM_b06FwSbssLen = 0x1c;
+static u32 bnx2_COM_b06FwText[(0x57bc/4) + 1] = {
+	0x0a00022d, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x322e352e,
+	0x38000000, 0x02050802, 0x00000000, 0x00000003, 0x00000014, 0x00000032,
+	0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000010, 0x000003e8, 0x0000ea60, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x0000ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000002, 0x00000020, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24425840,
+	0x3c030800, 0x246358e8, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004,
+	0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261008b4, 0x3c1c0800,
+	0x279c5840, 0x0e0002f7, 0x00000000, 0x0000000d, 0x27bdffe8, 0x3c1a8000,
+	0x3c020008, 0x0342d825, 0x3c036010, 0xafbf0010, 0x8c655000, 0x3c020800,
+	0x24470f30, 0x3c040800, 0x24865860, 0x2402ff7f, 0x00a22824, 0x34a5380c,
+	0xac655000, 0x00002821, 0x24020037, 0x24030c80, 0xaf420008, 0xaf430024,
+	0xacc70000, 0x24a50001, 0x2ca20016, 0x1440fffc, 0x24c60004, 0x24845860,
+	0x3c020800, 0x24420f3c, 0x3c030800, 0x24630e2c, 0xac820004, 0x3c020800,
+	0x24420a2c, 0x3c050800, 0x24a51268, 0xac82000c, 0x3c020800, 0x244243dc,
+	0xac830008, 0x3c030800, 0x24633698, 0xac820014, 0x3c020800, 0x24423c24,
+	0xac830018, 0xac83001c, 0x3c030800, 0x24630f44, 0xac820024, 0x3c020800,
+	0x244243ac, 0xac83002c, 0x3c030800, 0x246343cc, 0xac820030, 0x3c020800,
+	0x244242f0, 0xac830034, 0x3c030800, 0x24633d78, 0xac82003c, 0x3c020800,
+	0x24420fd4, 0xac850010, 0xac850020, 0xac830040, 0x0e0010b7, 0xac820050,
+	0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0, 0xafb00010, 0x27500100,
+	0xafbf0018, 0xafb10014, 0x9203000b, 0x24020003, 0x1462005b, 0x96110008,
+	0x32220001, 0x10400009, 0x27430080, 0x8e020000, 0x96040014, 0x000211c2,
+	0x00021040, 0x00621821, 0xa4640000, 0x0a0002d0, 0x3c020800, 0x3c020800,
+	0x8c430020, 0x1060002a, 0x3c030800, 0x0e00148e, 0x00000000, 0x97420108,
+	0x8f850018, 0x9743010c, 0x3042003e, 0x00021400, 0x00621825, 0xaca30000,
+	0x8f840018, 0x8f420100, 0xac820004, 0x97430116, 0x9742010e, 0x8f840018,
+	0x00031c00, 0x00431025, 0xac820008, 0x97430110, 0x97440112, 0x8f850018,
+	0x00031c00, 0x00832025, 0xaca4000c, 0x97420114, 0x8f840018, 0x3042ffff,
+	0xac820010, 0x8f830018, 0xac600014, 0x8f820018, 0x3c030800, 0xac400018,
+	0x946258ce, 0x8f840018, 0x3c032000, 0x00431025, 0xac82001c, 0x0e0014cc,
+	0x24040001, 0x3c030800, 0x8c620040, 0x24420001, 0xac620040, 0x3c020800,
+	0x8c430044, 0x32240004, 0x24630001, 0x10800017, 0xac430044, 0x8f4202b8,
+	0x04430007, 0x8e020020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001,
+	0x0a0002f2, 0xac830060, 0x3c060800, 0x8cc4005c, 0xaf420280, 0x96030016,
+	0x00001021, 0xa7430284, 0x8e050004, 0x24840001, 0x3c031000, 0xaf450288,
+	0xaf4302b8, 0x0a0002f2, 0xacc4005c, 0x32220002, 0x0a0002f2, 0x0002102b,
+	0x3c026000, 0xac400808, 0x0000000d, 0x00001021, 0x8fbf0018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffc8, 0xafbf0034, 0xafbe0030,
+	0xafb7002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018,
+	0xafb10014, 0x0e000244, 0xafb00010, 0x3c170800, 0x3c160800, 0x24110020,
+	0x24150030, 0x2794000c, 0x27930008, 0x3c124000, 0x3c1e0800, 0x8f820004,
+	0x3c040800, 0x8c830020, 0x10430005, 0x8ee200a4, 0xaf830004, 0x0e001593,
+	0x00000000, 0x8ee200a4, 0x8ec300a0, 0x10430004, 0x26c400a0, 0x94820002,
+	0xa742009e, 0xaee300a4, 0x8f500000, 0x32020007, 0x1040ffee, 0x32020001,
+	0x1040002c, 0x32020002, 0x8f420100, 0xaf420020, 0x8f430104, 0xaf4300a8,
+	0x9342010b, 0x93630000, 0x306300ff, 0x10710005, 0x304400ff, 0x10750006,
+	0x2c820016, 0x0a000333, 0x00000000, 0xaf940000, 0x0a000334, 0x2c820016,
+	0xaf930000, 0x0a000334, 0x00000000, 0xaf800000, 0x14400005, 0x00041880,
+	0x0e0003cc, 0x00000000, 0x0a000340, 0x00000000, 0x3c020800, 0x24425860,
+	0x00621821, 0x8c620000, 0x0040f809, 0x00000000, 0x10400005, 0x3c030800,
+	0x8f420104, 0x3c016020, 0xac220014, 0x3c030800, 0x8c620034, 0xaf520138,
+	0x24420001, 0xac620034, 0x32020002, 0x1040001a, 0x32020004, 0x8f420140,
+	0xaf420020, 0x93630000, 0x306300ff, 0x10710005, 0x00000000, 0x10750006,
+	0x00000000, 0x0a00035d, 0x00000000, 0xaf940000, 0x0a00035e, 0x00000000,
+	0xaf930000, 0x0a00035e, 0x00000000, 0xaf800000, 0x0e000c7b, 0x00000000,
+	0x3c040800, 0x8c820038, 0xaf520178, 0x24420001, 0xac820038, 0x32020004,
+	0x1040ffa4, 0x00000000, 0x8f420180, 0xaf420020, 0x93630000, 0x306300ff,
+	0x10710005, 0x00000000, 0x10750006, 0x00000000, 0x0a000378, 0x00000000,
+	0xaf940000, 0x0a000379, 0x00000000, 0xaf930000, 0x0a000379, 0x00000000,
+	0xaf800000, 0x8f430180, 0x24020f00, 0x14620005, 0x00000000, 0x8f420188,
+	0xa742009c, 0x0a000387, 0x8fc2003c, 0x93620000, 0x14510004, 0x8fc2003c,
+	0x0e000bad, 0x00000000, 0x8fc2003c, 0xaf5201b8, 0x24420001, 0x0a00030b,
+	0xafc2003c, 0x27bdffe8, 0xafbf0010, 0x97420108, 0x24033000, 0x30447000,
+	0x10830016, 0x28823001, 0x10400007, 0x24024000, 0x1080000b, 0x24022000,
+	0x1082000c, 0x00000000, 0x0a0003b3, 0x00000000, 0x10820010, 0x24025000,
+	0x10820012, 0x00000000, 0x0a0003b3, 0x00000000, 0x0000000d, 0x0a0003b5,
+	0x00001021, 0x0e000442, 0x00000000, 0x0a0003b6, 0x8fbf0010, 0x0e00041a,
+	0x00000000, 0x0a0003b5, 0x00001021, 0x0e000669, 0x00000000, 0x0a0003b5,
+	0x00001021, 0x0e001467, 0x00000000, 0x0a0003b5, 0x00001021, 0x0000000d,
+	0x00001021, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x93620000, 0x24030020,
+	0x304400ff, 0x10830005, 0x24020030, 0x10820007, 0x00000000, 0x0a0003c9,
+	0x00000000, 0x2782000c, 0xaf820000, 0x03e00008, 0x00000000, 0x27820008,
+	0xaf820000, 0x03e00008, 0x00000000, 0xaf800000, 0x03e00008, 0x00000000,
+	0x0000000d, 0x03e00008, 0x00001021, 0x03e00008, 0x00001021, 0x27440100,
+	0x94830008, 0x30620004, 0x10400017, 0x30620002, 0x8f4202b8, 0x04430007,
+	0x8c820020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001, 0x03e00008,
+	0xac830060, 0xaf420280, 0x94830016, 0x3c060800, 0xa7430284, 0x8c850004,
+	0x8cc4005c, 0x00001021, 0x3c031000, 0x24840001, 0xaf450288, 0xaf4302b8,
+	0x03e00008, 0xacc4005c, 0x14400003, 0x3c040800, 0x03e00008, 0x00001021,
+	0x8c830084, 0x24020001, 0x24630001, 0x03e00008, 0xac830084, 0x27450100,
+	0x3c040800, 0x8c820088, 0x94a3000c, 0x24420001, 0x007a1821, 0xac820088,
+	0x8ca40018, 0x90664000, 0xaf440038, 0x8ca2001c, 0x2403fff8, 0x00063600,
+	0x00431024, 0x34420004, 0x3c030005, 0xaf42003c, 0xaf430030, 0x00000000,
+	0x00000000, 0x00000000, 0xaf460404, 0x00000000, 0x00000000, 0x00000000,
+	0x3c020006, 0x34420001, 0xaf420030, 0x00000000, 0x00000000, 0x00000000,
+	0x8f420000, 0x30420010, 0x1040fffd, 0x00001021, 0x03e00008, 0x00000000,
+	0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x1060001e,
+	0xafbf0014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020018, 0xac620000,
+	0x8f840018, 0x9602000c, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018,
+	0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018,
+	0x3c026000, 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce,
+	0x8f850018, 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010,
+	0x27500100, 0xafbf0014, 0x92020009, 0x14400003, 0x3c020800, 0x0a00046c,
+	0x24020001, 0x8c430020, 0x1060001f, 0x00001021, 0x0e00148e, 0x00000000,
+	0x8f830018, 0x8e020018, 0xac620000, 0x8f840018, 0x9602000c, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448, 0xac830018,
+	0x96020008, 0x3c030800, 0x946458ce, 0x8f850018, 0x00021400, 0x00441025,
+	0x24040001, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf0014, 0x8fb00010,
+	0x03e00008, 0x27bd0018, 0x3c0b0800, 0x8d6808b0, 0x3c070800, 0x24e700b0,
+	0x00084900, 0x01271821, 0xac640000, 0x93620005, 0x97660008, 0x00e95021,
+	0x93630023, 0x9364003f, 0x25080001, 0x00021600, 0x00063400, 0x00461025,
+	0x00031a00, 0x00431025, 0x00822025, 0xad440004, 0x9362007e, 0x9366007f,
+	0x8f630178, 0x9364007a, 0x00021600, 0x00063400, 0x00461025, 0x00031a00,
+	0x00431025, 0x00822025, 0xad440008, 0x93620080, 0x9363007d, 0x3108007f,
+	0x01403821, 0xad6808b0, 0x00021600, 0x00031c00, 0x00431025, 0x00451025,
+	0x03e00008, 0xace2000c, 0x27bdffb8, 0xafb3002c, 0x00009821, 0xafbe0040,
+	0x0000f021, 0xafb50034, 0x27550100, 0xafbf0044, 0xafb7003c, 0xafb60038,
+	0xafb40030, 0xafb20028, 0xafb10024, 0xafb00020, 0xafa00010, 0xafa00014,
+	0x96a20008, 0x8f540100, 0x8eb10018, 0x30420001, 0x10400037, 0x02a0b821,
+	0x8f630054, 0x2622ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d,
+	0x00000000, 0x2400015c, 0x0a0004e5, 0x00002021, 0x8f62004c, 0x02221023,
+	0x18400028, 0x00002021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c,
+	0x308400ff, 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c,
+	0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001,
+	0x00021023, 0x30420005, 0x0a0004e5, 0x34440004, 0x27660100, 0x00041080,
+	0x00c21021, 0x8c430000, 0x02231823, 0x04600004, 0x24820001, 0x30440007,
+	0x1485fff9, 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094,
+	0x24040005, 0x24420001, 0x0a0004e5, 0xac620094, 0x24040004, 0x00809821,
+	0x9362003f, 0x304400ff, 0x38830016, 0x2c630001, 0x38820010, 0x2c420001,
+	0x00621825, 0x1460000c, 0x24020001, 0x38830008, 0x2c630001, 0x38820014,
+	0x2c420001, 0x00621825, 0x14600005, 0x24020001, 0x24020012, 0x14820002,
+	0x00001021, 0x24020001, 0x10400009, 0x00000000, 0x8ea20020, 0x8f630040,
+	0x0040b021, 0x00431023, 0x5c400010, 0x8f760040, 0x0a000511, 0x00000000,
+	0x9343010b, 0x24020004, 0x1462000a, 0x8eb60020, 0x8f630040, 0x3c021000,
+	0x00761823, 0x0043102a, 0x10400004, 0x00000000, 0x0000000d, 0x00000000,
+	0x240002fa, 0x9343010b, 0x24020004, 0x5462000b, 0x96a20008, 0x24020001,
+	0xafa20010, 0x96a20008, 0x24030001, 0xafa30018, 0x8eb2001c, 0x36730002,
+	0x30420020, 0x0a000526, 0xafa20014, 0x36730080, 0x30420002, 0x10400003,
+	0xafa00018, 0x0a000526, 0x8eb2001c, 0x8eb20014, 0x2402fffb, 0x02628024,
+	0x1200002a, 0x3c030800, 0x8c620030, 0x02021024, 0x10400026, 0x3c020800,
+	0x8c430020, 0x10600024, 0x32620004, 0x0e00148e, 0x00000000, 0x8f830018,
+	0x8f420100, 0xac620000, 0x8f840018, 0x02401821, 0x32620002, 0xac900004,
+	0x8f840018, 0x54400001, 0x02c01821, 0xac830008, 0x8f830018, 0x8ee20020,
+	0xac62000c, 0x8f840018, 0x8f620040, 0xac820010, 0x8f830018, 0x8ee20018,
+	0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
+	0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc,
+	0xaca3001c, 0x32620004, 0x10400063, 0x00003821, 0x3c029000, 0x34420001,
+	0x3c038000, 0x02821025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000,
+	0x8f65005c, 0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821,
+	0x00a2102b, 0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023,
+	0xaf710064, 0x3c023fff, 0x0a000580, 0x3442ffff, 0x8f62005c, 0x02221023,
+	0x04400011, 0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff,
+	0x3442ffff, 0xaf710064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004,
+	0x02251021, 0x3c053fff, 0x34a5ffff, 0x02251021, 0xaf62005c, 0x24070001,
+	0xaf71004c, 0x8f620054, 0x16220005, 0x00000000, 0x93620023, 0x30420040,
+	0x10400017, 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001,
+	0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804,
+	0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b,
+	0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021,
+	0xaf62000c, 0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000,
+	0x34420001, 0x02821025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004,
+	0x00000000, 0x0e0013c4, 0x00000000, 0x00403821, 0x54e00001, 0x241e0001,
+	0x8f700040, 0x8f620040, 0x14520003, 0x00521023, 0x0a0005bf, 0x00001021,
+	0x28420001, 0x10400041, 0x8fa20010, 0x0e000fae, 0x02402021, 0xaf720040,
+	0x9362003e, 0x30420001, 0x1440000b, 0x3c029000, 0x93620022, 0x24420001,
+	0xa3620022, 0x93630022, 0x3c020800, 0x8c440098, 0x0064182b, 0x14600027,
+	0x3c020800, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
+	0x34420001, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020,
+	0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050273, 0x0a0005f2,
+	0x24050001, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x24050001, 0x24020001, 0xa7620012,
+	0xa3600022, 0x0a0005fe, 0x2ca20001, 0x9743007a, 0x9444002a, 0x00002821,
+	0x00641821, 0x3063fffe, 0xa7630012, 0x2ca20001, 0x00021023, 0x03c2f024,
+	0x8fa20010, 0x10400004, 0x8fa30014, 0x0e0013c1, 0x00000000, 0x8fa30014,
+	0x10600003, 0x00000000, 0x0e0010eb, 0x00000000, 0x13c0001f, 0x3c029000,
+	0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074,
+	0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000, 0x02802021,
+	0x0e000470, 0x2405036c, 0x0a00062b, 0x8fa20018, 0x8f4201f8, 0x00431024,
+	0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, 0xaf4301f8,
+	0x8fa20018, 0x5040002f, 0x96a20008, 0x8f620048, 0x8f630024, 0x00761821,
+	0xaf630048, 0x9764003c, 0x00501023, 0x0044102b, 0x10400025, 0x3c029000,
+	0x34420001, 0x3c040800, 0x8c830080, 0x8f450100, 0x3c068000, 0x24630001,
+	0x00a21025, 0xac830080, 0xaf420020, 0x8f420020, 0x00461024, 0x1440fffd,
+	0x00000000, 0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074,
+	0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021,
+	0x0e000470, 0x2405038a, 0x0a00065b, 0x96a20008, 0x8f4201f8, 0x00431024,
+	0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8,
+	0x96a20008, 0x8fbf0044, 0x8fbe0040, 0x8fb7003c, 0x8fb60038, 0x8fb50034,
+	0x8fb40030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x00021042,
+	0x30420001, 0x03e00008, 0x27bd0048, 0x27bdffe0, 0xafbf0018, 0x97420108,
+	0x24030019, 0x304400ff, 0x10830065, 0x2882001a, 0x1040001a, 0x2882000a,
+	0x1040000f, 0x28820008, 0x10400040, 0x24020001, 0x1082003a, 0x28820002,
+	0x50400005, 0x24020006, 0x10800032, 0x3c026000, 0x0a0006fb, 0x00000000,
+	0x1082003d, 0x00000000, 0x0a0006fb, 0x00000000, 0x2402000b, 0x10820044,
+	0x2882000b, 0x1440004b, 0x2402000e, 0x10820045, 0x00000000, 0x0a0006fb,
+	0x00000000, 0x24020020, 0x10820062, 0x28820021, 0x1040000e, 0x2402001c,
+	0x1082004c, 0x2882001d, 0x10400005, 0x2402001b, 0x10820043, 0x00000000,
+	0x0a0006fb, 0x00000000, 0x2402001f, 0x10820050, 0x00000000, 0x0a0006fb,
+	0x00000000, 0x240200c1, 0x10820042, 0x288200c2, 0x10400005, 0x24020080,
+	0x10820021, 0x00000000, 0x0a0006fb, 0x00000000, 0x240200c2, 0x1082003d,
+	0x240200c9, 0x50820049, 0xafa00010, 0x0a0006fb, 0x00000000, 0x0e001163,
+	0xac400808, 0x0a0006fd, 0x8fbf0018, 0x3c026000, 0x8c444448, 0x3c030800,
+	0xac640064, 0x0e001163, 0x00000000, 0x3c026000, 0x8c444448, 0x3c030800,
+	0x0a0006fc, 0xac640068, 0x8f440100, 0x0e0006ff, 0x00000000, 0x3c026000,
+	0x8c444448, 0x3c030800, 0x0a0006fc, 0xac64006c, 0x0e001191, 0x00000000,
+	0x0a0006fd, 0x8fbf0018, 0x8f440100, 0x0e0011bb, 0x00000000, 0x0a0006fd,
+	0x8fbf0018, 0x0e001202, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0000000d,
+	0x0a0006fd, 0x8fbf0018, 0x0e000826, 0x00000000, 0x0a0006fd, 0x8fbf0018,
+	0x8f440100, 0x0e001264, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00134e,
+	0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00087c, 0x27440100, 0x0a0006fd,
+	0x8fbf0018, 0x8f640040, 0x0e000fae, 0x00000000, 0x0a0006fd, 0x8fbf0018,
+	0x8f440100, 0x0e001059, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e001417,
+	0x00000000, 0x0a0006fd, 0x8fbf0018, 0xafa00014, 0x8f440100, 0x8f450118,
+	0x8f46011c, 0x0e001439, 0x8f470120, 0x0a0006fd, 0x8fbf0018, 0x0000000d,
+	0x8fbf0018, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x9742010c,
+	0x1440005e, 0x00803821, 0x3c029000, 0x34420001, 0x00e21025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023,
+	0x30420010, 0x14400026, 0x3c030800, 0x8f630074, 0x3c027fff, 0x3442ffff,
+	0x00621824, 0xaf630074, 0x93620005, 0x34420001, 0xa3620005, 0x8f63004c,
+	0x8f620054, 0x10620021, 0x24040001, 0x9762006a, 0x00022880, 0x50a00001,
+	0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821,
+	0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050,
+	0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824,
+	0x00a21021, 0xaf62000c, 0x0a00073d, 0x24040001, 0x8c6200a8, 0x00002021,
+	0x24420001, 0xac6200a8, 0x0000000d, 0x00000000, 0x2400044d, 0x3c028000,
+	0x34420001, 0x00e21025, 0xaf420020, 0x1080001f, 0x3c029000, 0x34420001,
+	0x00e21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
+	0x00e31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00e02021, 0x0e000470,
+	0x24050455, 0x0a000761, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf4701c0, 0xa34201c4, 0xaf4301f8, 0x0e001163,
+	0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafbf0024,
+	0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x93630005,
+	0x00809821, 0x24020030, 0x30630030, 0x146200ac, 0x00a0a021, 0x3c020800,
+	0x8c430020, 0x106000a6, 0x00000000, 0x0e00148e, 0x00000000, 0x8f830018,
+	0xac730000, 0x936200c4, 0x30420002, 0x10400004, 0x24020001, 0x8f830018,
+	0x0a000784, 0x00000000, 0x8f830018, 0x24020003, 0xac620004, 0x8f6200dc,
+	0x8f630040, 0x00431023, 0x18400004, 0x00000000, 0x0000000d, 0x00000000,
+	0x24000509, 0x8f840018, 0x8f6200dc, 0xac820008, 0x8f830018, 0xac60000c,
+	0x8f820018, 0xac400010, 0x8f830018, 0x8f62004c, 0x3c100800, 0xac620014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x261258c0, 0x00002021, 0xaca30018,
+	0x9642000e, 0x8f850018, 0x3c034010, 0x00431025, 0x0e0014cc, 0xaca2001c,
+	0x8f830018, 0xac730000, 0x9362003e, 0x9363003f, 0x8f840018, 0x00021200,
+	0x00621825, 0xac830004, 0x93620081, 0x93630082, 0x8f840018, 0x00021600,
+	0x00031c00, 0x00431025, 0xac820008, 0x8f830018, 0x8f620040, 0xac62000c,
+	0x8f840018, 0x8f620048, 0xac820010, 0x8f71004c, 0x8f820018, 0xac510014,
+	0x8f620050, 0x8f850018, 0x00401821, 0x02221023, 0x5c400001, 0x02201821,
+	0x00002021, 0xaca30018, 0x9642000e, 0x8f850018, 0x3c03c00b, 0x00431025,
+	0x0e0014cc, 0xaca2001c, 0x8f620054, 0x8f840018, 0x00401821, 0x02221023,
+	0x5c400001, 0x02201821, 0xac830000, 0x8f840018, 0x8f630058, 0xac830004,
+	0x93620023, 0x30420010, 0x10400004, 0x00000000, 0x8f830018, 0x0a0007dd,
+	0x8f620148, 0x8f830018, 0x8f62005c, 0xac620008, 0x8f830018, 0x8f620060,
+	0xac62000c, 0x8f840018, 0x8f620064, 0xac820010, 0x97630068, 0x9762006a,
+	0x8f840018, 0x00031c00, 0x00431025, 0xac820014, 0x8f850018, 0x00002021,
+	0x2402ffff, 0x260358c0, 0xaca20018, 0x9462000e, 0x8f850018, 0x3c03c00c,
+	0x00431025, 0x0e0014cc, 0xaca2001c, 0x8f840018, 0x8f630018, 0xac830000,
+	0x936200c4, 0x30420002, 0x10400006, 0x00000000, 0x976200c8, 0x8f830018,
+	0x3042ffff, 0x0a000803, 0xac620004, 0x8f820018, 0xac400004, 0x8f830018,
+	0x8f62006c, 0xac620008, 0x8f840018, 0x8f6200dc, 0xac82000c, 0x8f830018,
+	0xac600010, 0x93620005, 0x8f830018, 0x00021600, 0x00541025, 0xac620014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x260258c0, 0xaca30018,
+	0x9443000e, 0x8f850018, 0x3c02400d, 0x00621825, 0x0e0014cc, 0xaca3001c,
+	0x0e00122e, 0x02602021, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb00010,
+	0x27500100, 0xafbf0018, 0xafb10014, 0x9603000c, 0x240200c1, 0x54620024,
+	0x8e040000, 0x3c029000, 0x8f450100, 0x34420001, 0x3c038000, 0x00a21025,
+	0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d,
+	0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x00a31825,
+	0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470, 0x240505b2,
+	0x0a000878, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002,
+	0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x0a000878, 0x8fbf0018,
+	0x8f65004c, 0x24060001, 0x0e0012a3, 0x240705be, 0x3c020800, 0x8c430020,
+	0x9611000c, 0x1060001d, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018,
+	0xac500000, 0x8f840018, 0x00111400, 0xac820004, 0x8f830018, 0xac600008,
+	0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f840018, 0x240205c1,
+	0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
+	0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc,
+	0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
+	0x27bdffb0, 0xafb5003c, 0x0000a821, 0xafbe0048, 0x0000f021, 0xafb70044,
+	0x0000b821, 0xafb30034, 0x00009821, 0xafb60040, 0x0080b021, 0xafbf004c,
+	0xafb40038, 0xafb20030, 0xafb1002c, 0xafb00028, 0xafa00010, 0x8f620040,
+	0x8ec30014, 0x96d1000c, 0x00431023, 0x04410025, 0x8ed40000, 0x32220401,
+	0x1040030c, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
+	0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020,
+	0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050664, 0x0a000ba2,
+	0x8fbf004c, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x0a000ba2, 0x8fbf004c, 0x32220010,
+	0x1040006b, 0x00003021, 0x9362003f, 0x92c6000f, 0x304500ff, 0x24c3fff8,
+	0x2c62000f, 0x10400057, 0x3c020800, 0x244257c0, 0x00031880, 0x00621821,
+	0x8c640000, 0x00800008, 0x00000000, 0x38a20012, 0x0a000924, 0x0002a82b,
+	0x2402000e, 0x14a20004, 0x2402000c, 0x24150001, 0x0a000924, 0x24060010,
+	0x10a20049, 0x38a30010, 0x2c630001, 0x38a20016, 0x2c420001, 0x00621825,
+	0x1460004d, 0x0000a821, 0x24020014, 0x10a2004a, 0x00000000, 0x0000000d,
+	0x00000000, 0x2400069c, 0x0a000924, 0x0000a821, 0x24020016, 0x14a20005,
+	0x2402000c, 0x24150001, 0x24060010, 0x0a000924, 0x3231fffd, 0x10a20032,
+	0x38a30010, 0x2c630001, 0x38a2000e, 0x2c420001, 0x00621825, 0x14600036,
+	0x0000a821, 0x24020014, 0x14a20003, 0x24150001, 0x0a000924, 0x24060012,
+	0x0000000d, 0x00000000, 0x240006bc, 0x0a000924, 0x0000a821, 0x2402000e,
+	0x14a20004, 0x24020016, 0x24150001, 0x0a000924, 0x3231fffb, 0x14a20004,
+	0x24020014, 0x24150001, 0x0a000924, 0x3231fffd, 0x54a20013, 0x92c2000e,
+	0x24150001, 0x24060012, 0x0a000924, 0x3231fffd, 0x2402000c, 0x54a2000c,
+	0x92c2000e, 0x92c3000e, 0x2402000a, 0x10620005, 0x24150001, 0x0000000d,
+	0x00000000, 0x240006e8, 0x24150001, 0x0a000924, 0x24060014, 0x92c2000e,
+	0x14a20003, 0x00000000, 0x0a000924, 0x24150001, 0x10a6ffc1, 0x24020012,
+	0x10a20005, 0x0000a821, 0x0000000d, 0x00000000, 0x24000704, 0x0000a821,
+	0x12a00022, 0x32220004, 0x10400002, 0x24020001, 0xafa20010, 0x32230102,
+	0x24020002, 0x1462000f, 0x00000000, 0x92c2000a, 0x30420020, 0x1440000b,
+	0x00000000, 0x8f630048, 0x8f620040, 0x14620004, 0x00000000, 0x8f620048,
+	0x24420001, 0xaf620048, 0x8f620040, 0x24420001, 0xaf620040, 0xa366003f,
+	0x38c30012, 0x2c630001, 0x38c20010, 0x2c420001, 0x00621825, 0x10600005,
+	0x3c030800, 0x8c620074, 0x24420001, 0x0e00140d, 0xac620074, 0x32220040,
+	0x32230020, 0xafa30020, 0x32230080, 0xafa30024, 0x32230001, 0xafa30018,
+	0x32230008, 0xafa3001c, 0x32230100, 0x104000c4, 0xafa30014, 0x8ec60010,
+	0x8f630054, 0x24c2ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d,
+	0x00000000, 0x2400015c, 0x0a000989, 0x00009021, 0x8f62004c, 0x00c21023,
+	0x18400028, 0x00009021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c,
+	0x308400ff, 0x24420001, 0x30a500ff, 0x00804021, 0x1485000b, 0xac62008c,
+	0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001,
+	0x00021023, 0x30420005, 0x0a000989, 0x34520004, 0x27670100, 0x00041080,
+	0x00e21021, 0x8c430000, 0x00c31823, 0x04600004, 0x24820001, 0x30440007,
+	0x1485fff9, 0x00041080, 0x10880007, 0x3c030800, 0xa3640121, 0x8c620094,
+	0x24120005, 0x24420001, 0x0a000989, 0xac620094, 0x24120004, 0x32420001,
+	0x10400021, 0x3c020800, 0x8c430020, 0x8ed00000, 0x1060001c, 0x8ed30010,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f820018, 0xac530014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010,
+	0x00621825, 0x0e0014cc, 0xaca3001c, 0x24130001, 0x32420004, 0x10400068,
+	0x00003821, 0x3c029000, 0x8ec60010, 0x34420001, 0x3c038000, 0x02821025,
+	0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
+	0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c,
+	0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006,
+	0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf660064, 0x3c023fff,
+	0x0a0009da, 0x3442ffff, 0x8f62005c, 0x00c21023, 0x04400011, 0x00000000,
+	0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf660064,
+	0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x00c51021, 0x3c053fff,
+	0x34a5ffff, 0x00c51021, 0xaf62005c, 0x24070001, 0xaf66004c, 0x8fa20010,
+	0x10400003, 0x00000000, 0xaf660050, 0xaf660054, 0x8f620054, 0x14c20005,
+	0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a,
+	0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800,
+	0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021,
+	0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074,
+	0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x93620082, 0x30420080,
+	0x50400001, 0xa3600081, 0x3c028000, 0x34420001, 0x02821025, 0xaf420020,
+	0x9363007e, 0x9362007a, 0x10620005, 0x00e0b821, 0x0e0013c4, 0x00000000,
+	0x00403821, 0x00e0b821, 0x8fa30020, 0x10600009, 0x8fa20010, 0x8ec20018,
+	0xaf620018, 0x8ec3001c, 0xaf63001c, 0x8ec20020, 0x24170001, 0xaf620058,
+	0x8fa20010, 0x10400057, 0x8fa30024, 0x93620023, 0x30420040, 0x10400053,
+	0x00000000, 0x16600021, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040001e,
+	0x24130001, 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018,
+	0x24020001, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
+	0x3c024010, 0x00621825, 0xaca3001c, 0x0e0014cc, 0x24130001, 0x8e420020,
+	0x1040001c, 0x8ed00000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000,
+	0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c,
+	0x8f820018, 0xac400010, 0x8f830018, 0x24020798, 0xac620014, 0x8f850018,
+	0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce,
+	0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000,
+	0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x24020001, 0xaf62000c, 0x93630023, 0x3c028000, 0x34420001,
+	0x02821025, 0x306300bf, 0xa3630023, 0xaf420020, 0x8fa30024, 0x10600012,
+	0x8fa30018, 0x9362007c, 0x24420001, 0xa362007c, 0x9363007e, 0x9362007a,
+	0x1462000b, 0x8fa30018, 0x9362007c, 0x3c030800, 0x8c640024, 0x0044102b,
+	0x14400005, 0x8fa30018, 0x0e0013c4, 0x00000000, 0x02e2b825, 0x8fa30018,
+	0x3062ffff, 0x10400003, 0x32220200, 0x0a000a94, 0x241e0004, 0x10400003,
+	0x00000000, 0x241e0040, 0x24170001, 0x12a000d0, 0x32220002, 0x104000cf,
+	0x8fa2001c, 0x92c2000a, 0x30420002, 0x5040003b, 0x92c2000a, 0x93620023,
+	0x30420008, 0x54400037, 0x92c2000a, 0x3c020800, 0x8c430020, 0x10600023,
+	0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000,
+	0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040,
+	0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018,
+	0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
+	0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
+	0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630008,
+	0xa3630023, 0xaf420020, 0x92c2000a, 0x30420020, 0x1040008e, 0x8fa2001c,
+	0x93620023, 0x30420001, 0x14400035, 0x3c020800, 0x8c430020, 0x10600023,
+	0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000,
+	0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040,
+	0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018,
+	0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
+	0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
+	0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630001,
+	0xa3630023, 0xaf420020, 0x93620023, 0x30420040, 0x10400052, 0x8fa2001c,
+	0x16600020, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040003c, 0x3c029000,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x24020001,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010,
+	0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x3c029000,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x3c02008d,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f840018, 0x240207ee, 0xac820014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
+	0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
+	0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x306300bf,
+	0xa3630023, 0xaf420020, 0x8fa2001c, 0x1040000e, 0x8fa20014, 0x92c2000a,
+	0xa3620082, 0x57c00005, 0x37de0008, 0x8fa30014, 0x10600004, 0x00000000,
+	0x37de0008, 0x0a000b75, 0x24170001, 0x0e0012cf, 0x02802021, 0x8fa20014,
+	0x10400003, 0x00000000, 0x37de0010, 0x24170001, 0x12e00020, 0x3c029000,
+	0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x03c21025, 0xa362007d,
+	0x8f640074, 0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000,
+	0x02802021, 0x0e000470, 0x2405082a, 0x0a000b9b, 0x00000000, 0x8f4201f8,
+	0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4,
+	0xaf4301f8, 0x9363003f, 0x24020012, 0x14620004, 0x8fbf004c, 0x0e00140d,
+	0x00000000, 0x8fbf004c, 0x8fbe0048, 0x8fb70044, 0x8fb60040, 0x8fb5003c,
+	0x8fb40038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x03e00008,
+	0x27bd0050, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f500180, 0x97420184,
+	0x30420200, 0x14400015, 0x00000000, 0x8f430188, 0x3c02ff00, 0x00621824,
+	0x3c020200, 0x10620031, 0x0043102b, 0x14400007, 0x3c020300, 0x1060000b,
+	0x3c020100, 0x1062000d, 0x00000000, 0x0a000c2c, 0x00000000, 0x10620027,
+	0x3c020400, 0x1062003e, 0x02002021, 0x0a000c2c, 0x00000000, 0x0e000c31,
+	0x02002021, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420020, 0x1440005e,
+	0x8fbf0014, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000,
+	0x34630001, 0x02031825, 0x34420020, 0xa3620005, 0xaf430020, 0x93620005,
+	0x30420020, 0x14400003, 0x02002021, 0x0000000d, 0x02002021, 0x0e000766,
+	0x24055854, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420001, 0x1040003f,
+	0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x93620023, 0x34420004, 0xa3620023,
+	0x93630005, 0x3c048000, 0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020,
+	0x34840001, 0x02042025, 0x0a000c0a, 0xaf440020, 0x00002821, 0x00003021,
+	0x0e000fb1, 0x240708d9, 0x3c020800, 0x8c430020, 0x10600023, 0x8fbf0014,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x93630082, 0x9362003f,
+	0x8f840018, 0x00031a00, 0x00431025, 0xac820004, 0x8f830018, 0xac600008,
+	0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
+	0x944358ce, 0x8f850018, 0x3c02400a, 0x00621825, 0x0e0014cc, 0xaca3001c,
+	0x0a000c2e, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x8f420188, 0x00803021, 0x93640000,
+	0x24030020, 0x00021402, 0x10830008, 0x304500ff, 0x3c036018, 0x8c625000,
+	0x34420400, 0xac625000, 0x0000000d, 0x00000000, 0x24000955, 0x9363003f,
+	0x24020012, 0x14620023, 0x3c029000, 0x34420001, 0x3c038000, 0x00c21025,
+	0xaf650178, 0xa365007a, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
+	0x00c31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00c02021, 0x0e000470,
+	0x24050963, 0x0a000c79, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a000c79,
+	0x8fbf0010, 0x9362007e, 0x1445000e, 0x00000000, 0x8f620178, 0x1045000b,
+	0x00000000, 0x8f820000, 0xaf650178, 0x8f660178, 0x8f440180, 0x8f65004c,
+	0x8c430000, 0x0060f809, 0x30c600ff, 0x0a000c79, 0x8fbf0010, 0xaf650178,
+	0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93630000,
+	0x24020020, 0x10620005, 0x00000000, 0x93630000, 0x24020030, 0x1462004d,
+	0x8fbf0010, 0x93420148, 0x2444ffff, 0x2c830005, 0x10600047, 0x3c020800,
+	0x24425800, 0x00041880, 0x00621821, 0x8c640000, 0x00800008, 0x00000000,
+	0x8f430144, 0x8f62000c, 0x14620006, 0x24020001, 0xaf62000c, 0x0e000d59,
+	0x00000000, 0x0a000cd1, 0x8fbf0010, 0x8f62000c, 0x0a000cca, 0x00000000,
+	0x97630010, 0x8f420144, 0x14430006, 0x24020001, 0xa7620010, 0x0e00137a,
+	0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620010, 0x0a000cca, 0x00000000,
+	0x97630012, 0x8f420144, 0x14430006, 0x24020001, 0xa7620012, 0x0e001395,
+	0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620012, 0x0a000cca, 0x00000000,
+	0x97630014, 0x8f420144, 0x14430006, 0x24020001, 0xa7620014, 0x0e0013bb,
+	0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620014, 0x0a000cca, 0x00000000,
+	0x97630016, 0x8f420144, 0x14430006, 0x24020001, 0xa7620016, 0x0e0013be,
+	0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620016, 0x14400006, 0x8fbf0010,
+	0x3c030800, 0x8c620070, 0x24420001, 0xac620070, 0x8fbf0010, 0x03e00008,
+	0x27bd0018, 0x27bdffe0, 0x3c029000, 0xafbf001c, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x8f500140, 0x34420001, 0x3c038000, 0x02021025, 0xaf420020,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x24020012, 0x24030080, 0xa362003f,
+	0xa3630082, 0x93620023, 0x30420040, 0x10400007, 0x00008821, 0x93620023,
+	0x24110001, 0x304200bf, 0xa3620023, 0x0a000cf0, 0x3c028000, 0x3c028000,
+	0x34420001, 0x3c039000, 0x34630001, 0x3c048000, 0x02021025, 0x02031825,
+	0xaf420020, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000,
+	0x9362007d, 0x3c038000, 0x34420020, 0xa362007d, 0x8f640074, 0x34630001,
+	0x02031825, 0xaf430020, 0x04810006, 0x3c038000, 0x02002021, 0x0e000470,
+	0x24050a63, 0x0a000d13, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf5001c0, 0xa34201c4, 0xaf4301f8, 0x1220003f,
+	0x3c120800, 0x8e420020, 0x8f71004c, 0x1040003c, 0x8fbf001c, 0x0e00148e,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac510014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825,
+	0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x8fbf001c, 0x0e00148e,
+	0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x3c02008d, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f840018, 0x24020a6a, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019,
+	0x00621825, 0x0e0014cc, 0xaca3001c, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x93620081,
+	0x3c030800, 0x8c640048, 0x0044102b, 0x14400005, 0x00000000, 0x0e000cd3,
+	0x00000000, 0x0a000da4, 0x8fbf0010, 0x93620081, 0x24420001, 0x0e0013c4,
+	0xa3620081, 0x9763006a, 0x00032880, 0x14a00002, 0x00403821, 0x24050001,
+	0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804,
+	0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b,
+	0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021,
+	0xaf62000c, 0x10e00021, 0x3c029000, 0x8f450140, 0x34420001, 0x3c038000,
+	0x00a21025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
+	0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001,
+	0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470,
+	0x24050a92, 0x0a000da4, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x8fbf0010,
+	0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafb3001c, 0x27530100, 0xafbf0024,
+	0xafb40020, 0xafb20018, 0xafb10014, 0xafb00010, 0x96620008, 0x3c140800,
+	0x8f520100, 0x30420001, 0x104000da, 0x00000000, 0x8e700018, 0x8f630054,
+	0x2602ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, 0x00000000,
+	0x2400015c, 0x0a000dea, 0x00008821, 0x8f62004c, 0x02021023, 0x18400028,
+	0x00008821, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff,
+	0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c, 0x3c040800,
+	0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, 0x00021023,
+	0x30420005, 0x0a000dea, 0x34510004, 0x27660100, 0x00041080, 0x00c21021,
+	0x8c430000, 0x02031823, 0x04600004, 0x24820001, 0x30440007, 0x1485fff9,
+	0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094, 0x24110005,
+	0x24420001, 0x0a000dea, 0xac620094, 0x24110004, 0x32220001, 0x1040001e,
+	0x8e820020, 0x1040001d, 0x32220004, 0x0e00148e, 0x00000000, 0x8f820018,
+	0xac520000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018, 0xac600008,
+	0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac500014,
+	0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
+	0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc, 0xaca3001c,
+	0x32220004, 0x10400081, 0x00003821, 0x3c029000, 0x34420001, 0x3c038000,
+	0x02421025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c,
+	0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b,
+	0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf700064,
+	0x3c023fff, 0x0a000e37, 0x3442ffff, 0x8f62005c, 0x02021023, 0x04400011,
+	0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff,
+	0xaf700064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x02051021,
+	0x3c053fff, 0x34a5ffff, 0x02051021, 0xaf62005c, 0x24070001, 0xaf70004c,
+	0x8f620054, 0x16020005, 0x00000000, 0x93620023, 0x30420040, 0x10400017,
+	0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068,
+	0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b,
+	0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001,
+	0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c,
+	0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000, 0x34420001,
+	0x02421025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, 0x00000000,
+	0x0e0013c4, 0x00000000, 0x00403821, 0x10e0001f, 0x3c029000, 0x34420001,
+	0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
+	0x02431825, 0xaf430020, 0x04810006, 0x3c038000, 0x02402021, 0x0e000470,
+	0x24050b3d, 0x0a000e8d, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
+	0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4, 0xaf4301f8, 0x9342010b,
+	0x9343010b, 0x8e820020, 0x27500100, 0x38630006, 0x10400029, 0x2c710001,
+	0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
+	0x96020008, 0xac820004, 0x8f830018, 0x8e020014, 0xac620008, 0x8f850018,
+	0x3c026000, 0x8c434448, 0xaca3000c, 0x8f840018, 0x96020012, 0xac820010,
+	0x8f850018, 0x8e030020, 0xaca30014, 0x9602000c, 0x9603000e, 0x8f840018,
+	0x00021400, 0x00431025, 0xac820018, 0x12200005, 0x3c020800, 0x944358ce,
+	0x8f840018, 0x0a000eb8, 0x3c024013, 0x944358ce, 0x8f840018, 0x3c024014,
+	0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8e700014, 0x8f620040,
+	0x14500003, 0x00501023, 0x0a000ec3, 0x00001021, 0x28420001, 0x1040003a,
+	0x00000000, 0x0e000fae, 0x02002021, 0xaf700040, 0x9362003e, 0x30420001,
+	0x1440000b, 0x3c029000, 0x93620022, 0x24420001, 0xa3620022, 0x93630022,
+	0x3c020800, 0x8c440098, 0x0064182b, 0x14600025, 0x3c020800, 0x3c029000,
+	0x34420001, 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d,
+	0x8f640074, 0x34630001, 0x02431825, 0xaf430020, 0x04810006, 0x3c038000,
+	0x02402021, 0x0e000470, 0x24050273, 0x0a000ef6, 0x24020001, 0x8f4201f8,
+	0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4,
+	0xaf4301f8, 0x24020001, 0xa7620012, 0x0a000efe, 0xa3600022, 0x9743007a,
+	0x9444002a, 0x00641821, 0x3063fffe, 0xa7630012, 0x97420108, 0x8fbf0024,
+	0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042,
+	0x30420001, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb20018, 0x3c120800,
+	0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400046, 0xafb10014,
+	0x0e00148e, 0x00000000, 0x8f840018, 0x8e020000, 0xac820000, 0x936300b1,
+	0x936200c5, 0x8f850018, 0x00031e00, 0x00021400, 0x34420100, 0x00621825,
+	0xaca30004, 0x8f840018, 0x8e02001c, 0xac820008, 0x8f830018, 0x8f620048,
+	0xac62000c, 0x8f840018, 0x96020012, 0xac820010, 0x8f830018, 0x8f620040,
+	0x24040001, 0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800,
+	0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018, 0x3c024016, 0x00621825,
+	0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010, 0x1060001c, 0x8e420020,
+	0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000,
+	0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c,
+	0x8f820018, 0xac400010, 0x8f830018, 0xac600014, 0x8f850018, 0x3c036000,
+	0x8c634448, 0x24040001, 0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015,
+	0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0xafb20018,
+	0x3c120800, 0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400041,
+	0xafb10014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000,
+	0x8f840018, 0x24020100, 0xac820004, 0x8f830018, 0x8e02001c, 0xac620008,
+	0x8f840018, 0x8e020018, 0xac82000c, 0x8f830018, 0x96020012, 0xac620010,
+	0x8f840018, 0x96020008, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x24040001, 0x3c020800, 0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018,
+	0x3c024017, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010,
+	0x1060001c, 0x8e420020, 0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000,
+	0x8f820018, 0xac500000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008,
+	0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0xac600014,
+	0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, 0xaca30018, 0x9622000e,
+	0x8f850018, 0x3c034015, 0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021,
+	0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
+	0x27bdfff0, 0x03e00008, 0x27bd0010, 0x27bdffd0, 0xafb10014, 0x00808821,
+	0xafb40020, 0x00c0a021, 0xafbf0028, 0xafb50024, 0xafb3001c, 0xafb20018,
+	0xafb00010, 0x93620023, 0x00e0a821, 0x30420040, 0x1040003e, 0x30b3ffff,
+	0x3c120800, 0x8e420020, 0x1040003a, 0x8f70004c, 0x0e00148e, 0x00000000,
+	0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018,
+	0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
+	0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800,
+	0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010, 0x00621825,
+	0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001b, 0x00000000, 0x0e00148e,
+	0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x3c02008d, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac550014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001,
+	0xaca30018, 0x9602000e, 0x8f850018, 0x3c034019, 0x00431025, 0x0e0014cc,
+	0xaca2001c, 0x93620023, 0x30420020, 0x14400003, 0x3c120800, 0x1280003f,
+	0x3c029000, 0x8e420020, 0x8f70004c, 0x1040003b, 0x3c029000, 0x0e00148e,
+	0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448,
+	0x3c020800, 0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010,
+	0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001c, 0x3c029000,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x00131400,
+	0xac820004, 0x8f830018, 0xac750008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c036000, 0x8c634448,
+	0x24040001, 0xaca30018, 0x9602000e, 0x8f850018, 0x3c03401b, 0x00431025,
+	0x0e0014cc, 0xaca2001c, 0x3c029000, 0x34420001, 0x02221025, 0xaf420020,
+	0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023,
+	0x3c028000, 0x34420001, 0x02221025, 0x8fbf0028, 0x8fb50024, 0x8fb40020,
+	0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3063009f, 0xa3630023,
+	0xaf420020, 0x03e00008, 0x27bd0030, 0x27bdffe0, 0xafb10014, 0x27510100,
+	0x3c029000, 0x34420001, 0xafb00010, 0x00808021, 0x02021025, 0x3c038000,
+	0xafbf0018, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
+	0xa7600008, 0x8f63005c, 0x3c028000, 0x34420001, 0xaf630148, 0x8f640050,
+	0x02021025, 0x3c039000, 0xaf64017c, 0xaf420020, 0x8f450100, 0x34630001,
+	0x3c048000, 0x00a31825, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd,
+	0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d, 0x8f640074,
+	0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021,
+	0x0e000470, 0x24050de5, 0x0a001093, 0x3c020800, 0x8f4201f8, 0x00431024,
+	0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8,
+	0x3c020800, 0x8c430020, 0x1060001e, 0x8fbf0018, 0x0e00148e, 0x00000000,
+	0x8f830018, 0xac700000, 0x9622000c, 0x8f840018, 0x00021400, 0xac820004,
+	0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
+	0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401f, 0x00621825,
+	0x0e0014cc, 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008,
+	0x27bd0020, 0x3c020800, 0x24424c3c, 0xaf82000c, 0x03e00008, 0x00000000,
+	0x27bdffe8, 0xafb00010, 0x27500100, 0xafbf0014, 0x8e02001c, 0x14400003,
+	0x3c020800, 0x0000000d, 0x3c020800, 0x8c430020, 0x10600020, 0x00001021,
+	0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
+	0x8e02001c, 0xac820004, 0x8f830018, 0xac600008, 0x8f840018, 0x8e020018,
+	0xac82000c, 0x8f850018, 0x96020012, 0xaca20010, 0x8f830018, 0x3c026000,
+	0xac600014, 0x8f840018, 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce,
+	0x8f840018, 0x3c024012, 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001,
+	0x00001021, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800,
+	0x97430078, 0x9444002e, 0x00001021, 0x00641821, 0x3063fffe, 0x03e00008,
+	0xa7630010, 0x27bdfff0, 0x00001021, 0x03e00008, 0x27bd0010, 0x8f420100,
+	0x34420001, 0xaf4200a4, 0x03e00008, 0x00001021, 0x27bdffe0, 0xafbf0018,
+	0xafb10014, 0xafb00010, 0x9362007e, 0x30d000ff, 0x16020031, 0x00808821,
+	0x8f620178, 0x1602002e, 0x00000000, 0x9362007f, 0x1602002b, 0x00000000,
+	0x9362007a, 0x16020004, 0x00000000, 0x0000000d, 0x00000000, 0x240009d2,
+	0x0e0013e6, 0x00000000, 0x3c039000, 0x34630001, 0x3c048000, 0x02231825,
+	0xa370007a, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000,
+	0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, 0x02231825,
+	0xaf430020, 0x04810006, 0x3c038000, 0x02202021, 0x0e000470, 0x240509dd,
+	0x0a001138, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002,
+	0x3c031000, 0xaf5101c0, 0xa34201c4, 0xaf4301f8, 0x0a001138, 0x8fbf0018,
+	0x0000000d, 0x00000000, 0x240009e2, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x27bdffe8, 0x30a500ff, 0x3c029000, 0x34420001,
+	0x00803821, 0x00e21025, 0x3c038000, 0xafbf0010, 0xaf420020, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x00a21025,
+	0xa362007d, 0x8f640074, 0x34630001, 0x00e31825, 0xaf430020, 0x04810006,
+	0x3c038000, 0x00e02021, 0x0e000470, 0x00c02821, 0x0a001161, 0x8fbf0010,
+	0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4701c0,
+	0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800,
+	0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x10600024, 0xafbf0014,
+	0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
+	0x8e020004, 0xac820004, 0x8f830018, 0x8e020018, 0xac620008, 0x8f840018,
+	0x8e03001c, 0xac83000c, 0x9602000c, 0x9203000a, 0x8f840018, 0x00021400,
+	0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
+	0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018,
+	0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8,
+	0xafb00010, 0x27500100, 0x10600020, 0xafbf0014, 0x0e00148e, 0x00000000,
+	0x8f820018, 0xac400000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008,
+	0x8f830018, 0xac60000c, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400,
+	0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
+	0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018,
+	0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010, 0x27500100,
+	0xafbf0014, 0x9602000c, 0x10400024, 0x00802821, 0x3c020800, 0x8c430020,
+	0x1060003a, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f840018, 0x8e030000,
+	0xac830000, 0x9602000c, 0x8f840018, 0x00021400, 0xac820004, 0x8f830018,
+	0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
+	0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
+	0xaca30018, 0x944358ce, 0x8f850018, 0x3c02400b, 0x00621825, 0x0e0014cc,
+	0xaca3001c, 0x0a0011ff, 0x8fbf0014, 0x93620005, 0x30420010, 0x14400015,
+	0x3c029000, 0x34420001, 0x00a21025, 0xaf420020, 0x3c038000, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x93620005, 0x34630001,
+	0x00a02021, 0x00a31825, 0x24055852, 0x34420010, 0xa3620005, 0x0e000766,
+	0xaf430020, 0x0a0011ff, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010,
+	0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010,
+	0x27500100, 0x10600022, 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f840018,
+	0x8e020004, 0xac820000, 0x9603000c, 0x9762002c, 0x8f840018, 0x00031c00,
+	0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000,
+	0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
+	0x3c02400e, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x0e00122e, 0x8e040000,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c038000, 0x8f420278,
+	0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf440240, 0xa3420244,
+	0x03e00008, 0xaf430278, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014,
+	0x00808821, 0xafb20018, 0x00c09021, 0xafb00010, 0x30b0ffff, 0x1060001c,
+	0xafbf001c, 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018,
+	0x00101400, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
+	0x8f830018, 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000,
+	0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024019,
+	0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x27450100,
+	0xafbf0010, 0x94a3000c, 0x240200c1, 0x14620031, 0x00803021, 0x3c029000,
+	0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
+	0x1440fffd, 0x3c028000, 0x34420001, 0x3c049000, 0x34840001, 0x3c058000,
+	0x24030012, 0x00c21025, 0x00c42025, 0xa363003f, 0xaf420020, 0xaf440020,
+	0x8f420020, 0x00451024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
+	0x34420020, 0xa362007d, 0x8f640074, 0x34630001, 0x00c31825, 0xaf430020,
+	0x04810006, 0x3c038000, 0x00c02021, 0x0e000470, 0x24050906, 0x0a0012a1,
+	0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
+	0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a0012a1, 0x8fbf0010, 0x00c02021,
+	0x94a5000c, 0x24060001, 0x0e000fb1, 0x2407090e, 0x8fbf0010, 0x03e00008,
+	0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00808021,
+	0xafb20018, 0x00a09021, 0xafb10014, 0x30d100ff, 0x1060001c, 0xafbf001c,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000, 0x8c434448,
+	0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024010, 0x00621825,
+	0xac83001c, 0x0e0014cc, 0x02202021, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010,
+	0x93620005, 0x30420001, 0x10400036, 0x00808021, 0x3c029000, 0x34420001,
+	0x02021025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x93620023, 0x34420004, 0xa3620023, 0x93630005, 0x3c048000,
+	0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020, 0x34840001, 0x02042025,
+	0xaf440020, 0x10600020, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f820018,
+	0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00, 0x00431025,
+	0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
+	0xac600010, 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448,
+	0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c02400a, 0x00621825,
+	0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf0014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014, 0x00808821,
+	0xafb20018, 0x00a09021, 0xafb00010, 0x30d000ff, 0x1060002f, 0xafbf001c,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f830018, 0xac700004,
+	0x8f820018, 0xac520008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
+	0x9763006a, 0x00032880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081,
+	0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001,
+	0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021,
+	0x8f830018, 0x2402fffe, 0x00822824, 0x3c026000, 0xac650014, 0x8f840018,
+	0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024011,
+	0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014,
+	0xafb00010, 0x8f440100, 0x27500100, 0x8f650050, 0x0e0010fc, 0x9206001b,
+	0x3c020800, 0x8c430020, 0x1060001d, 0x8e100018, 0x0e00148e, 0x00000000,
+	0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f840018,
+	0x8f620050, 0xac820008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
+	0x8f830018, 0x3c026000, 0xac600014, 0x8f850018, 0x8c434448, 0x24040001,
+	0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401c, 0x00621825,
+	0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018,
+	0x8f430238, 0x3c020800, 0x04610013, 0x8c44009c, 0x2406fffe, 0x3c050800,
+	0x3c038000, 0x2484ffff, 0x14800009, 0x00000000, 0x97420078, 0x8ca3007c,
+	0x24420001, 0x00461024, 0x24630001, 0xa7620010, 0x03e00008, 0xaca3007c,
+	0x8f420238, 0x00431024, 0x1440fff3, 0x2484ffff, 0x8f420140, 0x3c031000,
+	0xaf420200, 0x03e00008, 0xaf430238, 0x27bdffe8, 0x3c029000, 0xafbf0010,
+	0x8f450140, 0x34420001, 0x3c038000, 0x00a21025, 0xaf420020, 0x8f420020,
+	0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001,
+	0xa362007d, 0x8f640074, 0x34630001, 0x00a31825, 0xaf430020, 0x04810006,
+	0x3c038000, 0x00a02021, 0x0e000470, 0x24050ac7, 0x0a0013b9, 0x8fbf0010,
+	0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0,
+	0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x0000000d,
+	0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x24020001,
+	0x03e00008, 0xa7620010, 0x9362003f, 0x304400ff, 0x3883000e, 0x2c630001,
+	0x38820010, 0x2c420001, 0x00621825, 0x14600003, 0x24020012, 0x14820003,
+	0x00000000, 0x03e00008, 0x00001021, 0x9363007e, 0x9362007a, 0x14620006,
+	0x00000000, 0x9363007e, 0x24020001, 0x24630001, 0x03e00008, 0xa363007e,
+	0x9362007e, 0x8f630178, 0x304200ff, 0x14430006, 0x00000000, 0x9363000b,
+	0x24020001, 0x24630001, 0x03e00008, 0xa363000b, 0x03e00008, 0x00001021,
+	0x9362000b, 0x10400023, 0x00001021, 0xa360000b, 0x9362003f, 0x304400ff,
+	0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, 0x00621825, 0x14600017,
+	0x00001821, 0x24020012, 0x10820014, 0x00000000, 0x9363007e, 0x9362007a,
+	0x14620007, 0x00000000, 0x9362007e, 0x24030001, 0x24420001, 0xa362007e,
+	0x03e00008, 0x00601021, 0x9362007e, 0x8f630178, 0x304200ff, 0x14430005,
+	0x00001821, 0x9362000b, 0x24030001, 0x24420001, 0xa362000b, 0x03e00008,
+	0x00601021, 0x03e00008, 0x00000000, 0x24040001, 0xaf64000c, 0x8f6300dc,
+	0x8f6200cc, 0x50620001, 0xa7640010, 0xa7640012, 0xa7640014, 0x03e00008,
+	0xa7640016, 0x3c020800, 0x8c430020, 0x27bdffe8, 0x1060001b, 0xafbf0010,
+	0x0e00148e, 0x00000000, 0x8f820018, 0xac400000, 0x8f830018, 0xac600004,
+	0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
+	0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, 0x8c434448, 0x3c020800,
+	0xac830018, 0x944358ce, 0x8f840018, 0x3c024020, 0x00621825, 0xac83001c,
+	0x0e0014cc, 0x24040001, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800,
+	0x8c430020, 0x27bdffe0, 0xafb00010, 0x00a08021, 0xafb10014, 0x00c08821,
+	0xafb20018, 0x00e09021, 0x1060001e, 0xafbf001c, 0x0e00148e, 0x00000000,
+	0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f820018,
+	0xac510008, 0x8f830018, 0xac72000c, 0x8f840018, 0x8fa20030, 0xac820010,
+	0x8f830018, 0x8fa20034, 0xac620014, 0x8f840018, 0x3c026000, 0x8c434448,
+	0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c0240c9, 0x00621825,
+	0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, 0x8c430020, 0x27bdffe8,
+	0xafb00010, 0x27500100, 0x1060001d, 0xafbf0014, 0x0e00148e, 0x00000000,
+	0x8f830018, 0x8e020004, 0xac620000, 0x8f840018, 0x8e020018, 0xac820004,
+	0x8f850018, 0x8e020000, 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018,
+	0xac400010, 0x8f830018, 0xac600014, 0x8f820018, 0xac400018, 0x96030008,
+	0x3c020800, 0x944458ce, 0x8f850018, 0x00031c00, 0x00641825, 0x24040001,
+	0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018,
+	0x3c060800, 0x24c558c0, 0x3c02000a, 0x03421821, 0x94640006, 0x94a2000a,
+	0x00441023, 0x00021400, 0x00021c03, 0x04610006, 0xa4a40006, 0x0000000d,
+	0x00000000, 0x2400005a, 0x0a0014a3, 0x24020001, 0x8f820014, 0x0062102b,
+	0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1040001c, 0x274a0400,
+	0x3c07000a, 0x3c020800, 0x244558c0, 0x94a9000a, 0x8f880014, 0x03471021,
+	0x94430006, 0x00402021, 0xa4a30006, 0x94820006, 0xa4a20006, 0x01221023,
+	0x00021400, 0x00021403, 0x04410006, 0x0048102b, 0x0000000d, 0x00000000,
+	0x2400005a, 0x0a0014be, 0x24020001, 0x14400002, 0x00001021, 0x24020001,
+	0x304200ff, 0x1440ffec, 0x03471021, 0x24c458c0, 0x8c820010, 0xaf420038,
+	0x8c830014, 0x3c020005, 0xaf43003c, 0xaf420030, 0xaf800010, 0xaf8a0018,
+	0x03e00008, 0x00000000, 0x27bdffe0, 0x8f820010, 0x8f850018, 0x3c070800,
+	0x24e858c0, 0xafbf001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x9503000a,
+	0x8d060014, 0x00009021, 0x309000ff, 0x00e08821, 0x24420001, 0x24a50020,
+	0x24630001, 0xaf820010, 0xaf850018, 0xa503000a, 0x24c30020, 0x3c028000,
+	0x04c10007, 0xad030014, 0x00621024, 0x14400005, 0x262258c0, 0x8d020010,
+	0x24420001, 0xad020010, 0x262258c0, 0x9444000a, 0x94450018, 0x0010102b,
+	0x00a41826, 0x2c630001, 0x00621825, 0x1060001c, 0x3c030006, 0x8f820010,
+	0x24120001, 0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000,
+	0x00000000, 0x27450400, 0x8f420000, 0x30420010, 0x1040fffd, 0x262258c0,
+	0x9444000a, 0x94430018, 0xaf800010, 0xaf850018, 0x14830012, 0x262758c0,
+	0x0e00155a, 0x00000000, 0x1600000e, 0x262758c0, 0x0e00148e, 0x00000000,
+	0x0a001517, 0x262758c0, 0x00041c00, 0x00031c03, 0x00051400, 0x00021403,
+	0x00621823, 0x18600002, 0x3c026000, 0xac400808, 0x262758c0, 0x94e2000e,
+	0x94e3000c, 0x24420001, 0xa4e2000e, 0x3042ffff, 0x50430001, 0xa4e0000e,
+	0x12000005, 0x3c02000a, 0x94e2000a, 0xa74200a2, 0x0a001554, 0x02401021,
+	0x03421821, 0x94640006, 0x94e2000a, 0x00441023, 0x00021400, 0x00021c03,
+	0x04610006, 0xa4e40006, 0x0000000d, 0x00000000, 0x2400005a, 0x0a001536,
+	0x24020001, 0x8f820014, 0x0062102b, 0x14400002, 0x00001021, 0x24020001,
+	0x304200ff, 0x1040001b, 0x3c020800, 0x3c06000a, 0x244558c0, 0x94a8000a,
+	0x8f870014, 0x03461021, 0x94430006, 0x00402021, 0xa4a30006, 0x94820006,
+	0xa4a20006, 0x01021023, 0x00021400, 0x00021403, 0x04410006, 0x0047102b,
+	0x0000000d, 0x00000000, 0x2400005a, 0x0a001550, 0x24020001, 0x14400002,
+	0x00001021, 0x24020001, 0x304200ff, 0x1440ffec, 0x03461021, 0x02401021,
+	0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
+	0x3c020800, 0x244558c0, 0x94a3001a, 0x8ca40024, 0x00403021, 0x000318c0,
+	0x00832021, 0xaf44003c, 0x8ca20020, 0xaf420038, 0x3c020050, 0x34420008,
+	0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x8f420000, 0x30420020,
+	0x1040fffd, 0x00000000, 0x8f430400, 0x24c658c0, 0xacc30010, 0x8f420404,
+	0x3c030020, 0xacc20014, 0xaf430030, 0x94c40018, 0x94c3001c, 0x94c2001a,
+	0x94c5001e, 0x00832021, 0x24420001, 0xa4c2001a, 0x3042ffff, 0x14450002,
+	0xa4c40018, 0xa4c0001a, 0x03e00008, 0x00000000, 0x8f820010, 0x3c030006,
+	0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000, 0x00000000,
+	0x27430400, 0x8f420000, 0x30420010, 0x1040fffd, 0x00000000, 0xaf800010,
+	0xaf830018, 0x03e00008, 0x00000000, 0x27bdffe8, 0xafb00010, 0x3c100800,
+	0x261058c0, 0x3c05000a, 0x02002021, 0x03452821, 0xafbf0014, 0x0e0015b0,
+	0x2406000a, 0x96020002, 0x9603001e, 0x3042000f, 0x24420003, 0x00431804,
+	0x24027fff, 0x0043102b, 0xaf830014, 0x10400004, 0x00000000, 0x0000000d,
+	0x00000000, 0x24000043, 0x0e00155a, 0x00000000, 0x8fbf0014, 0x8fb00010,
+	0x03e00008, 0x27bd0018, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff,
+	0x24a50004, 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000,
+	0x0a0015c1, 0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004,
+	0x00a01021, 0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c036000,
+	0x8c642b7c, 0x3c036010, 0x8c6553fc, 0x00041582, 0x00042302, 0x308403ff,
+	0x00052d82, 0x00441026, 0x0002102b, 0x0005282b, 0x00451025, 0x1440000d,
+	0x3c020050, 0x34420004, 0xaf400038, 0xaf40003c, 0xaf420030, 0x00000000,
+	0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, 0x3c020020, 0xaf420030,
+	0x0000000d, 0x03e00008, 0x00000000, 0x3c020050, 0x34420004, 0xaf440038,
+	0xaf45003c, 0xaf420030, 0x00000000, 0x00000000, 0x8f420000, 0x30420020,
+	0x1040fffd, 0x3c020020, 0xaf420030, 0x03e00008, 0x00000000, 0x00000000};
+
+static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = {
+	0x08002428, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c,
+	0x08002380, 0x0800245c, 0x080023e4, 0x0800245c, 0x0800231c, 0x0800245c,
+	0x0800245c, 0x0800245c, 0x08002328, 0x00000000, 0x08003240, 0x08003270,
+	0x080032a0, 0x080032d0, 0x08003300, 0x00000000, 0x00000000 };
+static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
+static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x0 };
+
+static int bnx2_RXP_b06FwReleaseMajor = 0x1;
+static int bnx2_RXP_b06FwReleaseMinor = 0x0;
+static int bnx2_RXP_b06FwReleaseFix = 0x0;
+static u32 bnx2_RXP_b06FwStartAddr = 0x08003184;
+static u32 bnx2_RXP_b06FwTextAddr = 0x08000000;
+static int bnx2_RXP_b06FwTextLen = 0x588c;
+static u32 bnx2_RXP_b06FwDataAddr = 0x080058e0;
+static int bnx2_RXP_b06FwDataLen = 0x0;
+static u32 bnx2_RXP_b06FwRodataAddr = 0x08005890;
+static int bnx2_RXP_b06FwRodataLen = 0x28;
+static u32 bnx2_RXP_b06FwBssAddr = 0x08005900;
+static int bnx2_RXP_b06FwBssLen = 0x13a4;
+static u32 bnx2_RXP_b06FwSbssAddr = 0x080058e0;
+static int bnx2_RXP_b06FwSbssLen = 0x1c;
+static u32 bnx2_RXP_b06FwText[(0x588c/4) + 1] = {
+	0x0a000c61, 0x00000000, 0x00000000, 0x0000000d, 0x72787020, 0x322e362e,
+	0x31000000, 0x02060103, 0x00000000, 0x0000000d, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d,
+	0x3c020800, 0x244258e0, 0x3c030800, 0x24636ca4, 0xac400000, 0x0043202b,
+	0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800,
+	0x26103184, 0x3c1c0800, 0x279c58e0, 0x0e00104a, 0x00000000, 0x0000000d,
+	0x27bdffe8, 0xafb00010, 0xafbf0014, 0x0e000f1d, 0x00808021, 0x1440000d,
+	0x00000000, 0x8f820010, 0x10400005, 0x00000000, 0x9743011c, 0x9742011e,
+	0x0a000c89, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825,
+	0xaf830004, 0x8f840008, 0x3c020020, 0x34424000, 0x00821824, 0x54620004,
+	0x3c020020, 0x8f820014, 0x0a000c9a, 0x34421000, 0x34428000, 0x00821824,
+	0x14620004, 0x00000000, 0x8f820014, 0x34428000, 0xaf820014, 0x8f820008,
+	0x9743010c, 0x00403021, 0x30421000, 0x10400010, 0x3069ffff, 0x30c20020,
+	0x1440000e, 0x24070005, 0x3c021000, 0x00c21024, 0x10400009, 0x3c030dff,
+	0x3463ffff, 0x3c020e00, 0x00c21024, 0x0062182b, 0x50600004, 0x24070001,
+	0x0a000cb2, 0x3c020800, 0x24070001, 0x3c020800, 0x8c430034, 0x1460001d,
+	0x00405821, 0x8f820014, 0x30424000, 0x1440001a, 0x3c020001, 0x3c021f01,
+	0x00c24024, 0x3c031000, 0x15030015, 0x3c020001, 0x31220200, 0x14400012,
+	0x3c020001, 0x9744010e, 0x24020003, 0xa342018b, 0x97850016, 0x24020002,
+	0x34e30002, 0xaf400180, 0xa742018c, 0xa7430188, 0x24840004, 0x30a5bfff,
+	0xa744018e, 0xa74501a6, 0xaf4801b8, 0x0a000f19, 0x00001021, 0x3c020001,
+	0x00c21024, 0x1040002f, 0x00000000, 0x9742010e, 0x3c038000, 0x3046ffff,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9784000a,
+	0x8f850004, 0x8f870014, 0x24020080, 0x24030002, 0xaf420180, 0x24020003,
+	0xa743018c, 0xa746018e, 0xa7420188, 0x30e28000, 0xa7440190, 0x1040000c,
+	0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000,
+	0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00e21024, 0xaf820014,
+	0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff,
+	0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19,
+	0x00001021, 0x8f820014, 0x30434000, 0x10600016, 0x00404021, 0x3c020f00,
+	0x00c21024, 0x14400012, 0x00000000, 0x93420116, 0x34424000, 0x03421821,
+	0x94650002, 0x2ca21389, 0x1040000b, 0x3c020800, 0x24425900, 0x00051942,
+	0x00031880, 0x00621821, 0x30a5001f, 0x8c640000, 0x24020001, 0x00a21004,
+	0x00822024, 0x02048025, 0x12000030, 0x3c021000, 0x9742010e, 0x34e80002,
+	0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020180,
+	0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000,
+	0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00e21024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x0a000f19, 0x00001021, 0x00c21024, 0x104000c0, 0x3c020800,
+	0x8c430030, 0x10600037, 0x31024000, 0x10400035, 0x3c030f00, 0x00c31824,
+	0x3c020100, 0x0043102b, 0x14400031, 0x3c030800, 0x9742010e, 0x34e80002,
+	0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020080,
+	0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000,
+	0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x00e21024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x0a000f19, 0x00001021, 0x3c030800, 0x8c620024, 0x30420008,
+	0x10400035, 0x34ea0002, 0x3c020f00, 0x00c21024, 0x14400032, 0x8d620034,
+	0x31220200, 0x1040002f, 0x8d620034, 0x9742010e, 0x30e8fffb, 0x3c038000,
+	0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
+	0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020180, 0x24030002,
+	0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000, 0xa7440190,
+	0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
+	0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00e21024,
+	0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
+	0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
+	0x8d620034, 0x8f860008, 0x10400012, 0x30c20100, 0x10400010, 0x3c020f00,
+	0x00c21024, 0x3c030200, 0x1043000c, 0x3c020800, 0x8c430038, 0x8f840004,
+	0x3c020800, 0x2442003c, 0x2463ffff, 0x00832024, 0x00822021, 0x90830000,
+	0x24630004, 0x0a000de1, 0x000329c0, 0x00000000, 0x00061602, 0x3042000f,
+	0x000229c0, 0x3c04fc00, 0x00441021, 0x3c030300, 0x0062182b, 0x50600001,
+	0x24050800, 0x9742010e, 0x3148ffff, 0x3c038000, 0x24420004, 0x3046ffff,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
+	0x8f840004, 0x8f870014, 0x24020002, 0xaf450180, 0xa742018c, 0xa746018e,
+	0xa7480188, 0x30e28000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116,
+	0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004,
+	0x3c02ffff, 0x34427fff, 0x00e21024, 0xaf820014, 0x97820016, 0x9743010c,
+	0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
+	0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x8f424000,
+	0x30420100, 0x104000d5, 0x3c020800, 0x8c440024, 0x24030001, 0x1483002f,
+	0x00405021, 0x9742010e, 0x34e70002, 0x3c038000, 0x24420004, 0x3045ffff,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
+	0x8f840004, 0x8f860014, 0x24020002, 0xaf400180, 0xa742018c, 0xa745018e,
+	0xa7470188, 0x30c28000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116,
+	0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004,
+	0x3c02ffff, 0x34427fff, 0x00c21024, 0xaf820014, 0x97820016, 0x9743010c,
+	0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
+	0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x30820001,
+	0x1040002e, 0x30eb0004, 0x9742010e, 0x30e9fffb, 0x3c038000, 0x24420004,
+	0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b,
+	0x9783000a, 0x8f840004, 0x8f860014, 0x24020002, 0xaf400180, 0xa742018c,
+	0xa745018e, 0xa7470188, 0x30c28000, 0xa7430190, 0x1040000c, 0xaf4401a8,
+	0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff,
+	0x14600004, 0x3c02ffff, 0x34427fff, 0x00c21024, 0xaf820014, 0x97820016,
+	0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825,
+	0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x3127ffff, 0x8d420024,
+	0x30420004, 0x10400030, 0x8d420024, 0x9742010e, 0x30e9fffb, 0x3c038000,
+	0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
+	0xa342018b, 0x9784000a, 0x8f850004, 0x8f880014, 0x24020100, 0x24030002,
+	0xaf420180, 0xa743018c, 0xa746018e, 0xa7470188, 0x31028000, 0xa7440190,
+	0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
+	0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x01021024,
+	0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
+	0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
+	0x3127ffff, 0x8d420024, 0x30420008, 0x1040002d, 0x00000000, 0x9742010e,
+	0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f880014, 0x24020180,
+	0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7470188, 0x31028000,
+	0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
+	0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
+	0x01021024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
+	0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
+	0xaf4201b8, 0x15600041, 0x00001021, 0x27440180, 0x3c038000, 0x8f4201b8,
+	0x00431024, 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008, 0xa083000b,
+	0xa4800010, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x3c030800,
+	0x8c620024, 0x30420001, 0x1040002e, 0x00001021, 0x9742010e, 0x34e70002,
+	0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x24020003, 0xa342018b, 0x9783000a, 0x8f840004, 0x8f860014, 0x24020002,
+	0xaf400180, 0xa742018c, 0xa745018e, 0xa7470188, 0x30c28000, 0xa7430190,
+	0x1040000c, 0xaf4401a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
+	0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00c21024,
+	0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
+	0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
+	0x00001021, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x8f4b0070,
+	0x93420112, 0x8f840008, 0x00022882, 0x30820100, 0x14400003, 0x24a30003,
+	0x03e00008, 0x00001021, 0x30824000, 0x10400010, 0x27424000, 0x00031880,
+	0x00431021, 0x8c470000, 0x24a30004, 0x00031880, 0x27424000, 0x00431021,
+	0x8c490000, 0x93430116, 0x27424000, 0x306300fc, 0x00431021, 0x8c4a0000,
+	0x0a000f45, 0x3c030800, 0x30822000, 0x1040ffea, 0x00031880, 0x27424000,
+	0x00431021, 0x8c470000, 0x24a30004, 0x00031880, 0x27424000, 0x00431021,
+	0x8c490000, 0x00005021, 0x3c030800, 0x24680100, 0x00071602, 0x00021080,
+	0x00481021, 0x8c460000, 0x00071b82, 0x306303fc, 0x01031821, 0x8c640400,
+	0x00071182, 0x304203fc, 0x01021021, 0x8c450800, 0x30e300ff, 0x00031880,
+	0x01031821, 0x00091602, 0x00021080, 0x01021021, 0x00c43026, 0x8c640c00,
+	0x8c431000, 0x00c53026, 0x00091382, 0x304203fc, 0x01021021, 0x8c451400,
+	0x312200ff, 0x00021080, 0x01021021, 0x00c43026, 0x00c33026, 0x00091982,
+	0x306303fc, 0x01031821, 0x8c641800, 0x8c431c00, 0x00c53026, 0x00c43026,
+	0x11400015, 0x00c33026, 0x000a1602, 0x00021080, 0x01021021, 0x8c432000,
+	0x000a1382, 0x304203fc, 0x01021021, 0x8c452400, 0x314200ff, 0x00021080,
+	0x01021021, 0x00c33026, 0x000a1982, 0x306303fc, 0x01031821, 0x8c642800,
+	0x8c432c00, 0x00c53026, 0x00c43026, 0x00c33026, 0x8f430070, 0x3c050800,
+	0x8ca43100, 0x2c820020, 0x10400008, 0x006b5823, 0x3c020800, 0x24423104,
+	0x00041880, 0x00621821, 0x24820001, 0xac6b0000, 0xaca23100, 0xaf860004,
+	0x03e00008, 0x24020001, 0x27bdffe8, 0xafbf0010, 0x8f460128, 0x8f840010,
+	0xaf460020, 0x8f450104, 0x8f420100, 0x24030800, 0xaf850008, 0xaf820014,
+	0xaf4301b8, 0x1080000a, 0x3c020800, 0x8c430034, 0x10600007, 0x30a22000,
+	0x10400005, 0x34a30100, 0x8f82000c, 0xaf830008, 0x24420001, 0xaf82000c,
+	0x3c020800, 0x8c4300c0, 0x10600006, 0x3c030800, 0x8c6200c4, 0x24040001,
+	0x24420001, 0x0a000fd5, 0xac6200c4, 0x8f820008, 0x3c030010, 0x00431024,
+	0x14400009, 0x3c02001f, 0x3c030800, 0x8c620020, 0x00002021, 0x24420001,
+	0x0e000c78, 0xac620020, 0x0a000fd5, 0x00402021, 0x3442ff00, 0x14c20009,
+	0x2403bfff, 0x3c030800, 0x8c620020, 0x24040001, 0x24420001, 0x0e000c78,
+	0xac620020, 0x0a000fd5, 0x00402021, 0x8f820014, 0x00431024, 0x14400006,
+	0x00000000, 0xaf400048, 0x0e0011a9, 0xaf400040, 0x0a000fd5, 0x00402021,
+	0x0e001563, 0x00000000, 0x00402021, 0x10800005, 0x3c024000, 0x8f430124,
+	0x3c026020, 0xac430014, 0x3c024000, 0xaf420138, 0x00000000, 0x8fbf0010,
+	0x03e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0xafb00010,
+	0x8f420140, 0xaf420020, 0x8f430148, 0x3c027000, 0x00621824, 0x3c023000,
+	0x10620021, 0x0043102b, 0x14400006, 0x3c024000, 0x3c022000, 0x10620009,
+	0x3c024000, 0x0a001040, 0x00000000, 0x10620045, 0x3c025000, 0x10620047,
+	0x3c024000, 0x0a001040, 0x00000000, 0x27440180, 0x3c038000, 0x8f4201b8,
+	0x00431024, 0x1440fffd, 0x00000000, 0x8f420148, 0x24030002, 0xa083000b,
+	0x00021402, 0xa4820008, 0x8f430148, 0xa4830010, 0x8f420144, 0x3c031000,
+	0xac820024, 0xaf4301b8, 0x0a001040, 0x3c024000, 0x8f420148, 0x24030002,
+	0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003,
+	0x10400005, 0x24020003, 0x0600001d, 0x36053000, 0x0a001027, 0x3c038000,
+	0x12020007, 0x00000000, 0x0a001034, 0x00000000, 0x0e00112c, 0x00000000,
+	0x0a001025, 0x00402021, 0x0e00113e, 0x00000000, 0x00402021, 0x36053000,
+	0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008,
+	0xa222000b, 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8,
+	0x0a001040, 0x3c024000, 0x0000000d, 0x00000000, 0x240002bf, 0x0a001040,
+	0x3c024000, 0x0e001441, 0x00000000, 0x0a001040, 0x3c024000, 0x0e0015ea,
+	0x00000000, 0x3c024000, 0xaf420178, 0x00000000, 0x8fbf0018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0020, 0x24020800, 0x03e00008, 0xaf4201b8,
+	0x27bdffe8, 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000,
+	0x2403ff7f, 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000,
+	0x3c020008, 0xaf430008, 0x8e040808, 0x0342d825, 0x8e020808, 0x3c030800,
+	0xac600020, 0x3084fff0, 0x2c840001, 0x3042fff0, 0x38420010, 0x2c420001,
+	0xaf840010, 0xaf820000, 0x0e00160c, 0x00000000, 0x0e001561, 0x00000000,
+	0x3c020400, 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c,
+	0x8e021980, 0x34420200, 0xae021980, 0x8f500000, 0x32020003, 0x1040fffd,
+	0x32020001, 0x10400004, 0x32020002, 0x0e000f92, 0x00000000, 0x32020002,
+	0x1040fff6, 0x00000000, 0x0e000fe0, 0x00000000, 0x0a001071, 0x00000000,
+	0x27bdffe8, 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000,
+	0x2403ff7f, 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000,
+	0x3c020008, 0xaf430008, 0x8e040808, 0x0342d825, 0x8e020808, 0x3c030800,
+	0xac600020, 0x3084fff0, 0x2c840001, 0x3042fff0, 0x38420010, 0x2c420001,
+	0xaf840010, 0xaf820000, 0x0e00160c, 0x00000000, 0x0e001561, 0x00000000,
+	0x3c020400, 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c,
+	0x8e021980, 0x8fbf0014, 0x34420200, 0xae021980, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x00804821, 0x30a5ffff, 0x30c6ffff, 0x30e7ffff, 0x3c038000,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
+	0x8f840004, 0x8f880014, 0xaf490180, 0xa745018c, 0xa746018e, 0xa7470188,
+	0x31028000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116, 0x304200fc,
+	0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff,
+	0x34427fff, 0x01021024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104,
+	0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac,
+	0x3c021000, 0xaf4201b8, 0x03e00008, 0x00000000, 0x27440180, 0x3c038000,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008,
+	0xa083000b, 0xa4800010, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00000000,
+	0x27440180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000,
+	0x8f420148, 0x24030002, 0xa083000b, 0x00021402, 0xa4820008, 0x8f430148,
+	0xa4830010, 0x8f420144, 0x3c031000, 0xac820024, 0x03e00008, 0xaf4301b8,
+	0x27bdffe0, 0xafbf0018, 0xafb10014, 0xafb00010, 0x8f420148, 0x24030002,
+	0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003,
+	0x10400005, 0x24020003, 0x0600001d, 0x36053000, 0x0a001117, 0x3c038000,
+	0x12020007, 0x00000000, 0x0a001124, 0x00000000, 0x0e00112c, 0x00000000,
+	0x0a001115, 0x00402021, 0x0e00113e, 0x00000000, 0x00402021, 0x36053000,
+	0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008,
+	0xa222000b, 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8,
+	0x0a001128, 0x8fbf0018, 0x0000000d, 0x00000000, 0x240002bf, 0x8fbf0018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3084ffff, 0x2c821389,
+	0x1040000d, 0x00001021, 0x3c030800, 0x24635900, 0x00042942, 0x00052880,
+	0x00a32821, 0x3086001f, 0x8ca40000, 0x24030001, 0x00c31804, 0x00832025,
+	0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x3084ffff, 0x2c821389,
+	0x1040000e, 0x00001021, 0x3c030800, 0x24635900, 0x00042942, 0x00052880,
+	0x00a32821, 0x3086001f, 0x24030001, 0x8ca40000, 0x00c31804, 0x00031827,
+	0x00832024, 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x9482000c,
+	0x24870014, 0x00021302, 0x00021080, 0x00824021, 0x00e8182b, 0x1060004f,
+	0x00000000, 0x90e30000, 0x2c620009, 0x10400047, 0x3c020800, 0x24425890,
+	0x00031880, 0x00621821, 0x8c640000, 0x00800008, 0x00000000, 0x0a0011a4,
+	0x24e70001, 0x90e30001, 0x2402000a, 0x54620024, 0x01003821, 0x01071023,
+	0x2c42000a, 0x54400020, 0x01003821, 0x3c050800, 0x8ca26c98, 0x24e70002,
+	0x34420100, 0xaca26c98, 0x90e30000, 0x90e20001, 0x90e40002, 0x90e60003,
+	0x24e70004, 0x24a56c98, 0x00031e00, 0x00021400, 0x00621825, 0x00042200,
+	0x00641825, 0x00661825, 0xaca30004, 0x90e20000, 0x90e30001, 0x90e40002,
+	0x90e60003, 0x24e70004, 0x00021600, 0x00031c00, 0x00431025, 0x00042200,
+	0x00441025, 0x00461025, 0x0a0011a4, 0xaca20008, 0x90e30001, 0x24020004,
+	0x1062000e, 0x00601021, 0x0a00119e, 0x01001021, 0x90e30001, 0x24020003,
+	0x10620008, 0x00601021, 0x0a00119e, 0x01001021, 0x90e30001, 0x24020002,
+	0x14620003, 0x01001021, 0x00601021, 0x00e21021, 0x0a0011a4, 0x00403821,
+	0x90e20001, 0x0a0011a4, 0x00e23821, 0x01003821, 0x00e8102b, 0x5440ffb4,
+	0x90e30000, 0x03e00008, 0x24020001, 0x27bdff90, 0x3c030800, 0xafbf006c,
+	0xafbe0068, 0xafb70064, 0xafb60060, 0xafb5005c, 0xafb40058, 0xafb30054,
+	0xafb20050, 0xafb1004c, 0xafb00048, 0xac606c98, 0x93620023, 0x30420010,
+	0x1440027c, 0x24020001, 0x93420116, 0x93630005, 0x34424000, 0x30630001,
+	0x14600005, 0x0342b021, 0x0e0015e0, 0x00000000, 0x0a001436, 0x8fbf006c,
+	0x93420112, 0x8f430104, 0x3c040020, 0x34424000, 0x00641824, 0x10600012,
+	0x03422821, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x00000000, 0x8f420128, 0xaca20000, 0x8f640040, 0x24030008, 0x240240c1,
+	0xa4a20008, 0x24020002, 0xa0a2000b, 0x3c021000, 0x0a0011f1, 0xa0a3000a,
+	0x8f420104, 0x3c030040, 0x00431024, 0x1040001d, 0x3c038000, 0x27450180,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000,
+	0x8f640040, 0x24030010, 0x240240c1, 0xa4a20008, 0x24020002, 0xa0a3000a,
+	0x24030008, 0xa0a2000b, 0x3c021000, 0xa4a30010, 0xa0a00012, 0xa0a00013,
+	0xaca00014, 0xaca00024, 0xaca00028, 0xaca0002c, 0xaca40018, 0x0e0015e0,
+	0xaf4201b8, 0x0a001436, 0x8fbf006c, 0x8f820000, 0x10400016, 0x00000000,
+	0x8f420104, 0x3c030001, 0x00431024, 0x10400011, 0x00000000, 0x8ca3000c,
+	0x8f620030, 0x1462022d, 0x24020001, 0x8ca30010, 0x8f62002c, 0x14620229,
+	0x24020001, 0x9763003a, 0x96c20000, 0x14430225, 0x24020001, 0x97630038,
+	0x96c20002, 0x14430221, 0x24020001, 0xaf400048, 0xaf400054, 0xaf400040,
+	0x8f740040, 0x8f650048, 0x00b43023, 0x04c10004, 0x00000000, 0x0000000d,
+	0x00000000, 0x240001af, 0x9742011a, 0x3052ffff, 0x12400004, 0x8ed30004,
+	0x02721021, 0x0a001228, 0x2451ffff, 0x02608821, 0x92d7000d, 0xa7a00020,
+	0xa3a0001a, 0xafa00028, 0x9362003f, 0x32e30004, 0x1060003a, 0x305000ff,
+	0x24040012, 0x16040006, 0x24020001, 0x3c040800, 0x8c830028, 0x24630001,
+	0x0a001328, 0xac830028, 0x8f620044, 0x16620010, 0x27a60010, 0x27450180,
+	0x3c038000, 0x2402001a, 0xa7a20020, 0x24020020, 0xafb40028, 0xa3b00022,
+	0xa3a40023, 0xa3a2001a, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000,
+	0x0a00130d, 0x00000000, 0x8f620044, 0x02621023, 0x0440001a, 0x02651023,
+	0x044100d9, 0x24020001, 0x3c020800, 0x8c4300d8, 0x10600004, 0x24020001,
+	0xa7a20020, 0x0a00125e, 0xafb40028, 0x2402001a, 0xa7a20020, 0x24020020,
+	0xafb40028, 0xa3b00022, 0xa3a40023, 0xa3a2001a, 0x27a60010, 0x27450180,
+	0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d,
+	0x00000000, 0x0a001328, 0x24020001, 0x0293f023, 0x1bc00016, 0x025e102a,
+	0x54400007, 0x32f700fe, 0x57d2000f, 0x027e9821, 0x32e20001, 0x5440000c,
+	0x027e9821, 0x32f700fe, 0x0240f021, 0x3c040800, 0x8c8300c8, 0x00009021,
+	0x24020001, 0xa7a20020, 0xafb40028, 0x24630001, 0x0a001282, 0xac8300c8,
+	0x025e1023, 0x0a001282, 0x3052ffff, 0x0000f021, 0x24a2ffff, 0x02221823,
+	0x1860001f, 0x0072102a, 0x54400019, 0x00a08821, 0x97a20020, 0x3c040800,
+	0x8c8300cc, 0xafb40028, 0x34420001, 0x24630001, 0xa7a20020, 0x02741026,
+	0x2c420001, 0xac8300cc, 0x2cc30001, 0x00431024, 0x1440000a, 0x02401821,
+	0x27a60010, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
+	0x00000000, 0x0a00130d, 0x00000000, 0x00a08821, 0x02431023, 0x3052ffff,
+	0x0a0012ae, 0x32f700f6, 0x02741023, 0x18400008, 0x97a20020, 0x3c040800,
+	0x8c8300d4, 0xafb30028, 0x34420400, 0x24630001, 0xa7a20020, 0xac8300d4,
+	0x32e20002, 0x1040001c, 0x32e20010, 0x8f620044, 0x1662000d, 0x27a60010,
+	0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001, 0xa7a20020,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d, 0x00000000,
+	0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001, 0xa7a20020,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d, 0x00000000,
+	0x54400003, 0x8ed50008, 0x0a001328, 0x24020001, 0x8f630054, 0x26a2ffff,
+	0x00431023, 0x18400011, 0x27a60010, 0x97a20020, 0x3c040800, 0x8c8300d0,
+	0x27450180, 0x3c078000, 0xafb40028, 0x34420001, 0x24630001, 0xa7a20020,
+	0xac8300d0, 0x8f4201b8, 0x00471024, 0x1440fffd, 0x00000000, 0x0a00130d,
+	0x00000000, 0x32e20020, 0x10400011, 0x00000000, 0x96c20012, 0x0052102b,
+	0x10400008, 0x97a20020, 0x96d20012, 0x12400003, 0x02721021, 0x0a0012f2,
+	0x2451ffff, 0x02608821, 0x97a20020, 0x93a3001a, 0x34420008, 0x34630004,
+	0xa7a20020, 0xa3a3001a, 0x8f420104, 0x3c030080, 0x00431024, 0x10400037,
+	0x3a03000a, 0x0e001151, 0x02c02021, 0x24030002, 0x1443002b, 0x3c030800,
+	0x27a60010, 0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001,
+	0xa7a20020, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128,
+	0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, 0x90c4000a,
+	0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, 0x90c30012,
+	0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, 0x8cc20024,
+	0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc4002c, 0x24020001, 0x3c031000,
+	0xaca4002c, 0xaf4301b8, 0xaf400044, 0xaf400050, 0x0a001436, 0x8fbf006c,
+	0x8c626c98, 0x30420100, 0x10400003, 0x24636c98, 0x8c620004, 0xaf62017c,
+	0x3a03000a, 0x2c630001, 0x3a02000c, 0x2c420001, 0x00621825, 0x14600003,
+	0x2402000e, 0x56020030, 0x00009021, 0x52400008, 0x96c4000e, 0x12400004,
+	0xa7b20040, 0x02721021, 0x0a001343, 0x2451ffff, 0x02608821, 0x96c4000e,
+	0x93630035, 0x8f62004c, 0x00642004, 0x00952021, 0x00821023, 0x18400015,
+	0x00000000, 0x8f620018, 0x02621023, 0x1c400015, 0x97a20020, 0x8f620018,
+	0x1662001c, 0x00000000, 0x8f62001c, 0x02a21023, 0x1c40000e, 0x97a20020,
+	0x8f62001c, 0x16a20015, 0x00000000, 0x8f620058, 0x00821023, 0x18400011,
+	0x97a20020, 0x0a001364, 0xafb10028, 0x8f620058, 0x00821023, 0x0441000b,
+	0x97a20020, 0xafb10028, 0xafb30034, 0xafb50038, 0xafa4003c, 0x34420020,
+	0x0a00136d, 0xa7a20020, 0x02809821, 0x02608821, 0x8f640058, 0x8f62004c,
+	0x02a21023, 0x18400009, 0x00000000, 0x8f620054, 0x02a21023, 0x1c400005,
+	0x97a20020, 0xafb10028, 0xafb50024, 0x0a001385, 0x34420040, 0x9742011a,
+	0x1440000c, 0x24020014, 0x8f620058, 0x14820009, 0x24020014, 0x8f63004c,
+	0x8f620054, 0x10620004, 0x97a20020, 0xafb10028, 0x34420080, 0xa7a20020,
+	0x24020014, 0x1202000a, 0x2a020015, 0x10400005, 0x2402000c, 0x12020006,
+	0x32e20001, 0x0a0013c6, 0x00000000, 0x24020016, 0x16020035, 0x32e20001,
+	0x8f620084, 0x24420001, 0x16a20031, 0x32e20001, 0x24020014, 0x12020021,
+	0x2a020015, 0x10400005, 0x2402000c, 0x12020008, 0x32e20001, 0x0a0013c6,
+	0x00000000, 0x24020016, 0x1202000c, 0x32e20001, 0x0a0013c6, 0x00000000,
+	0x97a30020, 0x2402000e, 0xafb10028, 0xa3b00022, 0xa3a20023, 0xafb50024,
+	0x34630054, 0x0a0013c5, 0xa7a30020, 0x97a20020, 0x93a4001a, 0x24030010,
+	0xafb10028, 0xa3b00022, 0xa3a30023, 0xafb50024, 0x3442005d, 0x34840002,
+	0xa7a20020, 0x0a0013c5, 0xa3a4001a, 0x97a20020, 0x24030012, 0xa3a30023,
+	0x93a3001a, 0xafb10028, 0xa3b00022, 0xafb50024, 0x3042fffe, 0x3442005c,
+	0x34630002, 0xa7a20020, 0xa3a3001a, 0x32e20001, 0x10400030, 0x2402000c,
+	0x12020013, 0x2a02000d, 0x10400005, 0x2402000a, 0x12020008, 0x97a20020,
+	0x0a0013f8, 0x32e20009, 0x2402000e, 0x1202001b, 0x32e20009, 0x0a0013f9,
+	0x0002102b, 0x93a4001a, 0x24030008, 0xafb10028, 0xa3b00022, 0xa3a30023,
+	0x0a0013f4, 0x34420013, 0x97a30020, 0x30620004, 0x14400005, 0x93a2001a,
+	0x3463001b, 0xa7a30020, 0x0a0013e7, 0x24030016, 0x3463001b, 0xa7a30020,
+	0x24030010, 0xafb10028, 0xa3b00022, 0xa3a30023, 0x34420002, 0x0a0013f7,
+	0xa3a2001a, 0x97a20020, 0x93a4001a, 0x24030010, 0xafb10028, 0xa3b00022,
+	0xa3a30023, 0x3442001b, 0x34840002, 0xa7a20020, 0xa3a4001a, 0x32e20009,
+	0x0002102b, 0x00021023, 0x30420007, 0x12400015, 0x34450003, 0x8f820018,
+	0x24030800, 0x27440180, 0x24420001, 0xaf820018, 0x24020004, 0xaf4301b8,
+	0xa4850008, 0xa082000b, 0x93430120, 0x00003021, 0x3c021000, 0xa492000e,
+	0xac950024, 0xac930028, 0x007e1821, 0xa483000c, 0xaf4201b8, 0x0a001413,
+	0x97a20020, 0x24060001, 0x97a20020, 0x10400020, 0x27450180, 0x3c038000,
+	0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000,
+	0x8fa30028, 0x240240c1, 0xa4a20008, 0xaca30018, 0x93a4001a, 0x24020002,
+	0xa0a2000b, 0xa0a4000a, 0x97a20020, 0xa4a20010, 0x93a30022, 0xa0a30012,
+	0x93a20023, 0xa0a20013, 0x8fa30024, 0xaca30014, 0x8fa20034, 0xaca20024,
+	0x8fa30038, 0xaca30028, 0x8fa2003c, 0x3c031000, 0xaca2002c, 0xaf4301b8,
+	0x00c01021, 0x8fbf006c, 0x8fbe0068, 0x8fb70064, 0x8fb60060, 0x8fb5005c,
+	0x8fb40058, 0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x03e00008,
+	0x27bd0070, 0x8f470140, 0x8f460148, 0x3c028000, 0x00c24024, 0x00062c02,
+	0x30a300ff, 0x24020019, 0x106200e7, 0x27440180, 0x2862001a, 0x1040001f,
+	0x24020008, 0x106200be, 0x28620009, 0x1040000d, 0x24020001, 0x10620046,
+	0x28620002, 0x50400005, 0x24020006, 0x1060002e, 0x00a01821, 0x0a00155e,
+	0x00000000, 0x1062005b, 0x00a01821, 0x0a00155e, 0x00000000, 0x2402000b,
+	0x10620084, 0x2862000c, 0x10400005, 0x24020009, 0x106200bc, 0x00061c02,
+	0x0a00155e, 0x00000000, 0x2402000e, 0x106200b7, 0x00061c02, 0x0a00155e,
+	0x00000000, 0x28620021, 0x10400009, 0x2862001f, 0x104000c1, 0x2402001b,
+	0x106200bf, 0x2402001c, 0x1062009a, 0x00061c02, 0x0a00155e, 0x00000000,
+	0x240200c2, 0x106200ca, 0x286200c3, 0x10400005, 0x24020080, 0x1062005a,
+	0x00a01821, 0x0a00155e, 0x00000000, 0x240200c9, 0x106200cd, 0x30c5ffff,
+	0x0a00155e, 0x00000000, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd,
+	0x24020001, 0xa4830008, 0x24030002, 0xac870000, 0xac800004, 0xa082000a,
+	0xa083000b, 0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, 0xac830024,
+	0x3c036000, 0xaf4201b8, 0x03e00008, 0xac600808, 0x11000009, 0x00a01821,
+	0x3c020800, 0x24030002, 0xa0436c88, 0x24426c88, 0xac470008, 0x8f430144,
+	0x03e00008, 0xac430004, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd,
+	0x24020002, 0xac800000, 0xac870004, 0xa4830008, 0xa082000a, 0xa082000b,
+	0xa4860010, 0xac800024, 0x8f420144, 0x3c031000, 0xac820028, 0x3c026000,
+	0xaf4301b8, 0x03e00008, 0xac400808, 0x3c080800, 0x3c058000, 0x8f4201b8,
+	0x00451024, 0x1440fffd, 0x00000000, 0xac870000, 0x91026c88, 0x00002821,
+	0x10400002, 0x25076c88, 0x8ce50008, 0xac850004, 0xa4830008, 0x91036c88,
+	0x24020002, 0xa082000b, 0xa4860010, 0x34630001, 0xa083000a, 0x8f420144,
+	0xac820024, 0x91036c88, 0x10600002, 0x00001021, 0x8ce20004, 0xac820028,
+	0x3c021000, 0xaf4201b8, 0x3c026000, 0xa1006c88, 0x03e00008, 0xac400808,
+	0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xa082000b,
+	0xa4830008, 0xa4860010, 0x8f420144, 0x3c031000, 0xa4820012, 0x03e00008,
+	0xaf4301b8, 0x30c2ffff, 0x14400028, 0x00061c02, 0x93620005, 0x30420004,
+	0x14400020, 0x3c029000, 0x34420001, 0x00e21025, 0xaf420020, 0x3c038000,
+	0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000,
+	0x34630001, 0x00e31825, 0x34420004, 0xa3620005, 0xaf430020, 0x93620005,
+	0x30420004, 0x14400003, 0x3c038000, 0x0000000d, 0x3c038000, 0x8f4201b8,
+	0x00431024, 0x1440fffd, 0x24020005, 0x3c031000, 0xac870000, 0xa082000b,
+	0xaf4301b8, 0x0a00150d, 0x00061c02, 0x0000000d, 0x03e00008, 0x00000000,
+	0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001,
+	0xa4830008, 0x24030002, 0xac870000, 0xac800004, 0xa082000a, 0xa083000b,
+	0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, 0xac830024, 0x03e00008,
+	0xaf4201b8, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002,
+	0xac800000, 0xac870004, 0xa4830008, 0xa082000a, 0xa082000b, 0xa4860010,
+	0xac800024, 0x8f420144, 0x3c031000, 0xac820028, 0x03e00008, 0xaf4301b8,
+	0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001,
+	0xa4830008, 0x24030002, 0xa082000a, 0x3c021000, 0xac870000, 0xac800004,
+	0xa083000b, 0xa4860010, 0xac800024, 0xac800028, 0x03e00008, 0xaf4201b8,
+	0x00a01821, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002,
+	0xac870000, 0xac800004, 0xa4830008, 0xa080000a, 0x0a001518, 0xa082000b,
+	0x8f440144, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002,
+	0x240340c9, 0xaf470180, 0xa342018b, 0x3c021000, 0xa7430188, 0xaf4401a4,
+	0xaf4501a8, 0xaf4001ac, 0x03e00008, 0xaf4201b8, 0x0000000d, 0x03e00008,
+	0x00000000, 0x03e00008, 0x00000000, 0x8f420100, 0x3042003e, 0x14400011,
+	0x24020001, 0xaf400048, 0x8f420100, 0x304207c0, 0x10400005, 0x00000000,
+	0xaf40004c, 0xaf400050, 0x03e00008, 0x24020001, 0xaf400054, 0xaf400040,
+	0x8f420100, 0x30423800, 0x54400001, 0xaf400044, 0x24020001, 0x03e00008,
+	0x00000000, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002,
+	0x240340c9, 0xaf440180, 0xa342018b, 0x3c021000, 0xa7430188, 0xaf4501a4,
+	0xaf4601a8, 0xaf4701ac, 0x03e00008, 0xaf4201b8, 0x3c029000, 0x34420001,
+	0x00822025, 0xaf440020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
+	0x00000000, 0x03e00008, 0x00000000, 0x3c028000, 0x34420001, 0x00822025,
+	0x03e00008, 0xaf440020, 0x308600ff, 0x27450180, 0x3c038000, 0x8f4201b8,
+	0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8f640040,
+	0x24030008, 0x240240c1, 0xa4a20008, 0x24020002, 0xa0a2000b, 0x3c021000,
+	0xa0a6000a, 0xa4a30010, 0xa0a00012, 0xa0a00013, 0xaca00014, 0xaca00024,
+	0xaca00028, 0xaca0002c, 0xaca40018, 0x03e00008, 0xaf4201b8, 0x24020001,
+	0xacc40000, 0x03e00008, 0xa4e50000, 0x24020001, 0xaf400044, 0x03e00008,
+	0xaf400050, 0x00803021, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024,
+	0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1,
+	0xa4a20008, 0xaca30018, 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a,
+	0x94c20010, 0xa4a20010, 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013,
+	0x8cc30014, 0xaca30014, 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028,
+	0x8cc2002c, 0x3c031000, 0xaca2002c, 0x24020001, 0xaf4301b8, 0xaf400044,
+	0x03e00008, 0xaf400050, 0x27bdffe8, 0xafbf0010, 0x0e001047, 0x00000000,
+	0x00002021, 0x0e000c78, 0xaf400180, 0x8fbf0010, 0x03e00008, 0x27bd0018,
+	0x8f460148, 0x27450180, 0x3c038000, 0x00061402, 0x304700ff, 0x8f4201b8,
+	0x00431024, 0x1440fffd, 0x00000000, 0x8f440140, 0x00061202, 0x304200ff,
+	0x00061c02, 0xaca20004, 0x24020002, 0xa4a30008, 0x30c300ff, 0xa0a2000b,
+	0xaca30024, 0x10e0000a, 0xaca40000, 0x28e20004, 0x14400005, 0x24020001,
+	0x24020005, 0x54e20005, 0xa0a0000a, 0x24020001, 0x0a001609, 0xa0a2000a,
+	0xa0a0000a, 0x3c021000, 0x03e00008, 0xaf4201b8, 0x03e00008, 0x00001021,
+	0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000,
+	0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a00161f, 0x00a01021,
+	0xac860000, 0x00000000, 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa,
+	0x24a5ffff, 0x03e00008, 0x00000000, 0x00000000 }; 
+
+static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_RXP_b06FwRodata[(0x28/4) + 1] = {
+	0x0800468c, 0x0800458c, 0x08004630, 0x08004648, 0x08004660, 0x08004680,
+	0x0800468c, 0x0800468c, 0x08004594, 0x00000000, 0x00000000 };
+static u32 bnx2_RXP_b06FwBss[(0x13a4/4) + 1] = { 0x0 };
+static u32 bnx2_RXP_b06FwSbss[(0x1c/4) + 1] = { 0x0 };
+
+static u32 bnx2_rv2p_proc1[] = {
+	0x00000008, 0xac000001, 0x0000000c, 0x2f800001, 0x00000010, 0x213f0004,
+	0x00000010, 0x20bf002c, 0x00000010, 0x203f0143, 0x00000018, 0x8000fffd,
+	0x00000010, 0xb1b8b017, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
+	0x00000000, 0x2c380000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x00000008, 0x02000002,
+	0x00000010, 0x91de0000, 0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08,
+	0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000010, 0x2c620002,
+	0x00000018, 0x80000012, 0x0000000b, 0x2fdf0002, 0x0000000c, 0x1f800002,
+	0x00000000, 0x2c070000, 0x00000018, 0x8000ffe6, 0x00000008, 0x02000002,
+	0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
+	0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000018, 0x80000004,
+	0x0000000c, 0x1f800002, 0x00000000, 0x00000000, 0x00000018, 0x8000ffd9,
+	0x0000000c, 0x29800002, 0x0000000c, 0x1f800002, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000005, 0x00000018, 0x8000ffd4, 0x00000008, 0x02240030,
+	0x00000018, 0x00040000, 0x00000018, 0x80000015, 0x00000018, 0x80000017,
+	0x00000018, 0x8000001b, 0x00000018, 0x8000004c, 0x00000018, 0x8000008c,
+	0x00000018, 0x8000000f, 0x00000018, 0x8000000e, 0x00000018, 0x8000000d,
+	0x00000018, 0x8000000c, 0x00000018, 0x800000c2, 0x00000018, 0x8000000a,
+	0x00000018, 0x80000009, 0x00000018, 0x80000008, 0x00000018, 0x800000fd,
+	0x00000018, 0x80000006, 0x00000018, 0x80000005, 0x00000018, 0x800000ff,
+	0x00000018, 0x80000104, 0x00000018, 0x80000002, 0x00000018, 0x80000098,
+	0x00000018, 0x80000000, 0x0000000c, 0x1f800001, 0x00000000, 0x00000000,
+	0x00000018, 0x8000ffba, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
+	0x0000000c, 0x1f800001, 0x00000008, 0x2a000002, 0x00000018, 0x8000ffb5,
+	0x00000010, 0xb1a0b012, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000,
+	0x00000008, 0x2c800000, 0x00000008, 0x2d000000, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d80011c, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x0000000f, 0x47600008, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
+	0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000018, 0x80000013,
+	0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000010, 0x91d40000, 0x00000008, 0x2d80011c,
+	0x0000000f, 0x060e0001, 0x00000010, 0x001f0000, 0x00000000, 0x0f580000,
+	0x00000010, 0x91de0000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000000, 0x02620000,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x309a0000, 0x00000000, 0x31040000,
+	0x00000000, 0x0c961800, 0x00000009, 0x0c99ffff, 0x00000004, 0xcc993400,
+	0x00000010, 0xb1963202, 0x00000008, 0x0f800000, 0x0000000c, 0x29800001,
+	0x00000010, 0x00220002, 0x0000000c, 0x29520001, 0x0000000c, 0x29520000,
+	0x00000008, 0x22000001, 0x0000000c, 0x1f800001, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000003, 0x00000018, 0x8000ff83, 0x00000010, 0xb1a0b01d,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x0000000f, 0x47600008, 0x00000000, 0x060e0000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f580000, 0x00000010, 0x91de0000,
+	0x00000000, 0x0a640000, 0x00000000, 0x0ae50000, 0x00000000, 0x0b670000,
+	0x00000000, 0x0d620000, 0x00000000, 0x0ce71800, 0x00000009, 0x0c99ffff,
+	0x00000004, 0xcc993400, 0x00000010, 0xb1963220, 0x00000008, 0x0f800000,
+	0x00000018, 0x8000001e, 0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002,
+	0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d80012c, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
+	0x00000000, 0x0f580000, 0x00000010, 0x91de0000, 0x00000000, 0x0a640000,
+	0x00000000, 0x0ae50000, 0x00000000, 0x0b670000, 0x00000000, 0x0d620000,
+	0x00000000, 0x02630000, 0x0000000f, 0x47620010, 0x00000000, 0x0ce71800,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x311a0000, 0x00000000, 0x31840000,
+	0x0000000b, 0xc20000ff, 0x00000002, 0x42040000, 0x00000001, 0x31620800,
+	0x0000000f, 0x020e0010, 0x00000002, 0x31620800, 0x00000009, 0x0c99ffff,
+	0x00000004, 0xcc993400, 0x00000010, 0xb1963202, 0x00000008, 0x0f800000,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x0000000c, 0x61420006,
+	0x00000008, 0x22000008, 0x00000000, 0x2adf0000, 0x00000008, 0x2a000004,
+	0x00000018, 0x8000ff42, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91a0b008, 0x00000010, 0x91d40000, 0x0000000c, 0x31620018,
+	0x00000008, 0x2d800001, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x00000008, 0xac000001, 0x00000018, 0x8000000e, 0x00000000, 0x0380b000,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c004000, 0x00000010, 0x91d40000,
+	0x00000008, 0x2d800101, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x0000000c, 0x31620018, 0x00000008, 0x2d800001, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c000e00,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000008, 0x2a000007,
+	0x00000018, 0x8000ff27, 0x00000010, 0xb1a0b016, 0x0000000b, 0x2fdf0002,
+	0x00000000, 0x03d80000, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
+	0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000008, 0x07000001,
+	0x00000010, 0xb5de1c00, 0x00000010, 0x2c620002, 0x00000018, 0x8000000a,
+	0x0000000b, 0x2fdf0002, 0x00000000, 0x2c070000, 0x0000000c, 0x1f800001,
+	0x00000010, 0x91de0000, 0x00000018, 0x8000ff11, 0x00000008, 0x2c8000b0,
+	0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000010, 0x91de0000,
+	0x00000000, 0x2adf0000, 0x00000008, 0x2a00000a, 0x00000018, 0x8000ff07,
+	0x00000000, 0x82265600, 0x0000000f, 0x47220008, 0x00000009, 0x070e000f,
+	0x00000008, 0x070e0008, 0x00000008, 0x02800001, 0x00000007, 0x02851c00,
+	0x00000008, 0x82850001, 0x00000000, 0x02840a00, 0x00000007, 0x42851c00,
+	0x00000003, 0xc3aa5200, 0x00000000, 0x03b10e00, 0x00000010, 0x001f0000,
+	0x0000000f, 0x0f280007, 0x00000007, 0x4b071c00, 0x00000000, 0x00000000,
+	0x0000000f, 0x0a960003, 0x00000000, 0x0a955c00, 0x00000000, 0x4a005a00,
+	0x00000000, 0x0c960a00, 0x00000009, 0x0c99ffff, 0x00000008, 0x0d00ffff,
+	0x00000010, 0xb1963202, 0x00000008, 0x0f800005, 0x00000010, 0x00220020,
+	0x00000000, 0x02a70000, 0x00000010, 0xb1850002, 0x00000008, 0x82850200,
+	0x00000000, 0x02000000, 0x00000000, 0x03a60000, 0x00000018, 0x8000004e,
+	0x00000000, 0x072b0000, 0x00000001, 0x878c1c00, 0x00000000, 0x870e1e00,
+	0x00000000, 0x860c1e00, 0x00000000, 0x03061e00, 0x00000010, 0xb18e0003,
+	0x00000018, 0x80000047, 0x00000018, 0x8000fffa, 0x00000010, 0x918c0003,
+	0x00000010, 0xb1870002, 0x00000018, 0x80000043, 0x00000010, 0x91d40000,
+	0x0000000c, 0x29800001, 0x00000000, 0x2a860000, 0x00000000, 0x230c0000,
+	0x00000000, 0x2b070000, 0x00000010, 0xb187000e, 0x00000008, 0x2a000008,
+	0x00000018, 0x8000003b, 0x00000010, 0x91d40000, 0x00000000, 0x28d18c00,
+	0x00000000, 0x2a860000, 0x00000000, 0x230c0000, 0x00000000, 0x2b070000,
+	0x00000018, 0x8000fff8, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
+	0x00000000, 0x2aab0000, 0x00000000, 0xa3265600, 0x00000000, 0x2b000000,
+	0x0000000c, 0x1f800001, 0x00000008, 0x2a000008, 0x00000018, 0x8000fec8,
+	0x00000010, 0x91d40000, 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001,
+	0x00000008, 0x2a000009, 0x00000018, 0x8000fec3, 0x00000010, 0x91d40000,
+	0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000000, 0x29420000,
+	0x00000008, 0x2a000002, 0x00000018, 0x8000febd, 0x00000018, 0x8000febc,
+	0x00000010, 0xb1bcb016, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
+	0x00000000, 0x2c3c0000, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800150, 0x00000000, 0x00000000,
+	0x00000010, 0x205f0000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
+	0x00000008, 0x2d800108, 0x00000008, 0x07000001, 0x00000010, 0xb5de1c00,
+	0x00000010, 0x2c620002, 0x00000018, 0x8000000a, 0x0000000b, 0x2fdf0002,
+	0x00000000, 0x2c070000, 0x0000000c, 0x1f800000, 0x00000010, 0x91de0000,
+	0x00000018, 0x8000fea6, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
+	0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x0000000c, 0x29800000,
+	0x0000000c, 0x1f800000, 0x00000010, 0x91de0000, 0x00000000, 0x2adf0000,
+	0x00000008, 0x2a000006, 0x00000018, 0x8000fe9c, 0x00000008, 0x03050004,
+	0x00000006, 0x83040c00, 0x00000008, 0x02850200, 0x00000000, 0x86050c00,
+	0x00000001, 0x860c0e00, 0x00000008, 0x02040004, 0x00000000, 0x02041800,
+	0x00000000, 0x83871800, 0x00000018, 0x00020000 };
+
+static u32 bnx2_rv2p_proc2[] = {
+	0x00000000, 0x2a000000, 0x00000010, 0xb1d40000, 0x00000008, 0x02540003,
+	0x00000018, 0x00040000, 0x00000018, 0x8000000a, 0x00000018, 0x8000000a,
+	0x00000018, 0x8000000e, 0x00000018, 0x80000056, 0x00000018, 0x800001b9,
+	0x00000018, 0x800001e1, 0x00000018, 0x8000019b, 0x00000018, 0x800001f9,
+	0x00000018, 0x8000019f, 0x00000018, 0x800001a6, 0x00000018, 0x80000000,
+	0x0000000c, 0x29800001, 0x00000000, 0x2a000000, 0x0000000c, 0x29800000,
+	0x00000010, 0x20530000, 0x00000018, 0x8000ffee, 0x0000000c, 0x29800001,
+	0x00000010, 0x91de0000, 0x00000010, 0x001f0000, 0x00000000, 0x2f80aa00,
+	0x00000000, 0x2a000000, 0x00000000, 0x0d610000, 0x00000000, 0x03620000,
+	0x00000000, 0x2c400000, 0x00000000, 0x02638c00, 0x00000000, 0x26460000,
+	0x00000010, 0x00420002, 0x00000008, 0x02040012, 0x00000010, 0xb9060836,
+	0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000000, 0x0b660000, 0x00000000, 0x0c000000, 0x00000000, 0x0b800000,
+	0x00000010, 0x00420009, 0x00000008, 0x0cc60012, 0x00000008, 0x0f800003,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000008, 0x27110012,
+	0x00000000, 0x66900000, 0x00000008, 0xa31b0012, 0x00000018, 0x80000008,
+	0x00000000, 0x0cc60000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
+	0x00000010, 0x009f0000, 0x00000000, 0x27110000, 0x00000000, 0x66900000,
+	0x00000000, 0x231b0000, 0x00000010, 0xb197320e, 0x00000000, 0x25960000,
+	0x00000000, 0x021b0000, 0x00000010, 0x001f0000, 0x00000008, 0x0f800003,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000000, 0x22c50800,
+	0x00000010, 0x009f0000, 0x00000000, 0x27002200, 0x00000000, 0x26802000,
+	0x00000000, 0x231b0000, 0x0000000c, 0x69520001, 0x00000018, 0x8000fff3,
+	0x00000010, 0x01130002, 0x00000010, 0xb1980003, 0x00000010, 0x001f0000,
+	0x00000008, 0x0f800004, 0x00000008, 0x22000003, 0x00000008, 0x2c80000c,
+	0x00000008, 0x2d00000c, 0x00000010, 0x009f0000, 0x00000000, 0x25960000,
+	0x0000000c, 0x29800000, 0x00000000, 0x32140000, 0x00000000, 0x32950000,
+	0x00000000, 0x33160000, 0x00000000, 0x31e32e00, 0x00000008, 0x2d800010,
+	0x00000010, 0x20530000, 0x00000018, 0x8000ffac, 0x00000000, 0x23000000,
+	0x00000000, 0x25e60000, 0x00000008, 0x2200000b, 0x0000000c, 0x69520000,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000018, 0x8000ffa5,
+	0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
+	0x00000010, 0x001f0000, 0x00000000, 0x02700000, 0x00000000, 0x0d620000,
+	0x00000000, 0xbb630800, 0x00000000, 0x2a000000, 0x00000009, 0x076000ff,
+	0x0000000f, 0x2c0e0007, 0x00000008, 0x2c800000, 0x00000008, 0x2d000064,
+	0x00000008, 0x2d80011c, 0x00000009, 0x06420002, 0x0000000c, 0x61420001,
+	0x00000000, 0x0f400000, 0x00000000, 0x02d08c00, 0x00000000, 0x23000000,
+	0x00000004, 0x826da000, 0x00000000, 0x8304a000, 0x00000000, 0x22c50c00,
+	0x00000000, 0x03760000, 0x00000004, 0x83860a00, 0x00000000, 0x83870c00,
+	0x00000010, 0x91de0000, 0x00000000, 0x037c0000, 0x00000000, 0x837b0c00,
+	0x00000001, 0x83060e00, 0x00000000, 0x83870c00, 0x00000000, 0x82850e00,
+	0x00000010, 0xb1860016, 0x0000000f, 0x47610018, 0x00000000, 0x068e0000,
+	0x0000000f, 0x47670010, 0x0000000f, 0x47e20010, 0x00000000, 0x870e1e00,
+	0x00000010, 0xb70e1a10, 0x00000010, 0x0ce7000e, 0x00000008, 0x22000009,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
+	0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
+	0x00000018, 0x8000023f, 0x00000000, 0x37ed0000, 0x0000000c, 0x73e7001a,
+	0x00000010, 0x20530000, 0x00000008, 0x22000008, 0x0000000c, 0x61420004,
+	0x00000000, 0x02f60000, 0x00000004, 0x82840a00, 0x00000010, 0xb1840a2b,
+	0x00000010, 0x2d67000a, 0x00000010, 0xb96d0804, 0x00000004, 0xb6ed0a00,
+	0x00000000, 0x37ed0000, 0x00000018, 0x80000029, 0x0000000c, 0x61420000,
+	0x00000000, 0x37040000, 0x00000000, 0x37850000, 0x0000000c, 0x33e7001a,
+	0x00000018, 0x80000024, 0x00000010, 0xb96d0809, 0x00000004, 0xb6ed0a00,
+	0x00000000, 0x036d0000, 0x00000004, 0xb76e0c00, 0x00000010, 0x91ee0c1f,
+	0x0000000c, 0x73e7001a, 0x00000004, 0xb6ef0c00, 0x00000000, 0x37ed0000,
+	0x00000018, 0x8000001b, 0x0000000c, 0x61420000, 0x00000010, 0xb7ee0a05,
+	0x00000010, 0xb96f0815, 0x00000003, 0xb76e0800, 0x00000004, 0xb7ef0a00,
+	0x00000018, 0x80000015, 0x00000010, 0x0ce7000c, 0x00000008, 0x22000009,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
+	0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
+	0x00000018, 0x80000215, 0x00000010, 0x20530000, 0x00000008, 0x22000008,
+	0x0000000c, 0x61420004, 0x00000000, 0x37040000, 0x00000000, 0x37850000,
+	0x00000000, 0x036d0000, 0x00000003, 0xb8f10c00, 0x00000018, 0x80000004,
+	0x00000000, 0x02840000, 0x00000002, 0x21421800, 0x0000000c, 0x61420000,
+	0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff,
+	0x00000000, 0x23000000, 0x00000010, 0xb1840a3d, 0x00000010, 0x01420002,
+	0x00000004, 0xb8f10a00, 0x00000003, 0x83760a00, 0x00000010, 0xb8040c39,
+	0x00000010, 0xb7e6080a, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
+	0x00000009, 0x0c68ffff, 0x00000009, 0x0b67ffff, 0x00000000, 0x0be60000,
+	0x00000000, 0x0c840000, 0x00000010, 0xb197320c, 0x00000008, 0x0f800002,
+	0x00000018, 0x8000000a, 0x00000000, 0x0a6a0000, 0x00000000, 0x0aeb0000,
+	0x00000000, 0x0c000000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0be90000,
+	0x00000000, 0x0c840000, 0x00000010, 0xb1973203, 0x00000008, 0x0f800002,
+	0x00000018, 0x80000001, 0x00000010, 0x001f0000, 0x00000000, 0x0c860000,
+	0x00000000, 0x06980000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
+	0x00000010, 0x009f0000, 0x00000010, 0xb1973210, 0x00000000, 0x231b0000,
+	0x00000000, 0x02043600, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x800001de, 0x00000000, 0x06980000,
+	0x00000010, 0x20530000, 0x00000000, 0x22c58c00, 0x00000010, 0x001f0000,
+	0x00000008, 0x0f800003, 0x00000018, 0x8000fff0, 0x00000000, 0x02043600,
+	0x00000000, 0x231b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
+	0x0000000c, 0x29000000, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000000, 0x32140000, 0x00000000, 0x32950000, 0x00000005, 0x73e72c00,
+	0x00000005, 0x74683000, 0x00000000, 0x33170000, 0x00000018, 0x80000138,
+	0x00000010, 0x91c60004, 0x00000008, 0x07000004, 0x00000010, 0xb1c41c02,
+	0x00000010, 0x91840a04, 0x00000018, 0x800001c3, 0x00000010, 0x20530000,
+	0x00000000, 0x22c58c00, 0x00000010, 0xb1840a8e, 0x0000000c, 0x21420006,
+	0x00000010, 0x0ce7001a, 0x0000000f, 0x43680010, 0x00000000, 0x03f30c00,
+	0x00000010, 0x91870850, 0x0000000f, 0x46ec0010, 0x00000010, 0xb68d0c4e,
+	0x00000000, 0x838d0c00, 0x00000000, 0xa3050800, 0x00000001, 0xa3460e00,
+	0x00000000, 0x02048c00, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000010, 0x001f0000, 0x00000008, 0x22000008, 0x00000003, 0x8384a000,
+	0x0000000f, 0x65870010, 0x00000009, 0x2607ffff, 0x00000000, 0x27750c00,
+	0x00000000, 0x66f40000, 0x0000000c, 0x29000000, 0x00000018, 0x800001aa,
+	0x00000000, 0x03068c00, 0x00000003, 0xf4680c00, 0x00000010, 0x20530000,
+	0x00000000, 0x22c58c00, 0x00000018, 0x8000ffe5, 0x00000000, 0x39760000,
+	0x00000000, 0x39840000, 0x0000000c, 0x33e70019, 0x00000010, 0x001f0000,
+	0x00000000, 0x031e0000, 0x00000000, 0x0760fe00, 0x0000000f, 0x0f0e0007,
+	0x00000000, 0x83850800, 0x00000000, 0x0a7d0000, 0x00000000, 0x0afe0000,
+	0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000, 0x00000000, 0x0c000000,
+	0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
+	0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
+	0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
+	0x00000002, 0x33e70e00, 0x00000000, 0x28f30000, 0x00000010, 0x009f0000,
+	0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000008, 0x22000006, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
+	0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x8000017e, 0x00000003, 0xf4683600,
+	0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
+	0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
+	0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000018, 0x8000ffac, 0x00000010, 0x001f0000,
+	0x00000000, 0x031e0000, 0x00000000, 0x83850800, 0x00000009, 0x076000ff,
+	0x0000000f, 0x0f0e0007, 0x00000000, 0x0c000000, 0x00000000, 0x0a7d0000,
+	0x00000000, 0x0afe0000, 0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000,
+	0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
+	0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
+	0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
+	0x00000002, 0x33e70e00, 0x00000000, 0x39840000, 0x00000003, 0xb9720800,
+	0x00000000, 0x28f30000, 0x0000000f, 0x65680010, 0x00000010, 0x009f0000,
+	0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
+	0x00000008, 0x22000007, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
+	0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
+	0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
+	0x0000000c, 0x29000000, 0x00000018, 0x80000145, 0x00000003, 0xf4683600,
+	0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
+	0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
+	0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
+	0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000018, 0x8000ff73, 0x00000010, 0x0ce70005,
+	0x00000008, 0x2c80000c, 0x00000008, 0x2d000070, 0x00000008, 0x2d800010,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000018, 0x8000011d,
+	0x00000000, 0x2c1e0000, 0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010,
+	0x00000008, 0x2d800048, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
+	0x00000018, 0x8000fe5d, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
+	0x00000010, 0x001f0000, 0x00000000, 0x0f008000, 0x00000008, 0x0f800007,
+	0x00000018, 0x80000006, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
+	0x00000010, 0x001f0000, 0x0000000f, 0x0f470007, 0x00000008, 0x0f800008,
+	0x00000018, 0x80000119, 0x00000010, 0x20530000, 0x00000018, 0x8000fe4f,
+	0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
+	0x00000000, 0x2a000000, 0x00000009, 0x0261ffff, 0x0000000d, 0x70e10001,
+	0x00000018, 0x80000101, 0x00000000, 0x2c400000, 0x00000008, 0x2c8000c4,
+	0x00000008, 0x2d00001c, 0x00000008, 0x2d800001, 0x00000005, 0x70e10800,
+	0x00000010, 0x91de0000, 0x00000018, 0x8000fe41, 0x0000000c, 0x29800001,
+	0x00000010, 0x91de0000, 0x00000000, 0x2fd50000, 0x00000010, 0x001f0000,
+	0x00000000, 0x02700000, 0x00000000, 0x0d620000, 0x00000000, 0xbb630800,
+	0x00000000, 0x2a000000, 0x00000000, 0x0f400000, 0x00000000, 0x2c400000,
+	0x0000000c, 0x73e7001b, 0x00000010, 0x0ce7000e, 0x00000000, 0x286d0000,
+	0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff, 0x00000018, 0x80000069,
+	0x00000008, 0x02000004, 0x00000010, 0x91c40803, 0x00000018, 0x800000f6,
+	0x00000010, 0x20530000, 0x00000018, 0x800000e5, 0x00000008, 0x2c8000b8,
+	0x00000008, 0x2d000010, 0x00000008, 0x2d800048, 0x00000018, 0x80000005,
+	0x00000008, 0x2c8000c4, 0x00000008, 0x2d00001c, 0x00000008, 0x2d800001,
+	0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800048,
+	0x00000008, 0x2d000068, 0x00000008, 0x2d800104, 0x00000000, 0x00000000,
+	0x00000010, 0x91de0000, 0x00000000, 0x27f60000, 0x00000010, 0xb87a9e04,
+	0x00000008, 0x2200000d, 0x00000018, 0x800000e2, 0x00000010, 0x20530000,
+	0x00000018, 0x8000fe18, 0x0000000c, 0x29800001, 0x00000010, 0x91de0000,
+	0x00000000, 0x2fd50000, 0x00000010, 0x001f0000, 0x00000000, 0x02700000,
+	0x00000000, 0x0d620000, 0x00000000, 0xbb630800, 0x00000000, 0x2a000000,
+	0x00000010, 0x0e670011, 0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010,
+	0x00000009, 0x266dffff, 0x00000004, 0xb8f1a000, 0x00000000, 0x0f400000,
+	0x0000000c, 0x73e7001c, 0x00000018, 0x80000040, 0x00000008, 0x02000004,
+	0x00000010, 0x91c40802, 0x00000018, 0x800000cd, 0x00000000, 0x2c1e0000,
+	0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010, 0x00000008, 0x2d800048,
+	0x00000010, 0x20530000, 0x00000010, 0x91de0000, 0x00000018, 0x8000fdfe,
+	0x0000000c, 0x29800001, 0x00000000, 0x03550000, 0x00000000, 0x06460000,
+	0x00000000, 0x03d60000, 0x00000000, 0x2a000000, 0x0000000f, 0x0f480007,
+	0x00000010, 0xb18c0027, 0x0000000f, 0x47420008, 0x00000009, 0x070e000f,
+	0x00000008, 0x070e0008, 0x00000010, 0x001f0000, 0x00000008, 0x09000001,
+	0x00000007, 0x09121c00, 0x00000003, 0xcbca9200, 0x00000000, 0x0b97a200,
+	0x00000007, 0x4b171c00, 0x0000000f, 0x0a960003, 0x00000000, 0x0a959c00,
+	0x00000000, 0x4a009a00, 0x00000008, 0x82120001, 0x00000001, 0x0c170800,
+	0x00000000, 0x02180000, 0x00000000, 0x0c971800, 0x00000008, 0x0d00ffff,
+	0x00000008, 0x0f800006, 0x0000000c, 0x29000000, 0x00000008, 0x22000001,
+	0x00000000, 0x22c50c00, 0x00000010, 0x009f0000, 0x00000010, 0xb197320b,
+	0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
+	0x00000018, 0x800000a4, 0x00000000, 0x02180000, 0x00000010, 0x20530000,
+	0x00000000, 0x22c53600, 0x00000010, 0x001f0000, 0x00000008, 0x0f800006,
+	0x00000018, 0x8000fff5, 0x00000010, 0x91870002, 0x00000008, 0x2200000a,
+	0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
+	0x00000018, 0x80000098, 0x00000008, 0x0200000a, 0x00000010, 0x91c40804,
+	0x00000010, 0x02c20003, 0x00000010, 0x001f0000, 0x00000008, 0x0f800008,
+	0x00000010, 0x20530000, 0x00000018, 0x8000fdc9, 0x00000000, 0x06820000,
+	0x00000010, 0x001f0000, 0x00000010, 0x0ce70028, 0x00000000, 0x03720000,
+	0x00000000, 0xa8760c00, 0x00000000, 0x0cf60000, 0x00000010, 0xb8723224,
+	0x00000000, 0x03440000, 0x00000008, 0x22000010, 0x00000000, 0x03ca0000,
+	0x0000000f, 0x65680010, 0x00000000, 0x0bcf0000, 0x00000000, 0x27f20000,
+	0x00000010, 0xb7ef3203, 0x0000000c, 0x21420004, 0x0000000c, 0x73e70019,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x8000007e,
+	0x00000004, 0xb9723200, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
+	0x0000000c, 0x61420004, 0x00000000, 0x25070000, 0x00000000, 0x27970000,
+	0x00000000, 0x290e0000, 0x00000010, 0x0ce70010, 0x00000010, 0xb873320f,
+	0x0000000f, 0x436c0010, 0x00000000, 0x03f30c00, 0x00000000, 0x03f30000,
+	0x00000000, 0x83990e00, 0x00000001, 0x83860e00, 0x00000000, 0x83060e00,
+	0x00000003, 0xf66c0c00, 0x00000000, 0x39f30e00, 0x00000000, 0x3af50e00,
+	0x00000000, 0x7a740000, 0x0000000f, 0x43680010, 0x00000001, 0x83860e00,
+	0x00000000, 0x83060e00, 0x00000003, 0xf4680c00, 0x00000000, 0x286d0000,
+	0x00000000, 0x03690000, 0x00000010, 0xb1f60c54, 0x00000000, 0x0a6a0000,
+	0x00000000, 0x0aeb0000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0c000000,
+	0x00000000, 0x0be90000, 0x00000003, 0x8cf6a000, 0x0000000c, 0x09800002,
+	0x00000010, 0x009f0000, 0x00000010, 0xb8173209, 0x00000000, 0x35140000,
+	0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34970000,
+	0x00000004, 0xb8f12e00, 0x00000010, 0x001f0000, 0x00000008, 0x0f800004,
+	0x00000018, 0x8000fff7, 0x00000000, 0x03e90000, 0x00000010, 0xb8f6a01a,
+	0x00000010, 0x20130019, 0x00000010, 0xb1f10e18, 0x00000000, 0x83973200,
+	0x00000000, 0x38700e00, 0x00000000, 0xbb760e00, 0x00000000, 0x37d00000,
+	0x0000000c, 0x73e7001a, 0x00000003, 0xb8f1a000, 0x00000000, 0x32140000,
+	0x00000000, 0x32950000, 0x00000005, 0x73e72c00, 0x00000000, 0x33190000,
+	0x00000005, 0x74680000, 0x00000010, 0x0ce7000d, 0x00000008, 0x22000009,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x0000000c, 0x73e70019,
+	0x0000000f, 0x65680010, 0x0000000c, 0x21420004, 0x00000018, 0x8000003c,
+	0x00000010, 0x20530000, 0x0000000c, 0x61420004, 0x00000000, 0x290e0000,
+	0x00000018, 0x80000002, 0x00000010, 0x91973206, 0x00000000, 0x35140000,
+	0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34990000,
+	0x00000004, 0xb8f13200, 0x00000000, 0x83690c00, 0x00000010, 0xb1860013,
+	0x00000000, 0x28e90000, 0x00000008, 0x22000004, 0x00000000, 0x23ec0000,
+	0x00000000, 0x03690000, 0x00000010, 0xb8660c07, 0x00000009, 0x036cffff,
+	0x00000000, 0x326a0000, 0x00000000, 0x32eb0000, 0x00000005, 0x73e70c00,
+	0x00000000, 0x33690000, 0x00000005, 0x74680000, 0x0000000c, 0x73e7001c,
+	0x00000000, 0x03690000, 0x00000010, 0xb1f60c12, 0x00000010, 0xb1d00c11,
+	0x0000000c, 0x21420005, 0x0000000c, 0x33e7001c, 0x00000018, 0x8000000e,
+	0x00000010, 0x2e67000d, 0x00000000, 0x03690000, 0x00000010, 0xb1f60c0b,
+	0x00000010, 0xb1d00c0a, 0x00000000, 0x03440000, 0x00000008, 0x2200000c,
+	0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x80000015,
+	0x0000000c, 0x33e7001c, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
+	0x00000000, 0x290e0000, 0x00000018, 0x000d0000, 0x00000000, 0x06820000,
+	0x00000010, 0x2de7000d, 0x00000010, 0x0ce7000c, 0x00000000, 0x27f20000,
+	0x00000010, 0xb96d9e0a, 0x00000000, 0xa86d9e00, 0x00000009, 0x0361ffff,
+	0x00000010, 0xb7500c07, 0x00000008, 0x2200000f, 0x0000000f, 0x65680010,
+	0x00000000, 0x29000000, 0x00000018, 0x80000004, 0x0000000c, 0x33e7001b,
+	0x00000010, 0x20530000, 0x00000018, 0x000d0000, 0x00000000, 0x2b820000,
+	0x00000010, 0x20d2002f, 0x00000010, 0x0052002e, 0x00000009, 0x054e0007,
+	0x00000010, 0xb18a002c, 0x00000000, 0x050a8c00, 0x00000008, 0x850a0008,
+	0x00000010, 0x918a0029, 0x00000003, 0xc5008800, 0x00000008, 0xa3460001,
+	0x00000010, 0xb1c60007, 0x00000008, 0x22000001, 0x0000000c, 0x29800000,
+	0x00000010, 0x20530000, 0x00000000, 0x274e8c00, 0x00000000, 0x66cd0000,
+	0x00000000, 0x22c58c00, 0x00000008, 0x22000014, 0x00000003, 0x22c58e00,
+	0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
+	0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
+	0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x0000000c, 0x69520000,
+	0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000003, 0x22c58e00,
+	0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
+	0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
+	0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x00000000, 0xa2c58c00,
+	0x00000000, 0xa74e8c00, 0x00000000, 0xe6cd0000, 0x0000000f, 0x620a0010,
+	0x00000008, 0x23460001, 0x0000000c, 0x29800000, 0x00000010, 0x20530000,
+	0x0000000c, 0x29520000, 0x00000018, 0x80000002, 0x0000000c, 0x29800000,
+	0x00000018, 0x00570000 };
+
+static const int bnx2_TPAT_b06FwReleaseMajor = 0x1;
+static const int bnx2_TPAT_b06FwReleaseMinor = 0x0;
+static const int bnx2_TPAT_b06FwReleaseFix = 0x0;
+static const u32 bnx2_TPAT_b06FwStartAddr = 0x08000860;
+static const u32 bnx2_TPAT_b06FwTextAddr = 0x08000800;
+static const int bnx2_TPAT_b06FwTextLen = 0x122c;
+static const u32 bnx2_TPAT_b06FwDataAddr = 0x08001a60;
+static const int bnx2_TPAT_b06FwDataLen = 0x0;
+static const u32 bnx2_TPAT_b06FwRodataAddr = 0x00000000;
+static const int bnx2_TPAT_b06FwRodataLen = 0x0;
+static const u32 bnx2_TPAT_b06FwBssAddr = 0x08001aa0;
+static const int bnx2_TPAT_b06FwBssLen = 0x250;
+static const u32 bnx2_TPAT_b06FwSbssAddr = 0x08001a60;
+static const int bnx2_TPAT_b06FwSbssLen = 0x34;
+static u32 bnx2_TPAT_b06FwText[(0x122c/4) + 1] = {
+	0x0a000218, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20322e35,
+	0x2e313100, 0x02050b01, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800,
+	0x24421a60, 0x3c030800, 0x24631cf0, 0xac400000, 0x0043202b, 0x1480fffd,
+	0x24420004, 0x3c1d0800, 0x37bd2ffc, 0x03a0f021, 0x3c100800, 0x26100860,
+	0x3c1c0800, 0x279c1a60, 0x0e000546, 0x00000000, 0x0000000d, 0x8f820010,
+	0x8c450008, 0x24030800, 0xaf430178, 0x97430104, 0x3c020008, 0xaf420140,
+	0x8f820024, 0x30420001, 0x10400007, 0x3069ffff, 0x24020002, 0x2523fffe,
+	0xa7420146, 0xa7430148, 0x0a000242, 0x3c020800, 0xa7400146, 0x3c020800,
+	0x8c43083c, 0x1460000e, 0x24020f00, 0x8f820024, 0x30430020, 0x0003182b,
+	0x00031823, 0x30650009, 0x30420c00, 0x24030400, 0x14430002, 0x34a40001,
+	0x34a40005, 0xa744014a, 0x0a000264, 0x3c020800, 0x8f830014, 0x14620008,
+	0x00000000, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023, 0x3042000d,
+	0x0a000262, 0x34420005, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023,
+	0x30420009, 0x34420001, 0xa742014a, 0x3c020800, 0x8c430820, 0x8f840024,
+	0x3c020048, 0x00621825, 0x30840006, 0x24020002, 0x1082000d, 0x2c820003,
+	0x50400005, 0x24020004, 0x10800012, 0x3c020001, 0x0a000284, 0x00000000,
+	0x10820007, 0x24020006, 0x1482000f, 0x3c020111, 0x0a00027c, 0x00621025,
+	0x0a00027b, 0x3c020101, 0x3c020011, 0x00621025, 0x24030001, 0xaf421000,
+	0xaf830020, 0x0a000284, 0x00000000, 0x00621025, 0xaf421000, 0xaf800020,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f830020, 0x1060003f,
+	0x3c048000, 0x8f421000, 0x00441024, 0x1040fffd, 0x00000000, 0x10600039,
+	0x00000000, 0x8f421000, 0x3c030020, 0x00431024, 0x10400034, 0x00000000,
+	0x97421014, 0x14400031, 0x00000000, 0x97421008, 0x8f840010, 0x24420006,
+	0x00024082, 0x00081880, 0x00643821, 0x8ce50000, 0x30430003, 0x30420001,
+	0x10400004, 0x00000000, 0x0000000d, 0x0a0002c3, 0x00081080, 0x5460000f,
+	0x30a5ffff, 0x3c06ffff, 0x00a62824, 0x0005182b, 0x00a61026, 0x0002102b,
+	0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x240001fb,
+	0x8ce20000, 0x0a0002c2, 0x00462825, 0x0005182b, 0x38a2ffff, 0x0002102b,
+	0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x24000205,
+	0x8ce20000, 0x3445ffff, 0x00081080, 0x00441021, 0x3c030800, 0xac450000,
+	0x8c620830, 0x24420001, 0xac620830, 0x8f840018, 0x01202821, 0x24820008,
+	0x30421fff, 0x24434000, 0x0343d821, 0x30a30007, 0xaf84000c, 0xaf820018,
+	0xaf420084, 0x10600002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000,
+	0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023,
+	0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000,
+	0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x8f830024, 0x27bdffe0,
+	0xafbf0018, 0xafb10014, 0x30620200, 0x14400004, 0xafb00010, 0x0000000d,
+	0x00000000, 0x24000242, 0x00031a82, 0x30630003, 0x000310c0, 0x00431021,
+	0x00021080, 0x00431021, 0x00021080, 0x3c030800, 0x24631aa0, 0x00438821,
+	0x8e240000, 0x10800004, 0x00000000, 0x0000000d, 0x00000000, 0x2400024d,
+	0x8f850010, 0x24020001, 0xae220000, 0x8ca70008, 0xa2200007, 0x8f620004,
+	0x26300014, 0x02002021, 0x00021402, 0xa2220004, 0x304600ff, 0x24c60005,
+	0x0e000673, 0x00063082, 0x8f620004, 0xa6220008, 0x8f430108, 0x3c021000,
+	0x00621824, 0x10600008, 0x00000000, 0x97420104, 0x92230007, 0x2442ffec,
+	0x3045ffff, 0x34630002, 0x0a000321, 0xa2230007, 0x97420104, 0x2442fff0,
+	0x3045ffff, 0x8f620004, 0x3042ffff, 0x2c420013, 0x54400005, 0x92230007,
+	0x92220007, 0x34420001, 0xa2220007, 0x92230007, 0x24020001, 0x10620009,
+	0x28620002, 0x14400014, 0x24020002, 0x10620012, 0x24020003, 0x1062000a,
+	0x00000000, 0x0a000342, 0x00000000, 0x8f820010, 0x8c43000c, 0x3c04ffff,
+	0x00641824, 0x00651825, 0x0a000342, 0xac43000c, 0x8f820010, 0x8c430010,
+	0x3c04ffff, 0x00641824, 0x00651825, 0xac430010, 0x8f620004, 0x3042ffff,
+	0x24420002, 0x00021083, 0xa2220005, 0x304500ff, 0x8f820010, 0x3c04ffff,
+	0x00052880, 0x00a22821, 0x8ca70000, 0x96220008, 0x97430104, 0x00e42024,
+	0x24420002, 0x00621823, 0x00833825, 0xaca70000, 0x92240005, 0x00041080,
+	0x02021021, 0x90430000, 0x3c05fff6, 0x34a5ffff, 0x3063000f, 0x00832021,
+	0xa2240006, 0x308200ff, 0x24420003, 0x00021080, 0x02021021, 0x8c460000,
+	0x308300ff, 0x8f820010, 0x3c04ff3f, 0x00031880, 0x00c53824, 0x00621821,
+	0xae26000c, 0xac67000c, 0x8e22000c, 0x92230006, 0x3484ffff, 0x00441024,
+	0x24630003, 0x00031880, 0x02031821, 0x00e42024, 0xae22000c, 0xac640000,
+	0x92220006, 0x24420004, 0x00021080, 0x02021021, 0x94470002, 0xac470000,
+	0x92230006, 0x8f820010, 0x00031880, 0x00621821, 0x24020010, 0xac670010,
+	0x24030002, 0xa7420140, 0xa7400142, 0xa7400144, 0xa7430146, 0x97420104,
+	0x24030001, 0x2442fffe, 0xa7420148, 0xa743014a, 0x8f820024, 0x24030002,
+	0x30440006, 0x1083000d, 0x2c820003, 0x10400005, 0x24020004, 0x10800011,
+	0x3c020009, 0x0a0003a5, 0x00000000, 0x10820007, 0x24020006, 0x1482000d,
+	0x3c020119, 0x0a00039f, 0x24030001, 0x0a00039e, 0x3c020109, 0x3c020019,
+	0x24030001, 0xaf421000, 0xaf830020, 0x0a0003a5, 0x00000000, 0xaf421000,
+	0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92220004,
+	0x24030008, 0x8f840020, 0x24420002, 0x30420007, 0x00621823, 0x30630007,
+	0x10800006, 0xae230010, 0x3c038000, 0x8f421000, 0x00431024, 0x1040fffd,
+	0x00000000, 0x8f820018, 0xaf82000c, 0x24420010, 0x30421fff, 0xaf820018,
+	0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007,
+	0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821,
+	0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030,
+	0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021,
+	0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008,
+	0x27bd0020, 0x8f830024, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x30620200,
+	0x14400004, 0xafb00010, 0x0000000d, 0x00000000, 0x240002e4, 0x00031a82,
+	0x30630003, 0x000310c0, 0x00431021, 0x00021080, 0x00431021, 0x00021080,
+	0x3c030800, 0x24631aa0, 0x00438021, 0x8e040000, 0x14800004, 0x00000000,
+	0x0000000d, 0x00000000, 0x240002e9, 0x8f620004, 0x04410008, 0x26050014,
+	0x92020006, 0x8e03000c, 0x24420003, 0x00021080, 0x00a21021, 0xac430000,
+	0xae000000, 0x92020005, 0x24420001, 0x00021080, 0x00a21021, 0x8c430000,
+	0x3c040001, 0x00641821, 0xac430000, 0x92060004, 0x27710008, 0x02202021,
+	0x24c60005, 0x0e000673, 0x00063082, 0x92040006, 0x3c057fff, 0x8f620004,
+	0x00042080, 0x00912021, 0x8c830004, 0x34a5ffff, 0x00451024, 0x00621821,
+	0xac830004, 0x92050005, 0x3c07ffff, 0x92040004, 0x00052880, 0x00b12821,
+	0x8ca30000, 0x97420104, 0x96060008, 0x00671824, 0x00441021, 0x00461023,
+	0x3042ffff, 0x00621825, 0xaca30000, 0x92030007, 0x24020001, 0x1062000a,
+	0x28620002, 0x1440001d, 0x2402000a, 0x24020002, 0x10620019, 0x24020003,
+	0x1062000e, 0x2402000a, 0x0a000447, 0x00000000, 0x92020004, 0x97430104,
+	0x8e24000c, 0x00621821, 0x2463fff2, 0x3063ffff, 0x00872024, 0x00832025,
+	0xae24000c, 0x0a000447, 0x2402000a, 0x92020004, 0x97430104, 0x8e240010,
+	0x00621821, 0x2463ffee, 0x3063ffff, 0x00872024, 0x00832025, 0xae240010,
+	0x2402000a, 0xa7420140, 0x96030012, 0x8f840024, 0xa7430142, 0x92020004,
+	0xa7420144, 0xa7400146, 0x97430104, 0x30840006, 0x24020001, 0xa7430148,
+	0xa742014a, 0x24020002, 0x1082000d, 0x2c820003, 0x10400005, 0x24020004,
+	0x10800011, 0x3c020041, 0x0a00046c, 0x00000000, 0x10820007, 0x24020006,
+	0x1482000d, 0x3c020151, 0x0a000466, 0x24030001, 0x0a000465, 0x3c020141,
+	0x3c020051, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00046c, 0x00000000,
+	0xaf421000, 0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x8f820020, 0x8f840018, 0x10400006, 0x92030004, 0x3c058000, 0x8f421000,
+	0x00451024, 0x1040fffd, 0x00000000, 0x2463000a, 0x30620007, 0x10400002,
+	0x24620007, 0x304303f8, 0x00831021, 0x30421fff, 0xaf84000c, 0xaf820018,
+	0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007,
+	0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821,
+	0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030,
+	0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021,
+	0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008,
+	0x27bd0020, 0x8f620000, 0x97430104, 0x3c048000, 0x3045ffff, 0x3066ffff,
+	0x8f420178, 0x00441024, 0x1440fffd, 0x2402000a, 0x30a30007, 0xa7420140,
+	0x24020008, 0x00431023, 0x30420007, 0x24a3fffe, 0xa7420142, 0xa7430144,
+	0xa7400146, 0xa7460148, 0x8f420108, 0x8f830024, 0x30420020, 0x0002102b,
+	0x00021023, 0x30420009, 0x34420001, 0x30630006, 0xa742014a, 0x24020002,
+	0x1062000d, 0x2c620003, 0x10400005, 0x24020004, 0x10600011, 0x3c020041,
+	0x0a0004d6, 0x00000000, 0x10620007, 0x24020006, 0x1462000d, 0x3c020151,
+	0x0a0004d0, 0x24030001, 0x0a0004cf, 0x3c020141, 0x3c020051, 0x24030001,
+	0xaf421000, 0xaf830020, 0x0a0004d6, 0x00000000, 0xaf421000, 0xaf800020,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f820020, 0x24a30008,
+	0x8f850018, 0x10400006, 0x30c6ffff, 0x3c048000, 0x8f421000, 0x00441024,
+	0x1040fffd, 0x00000000, 0x3063ffff, 0x30620007, 0x10400002, 0x24620007,
+	0x3043fff8, 0x00a31021, 0x30421fff, 0x24434000, 0x0343d821, 0x00c02021,
+	0x30830007, 0xaf85000c, 0xaf820018, 0xaf420084, 0x10600002, 0x24820007,
+	0x3044fff8, 0x8f820030, 0x8f850000, 0x00441821, 0xaf82001c, 0x0065102b,
+	0xaf830030, 0x14400002, 0x00651023, 0xaf820030, 0x8f840030, 0x34028000,
+	0x3c030800, 0x8c650834, 0x00821021, 0x03421821, 0xaf830010, 0xaf440080,
+	0x10a00006, 0x2402000e, 0x9383002f, 0x14620004, 0x3c021000, 0x2402043f,
+	0xa7420148, 0x3c021000, 0x03e00008, 0xaf420178, 0x8f820024, 0x30424000,
+	0x10400005, 0x24020800, 0x0000000d, 0x00000000, 0x2400040e, 0x24020800,
+	0xaf420178, 0x97440104, 0x3c030008, 0xaf430140, 0x8f820024, 0x30420001,
+	0x10400006, 0x3085ffff, 0x24020002, 0x24a3fffe, 0xa7420146, 0x0a000526,
+	0xa7430148, 0xa7400146, 0x8f840018, 0x2402000d, 0xa742014a, 0x24830008,
+	0x30631fff, 0x24624000, 0x0342d821, 0x30a20007, 0xaf84000c, 0xaf830018,
+	0xaf430084, 0x10400002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000,
+	0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023,
+	0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000,
+	0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x27bdffe8, 0x3c046008,
+	0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, 0x375b4000,
+	0x00431024, 0x3442380c, 0xac825000, 0x8f430008, 0x3c100800, 0x37428000,
+	0x34630001, 0xaf430008, 0xaf820010, 0x3c02601c, 0xaf800018, 0xaf400080,
+	0xaf400084, 0x8c450008, 0x3c036000, 0x8c620808, 0x3c040800, 0x3c030080,
+	0xac830820, 0x3042fff0, 0x38420010, 0x2c420001, 0xaf850000, 0xaf820004,
+	0x0e000658, 0x00000000, 0x8f420000, 0x30420001, 0x1040fffb, 0x00000000,
+	0x8f430108, 0x8f440100, 0x30622000, 0xaf830024, 0xaf840014, 0x10400004,
+	0x8e02082c, 0x24420001, 0x0a0005c6, 0xae02082c, 0x30620200, 0x14400003,
+	0x24020f00, 0x14820027, 0x24020d00, 0x97420104, 0x1040001c, 0x30624000,
+	0x14400005, 0x00000000, 0x0e00022f, 0x00000000, 0x0a0005bb, 0x00000000,
+	0x8f620008, 0x8f630000, 0x24020030, 0x00031e02, 0x306300f0, 0x10620007,
+	0x28620031, 0x1440002f, 0x24020040, 0x10620007, 0x00000000, 0x0a0005bb,
+	0x00000000, 0x0e0002e8, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0003db,
+	0x00000000, 0x0a0005bb, 0x00000000, 0x30620040, 0x1440002b, 0x00000000,
+	0x0000000d, 0x00000000, 0x240004b2, 0x0a0005c6, 0x00000000, 0x1482000f,
+	0x30620006, 0x97420104, 0x10400005, 0x30620040, 0x0e000510, 0x00000000,
+	0x0a0005bb, 0x00000000, 0x1440001b, 0x00000000, 0x0000000d, 0x00000000,
+	0x240004c4, 0x0a0005c6, 0x00000000, 0x1040000e, 0x30621000, 0x10400005,
+	0x00000000, 0x0e000688, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0004a1,
+	0x00000000, 0x8f82002c, 0x24420001, 0xaf82002c, 0x0a0005c6, 0x00000000,
+	0x30620040, 0x14400004, 0x00000000, 0x0000000d, 0x00000000, 0x240004db,
+	0x8f420138, 0x3c034000, 0x00431025, 0xaf420138, 0x0a000566, 0x00000000,
+	0x3c046008, 0x8c835000, 0x3c1a8000, 0x2402ff7f, 0x375b4000, 0x00621824,
+	0x3463380c, 0xac835000, 0x8f420008, 0x3c056000, 0x3c03601c, 0x34420001,
+	0xaf420008, 0x37428000, 0xaf800018, 0xaf820010, 0xaf400080, 0xaf400084,
+	0x8c660008, 0x8ca20808, 0x3c040800, 0x3c030080, 0xac830820, 0x3042fff0,
+	0x38420010, 0x2c420001, 0xaf860000, 0xaf820004, 0x03e00008, 0x00000000,
+	0x3084ffff, 0x30820007, 0x10400002, 0x24820007, 0x3044fff8, 0x8f820018,
+	0x00441821, 0x30631fff, 0x24644000, 0x0344d821, 0xaf82000c, 0xaf830018,
+	0x03e00008, 0xaf430084, 0x3084ffff, 0x30820007, 0x10400002, 0x24820007,
+	0x3044fff8, 0x8f820030, 0x8f830000, 0x00442021, 0xaf82001c, 0x0083102b,
+	0xaf840030, 0x14400002, 0x00831023, 0xaf820030, 0x8f820030, 0x34038000,
+	0x00431821, 0x03432021, 0xaf840010, 0x03e00008, 0xaf420080, 0x8f830024,
+	0x24020002, 0x30630006, 0x1062000d, 0x2c620003, 0x50400005, 0x24020004,
+	0x10600012, 0x3c020001, 0x0a00062a, 0x00000000, 0x10620007, 0x24020006,
+	0x1462000f, 0x3c020111, 0x0a000622, 0x00821025, 0x0a000621, 0x3c020101,
+	0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00062a,
+	0x00000000, 0x00821025, 0xaf421000, 0xaf800020, 0x00000000, 0x00000000,
+	0x00000000, 0x03e00008, 0x00000000, 0x8f820020, 0x10400005, 0x3c038000,
+	0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x03e00008, 0x00000000,
+	0x8f820024, 0x27bdffe8, 0x30424000, 0x14400005, 0xafbf0010, 0x0e00022f,
+	0x00000000, 0x0a000656, 0x8fbf0010, 0x8f620008, 0x8f630000, 0x24020030,
+	0x00031e02, 0x306300f0, 0x10620008, 0x28620031, 0x1440000d, 0x8fbf0010,
+	0x24020040, 0x10620007, 0x00000000, 0x0a000656, 0x00000000, 0x0e0002e8,
+	0x00000000, 0x0a000656, 0x8fbf0010, 0x0e0003db, 0x00000000, 0x8fbf0010,
+	0x03e00008, 0x27bd0018, 0x8f840028, 0x1080000f, 0x3c026000, 0x8c430c3c,
+	0x30630fff, 0xaf830008, 0x14600011, 0x3082000f, 0x10400005, 0x308200f0,
+	0x10400003, 0x30820f00, 0x14400006, 0x00000000, 0x0000000d, 0x00000000,
+	0x2400051a, 0x03e00008, 0x00000000, 0x0000000d, 0x00000000, 0x2400051f,
+	0x03e00008, 0x00000000, 0xaf830028, 0x03e00008, 0x00000000, 0x10c00007,
+	0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb,
+	0x24840004, 0x03e00008, 0x00000000, 0x0a000684, 0x00a01021, 0xac860000,
+	0x00000000, 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa, 0x24a5ffff,
+	0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x00000000};
+
+static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 };
+static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 };
+
+static const int bnx2_TXP_b06FwReleaseMajor = 0x1;
+static const int bnx2_TXP_b06FwReleaseMinor = 0x0;
+static const int bnx2_TXP_b06FwReleaseFix = 0x0;
+static const u32 bnx2_TXP_b06FwStartAddr = 0x080034b0;
+static const u32 bnx2_TXP_b06FwTextAddr = 0x08000000;
+static const int bnx2_TXP_b06FwTextLen = 0x5748;
+static const u32 bnx2_TXP_b06FwDataAddr = 0x08005760;
+static const int bnx2_TXP_b06FwDataLen = 0x0;
+static const u32 bnx2_TXP_b06FwRodataAddr = 0x00000000;
+static const int bnx2_TXP_b06FwRodataLen = 0x0;
+static const u32 bnx2_TXP_b06FwBssAddr = 0x080057a0;
+static const int bnx2_TXP_b06FwBssLen = 0x1c4;
+static const u32 bnx2_TXP_b06FwSbssAddr = 0x08005760;
+static const int bnx2_TXP_b06FwSbssLen = 0x38;
+static u32 bnx2_TXP_b06FwText[(0x5748/4) + 1] = {
+	0x0a000d2c, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x322e352e,
+	0x38000000, 0x02050800, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800,
+	0x24425760, 0x3c030800, 0x24635964, 0xac400000, 0x0043202b, 0x1480fffd,
+	0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261034b0,
+	0x3c1c0800, 0x279c5760, 0x0e000f5b, 0x00000000, 0x0000000d, 0x8f840014,
+	0x27bdffe8, 0xafb10014, 0xafb00010, 0x8f460104, 0x8f830008, 0x8c8500ac,
+	0xaf430080, 0x948200a8, 0xa7420e10, 0x948300aa, 0xa7430e12, 0x8c8200ac,
+	0xaf420e18, 0x97430e10, 0xa7430e14, 0x97420e12, 0x00008021, 0xa7420e16,
+	0x8f430e18, 0x00006021, 0x00c53023, 0xaf430e1c, 0x10c001a2, 0x2d820001,
+	0x3c0e1000, 0x2419fff8, 0x24110010, 0x240f0f00, 0x3c188100, 0x93620008,
+	0x10400009, 0x00000000, 0x97620010, 0x00c2102b, 0x14400005, 0x00000000,
+	0x97620010, 0x3042ffff, 0x0a000d6d, 0xaf420e00, 0xaf460e00, 0x8f420000,
+	0x30420008, 0x1040fffd, 0x00000000, 0x97420e08, 0x8f450e04, 0x3044ffff,
+	0x30820001, 0x14400005, 0x00000000, 0x14a00005, 0x3083a040, 0x0a000f34,
+	0x00000000, 0x0000000d, 0x3083a040, 0x24020040, 0x1462004f, 0x3082a000,
+	0x308a0036, 0x8f88000c, 0x30890008, 0x24020800, 0xaf420178, 0x01001821,
+	0x9742008a, 0x00431023, 0x2442ffff, 0x30421fff, 0x2c420008, 0x1440fffa,
+	0x00a06021, 0x8f820018, 0x00cc3023, 0x24070001, 0x8f830008, 0x304b00ff,
+	0x24420001, 0xaf820018, 0x25024000, 0x106f0005, 0x03422021, 0x93820012,
+	0x30420007, 0x00021240, 0x34470001, 0x000b1400, 0x3c030100, 0x00431025,
+	0xac820000, 0x8f830018, 0x00ea3825, 0x1120000f, 0xac830004, 0x97430e0a,
+	0x8f84000c, 0x00ee3825, 0x2402000e, 0x00781825, 0xaf430160, 0x25830006,
+	0x24840008, 0x30841fff, 0xa742015a, 0xa7430158, 0xaf84000c, 0x0a000db7,
+	0x00000000, 0x8f83000c, 0x25820002, 0xa7420158, 0x24630008, 0x30631fff,
+	0xaf83000c, 0x54c0000f, 0x8f420e14, 0x8f820008, 0x504f0002, 0x24100001,
+	0x34e70040, 0x97420e10, 0x97430e12, 0x8f850014, 0x00021400, 0x00621825,
+	0xaca300a8, 0x8f840014, 0x8f420e18, 0xac8200ac, 0x8f420e14, 0x8f430e1c,
+	0xaf420144, 0xaf430148, 0xa34b0152, 0xaf470154, 0x0a000efb, 0xaf4e0178,
+	0x10400165, 0x00000000, 0x93620008, 0x50400008, 0xafa60008, 0x97620010,
+	0x00a2102b, 0x10400003, 0x30820040, 0x1040015c, 0x00000000, 0xafa60008,
+	0xa7840010, 0xaf850004, 0x93620008, 0x1440005f, 0x27ac0008, 0xaf60000c,
+	0x97820010, 0x30424000, 0x10400002, 0x2403000e, 0x24030016, 0xa363000a,
+	0x24034007, 0xaf630014, 0x93820012, 0x8f630014, 0x30420007, 0x00021240,
+	0x00621825, 0xaf630014, 0x97820010, 0x8f630014, 0x30420010, 0x00621825,
+	0xaf630014, 0x97820010, 0x30420008, 0x5040000e, 0x00002821, 0x8f620014,
+	0x004e1025, 0xaf620014, 0x97430e0a, 0x2402000e, 0x00781825, 0xaf630004,
+	0xa3620002, 0x9363000a, 0x3405fffc, 0x24630004, 0x0a000e06, 0xa363000a,
+	0xaf600004, 0xa3600002, 0x97820010, 0x9363000a, 0x30421f00, 0x00021182,
+	0x24420028, 0x00621821, 0xa3630009, 0x97420e0c, 0xa7620010, 0x93630009,
+	0x24020008, 0x24630002, 0x30630007, 0x00431023, 0x30420007, 0xa362000b,
+	0x93640009, 0x97620010, 0x8f890004, 0x97830010, 0x00441021, 0x00a21021,
+	0x30630040, 0x10600007, 0x3045ffff, 0x00a9102b, 0x14400005, 0x0125102b,
+	0x3c068000, 0x0a000e3a, 0x00005821, 0x0125102b, 0x544000c7, 0x00006021,
+	0x97420e14, 0xa7420e10, 0x97430e16, 0xa7430e12, 0x8f420e1c, 0xaf420e18,
+	0xaf450e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000, 0x97420e08,
+	0x00a04821, 0xa7820010, 0x8f430e04, 0x00003021, 0x240b0001, 0xaf830004,
+	0x97620010, 0x0a000e4c, 0x304dffff, 0x8f890004, 0x97820010, 0x30420040,
+	0x10400004, 0x01206821, 0x3c068000, 0x0a000e4c, 0x00005821, 0x97630010,
+	0x8f820004, 0x10430003, 0x00003021, 0x0a000eee, 0x00006021, 0x240b0001,
+	0x8d820000, 0x00491023, 0x1440000d, 0xad820000, 0x8f620014, 0x34420040,
+	0xaf620014, 0x97430e10, 0x97420e12, 0x8f840014, 0x00031c00, 0x00431025,
+	0xac8200a8, 0x8f830014, 0x8f420e18, 0xac6200ac, 0x93620008, 0x1440003e,
+	0x00000000, 0x25260002, 0x8f84000c, 0x9743008a, 0x3063ffff, 0xafa30000,
+	0x8fa20000, 0x00441023, 0x2442ffff, 0x30421fff, 0x2c420010, 0x1440fff7,
+	0x00000000, 0x8f82000c, 0x8f830018, 0x00021082, 0x00021080, 0x24424000,
+	0x03422821, 0x00605021, 0x24630001, 0x314200ff, 0x00021400, 0xaf830018,
+	0x3c033200, 0x00431025, 0xaca20000, 0x93630009, 0x9362000a, 0x00031c00,
+	0x00431025, 0xaca20004, 0x8f830018, 0xaca30008, 0x97820010, 0x30420008,
+	0x10400002, 0x00c04021, 0x25280006, 0x97430e14, 0x93640002, 0x8f450e1c,
+	0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0xa7420146,
+	0xaf450148, 0xa34a0152, 0x8f82000c, 0x308400ff, 0xa744015a, 0xaf460160,
+	0xa7480158, 0xaf470154, 0xaf4e0178, 0x00511021, 0x30421fff, 0xaf82000c,
+	0x0a000ed9, 0x8d820000, 0x93620009, 0x9363000b, 0x8f85000c, 0x2463000a,
+	0x00435021, 0x25440007, 0x00992024, 0x9743008a, 0x3063ffff, 0xafa30000,
+	0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b, 0x1440fff7,
+	0x00000000, 0x8f82000c, 0x8f840018, 0x00021082, 0x00021080, 0x24424000,
+	0x03422821, 0x00804021, 0x24840001, 0xaf840018, 0x93630009, 0x310200ff,
+	0x00022400, 0x3c024100, 0x24630002, 0x00621825, 0x00832025, 0xaca40000,
+	0x8f62000c, 0x00461025, 0xaca20004, 0x97430e14, 0x93640002, 0x8f450e1c,
+	0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0x308400ff,
+	0xa7420146, 0xaf450148, 0xa3480152, 0x8f83000c, 0x25420007, 0x00591024,
+	0xa744015a, 0xaf460160, 0xa7490158, 0xaf470154, 0xaf4e0178, 0x00621821,
+	0x30631fff, 0xaf83000c, 0x8d820000, 0x14400005, 0x00000000, 0x8f620014,
+	0x2403ffbf, 0x00431024, 0xaf620014, 0x8f62000c, 0x004d1021, 0xaf62000c,
+	0x93630008, 0x14600008, 0x00000000, 0x11600006, 0x00000000, 0x8f630014,
+	0x3c02efff, 0x3442fffe, 0x00621824, 0xaf630014, 0xa36b0008, 0x01206021,
+	0x1580000c, 0x8fa60008, 0x97420e14, 0x97430e16, 0x8f850014, 0x00021400,
+	0x00621825, 0xaca300a8, 0x8f840014, 0x8f420e1c, 0xac8200ac, 0x0a000efd,
+	0x2d820001, 0x14c0fe65, 0x2d820001, 0x00501025, 0x10400058, 0x24020f00,
+	0x8f830008, 0x14620023, 0x3c048000, 0x11800009, 0x3c038000, 0x97420e08,
+	0x30420040, 0x14400005, 0x00000000, 0x0000000d, 0x00000000, 0x2400032c,
+	0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x00000000, 0x97420e10,
+	0x3c030500, 0x00431025, 0xaf42014c, 0x97430e14, 0xa7430144, 0x97420e16,
+	0xa7420146, 0x8f430e1c, 0x24022000, 0xaf430148, 0x3c031000, 0xa3400152,
+	0xa740015a, 0xaf400160, 0xa7400158, 0xaf420154, 0xaf430178, 0x8f830008,
+	0x3c048000, 0x8f420178, 0x00441024, 0x1440fffd, 0x24020f00, 0x10620016,
+	0x00000000, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c,
+	0x3c031000, 0xaf420148, 0x0a000f51, 0x24020240, 0x97420e14, 0x97430e16,
+	0x8f840014, 0x00021400, 0x00621825, 0xac8300a8, 0x8f850014, 0x8f420e1c,
+	0x00006021, 0xaca200ac, 0x0a000efd, 0x2d820001, 0xaf40014c, 0x11800007,
+	0x00000000, 0x97420e10, 0xa7420144, 0x97430e12, 0xa7430146, 0x0a000f4e,
+	0x8f420e18, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c,
+	0xaf420148, 0x24020040, 0x3c031000, 0xa3400152, 0xa740015a, 0xaf400160,
+	0xa7400158, 0xaf420154, 0xaf430178, 0x8fb10014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x27bdffd0, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008,
+	0x03421821, 0xafbf002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c,
+	0xafb20018, 0xafb10014, 0xafb00010, 0xaf830014, 0xaf440e00, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd,
+	0x3c046004, 0xaf420e00, 0x8c835000, 0x24160800, 0x24150d00, 0x3c140800,
+	0x24130f00, 0x3c120800, 0x3c114000, 0x2402ff7f, 0x00621824, 0x3463380c,
+	0x24020009, 0xac835000, 0xaf420008, 0xaf800018, 0xaf80000c, 0x0e001559,
+	0x00000000, 0x0e000ff0, 0x00000000, 0x3c020800, 0x245057c0, 0x8f420000,
+	0x30420001, 0x1040fffd, 0x00000000, 0x8f440100, 0xaf840008, 0xaf440020,
+	0xaf560178, 0x93430108, 0xa3830012, 0x93820012, 0x30420001, 0x10400008,
+	0x00000000, 0x93820012, 0x30420006, 0x00021100, 0x0e000d43, 0x0050d821,
+	0x0a000fac, 0x00000000, 0x14950005, 0x00000000, 0x0e000d43, 0x269b5840,
+	0x0a000fac, 0x00000000, 0x14930005, 0x00000000, 0x0e000d43, 0x265b5860,
+	0x0a000fac, 0x00000000, 0x0e0010ea, 0x00000000, 0xaf510138, 0x0a000f89,
+	0x00000000, 0x27bdfff8, 0x3084ffff, 0x24820007, 0x3044fff8, 0x8f85000c,
+	0x9743008a, 0x3063ffff, 0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff,
+	0x30421fff, 0x0044102b, 0x1440fff7, 0x00000000, 0x8f82000c, 0x00021082,
+	0x00021080, 0x24424000, 0x03421021, 0x03e00008, 0x27bd0008, 0x3084ffff,
+	0x8f82000c, 0x24840007, 0x3084fff8, 0x00441021, 0x30421fff, 0xaf82000c,
+	0x03e00008, 0x00000000, 0x27bdffe8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd,
+	0x3c020008, 0x03421821, 0xafbf0010, 0xaf830014, 0xaf440e00, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd,
+	0x3c046004, 0xaf420e00, 0x8c825000, 0x2403ff7f, 0x00431024, 0x3442380c,
+	0x24030009, 0xac825000, 0xaf430008, 0xaf800018, 0xaf80000c, 0x0e001559,
+	0x00000000, 0x0e000ff0, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018,
+	0x27bdffe8, 0x3c02000a, 0x03421821, 0x3c040800, 0x24845880, 0x24050019,
+	0xafbf0010, 0xaf830024, 0x0e001565, 0x00003021, 0x3c050800, 0x3c020800,
+	0x24425330, 0xaca258e8, 0x24a558e8, 0x3c020800, 0x244254f8, 0x3c030800,
+	0x2463550c, 0x3c040800, 0xaca20004, 0x3c020800, 0x24425338, 0xaca30008,
+	0xac825900, 0x24845900, 0x3c020800, 0x244253c4, 0x3c070800, 0x24e75404,
+	0x3c060800, 0x24c65520, 0x3c050800, 0x24a55438, 0x3c030800, 0xac820004,
+	0x3c020800, 0x24425528, 0xac870008, 0xac86000c, 0xac850010, 0xac625920,
+	0x24635920, 0x8fbf0010, 0x3c020800, 0x24425540, 0xac620004, 0x3c020800,
+	0xac670008, 0xac66000c, 0xac650010, 0xac400048, 0x03e00008, 0x27bd0018,
+	0x974309da, 0x00804021, 0xad030000, 0x8f4209dc, 0xad020004, 0x8f4309e0,
+	0xad030008, 0x934409d9, 0x24020001, 0x30840003, 0x1082001f, 0x30a900ff,
+	0x28820002, 0x10400005, 0x24020002, 0x10800009, 0x3c0a0800, 0x0a001078,
+	0x93420934, 0x1082000b, 0x24020003, 0x10820026, 0x3c0a0800, 0x0a001078,
+	0x93420934, 0x974209e4, 0x00021400, 0x34420800, 0xad02000c, 0x0a001077,
+	0x25080010, 0x974209e4, 0x00021400, 0x34428100, 0xad02000c, 0x974309e8,
+	0x3c0a0800, 0x00031c00, 0x34630800, 0xad030010, 0x0a001077, 0x25080014,
+	0x974409e4, 0x3c050800, 0x24a25880, 0x9443001c, 0x94460014, 0x94470010,
+	0x00a05021, 0x24020800, 0xad000010, 0xad020014, 0x00042400, 0x00661821,
+	0x00671823, 0x2463fff2, 0x00832025, 0xad04000c, 0x0a001077, 0x25080018,
+	0x974209e4, 0x3c050800, 0x00021400, 0x34428100, 0xad02000c, 0x974409e8,
+	0x24a25880, 0x9443001c, 0x94460014, 0x94470010, 0x00a05021, 0x24020800,
+	0xad000014, 0xad020018, 0x00042400, 0x00661821, 0x00671823, 0x2463ffee,
+	0x00832025, 0xad040010, 0x2508001c, 0x93420934, 0x93450921, 0x3c074000,
+	0x25445880, 0x94830018, 0x94860014, 0x00021082, 0x00021600, 0x00052c00,
+	0x00a72825, 0x00451025, 0x00661821, 0x00431025, 0xad020000, 0x9783002c,
+	0x974209ea, 0x00621821, 0x00031c00, 0xad030004, 0x9782002c, 0x24420001,
+	0x30427fff, 0xa782002c, 0x93430920, 0x3c020006, 0x00031e00, 0x00621825,
+	0xad030008, 0x8f42092c, 0xad02000c, 0x8f430930, 0xad030010, 0x8f440938,
+	0x25080014, 0xad040000, 0x8f820020, 0x11200004, 0xad020004, 0x8f420940,
+	0x0a0010a1, 0x2442ffff, 0x8f420940, 0xad020008, 0x8f440948, 0x8f420940,
+	0x93430936, 0x00823023, 0x00663006, 0x3402ffff, 0x0046102b, 0x54400001,
+	0x3406ffff, 0x93420937, 0x25445880, 0x90830024, 0xad000010, 0x00021700,
+	0x34630010, 0x00031c00, 0x00431025, 0x00461025, 0xad02000c, 0x8c830008,
+	0x14600031, 0x25080014, 0x3c020800, 0x8c430048, 0x1060002d, 0x00000000,
+	0x9342010b, 0xad020000, 0x8f830000, 0x8c6200b0, 0xad020004, 0x8f830000,
+	0x8c6200b4, 0xad020008, 0x8f830000, 0x8c6200c0, 0xad02000c, 0x8f830000,
+	0x8c6200c4, 0xad020010, 0x8f830000, 0x8c6200c8, 0xad020014, 0x8f830000,
+	0x8c6200cc, 0xad020018, 0x8f830000, 0x8c6200e0, 0xad02001c, 0x8f830000,
+	0x8c6200e8, 0xad020020, 0x8f830000, 0x8c6200f0, 0x3c04600e, 0xad020024,
+	0x8c8200d0, 0xad020028, 0x8c8300d4, 0xad03002c, 0x8f820028, 0x3c046012,
+	0xad020030, 0x8c8200a8, 0xad020034, 0x8c8300ac, 0x3c026000, 0xad030038,
+	0x8c434448, 0xad03003c, 0x03e00008, 0x01001021, 0x27bdffa8, 0x3c020008,
+	0x03423021, 0xafbf0054, 0xafbe0050, 0xafb7004c, 0xafb60048, 0xafb50044,
+	0xafb40040, 0xafb3003c, 0xafb20038, 0xafb10034, 0xafb00030, 0xaf860000,
+	0x24020040, 0xaf420814, 0xaf400810, 0x8f420944, 0x8f430950, 0x8f440954,
+	0x8f45095c, 0xaf820034, 0xaf830020, 0xaf84001c, 0xaf850030, 0x90c20000,
+	0x24030020, 0x304400ff, 0x10830005, 0x24020030, 0x10820022, 0x3c030800,
+	0x0a001139, 0x8c62002c, 0x24020088, 0xaf420818, 0x3c020800, 0x244258e8,
+	0xafa20020, 0x93430109, 0x3c020800, 0x10600009, 0x24575900, 0x3c026000,
+	0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000,
+	0x24000376, 0x9342010a, 0x30420080, 0x14400021, 0x24020800, 0x3c026000,
+	0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000,
+	0x2400037d, 0x0a001141, 0x24020800, 0x93430109, 0x3063007f, 0x00031140,
+	0x000318c0, 0x00431021, 0x24430088, 0xaf430818, 0x0000000d, 0x3c020800,
+	0x24425940, 0x3c030800, 0x24775950, 0x0a001140, 0xafa20020, 0x24420001,
+	0xac62002c, 0x0000000d, 0x00000000, 0x24000395, 0x0a0014c1, 0x8fbf0054,
+	0x24020800, 0xaf420178, 0x8f450104, 0x8f420988, 0x00a21023, 0x58400005,
+	0x8f4309a0, 0x0000000d, 0x00000000, 0x240003b1, 0x8f4309a0, 0x3c100800,
+	0xae0358b0, 0x8f4209a4, 0x8f830020, 0x260458b0, 0x2491ffd0, 0xae220034,
+	0x00a21023, 0xae230028, 0xac82ffd0, 0x8fa30020, 0x8c620000, 0x0040f809,
+	0x0200b021, 0x00409021, 0x32440010, 0x32420002, 0x10400007, 0xafa40024,
+	0x8e220020, 0x32530040, 0x2403ffbf, 0x00431024, 0x0a001493, 0xae220020,
+	0x32420020, 0x10400002, 0x3c020800, 0x24575920, 0x32420001, 0x14400007,
+	0x00000000, 0x8f820008, 0xaf420080, 0x8ec358b0, 0xaf430e10, 0x8e220034,
+	0xaf420e18, 0x9343010b, 0x93420905, 0x30420008, 0x1040003c, 0x307400ff,
+	0x8f820000, 0x8c430074, 0x0460000a, 0x00000000, 0x3c026000, 0x24030100,
+	0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x240003ed,
+	0x8f820000, 0x9044007b, 0x9343010a, 0x14830027, 0x32530040, 0x00003821,
+	0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd,
+	0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100,
+	0xaf420148, 0x24020047, 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000,
+	0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001, 0xad230030,
+	0x9342010a, 0x3c030047, 0xafa50014, 0x00021600, 0x00431025, 0x00471025,
+	0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b,
+	0x3c070100, 0x3c050800, 0x24a25880, 0x0a001250, 0x8c430020, 0x32820002,
+	0x10400050, 0x00000000, 0x0e0015b9, 0x32530040, 0x3c039000, 0x34630001,
+	0x8f820008, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024,
+	0x1440fffd, 0x00000000, 0x8f830000, 0x90620005, 0x34420008, 0xa0620005,
+	0x8f840000, 0x8c820074, 0x3c038000, 0x00431025, 0xac820074, 0x90830000,
+	0x24020020, 0x10620004, 0x00000000, 0x0000000d, 0x00000000, 0x2400040b,
+	0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x9084007b,
+	0x9342010a, 0x14820028, 0x3c030800, 0x00003821, 0x24052000, 0x3c090800,
+	0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0,
+	0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100, 0xaf420148, 0x24020046,
+	0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154,
+	0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030046,
+	0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b,
+	0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070100, 0x3c030800,
+	0x24625880, 0x0a001250, 0x8c430020, 0x93420108, 0x30420010, 0x50400056,
+	0x9343093f, 0x8f860000, 0x90c2007f, 0x8cc30178, 0x304800ff, 0x15030004,
+	0x00000000, 0x0000000d, 0x00000000, 0x24000425, 0x90c2007e, 0x90c40080,
+	0x00081c00, 0x00021600, 0x00431025, 0x00042200, 0x90c3007a, 0x90c5000a,
+	0x00441025, 0x11050028, 0x00623825, 0xa0c8000a, 0x00004021, 0x24056000,
+	0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0,
+	0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0xaf420148, 0x24020052,
+	0xaf47014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7480158, 0xaf450154,
+	0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030052,
+	0xafa50014, 0x00021600, 0x00431025, 0x00481025, 0xafa20010, 0x9343010b,
+	0xafa30018, 0x8f440100, 0x0e00159b, 0x8f450104, 0x0a00124a, 0x00000000,
+	0x3c026000, 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d,
+	0x00000000, 0x2400043e, 0x16800009, 0x3c050800, 0x3c040800, 0x24825880,
+	0x8c430020, 0x32530040, 0x2404ffbf, 0x00641824, 0x0a001493, 0xac430020,
+	0x8ca25880, 0x10400005, 0x3c030800, 0x8c620034, 0xaca05880, 0x24420001,
+	0xac620034, 0x9343093f, 0x24020012, 0x5462000e, 0x97420908, 0x32820038,
+	0x14400009, 0x3c030800, 0x8f830000, 0x8c62004c, 0xac62005c, 0x3c020800,
+	0x24445880, 0x8c820020, 0x0a001285, 0x32530040, 0xac605880, 0x97420908,
+	0x5440001c, 0x97420908, 0x3c039000, 0x34630001, 0x8f820008, 0x32530040,
+	0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd,
+	0x3c028000, 0x8f840000, 0x8f850008, 0x8c830050, 0x34420001, 0x00a22825,
+	0xaf830020, 0xac830070, 0xac83005c, 0xaf450020, 0x3c050800, 0x24a45880,
+	0x8c820020, 0x2403ffbf, 0x00431024, 0x0a001493, 0xac820020, 0x000211c0,
+	0xaf420024, 0x97420908, 0x3c030080, 0x34630003, 0x000211c0, 0xaf42080c,
+	0xaf43081c, 0x974209ec, 0x8f4309a4, 0xa782002c, 0x3c020800, 0x24445880,
+	0xac83002c, 0x93420937, 0x93430934, 0x00021080, 0x00621821, 0xa4830018,
+	0x934209d8, 0x32850038, 0xafa50028, 0x00621821, 0xa483001a, 0x934209d8,
+	0x93430934, 0x3c1e0800, 0x00809821, 0x00431021, 0x24420010, 0xa4820016,
+	0x24020006, 0xae620020, 0x8fa20028, 0x10400003, 0x0000a821, 0x0a0012f0,
+	0x24120008, 0x8f420958, 0x8f830020, 0x8f840030, 0x00431023, 0x00832023,
+	0x04800003, 0xae620004, 0x04410003, 0x0082102b, 0x0a0012bc, 0xae600004,
+	0x54400001, 0xae640004, 0x8ee20000, 0x0040f809, 0x00000000, 0x00409021,
+	0x32420001, 0x5440001e, 0x8ee20004, 0x8e630008, 0x1060002b, 0x3c02c000,
+	0x00621025, 0xaf420e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000,
+	0x97420e08, 0xa7820010, 0x8f430e04, 0x8e620008, 0xaf830004, 0x8f840004,
+	0x0044102b, 0x1040000b, 0x24150001, 0x24020100, 0x3c016000, 0xac22081c,
+	0x3c020001, 0x3c016000, 0xac22081c, 0x0000000d, 0x00000000, 0x240004cd,
+	0x24150001, 0x8ee20004, 0x0040f809, 0x00000000, 0x02429025, 0x32420002,
+	0x5040001d, 0x8f470940, 0x12a00006, 0x8ec258b0, 0x8f830000, 0xac6200a8,
+	0x8f840000, 0x8e620034, 0xac8200ac, 0x32420004, 0x50400013, 0x8f470940,
+	0x3c020800, 0x3283007d, 0x10600110, 0x24575920, 0x32820001, 0x50400006,
+	0x36520002, 0x8f830034, 0x8f420940, 0x10620109, 0x00000000, 0x36520002,
+	0x24020008, 0xa6600010, 0xa6620012, 0xae600008, 0xa2600024, 0x8f470940,
+	0x3c030800, 0x24685880, 0x8d02002c, 0x8d050008, 0x95040010, 0x9506000a,
+	0x95030026, 0x00451021, 0x00862021, 0x00641821, 0xaf870034, 0xad02002c,
+	0x32820030, 0x10400008, 0xa5030014, 0x91020024, 0x32910040, 0x34420004,
+	0xa1020024, 0xaf400048, 0x0a001345, 0x3c040800, 0x93420923, 0x30420002,
+	0x10400029, 0x32910040, 0x8f830000, 0x8f840020, 0x8c620084, 0x00441023,
+	0x0442000a, 0x3c039000, 0x95020014, 0x8c630084, 0x00821021, 0x00621823,
+	0x1c600004, 0x3c039000, 0x91020024, 0x34420001, 0xa1020024, 0x34630001,
+	0x8f820008, 0x32910040, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020,
+	0x00441024, 0x1440fffd, 0x00000000, 0x8f840000, 0x9083003f, 0x2402000a,
+	0x10620005, 0x2402000c, 0x9083003f, 0x24020008, 0x14620002, 0x24020014,
+	0xa082003f, 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020,
+	0x3c040800, 0x24865880, 0x94c20010, 0x94c3001a, 0x8cc40008, 0x00432821,
+	0x14800006, 0xa4c5001c, 0x3c020800, 0x8c430048, 0x10600002, 0x24a20040,
+	0xa4c2001c, 0x27d05880, 0x9604001c, 0x96020012, 0x00822021, 0x24840002,
+	0x0e000faf, 0x3084ffff, 0x8f850018, 0x00a01821, 0xa2030025, 0x8ee60008,
+	0x00402021, 0x24a50001, 0xaf850018, 0x00c0f809, 0x00000000, 0x00402021,
+	0x0e001026, 0x02202821, 0x8ee3000c, 0x0060f809, 0x00402021, 0x9604001c,
+	0x96020012, 0x00822021, 0x24840002, 0x0e000fc5, 0x3084ffff, 0x8fc25880,
+	0x8e030008, 0x00431023, 0x14400012, 0xafc25880, 0x54600006, 0x8e020020,
+	0x3243004a, 0x24020002, 0x14620005, 0x00000000, 0x8e020020, 0x34420040,
+	0x0a001382, 0xae020020, 0x52a00006, 0x36520002, 0x8e020030, 0xaf420e10,
+	0x8e030034, 0xaf430e18, 0x36520002, 0x52a00008, 0x96670014, 0x8f830000,
+	0x8f420e10, 0xac6200a8, 0x8f840000, 0x8f420e18, 0xac8200ac, 0x96670014,
+	0x92680024, 0x24020040, 0xaf420814, 0x8f830020, 0x8f82001c, 0x00671821,
+	0x00621023, 0xaf830020, 0x18400008, 0x00000000, 0x8f820000, 0xaf83001c,
+	0xac430054, 0x54e00005, 0xaf400040, 0x0a0013a0, 0x8f42095c, 0x54e00001,
+	0xaf400044, 0x8f42095c, 0x31030008, 0xaf820030, 0x1060001a, 0x00000000,
+	0x8f840000, 0x90820120, 0x90830121, 0x304600ff, 0x00c31823, 0x30630007,
+	0x24020007, 0x1062000e, 0x00000000, 0x90820122, 0x304200fe, 0xa0820122,
+	0x8f850000, 0x00061880, 0x8f840020, 0x24a20100, 0x00431021, 0x24c30001,
+	0x30630007, 0xac440000, 0x0a0013bd, 0xa0a30120, 0x90820122, 0x34420001,
+	0xa0820122, 0x14e00003, 0x31020001, 0x10400031, 0x32510002, 0x8f820000,
+	0x8c43000c, 0x30630001, 0x1060002c, 0x32510002, 0x3c029000, 0x8f830008,
+	0x34420001, 0x3c048000, 0x00621825, 0xaf430020, 0x8f420020, 0x00441024,
+	0x1440fffd, 0x00000000, 0x8f870000, 0x8ce2000c, 0x30420001, 0x10400018,
+	0x00000000, 0x94e2006a, 0x00022880, 0x50a00001, 0x24050001, 0x94e30068,
+	0x90e40081, 0x3c020800, 0x8c460024, 0x00652821, 0x00852804, 0x00c5102b,
+	0x54400001, 0x00a03021, 0x3c020800, 0x8c440028, 0x00c4182b, 0x54600001,
+	0x00c02021, 0x8f430074, 0x2402fffe, 0x00822824, 0x00a31821, 0xace3000c,
+	0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x8f820020,
+	0x3c050800, 0x24b05880, 0xae020028, 0x8ee30010, 0x0060f809, 0x00000000,
+	0x8f820028, 0x24420001, 0xaf820028, 0x12a00005, 0xaf40004c, 0x8f420e10,
+	0xae020030, 0x8f430e18, 0xae030034, 0x1220fea7, 0x24020006, 0x8f870024,
+	0x9786002c, 0x8f830000, 0x8f820034, 0x8f840020, 0x8f85001c, 0x32530040,
+	0xa4e6002c, 0xac620044, 0x32420008, 0xac640050, 0xac650054, 0x1040007a,
+	0x32820020, 0x10400027, 0x32910010, 0x00003821, 0x24052000, 0x3c090800,
+	0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0,
+	0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030400, 0xaf420148, 0x24020041,
+	0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154,
+	0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030041,
+	0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b,
+	0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070400, 0x12200028,
+	0x00003821, 0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024,
+	0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034,
+	0x3c030300, 0xaf420148, 0x2402004e, 0xaf43014c, 0xa3420152, 0x8d230030,
+	0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001,
+	0xad230030, 0x9342010a, 0x3c03004e, 0xafa50014, 0x00021600, 0x00431025,
+	0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104,
+	0x0e00159b, 0x3c070300, 0x0a00148b, 0x8fa20024, 0x32820008, 0x10400026,
+	0x24052000, 0x00003821, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024,
+	0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034,
+	0x3c030200, 0xaf420148, 0x2402004b, 0xaf43014c, 0xa3420152, 0x8d230030,
+	0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001,
+	0xad230030, 0x9342010a, 0x3c03004b, 0xafa50014, 0x00021600, 0x00431025,
+	0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104,
+	0x0e00159b, 0x3c070200, 0x8fa20024, 0x14400004, 0x8fa30020, 0x32420010,
+	0x10400004, 0x00000000, 0x8c620004, 0x0040f809, 0x00000000, 0x12600006,
+	0x8fa40020, 0x8c820008, 0x0040f809, 0x00000000, 0x0a0014c1, 0x8fbf0054,
+	0x3c030800, 0x8c6258a0, 0x30420040, 0x14400023, 0x8fbf0054, 0x00002821,
+	0x24040040, 0x8f870020, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd,
+	0x8ec258b0, 0x26c358b0, 0x2463ffd0, 0xaf420144, 0x8c620034, 0xaf420148,
+	0x24020049, 0xaf47014c, 0xa3420152, 0x3c021000, 0xa7450158, 0xaf440154,
+	0xaf420178, 0x8c660034, 0x9342010a, 0x3c030049, 0xafa40014, 0x00021600,
+	0x00431025, 0x00451025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100,
+	0x0e00159b, 0x8f450104, 0x8fbf0054, 0x8fbe0050, 0x8fb7004c, 0x8fb60048,
+	0x8fb50044, 0x8fb40040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+	0x03e00008, 0x27bd0058, 0x03e00008, 0x00001021, 0x3c020800, 0x24435880,
+	0x8c650004, 0x8c445880, 0x0085182b, 0x10600002, 0x00403021, 0x00802821,
+	0x9744093c, 0x00a4102b, 0x54400001, 0x00a02021, 0x93420923, 0x0004182b,
+	0x00021042, 0x30420001, 0x00431024, 0x1040000d, 0x24c25880, 0x8f850000,
+	0x8f830020, 0x8ca20084, 0x00431023, 0x04420007, 0x24c25880, 0x8ca20084,
+	0x00641821, 0x00431023, 0x28420001, 0x00822023, 0x24c25880, 0xac440008,
+	0xa4400026, 0x03e00008, 0x00001021, 0x8f850004, 0x97840010, 0x3c030800,
+	0x24635880, 0x24020008, 0xa4620012, 0x8f820004, 0xa4600010, 0x000420c2,
+	0x30840008, 0x2c420001, 0x00021023, 0x30420006, 0xac650008, 0x03e00008,
+	0xa0640024, 0x3c020800, 0x24425880, 0x90450025, 0x9443001c, 0x3c021100,
+	0xac800004, 0x00052c00, 0x24630002, 0x00621825, 0x00a32825, 0x24820008,
+	0x03e00008, 0xac850000, 0x27bdffd8, 0x3c020800, 0x24425880, 0xafbf0020,
+	0x90480025, 0x8c440008, 0x8c460020, 0x8f870020, 0x3c030800, 0x3c058000,
+	0x8f420178, 0x00451024, 0x1440fffd, 0x8c6258b0, 0x246358b0, 0x2469ffd0,
+	0xaf420144, 0x8d220034, 0x30c32000, 0xaf420148, 0x3c021000, 0xaf47014c,
+	0xa3480152, 0xa7440158, 0xaf460154, 0xaf420178, 0x10600004, 0x3c030800,
+	0x8c620030, 0x24420001, 0xac620030, 0x9342010a, 0x00081c00, 0x3084ffff,
+	0xafa60014, 0x00021600, 0x00431025, 0x00441025, 0xafa20010, 0x9343010b,
+	0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x8d260034, 0x8fbf0020,
+	0x03e00008, 0x27bd0028, 0x0000000d, 0x00000000, 0x2400019d, 0x03e00008,
+	0x00000000, 0x0000000d, 0x00000000, 0x240001a9, 0x03e00008, 0x00000000,
+	0x03e00008, 0x00000000, 0x3c020800, 0x24425880, 0xac400008, 0xa4400026,
+	0x03e00008, 0x24020001, 0x3c020800, 0x24425880, 0x24030008, 0xac400008,
+	0xa4400010, 0xa4430012, 0xa0400024, 0x03e00008, 0x24020004, 0x03e00008,
+	0x00001021, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004,
+	0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a00156c,
+	0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004, 0x00a01021,
+	0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c0a0800, 0x8d490068,
+	0x3c050800, 0x24a52098, 0x00093140, 0x00c51021, 0xac440000, 0x8f440e04,
+	0x00a61021, 0xac440004, 0x97430e08, 0x97420e0c, 0x00a62021, 0x00031c00,
+	0x00431025, 0xac820008, 0x8f430e10, 0x00801021, 0xac43000c, 0x8f440e14,
+	0xac440010, 0x8f430e18, 0x3c0800ff, 0xac430014, 0x8f470e1c, 0x3508ffff,
+	0x25290001, 0xac470018, 0x3c070800, 0x8ce3006c, 0x9344010a, 0x3c026000,
+	0x24630001, 0xace3006c, 0x8c434448, 0x3129007f, 0x00a62821, 0xad490068,
+	0x00042600, 0x00681824, 0x00832025, 0x03e00008, 0xaca4001c, 0x8fac0010,
+	0x8fad0014, 0x8fae0018, 0x3c0b0800, 0x8d6a0060, 0x3c080800, 0x25080080,
+	0x000a4940, 0x01281021, 0x01091821, 0xac440000, 0x00601021, 0xac650004,
+	0xac460008, 0xac67000c, 0xac4c0010, 0xac6d0014, 0x3c036000, 0xac4e0018,
+	0x8c654448, 0x3c040800, 0x8c820064, 0x254a0001, 0x314a00ff, 0x01094021,
+	0xad6a0060, 0x24420001, 0xac820064, 0x03e00008, 0xad05001c, 0x3c030800,
+	0x3c090800, 0x8d250070, 0x246330b0, 0x8f460100, 0x00053900, 0x00e31021,
+	0xac460000, 0x8f440104, 0x00671021, 0xac440004, 0x8f460108, 0x8f840014,
+	0x24a50001, 0xac460008, 0x8c880074, 0x3c060800, 0x8cc20074, 0x30a5003f,
+	0x00671821, 0xad250070, 0x24420001, 0xacc20074, 0x03e00008, 0xac68000c,
+	0x00000000 };
+
+static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
+static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 };
+static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 };
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.c
new file mode 100644
index 0000000..ee34d0c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.c
@@ -0,0 +1,739 @@
+#ifdef ALLMULTI
+#error multicast support is not yet implemented
+#endif
+
+/**
+   Per an email message from Russ Nelson <nelson at crynwr.com> on
+   18 March 2008 this file is now licensed under GPL Version 2.
+
+   From: Russ Nelson <nelson at crynwr.com>
+   Date: Tue, 18 Mar 2008 12:42:00 -0400
+   Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
+   -- quote from email 
+   As copyright holder, if I say it doesn't conflict with the GPL,
+   then it doesn't conflict with the GPL.
+
+   However, there's no point in causing people's brains to overheat,
+   so yes, I grant permission for the code to be relicensed under the
+   GPLv2.  Please make sure that this change in licensing makes its
+   way upstream.  -russ 
+   -- quote from email
+**/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
+/*
+  Permission is granted to distribute the enclosed cs89x0.[ch] driver
+  only in conjunction with the Etherboot package.  The code is
+  ordinarily distributed under the GPL.
+  
+  Russ Nelson, January 2000
+
+  ChangeLog:
+
+  Thu Dec 6 22:40:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * disabled all "advanced" features; this should make the code more reliable
+
+  * reorganized the reset function
+
+  * always reset the address port, so that autoprobing will continue working
+
+  * some cosmetic changes
+
+  * 2.5
+
+  Thu Dec 5 21:00:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * tested the code against a CS8900 card
+
+  * lots of minor bug fixes and adjustments
+
+  * this is the first release, that actually works! it still requires some
+    changes in order to be more tolerant to different environments
+
+  * 4
+
+  Fri Nov 22 23:00:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * read the manuals for the CS89x0 chipsets and took note of all the
+    changes that will be neccessary in order to adapt Russel Nelson's code
+    to the requirements of a BOOT-Prom
+
+  * 6
+
+  Thu Nov 19 22:00:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * Synched with Russel Nelson's current code (v1.00)
+
+  * 2
+
+  Thu Nov 12 18:00:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * Cleaned up some of the code and tried to optimize the code size.
+
+  * 1.5
+
+  Sun Nov 10 16:30:00 1996  Markus Gutschke  <gutschk at math.uni-muenster.de>
+
+  * First experimental release. This code compiles fine, but I
+  have no way of testing whether it actually works.
+
+  * I did not (yet) bother to make the code 16bit aware, so for
+  the time being, it will only work for Etherboot/32.
+
+  * 12
+
+  */
+
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/isa.h>
+#include <ipxe/console.h>
+#include "cs89x0.h"
+
+static unsigned short	eth_nic_base;
+static unsigned long    eth_mem_start;
+static unsigned short   eth_irqno;
+static unsigned short   eth_cs_type;	/* one of: CS8900, CS8920, CS8920M  */
+static unsigned short   eth_auto_neg_cnf;
+static unsigned short   eth_adapter_cnf;
+static unsigned short	eth_linectl;
+
+/*************************************************************************
+	CS89x0 - specific routines
+**************************************************************************/
+
+static inline int readreg(int portno)
+{
+	outw(portno, eth_nic_base + ADD_PORT);
+	return inw(eth_nic_base + DATA_PORT);
+}
+
+static inline void writereg(int portno, int value)
+{
+	outw(portno, eth_nic_base + ADD_PORT);
+	outw(value, eth_nic_base + DATA_PORT);
+	return;
+}
+
+/*************************************************************************
+EEPROM access
+**************************************************************************/
+
+static int wait_eeprom_ready(void)
+{
+	unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
+
+	/* check to see if the EEPROM is ready, a timeout is used -
+	   just in case EEPROM is ready when SI_BUSY in the
+	   PP_SelfST is clear */
+	while(readreg(PP_SelfST) & SI_BUSY) {
+		if (currticks() >= tmo)
+			return -1; }
+	return 0;
+}
+
+static int get_eeprom_data(int off, int len, unsigned short *buffer)
+{
+	int i;
+
+#ifdef	EDEBUG
+	printf("\ncs: EEPROM data from %hX for %hX:",off,len);
+#endif
+	for (i = 0; i < len; i++) {
+		if (wait_eeprom_ready() < 0)
+			return -1;
+		/* Now send the EEPROM read command and EEPROM location
+		   to read */
+		writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
+		if (wait_eeprom_ready() < 0)
+			return -1;
+		buffer[i] = readreg(PP_EEData);
+#ifdef	EDEBUG
+		if (!(i%10))
+			printf("\ncs: ");
+		printf("%hX ", buffer[i]);
+#endif
+	}
+#ifdef	EDEBUG
+	putchar('\n');
+#endif
+
+	return(0);
+}
+
+static int get_eeprom_chksum(int off __unused, int len, unsigned short *buffer)
+{
+	int  i, cksum;
+
+	cksum = 0;
+	for (i = 0; i < len; i++)
+		cksum += buffer[i];
+	cksum &= 0xffff;
+	if (cksum == 0)
+		return 0;
+	return -1;
+}
+
+/*************************************************************************
+Activate all of the available media and probe for network
+**************************************************************************/
+
+static void clrline(void)
+{
+	int i;
+
+	putchar('\r');
+	for (i = 79; i--; ) putchar(' ');
+	printf("\rcs: ");
+	return;
+}
+
+static void control_dc_dc(int on_not_off)
+{
+	unsigned int selfcontrol;
+	unsigned long tmo = currticks() + TICKS_PER_SEC;
+
+	/* control the DC to DC convertor in the SelfControl register.  */
+	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
+	if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
+		selfcontrol |= HCB1;
+	else
+		selfcontrol &= ~HCB1;
+	writereg(PP_SelfCTL, selfcontrol);
+
+	/* Wait for the DC/DC converter to power up - 1000ms */
+	while (currticks() < tmo);
+
+	return;
+}
+
+static int detect_tp(void)
+{
+	unsigned long tmo;
+
+	/* Turn on the chip auto detection of 10BT/ AUI */
+
+	clrline(); printf("attempting %s:","TP");
+
+        /* If connected to another full duplex capable 10-Base-T card
+	   the link pulses seem to be lost when the auto detect bit in
+	   the LineCTL is set.  To overcome this the auto detect bit
+	   will be cleared whilst testing the 10-Base-T interface.
+	   This would not be necessary for the sparrow chip but is
+	   simpler to do it anyway. */
+	writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
+	control_dc_dc(0);
+
+        /* Delay for the hardware to work out if the TP cable is
+	   present - 150ms */
+	for (tmo = currticks() + 4; currticks() < tmo; );
+
+	if ((readreg(PP_LineST) & LINK_OK) == 0)
+		return 0;
+
+	if (eth_cs_type != CS8900) {
+
+		writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
+
+		if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
+			printf(" negotiating duplex... ");
+			while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
+				if (currticks() - tmo > 40*TICKS_PER_SEC) {
+					printf("time out ");
+					break;
+				}
+			}
+		}
+		if (readreg(PP_AutoNegST) & FDX_ACTIVE)
+			printf("using full duplex");
+		else
+			printf("using half duplex");
+	}
+
+	return A_CNF_MEDIA_10B_T;
+}
+
+/* send a test packet - return true if carrier bits are ok */
+static int send_test_pkt(struct nic *nic)
+{
+	static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
+				     0, 46, /*A 46 in network order       */
+				     0, 0,  /*DSAP=0 & SSAP=0 fields      */
+				     0xf3,0 /*Control (Test Req+P bit set)*/ };
+	unsigned long tmo;
+
+	writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
+
+	memcpy(testpacket, nic->node_addr, ETH_ALEN);
+	memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
+
+	outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
+	outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
+
+	/* Test to see if the chip has allocated memory for the packet */
+	for (tmo = currticks() + 2;
+	     (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
+		if (currticks() >= tmo)
+			return(0);
+
+	/* Write the contents of the packet */
+	outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
+	      (ETH_ZLEN+1)>>1);
+
+	printf(" sending test packet ");
+	/* wait a couple of timer ticks for packet to be received */
+	for (tmo = currticks() + 2; currticks() < tmo; );
+
+	if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
+			printf("succeeded");
+			return 1;
+	}
+	printf("failed");
+	return 0;
+}
+
+
+static int detect_aui(struct nic *nic)
+{
+	clrline(); printf("attempting %s:","AUI");
+	control_dc_dc(0);
+
+	writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
+
+	if (send_test_pkt(nic)) {
+		return A_CNF_MEDIA_AUI; }
+	else
+		return 0;
+}
+
+static int detect_bnc(struct nic *nic)
+{
+	clrline(); printf("attempting %s:","BNC");
+	control_dc_dc(1);
+
+	writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
+
+	if (send_test_pkt(nic)) {
+		return A_CNF_MEDIA_10B_2; }
+	else
+		return 0;
+}
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+***************************************************************************/
+
+static void cs89x0_reset(struct nic *nic)
+{
+	int  i;
+	unsigned long reset_tmo;
+
+	writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
+
+	/* wait for two ticks; that is 2*55ms */
+	for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
+
+	if (eth_cs_type != CS8900) {
+		/* Hardware problem requires PNP registers to be reconfigured
+		   after a reset */
+		if (eth_irqno != 0xFFFF) {
+			outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
+			outb(eth_irqno, eth_nic_base + DATA_PORT);
+			outb(0, eth_nic_base + DATA_PORT + 1); }
+
+		if (eth_mem_start) {
+			outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
+			outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
+			outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
+
+	/* Wait until the chip is reset */
+	for (reset_tmo = currticks() + 2;
+	     (readreg(PP_SelfST) & INIT_DONE) == 0 &&
+		     currticks() < reset_tmo; );
+
+	/* disable interrupts and memory accesses */
+	writereg(PP_BusCTL, 0);
+
+	/* set the ethernet address */
+	for (i=0; i < ETH_ALEN/2; i++)
+		writereg(PP_IA+i*2,
+			 nic->node_addr[i*2] |
+			 (nic->node_addr[i*2+1] << 8));
+
+	/* receive only error free packets addressed to this card */
+	writereg(PP_RxCTL, DEF_RX_ACCEPT);
+
+	/* do not generate any interrupts on receive operations */
+	writereg(PP_RxCFG, 0);
+
+	/* do not generate any interrupts on transmit operations */
+	writereg(PP_TxCFG, 0);
+
+	/* do not generate any interrupts on buffer operations */
+	writereg(PP_BufCFG, 0);
+
+	/* reset address port, so that autoprobing will keep working */
+	outw(PP_ChipID, eth_nic_base + ADD_PORT);
+
+	return;
+}
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+***************************************************************************/
+
+static void cs89x0_transmit(
+	struct nic *nic,
+	const char *d,			/* Destination */
+	unsigned int t,			/* Type */
+	unsigned int s,			/* size */
+	const char *p)			/* Packet */
+{
+	unsigned long tmo;
+	int           sr;
+
+	/* does this size have to be rounded??? please,
+	   somebody have a look in the specs */
+	if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
+		sr = ETH_ZLEN;
+
+retry:
+	/* initiate a transmit sequence */
+	outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
+	outw(sr, eth_nic_base + TX_LEN_PORT);
+
+	/* Test to see if the chip has allocated memory for the packet */
+	if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
+		/* Oops... this should not happen! */
+		printf("cs: unable to send packet; retrying...\n");
+		for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
+		cs89x0_reset(nic);
+		goto retry; }
+
+	/* Write the contents of the packet */
+	outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
+	outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
+	      ETH_ALEN/2);
+	outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
+	outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
+	for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
+		outw(0, eth_nic_base + TX_FRAME_PORT);
+
+	/* wait for transfer to succeed */
+	for (tmo = currticks()+5*TICKS_PER_SEC;
+	     (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
+		/* nothing */ ;
+	if ((s & TX_SEND_OK_BITS) != TX_OK) {
+		printf("\ntransmission error %#hX\n", s);
+	}
+
+	return;
+}
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+***************************************************************************/
+
+static int cs89x0_poll(struct nic *nic, int retrieve)
+{
+	int status;
+
+	status = readreg(PP_RxEvent);
+
+	if ((status & RX_OK) == 0)
+		return(0);
+
+	if ( ! retrieve ) return 1;
+
+	status = inw(eth_nic_base + RX_FRAME_PORT);
+	nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
+	insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
+	if (nic->packetlen & 1)
+		nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
+	return 1;
+}
+
+static void cs89x0_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations cs89x0_operations = {
+	.connect	= dummy_connect,
+	.poll		= cs89x0_poll,
+	.transmit	= cs89x0_transmit,
+	.irq		= cs89x0_irq,
+};
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+***************************************************************************/
+
+static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr ) {
+	/* if they give us an odd I/O address, then do ONE write to
+	   the address port, to get it back to address zero, where we
+	   expect to find the EISA signature word. */
+	if (ioaddr & 1) {
+		ioaddr &= ~1;
+		if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
+			return 0;
+		outw(PP_ChipID, ioaddr + ADD_PORT);
+	}
+	
+	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
+		return 0;
+
+	return 1;
+}
+
+static int cs89x0_probe ( struct nic *nic, struct isa_device *isa __unused ) {
+	int      i, result = -1;
+	unsigned rev_type = 0, isa_cnf, cs_revision;
+	unsigned short eeprom_buff[CHKSUM_LEN];
+
+	nic->ioaddr &= ~1; /* LSB = 1 indicates a more aggressive probe */
+	eth_nic_base = nic->ioaddr;
+
+	/* get the chip type */
+	rev_type = readreg(PRODUCT_ID_ADD);
+	eth_cs_type = rev_type &~ REVISON_BITS;
+	cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+	
+	printf("\ncs: cs89%c0%s rev %c, base %#hX",
+	       eth_cs_type==CS8900?'0':'2',
+	       eth_cs_type==CS8920M?"M":"",
+	       cs_revision,
+	       eth_nic_base);
+#ifndef EMBEDDED 
+	/* First check to see if an EEPROM is attached*/
+	if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
+		printf("\ncs: no EEPROM...\n");
+		outw(PP_ChipID, eth_nic_base + ADD_PORT);
+		return 0;
+	} else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
+				   eeprom_buff) < 0) {
+		printf("\ncs: EEPROM read failed...\n");
+		outw(PP_ChipID, eth_nic_base + ADD_PORT);
+		return 0;
+	} else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
+				     eeprom_buff) < 0) {
+		printf("\ncs: EEPROM checksum bad...\n");
+		outw(PP_ChipID, eth_nic_base + ADD_PORT);
+		return 0;
+	}
+
+	/* get transmission control word but keep the
+	   autonegotiation bits */
+	eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
+	/* Store adapter configuration */
+	eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
+	/* Store ISA configuration */
+	isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
+	
+	/* store the initial memory base address */
+	eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
+	
+	printf("%s%s%s, addr ",
+	       (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
+	       (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
+	       (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
+	
+	/* If this is a CS8900 then no pnp soft */
+	if (eth_cs_type != CS8900 &&
+	    /* Check if the ISA IRQ has been set  */
+	    (i = readreg(PP_CS8920_ISAINT) & 0xff,
+	     (i != 0 && i < CS8920_NO_INTS)))
+		eth_irqno = i;
+	else {
+		i = isa_cnf & INT_NO_MASK;
+		if (eth_cs_type == CS8900) {
+			/* the table that follows is dependent
+			   upon how you wired up your cs8900
+			   in your system.  The table is the
+			   same as the cs8900 engineering demo
+			   board.  irq_map also depends on the
+			   contents of the table.  Also see
+			   write_irq, which is the reverse
+			   mapping of the table below. */
+			if (i < 4) i = "\012\013\014\005"[i];
+			else printf("\ncs: BUG: isa_config is %d\n", i); }
+		eth_irqno = i; }
+	
+        nic->irqno = eth_irqno;
+
+	/* Retrieve and print the ethernet address. */
+	for (i=0; i<ETH_ALEN; i++) {
+		nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
+	}
+
+	DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
+
+#endif
+#ifdef EMBEDDED
+	/* Retrieve and print the ethernet address. */
+	{
+		unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
+		memcpy(nic->node_addr, MAC_HW_ADDR, 6);
+	}
+
+	DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
+	
+	eth_adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T;
+	eth_auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT;
+#endif
+#ifndef EMBEDDED 
+	/* Set the LineCTL quintuplet based on adapter
+	   configuration read from EEPROM */
+	if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
+	    (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
+		eth_linectl = LOW_RX_SQUELCH;
+	else
+		eth_linectl = 0;
+	
+	/* check to make sure that they have the "right"
+	   hardware available */
+	switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
+	case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
+		break;
+	case A_CNF_MEDIA_AUI:   result = eth_adapter_cnf & A_CNF_AUI;
+		break;
+	case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
+		break;
+	default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
+					     A_CNF_10B_2);
+	}
+	if (!result) {
+		printf("cs: EEPROM is configured for unavailable media\n");
+	error:
+		writereg(PP_LineCTL, readreg(PP_LineCTL) &
+			 ~(SERIAL_TX_ON | SERIAL_RX_ON));
+		outw(PP_ChipID, eth_nic_base + ADD_PORT);
+		return 0;
+	}
+#endif
+	/* Initialize the card for probing of the attached media */
+	cs89x0_reset(nic);
+	
+	/* set the hardware to the configured choice */
+	switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
+	case A_CNF_MEDIA_10B_T:
+		result = detect_tp();
+		if (!result) {
+			clrline();
+			printf("10Base-T (RJ-45%s",
+			       ") has no cable\n"); }
+		/* check "ignore missing media" bit */
+		if (eth_auto_neg_cnf & IMM_BIT)
+			/* Yes! I don't care if I see a link pulse */
+			result = A_CNF_MEDIA_10B_T;
+		break;
+	case A_CNF_MEDIA_AUI:
+		result = detect_aui(nic);
+		if (!result) {
+			clrline();
+			printf("10Base-5 (AUI%s",
+			       ") has no cable\n"); }
+		/* check "ignore missing media" bit */
+		if (eth_auto_neg_cnf & IMM_BIT)
+			/* Yes! I don't care if I see a carrrier */
+			result = A_CNF_MEDIA_AUI;
+		break;
+	case A_CNF_MEDIA_10B_2:
+		result = detect_bnc(nic);
+		if (!result) {
+			clrline();
+			printf("10Base-2 (BNC%s",
+			       ") has no cable\n"); }
+		/* check "ignore missing media" bit */
+		if (eth_auto_neg_cnf & IMM_BIT)
+			/* Yes! I don't care if I can xmit a packet */
+			result = A_CNF_MEDIA_10B_2;
+		break;
+	case A_CNF_MEDIA_AUTO:
+		writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
+		if (eth_adapter_cnf & A_CNF_10B_T)
+			if ((result = detect_tp()) != 0)
+				break;
+		if (eth_adapter_cnf & A_CNF_AUI)
+			if ((result = detect_aui(nic)) != 0)
+				break;
+		if (eth_adapter_cnf & A_CNF_10B_2)
+			if ((result = detect_bnc(nic)) != 0)
+				break;
+		clrline(); printf("no media detected\n");
+		goto error;
+	}
+	clrline();
+	switch(result) {
+	case 0:                 printf("no network cable attached to configured media\n");
+		goto error;
+	case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
+		break;
+	case A_CNF_MEDIA_AUI:   printf("using 10Base-5 (AUI)\n");
+		break;
+	case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
+		break;
+	}
+	
+	/* Turn on both receive and transmit operations */
+	writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
+		 SERIAL_TX_ON);
+	
+	return 0;
+#ifdef EMBEDDED
+ error:
+	writereg(PP_LineCTL, readreg(PP_LineCTL) &
+		 ~(SERIAL_TX_ON | SERIAL_RX_ON));
+	outw(PP_ChipID, eth_nic_base + ADD_PORT);
+	return 0;
+#endif
+
+	nic->nic_op   = &cs89x0_operations;
+	return 1;
+}
+
+static void cs89x0_disable ( struct nic *nic,
+			     struct isa_device *isa __unused ) {
+	cs89x0_reset(nic);
+}
+	
+static isa_probe_addr_t cs89x0_probe_addrs[] = { 
+#ifndef EMBEDDED
+	/* use "conservative" default values for autoprobing */
+	0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
+	0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
+	/* if that did not work, then be more aggressive */
+	0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
+	0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
+#else
+	0x01000300,
+#endif
+};
+
+ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
+	     ISAPNP_VENDOR('C','S','C'), 0x0007 );
+
+DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
+	 cs89x0_probe, cs89x0_disable );
+
+ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.h
new file mode 100644
index 0000000..a36b907
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.h
@@ -0,0 +1,481 @@
+/**
+   Per an email message from Russ Nelson <nelson at crynwr.com> on
+   18 March 2008 this file is now licensed under GPL Version 2.
+
+   From: Russ Nelson <nelson at crynwr.com>
+   Date: Tue, 18 Mar 2008 12:42:00 -0400
+   Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
+   -- quote from email 
+   As copyright holder, if I say it doesn't conflict with the GPL,
+   then it doesn't conflict with the GPL.
+
+   However, there's no point in causing people's brains to overheat,
+   so yes, I grant permission for the code to be relicensed under the
+   GPLv2.  Please make sure that this change in licensing makes its
+   way upstream.  -russ 
+   -- quote from email
+**/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*  Copyright, 1988-1992, Russell Nelson, Crynwr Software
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, version 1.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
+				/* offset   2h -> Model/Product Number  */
+				/* offset   3h -> Chip Revision Number  */
+
+#define PP_ISAIOB 0x0020	/*  IO base address */
+#define PP_CS8900_ISAINT 0x0022	/*  ISA interrupt select */
+#define PP_CS8920_ISAINT 0x0370	/*  ISA interrupt select */
+#define PP_CS8900_ISADMA 0x0024	/*  ISA Rec DMA channel */
+#define PP_CS8920_ISADMA 0x0374	/*  ISA Rec DMA channel */
+#define PP_ISASOF 0x0026	/*  ISA DMA offset */
+#define PP_DmaFrameCnt 0x0028	/*  ISA DMA Frame count */
+#define PP_DmaByteCnt 0x002A	/*  ISA DMA Byte count */
+#define PP_CS8900_ISAMemB 0x002C	/*  Memory base */
+#define PP_CS8920_ISAMemB 0x0348 /*  */
+
+#define PP_ISABootBase 0x0030	/*  Boot Prom base  */
+#define PP_ISABootMask 0x0034	/*  Boot Prom Mask */
+
+/* EEPROM data and command registers */
+#define PP_EECMD 0x0040		/*  NVR Interface Command register */
+#define PP_EEData 0x0042	/*  NVR Interface Data Register */
+#define PP_DebugReg 0x0044	/*  Debug Register */
+
+#define PP_RxCFG 0x0102		/*  Rx Bus config */
+#define PP_RxCTL 0x0104		/*  Receive Control Register */
+#define PP_TxCFG 0x0106		/*  Transmit Config Register */
+#define PP_TxCMD 0x0108		/*  Transmit Command Register */
+#define PP_BufCFG 0x010A	/*  Bus configuration Register */
+#define PP_LineCTL 0x0112	/*  Line Config Register */
+#define PP_SelfCTL 0x0114	/*  Self Command Register */
+#define PP_BusCTL 0x0116	/*  ISA bus control Register */
+#define PP_TestCTL 0x0118	/*  Test Register */
+#define PP_AutoNegCTL 0x011C	/*  Auto Negotiation Ctrl */
+
+#define PP_ISQ 0x0120		/*  Interrupt Status */
+#define PP_RxEvent 0x0124	/*  Rx Event Register */
+#define PP_TxEvent 0x0128	/*  Tx Event Register */
+#define PP_BufEvent 0x012C	/*  Bus Event Register */
+#define PP_RxMiss 0x0130	/*  Receive Miss Count */
+#define PP_TxCol 0x0132		/*  Transmit Collision Count */
+#define PP_LineST 0x0134	/*  Line State Register */
+#define PP_SelfST 0x0136	/*  Self State register */
+#define PP_BusST 0x0138		/*  Bus Status */
+#define PP_TDR 0x013C		/*  Time Domain Reflectometry */
+#define PP_AutoNegST 0x013E	/*  Auto Neg Status */
+#define PP_TxCommand 0x0144	/*  Tx Command */
+#define PP_TxLength 0x0146	/*  Tx Length */
+#define PP_LAF 0x0150		/*  Hash Table */
+#define PP_IA 0x0158		/*  Physical Address Register */
+
+#define PP_RxStatus 0x0400	/*  Receive start of frame */
+#define PP_RxLength 0x0402	/*  Receive Length of frame */
+#define PP_RxFrame 0x0404	/*  Receive frame pointer */
+#define PP_TxFrame 0x0A00	/*  Transmit frame pointer */
+
+/*  Primary I/O Base Address. If no I/O base is supplied by the user, then this */
+/*  can be used as the default I/O base to access the PacketPage Area. */
+#define DEFAULTIOBASE 0x0300
+#define FIRST_IO 0x020C		/*  First I/O port to check */
+#define LAST_IO 0x037C		/*  Last I/O port to check (+10h) */
+#define ADD_MASK 0x3000		/*  Mask it use of the ADD_PORT register */
+#define ADD_SIG 0x3000		/*  Expected ID signature */
+
+#define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
+
+#ifdef	IBMEIPKT
+#define EISA_ID_SIG 0x4D24	/*  IBM */
+#define PART_NO_SIG 0x1010	/*  IBM */
+#define MONGOOSE_BIT 0x0000	/*  IBM */
+#else
+#define EISA_ID_SIG 0x630E	/*  PnP Vendor ID (same as chip id for Crystal board) */
+#define PART_NO_SIG 0x4000	/*  ID code CS8920 board (PnP Vendor Product code) */
+#define MONGOOSE_BIT 0x2000	/*  PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
+#endif
+
+#define PRODUCT_ID_ADD 0x0002   /*  Address of product ID */
+
+/*  Mask to find out the types of  registers */
+#define REG_TYPE_MASK 0x001F
+
+/*  Eeprom Commands */
+#define ERSE_WR_ENBL 0x00F0
+#define ERSE_WR_DISABLE 0x0000
+
+/*  Defines Control/Config register quintuplet numbers */
+#define RX_BUF_CFG 0x0003
+#define RX_CONTROL 0x0005
+#define TX_CFG 0x0007
+#define TX_COMMAND 0x0009
+#define BUF_CFG 0x000B
+#define LINE_CONTROL 0x0013
+#define SELF_CONTROL 0x0015
+#define BUS_CONTROL 0x0017
+#define TEST_CONTROL 0x0019
+
+/*  Defines Status/Count registers quintuplet numbers */
+#define RX_EVENT 0x0004
+#define TX_EVENT 0x0008
+#define BUF_EVENT 0x000C
+#define RX_MISS_COUNT 0x0010
+#define TX_COL_COUNT 0x0012
+#define LINE_STATUS 0x0014
+#define SELF_STATUS 0x0016
+#define BUS_STATUS 0x0018
+#define TDR 0x001C
+
+/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */
+#define SKIP_1 0x0040
+#define RX_STREAM_ENBL 0x0080
+#define RX_OK_ENBL 0x0100
+#define RX_DMA_ONLY 0x0200
+#define AUTO_RX_DMA 0x0400
+#define BUFFER_CRC 0x0800
+#define RX_CRC_ERROR_ENBL 0x1000
+#define RX_RUNT_ENBL 0x2000
+#define RX_EXTRA_DATA_ENBL 0x4000
+
+/* PP_RxCTL - Receive Control bit definition - Read/write */
+#define RX_IA_HASH_ACCEPT 0x0040
+#define RX_PROM_ACCEPT 0x0080
+#define RX_OK_ACCEPT 0x0100
+#define RX_MULTCAST_ACCEPT 0x0200
+#define RX_IA_ACCEPT 0x0400
+#define RX_BROADCAST_ACCEPT 0x0800
+#define RX_BAD_CRC_ACCEPT 0x1000
+#define RX_RUNT_ACCEPT 0x2000
+#define RX_EXTRA_DATA_ACCEPT 0x4000
+#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
+/*  Default receive mode - individually addressed, broadcast, and error free */
+#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
+
+/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
+#define TX_LOST_CRS_ENBL 0x0040
+#define TX_SQE_ERROR_ENBL 0x0080
+#define TX_OK_ENBL 0x0100
+#define TX_LATE_COL_ENBL 0x0200
+#define TX_JBR_ENBL 0x0400
+#define TX_ANY_COL_ENBL 0x0800
+#define TX_16_COL_ENBL 0x8000
+
+/* PP_TxCMD - Transmit Command bit definition - Read-only */
+#define TX_START_4_BYTES 0x0000
+#define TX_START_64_BYTES 0x0040
+#define TX_START_128_BYTES 0x0080
+#define TX_START_ALL_BYTES 0x00C0
+#define TX_FORCE 0x0100
+#define TX_ONE_COL 0x0200
+#define TX_TWO_PART_DEFF_DISABLE 0x0400
+#define TX_NO_CRC 0x1000
+#define TX_RUNT 0x2000
+
+/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
+#define GENERATE_SW_INTERRUPT 0x0040
+#define RX_DMA_ENBL 0x0080
+#define READY_FOR_TX_ENBL 0x0100
+#define TX_UNDERRUN_ENBL 0x0200
+#define RX_MISS_ENBL 0x0400
+#define RX_128_BYTE_ENBL 0x0800
+#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
+#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
+#define RX_DEST_MATCH_ENBL 0x8000
+
+/* PP_LineCTL - Line Control bit definition - Read/write */
+#define SERIAL_RX_ON 0x0040
+#define SERIAL_TX_ON 0x0080
+#define AUI_ONLY 0x0100
+#define AUTO_AUI_10BASET 0x0200
+#define MODIFIED_BACKOFF 0x0800
+#define NO_AUTO_POLARITY 0x1000
+#define TWO_PART_DEFDIS 0x2000
+#define LOW_RX_SQUELCH 0x4000
+
+/* PP_SelfCTL - Software Self Control bit definition - Read/write */
+#define POWER_ON_RESET 0x0040
+#define SW_STOP 0x0100
+#define SLEEP_ON 0x0200
+#define AUTO_WAKEUP 0x0400
+#define HCB0_ENBL 0x1000
+#define HCB1_ENBL 0x2000
+#define HCB0 0x4000
+#define HCB1 0x8000
+
+/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
+#define RESET_RX_DMA 0x0040
+#define MEMORY_ON 0x0400
+#define DMA_BURST_MODE 0x0800
+#define IO_CHANNEL_READY_ON 0x1000
+#define RX_DMA_SIZE_64K 0x2000
+#define ENABLE_IRQ 0x8000
+
+/* PP_TestCTL - Test Control bit definition - Read/write */
+#define LINK_OFF 0x0080
+#define ENDEC_LOOPBACK 0x0200
+#define AUI_LOOPBACK 0x0400
+#define BACKOFF_OFF 0x0800
+#define FAST_TEST 0x8000
+
+/* PP_RxEvent - Receive Event Bit definition - Read-only */
+#define RX_IA_HASHED 0x0040
+#define RX_DRIBBLE 0x0080
+#define RX_OK 0x0100
+#define RX_HASHED 0x0200
+#define RX_IA 0x0400
+#define RX_BROADCAST 0x0800
+#define RX_CRC_ERROR 0x1000
+#define RX_RUNT 0x2000
+#define RX_EXTRA_DATA 0x4000
+
+#define HASH_INDEX_MASK 0x0FC00
+
+/* PP_TxEvent - Transmit Event Bit definition - Read-only */
+#define TX_LOST_CRS 0x0040
+#define TX_SQE_ERROR 0x0080
+#define TX_OK 0x0100
+#define TX_LATE_COL 0x0200
+#define TX_JBR 0x0400
+#define TX_16_COL 0x8000
+#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
+#define TX_COL_COUNT_MASK 0x7800
+
+/* PP_BufEvent - Buffer Event Bit definition - Read-only */
+#define SW_INTERRUPT 0x0040
+#define RX_DMA 0x0080
+#define READY_FOR_TX 0x0100
+#define TX_UNDERRUN 0x0200
+#define RX_MISS 0x0400
+#define RX_128_BYTE 0x0800
+#define TX_COL_OVRFLW 0x1000
+#define RX_MISS_OVRFLW 0x2000
+#define RX_DEST_MATCH 0x8000
+
+/* PP_LineST - Ethernet Line Status bit definition - Read-only */
+#define LINK_OK 0x0080
+#define AUI_ON 0x0100
+#define TENBASET_ON 0x0200
+#define POLARITY_OK 0x1000
+#define CRS_OK 0x4000
+
+/* PP_SelfST - Chip Software Status bit definition */
+#define ACTIVE_33V 0x0040
+#define INIT_DONE 0x0080
+#define SI_BUSY 0x0100
+#define EEPROM_PRESENT 0x0200
+#define EEPROM_OK 0x0400
+#define EL_PRESENT 0x0800
+#define EE_SIZE_64 0x1000
+
+/* PP_BusST - ISA Bus Status bit definition */
+#define TX_BID_ERROR 0x0080
+#define READY_FOR_TX_NOW 0x0100
+
+/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
+#define RE_NEG_NOW 0x0040
+#define ALLOW_FDX 0x0080
+#define AUTO_NEG_ENABLE 0x0100
+#define NLP_ENABLE 0x0200
+#define FORCE_FDX 0x8000
+#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
+#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
+
+/* PP_AutoNegST - Auto Negotiation Status bit definition */
+#define AUTO_NEG_BUSY 0x0080
+#define FLP_LINK 0x0100
+#define FLP_LINK_GOOD 0x0800
+#define LINK_FAULT 0x1000
+#define HDX_ACTIVE 0x4000
+#define FDX_ACTIVE 0x8000
+
+/*  The following block defines the ISQ event types */
+#define ISQ_RECEIVER_EVENT 0x04
+#define ISQ_TRANSMITTER_EVENT 0x08
+#define ISQ_BUFFER_EVENT 0x0c
+#define ISQ_RX_MISS_EVENT 0x10
+#define ISQ_TX_COL_EVENT 0x12
+
+#define ISQ_EVENT_MASK 0x003F   /*  ISQ mask to find out type of event */
+#define ISQ_HIST 16		/*  small history buffer */
+#define AUTOINCREMENT 0x8000	/*  Bit mask to set bit-15 for autoincrement */
+
+#define TXRXBUFSIZE 0x0600
+#define RXDMABUFSIZE 0x8000
+#define RXDMASIZE 0x4000
+#define TXRX_LENGTH_MASK 0x07FF
+
+/*  rx options bits */
+#define RCV_WITH_RXON	1       /*  Set SerRx ON */
+#define RCV_COUNTS	2       /*  Use Framecnt1 */
+#define RCV_PONG	4       /*  Pong respondent */
+#define RCV_DONG	8       /*  Dong operation */
+#define RCV_POLLING	0x10	/*  Poll RxEvent */
+#define RCV_ISQ		0x20	/*  Use ISQ, int */
+#define RCV_AUTO_DMA	0x100	/*  Set AutoRxDMAE */
+#define RCV_DMA		0x200	/*  Set RxDMA only */
+#define RCV_DMA_ALL	0x400	/*  Copy all DMA'ed */
+#define RCV_FIXED_DATA	0x800	/*  Every frame same */
+#define RCV_IO		0x1000	/*  Use ISA IO only */
+#define RCV_MEMORY	0x2000	/*  Use ISA Memory */
+
+#define RAM_SIZE	0x1000       /*  The card has 4k bytes or RAM */
+#define PKT_START PP_TxFrame  /*  Start of packet RAM */
+
+#define RX_FRAME_PORT	0x0000
+#define TX_FRAME_PORT RX_FRAME_PORT
+#define TX_CMD_PORT	0x0004
+#define TX_NOW		0x0000       /*  Tx packet after   5 bytes copied */
+#define TX_AFTER_381	0x0020       /*  Tx packet after 381 bytes copied */
+#define TX_AFTER_ALL	0x00C0       /*  Tx packet after all bytes copied */
+#define TX_LEN_PORT	0x0006
+#define ISQ_PORT	0x0008
+#define ADD_PORT	0x000A
+#define DATA_PORT	0x000C
+
+#define EEPROM_WRITE_EN		0x00F0
+#define EEPROM_WRITE_DIS	0x0000
+#define EEPROM_WRITE_CMD	0x0100
+#define EEPROM_READ_CMD		0x0200
+
+/*  Receive Header */
+/*  Description of header of each packet in receive area of memory */
+#define RBUF_EVENT_LOW	0   /*  Low byte of RxEvent - status of received frame */
+#define RBUF_EVENT_HIGH	1   /*  High byte of RxEvent - status of received frame */
+#define RBUF_LEN_LOW	2   /*  Length of received data - low byte */
+#define RBUF_LEN_HI	3   /*  Length of received data - high byte */
+#define RBUF_HEAD_LEN	4   /*  Length of this header */
+
+#define CHIP_READ 0x1   /*  Used to mark state of the repins code (chip or dma) */
+#define DMA_READ 0x2   /*  Used to mark state of the repins code (chip or dma) */
+
+/*  for bios scan */
+/*  */
+#ifdef	CSDEBUG
+/*  use these values for debugging bios scan */
+#define BIOS_START_SEG 0x00000
+#define BIOS_OFFSET_INC 0x0010
+#else
+#define BIOS_START_SEG 0x0c000
+#define BIOS_OFFSET_INC 0x0200
+#endif
+
+#define BIOS_LAST_OFFSET 0x0fc00
+
+/*  Byte offsets into the EEPROM configuration buffer */
+#define ISA_CNF_OFFSET 0x6
+#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8)			/*  8900 eeprom */
+#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8)		/*  8920 eeprom */
+
+  /*  the assumption here is that the bits in the eeprom are generally  */
+  /*  in the same position as those in the autonegctl register. */
+  /*  Of course the IMM bit is not in that register so it must be  */
+  /*  masked out */
+#define EE_FORCE_FDX  0x8000
+#define EE_NLP_ENABLE 0x0200
+#define EE_AUTO_NEG_ENABLE 0x0100
+#define EE_ALLOW_FDX 0x0080
+#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
+
+#define IMM_BIT 0x0040		/*  ignore missing media */
+
+#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
+#define A_CNF_10B_T 0x0001
+#define A_CNF_AUI 0x0002
+#define A_CNF_10B_2 0x0004
+#define A_CNF_MEDIA_TYPE 0x0060
+#define A_CNF_MEDIA_AUTO 0x0000
+#define A_CNF_MEDIA_10B_T 0x0020
+#define A_CNF_MEDIA_AUI 0x0040
+#define A_CNF_MEDIA_10B_2 0x0060
+#define A_CNF_DC_DC_POLARITY 0x0080
+#define A_CNF_NO_AUTO_POLARITY 0x2000
+#define A_CNF_LOW_RX_SQUELCH 0x4000
+#define A_CNF_EXTND_10B_2 0x8000
+
+#define PACKET_PAGE_OFFSET 0x8
+
+/*  Bit definitions for the ISA configuration word from the EEPROM */
+#define INT_NO_MASK 0x000F
+#define DMA_NO_MASK 0x0070
+#define ISA_DMA_SIZE 0x0200
+#define ISA_AUTO_RxDMA 0x0400
+#define ISA_RxDMA 0x0800
+#define DMA_BURST 0x1000
+#define STREAM_TRANSFER 0x2000
+#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
+
+/*  DMA controller registers */
+#define DMA_BASE 0x00     /*  DMA controller base */
+#define DMA_BASE_2 0x0C0    /*  DMA controller base */
+
+#define DMA_STAT 0x0D0    /*  DMA controller status register */
+#define DMA_MASK 0x0D4    /*  DMA controller mask register */
+#define DMA_MODE 0x0D6    /*  DMA controller mode register */
+#define DMA_RESETFF 0x0D8    /*  DMA controller first/last flip flop */
+
+/*  DMA data */
+#define DMA_DISABLE 0x04     /*  Disable channel n */
+#define DMA_ENABLE 0x00     /*  Enable channel n */
+/*  Demand transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE 0x14
+/*  Demand transfers, incr. address, auto init, reads, ch. n */
+#define DMA_TX_MODE 0x18
+
+#define DMA_SIZE (16*1024) /*  Size of dma buffer - 16k */
+
+#define CS8900 0x0000
+#define CS8920 0x4000
+#define CS8920M 0x6000
+#define REVISON_BITS 0x1F00
+#define EEVER_NUMBER 0x12
+#define CHKSUM_LEN 0x14
+#define CHKSUM_VAL 0x0000
+#define START_EEPROM_DATA 0x001c /*  Offset into eeprom for start of data */
+#define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
+#define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
+#define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
+#define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
+
+#define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
+
+#define PNP_ADD_PORT 0x0279
+#define PNP_WRITE_PORT 0x0A79
+
+#define GET_PNP_ISA_STRUCT 0x40
+#define PNP_ISA_STRUCT_LEN 0x06
+#define PNP_CSN_CNT_OFF 0x01
+#define PNP_RD_PORT_OFF 0x02
+#define PNP_FUNCTION_OK 0x00
+#define PNP_WAKE 0x03
+#define PNP_RSRC_DATA 0x04
+#define PNP_RSRC_READY 0x01
+#define PNP_STATUS 0x05
+#define PNP_ACTIVATE 0x30
+#define PNP_CNF_IO_H 0x60
+#define PNP_CNF_IO_L 0x61
+#define PNP_CNF_INT 0x70
+#define PNP_CNF_DMA 0x74
+#define PNP_CNF_MEM 0x48
+
+#define BIT0 1
+#define BIT15 0x8000
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.txt b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.txt
new file mode 100644
index 0000000..72b7df2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/cs89x0.txt
@@ -0,0 +1,45 @@
+/**
+   Per an email message from Russ Nelson <nelson at crynwr.com> on
+   18 March 2008 the files cs89x0.[ch] are now licensed under GPL
+   Version 2.
+
+   From: Russ Nelson <nelson at crynwr.com>
+   Date: Tue, 18 Mar 2008 12:42:00 -0400
+   Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
+   -- quote from email 
+   As copyright holder, if I say it doesn't conflict with the GPL,
+   then it doesn't conflict with the GPL.
+
+   However, there's no point in causing people's brains to overheat,
+   so yes, I grant permission for the code to be relicensed under the
+   GPLv2.  Please make sure that this change in licensing makes its
+   way upstream.  -russ 
+   -- quote from email
+**/
+
+Permission is granted to distribute the enclosed cs89x0.[ch] driver
+only in conjunction with the Etherboot package.  The code is
+ordinarily distributed under the GPL.
+
+Russ Nelson, January 2000
+
+CREDITS
+
+I want to thank
+
+  Mike Cruse <mcruse at cti-ltd.com>
+     for providing an evaluation NIC and for sponsoring the
+     development of this driver.
+
+  Randall Sears <sears at crystal.cirrus.com>
+  Deva Bodas <bodas at crystal.cirrus.com>
+  Andreas Kraemer <akraemer at crystal.cirrus.com>
+  Wolfgang Krause <100303.2673 at compuserve.com>
+     for excellent technical support and for providing the required
+     programming information. I appreciate Crystal Semiconductor's
+     commitment towards free software.
+
+  Russell Nelson <nelson at crynwr.com>
+     for writing the Linux device driver for the CS89x0
+     chipset. Russel's code is very well designed and simplified my
+     job a lot.
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/davicom.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/davicom.c
new file mode 100644
index 0000000..1411774
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/davicom.c
@@ -0,0 +1,708 @@
+#ifdef ALLMULTI
+#error multicast support is not yet implemented
+#endif
+/*  
+    DAVICOM DM9009/DM9102/DM9102A Etherboot Driver	V1.00
+
+    This driver was ported from Marty Connor's Tulip Etherboot driver. 
+    Thanks Marty Connor (mdc at etherboot.org) 
+
+    This davicom etherboot driver supports DM9009/DM9102/DM9102A/
+    DM9102A+DM9801/DM9102A+DM9802 NICs.
+
+    This software may be used and distributed according to the terms
+    of the GNU Public License, incorporated herein by reference.
+
+*/
+
+FILE_LICENCE ( GPL_ANY );
+
+/*********************************************************************/
+/* Revision History                                                  */
+/*********************************************************************/
+
+/*
+  19 OCT 2000  Sten     1.00
+			Different half and full duplex mode
+			Do the different programming for DM9801/DM9802
+
+  12 OCT 2000  Sten     0.90
+			This driver was ported from tulip driver and it 
+			has the following difference.
+			Changed symbol tulip/TULIP to davicom/DAVICOM
+			Deleted some code that did not use in this driver.
+			Used chain-strcture to replace ring structure
+			for both TX/RX descriptor.
+			Allocated two tx descriptor.
+			According current media mode to set operating 
+			register(CR6)
+*/
+
+
+/*********************************************************************/
+/* Declarations                                                      */
+/*********************************************************************/
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+#define TX_TIME_OUT       2*TICKS_PER_SEC
+
+/* Register offsets for davicom device */
+enum davicom_offsets {
+   CSR0=0,     CSR1=0x08,  CSR2=0x10,  CSR3=0x18,  CSR4=0x20,  CSR5=0x28,
+   CSR6=0x30,  CSR7=0x38,  CSR8=0x40,  CSR9=0x48, CSR10=0x50, CSR11=0x58,
+  CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0
+};
+
+/* EEPROM Address width definitions */
+#define EEPROM_ADDRLEN 6
+#define EEPROM_SIZE    32              /* 1 << EEPROM_ADDRLEN */
+/* Used to be 128, but we only need to read enough to get the MAC
+   address at bytes 20..25 */
+
+/* Data Read from the EEPROM */
+static unsigned char ee_data[EEPROM_SIZE];
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD    (5 << addr_len)
+#define EE_READ_CMD     (6 << addr_len)
+#define EE_ERASE_CMD    (7 << addr_len)
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK    0x02    /* EEPROM shift clock. */
+#define EE_CS           0x01    /* EEPROM chip select. */
+#define EE_DATA_WRITE   0x04    /* EEPROM chip data in. */
+#define EE_WRITE_0      0x01
+#define EE_WRITE_1      0x05
+#define EE_DATA_READ    0x08    /* EEPROM chip data out. */
+#define EE_ENB          (0x4800 | EE_CS)
+
+/* Sten 10/11 for phyxcer */
+#define PHY_DATA_0	0x0
+#define PHY_DATA_1	0x20000
+#define MDCLKH		0x10000
+
+/* Delay between EEPROM clock transitions.  Even at 33Mhz current PCI
+   implementations don't overrun the EEPROM clock.  We add a bus
+   turn-around to insure that this remains true.  */
+#define eeprom_delay()  inl(ee_addr)
+
+/* helpful macro if on a big_endian machine for changing byte order.
+   not strictly needed on Intel
+   Already defined in Etherboot includes
+#define le16_to_cpu(val) (val)
+*/
+
+/* transmit and receive descriptor format */
+struct txdesc {
+  volatile unsigned long   status;         /* owner, status */
+  unsigned long   buf1sz:11,      /* size of buffer 1 */
+    buf2sz:11,                    /* size of buffer 2 */
+    control:10;                   /* control bits */
+  const unsigned char *buf1addr;  /* buffer 1 address */
+  const unsigned char *buf2addr;  /* buffer 2 address */
+};
+
+struct rxdesc {
+  volatile unsigned long   status;         /* owner, status */
+  unsigned long   buf1sz:11,      /* size of buffer 1 */
+    buf2sz:11,                    /* size of buffer 2 */
+    control:10;                   /* control bits */
+  unsigned char   *buf1addr;      /* buffer 1 address */
+  unsigned char   *buf2addr;      /* buffer 2 address */
+};
+
+/* Size of transmit and receive buffers */
+#define BUFLEN 1536
+
+/*********************************************************************/
+/* Global Storage                                                    */
+/*********************************************************************/
+
+static struct nic_operations davicom_operations;
+
+/* PCI Bus parameters */
+static unsigned short vendor, dev_id;
+static unsigned long ioaddr;
+
+/* Note: transmit and receive buffers must be longword aligned and
+   longword divisable */
+
+/* transmit descriptor and buffer */
+#define NTXD 2
+#define NRXD 4
+struct {
+	struct txdesc txd[NTXD] __attribute__ ((aligned(4)));
+	unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));
+	struct rxdesc rxd[NRXD] __attribute__ ((aligned(4)));
+	unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4)));
+} davicom_bufs __shared;
+#define txd davicom_bufs.txd
+#define txb davicom_bufs.txb
+#define rxd davicom_bufs.rxd
+#define rxb davicom_bufs.rxb
+static int rxd_tail;
+static int TxPtr;
+
+
+/*********************************************************************/
+/* Function Prototypes                                               */
+/*********************************************************************/
+static void whereami(const char *str);
+static int read_eeprom(unsigned long ioaddr, int location, int addr_len);
+static int davicom_probe(struct nic *nic,struct pci_device *pci);
+static void davicom_init_chain(struct nic *nic);	/* Sten 10/9 */
+static void davicom_reset(struct nic *nic);
+static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
+			   unsigned int s, const char *p);
+static int davicom_poll(struct nic *nic, int retrieve);
+static void davicom_disable(struct nic *nic);
+static void davicom_wait(unsigned int nticks);
+static int phy_read(int);
+static void phy_write(int, u16);
+static void phy_write_1bit(u32, u32);
+static int phy_read_1bit(u32);
+static void davicom_media_chk(struct nic *);
+
+
+/*********************************************************************/
+/* Utility Routines                                                  */
+/*********************************************************************/
+static inline void whereami(const char *str)
+{
+  DBGP("%s\n", str);
+  /* sleep(2); */
+}
+
+static void davicom_wait(unsigned int nticks)
+{
+  unsigned int to = currticks() + nticks;
+  while (currticks() < to)
+    /* wait */ ;
+}
+
+
+/*********************************************************************/
+/* For DAVICOM phyxcer register by MII interface		     */
+/*********************************************************************/
+/*
+  Read a word data from phy register
+*/
+static int phy_read(int location)
+{
+ int i, phy_addr=1;
+ u16 phy_data;
+ u32 io_dcr9;
+
+ whereami("phy_read\n");
+
+ io_dcr9 = ioaddr + CSR9;
+
+ /* Send 33 synchronization clock to Phy controller */
+ for (i=0; i<34; i++)
+     phy_write_1bit(io_dcr9, PHY_DATA_1);
+
+ /* Send start command(01) to Phy */
+ phy_write_1bit(io_dcr9, PHY_DATA_0);
+ phy_write_1bit(io_dcr9, PHY_DATA_1);
+
+ /* Send read command(10) to Phy */
+ phy_write_1bit(io_dcr9, PHY_DATA_1);
+ phy_write_1bit(io_dcr9, PHY_DATA_0);
+
+ /* Send Phy addres */
+ for (i=0x10; i>0; i=i>>1)
+     phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
+   
+ /* Send register addres */
+ for (i=0x10; i>0; i=i>>1)
+     phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
+
+ /* Skip transition state */
+ phy_read_1bit(io_dcr9);
+
+ /* read 16bit data */
+ for (phy_data=0, i=0; i<16; i++) {
+   phy_data<<=1;
+   phy_data|=phy_read_1bit(io_dcr9);
+ }
+
+ return phy_data;
+}
+
+/*
+  Write a word to Phy register
+*/
+static void phy_write(int location, u16 phy_data)
+{
+ u16 i, phy_addr=1;
+ u32 io_dcr9; 
+
+ whereami("phy_write\n");
+
+ io_dcr9 = ioaddr + CSR9;
+
+ /* Send 33 synchronization clock to Phy controller */
+ for (i=0; i<34; i++)
+   phy_write_1bit(io_dcr9, PHY_DATA_1);
+
+ /* Send start command(01) to Phy */
+ phy_write_1bit(io_dcr9, PHY_DATA_0);
+ phy_write_1bit(io_dcr9, PHY_DATA_1);
+
+ /* Send write command(01) to Phy */
+ phy_write_1bit(io_dcr9, PHY_DATA_0);
+ phy_write_1bit(io_dcr9, PHY_DATA_1);
+
+ /* Send Phy addres */
+ for (i=0x10; i>0; i=i>>1)
+   phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
+
+ /* Send register addres */
+ for (i=0x10; i>0; i=i>>1)
+   phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
+
+ /* written trasnition */
+ phy_write_1bit(io_dcr9, PHY_DATA_1);
+ phy_write_1bit(io_dcr9, PHY_DATA_0);
+
+ /* Write a word data to PHY controller */
+ for (i=0x8000; i>0; i>>=1)
+   phy_write_1bit(io_dcr9, phy_data&i ? PHY_DATA_1: PHY_DATA_0);
+}
+
+/*
+  Write one bit data to Phy Controller
+*/
+static void phy_write_1bit(u32 ee_addr, u32 phy_data)
+{
+ whereami("phy_write_1bit\n");
+ outl(phy_data, ee_addr);                        /* MII Clock Low */
+ eeprom_delay();
+ outl(phy_data|MDCLKH, ee_addr);                 /* MII Clock High */
+ eeprom_delay();
+ outl(phy_data, ee_addr);                        /* MII Clock Low */
+ eeprom_delay();
+}
+
+/*
+  Read one bit phy data from PHY controller
+*/
+static int phy_read_1bit(u32 ee_addr)
+{
+ int phy_data;
+
+ whereami("phy_read_1bit\n");
+
+ outl(0x50000, ee_addr);
+ eeprom_delay();
+
+ phy_data=(inl(ee_addr)>>19) & 0x1;
+
+ outl(0x40000, ee_addr);
+ eeprom_delay();
+
+ return phy_data;
+}
+
+/*
+  DM9801/DM9802 present check and program 
+*/
+static void HPNA_process(void)
+{
+
+ if ( (phy_read(3) & 0xfff0) == 0xb900 ) {
+   if ( phy_read(31) == 0x4404 ) {
+     /* DM9801 present */
+     if (phy_read(3) == 0xb901)
+       phy_write(16, 0x5);	/* DM9801 E4 */
+     else
+       phy_write(16, 0x1005); /* DM9801 E3 and others */
+     phy_write(25, ((phy_read(24) + 3) & 0xff) | 0xf000);
+   } else {
+     /* DM9802 present */
+     phy_write(16, 0x5);
+     phy_write(25, (phy_read(25) & 0xff00) + 2);
+   }
+ }
+}
+
+/*
+  Sense media mode and set CR6
+*/
+static void davicom_media_chk(struct nic * nic __unused)
+{
+  unsigned long to, csr6;
+
+  csr6 = 0x00200000;	/* SF */
+  outl(csr6, ioaddr + CSR6);
+
+#define	PCI_DEVICE_ID_DM9009		0x9009
+  if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9009) {
+    /* Set to 10BaseT mode for DM9009 */
+    phy_write(0, 0);
+  } else {
+    /* For DM9102/DM9102A */
+    to = currticks() + 2 * TICKS_PER_SEC;
+    while ( ((phy_read(1) & 0x24)!=0x24) && (currticks() < to))
+      /* wait */ ;
+
+    if ( (phy_read(1) & 0x24) == 0x24 ) {
+      if (phy_read(17) & 0xa000)  
+        csr6 |= 0x00000200;	/* Full Duplex mode */
+    } else
+      csr6 |= 0x00040000; /* Select DM9801/DM9802 when Ethernet link failed */
+  }
+
+  /* set the chip's operating mode */
+  outl(csr6, ioaddr + CSR6);
+
+  /* DM9801/DM9802 present check & program */
+  if (csr6 & 0x40000)
+    HPNA_process();
+}
+
+
+/*********************************************************************/
+/* EEPROM Reading Code                                               */
+/*********************************************************************/
+/* EEPROM routines adapted from the Linux Tulip Code */
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way
+   through:->.
+*/
+static int read_eeprom(unsigned long ioaddr, int location, int addr_len)
+{
+  int i;
+  unsigned short retval = 0;
+  long ee_addr = ioaddr + CSR9;
+  int read_cmd = location | EE_READ_CMD;
+
+  whereami("read_eeprom\n");
+
+  outl(EE_ENB & ~EE_CS, ee_addr);
+  outl(EE_ENB, ee_addr);
+
+  /* Shift the read command bits out. */
+  for (i = 4 + addr_len; i >= 0; i--) {
+    short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+    outl(EE_ENB | dataval, ee_addr);
+    eeprom_delay();
+    outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+    eeprom_delay();
+  }
+  outl(EE_ENB, ee_addr);
+
+  for (i = 16; i > 0; i--) {
+    outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+    eeprom_delay();
+    retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+    outl(EE_ENB, ee_addr);
+    eeprom_delay();
+  }
+
+  /* Terminate the EEPROM access. */
+  outl(EE_ENB & ~EE_CS, ee_addr);
+  return retval;
+}
+
+/*********************************************************************/
+/* davicom_init_chain - setup the tx and rx descriptors                */
+/* Sten 10/9							     */
+/*********************************************************************/
+static void davicom_init_chain(struct nic *nic)
+{
+  int i;
+
+  /* setup the transmit descriptor */
+  /* Sten: Set 2 TX descriptor but use one TX buffer because
+	   it transmit a packet and wait complete every time. */
+  for (i=0; i<NTXD; i++) {
+    txd[i].buf1addr = (void *)virt_to_bus(&txb[0]);	/* Used same TX buffer */
+    txd[i].buf2addr = (void *)virt_to_bus(&txd[i+1]);	/*  Point to Next TX desc */
+    txd[i].buf1sz   = 0;
+    txd[i].buf2sz   = 0;
+    txd[i].control  = 0x184;           /* Begin/End/Chain */
+    txd[i].status   = 0x00000000;      /* give ownership to Host */
+  }
+
+  /* construct perfect filter frame with mac address as first match
+     and broadcast address for all others */
+  for (i=0; i<192; i++) txb[i] = 0xFF;
+  txb[0] = nic->node_addr[0];
+  txb[1] = nic->node_addr[1];
+  txb[4] = nic->node_addr[2];
+  txb[5] = nic->node_addr[3];
+  txb[8] = nic->node_addr[4];
+  txb[9] = nic->node_addr[5];
+
+  /* setup receive descriptor */
+  for (i=0; i<NRXD; i++) {
+    rxd[i].buf1addr = (void *)virt_to_bus(&rxb[i * BUFLEN]);
+    rxd[i].buf2addr = (void *)virt_to_bus(&rxd[i+1]); /* Point to Next RX desc */
+    rxd[i].buf1sz   = BUFLEN;
+    rxd[i].buf2sz   = 0;        /* not used */
+    rxd[i].control  = 0x4;		/* Chain Structure */
+    rxd[i].status   = 0x80000000;   /* give ownership to device */
+  }
+
+  /* Chain the last descriptor to first */
+  txd[NTXD - 1].buf2addr = (void *)virt_to_bus(&txd[0]);
+  rxd[NRXD - 1].buf2addr = (void *)virt_to_bus(&rxd[0]);
+  TxPtr = 0;
+  rxd_tail = 0;
+}
+
+
+/*********************************************************************/
+/* davicom_reset - Reset adapter                                         */
+/*********************************************************************/
+static void davicom_reset(struct nic *nic)
+{
+  unsigned long to;
+
+  whereami("davicom_reset\n");
+
+  /* Stop Tx and RX */
+  outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+  /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+  outl(0x00000001, ioaddr + CSR0);
+
+  davicom_wait(TICKS_PER_SEC);
+
+  /* TX/RX descriptor burst */
+  outl(0x0C00000, ioaddr + CSR0);	/* Sten 10/9 */
+
+  /* set up transmit and receive descriptors */
+  davicom_init_chain(nic);	/* Sten 10/9 */
+
+  /* Point to receive descriptor */
+  outl(virt_to_bus(&rxd[0]), ioaddr + CSR3);
+  outl(virt_to_bus(&txd[0]), ioaddr + CSR4);	/* Sten 10/9 */
+
+  /* According phyxcer media mode to set CR6,
+     DM9102/A phyxcer can auto-detect media mode */
+  davicom_media_chk(nic);
+
+  /* Prepare Setup Frame Sten 10/9 */
+  txd[TxPtr].buf1sz = 192;
+  txd[TxPtr].control = 0x024;		/* SF/CE */
+  txd[TxPtr].status = 0x80000000;	/* Give ownership to device */
+
+  /* Start Tx */
+  outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6);
+  /* immediate transmit demand */
+  outl(0, ioaddr + CSR1);
+
+  to = currticks() + TX_TIME_OUT;
+  while ((txd[TxPtr].status & 0x80000000) && (currticks() < to)) /* Sten 10/9 */
+    /* wait */ ;
+
+  if (currticks() >= to) {
+    DBG ("TX Setup Timeout!\n");
+  }
+  /* Point to next TX descriptor */
+ TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr;	/* Sten 10/9 */
+
+  DBG("txd.status = %lX\n", txd[TxPtr].status);
+  DBG("ticks = %ld\n", currticks() - (to - TX_TIME_OUT));
+  DBG_MORE();
+
+  /* enable RX */
+  outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6);
+  /* immediate poll demand */
+  outl(0, ioaddr + CSR2);
+}
+
+
+/*********************************************************************/
+/* eth_transmit - Transmit a frame                                   */
+/*********************************************************************/
+static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
+                           unsigned int s, const char *p)
+{
+  unsigned long to;
+
+  whereami("davicom_transmit\n");
+
+  /* Stop Tx */
+  /* outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); */
+
+  /* setup ethernet header */
+  memcpy(&txb[0], d, ETH_ALEN);	/* DA 6byte */
+  memcpy(&txb[ETH_ALEN], nic->node_addr, ETH_ALEN); /* SA 6byte*/
+  txb[ETH_ALEN*2] = (t >> 8) & 0xFF; /* Frame type: 2byte */
+  txb[ETH_ALEN*2+1] = t & 0xFF;
+  memcpy(&txb[ETH_HLEN], p, s); /* Frame data */
+
+  /* setup the transmit descriptor */
+  txd[TxPtr].buf1sz   = ETH_HLEN+s;
+  txd[TxPtr].control  = 0x00000184;      /* LS+FS+CE */
+  txd[TxPtr].status   = 0x80000000;      /* give ownership to device */
+
+  /* immediate transmit demand */
+  outl(0, ioaddr + CSR1);
+
+  to = currticks() + TX_TIME_OUT;
+  while ((txd[TxPtr].status & 0x80000000) && (currticks() < to))
+    /* wait */ ;
+
+  if (currticks() >= to) {
+    DBG ("TX Timeout!\n");
+  }
+ 
+  /* Point to next TX descriptor */
+  TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr;	/* Sten 10/9 */
+
+}
+
+/*********************************************************************/
+/* eth_poll - Wait for a frame                                       */
+/*********************************************************************/
+static int davicom_poll(struct nic *nic, int retrieve)
+{
+  whereami("davicom_poll\n");
+
+  if (rxd[rxd_tail].status & 0x80000000)
+    return 0;
+
+  if ( ! retrieve ) return 1;
+
+  whereami("davicom_poll got one\n");
+
+  nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
+
+  if( rxd[rxd_tail].status & 0x00008000){
+      rxd[rxd_tail].status = 0x80000000;
+      rxd_tail++;
+      if (rxd_tail == NRXD) rxd_tail = 0;
+      return 0;
+  }
+
+  /* copy packet to working buffer */
+  /* XXX - this copy could be avoided with a little more work
+     but for now we are content with it because the optimised
+     memcpy is quite fast */
+
+  memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
+
+  /* return the descriptor and buffer to receive ring */
+  rxd[rxd_tail].status = 0x80000000;
+  rxd_tail++;
+  if (rxd_tail == NRXD) rxd_tail = 0;
+
+  return 1;
+}
+
+/*********************************************************************/
+/* eth_disable - Disable the interface                               */
+/*********************************************************************/
+static void davicom_disable ( struct nic *nic ) {
+
+  whereami("davicom_disable\n");
+
+  davicom_reset(nic);
+
+  /* disable interrupts */
+  outl(0x00000000, ioaddr + CSR7);
+
+  /* Stop the chip's Tx and Rx processes. */
+  outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+  /* Clear the missed-packet counter. */
+  inl(ioaddr + CSR8);
+}
+
+
+/*********************************************************************/
+/* eth_irq - enable, disable and force interrupts                    */
+/*********************************************************************/
+static void davicom_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+
+/*********************************************************************/
+/* eth_probe - Look for an adapter                                   */
+/*********************************************************************/
+static int davicom_probe ( struct nic *nic, struct pci_device *pci ) {
+
+  unsigned int i;
+
+  whereami("davicom_probe\n");
+
+  if (pci->ioaddr == 0)
+    return 0;
+
+  vendor  = pci->vendor;
+  dev_id  = pci->device;
+  ioaddr  = pci->ioaddr;
+
+  nic->ioaddr = pci->ioaddr;
+  nic->irqno = 0;
+
+  /* wakeup chip */
+  pci_write_config_dword(pci, 0x40, 0x00000000);
+
+  /* Stop the chip's Tx and Rx processes. */
+  outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+  /* Clear the missed-packet counter. */
+  inl(ioaddr + CSR8);
+
+  /* Get MAC Address */
+  /* read EEPROM data */
+  for (i = 0; i < sizeof(ee_data)/2; i++)
+    ((unsigned short *)ee_data)[i] =
+        le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
+
+  /* extract MAC address from EEPROM buffer */
+  for (i=0; i<ETH_ALEN; i++)
+    nic->node_addr[i] = ee_data[20+i];
+
+  DBG ( "Davicom %s at IOADDR %4.4lx\n", eth_ntoa ( nic->node_addr ), ioaddr );
+
+  /* initialize device */
+  davicom_reset(nic);
+  nic->nic_op	= &davicom_operations;
+  return 1;
+}
+
+static struct nic_operations davicom_operations = {
+	.connect	= dummy_connect,
+	.poll		= davicom_poll,
+	.transmit	= davicom_transmit,
+	.irq		= davicom_irq,
+
+};
+
+static struct pci_device_id davicom_nics[] = {
+PCI_ROM(0x1282, 0x9100, "davicom9100", "Davicom 9100", 0),
+PCI_ROM(0x1282, 0x9102, "davicom9102", "Davicom 9102", 0),
+PCI_ROM(0x1282, 0x9009, "davicom9009", "Davicom 9009", 0),
+PCI_ROM(0x1282, 0x9132, "davicom9132", "Davicom 9132", 0),	/* Needs probably some fixing */
+};
+
+PCI_DRIVER ( davicom_driver, davicom_nics, PCI_NO_CLASS );
+
+DRIVER ( "DAVICOM", nic_driver, pci_driver, davicom_driver,
+	 davicom_probe, davicom_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/depca.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/depca.c
new file mode 100644
index 0000000..735a52d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/depca.c
@@ -0,0 +1,805 @@
+/* #warning "depca.c: FIXME: fix relocation" */
+
+FILE_LICENCE ( GPL_ANY );
+
+#if 0
+/* Not fixed for relocation yet. Probably won't work relocated above 16MB */
+#ifdef ALLMULTI
+#error multicast support is not yet implemented
+#endif
+/* Etherboot: depca.h merged, comments from Linux driver retained */
+/*  depca.c: A DIGITAL DEPCA  & EtherWORKS ethernet driver for linux.
+
+    Written 1994, 1995 by David C. Davies.
+
+
+                      Copyright 1994 David C. Davies
+		                   and 
+			 United States Government
+	 (as represented by the Director, National Security Agency).  
+
+               Copyright 1995  Digital Equipment Corporation.
+
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+
+    This driver is written for the Digital Equipment Corporation series
+    of DEPCA and EtherWORKS ethernet cards:
+
+        DEPCA       (the original)
+    	DE100
+    	DE101
+	DE200 Turbo
+	DE201 Turbo
+	DE202 Turbo (TP BNC)
+	DE210
+	DE422       (EISA)
+
+    The  driver has been tested on DE100, DE200 and DE202 cards  in  a
+    relatively busy network. The DE422 has been tested a little.
+
+    This  driver will NOT work   for the DE203,  DE204  and DE205 series  of
+    cards,  since they have  a  new custom ASIC in   place of the AMD  LANCE
+    chip.  See the 'ewrk3.c'   driver in the  Linux  source tree for running
+    those cards.
+
+    I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
+    a DECstation 5000/200.
+
+    The author may be reached at davies at maniac.ultranet.com
+
+    =========================================================================
+
+    The  driver was originally based  on   the 'lance.c' driver from  Donald
+    Becker   which  is included with  the  standard  driver distribution for
+    linux.  V0.4  is  a complete  re-write  with only  the kernel  interface
+    remaining from the original code.
+
+    1) Lance.c code in /linux/drivers/net/
+    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
+       AMD, 1992 [(800) 222-9323].
+    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
+       AMD, Pub. #17881, May 1993.
+    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
+       AMD, Pub. #16907, May 1992
+    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
+    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
+    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
+       Digital Equipment Corporation, 1989
+    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
+    
+
+    Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
+    driver.
+
+    The original DEPCA  card requires that the  ethernet ROM address counter
+    be enabled to count and has an 8 bit NICSR.  The ROM counter enabling is
+    only  done when a  0x08 is read as the  first address octet (to minimise
+    the chances  of writing over some  other hardware's  I/O register).  The
+    NICSR accesses   have been changed  to  byte accesses  for all the cards
+    supported by this driver, since there is only one  useful bit in the MSB
+    (remote boot timeout) and it  is not used.  Also, there  is a maximum of
+    only 48kB network  RAM for this  card.  My thanks  to Torbjorn Lindh for
+    help debugging all this (and holding my feet to  the fire until I got it
+    right).
+
+    The DE200  series  boards have  on-board 64kB  RAM for  use  as a shared
+    memory network  buffer. Only the DE100  cards make use  of a  2kB buffer
+    mode which has not  been implemented in  this driver (only the 32kB  and
+    64kB modes are supported [16kB/48kB for the original DEPCA]).
+
+    At the most only 2 DEPCA cards can  be supported on  the ISA bus because
+    there is only provision  for two I/O base addresses  on each card (0x300
+    and 0x200). The I/O address is detected by searching for a byte sequence
+    in the Ethernet station address PROM at the expected I/O address for the
+    Ethernet  PROM.   The shared memory  base   address  is 'autoprobed'  by
+    looking  for the self  test PROM  and detecting the  card name.   When a
+    second  DEPCA is  detected,  information  is   placed in the   base_addr
+    variable of the  next device structure (which  is created if necessary),
+    thus  enabling ethif_probe  initialization  for the device.  More than 2
+    EISA cards can  be  supported, but  care will  be  needed assigning  the
+    shared memory to ensure that each slot has the  correct IRQ, I/O address
+    and shared memory address assigned.
+
+    ************************************************************************
+
+    NOTE: If you are using two  ISA DEPCAs, it is  important that you assign
+    the base memory addresses correctly.   The  driver autoprobes I/O  0x300
+    then 0x200.  The  base memory address for  the first device must be less
+    than that of the second so that the auto probe will correctly assign the
+    I/O and memory addresses on the same card.  I can't think of a way to do
+    this unambiguously at the moment, since there is nothing on the cards to
+    tie I/O and memory information together.
+
+    I am unable  to  test  2 cards   together for now,    so this  code   is
+    unchecked. All reports, good or bad, are welcome.
+
+    ************************************************************************
+
+    The board IRQ   setting must be  at an  unused IRQ which  is auto-probed
+    using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
+    {2,3,4,5,7}, whereas the  DE200 is at {5,9,10,11,15}.  Note that IRQ2 is
+    really IRQ9 in machines with 16 IRQ lines.
+
+    No 16MB memory  limitation should exist with this  driver as DMA is  not
+    used and the common memory area is in low memory on the network card (my
+    current system has 20MB and I've not had problems yet).
+
+    The ability to load this driver as a loadable module has been added. To
+    utilise this ability, you have to do <8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy depca.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) if you wish, edit the  source code near  line 1530 to reflect the I/O
+    address and IRQ you're using (see also 5).
+    3) compile  depca.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the depca configuration turned off and reboot.
+    5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
+       [Alan Cox: Changed the code to allow command line irq/io assignments]
+       [Dave Davies: Changed the code to allow command line mem/name
+                                                                assignments]
+    6) run the net startup bits for your eth?? interface manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    Note that autoprobing is not allowed in loadable modules - the system is
+    already up and running and you're messing with interrupts.
+
+    To unload a module, turn off the associated interface 
+    'ifconfig eth?? down' then 'rmmod depca'.
+
+    To assign a base memory address for the shared memory  when running as a
+    loadable module, see 5 above.  To include the adapter  name (if you have
+    no PROM  but know the card name)  also see 5  above. Note that this last
+    option  will not work  with kernel  built-in  depca's. 
+
+    The shared memory assignment for a loadable module  makes sense to avoid
+    the 'memory autoprobe' picking the wrong shared memory  (for the case of
+    2 depca's in a PC).
+
+    ************************************************************************
+    Support for MCA EtherWORKS cards added 11-3-98.
+    Verified to work with up to 2 DE212 cards in a system (although not
+      fully stress-tested).  
+
+    Currently known bugs/limitations:
+
+    Note:  with the MCA stuff as a module, it trusts the MCA configuration,
+           not the command line for IRQ and memory address.  You can
+           specify them if you want, but it will throw your values out.
+           You still have to pass the IO address it was configured as
+           though.
+
+    ************************************************************************
+    TO DO:
+    ------
+
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1     25-jan-94   Initial writing.
+      0.2     27-jan-94   Added LANCE TX hardware buffer chaining.
+      0.3      1-feb-94   Added multiple DEPCA support.
+      0.31     4-feb-94   Added DE202 recognition.
+      0.32    19-feb-94   Tidy up. Improve multi-DEPCA support.
+      0.33    25-feb-94   Fix DEPCA ethernet ROM counter enable.
+                          Add jabber packet fix from murf at perftech.com
+			  and becker at super.org
+      0.34     7-mar-94   Fix DEPCA max network memory RAM & NICSR access.
+      0.35     8-mar-94   Added DE201 recognition. Tidied up.
+      0.351   30-apr-94   Added EISA support. Added DE422 recognition.
+      0.36    16-may-94   DE422 fix released.
+      0.37    22-jul-94   Added MODULE support
+      0.38    15-aug-94   Added DBR ROM switch in depca_close(). 
+                          Multi DEPCA bug fix.
+      0.38axp 15-sep-94   Special version for Alpha AXP Linux V1.0.
+      0.381   12-dec-94   Added DE101 recognition, fix multicast bug.
+      0.382    9-feb-95   Fix recognition bug reported by <bkm at star.rl.ac.uk>.
+      0.383   22-feb-95   Fix for conflict with VESA SCSI reported by
+                          <stromain at alf.dec.com>
+      0.384   17-mar-95   Fix a ring full bug reported by <bkm at star.rl.ac.uk>
+      0.385    3-apr-95   Fix a recognition bug reported by 
+                                                <ryan.niemi at lastfrontier.com>
+      0.386   21-apr-95   Fix the last fix...sorry, must be galloping senility
+      0.40    25-May-95   Rewrite for portability & updated.
+                          ALPHA support from <jestabro at amt.tay1.dec.com>
+      0.41    26-Jun-95   Added verify_area() calls in depca_ioctl() from
+                          suggestion by <heiko at colossus.escape.de>
+      0.42    27-Dec-95   Add 'mem' shared memory assignment for loadable 
+                          modules.
+                          Add 'adapter_name' for loadable modules when no PROM.
+			  Both above from a suggestion by 
+			  <pchen at woodruffs121.residence.gatech.edu>.
+			  Add new multicasting code.
+      0.421   22-Apr-96	  Fix alloc_device() bug <jari at markkus2.fimr.fi>
+      0.422   29-Apr-96	  Fix depca_hw_init() bug <jari at markkus2.fimr.fi>
+      0.423    7-Jun-96   Fix module load bug <kmg at barco.be>
+      0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
+      0.44     1-Sep-97   Fix *_probe() to test check_region() first - bug
+                           reported by <mmogilvi at elbert.uccs.edu>
+      0.45     3-Nov-98   Added support for MCA EtherWORKS (DE210/DE212) cards
+                           by <tymm at computer.org> 
+      0.451    5-Nov-98   Fixed mca stuff cuz I'm a dummy. <tymm at computer.org>
+      0.5     14-Nov-98   Re-spin for 2.1.x kernels.
+      0.51    27-Jun-99   Correct received packet length for CRC from
+                           report by <worm at dkik.dk>
+
+    =========================================================================
+*/
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/isa.h>
+#include <ipxe/console.h>
+#include <ipxe/ethernet.h>
+
+/*
+** I/O addresses. Note that the 2k buffer option is not supported in
+** this driver.
+*/
+#define DEPCA_NICSR 0x00   /* Network interface CSR */
+#define DEPCA_RBI   0x02   /* RAM buffer index (2k buffer mode) */
+#define DEPCA_DATA  0x04   /* LANCE registers' data port */
+#define DEPCA_ADDR  0x06   /* LANCE registers' address port */
+#define DEPCA_HBASE 0x08   /* EISA high memory base address reg. */
+#define DEPCA_PROM  0x0c   /* Ethernet address ROM data port */
+#define DEPCA_CNFG  0x0c   /* EISA Configuration port */
+#define DEPCA_RBSA  0x0e   /* RAM buffer starting address (2k buff.) */
+
+/*
+** These are LANCE registers addressable through nic->ioaddr + DEPCA_ADDR 
+*/
+#define CSR0       0
+#define CSR1       1
+#define CSR2       2
+#define CSR3       3
+
+/* 
+** NETWORK INTERFACE CSR (NI_CSR) bit definitions 
+*/
+ 
+#define TO       	0x0100	/* Time Out for remote boot */
+#define SHE      	0x0080  /* SHadow memory Enable */
+#define BS       	0x0040  /* Bank Select */
+#define BUF      	0x0020	/* BUFfer size (1->32k, 0->64k) */
+#define RBE      	0x0010	/* Remote Boot Enable (1->net boot) */
+#define AAC      	0x0008  /* Address ROM Address Counter (1->enable) */
+#define _128KB      	0x0008  /* 128kB Network RAM (1->enable) */
+#define IM       	0x0004	/* Interrupt Mask (1->mask) */
+#define IEN      	0x0002	/* Interrupt tristate ENable (1->enable) */
+#define LED      	0x0001	/* LED control */
+
+/* 
+** Control and Status Register 0 (CSR0) bit definitions 
+*/
+
+#define ERR     	0x8000 	/* Error summary */
+#define BABL    	0x4000 	/* Babble transmitter timeout error  */
+#define CERR    	0x2000 	/* Collision Error */
+#define MISS    	0x1000 	/* Missed packet */
+#define MERR    	0x0800 	/* Memory Error */
+#define RINT    	0x0400 	/* Receiver Interrupt */
+#define TINT    	0x0200 	/* Transmit Interrupt */
+#define IDON    	0x0100 	/* Initialization Done */
+#define INTR    	0x0080 	/* Interrupt Flag */
+#define INEA    	0x0040 	/* Interrupt Enable */
+#define RXON    	0x0020 	/* Receiver on */
+#define TXON    	0x0010 	/* Transmitter on */
+#define TDMD    	0x0008 	/* Transmit Demand */
+#define STOP    	0x0004 	/* Stop */
+#define STRT    	0x0002 	/* Start */
+#define INIT    	0x0001 	/* Initialize */
+#define INTM            0xff00  /* Interrupt Mask */
+#define INTE            0xfff0  /* Interrupt Enable */
+
+/*
+** CONTROL AND STATUS REGISTER 3 (CSR3)
+*/
+
+#define BSWP    	0x0004	/* Byte SWaP */
+#define ACON    	0x0002	/* ALE control */
+#define BCON    	0x0001	/* Byte CONtrol */
+
+/*
+** Initialization Block Mode Register 
+*/
+
+#define PROM       	0x8000 	/* Promiscuous Mode */
+#define EMBA       	0x0080	/* Enable Modified Back-off Algorithm */
+#define INTL       	0x0040 	/* Internal Loopback */
+#define DRTY       	0x0020 	/* Disable Retry */
+#define COLL       	0x0010 	/* Force Collision */
+#define DTCR       	0x0008 	/* Disable Transmit CRC */
+#define LOOP       	0x0004 	/* Loopback */
+#define DTX        	0x0002 	/* Disable the Transmitter */
+#define DRX        	0x0001 	/* Disable the Receiver */
+
+/*
+** Receive Message Descriptor 1 (RMD1) bit definitions. 
+*/
+
+#define R_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define R_ERR     	0x4000 	/* Error Summary */
+#define R_FRAM    	0x2000 	/* Framing Error */
+#define R_OFLO    	0x1000 	/* Overflow Error */
+#define R_CRC     	0x0800 	/* CRC Error */
+#define R_BUFF    	0x0400 	/* Buffer Error */
+#define R_STP     	0x0200 	/* Start of Packet */
+#define R_ENP     	0x0100 	/* End of Packet */
+
+/*
+** Transmit Message Descriptor 1 (TMD1) bit definitions. 
+*/
+
+#define T_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define T_ERR     	0x4000 	/* Error Summary */
+#define T_ADD_FCS 	0x2000 	/* More the 1 retry needed to Xmit */
+#define T_MORE    	0x1000	/* >1 retry to transmit packet */
+#define T_ONE     	0x0800 	/* 1 try needed to transmit the packet */
+#define T_DEF     	0x0400 	/* Deferred */
+#define T_STP       0x02000000 	/* Start of Packet */
+#define T_ENP       0x01000000	/* End of Packet */
+#define T_FLAGS     0xff000000  /* TX Flags Field */
+
+/*
+** Transmit Message Descriptor 3 (TMD3) bit definitions.
+*/
+
+#define TMD3_BUFF    0x8000	/* BUFFer error */
+#define TMD3_UFLO    0x4000	/* UnderFLOw error */
+#define TMD3_RES     0x2000	/* REServed */
+#define TMD3_LCOL    0x1000	/* Late COLlision */
+#define TMD3_LCAR    0x0800	/* Loss of CARrier */
+#define TMD3_RTRY    0x0400	/* ReTRY error */
+
+/*
+** Ethernet PROM defines
+*/
+#define PROBE_LENGTH    32
+
+/*
+** Set the number of Tx and Rx buffers. Ensure that the memory requested
+** here is <= to the amount of shared memory set up by the board switches.
+** The number of descriptors MUST BE A POWER OF 2.
+**
+** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
+*/
+#define NUM_RX_DESC     2               /* Number of RX descriptors */
+#define NUM_TX_DESC     2               /* Number of TX descriptors */
+#define RX_BUFF_SZ	1536            /* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ	1536            /* Buffer size for each Tx buffer */
+
+/*
+** ISA Bus defines
+*/
+#ifndef	DEPCA_MODEL
+#define	DEPCA_MODEL	DEPCA
+#endif
+
+static enum {
+	DEPCA, DE100, DE101, DE200, DE201, DE202, DE210, DE212, DE422, unknown
+} adapter = DEPCA_MODEL;
+
+/*
+** Name <-> Adapter mapping
+*/
+
+static char *adapter_name[] = {
+	"DEPCA",
+	"DE100","DE101",
+	"DE200","DE201","DE202",
+	"DE210","DE212",
+	"DE422",
+	""
+};
+
+#ifndef	DEPCA_RAM_BASE
+#define DEPCA_RAM_BASE	0xd0000
+#endif
+
+/*
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry. 
+*/
+#define ALIGN4      ((u32)4 - 1)       /* 1 longword align */
+#define ALIGN8      ((u32)8 - 1)       /* 2 longword (quadword) align */
+#define ALIGN         ALIGN8              /* Keep the LANCE happy... */
+
+/*
+** The DEPCA Rx and Tx ring descriptors. 
+*/
+struct depca_rx_desc {
+    volatile s32 base;
+    s16 buf_length;		/* This length is negative 2's complement! */
+    s16 msg_length;		/* This length is "normal". */
+};
+
+struct depca_tx_desc {
+    volatile s32 base;
+    s16 length;		        /* This length is negative 2's complement! */
+    s16 misc;                   /* Errors and TDR info */
+};
+
+#define LA_MASK 0x0000ffff      /* LANCE address mask for mapping network RAM
+				   to LANCE memory address space */
+
+/*
+** The Lance initialization block, described in databook, in common memory.
+*/
+struct depca_init {
+    u16 mode;	                /* Mode register */
+    u8  phys_addr[ETH_ALEN];	/* Physical ethernet address */
+    u8  mcast_table[8];	        /* Multicast Hash Table. */
+    u32 rx_ring;     	        /* Rx ring base pointer & ring length */
+    u32 tx_ring;	        /* Tx ring base pointer & ring length */
+};
+
+struct depca_private {
+	struct depca_rx_desc	*rx_ring;
+	struct depca_tx_desc	*tx_ring;
+	struct depca_init	init_block;	/* Shadow init block */
+	char			*rx_memcpy[NUM_RX_DESC];
+	char			*tx_memcpy[NUM_TX_DESC];
+	u32			bus_offset;	/* ISA bus address offset */
+	u32			sh_mem;		/* address of shared mem */
+	u32			dma_buffs;	/* Rx & Tx buffer start */
+	int			rx_cur, tx_cur;	/* Next free ring entry */
+	int			txRingMask, rxRingMask;
+	s32			rx_rlen, tx_rlen;
+	/* log2([rt]xRingMask+1) for the descriptors */
+};
+
+static Address		mem_start = DEPCA_RAM_BASE;
+static Address		mem_len, offset;
+static struct depca_private	lp;
+
+/*
+** Miscellaneous defines...
+*/
+#define STOP_DEPCA(ioaddr) \
+    outw(CSR0, ioaddr + DEPCA_ADDR);\
+    outw(STOP, ioaddr + DEPCA_DATA)
+
+/* Initialize the lance Rx and Tx descriptor rings. */
+static void depca_init_ring(struct nic *nic)
+{
+	int	i;
+	u32	p;
+
+	lp.rx_cur = lp.tx_cur = 0;
+	/* Initialize the base addresses and length of each buffer in the ring */
+	for (i = 0; i <= lp.rxRingMask; i++) {
+		writel((p = lp.dma_buffs + i * RX_BUFF_SZ) | R_OWN, &lp.rx_ring[i].base);
+		writew(-RX_BUFF_SZ, &lp.rx_ring[i].buf_length);
+		lp.rx_memcpy[i] = (char *) (p + lp.bus_offset);
+	}
+	for (i = 0; i <= lp.txRingMask; i++) {
+		writel((p = lp.dma_buffs + (i + lp.txRingMask + 1) * TX_BUFF_SZ) & 0x00ffffff, &lp.tx_ring[i].base);
+		lp.tx_memcpy[i] = (char *) (p + lp.bus_offset);
+	}
+
+	/* Set up the initialization block */
+	lp.init_block.rx_ring = ((u32) ((u32) lp.rx_ring) & LA_MASK) | lp.rx_rlen;
+	lp.init_block.tx_ring = ((u32) ((u32) lp.tx_ring) & LA_MASK) | lp.tx_rlen;
+	for (i = 0; i < ETH_ALEN; i++)
+		lp.init_block.phys_addr[i] = nic->node_addr[i];
+	lp.init_block.mode = 0x0000;	/* Enable the Tx and Rx */
+	memset(lp.init_block.mcast_table, 0, sizeof(lp.init_block.mcast_table));
+}
+
+static inline void LoadCSRs(struct nic *nic)
+{
+	outw(CSR1, nic->ioaddr + DEPCA_ADDR);	/* initialisation block address LSW */
+	outw((u16) (lp.sh_mem & LA_MASK), nic->ioaddr + DEPCA_DATA);
+	outw(CSR2, nic->ioaddr + DEPCA_ADDR);	/* initialisation block address MSW */
+	outw((u16) ((lp.sh_mem & LA_MASK) >> 16), nic->ioaddr + DEPCA_DATA);
+	outw(CSR3, nic->ioaddr + DEPCA_ADDR);	/* ALE control */
+	outw(ACON, nic->ioaddr + DEPCA_DATA);
+	outw(CSR0, nic->ioaddr + DEPCA_ADDR);	/* Point back to CSR0 */
+}
+
+static inline int InitRestartDepca(struct nic *nic)
+{
+	int		i;
+
+	/* Copy the shadow init_block to shared memory */
+	memcpy_toio((char *)lp.sh_mem, &lp.init_block, sizeof(struct depca_init));
+	outw(CSR0, nic->ioaddr + DEPCA_ADDR);		/* point back to CSR0 */
+	outw(INIT, nic->ioaddr + DEPCA_DATA);		/* initialise DEPCA */
+
+	for (i = 0; i < 100 && !(inw(nic->ioaddr + DEPCA_DATA) & IDON); i++)
+		;
+	if (i < 100) {
+		/* clear IDON by writing a 1, and start LANCE */
+		outw(IDON | STRT, nic->ioaddr + DEPCA_DATA);
+	} else {
+		printf("DEPCA not initialised\n");
+		return (1);
+	}
+	return (0);
+}
+
+/**************************************************************************
+RESET - Reset adapter
+***************************************************************************/
+static void depca_reset(struct nic *nic)
+{
+	s16	nicsr;
+	int	i, j;
+
+	STOP_DEPCA(nic->ioaddr);
+	nicsr = inb(nic->ioaddr + DEPCA_NICSR);
+	nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+	outb(nicsr, nic->ioaddr + DEPCA_NICSR);
+	if (inw(nic->ioaddr + DEPCA_DATA) != STOP)
+	{
+		printf("depca: Cannot stop NIC\n");
+		return;
+	}
+
+	/* Initialisation block */
+	lp.sh_mem = mem_start;
+	mem_start += sizeof(struct depca_init);
+	/* Tx & Rx descriptors (aligned to a quadword boundary) */
+	mem_start = (mem_start + ALIGN) & ~ALIGN;
+	lp.rx_ring = (struct depca_rx_desc *) mem_start;
+	mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
+	lp.tx_ring = (struct depca_tx_desc *) mem_start;
+	mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
+
+	lp.bus_offset = mem_start & 0x00ff0000;
+	/* LANCE re-mapped start address */
+	lp.dma_buffs = mem_start & LA_MASK;
+
+	/* Finish initialising the ring information. */
+	lp.rxRingMask = NUM_RX_DESC - 1;
+	lp.txRingMask = NUM_TX_DESC - 1;
+
+	/* Calculate Tx/Rx RLEN size for the descriptors. */
+	for (i = 0, j = lp.rxRingMask; j > 0; i++) {
+		j >>= 1;
+	}
+	lp.rx_rlen = (s32) (i << 29);
+	for (i = 0, j = lp.txRingMask; j > 0; i++) {
+		j >>= 1;
+	}
+	lp.tx_rlen = (s32) (i << 29);
+
+	/* Load the initialisation block */
+	depca_init_ring(nic);
+	LoadCSRs(nic);
+	InitRestartDepca(nic);
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int depca_poll(struct nic *nic, int retrieve)
+{
+	int		entry;
+	u32		status;
+
+	entry = lp.rx_cur;
+	if ((status = readl(&lp.rx_ring[entry].base) & R_OWN))
+		return (0);
+
+	if ( ! retrieve ) return 1;
+
+	memcpy(nic->packet, lp.rx_memcpy[entry], nic->packetlen = lp.rx_ring[entry].msg_length);
+	lp.rx_ring[entry].base |= R_OWN;
+	lp.rx_cur = (++lp.rx_cur) & lp.rxRingMask;
+	return (1);
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void depca_transmit(
+	struct nic *nic,
+	const char *d,			/* Destination */
+	unsigned int t,			/* Type */
+	unsigned int s,			/* size */
+	const char *p)			/* Packet */
+{
+	int		entry, len;
+	char		*mem;
+
+	/* send the packet to destination */
+	/*
+	** Caution: the right order is important here... dont
+	** setup the ownership rights until all the other
+	** information is in place
+	*/
+	mem = lp.tx_memcpy[entry = lp.tx_cur];
+	memcpy_toio(mem, d, ETH_ALEN);
+	memcpy_toio(mem + ETH_ALEN, nic->node_addr, ETH_ALEN);
+	mem[ETH_ALEN * 2] = t >> 8;
+	mem[ETH_ALEN * 2 + 1] = t;
+	memcpy_toio(mem + ETH_HLEN, p, s);
+	s += ETH_HLEN;
+	len = (s < ETH_ZLEN ? ETH_ZLEN : s);
+	/* clean out flags */
+	writel(readl(&lp.tx_ring[entry].base) & ~T_FLAGS, &lp.tx_ring[entry].base);
+	/* clears other error flags */
+	writew(0x0000, &lp.tx_ring[entry].misc);
+	/* packet length in buffer */
+	writew(-len, &lp.tx_ring[entry].length);
+	/* start and end of packet, ownership */
+	writel(readl(&lp.tx_ring[entry].base) | (T_STP|T_ENP|T_OWN), &lp.tx_ring[entry].base);
+	/* update current pointers */
+	lp.tx_cur = (++lp.tx_cur) & lp.txRingMask;
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void depca_disable ( struct nic *nic ) {
+	depca_reset(nic);
+
+	STOP_DEPCA(nic->ioaddr);
+}
+
+/**************************************************************************
+IRQ - Interrupt Control
+***************************************************************************/
+static void depca_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all DEPCA products. Note that the original DEPCA needs
+** its ROM address counter to be initialized and enabled. Only enable
+** if the first address octet is a 0x08 - this minimises the chances of
+** messing around with some other hardware, but it assumes that this DEPCA
+** card initialized itself correctly.
+**
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the (length_of_the_signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+
+
+/*
+ * Ugly, ugly, ugly.  I can't quite make out where the split should be
+ * between probe1 and probe()...
+ *
+ */
+static u8 nicsr;
+
+
+static int depca_probe1 ( isa_probe_addr_t ioaddr ) {
+	u8	data;
+	/* This is only correct for little endian machines, but then
+	   Etherboot doesn't work on anything but a PC */
+	u8	sig[] = { 0xFF, 0x00, 0x55, 0xAA, 0xFF, 0x00, 0x55, 0xAA };
+	int	i, j;
+
+	data = inb(ioaddr + DEPCA_PROM);		/* clear counter on DEPCA */
+	data = inb(ioaddr + DEPCA_PROM);		/* read data */
+	if (data == 0x8) {
+		nicsr = inb(ioaddr + DEPCA_NICSR);
+		nicsr |= AAC;
+		outb(nicsr, ioaddr + DEPCA_NICSR);
+	}
+	for (i = 0, j = 0; j < (int)sizeof(sig) && i < PROBE_LENGTH+((int)sizeof(sig))-1; ++i) {
+		data = inb(ioaddr + DEPCA_PROM);
+		if (data == sig[j])		/* track signature */
+			++j;
+		else
+			j = (data == sig[0]) ? 1 : 0;
+	}
+	if (j != sizeof(sig))
+		return (0);
+	/* put the card in its initial state */
+	STOP_DEPCA(ioaddr);
+	nicsr = ((inb(ioaddr + DEPCA_NICSR) & ~SHE & ~RBE & ~IEN) | IM);
+	outb(nicsr, ioaddr + DEPCA_NICSR);
+	if (inw(ioaddr + DEPCA_DATA) != STOP)
+		return (0);
+	memcpy((char *)mem_start, sig, sizeof(sig));
+	if (memcmp((char *)mem_start, sig, sizeof(sig)) != 0)
+		return (0);
+
+	return 1;
+}
+
+static struct nic_operations depca_operations = {
+	.connect	= dummy_connect,
+	.poll		= depca_poll,
+	.transmit	= depca_transmit,
+	.irq		= depca_irq,
+
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int depca_probe ( struct nic *nic, struct isa_device *isa ) {
+
+	int	i, j;
+	long	sum, chksum;
+
+	nic->irqno    = 0;
+	nic->ioaddr   = isa->ioaddr;
+
+	for (i = 0, j = 0, sum = 0; j < 3; j++) {
+		sum <<= 1;
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+		sum += (u8)(nic->node_addr[i++] = inb(nic->ioaddr + DEPCA_PROM));
+		sum += (u16)((nic->node_addr[i++] = inb(nic->ioaddr + DEPCA_PROM)) << 8);
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+	if (sum == 0xFFFF)
+		sum = 0;
+	chksum = (u8)inb(nic->ioaddr + DEPCA_PROM);
+	chksum |= (u16)(inb(nic->ioaddr + DEPCA_PROM) << 8);
+	mem_len = (adapter == DEPCA) ? (48 << 10) : (64 << 10);
+	offset = 0;
+	if (nicsr & BUF) {
+		offset = 0x8000;
+		nicsr &= ~BS;
+		mem_len -= (32 << 10);
+	}
+	if (adapter != DEPCA)	/* enable shadow RAM */
+		outb(nicsr |= SHE, nic->ioaddr + DEPCA_NICSR);
+	DBG ( "%s base %4.4x, memory [%4.4lx-%4.4lx] addr %s",
+	       adapter_name[adapter], nic->ioaddr, mem_start,
+	       mem_start + mem_len, eth_ntoa ( nic->node_addr ) );
+	if (sum != chksum)
+		printf(" (bad checksum)");
+	putchar('\n');
+
+	depca_reset(nic);
+
+	/* point to NIC specific routines */
+	nic->nic_op	= &depca_operations;
+	return 1;
+}
+
+static isa_probe_addr_t depca_probe_addrs[] = {
+	0x300, 0x200,
+};
+
+ISA_DRIVER ( depca_driver, depca_probe_addrs, depca_probe1,
+		     GENERIC_ISAPNP_VENDOR, 0x80f7 );
+
+DRIVER ( "depce", nic_driver, isa_driver, depca_driver,
+	 depca_probe, depca_disable );
+
+ISA_ROM ( "depca", "Digital DE100 and DE200" );
+
+#endif
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/dmfe.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/dmfe.c
new file mode 100644
index 0000000..dd6c1de
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/dmfe.c
@@ -0,0 +1,1227 @@
+/**************************************************************************
+*
+*    dmfe.c -- Etherboot device driver for the Davicom 
+*	DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast ethernet card
+*
+*    Written 2003-2003 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*
+*       dmfe.c:     A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 
+*		NIC fast ethernet driver for Linux.
+*       Copyright (C) 1997  Sten Wang
+*       (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+*
+*
+*    REVISION HISTORY:
+*    ================
+*    v1.0       10-02-2004      timlegge        Boots ltsp needs cleanup 
+*
+*    Indent Options: indent -kr -i8
+*
+*
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+/* #define EDEBUG 1 */
+#ifdef EDEBUG
+#define dprintf(x) printf x
+#else
+#define dprintf(x)
+#endif
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+/* Board/System/Debug information/definition ---------------- */
+#define PCI_DM9132_ID   0x91321282	/* Davicom DM9132 ID */
+#define PCI_DM9102_ID   0x91021282	/* Davicom DM9102 ID */
+#define PCI_DM9100_ID   0x91001282	/* Davicom DM9100 ID */
+#define PCI_DM9009_ID   0x90091282	/* Davicom DM9009 ID */
+
+#define DM9102_IO_SIZE  0x80
+#define DM9102A_IO_SIZE 0x100
+#define TX_MAX_SEND_CNT 0x1	/* Maximum tx packet per time */
+#define TX_DESC_CNT     0x10	/* Allocated Tx descriptors */
+#define RX_DESC_CNT     0x20	/* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
+#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
+#define TX_BUF_ALLOC    0x600
+#define RX_ALLOC_SIZE   0x620
+#define DM910X_RESET    1
+#define CR0_DEFAULT     0x00E00000	/* TX & RX burst mode */
+#define CR6_DEFAULT     0x00080000	/* HD */
+#define CR7_DEFAULT     0x180c1
+#define CR15_DEFAULT    0x06	/* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK  0x4302	/* TXJT, LC, EC, FUE */
+#define MAX_PACKET_SIZE 1514
+#define DMFE_MAX_MULTICAST 14
+#define RX_COPY_SIZE	100
+#define MAX_CHECK_PACKET 0x8000
+#define DM9801_NOISE_FLOOR 8
+#define DM9802_NOISE_FLOOR 5
+
+#define DMFE_10MHF      0
+#define DMFE_100MHF     1
+#define DMFE_10MFD      4
+#define DMFE_100MFD     5
+#define DMFE_AUTO       8
+#define DMFE_1M_HPNA    0x10
+
+#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
+#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
+#define DMFE_TXTH_128	0x0000	/* TX TH 128 byte */
+#define DMFE_TXTH_256	0x4000	/* TX TH 256 byte */
+#define DMFE_TXTH_512	0x8000	/* TX TH 512 byte */
+#define DMFE_TXTH_1K	0xC000	/* TX TH 1K  byte */
+
+#define DMFE_TIMER_WUT  (jiffies + HZ * 1)	/* timer wakeup time : 1 second */
+#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
+#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
+
+#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+
+
+/* CR9 definition: SROM/MII */
+#define CR9_SROM_READ   0x4800
+#define CR9_SRCS        0x1
+#define CR9_SRCLK       0x2
+#define CR9_CRDOUT      0x8
+#define SROM_DATA_0     0x0
+#define SROM_DATA_1     0x4
+#define PHY_DATA_1      0x20000
+#define PHY_DATA_0      0x00000
+#define MDCLKH          0x10000
+
+#define PHY_POWER_DOWN	0x800
+
+#define SROM_V41_CODE   0x14
+
+#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);
+
+#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
+
+/* Sten Check */
+#define DEVICE net_device
+
+/* Structure/enum declaration ------------------------------- */
+struct tx_desc {
+	u32 tdes0, tdes1, tdes2, tdes3;	/* Data for the card */
+	void * tx_buf_ptr;		/* Data for us */
+	struct tx_desc * next_tx_desc;
+} __attribute__ ((aligned(32)));
+
+struct rx_desc {
+	u32 rdes0, rdes1, rdes2, rdes3;	/* Data for the card */
+	void * rx_skb_ptr;		/* Data for us */
+	struct rx_desc * next_rx_desc;
+} __attribute__ ((aligned(32)));
+
+static struct dmfe_private {
+	u32 chip_id;		/* Chip vendor/Device ID */
+	u32 chip_revision;	/* Chip revision */
+	u32 cr0_data;
+//	u32 cr5_data;
+	u32 cr6_data;
+	u32 cr7_data;
+	u32 cr15_data;
+
+	u16 HPNA_command;	/* For HPNA register 16 */
+	u16 HPNA_timer;		/* For HPNA remote device check */
+	u16 NIC_capability;	/* NIC media capability */
+	u16 PHY_reg4;		/* Saved Phyxcer register 4 value */
+
+	u8 HPNA_present;	/* 0:none, 1:DM9801, 2:DM9802 */
+	u8 chip_type;		/* Keep DM9102A chip type */
+	u8 media_mode;		/* user specify media mode */
+	u8 op_mode;		/* real work media mode */
+	u8 phy_addr;
+	u8 dm910x_chk_mode;	/* Operating mode check */
+
+	/* NIC SROM data */
+	unsigned char srom[128];
+	/* Etherboot Only */
+	u8 cur_tx;
+	u8 cur_rx;
+} dfx;
+
+static struct dmfe_private *db;
+
+enum dmfe_offsets {
+	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 =
+	    0x70,
+	DCR15 = 0x78
+};
+
+enum dmfe_CR6_bits {
+	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
+};
+
+/* Global variable declaration ----------------------------- */
+static struct nic_operations dmfe_operations;
+
+static unsigned char dmfe_media_mode = DMFE_AUTO;
+static u32 dmfe_cr6_user_set;
+
+/* For module input parameter */
+static u8 chkmode = 1;
+static u8 HPNA_mode;		/* Default: Low Power/High Speed */
+static u8 HPNA_rx_cmd;		/* Default: Disable Rx remote command */
+static u8 HPNA_tx_cmd;		/* Default: Don't issue remote command */
+static u8 HPNA_NoiseFloor;	/* Default: HPNA NoiseFloor */
+static u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
+				   4: TX pause packet */
+
+
+/**********************************************
+* Descriptor Ring and Buffer defination
+***********************************************/
+struct {
+	struct tx_desc txd[TX_DESC_CNT] __attribute__ ((aligned(32)));
+	unsigned char txb[TX_BUF_ALLOC * TX_DESC_CNT]
+	__attribute__ ((aligned(32)));
+	struct rx_desc rxd[RX_DESC_CNT] __attribute__ ((aligned(32)));
+	unsigned char rxb[RX_ALLOC_SIZE * RX_DESC_CNT]
+	__attribute__ ((aligned(32)));
+} dmfe_bufs __shared;
+#define txd dmfe_bufs.txd
+#define txb dmfe_bufs.txb
+#define rxd dmfe_bufs.rxd
+#define rxb dmfe_bufs.rxb
+
+/* NIC specific static variables go here */
+static long int BASE;
+
+static u16 read_srom_word(long ioaddr, int offset);
+static void dmfe_init_dm910x(struct nic *nic);
+static void dmfe_descriptor_init(struct nic *, unsigned long ioaddr);
+static void update_cr6(u32, unsigned long);
+static void send_filter_frame(struct nic *nic);
+static void dm9132_id_table(struct nic *nic);
+
+static u16 phy_read(unsigned long, u8, u8, u32);
+static void phy_write(unsigned long, u8, u8, u16, u32);
+static void phy_write_1bit(unsigned long, u32);
+static u16 phy_read_1bit(unsigned long);
+static void dmfe_set_phyxcer(struct nic *nic);
+
+static void dmfe_parse_srom(struct nic *nic);
+static void dmfe_program_DM9801(struct nic *nic, int);
+static void dmfe_program_DM9802(struct nic *nic);
+
+static void dmfe_reset(struct nic *nic)
+{
+	/* system variable init */
+	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
+
+	db->NIC_capability = 0xf;	/* All capability */
+	db->PHY_reg4 = 0x1e0;
+
+	/* CR6 operation mode decision */
+	if (!chkmode || (db->chip_id == PCI_DM9132_ID) ||
+	    (db->chip_revision >= 0x02000030)) {
+		db->cr6_data |= DMFE_TXTH_256;
+		db->cr0_data = CR0_DEFAULT;
+		db->dm910x_chk_mode = 4;	/* Enter the normal mode */
+	} else {
+		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
+		db->cr0_data = 0;
+		db->dm910x_chk_mode = 1;	/* Enter the check mode */
+	}
+	/* Initilize DM910X board */
+	dmfe_init_dm910x(nic);
+
+	return;
+}
+
+/*	Initilize DM910X board
+ *	Reset DM910X board
+ *	Initilize TX/Rx descriptor chain structure
+ *	Send the set-up frame
+ *	Enable Tx/Rx machine
+ */
+
+static void dmfe_init_dm910x(struct nic *nic)
+{
+	unsigned long ioaddr = BASE;
+
+	/* Reset DM910x MAC controller */
+	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
+	udelay(100);
+	outl(db->cr0_data, ioaddr + DCR0);
+	udelay(5);
+
+	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
+	db->phy_addr = 1;
+
+	/* Parser SROM and media mode */
+	dmfe_parse_srom(nic);
+	db->media_mode = dmfe_media_mode;
+
+	/* RESET Phyxcer Chip by GPR port bit 7 */
+	outl(0x180, ioaddr + DCR12);	/* Let bit 7 output port */
+	if (db->chip_id == PCI_DM9009_ID) {
+		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */
+		mdelay(300);	/* Delay 300 ms */
+	}
+	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */
+
+	/* Process Phyxcer Media Mode */
+	if (!(db->media_mode & 0x10))	/* Force 1M mode */
+		dmfe_set_phyxcer(nic);
+
+	/* Media Mode Process */
+	if (!(db->media_mode & DMFE_AUTO))
+		db->op_mode = db->media_mode;	/* Force Mode */
+
+	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
+	dmfe_descriptor_init(nic, ioaddr);
+
+	/* tx descriptor start pointer */
+	outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4);	/* TX DESC address */
+
+	/* rx descriptor start pointer */
+	outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3);	/* RX DESC address */
+
+	/* Init CR6 to program DM910x operation */
+	update_cr6(db->cr6_data, ioaddr);
+
+	/* Send setup frame */
+	if (db->chip_id == PCI_DM9132_ID) {
+		dm9132_id_table(nic);	/* DM9132 */
+	} else {
+		send_filter_frame(nic);	/* DM9102/DM9102A */
+	}
+
+	/* Init CR7, interrupt active bit */
+	db->cr7_data = CR7_DEFAULT;
+	outl(db->cr7_data, ioaddr + DCR7);
+	/* Init CR15, Tx jabber and Rx watchdog timer */
+	outl(db->cr15_data, ioaddr + DCR15);
+	/* Enable DM910X Tx/Rx function */
+	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
+	update_cr6(db->cr6_data, ioaddr);
+}
+#ifdef EDEBUG
+void hex_dump(const char *data, const unsigned int len);
+#endif
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int dmfe_poll(struct nic *nic, int retrieve)
+{
+	u32 rdes0;
+	int entry = db->cur_rx % RX_DESC_CNT;
+	int rxlen;
+	rdes0 = le32_to_cpu(rxd[entry].rdes0);
+	if (rdes0 & 0x80000000)
+		return 0;
+
+	if (!retrieve)
+		return 1;
+
+	if ((rdes0 & 0x300) != 0x300) {
+		/* A packet without First/Last flag */
+		printf("strange Packet\n");
+		rxd[entry].rdes0 = cpu_to_le32(0x80000000);
+		return 0;
+	} else {
+		/* A packet with First/Last flag */
+		rxlen = ((rdes0 >> 16) & 0x3fff) - 4;
+		/* error summary bit check */
+		if (rdes0 & 0x8000) {
+			printf("Error\n");
+			return 0;
+		}
+		if (!(rdes0 & 0x8000) ||
+		    ((db->cr6_data & CR6_PM) && (rxlen > 6))) {
+			if (db->dm910x_chk_mode & 1)
+				printf("Silly check mode\n");
+
+			nic->packetlen = rxlen;
+			memcpy(nic->packet, rxb + (entry * RX_ALLOC_SIZE),
+			       nic->packetlen);
+		}
+	}
+	rxd[entry].rdes0 = cpu_to_le32(0x80000000);
+	db->cur_rx++;
+	return 1;
+}
+
+static void dmfe_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+	switch ( action ) {
+		case DISABLE :
+			break;
+		case ENABLE :
+			break;
+		case FORCE :
+			break;
+	}
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void dmfe_transmit(struct nic *nic, 
+	const char *dest,	/* Destination */
+	unsigned int type,	/* Type */
+	unsigned int size,	/* size */
+	const char *packet)	/* Packet */
+{	
+	u16 nstype;
+	u8 *ptxb;
+
+	ptxb = &txb[db->cur_tx];
+
+	/* Stop Tx */
+	outl(0, BASE + DCR7);
+	memcpy(ptxb, dest, ETH_ALEN);
+	memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
+	nstype = htons((u16) type);
+	memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
+	memcpy(ptxb + ETH_HLEN, packet, size);
+
+	size += ETH_HLEN;
+	while (size < ETH_ZLEN)
+		ptxb[size++] = '\0';
+
+	/* setup the transmit descriptor */
+	txd[db->cur_tx].tdes1 = cpu_to_le32(0xe1000000 | size);
+	txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000);	/* give ownership to device */
+
+	/* immediate transmit demand */
+	outl(0x1, BASE + DCR1);
+	outl(db->cr7_data, BASE + DCR7);
+
+	/* Point to next TX descriptor */
+	db->cur_tx++;
+	db->cur_tx = db->cur_tx % TX_DESC_CNT;
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void dmfe_disable ( struct nic *nic __unused ) {
+	/* Reset & stop DM910X board */
+	outl(DM910X_RESET, BASE + DCR0);
+	udelay(5);
+	phy_write(BASE, db->phy_addr, 0, 0x8000, db->chip_id);
+
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int dmfe_probe ( struct nic *nic, struct pci_device *pci ) {
+
+	uint32_t dev_rev, pci_pmr;
+	int i;
+
+	if (pci->ioaddr == 0)
+		return 0;
+
+	BASE = pci->ioaddr;
+	printf("dmfe.c: Found %s Vendor=0x%hX Device=0x%hX\n",
+	       pci->id->name, pci->vendor, pci->device);
+
+	/* Read Chip revision */
+	pci_read_config_dword(pci, PCI_REVISION_ID, &dev_rev);
+	dprintf(("Revision %lX\n", dev_rev));
+
+	/* point to private storage */
+	db = &dfx;
+
+	db->chip_id = ((u32) pci->device << 16) | pci->vendor;
+	BASE = pci_bar_start(pci, PCI_BASE_ADDRESS_0);
+	db->chip_revision = dev_rev;
+
+	pci_read_config_dword(pci, 0x50, &pci_pmr);
+	pci_pmr &= 0x70000;
+	if ((pci_pmr == 0x10000) && (dev_rev == 0x02000031))
+		db->chip_type = 1;	/* DM9102A E3 */
+	else
+		db->chip_type = 0;
+
+	dprintf(("Chip type : %d\n", db->chip_type));
+
+	/* read 64 word srom data */
+	for (i = 0; i < 64; i++)
+		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(BASE, i));
+
+	/* Set Node address */
+	for (i = 0; i < 6; i++)
+		nic->node_addr[i] = db->srom[20 + i];
+
+	/* Print out some hardware info */
+	DBG ( "%s: %s at ioaddr %4.4lx\n",
+	      pci->id->name, eth_ntoa ( nic->node_addr ), BASE );
+
+	/* Set the card as PCI Bus Master */
+	adjust_pci_device(pci);
+
+	dmfe_reset(nic);
+
+	nic->irqno  = 0;
+	nic->ioaddr = pci->ioaddr;
+
+	/* point to NIC specific routines */
+	nic->nic_op	= &dmfe_operations;
+
+	return 1;
+}
+
+/*
+ *	Initialize transmit/Receive descriptor
+ *	Using Chain structure, and allocate Tx/Rx buffer
+ */
+
+static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr)
+{
+	int i;
+	db->cur_tx = 0;
+	db->cur_rx = 0;
+
+	/* tx descriptor start pointer */
+	outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4);	/* TX DESC address */
+
+	/* rx descriptor start pointer */
+	outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3);	/* RX DESC address */
+
+	/* Init Transmit chain */
+	for (i = 0; i < TX_DESC_CNT; i++) {
+		txd[i].tx_buf_ptr = &txb[i];
+		txd[i].tdes0 = cpu_to_le32(0);
+		txd[i].tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
+		txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i]));
+		txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1]));
+		txd[i].next_tx_desc = &txd[i + 1];
+	}
+	/* Mark the last entry as wrapping the ring */
+	txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]);
+	txd[i - 1].next_tx_desc = &txd[0];
+
+	/* receive descriptor chain */
+	for (i = 0; i < RX_DESC_CNT; i++) {
+		rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE];
+		rxd[i].rdes0 = cpu_to_le32(0x80000000);
+		rxd[i].rdes1 = cpu_to_le32(0x01000600);
+		rxd[i].rdes2 =
+		    cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE]));
+		rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1]));
+		rxd[i].next_rx_desc = &rxd[i + 1];
+	}
+	/* Mark the last entry as wrapping the ring */
+	rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0]));
+	rxd[i - 1].next_rx_desc = &rxd[0];
+
+}
+
+/*
+ *	Update CR6 value
+ *	Firstly stop DM910X , then written value and start
+ */
+
+static void update_cr6(u32 cr6_data, unsigned long ioaddr)
+{
+	u32 cr6_tmp;
+
+	cr6_tmp = cr6_data & ~0x2002;	/* stop Tx/Rx */
+	outl(cr6_tmp, ioaddr + DCR6);
+	udelay(5);
+	outl(cr6_data, ioaddr + DCR6);
+	udelay(5);
+}
+
+
+/*
+ *	Send a setup frame for DM9132
+ *	This setup frame initilize DM910X addres filter mode
+*/
+
+static void dm9132_id_table(struct nic *nic __unused)
+{
+#ifdef LINUX
+	u16 *addrptr;
+	u8 dmi_addr[8];
+	unsigned long ioaddr = BASE + 0xc0;	/* ID Table */
+	u32 hash_val;
+	u16 i, hash_table[4];
+#endif
+	dprintf(("dm9132_id_table\n"));
+
+	printf("FIXME: This function is broken.  If you have this card contact "
+		"Timothy Legge at the etherboot-user list\n");
+
+#ifdef LINUX
+	//DMFE_DBUG(0, "dm9132_id_table()", 0);
+
+	/* Node address */
+	addrptr = (u16 *) nic->node_addr;
+	outw(addrptr[0], ioaddr);
+	ioaddr += 4;
+	outw(addrptr[1], ioaddr);
+	ioaddr += 4;
+	outw(addrptr[2], ioaddr);
+	ioaddr += 4;
+
+	/* Clear Hash Table */
+	for (i = 0; i < 4; i++)
+		hash_table[i] = 0x0;
+
+	/* broadcast address */
+	hash_table[3] = 0x8000;
+
+	/* the multicast address in Hash Table : 64 bits */
+	for (mcptr = mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+		hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
+	}
+
+	/* Write the hash table to MAC MD table */
+	for (i = 0; i < 4; i++, ioaddr += 4)
+		outw(hash_table[i], ioaddr);
+#endif
+}
+
+
+/*
+ *	Send a setup frame for DM9102/DM9102A
+ *	This setup frame initilize DM910X addres filter mode
+ */
+
+static void send_filter_frame(struct nic *nic)
+{
+
+	u8 *ptxb;
+	int i;
+
+	dprintf(("send_filter_frame\n"));
+	/* point to the current txb incase multiple tx_rings are used */
+	ptxb = &txb[db->cur_tx];
+
+	/* construct perfect filter frame with mac address as first match
+	   and broadcast address for all others */
+	for (i = 0; i < 192; i++)
+		ptxb[i] = 0xFF;
+	ptxb[0] = nic->node_addr[0];
+	ptxb[1] = nic->node_addr[1];
+	ptxb[4] = nic->node_addr[2];
+	ptxb[5] = nic->node_addr[3];
+	ptxb[8] = nic->node_addr[4];
+	ptxb[9] = nic->node_addr[5];
+
+	/* prepare the setup frame */
+	txd[db->cur_tx].tdes1 = cpu_to_le32(0x890000c0);
+	txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000);
+	update_cr6(db->cr6_data | 0x2000, BASE);
+	outl(0x1, BASE + DCR1);	/* Issue Tx polling */
+	update_cr6(db->cr6_data, BASE);
+	db->cur_tx++;
+}
+
+/*
+ *	Read one word data from the serial ROM
+ */
+
+static u16 read_srom_word(long ioaddr, int offset)
+{
+	int i;
+	u16 srom_data = 0;
+	long cr9_ioaddr = ioaddr + DCR9;
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	/* Send the Read Command 110b */
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
+
+	/* Send the offset */
+	for (i = 5; i >= 0; i--) {
+		srom_data =
+		    (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
+		SROM_CLK_WRITE(srom_data, cr9_ioaddr);
+	}
+
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	for (i = 16; i > 0; i--) {
+		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
+		udelay(5);
+		srom_data =
+		    (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1
+					: 0);
+		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+		udelay(5);
+	}
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	return srom_data;
+}
+
+
+/*
+ *	Auto sense the media mode
+ */
+
+#if 0 /* not used */
+static u8 dmfe_sense_speed(struct nic *nic __unused)
+{
+	u8 ErrFlag = 0;
+	u16 phy_mode;
+
+	/* CR6 bit18=0, select 10/100M */
+	update_cr6((db->cr6_data & ~0x40000), BASE);
+
+	phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id);
+	phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id);
+
+	if ((phy_mode & 0x24) == 0x24) {
+		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
+			phy_mode =
+			    phy_read(BASE, db->phy_addr, 7,
+				     db->chip_id) & 0xf000;
+		else		/* DM9102/DM9102A */
+			phy_mode =
+			    phy_read(BASE, db->phy_addr, 17,
+				     db->chip_id) & 0xf000;
+		/* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
+		switch (phy_mode) {
+		case 0x1000:
+			db->op_mode = DMFE_10MHF;
+			break;
+		case 0x2000:
+			db->op_mode = DMFE_10MFD;
+			break;
+		case 0x4000:
+			db->op_mode = DMFE_100MHF;
+			break;
+		case 0x8000:
+			db->op_mode = DMFE_100MFD;
+			break;
+		default:
+			db->op_mode = DMFE_10MHF;
+			ErrFlag = 1;
+			break;
+		}
+	} else {
+		db->op_mode = DMFE_10MHF;
+		//DMFE_DBUG(0, "Link Failed :", phy_mode);
+		ErrFlag = 1;
+	}
+
+	return ErrFlag;
+}
+#endif
+
+/*
+ *	Set 10/100 phyxcer capability
+ *	AUTO mode : phyxcer register4 is NIC capability
+ *	Force mode: phyxcer register4 is the force media
+ */
+
+static void dmfe_set_phyxcer(struct nic *nic __unused)
+{
+	u16 phy_reg;
+
+	/* Select 10/100M phyxcer */
+	db->cr6_data &= ~0x40000;
+	update_cr6(db->cr6_data, BASE);
+
+	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
+	if (db->chip_id == PCI_DM9009_ID) {
+		phy_reg =
+		    phy_read(BASE, db->phy_addr, 18,
+			     db->chip_id) & ~0x1000;
+		phy_write(BASE, db->phy_addr, 18, phy_reg, db->chip_id);
+	}
+
+	/* Phyxcer capability setting */
+	phy_reg = phy_read(BASE, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+	if (db->media_mode & DMFE_AUTO) {
+		/* AUTO Mode */
+		phy_reg |= db->PHY_reg4;
+	} else {
+		/* Force Mode */
+		switch (db->media_mode) {
+		case DMFE_10MHF:
+			phy_reg |= 0x20;
+			break;
+		case DMFE_10MFD:
+			phy_reg |= 0x40;
+			break;
+		case DMFE_100MHF:
+			phy_reg |= 0x80;
+			break;
+		case DMFE_100MFD:
+			phy_reg |= 0x100;
+			break;
+		}
+		if (db->chip_id == PCI_DM9009_ID)
+			phy_reg &= 0x61;
+	}
+
+	/* Write new capability to Phyxcer Reg4 */
+	if (!(phy_reg & 0x01e0)) {
+		phy_reg |= db->PHY_reg4;
+		db->media_mode |= DMFE_AUTO;
+	}
+	phy_write(BASE, db->phy_addr, 4, phy_reg, db->chip_id);
+
+	/* Restart Auto-Negotiation */
+	if (db->chip_type && (db->chip_id == PCI_DM9102_ID))
+		phy_write(BASE, db->phy_addr, 0, 0x1800, db->chip_id);
+	if (!db->chip_type)
+		phy_write(BASE, db->phy_addr, 0, 0x1200, db->chip_id);
+}
+
+
+/*
+ *	Process op-mode
+ *	AUTO mode : PHY controller in Auto-negotiation Mode
+ *	Force mode: PHY controller in force mode with HUB
+ *			N-way force capability with SWITCH
+ */
+
+#if 0 /* not used */
+static void dmfe_process_mode(struct nic *nic __unused)
+{
+	u16 phy_reg;
+
+	/* Full Duplex Mode Check */
+	if (db->op_mode & 0x4)
+		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
+	else
+		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
+
+	/* Transciver Selection */
+	if (db->op_mode & 0x10)	/* 1M HomePNA */
+		db->cr6_data |= 0x40000;	/* External MII select */
+	else
+		db->cr6_data &= ~0x40000;	/* Internal 10/100 transciver */
+
+	update_cr6(db->cr6_data, BASE);
+
+	/* 10/100M phyxcer force mode need */
+	if (!(db->media_mode & 0x18)) {
+		/* Forece Mode */
+		phy_reg = phy_read(BASE, db->phy_addr, 6, db->chip_id);
+		if (!(phy_reg & 0x1)) {
+			/* parter without N-Way capability */
+			phy_reg = 0x0;
+			switch (db->op_mode) {
+			case DMFE_10MHF:
+				phy_reg = 0x0;
+				break;
+			case DMFE_10MFD:
+				phy_reg = 0x100;
+				break;
+			case DMFE_100MHF:
+				phy_reg = 0x2000;
+				break;
+			case DMFE_100MFD:
+				phy_reg = 0x2100;
+				break;
+			}
+			phy_write(BASE, db->phy_addr, 0, phy_reg,
+				  db->chip_id);
+			if (db->chip_type
+			    && (db->chip_id == PCI_DM9102_ID))
+				mdelay(20);
+			phy_write(BASE, db->phy_addr, 0, phy_reg,
+				  db->chip_id);
+		}
+	}
+}
+#endif
+
+/*
+ *	Write a word to Phy register
+ */
+
+static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
+		      u16 phy_data, u32 chip_id)
+{
+	u16 i;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_DM9132_ID) {
+		ioaddr = iobase + 0x80 + offset * 4;
+		outw(phy_data, ioaddr);
+	} else {
+		/* DM9102/DM9102A Chip */
+		ioaddr = iobase + DCR9;
+
+		/* Send 33 synchronization clock to Phy controller */
+		for (i = 0; i < 35; i++)
+			phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send start command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send write command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send Phy addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr,
+				       phy_addr & i ? PHY_DATA_1 :
+				       PHY_DATA_0);
+
+		/* Send register addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr,
+				       offset & i ? PHY_DATA_1 :
+				       PHY_DATA_0);
+
+		/* written trasnition */
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+
+		/* Write a word data to PHY controller */
+		for (i = 0x8000; i > 0; i >>= 1)
+			phy_write_1bit(ioaddr,
+				       phy_data & i ? PHY_DATA_1 :
+				       PHY_DATA_0);
+	}
+}
+
+
+/*
+ *	Read a word data from phy register
+ */
+
+static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset,
+		    u32 chip_id)
+{
+	int i;
+	u16 phy_data;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_DM9132_ID) {
+		/* DM9132 Chip */
+		ioaddr = iobase + 0x80 + offset * 4;
+		phy_data = inw(ioaddr);
+	} else {
+		/* DM9102/DM9102A Chip */
+		ioaddr = iobase + DCR9;
+
+		/* Send 33 synchronization clock to Phy controller */
+		for (i = 0; i < 35; i++)
+			phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send start command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send read command(10) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+
+		/* Send Phy addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr,
+				       phy_addr & i ? PHY_DATA_1 :
+				       PHY_DATA_0);
+
+		/* Send register addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr,
+				       offset & i ? PHY_DATA_1 :
+				       PHY_DATA_0);
+
+		/* Skip transition state */
+		phy_read_1bit(ioaddr);
+
+		/* read 16bit data */
+		for (phy_data = 0, i = 0; i < 16; i++) {
+			phy_data <<= 1;
+			phy_data |= phy_read_1bit(ioaddr);
+		}
+	}
+
+	return phy_data;
+}
+
+
+/*
+ *	Write one bit data to Phy Controller
+ */
+
+static void phy_write_1bit(unsigned long ioaddr, u32 phy_data)
+{
+	outl(phy_data, ioaddr);	/* MII Clock Low */
+	udelay(1);
+	outl(phy_data | MDCLKH, ioaddr);	/* MII Clock High */
+	udelay(1);
+	outl(phy_data, ioaddr);	/* MII Clock Low */
+	udelay(1);
+}
+
+
+/*
+ *	Read one bit phy data from PHY controller
+ */
+
+static u16 phy_read_1bit(unsigned long ioaddr)
+{
+	u16 phy_data;
+
+	outl(0x50000, ioaddr);
+	udelay(1);
+	phy_data = (inl(ioaddr) >> 19) & 0x1;
+	outl(0x40000, ioaddr);
+	udelay(1);
+
+	return phy_data;
+}
+
+
+/*
+ *	Parser SROM and media mode
+ */
+
+static void dmfe_parse_srom(struct nic *nic)
+{
+	unsigned char *srom = db->srom;
+	int dmfe_mode, tmp_reg;
+
+	/* Init CR15 */
+	db->cr15_data = CR15_DEFAULT;
+
+	/* Check SROM Version */
+	if (((int) srom[18] & 0xff) == SROM_V41_CODE) {
+		/* SROM V4.01 */
+		/* Get NIC support media mode */
+		db->NIC_capability = *(u16 *) (srom + 34);
+		db->PHY_reg4 = 0;
+		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
+			switch (db->NIC_capability & tmp_reg) {
+			case 0x1:
+				db->PHY_reg4 |= 0x0020;
+				break;
+			case 0x2:
+				db->PHY_reg4 |= 0x0040;
+				break;
+			case 0x4:
+				db->PHY_reg4 |= 0x0080;
+				break;
+			case 0x8:
+				db->PHY_reg4 |= 0x0100;
+				break;
+			}
+		}
+
+		/* Media Mode Force or not check */
+		dmfe_mode = *((int *) srom + 34) & *((int *) srom + 36);
+		switch (dmfe_mode) {
+		case 0x4:
+			dmfe_media_mode = DMFE_100MHF;
+			break;	/* 100MHF */
+		case 0x2:
+			dmfe_media_mode = DMFE_10MFD;
+			break;	/* 10MFD */
+		case 0x8:
+			dmfe_media_mode = DMFE_100MFD;
+			break;	/* 100MFD */
+		case 0x100:
+		case 0x200:
+			dmfe_media_mode = DMFE_1M_HPNA;
+			break;	/* HomePNA */
+		}
+
+		/* Special Function setting */
+		/* VLAN function */
+		if ((SF_mode & 0x1) || (srom[43] & 0x80))
+			db->cr15_data |= 0x40;
+
+		/* Flow Control */
+		if ((SF_mode & 0x2) || (srom[40] & 0x1))
+			db->cr15_data |= 0x400;
+
+		/* TX pause packet */
+		if ((SF_mode & 0x4) || (srom[40] & 0xe))
+			db->cr15_data |= 0x9800;
+	}
+
+	/* Parse HPNA parameter */
+	db->HPNA_command = 1;
+
+	/* Accept remote command or not */
+	if (HPNA_rx_cmd == 0)
+		db->HPNA_command |= 0x8000;
+
+	/* Issue remote command & operation mode */
+	if (HPNA_tx_cmd == 1)
+		switch (HPNA_mode) {	/* Issue Remote Command */
+		case 0:
+			db->HPNA_command |= 0x0904;
+			break;
+		case 1:
+			db->HPNA_command |= 0x0a00;
+			break;
+		case 2:
+			db->HPNA_command |= 0x0506;
+			break;
+		case 3:
+			db->HPNA_command |= 0x0602;
+			break;
+	} else
+		switch (HPNA_mode) {	/* Don't Issue */
+		case 0:
+			db->HPNA_command |= 0x0004;
+			break;
+		case 1:
+			db->HPNA_command |= 0x0000;
+			break;
+		case 2:
+			db->HPNA_command |= 0x0006;
+			break;
+		case 3:
+			db->HPNA_command |= 0x0002;
+			break;
+		}
+
+	/* Check DM9801 or DM9802 present or not */
+	db->HPNA_present = 0;
+	update_cr6(db->cr6_data | 0x40000, BASE);
+	tmp_reg = phy_read(BASE, db->phy_addr, 3, db->chip_id);
+	if ((tmp_reg & 0xfff0) == 0xb900) {
+		/* DM9801 or DM9802 present */
+		db->HPNA_timer = 8;
+		if (phy_read(BASE, db->phy_addr, 31, db->chip_id) ==
+		    0x4404) {
+			/* DM9801 HomeRun */
+			db->HPNA_present = 1;
+			dmfe_program_DM9801(nic, tmp_reg);
+		} else {
+			/* DM9802 LongRun */
+			db->HPNA_present = 2;
+			dmfe_program_DM9802(nic);
+		}
+	}
+
+}
+
+/*
+ *	Init HomeRun DM9801
+ */
+
+static void dmfe_program_DM9801(struct nic *nic __unused, int HPNA_rev)
+{
+	u32 reg17, reg25;
+
+	if (!HPNA_NoiseFloor)
+		HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
+	switch (HPNA_rev) {
+	case 0xb900:		/* DM9801 E3 */
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(BASE, db->phy_addr, 24, db->chip_id);
+		reg25 = ((reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
+		reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id);
+		break;
+	case 0xb901:		/* DM9801 E4 */
+		reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
+		reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
+		break;
+	case 0xb902:		/* DM9801 E5 */
+	case 0xb903:		/* DM9801 E6 */
+	default:
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
+		reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
+		break;
+	}
+	phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_write(BASE, db->phy_addr, 17, reg17, db->chip_id);
+	phy_write(BASE, db->phy_addr, 25, reg25, db->chip_id);
+}
+
+
+/*
+ *	Init HomeRun DM9802
+ */
+
+static void dmfe_program_DM9802(struct nic *nic __unused)
+{
+	u32 phy_reg;
+
+	if (!HPNA_NoiseFloor)
+		HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
+	phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_reg = phy_read(BASE, db->phy_addr, 25, db->chip_id);
+	phy_reg = (phy_reg & 0xff00) + HPNA_NoiseFloor;
+	phy_write(BASE, db->phy_addr, 25, phy_reg, db->chip_id);
+}
+
+static struct nic_operations dmfe_operations = {
+	.connect	= dummy_connect,
+	.poll		= dmfe_poll,
+	.transmit	= dmfe_transmit,
+	.irq		= dmfe_irq,
+
+};
+
+static struct pci_device_id dmfe_nics[] = {
+	PCI_ROM(0x1282, 0x9100, "dmfe9100", "Davicom 9100", 0),
+	PCI_ROM(0x1282, 0x9102, "dmfe9102", "Davicom 9102", 0),
+	PCI_ROM(0x1282, 0x9009, "dmfe9009", "Davicom 9009", 0),
+	PCI_ROM(0x1282, 0x9132, "dmfe9132", "Davicom 9132", 0),	/* Needs probably some fixing */
+};
+
+PCI_DRIVER ( dmfe_driver, dmfe_nics, PCI_NO_CLASS );
+
+DRIVER ( "DMFE/PCI", nic_driver, pci_driver, dmfe_driver,
+	 dmfe_probe, dmfe_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.c
new file mode 100644
index 0000000..a32a4d7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.c
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+REQUIRE_OBJECT(e1000_main);
+REQUIRE_OBJECT(e1000_82540);
+REQUIRE_OBJECT(e1000_82541);
+REQUIRE_OBJECT(e1000_82542);
+REQUIRE_OBJECT(e1000_82543);
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.h
new file mode 100644
index 0000000..31dbb85
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000.h
@@ -0,0 +1,326 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#include "e1000_api.h"
+
+#define BAR_0		0
+#define BAR_1		1
+#define BAR_5		5
+
+struct e1000_adapter;
+
+/* TX/RX descriptor defines */
+#define E1000_DEFAULT_TXD                  256
+#define E1000_MAX_TXD                      256
+#define E1000_MIN_TXD                       80
+#define E1000_MAX_82544_TXD               4096
+
+#define E1000_DEFAULT_TXD_PWR               12
+#define E1000_MAX_TXD_PWR                   12
+#define E1000_MIN_TXD_PWR                    7
+
+#define E1000_DEFAULT_RXD                  256
+#define E1000_MAX_RXD                      256
+
+#define E1000_MIN_RXD                       80
+#define E1000_MAX_82544_RXD               4096
+
+#define E1000_MIN_ITR_USECS                 10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS              10000 /* 100    irq/sec */
+
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
+/* Supported Rx Buffer Sizes */
+#define E1000_RXBUFFER_128   128
+#define E1000_RXBUFFER_256   256
+#define E1000_RXBUFFER_512   512
+#define E1000_RXBUFFER_1024  1024
+#define E1000_RXBUFFER_2048  2048
+#define E1000_RXBUFFER_4096  4096
+#define E1000_RXBUFFER_8192  8192
+#define E1000_RXBUFFER_16384 16384
+
+/* SmartSpeed delimiters */
+#define E1000_SMARTSPEED_DOWNSHIFT 3
+#define E1000_SMARTSPEED_MAX       15
+
+/* Packet Buffer allocations */
+#define E1000_PBA_BYTES_SHIFT 0xA
+#define E1000_TX_HEAD_ADDR_SHIFT 7
+#define E1000_PBA_TX_MASK 0xFFFF0000
+
+/* Early Receive defines */
+#define E1000_ERT_2048 0x100
+
+#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define E1000_TX_QUEUE_WAKE	16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+
+#define AUTO_ALL_MODES            0
+#define E1000_EEPROM_82544_APM    0x0004
+#define E1000_EEPROM_APME         0x0400
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct e1000_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	unsigned long time_stamp;
+	u16 length;
+	u16 next_to_watch;
+};
+
+struct e1000_rx_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	struct page *page;
+};
+
+
+
+struct e1000_tx_ring {
+	/* pointer to the descriptor ring memory */
+	void *desc;
+	/* physical address of the descriptor ring */
+	dma_addr_t dma;
+	/* length of descriptor ring in bytes */
+	unsigned int size;
+	/* number of descriptors in the ring */
+	unsigned int count;
+	/* next descriptor to associate a buffer with */
+	unsigned int next_to_use;
+	/* next descriptor to check for DD status bit */
+	unsigned int next_to_clean;
+	/* array of buffer information structs */
+	struct e1000_buffer *buffer_info;
+
+	spinlock_t tx_lock;
+	u16 tdh;
+	u16 tdt;
+
+	/* TXDdescriptor index increment to be used when advancing
+	* to the next descriptor. This is normally one, but on some
+	* architectures, but on some architectures there are cache
+	* coherency issues that require only the first descriptor in
+	* cache line can be used.
+	*/
+	unsigned int step;
+
+	bool last_tx_tso;
+};
+
+struct e1000_rx_ring {
+	struct e1000_adapter *adapter; /* back link */
+	/* pointer to the descriptor ring memory */
+	void *desc;
+	/* physical address of the descriptor ring */
+	dma_addr_t dma;
+	/* length of descriptor ring in bytes */
+	unsigned int size;
+	/* number of descriptors in the ring */
+	unsigned int count;
+	/* next descriptor to associate a buffer with */
+	unsigned int next_to_use;
+	/* next descriptor to check for DD status bit */
+	unsigned int next_to_clean;
+	/* array of buffer information structs */
+	struct e1000_rx_buffer *buffer_info;
+	struct sk_buff *rx_skb_top;
+
+	/* cpu for rx queue */
+	int cpu;
+
+	u16 rdh;
+	u16 rdt;
+};
+
+
+#define E1000_TX_DESC_INC(R,index) \
+	{index += (R)->step; if (index == (R)->count) index = 0; }
+
+#define E1000_TX_DESC_DEC(R,index) \
+	{ if (index == 0) index = (R)->count - (R)->step; \
+	else index -= (R)->step; }
+
+#define E1000_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define E1000_RX_DESC_EXT(R, i)	    \
+	(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
+
+/* board specific private data structure */
+
+struct e1000_adapter {
+	u32 bd_number;
+	u32 rx_buffer_len;
+	u32 wol;
+	u32 smartspeed;
+	u32 en_mng_pt;
+	u16 link_speed;
+	u16 link_duplex;
+	spinlock_t stats_lock;
+	unsigned int total_tx_bytes;
+	unsigned int total_tx_packets;
+	unsigned int total_rx_bytes;
+	unsigned int total_rx_packets;
+	/* Interrupt Throttle Rate */
+	u32 itr;
+	u32 itr_setting;
+	u16 tx_itr;
+	u16 rx_itr;
+
+	bool fc_autoneg;
+
+	/* TX */
+	struct e1000_tx_ring *tx_ring;
+	unsigned int restart_queue;
+	unsigned long tx_queue_len;
+	u32 txd_cmd;
+	u32 tx_int_delay;
+	u32 tx_abs_int_delay;
+	u32 gotc;
+	u64 gotc_old;
+	u64 tpt_old;
+	u64 colc_old;
+	u32 tx_timeout_count;
+	u32 tx_fifo_head;
+	u32 tx_head_addr;
+	u32 tx_fifo_size;
+	u8 tx_timeout_factor;
+	bool pcix_82544;
+	bool detect_tx_hung;
+
+	/* RX */
+	bool (*clean_rx) (struct e1000_adapter *adapter,
+			       struct e1000_rx_ring *rx_ring);
+	void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+			      struct e1000_rx_ring *rx_ring,
+				int cleaned_count);
+	struct e1000_rx_ring *rx_ring;
+
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+	u32 alloc_rx_buff_failed;
+	u32 rx_int_delay;
+	u32 rx_abs_int_delay;
+	bool rx_csum;
+	u32 gorc;
+	u64 gorc_old;
+	u32 max_frame_size;
+	u32 min_frame_size;
+
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_device *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+	struct e1000_hw_stats stats;
+	struct e1000_phy_info phy_info;
+	struct e1000_phy_stats phy_stats;
+
+	int msg_enable;
+	/* to not mess up cache alignment, always add to the bottom */
+	unsigned long state;
+	u32 eeprom_wol;
+
+	u32 *config_space;
+
+	/* hardware capability, feature, and workaround flags */
+	unsigned int flags;
+
+	/* upper limit parameter for tx desc size */
+	u32 tx_desc_pwr;
+
+#define NUM_TX_DESC	8
+#define NUM_RX_DESC	8
+
+	struct io_buffer *tx_iobuf[NUM_TX_DESC];
+	struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+	struct e1000_tx_desc *tx_base;
+	struct e1000_rx_desc *rx_base;
+
+	uint32_t tx_ring_size;
+	uint32_t rx_ring_size;
+
+	uint32_t tx_head;
+	uint32_t tx_tail;
+	uint32_t tx_fill_ctr;
+
+	uint32_t rx_curr;
+
+	uint32_t ioaddr;
+	uint32_t irqno;
+};
+
+#define E1000_FLAG_HAS_SMBUS                (1 << 0)
+#define E1000_FLAG_HAS_INTR_MODERATION      (1 << 4)
+#define E1000_FLAG_BAD_TX_CARRIER_STATS_FD  (1 << 6)
+#define E1000_FLAG_QUAD_PORT_A              (1 << 8)
+#define E1000_FLAG_SMART_POWER_DOWN         (1 << 9)
+
+extern char e1000_driver_name[];
+extern const char e1000_driver_version[];
+
+extern void e1000_power_up_phy(struct e1000_hw *hw);
+
+extern void e1000_set_ethtool_ops(struct net_device *netdev);
+extern void e1000_check_options(struct e1000_adapter *adapter);
+
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
+extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_update_stats(struct e1000_adapter *adapter);
+
+#endif /* _E1000_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82540.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82540.c
new file mode 100644
index 0000000..41f3f97
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82540.c
@@ -0,0 +1,754 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82540EM Gigabit Ethernet Controller
+ * 82540EP Gigabit Ethernet Controller
+ * 82545EM Gigabit Ethernet Controller (Copper)
+ * 82545EM Gigabit Ethernet Controller (Fiber)
+ * 82545GM Gigabit Ethernet Controller
+ * 82546EB Gigabit Ethernet Controller (Copper)
+ * 82546EB Gigabit Ethernet Controller (Fiber)
+ * 82546GB Gigabit Ethernet Controller
+ */
+
+#include "e1000_api.h"
+
+static s32  e1000_init_phy_params_82540(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_82540(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_82540(struct e1000_hw *hw);
+static s32  e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw);
+static s32  e1000_init_hw_82540(struct e1000_hw *hw);
+static s32  e1000_reset_hw_82540(struct e1000_hw *hw);
+static s32  e1000_set_phy_mode_82540(struct e1000_hw *hw);
+static s32  e1000_set_vco_speed_82540(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_82540(struct e1000_hw *hw);
+static s32  e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw);
+static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw);
+static s32  e1000_read_mac_addr_82540(struct e1000_hw *hw);
+
+/**
+ * e1000_init_phy_params_82540 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_phy_params_82540(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	phy->addr                      = 1;
+	phy->autoneg_mask              = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us            = 10000;
+	phy->type                      = e1000_phy_m88;
+
+	/* Function Pointers */
+	phy->ops.check_polarity        = e1000_check_polarity_m88;
+	phy->ops.commit                = e1000_phy_sw_reset_generic;
+#if 0
+	phy->ops.force_speed_duplex    = e1000_phy_force_speed_duplex_m88;
+#endif
+#if 0
+	phy->ops.get_cable_length      = e1000_get_cable_length_m88;
+#endif
+	phy->ops.get_cfg_done          = e1000_get_cfg_done_generic;
+	phy->ops.read_reg              = e1000_read_phy_reg_m88;
+	phy->ops.reset                 = e1000_phy_hw_reset_generic;
+	phy->ops.write_reg             = e1000_write_phy_reg_m88;
+	phy->ops.get_info              = e1000_get_phy_info_m88;
+	phy->ops.power_up              = e1000_power_up_phy_copper;
+	phy->ops.power_down            = e1000_power_down_phy_copper_82540;
+
+	ret_val = e1000_get_phy_id(hw);
+	if (ret_val)
+		goto out;
+
+	/* Verify phy id */
+	switch (hw->mac.type) {
+	case e1000_82540:
+	case e1000_82545:
+	case e1000_82545_rev_3:
+	case e1000_82546:
+	case e1000_82546_rev_3:
+		if (phy->id == M88E1011_I_PHY_ID)
+			break;
+		/* Fall Through */
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_82540 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	DEBUGFUNC("e1000_init_nvm_params_82540");
+
+	nvm->type               = e1000_nvm_eeprom_microwire;
+	nvm->delay_usec         = 50;
+	nvm->opcode_bits        = 3;
+	switch (nvm->override) {
+	case e1000_nvm_override_microwire_large:
+		nvm->address_bits       = 8;
+		nvm->word_size          = 256;
+		break;
+	case e1000_nvm_override_microwire_small:
+		nvm->address_bits       = 6;
+		nvm->word_size          = 64;
+		break;
+	default:
+		nvm->address_bits       = eecd & E1000_EECD_SIZE ? 8 : 6;
+		nvm->word_size          = eecd & E1000_EECD_SIZE ? 256 : 64;
+		break;
+	}
+
+	/* Function Pointers */
+	nvm->ops.acquire            = e1000_acquire_nvm_generic;
+	nvm->ops.read               = e1000_read_nvm_microwire;
+	nvm->ops.release            = e1000_release_nvm_generic;
+	nvm->ops.update             = e1000_update_nvm_checksum_generic;
+	nvm->ops.valid_led_default  = e1000_valid_led_default_generic;
+	nvm->ops.validate           = e1000_validate_nvm_checksum_generic;
+	nvm->ops.write              = e1000_write_nvm_microwire;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_mac_params_82540 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_mac_params_82540(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_mac_params_82540");
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82545EM_FIBER:
+	case E1000_DEV_ID_82545GM_FIBER:
+	case E1000_DEV_ID_82546EB_FIBER:
+	case E1000_DEV_ID_82546GB_FIBER:
+		hw->phy.media_type = e1000_media_type_fiber;
+		break;
+	case E1000_DEV_ID_82545GM_SERDES:
+	case E1000_DEV_ID_82546GB_SERDES:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_82540;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_82540;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_generic;
+	/* physical interface setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_setup_copper_link_82540
+	                : e1000_setup_fiber_serdes_link_82540;
+	/* check for link */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+		break;
+	case e1000_media_type_fiber:
+		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+		break;
+	case e1000_media_type_internal_serdes:
+		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+		break;
+	default:
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+	/* link info */
+	mac->ops.get_link_up_info =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_get_speed_and_duplex_copper_generic
+	                : e1000_get_speed_and_duplex_fiber_serdes_generic;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_82540;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
+	/* setup LED */
+	mac->ops.setup_led = e1000_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000_cleanup_led_generic;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_generic;
+	mac->ops.led_off = e1000_led_off_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540;
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_init_function_pointers_82540 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82540(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_82540");
+
+	hw->mac.ops.init_params = e1000_init_mac_params_82540;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_82540;
+	hw->phy.ops.init_params = e1000_init_phy_params_82540;
+}
+
+/**
+ *  e1000_reset_hw_82540 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 e1000_reset_hw_82540(struct e1000_hw *hw)
+{
+	u32 ctrl, manc;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_reset_hw_82540");
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	/*
+	 * Delay to allow any outstanding PCI transactions to complete
+	 * before resetting the device.
+	 */
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n");
+	switch (hw->mac.type) {
+	case e1000_82545_rev_3:
+	case e1000_82546_rev_3:
+		E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST);
+		break;
+	default:
+		/*
+		 * These controllers can't ack the 64-bit write when
+		 * issuing the reset, so we use IO-mapping as a
+		 * workaround to issue the reset.
+		 */
+		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+		break;
+	}
+
+	/* Wait for EEPROM reload */
+	msec_delay(5);
+
+	/* Disable HW ARPs on ASF enabled adapters */
+	manc = E1000_READ_REG(hw, E1000_MANC);
+	manc &= ~E1000_MANC_ARP_EN;
+	E1000_WRITE_REG(hw, E1000_MANC, manc);
+
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_READ_REG(hw, E1000_ICR);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82540 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82540(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txdctl, ctrl_ext;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_hw_82540");
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	if (mac->type < e1000_82545_rev_3)
+		E1000_WRITE_REG(hw, E1000_VET, 0);
+
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+		/*
+		 * Avoid back to back register writes by adding the register
+		 * read (flush).  This is to protect against some strange
+		 * bridge configurations that may issue Memory Write Block
+		 * (MWB) to our register space.  The *_rev_3 hardware at
+		 * least doesn't respond correctly to every other dword in an
+		 * MWB to our register space.
+		 */
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	if (mac->type < e1000_82545_rev_3)
+		e1000_pcix_mmrbc_workaround_generic(hw);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+	         E1000_TXDCTL_FULL_TX_DESC_WB;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82540(hw);
+
+	if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) ||
+	    (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) {
+		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		/*
+		 * Relaxed ordering must be disabled to avoid a parity
+		 * error crash in a PCI slot.
+		 */
+		ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_82540 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_setup_copper_link_82540");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	ret_val = e1000_set_phy_mode_82540(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.type == e1000_82545_rev_3 ||
+	    hw->mac.type == e1000_82546_rev_3) {
+		ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data);
+		if (ret_val)
+			goto out;
+		data |= 0x00000008;
+		ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000_copper_link_setup_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the output amplitude to the value in the EEPROM and adjust the VCO
+ *  speed to improve Bit Error Rate (BER) performance.  Configures collision
+ *  distance and flow control for fiber and serdes links.  Upon successful
+ *  setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_fiber_serdes_link_82540");
+
+	switch (mac->type) {
+	case e1000_82545_rev_3:
+	case e1000_82546_rev_3:
+		if (hw->phy.media_type == e1000_media_type_internal_serdes) {
+			/*
+			 * If we're on serdes media, adjust the output
+			 * amplitude to value set in the EEPROM.
+			 */
+			ret_val = e1000_adjust_serdes_amplitude_82540(hw);
+			if (ret_val)
+				goto out;
+		}
+		/* Adjust VCO speed to improve BER performance */
+		ret_val = e1000_set_vco_speed_82540(hw);
+		if (ret_val)
+			goto out;
+	default:
+		break;
+	}
+
+	ret_val = e1000_setup_fiber_serdes_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Adjust the SERDES output amplitude based on the EEPROM settings.
+ **/
+static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_adjust_serdes_amplitude_82540");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data);
+	if (ret_val)
+		goto out;
+
+	if (nvm_data != NVM_RESERVED_WORD) {
+		/* Adjust serdes output amplitude only. */
+		nvm_data &= NVM_SERDES_AMPLITUDE_MASK;
+		ret_val = hw->phy.ops.write_reg(hw,
+		                             M88E1000_PHY_EXT_CTRL,
+		                             nvm_data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_vco_speed_82540 - Set VCO speed for better performance
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the VCO speed to improve Bit Error Rate (BER) performance.
+ **/
+static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw)
+{
+	s32  ret_val = E1000_SUCCESS;
+	u16 default_page = 0;
+	u16 phy_data;
+
+	DEBUGFUNC("e1000_set_vco_speed_82540");
+
+	/* Set PHY register 30, page 5, bit 8 to 0 */
+
+	ret_val = hw->phy.ops.read_reg(hw,
+	                            M88E1000_PHY_PAGE_SELECT,
+	                            &default_page);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/* Set PHY register 30, page 4, bit 11 to 1 */
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PHY_VCO_REG_BIT11;
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
+	                              default_page);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_phy_mode_82540 - Set PHY to class A mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the PHY to class A mode and assumes the following operations will
+ *  follow to enable the new class mode:
+ *    1.  Do a PHY soft reset.
+ *    2.  Restart auto-negotiation or force link.
+ **/
+static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_set_phy_mode_82540");
+
+	if (hw->mac.type != e1000_82545_rev_3)
+		goto out;
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data);
+	if (ret_val) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+	if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) {
+		ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
+		                              0x000B);
+		if (ret_val) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+		ret_val = hw->phy.ops.write_reg(hw,
+		                              M88E1000_PHY_GEN_CONTROL,
+		                              0x8104);
+		if (ret_val) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		phy->reset_disable = false;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw)
+{
+	/* If the management interface is not enabled, then power down */
+	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
+		e1000_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_clear_hw_cntrs_82540");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+#if 0
+	E1000_READ_REG(hw, E1000_PRC64);
+	E1000_READ_REG(hw, E1000_PRC127);
+	E1000_READ_REG(hw, E1000_PRC255);
+	E1000_READ_REG(hw, E1000_PRC511);
+	E1000_READ_REG(hw, E1000_PRC1023);
+	E1000_READ_REG(hw, E1000_PRC1522);
+	E1000_READ_REG(hw, E1000_PTC64);
+	E1000_READ_REG(hw, E1000_PTC127);
+	E1000_READ_REG(hw, E1000_PTC255);
+	E1000_READ_REG(hw, E1000_PTC511);
+	E1000_READ_REG(hw, E1000_PTC1023);
+	E1000_READ_REG(hw, E1000_PTC1522);
+
+	E1000_READ_REG(hw, E1000_ALGNERRC);
+	E1000_READ_REG(hw, E1000_RXERRC);
+	E1000_READ_REG(hw, E1000_TNCRS);
+	E1000_READ_REG(hw, E1000_CEXTERR);
+	E1000_READ_REG(hw, E1000_TSCTC);
+	E1000_READ_REG(hw, E1000_TSCTFC);
+
+	E1000_READ_REG(hw, E1000_MGTPRC);
+	E1000_READ_REG(hw, E1000_MGTPDC);
+	E1000_READ_REG(hw, E1000_MGTPTC);
+#endif
+}
+
+/**
+ *  e1000_read_mac_addr_82540 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ *
+ *  This version is being used over generic because of customer issues
+ *  with VmWare and Virtual Box when using generic. It seems in
+ *  the emulated 82545, RAR[0] does NOT have a valid address after a
+ *  reset, this older method works and using this breaks nothing for
+ *  these legacy adapters.
+ **/
+s32 e1000_read_mac_addr_82540(struct e1000_hw *hw)
+{
+	s32  ret_val = E1000_SUCCESS;
+	u16 offset, nvm_data, i;
+
+	DEBUGFUNC("e1000_read_mac_addr");
+
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = i >> 1;
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	/* Flip last bit of mac address if we're on second port */
+	if (hw->bus.func == E1000_FUNC_1)
+		hw->mac.perm_addr[5] ^= 1;
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+out:
+	return ret_val;
+}
+
+static struct pci_device_id e1000_82540_nics[] = {
+     PCI_ROM(0x8086, 0x100E, "E1000_DEV_ID_82540EM", "E1000_DEV_ID_82540EM", e1000_82540),
+     PCI_ROM(0x8086, 0x1015, "E1000_DEV_ID_82540EM_LOM", "E1000_DEV_ID_82540EM_LOM", e1000_82540),
+     PCI_ROM(0x8086, 0x1016, "E1000_DEV_ID_82540EP_LOM", "E1000_DEV_ID_82540EP_LOM", e1000_82540),
+     PCI_ROM(0x8086, 0x1017, "E1000_DEV_ID_82540EP", "E1000_DEV_ID_82540EP", e1000_82540),
+     PCI_ROM(0x8086, 0x101E, "E1000_DEV_ID_82540EP_LP", "E1000_DEV_ID_82540EP_LP", e1000_82540),
+     PCI_ROM(0x8086, 0x100F, "E1000_DEV_ID_82545EM_COPPER", "E1000_DEV_ID_82545EM_COPPER", e1000_82545),
+     PCI_ROM(0x8086, 0x1011, "E1000_DEV_ID_82545EM_FIBER", "E1000_DEV_ID_82545EM_FIBER", e1000_82545),
+     PCI_ROM(0x8086, 0x1026, "E1000_DEV_ID_82545GM_COPPER", "E1000_DEV_ID_82545GM_COPPER", e1000_82545_rev_3),
+     PCI_ROM(0x8086, 0x1027, "E1000_DEV_ID_82545GM_FIBER", "E1000_DEV_ID_82545GM_FIBER", e1000_82545_rev_3),
+     PCI_ROM(0x8086, 0x1028, "E1000_DEV_ID_82545GM_SERDES", "E1000_DEV_ID_82545GM_SERDES", e1000_82545_rev_3),
+     PCI_ROM(0x8086, 0x1010, "E1000_DEV_ID_82546EB_COPPER", "E1000_DEV_ID_82546EB_COPPER", e1000_82546),
+     PCI_ROM(0x8086, 0x1012, "E1000_DEV_ID_82546EB_FIBER", "E1000_DEV_ID_82546EB_FIBER", e1000_82546),
+     PCI_ROM(0x8086, 0x101D, "E1000_DEV_ID_82546EB_QUAD_COPPER", "E1000_DEV_ID_82546EB_QUAD_COPPER", e1000_82546),
+     PCI_ROM(0x8086, 0x1079, "E1000_DEV_ID_82546GB_COPPER", "E1000_DEV_ID_82546GB_COPPER", e1000_82546_rev_3),
+     PCI_ROM(0x8086, 0x107A, "E1000_DEV_ID_82546GB_FIBER", "E1000_DEV_ID_82546GB_FIBER", e1000_82546_rev_3),
+     PCI_ROM(0x8086, 0x107B, "E1000_DEV_ID_82546GB_SERDES", "E1000_DEV_ID_82546GB_SERDES", e1000_82546_rev_3),
+     PCI_ROM(0x8086, 0x108A, "E1000_DEV_ID_82546GB_PCIE", "E1000_DEV_ID_82546GB_PCIE", e1000_82546_rev_3),
+     PCI_ROM(0x8086, 0x1099, "E1000_DEV_ID_82546GB_QUAD_COPPER", "E1000_DEV_ID_82546GB_QUAD_COPPER", e1000_82546_rev_3),
+     PCI_ROM(0x8086, 0x10B5, "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", e1000_82546_rev_3),
+};
+
+struct pci_driver e1000_82540_driver __pci_driver = {
+	.ids = e1000_82540_nics,
+	.id_count = (sizeof (e1000_82540_nics) / sizeof (e1000_82540_nics[0])),
+	.probe = e1000_probe,
+	.remove = e1000_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.c
new file mode 100644
index 0000000..2d1aecc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.c
@@ -0,0 +1,1314 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82541EI Gigabit Ethernet Controller
+ * 82541ER Gigabit Ethernet Controller
+ * 82541GI Gigabit Ethernet Controller
+ * 82541PI Gigabit Ethernet Controller
+ * 82547EI Gigabit Ethernet Controller
+ * 82547GI Gigabit Ethernet Controller
+ */
+
+#include "e1000_api.h"
+
+static s32  e1000_init_phy_params_82541(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_82541(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_82541(struct e1000_hw *hw);
+static s32  e1000_reset_hw_82541(struct e1000_hw *hw);
+static s32  e1000_init_hw_82541(struct e1000_hw *hw);
+static s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
+                                         u16 *duplex);
+static s32  e1000_phy_hw_reset_82541(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_82541(struct e1000_hw *hw);
+static s32  e1000_check_for_link_82541(struct e1000_hw *hw);
+#if 0
+static s32  e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
+#endif
+static s32  e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
+                                          bool active);
+static s32  e1000_setup_led_82541(struct e1000_hw *hw);
+static s32  e1000_cleanup_led_82541(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
+#if 0
+static s32  e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
+                                                     bool link_up);
+#endif
+static s32  e1000_phy_init_script_82541(struct e1000_hw *hw);
+static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
+
+#if 0
+static const u16 e1000_igp_cable_length_table[] =
+    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_igp_cable_length_table) / \
+                 sizeof(e1000_igp_cable_length_table[0]))
+#endif
+/**
+ *  e1000_init_phy_params_82541 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_phy_params_82541(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_82541");
+
+	phy->addr                      = 1;
+	phy->autoneg_mask              = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us            = 10000;
+	phy->type                      = e1000_phy_igp;
+
+	/* Function Pointers */
+	phy->ops.check_polarity        = e1000_check_polarity_igp;
+#if 0
+	phy->ops.force_speed_duplex    = e1000_phy_force_speed_duplex_igp;
+#endif
+#if 0
+	phy->ops.get_cable_length      = e1000_get_cable_length_igp_82541;
+#endif
+	phy->ops.get_cfg_done          = e1000_get_cfg_done_generic;
+	phy->ops.get_info              = e1000_get_phy_info_igp;
+	phy->ops.read_reg              = e1000_read_phy_reg_igp;
+	phy->ops.reset                 = e1000_phy_hw_reset_82541;
+	phy->ops.set_d3_lplu_state     = e1000_set_d3_lplu_state_82541;
+	phy->ops.write_reg             = e1000_write_phy_reg_igp;
+	phy->ops.power_up              = e1000_power_up_phy_copper;
+	phy->ops.power_down            = e1000_power_down_phy_copper_82541;
+
+	ret_val = e1000_get_phy_id(hw);
+	if (ret_val)
+		goto out;
+
+	/* Verify phy id */
+	if (phy->id != IGP01E1000_I_PHY_ID) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_82541 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw)
+{
+	struct   e1000_nvm_info *nvm = &hw->nvm;
+	s32  ret_val = E1000_SUCCESS;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u16 size;
+
+	DEBUGFUNC("e1000_init_nvm_params_82541");
+
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->type = e1000_nvm_eeprom_spi;
+		eecd |= E1000_EECD_ADDR_BITS;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->type = e1000_nvm_eeprom_spi;
+		eecd &= ~E1000_EECD_ADDR_BITS;
+		break;
+	case e1000_nvm_override_microwire_large:
+		nvm->type = e1000_nvm_eeprom_microwire;
+		eecd |= E1000_EECD_SIZE;
+		break;
+	case e1000_nvm_override_microwire_small:
+		nvm->type = e1000_nvm_eeprom_microwire;
+		eecd &= ~E1000_EECD_SIZE;
+		break;
+	default:
+		nvm->type = eecd & E1000_EECD_TYPE
+		            ? e1000_nvm_eeprom_spi
+		            : e1000_nvm_eeprom_microwire;
+		break;
+	}
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
+		                          ? 16 : 8;
+		nvm->delay_usec         = 1;
+		nvm->opcode_bits        = 8;
+		nvm->page_size          = (eecd & E1000_EECD_ADDR_BITS)
+		                          ? 32 : 8;
+
+		/* Function Pointers */
+		nvm->ops.acquire        = e1000_acquire_nvm_generic;
+		nvm->ops.read           = e1000_read_nvm_spi;
+		nvm->ops.release        = e1000_release_nvm_generic;
+		nvm->ops.update         = e1000_update_nvm_checksum_generic;
+		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
+		nvm->ops.write          = e1000_write_nvm_spi;
+
+		/*
+		 * nvm->word_size must be discovered after the pointers
+		 * are set so we can verify the size from the nvm image
+		 * itself.  Temporarily set it to a dummy value so the
+		 * read will work.
+		 */
+		nvm->word_size = 64;
+		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
+		if (ret_val)
+			goto out;
+		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
+		/*
+		 * if size != 0, it can be added to a constant and become
+		 * the left-shift value to set the word_size.  Otherwise,
+		 * word_size stays at 64.
+		 */
+		if (size) {
+			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
+			nvm->word_size = 1 << size;
+		}
+	} else {
+		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
+		                          ? 8 : 6;
+		nvm->delay_usec         = 50;
+		nvm->opcode_bits        = 3;
+		nvm->word_size          = (eecd & E1000_EECD_ADDR_BITS)
+		                          ? 256 : 64;
+
+		/* Function Pointers */
+		nvm->ops.acquire        = e1000_acquire_nvm_generic;
+		nvm->ops.read           = e1000_read_nvm_microwire;
+		nvm->ops.release        = e1000_release_nvm_generic;
+		nvm->ops.update         = e1000_update_nvm_checksum_generic;
+		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
+		nvm->ops.write          = e1000_write_nvm_microwire;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_mac_params_82541 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_mac_params_82541(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_init_mac_params_82541");
+
+	/* Set media type */
+	hw->phy.media_type = e1000_media_type_copper;
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+
+	/* Function Pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_82541;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_82541;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_generic;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
+	/* check for link */
+	mac->ops.check_for_link = e1000_check_for_link_82541;
+	/* link info */
+	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
+	/* setup LED */
+	mac->ops.setup_led = e1000_setup_led_82541;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000_cleanup_led_82541;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_generic;
+	mac->ops.led_off = e1000_led_off_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_function_pointers_82541 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82541(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_82541");
+
+	hw->mac.ops.init_params = e1000_init_mac_params_82541;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
+	hw->phy.ops.init_params = e1000_init_phy_params_82541;
+}
+
+/**
+ *  e1000_reset_hw_82541 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
+{
+	u32 ledctl, ctrl, manc;
+
+	DEBUGFUNC("e1000_reset_hw_82541");
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	/*
+	 * Delay to allow any outstanding PCI transactions to complete
+	 * before resetting the device.
+	 */
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Must reset the Phy before resetting the MAC */
+	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
+		msec_delay(5);
+	}
+
+	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
+	switch (hw->mac.type) {
+	case e1000_82541:
+	case e1000_82541_rev_2:
+		/*
+		 * These controllers can't ack the 64-bit write when
+		 * issuing the reset, so we use IO-mapping as a
+		 * workaround to issue the reset.
+		 */
+		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+		break;
+	default:
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+		break;
+	}
+
+	/* Wait for NVM reload */
+	msec_delay(20);
+
+	/* Disable HW ARPs on ASF enabled adapters */
+	manc = E1000_READ_REG(hw, E1000_MANC);
+	manc &= ~E1000_MANC_ARP_EN;
+	E1000_WRITE_REG(hw, E1000_MANC, manc);
+
+	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
+		e1000_phy_init_script_82541(hw);
+
+		/* Configure activity LED after Phy reset */
+		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+		ledctl &= IGP_ACTIVITY_LED_MASK;
+		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+	}
+
+	/* Once again, mask the interrupts */
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
+
+	/* Clear any pending interrupt events. */
+	E1000_READ_REG(hw, E1000_ICR);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_hw_82541 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82541(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	u32 i, txdctl;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_init_hw_82541");
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Storing the Speed Power Down  value for later use */
+	ret_val = hw->phy.ops.read_reg(hw,
+	                               IGP01E1000_GMII_FIFO,
+	                               &dev_spec->spd_default);
+	if (ret_val)
+		goto out;
+
+	/* Disabling VLAN filtering */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+		/*
+		 * Avoid back to back register writes by adding the register
+		 * read (flush).  This is to protect against some strange
+		 * bridge configurations that may issue Memory Write Block
+		 * (MWB) to our register space.
+		 */
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+	         E1000_TXDCTL_FULL_TX_DESC_WB;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82541(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_get_link_up_info_82541 - Report speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to speed buffer
+ * @duplex: pointer to duplex buffer
+ *
+ * Retrieve the current speed and duplex configuration.
+ **/
+static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
+                                        u16 *duplex)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_get_link_up_info_82541");
+
+	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
+	if (ret_val)
+		goto out;
+
+	if (!phy->speed_downgraded)
+		goto out;
+
+	/*
+	 * IGP01 PHY may advertise full duplex operation after speed
+	 * downgrade even if it is operating at half duplex.
+	 * Here we set the duplex settings to match the duplex in the
+	 * link partner's capabilities.
+	 */
+	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
+	if (ret_val)
+		goto out;
+
+	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
+		*duplex = HALF_DUPLEX;
+	} else {
+		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
+		if (ret_val)
+			goto out;
+
+		if (*speed == SPEED_100) {
+			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
+				*duplex = HALF_DUPLEX;
+		} else if (*speed == SPEED_10) {
+			if (!(data & NWAY_LPAR_10T_FD_CAPS))
+				*duplex = HALF_DUPLEX;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_82541 - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and release the semaphore (if necessary).
+ **/
+static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u32 ledctl;
+
+	DEBUGFUNC("e1000_phy_hw_reset_82541");
+
+	ret_val = e1000_phy_hw_reset_generic(hw);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_init_script_82541(hw);
+
+	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
+		/* Configure activity LED after PHY reset */
+		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+		ledctl &= IGP_ACTIVITY_LED_MASK;
+		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_82541 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	s32  ret_val;
+	u32 ctrl, ledctl;
+
+	DEBUGFUNC("e1000_setup_copper_link_82541");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	hw->phy.reset_disable = false;
+
+	/* Earlier revs of the IGP phy require us to force MDI. */
+	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
+		dev_spec->dsp_config = e1000_dsp_config_disabled;
+		phy->mdix = 1;
+	} else {
+		dev_spec->dsp_config = e1000_dsp_config_enabled;
+	}
+
+	ret_val = e1000_copper_link_setup_igp(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.autoneg) {
+		if (dev_spec->ffe_config == e1000_ffe_config_active)
+			dev_spec->ffe_config = e1000_ffe_config_enabled;
+	}
+
+	/* Configure activity LED after Phy reset */
+	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+	ledctl &= IGP_ACTIVITY_LED_MASK;
+	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+
+	ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_link_82541 - Check/Store link connection
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks the link condition of the adapter and stores the
+ *  results in the hw->mac structure.
+ **/
+static s32 e1000_check_for_link_82541(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_check_for_link_82541");
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		ret_val = -E1000_ERR_CONFIG;
+#if 0
+		ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
+#endif
+		goto out; /* No link detected */
+	}
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+#if 0
+	ret_val = e1000_config_dsp_after_link_change_82541(hw, true);
+#endif
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000_config_collision_dist_generic(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000_config_fc_after_link_up_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error configuring flow control\n");
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000_config_dsp_after_link_change_82541 - Config DSP after link
+ *  @hw: pointer to the HW structure
+ *  @link_up: boolean flag for link up status
+ *
+ *  Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
+ *  at any other case.
+ *
+ *  82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
+ *  gigabit link is achieved to improve link quality.
+ **/
+static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
+                                                    bool link_up)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	s32 ret_val;
+	u32 idle_errs = 0;
+	u16 phy_data, phy_saved_data, speed, duplex, i;
+	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+	                                           {IGP01E1000_PHY_AGC_PARAM_A,
+	                                            IGP01E1000_PHY_AGC_PARAM_B,
+	                                            IGP01E1000_PHY_AGC_PARAM_C,
+	                                            IGP01E1000_PHY_AGC_PARAM_D};
+
+	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
+
+	if (link_up) {
+		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			DEBUGOUT("Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (speed != SPEED_1000) {
+			ret_val = E1000_SUCCESS;
+			goto out;
+		}
+
+#if 0
+		ret_val = phy->ops.get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+
+		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
+		    phy->min_cable_length >= 50) {
+
+			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+				ret_val = phy->ops.read_reg(hw,
+				                            dsp_reg_array[i],
+				                            &phy_data);
+				if (ret_val)
+					goto out;
+
+				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+				ret_val = phy->ops.write_reg(hw,
+				                             dsp_reg_array[i],
+				                             phy_data);
+				if (ret_val)
+					goto out;
+			}
+			dev_spec->dsp_config = e1000_dsp_config_activated;
+		}
+
+		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
+		    (phy->min_cable_length >= 50)) {
+			ret_val = E1000_SUCCESS;
+			goto out;
+		}
+
+		/* clear previous idle error counts */
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			goto out;
+
+		for (i = 0; i < ffe_idle_err_timeout; i++) {
+			usec_delay(1000);
+			ret_val = phy->ops.read_reg(hw,
+			                            PHY_1000T_STATUS,
+			                            &phy_data);
+			if (ret_val)
+				goto out;
+
+			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+				dev_spec->ffe_config = e1000_ffe_config_active;
+
+				ret_val = phy->ops.write_reg(hw,
+				                  IGP01E1000_PHY_DSP_FFE,
+				                  IGP01E1000_PHY_DSP_FFE_CM_CP);
+				if (ret_val)
+					goto out;
+				break;
+			}
+
+			if (idle_errs)
+				ffe_idle_err_timeout =
+				                 FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+		}
+	} else {
+		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
+			/*
+			 * Save off the current value of register 0x2F5B
+			 * to be restored at the end of the routines.
+			 */
+			ret_val = phy->ops.read_reg(hw,
+			                            0x2F5B,
+			                            &phy_saved_data);
+			if (ret_val)
+				goto out;
+
+			/* Disable the PHY transmitter */
+			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
+			if (ret_val)
+				goto out;
+
+			msec_delay_irq(20);
+
+			ret_val = phy->ops.write_reg(hw,
+			                             0x0000,
+			                             IGP01E1000_IEEE_FORCE_GIG);
+			if (ret_val)
+				goto out;
+			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+				ret_val = phy->ops.read_reg(hw,
+				                            dsp_reg_array[i],
+				                            &phy_data);
+				if (ret_val)
+					goto out;
+
+				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
+
+				ret_val = phy->ops.write_reg(hw,
+				                             dsp_reg_array[i],
+				                             phy_data);
+				if (ret_val)
+					goto out;
+			}
+
+			ret_val = phy->ops.write_reg(hw,
+			                       0x0000,
+			                       IGP01E1000_IEEE_RESTART_AUTONEG);
+			if (ret_val)
+				goto out;
+
+			msec_delay_irq(20);
+
+			/* Now enable the transmitter */
+			ret_val = phy->ops.write_reg(hw,
+			                             0x2F5B,
+			                             phy_saved_data);
+			if (ret_val)
+				goto out;
+
+			dev_spec->dsp_config = e1000_dsp_config_enabled;
+		}
+
+		if (dev_spec->ffe_config != e1000_ffe_config_active) {
+			ret_val = E1000_SUCCESS;
+			goto out;
+		}
+
+		/*
+		 * Save off the current value of register 0x2F5B
+		 * to be restored at the end of the routines.
+		 */
+		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
+		if (ret_val)
+			goto out;
+
+		/* Disable the PHY transmitter */
+		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
+		if (ret_val)
+			goto out;
+
+		msec_delay_irq(20);
+
+		ret_val = phy->ops.write_reg(hw,
+		                             0x0000,
+		                             IGP01E1000_IEEE_FORCE_GIG);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.write_reg(hw,
+		                             IGP01E1000_PHY_DSP_FFE,
+		                             IGP01E1000_PHY_DSP_FFE_DEFAULT);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.write_reg(hw,
+		                             0x0000,
+		                             IGP01E1000_IEEE_RESTART_AUTONEG);
+		if (ret_val)
+			goto out;
+
+		msec_delay_irq(20);
+
+		/* Now enable the transmitter */
+		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
+
+		if (ret_val)
+			goto out;
+
+		dev_spec->ffe_config = e1000_ffe_config_enabled;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which represent the
+ *  combination of coarse and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, data;
+	u16 cur_agc_value, agc_value = 0;
+	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
+	                                                 {IGP01E1000_PHY_AGC_A,
+	                                                  IGP01E1000_PHY_AGC_B,
+	                                                  IGP01E1000_PHY_AGC_C,
+	                                                  IGP01E1000_PHY_AGC_D};
+
+	DEBUGFUNC("e1000_get_cable_length_igp_82541");
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
+		if (ret_val)
+			goto out;
+
+		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+		/* Bounds checking */
+		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+		    (cur_agc_value == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		agc_value += cur_agc_value;
+
+		if (min_agc_value > cur_agc_value)
+			min_agc_value = cur_agc_value;
+	}
+
+	/* Remove the minimal AGC result for length < 50m */
+	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
+		agc_value -= min_agc_value;
+		/* Average the three remaining channels for the length. */
+		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
+	} else {
+		/* Average the channels for the length. */
+		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
+	}
+
+	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
+	                         IGP01E1000_AGC_RANGE)
+	                        ? (e1000_igp_cable_length_table[agc_value] -
+	                           IGP01E1000_AGC_RANGE)
+	                        : 0;
+	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
+	                        IGP01E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d3_lplu_state_82541");
+
+	switch (hw->mac.type) {
+	case e1000_82541_rev_2:
+	case e1000_82547_rev_2:
+		break;
+	default:
+		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
+		goto out;
+		break;
+	}
+
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP01E1000_GMII_FLEX_SPD;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP01E1000_GMII_FLEX_SPD;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw,
+		                            IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_led_82541 - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+static s32 e1000_setup_led_82541(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_setup_led_82541");
+
+	ret_val = hw->phy.ops.read_reg(hw,
+	                               IGP01E1000_GMII_FIFO,
+	                               &dev_spec->spd_default);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw,
+	                                IGP01E1000_GMII_FIFO,
+	                                (u16)(dev_spec->spd_default &
+	                                        ~IGP01E1000_GMII_SPD));
+	if (ret_val)
+		goto out;
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+
+out:
+	return ret_val;
+#endif
+        return 0;
+}
+
+/**
+ *  e1000_cleanup_led_82541 - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+static s32 e1000_cleanup_led_82541(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_cleanup_led_82541");
+
+	ret_val = hw->phy.ops.write_reg(hw,
+	                                IGP01E1000_GMII_FIFO,
+	                                dev_spec->spd_default);
+	if (ret_val)
+		goto out;
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+
+out:
+	return ret_val;
+#endif
+        return 0;
+}
+
+/**
+ *  e1000_phy_init_script_82541 - Initialize GbE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the IGP PHY.
+ **/
+static s32 e1000_phy_init_script_82541(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
+	u32 ret_val;
+	u16 phy_saved_data;
+
+	DEBUGFUNC("e1000_phy_init_script_82541");
+
+	if (!dev_spec->phy_init_script) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Delay after phy reset to enable NVM configuration to load */
+	msec_delay(20);
+
+	/*
+	 * Save off the current value of register 0x2F5B to be restored at
+	 * the end of this routine.
+	 */
+	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
+
+	/* Disabled the PHY transmitter */
+	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
+
+	msec_delay(20);
+
+	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+
+	msec_delay(5);
+
+	switch (hw->mac.type) {
+	case e1000_82541:
+	case e1000_82547:
+		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
+
+		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
+
+		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
+
+		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
+
+		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
+
+		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
+
+		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
+
+		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
+
+		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
+		break;
+	case e1000_82541_rev_2:
+	case e1000_82547_rev_2:
+		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
+		break;
+	default:
+		break;
+	}
+
+	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
+
+	msec_delay(20);
+
+	/* Now enable the transmitter */
+	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
+
+	if (hw->mac.type == e1000_82547) {
+		u16 fused, fine, coarse;
+
+		/* Move to analog registers page */
+		hw->phy.ops.read_reg(hw,
+		                  IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
+		                  &fused);
+
+		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+			hw->phy.ops.read_reg(hw,
+			                  IGP01E1000_ANALOG_FUSE_STATUS,
+			                  &fused);
+
+			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
+
+			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
+				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+			} else if (coarse ==
+			           IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
+
+			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+			        (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+			        (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+			hw->phy.ops.write_reg(hw,
+			                   IGP01E1000_ANALOG_FUSE_CONTROL,
+			                   fused);
+			hw->phy.ops.write_reg(hw,
+			              IGP01E1000_ANALOG_FUSE_BYPASS,
+			              IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
+{
+	/* If the management interface is not enabled, then power down */
+	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
+		e1000_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_clear_hw_cntrs_82541");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+#if 0
+	E1000_READ_REG(hw, E1000_PRC64);
+	E1000_READ_REG(hw, E1000_PRC127);
+	E1000_READ_REG(hw, E1000_PRC255);
+	E1000_READ_REG(hw, E1000_PRC511);
+	E1000_READ_REG(hw, E1000_PRC1023);
+	E1000_READ_REG(hw, E1000_PRC1522);
+	E1000_READ_REG(hw, E1000_PTC64);
+	E1000_READ_REG(hw, E1000_PTC127);
+	E1000_READ_REG(hw, E1000_PTC255);
+	E1000_READ_REG(hw, E1000_PTC511);
+	E1000_READ_REG(hw, E1000_PTC1023);
+	E1000_READ_REG(hw, E1000_PTC1522);
+
+	E1000_READ_REG(hw, E1000_ALGNERRC);
+	E1000_READ_REG(hw, E1000_RXERRC);
+	E1000_READ_REG(hw, E1000_TNCRS);
+	E1000_READ_REG(hw, E1000_CEXTERR);
+	E1000_READ_REG(hw, E1000_TSCTC);
+	E1000_READ_REG(hw, E1000_TSCTFC);
+
+	E1000_READ_REG(hw, E1000_MGTPRC);
+	E1000_READ_REG(hw, E1000_MGTPDC);
+	E1000_READ_REG(hw, E1000_MGTPTC);
+#endif
+}
+
+static struct pci_device_id e1000_82541_nics[] = {
+     PCI_ROM(0x8086, 0x1013, "E1000_DEV_ID_82541EI", "E1000_DEV_ID_82541EI", e1000_82541),
+     PCI_ROM(0x8086, 0x1014, "E1000_DEV_ID_82541ER_LOM", "E1000_DEV_ID_82541ER_LOM", e1000_82541),
+     PCI_ROM(0x8086, 0x1018, "E1000_DEV_ID_82541EI_MOBILE", "E1000_DEV_ID_82541EI_MOBILE", e1000_82541),
+     PCI_ROM(0x8086, 0x1019, "E1000_DEV_ID_82547EI", "E1000_DEV_ID_82547EI", e1000_82547),
+     PCI_ROM(0x8086, 0x101A, "E1000_DEV_ID_82547EI_MOBILE", "E1000_DEV_ID_82547EI_MOBILE", e1000_82547),
+     PCI_ROM(0x8086, 0x1075, "E1000_DEV_ID_82547GI", "E1000_DEV_ID_82547GI", e1000_82547_rev_2),
+     PCI_ROM(0x8086, 0x1076, "E1000_DEV_ID_82541GI", "E1000_DEV_ID_82541GI", e1000_82541_rev_2),
+     PCI_ROM(0x8086, 0x1077, "E1000_DEV_ID_82541GI_MOBILE", "E1000_DEV_ID_82541GI_MOBILE", e1000_82541_rev_2),
+     PCI_ROM(0x8086, 0x1078, "E1000_DEV_ID_82541ER", "E1000_DEV_ID_82541ER", e1000_82541_rev_2),
+     PCI_ROM(0x8086, 0x107C, "E1000_DEV_ID_82541GI_LF", "E1000_DEV_ID_82541GI_LF", e1000_82541_rev_2),
+};
+
+struct pci_driver e1000_82541_driver __pci_driver = {
+	.ids = e1000_82541_nics,
+	.id_count = (sizeof (e1000_82541_nics) / sizeof (e1000_82541_nics[0])),
+	.probe = e1000_probe,
+	.remove = e1000_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.h
new file mode 100644
index 0000000..f86a148
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82541.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_82541_H_
+#define _E1000_82541_H_
+
+#define NVM_WORD_SIZE_BASE_SHIFT_82541 (NVM_WORD_SIZE_BASE_SHIFT + 1)
+
+#define IGP01E1000_PHY_CHANNEL_NUM                    4
+
+#define IGP01E1000_PHY_AGC_A                     0x1172
+#define IGP01E1000_PHY_AGC_B                     0x1272
+#define IGP01E1000_PHY_AGC_C                     0x1472
+#define IGP01E1000_PHY_AGC_D                     0x1872
+
+#define IGP01E1000_PHY_AGC_PARAM_A               0x1171
+#define IGP01E1000_PHY_AGC_PARAM_B               0x1271
+#define IGP01E1000_PHY_AGC_PARAM_C               0x1471
+#define IGP01E1000_PHY_AGC_PARAM_D               0x1871
+
+#define IGP01E1000_PHY_EDAC_MU_INDEX             0xC000
+#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS      0x8000
+
+#define IGP01E1000_PHY_DSP_RESET                 0x1F33
+
+#define IGP01E1000_PHY_DSP_FFE                   0x1F35
+#define IGP01E1000_PHY_DSP_FFE_CM_CP             0x0069
+#define IGP01E1000_PHY_DSP_FFE_DEFAULT           0x002A
+
+#define IGP01E1000_IEEE_FORCE_GIG                0x0140
+#define IGP01E1000_IEEE_RESTART_AUTONEG          0x3300
+
+#define IGP01E1000_AGC_LENGTH_SHIFT                   7
+#define IGP01E1000_AGC_RANGE                         10
+
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_20                20
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_100              100
+
+#define IGP01E1000_ANALOG_FUSE_STATUS            0x20D0
+#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS      0x20D1
+#define IGP01E1000_ANALOG_FUSE_CONTROL           0x20DC
+#define IGP01E1000_ANALOG_FUSE_BYPASS            0x20DE
+
+#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED     0x0100
+#define IGP01E1000_ANALOG_FUSE_FINE_MASK         0x0F80
+#define IGP01E1000_ANALOG_FUSE_COARSE_MASK       0x0070
+#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH     0x0040
+#define IGP01E1000_ANALOG_FUSE_COARSE_10         0x0010
+#define IGP01E1000_ANALOG_FUSE_FINE_1            0x0080
+#define IGP01E1000_ANALOG_FUSE_FINE_10           0x0500
+#define IGP01E1000_ANALOG_FUSE_POLY_MASK         0xF000
+#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002
+
+#define IGP01E1000_MSE_CHANNEL_D                 0x000F
+#define IGP01E1000_MSE_CHANNEL_C                 0x00F0
+#define IGP01E1000_MSE_CHANNEL_B                 0x0F00
+#define IGP01E1000_MSE_CHANNEL_A                 0xF000
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82542.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82542.c
new file mode 100644
index 0000000..b6d5202
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82542.c
@@ -0,0 +1,571 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82542 Gigabit Ethernet Controller
+ */
+
+#include "e1000_api.h"
+
+static s32  e1000_init_phy_params_82542(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_82542(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_82542(struct e1000_hw *hw);
+static s32  e1000_get_bus_info_82542(struct e1000_hw *hw);
+static s32  e1000_reset_hw_82542(struct e1000_hw *hw);
+static s32  e1000_init_hw_82542(struct e1000_hw *hw);
+static s32  e1000_setup_link_82542(struct e1000_hw *hw);
+static s32  e1000_led_on_82542(struct e1000_hw *hw);
+static s32  e1000_led_off_82542(struct e1000_hw *hw);
+static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index);
+static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw);
+
+/**
+ *  e1000_init_phy_params_82542 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_phy_params_82542(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_82542");
+
+	phy->type               = e1000_phy_none;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_82542 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_nvm_params_82542(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+
+	DEBUGFUNC("e1000_init_nvm_params_82542");
+
+	nvm->address_bits       =  6;
+	nvm->delay_usec         = 50;
+	nvm->opcode_bits        =  3;
+	nvm->type               = e1000_nvm_eeprom_microwire;
+	nvm->word_size          = 64;
+
+	/* Function Pointers */
+	nvm->ops.read           = e1000_read_nvm_microwire;
+	nvm->ops.release        = e1000_stop_nvm;
+	nvm->ops.write          = e1000_write_nvm_microwire;
+	nvm->ops.update         = e1000_update_nvm_checksum_generic;
+	nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_mac_params_82542 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_mac_params_82542(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_init_mac_params_82542");
+
+	/* Set media type */
+	hw->phy.media_type = e1000_media_type_fiber;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_82542;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_82542;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_82542;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_82542;
+	/* phy/fiber/serdes setup */
+	mac->ops.setup_physical_interface = e1000_setup_fiber_serdes_link_generic;
+	/* check for link */
+	mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* set RAR */
+	mac->ops.rar_set = e1000_rar_set_82542;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_82542;
+	mac->ops.led_off = e1000_led_off_82542;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82542;
+	/* link info */
+	mac->ops.get_link_up_info = e1000_get_speed_and_duplex_fiber_serdes_generic;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_function_pointers_82542 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82542(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_82542");
+
+	hw->mac.ops.init_params = e1000_init_mac_params_82542;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_82542;
+	hw->phy.ops.init_params = e1000_init_phy_params_82542;
+}
+
+/**
+ *  e1000_get_bus_info_82542 - Obtain bus information for adapter
+ *  @hw: pointer to the HW structure
+ *
+ *  This will obtain information about the HW bus for which the
+ *  adapter is attached and stores it in the hw structure.
+ **/
+static s32 e1000_get_bus_info_82542(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_get_bus_info_82542");
+
+	hw->bus.type = e1000_bus_type_pci;
+	hw->bus.speed = e1000_bus_speed_unknown;
+	hw->bus.width = e1000_bus_width_unknown;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_reset_hw_82542 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 e1000_reset_hw_82542(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_reset_hw_82542");
+
+	if (hw->revision_id == E1000_REVISION_2) {
+		DEBUGOUT("Disabling MWI on 82542 rev 2\n");
+		e1000_pci_clear_mwi(hw);
+	}
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	/*
+	 * Delay to allow any outstanding PCI transactions to complete before
+	 * resetting the device
+	 */
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to 82542/82543 MAC\n");
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	hw->nvm.ops.reload(hw);
+	msec_delay(2);
+
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_READ_REG(hw, E1000_ICR);
+
+	if (hw->revision_id == E1000_REVISION_2) {
+		if (bus->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+			e1000_pci_set_mwi(hw);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82542 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82542(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82542 *dev_spec = &hw->dev_spec._82542;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_hw_82542");
+
+	/* Disabling VLAN filtering */
+	E1000_WRITE_REG(hw, E1000_VET, 0);
+	mac->ops.clear_vfta(hw);
+
+	/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+	if (hw->revision_id == E1000_REVISION_2) {
+		DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+		e1000_pci_clear_mwi(hw);
+		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
+		E1000_WRITE_FLUSH(hw);
+		msec_delay(5);
+	}
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+	if (hw->revision_id == E1000_REVISION_2) {
+		E1000_WRITE_REG(hw, E1000_RCTL, 0);
+		E1000_WRITE_FLUSH(hw);
+		msec_delay(1);
+		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+			e1000_pci_set_mwi(hw);
+	}
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/*
+	 * Set the PCI priority bit correctly in the CTRL register.  This
+	 * determines if the adapter gives priority to receives, or if it
+	 * gives equal priority to transmits and receives.
+	 */
+	if (dev_spec->dma_fairness) {
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
+	}
+
+	/* Setup link and flow control */
+	ret_val = e1000_setup_link_82542(hw);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82542(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_link_82542 - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82542(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_link_82542");
+
+	ret_val = e1000_set_default_fc_generic(hw);
+	if (ret_val)
+		goto out;
+
+	hw->fc.requested_mode &= ~e1000_fc_tx_pause;
+
+	if (mac->report_tx_early == 1)
+		hw->fc.requested_mode &= ~e1000_fc_rx_pause;
+
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+	                                             hw->fc.current_mode);
+
+	/* Call the necessary subroutine to configure the link. */
+	ret_val = mac->ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	DEBUGOUT("Initializing Flow Control address, type and timer regs\n");
+
+	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+
+	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_led_on_82542 - Turn on SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED on.
+ **/
+static s32 e1000_led_on_82542(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGFUNC("e1000_led_on_82542");
+
+	ctrl |= E1000_CTRL_SWDPIN0;
+	ctrl |= E1000_CTRL_SWDPIO0;
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_led_off_82542 - Turn off SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED off.
+ **/
+static s32 e1000_led_off_82542(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGFUNC("e1000_led_off_82542");
+
+	ctrl &= ~E1000_CTRL_SWDPIN0;
+	ctrl |= E1000_CTRL_SWDPIO0;
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_rar_set_82542 - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	DEBUGFUNC("e1000_rar_set_82542");
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+	           ((u32) addr[1] << 8) |
+	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	/* If MAC address zero, no need to set the AV bit */
+	if (rar_low || rar_high)
+		rar_high |= E1000_RAH_AV;
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
+	E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ *  e1000_translate_register_82542 - Translate the proper register offset
+ *  @reg: e1000 register to be read
+ *
+ *  Registers in 82542 are located in different offsets than other adapters
+ *  even though they function in the same manner.  This function takes in
+ *  the name of the register to read and returns the correct offset for
+ *  82542 silicon.
+ **/
+u32 e1000_translate_register_82542(u32 reg)
+{
+	/*
+	 * Some of the 82542 registers are located at different
+	 * offsets than they are in newer adapters.
+	 * Despite the difference in location, the registers
+	 * function in the same manner.
+	 */
+	switch (reg) {
+	case E1000_RA:
+		reg = 0x00040;
+		break;
+	case E1000_RDTR:
+		reg = 0x00108;
+		break;
+	case E1000_RDBAL(0):
+		reg = 0x00110;
+		break;
+	case E1000_RDBAH(0):
+		reg = 0x00114;
+		break;
+	case E1000_RDLEN(0):
+		reg = 0x00118;
+		break;
+	case E1000_RDH(0):
+		reg = 0x00120;
+		break;
+	case E1000_RDT(0):
+		reg = 0x00128;
+		break;
+	case E1000_RDBAL(1):
+		reg = 0x00138;
+		break;
+	case E1000_RDBAH(1):
+		reg = 0x0013C;
+		break;
+	case E1000_RDLEN(1):
+		reg = 0x00140;
+		break;
+	case E1000_RDH(1):
+		reg = 0x00148;
+		break;
+	case E1000_RDT(1):
+		reg = 0x00150;
+		break;
+	case E1000_FCRTH:
+		reg = 0x00160;
+		break;
+	case E1000_FCRTL:
+		reg = 0x00168;
+		break;
+	case E1000_MTA:
+		reg = 0x00200;
+		break;
+	case E1000_TDBAL(0):
+		reg = 0x00420;
+		break;
+	case E1000_TDBAH(0):
+		reg = 0x00424;
+		break;
+	case E1000_TDLEN(0):
+		reg = 0x00428;
+		break;
+	case E1000_TDH(0):
+		reg = 0x00430;
+		break;
+	case E1000_TDT(0):
+		reg = 0x00438;
+		break;
+	case E1000_TIDV:
+		reg = 0x00440;
+		break;
+	case E1000_VFTA:
+		reg = 0x00600;
+		break;
+	case E1000_TDFH:
+		reg = 0x08010;
+		break;
+	case E1000_TDFT:
+		reg = 0x08018;
+		break;
+	default:
+		break;
+	}
+
+	return reg;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82542 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_clear_hw_cntrs_82542");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+#if 0
+	E1000_READ_REG(hw, E1000_PRC64);
+	E1000_READ_REG(hw, E1000_PRC127);
+	E1000_READ_REG(hw, E1000_PRC255);
+	E1000_READ_REG(hw, E1000_PRC511);
+	E1000_READ_REG(hw, E1000_PRC1023);
+	E1000_READ_REG(hw, E1000_PRC1522);
+	E1000_READ_REG(hw, E1000_PTC64);
+	E1000_READ_REG(hw, E1000_PTC127);
+	E1000_READ_REG(hw, E1000_PTC255);
+	E1000_READ_REG(hw, E1000_PTC511);
+	E1000_READ_REG(hw, E1000_PTC1023);
+	E1000_READ_REG(hw, E1000_PTC1522);
+#endif
+}
+
+static struct pci_device_id e1000_82542_nics[] = {
+     PCI_ROM(0x8086, 0x1000, "E1000_DEV_ID_82542", "E1000_DEV_ID_82542", e1000_82542),
+};
+
+struct pci_driver e1000_82542_driver __pci_driver = {
+	.ids = e1000_82542_nics,
+	.id_count = (sizeof (e1000_82542_nics) / sizeof (e1000_82542_nics[0])),
+	.probe = e1000_probe,
+	.remove = e1000_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.c
new file mode 100644
index 0000000..848c99e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.c
@@ -0,0 +1,1635 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82543GC Gigabit Ethernet Controller (Fiber)
+ * 82543GC Gigabit Ethernet Controller (Copper)
+ * 82544EI Gigabit Ethernet Controller (Copper)
+ * 82544EI Gigabit Ethernet Controller (Fiber)
+ * 82544GC Gigabit Ethernet Controller (Copper)
+ * 82544GC Gigabit Ethernet Controller (LOM)
+ */
+
+#include "e1000_api.h"
+
+static s32  e1000_init_phy_params_82543(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_82543(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_82543(struct e1000_hw *hw);
+static s32  e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset,
+                                     u16 *data);
+static s32  e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset,
+                                      u16 data);
+#if 0
+static s32  e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw);
+#endif
+static s32  e1000_phy_hw_reset_82543(struct e1000_hw *hw);
+static s32  e1000_reset_hw_82543(struct e1000_hw *hw);
+static s32  e1000_init_hw_82543(struct e1000_hw *hw);
+static s32  e1000_setup_link_82543(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_82543(struct e1000_hw *hw);
+static s32  e1000_setup_fiber_link_82543(struct e1000_hw *hw);
+static s32  e1000_check_for_copper_link_82543(struct e1000_hw *hw);
+static s32  e1000_check_for_fiber_link_82543(struct e1000_hw *hw);
+static s32  e1000_led_on_82543(struct e1000_hw *hw);
+static s32  e1000_led_off_82543(struct e1000_hw *hw);
+static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset,
+                                   u32 value);
+static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value);
+static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw);
+static s32  e1000_config_mac_to_phy_82543(struct e1000_hw *hw);
+static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw);
+static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
+static s32  e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
+static u16  e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw);
+static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
+                                           u16 count);
+static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw);
+static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state);
+static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state);
+
+/**
+ *  e1000_init_phy_params_82543 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_phy_params_82543(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_82543");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type               = e1000_phy_none;
+		goto out;
+	} else {
+		phy->ops.power_up       = e1000_power_up_phy_copper;
+		phy->ops.power_down     = e1000_power_down_phy_copper;
+	}
+
+	phy->addr                       = 1;
+	phy->autoneg_mask               = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us             = 10000;
+	phy->type                       = e1000_phy_m88;
+
+	/* Function Pointers */
+	phy->ops.check_polarity         = e1000_check_polarity_m88;
+	phy->ops.commit                 = e1000_phy_sw_reset_generic;
+#if 0
+	phy->ops.force_speed_duplex     = e1000_phy_force_speed_duplex_82543;
+#endif
+#if 0
+	phy->ops.get_cable_length       = e1000_get_cable_length_m88;
+#endif
+	phy->ops.get_cfg_done           = e1000_get_cfg_done_generic;
+	phy->ops.read_reg               = (hw->mac.type == e1000_82543)
+	                                  ? e1000_read_phy_reg_82543
+	                                  : e1000_read_phy_reg_m88;
+	phy->ops.reset                  = (hw->mac.type == e1000_82543)
+	                                  ? e1000_phy_hw_reset_82543
+	                                  : e1000_phy_hw_reset_generic;
+	phy->ops.write_reg              = (hw->mac.type == e1000_82543)
+	                                  ? e1000_write_phy_reg_82543
+	                                  : e1000_write_phy_reg_m88;
+	phy->ops.get_info               = e1000_get_phy_info_m88;
+
+	/*
+	 * The external PHY of the 82543 can be in a funky state.
+	 * Resetting helps us read the PHY registers for acquiring
+	 * the PHY ID.
+	 */
+	if (!e1000_init_phy_disabled_82543(hw)) {
+		ret_val = phy->ops.reset(hw);
+		if (ret_val) {
+			DEBUGOUT("Resetting PHY during init failed.\n");
+			goto out;
+		}
+		msec_delay(20);
+	}
+
+	ret_val = e1000_get_phy_id(hw);
+	if (ret_val)
+		goto out;
+
+	/* Verify phy id */
+	switch (hw->mac.type) {
+	case e1000_82543:
+		if (phy->id != M88E1000_E_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+		break;
+	case e1000_82544:
+		if (phy->id != M88E1000_I_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_82543 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+
+	DEBUGFUNC("e1000_init_nvm_params_82543");
+
+	nvm->type               = e1000_nvm_eeprom_microwire;
+	nvm->word_size          = 64;
+	nvm->delay_usec         = 50;
+	nvm->address_bits       =  6;
+	nvm->opcode_bits        =  3;
+
+	/* Function Pointers */
+	nvm->ops.read           = e1000_read_nvm_microwire;
+	nvm->ops.update         = e1000_update_nvm_checksum_generic;
+	nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+	nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
+	nvm->ops.write          = e1000_write_nvm_microwire;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_mac_params_82543 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_init_mac_params_82543(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_init_mac_params_82543");
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82544EI_FIBER:
+		hw->phy.media_type = e1000_media_type_fiber;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_82543;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_82543;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_82543;
+	/* physical interface setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_setup_copper_link_82543
+	                : e1000_setup_fiber_link_82543;
+	/* check for link */
+	mac->ops.check_for_link =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_check_for_copper_link_82543
+	                : e1000_check_for_fiber_link_82543;
+	/* link info */
+	mac->ops.get_link_up_info =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_get_speed_and_duplex_copper_generic
+	                : e1000_get_speed_and_duplex_fiber_serdes_generic;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_82543;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_82543;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_82543;
+	mac->ops.led_off = e1000_led_off_82543;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82543;
+
+	/* Set tbi compatibility */
+	if ((hw->mac.type != e1000_82543) ||
+	    (hw->phy.media_type == e1000_media_type_fiber))
+		e1000_set_tbi_compatibility_82543(hw, false);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_function_pointers_82543 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82543(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_82543");
+
+	hw->mac.ops.init_params = e1000_init_mac_params_82543;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_82543;
+	hw->phy.ops.init_params = e1000_init_phy_params_82543;
+}
+
+/**
+ *  e1000_tbi_compatibility_enabled_82543 - Returns TBI compat status
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns the current status of 10-bit Interface (TBI) compatibility
+ *  (enabled/disabled).
+ **/
+static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+	bool state = false;
+
+	DEBUGFUNC("e1000_tbi_compatibility_enabled_82543");
+
+	if (hw->mac.type != e1000_82543) {
+		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
+		goto out;
+	}
+
+	state = (dev_spec->tbi_compatibility & TBI_COMPAT_ENABLED)
+	        ? true : false;
+
+out:
+	return state;
+}
+
+/**
+ *  e1000_set_tbi_compatibility_82543 - Set TBI compatibility
+ *  @hw: pointer to the HW structure
+ *  @state: enable/disable TBI compatibility
+ *
+ *  Enables or disabled 10-bit Interface (TBI) compatibility.
+ **/
+static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state)
+{
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+
+	DEBUGFUNC("e1000_set_tbi_compatibility_82543");
+
+	if (hw->mac.type != e1000_82543) {
+		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
+		goto out;
+	}
+
+	if (state)
+		dev_spec->tbi_compatibility |= TBI_COMPAT_ENABLED;
+	else
+		dev_spec->tbi_compatibility &= ~TBI_COMPAT_ENABLED;
+
+out:
+	return;
+}
+
+/**
+ *  e1000_tbi_sbp_enabled_82543 - Returns TBI SBP status
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns the current status of 10-bit Interface (TBI) store bad packet (SBP)
+ *  (enabled/disabled).
+ **/
+bool e1000_tbi_sbp_enabled_82543(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+	bool state = false;
+
+	DEBUGFUNC("e1000_tbi_sbp_enabled_82543");
+
+	if (hw->mac.type != e1000_82543) {
+		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
+		goto out;
+	}
+
+	state = (dev_spec->tbi_compatibility & TBI_SBP_ENABLED)
+	        ? true : false;
+
+out:
+	return state;
+}
+
+/**
+ *  e1000_set_tbi_sbp_82543 - Set TBI SBP
+ *  @hw: pointer to the HW structure
+ *  @state: enable/disable TBI store bad packet
+ *
+ *  Enables or disabled 10-bit Interface (TBI) store bad packet (SBP).
+ **/
+static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state)
+{
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+
+	DEBUGFUNC("e1000_set_tbi_sbp_82543");
+
+	if (state && e1000_tbi_compatibility_enabled_82543(hw))
+		dev_spec->tbi_compatibility |= TBI_SBP_ENABLED;
+	else
+		dev_spec->tbi_compatibility &= ~TBI_SBP_ENABLED;
+
+	return;
+}
+
+/**
+ *  e1000_init_phy_disabled_82543 - Returns init PHY status
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns the current status of whether PHY initialization is disabled.
+ *  True if PHY initialization is disabled else false.
+ **/
+static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+	bool ret_val;
+
+	DEBUGFUNC("e1000_init_phy_disabled_82543");
+
+	if (hw->mac.type != e1000_82543) {
+		ret_val = false;
+		goto out;
+	}
+
+	ret_val = dev_spec->init_phy_disabled;
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000_tbi_adjust_stats_82543 - Adjust stats when TBI enabled
+ *  @hw: pointer to the HW structure
+ *  @stats: Struct containing statistic register values
+ *  @frame_len: The length of the frame in question
+ *  @mac_addr: The Ethernet destination address of the frame in question
+ *  @max_frame_size: The maximum frame size
+ *
+ *  Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ **/
+void e1000_tbi_adjust_stats_82543(struct e1000_hw *hw,
+                                  struct e1000_hw_stats *stats, u32 frame_len,
+                                  u8 *mac_addr, u32 max_frame_size)
+{
+	if (!(e1000_tbi_sbp_enabled_82543(hw)))
+		goto out;
+
+	/* First adjust the frame length. */
+	frame_len--;
+	/*
+	 * We need to adjust the statistics counters, since the hardware
+	 * counters overcount this packet as a CRC error and undercount
+	 * the packet as a good packet
+	 */
+	/* This packet should not be counted as a CRC error.    */
+	stats->crcerrs--;
+	/* This packet does count as a Good Packet Received.    */
+	stats->gprc++;
+
+	/* Adjust the Good Octets received counters             */
+	stats->gorc += frame_len;
+
+	/*
+	 * Is this a broadcast or multicast?  Check broadcast first,
+	 * since the test for a multicast frame will test positive on
+	 * a broadcast frame.
+	 */
+	if ((mac_addr[0] == 0xff) && (mac_addr[1] == 0xff))
+		/* Broadcast packet */
+		stats->bprc++;
+	else if (*mac_addr & 0x01)
+		/* Multicast packet */
+		stats->mprc++;
+
+	/*
+	 * In this case, the hardware has overcounted the number of
+	 * oversize frames.
+	 */
+	if ((frame_len == max_frame_size) && (stats->roc > 0))
+		stats->roc--;
+
+	/*
+	 * Adjust the bin counters when the extra byte put the frame in the
+	 * wrong bin. Remember that the frame_len was adjusted above.
+	 */
+	if (frame_len == 64) {
+		stats->prc64++;
+		stats->prc127--;
+	} else if (frame_len == 127) {
+		stats->prc127++;
+		stats->prc255--;
+	} else if (frame_len == 255) {
+		stats->prc255++;
+		stats->prc511--;
+	} else if (frame_len == 511) {
+		stats->prc511++;
+		stats->prc1023--;
+	} else if (frame_len == 1023) {
+		stats->prc1023++;
+		stats->prc1522--;
+	} else if (frame_len == 1522) {
+		stats->prc1522++;
+	}
+
+out:
+	return;
+}
+#endif
+
+/**
+ *  e1000_read_phy_reg_82543 - Read PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY at offset and stores the information read to data.
+ **/
+static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	u32 mdic;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_82543");
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		DEBUGOUT1("PHY Address %d is out of range\n", offset);
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	/*
+	 * We must first send a preamble through the MDIO pin to signal the
+	 * beginning of an MII instruction.  This is done by sending 32
+	 * consecutive "1" bits.
+	 */
+	e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+	/*
+	 * Now combine the next few fields that are required for a read
+	 * operation.  We use this method instead of calling the
+	 * e1000_shift_out_mdi_bits routine five different times.  The format
+	 * of an MII read instruction consists of a shift out of 14 bits and
+	 * is defined as follows:
+	 * 	<Preamble><SOF><Op Code><Phy Addr><Offset>
+	 * followed by a shift in of 18 bits.  This first two bits shifted in
+	 * are TurnAround bits used to avoid contention on the MDIO pin when a
+	 * READ operation is performed.  These two bits are thrown away
+	 * followed by a shift in of 16 bits which contains the desired data.
+	 */
+	mdic = (offset | (hw->phy.addr << 5) |
+		(PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+	e1000_shift_out_mdi_bits_82543(hw, mdic, 14);
+
+	/*
+	 * Now that we've shifted out the read command to the MII, we need to
+	 * "shift in" the 16-bit value (18 total bits) of the requested PHY
+	 * register address.
+	 */
+	*data = e1000_shift_in_mdi_bits_82543(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_82543 - Write PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be written
+ *  @data: pointer to the data to be written at offset
+ *
+ *  Writes data to the PHY at offset.
+ **/
+static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	u32 mdic;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_82543");
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		DEBUGOUT1("PHY Address %d is out of range\n", offset);
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	/*
+	 * We'll need to use the SW defined pins to shift the write command
+	 * out to the PHY. We first send a preamble to the PHY to signal the
+	 * beginning of the MII instruction.  This is done by sending 32
+	 * consecutive "1" bits.
+	 */
+	e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+	/*
+	 * Now combine the remaining required fields that will indicate a
+	 * write operation. We use this method instead of calling the
+	 * e1000_shift_out_mdi_bits routine for each field in the command. The
+	 * format of a MII write instruction is as follows:
+	 * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+	 */
+	mdic = ((PHY_TURNAROUND) | (offset << 2) | (hw->phy.addr << 7) |
+	        (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+	mdic <<= 16;
+	mdic |= (u32) data;
+
+	e1000_shift_out_mdi_bits_82543(hw, mdic, 32);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_raise_mdi_clk_82543 - Raise Management Data Input clock
+ *  @hw: pointer to the HW structure
+ *  @ctrl: pointer to the control register
+ *
+ *  Raise the management data input clock by setting the MDC bit in the control
+ *  register.
+ **/
+static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
+{
+	/*
+	 * Raise the clock input to the Management Data Clock (by setting the
+	 * MDC bit), and then delay a sufficient amount of time.
+	 */
+	E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl | E1000_CTRL_MDC));
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(10);
+}
+
+/**
+ *  e1000_lower_mdi_clk_82543 - Lower Management Data Input clock
+ *  @hw: pointer to the HW structure
+ *  @ctrl: pointer to the control register
+ *
+ *  Lower the management data input clock by clearing the MDC bit in the
+ *  control register.
+ **/
+static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
+{
+	/*
+	 * Lower the clock input to the Management Data Clock (by clearing the
+	 * MDC bit), and then delay a sufficient amount of time.
+	 */
+	E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl & ~E1000_CTRL_MDC));
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(10);
+}
+
+/**
+ *  e1000_shift_out_mdi_bits_82543 - Shift data bits our to the PHY
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the PHY
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the PHY.  So, the value in the
+ *  "data" parameter will be shifted out to the PHY one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
+                                           u16 count)
+{
+	u32 ctrl, mask;
+
+	/*
+	 * We need to shift "count" number of bits out to the PHY.  So, the
+	 * value in the "data" parameter will be shifted out to the PHY one
+	 * bit at a time.  In order to do this, "data" must be broken down
+	 * into bits.
+	 */
+	mask = 0x01;
+	mask <<= (count -1);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+	ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+	while (mask) {
+		/*
+		 * A "1" is shifted out to the PHY by setting the MDIO bit to
+		 * "1" and then raising and lowering the Management Data Clock.
+		 * A "0" is shifted out to the PHY by setting the MDIO bit to
+		 * "0" and then raising and lowering the clock.
+		 */
+		if (data & mask) ctrl |= E1000_CTRL_MDIO;
+		else ctrl &= ~E1000_CTRL_MDIO;
+
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		E1000_WRITE_FLUSH(hw);
+
+		usec_delay(10);
+
+		e1000_raise_mdi_clk_82543(hw, &ctrl);
+		e1000_lower_mdi_clk_82543(hw, &ctrl);
+
+		mask >>= 1;
+	}
+}
+
+/**
+ *  e1000_shift_in_mdi_bits_82543 - Shift data bits in from the PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  In order to read a register from the PHY, we need to shift 18 bits
+ *  in from the PHY.  Bits are "shifted in" by raising the clock input to
+ *  the PHY (setting the MDC bit), and then reading the value of the data out
+ *  MDIO bit.
+ **/
+static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u16 data = 0;
+	u8 i;
+
+	/*
+	 * In order to read a register from the PHY, we need to shift in a
+	 * total of 18 bits from the PHY.  The first two bit (turnaround)
+	 * times are used to avoid contention on the MDIO pin when a read
+	 * operation is performed.  These two bits are ignored by us and
+	 * thrown away.  Bits are "shifted in" by raising the input to the
+	 * Management Data Clock (setting the MDC bit) and then reading the
+	 * value of the MDIO bit.
+	 */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/*
+	 * Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
+	 * input.
+	 */
+	ctrl &= ~E1000_CTRL_MDIO_DIR;
+	ctrl &= ~E1000_CTRL_MDIO;
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	/*
+	 * Raise and lower the clock before reading in the data.  This accounts
+	 * for the turnaround bits.  The first clock occurred when we clocked
+	 * out the last bit of the Register Address.
+	 */
+	e1000_raise_mdi_clk_82543(hw, &ctrl);
+	e1000_lower_mdi_clk_82543(hw, &ctrl);
+
+	for (data = 0, i = 0; i < 16; i++) {
+		data <<= 1;
+		e1000_raise_mdi_clk_82543(hw, &ctrl);
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		/* Check to see if we shifted in a "1". */
+		if (ctrl & E1000_CTRL_MDIO)
+			data |= 1;
+		e1000_lower_mdi_clk_82543(hw, &ctrl);
+	}
+
+	e1000_raise_mdi_clk_82543(hw, &ctrl);
+	e1000_lower_mdi_clk_82543(hw, &ctrl);
+
+	return data;
+}
+
+#if 0
+/**
+ *  e1000_phy_force_speed_duplex_82543 - Force speed/duplex for PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the function to force speed and duplex for the m88 PHY, and
+ *  if the PHY is not auto-negotiating and the speed is forced to 10Mbit,
+ *  then call the function for polarity reversal workaround.
+ **/
+static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_82543");
+
+	ret_val = e1000_phy_force_speed_duplex_m88(hw);
+	if (ret_val)
+		goto out;
+
+	if (!hw->mac.autoneg &&
+	    (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED))
+		ret_val = e1000_polarity_reversal_workaround_82543(hw);
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000_polarity_reversal_workaround_82543 - Workaround polarity reversal
+ *  @hw: pointer to the HW structure
+ *
+ *  When forcing link to 10 Full or 10 Half, the PHY can reverse the polarity
+ *  inadvertently.  To workaround the issue, we disable the transmitter on
+ *  the PHY until we have established the link partner's link parameters.
+ **/
+static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 mii_status_reg;
+	u16 i;
+	bool link;
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	/* Polarity reversal workaround for forced 10F/10H links. */
+
+	/* Disable the transmitter on the PHY */
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+	if (ret_val)
+		goto out;
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * This loop will early-out if the NO link condition has been met.
+	 * In other words, DO NOT use e1000_phy_has_link_generic() here.
+	 */
+	for (i = PHY_FORCE_TIME; i > 0; i--) {
+		/*
+		 * Read the MII Status Register and wait for Link Status bit
+		 * to be clear.
+		 */
+
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0)
+			break;
+		msec_delay_irq(100);
+	}
+
+	/* Recommended delay time after link has been lost */
+	msec_delay_irq(1000);
+
+	/* Now we will re-enable the transmitter on the PHY */
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+	if (ret_val)
+		goto out;
+	msec_delay_irq(50);
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+	if (ret_val)
+		goto out;
+	msec_delay_irq(50);
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+	if (ret_val)
+		goto out;
+	msec_delay_irq(50);
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Read the MII Status Register and wait for Link Status bit
+	 * to be set.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_TIME, 100000, &link);
+	if (ret_val)
+		goto out;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_82543 - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the PHY_RESET_DIR bit in the extended device control register
+ *  to put the PHY into a reset and waits for completion.  Once the reset
+ *  has been accomplished, clear the PHY_RESET_DIR bit to take the PHY out
+ *  of reset.
+ **/
+static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_phy_hw_reset_82543");
+
+	/*
+	 * Read the Extended Device Control Register, assert the PHY_RESET_DIR
+	 * bit to put the PHY into reset...
+	 */
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+	ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	/* ...then take it out of reset. */
+	ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(150);
+
+	if (!(hw->phy.ops.get_cfg_done))
+		return E1000_SUCCESS;
+
+	ret_val = hw->phy.ops.get_cfg_done(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_82543 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 e1000_reset_hw_82543(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_reset_hw_82543");
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	e1000_set_tbi_sbp_82543(hw, false);
+
+	/*
+	 * Delay to allow any outstanding PCI transactions to complete before
+	 * resetting the device
+	 */
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to 82543/82544 MAC\n");
+	if (hw->mac.type == e1000_82543) {
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+	} else {
+		/*
+		 * The 82544 can't ACK the 64-bit write when issuing the
+		 * reset, so use IO-mapping as a workaround.
+		 */
+		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+	}
+
+	/*
+	 * After MAC reset, force reload of NVM to restore power-on
+	 * settings to device.
+	 */
+	hw->nvm.ops.reload(hw);
+	msec_delay(2);
+
+	/* Masking off and clearing any pending interrupts */
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_READ_REG(hw, E1000_ICR);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82543 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82543(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
+	u32 ctrl;
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_hw_82543");
+
+	/* Disabling VLAN filtering */
+	E1000_WRITE_REG(hw, E1000_VET, 0);
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	/*
+	 * Set the PCI priority bit correctly in the CTRL register.  This
+	 * determines if the adapter gives priority to receives, or if it
+	 * gives equal priority to transmits and receives.
+	 */
+	if (hw->mac.type == e1000_82543 && dev_spec->dma_fairness) {
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
+	}
+
+	e1000_pcix_mmrbc_workaround_generic(hw);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82543(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_link_82543 - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM to determine the initial polarity value and write the
+ *  extended device control register with the information before calling
+ *  the generic setup link function, which does the following:
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82543(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+	s32  ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_setup_link_82543");
+
+	/*
+	 * Take the 4 bits from NVM word 0xF that determine the initial
+	 * polarity value for the SW controlled pins, and setup the
+	 * Extended Device Control reg with that info.
+	 * This is needed because one of the SW controlled pins is used for
+	 * signal detection.  So this should be done before phy setup.
+	 */
+	if (hw->mac.type == e1000_82543) {
+		ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+		ctrl_ext = ((data & NVM_WORD0F_SWPDIO_EXT_MASK) <<
+		            NVM_SWDPIO_EXT_SHIFT);
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	}
+
+	ret_val = e1000_setup_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_82543 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_setup_copper_link_82543");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL) | E1000_CTRL_SLU;
+	/*
+	 * With 82543, we need to force speed and duplex on the MAC
+	 * equal to what the PHY speed and duplex configuration is.
+	 * In addition, we need to perform a hardware reset on the
+	 * PHY to take it out of reset.
+	 */
+	if (hw->mac.type == e1000_82543) {
+		ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		ret_val = hw->phy.ops.reset(hw);
+		if (ret_val)
+			goto out;
+		hw->phy.reset_disable = false;
+	} else {
+		ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	}
+
+	/* Set MDI/MDI-X, Polarity Reversal, and downshift settings */
+	ret_val = e1000_copper_link_setup_m88(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement and perform
+		 * autonegotiation.
+		 */
+		ret_val = e1000_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+#if 0
+		DEBUGOUT("Forcing Speed and Duplex\n");
+		ret_val = e1000_phy_force_speed_duplex_82543(hw);
+		if (ret_val) {
+			DEBUGOUT("Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+#endif
+	}
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw,
+	                                     COPPER_LINK_UP_LIMIT,
+	                                     10,
+	                                     &link);
+	if (ret_val)
+		goto out;
+
+
+	if (link) {
+		DEBUGOUT("Valid link established!!!\n");
+		/* Config the MAC and PHY after link is up */
+		if (hw->mac.type == e1000_82544) {
+			e1000_config_collision_dist_generic(hw);
+		} else {
+			ret_val = e1000_config_mac_to_phy_82543(hw);
+			if (ret_val)
+				goto out;
+		}
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+	} else {
+		DEBUGOUT("Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_link_82543 - Setup link for fiber
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber links.  Upon
+ *  successful setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_setup_fiber_link_82543");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	e1000_config_collision_dist_generic(hw);
+
+	ret_val = e1000_commit_fc_settings_generic(hw);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT("Auto-negotiation enabled\n");
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(1);
+
+	/*
+	 * For these adapters, the SW definable pin 1 is cleared when the
+	 * optics detect a signal.  If we have a signal, then poll for a
+	 * "Link-Up" indication.
+	 */
+	if (!(E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+	} else {
+		DEBUGOUT("No signal detected\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_copper_link_82543 - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the phy for link, if link exists, do the following:
+ *   - check for downshift
+ *   - do polarity workaround (if necessary)
+ *   - configure collision distance
+ *   - configure flow control after link up
+ *   - configure tbi compatibility
+ **/
+static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 icr, rctl;
+	s32 ret_val;
+	u16 speed, duplex;
+	bool link;
+
+	DEBUGFUNC("e1000_check_for_copper_link_82543");
+
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	e1000_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we can return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		/*
+		 * If speed and duplex are forced to 10H or 10F, then we will
+		 * implement the polarity reversal workaround.  We disable
+		 * interrupts first, and upon returning, place the devices
+		 * interrupt state to its previous value except for the link
+		 * status change interrupt which will happened due to the
+		 * execution of this workaround.
+		 */
+		if (mac->forced_speed_duplex & E1000_ALL_10_SPEED) {
+			E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
+			ret_val = e1000_polarity_reversal_workaround_82543(hw);
+			icr = E1000_READ_REG(hw, E1000_ICR);
+			E1000_WRITE_REG(hw, E1000_ICS, (icr & ~E1000_ICS_LSC));
+			E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
+		}
+
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+	 * have Si on board that is 82544 or newer, Auto
+	 * Speed Detection takes care of MAC speed/duplex
+	 * configuration.  So we only need to configure Collision
+	 * Distance in the MAC.  Otherwise, we need to force
+	 * speed/duplex on the MAC to the current PHY speed/duplex
+	 * settings.
+	 */
+	if (mac->type == e1000_82544)
+		e1000_config_collision_dist_generic(hw);
+	else {
+		ret_val = e1000_config_mac_to_phy_82543(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring MAC to PHY settings\n");
+			goto out;
+		}
+	}
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000_config_fc_after_link_up_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error configuring flow control\n");
+	}
+
+	/*
+	 * At this point we know that we are on copper and we have
+	 * auto-negotiated link.  These are conditions for checking the link
+	 * partner capability register.  We use the link speed to determine if
+	 * TBI compatibility needs to be turned on or off.  If the link is not
+	 * at gigabit speed, then TBI compatibility is not needed.  If we are
+	 * at gigabit speed, we turn on TBI compatibility.
+	 */
+	if (e1000_tbi_compatibility_enabled_82543(hw)) {
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			DEBUGOUT("Error getting link speed and duplex\n");
+			return ret_val;
+		}
+		if (speed != SPEED_1000) {
+			/*
+			 * If link speed is not set to gigabit speed,
+			 * we do not need to enable TBI compatibility.
+			 */
+			if (e1000_tbi_sbp_enabled_82543(hw)) {
+				/*
+				 * If we previously were in the mode,
+				 * turn it off.
+				 */
+				e1000_set_tbi_sbp_82543(hw, false);
+				rctl = E1000_READ_REG(hw, E1000_RCTL);
+				rctl &= ~E1000_RCTL_SBP;
+				E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+			}
+		} else {
+			/*
+			 * If TBI compatibility is was previously off,
+			 * turn it on. For compatibility with a TBI link
+			 * partner, we will store bad packets. Some
+			 * frames have an additional byte on the end and
+			 * will look like CRC errors to to the hardware.
+			 */
+			if (!e1000_tbi_sbp_enabled_82543(hw)) {
+				e1000_set_tbi_sbp_82543(hw, true);
+				rctl = E1000_READ_REG(hw, E1000_RCTL);
+				rctl |= E1000_RCTL_SBP;
+				E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+			}
+		}
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_fiber_link_82543 - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw, ctrl, status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_fiber_link_82543");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 0 == have signal */
+	if ((!(ctrl & E1000_CTRL_SWDPIN1)) &&
+	    (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			ret_val = 0;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_mac_to_phy_82543 - Configure MAC to PHY settings
+ *  @hw: pointer to the HW structure
+ *
+ *  For the 82543 silicon, we need to set the MAC to match the settings
+ *  of the PHY, even if the PHY is auto-negotiating.
+ **/
+static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data;
+
+	DEBUGFUNC("e1000_config_mac_to_phy_82543");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	/* Set the bits to force speed and duplex */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+	/*
+	 * Set up duplex in the Device Control and Transmit Control
+	 * registers depending on negotiated values.
+	 */
+	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	ctrl &= ~E1000_CTRL_FD;
+	if (phy_data & M88E1000_PSSR_DPLX)
+		ctrl |= E1000_CTRL_FD;
+
+	e1000_config_collision_dist_generic(hw);
+
+	/*
+	 * Set up speed in the Device Control register depending on
+	 * negotiated values.
+	 */
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+		ctrl |= E1000_CTRL_SPD_1000;
+	else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+		ctrl |= E1000_CTRL_SPD_100;
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_vfta_82543 - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: the 32-bit offset in which to write the value to.
+ *  @value: the 32-bit value to write at location offset.
+ *
+ *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
+ *  table.
+ **/
+static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	u32 temp;
+
+	DEBUGFUNC("e1000_write_vfta_82543");
+
+	if ((hw->mac.type == e1000_82544) && (offset & 1)) {
+		temp = E1000_READ_REG_ARRAY(hw, E1000_VFTA, offset - 1);
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+		E1000_WRITE_FLUSH(hw);
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset - 1, temp);
+		E1000_WRITE_FLUSH(hw);
+	} else {
+		e1000_write_vfta_generic(hw, offset, value);
+	}
+}
+
+/**
+ *  e1000_mta_set_82543 - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta, temp;
+
+	DEBUGFUNC("e1000_mta_set_82543");
+
+	hash_reg = (hash_value >> 5);
+
+	/*
+	 * If we are on an 82544 and we are trying to write an odd offset
+	 * in the MTA, save off the previous entry before writing and
+	 * restore the old value after writing.
+	 */
+	if ((hw->mac.type == e1000_82544) && (hash_reg & 1)) {
+		hash_reg &= (hw->mac.mta_reg_count - 1);
+		hash_bit = hash_value & 0x1F;
+		mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+		mta |= (1 << hash_bit);
+		temp = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg - 1);
+
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+		E1000_WRITE_FLUSH(hw);
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg - 1, temp);
+		E1000_WRITE_FLUSH(hw);
+	} else {
+		e1000_mta_set_generic(hw, hash_value);
+	}
+}
+
+/**
+ *  e1000_led_on_82543 - Turn on SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED on.
+ **/
+static s32 e1000_led_on_82543(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGFUNC("e1000_led_on_82543");
+
+	if (hw->mac.type == e1000_82544 &&
+	    hw->phy.media_type == e1000_media_type_copper) {
+		/* Clear SW-definable Pin 0 to turn on the LED */
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+	} else {
+		/* Fiber 82544 and all 82543 use this method */
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+	}
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	return E1000_SUCCESS;
+#endif
+        return 0;
+}
+
+/**
+ *  e1000_led_off_82543 - Turn off SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED off.
+ **/
+static s32 e1000_led_off_82543(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGFUNC("e1000_led_off_82543");
+
+	if (hw->mac.type == e1000_82544 &&
+	    hw->phy.media_type == e1000_media_type_copper) {
+		/* Set SW-definable Pin 0 to turn off the LED */
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+	} else {
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+	}
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	return E1000_SUCCESS;
+#endif
+        return 0;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82543 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_clear_hw_cntrs_82543");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+#if 0
+	E1000_READ_REG(hw, E1000_PRC64);
+	E1000_READ_REG(hw, E1000_PRC127);
+	E1000_READ_REG(hw, E1000_PRC255);
+	E1000_READ_REG(hw, E1000_PRC511);
+	E1000_READ_REG(hw, E1000_PRC1023);
+	E1000_READ_REG(hw, E1000_PRC1522);
+	E1000_READ_REG(hw, E1000_PTC64);
+	E1000_READ_REG(hw, E1000_PTC127);
+	E1000_READ_REG(hw, E1000_PTC255);
+	E1000_READ_REG(hw, E1000_PTC511);
+	E1000_READ_REG(hw, E1000_PTC1023);
+	E1000_READ_REG(hw, E1000_PTC1522);
+
+	E1000_READ_REG(hw, E1000_ALGNERRC);
+	E1000_READ_REG(hw, E1000_RXERRC);
+	E1000_READ_REG(hw, E1000_TNCRS);
+	E1000_READ_REG(hw, E1000_CEXTERR);
+	E1000_READ_REG(hw, E1000_TSCTC);
+	E1000_READ_REG(hw, E1000_TSCTFC);
+#endif
+}
+
+static struct pci_device_id e1000_82543_nics[] = {
+     PCI_ROM(0x8086, 0x1001, "E1000_DEV_ID_82543GC_FIBER", "E1000_DEV_ID_82543GC_FIBER", e1000_82543),
+     PCI_ROM(0x8086, 0x1004, "E1000_DEV_ID_82543GC_COPPER", "E1000_DEV_ID_82543GC_COPPER", e1000_82543),
+     PCI_ROM(0x8086, 0x1008, "E1000_DEV_ID_82544EI_COPPER", "E1000_DEV_ID_82544EI_COPPER", e1000_82544),
+     PCI_ROM(0x8086, 0x1009, "E1000_DEV_ID_82544EI_FIBER", "E1000_DEV_ID_82544EI_FIBER", e1000_82544),
+     PCI_ROM(0x8086, 0x100C, "E1000_DEV_ID_82544GC_COPPER", "E1000_DEV_ID_82544GC_COPPER", e1000_82544),
+     PCI_ROM(0x8086, 0x100D, "E1000_DEV_ID_82544GC_LOM", "E1000_DEV_ID_82544GC_LOM", e1000_82544),
+};
+
+struct pci_driver e1000_82543_driver __pci_driver = {
+	.ids = e1000_82543_nics,
+	.id_count = (sizeof (e1000_82543_nics) / sizeof (e1000_82543_nics[0])),
+	.probe = e1000_probe,
+	.remove = e1000_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.h
new file mode 100644
index 0000000..30073e8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_82543.h
@@ -0,0 +1,45 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_82543_H_
+#define _E1000_82543_H_
+
+#define PHY_PREAMBLE      0xFFFFFFFF
+#define PHY_PREAMBLE_SIZE 32
+#define PHY_SOF           0x1
+#define PHY_OP_READ       0x2
+#define PHY_OP_WRITE      0x1
+#define PHY_TURNAROUND    0x2
+
+#define TBI_COMPAT_ENABLED 0x1 /* Global "knob" for the workaround */
+/* If TBI_COMPAT_ENABLED, then this is the current state (on/off) */
+#define TBI_SBP_ENABLED    0x2
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.c
new file mode 100644
index 0000000..72aac4c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.c
@@ -0,0 +1,1108 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000_api.h"
+
+/**
+ *  e1000_init_mac_params - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the MAC
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 e1000_init_mac_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.ops.init_params) {
+		ret_val = hw->mac.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("MAC Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("mac.init_mac_params was NULL\n");
+		ret_val = -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the NVM
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 e1000_init_nvm_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->nvm.ops.init_params) {
+		ret_val = hw->nvm.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("NVM Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("nvm.init_nvm_params was NULL\n");
+		ret_val = -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_phy_params - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the PHY
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 e1000_init_phy_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.ops.init_params) {
+		ret_val = hw->phy.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("PHY Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("phy.init_phy_params was NULL\n");
+		ret_val =  -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_mac_type - Sets MAC type
+ *  @hw: pointer to the HW structure
+ *
+ *  This function sets the mac type of the adapter based on the
+ *  device ID stored in the hw structure.
+ *  MUST BE FIRST FUNCTION CALLED (explicitly or through
+ *  e1000_setup_init_funcs()).
+ **/
+s32 e1000_set_mac_type(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_set_mac_type");
+
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82542:
+		mac->type = e1000_82542;
+		break;
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+		mac->type = e1000_82543;
+		break;
+	case E1000_DEV_ID_82544EI_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82544GC_COPPER:
+	case E1000_DEV_ID_82544GC_LOM:
+		mac->type = e1000_82544;
+		break;
+	case E1000_DEV_ID_82540EM:
+	case E1000_DEV_ID_82540EM_LOM:
+	case E1000_DEV_ID_82540EP:
+	case E1000_DEV_ID_82540EP_LOM:
+	case E1000_DEV_ID_82540EP_LP:
+		mac->type = e1000_82540;
+		break;
+	case E1000_DEV_ID_82545EM_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+		mac->type = e1000_82545;
+		break;
+	case E1000_DEV_ID_82545GM_COPPER:
+	case E1000_DEV_ID_82545GM_FIBER:
+	case E1000_DEV_ID_82545GM_SERDES:
+		mac->type = e1000_82545_rev_3;
+		break;
+	case E1000_DEV_ID_82546EB_COPPER:
+	case E1000_DEV_ID_82546EB_FIBER:
+	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+		mac->type = e1000_82546;
+		break;
+	case E1000_DEV_ID_82546GB_COPPER:
+	case E1000_DEV_ID_82546GB_FIBER:
+	case E1000_DEV_ID_82546GB_SERDES:
+	case E1000_DEV_ID_82546GB_PCIE:
+	case E1000_DEV_ID_82546GB_QUAD_COPPER:
+	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+		mac->type = e1000_82546_rev_3;
+		break;
+	case E1000_DEV_ID_82541EI:
+	case E1000_DEV_ID_82541EI_MOBILE:
+	case E1000_DEV_ID_82541ER_LOM:
+		mac->type = e1000_82541;
+		break;
+	case E1000_DEV_ID_82541ER:
+	case E1000_DEV_ID_82541GI:
+	case E1000_DEV_ID_82541GI_LF:
+	case E1000_DEV_ID_82541GI_MOBILE:
+		mac->type = e1000_82541_rev_2;
+		break;
+	case E1000_DEV_ID_82547EI:
+	case E1000_DEV_ID_82547EI_MOBILE:
+		mac->type = e1000_82547;
+		break;
+	case E1000_DEV_ID_82547GI:
+		mac->type = e1000_82547_rev_2;
+		break;
+	default:
+		/* Should never have loaded on this device */
+		ret_val = -E1000_ERR_MAC_INIT;
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_init_funcs - Initializes function pointers
+ *  @hw: pointer to the HW structure
+ *  @init_device: true will initialize the rest of the function pointers
+ *                 getting the device ready for use.  false will only set
+ *                 MAC type and the function pointers for the other init
+ *                 functions.  Passing false will not generate any hardware
+ *                 reads or writes.
+ *
+ *  This function must be called by a driver in order to use the rest
+ *  of the 'shared' code files. Called by drivers only.
+ **/
+s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
+{
+	s32 ret_val;
+
+	/* Can't do much good without knowing the MAC type. */
+	ret_val = e1000_set_mac_type(hw);
+	if (ret_val) {
+		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
+		goto out;
+	}
+
+	if (!hw->hw_addr) {
+		DEBUGOUT("ERROR: Registers not mapped\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Init function pointers to generic implementations. We do this first
+	 * allowing a driver module to override it afterward.
+	 */
+	e1000_init_mac_ops_generic(hw);
+	e1000_init_phy_ops_generic(hw);
+	e1000_init_nvm_ops_generic(hw);
+
+	/*
+	 * Set up the init function pointers. These are functions within the
+	 * adapter family file that sets up function pointers for the rest of
+	 * the functions in that family.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82542:
+		e1000_init_function_pointers_82542(hw);
+		break;
+	case e1000_82543:
+	case e1000_82544:
+		e1000_init_function_pointers_82543(hw);
+		break;
+	case e1000_82540:
+	case e1000_82545:
+	case e1000_82545_rev_3:
+	case e1000_82546:
+	case e1000_82546_rev_3:
+		e1000_init_function_pointers_82540(hw);
+		break;
+	case e1000_82541:
+	case e1000_82541_rev_2:
+	case e1000_82547:
+	case e1000_82547_rev_2:
+		e1000_init_function_pointers_82541(hw);
+		break;
+	default:
+		DEBUGOUT("Hardware not supported\n");
+		ret_val = -E1000_ERR_CONFIG;
+		break;
+	}
+
+	/*
+	 * Initialize the rest of the function pointers. These require some
+	 * register reads/writes in some cases.
+	 */
+	if (!(ret_val) && init_device) {
+		ret_val = e1000_init_mac_params(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = e1000_init_nvm_params(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = e1000_init_phy_params(hw);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_bus_info - Obtain bus information for adapter
+ *  @hw: pointer to the HW structure
+ *
+ *  This will obtain information about the HW bus for which the
+ *  adapter is attached and stores it in the hw structure. This is a
+ *  function pointer entry point called by drivers.
+ **/
+s32 e1000_get_bus_info(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.get_bus_info)
+		return hw->mac.ops.get_bus_info(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  This clears the VLAN filter table on the adapter. This is a function
+ *  pointer entry point called by drivers.
+ **/
+void e1000_clear_vfta(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.clear_vfta)
+		hw->mac.ops.clear_vfta(hw);
+}
+
+/**
+ *  e1000_write_vfta - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: the 32-bit offset in which to write the value to.
+ *  @value: the 32-bit value to write at location offset.
+ *
+ *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
+ *  table. This is a function pointer entry point called by drivers.
+ **/
+void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	if (hw->mac.ops.write_vfta)
+		hw->mac.ops.write_vfta(hw, offset, value);
+}
+
+/**
+ *  e1000_update_mc_addr_list - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates the Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
+                               u32 mc_addr_count)
+{
+	if (hw->mac.ops.update_mc_addr_list)
+		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
+		                                mc_addr_count);
+}
+
+/**
+ *  e1000_force_mac_fc - Force MAC flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings. Currently no func pointer exists
+ *  and all implementations are handled in the generic version of this
+ *  function.
+ **/
+s32 e1000_force_mac_fc(struct e1000_hw *hw)
+{
+	return e1000_force_mac_fc_generic(hw);
+}
+
+/**
+ *  e1000_check_for_link - Check/Store link connection
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks the link condition of the adapter and stores the
+ *  results in the hw->mac structure. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 e1000_check_for_link(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.check_for_link)
+		return hw->mac.ops.check_for_link(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+#if 0
+/**
+ *  e1000_check_mng_mode - Check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point called by drivers.
+ **/
+bool e1000_check_mng_mode(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.check_mng_mode)
+		return hw->mac.ops.check_mng_mode(hw);
+
+	return false;
+}
+
+/**
+ *  e1000_mng_write_dhcp_info - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
+{
+	return e1000_mng_write_dhcp_info_generic(hw, buffer, length);
+}
+#endif
+
+/**
+ *  e1000_reset_hw - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 e1000_reset_hw(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.reset_hw)
+		return hw->mac.ops.reset_hw(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_init_hw - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation. This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 e1000_init_hw(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.init_hw)
+		return hw->mac.ops.init_hw(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_setup_link - Configures link and flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  This configures link and flow control settings for the adapter. This
+ *  is a function pointer entry point called by drivers. While modules can
+ *  also call this, they probably call their own version of this function.
+ **/
+s32 e1000_setup_link(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.setup_link)
+		return hw->mac.ops.setup_link(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_get_speed_and_duplex - Returns current speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to a 16-bit value to store the speed
+ *  @duplex: pointer to a 16-bit value to store the duplex.
+ *
+ *  This returns the speed and duplex of the adapter in the two 'out'
+ *  variables passed in. This is a function pointer entry point called
+ *  by drivers.
+ **/
+s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+	if (hw->mac.ops.get_link_up_info)
+		return hw->mac.ops.get_link_up_info(hw, speed, duplex);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_setup_led - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 e1000_setup_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.setup_led)
+		return hw->mac.ops.setup_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_cleanup_led - Restores SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This restores the SW controllable LED to the value saved off by
+ *  e1000_setup_led. This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_cleanup_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.cleanup_led)
+		return hw->mac.ops.cleanup_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_blink_led - Blink SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This starts the adapter LED blinking. Request the LED to be setup first
+ *  and cleaned up after. This is a function pointer entry point called by
+ *  drivers.
+ **/
+s32 e1000_blink_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.blink_led)
+		return hw->mac.ops.blink_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_id_led_init - store LED configurations in SW
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the LED config in SW. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 e1000_id_led_init(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.id_led_init)
+		return hw->mac.ops.id_led_init(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_led_on - Turn on SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED on. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 e1000_led_on(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.led_on)
+		return hw->mac.ops.led_on(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_led_off - Turn off SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED off. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 e1000_led_off(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.led_off)
+		return hw->mac.ops.led_off(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_reset_adaptive - Reset adaptive IFS
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the adaptive IFS. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000_reset_adaptive(struct e1000_hw *hw)
+{
+	e1000_reset_adaptive_generic(hw);
+}
+
+/**
+ *  e1000_update_adaptive - Update adaptive IFS
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates adapter IFS. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000_update_adaptive(struct e1000_hw *hw)
+{
+	e1000_update_adaptive_generic(hw);
+}
+
+/**
+ *  e1000_disable_pcie_master - Disable PCI-Express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests. Currently no func pointer exists and all implementations are
+ *  handled in the generic version of this function.
+ **/
+s32 e1000_disable_pcie_master(struct e1000_hw *hw)
+{
+	return e1000_disable_pcie_master_generic(hw);
+}
+
+/**
+ *  e1000_config_collision_dist - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup.
+ **/
+void e1000_config_collision_dist(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.config_collision_dist)
+		hw->mac.ops.config_collision_dist(hw);
+}
+
+/**
+ *  e1000_rar_set - Sets a receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: address to set the RAR to
+ *  @index: the RAR to set
+ *
+ *  Sets a Receive Address Register (RAR) to the specified address.
+ **/
+void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	if (hw->mac.ops.rar_set)
+		hw->mac.ops.rar_set(hw, addr, index);
+}
+
+/**
+ *  e1000_validate_mdi_setting - Ensures valid MDI/MDIX SW state
+ *  @hw: pointer to the HW structure
+ *
+ *  Ensures that the MDI/MDIX SW state is valid.
+ **/
+s32 e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.validate_mdi_setting)
+		return hw->mac.ops.validate_mdi_setting(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_mta_set - Sets multicast table bit
+ *  @hw: pointer to the HW structure
+ *  @hash_value: Multicast hash value.
+ *
+ *  This sets the bit in the multicast table corresponding to the
+ *  hash value.  This is a function pointer entry point called by drivers.
+ **/
+void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+	if (hw->mac.ops.mta_set)
+		hw->mac.ops.mta_set(hw, hash_value);
+}
+
+/**
+ *  e1000_hash_mc_addr - Determines address location in multicast table
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: Multicast address to hash.
+ *
+ *  This hashes an address to determine its location in the multicast
+ *  table. Currently no func pointer exists and all implementations
+ *  are handled in the generic version of this function.
+ **/
+u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+	return e1000_hash_mc_addr_generic(hw, mc_addr);
+}
+
+#if 0
+/**
+ *  e1000_enable_tx_pkt_filtering - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+	return e1000_enable_tx_pkt_filtering_generic(hw);
+}
+
+/**
+ *  e1000_mng_host_if_write - Writes to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 e1000_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length,
+                            u16 offset, u8 *sum)
+{
+	if (hw->mac.ops.mng_host_if_write)
+		return hw->mac.ops.mng_host_if_write(hw, buffer, length,
+		                                     offset, sum);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ *  e1000_mng_write_cmd_header - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+                               struct e1000_host_mng_command_header *hdr)
+{
+	if (hw->mac.ops.mng_write_cmd_header)
+		return hw->mac.ops.mng_write_cmd_header(hw, hdr);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ *  e1000_mng_enable_host_if - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 e1000_mng_enable_host_if(struct e1000_hw * hw)
+{
+	if (hw->mac.ops.mng_enable_host_if)
+		return hw->mac.ops.mng_enable_host_if(hw);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+#endif
+
+/**
+ *  e1000_wait_autoneg - Waits for autonegotiation completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for autoneg to complete. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+s32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.wait_autoneg)
+		return hw->mac.ops.wait_autoneg(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_check_reset_block - Verifies PHY can be reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks if the PHY is in a state that can be reset or if manageability
+ *  has it tied up. This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.check_reset_block)
+		return hw->phy.ops.check_reset_block(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_read_phy_reg - Reads PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to read
+ *  @data: the buffer to store the 16-bit read.
+ *
+ *  Reads the PHY register and returns the value in data.
+ *  This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	if (hw->phy.ops.read_reg)
+		return hw->phy.ops.read_reg(hw, offset, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_write_phy_reg - Writes PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to write
+ *  @data: the value to write.
+ *
+ *  Writes the PHY register at offset with the value in data.
+ *  This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	if (hw->phy.ops.write_reg)
+		return hw->phy.ops.write_reg(hw, offset, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_release_phy - Generic release PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return if silicon family does not require a semaphore when accessing the
+ *  PHY.
+ **/
+void e1000_release_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.release)
+		hw->phy.ops.release(hw);
+}
+
+/**
+ *  e1000_acquire_phy - Generic acquire PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family does not require a semaphore when
+ *  accessing the PHY.
+ **/
+s32 e1000_acquire_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.acquire)
+		return hw->phy.ops.acquire(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_read_kmrn_reg - Reads register using Kumeran interface
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to read
+ *  @data: the location to store the 16-bit value read.
+ *
+ *  Reads a register out of the Kumeran interface. Currently no func pointer
+ *  exists and all implementations are handled in the generic version of
+ *  this function.
+ **/
+s32 e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return e1000_read_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ *  e1000_write_kmrn_reg - Writes register using Kumeran interface
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to write
+ *  @data: the value to write.
+ *
+ *  Writes a register to the Kumeran interface. Currently no func pointer
+ *  exists and all implementations are handled in the generic version of
+ *  this function.
+ **/
+s32 e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return e1000_write_kmrn_reg_generic(hw, offset, data);
+}
+
+#if 0
+/**
+ *  e1000_get_cable_length - Retrieves cable length estimation
+ *  @hw: pointer to the HW structure
+ *
+ *  This function estimates the cable length and stores them in
+ *  hw->phy.min_length and hw->phy.max_length. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_cable_length)
+		return hw->phy.ops.get_cable_length(hw);
+
+	return E1000_SUCCESS;
+}
+#endif
+
+/**
+ *  e1000_get_phy_info - Retrieves PHY information from registers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function gets some information from various PHY registers and
+ *  populates hw->phy values with it. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_info)
+		return hw->phy.ops.get_info(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_phy_hw_reset - Hard PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs a hard PHY reset. This is a function pointer entry point called
+ *  by drivers.
+ **/
+s32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.reset)
+		return hw->phy.ops.reset(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_phy_commit - Soft PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs a soft PHY reset on those that apply. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 e1000_phy_commit(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.commit)
+		return hw->phy.ops.commit(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_set_d0_lplu_state - Sets low power link up state for D0
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D0
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D0
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.  This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+	if (hw->phy.ops.set_d0_lplu_state)
+		return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.  This is a function pointer entry point called by drivers.
+ **/
+s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+	if (hw->phy.ops.set_d3_lplu_state)
+		return hw->phy.ops.set_d3_lplu_state(hw, active);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_read_mac_addr - Reads MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MAC address out of the adapter and stores it in the HW structure.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+s32 e1000_read_mac_addr(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.read_mac_addr)
+		return hw->mac.ops.read_mac_addr(hw);
+
+	return e1000_read_mac_addr_generic(hw);
+}
+
+/**
+ *  e1000_read_pba_num - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
+{
+	return e1000_read_pba_num_generic(hw, pba_num);
+}
+
+/**
+ *  e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Validates the NVM checksum is correct. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.validate)
+		return hw->nvm.ops.validate(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_update_nvm_checksum - Updates NVM (EEPROM) checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the NVM checksum. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+s32 e1000_update_nvm_checksum(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.update)
+		return hw->nvm.ops.update(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_reload_nvm - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+void e1000_reload_nvm(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.reload)
+		hw->nvm.ops.reload(hw);
+}
+
+/**
+ *  e1000_read_nvm - Reads NVM (EEPROM)
+ *  @hw: pointer to the HW structure
+ *  @offset: the word offset to read
+ *  @words: number of 16-bit words to read
+ *  @data: pointer to the properly sized buffer for the data.
+ *
+ *  Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	if (hw->nvm.ops.read)
+		return hw->nvm.ops.read(hw, offset, words, data);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  e1000_write_nvm - Writes to NVM (EEPROM)
+ *  @hw: pointer to the HW structure
+ *  @offset: the word offset to read
+ *  @words: number of 16-bit words to write
+ *  @data: pointer to the properly sized buffer for the data.
+ *
+ *  Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	if (hw->nvm.ops.write)
+		return hw->nvm.ops.write(hw, offset, words, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ * e1000_power_up_phy - Restores link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_up_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.power_up)
+		hw->phy.ops.power_up(hw);
+
+	e1000_setup_link(hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down PHY
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void e1000_power_down_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.power_down)
+		hw->phy.ops.power_down(hw);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.h
new file mode 100644
index 0000000..fc1e533
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_api.h
@@ -0,0 +1,127 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_API_H_
+#define _E1000_API_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+#include "e1000_hw.h"
+
+extern void    e1000_init_function_pointers_82542(struct e1000_hw *hw) __attribute__((weak));
+extern void    e1000_init_function_pointers_82543(struct e1000_hw *hw) __attribute__((weak));
+extern void    e1000_init_function_pointers_82540(struct e1000_hw *hw) __attribute__((weak));
+extern void    e1000_init_function_pointers_82541(struct e1000_hw *hw) __attribute__((weak));
+
+s32  e1000_set_mac_type(struct e1000_hw *hw);
+s32  e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device);
+s32  e1000_init_mac_params(struct e1000_hw *hw);
+s32  e1000_init_nvm_params(struct e1000_hw *hw);
+s32  e1000_init_phy_params(struct e1000_hw *hw);
+s32  e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_clear_vfta(struct e1000_hw *hw);
+void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+s32  e1000_force_mac_fc(struct e1000_hw *hw);
+s32  e1000_check_for_link(struct e1000_hw *hw);
+s32  e1000_reset_hw(struct e1000_hw *hw);
+s32  e1000_init_hw(struct e1000_hw *hw);
+s32  e1000_setup_link(struct e1000_hw *hw);
+s32  e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed,
+                                u16 *duplex);
+s32  e1000_disable_pcie_master(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+void e1000_mta_set(struct e1000_hw *hw, u32 hash_value);
+u32  e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
+void e1000_update_mc_addr_list(struct e1000_hw *hw,
+                               u8 *mc_addr_list, u32 mc_addr_count);
+s32  e1000_setup_led(struct e1000_hw *hw);
+s32  e1000_cleanup_led(struct e1000_hw *hw);
+s32  e1000_check_reset_block(struct e1000_hw *hw);
+s32  e1000_blink_led(struct e1000_hw *hw);
+s32  e1000_led_on(struct e1000_hw *hw);
+s32  e1000_led_off(struct e1000_hw *hw);
+s32 e1000_id_led_init(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+#if 0
+s32  e1000_get_cable_length(struct e1000_hw *hw);
+#endif
+s32  e1000_validate_mdi_setting(struct e1000_hw *hw);
+s32  e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_get_phy_info(struct e1000_hw *hw);
+void e1000_release_phy(struct e1000_hw *hw);
+s32  e1000_acquire_phy(struct e1000_hw *hw);
+s32  e1000_phy_hw_reset(struct e1000_hw *hw);
+s32  e1000_phy_commit(struct e1000_hw *hw);
+void e1000_power_up_phy(struct e1000_hw *hw);
+void e1000_power_down_phy(struct e1000_hw *hw);
+s32  e1000_read_mac_addr(struct e1000_hw *hw);
+s32  e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num);
+void e1000_reload_nvm(struct e1000_hw *hw);
+s32  e1000_update_nvm_checksum(struct e1000_hw *hw);
+s32  e1000_validate_nvm_checksum(struct e1000_hw *hw);
+s32  e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words,
+                     u16 *data);
+s32  e1000_wait_autoneg(struct e1000_hw *hw);
+s32  e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32  e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
+bool e1000_check_mng_mode(struct e1000_hw *hw);
+bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
+s32  e1000_mng_enable_host_if(struct e1000_hw *hw);
+s32  e1000_mng_host_if_write(struct e1000_hw *hw,
+                             u8 *buffer, u16 length, u16 offset, u8 *sum);
+s32  e1000_mng_write_cmd_header(struct e1000_hw *hw,
+                                struct e1000_host_mng_command_header *hdr);
+s32  e1000_mng_write_dhcp_info(struct e1000_hw * hw,
+                                    u8 *buffer, u16 length);
+u32  e1000_translate_register_82542(u32 reg) __attribute__((weak));
+
+extern int e1000_probe(struct pci_device *pdev);
+extern void e1000_remove(struct pci_device *pdev);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_defines.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_defines.h
new file mode 100644
index 0000000..c585f09
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_defines.h
@@ -0,0 +1,1416 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+#define E1000_WUS_ARP          E1000_WUFC_ARP
+#define E1000_WUS_IPV4         E1000_WUFC_IPV4
+#define E1000_WUS_IPV6         E1000_WUFC_IPV6
+#define E1000_WUS_FLX0         E1000_WUFC_FLX0
+#define E1000_WUS_FLX1         E1000_WUFC_FLX1
+#define E1000_WUS_FLX2         E1000_WUFC_FLX2
+#define E1000_WUS_FLX3         E1000_WUFC_FLX3
+#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
+                                                  * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
+                                                  * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_REG_ADDR         0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_PHY_ADDR         0x07000000
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_RESET            0x10000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK                 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x01
+#define E1000_SWFW_PHY0_SM  0x02
+#define E1000_SWFW_PHY1_SM  0x04
+#define E1000_SWFW_CSR_SM   0x08
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+                                             * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+                                               * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+                                           * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_CFG_PCS_EN             8
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_10            0
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_10          0
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
+                                                 * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
+                                            * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME   20
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+#define E1000_RFCTL_LEF                 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE       4
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_SPD_EN             0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K  0x0006    /* 6KB */
+#define E1000_PBA_8K  0x0008    /* 8KB */
+#define E1000_PBA_10K 0x000A    /* 10KB */
+#define E1000_PBA_12K 0x000C    /* 12KB */
+#define E1000_PBA_14K 0x000E    /* 14KB */
+#define E1000_PBA_16K 0x0010    /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB */
+#define E1000_PBA_64K 0x0040    /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
+                                            * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
+                                            * bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
+                                            * an interrupt */
+#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
+
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX      15
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
+#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_CC         0x10000000        /* Receive config change */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
+
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
+#define E1000_GCR_CAP_VER2              0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                           E1000_GCR_RXDSCW_NO_SNOOP      | \
+                           E1000_GCR_RXDSCR_NO_SNOOP      | \
+                           E1000_GCR_TXD_NO_SNOOP         | \
+                           E1000_GCR_TXDSCW_NO_SNOOP      | \
+                           E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Register */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT                 0x0003
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_VERSION                0x0005
+#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD         0x0007
+#define NVM_INIT_CONTROL1_REG      0x000A
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_FLASH_VERSION          0x0032
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+#define NVM_WORD0F_ANE              0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
+#define NVM_WORD0F_LPLU             0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_MAC_ADDR_OFFSET        0
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_RESERVED_WORD          0xFFFF
+#define NVM_PHY_CLASS_A            0x8000
+#define NVM_SERDES_AMPLITUDE_MASK  0x000F
+#define NVM_SIZE_MASK              0x1C00
+#define NVM_SIZE_SHIFT             10
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+#define NVM_SWDPIO_EXT_SHIFT       4
+
+/* NVM Commands - Microwire */
+#define NVM_READ_OPCODE_MICROWIRE  0x6  /* NVM read opcode */
+#define NVM_WRITE_OPCODE_MICROWIRE 0x5  /* NVM write opcode */
+#define NVM_ERASE_OPCODE_MICROWIRE 0x7  /* NVM erase opcode */
+#define NVM_EWEN_OPCODE_MICROWIRE  0x13 /* NVM erase/write enable */
+#define NVM_EWDS_OPCODE_MICROWIRE  0x10 /* NVM erase/write disable */
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+#define NVM_STATUS_WEN_SPI         0x02
+#define NVM_STATUS_BP0_SPI         0x04
+#define NVM_STATUS_BP1_SPI         0x08
+#define NVM_STATUS_WPEN_SPI        0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                              (ID_LED_OFF1_OFF2 <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCIX_COMMAND_REGISTER        0xE6
+#define PCIX_STATUS_REGISTER_LO      0xE8
+#define PCIX_STATUS_REGISTER_HI      0xEA
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+#define PCIE_DEVICE_CONTROL2         0x28
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+#define PCIX_STATUS_LO_FUNC_MASK     0x7
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+#define PCIE_DEVICE_CONTROL2_16ms    0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1011_I_REV_4     0x04
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+        GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS         \
+        GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE          \
+        GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2       \
+        GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR         \
+        GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT         \
+        GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+        GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+        GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL       \
+        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+        GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2     \
+        GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+        GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+        GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET          \
+        GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID         \
+        GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID           \
+        GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+        GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL     \
+        GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+        GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL           \
+        GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL         \
+        GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC     \
+        GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS        \
+        GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY         \
+        GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE       \
+        GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC           \
+        GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+
+
+#endif /* _E1000_DEFINES_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_hw.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_hw.h
new file mode 100644
index 0000000..753f75e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_hw.h
@@ -0,0 +1,728 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82542                    0x1000
+#define E1000_DEV_ID_82543GC_FIBER            0x1001
+#define E1000_DEV_ID_82543GC_COPPER           0x1004
+#define E1000_DEV_ID_82544EI_COPPER           0x1008
+#define E1000_DEV_ID_82544EI_FIBER            0x1009
+#define E1000_DEV_ID_82544GC_COPPER           0x100C
+#define E1000_DEV_ID_82544GC_LOM              0x100D
+#define E1000_DEV_ID_82540EM                  0x100E
+#define E1000_DEV_ID_82540EM_LOM              0x1015
+#define E1000_DEV_ID_82540EP_LOM              0x1016
+#define E1000_DEV_ID_82540EP                  0x1017
+#define E1000_DEV_ID_82540EP_LP               0x101E
+#define E1000_DEV_ID_82545EM_COPPER           0x100F
+#define E1000_DEV_ID_82545EM_FIBER            0x1011
+#define E1000_DEV_ID_82545GM_COPPER           0x1026
+#define E1000_DEV_ID_82545GM_FIBER            0x1027
+#define E1000_DEV_ID_82545GM_SERDES           0x1028
+#define E1000_DEV_ID_82546EB_COPPER           0x1010
+#define E1000_DEV_ID_82546EB_FIBER            0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER      0x101D
+#define E1000_DEV_ID_82546GB_COPPER           0x1079
+#define E1000_DEV_ID_82546GB_FIBER            0x107A
+#define E1000_DEV_ID_82546GB_SERDES           0x107B
+#define E1000_DEV_ID_82546GB_PCIE             0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER      0x1099
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_82541EI                  0x1013
+#define E1000_DEV_ID_82541EI_MOBILE           0x1018
+#define E1000_DEV_ID_82541ER_LOM              0x1014
+#define E1000_DEV_ID_82541ER                  0x1078
+#define E1000_DEV_ID_82541GI                  0x1076
+#define E1000_DEV_ID_82541GI_LF               0x107C
+#define E1000_DEV_ID_82541GI_MOBILE           0x1077
+#define E1000_DEV_ID_82547EI                  0x1019
+#define E1000_DEV_ID_82547EI_MOBILE           0x101A
+#define E1000_DEV_ID_82547GI                  0x1075
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0     0
+#define E1000_FUNC_1     1
+
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82542,
+	e1000_82543,
+	e1000_82544,
+	e1000_82540,
+	e1000_82545,
+	e1000_82545_rev_3,
+	e1000_82546,
+	e1000_82546_rev_3,
+	e1000_82541,
+	e1000_82541_rev_2,
+	e1000_82547,
+	e1000_82547_rev_2,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum e1000_media_type {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_eeprom_microwire,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large,
+	e1000_nvm_override_microwire_small,
+	e1000_nvm_override_microwire_large
+};
+
+enum e1000_phy_type {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+};
+
+enum e1000_bus_type {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+enum e1000_ffe_config {
+	e1000_ffe_config_enabled = 0,
+	e1000_ffe_config_active,
+	e1000_ffe_config_blocked
+};
+
+enum e1000_dsp_config {
+	e1000_dsp_config_disabled = 0,
+	e1000_dsp_config_enabled,
+	e1000_dsp_config_activated,
+	e1000_dsp_config_undefined = 0xFF
+};
+
+enum e1000_ms_type {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+};
+
+enum e1000_serdes_link_state {
+	e1000_serdes_link_down = 0,
+	e1000_serdes_link_autoneg_progress,
+	e1000_serdes_link_autoneg_complete,
+	e1000_serdes_link_forced_up
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	__le64 buffer_addr; /* Address of the descriptor's data buffer */
+	__le16 length;      /* Length of data DMAed into data buffer */
+	__le16 csum;        /* Packet checksum */
+	u8  status;         /* Descriptor status */
+	u8  errors;         /* Descriptor Errors */
+	__le16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		__le64 buffer_addr;
+		__le64 reserved;
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;         /* RSS Hash */
+				struct {
+					__le16 ip_id;  /* IP id */
+					__le16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length;
+			__le16 vlan;          /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		__le64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;           /* RSS Hash */
+				struct {
+					__le16 ip_id;    /* IP id */
+					__le16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length0;       /* length of buffer 0 */
+			__le16 vlan;          /* VLAN tag */
+		} middle;
+		struct {
+			__le16 header_status;
+			__le16 length[3];     /* length of buffers 1-3 */
+		} upper;
+		__le64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 cso;           /* Checksum offset */
+			u8 cmd;           /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 css;           /* Checksum start */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		__le32 ip_config;
+		struct {
+			u8 ipcss;         /* IP checksum start */
+			u8 ipcso;         /* IP checksum offset */
+			__le16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		__le32 tcp_config;
+		struct {
+			u8 tucss;         /* TCP checksum start */
+			u8 tucso;         /* TCP checksum offset */
+			__le16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	__le32 cmd_and_length;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 hdr_len;       /* Header length */
+			__le16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 popts;         /* Packet Options */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 tor;
+	u64 tot;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+	u64 cbtmpc;
+	u64 htdpmc;
+	u64 cbrdpc;
+	u64 cbrmpc;
+	u64 rpthc;
+	u64 hgptc;
+	u64 htcbdpc;
+	u64 hgorc;
+	u64 hgotc;
+	u64 lenerrs;
+	u64 scvpc;
+	u64 hrmpc;
+	u64 doosync;
+};
+
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_manage.h"
+
+struct e1000_mac_operations {
+	/* Function pointers for the MAC. */
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*id_led_init)(struct e1000_hw *);
+	s32  (*blink_led)(struct e1000_hw *);
+	s32  (*check_for_link)(struct e1000_hw *);
+	bool (*check_mng_mode)(struct e1000_hw *hw);
+	s32  (*cleanup_led)(struct e1000_hw *);
+	void (*clear_hw_cntrs)(struct e1000_hw *);
+	void (*clear_vfta)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	void (*set_lan_id)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	s32  (*led_on)(struct e1000_hw *);
+	s32  (*led_off)(struct e1000_hw *);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+	s32  (*setup_led)(struct e1000_hw *);
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
+	void (*mta_set)(struct e1000_hw *, u32);
+	void (*config_collision_dist)(struct e1000_hw *);
+	void (*rar_set)(struct e1000_hw *, u8*, u32);
+	s32  (*read_mac_addr)(struct e1000_hw *);
+	s32  (*validate_mdi_setting)(struct e1000_hw *);
+	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
+	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
+                      struct e1000_host_mng_command_header*);
+	s32  (*mng_enable_host_if)(struct e1000_hw *);
+	s32  (*wait_autoneg)(struct e1000_hw *);
+};
+
+struct e1000_phy_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*check_polarity)(struct e1000_hw *);
+	s32  (*check_reset_block)(struct e1000_hw *);
+	s32  (*commit)(struct e1000_hw *);
+#if 0
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+#endif
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+#if 0
+	s32  (*get_cable_length)(struct e1000_hw *);
+#endif
+	s32  (*get_info)(struct e1000_hw *);
+	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
+	void (*release)(struct e1000_hw *);
+	s32  (*reset)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_reg)(struct e1000_hw *, u32, u16);
+	void (*power_up)(struct e1000_hw *);
+	void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release)(struct e1000_hw *);
+	void (*reload)(struct e1000_hw *);
+	s32  (*update)(struct e1000_hw *);
+	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+	s32  (*validate)(struct e1000_hw *);
+	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 mc_filter_type;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+
+	/* Maximum size of the MTA register table in all supported adapters */
+	#define MAX_MTA_REG 128
+	u32 mta_shadow[MAX_MTA_REG];
+	u16 rar_entry_count;
+
+	u8  forced_speed_duplex;
+
+	bool adaptive_ifs;
+	bool arc_subsystem_valid;
+	bool asf_firmware_present;
+	bool autoneg;
+	bool autoneg_failed;
+	bool get_link_status;
+	bool in_ifs_mode;
+	bool report_tx_early;
+	enum e1000_serdes_link_state serdes_link_state;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+	enum e1000_phy_type type;
+
+	enum e1000_1000t_rx_status local_rx;
+	enum e1000_1000t_rx_status remote_rx;
+	enum e1000_ms_type ms_type;
+	enum e1000_ms_type original_ms_type;
+	enum e1000_rev_polarity cable_polarity;
+	enum e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	enum e1000_media_type media_type;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool reset_disable;
+	bool speed_downgraded;
+	bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+	enum e1000_nvm_type type;
+	enum e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_type type;
+	enum e1000_bus_speed speed;
+	enum e1000_bus_width width;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+	u32 high_water;          /* Flow control high-water mark */
+	u32 low_water;           /* Flow control low-water mark */
+	u16 pause_time;          /* Flow control pause timer */
+	bool send_xon;           /* Flow control send XON */
+	bool strict_ieee;        /* Strict IEEE mode */
+	enum e1000_fc_mode current_mode; /* FC mode in effect */
+	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+struct e1000_dev_spec_82541 {
+	enum e1000_dsp_config dsp_config;
+	enum e1000_ffe_config ffe_config;
+	u16 spd_default;
+	bool phy_init_script;
+};
+
+struct e1000_dev_spec_82542 {
+	bool dma_fairness;
+};
+
+struct e1000_dev_spec_82543 {
+	u32  tbi_compatibility;
+	bool dma_fairness;
+	bool init_phy_disabled;
+};
+
+struct e1000_hw {
+	void *back;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	union {
+		struct e1000_dev_spec_82541	_82541;
+		struct e1000_dev_spec_82542	_82542;
+		struct e1000_dev_spec_82543	_82543;
+	} dev_spec;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+#include "e1000_82541.h"
+#include "e1000_82543.h"
+
+/* These functions must be implemented by drivers */
+void e1000_pci_clear_mwi(struct e1000_hw *hw);
+void e1000_pci_set_mwi(struct e1000_hw *hw);
+s32  e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
+void e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.c
new file mode 100644
index 0000000..2351387
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.c
@@ -0,0 +1,2196 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000_api.h"
+
+static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
+static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+
+/**
+ *  e1000_init_mac_ops_generic - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_mac_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	DEBUGFUNC("e1000_init_mac_ops_generic");
+
+	/* General Setup */
+	mac->ops.init_params = e1000_null_ops_generic;
+	mac->ops.init_hw = e1000_null_ops_generic;
+	mac->ops.reset_hw = e1000_null_ops_generic;
+	mac->ops.setup_physical_interface = e1000_null_ops_generic;
+	mac->ops.get_bus_info = e1000_null_ops_generic;
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
+	mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
+	mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
+	mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
+	/* LED */
+	mac->ops.cleanup_led = e1000_null_ops_generic;
+	mac->ops.setup_led = e1000_null_ops_generic;
+	mac->ops.blink_led = e1000_null_ops_generic;
+	mac->ops.led_on = e1000_null_ops_generic;
+	mac->ops.led_off = e1000_null_ops_generic;
+	/* LINK */
+	mac->ops.setup_link = e1000_null_ops_generic;
+	mac->ops.get_link_up_info = e1000_null_link_info;
+	mac->ops.check_for_link = e1000_null_ops_generic;
+	mac->ops.wait_autoneg = e1000_wait_autoneg_generic;
+#if 0
+	/* Management */
+	mac->ops.check_mng_mode = e1000_null_mng_mode;
+	mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic;
+	mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic;
+	mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic;
+#endif
+	/* VLAN, MC, etc. */
+	mac->ops.update_mc_addr_list = e1000_null_update_mc;
+	mac->ops.clear_vfta = e1000_null_mac_generic;
+	mac->ops.write_vfta = e1000_null_write_vfta;
+	mac->ops.mta_set = e1000_null_mta_set;
+	mac->ops.rar_set = e1000_rar_set_generic;
+	mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
+}
+
+/**
+ *  e1000_null_ops_generic - No-op function, returns 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_ops_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_null_ops_generic");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_mac_generic - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_mac_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_null_mac_generic");
+	return;
+}
+
+/**
+ *  e1000_null_link_info - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_link_info(struct e1000_hw *hw __unused,
+                         u16 *s __unused, u16 *d __unused)
+{
+	DEBUGFUNC("e1000_null_link_info");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_mng_mode - No-op function, return false
+ *  @hw: pointer to the HW structure
+ **/
+bool e1000_null_mng_mode(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_null_mng_mode");
+	return false;
+}
+
+/**
+ *  e1000_null_update_mc - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_update_mc(struct e1000_hw *hw __unused,
+                          u8 *h __unused, u32 a __unused)
+{
+	DEBUGFUNC("e1000_null_update_mc");
+	return;
+}
+
+/**
+ *  e1000_null_write_vfta - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_write_vfta(struct e1000_hw *hw __unused,
+                           u32 a __unused, u32 b __unused)
+{
+	DEBUGFUNC("e1000_null_write_vfta");
+	return;
+}
+
+/**
+ *  e1000_null_set_mta - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_mta_set(struct e1000_hw *hw __unused, u32 a __unused)
+{
+	DEBUGFUNC("e1000_null_mta_set");
+	return;
+}
+
+/**
+ *  e1000_null_rar_set - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_rar_set(struct e1000_hw *hw __unused, u8 *h __unused,
+                        u32 a __unused)
+{
+	DEBUGFUNC("e1000_null_rar_set");
+	return;
+}
+
+/**
+ *  e1000_get_bus_info_pci_generic - Get PCI(x) bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCI/PCIx), and PCI(-x) function.
+ **/
+s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_bus_info *bus = &hw->bus;
+	u32 status = E1000_READ_REG(hw, E1000_STATUS);
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_get_bus_info_pci_generic");
+
+	/* PCI or PCI-X? */
+	bus->type = (status & E1000_STATUS_PCIX_MODE)
+			? e1000_bus_type_pcix
+			: e1000_bus_type_pci;
+
+	/* Bus speed */
+	if (bus->type == e1000_bus_type_pci) {
+		bus->speed = (status & E1000_STATUS_PCI66)
+		             ? e1000_bus_speed_66
+		             : e1000_bus_speed_33;
+	} else {
+		switch (status & E1000_STATUS_PCIX_SPEED) {
+		case E1000_STATUS_PCIX_SPEED_66:
+			bus->speed = e1000_bus_speed_66;
+			break;
+		case E1000_STATUS_PCIX_SPEED_100:
+			bus->speed = e1000_bus_speed_100;
+			break;
+		case E1000_STATUS_PCIX_SPEED_133:
+			bus->speed = e1000_bus_speed_133;
+			break;
+		default:
+			bus->speed = e1000_bus_speed_reserved;
+			break;
+		}
+	}
+
+	/* Bus width */
+	bus->width = (status & E1000_STATUS_BUS64)
+	             ? e1000_bus_width_64
+	             : e1000_bus_width_32;
+
+	/* Which PCI(-X) function? */
+	mac->ops.set_lan_id(hw);
+
+	return ret_val;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_get_bus_info_pcie_generic - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_bus_info *bus = &hw->bus;
+
+	s32 ret_val;
+	u16 pcie_link_status;
+
+	DEBUGFUNC("e1000_get_bus_info_pcie_generic");
+
+	bus->type = e1000_bus_type_pci_express;
+	bus->speed = e1000_bus_speed_2500;
+
+	ret_val = e1000_read_pcie_cap_reg(hw,
+	                                  PCIE_LINK_STATUS,
+	                                  &pcie_link_status);
+	if (ret_val)
+		bus->width = e1000_bus_width_unknown;
+	else
+		bus->width = (enum e1000_bus_width)((pcie_link_status &
+		                                PCIE_LINK_WIDTH_MASK) >>
+		                               PCIE_LINK_WIDTH_SHIFT);
+
+	mac->ops.set_lan_id(hw);
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u32 reg;
+
+	/*
+	 * The status register reports the correct function number
+	 * for the device regardless of function swap state.
+	 */
+	reg = E1000_READ_REG(hw, E1000_STATUS);
+	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/**
+ *  e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading PCI config space.
+ **/
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u16 pci_header_type;
+	u32 status;
+
+	e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		bus->func = (status & E1000_STATUS_FUNC_MASK)
+		            >> E1000_STATUS_FUNC_SHIFT;
+	} else {
+		bus->func = 0;
+	}
+}
+
+/**
+ *  e1000_set_lan_id_single_port - Set LAN id for a single port device
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the LAN function id to zero for a single port device.
+ **/
+void e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+
+	bus->func = 0;
+}
+
+/**
+ *  e1000_clear_vfta_generic - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void e1000_clear_vfta_generic(struct e1000_hw *hw)
+{
+	u32 offset;
+
+	DEBUGFUNC("e1000_clear_vfta_generic");
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  e1000_write_vfta_generic - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	DEBUGFUNC("e1000_write_vfta_generic");
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_init_rx_addrs_generic - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+	u8 mac_addr[ETH_ADDR_LEN] = {0};
+
+	DEBUGFUNC("e1000_init_rx_addrs_generic");
+
+	/* Setup the receive address */
+	DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++)
+		hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ *  e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address. If an
+ *  alternate MAC address is found it is programmed into RAR0, replacing
+ *  the permanent address that was installed into RAR0 by the Si on reset.
+ *  This function will return SUCCESS unless it encounters an error while
+ *  reading the EEPROM.
+ **/
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 i;
+	s32 ret_val = E1000_SUCCESS;
+	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+	u8 alt_mac_addr[ETH_ADDR_LEN];
+
+	DEBUGFUNC("e1000_check_alt_mac_addr_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+	                         &nvm_alt_mac_addr_offset);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (nvm_alt_mac_addr_offset == 0xFFFF) {
+		/* There is no Alternate MAC Address */
+		goto out;
+	}
+
+	if (hw->bus.func == E1000_FUNC_1)
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = nvm_alt_mac_addr_offset + (i >> 1);
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+
+		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+	}
+
+	/* if multicast bit is set, the alternate address will not be used */
+	if (alt_mac_addr[0] & 0x01) {
+		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
+		goto out;
+	}
+
+	/*
+	 * We have a valid alternate MAC address, and we want to treat it the
+	 * same as the normal permanent MAC address stored by the HW into the
+	 * RAR. Do this by mapping this address into RAR0.
+	 */
+	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_rar_set_generic - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	DEBUGFUNC("e1000_rar_set_generic");
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+	           ((u32) addr[1] << 8) |
+	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	/* If MAC address zero, no need to set the AV bit */
+	if (rar_low || rar_high)
+		rar_high |= E1000_RAH_AV;
+
+	/*
+	 * Some bridges will combine consecutive 32-bit writes into
+	 * a single burst write, which will malfunction on some parts.
+	 * The flushes avoid this.
+	 */
+	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+	E1000_WRITE_FLUSH(hw);
+	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_mta_set_generic - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	DEBUGFUNC("e1000_mta_set_generic");
+	/*
+	 * The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_update_mc_addr_list_generic - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates entire Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+                                       u8 *mc_addr_list, u32 mc_addr_count)
+{
+	u32 hash_value, hash_bit, hash_reg;
+	int i;
+
+	DEBUGFUNC("e1000_update_mc_addr_list_generic");
+
+	/* clear mta_shadow */
+	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+	/* update mta_shadow from mc_addr_list */
+	for (i = 0; (u32) i < mc_addr_count; i++) {
+		hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+
+		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+		hash_bit = hash_value & 0x1F;
+
+		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+		mc_addr_list += (ETH_ADDR_LEN);
+	}
+
+	/* replace the entire MTA table */
+	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_hash_mc_addr_generic - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  e1000_mta_set_generic()
+ **/
+u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	DEBUGFUNC("e1000_hash_mc_addr_generic");
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/*
+	 * The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 *
+	 * For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB                 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+	default:
+	case 0:
+		break;
+	case 1:
+		bit_shift += 1;
+		break;
+	case 2:
+		bit_shift += 2;
+		break;
+	case 3:
+		bit_shift += 4;
+		break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+	                          (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value
+ *  @hw: pointer to the HW structure
+ *
+ *  In certain situations, a system BIOS may report that the PCIx maximum
+ *  memory read byte count (MMRBC) value is higher than than the actual
+ *  value. We check the PCIx command register with the current PCIx status
+ *  register.
+ **/
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw)
+{
+	u16 cmd_mmrbc;
+	u16 pcix_cmd;
+	u16 pcix_stat_hi_word;
+	u16 stat_mmrbc;
+
+	DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic");
+
+	/* Workaround for PCI-X issue when BIOS sets MMRBC incorrectly */
+	if (hw->bus.type != e1000_bus_type_pcix)
+		return;
+
+	e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+	e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+	cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >>
+	             PCIX_COMMAND_MMRBC_SHIFT;
+	stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+	              PCIX_STATUS_HI_MMRBC_SHIFT;
+	if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+		stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+	if (cmd_mmrbc > stat_mmrbc) {
+		pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK;
+		pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+		e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
+	}
+}
+
+/**
+ *  e1000_clear_hw_cntrs_base_generic - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
+
+#if 0
+	E1000_READ_REG(hw, E1000_CRCERRS);
+	E1000_READ_REG(hw, E1000_SYMERRS);
+	E1000_READ_REG(hw, E1000_MPC);
+	E1000_READ_REG(hw, E1000_SCC);
+	E1000_READ_REG(hw, E1000_ECOL);
+	E1000_READ_REG(hw, E1000_MCC);
+	E1000_READ_REG(hw, E1000_LATECOL);
+	E1000_READ_REG(hw, E1000_COLC);
+	E1000_READ_REG(hw, E1000_DC);
+	E1000_READ_REG(hw, E1000_SEC);
+	E1000_READ_REG(hw, E1000_RLEC);
+	E1000_READ_REG(hw, E1000_XONRXC);
+	E1000_READ_REG(hw, E1000_XONTXC);
+	E1000_READ_REG(hw, E1000_XOFFRXC);
+	E1000_READ_REG(hw, E1000_XOFFTXC);
+	E1000_READ_REG(hw, E1000_FCRUC);
+	E1000_READ_REG(hw, E1000_GPRC);
+	E1000_READ_REG(hw, E1000_BPRC);
+	E1000_READ_REG(hw, E1000_MPRC);
+	E1000_READ_REG(hw, E1000_GPTC);
+	E1000_READ_REG(hw, E1000_GORCL);
+	E1000_READ_REG(hw, E1000_GORCH);
+	E1000_READ_REG(hw, E1000_GOTCL);
+	E1000_READ_REG(hw, E1000_GOTCH);
+	E1000_READ_REG(hw, E1000_RNBC);
+	E1000_READ_REG(hw, E1000_RUC);
+	E1000_READ_REG(hw, E1000_RFC);
+	E1000_READ_REG(hw, E1000_ROC);
+	E1000_READ_REG(hw, E1000_RJC);
+	E1000_READ_REG(hw, E1000_TORL);
+	E1000_READ_REG(hw, E1000_TORH);
+	E1000_READ_REG(hw, E1000_TOTL);
+	E1000_READ_REG(hw, E1000_TOTH);
+	E1000_READ_REG(hw, E1000_TPR);
+	E1000_READ_REG(hw, E1000_TPT);
+	E1000_READ_REG(hw, E1000_MPTC);
+	E1000_READ_REG(hw, E1000_BPTC);
+#endif
+}
+
+/**
+ *  e1000_check_for_copper_link_generic - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_check_for_copper_link");
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000_config_collision_dist_generic(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000_config_fc_after_link_up_generic(hw);
+	if (ret_val)
+		DEBUGOUT("Error configuring flow control\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_fiber_link_generic - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_fiber_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_serdes_link_generic - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), and our link partner is not trying to
+	 * auto-negotiate with us (we are receiving idles or data),
+	 * we need to force link up. We also need to give auto-negotiation
+	 * time to complete.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
+		/*
+		 * If we force link for non-auto-negotiation switch, check
+		 * link status based on MAC synchronization for internal
+		 * serdes media type.
+		 */
+		/* SYNCH bit and IV bit are sticky. */
+		usec_delay(10);
+		rxcw = E1000_READ_REG(hw, E1000_RXCW);
+		if (rxcw & E1000_RXCW_SYNCH) {
+			if (!(rxcw & E1000_RXCW_IV)) {
+				mac->serdes_has_link = true;
+				DEBUGOUT("SERDES: Link up - forced.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			DEBUGOUT("SERDES: Link down - force failed.\n");
+		}
+	}
+
+	if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		if (status & E1000_STATUS_LU) {
+			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
+			usec_delay(10);
+			rxcw = E1000_READ_REG(hw, E1000_RXCW);
+			if (rxcw & E1000_RXCW_SYNCH) {
+				if (!(rxcw & E1000_RXCW_IV)) {
+					mac->serdes_has_link = true;
+					DEBUGOUT("SERDES: Link up - autoneg "
+					   "completed sucessfully.\n");
+				} else {
+					mac->serdes_has_link = false;
+					DEBUGOUT("SERDES: Link down - invalid"
+					   "codewords detected in autoneg.\n");
+				}
+			} else {
+				mac->serdes_has_link = false;
+				DEBUGOUT("SERDES: Link down - no sync.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			DEBUGOUT("SERDES: Link down - autoneg failed\n");
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_link_generic - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 e1000_setup_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_link_generic");
+
+	/*
+	 * In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (hw->phy.ops.check_reset_block)
+		if (hw->phy.ops.check_reset_block(hw))
+			goto out;
+
+	/*
+	 * If requested flow control is set to default, set flow control
+	 * based on the EEPROM flow control settings.
+	 */
+	if (hw->fc.requested_mode == e1000_fc_default) {
+		ret_val = e1000_set_default_fc_generic(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes
+ *  links.  Upon successful setup, poll for link.
+ **/
+s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	e1000_config_collision_dist_generic(hw);
+
+	ret_val = e1000_commit_fc_settings_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
+	 */
+	DEBUGOUT("Auto-negotiation enabled\n");
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(1);
+
+	/*
+	 * For these adapters, the SW definable pin 1 is set when the optics
+	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
+	 * indication.
+	 */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+	    (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+	} else {
+		DEBUGOUT("No signal detected\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_collision_dist_generic - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000_config_collision_dist_generic(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	DEBUGFUNC("e1000_config_collision_dist_generic");
+
+	tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_poll_fiber_serdes_link_generic - Poll for link up
+ *  @hw: pointer to the HW structure
+ *
+ *  Polls for link up by reading the status register, if link fails to come
+ *  up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 i, status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
+
+	/*
+	 * If we have a signal (the cable is plugged in, or assumed true for
+	 * serdes media) then poll for a "Link-Up" indication in the Device
+	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
+	 * seconds (Auto-negotiation should complete in less than 500
+	 * milliseconds even if the other end is doing it in SW).
+	 */
+	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+		msec_delay(10);
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		if (status & E1000_STATUS_LU)
+			break;
+	}
+	if (i == FIBER_LINK_UP_LIMIT) {
+		DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+		mac->autoneg_failed = 1;
+		/*
+		 * AutoNeg failed to achieve a link, so we'll call
+		 * mac->check_for_link. This routine will force the
+		 * link up if we detect a signal. This will allow us to
+		 * communicate with non-autonegotiating link partners.
+		 */
+		ret_val = hw->mac.ops.check_for_link(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while checking for link\n");
+			goto out;
+		}
+		mac->autoneg_failed = 0;
+	} else {
+		mac->autoneg_failed = 0;
+		DEBUGOUT("Valid Link Found\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_commit_fc_settings_generic - Configure flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Write the flow control settings to the Transmit Config Word Register (TXCW)
+ *  base on the flow control settings in e1000_mac_info.
+ **/
+s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txcw;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_commit_fc_settings_generic");
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Transmit Config Word Register (TXCW) and re-start auto-
+	 * negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames,
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we
+	 *          do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/* Flow control completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is disabled
+		 * by a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of Rx Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric RX
+		 * PAUSE.  Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+	mac->txcw = txcw;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  transmission as well.
+ **/
+s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 fcrtl = 0, fcrth = 0;
+
+	DEBUGFUNC("e1000_set_fc_watermarks_generic");
+
+	/*
+	 * Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.current_mode & e1000_fc_tx_pause) {
+		/*
+		 * We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
+	E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_set_default_fc_generic - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_set_default_fc_generic");
+
+	/*
+	 * Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		hw->fc.requested_mode = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		hw->fc.requested_mode = e1000_fc_tx_pause;
+	else
+		hw->fc.requested_mode = e1000_fc_full;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_force_mac_fc_generic - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_force_mac_fc_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/*
+	 * Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc.current_mode" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_fc_after_link_up_generic - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	DEBUGFUNC("e1000_config_fc_after_link_up_generic");
+
+	/*
+	 * Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes)
+			ret_val = e1000_force_mac_fc_generic(hw);
+	} else {
+		if (hw->phy.media_type == e1000_media_type_copper)
+			ret_val = e1000_force_mac_fc_generic(hw);
+	}
+
+	if (ret_val) {
+		DEBUGOUT("Error forcing flow control settings\n");
+		goto out;
+	}
+
+	/*
+	 * Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+		/*
+		 * Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			DEBUGOUT("Copper PHY and Auto Neg "
+			         "has not completed.\n");
+			goto out;
+		}
+
+		/*
+		 * The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+		                             &mii_nway_adv_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+		                             &mii_nway_lp_ability_reg);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/*
+			 * Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
+				DEBUGOUT("Flow Control = FULL.\r\n");
+			} else {
+				hw->fc.current_mode = e1000_fc_rx_pause;
+				DEBUGOUT("Flow Control = "
+				         "RX PAUSE frames only.\r\n");
+			}
+		}
+		/*
+		 * For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_tx_pause;
+			DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/*
+		 * For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_rx_pause;
+			DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+		} else {
+			/*
+			 * Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.current_mode = e1000_fc_none;
+			DEBUGOUT("Flow Control = NONE.\r\n");
+		}
+
+		/*
+		 * Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			DEBUGOUT("Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			hw->fc.current_mode = e1000_fc_none;
+
+		/*
+		 * Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = e1000_force_mac_fc_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error forcing flow control settings\n");
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	u32 status;
+
+	DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
+
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		DEBUGOUT("1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		DEBUGOUT("100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		DEBUGOUT("10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Sets the speed and duplex to gigabit full duplex (the only possible option)
+ *  for fiber/serdes links.
+ **/
+s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused,
+                                                    u16 *speed, u16 *duplex)
+{
+	DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
+
+	*speed = SPEED_1000;
+	*duplex = FULL_DUPLEX;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_hw_semaphore_generic - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_get_hw_semaphore_generic");
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000_put_hw_semaphore_generic(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_put_hw_semaphore_generic - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 swsm;
+
+	DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+	swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+#endif
+}
+
+/**
+ *  e1000_get_auto_rd_done_generic - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_get_auto_rd_done_generic");
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msec_delay(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_valid_led_default_generic - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_valid_led_default_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_id_led_init_generic -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000_id_led_init_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	DEBUGFUNC("e1000_id_led_init_generic");
+
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_setup_led_generic - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+s32 e1000_setup_led_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ledctl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_led_generic");
+
+	if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+		hw->mac.ledctl_default = ledctl;
+		/* Turn off LED0 */
+		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+		            E1000_LEDCTL_LED0_BLINK |
+		            E1000_LEDCTL_LED0_MODE_MASK);
+		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+		           E1000_LEDCTL_LED0_MODE_SHIFT);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+	}
+
+out:
+	return ret_val;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_cleanup_led_generic - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 e1000_cleanup_led_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_cleanup_led_generic");
+
+	if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+
+out:
+	return ret_val;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_blink_led_generic - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the LEDs which are set to be on.
+ **/
+s32 e1000_blink_led_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	DEBUGFUNC("e1000_blink_led_generic");
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/*
+		 * set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2
+		 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+				                 (i * 8));
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_led_on_generic - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+s32 e1000_led_on_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_led_on_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_led_off_generic - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 e1000_led_off_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_led_off_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+#endif
+	return 0;
+}
+
+/**
+ *  e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities
+ *  @hw: pointer to the HW structure
+ *  @no_snoop: bitmap of snoop events
+ *
+ *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
+{
+	u32 gcr;
+
+	DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	if (no_snoop) {
+		gcr = E1000_READ_REG(hw, E1000_GCR);
+		gcr &= ~(PCIE_NO_SNOOP_ALL);
+		gcr |= no_snoop;
+		E1000_WRITE_REG(hw, E1000_GCR, gcr);
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000_disable_pcie_master_generic - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_disable_pcie_master_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	while (timeout) {
+		if (!(E1000_READ_REG(hw, E1000_STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		usec_delay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		DEBUGOUT("Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000_reset_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_reset_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	mac->current_ifs_val = 0;
+	mac->ifs_min_val = IFS_MIN;
+	mac->ifs_max_val = IFS_MAX;
+	mac->ifs_step_size = IFS_STEP;
+	mac->ifs_ratio = IFS_RATIO;
+
+	mac->in_ifs_mode = false;
+	E1000_WRITE_REG(hw, E1000_AIT, 0);
+out:
+	return;
+}
+
+/**
+ *  e1000_update_adaptive_generic - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void e1000_update_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_update_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = true;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = false;
+			E1000_WRITE_REG(hw, E1000_AIT, 0);
+		}
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_validate_mdi_setting_generic");
+
+	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+		DEBUGOUT("Invalid MDI setting detected\n");
+		hw->phy.mdix = 1;
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.h
new file mode 100644
index 0000000..51acae0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_mac.h
@@ -0,0 +1,94 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void e1000_init_mac_ops_generic(struct e1000_hw *hw);
+void e1000_null_mac_generic(struct e1000_hw *hw);
+s32  e1000_null_ops_generic(struct e1000_hw *hw);
+s32  e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d);
+bool e1000_null_mng_mode(struct e1000_hw *hw);
+void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a);
+void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b);
+void e1000_null_mta_set(struct e1000_hw *hw, u32 a);
+void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a);
+s32  e1000_blink_led_generic(struct e1000_hw *hw);
+s32  e1000_check_for_copper_link_generic(struct e1000_hw *hw);
+s32  e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
+s32  e1000_check_for_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_cleanup_led_generic(struct e1000_hw *hw);
+s32  e1000_commit_fc_settings_generic(struct e1000_hw *hw);
+s32  e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_config_fc_after_link_up_generic(struct e1000_hw *hw);
+s32  e1000_disable_pcie_master_generic(struct e1000_hw *hw);
+s32  e1000_force_mac_fc_generic(struct e1000_hw *hw);
+s32  e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
+s32  e1000_get_bus_info_pci_generic(struct e1000_hw *hw);
+s32  e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
+s32  e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
+s32  e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+s32  e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+                                                     u16 *speed, u16 *duplex);
+s32  e1000_id_led_init_generic(struct e1000_hw *hw);
+s32  e1000_led_on_generic(struct e1000_hw *hw);
+s32  e1000_led_off_generic(struct e1000_hw *hw);
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+	                               u8 *mc_addr_list, u32 mc_addr_count);
+s32  e1000_set_default_fc_generic(struct e1000_hw *hw);
+s32  e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
+s32  e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_setup_led_generic(struct e1000_hw *hw);
+s32  e1000_setup_link_generic(struct e1000_hw *hw);
+
+u32  e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
+
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000_config_collision_dist_generic(struct e1000_hw *hw);
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
+void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
+void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000_reset_adaptive_generic(struct e1000_hw *hw);
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
+void e1000_update_adaptive_generic(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_main.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_main.c
new file mode 100644
index 0000000..653323b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_main.c
@@ -0,0 +1,909 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  Portions Copyright(c) 2010 Marty Connor <mdc at etherboot.org>
+  Portions Copyright(c) 2010 Entity Cyber, Inc.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "e1000.h"
+
+/**
+ * e1000_irq_disable - Disable interrupt generation
+ *
+ * @adapter: board private structure
+ **/
+static void e1000_irq_disable ( struct e1000_adapter *adapter )
+{
+	E1000_WRITE_REG ( &adapter->hw, E1000_IMC, ~0 );
+	E1000_WRITE_FLUSH ( &adapter->hw );
+}
+
+/**
+ * e1000_irq_enable - Enable interrupt generation
+ *
+ * @adapter: board private structure
+ **/
+static void e1000_irq_enable ( struct e1000_adapter *adapter )
+{
+	E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK);
+	E1000_WRITE_FLUSH(&adapter->hw);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int e1000_sw_init(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct pci_device  *pdev = adapter->pdev;
+
+	/* PCI config space info */
+
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &hw->subsystem_vendor_id);
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_device_id);
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+	adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE +
+                                  ETH_HLEN + ETH_FCS_LEN;
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	hw->fc.requested_mode = e1000_fc_none;
+
+	/* Initialize the hardware-specific values */
+	if (e1000_setup_init_funcs(hw, false)) {
+		DBG ("Hardware Initialization Failure\n");
+		return -EIO;
+	}
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	e1000_irq_disable ( adapter );
+
+	return 0;
+}
+
+int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+    struct e1000_adapter *adapter = hw->back;
+    uint16_t cap_offset;
+
+#define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
+    cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+    if (!cap_offset)
+        return -E1000_ERR_CONFIG;
+
+    pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+    return 0;
+}
+
+void e1000_pci_clear_mwi ( struct e1000_hw *hw )
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_write_config_word ( adapter->pdev, PCI_COMMAND,
+			        hw->bus.pci_cmd_word & ~PCI_COMMAND_INVALIDATE );
+}
+
+void e1000_pci_set_mwi ( struct e1000_hw *hw )
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_write_config_word ( adapter->pdev, PCI_COMMAND,
+                                hw->bus.pci_cmd_word );
+}
+
+void e1000_read_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value )
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_read_config_word ( adapter->pdev, reg, value );
+}
+
+void e1000_write_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value )
+{
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_write_config_word ( adapter->pdev, reg, *value );
+}
+
+/**
+ * e1000_init_manageability - disable interception of ARP packets
+ *
+ * @v adapter	e1000 private structure
+ **/
+static void e1000_init_manageability ( struct e1000_adapter *adapter )
+{
+	if (adapter->en_mng_pt) {
+		u32 manc = E1000_READ_REG(&adapter->hw, E1000_MANC);
+
+		/* disable hardware interception of ARP */
+		manc &= ~(E1000_MANC_ARP_EN);
+
+		E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc);
+	}
+}
+
+/**
+ * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int e1000_setup_tx_resources ( struct e1000_adapter *adapter )
+{
+	DBG ( "e1000_setup_tx_resources\n" );
+
+	/* Allocate transmit descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata #23
+	   so we use malloc_dma() requesting a 128 byte block that is
+	   128 byte aligned. This should guarantee that the memory
+	   allocated will not cross a 64K boundary, because 128 is an
+	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
+	   allocations of 128 bytes on a 128 byte boundary will not
+	   cross 64K bytes.
+	 */
+
+        adapter->tx_base =
+		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
+
+	if ( ! adapter->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
+
+	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
+
+	return 0;
+}
+
+/**
+ * e1000_process_tx_packets - process transmitted packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void e1000_process_tx_packets ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t tx_status;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	/* Check status of transmitted packets
+	 */
+	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
+
+		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
+					   ( i * sizeof ( *adapter->tx_base ) );
+
+		tx_status = tx_curr_desc->upper.data;
+
+		/* if the packet at tx_head is not owned by hardware it is for us */
+		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
+			break;
+
+		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
+		      adapter->tx_head, adapter->tx_tail, tx_status );
+
+		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
+				   E1000_TXD_STAT_TU ) ) {
+			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
+			DBG ( "Error transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		} else {
+			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
+			DBG ( "Success transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		}
+
+		/* Decrement count of used descriptors, clear this descriptor
+		 */
+		adapter->tx_fill_ctr--;
+		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
+	}
+}
+
+static void e1000_free_tx_resources ( struct e1000_adapter *adapter )
+{
+	DBG ( "e1000_free_tx_resources\n" );
+
+        free_dma ( adapter->tx_base, adapter->tx_ring_size );
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void e1000_configure_tx ( struct e1000_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t tctl;
+
+	DBG ( "e1000_configure_tx\n" );
+
+	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
+	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
+
+        DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
+        DBG ( "E1000_TDLEN(0): %d\n",     E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
+
+	adapter->tx_head = 0;
+	adapter->tx_tail = 0;
+	adapter->tx_fill_ctr = 0;
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT) |
+		(E1000_COLLISION_DISTANCE  << E1000_COLD_SHIFT);
+
+	e1000_config_collision_dist ( hw );
+
+	E1000_WRITE_REG ( hw, E1000_TCTL, tctl );
+        E1000_WRITE_FLUSH ( hw );
+}
+
+static void e1000_free_rx_resources ( struct e1000_adapter *adapter )
+{
+	int i;
+
+	DBG ( "e1000_free_rx_resources\n" );
+
+	free_dma ( adapter->rx_base, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		free_iob ( adapter->rx_iobuf[i] );
+	}
+}
+
+/**
+ * e1000_refill_rx_ring - allocate Rx io_buffers
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int e1000_refill_rx_ring ( struct e1000_adapter *adapter )
+{
+	int i, rx_curr;
+	int rc = 0;
+	struct e1000_rx_desc *rx_curr_desc;
+	struct e1000_hw *hw = &adapter->hw;
+	struct io_buffer *iob;
+
+	DBG ("e1000_refill_rx_ring\n");
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
+		rx_curr_desc = adapter->rx_base + rx_curr;
+
+		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
+			continue;
+
+		if ( adapter->rx_iobuf[rx_curr] != NULL )
+			continue;
+
+		DBG2 ( "Refilling rx desc %d\n", rx_curr );
+
+		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+		adapter->rx_iobuf[rx_curr] = iob;
+
+		if ( ! iob ) {
+			DBG ( "alloc_iob failed\n" );
+			rc = -ENOMEM;
+			break;
+		} else {
+			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
+
+			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
+		}
+	}
+	return rc;
+}
+
+/**
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int e1000_setup_rx_resources ( struct e1000_adapter *adapter )
+{
+	int i, rc = 0;
+
+	DBG ( "e1000_setup_rx_resources\n" );
+
+	/* Allocate receive descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata
+	 */
+
+        adapter->rx_base =
+		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
+
+	if ( ! adapter->rx_base ) {
+		return -ENOMEM;
+	}
+	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		/* let e1000_refill_rx_ring() io_buffer allocations */
+		adapter->rx_iobuf[i] = NULL;
+	}
+
+	/* allocate io_buffers */
+	rc = e1000_refill_rx_ring ( adapter );
+	if ( rc < 0 )
+		e1000_free_rx_resources ( adapter );
+
+	return rc;
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void e1000_configure_rx ( struct e1000_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl;
+
+	DBG ( "e1000_configure_rx\n" );
+
+	/* disable receives while setting up the descriptors */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	E1000_WRITE_FLUSH ( hw );
+	mdelay(10);
+
+	adapter->rx_curr = 0;
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+
+	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
+	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
+
+	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
+
+	/* Enable Receives */
+	rctl |=  E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+		 E1000_RCTL_MPE | E1000_RCTL_SECRC;
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl );
+	E1000_WRITE_FLUSH ( hw );
+
+        DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
+        DBG ( "E1000_RDLEN(0): %d\n",     E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
+        DBG ( "E1000_RCTL:  %#08x\n",  E1000_READ_REG ( hw, E1000_RCTL ) );
+}
+
+/**
+ * e1000_process_rx_packets - process received packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void e1000_process_rx_packets ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t rx_status;
+	uint32_t rx_len;
+	uint32_t rx_err;
+	struct e1000_rx_desc *rx_curr_desc;
+
+	/* Process received packets
+	 */
+	while ( 1 ) {
+
+		i = adapter->rx_curr;
+
+		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+			          ( i * sizeof ( *adapter->rx_base ) );
+		rx_status = rx_curr_desc->status;
+
+		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
+
+		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+			break;
+
+		if ( adapter->rx_iobuf[i] == NULL )
+			break;
+
+		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
+
+		rx_len = rx_curr_desc->length;
+
+                DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
+                      i, rx_status, rx_len );
+
+                rx_err = rx_curr_desc->errors;
+
+		iob_put ( adapter->rx_iobuf[i], rx_len );
+
+		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
+
+			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
+			DBG ( "e1000_poll: Corrupted packet received!"
+			      " rx_err: %#08x\n", rx_err );
+		} else {
+			/* Add this packet to the receive queue. */
+			netdev_rx ( netdev, adapter->rx_iobuf[i] );
+		}
+		adapter->rx_iobuf[i] = NULL;
+
+		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
+	}
+}
+
+/**
+ * e1000_reset - Put e1000 NIC in known initial state
+ *
+ * @v adapter	e1000 private structure
+ **/
+void e1000_reset ( struct e1000_adapter *adapter )
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	u32 pba = 0;
+
+	DBG ( "e1000_reset\n" );
+
+	switch (mac->type) {
+	case e1000_82542:
+	case e1000_82543:
+	case e1000_82544:
+	case e1000_82540:
+	case e1000_82541:
+	case e1000_82541_rev_2:
+		pba = E1000_PBA_48K;
+		break;
+	case e1000_82545:
+	case e1000_82545_rev_3:
+	case e1000_82546:
+	case e1000_82546_rev_3:
+		pba = E1000_PBA_48K;
+		break;
+	case e1000_82547:
+	case e1000_82547_rev_2:
+		pba = E1000_PBA_30K;
+		break;
+	case e1000_undefined:
+	case e1000_num_macs:
+		break;
+	}
+
+	E1000_WRITE_REG ( &adapter->hw, E1000_PBA, pba );
+
+	/* Allow time for pending master requests to run */
+	e1000_reset_hw ( &adapter->hw );
+
+	if ( mac->type >= e1000_82544 )
+		E1000_WRITE_REG ( &adapter->hw, E1000_WUC, 0 );
+
+	if ( e1000_init_hw ( &adapter->hw ) )
+		DBG ( "Hardware Error\n" );
+
+	e1000_reset_adaptive ( &adapter->hw );
+	e1000_get_phy_info ( &adapter->hw );
+
+	e1000_init_manageability ( adapter );
+}
+
+/** Functions that implement the iPXE driver API **/
+
+/**
+ * e1000_close - Disables a network interface
+ *
+ * @v netdev	network interface device structure
+ *
+ **/
+static void e1000_close ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl;
+
+	DBG ( "e1000_close\n" );
+
+	/* Disable and acknowledge interrupts */
+	e1000_irq_disable ( adapter );
+	E1000_READ_REG ( hw, E1000_ICR );
+
+	/* disable receives */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	E1000_WRITE_FLUSH ( hw );
+
+	e1000_reset_hw ( hw );
+
+	e1000_free_tx_resources ( adapter );
+	e1000_free_rx_resources ( adapter );
+}
+
+/**
+ * e1000_transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ */
+static int e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct e1000_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t tx_curr = adapter->tx_tail;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	DBG ("e1000_transmit\n");
+
+	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Save pointer to iobuf we have been given to transmit,
+	   netdev_tx_complete() will need it later
+	 */
+	adapter->tx_iobuf[tx_curr] = iobuf;
+
+	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
+		       ( tx_curr * sizeof ( *adapter->tx_base ) );
+
+	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
+	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+
+	/* Add the packet to TX ring
+	 */
+	tx_curr_desc->buffer_addr =
+		virt_to_bus ( iobuf->data );
+	tx_curr_desc->lower.data =
+		E1000_TXD_CMD_RPS  | E1000_TXD_CMD_EOP |
+		E1000_TXD_CMD_IFCS | iob_len ( iobuf );
+	tx_curr_desc->upper.data = 0;
+
+	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+
+	/* Point to next free descriptor */
+	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
+	adapter->tx_fill_ctr++;
+
+	/* Write new tail to NIC, making packet available for transmit
+	 */
+	wmb();
+	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
+
+	return 0;
+}
+
+/**
+ * e1000_poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void e1000_poll ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+
+	uint32_t icr;
+
+	DBGP ( "e1000_poll\n" );
+
+	/* Acknowledge interrupts */
+	icr = E1000_READ_REG ( hw, E1000_ICR );
+	if ( ! icr )
+		return;
+
+        DBG ( "e1000_poll: intr_status = %#08x\n", icr );
+
+	e1000_process_tx_packets ( netdev );
+
+	e1000_process_rx_packets ( netdev );
+
+	e1000_refill_rx_ring(adapter);
+}
+
+/**
+ * e1000_irq - enable or Disable interrupts
+ *
+ * @v adapter   e1000 adapter
+ * @v action    requested interrupt action
+ **/
+static void e1000_irq ( struct net_device *netdev, int enable )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+
+	DBG ( "e1000_irq\n" );
+
+	if ( enable ) {
+		e1000_irq_enable ( adapter );
+	} else {
+		e1000_irq_disable ( adapter );
+	}
+}
+
+static struct net_device_operations e1000_operations;
+
+/**
+ * e1000_probe - Initial configuration of e1000 NIC
+ *
+ * @v pci	PCI device
+ * @v id	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+int e1000_probe ( struct pci_device *pdev )
+{
+	int i, err;
+	struct net_device *netdev;
+	struct e1000_adapter *adapter;
+	unsigned long mmio_start, mmio_len;
+
+	DBG ( "e1000_probe\n" );
+
+	err = -ENOMEM;
+
+	/* Allocate net device ( also allocates memory for netdev->priv
+	   and makes netdev-priv point to it ) */
+	netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) );
+	if ( ! netdev )
+		goto err_alloc_etherdev;
+
+	/* Associate e1000-specific network operations operations with
+	 * generic network device layer */
+	netdev_init ( netdev, &e1000_operations );
+
+	/* Associate this network device with given PCI device */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Initialize driver private storage */
+	adapter = netdev_priv ( netdev );
+        memset ( adapter, 0, ( sizeof ( *adapter ) ) );
+
+	adapter->pdev       = pdev;
+
+	adapter->ioaddr     = pdev->ioaddr;
+        adapter->hw.io_base = pdev->ioaddr;
+
+        adapter->irqno      = pdev->irq;
+	adapter->netdev     = netdev;
+	adapter->hw.back    = adapter;
+
+	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
+	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
+
+	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
+	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
+
+	DBG ( "mmio_start: %#08lx\n", mmio_start );
+	DBG ( "mmio_len: %#08lx\n", mmio_len );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pdev );
+
+	err = -EIO;
+
+	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
+	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
+
+	if ( ! adapter->hw.hw_addr )
+		goto err_ioremap;
+
+	/* Hardware features, flags and workarounds */
+	if (adapter->hw.mac.type >= e1000_82540) {
+		adapter->flags |= E1000_FLAG_HAS_SMBUS;
+		adapter->flags |= E1000_FLAG_HAS_INTR_MODERATION;
+	}
+
+	if (adapter->hw.mac.type == e1000_82543)
+		adapter->flags |= E1000_FLAG_BAD_TX_CARRIER_STATS_FD;
+
+	adapter->hw.phy.autoneg_wait_to_complete = true;
+	adapter->hw.mac.adaptive_ifs = true;
+
+	/* setup the private structure */
+	if ( ( err = e1000_sw_init ( adapter ) ) )
+		goto err_sw_init;
+
+	if ((err = e1000_init_mac_params(&adapter->hw)))
+		goto err_hw_init;
+
+	if ((err = e1000_init_nvm_params(&adapter->hw)))
+		goto err_hw_init;
+
+        /* Force auto-negotiated speed and duplex */
+        adapter->hw.mac.autoneg = 1;
+
+	if ((err = e1000_init_phy_params(&adapter->hw)))
+		goto err_hw_init;
+
+	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
+
+	/* before reading the EEPROM, reset the controller to
+	 * put the device in a known good starting state
+	 */
+	err = e1000_reset_hw ( &adapter->hw );
+	if ( err < 0 ) {
+		DBG ( "Hardware Initialization Failed\n" );
+		goto err_reset;
+	}
+	/* make sure the NVM is good */
+
+	if ( e1000_validate_nvm_checksum(&adapter->hw) < 0 ) {
+		DBG ( "The NVM Checksum Is Not Valid\n" );
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	/* copy the MAC address out of the EEPROM */
+	if ( e1000_read_mac_addr ( &adapter->hw ) )
+		DBG ( "EEPROM Read Error\n" );
+
+        memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
+
+	/* reset the hardware with the new settings */
+	e1000_reset ( adapter );
+
+	if ( ( err = register_netdev ( netdev ) ) != 0)
+		goto err_register;
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	for (i = 0; i < 6; i++)
+		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
+
+	DBG ( "e1000_probe succeeded!\n" );
+
+	/* No errors, return success */
+	return 0;
+
+/* Error return paths */
+err_reset:
+err_register:
+err_hw_init:
+err_eeprom:
+	if (!e1000_check_reset_block(&adapter->hw))
+		e1000_phy_hw_reset(&adapter->hw);
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+err_sw_init:
+	iounmap ( adapter->hw.hw_addr );
+err_ioremap:
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return err;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+void e1000_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+
+	DBG ( "e1000_remove\n" );
+
+	if ( adapter->hw.flash_address )
+		iounmap ( adapter->hw.flash_address );
+	if  ( adapter->hw.hw_addr )
+		iounmap ( adapter->hw.hw_addr );
+
+	unregister_netdev ( netdev );
+	e1000_reset_hw ( &adapter->hw );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ *
+ * @v netdev	network interface device structure
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int e1000_open ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	DBG ( "e1000_open\n" );
+
+	/* allocate transmit descriptors */
+	err = e1000_setup_tx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up TX resources!\n" );
+		goto err_setup_tx;
+	}
+
+	/* allocate receive descriptors */
+	err = e1000_setup_rx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up RX resources!\n" );
+		goto err_setup_rx;
+	}
+
+	e1000_configure_tx ( adapter );
+
+	e1000_configure_rx ( adapter );
+
+        DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
+
+	return 0;
+
+err_setup_rx:
+	e1000_free_tx_resources ( adapter );
+err_setup_tx:
+	e1000_reset ( adapter );
+
+	return err;
+}
+
+/** e1000 net device operations */
+static struct net_device_operations e1000_operations = {
+        .open           = e1000_open,
+        .close          = e1000_close,
+        .transmit       = e1000_transmit,
+        .poll           = e1000_poll,
+        .irq            = e1000_irq,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.c
new file mode 100644
index 0000000..3362942
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.c
@@ -0,0 +1,389 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#if 0
+
+#include "e1000_api.h"
+
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
+
+/**
+ *  e1000_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8  sum = 0;
+
+	DEBUGFUNC("e1000_calculate_checksum");
+
+	if (!buffer)
+		return 0;
+
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
+{
+	u32 hicr;
+	s32 ret_val = E1000_SUCCESS;
+	u8  i;
+
+	DEBUGFUNC("e1000_mng_enable_host_if_generic");
+
+	/* Check that the host interface is enabled. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	if ((hicr & E1000_HICR_EN) == 0) {
+		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+	/* check the previous command is completed */
+	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+		hicr = E1000_READ_REG(hw, E1000_HICR);
+		if (!(hicr & E1000_HICR_C))
+			break;
+		msec_delay_irq(1);
+	}
+
+	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+		DEBUGOUT("Previous command timeout failed .\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_mng_mode_generic - Generic check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the firmware semaphore register and returns true (>0) if
+ *  manageability is enabled, else false (0).
+ **/
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	DEBUGFUNC("e1000_check_mng_mode_generic");
+
+	fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
+ *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ **/
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
+{
+	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+	u32 *buffer = (u32 *)&hw->mng_cookie;
+	u32 offset;
+	s32 ret_val, hdr_csum, csum;
+	u8 i, len;
+	bool tx_filter = true;
+
+	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
+
+	/* No manageability, no filtering */
+	if (!hw->mac.ops.check_mng_mode(hw)) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/*
+	 * If we can't read from the host interface for whatever
+	 * reason, disable filtering.
+	 */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val != E1000_SUCCESS) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/* Read in the header.  Length and offset are in dwords. */
+	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+	for (i = 0; i < len; i++) {
+		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
+		                                           E1000_HOST_IF,
+		                                           offset + i);
+	}
+	hdr_csum = hdr->checksum;
+	hdr->checksum = 0;
+	csum = e1000_calculate_checksum((u8 *)hdr,
+	                                E1000_MNG_DHCP_COOKIE_LENGTH);
+	/*
+	 * If either the checksums or signature don't match, then
+	 * the cookie area isn't considered valid, in which case we
+	 * take the safe route of assuming Tx filtering is enabled.
+	 */
+	if (hdr_csum != csum)
+		goto out;
+	if (hdr->signature != E1000_IAMT_SIGNATURE)
+		goto out;
+
+	/* Cookie area is valid, make the final check for filtering. */
+	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
+		tx_filter = false;
+
+out:
+	hw->mac.tx_pkt_filtering = tx_filter;
+	return tx_filter;
+}
+
+/**
+ *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
+                                      u16 length)
+{
+	struct e1000_host_mng_command_header hdr;
+	s32 ret_val;
+	u32 hicr;
+
+	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
+
+	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+	hdr.command_length = length;
+	hdr.reserved1 = 0;
+	hdr.reserved2 = 0;
+	hdr.checksum = 0;
+
+	/* Enable the host interface */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val)
+		goto out;
+
+	/* Populate the host interface with the contents of "buffer". */
+	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+	                                  sizeof(hdr), &(hdr.checksum));
+	if (ret_val)
+		goto out;
+
+	/* Write the manageability command header */
+	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+	if (ret_val)
+		goto out;
+
+	/* Tell the ARC a new command is pending. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_mng_write_cmd_header_generic - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr)
+{
+	u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
+
+	/* Write the whole command header structure with new checksum. */
+
+	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+	length >>= 2;
+	/* Write the relevant command block into the ram area. */
+	for (i = 0; i < length; i++) {
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+		                            *((u32 *) hdr + i));
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_mng_host_if_write_generic - Write to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                    u16 length, u16 offset, u8 *sum)
+{
+	u8 *tmp;
+	u8 *bufptr = buffer;
+	u32 data = 0;
+	s32 ret_val = E1000_SUCCESS;
+	u16 remaining, i, j, prev_bytes;
+
+	DEBUGFUNC("e1000_mng_host_if_write_generic");
+
+	/* sum = only sum of the data and it is not checksum */
+
+	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	tmp = (u8 *)&data;
+	prev_bytes = offset & 0x3;
+	offset >>= 2;
+
+	if (prev_bytes) {
+		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+		for (j = prev_bytes; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+		length -= j - prev_bytes;
+		offset++;
+	}
+
+	remaining = length & 0x3;
+	length -= remaining;
+
+	/* Calculate length in DWORDs */
+	length >>= 2;
+
+	/*
+	 * The device driver writes the relevant command block into the
+	 * ram area.
+	 */
+	for (i = 0; i < length; i++) {
+		for (j = 0; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+		                            data);
+	}
+	if (remaining) {
+		for (j = 0; j < sizeof(u32); j++) {
+			if (j < remaining)
+				*(tmp + j) = *bufptr++;
+			else
+				*(tmp + j) = 0;
+
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = false;
+
+	DEBUGFUNC("e1000_enable_mng_pass_thru");
+
+	if (!hw->mac.asf_firmware_present)
+		goto out;
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		goto out;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = E1000_READ_REG(hw, E1000_FWSM);
+		factps = E1000_READ_REG(hw, E1000_FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = true;
+			goto out;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = true;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.h
new file mode 100644
index 0000000..14467aa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_manage.h
@@ -0,0 +1,84 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_MANAGE_H_
+#define _E1000_MANAGE_H_
+
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
+s32  e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
+s32  e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                     u16 length, u16 offset, u8 *sum);
+s32  e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr);
+s32  e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
+                                       u8 *buffer, u16 length);
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE                  0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_VFTA_ENTRY_SHIFT               5
+#define E1000_VFTA_ENTRY_MASK                0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+#define E1000_HICR_SV              0x04  /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET        0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE  0x544D4149
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c
new file mode 100644
index 0000000..488252f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c
@@ -0,0 +1,923 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000_api.h"
+
+static void e1000_reload_nvm_generic(struct e1000_hw *hw);
+
+/**
+ *  e1000_init_nvm_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	DEBUGFUNC("e1000_init_nvm_ops_generic");
+
+	/* Initialize function pointers */
+	nvm->ops.init_params = e1000_null_ops_generic;
+	nvm->ops.acquire = e1000_null_ops_generic;
+	nvm->ops.read = e1000_null_read_nvm;
+	nvm->ops.release = e1000_null_nvm_generic;
+	nvm->ops.reload = e1000_reload_nvm_generic;
+	nvm->ops.update = e1000_null_ops_generic;
+	nvm->ops.valid_led_default = e1000_null_led_default;
+	nvm->ops.validate = e1000_null_ops_generic;
+	nvm->ops.write = e1000_null_write_nvm;
+}
+
+/**
+ *  e1000_null_nvm_read - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_read_nvm(struct e1000_hw *hw __unused, u16 a __unused,
+                        u16 b __unused, u16 *c __unused)
+{
+	DEBUGFUNC("e1000_null_read_nvm");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_nvm_generic - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_nvm_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_null_nvm_generic");
+	return;
+}
+
+/**
+ *  e1000_null_led_default - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_led_default(struct e1000_hw *hw __unused,
+                           u16 *data __unused)
+{
+	DEBUGFUNC("e1000_null_led_default");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_write_nvm - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_write_nvm(struct e1000_hw *hw __unused, u16 a __unused,
+                         u16 b __unused, u16 *c __unused)
+{
+	DEBUGFUNC("e1000_null_write_nvm");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u32 mask;
+
+	DEBUGFUNC("e1000_shift_out_eec_bits");
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_microwire)
+		eecd &= ~E1000_EECD_DO;
+	else
+	if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+
+		usec_delay(nvm->delay_usec);
+
+		e1000_raise_eec_clk(hw, &eecd);
+		e1000_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	DEBUGFUNC("e1000_shift_in_eec_bits");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		e1000_raise_eec_clk(hw, &eecd);
+
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+
+	DEBUGFUNC("e1000_poll_eerd_eewr_done");
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = E1000_READ_REG(hw, E1000_EERD);
+		else
+			reg = E1000_READ_REG(hw, E1000_EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE) {
+			ret_val = E1000_SUCCESS;
+			break;
+		}
+
+		usec_delay(5);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm_generic - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000_acquire_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_acquire_nvm_generic");
+
+	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		usec_delay(5);
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		DEBUGOUT("Could not acquire NVM grant\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	DEBUGFUNC("e1000_standby_nvm");
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+
+		e1000_raise_eec_clk(hw, &eecd);
+
+		/* Select EEPROM */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+
+		e1000_lower_eec_clk(hw, &eecd);
+	} else
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  e1000_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+void e1000_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("e1000_stop_nvm");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		e1000_lower_eec_clk(hw, &eecd);
+	} else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+		/* CS on Microwire is active-high */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		e1000_raise_eec_clk(hw, &eecd);
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  e1000_release_nvm_generic - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000_release_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("e1000_release_nvm_generic");
+
+	e1000_stop_nvm(hw);
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	eecd &= ~E1000_EECD_REQ;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 ret_val = E1000_SUCCESS;
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+	DEBUGFUNC("e1000_ready_nvm_eeprom");
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		/* Clear SK and DI */
+		eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		/* Set CS */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+	} else
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		usec_delay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/*
+		 * Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out.
+		 */
+		while (timeout) {
+			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+			                         hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			usec_delay(5);
+			e1000_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			DEBUGOUT("SPI NVM Status error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_spi - Read EEPROM's using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i = 0;
+	s32 ret_val;
+	u16 word_in;
+	u8 read_opcode = NVM_READ_OPCODE_SPI;
+
+	DEBUGFUNC("e1000_read_nvm_spi");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	e1000_standby_nvm(hw);
+
+	if ((nvm->address_bits == 8) && (offset >= 128))
+		read_opcode |= NVM_A8_OPCODE_SPI;
+
+	/* Send the READ command (opcode + addr) */
+	e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+	e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
+
+	/*
+	 * Read the data.  SPI NVMs increment the address with each byte
+	 * read and will roll over if reading beyond the end.  This allows
+	 * us to read the whole NVM from any offset
+	 */
+	for (i = 0; i < words; i++) {
+		word_in = e1000_shift_in_eec_bits(hw, 16);
+		data[i] = (word_in >> 8) | (word_in << 8);
+	}
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_microwire - Reads EEPROM's using microwire
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
+                             u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i = 0;
+	s32 ret_val;
+	u8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
+
+	DEBUGFUNC("e1000_read_nvm_microwire");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	for (i = 0; i < words; i++) {
+		/* Send the READ command (opcode + addr) */
+		e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+		e1000_shift_out_eec_bits(hw, (u16)(offset + i),
+					nvm->address_bits);
+
+		/*
+		 * Read the data.  For microwire, each word requires the
+		 * overhead of setup and tear-down.
+		 */
+		data[i] = e1000_shift_in_eec_bits(hw, 16);
+		e1000_standby_nvm(hw);
+	}
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_nvm_eerd");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * too many words for the offset, and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		E1000_WRITE_REG(hw, E1000_EERD, eerd);
+		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
+		           E1000_NVM_RW_REG_DATA);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	DEBUGFUNC("e1000_write_nvm_spi");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = e1000_ready_nvm_eeprom(hw);
+		if (ret_val)
+			goto release;
+
+		e1000_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+		                         nvm->opcode_bits);
+
+		e1000_standby_nvm(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+		                         nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			e1000_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				e1000_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msec_delay(10);
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_microwire - Writes EEPROM using microwire
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using microwire interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
+                              u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32  ret_val;
+	u32 eecd;
+	u16 words_written = 0;
+	u16 widx = 0;
+
+	DEBUGFUNC("e1000_write_nvm_microwire");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
+	                         (u16)(nvm->opcode_bits + 2));
+
+	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
+
+	e1000_standby_nvm(hw);
+
+	while (words_written < words) {
+		e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
+		                         nvm->opcode_bits);
+
+		e1000_shift_out_eec_bits(hw, (u16)(offset + words_written),
+		                         nvm->address_bits);
+
+		e1000_shift_out_eec_bits(hw, data[words_written], 16);
+
+		e1000_standby_nvm(hw);
+
+		for (widx = 0; widx < 200; widx++) {
+			eecd = E1000_READ_REG(hw, E1000_EECD);
+			if (eecd & E1000_EECD_DO)
+				break;
+			usec_delay(50);
+		}
+
+		if (widx == 200) {
+			DEBUGOUT("NVM Write did not complete\n");
+			ret_val = -E1000_ERR_NVM;
+			goto release;
+		}
+
+		e1000_standby_nvm(hw);
+
+		words_written++;
+	}
+
+	e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
+	                         (u16)(nvm->opcode_bits + 2));
+
+	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_pba_num_generic - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ **/
+s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
+{
+	s32  ret_val;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_read_pba_num_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num = (u32)(nvm_data << 16);
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num |= nvm_data;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr_generic - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
+
+	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
+	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
+
+	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
+
+	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_validate_nvm_checksum_generic");
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		DEBUGOUT("NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum_generic - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32  ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_update_nvm_checksum");
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val)
+		DEBUGOUT("NVM Write Error while updating checksum.\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reload_nvm_generic - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+static void e1000_reload_nvm_generic(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+
+	DEBUGFUNC("e1000_reload_nvm_generic");
+
+	usec_delay(10);
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	E1000_WRITE_FLUSH(hw);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h
new file mode 100644
index 0000000..1585417
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h
@@ -0,0 +1,63 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
+s32  e1000_null_read_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c);
+void e1000_null_nvm_generic(struct e1000_hw *hw);
+s32  e1000_null_led_default(struct e1000_hw *hw, u16 *data);
+s32  e1000_null_write_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c);
+s32  e1000_acquire_nvm_generic(struct e1000_hw *hw);
+
+s32  e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32  e1000_read_mac_addr_generic(struct e1000_hw *hw);
+s32  e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
+s32  e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset,
+                              u16 words, u16 *data);
+s32  e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data);
+s32  e1000_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32  e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
+                          u16 words, u16 *data);
+s32  e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset,
+                               u16 words, u16 *data);
+s32  e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000_stop_nvm(struct e1000_hw *hw);
+void e1000_release_nvm_generic(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE  0xDB00
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h
new file mode 100644
index 0000000..5cd8e39
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h
@@ -0,0 +1,118 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* glue for the OS-dependent part of e1000
+ * includes register access macros
+ */
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#define u8         unsigned char
+#define bool       boolean_t
+#define dma_addr_t unsigned long
+#define __le16     uint16_t
+#define __le32     uint32_t
+#define __le64     uint64_t
+
+#define __iomem
+
+#define ETH_FCS_LEN 4
+
+typedef int spinlock_t;
+typedef enum {
+    false = 0,
+    true = 1
+} boolean_t;
+
+#define usec_delay(x) udelay(x)
+#define msec_delay(x) mdelay(x)
+#define msec_delay_irq(x) mdelay(x)
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+#define ETH_ADDR_LEN           ETH_ALEN
+
+#define DEBUGFUNC(F) DBG(F "\n")
+
+#define DEBUGOUT(S)             DBG(S)
+#define DEBUGOUT1(S, A...)      DBG(S, A)
+
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+#define E1000_REGISTER(a, reg) (((a)->mac.type >= e1000_82543) \
+                               ? reg                           \
+                               : e1000_translate_register_82542(reg))
+
+#define E1000_WRITE_REG(a, reg, value) \
+    writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg)))
+
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg)))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+    writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+    writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))))
+
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+    readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+    writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+    readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))
+
+#define E1000_WRITE_REG_IO(a, reg, offset) do { \
+    outl(reg, ((a)->io_base));                  \
+    outl(offset, ((a)->io_base + 4));      } while(0)
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
+
+#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
+    writel((value), ((a)->flash_address + reg)))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
+    writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
+
+#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
+
+#endif /* _E1000_OSDEP_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.c
new file mode 100644
index 0000000..b3cad48
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.c
@@ -0,0 +1,2308 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000_api.h"
+
+#if 0
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_m88_cable_length_table) / \
+                 sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_igp_2_cable_length_table) / \
+                 sizeof(e1000_igp_2_cable_length_table[0]))
+#endif
+
+/**
+ *  e1000_init_phy_ops_generic - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_phy_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	DEBUGFUNC("e1000_init_phy_ops_generic");
+
+	/* Initialize function pointers */
+	phy->ops.init_params = e1000_null_ops_generic;
+	phy->ops.acquire = e1000_null_ops_generic;
+	phy->ops.check_polarity = e1000_null_ops_generic;
+	phy->ops.check_reset_block = e1000_null_ops_generic;
+	phy->ops.commit = e1000_null_ops_generic;
+#if 0
+	phy->ops.force_speed_duplex = e1000_null_ops_generic;
+#endif
+	phy->ops.get_cfg_done = e1000_null_ops_generic;
+#if 0
+	phy->ops.get_cable_length = e1000_null_ops_generic;
+#endif
+	phy->ops.get_info = e1000_null_ops_generic;
+	phy->ops.read_reg = e1000_null_read_reg;
+	phy->ops.release = e1000_null_phy_generic;
+	phy->ops.reset = e1000_null_ops_generic;
+	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
+	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
+	phy->ops.write_reg = e1000_null_write_reg;
+	phy->ops.power_up = e1000_null_phy_generic;
+	phy->ops.power_down = e1000_null_phy_generic;
+}
+
+/**
+ *  e1000_null_read_reg - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_read_reg(struct e1000_hw *hw __unused, u32 offset __unused,
+                        u16 *data __unused)
+{
+	DEBUGFUNC("e1000_null_read_reg");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_phy_generic - No-op function, return void
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_null_phy_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_null_phy_generic");
+	return;
+}
+
+/**
+ *  e1000_null_lplu_state - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_lplu_state(struct e1000_hw *hw __unused, bool active __unused)
+{
+	DEBUGFUNC("e1000_null_lplu_state");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_null_write_reg - No-op function, return 0
+ *  @hw: pointer to the HW structure
+ **/
+s32 e1000_null_write_reg(struct e1000_hw *hw __unused, u32 offset __unused,
+                         u16 data __unused)
+{
+	DEBUGFUNC("e1000_null_write_reg");
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_check_reset_block_generic - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000_check_reset_block_generic(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	DEBUGFUNC("e1000_check_reset_block");
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 e1000_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id;
+
+	DEBUGFUNC("e1000_get_phy_id");
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		usec_delay(20);
+		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_reset_dsp_generic - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_phy_reset_dsp_generic");
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control register in the PHY at offset and stores the
+ *  information read to data.
+ **/
+s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_READ));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Read did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+	        (offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_WRITE));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Write did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_m88 - Read m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_m88 - Write m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_igp");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_igp");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_kmrn_reg_generic - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_kmrn_reg_generic");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+
+	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_kmrn_reg_generic - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary.  Then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release any acquired semaphores
+ *  before exiting.
+ **/
+s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_kmrn_reg_generic");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	DEBUGFUNC("e1000_copper_link_setup_m88");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/*
+	 * Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+
+	/*
+	 * Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	if (phy->revision < E1000_REVISION_4) {
+		/*
+		 * Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == E1000_REVISION_2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Commit the changes. */
+	ret_val = phy->ops.commit(hw);
+	if (ret_val) {
+		DEBUGOUT("Error committing the PHY changes\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_copper_link_setup_igp");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.reset(hw);
+	if (ret_val) {
+		DEBUGOUT("Error resetting the PHY.\n");
+		goto out;
+	}
+
+	/*
+	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+	 * timeout issues when LFS is enabled.
+	 */
+	msec_delay(100);
+
+	/*
+	 * The NVM settings will configure LPLU in D3 for
+	 * non-IGP1 PHYs.
+	 */
+	if (phy->type == e1000_phy_igp) {
+		/* disable lplu d3 during driver init */
+		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D3\n");
+			goto out;
+		}
+	}
+
+	/* disable lplu d0 during driver init */
+	if (hw->phy.ops.set_d0_lplu_state) {
+		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D0\n");
+			goto out;
+		}
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		goto out;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/*
+		 * when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default.
+		 */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+			if (ret_val)
+				goto out;
+		}
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("e1000_copper_link_autoneg");
+
+	/*
+	 * Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/*
+	 * If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+	ret_val = e1000_phy_setup_autoneg(hw);
+	if (ret_val) {
+		DEBUGOUT("Error Setting up Auto-Negotiation\n");
+		goto out;
+	}
+	DEBUGOUT("Restarting Auto-Neg\n");
+
+	/*
+	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->autoneg_wait_to_complete) {
+		ret_val = hw->mac.ops.wait_autoneg(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while waiting for "
+			         "autoneg to complete\n");
+			goto out;
+		}
+	}
+
+	hw->mac.get_link_status = true;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	DEBUGFUNC("e1000_phy_setup_autoneg");
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
+		                            &mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+	                         NWAY_AR_100TX_HD_CAPS |
+	                         NWAY_AR_10T_FD_CAPS   |
+	                         NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		DEBUGOUT("Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		DEBUGOUT("Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		DEBUGOUT("Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		DEBUGOUT("Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		DEBUGOUT("Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/*
+		 * Flow control (Rx & Tx) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled, and Tx Flow control is
+		 * disabled, by a software over-ride.
+		 *
+		 * Since there really isn't a way to advertise that we are
+		 * capable of Rx Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric Rx PAUSE.  Later
+		 * (in e1000_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = phy->ops.write_reg(hw,
+		                              PHY_1000T_CTRL,
+		                              mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_generic - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_setup_copper_link_generic");
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement and perform
+		 * autonegotiation.
+		 */
+		ret_val = e1000_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+#if 0
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+		DEBUGOUT("Forcing Speed and Duplex\n");
+		ret_val = hw->phy.ops.force_speed_duplex(hw);
+		if (ret_val) {
+			DEBUGOUT("Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+#endif
+	}
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw,
+	                                     COPPER_LINK_UP_LIMIT,
+	                                     10,
+	                                     &link);
+	if (ret_val)
+		goto out;
+
+	if (link) {
+		DEBUGOUT("Valid link established!!!\n");
+		e1000_config_collision_dist_generic(hw);
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+	} else {
+		DEBUGOUT("Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			DEBUGOUT("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/* Reset the phy to commit changes. */
+	ret_val = hw->phy.ops.commit(hw);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = phy->ops.write_reg(hw,
+			                              M88E1000_PHY_PAGE_SELECT,
+			                              0x001d);
+			if (ret_val)
+				goto out;
+			ret_val = e1000_phy_reset_dsp_generic(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000_phy_force_speed_duplex_igp(hw);
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IFE PMC: %X\n", data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			DEBUGOUT("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
+
+	/* Turn off flow control when forcing speed/duplex */
+	hw->fc.current_mode = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		DEBUGOUT("Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		DEBUGOUT("Forcing 10mb\n");
+	}
+
+	e1000_config_collision_dist_generic(hw);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+}
+#endif
+
+/**
+ *  e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                              data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_downshift_generic - Checks whether a downshift in speed occurred
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000_check_downshift_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("e1000_check_downshift_generic");
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = false;
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_check_polarity_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	DEBUGFUNC("e1000_check_polarity_igp");
+
+	/*
+	 * Polarity is determined based on the speed of
+	 * our connection.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/*
+		 * This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_ife - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reversal feature being enabled.
+ **/
+s32 e1000_check_polarity_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("e1000_check_polarity_ife");
+
+	/*
+	 * Polarity is determined based on the reversal feature being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask = IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset = IFE_PHY_SPECIAL_CONTROL;
+		mask = IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+		                       ? e1000_rev_polarity_reversed
+		                       : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_wait_autoneg_generic - Wait for auto-neg completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+s32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("e1000_wait_autoneg_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msec_delay(100);
+	}
+
+	/*
+	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_has_link_generic - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                               u32 usec_interval, bool *success)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("e1000_phy_has_link_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	for (i = 0; i < iterations; i++) {
+		/*
+		 * Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val) {
+			/*
+			 * If the first read fails, another entity may have
+			 * ownership of the resources, wait and try again to
+			 * see if they have relinquished the resources yet.
+			 */
+			usec_delay(usec_interval);
+		}
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			msec_delay_irq(usec_interval/1000);
+		else
+			usec_delay(usec_interval);
+	}
+
+	*success = (i < iterations) ? true : false;
+
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 e1000_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	DEBUGFUNC("e1000_get_cable_length_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) {
+		ret_val = E1000_ERR_PHY;
+		goto out;
+	}
+
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which represent the
+ *  combination of coarse and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+	                                                 {IGP02E1000_PHY_AGC_A,
+	                                                  IGP02E1000_PHY_AGC_B,
+	                                                  IGP02E1000_PHY_AGC_C,
+	                                                  IGP02E1000_PHY_AGC_D};
+
+	DEBUGFUNC("e1000_get_cable_length_igp_2");
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Getting bits 15:9, which represent the combination of
+		 * coarse and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length.
+		 */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+		                IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+	              e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_m88");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		DEBUGOUT("Phy info is only valid for copper media\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+	                           ? true : false;
+
+	ret_val = e1000_check_polarity_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+#if 0
+		ret_val = hw->phy.ops.get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_igp");
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = e1000_check_polarity_igp(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+#if 0
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+	} else {
+#endif
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+#if 0
+	}
+#endif
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_sw_reset_generic - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("e1000_phy_sw_reset_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	usec_delay(1);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_generic - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and release the semaphore (if necessary).
+ **/
+s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_phy_hw_reset_generic");
+
+	ret_val = phy->ops.check_reset_block(hw);
+	if (ret_val) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(phy->reset_delay_us);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(150);
+
+	phy->ops.release(hw);
+
+	ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cfg_done_generic - Generic configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Generic function to wait 10 milli-seconds for configuration to complete
+ *  and return success.
+ **/
+s32 e1000_get_cfg_done_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("e1000_get_cfg_done_generic");
+
+	msec_delay_irq(10);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 e1000_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	DEBUGOUT("Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to Tx amplitude in Gig mode */
+	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_phy_type_from_id - Get PHY type from id
+ *  @phy_id: phy_id read from the phy
+ *
+ *  Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
+{
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	switch (phy_id)	{
+	case M88E1000_I_PHY_ID:
+	case M88E1000_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+	case M88E1011_I_PHY_ID:
+		phy_type = e1000_phy_m88;
+		break;
+	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+		phy_type = e1000_phy_igp_2;
+		break;
+	case GG82563_E_PHY_ID:
+		phy_type = e1000_phy_gg82563;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy_type = e1000_phy_igp_3;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy_type = e1000_phy_ife;
+		break;
+	default:
+		phy_type = e1000_phy_unknown;
+		break;
+	}
+	return phy_type;
+}
+
+/**
+ *  e1000_determine_phy_address - Determines PHY address.
+ *  @hw: pointer to the HW structure
+ *
+ *  This uses a trial and error method to loop through possible PHY
+ *  addresses. It tests each by reading the PHY ID registers and
+ *  checking for a match.
+ **/
+s32 e1000_determine_phy_address(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+	u32 phy_addr = 0;
+	u32 i;
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	hw->phy.id = phy_type;
+
+	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+		hw->phy.addr = phy_addr;
+		i = 0;
+
+		do {
+			e1000_get_phy_id(hw);
+			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
+
+			/*
+			 * If phy_type is valid, break - we found our
+			 * PHY address
+			 */
+			if (phy_type  != e1000_phy_unknown) {
+				ret_val = E1000_SUCCESS;
+				goto out;
+			}
+			msec_delay(1);
+			i++;
+		} while (i < 10);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_up_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg &= ~MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_down_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg |= MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+	msec_delay(1);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.h
new file mode 100644
index 0000000..93bd7a1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_phy.h
@@ -0,0 +1,171 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+void e1000_init_phy_ops_generic(struct e1000_hw *hw);
+s32  e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+void e1000_null_phy_generic(struct e1000_hw *hw);
+s32  e1000_null_lplu_state(struct e1000_hw *hw, bool active);
+s32  e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_check_downshift_generic(struct e1000_hw *hw);
+s32  e1000_check_polarity_m88(struct e1000_hw *hw);
+s32  e1000_check_polarity_igp(struct e1000_hw *hw);
+s32  e1000_check_polarity_ife(struct e1000_hw *hw);
+s32  e1000_check_reset_block_generic(struct e1000_hw *hw);
+s32  e1000_copper_link_autoneg(struct e1000_hw *hw);
+s32  e1000_copper_link_setup_igp(struct e1000_hw *hw);
+s32  e1000_copper_link_setup_m88(struct e1000_hw *hw);
+#if 0
+s32  e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+#endif
+#if 0
+s32  e1000_get_cable_length_m88(struct e1000_hw *hw);
+s32  e1000_get_cable_length_igp_2(struct e1000_hw *hw);
+#endif
+s32  e1000_get_cfg_done_generic(struct e1000_hw *hw);
+s32  e1000_get_phy_id(struct e1000_hw *hw);
+s32  e1000_get_phy_info_igp(struct e1000_hw *hw);
+s32  e1000_get_phy_info_m88(struct e1000_hw *hw);
+s32  e1000_phy_sw_reset_generic(struct e1000_hw *hw);
+#if 0
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+#endif
+s32  e1000_phy_hw_reset_generic(struct e1000_hw *hw);
+s32  e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
+s32  e1000_phy_setup_autoneg(struct e1000_hw *hw);
+s32  e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
+s32  e1000_setup_copper_link_generic(struct e1000_hw *hw);
+s32  e1000_wait_autoneg_generic(struct e1000_hw *hw);
+s32  e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_phy_reset_dsp(struct e1000_hw *hw);
+s32  e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                                u32 usec_interval, bool *success);
+s32  e1000_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id);
+s32  e1000_determine_phy_address(struct e1000_hw *hw);
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+s32  e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+
+#define E1000_MAX_PHY_ADDR                4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
+#define IGP_PAGE_SHIFT                    5
+#define PHY_REG_MASK                      0x1F
+
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD          0x0010
+#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0800
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define IGP03E1000_PHY_MISC_CTRL          0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
+#define E1000_KMRNCTRLSTA_REN             0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED    0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
+#define IFE_PSC_FORCE_POLARITY             0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE            0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_regs.h
new file mode 100644
index 0000000..579c070
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000/e1000_regs.h
@@ -0,0 +1,329 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C  /* Future Extended - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* Rx Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
+#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
+#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
+#define E1000_RXCTL(_n)   (0x0C014 + (0x40 * (_n)))
+#define E1000_RQDPC(_n)   (0x0C030 + (0x40 * (_n)))
+#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
+#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+                                         (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+                                         (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+                                         (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+                                         (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+                                         (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+                                         (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+                                         (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+                                         (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+                                         (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+                                         (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+                                         (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+                                         (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+                                         (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n)       (0x03840 + (_n << 8))
+#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
+#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+                                         (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+                                         (0x0E03C + ((_n) * 0x40)))
+#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                                       (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                                       (0x054E4 + ((_i - 16) * 8)))
+#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
+#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
+#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
+#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
+#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA      0x0003C /* PHY address - RW */
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR         0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+                                                    * (_i) - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * upper reg - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * vector ctrl reg - RW */
+#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.c
new file mode 100644
index 0000000..b7318b7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.c
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+REQUIRE_OBJECT(e1000e_main);
+REQUIRE_OBJECT(e1000e_80003es2lan);
+REQUIRE_OBJECT(e1000e_82571);
+REQUIRE_OBJECT(e1000e_ich8lan);
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.h
new file mode 100644
index 0000000..bc8e7b0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e.h
@@ -0,0 +1,532 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000E_H_
+#define _E1000E_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+/* Begin OS Dependencies */
+
+#define u8         unsigned char
+#define bool       boolean_t
+#define dma_addr_t unsigned long
+#define __le16     uint16_t
+#define __le32     uint32_t
+#define __le64     uint64_t
+
+#define __iomem
+
+#define msleep(x) mdelay(x)
+
+#define ETH_FCS_LEN 4
+
+typedef int spinlock_t;
+typedef enum {
+    false = 0,
+    true = 1
+} boolean_t;
+
+/* End OS Dependencies */
+
+#include "e1000e_hw.h"
+
+#define E1000_TX_FLAGS_CSUM		0x00000001
+#define E1000_TX_FLAGS_VLAN		0x00000002
+#define E1000_TX_FLAGS_TSO		0x00000004
+#define E1000_TX_FLAGS_IPV4		0x00000008
+#define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT	16
+
+#define E1000_MAX_PER_TXD	8192
+#define E1000_MAX_TXD_PWR	12
+
+#define MINIMUM_DHCP_PACKET_SIZE 282
+
+struct e1000_info;
+
+#define e_dbg(arg...) if (0) { printf (arg); };
+
+#ifdef CONFIG_E1000E_MSIX
+/* Interrupt modes, as used by the IntMode paramter */
+#define E1000E_INT_MODE_LEGACY		0
+#define E1000E_INT_MODE_MSI		1
+#define E1000E_INT_MODE_MSIX		2
+
+#endif /* CONFIG_E1000E_MSIX */
+#ifndef CONFIG_E1000E_NAPI
+#define E1000_MAX_INTR 10
+
+#endif /* CONFIG_E1000E_NAPI */
+/* Tx/Rx descriptor defines */
+#define E1000_DEFAULT_TXD		256
+#define E1000_MAX_TXD			4096
+#define E1000_MIN_TXD			64
+
+#define E1000_DEFAULT_RXD		256
+#define E1000_MAX_RXD			4096
+#define E1000_MIN_RXD			64
+
+#define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS		10000 /* 100    irq/sec */
+
+/* Early Receive defines */
+#define E1000_ERT_2048			0x100
+
+#define E1000_FC_PAUSE_TIME		0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE		16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES			0
+#define E1000_EEPROM_APME		0x0400
+
+#define E1000_MNG_VLAN_NONE		(-1)
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS			(MAX_PS_BUFFERS - 1)
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE 	1522
+
+#define DEFAULT_JUMBO			9234
+
+enum e1000_boards {
+	board_82571,
+	board_82572,
+	board_82573,
+	board_82574,
+	board_80003es2lan,
+	board_ich8lan,
+	board_ich9lan,
+	board_ich10lan,
+	board_pchlan,
+	board_82583,
+};
+
+/* board specific private data structure */
+struct e1000_adapter {
+	const struct e1000_info *ei;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_device *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+
+	struct e1000_phy_info phy_info;
+
+	u32 wol;
+	u32 pba;
+	u32 max_hw_frame_size;
+
+	bool fc_autoneg;
+
+	unsigned int flags;
+	unsigned int flags2;
+
+#define NUM_TX_DESC	8
+#define NUM_RX_DESC	8
+
+	struct io_buffer *tx_iobuf[NUM_TX_DESC];
+	struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+	struct e1000_tx_desc *tx_base;
+	struct e1000_rx_desc *rx_base;
+
+	uint32_t tx_ring_size;
+	uint32_t rx_ring_size;
+
+	uint32_t tx_head;
+	uint32_t tx_tail;
+	uint32_t tx_fill_ctr;
+
+	uint32_t rx_curr;
+
+	uint32_t ioaddr;
+	uint32_t irqno;
+
+        uint32_t tx_int_delay;
+        uint32_t tx_abs_int_delay;
+        uint32_t txd_cmd;
+};
+
+struct e1000_info {
+	enum e1000_mac_type	mac;
+	unsigned int		flags;
+	unsigned int		flags2;
+	u32			pba;
+	u32			max_hw_frame_size;
+	s32			(*get_variants)(struct e1000_adapter *);
+	void			(*init_ops)(struct e1000_hw *);
+};
+
+/* hardware capability, feature, and workaround flags */
+#define FLAG_HAS_AMT                      (1 << 0)
+#define FLAG_HAS_FLASH                    (1 << 1)
+#define FLAG_HAS_HW_VLAN_FILTER           (1 << 2)
+#define FLAG_HAS_WOL                      (1 << 3)
+#define FLAG_HAS_ERT                      (1 << 4)
+#define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
+#define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
+#define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
+#define FLAG_IS_ICH                       (1 << 9)
+#ifdef CONFIG_E1000E_MSIX
+#define FLAG_HAS_MSIX                     (1 << 10)
+#endif
+#define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
+#define FLAG_IS_QUAD_PORT_A               (1 << 12)
+#define FLAG_IS_QUAD_PORT                 (1 << 13)
+#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN   (1 << 14)
+#define FLAG_APME_IN_WUC                  (1 << 15)
+#define FLAG_APME_IN_CTRL3                (1 << 16)
+#define FLAG_APME_CHECK_PORT_B            (1 << 17)
+#define FLAG_DISABLE_FC_PAUSE_TIME        (1 << 18)
+#define FLAG_NO_WAKE_UCAST                (1 << 19)
+#define FLAG_MNG_PT_ENABLED               (1 << 20)
+#define FLAG_RESET_OVERWRITES_LAA         (1 << 21)
+#define FLAG_TARC_SPEED_MODE_BIT          (1 << 22)
+#define FLAG_TARC_SET_BIT_ZERO            (1 << 23)
+#define FLAG_RX_NEEDS_RESTART             (1 << 24)
+#define FLAG_LSC_GIG_SPEED_DROP           (1 << 25)
+#define FLAG_SMART_POWER_DOWN             (1 << 26)
+#define FLAG_MSI_ENABLED                  (1 << 27)
+#define FLAG_RX_CSUM_ENABLED              (1 << 28)
+#define FLAG_TSO_FORCE                    (1 << 29)
+#define FLAG_RX_RESTART_NOW               (1 << 30)
+#define FLAG_MSI_TEST_FAILED              (1 << 31)
+
+/* CRC Stripping defines */
+#define FLAG2_CRC_STRIPPING               (1 << 0)
+#define FLAG2_HAS_PHY_WAKEUP              (1 << 1)
+
+#define E1000_RX_DESC_PS(R, i)	    \
+	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
+
+enum e1000_state_t {
+	__E1000E_TESTING,
+	__E1000E_RESETTING,
+	__E1000E_DOWN
+};
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+extern void e1000e_check_options(struct e1000_adapter *adapter);
+
+extern void e1000e_reset(struct e1000_adapter *adapter);
+extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
+
+extern void e1000e_init_function_pointers_82571(struct e1000_hw *hw)
+						__attribute__((weak));
+extern void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw)
+						__attribute__((weak));
+extern void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw)
+						__attribute__((weak));
+
+extern int e1000e_probe(struct pci_device *pdev);
+
+extern void e1000e_remove(struct pci_device *pdev);
+
+extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
+
+static inline s32 e1000e_commit_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.commit)
+		return hw->phy.ops.commit(hw);
+
+	return 0;
+}
+
+extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+						 bool state);
+extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+
+extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
+extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+extern s32 e1000e_id_led_init(struct e1000_hw *hw);
+extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+extern s32 e1000e_setup_link(struct e1000_hw *hw);
+static inline void e1000e_clear_vfta(struct e1000_hw *hw)
+{
+	hw->mac.ops.clear_vfta(hw);
+}
+extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
+					       u8 *mc_addr_list,
+					       u32 mc_addr_count);
+extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+extern void e1000e_config_collision_dist(struct e1000_hw *hw);
+extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+extern s32 e1000e_blink_led(struct e1000_hw *hw);
+extern void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+static inline void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	if (hw->mac.ops.write_vfta)
+		hw->mac.ops.write_vfta(hw, offset, value);
+}
+extern void e1000e_reset_adaptive(struct e1000_hw *hw);
+extern void e1000e_update_adaptive(struct e1000_hw *hw);
+
+extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+#if 0
+extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+#endif
+#if 0
+extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+#endif
+extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+#if 0
+extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+#endif
+extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
+#if 0
+extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+#endif
+extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
+extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+#if 0
+extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+#endif
+extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+			       u32 usec_interval, bool *success);
+extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_check_downshift(struct e1000_hw *hw);
+
+static inline s32 e1000e_phy_hw_reset(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.reset)
+		return hw->phy.ops.reset(hw);
+
+	return 0;
+}
+
+static inline s32 e1000e_check_reset_block(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.check_reset_block)
+		return hw->phy.ops.check_reset_block(hw);
+
+	return 0;
+}
+
+static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	if (hw->phy.ops.read_reg)
+		return hw->phy.ops.read_reg(hw, offset, data);
+
+	return 0;
+}
+
+static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	if (hw->phy.ops.write_reg)
+		return hw->phy.ops.write_reg(hw, offset, data);
+
+	return 0;
+}
+
+#if 0
+static inline s32 e1000e_get_cable_length(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_cable_length)
+		return hw->phy.ops.get_cable_length(hw);
+
+	return 0;
+}
+#endif
+
+extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+extern void e1000e_release_nvm(struct e1000_hw *hw);
+
+static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+       if (hw->mac.ops.read_mac_addr)
+               return hw->mac.ops.read_mac_addr(hw);
+
+       return e1000e_read_mac_addr_generic(hw);
+}
+
+static inline s32 e1000e_validate_nvm_checksum(struct e1000_hw *hw)
+{
+	return hw->nvm.ops.validate(hw);
+}
+
+static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
+{
+	return hw->nvm.ops.update(hw);
+}
+
+static inline s32 e1000e_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	return hw->nvm.ops.read(hw, offset, words, data);
+}
+
+static inline s32 e1000e_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	return hw->nvm.ops.write(hw, offset, words, data);
+}
+
+static inline s32 e1000e_get_phy_info(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_info)
+		return hw->phy.ops.get_info(hw);
+
+	return 0;
+}
+
+extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+#if 0
+extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+#endif
+
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
+{
+	return readl(hw->hw_addr + reg);
+}
+
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+	writel(val, hw->hw_addr + reg);
+}
+
+#define er32(reg)	__er32(hw, E1000_##reg)
+#define ew32(reg, val)	__ew32(hw, E1000_##reg, (val))
+#define e1e_flush()	er32(STATUS)
+
+#define E1000_WRITE_REG(a, reg, value)  \
+    writel((value), ((a)->hw_addr + reg))
+
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value)  \
+    writel((value), ((a)->hw_addr + reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
+{
+	return readw(hw->flash_address + reg);
+}
+
+static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
+{
+	return readl(hw->flash_address + reg);
+}
+
+static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
+{
+	writew(val, hw->flash_address + reg);
+}
+
+static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+	writel(val, hw->flash_address + reg);
+}
+
+#define er16flash(reg)		__er16flash(hw, (reg))
+#define er32flash(reg)		__er32flash(hw, (reg))
+#define ew16flash(reg, val)	__ew16flash(hw, (reg), (val))
+#define ew32flash(reg, val)	__ew32flash(hw, (reg), (val))
+
+#endif /* _E1000E_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c
new file mode 100644
index 0000000..a3eed9b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c
@@ -0,0 +1,1533 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include "e1000e.h"
+
+static s32  e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw);
+static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw);
+static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                   u32 offset,
+                                                   u16 *data);
+static s32  e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                    u32 offset,
+                                                    u16 data);
+static s32  e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+                                        u16 words, u16 *data);
+static s32  e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw);
+#if 0
+static s32  e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
+#endif
+#if 0
+static s32  e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw);
+#endif
+static s32  e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+static s32  e1000e_reset_hw_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_init_hw_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static s32  e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+static s32  e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
+static s32  e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                            u16 *data);
+static s32  e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                             u16 data);
+static s32  e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
+static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static s32  e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw);
+static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
+
+#if 0
+/*
+ * A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const u16 e1000_gg82563_cable_length_table[] =
+         { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+#define GG82563_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_gg82563_cable_length_table) / \
+                 sizeof(e1000_gg82563_cable_length_table[0]))
+#endif
+
+/**
+ *  e1000e_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type        = e1000_phy_none;
+		goto out;
+	} else {
+		phy->ops.power_up = e1000e_power_up_phy_copper;
+		phy->ops.power_down = e1000e_power_down_phy_copper_80003es2lan;
+	}
+
+	phy->addr                = 1;
+	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us      = 100;
+	phy->type                = e1000_phy_gg82563;
+
+	phy->ops.acquire            = e1000e_acquire_phy_80003es2lan;
+	phy->ops.check_polarity     = e1000e_check_polarity_m88;
+	phy->ops.check_reset_block  = e1000e_check_reset_block_generic;
+	phy->ops.commit             = e1000e_phy_sw_reset;
+	phy->ops.get_cfg_done       = e1000e_get_cfg_done_80003es2lan;
+	phy->ops.get_info           = e1000e_get_phy_info_m88;
+	phy->ops.release            = e1000e_release_phy_80003es2lan;
+	phy->ops.reset              = e1000e_phy_hw_reset_generic;
+	phy->ops.set_d3_lplu_state  = e1000e_set_d3_lplu_state;
+#if 0
+	phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_80003es2lan;
+#endif
+#if 0
+	phy->ops.get_cable_length   = e1000e_get_cable_length_80003es2lan;
+#endif
+	phy->ops.read_reg           = e1000e_read_phy_reg_gg82563_80003es2lan;
+	phy->ops.write_reg          = e1000e_write_phy_reg_gg82563_80003es2lan;
+
+	phy->ops.cfg_on_link_up    = e1000e_cfg_on_link_up_80003es2lan;
+
+	/* This can only be done after all function pointers are setup. */
+	ret_val = e1000e_get_phy_id(hw);
+
+	/* Verify phy id */
+	if (phy->id != GG82563_E_PHY_ID) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u16 size;
+
+	nvm->opcode_bits        = 8;
+	nvm->delay_usec         = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	nvm->type               = e1000_nvm_eeprom_spi;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+	                  E1000_EECD_SIZE_EX_SHIFT);
+
+	/*
+	 * Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+
+	/* EEPROM access above 16k is unsupported */
+	if (size > 14)
+		size = 14;
+	nvm->word_size	= 1 << size;
+
+	/* Function Pointers */
+	nvm->ops.acquire           = e1000e_acquire_nvm_80003es2lan;
+	nvm->ops.read              = e1000e_read_nvm_eerd;
+	nvm->ops.release           = e1000e_release_nvm_80003es2lan;
+	nvm->ops.update            = e1000e_update_nvm_checksum_generic;
+	nvm->ops.valid_led_default = e1000e_valid_led_default;
+	nvm->ops.validate          = e1000e_validate_nvm_checksum_generic;
+	nvm->ops.write             = e1000e_write_nvm_80003es2lan;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+	        (er32(FWSM) & E1000_FWSM_MODE_MASK)
+	                ? true : false;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000e_get_bus_info_pcie;
+	/* reset */
+	mac->ops.reset_hw = e1000e_reset_hw_80003es2lan;
+	/* hw initialization */
+	mac->ops.init_hw = e1000e_init_hw_80003es2lan;
+	/* link setup */
+	mac->ops.setup_link = e1000e_setup_link;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000e_setup_copper_link_80003es2lan
+	                : e1000e_setup_fiber_serdes_link;
+	/* check for link */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		mac->ops.check_for_link = e1000e_check_for_copper_link;
+		break;
+	case e1000_media_type_fiber:
+		mac->ops.check_for_link = e1000e_check_for_fiber_link;
+		break;
+	case e1000_media_type_internal_serdes:
+		mac->ops.check_for_link = e1000e_check_for_serdes_link;
+		break;
+	default:
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+	/* check management mode */
+#if 0
+	mac->ops.check_mng_mode = e1000e_check_mng_mode_generic;
+#endif
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000e_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000e_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000e_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000e_read_mac_addr_80003es2lan;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000e_id_led_init;
+	/* blink LED */
+	mac->ops.blink_led = e1000e_blink_led;
+	/* setup LED */
+	mac->ops.setup_led = e1000e_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000e_cleanup_led_generic;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000e_led_on_generic;
+	mac->ops.led_off = e1000e_led_off_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_80003es2lan;
+	/* link info */
+	mac->ops.get_link_up_info = e1000e_get_link_up_info_80003es2lan;
+
+	/* set lan id for port to determine which phy lock to use */
+	hw->mac.ops.set_lan_id(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_function_pointers_80003es2lan - Init ESB2 func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw)
+{
+	e1000e_init_mac_ops_generic(hw);
+	e1000e_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000e_init_mac_params_80003es2lan;
+	hw->nvm.ops.init_params = e1000e_init_nvm_params_80003es2lan;
+	hw->phy.ops.init_params = e1000e_init_phy_params_80003es2lan;
+}
+
+/**
+ *  e1000e_acquire_phy_80003es2lan - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to acquire access rights to the correct PHY.
+ **/
+static s32 e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	return e1000e_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000e_release_phy_80003es2lan - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.
+ **/
+static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	e1000e_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000e_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the semaphore to access the Kumeran interface.
+ *
+ **/
+static s32 e1000e_acquire_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = E1000_SWFW_CSR_SM;
+
+	return e1000e_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000e_release_mac_csr_80003es2lan - Release rights to access Kumeran Register
+ *  @hw: pointer to the HW structure
+ *
+ *  Release the semaphore used to access the Kumeran interface
+ **/
+static void e1000e_release_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = E1000_SWFW_CSR_SM;
+
+	e1000e_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000e_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the semaphore to access the EEPROM.
+ **/
+static s32 e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_acquire_nvm(hw);
+
+	if (ret_val)
+		e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_release_nvm_80003es2lan - Relinquish rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Release the semaphore used to access the EEPROM.
+ **/
+static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	e1000e_release_nvm(hw);
+	e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000e_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = E1000_SUCCESS;
+	s32 i = 0, timeout = 50;
+
+	while (i < timeout) {
+		if (e1000e_get_hw_semaphore(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = er32(SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/*
+		 * Firmware currently using resource (fwmask)
+		 * or other software thread using resource (swmask)
+		 */
+		e1000e_put_hw_semaphore(hw);
+		mdelay(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		e_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	ew32(SW_FW_SYNC, swfw_sync);
+
+	e1000e_put_hw_semaphore(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	while (e1000e_get_hw_semaphore(hw) != E1000_SUCCESS)
+		; /* Empty */
+
+	swfw_sync = er32(SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	ew32(SW_FW_SYNC, swfw_sync);
+
+	e1000e_put_hw_semaphore(hw);
+}
+
+/**
+ *  e1000e_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: pointer to the data returned from the operation
+ *
+ *  Read the GG82563 PHY register.
+ **/
+static s32 e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                  u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	ret_val = e1000e_acquire_phy_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+		page_select = GG82563_PHY_PAGE_SELECT;
+	} else {
+		/*
+		 * Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+	}
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
+	if (ret_val) {
+		e1000e_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
+		/*
+		 * The "ready" bit in the MDIC register may be incorrectly set
+		 * before the device has completed the "Page Select" MDI
+		 * transaction.  So we wait 200us after each MDI command...
+		 */
+		udelay(200);
+
+		/* ...and verify the command was successful. */
+		ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
+
+		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+			ret_val = -E1000_ERR_PHY;
+			e1000e_release_phy_80003es2lan(hw);
+			goto out;
+		}
+
+		udelay(200);
+
+		ret_val = e1000e_read_phy_reg_mdic(hw,
+		                                  MAX_PHY_REG_ADDRESS & offset,
+		                                  data);
+
+		udelay(200);
+	} else
+		ret_val = e1000e_read_phy_reg_mdic(hw,
+		                                  MAX_PHY_REG_ADDRESS & offset,
+		                                  data);
+
+	e1000e_release_phy_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: value to write to the register
+ *
+ *  Write to the GG82563 PHY register.
+ **/
+static s32 e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                   u32 offset, u16 data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	ret_val = e1000e_acquire_phy_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+		page_select = GG82563_PHY_PAGE_SELECT;
+	} else {
+		/*
+		 * Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+	}
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
+	if (ret_val) {
+		e1000e_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
+		/*
+		 * The "ready" bit in the MDIC register may be incorrectly set
+		 * before the device has completed the "Page Select" MDI
+		 * transaction.  So we wait 200us after each MDI command...
+		 */
+		udelay(200);
+
+		/* ...and verify the command was successful. */
+		ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
+
+		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+			ret_val = -E1000_ERR_PHY;
+			e1000e_release_phy_80003es2lan(hw);
+			goto out;
+		}
+
+		udelay(200);
+
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+		                                  MAX_PHY_REG_ADDRESS & offset,
+		                                  data);
+
+		udelay(200);
+	} else
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+		                                  MAX_PHY_REG_ADDRESS & offset,
+		data);
+
+	e1000e_release_phy_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_nvm_80003es2lan - Write to ESB2 NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @words: number of words to write
+ *  @data: buffer of data to write to the NVM
+ *
+ *  Write "words" of data to the ESB2 NVM.
+ **/
+static s32 e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+                            u16 words, u16 *data)
+{
+	return e1000e_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ *  e1000e_get_cfg_done_80003es2lan - Wait for configuration to complete
+ *  @hw: pointer to the HW structure
+ *
+ *  Wait a specific amount of time for manageability processes to complete.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	if (hw->bus.func == 1)
+		mask = E1000_NVM_CFG_DONE_PORT_1;
+
+	while (timeout) {
+		if (er32(EEMNGCTL) & mask)
+			break;
+		msleep(1);
+		timeout--;
+	}
+	if (!timeout) {
+		e_dbg("MNG configuration cycle has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the speed and duplex settings onto the PHY.  This is a
+ *  function pointer entry point called by the phy module.
+ **/
+static s32 e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data;
+	bool link;
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	e_dbg("GG82563 PSCR: %X\n", phy_data);
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	udelay(1);
+
+	if (hw->phy.autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link "
+		         "on GG82563 phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = e1000e_phy_reset_dsp(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to verify the TX_CLK corresponds
+	 * to the link speed.  10Mbps -> 2.5MHz, else 25MHz.
+	 */
+	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+	if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+	else
+		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  e1000e_get_cable_length_80003es2lan - Set approximate cable length
+ *  @hw: pointer to the HW structure
+ *
+ *  Find the approximate cable length as measured by the GG82563 PHY.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, index;
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+
+	if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+	phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000e_get_link_up_info_80003es2lan - Report speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to speed buffer
+ *  @duplex: pointer to duplex buffer
+ *
+ *  Retrieve the current speed and duplex configuration.
+ **/
+static s32 e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	s32 ret_val;
+
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		ret_val = e1000e_get_speed_and_duplex_copper(hw,
+		                                                    speed,
+		                                                    duplex);
+		hw->phy.ops.cfg_on_link_up(hw);
+	} else {
+		ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
+		                                                  speed,
+		                                                  duplex);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_reset_hw_80003es2lan - Reset the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Perform a global reset to the ESB2 controller.
+ **/
+static s32 e1000e_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val)
+		e_dbg("PCI-E Master disable polling has failed.\n");
+
+	e_dbg("Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	ctrl = er32(CTRL);
+
+	ret_val = e1000e_acquire_phy_80003es2lan(hw);
+	e_dbg("Issuing a global reset to MAC\n");
+	ew32(CTRL, ctrl | E1000_CTRL_RST);
+	e1000e_release_phy_80003es2lan(hw);
+
+	ret_val = e1000e_get_auto_rd_done(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		goto out;
+
+	/* Clear any pending interrupt events. */
+	ew32(IMC, 0xffffffff);
+	er32(ICR);
+
+	ret_val = e1000e_check_alt_mac_addr_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_hw_80003es2lan - Initialize the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ **/
+static s32 e1000e_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i;
+
+	e1000e_initialize_hw_bits_80003es2lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val) {
+		e_dbg("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	e_dbg("Initializing the IEEE VLAN\n");
+	e1000e_clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	e_dbg("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = er32(TXDCTL(0));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL(0), reg_data);
+
+	/* ...for both queues. */
+	reg_data = er32(TXDCTL(1));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL(1), reg_data);
+
+	/* Enable retransmit on late collisions */
+	reg_data = er32(TCTL);
+	reg_data |= E1000_TCTL_RTLC;
+	ew32(TCTL, reg_data);
+
+	/* Configure Gigabit Carry Extend Padding */
+	reg_data = er32(TCTL_EXT);
+	reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+	reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+	ew32(TCTL_EXT, reg_data);
+
+	/* Configure Transmit Inter-Packet Gap */
+	reg_data = er32(TIPG);
+	reg_data &= ~E1000_TIPG_IPGT_MASK;
+	reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	ew32(TIPG, reg_data);
+
+	reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+	reg_data &= ~0x00100000;
+	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+	/* default to true to enable the MDIC W/A */
+	hw->dev_spec._80003es2lan.mdic_wa_enable = true;
+
+	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
+	                              E1000_KMRNCTRLSTA_OFFSET >>
+	                              E1000_KMRNCTRLSTA_OFFSET_SHIFT,
+	                              &i);
+	if (!ret_val) {
+		if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
+		     E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
+			hw->dev_spec._80003es2lan.mdic_wa_enable = false;
+	}
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000e_clear_hw_cntrs_80003es2lan(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL(0));
+	reg |= (1 << 22);
+	ew32(TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL(1));
+	reg |= (1 << 22);
+	ew32(TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC(0));
+	reg &= ~(0xF << 27); /* 30:27 */
+	if (hw->phy.media_type != e1000_media_type_copper)
+		reg &= ~(1 << 20);
+	ew32(TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC(1));
+	if (er32(TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	ew32(TARC(1), reg);
+
+	return;
+}
+
+/**
+ *  e1000e_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ *  @hw: pointer to the HW structure
+ *
+ *  Setup some GG82563 PHY registers for obtaining link
+ **/
+static s32 e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u32 ctrl_ext;
+	u16 data;
+
+	if (!phy->reset_disable) {
+		ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+		/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+		data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+		ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Options:
+		 *   MDI/MDI-X = 0 (default)
+		 *   0 - Auto for all speeds
+		 *   1 - MDI mode
+		 *   2 - MDI-X mode
+		 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+		 */
+		ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+		switch (phy->mdix) {
+		case 1:
+			data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+			break;
+		case 2:
+			data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+			break;
+		case 0:
+		default:
+			data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+			break;
+		}
+
+		/*
+		 * Options:
+		 *   disable_polarity_correction = 0 (default)
+		 *       Automatic Correction for Reversed Cable Polarity
+		 *   0 - Disabled
+		 *   1 - Enabled
+		 */
+		data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+		if (phy->disable_polarity_correction)
+			data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+		ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
+		if (ret_val)
+			goto out;
+
+		/* SW Reset the PHY so all changes take effect */
+		ret_val = e1000e_commit_phy(hw);
+		if (ret_val) {
+			e_dbg("Error Resetting the PHY\n");
+			goto out;
+		}
+
+	}
+
+	/* Bypass Rx and Tx FIFO's */
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
+					E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+					E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+					E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
+	                              E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+	                              &data);
+	if (ret_val)
+		goto out;
+	data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+	                               data);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
+	if (ret_val)
+		goto out;
+
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+	ew32(CTRL_EXT, ctrl_ext);
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Do not init these registers when the HW is in IAMT mode, since the
+	 * firmware will have already initialized them.  We only initialize
+	 * them if the HW is not in IAMT mode.
+	 */
+	if (!(hw->mac.ops.check_mng_mode(hw))) {
+		/* Enable Electrical Idle on the PHY */
+		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+		ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL,
+		                                data);
+		if (ret_val)
+			goto out;
+
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                               &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+		ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                                data);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Workaround: Disable padding in Kumeran interface in the MAC
+	 * and in the PHY to avoid CRC errors.
+	 */
+	ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data |= GG82563_ICR_DIS_PADDING;
+	ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
+	if (ret_val)
+		goto out;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Essentially a wrapper for setting up all things "copper" related.
+ *  This is a function pointer entry point called by the mac module.
+ **/
+static s32 e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	u16 reg_data;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	/*
+	 * Set the mac to wait the maximum time between each
+	 * iteration and increase the max iterations when
+	 * polling the phy; this fixes erroneous timeouts at 10Mbps.
+	 */
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
+	                                           0xFFFF);
+	if (ret_val)
+		goto out;
+	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+	                                          &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= 0x3F;
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+	                                           reg_data);
+	if (ret_val)
+		goto out;
+	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
+	                              E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+	                              &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_copper_link_setup_gg82563_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_setup_copper_link(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_cfg_on_link_up_80003es2lan - es2 link configuration after link-up
+ *  @hw: pointer to the HW structure
+ *  @duplex: current duplex setting
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  10/100 operation.
+ **/
+static s32 e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 speed;
+	u16 duplex;
+
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		ret_val = e1000e_get_speed_and_duplex_copper(hw,
+		                                                    &speed,
+		                                                    &duplex);
+		if (ret_val)
+			goto out;
+
+		if (speed == SPEED_1000)
+			ret_val = e1000e_cfg_kmrn_1000_80003es2lan(hw);
+		else
+			ret_val = e1000e_cfg_kmrn_10_100_80003es2lan(hw, duplex);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ *  @hw: pointer to the HW structure
+ *  @duplex: current duplex setting
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  10/100 operation.
+ **/
+static s32 e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 tipg;
+	u32 i = 0;
+	u16 reg_data, reg_data2;
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = er32(TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+	ew32(TIPG, tipg);
+
+
+	do {
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                               &reg_data);
+		if (ret_val)
+			goto out;
+
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                               &reg_data2);
+		if (ret_val)
+			goto out;
+		i++;
+	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+	if (duplex == HALF_DUPLEX)
+		reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+	else
+		reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  gigabit operation.
+ **/
+static s32 e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg_data, reg_data2;
+	u32 tipg;
+	u32 i = 0;
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = er32(TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	ew32(TIPG, tipg);
+
+
+	do {
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                               &reg_data);
+		if (ret_val)
+			goto out;
+
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                               &reg_data2);
+		if (ret_val)
+			goto out;
+		i++;
+	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+	reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_kmrn_reg_80003es2lan - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquire semaphore, then read the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release the semaphore before exiting.
+ **/
+static s32 e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                           u16 *data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	ret_val = e1000e_acquire_mac_csr_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	kmrnctrlsta = er32(KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	e1000e_release_mac_csr_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_kmrn_reg_80003es2lan - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquire semaphore, then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release semaphore
+ *  before exiting.
+ **/
+static s32 e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                            u16 data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	ret_val = e1000e_acquire_mac_csr_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	e1000e_release_mac_csr_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_mac_addr_80003es2lan - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * If there's an alternate MAC address place it in RAR0
+	 * so that it will override the Si installed default perm
+	 * address.
+	 */
+	ret_val = e1000e_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_read_mac_addr_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000e_power_down_phy_copper_80003es2lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
+{
+	/* If the management interface is not enabled, then power down */
+	if (!(hw->mac.ops.check_mng_mode(hw) ||
+	      e1000e_check_reset_block(hw)))
+             e1000e_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000e_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw __unused)
+{
+#if 0
+	e1000e_clear_hw_cntrs_base(hw);
+
+	er32(PRC64);
+	er32(PRC127);
+	er32(PRC255);
+	er32(PRC511);
+	er32(PRC1023);
+	er32(PRC1522);
+	er32(PTC64);
+	er32(PTC127);
+	er32(PTC255);
+	er32(PTC511);
+	er32(PTC1023);
+	er32(PTC1522);
+
+	er32(ALGNERRC);
+	er32(RXERRC);
+	er32(TNCRS);
+	er32(CEXTERR);
+	er32(TSCTC);
+	er32(TSCTFC);
+
+	er32(MGTPRC);
+	er32(MGTPDC);
+	er32(MGTPTC);
+
+	er32(IAC);
+	er32(ICRXOC);
+
+	er32(ICRXPTC);
+	er32(ICRXATC);
+	er32(ICTXPTC);
+	er32(ICTXATC);
+	er32(ICTXQEC);
+	er32(ICTXQMTC);
+	er32(ICRXDMTC);
+#endif
+}
+
+static struct pci_device_id e1000e_80003es2lan_nics[] = {
+     PCI_ROM(0x8086, 0x1096, "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", board_80003es2lan),
+     PCI_ROM(0x8086, 0x10BA, "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", board_80003es2lan),
+     PCI_ROM(0x8086, 0x1098, "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", board_80003es2lan),
+     PCI_ROM(0x8086, 0x10BB, "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", board_80003es2lan),
+};
+
+struct pci_driver e1000e_80003es2lan_driver __pci_driver = {
+	.ids = e1000e_80003es2lan_nics,
+	.id_count = (sizeof (e1000e_80003es2lan_nics) / sizeof (e1000e_80003es2lan_nics[0])),
+	.probe = e1000e_probe,
+	.remove = e1000e_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h
new file mode 100644
index 0000000..93430a1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_80003ES2LAN_H_
+#define _E1000E_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL       0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL        0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL         0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE  0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS    0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS    0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING   0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT   0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE          0x2000
+
+#define E1000_KMRNCTRLSTA_OPMODE_MASK            0x000C
+#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO     0x0004
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN        0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN       0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN     0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE  0x0002 /* 1=Reversal Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK        0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI         0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX        0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO        0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG          0x2000
+                                               /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK                0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5          0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25          0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5        0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25         0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX           0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH               0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER         0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY                  0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE     0x0001
+                                          /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING                 0x0010 /* Disable Padding */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c
new file mode 100644
index 0000000..a061d6d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c
@@ -0,0 +1,1818 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Copper)
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82571EB Dual Port Gigabit Mezzanine Adapter
+ * 82571EB Quad Port Gigabit Mezzanine Adapter
+ * 82571PT Gigabit PT Quad Port Server ExpressModule
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+ * 82574L Gigabit Network Connection
+ * 82574L Gigabit Network Connection
+ * 82583V Gigabit Network Connection
+ */
+
+#include "e1000e.h"
+
+static s32  e1000e_init_phy_params_82571(struct e1000_hw *hw);
+static s32  e1000e_init_nvm_params_82571(struct e1000_hw *hw);
+static s32  e1000e_init_mac_params_82571(struct e1000_hw *hw);
+static s32  e1000e_acquire_nvm_82571(struct e1000_hw *hw);
+static void e1000e_release_nvm_82571(struct e1000_hw *hw);
+static s32  e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset,
+                                  u16 words, u16 *data);
+static s32  e1000e_update_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000e_get_cfg_done_82571(struct e1000_hw *hw);
+static s32  e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw,
+                                          bool active);
+static s32  e1000e_reset_hw_82571(struct e1000_hw *hw);
+static s32  e1000e_init_hw_82571(struct e1000_hw *hw);
+static void e1000e_clear_vfta_82571(struct e1000_hw *hw);
+#if 0
+static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw);
+#endif
+static s32  e1000e_led_on_82574(struct e1000_hw *hw);
+static s32  e1000e_setup_link_82571(struct e1000_hw *hw);
+static s32  e1000e_setup_copper_link_82571(struct e1000_hw *hw);
+static s32  e1000e_check_for_serdes_link_82571(struct e1000_hw *hw);
+static s32  e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+static s32  e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data);
+static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static s32  e1000e_get_hw_semaphore_82571(struct e1000_hw *hw);
+static s32  e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000e_get_phy_id_82571(struct e1000_hw *hw);
+static void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw);
+static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw);
+static s32  e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+                                       u16 words, u16 *data);
+static s32  e1000e_read_mac_addr_82571(struct e1000_hw *hw);
+static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw);
+
+/**
+ *  e1000e_init_phy_params_82571 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_phy_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type = e1000_phy_none;
+		goto out;
+	}
+
+	phy->addr                        = 1;
+	phy->autoneg_mask                = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us              = 100;
+
+	phy->ops.acquire                 = e1000e_get_hw_semaphore_82571;
+	phy->ops.check_polarity          = e1000e_check_polarity_igp;
+	phy->ops.check_reset_block       = e1000e_check_reset_block_generic;
+	phy->ops.release                 = e1000e_put_hw_semaphore_82571;
+	phy->ops.reset                   = e1000e_phy_hw_reset_generic;
+	phy->ops.set_d0_lplu_state       = e1000e_set_d0_lplu_state_82571;
+	phy->ops.set_d3_lplu_state       = e1000e_set_d3_lplu_state;
+	phy->ops.power_up                = e1000e_power_up_phy_copper;
+	phy->ops.power_down              = e1000e_power_down_phy_copper_82571;
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		phy->type                   = e1000_phy_igp_2;
+		phy->ops.get_cfg_done       = e1000e_get_cfg_done_82571;
+		phy->ops.get_info           = e1000e_get_phy_info_igp;
+#if 0
+		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp;
+#endif
+#if 0
+		phy->ops.get_cable_length   = e1000e_get_cable_length_igp_2;
+#endif
+		phy->ops.read_reg           = e1000e_read_phy_reg_igp;
+		phy->ops.write_reg          = e1000e_write_phy_reg_igp;
+
+		/* This uses above function pointers */
+		ret_val = e1000e_get_phy_id_82571(hw);
+
+		/* Verify PHY ID */
+		if (phy->id != IGP01E1000_I_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+		break;
+	case e1000_82573:
+		phy->type                   = e1000_phy_m88;
+		phy->ops.get_cfg_done       = e1000e_get_cfg_done;
+		phy->ops.get_info           = e1000e_get_phy_info_m88;
+		phy->ops.commit             = e1000e_phy_sw_reset;
+#if 0
+		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
+#endif
+#if 0
+		phy->ops.get_cable_length   = e1000e_get_cable_length_m88;
+#endif
+		phy->ops.read_reg           = e1000e_read_phy_reg_m88;
+		phy->ops.write_reg          = e1000e_write_phy_reg_m88;
+
+		/* This uses above function pointers */
+		ret_val = e1000e_get_phy_id_82571(hw);
+
+		/* Verify PHY ID */
+		if (phy->id != M88E1111_I_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id);
+			goto out;
+		}
+		break;
+	case e1000_82583:
+	case e1000_82574:
+		phy->type                   = e1000_phy_bm;
+		phy->ops.get_cfg_done       = e1000e_get_cfg_done;
+		phy->ops.get_info           = e1000e_get_phy_info_m88;
+		phy->ops.commit             = e1000e_phy_sw_reset;
+#if 0
+		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
+#endif
+#if 0
+		phy->ops.get_cable_length   = e1000e_get_cable_length_m88;
+#endif
+		phy->ops.read_reg           = e1000e_read_phy_reg_bm2;
+		phy->ops.write_reg          = e1000e_write_phy_reg_bm2;
+
+		/* This uses above function pointers */
+		ret_val = e1000e_get_phy_id_82571(hw);
+		/* Verify PHY ID */
+		if (phy->id != BME1000_E_PHY_ID_R2) {
+			ret_val = -E1000_ERR_PHY;
+			e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id);
+			goto out;
+		}
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_nvm_params_82571 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_nvm_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u16 size;
+
+	nvm->opcode_bits = 8;
+	nvm->delay_usec = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		if (((eecd >> 15) & 0x3) == 0x3) {
+			nvm->type = e1000_nvm_flash_hw;
+			nvm->word_size = 2048;
+			/*
+			 * Autonomous Flash update bit must be cleared due
+			 * to Flash update issue.
+			 */
+			eecd &= ~E1000_EECD_AUPDEN;
+			ew32(EECD, eecd);
+			break;
+		}
+		/* Fall Through */
+	default:
+		nvm->type = e1000_nvm_eeprom_spi;
+		size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+		                  E1000_EECD_SIZE_EX_SHIFT);
+		/*
+		 * Added to a constant, "size" becomes the left-shift value
+		 * for setting word_size.
+		 */
+		size += NVM_WORD_SIZE_BASE_SHIFT;
+
+		/* EEPROM access above 16k is unsupported */
+		if (size > 14)
+			size = 14;
+		nvm->word_size	= 1 << size;
+		break;
+	}
+
+	/* Function Pointers */
+	nvm->ops.acquire       = e1000e_acquire_nvm_82571;
+	nvm->ops.read          = e1000e_read_nvm_eerd;
+	nvm->ops.release       = e1000e_release_nvm_82571;
+	nvm->ops.update        = e1000e_update_nvm_checksum_82571;
+	nvm->ops.validate      = e1000e_validate_nvm_checksum_82571;
+	nvm->ops.valid_led_default = e1000e_valid_led_default_82571;
+	nvm->ops.write         = e1000e_write_nvm_82571;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_init_mac_params_82571 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_init_mac_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+	u32 swsm = 0;
+	u32 swsm2 = 0;
+	bool force_clear_smbi = false;
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82571EB_FIBER:
+	case E1000_DEV_ID_82572EI_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+		hw->phy.media_type = e1000_media_type_fiber;
+		break;
+	case E1000_DEV_ID_82571EB_SERDES:
+	case E1000_DEV_ID_82571EB_SERDES_DUAL:
+	case E1000_DEV_ID_82571EB_SERDES_QUAD:
+	case E1000_DEV_ID_82572EI_SERDES:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+	        (er32(FWSM) & E1000_FWSM_MODE_MASK)
+	                ? true : false;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000e_get_bus_info_pcie;
+	/* function id */
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		mac->ops.set_lan_id = e1000e_set_lan_id_single_port;
+		break;
+	default:
+		break;
+	}
+	/* reset */
+	mac->ops.reset_hw = e1000e_reset_hw_82571;
+	/* hw initialization */
+	mac->ops.init_hw = e1000e_init_hw_82571;
+	/* link setup */
+	mac->ops.setup_link = e1000e_setup_link_82571;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000e_setup_copper_link_82571
+	                : e1000e_setup_fiber_serdes_link_82571;
+	/* check for link */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		mac->ops.check_for_link = e1000e_check_for_copper_link;
+		break;
+	case e1000_media_type_fiber:
+		mac->ops.check_for_link = e1000e_check_for_fiber_link;
+		break;
+	case e1000_media_type_internal_serdes:
+		mac->ops.check_for_link = e1000e_check_for_serdes_link_82571;
+		break;
+	default:
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+	/* check management mode */
+#if 0
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+		mac->ops.check_mng_mode = e1000e_check_mng_mode_82574;
+		break;
+	default:
+		mac->ops.check_mng_mode = e1000e_check_mng_mode_generic;
+		break;
+	}
+#endif
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000e_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000e_clear_vfta_82571;
+	/* setting MTA */
+	mac->ops.mta_set = e1000e_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000e_read_mac_addr_82571;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000e_id_led_init;
+	/* blink LED */
+	mac->ops.blink_led = e1000e_blink_led;
+	/* setup LED */
+	mac->ops.setup_led = e1000e_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000e_cleanup_led_generic;
+	/* turn on/off LED */
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+		mac->ops.led_on = e1000e_led_on_82574;
+		break;
+	default:
+		mac->ops.led_on = e1000e_led_on_generic;
+		break;
+	}
+	mac->ops.led_off = e1000e_led_off_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_82571;
+	/* link info */
+	mac->ops.get_link_up_info =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000e_get_speed_and_duplex_copper
+	                : e1000e_get_speed_and_duplex_fiber_serdes;
+
+	/*
+	 * Ensure that the inter-port SWSM.SMBI lock bit is clear before
+	 * first NVM or PHY acess. This should be done for single-port
+	 * devices, and for one port only on dual-port devices so that
+	 * for those devices we can still use the SMBI lock to synchronize
+	 * inter-port accesses to the PHY & NVM.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		swsm2 = er32(SWSM2);
+
+		if (!(swsm2 & E1000_SWSM2_LOCK)) {
+			/* Only do this for the first interface on this card */
+			ew32(SWSM2,
+			    swsm2 | E1000_SWSM2_LOCK);
+			force_clear_smbi = true;
+		} else
+			force_clear_smbi = false;
+		break;
+	default:
+		force_clear_smbi = true;
+		break;
+	}
+
+	if (force_clear_smbi) {
+		/* Make sure SWSM.SMBI is clear */
+		swsm = er32(SWSM);
+		if (swsm & E1000_SWSM_SMBI) {
+			/* This bit should not be set on a first interface, and
+			 * indicates that the bootagent or EFI code has
+			 * improperly left this bit enabled
+			 */
+			e_dbg("Please update your 82571 Bootagent\n");
+		}
+		ew32(SWSM, swsm & ~E1000_SWSM_SMBI);
+	}
+
+	/*
+	 * Initialze device specific counter of SMBI acquisition
+	 * timeouts.
+	 */
+	 hw->dev_spec._82571.smb_counter = 0;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_function_pointers_82571 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void e1000e_init_function_pointers_82571(struct e1000_hw *hw)
+{
+	e1000e_init_mac_ops_generic(hw);
+	e1000e_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000e_init_mac_params_82571;
+	hw->nvm.ops.init_params = e1000e_init_nvm_params_82571;
+	hw->phy.ops.init_params = e1000e_init_phy_params_82571;
+}
+
+/**
+ *  e1000e_get_phy_id_82571 - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+static s32 e1000e_get_phy_id_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id = 0;
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/*
+		 * The 82571 firmware may still be configuring the PHY.
+		 * In this case, we cannot access the PHY until the
+		 * configuration is done.  So we explicitly set the
+		 * PHY ID.
+		 */
+		phy->id = IGP01E1000_I_PHY_ID;
+		break;
+	case e1000_82573:
+		ret_val = e1000e_get_phy_id(hw);
+		break;
+	case e1000_82574:
+	case e1000_82583:
+		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		udelay(20);
+		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_hw_semaphore_82571 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000e_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 sw_timeout = hw->nvm.word_size + 1;
+	s32 fw_timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/*
+	 * If we have timedout 3 times on trying to acquire
+	 * the inter-port SMBI semaphore, there is old code
+	 * operating on the other port, and it is not
+	 * releasing SMBI. Modify the number of times that
+	 * we try for the semaphore to interwork with this
+	 * older code.
+	 */
+	if (hw->dev_spec._82571.smb_counter > 2)
+		sw_timeout = 1;
+
+	/* Get the SW semaphore */
+	while (i < sw_timeout) {
+		swsm = er32(SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		udelay(50);
+		i++;
+	}
+
+	if (i == sw_timeout) {
+		e_dbg("Driver can't access device - SMBI bit is set.\n");
+		hw->dev_spec._82571.smb_counter++;
+	}
+	/* Get the FW semaphore. */
+	for (i = 0; i < fw_timeout; i++) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (er32(SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		udelay(50);
+	}
+
+	if (i == fw_timeout) {
+		/* Release semaphores */
+		e1000e_put_hw_semaphore_82571(hw);
+		e_dbg("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_put_hw_semaphore_82571 - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = er32(SWSM);
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+	ew32(SWSM, swsm);
+}
+
+/**
+ *  e1000e_acquire_nvm_82571 - Request for access to the EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ *  Then for non-82573 hardware, set the EEPROM access request bit and wait
+ *  for EEPROM access grant bit.  If the access grant bit is not set, release
+ *  hardware semaphore.
+ **/
+static s32 e1000e_acquire_nvm_82571(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_get_hw_semaphore_82571(hw);
+	if (ret_val)
+		goto out;
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		break;
+	default:
+		ret_val = e1000e_acquire_nvm(hw);
+		break;
+	}
+
+	if (ret_val)
+		e1000e_put_hw_semaphore_82571(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_release_nvm_82571 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+static void e1000e_release_nvm_82571(struct e1000_hw *hw)
+{
+	e1000e_release_nvm(hw);
+	e1000e_put_hw_semaphore_82571(hw);
+}
+
+/**
+ *  e1000e_write_nvm_82571 - Write to EEPROM using appropriate interface
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
+                                 u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		ret_val = e1000e_write_nvm_eewr_82571(hw, offset, words, data);
+		break;
+	case e1000_82571:
+	case e1000_82572:
+		ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
+		break;
+	default:
+		ret_val = -E1000_ERR_NVM;
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_update_nvm_checksum_82571 - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+static s32 e1000e_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	u32 eecd;
+	s32 ret_val;
+	u16 i;
+
+	ret_val = e1000e_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * If our nvm is an EEPROM, then we're done
+	 * otherwise, commit the checksum to the flash NVM.
+	 */
+	if (hw->nvm.type != e1000_nvm_flash_hw)
+		goto out;
+
+	/* Check for pending operations. */
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msleep(1);
+		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Reset the firmware if using STM opcode. */
+	if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+		/*
+		 * The enabling of and the actual reset must be done
+		 * in two write cycles.
+		 */
+		ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
+		e1e_flush();
+		ew32(HICR, E1000_HICR_FW_RESET);
+	}
+
+	/* Commit the write to flash */
+	eecd = er32(EECD) | E1000_EECD_FLUPD;
+	ew32(EECD, eecd);
+
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msleep(1);
+		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+static s32 e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	if (hw->nvm.type == e1000_nvm_flash_hw)
+		e1000e_fix_nvm_checksum_82571(hw);
+
+	return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ *  e1000e_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  After checking for invalid values, poll the EEPROM to ensure the previous
+ *  command has completed before trying to write the next word.  After write
+ *  poll for completion.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+                                      u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eewr = 0;
+	s32 ret_val = 0;
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		e_dbg("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+		       ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+		       E1000_NVM_RW_REG_START;
+
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+
+		ew32(EEWR, eewr);
+
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_cfg_done_82571 - Poll for configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the management control register for the config done bit to be set.
+ **/
+static s32 e1000e_get_cfg_done_82571(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	while (timeout) {
+		if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0)
+			break;
+		msleep(1);
+		timeout--;
+	}
+	if (!timeout) {
+		e_dbg("MNG configuration cycle has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When activating LPLU
+ *  this function also disables smart speed and vice versa.  LPLU will not be
+ *  activated unless the device autonegotiation advertisement meets standards
+ *  of either 10 or 10/100 or 10/100/1000 at all duplexes.  This is a function
+ *  pointer entry point only called by PHY setup routines.
+ **/
+static s32 e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (active) {
+		data |= IGP02E1000_PM_D0_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+		if (ret_val)
+			goto out;
+	} else {
+		data &= ~IGP02E1000_PM_D0_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_reset_hw_82571 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 e1000e_reset_hw_82571(struct e1000_hw *hw)
+{
+	u32 ctrl, extcnf_ctrl, ctrl_ext;
+	s32 ret_val;
+	u16 i = 0;
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val)
+		e_dbg("PCI-E Master disable polling has failed.\n");
+
+	e_dbg("Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	/*
+	 * Must acquire the MDIO ownership before MAC reset.
+	 * Ownership defaults to firmware after a reset.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+		do {
+			ew32(EXTCNF_CTRL, extcnf_ctrl);
+			extcnf_ctrl = er32(EXTCNF_CTRL);
+
+			if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+				break;
+
+			extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+			msleep(2);
+			i++;
+		} while (i < MDIO_OWNERSHIP_TIMEOUT);
+		break;
+	default:
+		break;
+	}
+
+	ctrl = er32(CTRL);
+
+	e_dbg("Issuing a global reset to MAC\n");
+	ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+	if (hw->nvm.type == e1000_nvm_flash_hw) {
+		udelay(10);
+		ctrl_ext = er32(CTRL_EXT);
+		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+		ew32(CTRL_EXT, ctrl_ext);
+		e1e_flush();
+	}
+
+	ret_val = e1000e_get_auto_rd_done(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		goto out;
+
+	/*
+	 * Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+	 * Need to wait for Phy configuration completion before accessing
+	 * NVM and Phy.
+	 */
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		msleep(25);
+		break;
+	default:
+		break;
+	}
+
+	/* Clear any pending interrupt events. */
+	ew32(IMC, 0xffffffff);
+	er32(ICR);
+
+	/* Install any alternate MAC address into RAR0 */
+	ret_val = e1000e_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	e1000e_set_laa_state_82571(hw, true);
+
+	/* Reinitialize the 82571 serdes link state machine */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes)
+		hw->mac.serdes_link_state = e1000_serdes_link_down;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_hw_82571 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000e_init_hw_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i, rar_count = mac->rar_entry_count;
+
+	e1000e_initialize_hw_bits_82571(hw);
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val) {
+		e_dbg("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	e_dbg("Initializing the IEEE VLAN\n");
+	e1000e_clear_vfta(hw);
+
+	/* Setup the receive address. */
+	/*
+	 * If, however, a locally administered address was assigned to the
+	 * 82571, we must reserve a RAR for it to work around an issue where
+	 * resetting one port will reload the MAC on the other port.
+	 */
+	if (e1000e_get_laa_state_82571(hw))
+		rar_count--;
+	e1000e_init_rx_addrs(hw, rar_count);
+
+	/* Zero out the Multicast HASH table */
+	e_dbg("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = er32(TXDCTL(0));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB |
+	           E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL(0), reg_data);
+
+	/* ...for both queues. */
+	switch (mac->type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+#if 0
+		e1000e_enable_tx_pkt_filtering(hw);
+#endif
+		reg_data = er32(GCR);
+		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+		ew32(GCR, reg_data);
+		break;
+	default:
+		reg_data = er32(TXDCTL(1));
+		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+					E1000_TXDCTL_FULL_TX_DESC_WB |
+					E1000_TXDCTL_COUNT_DESC;
+		ew32(TXDCTL(1), reg_data);
+		break;
+	}
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000e_clear_hw_cntrs_82571(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL(0));
+	reg |= (1 << 22);
+	ew32(TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL(1));
+	reg |= (1 << 22);
+	ew32(TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC(0));
+	reg &= ~(0xF << 27); /* 30:27 */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+		break;
+	default:
+		break;
+	}
+	ew32(TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC(1));
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg &= ~((1 << 29) | (1 << 30));
+		reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+		if (er32(TCTL) & E1000_TCTL_MULR)
+			reg &= ~(1 << 28);
+		else
+			reg |= (1 << 28);
+		ew32(TARC(1), reg);
+		break;
+	default:
+		break;
+	}
+
+	/* Device Control */
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		reg = er32(CTRL);
+		reg &= ~(1 << 29);
+		ew32(CTRL, reg);
+		break;
+	default:
+		break;
+	}
+
+	/* Extended Device Control */
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		reg = er32(CTRL_EXT);
+		reg &= ~(1 << 23);
+		reg |= (1 << 22);
+		ew32(CTRL_EXT, reg);
+		break;
+	default:
+		break;
+	}
+
+
+	if (hw->mac.type == e1000_82571) {
+		reg = er32(PBA_ECC);
+		reg |= E1000_PBA_ECC_CORR_EN;
+		ew32(PBA_ECC, reg);
+	}
+
+	/*
+	 * Workaround for hardware errata.
+	 * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572
+	 */
+
+	if ((hw->mac.type == e1000_82571) ||
+	   (hw->mac.type == e1000_82572)) {
+		reg = er32(CTRL_EXT);
+		reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN;
+		ew32(CTRL_EXT, reg);
+	}
+
+	/* PCI-Ex Control Registers */
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+		reg = er32(GCR);
+		reg |= (1 << 22);
+		ew32(GCR, reg);
+		/*
+		 * Workaround for hardware errata.
+		 * apply workaround for hardware errata documented in errata
+		 * docs Fixes issue where some error prone or unreliable PCIe
+		 * completions are occurring, particularly with ASPM enabled.
+		 * Without fix, issue can cause tx timeouts.
+		 */
+		reg = er32(GCR2);
+		reg |= 1;
+		ew32(GCR2, reg);
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
+/**
+ *  e1000e_clear_vfta_82571 - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+static void e1000e_clear_vfta_82571(struct e1000_hw *hw)
+{
+	u32 offset;
+	u32 vfta_value = 0;
+	u32 vfta_offset = 0;
+	u32 vfta_bit_in_reg = 0;
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		if (hw->mng_cookie.vlan_id != 0) {
+			/*
+			*The VFTA is a 4096b bit-field, each identifying
+			*a single VLAN ID.  The following operations
+			*determine which 32b entry (i.e. offset) into the
+			*array we want to set the VLAN ID (i.e. bit) of
+			*the manageability unit.
+			*/
+			vfta_offset = (hw->mng_cookie.vlan_id >>
+				E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
+			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+				E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+		}
+
+		for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+			/*
+			*If the offset we want to clear is the same offset of
+			*the manageability VLAN ID, then clear all bits except
+			*that of the manageability unit
+			*/
+			vfta_value = (offset == vfta_offset) ?
+							vfta_bit_in_reg : 0;
+			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset,
+				vfta_value);
+			e1e_flush();
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+#if 0
+/**
+ *  e1000e_check_mng_mode_82574 - Check manageability is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the NVM Initialization Control Word 2 and returns true
+ *  (>0) if any manageability is enabled, else false (0).
+ **/
+static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw)
+{
+	u16 data;
+
+	e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+	return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
+}
+#endif
+
+/**
+ *  e1000e_led_on_82574 - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+static s32 e1000e_led_on_82574(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl;
+	u32 i;
+
+	ctrl = hw->mac.ledctl_mode2;
+	if (!(E1000_STATUS_LU & er32(STATUS))) {
+		/*
+		 * If no link, then turn LED on by setting the invert bit
+		 * for each LED that's "on" (0x0E) in ledctl_mode2.
+		 */
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+	}
+	ew32(LEDCTL, ctrl);
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_setup_link_82571 - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000e_setup_link_82571(struct e1000_hw *hw)
+{
+	/*
+	 * 82573 does not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		if (hw->fc.requested_mode == e1000_fc_default)
+			hw->fc.requested_mode = e1000_fc_full;
+		break;
+	default:
+		break;
+	}
+	return e1000e_setup_link(hw);
+}
+
+/**
+ *  e1000e_setup_copper_link_82571 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 e1000e_setup_copper_link_82571(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32  ret_val;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
+	case e1000_phy_bm:
+		ret_val = e1000e_copper_link_setup_m88(hw);
+		break;
+	case e1000_phy_igp_2:
+		ret_val = e1000e_copper_link_setup_igp(hw);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_setup_copper_link(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes links.
+ *  Upon successful setup, poll for link.
+ **/
+static s32 e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/*
+		 * If SerDes loopback mode is entered, there is no form
+		 * of reset to take the adapter out of that mode.  So we
+		 * have to explicitly take the adapter out of loopback
+		 * mode.  This prevents drivers from twiddling their thumbs
+		 * if another tool failed to take it out of loopback mode.
+		 */
+		ew32(SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+		break;
+	default:
+		break;
+	}
+
+	return e1000e_setup_fiber_serdes_link(hw);
+}
+
+/**
+ *  e1000e_check_for_serdes_link_82571 - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Reports the link state as up or down.
+ *
+ *  If autonegotiation is supported by the link partner, the link state is
+ *  determined by the result of autongotiation. This is the most likely case.
+ *  If autonegotiation is not supported by the link partner, and the link
+ *  has a valid signal, force the link up.
+ *
+ *  The link state is represented internally here by 4 states:
+ *
+ *  1) down
+ *  2) autoneg_progress
+ *  3) autoneg_complete (the link sucessfully autonegotiated)
+ *  4) forced_up (the link has been forced up, it did not autonegotiate)
+ *
+ **/
+s32 e1000e_check_for_serdes_link_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	ctrl = er32(CTRL);
+	status = er32(STATUS);
+	rxcw = er32(RXCW);
+
+	if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
+
+		/* Receiver is synchronized with no invalid bits.  */
+		switch (mac->serdes_link_state) {
+		case e1000_serdes_link_autoneg_complete:
+			if (!(status & E1000_STATUS_LU)) {
+				/*
+				 * We have lost link, retry autoneg before
+				 * reporting link failure
+				 */
+				mac->serdes_link_state =
+				    e1000_serdes_link_autoneg_progress;
+				mac->serdes_has_link = false;
+				e_dbg("AN_UP     -> AN_PROG\n");
+			}
+		break;
+
+		case e1000_serdes_link_forced_up:
+			/*
+			 * If we are receiving /C/ ordered sets, re-enable
+			 * auto-negotiation in the TXCW register and disable
+			 * forced link in the Device Control register in an
+			 * attempt to auto-negotiate with our link partner.
+			 */
+			if (rxcw & E1000_RXCW_C) {
+				/* Enable autoneg, and unforce link up */
+				ew32(TXCW, mac->txcw);
+				ew32(CTRL,
+				    (ctrl & ~E1000_CTRL_SLU));
+				mac->serdes_link_state =
+				    e1000_serdes_link_autoneg_progress;
+				mac->serdes_has_link = false;
+				e_dbg("FORCED_UP -> AN_PROG\n");
+			}
+			break;
+
+		case e1000_serdes_link_autoneg_progress:
+			if (rxcw & E1000_RXCW_C) {
+				/* We received /C/ ordered sets, meaning the
+				 * link partner has autonegotiated, and we can
+				 * trust the Link Up (LU) status bit
+				 */
+				if (status & E1000_STATUS_LU) {
+					mac->serdes_link_state =
+					    e1000_serdes_link_autoneg_complete;
+					e_dbg("AN_PROG   -> AN_UP\n");
+					mac->serdes_has_link = true;
+				} else {
+					/* Autoneg completed, but failed */
+					mac->serdes_link_state =
+					    e1000_serdes_link_down;
+					e_dbg("AN_PROG   -> DOWN\n");
+				}
+			} else {
+				/* The link partner did not autoneg.
+				 * Force link up and full duplex, and change
+				 * state to forced.
+				 */
+				ew32(TXCW,
+				(mac->txcw & ~E1000_TXCW_ANE));
+				ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+				ew32(CTRL, ctrl);
+
+				/* Configure Flow Control after link up. */
+				ret_val =
+				    e1000e_config_fc_after_link_up(hw);
+				if (ret_val) {
+					e_dbg("Error config flow control\n");
+					break;
+				}
+				mac->serdes_link_state =
+				e1000_serdes_link_forced_up;
+				mac->serdes_has_link = true;
+				e_dbg("AN_PROG   -> FORCED_UP\n");
+			}
+			break;
+
+		case e1000_serdes_link_down:
+		default:
+			/* The link was down but the receiver has now gained
+			 * valid sync, so lets see if we can bring the link
+			 * up. */
+			ew32(TXCW, mac->txcw);
+			ew32(CTRL,
+			    (ctrl & ~E1000_CTRL_SLU));
+			mac->serdes_link_state =
+			    e1000_serdes_link_autoneg_progress;
+			e_dbg("DOWN      -> AN_PROG\n");
+			break;
+		}
+	} else {
+		if (!(rxcw & E1000_RXCW_SYNCH)) {
+			mac->serdes_has_link = false;
+			mac->serdes_link_state = e1000_serdes_link_down;
+			e_dbg("ANYSTATE  -> DOWN\n");
+		} else {
+			/*
+			 * We have sync, and can tolerate one
+			 * invalid (IV) codeword before declaring
+			 * link down, so reread to look again
+			 */
+			udelay(10);
+			rxcw = er32(RXCW);
+			if (rxcw & E1000_RXCW_IV) {
+				mac->serdes_link_state = e1000_serdes_link_down;
+				mac->serdes_has_link = false;
+				e_dbg("ANYSTATE  -> DOWN\n");
+			}
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_valid_led_default_82571 - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
+	case e1000_82573:
+		if(*data == ID_LED_RESERVED_F746)
+			*data = ID_LED_DEFAULT_82573;
+		break;
+	default:
+		if (*data == ID_LED_RESERVED_0000 ||
+			*data == ID_LED_RESERVED_FFFF)
+			*data = ID_LED_DEFAULT;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_laa_state_82571 - Get locally administered address state
+ *  @hw: pointer to the HW structure
+ *
+ *  Retrieve and return the current locally administered address state.
+ **/
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
+{
+	if (hw->mac.type != e1000_82571)
+		return false;
+
+	return hw->dev_spec._82571.laa_is_present;
+}
+
+/**
+ *  e1000e_set_laa_state_82571 - Set locally administered address state
+ *  @hw: pointer to the HW structure
+ *  @state: enable/disable locally administered address
+ *
+ *  Enable/Disable the current locally administered address state.
+ **/
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
+{
+	if (hw->mac.type != e1000_82571)
+		return;
+
+	hw->dev_spec._82571.laa_is_present = state;
+
+	/* If workaround is activated... */
+	if (state)
+		/*
+		 * Hold a copy of the LAA in RAR[14] This is done so that
+		 * between the time RAR[0] gets clobbered and the time it
+		 * gets fixed, the actual LAA is in one of the RARs and no
+		 * incoming packets directed to this port are dropped.
+		 * Eventually the LAA will be in RAR[0] and RAR[14].
+		 */
+		e1000e_rar_set(hw, hw->mac.addr,
+		                      hw->mac.rar_entry_count - 1);
+	return;
+}
+
+/**
+ *  e1000e_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies that the EEPROM has completed the update.  After updating the
+ *  EEPROM, we need to check bit 15 in work 0x23 for the checksum fix.  If
+ *  the checksum fix is not implemented, we need to set the bit and update
+ *  the checksum.  Otherwise, if bit 15 is set and the checksum is incorrect,
+ *  we need to return bad checksum.
+ **/
+static s32 e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	if (nvm->type != e1000_nvm_flash_hw)
+		goto out;
+
+	/*
+	 * Check bit 4 of word 10h.  If it is 0, firmware is done updating
+	 * 10h-12h.  Checksum may need to be fixed.
+	 */
+	ret_val = e1000e_read_nvm(hw, 0x10, 1, &data);
+	if (ret_val)
+		goto out;
+
+	if (!(data & 0x10)) {
+		/*
+		 * Read 0x23 and check bit 15.  This bit is a 1
+		 * when the checksum has already been fixed.  If
+		 * the checksum is still wrong and this bit is a
+		 * 1, we need to return bad checksum.  Otherwise,
+		 * we need to set this bit to a 1 and update the
+		 * checksum.
+		 */
+		ret_val = e1000e_read_nvm(hw, 0x23, 1, &data);
+		if (ret_val)
+			goto out;
+
+		if (!(data & 0x8000)) {
+			data |= 0x8000;
+			ret_val = e1000e_write_nvm(hw, 0x23, 1, &data);
+			if (ret_val)
+				goto out;
+			ret_val = e1000e_update_nvm_checksum(hw);
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_mac_addr_82571 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000e_read_mac_addr_82571(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * If there's an alternate MAC address place it in RAR0
+	 * so that it will override the Si installed default perm
+	 * address.
+	 */
+	ret_val = e1000e_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_read_mac_addr_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000e_power_down_phy_copper_82571 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!(phy->ops.check_reset_block))
+		return;
+
+	/* If the management interface is not enabled, then power down */
+	if (!(mac->ops.check_mng_mode(hw) || e1000e_check_reset_block(hw)))
+		e1000e_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000e_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw __unused)
+{
+#if 0
+	e1000e_clear_hw_cntrs_base(hw);
+
+	er32(PRC64);
+	er32(PRC127);
+	er32(PRC255);
+	er32(PRC511);
+	er32(PRC1023);
+	er32(PRC1522);
+	er32(PTC64);
+	er32(PTC127);
+	er32(PTC255);
+	er32(PTC511);
+	er32(PTC1023);
+	er32(PTC1522);
+
+	er32(ALGNERRC);
+	er32(RXERRC);
+	er32(TNCRS);
+	er32(CEXTERR);
+	er32(TSCTC);
+	er32(TSCTFC);
+
+	er32(MGTPRC);
+	er32(MGTPDC);
+	er32(MGTPTC);
+
+	er32(IAC);
+	er32(ICRXOC);
+
+	er32(ICRXPTC);
+	er32(ICRXATC);
+	er32(ICTXPTC);
+	er32(ICTXATC);
+	er32(ICTXQEC);
+	er32(ICTXQMTC);
+	er32(ICRXDMTC);
+#endif
+}
+
+static struct pci_device_id e1000e_82571_nics[] = {
+     PCI_ROM(0x8086, 0x105E, "E1000_DEV_ID_82571EB_COPPER", "E1000_DEV_ID_82571EB_COPPER", board_82571),
+     PCI_ROM(0x8086, 0x105F, "E1000_DEV_ID_82571EB_FIBER", "E1000_DEV_ID_82571EB_FIBER", board_82571),
+     PCI_ROM(0x8086, 0x10A4, "E1000_DEV_ID_82571EB_QUAD_COPPER", "E1000_DEV_ID_82571EB_QUAD_COPPER", board_82571),
+     PCI_ROM(0x8086, 0x10BC, "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", board_82571),
+     PCI_ROM(0x8086, 0x10A5, "E1000_DEV_ID_82571EB_QUAD_FIBER", "E1000_DEV_ID_82571EB_QUAD_FIBER", board_82571),
+     PCI_ROM(0x8086, 0x1060, "E1000_DEV_ID_82571EB_SERDES", "E1000_DEV_ID_82571EB_SERDES", board_82571),
+     PCI_ROM(0x8086, 0x10D9, "E1000_DEV_ID_82571EB_SERDES_DUAL", "E1000_DEV_ID_82571EB_SERDES_DUAL", board_82571),
+     PCI_ROM(0x8086, 0x10DA, "E1000_DEV_ID_82571EB_SERDES_QUAD", "E1000_DEV_ID_82571EB_SERDES_QUAD", board_82571),
+     PCI_ROM(0x8086, 0x10D5, "E1000_DEV_ID_82571PT_QUAD_COPPER", "E1000_DEV_ID_82571PT_QUAD_COPPER", board_82571),
+     PCI_ROM(0x8086, 0x10B9, "E1000_DEV_ID_82572EI", "E1000_DEV_ID_82572EI", board_82572),
+     PCI_ROM(0x8086, 0x107D, "E1000_DEV_ID_82572EI_COPPER", "E1000_DEV_ID_82572EI_COPPER", board_82572),
+     PCI_ROM(0x8086, 0x107E, "E1000_DEV_ID_82572EI_FIBER", "E1000_DEV_ID_82572EI_FIBER", board_82572),
+     PCI_ROM(0x8086, 0x107F, "E1000_DEV_ID_82572EI_SERDES", "E1000_DEV_ID_82572EI_SERDES", board_82572),
+     PCI_ROM(0x8086, 0x108B, "E1000_DEV_ID_82573E", "E1000_DEV_ID_82573E", board_82573),
+     PCI_ROM(0x8086, 0x108C, "E1000_DEV_ID_82573E_IAMT", "E1000_DEV_ID_82573E_IAMT", board_82573),
+     PCI_ROM(0x8086, 0x109A, "E1000_DEV_ID_82573L", "E1000_DEV_ID_82573L", board_82573),
+     PCI_ROM(0x8086, 0x10D3, "E1000_DEV_ID_82574L", "E1000_DEV_ID_82574L", board_82574),
+     PCI_ROM(0x8086, 0x10F6, "E1000_DEV_ID_82574LA", "E1000_DEV_ID_82574LA", board_82574),
+     PCI_ROM(0x8086, 0x150C, "E1000_DEV_ID_82583V", "E1000_DEV_ID_82583V", board_82583),
+};
+
+struct pci_driver e1000e_82571_driver __pci_driver = {
+	.ids = e1000e_82571_nics,
+	.id_count = (sizeof (e1000e_82571_nics) / sizeof (e1000e_82571_nics[0])),
+	.probe = e1000e_probe,
+	.remove = e1000e_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h
new file mode 100644
index 0000000..c645e25
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h
@@ -0,0 +1,55 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_82571_H_
+#define _E1000E_82571_H_
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+                              (ID_LED_OFF1_ON2  <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n)    (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574        0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574   0x01F00000
+
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
+#define E1000_RXCFGL    0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h
new file mode 100644
index 0000000..da135d9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h
@@ -0,0 +1,1469 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_DEFINES_H_
+#define _E1000E_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO_PHY 0x00000800 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0_PHY      0x00001000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1_PHY      0x00002000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2_PHY      0x00004000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3_PHY      0x00008000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4_PHY      0x00000200 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5_PHY      0x00000400 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF /*Mask for 6 wakeup filters */
+#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/
+#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_ALL_FILTERS_6  0x003F00FF /* Mask for all 6 wakeup filters*/
+#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
+#define E1000_WUFC_FLX_FILTERS_6  0x003F0000 /* Mask for 6 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+#define E1000_WUS_ARP          E1000_WUFC_ARP
+#define E1000_WUS_IPV4         E1000_WUFC_IPV4
+#define E1000_WUS_IPV6         E1000_WUFC_IPV6
+#define E1000_WUS_FLX0_PHY      E1000_WUFC_FLX0_PHY
+#define E1000_WUS_FLX1_PHY      E1000_WUFC_FLX1_PHY
+#define E1000_WUS_FLX2_PHY      E1000_WUFC_FLX2_PHY
+#define E1000_WUS_FLX3_PHY      E1000_WUFC_FLX3_PHY
+#define E1000_WUS_FLX_FILTERS_PHY_4        E1000_WUFC_FLX_FILTERS_PHY_4
+#define E1000_WUS_FLX0         E1000_WUFC_FLX0
+#define E1000_WUS_FLX1         E1000_WUFC_FLX1
+#define E1000_WUS_FLX2         E1000_WUFC_FLX2
+#define E1000_WUS_FLX3         E1000_WUFC_FLX3
+#define E1000_WUS_FLX4         E1000_WUFC_FLX4
+#define E1000_WUS_FLX5         E1000_WUFC_FLX5
+#define E1000_WUS_FLX4_PHY         E1000_WUFC_FLX4_PHY
+#define E1000_WUS_FLX5_PHY         E1000_WUFC_FLX5_PHY
+#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
+#define E1000_WUS_FLX_FILTERS_6  E1000_WUFC_FLX_FILTERS_6
+#define E1000_WUS_FLX_FILTERS_PHY_6  E1000_WUFC_FLX_FILTERS_PHY_6
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+/* Six Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6   6
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
+                                                  * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
+                                                  * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_LSECCK         0x00001000
+#define E1000_CTRL_EXT_PHYPDEN        0x00100000
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_REG_ADDR         0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_PHY_ADDR         0x07000000
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_RESET            0x10000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDEXT_LSECH                0x01000000
+#define E1000_RXDEXT_LSECE_MASK           0x60000000
+#define E1000_RXDEXT_LSECE_NO_ERROR       0x00000000
+#define E1000_RXDEXT_LSECE_NO_SA_MATCH    0x20000000
+#define E1000_RXDEXT_LSECE_REPLAY_DETECT  0x40000000
+#define E1000_RXDEXT_LSECE_BAD_SIG        0x60000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK                 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x01
+#define E1000_SWFW_PHY0_SM  0x02
+#define E1000_SWFW_PHY1_SM  0x04
+#define E1000_SWFW_CSR_SM   0x08
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+                                             * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+                                               * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+                                           * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_CFG_PCS_EN             8
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_10            0
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_10          0
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
+                                                 * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
+                                            * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME   20
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_PHY_LED0_MODE_MASK          0x00000007
+#define E1000_PHY_LED0_IVRT               0x00000008
+#define E1000_PHY_LED0_BLINK              0x00000010
+#define E1000_PHY_LED0_MASK               0x0000001F
+
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+#define E1000_TXD_CMD_LINKSEC     0x10000000 /* Apply LinkSec on packet */
+#define E1000_TXD_EXTCMD_TSTAMP   0x00000010 /* IEEE1588 Timestamp packet */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+#define E1000_RFCTL_LEF                 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE       4
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_SPD_EN             0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K  0x0006    /* 6KB */
+#define E1000_PBA_8K  0x0008    /* 8KB */
+#define E1000_PBA_10K 0x000A    /* 10KB */
+#define E1000_PBA_12K 0x000C    /* 12KB */
+#define E1000_PBA_14K 0x000E    /* 14KB */
+#define E1000_PBA_16K 0x0010    /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB */
+#define E1000_PBA_64K 0x0040    /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
+                                            * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
+                                            * bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
+                                            * an interrupt */
+#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
+#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
+
+/* PBA ECC Register */
+#define E1000_PBA_ECC_COUNTER_MASK  0xFFF00000 /* ECC counter mask */
+#define E1000_PBA_ECC_COUNTER_SHIFT 20         /* ECC counter shift value */
+#define E1000_PBA_ECC_CORR_EN      0x00000001 /* Enable ECC error correction */
+#define E1000_PBA_ECC_STAT_CLR      0x00000002 /* Clear ECC error counter */
+#define E1000_PBA_ECC_INT_EN     0x00000004 /* Enable ICR bit 5 on ECC error */
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+#define E1000_IMS_RXQ0          E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1          E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0          E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1          E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER         E1000_ICR_OTHER /* Other Interrupts */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX      15
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
+#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_CC         0x10000000        /* Receive config change */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
+
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
+#define E1000_GCR_CAP_VER2              0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                           E1000_GCR_RXDSCW_NO_SNOOP      | \
+                           E1000_GCR_RXDSCR_NO_SNOOP      | \
+                           E1000_GCR_TXD_NO_SNOOP         | \
+                           E1000_GCR_TXDSCW_NO_SNOOP      | \
+                           E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Register */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT                 0x0003
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_VERSION                0x0005
+#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD         0x0007
+#define NVM_INIT_CONTROL1_REG      0x000A
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_FLASH_VERSION          0x0032
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+#define NVM_WORD0F_ANE              0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
+#define NVM_WORD0F_LPLU             0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_MAC_ADDR_OFFSET        0
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_RESERVED_WORD          0xFFFF
+#define NVM_PHY_CLASS_A            0x8000
+#define NVM_SERDES_AMPLITUDE_MASK  0x000F
+#define NVM_SIZE_MASK              0x1C00
+#define NVM_SIZE_SHIFT             10
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+#define NVM_SWDPIO_EXT_SHIFT       4
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+#define NVM_STATUS_WEN_SPI         0x02
+#define NVM_STATUS_BP0_SPI         0x04
+#define NVM_STATUS_BP1_SPI         0x08
+#define NVM_STATUS_WPEN_SPI        0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                              (ID_LED_OFF1_OFF2 <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+#define PCIE_DEVICE_CONTROL2         0x28
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+#define PCIE_DEVICE_CONTROL2_16ms    0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1011_I_REV_4     0x04
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+#define BME1000_E_PHY_ID     0x01410CB0
+#define BME1000_E_PHY_ID_R2  0x01410CB1
+#define I82577_E_PHY_ID 0x01540050
+#define I82578_E_PHY_ID 0x004DD040
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
+#define I82578_EPSCR_DOWNSHIFT_ENABLE          0x0020
+#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK    0x001C
+
+/* BME1000 PHY Specific Control Register */
+#define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+        GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS         \
+        GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE          \
+        GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2       \
+        GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR         \
+        GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT         \
+        GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+        GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+        GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL       \
+        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+        GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2     \
+        GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+        GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+        GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET          \
+        GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID         \
+        GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID           \
+        GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+        GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL     \
+        GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+        GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL           \
+        GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL         \
+        GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC     \
+        GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS        \
+        GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY         \
+        GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE       \
+        GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC           \
+        GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+
+
+#endif /* _E1000E_DEFINES_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h
new file mode 100644
index 0000000..03ed35c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h
@@ -0,0 +1,719 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_HW_H_
+#define _E1000E_HW_H_
+
+#include "e1000e_regs.h"
+#include "e1000e_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82571EB_COPPER           0x105E
+#define E1000_DEV_ID_82571EB_FIBER            0x105F
+#define E1000_DEV_ID_82571EB_SERDES           0x1060
+#define E1000_DEV_ID_82571EB_SERDES_DUAL      0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD      0x10DA
+#define E1000_DEV_ID_82571EB_QUAD_COPPER      0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER      0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER       0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP   0x10BC
+#define E1000_DEV_ID_82572EI_COPPER           0x107D
+#define E1000_DEV_ID_82572EI_FIBER            0x107E
+#define E1000_DEV_ID_82572EI_SERDES           0x107F
+#define E1000_DEV_ID_82572EI                  0x10B9
+#define E1000_DEV_ID_82573E                   0x108B
+#define E1000_DEV_ID_82573E_IAMT              0x108C
+#define E1000_DEV_ID_82573L                   0x109A
+#define E1000_DEV_ID_82574L                   0x10D3
+#define E1000_DEV_ID_82574LA                  0x10F6
+#define E1000_DEV_ID_82583V                   0x150C
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT   0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT   0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT   0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT   0x10BB
+#define E1000_DEV_ID_ICH8_82567V_3            0x1501
+#define E1000_DEV_ID_ICH8_IGP_M_AMT           0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT             0x104A
+#define E1000_DEV_ID_ICH8_IGP_C               0x104B
+#define E1000_DEV_ID_ICH8_IFE                 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT              0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G               0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M               0x104D
+#define E1000_DEV_ID_ICH9_IGP_M               0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_AMT           0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M_V             0x10CB
+#define E1000_DEV_ID_ICH9_IGP_AMT             0x10BD
+#define E1000_DEV_ID_ICH9_BM                  0x10E5
+#define E1000_DEV_ID_ICH9_IGP_C               0x294C
+#define E1000_DEV_ID_ICH9_IFE                 0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT              0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G               0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM            0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF            0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V             0x10CE
+#define E1000_DEV_ID_ICH10_D_BM_LM            0x10DE
+#define E1000_DEV_ID_ICH10_D_BM_LF            0x10DF
+#define E1000_DEV_ID_PCH_M_HV_LM              0x10EA
+#define E1000_DEV_ID_PCH_M_HV_LC              0x10EB
+#define E1000_DEV_ID_PCH_D_HV_DM              0x10EF
+#define E1000_DEV_ID_PCH_D_HV_DC              0x10F0
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0     0
+#define E1000_FUNC_1     1
+
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82571,
+	e1000_82572,
+	e1000_82573,
+	e1000_82574,
+	e1000_82583,
+	e1000_80003es2lan,
+	e1000_ich8lan,
+	e1000_ich9lan,
+	e1000_ich10lan,
+	e1000_pchlan,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum e1000_media_type {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large,
+};
+
+enum e1000_phy_type {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+	e1000_phy_bm,
+	e1000_phy_82578,
+	e1000_phy_82577,
+};
+
+enum e1000_bus_type {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+};
+
+enum e1000_serdes_link_state {
+	e1000_serdes_link_down = 0,
+	e1000_serdes_link_autoneg_progress,
+	e1000_serdes_link_autoneg_complete,
+	e1000_serdes_link_forced_up
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	__le64 buffer_addr; /* Address of the descriptor's data buffer */
+	__le16 length;      /* Length of data DMAed into data buffer */
+	__le16 csum;        /* Packet checksum */
+	u8  status;         /* Descriptor status */
+	u8  errors;         /* Descriptor Errors */
+	__le16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		__le64 buffer_addr;
+		__le64 reserved;
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;         /* RSS Hash */
+				struct {
+					__le16 ip_id;  /* IP id */
+					__le16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length;
+			__le16 vlan;          /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		__le64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;           /* RSS Hash */
+				struct {
+					__le16 ip_id;    /* IP id */
+					__le16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length0;       /* length of buffer 0 */
+			__le16 vlan;          /* VLAN tag */
+		} middle;
+		struct {
+			__le16 header_status;
+			__le16 length[3];     /* length of buffers 1-3 */
+		} upper;
+		__le64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 cso;           /* Checksum offset */
+			u8 cmd;           /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 css;           /* Checksum start */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		__le32 ip_config;
+		struct {
+			u8 ipcss;         /* IP checksum start */
+			u8 ipcso;         /* IP checksum offset */
+			__le16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		__le32 tcp_config;
+		struct {
+			u8 tucss;         /* TCP checksum start */
+			u8 tucso;         /* TCP checksum offset */
+			__le16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	__le32 cmd_and_length;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 hdr_len;       /* Header length */
+			__le16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 popts;         /* Packet Options */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 tor;
+	u64 tot;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+	u64 doosync;
+};
+
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000e_mac.h"
+#include "e1000e_phy.h"
+#include "e1000e_nvm.h"
+#include "e1000e_manage.h"
+
+struct e1000_mac_operations {
+	/* Function pointers for the MAC. */
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*id_led_init)(struct e1000_hw *);
+	s32  (*blink_led)(struct e1000_hw *);
+	s32  (*check_for_link)(struct e1000_hw *);
+	bool (*check_mng_mode)(struct e1000_hw *hw);
+	s32  (*cleanup_led)(struct e1000_hw *);
+	void (*clear_hw_cntrs)(struct e1000_hw *);
+	void (*clear_vfta)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	void (*set_lan_id)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	s32  (*led_on)(struct e1000_hw *);
+	s32  (*led_off)(struct e1000_hw *);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+	s32  (*setup_led)(struct e1000_hw *);
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
+	void (*mta_set)(struct e1000_hw *, u32);
+	void (*config_collision_dist)(struct e1000_hw *);
+	void (*rar_set)(struct e1000_hw *, u8*, u32);
+	s32  (*read_mac_addr)(struct e1000_hw *);
+	s32  (*validate_mdi_setting)(struct e1000_hw *);
+	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
+	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
+                      struct e1000_host_mng_command_header*);
+	s32  (*mng_enable_host_if)(struct e1000_hw *);
+	s32  (*wait_autoneg)(struct e1000_hw *);
+};
+
+struct e1000_phy_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*cfg_on_link_up)(struct e1000_hw *);
+	s32  (*check_polarity)(struct e1000_hw *);
+	s32  (*check_reset_block)(struct e1000_hw *);
+	s32  (*commit)(struct e1000_hw *);
+#if 0
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+#endif
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+#if 0
+	s32  (*get_cable_length)(struct e1000_hw *);
+#endif
+	s32  (*get_info)(struct e1000_hw *);
+	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
+	s32  (*read_reg_locked)(struct e1000_hw *, u32, u16 *);
+	void (*release)(struct e1000_hw *);
+	s32  (*reset)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_reg)(struct e1000_hw *, u32, u16);
+	s32  (*write_reg_locked)(struct e1000_hw *, u32, u16);
+	void (*power_up)(struct e1000_hw *);
+	void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release)(struct e1000_hw *);
+	void (*reload)(struct e1000_hw *);
+	s32  (*update)(struct e1000_hw *);
+	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+	s32  (*validate)(struct e1000_hw *);
+	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 mc_filter_type;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+
+	/* Maximum size of the MTA register table in all supported adapters */
+	#define MAX_MTA_REG 128
+	u32 mta_shadow[MAX_MTA_REG];
+	u16 rar_entry_count;
+
+	u8  forced_speed_duplex;
+
+	bool adaptive_ifs;
+	bool arc_subsystem_valid;
+	bool asf_firmware_present;
+	bool autoneg;
+	bool autoneg_failed;
+	bool get_link_status;
+	bool in_ifs_mode;
+	enum e1000_serdes_link_state serdes_link_state;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+	enum e1000_phy_type type;
+
+	enum e1000_1000t_rx_status local_rx;
+	enum e1000_1000t_rx_status remote_rx;
+	enum e1000_ms_type ms_type;
+	enum e1000_ms_type original_ms_type;
+	enum e1000_rev_polarity cable_polarity;
+	enum e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	enum e1000_media_type media_type;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool reset_disable;
+	bool speed_downgraded;
+	bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+	enum e1000_nvm_type type;
+	enum e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_type type;
+	enum e1000_bus_speed speed;
+	enum e1000_bus_width width;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+	u32 high_water;          /* Flow control high-water mark */
+	u32 low_water;           /* Flow control low-water mark */
+	u16 pause_time;          /* Flow control pause timer */
+	bool send_xon;           /* Flow control send XON */
+	bool strict_ieee;        /* Strict IEEE mode */
+	enum e1000_fc_mode current_mode; /* FC mode in effect */
+	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+struct e1000_dev_spec_82571 {
+	bool laa_is_present;
+	u32 smb_counter;
+};
+
+struct e1000_dev_spec_80003es2lan {
+	bool  mdic_wa_enable;
+};
+
+struct e1000_shadow_ram {
+	u16  value;
+	bool modified;
+};
+
+#define E1000_ICH8_SHADOW_RAM_WORDS		2048
+
+struct e1000_dev_spec_ich8lan {
+	bool kmrn_lock_loss_workaround_enabled;
+	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
+	bool nvm_k1_enabled;
+};
+
+struct e1000_hw {
+	struct e1000_adapter *adapter;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+
+	void *back;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	union {
+		struct e1000_dev_spec_82571	_82571;
+		struct e1000_dev_spec_80003es2lan _80003es2lan;
+		struct e1000_dev_spec_ich8lan	ich8lan;
+	} dev_spec;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+#include "e1000e_82571.h"
+#include "e1000e_80003es2lan.h"
+#include "e1000e_ich8lan.h"
+
+/* These functions must be implemented by drivers */
+s32  e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c
new file mode 100644
index 0000000..7b9a49b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c
@@ -0,0 +1,3444 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * 82562G 10/100 Network Connection
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567V Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82567LF-3 Gigabit Network Connection
+ * 82567LM-3 Gigabit Network Connection
+ * 82567LM-4 Gigabit Network Connection
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
+ */
+
+#include "e1000e.h"
+
+static s32  e1000e_init_phy_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_init_phy_params_pchlan(struct e1000_hw *hw);
+static s32  e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_init_mac_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw);
+static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw);
+static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw);
+static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_check_reset_block_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_get_phy_info_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
+static s32  e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
+                                            bool active);
+static s32  e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
+                                            bool active);
+static s32  e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
+                                   u16 words, u16 *data);
+static s32  e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
+                                    u16 words, u16 *data);
+static s32  e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_valid_led_default_ich8lan(struct e1000_hw *hw,
+                                            u16 *data);
+static s32  e1000e_id_led_init_pchlan(struct e1000_hw *hw);
+static s32  e1000e_get_bus_info_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_reset_hw_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_init_hw_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_setup_link_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw,
+                                           u16 *speed, u16 *duplex);
+static s32  e1000e_cleanup_led_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_led_on_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_led_off_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+static s32  e1000e_setup_led_pchlan(struct e1000_hw *hw);
+static s32  e1000e_cleanup_led_pchlan(struct e1000_hw *hw);
+static s32  e1000e_led_on_pchlan(struct e1000_hw *hw);
+static s32  e1000e_led_off_pchlan(struct e1000_hw *hw);
+static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
+static s32  e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
+static s32  e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
+static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw,
+                                          u32 offset, u8 *data);
+static s32  e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 size, u16 *data);
+static s32  e1000e_read_flash_word_ich8lan(struct e1000_hw *hw,
+                                          u32 offset, u16 *data);
+static s32  e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                                 u32 offset, u8 byte);
+static s32  e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                           u32 offset, u8 data);
+static s32  e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                           u8 size, u16 data);
+static s32  e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw);
+static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw);
+static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw);
+static s32  e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw);
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+	struct ich8_hsfsts {
+		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
+		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
+		u16 dael       :1; /* bit 2 Direct Access error Log */
+		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
+		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
+		u16 reserved1  :2; /* bit 13:6 Reserved */
+		u16 reserved2  :6; /* bit 13:6 Reserved */
+		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
+	} hsf_status;
+	u16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+	struct ich8_hsflctl {
+		u16 flcgo      :1;   /* 0 Flash Cycle Go */
+		u16 flcycle    :2;   /* 2:1 Flash Cycle */
+		u16 reserved   :5;   /* 7:3 Reserved  */
+		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
+		u16 flockdn    :6;   /* 15:10 Reserved */
+	} hsf_ctrl;
+	u16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+	struct ich8_flracc {
+		u32 grra      :8; /* 0:7 GbE region Read Access */
+		u32 grwa      :8; /* 8:15 GbE region Write Access */
+		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
+		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
+	} hsf_flregacc;
+	u16 regval;
+};
+
+/**
+ *  e1000e_init_phy_params_pchlan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	phy->addr                     = 1;
+	phy->reset_delay_us           = 100;
+
+	phy->ops.acquire              = e1000e_acquire_swflag_ich8lan;
+	phy->ops.check_polarity       = e1000e_check_polarity_ife;
+	phy->ops.check_reset_block    = e1000e_check_reset_block_ich8lan;
+#if 0
+	phy->ops.force_speed_duplex   = e1000e_phy_force_speed_duplex_ife;
+#endif
+#if 0
+	phy->ops.get_cable_length     = e1000e_get_cable_length_igp_2;
+#endif
+	phy->ops.get_cfg_done         = e1000e_get_cfg_done_ich8lan;
+	phy->ops.get_info             = e1000e_get_phy_info_ich8lan;
+	phy->ops.read_reg             = e1000e_read_phy_reg_hv;
+	phy->ops.read_reg_locked      = e1000e_read_phy_reg_hv_locked;
+	phy->ops.release              = e1000e_release_swflag_ich8lan;
+	phy->ops.reset                = e1000e_phy_hw_reset_ich8lan;
+	phy->ops.set_d0_lplu_state    = e1000e_set_lplu_state_pchlan;
+	phy->ops.set_d3_lplu_state    = e1000e_set_lplu_state_pchlan;
+	phy->ops.write_reg            = e1000e_write_phy_reg_hv;
+	phy->ops.write_reg_locked     = e1000e_write_phy_reg_hv_locked;
+	phy->ops.power_up             = e1000e_power_up_phy_copper;
+	phy->ops.power_down           = e1000e_power_down_phy_copper_ich8lan;
+	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+	phy->id = e1000_phy_unknown;
+	e1000e_get_phy_id(hw);
+	phy->type = e1000e_get_phy_type_from_id(phy->id);
+
+	if (phy->type == e1000_phy_82577) {
+		phy->ops.check_polarity = e1000e_check_polarity_82577;
+#if 0
+		phy->ops.force_speed_duplex =
+			e1000e_phy_force_speed_duplex_82577;
+#endif
+#if 0
+		phy->ops.get_cable_length   = e1000e_get_cable_length_82577;
+#endif
+		phy->ops.get_info = e1000e_get_phy_info_82577;
+		phy->ops.commit = e1000e_phy_sw_reset;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_phy_params_ich8lan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000e_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i = 0;
+
+	phy->addr                     = 1;
+	phy->reset_delay_us           = 100;
+
+	phy->ops.acquire              = e1000e_acquire_swflag_ich8lan;
+	phy->ops.check_polarity       = e1000e_check_polarity_ife;
+	phy->ops.check_reset_block    = e1000e_check_reset_block_ich8lan;
+#if 0
+	phy->ops.force_speed_duplex   = e1000e_phy_force_speed_duplex_ife;
+#endif
+#if 0
+	phy->ops.get_cable_length     = e1000e_get_cable_length_igp_2;
+#endif
+	phy->ops.get_cfg_done         = e1000e_get_cfg_done_ich8lan;
+	phy->ops.get_info             = e1000e_get_phy_info_ich8lan;
+	phy->ops.read_reg             = e1000e_read_phy_reg_igp;
+	phy->ops.release              = e1000e_release_swflag_ich8lan;
+	phy->ops.reset                = e1000e_phy_hw_reset_ich8lan;
+	phy->ops.set_d0_lplu_state    = e1000e_set_d0_lplu_state_ich8lan;
+	phy->ops.set_d3_lplu_state    = e1000e_set_d3_lplu_state_ich8lan;
+	phy->ops.write_reg            = e1000e_write_phy_reg_igp;
+	phy->ops.power_up             = e1000e_power_up_phy_copper;
+	phy->ops.power_down           = e1000e_power_down_phy_copper_ich8lan;
+
+	/*
+	 * We may need to do this twice - once for IGP and if that fails,
+	 * we'll set BM func pointers and try again
+	 */
+	ret_val = e1000e_determine_phy_address(hw);
+	if (ret_val) {
+		phy->ops.write_reg = e1000e_write_phy_reg_bm;
+		phy->ops.read_reg  = e1000e_read_phy_reg_bm;
+		ret_val = e1000e_determine_phy_address(hw);
+		if (ret_val) {
+			DBG("Cannot determine PHY addr. Erroring out\n");
+			goto out;
+		}
+	}
+
+	phy->id = 0;
+	while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
+	       (i++ < 100)) {
+		msleep(1);
+		ret_val = e1000e_get_phy_id(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Verify phy id */
+	switch (phy->id) {
+	case IGP03E1000_E_PHY_ID:
+		phy->type = e1000_phy_igp_3;
+		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked;
+		phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy->type = e1000_phy_ife;
+		phy->autoneg_mask = E1000_ALL_NOT_GIG;
+		break;
+	case BME1000_E_PHY_ID:
+		phy->type = e1000_phy_bm;
+		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		phy->ops.read_reg = e1000e_read_phy_reg_bm;
+		phy->ops.write_reg = e1000e_write_phy_reg_bm;
+		phy->ops.commit = e1000e_phy_sw_reset;
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_nvm_params_ich8lan - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific NVM parameters and function
+ *  pointers.
+ **/
+static s32 e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 gfpreg, sector_base_addr, sector_end_addr;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	/* Can't read flash registers if the register set isn't mapped. */
+	if (!hw->flash_address) {
+		e_dbg("ERROR: Flash registers not mapped\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	nvm->type = e1000_nvm_flash_sw;
+
+	gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+	/*
+	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
+	 * Add 1 to sector_end_addr since this sector is included in
+	 * the overall size.
+	 */
+	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+	/* flash_base_addr is byte-aligned */
+	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+	/*
+	 * find total size of the NVM, then cut in half since the total
+	 * size represents two separate NVM banks.
+	 */
+	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+	                          << FLASH_SECTOR_ADDR_SHIFT;
+	nvm->flash_bank_size /= 2;
+	/* Adjust to word count */
+	nvm->flash_bank_size /= sizeof(u16);
+
+	nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
+
+	/* Clear shadow ram */
+	for (i = 0; i < nvm->word_size; i++) {
+		dev_spec->shadow_ram[i].modified = false;
+		dev_spec->shadow_ram[i].value    = 0xFFFF;
+	}
+
+	/* Function Pointers */
+	nvm->ops.acquire       = e1000e_acquire_nvm_ich8lan;
+	nvm->ops.release       = e1000e_release_nvm_ich8lan;
+	nvm->ops.read          = e1000e_read_nvm_ich8lan;
+	nvm->ops.update        = e1000e_update_nvm_checksum_ich8lan;
+	nvm->ops.valid_led_default = e1000e_valid_led_default_ich8lan;
+	nvm->ops.validate      = e1000e_validate_nvm_checksum_ich8lan;
+	nvm->ops.write         = e1000e_write_nvm_ich8lan;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_mac_params_ich8lan - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific MAC parameters and function
+ *  pointers.
+ **/
+static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	/* Set media type function pointer */
+	hw->phy.media_type = e1000_media_type_copper;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 32;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+	if (mac->type == e1000_ich8lan)
+		mac->rar_entry_count--;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid = true;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000e_get_bus_info_ich8lan;
+	/* function id */
+	mac->ops.set_lan_id = e1000e_set_lan_id_single_port;
+	/* reset */
+	mac->ops.reset_hw = e1000e_reset_hw_ich8lan;
+	/* hw initialization */
+	mac->ops.init_hw = e1000e_init_hw_ich8lan;
+	/* link setup */
+	mac->ops.setup_link = e1000e_setup_link_ich8lan;
+	/* physical interface setup */
+	mac->ops.setup_physical_interface = e1000e_setup_copper_link_ich8lan;
+	/* check for link */
+	mac->ops.check_for_link = e1000e_check_for_copper_link_ich8lan;
+	/* check management mode */
+	mac->ops.check_mng_mode = e1000e_check_mng_mode_ich8lan;
+	/* link info */
+	mac->ops.get_link_up_info = e1000e_get_link_up_info_ich8lan;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000e_mta_set_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_ich8lan;
+
+	/* LED operations */
+	switch (mac->type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+		/* ID LED init */
+		mac->ops.id_led_init = e1000e_id_led_init;
+		/* blink LED */
+		mac->ops.blink_led = e1000e_blink_led;
+		/* setup LED */
+		mac->ops.setup_led = e1000e_setup_led_generic;
+		/* cleanup LED */
+		mac->ops.cleanup_led = e1000e_cleanup_led_ich8lan;
+		/* turn on/off LED */
+		mac->ops.led_on = e1000e_led_on_ich8lan;
+		mac->ops.led_off = e1000e_led_off_ich8lan;
+		break;
+	case e1000_pchlan:
+		/* ID LED init */
+		mac->ops.id_led_init = e1000e_id_led_init_pchlan;
+		/* setup LED */
+		mac->ops.setup_led = e1000e_setup_led_pchlan;
+		/* cleanup LED */
+		mac->ops.cleanup_led = e1000e_cleanup_led_pchlan;
+		/* turn on/off LED */
+		mac->ops.led_on = e1000e_led_on_pchlan;
+		mac->ops.led_off = e1000e_led_off_pchlan;
+		break;
+	default:
+		break;
+	}
+
+	/* Enable PCS Lock-loss workaround for ICH8 */
+	if (mac->type == e1000_ich8lan)
+		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
+
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_check_for_copper_link_ich8lan - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+static s32 e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000e_k1_gig_workaround_hv(hw, link);
+		if (ret_val)
+			goto out;
+	}
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	if (hw->phy.type == e1000_phy_82578) {
+		ret_val = e1000e_link_stall_workaround_hv(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000e_check_downshift(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000e_config_collision_dist(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000e_config_fc_after_link_up(hw);
+	if (ret_val)
+		e_dbg("Error configuring flow control\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_function_pointers_ich8lan - Initialize ICH8 function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific function pointers for PHY, MAC, and NVM.
+ **/
+void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw)
+{
+	e1000e_init_mac_ops_generic(hw);
+	e1000e_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000e_init_mac_params_ich8lan;
+	hw->nvm.ops.init_params = e1000e_init_nvm_params_ich8lan;
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+		hw->phy.ops.init_params = e1000e_init_phy_params_ich8lan;
+		break;
+	case e1000_pchlan:
+		hw->phy.ops.init_params = e1000e_init_phy_params_pchlan;
+		break;
+	default:
+		break;
+	}
+}
+
+#if 0
+static DEFINE_MUTEX(nvm_mutex);
+#endif
+
+/**
+ *  e1000e_acquire_nvm_ich8lan - Acquire NVM mutex
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquires the mutex for performing NVM operations.
+ **/
+static s32 e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw __unused)
+{
+#if 0
+	mutex_lock(&nvm_mutex);
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_release_nvm_ich8lan - Release NVM mutex
+ *  @hw: pointer to the HW structure
+ *
+ *  Releases the mutex used while performing NVM operations.
+ **/
+static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw __unused)
+{
+#if 0
+	mutex_unlock(&nvm_mutex);
+#endif
+	return;
+}
+
+#if 0
+static DEFINE_MUTEX(swflag_mutex);
+#endif
+
+/**
+ *  e1000e_acquire_swflag_ich8lan - Acquire software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquires the software control flag for performing PHY and select
+ *  MAC CSR accesses.
+ **/
+static s32 e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+#if 0
+	mutex_lock(&swflag_mutex);
+#endif
+
+	while (timeout) {
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
+			break;
+
+		mdelay(1);
+		timeout--;
+	}
+
+	if (!timeout) {
+		e_dbg("SW/FW/HW has locked the resource for too long.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	timeout = SW_FLAG_TIMEOUT;
+
+	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+	ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+	while (timeout) {
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+			break;
+
+		mdelay(1);
+		timeout--;
+	}
+
+	if (!timeout) {
+		e_dbg("Failed to acquire the semaphore.\n");
+		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+		ew32(EXTCNF_CTRL, extcnf_ctrl);
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+#if 0
+	if (ret_val)
+		mutex_unlock(&swflag_mutex);
+#endif
+	return ret_val;
+}
+
+/**
+ *  e1000e_release_swflag_ich8lan - Release software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Releases the software control flag for performing PHY and select
+ *  MAC CSR accesses.
+ **/
+static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl;
+
+	extcnf_ctrl = er32(EXTCNF_CTRL);
+	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+	ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+#if 0
+	mutex_unlock(&swflag_mutex);
+#endif
+	return;
+}
+
+/**
+ *  e1000e_check_mng_mode_ich8lan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = er32(FWSM);
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+/**
+ *  e1000e_check_reset_block_ich8lan - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks if firmware is blocking the reset of the PHY.
+ *  This is a function pointer entry point only called by
+ *  reset routines.
+ **/
+static s32 e1000e_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = er32(FWSM);
+	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
+	                                        : E1000_BLK_PHY_RESET;
+}
+
+/**
+ *  e1000e_sw_lcd_config_ich8lan - SW-based LCD Configuration
+ *  @hw:   pointer to the HW structure
+ *
+ *  SW should configure the LCD from the NVM extended configuration region
+ *  as a workaround for certain parts.
+ **/
+static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+	s32 ret_val;
+	u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	/*
+	 * Initialize the PHY from the NVM on ICH platforms.  This
+	 * is needed due to an issue where the NVM configuration is
+	 * not properly autoloaded after power transitions.
+	 * Therefore, after each PHY reset, we will load the
+	 * configuration data out of the NVM manually.
+	 */
+	if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) ||
+		(hw->mac.type == e1000_pchlan)) {
+		/* Check if SW needs to configure the PHY */
+		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
+		    (hw->mac.type == e1000_pchlan))
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+		else
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+		data = er32(FEXTNVM);
+		if (!(data & sw_cfg_mask))
+			goto out;
+
+		/* Wait for basic configuration completes before proceeding */
+		e1000e_lan_init_done_ich8lan(hw);
+
+		/*
+		 * Make sure HW does not configure LCD from PHY
+		 * extended configuration before SW configuration
+		 */
+		data = er32(EXTCNF_CTRL);
+		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+			goto out;
+
+		cnf_size = er32(EXTCNF_SIZE);
+		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+		if (!cnf_size)
+			goto out;
+
+		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+		if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+		    (hw->mac.type == e1000_pchlan)) {
+			/*
+			 * HW configures the SMBus address and LEDs when the
+			 * OEM and LCD Write Enable bits are set in the NVM.
+			 * When both NVM bits are cleared, SW will configure
+			 * them instead.
+			 */
+			data = er32(STRAP);
+			data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+			reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
+			reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+			ret_val = e1000e_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
+			                                        reg_data);
+			if (ret_val)
+				goto out;
+
+			data = er32(LEDCTL);
+			ret_val = e1000e_write_phy_reg_hv_locked(hw,
+			                                        HV_LED_CONFIG,
+			                                        (u16)data);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Configure LCD from extended configuration region. */
+
+		/* cnf_base_addr is in DWORD */
+		word_addr = (u16)(cnf_base_addr << 1);
+
+		for (i = 0; i < cnf_size; i++) {
+			ret_val = e1000e_read_nvm(hw, (word_addr + i * 2), 1,
+			                           &reg_data);
+			if (ret_val)
+				goto out;
+
+			ret_val = e1000e_read_nvm(hw, (word_addr + i * 2 + 1),
+			                           1, &reg_addr);
+			if (ret_val)
+				goto out;
+
+			/* Save off the PHY page for future writes. */
+			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+				phy_page = reg_data;
+				continue;
+			}
+
+			reg_addr &= PHY_REG_MASK;
+			reg_addr |= phy_page;
+
+			ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
+			                                    reg_data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ *  e1000e_k1_gig_workaround_hv - K1 Si workaround
+ *  @hw:   pointer to the HW structure
+ *  @link: link up bool flag
+ *
+ *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
+ *  If link is down, the function will restore the default K1 setting located
+ *  in the NVM.
+ **/
+static s32 e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 status_reg = 0;
+	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
+
+	if (hw->mac.type != e1000_pchlan)
+		goto out;
+
+	/* Wrap the whole flow with the sw flag */
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
+	if (link) {
+		if (hw->phy.type == e1000_phy_82578) {
+			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
+			                                      &status_reg);
+			if (ret_val)
+				goto release;
+
+			status_reg &= BM_CS_STATUS_LINK_UP |
+			              BM_CS_STATUS_RESOLVED |
+			              BM_CS_STATUS_SPEED_MASK;
+
+			if (status_reg == (BM_CS_STATUS_LINK_UP |
+			                   BM_CS_STATUS_RESOLVED |
+			                   BM_CS_STATUS_SPEED_1000))
+				k1_enable = false;
+		}
+
+		if (hw->phy.type == e1000_phy_82577) {
+			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
+			                                      &status_reg);
+			if (ret_val)
+				goto release;
+
+			status_reg &= HV_M_STATUS_LINK_UP |
+			              HV_M_STATUS_AUTONEG_COMPLETE |
+			              HV_M_STATUS_SPEED_MASK;
+
+			if (status_reg == (HV_M_STATUS_LINK_UP |
+			                   HV_M_STATUS_AUTONEG_COMPLETE |
+			                   HV_M_STATUS_SPEED_1000))
+				k1_enable = false;
+		}
+
+		/* Link stall fix for link up */
+		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+		                                       0x0100);
+		if (ret_val)
+			goto release;
+
+	} else {
+		/* Link stall fix for link down */
+		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+		                                       0x4100);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = e1000e_configure_k1_ich8lan(hw, k1_enable);
+
+release:
+	hw->phy.ops.release(hw);
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_configure_k1_ich8lan - Configure K1 power state
+ *  @hw: pointer to the HW structure
+ *  @enable: K1 state to configure
+ *
+ *  Configure the K1 power state based on the provided parameter.
+ *  Assumes semaphore already acquired.
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ **/
+s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl_reg = 0;
+	u32 ctrl_ext = 0;
+	u32 reg = 0;
+	u16 kmrn_reg = 0;
+
+	ret_val = e1000e_read_kmrn_reg_locked(hw,
+	                                     E1000_KMRNCTRLSTA_K1_CONFIG,
+	                                     &kmrn_reg);
+	if (ret_val)
+		goto out;
+
+	if (k1_enable)
+		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+	else
+		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
+
+	ret_val = e1000e_write_kmrn_reg_locked(hw,
+	                                      E1000_KMRNCTRLSTA_K1_CONFIG,
+	                                      kmrn_reg);
+	if (ret_val)
+		goto out;
+
+	udelay(20);
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_reg = er32(CTRL);
+
+	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+	reg |= E1000_CTRL_FRCSPD;
+	ew32(CTRL, reg);
+
+	E1000_WRITE_REG(hw,
+	                E1000_CTRL_EXT,
+	                ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+	udelay(20);
+	ew32(CTRL, ctrl_reg);
+	ew32(CTRL_EXT, ctrl_ext);
+	udelay(20);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_oem_bits_config_ich8lan - SW-based LCD Configuration
+ *  @hw:       pointer to the HW structure
+ *  @d0_state: boolean if entering d0 or d3 device state
+ *
+ *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
+ *  in NVM determines whether HW should configure LPLU and Gbe Disable.
+ **/
+s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
+{
+	s32 ret_val = 0;
+	u32 mac_reg;
+	u16 oem_reg;
+
+	if (hw->mac.type != e1000_pchlan)
+		return ret_val;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	mac_reg = er32(EXTCNF_CTRL);
+	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+		goto out;
+
+	mac_reg = er32(FEXTNVM);
+	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
+		goto out;
+
+	mac_reg = er32(PHY_CTRL);
+
+	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
+	if (ret_val)
+		goto out;
+
+	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+	if (d0_state) {
+		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+			oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+			oem_reg |= HV_OEM_BITS_LPLU;
+	} else {
+		if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+			oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+		if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+			oem_reg |= HV_OEM_BITS_LPLU;
+	}
+	/* Restart auto-neg to activate the bits */
+	if (!e1000e_check_reset_block(hw))
+		oem_reg |= HV_OEM_BITS_RESTART_AN;
+	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
+
+out:
+	hw->phy.ops.release(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ *  done after every PHY reset.
+ **/
+static s32 e1000e_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.type != e1000_pchlan)
+		goto out;
+
+	if (((hw->phy.type == e1000_phy_82577) &&
+	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+		/* Disable generation of early preamble */
+		ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431);
+		if (ret_val)
+			goto out;
+
+		/* Preamble tuning for SSC */
+		ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
+		if (ret_val)
+			goto out;
+	}
+
+	if (hw->phy.type == e1000_phy_82578) {
+		/*
+		 * Return registers to default by doing a soft reset then
+		 * writing 0x3140 to the control register.
+		 */
+		if (hw->phy.revision < 2) {
+			e1000e_phy_sw_reset(hw);
+			ret_val = e1e_wphy(hw, PHY_CONTROL,
+			                                0x3140);
+		}
+	}
+
+	/* Select page 0 */
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = 1;
+	ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+	if (ret_val)
+		goto out;
+	hw->phy.ops.release(hw);
+
+	/*
+	 * Configure the K1 Si workaround during phy reset assuming there is
+	 * link so that it disables K1 if link is in 1Gbps.
+	 */
+	ret_val = e1000e_k1_gig_workaround_hv(hw, true);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_lan_init_done_ich8lan - Check for PHY config completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check the appropriate indication the MAC has finished configuring the
+ *  PHY after a software reset.
+ **/
+static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw)
+{
+	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+
+	/* Wait for basic configuration completes before proceeding */
+	do {
+		data = er32(STATUS);
+		data &= E1000_STATUS_LAN_INIT_DONE;
+		udelay(100);
+	} while ((!data) && --loop);
+
+	/*
+	 * If basic configuration is incomplete before the above loop
+	 * count reaches 0, loading the configuration from NVM will
+	 * leave the PHY in a bad state possibly resulting in no link.
+	 */
+	if (loop == 0)
+		e_dbg("LAN_INIT_DONE not set, increase timeout\n");
+
+	/* Clear the Init Done bit for the next init event */
+	data = er32(STATUS);
+	data &= ~E1000_STATUS_LAN_INIT_DONE;
+	ew32(STATUS, data);
+}
+
+/**
+ *  e1000e_phy_hw_reset_ich8lan - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg;
+
+	ret_val = e1000e_phy_hw_reset_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/* Allow time for h/w to get to a quiescent state after reset */
+	msleep(10);
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000e_hv_phy_workarounds_ich8lan(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Dummy read to clear the phy wakeup bit after lcd reset */
+	if (hw->mac.type == e1000_pchlan)
+		e1e_rphy(hw, BM_WUC, &reg);
+
+	/* Configure the LCD with the extended configuration region in NVM */
+	ret_val = e1000e_sw_lcd_config_ich8lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Configure the LCD with the OEM bits in NVM */
+	if (hw->mac.type == e1000_pchlan)
+		ret_val = e1000e_oem_bits_config_ich8lan(hw, true);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ *  @hw: pointer to the HW structure
+ *
+ *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
+ **/
+static s32 e1000e_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+
+	switch (hw->phy.type) {
+	case e1000_phy_ife:
+		ret_val = e1000e_get_phy_info_ife_ich8lan(hw);
+		break;
+	case e1000_phy_igp_3:
+	case e1000_phy_bm:
+	case e1000_phy_82578:
+	case e1000_phy_82577:
+		ret_val = e1000e_get_phy_info_igp(hw);
+		break;
+	default:
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ *  @hw: pointer to the HW structure
+ *
+ *  Populates "phy" structure with various feature states.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		e_dbg("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+	if (ret_val)
+		goto out;
+	phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
+	                           ? false : true;
+
+	if (phy->polarity_correction) {
+		ret_val = e1000e_check_polarity_ife(hw);
+		if (ret_val)
+			goto out;
+	} else {
+		/* Polarity is forced */
+		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false;
+
+	/* The following parameters are undefined for 10/100 operation. */
+	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+	phy->local_rx = e1000_1000t_rx_status_undefined;
+	phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_lplu_state_pchlan - Set Low Power Link Up state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
+ *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ *  the phy speed. This function will manually set the LPLU bit and restart
+ *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ *  since it configures the same bit.
+ **/
+static s32 e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 oem_reg;
+
+	ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
+	if (ret_val)
+		goto out;
+
+	if (active)
+		oem_reg |= HV_OEM_BITS_LPLU;
+	else
+		oem_reg &= ~HV_OEM_BITS_LPLU;
+
+	oem_reg |= HV_OEM_BITS_RESTART_AN;
+	ret_val = e1e_wphy(hw, HV_OEM_BITS, oem_reg);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	if (phy->type == e1000_phy_ife)
+		goto out;
+
+	phy_ctrl = er32(PHY_CTRL);
+
+	if (active) {
+		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
+		/*
+		 * Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers
+		 */
+		if (hw->mac.type == e1000_ich8lan)
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw,
+		                            IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+		if (ret_val)
+			goto out;
+	} else {
+		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D3 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	phy_ctrl = er32(PHY_CTRL);
+
+	if (!active) {
+		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
+		/*
+		 * Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers
+		 */
+		if (hw->mac.type == e1000_ich8lan)
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw,
+		                            IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ *  @hw: pointer to the HW structure
+ *  @bank:  pointer to the variable that returns the active bank
+ *
+ *  Reads signature byte from the NVM using the flash access registers.
+ *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
+ **/
+static s32 e1000e_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
+{
+	u32 eecd;
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
+	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+	u8 sig_byte = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+		eecd = er32(EECD);
+		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+		    E1000_EECD_SEC1VAL_VALID_MASK) {
+			if (eecd & E1000_EECD_SEC1VAL)
+				*bank = 1;
+			else
+				*bank = 0;
+
+			goto out;
+		}
+		e_dbg("Unable to determine valid NVM bank via EEC - "
+		         "reading flash signature\n");
+		/* fall-thru */
+	default:
+		/* set bank to 0 in case flash read fails */
+		*bank = 0;
+
+		/* Check bank 0 */
+		ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset,
+		                                        &sig_byte);
+		if (ret_val)
+			goto out;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 0;
+			goto out;
+		}
+
+		/* Check bank 1 */
+		ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset +
+		                                        bank1_offset,
+		                                        &sig_byte);
+		if (ret_val)
+			goto out;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 1;
+			goto out;
+		}
+
+		e_dbg("ERROR: No valid NVM bank present\n");
+		ret_val = -E1000_ERR_NVM;
+		break;
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_nvm_ich8lan - Read word(s) from the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to read.
+ *  @words: Size of data to read in words
+ *  @data: Pointer to the word(s) to read at offset.
+ *
+ *  Reads a word(s) from the NVM using the flash access registers.
+ **/
+static s32 e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+                                  u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 act_offset;
+	s32 ret_val = E1000_SUCCESS;
+	u32 bank = 0;
+	u16 i, word;
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		e_dbg("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	nvm->ops.acquire(hw);
+
+	ret_val = e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val != E1000_SUCCESS) {
+		e_dbg("Could not detect valid bank, assuming bank 0\n");
+		bank = 0;
+	}
+
+	act_offset = (bank) ? nvm->flash_bank_size : 0;
+	act_offset += offset;
+
+	ret_val = E1000_SUCCESS;
+	for (i = 0; i < words; i++) {
+		if ((dev_spec->shadow_ram) &&
+		    (dev_spec->shadow_ram[offset+i].modified)) {
+			data[i] = dev_spec->shadow_ram[offset+i].value;
+		} else {
+			ret_val = e1000e_read_flash_word_ich8lan(hw,
+			                                        act_offset + i,
+			                                        &word);
+			if (ret_val)
+				break;
+			data[i] = word;
+		}
+	}
+
+	nvm->ops.release(hw);
+
+out:
+	if (ret_val)
+		e_dbg("NVM read error: %d\n", ret_val);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_flash_cycle_init_ich8lan - Initialize flash
+ *  @hw: pointer to the HW structure
+ *
+ *  This function does initial flash setup so that a new read/write/erase cycle
+ *  can be started.
+ **/
+static s32 e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	s32 i = 0;
+
+	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+	/* Check if the flash descriptor is valid */
+	if (hsfsts.hsf_status.fldesvalid == 0) {
+		e_dbg("Flash descriptor invalid.  "
+		         "SW Sequencing must be used.");
+		goto out;
+	}
+
+	/* Clear FCERR and DAEL in hw status by writing 1 */
+	hsfsts.hsf_status.flcerr = 1;
+	hsfsts.hsf_status.dael = 1;
+
+	ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+	/*
+	 * Either we should have a hardware SPI cycle in progress
+	 * bit to check against, in order to start a new cycle or
+	 * FDONE bit should be changed in the hardware so that it
+	 * is 1 after hardware reset, which can then be used as an
+	 * indication whether a cycle is in progress or has been
+	 * completed.
+	 */
+
+	if (hsfsts.hsf_status.flcinprog == 0) {
+		/*
+		 * There is no cycle running at present,
+		 * so we can start a cycle.
+		 * Begin by setting Flash Cycle Done.
+		 */
+		hsfsts.hsf_status.flcdone = 1;
+		ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+		ret_val = E1000_SUCCESS;
+	} else {
+		/*
+		 * Otherwise poll for sometime so the current
+		 * cycle has a chance to end before giving up.
+		 */
+		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+			hsfsts.regval = er16flash(
+			                                      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcinprog == 0) {
+				ret_val = E1000_SUCCESS;
+				break;
+			}
+			udelay(1);
+		}
+		if (ret_val == E1000_SUCCESS) {
+			/*
+			 * Successful in waiting for previous cycle to timeout,
+			 * now set the Flash Cycle Done.
+			 */
+			hsfsts.hsf_status.flcdone = 1;
+			ew16flash(ICH_FLASH_HSFSTS,
+			                        hsfsts.regval);
+		} else {
+			e_dbg("Flash controller busy, cannot get access");
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ *  @hw: pointer to the HW structure
+ *  @timeout: maximum time to wait for completion
+ *
+ *  This function starts a flash cycle and waits for its completion.
+ **/
+static s32 e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
+{
+	union ich8_hws_flash_ctrl hsflctl;
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	u32 i = 0;
+
+	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+	hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+	hsflctl.hsf_ctrl.flcgo = 1;
+	ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+	/* wait till FDONE bit is set to 1 */
+	do {
+		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+		if (hsfsts.hsf_status.flcdone == 1)
+			break;
+		udelay(1);
+	} while (i++ < timeout);
+
+	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+		ret_val = E1000_SUCCESS;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_flash_word_ich8lan - Read word from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: offset to data location
+ *  @data: pointer to the location for storing the data
+ *
+ *  Reads the flash word at offset into data.  Offset is converted
+ *  to bytes before read.
+ **/
+static s32 e1000e_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u16 *data)
+{
+	s32 ret_val;
+
+	if (!data) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Must convert offset into bytes. */
+	offset <<= 1;
+
+	ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 2, data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_flash_byte_ich8lan - Read byte from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to read.
+ *  @data: Pointer to a byte to store the value read.
+ *
+ *  Reads a single byte from the NVM using the flash access registers.
+ **/
+static s32 e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u8 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 word = 0;
+
+	ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 1, &word);
+	if (ret_val)
+		goto out;
+
+	*data = (u8)word;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_flash_data_ich8lan - Read byte or word from NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte or word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: Pointer to the word to store the value read.
+ *
+ *  Reads a byte or word from the NVM using the flash access registers.
+ **/
+static s32 e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u8 size, u16 *data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+	u8 count = 0;
+
+	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		goto out;
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+	                    hw->nvm.flash_base_addr;
+
+	do {
+		udelay(1);
+		/* Steps */
+		ret_val = e1000e_flash_cycle_init_ich8lan(hw);
+		if (ret_val != E1000_SUCCESS)
+			break;
+
+		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size - 1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+		ret_val = e1000e_flash_cycle_ich8lan(hw,
+		                                ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+		/*
+		 * Check if FCERR is set to 1, if set to 1, clear it
+		 * and try the whole sequence a few more times, else
+		 * read in (shift in) the Flash Data0, the order is
+		 * least significant byte first msb to lsb
+		 */
+		if (ret_val == E1000_SUCCESS) {
+			flash_data = er32flash(ICH_FLASH_FDATA0);
+			if (size == 1)
+				*data = (u8)(flash_data & 0x000000FF);
+			else if (size == 2)
+				*data = (u16)(flash_data & 0x0000FFFF);
+			break;
+		} else {
+			/*
+			 * If we've gotten here, then things are probably
+			 * completely hosed, but if the error condition is
+			 * detected, it won't hurt to give it another try...
+			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+			 */
+			hsfsts.regval = er16flash(
+			                                      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1) {
+				/* Repeat for some time before giving up. */
+				continue;
+			} else if (hsfsts.hsf_status.flcdone == 0) {
+				e_dbg("Timeout error - flash cycle "
+				         "did not complete.");
+				break;
+			}
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_nvm_ich8lan - Write word(s) to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to write.
+ *  @words: Size of data to write in words
+ *  @data: Pointer to the word(s) to write at offset.
+ *
+ *  Writes a byte or word to the NVM using the flash access registers.
+ **/
+static s32 e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+                                   u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		e_dbg("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	nvm->ops.acquire(hw);
+
+	for (i = 0; i < words; i++) {
+		dev_spec->shadow_ram[offset+i].modified = true;
+		dev_spec->shadow_ram[offset+i].value = data[i];
+	}
+
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  The NVM checksum is updated by calling the generic update_nvm_checksum,
+ *  which writes the checksum to the shadow ram.  The changes in the shadow
+ *  ram are then committed to the EEPROM by processing each bank at a time
+ *  checking for the modified bit and writing only the pending changes.
+ *  After a successful commit, the shadow ram is cleared and is ready for
+ *  future writes.
+ **/
+static s32 e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1000e_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		goto out;
+
+	if (nvm->type != e1000_nvm_flash_sw)
+		goto out;
+
+	nvm->ops.acquire(hw);
+
+	/*
+	 * We're writing to the opposite bank so if we're on bank 1,
+	 * write to bank 0 etc.  We also need to erase the segment that
+	 * is going to be written
+	 */
+	ret_val =  e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val != E1000_SUCCESS) {
+		e_dbg("Could not detect valid bank, assuming bank 0\n");
+		bank = 0;
+	}
+
+	if (bank == 0) {
+		new_bank_offset = nvm->flash_bank_size;
+		old_bank_offset = 0;
+		ret_val = e1000e_erase_flash_bank_ich8lan(hw, 1);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			goto out;
+		}
+	} else {
+		old_bank_offset = nvm->flash_bank_size;
+		new_bank_offset = 0;
+		ret_val = e1000e_erase_flash_bank_ich8lan(hw, 0);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			goto out;
+		}
+	}
+
+	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+		/*
+		 * Determine whether to write the value stored
+		 * in the other NVM bank or a modified value stored
+		 * in the shadow RAM
+		 */
+		if (dev_spec->shadow_ram[i].modified) {
+			data = dev_spec->shadow_ram[i].value;
+		} else {
+			ret_val = e1000e_read_flash_word_ich8lan(hw, i +
+			                                        old_bank_offset,
+			                                        &data);
+			if (ret_val)
+				break;
+		}
+
+		/*
+		 * If the word is 0x13, then make sure the signature bits
+		 * (15:14) are 11b until the commit has completed.
+		 * This will allow us to write 10b which indicates the
+		 * signature is valid.  We want to do this after the write
+		 * has completed so that we don't mark the segment valid
+		 * while the write is still in progress
+		 */
+		if (i == E1000_ICH_NVM_SIG_WORD)
+			data |= E1000_ICH_NVM_SIG_MASK;
+
+		/* Convert offset to bytes. */
+		act_offset = (i + new_bank_offset) << 1;
+
+		udelay(100);
+		/* Write the bytes to the new bank. */
+		ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
+		                                               act_offset,
+		                                               (u8)data);
+		if (ret_val)
+			break;
+
+		udelay(100);
+		ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
+		                                          act_offset + 1,
+		                                          (u8)(data >> 8));
+		if (ret_val)
+			break;
+	}
+
+	/*
+	 * Don't bother writing the segment valid bits if sector
+	 * programming failed.
+	 */
+	if (ret_val) {
+		e_dbg("Flash commit failed.\n");
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/*
+	 * Finally validate the new segment by setting bit 15:14
+	 * to 10b in word 0x13 , this can be done without an
+	 * erase as well since these bits are 11 to start with
+	 * and we need to change bit 14 to 0b
+	 */
+	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+	ret_val = e1000e_read_flash_word_ich8lan(hw, act_offset, &data);
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	data &= 0xBFFF;
+	ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
+	                                               act_offset * 2 + 1,
+	                                               (u8)(data >> 8));
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/*
+	 * And invalidate the previously valid segment by setting
+	 * its signature word (0x13) high_byte to 0b. This can be
+	 * done without an erase because flash erase sets all bits
+	 * to 1's. We can write 1's to 0's without an erase
+	 */
+	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+	ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/* Great!  Everything worked, we can now clear the cached entries. */
+	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+		dev_spec->shadow_ram[i].modified = false;
+		dev_spec->shadow_ram[i].value = 0xFFFF;
+	}
+
+	nvm->ops.release(hw);
+
+	/*
+	 * Reload the EEPROM, or else modifications will not appear
+	 * until after the next adapter reset.
+	 */
+	nvm->ops.reload(hw);
+	msleep(10);
+
+out:
+	if (ret_val)
+		e_dbg("NVM update error: %d\n", ret_val);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ *  calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+static s32 e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	/*
+	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
+	 * needs to be fixed.  This bit is an indication that the NVM
+	 * was prepared by OEM software and did not calculate the
+	 * checksum...a likely scenario.
+	 */
+	ret_val = e1000e_read_nvm(hw, 0x19, 1, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & 0x40) == 0) {
+		data |= 0x40;
+		ret_val = e1000e_write_nvm(hw, 0x19, 1, &data);
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_update_nvm_checksum(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_validate_nvm_checksum_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_flash_data_ich8lan - Writes bytes to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte/word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: The byte(s) to write to the NVM.
+ *
+ *  Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static s32 e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 size, u16 data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+	u8 count = 0;
+
+	if (size < 1 || size > 2 || data > size * 0xff ||
+	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		goto out;
+
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+	                    hw->nvm.flash_base_addr;
+
+	do {
+		udelay(1);
+		/* Steps */
+		ret_val = e1000e_flash_cycle_init_ich8lan(hw);
+		if (ret_val != E1000_SUCCESS)
+			break;
+
+		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size - 1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+		if (size == 1)
+			flash_data = (u32)data & 0x00FF;
+		else
+			flash_data = (u32)data;
+
+		ew32flash(ICH_FLASH_FDATA0, flash_data);
+
+		/*
+		 * check if FCERR is set to 1 , if set to 1, clear it
+		 * and try the whole sequence a few more times else done
+		 */
+		ret_val = e1000e_flash_cycle_ich8lan(hw,
+		                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+		if (ret_val == E1000_SUCCESS)
+			break;
+
+		/*
+		 * If we're here, then things are most likely
+		 * completely hosed, but if the error condition
+		 * is detected, it won't hurt to give it another
+		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+		 */
+		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+		if (hsfsts.hsf_status.flcerr == 1) {
+			/* Repeat for some time before giving up. */
+			continue;
+		} else if (hsfsts.hsf_status.flcdone == 0) {
+			e_dbg("Timeout error - flash cycle "
+				 "did not complete.");
+			break;
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_flash_byte_ich8lan - Write a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The index of the byte to read.
+ *  @data: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ **/
+static s32 e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 data)
+{
+	u16 word = (u16)data;
+
+	return e1000e_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ *  e1000e_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to write.
+ *  @byte: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ *  Goes through a retry algorithm before giving up.
+ **/
+static s32 e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                                u32 offset, u8 byte)
+{
+	s32 ret_val;
+	u16 program_retries;
+
+	ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte);
+	if (ret_val == E1000_SUCCESS)
+		goto out;
+
+	for (program_retries = 0; program_retries < 100; program_retries++) {
+		e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset);
+		udelay(100);
+		ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte);
+		if (ret_val == E1000_SUCCESS)
+			break;
+	}
+	if (program_retries == 100) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ *  @hw: pointer to the HW structure
+ *  @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ *  bank N is 4096 * N + flash_reg_addr.
+ **/
+static s32 e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	/* bank size is in 16bit words - adjust to bytes */
+	u32 flash_bank_size = nvm->flash_bank_size * 2;
+	s32 ret_val = E1000_SUCCESS;
+	s32 count = 0;
+	s32 j, iteration, sector_size;
+
+	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+	/*
+	 * Determine HW Sector size: Read BERASE bits of hw flash status
+	 * register
+	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
+	 *     consecutive sectors.  The start index for the nth Hw sector
+	 *     can be calculated as = bank * 4096 + n * 256
+	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+	 *     The start index for the nth Hw sector can be calculated
+	 *     as = bank * 4096
+	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+	 *     (ich9 only, otherwise error condition)
+	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+	 */
+	switch (hsfsts.hsf_status.berasesz) {
+	case 0:
+		/* Hw sector size 256 */
+		sector_size = ICH_FLASH_SEG_SIZE_256;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+		break;
+	case 1:
+		sector_size = ICH_FLASH_SEG_SIZE_4K;
+		iteration = 1;
+		break;
+	case 2:
+		sector_size = ICH_FLASH_SEG_SIZE_8K;
+		iteration = 1;
+		break;
+	case 3:
+		sector_size = ICH_FLASH_SEG_SIZE_64K;
+		iteration = 1;
+		break;
+	default:
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Start with the base address, then add the sector offset. */
+	flash_linear_addr = hw->nvm.flash_base_addr;
+	flash_linear_addr += (bank) ? flash_bank_size : 0;
+
+	for (j = 0; j < iteration ; j++) {
+		do {
+			/* Steps */
+			ret_val = e1000e_flash_cycle_init_ich8lan(hw);
+			if (ret_val)
+				goto out;
+
+			/*
+			 * Write a value 11 (block Erase) in Flash
+			 * Cycle field in hw flash control
+			 */
+			hsflctl.regval = er16flash(
+			                                      ICH_FLASH_HSFCTL);
+			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+			ew16flash(ICH_FLASH_HSFCTL,
+			                        hsflctl.regval);
+
+			/*
+			 * Write the last 24 bits of an index within the
+			 * block into Flash Linear address field in Flash
+			 * Address.
+			 */
+			flash_linear_addr += (j * sector_size);
+			ew32flash(ICH_FLASH_FADDR,
+			                      flash_linear_addr);
+
+			ret_val = e1000e_flash_cycle_ich8lan(hw,
+			                       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+			if (ret_val == E1000_SUCCESS)
+				break;
+
+			/*
+			 * Check if FCERR is set to 1.  If 1,
+			 * clear it and try the whole sequence
+			 * a few more times else Done
+			 */
+			hsfsts.regval = er16flash(
+						      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1)
+				/* repeat for some time before giving up */
+				continue;
+			else if (hsfsts.hsf_status.flcdone == 0)
+				goto out;
+		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_valid_led_default_ich8lan - Set the default LED settings
+ *  @hw: pointer to the HW structure
+ *  @data: Pointer to the LED settings
+ *
+ *  Reads the LED default settings from the NVM to data.  If the NVM LED
+ *  settings is all 0's or F's, set the LED default to a valid LED default
+ *  setting.
+ **/
+static s32 e1000e_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 ||
+	    *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT_ICH8LAN;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_id_led_init_pchlan - store LED configurations
+ *  @hw: pointer to the HW structure
+ *
+ *  PCH does not control LEDs via the LEDCTL register, rather it uses
+ *  the PHY LED configuration register.
+ *
+ *  PCH also does not have an "always on" or "always off" mode which
+ *  complicates the ID feature.  Instead of using the "on" mode to indicate
+ *  in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()),
+ *  use "link_up" mode.  The LEDs will still ID on request if there is no
+ *  link based on logic in e1000e_led_[on|off]_pchlan().
+ **/
+static s32 e1000e_id_led_init_pchlan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+	u16 data, i, temp, shift;
+
+	/* Get default ID LED modes */
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = er32(LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+		shift = (i * 5);
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode1 |= (ledctl_on << shift);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode1 |= (ledctl_off << shift);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode2 |= (ledctl_on << shift);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode2 |= (ledctl_off << shift);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_bus_info_ich8lan - Get/Set the bus type and width
+ *  @hw: pointer to the HW structure
+ *
+ *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ *  register, so the the bus width is hard coded.
+ **/
+static s32 e1000e_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val;
+
+	ret_val = e1000e_get_bus_info_pcie(hw);
+
+	/*
+	 * ICH devices are "PCI Express"-ish.  They have
+	 * a configuration space, but do not contain
+	 * PCI Express Capability registers, so bus width
+	 * must be hardcoded.
+	 */
+	if (bus->width == e1000_bus_width_unknown)
+		bus->width = e1000_bus_width_pcie_x1;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_reset_hw_ich8lan - Reset the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a full reset of the hardware which includes a reset of the PHY and
+ *  MAC.
+ **/
+static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u16 reg;
+	u32 ctrl, kab;
+	s32 ret_val;
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val)
+		e_dbg("PCI-E Master disable polling has failed.\n");
+
+	e_dbg("Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	/*
+	 * Disable the Transmit and Receive units.  Then delay to allow
+	 * any pending transactions to complete before we hit the MAC
+	 * with the global reset.
+	 */
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	/* Workaround for ICH8 bit corruption issue in FIFO memory */
+	if (hw->mac.type == e1000_ich8lan) {
+		/* Set Tx and Rx buffer allocation to 8k apiece. */
+		ew32(PBA, E1000_PBA_8K);
+		/* Set Packet Buffer Size to 16k. */
+		ew32(PBS, E1000_PBS_16K);
+	}
+
+	if (hw->mac.type == e1000_pchlan) {
+		/* Save the NVM K1 bit setting*/
+		ret_val = e1000e_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
+		if (ret_val)
+			return ret_val;
+
+		if (reg & E1000_NVM_K1_ENABLE)
+			dev_spec->nvm_k1_enabled = true;
+		else
+			dev_spec->nvm_k1_enabled = false;
+	}
+
+	ctrl = er32(CTRL);
+
+	if (!e1000e_check_reset_block(hw) && !hw->phy.reset_disable) {
+		/* Clear PHY Reset Asserted bit */
+		if (hw->mac.type >= e1000_pchlan) {
+			u32 status = er32(STATUS);
+			ew32(STATUS, status &
+			                ~E1000_STATUS_PHYRA);
+		}
+
+		/*
+		 * PHY HW reset requires MAC CORE reset at the same
+		 * time to make sure the interface between MAC and the
+		 * external PHY is reset.
+		 */
+		ctrl |= E1000_CTRL_PHY_RST;
+	}
+	ret_val = e1000e_acquire_swflag_ich8lan(hw);
+	e_dbg("Issuing a global reset to ich8lan\n");
+	ew32(CTRL, (ctrl | E1000_CTRL_RST));
+	msleep(20);
+
+	if (!ret_val)
+		e1000e_release_swflag_ich8lan(hw);
+
+	if (ctrl & E1000_CTRL_PHY_RST)
+		ret_val = hw->phy.ops.get_cfg_done(hw);
+
+	if (hw->mac.type >= e1000_ich10lan) {
+		e1000e_lan_init_done_ich8lan(hw);
+	} else {
+		ret_val = e1000e_get_auto_rd_done(hw);
+		if (ret_val) {
+			/*
+			 * When auto config read does not complete, do not
+			 * return with an error. This can happen in situations
+			 * where there is no eeprom and prevents getting link.
+			 */
+			e_dbg("Auto Read Done did not complete\n");
+		}
+	}
+	/* Dummy read to clear the phy wakeup bit after lcd reset */
+	if (hw->mac.type == e1000_pchlan)
+		e1e_rphy(hw, BM_WUC, &reg);
+
+	ret_val = e1000e_sw_lcd_config_ich8lan(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000e_oem_bits_config_ich8lan(hw, true);
+		if (ret_val)
+			goto out;
+	}
+	/*
+	 * For PCH, this write will make sure that any noise
+	 * will be detected as a CRC error and be dropped rather than show up
+	 * as a bad packet to the DMA engine.
+	 */
+	if (hw->mac.type == e1000_pchlan)
+		ew32(CRC_OFFSET, 0x65656565);
+
+	ew32(IMC, 0xffffffff);
+	er32(ICR);
+
+	kab = er32(KABGTXD);
+	kab |= E1000_KABGTXD_BGSQLBIAS;
+	ew32(KABGTXD, kab);
+
+	if (hw->mac.type == e1000_pchlan)
+		ret_val = e1000e_hv_phy_workarounds_ich8lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_init_hw_ich8lan - Initialize the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Prepares the hardware for transmit and receive by doing the following:
+ *   - initialize hardware bits
+ *   - initialize LED identification
+ *   - setup receive address registers
+ *   - setup flow control
+ *   - setup transmit descriptors
+ *   - clear statistics
+ **/
+static s32 e1000e_init_hw_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl_ext, txdctl, snoop;
+	s32 ret_val;
+	u16 i;
+
+	e1000e_initialize_hw_bits_ich8lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val)
+		/* This is not fatal and we should not stop init due to this */
+		e_dbg("Error initializing identification LED\n");
+
+	/* Setup the receive address. */
+	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	e_dbg("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/*
+	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
+	 * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
+	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
+	 */
+	if (hw->phy.type == e1000_phy_82578) {
+		e1e_rphy(hw, BM_WUC, &i);
+		ret_val = e1000e_phy_hw_reset_ich8lan(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy for both queues */
+	txdctl = er32(TXDCTL(0));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	ew32(TXDCTL(0), txdctl);
+	txdctl = er32(TXDCTL(1));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	ew32(TXDCTL(1), txdctl);
+
+	/*
+	 * ICH8 has opposite polarity of no_snoop bits.
+	 * By default, we should use snoop behavior.
+	 */
+	if (mac->type == e1000_ich8lan)
+		snoop = PCIE_ICH8_SNOOP_ALL;
+	else
+		snoop = (u32)~(PCIE_NO_SNOOP_ALL);
+	e1000e_set_pcie_no_snoop(hw, snoop);
+
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+	ew32(CTRL_EXT, ctrl_ext);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000e_clear_hw_cntrs_ich8lan(hw);
+
+	return ret_val;
+}
+/**
+ *  e1000e_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets/Clears required hardware bits necessary for correctly setting up the
+ *  hardware for transmit and receive.
+ **/
+static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Extended Device Control */
+	reg = er32(CTRL_EXT);
+	reg |= (1 << 22);
+	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
+	if (hw->mac.type >= e1000_pchlan)
+		reg |= E1000_CTRL_EXT_PHYPDEN;
+	ew32(CTRL_EXT, reg);
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL(0));
+	reg |= (1 << 22);
+	ew32(TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL(1));
+	reg |= (1 << 22);
+	ew32(TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC(0));
+	if (hw->mac.type == e1000_ich8lan)
+		reg |= (1 << 28) | (1 << 29);
+	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+	ew32(TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC(1));
+	if (er32(TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	reg |= (1 << 24) | (1 << 26) | (1 << 30);
+	ew32(TARC(1), reg);
+
+	/* Device Status */
+	if (hw->mac.type == e1000_ich8lan) {
+		reg = er32(STATUS);
+		reg &= ~(1 << 31);
+		ew32(STATUS, reg);
+	}
+
+	return;
+}
+
+/**
+ *  e1000e_setup_link_ich8lan - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (e1000e_check_reset_block(hw))
+		goto out;
+
+	/*
+	 * ICH parts do not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	if (hw->fc.requested_mode == e1000_fc_default)
+		hw->fc.requested_mode = e1000_fc_full;
+
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	e_dbg("After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
+
+	/* Continue to configure the copper link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	ew32(FCTTV, hw->fc.pause_time);
+	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82577)) {
+		ret_val = e1e_wphy(hw,
+		                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
+		                             hw->fc.pause_time);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_set_fc_watermarks(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the kumeran interface to the PHY to wait the appropriate time
+ *  when polling the PHY, then call the generic setup_copper_link to finish
+ *  configuring the copper link.
+ **/
+static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	u16 reg_data;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	/*
+	 * Set the mac to wait the maximum time between each iteration
+	 * and increase the max iterations when polling the phy;
+	 * this fixes erroneous timeouts at 10Mbps.
+	 */
+	ret_val = e1000e_write_kmrn_reg(hw,
+	                                       E1000_KMRNCTRLSTA_TIMEOUTS,
+	                                       0xFFFF);
+	if (ret_val)
+		goto out;
+	ret_val = e1000e_read_kmrn_reg(hw,
+	                                      E1000_KMRNCTRLSTA_INBAND_PARAM,
+	                                      &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= 0x3F;
+	ret_val = e1000e_write_kmrn_reg(hw,
+	                                       E1000_KMRNCTRLSTA_INBAND_PARAM,
+	                                       reg_data);
+	if (ret_val)
+		goto out;
+
+	switch (hw->phy.type) {
+	case e1000_phy_igp_3:
+		ret_val = e1000e_copper_link_setup_igp(hw);
+		if (ret_val)
+			goto out;
+		break;
+	case e1000_phy_bm:
+	case e1000_phy_82578:
+		ret_val = e1000e_copper_link_setup_m88(hw);
+		if (ret_val)
+			goto out;
+		break;
+	case e1000_phy_82577:
+		ret_val = e1000e_copper_link_setup_82577(hw);
+		if (ret_val)
+			goto out;
+		break;
+	case e1000_phy_ife:
+		ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL,
+		                               &reg_data);
+		if (ret_val)
+			goto out;
+
+		reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+		switch (hw->phy.mdix) {
+		case 1:
+			reg_data &= ~IFE_PMC_FORCE_MDIX;
+			break;
+		case 2:
+			reg_data |= IFE_PMC_FORCE_MDIX;
+			break;
+		case 0:
+		default:
+			reg_data |= IFE_PMC_AUTO_MDIX;
+			break;
+		}
+		ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL,
+		                                reg_data);
+		if (ret_val)
+			goto out;
+		break;
+	default:
+		break;
+	}
+	ret_val = e1000e_setup_copper_link(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_link_up_info_ich8lan - Get current link speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to store current link speed
+ *  @duplex: pointer to store the current link duplex
+ *
+ *  Calls the generic get_speed_and_duplex to retrieve the current link
+ *  information and then calls the Kumeran lock loss workaround for links at
+ *  gigabit speeds.
+ **/
+static s32 e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
+                                          u16 *duplex)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
+	if (ret_val)
+		goto out;
+
+	if ((hw->mac.type == e1000_ich8lan) &&
+	    (hw->phy.type == e1000_phy_igp_3) &&
+	    (*speed == SPEED_1000)) {
+		ret_val = e1000e_kmrn_lock_loss_workaround_ich8lan(hw);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ *  @hw: pointer to the HW structure
+ *
+ *  Work-around for 82566 Kumeran PCS lock loss:
+ *  On link status change (i.e. PCI reset, speed change) and link is up and
+ *  speed is gigabit-
+ *    0) if workaround is optionally disabled do nothing
+ *    1) wait 1ms for Kumeran link to come up
+ *    2) check Kumeran Diagnostic register PCS lock loss bit
+ *    3) if not set the link is locked (all is good), otherwise...
+ *    4) reset the PHY
+ *    5) repeat up to 10 times
+ *  Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static s32 e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, data;
+	bool link;
+
+	if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
+		goto out;
+
+	/*
+	 * Make sure link is up before proceeding.  If not just return.
+	 * Attempting this while link is negotiating fouled up link
+	 * stability
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (!link) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	for (i = 0; i < 10; i++) {
+		/* read once to clear */
+		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			goto out;
+		/* and again to get new status */
+		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			goto out;
+
+		/* check for PCS lock */
+		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
+			ret_val = E1000_SUCCESS;
+			goto out;
+		}
+
+		/* Issue PHY reset */
+		e1000e_phy_hw_reset(hw);
+		mdelay(5);
+	}
+	/* Disable GigE link negotiation */
+	phy_ctrl = er32(PHY_CTRL);
+	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+	             E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+	ew32(PHY_CTRL, phy_ctrl);
+
+	/*
+	 * Call gig speed drop workaround on Gig disable before accessing
+	 * any PHY registers
+	 */
+	e1000e_gig_downshift_workaround_ich8lan(hw);
+
+	/* unable to acquire PCS lock */
+	ret_val = -E1000_ERR_PHY;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
+ *  @hw: pointer to the HW structure
+ *  @state: boolean value used to set the current Kumeran workaround state
+ *
+ *  If ICH8, set the current Kumeran workaround state (enabled - true
+ *  /disabled - false).
+ **/
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+                                                 bool state)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+	if (hw->mac.type != e1000_ich8lan) {
+		e_dbg("Workaround applies to ICH8 only.\n");
+		return;
+	}
+
+	dev_spec->kmrn_lock_loss_workaround_enabled = state;
+
+	return;
+}
+
+/**
+ *  e1000e_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ *  @hw: pointer to the HW structure
+ *
+ *  Workaround for 82566 power-down on D3 entry:
+ *    1) disable gigabit link
+ *    2) write VR power-down enable
+ *    3) read it back
+ *  Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+	u16 data;
+	u8  retry = 0;
+
+	if (hw->phy.type != e1000_phy_igp_3)
+		goto out;
+
+	/* Try the workaround twice (if needed) */
+	do {
+		/* Disable link */
+		reg = er32(PHY_CTRL);
+		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+		        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+		ew32(PHY_CTRL, reg);
+
+		/*
+		 * Call gig speed drop workaround on Gig disable before
+		 * accessing any PHY registers
+		 */
+		if (hw->mac.type == e1000_ich8lan)
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* Write VR power-down enable */
+		e1e_rphy(hw, IGP3_VR_CTRL, &data);
+		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		e1e_wphy(hw, IGP3_VR_CTRL,
+		                   data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+		/* Read it back and test */
+		e1e_rphy(hw, IGP3_VR_CTRL, &data);
+		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+			break;
+
+		/* Issue PHY reset and repeat at most one more time */
+		reg = er32(CTRL);
+		ew32(CTRL, reg | E1000_CTRL_PHY_RST);
+		retry++;
+	} while (retry);
+
+out:
+	return;
+}
+
+/**
+ *  e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ *  @hw: pointer to the HW structure
+ *
+ *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ *  LPLU, Gig disable, MDIC PHY reset):
+ *    1) Set Kumeran Near-end loopback
+ *    2) Clear Kumeran Near-end loopback
+ *  Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg_data;
+
+	if ((hw->mac.type != e1000_ich8lan) ||
+	    (hw->phy.type != e1000_phy_igp_3))
+		goto out;
+
+	ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                      &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000e_write_kmrn_reg(hw,
+	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                       reg_data);
+	if (ret_val)
+		goto out;
+	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000e_write_kmrn_reg(hw,
+	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                       reg_data);
+out:
+	return;
+}
+
+/**
+ *  e1000e_disable_gig_wol_ich8lan - disable gig during WoL
+ *  @hw: pointer to the HW structure
+ *
+ *  During S0 to Sx transition, it is possible the link remains at gig
+ *  instead of negotiating to a lower speed.  Before going to Sx, set
+ *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ *  to a lower speed.
+ *
+ *  Should only be called for applicable parts.
+ **/
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+	u32 phy_ctrl;
+
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+	case e1000_pchlan:
+		phy_ctrl = er32(PHY_CTRL);
+		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+		            E1000_PHY_CTRL_GBE_DISABLE;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		if (hw->mac.type == e1000_pchlan)
+			e1000e_phy_hw_reset_ich8lan(hw);
+	default:
+		break;
+	}
+
+	return;
+}
+
+/**
+ *  e1000e_cleanup_led_ich8lan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000e_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+		                              0);
+	else
+		ew32(LEDCTL, hw->mac.ledctl_default);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_led_on_ich8lan - Turn LEDs on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LEDs.
+ **/
+static s32 e1000e_led_on_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+		                (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+	else
+		ew32(LEDCTL, hw->mac.ledctl_mode2);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_led_off_ich8lan - Turn LEDs off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LEDs.
+ **/
+static s32 e1000e_led_off_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = e1e_wphy(hw,
+		               IFE_PHY_SPECIAL_CONTROL_LED,
+		               (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+	else
+		ew32(LEDCTL, hw->mac.ledctl_mode1);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_led_pchlan - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use.
+ **/
+static s32 e1000e_setup_led_pchlan(struct e1000_hw *hw)
+{
+	return e1e_wphy(hw, HV_LED_CONFIG,
+					(u16)hw->mac.ledctl_mode1);
+}
+
+/**
+ *  e1000e_cleanup_led_pchlan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000e_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+	return e1e_wphy(hw, HV_LED_CONFIG,
+					(u16)hw->mac.ledctl_default);
+}
+
+/**
+ *  e1000e_led_on_pchlan - Turn LEDs on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LEDs.
+ **/
+static s32 e1000e_led_on_pchlan(struct e1000_hw *hw)
+{
+	u16 data = (u16)hw->mac.ledctl_mode2;
+	u32 i, led;
+
+	/*
+	 * If no link, then turn LED on by setting the invert bit
+	 * for each LED that's mode is "link_up" in ledctl_mode2.
+	 */
+	if (!(er32(STATUS) & E1000_STATUS_LU)) {
+		for (i = 0; i < 3; i++) {
+			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+			if ((led & E1000_PHY_LED0_MODE_MASK) !=
+			    E1000_LEDCTL_MODE_LINK_UP)
+				continue;
+			if (led & E1000_PHY_LED0_IVRT)
+				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+			else
+				data |= (E1000_PHY_LED0_IVRT << (i * 5));
+		}
+	}
+
+	return e1e_wphy(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ *  e1000e_led_off_pchlan - Turn LEDs off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LEDs.
+ **/
+static s32 e1000e_led_off_pchlan(struct e1000_hw *hw)
+{
+	u16 data = (u16)hw->mac.ledctl_mode1;
+	u32 i, led;
+
+	/*
+	 * If no link, then turn LED off by clearing the invert bit
+	 * for each LED that's mode is "link_up" in ledctl_mode1.
+	 */
+	if (!(er32(STATUS) & E1000_STATUS_LU)) {
+		for (i = 0; i < 3; i++) {
+			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+			if ((led & E1000_PHY_LED0_MODE_MASK) !=
+			    E1000_LEDCTL_MODE_LINK_UP)
+				continue;
+			if (led & E1000_PHY_LED0_IVRT)
+				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+			else
+				data |= (E1000_PHY_LED0_IVRT << (i * 5));
+		}
+	}
+
+	return e1e_wphy(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ *  e1000e_get_cfg_done_ich8lan - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 bank = 0;
+
+	if (hw->mac.type >= e1000_pchlan) {
+		u32 status = er32(STATUS);
+
+		if (status & E1000_STATUS_PHYRA) {
+			ew32(STATUS, status &
+			                ~E1000_STATUS_PHYRA);
+		} else
+			e_dbg("PHY Reset Asserted not set - needs delay\n");
+	}
+
+	e1000e_get_cfg_done(hw);
+
+	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
+	if ((hw->mac.type != e1000_ich10lan) &&
+	    (hw->mac.type != e1000_pchlan)) {
+		if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
+		    (hw->phy.type == e1000_phy_igp_3)) {
+			e1000e_phy_init_script_igp3(hw);
+		}
+	} else {
+		if (e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+			/* Maybe we should do a basic PHY config */
+			e_dbg("EEPROM not present\n");
+			ret_val = -E1000_ERR_CONFIG;
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ * e1000e_power_down_phy_copper_ich8lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
+{
+	/* If the management interface is not enabled, then power down */
+	if (!(hw->mac.ops.check_mng_mode(hw) ||
+	      e1000e_check_reset_block(hw)))
+		e1000e_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000e_clear_hw_cntrs_ich8lan - Clear statistical counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears hardware counters specific to the silicon family and calls
+ *  clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw __unused)
+{
+#if 0
+	u16 phy_data;
+
+	e1000e_clear_hw_cntrs_base(hw);
+
+	er32(ALGNERRC);
+	er32(RXERRC);
+	er32(TNCRS);
+	er32(CEXTERR);
+	er32(TSCTC);
+	er32(TSCTFC);
+
+	er32(MGTPRC);
+	er32(MGTPDC);
+	er32(MGTPTC);
+
+	er32(IAC);
+	er32(ICRXOC);
+
+	/* Clear PHY statistics registers */
+	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82577)) {
+		e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
+		e1e_rphy(hw, HV_SCC_LOWER, &phy_data);
+		e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
+		e1e_rphy(hw, HV_ECOL_LOWER, &phy_data);
+		e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
+		e1e_rphy(hw, HV_MCC_LOWER, &phy_data);
+		e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
+		e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data);
+		e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
+		e1e_rphy(hw, HV_COLC_LOWER, &phy_data);
+		e1e_rphy(hw, HV_DC_UPPER, &phy_data);
+		e1e_rphy(hw, HV_DC_LOWER, &phy_data);
+		e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
+		e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data);
+	}
+#endif
+}
+
+static struct pci_device_id e1000e_ich8lan_nics[] = {
+     PCI_ROM(0x8086, 0x104C, "E1000_DEV_ID_ICH8_IFE", "E1000_DEV_ID_ICH8_IFE", board_ich8lan),
+     PCI_ROM(0x8086, 0x10C5, "E1000_DEV_ID_ICH8_IFE_G", "E1000_DEV_ID_ICH8_IFE_G", board_ich8lan),
+     PCI_ROM(0x8086, 0x10C4, "E1000_DEV_ID_ICH8_IFE_GT", "E1000_DEV_ID_ICH8_IFE_GT", board_ich8lan),
+     PCI_ROM(0x8086, 0x104A, "E1000_DEV_ID_ICH8_IGP_AMT", "E1000_DEV_ID_ICH8_IGP_AMT", board_ich8lan),
+     PCI_ROM(0x8086, 0x104B, "E1000_DEV_ID_ICH8_IGP_C", "E1000_DEV_ID_ICH8_IGP_C", board_ich8lan),
+     PCI_ROM(0x8086, 0x104D, "E1000_DEV_ID_ICH8_IGP_M", "E1000_DEV_ID_ICH8_IGP_M", board_ich8lan),
+     PCI_ROM(0x8086, 0x1049, "E1000_DEV_ID_ICH8_IGP_M_AMT", "E1000_DEV_ID_ICH8_IGP_M_AMT", board_ich8lan),
+     PCI_ROM(0x8086, 0x1501, "E1000_DEV_ID_ICH8_82567V_3", "E1000_DEV_ID_ICH8_82567V_3", board_ich8lan),
+     PCI_ROM(0x8086, 0x10C0, "E1000_DEV_ID_ICH9_IFE", "E1000_DEV_ID_ICH9_IFE", board_ich9lan),
+     PCI_ROM(0x8086, 0x10C2, "E1000_DEV_ID_ICH9_IFE_G", "E1000_DEV_ID_ICH9_IFE_G", board_ich9lan),
+     PCI_ROM(0x8086, 0x10C3, "E1000_DEV_ID_ICH9_IFE_GT", "E1000_DEV_ID_ICH9_IFE_GT", board_ich9lan),
+     PCI_ROM(0x8086, 0x10BD, "E1000_DEV_ID_ICH9_IGP_AMT", "E1000_DEV_ID_ICH9_IGP_AMT", board_ich9lan),
+     PCI_ROM(0x8086, 0x294C, "E1000_DEV_ID_ICH9_IGP_C", "E1000_DEV_ID_ICH9_IGP_C", board_ich9lan),
+     PCI_ROM(0x8086, 0x10E5, "E1000_DEV_ID_ICH9_BM", "E1000_DEV_ID_ICH9_BM", board_ich9lan),
+     PCI_ROM(0x8086, 0x10BF, "E1000_DEV_ID_ICH9_IGP_M", "E1000_DEV_ID_ICH9_IGP_M", board_ich9lan),
+     PCI_ROM(0x8086, 0x10F5, "E1000_DEV_ID_ICH9_IGP_M_AMT", "E1000_DEV_ID_ICH9_IGP_M_AMT", board_ich9lan),
+     PCI_ROM(0x8086, 0x10CB, "E1000_DEV_ID_ICH9_IGP_M_V", "E1000_DEV_ID_ICH9_IGP_M_V", board_ich9lan),
+     PCI_ROM(0x8086, 0x10CC, "E1000_DEV_ID_ICH10_R_BM_LM", "E1000_DEV_ID_ICH10_R_BM_LM", board_ich9lan),
+     PCI_ROM(0x8086, 0x10CD, "E1000_DEV_ID_ICH10_R_BM_LF", "E1000_DEV_ID_ICH10_R_BM_LF", board_ich9lan),
+     PCI_ROM(0x8086, 0x10CE, "E1000_DEV_ID_ICH10_R_BM_V", "E1000_DEV_ID_ICH10_R_BM_V", board_ich9lan),
+     PCI_ROM(0x8086, 0x10DE, "E1000_DEV_ID_ICH10_D_BM_LM", "E1000_DEV_ID_ICH10_D_BM_LM", board_ich10lan),
+     PCI_ROM(0x8086, 0x10DF, "E1000_DEV_ID_ICH10_D_BM_LF", "E1000_DEV_ID_ICH10_D_BM_LF", board_ich10lan),
+     PCI_ROM(0x8086, 0x10EA, "E1000_DEV_ID_PCH_M_HV_LM", "E1000_DEV_ID_PCH_M_HV_LM", board_pchlan),
+     PCI_ROM(0x8086, 0x10EB, "E1000_DEV_ID_PCH_M_HV_LC", "E1000_DEV_ID_PCH_M_HV_LC", board_pchlan),
+     PCI_ROM(0x8086, 0x10EF, "E1000_DEV_ID_PCH_D_HV_DM", "E1000_DEV_ID_PCH_D_HV_DM", board_pchlan),
+     PCI_ROM(0x8086, 0x10F0, "E1000_DEV_ID_PCH_D_HV_DC", "E1000_DEV_ID_PCH_D_HV_DC", board_pchlan),
+};
+
+struct pci_driver e1000e_ich8lan_driver __pci_driver = {
+	.ids = e1000e_ich8lan_nics,
+	.id_count = (sizeof (e1000e_ich8lan_nics) / sizeof (e1000e_ich8lan_nics[0])),
+	.probe = e1000e_probe,
+	.remove = e1000e_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h
new file mode 100644
index 0000000..af34478
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h
@@ -0,0 +1,196 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_ICH8LAN_H_
+#define _E1000E_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG                 0x0000
+#define ICH_FLASH_HSFSTS                 0x0004
+#define ICH_FLASH_HSFCTL                 0x0006
+#define ICH_FLASH_FADDR                  0x0008
+#define ICH_FLASH_FDATA0                 0x0010
+
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define ICH_FLASH_READ_COMMAND_TIMEOUT   10000000
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT  10000000
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT  10000000
+#define ICH_FLASH_LINEAR_ADDR_MASK       0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT     10
+
+#define ICH_CYCLE_READ                   0
+#define ICH_CYCLE_WRITE                  2
+#define ICH_CYCLE_ERASE                  3
+
+#define FLASH_GFPREG_BASE_MASK           0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT          12
+
+#define ICH_FLASH_SEG_SIZE_256           256
+#define ICH_FLASH_SEG_SIZE_4K            4096
+#define ICH_FLASH_SEG_SIZE_8K            8192
+#define ICH_FLASH_SEG_SIZE_64K           65536
+#define ICH_FLASH_SECTOR_SIZE            4096
+
+#define ICH_FLASH_REG_MAPSIZE            0x00A0
+
+#define E1000_ICH_FWSM_RSPCIPHY          0x00000040 /* Reset PHY on PCI Reset */
+#define E1000_ICH_FWSM_DISSW             0x10000000 /* FW Disables SW Writes */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID          0x00008000
+
+#define E1000_ICH_MNG_IAMT_MODE          0x2
+
+#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
+                                 (ID_LED_OFF1_OFF2 <<  8) | \
+                                 (ID_LED_OFF1_ON2  <<  4) | \
+                                 (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD           0x13
+#define E1000_ICH_NVM_SIG_MASK           0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK     0xC0
+#define E1000_ICH_NVM_SIG_VALUE          0x80
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT      1500
+
+#define E1000_FEXTNVM_SW_CONFIG        1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+
+#define PCIE_ICH8_SNOOP_ALL   PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES            7
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+                           ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
+#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */
+#define IGP3_PM_CTRL    PHY_REG(769, 20) /* Power Management Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS         0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN           0x0200
+#define IGP3_PM_CTRL_FORCE_PWR_DOWN          0x0020
+
+/* PHY Wakeup Registers and defines */
+#define BM_RCTL         PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC          PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC         PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS          PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i)    (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i)    (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i)    (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i)      (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
+#define BM_RCTL_UPE           0x0001          /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE           0x0002          /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT      3               /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK       (3 << 3)        /* Multicast Offset Mask */
+#define BM_RCTL_BAM           0x0020          /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF          0x0040          /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE          0x0080          /* Rx Flow Control Enable */
+
+#define HV_LED_CONFIG		PHY_REG(768, 30) /* LED Configuration */
+#define HV_MUX_DATA_CTRL               PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC    0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED   0x0004
+#define HV_SCC_UPPER		PHY_REG(778, 16) /* Single Collision Count */
+#define HV_SCC_LOWER		PHY_REG(778, 17)
+#define HV_ECOL_UPPER		PHY_REG(778, 18) /* Excessive Collision Count */
+#define HV_ECOL_LOWER		PHY_REG(778, 19)
+#define HV_MCC_UPPER		PHY_REG(778, 20) /* Multiple Collision Count */
+#define HV_MCC_LOWER		PHY_REG(778, 21)
+#define HV_LATECOL_UPPER	PHY_REG(778, 23) /* Late Collision Count */
+#define HV_LATECOL_LOWER	PHY_REG(778, 24)
+#define HV_COLC_UPPER		PHY_REG(778, 25) /* Collision Count */
+#define HV_COLC_LOWER		PHY_REG(778, 26)
+#define HV_DC_UPPER		PHY_REG(778, 27) /* Defer Count */
+#define HV_DC_LOWER		PHY_REG(778, 28)
+#define HV_TNCRS_UPPER		PHY_REG(778, 29) /* Transmit with no CRS */
+#define HV_TNCRS_LOWER		PHY_REG(778, 30)
+
+#define E1000_FCRTV_PCH     0x05F40 /* PCH Flow Control Refresh Timer Value */
+
+#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE 0x1  /* NVM Enable K1 bit */
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR            PHY_REG(768, 26)
+#define HV_SMB_ADDR_PEC_EN     0x0200
+#define HV_SMB_ADDR_VALID      0x0080
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP                     0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS            PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU       0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS    0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+#define LCD_CFG_PHY_ADDR_BIT   0x0020 /* Phy address bit from LCD Config word */
+
+#define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */
+
+/*
+ * Additional interrupts need to be handled for ICH family:
+ *  DSW = The FW changed the status of the DISSW bit in FWSM
+ *  PHYINT = The LAN connected device generates an interrupt
+ *  EPRST = Manageability reset event
+ */
+#define IMS_ICH_ENABLE_MASK (\
+    E1000_IMS_DSW   | \
+    E1000_IMS_PHYINT | \
+    E1000_IMS_EPRST)
+
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNC       0x00004000          /* PN threshold - client */
+#define E1000_IMS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
+#define E1000_ICS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
+
+/* Security Processing bit Indication */
+#define E1000_RXDEXT_LINKSEC_STATUS_LSECH       0x01000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK     0x60000000
+#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH  0x20000000
+#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG      0x60000000
+
+
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+                                                 bool state);
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c
new file mode 100644
index 0000000..d96b279
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c
@@ -0,0 +1,1883 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000e.h"
+
+static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
+static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw);
+static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw);
+static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw);
+static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+
+/**
+ *  e1000e_init_mac_ops_generic - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000e_init_mac_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	/* General Setup */
+	mac->ops.set_lan_id = e1000e_set_lan_id_multi_port_pcie;
+	mac->ops.read_mac_addr = e1000e_read_mac_addr_generic;
+	mac->ops.config_collision_dist = e1000e_config_collision_dist;
+	/* LINK */
+	mac->ops.wait_autoneg = e1000e_wait_autoneg;
+	/* Management */
+#if 0
+	mac->ops.mng_host_if_write = e1000e_mng_host_if_write_generic;
+	mac->ops.mng_write_cmd_header = e1000e_mng_write_cmd_header_generic;
+	mac->ops.mng_enable_host_if = e1000e_mng_enable_host_if_generic;
+#endif
+	/* VLAN, MC, etc. */
+	mac->ops.rar_set = e1000e_rar_set;
+	mac->ops.validate_mdi_setting = e1000e_validate_mdi_setting_generic;
+}
+
+/**
+ *  e1000e_get_bus_info_pcie - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_bus_info *bus = &hw->bus;
+
+	s32 ret_val;
+	u16 pcie_link_status;
+
+	bus->type = e1000_bus_type_pci_express;
+	bus->speed = e1000_bus_speed_2500;
+
+	ret_val = e1000e_read_pcie_cap_reg(hw,
+	                                  PCIE_LINK_STATUS,
+	                                  &pcie_link_status);
+	if (ret_val)
+		bus->width = e1000_bus_width_unknown;
+	else
+		bus->width = (enum e1000_bus_width)((pcie_link_status &
+		                                PCIE_LINK_WIDTH_MASK) >>
+		                               PCIE_LINK_WIDTH_SHIFT);
+
+	mac->ops.set_lan_id(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u32 reg;
+
+	/*
+	 * The status register reports the correct function number
+	 * for the device regardless of function swap state.
+	 */
+	reg = er32(STATUS);
+	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/**
+ *  e1000e_set_lan_id_single_port - Set LAN id for a single port device
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the LAN function id to zero for a single port device.
+ **/
+void e1000e_set_lan_id_single_port(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+
+	bus->func = 0;
+}
+
+/**
+ *  e1000e_clear_vfta_generic - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void e1000e_clear_vfta_generic(struct e1000_hw *hw)
+{
+	u32 offset;
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+		e1e_flush();
+	}
+}
+
+/**
+ *  e1000e_write_vfta_generic - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_init_rx_addrs - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+	u8 mac_addr[ETH_ADDR_LEN] = {0};
+
+	/* Setup the receive address */
+	e_dbg("Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	e_dbg("Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++)
+		hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ *  e1000e_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address. If an
+ *  alternate MAC address is found it is programmed into RAR0, replacing
+ *  the permanent address that was installed into RAR0 by the Si on reset.
+ *  This function will return SUCCESS unless it encounters an error while
+ *  reading the EEPROM.
+ **/
+s32 e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 i;
+	s32 ret_val = E1000_SUCCESS;
+	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+	u8 alt_mac_addr[ETH_ADDR_LEN];
+
+	ret_val = e1000e_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+	                         &nvm_alt_mac_addr_offset);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	if (nvm_alt_mac_addr_offset == 0xFFFF) {
+		/* There is no Alternate MAC Address */
+		goto out;
+	}
+
+	if (hw->bus.func == E1000_FUNC_1)
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = nvm_alt_mac_addr_offset + (i >> 1);
+		ret_val = e1000e_read_nvm(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			e_dbg("NVM Read Error\n");
+			goto out;
+		}
+
+		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+	}
+
+	/* if multicast bit is set, the alternate address will not be used */
+	if (alt_mac_addr[0] & 0x01) {
+		e_dbg("Ignoring Alternate Mac Address with MC bit set\n");
+		goto out;
+	}
+
+	/*
+	 * We have a valid alternate MAC address, and we want to treat it the
+	 * same as the normal permanent MAC address stored by the HW into the
+	 * RAR. Do this by mapping this address into RAR0.
+	 */
+	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_rar_set - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+	           ((u32) addr[1] << 8) |
+	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	/* If MAC address zero, no need to set the AV bit */
+	if (rar_low || rar_high)
+		rar_high |= E1000_RAH_AV;
+
+	/*
+	 * Some bridges will combine consecutive 32-bit writes into
+	 * a single burst write, which will malfunction on some parts.
+	 * The flushes avoid this.
+	 */
+	ew32(RAL(index), rar_low);
+	e1e_flush();
+	ew32(RAH(index), rar_high);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_mta_set_generic - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	/*
+	 * The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_update_mc_addr_list_generic - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates entire Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
+                                       u8 *mc_addr_list, u32 mc_addr_count)
+{
+	u32 hash_value, hash_bit, hash_reg;
+	int i;
+
+	/* clear mta_shadow */
+	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+	/* update mta_shadow from mc_addr_list */
+	for (i = 0; (u32) i < mc_addr_count; i++) {
+		hash_value = e1000e_hash_mc_addr_generic(hw, mc_addr_list);
+
+		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+		hash_bit = hash_value & 0x1F;
+
+		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+		mc_addr_list += (ETH_ADDR_LEN);
+	}
+
+	/* replace the entire MTA table */
+	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_hash_mc_addr_generic - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  e1000e_mta_set_generic()
+ **/
+static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/*
+	 * The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 *
+	 * For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB                 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+	default:
+	case 0:
+		break;
+	case 1:
+		bit_shift += 1;
+		break;
+	case 2:
+		bit_shift += 2;
+		break;
+	case 3:
+		bit_shift += 4;
+		break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+	                          (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  e1000e_clear_hw_cntrs_base - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw __unused)
+{
+#if 0
+	er32(CRCERRS);
+	er32(SYMERRS);
+	er32(MPC);
+	er32(SCC);
+	er32(ECOL);
+	er32(MCC);
+	er32(LATECOL);
+	er32(COLC);
+	er32(DC);
+	er32(SEC);
+	er32(RLEC);
+	er32(XONRXC);
+	er32(XONTXC);
+	er32(XOFFRXC);
+	er32(XOFFTXC);
+	er32(FCRUC);
+	er32(GPRC);
+	er32(BPRC);
+	er32(MPRC);
+	er32(GPTC);
+	er32(GORCL);
+	er32(GORCH);
+	er32(GOTCL);
+	er32(GOTCH);
+	er32(RNBC);
+	er32(RUC);
+	er32(RFC);
+	er32(ROC);
+	er32(RJC);
+	er32(TORL);
+	er32(TORH);
+	er32(TOTL);
+	er32(TOTH);
+	er32(TPR);
+	er32(TPT);
+	er32(MPTC);
+	er32(BPTC);
+#endif
+}
+
+/**
+ *  e1000e_check_for_copper_link - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000e_check_downshift(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000e_config_collision_dist(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000e_config_fc_after_link_up(hw);
+	if (ret_val)
+		e_dbg("Error configuring flow control\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_for_fiber_link - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	ctrl = er32(CTRL);
+	status = er32(STATUS);
+	rxcw = er32(RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = er32(CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		ew32(CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000e_config_fc_after_link_up(hw);
+		if (ret_val) {
+			e_dbg("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		ew32(TXCW, mac->txcw);
+		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_for_serdes_link - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	ctrl = er32(CTRL);
+	status = er32(STATUS);
+	rxcw = er32(RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), and our link partner is not trying to
+	 * auto-negotiate with us (we are receiving idles or data),
+	 * we need to force link up. We also need to give auto-negotiation
+	 * time to complete.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = er32(CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		ew32(CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000e_config_fc_after_link_up(hw);
+		if (ret_val) {
+			e_dbg("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		ew32(TXCW, mac->txcw);
+		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
+		/*
+		 * If we force link for non-auto-negotiation switch, check
+		 * link status based on MAC synchronization for internal
+		 * serdes media type.
+		 */
+		/* SYNCH bit and IV bit are sticky. */
+		udelay(10);
+		rxcw = er32(RXCW);
+		if (rxcw & E1000_RXCW_SYNCH) {
+			if (!(rxcw & E1000_RXCW_IV)) {
+				mac->serdes_has_link = true;
+				e_dbg("SERDES: Link up - forced.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			e_dbg("SERDES: Link down - force failed.\n");
+		}
+	}
+
+	if (E1000_TXCW_ANE & er32(TXCW)) {
+		status = er32(STATUS);
+		if (status & E1000_STATUS_LU) {
+			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
+			udelay(10);
+			rxcw = er32(RXCW);
+			if (rxcw & E1000_RXCW_SYNCH) {
+				if (!(rxcw & E1000_RXCW_IV)) {
+					mac->serdes_has_link = true;
+					e_dbg("SERDES: Link up - autoneg "
+					   "completed sucessfully.\n");
+				} else {
+					mac->serdes_has_link = false;
+					e_dbg("SERDES: Link down - invalid"
+					   "codewords detected in autoneg.\n");
+				}
+			} else {
+				mac->serdes_has_link = false;
+				e_dbg("SERDES: Link down - no sync.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			e_dbg("SERDES: Link down - autoneg failed\n");
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_link - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 e1000e_setup_link(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (hw->phy.ops.check_reset_block)
+		if (e1000e_check_reset_block(hw))
+			goto out;
+
+	/*
+	 * If requested flow control is set to default, set flow control
+	 * based on the EEPROM flow control settings.
+	 */
+	if (hw->fc.requested_mode == e1000_fc_default) {
+		ret_val = e1000e_set_default_fc_generic(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	e_dbg("After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	e_dbg("Initializing the Flow Control address, type and timer regs\n");
+	ew32(FCT, FLOW_CONTROL_TYPE);
+	ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	ew32(FCTTV, hw->fc.pause_time);
+
+	ret_val = e1000e_set_fc_watermarks(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes
+ *  links.  Upon successful setup, poll for link.
+ **/
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	ctrl = er32(CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	e1000e_config_collision_dist(hw);
+
+	ret_val = e1000e_commit_fc_settings_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
+	 */
+	e_dbg("Auto-negotiation enabled\n");
+
+	ew32(CTRL, ctrl);
+	e1e_flush();
+	msleep(1);
+
+	/*
+	 * For these adapters, the SW definable pin 1 is set when the optics
+	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
+	 * indication.
+	 */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+	    (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = e1000e_poll_fiber_serdes_link_generic(hw);
+	} else {
+		e_dbg("No signal detected\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_config_collision_dist - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000e_config_collision_dist(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	tctl = er32(TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	ew32(TCTL, tctl);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_poll_fiber_serdes_link_generic - Poll for link up
+ *  @hw: pointer to the HW structure
+ *
+ *  Polls for link up by reading the status register, if link fails to come
+ *  up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 i, status;
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * If we have a signal (the cable is plugged in, or assumed true for
+	 * serdes media) then poll for a "Link-Up" indication in the Device
+	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
+	 * seconds (Auto-negotiation should complete in less than 500
+	 * milliseconds even if the other end is doing it in SW).
+	 */
+	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+		msleep(10);
+		status = er32(STATUS);
+		if (status & E1000_STATUS_LU)
+			break;
+	}
+	if (i == FIBER_LINK_UP_LIMIT) {
+		e_dbg("Never got a valid link from auto-neg!!!\n");
+		mac->autoneg_failed = 1;
+		/*
+		 * AutoNeg failed to achieve a link, so we'll call
+		 * mac->check_for_link. This routine will force the
+		 * link up if we detect a signal. This will allow us to
+		 * communicate with non-autonegotiating link partners.
+		 */
+		ret_val = hw->mac.ops.check_for_link(hw);
+		if (ret_val) {
+			e_dbg("Error while checking for link\n");
+			goto out;
+		}
+		mac->autoneg_failed = 0;
+	} else {
+		mac->autoneg_failed = 0;
+		e_dbg("Valid Link Found\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_commit_fc_settings_generic - Configure flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Write the flow control settings to the Transmit Config Word Register (TXCW)
+ *  base on the flow control settings in e1000_mac_info.
+ **/
+static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txcw;
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Transmit Config Word Register (TXCW) and re-start auto-
+	 * negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames,
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we
+	 *          do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/* Flow control completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is disabled
+		 * by a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of Rx Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric RX
+		 * PAUSE.  Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		e_dbg("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	ew32(TXCW, txcw);
+	mac->txcw = txcw;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_fc_watermarks - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  transmission as well.
+ **/
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 fcrtl = 0, fcrth = 0;
+
+	/*
+	 * Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.current_mode & e1000_fc_tx_pause) {
+		/*
+		 * We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	ew32(FCRTL, fcrtl);
+	ew32(FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_set_default_fc_generic - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	/*
+	 * Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		hw->fc.requested_mode = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		hw->fc.requested_mode = e1000_fc_tx_pause;
+	else
+		hw->fc.requested_mode = e1000_fc_full;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_force_mac_fc - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000e_force_mac_fc(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	ctrl = er32(CTRL);
+
+	/*
+	 * Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc.current_mode" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	e_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		e_dbg("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ew32(CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_config_fc_after_link_up - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	/*
+	 * Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes)
+			ret_val = e1000e_force_mac_fc(hw);
+	} else {
+		if (hw->phy.media_type == e1000_media_type_copper)
+			ret_val = e1000e_force_mac_fc(hw);
+	}
+
+	if (ret_val) {
+		e_dbg("Error forcing flow control settings\n");
+		goto out;
+	}
+
+	/*
+	 * Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+		/*
+		 * Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			e_dbg("Copper PHY and Auto Neg "
+			         "has not completed.\n");
+			goto out;
+		}
+
+		/*
+		 * The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV,
+		                             &mii_nway_adv_reg);
+		if (ret_val)
+			goto out;
+		ret_val = e1e_rphy(hw, PHY_LP_ABILITY,
+		                             &mii_nway_lp_ability_reg);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/*
+			 * Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
+				e_dbg("Flow Control = FULL.\r\n");
+			} else {
+				hw->fc.current_mode = e1000_fc_rx_pause;
+				e_dbg("Flow Control = "
+				         "RX PAUSE frames only.\r\n");
+			}
+		}
+		/*
+		 * For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_tx_pause;
+			e_dbg("Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/*
+		 * For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_rx_pause;
+			e_dbg("Flow Control = RX PAUSE frames only.\r\n");
+		} else {
+			/*
+			 * Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.current_mode = e1000_fc_none;
+			e_dbg("Flow Control = NONE.\r\n");
+		}
+
+		/*
+		 * Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			e_dbg("Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			hw->fc.current_mode = e1000_fc_none;
+
+		/*
+		 * Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = e1000e_force_mac_fc(hw);
+		if (ret_val) {
+			e_dbg("Error forcing flow control settings\n");
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_speed_and_duplex_copper - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	u32 status;
+
+	status = er32(STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		e_dbg("1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		e_dbg("100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		e_dbg("10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		e_dbg("Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		e_dbg("Half Duplex\n");
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Sets the speed and duplex to gigabit full duplex (the only possible option)
+ *  for fiber/serdes links.
+ **/
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw __unused,
+                                                    u16 *speed, u16 *duplex)
+{
+	*speed = SPEED_1000;
+	*duplex = FULL_DUPLEX;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_get_hw_semaphore - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = er32(SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		udelay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		e_dbg("Driver can't access device - SMBI bit is set.\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (er32(SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		udelay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000e_put_hw_semaphore(hw);
+		e_dbg("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_put_hw_semaphore - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000e_put_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = er32(SWSM);
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+	ew32(SWSM, swsm);
+}
+/**
+ *  e1000e_get_auto_rd_done - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (er32(EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msleep(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		e_dbg("Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_valid_led_default - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_id_led_init -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000e_id_led_init(struct e1000_hw *hw __unused)
+{
+#if 0
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = er32(LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_setup_led_generic - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+s32 e1000e_setup_led_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ledctl;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.ops.setup_led != e1000e_setup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		ledctl = er32(LEDCTL);
+		hw->mac.ledctl_default = ledctl;
+		/* Turn off LED0 */
+		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+		            E1000_LEDCTL_LED0_BLINK |
+		            E1000_LEDCTL_LED0_MODE_MASK);
+		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+		           E1000_LEDCTL_LED0_MODE_SHIFT);
+		ew32(LEDCTL, ledctl);
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
+		ew32(LEDCTL, hw->mac.ledctl_mode1);
+	}
+
+out:
+	return ret_val;
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_cleanup_led_generic - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.ops.cleanup_led != e1000e_cleanup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ew32(LEDCTL, hw->mac.ledctl_default);
+
+out:
+	return ret_val;
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_blink_led - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the LEDs which are set to be on.
+ **/
+s32 e1000e_blink_led(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/*
+		 * set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2
+		 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+				                 (i * 8));
+	}
+
+	ew32(LEDCTL, ledctl_blink);
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_led_on_generic - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+s32 e1000e_led_on_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl;
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = er32(CTRL);
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		ew32(CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		ew32(LEDCTL, hw->mac.ledctl_mode2);
+		break;
+	default:
+		break;
+	}
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_led_off_generic - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 e1000e_led_off_generic(struct e1000_hw *hw __unused)
+{
+#if 0
+	u32 ctrl;
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = er32(CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		ew32(CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		ew32(LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+#endif
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_set_pcie_no_snoop - Set PCI-express capabilities
+ *  @hw: pointer to the HW structure
+ *  @no_snoop: bitmap of snoop events
+ *
+ *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
+{
+	u32 gcr;
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	if (no_snoop) {
+		gcr = er32(GCR);
+		gcr &= ~(PCIE_NO_SNOOP_ALL);
+		gcr |= no_snoop;
+		ew32(GCR, gcr);
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000e_disable_pcie_master - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	ew32(CTRL, ctrl);
+
+	while (timeout) {
+		if (!(er32(STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		udelay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		e_dbg("Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000e_reset_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!mac->adaptive_ifs) {
+		e_dbg("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	mac->current_ifs_val = 0;
+	mac->ifs_min_val = IFS_MIN;
+	mac->ifs_max_val = IFS_MAX;
+	mac->ifs_step_size = IFS_STEP;
+	mac->ifs_ratio = IFS_RATIO;
+
+	mac->in_ifs_mode = false;
+	ew32(AIT, 0);
+out:
+	return;
+}
+
+/**
+ *  e1000e_update_adaptive - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void e1000e_update_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!mac->adaptive_ifs) {
+		e_dbg("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = true;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				ew32(AIT, mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = false;
+			ew32(AIT, 0);
+		}
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000e_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+		e_dbg("Invalid MDI setting detected\n");
+		hw->phy.mdix = 1;
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h
new file mode 100644
index 0000000..5b8a425
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h
@@ -0,0 +1,79 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_MAC_H_
+#define _E1000E_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void e1000e_init_mac_ops_generic(struct e1000_hw *hw);
+s32  e1000e_blink_led(struct e1000_hw *hw);
+s32  e1000e_check_for_copper_link(struct e1000_hw *hw);
+s32  e1000e_check_for_fiber_link(struct e1000_hw *hw);
+s32  e1000e_check_for_serdes_link(struct e1000_hw *hw);
+s32  e1000e_cleanup_led_generic(struct e1000_hw *hw);
+s32  e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+s32  e1000e_disable_pcie_master(struct e1000_hw *hw);
+s32  e1000e_force_mac_fc(struct e1000_hw *hw);
+s32  e1000e_get_auto_rd_done(struct e1000_hw *hw);
+s32  e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+void e1000e_set_lan_id_single_port(struct e1000_hw *hw);
+s32  e1000e_get_hw_semaphore(struct e1000_hw *hw);
+s32  e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+s32  e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw,
+                                                     u16 *speed, u16 *duplex);
+s32  e1000e_id_led_init(struct e1000_hw *hw);
+s32  e1000e_led_on_generic(struct e1000_hw *hw);
+s32  e1000e_led_off_generic(struct e1000_hw *hw);
+void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
+	                               u8 *mc_addr_list, u32 mc_addr_count);
+s32  e1000e_set_fc_watermarks(struct e1000_hw *hw);
+s32  e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+s32  e1000e_setup_led_generic(struct e1000_hw *hw);
+s32  e1000e_setup_link(struct e1000_hw *hw);
+
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+void e1000e_clear_vfta_generic(struct e1000_hw *hw);
+void e1000e_config_collision_dist(struct e1000_hw *hw);
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
+void e1000e_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000e_reset_adaptive(struct e1000_hw *hw);
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+void e1000e_update_adaptive(struct e1000_hw *hw);
+void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c
new file mode 100644
index 0000000..e5cb249
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c
@@ -0,0 +1,1265 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  Portions Copyright(c) 2010 Marty Connor <mdc at etherboot.org>
+  Portions Copyright(c) 2010 Entity Cyber, Inc.
+  Portions Copyright(c) 2010 Northrop Grumman Corporation
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000e.h"
+
+static s32 e1000e_get_variants_82571(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	static int global_quad_port_a; /* global port a indication */
+	struct pci_device *pdev = adapter->pdev;
+	u16 eeprom_data = 0;
+	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
+
+	/* tag quad port adapters first, it's used below */
+	switch (pdev->device) {
+	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
+		adapter->flags |= FLAG_IS_QUAD_PORT;
+		/* mark the first port */
+		if (global_quad_port_a == 0)
+			adapter->flags |= FLAG_IS_QUAD_PORT_A;
+		/* Reset for multiple quad port adapters */
+		global_quad_port_a++;
+		if (global_quad_port_a == 4)
+			global_quad_port_a = 0;
+		break;
+	default:
+		break;
+	}
+
+	switch (adapter->hw.mac.type) {
+	case e1000_82571:
+		/* these dual ports don't have WoL on port B at all */
+		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
+		    (is_port_b))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		/* quad ports only support WoL on port A */
+		if (adapter->flags & FLAG_IS_QUAD_PORT &&
+		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		/* Does not support WoL on any port */
+		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
+			adapter->flags &= ~FLAG_HAS_WOL;
+		break;
+
+	case e1000_82573:
+		if (pdev->device == E1000_DEV_ID_82573L) {
+			if (e1000e_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
+					   &eeprom_data) < 0)
+				break;
+			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) {
+				adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
+				adapter->max_hw_frame_size = DEFAULT_JUMBO;
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct e1000_info e1000_82571_info = {
+	.mac			= e1000_82571,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_RESET_OVERWRITES_LAA /* errata */
+				  | FLAG_TARC_SPEED_MODE_BIT /* errata */
+				  | FLAG_APME_CHECK_PORT_B,
+	.pba			= 38,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_82571,
+	.get_variants		= e1000e_get_variants_82571,
+};
+
+static struct e1000_info e1000_82572_info = {
+	.mac			= e1000_82572,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
+	.pba			= 38,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_82571,
+	.get_variants		= e1000e_get_variants_82571,
+};
+
+static struct e1000_info e1000_82573_info = {
+	.mac			= e1000_82573,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_SWSM_ON_LOAD,
+	.pba			= 20,
+	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
+	.init_ops		= e1000e_init_function_pointers_82571,
+	.get_variants		= e1000e_get_variants_82571,
+};
+
+static struct e1000_info e1000_82574_info = {
+	.mac			= e1000_82574,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+#ifdef CONFIG_E1000E_MSIX
+				  | FLAG_HAS_MSIX
+#endif
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_CTRLEXT_ON_LOAD,
+	.pba			= 20,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_82571,
+	.get_variants		= e1000e_get_variants_82571,
+};
+
+static struct e1000_info e1000_82583_info = {
+	.mac			= e1000_82583,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_CTRLEXT_ON_LOAD,
+	.pba			= 20,
+	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
+	.init_ops		= e1000e_init_function_pointers_82571,
+	.get_variants		= e1000e_get_variants_82571,
+};
+
+static struct e1000_info e1000_es2_info = {
+	.mac			= e1000_80003es2lan,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_RX_NEEDS_RESTART /* errata */
+				  | FLAG_TARC_SET_BIT_ZERO /* errata */
+				  | FLAG_APME_CHECK_PORT_B
+				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+	.pba			= 38,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_80003es2lan,
+	.get_variants		= NULL,
+};
+
+static s32 e1000e_get_variants_ich8lan(struct e1000_adapter *adapter)
+{
+	if (adapter->hw.phy.type == e1000_phy_ife) {
+		adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+		adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+	}
+
+	if ((adapter->hw.mac.type == e1000_ich8lan) &&
+	    (adapter->hw.phy.type == e1000_phy_igp_3))
+		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+
+	return 0;
+}
+
+static struct e1000_info e1000_ich8_info = {
+	.mac			= e1000_ich8lan,
+	.flags			= FLAG_HAS_WOL
+				  | FLAG_IS_ICH
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 8,
+	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
+	.init_ops		= e1000e_init_function_pointers_ich8lan,
+	.get_variants		= e1000e_get_variants_ich8lan,
+};
+
+static struct e1000_info e1000_ich9_info = {
+	.mac			= e1000_ich9lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_ich8lan,
+	.get_variants		= e1000e_get_variants_ich8lan,
+};
+
+static struct e1000_info e1000_ich10_info = {
+	.mac			= e1000_ich10lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_ich8lan,
+	.get_variants		= e1000e_get_variants_ich8lan,
+};
+
+static struct e1000_info e1000_pch_info = {
+	.mac			= e1000_pchlan,
+	.flags			= FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+				  | FLAG_APME_IN_WUC,
+	.pba			= 26,
+	.max_hw_frame_size	= 4096,
+	.init_ops		= e1000e_init_function_pointers_ich8lan,
+	.get_variants		= e1000e_get_variants_ich8lan,
+};
+
+static const struct e1000_info *e1000_info_tbl[] = {
+	[board_82571]		= &e1000_82571_info,
+	[board_82572]		= &e1000_82572_info,
+	[board_82573]		= &e1000_82573_info,
+	[board_82574]		= &e1000_82574_info,
+	[board_82583]		= &e1000_82583_info,
+	[board_80003es2lan]	= &e1000_es2_info,
+	[board_ich8lan]		= &e1000_ich8_info,
+	[board_ich9lan]		= &e1000_ich9_info,
+	[board_ich10lan]	= &e1000_ich10_info,
+	[board_pchlan]		= &e1000_pch_info,
+};
+
+/* Low-level support routines */
+
+s32 e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+	u16 cap_offset;
+
+	cap_offset = pci_find_capability(hw->adapter->pdev, PCI_CAP_ID_EXP);
+	if (!cap_offset)
+		return -E1000_ERR_CONFIG;
+
+	pci_read_config_word(hw->adapter->pdev, cap_offset + reg, value);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ * e1000e_irq_disable - Mask off interrupt generation on the NIC
+ **/
+static void e1000e_irq_disable(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	ew32(IMC, ~0);
+	e1e_flush();
+}
+
+/**
+ * e1000e_irq_enable - Enable default interrupt generation settings
+ **/
+static void e1000e_irq_enable(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	ew32(IMS, IMS_ENABLE_MASK);
+	e1e_flush();
+}
+
+/**
+ * e1000_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ **/
+static void e1000e_get_hw_control(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+	u32 swsm;
+
+	/* Let firmware know the driver has taken over */
+	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
+	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+		ctrl_ext = er32(CTRL_EXT);
+		ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+	}
+}
+
+/**
+ * e1000e_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000e_reset ***
+ **/
+void e1000e_power_up_phy(struct e1000_adapter *adapter)
+{
+	if (adapter->hw.phy.ops.power_up)
+		adapter->hw.phy.ops.power_up(&adapter->hw);
+
+	adapter->hw.mac.ops.setup_link(&adapter->hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down the PHY
+ *
+ * Power down the PHY so no link is implied when interface is down.
+ * The PHY cannot be powered down if management or WoL is active.
+ */
+void e1000e_power_down_phy(struct e1000_adapter *adapter)
+{
+	/* WoL is enabled */
+	if (adapter->wol)
+		return;
+
+	if (adapter->hw.phy.ops.power_down)
+		adapter->hw.phy.ops.power_down(&adapter->hw);
+}
+
+/**
+ * e1000e_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for Rx, Tx etc.
+ */
+void e1000e_reset(struct e1000_adapter *adapter)
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_fc_info *fc = &adapter->hw.fc;
+	u32 pba = adapter->pba;
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* Reset Packet Buffer Allocation to default */
+	ew32(PBA, pba);
+
+	hw->fc.requested_mode = e1000_fc_none;
+	fc->current_mode = fc->requested_mode;
+
+	/* Allow time for pending master requests to run */
+	mac->ops.reset_hw(hw);
+
+	/*
+	 * For parts with AMT enabled, let the firmware know
+	 * that the network interface is in control
+	 */
+	if (adapter->flags & FLAG_HAS_AMT)
+		e1000e_get_hw_control(adapter);
+
+	ew32(WUC, 0);
+	if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)
+		e1e_wphy(&adapter->hw, BM_WUC, 0);
+
+	if (mac->ops.init_hw(hw))
+		DBG("Hardware Error\n");
+
+	/* additional part of the flow-control workaround above */
+	if (hw->mac.type == e1000_pchlan)
+		ew32(FCRTV_PCH, 0x1000);
+
+	e1000e_reset_adaptive(hw);
+
+	e1000e_get_phy_info(hw);
+
+	if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) &&
+	    !(adapter->flags & FLAG_SMART_POWER_DOWN)) {
+		u16 phy_data = 0;
+		/*
+		 * speed up time to link by disabling smart power down, ignore
+		 * the return value of this function because there is nothing
+		 * different we would do if it failed
+		 */
+		e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+		phy_data &= ~IGP02E1000_PM_SPD;
+		e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+	}
+}
+
+static int e1000e_sw_init(struct e1000_adapter *adapter)
+{
+	s32 rc;
+
+	/* Set various function pointers */
+	adapter->ei->init_ops(&adapter->hw);
+
+	rc = adapter->hw.mac.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+	rc = adapter->hw.nvm.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+	rc = adapter->hw.phy.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	e1000e_irq_disable(adapter);
+
+	return E1000_SUCCESS;
+}
+
+/* TX support routines */
+
+/**
+ * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int e1000e_setup_tx_resources ( struct e1000_adapter *adapter )
+{
+	DBGP ( "e1000_setup_tx_resources\n" );
+
+	/* Allocate transmit descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata #23
+	   so we use malloc_dma() requesting a 128 byte block that is
+	   128 byte aligned. This should guarantee that the memory
+	   allocated will not cross a 64K boundary, because 128 is an
+	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
+	   allocations of 128 bytes on a 128 byte boundary will not
+	   cross 64K bytes.
+	 */
+
+	adapter->tx_base =
+		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
+
+	if ( ! adapter->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
+
+	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
+
+	return 0;
+}
+
+/**
+ * e1000_process_tx_packets - process transmitted packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void e1000e_process_tx_packets ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t tx_status;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	/* Check status of transmitted packets
+	 */
+	DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
+	      adapter->tx_tail );
+
+	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
+
+		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
+					   ( i * sizeof ( *adapter->tx_base ) );
+
+		tx_status = tx_curr_desc->upper.data;
+
+		DBG ( "	 tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+		DBG ( "	 tx_status = %#08x\n", tx_status );
+
+		/* if the packet at tx_head is not owned by hardware it is for us */
+		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
+			break;
+
+		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
+		      adapter->tx_head, adapter->tx_tail, tx_status );
+
+		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
+				   E1000_TXD_STAT_TU ) ) {
+			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
+			DBG ( "Error transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		} else {
+			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
+			DBG ( "Success transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		}
+
+		/* Decrement count of used descriptors, clear this descriptor
+		 */
+		adapter->tx_fill_ctr--;
+		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
+	}
+}
+
+static void e1000e_free_tx_resources ( struct e1000_adapter *adapter )
+{
+	DBGP ( "e1000_free_tx_resources\n" );
+
+	free_dma ( adapter->tx_base, adapter->tx_ring_size );
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void e1000e_configure_tx ( struct e1000_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tctl, tipg, tarc;
+	u32 ipgr1, ipgr2;
+
+	DBGP ( "e1000_configure_tx\n" );
+
+	/* disable transmits while setting up the descriptors */
+	tctl = E1000_READ_REG ( hw, E1000_TCTL );
+	E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN );
+	e1e_flush();
+	mdelay(10);
+
+	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
+	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
+
+	DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
+	DBG ( "E1000_TDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
+
+	adapter->tx_head = 0;
+	adapter->tx_tail = 0;
+	adapter->tx_fill_ctr = 0;
+
+	/* Set the default values for the Tx Inter Packet Gap timer */
+	tipg = DEFAULT_82543_TIPG_IPGT_COPPER;		/*  8  */
+	ipgr1 = DEFAULT_82543_TIPG_IPGR1;		/*  8  */
+	ipgr2 = DEFAULT_82543_TIPG_IPGR2;		/*  6  */
+
+	if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
+		ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /*  7  */
+
+	tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+	tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
+	ew32(TIPG, tipg);
+
+	/* Program the Transmit Control Register */
+	tctl = er32(TCTL);
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
+		tarc = er32(TARC(0));
+		/*
+		 * set the speed mode bit, we'll clear it if we're not at
+		 * gigabit link later
+		 */
+#define SPEED_MODE_BIT (1 << 21)
+		tarc |= SPEED_MODE_BIT;
+		ew32(TARC(0), tarc);
+	}
+
+	/* errata: program both queues to unweighted RR */
+	if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
+		tarc = er32(TARC(0));
+		tarc |= 1;
+		ew32(TARC(0), tarc);
+		tarc = er32(TARC(1));
+		tarc |= 1;
+		ew32(TARC(1), tarc);
+	}
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+	/* enable Report Status bit */
+	adapter->txd_cmd |= E1000_TXD_CMD_RS;
+
+	/*
+	 * enable transmits in the hardware, need to do this
+	 * after setting TARC(0)
+	 */
+	tctl |= E1000_TCTL_EN;
+	ew32(TCTL, tctl);
+	e1e_flush();
+
+	e1000e_config_collision_dist(hw);
+}
+
+/* RX support routines */
+
+static void e1000e_free_rx_resources ( struct e1000_adapter *adapter )
+{
+	int i;
+
+	DBGP ( "e1000_free_rx_resources\n" );
+
+	free_dma ( adapter->rx_base, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		free_iob ( adapter->rx_iobuf[i] );
+	}
+}
+
+/**
+ * e1000_refill_rx_ring - allocate Rx io_buffers
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int e1000e_refill_rx_ring ( struct e1000_adapter *adapter )
+{
+	int i, rx_curr;
+	int rc = 0;
+	struct e1000_rx_desc *rx_curr_desc;
+	struct e1000_hw *hw = &adapter->hw;
+	struct io_buffer *iob;
+
+	DBGP ("e1000_refill_rx_ring\n");
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
+		rx_curr_desc = adapter->rx_base + rx_curr;
+
+		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
+			continue;
+
+		if ( adapter->rx_iobuf[rx_curr] != NULL )
+			continue;
+
+		DBG2 ( "Refilling rx desc %d\n", rx_curr );
+
+		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+		adapter->rx_iobuf[rx_curr] = iob;
+
+		if ( ! iob ) {
+			DBG ( "alloc_iob failed\n" );
+			rc = -ENOMEM;
+			break;
+		} else {
+			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
+
+			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
+		}
+	}
+	return rc;
+}
+
+/**
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int e1000e_setup_rx_resources ( struct e1000_adapter *adapter )
+{
+	int i, rc = 0;
+
+	DBGP ( "e1000_setup_rx_resources\n" );
+
+	/* Allocate receive descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata
+	 */
+
+	adapter->rx_base =
+		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
+
+	if ( ! adapter->rx_base ) {
+		return -ENOMEM;
+	}
+	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		/* let e1000_refill_rx_ring() io_buffer allocations */
+		adapter->rx_iobuf[i] = NULL;
+	}
+
+	/* allocate io_buffers */
+	rc = e1000e_refill_rx_ring ( adapter );
+	if ( rc < 0 )
+		e1000e_free_rx_resources ( adapter );
+
+	return rc;
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void e1000e_configure_rx ( struct e1000_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl;
+
+	DBGP ( "e1000_configure_rx\n" );
+
+	/* disable receives while setting up the descriptors */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	e1e_flush();
+	mdelay(10);
+
+	adapter->rx_curr = 0;
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+
+	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
+	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
+
+	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
+
+	/* Enable Receives */
+	rctl |=	 E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+		 E1000_RCTL_MPE;
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl );
+	e1e_flush();
+
+	DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
+	DBG ( "E1000_RDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
+	DBG ( "E1000_RCTL:  %#08x\n",  E1000_READ_REG ( hw, E1000_RCTL ) );
+}
+
+/**
+ * e1000_process_rx_packets - process received packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void e1000e_process_rx_packets ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t rx_status;
+	uint32_t rx_len;
+	uint32_t rx_err;
+	struct e1000_rx_desc *rx_curr_desc;
+
+	/* Process received packets
+	 */
+	while ( 1 ) {
+
+		i = adapter->rx_curr;
+
+		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+				  ( i * sizeof ( *adapter->rx_base ) );
+		rx_status = rx_curr_desc->status;
+
+		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
+
+		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+			break;
+
+		if ( adapter->rx_iobuf[i] == NULL )
+			break;
+
+		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
+
+		rx_len = rx_curr_desc->length;
+
+		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
+		      i, rx_status, rx_len );
+
+		rx_err = rx_curr_desc->errors;
+
+		iob_put ( adapter->rx_iobuf[i], rx_len );
+
+		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
+
+			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
+			DBG ( "e1000_poll: Corrupted packet received!"
+			      " rx_err: %#08x\n", rx_err );
+		} else	{
+			/* Add this packet to the receive queue. */
+			netdev_rx ( netdev, adapter->rx_iobuf[i] );
+		}
+		adapter->rx_iobuf[i] = NULL;
+
+		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
+	}
+}
+
+/** Functions that implement the iPXE driver API **/
+
+/**
+ * e1000_close - Disables a network interface
+ *
+ * @v netdev	network interface device structure
+ *
+ **/
+static void e1000e_close ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl;
+
+	DBGP ( "e1000_close\n" );
+
+	/* Disable and acknowledge interrupts */
+	e1000e_irq_disable ( adapter );
+	E1000_READ_REG ( hw, E1000_ICR );
+
+	/* disable receives */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	e1e_flush();
+
+	e1000e_reset ( adapter );
+
+	e1000e_free_tx_resources ( adapter );
+	e1000e_free_rx_resources ( adapter );
+}
+
+/**
+ * e1000_transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ */
+static int e1000e_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct e1000_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t tx_curr = adapter->tx_tail;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	DBGP ("e1000_transmit\n");
+
+	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Save pointer to iobuf we have been given to transmit,
+	   netdev_tx_complete() will need it later
+	 */
+	adapter->tx_iobuf[tx_curr] = iobuf;
+
+	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
+		       ( tx_curr * sizeof ( *adapter->tx_base ) );
+
+	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
+	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+
+	/* Add the packet to TX ring
+	 */
+	tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data );
+	tx_curr_desc->upper.data = 0;
+	tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf );
+
+	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+
+	/* Point to next free descriptor */
+	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
+	adapter->tx_fill_ctr++;
+
+	/* Write new tail to NIC, making packet available for transmit
+	 */
+	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
+	e1e_flush();
+
+	return 0;
+}
+
+/**
+ * e1000_poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void e1000e_poll ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+
+	uint32_t icr;
+
+	DBGP ( "e1000_poll\n" );
+
+	/* Acknowledge interrupts */
+	icr = E1000_READ_REG ( hw, E1000_ICR );
+	if ( ! icr )
+		return;
+
+	DBG ( "e1000_poll: intr_status = %#08x\n", icr );
+
+	e1000e_process_tx_packets ( netdev );
+
+	e1000e_process_rx_packets ( netdev );
+
+	e1000e_refill_rx_ring(adapter);
+}
+
+/**
+ * e1000_irq - enable or Disable interrupts
+ *
+ * @v adapter	e1000 adapter
+ * @v action	requested interrupt action
+ **/
+static void e1000e_irq ( struct net_device *netdev, int enable )
+{
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+
+	DBGP ( "e1000_irq\n" );
+
+	if ( enable ) {
+		e1000e_irq_enable ( adapter );
+	} else {
+		e1000e_irq_disable ( adapter );
+	}
+}
+
+static struct net_device_operations e1000e_operations;
+
+/**
+ * e1000_probe - Initial configuration of e1000 NIC
+ *
+ * @v pci	PCI device
+ * @v id	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+int e1000e_probe ( struct pci_device *pdev )
+{
+	int i, err;
+	struct net_device *netdev;
+	struct e1000_adapter *adapter;
+	unsigned long mmio_start, mmio_len;
+	unsigned long flash_start, flash_len;
+	struct e1000_hw *hw;
+	const struct e1000_info *ei = e1000_info_tbl[pdev->id->driver_data];
+
+	DBGP ( "e1000_probe\n" );
+
+	err = -ENOMEM;
+
+	/* Allocate net device ( also allocates memory for netdev->priv
+	   and makes netdev-priv point to it ) */
+	netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) );
+	if ( ! netdev ) {
+                DBG ( "err_alloc_etherdev\n" );
+		goto err_alloc_etherdev;
+        }
+
+	/* Associate e1000-specific network operations operations with
+	 * generic network device layer */
+	netdev_init ( netdev, &e1000e_operations );
+
+	/* Associate this network device with given PCI device */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Initialize driver private storage */
+	adapter = netdev_priv ( netdev );
+	memset ( adapter, 0, ( sizeof ( *adapter ) ) );
+
+	adapter->pdev	    = pdev;
+
+	adapter->ioaddr	    = pdev->ioaddr;
+	adapter->hw.io_base = pdev->ioaddr;
+
+	hw		    = &adapter->hw;
+	hw->device_id	    = pdev->device;
+
+	adapter->irqno	    = pdev->irq;
+	adapter->netdev	    = netdev;
+	adapter->hw.back    = adapter;
+
+	adapter->ei	    = ei;
+	adapter->pba	    = ei->pba;
+	adapter->flags	    = ei->flags;
+	adapter->flags2	    = ei->flags2;
+
+	adapter->hw.adapter  = adapter;
+	adapter->hw.mac.type = ei->mac;
+	adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
+	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pdev );
+
+	err = -EIO;
+
+	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
+	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
+
+	DBG ( "mmio_start: %#08lx\n", mmio_start );
+	DBG ( "mmio_len: %#08lx\n", mmio_len );
+
+	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
+	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
+
+	if ( ! adapter->hw.hw_addr ) {
+                DBG ( "err_ioremap\n" );
+		goto err_ioremap;
+        }
+
+	/* Flash BAR mapping depends on mac_type */
+	if ( ( adapter->flags & FLAG_HAS_FLASH) && ( pdev->ioaddr ) ) {
+		flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 );
+		flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 );
+		adapter->hw.flash_address = ioremap ( flash_start, flash_len );
+		if ( ! adapter->hw.flash_address ) {
+                        DBG ( "err_flashmap\n" );
+			goto err_flashmap;
+		}
+	}
+
+	/* setup adapter struct */
+	err = e1000e_sw_init ( adapter );
+	if (err) {
+                DBG ( "err_sw_init\n" );
+		goto err_sw_init;
+        }
+
+	if (ei->get_variants) {
+		err = ei->get_variants(adapter);
+		if (err) {
+                        DBG ( "err_hw_initr\n" );
+			goto err_hw_init;
+                }
+	}
+
+	/* Copper options */
+	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+		adapter->hw.phy.mdix = AUTO_ALL_MODES;
+		adapter->hw.phy.disable_polarity_correction = 0;
+		adapter->hw.phy.ms_type = e1000_ms_hw_default;
+	}
+
+	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
+
+	/* Force auto-negotiation */
+	adapter->hw.mac.autoneg = 1;
+	adapter->fc_autoneg = 1;
+	adapter->hw.phy.autoneg_wait_to_complete = true;
+	adapter->hw.mac.adaptive_ifs = true;
+	adapter->hw.fc.requested_mode = e1000_fc_default;
+	adapter->hw.fc.current_mode = e1000_fc_default;
+
+	/*
+	 * before reading the NVM, reset the controller to
+	 * put the device in a known good starting state
+	 */
+	adapter->hw.mac.ops.reset_hw(&adapter->hw);
+
+	/*
+	 * systems with ASPM and others may see the checksum fail on the first
+	 * attempt. Let's give it a few tries
+	 */
+	for (i = 0;; i++) {
+		if (e1000e_validate_nvm_checksum(&adapter->hw) >= 0)
+			break;
+		if (i == 2) {
+			DBG("The NVM Checksum Is Not Valid\n");
+			err = -EIO;
+			goto err_eeprom;
+		}
+	}
+
+	/* copy the MAC address out of the EEPROM */
+	if ( e1000e_read_mac_addr ( &adapter->hw ) )
+		DBG ( "EEPROM Read Error\n" );
+
+	memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
+
+	/* reset the hardware with the new settings */
+	e1000e_reset ( adapter );
+
+	if ( ( err = register_netdev ( netdev ) ) != 0) {
+                DBG ( "err_register\n" );
+		goto err_register;
+        }
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	for (i = 0; i < 6; i++)
+		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
+
+	DBG ( "e1000e_probe succeeded!\n" );
+
+	/* No errors, return success */
+	return 0;
+
+/* Error return paths */
+err_register:
+err_hw_init:
+err_eeprom:
+err_flashmap:
+	if (!e1000e_check_reset_block(&adapter->hw))
+		e1000e_phy_hw_reset(&adapter->hw);
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+err_sw_init:
+	iounmap ( adapter->hw.hw_addr );
+err_ioremap:
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return err;
+}
+
+/**
+ * e1000e_remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+void e1000e_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct e1000_adapter *adapter = netdev_priv ( netdev );
+
+	DBGP ( "e1000e_remove\n" );
+
+	if ( adapter->hw.flash_address )
+		iounmap ( adapter->hw.flash_address );
+	if  ( adapter->hw.hw_addr )
+		iounmap ( adapter->hw.hw_addr );
+
+	unregister_netdev ( netdev );
+	e1000e_reset  ( adapter );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/**
+ * e1000e_open - Called when a network interface is made active
+ *
+ * @v netdev	network interface device structure
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int e1000e_open ( struct net_device *netdev )
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	DBGP ( "e1000e_open\n" );
+
+	/* allocate transmit descriptors */
+	err = e1000e_setup_tx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up TX resources!\n" );
+		goto err_setup_tx;
+	}
+
+	/* allocate receive descriptors */
+	err = e1000e_setup_rx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up RX resources!\n" );
+		goto err_setup_rx;
+	}
+
+	e1000e_configure_tx ( adapter );
+
+	e1000e_configure_rx ( adapter );
+
+	DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
+
+	return 0;
+
+err_setup_rx:
+        DBG ( "err_setup_rx\n" );
+	e1000e_free_tx_resources ( adapter );
+err_setup_tx:
+        DBG ( "err_setup_tx\n" );
+	e1000e_reset ( adapter );
+
+	return err;
+}
+
+/** e1000e net device operations */
+static struct net_device_operations e1000e_operations = {
+	.open		= e1000e_open,
+	.close		= e1000e_close,
+	.transmit	= e1000e_transmit,
+	.poll		= e1000e_poll,
+	.irq		= e1000e_irq,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c
new file mode 100644
index 0000000..e093536
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c
@@ -0,0 +1,372 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#if 0
+
+#include "e1000e.h"
+
+static u8 e1000e_calculate_checksum(u8 *buffer, u32 length);
+
+/**
+ *  e1000e_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+static u8 e1000e_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8  sum = 0;
+
+	if (!buffer)
+		return 0;
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  e1000e_mng_enable_host_if_generic - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 e1000e_mng_enable_host_if_generic(struct e1000_hw *hw)
+{
+	u32 hicr;
+	s32 ret_val = E1000_SUCCESS;
+	u8  i;
+
+	/* Check that the host interface is enabled. */
+	hicr = er32(HICR);
+	if ((hicr & E1000_HICR_EN) == 0) {
+		e_dbg("E1000_HOST_EN bit disabled.\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+	/* check the previous command is completed */
+	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+		hicr = er32(HICR);
+		if (!(hicr & E1000_HICR_C))
+			break;
+		mdelay(1);
+	}
+
+	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+		e_dbg("Previous command timeout failed .\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_mng_mode_generic - Generic check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the firmware semaphore register and returns true (>0) if
+ *  manageability is enabled, else false (0).
+ **/
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = er32(FWSM);
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
+ *  e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ **/
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+	u32 *buffer = (u32 *)&hw->mng_cookie;
+	u32 offset;
+	s32 ret_val, hdr_csum, csum;
+	u8 i, len;
+	bool tx_filter = true;
+
+	/* No manageability, no filtering */
+	if (!hw->mac.ops.check_mng_mode(hw)) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/*
+	 * If we can't read from the host interface for whatever
+	 * reason, disable filtering.
+	 */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val != E1000_SUCCESS) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/* Read in the header.  Length and offset are in dwords. */
+	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+	for (i = 0; i < len; i++) {
+		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
+		                                           E1000_HOST_IF,
+		                                           offset + i);
+	}
+	hdr_csum = hdr->checksum;
+	hdr->checksum = 0;
+	csum = e1000e_calculate_checksum((u8 *)hdr,
+	                                E1000_MNG_DHCP_COOKIE_LENGTH);
+	/*
+	 * If either the checksums or signature don't match, then
+	 * the cookie area isn't considered valid, in which case we
+	 * take the safe route of assuming Tx filtering is enabled.
+	 */
+	if (hdr_csum != csum)
+		goto out;
+	if (hdr->signature != E1000_IAMT_SIGNATURE)
+		goto out;
+
+	/* Cookie area is valid, make the final check for filtering. */
+	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
+		tx_filter = false;
+
+out:
+	hw->mac.tx_pkt_filtering = tx_filter;
+	return tx_filter;
+}
+
+/**
+ *  e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer,
+                                      u16 length)
+{
+	struct e1000_host_mng_command_header hdr;
+	s32 ret_val;
+	u32 hicr;
+
+	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+	hdr.command_length = length;
+	hdr.reserved1 = 0;
+	hdr.reserved2 = 0;
+	hdr.checksum = 0;
+
+	/* Enable the host interface */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val)
+		goto out;
+
+	/* Populate the host interface with the contents of "buffer". */
+	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+	                                  sizeof(hdr), &(hdr.checksum));
+	if (ret_val)
+		goto out;
+
+	/* Write the manageability command header */
+	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+	if (ret_val)
+		goto out;
+
+	/* Tell the ARC a new command is pending. */
+	hicr = er32(HICR);
+	ew32(HICR, hicr | E1000_HICR_C);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_mng_write_cmd_header_generic - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr)
+{
+	u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+	/* Write the whole command header structure with new checksum. */
+
+	hdr->checksum = e1000e_calculate_checksum((u8 *)hdr, length);
+
+	length >>= 2;
+	/* Write the relevant command block into the ram area. */
+	for (i = 0; i < length; i++) {
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+		                            *((u32 *) hdr + i));
+		e1e_flush();
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_mng_host_if_write_generic - Write to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                    u16 length, u16 offset, u8 *sum)
+{
+	u8 *tmp;
+	u8 *bufptr = buffer;
+	u32 data = 0;
+	s32 ret_val = E1000_SUCCESS;
+	u16 remaining, i, j, prev_bytes;
+
+	/* sum = only sum of the data and it is not checksum */
+
+	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	tmp = (u8 *)&data;
+	prev_bytes = offset & 0x3;
+	offset >>= 2;
+
+	if (prev_bytes) {
+		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+		for (j = prev_bytes; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+		length -= j - prev_bytes;
+		offset++;
+	}
+
+	remaining = length & 0x3;
+	length -= remaining;
+
+	/* Calculate length in DWORDs */
+	length >>= 2;
+
+	/*
+	 * The device driver writes the relevant command block into the
+	 * ram area.
+	 */
+	for (i = 0; i < length; i++) {
+		for (j = 0; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+		                            data);
+	}
+	if (remaining) {
+		for (j = 0; j < sizeof(u32); j++) {
+			if (j < remaining)
+				*(tmp + j) = *bufptr++;
+			else
+				*(tmp + j) = 0;
+
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = false;
+
+	if (!hw->mac.asf_firmware_present)
+		goto out;
+
+	manc = er32(MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		goto out;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = er32(FWSM);
+		factps = er32(FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = true;
+			goto out;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = true;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h
new file mode 100644
index 0000000..f136aee
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_MANAGE_H_
+#define _E1000E_MANAGE_H_
+
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+s32  e1000e_mng_enable_host_if_generic(struct e1000_hw *hw);
+s32  e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                     u16 length, u16 offset, u8 *sum);
+s32  e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr);
+#if 0
+s32  e1000e_mng_write_dhcp_info(struct e1000_hw *hw,
+                                       u8 *buffer, u16 length);
+#endif
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE                  0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_VFTA_ENTRY_SHIFT               5
+#define E1000_VFTA_ENTRY_MASK                0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+#define E1000_HICR_SV              0x04  /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET        0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE  0x544D4149
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c
new file mode 100644
index 0000000..f49d421
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c
@@ -0,0 +1,596 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000e.h"
+
+static void e1000e_stop_nvm(struct e1000_hw *hw);
+static void e1000e_reload_nvm(struct e1000_hw *hw);
+
+/**
+ *  e1000e_init_nvm_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000e_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	/* Initialize function pointers */
+	nvm->ops.reload = e1000e_reload_nvm;
+}
+
+/**
+ *  e1000e_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000e_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	ew32(EECD, *eecd);
+	e1e_flush();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000e_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000e_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	ew32(EECD, *eecd);
+	e1e_flush();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000e_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000e_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u32 mask;
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		ew32(EECD, eecd);
+		e1e_flush();
+
+		udelay(nvm->delay_usec);
+
+		e1000e_raise_eec_clk(hw, &eecd);
+		e1000e_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	ew32(EECD, eecd);
+}
+
+/**
+ *  e1000e_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 e1000e_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	eecd = er32(EECD);
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		e1000e_raise_eec_clk(hw, &eecd);
+
+		eecd = er32(EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		e1000e_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = er32(EERD);
+		else
+			reg = er32(EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE) {
+			ret_val = E1000_SUCCESS;
+			break;
+		}
+
+		udelay(5);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_acquire_nvm - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000e_acquire_nvm(struct e1000_hw *hw)
+{
+	u32 eecd = er32(EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+	s32 ret_val = E1000_SUCCESS;
+
+	ew32(EECD, eecd | E1000_EECD_REQ);
+	eecd = er32(EECD);
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		udelay(5);
+		eecd = er32(EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		ew32(EECD, eecd);
+		e_dbg("Could not acquire NVM grant\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void e1000e_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		ew32(EECD, eecd);
+		e1e_flush();
+		udelay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		ew32(EECD, eecd);
+		e1e_flush();
+		udelay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  e1000e_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000e_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	eecd = er32(EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		e1000e_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  e1000e_release_nvm - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000e_release_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	e1000e_stop_nvm(hw);
+
+	eecd = er32(EECD);
+	eecd &= ~E1000_EECD_REQ;
+	ew32(EECD, eecd);
+}
+
+/**
+ *  e1000e_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000e_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	s32 ret_val = E1000_SUCCESS;
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		ew32(EECD, eecd);
+		udelay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/*
+		 * Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out.
+		 */
+		while (timeout) {
+			e1000e_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+			                         hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)e1000e_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			udelay(5);
+			e1000e_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			e_dbg("SPI NVM Status error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * too many words for the offset, and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		e_dbg("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		ew32(EERD, eerd);
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (er32(EERD) >>
+		           E1000_NVM_RW_REG_DATA);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		e_dbg("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = e1000e_ready_nvm_eeprom(hw);
+		if (ret_val)
+			goto release;
+
+		e1000e_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		e1000e_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+		                         nvm->opcode_bits);
+
+		e1000e_standby_nvm(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		e1000e_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		e1000e_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+		                         nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			e1000e_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				e1000e_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msleep(10);
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_pba_num - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ **/
+s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
+{
+	s32  ret_val;
+	u16 nvm_data;
+
+	ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num = (u32)(nvm_data << 16);
+
+	ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		e_dbg("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num |= nvm_data;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_mac_addr_generic - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 e1000e_read_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
+
+	rar_high = er32(RAH(0));
+	rar_low = er32(RAL(0));
+
+	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
+
+	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			e_dbg("NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		e_dbg("NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_update_nvm_checksum_generic - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32  ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			e_dbg("NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = e1000e_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val)
+		e_dbg("NVM Write Error while updating checksum.\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_reload_nvm - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+static void e1000e_reload_nvm(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+
+	udelay(10);
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h
new file mode 100644
index 0000000..1a8e0f3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h
@@ -0,0 +1,53 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_NVM_H_
+#define _E1000E_NVM_H_
+
+void e1000e_init_nvm_ops_generic(struct e1000_hw *hw);
+s32  e1000e_acquire_nvm(struct e1000_hw *hw);
+
+s32  e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32  e1000e_read_mac_addr_generic(struct e1000_hw *hw);
+s32  e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
+s32  e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+s32  e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32  e1000e_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
+                          u16 words, u16 *data);
+s32  e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000e_release_nvm(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE  0xDB00
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c
new file mode 100644
index 0000000..337be73
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c
@@ -0,0 +1,3323 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "e1000e.h"
+
+static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw);
+static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw);
+static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg);
+static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read);
+static u32 e1000e_get_phy_addr_for_hv_page(u32 page);
+static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read);
+#if 0
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_m88_cable_length_table) / \
+                 sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_igp_2_cable_length_table) / \
+                 sizeof(e1000_igp_2_cable_length_table[0]))
+#endif
+
+/**
+ *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	manc = er32(MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 e1000e_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id;
+	u16 retry_count = 0;
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+	while (retry_count < 2) {
+		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		udelay(20);
+		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+		if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
+			goto out;
+
+		/*
+		 * If the PHY ID is still unknown, we may have an 82577
+		 * without link.  We will try again after setting Slow MDIC
+		 * mode. No harm in trying again in this case since the PHY
+		 * ID is unknown at this point anyway.
+		 */
+		ret_val = phy->ops.acquire(hw);
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+		phy->ops.release(hw);
+
+		retry_count++;
+	}
+out:
+	/* Revert to MDIO fast mode, if applicable */
+	if (retry_count) {
+		ret_val = phy->ops.acquire(hw);
+		if (ret_val)
+			return ret_val;
+		ret_val = e1000e_set_mdio_slow_mode_hv(hw, false);
+		phy->ops.release(hw);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_reset_dsp - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control register in the PHY at offset and stores the
+ *  information read to data.
+ **/
+s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_READ));
+
+	ew32(MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		udelay(50);
+		mdic = er32(MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		e_dbg("MDI Read did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		e_dbg("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+	        (offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_WRITE));
+
+	ew32(MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		udelay(50);
+		mdic = er32(MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		e_dbg("MDI Write did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		e_dbg("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_m88 - Read m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_m88 - Write m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  __e1000e_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and stores the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+static s32 __e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
+                                    bool locked)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore then reads the PHY register at offset and stores the
+ *  retrieved information in data.
+ *  Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_read_phy_reg_igp_locked - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset and stores the retrieved information
+ *  in data.  Assumes semaphore already acquired.
+ **/
+s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
+ *  e1000e_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
+                                     bool locked)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_write_phy_reg_igp_locked - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset.
+ *  Assumes semaphore already acquired.
+ **/
+s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
+ *  __e1000e_read_kmrn_reg - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release any acquired semaphores before exiting.
+ **/
+static s32 __e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
+                                 bool locked)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	kmrnctrlsta = er32(KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_kmrn_reg -  Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore then reads the PHY register at offset using the
+ *  kumeran interface.  The information retrieved is stored in data.
+ *  Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_read_kmrn_reg_locked -  Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset using the kumeran interface.  The
+ *  information retrieved is stored in data.
+ *  Assumes semaphore already acquired.
+ **/
+s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_kmrn_reg(hw, offset, data, true);
+}
+
+/**
+ *  __e1000e_write_kmrn_reg - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary.  Then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release any acquired semaphores
+ *  before exiting.
+ **/
+static s32 __e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
+                                  bool locked)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_kmrn_reg -  Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore then writes the data to the PHY register at the offset
+ *  using the kumeran interface.  Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_write_kmrn_reg_locked -  Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Write the data to PHY register at the offset using the kumeran interface.
+ *  Assumes semaphore already acquired.
+ **/
+s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_kmrn_reg(hw, offset, data, true);
+}
+
+/**
+ *  e1000e_copper_link_setup_82577 - Setup 82577 PHY for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up Carrier-sense on Transmit and downshift values.
+ **/
+s32 e1000e_copper_link_setup_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+
+	/* Enable downshift */
+	phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
+
+	ret_val = e1e_wphy(hw, I82577_CFG_REG, phy_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/* For BM PHY this bit is downshift enable */
+	if (phy->type != e1000_phy_bm)
+		phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/*
+	 * Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+
+	/*
+	 * Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	/* Enable downshift on BM (disabled by default) */
+	if (phy->type == e1000_phy_bm)
+		phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	if ((phy->type == e1000_phy_m88) &&
+	    (phy->revision < E1000_REVISION_4) &&
+	    (phy->id != BME1000_E_PHY_ID_R2)) {
+		/*
+		 * Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == E1000_REVISION_2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+		/* Set PHY page 0, register 29 to 0x0003 */
+		ret_val = e1e_wphy(hw, 29, 0x0003);
+		if (ret_val)
+			goto out;
+
+		/* Set PHY page 0, register 30 to 0x0000 */
+		ret_val = e1e_wphy(hw, 30, 0x0000);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Commit the changes. */
+	ret_val = e1000e_commit_phy(hw);
+	if (ret_val) {
+		e_dbg("Error committing the PHY changes\n");
+		goto out;
+	}
+
+	if (phy->type == e1000_phy_82578) {
+		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                            &phy_data);
+		if (ret_val)
+			goto out;
+
+		/* 82578 PHY - set the downshift count to 1x. */
+		phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
+		phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
+		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = e1000e_phy_hw_reset(hw);
+	if (ret_val) {
+		e_dbg("Error resetting the PHY.\n");
+		goto out;
+	}
+
+	/*
+	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+	 * timeout issues when LFS is enabled.
+	 */
+	msleep(100);
+
+	/*
+	 * The NVM settings will configure LPLU in D3 for
+	 * non-IGP1 PHYs.
+	 */
+	if (phy->type == e1000_phy_igp) {
+		/* disable lplu d3 during driver init */
+		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+		if (ret_val) {
+			e_dbg("Error Disabling LPLU D3\n");
+			goto out;
+		}
+	}
+
+	/* disable lplu d0 during driver init */
+	if (hw->phy.ops.set_d0_lplu_state) {
+		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+		if (ret_val) {
+			e_dbg("Error Disabling LPLU D0\n");
+			goto out;
+		}
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		goto out;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/*
+		 * when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default.
+		 */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = e1e_rphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+			if (ret_val)
+				goto out;
+		}
+
+		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	/*
+	 * Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/*
+	 * If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	e_dbg("Reconfiguring auto-neg advertisement params\n");
+	ret_val = e1000e_phy_setup_autoneg(hw);
+	if (ret_val) {
+		e_dbg("Error Setting up Auto-Negotiation\n");
+		goto out;
+	}
+	e_dbg("Restarting Auto-Neg\n");
+
+	/*
+	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->autoneg_wait_to_complete) {
+		ret_val = hw->mac.ops.wait_autoneg(hw);
+		if (ret_val) {
+			e_dbg("Error while waiting for "
+			         "autoneg to complete\n");
+			goto out;
+		}
+	}
+
+	hw->mac.get_link_status = true;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = e1e_rphy(hw, PHY_1000T_CTRL,
+		                            &mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+	                         NWAY_AR_100TX_HD_CAPS |
+	                         NWAY_AR_10T_FD_CAPS   |
+	                         NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	e_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		e_dbg("Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		e_dbg("Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		e_dbg("Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		e_dbg("Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+		e_dbg("Advertise 1000mb Half duplex request denied!\n");
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		e_dbg("Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/*
+		 * Flow control (Rx & Tx) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled, and Tx Flow control is
+		 * disabled, by a software over-ride.
+		 *
+		 * Since there really isn't a way to advertise that we are
+		 * capable of Rx Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric Rx PAUSE.  Later
+		 * (in e1000e_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		e_dbg("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = e1e_wphy(hw,
+		                              PHY_1000T_CTRL,
+		                              mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_copper_link - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_setup_copper_link(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	bool link;
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement and perform
+		 * autonegotiation.
+		 */
+		ret_val = e1000e_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+#if 0
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+		e_dbg("Forcing Speed and Duplex\n");
+		ret_val = hw->phy.ops.force_speed_duplex(hw);
+		if (ret_val) {
+			e_dbg("Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+#endif
+	}
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw,
+	                                     COPPER_LINK_UP_LIMIT,
+	                                     10,
+	                                     &link);
+	if (ret_val)
+		goto out;
+
+	if (link) {
+		e_dbg("Valid link established!!!\n");
+		e1000e_config_collision_dist(hw);
+		ret_val = e1000e_config_fc_after_link_up(hw);
+	} else {
+		e_dbg("Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	e_dbg("IGP PSCR: %X\n", phy_data);
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			e_dbg("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	e_dbg("M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/* Reset the phy to commit changes. */
+	ret_val = e1000e_commit_phy(hw);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = e1e_wphy(hw,
+			                              M88E1000_PHY_PAGE_SELECT,
+			                              0x001d);
+			if (ret_val)
+				goto out;
+			ret_val = e1000e_phy_reset_dsp(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+s32 e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+		goto out;
+	}
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	e_dbg("IFE PMC: %X\n", data);
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			e_dbg("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	/* Turn off flow control when forcing speed/duplex */
+	hw->fc.current_mode = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = er32(CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		e_dbg("Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		e_dbg("Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		e_dbg("Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		e_dbg("Forcing 10mb\n");
+	}
+
+	e1000e_config_collision_dist(hw);
+
+	ew32(CTRL, ctrl);
+}
+#endif
+
+/**
+ *  e1000e_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                              data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_downshift - Checks whether a downshift in speed occurred
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000e_check_downshift(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+	case e1000_phy_bm:
+	case e1000_phy_82578:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = false;
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 e1000e_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+s32 e1000e_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	/*
+	 * Polarity is determined based on the speed of
+	 * our connection.
+	 */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/*
+		 * This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_polarity_ife - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reversal feature being enabled.
+ **/
+s32 e1000e_check_polarity_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	/*
+	 * Polarity is determined based on the reversal feature being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask = IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset = IFE_PHY_SPECIAL_CONTROL;
+		mask = IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+		                       ? e1000_rev_polarity_reversed
+		                       : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_wait_autoneg - Wait for auto-neg completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+s32 e1000e_wait_autoneg(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msleep(100);
+	}
+
+	/*
+	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_has_link_generic - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                               u32 usec_interval, bool *success)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	for (i = 0; i < iterations; i++) {
+		/*
+		 * Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val) {
+			/*
+			 * If the first read fails, another entity may have
+			 * ownership of the resources, wait and try again to
+			 * see if they have relinquished the resources yet.
+			 */
+			udelay(usec_interval);
+		}
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			mdelay(usec_interval/1000);
+		else
+			udelay(usec_interval);
+	}
+
+	*success = (i < iterations) ? true : false;
+
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which represent the
+ *  combination of coarse and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+	                                                 {IGP02E1000_PHY_AGC_A,
+	                                                  IGP02E1000_PHY_AGC_B,
+	                                                  IGP02E1000_PHY_AGC_C,
+	                                                  IGP02E1000_PHY_AGC_D};
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Getting bits 15:9, which represent the combination of
+		 * coarse and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length.
+		 */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+		                IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+	              e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000e_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	if (phy->media_type != e1000_media_type_copper) {
+		e_dbg("Phy info is only valid for copper media\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		e_dbg("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+	                           ? true : false;
+
+	ret_val = e1000e_check_polarity_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+#if 0
+		ret_val = e1000e_get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+#endif
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		e_dbg("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = e1000e_check_polarity_igp(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+#if 0
+		ret_val = phy->ops.get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+#endif
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_sw_reset - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_ctrl;
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	udelay(1);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_hw_reset_generic - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and release the semaphore (if necessary).
+ **/
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+
+	ret_val = e1000e_check_reset_block(hw);
+	if (ret_val) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ctrl = er32(CTRL);
+	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
+	e1e_flush();
+
+	udelay(phy->reset_delay_us);
+
+	ew32(CTRL, ctrl);
+	e1e_flush();
+
+	udelay(150);
+
+	phy->ops.release(hw);
+
+	ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_cfg_done - Generic configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Generic function to wait 10 milli-seconds for configuration to complete
+ *  and return success.
+ **/
+s32 e1000e_get_cfg_done(struct e1000_hw *hw __unused)
+{
+	mdelay(10);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	e_dbg("Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	e1e_wphy(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	e1e_wphy(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	e1e_wphy(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	e1e_wphy(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to Tx amplitude in Gig mode */
+	e1e_wphy(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	e1e_wphy(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	e1e_wphy(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	e1e_wphy(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	e1e_wphy(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	e1e_wphy(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	e1e_wphy(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	e1e_wphy(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	e1e_wphy(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	e1e_wphy(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	e1e_wphy(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	e1e_wphy(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	e1e_wphy(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	e1e_wphy(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	e1e_wphy(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	e1e_wphy(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	e1e_wphy(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	e1e_wphy(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	e1e_wphy(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	e1e_wphy(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	e1e_wphy(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	e1e_wphy(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	e1e_wphy(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	e1e_wphy(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	e1e_wphy(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	e1e_wphy(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	e1e_wphy(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	e1e_wphy(hw, 0x0000, 0x1340);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000e_get_phy_type_from_id - Get PHY type from id
+ *  @phy_id: phy_id read from the phy
+ *
+ *  Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
+{
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	switch (phy_id)	{
+	case M88E1000_I_PHY_ID:
+	case M88E1000_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+	case M88E1011_I_PHY_ID:
+		phy_type = e1000_phy_m88;
+		break;
+	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+		phy_type = e1000_phy_igp_2;
+		break;
+	case GG82563_E_PHY_ID:
+		phy_type = e1000_phy_gg82563;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy_type = e1000_phy_igp_3;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy_type = e1000_phy_ife;
+		break;
+	case BME1000_E_PHY_ID:
+	case BME1000_E_PHY_ID_R2:
+		phy_type = e1000_phy_bm;
+		break;
+	case I82578_E_PHY_ID:
+		phy_type = e1000_phy_82578;
+		break;
+	case I82577_E_PHY_ID:
+		phy_type = e1000_phy_82577;
+		break;
+	default:
+		phy_type = e1000_phy_unknown;
+		break;
+	}
+	return phy_type;
+}
+
+/**
+ *  e1000e_determine_phy_address - Determines PHY address.
+ *  @hw: pointer to the HW structure
+ *
+ *  This uses a trial and error method to loop through possible PHY
+ *  addresses. It tests each by reading the PHY ID registers and
+ *  checking for a match.
+ **/
+s32 e1000e_determine_phy_address(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+	u32 phy_addr = 0;
+	u32 i;
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	hw->phy.id = phy_type;
+
+	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+		hw->phy.addr = phy_addr;
+		i = 0;
+
+		do {
+			e1000e_get_phy_id(hw);
+			phy_type = e1000e_get_phy_type_from_id(hw->phy.id);
+
+			/*
+			 * If phy_type is valid, break - we found our
+			 * PHY address
+			 */
+			if (phy_type  != e1000_phy_unknown) {
+				ret_val = E1000_SUCCESS;
+				goto out;
+			}
+			msleep(1);
+			i++;
+		} while (i < 10);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_addr_for_bm_page - Retrieve PHY page address
+ *  @page: page to access
+ *
+ *  Returns the phy address for the page requested.
+ **/
+static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg)
+{
+	u32 phy_addr = 2;
+
+	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
+		phy_addr = 1;
+
+	return phy_addr;
+}
+
+/**
+ *  e1000e_write_phy_reg_bm - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u32 page_select = 0;
+	u32 page = offset >> IGP_PAGE_SHIFT;
+	u32 page_shift = 0;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data,
+		                                         false);
+		goto out;
+	}
+
+	hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset);
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/*
+		 * Page select is register 31 for phy address 1 and 22 for
+		 * phy address 2 and 3. Page select is shifted only for
+		 * phy address 1.
+		 */
+		if (hw->phy.addr == 1) {
+			page_shift = IGP_PAGE_SHIFT;
+			page_select = IGP01E1000_PHY_PAGE_SELECT;
+		} else {
+			page_shift = 0;
+			page_select = BM_PHY_PAGE_SELECT;
+		}
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
+		                                   (page << page_shift));
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+out:
+	hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_bm - Read BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u32 page_select = 0;
+	u32 page = offset >> IGP_PAGE_SHIFT;
+	u32 page_shift = 0;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data,
+		                                         true);
+		goto out;
+	}
+
+	hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset);
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/*
+		 * Page select is register 31 for phy address 1 and 22 for
+		 * phy address 2 and 3. Page select is shifted only for
+		 * phy address 1.
+		 */
+		if (hw->phy.addr == 1) {
+			page_shift = IGP_PAGE_SHIFT;
+			page_select = IGP01E1000_PHY_PAGE_SELECT;
+		} else {
+			page_shift = 0;
+			page_select = BM_PHY_PAGE_SELECT;
+		}
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
+		                                   (page << page_shift));
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+out:
+	hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_bm2 - Read BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data,
+		                                         true);
+		goto out;
+	}
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+		                                   page);
+
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+out:
+	hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_bm2 - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data,
+		                                         false);
+		goto out;
+	}
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+		                                   page);
+
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+out:
+	hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ *  e1000e_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read or written
+ *  @data: pointer to the data to read or write
+ *  @read: determines if operation is read or write
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting. Note that procedure to read the wakeup
+ *  registers are different. It works as such:
+ *  1) Set page 769, register 17, bit 2 = 1
+ *  2) Set page to 800 for host (801 if we were manageability)
+ *  3) Write the address using the address opcode (0x11)
+ *  4) Read or write the data using the data opcode (0x12)
+ *  5) Restore 769_17.2 to its original value
+ *
+ *  Assumes semaphore already acquired.
+ **/
+static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read)
+{
+	s32 ret_val;
+	u16 reg = BM_PHY_REG_NUM(offset);
+	u16 phy_reg = 0;
+
+	/* Gig must be disabled for MDIO accesses to page 800 */
+	if ((hw->mac.type == e1000_pchlan) &&
+	   (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
+		e_dbg("Attempting to access page 800 while gig enabled.\n");
+
+	/* All operations in this function are phy address 1 */
+	hw->phy.addr = 1;
+
+	/* Set page 769 */
+	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+	if (ret_val) {
+		e_dbg("Could not read PHY page 769\n");
+		goto out;
+	}
+
+	/* First clear bit 4 to avoid a power state change */
+	phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+	if (ret_val) {
+		e_dbg("Could not clear PHY page 769 bit 4\n");
+		goto out;
+	}
+
+	/* Write bit 2 = 1, and clear bit 4 to 769_17 */
+	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
+	                                   phy_reg | BM_WUC_ENABLE_BIT);
+	if (ret_val) {
+		e_dbg("Could not write PHY page 769 bit 2\n");
+		goto out;
+	}
+
+	/* Select page 800 */
+	ret_val = e1000e_write_phy_reg_mdic(hw,
+	                                   IGP01E1000_PHY_PAGE_SELECT,
+	                                   (BM_WUC_PAGE << IGP_PAGE_SHIFT));
+
+	/* Write the page 800 offset value using opcode 0x11 */
+	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
+	if (ret_val) {
+		e_dbg("Could not write address opcode to page 800\n");
+		goto out;
+	}
+
+	if (read) {
+	        /* Read the page 800 value using opcode 0x12 */
+		ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+		                                  data);
+	} else {
+	        /* Write the page 800 value using opcode 0x12 */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+		                                   *data);
+	}
+
+	if (ret_val) {
+		e_dbg("Could not access data value from page 800\n");
+		goto out;
+	}
+
+	/*
+	 * Restore 769_17.2 to its original value
+	 * Set page 769
+	 */
+	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+	/* Clear 769_17.2 */
+	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+	if (ret_val) {
+		e_dbg("Could not clear PHY page 769 bit 2\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * e1000e_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000e_power_up_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+	mii_reg &= ~MII_CR_POWER_DOWN;
+	e1e_wphy(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000e_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000e_power_down_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+	mii_reg |= MII_CR_POWER_DOWN;
+	e1e_wphy(hw, PHY_CONTROL, mii_reg);
+	msleep(1);
+}
+
+/**
+ *  e1000e_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ *  @hw:   pointer to the HW structure
+ *  @slow: true for slow mode, false for normal mode
+ *
+ *  Assumes semaphore already acquired.
+ **/
+s32 e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data = 0;
+
+	/* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
+	hw->phy.addr = 1;
+	ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+				         (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1,
+	                                   (0x2180 | (slow << 10)));
+	if (ret_val)
+		goto out;
+
+	/* dummy read when reverting to fast mode - throw away result */
+	if (!slow)
+		ret_val = e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  __e1000e_read_phy_reg_hv -  Read HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and stores the retrieved information in data.  Release any acquired
+ *  semaphore before exiting.
+ **/
+static s32 __e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
+                                   bool locked)
+{
+	s32 ret_val;
+	u16 page = BM_PHY_REG_PAGE(offset);
+	u16 reg = BM_PHY_REG_NUM(offset);
+	bool in_slow_mode = false;
+
+	if (!locked) {
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Workaround failure in MDIO access while cable is disconnected */
+	if ((hw->phy.type == e1000_phy_82577) &&
+	    !(er32(STATUS) & E1000_STATUS_LU)) {
+		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+
+		in_slow_mode = true;
+	}
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset,
+		                                         data, true);
+		goto out;
+	}
+
+	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+		ret_val = e1000e_access_phy_debug_regs_hv(hw, offset,
+		                                         data, true);
+		goto out;
+	}
+
+	hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page);
+
+	if (page == HV_INTC_FC_PAGE_START)
+		page = 0;
+
+	if (reg > MAX_PHY_MULTI_PAGE_REG) {
+		u32 phy_addr = hw->phy.addr;
+
+		hw->phy.addr = 1;
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+					     IGP01E1000_PHY_PAGE_SELECT,
+					     (page << IGP_PAGE_SHIFT));
+		hw->phy.addr = phy_addr;
+
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+	                                  data);
+out:
+	/* Revert to MDIO fast mode, if applicable */
+	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+		ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false);
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_hv -  Read HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore then reads the PHY register at offset and stores
+ *  the retrieved information in data.  Release the acquired semaphore
+ *  before exiting.
+ **/
+s32 e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_phy_reg_hv(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_read_phy_reg_hv_locked -  Read HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset and stores the retrieved information
+ *  in data.  Assumes semaphore already acquired.
+ **/
+s32 e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __e1000e_read_phy_reg_hv(hw, offset, data, true);
+}
+
+/**
+ *  __e1000e_write_phy_reg_hv - Write HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+static s32 __e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
+                                    bool locked)
+{
+	s32 ret_val;
+	u16 page = BM_PHY_REG_PAGE(offset);
+	u16 reg = BM_PHY_REG_NUM(offset);
+	bool in_slow_mode = false;
+
+	if (!locked) {
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Workaround failure in MDIO access while cable is disconnected */
+	if ((hw->phy.type == e1000_phy_82577) &&
+	    !(er32(STATUS) & E1000_STATUS_LU)) {
+		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+
+		in_slow_mode = true;
+	}
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset,
+		                                         &data, false);
+		goto out;
+	}
+
+	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+		ret_val = e1000e_access_phy_debug_regs_hv(hw, offset,
+		                                         &data, false);
+		goto out;
+	}
+
+	hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page);
+
+	if (page == HV_INTC_FC_PAGE_START)
+		page = 0;
+
+	/*
+	 * Workaround MDIO accesses being disabled after entering IEEE Power
+	 * Down (whenever bit 11 of the PHY Control register is set)
+	 */
+	if ((hw->phy.type == e1000_phy_82578) &&
+	    (hw->phy.revision >= 1) &&
+	    (hw->phy.addr == 2) &&
+	    ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+	    (data & (1 << 11))) {
+		u16 data2 = 0x7EFF;
+		ret_val = e1000e_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+		                                         &data2, false);
+		if (ret_val)
+			goto out;
+	}
+
+	if (reg > MAX_PHY_MULTI_PAGE_REG) {
+		u32 phy_addr = hw->phy.addr;
+
+		hw->phy.addr = 1;
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+					     IGP01E1000_PHY_PAGE_SELECT,
+					     (page << IGP_PAGE_SHIFT));
+		hw->phy.addr = phy_addr;
+
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+	                                  data);
+
+out:
+	/* Revert to MDIO fast mode, if applicable */
+	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+		ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false);
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_hv - Write HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore then writes the data to PHY register at the offset.
+ *  Release the acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_phy_reg_hv(hw, offset, data, false);
+}
+
+/**
+ *  e1000e_write_phy_reg_hv_locked - Write HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset.  Assumes semaphore
+ *  already acquired.
+ **/
+s32 e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __e1000e_write_phy_reg_hv(hw, offset, data, true);
+}
+
+/**
+ *  e1000e_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ *  @page: page to be accessed
+ **/
+static u32 e1000e_get_phy_addr_for_hv_page(u32 page)
+{
+	u32 phy_addr = 2;
+
+	if (page >= HV_INTC_FC_PAGE_START)
+		phy_addr = 1;
+
+	return phy_addr;
+}
+
+/**
+ *  e1000e_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read or written
+ *  @data: pointer to the data to be read or written
+ *  @read: determines if operation is read or written
+ *
+ *  Reads the PHY register at offset and stores the retreived information
+ *  in data.  Assumes semaphore already acquired.  Note that the procedure
+ *  to read these regs uses the address port and data port to read/write.
+ **/
+static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read)
+{
+	s32 ret_val;
+	u32 addr_reg = 0;
+	u32 data_reg = 0;
+
+	/* This takes care of the difference with desktop vs mobile phy */
+	addr_reg = (hw->phy.type == e1000_phy_82578) ?
+	           I82578_ADDR_REG : I82577_ADDR_REG;
+	data_reg = addr_reg + 1;
+
+	/* All operations in this function are phy address 2 */
+	hw->phy.addr = 2;
+
+	/* masking with 0x3F to remove the page from offset */
+	ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
+	if (ret_val) {
+		e_dbg("Could not write PHY the HV address register\n");
+		goto out;
+	}
+
+	/* Read or write the data value next */
+	if (read)
+		ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data);
+	else
+		ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data);
+
+	if (ret_val) {
+		e_dbg("Could not read data value from HV data register\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_link_stall_workaround_hv - Si workaround
+ *  @hw: pointer to the HW structure
+ *
+ *  This function works around a Si bug where the link partner can get
+ *  a link up indication before the PHY does.  If small packets are sent
+ *  by the link partner they can be placed in the packet buffer without
+ *  being properly accounted for by the PHY and will stall preventing
+ *  further packets from being received.  The workaround is to clear the
+ *  packet buffer after the PHY detects link up.
+ **/
+s32 e1000e_link_stall_workaround_hv(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	if (hw->phy.type != e1000_phy_82578)
+		goto out;
+
+	/* Do not apply workaround if in PHY loopback bit 14 set */
+	e1e_rphy(hw, PHY_CONTROL, &data);
+	if (data & PHY_CONTROL_LB)
+		goto out;
+
+	/* check if link is up and at 1Gbps */
+	ret_val = e1e_rphy(hw, BM_CS_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	data &= BM_CS_STATUS_LINK_UP |
+	        BM_CS_STATUS_RESOLVED |
+	        BM_CS_STATUS_SPEED_MASK;
+
+	if (data != (BM_CS_STATUS_LINK_UP |
+	             BM_CS_STATUS_RESOLVED |
+	             BM_CS_STATUS_SPEED_1000))
+		goto out;
+
+	msleep(200);
+
+	/* flush the packets in the fifo buffer */
+	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
+	                                HV_MUX_DATA_CTRL_GEN_TO_MAC |
+	                                HV_MUX_DATA_CTRL_FORCE_SPEED);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
+	                                HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_polarity_82577 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 e1000e_check_polarity_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000e_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, I82577_PHY_CTRL_2, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
+	phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
+
+	ret_val = e1e_wphy(hw, I82577_PHY_CTRL_2, phy_data);
+	if (ret_val)
+		goto out;
+
+	e_dbg("I82577_PHY_CTRL_2: %X\n", phy_data);
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link on 82577 phy\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			e_dbg("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  e1000e_get_phy_info_82577 - Retrieve I82577 PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		e_dbg("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = e1000e_check_polarity_82577(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
+
+	if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
+	    I82577_PHY_STATUS2_SPEED_1000MBPS) {
+#if 0
+		ret_val = e1000e_get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+#endif
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  e1000e_get_cable_length_82577 - Determine cable length for 82577 PHY
+ *  @hw: pointer to the HW structure
+ *
+ * Reads the diagnostic status register and verifies result is valid before
+ * placing it in the phy_cable_length field.
+ **/
+s32 e1000e_get_cable_length_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, length;
+
+	ret_val = e1e_rphy(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+	         I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+
+	if (length == E1000_CABLE_LENGTH_UNDEFINED)
+		ret_val = -E1000_ERR_PHY;
+
+	phy->cable_length = length;
+
+out:
+	return ret_val;
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h
new file mode 100644
index 0000000..9081050
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h
@@ -0,0 +1,261 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_PHY_H_
+#define _E1000E_PHY_H_
+
+void e1000e_init_phy_ops_generic(struct e1000_hw *hw);
+s32  e1000e_check_downshift(struct e1000_hw *hw);
+s32  e1000e_check_polarity_m88(struct e1000_hw *hw);
+s32  e1000e_check_polarity_igp(struct e1000_hw *hw);
+s32  e1000e_check_polarity_ife(struct e1000_hw *hw);
+s32  e1000e_check_reset_block_generic(struct e1000_hw *hw);
+s32  e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+s32  e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+#if 0
+s32  e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+#endif
+#if 0
+s32  e1000e_get_cable_length_m88(struct e1000_hw *hw);
+s32  e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+#endif
+s32  e1000e_get_cfg_done(struct e1000_hw *hw);
+s32  e1000e_get_phy_id(struct e1000_hw *hw);
+s32  e1000e_get_phy_info_igp(struct e1000_hw *hw);
+s32  e1000e_get_phy_info_m88(struct e1000_hw *hw);
+s32  e1000e_phy_sw_reset(struct e1000_hw *hw);
+#if 0
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+#endif
+s32  e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+s32  e1000e_phy_reset_dsp(struct e1000_hw *hw);
+s32  e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32  e1000e_setup_copper_link(struct e1000_hw *hw);
+s32  e1000e_wait_autoneg(struct e1000_hw *hw);
+s32  e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_phy_reset_dsp(struct e1000_hw *hw);
+s32  e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                                u32 usec_interval, bool *success);
+s32  e1000e_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+s32  e1000e_determine_phy_address(struct e1000_hw *hw);
+s32  e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
+void e1000e_power_up_phy_copper(struct e1000_hw *hw);
+void e1000e_power_down_phy_copper(struct e1000_hw *hw);
+s32  e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
+s32  e1000e_link_stall_workaround_hv(struct e1000_hw *hw);
+s32  e1000e_copper_link_setup_82577(struct e1000_hw *hw);
+s32  e1000e_check_polarity_82577(struct e1000_hw *hw);
+s32  e1000e_get_phy_info_82577(struct e1000_hw *hw);
+#if 0
+s32  e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+#endif
+#if 0
+s32  e1000e_get_cable_length_82577(struct e1000_hw *hw);
+#endif
+
+#define E1000_MAX_PHY_ADDR                4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
+#define IGP_PAGE_SHIFT                    5
+#define PHY_REG_MASK                      0x1F
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE                 769
+#define BM_PCIE_PAGE                      770
+#define BM_WUC_PAGE                       800
+#define BM_WUC_ADDRESS_OPCODE             0x11
+#define BM_WUC_DATA_OPCODE                0x12
+#define BM_WUC_ENABLE_PAGE                BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG                 17
+#define BM_WUC_ENABLE_BIT                 (1 << 2)
+#define BM_WUC_HOST_WU_BIT                (1 << 4)
+
+#define PHY_UPPER_SHIFT                   21
+#define BM_PHY_REG(page, reg) \
+	(((reg) & MAX_PHY_REG_ADDRESS) |\
+	 (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+	 (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+	((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+	((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+	 (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+		~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START             768
+#define I82578_ADDR_REG                   29
+#define I82577_ADDR_REG                   16
+#define I82577_CFG_REG                    22
+#define I82577_CFG_ASSERT_CRS_ON_TX       (1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT       (3 << 10) /* auto downshift 100/10 */
+#define I82577_CTRL_REG                   23
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2            18
+#define I82577_PHY_LBK_CTRL          19
+#define I82577_PHY_STATUS_2          26
+#define I82577_PHY_DIAG_STATUS       31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY   0x0400
+#define I82577_PHY_STATUS2_MDIX           0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK     0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
+#define I82577_PHY_STATUS2_SPEED_100MBPS  0x0100
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_AUTO_MDIX        0x0400
+#define I82577_PHY_CTRL2_FORCE_MDI_MDIX   0x0200
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH       0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1                       16
+#define BM_CS_CTRL1_ENERGY_DETECT         0x0300 /* Enable Energy Detect */
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS                      17
+#define BM_CS_STATUS_ENERGY_DETECT        0x0010 /* Energy Detect Status */
+#define BM_CS_STATUS_LINK_UP              0x0400
+#define BM_CS_STATUS_RESOLVED             0x0800
+#define BM_CS_STATUS_SPEED_MASK           0xC000
+#define BM_CS_STATUS_SPEED_1000           0x8000
+
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS                       26
+#define HV_M_STATUS_AUTONEG_COMPLETE      0x1000
+#define HV_M_STATUS_SPEED_MASK            0x0300
+#define HV_M_STATUS_SPEED_1000            0x0200
+#define HV_M_STATUS_LINK_UP               0x0040
+
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD          0x0010
+#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0800
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define IGP03E1000_PHY_MISC_CTRL          0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
+#define E1000_KMRNCTRLSTA_REN             0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG        0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE        0x0002
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED    0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
+#define IFE_PSC_FORCE_POLARITY             0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE            0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h
new file mode 100644
index 0000000..064d92c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h
@@ -0,0 +1,340 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _E1000E_REGS_H_
+#define _E1000E_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C  /* Future Extended - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_IVAR     0x000E4  /* Interrupt Vector Allocation Register - RW */
+#define E1000_SVCR     0x000F0
+#define E1000_SVT       0x000F4
+#define E1000_RCTL     0x00100  /* Rx Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
+#define E1000_PBA_ECC  0x01100  /* PBA ECC Register */
+#define E1000_TCTL     0x00400  /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
+#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
+#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
+#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
+#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+                                         (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+                                         (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+                                         (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+                                         (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+                                         (0x0C010 + ((_n) * 0x40)))
+#define E1000_RXCTL(_n)      ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+                                         (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
+#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+                                         (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+                                         (0x0C028 + ((_n) * 0x40)))
+#define E1000_RQDPC(_n)      ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
+                                         (0x0C030 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+                                         (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+                                         (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+                                         (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+                                         (0x0E010 + ((_n) * 0x40)))
+#define E1000_TXCTL(_n)      ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+                                         (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
+#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+                                         (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+                                         (0x0E028 + ((_n) * 0x40)))
+#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+                                         (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+                                         (0x0E03C + ((_n) * 0x40)))
+#define E1000_TARC(_n)                   (0x03840 + ((_n) * 0x100))
+#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                                       (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                                       (0x054E4 + ((_i - 16) * 8)))
+#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
+#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
+#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
+#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_CRC_OFFSET 0x05F50  /* CRC Offset register */
+
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
+#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA      0x0003C /* PHY address - RW */
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR         0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+                                                    * (_i) - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * upper reg - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * vector ctrl reg - RW */
+#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+#define E1000_RXMTRL     0x0B634 /* Time sync Rx EtherType and Msg Type - RW */
+#define E1000_RXUDP      0x0B638 /* Time Sync Rx UDP Port - RW */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro.c
new file mode 100644
index 0000000..909482b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro.c
@@ -0,0 +1,638 @@
+#ifdef ALLMULTI
+#error multicast support is not yet implemented
+#endif
+/**************************************************************************
+Etherboot -  BOOTP/TFTP Bootstrap Program
+Intel EEPRO/10 NIC driver for Etherboot
+Adapted from Linux eepro.c from kernel 2.2.17
+
+This board accepts a 32 pin EEPROM (29C256), however a test with a
+27C010 shows that this EPROM also works in the socket, but it's not clear
+how repeatably. The two top address pins appear to be held low, thus
+the bottom 32kB of the 27C010 is visible in the CPU's address space.
+To be sure you could put 4 copies of the code in the 27C010, then
+it doesn't matter whether the extra lines are held low or high, just
+hopefully not floating as CMOS chips don't like floating inputs.
+
+Be careful with seating the EPROM as the socket on my board actually
+has 34 pins, the top row of 2 are not used.
+***************************************************************************/
+
+/*
+
+ timlegge	2005-05-18	remove the relocation changes cards that 
+				write directly to the hardware don't need it
+*/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "etherboot.h"
+#include <errno.h>
+#include "nic.h"
+#include <ipxe/isa.h>
+#include <ipxe/ethernet.h>
+
+/* Different 82595 chips */
+#define LAN595		0
+#define LAN595TX	1
+#define LAN595FX	2
+#define LAN595FX_10ISA	3
+
+#define	SLOW_DOWN	inb(0x80);
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00	/* Etherexpress Pro/10 */
+#define SA_ADDR1 0xaa
+#define SA_ADDR2 0x00
+
+#define GetBit(x,y) ((x & (1<<y))>>y)
+
+/* EEPROM Word 0: */
+#define ee_PnP       0  /* Plug 'n Play enable bit */
+#define ee_Word1     1  /* Word 1? */
+#define ee_BusWidth  2  /* 8/16 bit */
+#define ee_FlashAddr 3  /* Flash Address */
+#define ee_FlashMask 0x7   /* Mask */
+#define ee_AutoIO    6  /* */
+#define ee_reserved0 7  /* =0! */
+#define ee_Flash     8  /* Flash there? */
+#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
+#define ee_IO0       10 /* IO Address LSB */
+#define ee_IO0Mask   0x /*...*/
+#define ee_IO1       15 /* IO MSB */
+
+/* EEPROM Word 1: */
+#define ee_IntSel    0   /* Interrupt */
+#define ee_IntMask   0x7
+#define ee_LI        3   /* Link Integrity 0= enabled */
+#define ee_PC        4   /* Polarity Correction 0= enabled */
+#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
+#define ee_Jabber    6   /* Jabber prevention 0= enabled */
+#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
+#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
+#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
+#define ee_reserved1 10  /* .. 12 =0! */
+#define ee_AltReady  13  /* Alternate Ready, 0=normal */
+#define ee_reserved2 14  /* =0! */
+#define ee_Duplex    15
+
+/* Word2,3,4: */
+#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
+
+/* Word 5: */
+#define ee_BNC_TPE   0 /* 0=TPE */
+#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
+#define ee_BootTypeMask 0x3 
+#define ee_NumConn   3  /* Number of Connections 0= One or Two */
+#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
+#define ee_PortTPE   5
+#define ee_PortBNC   6
+#define ee_PortAUI   7
+#define ee_PowerMgt  10 /* 0= disabled */
+#define ee_CP        13 /* Concurrent Processing */
+#define ee_CPMask    0x7
+
+/* Word 6: */
+#define ee_Stepping  0 /* Stepping info */
+#define ee_StepMask  0x0F
+#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
+#define ee_BoardMask 0x0FFF
+
+/* Word 7: */
+#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
+#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
+
+/*..*/
+#define ee_SIZE 0x40 /* total EEprom Size */
+#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
+
+
+/* Card identification via EEprom:   */
+#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
+#define ee_addr_id 0x11      /* Word offset for Card ID */
+#define ee_addr_SN 0x12      /* Serial Number */
+#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
+
+
+#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
+#define ee_vendor_intel1 0xD4
+#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
+#define ee_id_eepro10p1 0x31
+
+/* now this section could be used by both boards: the oldies and the ee10:
+ * ee10 uses tx buffer before of rx buffer and the oldies the inverse.
+ * (aris)
+ */
+#define	RAM_SIZE	0x8000
+
+#define	RCV_HEADER	8
+#define RCV_DEFAULT_RAM	0x6000
+#define RCV_RAM 	rcv_ram
+
+static unsigned rcv_ram = RCV_DEFAULT_RAM;
+
+#define XMT_HEADER	8
+#define XMT_RAM		(RAM_SIZE - RCV_RAM)
+
+#define XMT_START	((rcv_start + RCV_RAM) % RAM_SIZE)
+
+#define RCV_LOWER_LIMIT	(rcv_start >> 8)
+#define RCV_UPPER_LIMIT	(((rcv_start + RCV_RAM) - 2) >> 8)
+#define XMT_LOWER_LIMIT	(XMT_START >> 8)
+#define XMT_UPPER_LIMIT	(((XMT_START + XMT_RAM) - 2) >> 8)
+
+#define RCV_START_PRO	0x00
+#define RCV_START_10	XMT_RAM
+					/* by default the old driver */
+static unsigned rcv_start = RCV_START_PRO;
+
+#define	RCV_DONE	0x0008
+#define	RX_OK		0x2000
+#define	RX_ERROR	0x0d81
+
+#define	TX_DONE_BIT	0x0080
+#define	CHAIN_BIT	0x8000
+#define	XMT_STATUS	0x02
+#define	XMT_CHAIN	0x04
+#define	XMT_COUNT	0x06
+
+#define	BANK0_SELECT	0x00		
+#define	BANK1_SELECT	0x40		
+#define	BANK2_SELECT	0x80		
+
+/* Bank 0 registers */
+#define	COMMAND_REG	0x00	/* Register 0 */
+#define	MC_SETUP	0x03
+#define	XMT_CMD		0x04
+#define	DIAGNOSE_CMD	0x07
+#define	RCV_ENABLE_CMD	0x08
+#define	RCV_DISABLE_CMD	0x0a
+#define	STOP_RCV_CMD	0x0b
+#define	RESET_CMD	0x0e
+#define	POWER_DOWN_CMD	0x18
+#define	RESUME_XMT_CMD	0x1c
+#define	SEL_RESET_CMD	0x1e
+#define	STATUS_REG	0x01	/* Register 1 */
+#define	RX_INT		0x02
+#define	TX_INT		0x04
+#define	EXEC_STATUS	0x30
+#define	ID_REG		0x02	/* Register 2	*/
+#define	R_ROBIN_BITS	0xc0	/* round robin counter */
+#define	ID_REG_MASK	0x2c
+#define	ID_REG_SIG	0x24
+#define	AUTO_ENABLE	0x10
+#define	INT_MASK_REG	0x03	/* Register 3	*/
+#define	RX_STOP_MASK	0x01
+#define	RX_MASK		0x02
+#define	TX_MASK		0x04
+#define	EXEC_MASK	0x08
+#define	ALL_MASK	0x0f
+#define	IO_32_BIT	0x10
+#define	RCV_BAR		0x04	/* The following are word (16-bit) registers */
+#define	RCV_STOP	0x06
+
+#define	XMT_BAR_PRO	0x0a
+#define	XMT_BAR_10	0x0b
+static unsigned xmt_bar = XMT_BAR_PRO;
+
+#define	HOST_ADDRESS_REG	0x0c
+#define	IO_PORT		0x0e
+#define	IO_PORT_32_BIT	0x0c
+
+/* Bank 1 registers */
+#define	REG1	0x01
+#define	WORD_WIDTH	0x02
+#define	INT_ENABLE	0x80
+#define INT_NO_REG	0x02
+#define	RCV_LOWER_LIMIT_REG	0x08
+#define	RCV_UPPER_LIMIT_REG	0x09
+
+#define	XMT_LOWER_LIMIT_REG_PRO	0x0a
+#define	XMT_UPPER_LIMIT_REG_PRO	0x0b
+#define	XMT_LOWER_LIMIT_REG_10	0x0b
+#define	XMT_UPPER_LIMIT_REG_10	0x0a
+static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
+static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
+
+/* Bank 2 registers */
+#define	XMT_Chain_Int	0x20	/* Interrupt at the end of the transmit chain */
+#define	XMT_Chain_ErrStop	0x40 /* Interrupt at the end of the chain even if there are errors */
+#define	RCV_Discard_BadFrame	0x80 /* Throw bad frames away, and continue to receive others */
+#define	REG2		0x02
+#define	PRMSC_Mode	0x01
+#define	Multi_IA	0x20
+#define	REG3		0x03
+#define	TPE_BIT		0x04
+#define	BNC_BIT		0x20
+#define	REG13		0x0d
+#define	FDX		0x00
+#define	A_N_ENABLE	0x02
+	
+#define	I_ADD_REG0	0x04
+#define	I_ADD_REG1	0x05
+#define	I_ADD_REG2	0x06
+#define	I_ADD_REG3	0x07
+#define	I_ADD_REG4	0x08
+#define	I_ADD_REG5	0x09
+
+#define EEPROM_REG_PRO	0x0a
+#define EEPROM_REG_10	0x0b
+static unsigned eeprom_reg = EEPROM_REG_PRO;
+
+#define EESK 0x01
+#define EECS 0x02
+#define EEDI 0x04
+#define EEDO 0x08
+
+/* The horrible routine to read a word from the serial EEPROM. */
+/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay() { udelay(40); }
+#define EE_READ_CMD (6 << 6)
+
+/* do a full reset; data sheet asks for 250us delay */
+#define eepro_full_reset(ioaddr)	outb(RESET_CMD, ioaddr); udelay(255);
+
+/* do a nice reset */
+#define eepro_sel_reset(ioaddr) \
+  do {  \
+    outb ( SEL_RESET_CMD, ioaddr ); \
+    (void) SLOW_DOWN; \
+    (void) SLOW_DOWN; \
+  } while (0)
+
+/* clear all interrupts */
+#define	eepro_clear_int(ioaddr)	outb(ALL_MASK, ioaddr + STATUS_REG)
+
+/* enable rx */
+#define	eepro_en_rx(ioaddr)	outb(RCV_ENABLE_CMD, ioaddr)
+
+/* disable rx */
+#define	eepro_dis_rx(ioaddr)	outb(RCV_DISABLE_CMD, ioaddr)
+
+/* switch bank */
+#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
+#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
+#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
+
+static unsigned int	rx_start, tx_start;
+static int		tx_last;
+static unsigned	int	tx_end;
+static int		eepro = 0;
+static unsigned int	mem_start, mem_end = RCV_DEFAULT_RAM / 1024;
+
+/**************************************************************************
+RESET - Reset adapter
+***************************************************************************/
+static void eepro_reset(struct nic *nic)
+{
+	int		temp_reg, i;
+
+	/* put the card in its initial state */
+	eepro_sw2bank2(nic->ioaddr);	/* be careful, bank2 now */
+	temp_reg = inb(nic->ioaddr + eeprom_reg);
+	DBG("Stepping %d\n", temp_reg >> 5);
+	if (temp_reg & 0x10)	/* check the TurnOff Enable bit */
+		outb(temp_reg & 0xEF, nic->ioaddr + eeprom_reg);
+	for (i = 0; i < ETH_ALEN; i++)	/* fill the MAC address */
+		outb(nic->node_addr[i], nic->ioaddr + I_ADD_REG0 + i);
+	temp_reg = inb(nic->ioaddr + REG1);
+	/* setup Transmit Chaining and discard bad RCV frames */
+	outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop
+		| RCV_Discard_BadFrame, nic->ioaddr + REG1);
+	temp_reg = inb(nic->ioaddr + REG2);		/* match broadcast */
+	outb(temp_reg | 0x14, nic->ioaddr + REG2);
+	temp_reg = inb(nic->ioaddr + REG3);
+	outb(temp_reg & 0x3F, nic->ioaddr + REG3);	/* clear test mode */
+	/* set the receiving mode */
+	eepro_sw2bank1(nic->ioaddr);	/* be careful, bank1 now */
+	/* initialise the RCV and XMT upper and lower limits */
+	outb(RCV_LOWER_LIMIT, nic->ioaddr + RCV_LOWER_LIMIT_REG);
+	outb(RCV_UPPER_LIMIT, nic->ioaddr + RCV_UPPER_LIMIT_REG);
+	outb(XMT_LOWER_LIMIT, nic->ioaddr + xmt_lower_limit_reg);
+	outb(XMT_UPPER_LIMIT, nic->ioaddr + xmt_upper_limit_reg);
+	eepro_sw2bank0(nic->ioaddr);	/* Switch back to bank 0 */
+	eepro_clear_int(nic->ioaddr);
+	/* Initialise RCV */
+	outw(rx_start = (RCV_LOWER_LIMIT << 8), nic->ioaddr + RCV_BAR);
+	outw(((RCV_UPPER_LIMIT << 8) | 0xFE), nic->ioaddr + RCV_STOP);
+ 	/* Make sure 1st poll won't find a valid packet header */
+ 	outw((RCV_LOWER_LIMIT << 8), nic->ioaddr + HOST_ADDRESS_REG);
+ 	outw(0,                      nic->ioaddr + IO_PORT);
+	/* Intialise XMT */
+	outw((XMT_LOWER_LIMIT << 8), nic->ioaddr + xmt_bar);
+	eepro_sel_reset(nic->ioaddr);
+	tx_start = tx_end = (unsigned int) (XMT_LOWER_LIMIT << 8);
+	tx_last = 0;
+	eepro_en_rx(nic->ioaddr);
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int eepro_poll(struct nic *nic, int retrieve)
+{
+	unsigned int	rcv_car = rx_start;
+	unsigned int	rcv_event, rcv_status, rcv_next_frame, rcv_size;
+
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+#if	0
+	if ((inb(nic->ioaddr + STATUS_REG) & 0x40) == 0)
+		return (0);
+	outb(0x40, nic->ioaddr + STATUS_REG);
+#endif
+	outw(rcv_car, nic->ioaddr + HOST_ADDRESS_REG);
+	rcv_event = inw(nic->ioaddr + IO_PORT);
+	if (rcv_event != RCV_DONE)
+		return (0);
+
+	/* FIXME: I'm guessing this might not work with this card, since
+	   it looks like once a rcv_event is started it must be completed.
+	   maybe there's another way. */
+	if ( ! retrieve ) return 1;
+
+	rcv_status = inw(nic->ioaddr + IO_PORT);
+	rcv_next_frame = inw(nic->ioaddr + IO_PORT);
+	rcv_size = inw(nic->ioaddr + IO_PORT);
+#if	0
+	printf("%hX %hX %d %hhX\n", rcv_status, rcv_next_frame, rcv_size,
+		inb(nic->ioaddr + STATUS_REG));
+#endif
+	if ((rcv_status & (RX_OK|RX_ERROR)) != RX_OK) {
+		printf("Receive error %hX\n", rcv_status);
+		return (0);
+	}
+	rcv_size &= 0x3FFF;
+	insw(nic->ioaddr + IO_PORT, nic->packet, ((rcv_size + 3) >> 1));
+#if	0
+{
+	int i;
+	for (i = 0; i < 48; i++) {
+		printf("%hhX", nic->packet[i]);
+		putchar(i % 16 == 15 ? '\n' : ' ');
+	}
+}
+#endif
+	nic->packetlen = rcv_size;
+	rcv_car  = (rx_start + RCV_HEADER + rcv_size);
+	rx_start = rcv_next_frame;
+/* 
+	hex_dump(rcv_car, nic->packetlen); 
+*/
+
+	if (rcv_car == 0)
+		rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff);
+	outw(rcv_car - 1, nic->ioaddr + RCV_STOP);
+	return (1);
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void eepro_transmit(
+	struct nic *nic,
+	const char *d,			/* Destination */
+	unsigned int t,			/* Type */
+	unsigned int s,			/* size */
+	const char *p)			/* Packet */
+{
+	unsigned int	status, tx_available, last, end, length;
+	unsigned short	type;
+	int		boguscount = 20;
+
+	length = s + ETH_HLEN;
+	if (tx_end > tx_start)
+		tx_available = XMT_RAM - (tx_end - tx_start);
+	else if (tx_end < tx_start)
+		tx_available = tx_start - tx_end;
+	else
+		tx_available = XMT_RAM;
+	assert ( length <= tx_available );
+	last = tx_end;
+	end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+	if (end >= (XMT_UPPER_LIMIT << 8)) {
+		last = (XMT_LOWER_LIMIT << 8);
+		end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
+	}
+	outw(last, nic->ioaddr + HOST_ADDRESS_REG);
+	outw(XMT_CMD, nic->ioaddr + IO_PORT);
+	outw(0, nic->ioaddr + IO_PORT);
+	outw(end, nic->ioaddr + IO_PORT);
+	outw(length, nic->ioaddr + IO_PORT);
+	outsw(nic->ioaddr + IO_PORT, d, ETH_ALEN / 2);
+	outsw(nic->ioaddr + IO_PORT, nic->node_addr, ETH_ALEN / 2);
+	type = htons(t);
+	outsw(nic->ioaddr + IO_PORT, &type, sizeof(type) / 2);
+	outsw(nic->ioaddr + IO_PORT, p, (s + 3) >> 1);
+	/* A dummy read to flush the DRAM write pipeline */
+	status = inw(nic->ioaddr + IO_PORT);
+	outw(last, nic->ioaddr + xmt_bar);
+	outb(XMT_CMD, nic->ioaddr);
+	tx_start = last;
+	tx_last = last;
+	tx_end = end;
+#if	0
+	printf("%d %d\n", tx_start, tx_end);
+#endif
+	while (boguscount > 0) {
+		if (((status = inw(nic->ioaddr + IO_PORT)) & TX_DONE_BIT) == 0) {
+			udelay(40);
+			boguscount--;
+			continue;
+		}
+		if ((status & 0x2000) == 0) {
+			DBG("Transmit status %hX\n", status);
+		}
+	}
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void eepro_disable ( struct nic *nic, struct isa_device *isa __unused ) {
+	eepro_sw2bank0(nic->ioaddr);	/* Switch to bank 0 */
+	/* Flush the Tx and disable Rx */
+	outb(STOP_RCV_CMD, nic->ioaddr);
+	tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
+	tx_last = 0;
+	/* Reset the 82595 */
+	eepro_full_reset(nic->ioaddr);
+}
+
+/**************************************************************************
+DISABLE - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void eepro_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static int read_eeprom(uint16_t ioaddr, int location)
+{
+	int		i;
+	unsigned short	retval = 0;
+	int		ee_addr = ioaddr + eeprom_reg;
+	int		read_cmd = location | EE_READ_CMD;
+	int		ctrl_val = EECS;
+
+	if (eepro == LAN595FX_10ISA) {
+		eepro_sw2bank1(ioaddr);
+		outb(0x00, ioaddr + STATUS_REG);
+	}
+	eepro_sw2bank2(ioaddr);
+	outb(ctrl_val, ee_addr);
+	/* shift the read command bits out */
+	for (i = 8; i >= 0; i--) {
+		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
+		outb(outval, ee_addr);
+		outb(outval | EESK, ee_addr);	/* EEPROM clock tick */
+		eeprom_delay();
+		outb(outval, ee_addr);		/* finish EEPROM clock tick */
+		eeprom_delay();
+	}
+	outb(ctrl_val, ee_addr);
+	for (i = 16; i > 0; i--) {
+		outb(ctrl_val | EESK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
+		outb(ctrl_val, ee_addr);
+		eeprom_delay();
+	}
+	/* terminate the EEPROM access */
+	ctrl_val &= ~EECS;
+	outb(ctrl_val | EESK, ee_addr);
+	eeprom_delay();
+	outb(ctrl_val, ee_addr);
+	eeprom_delay();
+	eepro_sw2bank0(ioaddr);
+	return (retval);
+}
+
+static int eepro_probe1 ( isa_probe_addr_t ioaddr ) {
+	int		id, counter;
+
+	id = inb(ioaddr + ID_REG);
+	if ((id & ID_REG_MASK) != ID_REG_SIG)
+		return (0);
+	counter = id & R_ROBIN_BITS;
+	if (((id = inb(ioaddr + ID_REG)) & R_ROBIN_BITS) != (counter + 0x40))
+		return (0);
+	/* yes the 82595 has been found */
+	return (1);
+}
+
+static struct nic_operations eepro_operations = {
+	.connect	= dummy_connect,
+	.poll		= eepro_poll,
+	.transmit	= eepro_transmit,
+	.irq		= eepro_irq,
+
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int eepro_probe ( struct nic *nic, struct isa_device *isa ) {
+
+	int		i, l_eepro = 0;
+	union {
+		unsigned char	caddr[ETH_ALEN];
+		unsigned short	saddr[ETH_ALEN/2];
+	} station_addr;
+	const char *name;
+
+	nic->irqno  = 0;
+	nic->ioaddr = isa->ioaddr;
+
+	station_addr.saddr[2] = read_eeprom(nic->ioaddr,2);
+	if ( ( station_addr.saddr[2] == 0x0000 ) ||
+	     ( station_addr.saddr[2] == 0xFFFF ) ) {
+		l_eepro = 3;
+		eepro = LAN595FX_10ISA;
+		eeprom_reg= EEPROM_REG_10;
+		rcv_start = RCV_START_10;
+		xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
+		xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
+		station_addr.saddr[2] = read_eeprom(nic->ioaddr,2);
+	}
+	station_addr.saddr[1] = read_eeprom(nic->ioaddr,3);
+	station_addr.saddr[0] = read_eeprom(nic->ioaddr,4);
+	if (l_eepro)
+		name = "Intel EtherExpress 10 ISA";
+	else if (read_eeprom(nic->ioaddr,7) == ee_FX_INT2IRQ) {
+		name = "Intel EtherExpress Pro/10+ ISA";
+		l_eepro = 2;
+	} else if (station_addr.saddr[0] == SA_ADDR1) {
+		name = "Intel EtherExpress Pro/10 ISA";
+		l_eepro = 1;
+	} else {
+		l_eepro = 0;
+		name = "Intel 82595-based LAN card";
+	}
+	station_addr.saddr[0] = swap16(station_addr.saddr[0]);
+	station_addr.saddr[1] = swap16(station_addr.saddr[1]);
+	station_addr.saddr[2] = swap16(station_addr.saddr[2]);
+	for (i = 0; i < ETH_ALEN; i++) {
+		nic->node_addr[i] = station_addr.caddr[i];
+	}
+
+	DBG ( "%s ioaddr %#hX, addr %s", name, nic->ioaddr, eth_ntoa ( nic->node_addr ) );
+
+	mem_start = RCV_LOWER_LIMIT << 8;
+	if ((mem_end & 0x3F) < 3 || (mem_end & 0x3F) > 29)
+		mem_end = RCV_UPPER_LIMIT << 8;
+	else {
+		mem_end = mem_end * 1024 + (RCV_LOWER_LIMIT << 8);
+		rcv_ram = mem_end - (RCV_LOWER_LIMIT << 8);
+	}
+	printf(", Rx mem %dK, if %s\n", (mem_end - mem_start) >> 10,
+		GetBit(read_eeprom(nic->ioaddr,5), ee_BNC_TPE) ? "BNC" : "TP");
+
+	eepro_reset(nic);
+
+	/* point to NIC specific routines */
+	nic->nic_op	= &eepro_operations;
+	return 1;
+}
+
+static isa_probe_addr_t eepro_probe_addrs[] = {
+	0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360,
+};
+
+ISA_DRIVER ( eepro_driver, eepro_probe_addrs, eepro_probe1,
+		     GENERIC_ISAPNP_VENDOR, 0x828a );
+
+DRIVER ( "eepro", nic_driver, isa_driver, eepro_driver,
+	 eepro_probe, eepro_disable );
+
+ISA_ROM ( "eepro", "Intel Etherexpress Pro/10" );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.c
new file mode 100644
index 0000000..85840cd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.c
@@ -0,0 +1,1163 @@
+/*
+ * eepro100.c -- This is a driver for Intel Fast Ethernet Controllers
+ * (ifec).
+ *
+ * Originally written for Etherboot by:
+ *
+ *   Copyright (C) AW Computer Systems.
+ *   written by R.E.Wolff -- R.E.Wolff at BitWizard.nl
+ *
+ *   AW Computer Systems is contributing to the free software community
+ *   by paying for this driver and then putting the result under GPL.
+ *
+ *   If you need a Linux device driver, please contact BitWizard for a
+ *   quote.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *              date       version  by      what
+ *  Written:    May 29 1997  V0.10  REW     Initial revision.
+ * changes:     May 31 1997  V0.90  REW     Works!
+ *              Jun 1  1997  V0.91  REW     Cleanup
+ *              Jun 2  1997  V0.92  REW     Add some code documentation
+ *              Jul 25 1997  V1.00  REW     Tested by AW to work in a PROM
+ *                                          Cleanup for publication
+ *              Dez 11 2004  V1.10  Kiszka  Add RX ring buffer support
+ *              Jun    2008  v2.0   mdeck   Updated to iPXE. Changed much.
+ *
+ * Cleanups and fixes by Thomas Miletich<thomas.miletich at gmail.com>
+ *
+ * This is the etherboot intel etherexpress Pro/100B driver.
+ *
+ * It was written from scratch, with Donald Beckers eepro100.c kernel
+ * driver as a guideline. Mostly the 82557 related definitions and the
+ * lower level routines have been cut-and-pasted into this source.
+ *
+ * The driver was finished before Intel got the NDA out of the closet.
+ *
+ * Datasheet is now published and available from 
+ * ftp://download.intel.com/design/network/manuals/8255X_OpenSDM.pdf
+ *    - Michael Brown
+ * */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * General Theory of Operation
+ *
+ * Initialization
+ *
+ * ifec_pci_probe() is called by iPXE during initialization. Typical NIC
+ * initialization is performed.  EEPROM data is read.
+ *
+ * Network Boot
+ *
+ * ifec_net_open() is called by iPXE before attempting to network boot from the
+ * card.  Here, the Command Unit & Receive Unit are initialized.  The tx & rx
+ * rings are setup.  The MAC address is programmed and the card is configured.
+ *
+ * Transmit
+ *
+ * ifec_net_transmit() enqueues a packet in the tx ring - active::tcbs[]  The tx
+ * ring is composed of TCBs linked to each other into a ring.  A tx request
+ * fills out the next available TCB with a pointer to the packet data.
+ * The last enqueued tx is always at active::tcb_head.  Thus, a tx request fills
+ * out the TCB following tcb_head.
+ * active::tcb_tail points to the TCB we're awaiting completion of.
+ * ifec_tx_process() checks tcb_tail, and once complete,
+ * blindly increments tcb_tail to the next ring TCB.
+ *
+ * Receive
+ *
+ * priv::rfds[] is an array of Receive Frame Descriptors. The RFDs are linked
+ * together to form a ring.
+ * ifec_net_poll() calls ifec_rx_process(), which checks the next RFD for
+ * data.  If we received a packet, we allocate a new io_buffer and copy the
+ * packet data into it. If alloc_iob() fails, we don't touch the RFD and try
+ * again on the next poll.
+ */
+
+/*
+ * Debugging levels:
+ *	- DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(),
+ *	  TX overflow, corrupted packets, ...
+ *	- DBG2() is for successful events, like packet received,
+ *	  packet transmitted, and other general notifications.
+ *	- DBGP() prints the name of each called function on entry
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/spi_bit.h>
+#include <ipxe/timer.h>
+#include <ipxe/nvs.h>
+#include <ipxe/threewire.h>
+#include <ipxe/netdevice.h>
+#include "eepro100.h"
+
+/****************************** Global data **********************************/
+
+/*
+ * This is the default configuration command data. The values were copied from
+ * the Linux kernel initialization for the eepro100.
+ */
+static struct ifec_cfg ifec_cfg = {
+	.status  = 0,
+	.command = CmdConfigure | CmdSuspend,
+	.link    = 0,        /* Filled in later */
+	.byte = { 22,        /* How many bytes in this array */
+	          ( TX_FIFO << 4 ) | RX_FIFO,  /* Rx & Tx FIFO limits */
+	          0, 0,                        /* Adaptive Interframe Spacing */
+	          RX_DMA_COUNT,                /* Rx DMA max byte count */
+	          TX_DMA_COUNT + 0x80,         /* Tx DMA max byte count */
+	          0x32,      /* Many bits. */
+	          0x03,      /* Discard short receive & Underrun retries */
+	          1,         /* 1=Use MII  0=Use AUI */
+	          0,
+	          0x2E,      /* NSAI, Preamble length, & Loopback*/
+	          0,         /* Linear priority */
+	          0x60,      /* L PRI MODE & Interframe spacing */
+	          0, 0xf2,
+	          0x48,      /* Promiscuous, Broadcast disable, CRS & CDT */
+	          0, 0x40,
+	          0xf2,      /* Stripping, Padding, Receive CRC Transfer */
+	          0x80,      /* 0x40=Force full-duplex, 0x80=Allowfull-duplex*/
+	          0x3f,      /* Multiple IA */
+	          0x0D }     /* Multicast all */
+};
+
+static struct net_device_operations ifec_operations = {
+	.open     = ifec_net_open,
+	.close    = ifec_net_close,
+	.transmit = ifec_net_transmit,
+	.poll     = ifec_net_poll,
+	.irq      = ifec_net_irq
+};
+
+/******************* iPXE PCI Device Driver API functions ********************/
+
+/*
+ * Initialize the PCI device.
+ *
+ * @v pci 		The device's associated pci_device structure.
+ * @v id  		The PCI device + vendor id.
+ * @ret rc		Returns zero if successfully initialized.
+ *
+ * This function is called very early on, while iPXE is initializing.
+ * This is a iPXE PCI Device Driver API function.
+ */
+static int ifec_pci_probe ( struct pci_device *pci )
+{
+	struct net_device *netdev;
+	struct ifec_private *priv;
+	int rc;
+
+	DBGP ( "ifec_pci_probe: " );
+
+	if ( pci->ioaddr == 0 )
+		return -EINVAL;
+
+	netdev = alloc_etherdev ( sizeof(*priv) );
+	if ( !netdev )
+		return -ENOMEM;
+
+	netdev_init ( netdev, &ifec_operations );
+	priv = netdev->priv;
+
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+
+	/* enable bus master, etc */
+	adjust_pci_device( pci );
+
+	DBGP ( "pci " );
+
+	memset ( priv, 0, sizeof(*priv) );
+	priv->ioaddr = pci->ioaddr;
+
+	ifec_reset ( netdev );
+	DBGP ( "reset " );
+
+	ifec_init_eeprom ( netdev );
+
+	/* read MAC address */
+	nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MAC_0, netdev->hw_addr,
+		   ETH_ALEN );
+	/* read mdio_register */
+	nvs_read ( &priv->eeprom.nvs, EEPROM_ADDR_MDIO_REGISTER,
+		   &priv->mdio_register, 2 );
+
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto error;
+
+	netdev_link_up ( netdev );
+
+	DBGP ( "ints\n" );
+
+	return 0;
+
+error:
+	ifec_reset     ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put     ( netdev );
+
+	return rc;
+}
+
+/*
+ * Remove a device from the PCI device list.
+ *
+ * @v pci		PCI device to remove.
+ *
+ * This is a PCI Device Driver API function.
+ */
+static void ifec_pci_remove ( struct pci_device *pci )
+{
+	struct net_device *netdev = pci_get_drvdata ( pci );
+
+	DBGP ( "ifec_pci_remove\n" );
+
+	unregister_netdev ( netdev );
+	ifec_reset        ( netdev );
+	netdev_nullify    ( netdev );
+	netdev_put        ( netdev );
+}
+
+/****************** iPXE Network Device Driver API functions *****************/
+
+/*
+ * Close a network device.
+ *
+ * @v netdev		Device to close.
+ *
+ * This is a iPXE Network Device Driver API function.
+ */
+static void ifec_net_close ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+	unsigned short intr_status;
+
+	DBGP ( "ifec_net_close\n" );
+
+	/* disable interrupts */
+	ifec_net_irq ( netdev, 0 );
+
+	/* Ack & clear ints */
+	intr_status = inw ( ioaddr + SCBStatus );
+	outw ( intr_status, ioaddr + SCBStatus );
+	inw ( ioaddr + SCBStatus );
+
+	ifec_reset ( netdev );
+
+	/* Free any resources */
+	ifec_free ( netdev );
+}
+
+/* Interrupts to be masked */
+#define INTERRUPT_MASK	( SCBMaskEarlyRx | SCBMaskFlowCtl )
+
+/*
+ * Enable or disable IRQ masking.
+ *
+ * @v netdev		Device to control.
+ * @v enable		Zero to mask off IRQ, non-zero to enable IRQ.
+ *
+ * This is a iPXE Network Driver API function.
+ */
+static void ifec_net_irq ( struct net_device *netdev, int enable )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+
+	DBGP ( "ifec_net_irq\n" );
+
+	outw ( enable ? INTERRUPT_MASK : SCBMaskAll, ioaddr + SCBCmd );
+}
+
+/*
+ * Opens a network device.
+ *
+ * @v netdev		Device to be opened.
+ * @ret rc  		Non-zero if failed to open.
+ *
+ * This enables tx and rx on the device.
+ * This is a iPXE Network Device Driver API function.
+ */
+static int ifec_net_open ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	struct ifec_ias *ias = NULL;
+	struct ifec_cfg *cfg = NULL;
+	int i, options;
+	int rc = -ENOMEM;
+
+	DBGP ( "ifec_net_open: " );
+
+	/* Ensure interrupts are disabled. */
+	ifec_net_irq ( netdev, 0 );
+
+	/* Initialize Command Unit and Receive Unit base addresses. */
+	ifec_scb_cmd ( netdev, 0, RUAddrLoad );
+	ifec_scb_cmd ( netdev, virt_to_bus ( &priv->stats ), CUStatsAddr );
+	ifec_scb_cmd ( netdev, 0, CUCmdBase );
+
+	/* Initialize both rings */
+	if ( ( rc = ifec_rx_setup ( netdev ) ) != 0 )
+		goto error;
+	if ( ( rc = ifec_tx_setup ( netdev ) ) != 0 )
+		goto error;
+
+	/* Initialize MDIO */
+	options = 0x00; /* 0x40 = 10mbps half duplex, 0x00 = Autosense */
+	ifec_mdio_setup ( netdev, options );
+
+	/* Prepare MAC address w/ Individual Address Setup (ias) command.*/
+	ias = malloc_dma ( sizeof ( *ias ), CB_ALIGN );
+	if ( !ias ) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	ias->command      = CmdIASetup;
+	ias->status       = 0;
+	memcpy ( ias->ia, netdev->ll_addr, ETH_ALEN );
+
+	/* Prepare operating parameters w/ a configure command. */
+	cfg = malloc_dma ( sizeof ( *cfg ), CB_ALIGN );
+	if ( !cfg ) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	memcpy ( cfg, &ifec_cfg, sizeof ( *cfg ) );
+	cfg->link     = virt_to_bus ( priv->tcbs );
+	cfg->byte[19] = ( options & 0x10 ) ? 0xC0 : 0x80;
+	ias->link     = virt_to_bus ( cfg );
+
+	/* Issue the ias and configure commands. */
+	ifec_scb_cmd ( netdev, virt_to_bus ( ias ), CUStart );
+	ifec_scb_cmd_wait ( netdev );
+	priv->configured = 1;
+
+	/* Wait up to 10 ms for configuration to initiate */
+	for ( i = 10; i && !cfg->status; i-- )
+		mdelay ( 1 );
+	if ( ! cfg->status ) {
+		DBG ( "Failed to initiate!\n" );
+		goto error;
+	}
+	free_dma ( ias, sizeof ( *ias ) );
+	free_dma ( cfg, sizeof ( *cfg ) );
+	DBG2 ( "cfg " );
+
+	/* Enable rx by sending ring address to card */
+	if ( priv->rfds[0] != NULL ) {
+		ifec_scb_cmd ( netdev, virt_to_bus( priv->rfds[0] ), RUStart );
+		ifec_scb_cmd_wait ( netdev );
+	}
+	DBG2 ( "rx_start\n" );
+
+	return 0;
+
+error:
+	free_dma ( cfg, sizeof ( *cfg ) );
+	free_dma ( ias, sizeof ( *ias ) );
+	ifec_free ( netdev );
+	ifec_reset ( netdev );
+	return rc;
+}
+
+/*
+ * This function allows a driver to process events during operation.
+ *
+ * @v netdev		Device being polled.
+ *
+ * This is called periodically by iPXE to let the driver check the status of
+ * transmitted packets and to allow the driver to check for received packets.
+ * This is a iPXE Network Device Driver API function.
+ */
+static void ifec_net_poll ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned short intr_status;
+
+	DBGP ( "ifec_net_poll\n" );
+
+	/* acknowledge interrupts ASAP */
+	intr_status = inw ( priv->ioaddr + SCBStatus );
+	outw ( intr_status, priv->ioaddr + SCBStatus );
+	inw ( priv->ioaddr + SCBStatus );
+
+	DBG2 ( "poll - status: 0x%04X\n", intr_status );
+
+	/* anything to do here? */
+	if ( ( intr_status & ( ~INTERRUPT_MASK ) ) == 0 )
+		return;
+
+	/* process received and transmitted packets */
+	ifec_tx_process ( netdev );
+	ifec_rx_process ( netdev );
+
+	ifec_check_ru_status ( netdev, intr_status );
+
+	return;
+}
+
+/*
+ * This transmits a packet.
+ *
+ * @v netdev		Device to transmit from.
+ * @v iobuf 		Data to transmit.
+ * @ret rc  		Non-zero if failed to transmit.
+ *
+ * This is a iPXE Network Driver API function.
+ */
+static int ifec_net_transmit ( struct net_device *netdev,
+                               struct io_buffer *iobuf )
+{
+	struct ifec_private *priv = netdev->priv;
+	struct ifec_tcb *tcb = priv->tcb_head->next;
+	unsigned long ioaddr = priv->ioaddr;
+
+	DBGP ( "ifec_net_transmit\n" );
+
+	/* Wait for TCB to become available. */
+	if ( tcb->status || tcb->iob ) {
+		DBG ( "TX overflow\n" );
+		return -ENOBUFS;
+	}
+
+	DBG2 ( "transmitting packet (%zd bytes). status = %hX, cmd=%hX\n",
+		iob_len ( iobuf ), tcb->status, inw ( ioaddr + SCBCmd ) );
+
+	tcb->command   = CmdSuspend | CmdTx | CmdTxFlex;
+	tcb->count     = 0x01208000;
+	tcb->tbd_addr0 = virt_to_bus ( iobuf->data );
+	tcb->tbd_size0 = 0x3FFF & iob_len ( iobuf );
+	tcb->iob = iobuf;
+
+	ifec_tx_wake ( netdev );
+
+	/* Append to end of ring. */
+	priv->tcb_head = tcb;
+
+	return 0;
+}
+
+/*************************** Local support functions *************************/
+
+/* Define what each GPIO Pin does */
+static const uint16_t ifec_ee_bits[] = {
+	[SPI_BIT_SCLK]	= EE_SHIFT_CLK,
+	[SPI_BIT_MOSI]	= EE_DATA_WRITE,
+	[SPI_BIT_MISO]	= EE_DATA_READ,
+	[SPI_BIT_SS(0)]	= EE_ENB,
+};
+
+/*
+ * Read a single bit from the GPIO pins used for SPI.
+ * should be called by SPI bitbash functions only
+ *
+ * @v basher		Bitbash device
+ * @v bit_id		Line to be read
+ */
+static int ifec_spi_read_bit ( struct bit_basher *basher,
+			       unsigned int bit_id )
+{
+	struct ifec_private *priv =
+		container_of ( basher, struct ifec_private, spi.basher );
+	unsigned long ee_addr = priv->ioaddr + CSREeprom;
+	unsigned int ret = 0;
+	uint16_t mask;
+
+	DBGP ( "ifec_spi_read_bit\n" );
+
+	mask = ifec_ee_bits[bit_id];
+	ret = inw (ee_addr);
+
+	return ( ret & mask ) ? 1 : 0;
+}
+
+/*
+ * Write a single bit to the GPIO pins used for SPI.
+ * should be called by SPI bitbash functions only
+ *
+ * @v basher		Bitbash device
+ * @v bit_id		Line to write to
+ * @v data		Value to write
+ */
+static void ifec_spi_write_bit ( struct bit_basher *basher,
+				 unsigned int bit_id,
+				 unsigned long data )
+{
+	struct ifec_private *priv =
+		container_of ( basher, struct ifec_private, spi.basher );
+	unsigned long ee_addr = priv->ioaddr + CSREeprom;
+	short val;
+	uint16_t mask = ifec_ee_bits[bit_id];
+
+	DBGP ( "ifec_spi_write_bit\n" );
+
+	val = inw ( ee_addr );
+	val &= ~mask;
+	val |= data & mask;
+
+	outw ( val, ee_addr );
+}
+
+/* set function pointer to SPI read- and write-bit functions */
+static struct bit_basher_operations ifec_basher_ops = {
+	.read = ifec_spi_read_bit,
+	.write = ifec_spi_write_bit,
+};
+
+/*
+ * Initialize the eeprom stuff
+ *
+ * @v netdev		Network device
+ */
+static void ifec_init_eeprom ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+
+	DBGP ( "ifec_init_eeprom\n" );
+
+	priv->spi.basher.op = &ifec_basher_ops;
+	priv->spi.bus.mode = SPI_MODE_THREEWIRE;
+	init_spi_bit_basher ( &priv->spi );
+
+	priv->eeprom.bus = &priv->spi.bus;
+
+	/* init as 93c46(93c14 compatible) first, to set the command len,
+	 * block size and word len. Needs to be set for address len detection.
+	 */
+	init_at93c46 ( &priv->eeprom, 16 );
+
+	/* detect address length, */
+	threewire_detect_address_len ( &priv->eeprom );
+
+	/* address len == 8 means 93c66 instead of 93c46 */
+	if ( priv->eeprom.address_len == 8 )
+		init_at93c66 ( &priv->eeprom, 16 );
+}
+
+/*
+ * Support function: ifec_mdio_read
+ *
+ * This probably reads a register in the "physical media interface chip".
+ * -- REW
+ */
+static int ifec_mdio_read ( struct net_device *netdev, int phy_id,
+                                                       int location )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+	int val;
+	int boguscnt = 64*4;     /* <64 usec. to complete, typ 27 ticks */
+
+	DBGP ( "ifec_mdio_read\n" );
+
+	outl ( 0x08000000 | ( location << 16 ) | ( phy_id << 21 ),
+	       ioaddr + CSRCtrlMDI );
+	do {
+		udelay ( 16 );
+
+		val = inl ( ioaddr + CSRCtrlMDI );
+
+		if ( --boguscnt < 0 ) {
+			DBG ( " ifec_mdio_read() time out with val = %X.\n",
+			         val );
+			break;
+		}
+	} while (! ( val & 0x10000000 ) );
+	return val & 0xffff;
+}
+
+/*
+ * Initializes MDIO.
+ *
+ * @v netdev 		Network device
+ * @v options		MDIO options
+ */
+static void ifec_mdio_setup ( struct net_device *netdev, int options )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned short mdio_register = priv->mdio_register;
+
+	DBGP ( "ifec_mdio_setup\n" );
+
+	if (   ( (mdio_register>>8) & 0x3f ) == DP83840
+	    || ( (mdio_register>>8) & 0x3f ) == DP83840A ) {
+		int mdi_reg23 = ifec_mdio_read ( netdev, mdio_register
+						  & 0x1f, 23 ) | 0x0422;
+		if (CONGENB)
+			mdi_reg23 |= 0x0100;
+		DBG2 ( "DP83840 specific setup, setting register 23 to "
+		                                         "%hX.\n", mdi_reg23 );
+		ifec_mdio_write ( netdev, mdio_register & 0x1f, 23, mdi_reg23 );
+	}
+	DBG2 ( "dp83840 " );
+	if ( options != 0 ) {
+		ifec_mdio_write ( netdev, mdio_register & 0x1f, 0,
+		                           ( (options & 0x20) ? 0x2000 : 0 ) |
+		                           ( (options & 0x10) ? 0x0100 : 0 ) );
+		DBG2 ( "set mdio_register. " );
+	}
+}
+
+/*
+ * Support function: ifec_mdio_write
+ *
+ * This probably writes to the "physical media interface chip".
+ * -- REW
+ */
+static int ifec_mdio_write ( struct net_device *netdev,
+                             int phy_id, int location, int value )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+	int val;
+	int boguscnt = 64*4;     /* <64 usec. to complete, typ 27 ticks */
+
+	DBGP ( "ifec_mdio_write\n" );
+
+	outl ( 0x04000000 | ( location << 16 ) | ( phy_id << 21 ) | value,
+	       ioaddr + CSRCtrlMDI );
+	do {
+		udelay ( 16 );
+
+		val = inl ( ioaddr + CSRCtrlMDI );
+		if ( --boguscnt < 0 ) {
+			DBG ( " ifec_mdio_write() time out with val = %X.\n",
+			      val );
+			break;
+		}
+	} while (! ( val & 0x10000000 ) );
+	return val & 0xffff;
+}
+
+/*
+ * Resets the hardware.
+ *
+ * @v netdev		Network device
+ */
+static void ifec_reset ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+
+	DBGP ( "ifec_reset\n" );
+
+	/* do partial reset first */
+	outl ( PortPartialReset, ioaddr + CSRPort );
+	inw ( ioaddr + SCBStatus );
+	udelay ( 20 );
+
+	/* full reset */
+	outl ( PortReset, ioaddr + CSRPort );
+	inw ( ioaddr + SCBStatus );
+	udelay ( 20 );
+
+	/* disable interrupts again */
+	ifec_net_irq ( netdev, 0 );
+}
+
+/*
+ * free()s the tx/rx rings.
+ *
+ * @v netdev		Network device
+ */
+static void ifec_free ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev_priv ( netdev );
+	int i;
+
+	DBGP ( "ifec_free\n" );
+
+	/* free all allocated receive io_buffers */
+	for ( i = 0; i < RFD_COUNT; i++ ) {
+		free_iob ( priv->rx_iobs[i] );
+		priv->rx_iobs[i] = NULL;
+		priv->rfds[i] = NULL;
+	}
+
+	/* free TX ring buffer */
+	free_dma ( priv->tcbs, TX_RING_BYTES );
+
+	priv->tcbs = NULL;
+}
+
+/*
+ * Initializes an RFD.
+ *
+ * @v rfd    		RFD struct to initialize
+ * @v command		Command word
+ * @v link   		Link value
+ */
+static void ifec_rfd_init ( struct ifec_rfd *rfd, s16 command, u32 link )
+{
+	DBGP ( "ifec_rfd_init\n" );
+
+	rfd->status      = 0;
+	rfd->command     = command;
+	rfd->rx_buf_addr = 0xFFFFFFFF;
+	rfd->count       = 0;
+	rfd->size        = RFD_PACKET_LEN;
+	rfd->link        = link;
+}
+
+/*
+ * Send address of new RFD to card
+ *
+ * @v netdev		Network device
+ */
+static void ifec_reprime_ru ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	int cur_rx = priv->cur_rx;
+	
+	DBGP ( "ifec_reprime_ru\n" );
+	
+	if ( priv->rfds[cur_rx] != NULL ) {
+		ifec_scb_cmd ( netdev, virt_to_bus ( priv->rfds[cur_rx] ),
+			       RUStart );
+		ifec_scb_cmd_wait ( netdev );
+	}
+}
+
+/*
+ * Check if reprime of RU needed
+ *
+ * @v netdev		Network device
+ */
+static void ifec_check_ru_status ( struct net_device *netdev,
+				   unsigned short intr_status )
+{
+	struct ifec_private *priv = netdev->priv;
+
+	DBGP ( "ifec_check_ru_status\n" );
+
+	/*
+	* The chip may have suspended reception for various reasons.
+	* Check for that, and re-prime it should this be the case.
+	*/
+	switch ( ( intr_status >> 2 ) & 0xf ) {
+		case 0:  /* Idle */
+		case 4:  /* Ready */
+			break;
+		case 1:  /* Suspended */
+		case 2:  /* No resources (RFDs) */
+		case 9:  /* Suspended with no more RBDs */
+		case 10: /* No resources due to no RBDs */
+		case 12: /* Ready with no RBDs */
+			DBG ( "ifec_net_poll: RU reprimed.\n" );
+			ifec_reprime_ru ( netdev );
+			break;
+		default:
+			/* reserved values */
+			DBG ( "ifec_net_poll: RU state anomaly: %i\n",
+			      ( inw ( priv->ioaddr + SCBStatus ) >> 2 ) & 0xf );
+			break;
+	}
+}
+
+#define RFD_STATUS ( RFD_OK | RFDRxCol | RFDRxErr | RFDShort | \
+		     RFDDMAOverrun | RFDNoBufs | RFDCRCError )
+/*
+ * Looks for received packets in the rx ring, reports success or error to
+ * the core accordingly. Starts reallocation of rx ring.
+ *
+ * @v netdev		Network device
+ */
+static void ifec_rx_process ( struct net_device *netdev )
+{
+	struct ifec_private *priv   = netdev->priv;
+	int cur_rx = priv->cur_rx;
+	struct io_buffer *iob = priv->rx_iobs[cur_rx];
+	struct ifec_rfd *rfd = priv->rfds[cur_rx];
+	unsigned int rx_len;
+	s16 status;
+
+	DBGP ( "ifec_rx_process\n" );
+
+	/* Process any received packets */
+	while ( iob && rfd && ( status = rfd->status ) ) {
+		rx_len = rfd->count & RFDMaskCount;
+
+		DBG2 ( "Got a packet: Len = %d, cur_rx = %d.\n", rx_len,
+		       cur_rx );
+		DBGIO_HD ( (void*)rfd->packet, 0x30 );
+
+		if ( ( status & ( RFD_STATUS & ~RFDShort ) ) != RFD_OK ) {
+			DBG ( "Corrupted packet received. "
+			      "Status = %#08hx\n", status );
+			netdev_rx_err ( netdev, iob, -EINVAL );
+		} else {
+			/* Hand off the packet to the network subsystem */
+			iob_put ( iob, rx_len );
+			DBG2 ( "Received packet: %p, len: %d\n", iob, rx_len );
+			netdev_rx ( netdev, iob );
+		}
+
+		/* make sure we don't reuse this RFD */
+		priv->rx_iobs[cur_rx] = NULL;
+		priv->rfds[cur_rx] = NULL;
+
+		/* Next RFD */
+		priv->cur_rx = ( cur_rx + 1 ) % RFD_COUNT;
+		cur_rx = priv->cur_rx;
+		iob = priv->rx_iobs[cur_rx];
+		rfd = priv->rfds[cur_rx];
+	}
+
+	ifec_refill_rx_ring ( netdev );
+}
+
+/*
+ * Allocates io_buffer, set pointers in ifec_private structure accordingly,
+ * reserves space for RFD header in io_buffer.
+ *
+ * @v netdev		Network device
+ * @v cur		Descriptor number to work on
+ * @v cmd		Value to set cmd field in RFD to
+ * @v link		Pointer to ned RFD
+ * @ret rc		0 on success, negative on failure
+ */
+static int ifec_get_rx_desc ( struct net_device *netdev, int cur, int cmd,
+			      int link )
+{
+	struct ifec_private *priv = netdev->priv;
+	struct ifec_rfd *rfd  = priv->rfds[cur];
+
+	DBGP ( "ifec_get_rx_desc\n" );
+
+	priv->rx_iobs[cur] = alloc_iob ( sizeof ( *rfd ) );
+	if ( ! priv->rx_iobs[cur] ) {
+		DBG ( "alloc_iob failed. desc. nr: %d\n", cur );
+		priv->rfds[cur] = NULL;
+		return -ENOMEM;
+	}
+
+	/* Initialize new tail. */
+	priv->rfds[cur] = priv->rx_iobs[cur]->data;
+	ifec_rfd_init ( priv->rfds[cur], cmd, link );
+	iob_reserve ( priv->rx_iobs[cur], RFD_HEADER_LEN );
+
+	return 0;
+}
+
+/*
+ * Allocate new descriptor entries and initialize them if needed
+ *
+ * @v netdev		Network device
+ */
+static void ifec_refill_rx_ring ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	int i, cur_rx;
+	unsigned short intr_status;
+
+	DBGP ( "ifec_refill_rx_ring\n" );
+
+	for ( i = 0; i < RFD_COUNT; i++ ) {
+		cur_rx = ( priv->cur_rx + i ) % RFD_COUNT;
+		/* only refill if empty */
+		if ( priv->rfds[cur_rx] != NULL ||
+		     priv->rx_iobs[cur_rx] != NULL )
+			continue;
+
+		DBG2 ( "refilling RFD %d\n", cur_rx );
+
+		if ( ifec_get_rx_desc ( netdev, cur_rx,
+		     CmdSuspend | CmdEndOfList, 0 ) == 0 ) {
+			if ( i > 0 ) {
+				int prev_rx = ( ( ( cur_rx + RFD_COUNT ) - 1 )
+						% RFD_COUNT );
+				struct ifec_rfd *rfd = priv->rfds[prev_rx];
+
+				rfd->command = 0;
+				rfd->link = virt_to_bus ( priv->rfds[cur_rx] );
+			}
+		}
+	}
+
+	intr_status = inw ( priv->ioaddr + SCBStatus );
+	ifec_check_ru_status ( netdev, intr_status );
+}
+
+/*
+ * Initial allocation & initialization of the rx ring.
+ *
+ * @v netdev  		Device of rx ring.
+ * @ret rc    		Non-zero if error occured
+ */
+static int ifec_rx_setup ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	int i;
+
+	DBGP ( "ifec_rx_setup\n" );
+
+	priv->cur_rx = 0;
+
+	/* init values for ifec_refill_rx_ring() */
+	for ( i = 0; i < RFD_COUNT; i++ ) {
+		priv->rfds[i] = NULL;
+		priv->rx_iobs[i] = NULL;
+	}
+	ifec_refill_rx_ring ( netdev );
+
+	return 0;
+}
+
+/*
+ * Initiates a SCB command.
+ *
+ * @v netdev		Network device
+ * @v ptr   		General pointer value for command.
+ * @v cmd   		Command to issue.
+ * @ret rc  		Non-zero if command not issued.
+ */
+static int ifec_scb_cmd ( struct net_device *netdev, u32 ptr, u8 cmd )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+	int rc;
+
+	DBGP ( "ifec_scb_cmd\n" );
+
+	rc = ifec_scb_cmd_wait ( netdev );	/* Wait until ready */
+	if ( !rc ) {
+		outl ( ptr, ioaddr + SCBPointer );
+		outb ( cmd, ioaddr + SCBCmd );		/* Issue command */
+	}
+	return rc;
+}
+
+/*
+ * Wait for command unit to accept a command.
+ *
+ * @v cmd_ioaddr	I/O address of command register.
+ * @ret rc      	Non-zero if command timed out.
+ */
+static int ifec_scb_cmd_wait ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long cmd_ioaddr = priv->ioaddr + SCBCmd;
+	int rc, wait = CU_CMD_TIMEOUT;
+
+	DBGP ( "ifec_scb_cmd_wait\n" );
+
+	for ( ; wait && ( rc = inb ( cmd_ioaddr ) ); wait-- )
+		udelay ( 1 );
+
+	if ( !wait )
+		DBG ( "ifec_scb_cmd_wait timeout!\n" );
+	return rc;
+}
+
+/*
+ * Check status of transmitted packets & perform tx completions.
+ *
+ * @v netdev    	Network device.
+ */
+static void ifec_tx_process ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	struct ifec_tcb *tcb = priv->tcb_tail;
+	s16 status;
+
+	DBGP ( "ifec_tx_process\n" );
+
+	/* Check status of transmitted packets */
+	while ( ( status = tcb->status ) && tcb->iob ) {
+		if ( status & TCB_U ) {
+			/* report error to iPXE */
+			DBG ( "ifec_tx_process : tx error!\n " );
+			netdev_tx_complete_err ( netdev, tcb->iob, -EINVAL );
+		} else {
+			/* report successful transmit */
+			netdev_tx_complete ( netdev, tcb->iob );
+		}
+		DBG2 ( "tx completion\n" );
+
+		tcb->iob = NULL;
+		tcb->status = 0;
+
+		priv->tcb_tail = tcb->next;	/* Next TCB */
+		tcb = tcb->next;
+	}
+}
+
+/*
+ * Allocates & initialize tx resources.
+ *
+ * @v netdev    	Network device.
+ * @ret rc      	Non-zero if error occurred.
+ */
+static int ifec_tx_setup ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	struct ifec_tcb *tcb;
+	int i;
+
+	DBGP ( "ifec_tx_setup\n" );
+
+	/* allocate tx ring */
+	priv->tcbs = malloc_dma ( TX_RING_BYTES, CB_ALIGN );
+	if ( !priv->tcbs ) {
+		DBG ( "TX-ring allocation failed\n" );
+		return -ENOMEM;
+	}
+
+	tcb = priv->tcb_tail = priv->tcbs;
+	priv->tx_curr = priv->tx_tail = 0;
+	priv->tx_cnt = 0;
+
+	for ( i = 0; i < TCB_COUNT; i++, tcb++ ) {
+		tcb->status    = 0;
+		tcb->count     = 0x01208000;
+		tcb->iob       = NULL;
+		tcb->tbda_addr = virt_to_bus ( &tcb->tbd_addr0 );
+		tcb->link      = virt_to_bus ( tcb + 1 );
+		tcb->next      = tcb + 1;
+	}
+	/* We point tcb_head at the last TCB, so the first ifec_net_transmit()
+	 * will use the first (head->next) TCB to transmit. */
+	priv->tcb_head = --tcb;
+	tcb->link = virt_to_bus ( priv->tcbs );
+	tcb->next = priv->tcbs;
+	
+	return 0;
+}
+
+/*
+ * Wake up the Command Unit and issue a Resume/Start.
+ *
+ * @v netdev		Network device containing Command Unit
+ *
+ * The time between clearing the S bit and issuing Resume must be as short as
+ * possible to prevent a race condition. As noted in linux eepro100.c :
+ *   Note: Watch out for the potential race condition here: imagine
+ *	erasing the previous suspend
+ *		the chip processes the previous command
+ *		the chip processes the final command, and suspends
+ *	doing the CU_RESUME
+ *		the chip processes the next-yet-valid post-final-command.
+ *   So blindly sending a CU_RESUME is only safe if we do it immediately after
+ *   erasing the previous CmdSuspend, without the possibility of an intervening
+ *   delay.
+ */
+void ifec_tx_wake ( struct net_device *netdev )
+{
+	struct ifec_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->ioaddr;
+	struct ifec_tcb *tcb = priv->tcb_head->next;
+
+	DBGP ( "ifec_tx_wake\n" );
+
+	/* For the special case of the first transmit, we issue a START. The
+	 * card won't RESUME after the configure command. */
+	if ( priv->configured ) {
+		priv->configured = 0;
+		ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart );
+		ifec_scb_cmd_wait ( netdev );
+		return;
+	}
+
+	/* Resume if suspended. */
+	switch ( ( inw ( ioaddr + SCBStatus ) >> 6 ) & 0x3 ) {
+	case 0:  /* Idle - We should not reach this state. */
+		DBG2 ( "ifec_tx_wake: tx idle!\n" );
+		ifec_scb_cmd ( netdev, virt_to_bus ( tcb ), CUStart );
+		ifec_scb_cmd_wait ( netdev );
+		return;
+	case 1:  /* Suspended */
+		DBG2 ( "s" );
+		break;
+	default: /* Active */
+		DBG2 ( "a" );
+	}
+	ifec_scb_cmd_wait ( netdev );
+	outl ( 0, ioaddr + SCBPointer );
+	priv->tcb_head->command &= ~CmdSuspend;
+	/* Immediately issue Resume command */
+	outb ( CUResume, ioaddr + SCBCmd );
+	ifec_scb_cmd_wait ( netdev );
+}
+
+/*********************************************************************/
+
+static struct pci_device_id ifec_nics[] = {
+PCI_ROM(0x8086, 0x1029, "id1029",        "Intel EtherExpressPro100 ID1029", 0),
+PCI_ROM(0x8086, 0x1030, "id1030",        "Intel EtherExpressPro100 ID1030", 0),
+PCI_ROM(0x8086, 0x1031, "82801cam",      "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x1032, "eepro100-1032", "Intel PRO/100 VE Network Connection", 0),
+PCI_ROM(0x8086, 0x1033, "eepro100-1033", "Intel PRO/100 VM Network Connection", 0),
+PCI_ROM(0x8086, 0x1034, "eepro100-1034", "Intel PRO/100 VM Network Connection", 0),
+PCI_ROM(0x8086, 0x1035, "eepro100-1035", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x1036, "eepro100-1036", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x1037, "eepro100-1037", "Intel 82801CAM (ICH3) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x1038, "id1038",        "Intel PRO/100 VM Network Connection", 0),
+PCI_ROM(0x8086, 0x1039, "82562et",       "Intel PRO100 VE 82562ET", 0),
+PCI_ROM(0x8086, 0x103a, "id103a",        "Intel Corporation 82559 InBusiness 10/100", 0),
+PCI_ROM(0x8086, 0x103b, "82562etb",      "Intel PRO100 VE 82562ETB", 0),
+PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection", 0),
+PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection", 0),
+PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection", 0),
+PCI_ROM(0x8086, 0x1051, "prove",         "Intel PRO/100 VE Network Connection", 0),
+PCI_ROM(0x8086, 0x1059, "82551qm",       "Intel PRO/100 M Mobile Connection", 0),
+PCI_ROM(0x8086, 0x1209, "82559er",       "Intel EtherExpressPro100 82559ER", 0),
+PCI_ROM(0x8086, 0x1227, "82865",         "Intel 82865 EtherExpress PRO/100A", 0),
+PCI_ROM(0x8086, 0x1228, "82556",         "Intel 82556 EtherExpress PRO/100 Smart", 0),
+PCI_ROM(0x8086, 0x1229, "eepro100",      "Intel EtherExpressPro100", 0),
+PCI_ROM(0x8086, 0x2449, "82562em",       "Intel EtherExpressPro100 82562EM", 0),
+PCI_ROM(0x8086, 0x2459, "82562-1",       "Intel 82562 based Fast Ethernet Connection", 0),
+PCI_ROM(0x8086, 0x245d, "82562-2",       "Intel 82562 based Fast Ethernet Connection", 0),
+PCI_ROM(0x8086, 0x1050, "82562ez",       "Intel 82562EZ Network Connection", 0),
+PCI_ROM(0x8086, 0x1051, "eepro100-1051", "Intel 82801EB/ER (ICH5/ICH5R) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x1065, "82562-3",       "Intel 82562 based Fast Ethernet Connection", 0),
+PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0),
+PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0),
+PCI_ROM(0x8086, 0x1092, "82562-3",       "Intel Pro/100 VE Network", 0),
+PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0),
+};
+
+/* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need
+ * a workaround for hardware bug on 10 mbit half duplex (see linux driver eepro100.c)
+ * 2003/03/17 gbaum */
+
+struct pci_driver ifec_driver __pci_driver = {
+	.ids      = ifec_nics,
+	.id_count = ( sizeof (ifec_nics) / sizeof (ifec_nics[0]) ),
+	.probe    = ifec_pci_probe,
+	.remove   = ifec_pci_remove
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.h
new file mode 100644
index 0000000..3f72f59
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/eepro100.h
@@ -0,0 +1,204 @@
+
+#ifndef __EEPRO100_H_
+#define __EEPRO100_H_
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define CONGENB         0	/* Enable congestion control in the DP83840. */
+#define TX_FIFO         8	/* Tx FIFO threshold in 4 byte units, 0-15 */
+#define RX_FIFO         8	/* Rx FIFO threshold, default 32 bytes. */
+#define TX_DMA_COUNT    0	/* Tx DMA burst length, 0-127, default 0. */
+#define RX_DMA_COUNT    0	/* Rx DMA length, 0 means no preemption. */
+#define CU_CMD_TIMEOUT  1000	/* CU command accept timeout in microseconds */
+#define LINK_CHECK_PERIOD 1000	/* # of poll() calls between link checks */
+
+#define RFD_PACKET_LEN  1518
+#define RFD_IOB_LEN     1536
+#define RFD_HEADER_LEN  16
+#define CB_ALIGN        2	/* Alignment of command blocks */
+
+#define RFD_COUNT       4
+#define TCB_COUNT       4
+#define RX_RING_BYTES   ( RFD_COUNT * sizeof ( struct ifec_rfd ) )
+#define TX_RING_BYTES   ( TCB_COUNT * sizeof ( struct ifec_tcb ) )
+
+/* some EEPROM addresses */
+#define EEPROM_ADDR_MAC_0		0
+#define EEPROM_ADDR_MDIO_REGISTER	6
+
+/* Control / Status Register byte offsets - SDM Table 11 */
+enum CSROffsets {
+	SCBStatus=0,             SCBCmd=2,              SCBPointer = 4,
+	CSRPort=8,               CSRFlash=12,           CSREeprom = 14,
+	CSRCtrlMDI=16,           CSREarlyRx=20
+};
+
+/* System Control Block Command Word - SDM Table 12 */
+enum SCBCmdBits {
+	/* SCB Interrupt Masks - SDM Table 14 */
+	SCBMaskCmdDone=0x8000,   SCBMaskRxDone=0x4000,  SCBMaskCmdIdle=0x2000,
+	SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
+	SCBTriggerIntr=0x0200,   SCBMaskAll=0x0100,
+	/* SCB Control Commands - SDM Table 14-16 */
+	CUStart=0x0010,          CUResume=0x0020,       CUStatsAddr=0x0040,
+	CUShowStats=0x0050,      CUCmdBase=0x0060,      CUDumpStats=0x0070,
+	RUStart=0x0001,          RUResume=0x0002,       RUAbort=0x0004,
+	RUAddrLoad=0x0006,       RUResumeNoResources=0x0007
+};
+
+enum SCBPortCmds {
+	PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3
+};
+
+/* Action Commands - SDM Table 14,37 */
+enum ActionCommands {
+	CmdNOp = 0,              CmdIASetup = 1,        CmdConfigure = 2,
+	CmdMulticastList = 3,    CmdTx = 4,             CmdTDR = 5,
+	CmdDump = 6,             CmdDiagnose = 7,
+	/* And some extra flags: */
+	CmdEndOfList = 0x8000,
+	CmdSuspend = 0x4000,     CmdIntr = 0x2000,      CmdTxFlex = 0x0008
+};
+
+enum TCBBits {
+	TCB_C=0x8000,            TCB_OK=0x2000,         TCB_U=0x1000
+};
+
+enum RFDBits {
+	/* Status Word Bits */
+	RFDRxCol=0x0001,         RFDIAMatch=0x0002,     RFDNoMatch=0x0004,
+	RFDReserved3=0x0008,     RFDRxErr=0x0010,       RFDEthType=0x0020,
+	RFDReserved6=0x0040,     RFDShort=0x0080,       RFDDMAOverrun=0x0100,
+	RFDNoBufs=0x0200,        RFDCRCAlign=0x0400,    RFDCRCError=0x0800,
+	RFDReserved12=0x1000,    RFD_OK=0x2000,         RFDComplete=0x8000,
+	/* Command Word Bits */
+	//RFD_SF=0x0008,           RFDSuspend=0x4000,     RFDEndOfList=0x8000,
+	/* Other */
+	RFDMaskCount=0x3FFF
+};
+
+enum phy_chips {
+	NonSuchPhy=0,            I82553AB,              I82553C,
+	I82503,                  DP83840,               S80C240,
+	S80C24,                  PhyUndefined,          DP83840A=10
+};
+
+/* Serial EEPROM section.
+   A "bit" grungy, but we work our way through bit-by-bit :->. */
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK    0x01    /* EEPROM shift clock. */
+#define EE_CS           0x02    /* EEPROM chip select. */
+#define EE_DATA_WRITE   0x04    /* EEPROM chip data in. */
+#define EE_DATA_READ    0x08    /* EEPROM chip data out. */
+#define EE_ENB          ( 0x4800 | EE_CS )
+
+/* Elements of the dump_statistics block. This block must be lword aligned. */
+struct ifec_stats {
+	u32
+	tx_good_frames,          tx_coll16_errs,        tx_late_colls,
+	tx_underruns,            tx_lost_carrier,       tx_deferred,
+	tx_one_colls,            tx_multi_colls,        tx_total_colls,
+	rx_good_frames,          rx_crc_errs,           rx_align_errs,
+	rx_resource_errs,        rx_overrun_errs,       rx_colls_errs,
+	rx_runt_errs,            done_marker;
+};
+
+struct ifec_tcb {                  /* A Transmit Command Block & TBD. Must be */
+	volatile s16 status;       /*             word (even address) aligned */
+	u16          command;
+	u32          link;         /* PHYSICAL next ifec_tcb, doesn't change */
+	u32          tbda_addr;    /* TBD Array, points to TBD below */
+	s32          count;        /* # of TBD, Tx start thresh., etc. */
+	/* The following constitutes a Transmit Buffer Descriptor (TBD).
+	 * TBDs must be aligned on an even address (word-aligned). */
+	u32          tbd_addr0;    /* PHYSICAL ptr to Tx data */
+	s32          tbd_size0;    /* Length of Tx data */
+	/* Driver-specific data; not part of TCB format. */
+	struct io_buffer *iob;     /* Exists from tx() to completion poll() */
+	struct ifec_tcb  *next;    /* VIRTUAL next ifec_tcb, doesn't change */
+};
+
+struct ifec_rfd {              /* A Receive Frame Descriptor. Must be aligned */
+	volatile s16 status;   /*           on a physical word (even address) */
+	s16          command;
+	u32          link;          /* PHYSICAL next ifec_rfd, doesn't change */
+	u32          rx_buf_addr;   /* Unused. Flex rx mode is not documented */
+	u16          count;         /*                  and may be impossible */
+	u16          size;
+	char         packet[RFD_PACKET_LEN];
+};
+
+struct ifec_ias {              /* Individual Address Setup command block. */
+	volatile s16 status;   /* Must be word (even address) aligned. */
+	u16          command;
+	u32          link;     /* PHYSICAL next command block to process */
+	u8           ia[6];
+};
+
+struct ifec_cfg {                   /* The configure command format. */
+	volatile s16 status;
+	u16          command;
+	u32          link;          /* PHYSICAL next command block to process */
+	u8           byte[22];      /* 22 configuration bytes */
+};
+
+struct ifec_private {
+	unsigned long         ioaddr;
+	struct ifec_stats     stats;
+	unsigned short        mdio_register;
+
+	struct ifec_tcb      *tcbs;
+	struct ifec_rfd      *rfds[RFD_COUNT];
+	struct ifec_tcb      *tcb_head, *tcb_tail;
+	struct io_buffer     *tx_iobs[TCB_COUNT];
+	struct io_buffer     *rx_iobs[RFD_COUNT];
+	int		      cur_rx;
+	int		      tx_curr;
+	int		      tx_tail;
+	int		      tx_cnt;
+	/*
+	 * The configured flag indicates if a Config command was last issued.
+	 * The following attempt to issue a command (in ifec_tx_wake) will
+	 * use a START rather than RESUME SCB command. It seems the card won't
+	 * RESUME after a configure command.
+	 */
+	int                   configured;
+	struct spi_bit_basher spi;
+	struct spi_device     eeprom;
+	
+};
+
+/**************************** Function prototypes ****************************/
+
+/* PCI device API prototypes */
+static int  ifec_pci_probe  ( struct pci_device *pci );
+static void ifec_pci_remove ( struct pci_device *pci );
+
+/* Network device API prototypes */
+static void ifec_net_close    ( struct net_device* );
+static void ifec_net_irq      ( struct net_device*, int enable );
+static int  ifec_net_open     ( struct net_device* );
+static void ifec_net_poll     ( struct net_device* );
+static int  ifec_net_transmit ( struct net_device*, struct io_buffer *iobuf );
+
+/* Local function prototypes */
+static void ifec_init_eeprom     ( struct net_device * );
+static int  ifec_mdio_read       ( struct net_device *, int phy, int location );
+static void ifec_mdio_setup      ( struct net_device *, int options );
+static int  ifec_mdio_write      ( struct net_device *, int phy, int loc, int val);
+static void ifec_reset           ( struct net_device * );
+static void ifec_free            ( struct net_device * );
+static void ifec_rfd_init        ( struct ifec_rfd *rfd, s16 command, u32 link );
+static void  ifec_rx_process     ( struct net_device * );
+static void ifec_reprime_ru      ( struct net_device * );
+static void ifec_check_ru_status ( struct net_device *, unsigned short );
+static int  ifec_get_rx_desc     ( struct net_device *, int ,int ,int );
+static void ifec_refill_rx_ring  ( struct net_device * );
+static int  ifec_rx_setup        ( struct net_device * );
+static int  ifec_scb_cmd         ( struct net_device *, u32 ptr, u8 cmd );
+static int  ifec_scb_cmd_wait    ( struct net_device * );
+static void ifec_tx_process      ( struct net_device * );
+static int  ifec_tx_setup        ( struct net_device * );
+static void ifec_tx_wake         ( struct net_device * );
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snp.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snp.h
new file mode 100644
index 0000000..4d6b101
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snp.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _SNP_H
+#define _SNP_H
+
+/** @file
+ *
+ * SNP driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/device.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
+
+/** A network device that consumes the EFI Simple Network Protocol */
+struct snp_device {
+	/** Underlying simple network protocol instance */
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+
+	/** Generic device */
+	struct device dev;
+
+	/** Network device */
+	struct net_device *netdev;
+
+	/** State to put the snp in when removing the device */
+	uint32 removal_state;
+};
+
+#endif /* _SNP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.c
new file mode 100644
index 0000000..b725d40
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <string.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
+#include "snp.h"
+#include "snpnet.h"
+
+/** @file
+ *
+ * SNP network device driver
+ *
+ */
+
+/** SNP net device structure */
+struct snpnet_device {
+	/** The underlying simple network protocol */
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+
+	/** State that the SNP should be in after close */
+	UINT32 close_state;
+};
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int snpnet_transmit ( struct net_device *netdev,
+			     struct io_buffer *iobuf ) {
+	struct snpnet_device *snpnetdev = netdev->priv;
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
+	EFI_STATUS efirc;
+	size_t len = iob_len ( iobuf );
+
+	efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, NULL );
+	return EFIRC_TO_RC ( efirc );
+}
+
+/**
+ * Find a I/O buffer on the list of outstanding Tx buffers and complete it.
+ *
+ * @v snpnetdev		SNP network device
+ * @v txbuf		Buffer address
+ */
+static void snpnet_complete ( struct net_device *netdev, void *txbuf ) {
+	struct io_buffer *tmp;
+	struct io_buffer *iobuf;
+
+	list_for_each_entry_safe ( iobuf, tmp, &netdev->tx_queue, list ) {
+		if ( iobuf->data == txbuf ) {
+			netdev_tx_complete ( netdev, iobuf );
+			break;
+		}
+	}
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void snpnet_poll ( struct net_device *netdev ) {
+	struct snpnet_device *snpnetdev = netdev->priv;
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
+	EFI_STATUS efirc;
+	struct io_buffer *iobuf = NULL;
+	UINTN len;
+	void *txbuf;
+
+	/* Process Tx completions */
+	while ( 1 ) {
+		efirc = snp->GetStatus ( snp, NULL, &txbuf );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not get status %s\n", snp,
+			       efi_strerror ( efirc ) );
+			break;
+		}
+
+		if ( txbuf == NULL )
+			break;
+
+		snpnet_complete ( netdev, txbuf );
+	}
+
+	/* Process received packets */
+	while ( 1 ) {
+		/* The spec is not clear if the max packet size refers to the
+		 * payload or the entire packet including headers. The Receive
+		 * function needs a buffer large enough to contain the headers,
+		 * and potentially a 4-byte CRC and 4-byte VLAN tag (?), so add
+		 * some breathing room.
+		 */
+		len = snp->Mode->MaxPacketSize + ETH_HLEN + 8;
+		iobuf = alloc_iob ( len );
+		if ( iobuf == NULL ) {
+			netdev_rx_err ( netdev, NULL, -ENOMEM );
+			break;
+		}
+
+		efirc = snp->Receive ( snp, NULL, &len, iobuf->data,
+				       NULL, NULL, NULL );
+
+		/* No packets left? */
+		if ( efirc == EFI_NOT_READY ) {
+			free_iob ( iobuf );
+			break;
+		}
+
+		/* Other error? */
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p receive packet error: %s "
+				    "(len was %zd, is now %zd)\n",
+			       snp, efi_strerror ( efirc ), iob_len(iobuf),
+			       (size_t)len );
+			netdev_rx_err ( netdev, iobuf, efirc );
+			break;
+		}
+
+		/* Packet is valid, deliver it */
+		iob_put ( iobuf, len );
+		netdev_rx ( netdev, iob_disown ( iobuf ) );
+	}
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int snpnet_open ( struct net_device *netdev ) {
+	struct snpnet_device *snpnetdev = netdev->priv;
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
+	EFI_STATUS efirc;
+	UINT32 enableFlags, disableFlags;
+
+	snpnetdev->close_state = snp->Mode->State;
+	if ( snp->Mode->State != EfiSimpleNetworkInitialized ) {
+		efirc = snp->Initialize ( snp, 0, 0 );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not initialize: %s\n",
+			       snp, efi_strerror ( efirc ) );
+			return EFIRC_TO_RC ( efirc );
+		}
+	}
+
+        /* Use the default MAC address */
+	efirc = snp->StationAddress ( snp, FALSE,
+				      (EFI_MAC_ADDRESS *)netdev->ll_addr );
+	if ( efirc ) {
+		DBGC ( snp, "SNP %p could not reset station address: %s\n",
+		       snp, efi_strerror ( efirc ) );
+	}
+
+	/* Set up receive filters to receive unicast and broadcast packets
+	 * always. Also, enable either promiscuous multicast (if possible) or
+	 * promiscuous operation, in order to catch all multicast packets.
+	 */
+	enableFlags = snp->Mode->ReceiveFilterMask &
+		      ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+			EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
+	disableFlags = snp->Mode->ReceiveFilterMask &
+		       ( EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+			 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
+			 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST );
+	if ( snp->Mode->ReceiveFilterMask &
+	     EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST ) {
+		enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+	} else if ( snp->Mode->ReceiveFilterMask &
+		    EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS ) {
+		enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+	}
+	disableFlags &= ~enableFlags;
+	efirc = snp->ReceiveFilters ( snp, enableFlags, disableFlags,
+				      FALSE, 0, NULL );
+	if ( efirc ) {
+		DBGC ( snp, "SNP %p could not set receive filters: %s\n",
+		       snp, efi_strerror ( efirc ) );
+	}
+
+	DBGC ( snp, "SNP %p opened\n", snp );
+	return 0;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void snpnet_close ( struct net_device *netdev ) {
+	struct snpnet_device *snpnetdev = netdev->priv;
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
+	EFI_STATUS efirc;
+
+	if ( snpnetdev->close_state != EfiSimpleNetworkInitialized ) {
+		efirc = snp->Shutdown ( snp );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not shut down: %s\n",
+			       snp, efi_strerror ( efirc ) );
+		}
+	}
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev		Net device
+ * @v enable		Interrupts should be enabled
+ */
+static void snpnet_irq ( struct net_device *netdev, int enable ) {
+	struct snpnet_device *snpnetdev = netdev->priv;
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
+
+	/* On EFI, interrupts are never necessary. (This function is only
+	 * required for BIOS PXE.) If interrupts were required, they could be
+	 * simulated using a fast timer.
+	 */
+	DBGC ( snp, "SNP %p cannot %s interrupts\n",
+	       snp, ( enable ? "enable" : "disable" ) );
+}
+
+/** SNP network device operations */
+static struct net_device_operations snpnet_operations = {
+	.open		= snpnet_open,
+	.close		= snpnet_close,
+	.transmit	= snpnet_transmit,
+	.poll		= snpnet_poll,
+	.irq   		= snpnet_irq,
+};
+
+/**
+ * Probe SNP device
+ *
+ * @v snpdev		SNP device
+ * @ret rc		Return status code
+ */
+int snpnet_probe ( struct snp_device *snpdev ) {
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp;
+	EFI_STATUS efirc;
+	struct net_device *netdev;
+	struct snpnet_device *snpnetdev;
+	int rc;
+
+	DBGC ( snp, "SNP %p probing...\n", snp );
+
+	/* Allocate net device */
+	netdev = alloc_etherdev ( sizeof ( struct snpnet_device ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &snpnet_operations );
+	netdev->dev = &snpdev->dev;
+	snpdev->netdev = netdev;
+	snpnetdev = netdev->priv;
+	snpnetdev->snp = snp;
+	snpdev->removal_state = snp->Mode->State;
+
+	/* Start the interface */
+	if ( snp->Mode->State == EfiSimpleNetworkStopped ) {
+		efirc = snp->Start ( snp );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not start: %s\n", snp,
+			       efi_strerror ( efirc ) );
+			rc = EFIRC_TO_RC ( efirc );
+			goto err_start;
+		}
+	}
+
+	if ( snp->Mode->HwAddressSize > sizeof ( netdev->hw_addr ) ) {
+		DBGC ( snp, "SNP %p hardware address is too large\n", snp );
+		rc = -EINVAL;
+		goto err_hwaddr;
+	}
+	memcpy ( netdev->hw_addr, snp->Mode->PermanentAddress.Addr,
+		 snp->Mode->HwAddressSize );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register;
+
+	/* Mark as link up; we don't handle link state */
+	netdev_link_up ( netdev );
+
+	DBGC ( snp, "SNP %p added\n", snp );
+	return 0;
+
+err_register:
+err_hwaddr:
+	if ( snpdev->removal_state == EfiSimpleNetworkStopped )
+		snp->Stop ( snp );
+
+err_start:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	snpdev->netdev = NULL;
+	return rc;
+}
+
+/**
+ * Remove SNP device
+ *
+ * @v snpdev		SNP device
+ */
+void snpnet_remove ( struct snp_device *snpdev ) {
+	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp;
+	EFI_STATUS efirc;
+	struct net_device *netdev = snpdev->netdev;
+
+	if ( snp->Mode->State == EfiSimpleNetworkInitialized &&
+	     snpdev->removal_state != EfiSimpleNetworkInitialized ) {
+		DBGC ( snp, "SNP %p shutting down\n", snp );
+		efirc = snp->Shutdown ( snp );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not shut down: %s\n",
+			       snp, efi_strerror ( efirc ) );
+		}
+	}
+
+	if ( snp->Mode->State == EfiSimpleNetworkStarted &&
+	     snpdev->removal_state == EfiSimpleNetworkStopped ) {
+		DBGC ( snp, "SNP %p stopping\n", snp );
+		efirc = snp->Stop ( snp );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not be stopped\n", snp );
+		}
+	}
+
+	/* Unregister net device */
+	unregister_netdev ( netdev );
+
+	/* Free network device */
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+
+	DBGC ( snp, "SNP %p removed\n", snp );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.h
new file mode 100644
index 0000000..72b4a7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snpnet.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _SNPNET_H
+#define _SNPNET_H
+
+/** @file
+ *
+ * EFI Simple Network Protocol network device driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct snp_device;
+
+extern int snpnet_probe ( struct snp_device *snpdev );
+extern void snpnet_remove ( struct snp_device *snpdev );
+
+#endif /* _SNPNET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snponly.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snponly.c
new file mode 100644
index 0000000..6fcc54a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/efi/snponly.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/device.h>
+#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
+#include "snp.h"
+#include "snpnet.h"
+
+/** @file
+ *
+ * Chain-loading Simple Network Protocol Bus Driver
+ *
+ * This bus driver allows iPXE to use the EFI Simple Network Protocol provided
+ * by the platform to transmit and receive packets. It attaches to only the
+ * device handle that iPXE was loaded from, that is, it will only use the
+ * Simple Network Protocol on the current loaded image's device handle.
+ *
+ * Eseentially, this driver provides the EFI equivalent of the "undionly"
+ * driver.
+ */
+
+/** The one and only SNP network device */
+static struct snp_device snponly_dev;
+
+/** EFI simple network protocol GUID */
+static EFI_GUID efi_simple_network_protocol_guid
+	= EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
+
+/**
+ * Probe SNP root bus
+ *
+ * @v rootdev		SNP bus root device
+ *
+ * Look at the loaded image's device handle and see if the simple network
+ * protocol exists. If so, register a driver for it.
+ */
+static int snpbus_probe ( struct root_device *rootdev ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_STATUS efirc;
+	int rc;
+	void *snp;
+
+	efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle,
+				   &efi_simple_network_protocol_guid,
+				   &snp, efi_image_handle, NULL,
+				   EFI_OPEN_PROTOCOL_GET_PROTOCOL );
+	if ( efirc ) {
+		DBG ( "Could not find Simple Network Protocol!\n" );
+		return -ENODEV;
+	}
+	snponly_dev.snp = snp;
+
+	/* Add to device hierarchy */
+	strncpy ( snponly_dev.dev.name, "EFI SNP",
+		  ( sizeof ( snponly_dev.dev.name ) - 1 ) );
+	snponly_dev.dev.parent = &rootdev->dev;
+	list_add ( &snponly_dev.dev.siblings, &rootdev->dev.children);
+	INIT_LIST_HEAD ( &snponly_dev.dev.children );
+
+	/* Create network device */
+	if ( ( rc = snpnet_probe ( &snponly_dev ) ) != 0 )
+		goto err;
+
+	return 0;
+
+err:
+	list_del ( &snponly_dev.dev.siblings );
+	return rc;
+}
+
+/**
+ * Remove SNP root bus
+ *
+ * @v rootdev		SNP bus root device
+ */
+static void snpbus_remove ( struct root_device *rootdev __unused ) {
+	snpnet_remove ( &snponly_dev );
+	list_del ( &snponly_dev.dev.siblings );
+}
+
+/** SNP bus root device driver */
+static struct root_driver snp_root_driver = {
+	.probe = snpbus_probe,
+	.remove = snpbus_remove,
+};
+
+/** SNP bus root device */
+struct root_device snp_root_device __root_device = {
+	.dev = { .name = "EFI SNP" },
+	.driver = &snp_root_driver,
+};
+
+/**
+ * Prepare for exit
+ *
+ * @v booting		System is shutting down for OS boot
+ */
+static void snponly_shutdown ( int booting ) {
+	/* If we are shutting down to boot an OS, make sure the SNP does not
+	 * stay active.
+	 */
+	if ( booting )
+		snponly_dev.removal_state = EfiSimpleNetworkStopped;
+}
+
+struct startup_fn startup_snponly __startup_fn ( STARTUP_LATE ) = {
+	.shutdown = snponly_shutdown,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.c
new file mode 100644
index 0000000..5211317
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.c
@@ -0,0 +1,537 @@
+
+/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Etherboot */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* 05/06/2003	timlegge	Fixed relocation and implemented Multicast */
+#define LINUX_OUT_MACROS
+
+#include "etherboot.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include "nic.h"
+#include <ipxe/console.h>
+#include "epic100.h"
+
+/* Condensed operations for readability */
+#define virt_to_le32desc(addr)	cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)	bus_to_virt(le32_to_cpu(addr))
+
+#define TX_RING_SIZE	2	/* use at least 2 buffers for TX */
+#define RX_RING_SIZE	2
+
+#define PKT_BUF_SZ	1536	/* Size of each temporary Tx/Rx buffer.*/
+
+/*
+#define DEBUG_RX
+#define DEBUG_TX
+#define DEBUG_EEPROM
+*/
+
+#define EPIC_DEBUG 0	/* debug level */
+
+/* The EPIC100 Rx and Tx buffer descriptors. */
+struct epic_rx_desc {
+    unsigned long status;
+    unsigned long bufaddr;
+    unsigned long buflength;
+    unsigned long next;
+};
+/* description of the tx descriptors control bits commonly used */
+#define TD_STDFLAGS	TD_LASTDESC
+
+struct epic_tx_desc {
+    unsigned long status;
+    unsigned long bufaddr;
+    unsigned long buflength;
+    unsigned long  next;
+};
+
+#define delay(nanosec)   do { int _i = 3; while (--_i > 0) \
+                                     { __SLOW_DOWN_IO; }} while (0)
+
+static void	epic100_open(void);
+static void	epic100_init_ring(void);
+static void	epic100_disable(struct nic *nic);
+static int	epic100_poll(struct nic *nic, int retrieve);
+static void	epic100_transmit(struct nic *nic, const char *destaddr,
+				 unsigned int type, unsigned int len, const char *data);
+#ifdef	DEBUG_EEPROM
+static int	read_eeprom(int location);
+#endif
+static int	mii_read(int phy_id, int location);
+static void     epic100_irq(struct nic *nic, irq_action_t action);
+
+static struct nic_operations epic100_operations;
+
+static int	ioaddr;
+
+static int	command;
+static int	intstat;
+static int	intmask;
+static int	genctl ;
+static int	eectl  ;
+static int	test   ;
+static int	mmctl  ;
+static int	mmdata ;
+static int	lan0   ;
+static int	mc0    ;
+static int	rxcon  ;
+static int	txcon  ;
+static int	prcdar ;
+static int	ptcdar ;
+static int	eththr ;
+
+static unsigned int	cur_rx, cur_tx;		/* The next free ring entry */
+#ifdef	DEBUG_EEPROM
+static unsigned short	eeprom[64];
+#endif
+static signed char	phys[4];		/* MII device addresses. */
+struct {
+	struct epic_rx_desc	rx_ring[RX_RING_SIZE]
+	__attribute__ ((aligned(4)));
+	struct epic_tx_desc	tx_ring[TX_RING_SIZE]
+	__attribute__ ((aligned(4)));
+	unsigned char	 	rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
+	unsigned char		tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
+} epic100_bufs __shared;
+#define rx_ring epic100_bufs.rx_ring
+#define tx_ring epic100_bufs.tx_ring
+#define rx_packet epic100_bufs.rx_packet
+#define tx_packet epic100_bufs.tx_packet
+
+/***********************************************************************/
+/*                    Externally visible functions                     */
+/***********************************************************************/
+
+
+static int
+epic100_probe ( struct nic *nic, struct pci_device *pci ) {
+
+    int i;
+    unsigned short* ap;
+    unsigned int phy, phy_idx;
+
+    if (pci->ioaddr == 0)
+	return 0;
+
+    /* Ideally we would detect all network cards in slot order.  That would
+       be best done a central PCI probe dispatch, which wouldn't work
+       well with the current structure.  So instead we detect just the
+       Epic cards in slot order. */
+
+    ioaddr = pci->ioaddr;
+
+    nic->irqno  = 0;
+    nic->ioaddr = pci->ioaddr & ~3;
+
+    /* compute all used static epic100 registers address */
+    command = ioaddr + COMMAND;		/* Control Register */
+    intstat = ioaddr + INTSTAT;		/* Interrupt Status */
+    intmask = ioaddr + INTMASK;		/* Interrupt Mask */
+    genctl  = ioaddr + GENCTL;		/* General Control */
+    eectl   = ioaddr + EECTL;		/* EEPROM Control  */
+    test    = ioaddr + TEST;		/* Test register (clocks) */
+    mmctl   = ioaddr + MMCTL;		/* MII Management Interface Control */
+    mmdata  = ioaddr + MMDATA;		/* MII Management Interface Data */
+    lan0    = ioaddr + LAN0;		/* MAC address. (0x40-0x48) */
+    mc0     = ioaddr + MC0; 		/* Multicast Control */
+    rxcon   = ioaddr + RXCON;		/* Receive Control */
+    txcon   = ioaddr + TXCON;		/* Transmit Control */
+    prcdar  = ioaddr + PRCDAR;		/* PCI Receive Current Descr Address */
+    ptcdar  = ioaddr + PTCDAR;		/* PCI Transmit Current Descr Address */
+    eththr  = ioaddr + ETHTHR;		/* Early Transmit Threshold */
+
+    /* Reset the chip & bring it out of low-power mode. */
+    outl(GC_SOFT_RESET, genctl);
+
+    /* Disable ALL interrupts by setting the interrupt mask. */
+    outl(INTR_DISABLE, intmask);
+
+    /*
+     * set the internal clocks:
+     * Application Note 7.15 says:
+     *    In order to set the CLOCK TEST bit in the TEST register,
+     *	  perform the following:
+     *
+     *        Write 0x0008 to the test register at least sixteen
+     *        consecutive times.
+     *
+     * The CLOCK TEST bit is Write-Only. Writing it several times
+     * consecutively insures a successful write to the bit...
+     */
+
+    for (i = 0; i < 16; i++) {
+	outl(0x00000008, test);
+    }
+
+#ifdef	DEBUG_EEPROM
+{
+    unsigned short sum = 0;
+    unsigned short value;
+    for (i = 0; i < 64; i++) {
+	value = read_eeprom(i);
+	eeprom[i] = value;
+	sum += value;
+    }
+}
+
+#if	(EPIC_DEBUG > 1)
+    printf("EEPROM contents\n");
+    for (i = 0; i < 64; i++) {
+	printf(" %hhX%s", eeprom[i], i % 16 == 15 ? "\n" : "");
+    }
+#endif
+#endif
+
+    /* This could also be read from the EEPROM. */
+    ap = (unsigned short*)nic->node_addr;
+    for (i = 0; i < 3; i++)
+	*ap++ = inw(lan0 + i*4);
+
+    DBG ( " I/O %4.4x %s ", ioaddr, eth_ntoa ( nic->node_addr ) );
+
+    /* Find the connected MII xcvrs. */
+    for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(phys); phy++) {
+	int mii_status = mii_read(phy, 0);
+
+	if (mii_status != 0xffff  && mii_status != 0x0000) {
+	    phys[phy_idx++] = phy;
+#if	(EPIC_DEBUG > 1)
+	    printf("MII transceiver found at address %d.\n", phy);
+#endif
+	}
+    }
+    if (phy_idx == 0) {
+#if	(EPIC_DEBUG > 1)
+	printf("***WARNING***: No MII transceiver found!\n");
+#endif
+	/* Use the known PHY address of the EPII. */
+	phys[0] = 3;
+    }
+
+    epic100_open();
+    nic->nic_op	= &epic100_operations;
+
+    return 1;
+}
+
+static void set_rx_mode(void)
+{
+	unsigned char mc_filter[8];
+	int i;
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	outl(0x0C, rxcon);
+	for(i = 0; i < 4; i++)
+		outw(((unsigned short *)mc_filter)[i], mc0 + i*4);
+	return;
+}
+	
+   static void
+epic100_open(void)
+{
+    int mii_reg5;
+    unsigned long tmp;
+
+    epic100_init_ring();
+
+    /* Pull the chip out of low-power mode, and set for PCI read multiple. */
+    outl(GC_RX_FIFO_THR_64 | GC_MRC_READ_MULT | GC_ONE_COPY, genctl);
+
+    outl(TX_FIFO_THRESH, eththr);
+
+    tmp = TC_EARLY_TX_ENABLE | TX_SLOT_TIME;
+
+    mii_reg5 = mii_read(phys[0], 5);
+    if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) {
+	printf(" full-duplex mode");
+	tmp |= TC_LM_FULL_DPX;
+    } else
+	tmp |= TC_LM_NORMAL;
+
+    outl(tmp, txcon);
+
+    /* Give adress of RX and TX ring to the chip */
+    outl(virt_to_le32desc(&rx_ring), prcdar);
+    outl(virt_to_le32desc(&tx_ring), ptcdar);
+
+    /* Start the chip's Rx process: receive unicast and broadcast */
+    set_rx_mode();
+    outl(CR_START_RX | CR_QUEUE_RX, command);
+
+    putchar('\n');
+}
+
+/* Initialize the Rx and Tx rings. */
+    static void
+epic100_init_ring(void)
+{
+    int i;
+
+    cur_rx = cur_tx = 0;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	rx_ring[i].status    = cpu_to_le32(RRING_OWN);	/* Owned by Epic chip */
+	rx_ring[i].buflength = cpu_to_le32(PKT_BUF_SZ);
+	rx_ring[i].bufaddr   = virt_to_bus(&rx_packet[i * PKT_BUF_SZ]);
+	rx_ring[i].next      = virt_to_le32desc(&rx_ring[i + 1]) ;
+    }
+    /* Mark the last entry as wrapping the ring. */
+    rx_ring[i-1].next = virt_to_le32desc(&rx_ring[0]);
+
+    /*
+     *The Tx buffer descriptor is filled in as needed,
+     * but we do need to clear the ownership bit.
+     */
+
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	tx_ring[i].status  = 0x0000;			/* Owned by CPU */
+    	tx_ring[i].buflength = 0x0000 | cpu_to_le32(TD_STDFLAGS << 16);
+	tx_ring[i].bufaddr = virt_to_bus(&tx_packet[i * PKT_BUF_SZ]);
+	tx_ring[i].next    = virt_to_le32desc(&tx_ring[i + 1]);
+    }
+	tx_ring[i-1].next    = virt_to_le32desc(&tx_ring[0]);
+}
+
+/* function: epic100_transmit
+ * This transmits a packet.
+ *
+ * Arguments: char d[6]:          destination ethernet address.
+ *            unsigned short t:   ethernet protocol type.
+ *            unsigned short s:   size of the data-part of the packet.
+ *            char *p:            the data for the packet.
+ * returns:   void.
+ */
+    static void
+epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
+		 unsigned int len, const char *data)
+{
+    unsigned short nstype;
+    unsigned char *txp;
+    int entry;
+    unsigned long ct;
+
+    /* Calculate the next Tx descriptor entry. */
+    entry = cur_tx % TX_RING_SIZE;
+
+    if ((tx_ring[entry].status & TRING_OWN) == TRING_OWN) {
+	printf("eth_transmit: Unable to transmit. status=%4.4lx. Resetting...\n",
+	       tx_ring[entry].status);
+
+	epic100_open();
+	return;
+    }
+
+    txp = tx_packet + (entry * PKT_BUF_SZ);
+
+    memcpy(txp, destaddr, ETH_ALEN);
+    memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN);
+    nstype = htons(type);
+    memcpy(txp + 12, (char*)&nstype, 2);
+    memcpy(txp + ETH_HLEN, data, len);
+
+    len += ETH_HLEN;
+	len &= 0x0FFF;
+	while(len < ETH_ZLEN)
+		txp[len++] = '\0';
+    /*
+     * Caution: the write order is important here,
+     * set the base address with the "ownership"
+     * bits last.
+     */
+   
+    tx_ring[entry].buflength |= cpu_to_le32(len);
+    tx_ring[entry].status = cpu_to_le32(len << 16) |
+	    cpu_to_le32(TRING_OWN);	/* Pass ownership to the chip. */
+
+    cur_tx++;
+
+    /* Trigger an immediate transmit demand. */
+    outl(CR_QUEUE_TX, command);
+
+    ct = currticks();
+    /* timeout 10 ms for transmit */
+    while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) &&
+		ct + 10*1000 < currticks())
+	/* Wait */;
+
+    if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
+	printf("Oops, transmitter timeout, status=%4.4lX\n",
+	    tx_ring[entry].status);
+}
+
+/* function: epic100_poll / eth_poll
+ * This receives a packet from the network.
+ *
+ * Arguments: none
+ *
+ * returns:   1 if a packet was received.
+ *            0 if no pacet was received.
+ * side effects:
+ *            returns the packet in the array nic->packet.
+ *            returns the length of the packet in nic->packetlen.
+ */
+
+    static int
+epic100_poll(struct nic *nic, int retrieve)
+{
+    int entry;
+    int retcode;
+    int status;
+    entry = cur_rx % RX_RING_SIZE;
+
+    if ((rx_ring[entry].status & cpu_to_le32(RRING_OWN)) == RRING_OWN)
+	return (0);
+
+    if ( ! retrieve ) return 1;
+
+    status = le32_to_cpu(rx_ring[entry].status);
+    /* We own the next entry, it's a new packet. Send it up. */
+
+#if	(EPIC_DEBUG > 4)
+    printf("epic_poll: entry %d status %hX\n", entry, status);
+#endif
+
+    cur_rx++;
+    if (status & 0x2000) {
+	printf("epic_poll: Giant packet\n");
+	retcode = 0;
+    } else if (status & 0x0006) {
+	/* Rx Frame errors are counted in hardware. */
+	printf("epic_poll: Frame received with errors\n");
+	retcode = 0;
+    } else {
+	/* Omit the four octet CRC from the length. */
+	nic->packetlen = le32_to_cpu((rx_ring[entry].buflength))- 4;
+	memcpy(nic->packet, &rx_packet[entry * PKT_BUF_SZ], nic->packetlen);
+	retcode = 1;
+    }
+
+    /* Clear all error sources. */
+    outl(status & INTR_CLEARERRS, intstat);
+
+    /* Give the descriptor back to the chip */
+    rx_ring[entry].status = RRING_OWN;
+
+    /* Restart Receiver */
+    outl(CR_START_RX | CR_QUEUE_RX, command); 
+
+    return retcode;
+}
+
+
+static void epic100_disable ( struct nic *nic __unused ) {
+	/* Soft reset the chip. */
+	outl(GC_SOFT_RESET, genctl);
+}
+
+static void epic100_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+#ifdef	DEBUG_EEPROM
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS		0x02	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x08	/* EEPROM chip data in. */
+#define EE_WRITE_0	0x01
+#define EE_WRITE_1	0x09
+#define EE_DATA_READ	0x10	/* EEPROM chip data out. */
+#define EE_ENB		(0x0001 | EE_CS)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD	(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+#define eeprom_delay(n)	delay(n)
+
+    static int
+read_eeprom(int location)
+{
+    int i;
+    int retval = 0;
+    int read_cmd = location | EE_READ_CMD;
+
+    outl(EE_ENB & ~EE_CS, eectl);
+    outl(EE_ENB, eectl);
+
+    /* Shift the read command bits out. */
+    for (i = 10; i >= 0; i--) {
+	short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+	outl(EE_ENB | dataval, eectl);
+	eeprom_delay(100);
+	outl(EE_ENB | dataval | EE_SHIFT_CLK, eectl);
+	eeprom_delay(150);
+	outl(EE_ENB | dataval, eectl);	/* Finish EEPROM a clock tick. */
+	eeprom_delay(250);
+    }
+    outl(EE_ENB, eectl);
+
+    for (i = 16; i > 0; i--) {
+	outl(EE_ENB | EE_SHIFT_CLK, eectl);
+	eeprom_delay(100);
+	retval = (retval << 1) | ((inl(eectl) & EE_DATA_READ) ? 1 : 0);
+	outl(EE_ENB, eectl);
+	eeprom_delay(100);
+    }
+
+    /* Terminate the EEPROM access. */
+    outl(EE_ENB & ~EE_CS, eectl);
+    return retval;
+}
+#endif
+
+
+#define MII_READOP	1
+#define MII_WRITEOP	2
+
+    static int
+mii_read(int phy_id, int location)
+{
+    int i;
+
+    outl((phy_id << 9) | (location << 4) | MII_READOP, mmctl);
+    /* Typical operation takes < 50 ticks. */
+
+    for (i = 4000; i > 0; i--)
+	if ((inl(mmctl) & MII_READOP) == 0)
+	    break;
+    return inw(mmdata);
+}
+
+static struct nic_operations epic100_operations = {
+	.connect	= dummy_connect,
+	.poll		= epic100_poll,
+	.transmit	= epic100_transmit,
+	.irq		= epic100_irq,
+
+};
+
+static struct pci_device_id epic100_nics[] = {
+PCI_ROM(0x10b8, 0x0005, "epic100",    "SMC EtherPowerII", 0),		/* SMC 83c170 EPIC/100 */
+PCI_ROM(0x10b8, 0x0006, "smc-83c175", "SMC EPIC/C 83c175", 0),
+};
+
+PCI_DRIVER ( epic100_driver, epic100_nics, PCI_NO_CLASS );
+
+DRIVER ( "EPIC100", nic_driver, pci_driver, epic100_driver,
+	 epic100_probe, epic100_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.h
new file mode 100644
index 0000000..f290b10
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/epic100.h
@@ -0,0 +1,190 @@
+#ifndef	_EPIC100_H_
+# define _EPIC100_H_
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef	PCI_VENDOR_SMC
+# define PCI_VENDOR_SMC		0x10B8
+#endif
+
+#ifndef	PCI_DEVICE_SMC_EPIC100
+# define PCI_DEVICE_SMC_EPIC100	0x0005
+#endif
+
+#define PCI_DEVICE_ID_NONE	0xFFFF
+
+/* Offsets to registers (using SMC names). */
+enum epic100_registers {
+    COMMAND= 0,		/* Control Register */
+    INTSTAT= 4,		/* Interrupt Status */
+    INTMASK= 8,		/* Interrupt Mask */
+    GENCTL = 0x0C,	/* General Control */
+    NVCTL  = 0x10,	/* Non Volatile Control */
+    EECTL  = 0x14,	/* EEPROM Control  */
+    TEST   = 0x1C,	/* Test register: marked as reserved (see in source code) */
+    CRCCNT = 0x20,	/* CRC Error Counter */
+    ALICNT = 0x24,	/* Frame Alignment Error Counter */
+    MPCNT  = 0x28,	/* Missed Packet Counter */
+    MMCTL  = 0x30,	/* MII Management Interface Control */
+    MMDATA = 0x34,	/* MII Management Interface Data */
+    MIICFG = 0x38,	/* MII Configuration */
+    IPG    = 0x3C,	/* InterPacket Gap */
+    LAN0   = 0x40,	/* MAC address. (0x40-0x48) */
+    IDCHK  = 0x4C,	/* BoardID/ Checksum */
+    MC0    = 0x50,	/* Multicast filter table. (0x50-0x5c) */
+    RXCON  = 0x60,	/* Receive Control */
+    TXCON  = 0x70,	/* Transmit Control */
+    TXSTAT = 0x74,	/* Transmit Status */
+    PRCDAR = 0x84,	/* PCI Receive Current Descriptor Address */
+    PRSTAT = 0xA4,	/* PCI Receive DMA Status */
+    PRCPTHR= 0xB0,	/* PCI Receive Copy Threshold */
+    PTCDAR = 0xC4,	/* PCI Transmit Current Descriptor Address */
+    ETHTHR = 0xDC	/* Early Transmit Threshold */
+};
+
+/* Command register (CR_) bits */
+#define CR_STOP_RX		(0x00000001)
+#define CR_START_RX		(0x00000002)
+#define CR_QUEUE_TX		(0x00000004)
+#define CR_QUEUE_RX		(0x00000008)
+#define CR_NEXTFRAME		(0x00000010)
+#define CR_STOP_TX_DMA		(0x00000020)
+#define CR_STOP_RX_DMA		(0x00000040)
+#define CR_TX_UGO		(0x00000080)
+
+/* Interrupt register bits. NI means No Interrupt generated */
+
+#define	INTR_RX_THR_STA		(0x00400000)	/* rx copy threshold status NI */
+#define	INTR_RX_BUFF_EMPTY	(0x00200000)	/* rx buffers empty. NI */
+#define	INTR_TX_IN_PROG		(0x00100000)	/* tx copy in progess. NI */
+#define	INTR_RX_IN_PROG		(0x00080000)	/* rx copy in progress. NI */
+#define	INTR_TXIDLE		(0x00040000)	/* tx idle. NI */
+#define INTR_RXIDLE		(0x00020000)	/* rx idle. NI */
+#define INTR_INTR_ACTIVE	(0x00010000)	/* Interrupt active. NI */
+#define INTR_RX_STATUS_OK	(0x00008000)	/* rx status valid. NI */
+#define INTR_PCI_TGT_ABT	(0x00004000)	/* PCI Target abort */
+#define INTR_PCI_MASTER_ABT	(0x00002000)	/* PCI Master abort */
+#define INTR_PCI_PARITY_ERR	(0x00001000)	/* PCI adress parity error */
+#define INTR_PCI_DATA_ERR	(0x00000800)	/* PCI data parity error */
+#define INTR_RX_THR_CROSSED	(0x00000400)	/* rx copy threshold crossed */
+#define INTR_CNTFULL		(0x00000200)	/* Counter overflow */
+#define INTR_TXUNDERRUN		(0x00000100)	/* tx underrun. */
+#define INTR_TXEMPTY		(0x00000080)	/* tx queue empty */
+#define INTR_TX_CH_COMPLETE	(0x00000040)	/* tx chain complete */
+#define INTR_TXDONE		(0x00000020)	/* tx complete (w or w/o err) */
+#define INTR_RXERROR		(0x00000010)	/* rx error (CRC) */
+#define INTR_RXOVERFLOW		(0x00000008)	/* rx buffer overflow */
+#define INTR_RX_QUEUE_EMPTY	(0x00000004)	/* rx queue empty. */
+#define INTR_RXHEADER		(0x00000002)	/* header copy complete */
+#define INTR_RXDONE		(0x00000001)	/* Receive copy complete */
+
+#define INTR_CLEARINTR		(0x00007FFF)
+#define INTR_VALIDBITS		(0x007FFFFF)
+#define INTR_DISABLE		(0x00000000)
+#define INTR_CLEARERRS		(0x00007F18)
+#define INTR_ABNINTR		(INTR_CNTFULL | INTR_TXUNDERRUN | INTR_RXOVERFLOW)
+
+/* General Control (GC_) bits */
+
+#define GC_SOFT_RESET		(0x00000001)
+#define GC_INTR_ENABLE		(0x00000002)
+#define GC_SOFT_INTR		(0x00000004)
+#define GC_POWER_DOWN		(0x00000008)
+#define GC_ONE_COPY		(0x00000010)
+#define GC_BIG_ENDIAN		(0x00000020)
+#define GC_RX_PREEMPT_TX	(0x00000040)
+#define GC_TX_PREEMPT_RX	(0x00000080)
+
+/*
+ * Receive FIFO Threshold values
+ * Control the level at which the  PCI burst state machine
+ * begins to empty the receive FIFO. Possible values: 0-3
+ *
+ * 0 => 32, 1 => 64, 2 => 96 3 => 128 bytes.
+ */
+#define GC_RX_FIFO_THR_32	(0x00000000)
+#define GC_RX_FIFO_THR_64	(0x00000100)
+#define GC_RX_FIFO_THR_96	(0x00000200)
+#define GC_RX_FIFO_THR_128	(0x00000300)
+
+/* Memory Read Control (MRC_) values */
+#define GC_MRC_MEM_READ		(0x00000000)
+#define GC_MRC_READ_MULT	(0x00000400)
+#define GC_MRC_READ_LINE	(0x00000800)
+
+#define GC_SOFTBIT0		(0x00001000)
+#define GC_SOFTBIT1		(0x00002000)
+#define GC_RESET_PHY		(0x00004000)
+
+/* Definitions of the Receive Control (RC_) register bits */
+
+#define RC_SAVE_ERRORED_PKT	(0x00000001)
+#define RC_SAVE_RUNT_FRAMES	(0x00000002)
+#define RC_RCV_BROADCAST	(0x00000004)
+#define RC_RCV_MULTICAST	(0x00000008)
+#define RC_RCV_INVERSE_PKT	(0x00000010)
+#define RC_PROMISCUOUS_MODE	(0x00000020)
+#define RC_MONITOR_MODE		(0x00000040)
+#define RC_EARLY_RCV_ENABLE	(0x00000080)
+
+/* description of the rx descriptors control bits */
+#define RD_FRAGLIST		(0x0001)	/* Desc points to a fragment list */
+#define RD_LLFORM		(0x0002)	/* Frag list format */
+#define RD_HDR_CPY		(0x0004)	/* Desc used for header copy */
+
+/* Definition of the Transmit CONTROL (TC) register bits */
+
+#define TC_EARLY_TX_ENABLE	(0x00000001)
+
+/* Loopback Mode (LM_) Select valuesbits */
+#define TC_LM_NORMAL		(0x00000000)
+#define TC_LM_INTERNAL		(0x00000002)
+#define TC_LM_EXTERNAL		(0x00000004)
+#define TC_LM_FULL_DPX		(0x00000006)
+
+#define TX_SLOT_TIME		(0x00000078)
+
+/* Bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH		128	/* Rounded down to 4 byte units. */
+
+/* description of rx descriptors status bits */
+#define RRING_PKT_INTACT	(0x0001)
+#define RRING_ALIGN_ERR		(0x0002)
+#define RRING_CRC_ERR		(0x0004)
+#define RRING_MISSED_PKT	(0x0008)
+#define RRING_MULTICAST		(0x0010)
+#define RRING_BROADCAST		(0x0020)
+#define RRING_RECEIVER_DISABLE	(0x0040)
+#define RRING_STATUS_VALID	(0x1000)
+#define RRING_FRAGLIST_ERR	(0x2000)
+#define RRING_HDR_COPIED	(0x4000)
+#define RRING_OWN		(0x8000)
+
+/* error summary */
+#define RRING_ERROR		(RRING_ALIGN_ERR|RRING_CRC_ERR)
+
+/* description of tx descriptors status bits */
+#define TRING_PKT_INTACT	(0x0001)	/* pkt transmitted. */
+#define TRING_PKT_NONDEFER	(0x0002)	/* pkt xmitted w/o deferring */
+#define TRING_COLL		(0x0004)	/* pkt xmitted w collisions */
+#define TRING_CARR		(0x0008)	/* carrier sense lost */
+#define TRING_UNDERRUN		(0x0010)	/* DMA underrun */
+#define TRING_HB_COLL		(0x0020)	/* Collision detect Heartbeat */
+#define TRING_WIN_COLL		(0x0040)	/* out of window collision */
+#define TRING_DEFERRED		(0x0080)	/* Deferring */
+#define TRING_COLL_COUNT	(0x0F00)	/* collision counter (mask) */
+#define TRING_COLL_EXCESS	(0x1000)	/* tx aborted: excessive colls */
+#define TRING_OWN		(0x8000)	/* desc ownership bit */
+
+/* error summary */
+#define TRING_ABORT	(TRING_COLL_EXCESS|TRING_WIN_COLL|TRING_UNDERRUN)
+#define TRING_ERROR	(TRING_DEFERRED|TRING_WIN_COLL|TRING_UNDERRUN|TRING_CARR/*|TRING_COLL*/ )
+
+/* description of the tx descriptors control bits */
+#define TD_FRAGLIST		(0x0001)	/* Desc points to a fragment list */
+#define TD_LLFORM		(0x0002)	/* Frag list format */
+#define TD_IAF			(0x0004)	/* Generate Interrupt after tx */
+#define TD_NOCRC		(0x0008)	/* No CRC generated */
+#define TD_LASTDESC		(0x0010)	/* Last desc for this frame */
+
+#endif	/* _EPIC100_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.c
new file mode 100644
index 0000000..15e7d4c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.c
@@ -0,0 +1,4225 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown at fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/console.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/timer.h>
+#include <mii.h>
+#include "etherfabric.h"
+#include "etherfabric_nic.h"
+
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+
+#define EFAB_REGDUMP(...)
+#define EFAB_TRACE(...) DBGP(__VA_ARGS__)
+
+// printf() is not allowed within drivers.  Use DBG() instead.
+#define EFAB_LOG(...) DBG(__VA_ARGS__)
+#define EFAB_ERR(...) DBG(__VA_ARGS__)
+
+#define FALCON_USE_IO_BAR 0
+
+#define HZ 100
+#define EFAB_BYTE 1
+
+/**************************************************************************
+ *
+ * Hardware data structures and sizing
+ *
+ **************************************************************************
+ */
+extern int __invalid_queue_size;
+#define FQS(_prefix, _x)					\
+	( ( (_x) == 512 ) ? _prefix ## _SIZE_512 :		\
+	  ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K :		\
+	    ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K :		\
+	      ( ( (_x) == 4096) ? _prefix ## _SIZE_4K :		\
+		__invalid_queue_size ) ) ) )
+
+
+#define EFAB_MAX_FRAME_LEN(mtu)				\
+	( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 )
+
+/**************************************************************************
+ *
+ * GMII routines
+ *
+ **************************************************************************
+ */
+
+static void falcon_mdio_write (struct efab_nic *efab, int device,
+			       int location, int value );
+static int falcon_mdio_read ( struct efab_nic *efab, int device, int location );
+
+/* GMII registers */
+#define GMII_PSSR		0x11	/* PHY-specific status register */
+
+/* Pseudo extensions to the link partner ability register */
+#define LPA_EF_1000FULL		0x00020000
+#define LPA_EF_1000HALF		0x00010000
+#define LPA_EF_10000FULL		0x00040000
+#define LPA_EF_10000HALF		0x00080000
+
+#define LPA_100			(LPA_100FULL | LPA_100HALF | LPA_100BASE4)
+#define LPA_EF_1000		( LPA_EF_1000FULL | LPA_EF_1000HALF )
+#define LPA_EF_10000               ( LPA_EF_10000FULL | LPA_EF_10000HALF )
+#define LPA_EF_DUPLEX		( LPA_10FULL | LPA_100FULL | LPA_EF_1000FULL | \
+				  LPA_EF_10000FULL )
+
+/* Mask of bits not associated with speed or duplexity. */
+#define LPA_OTHER		~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \
+				   LPA_100HALF | LPA_EF_1000FULL | LPA_EF_1000HALF )
+
+/* PHY-specific status register */
+#define PSSR_LSTATUS		0x0400	/* Bit 10 - link status */
+
+/**
+ * Retrieve GMII autonegotiation advertised abilities
+ *
+ */
+static unsigned int
+gmii_autoneg_advertised ( struct efab_nic *efab )
+{
+	unsigned int mii_advertise;
+	unsigned int gmii_advertise;
+
+	/* Extended bits are in bits 8 and 9 of MII_CTRL1000 */
+	mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE );
+	gmii_advertise = ( ( falcon_mdio_read ( efab, 0, MII_CTRL1000 ) >> 8 )
+			   & 0x03 );
+	return ( ( gmii_advertise << 16 ) | mii_advertise );
+}
+
+/**
+ * Retrieve GMII autonegotiation link partner abilities
+ *
+ */
+static unsigned int
+gmii_autoneg_lpa ( struct efab_nic *efab )
+{
+	unsigned int mii_lpa;
+	unsigned int gmii_lpa;
+
+	/* Extended bits are in bits 10 and 11 of MII_STAT1000 */
+	mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA );
+	gmii_lpa = ( falcon_mdio_read ( efab, 0, MII_STAT1000 ) >> 10 ) & 0x03;
+	return ( ( gmii_lpa << 16 ) | mii_lpa );
+}
+
+/**
+ * Calculate GMII autonegotiated link technology
+ *
+ */
+static unsigned int
+gmii_nway_result ( unsigned int negotiated )
+{
+	unsigned int other_bits;
+
+	/* Mask out the speed and duplexity bits */
+	other_bits = negotiated & LPA_OTHER;
+
+	if ( negotiated & LPA_EF_1000FULL )
+		return ( other_bits | LPA_EF_1000FULL );
+	else if ( negotiated & LPA_EF_1000HALF )
+		return ( other_bits | LPA_EF_1000HALF );
+	else if ( negotiated & LPA_100FULL )
+		return ( other_bits | LPA_100FULL );
+	else if ( negotiated & LPA_100BASE4 )
+		return ( other_bits | LPA_100BASE4 );
+	else if ( negotiated & LPA_100HALF )
+		return ( other_bits | LPA_100HALF );
+	else if ( negotiated & LPA_10FULL )
+		return ( other_bits | LPA_10FULL );
+	else return ( other_bits | LPA_10HALF );
+}
+
+/**
+ * Check GMII PHY link status
+ *
+ */
+static int
+gmii_link_ok ( struct efab_nic *efab )
+{
+	int status;
+	int phy_status;
+
+	/* BMSR is latching - it returns "link down" if the link has
+	 * been down at any point since the last read.  To get a
+	 * real-time status, we therefore read the register twice and
+	 * use the result of the second read.
+	 */
+	(void) falcon_mdio_read ( efab, 0, MII_BMSR );
+	status = falcon_mdio_read ( efab, 0, MII_BMSR );
+
+	/* Read the PHY-specific Status Register.  This is
+	 * non-latching, so we need do only a single read.
+	 */
+	phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR );
+
+	return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) );
+}
+
+/**************************************************************************
+ *
+ * MDIO routines
+ *
+ **************************************************************************
+ */
+
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD	(1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS	(2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS	(3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS	(4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS	(5)
+/* Transmission convergence */
+#define MDIO_MMD_TC	(6)
+/* Auto negotiation */
+#define MDIO_MMD_AN	(7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1	(0)
+#define MDIO_MMDREG_STAT1	(1)
+#define MDIO_MMDREG_DEVS0	(5)
+#define MDIO_MMDREG_STAT2	(8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN	(15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH	(1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN	(7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH	(1)
+
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN	(2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH	(1)
+
+/* Bits in MMDREG_DEVS0. */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_DTEXS	 DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
+#define MDIO_MMDREG_DEVS0_PHYXS	 DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS	 DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_WIS	 DEV_PRESENT_BIT(MDIO_MMD_WIS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+#define MDIO_MMDREG_DEVS0_AN     DEV_PRESENT_BIT(MDIO_MMD_AN)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL	(2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN	(14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PHY XGXS lane state */
+#define MDIO_PHYXS_LANE_STATE		(0x18) 
+#define MDIO_PHYXS_LANE_ALIGNED_LBN	(12)
+#define MDIO_PHYXS_LANE_SYNC0_LBN	(0)
+#define MDIO_PHYXS_LANE_SYNC1_LBN	(1)
+#define MDIO_PHYXS_LANE_SYNC2_LBN	(2)
+#define MDIO_PHYXS_LANE_SYNC3_LBN	(3)
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TRIES      100
+#define MDIO45_RESET_SPINTIME   10
+
+static int
+mdio_clause45_wait_reset_mmds ( struct efab_nic* efab )
+{
+	int tries = MDIO45_RESET_TRIES;
+	int in_reset;
+
+	while(tries) {
+		int mask = efab->phy_op->mmds;
+		int mmd = 0;
+		in_reset = 0;
+		while(mask) {
+			if (mask & 1) {
+				int stat = falcon_mdio_read ( efab,  mmd,
+							      MDIO_MMDREG_CTRL1 );
+				if (stat < 0) {
+					EFAB_ERR("Failed to read status of MMD %d\n",
+						 mmd );
+					in_reset = 1;
+					break;
+				}
+				if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+					in_reset |= (1 << mmd);
+			}
+			mask = mask >> 1;
+			mmd++;
+		}
+		if (!in_reset)
+			break;
+		tries--;
+		mdelay ( MDIO45_RESET_SPINTIME );
+	}
+	if (in_reset != 0) {
+		EFAB_ERR("Not all MMDs came out of reset in time. MMDs "
+			 "still in reset: %x\n", in_reset);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int
+mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd )
+{
+	int tries = MDIO45_RESET_TRIES;
+	int ctrl;
+
+	falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1,
+			    ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) );
+
+	/* Wait for the reset bit to clear. */
+	do {
+		mdelay ( MDIO45_RESET_SPINTIME );
+
+		ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 );
+		if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) )
+			return 0;
+	} while ( --tries );
+
+	EFAB_ERR ( "Failed to reset mmd %d\n", mmd );
+
+	return -ETIMEDOUT;
+}
+
+static int
+mdio_clause45_links_ok(struct efab_nic *efab )
+{
+	int status, good;
+	int ok = 1;
+	int mmd = 0;
+	int mmd_mask = efab->phy_op->mmds;
+
+	while (mmd_mask) {
+		if (mmd_mask & 1) {
+			/* Double reads because link state is latched, and a
+			 * read	moves the current state into the register */
+			status = falcon_mdio_read ( efab, mmd,
+						    MDIO_MMDREG_STAT1 );
+			status = falcon_mdio_read ( efab, mmd,
+						    MDIO_MMDREG_STAT1 );
+
+			good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+			ok = ok && good;
+		}
+		mmd_mask = (mmd_mask >> 1);
+		mmd++;
+	}
+	return ok;
+}
+
+static int
+mdio_clause45_check_mmds ( struct efab_nic *efab )
+{
+	int mmd = 0;
+	int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+					 MDIO_MMDREG_DEVS0 );
+	int mmd_mask = efab->phy_op->mmds;
+
+	/* Check all the expected MMDs are present */
+	if ( devices < 0 ) {
+		EFAB_ERR ( "Failed to read devices present\n" );
+		return -EIO;
+	}
+	if ( ( devices & mmd_mask ) != mmd_mask ) {
+		EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n",
+			   devices, mmd_mask );
+		return -EIO;
+	}
+
+	/* Check all required MMDs are responding and happy. */
+	while ( mmd_mask ) {
+		if ( mmd_mask & 1 ) {
+			efab_dword_t reg;
+			int status;
+			reg.opaque = falcon_mdio_read ( efab, mmd,
+							MDIO_MMDREG_STAT2 );
+			status = EFAB_DWORD_FIELD ( reg,
+						    MDIO_MMDREG_STAT2_PRESENT );
+			if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) {
+
+
+				return -EIO;
+			}
+		}
+		mmd_mask >>= 1;
+		mmd++;
+	}
+
+	return 0;
+}
+
+/* I/O BAR address register */
+#define FCN_IOM_IND_ADR_REG 0x0
+
+/* I/O BAR data register */
+#define FCN_IOM_IND_DAT_REG 0x4
+
+/* Address region register */
+#define FCN_ADR_REGION_REG_KER	0x00
+#define FCN_ADR_REGION0_LBN	0
+#define FCN_ADR_REGION0_WIDTH	18
+#define FCN_ADR_REGION1_LBN	32
+#define FCN_ADR_REGION1_WIDTH	18
+#define FCN_ADR_REGION2_LBN	64
+#define FCN_ADR_REGION2_WIDTH	18
+#define FCN_ADR_REGION3_LBN	96
+#define FCN_ADR_REGION3_WIDTH	18
+
+/* Interrupt enable register */
+#define FCN_INT_EN_REG_KER 0x0010
+#define FCN_MEM_PERR_INT_EN_KER_LBN 5
+#define FCN_MEM_PERR_INT_EN_KER_WIDTH 1
+#define FCN_KER_INT_CHAR_LBN 4
+#define FCN_KER_INT_CHAR_WIDTH 1
+#define FCN_KER_INT_KER_LBN 3
+#define FCN_KER_INT_KER_WIDTH 1
+#define FCN_ILL_ADR_ERR_INT_EN_KER_LBN 2
+#define FCN_ILL_ADR_ERR_INT_EN_KER_WIDTH 1
+#define FCN_SRM_PERR_INT_EN_KER_LBN 1
+#define FCN_SRM_PERR_INT_EN_KER_WIDTH 1
+#define FCN_DRV_INT_EN_KER_LBN 0
+#define FCN_DRV_INT_EN_KER_WIDTH 1
+
+/* Interrupt status register */
+#define FCN_INT_ADR_REG_KER	0x0030
+#define FCN_INT_ADR_KER_LBN 0
+#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 )
+
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define FCN_INT_ACK_KER_REG_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* Hardware initialisation register */
+#define FCN_HW_INIT_REG_KER 0x00c0
+#define FCN_BCSR_TARGET_MASK_LBN 101
+#define FCN_BCSR_TARGET_MASK_WIDTH 4
+
+/* SPI host command register */
+#define FCN_EE_SPI_HCMD_REG 0x0100
+#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31
+#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define FCN_EE_WR_TIMER_ACTIVE_LBN 28
+#define FCN_EE_WR_TIMER_ACTIVE_WIDTH 1
+#define FCN_EE_SPI_HCMD_SF_SEL_LBN 24
+#define FCN_EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define FCN_EE_SPI_EEPROM 0
+#define FCN_EE_SPI_FLASH 1
+#define FCN_EE_SPI_HCMD_DABCNT_LBN 16
+#define FCN_EE_SPI_HCMD_DABCNT_WIDTH 5
+#define FCN_EE_SPI_HCMD_READ_LBN 15
+#define FCN_EE_SPI_HCMD_READ_WIDTH 1
+#define FCN_EE_SPI_READ 1
+#define FCN_EE_SPI_WRITE 0
+#define FCN_EE_SPI_HCMD_DUBCNT_LBN 12
+#define FCN_EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define FCN_EE_SPI_HCMD_ADBCNT_LBN 8
+#define FCN_EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define FCN_EE_SPI_HCMD_ENC_LBN 0
+#define FCN_EE_SPI_HCMD_ENC_WIDTH 8
+
+/* SPI host address register */
+#define FCN_EE_SPI_HADR_REG 0x0110
+#define FCN_EE_SPI_HADR_DUBYTE_LBN 24
+#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8
+#define FCN_EE_SPI_HADR_ADR_LBN 0
+#define FCN_EE_SPI_HADR_ADR_WIDTH 24
+
+/* SPI host data register */
+#define FCN_EE_SPI_HDATA_REG 0x0120
+#define FCN_EE_SPI_HDATA3_LBN 96
+#define FCN_EE_SPI_HDATA3_WIDTH 32
+#define FCN_EE_SPI_HDATA2_LBN 64
+#define FCN_EE_SPI_HDATA2_WIDTH 32
+#define FCN_EE_SPI_HDATA1_LBN 32
+#define FCN_EE_SPI_HDATA1_WIDTH 32
+#define FCN_EE_SPI_HDATA0_LBN 0
+#define FCN_EE_SPI_HDATA0_WIDTH 32
+
+/* VPD Config 0 Register register */
+#define FCN_EE_VPD_CFG_REG 0x0140
+#define FCN_EE_VPD_EN_LBN 0
+#define FCN_EE_VPD_EN_WIDTH 1
+#define FCN_EE_VPD_EN_AD9_MODE_LBN 1
+#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define FCN_EE_EE_CLOCK_DIV_LBN 112
+#define FCN_EE_EE_CLOCK_DIV_WIDTH 7
+#define FCN_EE_SF_CLOCK_DIV_LBN 120
+#define FCN_EE_SF_CLOCK_DIV_WIDTH 7
+
+
+/* NIC status register */
+#define FCN_NIC_STAT_REG 0x0200
+#define FCN_ONCHIP_SRAM_LBN 16
+#define FCN_ONCHIP_SRAM_WIDTH 1
+#define FCN_SF_PRST_LBN 9
+#define FCN_SF_PRST_WIDTH 1
+#define FCN_EE_PRST_LBN 8
+#define FCN_EE_PRST_WIDTH 1
+#define FCN_EE_STRAP_LBN 7
+#define FCN_EE_STRAP_WIDTH 1
+#define FCN_PCI_PCIX_MODE_LBN 4
+#define FCN_PCI_PCIX_MODE_WIDTH 3
+#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0
+#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1
+#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5
+#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6
+#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7
+#define FCN_STRAP_ISCSI_EN_LBN 3
+#define FCN_STRAP_ISCSI_EN_WIDTH 1
+#define FCN_STRAP_PINS_LBN 0
+#define FCN_STRAP_PINS_WIDTH 3
+#define FCN_STRAP_10G_LBN 2
+#define FCN_STRAP_10G_WIDTH 1
+#define FCN_STRAP_DUAL_PORT_LBN 1
+#define FCN_STRAP_DUAL_PORT_WIDTH 1
+#define FCN_STRAP_PCIE_LBN 0
+#define FCN_STRAP_PCIE_WIDTH 1
+
+/* Falcon revisions */
+#define FALCON_REV_A0 0
+#define FALCON_REV_A1 1
+#define FALCON_REV_B0 2
+
+/* GPIO control register */
+#define FCN_GPIO_CTL_REG_KER 0x0210
+#define FCN_GPIO_CTL_REG_KER 0x0210
+
+#define FCN_GPIO3_OEN_LBN 27
+#define FCN_GPIO3_OEN_WIDTH 1
+#define FCN_GPIO2_OEN_LBN 26
+#define FCN_GPIO2_OEN_WIDTH 1
+#define FCN_GPIO1_OEN_LBN 25
+#define FCN_GPIO1_OEN_WIDTH 1
+#define FCN_GPIO0_OEN_LBN 24
+#define FCN_GPIO0_OEN_WIDTH 1
+
+#define FCN_GPIO3_OUT_LBN 19
+#define FCN_GPIO3_OUT_WIDTH 1
+#define FCN_GPIO2_OUT_LBN 18
+#define FCN_GPIO2_OUT_WIDTH 1
+#define FCN_GPIO1_OUT_LBN 17
+#define FCN_GPIO1_OUT_WIDTH 1
+#define FCN_GPIO0_OUT_LBN 16
+#define FCN_GPIO0_OUT_WIDTH 1
+
+#define FCN_GPIO3_IN_LBN 11
+#define FCN_GPIO3_IN_WIDTH 1
+#define FCN_GPIO2_IN_LBN 10
+#define FCN_GPIO2_IN_WIDTH 1
+#define FCN_GPIO1_IN_LBN 9
+#define FCN_GPIO1_IN_WIDTH 1
+#define FCN_GPIO0_IN_LBN 8
+#define FCN_GPIO0_IN_WIDTH 1
+
+#define FCN_FLASH_PRESENT_LBN 7
+#define FCN_FLASH_PRESENT_WIDTH 1
+#define FCN_EEPROM_PRESENT_LBN 6
+#define FCN_EEPROM_PRESENT_WIDTH 1
+#define FCN_BOOTED_USING_NVDEVICE_LBN 3
+#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1
+
+/* Defines for extra non-volatile storage */
+#define FCN_NV_MAGIC_NUMBER 0xFA1C
+
+/* Global control register */
+#define FCN_GLB_CTL_REG_KER	0x0220
+#define FCN_EXT_PHY_RST_CTL_LBN 63
+#define FCN_EXT_PHY_RST_CTL_WIDTH 1
+#define FCN_PCIE_SD_RST_CTL_LBN 61
+#define FCN_PCIE_SD_RST_CTL_WIDTH 1
+#define FCN_PCIE_STCK_RST_CTL_LBN 59
+#define FCN_PCIE_STCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_NSTCK_RST_CTL_LBN 58
+#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_CORE_RST_CTL_LBN 57
+#define FCN_PCIE_CORE_RST_CTL_WIDTH 1
+#define FCN_EE_RST_CTL_LBN 49
+#define FCN_EE_RST_CTL_WIDTH 1
+#define FCN_RST_EXT_PHY_LBN 31
+#define FCN_RST_EXT_PHY_WIDTH 1
+#define FCN_EXT_PHY_RST_DUR_LBN 1
+#define FCN_EXT_PHY_RST_DUR_WIDTH 3
+#define FCN_SWRST_LBN 0
+#define FCN_SWRST_WIDTH 1
+#define INCLUDE_IN_RESET 0
+#define EXCLUDE_FROM_RESET 1
+
+/* FPGA build version */
+#define FCN_ALTERA_BUILD_REG_KER 0x0300
+#define FCN_VER_MAJOR_LBN 24
+#define FCN_VER_MAJOR_WIDTH 8
+#define FCN_VER_MINOR_LBN 16
+#define FCN_VER_MINOR_WIDTH 8
+#define FCN_VER_BUILD_LBN 0
+#define FCN_VER_BUILD_WIDTH 16
+#define FCN_VER_ALL_LBN 0
+#define FCN_VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define FCN_SPARE_REG_KER 0x310
+#define FCN_MEM_PERR_EN_TX_DATA_LBN 72
+#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2
+
+/* Timer table for kernel access */
+#define FCN_TIMER_CMD_REG_KER 0x420
+#define FCN_TIMER_MODE_LBN 12
+#define FCN_TIMER_MODE_WIDTH 2
+#define FCN_TIMER_MODE_DIS 0
+#define FCN_TIMER_MODE_INT_HLDOFF 1
+#define FCN_TIMER_VAL_LBN 0
+#define FCN_TIMER_VAL_WIDTH 12
+
+/* Receive configuration register */
+#define FCN_RX_CFG_REG_KER 0x800
+#define FCN_RX_XOFF_EN_LBN 0
+#define FCN_RX_XOFF_EN_WIDTH 1
+
+/* SRAM receive descriptor cache configuration register */
+#define FCN_SRM_RX_DC_CFG_REG_KER 0x610
+#define FCN_SRM_RX_DC_BASE_ADR_LBN 0
+#define FCN_SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM transmit descriptor cache configuration register */
+#define FCN_SRM_TX_DC_CFG_REG_KER 0x620
+#define FCN_SRM_TX_DC_BASE_ADR_LBN 0
+#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM configuration register */
+#define FCN_SRM_CFG_REG_KER 0x630
+#define FCN_SRAM_OOB_ADR_INTEN_LBN 5
+#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BUF_INTEN_LBN 4
+#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3
+#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define FCN_SRM_NUM_BANK_LBN 2
+#define FCN_SRM_NUM_BANK_WIDTH 1
+#define FCN_SRM_BANK_SIZE_LBN 0
+#define FCN_SRM_BANK_SIZE_WIDTH 2
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+
+#define FCN_RX_CFG_REG_KER 0x800
+#define FCN_RX_INGR_EN_B0_LBN 47
+#define FCN_RX_INGR_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_B0_LBN 19
+#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9
+#define FCN_RX_XON_MAC_TH_B0_LBN 10
+#define FCN_RX_XON_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_TH_B0_LBN 1
+#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_B0_LBN 0
+#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XON_MAC_TH_A1_LBN 6
+#define FCN_RX_XON_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_TH_A1_LBN 1
+#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
+/* Receive filter control register */
+#define FCN_RX_FILTER_CTL_REG_KER 0x810
+#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32
+#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define FCN_NUM_KER_LBN 24
+#define FCN_NUM_KER_WIDTH 2
+#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16
+#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8
+#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0
+#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820
+#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24
+#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_RX_FLUSH_DESCQ_LBN 0
+#define FCN_RX_FLUSH_DESCQ_WIDTH 12
+
+/* Receive descriptor update register */
+#define FCN_RX_DESC_UPD_REG_KER 0x0830
+#define FCN_RX_DESC_WPTR_LBN 96
+#define FCN_RX_DESC_WPTR_WIDTH 12
+#define FCN_RX_DESC_UPD_REG_KER_DWORD ( FCN_RX_DESC_UPD_REG_KER + 12 )
+#define FCN_RX_DESC_WPTR_DWORD_LBN 0
+#define FCN_RX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Receive descriptor cache configuration register */
+#define FCN_RX_DC_CFG_REG_KER 0x840
+#define FCN_RX_DC_SIZE_LBN 0
+#define FCN_RX_DC_SIZE_WIDTH 2
+
+#define FCN_RX_SELF_RST_REG_KER 0x890
+#define FCN_RX_ISCSI_DIS_LBN 17
+#define FCN_RX_ISCSI_DIS_WIDTH 1
+#define FCN_RX_NODESC_WAIT_DIS_LBN 9
+#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1
+#define FCN_RX_RECOVERY_EN_LBN 8
+#define FCN_RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12
+#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_TX_FLUSH_DESCQ_LBN 0
+#define FCN_TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit configuration register 2 */
+#define FCN_TX_CFG2_REG_KER 0xa80
+#define FCN_TX_DIS_NON_IP_EV_LBN 17
+#define FCN_TX_DIS_NON_IP_EV_WIDTH 1
+
+/* Transmit descriptor update register */
+#define FCN_TX_DESC_UPD_REG_KER 0x0a10
+#define FCN_TX_DESC_WPTR_LBN 96
+#define FCN_TX_DESC_WPTR_WIDTH 12
+#define FCN_TX_DESC_UPD_REG_KER_DWORD ( FCN_TX_DESC_UPD_REG_KER + 12 )
+#define FCN_TX_DESC_WPTR_DWORD_LBN 0
+#define FCN_TX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Transmit descriptor cache configuration register */
+#define FCN_TX_DC_CFG_REG_KER 0xa20
+#define FCN_TX_DC_SIZE_LBN 0
+#define FCN_TX_DC_SIZE_WIDTH 2
+
+/* PHY management transmit data register */
+#define FCN_MD_TXD_REG_KER 0xc00
+#define FCN_MD_TXD_LBN 0
+#define FCN_MD_TXD_WIDTH 16
+
+/* PHY management receive data register */
+#define FCN_MD_RXD_REG_KER 0xc10
+#define FCN_MD_RXD_LBN 0
+#define FCN_MD_RXD_WIDTH 16
+
+/* PHY management configuration & status register */
+#define FCN_MD_CS_REG_KER 0xc20
+#define FCN_MD_GC_LBN 4
+#define FCN_MD_GC_WIDTH 1
+#define FCN_MD_RIC_LBN 2
+#define FCN_MD_RIC_WIDTH 1
+#define FCN_MD_RDC_LBN 1
+#define FCN_MD_RDC_WIDTH 1
+#define FCN_MD_WRC_LBN 0
+#define FCN_MD_WRC_WIDTH 1
+
+/* PHY management PHY address register */
+#define FCN_MD_PHY_ADR_REG_KER 0xc30
+#define FCN_MD_PHY_ADR_LBN 0
+#define FCN_MD_PHY_ADR_WIDTH 16
+
+/* PHY management ID register */
+#define FCN_MD_ID_REG_KER 0xc40
+#define FCN_MD_PRT_ADR_LBN 11
+#define FCN_MD_PRT_ADR_WIDTH 5
+#define FCN_MD_DEV_ADR_LBN 6
+#define FCN_MD_DEV_ADR_WIDTH 5
+
+/* PHY management status & mask register */
+#define FCN_MD_STAT_REG_KER 0xc50
+#define FCN_MD_PINT_LBN 4
+#define FCN_MD_PINT_WIDTH 1
+#define FCN_MD_DONE_LBN 3
+#define FCN_MD_DONE_WIDTH 1
+#define FCN_MD_BSERR_LBN 2
+#define FCN_MD_BSERR_WIDTH 1
+#define FCN_MD_LNFL_LBN 1
+#define FCN_MD_LNFL_WIDTH 1
+#define FCN_MD_BSY_LBN 0
+#define FCN_MD_BSY_WIDTH 1
+
+/* Port 0 and 1 MAC control registers */
+#define FCN_MAC0_CTRL_REG_KER 0xc80
+#define FCN_MAC1_CTRL_REG_KER 0xc90
+#define FCN_MAC_XOFF_VAL_LBN 16
+#define FCN_MAC_XOFF_VAL_WIDTH 16
+#define FCN_MAC_BCAD_ACPT_LBN 4
+#define FCN_MAC_BCAD_ACPT_WIDTH 1
+#define FCN_MAC_UC_PROM_LBN 3
+#define FCN_MAC_UC_PROM_WIDTH 1
+#define FCN_MAC_LINK_STATUS_LBN 2
+#define FCN_MAC_LINK_STATUS_WIDTH 1
+#define FCN_MAC_SPEED_LBN 0
+#define FCN_MAC_SPEED_WIDTH 2
+
+/* 10Gig Xaui XGXS Default Values  */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0  /* 20mA */
+
+/* GMAC registers */
+#define FALCON_GMAC_REGBANK 0xe00
+#define FALCON_GMAC_REGBANK_SIZE 0x200
+#define FALCON_GMAC_REG_SIZE 0x10
+
+/* XGMAC registers */
+#define FALCON_XMAC_REGBANK 0x1200
+#define FALCON_XMAC_REGBANK_SIZE 0x200
+#define FALCON_XMAC_REG_SIZE 0x10
+
+/* XGMAC address register low */
+#define FCN_XM_ADR_LO_REG_MAC 0x00
+#define FCN_XM_ADR_3_LBN 24
+#define FCN_XM_ADR_3_WIDTH 8
+#define FCN_XM_ADR_2_LBN 16
+#define FCN_XM_ADR_2_WIDTH 8
+#define FCN_XM_ADR_1_LBN 8
+#define FCN_XM_ADR_1_WIDTH 8
+#define FCN_XM_ADR_0_LBN 0
+#define FCN_XM_ADR_0_WIDTH 8
+
+/* XGMAC address register high */
+#define FCN_XM_ADR_HI_REG_MAC 0x01
+#define FCN_XM_ADR_5_LBN 8
+#define FCN_XM_ADR_5_WIDTH 8
+#define FCN_XM_ADR_4_LBN 0
+#define FCN_XM_ADR_4_WIDTH 8
+
+/* XGMAC global configuration - port 0*/
+#define FCN_XM_GLB_CFG_REG_MAC 0x02
+#define FCN_XM_RX_STAT_EN_LBN 11
+#define FCN_XM_RX_STAT_EN_WIDTH 1
+#define FCN_XM_TX_STAT_EN_LBN 10
+#define FCN_XM_TX_STAT_EN_WIDTH 1
+#define FCN_XM_RX_JUMBO_MODE_LBN 6
+#define FCN_XM_RX_JUMBO_MODE_WIDTH 1
+#define FCN_XM_CORE_RST_LBN 0
+#define FCN_XM_CORE_RST_WIDTH 1
+
+/* XGMAC transmit configuration - port 0 */
+#define FCN_XM_TX_CFG_REG_MAC 0x03
+#define FCN_XM_IPG_LBN 16
+#define FCN_XM_IPG_WIDTH 4
+#define FCN_XM_FCNTL_LBN 10
+#define FCN_XM_FCNTL_WIDTH 1
+#define FCN_XM_TXCRC_LBN 8
+#define FCN_XM_TXCRC_WIDTH 1
+#define FCN_XM_AUTO_PAD_LBN 5
+#define FCN_XM_AUTO_PAD_WIDTH 1
+#define FCN_XM_TX_PRMBL_LBN 2
+#define FCN_XM_TX_PRMBL_WIDTH 1
+#define FCN_XM_TXEN_LBN 1
+#define FCN_XM_TXEN_WIDTH 1
+
+/* XGMAC receive configuration - port 0 */
+#define FCN_XM_RX_CFG_REG_MAC 0x04
+#define FCN_XM_PASS_CRC_ERR_LBN 25
+#define FCN_XM_PASS_CRC_ERR_WIDTH 1
+#define FCN_XM_AUTO_DEPAD_LBN 8
+#define FCN_XM_AUTO_DEPAD_WIDTH 1
+#define FCN_XM_RXEN_LBN 1
+#define FCN_XM_RXEN_WIDTH 1
+
+/* XGMAC management interrupt mask register */
+#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define FCN_XM_MSK_PRMBLE_ERR_LBN 2
+#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define FCN_XM_MSK_RMTFLT_LBN 1
+#define FCN_XM_MSK_RMTFLT_WIDTH 1
+#define FCN_XM_MSK_LCLFLT_LBN 0
+#define FCN_XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define FCN_XM_FC_REG_MAC 0x7
+#define FCN_XM_PAUSE_TIME_LBN 16
+#define FCN_XM_PAUSE_TIME_WIDTH 16
+#define FCN_XM_DIS_FCNTL_LBN 0
+#define FCN_XM_DIS_FCNTL_WIDTH 1
+
+/* XGMAC transmit parameter register */
+#define FCN_XM_TX_PARAM_REG_MAC 0x0d
+#define FCN_XM_TX_JUMBO_MODE_LBN 31
+#define FCN_XM_TX_JUMBO_MODE_WIDTH 1
+#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16
+#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14
+#define FCN_XM_ACPT_ALL_MCAST_LBN 11
+#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1
+
+/* XGMAC receive parameter register */
+#define FCN_XM_RX_PARAM_REG_MAC 0x0e
+#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0
+#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14
+
+/* XGMAC management interrupt status register */
+#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f
+#define FCN_XM_PRMBLE_ERR 2
+#define FCN_XM_PRMBLE_WIDTH 1
+#define FCN_XM_RMTFLT_LBN 1
+#define FCN_XM_RMTFLT_WIDTH 1
+#define FCN_XM_LCLFLT_LBN 0
+#define FCN_XM_LCLFLT_WIDTH 1
+
+/* XAUI XGXS core status register */
+#define FCN_XX_ALIGN_DONE_LBN 20
+#define FCN_XX_ALIGN_DONE_WIDTH 1
+#define FCN_XX_CORE_STAT_REG_MAC 0x16
+#define FCN_XX_SYNC_STAT_LBN 16
+#define FCN_XX_SYNC_STAT_WIDTH 4
+#define FCN_XX_SYNC_STAT_DECODE_SYNCED 0xf
+#define FCN_XX_COMMA_DET_LBN 12
+#define FCN_XX_COMMA_DET_WIDTH 4
+#define FCN_XX_COMMA_DET_RESET 0xf
+#define FCN_XX_CHARERR_LBN 4
+#define FCN_XX_CHARERR_WIDTH 4
+#define FCN_XX_CHARERR_RESET 0xf
+#define FCN_XX_DISPERR_LBN 0
+#define FCN_XX_DISPERR_WIDTH 4
+#define FCN_XX_DISPERR_RESET 0xf
+
+/* XGXS/XAUI powerdown/reset register */
+#define FCN_XX_PWR_RST_REG_MAC 0x10
+#define FCN_XX_PWRDND_EN_LBN 15
+#define FCN_XX_PWRDND_EN_WIDTH 1
+#define FCN_XX_PWRDNC_EN_LBN 14
+#define FCN_XX_PWRDNC_EN_WIDTH 1
+#define FCN_XX_PWRDNB_EN_LBN 13
+#define FCN_XX_PWRDNB_EN_WIDTH 1
+#define FCN_XX_PWRDNA_EN_LBN 12
+#define FCN_XX_PWRDNA_EN_WIDTH 1
+#define FCN_XX_RSTPLLCD_EN_LBN 9
+#define FCN_XX_RSTPLLCD_EN_WIDTH 1
+#define FCN_XX_RSTPLLAB_EN_LBN 8
+#define FCN_XX_RSTPLLAB_EN_WIDTH 1
+#define FCN_XX_RESETD_EN_LBN 7
+#define FCN_XX_RESETD_EN_WIDTH 1
+#define FCN_XX_RESETC_EN_LBN 6
+#define FCN_XX_RESETC_EN_WIDTH 1
+#define FCN_XX_RESETB_EN_LBN 5
+#define FCN_XX_RESETB_EN_WIDTH 1
+#define FCN_XX_RESETA_EN_LBN 4
+#define FCN_XX_RESETA_EN_WIDTH 1
+#define FCN_XX_RSTXGXSRX_EN_LBN 2
+#define FCN_XX_RSTXGXSRX_EN_WIDTH 1
+#define FCN_XX_RSTXGXSTX_EN_LBN 1
+#define FCN_XX_RSTXGXSTX_EN_WIDTH 1
+#define FCN_XX_RST_XX_EN_LBN 0
+#define FCN_XX_RST_XX_EN_WIDTH 1
+
+
+/* XGXS/XAUI powerdown/reset control register */
+#define FCN_XX_SD_CTL_REG_MAC 0x11
+#define FCN_XX_TERMADJ1_LBN 17
+#define FCN_XX_TERMADJ1_WIDTH 1
+#define FCN_XX_TERMADJ0_LBN 16
+#define FCN_XX_TERMADJ0_WIDTH 1
+#define FCN_XX_HIDRVD_LBN 15
+#define FCN_XX_HIDRVD_WIDTH 1
+#define FCN_XX_LODRVD_LBN 14
+#define FCN_XX_LODRVD_WIDTH 1
+#define FCN_XX_HIDRVC_LBN 13
+#define FCN_XX_HIDRVC_WIDTH 1
+#define FCN_XX_LODRVC_LBN 12
+#define FCN_XX_LODRVC_WIDTH 1
+#define FCN_XX_HIDRVB_LBN 11
+#define FCN_XX_HIDRVB_WIDTH 1
+#define FCN_XX_LODRVB_LBN 10
+#define FCN_XX_LODRVB_WIDTH 1
+#define FCN_XX_HIDRVA_LBN 9
+#define FCN_XX_HIDRVA_WIDTH 1
+#define FCN_XX_LODRVA_LBN 8
+#define FCN_XX_LODRVA_WIDTH 1
+#define FCN_XX_LPBKD_LBN 3
+#define FCN_XX_LPBKD_WIDTH 1
+#define FCN_XX_LPBKC_LBN 2
+#define FCN_XX_LPBKC_WIDTH 1
+#define FCN_XX_LPBKB_LBN 1
+#define FCN_XX_LPBKB_WIDTH 1
+#define FCN_XX_LPBKA_LBN 0
+#define FCN_XX_LPBKA_WIDTH 1
+
+#define FCN_XX_TXDRV_CTL_REG_MAC 0x12
+#define FCN_XX_DEQD_LBN 28
+#define FCN_XX_DEQD_WIDTH 4
+#define FCN_XX_DEQC_LBN 24
+#define FCN_XX_DEQC_WIDTH 4
+#define FCN_XX_DEQB_LBN 20
+#define FCN_XX_DEQB_WIDTH 4
+#define FCN_XX_DEQA_LBN 16
+#define FCN_XX_DEQA_WIDTH 4
+#define FCN_XX_DTXD_LBN 12
+#define FCN_XX_DTXD_WIDTH 4
+#define FCN_XX_DTXC_LBN 8
+#define FCN_XX_DTXC_WIDTH 4
+#define FCN_XX_DTXB_LBN 4
+#define FCN_XX_DTXB_WIDTH 4
+#define FCN_XX_DTXA_LBN 0
+#define FCN_XX_DTXA_WIDTH 4
+
+/* Receive filter table */
+#define FCN_RX_FILTER_TBL0 0xF00000 
+
+/* Receive descriptor pointer table */
+#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define FCN_RX_ISCSI_DDIG_EN_LBN 88
+#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_RX_ISCSI_HDIG_EN_LBN 87
+#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1
+#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36
+#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FCN_RX_DESCQ_EVQ_ID_LBN 24
+#define FCN_RX_DESCQ_EVQ_ID_WIDTH 12
+#define FCN_RX_DESCQ_OWNER_ID_LBN 10
+#define FCN_RX_DESCQ_OWNER_ID_WIDTH 14
+#define FCN_RX_DESCQ_SIZE_LBN 3
+#define FCN_RX_DESCQ_SIZE_WIDTH 2
+#define FCN_RX_DESCQ_SIZE_4K 3
+#define FCN_RX_DESCQ_SIZE_2K 2
+#define FCN_RX_DESCQ_SIZE_1K 1
+#define FCN_RX_DESCQ_SIZE_512 0
+#define FCN_RX_DESCQ_TYPE_LBN 2
+#define FCN_RX_DESCQ_TYPE_WIDTH 1
+#define FCN_RX_DESCQ_JUMBO_LBN 1
+#define FCN_RX_DESCQ_JUMBO_WIDTH 1
+#define FCN_RX_DESCQ_EN_LBN 0
+#define FCN_RX_DESCQ_EN_WIDTH 1
+
+/* Transmit descriptor pointer table */
+#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91
+#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1
+#define FCN_TX_DESCQ_EN_LBN 88
+#define FCN_TX_DESCQ_EN_WIDTH 1
+#define FCN_TX_ISCSI_DDIG_EN_LBN 87
+#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_TX_ISCSI_HDIG_EN_LBN 86
+#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1
+#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36
+#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FCN_TX_DESCQ_EVQ_ID_LBN 24
+#define FCN_TX_DESCQ_EVQ_ID_WIDTH 12
+#define FCN_TX_DESCQ_OWNER_ID_LBN 10
+#define FCN_TX_DESCQ_OWNER_ID_WIDTH 14
+#define FCN_TX_DESCQ_SIZE_LBN 3
+#define FCN_TX_DESCQ_SIZE_WIDTH 2
+#define FCN_TX_DESCQ_SIZE_4K 3
+#define FCN_TX_DESCQ_SIZE_2K 2
+#define FCN_TX_DESCQ_SIZE_1K 1
+#define FCN_TX_DESCQ_SIZE_512 0
+#define FCN_TX_DESCQ_TYPE_LBN 1
+#define FCN_TX_DESCQ_TYPE_WIDTH 2
+#define FCN_TX_DESCQ_FLUSH_LBN 0
+#define FCN_TX_DESCQ_FLUSH_WIDTH 1
+
+/* Event queue pointer */
+#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000
+#define FCN_EVQ_EN_LBN 23
+#define FCN_EVQ_EN_WIDTH 1
+#define FCN_EVQ_SIZE_LBN 20
+#define FCN_EVQ_SIZE_WIDTH 3
+#define FCN_EVQ_SIZE_32K 6
+#define FCN_EVQ_SIZE_16K 5
+#define FCN_EVQ_SIZE_8K 4
+#define FCN_EVQ_SIZE_4K 3
+#define FCN_EVQ_SIZE_2K 2
+#define FCN_EVQ_SIZE_1K 1
+#define FCN_EVQ_SIZE_512 0
+#define FCN_EVQ_BUF_BASE_ID_LBN 0
+#define FCN_EVQ_BUF_BASE_ID_WIDTH 20
+
+/* RSS indirection table */
+#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000
+
+/* Event queue read pointer */
+#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000
+#define FCN_EVQ_RPTR_LBN 0
+#define FCN_EVQ_RPTR_WIDTH 14
+#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 )
+#define FCN_EVQ_RPTR_DWORD_LBN 0
+#define FCN_EVQ_RPTR_DWORD_WIDTH 14
+
+/* Special buffer descriptors */
+#define FCN_BUF_FULL_TBL_KER_A1 0x18000
+#define FCN_BUF_FULL_TBL_KER_B0 0x800000
+#define FCN_IP_DAT_BUF_SIZE_LBN 50
+#define FCN_IP_DAT_BUF_SIZE_WIDTH 1
+#define FCN_IP_DAT_BUF_SIZE_8K 1
+#define FCN_IP_DAT_BUF_SIZE_4K 0
+#define FCN_BUF_ADR_FBUF_LBN 14
+#define FCN_BUF_ADR_FBUF_WIDTH 34
+#define FCN_BUF_OWNER_ID_FBUF_LBN 0
+#define FCN_BUF_OWNER_ID_FBUF_WIDTH 14
+
+/** Offset of a GMAC register within Falcon */
+#define FALCON_GMAC_REG( efab, mac_reg )				\
+	( FALCON_GMAC_REGBANK +					\
+	  ( (mac_reg) * FALCON_GMAC_REG_SIZE ) )
+
+/** Offset of an XMAC register within Falcon */
+#define FALCON_XMAC_REG( efab_port, mac_reg )			\
+	( FALCON_XMAC_REGBANK +					\
+	  ( (mac_reg) * FALCON_XMAC_REG_SIZE ) )
+
+#define FCN_MAC_DATA_LBN 0
+#define FCN_MAC_DATA_WIDTH 32
+
+/* Transmit descriptor */
+#define FCN_TX_KER_PORT_LBN 63
+#define FCN_TX_KER_PORT_WIDTH 1
+#define FCN_TX_KER_BYTE_CNT_LBN 48
+#define FCN_TX_KER_BYTE_CNT_WIDTH 14
+#define FCN_TX_KER_BUF_ADR_LBN 0
+#define FCN_TX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 )
+
+
+/* Receive descriptor */
+#define FCN_RX_KER_BUF_SIZE_LBN 48
+#define FCN_RX_KER_BUF_SIZE_WIDTH 14
+#define FCN_RX_KER_BUF_ADR_LBN 0
+#define FCN_RX_KER_BUF_ADR_WIDTH EFAB_DMA_TYPE_WIDTH ( 46 )
+
+/* Event queue entries */
+#define FCN_EV_CODE_LBN 60
+#define FCN_EV_CODE_WIDTH 4
+#define FCN_RX_IP_EV_DECODE 0
+#define FCN_TX_IP_EV_DECODE 2
+#define FCN_DRIVER_EV_DECODE 5
+
+/* Receive events */
+#define FCN_RX_EV_PKT_OK_LBN 56
+#define FCN_RX_EV_PKT_OK_WIDTH 1
+#define FCN_RX_PORT_LBN 30
+#define FCN_RX_PORT_WIDTH 1
+#define FCN_RX_EV_BYTE_CNT_LBN 16
+#define FCN_RX_EV_BYTE_CNT_WIDTH 14
+#define FCN_RX_EV_DESC_PTR_LBN 0
+#define FCN_RX_EV_DESC_PTR_WIDTH 12
+
+/* Transmit events */
+#define FCN_TX_EV_DESC_PTR_LBN 0
+#define FCN_TX_EV_DESC_PTR_WIDTH 12
+
+/*******************************************************************************
+ *
+ *
+ * Low-level hardware access
+ *
+ *
+ *******************************************************************************/ 
+
+#define FCN_REVISION_REG(efab, reg) \
+	( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 )
+
+#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val)			\
+	if ( efab->pci_revision == FALCON_REV_B0 )			\
+		EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val );	\
+	else								\
+		EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val );
+
+#if FALCON_USE_IO_BAR
+
+/* Write dword via the I/O BAR */
+static inline void _falcon_writel ( struct efab_nic *efab, uint32_t value,
+				    unsigned int reg ) {
+	outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG );
+	outl ( value, efab->iobase + FCN_IOM_IND_DAT_REG );
+}
+
+/* Read dword via the I/O BAR */
+static inline uint32_t _falcon_readl ( struct efab_nic *efab,
+				       unsigned int reg ) {
+	outl ( reg, efab->iobase + FCN_IOM_IND_ADR_REG );
+	return inl ( efab->iobase + FCN_IOM_IND_DAT_REG );
+}
+
+#else /* FALCON_USE_IO_BAR */
+
+#define _falcon_writel( efab, value, reg ) \
+	writel ( (value), (efab)->membase + (reg) )
+#define _falcon_readl( efab, reg ) readl ( (efab)->membase + (reg) )
+
+#endif /* FALCON_USE_IO_BAR */
+
+/**
+ * Write to a Falcon register
+ *
+ */
+static inline void
+falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
+
+	EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n",
+		       reg, EFAB_OWORD_VAL ( *value ) );
+
+	_falcon_writel ( efab, value->u32[0], reg + 0  );
+	_falcon_writel ( efab, value->u32[1], reg + 4  );
+	_falcon_writel ( efab, value->u32[2], reg + 8  );
+	wmb();
+	_falcon_writel ( efab, value->u32[3], reg + 12 );
+	wmb();
+}
+
+/**
+ * Write to Falcon SRAM
+ *
+ */
+static inline void
+falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value,
+		    unsigned int index )
+{
+	unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
+			     ( index * sizeof ( *value ) ) );
+
+	EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n",
+		       reg, EFAB_QWORD_VAL ( *value ) );
+
+	_falcon_writel ( efab, value->u32[0], reg + 0  );
+	_falcon_writel ( efab, value->u32[1], reg + 4  );
+	wmb();
+}
+
+/**
+ * Write dword to Falcon register that allows partial writes
+ *
+ */
+static inline void
+falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
+	EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n",
+		       reg, EFAB_DWORD_VAL ( *value ) );
+	_falcon_writel ( efab, value->u32[0], reg );
+}
+
+/**
+ * Read from a Falcon register
+ *
+ */
+static inline void
+falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
+	value->u32[0] = _falcon_readl ( efab, reg + 0  );
+	wmb();
+	value->u32[1] = _falcon_readl ( efab, reg + 4  );
+	value->u32[2] = _falcon_readl ( efab, reg + 8  );
+	value->u32[3] = _falcon_readl ( efab, reg + 12 );
+
+	EFAB_REGDUMP ( "Read from register %x, got " EFAB_OWORD_FMT "\n",
+		       reg, EFAB_OWORD_VAL ( *value ) );
+}
+
+/** 
+ * Read from Falcon SRAM
+ *
+ */
+static inline void
+falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value,
+		   unsigned int index )
+{
+	unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
+			     ( index * sizeof ( *value ) ) );
+
+	value->u32[0] = _falcon_readl ( efab, reg + 0 );
+	value->u32[1] = _falcon_readl ( efab, reg + 4 );
+	EFAB_REGDUMP ( "Read from SRAM register %x, got " EFAB_QWORD_FMT "\n",
+		       reg, EFAB_QWORD_VAL ( *value ) );
+}
+
+/**
+ * Read dword from a portion of a Falcon register
+ *
+ */
+static inline void
+falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
+	value->u32[0] = _falcon_readl ( efab, reg );
+	EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
+		       reg, EFAB_DWORD_VAL ( *value ) );
+}
+
+#define FCN_DUMP_REG( efab, _reg ) do {				\
+		efab_oword_t reg;				\
+		falcon_read ( efab, &reg, _reg );		\
+		EFAB_LOG ( #_reg " = " EFAB_OWORD_FMT "\n",	\
+			   EFAB_OWORD_VAL ( reg ) );		\
+	} while ( 0 );
+
+#define FCN_DUMP_MAC_REG( efab, _mac_reg ) do {				\
+		efab_dword_t reg;					\
+		efab->mac_op->mac_readl ( efab, &reg, _mac_reg );	\
+		EFAB_LOG ( #_mac_reg " = " EFAB_DWORD_FMT "\n",		\
+			   EFAB_DWORD_VAL ( reg ) );			\
+	} while ( 0 );
+
+/**
+ * See if an event is present
+ *
+ * @v event		Falcon event structure
+ * @ret True		An event is pending
+ * @ret False		No event is pending
+ *
+ * We check both the high and low dword of the event for all ones.  We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords.  This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int
+falcon_event_present ( falcon_event_t* event )
+{
+	return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
+		     EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
+}
+
+static void
+falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue )
+{
+	efab_dword_t reg;
+
+	EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr );
+	falcon_writel ( efab, &reg,
+			FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) );
+}
+
+#if 0
+/**
+ * Dump register contents (for debugging)
+ *
+ * Marked as static inline so that it will not be compiled in if not
+ * used.
+ */
+static inline void
+falcon_dump_regs ( struct efab_nic *efab )
+{
+	FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_TIMER_CMD_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_SRM_RX_DC_CFG_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_SRM_TX_DC_CFG_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_RX_FILTER_CTL_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_RX_DC_CFG_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER );
+	FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+	FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+	FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
+	FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GM_MII_MGMT_CFG_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GM_ADR1_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GM_ADR2_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG0_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG1_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG2_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG3_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC );
+	FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC );
+}
+#endif
+
+static void
+falcon_interrupts ( struct efab_nic *efab, int enabled, int force )
+{
+	efab_oword_t int_en_reg_ker;
+
+	EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
+				FCN_KER_INT_KER, force,
+				FCN_DRV_INT_EN_KER, enabled );
+	falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );	
+}
+
+/*******************************************************************************
+ *
+ *
+ * SPI access
+ *
+ *
+ *******************************************************************************/ 
+
+
+/** Maximum length for a single SPI transaction */
+#define FALCON_SPI_MAX_LEN 16
+
+static int
+falcon_spi_wait ( struct efab_nic *efab )
+{
+	efab_oword_t reg;
+	int count;
+
+	count = 0;
+	do {
+		udelay ( 100 );
+		falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG );
+		if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 )
+			return 0;
+	} while ( ++count < 1000 );
+
+	EFAB_ERR ( "Timed out waiting for SPI\n" );
+	return -ETIMEDOUT;
+}
+
+static int
+falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device,
+		unsigned int command, int address,
+		const void* data_out, void *data_in, size_t len )
+{
+	struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus );
+	int address_len, rc, device_id, read_cmd;
+	efab_oword_t reg;
+
+	/* falcon_init_spi_device() should have reduced the block size
+	 * down so this constraint holds */
+	assert ( len <= FALCON_SPI_MAX_LEN );
+
+	/* Is this the FLASH or EEPROM device? */
+	if ( device == &efab->spi_flash )
+		device_id = FCN_EE_SPI_FLASH;
+	else if ( device == &efab->spi_eeprom )
+		device_id = FCN_EE_SPI_EEPROM;
+	else {
+		EFAB_ERR ( "Unknown device %p\n", device );
+		return -EINVAL;
+	}
+
+	EFAB_TRACE ( "Executing spi command %d on device %d at %d for %zd bytes\n",
+		     command, device_id, address, len );
+
+	/* The bus must be idle */
+	rc = falcon_spi_wait ( efab );
+	if ( rc )
+		goto fail1;
+
+	/* Copy data out */
+	if ( data_out ) {
+		memcpy ( &reg, data_out, len );
+		falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG );
+	}
+
+	/* Program address register */
+	if ( address >= 0 ) {
+		EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
+		falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG );
+	}
+
+	/* Issue command */
+	address_len = ( address >= 0 ) ? device->address_len / 8 : 0;
+	read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE );
+	EFAB_POPULATE_OWORD_7 ( reg,
+				FCN_EE_SPI_HCMD_CMD_EN, 1,
+				FCN_EE_SPI_HCMD_SF_SEL, device_id,
+				FCN_EE_SPI_HCMD_DABCNT, len,
+				FCN_EE_SPI_HCMD_READ, read_cmd,
+				FCN_EE_SPI_HCMD_DUBCNT, 0,
+				FCN_EE_SPI_HCMD_ADBCNT, address_len,
+				FCN_EE_SPI_HCMD_ENC, command );
+	falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG );
+
+	/* Wait for the command to complete */
+	rc = falcon_spi_wait ( efab );
+	if ( rc )
+		goto fail2;
+
+	/* Copy data in */
+	if ( data_in ) {
+		falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG );
+		memcpy ( data_in, &reg, len );
+	}
+
+	return 0;
+
+fail2:
+fail1:
+	EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%zx\n",
+		   command, device_id, address, len );
+
+	return rc;
+}
+
+/*******************************************************************************
+ *
+ *
+ * Falcon bit-bashed I2C interface
+ *
+ *
+ *******************************************************************************/ 
+
+static void
+falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id,
+		       unsigned long data )
+{
+	struct efab_nic *efab = container_of ( basher, struct efab_nic,
+					       i2c_bb.basher );
+	efab_oword_t reg;
+
+	falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+	switch ( bit_id ) {
+	case I2C_BIT_SCL:
+		EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) );
+		break;
+	case I2C_BIT_SDA:
+		EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) );
+		break;
+	default:
+		EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+		break;
+	}
+
+	falcon_write ( efab, &reg,  FCN_GPIO_CTL_REG_KER );
+}
+
+static int
+falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id )
+{
+	struct efab_nic *efab = container_of ( basher, struct efab_nic,
+					       i2c_bb.basher );
+	efab_oword_t reg;
+	
+	falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+	switch ( bit_id ) {
+	case I2C_BIT_SCL:
+		return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN );
+		break;
+	case I2C_BIT_SDA:
+		return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN );
+		break;
+	default:
+		EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+		break;
+	}
+
+	return -1;
+}
+
+static struct bit_basher_operations falcon_i2c_bit_ops = {
+	.read           = falcon_i2c_bit_read,
+	.write          = falcon_i2c_bit_write,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * MDIO access
+ *
+ *
+ *******************************************************************************/ 
+
+static int
+falcon_gmii_wait ( struct efab_nic *efab )
+{
+	efab_dword_t md_stat;
+	int count;
+
+	/* wait upto 10ms */
+	for (count = 0; count < 1000; count++) {
+		falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER );
+		if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) {
+			if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 ||
+			     EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) {
+				EFAB_ERR ( "Error from GMII access "
+					   EFAB_DWORD_FMT"\n",
+					   EFAB_DWORD_VAL ( md_stat ));
+				return -EIO;
+			}
+			return 0;
+		}
+		udelay(10);
+	}
+
+	EFAB_ERR ( "Timed out waiting for GMII\n" );
+	return -ETIMEDOUT;
+}
+
+static void
+falcon_mdio_write ( struct efab_nic *efab, int device,
+		    int location, int value )
+{
+	efab_oword_t reg;
+
+	EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
+		     device, location, value );
+
+	/* Check MII not currently being accessed */
+	if ( falcon_gmii_wait ( efab ) )
+		return;
+
+	/* Write the address/ID register */
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+	falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+
+	if ( efab->phy_10g ) {
+		/* clause45 */
+		EFAB_POPULATE_OWORD_2 ( reg, 
+					FCN_MD_PRT_ADR, efab->phy_addr,
+					FCN_MD_DEV_ADR, device );
+	}
+	else {
+		/* clause22 */
+		assert ( device == 0 );
+
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_PRT_ADR, efab->phy_addr,
+					FCN_MD_DEV_ADR, location );
+	}
+	falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+		
+
+	/* Write data */
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
+	falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
+
+	EFAB_POPULATE_OWORD_2 ( reg,
+				FCN_MD_WRC, 1,
+				FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) );
+	falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+		
+	/* Wait for data to be written */
+	if ( falcon_gmii_wait ( efab ) ) {
+		/* Abort the write operation */
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_WRC, 0,
+					FCN_MD_GC, 1);
+		falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+		udelay(10);
+	}
+}
+
+static int
+falcon_mdio_read ( struct efab_nic *efab, int device, int location )
+{
+	efab_oword_t reg;
+	int value;
+
+	/* Check MII not currently being accessed */
+	if ( falcon_gmii_wait ( efab ) ) 
+		return -1;
+
+	if ( efab->phy_10g ) {
+		/* clause45 */
+		EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+		falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_PRT_ADR, efab->phy_addr,
+					FCN_MD_DEV_ADR, device );
+		falcon_write ( efab, &reg, FCN_MD_ID_REG_KER);
+
+		/* request data to be read */
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_RDC, 1,
+					FCN_MD_GC, 0 );
+	}
+	else {
+		/* clause22 */
+		assert ( device == 0 );
+
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_PRT_ADR, efab->phy_addr,
+					FCN_MD_DEV_ADR, location );
+		falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+		/* Request data to be read */
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_RIC, 1,
+					FCN_MD_GC, 1 );
+	}
+
+	falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+		
+	/* Wait for data to become available */
+	if ( falcon_gmii_wait ( efab ) ) {
+		/* Abort the read operation */
+		EFAB_POPULATE_OWORD_2 ( reg,
+					FCN_MD_RIC, 0,
+					FCN_MD_GC, 1 );
+		falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+		udelay ( 10 );
+		value = -1;
+	}
+	else {
+		/* Read the data */
+		falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
+		value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+	}
+
+	EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+		     device, location, value );
+
+	return value;
+}
+
+/*******************************************************************************
+ *
+ *
+ * MAC wrapper
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_reconfigure_mac_wrapper ( struct efab_nic *efab )
+{
+	efab_oword_t reg;
+	int link_speed;
+
+	if ( efab->link_options & LPA_EF_10000 ) {
+		link_speed = 0x3;
+	} else if ( efab->link_options & LPA_EF_1000 ) {
+		link_speed = 0x2;
+	} else if ( efab->link_options & LPA_100 ) {
+		link_speed = 0x1;
+	} else {
+		link_speed = 0x0;
+	}
+	EFAB_POPULATE_OWORD_5 ( reg,
+				FCN_MAC_XOFF_VAL, 0xffff /* datasheet */,
+				FCN_MAC_BCAD_ACPT, 1,
+				FCN_MAC_UC_PROM, 0,
+				FCN_MAC_LINK_STATUS, 1,
+				FCN_MAC_SPEED, link_speed );
+
+	falcon_write ( efab, &reg, FCN_MAC0_CTRL_REG_KER );
+}
+
+/*******************************************************************************
+ *
+ *
+ * GMAC handling
+ *
+ *
+ *******************************************************************************/
+
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG_MAC 0x00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG_MAC 0x01
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG_MAC 0x04
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC MII management configuration register */
+#define GM_MII_MGMT_CFG_REG_MAC 0x08
+#define GM_MGMT_CLK_SEL_LBN 0
+#define GM_MGMT_CLK_SEL_WIDTH 3
+
+/* GMAC MII management command register */
+#define GM_MII_MGMT_CMD_REG_MAC 0x09
+#define GM_MGMT_SCAN_CYC_LBN 1
+#define GM_MGMT_SCAN_CYC_WIDTH 1
+#define GM_MGMT_RD_CYC_LBN 0
+#define GM_MGMT_RD_CYC_WIDTH 1
+
+/* GMAC MII management address register */
+#define GM_MII_MGMT_ADR_REG_MAC 0x0a
+#define GM_MGMT_PHY_ADDR_LBN 8
+#define GM_MGMT_PHY_ADDR_WIDTH 5
+#define GM_MGMT_REG_ADDR_LBN 0
+#define GM_MGMT_REG_ADDR_WIDTH 5
+
+/* GMAC MII management control register */
+#define GM_MII_MGMT_CTL_REG_MAC 0x0b
+#define GM_MGMT_CTL_LBN 0
+#define GM_MGMT_CTL_WIDTH 16
+
+/* GMAC MII management status register */
+#define GM_MII_MGMT_STAT_REG_MAC 0x0c
+#define GM_MGMT_STAT_LBN 0
+#define GM_MGMT_STAT_WIDTH 16
+
+/* GMAC MII management indicators register */
+#define GM_MII_MGMT_IND_REG_MAC 0x0d
+#define GM_MGMT_BUSY_LBN 0
+#define GM_MGMT_BUSY_WIDTH 1
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG_MAC 0x10
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG_MAC 0x11
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG_MAC 0x12
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG_MAC 0x13
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG_MAC 0x14
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG_MAC 0x15
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG_MAC 0x16
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG_MAC 0x17
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+static void
+falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+		     unsigned int mac_reg )
+{
+	efab_oword_t temp;
+
+	EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
+				EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) );
+	falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
+}
+
+static void
+falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+		    unsigned int mac_reg )
+{
+	efab_oword_t temp;
+
+	falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
+	EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA,
+				EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
+}
+
+static void
+mentormac_reset ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+
+	/* Take into reset */
+	EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
+	falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+	udelay ( 1000 );
+
+	/* Take out of reset */
+	EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
+	falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+	udelay ( 1000 );
+
+	/* Configure GMII interface so PHY is accessible.  Note that
+	 * GMII interface is connected only to port 0, and that on
+	 * Falcon this is a no-op.
+	 */
+	EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
+	falcon_gmac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
+	udelay ( 10 );
+}
+
+static void
+mentormac_init ( struct efab_nic *efab )
+{
+	int pause, if_mode, full_duplex, bytemode, half_duplex;
+	efab_dword_t reg;
+
+	/* Configuration register 1 */
+	pause = ( efab->link_options & LPA_PAUSE_CAP ) ? 1 : 0;
+	if ( ! ( efab->link_options & LPA_EF_DUPLEX ) ) {
+		/* Half-duplex operation requires TX flow control */
+		pause = 1;
+	}
+	EFAB_POPULATE_DWORD_4 ( reg,
+				GM_TX_EN, 1,
+				GM_TX_FC_EN, pause,
+				GM_RX_EN, 1,
+				GM_RX_FC_EN, 1 );
+	falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+	udelay ( 10 );
+
+	/* Configuration register 2 */
+	if_mode = ( efab->link_options & LPA_EF_1000 ) ? 2 : 1;
+	full_duplex = ( efab->link_options & LPA_EF_DUPLEX ) ? 1 : 0;
+	EFAB_POPULATE_DWORD_4 ( reg,
+				GM_IF_MODE, if_mode,
+				GM_PAD_CRC_EN, 1,
+				GM_FD, full_duplex,
+				GM_PAMBL_LEN, 0x7 /* ? */ );
+	falcon_gmac_writel ( efab, &reg, GM_CFG2_REG_MAC );
+	udelay ( 10 );
+
+	/* Max frame len register */
+	EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN,
+				EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) );
+	falcon_gmac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
+	udelay ( 10 );
+
+	/* FIFO configuration register 0 */
+	EFAB_POPULATE_DWORD_5 ( reg,
+				GMF_FTFENREQ, 1,
+				GMF_STFENREQ, 1,
+				GMF_FRFENREQ, 1,
+				GMF_SRFENREQ, 1,
+				GMF_WTMENREQ, 1 );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
+	udelay ( 10 );
+
+	/* FIFO configuration register 1 */
+	EFAB_POPULATE_DWORD_2 ( reg,
+				GMF_CFGFRTH, 0x12,
+				GMF_CFGXOFFRTX, 0xffff );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
+	udelay ( 10 );
+
+	/* FIFO configuration register 2 */
+	EFAB_POPULATE_DWORD_2 ( reg,
+				GMF_CFGHWM, 0x3f,
+				GMF_CFGLWM, 0xa );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
+	udelay ( 10 );
+
+	/* FIFO configuration register 3 */
+	EFAB_POPULATE_DWORD_2 ( reg,
+				GMF_CFGHWMFT, 0x1c,
+				GMF_CFGFTTH, 0x08 );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
+	udelay ( 10 );
+
+	/* FIFO configuration register 4 */
+	EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
+	udelay ( 10 );
+	
+	/* FIFO configuration register 5 */
+	bytemode = ( efab->link_options & LPA_EF_1000 ) ? 1 : 0;
+	half_duplex = ( efab->link_options & LPA_EF_DUPLEX ) ? 0 : 1;
+	falcon_gmac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
+	EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
+	EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
+	EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
+	EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
+	falcon_gmac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
+	udelay ( 10 );
+	
+	/* MAC address */
+	EFAB_POPULATE_DWORD_4 ( reg,
+				GM_HWADDR_5, efab->mac_addr[5],
+				GM_HWADDR_4, efab->mac_addr[4],
+				GM_HWADDR_3, efab->mac_addr[3],
+				GM_HWADDR_2, efab->mac_addr[2] );
+	falcon_gmac_writel ( efab, &reg, GM_ADR1_REG_MAC );
+	udelay ( 10 );
+	EFAB_POPULATE_DWORD_2 ( reg,
+				GM_HWADDR_1, efab->mac_addr[1],
+				GM_HWADDR_0, efab->mac_addr[0] );
+	falcon_gmac_writel ( efab, &reg, GM_ADR2_REG_MAC );
+	udelay ( 10 );
+}
+
+static int
+falcon_init_gmac ( struct efab_nic *efab )
+{
+	/* Reset the MAC */
+	mentormac_reset ( efab );
+
+	/* Initialise PHY */
+	efab->phy_op->init ( efab );
+
+	/* check the link is up */
+	if ( !efab->link_up )
+		return -EAGAIN;
+
+	/* Initialise MAC */
+	mentormac_init ( efab );
+
+	/* reconfigure the MAC wrapper */
+	falcon_reconfigure_mac_wrapper ( efab );
+
+	return 0;
+}
+
+static struct efab_mac_operations falcon_gmac_operations = {
+	.init                   = falcon_init_gmac,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * XMAC handling
+ *
+ *
+ *******************************************************************************/
+
+/**
+ * Write dword to a Falcon XMAC register
+ *
+ */
+static void
+falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+		     unsigned int mac_reg )
+{
+	efab_oword_t temp;
+
+	EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
+				EFAB_DWORD_FIELD ( *value, FCN_MAC_DATA ) );
+	falcon_write ( efab, &temp,
+		       FALCON_XMAC_REG ( efab, mac_reg ) );
+}
+
+/**
+ * Read dword from a Falcon XMAC register
+ *
+ */
+static void
+falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+		    unsigned int mac_reg )
+{
+	efab_oword_t temp;
+
+	falcon_read ( efab, &temp,
+		      FALCON_XMAC_REG ( efab, mac_reg ) );
+	EFAB_POPULATE_DWORD_1 ( *value, FCN_MAC_DATA,
+				EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
+}
+
+/**
+ * Configure Falcon XAUI output
+ */
+static void
+falcon_setup_xaui ( struct efab_nic *efab )
+{
+	efab_dword_t sdctl, txdrv;
+
+	falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT );
+	EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT );
+	falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+
+	EFAB_POPULATE_DWORD_8 ( txdrv,
+				FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+				FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+				FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+				FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+				FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+				FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+				FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+				FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+	falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC);
+}
+
+static int
+falcon_xgmii_status ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+
+	if ( efab->pci_revision  < FALCON_REV_B0 )
+		return 1;
+	/* The ISR latches, so clear it and re-read */
+	falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+	falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+	if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) ||
+	     EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) {
+		EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n",
+			     EFAB_DWORD_VAL ( reg ) );
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+falcon_mask_status_intr ( struct efab_nic *efab, int enable )
+{
+	efab_dword_t reg;
+
+	if ( efab->pci_revision  < FALCON_REV_B0 )
+		return;
+
+	/* Flush the ISR */
+	if ( enable )
+		falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+	EFAB_POPULATE_DWORD_2 ( reg,
+				FCN_XM_MSK_RMTFLT, !enable,
+				FCN_XM_MSK_LCLFLT, !enable);
+	falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_MSK_REG_MAC_B0 );
+}
+
+/**
+ * Reset 10G MAC connected to port
+ *
+ */
+static int
+falcon_reset_xmac ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+	int count;
+
+	EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+
+	for ( count = 0 ; count < 1000 ; count++ ) {
+		udelay ( 10 );
+		falcon_xmac_readl ( efab, &reg,
+				    FCN_XM_GLB_CFG_REG_MAC );
+		if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
+			return 0;
+	}
+	return -ETIMEDOUT;
+}
+
+
+static int
+falcon_reset_xaui ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+	int count;
+
+	if (!efab->is_asic)
+		return 0;
+
+	EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
+	falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+	/* Give some time for the link to establish */
+	for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+		falcon_xmac_readl ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+		if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) {
+			falcon_setup_xaui ( efab );
+			return 0;
+		}
+		udelay(10);
+	}
+	EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" );
+	return -ETIMEDOUT;
+}
+
+static int
+falcon_xaui_link_ok ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+	int align_done, lane_status, sync;
+	int has_phyxs;
+	int link_ok = 1;
+
+	/* Read Falcon XAUI side */
+	if ( efab->is_asic ) {
+		/* Read link status */
+		falcon_xmac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+		align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
+
+		sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
+		sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED );
+		
+		link_ok = align_done && sync;
+	}
+
+	/* Clear link status ready for next read */
+	EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET );
+	EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET);
+	EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET);
+	falcon_xmac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+
+	has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) );
+	if ( link_ok && has_phyxs ) {
+		lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+						 MDIO_PHYXS_LANE_STATE );
+		link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) );
+
+		if (!link_ok )
+			EFAB_LOG ( "XGXS lane status: %x\n", lane_status );
+	}
+
+	return link_ok;
+}
+
+/**
+ * Initialise XMAC
+ *
+ */
+static void
+falcon_reconfigure_xmac ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+	int max_frame_len;
+
+	/* Configure MAC - cut-thru mode is hard wired on */
+	EFAB_POPULATE_DWORD_3 ( reg,
+				FCN_XM_RX_JUMBO_MODE, 1,
+				FCN_XM_TX_STAT_EN, 1,
+				FCN_XM_RX_STAT_EN, 1);
+	falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+
+	/* Configure TX */
+	EFAB_POPULATE_DWORD_6 ( reg, 
+				FCN_XM_TXEN, 1,
+				FCN_XM_TX_PRMBL, 1,
+				FCN_XM_AUTO_PAD, 1,
+				FCN_XM_TXCRC, 1,
+				FCN_XM_FCNTL, 1,
+				FCN_XM_IPG, 0x3 );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
+
+	/* Configure RX */
+	EFAB_POPULATE_DWORD_4 ( reg,
+				FCN_XM_RXEN, 1,
+				FCN_XM_AUTO_DEPAD, 0,
+				FCN_XM_ACPT_ALL_MCAST, 1,
+				FCN_XM_PASS_CRC_ERR, 1 );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
+
+	/* Set frame length */
+	max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN );
+	EFAB_POPULATE_DWORD_1 ( reg,
+				FCN_XM_MAX_RX_FRM_SIZE, max_frame_len );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
+	EFAB_POPULATE_DWORD_2 ( reg,
+				FCN_XM_MAX_TX_FRM_SIZE, max_frame_len,
+				FCN_XM_TX_JUMBO_MODE, 1 );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+
+	/* Enable flow control receipt */
+	EFAB_POPULATE_DWORD_2 ( reg,
+				FCN_XM_PAUSE_TIME, 0xfffe,
+				FCN_XM_DIS_FCNTL, 0 );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_FC_REG_MAC );
+
+	/* Set MAC address */
+	EFAB_POPULATE_DWORD_4 ( reg,
+				FCN_XM_ADR_0, efab->mac_addr[0],
+				FCN_XM_ADR_1, efab->mac_addr[1],
+				FCN_XM_ADR_2, efab->mac_addr[2],
+				FCN_XM_ADR_3, efab->mac_addr[3] );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
+	EFAB_POPULATE_DWORD_2 ( reg,
+				FCN_XM_ADR_4, efab->mac_addr[4],
+				FCN_XM_ADR_5, efab->mac_addr[5] );
+	falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+}
+
+static int
+falcon_init_xmac ( struct efab_nic *efab )
+{
+	int count, rc;
+
+	/* Mask the PHY management interrupt */
+	falcon_mask_status_intr ( efab, 0 );
+
+	/* Initialise the PHY to instantiate the clock. */
+	rc = efab->phy_op->init ( efab );
+	if ( rc ) {
+		EFAB_ERR ( "unable to initialise PHY\n" );
+		goto fail1;
+	}
+
+	falcon_reset_xaui ( efab );
+
+	/* Give the PHY and MAC time to faff */
+	mdelay ( 100 );
+
+	/* Reset and reconfigure the XMAC */
+	rc = falcon_reset_xmac ( efab );
+	if ( rc )
+		goto fail2;
+	falcon_reconfigure_xmac ( efab );
+	falcon_reconfigure_mac_wrapper ( efab );
+	/**
+	 * Now wait for the link to come up. This may take a while
+	 * for some slower PHY's.
+	 */
+	for (count=0; count<50; count++) {
+		int link_ok = 1;
+
+		/* Wait a while for the link to come up. */
+		mdelay ( 100 );
+		if ((count % 5) == 0)
+			putchar ( '.' );
+
+		/* Does the PHY think the wire-side link is up? */
+		link_ok = mdio_clause45_links_ok ( efab );
+		/* Ensure the XAUI link to the PHY is good */
+		if ( link_ok ) {
+			link_ok = falcon_xaui_link_ok ( efab );
+			if ( !link_ok )
+				falcon_reset_xaui ( efab );
+		}
+
+		/* Check fault indication */
+		if ( link_ok )
+			link_ok = falcon_xgmii_status ( efab );
+
+		efab->link_up = link_ok;
+		if ( link_ok ) {
+			/* unmask the status interrupt */
+			falcon_mask_status_intr ( efab, 1 );
+			return 0;
+		}
+	}
+
+	/* Link failed to come up, but initialisation was fine. */
+	rc = -ETIMEDOUT;
+
+fail2:
+fail1:
+	return rc;
+}
+
+static struct efab_mac_operations falcon_xmac_operations = {
+	.init                   = falcon_init_xmac,
+};
+
+/*******************************************************************************
+ *
+ *
+ * Null PHY handling
+ *
+ *
+ *******************************************************************************/
+
+static int
+falcon_xaui_phy_init ( struct efab_nic *efab )
+{
+	/* CX4 is always 10000FD only */
+	efab->link_options = LPA_EF_10000FULL;
+
+	/* There is no PHY! */
+	return 0;
+}
+
+static struct efab_phy_operations falcon_xaui_phy_ops = {
+	.init                   = falcon_xaui_phy_init,
+	.mmds                   = 0,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * Alaska PHY
+ *
+ *
+ *******************************************************************************/
+
+/**
+ * Initialise Alaska PHY
+ *
+ */
+static int
+alaska_init ( struct efab_nic *efab )
+{
+	unsigned int advertised, lpa;
+
+	/* Read link up status */
+	efab->link_up = gmii_link_ok ( efab );
+
+	if ( ! efab->link_up )
+		return -EIO;
+
+	/* Determine link options from PHY. */
+	advertised = gmii_autoneg_advertised ( efab );
+	lpa = gmii_autoneg_lpa ( efab );
+	efab->link_options = gmii_nway_result ( advertised & lpa );
+
+	return 0;
+}
+
+static struct efab_phy_operations falcon_alaska_phy_ops = {
+	.init  	    	= alaska_init,
+};
+
+/*******************************************************************************
+ *
+ *
+ * xfp
+ *
+ *
+ *******************************************************************************/
+
+#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS    |		\
+			    MDIO_MMDREG_DEVS0_PMAPMD |		\
+			    MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_xfp_phy_init ( struct efab_nic *efab )
+{
+	int rc;
+
+	/* Optical link is always 10000FD only */
+	efab->link_options = LPA_EF_10000FULL;
+
+	/* Reset the PHY */
+	rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS );
+	if ( rc )
+		return rc;
+
+	return 0;
+}
+
+static struct efab_phy_operations falcon_xfp_phy_ops = {
+	.init                   = falcon_xfp_phy_init,
+	.mmds                   = XFP_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * txc43128
+ *
+ *
+ *******************************************************************************/
+
+/* Command register */
+#define TXC_GLRGS_GLCMD		(0xc004)
+#define TXC_GLCMD_LMTSWRST_LBN	(14)
+
+/* Amplitude on lanes 0+1, 2+3 */
+#define  TXC_ALRGS_ATXAMP0	(0xc041)
+#define  TXC_ALRGS_ATXAMP1	(0xc042)
+/* Bit position of value for lane 0+2, 1+3 */
+#define TXC_ATXAMP_LANE02_LBN	(3)
+#define TXC_ATXAMP_LANE13_LBN	(11)
+
+#define TXC_ATXAMP_1280_mV	(0)
+#define TXC_ATXAMP_1200_mV	(8)
+#define TXC_ATXAMP_1120_mV	(12)
+#define TXC_ATXAMP_1060_mV	(14)
+#define TXC_ATXAMP_0820_mV	(25)
+#define TXC_ATXAMP_0720_mV	(26)
+#define TXC_ATXAMP_0580_mV	(27)
+#define TXC_ATXAMP_0440_mV	(28)
+
+#define TXC_ATXAMP_0820_BOTH	( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \
+				  (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) )
+
+#define TXC_ATXAMP_DEFAULT	(0x6060) /* From databook */
+
+/* Preemphasis on lanes 0+1, 2+3 */
+#define  TXC_ALRGS_ATXPRE0	(0xc043)
+#define  TXC_ALRGS_ATXPRE1	(0xc044)
+
+#define TXC_ATXPRE_NONE (0)
+#define TXC_ATXPRE_DEFAULT	(0x1010) /* From databook */
+
+#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS    |	       \
+			    MDIO_MMDREG_DEVS0_PMAPMD |	       \
+			    MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_txc_logic_reset ( struct efab_nic *efab )
+{
+	int val;
+	int tries = 50;
+
+	val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+	val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
+	falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val );
+
+	while ( tries--) {
+		val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+		if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) )
+			return 0;
+		udelay(1);
+	}
+
+	EFAB_ERR ( "logic reset failed\n" );
+
+	return -ETIMEDOUT;
+}
+
+static int
+falcon_txc_phy_init ( struct efab_nic *efab )
+{
+	int rc;
+
+	/* CX4 is always 10000FD only */
+	efab->link_options = LPA_EF_10000FULL;
+
+	/* reset the phy */
+	rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD );
+	if ( rc )
+		goto fail1;
+
+	rc = mdio_clause45_check_mmds ( efab );
+	if ( rc )
+		goto fail2;
+
+	/* Turn amplitude down and preemphasis off on the host side
+	 * (PHY<->MAC) as this is believed less likely to upset falcon
+	 * and no adverse effects have been noted. It probably also 
+	 * saves a picowatt or two */
+
+	/* Turn off preemphasis */
+	falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0,
+			    TXC_ATXPRE_NONE );
+	falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1,
+			    TXC_ATXPRE_NONE );
+
+	/* Turn down the amplitude */
+	falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0,
+			    TXC_ATXAMP_0820_BOTH );
+	falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1,
+			    TXC_ATXAMP_0820_BOTH );
+
+	/* Set the line side amplitude and preemphasis to the databook
+	 * defaults as an erratum causes them to be 0 on at least some
+	 * PHY rev.s */
+	falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0,
+			    TXC_ATXPRE_DEFAULT );
+	falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1,
+			    TXC_ATXPRE_DEFAULT );
+	falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0,
+			    TXC_ATXAMP_DEFAULT );
+	falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1,
+			    TXC_ATXAMP_DEFAULT );
+
+	rc = falcon_txc_logic_reset ( efab );
+	if ( rc )
+		goto fail3;
+
+	return 0;
+
+fail3:
+fail2:
+fail1:
+	return rc;
+}
+
+static struct efab_phy_operations falcon_txc_phy_ops = {
+	.init                   = falcon_txc_phy_init,
+	.mmds                   = TXC_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * tenxpress
+ *
+ *
+ *******************************************************************************/
+
+
+#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD |	\
+				  MDIO_MMDREG_DEVS0_PCS    |	\
+				  MDIO_MMDREG_DEVS0_PHYXS )
+
+#define	PCS_TEST_SELECT_REG 0xd807	/* PRM 10.5.8 */
+#define	CLK312_EN_LBN 3
+#define	CLK312_EN_WIDTH 1
+
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG	0xd000
+#define PCS_BOOT_FATAL_ERR_LBN	0
+#define PCS_BOOT_PROGRESS_LBN	1
+#define PCS_BOOT_PROGRESS_WIDTH	2
+#define PCS_BOOT_COMPLETE_LBN	3
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+static int
+falcon_tenxpress_check_c11 ( struct efab_nic *efab )
+{
+	int count;
+	uint32_t boot_stat;
+
+	/* Check that the C11 CPU has booted */
+	for (count=0; count<10; count++) {
+		boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS,
+					       PCS_BOOT_STATUS_REG );
+		if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) )
+			return 0;
+
+		udelay(10);
+	}
+
+	EFAB_ERR ( "C11 failed to boot\n" );
+	return -ETIMEDOUT;
+}
+
+static int
+falcon_tenxpress_phy_init ( struct efab_nic *efab )
+{
+	int rc, reg;
+
+	/* 10XPRESS is always 10000FD (at the moment) */
+	efab->link_options = LPA_EF_10000FULL;
+
+	/* Wait for the blocks to come out of reset */
+	rc = mdio_clause45_wait_reset_mmds ( efab );
+	if ( rc )
+		goto fail1;
+
+	rc = mdio_clause45_check_mmds ( efab );
+	if ( rc )
+		goto fail2;
+
+	/* Turn on the clock  */
+	reg = (1 << CLK312_EN_LBN);
+	falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+	/* Wait 200ms for the PHY to boot */
+	mdelay(200);
+
+	rc = falcon_tenxpress_check_c11 ( efab );
+	if ( rc )
+		goto fail3;
+
+	return 0;
+
+fail3:
+fail2:
+fail1:
+	return rc;
+}
+
+static struct efab_phy_operations falcon_tenxpress_phy_ops = {
+	.init                   = falcon_tenxpress_phy_init,
+	.mmds                   = TENXPRESS_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * PM8358
+ *
+ *
+ *******************************************************************************/
+
+/* The PM8358 just presents a DTE XS */
+#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
+
+/* PHY-specific definitions */
+/* Master ID and Global Performance Monitor Update */
+#define PMC_MASTER_REG (0xd000)
+/* Analog Tx Rx settings under software control */
+#define PMC_MASTER_ANLG_CTRL (1<< 11)
+
+/* Master Configuration register 2 */
+#define PMC_MCONF2_REG	(0xd002)
+/* Drive Tx off centre of data eye (1) vs. clock edge (0) */
+#define	PMC_MCONF2_TEDGE (1 << 2) 
+/* Drive Rx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_REDGE (1 << 3)
+
+/* Analog Rx settings */
+#define PMC_ANALOG_RX_CFG0   (0xd025)
+#define PMC_ANALOG_RX_CFG1   (0xd02d)
+#define PMC_ANALOG_RX_CFG2   (0xd035)
+#define PMC_ANALOG_RX_CFG3   (0xd03d)
+
+
+#define PMC_ANALOG_RX_TERM     (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float,
+					    1 for 50 to 1.2V */
+#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
+#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
+#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
+#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
+#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
+
+static int
+falcon_pm8358_phy_init ( struct efab_nic *efab )
+{
+	int rc, reg, i;
+
+	/* This is a XAUI retimer part */
+	efab->link_options = LPA_EF_10000FULL;
+
+	rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS );
+	if ( rc )
+		return rc;
+	
+	/* Enable software control of analogue settings */
+	reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS,  PMC_MASTER_REG );
+	reg |= PMC_MASTER_ANLG_CTRL;
+	falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg );
+
+	/* Turn rx eq on for all channels */
+	for (i=0; i< 3; i++) {
+		/* The analog CFG registers are evenly spaced 8 apart */
+		uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i;
+		reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr );
+		reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL;
+		falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg );
+	}
+
+	/* Set TEDGE, clear REDGE */
+	reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG );
+	reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE;
+	falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg );
+
+	return 0;
+}
+
+static struct efab_phy_operations falcon_pm8358_phy_ops = {
+	.init                   = falcon_pm8358_phy_init,
+	.mmds                   = PM8358_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * SFE4001 support
+ *
+ *
+ *******************************************************************************/
+
+#define MAX_TEMP_THRESH 90
+
+/* I2C Expander */
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+/* Temperature Sensor */
+#define MAX6647	0x4e
+
+#define RSL	0x02
+#define RLHN	0x05
+#define WLHO	0x0b
+
+static struct i2c_device i2c_pca9539 = {
+	.dev_addr = PCA9539,
+	.dev_addr_len = 1,
+	.word_addr_len = 1,
+};
+
+
+static struct i2c_device i2c_max6647 = {
+	.dev_addr = MAX6647,
+	.dev_addr_len = 1,
+	.word_addr_len = 1,
+};
+
+static int
+sfe4001_init ( struct efab_nic *efab )
+{
+	struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+	efab_dword_t reg;
+	uint8_t in, cfg, out;
+	int count, rc;
+
+	EFAB_LOG ( "Initialise SFE4001 board\n" );
+
+	/* Ensure XGXS and XAUI SerDes are held in reset */
+	EFAB_POPULATE_DWORD_7 ( reg,
+				FCN_XX_PWRDNA_EN, 1,
+				FCN_XX_PWRDNB_EN, 1,
+				FCN_XX_RSTPLLAB_EN, 1,
+				FCN_XX_RESETA_EN, 1,
+				FCN_XX_RESETB_EN, 1,
+				FCN_XX_RSTXGXSRX_EN, 1,
+				FCN_XX_RSTXGXSTX_EN, 1 );
+	falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC);
+	udelay(10);
+
+	/* Set DSP over-temperature alert threshold */
+	cfg = MAX_TEMP_THRESH;
+	rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE );
+	if ( rc )
+		goto fail1;
+
+	/* Read it back and verify */
+	rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE );
+	if ( rc )
+		goto fail2;
+
+	if ( in != MAX_TEMP_THRESH ) {
+		EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d "
+			   "confirmed=%d)\n", cfg, in );
+		rc = -EIO;
+		goto fail3;
+	}
+
+	/* Clear any previous over-temperature alert */
+	rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+	if ( rc )
+		goto fail4;
+
+	/* Enable port 0 and 1 outputs on IO expander */
+	cfg = 0x00;
+	rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+	if ( rc )
+		goto fail5;
+	cfg = 0xff & ~(1 << P1_SPARE_LBN);
+	rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+	if ( rc )
+		goto fail6;
+
+	/* Turn all power off then wait 1 sec. This ensures PHY is reset */
+	out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+		       (0 << P0_EN_1V0X_LBN));
+
+	rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+	if ( rc )
+		goto fail7;
+
+	mdelay(1000);
+
+	for (count=0; count<20; count++) {
+		/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+		out = 0xff & ~( (1 << P0_EN_1V2_LBN)  | (1 << P0_EN_2V5_LBN) |
+				(1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN)  | 
+				(1 << P0_X_TRST_LBN) );
+
+		rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+		if ( rc )
+			goto fail8;
+
+		mdelay ( 10 );
+		
+		/* Turn on the 1V power rail */
+		out  &= ~( 1 << P0_EN_1V0X_LBN );
+		rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+		if ( rc )
+			goto fail9;
+
+		EFAB_LOG ( "Waiting for power...(attempt %d)\n", count);
+		mdelay ( 1000 );
+
+		/* Check DSP is powered */
+		rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE );
+		if ( rc )
+			goto fail10;
+
+		if ( in & ( 1 << P1_AFE_PWD_LBN ) )
+			return 0;
+	}
+
+	rc = -ETIMEDOUT;
+
+fail10:
+fail9:
+fail8:
+fail7:
+	/* Turn off power rails */
+	out = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+	/* Disable port 1 outputs on IO expander */
+	out = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail6:
+	/* Disable port 0 outputs */
+	out = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail5:
+fail4:
+fail3:
+fail2:
+fail1:
+	EFAB_ERR ( "Failed initialising SFE4001 board\n" );
+	return rc;
+}
+
+static void
+sfe4001_fini ( struct efab_nic *efab )
+{
+	struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+	uint8_t in, cfg, out;
+
+	EFAB_ERR ( "Turning off SFE4001\n" );
+
+	/* Turn off all power rails */
+	out = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+
+	/* Disable port 1 outputs on IO expander */
+	cfg = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+
+	/* Disable port 0 outputs on IO expander */
+	cfg = 0xff;
+	(void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+
+	/* Clear any over-temperature alert */
+	(void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+}
+
+struct efab_board_operations sfe4001_ops = {
+	.init		= sfe4001_init,
+	.fini		= sfe4001_fini,
+};
+
+static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+	return 0;
+}
+static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4002_ops = {
+	.init		= sfe4002_init,
+	.fini		= sfe4002_fini,
+};
+
+static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+	return 0;
+}
+static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4003_ops = {
+	.init		= sfe4003_init,
+	.fini		= sfe4003_fini,
+};
+
+/*******************************************************************************
+ *
+ *
+ * Hardware initialisation
+ *
+ *
+ *******************************************************************************/ 
+
+static void
+falcon_free_special_buffer ( void *p )
+{
+	/* We don't bother cleaning up the buffer table entries -
+	 * we're hardly limited */
+	free_dma ( p, EFAB_BUF_ALIGN );
+}
+
+static void*
+falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes,
+			      struct efab_special_buffer *entry )
+{
+	void* buffer;
+	int remaining;
+	efab_qword_t buf_desc;
+	unsigned long dma_addr;
+
+	/* Allocate the buffer, aligned on a buffer address boundary */
+	buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN );
+	if ( ! buffer )
+		return NULL;
+
+	/* Push buffer table entries to back the buffer */
+	entry->id = efab->buffer_head;
+	entry->dma_addr = dma_addr = virt_to_bus ( buffer );
+	assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
+
+	remaining = bytes;
+	while ( remaining > 0 ) {
+		EFAB_POPULATE_QWORD_3 ( buf_desc,
+					FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
+					FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
+					FCN_BUF_OWNER_ID_FBUF, 0 );
+
+		falcon_write_sram ( efab, &buf_desc, efab->buffer_head );
+
+		++efab->buffer_head;
+		dma_addr += EFAB_BUF_ALIGN;
+		remaining -= EFAB_BUF_ALIGN;
+	}
+
+	EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table "
+		     "entries 0x%x..0x%x\n", bytes, buffer, entry->id,
+		     efab->buffer_head - 1 );
+
+	return buffer;
+}
+
+static void
+clear_b0_fpga_memories ( struct efab_nic *efab)
+{
+	efab_oword_t blanko, temp;
+	int offset; 
+
+	EFAB_ZERO_OWORD ( blanko );
+
+	/* Clear the address region register */
+	EFAB_POPULATE_OWORD_4 ( temp,
+				FCN_ADR_REGION0, 0,
+				FCN_ADR_REGION1, ( 1 << 16 ),
+				FCN_ADR_REGION2, ( 2 << 16 ),
+				FCN_ADR_REGION3, ( 3 << 16 ) );
+	falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER );
+	
+	EFAB_TRACE ( "Clearing filter and RSS tables\n" );
+
+	for ( offset = FCN_RX_FILTER_TBL0 ;
+	      offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ;
+	      offset += 0x10 ) {
+		falcon_write ( efab, &blanko, offset );
+	}
+
+	EFAB_TRACE ( "Wiping buffer tables\n" );
+
+	/* Notice the 8 byte access mode */
+	for ( offset = 0x2800000 ;
+	      offset < 0x3000000 ;
+	      offset += 0x8) {
+		_falcon_writel ( efab, 0, offset );
+		_falcon_writel ( efab, 0, offset + 4 );
+		wmb();
+	}
+}
+
+static int
+falcon_reset ( struct efab_nic *efab )
+{
+	efab_oword_t glb_ctl_reg_ker;
+
+	/* Initiate software reset */
+	EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker,
+				FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+				FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+				FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+				FCN_EE_RST_CTL, EXCLUDE_FROM_RESET,
+				FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */
+				FCN_SWRST, 1 );
+
+	falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+
+	/* Allow 50ms for reset */
+	mdelay ( 50 );
+
+	/* Check for device reset complete */
+	falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+	if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) {
+		EFAB_ERR ( "Reset failed\n" );
+		return -ETIMEDOUT;
+	}
+
+	if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) {
+		clear_b0_fpga_memories ( efab );
+	}
+
+	return 0;
+}
+
+/** Offset of MAC address within EEPROM or Flash */
+#define FALCON_MAC_ADDRESS_OFFSET 0x310
+
+/*
+ * Falcon EEPROM structure
+ */
+#define SF_NV_CONFIG_BASE 0x300
+#define SF_NV_CONFIG_EXTRA 0xA0
+
+struct falcon_nv_config_ver2 {
+	uint16_t nports;
+	uint8_t  port0_phy_addr;
+	uint8_t  port0_phy_type;
+	uint8_t  port1_phy_addr;
+	uint8_t  port1_phy_type;
+	uint16_t asic_sub_revision;
+	uint16_t board_revision;
+	uint8_t mac_location;
+};
+
+struct falcon_nv_extra {
+	uint16_t magicnumber;
+	uint16_t structure_version;
+	uint16_t checksum;
+	union {
+		struct falcon_nv_config_ver2 ver2;
+	} ver_specific;
+};
+
+#define BOARD_TYPE(_rev) (_rev >> 8)
+
+static void
+falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci )
+{
+	efab_oword_t altera_build, nic_stat;
+	int fpga_version;
+	uint8_t revision;
+
+	/* PCI revision */
+	pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision );
+	efab->pci_revision = revision;
+
+	/* Asic vs FPGA */
+	falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER );
+	fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL );
+	efab->is_asic = (fpga_version == 0);
+
+	/* MAC and PCI type */
+	falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+	if ( efab->pci_revision == FALCON_REV_B0 ) {
+		efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
+	}
+	else if ( efab->is_asic ) {
+		efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
+	}
+	else {
+		int minor = EFAB_OWORD_FIELD ( altera_build,  FCN_VER_MINOR );
+		efab->phy_10g = ( minor == 0x14 );
+	}
+}
+
+static void
+falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi )
+{
+	/* Falcon's SPI interface only supports reads/writes of up to 16 bytes.
+	 * Reduce the nvs block size down to satisfy this - which means callers
+	 * should use the nvs_* functions rather than spi_*. */
+	if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN )
+		spi->nvs.block_size = FALCON_SPI_MAX_LEN;
+
+	spi->bus = &efab->spi_bus;
+	efab->spi = spi;
+}
+
+static int
+falcon_probe_spi ( struct efab_nic *efab )
+{
+	efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+	int has_flash, has_eeprom, ad9bit;
+
+	falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+	falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER );
+	falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG );
+
+	/* determine if FLASH / EEPROM is present */
+	if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) {
+		has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST );
+		has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST );
+	} else {
+		has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT );
+		has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT );
+	}
+	ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE );
+
+	/* Configure the SPI and I2C bus */
+	efab->spi_bus.rw = falcon_spi_rw;
+	init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops );
+
+	/* Configure the EEPROM SPI device. Generally, an Atmel 25040
+	 * (or similar) is used, but this is only possible if there is also
+	 * a flash device present to store the boot-time chip configuration.
+	 */
+	if ( has_eeprom ) {
+		if ( has_flash && ad9bit )
+			init_at25040 ( &efab->spi_eeprom );
+		else
+			init_mc25xx640 ( &efab->spi_eeprom );
+		falcon_init_spi_device ( efab, &efab->spi_eeprom );
+	}
+
+	/* Configure the FLASH SPI device */
+	if ( has_flash ) {
+		init_at25f1024 ( &efab->spi_flash );
+		falcon_init_spi_device ( efab, &efab->spi_flash );
+	}
+
+	EFAB_LOG ( "flash is %s, EEPROM is %s%s\n",
+		   ( has_flash ? "present" : "absent" ),
+		   ( has_eeprom ? "present " : "absent" ),
+		   ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") );
+
+	/* The device MUST have flash or eeprom */
+	if ( ! efab->spi ) {
+		EFAB_ERR ( "Device appears to have no flash or eeprom\n" );
+		return -EIO;
+	}
+
+	/* If the device has EEPROM attached, then advertise NVO space */
+	if ( has_eeprom ) {
+		nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, 0x100, 0xf0,
+			   NULL, &efab->netdev->refcnt );
+	}
+
+	return 0;
+}
+
+static int
+falcon_probe_nvram ( struct efab_nic *efab )
+{
+	struct nvs_device *nvs = &efab->spi->nvs;
+	struct falcon_nv_extra nv;
+	int rc, board_revision;
+
+	/* Read the MAC address */
+	rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET,
+			efab->mac_addr, ETH_ALEN );
+	if ( rc )
+		return rc;
+
+	/* Poke through the NVRAM structure for the PHY type. */
+	rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA,
+			&nv, sizeof ( nv ) );
+	if ( rc )
+		return rc;
+
+	/* Handle each supported NVRAM version */
+	if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) &&
+	     ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) {
+		struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2;
+		
+		/* Get the PHY type */
+		efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr );
+		efab->phy_type = le16_to_cpu ( ver2->port0_phy_type );
+		board_revision = le16_to_cpu ( ver2->board_revision );
+	}
+	else {
+		EFAB_ERR ( "NVram is not recognised\n" );
+		return -EINVAL;
+	}
+
+	efab->board_type = BOARD_TYPE ( board_revision );
+	
+	EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n",
+		     efab->board_type, efab->phy_type, efab->phy_addr );
+
+	/* Patch in the board operations */
+	switch ( efab->board_type ) {
+	case EFAB_BOARD_SFE4001:
+		efab->board_op = &sfe4001_ops;
+		break;
+	case EFAB_BOARD_SFE4002:
+		efab->board_op = &sfe4002_ops;
+		break;
+	case EFAB_BOARD_SFE4003:
+		efab->board_op = &sfe4003_ops;
+		break;
+	default:
+		EFAB_ERR ( "Unrecognised board type\n" );
+		return -EINVAL;
+	}
+
+	/* Patch in MAC operations */
+	if ( efab->phy_10g )
+		efab->mac_op = &falcon_xmac_operations;
+	else
+		efab->mac_op = &falcon_gmac_operations;
+
+	/* Hook in the PHY ops */
+	switch ( efab->phy_type ) {
+	case PHY_TYPE_10XPRESS:
+		efab->phy_op = &falcon_tenxpress_phy_ops;
+		break;
+	case PHY_TYPE_CX4:
+		efab->phy_op = &falcon_xaui_phy_ops;
+		break;
+	case PHY_TYPE_XFP:
+		efab->phy_op = &falcon_xfp_phy_ops;
+		break;
+	case PHY_TYPE_CX4_RTMR:
+		efab->phy_op = &falcon_txc_phy_ops;
+		break;
+	case PHY_TYPE_PM8358:
+		efab->phy_op = &falcon_pm8358_phy_ops;
+		break;
+	case PHY_TYPE_1GIG_ALASKA:
+		efab->phy_op = &falcon_alaska_phy_ops;
+		break;
+	default:
+		EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+falcon_init_sram ( struct efab_nic *efab )
+{
+	efab_oword_t reg;
+	int count;
+
+	/* use card in internal SRAM mode */
+	falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 );
+	falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
+
+	/* Deactivate any external SRAM that might be present */
+	EFAB_POPULATE_OWORD_2 ( reg, 
+				FCN_GPIO1_OEN, 1,
+				FCN_GPIO1_OUT, 1 );
+	falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+
+	/* Initiate SRAM reset */
+	EFAB_POPULATE_OWORD_2 ( reg,
+				FCN_SRAM_OOB_BT_INIT_EN, 1,
+				FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 );
+	falcon_write ( efab, &reg, FCN_SRM_CFG_REG_KER );
+
+	/* Wait for SRAM reset to complete */
+	count = 0;
+	do {
+		/* SRAM reset is slow; expect around 16ms */
+		mdelay ( 20 );
+
+		/* Check for reset complete */
+		falcon_read ( efab, &reg, FCN_SRM_CFG_REG_KER );
+		if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) )
+			return 0;
+	} while (++count < 20);	/* wait upto 0.4 sec */
+
+	EFAB_ERR ( "timed out waiting for SRAM reset\n");
+	return -ETIMEDOUT;
+}
+
+static void
+falcon_setup_nic ( struct efab_nic *efab )
+{
+	efab_dword_t timer_cmd;
+	efab_oword_t reg;
+	int tx_fc, xoff_thresh, xon_thresh;
+
+	/* bug5129: Clear the parity enables on the TX data fifos as 
+	 * they produce false parity errors because of timing issues 
+	 */
+	falcon_read ( efab, &reg, FCN_SPARE_REG_KER );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 );
+	falcon_write ( efab, &reg, FCN_SPARE_REG_KER );
+	
+	/* Set up TX and RX descriptor caches in SRAM */
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 );
+	falcon_write ( efab, &reg, FCN_SRM_TX_DC_CFG_REG_KER );
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ );
+	falcon_write ( efab, &reg, FCN_TX_DC_CFG_REG_KER );
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 );
+	falcon_write ( efab, &reg, FCN_SRM_RX_DC_CFG_REG_KER );
+	EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ );
+	falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
+	
+	/* Set number of RSS CPUs
+	 * bug7244: Increase filter depth to reduce RX_RESET likelyhood
+	 */
+	EFAB_POPULATE_OWORD_5 ( reg,
+				FCN_NUM_KER, 0,
+				FCN_UDP_FULL_SRCH_LIMIT, 8,
+                                FCN_UDP_WILD_SRCH_LIMIT, 8,
+                                FCN_TCP_WILD_SRCH_LIMIT, 8,
+                                FCN_TCP_FULL_SRCH_LIMIT, 8);
+	falcon_write ( efab, &reg, FCN_RX_FILTER_CTL_REG_KER );
+	udelay ( 1000 );
+
+	/* Setup RX.  Wait for descriptor is broken and must
+	 * be disabled.  RXDP recovery shouldn't be needed, but is.
+	 * disable ISCSI parsing because we don't need it
+	 */
+	falcon_read ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 );
+	falcon_write ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
+	
+	/* Determine recommended flow control settings. *
+	 * Flow control is qualified on B0 and A1/1G, not on A1/10G */
+	if ( efab->pci_revision == FALCON_REV_B0 ) {
+		tx_fc = 1;
+		xoff_thresh = 54272;  /* ~80Kb - 3*max MTU */
+		xon_thresh = 27648; /* ~3*max MTU */
+	}
+	else if ( !efab->phy_10g ) {
+		tx_fc = 1;
+		xoff_thresh = 2048;
+		xon_thresh = 512;
+	}
+	else {
+		tx_fc = xoff_thresh = xon_thresh = 0;
+	}
+
+	/* Setup TX and RX */
+	falcon_read ( efab, &reg, FCN_TX_CFG2_REG_KER );
+	EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 );
+	falcon_write ( efab, &reg, FCN_TX_CFG2_REG_KER );
+
+	falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
+	EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE,
+				   (3*4096) / 32 );
+	if ( efab->pci_revision == FALCON_REV_B0)
+		EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 );
+	EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH,
+				   xon_thresh / 256);
+	EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH,
+				   xoff_thresh / 256);
+	EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc);
+	falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
+
+	/* Set timer register */
+	EFAB_POPULATE_DWORD_2 ( timer_cmd,
+				FCN_TIMER_MODE, FCN_TIMER_MODE_DIS,
+				FCN_TIMER_VAL, 0 );
+	falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER );
+}
+
+static void
+falcon_init_resources ( struct efab_nic *efab )
+{
+	struct efab_ev_queue *ev_queue = &efab->ev_queue;
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	struct efab_tx_queue *tx_queue = &efab->tx_queue;
+
+	efab_oword_t reg;
+	int jumbo;
+
+	/* Initialise the ptrs */
+	tx_queue->read_ptr = tx_queue->write_ptr = 0;
+	rx_queue->read_ptr = rx_queue->write_ptr = 0;
+	ev_queue->read_ptr = 0;
+
+	/* Push the event queue to the hardware */
+	EFAB_POPULATE_OWORD_3 ( reg,
+				FCN_EVQ_EN, 1,
+				FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE),
+				FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id );
+	falcon_write ( efab, &reg, 
+		       FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
+	
+	/* Push the tx queue to the hardware */
+	EFAB_POPULATE_OWORD_8 ( reg,
+				FCN_TX_DESCQ_EN, 1,
+				FCN_TX_ISCSI_DDIG_EN, 0,
+				FCN_TX_ISCSI_DDIG_EN, 0,
+				FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id,
+				FCN_TX_DESCQ_EVQ_ID, 0,
+				FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE),
+				FCN_TX_DESCQ_TYPE, 0 /* kernel queue */,
+				FCN_TX_NON_IP_DROP_DIS_B0, 1 );
+	falcon_write ( efab, &reg, 
+		       FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+	
+	/* Push the rx queue to the hardware */
+	jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1;
+	EFAB_POPULATE_OWORD_8 ( reg,
+				FCN_RX_ISCSI_DDIG_EN, 0,
+				FCN_RX_ISCSI_HDIG_EN, 0,
+				FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id,
+				FCN_RX_DESCQ_EVQ_ID, 0,
+				FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE),
+				FCN_RX_DESCQ_TYPE, 0 /* kernel queue */,
+				FCN_RX_DESCQ_JUMBO, jumbo,
+				FCN_RX_DESCQ_EN, 1 );
+	falcon_write ( efab, &reg,
+		       FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+
+	/* Program INT_ADR_REG_KER */
+	EFAB_POPULATE_OWORD_1 ( reg,
+				FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) );
+	falcon_write ( efab, &reg, FCN_INT_ADR_REG_KER );
+
+	/* Ack the event queue */
+	falcon_eventq_read_ack ( efab, ev_queue );
+}
+
+static void
+falcon_fini_resources ( struct efab_nic *efab )
+{
+	efab_oword_t cmd;
+	
+	/* Disable interrupts */
+	falcon_interrupts ( efab, 0, 0 );
+
+	/* Flush the dma queues */
+	EFAB_POPULATE_OWORD_2 ( cmd,
+				FCN_TX_FLUSH_DESCQ_CMD, 1,
+				FCN_TX_FLUSH_DESCQ, 0 );
+	falcon_write ( efab, &cmd, 
+		       FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+	EFAB_POPULATE_OWORD_2 ( cmd,
+				FCN_RX_FLUSH_DESCQ_CMD, 1,
+				FCN_RX_FLUSH_DESCQ, 0 );
+	falcon_write ( efab, &cmd,
+		       FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+
+	mdelay ( 100 );
+
+	/* Remove descriptor rings from card */
+	EFAB_ZERO_OWORD ( cmd );
+	falcon_write ( efab, &cmd, 
+		       FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+	falcon_write ( efab, &cmd, 
+		       FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+	falcon_write ( efab, &cmd, 
+		       FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
+}
+
+/*******************************************************************************
+ *
+ *
+ * Hardware rx path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob )
+{
+	EFAB_POPULATE_QWORD_2 ( *rxd,
+				FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE,
+				FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
+}
+
+static void
+falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue )
+{
+	efab_dword_t reg;
+	int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE;
+
+	EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr );
+	falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
+}
+
+
+/*******************************************************************************
+ *
+ *
+ * Hardware tx path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob )
+{
+	EFAB_POPULATE_QWORD_2 ( *txd,
+				FCN_TX_KER_BYTE_CNT, iob_len ( iob ),
+				FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
+}
+
+static void
+falcon_notify_tx_desc ( struct efab_nic *efab,
+			struct efab_tx_queue *tx_queue )
+{
+	efab_dword_t reg;
+	int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE;
+
+	EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr );
+	falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+}
+
+
+/*******************************************************************************
+ *
+ *
+ * Software receive interface
+ *
+ *
+ *******************************************************************************/ 
+
+static int
+efab_fill_rx_queue ( struct efab_nic *efab,
+		     struct efab_rx_queue *rx_queue )
+{
+	int fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+	int space = EFAB_NUM_RX_DESC - fill_level - 1;
+	int pushed = 0;
+
+	while ( space ) {
+		int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC;
+		int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE;
+		struct io_buffer *iob;
+		falcon_rx_desc_t *rxd;
+
+		assert ( rx_queue->buf[buf_id] == NULL );
+		iob = alloc_iob ( EFAB_RX_BUF_SIZE );
+		if ( !iob )
+			break;
+
+		EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n",
+			     buf_id, iob, iob->data );
+
+		rx_queue->buf[buf_id] = iob;
+		rxd = rx_queue->ring + desc_id;
+		falcon_build_rx_desc ( rxd, iob );
+		++rx_queue->write_ptr;
+		++pushed;
+		--space;
+	}
+
+	if ( pushed ) {
+		/* Push the ptr to hardware */
+		falcon_notify_rx_desc ( efab, rx_queue );
+
+		fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+		EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n",
+			     pushed, fill_level );
+	}
+
+	if ( fill_level == 0 )
+		return -ENOMEM;
+	return 0;
+}
+	
+static void
+efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop )
+{
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	struct io_buffer *iob;
+	unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE;
+	unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC;
+
+	assert ( id == read_ptr );
+	
+	/* Pop this rx buffer out of the software ring */
+	iob = rx_queue->buf[buf_ptr];
+	rx_queue->buf[buf_ptr] = NULL;
+
+	EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n",
+		     id, iob, iob->data, len, drop ? "bad" : "ok" );
+
+	/* Pass the packet up if required */
+	if ( drop )
+		free_iob ( iob );
+	else {
+		iob_put ( iob, len );
+		netdev_rx ( efab->netdev, iob );
+	}
+
+	++rx_queue->read_ptr;
+}
+
+/*******************************************************************************
+ *
+ *
+ * Software transmit interface
+ *
+ *
+ *******************************************************************************/ 
+
+static int
+efab_transmit ( struct net_device *netdev, struct io_buffer *iob )
+{
+	struct efab_nic *efab = netdev_priv ( netdev );
+	struct efab_tx_queue *tx_queue = &efab->tx_queue;
+	int fill_level, space;
+	falcon_tx_desc_t *txd;
+	int buf_id;
+
+	fill_level = tx_queue->write_ptr - tx_queue->read_ptr;
+	space = EFAB_TXD_SIZE - fill_level - 1;
+	if ( space < 1 )
+		return -ENOBUFS;
+
+	/* Save the iobuffer for later completion */
+	buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE;
+	assert ( tx_queue->buf[buf_id] == NULL );
+	tx_queue->buf[buf_id] = iob;
+
+	EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %zd\n",
+		     buf_id, iob, iob->data, iob_len ( iob ) );
+
+	/* Form the descriptor, and push it to hardware */
+	txd = tx_queue->ring + buf_id;
+	falcon_build_tx_desc ( txd, iob );
+	++tx_queue->write_ptr;
+	falcon_notify_tx_desc ( efab, tx_queue );
+
+	return 0;
+}
+
+static int
+efab_transmit_done ( struct efab_nic *efab, int id )
+{
+	struct efab_tx_queue *tx_queue = &efab->tx_queue;
+	unsigned int read_ptr, stop;
+
+	/* Complete all buffers from read_ptr up to and including id */
+	read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+	stop = ( id + 1 ) % EFAB_TXD_SIZE;
+
+	while ( read_ptr != stop ) {
+		struct io_buffer *iob = tx_queue->buf[read_ptr];
+		assert ( iob );
+
+		/* Complete the tx buffer */
+		if ( iob )
+			netdev_tx_complete ( efab->netdev, iob );
+		tx_queue->buf[read_ptr] = NULL;
+		
+		++tx_queue->read_ptr;
+		read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ *
+ *
+ * Hardware event path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_clear_interrupts ( struct efab_nic *efab )
+{
+	efab_dword_t reg;
+
+	if ( efab->pci_revision == FALCON_REV_B0 ) {
+		/* read the ISR */
+		falcon_readl( efab, &reg, INT_ISR0_B0 );
+	}
+	else {
+		/* write to the INT_ACK register */
+		falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 );
+		mb();
+		falcon_readl ( efab, &reg,
+			       WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 );
+	}
+}
+
+static void
+falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt )
+{
+	int ev_code, desc_ptr, len, drop;
+
+	/* Decode event */
+	ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
+	switch ( ev_code ) {
+	case FCN_TX_IP_EV_DECODE:
+		desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR );
+		efab_transmit_done ( efab, desc_ptr );
+		break;
+	
+	case FCN_RX_IP_EV_DECODE:
+		desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
+		len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
+		drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
+
+		efab_receive ( efab, desc_ptr, len, drop );
+		break;
+
+	default:
+		EFAB_TRACE ( "Unknown event type %d\n", ev_code );
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ *
+ * Software (polling) interrupt handler
+ *
+ *
+ *******************************************************************************/
+
+static void
+efab_poll ( struct net_device *netdev )
+{
+	struct efab_nic *efab = netdev_priv ( netdev );
+	struct efab_ev_queue *ev_queue = &efab->ev_queue;
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	falcon_event_t *evt;
+
+	/* Read the event queue by directly looking for events
+	 * (we don't even bother to read the eventq write ptr) */
+	evt = ev_queue->ring + ev_queue->read_ptr;
+	while ( falcon_event_present ( evt ) ) {
+		
+		EFAB_TRACE ( "Event at index 0x%x address %p is "
+			     EFAB_QWORD_FMT "\n", ev_queue->read_ptr,
+			     evt, EFAB_QWORD_VAL ( *evt ) );
+		
+		falcon_handle_event ( efab, evt );
+		
+		/* Clear the event */
+		EFAB_SET_QWORD ( *evt );
+	
+		/* Move to the next event. We don't ack the event
+		 * queue until the end */
+		ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) %
+				       EFAB_EVQ_SIZE );
+		evt = ev_queue->ring + ev_queue->read_ptr;
+	}
+
+	/* Push more buffers if needed */
+	(void) efab_fill_rx_queue ( efab, rx_queue );
+
+	/* Clear any pending interrupts */
+	falcon_clear_interrupts ( efab );
+
+	/* Ack the event queue */
+	falcon_eventq_read_ack ( efab, ev_queue );
+}
+
+static void
+efab_irq ( struct net_device *netdev, int enable )
+{
+	struct efab_nic *efab = netdev_priv ( netdev );
+	struct efab_ev_queue *ev_queue = &efab->ev_queue;
+
+	switch ( enable ) {
+	case 0:
+		falcon_interrupts ( efab, 0, 0 );
+		break;
+	case 1:
+		falcon_interrupts ( efab, 1, 0 );
+		falcon_eventq_read_ack ( efab, ev_queue );
+		break;
+	case 2:
+		falcon_interrupts ( efab, 1, 1 );
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ *
+ * Software open/close
+ *
+ *
+ *******************************************************************************/
+
+static void
+efab_free_resources ( struct efab_nic *efab )
+{
+	struct efab_ev_queue *ev_queue = &efab->ev_queue;
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	struct efab_tx_queue *tx_queue = &efab->tx_queue;
+	int i;
+
+	for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) {
+		if ( rx_queue->buf[i] )
+			free_iob ( rx_queue->buf[i] );
+	}
+
+	for ( i = 0; i < EFAB_TXD_SIZE; i++ ) {
+		if ( tx_queue->buf[i] )
+			netdev_tx_complete ( efab->netdev,  tx_queue->buf[i] );
+	}
+
+	if ( rx_queue->ring )
+		falcon_free_special_buffer ( rx_queue->ring );
+
+	if ( tx_queue->ring )
+		falcon_free_special_buffer ( tx_queue->ring );
+
+	if ( ev_queue->ring )
+		falcon_free_special_buffer ( ev_queue->ring );
+
+	memset ( rx_queue, 0, sizeof ( *rx_queue ) );
+	memset ( tx_queue, 0, sizeof ( *tx_queue ) );
+	memset ( ev_queue, 0, sizeof ( *ev_queue ) );
+
+	/* Ensure subsequent buffer allocations start at id 0 */
+	efab->buffer_head = 0;
+}
+
+static int
+efab_alloc_resources ( struct efab_nic *efab )
+{
+	struct efab_ev_queue *ev_queue = &efab->ev_queue;
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	struct efab_tx_queue *tx_queue = &efab->tx_queue;
+	size_t bytes;
+
+	/* Allocate the hardware event queue */
+	bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE;
+	ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+						       &ev_queue->entry );
+	if ( !ev_queue->ring )
+		goto fail1;
+
+	/* Initialise the hardware event queue */
+	memset ( ev_queue->ring, 0xff, bytes );
+
+	/* Allocate the hardware tx queue */
+	bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE;
+	tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+						       &tx_queue->entry );
+	if ( ! tx_queue->ring )
+		goto fail2;
+
+	/* Allocate the hardware rx queue */
+	bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE;
+	rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+						       &rx_queue->entry );
+	if ( ! rx_queue->ring )
+		goto fail3;
+
+	return 0;
+
+fail3:
+	falcon_free_special_buffer ( tx_queue->ring );
+	tx_queue->ring = NULL;
+fail2:
+	falcon_free_special_buffer ( ev_queue->ring );
+	ev_queue->ring = NULL;
+fail1:
+	return -ENOMEM;
+}
+
+static int
+efab_init_mac ( struct efab_nic *efab )
+{
+	int count, rc;
+
+	/* This can take several seconds */
+	EFAB_LOG ( "Waiting for link..\n" );
+	for ( count=0; count<5; count++ ) {
+		rc = efab->mac_op->init ( efab );
+		if ( rc ) {
+			EFAB_ERR ( "Failed reinitialising MAC, error %s\n",
+				strerror ( rc ));
+			return rc;
+		}
+
+		/* Sleep for 2s to wait for the link to settle, either
+		 * because we want to use it, or because we're about
+		 * to reset the mac anyway
+		 */
+		sleep ( 2 );
+
+		if ( ! efab->link_up ) {
+			EFAB_ERR ( "!\n" );
+			continue;
+		}
+
+		EFAB_LOG ( "\n%dMbps %s-duplex\n",
+			   ( efab->link_options & LPA_EF_10000 ? 10000 :
+			     ( efab->link_options & LPA_EF_1000 ? 1000 :
+			       ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
+			   ( efab->link_options & LPA_EF_DUPLEX ?
+			     "full" : "half" ) );
+
+		/* TODO: Move link state handling to the poll() routine */
+		netdev_link_up ( efab->netdev );
+		return 0;
+	}
+
+	EFAB_ERR ( "timed initialising MAC\n" );
+	return -ETIMEDOUT;
+}
+
+static void
+efab_close ( struct net_device *netdev )
+{
+	struct efab_nic *efab = netdev_priv ( netdev );
+
+	falcon_fini_resources ( efab );
+	efab_free_resources ( efab );
+	efab->board_op->fini ( efab );
+	falcon_reset ( efab );
+}
+
+static int
+efab_open ( struct net_device *netdev )
+{
+	struct efab_nic *efab = netdev_priv ( netdev );
+	struct efab_rx_queue *rx_queue = &efab->rx_queue;
+	int rc;
+
+	rc = falcon_reset ( efab );
+	if ( rc )
+		goto fail1;
+
+	rc = efab->board_op->init ( efab );
+	if ( rc )
+		goto fail2;
+	
+	rc = falcon_init_sram ( efab );
+	if ( rc )
+		goto fail3;
+
+	/* Configure descriptor caches before pushing hardware queues */
+	falcon_setup_nic ( efab );
+
+	rc = efab_alloc_resources ( efab );
+	if ( rc )
+		goto fail4;
+	
+	falcon_init_resources ( efab );
+
+	/* Push rx buffers */
+	rc = efab_fill_rx_queue ( efab, rx_queue );
+	if ( rc )
+		goto fail5;
+
+	/* Try and bring the interface up */
+	rc = efab_init_mac ( efab );
+	if ( rc )
+		goto fail6;
+
+	return 0;
+
+fail6:
+fail5:
+	efab_free_resources ( efab );
+fail4:
+fail3:
+	efab->board_op->fini ( efab );
+fail2:
+	falcon_reset ( efab );
+fail1:
+	return rc;
+}
+
+static struct net_device_operations efab_operations = {
+        .open           = efab_open,
+        .close          = efab_close,
+        .transmit       = efab_transmit,
+        .poll           = efab_poll,
+        .irq            = efab_irq,
+};
+
+static void
+efab_remove ( struct pci_device *pci )
+{
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct efab_nic *efab = netdev_priv ( netdev );
+
+	if ( efab->membase ) {
+		falcon_reset ( efab );
+
+		iounmap ( efab->membase );
+		efab->membase = NULL;
+	}
+
+	if ( efab->nvo.nvs ) {
+		unregister_nvo ( &efab->nvo );
+		efab->nvo.nvs = NULL;
+	}
+
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static int
+efab_probe ( struct pci_device *pci )
+{
+	struct net_device *netdev;
+	struct efab_nic *efab;
+	unsigned long mmio_start, mmio_len;
+	int rc;
+
+	/* Create the network adapter */
+	netdev = alloc_etherdev ( sizeof ( struct efab_nic ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto fail1;
+	}
+
+	/* Initialise the network adapter, and initialise private storage */
+	netdev_init ( netdev, &efab_operations );
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+
+	efab = netdev_priv ( netdev );
+	memset ( efab, 0, sizeof ( *efab ) );
+	efab->netdev = netdev;
+
+	/* Get iobase/membase */
+	mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 );
+	mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 );
+	efab->membase = ioremap ( mmio_start, mmio_len );
+	EFAB_TRACE ( "BAR of %lx bytes at phys %lx mapped at %p\n",
+		     mmio_len, mmio_start, efab->membase );
+
+	/* Enable the PCI device */
+	adjust_pci_device ( pci );
+	efab->iobase = pci->ioaddr & ~3;
+
+	/* Determine the NIC variant */
+	falcon_probe_nic_variant ( efab, pci );
+
+	/* Read the SPI interface and determine the MAC address,
+	 * and the board and phy variant. Hook in the op tables */
+	rc = falcon_probe_spi ( efab );
+	if ( rc )
+		goto fail2;
+	rc = falcon_probe_nvram ( efab );
+	if ( rc )
+		goto fail3;
+
+	memcpy ( netdev->hw_addr, efab->mac_addr, ETH_ALEN );
+
+	rc = register_netdev ( netdev );
+	if ( rc )
+		goto fail4;
+	netdev_link_up ( netdev );
+
+	/* Advertise non-volatile storage */
+	if ( efab->nvo.nvs ) {
+		rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) );
+		if ( rc )
+			goto fail5;
+	}
+
+	EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", pci->id->name,
+		   efab->is_asic ? "ASIC" : "FPGA",
+		   efab->phy_10g ? "10G" : "1G",
+		   efab->pci_revision );
+
+	return 0;
+
+fail5:
+	unregister_netdev ( netdev );
+fail4:
+fail3:
+fail2:
+	iounmap ( efab->membase );
+	efab->membase = NULL;
+	netdev_put ( netdev );
+fail1:
+	return rc;
+}
+
+
+static struct pci_device_id efab_nics[] = {
+	PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon", 0),
+	PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0", 0),
+};
+
+struct pci_driver etherfabric_driver __pci_driver = {
+	.ids = efab_nics,
+	.id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ),
+	.probe = efab_probe,
+	.remove = efab_remove,
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.h
new file mode 100644
index 0000000..9657eb7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric.h
@@ -0,0 +1,553 @@
+/**************************************************************************
+ *
+ * GPL net driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown at fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.  This file is not a complete program and may only be used
+ * when the entire operating system is licensed under the GPL.
+ *
+ **************************************************************************
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#ifndef EFAB_BITFIELD_H
+#define EFAB_BITFIELD_H
+
+/** @file
+ *
+ * Etherfabric bitfield access
+ *
+ * Etherfabric NICs make extensive use of bitfields up to 128 bits
+ * wide.  Since there is no native 128-bit datatype on most systems,
+ * and since 64-bit datatypes are inefficient on 32-bit systems and
+ * vice versa, we wrap accesses in a way that uses the most efficient
+ * datatype.
+ *
+ * The NICs are PCI devices and therefore little-endian.  Since most
+ * of the quantities that we deal with are DMAed to/from host memory,
+ * we define our datatypes (efab_oword_t, efab_qword_t and
+ * efab_dword_t) to be little-endian.
+ *
+ * In the less common case of using PIO for individual register
+ * writes, we construct the little-endian datatype in host memory and
+ * then use non-swapping equivalents of writel/writeq, rather than
+ * constructing a native-endian datatype and relying on the implicit
+ * byte-swapping done by writel/writeq.  (We use a similar strategy
+ * for register reads.)
+ */
+
+/** Dummy field low bit number */
+#define EFAB_DUMMY_FIELD_LBN 0
+/** Dummy field width */
+#define EFAB_DUMMY_FIELD_WIDTH 0
+/** Dword 0 low bit number */
+#define EFAB_DWORD_0_LBN 0
+/** Dword 0 width */
+#define EFAB_DWORD_0_WIDTH 32
+/** Dword 1 low bit number */
+#define EFAB_DWORD_1_LBN 32
+/** Dword 1 width */
+#define EFAB_DWORD_1_WIDTH 32
+/** Dword 2 low bit number */
+#define EFAB_DWORD_2_LBN 64
+/** Dword 2 width */
+#define EFAB_DWORD_2_WIDTH 32
+/** Dword 3 low bit number */
+#define EFAB_DWORD_3_LBN 96
+/** Dword 3 width */
+#define EFAB_DWORD_3_WIDTH 32
+
+/** Specified attribute (e.g. LBN) of the specified field */
+#define EFAB_VAL(field,attribute) field ## _ ## attribute
+/** Low bit number of the specified field */
+#define EFAB_LOW_BIT( field ) EFAB_VAL ( field, LBN )
+/** Bit width of the specified field */
+#define EFAB_WIDTH( field ) EFAB_VAL ( field, WIDTH )
+/** High bit number of the specified field */
+#define EFAB_HIGH_BIT(field) ( EFAB_LOW_BIT(field) + EFAB_WIDTH(field) - 1 )
+/** Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 64 bits.
+ */
+#define EFAB_MASK64( field )						\
+	( EFAB_WIDTH(field) == 64 ? ~( ( uint64_t ) 0 ) :		\
+	  ( ( ( ( ( uint64_t ) 1 ) << EFAB_WIDTH(field) ) ) - 1 ) )
+
+/** Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 32 bits.  Use
+ * EFAB_MASK64 for higher width fields.
+ */
+#define EFAB_MASK32( field )						\
+	( EFAB_WIDTH(field) == 32 ? ~( ( uint32_t ) 0 ) :		\
+	  ( ( ( ( ( uint32_t ) 1 ) << EFAB_WIDTH(field) ) ) - 1 ) )
+
+/** A doubleword (i.e. 4 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_dword {
+	uint32_t u32[1];
+	uint32_t opaque; /* For bitwise operations between two efab_dwords */
+} efab_dword_t;
+
+/** A quadword (i.e. 8 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_qword {
+	uint64_t u64[1];
+	uint32_t u32[2];
+	efab_dword_t dword[2];
+} efab_qword_t;
+
+/**
+ * An octword (eight-word, i.e. 16 byte) datatype
+ *
+ * This datatype is defined to be little-endian.
+ */
+typedef union efab_oword {
+	uint64_t u64[2];
+	efab_qword_t qword[2];
+	uint32_t u32[4];
+	efab_dword_t dword[4];
+} efab_oword_t;
+
+/** Format string for printing an efab_dword_t */
+#define EFAB_DWORD_FMT "%08x"
+
+/** Format string for printing an efab_qword_t */
+#define EFAB_QWORD_FMT "%08x:%08x"
+
+/** Format string for printing an efab_oword_t */
+#define EFAB_OWORD_FMT "%08x:%08x:%08x:%08x"
+
+/** printk parameters for printing an efab_dword_t */
+#define EFAB_DWORD_VAL(dword)					\
+	( ( unsigned int ) le32_to_cpu ( (dword).u32[0] ) )
+
+/** printk parameters for printing an efab_qword_t */
+#define EFAB_QWORD_VAL(qword)					\
+	( ( unsigned int ) le32_to_cpu ( (qword).u32[1] ) ),	\
+	( ( unsigned int ) le32_to_cpu ( (qword).u32[0] ) )
+
+/** printk parameters for printing an efab_oword_t */
+#define EFAB_OWORD_VAL(oword)					\
+	( ( unsigned int ) le32_to_cpu ( (oword).u32[3] ) ),	\
+	( ( unsigned int ) le32_to_cpu ( (oword).u32[2] ) ),	\
+	( ( unsigned int ) le32_to_cpu ( (oword).u32[1] ) ),	\
+	( ( unsigned int ) le32_to_cpu ( (oword).u32[0] ) )
+
+/**
+ * Extract bit field portion [low,high) from the native-endian element
+ * which contains bits [min,max).
+ *
+ * For example, suppose "element" represents the high 32 bits of a
+ * 64-bit value, and we wish to extract the bits belonging to the bit
+ * field occupying bits 28-45 of this 64-bit value.
+ *
+ * Then EFAB_EXTRACT ( element, 32, 63, 28, 45 ) would give
+ *
+ *   ( element ) << 4
+ *
+ * The result will contain the relevant bits filled in in the range
+ * [0,high-low), with garbage in bits [high-low+1,...).
+ */
+#define EFAB_EXTRACT_NATIVE( native_element, min ,max ,low ,high )	\
+	( ( ( low > max ) || ( high < min ) ) ? 0 :			\
+	  ( ( low > min ) ?						\
+	    ( (native_element) >> ( low - min ) ) :			\
+	    ( (native_element) << ( min - low ) ) ) )
+
+/**
+ * Extract bit field portion [low,high) from the 64-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFAB_EXTRACT64( element, min, max, low, high )			\
+	EFAB_EXTRACT_NATIVE ( le64_to_cpu(element), min, max, low, high )
+
+/**
+ * Extract bit field portion [low,high) from the 32-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFAB_EXTRACT32( element, min, max, low, high )			\
+	EFAB_EXTRACT_NATIVE ( le32_to_cpu(element), min, max, low, high )
+
+#define EFAB_EXTRACT_OWORD64( oword, low, high )			\
+	( EFAB_EXTRACT64 ( (oword).u64[0],   0,  63, low, high ) |	\
+	  EFAB_EXTRACT64 ( (oword).u64[1],  64, 127, low, high ) )
+
+#define EFAB_EXTRACT_QWORD64( qword, low, high )			\
+	( EFAB_EXTRACT64 ( (qword).u64[0],   0,  63, low, high ) )
+
+#define EFAB_EXTRACT_OWORD32( oword, low, high )			\
+	( EFAB_EXTRACT32 ( (oword).u32[0],   0,  31, low, high ) |	\
+	  EFAB_EXTRACT32 ( (oword).u32[1],  32,  63, low, high ) |	\
+	  EFAB_EXTRACT32 ( (oword).u32[2],  64,  95, low, high ) |	\
+	  EFAB_EXTRACT32 ( (oword).u32[3],  96, 127, low, high ) )
+
+#define EFAB_EXTRACT_QWORD32( qword, low, high )			\
+	( EFAB_EXTRACT32 ( (qword).u32[0],   0,  31, low, high ) |	\
+	  EFAB_EXTRACT32 ( (qword).u32[1],  32,  63, low, high ) )
+
+#define EFAB_EXTRACT_DWORD( dword, low, high )				\
+	( EFAB_EXTRACT32 ( (dword).u32[0],   0,  31, low, high ) )
+
+#define EFAB_OWORD_FIELD64( oword, field )				\
+	( EFAB_EXTRACT_OWORD64 ( oword, EFAB_LOW_BIT ( field ),		\
+				 EFAB_HIGH_BIT ( field ) ) &		\
+	  EFAB_MASK64 ( field ) )
+
+#define EFAB_QWORD_FIELD64( qword, field )				\
+	( EFAB_EXTRACT_QWORD64 ( qword, EFAB_LOW_BIT ( field ),		\
+				 EFAB_HIGH_BIT ( field ) ) &		\
+	  EFAB_MASK64 ( field ) )
+
+#define EFAB_OWORD_FIELD32( oword, field )				\
+	( EFAB_EXTRACT_OWORD32 ( oword, EFAB_LOW_BIT ( field ),		\
+				 EFAB_HIGH_BIT ( field ) ) &		\
+	  EFAB_MASK32 ( field ) )
+
+#define EFAB_QWORD_FIELD32( qword, field )				\
+	( EFAB_EXTRACT_QWORD32 ( qword, EFAB_LOW_BIT ( field ),		\
+				 EFAB_HIGH_BIT ( field ) ) &		\
+	  EFAB_MASK32 ( field ) )
+
+#define EFAB_DWORD_FIELD( dword, field )				\
+	( EFAB_EXTRACT_DWORD ( dword, EFAB_LOW_BIT ( field ),		\
+			       EFAB_HIGH_BIT ( field ) ) &		\
+	  EFAB_MASK32 ( field ) )
+
+#define EFAB_OWORD_IS_ZERO64( oword )					\
+	( ! ( (oword).u64[0] || (oword).u64[1] ) )
+
+#define EFAB_QWORD_IS_ZERO64( qword )					\
+	( ! ( (qword).u64[0] ) )
+
+#define EFAB_OWORD_IS_ZERO32( oword )					\
+	( ! ( (oword).u32[0] || (oword).u32[1] ||			\
+	      (oword).u32[2] || (oword).u32[3] ) )
+
+#define EFAB_QWORD_IS_ZERO32( qword )					\
+	( ! ( (qword).u32[0] || (qword).u32[1] ) )
+
+#define EFAB_DWORD_IS_ZERO( dword )					\
+	( ! ( (dword).u32[0] ) )
+
+#define EFAB_OWORD_IS_ALL_ONES64( oword )				\
+	( ( (oword).u64[0] & (oword).u64[1] ) == ~( ( uint64_t ) 0 ) )
+
+#define EFAB_QWORD_IS_ALL_ONES64( qword )				\
+	( (qword).u64[0] == ~( ( uint64_t ) 0 ) )
+
+#define EFAB_OWORD_IS_ALL_ONES32( oword )				\
+	( ( (oword).u32[0] & (oword).u32[1] &				\
+	    (oword).u32[2] & (oword).u32[3] ) == ~( ( uint32_t ) 0 ) )
+
+#define EFAB_QWORD_IS_ALL_ONES32( qword )				\
+	( ( (qword).u32[0] & (qword).u32[1] ) == ~( ( uint32_t ) 0 ) )
+
+#define EFAB_DWORD_IS_ALL_ONES( dword )					\
+	( (dword).u32[0] == ~( ( uint32_t ) 0 ) )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_OWORD_FIELD	EFAB_OWORD_FIELD64
+#define EFAB_QWORD_FIELD	EFAB_QWORD_FIELD64
+#define EFAB_OWORD_IS_ZERO	EFAB_OWORD_IS_ZERO64
+#define EFAB_QWORD_IS_ZERO	EFAB_QWORD_IS_ZERO64
+#define EFAB_OWORD_IS_ALL_ONES	EFAB_OWORD_IS_ALL_ONES64
+#define EFAB_QWORD_IS_ALL_ONES	EFAB_QWORD_IS_ALL_ONES64
+#else
+#define EFAB_OWORD_FIELD	EFAB_OWORD_FIELD32
+#define EFAB_QWORD_FIELD	EFAB_QWORD_FIELD32
+#define EFAB_OWORD_IS_ZERO	EFAB_OWORD_IS_ZERO32
+#define EFAB_QWORD_IS_ZERO	EFAB_QWORD_IS_ZERO32
+#define EFAB_OWORD_IS_ALL_ONES	EFAB_OWORD_IS_ALL_ONES32
+#define EFAB_QWORD_IS_ALL_ONES	EFAB_QWORD_IS_ALL_ONES32
+#endif
+
+/**
+ * Construct bit field portion
+ *
+ * Creates the portion of the bit field [low,high) that lies within
+ * the range [min,max).
+ */
+#define EFAB_INSERT_NATIVE64( min, max, low, high, value )	\
+	( ( ( low > max ) || ( high < min ) ) ? 0 :		\
+	  ( ( low > min ) ?					\
+	    ( ( ( uint64_t ) (value) ) << ( low - min ) ) :	\
+	    ( ( ( uint64_t ) (value) ) >> ( min - low ) ) ) )
+
+#define EFAB_INSERT_NATIVE32( min, max, low, high, value )	\
+	( ( ( low > max ) || ( high < min ) ) ? 0 :		\
+	  ( ( low > min ) ?					\
+	    ( ( ( uint32_t ) (value) ) << ( low - min ) ) :	\
+	    ( ( ( uint32_t ) (value) ) >> ( min - low ) ) ) )
+
+#define EFAB_INSERT_NATIVE( min, max, low, high, value )	\
+	( ( ( ( max - min ) >= 32 ) ||				\
+	    ( ( high - low ) >= 32 ) )	 			\
+	  ? EFAB_INSERT_NATIVE64 ( min, max, low, high, value )	\
+	  : EFAB_INSERT_NATIVE32 ( min, max, low, high, value ) )
+
+/**
+ * Construct bit field portion
+ *
+ * Creates the portion of the named bit field that lies within the
+ * range [min,max).
+ */
+#define EFAB_INSERT_FIELD_NATIVE( min, max, field, value )	\
+	EFAB_INSERT_NATIVE ( min, max, EFAB_LOW_BIT ( field ),	\
+			     EFAB_HIGH_BIT ( field ), value )
+
+/**
+ * Construct bit field
+ *
+ * Creates the portion of the named bit fields that lie within the
+ * range [min,max).
+ */
+#define EFAB_INSERT_FIELDS_NATIVE( min, max,				\
+				   field1, value1,			\
+				   field2, value2,			\
+				   field3, value3,			\
+				   field4, value4,			\
+				   field5, value5,			\
+				   field6, value6,			\
+				   field7, value7,			\
+				   field8, value8,			\
+				   field9, value9,			\
+				   field10, value10 )			\
+	( EFAB_INSERT_FIELD_NATIVE ( min, max, field1, value1 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field2, value2 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field3, value3 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field4, value4 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field5, value5 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field6, value6 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field7, value7 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field8, value8 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field9, value9 ) |	\
+	  EFAB_INSERT_FIELD_NATIVE ( min, max, field10, value10 ) )
+
+#define EFAB_INSERT_FIELDS64( ... )					\
+	cpu_to_le64 ( EFAB_INSERT_FIELDS_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INSERT_FIELDS32( ... )					\
+	cpu_to_le32 ( EFAB_INSERT_FIELDS_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_POPULATE_OWORD64( oword, ... ) do {			\
+	(oword).u64[0] = EFAB_INSERT_FIELDS64 (   0,  63, __VA_ARGS__ );\
+	(oword).u64[1] = EFAB_INSERT_FIELDS64 (  64, 127, __VA_ARGS__ );\
+	} while ( 0 )
+
+#define EFAB_POPULATE_QWORD64( qword, ... ) do {			\
+	(qword).u64[0] = EFAB_INSERT_FIELDS64 (   0,  63, __VA_ARGS__ );\
+	} while ( 0 )
+
+#define EFAB_POPULATE_OWORD32( oword, ... ) do {			\
+	(oword).u32[0] = EFAB_INSERT_FIELDS32 (   0,  31, __VA_ARGS__ );\
+	(oword).u32[1] = EFAB_INSERT_FIELDS32 (  32,  63, __VA_ARGS__ );\
+	(oword).u32[2] = EFAB_INSERT_FIELDS32 (  64,  95, __VA_ARGS__ );\
+	(oword).u32[3] = EFAB_INSERT_FIELDS32 (  96, 127, __VA_ARGS__ );\
+	} while ( 0 )
+
+#define EFAB_POPULATE_QWORD32( qword, ... ) do {			\
+	(qword).u32[0] = EFAB_INSERT_FIELDS32 (   0,  31, __VA_ARGS__ );\
+	(qword).u32[1] = EFAB_INSERT_FIELDS32 (  32,  63, __VA_ARGS__ );\
+	} while ( 0 )
+
+#define EFAB_POPULATE_DWORD( dword, ... ) do {				\
+	(dword).u32[0] = EFAB_INSERT_FIELDS32 (   0,  31, __VA_ARGS__ );\
+	} while ( 0 )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_POPULATE_OWORD EFAB_POPULATE_OWORD64
+#define EFAB_POPULATE_QWORD EFAB_POPULATE_QWORD64
+#else
+#define EFAB_POPULATE_OWORD EFAB_POPULATE_OWORD32
+#define EFAB_POPULATE_QWORD EFAB_POPULATE_QWORD32
+#endif
+
+/* Populate an octword field with various numbers of arguments */
+#define EFAB_POPULATE_OWORD_10 EFAB_POPULATE_OWORD
+#define EFAB_POPULATE_OWORD_9( oword, ... ) \
+	EFAB_POPULATE_OWORD_10 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_8( oword, ... ) \
+	EFAB_POPULATE_OWORD_9 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_7( oword, ... ) \
+	EFAB_POPULATE_OWORD_8 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_6( oword, ... ) \
+	EFAB_POPULATE_OWORD_7 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_5( oword, ... ) \
+	EFAB_POPULATE_OWORD_6 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_4( oword, ... ) \
+	EFAB_POPULATE_OWORD_5 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_3( oword, ... ) \
+	EFAB_POPULATE_OWORD_4 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_2( oword, ... ) \
+	EFAB_POPULATE_OWORD_3 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_OWORD_1( oword, ... ) \
+	EFAB_POPULATE_OWORD_2 ( oword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_OWORD( oword ) \
+	EFAB_POPULATE_OWORD_1 ( oword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_OWORD( oword ) \
+	EFAB_POPULATE_OWORD_4 ( oword, \
+				EFAB_DWORD_0, 0xffffffff, \
+				EFAB_DWORD_1, 0xffffffff, \
+				EFAB_DWORD_2, 0xffffffff, \
+				EFAB_DWORD_3, 0xffffffff )
+
+/* Populate a quadword field with various numbers of arguments */
+#define EFAB_POPULATE_QWORD_10 EFAB_POPULATE_QWORD
+#define EFAB_POPULATE_QWORD_9( qword, ... ) \
+	EFAB_POPULATE_QWORD_10 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_8( qword, ... ) \
+	EFAB_POPULATE_QWORD_9 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_7( qword, ... ) \
+	EFAB_POPULATE_QWORD_8 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_6( qword, ... ) \
+	EFAB_POPULATE_QWORD_7 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_5( qword, ... ) \
+	EFAB_POPULATE_QWORD_6 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_4( qword, ... ) \
+	EFAB_POPULATE_QWORD_5 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_3( qword, ... ) \
+	EFAB_POPULATE_QWORD_4 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_2( qword, ... ) \
+	EFAB_POPULATE_QWORD_3 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_QWORD_1( qword, ... ) \
+	EFAB_POPULATE_QWORD_2 ( qword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_QWORD( qword ) \
+	EFAB_POPULATE_QWORD_1 ( qword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_QWORD( qword ) \
+	EFAB_POPULATE_QWORD_2 ( qword, \
+				EFAB_DWORD_0, 0xffffffff, \
+				EFAB_DWORD_1, 0xffffffff )
+
+/* Populate a dword field with various numbers of arguments */
+#define EFAB_POPULATE_DWORD_10 EFAB_POPULATE_DWORD
+#define EFAB_POPULATE_DWORD_9( dword, ... ) \
+	EFAB_POPULATE_DWORD_10 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_8( dword, ... ) \
+	EFAB_POPULATE_DWORD_9 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_7( dword, ... ) \
+	EFAB_POPULATE_DWORD_8 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_6( dword, ... ) \
+	EFAB_POPULATE_DWORD_7 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_5( dword, ... ) \
+	EFAB_POPULATE_DWORD_6 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_4( dword, ... ) \
+	EFAB_POPULATE_DWORD_5 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_3( dword, ... ) \
+	EFAB_POPULATE_DWORD_4 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_2( dword, ... ) \
+	EFAB_POPULATE_DWORD_3 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_POPULATE_DWORD_1( dword, ... ) \
+	EFAB_POPULATE_DWORD_2 ( dword, EFAB_DUMMY_FIELD, 0, __VA_ARGS__ )
+#define EFAB_ZERO_DWORD( dword ) \
+	EFAB_POPULATE_DWORD_1 ( dword, EFAB_DUMMY_FIELD, 0 )
+#define EFAB_SET_DWORD( dword ) \
+	EFAB_POPULATE_DWORD_1 ( dword, EFAB_DWORD_0, 0xffffffff )
+
+/*
+ * Modify a named field within an already-populated structure.  Used
+ * for read-modify-write operations.
+ *
+ */
+
+#define EFAB_INSERT_FIELD64( ... )					\
+	cpu_to_le64 ( EFAB_INSERT_FIELD_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INSERT_FIELD32( ... )					\
+	cpu_to_le32 ( EFAB_INSERT_FIELD_NATIVE ( __VA_ARGS__ ) )
+
+#define EFAB_INPLACE_MASK64( min, max, field )				\
+	EFAB_INSERT_FIELD64 ( min, max, field, EFAB_MASK64 ( field ) )
+
+#define EFAB_INPLACE_MASK32( min, max, field )				\
+	EFAB_INSERT_FIELD32 ( min, max, field, EFAB_MASK32 ( field ) )
+
+#define EFAB_SET_OWORD_FIELD64( oword, field, value ) do {		      \
+	(oword).u64[0] = ( ( (oword).u64[0] 				      \
+			     & ~EFAB_INPLACE_MASK64 (  0,  63, field ) )      \
+			   | EFAB_INSERT_FIELD64 (  0,  63, field, value ) ); \
+	(oword).u64[1] = ( ( (oword).u64[1] 				      \
+			     & ~EFAB_INPLACE_MASK64 ( 64, 127, field ) )      \
+			   | EFAB_INSERT_FIELD64 ( 64, 127, field, value ) ); \
+	} while ( 0 )
+
+#define EFAB_SET_QWORD_FIELD64( qword, field, value ) do {		      \
+	(qword).u64[0] = ( ( (qword).u64[0] 				      \
+			     & ~EFAB_INPLACE_MASK64 (  0,  63, field ) )      \
+			   | EFAB_INSERT_FIELD64 (  0,  63, field, value ) ); \
+	} while ( 0 )
+
+#define EFAB_SET_OWORD_FIELD32( oword, field, value ) do {		      \
+	(oword).u32[0] = ( ( (oword).u32[0] 				      \
+			     & ~EFAB_INPLACE_MASK32 (  0,  31, field ) )      \
+			   | EFAB_INSERT_FIELD32 (  0,  31, field, value ) ); \
+	(oword).u32[1] = ( ( (oword).u32[1] 				      \
+			     & ~EFAB_INPLACE_MASK32 ( 32,  63, field ) )      \
+			   | EFAB_INSERT_FIELD32 ( 32,  63, field, value ) ); \
+	(oword).u32[2] = ( ( (oword).u32[2] 				      \
+			     & ~EFAB_INPLACE_MASK32 ( 64,  95, field ) )      \
+			   | EFAB_INSERT_FIELD32 ( 64,  95, field, value ) ); \
+	(oword).u32[3] = ( ( (oword).u32[3] 				      \
+			     & ~EFAB_INPLACE_MASK32 ( 96, 127, field ) )      \
+			   | EFAB_INSERT_FIELD32 ( 96, 127, field, value ) ); \
+	} while ( 0 )
+
+#define EFAB_SET_QWORD_FIELD32( qword, field, value ) do {		      \
+	(qword).u32[0] = ( ( (qword).u32[0] 				      \
+			     & ~EFAB_INPLACE_MASK32 (  0,  31, field ) )      \
+			   | EFAB_INSERT_FIELD32 (  0,  31, field, value ) ); \
+	(qword).u32[1] = ( ( (qword).u32[1] 				      \
+			     & ~EFAB_INPLACE_MASK32 ( 32,  63, field ) )      \
+			   | EFAB_INSERT_FIELD32 ( 32,  63, field, value ) ); \
+	} while ( 0 )
+
+#define EFAB_SET_DWORD_FIELD( dword, field, value ) do {		      \
+	(dword).u32[0] = ( ( (dword).u32[0] 				      \
+			     & ~EFAB_INPLACE_MASK32 (  0,  31, field ) )      \
+			   | EFAB_INSERT_FIELD32 (  0,  31, field, value ) ); \
+	} while ( 0 )
+
+#if ( BITS_PER_LONG == 64 )
+#define EFAB_SET_OWORD_FIELD EFAB_SET_OWORD_FIELD64
+#define EFAB_SET_QWORD_FIELD EFAB_SET_QWORD_FIELD64
+#else
+#define EFAB_SET_OWORD_FIELD EFAB_SET_OWORD_FIELD32
+#define EFAB_SET_QWORD_FIELD EFAB_SET_QWORD_FIELD32
+#endif
+
+/* Used to avoid compiler warnings about shift range exceeding width
+ * of the data types when dma_addr_t is only 32 bits wide.
+ */
+#define DMA_ADDR_T_WIDTH	( 8 * sizeof ( dma_addr_t ) )
+#define EFAB_DMA_TYPE_WIDTH( width ) \
+	( ( (width) < DMA_ADDR_T_WIDTH ) ? (width) : DMA_ADDR_T_WIDTH )
+#define EFAB_DMA_MAX_MASK ( ( DMA_ADDR_T_WIDTH == 64 ) ? \
+			    ~( ( uint64_t ) 0 ) : ~( ( uint32_t ) 0 ) )
+#define EFAB_DMA_MASK(mask) ( (mask) & EFAB_DMA_MAX_MASK )
+
+#endif /* EFAB_BITFIELD_H */
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric_nic.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric_nic.h
new file mode 100644
index 0000000..a767e12
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/etherfabric_nic.h
@@ -0,0 +1,204 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown at fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#ifndef EFAB_NIC_H
+#define  EFAB_NIC_H
+#include <ipxe/bitbash.h>
+#include <ipxe/i2c.h>
+#include <ipxe/spi.h>
+#include <ipxe/nvo.h>
+#include <ipxe/if_ether.h>
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403)
+ * But newer boards are getting bigger...
+ */
+typedef enum {
+	EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
+	EFAB_BOARD_SFE4001 = 1,
+	EFAB_BOARD_SFE4002 = 2,
+	EFAB_BOARD_SFE4003 = 3,
+	/* Insert new types before here */
+	EFAB_BOARD_MAX
+} efab_board_type;
+
+/* PHY types. */
+typedef enum {
+	PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */
+	PHY_TYPE_CX4_RTMR = 1,
+	PHY_TYPE_1GIG_ALASKA = 2,
+	PHY_TYPE_10XPRESS = 3,
+	PHY_TYPE_XFP = 4,
+	PHY_TYPE_CX4 = 5,
+	PHY_TYPE_PM8358 = 6,
+} phy_type_t;
+
+/**************************************************************************
+ *
+ * Hardware data structures and sizing
+ *
+ **************************************************************************
+ */
+
+#define dma_addr_t unsigned long
+typedef efab_qword_t falcon_rx_desc_t;
+typedef efab_qword_t falcon_tx_desc_t;
+typedef efab_qword_t falcon_event_t;
+
+#define EFAB_BUF_ALIGN		4096
+#define EFAB_RXD_SIZE		512
+#define EFAB_TXD_SIZE		512
+#define EFAB_EVQ_SIZE		512
+
+#define EFAB_NUM_RX_DESC        16
+#define EFAB_RX_BUF_SIZE	1600
+
+/**************************************************************************
+ *
+ * Data structures
+ *
+ **************************************************************************
+ */
+
+struct efab_nic;
+
+/* A buffer table allocation backing a tx dma, rx dma or eventq */
+struct efab_special_buffer {
+	dma_addr_t dma_addr;
+	int id;
+};
+
+/* A TX queue */
+struct efab_tx_queue {
+	/* The hardware ring */
+	falcon_tx_desc_t *ring;
+
+	/* The software ring storing io_buffers. */
+	struct io_buffer *buf[EFAB_TXD_SIZE];
+
+	/* The buffer table reservation pushed to hardware */
+	struct efab_special_buffer entry;
+
+	/* Software descriptor write ptr */
+	unsigned int write_ptr;
+
+	/* Hardware descriptor read ptr */
+	unsigned int read_ptr;
+};
+
+/* An RX queue */
+struct efab_rx_queue {
+	/* The hardware ring */
+	falcon_rx_desc_t *ring;
+
+	/* The software ring storing io_buffers */
+	struct io_buffer *buf[EFAB_NUM_RX_DESC];
+
+	/* The buffer table reservation pushed to hardware */
+	struct efab_special_buffer entry;
+
+	/* Descriptor write ptr, into both the hardware and software rings */
+	unsigned int write_ptr;
+
+	/* Hardware completion ptr */
+	unsigned int read_ptr;
+};
+
+/* An event queue */
+struct efab_ev_queue {
+	/* The hardware ring to push to hardware.
+	 * Must be the first entry in the structure */
+	falcon_event_t *ring;
+
+	/* The buffer table reservation pushed to hardware */
+	struct efab_special_buffer entry;
+
+	/* Pointers into the ring */
+	unsigned int read_ptr;
+};
+
+struct efab_mac_operations {
+	int ( * init ) ( struct efab_nic *efab );
+};
+
+struct efab_phy_operations {
+	int ( * init ) ( struct efab_nic *efab );
+	unsigned int mmds;
+};
+
+struct efab_board_operations {
+	int ( * init ) ( struct efab_nic *efab );
+	void ( * fini ) ( struct efab_nic *efab );
+};
+
+struct efab_nic {
+	struct net_device *netdev;
+	int pci_revision;
+	int is_asic;
+
+	/* I2C bit-bashed interface */
+	struct i2c_bit_basher i2c_bb;
+
+	/** SPI bus and devices, and the user visible NVO area */
+	struct spi_bus spi_bus;
+	struct spi_device spi_flash;
+	struct spi_device spi_eeprom;
+	struct spi_device *spi;
+	struct nvo_block nvo;
+
+	/** Board, MAC, and PHY operations tables */
+	struct efab_board_operations *board_op;
+	struct efab_mac_operations *mac_op;
+	struct efab_phy_operations *phy_op;
+
+	/* PHY and board types */
+	int phy_addr;
+	int phy_type;
+	int phy_10g;
+	int board_type;
+
+	/** Memory and IO base */
+	void *membase;
+	unsigned int iobase;
+
+	/* Buffer table allocation head */
+	int buffer_head;
+
+	/* Queues */
+	struct efab_rx_queue rx_queue;
+	struct efab_tx_queue tx_queue;
+	struct efab_ev_queue ev_queue;
+
+	/** MAC address */
+	uint8_t mac_addr[ETH_ALEN];
+	/** GMII link options */
+	unsigned int link_options;
+	/** Link status */
+	int link_up;
+
+	/** INT_REG_KER */
+	efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
+};
+#endif /* EFAB_NIC_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.c
new file mode 100644
index 0000000..c34a429
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.c
@@ -0,0 +1,1981 @@
+/*
+ *    forcedeth.c -- Driver for NVIDIA nForce media access controllers for iPXE
+ *    Copyright (c) 2010 Andrei Faur <da3drus at gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License as
+ *    published by the Free Software Foundation; either version 2 of the
+ *    License, or any later version.
+ *
+ *    This program is distributed in the hope that it will be useful, but
+ *    WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Portions of this code are taken from the Linux forcedeth driver that was
+ * based on a cleanroom reimplementation which was based on reverse engineered
+ * documentation written by Carl-Daniel Hailfinger and Andrew de Quincey:
+ * Copyright (C) 2003,4,5 Manfred Spraul
+ * Copyright (C) 2004 Andrew de Quincey (wol support)
+ * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
+ *		IRQ rate fixes, bigendian fixes, cleanups, verification)
+ * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
+ *
+ * The probe, remove, open and close functions, along with the functions they
+ * call, are direct copies of the above mentioned driver, modified where
+ * necessary to make them work for iPXE.
+ *
+ * The poll and transmit functions were completely rewritten to make use of
+ * the iPXE API. This process was aided by constant referencing of the above
+ * mentioned Linux driver. This driver would not have been possible without this
+ * prior work.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/crypto.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+#include <mii.h>
+#include "forcedeth.h"
+
+static inline void pci_push ( void *ioaddr )
+{
+	/* force out pending posted writes */
+	readl ( ioaddr );
+}
+
+static int
+reg_delay ( struct forcedeth_private *priv, int offset, u32 mask,
+	    u32 target, int delay, int delaymax, const char *msg )
+{
+	void *ioaddr = priv->mmio_addr;
+
+	pci_push ( ioaddr );
+	do {
+		udelay ( delay );
+		delaymax -= delay;
+		if ( delaymax < 0 ) {
+			if ( msg )
+				DBG ( "%s\n", msg );
+			return 1;
+		}
+	} while ( ( readl ( ioaddr + offset ) & mask ) != target );
+
+	return 0;
+}
+
+/* read/write a register on the PHY */
+static int
+mii_rw ( struct forcedeth_private *priv, int addr, int miireg, int value )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 reg;
+	int retval;
+
+	writel ( NVREG_MIISTAT_MASK_RW, ioaddr + NvRegMIIStatus );
+
+	reg = readl ( ioaddr + NvRegMIIControl );
+	if ( reg & NVREG_MIICTL_INUSE ) {
+		writel ( NVREG_MIICTL_INUSE, ioaddr + NvRegMIIControl );
+		udelay ( NV_MIIBUSY_DELAY );
+	}
+
+	reg = ( addr << NVREG_MIICTL_ADDRSHIFT ) | miireg;
+	if ( value != MII_READ ) {
+		writel ( value, ioaddr + NvRegMIIData );
+		reg |= NVREG_MIICTL_WRITE;
+	}
+	writel ( reg, ioaddr + NvRegMIIControl );
+
+	if ( reg_delay ( priv, NvRegMIIControl, NVREG_MIICTL_INUSE, 0,
+			NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL ) ) {
+		DBG ( "mii_rw of reg %d at PHY %d timed out.\n",
+			miireg, addr );
+		retval = -1;
+	} else if ( value != MII_READ ) {
+		/* it was a write operation - fewer failures are detectable */
+		DBG ( "mii_rw wrote 0x%x to reg %d at PHY %d\n",
+			value, miireg, addr );
+		retval = 0;
+	} else if ( readl ( ioaddr + NvRegMIIStatus ) & NVREG_MIISTAT_ERROR ) {
+		DBG ( "mii_rw of reg %d at PHY %d failed.\n",
+			miireg, addr );
+		retval = -1;
+	} else {
+		retval = readl ( ioaddr + NvRegMIIData );
+		DBG ( "mii_rw read from reg %d at PHY %d: 0x%x.\n",
+			miireg, addr, retval );
+	}
+
+	return retval;
+}
+
+static void
+nv_txrx_gate ( struct forcedeth_private *priv, int gate )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 powerstate;
+
+	if ( ! priv->mac_in_use &&
+	     ( priv->driver_data & DEV_HAS_POWER_CNTRL ) ) {
+		powerstate = readl ( ioaddr + NvRegPowerState2 );
+		if ( gate )
+			powerstate |= NVREG_POWERSTATE2_GATE_CLOCKS;
+		else
+			powerstate &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
+		writel ( powerstate, ioaddr + NvRegPowerState2 );
+	}
+}
+
+static void
+nv_mac_reset ( struct forcedeth_private * priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 temp1, temp2, temp3;
+
+	writel ( NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	pci_push ( ioaddr );
+
+	/* save registers since they will be cleared on reset */
+	temp1 = readl ( ioaddr + NvRegMacAddrA );
+	temp2 = readl ( ioaddr + NvRegMacAddrB );
+	temp3 = readl ( ioaddr + NvRegTransmitPoll );
+
+	writel ( NVREG_MAC_RESET_ASSERT, ioaddr + NvRegMacReset );
+	pci_push ( ioaddr );
+	udelay ( NV_MAC_RESET_DELAY );
+	writel ( 0, ioaddr + NvRegMacReset );
+	pci_push ( ioaddr );
+	udelay ( NV_MAC_RESET_DELAY );
+
+	/* restore saved registers */
+	writel ( temp1, ioaddr + NvRegMacAddrA );
+	writel ( temp2, ioaddr + NvRegMacAddrB );
+	writel ( temp3, ioaddr + NvRegTransmitPoll );
+
+	writel ( NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	pci_push ( ioaddr );
+}
+
+static void
+nv_init_tx_ring ( struct forcedeth_private *priv )
+{
+	int i;
+
+	for ( i = 0; i < TX_RING_SIZE; i++ ) {
+		priv->tx_ring[i].flaglen = 0;
+		priv->tx_ring[i].buf = 0;
+		priv->tx_iobuf[i] = NULL;
+	}
+
+	priv->tx_fill_ctr = 0;
+	priv->tx_curr = 0;
+	priv->tx_tail = 0;
+}
+
+/**
+ * nv_alloc_rx - Allocates iobufs for every Rx descriptor
+ * that doesn't have one and isn't in use by the hardware
+ *
+ * @v priv	Driver private structure
+ */
+static void
+nv_alloc_rx ( struct forcedeth_private *priv )
+{
+	struct ring_desc *rx_curr_desc;
+	int i;
+	u32 status;
+
+	DBGP ( "nv_alloc_rx\n" );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		rx_curr_desc = priv->rx_ring + i;
+		status = le32_to_cpu ( rx_curr_desc->flaglen );
+
+		/* Don't touch the descriptors owned by the hardware */
+		if ( status & NV_RX_AVAIL )
+			continue;
+
+		/* Descriptors with iobufs still need to be processed */
+		if ( priv->rx_iobuf[i] != NULL )
+			continue;
+
+		/* If alloc_iob fails, try again later (next poll) */
+		if ( ! ( priv->rx_iobuf[i] = alloc_iob ( RX_BUF_SZ ) ) ) {
+			DBG ( "Refill rx_ring failed, size %d\n", RX_BUF_SZ );
+			break;
+		}
+
+		rx_curr_desc->buf =
+			cpu_to_le32 ( virt_to_bus ( priv->rx_iobuf[i]->data ) );
+		wmb();
+		rx_curr_desc->flaglen =
+			cpu_to_le32 ( RX_BUF_SZ | NV_RX_AVAIL );
+	}
+}
+
+static void
+nv_init_rx_ring ( struct forcedeth_private *priv )
+{
+	int i;
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		priv->rx_ring[i].flaglen = 0;
+		priv->rx_ring[i].buf = 0;
+		priv->rx_iobuf[i] = NULL;
+	}
+
+	priv->rx_curr = 0;
+}
+
+/**
+ * nv_init_rings - Allocate and intialize descriptor rings
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Return status code
+ **/
+static int
+nv_init_rings ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	int rc = -ENOMEM;
+
+	/* Allocate ring for both TX and RX */
+	priv->rx_ring =
+		malloc_dma ( sizeof(struct ring_desc) * RXTX_RING_SIZE, 32 );
+	if ( ! priv->rx_ring )
+		goto err_malloc;
+	priv->tx_ring = &priv->rx_ring[RX_RING_SIZE];
+
+	/* Initialize rings */
+	nv_init_tx_ring ( priv );
+	nv_init_rx_ring ( priv );
+
+	/* Allocate iobufs for RX */
+	nv_alloc_rx ( priv );
+
+	/* Give hw rings */
+	writel ( cpu_to_le32 ( virt_to_bus ( priv->rx_ring ) ),
+		 ioaddr + NvRegRxRingPhysAddr );
+	writel ( cpu_to_le32 ( virt_to_bus ( priv->tx_ring ) ),
+		 ioaddr + NvRegTxRingPhysAddr );
+
+	DBG ( "RX ring at phys addr: %#08lx\n",
+		virt_to_bus ( priv->rx_ring ) );
+	DBG ( "TX ring at phys addr: %#08lx\n",
+		virt_to_bus ( priv->tx_ring ) );
+
+	writel ( ( ( RX_RING_SIZE - 1 ) << NVREG_RINGSZ_RXSHIFT ) +
+		 ( ( TX_RING_SIZE - 1 ) << NVREG_RINGSZ_TXSHIFT ),
+		 ioaddr + NvRegRingSizes );
+
+	return 0;
+
+err_malloc:
+	DBG ( "Could not allocate descriptor rings\n");
+	return rc;
+}
+
+static void
+nv_free_rxtx_resources ( struct forcedeth_private *priv )
+{
+	int i;
+
+	DBGP ( "nv_free_rxtx_resources\n" );
+
+	free_dma ( priv->rx_ring, sizeof(struct ring_desc) * RXTX_RING_SIZE );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		free_iob ( priv->rx_iobuf[i] );
+		priv->rx_iobuf[i] = NULL;
+	}
+}
+
+static void
+nv_txrx_reset ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+
+	writel ( NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	pci_push ( ioaddr );
+	udelay ( NV_TXRX_RESET_DELAY );
+	writel ( NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	pci_push ( ioaddr );
+}
+
+static void
+nv_disable_hw_interrupts ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+
+	writel ( 0, ioaddr + NvRegIrqMask );
+}
+
+static void
+nv_enable_hw_interrupts ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+
+	writel ( NVREG_IRQMASK_THROUGHPUT, ioaddr + NvRegIrqMask );
+}
+
+static void
+nv_start_rx ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 rx_ctrl = readl ( ioaddr + NvRegReceiverControl );
+
+	DBGP ( "nv_start_rx\n" );
+	/* Already running? Stop it. */
+	if ( ( readl ( ioaddr + NvRegReceiverControl ) & NVREG_RCVCTL_START ) && !priv->mac_in_use ) {
+		rx_ctrl &= ~NVREG_RCVCTL_START;
+		writel ( rx_ctrl, ioaddr + NvRegReceiverControl );
+		pci_push ( ioaddr );
+	}
+	writel ( priv->linkspeed, ioaddr + NvRegLinkSpeed );
+	pci_push ( ioaddr );
+        rx_ctrl |= NVREG_RCVCTL_START;
+        if ( priv->mac_in_use )
+		rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN;
+	writel ( rx_ctrl, ioaddr + NvRegReceiverControl );
+	DBG ( "nv_start_rx to duplex %d, speed 0x%08x.\n",
+		priv->duplex, priv->linkspeed);
+	pci_push ( ioaddr );
+}
+
+static void
+nv_stop_rx ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 rx_ctrl = readl ( ioaddr + NvRegReceiverControl );
+
+	DBGP ( "nv_stop_rx\n" );
+	if ( ! priv->mac_in_use )
+		rx_ctrl &= ~NVREG_RCVCTL_START;
+	else
+		rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN;
+	writel ( rx_ctrl, ioaddr + NvRegReceiverControl );
+	reg_delay ( priv, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
+			NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
+			"nv_stop_rx: ReceiverStatus remained busy");
+
+	udelay ( NV_RXSTOP_DELAY2 );
+	if ( ! priv->mac_in_use )
+		writel ( 0, priv + NvRegLinkSpeed );
+}
+
+static void
+nv_start_tx ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 tx_ctrl = readl ( ioaddr + NvRegTransmitterControl );
+
+	DBGP ( "nv_start_tx\n" );
+	tx_ctrl |= NVREG_XMITCTL_START;
+	if ( priv->mac_in_use )
+		tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN;
+	writel ( tx_ctrl, ioaddr + NvRegTransmitterControl );
+	pci_push ( ioaddr );
+}
+
+static void
+nv_stop_tx ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 tx_ctrl = readl ( ioaddr + NvRegTransmitterControl );
+
+	DBGP ( "nv_stop_tx");
+
+	if ( ! priv->mac_in_use )
+		tx_ctrl &= ~NVREG_XMITCTL_START;
+	else
+		tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN;
+	writel ( tx_ctrl, ioaddr + NvRegTransmitterControl );
+	reg_delay ( priv, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
+			NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
+			"nv_stop_tx: TransmitterStatus remained busy");
+
+	udelay ( NV_TXSTOP_DELAY2 );
+	if ( ! priv->mac_in_use )
+		writel( readl ( ioaddr + NvRegTransmitPoll) &
+				NVREG_TRANSMITPOLL_MAC_ADDR_REV,
+			ioaddr + NvRegTransmitPoll);
+}
+
+
+static void
+nv_update_pause ( struct forcedeth_private *priv, u32 pause_flags )
+{
+	void *ioaddr = priv->mmio_addr;
+
+	priv->pause_flags &= ~ ( NV_PAUSEFRAME_TX_ENABLE |
+				 NV_PAUSEFRAME_RX_ENABLE );
+
+	if ( priv->pause_flags & NV_PAUSEFRAME_RX_CAPABLE ) {
+		u32 pff = readl ( ioaddr + NvRegPacketFilterFlags ) & ~NVREG_PFF_PAUSE_RX;
+		if ( pause_flags & NV_PAUSEFRAME_RX_ENABLE ) {
+			writel ( pff | NVREG_PFF_PAUSE_RX, ioaddr + NvRegPacketFilterFlags );
+			priv->pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+		} else {
+			writel ( pff, ioaddr + NvRegPacketFilterFlags );
+		}
+	}
+	if ( priv->pause_flags & NV_PAUSEFRAME_TX_CAPABLE ) {
+		u32 regmisc = readl ( ioaddr + NvRegMisc1 ) & ~NVREG_MISC1_PAUSE_TX;
+		if ( pause_flags & NV_PAUSEFRAME_TX_ENABLE ) {
+			u32 pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V1;
+			if ( priv->driver_data & DEV_HAS_PAUSEFRAME_TX_V2 )
+				pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V2;
+			if ( priv->driver_data & DEV_HAS_PAUSEFRAME_TX_V3 ) {
+				pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V3;
+				/* limit the number of tx pause frames to a default of 8 */
+				writel ( readl ( ioaddr + NvRegTxPauseFrameLimit ) |
+						NVREG_TX_PAUSEFRAMELIMIT_ENABLE,
+					 ioaddr + NvRegTxPauseFrameLimit );
+			}
+			writel ( pause_enable, ioaddr + NvRegTxPauseFrame );
+			writel ( regmisc | NVREG_MISC1_PAUSE_TX, ioaddr + NvRegMisc1 );
+			priv->pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+		} else {
+			writel ( NVREG_TX_PAUSEFRAME_DISABLE, ioaddr + NvRegTxPauseFrame );
+			writel ( regmisc, ioaddr + NvRegMisc1 );
+		}
+	}
+}
+
+static int
+nv_update_linkspeed ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	int adv = 0;
+	int lpa = 0;
+	int adv_lpa, adv_pause, lpa_pause;
+	u32 newls = priv->linkspeed;
+	int newdup = priv->duplex;
+	int mii_status;
+	int retval = 0;
+	u32 control_1000, status_1000, phyreg, pause_flags, txreg;
+	u32 txrxFlags = 0;
+	u32 phy_exp;
+
+	/* BMSR_LSTATUS is latched, read it twice:
+	 * we want the current value.
+	 */
+	mii_rw ( priv, priv->phyaddr, MII_BMSR, MII_READ );
+	mii_status = mii_rw ( priv, priv->phyaddr, MII_BMSR, MII_READ );
+
+	if ( ! ( mii_status & BMSR_LSTATUS ) ) {
+		DBG ( "No link detected by phy - falling back to 10HD.\n" );
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+		newdup = 0;
+		retval = 0;
+		goto set_speed;
+	}
+
+	/* check auto negotiation is complete */
+	if ( ! ( mii_status & BMSR_ANEGCOMPLETE ) ) {
+		/* still in autonegotiation - configure nic for 10 MBit HD and wait. */
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+		newdup = 0;
+		retval = 0;
+		DBG ( "autoneg not completed - falling back to 10HD.\n" );
+		goto set_speed;
+	}
+
+	adv = mii_rw ( priv, priv->phyaddr, MII_ADVERTISE, MII_READ );
+	lpa = mii_rw ( priv, priv->phyaddr, MII_LPA, MII_READ );
+	DBG ( "nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", adv, lpa );
+
+	retval = 1;
+	if ( priv->gigabit == PHY_GIGABIT ) {
+		control_1000 = mii_rw ( priv, priv->phyaddr, MII_CTRL1000, MII_READ);
+		status_1000 = mii_rw ( priv, priv->phyaddr, MII_STAT1000, MII_READ);
+
+		if ( ( control_1000 & ADVERTISE_1000FULL ) &&
+			( status_1000 & LPA_1000FULL ) ) {
+			DBG ( "nv_update_linkspeed: GBit ethernet detected.\n" );
+			newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000;
+			newdup = 1;
+			goto set_speed;
+		}
+	}
+
+	/* FIXME: handle parallel detection properly */
+	adv_lpa = lpa & adv;
+	if ( adv_lpa & LPA_100FULL ) {
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100;
+		newdup = 1;
+	} else if ( adv_lpa & LPA_100HALF ) {
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100;
+		newdup = 0;
+	} else if ( adv_lpa & LPA_10FULL ) {
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+		newdup = 1;
+	} else if ( adv_lpa & LPA_10HALF ) {
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+		newdup = 0;
+	} else {
+		DBG ( "bad ability %04x - falling back to 10HD.\n", adv_lpa);
+		newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+		newdup = 0;
+	}
+
+set_speed:
+	if ( priv->duplex == newdup && priv->linkspeed == newls )
+		return retval;
+
+	DBG ( "changing link setting from %d/%d to %d/%d.\n",
+		priv->linkspeed, priv->duplex, newls, newdup);
+
+	priv->duplex = newdup;
+	priv->linkspeed = newls;
+
+	/* The transmitter and receiver must be restarted for safe update */
+	if ( readl ( ioaddr + NvRegTransmitterControl ) & NVREG_XMITCTL_START ) {
+		txrxFlags |= NV_RESTART_TX;
+		nv_stop_tx ( priv );
+	}
+	if ( readl ( ioaddr + NvRegReceiverControl ) & NVREG_RCVCTL_START) {
+		txrxFlags |= NV_RESTART_RX;
+		nv_stop_rx ( priv );
+	}
+
+	if ( priv->gigabit == PHY_GIGABIT ) {
+		phyreg = readl ( ioaddr + NvRegSlotTime );
+		phyreg &= ~(0x3FF00);
+		if ( ( ( priv->linkspeed & 0xFFF ) == NVREG_LINKSPEED_10 ) ||
+		     ( ( priv->linkspeed & 0xFFF ) == NVREG_LINKSPEED_100) )
+			phyreg |= NVREG_SLOTTIME_10_100_FULL;
+		else if ( ( priv->linkspeed & 0xFFF ) == NVREG_LINKSPEED_1000 )
+			phyreg |= NVREG_SLOTTIME_1000_FULL;
+		writel( phyreg, priv + NvRegSlotTime );
+	}
+
+	phyreg = readl ( ioaddr + NvRegPhyInterface );
+	phyreg &= ~( PHY_HALF | PHY_100 | PHY_1000 );
+	if ( priv->duplex == 0 )
+		phyreg |= PHY_HALF;
+	if ( ( priv->linkspeed & NVREG_LINKSPEED_MASK ) == NVREG_LINKSPEED_100 )
+		phyreg |= PHY_100;
+	else if ( ( priv->linkspeed & NVREG_LINKSPEED_MASK ) == NVREG_LINKSPEED_1000 )
+		phyreg |= PHY_1000;
+	writel ( phyreg, ioaddr + NvRegPhyInterface );
+
+	phy_exp = mii_rw ( priv, priv->phyaddr, MII_EXPANSION, MII_READ ) & EXPANSION_NWAY; /* autoneg capable */
+	if ( phyreg & PHY_RGMII ) {
+		if ( ( priv->linkspeed & NVREG_LINKSPEED_MASK ) == NVREG_LINKSPEED_1000 ) {
+			txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+		} else {
+			if ( !phy_exp && !priv->duplex && ( priv->driver_data & DEV_HAS_COLLISION_FIX ) ) {
+				if ( ( priv->linkspeed & NVREG_LINKSPEED_MASK ) == NVREG_LINKSPEED_10 )
+					txreg = NVREG_TX_DEFERRAL_RGMII_STRETCH_10;
+				else
+					txreg = NVREG_TX_DEFERRAL_RGMII_STRETCH_100;
+			} else {
+				txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+			}
+		}
+	} else {
+		if ( !phy_exp && !priv->duplex && ( priv->driver_data & DEV_HAS_COLLISION_FIX ) )
+			txreg = NVREG_TX_DEFERRAL_MII_STRETCH;
+		else
+			txreg = NVREG_TX_DEFERRAL_DEFAULT;
+	}
+	writel ( txreg, ioaddr + NvRegTxDeferral );
+
+	txreg = NVREG_TX_WM_DESC1_DEFAULT;
+	writel ( txreg, ioaddr + NvRegTxWatermark );
+
+	writel ( NVREG_MISC1_FORCE | ( priv->duplex ? 0 : NVREG_MISC1_HD ), ioaddr + NvRegMisc1 );
+	pci_push ( ioaddr );
+	writel ( priv->linkspeed, priv + NvRegLinkSpeed);
+	pci_push ( ioaddr );
+
+	pause_flags = 0;
+	/* setup pause frame */
+	if ( priv->duplex != 0 ) {
+		if ( priv->pause_flags & NV_PAUSEFRAME_AUTONEG ) {
+			adv_pause = adv & ( ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM );
+			lpa_pause = lpa & ( LPA_PAUSE_CAP | LPA_PAUSE_ASYM );
+
+			switch ( adv_pause ) {
+			case ADVERTISE_PAUSE_CAP:
+				if ( lpa_pause & LPA_PAUSE_CAP ) {
+					pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+					if ( priv->pause_flags & NV_PAUSEFRAME_TX_REQ )
+						pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+				}
+				break;
+			case ADVERTISE_PAUSE_ASYM:
+				if ( lpa_pause == ( LPA_PAUSE_CAP | LPA_PAUSE_ASYM ) )
+				{
+					pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+				}
+				break;
+			case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
+				if ( lpa_pause & LPA_PAUSE_CAP )
+				{
+					pause_flags |=  NV_PAUSEFRAME_RX_ENABLE;
+					if ( priv->pause_flags & NV_PAUSEFRAME_TX_REQ )
+						pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+				}
+				if ( lpa_pause == LPA_PAUSE_ASYM )
+				{
+					pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+				}
+				break;
+			}
+		} else {
+			pause_flags = priv->pause_flags;
+		}
+	}
+	nv_update_pause ( priv, pause_flags );
+
+	if ( txrxFlags & NV_RESTART_TX )
+		nv_start_tx ( priv );
+	if ( txrxFlags & NV_RESTART_RX )
+		nv_start_rx ( priv );
+
+	return retval;
+}
+
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev	Network device
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ **/
+static int
+forcedeth_open ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	void *ioaddr = priv->mmio_addr;
+	int i;
+	int rc;
+	u32 low;
+
+	DBGP ( "forcedeth_open\n" );
+
+	/* Power up phy */
+	mii_rw ( priv, priv->phyaddr, MII_BMCR,
+		 mii_rw ( priv, priv->phyaddr, MII_BMCR, MII_READ ) & ~BMCR_PDOWN );
+
+	nv_txrx_gate ( priv, 0 );
+
+	/* Erase previous misconfiguration */
+	if ( priv->driver_data & DEV_HAS_POWER_CNTRL )
+		nv_mac_reset ( priv );
+
+	/* Clear multicast masks and addresses, enter promiscuous mode */
+	writel ( 0, ioaddr + NvRegMulticastAddrA );
+	writel ( 0, ioaddr + NvRegMulticastAddrB );
+	writel ( NVREG_MCASTMASKA_NONE, ioaddr + NvRegMulticastMaskA );
+	writel ( NVREG_MCASTMASKB_NONE, ioaddr + NvRegMulticastMaskB );
+	writel ( NVREG_PFF_PROMISC, ioaddr + NvRegPacketFilterFlags );
+
+	writel ( 0, ioaddr + NvRegTransmitterControl );
+	writel ( 0, ioaddr + NvRegReceiverControl );
+
+	writel ( 0, ioaddr + NvRegAdapterControl );
+
+	writel ( 0, ioaddr + NvRegLinkSpeed );
+	writel ( readl ( ioaddr + NvRegTransmitPoll ) & NVREG_TRANSMITPOLL_MAC_ADDR_REV,
+		 ioaddr + NvRegTransmitPoll );
+	nv_txrx_reset ( priv );
+	writel ( 0, ioaddr + NvRegUnknownSetupReg6 );
+
+	/* Initialize descriptor rings */
+	if ( ( rc = nv_init_rings ( priv ) ) != 0 )
+		goto err_init_rings;
+
+	writel ( priv->linkspeed, ioaddr + NvRegLinkSpeed );
+	writel ( NVREG_TX_WM_DESC1_DEFAULT, ioaddr + NvRegTxWatermark );
+	writel ( NVREG_TXRXCTL_DESC_1, ioaddr + NvRegTxRxControl );
+	writel ( 0 , ioaddr + NvRegVlanControl );
+	pci_push ( ioaddr );
+	writel ( NVREG_TXRXCTL_BIT1 | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	reg_delay ( priv, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31,
+		    NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX,
+		    "open: SetupReg5, Bit 31 remained off\n" );
+
+	writel ( 0, ioaddr + NvRegMIIMask );
+	writel ( NVREG_IRQSTAT_MASK, ioaddr + NvRegIrqStatus );
+	writel ( NVREG_MIISTAT_MASK_ALL, ioaddr + NvRegMIIStatus );
+
+	writel ( NVREG_MISC1_FORCE | NVREG_MISC1_HD, ioaddr + NvRegMisc1 );
+	writel ( readl ( ioaddr + NvRegTransmitterStatus ),
+		 ioaddr + NvRegTransmitterStatus );
+	writel ( RX_BUF_SZ, ioaddr + NvRegOffloadConfig );
+
+	writel ( readl ( ioaddr + NvRegReceiverStatus),
+		 ioaddr + NvRegReceiverStatus );
+
+	/* Set up slot time */
+	get_random_bytes ( &low, sizeof(low) );
+	low &= NVREG_SLOTTIME_MASK;
+	writel ( low | NVREG_SLOTTIME_DEFAULT, ioaddr + NvRegSlotTime );
+
+	writel ( NVREG_TX_DEFERRAL_DEFAULT , ioaddr + NvRegTxDeferral );
+	writel ( NVREG_RX_DEFERRAL_DEFAULT , ioaddr + NvRegRxDeferral );
+
+	writel ( NVREG_POLL_DEFAULT_THROUGHPUT, ioaddr + NvRegPollingInterval );
+
+	writel ( NVREG_UNKSETUP6_VAL, ioaddr + NvRegUnknownSetupReg6 );
+	writel ( ( priv->phyaddr << NVREG_ADAPTCTL_PHYSHIFT ) |
+		 NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING,
+		 ioaddr + NvRegAdapterControl );
+	writel ( NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, ioaddr + NvRegMIISpeed );
+	writel ( NVREG_MII_LINKCHANGE, ioaddr + NvRegMIIMask );
+
+	i = readl ( ioaddr + NvRegPowerState );
+	if ( ( i & NVREG_POWERSTATE_POWEREDUP ) == 0 )
+		writel ( NVREG_POWERSTATE_POWEREDUP | i, ioaddr + NvRegPowerState );
+
+	pci_push ( ioaddr );
+	udelay ( 10 );
+	writel ( readl ( ioaddr + NvRegPowerState ) | NVREG_POWERSTATE_VALID,
+		 ioaddr + NvRegPowerState );
+
+	nv_disable_hw_interrupts ( priv );
+	pci_push ( ioaddr );
+	writel ( NVREG_MIISTAT_MASK_ALL, ioaddr + NvRegMIIStatus );
+	writel ( NVREG_IRQSTAT_MASK, ioaddr + NvRegIrqStatus );
+	pci_push ( ioaddr );
+
+	readl ( ioaddr + NvRegMIIStatus );
+	writel ( NVREG_MIISTAT_MASK_ALL, ioaddr + NvRegMIIStatus );
+	priv->linkspeed = 0;
+	nv_update_linkspeed ( priv );
+	nv_start_rx ( priv );
+	nv_start_tx ( priv );
+
+	return 0;
+
+err_init_rings:
+	return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int
+forcedeth_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	void *ioaddr = priv->mmio_addr;
+	struct ring_desc *tx_curr_desc;
+	u32 size = iob_len ( iobuf );
+
+	DBGP ( "forcedeth_transmit\n" );
+
+	/* NOTE: Some NICs have a hw bug that causes them to malfunction
+	 * when there are more than 16 outstanding TXs. Increasing the TX
+	 * ring size might trigger this bug */
+	if ( priv->tx_fill_ctr == TX_RING_SIZE ) {
+		DBG ( "Tx overflow\n" );
+		return -ENOBUFS;
+	}
+
+	/* Pad small packets to minimum length */
+	iob_pad ( iobuf, ETH_ZLEN );
+
+	priv->tx_iobuf[priv->tx_curr] = iobuf;
+
+	tx_curr_desc = priv->tx_ring + priv->tx_curr;
+
+	/* Configure current descriptor to transmit packet
+	 * ( NV_TX_VALID sets the ownership bit ) */
+	tx_curr_desc->buf =
+		cpu_to_le32 ( virt_to_bus ( iobuf->data ) );
+	wmb();
+	/* Since we don't do fragmentation offloading, we always have
+	 * the last packet bit set */
+	tx_curr_desc->flaglen =
+		cpu_to_le32 ( ( size - 1 ) | NV_TX_VALID | NV_TX_LASTPACKET );
+
+	DBG ( "forcedeth_transmit: flaglen = %#04x\n",
+		( size - 1 ) | NV_TX_VALID | NV_TX_LASTPACKET );
+	DBG ( "forcedeth_transmit: tx_fill_ctr = %d\n",
+		priv->tx_fill_ctr );
+
+	writel ( NVREG_TXRXCTL_KICK | NVREG_TXRXCTL_DESC_1,
+		 ioaddr + NvRegTxRxControl );
+	pci_push ( ioaddr );
+
+	/* Point to the next free descriptor */
+	priv->tx_curr = ( priv->tx_curr + 1 ) % TX_RING_SIZE;
+
+	/* Increment number of descriptors in use */
+	priv->tx_fill_ctr++;
+
+	return 0;
+}
+
+/**
+ * nv_process_tx_packets - Checks for successfully sent packets,
+ * reports them to iPXE with netdev_tx_complete()
+ *
+ * @v netdev    Network device
+ */
+static void
+nv_process_tx_packets ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	struct ring_desc *tx_curr_desc;
+	u32 flaglen;
+
+	DBGP ( "nv_process_tx_packets\n" );
+
+	while ( priv->tx_tail != priv->tx_curr ) {
+
+		tx_curr_desc = priv->tx_ring + priv->tx_tail;
+		flaglen = le32_to_cpu ( tx_curr_desc->flaglen );
+		rmb();
+
+		/* Skip this descriptor if hardware still owns it */
+		if ( flaglen & NV_TX_VALID )
+			break;
+
+		DBG ( "Transmitted packet.\n" );
+		DBG ( "priv->tx_fill_ctr= %d\n", priv->tx_fill_ctr );
+		DBG ( "priv->tx_tail	= %d\n", priv->tx_tail );
+		DBG ( "priv->tx_curr	= %d\n", priv->tx_curr );
+		DBG ( "flaglen		= %#04x\n", flaglen );
+
+		/* This packet is ready for completion */
+		netdev_tx_complete ( netdev, priv->tx_iobuf[priv->tx_tail] );
+
+		/* Clear the descriptor */
+		memset ( tx_curr_desc, 0, sizeof(*tx_curr_desc) );
+
+		/* Reduce the number of tx descriptors in use */
+		priv->tx_fill_ctr--;
+
+		/* Go to next available descriptor */
+		priv->tx_tail = ( priv->tx_tail + 1 ) % TX_RING_SIZE;
+	}
+}
+
+/**
+ * nv_process_rx_packets - Checks for received packets, reports them
+ * to iPXE with netdev_rx() or netdev_rx_err() if there was an error receiving
+ * the packet
+ *
+ * @v netdev    Network device
+ */
+static void
+nv_process_rx_packets ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	struct io_buffer *curr_iob;
+	struct ring_desc *rx_curr_desc;
+	u32 flags, len;
+	int i;
+
+	DBGP ( "nv_process_rx_packets\n" );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+
+		rx_curr_desc = priv->rx_ring + priv->rx_curr;
+		flags = le32_to_cpu ( rx_curr_desc->flaglen );
+		rmb();
+
+		/* Skip this descriptor if hardware still owns it */
+		if ( flags & NV_RX_AVAIL )
+			break;
+
+		/* We own the descriptor, but it has not been refilled yet */
+		curr_iob = priv->rx_iobuf[priv->rx_curr];
+		DBG ( "%p %p\n", curr_iob, priv->rx_iobuf[priv->rx_curr] );
+		if ( curr_iob == NULL )
+			break;
+
+		DBG ( "Received packet.\n" );
+		DBG ( "priv->rx_curr	= %d\n", priv->rx_curr );
+		DBG ( "flags		= %#04x\n", flags );
+
+		/* Check for errors */
+		if ( ( flags & NV_RX_DESCRIPTORVALID ) &&
+		     ( flags & NV_RX_ERROR ) ) {
+				netdev_rx_err ( netdev, curr_iob, -EINVAL );
+				DBG ( " Corrupted packet received!\n" );
+		} else {
+			len = flags & LEN_MASK_V1;
+
+			iob_put ( curr_iob, len );
+			netdev_rx ( netdev, curr_iob );
+		}
+
+		/* Invalidate iobuf */
+		priv->rx_iobuf[priv->rx_curr] = NULL;
+
+		/* Invalidate descriptor */
+		memset ( rx_curr_desc, 0, sizeof(*rx_curr_desc) );
+
+		/* Point to the next free descriptor */
+		priv->rx_curr = ( priv->rx_curr + 1 ) % RX_RING_SIZE;
+	}
+
+	nv_alloc_rx ( priv );
+}
+
+/**
+ * check_link - Check for link status change
+ *
+ * @v netdev	Network device
+ */
+static void
+forcedeth_link_status ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	void *ioaddr = priv->mmio_addr;
+
+	/* Clear the MII link change status by reading the MIIStatus register */
+	readl ( ioaddr + NvRegMIIStatus );
+	writel ( NVREG_MIISTAT_LINKCHANGE, ioaddr + NvRegMIIStatus );
+
+	if ( nv_update_linkspeed ( priv ) == 1 )
+		netdev_link_up ( netdev );
+	else
+		netdev_link_down ( netdev );
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void
+forcedeth_poll ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	void *ioaddr = priv->mmio_addr;
+	u32 status;
+
+	DBGP ( "forcedeth_poll\n" );
+
+	status = readl ( ioaddr + NvRegIrqStatus ) & NVREG_IRQSTAT_MASK;
+
+	/* Return when no interrupts have been triggered */
+	if ( ! status )
+		return;
+
+	/* Clear interrupts */
+	writel ( NVREG_IRQSTAT_MASK, ioaddr + NvRegIrqStatus );
+
+	DBG ( "forcedeth_poll: status = %#04x\n", status );
+
+	/* Link change interrupt occured. Call always if link is down,
+	 * to give auto-neg a chance to finish */
+	if ( ( status & NVREG_IRQ_LINK ) || ! ( netdev_link_ok ( netdev ) ) )
+		forcedeth_link_status ( netdev );
+
+	/* Process transmitted packets */
+	nv_process_tx_packets ( netdev );
+
+	/* Process received packets */
+	nv_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev	network interface device structure
+ **/
+static void
+forcedeth_close ( struct net_device *netdev )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+	void *ioaddr = priv->mmio_addr;
+
+	DBGP ( "forcedeth_close\n" );
+
+	nv_stop_rx ( priv );
+	nv_stop_tx ( priv );
+	nv_txrx_reset ( priv );
+
+	/* Disable interrupts on the nic or we will lock up */
+	nv_disable_hw_interrupts ( priv );
+	pci_push ( ioaddr );
+
+	nv_free_rxtx_resources ( priv );
+
+	nv_txrx_gate ( priv, 0 );
+
+	/* FIXME: power down nic */
+}
+
+/**
+ * irq - enable or disable interrupts
+ *
+ * @v netdev    network adapter
+ * @v action    requested interrupt action
+ **/
+static void
+forcedeth_irq ( struct net_device *netdev, int action )
+{
+	struct forcedeth_private *priv = netdev_priv ( netdev );
+
+	DBGP ( "forcedeth_irq\n" );
+
+	switch ( action ) {
+	case 0:
+		nv_disable_hw_interrupts ( priv );
+		break;
+	default:
+		nv_enable_hw_interrupts ( priv );
+		break;
+	}
+}
+
+static struct net_device_operations forcedeth_operations  = {
+	.open		= forcedeth_open,
+	.transmit	= forcedeth_transmit,
+	.poll		= forcedeth_poll,
+	.close		= forcedeth_close,
+	.irq		= forcedeth_irq,
+};
+
+static int
+nv_setup_mac_addr ( struct forcedeth_private *priv )
+{
+	struct net_device *dev = priv->netdev;
+	void *ioaddr = priv->mmio_addr;
+	u32 orig_mac[2];
+	u32 txreg;
+
+	orig_mac[0] = readl ( ioaddr + NvRegMacAddrA );
+	orig_mac[1] = readl ( ioaddr + NvRegMacAddrB );
+
+	txreg = readl ( ioaddr + NvRegTransmitPoll );
+
+	if ( ( priv->driver_data & DEV_HAS_CORRECT_MACADDR ) ||
+	     ( txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV ) ) {
+		/* mac address is already in correct order */
+		dev->hw_addr[0] = ( orig_mac[0] >> 0 ) & 0xff;
+		dev->hw_addr[1] = ( orig_mac[0] >> 8 ) & 0xff;
+		dev->hw_addr[2] = ( orig_mac[0] >> 16 ) & 0xff;
+		dev->hw_addr[3] = ( orig_mac[0] >> 24 ) & 0xff;
+		dev->hw_addr[4] = ( orig_mac[1] >> 0 ) & 0xff;
+		dev->hw_addr[5] = ( orig_mac[1] >> 8 ) & 0xff;
+	} else {
+		/* need to reverse mac address to correct order */
+		dev->hw_addr[0] = ( orig_mac[1] >> 8 ) & 0xff;
+		dev->hw_addr[1] = ( orig_mac[1] >> 0 ) & 0xff;
+		dev->hw_addr[2] = ( orig_mac[0] >> 24 ) & 0xff;
+		dev->hw_addr[3] = ( orig_mac[0] >> 16 ) & 0xff;
+		dev->hw_addr[4] = ( orig_mac[0] >> 8 ) & 0xff;
+		dev->hw_addr[5] = ( orig_mac[0] >> 0 ) & 0xff;
+	}
+
+	if ( ! is_valid_ether_addr ( dev->hw_addr ) )
+		return -EADDRNOTAVAIL;
+
+	DBG ( "MAC address is: %s\n", eth_ntoa ( dev->hw_addr ) );
+
+	return 0;
+}
+
+static int
+nv_mgmt_acquire_sema ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	int i;
+	u32 tx_ctrl, mgmt_sema;
+
+	for ( i = 0; i < 10; i++ ) {
+		mgmt_sema = readl ( ioaddr + NvRegTransmitterControl ) &
+			NVREG_XMITCTL_MGMT_SEMA_MASK;
+		if ( mgmt_sema == NVREG_XMITCTL_MGMT_SEMA_FREE )
+			break;
+		mdelay ( 500 );
+	}
+
+	if ( mgmt_sema != NVREG_XMITCTL_MGMT_SEMA_FREE )
+		return 0;
+
+	for ( i = 0; i < 2; i++ ) {
+		tx_ctrl = readl ( ioaddr + NvRegTransmitterControl );
+		tx_ctrl |= NVREG_XMITCTL_HOST_SEMA_ACQ;
+		writel ( tx_ctrl, ioaddr + NvRegTransmitterControl );
+
+		/* verify that the semaphore was acquired */
+		tx_ctrl = readl ( ioaddr + NvRegTransmitterControl );
+		if ( ( ( tx_ctrl & NVREG_XMITCTL_HOST_SEMA_MASK ) ==
+		       NVREG_XMITCTL_HOST_SEMA_ACQ ) &&
+		     ( ( tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK ) ==
+		       NVREG_XMITCTL_MGMT_SEMA_FREE ) ) {
+			priv->mgmt_sema = 1;
+			return 1;
+		} else {
+			udelay ( 50 );
+		}
+	}
+
+	return 0;
+}
+
+static void
+nv_mgmt_release_sema ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 tx_ctrl;
+
+	if ( priv->driver_data & DEV_HAS_MGMT_UNIT ) {
+		if ( priv->mgmt_sema ) {
+			tx_ctrl = readl (ioaddr + NvRegTransmitterControl );
+			tx_ctrl &= ~NVREG_XMITCTL_HOST_SEMA_ACQ;
+			writel ( tx_ctrl, ioaddr + NvRegTransmitterControl );
+		}
+	}
+}
+
+static int
+nv_mgmt_get_version ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 data_ready = readl ( ioaddr + NvRegTransmitterControl );
+	u32 data_ready2 = 0;
+	unsigned long start;
+	int ready = 0;
+
+	writel ( NVREG_MGMTUNITGETVERSION,
+		ioaddr + NvRegMgmtUnitGetVersion );
+	writel ( data_ready ^ NVREG_XMITCTL_DATA_START,
+		ioaddr + NvRegTransmitterControl );
+	start = currticks();
+
+	while ( currticks() > start + 5 * ticks_per_sec() ) {
+		data_ready2 = readl ( ioaddr + NvRegTransmitterControl );
+		if ( ( data_ready & NVREG_XMITCTL_DATA_READY ) !=
+		     ( data_ready2 & NVREG_XMITCTL_DATA_READY ) ) {
+			ready = 1;
+			break;
+		}
+		mdelay ( 1000 );
+	}
+
+	if ( ! ready || ( data_ready2 & NVREG_XMITCTL_DATA_ERROR ) )
+		return 0;
+
+	priv->mgmt_version =
+		readl ( ioaddr + NvRegMgmtUnitVersion ) & NVREG_MGMTUNITVERSION;
+
+	return 1;
+}
+
+
+
+static int
+phy_reset ( struct forcedeth_private *priv, u32 bmcr_setup )
+{
+	u32 miicontrol;
+	unsigned int tries = 0;
+
+	miicontrol = BMCR_RESET | bmcr_setup;
+	if ( mii_rw ( priv, priv->phyaddr, MII_BMCR, miicontrol ) ) {
+		return -1;
+	}
+
+	mdelay ( 500 );
+
+	/* must wait till reset is deasserted */
+	while ( miicontrol & BMCR_RESET ) {
+		mdelay ( 10 );
+		miicontrol = mii_rw ( priv, priv->phyaddr, MII_BMCR, MII_READ );
+		if ( tries++ > 100 )
+			return -1;
+	}
+	return 0;
+}
+
+static int
+phy_init ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 phyinterface, phy_reserved, mii_status;
+	u32 mii_control, mii_control_1000, reg;
+
+	/* phy errata for E3016 phy */
+	if ( priv->phy_model == PHY_MODEL_MARVELL_E3016 ) {
+		reg = mii_rw ( priv, priv->phyaddr, MII_NCONFIG, MII_READ );
+		reg &= ~PHY_MARVELL_E3016_INITMASK;
+		if ( mii_rw ( priv, priv->phyaddr, MII_NCONFIG, reg ) ) {
+			DBG ( "PHY write to errata reg failed.\n" );
+			return PHY_ERROR;
+		}
+	}
+
+	if ( priv->phy_oui == PHY_OUI_REALTEK ) {
+		if ( priv->phy_model == PHY_MODEL_REALTEK_8211 &&
+		     priv->phy_rev == PHY_REV_REALTEK_8211B ) {
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+		}
+
+		if ( priv->phy_model == PHY_MODEL_REALTEK_8211 &&
+		     priv->phy_rev == PHY_REV_REALTEK_8211C ) {
+			u32 powerstate = readl ( ioaddr + NvRegPowerState2 );
+
+			/* need to perform hw phy reset */
+			powerstate |= NVREG_POWERSTATE2_PHY_RESET;
+			writel ( powerstate , ioaddr + NvRegPowerState2 );
+			mdelay ( 25 );
+
+			powerstate &= ~NVREG_POWERSTATE2_PHY_RESET;
+			writel ( powerstate , ioaddr + NvRegPowerState2 );
+			mdelay ( 25 );
+
+			reg = mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG6, MII_READ );
+			reg |= PHY_REALTEK_INIT9;
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG6, reg ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+
+			reg = mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG7, MII_READ );
+			if ( ! ( reg & PHY_REALTEK_INIT11 ) ) {
+				reg |= PHY_REALTEK_INIT11;
+				if ( mii_rw ( priv, priv->phyaddr,
+					PHY_REALTEK_INIT_REG7, reg ) ) {
+					DBG ( "PHY init failed.\n" );
+					return PHY_ERROR;
+				}
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+		}
+		if ( priv->phy_model == PHY_MODEL_REALTEK_8201 ) {
+			if ( priv->driver_data & DEV_NEED_PHY_INIT_FIX ) {
+				phy_reserved = mii_rw ( priv, priv->phyaddr,
+							PHY_REALTEK_INIT_REG6,
+							MII_READ );
+				phy_reserved |= PHY_REALTEK_INIT7;
+				if ( mii_rw ( priv, priv->phyaddr,
+					      PHY_REALTEK_INIT_REG6,
+					      phy_reserved ) ) {
+					DBG ( "PHY init failed.\n" );
+					return PHY_ERROR;
+				}
+			}
+		}
+	}
+
+	/* set advertise register */
+	reg = mii_rw ( priv, priv->phyaddr, MII_ADVERTISE, MII_READ );
+	reg |= ( ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF |
+		 ADVERTISE_100FULL | ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP );
+	if ( mii_rw ( priv, priv->phyaddr, MII_ADVERTISE, reg ) ) {
+		DBG ( "PHY init failed.\n" );
+		return PHY_ERROR;
+	}
+
+	/* get phy interface type */
+	phyinterface = readl ( ioaddr + NvRegPhyInterface );
+
+	/* see if gigabit phy */
+	mii_status = mii_rw ( priv, priv->phyaddr, MII_BMSR, MII_READ );
+	if ( mii_status & PHY_GIGABIT ) {
+		priv->gigabit = PHY_GIGABIT;
+		mii_control_1000 =
+			mii_rw ( priv, priv->phyaddr, MII_CTRL1000, MII_READ );
+		mii_control_1000 &= ~ADVERTISE_1000HALF;
+		if ( phyinterface & PHY_RGMII )
+			mii_control_1000 |= ADVERTISE_1000FULL;
+		else
+			mii_control_1000 &= ~ADVERTISE_1000FULL;
+
+		if ( mii_rw ( priv, priv->phyaddr, MII_CTRL1000, mii_control_1000)) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+	} else {
+		priv->gigabit = 0;
+	}
+
+	mii_control = mii_rw ( priv, priv->phyaddr, MII_BMCR, MII_READ );
+	mii_control |= BMCR_ANENABLE;
+
+	if ( priv->phy_oui == PHY_OUI_REALTEK &&
+	     priv->phy_model == PHY_MODEL_REALTEK_8211 &&
+	     priv->phy_rev == PHY_REV_REALTEK_8211C ) {
+		/* start autoneg since we already performed hw reset above */
+		mii_control |= BMCR_ANRESTART;
+		if ( mii_rw ( priv, priv->phyaddr, MII_BMCR, mii_control ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+	} else {
+		/* reset the phy
+		 * (certain phys need bmcr to be setup with reset )
+		 */
+		if ( phy_reset ( priv, mii_control ) ) {
+			DBG ( "PHY reset failed\n" );
+			return PHY_ERROR;
+		}
+	}
+
+	/* phy vendor specific configuration */
+	if ( ( priv->phy_oui == PHY_OUI_CICADA ) && ( phyinterface & PHY_RGMII ) ) {
+		phy_reserved = mii_rw ( priv, priv->phyaddr, MII_RESV1, MII_READ );
+		phy_reserved &= ~( PHY_CICADA_INIT1 | PHY_CICADA_INIT2 );
+		phy_reserved |= ( PHY_CICADA_INIT3 | PHY_CICADA_INIT4 );
+		if ( mii_rw ( priv, priv->phyaddr, MII_RESV1, phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr, MII_NCONFIG, MII_READ );
+		phy_reserved |= PHY_CICADA_INIT5;
+		if ( mii_rw ( priv, priv->phyaddr, MII_NCONFIG, phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+	}
+	if ( priv->phy_oui == PHY_OUI_CICADA ) {
+		phy_reserved = mii_rw ( priv, priv->phyaddr, MII_SREVISION, MII_READ );
+		phy_reserved |= PHY_CICADA_INIT6;
+		if ( mii_rw ( priv, priv->phyaddr, MII_SREVISION, phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+	}
+	if ( priv->phy_oui == PHY_OUI_VITESSE ) {
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG1,
+						   PHY_VITESSE_INIT1)) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT2)) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG4, MII_READ);
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG4,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG3, MII_READ);
+		phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+		phy_reserved |= PHY_VITESSE_INIT3;
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG3,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT4 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT5 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG4, MII_READ);
+		phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+		phy_reserved |= PHY_VITESSE_INIT3;
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG4,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG3, MII_READ);
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG3,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT6 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT7 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG4, MII_READ);
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG4,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_VITESSE_INIT_REG3, MII_READ);
+		phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
+		phy_reserved |= PHY_VITESSE_INIT8;
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG3,
+						   phy_reserved ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG2,
+						   PHY_VITESSE_INIT9 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+		if ( mii_rw ( priv, priv->phyaddr, PHY_VITESSE_INIT_REG1,
+						   PHY_VITESSE_INIT10 ) ) {
+			DBG ( "PHY init failed.\n" );
+			return PHY_ERROR;
+		}
+	}
+
+	if ( priv->phy_oui == PHY_OUI_REALTEK ) {
+		if ( priv->phy_model == PHY_MODEL_REALTEK_8211 &&
+		     priv->phy_rev == PHY_REV_REALTEK_8211B ) {
+			/* reset could have cleared these out, set them back */
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+		}
+		if ( priv->phy_model == PHY_MODEL_REALTEK_8201 ) {
+			if ( priv->driver_data & DEV_NEED_PHY_INIT_FIX ) {
+				phy_reserved = mii_rw ( priv, priv->phyaddr,
+							PHY_REALTEK_INIT_REG6,
+							MII_READ );
+				phy_reserved |= PHY_REALTEK_INIT7;
+				if ( mii_rw ( priv, priv->phyaddr,
+					      PHY_REALTEK_INIT_REG6,
+					      phy_reserved ) ) {
+					DBG ( "PHY init failed.\n" );
+					return PHY_ERROR;
+				}
+			}
+
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG1,
+				      PHY_REALTEK_INIT3 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			phy_reserved = mii_rw ( priv, priv->phyaddr,
+						PHY_REALTEK_INIT_REG2,
+						MII_READ );
+			phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
+			phy_reserved |= PHY_REALTEK_INIT3;
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG2,
+				      phy_reserved ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+			if ( mii_rw ( priv, priv->phyaddr,
+				      PHY_REALTEK_INIT_REG1,
+				      PHY_REALTEK_INIT1 ) ) {
+				DBG ( "PHY init failed.\n" );
+				return PHY_ERROR;
+			}
+		}
+	}
+
+	/* some phys clear out pause advertisement on reset, set it back */
+	mii_rw ( priv, priv->phyaddr, MII_ADVERTISE, reg );
+
+	/* restart auto negotiation, power down phy */
+	mii_control = mii_rw ( priv, priv->phyaddr, MII_BMCR, MII_READ );
+	mii_control |= ( BMCR_ANRESTART | BMCR_ANENABLE );
+	if ( mii_rw ( priv, priv->phyaddr, MII_BMCR, mii_control ) ) {
+		return PHY_ERROR;
+	}
+
+	return 0;
+}
+
+/**
+ * nv_setup_phy - Find PHY and initialize it
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Return status code
+ **/
+static int
+nv_setup_phy ( struct forcedeth_private *priv )
+{
+	void *ioaddr = priv->mmio_addr;
+	u32 phystate_orig = 0, phystate;
+	int phyinitialised = 0;
+	u32 powerstate;
+	int rc = 0;
+	int i;
+
+	if ( priv->driver_data & DEV_HAS_POWER_CNTRL ) {
+		/* take phy and nic out of low power mode */
+		powerstate = readl ( ioaddr + NvRegPowerState2 );
+		powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
+		if ( ( priv->driver_data & DEV_NEED_LOW_POWER_FIX ) &&
+		     ( ( priv->pci_dev->class & 0xff ) >= 0xA3 ) )
+			powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
+		writel ( powerstate, ioaddr + NvRegPowerState2 );
+	}
+
+
+	/* clear phy state and temporarily halt phy interrupts */
+	writel ( 0, ioaddr + NvRegMIIMask );
+	phystate = readl ( ioaddr + NvRegAdapterControl );
+	if ( phystate & NVREG_ADAPTCTL_RUNNING ) {
+		phystate_orig = 1;
+		phystate &= ~NVREG_ADAPTCTL_RUNNING;
+		writel ( phystate, ioaddr + NvRegAdapterControl );
+	}
+	writel ( NVREG_MIISTAT_MASK_ALL, ioaddr + NvRegMIIStatus );
+
+	if ( priv->driver_data & DEV_HAS_MGMT_UNIT ) {
+		/* management unit running on the mac? */
+		if ( ( readl ( ioaddr + NvRegTransmitterControl ) & NVREG_XMITCTL_MGMT_ST ) &&
+		     ( readl ( ioaddr + NvRegTransmitterControl ) & NVREG_XMITCTL_SYNC_PHY_INIT ) &&
+		     nv_mgmt_acquire_sema ( priv ) &&
+		     nv_mgmt_get_version ( priv ) ) {
+			priv->mac_in_use = 1;
+			if ( priv->mgmt_version > 0 ) {
+				priv->mac_in_use = readl ( ioaddr + NvRegMgmtUnitControl ) & NVREG_MGMTUNITCONTROL_INUSE;
+			}
+
+			DBG ( "mgmt unit is running. mac in use\n" );
+
+			/* management unit setup the phy already? */
+			if ( priv->mac_in_use &&
+			   ( ( readl ( ioaddr + NvRegTransmitterControl ) & NVREG_XMITCTL_SYNC_MASK ) ==
+			     NVREG_XMITCTL_SYNC_PHY_INIT ) ) {
+				/* phy is inited by mgmt unit */
+				phyinitialised = 1;
+				DBG ( "Phy already initialized by mgmt unit" );
+			}
+		}
+	}
+
+	/* find a suitable phy */
+	for ( i = 1; i <= 32; i++ ) {
+		int id1, id2;
+		int phyaddr = i & 0x1f;
+
+		id1 = mii_rw ( priv, phyaddr, MII_PHYSID1, MII_READ );
+		if ( id1 < 0 || id1 == 0xffff )
+			continue;
+		id2 = mii_rw ( priv, phyaddr, MII_PHYSID2, MII_READ );
+		if ( id2 < 0 || id2 == 0xffff )
+			continue;
+
+		priv->phy_model = id2 & PHYID2_MODEL_MASK;
+		id1 = ( id1 & PHYID1_OUI_MASK ) << PHYID1_OUI_SHFT;
+		id2 = ( id2 & PHYID2_OUI_MASK ) >> PHYID2_OUI_SHFT;
+		DBG ( "Found PHY: %04x:%04x at address %d\n", id1, id2, phyaddr );
+		priv->phyaddr = phyaddr;
+		priv->phy_oui = id1 | id2;
+
+		/* Realtek hardcoded phy id1 to all zeros on certain phys */
+		if ( priv->phy_oui == PHY_OUI_REALTEK2 )
+			priv->phy_oui = PHY_OUI_REALTEK;
+		/* Setup phy revision for Realtek */
+		if ( priv->phy_oui == PHY_OUI_REALTEK &&
+		     priv->phy_model == PHY_MODEL_REALTEK_8211 )
+			priv->phy_rev = mii_rw ( priv, phyaddr, MII_RESV1,
+						 MII_READ ) & PHY_REV_MASK;
+		break;
+	}
+	if ( i == 33 ) {
+		DBG ( "Could not find a valid PHY.\n" );
+		rc = -ENODEV;
+		goto err_phy;
+	}
+
+	if ( ! phyinitialised ) {
+		/* reset it */
+		phy_init ( priv );
+	} else {
+		u32 mii_status = mii_rw ( priv, priv->phyaddr, MII_BMSR, MII_READ );
+		if ( mii_status & PHY_GIGABIT ) {
+			priv->gigabit = PHY_GIGABIT;
+		}
+	}
+
+	return 0;
+
+err_phy:
+	if ( phystate_orig )
+		writel ( phystate | NVREG_ADAPTCTL_RUNNING,
+			 ioaddr + NvRegAdapterControl );
+	return rc;
+}
+
+/**
+ * forcedeth_map_regs - Find a suitable BAR for the NIC and
+ * map the registers in memory
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Return status code
+ **/
+static int
+forcedeth_map_regs ( struct forcedeth_private *priv )
+{
+	void *ioaddr;
+	uint32_t bar;
+	unsigned long addr;
+	u32 register_size;
+	int reg;
+	int rc;
+
+	/* Set register size based on NIC */
+	if ( priv->driver_data & ( DEV_HAS_VLAN | DEV_HAS_MSI_X |
+		DEV_HAS_POWER_CNTRL | DEV_HAS_STATISTICS_V2 |
+		DEV_HAS_STATISTICS_V3 ) ) {
+		register_size = NV_PCI_REGSZ_VER3;
+	} else if ( priv->driver_data & DEV_HAS_STATISTICS_V1 ) {
+		register_size = NV_PCI_REGSZ_VER2;
+	} else {
+		register_size = NV_PCI_REGSZ_VER1;
+	}
+
+	/* Find an appropriate region for all the registers */
+	rc = -EINVAL;
+	addr = 0;
+	for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
+		pci_read_config_dword ( priv->pci_dev, reg, &bar );
+
+		if ( ( ( bar & PCI_BASE_ADDRESS_SPACE ) ==
+			 PCI_BASE_ADDRESS_SPACE_MEMORY ) &&
+		       ( pci_bar_size ( priv->pci_dev, reg ) >=
+			 register_size ) ) {
+			addr = pci_bar_start ( priv->pci_dev, reg );
+			break;
+		}
+	}
+
+	if ( reg > PCI_BASE_ADDRESS_5 ) {
+		DBG ( "Couldn't find register window\n" );
+		goto err_bar_sz;
+	}
+
+	rc = -ENOMEM;
+	ioaddr = ioremap ( addr, register_size );
+	if ( ! ioaddr ) {
+		DBG ( "Cannot remap MMIO\n" );
+		goto err_ioremap;
+	}
+
+	priv->mmio_addr = ioaddr;
+
+	return 0;
+
+err_bar_sz:
+err_ioremap:
+	return rc;
+}
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pdev	PCI device
+ * @v ent	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+static int
+forcedeth_probe ( struct pci_device *pdev )
+{
+	struct net_device *netdev;
+	struct forcedeth_private *priv;
+	void *ioaddr;
+	int rc;
+
+	DBGP ( "forcedeth_probe\n" );
+
+	DBG ( "Found %s, vendor = %#04x, device = %#04x\n",
+	      pdev->id->name, pdev->id->vendor, pdev->id->device );
+
+	/* Allocate our private data */
+	netdev = alloc_etherdev ( sizeof ( *priv ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		DBG ( "Failed to allocate net device\n" );
+		goto err_alloc_etherdev;
+	}
+
+	/* Link our operations to the netdev struct */
+	netdev_init ( netdev, &forcedeth_operations );
+
+	/* Link the PCI device to the netdev struct */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Get a reference to our private data */
+	priv = netdev_priv ( netdev );
+
+	/* We'll need these set up for the rest of the routines */
+	priv->pci_dev = pdev;
+	priv->netdev = netdev;
+	priv->driver_data = pdev->id->driver_data;
+
+	adjust_pci_device ( pdev );
+
+	/* Use memory mapped I/O */
+	if ( ( rc = forcedeth_map_regs ( priv ) ) != 0 )
+		goto err_map_regs;
+	ioaddr = priv->mmio_addr;
+
+	/* Verify and get MAC address */
+	if ( ( rc = nv_setup_mac_addr ( priv ) ) != 0 ) {
+		DBG ( "Invalid MAC address detected\n" );
+		goto err_mac_addr;
+	}
+
+	/* Disable WOL */
+	writel ( 0, ioaddr + NvRegWakeUpFlags );
+
+	if ( ( rc = nv_setup_phy ( priv ) ) != 0 )
+		goto err_setup_phy;
+
+	/* Set Pause Frame parameters */
+	priv->pause_flags = NV_PAUSEFRAME_RX_CAPABLE |
+			    NV_PAUSEFRAME_RX_REQ |
+			    NV_PAUSEFRAME_AUTONEG;
+	if ( ( priv->driver_data & DEV_HAS_PAUSEFRAME_TX_V1 ) ||
+	     ( priv->driver_data & DEV_HAS_PAUSEFRAME_TX_V2 ) ||
+	     ( priv->driver_data & DEV_HAS_PAUSEFRAME_TX_V3 ) ) {
+		priv->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ;
+	}
+
+	if ( priv->pause_flags & NV_PAUSEFRAME_TX_CAPABLE )
+		writel ( NVREG_TX_PAUSEFRAME_DISABLE, ioaddr + NvRegTxPauseFrame );
+
+	/* Set default link speed settings */
+	priv->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+	priv->duplex = 0;
+
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBG ( "Error registering netdev\n" );
+		goto err_register_netdev;
+	}
+
+	forcedeth_link_status ( netdev );
+
+	return 0;
+
+err_register_netdev:
+err_setup_phy:
+err_mac_addr:
+	iounmap ( priv->mmio_addr );
+err_map_regs:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return rc;
+}
+
+static void
+nv_restore_phy ( struct forcedeth_private *priv )
+{
+	u16 phy_reserved, mii_control;
+
+	if ( priv->phy_oui == PHY_OUI_REALTEK &&
+	     priv->phy_model == PHY_MODEL_REALTEK_8201 ) {
+		mii_rw ( priv, priv->phyaddr, PHY_REALTEK_INIT_REG1,
+					      PHY_REALTEK_INIT3 );
+		phy_reserved = mii_rw ( priv, priv->phyaddr,
+					PHY_REALTEK_INIT_REG2, MII_READ );
+		phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
+		phy_reserved |= PHY_REALTEK_INIT8;
+		mii_rw ( priv, priv->phyaddr, PHY_REALTEK_INIT_REG2,
+					      phy_reserved );
+		mii_rw ( priv, priv->phyaddr, PHY_REALTEK_INIT_REG1,
+					      PHY_REALTEK_INIT1 );
+
+		/* restart auto negotiation */
+		mii_control = mii_rw ( priv, priv->phyaddr, MII_BMCR, MII_READ );
+		mii_control |= ( BMCR_ANRESTART | BMCR_ANENABLE );
+		mii_rw ( priv, priv->phyaddr, MII_BMCR, mii_control );
+	}
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ **/
+static void
+forcedeth_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct forcedeth_private *priv = netdev->priv;
+
+	DBGP ( "forcedeth_remove\n" );
+
+	unregister_netdev ( netdev );
+
+	nv_restore_phy ( priv );
+
+	nv_mgmt_release_sema ( priv );
+
+	iounmap ( priv->mmio_addr );
+
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id forcedeth_nics[] = {
+	PCI_ROM(0x10DE, 0x01C3, "nForce", "nForce Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER),
+	PCI_ROM(0x10DE, 0x0066, "nForce2", "nForce2 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER),
+	PCI_ROM(0x10DE, 0x00D6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER),
+	PCI_ROM(0x10DE, 0x0086, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM),
+	PCI_ROM(0x10DE, 0x008C, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM),
+	PCI_ROM(0x10DE, 0x00E6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM),
+	PCI_ROM(0x10DE, 0x00DF, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM),
+	PCI_ROM(0x10DE, 0x0056, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT),
+	PCI_ROM(0x10DE, 0x0057, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT),
+	PCI_ROM(0x10DE, 0x0037, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT),
+	PCI_ROM(0x10DE, 0x0038, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT),
+	PCI_ROM(0x10DE, 0x0268, "MCP51", "MCP51 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX),
+	PCI_ROM(0x10DE, 0x0269, "MCP51", "MCP51 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX),
+	PCI_ROM(0x10DE, 0x0372, "MCP55", "MCP55 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X| DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED| DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0373, "MCP55", "MCP55 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X| DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x03E5, "MCP61", "MCP61 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x03E6, "MCP61", "MCP61 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x03EE, "MCP61", "MCP61 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x03EF, "MCP61", "MCP61 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0450, "MCP65", "MCP65 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA| DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0451, "MCP65", "MCP65 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA| DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0452, "MCP65", "MCP65 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA| DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0453, "MCP65", "MCP65 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA| DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x054C, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x054D, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x054E, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x054F, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x07DC, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x07DD, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x07DE, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x07DF, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0760, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0761, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0762, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0763, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0AB0, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0AB1, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0AB2, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0AB3, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX),
+	PCI_ROM(0x10DE, 0x0D7D, "MCP89", "MCP89 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX),
+};
+
+struct pci_driver forcedeth_driver __pci_driver = {
+	.ids		= forcedeth_nics,
+	.id_count	= ARRAY_SIZE(forcedeth_nics),
+	.probe		= forcedeth_probe,
+	.remove		= forcedeth_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.h
new file mode 100644
index 0000000..70686d1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/forcedeth.h
@@ -0,0 +1,601 @@
+/*
+ *    forcedeth.h -- Driver for NVIDIA nForce media access controllers for iPXE
+ *    Copyright (c) 2010 Andrei Faur <da3drus at gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License as
+ *    published by the Free Software Foundation; either version 2 of the
+ *    License, or any later version.
+ *
+ *    This program is distributed in the hope that it will be useful, but
+ *    WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Portions of this code are taken from the Linux forcedeth driver that was
+ * based on a cleanroom reimplementation which was based on reverse engineered
+ * documentation written by Carl-Daniel Hailfinger and Andrew de Quincey:
+ * Copyright (C) 2003,4,5 Manfred Spraul
+ * Copyright (C) 2004 Andrew de Quincey (wol support)
+ * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
+ *		IRQ rate fixes, bigendian fixes, cleanups, verification)
+ * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation
+ *
+ * This header is a direct copy of #define lines and structs found in the
+ * above mentioned driver, modified where necessary to make them work for iPXE.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _FORCEDETH_H_
+#define _FORCEDETH_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+struct ring_desc {
+	u32 buf;
+	u32 flaglen;
+};
+
+struct ring_desc_ex {
+	u32 bufhigh;
+	u32 buflow;
+	u32 txvlan;
+	u32 flaglen;
+};
+
+#define DESC_VER_1	1
+#define DESC_VER_2	2
+#define DESC_VER_3	3
+
+#define RX_RING_SIZE		16
+#define TX_RING_SIZE		16
+#define RXTX_RING_SIZE		( ( RX_RING_SIZE ) + ( TX_RING_SIZE ) )
+#define RX_RING_MIN		128
+#define TX_RING_MIN		64
+#define RING_MAX_DESC_VER_1	1024
+#define RING_MAX_DESC_VER_2_3	16384
+
+#define NV_RX_ALLOC_PAD	(64)
+
+#define NV_RX_HEADERS	(64)
+
+#define RX_BUF_SZ		( ( ETH_FRAME_LEN ) + ( NV_RX_HEADERS ) )
+
+#define NV_PKTLIMIT_1	1500
+#define NV_PKTLIMIT_2	9100
+
+#define NV_LINK_POLL_FREQUENCY	128
+
+/* PHY defines */
+#define PHY_OUI_MARVELL		0x5043
+#define PHY_OUI_CICADA		0x03f1
+#define PHY_OUI_VITESSE		0x01c1
+#define PHY_OUI_REALTEK		0x0732
+#define PHY_OUI_REALTEK2	0x0020
+#define PHYID1_OUI_MASK	0x03ff
+#define PHYID1_OUI_SHFT	6
+#define PHYID2_OUI_MASK	0xfc00
+#define PHYID2_OUI_SHFT	10
+#define PHYID2_MODEL_MASK		0x03f0
+#define PHY_MODEL_REALTEK_8211		0x0110
+#define PHY_REV_MASK			0x0001
+#define PHY_REV_REALTEK_8211B		0x0000
+#define PHY_REV_REALTEK_8211C		0x0001
+#define PHY_MODEL_REALTEK_8201		0x0200
+#define PHY_MODEL_MARVELL_E3016		0x0220
+#define PHY_MARVELL_E3016_INITMASK	0x0300
+#define PHY_CICADA_INIT1	0x0f000
+#define PHY_CICADA_INIT2	0x0e00
+#define PHY_CICADA_INIT3	0x01000
+#define PHY_CICADA_INIT4	0x0200
+#define PHY_CICADA_INIT5	0x0004
+#define PHY_CICADA_INIT6	0x02000
+#define PHY_VITESSE_INIT_REG1	0x1f
+#define PHY_VITESSE_INIT_REG2	0x10
+#define PHY_VITESSE_INIT_REG3	0x11
+#define PHY_VITESSE_INIT_REG4	0x12
+#define PHY_VITESSE_INIT_MSK1	0xc
+#define PHY_VITESSE_INIT_MSK2	0x0180
+#define PHY_VITESSE_INIT1	0x52b5
+#define PHY_VITESSE_INIT2	0xaf8a
+#define PHY_VITESSE_INIT3	0x8
+#define PHY_VITESSE_INIT4	0x8f8a
+#define PHY_VITESSE_INIT5	0xaf86
+#define PHY_VITESSE_INIT6	0x8f86
+#define PHY_VITESSE_INIT7	0xaf82
+#define PHY_VITESSE_INIT8	0x0100
+#define PHY_VITESSE_INIT9	0x8f82
+#define PHY_VITESSE_INIT10	0x0
+#define PHY_REALTEK_INIT_REG1	0x1f
+#define PHY_REALTEK_INIT_REG2	0x19
+#define PHY_REALTEK_INIT_REG3	0x13
+#define PHY_REALTEK_INIT_REG4	0x14
+#define PHY_REALTEK_INIT_REG5	0x18
+#define PHY_REALTEK_INIT_REG6	0x11
+#define PHY_REALTEK_INIT_REG7	0x01
+#define PHY_REALTEK_INIT1	0x0000
+#define PHY_REALTEK_INIT2	0x8e00
+#define PHY_REALTEK_INIT3	0x0001
+#define PHY_REALTEK_INIT4	0xad17
+#define PHY_REALTEK_INIT5	0xfb54
+#define PHY_REALTEK_INIT6	0xf5c7
+#define PHY_REALTEK_INIT7	0x1000
+#define PHY_REALTEK_INIT8	0x0003
+#define PHY_REALTEK_INIT9	0x0008
+#define PHY_REALTEK_INIT10	0x0005
+#define PHY_REALTEK_INIT11	0x0200
+#define PHY_REALTEK_INIT_MSK1	0x0003
+
+#define PHY_GIGABIT	0x0100
+
+#define PHY_TIMEOUT	0x1
+#define PHY_ERROR	0x2
+
+#define PHY_100	0x1
+#define PHY_1000	0x2
+#define PHY_HALF	0x100
+
+
+#define NV_PAUSEFRAME_RX_CAPABLE	0x0001
+#define NV_PAUSEFRAME_TX_CAPABLE	0x0002
+#define NV_PAUSEFRAME_RX_ENABLE		0x0004
+#define NV_PAUSEFRAME_TX_ENABLE		0x0008
+#define NV_PAUSEFRAME_RX_REQ		0x0010
+#define NV_PAUSEFRAME_TX_REQ		0x0020
+#define NV_PAUSEFRAME_AUTONEG		0x0040
+
+/* MSI/MSI-X defines */
+#define NV_MSI_X_MAX_VECTORS  8
+#define NV_MSI_X_VECTORS_MASK 0x000f
+#define NV_MSI_CAPABLE        0x0010
+#define NV_MSI_X_CAPABLE      0x0020
+#define NV_MSI_ENABLED        0x0040
+#define NV_MSI_X_ENABLED      0x0080
+
+#define NV_MSI_X_VECTOR_ALL   0x0
+#define NV_MSI_X_VECTOR_RX    0x0
+#define NV_MSI_X_VECTOR_TX    0x1
+#define NV_MSI_X_VECTOR_OTHER 0x2
+
+#define NV_MSI_PRIV_OFFSET 0x68
+#define NV_MSI_PRIV_VALUE  0xffffffff
+
+
+#define NV_MIIBUSY_DELAY	50
+#define NV_MIIPHY_DELAY		10
+#define NV_MIIPHY_DELAYMAX	10000
+
+/* Hardware access */
+#define DEV_NEED_TIMERIRQ          0x0000001  /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER         0x0000002  /* poll link settings. Relies on the timer irq */
+#define DEV_HAS_LARGEDESC          0x0000004  /* device supports jumbo frames and needs packet format 2 */
+#define DEV_HAS_HIGH_DMA           0x0000008  /* device supports 64bit dma */
+#define DEV_HAS_CHECKSUM           0x0000010  /* device supports tx and rx checksum offloads */
+#define DEV_HAS_VLAN               0x0000020  /* device supports vlan tagging and striping */
+#define DEV_HAS_MSI                0x0000040  /* device supports MSI */
+#define DEV_HAS_MSI_X              0x0000080  /* device supports MSI-X */
+#define DEV_HAS_POWER_CNTRL        0x0000100  /* device supports power savings */
+#define DEV_HAS_STATISTICS_V1      0x0000200  /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2      0x0000600  /* device supports hw statistics version 2 */
+#define DEV_HAS_STATISTICS_V3      0x0000e00  /* device supports hw statistics version 3 */
+#define DEV_HAS_TEST_EXTENDED      0x0001000  /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT          0x0002000  /* device supports management unit */
+#define DEV_HAS_CORRECT_MACADDR    0x0004000  /* device supports correct mac address order */
+#define DEV_HAS_COLLISION_FIX      0x0008000  /* device supports tx collision fix */
+#define DEV_HAS_PAUSEFRAME_TX_V1   0x0010000  /* device supports tx pause frames version 1 */
+#define DEV_HAS_PAUSEFRAME_TX_V2   0x0020000  /* device supports tx pause frames version 2 */
+#define DEV_HAS_PAUSEFRAME_TX_V3   0x0040000  /* device supports tx pause frames version 3 */
+#define DEV_NEED_TX_LIMIT          0x0080000  /* device needs to limit tx */
+#define DEV_NEED_TX_LIMIT2         0x0180000  /* device needs to limit tx, expect for some revs */
+#define DEV_HAS_GEAR_MODE          0x0200000  /* device supports gear mode */
+#define DEV_NEED_PHY_INIT_FIX      0x0400000  /* device needs specific phy workaround */
+#define DEV_NEED_LOW_POWER_FIX     0x0800000  /* device needs special power up workaround */
+#define DEV_NEED_MSI_FIX           0x1000000  /* device needs msi workaround */
+
+#define FLAG_MASK_V1 0xffff0000
+#define FLAG_MASK_V2 0xffffc000
+#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
+#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)
+
+#define NV_TX_LASTPACKET	(1<<16)
+#define NV_TX_RETRYERROR	(1<<19)
+#define NV_TX_RETRYCOUNT_MASK	(0xF<<20)
+#define NV_TX_FORCED_INTERRUPT	(1<<24)
+#define NV_TX_DEFERRED		(1<<26)
+#define NV_TX_CARRIERLOST	(1<<27)
+#define NV_TX_LATECOLLISION	(1<<28)
+#define NV_TX_UNDERFLOW		(1<<29)
+#define NV_TX_ERROR		(1<<30)
+#define NV_TX_VALID		(1<<31)
+
+#define NV_TX2_LASTPACKET	(1<<29)
+#define NV_TX2_RETRYERROR	(1<<18)
+#define NV_TX2_RETRYCOUNT_MASK	(0xF<<19)
+#define NV_TX2_FORCED_INTERRUPT	(1<<30)
+#define NV_TX2_DEFERRED		(1<<25)
+#define NV_TX2_CARRIERLOST	(1<<26)
+#define NV_TX2_LATECOLLISION	(1<<27)
+#define NV_TX2_UNDERFLOW	(1<<28)
+/* error and valid are the same for both */
+#define NV_TX2_ERROR		(1<<30)
+#define NV_TX2_VALID		(1<<31)
+#define NV_TX2_TSO		(1<<28)
+#define NV_TX2_TSO_SHIFT	14
+#define NV_TX2_TSO_MAX_SHIFT	14
+#define NV_TX2_TSO_MAX_SIZE	(1<<NV_TX2_TSO_MAX_SHIFT)
+#define NV_TX2_CHECKSUM_L3	(1<<27)
+#define NV_TX2_CHECKSUM_L4	(1<<26)
+
+#define NV_TX3_VLAN_TAG_PRESENT (1<<18)
+
+#define NV_RX_DESCRIPTORVALID	(1<<16)
+#define NV_RX_MISSEDFRAME	(1<<17)
+#define NV_RX_SUBSTRACT1	(1<<18)
+#define NV_RX_ERROR1		(1<<23)
+#define NV_RX_ERROR2		(1<<24)
+#define NV_RX_ERROR3		(1<<25)
+#define NV_RX_ERROR4		(1<<26)
+#define NV_RX_CRCERR		(1<<27)
+#define NV_RX_OVERFLOW		(1<<28)
+#define NV_RX_FRAMINGERR	(1<<29)
+#define NV_RX_ERROR		(1<<30)
+#define NV_RX_AVAIL		(1<<31)
+#define NV_RX_ERROR_MASK	(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4|NV_RX_CRCERR|NV_RX_OVERFLOW|NV_RX_FRAMINGERR)
+
+#define NV_RX2_CHECKSUMMASK	(0x1C000000)
+#define NV_RX2_CHECKSUM_IP	(0x10000000)
+#define NV_RX2_CHECKSUM_IP_TCP	(0x14000000)
+#define NV_RX2_CHECKSUM_IP_UDP	(0x18000000)
+#define NV_RX2_DESCRIPTORVALID	(1<<29)
+#define NV_RX2_SUBSTRACT1	(1<<25)
+#define NV_RX2_ERROR1		(1<<18)
+#define NV_RX2_ERROR2		(1<<19)
+#define NV_RX2_ERROR3		(1<<20)
+#define NV_RX2_ERROR4		(1<<21)
+#define NV_RX2_CRCERR		(1<<22)
+#define NV_RX2_OVERFLOW		(1<<23)
+#define NV_RX2_FRAMINGERR	(1<<24)
+/* error and avail are the same for both */
+#define NV_RX2_ERROR		(1<<30)
+#define NV_RX2_AVAIL		(1<<31)
+#define NV_RX2_ERROR_MASK	(NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4|NV_RX2_CRCERR|NV_RX2_OVERFLOW|NV_RX2_FRAMINGERR)
+
+#define NV_RX3_VLAN_TAG_PRESENT (1<<16)
+#define NV_RX3_VLAN_TAG_MASK	(0x0000FFFF)
+
+/* Miscellaneous hardware related defines */
+#define NV_PCI_REGSZ_VER1	0x270
+#define NV_PCI_REGSZ_VER2	0x2d4
+#define NV_PCI_REGSZ_VER3	0x604
+#define NV_PCI_REGSZ_MAX	0x604
+
+/* various timeout delays: all in usec */
+#define NV_TXRX_RESET_DELAY	4
+#define NV_TXSTOP_DELAY1	10
+#define NV_TXSTOP_DELAY1MAX	500000
+#define NV_TXSTOP_DELAY2	100
+#define NV_RXSTOP_DELAY1	10
+#define NV_RXSTOP_DELAY1MAX	500000
+#define NV_RXSTOP_DELAY2	100
+#define NV_SETUP5_DELAY		5
+#define NV_SETUP5_DELAYMAX	50000
+#define NV_POWERUP_DELAY	5
+#define NV_POWERUP_DELAYMAX	5000
+#define NV_MIIBUSY_DELAY	50
+#define NV_MIIPHY_DELAY	10
+#define NV_MIIPHY_DELAYMAX	10000
+#define NV_MAC_RESET_DELAY	64
+
+#define NV_MSI_X_CAPABLE	0x0020
+
+#define MII_READ	(-1)
+
+struct forcedeth_private {
+	struct pci_device *pci_dev;
+	struct net_device *netdev;
+
+	void *mmio_addr;
+
+	u32 linkspeed;
+	int duplex;
+
+	int phyaddr;
+	unsigned int phy_oui;
+	unsigned int phy_rev;
+	unsigned int phy_model;
+
+	u16 gigabit;
+	u32 mac_in_use;
+	int mgmt_version;
+	int mgmt_sema;
+
+	/* rx specific fields */
+	struct ring_desc *rx_ring;
+	struct io_buffer *rx_iobuf[RX_RING_SIZE];
+	int rx_curr;
+
+	/* tx specific fields */
+	struct ring_desc *tx_ring;
+	struct io_buffer *tx_iobuf[TX_RING_SIZE];
+	int tx_fill_ctr;
+	int tx_curr;
+	int tx_tail;
+
+	/* flow control */
+	u32 pause_flags;
+
+	unsigned long driver_data;
+};
+
+enum {
+	NvRegIrqStatus = 0x000,
+#define NVREG_IRQSTAT_MIIEVENT	0x040
+#define NVREG_IRQSTAT_MASK		0x83ff
+	NvRegIrqMask = 0x004,
+#define NVREG_IRQ_RX_ERROR		0x0001
+#define NVREG_IRQ_RX			0x0002
+#define NVREG_IRQ_RX_NOBUF		0x0004
+#define NVREG_IRQ_TX_ERR		0x0008
+#define NVREG_IRQ_TX_OK			0x0010
+#define NVREG_IRQ_TIMER			0x0020
+#define NVREG_IRQ_LINK			0x0040
+#define NVREG_IRQ_RX_FORCED		0x0080
+#define NVREG_IRQ_TX_FORCED		0x0100
+#define NVREG_IRQ_RECOVER_ERROR		0x8200
+#define NVREG_IRQMASK_THROUGHPUT	0x00df
+#define NVREG_IRQMASK_CPU		0x0060
+#define NVREG_IRQ_TX_ALL		(NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED)
+#define NVREG_IRQ_RX_ALL		(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED)
+#define NVREG_IRQ_OTHER			(NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR)
+
+	NvRegUnknownSetupReg6 = 0x008,
+#define NVREG_UNKSETUP6_VAL		3
+
+/*
+ * NVREG_POLL_DEFAULT is the interval length of the timer source on the nic
+ * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
+ */
+	NvRegPollingInterval = 0x00c,
+#define NVREG_POLL_DEFAULT_THROUGHPUT	65535 /* backup tx cleanup if loop max reached */
+#define NVREG_POLL_DEFAULT_CPU	13
+	NvRegMSIMap0 = 0x020,
+	NvRegMSIMap1 = 0x024,
+	NvRegMSIIrqMask = 0x030,
+#define NVREG_MSI_VECTOR_0_ENABLED 0x01
+	NvRegMisc1 = 0x080,
+#define NVREG_MISC1_PAUSE_TX	0x01
+#define NVREG_MISC1_HD		0x02
+#define NVREG_MISC1_FORCE	0x3b0f3c
+
+	NvRegMacReset = 0x34,
+#define NVREG_MAC_RESET_ASSERT	0x0F3
+	NvRegTransmitterControl = 0x084,
+#define NVREG_XMITCTL_START	0x01
+#define NVREG_XMITCTL_MGMT_ST	0x40000000
+#define NVREG_XMITCTL_SYNC_MASK		0x000f0000
+#define NVREG_XMITCTL_SYNC_NOT_READY	0x0
+#define NVREG_XMITCTL_SYNC_PHY_INIT	0x00040000
+#define NVREG_XMITCTL_MGMT_SEMA_MASK	0x00000f00
+#define NVREG_XMITCTL_MGMT_SEMA_FREE	0x0
+#define NVREG_XMITCTL_HOST_SEMA_MASK	0x0000f000
+#define NVREG_XMITCTL_HOST_SEMA_ACQ	0x0000f000
+#define NVREG_XMITCTL_HOST_LOADED	0x00004000
+#define NVREG_XMITCTL_TX_PATH_EN	0x01000000
+#define NVREG_XMITCTL_DATA_START	0x00100000
+#define NVREG_XMITCTL_DATA_READY	0x00010000
+#define NVREG_XMITCTL_DATA_ERROR	0x00020000
+	NvRegTransmitterStatus = 0x088,
+#define NVREG_XMITSTAT_BUSY	0x01
+
+	NvRegPacketFilterFlags = 0x8c,
+#define NVREG_PFF_PAUSE_RX	0x08
+#define NVREG_PFF_ALWAYS	0x7F0000
+#define NVREG_PFF_PROMISC	0x80
+#define NVREG_PFF_MYADDR	0x20
+#define NVREG_PFF_LOOPBACK	0x10
+
+	NvRegOffloadConfig = 0x90,
+#define NVREG_OFFLOAD_HOMEPHY	0x601
+#define NVREG_OFFLOAD_NORMAL	RX_NIC_BUFSIZE
+	NvRegReceiverControl = 0x094,
+#define NVREG_RCVCTL_START	0x01
+#define NVREG_RCVCTL_RX_PATH_EN	0x01000000
+	NvRegReceiverStatus = 0x98,
+#define NVREG_RCVSTAT_BUSY	0x01
+
+	NvRegSlotTime = 0x9c,
+#define NVREG_SLOTTIME_LEGBF_ENABLED	0x80000000
+#define NVREG_SLOTTIME_10_100_FULL	0x00007f00
+#define NVREG_SLOTTIME_1000_FULL 	0x0003ff00
+#define NVREG_SLOTTIME_HALF		0x0000ff00
+#define NVREG_SLOTTIME_DEFAULT	 	0x00007f00
+#define NVREG_SLOTTIME_MASK		0x000000ff
+
+	NvRegTxDeferral = 0xA0,
+#define NVREG_TX_DEFERRAL_DEFAULT		0x15050f
+#define NVREG_TX_DEFERRAL_RGMII_10_100		0x16070f
+#define NVREG_TX_DEFERRAL_RGMII_1000		0x14050f
+#define NVREG_TX_DEFERRAL_RGMII_STRETCH_10	0x16190f
+#define NVREG_TX_DEFERRAL_RGMII_STRETCH_100	0x16300f
+#define NVREG_TX_DEFERRAL_MII_STRETCH		0x152000
+	NvRegRxDeferral = 0xA4,
+#define NVREG_RX_DEFERRAL_DEFAULT	0x16
+	NvRegMacAddrA = 0xA8,
+	NvRegMacAddrB = 0xAC,
+	NvRegMulticastAddrA = 0xB0,
+#define NVREG_MCASTADDRA_FORCE	0x01
+	NvRegMulticastAddrB = 0xB4,
+	NvRegMulticastMaskA = 0xB8,
+#define NVREG_MCASTMASKA_NONE		0xffffffff
+	NvRegMulticastMaskB = 0xBC,
+#define NVREG_MCASTMASKB_NONE		0xffff
+
+	NvRegPhyInterface = 0xC0,
+#define PHY_RGMII		0x10000000
+	NvRegBackOffControl = 0xC4,
+#define NVREG_BKOFFCTRL_DEFAULT			0x70000000
+#define NVREG_BKOFFCTRL_SEED_MASK		0x000003ff
+#define NVREG_BKOFFCTRL_SELECT			24
+#define NVREG_BKOFFCTRL_GEAR			12
+
+	NvRegTxRingPhysAddr = 0x100,
+	NvRegRxRingPhysAddr = 0x104,
+	NvRegRingSizes = 0x108,
+#define NVREG_RINGSZ_TXSHIFT 0
+#define NVREG_RINGSZ_RXSHIFT 16
+	NvRegTransmitPoll = 0x10c,
+#define NVREG_TRANSMITPOLL_MAC_ADDR_REV	0x00008000
+	NvRegLinkSpeed = 0x110,
+#define NVREG_LINKSPEED_FORCE 0x10000
+#define NVREG_LINKSPEED_10	1000
+#define NVREG_LINKSPEED_100	100
+#define NVREG_LINKSPEED_1000	50
+#define NVREG_LINKSPEED_MASK	(0xFFF)
+	NvRegUnknownSetupReg5 = 0x130,
+#define NVREG_UNKSETUP5_BIT31	(1<<31)
+	NvRegTxWatermark = 0x13c,
+#define NVREG_TX_WM_DESC1_DEFAULT	0x0200010
+#define NVREG_TX_WM_DESC2_3_DEFAULT	0x1e08000
+#define NVREG_TX_WM_DESC2_3_1000	0xfe08000
+	NvRegTxRxControl = 0x144,
+#define NVREG_TXRXCTL_KICK	0x0001
+#define NVREG_TXRXCTL_BIT1	0x0002
+#define NVREG_TXRXCTL_BIT2	0x0004
+#define NVREG_TXRXCTL_IDLE	0x0008
+#define NVREG_TXRXCTL_RESET	0x0010
+#define NVREG_TXRXCTL_RXCHECK	0x0400
+#define NVREG_TXRXCTL_DESC_1	0
+#define NVREG_TXRXCTL_DESC_2	0x002100
+#define NVREG_TXRXCTL_DESC_3	0xc02200
+#define NVREG_TXRXCTL_VLANSTRIP 0x00040
+#define NVREG_TXRXCTL_VLANINS	0x00080
+	NvRegTxRingPhysAddrHigh = 0x148,
+	NvRegRxRingPhysAddrHigh = 0x14C,
+	NvRegTxPauseFrame = 0x170,
+#define NVREG_TX_PAUSEFRAME_DISABLE	0x0fff0080
+#define NVREG_TX_PAUSEFRAME_ENABLE_V1	0x01800010
+#define NVREG_TX_PAUSEFRAME_ENABLE_V2	0x056003f0
+#define NVREG_TX_PAUSEFRAME_ENABLE_V3	0x09f00880
+	NvRegTxPauseFrameLimit = 0x174,
+#define NVREG_TX_PAUSEFRAMELIMIT_ENABLE	0x00010000
+	NvRegMIIStatus = 0x180,
+#define NVREG_MIISTAT_ERROR		0x0001
+#define NVREG_MIISTAT_LINKCHANGE	0x0008
+#define NVREG_MIISTAT_MASK_RW		0x0007
+#define NVREG_MIISTAT_MASK_ALL		0x000f
+	NvRegMIIMask = 0x184,
+#define NVREG_MII_LINKCHANGE		0x0008
+
+	NvRegAdapterControl = 0x188,
+#define NVREG_ADAPTCTL_START	0x02
+#define NVREG_ADAPTCTL_LINKUP	0x04
+#define NVREG_ADAPTCTL_PHYVALID	0x40000
+#define NVREG_ADAPTCTL_RUNNING	0x100000
+#define NVREG_ADAPTCTL_PHYSHIFT	24
+	NvRegMIISpeed = 0x18c,
+#define NVREG_MIISPEED_BIT8	(1<<8)
+#define NVREG_MIIDELAY	5
+	NvRegMIIControl = 0x190,
+#define NVREG_MIICTL_INUSE	0x08000
+#define NVREG_MIICTL_WRITE	0x00400
+#define NVREG_MIICTL_ADDRSHIFT	5
+	NvRegMIIData = 0x194,
+	NvRegTxUnicast = 0x1a0,
+	NvRegTxMulticast = 0x1a4,
+	NvRegTxBroadcast = 0x1a8,
+	NvRegWakeUpFlags = 0x200,
+#define NVREG_WAKEUPFLAGS_VAL		0x7770
+#define NVREG_WAKEUPFLAGS_BUSYSHIFT	24
+#define NVREG_WAKEUPFLAGS_ENABLESHIFT	16
+#define NVREG_WAKEUPFLAGS_D3SHIFT	12
+#define NVREG_WAKEUPFLAGS_D2SHIFT	8
+#define NVREG_WAKEUPFLAGS_D1SHIFT	4
+#define NVREG_WAKEUPFLAGS_D0SHIFT	0
+#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT		0x01
+#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT	0x02
+#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE	0x04
+#define NVREG_WAKEUPFLAGS_ENABLE	0x1111
+
+	NvRegMgmtUnitGetVersion = 0x204,
+#define NVREG_MGMTUNITGETVERSION     	0x01
+	NvRegMgmtUnitVersion = 0x208,
+#define NVREG_MGMTUNITVERSION		0x08
+	NvRegPowerCap = 0x268,
+#define NVREG_POWERCAP_D3SUPP	(1<<30)
+#define NVREG_POWERCAP_D2SUPP	(1<<26)
+#define NVREG_POWERCAP_D1SUPP	(1<<25)
+	NvRegPowerState = 0x26c,
+#define NVREG_POWERSTATE_POWEREDUP	0x8000
+#define NVREG_POWERSTATE_VALID		0x0100
+#define NVREG_POWERSTATE_MASK		0x0003
+#define NVREG_POWERSTATE_D0		0x0000
+#define NVREG_POWERSTATE_D1		0x0001
+#define NVREG_POWERSTATE_D2		0x0002
+#define NVREG_POWERSTATE_D3		0x0003
+	NvRegMgmtUnitControl = 0x278,
+#define NVREG_MGMTUNITCONTROL_INUSE	0x20000
+	NvRegTxCnt = 0x280,
+	NvRegTxZeroReXmt = 0x284,
+	NvRegTxOneReXmt = 0x288,
+	NvRegTxManyReXmt = 0x28c,
+	NvRegTxLateCol = 0x290,
+	NvRegTxUnderflow = 0x294,
+	NvRegTxLossCarrier = 0x298,
+	NvRegTxExcessDef = 0x29c,
+	NvRegTxRetryErr = 0x2a0,
+	NvRegRxFrameErr = 0x2a4,
+	NvRegRxExtraByte = 0x2a8,
+	NvRegRxLateCol = 0x2ac,
+	NvRegRxRunt = 0x2b0,
+	NvRegRxFrameTooLong = 0x2b4,
+	NvRegRxOverflow = 0x2b8,
+	NvRegRxFCSErr = 0x2bc,
+	NvRegRxFrameAlignErr = 0x2c0,
+	NvRegRxLenErr = 0x2c4,
+	NvRegRxUnicast = 0x2c8,
+	NvRegRxMulticast = 0x2cc,
+	NvRegRxBroadcast = 0x2d0,
+	NvRegTxDef = 0x2d4,
+	NvRegTxFrame = 0x2d8,
+	NvRegRxCnt = 0x2dc,
+	NvRegTxPause = 0x2e0,
+	NvRegRxPause = 0x2e4,
+	NvRegRxDropFrame = 0x2e8,
+	NvRegVlanControl = 0x300,
+#define NVREG_VLANCONTROL_ENABLE	0x2000
+	NvRegMSIXMap0 = 0x3e0,
+	NvRegMSIXMap1 = 0x3e4,
+	NvRegMSIXIrqStatus = 0x3f0,
+
+	NvRegPowerState2 = 0x600,
+#define NVREG_POWERSTATE2_POWERUP_MASK		0x0F15
+#define NVREG_POWERSTATE2_POWERUP_REV_A3	0x0001
+#define NVREG_POWERSTATE2_PHY_RESET		0x0004
+#define NVREG_POWERSTATE2_GATE_CLOCKS		0x0F00
+};
+
+enum {
+	NV_OPTIMIZATION_MODE_THROUGHPUT,
+	NV_OPTIMIZATION_MODE_CPU,
+	NV_OPTIMIZATION_MODE_DYNAMIC
+};
+
+enum {
+	NV_CROSSOVER_DETECTION_DISABLED,
+	NV_CROSSOVER_DETECTION_ENABLED
+};
+
+
+#define NV_SETUP_RX_RING	0x01
+#define NV_SETUP_TX_RING	0x02
+
+#define NV_RESTART_TX		0x1
+#define NV_RESTART_RX		0x2
+
+#endif /* _FORCEDETH_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/hfa384x.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/hfa384x.h
new file mode 100644
index 0000000..2e3ccf5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/hfa384x.h
@@ -0,0 +1,3069 @@
+/* src/prism2/include/prism2/hfa384x.h
+*
+* Defines the constants and data structures for the hfa384x
+*
+* Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+* --------------------------------------------------------------------
+*
+* linux-wlan
+*
+*   The contents of this file are subject to the Mozilla Public
+*   License Version 1.1 (the "License"); you may not use this file
+*   except in compliance with the License. You may obtain a copy of
+*   the License at http://www.mozilla.org/MPL/
+*
+*   Software distributed under the License is distributed on an "AS
+*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+*   implied. See the License for the specific language governing
+*   rights and limitations under the License.
+*
+*   Alternatively, the contents of this file may be used under the
+*   terms of the GNU Public License version 2 (the "GPL"), in which
+*   case the provisions of the GPL are applicable instead of the
+*   above.  If you wish to allow the use of your version of this file
+*   only under the terms of the GPL and not to allow others to use
+*   your version of this file under the MPL, indicate your decision
+*   by deleting the provisions above and replace them with the notice
+*   and other provisions required by the GPL.  If you do not delete
+*   the provisions above, a recipient may use your version of this
+*   file under either the MPL or the GPL.
+*
+* --------------------------------------------------------------------
+*
+* Inquiries regarding the linux-wlan Open Source project can be
+* made directly to:
+*
+* AbsoluteValue Systems Inc.
+* info at linux-wlan.com
+* http://www.linux-wlan.com
+*
+* --------------------------------------------------------------------
+*
+* Portions of the development of this software were funded by 
+* Intersil Corporation as part of PRISM(R) chipset product development.
+*
+* --------------------------------------------------------------------
+*
+*   [Implementation and usage notes]
+*
+*   [References]
+*	CW10 Programmer's Manual v1.5
+*	IEEE 802.11 D10.0
+*
+* --------------------------------------------------------------------
+*/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _HFA384x_H
+#define _HFA384x_H
+
+/*=============================================================*/
+#define HFA384x_FIRMWARE_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+#define HFA384x_LEVEL_TO_dBm(v)   (0x100 + (v) * 100 / 255 - 100)
+
+/*------ Constants --------------------------------------------*/
+/*--- Mins & Maxs -----------------------------------*/
+#define		HFA384x_CMD_ALLOC_LEN_MIN	((UINT16)4)
+#define		HFA384x_CMD_ALLOC_LEN_MAX	((UINT16)2400)
+#define		HFA384x_BAP_DATALEN_MAX		((UINT16)4096)
+#define		HFA384x_BAP_OFFSET_MAX		((UINT16)4096)
+#define		HFA384x_PORTID_MAX		((UINT16)7)
+#define		HFA384x_NUMPORTS_MAX		((UINT16)(HFA384x_PORTID_MAX+1))
+#define		HFA384x_PDR_LEN_MAX		((UINT16)512)	/* in bytes, from EK */
+#define		HFA384x_PDA_RECS_MAX		((UINT16)200)	/* a guess */
+#define		HFA384x_PDA_LEN_MAX		((UINT16)1024)	/* in bytes, from EK */
+#define		HFA384x_SCANRESULT_MAX		((UINT16)31)
+#define		HFA384x_HSCANRESULT_MAX		((UINT16)31)
+#define		HFA384x_CHINFORESULT_MAX	((UINT16)16)
+#define		HFA384x_DRVR_FIDSTACKLEN_MAX	(10)
+#define		HFA384x_DRVR_TXBUF_MAX		(sizeof(hfa384x_tx_frame_t) + \
+						WLAN_DATA_MAXLEN - \
+						WLAN_WEP_IV_LEN - \
+						WLAN_WEP_ICV_LEN + 2)
+#define		HFA384x_DRVR_MAGIC		(0x4a2d)
+#define		HFA384x_INFODATA_MAXLEN		(sizeof(hfa384x_infodata_t))
+#define		HFA384x_INFOFRM_MAXLEN		(sizeof(hfa384x_InfFrame_t))
+#define		HFA384x_RID_GUESSING_MAXLEN	2048  /* I'm not really sure */
+#define		HFA384x_RIDDATA_MAXLEN		HFA384x_RID_GUESSING_MAXLEN	
+#define		HFA384x_USB_RWMEM_MAXLEN	2048
+
+/*--- Support Constants -----------------------------*/
+#define		HFA384x_BAP_PROC			((UINT16)0)
+#define		HFA384x_BAP_INT				((UINT16)1)
+#define		HFA384x_PORTTYPE_IBSS			((UINT16)0)
+#define		HFA384x_PORTTYPE_BSS			((UINT16)1)
+#define		HFA384x_PORTTYPE_WDS			((UINT16)2)
+#define		HFA384x_PORTTYPE_PSUEDOIBSS		((UINT16)3)
+#define		HFA384x_PORTTYPE_HOSTAP    		((UINT16)6)
+#define		HFA384x_WEPFLAGS_PRIVINVOKED		((UINT16)BIT0)
+#define		HFA384x_WEPFLAGS_EXCLUDE		((UINT16)BIT1)
+#define		HFA384x_WEPFLAGS_DISABLE_TXCRYPT	((UINT16)BIT4)
+#define		HFA384x_WEPFLAGS_DISABLE_RXCRYPT	((UINT16)BIT7)
+#define		HFA384x_WEPFLAGS_DISALLOW_MIXED 	((UINT16)BIT11)
+#define		HFA384x_WEPFLAGS_IV_INTERVAL1		((UINT16)0)
+#define		HFA384x_WEPFLAGS_IV_INTERVAL10		((UINT16)BIT5)
+#define		HFA384x_WEPFLAGS_IV_INTERVAL50		((UINT16)BIT6)
+#define		HFA384x_WEPFLAGS_IV_INTERVAL100		((UINT16)(BIT5 | BIT6))
+#define		HFA384x_WEPFLAGS_FIRMWARE_WPA  		((UINT16)BIT8)
+#define		HFA384x_WEPFLAGS_HOST_MIC      		((UINT16)BIT9)
+#define 	HFA384x_ROAMMODE_FWSCAN_FWROAM		((UINT16)1)
+#define 	HFA384x_ROAMMODE_FWSCAN_HOSTROAM	((UINT16)2)
+#define 	HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM	((UINT16)3)
+#define 	HFA384x_PORTSTATUS_DISABLED		((UINT16)1)
+#define 	HFA384x_PORTSTATUS_INITSRCH		((UINT16)2)
+#define 	HFA384x_PORTSTATUS_CONN_IBSS		((UINT16)3)
+#define 	HFA384x_PORTSTATUS_CONN_ESS		((UINT16)4)
+#define 	HFA384x_PORTSTATUS_OOR_ESS		((UINT16)5)
+#define 	HFA384x_PORTSTATUS_CONN_WDS		((UINT16)6)
+#define 	HFA384x_PORTSTATUS_HOSTAP		((UINT16)8)
+#define		HFA384x_RATEBIT_1			((UINT16)1)
+#define		HFA384x_RATEBIT_2			((UINT16)2)
+#define		HFA384x_RATEBIT_5dot5			((UINT16)4)
+#define		HFA384x_RATEBIT_11			((UINT16)8)
+
+/*--- Just some symbolic names for legibility -------*/
+#define		HFA384x_TXCMD_NORECL		((UINT16)0)
+#define		HFA384x_TXCMD_RECL		((UINT16)1)
+
+/*--- MAC Internal memory constants and macros ------*/
+/* masks and macros used to manipulate MAC internal memory addresses. */
+/* MAC internal memory addresses are 23 bit quantities.  The MAC uses 
+ * a paged address space where the upper 16 bits are the page number 
+ * and the lower 7 bits are the offset.  There are various Host API 
+ * elements that require two 16-bit quantities to specify a MAC 
+ * internal memory address.  Unfortunately, some of the API's use a 
+ * page/offset format where the offset value is JUST the lower seven 
+ * bits and the page is  the remaining 16 bits.  Some of the API's 
+ * assume that the 23 bit address has been split at the 16th bit.  We 
+ * refer to these two formats as AUX format and CMD format.  The 
+ * macros below help handle some of this.
+ */ 
+
+/* Handy constant */
+#define		HFA384x_ADDR_AUX_OFF_MAX	((UINT16)0x007f)
+
+/* Mask bits for discarding unwanted pieces in a flat address */
+#define		HFA384x_ADDR_FLAT_AUX_PAGE_MASK	(0x007fff80)
+#define		HFA384x_ADDR_FLAT_AUX_OFF_MASK	(0x0000007f)
+#define		HFA384x_ADDR_FLAT_CMD_PAGE_MASK	(0xffff0000)
+#define		HFA384x_ADDR_FLAT_CMD_OFF_MASK	(0x0000ffff)
+
+/* Mask bits for discarding unwanted pieces in AUX format 16-bit address parts */
+#define		HFA384x_ADDR_AUX_PAGE_MASK	(0xffff)
+#define		HFA384x_ADDR_AUX_OFF_MASK	(0x007f)
+
+/* Mask bits for discarding unwanted pieces in CMD format 16-bit address parts */
+#define		HFA384x_ADDR_CMD_PAGE_MASK	(0x007f)
+#define		HFA384x_ADDR_CMD_OFF_MASK	(0xffff)
+
+/* Make a 32-bit flat address from AUX format 16-bit page and offset */
+#define		HFA384x_ADDR_AUX_MKFLAT(p,o)	\
+		(((UINT32)(((UINT16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) <<7) | \
+		((UINT32)(((UINT16)(o))&HFA384x_ADDR_AUX_OFF_MASK))
+
+/* Make a 32-bit flat address from CMD format 16-bit page and offset */
+#define		HFA384x_ADDR_CMD_MKFLAT(p,o)	\
+		(((UINT32)(((UINT16)(p))&HFA384x_ADDR_CMD_PAGE_MASK)) <<16) | \
+		((UINT32)(((UINT16)(o))&HFA384x_ADDR_CMD_OFF_MASK))
+
+/* Make AUX format offset and page from a 32-bit flat address */
+#define		HFA384x_ADDR_AUX_MKPAGE(f) \
+		((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_PAGE_MASK)>>7))
+#define		HFA384x_ADDR_AUX_MKOFF(f) \
+		((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_OFF_MASK))
+
+/* Make CMD format offset and page from a 32-bit flat address */
+#define		HFA384x_ADDR_CMD_MKPAGE(f) \
+		((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_PAGE_MASK)>>16))
+#define		HFA384x_ADDR_CMD_MKOFF(f) \
+		((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_OFF_MASK))
+
+/*--- Aux register masks/tests ----------------------*/
+/* Some of the upper bits of the AUX offset register are used to */
+/*  select address space. */
+#define		HFA384x_AUX_CTL_EXTDS	(0x00)
+#define		HFA384x_AUX_CTL_NV	(0x01)
+#define		HFA384x_AUX_CTL_PHY	(0x02)
+#define		HFA384x_AUX_CTL_ICSRAM	(0x03)
+
+/* Make AUX register offset and page values from a flat address */
+#define		HFA384x_AUX_MKOFF(f, c) \
+	(HFA384x_ADDR_AUX_MKOFF(f) | (((UINT16)(c))<<12))
+#define		HFA384x_AUX_MKPAGE(f)	HFA384x_ADDR_AUX_MKPAGE(f)
+
+
+/*--- Controller Memory addresses -------------------*/
+#define		HFA3842_PDA_BASE	(0x007f0000UL)
+#define		HFA3841_PDA_BASE	(0x003f0000UL)
+#define		HFA3841_PDA_BOGUS_BASE	(0x00390000UL)
+
+/*--- Driver Download states  -----------------------*/
+#define		HFA384x_DLSTATE_DISABLED		0
+#define		HFA384x_DLSTATE_RAMENABLED		1
+#define		HFA384x_DLSTATE_FLASHENABLED		2
+#define		HFA384x_DLSTATE_FLASHWRITTEN		3
+#define		HFA384x_DLSTATE_FLASHWRITEPENDING	4
+#define		HFA384x_DLSTATE_GENESIS 		5
+
+/*--- Register I/O offsets --------------------------*/
+#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX))
+
+#define		HFA384x_CMD_OFF			(0x00)
+#define		HFA384x_PARAM0_OFF		(0x02)
+#define		HFA384x_PARAM1_OFF		(0x04)
+#define		HFA384x_PARAM2_OFF		(0x06)
+#define		HFA384x_STATUS_OFF		(0x08)
+#define		HFA384x_RESP0_OFF		(0x0A)
+#define		HFA384x_RESP1_OFF		(0x0C)
+#define		HFA384x_RESP2_OFF		(0x0E)
+#define		HFA384x_INFOFID_OFF		(0x10)
+#define		HFA384x_RXFID_OFF		(0x20)
+#define		HFA384x_ALLOCFID_OFF		(0x22)
+#define		HFA384x_TXCOMPLFID_OFF		(0x24)
+#define		HFA384x_SELECT0_OFF		(0x18)
+#define		HFA384x_OFFSET0_OFF		(0x1C)
+#define		HFA384x_DATA0_OFF		(0x36)
+#define		HFA384x_SELECT1_OFF		(0x1A)
+#define		HFA384x_OFFSET1_OFF		(0x1E)
+#define		HFA384x_DATA1_OFF		(0x38)
+#define		HFA384x_EVSTAT_OFF		(0x30)
+#define		HFA384x_INTEN_OFF		(0x32)
+#define		HFA384x_EVACK_OFF		(0x34)
+#define		HFA384x_CONTROL_OFF		(0x14)
+#define		HFA384x_SWSUPPORT0_OFF		(0x28)
+#define		HFA384x_SWSUPPORT1_OFF		(0x2A)
+#define		HFA384x_SWSUPPORT2_OFF		(0x2C)
+#define		HFA384x_AUXPAGE_OFF		(0x3A)
+#define		HFA384x_AUXOFFSET_OFF		(0x3C)
+#define		HFA384x_AUXDATA_OFF		(0x3E)
+
+#elif (WLAN_HOSTIF == WLAN_PCI || WLAN_HOSTIF == WLAN_USB)
+
+#define		HFA384x_CMD_OFF			(0x00)
+#define		HFA384x_PARAM0_OFF		(0x04)
+#define		HFA384x_PARAM1_OFF		(0x08)
+#define		HFA384x_PARAM2_OFF		(0x0c)
+#define		HFA384x_STATUS_OFF		(0x10)
+#define		HFA384x_RESP0_OFF		(0x14)
+#define		HFA384x_RESP1_OFF		(0x18)
+#define		HFA384x_RESP2_OFF		(0x1c)
+#define		HFA384x_INFOFID_OFF		(0x20)
+#define		HFA384x_RXFID_OFF		(0x40)
+#define		HFA384x_ALLOCFID_OFF		(0x44)
+#define		HFA384x_TXCOMPLFID_OFF		(0x48)
+#define		HFA384x_SELECT0_OFF		(0x30)
+#define		HFA384x_OFFSET0_OFF		(0x38)
+#define		HFA384x_DATA0_OFF		(0x6c)
+#define		HFA384x_SELECT1_OFF		(0x34)
+#define		HFA384x_OFFSET1_OFF		(0x3c)
+#define		HFA384x_DATA1_OFF		(0x70)
+#define		HFA384x_EVSTAT_OFF		(0x60)
+#define		HFA384x_INTEN_OFF		(0x64)
+#define		HFA384x_EVACK_OFF		(0x68)
+#define		HFA384x_CONTROL_OFF		(0x28)
+#define		HFA384x_SWSUPPORT0_OFF		(0x50)
+#define		HFA384x_SWSUPPORT1_OFF		(0x54)
+#define		HFA384x_SWSUPPORT2_OFF		(0x58)
+#define		HFA384x_AUXPAGE_OFF		(0x74)
+#define		HFA384x_AUXOFFSET_OFF		(0x78)
+#define		HFA384x_AUXDATA_OFF		(0x7c)
+#define		HFA384x_PCICOR_OFF		(0x4c)
+#define		HFA384x_PCIHCR_OFF		(0x5c)
+#define		HFA384x_PCI_M0_ADDRH_OFF	(0x80)
+#define		HFA384x_PCI_M0_ADDRL_OFF	(0x84)
+#define		HFA384x_PCI_M0_LEN_OFF		(0x88)
+#define		HFA384x_PCI_M0_CTL_OFF		(0x8c)
+#define		HFA384x_PCI_STATUS_OFF		(0x98)
+#define		HFA384x_PCI_M1_ADDRH_OFF	(0xa0)
+#define		HFA384x_PCI_M1_ADDRL_OFF	(0xa4)
+#define		HFA384x_PCI_M1_LEN_OFF		(0xa8)
+#define		HFA384x_PCI_M1_CTL_OFF		(0xac)
+
+#endif
+
+/*--- Register Field Masks --------------------------*/
+#define		HFA384x_CMD_BUSY		((UINT16)BIT15)
+#define		HFA384x_CMD_AINFO		((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8))
+#define		HFA384x_CMD_MACPORT		((UINT16)(BIT10 | BIT9 | BIT8))
+#define		HFA384x_CMD_RECL		((UINT16)BIT8)
+#define		HFA384x_CMD_WRITE		((UINT16)BIT8)
+#define		HFA384x_CMD_PROGMODE		((UINT16)(BIT9 | BIT8))
+#define		HFA384x_CMD_CMDCODE		((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0))
+
+#define		HFA384x_STATUS_RESULT		((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8))
+#define		HFA384x_STATUS_CMDCODE		((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0))
+
+#define		HFA384x_OFFSET_BUSY		((UINT16)BIT15)
+#define		HFA384x_OFFSET_ERR		((UINT16)BIT14)
+#define		HFA384x_OFFSET_DATAOFF		((UINT16)(BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1))
+
+#define		HFA384x_EVSTAT_TICK		((UINT16)BIT15)
+#define		HFA384x_EVSTAT_WTERR		((UINT16)BIT14)
+#define		HFA384x_EVSTAT_INFDROP		((UINT16)BIT13)
+#define		HFA384x_EVSTAT_INFO		((UINT16)BIT7)
+#define		HFA384x_EVSTAT_DTIM		((UINT16)BIT5)
+#define		HFA384x_EVSTAT_CMD		((UINT16)BIT4)
+#define		HFA384x_EVSTAT_ALLOC		((UINT16)BIT3)
+#define		HFA384x_EVSTAT_TXEXC		((UINT16)BIT2)
+#define		HFA384x_EVSTAT_TX		((UINT16)BIT1)
+#define		HFA384x_EVSTAT_RX		((UINT16)BIT0)
+
+#define         HFA384x_INT_BAP_OP           (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC)
+
+#define         HFA384x_INT_NORMAL           (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC|HFA384x_EVSTAT_INFDROP|HFA384x_EVSTAT_ALLOC|HFA384x_EVSTAT_DTIM)
+
+#define		HFA384x_INTEN_TICK		((UINT16)BIT15)
+#define		HFA384x_INTEN_WTERR		((UINT16)BIT14)
+#define		HFA384x_INTEN_INFDROP		((UINT16)BIT13)
+#define		HFA384x_INTEN_INFO		((UINT16)BIT7)
+#define		HFA384x_INTEN_DTIM		((UINT16)BIT5)
+#define		HFA384x_INTEN_CMD		((UINT16)BIT4)
+#define		HFA384x_INTEN_ALLOC		((UINT16)BIT3)
+#define		HFA384x_INTEN_TXEXC		((UINT16)BIT2)
+#define		HFA384x_INTEN_TX		((UINT16)BIT1)
+#define		HFA384x_INTEN_RX		((UINT16)BIT0)
+
+#define		HFA384x_EVACK_TICK		((UINT16)BIT15)
+#define		HFA384x_EVACK_WTERR		((UINT16)BIT14)
+#define		HFA384x_EVACK_INFDROP		((UINT16)BIT13)
+#define		HFA384x_EVACK_INFO		((UINT16)BIT7)
+#define		HFA384x_EVACK_DTIM		((UINT16)BIT5)
+#define		HFA384x_EVACK_CMD		((UINT16)BIT4)
+#define		HFA384x_EVACK_ALLOC		((UINT16)BIT3)
+#define		HFA384x_EVACK_TXEXC		((UINT16)BIT2)
+#define		HFA384x_EVACK_TX		((UINT16)BIT1)
+#define		HFA384x_EVACK_RX		((UINT16)BIT0)
+
+#define		HFA384x_CONTROL_AUXEN		((UINT16)(BIT15 | BIT14))
+
+
+/*--- Command Code Constants --------------------------*/
+/*--- Controller Commands --------------------------*/
+#define		HFA384x_CMDCODE_INIT		((UINT16)0x00)
+#define		HFA384x_CMDCODE_ENABLE		((UINT16)0x01)
+#define		HFA384x_CMDCODE_DISABLE		((UINT16)0x02)
+#define		HFA384x_CMDCODE_DIAG		((UINT16)0x03)
+
+/*--- Buffer Mgmt Commands --------------------------*/
+#define		HFA384x_CMDCODE_ALLOC		((UINT16)0x0A)
+#define		HFA384x_CMDCODE_TX		((UINT16)0x0B)
+#define		HFA384x_CMDCODE_CLRPRST		((UINT16)0x12)
+
+/*--- Regulate Commands --------------------------*/
+#define		HFA384x_CMDCODE_NOTIFY		((UINT16)0x10)
+#define		HFA384x_CMDCODE_INQ		((UINT16)0x11)
+
+/*--- Configure Commands --------------------------*/
+#define		HFA384x_CMDCODE_ACCESS		((UINT16)0x21)
+#define		HFA384x_CMDCODE_DOWNLD		((UINT16)0x22)
+
+/*--- Debugging Commands -----------------------------*/
+#define 	HFA384x_CMDCODE_MONITOR		((UINT16)(0x38))
+#define		HFA384x_MONITOR_ENABLE		((UINT16)(0x0b))
+#define		HFA384x_MONITOR_DISABLE		((UINT16)(0x0f))
+
+/*--- Result Codes --------------------------*/
+#define		HFA384x_SUCCESS			((UINT16)(0x00))
+#define		HFA384x_CARD_FAIL		((UINT16)(0x01))
+#define		HFA384x_NO_BUFF			((UINT16)(0x05))
+#define		HFA384x_CMD_ERR			((UINT16)(0x7F))
+
+/*--- Programming Modes --------------------------
+	MODE 0: Disable programming
+	MODE 1: Enable volatile memory programming
+	MODE 2: Enable non-volatile memory programming
+	MODE 3: Program non-volatile memory section
+--------------------------------------------------*/
+#define		HFA384x_PROGMODE_DISABLE	((UINT16)0x00)
+#define		HFA384x_PROGMODE_RAM		((UINT16)0x01)
+#define		HFA384x_PROGMODE_NV		((UINT16)0x02)
+#define		HFA384x_PROGMODE_NVWRITE	((UINT16)0x03)
+
+/*--- AUX register enable --------------------------*/
+#define		HFA384x_AUXPW0			((UINT16)0xfe01)
+#define		HFA384x_AUXPW1			((UINT16)0xdc23)
+#define		HFA384x_AUXPW2			((UINT16)0xba45)
+
+#define		HFA384x_CONTROL_AUX_ISDISABLED	((UINT16)0x0000)
+#define		HFA384x_CONTROL_AUX_ISENABLED	((UINT16)0xc000)
+#define		HFA384x_CONTROL_AUX_DOENABLE	((UINT16)0x8000)
+#define		HFA384x_CONTROL_AUX_DODISABLE	((UINT16)0x4000)
+
+/*--- Record ID Constants --------------------------*/
+/*--------------------------------------------------------------------
+Configuration RIDs: Network Parameters, Static Configuration Entities
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_CNFPORTTYPE		((UINT16)0xFC00)
+#define		HFA384x_RID_CNFOWNMACADDR	((UINT16)0xFC01)
+#define		HFA384x_RID_CNFDESIREDSSID	((UINT16)0xFC02)
+#define		HFA384x_RID_CNFOWNCHANNEL	((UINT16)0xFC03)
+#define		HFA384x_RID_CNFOWNSSID		((UINT16)0xFC04)
+#define		HFA384x_RID_CNFOWNATIMWIN	((UINT16)0xFC05)
+#define		HFA384x_RID_CNFSYSSCALE		((UINT16)0xFC06)
+#define		HFA384x_RID_CNFMAXDATALEN	((UINT16)0xFC07)
+#define		HFA384x_RID_CNFWDSADDR		((UINT16)0xFC08)
+#define		HFA384x_RID_CNFPMENABLED	((UINT16)0xFC09)
+#define		HFA384x_RID_CNFPMEPS		((UINT16)0xFC0A)
+#define		HFA384x_RID_CNFMULTICASTRX	((UINT16)0xFC0B)
+#define		HFA384x_RID_CNFMAXSLEEPDUR	((UINT16)0xFC0C)
+#define		HFA384x_RID_CNFPMHOLDDUR	((UINT16)0xFC0D)
+#define		HFA384x_RID_CNFOWNNAME		((UINT16)0xFC0E)
+#define		HFA384x_RID_CNFOWNDTIMPER	((UINT16)0xFC10)
+#define		HFA384x_RID_CNFWDSADDR1		((UINT16)0xFC11)
+#define		HFA384x_RID_CNFWDSADDR2		((UINT16)0xFC12)
+#define		HFA384x_RID_CNFWDSADDR3		((UINT16)0xFC13)
+#define		HFA384x_RID_CNFWDSADDR4		((UINT16)0xFC14)
+#define		HFA384x_RID_CNFWDSADDR5		((UINT16)0xFC15)
+#define		HFA384x_RID_CNFWDSADDR6		((UINT16)0xFC16)
+#define		HFA384x_RID_CNFMCASTPMBUFF	((UINT16)0xFC17)
+
+/*--------------------------------------------------------------------
+Configuration RID lengths: Network Params, Static Config Entities
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+/* TODO: fill in the rest of these */
+#define		HFA384x_RID_CNFPORTTYPE_LEN	((UINT16)2)
+#define		HFA384x_RID_CNFOWNMACADDR_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFDESIREDSSID_LEN	((UINT16)34)
+#define		HFA384x_RID_CNFOWNCHANNEL_LEN	((UINT16)2)
+#define		HFA384x_RID_CNFOWNSSID_LEN	((UINT16)34)
+#define		HFA384x_RID_CNFOWNATIMWIN_LEN	((UINT16)2)
+#define		HFA384x_RID_CNFSYSSCALE_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFMAXDATALEN_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFWDSADDR_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFPMENABLED_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFPMEPS_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFMULTICASTRX_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFMAXSLEEPDUR_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFPMHOLDDUR_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFOWNNAME_LEN	((UINT16)34)
+#define		HFA384x_RID_CNFOWNDTIMPER_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFWDSADDR1_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWDSADDR2_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWDSADDR3_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWDSADDR4_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWDSADDR5_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWDSADDR6_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFMCASTPMBUFF_LEN	((UINT16)0)
+#define		HFA384x_RID_CNFAUTHENTICATION_LEN ((UINT16)sizeof(UINT16))
+#define		HFA384x_RID_CNFMAXSLEEPDUR_LEN	((UINT16)0)
+
+/*--------------------------------------------------------------------
+Configuration RIDs: Network Parameters, Dynamic Configuration Entities
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_GROUPADDR		((UINT16)0xFC80)
+#define		HFA384x_RID_CREATEIBSS		((UINT16)0xFC81)
+#define		HFA384x_RID_FRAGTHRESH		((UINT16)0xFC82)
+#define		HFA384x_RID_RTSTHRESH		((UINT16)0xFC83)
+#define		HFA384x_RID_TXRATECNTL		((UINT16)0xFC84)
+#define		HFA384x_RID_PROMISCMODE		((UINT16)0xFC85)
+#define		HFA384x_RID_FRAGTHRESH0		((UINT16)0xFC90)
+#define		HFA384x_RID_FRAGTHRESH1		((UINT16)0xFC91)
+#define		HFA384x_RID_FRAGTHRESH2		((UINT16)0xFC92)
+#define		HFA384x_RID_FRAGTHRESH3		((UINT16)0xFC93)
+#define		HFA384x_RID_FRAGTHRESH4		((UINT16)0xFC94)
+#define		HFA384x_RID_FRAGTHRESH5		((UINT16)0xFC95)
+#define		HFA384x_RID_FRAGTHRESH6		((UINT16)0xFC96)
+#define		HFA384x_RID_RTSTHRESH0		((UINT16)0xFC97)
+#define		HFA384x_RID_RTSTHRESH1		((UINT16)0xFC98)
+#define		HFA384x_RID_RTSTHRESH2		((UINT16)0xFC99)
+#define		HFA384x_RID_RTSTHRESH3		((UINT16)0xFC9A)
+#define		HFA384x_RID_RTSTHRESH4		((UINT16)0xFC9B)
+#define		HFA384x_RID_RTSTHRESH5		((UINT16)0xFC9C)
+#define		HFA384x_RID_RTSTHRESH6		((UINT16)0xFC9D)
+#define		HFA384x_RID_TXRATECNTL0		((UINT16)0xFC9E)
+#define		HFA384x_RID_TXRATECNTL1		((UINT16)0xFC9F)
+#define		HFA384x_RID_TXRATECNTL2		((UINT16)0xFCA0)
+#define		HFA384x_RID_TXRATECNTL3		((UINT16)0xFCA1)
+#define		HFA384x_RID_TXRATECNTL4		((UINT16)0xFCA2)
+#define		HFA384x_RID_TXRATECNTL5		((UINT16)0xFCA3)
+#define		HFA384x_RID_TXRATECNTL6		((UINT16)0xFCA4)
+
+/*--------------------------------------------------------------------
+Configuration RID Lengths: Network Param, Dynamic Config Entities
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+/* TODO: fill in the rest of these */
+#define		HFA384x_RID_GROUPADDR_LEN	((UINT16)16 * WLAN_ADDR_LEN)
+#define		HFA384x_RID_CREATEIBSS_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL_LEN	((UINT16)4)
+#define		HFA384x_RID_PROMISCMODE_LEN	((UINT16)2)
+#define		HFA384x_RID_FRAGTHRESH0_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH1_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH2_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH3_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH4_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH5_LEN	((UINT16)0)
+#define		HFA384x_RID_FRAGTHRESH6_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH0_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH1_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH2_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH3_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH4_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH5_LEN	((UINT16)0)
+#define		HFA384x_RID_RTSTHRESH6_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL0_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL1_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL2_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL3_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL4_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL5_LEN	((UINT16)0)
+#define		HFA384x_RID_TXRATECNTL6_LEN	((UINT16)0)
+
+/*--------------------------------------------------------------------
+Configuration RIDs: Behavior Parameters
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_ITICKTIME		((UINT16)0xFCE0)
+
+/*--------------------------------------------------------------------
+Configuration RID Lengths: Behavior Parameters
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_ITICKTIME_LEN	((UINT16)2)
+
+/*----------------------------------------------------------------------
+Information RIDs: NIC Information
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_MAXLOADTIME		((UINT16)0xFD00)
+#define		HFA384x_RID_DOWNLOADBUFFER	((UINT16)0xFD01)
+#define		HFA384x_RID_PRIIDENTITY		((UINT16)0xFD02)
+#define		HFA384x_RID_PRISUPRANGE		((UINT16)0xFD03)
+#define		HFA384x_RID_PRI_CFIACTRANGES	((UINT16)0xFD04)
+#define		HFA384x_RID_NICSERIALNUMBER	((UINT16)0xFD0A)
+#define		HFA384x_RID_NICIDENTITY		((UINT16)0xFD0B)
+#define		HFA384x_RID_MFISUPRANGE		((UINT16)0xFD0C)
+#define		HFA384x_RID_CFISUPRANGE		((UINT16)0xFD0D)
+#define		HFA384x_RID_CHANNELLIST		((UINT16)0xFD10)
+#define		HFA384x_RID_REGULATORYDOMAINS	((UINT16)0xFD11)
+#define		HFA384x_RID_TEMPTYPE		((UINT16)0xFD12)
+#define		HFA384x_RID_CIS			((UINT16)0xFD13)
+#define		HFA384x_RID_STAIDENTITY		((UINT16)0xFD20)
+#define		HFA384x_RID_STASUPRANGE		((UINT16)0xFD21)
+#define		HFA384x_RID_STA_MFIACTRANGES	((UINT16)0xFD22)
+#define		HFA384x_RID_STA_CFIACTRANGES	((UINT16)0xFD23)
+#define		HFA384x_RID_BUILDSEQ		((UINT16)0xFFFE)
+#define		HFA384x_RID_FWID		((UINT16)0xFFFF)
+
+/*----------------------------------------------------------------------
+Information RID Lengths: NIC Information
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_MAXLOADTIME_LEN		((UINT16)0)
+#define		HFA384x_RID_DOWNLOADBUFFER_LEN		((UINT16)sizeof(hfa384x_downloadbuffer_t))
+#define		HFA384x_RID_PRIIDENTITY_LEN		((UINT16)8)
+#define		HFA384x_RID_PRISUPRANGE_LEN		((UINT16)10)
+#define		HFA384x_RID_CFIACTRANGES_LEN		((UINT16)10)
+#define		HFA384x_RID_NICSERIALNUMBER_LEN		((UINT16)12)
+#define		HFA384x_RID_NICIDENTITY_LEN		((UINT16)8)
+#define		HFA384x_RID_MFISUPRANGE_LEN		((UINT16)10)
+#define		HFA384x_RID_CFISUPRANGE_LEN		((UINT16)10)
+#define		HFA384x_RID_CHANNELLIST_LEN		((UINT16)0)
+#define		HFA384x_RID_REGULATORYDOMAINS_LEN	((UINT16)12)
+#define		HFA384x_RID_TEMPTYPE_LEN		((UINT16)0)
+#define		HFA384x_RID_CIS_LEN			((UINT16)480)
+#define		HFA384x_RID_STAIDENTITY_LEN		((UINT16)8)
+#define		HFA384x_RID_STASUPRANGE_LEN		((UINT16)10)
+#define		HFA384x_RID_MFIACTRANGES_LEN		((UINT16)10)
+#define		HFA384x_RID_CFIACTRANGES2_LEN		((UINT16)10)
+#define		HFA384x_RID_BUILDSEQ_LEN		((UINT16)sizeof(hfa384x_BuildSeq_t))
+#define		HFA384x_RID_FWID_LEN			((UINT16)sizeof(hfa384x_FWID_t))
+
+/*--------------------------------------------------------------------
+Information RIDs:  MAC Information
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_PORTSTATUS		((UINT16)0xFD40)
+#define		HFA384x_RID_CURRENTSSID		((UINT16)0xFD41)
+#define		HFA384x_RID_CURRENTBSSID	((UINT16)0xFD42)
+#define		HFA384x_RID_COMMSQUALITY	((UINT16)0xFD43)
+#define		HFA384x_RID_CURRENTTXRATE	((UINT16)0xFD44)
+#define		HFA384x_RID_CURRENTBCNINT	((UINT16)0xFD45)
+#define		HFA384x_RID_CURRENTSCALETHRESH	((UINT16)0xFD46)
+#define		HFA384x_RID_PROTOCOLRSPTIME	((UINT16)0xFD47)
+#define		HFA384x_RID_SHORTRETRYLIMIT	((UINT16)0xFD48)
+#define		HFA384x_RID_LONGRETRYLIMIT	((UINT16)0xFD49)
+#define		HFA384x_RID_MAXTXLIFETIME	((UINT16)0xFD4A)
+#define		HFA384x_RID_MAXRXLIFETIME	((UINT16)0xFD4B)
+#define		HFA384x_RID_CFPOLLABLE		((UINT16)0xFD4C)
+#define		HFA384x_RID_AUTHALGORITHMS	((UINT16)0xFD4D)
+#define		HFA384x_RID_PRIVACYOPTIMP	((UINT16)0xFD4F)
+#define		HFA384x_RID_DBMCOMMSQUALITY	((UINT16)0xFD51)
+#define		HFA384x_RID_CURRENTTXRATE1	((UINT16)0xFD80)
+#define		HFA384x_RID_CURRENTTXRATE2	((UINT16)0xFD81)
+#define		HFA384x_RID_CURRENTTXRATE3	((UINT16)0xFD82)
+#define		HFA384x_RID_CURRENTTXRATE4	((UINT16)0xFD83)
+#define		HFA384x_RID_CURRENTTXRATE5	((UINT16)0xFD84)
+#define		HFA384x_RID_CURRENTTXRATE6	((UINT16)0xFD85)
+#define		HFA384x_RID_OWNMACADDRESS	((UINT16)0xFD86)
+// #define	HFA384x_RID_PCFINFO		((UINT16)0xFD87)
+#define		HFA384x_RID_SCANRESULTS       	((UINT16)0xFD88) // NEW
+#define		HFA384x_RID_HOSTSCANRESULTS   	((UINT16)0xFD89) // NEW
+#define		HFA384x_RID_AUTHENTICATIONUSED	((UINT16)0xFD8A) // NEW
+#define		HFA384x_RID_ASSOCIATEFAILURE  	((UINT16)0xFD8D) // 1.8.0
+
+/*--------------------------------------------------------------------
+Information RID Lengths:  MAC Information
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_PORTSTATUS_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTSSID_LEN		((UINT16)34)
+#define		HFA384x_RID_CURRENTBSSID_LEN		((UINT16)WLAN_BSSID_LEN)
+#define		HFA384x_RID_COMMSQUALITY_LEN		((UINT16)sizeof(hfa384x_commsquality_t))
+#define		HFA384x_RID_DBMCOMMSQUALITY_LEN		((UINT16)sizeof(hfa384x_dbmcommsquality_t))
+#define		HFA384x_RID_CURRENTTXRATE_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTBCNINT_LEN		((UINT16)0)
+#define		HFA384x_RID_STACURSCALETHRESH_LEN	((UINT16)12)
+#define		HFA384x_RID_APCURSCALETHRESH_LEN	((UINT16)6)
+#define		HFA384x_RID_PROTOCOLRSPTIME_LEN		((UINT16)0)
+#define		HFA384x_RID_SHORTRETRYLIMIT_LEN		((UINT16)0)
+#define		HFA384x_RID_LONGRETRYLIMIT_LEN		((UINT16)0)
+#define		HFA384x_RID_MAXTXLIFETIME_LEN		((UINT16)0)
+#define		HFA384x_RID_MAXRXLIFETIME_LEN		((UINT16)0)
+#define		HFA384x_RID_CFPOLLABLE_LEN		((UINT16)0)
+#define		HFA384x_RID_AUTHALGORITHMS_LEN		((UINT16)4)
+#define		HFA384x_RID_PRIVACYOPTIMP_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE1_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE2_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE3_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE4_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE5_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTTXRATE6_LEN		((UINT16)0)
+#define		HFA384x_RID_OWNMACADDRESS_LEN		((UINT16)6)
+#define		HFA384x_RID_PCFINFO_LEN			((UINT16)6)
+#define		HFA384x_RID_CNFAPPCFINFO_LEN		((UINT16)sizeof(hfa384x_PCFInfo_data_t))
+#define		HFA384x_RID_SCANREQUEST_LEN		((UINT16)sizeof(hfa384x_ScanRequest_data_t))
+#define		HFA384x_RID_JOINREQUEST_LEN		((UINT16)sizeof(hfa384x_JoinRequest_data_t))
+#define		HFA384x_RID_AUTHENTICATESTA_LEN		((UINT16)sizeof(hfa384x_authenticateStation_data_t))
+#define		HFA384x_RID_CHANNELINFOREQUEST_LEN	((UINT16)sizeof(hfa384x_ChannelInfoRequest_data_t))
+/*--------------------------------------------------------------------
+Information RIDs:  Modem Information
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_PHYTYPE		((UINT16)0xFDC0)
+#define		HFA384x_RID_CURRENTCHANNEL	((UINT16)0xFDC1)
+#define		HFA384x_RID_CURRENTPOWERSTATE	((UINT16)0xFDC2)
+#define		HFA384x_RID_CCAMODE		((UINT16)0xFDC3)
+#define		HFA384x_RID_SUPPORTEDDATARATES	((UINT16)0xFDC6)
+#define		HFA384x_RID_LFOSTATUS           ((UINT16)0xFDC7) // 1.7.1
+
+/*--------------------------------------------------------------------
+Information RID Lengths:  Modem Information 
+  This is the length of JUST the DATA part of the RID (does not 
+  include the len or code fields)
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_PHYTYPE_LEN			((UINT16)0)
+#define		HFA384x_RID_CURRENTCHANNEL_LEN		((UINT16)0)
+#define		HFA384x_RID_CURRENTPOWERSTATE_LEN	((UINT16)0)
+#define		HFA384x_RID_CCAMODE_LEN			((UINT16)0)
+#define		HFA384x_RID_SUPPORTEDDATARATES_LEN	((UINT16)10)
+
+/*--------------------------------------------------------------------
+API ENHANCEMENTS (NOT ALREADY IMPLEMENTED)
+--------------------------------------------------------------------*/
+#define		HFA384x_RID_CNFWEPDEFAULTKEYID	((UINT16)0xFC23)
+#define		HFA384x_RID_CNFWEPDEFAULTKEY0	((UINT16)0xFC24)
+#define		HFA384x_RID_CNFWEPDEFAULTKEY1	((UINT16)0xFC25)
+#define		HFA384x_RID_CNFWEPDEFAULTKEY2	((UINT16)0xFC26)
+#define		HFA384x_RID_CNFWEPDEFAULTKEY3	((UINT16)0xFC27)
+#define		HFA384x_RID_CNFWEPFLAGS		((UINT16)0xFC28)
+#define		HFA384x_RID_CNFWEPKEYMAPTABLE	((UINT16)0xFC29)
+#define		HFA384x_RID_CNFAUTHENTICATION	((UINT16)0xFC2A)
+#define		HFA384x_RID_CNFMAXASSOCSTATIONS	((UINT16)0xFC2B)
+#define		HFA384x_RID_CNFTXCONTROL	((UINT16)0xFC2C)
+#define		HFA384x_RID_CNFROAMINGMODE	((UINT16)0xFC2D)
+#define		HFA384x_RID_CNFHOSTAUTHASSOC	((UINT16)0xFC2E)
+#define		HFA384x_RID_CNFRCVCRCERROR	((UINT16)0xFC30)
+// #define		HFA384x_RID_CNFMMLIFE		((UINT16)0xFC31)
+#define		HFA384x_RID_CNFALTRETRYCNT	((UINT16)0xFC32)
+#define		HFA384x_RID_CNFAPBCNINT		((UINT16)0xFC33)
+#define		HFA384x_RID_CNFAPPCFINFO	((UINT16)0xFC34)
+#define		HFA384x_RID_CNFSTAPCFINFO	((UINT16)0xFC35)
+#define		HFA384x_RID_CNFPRIORITYQUSAGE	((UINT16)0xFC37)
+#define		HFA384x_RID_CNFTIMCTRL		((UINT16)0xFC40)
+#define		HFA384x_RID_CNFTHIRTY2TALLY	((UINT16)0xFC42)
+#define		HFA384x_RID_CNFENHSECURITY	((UINT16)0xFC43)
+#define		HFA384x_RID_CNFDBMADJUST  	((UINT16)0xFC46) // NEW
+#define		HFA384x_RID_CNFWPADATA       	((UINT16)0xFC48) // 1.7.0
+#define		HFA384x_RID_CNFPROPOGATIONDELAY	((UINT16)0xFC49) // 1.7.6
+#define		HFA384x_RID_CNFSHORTPREAMBLE	((UINT16)0xFCB0)
+#define		HFA384x_RID_CNFEXCLONGPREAMBLE	((UINT16)0xFCB1)
+#define		HFA384x_RID_CNFAUTHRSPTIMEOUT	((UINT16)0xFCB2)
+#define		HFA384x_RID_CNFBASICRATES	((UINT16)0xFCB3)
+#define		HFA384x_RID_CNFSUPPRATES	((UINT16)0xFCB4) 
+#define		HFA384x_RID_CNFFALLBACKCTRL	((UINT16)0xFCB5) // NEW 
+#define		HFA384x_RID_WEPKEYSTATUS   	((UINT16)0xFCB6) // NEW
+#define		HFA384x_RID_WEPKEYMAPINDEX 	((UINT16)0xFCB7) // NEW
+#define		HFA384x_RID_BROADCASTKEYID 	((UINT16)0xFCB8) // NEW 
+#define		HFA384x_RID_ENTSECFLAGEYID 	((UINT16)0xFCB9) // NEW
+#define		HFA384x_RID_CNFPASSIVESCANCTRL	((UINT16)0xFCBA) // NEW STA
+#define		HFA384x_RID_CNFWPAHANDLING	((UINT16)0xFCBB) // 1.7.0
+#define		HFA384x_RID_MDCCONTROL        	((UINT16)0xFCBC) // 1.7.0/1.4.0
+#define		HFA384x_RID_MDCCOUNTRY        	((UINT16)0xFCBD) // 1.7.0/1.4.0
+#define		HFA384x_RID_TXPOWERMAX        	((UINT16)0xFCBE) // 1.7.0/1.4.0
+#define		HFA384x_RID_CNFLFOENBLED      	((UINT16)0xFCBF) // 1.6.3
+#define         HFA384x_RID_CAPINFO             ((UINT16)0xFCC0) // 1.7.0/1.3.7
+#define         HFA384x_RID_LISTENINTERVAL      ((UINT16)0xFCC1) // 1.7.0/1.3.7
+#define         HFA384x_RID_DIVERSITYENABLED    ((UINT16)0xFCC2) // 1.7.0/1.3.7
+#define         HFA384x_RID_LED_CONTROL         ((UINT16)0xFCC4) // 1.7.6      
+#define         HFA384x_RID_HFO_DELAY           ((UINT16)0xFCC5) // 1.7.6      
+#define         HFA384x_RID_DISSALOWEDBSSID     ((UINT16)0xFCC6) // 1.8.0
+#define		HFA384x_RID_SCANREQUEST		((UINT16)0xFCE1)
+#define		HFA384x_RID_JOINREQUEST		((UINT16)0xFCE2)
+#define		HFA384x_RID_AUTHENTICATESTA	((UINT16)0xFCE3)
+#define		HFA384x_RID_CHANNELINFOREQUEST	((UINT16)0xFCE4)
+#define		HFA384x_RID_HOSTSCAN          	((UINT16)0xFCE5) // NEW STA
+#define		HFA384x_RID_ASSOCIATESTA	((UINT16)0xFCE6)
+
+#define		HFA384x_RID_CNFWEPDEFAULTKEY_LEN	((UINT16)6)
+#define		HFA384x_RID_CNFWEP128DEFAULTKEY_LEN	((UINT16)14)
+#define		HFA384x_RID_CNFPRIOQUSAGE_LEN		((UINT16)4)
+/*--------------------------------------------------------------------
+PD Record codes
+--------------------------------------------------------------------*/
+#define HFA384x_PDR_PCB_PARTNUM		((UINT16)0x0001)
+#define HFA384x_PDR_PDAVER		((UINT16)0x0002)
+#define HFA384x_PDR_NIC_SERIAL		((UINT16)0x0003)
+#define HFA384x_PDR_MKK_MEASUREMENTS	((UINT16)0x0004)
+#define HFA384x_PDR_NIC_RAMSIZE		((UINT16)0x0005)
+#define HFA384x_PDR_MFISUPRANGE		((UINT16)0x0006)
+#define HFA384x_PDR_CFISUPRANGE		((UINT16)0x0007)
+#define HFA384x_PDR_NICID		((UINT16)0x0008)
+//#define HFA384x_PDR_REFDAC_MEASUREMENTS	((UINT16)0x0010)
+//#define HFA384x_PDR_VGDAC_MEASUREMENTS	((UINT16)0x0020)
+//#define HFA384x_PDR_LEVEL_COMP_MEASUREMENTS	((UINT16)0x0030)
+//#define HFA384x_PDR_MODEM_TRIMDAC_MEASUREMENTS	((UINT16)0x0040)
+//#define HFA384x_PDR_COREGA_HACK		((UINT16)0x00ff)
+#define HFA384x_PDR_MAC_ADDRESS		((UINT16)0x0101)
+//#define HFA384x_PDR_MKK_CALLNAME	((UINT16)0x0102)
+#define HFA384x_PDR_REGDOMAIN		((UINT16)0x0103)
+#define HFA384x_PDR_ALLOWED_CHANNEL	((UINT16)0x0104)
+#define HFA384x_PDR_DEFAULT_CHANNEL	((UINT16)0x0105)
+//#define HFA384x_PDR_PRIVACY_OPTION	((UINT16)0x0106)
+#define HFA384x_PDR_TEMPTYPE		((UINT16)0x0107)
+//#define HFA384x_PDR_REFDAC_SETUP	((UINT16)0x0110)
+//#define HFA384x_PDR_VGDAC_SETUP		((UINT16)0x0120)
+//#define HFA384x_PDR_LEVEL_COMP_SETUP	((UINT16)0x0130)
+//#define HFA384x_PDR_TRIMDAC_SETUP	((UINT16)0x0140)
+#define HFA384x_PDR_IFR_SETTING		((UINT16)0x0200)
+#define HFA384x_PDR_RFR_SETTING		((UINT16)0x0201)
+#define HFA384x_PDR_HFA3861_BASELINE	((UINT16)0x0202)
+#define HFA384x_PDR_HFA3861_SHADOW	((UINT16)0x0203)
+#define HFA384x_PDR_HFA3861_IFRF	((UINT16)0x0204)
+#define HFA384x_PDR_HFA3861_CHCALSP	((UINT16)0x0300)
+#define HFA384x_PDR_HFA3861_CHCALI	((UINT16)0x0301)
+#define HFA384x_PDR_MAX_TX_POWER  	((UINT16)0x0302)
+#define HFA384x_PDR_MASTER_CHAN_LIST	((UINT16)0x0303)
+#define HFA384x_PDR_3842_NIC_CONFIG	((UINT16)0x0400)
+#define HFA384x_PDR_USB_ID		((UINT16)0x0401)
+#define HFA384x_PDR_PCI_ID		((UINT16)0x0402)
+#define HFA384x_PDR_PCI_IFCONF		((UINT16)0x0403)
+#define HFA384x_PDR_PCI_PMCONF		((UINT16)0x0404)
+#define HFA384x_PDR_RFENRGY		((UINT16)0x0406)
+#define HFA384x_PDR_USB_POWER_TYPE      ((UINT16)0x0407)
+//#define HFA384x_PDR_UNKNOWN408		((UINT16)0x0408)
+#define HFA384x_PDR_USB_MAX_POWER	((UINT16)0x0409)
+#define HFA384x_PDR_USB_MANUFACTURER	((UINT16)0x0410)
+#define HFA384x_PDR_USB_PRODUCT  	((UINT16)0x0411)
+#define HFA384x_PDR_ANT_DIVERSITY   	((UINT16)0x0412)
+#define HFA384x_PDR_HFO_DELAY       	((UINT16)0x0413)
+#define HFA384x_PDR_SCALE_THRESH 	((UINT16)0x0414)
+
+#define HFA384x_PDR_HFA3861_MANF_TESTSP	((UINT16)0x0900)
+#define HFA384x_PDR_HFA3861_MANF_TESTI	((UINT16)0x0901)
+#define HFA384x_PDR_END_OF_PDA		((UINT16)0x0000)
+
+
+/*=============================================================*/
+/*------ Macros -----------------------------------------------*/
+
+/*--- Register ID macros ------------------------*/
+
+#define		HFA384x_CMD		HFA384x_CMD_OFF
+#define		HFA384x_PARAM0		HFA384x_PARAM0_OFF
+#define		HFA384x_PARAM1		HFA384x_PARAM1_OFF
+#define		HFA384x_PARAM2		HFA384x_PARAM2_OFF
+#define		HFA384x_STATUS		HFA384x_STATUS_OFF
+#define		HFA384x_RESP0		HFA384x_RESP0_OFF
+#define		HFA384x_RESP1		HFA384x_RESP1_OFF
+#define		HFA384x_RESP2		HFA384x_RESP2_OFF
+#define		HFA384x_INFOFID		HFA384x_INFOFID_OFF
+#define		HFA384x_RXFID		HFA384x_RXFID_OFF
+#define		HFA384x_ALLOCFID	HFA384x_ALLOCFID_OFF
+#define		HFA384x_TXCOMPLFID	HFA384x_TXCOMPLFID_OFF
+#define		HFA384x_SELECT0		HFA384x_SELECT0_OFF
+#define		HFA384x_OFFSET0		HFA384x_OFFSET0_OFF
+#define		HFA384x_DATA0		HFA384x_DATA0_OFF
+#define		HFA384x_SELECT1		HFA384x_SELECT1_OFF
+#define		HFA384x_OFFSET1		HFA384x_OFFSET1_OFF
+#define		HFA384x_DATA1		HFA384x_DATA1_OFF
+#define		HFA384x_EVSTAT		HFA384x_EVSTAT_OFF
+#define		HFA384x_INTEN		HFA384x_INTEN_OFF
+#define		HFA384x_EVACK		HFA384x_EVACK_OFF
+#define		HFA384x_CONTROL		HFA384x_CONTROL_OFF
+#define		HFA384x_SWSUPPORT0	HFA384x_SWSUPPORT0_OFF
+#define		HFA384x_SWSUPPORT1	HFA384x_SWSUPPORT1_OFF
+#define		HFA384x_SWSUPPORT2	HFA384x_SWSUPPORT2_OFF
+#define		HFA384x_AUXPAGE		HFA384x_AUXPAGE_OFF
+#define		HFA384x_AUXOFFSET	HFA384x_AUXOFFSET_OFF
+#define		HFA384x_AUXDATA		HFA384x_AUXDATA_OFF
+#define		HFA384x_PCICOR		HFA384x_PCICOR_OFF
+#define		HFA384x_PCIHCR		HFA384x_PCIHCR_OFF
+
+
+/*--- Register Test/Get/Set Field macros ------------------------*/
+
+#define		HFA384x_CMD_ISBUSY(value)		((UINT16)(((UINT16)value) & HFA384x_CMD_BUSY))
+#define		HFA384x_CMD_AINFO_GET(value)		((UINT16)(((UINT16)(value) & HFA384x_CMD_AINFO) >> 8))
+#define		HFA384x_CMD_AINFO_SET(value)		((UINT16)((UINT16)(value) << 8))
+#define		HFA384x_CMD_MACPORT_GET(value)		((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_MACPORT)))
+#define		HFA384x_CMD_MACPORT_SET(value)		((UINT16)HFA384x_CMD_AINFO_SET(value))
+#define		HFA384x_CMD_ISRECL(value)		((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_RECL)))
+#define		HFA384x_CMD_RECL_SET(value)		((UINT16)HFA384x_CMD_AINFO_SET(value))
+#define		HFA384x_CMD_QOS_GET(value)		((UINT16((((UINT16)(value))&((UINT16)0x3000)) >> 12))
+#define		HFA384x_CMD_QOS_SET(value)		((UINT16)((((UINT16)(value)) << 12) & 0x3000))
+#define		HFA384x_CMD_ISWRITE(value)		((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_WRITE)))
+#define		HFA384x_CMD_WRITE_SET(value)		((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value))
+#define		HFA384x_CMD_PROGMODE_GET(value)		((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_PROGMODE)))
+#define		HFA384x_CMD_PROGMODE_SET(value)		((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value))
+#define		HFA384x_CMD_CMDCODE_GET(value)		((UINT16)(((UINT16)(value)) & HFA384x_CMD_CMDCODE))
+#define		HFA384x_CMD_CMDCODE_SET(value)		((UINT16)(value))
+
+#define		HFA384x_STATUS_RESULT_GET(value)	((UINT16)((((UINT16)(value)) & HFA384x_STATUS_RESULT) >> 8))
+#define		HFA384x_STATUS_RESULT_SET(value)	(((UINT16)(value)) << 8)
+#define		HFA384x_STATUS_CMDCODE_GET(value)	(((UINT16)(value)) & HFA384x_STATUS_CMDCODE)
+#define		HFA384x_STATUS_CMDCODE_SET(value)	((UINT16)(value))
+
+#define		HFA384x_OFFSET_ISBUSY(value)		((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_BUSY))
+#define		HFA384x_OFFSET_ISERR(value)		((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_ERR))
+#define		HFA384x_OFFSET_DATAOFF_GET(value)	((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_DATAOFF))
+#define		HFA384x_OFFSET_DATAOFF_SET(value)	((UINT16)(value))
+
+#define		HFA384x_EVSTAT_ISTICK(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TICK))
+#define		HFA384x_EVSTAT_ISWTERR(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_WTERR))
+#define		HFA384x_EVSTAT_ISINFDROP(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFDROP))
+#define		HFA384x_EVSTAT_ISINFO(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFO))
+#define		HFA384x_EVSTAT_ISDTIM(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_DTIM))
+#define		HFA384x_EVSTAT_ISCMD(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_CMD))
+#define		HFA384x_EVSTAT_ISALLOC(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_ALLOC))
+#define		HFA384x_EVSTAT_ISTXEXC(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TXEXC))
+#define		HFA384x_EVSTAT_ISTX(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TX))
+#define		HFA384x_EVSTAT_ISRX(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_RX))
+
+#define		HFA384x_EVSTAT_ISBAP_OP(value)		((UINT16)(((UINT16)(value)) & HFA384x_INT_BAP_OP))
+
+#define		HFA384x_INTEN_ISTICK(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TICK))
+#define		HFA384x_INTEN_TICK_SET(value)		((UINT16)(((UINT16)(value)) << 15))
+#define		HFA384x_INTEN_ISWTERR(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_WTERR))
+#define		HFA384x_INTEN_WTERR_SET(value)		((UINT16)(((UINT16)(value)) << 14))
+#define		HFA384x_INTEN_ISINFDROP(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFDROP))
+#define		HFA384x_INTEN_INFDROP_SET(value)	((UINT16)(((UINT16)(value)) << 13))
+#define		HFA384x_INTEN_ISINFO(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFO))
+#define		HFA384x_INTEN_INFO_SET(value)		((UINT16)(((UINT16)(value)) << 7))
+#define		HFA384x_INTEN_ISDTIM(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_DTIM))
+#define		HFA384x_INTEN_DTIM_SET(value)		((UINT16)(((UINT16)(value)) << 5))
+#define		HFA384x_INTEN_ISCMD(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_CMD))
+#define		HFA384x_INTEN_CMD_SET(value)		((UINT16)(((UINT16)(value)) << 4))
+#define		HFA384x_INTEN_ISALLOC(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_ALLOC))
+#define		HFA384x_INTEN_ALLOC_SET(value)		((UINT16)(((UINT16)(value)) << 3))
+#define		HFA384x_INTEN_ISTXEXC(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TXEXC))
+#define		HFA384x_INTEN_TXEXC_SET(value)		((UINT16)(((UINT16)(value)) << 2))
+#define		HFA384x_INTEN_ISTX(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TX))
+#define		HFA384x_INTEN_TX_SET(value)		((UINT16)(((UINT16)(value)) << 1))
+#define		HFA384x_INTEN_ISRX(value)		((UINT16)(((UINT16)(value)) & HFA384x_INTEN_RX))
+#define		HFA384x_INTEN_RX_SET(value)		((UINT16)(((UINT16)(value)) << 0))
+
+#define		HFA384x_EVACK_ISTICK(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TICK))
+#define		HFA384x_EVACK_TICK_SET(value)		((UINT16)(((UINT16)(value)) << 15))
+#define		HFA384x_EVACK_ISWTERR(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_WTERR))
+#define		HFA384x_EVACK_WTERR_SET(value)		((UINT16)(((UINT16)(value)) << 14))
+#define		HFA384x_EVACK_ISINFDROP(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFDROP))
+#define		HFA384x_EVACK_INFDROP_SET(value)	((UINT16)(((UINT16)(value)) << 13))
+#define		HFA384x_EVACK_ISINFO(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFO))
+#define		HFA384x_EVACK_INFO_SET(value)		((UINT16)(((UINT16)(value)) << 7))
+#define		HFA384x_EVACK_ISDTIM(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_DTIM))
+#define		HFA384x_EVACK_DTIM_SET(value)		((UINT16)(((UINT16)(value)) << 5))
+#define		HFA384x_EVACK_ISCMD(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_CMD))
+#define		HFA384x_EVACK_CMD_SET(value)		((UINT16)(((UINT16)(value)) << 4))
+#define		HFA384x_EVACK_ISALLOC(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_ALLOC))
+#define		HFA384x_EVACK_ALLOC_SET(value)		((UINT16)(((UINT16)(value)) << 3))
+#define		HFA384x_EVACK_ISTXEXC(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TXEXC))
+#define		HFA384x_EVACK_TXEXC_SET(value)		((UINT16)(((UINT16)(value)) << 2))
+#define		HFA384x_EVACK_ISTX(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TX))
+#define		HFA384x_EVACK_TX_SET(value)		((UINT16)(((UINT16)(value)) << 1))
+#define		HFA384x_EVACK_ISRX(value)		((UINT16)(((UINT16)(value)) & HFA384x_EVACK_RX))
+#define		HFA384x_EVACK_RX_SET(value)		((UINT16)(((UINT16)(value)) << 0))
+
+#define		HFA384x_CONTROL_AUXEN_SET(value)	((UINT16)(((UINT16)(value)) << 14))
+#define		HFA384x_CONTROL_AUXEN_GET(value)	((UINT16)(((UINT16)(value)) >> 14))
+
+/* Byte Order */
+#ifdef __KERNEL__
+#define hfa384x2host_16(n)	(__le16_to_cpu((UINT16)(n)))
+#define hfa384x2host_32(n)	(__le32_to_cpu((UINT32)(n)))
+#define host2hfa384x_16(n)	(__cpu_to_le16((UINT16)(n)))
+#define host2hfa384x_32(n)	(__cpu_to_le32((UINT32)(n)))
+#endif
+
+/* Host Maintained State Info */
+#define HFA384x_STATE_PREINIT	0
+#define HFA384x_STATE_INIT	1
+#define HFA384x_STATE_RUNNING	2
+
+/*=============================================================*/
+/*------ Types and their related constants --------------------*/
+
+#define HFA384x_HOSTAUTHASSOC_HOSTAUTH   BIT0
+#define HFA384x_HOSTAUTHASSOC_HOSTASSOC  BIT1
+
+#define HFA384x_WHAHANDLING_DISABLED     0
+#define HFA384x_WHAHANDLING_PASSTHROUGH  BIT1
+
+/*-------------------------------------------------------------*/
+/* Commonly used basic types */
+typedef struct hfa384x_bytestr
+{
+	UINT16	len;
+	UINT8	data[0];
+} __WLAN_ATTRIB_PACK__ hfa384x_bytestr_t;
+
+typedef struct hfa384x_bytestr32
+{
+	UINT16	len;
+	UINT8	data[32];
+} __WLAN_ATTRIB_PACK__ hfa384x_bytestr32_t;
+
+/*--------------------------------------------------------------------
+Configuration Record Structures:
+	Network Parameters, Static Configuration Entities
+--------------------------------------------------------------------*/
+/* Prototype structure: all configuration record structures start with
+these members */
+
+typedef struct hfa384x_record 
+{
+	UINT16	reclen;
+	UINT16	rid;
+} __WLAN_ATTRIB_PACK__ hfa384x_rec_t;
+
+typedef struct hfa384x_record16
+{
+	UINT16	reclen;
+	UINT16	rid;
+	UINT16	val;
+} __WLAN_ATTRIB_PACK__ hfa384x_rec16_t;
+
+typedef struct hfa384x_record32
+{
+	UINT16	reclen;
+	UINT16	rid;
+	UINT32	val;
+} __WLAN_ATTRIB_PACK__ hfa384x_rec32;
+
+/*-- Hardware/Firmware Component Information ----------*/
+typedef struct hfa384x_compident
+{
+	UINT16	id;
+	UINT16	variant;
+	UINT16	major;
+	UINT16	minor;
+} __WLAN_ATTRIB_PACK__ hfa384x_compident_t;
+
+typedef struct hfa384x_caplevel
+{
+	UINT16	role;
+	UINT16	id;
+	UINT16	variant;
+	UINT16	bottom;
+	UINT16	top;
+} __WLAN_ATTRIB_PACK__ hfa384x_caplevel_t;
+
+/*-- Configuration Record: cnfPortType --*/
+typedef struct hfa384x_cnfPortType
+{
+	UINT16	cnfPortType;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfPortType_t;
+
+/*-- Configuration Record: cnfOwnMACAddress --*/
+typedef struct hfa384x_cnfOwnMACAddress
+{
+	UINT8	cnfOwnMACAddress[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnMACAddress_t;
+
+/*-- Configuration Record: cnfDesiredSSID --*/
+typedef struct hfa384x_cnfDesiredSSID
+{
+	UINT8	cnfDesiredSSID[34];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfDesiredSSID_t;
+
+/*-- Configuration Record: cnfOwnChannel --*/
+typedef struct hfa384x_cnfOwnChannel
+{
+	UINT16	cnfOwnChannel;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnChannel_t;
+
+/*-- Configuration Record: cnfOwnSSID --*/
+typedef struct hfa384x_cnfOwnSSID
+{
+	UINT8	cnfOwnSSID[34];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnSSID_t;
+
+/*-- Configuration Record: cnfOwnATIMWindow --*/
+typedef struct hfa384x_cnfOwnATIMWindow
+{
+	UINT16	cnfOwnATIMWindow;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnATIMWindow_t;
+
+/*-- Configuration Record: cnfSystemScale --*/
+typedef struct hfa384x_cnfSystemScale
+{
+	UINT16	cnfSystemScale;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfSystemScale_t;
+
+/*-- Configuration Record: cnfMaxDataLength --*/
+typedef struct hfa384x_cnfMaxDataLength
+{
+	UINT16	cnfMaxDataLength;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxDataLength_t;
+
+/*-- Configuration Record: cnfWDSAddress --*/
+typedef struct hfa384x_cnfWDSAddress
+{
+	UINT8	cnfWDSAddress[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddress_t;
+
+/*-- Configuration Record: cnfPMEnabled --*/
+typedef struct hfa384x_cnfPMEnabled
+{
+	UINT16	cnfPMEnabled;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEnabled_t;
+
+/*-- Configuration Record: cnfPMEPS --*/
+typedef struct hfa384x_cnfPMEPS
+{
+	UINT16	cnfPMEPS;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEPS_t;
+
+/*-- Configuration Record: cnfMulticastReceive --*/
+typedef struct hfa384x_cnfMulticastReceive
+{
+	UINT16	cnfMulticastReceive;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastReceive_t;
+
+/*-- Configuration Record: cnfAuthentication --*/
+#define HFA384x_CNFAUTHENTICATION_OPENSYSTEM	0x0001
+#define HFA384x_CNFAUTHENTICATION_SHAREDKEY	0x0002
+#define HFA384x_CNFAUTHENTICATION_LEAP     	0x0004
+
+/*-- Configuration Record: cnfMaxSleepDuration --*/
+typedef struct hfa384x_cnfMaxSleepDuration
+{
+	UINT16	cnfMaxSleepDuration;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxSleepDuration_t;
+
+/*-- Configuration Record: cnfPMHoldoverDuration --*/
+typedef struct hfa384x_cnfPMHoldoverDuration
+{
+	UINT16	cnfPMHoldoverDuration;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMHoldoverDuration_t;
+
+/*-- Configuration Record: cnfOwnName --*/
+typedef struct hfa384x_cnfOwnName
+{
+	UINT8	cnfOwnName[34];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnName_t;
+
+/*-- Configuration Record: cnfOwnDTIMPeriod --*/
+typedef struct hfa384x_cnfOwnDTIMPeriod
+{
+	UINT16	cnfOwnDTIMPeriod;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnDTIMPeriod_t;
+
+/*-- Configuration Record: cnfWDSAddress --*/
+typedef struct hfa384x_cnfWDSAddressN
+{
+	UINT8	cnfWDSAddress[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddressN_t;
+
+/*-- Configuration Record: cnfMulticastPMBuffering --*/
+typedef struct hfa384x_cnfMulticastPMBuffering
+{
+	UINT16	cnfMulticastPMBuffering;
+} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastPMBuffering_t;
+
+/*--------------------------------------------------------------------
+Configuration Record Structures:
+	Network Parameters, Dynamic Configuration Entities
+--------------------------------------------------------------------*/
+
+/*-- Configuration Record: GroupAddresses --*/
+typedef struct hfa384x_GroupAddresses
+{
+	UINT8	MACAddress[16][6];
+} __WLAN_ATTRIB_PACK__ hfa384x_GroupAddresses_t;
+
+/*-- Configuration Record: CreateIBSS --*/
+typedef struct hfa384x_CreateIBSS
+{
+	UINT16	CreateIBSS;
+} __WLAN_ATTRIB_PACK__ hfa384x_CreateIBSS_t;
+
+#define HFA384x_CREATEIBSS_JOINCREATEIBSS          0
+#define HFA384x_CREATEIBSS_JOINESS_JOINCREATEIBSS  1
+#define HFA384x_CREATEIBSS_JOINIBSS                2
+#define HFA384x_CREATEIBSS_JOINESS_JOINIBSS        3
+
+/*-- Configuration Record: FragmentationThreshold --*/
+typedef struct hfa384x_FragmentationThreshold
+{
+	UINT16	FragmentationThreshold;
+} __WLAN_ATTRIB_PACK__ hfa384x_FragmentationThreshold_t;
+
+/*-- Configuration Record: RTSThreshold --*/
+typedef struct hfa384x_RTSThreshold
+{
+	UINT16	RTSThreshold;
+} __WLAN_ATTRIB_PACK__ hfa384x_RTSThreshold_t;
+
+/*-- Configuration Record: TxRateControl --*/
+typedef struct hfa384x_TxRateControl
+{
+	UINT16	TxRateControl;
+} __WLAN_ATTRIB_PACK__ hfa384x_TxRateControl_t;
+
+/*-- Configuration Record: PromiscuousMode --*/
+typedef struct hfa384x_PromiscuousMode
+{
+	UINT16	PromiscuousMode;
+} __WLAN_ATTRIB_PACK__ hfa384x_PromiscuousMode_t;
+
+/*-- Configuration Record: ScanRequest (data portion only) --*/
+typedef struct hfa384x_ScanRequest_data
+{
+	UINT16	channelList;
+	UINT16	txRate;
+} __WLAN_ATTRIB_PACK__ hfa384x_ScanRequest_data_t;
+
+/*-- Configuration Record: HostScanRequest (data portion only) --*/
+typedef struct hfa384x_HostScanRequest_data
+{
+	UINT16	channelList;
+	UINT16	txRate;
+	hfa384x_bytestr32_t ssid;
+} __WLAN_ATTRIB_PACK__ hfa384x_HostScanRequest_data_t;
+
+/*-- Configuration Record: JoinRequest (data portion only) --*/
+typedef struct hfa384x_JoinRequest_data
+{
+	UINT8	bssid[WLAN_BSSID_LEN];
+	UINT16	channel;
+} __WLAN_ATTRIB_PACK__ hfa384x_JoinRequest_data_t;
+
+/*-- Configuration Record: authenticateStation (data portion only) --*/
+typedef struct hfa384x_authenticateStation_data
+{
+	UINT8	address[WLAN_ADDR_LEN];
+	UINT16	status;
+	UINT16	algorithm;
+} __WLAN_ATTRIB_PACK__ hfa384x_authenticateStation_data_t;
+
+/*-- Configuration Record: associateStation (data portion only) --*/
+typedef struct hfa384x_associateStation_data
+{
+	UINT8	address[WLAN_ADDR_LEN];
+	UINT16	status;
+	UINT16	type;
+} __WLAN_ATTRIB_PACK__ hfa384x_associateStation_data_t;
+
+/*-- Configuration Record: ChannelInfoRequest (data portion only) --*/
+typedef struct hfa384x_ChannelInfoRequest_data
+{
+	UINT16	channelList;
+	UINT16	channelDwellTime;
+} __WLAN_ATTRIB_PACK__ hfa384x_ChannelInfoRequest_data_t;
+
+/*-- Configuration Record: WEPKeyMapping (data portion only) --*/
+typedef struct hfa384x_WEPKeyMapping
+{
+	UINT8	address[WLAN_ADDR_LEN];
+	UINT16	key_index;
+	UINT8 	key[16];
+	UINT8 	mic_transmit_key[4];
+	UINT8 	mic_receive_key[4];
+} __WLAN_ATTRIB_PACK__ hfa384x_WEPKeyMapping_t;
+
+/*-- Configuration Record: WPAData       (data portion only) --*/
+typedef struct hfa384x_WPAData
+{
+	UINT16	datalen;
+        UINT8 	data[0]; // max 80
+} __WLAN_ATTRIB_PACK__ hfa384x_WPAData_t;
+
+/*--------------------------------------------------------------------
+Configuration Record Structures: Behavior Parameters
+--------------------------------------------------------------------*/
+
+/*-- Configuration Record: TickTime --*/
+typedef struct hfa384x_TickTime
+{
+	UINT16	TickTime;
+} __WLAN_ATTRIB_PACK__ hfa384x_TickTime_t;
+
+/*--------------------------------------------------------------------
+Information Record Structures: NIC Information
+--------------------------------------------------------------------*/
+
+/*-- Information Record: MaxLoadTime --*/
+typedef struct hfa384x_MaxLoadTime
+{
+	UINT16	MaxLoadTime;
+} __WLAN_ATTRIB_PACK__ hfa384x_MaxLoadTime_t;
+
+/*-- Information Record: DownLoadBuffer --*/
+/* NOTE: The page and offset are in AUX format */
+typedef struct hfa384x_downloadbuffer
+{
+	UINT16	page;
+	UINT16	offset;
+	UINT16	len;
+} __WLAN_ATTRIB_PACK__ hfa384x_downloadbuffer_t;
+
+/*-- Information Record: PRIIdentity --*/
+typedef struct hfa384x_PRIIdentity
+{
+	UINT16	PRICompID;
+	UINT16	PRIVariant;
+	UINT16	PRIMajorVersion;
+	UINT16	PRIMinorVersion;
+} __WLAN_ATTRIB_PACK__ hfa384x_PRIIdentity_t;
+
+/*-- Information Record: PRISupRange --*/
+typedef struct hfa384x_PRISupRange
+{
+	UINT16	PRIRole;
+	UINT16	PRIID;
+	UINT16	PRIVariant;
+	UINT16	PRIBottom;
+	UINT16	PRITop;
+} __WLAN_ATTRIB_PACK__ hfa384x_PRISupRange_t;
+
+/*-- Information Record: CFIActRanges --*/
+typedef struct hfa384x_CFIActRanges
+{
+	UINT16	CFIRole;
+	UINT16	CFIID;
+	UINT16	CFIVariant;
+	UINT16	CFIBottom;
+	UINT16	CFITop;
+} __WLAN_ATTRIB_PACK__ hfa384x_CFIActRanges_t;
+
+/*-- Information Record: NICSerialNumber --*/
+typedef struct hfa384x_NICSerialNumber
+{
+	UINT8	NICSerialNumber[12];
+} __WLAN_ATTRIB_PACK__ hfa384x_NICSerialNumber_t;
+
+/*-- Information Record: NICIdentity --*/
+typedef struct hfa384x_NICIdentity
+{
+	UINT16	NICCompID;
+	UINT16	NICVariant;
+	UINT16	NICMajorVersion;
+	UINT16	NICMinorVersion;
+} __WLAN_ATTRIB_PACK__ hfa384x_NICIdentity_t;
+
+/*-- Information Record: MFISupRange --*/
+typedef struct hfa384x_MFISupRange
+{
+	UINT16	MFIRole;
+	UINT16	MFIID;
+	UINT16	MFIVariant;
+	UINT16	MFIBottom;
+	UINT16	MFITop;
+} __WLAN_ATTRIB_PACK__ hfa384x_MFISupRange_t;
+
+/*-- Information Record: CFISupRange --*/
+typedef struct hfa384x_CFISupRange
+{
+	UINT16	CFIRole;
+	UINT16	CFIID;
+	UINT16	CFIVariant;
+	UINT16	CFIBottom;
+	UINT16	CFITop;
+} __WLAN_ATTRIB_PACK__ hfa384x_CFISupRange_t;
+
+/*-- Information Record: BUILDSEQ:BuildSeq --*/
+typedef struct hfa384x_BuildSeq {
+	UINT16	primary;
+	UINT16	secondary;
+} __WLAN_ATTRIB_PACK__ hfa384x_BuildSeq_t;
+
+/*-- Information Record: FWID --*/
+#define HFA384x_FWID_LEN	14
+typedef struct hfa384x_FWID {
+	UINT8	primary[HFA384x_FWID_LEN];
+	UINT8	secondary[HFA384x_FWID_LEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_FWID_t;
+
+/*-- Information Record: ChannelList --*/
+typedef struct hfa384x_ChannelList
+{
+	UINT16	ChannelList;
+} __WLAN_ATTRIB_PACK__ hfa384x_ChannelList_t;
+
+/*-- Information Record: RegulatoryDomains --*/
+typedef struct hfa384x_RegulatoryDomains
+{
+	UINT8	RegulatoryDomains[12];
+} __WLAN_ATTRIB_PACK__ hfa384x_RegulatoryDomains_t;
+
+/*-- Information Record: TempType --*/
+typedef struct hfa384x_TempType
+{
+	UINT16	TempType;
+} __WLAN_ATTRIB_PACK__ hfa384x_TempType_t;
+
+/*-- Information Record: CIS --*/
+typedef struct hfa384x_CIS
+{
+	UINT8	CIS[480];
+} __WLAN_ATTRIB_PACK__ hfa384x_CIS_t;
+
+/*-- Information Record: STAIdentity --*/
+typedef struct hfa384x_STAIdentity
+{
+	UINT16	STACompID;
+	UINT16	STAVariant;
+	UINT16	STAMajorVersion;
+	UINT16	STAMinorVersion;
+} __WLAN_ATTRIB_PACK__ hfa384x_STAIdentity_t;
+
+/*-- Information Record: STASupRange --*/
+typedef struct hfa384x_STASupRange
+{
+	UINT16	STARole;
+	UINT16	STAID;
+	UINT16	STAVariant;
+	UINT16	STABottom;
+	UINT16	STATop;
+} __WLAN_ATTRIB_PACK__ hfa384x_STASupRange_t;
+
+/*-- Information Record: MFIActRanges --*/
+typedef struct hfa384x_MFIActRanges
+{
+	UINT16	MFIRole;
+	UINT16	MFIID;
+	UINT16	MFIVariant;
+	UINT16	MFIBottom;
+	UINT16	MFITop;
+} __WLAN_ATTRIB_PACK__ hfa384x_MFIActRanges_t;
+
+/*--------------------------------------------------------------------
+Information Record Structures: NIC Information
+--------------------------------------------------------------------*/
+
+/*-- Information Record: PortStatus --*/
+typedef struct hfa384x_PortStatus
+{
+	UINT16	PortStatus;
+} __WLAN_ATTRIB_PACK__ hfa384x_PortStatus_t;
+
+#define HFA384x_PSTATUS_DISABLED	((UINT16)1)
+#define HFA384x_PSTATUS_SEARCHING	((UINT16)2)
+#define HFA384x_PSTATUS_CONN_IBSS	((UINT16)3)
+#define HFA384x_PSTATUS_CONN_ESS	((UINT16)4)
+#define HFA384x_PSTATUS_OUTOFRANGE	((UINT16)5)
+#define HFA384x_PSTATUS_CONN_WDS	((UINT16)6)
+
+/*-- Information Record: CurrentSSID --*/
+typedef struct hfa384x_CurrentSSID
+{
+	UINT8	CurrentSSID[34];
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentSSID_t;
+
+/*-- Information Record: CurrentBSSID --*/
+typedef struct hfa384x_CurrentBSSID
+{
+	UINT8	CurrentBSSID[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBSSID_t;
+
+/*-- Information Record: commsquality --*/
+typedef struct hfa384x_commsquality
+{
+	UINT16	CQ_currBSS;
+	UINT16	ASL_currBSS;
+	UINT16	ANL_currFC;
+} __WLAN_ATTRIB_PACK__ hfa384x_commsquality_t;
+
+/*-- Information Record: dmbcommsquality --*/
+typedef struct hfa384x_dbmcommsquality
+{
+	UINT16	CQdbm_currBSS;
+	UINT16	ASLdbm_currBSS;
+	UINT16	ANLdbm_currFC;
+} __WLAN_ATTRIB_PACK__ hfa384x_dbmcommsquality_t;
+
+/*-- Information Record: CurrentTxRate --*/
+typedef struct hfa384x_CurrentTxRate
+{
+	UINT16	CurrentTxRate;
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentTxRate_t;
+
+/*-- Information Record: CurrentBeaconInterval --*/
+typedef struct hfa384x_CurrentBeaconInterval
+{
+	UINT16	CurrentBeaconInterval;
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBeaconInterval_t;
+
+/*-- Information Record: CurrentScaleThresholds --*/
+typedef struct hfa384x_CurrentScaleThresholds
+{
+	UINT16	EnergyDetectThreshold;
+	UINT16	CarrierDetectThreshold;
+	UINT16	DeferDetectThreshold;
+	UINT16	CellSearchThreshold; /* Stations only */
+	UINT16	DeadSpotThreshold; /* Stations only */
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentScaleThresholds_t;
+
+/*-- Information Record: ProtocolRspTime --*/
+typedef struct hfa384x_ProtocolRspTime
+{
+	UINT16	ProtocolRspTime;
+} __WLAN_ATTRIB_PACK__ hfa384x_ProtocolRspTime_t;
+
+/*-- Information Record: ShortRetryLimit --*/
+typedef struct hfa384x_ShortRetryLimit
+{
+	UINT16	ShortRetryLimit;
+} __WLAN_ATTRIB_PACK__ hfa384x_ShortRetryLimit_t;
+
+/*-- Information Record: LongRetryLimit --*/
+typedef struct hfa384x_LongRetryLimit
+{
+	UINT16	LongRetryLimit;
+} __WLAN_ATTRIB_PACK__ hfa384x_LongRetryLimit_t;
+
+/*-- Information Record: MaxTransmitLifetime --*/
+typedef struct hfa384x_MaxTransmitLifetime
+{
+	UINT16	MaxTransmitLifetime;
+} __WLAN_ATTRIB_PACK__ hfa384x_MaxTransmitLifetime_t;
+
+/*-- Information Record: MaxReceiveLifetime --*/
+typedef struct hfa384x_MaxReceiveLifetime
+{
+	UINT16	MaxReceiveLifetime;
+} __WLAN_ATTRIB_PACK__ hfa384x_MaxReceiveLifetime_t;
+
+/*-- Information Record: CFPollable --*/
+typedef struct hfa384x_CFPollable
+{
+	UINT16	CFPollable;
+} __WLAN_ATTRIB_PACK__ hfa384x_CFPollable_t;
+
+/*-- Information Record: AuthenticationAlgorithms --*/
+typedef struct hfa384x_AuthenticationAlgorithms
+{
+	UINT16	AuthenticationType;
+	UINT16	TypeEnabled;
+} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_t;
+
+/*-- Information Record: AuthenticationAlgorithms
+(data only --*/
+typedef struct hfa384x_AuthenticationAlgorithms_data
+{
+	UINT16	AuthenticationType;
+	UINT16	TypeEnabled;
+} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_data_t;
+
+/*-- Information Record: PrivacyOptionImplemented --*/
+typedef struct hfa384x_PrivacyOptionImplemented
+{
+	UINT16	PrivacyOptionImplemented;
+} __WLAN_ATTRIB_PACK__ hfa384x_PrivacyOptionImplemented_t;
+
+/*-- Information Record: OwnMACAddress --*/
+typedef struct hfa384x_OwnMACAddress
+{
+	UINT8	OwnMACAddress[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_OwnMACAddress_t;
+
+/*-- Information Record: PCFInfo --*/
+typedef struct hfa384x_PCFInfo
+{
+	UINT16	MediumOccupancyLimit;
+	UINT16	CFPPeriod;
+	UINT16	CFPMaxDuration;
+	UINT16	CFPFlags;
+} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_t;
+
+/*-- Information Record: PCFInfo (data portion only) --*/
+typedef struct hfa384x_PCFInfo_data
+{
+	UINT16	MediumOccupancyLimit;
+	UINT16	CFPPeriod;
+	UINT16	CFPMaxDuration;
+	UINT16	CFPFlags;
+} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_data_t;
+
+/*--------------------------------------------------------------------
+Information Record Structures: Modem Information Records 
+--------------------------------------------------------------------*/
+
+/*-- Information Record: PHYType --*/
+typedef struct hfa384x_PHYType
+{
+	UINT16	PHYType;
+} __WLAN_ATTRIB_PACK__ hfa384x_PHYType_t;
+
+/*-- Information Record: CurrentChannel --*/
+typedef struct hfa384x_CurrentChannel
+{
+	UINT16	CurrentChannel;
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentChannel_t;
+
+/*-- Information Record: CurrentPowerState --*/
+typedef struct hfa384x_CurrentPowerState
+{
+	UINT16	CurrentPowerState;
+} __WLAN_ATTRIB_PACK__ hfa384x_CurrentPowerState_t;
+
+/*-- Information Record: CCAMode --*/
+typedef struct hfa384x_CCAMode
+{
+	UINT16	CCAMode;
+} __WLAN_ATTRIB_PACK__ hfa384x_CCAMode_t;
+
+/*-- Information Record: SupportedDataRates --*/
+typedef struct hfa384x_SupportedDataRates
+{
+	UINT8	SupportedDataRates[10];
+} __WLAN_ATTRIB_PACK__ hfa384x_SupportedDataRates_t;
+
+/*-- Information Record: LFOStatus --*/
+typedef struct hfa384x_LFOStatus          
+{
+	UINT16  TestResults;
+	UINT16  LFOResult;
+	UINT16  VRHFOResult;
+} __WLAN_ATTRIB_PACK__ hfa384x_LFOStatus_t;
+
+#define HFA384x_TESTRESULT_ALLPASSED    BIT0
+#define HFA384x_TESTRESULT_LFO_FAIL     BIT1
+#define HFA384x_TESTRESULT_VR_HF0_FAIL  BIT2
+#define HFA384x_HOST_FIRM_COORDINATE    BIT7
+#define HFA384x_TESTRESULT_COORDINATE   BIT15
+
+/*-- Information Record: LEDControl --*/
+typedef struct hfa384x_LEDControl
+{
+	UINT16  searching_on;
+	UINT16  searching_off;
+	UINT16  assoc_on;
+	UINT16  assoc_off;
+	UINT16  activity;
+} __WLAN_ATTRIB_PACK__ hfa384x_LEDControl_t;
+
+/*--------------------------------------------------------------------
+                 FRAME DESCRIPTORS AND FRAME STRUCTURES
+
+FRAME DESCRIPTORS: Offsets
+
+----------------------------------------------------------------------
+Control Info (offset 44-51)
+--------------------------------------------------------------------*/
+#define		HFA384x_FD_STATUS_OFF			((UINT16)0x44)
+#define		HFA384x_FD_TIME_OFF			((UINT16)0x46)
+#define		HFA384x_FD_SWSUPPORT_OFF		((UINT16)0x4A)
+#define		HFA384x_FD_SILENCE_OFF			((UINT16)0x4A)
+#define		HFA384x_FD_SIGNAL_OFF			((UINT16)0x4B)
+#define		HFA384x_FD_RATE_OFF			((UINT16)0x4C)
+#define		HFA384x_FD_RXFLOW_OFF			((UINT16)0x4D)
+#define		HFA384x_FD_RESERVED_OFF			((UINT16)0x4E)
+#define		HFA384x_FD_TXCONTROL_OFF		((UINT16)0x50)
+/*--------------------------------------------------------------------
+802.11 Header (offset 52-6B)
+--------------------------------------------------------------------*/
+#define		HFA384x_FD_FRAMECONTROL_OFF		((UINT16)0x52)
+#define		HFA384x_FD_DURATIONID_OFF		((UINT16)0x54)
+#define		HFA384x_FD_ADDRESS1_OFF			((UINT16)0x56)
+#define		HFA384x_FD_ADDRESS2_OFF			((UINT16)0x5C)
+#define		HFA384x_FD_ADDRESS3_OFF			((UINT16)0x62)
+#define		HFA384x_FD_SEQCONTROL_OFF		((UINT16)0x68)
+#define		HFA384x_FD_ADDRESS4_OFF			((UINT16)0x6A)
+#define		HFA384x_FD_DATALEN_OFF			((UINT16)0x70) 
+/*--------------------------------------------------------------------
+802.3 Header (offset 72-7F)
+--------------------------------------------------------------------*/
+#define		HFA384x_FD_DESTADDRESS_OFF		((UINT16)0x72)
+#define		HFA384x_FD_SRCADDRESS_OFF		((UINT16)0x78)
+#define		HFA384x_FD_DATALENGTH_OFF		((UINT16)0x7E)
+
+/*--------------------------------------------------------------------
+FRAME STRUCTURES: Communication Frames
+----------------------------------------------------------------------
+Communication Frames: Transmit Frames
+--------------------------------------------------------------------*/
+/*-- Communication Frame: Transmit Frame Structure --*/
+typedef struct hfa384x_tx_frame
+{
+	UINT16	status;
+	UINT16	reserved1;
+	UINT16	reserved2;
+	UINT32	sw_support;
+	UINT8	tx_retrycount;
+	UINT8   tx_rate;
+	UINT16	tx_control;
+
+	/*-- 802.11 Header Information --*/
+
+	UINT16	frame_control;
+	UINT16	duration_id;
+	UINT8	address1[6];
+	UINT8	address2[6];
+	UINT8	address3[6];
+	UINT16	sequence_control;
+	UINT8	address4[6];
+	UINT16	data_len; /* little endian format */
+
+	/*-- 802.3 Header Information --*/
+
+	UINT8	dest_addr[6];
+	UINT8	src_addr[6];
+	UINT16	data_length; /* big endian format */
+} __WLAN_ATTRIB_PACK__ hfa384x_tx_frame_t;
+/*--------------------------------------------------------------------
+Communication Frames: Field Masks for Transmit Frames
+--------------------------------------------------------------------*/
+/*-- Status Field --*/
+#define		HFA384x_TXSTATUS_ACKERR			((UINT16)BIT5)
+#define		HFA384x_TXSTATUS_FORMERR		((UINT16)BIT3)
+#define		HFA384x_TXSTATUS_DISCON			((UINT16)BIT2)
+#define		HFA384x_TXSTATUS_AGEDERR		((UINT16)BIT1)
+#define		HFA384x_TXSTATUS_RETRYERR		((UINT16)BIT0)
+/*-- Transmit Control Field --*/
+#define		HFA384x_TX_CFPOLL			((UINT16)BIT12)
+#define		HFA384x_TX_PRST				((UINT16)BIT11)
+#define		HFA384x_TX_MACPORT			((UINT16)(BIT10 | BIT9 | BIT8))
+#define		HFA384x_TX_NOENCRYPT			((UINT16)BIT7)
+#define		HFA384x_TX_RETRYSTRAT			((UINT16)(BIT6 | BIT5))
+#define		HFA384x_TX_STRUCTYPE			((UINT16)(BIT4 | BIT3))
+#define		HFA384x_TX_TXEX				((UINT16)BIT2)
+#define		HFA384x_TX_TXOK				((UINT16)BIT1)
+/*--------------------------------------------------------------------
+Communication Frames: Test/Get/Set Field Values for Transmit Frames
+--------------------------------------------------------------------*/
+/*-- Status Field --*/
+#define HFA384x_TXSTATUS_ISERROR(v)	\
+	(((UINT16)(v))&\
+	(HFA384x_TXSTATUS_ACKERR|HFA384x_TXSTATUS_FORMERR|\
+	HFA384x_TXSTATUS_DISCON|HFA384x_TXSTATUS_AGEDERR|\
+	HFA384x_TXSTATUS_RETRYERR))
+
+#define	HFA384x_TXSTATUS_ISACKERR(v)	((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_ACKERR))
+#define	HFA384x_TXSTATUS_ISFORMERR(v)	((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_FORMERR))
+#define	HFA384x_TXSTATUS_ISDISCON(v)	((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_DISCON))
+#define	HFA384x_TXSTATUS_ISAGEDERR(v)	((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_AGEDERR))
+#define	HFA384x_TXSTATUS_ISRETRYERR(v)	((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_RETRYERR))
+
+#define	HFA384x_TX_GET(v,m,s)		((((UINT16)(v))&((UINT16)(m)))>>((UINT16)(s)))
+#define	HFA384x_TX_SET(v,m,s)		((((UINT16)(v))<<((UINT16)(s)))&((UINT16)(m)))
+
+#define	HFA384x_TX_CFPOLL_GET(v)	HFA384x_TX_GET(v, HFA384x_TX_CFPOLL,12)
+#define	HFA384x_TX_CFPOLL_SET(v)	HFA384x_TX_SET(v, HFA384x_TX_CFPOLL,12)
+#define	HFA384x_TX_PRST_GET(v)		HFA384x_TX_GET(v, HFA384x_TX_PRST,11)
+#define	HFA384x_TX_PRST_SET(v)		HFA384x_TX_SET(v, HFA384x_TX_PRST,11)
+#define	HFA384x_TX_MACPORT_GET(v)	HFA384x_TX_GET(v, HFA384x_TX_MACPORT, 8)
+#define	HFA384x_TX_MACPORT_SET(v)	HFA384x_TX_SET(v, HFA384x_TX_MACPORT, 8)
+#define	HFA384x_TX_NOENCRYPT_GET(v)	HFA384x_TX_GET(v, HFA384x_TX_NOENCRYPT, 7)
+#define	HFA384x_TX_NOENCRYPT_SET(v)	HFA384x_TX_SET(v, HFA384x_TX_NOENCRYPT, 7)
+#define	HFA384x_TX_RETRYSTRAT_GET(v)	HFA384x_TX_GET(v, HFA384x_TX_RETRYSTRAT, 5)
+#define	HFA384x_TX_RETRYSTRAT_SET(v)	HFA384x_TX_SET(v, HFA384x_TX_RETRYSTRAT, 5)
+#define	HFA384x_TX_STRUCTYPE_GET(v)	HFA384x_TX_GET(v, HFA384x_TX_STRUCTYPE, 3)
+#define	HFA384x_TX_STRUCTYPE_SET(v)	HFA384x_TX_SET(v, HFA384x_TX_STRUCTYPE, 3)
+#define	HFA384x_TX_TXEX_GET(v)		HFA384x_TX_GET(v, HFA384x_TX_TXEX, 2)
+#define	HFA384x_TX_TXEX_SET(v)		HFA384x_TX_SET(v, HFA384x_TX_TXEX, 2)
+#define	HFA384x_TX_TXOK_GET(v)		HFA384x_TX_GET(v, HFA384x_TX_TXOK, 1)
+#define	HFA384x_TX_TXOK_SET(v)		HFA384x_TX_SET(v, HFA384x_TX_TXOK, 1)
+/*--------------------------------------------------------------------
+Communication Frames: Receive Frames
+--------------------------------------------------------------------*/
+/*-- Communication Frame: Receive Frame Structure --*/
+typedef struct hfa384x_rx_frame
+{
+	/*-- MAC rx descriptor (hfa384x byte order) --*/
+	UINT16	status;
+	UINT32	time;
+	UINT8	silence;
+	UINT8	signal;
+	UINT8	rate;
+	UINT8	rx_flow;
+	UINT16	reserved1;
+	UINT16	reserved2;
+
+	/*-- 802.11 Header Information (802.11 byte order) --*/
+	UINT16	frame_control;
+	UINT16	duration_id;
+	UINT8	address1[6];
+	UINT8	address2[6];
+	UINT8	address3[6];
+	UINT16	sequence_control;
+	UINT8	address4[6];
+	UINT16	data_len; /* hfa384x (little endian) format */
+
+	/*-- 802.3 Header Information --*/
+	UINT8	dest_addr[6];
+	UINT8	src_addr[6];
+	UINT16	data_length; /* IEEE? (big endian) format */
+} __WLAN_ATTRIB_PACK__ hfa384x_rx_frame_t;
+/*--------------------------------------------------------------------
+Communication Frames: Field Masks for Receive Frames
+--------------------------------------------------------------------*/
+/*-- Offsets --------*/
+#define		HFA384x_RX_DATA_LEN_OFF			((UINT16)44)
+#define		HFA384x_RX_80211HDR_OFF			((UINT16)14)
+#define		HFA384x_RX_DATA_OFF			((UINT16)60)
+
+/*-- Status Fields --*/
+#define		HFA384x_RXSTATUS_MSGTYPE		((UINT16)(BIT15 | BIT14 | BIT13))
+#define		HFA384x_RXSTATUS_MACPORT		((UINT16)(BIT10 | BIT9 | BIT8))
+#define		HFA384x_RXSTATUS_UNDECR			((UINT16)BIT1)
+#define		HFA384x_RXSTATUS_FCSERR			((UINT16)BIT0)
+/*--------------------------------------------------------------------
+Communication Frames: Test/Get/Set Field Values for Receive Frames
+--------------------------------------------------------------------*/
+#define		HFA384x_RXSTATUS_MSGTYPE_GET(value)	((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MSGTYPE) >> 13))
+#define		HFA384x_RXSTATUS_MSGTYPE_SET(value)	((UINT16)(((UINT16)(value)) << 13))
+#define		HFA384x_RXSTATUS_MACPORT_GET(value)	((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8))
+#define		HFA384x_RXSTATUS_MACPORT_SET(value)	((UINT16)(((UINT16)(value)) << 8))
+#define		HFA384x_RXSTATUS_ISUNDECR(value)	((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_UNDECR))
+#define		HFA384x_RXSTATUS_ISFCSERR(value)	((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_FCSERR))
+/*--------------------------------------------------------------------
+ FRAME STRUCTURES: Information Types and Information Frame Structures
+----------------------------------------------------------------------
+Information Types
+--------------------------------------------------------------------*/
+#define		HFA384x_IT_HANDOVERADDR			((UINT16)0xF000UL)
+#define		HFA384x_IT_HANDOVERDEAUTHADDRESS	((UINT16)0xF001UL)//AP 1.3.7
+#define		HFA384x_IT_COMMTALLIES			((UINT16)0xF100UL)
+#define		HFA384x_IT_SCANRESULTS			((UINT16)0xF101UL)
+#define		HFA384x_IT_CHINFORESULTS		((UINT16)0xF102UL)
+#define		HFA384x_IT_HOSTSCANRESULTS		((UINT16)0xF103UL)
+#define		HFA384x_IT_LINKSTATUS			((UINT16)0xF200UL)
+#define		HFA384x_IT_ASSOCSTATUS			((UINT16)0xF201UL)
+#define		HFA384x_IT_AUTHREQ			((UINT16)0xF202UL)
+#define		HFA384x_IT_PSUSERCNT			((UINT16)0xF203UL)
+#define		HFA384x_IT_KEYIDCHANGED			((UINT16)0xF204UL)
+#define		HFA384x_IT_ASSOCREQ    			((UINT16)0xF205UL)
+#define		HFA384x_IT_MICFAILURE  			((UINT16)0xF206UL)
+
+/*--------------------------------------------------------------------
+Information Frames Structures
+----------------------------------------------------------------------
+Information Frames: Notification Frame Structures
+--------------------------------------------------------------------*/
+/*--  Notification Frame,MAC Mgmt: Handover Address --*/
+typedef struct hfa384x_HandoverAddr
+{
+	UINT16	framelen;
+	UINT16	infotype;
+	UINT8	handover_addr[WLAN_BSSID_LEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_HandoverAddr_t;
+
+/*--  Inquiry Frame, Diagnose: Communication Tallies --*/
+typedef struct hfa384x_CommTallies16
+{
+	UINT16	txunicastframes;
+	UINT16	txmulticastframes;
+	UINT16	txfragments;
+	UINT16	txunicastoctets;
+	UINT16	txmulticastoctets;
+	UINT16	txdeferredtrans;
+	UINT16	txsingleretryframes;
+	UINT16	txmultipleretryframes;
+	UINT16	txretrylimitexceeded;
+	UINT16	txdiscards;
+	UINT16	rxunicastframes;
+	UINT16	rxmulticastframes;
+	UINT16	rxfragments;
+	UINT16	rxunicastoctets;
+	UINT16	rxmulticastoctets;
+	UINT16	rxfcserrors;
+	UINT16	rxdiscardsnobuffer;
+	UINT16	txdiscardswrongsa;
+	UINT16	rxdiscardswepundecr;
+	UINT16	rxmsginmsgfrag;
+	UINT16	rxmsginbadmsgfrag;
+} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies16_t;
+
+typedef struct hfa384x_CommTallies32
+{
+	UINT32	txunicastframes;
+	UINT32	txmulticastframes;
+	UINT32	txfragments;
+	UINT32	txunicastoctets;
+	UINT32	txmulticastoctets;
+	UINT32	txdeferredtrans;
+	UINT32	txsingleretryframes;
+	UINT32	txmultipleretryframes;
+	UINT32	txretrylimitexceeded;
+	UINT32	txdiscards;
+	UINT32	rxunicastframes;
+	UINT32	rxmulticastframes;
+	UINT32	rxfragments;
+	UINT32	rxunicastoctets;
+	UINT32	rxmulticastoctets;
+	UINT32	rxfcserrors;
+	UINT32	rxdiscardsnobuffer;
+	UINT32	txdiscardswrongsa;
+	UINT32	rxdiscardswepundecr;
+	UINT32	rxmsginmsgfrag;
+	UINT32	rxmsginbadmsgfrag;
+} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies32_t;
+
+/*--  Inquiry Frame, Diagnose: Scan Results & Subfields--*/
+typedef struct hfa384x_ScanResultSub
+{
+	UINT16	chid;
+	UINT16	anl;
+	UINT16	sl;
+	UINT8	bssid[WLAN_BSSID_LEN];
+	UINT16	bcnint;
+	UINT16	capinfo;
+	hfa384x_bytestr32_t	ssid;
+	UINT8	supprates[10]; /* 802.11 info element */
+	UINT16	proberesp_rate;
+} __WLAN_ATTRIB_PACK__ hfa384x_ScanResultSub_t;
+
+typedef struct hfa384x_ScanResult
+{
+	UINT16	rsvd;
+	UINT16	scanreason;
+	hfa384x_ScanResultSub_t
+		result[HFA384x_SCANRESULT_MAX];
+} __WLAN_ATTRIB_PACK__ hfa384x_ScanResult_t;
+
+/*--  Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/
+typedef struct hfa384x_ChInfoResultSub
+{
+	UINT16	chid;
+	UINT16	anl;
+	UINT16	pnl;
+	UINT16	active;
+} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResultSub_t;
+
+#define HFA384x_CHINFORESULT_BSSACTIVE	BIT0
+#define HFA384x_CHINFORESULT_PCFACTIVE	BIT1
+
+typedef struct hfa384x_ChInfoResult
+{
+	UINT16	scanchannels;
+	hfa384x_ChInfoResultSub_t	
+		result[HFA384x_CHINFORESULT_MAX];
+} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResult_t;
+
+/*--  Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/
+typedef struct hfa384x_HScanResultSub
+{
+	UINT16	chid;
+	UINT16	anl;
+	UINT16	sl;
+	UINT8	bssid[WLAN_BSSID_LEN];
+	UINT16	bcnint;
+	UINT16	capinfo;
+	hfa384x_bytestr32_t	ssid;
+	UINT8	supprates[10]; /* 802.11 info element */
+	UINT16	proberesp_rate;
+	UINT16	atim;
+} __WLAN_ATTRIB_PACK__ hfa384x_HScanResultSub_t;
+
+typedef struct hfa384x_HScanResult
+{
+	UINT16	nresult;
+	UINT16	rsvd;
+	hfa384x_HScanResultSub_t
+		result[HFA384x_HSCANRESULT_MAX];
+} __WLAN_ATTRIB_PACK__ hfa384x_HScanResult_t;
+
+/*--  Unsolicited Frame, MAC Mgmt: LinkStatus --*/
+
+#define HFA384x_LINK_NOTCONNECTED	((UINT16)0)
+#define HFA384x_LINK_CONNECTED		((UINT16)1)
+#define HFA384x_LINK_DISCONNECTED	((UINT16)2)
+#define HFA384x_LINK_AP_CHANGE		((UINT16)3)
+#define HFA384x_LINK_AP_OUTOFRANGE	((UINT16)4)
+#define HFA384x_LINK_AP_INRANGE		((UINT16)5)
+#define HFA384x_LINK_ASSOCFAIL		((UINT16)6)
+
+typedef struct hfa384x_LinkStatus
+{
+	UINT16	linkstatus;
+} __WLAN_ATTRIB_PACK__ hfa384x_LinkStatus_t;
+
+
+/*--  Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/
+
+#define HFA384x_ASSOCSTATUS_STAASSOC	((UINT16)1)
+#define HFA384x_ASSOCSTATUS_REASSOC	((UINT16)2)
+#define HFA384x_ASSOCSTATUS_DISASSOC	((UINT16)3)
+#define HFA384x_ASSOCSTATUS_ASSOCFAIL	((UINT16)4)
+#define HFA384x_ASSOCSTATUS_AUTHFAIL	((UINT16)5)
+
+typedef struct hfa384x_AssocStatus
+{
+	UINT16	assocstatus;
+	UINT8	sta_addr[WLAN_ADDR_LEN];
+	/* old_ap_addr is only valid if assocstatus == 2 */
+	UINT8	old_ap_addr[WLAN_ADDR_LEN];
+	UINT16	reason;
+	UINT16	reserved;
+} __WLAN_ATTRIB_PACK__ hfa384x_AssocStatus_t;
+
+/*--  Unsolicited Frame, MAC Mgmt: AuthRequest (AP Only) --*/
+
+typedef struct hfa384x_AuthRequest
+{
+	UINT8	sta_addr[WLAN_ADDR_LEN];
+	UINT16	algorithm;
+} __WLAN_ATTRIB_PACK__ hfa384x_AuthReq_t;
+
+/*--  Unsolicited Frame, MAC Mgmt: AssocRequest (AP Only) --*/
+
+typedef struct hfa384x_AssocRequest
+{
+	UINT8	sta_addr[WLAN_ADDR_LEN];
+	UINT16	type;
+	UINT8   wpa_data[80];
+} __WLAN_ATTRIB_PACK__ hfa384x_AssocReq_t;
+
+
+#define HFA384x_ASSOCREQ_TYPE_ASSOC     0
+#define HFA384x_ASSOCREQ_TYPE_REASSOC   1
+
+/*--  Unsolicited Frame, MAC Mgmt: MIC Failure  (AP Only) --*/
+
+typedef struct hfa384x_MicFailure  
+{
+	UINT8	sender[WLAN_ADDR_LEN];
+	UINT8	dest[WLAN_ADDR_LEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_MicFailure_t;
+
+/*--  Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/
+
+typedef struct hfa384x_PSUserCount
+{
+	UINT16	usercnt;
+} __WLAN_ATTRIB_PACK__ hfa384x_PSUserCount_t;
+
+typedef struct hfa384x_KeyIDChanged
+{
+	UINT8	sta_addr[WLAN_ADDR_LEN];
+	UINT16	keyid;
+} __WLAN_ATTRIB_PACK__ hfa384x_KeyIDChanged_t;
+
+/*--  Collection of all Inf frames ---------------*/
+typedef union hfa384x_infodata {
+	hfa384x_CommTallies16_t	commtallies16;
+	hfa384x_CommTallies32_t	commtallies32;
+	hfa384x_ScanResult_t	scanresult;
+	hfa384x_ChInfoResult_t	chinforesult;
+	hfa384x_HScanResult_t	hscanresult;
+	hfa384x_LinkStatus_t	linkstatus;
+	hfa384x_AssocStatus_t	assocstatus;
+	hfa384x_AuthReq_t	authreq;
+	hfa384x_PSUserCount_t	psusercnt;
+	hfa384x_KeyIDChanged_t  keyidchanged;
+} __WLAN_ATTRIB_PACK__ hfa384x_infodata_t;
+
+typedef struct hfa384x_InfFrame
+{
+	UINT16			framelen;
+	UINT16			infotype;
+	hfa384x_infodata_t	info;
+} __WLAN_ATTRIB_PACK__ hfa384x_InfFrame_t;
+
+#if (WLAN_HOSTIF == WLAN_USB)
+/*--------------------------------------------------------------------
+USB Packet structures and constants.
+--------------------------------------------------------------------*/
+
+/* Should be sent to the ctrlout endpoint */
+#define HFA384x_USB_ENBULKIN	6
+
+/* Should be sent to the bulkout endpoint */
+#define HFA384x_USB_TXFRM	0
+#define HFA384x_USB_CMDREQ	1
+#define HFA384x_USB_WRIDREQ	2
+#define HFA384x_USB_RRIDREQ	3
+#define HFA384x_USB_WMEMREQ	4
+#define HFA384x_USB_RMEMREQ	5
+
+/* Received from the bulkin endpoint */
+#define HFA384x_USB_ISFRM(a)	(!((a) & 0x8000))
+#define HFA384x_USB_ISTXFRM(a)	(((a) & 0x9000) == 0x1000)
+#define HFA384x_USB_ISRXFRM(a)	(!((a) & 0x9000))
+#define HFA384x_USB_INFOFRM	0x8000
+#define HFA384x_USB_CMDRESP	0x8001
+#define HFA384x_USB_WRIDRESP	0x8002
+#define HFA384x_USB_RRIDRESP	0x8003
+#define HFA384x_USB_WMEMRESP	0x8004
+#define HFA384x_USB_RMEMRESP	0x8005
+#define HFA384x_USB_BUFAVAIL	0x8006
+#define HFA384x_USB_ERROR	0x8007
+
+/*------------------------------------*/
+/* Request (bulk OUT) packet contents */
+
+typedef struct hfa384x_usb_txfrm {
+	hfa384x_tx_frame_t	desc;
+	UINT8			data[WLAN_DATA_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_txfrm_t;
+
+typedef struct hfa384x_usb_cmdreq {
+	UINT16		type;
+	UINT16		cmd;
+	UINT16		parm0;
+	UINT16		parm1;
+	UINT16		parm2;
+	UINT8		pad[54];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdreq_t;
+
+typedef struct hfa384x_usb_wridreq {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT16		rid;
+	UINT8		data[HFA384x_RIDDATA_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_wridreq_t;
+
+typedef struct hfa384x_usb_rridreq {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT16		rid;
+	UINT8		pad[58];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridreq_t;
+
+typedef struct hfa384x_usb_wmemreq {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT16		offset;
+	UINT16		page;
+	UINT8		data[HFA384x_USB_RWMEM_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_wmemreq_t;
+
+typedef struct hfa384x_usb_rmemreq {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT16		offset;
+	UINT16		page;
+	UINT8		pad[56];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemreq_t;
+
+/*------------------------------------*/
+/* Response (bulk IN) packet contents */
+
+typedef struct hfa384x_usb_rxfrm {
+	hfa384x_rx_frame_t	desc;
+	UINT8			data[WLAN_DATA_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_rxfrm_t;
+
+typedef struct hfa384x_usb_infofrm {
+	UINT16			type;
+	hfa384x_InfFrame_t	info;
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_infofrm_t;
+
+typedef struct hfa384x_usb_statusresp {
+	UINT16		type;
+	UINT16		status;
+	UINT16		resp0;
+	UINT16		resp1;
+	UINT16		resp2;
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdresp_t;
+
+typedef hfa384x_usb_cmdresp_t hfa384x_usb_wridresp_t;
+
+typedef struct hfa384x_usb_rridresp {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT16		rid;
+	UINT8		data[HFA384x_RIDDATA_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridresp_t;
+
+typedef hfa384x_usb_cmdresp_t hfa384x_usb_wmemresp_t;
+
+typedef struct hfa384x_usb_rmemresp {
+	UINT16		type;
+	UINT16		frmlen;
+	UINT8		data[HFA384x_USB_RWMEM_MAXLEN];
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemresp_t;
+
+typedef struct hfa384x_usb_bufavail {
+	UINT16		type;
+	UINT16		frmlen;
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_bufavail_t;
+
+typedef struct hfa384x_usb_error {
+	UINT16		type;
+	UINT16		errortype;
+} __WLAN_ATTRIB_PACK__ hfa384x_usb_error_t;
+
+/*----------------------------------------------------------*/
+/* Unions for packaging all the known packet types together */
+
+typedef union hfa384x_usbout {
+	UINT16			type;
+	hfa384x_usb_txfrm_t	txfrm;
+	hfa384x_usb_cmdreq_t	cmdreq;
+	hfa384x_usb_wridreq_t	wridreq;
+	hfa384x_usb_rridreq_t	rridreq;
+	hfa384x_usb_wmemreq_t	wmemreq;
+	hfa384x_usb_rmemreq_t	rmemreq;
+} __WLAN_ATTRIB_PACK__ hfa384x_usbout_t;
+
+typedef union hfa384x_usbin {
+	UINT16			type;
+	hfa384x_usb_rxfrm_t	rxfrm;
+	hfa384x_usb_txfrm_t	txfrm;
+	hfa384x_usb_infofrm_t	infofrm;
+	hfa384x_usb_cmdresp_t	cmdresp;
+	hfa384x_usb_wridresp_t	wridresp;
+	hfa384x_usb_rridresp_t	rridresp;
+	hfa384x_usb_wmemresp_t	wmemresp;
+	hfa384x_usb_rmemresp_t	rmemresp;
+	hfa384x_usb_bufavail_t	bufavail;
+	hfa384x_usb_error_t	usberror;
+	UINT8			boguspad[3000];
+} __WLAN_ATTRIB_PACK__ hfa384x_usbin_t;
+
+#endif /* WLAN_USB */
+
+/*--------------------------------------------------------------------
+PD record structures.
+--------------------------------------------------------------------*/
+
+typedef struct hfa384x_pdr_pcb_partnum
+{
+	UINT8	num[8];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_partnum_t;
+
+typedef struct hfa384x_pdr_pcb_tracenum
+{
+	UINT8	num[8];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_tracenum_t;
+
+typedef struct hfa384x_pdr_nic_serial
+{
+	UINT8	num[12];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_serial_t;
+
+typedef struct hfa384x_pdr_mkk_measurements
+{
+	double	carrier_freq;
+	double	occupied_band;
+	double	power_density;
+	double	tx_spur_f1;
+	double	tx_spur_f2;
+	double	tx_spur_f3;
+	double	tx_spur_f4;
+	double	tx_spur_l1;
+	double	tx_spur_l2;
+	double	tx_spur_l3;
+	double	tx_spur_l4;
+	double	rx_spur_f1;
+	double	rx_spur_f2;
+	double	rx_spur_l1;
+	double	rx_spur_l2;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_measurements_t;
+
+typedef struct hfa384x_pdr_nic_ramsize
+{
+	UINT8	size[12]; /* units of KB */
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_ramsize_t;
+
+typedef struct hfa384x_pdr_mfisuprange
+{
+	UINT16	id;
+	UINT16	variant;
+	UINT16	bottom;
+	UINT16	top;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mfisuprange_t;
+
+typedef struct hfa384x_pdr_cfisuprange
+{
+	UINT16	id;
+	UINT16	variant;
+	UINT16	bottom;
+	UINT16	top;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_cfisuprange_t;
+
+typedef struct hfa384x_pdr_nicid
+{
+	UINT16	id;
+	UINT16	variant;
+	UINT16	major;
+	UINT16	minor;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nicid_t;
+
+
+typedef struct hfa384x_pdr_refdac_measurements
+{
+	UINT16	value[0];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_measurements_t;
+
+typedef struct hfa384x_pdr_vgdac_measurements
+{
+	UINT16	value[0];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_measurements_t;
+
+typedef struct hfa384x_pdr_level_comp_measurements
+{
+	UINT16	value[0];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_compc_measurements_t;
+
+typedef struct hfa384x_pdr_mac_address
+{
+	UINT8	addr[6];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mac_address_t;
+
+typedef struct hfa384x_pdr_mkk_callname
+{
+	UINT8	callname[8];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_callname_t;
+
+typedef struct hfa384x_pdr_regdomain
+{
+	UINT16	numdomains;
+	UINT16	domain[5];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_regdomain_t;
+
+typedef struct hfa384x_pdr_allowed_channel
+{
+	UINT16	ch_bitmap;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_allowed_channel_t;
+
+typedef struct hfa384x_pdr_default_channel
+{
+	UINT16	channel;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_default_channel_t;
+
+typedef struct hfa384x_pdr_privacy_option
+{
+	UINT16	available;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_privacy_option_t;
+
+typedef struct hfa384x_pdr_temptype
+{
+	UINT16	type;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_temptype_t;
+
+typedef struct hfa384x_pdr_refdac_setup
+{
+	UINT16	ch_value[14];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_setup_t;
+
+typedef struct hfa384x_pdr_vgdac_setup
+{
+	UINT16	ch_value[14];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_setup_t;
+
+typedef struct hfa384x_pdr_level_comp_setup
+{
+	UINT16	ch_value[14];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_comp_setup_t;
+
+typedef struct hfa384x_pdr_trimdac_setup
+{
+	UINT16	trimidac;
+	UINT16	trimqdac;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_trimdac_setup_t;
+
+typedef struct hfa384x_pdr_ifr_setting
+{
+	UINT16	value[3];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_ifr_setting_t;
+
+typedef struct hfa384x_pdr_rfr_setting
+{
+	UINT16	value[3];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_rfr_setting_t;
+
+typedef struct hfa384x_pdr_hfa3861_baseline
+{
+	UINT16	value[50];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_baseline_t;
+
+typedef struct hfa384x_pdr_hfa3861_shadow
+{
+	UINT32	value[32];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_shadow_t;
+
+typedef struct hfa384x_pdr_hfa3861_ifrf
+{
+	UINT32	value[20];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_ifrf_t;
+
+typedef struct hfa384x_pdr_hfa3861_chcalsp
+{
+	UINT16	value[14];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcalsp_t;
+
+typedef struct hfa384x_pdr_hfa3861_chcali
+{
+	UINT16	value[17];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcali_t;
+
+typedef struct hfa384x_pdr_hfa3861_nic_config
+{
+	UINT16	config_bitmap;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_config_t;
+
+typedef struct hfa384x_pdr_hfo_delay
+{
+	UINT8   hfo_delay;
+} __WLAN_ATTRIB_PACK__ hfa384x_hfo_delay_t;
+
+typedef struct hfa384x_pdr_hfa3861_manf_testsp
+{
+	UINT16	value[30];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testsp_t;
+
+typedef struct hfa384x_pdr_hfa3861_manf_testi
+{
+	UINT16	value[30];
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testi_t;
+
+typedef struct hfa384x_end_of_pda
+{
+	UINT16	crc;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdr_end_of_pda_t;
+
+typedef struct hfa384x_pdrec
+{
+	UINT16	len; /* in words */
+	UINT16	code;
+	union pdr {
+	hfa384x_pdr_pcb_partnum_t	pcb_partnum;
+	hfa384x_pdr_pcb_tracenum_t	pcb_tracenum;
+	hfa384x_pdr_nic_serial_t	nic_serial;
+	hfa384x_pdr_mkk_measurements_t	mkk_measurements;
+	hfa384x_pdr_nic_ramsize_t	nic_ramsize;
+	hfa384x_pdr_mfisuprange_t	mfisuprange;
+	hfa384x_pdr_cfisuprange_t	cfisuprange;
+	hfa384x_pdr_nicid_t		nicid;
+	hfa384x_pdr_refdac_measurements_t	refdac_measurements;
+	hfa384x_pdr_vgdac_measurements_t	vgdac_measurements;
+	hfa384x_pdr_level_compc_measurements_t	level_compc_measurements;
+	hfa384x_pdr_mac_address_t	mac_address;
+	hfa384x_pdr_mkk_callname_t	mkk_callname;
+	hfa384x_pdr_regdomain_t		regdomain;
+	hfa384x_pdr_allowed_channel_t	allowed_channel;
+	hfa384x_pdr_default_channel_t	default_channel;
+	hfa384x_pdr_privacy_option_t	privacy_option;
+	hfa384x_pdr_temptype_t		temptype;
+	hfa384x_pdr_refdac_setup_t	refdac_setup;
+	hfa384x_pdr_vgdac_setup_t	vgdac_setup;
+	hfa384x_pdr_level_comp_setup_t	level_comp_setup;
+	hfa384x_pdr_trimdac_setup_t	trimdac_setup;
+	hfa384x_pdr_ifr_setting_t	ifr_setting;
+	hfa384x_pdr_rfr_setting_t	rfr_setting;
+	hfa384x_pdr_hfa3861_baseline_t	hfa3861_baseline;
+	hfa384x_pdr_hfa3861_shadow_t	hfa3861_shadow;
+	hfa384x_pdr_hfa3861_ifrf_t	hfa3861_ifrf;
+	hfa384x_pdr_hfa3861_chcalsp_t	hfa3861_chcalsp;
+	hfa384x_pdr_hfa3861_chcali_t	hfa3861_chcali;
+	hfa384x_pdr_nic_config_t	nic_config;
+	hfa384x_hfo_delay_t             hfo_delay;
+	hfa384x_pdr_hfa3861_manf_testsp_t	hfa3861_manf_testsp;
+	hfa384x_pdr_hfa3861_manf_testi_t	hfa3861_manf_testi;
+	hfa384x_pdr_end_of_pda_t	end_of_pda;
+
+	} data;
+} __WLAN_ATTRIB_PACK__ hfa384x_pdrec_t;
+
+
+#ifdef __KERNEL__
+/*--------------------------------------------------------------------
+---  MAC state structure, argument to all functions --
+---  Also, a collection of support types --
+--------------------------------------------------------------------*/
+typedef struct hfa384x_statusresult
+{
+	UINT16	status;
+	UINT16	resp0;
+	UINT16	resp1;
+	UINT16	resp2;
+} hfa384x_cmdresult_t;
+
+#if (WLAN_HOSTIF == WLAN_USB)
+
+/* USB Control Exchange (CTLX):
+ *  A queue of the structure below is maintained for all of the 
+ *  Request/Response type USB packets supported by Prism2.
+ */
+/* The following hfa384x_* structures are arguments to 
+ * the usercb() for the different CTLX types.
+ */
+typedef hfa384x_cmdresult_t hfa384x_wridresult_t;
+typedef hfa384x_cmdresult_t hfa384x_wmemresult_t;
+
+typedef struct hfa384x_rridresult
+{
+	UINT16		rid;
+	const void	*riddata;
+	UINT		riddata_len;
+} hfa384x_rridresult_t;
+
+enum ctlx_state {
+	CTLX_START = 0,	/* Start state, not queued */
+
+	CTLX_COMPLETE,	/* CTLX successfully completed */
+	CTLX_REQ_FAILED,	/* OUT URB completed w/ error */
+
+	CTLX_PENDING,		/* Queued, data valid */
+	CTLX_REQ_SUBMITTED,	/* OUT URB submitted */
+	CTLX_REQ_COMPLETE,	/* OUT URB complete */
+	CTLX_RESP_COMPLETE	/* IN URB received */
+};
+typedef enum ctlx_state  CTLX_STATE;
+
+struct hfa384x_usbctlx;
+struct hfa384x;
+
+typedef void (*ctlx_cmdcb_t)( struct hfa384x*, const struct hfa384x_usbctlx* );
+
+typedef void (*ctlx_usercb_t)(
+	struct hfa384x	*hw, 
+	void		*ctlxresult,
+	void		*usercb_data);
+
+typedef struct hfa384x_usbctlx
+{
+	struct list_head	list;
+
+	size_t			outbufsize;
+	hfa384x_usbout_t	outbuf;		/* pkt buf for OUT */
+	hfa384x_usbin_t		inbuf;		/* pkt buf for IN(a copy) */
+
+	CTLX_STATE		state;		/* Tracks running state */
+
+	struct completion	done;
+	volatile int		reapable;	/* Food for the reaper task */
+
+	ctlx_cmdcb_t		cmdcb;		/* Async command callback */
+	ctlx_usercb_t		usercb;		/* Async user callback, */
+	void			*usercb_data;	/*  at CTLX completion  */
+
+	int			variant;	/* Identifies cmd variant */
+} hfa384x_usbctlx_t;
+
+typedef struct hfa384x_usbctlxq
+{
+	spinlock_t		lock;
+	struct list_head	pending;
+	struct list_head	active;
+	struct list_head	completing;
+	struct list_head	reapable;
+} hfa384x_usbctlxq_t;
+#endif
+
+typedef struct hfa484x_metacmd
+{
+	UINT16		cmd;
+
+	UINT16          parm0;
+	UINT16          parm1;
+	UINT16          parm2;
+
+#if 0 //XXX cmd irq stuff
+	UINT16          bulkid;         /* what RID/FID to copy down. */
+	int             bulklen;        /* how much to copy from BAP */
+        char            *bulkdata;      /* And to where? */
+#endif
+
+	hfa384x_cmdresult_t result;
+} hfa384x_metacmd_t;
+
+#define	MAX_PRISM2_GRP_ADDR	16
+#define	MAX_GRP_ADDR		32
+#define WLAN_COMMENT_MAX	80  /* Max. length of user comment string. */
+
+#define MM_SAT_PCF		(BIT14)
+#define MM_GCSD_PCF		(BIT15)
+#define MM_GCSD_PCF_EB		(BIT14 | BIT15)
+
+#define WLAN_STATE_STOPPED	0   /* Network is not active. */
+#define WLAN_STATE_STARTED	1   /* Network has been started. */
+
+#define WLAN_AUTH_MAX           60  /* Max. # of authenticated stations. */
+#define WLAN_ACCESS_MAX		60  /* Max. # of stations in an access list. */
+#define WLAN_ACCESS_NONE	0   /* No stations may be authenticated. */
+#define WLAN_ACCESS_ALL		1   /* All stations may be authenticated. */
+#define WLAN_ACCESS_ALLOW	2   /* Authenticate only "allowed" stations. */
+#define WLAN_ACCESS_DENY	3   /* Do not authenticate "denied" stations. */
+
+/* XXX These are going away ASAP */
+typedef struct prism2sta_authlist
+{
+	UINT	cnt;
+	UINT8	addr[WLAN_AUTH_MAX][WLAN_ADDR_LEN];
+	UINT8	assoc[WLAN_AUTH_MAX];
+} prism2sta_authlist_t;
+
+typedef struct prism2sta_accesslist
+{
+	UINT	modify;
+	UINT	cnt;
+	UINT8	addr[WLAN_ACCESS_MAX][WLAN_ADDR_LEN];
+	UINT	cnt1;
+	UINT8	addr1[WLAN_ACCESS_MAX][WLAN_ADDR_LEN];
+} prism2sta_accesslist_t;
+
+typedef struct hfa384x
+{
+#if (WLAN_HOSTIF != WLAN_USB)
+	/* Resource config */
+	UINT32			iobase;
+	char			__iomem *membase;
+	UINT32			irq;
+#else
+	/* USB support data */
+	struct usb_device	*usb;
+	struct urb		rx_urb;
+	struct sk_buff		*rx_urb_skb;
+	struct urb		tx_urb;
+	struct urb		ctlx_urb;
+	hfa384x_usbout_t	txbuff;
+	hfa384x_usbctlxq_t	ctlxq;
+	struct timer_list	reqtimer;
+	struct timer_list	resptimer;
+
+	struct timer_list	throttle;
+
+	struct tasklet_struct	reaper_bh;
+	struct tasklet_struct	completion_bh;
+
+	struct work_struct	usb_work;
+
+	unsigned long		usb_flags;
+#define THROTTLE_RX	0
+#define THROTTLE_TX	1
+#define WORK_RX_HALT	2
+#define WORK_TX_HALT	3
+#define WORK_RX_RESUME	4
+#define WORK_TX_RESUME	5
+
+	unsigned short		req_timer_done:1;
+	unsigned short		resp_timer_done:1;
+
+	int                     endp_in;
+	int                     endp_out;
+#endif /* !USB */
+
+#if (WLAN_HOSTIF == WLAN_PCMCIA)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
+	struct pcmcia_device *pdev;
+#else
+	dev_link_t	*link;
+#endif
+	dev_node_t	node;
+#endif
+
+	int                     sniff_fcs;
+	int                     sniff_channel;  
+	int                     sniff_truncate;  
+	int                     sniffhdr;
+
+	wait_queue_head_t cmdq;	        /* wait queue itself */
+
+	/* Controller state */
+	UINT32		state;
+	UINT32		isap;
+	UINT8		port_enabled[HFA384x_NUMPORTS_MAX];
+#if (WLAN_HOSTIF != WLAN_USB)
+	UINT		auxen;
+	UINT            isram16;
+#endif /* !USB */
+
+	/* Download support */
+	UINT				dlstate;
+	hfa384x_downloadbuffer_t	bufinfo;
+	UINT16				dltimeout;
+
+#if (WLAN_HOSTIF != WLAN_USB)
+	spinlock_t	cmdlock;
+	volatile int    cmdflag;        /* wait queue flag */
+	hfa384x_metacmd_t *cmddata;      /* for our async callback */
+
+	/* BAP support */
+	spinlock_t	baplock;	
+	struct tasklet_struct   bap_tasklet;
+
+	/* MAC buffer ids */
+        UINT16          txfid_head;
+        UINT16          txfid_tail;
+        UINT            txfid_N;
+        UINT16          txfid_queue[HFA384x_DRVR_FIDSTACKLEN_MAX];
+	UINT16			infofid;
+	struct semaphore	infofid_sem;
+#endif /* !USB */
+
+	int                          scanflag;    /* to signal scan comlete */
+	int                          join_ap;        /* are we joined to a specific ap */
+	int                          join_retries;   /* number of join retries till we fail */
+	hfa384x_JoinRequest_data_t   joinreq;        /* join request saved data */
+
+	wlandevice_t            *wlandev;
+	/* Timer to allow for the deferred processing of linkstatus messages */
+	struct work_struct 	link_bh;
+
+        struct work_struct      commsqual_bh;
+	hfa384x_commsquality_t  qual;
+	struct timer_list	commsqual_timer;
+
+	UINT16 link_status;
+	UINT16 link_status_new;
+	struct sk_buff_head        authq;
+
+	/* And here we have stuff that used to be in priv */
+
+	/* State variables */
+	UINT		presniff_port_type;
+	UINT16		presniff_wepflags;
+	UINT32		dot11_desired_bss_type;
+	int		ap;	/* AP flag: 0 - Station, 1 - Access Point. */
+
+	int             dbmadjust;
+
+	/* Group Addresses - right now, there are up to a total
+	of MAX_GRP_ADDR group addresses */
+	UINT8		dot11_grp_addr[MAX_GRP_ADDR][WLAN_ADDR_LEN];
+	UINT		dot11_grpcnt;
+
+	/* Component Identities */
+	hfa384x_compident_t	ident_nic;
+	hfa384x_compident_t	ident_pri_fw;
+	hfa384x_compident_t	ident_sta_fw;
+	hfa384x_compident_t	ident_ap_fw;
+	UINT16			mm_mods;
+
+	/* Supplier compatibility ranges */
+	hfa384x_caplevel_t	cap_sup_mfi;
+	hfa384x_caplevel_t	cap_sup_cfi;
+	hfa384x_caplevel_t	cap_sup_pri;
+	hfa384x_caplevel_t	cap_sup_sta;
+	hfa384x_caplevel_t	cap_sup_ap;
+
+	/* Actor compatibility ranges */
+	hfa384x_caplevel_t	cap_act_pri_cfi; /* pri f/w to controller interface */
+	hfa384x_caplevel_t	cap_act_sta_cfi; /* sta f/w to controller interface */
+	hfa384x_caplevel_t	cap_act_sta_mfi; /* sta f/w to modem interface */
+	hfa384x_caplevel_t	cap_act_ap_cfi;  /* ap f/w to controller interface */
+	hfa384x_caplevel_t	cap_act_ap_mfi;  /* ap f/w to modem interface */
+
+	UINT32			psusercount;  /* Power save user count. */
+	hfa384x_CommTallies32_t	tallies;      /* Communication tallies. */
+	UINT8			comment[WLAN_COMMENT_MAX+1]; /* User comment */
+
+	/* Channel Info request results (AP only) */
+	struct {
+		atomic_t		done;
+		UINT8			count;
+		hfa384x_ChInfoResult_t	results;
+	} channel_info;
+
+	hfa384x_InfFrame_t      *scanresults;
+
+
+        prism2sta_authlist_t	authlist;     /* Authenticated station list. */
+	UINT			accessmode;   /* Access mode. */
+        prism2sta_accesslist_t	allow;        /* Allowed station list. */
+        prism2sta_accesslist_t	deny;         /* Denied station list. */
+
+} hfa384x_t;
+
+/*=============================================================*/
+/*--- Function Declarations -----------------------------------*/
+/*=============================================================*/
+#if (WLAN_HOSTIF == WLAN_USB)
+void 
+hfa384x_create( 
+	hfa384x_t *hw, 
+	struct usb_device *usb);
+#else
+void 
+hfa384x_create( 
+	hfa384x_t *hw, 
+	UINT irq, 
+	UINT32 iobase, 
+	UINT8 __iomem *membase);
+#endif
+
+void hfa384x_destroy(hfa384x_t *hw);
+
+irqreturn_t
+hfa384x_interrupt(int irq, void *dev_id PT_REGS);
+int
+hfa384x_corereset( hfa384x_t *hw, int holdtime, int settletime, int genesis);
+int
+hfa384x_drvr_chinforesults( hfa384x_t *hw);
+int
+hfa384x_drvr_commtallies( hfa384x_t *hw);
+int
+hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport);
+int
+hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport);
+int
+hfa384x_drvr_flashdl_enable(hfa384x_t *hw);
+int
+hfa384x_drvr_flashdl_disable(hfa384x_t *hw);
+int
+hfa384x_drvr_flashdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len);
+int
+hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len);
+int
+hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr);
+int
+hfa384x_drvr_hostscanresults( hfa384x_t *hw);
+int
+hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd);
+int
+hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 address, UINT32 *result);
+int
+hfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 address, UINT32 data);
+int
+hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr);
+int
+hfa384x_drvr_ramdl_disable(hfa384x_t *hw);
+int
+hfa384x_drvr_ramdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len);
+int
+hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len);
+int
+hfa384x_drvr_scanresults( hfa384x_t *hw);
+
+int
+hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len);
+
+static inline int 
+hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val)
+{
+	int		result = 0;
+	result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16));
+	if ( result == 0 ) {
+		*((UINT16*)val) = hfa384x2host_16(*((UINT16*)val));
+	}
+	return result;
+}
+
+static inline int 
+hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val)
+{
+	int		result = 0;
+
+	result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32));
+	if ( result == 0 ) {
+		*((UINT32*)val) = hfa384x2host_32(*((UINT32*)val));
+	}
+
+	return result;
+}
+
+static inline int
+hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 val)
+{
+	UINT16 value = host2hfa384x_16(val);
+	return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value));
+}
+
+static inline int
+hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 val)
+{
+	UINT32 value = host2hfa384x_32(val);
+	return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value));
+}
+
+#if (WLAN_HOSTIF == WLAN_USB) 	 
+int 	 
+hfa384x_drvr_getconfig_async(hfa384x_t     *hw, 	 
+                              UINT16        rid, 	 
+                              ctlx_usercb_t usercb, 	 
+                              void          *usercb_data); 	 
+ 	 
+int 	 
+hfa384x_drvr_setconfig_async(hfa384x_t *hw, 	 
+                              UINT16 rid, 	 
+                              void *buf, 	 
+                              UINT16 len, 	 
+                              ctlx_usercb_t usercb, 	 
+                              void *usercb_data); 	 
+#else
+static inline int
+hfa384x_drvr_setconfig_async(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len, 
+			     void *ptr1, void *ptr2) 	 
+{
+         (void)ptr1;
+         (void)ptr2;
+         return hfa384x_drvr_setconfig(hw, rid, buf, len);
+}
+#endif
+
+static inline int
+hfa384x_drvr_setconfig16_async(hfa384x_t *hw, UINT16 rid, UINT16 val)
+{ 	 
+	UINT16 value = host2hfa384x_16(val); 	 
+	return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), 
+					    NULL , NULL); 	 
+}
+
+static inline int
+hfa384x_drvr_setconfig32_async(hfa384x_t *hw, UINT16 rid, UINT32 val)
+{ 	 
+	UINT32 value = host2hfa384x_32(val); 	 
+	return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), 
+					    NULL , NULL); 	 
+}
+
+
+int
+hfa384x_drvr_start(hfa384x_t *hw);
+int
+hfa384x_drvr_stop(hfa384x_t *hw);
+int
+hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep);
+void
+hfa384x_tx_timeout(wlandevice_t *wlandev);
+
+int
+hfa384x_cmd_initialize(hfa384x_t *hw);
+int
+hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport);
+int
+hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport);
+int
+hfa384x_cmd_diagnose(hfa384x_t *hw);
+int
+hfa384x_cmd_allocate(hfa384x_t *hw, UINT16 len);
+int
+hfa384x_cmd_transmit(hfa384x_t *hw, UINT16 reclaim, UINT16 qos, UINT16 fid);
+int
+hfa384x_cmd_clearpersist(hfa384x_t *hw, UINT16 fid);
+int
+hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid, void *buf, UINT16 len);
+int
+hfa384x_cmd_inquire(hfa384x_t *hw, UINT16 fid);
+int
+hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid, void *buf, UINT16 len);
+int
+hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable);
+int
+hfa384x_cmd_download(
+	hfa384x_t *hw, 
+	UINT16 mode, 
+	UINT16 lowaddr,
+	UINT16 highaddr, 
+	UINT16 codelen);
+int
+hfa384x_cmd_aux_enable(hfa384x_t *hw, int force);
+int
+hfa384x_cmd_aux_disable(hfa384x_t *hw);
+int
+hfa384x_copy_from_bap(
+	hfa384x_t *hw, 
+	UINT16	bap, 
+	UINT16	id, 
+	UINT16	offset, 
+	void	*buf,
+	UINT	len);
+int
+hfa384x_copy_to_bap(
+	hfa384x_t *hw, 
+	UINT16	bap, 
+	UINT16	id, 
+	UINT16	offset,
+	void	*buf, 
+	UINT	len);
+void 
+hfa384x_copy_from_aux(
+	hfa384x_t *hw, 
+	UINT32	cardaddr, 
+	UINT32	auxctl, 
+	void	*buf, 
+	UINT	len);
+void 
+hfa384x_copy_to_aux(
+	hfa384x_t *hw, 
+	UINT32	cardaddr, 
+	UINT32	auxctl, 
+	void	*buf, 
+	UINT	len);
+
+#if (WLAN_HOSTIF != WLAN_USB)
+
+/* 
+   HFA384x is a LITTLE ENDIAN part.
+
+   the get/setreg functions implicitly byte-swap the data to LE.
+   the _noswap variants do not perform a byte-swap on the data.
+*/
+
+static inline UINT16 
+__hfa384x_getreg(hfa384x_t *hw, UINT reg);
+
+static inline void   
+__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg);
+
+static inline UINT16 
+__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg);
+
+static inline void
+__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg);
+
+#ifdef REVERSE_ENDIAN
+#define hfa384x_getreg __hfa384x_getreg_noswap
+#define hfa384x_setreg __hfa384x_setreg_noswap
+#define hfa384x_getreg_noswap __hfa384x_getreg
+#define hfa384x_setreg_noswap __hfa384x_setreg
+#else
+#define hfa384x_getreg __hfa384x_getreg
+#define hfa384x_setreg __hfa384x_setreg
+#define hfa384x_getreg_noswap __hfa384x_getreg_noswap
+#define hfa384x_setreg_noswap __hfa384x_setreg_noswap
+#endif
+
+/*----------------------------------------------------------------
+* hfa384x_getreg
+*
+* Retrieve the value of one of the MAC registers.  Done here
+* because different PRISM2 MAC parts use different buses and such.
+* NOTE: This function returns the value in HOST ORDER!!!!!!
+*
+* Arguments:
+*       hw         MAC part structure
+*       reg        Register identifier (offset for I/O based i/f)
+*
+* Returns:
+*       Value from the register in HOST ORDER!!!!
+----------------------------------------------------------------*/
+static inline UINT16 
+__hfa384x_getreg(hfa384x_t *hw, UINT reg)
+{
+/*	printk(KERN_DEBUG "Reading from 0x%0x\n", hw->membase + reg); */
+#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX))
+	return wlan_inw_le16_to_cpu(hw->iobase+reg);
+#elif (WLAN_HOSTIF == WLAN_PCI)
+	return __le16_to_cpu(readw(hw->membase + reg));
+#endif
+}
+
+/*----------------------------------------------------------------
+* hfa384x_setreg
+*
+* Set the value of one of the MAC registers.  Done here
+* because different PRISM2 MAC parts use different buses and such.
+* NOTE: This function assumes the value is in HOST ORDER!!!!!!
+*
+* Arguments:
+*       hw	MAC part structure
+*	val	Value, in HOST ORDER!!, to put in the register
+*       reg	Register identifier (offset for I/O based i/f)
+*
+* Returns:
+*       Nothing
+----------------------------------------------------------------*/
+static inline void
+__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg)
+{
+#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX))
+	wlan_outw_cpu_to_le16( val, hw->iobase + reg);
+	return;
+#elif (WLAN_HOSTIF == WLAN_PCI)
+	writew(__cpu_to_le16(val), hw->membase + reg);
+	return;
+#endif
+}
+
+
+/*----------------------------------------------------------------
+* hfa384x_getreg_noswap
+*
+* Retrieve the value of one of the MAC registers.  Done here
+* because different PRISM2 MAC parts use different buses and such.
+*
+* Arguments:
+*       hw         MAC part structure
+*       reg        Register identifier (offset for I/O based i/f)
+*
+* Returns:
+*       Value from the register.
+----------------------------------------------------------------*/
+static inline UINT16
+__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg)
+{
+#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX))
+	return wlan_inw(hw->iobase+reg);
+#elif (WLAN_HOSTIF == WLAN_PCI)
+	return readw(hw->membase + reg);
+#endif
+}
+
+
+/*----------------------------------------------------------------
+* hfa384x_setreg_noswap
+*
+* Set the value of one of the MAC registers.  Done here
+* because different PRISM2 MAC parts use different buses and such.
+*
+* Arguments:
+*       hw	MAC part structure
+*	val	Value to put in the register
+*       reg	Register identifier (offset for I/O based i/f)
+*
+* Returns:
+*       Nothing
+----------------------------------------------------------------*/
+static inline void 
+__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg)
+{
+#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX))
+	wlan_outw( val, hw->iobase + reg);
+	return;
+#elif (WLAN_HOSTIF == WLAN_PCI)
+	writew(val, hw->membase + reg);
+	return;
+#endif
+}
+
+
+static inline void hfa384x_events_all(hfa384x_t *hw)
+{
+	hfa384x_setreg(hw, 
+		       HFA384x_INT_NORMAL
+#ifdef CMD_IRQ
+		       | HFA384x_INTEN_CMD_SET(1)
+#endif
+		       ,
+		       HFA384x_INTEN);	
+
+}
+
+static inline void hfa384x_events_nobap(hfa384x_t *hw)
+{
+	hfa384x_setreg(hw, 
+		        (HFA384x_INT_NORMAL & ~HFA384x_INT_BAP_OP)
+#ifdef CMD_IRQ
+		       | HFA384x_INTEN_CMD_SET(1)
+#endif
+		       ,
+		       HFA384x_INTEN);	
+
+}
+
+#endif /* WLAN_HOSTIF != WLAN_USB */
+#endif /* __KERNEL__ */
+
+#endif  /* _HFA384x_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.c
new file mode 100644
index 0000000..cd5db1f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.c
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+REQUIRE_OBJECT(igb_main);
+REQUIRE_OBJECT(igb_82575);
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.h
new file mode 100644
index 0000000..c8e8205
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb.h
@@ -0,0 +1,324 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _IGB_H_
+#define _IGB_H_
+
+#include "igb_api.h"
+
+extern int igb_probe ( struct pci_device *pdev );
+extern void igb_remove ( struct pci_device *pdev );
+
+struct igb_adapter;
+
+/* Interrupt defines */
+#define IGB_START_ITR                    648 /* ~6000 ints/sec */
+
+/* Interrupt modes, as used by the IntMode paramter */
+#define IGB_INT_MODE_LEGACY                0
+#define IGB_INT_MODE_MSI                   1
+#define IGB_INT_MODE_MSIX                  2
+
+#define HW_PERF
+/* TX/RX descriptor defines */
+#define IGB_DEFAULT_TXD                  256
+#define IGB_MIN_TXD                       80
+#define IGB_MAX_TXD                     4096
+
+#define IGB_DEFAULT_RXD                  256
+#define IGB_MIN_RXD                       80
+#define IGB_MAX_RXD                     4096
+
+#define IGB_MIN_ITR_USECS                 10 /* 100k irq/sec */
+#define IGB_MAX_ITR_USECS               8191 /* 120  irq/sec */
+
+#define NON_Q_VECTORS                      1
+#define MAX_Q_VECTORS                      8
+
+/* Transmit and receive queues */
+#define IGB_MAX_RX_QUEUES                  (adapter->vfs_allocated_count ? 2 : \
+                                           (hw->mac.type > e1000_82575 ? 8 : 4))
+#define IGB_ABS_MAX_TX_QUEUES              8
+#define IGB_MAX_TX_QUEUES                  IGB_MAX_RX_QUEUES
+
+#define IGB_MAX_VF_MC_ENTRIES              30
+#define IGB_MAX_VF_FUNCTIONS               8
+#define IGB_MAX_VFTA_ENTRIES               128
+#define IGB_MAX_UTA_ENTRIES                128
+#define MAX_EMULATION_MAC_ADDRS            16
+#define OUI_LEN                            3
+
+struct vf_data_storage {
+	unsigned char vf_mac_addresses[ETH_ALEN];
+	u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
+	u16 num_vf_mc_hashes;
+	u16 default_vf_vlan_id;
+	u16 vlans_enabled;
+	unsigned char em_mac_addresses[MAX_EMULATION_MAC_ADDRS * ETH_ALEN];
+	u32 uta_table_copy[IGB_MAX_UTA_ENTRIES];
+	u32 flags;
+	unsigned long last_nack;
+};
+
+#define IGB_VF_FLAG_CTS            0x00000001 /* VF is clear to send data */
+#define IGB_VF_FLAG_UNI_PROMISC    0x00000002 /* VF has unicast promisc */
+#define IGB_VF_FLAG_MULTI_PROMISC  0x00000004 /* VF has multicast promisc */
+
+/* RX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ *           descriptors available in its onboard memory.
+ *           Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ *           available in host memory.
+ *           If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ *           descriptors until either it has this many to write back, or the
+ *           ITR timer expires.
+ */
+#define IGB_RX_PTHRESH                    (hw->mac.type <= e1000_82576 ? 16 : 8)
+#define IGB_RX_HTHRESH                     8
+#define IGB_RX_WTHRESH                     1
+#define IGB_TX_PTHRESH                     8
+#define IGB_TX_HTHRESH                     1
+#define IGB_TX_WTHRESH                     ((hw->mac.type == e1000_82576 && \
+                                             adapter->msix_entries) ? 0 : 16)
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
+/* Supported Rx Buffer Sizes */
+#define IGB_RXBUFFER_128   128    /* Used for packet split */
+#define IGB_RXBUFFER_256   256    /* Used for packet split */
+#define IGB_RXBUFFER_512   512
+#define IGB_RXBUFFER_1024  1024
+#define IGB_RXBUFFER_2048  2048
+#define IGB_RXBUFFER_4096  4096
+#define IGB_RXBUFFER_8192  8192
+#define IGB_RXBUFFER_16384 16384
+
+/* Packet Buffer allocations */
+#define IGB_PBA_BYTES_SHIFT 0xA
+#define IGB_TX_HEAD_ADDR_SHIFT 7
+#define IGB_PBA_TX_MASK 0xFFFF0000
+
+#define IGB_FC_PAUSE_TIME 0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define IGB_TX_QUEUE_WAKE	32
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGB_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+
+#define AUTO_ALL_MODES            0
+#define IGB_EEPROM_APME         0x0400
+
+#ifndef IGB_MASTER_SLAVE
+/* Switch to override PHY master/slave setting */
+#define IGB_MASTER_SLAVE	e1000_ms_hw_default
+#endif
+
+#define IGB_MNG_VLAN_NONE -1
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct igb_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	dma_addr_t page_dma;
+	union {
+		/* TX */
+		struct {
+			unsigned long time_stamp;
+			u16 length;
+			u16 next_to_watch;
+		};
+
+#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT
+		/* RX */
+		struct {
+			unsigned long page_offset;
+			struct page *page;
+		};
+#endif
+	};
+};
+
+struct igb_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+struct igb_q_vector {
+	struct igb_adapter *adapter; /* backlink */
+	struct igb_ring *rx_ring;
+	struct igb_ring *tx_ring;
+#if 0
+	struct napi_struct napi;
+#endif
+	u32 eims_value;
+	u16 cpu;
+
+	u16 itr_val;
+	u8 set_itr;
+	u8 itr_shift;
+	void __iomem *itr_register;
+
+#if 0
+	char name[IFNAMSIZ + 9];
+#endif
+#ifndef HAVE_NETDEV_NAPI_LIST
+	struct net_device poll_dev;
+#endif
+};
+
+struct igb_ring {
+	struct igb_q_vector *q_vector; /* backlink to q_vector */
+	struct pci_dev *pdev;          /* pci device for dma mapping */
+	dma_addr_t dma;                /* phys address of the ring */
+	void *desc;                    /* descriptor ring memory */
+	unsigned int size;             /* length of desc. ring in bytes */
+	u16 count;                     /* number of desc. in the ring */
+	u16 next_to_use;
+	u16 next_to_clean;
+	u8 queue_index;
+	u8 reg_idx;
+	void __iomem *head;
+	void __iomem *tail;
+	struct igb_buffer *buffer_info; /* array of buffer info structs */
+
+	unsigned int total_bytes;
+	unsigned int total_packets;
+
+	struct igb_queue_stats stats;
+
+	union {
+		/* TX */
+		struct {
+			unsigned int restart_queue;
+			u32 ctx_idx;
+			bool detect_tx_hung;
+		};
+		/* RX */
+		struct {
+			u64 hw_csum_err;
+			u64 hw_csum_good;
+			u32 rx_buffer_len;
+			u16 rx_ps_hdr_size;
+			bool rx_csum;
+#ifdef IGB_LRO
+			struct net_lro_mgr lro_mgr;
+			bool lro_used;
+#endif
+		};
+	};
+};
+
+
+#define IGB_ADVTXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
+
+#define IGB_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define E1000_RX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
+#define E1000_TX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
+#define E1000_TX_CTXTDESC_ADV(R, i)	    \
+	(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+
+#define MAX_MSIX_COUNT 10
+/* board specific private data structure */
+
+/* board specific private data structure */
+struct igb_adapter {
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_device *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+
+	struct e1000_phy_info phy_info;
+
+        u32 min_frame_size;
+        u32 max_frame_size;
+
+	u32 wol;
+	u32 pba;
+	u32 max_hw_frame_size;
+
+	bool fc_autoneg;
+
+	unsigned int flags;
+	unsigned int flags2;
+
+#define NUM_TX_DESC	8
+#define NUM_RX_DESC	8
+
+	struct io_buffer *tx_iobuf[NUM_TX_DESC];
+	struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+	struct e1000_tx_desc *tx_base;
+	struct e1000_rx_desc *rx_base;
+
+	uint32_t tx_ring_size;
+	uint32_t rx_ring_size;
+
+	uint32_t tx_head;
+	uint32_t tx_tail;
+	uint32_t tx_fill_ctr;
+
+	uint32_t rx_curr;
+
+	uint32_t ioaddr;
+	uint32_t irqno;
+
+        uint32_t tx_int_delay;
+        uint32_t tx_abs_int_delay;
+        uint32_t txd_cmd;
+};
+
+#define IGB_FLAG_HAS_MSI           (1 << 0)
+#define IGB_FLAG_MSI_ENABLE        (1 << 1)
+#define IGB_FLAG_DCA_ENABLED       (1 << 3)
+#define IGB_FLAG_LLI_PUSH          (1 << 4)
+#define IGB_FLAG_IN_NETPOLL        (1 << 5)
+#define IGB_FLAG_QUAD_PORT_A       (1 << 6)
+#define IGB_FLAG_QUEUE_PAIRS       (1 << 7)
+
+#define IGB_82576_TSYNC_SHIFT 19
+
+#endif /* _IGB_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.c
new file mode 100644
index 0000000..b5b615a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.c
@@ -0,0 +1,1617 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * 82575EB Gigabit Network Connection
+ * 82575EB Gigabit Backplane Connection
+ * 82575GB Gigabit Network Connection
+ * 82576 Gigabit Network Connection
+ * 82576 Quad Port Gigabit Mezzanine Adapter
+ */
+
+#include "igb.h"
+
+static s32  igb_init_phy_params_82575(struct e1000_hw *hw);
+static s32  igb_init_nvm_params_82575(struct e1000_hw *hw);
+static s32  igb_init_mac_params_82575(struct e1000_hw *hw);
+static s32  igb_acquire_phy_82575(struct e1000_hw *hw);
+static void igb_release_phy_82575(struct e1000_hw *hw);
+static s32  igb_acquire_nvm_82575(struct e1000_hw *hw);
+static void igb_release_nvm_82575(struct e1000_hw *hw);
+static s32  igb_check_for_link_82575(struct e1000_hw *hw);
+static s32  igb_get_cfg_done_82575(struct e1000_hw *hw);
+static s32  igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
+                                         u16 *duplex);
+static s32  igb_init_hw_82575(struct e1000_hw *hw);
+static s32  igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
+static s32  igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+                                           u16 *data);
+static s32  igb_reset_hw_82575(struct e1000_hw *hw);
+static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *hw,
+                                          bool active);
+static s32  igb_setup_copper_link_82575(struct e1000_hw *hw);
+static s32  igb_setup_serdes_link_82575(struct e1000_hw *hw);
+static s32  igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data);
+static s32  igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
+                                            u32 offset, u16 data);
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw);
+static s32  igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
+static s32  igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+                                                 u16 *speed, u16 *duplex);
+static s32  igb_get_phy_id_82575(struct e1000_hw *hw);
+static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
+static bool igb_sgmii_active_82575(struct e1000_hw *hw);
+static s32  igb_reset_init_script_82575(struct e1000_hw *hw);
+static s32  igb_read_mac_addr_82575(struct e1000_hw *hw);
+static void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
+static void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
+
+/**
+ *  igb_init_phy_params_82575 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_init_phy_params_82575");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type = e1000_phy_none;
+		goto out;
+	}
+
+	phy->ops.power_up   = igb_power_up_phy_copper;
+	phy->ops.power_down = igb_power_down_phy_copper_82575;
+
+	phy->autoneg_mask           = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us         = 100;
+
+	phy->ops.acquire            = igb_acquire_phy_82575;
+	phy->ops.check_reset_block  = igb_check_reset_block_generic;
+	phy->ops.commit             = igb_phy_sw_reset_generic;
+	phy->ops.get_cfg_done       = igb_get_cfg_done_82575;
+	phy->ops.release            = igb_release_phy_82575;
+
+	if (igb_sgmii_active_82575(hw)) {
+		phy->ops.reset      = igb_phy_hw_reset_sgmii_82575;
+		phy->ops.read_reg   = igb_read_phy_reg_sgmii_82575;
+		phy->ops.write_reg  = igb_write_phy_reg_sgmii_82575;
+	} else {
+		phy->ops.reset      = igb_phy_hw_reset_generic;
+		phy->ops.read_reg   = igb_read_phy_reg_igp;
+		phy->ops.write_reg  = igb_write_phy_reg_igp;
+	}
+
+	/* Set phy->phy_addr and phy->id. */
+	ret_val = igb_get_phy_id_82575(hw);
+
+	/* Verify phy id and set remaining function pointers */
+	switch (phy->id) {
+	case M88E1111_I_PHY_ID:
+		phy->type                   = e1000_phy_m88;
+		phy->ops.check_polarity     = igb_check_polarity_m88;
+		phy->ops.get_info           = igb_get_phy_info_m88;
+#if 0
+		phy->ops.get_cable_length   = igb_get_cable_length_m88;
+#endif
+#if 0
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+#endif
+		break;
+	case IGP03E1000_E_PHY_ID:
+	case IGP04E1000_E_PHY_ID:
+		phy->type                   = e1000_phy_igp_3;
+		phy->ops.check_polarity     = igb_check_polarity_igp;
+		phy->ops.get_info           = igb_get_phy_info_igp;
+#if 0
+		phy->ops.get_cable_length   = igb_get_cable_length_igp_2;
+#endif
+#if 0
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
+#endif
+		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82575;
+		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_generic;
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_init_nvm_params_82575 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u16 size;
+
+	DEBUGFUNC("igb_init_nvm_params_82575");
+
+	nvm->opcode_bits        = 8;
+	nvm->delay_usec         = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	nvm->type              = e1000_nvm_eeprom_spi;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+	                  E1000_EECD_SIZE_EX_SHIFT);
+
+	/*
+	 * Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+
+	/* EEPROM access above 16k is unsupported */
+	if (size > 14)
+		size = 14;
+	nvm->word_size = 1 << size;
+
+	/* Function Pointers */
+	nvm->ops.acquire       = igb_acquire_nvm_82575;
+	nvm->ops.read          = igb_read_nvm_eerd;
+	nvm->ops.release       = igb_release_nvm_82575;
+	nvm->ops.update        = igb_update_nvm_checksum_generic;
+	nvm->ops.valid_led_default = igb_valid_led_default_82575;
+	nvm->ops.validate      = igb_validate_nvm_checksum_generic;
+	nvm->ops.write         = igb_write_nvm_spi;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_init_mac_params_82575 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+	u32 ctrl_ext = 0;
+
+	DEBUGFUNC("igb_init_mac_params_82575");
+
+	/* Set media type */
+        /*
+	 * The 82575 uses bits 22:23 for link mode. The mode can be changed
+         * based on the EEPROM. We cannot rely upon device ID. There
+         * is no distinguishable difference between fiber and internal
+         * SerDes mode on the 82575. There can be an external PHY attached
+         * on the SGMII interface. For this, we'll set sgmii_active to true.
+         */
+	hw->phy.media_type = e1000_media_type_copper;
+	dev_spec->sgmii_active = false;
+
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+	case E1000_CTRL_EXT_LINK_MODE_SGMII:
+		dev_spec->sgmii_active = true;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+		break;
+	case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+		break;
+	default:
+		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+		break;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set uta register count */
+	mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+	if (mac->type == e1000_82576)
+		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+	        (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+	                ? true : false;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = igb_get_bus_info_pcie_generic;
+	/* reset */
+	mac->ops.reset_hw = igb_reset_hw_82575;
+	/* hw initialization */
+	mac->ops.init_hw = igb_init_hw_82575;
+	/* link setup */
+	mac->ops.setup_link = igb_setup_link_generic;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? igb_setup_copper_link_82575
+	                : igb_setup_serdes_link_82575;
+	/* physical interface shutdown */
+	mac->ops.shutdown_serdes = igb_shutdown_serdes_link_82575;
+	/* check for link */
+	mac->ops.check_for_link = igb_check_for_link_82575;
+	/* receive address register setting */
+	mac->ops.rar_set = igb_rar_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = igb_read_mac_addr_82575;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = igb_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = igb_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = igb_clear_vfta_generic;
+	/* setting MTA */
+#if 0
+	mac->ops.mta_set = igb_mta_set_generic;
+	/* ID LED init */
+	mac->ops.id_led_init = igb_id_led_init_generic;
+	/* blink LED */
+	mac->ops.blink_led = igb_blink_led_generic;
+	/* setup LED */
+	mac->ops.setup_led = igb_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = igb_cleanup_led_generic;
+	/* turn on/off LED */
+	mac->ops.led_on = igb_led_on_generic;
+	mac->ops.led_off = igb_led_off_generic;
+#endif
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = igb_clear_hw_cntrs_82575;
+	/* link info */
+	mac->ops.get_link_up_info = igb_get_link_up_info_82575;
+
+	/* set lan id for port to determine which phy lock to use */
+	hw->mac.ops.set_lan_id(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_init_function_pointers_82575 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to initialize all function pointers and parameters.
+ **/
+void igb_init_function_pointers_82575(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igb_init_function_pointers_82575");
+
+	hw->mac.ops.init_params = igb_init_mac_params_82575;
+	hw->nvm.ops.init_params = igb_init_nvm_params_82575;
+	hw->phy.ops.init_params = igb_init_phy_params_82575;
+#if 0
+	hw->mbx.ops.init_params = igb_init_mbx_params_pf;
+#endif
+}
+
+/**
+ *  igb_acquire_phy_82575 - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire access rights to the correct PHY.
+ **/
+static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
+{
+	u16 mask = E1000_SWFW_PHY0_SM;
+
+	DEBUGFUNC("igb_acquire_phy_82575");
+
+	if (hw->bus.func == E1000_FUNC_1)
+		mask = E1000_SWFW_PHY1_SM;
+
+	return igb_acquire_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  igb_release_phy_82575 - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.
+ **/
+static void igb_release_phy_82575(struct e1000_hw *hw)
+{
+	u16 mask = E1000_SWFW_PHY0_SM;
+
+	DEBUGFUNC("igb_release_phy_82575");
+
+	if (hw->bus.func == E1000_FUNC_1)
+		mask = E1000_SWFW_PHY1_SM;
+
+	igb_release_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  igb_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset using the serial gigabit media independent
+ *  interface and stores the retrieved information in data.
+ **/
+static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+                                          u16 *data)
+{
+	s32 ret_val = -E1000_ERR_PARAM;
+
+	DEBUGFUNC("igb_read_phy_reg_sgmii_82575");
+
+	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+		DEBUGOUT1("PHY Address %u is out of range\n", offset);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_read_phy_reg_i2c(hw, offset, data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset using the serial gigabit
+ *  media independent interface.
+ **/
+static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+                                           u16 data)
+{
+	s32 ret_val = -E1000_ERR_PARAM;
+
+	DEBUGFUNC("igb_write_phy_reg_sgmii_82575");
+
+	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+		DEBUGOUT1("PHY Address %d is out of range\n", offset);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_write_phy_reg_i2c(hw, offset, data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_phy_id_82575 - Retrieve PHY addr and id
+ *  @hw: pointer to the HW structure
+ *
+ *  Retrieves the PHY address and ID for both PHY's which do and do not use
+ *  sgmi interface.
+ **/
+static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val = E1000_SUCCESS;
+	u16 phy_id;
+	u32 ctrl_ext;
+
+	DEBUGFUNC("igb_get_phy_id_82575");
+
+	/*
+	 * For SGMII PHYs, we try the list of possible addresses until
+	 * we find one that works.  For non-SGMII PHYs
+	 * (e.g. integrated copper PHYs), an address of 1 should
+	 * work.  The result of this function should mean phy->phy_addr
+	 * and phy->id are set correctly.
+	 */
+	if (!igb_sgmii_active_82575(hw)) {
+		phy->addr = 1;
+		ret_val = igb_get_phy_id(hw);
+		goto out;
+	}
+
+	/* Power on sgmii phy if it is disabled */
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+	                ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(300);
+
+	/*
+	 * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+	 * Therefore, we need to test 1-7
+	 */
+	for (phy->addr = 1; phy->addr < 8; phy->addr++) {
+		ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
+		if (ret_val == E1000_SUCCESS) {
+			DEBUGOUT2("Vendor ID 0x%08X read at address %u\n",
+			          phy_id,
+			          phy->addr);
+			/*
+			 * At the time of this writing, The M88 part is
+			 * the only supported SGMII PHY product.
+			 */
+			if (phy_id == M88_VENDOR)
+				break;
+		} else {
+			DEBUGOUT1("PHY address %u was unreadable\n",
+			          phy->addr);
+		}
+	}
+
+	/* A valid PHY type couldn't be found. */
+	if (phy->addr == 8) {
+		phy->addr = 0;
+		ret_val = -E1000_ERR_PHY;
+	} else {
+		ret_val = igb_get_phy_id(hw);
+	}
+
+	/* restore previous sfp cage power state */
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_phy_hw_reset_sgmii_82575 - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY using the serial gigabit media independent interface.
+ **/
+static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_phy_hw_reset_sgmii_82575");
+
+	/*
+	 * This isn't a true "hard" reset, but is the only reset
+	 * available to us at this time.
+	 */
+
+	DEBUGOUT("Soft resetting SGMII attached PHY...\n");
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	/*
+	 * SFP documentation requires the following to configure the SPF module
+	 * to work on SGMII.  No further documentation is given.
+	 */
+	ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.commit(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("igb_set_d0_lplu_state_82575");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (active) {
+		data |= IGP02E1000_PM_D0_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+		if (ret_val)
+			goto out;
+	} else {
+		data &= ~IGP02E1000_PM_D0_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_acquire_nvm_82575 - Request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the necessary semaphores for exclusive access to the EEPROM.
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("igb_acquire_nvm_82575");
+
+	ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_acquire_nvm_generic(hw);
+
+	if (ret_val)
+		igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_release_nvm_82575 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ *  then release the semaphores acquired.
+ **/
+static void igb_release_nvm_82575(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igb_release_nvm_82575");
+
+	igb_release_nvm_generic(hw);
+	igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  igb_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = E1000_SUCCESS;
+	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+	DEBUGFUNC("igb_acquire_swfw_sync_82575");
+
+	while (i < timeout) {
+		if (igb_get_hw_semaphore_generic(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/*
+		 * Firmware currently using resource (fwmask)
+		 * or other software thread using resource (swmask)
+		 */
+		igb_put_hw_semaphore_generic(hw);
+		msec_delay_irq(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+	igb_put_hw_semaphore_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_release_swfw_sync_82575 - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	DEBUGFUNC("igb_release_swfw_sync_82575");
+
+	while (igb_get_hw_semaphore_generic(hw) != E1000_SUCCESS);
+	/* Empty */
+
+	swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+	igb_put_hw_semaphore_generic(hw);
+}
+
+/**
+ *  igb_get_cfg_done_82575 - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	DEBUGFUNC("igb_get_cfg_done_82575");
+
+	if (hw->bus.func == E1000_FUNC_1)
+		mask = E1000_NVM_CFG_DONE_PORT_1;
+	while (timeout) {
+		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+			break;
+		msec_delay(1);
+		timeout--;
+	}
+	if (!timeout) {
+		DEBUGOUT("MNG configuration cycle has not completed.\n");
+        }
+
+	/* If EEPROM is not marked present, init the PHY manually */
+	if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+	    (hw->phy.type == e1000_phy_igp_3))
+		igb_phy_init_script_igp3(hw);
+
+	return ret_val;
+}
+
+/**
+ *  igb_get_link_up_info_82575 - Get link speed/duplex info
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  This is a wrapper function, if using the serial gigabit media independent
+ *  interface, use PCS to retrieve the link speed and duplex information.
+ *  Otherwise, use the generic function to get the link speed and duplex info.
+ **/
+static s32 igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
+                                        u16 *duplex)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("igb_get_link_up_info_82575");
+
+	if (hw->phy.media_type != e1000_media_type_copper)
+		ret_val = igb_get_pcs_speed_and_duplex_82575(hw, speed,
+		                                               duplex);
+	else
+		ret_val = igb_get_speed_and_duplex_copper_generic(hw, speed,
+		                                                    duplex);
+
+	return ret_val;
+}
+
+/**
+ *  igb_check_for_link_82575 - Check for link
+ *  @hw: pointer to the HW structure
+ *
+ *  If sgmii is enabled, then use the pcs register to determine link, otherwise
+ *  use the generic interface for determining link.
+ **/
+static s32 igb_check_for_link_82575(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 speed, duplex;
+
+	DEBUGFUNC("igb_check_for_link_82575");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
+		                                               &duplex);
+		/*
+		 * Use this flag to determine if link needs to be checked or
+		 * not.  If we have link clear the flag so that we do not
+		 * continue to check for link.
+		 */
+		hw->mac.get_link_status = !hw->mac.serdes_has_link;
+	} else {
+		ret_val = igb_check_for_copper_link_generic(hw);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Using the physical coding sub-layer (PCS), retrieve the current speed and
+ *  duplex, then store the values in the pointers provided.
+ **/
+static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
+                                                u16 *speed, u16 *duplex)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 pcs;
+
+	DEBUGFUNC("igb_get_pcs_speed_and_duplex_82575");
+
+	/* Set up defaults for the return values of this function */
+	mac->serdes_has_link = false;
+	*speed = 0;
+	*duplex = 0;
+
+	/*
+	 * Read the PCS Status register for link state. For non-copper mode,
+	 * the status register is not accurate. The PCS status register is
+	 * used instead.
+	 */
+	pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
+
+	/*
+	 * The link up bit determines when link is up on autoneg. The sync ok
+	 * gets set once both sides sync up and agree upon link. Stable link
+	 * can be determined by checking for both link up and link sync ok
+	 */
+	if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+		mac->serdes_has_link = true;
+
+		/* Detect and store PCS speed */
+		if (pcs & E1000_PCS_LSTS_SPEED_1000) {
+			*speed = SPEED_1000;
+		} else if (pcs & E1000_PCS_LSTS_SPEED_100) {
+			*speed = SPEED_100;
+		} else {
+			*speed = SPEED_10;
+		}
+
+		/* Detect and store PCS duplex */
+		if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
+			*duplex = FULL_DUPLEX;
+		} else {
+			*duplex = HALF_DUPLEX;
+		}
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_shutdown_serdes_link_82575 - Remove link during power down
+ *  @hw: pointer to the HW structure
+ *
+ *  In the case of serdes shut down sfp and PCS on driver unload
+ *  when management pass thru is not enabled.
+ **/
+void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
+{
+#if 0
+	u32 reg;
+#endif
+	u16 eeprom_data = 0;
+
+	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+	    !igb_sgmii_active_82575(hw))
+		return;
+
+	if (hw->bus.func == E1000_FUNC_0)
+		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+	else if (hw->bus.func == E1000_FUNC_1)
+		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+
+	/*
+	 * If APM is not enabled in the EEPROM and management interface is
+	 * not enabled, then power down.
+	 */
+#if 0
+	if (!(eeprom_data & E1000_NVM_APME_82575) &&
+	    !igb_enable_mng_pass_thru(hw)) {
+		/* Disable PCS to turn off link */
+		reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
+		reg &= ~E1000_PCS_CFG_PCS_EN;
+		E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
+
+		/* shutdown the laser */
+		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		reg |= E1000_CTRL_EXT_SDP3_DATA;
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+		/* flush the write to verify completion */
+		E1000_WRITE_FLUSH(hw);
+		msec_delay(1);
+	}
+#endif
+	return;
+}
+
+/**
+ *  igb_reset_hw_82575 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.
+ **/
+static s32 igb_reset_hw_82575(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+
+	DEBUGFUNC("igb_reset_hw_82575");
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = igb_disable_pcie_master_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("PCI-E Master disable polling has failed.\n");
+	}
+
+	/* set the completion timeout for interface */
+	ret_val = igb_set_pcie_completion_timeout(hw);
+	if (ret_val) {
+		DEBUGOUT("PCI-E Set completion timeout has failed.\n");
+	}
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to MAC\n");
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	ret_val = igb_get_auto_rd_done_generic(hw);
+	if (ret_val) {
+		/*
+		 * When auto config read does not complete, do not
+		 * return with an error. This can happen in situations
+		 * where there is no eeprom and prevents getting link.
+		 */
+		DEBUGOUT("Auto Read Done did not complete\n");
+	}
+
+	/* If EEPROM is not present, run manual init scripts */
+	if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+		igb_reset_init_script_82575(hw);
+
+	/* Clear any pending interrupt events. */
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_READ_REG(hw, E1000_ICR);
+
+	/* Install any alternate MAC address into RAR0 */
+	ret_val = igb_check_alt_mac_addr_generic(hw);
+
+	return ret_val;
+}
+
+/**
+ *  igb_init_hw_82575 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 igb_init_hw_82575(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	u16 i, rar_count = mac->rar_entry_count;
+
+	DEBUGFUNC("igb_init_hw_82575");
+
+	/* Initialize identification LED */
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address */
+	igb_init_rx_addrs_generic(hw, rar_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Zero out the Unicast HASH table */
+	DEBUGOUT("Zeroing the UTA\n");
+	for (i = 0; i < mac->uta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	igb_clear_hw_cntrs_82575(hw);
+
+	return ret_val;
+}
+
+/**
+ *  igb_setup_copper_link_82575 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32  ret_val;
+
+	DEBUGFUNC("igb_setup_copper_link_82575");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	ret_val = igb_setup_serdes_link_82575(hw);
+	if (ret_val)
+		goto out;
+
+	if (igb_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
+		ret_val = hw->phy.ops.reset(hw);
+		if (ret_val) {
+			DEBUGOUT("Error resetting the PHY.\n");
+			goto out;
+		}
+	}
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
+		ret_val = igb_copper_link_setup_m88(hw);
+		break;
+	case e1000_phy_igp_3:
+		ret_val = igb_copper_link_setup_igp(hw);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_setup_copper_link_generic(hw);
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_setup_serdes_link_82575 - Setup link for serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configure the physical coding sub-layer (PCS) link.  The PCS link is
+ *  used on copper connections where the serialized gigabit media independent
+ *  interface (sgmii), or serdes fiber is being used.  Configures the link
+ *  for auto-negotiation or forces speed/duplex.
+ **/
+static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
+{
+	u32 ctrl_reg, reg;
+
+	DEBUGFUNC("igb_setup_serdes_link_82575");
+
+	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+	    !igb_sgmii_active_82575(hw))
+		return E1000_SUCCESS;
+
+	/*
+	 * On the 82575, SerDes loopback mode persists until it is
+	 * explicitly turned off or a power cycle is performed.  A read to
+	 * the register does not indicate its status.  Therefore, we ensure
+	 * loopback mode is disabled during initialization.
+	 */
+	E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+
+	/* power on the sfp cage if present */
+	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl_reg |= E1000_CTRL_SLU;
+
+	if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) {
+		/* set both sw defined pins */
+		ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
+
+		/* Set switch control to serdes energy detect */
+		reg = E1000_READ_REG(hw, E1000_CONNSW);
+		reg |= E1000_CONNSW_ENRGSRC;
+		E1000_WRITE_REG(hw, E1000_CONNSW, reg);
+	}
+
+	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
+
+	if (igb_sgmii_active_82575(hw)) {
+		/* allow time for SFP cage to power up phy */
+		msec_delay(300);
+
+		/* AN time out should be disabled for SGMII mode */
+		reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
+	} else {
+		ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
+		            E1000_CTRL_FD | E1000_CTRL_FRCDPX;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+
+	/*
+	 * New SerDes mode allows for forcing speed or autonegotiating speed
+	 * at 1gb. Autoneg should be default set by most drivers. This is the
+	 * mode that will be compatible with older link partners and switches.
+	 * However, both are supported by the hardware and some drivers/tools.
+	 */
+
+	reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
+	         E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+	/*
+	 * We force flow control to prevent the CTRL register values from being
+	 * overwritten by the autonegotiated flow control values
+	 */
+	reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+
+	/*
+	 * we always set sgmii to autoneg since it is the phy that will be
+	 * forcing the link and the serdes is just a go-between
+	 */
+	if (hw->mac.autoneg || igb_sgmii_active_82575(hw)) {
+		/* Set PCS register for autoneg */
+		reg |= E1000_PCS_LCTL_FSV_1000 |  /* Force 1000 */
+		       E1000_PCS_LCTL_FDV_FULL |  /* SerDes Full dplx */
+		       E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
+		       E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
+		DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
+	} else {
+		/* Check for duplex first */
+		if (hw->mac.forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
+			reg |= E1000_PCS_LCTL_FDV_FULL;
+
+		/* No need to check for 1000/full since the spec states that
+		 * it requires autoneg to be enabled */
+		/* Now set speed */
+		if (hw->mac.forced_speed_duplex & E1000_ALL_100_SPEED)
+			reg |= E1000_PCS_LCTL_FSV_100;
+
+		/* Force speed and force link */
+		reg |= E1000_PCS_LCTL_FSD |
+		       E1000_PCS_LCTL_FORCE_LINK |
+		       E1000_PCS_LCTL_FLV_LINK_UP;
+
+		DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
+	}
+
+	E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
+
+	if (!igb_sgmii_active_82575(hw))
+		igb_force_mac_fc_generic(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_valid_led_default_82575 - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("igb_valid_led_default_82575");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+		switch(hw->phy.media_type) {
+		case e1000_media_type_internal_serdes:
+			*data = ID_LED_DEFAULT_82575_SERDES;
+			break;
+		case e1000_media_type_copper:
+		default:
+			*data = ID_LED_DEFAULT;
+			break;
+		}
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_sgmii_active_82575 - Return sgmii state
+ *  @hw: pointer to the HW structure
+ *
+ *  82575 silicon has a serialized gigabit media independent interface (sgmii)
+ *  which can be enabled for use in the embedded applications.  Simply
+ *  return the current state of the sgmii interface.
+ **/
+static bool igb_sgmii_active_82575(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+	return dev_spec->sgmii_active;
+}
+
+/**
+ *  igb_reset_init_script_82575 - Inits HW defaults after reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Inits recommended HW defaults after a reset when there is no EEPROM
+ *  detected. This is only for the 82575.
+ **/
+static s32 igb_reset_init_script_82575(struct e1000_hw* hw)
+{
+	DEBUGFUNC("igb_reset_init_script_82575");
+
+	if (hw->mac.type == e1000_82575) {
+		DEBUGOUT("Running reset init script for 82575\n");
+		/* SerDes configuration via SERDESCTRL */
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
+
+		/* CCM configuration via CCMCTL register */
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
+
+		/* PCIe lanes configuration */
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
+
+		/* PCIe PLL Configuration */
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
+		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_read_mac_addr_82575 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_read_mac_addr_82575");
+
+	/*
+	 * If there's an alternate MAC address place it in RAR0
+	 * so that it will override the Si installed default perm
+	 * address.
+	 */
+	ret_val = igb_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_read_mac_addr_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ * igb_power_down_phy_copper_82575 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void igb_power_down_phy_copper_82575(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!(phy->ops.check_reset_block))
+		return;
+
+	/* If the management interface is not enabled, then power down */
+	if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
+		igb_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  igb_clear_hw_cntrs_82575 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igb_clear_hw_cntrs_82575");
+
+	igb_clear_hw_cntrs_base_generic(hw);
+
+	E1000_READ_REG(hw, E1000_PRC64);
+	E1000_READ_REG(hw, E1000_PRC127);
+	E1000_READ_REG(hw, E1000_PRC255);
+	E1000_READ_REG(hw, E1000_PRC511);
+	E1000_READ_REG(hw, E1000_PRC1023);
+	E1000_READ_REG(hw, E1000_PRC1522);
+	E1000_READ_REG(hw, E1000_PTC64);
+	E1000_READ_REG(hw, E1000_PTC127);
+	E1000_READ_REG(hw, E1000_PTC255);
+	E1000_READ_REG(hw, E1000_PTC511);
+	E1000_READ_REG(hw, E1000_PTC1023);
+	E1000_READ_REG(hw, E1000_PTC1522);
+
+	E1000_READ_REG(hw, E1000_ALGNERRC);
+	E1000_READ_REG(hw, E1000_RXERRC);
+	E1000_READ_REG(hw, E1000_TNCRS);
+	E1000_READ_REG(hw, E1000_CEXTERR);
+	E1000_READ_REG(hw, E1000_TSCTC);
+	E1000_READ_REG(hw, E1000_TSCTFC);
+
+	E1000_READ_REG(hw, E1000_MGTPRC);
+	E1000_READ_REG(hw, E1000_MGTPDC);
+	E1000_READ_REG(hw, E1000_MGTPTC);
+
+	E1000_READ_REG(hw, E1000_IAC);
+	E1000_READ_REG(hw, E1000_ICRXOC);
+
+	E1000_READ_REG(hw, E1000_ICRXPTC);
+	E1000_READ_REG(hw, E1000_ICRXATC);
+	E1000_READ_REG(hw, E1000_ICTXPTC);
+	E1000_READ_REG(hw, E1000_ICTXATC);
+	E1000_READ_REG(hw, E1000_ICTXQEC);
+	E1000_READ_REG(hw, E1000_ICTXQMTC);
+	E1000_READ_REG(hw, E1000_ICRXDMTC);
+
+	E1000_READ_REG(hw, E1000_CBTMPC);
+	E1000_READ_REG(hw, E1000_HTDPMC);
+	E1000_READ_REG(hw, E1000_CBRMPC);
+	E1000_READ_REG(hw, E1000_RPTHC);
+	E1000_READ_REG(hw, E1000_HGPTC);
+	E1000_READ_REG(hw, E1000_HTCBDPC);
+	E1000_READ_REG(hw, E1000_HGORCL);
+	E1000_READ_REG(hw, E1000_HGORCH);
+	E1000_READ_REG(hw, E1000_HGOTCL);
+	E1000_READ_REG(hw, E1000_HGOTCH);
+	E1000_READ_REG(hw, E1000_LENERRS);
+
+	/* This register should not be read in copper configurations */
+	if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
+	    igb_sgmii_active_82575(hw))
+		E1000_READ_REG(hw, E1000_SCVPC);
+}
+
+/**
+ *  igb_rx_fifo_flush_82575 - Clean rx fifo after RX enable
+ *  @hw: pointer to the HW structure
+ *
+ *  After rx enable if managability is enabled then there is likely some
+ *  bad data at the start of the fifo and possibly in the DMA fifo.  This
+ *  function clears the fifos and flushes any packets that came in as rx was
+ *  being enabled.
+ **/
+void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
+{
+	u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
+	int i, ms_wait;
+
+	DEBUGFUNC("igb_rx_fifo_workaround_82575");
+	if (hw->mac.type != e1000_82575 ||
+	    !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
+		return;
+
+	/* Disable all RX queues */
+	for (i = 0; i < 4; i++) {
+		rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i));
+		E1000_WRITE_REG(hw, E1000_RXDCTL(i),
+		                rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE);
+	}
+	/* Poll all queues to verify they have shut down */
+	for (ms_wait = 0; ms_wait < 10; ms_wait++) {
+		msec_delay(1);
+		rx_enabled = 0;
+		for (i = 0; i < 4; i++)
+			rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i));
+		if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE))
+			break;
+	}
+
+	if (ms_wait == 10) {
+		DEBUGOUT("Queue disable timed out after 10ms\n");
+        }
+	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
+	 * incoming packets are rejected.  Set enable and wait 2ms so that
+	 * any packet that was coming in as RCTL.EN was set is flushed
+	 */
+	rfctl = E1000_READ_REG(hw, E1000_RFCTL);
+	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
+
+	rlpml = E1000_READ_REG(hw, E1000_RLPML);
+	E1000_WRITE_REG(hw, E1000_RLPML, 0);
+
+	rctl = E1000_READ_REG(hw, E1000_RCTL);
+	temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP);
+	temp_rctl |= E1000_RCTL_LPE;
+
+	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl);
+	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(2);
+
+	/* Enable RX queues that were previously enabled and restore our
+	 * previous state
+	 */
+	for (i = 0; i < 4; i++)
+		E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]);
+	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+	E1000_WRITE_FLUSH(hw);
+
+	E1000_WRITE_REG(hw, E1000_RLPML, rlpml);
+	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
+
+	/* Flush receive errors generated by workaround */
+	E1000_READ_REG(hw, E1000_ROC);
+	E1000_READ_REG(hw, E1000_RNBC);
+	E1000_READ_REG(hw, E1000_MPC);
+}
+
+/**
+ *  igb_set_pcie_completion_timeout - set pci-e completion timeout
+ *  @hw: pointer to the HW structure
+ *
+ *  The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ *  however the hardware default for these parts is 500us to 1ms which is less
+ *  than the 10ms recommended by the pci-e spec.  To address this we need to
+ *  increase the value to either 10ms to 200ms for capability version 1 config,
+ *  or 16ms to 55ms for version 2.
+ **/
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+	u32 gcr = E1000_READ_REG(hw, E1000_GCR);
+	s32 ret_val = E1000_SUCCESS;
+	u16 pcie_devctl2;
+
+	/* only take action if timeout value is defaulted to 0 */
+	if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+		goto out;
+
+	/*
+	 * if capababilities version is type 1 we can write the
+	 * timeout of 10ms to 200ms through the GCR register
+	 */
+	if (!(gcr & E1000_GCR_CAP_VER2)) {
+		gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+		goto out;
+	}
+
+	/*
+	 * for version 2 capabilities we need to write the config space
+	 * directly in order to set the completion timeout value for
+	 * 16ms to 55ms
+	 */
+	ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+	                                  &pcie_devctl2);
+	if (ret_val)
+		goto out;
+
+	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+	ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+	                                   &pcie_devctl2);
+out:
+	/* disable completion timeout resend */
+	gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+	E1000_WRITE_REG(hw, E1000_GCR, gcr);
+	return ret_val;
+}
+
+/**
+ *  igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
+ *  @hw: pointer to the hardware struct
+ *  @enable: state to enter, either enabled or disabled
+ *
+ *  enables/disables L2 switch loopback functionality.
+ **/
+void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
+{
+	u32 dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+
+	if (enable)
+		dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+	else
+		dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+
+	E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+}
+
+/**
+ *  igb_vmdq_set_replication_pf - enable or disable vmdq replication
+ *  @hw: pointer to the hardware struct
+ *  @enable: state to enter, either enabled or disabled
+ *
+ *  enables/disables replication of packets across multiple pools.
+ **/
+void igb_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
+{
+	u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
+
+	if (enable)
+		vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+	else
+		vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
+
+	E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
+}
+
+static struct pci_device_id igb_82575_nics[] = {
+        PCI_ROM(0x8086, 0x10C9, "E1000_DEV_ID_82576", "E1000_DEV_ID_82576", 0),
+        PCI_ROM(0x8086, 0x150A, "E1000_DEV_ID_82576_NS", "E1000_DEV_ID_82576_NS", 0),
+        PCI_ROM(0x8086, 0x1518, "E1000_DEV_ID_82576_NS_SERDES", "E1000_DEV_ID_82576_NS_SERDES", 0),
+        PCI_ROM(0x8086, 0x10E6, "E1000_DEV_ID_82576_FIBER", "E1000_DEV_ID_82576_FIBER", 0),
+        PCI_ROM(0x8086, 0x10E7, "E1000_DEV_ID_82576_SERDES", "E1000_DEV_ID_82576_SERDES", 0),
+        PCI_ROM(0x8086, 0x150D, "E1000_DEV_ID_82576_SERDES_QUAD", "E1000_DEV_ID_82576_SERDES_QUAD", 0),
+        PCI_ROM(0x8086, 0x10E8, "E1000_DEV_ID_82576_QUAD_COPPER", "E1000_DEV_ID_82576_QUAD_COPPER", 0),
+        PCI_ROM(0x8086, 0x10A7, "E1000_DEV_ID_82575EB_COPPER", "E1000_DEV_ID_82575EB_COPPER", 0),
+        PCI_ROM(0x8086, 0x10A9, "E1000_DEV_ID_82575EB_FIBER_SERDES", "E1000_DEV_ID_82575EB_FIBER_SERDES", 0),
+        PCI_ROM(0x8086, 0x10D6, "E1000_DEV_ID_82575GB_QUAD_COPPER", "E1000_DEV_ID_82575GB_QUAD_COPPER", 0),
+};
+
+struct pci_driver igb_82575_driver __pci_driver = {
+        .ids = igb_82575_nics,
+        .id_count = (sizeof (igb_82575_nics) / sizeof (igb_82575_nics[0])),
+        .probe = igb_probe,
+        .remove = igb_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.h
new file mode 100644
index 0000000..12c9a24
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_82575.h
@@ -0,0 +1,442 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_82575_H_
+#define _IGB_82575_H_
+
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+                                     (ID_LED_DEF1_DEF2 <<  8) | \
+                                     (ID_LED_DEF1_DEF2 <<  4) | \
+                                     (ID_LED_OFF1_ON2))
+/*
+ * Receive Address Register Count
+ * Number of high/low register pairs in the RAR.  The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * These entries are also used for MAC-based filtering.
+ */
+/*
+ * For 82576, there are an additional set of RARs that begin at an offset
+ * separate from the first set of RARs.
+ */
+#define E1000_RAR_ENTRIES_82575   16
+#define E1000_RAR_ENTRIES_82576   24
+
+struct e1000_adv_data_desc {
+	__le64 buffer_addr;    /* Address of the descriptor's data buffer */
+	union {
+		u32 data;
+		struct {
+			u32 datalen :16; /* Data buffer length */
+			u32 rsvd    :4;
+			u32 dtyp    :4;  /* Descriptor type */
+			u32 dcmd    :8;  /* Descriptor command */
+		} config;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u32 status  :4;  /* Descriptor status */
+			u32 idx     :4;
+			u32 popts   :6;  /* Packet Options */
+			u32 paylen  :18; /* Payload length */
+		} options;
+	} upper;
+};
+
+#define E1000_TXD_DTYP_ADV_C    0x2  /* Advanced Context Descriptor */
+#define E1000_TXD_DTYP_ADV_D    0x3  /* Advanced Data Descriptor */
+#define E1000_ADV_TXD_CMD_DEXT  0x20 /* Descriptor extension (0 = legacy) */
+#define E1000_ADV_TUCMD_IPV4    0x2  /* IP Packet Type: 1=IPv4 */
+#define E1000_ADV_TUCMD_IPV6    0x0  /* IP Packet Type: 0=IPv6 */
+#define E1000_ADV_TUCMD_L4T_UDP 0x0  /* L4 Packet TYPE of UDP */
+#define E1000_ADV_TUCMD_L4T_TCP 0x4  /* L4 Packet TYPE of TCP */
+#define E1000_ADV_TUCMD_MKRREQ  0x10 /* Indicates markers are required */
+#define E1000_ADV_DCMD_EOP      0x1  /* End of Packet */
+#define E1000_ADV_DCMD_IFCS     0x2  /* Insert FCS (Ethernet CRC) */
+#define E1000_ADV_DCMD_RS       0x8  /* Report Status */
+#define E1000_ADV_DCMD_VLE      0x40 /* Add VLAN tag */
+#define E1000_ADV_DCMD_TSE      0x80 /* TCP Seg enable */
+/* Extended Device Control */
+#define E1000_CTRL_EXT_NSICR    0x00000001 /* Disable Intr Clear all on read */
+
+struct e1000_adv_context_desc {
+	union {
+		u32 ip_config;
+		struct {
+			u32 iplen    :9;
+			u32 maclen   :7;
+			u32 vlan_tag :16;
+		} fields;
+	} ip_setup;
+	u32 seq_num;
+	union {
+		u64 l4_config;
+		struct {
+			u32 mkrloc :9;
+			u32 tucmd  :11;
+			u32 dtyp   :4;
+			u32 adv    :8;
+			u32 rsvd   :4;
+			u32 idx    :4;
+			u32 l4len  :8;
+			u32 mss    :16;
+		} fields;
+	} l4_setup;
+};
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK                  0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_LEGACY                    0x00000000
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT                 0x04000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION           0x06000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define E1000_SRRCTL_DESCTYPE_MASK                      0x0E000000
+#define E1000_SRRCTL_DROP_EN                            0x80000000
+
+#define E1000_SRRCTL_BSIZEPKT_MASK      0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK      0x00003F00
+
+#define E1000_TX_HEAD_WB_ENABLE   0x1
+#define E1000_TX_SEQNUM_WB_ENABLE 0x2
+
+#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#define E1000_MRQC_ENABLE_VMDQ              0x00000003
+#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005
+#define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
+
+#define E1000_VMRCTL_MIRROR_PORT_SHIFT      8
+#define E1000_VMRCTL_MIRROR_DSTPORT_MASK    (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT)
+#define E1000_VMRCTL_POOL_MIRROR_ENABLE     (1 << 0)
+#define E1000_VMRCTL_UPLINK_MIRROR_ENABLE   (1 << 1)
+#define E1000_VMRCTL_DOWNLINK_MIRROR_ENABLE (1 << 2)
+
+#define E1000_EICR_TX_QUEUE ( \
+    E1000_EICR_TX_QUEUE0 |    \
+    E1000_EICR_TX_QUEUE1 |    \
+    E1000_EICR_TX_QUEUE2 |    \
+    E1000_EICR_TX_QUEUE3)
+
+#define E1000_EICR_RX_QUEUE ( \
+    E1000_EICR_RX_QUEUE0 |    \
+    E1000_EICR_RX_QUEUE1 |    \
+    E1000_EICR_RX_QUEUE2 |    \
+    E1000_EICR_RX_QUEUE3)
+
+#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
+#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
+
+#define EIMS_ENABLE_MASK ( \
+    E1000_EIMS_RX_QUEUE  | \
+    E1000_EIMS_TX_QUEUE  | \
+    E1000_EIMS_TCP_TIMER | \
+    E1000_EIMS_OTHER)
+
+/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
+#define E1000_IMIR_PORT_IM_EN     0x00010000  /* TCP port enable */
+#define E1000_IMIR_PORT_BP        0x00020000  /* TCP port check bypass */
+#define E1000_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
+#define E1000_IMIREXT_CTRL_URG    0x00002000  /* Check URG bit in header */
+#define E1000_IMIREXT_CTRL_ACK    0x00004000  /* Check ACK bit in header */
+#define E1000_IMIREXT_CTRL_PSH    0x00008000  /* Check PSH bit in header */
+#define E1000_IMIREXT_CTRL_RST    0x00010000  /* Check RST bit in header */
+#define E1000_IMIREXT_CTRL_SYN    0x00020000  /* Check SYN bit in header */
+#define E1000_IMIREXT_CTRL_FIN    0x00040000  /* Check FIN bit in header */
+#define E1000_IMIREXT_CTRL_BP     0x00080000  /* Bypass check of ctrl bits */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+	struct {
+		__le64 pkt_addr;             /* Packet buffer address */
+		__le64 hdr_addr;             /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			union {
+				__le32 data;
+				struct {
+					__le16 pkt_info; /*RSS type, Pkt type*/
+					__le16 hdr_info; /* Split Header,
+							  * header buffer len*/
+				} hs_rss;
+			} lo_dword;
+			union {
+				__le32 rss;          /* RSS Hash */
+				struct {
+					__le16 ip_id;    /* IP id */
+					__le16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;     /* ext status/error */
+			__le16 length;           /* Packet length */
+			__le16 vlan;             /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define E1000_RXDADV_RSSTYPE_MASK        0x0000000F
+#define E1000_RXDADV_RSSTYPE_SHIFT       12
+#define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT     5
+#define E1000_RXDADV_SPLITHEADER_EN      0x00001000
+#define E1000_RXDADV_SPH                 0x8000
+#define E1000_RXDADV_STAT_TS             0x10000 /* Pkt was time stamped */
+#define E1000_RXDADV_ERR_HBO             0x00800000
+
+/* RSS Hash results */
+#define E1000_RXDADV_RSSTYPE_NONE        0x00000000
+#define E1000_RXDADV_RSSTYPE_IPV4_TCP    0x00000001
+#define E1000_RXDADV_RSSTYPE_IPV4        0x00000002
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP    0x00000003
+#define E1000_RXDADV_RSSTYPE_IPV6_EX     0x00000004
+#define E1000_RXDADV_RSSTYPE_IPV6        0x00000005
+#define E1000_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define E1000_RXDADV_RSSTYPE_IPV4_UDP    0x00000007
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP    0x00000008
+#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor */
+#define E1000_RXDADV_PKTTYPE_NONE        0x00000000
+#define E1000_RXDADV_PKTTYPE_IPV4        0x00000010 /* IPV4 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV4_EX     0x00000020 /* IPV4 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_IPV6        0x00000040 /* IPV6 hdr present */
+#define E1000_RXDADV_PKTTYPE_IPV6_EX     0x00000080 /* IPV6 hdr + extensions */
+#define E1000_RXDADV_PKTTYPE_TCP         0x00000100 /* TCP hdr present */
+#define E1000_RXDADV_PKTTYPE_UDP         0x00000200 /* UDP hdr present */
+#define E1000_RXDADV_PKTTYPE_SCTP        0x00000400 /* SCTP hdr present */
+#define E1000_RXDADV_PKTTYPE_NFS         0x00000800 /* NFS hdr present */
+
+#define E1000_RXDADV_PKTTYPE_IPSEC_ESP   0x00001000 /* IPSec ESP */
+#define E1000_RXDADV_PKTTYPE_IPSEC_AH    0x00002000 /* IPSec AH */
+#define E1000_RXDADV_PKTTYPE_LINKSEC     0x00004000 /* LinkSec Encap */
+#define E1000_RXDADV_PKTTYPE_ETQF        0x00008000 /* PKTTYPE is ETQF index */
+#define E1000_RXDADV_PKTTYPE_ETQF_MASK   0x00000070 /* ETQF has 8 indices */
+#define E1000_RXDADV_PKTTYPE_ETQF_SHIFT  4          /* Right-shift 4 bits */
+
+/* LinkSec results */
+/* Security Processing bit Indication */
+#define E1000_RXDADV_LNKSEC_STATUS_SECP         0x00020000
+#define E1000_RXDADV_LNKSEC_ERROR_BIT_MASK      0x18000000
+#define E1000_RXDADV_LNKSEC_ERROR_NO_SA_MATCH   0x08000000
+#define E1000_RXDADV_LNKSEC_ERROR_REPLAY_ERROR  0x10000000
+#define E1000_RXDADV_LNKSEC_ERROR_BAD_SIG       0x18000000
+
+#define E1000_RXDADV_IPSEC_STATUS_SECP          0x00020000
+#define E1000_RXDADV_IPSEC_ERROR_BIT_MASK       0x18000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL       0x08000000
+#define E1000_RXDADV_IPSEC_ERROR_INVALID_LENGTH         0x10000000
+#define E1000_RXDADV_IPSEC_ERROR_AUTHENTICATION_FAILED  0x18000000
+
+/* Transmit Descriptor - Advanced */
+union e1000_adv_tx_desc {
+	struct {
+		__le64 buffer_addr;    /* Address of descriptor's data buf */
+		__le32 cmd_type_len;
+		__le32 olinfo_status;
+	} read;
+	struct {
+		__le64 rsvd;       /* Reserved */
+		__le32 nxtseq_seed;
+		__le32 status;
+	} wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP     0x01000000 /* End of Packet */
+#define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS      0x08000000 /* Report Status */
+#define E1000_ADVTXD_DCMD_DDTYP_ISCSI  0x10000000 /* DDP hdr type or iSCSI */
+#define E1000_ADVTXD_DCMD_DEXT    0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE     0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE     0x80000000 /* TCP Seg enable */
+#define E1000_ADVTXD_MAC_LINKSEC  0x00040000 /* Apply LinkSec on packet */
+#define E1000_ADVTXD_MAC_TSTAMP   0x00080000 /* IEEE1588 Timestamp packet */
+#define E1000_ADVTXD_STAT_SN_CRC  0x00000002 /* NXTSEQ/SEED present in WB */
+#define E1000_ADVTXD_IDX_SHIFT    4  /* Adv desc Index shift */
+#define E1000_ADVTXD_POPTS_ISCO_1ST  0x00000000 /* 1st TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_MDL  0x00000800 /* Middle TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define E1000_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define E1000_ADVTXD_POPTS_IPSEC     0x00000400 /* IPSec offload request */
+#define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+	__le32 vlan_macip_lens;
+	__le32 seqnum_seed;
+	__le32 type_tucmd_mlhl;
+	__le32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_VLAN_SHIFT     16  /* Adv ctxt vlan tag shift */
+#define E1000_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_IPV6    0x00000000  /* IP Packet Type: 0=IPv6 */
+#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000  /* L4 Packet TYPE of UDP */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000  /* L4 Packet TYPE of SCTP */
+#define E1000_ADVTXD_TUCMD_IPSEC_TYPE_ESP    0x00002000 /* IPSec Type ESP */
+/* IPSec Encrypt Enable for ESP */
+#define E1000_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN  0x00004000
+#define E1000_ADVTXD_TUCMD_MKRREQ  0x00002000 /* Req requires Markers and CRC */
+#define E1000_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT      16  /* Adv ctxt MSS shift */
+/* Adv ctxt IPSec SA IDX mask */
+#define E1000_ADVTXD_IPSEC_SA_INDEX_MASK     0x000000FF
+/* Adv ctxt IPSec ESP len mask */
+#define E1000_ADVTXD_IPSEC_ESP_LEN_MASK      0x000000FF
+
+/* Additional Transmit Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+#define E1000_TXDCTL_SWFLSH        0x04000000 /* Tx Desc. write-back flushing */
+/* Tx Queue Arbitration Priority 0=low, 1=high */
+#define E1000_TXDCTL_PRIORITY      0x08000000
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+#define E1000_RXDCTL_SWFLSH        0x04000000 /* Rx Desc. write-back flushing */
+
+/* Direct Cache Access (DCA) definitions */
+#define E1000_DCA_CTRL_DCA_ENABLE  0x00000000 /* DCA Enable */
+#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
+#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
+#define E1000_DCA_TXCTRL_CPUID_SHIFT_82576 24 /* Tx CPUID */
+#define E1000_DCA_RXCTRL_CPUID_SHIFT_82576 24 /* Rx CPUID */
+
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNS       0x00000020          /* PN threshold - server */
+#define E1000_IMS_LSECPNS       E1000_ICR_LSECPNS   /* PN threshold - server */
+#define E1000_ICS_LSECPNS       E1000_ICR_LSECPNS   /* PN threshold - server */
+
+/* ETQF register bit definitions */
+#define E1000_ETQF_FILTER_ENABLE   (1 << 26)
+#define E1000_ETQF_IMM_INT         (1 << 29)
+#define E1000_ETQF_1588            (1 << 30)
+#define E1000_ETQF_QUEUE_ENABLE    (1 << 31)
+/*
+ * ETQF filter list: one static filter per filter consumer. This is
+ *                   to avoid filter collisions later. Add new filters
+ *                   here!!
+ *
+ * Current filters:
+ *    EAPOL 802.1x (0x888e): Filter 0
+ */
+#define E1000_ETQF_FILTER_EAPOL          0
+
+#define E1000_FTQF_VF_BP               0x00008000
+#define E1000_FTQF_1588_TIME_STAMP     0x08000000
+#define E1000_FTQF_MASK                0xF0000000
+#define E1000_FTQF_MASK_PROTO_BP       0x10000000
+#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000
+#define E1000_FTQF_MASK_DEST_ADDR_BP   0x40000000
+#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
+
+#define E1000_NVM_APME_82575          0x0400
+#define MAX_NUM_VFS                   8
+
+#define E1000_DTXSWC_MAC_SPOOF_MASK   0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK  0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK         0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
+#define E1000_DTXSWC_LLE_SHIFT        16
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31)  /* global VF LB enable */
+
+/* Easy defines for setting default pool, would normally be left a zero */
+#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
+#define E1000_VT_CTL_DEFAULT_POOL_MASK  (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
+
+/* Other useful VMD_CTL register defines */
+#define E1000_VT_CTL_IGNORE_MAC         (1 << 28)
+#define E1000_VT_CTL_DISABLE_DEF_POOL   (1 << 29)
+#define E1000_VT_CTL_VM_REPL_EN         (1 << 30)
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
+#define E1000_VMOLR_LPE        0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_RSSE       0x00020000 /* Enable RSS */
+#define E1000_VMOLR_AUPE       0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_ROMPE      0x02000000 /* Accept overflow multicast */
+#define E1000_VMOLR_ROPE       0x04000000 /* Accept overflow unicast */
+#define E1000_VMOLR_BAM        0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME       0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
+#define E1000_VMOLR_STRCRC     0x80000000 /* CRC stripping enable */
+
+#define E1000_VLVF_ARRAY_SIZE     32
+#define E1000_VLVF_VLANID_MASK    0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT  12
+#define E1000_VLVF_POOLSEL_MASK   (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_LVLAN          0x00100000
+#define E1000_VLVF_VLANID_ENABLE  0x80000000
+
+#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+#define E1000_IOVCTL 0x05BBC
+#define E1000_IOVCTL_REUSE_VFQ 0x00000001
+
+#define E1000_RPLOLR_STRVLAN   0x40000000
+#define E1000_RPLOLR_STRCRC    0x80000000
+
+#define E1000_DTXCTL_8023LL     0x0004
+#define E1000_DTXCTL_VLAN_ADDED 0x0008
+#define E1000_DTXCTL_OOS_ENABLE 0x0010
+#define E1000_DTXCTL_MDP_EN     0x0020
+#define E1000_DTXCTL_SPOOF_INT  0x0040
+
+#define ALL_QUEUES   0xFFFF
+
+/* RX packet buffer size defines */
+#define E1000_RXPBS_SIZE_MASK_82576  0x0000007F
+void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable);
+void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable);
+
+#endif /* _IGB_82575_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.c
new file mode 100644
index 0000000..eda6bc0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.c
@@ -0,0 +1,1108 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+/**
+ *  igb_init_mac_params - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the MAC
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 igb_init_mac_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.ops.init_params) {
+		ret_val = hw->mac.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("MAC Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("mac.init_mac_params was NULL\n");
+		ret_val = -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_init_nvm_params - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the NVM
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 igb_init_nvm_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->nvm.ops.init_params) {
+		ret_val = hw->nvm.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("NVM Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("nvm.init_nvm_params was NULL\n");
+		ret_val = -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_init_phy_params - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the PHY
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 igb_init_phy_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->phy.ops.init_params) {
+		ret_val = hw->phy.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("PHY Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("phy.init_phy_params was NULL\n");
+		ret_val =  -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  igb_init_mbx_params - Initialize mailbox function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function initializes the function pointers for the PHY
+ *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
+ **/
+s32 igb_init_mbx_params(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mbx.ops.init_params) {
+		ret_val = hw->mbx.ops.init_params(hw);
+		if (ret_val) {
+			DEBUGOUT("Mailbox Initialization Error\n");
+			goto out;
+		}
+	} else {
+		DEBUGOUT("mbx.init_mbx_params was NULL\n");
+		ret_val =  -E1000_ERR_CONFIG;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  igb_set_mac_type - Sets MAC type
+ *  @hw: pointer to the HW structure
+ *
+ *  This function sets the mac type of the adapter based on the
+ *  device ID stored in the hw structure.
+ *  MUST BE FIRST FUNCTION CALLED (explicitly or through
+ *  igb_setup_init_funcs()).
+ **/
+s32 igb_set_mac_type(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_set_mac_type");
+
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82575EB_COPPER:
+	case E1000_DEV_ID_82575EB_FIBER_SERDES:
+	case E1000_DEV_ID_82575GB_QUAD_COPPER:
+		mac->type = e1000_82575;
+		break;
+	case E1000_DEV_ID_82576:
+	case E1000_DEV_ID_82576_FIBER:
+	case E1000_DEV_ID_82576_SERDES:
+	case E1000_DEV_ID_82576_QUAD_COPPER:
+	case E1000_DEV_ID_82576_NS:
+	case E1000_DEV_ID_82576_NS_SERDES:
+	case E1000_DEV_ID_82576_SERDES_QUAD:
+		mac->type = e1000_82576;
+		break;
+	default:
+		/* Should never have loaded on this device */
+		ret_val = -E1000_ERR_MAC_INIT;
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igb_setup_init_funcs - Initializes function pointers
+ *  @hw: pointer to the HW structure
+ *  @init_device: true will initialize the rest of the function pointers
+ *                 getting the device ready for use.  false will only set
+ *                 MAC type and the function pointers for the other init
+ *                 functions.  Passing false will not generate any hardware
+ *                 reads or writes.
+ *
+ *  This function must be called by a driver in order to use the rest
+ *  of the 'shared' code files. Called by drivers only.
+ **/
+s32 igb_setup_init_funcs(struct e1000_hw *hw, bool init_device)
+{
+	s32 ret_val;
+
+	/* Can't do much good without knowing the MAC type. */
+	ret_val = igb_set_mac_type(hw);
+	if (ret_val) {
+		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
+		goto out;
+	}
+
+	if (!hw->hw_addr) {
+		DEBUGOUT("ERROR: Registers not mapped\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Init function pointers to generic implementations. We do this first
+	 * allowing a driver module to override it afterward.
+	 */
+	igb_init_mac_ops_generic(hw);
+	igb_init_nvm_ops_generic(hw);
+#if 0
+	igb_init_mbx_ops_generic(hw);
+#endif
+	/*
+	 * Set up the init function pointers. These are functions within the
+	 * adapter family file that sets up function pointers for the rest of
+	 * the functions in that family.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82575:
+	case e1000_82576:
+		igb_init_function_pointers_82575(hw);
+		break;
+	default:
+		DEBUGOUT("Hardware not supported\n");
+		ret_val = -E1000_ERR_CONFIG;
+		break;
+	}
+
+	/*
+	 * Initialize the rest of the function pointers. These require some
+	 * register reads/writes in some cases.
+	 */
+	if (!(ret_val) && init_device) {
+		ret_val = igb_init_mac_params(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = igb_init_nvm_params(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = igb_init_phy_params(hw);
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = igb_init_mbx_params(hw);
+		if (ret_val)
+			goto out;
+#endif
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_bus_info - Obtain bus information for adapter
+ *  @hw: pointer to the HW structure
+ *
+ *  This will obtain information about the HW bus for which the
+ *  adapter is attached and stores it in the hw structure. This is a
+ *  function pointer entry point called by drivers.
+ **/
+s32 igb_get_bus_info(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.get_bus_info)
+		return hw->mac.ops.get_bus_info(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  This clears the VLAN filter table on the adapter. This is a function
+ *  pointer entry point called by drivers.
+ **/
+void igb_clear_vfta(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.clear_vfta)
+		hw->mac.ops.clear_vfta(hw);
+}
+
+/**
+ *  igb_write_vfta - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: the 32-bit offset in which to write the value to.
+ *  @value: the 32-bit value to write at location offset.
+ *
+ *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
+ *  table. This is a function pointer entry point called by drivers.
+ **/
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	if (hw->mac.ops.write_vfta)
+		hw->mac.ops.write_vfta(hw, offset, value);
+}
+
+/**
+ *  igb_update_mc_addr_list - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates the Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
+                               u32 mc_addr_count)
+{
+	if (hw->mac.ops.update_mc_addr_list)
+		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
+		                                mc_addr_count);
+}
+
+/**
+ *  igb_force_mac_fc - Force MAC flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings. Currently no func pointer exists
+ *  and all implementations are handled in the generic version of this
+ *  function.
+ **/
+s32 igb_force_mac_fc(struct e1000_hw *hw)
+{
+	return igb_force_mac_fc_generic(hw);
+}
+
+/**
+ *  igb_check_for_link - Check/Store link connection
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks the link condition of the adapter and stores the
+ *  results in the hw->mac structure. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 igb_check_for_link(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.check_for_link)
+		return hw->mac.ops.check_for_link(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_check_mng_mode - Check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point called by drivers.
+ **/
+bool igb_check_mng_mode(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.check_mng_mode)
+		return hw->mac.ops.check_mng_mode(hw);
+
+	return false;
+}
+
+#if 0
+/**
+ *  igb_mng_write_dhcp_info - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 igb_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
+{
+	return igb_mng_write_dhcp_info_generic(hw, buffer, length);
+}
+#endif
+
+/**
+ *  igb_reset_hw - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 igb_reset_hw(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.reset_hw)
+		return hw->mac.ops.reset_hw(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_init_hw - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation. This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 igb_init_hw(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.init_hw)
+		return hw->mac.ops.init_hw(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_setup_link - Configures link and flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  This configures link and flow control settings for the adapter. This
+ *  is a function pointer entry point called by drivers. While modules can
+ *  also call this, they probably call their own version of this function.
+ **/
+s32 igb_setup_link(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.setup_link)
+		return hw->mac.ops.setup_link(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_get_speed_and_duplex - Returns current speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to a 16-bit value to store the speed
+ *  @duplex: pointer to a 16-bit value to store the duplex.
+ *
+ *  This returns the speed and duplex of the adapter in the two 'out'
+ *  variables passed in. This is a function pointer entry point called
+ *  by drivers.
+ **/
+s32 igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+	if (hw->mac.ops.get_link_up_info)
+		return hw->mac.ops.get_link_up_info(hw, speed, duplex);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_setup_led - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 igb_setup_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.setup_led)
+		return hw->mac.ops.setup_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_cleanup_led - Restores SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This restores the SW controllable LED to the value saved off by
+ *  e1000_setup_led. This is a function pointer entry point called by drivers.
+ **/
+s32 igb_cleanup_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.cleanup_led)
+		return hw->mac.ops.cleanup_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_blink_led - Blink SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This starts the adapter LED blinking. Request the LED to be setup first
+ *  and cleaned up after. This is a function pointer entry point called by
+ *  drivers.
+ **/
+s32 igb_blink_led(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.blink_led)
+		return hw->mac.ops.blink_led(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_id_led_init - store LED configurations in SW
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the LED config in SW. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 igb_id_led_init(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.id_led_init)
+		return hw->mac.ops.id_led_init(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_led_on - Turn on SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED on. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 igb_led_on(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.led_on)
+		return hw->mac.ops.led_on(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_led_off - Turn off SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Turns the SW defined LED off. This is a function pointer entry point
+ *  called by drivers.
+ **/
+s32 igb_led_off(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.led_off)
+		return hw->mac.ops.led_off(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_reset_adaptive - Reset adaptive IFS
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the adaptive IFS. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igb_reset_adaptive(struct e1000_hw *hw)
+{
+	igb_reset_adaptive_generic(hw);
+}
+
+/**
+ *  igb_update_adaptive - Update adaptive IFS
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates adapter IFS. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igb_update_adaptive(struct e1000_hw *hw)
+{
+	igb_update_adaptive_generic(hw);
+}
+
+/**
+ *  igb_disable_pcie_master - Disable PCI-Express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests. Currently no func pointer exists and all implementations are
+ *  handled in the generic version of this function.
+ **/
+s32 igb_disable_pcie_master(struct e1000_hw *hw)
+{
+	return igb_disable_pcie_master_generic(hw);
+}
+
+/**
+ *  igb_config_collision_dist - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup.
+ **/
+void igb_config_collision_dist(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.config_collision_dist)
+		hw->mac.ops.config_collision_dist(hw);
+}
+
+/**
+ *  igb_rar_set - Sets a receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: address to set the RAR to
+ *  @index: the RAR to set
+ *
+ *  Sets a Receive Address Register (RAR) to the specified address.
+ **/
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	if (hw->mac.ops.rar_set)
+		hw->mac.ops.rar_set(hw, addr, index);
+}
+
+/**
+ *  igb_validate_mdi_setting - Ensures valid MDI/MDIX SW state
+ *  @hw: pointer to the HW structure
+ *
+ *  Ensures that the MDI/MDIX SW state is valid.
+ **/
+s32 igb_validate_mdi_setting(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.validate_mdi_setting)
+		return hw->mac.ops.validate_mdi_setting(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_mta_set - Sets multicast table bit
+ *  @hw: pointer to the HW structure
+ *  @hash_value: Multicast hash value.
+ *
+ *  This sets the bit in the multicast table corresponding to the
+ *  hash value.  This is a function pointer entry point called by drivers.
+ **/
+void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+	if (hw->mac.ops.mta_set)
+		hw->mac.ops.mta_set(hw, hash_value);
+}
+
+/**
+ *  igb_hash_mc_addr - Determines address location in multicast table
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: Multicast address to hash.
+ *
+ *  This hashes an address to determine its location in the multicast
+ *  table. Currently no func pointer exists and all implementations
+ *  are handled in the generic version of this function.
+ **/
+u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+	return igb_hash_mc_addr_generic(hw, mc_addr);
+}
+
+/**
+ *  igb_enable_tx_pkt_filtering - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+#if 0
+bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+	return igb_enable_tx_pkt_filtering_generic(hw);
+}
+#endif
+
+/**
+ *  igb_mng_host_if_write - Writes to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 igb_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length,
+                            u16 offset, u8 *sum)
+{
+	if (hw->mac.ops.mng_host_if_write)
+		return hw->mac.ops.mng_host_if_write(hw, buffer, length,
+		                                     offset, sum);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ *  igb_mng_write_cmd_header - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 igb_mng_write_cmd_header(struct e1000_hw *hw,
+                               struct e1000_host_mng_command_header *hdr)
+{
+	if (hw->mac.ops.mng_write_cmd_header)
+		return hw->mac.ops.mng_write_cmd_header(hw, hdr);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ *  igb_mng_enable_host_if - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 igb_mng_enable_host_if(struct e1000_hw * hw)
+{
+	if (hw->mac.ops.mng_enable_host_if)
+		return hw->mac.ops.mng_enable_host_if(hw);
+
+	return E1000_NOT_IMPLEMENTED;
+}
+
+/**
+ *  igb_wait_autoneg - Waits for autonegotiation completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for autoneg to complete. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+s32 igb_wait_autoneg(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.wait_autoneg)
+		return hw->mac.ops.wait_autoneg(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_check_reset_block - Verifies PHY can be reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks if the PHY is in a state that can be reset or if manageability
+ *  has it tied up. This is a function pointer entry point called by drivers.
+ **/
+s32 igb_check_reset_block(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.check_reset_block)
+		return hw->phy.ops.check_reset_block(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_read_phy_reg - Reads PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to read
+ *  @data: the buffer to store the 16-bit read.
+ *
+ *  Reads the PHY register and returns the value in data.
+ *  This is a function pointer entry point called by drivers.
+ **/
+s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	if (hw->phy.ops.read_reg)
+		return hw->phy.ops.read_reg(hw, offset, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_write_phy_reg - Writes PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to write
+ *  @data: the value to write.
+ *
+ *  Writes the PHY register at offset with the value in data.
+ *  This is a function pointer entry point called by drivers.
+ **/
+s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	if (hw->phy.ops.write_reg)
+		return hw->phy.ops.write_reg(hw, offset, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_release_phy - Generic release PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return if silicon family does not require a semaphore when accessing the
+ *  PHY.
+ **/
+void igb_release_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.release)
+		hw->phy.ops.release(hw);
+}
+
+/**
+ *  igb_acquire_phy - Generic acquire PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family does not require a semaphore when
+ *  accessing the PHY.
+ **/
+s32 igb_acquire_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.acquire)
+		return hw->phy.ops.acquire(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_read_kmrn_reg - Reads register using Kumeran interface
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to read
+ *  @data: the location to store the 16-bit value read.
+ *
+ *  Reads a register out of the Kumeran interface. Currently no func pointer
+ *  exists and all implementations are handled in the generic version of
+ *  this function.
+ **/
+s32 igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return igb_read_kmrn_reg_generic(hw, offset, data);
+}
+
+/**
+ *  igb_write_kmrn_reg - Writes register using Kumeran interface
+ *  @hw: pointer to the HW structure
+ *  @offset: the register to write
+ *  @data: the value to write.
+ *
+ *  Writes a register to the Kumeran interface. Currently no func pointer
+ *  exists and all implementations are handled in the generic version of
+ *  this function.
+ **/
+s32 igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return igb_write_kmrn_reg_generic(hw, offset, data);
+}
+
+#if 0
+/**
+ *  igb_get_cable_length - Retrieves cable length estimation
+ *  @hw: pointer to the HW structure
+ *
+ *  This function estimates the cable length and stores them in
+ *  hw->phy.min_length and hw->phy.max_length. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 igb_get_cable_length(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_cable_length)
+		return hw->phy.ops.get_cable_length(hw);
+
+	return E1000_SUCCESS;
+}
+#endif
+
+/**
+ *  igb_get_phy_info - Retrieves PHY information from registers
+ *  @hw: pointer to the HW structure
+ *
+ *  This function gets some information from various PHY registers and
+ *  populates hw->phy values with it. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 igb_get_phy_info(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_info)
+		return hw->phy.ops.get_info(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_phy_hw_reset - Hard PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs a hard PHY reset. This is a function pointer entry point called
+ *  by drivers.
+ **/
+s32 igb_phy_hw_reset(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.reset)
+		return hw->phy.ops.reset(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_phy_commit - Soft PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs a soft PHY reset on those that apply. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 igb_phy_commit(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.commit)
+		return hw->phy.ops.commit(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_set_d0_lplu_state - Sets low power link up state for D0
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D0
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D0
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.  This is a function pointer entry point called by drivers.
+ **/
+s32 igb_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+	if (hw->phy.ops.set_d0_lplu_state)
+		return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.  This is a function pointer entry point called by drivers.
+ **/
+s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+	if (hw->phy.ops.set_d3_lplu_state)
+		return hw->phy.ops.set_d3_lplu_state(hw, active);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_read_mac_addr - Reads MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MAC address out of the adapter and stores it in the HW structure.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+s32 igb_read_mac_addr(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.read_mac_addr)
+		return hw->mac.ops.read_mac_addr(hw);
+
+	return igb_read_mac_addr_generic(hw);
+}
+
+/**
+ *  igb_read_pba_num - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ *  Currently no func pointer exists and all implementations are handled in the
+ *  generic version of this function.
+ **/
+s32 igb_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
+{
+	return igb_read_pba_num_generic(hw, pba_num);
+}
+
+/**
+ *  igb_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Validates the NVM checksum is correct. This is a function pointer entry
+ *  point called by drivers.
+ **/
+s32 igb_validate_nvm_checksum(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.validate)
+		return hw->nvm.ops.validate(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_update_nvm_checksum - Updates NVM (EEPROM) checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the NVM checksum. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+s32 igb_update_nvm_checksum(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.update)
+		return hw->nvm.ops.update(hw);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_reload_nvm - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+void igb_reload_nvm(struct e1000_hw *hw)
+{
+	if (hw->nvm.ops.reload)
+		hw->nvm.ops.reload(hw);
+}
+
+/**
+ *  igb_read_nvm - Reads NVM (EEPROM)
+ *  @hw: pointer to the HW structure
+ *  @offset: the word offset to read
+ *  @words: number of 16-bit words to read
+ *  @data: pointer to the properly sized buffer for the data.
+ *
+ *  Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	if (hw->nvm.ops.read)
+		return hw->nvm.ops.read(hw, offset, words, data);
+
+	return -E1000_ERR_CONFIG;
+}
+
+/**
+ *  igb_write_nvm - Writes to NVM (EEPROM)
+ *  @hw: pointer to the HW structure
+ *  @offset: the word offset to read
+ *  @words: number of 16-bit words to write
+ *  @data: pointer to the properly sized buffer for the data.
+ *
+ *  Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
+ *  pointer entry point called by drivers.
+ **/
+s32 igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	if (hw->nvm.ops.write)
+		return hw->nvm.ops.write(hw, offset, words, data);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_write_8bit_ctrl_reg - Writes 8bit Control register
+ *  @hw: pointer to the HW structure
+ *  @reg: 32bit register offset
+ *  @offset: the register to write
+ *  @data: the value to write.
+ *
+ *  Writes the PHY register at offset with the value in data.
+ *  This is a function pointer entry point called by drivers.
+ **/
+s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, u32 offset,
+                              u8 data)
+{
+	return igb_write_8bit_ctrl_reg_generic(hw, reg, offset, data);
+}
+
+/**
+ * igb_power_up_phy - Restores link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void igb_power_up_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.power_up)
+		hw->phy.ops.power_up(hw);
+
+	igb_setup_link(hw);
+}
+
+/**
+ * igb_power_down_phy - Power down PHY
+ * @hw: pointer to the HW structure
+ *
+ * The phy may be powered down to save power, to turn off link when the
+ * driver is unloaded, or wake on lan is not enabled (among others).
+ **/
+void igb_power_down_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.power_down)
+		hw->phy.ops.power_down(hw);
+}
+
+/**
+ *  igb_shutdown_fiber_serdes_link - Remove link during power down
+ *  @hw: pointer to the HW structure
+ *
+ *  Shutdown the optics and PCS on driver unload.
+ **/
+void igb_shutdown_fiber_serdes_link(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.shutdown_serdes)
+		hw->mac.ops.shutdown_serdes(hw);
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.h
new file mode 100644
index 0000000..2d97fec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_api.h
@@ -0,0 +1,166 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_API_H_
+#define _IGB_API_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+#include "igb_hw.h"
+
+extern void    igb_init_function_pointers_82575(struct e1000_hw *hw) __attribute__((weak));
+extern void    igb_rx_fifo_flush_82575(struct e1000_hw *hw) __attribute__((weak));
+extern void    igb_init_function_pointers_vf(struct e1000_hw *hw) __attribute__((weak));
+extern void    igb_shutdown_fiber_serdes_link(struct e1000_hw *hw) __attribute__((weak));
+
+s32  igb_set_mac_type(struct e1000_hw *hw);
+s32  igb_setup_init_funcs(struct e1000_hw *hw, bool init_device);
+s32  igb_init_mac_params(struct e1000_hw *hw);
+s32  igb_init_nvm_params(struct e1000_hw *hw);
+s32  igb_init_phy_params(struct e1000_hw *hw);
+s32  igb_init_mbx_params(struct e1000_hw *hw);
+s32  igb_get_bus_info(struct e1000_hw *hw);
+void igb_clear_vfta(struct e1000_hw *hw);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+s32  igb_force_mac_fc(struct e1000_hw *hw);
+s32  igb_check_for_link(struct e1000_hw *hw);
+s32  igb_reset_hw(struct e1000_hw *hw);
+s32  igb_init_hw(struct e1000_hw *hw);
+s32  igb_setup_link(struct e1000_hw *hw);
+s32  igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed,
+                                u16 *duplex);
+s32  igb_disable_pcie_master(struct e1000_hw *hw);
+void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
+u32  igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+                               u8 *mc_addr_list, u32 mc_addr_count);
+s32  igb_setup_led(struct e1000_hw *hw);
+s32  igb_cleanup_led(struct e1000_hw *hw);
+s32  igb_check_reset_block(struct e1000_hw *hw);
+s32  igb_blink_led(struct e1000_hw *hw);
+s32  igb_led_on(struct e1000_hw *hw);
+s32  igb_led_off(struct e1000_hw *hw);
+s32 igb_id_led_init(struct e1000_hw *hw);
+void igb_reset_adaptive(struct e1000_hw *hw);
+void igb_update_adaptive(struct e1000_hw *hw);
+#if 0
+s32  igb_get_cable_length(struct e1000_hw *hw);
+#endif
+s32  igb_validate_mdi_setting(struct e1000_hw *hw);
+s32  igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
+                               u32 offset, u8 data);
+s32  igb_get_phy_info(struct e1000_hw *hw);
+void igb_release_phy(struct e1000_hw *hw);
+s32  igb_acquire_phy(struct e1000_hw *hw);
+s32  igb_phy_hw_reset(struct e1000_hw *hw);
+s32  igb_phy_commit(struct e1000_hw *hw);
+void igb_power_up_phy(struct e1000_hw *hw);
+void igb_power_down_phy(struct e1000_hw *hw);
+s32  igb_read_mac_addr(struct e1000_hw *hw);
+s32  igb_read_pba_num(struct e1000_hw *hw, u32 *part_num);
+void igb_reload_nvm(struct e1000_hw *hw);
+s32  igb_update_nvm_checksum(struct e1000_hw *hw);
+s32  igb_validate_nvm_checksum(struct e1000_hw *hw);
+s32  igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words,
+                     u16 *data);
+s32  igb_wait_autoneg(struct e1000_hw *hw);
+s32  igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32  igb_set_d0_lplu_state(struct e1000_hw *hw, bool active);
+bool igb_check_mng_mode(struct e1000_hw *hw);
+bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw);
+s32  igb_mng_enable_host_if(struct e1000_hw *hw);
+s32  igb_mng_host_if_write(struct e1000_hw *hw,
+                             u8 *buffer, u16 length, u16 offset, u8 *sum);
+s32  igb_mng_write_cmd_header(struct e1000_hw *hw,
+                                struct e1000_host_mng_command_header *hdr);
+s32  igb_mng_write_dhcp_info(struct e1000_hw * hw,
+                                    u8 *buffer, u16 length);
+
+/*
+ * TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct e1000_hw
+ *      status = the 8 bit status field of the Rx descriptor with EOP set
+ *      error = the 8 bit error field of the Rx descriptor with EOP set
+ *      length = the sum of all the length fields of the Rx descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = true;
+ *      e1000_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = false;
+ *  }
+ *  ...
+ */
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+#define TBI_ACCEPT(a, status, errors, length, last_byte, min_frame_size, max_frame_size) \
+    (e1000_tbi_sbp_enabled_82543(a) && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+          (((length) > (min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= (max_frame_size + 1))) : \
+          (((length) > min_frame_size) && \
+           ((length) <= (max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+#endif /* _IGB_API_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_defines.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_defines.h
new file mode 100644
index 0000000..4f58ba8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_defines.h
@@ -0,0 +1,1515 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_DEFINES_H_
+#define _IGB_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
+#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
+/*
+ * For 82576 to utilize Extended filter masks in addition to
+ * existing (filter) masks
+ */
+#define E1000_WUFC_EXT_FLX_FILTERS      0x00300000 /* Ext. FLX filter mask */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+#define E1000_WUS_ARP          E1000_WUFC_ARP
+#define E1000_WUS_IPV4         E1000_WUFC_IPV4
+#define E1000_WUS_IPV6         E1000_WUFC_IPV6
+#define E1000_WUS_FLX0         E1000_WUFC_FLX0
+#define E1000_WUS_FLX1         E1000_WUFC_FLX1
+#define E1000_WUS_FLX2         E1000_WUFC_FLX2
+#define E1000_WUS_FLX3         E1000_WUFC_FLX3
+#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+/* Two Extended Flexible Filters are supported (82576) */
+#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX     2
+#define E1000_FHFT_LENGTH_OFFSET        0xFC /* Length byte in FHFT */
+#define E1000_FHFT_LENGTH_MASK          0x0FF /* Length in lower byte */
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+/* Physical Func Reset Done Indication */
+#define E1000_CTRL_EXT_PFRSTD    0x00004000
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
+                                                  * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
+                                                  * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_REG_ADDR         0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_PHY_ADDR         0x07000000
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_RESET            0x10000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+#define E1000_IVAR_VALID        0x80
+#define E1000_GPIE_NSICR        0x00000001
+#define E1000_GPIE_MSIX_MODE    0x00000010
+#define E1000_GPIE_EIAME        0x40000000
+#define E1000_GPIE_PBA          0x80000000
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK                 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x01
+#define E1000_SWFW_PHY0_SM  0x02
+#define E1000_SWFW_PHY1_SM  0x04
+#define E1000_SWFW_CSR_SM   0x08
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+                                             * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+                                               * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+                                           * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_ADVD3WUC 0x00100000  /* D3 WUC */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_CFG_PCS_EN             8
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_10            0
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_10          0
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
+                                                 * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
+                                            * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME   20
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+#define E1000_RFCTL_LEF                 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE       4
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_SPD_EN             0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K  0x0006    /* 6KB */
+#define E1000_PBA_8K  0x0008    /* 8KB */
+#define E1000_PBA_10K 0x000A    /* 10KB */
+#define E1000_PBA_12K 0x000C    /* 12KB */
+#define E1000_PBA_14K 0x000E    /* 14KB */
+#define E1000_PBA_16K 0x0010    /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB */
+#define E1000_PBA_64K 0x0040    /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
+                                            * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
+                                            * bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
+                                            * an interrupt */
+#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
+
+
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+#define E1000_TCPTIMER_KS       0x00000100 /* KickStart */
+#define E1000_TCPTIMER_COUNT_ENABLE       0x00000200 /* Count Enable */
+#define E1000_TCPTIMER_COUNT_FINISH       0x00000400 /* Count finish */
+#define E1000_TCPTIMER_LOOP     0x00000800 /* Loop */
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EIMS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EIMS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EIMS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EIMS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EIMS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EIMS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EIMS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EIMS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Extended Interrupt Cause Set */
+#define E1000_EICS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EICS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EICS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EICS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EICS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EICS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EICS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EICS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EICS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EICS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+#define E1000_EITR_ITR_INT_MASK 0x0000FFFF
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX      15
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
+#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_CC         0x10000000        /* Receive config change */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
+
+#define E1000_TSYNCTXCTL_VALID    0x00000001 /* tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED  0x00000010 /* enable tx timestampping */
+
+#define E1000_TSYNCRXCTL_VALID      0x00000001 /* rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK  0x0000000E /* rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2       0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1       0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2    0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL         0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2    0x0A
+#define E1000_TSYNCRXCTL_ENABLED    0x00000010 /* enable rx timestampping */
+
+#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK   0x000000FF
+#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE       0x00
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE  0x01
+#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE   0x02
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03
+#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04
+
+#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK               0x00000F00
+#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE                 0x0000
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE            0x0100
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE       0x0200
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE      0x0300
+#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE             0x0800
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE           0x0900
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE  0x0A00
+#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE             0x0B00
+#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE           0x0C00
+#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE           0x0D00
+
+#define E1000_TIMINCA_16NS_SHIFT 24
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
+#define E1000_GCR_CAP_VER2              0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                           E1000_GCR_RXDSCW_NO_SNOOP      | \
+                           E1000_GCR_RXDSCR_NO_SNOOP      | \
+                           E1000_GCR_TXD_NO_SNOOP         | \
+                           E1000_GCR_TXDSCW_NO_SNOOP      | \
+                           E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Register */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT                 0x0003
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_VERSION                0x0005
+#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD         0x0007
+#define NVM_INIT_CONTROL1_REG      0x000A
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_FLASH_VERSION          0x0032
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+#define NVM_WORD0F_ANE              0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
+#define NVM_WORD0F_LPLU             0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_MAC_ADDR_OFFSET        0
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_RESERVED_WORD          0xFFFF
+#define NVM_PHY_CLASS_A            0x8000
+#define NVM_SERDES_AMPLITUDE_MASK  0x000F
+#define NVM_SIZE_MASK              0x1C00
+#define NVM_SIZE_SHIFT             10
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+#define NVM_SWDPIO_EXT_SHIFT       4
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+#define NVM_STATUS_WEN_SPI         0x02
+#define NVM_STATUS_BP0_SPI         0x04
+#define NVM_STATUS_BP1_SPI         0x08
+#define NVM_STATUS_WPEN_SPI        0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                              (ID_LED_OFF1_OFF2 <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+#define PCIE_DEVICE_CONTROL2         0x28
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+#define PCIE_DEVICE_CONTROL2_16ms    0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1011_I_REV_4     0x04
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+#define IGP04E1000_E_PHY_ID  0x02A80391
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+        GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS         \
+        GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE          \
+        GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2       \
+        GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR         \
+        GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT         \
+        GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+        GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+        GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL       \
+        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+        GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2     \
+        GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+        GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+        GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET          \
+        GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID         \
+        GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID           \
+        GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+        GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL     \
+        GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+        GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL           \
+        GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL         \
+        GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC     \
+        GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS        \
+        GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY         \
+        GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE       \
+        GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC           \
+        GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+/* LinkSec register fields */
+#define E1000_LSECTXCAP_SUM_MASK        0x00FF0000
+#define E1000_LSECTXCAP_SUM_SHIFT       16
+#define E1000_LSECRXCAP_SUM_MASK        0x00FF0000
+#define E1000_LSECRXCAP_SUM_SHIFT       16
+
+#define E1000_LSECTXCTRL_EN_MASK        0x00000003
+#define E1000_LSECTXCTRL_DISABLE        0x0
+#define E1000_LSECTXCTRL_AUTH           0x1
+#define E1000_LSECTXCTRL_AUTH_ENCRYPT   0x2
+#define E1000_LSECTXCTRL_AISCI          0x00000020
+#define E1000_LSECTXCTRL_PNTHRSH_MASK   0xFFFFFF00
+#define E1000_LSECTXCTRL_RSV_MASK       0x000000D8
+
+#define E1000_LSECRXCTRL_EN_MASK        0x0000000C
+#define E1000_LSECRXCTRL_EN_SHIFT       2
+#define E1000_LSECRXCTRL_DISABLE        0x0
+#define E1000_LSECRXCTRL_CHECK          0x1
+#define E1000_LSECRXCTRL_STRICT         0x2
+#define E1000_LSECRXCTRL_DROP           0x3
+#define E1000_LSECRXCTRL_PLSH           0x00000040
+#define E1000_LSECRXCTRL_RP             0x00000080
+#define E1000_LSECRXCTRL_RSV_MASK       0xFFFFFF33
+
+
+
+#endif /* _IGB_DEFINES_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_hw.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_hw.h
new file mode 100644
index 0000000..65a04f2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_hw.h
@@ -0,0 +1,697 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_HW_H_
+#define _IGB_HW_H_
+
+#include "igb_osdep.h"
+#include "igb_regs.h"
+#include "igb_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82576                    0x10C9
+#define E1000_DEV_ID_82576_FIBER              0x10E6
+#define E1000_DEV_ID_82576_SERDES             0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER        0x10E8
+#define E1000_DEV_ID_82576_NS                 0x150A
+#define E1000_DEV_ID_82576_NS_SERDES          0x1518
+#define E1000_DEV_ID_82576_SERDES_QUAD        0x150D
+#define E1000_DEV_ID_82575EB_COPPER           0x10A7
+#define E1000_DEV_ID_82575EB_FIBER_SERDES     0x10A9
+#define E1000_DEV_ID_82575GB_QUAD_COPPER      0x10D6
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0     0
+#define E1000_FUNC_1     1
+
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82575,
+	e1000_82576,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum e1000_media_type {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large,
+};
+
+enum e1000_phy_type {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+	e1000_phy_vf,
+};
+
+enum e1000_bus_type {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+};
+
+enum e1000_serdes_link_state {
+	e1000_serdes_link_down = 0,
+	e1000_serdes_link_autoneg_progress,
+	e1000_serdes_link_autoneg_complete,
+	e1000_serdes_link_forced_up
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	__le64 buffer_addr; /* Address of the descriptor's data buffer */
+	__le16 length;      /* Length of data DMAed into data buffer */
+	__le16 csum;        /* Packet checksum */
+	u8  status;         /* Descriptor status */
+	u8  errors;         /* Descriptor Errors */
+	__le16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		__le64 buffer_addr;
+		__le64 reserved;
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;         /* RSS Hash */
+				struct {
+					__le16 ip_id;  /* IP id */
+					__le16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length;
+			__le16 vlan;          /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		__le64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			__le32 mrq;           /* Multiple Rx Queues */
+			union {
+				__le32 rss;           /* RSS Hash */
+				struct {
+					__le16 ip_id;    /* IP id */
+					__le16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error;  /* ext status/error */
+			__le16 length0;       /* length of buffer 0 */
+			__le16 vlan;          /* VLAN tag */
+		} middle;
+		struct {
+			__le16 header_status;
+			__le16 length[3];     /* length of buffers 1-3 */
+		} upper;
+		__le64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 cso;           /* Checksum offset */
+			u8 cmd;           /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 css;           /* Checksum start */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		__le32 ip_config;
+		struct {
+			u8 ipcss;         /* IP checksum start */
+			u8 ipcso;         /* IP checksum offset */
+			__le16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		__le32 tcp_config;
+		struct {
+			u8 tucss;         /* TCP checksum start */
+			u8 tucso;         /* TCP checksum offset */
+			__le16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	__le32 cmd_and_length;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 hdr_len;       /* Header length */
+			__le16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		__le32 data;
+		struct {
+			__le16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		__le32 data;
+		struct {
+			u8 status;        /* Descriptor status */
+			u8 popts;         /* Packet Options */
+			__le16 special;
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 tor;
+	u64 tot;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+	u64 cbtmpc;
+	u64 htdpmc;
+	u64 cbrdpc;
+	u64 cbrmpc;
+	u64 rpthc;
+	u64 hgptc;
+	u64 htcbdpc;
+	u64 hgorc;
+	u64 hgotc;
+	u64 lenerrs;
+	u64 scvpc;
+	u64 hrmpc;
+	u64 doosync;
+};
+
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "igb_mac.h"
+#include "igb_phy.h"
+#include "igb_nvm.h"
+#include "igb_manage.h"
+
+struct e1000_mac_operations {
+	/* Function pointers for the MAC. */
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*id_led_init)(struct e1000_hw *);
+	s32  (*blink_led)(struct e1000_hw *);
+	s32  (*check_for_link)(struct e1000_hw *);
+	bool (*check_mng_mode)(struct e1000_hw *hw);
+	s32  (*cleanup_led)(struct e1000_hw *);
+	void (*clear_hw_cntrs)(struct e1000_hw *);
+	void (*clear_vfta)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	void (*set_lan_id)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	s32  (*led_on)(struct e1000_hw *);
+	s32  (*led_off)(struct e1000_hw *);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	void (*shutdown_serdes)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+	s32  (*setup_led)(struct e1000_hw *);
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
+	void (*mta_set)(struct e1000_hw *, u32);
+	void (*config_collision_dist)(struct e1000_hw *);
+	void (*rar_set)(struct e1000_hw *, u8*, u32);
+	s32  (*read_mac_addr)(struct e1000_hw *);
+	s32  (*validate_mdi_setting)(struct e1000_hw *);
+	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
+	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
+                      struct e1000_host_mng_command_header*);
+	s32  (*mng_enable_host_if)(struct e1000_hw *);
+	s32  (*wait_autoneg)(struct e1000_hw *);
+};
+
+struct e1000_phy_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*check_polarity)(struct e1000_hw *);
+	s32  (*check_reset_block)(struct e1000_hw *);
+	s32  (*commit)(struct e1000_hw *);
+#if 0
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+#endif
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+#if 0
+	s32  (*get_cable_length)(struct e1000_hw *);
+#endif
+	s32  (*get_info)(struct e1000_hw *);
+	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
+	s32  (*read_reg_locked)(struct e1000_hw *, u32, u16 *);
+	void (*release)(struct e1000_hw *);
+	s32  (*reset)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_reg)(struct e1000_hw *, u32, u16);
+	s32  (*write_reg_locked)(struct e1000_hw *, u32, u16);
+	void (*power_up)(struct e1000_hw *);
+	void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release)(struct e1000_hw *);
+	void (*reload)(struct e1000_hw *);
+	s32  (*update)(struct e1000_hw *);
+	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+	s32  (*validate)(struct e1000_hw *);
+	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 mc_filter_type;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+	u16 uta_reg_count;
+
+	/* Maximum size of the MTA register table in all supported adapters */
+	#define MAX_MTA_REG 128
+	u32 mta_shadow[MAX_MTA_REG];
+	u16 rar_entry_count;
+
+	u8  forced_speed_duplex;
+
+	bool adaptive_ifs;
+	bool arc_subsystem_valid;
+	bool asf_firmware_present;
+	bool autoneg;
+	bool autoneg_failed;
+	bool get_link_status;
+	bool in_ifs_mode;
+	enum e1000_serdes_link_state serdes_link_state;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+	enum e1000_phy_type type;
+
+	enum e1000_1000t_rx_status local_rx;
+	enum e1000_1000t_rx_status remote_rx;
+	enum e1000_ms_type ms_type;
+	enum e1000_ms_type original_ms_type;
+	enum e1000_rev_polarity cable_polarity;
+	enum e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	enum e1000_media_type media_type;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool reset_disable;
+	bool speed_downgraded;
+	bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+	enum e1000_nvm_type type;
+	enum e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_type type;
+	enum e1000_bus_speed speed;
+	enum e1000_bus_width width;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+	u32 high_water;          /* Flow control high-water mark */
+	u32 low_water;           /* Flow control low-water mark */
+	u16 pause_time;          /* Flow control pause timer */
+	bool send_xon;           /* Flow control send XON */
+	bool strict_ieee;        /* Strict IEEE mode */
+	enum e1000_fc_mode current_mode; /* FC mode in effect */
+	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+struct e1000_mbx_operations {
+	s32 (*init_params)(struct e1000_hw *hw);
+	s32 (*read)(struct e1000_hw *, u32 *, u16,  u16);
+	s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
+	s32 (*read_posted)(struct e1000_hw *, u32 *, u16,  u16);
+	s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
+	s32 (*check_for_msg)(struct e1000_hw *, u16);
+	s32 (*check_for_ack)(struct e1000_hw *, u16);
+	s32 (*check_for_rst)(struct e1000_hw *, u16);
+};
+
+struct e1000_mbx_stats {
+	u32 msgs_tx;
+	u32 msgs_rx;
+
+	u32 acks;
+	u32 reqs;
+	u32 rsts;
+};
+
+struct e1000_mbx_info {
+	struct e1000_mbx_operations ops;
+	struct e1000_mbx_stats stats;
+	u32 timeout;
+	u32 usec_delay;
+	u16 size;
+};
+
+struct e1000_dev_spec_82575 {
+	bool sgmii_active;
+	bool global_device_reset;
+};
+
+struct e1000_dev_spec_vf {
+	u32	vf_number;
+	u32	v2p_mailbox;
+};
+
+
+struct e1000_hw {
+	void *back;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_mbx_info mbx;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	union {
+		struct e1000_dev_spec_82575	_82575;
+		struct e1000_dev_spec_vf	vf;
+	} dev_spec;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+#include "igb_82575.h"
+
+/* These functions must be implemented by drivers */
+s32  igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+s32  igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+
+#endif /* _IGB_HW_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.c
new file mode 100644
index 0000000..237c6c7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.c
@@ -0,0 +1,1991 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+static s32 igb_set_default_fc_generic(struct e1000_hw *hw);
+static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw);
+static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw);
+static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+
+/**
+ *  igb_init_mac_ops_generic - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void igb_init_mac_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	DEBUGFUNC("igb_init_mac_ops_generic");
+
+	/* General Setup */
+	mac->ops.set_lan_id = igb_set_lan_id_multi_port_pcie;
+	mac->ops.read_mac_addr = igb_read_mac_addr_generic;
+	mac->ops.config_collision_dist = igb_config_collision_dist_generic;
+	/* LINK */
+	mac->ops.wait_autoneg = igb_wait_autoneg_generic;
+	/* Management */
+#if 0
+	mac->ops.mng_host_if_write = igb_mng_host_if_write_generic;
+	mac->ops.mng_write_cmd_header = igb_mng_write_cmd_header_generic;
+	mac->ops.mng_enable_host_if = igb_mng_enable_host_if_generic;
+#endif
+	/* VLAN, MC, etc. */
+	mac->ops.rar_set = igb_rar_set_generic;
+	mac->ops.validate_mdi_setting = igb_validate_mdi_setting_generic;
+}
+
+/**
+ *  igb_get_bus_info_pcie_generic - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 igb_get_bus_info_pcie_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_bus_info *bus = &hw->bus;
+
+	s32 ret_val;
+	u16 pcie_link_status;
+
+	DEBUGFUNC("igb_get_bus_info_pcie_generic");
+
+	bus->type = e1000_bus_type_pci_express;
+	bus->speed = e1000_bus_speed_2500;
+
+	ret_val = igb_read_pcie_cap_reg(hw,
+	                                  PCIE_LINK_STATUS,
+	                                  &pcie_link_status);
+	if (ret_val)
+		bus->width = e1000_bus_width_unknown;
+	else
+		bus->width = (enum e1000_bus_width)((pcie_link_status &
+		                                PCIE_LINK_WIDTH_MASK) >>
+		                               PCIE_LINK_WIDTH_SHIFT);
+
+	mac->ops.set_lan_id(hw);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u32 reg;
+
+	/*
+	 * The status register reports the correct function number
+	 * for the device regardless of function swap state.
+	 */
+	reg = E1000_READ_REG(hw, E1000_STATUS);
+	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/**
+ *  igb_set_lan_id_single_port - Set LAN id for a single port device
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the LAN function id to zero for a single port device.
+ **/
+void igb_set_lan_id_single_port(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+
+	bus->func = 0;
+}
+
+/**
+ *  igb_clear_vfta_generic - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void igb_clear_vfta_generic(struct e1000_hw *hw)
+{
+	u32 offset;
+
+	DEBUGFUNC("igb_clear_vfta_generic");
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+                E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  igb_write_vfta_generic - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	DEBUGFUNC("igb_write_vfta_generic");
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  igb_init_rx_addrs_generic - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+	u8 mac_addr[ETH_ADDR_LEN] = {0};
+
+	DEBUGFUNC("igb_init_rx_addrs_generic");
+
+	/* Setup the receive address */
+	DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++)
+		hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ *  igb_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address. If an
+ *  alternate MAC address is found it is programmed into RAR0, replacing
+ *  the permanent address that was installed into RAR0 by the Si on reset.
+ *  This function will return SUCCESS unless it encounters an error while
+ *  reading the EEPROM.
+ **/
+s32 igb_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 i;
+	s32 ret_val = E1000_SUCCESS;
+	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+	u8 alt_mac_addr[ETH_ADDR_LEN];
+
+	DEBUGFUNC("igb_check_alt_mac_addr_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+	                         &nvm_alt_mac_addr_offset);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (nvm_alt_mac_addr_offset == 0xFFFF) {
+		/* There is no Alternate MAC Address */
+		goto out;
+	}
+
+	if (hw->bus.func == E1000_FUNC_1)
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = nvm_alt_mac_addr_offset + (i >> 1);
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+
+		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+	}
+
+	/* if multicast bit is set, the alternate address will not be used */
+	if (alt_mac_addr[0] & 0x01) {
+		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
+		goto out;
+	}
+
+	/*
+	 * We have a valid alternate MAC address, and we want to treat it the
+	 * same as the normal permanent MAC address stored by the HW into the
+	 * RAR. Do this by mapping this address into RAR0.
+	 */
+	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_rar_set_generic - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	DEBUGFUNC("igb_rar_set_generic");
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+	           ((u32) addr[1] << 8) |
+	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	/* If MAC address zero, no need to set the AV bit */
+	if (rar_low || rar_high)
+		rar_high |= E1000_RAH_AV;
+
+	/*
+	 * Some bridges will combine consecutive 32-bit writes into
+	 * a single burst write, which will malfunction on some parts.
+	 * The flushes avoid this.
+	 */
+	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+	E1000_WRITE_FLUSH(hw);
+	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  igb_mta_set_generic - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	DEBUGFUNC("igb_mta_set_generic");
+	/*
+	 * The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  igb_update_mc_addr_list_generic - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates entire Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igb_update_mc_addr_list_generic(struct e1000_hw *hw,
+                                       u8 *mc_addr_list, u32 mc_addr_count)
+{
+	u32 hash_value, hash_bit, hash_reg;
+	int i;
+
+	DEBUGFUNC("igb_update_mc_addr_list_generic");
+
+	/* clear mta_shadow */
+	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+	/* update mta_shadow from mc_addr_list */
+	for (i = 0; (u32) i < mc_addr_count; i++) {
+		hash_value = igb_hash_mc_addr_generic(hw, mc_addr_list);
+
+		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+		hash_bit = hash_value & 0x1F;
+
+		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+		mc_addr_list += (ETH_ADDR_LEN);
+	}
+
+	/* replace the entire MTA table */
+	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  igb_hash_mc_addr_generic - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  igb_mta_set_generic()
+ **/
+u32 igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	DEBUGFUNC("igb_hash_mc_addr_generic");
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/*
+	 * The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 *
+	 * For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB                 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+	default:
+	case 0:
+		break;
+	case 1:
+		bit_shift += 1;
+		break;
+	case 2:
+		bit_shift += 2;
+		break;
+	case 3:
+		bit_shift += 4;
+		break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+	                          (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  igb_clear_hw_cntrs_base_generic - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igb_clear_hw_cntrs_base_generic");
+
+	E1000_READ_REG(hw, E1000_CRCERRS);
+	E1000_READ_REG(hw, E1000_SYMERRS);
+	E1000_READ_REG(hw, E1000_MPC);
+	E1000_READ_REG(hw, E1000_SCC);
+	E1000_READ_REG(hw, E1000_ECOL);
+	E1000_READ_REG(hw, E1000_MCC);
+	E1000_READ_REG(hw, E1000_LATECOL);
+	E1000_READ_REG(hw, E1000_COLC);
+	E1000_READ_REG(hw, E1000_DC);
+	E1000_READ_REG(hw, E1000_SEC);
+	E1000_READ_REG(hw, E1000_RLEC);
+	E1000_READ_REG(hw, E1000_XONRXC);
+	E1000_READ_REG(hw, E1000_XONTXC);
+	E1000_READ_REG(hw, E1000_XOFFRXC);
+	E1000_READ_REG(hw, E1000_XOFFTXC);
+	E1000_READ_REG(hw, E1000_FCRUC);
+	E1000_READ_REG(hw, E1000_GPRC);
+	E1000_READ_REG(hw, E1000_BPRC);
+	E1000_READ_REG(hw, E1000_MPRC);
+	E1000_READ_REG(hw, E1000_GPTC);
+	E1000_READ_REG(hw, E1000_GORCL);
+	E1000_READ_REG(hw, E1000_GORCH);
+	E1000_READ_REG(hw, E1000_GOTCL);
+	E1000_READ_REG(hw, E1000_GOTCH);
+	E1000_READ_REG(hw, E1000_RNBC);
+	E1000_READ_REG(hw, E1000_RUC);
+	E1000_READ_REG(hw, E1000_RFC);
+	E1000_READ_REG(hw, E1000_ROC);
+	E1000_READ_REG(hw, E1000_RJC);
+	E1000_READ_REG(hw, E1000_TORL);
+	E1000_READ_REG(hw, E1000_TORH);
+	E1000_READ_REG(hw, E1000_TOTL);
+	E1000_READ_REG(hw, E1000_TOTH);
+	E1000_READ_REG(hw, E1000_TPR);
+	E1000_READ_REG(hw, E1000_TPT);
+	E1000_READ_REG(hw, E1000_MPTC);
+	E1000_READ_REG(hw, E1000_BPTC);
+}
+
+/**
+ *  igb_check_for_copper_link_generic - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 igb_check_for_copper_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("igb_check_for_copper_link");
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	igb_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	igb_config_collision_dist_generic(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = igb_config_fc_after_link_up_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error configuring flow control\n");
+        }
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_check_for_fiber_link_generic - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 igb_check_for_fiber_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_check_for_fiber_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = igb_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_check_for_serdes_link_generic - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 igb_check_for_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_check_for_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), and our link partner is not trying to
+	 * auto-negotiate with us (we are receiving idles or data),
+	 * we need to force link up. We also need to give auto-negotiation
+	 * time to complete.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = igb_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
+		/*
+		 * If we force link for non-auto-negotiation switch, check
+		 * link status based on MAC synchronization for internal
+		 * serdes media type.
+		 */
+		/* SYNCH bit and IV bit are sticky. */
+		usec_delay(10);
+		rxcw = E1000_READ_REG(hw, E1000_RXCW);
+		if (rxcw & E1000_RXCW_SYNCH) {
+			if (!(rxcw & E1000_RXCW_IV)) {
+				mac->serdes_has_link = true;
+				DEBUGOUT("SERDES: Link up - forced.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			DEBUGOUT("SERDES: Link down - force failed.\n");
+		}
+	}
+
+	if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		if (status & E1000_STATUS_LU) {
+			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
+			usec_delay(10);
+			rxcw = E1000_READ_REG(hw, E1000_RXCW);
+			if (rxcw & E1000_RXCW_SYNCH) {
+				if (!(rxcw & E1000_RXCW_IV)) {
+					mac->serdes_has_link = true;
+					DEBUGOUT("SERDES: Link up - autoneg "
+					   "completed sucessfully.\n");
+				} else {
+					mac->serdes_has_link = false;
+					DEBUGOUT("SERDES: Link down - invalid"
+					   "codewords detected in autoneg.\n");
+				}
+			} else {
+				mac->serdes_has_link = false;
+				DEBUGOUT("SERDES: Link down - no sync.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			DEBUGOUT("SERDES: Link down - autoneg failed\n");
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_setup_link_generic - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 igb_setup_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_setup_link_generic");
+
+	/*
+	 * In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (hw->phy.ops.check_reset_block)
+		if (hw->phy.ops.check_reset_block(hw))
+			goto out;
+
+	/*
+	 * If requested flow control is set to default, set flow control
+	 * based on the EEPROM flow control settings.
+	 */
+	if (hw->fc.requested_mode == e1000_fc_default) {
+		ret_val = igb_set_default_fc_generic(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = igb_set_fc_watermarks_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes
+ *  links.  Upon successful setup, poll for link.
+ **/
+s32 igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_setup_fiber_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	igb_config_collision_dist_generic(hw);
+
+	ret_val = igb_commit_fc_settings_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
+	 */
+	DEBUGOUT("Auto-negotiation enabled\n");
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(1);
+
+	/*
+	 * For these adapters, the SW definable pin 1 is set when the optics
+	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
+	 * indication.
+	 */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+	    (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = igb_poll_fiber_serdes_link_generic(hw);
+	} else {
+		DEBUGOUT("No signal detected\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_config_collision_dist_generic - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igb_config_collision_dist_generic(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	DEBUGFUNC("igb_config_collision_dist_generic");
+
+	tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  igb_poll_fiber_serdes_link_generic - Poll for link up
+ *  @hw: pointer to the HW structure
+ *
+ *  Polls for link up by reading the status register, if link fails to come
+ *  up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 i, status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_poll_fiber_serdes_link_generic");
+
+	/*
+	 * If we have a signal (the cable is plugged in, or assumed true for
+	 * serdes media) then poll for a "Link-Up" indication in the Device
+	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
+	 * seconds (Auto-negotiation should complete in less than 500
+	 * milliseconds even if the other end is doing it in SW).
+	 */
+	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+		msec_delay(10);
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		if (status & E1000_STATUS_LU)
+			break;
+	}
+	if (i == FIBER_LINK_UP_LIMIT) {
+		DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+		mac->autoneg_failed = 1;
+		/*
+		 * AutoNeg failed to achieve a link, so we'll call
+		 * mac->check_for_link. This routine will force the
+		 * link up if we detect a signal. This will allow us to
+		 * communicate with non-autonegotiating link partners.
+		 */
+		ret_val = hw->mac.ops.check_for_link(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while checking for link\n");
+			goto out;
+		}
+		mac->autoneg_failed = 0;
+	} else {
+		mac->autoneg_failed = 0;
+		DEBUGOUT("Valid Link Found\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_commit_fc_settings_generic - Configure flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Write the flow control settings to the Transmit Config Word Register (TXCW)
+ *  base on the flow control settings in e1000_mac_info.
+ **/
+static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txcw;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_commit_fc_settings_generic");
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Transmit Config Word Register (TXCW) and re-start auto-
+	 * negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames,
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we
+	 *          do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/* Flow control completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is disabled
+		 * by a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of Rx Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric RX
+		 * PAUSE.  Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+	mac->txcw = txcw;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_set_fc_watermarks_generic - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  transmission as well.
+ **/
+s32 igb_set_fc_watermarks_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 fcrtl = 0, fcrth = 0;
+
+	DEBUGFUNC("igb_set_fc_watermarks_generic");
+
+	/*
+	 * Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.current_mode & e1000_fc_tx_pause) {
+		/*
+		 * We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
+	E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  igb_set_default_fc_generic - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 igb_set_default_fc_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	DEBUGFUNC("igb_set_default_fc_generic");
+
+	/*
+	 * Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		hw->fc.requested_mode = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		hw->fc.requested_mode = e1000_fc_tx_pause;
+	else
+		hw->fc.requested_mode = e1000_fc_full;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_force_mac_fc_generic - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 igb_force_mac_fc_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_force_mac_fc_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/*
+	 * Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc.current_mode" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_config_fc_after_link_up_generic - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 igb_config_fc_after_link_up_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	DEBUGFUNC("igb_config_fc_after_link_up_generic");
+
+	/*
+	 * Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes)
+			ret_val = igb_force_mac_fc_generic(hw);
+	} else {
+		if (hw->phy.media_type == e1000_media_type_copper)
+			ret_val = igb_force_mac_fc_generic(hw);
+	}
+
+	if (ret_val) {
+		DEBUGOUT("Error forcing flow control settings\n");
+		goto out;
+	}
+
+	/*
+	 * Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+		/*
+		 * Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			DEBUGOUT("Copper PHY and Auto Neg "
+			         "has not completed.\n");
+			goto out;
+		}
+
+		/*
+		 * The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+		                             &mii_nway_adv_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+		                             &mii_nway_lp_ability_reg);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/*
+			 * Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
+				DEBUGOUT("Flow Control = FULL.\r\n");
+			} else {
+				hw->fc.current_mode = e1000_fc_rx_pause;
+				DEBUGOUT("Flow Control = "
+				         "RX PAUSE frames only.\r\n");
+			}
+		}
+		/*
+		 * For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_tx_pause;
+			DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/*
+		 * For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_rx_pause;
+			DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+		} else {
+			/*
+			 * Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.current_mode = e1000_fc_none;
+			DEBUGOUT("Flow Control = NONE.\r\n");
+		}
+
+		/*
+		 * Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			DEBUGOUT("Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			hw->fc.current_mode = e1000_fc_none;
+
+		/*
+		 * Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = igb_force_mac_fc_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error forcing flow control settings\n");
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	u32 status;
+
+	DEBUGFUNC("igb_get_speed_and_duplex_copper_generic");
+
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		DEBUGOUT("1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		DEBUGOUT("100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		DEBUGOUT("10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Sets the speed and duplex to gigabit full duplex (the only possible option)
+ *  for fiber/serdes links.
+ **/
+s32 igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused,
+                                                  u16 *speed, u16 *duplex)
+{
+	DEBUGFUNC("igb_get_speed_and_duplex_fiber_serdes_generic");
+
+	*speed = SPEED_1000;
+	*duplex = FULL_DUPLEX;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_get_hw_semaphore_generic - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 igb_get_hw_semaphore_generic(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("igb_get_hw_semaphore_generic");
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		igb_put_hw_semaphore_generic(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_put_hw_semaphore_generic - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void igb_put_hw_semaphore_generic(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	DEBUGFUNC("igb_put_hw_semaphore_generic");
+
+	swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ *  igb_get_auto_rd_done_generic - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 igb_get_auto_rd_done_generic(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_get_auto_rd_done_generic");
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msec_delay(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_valid_led_default_generic - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("igb_valid_led_default_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_id_led_init_generic -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 igb_id_led_init_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	DEBUGFUNC("igb_id_led_init_generic");
+
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  igb_setup_led_generic - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+s32 igb_setup_led_generic(struct e1000_hw *hw)
+{
+	u32 ledctl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_setup_led_generic");
+
+	if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+		hw->mac.ledctl_default = ledctl;
+		/* Turn off LED0 */
+		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+		            E1000_LEDCTL_LED0_BLINK |
+		            E1000_LEDCTL_LED0_MODE_MASK);
+		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+		           E1000_LEDCTL_LED0_MODE_SHIFT);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_cleanup_led_generic - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 igb_cleanup_led_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_cleanup_led_generic");
+
+	if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_blink_led_generic - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the LEDs which are set to be on.
+ **/
+s32 igb_blink_led_generic(struct e1000_hw *hw)
+{
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	DEBUGFUNC("igb_blink_led_generic");
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/*
+		 * set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2
+		 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+				                 (i * 8));
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_led_on_generic - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+s32 igb_led_on_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	DEBUGFUNC("igb_led_on_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_led_off_generic - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 igb_led_off_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	DEBUGFUNC("igb_led_off_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+}
+#endif
+
+/**
+ *  igb_set_pcie_no_snoop_generic - Set PCI-express capabilities
+ *  @hw: pointer to the HW structure
+ *  @no_snoop: bitmap of snoop events
+ *
+ *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
+{
+	u32 gcr;
+
+	DEBUGFUNC("igb_set_pcie_no_snoop_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	if (no_snoop) {
+		gcr = E1000_READ_REG(hw, E1000_GCR);
+		gcr &= ~(PCIE_NO_SNOOP_ALL);
+		gcr |= no_snoop;
+		E1000_WRITE_REG(hw, E1000_GCR, gcr);
+	}
+out:
+	return;
+}
+
+/**
+ *  igb_disable_pcie_master_generic - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 igb_disable_pcie_master_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_disable_pcie_master_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	while (timeout) {
+		if (!(E1000_READ_REG(hw, E1000_STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		usec_delay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		DEBUGOUT("Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_reset_adaptive_generic - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void igb_reset_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("igb_reset_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	mac->current_ifs_val = 0;
+	mac->ifs_min_val = IFS_MIN;
+	mac->ifs_max_val = IFS_MAX;
+	mac->ifs_step_size = IFS_STEP;
+	mac->ifs_ratio = IFS_RATIO;
+
+	mac->in_ifs_mode = false;
+	E1000_WRITE_REG(hw, E1000_AIT, 0);
+out:
+	return;
+}
+
+/**
+ *  igb_update_adaptive_generic - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void igb_update_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("igb_update_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = true;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = false;
+			E1000_WRITE_REG(hw, E1000_AIT, 0);
+		}
+	}
+out:
+	return;
+}
+
+/**
+ *  igb_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_validate_mdi_setting_generic");
+
+	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+		DEBUGOUT("Invalid MDI setting detected\n");
+		hw->phy.mdix = 1;
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register
+ *  @hw: pointer to the HW structure
+ *  @reg: 32bit register offset such as E1000_SCTL
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes an address/data control type register.  There are several of these
+ *  and they all have the format address << 8 | data and bit 31 is polled for
+ *  completion.
+ **/
+s32 igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
+                                      u32 offset, u8 data)
+{
+	u32 i, regvalue = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_write_8bit_ctrl_reg_generic");
+
+	/* Set up the address and data */
+	regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+	E1000_WRITE_REG(hw, reg, regvalue);
+
+	/* Poll the ready bit to see if the MDI read completed */
+	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+		usec_delay(5);
+		regvalue = E1000_READ_REG(hw, reg);
+		if (regvalue & E1000_GEN_CTL_READY)
+			break;
+	}
+	if (!(regvalue & E1000_GEN_CTL_READY)) {
+		DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.h
new file mode 100644
index 0000000..7639e24
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_mac.h
@@ -0,0 +1,82 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_MAC_H_
+#define _IGB_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void igb_init_mac_ops_generic(struct e1000_hw *hw);
+s32  igb_blink_led_generic(struct e1000_hw *hw);
+s32  igb_check_for_copper_link_generic(struct e1000_hw *hw);
+s32  igb_check_for_fiber_link_generic(struct e1000_hw *hw);
+s32  igb_check_for_serdes_link_generic(struct e1000_hw *hw);
+s32  igb_cleanup_led_generic(struct e1000_hw *hw);
+s32  igb_config_fc_after_link_up_generic(struct e1000_hw *hw);
+s32  igb_disable_pcie_master_generic(struct e1000_hw *hw);
+s32  igb_force_mac_fc_generic(struct e1000_hw *hw);
+s32  igb_get_auto_rd_done_generic(struct e1000_hw *hw);
+s32  igb_get_bus_info_pcie_generic(struct e1000_hw *hw);
+void igb_set_lan_id_single_port(struct e1000_hw *hw);
+s32  igb_get_hw_semaphore_generic(struct e1000_hw *hw);
+s32  igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+s32  igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+                                                     u16 *speed, u16 *duplex);
+s32  igb_id_led_init_generic(struct e1000_hw *hw);
+s32  igb_led_on_generic(struct e1000_hw *hw);
+s32  igb_led_off_generic(struct e1000_hw *hw);
+void igb_update_mc_addr_list_generic(struct e1000_hw *hw,
+	                               u8 *mc_addr_list, u32 mc_addr_count);
+s32  igb_set_fc_watermarks_generic(struct e1000_hw *hw);
+s32  igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
+s32  igb_setup_led_generic(struct e1000_hw *hw);
+s32  igb_setup_link_generic(struct e1000_hw *hw);
+s32  igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
+                                       u32 offset, u8 data);
+
+u32  igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
+
+void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
+void igb_clear_vfta_generic(struct e1000_hw *hw);
+void igb_config_collision_dist_generic(struct e1000_hw *hw);
+void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
+void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
+void igb_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void igb_put_hw_semaphore_generic(struct e1000_hw *hw);
+void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  igb_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void igb_reset_adaptive_generic(struct e1000_hw *hw);
+void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
+void igb_update_adaptive_generic(struct e1000_hw *hw);
+void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+#endif /* _IGB_MAC_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_main.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_main.c
new file mode 100644
index 0000000..9295c2c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_main.c
@@ -0,0 +1,1010 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  Portions Copyright(c) 2010 Marty Connor <mdc at etherboot.org>
+  Portions Copyright(c) 2010 Entity Cyber, Inc.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+/* Low-level support routines */
+
+/**
+ * igb_read_pcie_cap_reg - retrieve PCIe capability register contents
+ * @hw: address of board private structure
+ * @reg: PCIe capability register requested
+ * @value: where to store requested value
+ **/
+int32_t igb_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+    struct igb_adapter *adapter = hw->back;
+    uint16_t cap_offset;
+
+#define	 PCI_CAP_ID_EXP	       0x10    /* PCI Express */
+    cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+    if (!cap_offset)
+	return -E1000_ERR_CONFIG;
+
+    pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+    return E1000_SUCCESS;
+}
+
+/**
+ * igb_write_pcie_cap_reg - write value to PCIe capability register
+ * @hw: address of board private structure
+ * @reg: PCIe capability register to write to
+ * @value: value to store in given register
+ **/
+int32_t igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+	struct igb_adapter *adapter = hw->back;
+	u16 cap_offset;
+
+	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+	if (!cap_offset)
+		return -E1000_ERR_CONFIG;
+
+	pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ * igb_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static void igb_irq_disable(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	E1000_WRITE_REG(hw, E1000_IAM, 0);
+	E1000_WRITE_REG(hw, E1000_IMC, ~0);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * igb_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static void igb_irq_enable(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
+	E1000_WRITE_REG(hw, E1000_IAM, IMS_ENABLE_MASK);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ * igb_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ *
+ **/
+void igb_get_hw_control(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+
+	/* Let firmware know the driver has taken over */
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+			ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+}
+
+/**
+ * igb_reset - put adapter in known initial state
+ * @adapter: board private structure
+ **/
+void igb_reset(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_fc_info *fc = &hw->fc;
+	u32 pba = 0;
+	u16 hwm;
+
+	/* Repartition Pba for greater than 9k mtu
+	 * To take effect CTRL.RST is required.
+	 */
+	switch (mac->type) {
+	case e1000_82576:
+		pba = E1000_READ_REG(hw, E1000_RXPBS);
+		pba &= E1000_RXPBS_SIZE_MASK_82576;
+		break;
+	case e1000_82575:
+	default:
+		pba = E1000_PBA_34K;
+		break;
+	}
+
+	/* flow control settings */
+	/* The high water mark must be low enough to fit one full frame
+	 * (or the size used for early receive) above it in the Rx FIFO.
+	 * Set it to the lower of:
+	 * - 90% of the Rx FIFO size, or
+	 * - the full Rx FIFO size minus one full frame */
+#define min(a,b) (((a)<(b))?(a):(b))
+	hwm = min(((pba << 10) * 9 / 10),
+			((pba << 10) - 2 * adapter->max_frame_size));
+
+	if (mac->type < e1000_82576) {
+		fc->high_water = hwm & 0xFFF8;	/* 8-byte granularity */
+		fc->low_water = fc->high_water - 8;
+	} else {
+		fc->high_water = hwm & 0xFFF0;	/* 16-byte granularity */
+		fc->low_water = fc->high_water - 16;
+	}
+	fc->pause_time = 0xFFFF;
+	fc->send_xon = 1;
+	fc->current_mode = fc->requested_mode;
+
+	/* Allow time for pending master requests to run */
+	igb_reset_hw(hw);
+	E1000_WRITE_REG(hw, E1000_WUC, 0);
+
+	if (igb_init_hw(hw)) {
+		DBG ("Hardware Error\n");
+        }
+
+	igb_get_phy_info(hw);
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ **/
+int igb_sw_init(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct pci_device *pdev = adapter->pdev;
+
+	/* PCI config space info */
+
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+	adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN;
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	/* Initialize the hardware-specific values */
+	if (igb_setup_init_funcs(hw, TRUE)) {
+		DBG ("Hardware Initialization Failure\n");
+		return -EIO;
+	}
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	igb_irq_disable(adapter);
+
+	return 0;
+}
+
+/* TX support routines */
+
+/**
+ * igb_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int igb_setup_tx_resources ( struct igb_adapter *adapter )
+{
+	DBG ( "igb_setup_tx_resources\n" );
+
+	/* Allocate transmit descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata #23
+	   so we use malloc_dma() requesting a 128 byte block that is
+	   128 byte aligned. This should guarantee that the memory
+	   allocated will not cross a 64K boundary, because 128 is an
+	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
+	   allocations of 128 bytes on a 128 byte boundary will not
+	   cross 64K bytes.
+	 */
+
+	adapter->tx_base =
+		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
+
+	if ( ! adapter->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
+
+	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
+
+	return 0;
+}
+
+/**
+ * igb_process_tx_packets - process transmitted packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void igb_process_tx_packets ( struct net_device *netdev )
+{
+	struct igb_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t tx_status;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	/* Check status of transmitted packets
+	 */
+	DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
+	      adapter->tx_tail );
+
+	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
+
+		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
+					   ( i * sizeof ( *adapter->tx_base ) );
+
+		tx_status = tx_curr_desc->upper.data;
+
+		DBG ( "	 tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+		DBG ( "	 tx_status = %#08x\n", tx_status );
+
+		/* if the packet at tx_head is not owned by hardware it is for us */
+		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
+			break;
+
+		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
+		      adapter->tx_head, adapter->tx_tail, tx_status );
+
+		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
+				   E1000_TXD_STAT_TU ) ) {
+			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
+			DBG ( "Error transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		} else {
+			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
+			DBG ( "Success transmitting packet, tx_status: %#08x\n",
+			      tx_status );
+		}
+
+		/* Decrement count of used descriptors, clear this descriptor
+		 */
+		adapter->tx_fill_ctr--;
+		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
+	}
+}
+
+static void igb_free_tx_resources ( struct igb_adapter *adapter )
+{
+	DBG ( "igb_free_tx_resources\n" );
+
+	free_dma ( adapter->tx_base, adapter->tx_ring_size );
+}
+
+/**
+ * igb_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void igb_configure_tx ( struct igb_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tctl, txdctl;
+
+	DBG ( "igb_configure_tx\n" );
+
+	/* disable transmits while setting up the descriptors */
+	tctl = E1000_READ_REG ( hw, E1000_TCTL );
+	E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN );
+	E1000_WRITE_FLUSH(hw);
+	mdelay(10);
+
+	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
+	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
+
+	DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
+	DBG ( "E1000_TDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
+
+	adapter->tx_head = 0;
+	adapter->tx_tail = 0;
+	adapter->tx_fill_ctr = 0;
+
+	txdctl = E1000_READ_REG ( hw, E1000_TXDCTL(0) );
+	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+	E1000_WRITE_REG ( hw, E1000_TXDCTL(0), txdctl );
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+	/* enable Report Status bit */
+	adapter->txd_cmd |= E1000_TXD_CMD_RS;
+
+	/* Program the Transmit Control Register */
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	igb_config_collision_dist(hw);
+
+	/* Enable transmits */
+	tctl |= E1000_TCTL_EN;
+	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/* RX support routines */
+
+static void igb_free_rx_resources ( struct igb_adapter *adapter )
+{
+	int i;
+
+	DBG ( "igb_free_rx_resources\n" );
+
+	free_dma ( adapter->rx_base, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		free_iob ( adapter->rx_iobuf[i] );
+	}
+}
+
+/**
+ * igb_refill_rx_ring - allocate Rx io_buffers
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int igb_refill_rx_ring ( struct igb_adapter *adapter )
+{
+	int i, rx_curr;
+	int rc = 0;
+	struct e1000_rx_desc *rx_curr_desc;
+	struct e1000_hw *hw = &adapter->hw;
+	struct io_buffer *iob;
+
+	DBGP ("igb_refill_rx_ring\n");
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
+		rx_curr_desc = adapter->rx_base + rx_curr;
+
+		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
+			continue;
+
+		if ( adapter->rx_iobuf[rx_curr] != NULL )
+			continue;
+
+		DBG2 ( "Refilling rx desc %d\n", rx_curr );
+
+		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+		adapter->rx_iobuf[rx_curr] = iob;
+
+		if ( ! iob ) {
+			DBG ( "alloc_iob failed\n" );
+			rc = -ENOMEM;
+			break;
+		} else {
+			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
+
+			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
+		}
+	}
+	return rc;
+}
+
+/**
+ * igb_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v adapter	e1000 private structure
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ **/
+static int igb_setup_rx_resources ( struct igb_adapter *adapter )
+{
+	int i, rc = 0;
+
+	DBGP ( "igb_setup_rx_resources\n" );
+
+	/* Allocate receive descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata
+	 */
+
+	adapter->rx_base =
+		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
+
+	if ( ! adapter->rx_base ) {
+		return -ENOMEM;
+	}
+	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		/* let igb_refill_rx_ring() io_buffer allocations */
+		adapter->rx_iobuf[i] = NULL;
+	}
+
+	/* allocate io_buffers */
+	rc = igb_refill_rx_ring ( adapter );
+	if ( rc < 0 )
+		igb_free_rx_resources ( adapter );
+
+	return rc;
+}
+
+/**
+ * igb_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void igb_configure_rx ( struct igb_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl, rxdctl, rxcsum, mrqc;
+
+	DBGP ( "igb_configure_rx\n" );
+
+	/* disable receives while setting up the descriptors */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	E1000_WRITE_FLUSH(hw);
+	mdelay(10);
+
+	adapter->rx_curr = 0;
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+
+	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
+	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
+
+	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
+	E1000_WRITE_REG ( hw, E1000_RDT(0), 0 );
+
+	DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
+	DBG ( "E1000_RDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
+	DBG ( "E1000_RCTL:  %#08x\n",	  E1000_READ_REG ( hw, E1000_RCTL ) );
+
+	rxdctl = E1000_READ_REG ( hw, E1000_RXDCTL(0) );
+	rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+	rxdctl &= 0xFFF00000;
+	rxdctl |= IGB_RX_PTHRESH;
+	rxdctl |= IGB_RX_HTHRESH << 8;
+	rxdctl |= IGB_RX_WTHRESH << 16;
+	E1000_WRITE_REG ( hw, E1000_RXDCTL(0), rxdctl );
+	E1000_WRITE_FLUSH ( hw );
+
+	rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
+	rxcsum &= ~( E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE );
+	E1000_WRITE_REG ( hw, E1000_RXCSUM, 0 );
+
+	/* The initial value for MRQC disables multiple receive
+	 * queues, however this setting is not recommended.
+	 * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41
+	 *   Section 8.10.9 Multiple Queues Command Register - MRQC
+	 */
+	mrqc = E1000_MRQC_ENABLE_VMDQ;
+	E1000_WRITE_REG ( hw, E1000_MRQC, mrqc );
+
+	/* Turn off loopback modes */
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+
+	/* set maximum packet size */
+	rctl |=	 E1000_RCTL_SZ_2048;
+
+	/* Broadcast enable, multicast promisc, unicast promisc */
+	rctl |=	 E1000_RCTL_BAM | E1000_RCTL_MPE | E1000_RCTL_UPE;
+
+	/* Store bad packets */
+	rctl |=	 E1000_RCTL_SBP;
+
+	/* enable LPE to prevent packets larger than max_frame_size */
+	rctl |= E1000_RCTL_LPE;
+
+	/* enable stripping of CRC. */
+	rctl |= E1000_RCTL_SECRC;
+
+	/* enable receive control register */
+	rctl |= E1000_RCTL_EN;
+	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+	E1000_WRITE_FLUSH(hw);
+
+	/* On the 82576, RDT([0]) must not be "bumped" before
+	 * the enable bit of RXDCTL([0]) is set.
+	 * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41
+	 *   Section 4.5.9 receive Initialization
+	 *
+	 * By observation I have found this to occur when the enable bit of
+	 * RCTL is set. The datasheet recommends polling for this bit,
+	 * however as I see no evidence of this in the Linux igb driver
+	 * I have omitted that step.
+	 * - Simon Horman, May 2009
+	 */
+	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
+
+	DBG ( "RDBAH: %#08x\n",	 E1000_READ_REG ( hw, E1000_RDBAH(0) ) );
+	DBG ( "RDBAL: %#08x\n",	 E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
+	DBG ( "RDLEN: %d\n",	 E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
+	DBG ( "RCTL:  %#08x\n",	 E1000_READ_REG ( hw, E1000_RCTL ) );
+}
+
+/**
+ * igb_process_rx_packets - process received packets
+ *
+ * @v netdev	network interface device structure
+ **/
+static void igb_process_rx_packets ( struct net_device *netdev )
+{
+	struct igb_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t rx_status;
+	uint32_t rx_len;
+	uint32_t rx_err;
+	struct e1000_rx_desc *rx_curr_desc;
+
+	DBGP ( "igb_process_rx_packets\n" );
+
+	/* Process received packets
+	 */
+	while ( 1 ) {
+
+		i = adapter->rx_curr;
+
+		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+				  ( i * sizeof ( *adapter->rx_base ) );
+		rx_status = rx_curr_desc->status;
+
+		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
+
+		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+			break;
+
+		if ( adapter->rx_iobuf[i] == NULL )
+			break;
+
+		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
+
+		rx_len = rx_curr_desc->length;
+
+		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
+		      i, rx_status, rx_len );
+
+		rx_err = rx_curr_desc->errors;
+
+		iob_put ( adapter->rx_iobuf[i], rx_len );
+
+		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
+
+			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
+			DBG ( "igb_process_rx_packets: Corrupted packet received!"
+			      " rx_err: %#08x\n", rx_err );
+		} else	{
+			/* Add this packet to the receive queue. */
+			netdev_rx ( netdev, adapter->rx_iobuf[i] );
+		}
+		adapter->rx_iobuf[i] = NULL;
+
+		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
+	}
+}
+
+/** Functions that implement the iPXE driver API **/
+
+/**
+ * igb_close - Disables a network interface
+ *
+ * @v netdev	network interface device structure
+ *
+ **/
+static void igb_close ( struct net_device *netdev )
+{
+	struct igb_adapter *adapter = netdev_priv ( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t rctl;
+
+	DBGP ( "igb_close\n" );
+
+	/* Disable and acknowledge interrupts */
+	igb_irq_disable ( adapter );
+	E1000_READ_REG ( hw, E1000_ICR );
+
+	/* disable receives */
+	rctl = E1000_READ_REG ( hw, E1000_RCTL );
+	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
+	E1000_WRITE_FLUSH(hw);
+
+	igb_reset ( adapter );
+
+	igb_free_tx_resources ( adapter );
+	igb_free_rx_resources ( adapter );
+}
+
+/**
+ * igb_transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc	 Returns 0 on success, negative on failure
+ */
+static int igb_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct igb_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t tx_curr = adapter->tx_tail;
+	struct e1000_tx_desc *tx_curr_desc;
+
+	DBGP ("igb_transmit\n");
+
+	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Save pointer to iobuf we have been given to transmit,
+	   netdev_tx_complete() will need it later
+	 */
+	adapter->tx_iobuf[tx_curr] = iobuf;
+
+	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
+		       ( tx_curr * sizeof ( *adapter->tx_base ) );
+
+	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
+	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+
+	/* Add the packet to TX ring
+	 */
+	tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data );
+	tx_curr_desc->upper.data = 0;
+	tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf );
+
+	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+
+	/* Point to next free descriptor */
+	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
+	adapter->tx_fill_ctr++;
+
+	/* Write new tail to NIC, making packet available for transmit
+	 */
+	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
+	E1000_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+/**
+ * igb_poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void igb_poll ( struct net_device *netdev )
+{
+	struct igb_adapter *adapter = netdev_priv( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+
+	uint32_t icr;
+
+	DBGP ( "igb_poll\n" );
+
+	/* Acknowledge interrupts */
+	icr = E1000_READ_REG ( hw, E1000_ICR );
+	if ( ! icr )
+		return;
+
+	DBG ( "igb_poll: intr_status = %#08x\n", icr );
+
+	igb_process_tx_packets ( netdev );
+
+	igb_process_rx_packets ( netdev );
+
+	igb_refill_rx_ring(adapter);
+}
+
+/**
+ * igb_irq - enable or Disable interrupts
+ *
+ * @v adapter	e1000 adapter
+ * @v action	requested interrupt action
+ **/
+static void igb_irq ( struct net_device *netdev, int enable )
+{
+	struct igb_adapter *adapter = netdev_priv ( netdev );
+
+	DBGP ( "igb_irq\n" );
+
+	if ( enable ) {
+		igb_irq_enable ( adapter );
+	} else {
+		igb_irq_disable ( adapter );
+	}
+}
+
+static struct net_device_operations igb_operations;
+
+/**
+ * igb_probe - Initial configuration of NIC
+ *
+ * @v pci	PCI device
+ * @v id	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+int igb_probe ( struct pci_device *pdev )
+{
+	int i, err;
+	struct net_device *netdev;
+	struct igb_adapter *adapter;
+	unsigned long mmio_start, mmio_len;
+	struct e1000_hw *hw;
+
+	DBGP ( "igb_probe\n" );
+
+	err = -ENOMEM;
+
+	/* Allocate net device ( also allocates memory for netdev->priv
+	   and makes netdev-priv point to it ) */
+	netdev = alloc_etherdev ( sizeof ( struct igb_adapter ) );
+	if ( ! netdev ) {
+		DBG ( "err_alloc_etherdev\n" );
+		goto err_alloc_etherdev;
+	}
+
+	/* Associate igb-specific network operations operations with
+	 * generic network device layer */
+	netdev_init ( netdev, &igb_operations );
+
+	/* Associate this network device with given PCI device */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Initialize driver private storage */
+	adapter = netdev_priv ( netdev );
+	memset ( adapter, 0, ( sizeof ( *adapter ) ) );
+
+	adapter->pdev	    = pdev;
+
+	adapter->ioaddr	    = pdev->ioaddr;
+	adapter->hw.io_base = pdev->ioaddr;
+
+	hw		    = &adapter->hw;
+	hw->vendor_id	    = pdev->vendor;
+	hw->device_id	    = pdev->device;
+
+	adapter->irqno	    = pdev->irq;
+	adapter->netdev	    = netdev;
+	adapter->hw.back    = adapter;
+
+	adapter->min_frame_size	   = ETH_ZLEN + ETH_FCS_LEN;
+	adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
+	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pdev );
+
+	err = -EIO;
+
+	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
+	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
+
+	DBG ( "mmio_start: %#08lx\n", mmio_start );
+	DBG ( "mmio_len: %#08lx\n", mmio_len );
+
+	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
+	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
+
+	if ( ! adapter->hw.hw_addr ) {
+		DBG ( "err_ioremap\n" );
+		goto err_ioremap;
+	}
+
+	/* setup adapter struct */
+	err = igb_sw_init ( adapter );
+	if (err) {
+		DBG ( "err_sw_init\n" );
+		goto err_sw_init;
+	}
+
+	igb_get_bus_info(hw);
+
+	/* Copper options */
+	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
+		adapter->hw.phy.mdix = AUTO_ALL_MODES;
+		adapter->hw.phy.disable_polarity_correction = 0;
+		adapter->hw.phy.ms_type = e1000_ms_hw_default;
+	}
+
+	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
+
+	/* Force auto-negotiation */
+	adapter->hw.mac.autoneg = 1;
+	adapter->fc_autoneg = 1;
+	adapter->hw.phy.autoneg_wait_to_complete = true;
+	adapter->hw.mac.adaptive_ifs = true;
+	adapter->hw.fc.requested_mode = e1000_fc_default;
+	adapter->hw.fc.current_mode = e1000_fc_default;
+
+	igb_validate_mdi_setting(hw);
+
+	/*
+	 * before reading the NVM, reset the controller to
+	 * put the device in a known good starting state
+	 */
+	igb_reset_hw(hw);
+
+	/*
+	 * systems with ASPM and others may see the checksum fail on the first
+	 * attempt. Let's give it a few tries
+	 */
+	for (i = 0;; i++) {
+		if (igb_validate_nvm_checksum(&adapter->hw) >= 0)
+			break;
+		if (i == 2) {
+			err = -EIO;
+			DBG ( "The NVM Checksum Is Not Valid\n" );
+			DBG ( "err_eeprom\n" );
+			goto err_eeprom;
+		}
+	}
+
+	/* copy the MAC address out of the EEPROM */
+	if ( igb_read_mac_addr ( &adapter->hw ) ) {
+		DBG ( "EEPROM Read Error\n" );
+	}
+
+	memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
+
+	/* reset the hardware with the new settings */
+	igb_reset ( adapter );
+
+	/* let the f/w know that the h/w is now under the control of the
+	 * driver. */
+	igb_get_hw_control(adapter);
+
+	if ( ( err = register_netdev ( netdev ) ) != 0) {
+		DBG ( "err_register\n" );
+		goto err_register;
+	}
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	for (i = 0; i < 6; i++) {
+		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
+        }
+
+	DBG ( "igb_probe succeeded!\n" );
+
+	/* No errors, return success */
+	return 0;
+
+/* Error return paths */
+err_register:
+err_eeprom:
+err_sw_init:
+	iounmap ( adapter->hw.hw_addr );
+err_ioremap:
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return err;
+}
+
+/**
+ * igb_remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+void igb_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct igb_adapter *adapter = netdev_priv ( netdev );
+
+	DBGP ( "igb_remove\n" );
+
+	if ( adapter->hw.flash_address )
+		iounmap ( adapter->hw.flash_address );
+	if  ( adapter->hw.hw_addr )
+		iounmap ( adapter->hw.hw_addr );
+
+	unregister_netdev ( netdev );
+	igb_reset  ( adapter );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/**
+ * igb_open - Called when a network interface is made active
+ *
+ * @v netdev	network interface device structure
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int igb_open ( struct net_device *netdev )
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	DBGP ( "igb_open\n" );
+
+	/* allocate transmit descriptors */
+	err = igb_setup_tx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up TX resources!\n" );
+		goto err_setup_tx;
+	}
+
+	/* allocate receive descriptors */
+	err = igb_setup_rx_resources ( adapter );
+	if ( err ) {
+		DBG ( "Error setting up RX resources!\n" );
+		goto err_setup_rx;
+	}
+
+	igb_configure_tx ( adapter );
+
+	igb_configure_rx ( adapter );
+
+	DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
+
+	return 0;
+
+err_setup_rx:
+	DBG ( "err_setup_rx\n" );
+	igb_free_tx_resources ( adapter );
+err_setup_tx:
+	DBG ( "err_setup_tx\n" );
+	igb_reset ( adapter );
+
+	return err;
+}
+
+/** igb net device operations */
+static struct net_device_operations igb_operations = {
+	.open		= igb_open,
+	.close		= igb_close,
+	.transmit	= igb_transmit,
+	.poll		= igb_poll,
+	.irq		= igb_irq,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.c
new file mode 100644
index 0000000..b29d4c4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.c
@@ -0,0 +1,388 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+#if 0
+
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
+
+/**
+ *  e1000_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8  sum = 0;
+
+	DEBUGFUNC("igb_calculate_checksum");
+
+	if (!buffer)
+		return 0;
+
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
+{
+	u32 hicr;
+	s32 ret_val = E1000_SUCCESS;
+	u8  i;
+
+	DEBUGFUNC("igb_mng_enable_host_if_generic");
+
+	/* Check that the host interface is enabled. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	if ((hicr & E1000_HICR_EN) == 0) {
+		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+	/* check the previous command is completed */
+	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+		hicr = E1000_READ_REG(hw, E1000_HICR);
+		if (!(hicr & E1000_HICR_C))
+			break;
+		msec_delay_irq(1);
+	}
+
+	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+		DEBUGOUT("Previous command timeout failed .\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_mng_mode_generic - Generic check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the firmware semaphore register and returns true (>0) if
+ *  manageability is enabled, else false (0).
+ **/
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	DEBUGFUNC("igb_check_mng_mode_generic");
+
+	fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
+ *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ **/
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
+{
+	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+	u32 *buffer = (u32 *)&hw->mng_cookie;
+	u32 offset;
+	s32 ret_val, hdr_csum, csum;
+	u8 i, len;
+	bool tx_filter = true;
+
+	DEBUGFUNC("igb_enable_tx_pkt_filtering_generic");
+
+	/* No manageability, no filtering */
+	if (!hw->mac.ops.check_mng_mode(hw)) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/*
+	 * If we can't read from the host interface for whatever
+	 * reason, disable filtering.
+	 */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val != E1000_SUCCESS) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/* Read in the header.  Length and offset are in dwords. */
+	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+	for (i = 0; i < len; i++) {
+		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
+		                                           E1000_HOST_IF,
+		                                           offset + i);
+	}
+	hdr_csum = hdr->checksum;
+	hdr->checksum = 0;
+	csum = e1000_calculate_checksum((u8 *)hdr,
+	                                E1000_MNG_DHCP_COOKIE_LENGTH);
+	/*
+	 * If either the checksums or signature don't match, then
+	 * the cookie area isn't considered valid, in which case we
+	 * take the safe route of assuming Tx filtering is enabled.
+	 */
+	if (hdr_csum != csum)
+		goto out;
+	if (hdr->signature != E1000_IAMT_SIGNATURE)
+		goto out;
+
+	/* Cookie area is valid, make the final check for filtering. */
+	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
+		tx_filter = false;
+
+out:
+	hw->mac.tx_pkt_filtering = tx_filter;
+	return tx_filter;
+}
+
+/**
+ *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
+                                      u16 length)
+{
+	struct e1000_host_mng_command_header hdr;
+	s32 ret_val;
+	u32 hicr;
+
+	DEBUGFUNC("igb_mng_write_dhcp_info_generic");
+
+	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+	hdr.command_length = length;
+	hdr.reserved1 = 0;
+	hdr.reserved2 = 0;
+	hdr.checksum = 0;
+
+	/* Enable the host interface */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val)
+		goto out;
+
+	/* Populate the host interface with the contents of "buffer". */
+	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+	                                  sizeof(hdr), &(hdr.checksum));
+	if (ret_val)
+		goto out;
+
+	/* Write the manageability command header */
+	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+	if (ret_val)
+		goto out;
+
+	/* Tell the ARC a new command is pending. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_mng_write_cmd_header_generic - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr)
+{
+	u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+	DEBUGFUNC("igb_mng_write_cmd_header_generic");
+
+	/* Write the whole command header structure with new checksum. */
+
+	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+	length >>= 2;
+	/* Write the relevant command block into the ram area. */
+	for (i = 0; i < length; i++) {
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+		                            *((u32 *) hdr + i));
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_mng_host_if_write_generic - Write to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                    u16 length, u16 offset, u8 *sum)
+{
+	u8 *tmp;
+	u8 *bufptr = buffer;
+	u32 data = 0;
+	s32 ret_val = E1000_SUCCESS;
+	u16 remaining, i, j, prev_bytes;
+
+	DEBUGFUNC("igb_mng_host_if_write_generic");
+
+	/* sum = only sum of the data and it is not checksum */
+
+	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	tmp = (u8 *)&data;
+	prev_bytes = offset & 0x3;
+	offset >>= 2;
+
+	if (prev_bytes) {
+		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+		for (j = prev_bytes; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+		length -= j - prev_bytes;
+		offset++;
+	}
+
+	remaining = length & 0x3;
+	length -= remaining;
+
+	/* Calculate length in DWORDs */
+	length >>= 2;
+
+	/*
+	 * The device driver writes the relevant command block into the
+	 * ram area.
+	 */
+	for (i = 0; i < length; i++) {
+		for (j = 0; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+		                            data);
+	}
+	if (remaining) {
+		for (j = 0; j < sizeof(u32); j++) {
+			if (j < remaining)
+				*(tmp + j) = *bufptr++;
+			else
+				*(tmp + j) = 0;
+
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = false;
+
+	DEBUGFUNC("igb_enable_mng_pass_thru");
+
+	if (!hw->mac.asf_firmware_present)
+		goto out;
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		goto out;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = E1000_READ_REG(hw, E1000_FWSM);
+		factps = E1000_READ_REG(hw, E1000_FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = true;
+			goto out;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = true;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.h
new file mode 100644
index 0000000..ff70d8c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_manage.h
@@ -0,0 +1,83 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_MANAGE_H_
+#define _IGB_MANAGE_H_
+
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
+s32  e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
+s32  e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                     u16 length, u16 offset, u8 *sum);
+s32  e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr);
+s32  e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
+                                       u8 *buffer, u16 length);
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE                  0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_VFTA_ENTRY_SHIFT               5
+#define E1000_VFTA_ENTRY_MASK                0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+#define E1000_HICR_SV              0x04  /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET        0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE  0x544D4149
+
+#endif /* _IGB_MANAGE_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.c
new file mode 100644
index 0000000..1bad567
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.c
@@ -0,0 +1,627 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+static void igb_stop_nvm(struct e1000_hw *hw);
+static void igb_reload_nvm_generic(struct e1000_hw *hw);
+
+/**
+ *  igb_init_nvm_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void igb_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	DEBUGFUNC("igb_init_nvm_ops_generic");
+
+	/* Initialize function pointers */
+	nvm->ops.reload = igb_reload_nvm_generic;
+}
+
+/**
+ *  igb_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  igb_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  igb_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u32 mask;
+
+	DEBUGFUNC("igb_shift_out_eec_bits");
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+
+		usec_delay(nvm->delay_usec);
+
+		igb_raise_eec_clk(hw, &eecd);
+		igb_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  igb_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	DEBUGFUNC("igb_shift_in_eec_bits");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		igb_raise_eec_clk(hw, &eecd);
+
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		igb_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  igb_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+
+	DEBUGFUNC("igb_poll_eerd_eewr_done");
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = E1000_READ_REG(hw, E1000_EERD);
+		else
+			reg = E1000_READ_REG(hw, E1000_EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE) {
+			ret_val = E1000_SUCCESS;
+			break;
+		}
+
+		usec_delay(5);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igb_acquire_nvm_generic - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 igb_acquire_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_acquire_nvm_generic");
+
+	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		usec_delay(5);
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		DEBUGOUT("Could not acquire NVM grant\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igb_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void igb_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	DEBUGFUNC("igb_standby_nvm");
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  igb_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void igb_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("igb_stop_nvm");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		igb_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  igb_release_nvm_generic - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void igb_release_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("igb_release_nvm_generic");
+
+	igb_stop_nvm(hw);
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	eecd &= ~E1000_EECD_REQ;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  igb_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 ret_val = E1000_SUCCESS;
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+	DEBUGFUNC("igb_ready_nvm_eeprom");
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		usec_delay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/*
+		 * Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out.
+		 */
+		while (timeout) {
+			igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+			                         hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			usec_delay(5);
+			igb_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			DEBUGOUT("SPI NVM Status error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_read_nvm_eerd");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * too many words for the offset, and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		E1000_WRITE_REG(hw, E1000_EERD, eerd);
+		ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
+		           E1000_NVM_RW_REG_DATA);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	DEBUGFUNC("igb_write_nvm_spi");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = igb_ready_nvm_eeprom(hw);
+		if (ret_val)
+			goto release;
+
+		igb_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+		                         nvm->opcode_bits);
+
+		igb_standby_nvm(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+		                         nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			igb_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				igb_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msec_delay(10);
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_pba_num_generic - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ **/
+s32 igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
+{
+	s32  ret_val;
+	u16 nvm_data;
+
+	DEBUGFUNC("igb_read_pba_num_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num = (u32)(nvm_data << 16);
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num |= nvm_data;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_mac_addr_generic - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 igb_read_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
+
+	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
+	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
+
+	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
+
+	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_validate_nvm_checksum_generic - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 igb_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("igb_validate_nvm_checksum_generic");
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		DEBUGOUT("NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_update_nvm_checksum_generic - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 igb_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32  ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("igb_update_nvm_checksum");
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val) {
+		DEBUGOUT("NVM Write Error while updating checksum.\n");
+        }
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_reload_nvm_generic - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+static void igb_reload_nvm_generic(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+
+	DEBUGFUNC("igb_reload_nvm_generic");
+
+	usec_delay(10);
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	E1000_WRITE_FLUSH(hw);
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.h
new file mode 100644
index 0000000..6b54d44
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_nvm.h
@@ -0,0 +1,52 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_NVM_H_
+#define _IGB_NVM_H_
+
+void igb_init_nvm_ops_generic(struct e1000_hw *hw);
+s32  igb_acquire_nvm_generic(struct e1000_hw *hw);
+
+s32  igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32  igb_read_mac_addr_generic(struct e1000_hw *hw);
+s32  igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
+s32  igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data);
+s32  igb_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32  igb_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
+                          u16 words, u16 *data);
+s32  igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  igb_update_nvm_checksum_generic(struct e1000_hw *hw);
+void igb_release_nvm_generic(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE  0xDB00
+
+#endif /* _IGB_NVM_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_osdep.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_osdep.h
new file mode 100644
index 0000000..167b0f8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_osdep.h
@@ -0,0 +1,129 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* glue for the OS independent part of e1000
+ * includes register access macros
+ */
+
+#ifndef _IGB_OSDEP_H_
+#define _IGB_OSDEP_H_
+
+/* Begin OS Dependencies */
+
+#define u8         unsigned char
+#define bool       boolean_t
+#define dma_addr_t unsigned long
+#define __le16     uint16_t
+#define __le32     uint32_t
+#define __le64     uint64_t
+
+#define __iomem
+#define __devinit
+
+#define msleep(x) mdelay(x)
+
+#define ETH_FCS_LEN 4
+
+typedef int spinlock_t;
+typedef enum {
+    false = 0,
+    true = 1
+} boolean_t;
+
+#define TRUE  1
+#define FALSE 0
+
+#define usec_delay(x) udelay(x)
+#define msec_delay(x) mdelay(x)
+#define msec_delay_irq(x) mdelay(x)
+
+/* End OS Dependencies */
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+#define ETH_ADDR_LEN           ETH_ALEN
+
+#ifdef __BIG_ENDIAN
+#define E1000_BIG_ENDIAN __BIG_ENDIAN
+#endif
+
+
+#define DEBUGOUT(S) if (0) { printf(S); }
+#define DEBUGOUT1(S, A...) if (0) { printf(S, A); }
+
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+#define E1000_REGISTER(a, reg) (reg)
+
+#define E1000_WRITE_REG(a, reg, value) do {  \
+                writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg))); } while (0)
+
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg)))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) do { \
+          writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))); } while (0);
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+    writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))))
+
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+    readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+    writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+    readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))
+
+#define E1000_WRITE_REG_IO(a, reg, offset) do { \
+    outl(reg, ((a)->io_base));                  \
+    outl(offset, ((a)->io_base + 4));      } while (0)
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
+
+#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
+    writel((value), ((a)->flash_address + reg)))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
+    writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
+
+#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
+
+#endif /* _IGB_OSDEP_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.c
new file mode 100644
index 0000000..16664fd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.c
@@ -0,0 +1,2470 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igb.h"
+
+static s32 igb_phy_setup_autoneg(struct e1000_hw *hw);
+
+#if 0
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_m88_cable_length_table) / \
+                 sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_igp_2_cable_length_table) / \
+                 sizeof(e1000_igp_2_cable_length_table[0]))
+#endif
+
+/**
+ *  igb_check_reset_block_generic - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 igb_check_reset_block_generic(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	DEBUGFUNC("igb_check_reset_block");
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ *  igb_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 igb_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id;
+
+	DEBUGFUNC("igb_get_phy_id");
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		usec_delay(20);
+		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_phy_reset_dsp_generic - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+s32 igb_phy_reset_dsp_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_phy_reset_dsp_generic");
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control register in the PHY at offset and stores the
+ *  information read to data.
+ **/
+s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_read_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_READ));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Read did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_write_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+	        (offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_WRITE));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Write did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_phy_reg_i2c - Read PHY register using i2c
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset using the i2c interface and stores the
+ *  retrieved information in data.
+ **/
+s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+
+	DEBUGFUNC("igb_read_phy_reg_i2c");
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+	          (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+	          (E1000_I2CCMD_OPCODE_READ));
+
+	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		usec_delay(50);
+		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		DEBUGOUT("I2CCMD Read did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		DEBUGOUT("I2CCMD Error bit set\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* Need to byte-swap the 16-bit value. */
+	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_write_phy_reg_i2c - Write PHY register using i2c
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset using the i2c interface.
+ **/
+s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+	u16 phy_data_swapped;
+
+	DEBUGFUNC("igb_write_phy_reg_i2c");
+
+	/* Swap the data bytes for the I2C interface */
+	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+	          (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+	          E1000_I2CCMD_OPCODE_WRITE |
+	          phy_data_swapped);
+
+	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		usec_delay(50);
+		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		DEBUGOUT("I2CCMD Write did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		DEBUGOUT("I2CCMD Error bit set\n");
+		return -E1000_ERR_PHY;
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_read_phy_reg_m88 - Read m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_read_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_phy_reg_m88 - Write m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_write_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  __igb_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and stores the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+static s32 __igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
+                                    bool locked)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("__igb_read_phy_reg_igp");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = igb_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
+out:
+	return ret_val;
+}
+/**
+ *  igb_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore then reads the PHY register at offset and stores the
+ *  retrieved information in data.
+ *  Release the acquired semaphore before exiting.
+ **/
+s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __igb_read_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ *  igb_read_phy_reg_igp_locked - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset and stores the retrieved information
+ *  in data.  Assumes semaphore already acquired.
+ **/
+s32 igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __igb_read_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
+ *  igb_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+static s32 __igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
+                                     bool locked)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_write_phy_reg_igp");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = igb_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __igb_write_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ *  igb_write_phy_reg_igp_locked - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset.
+ *  Assumes semaphore already acquired.
+ **/
+s32 igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __igb_write_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
+ *  __igb_read_kmrn_reg - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release any acquired semaphores before exiting.
+ **/
+static s32 __igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
+                                 bool locked)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("__igb_read_kmrn_reg");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+
+	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_read_kmrn_reg_generic -  Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore then reads the PHY register at offset using the
+ *  kumeran interface.  The information retrieved is stored in data.
+ *  Release the acquired semaphore before exiting.
+ **/
+s32 igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __igb_read_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ *  igb_read_kmrn_reg_locked -  Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset using the kumeran interface.  The
+ *  information retrieved is stored in data.
+ *  Assumes semaphore already acquired.
+ **/
+s32 igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return __igb_read_kmrn_reg(hw, offset, data, true);
+}
+
+/**
+ *  __igb_write_kmrn_reg - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *  @locked: semaphore has already been acquired or not
+ *
+ *  Acquires semaphore, if necessary.  Then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release any acquired semaphores
+ *  before exiting.
+ **/
+static s32 __igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
+                                  bool locked)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("igb_write_kmrn_reg_generic");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+
+	if (!locked)
+		hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_write_kmrn_reg_generic -  Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore then writes the data to the PHY register at the offset
+ *  using the kumeran interface.  Release the acquired semaphore before exiting.
+ **/
+s32 igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __igb_write_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ *  igb_write_kmrn_reg_locked -  Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Write the data to PHY register at the offset using the kumeran interface.
+ *  Assumes semaphore already acquired.
+ **/
+s32 igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return __igb_write_kmrn_reg(hw, offset, data, true);
+}
+
+/**
+ *  igb_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	DEBUGFUNC("igb_copper_link_setup_m88");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/*
+	 * Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+
+	/*
+	 * Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	if (phy->revision < E1000_REVISION_4) {
+		/*
+		 * Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == E1000_REVISION_2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		                             phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Commit the changes. */
+	ret_val = phy->ops.commit(hw);
+	if (ret_val) {
+		DEBUGOUT("Error committing the PHY changes\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("igb_copper_link_setup_igp");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.reset(hw);
+	if (ret_val) {
+		DEBUGOUT("Error resetting the PHY.\n");
+		goto out;
+	}
+
+	/*
+	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+	 * timeout issues when LFS is enabled.
+	 */
+	msec_delay(100);
+
+	/*
+	 * The NVM settings will configure LPLU in D3 for
+	 * non-IGP1 PHYs.
+	 */
+	if (phy->type == e1000_phy_igp) {
+		/* disable lplu d3 during driver init */
+		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D3\n");
+			goto out;
+		}
+	}
+
+	/* disable lplu d0 during driver init */
+	if (hw->phy.ops.set_d0_lplu_state) {
+		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D0\n");
+			goto out;
+		}
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		goto out;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/*
+		 * when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default.
+		 */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+			if (ret_val)
+				goto out;
+		}
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 igb_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("igb_copper_link_autoneg");
+
+	/*
+	 * Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/*
+	 * If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+	ret_val = igb_phy_setup_autoneg(hw);
+	if (ret_val) {
+		DEBUGOUT("Error Setting up Auto-Negotiation\n");
+		goto out;
+	}
+	DEBUGOUT("Restarting Auto-Neg\n");
+
+	/*
+	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->autoneg_wait_to_complete) {
+		ret_val = hw->mac.ops.wait_autoneg(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while waiting for "
+			         "autoneg to complete\n");
+			goto out;
+		}
+	}
+
+	hw->mac.get_link_status = true;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	DEBUGFUNC("igb_phy_setup_autoneg");
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
+		                            &mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+	                         NWAY_AR_100TX_HD_CAPS |
+	                         NWAY_AR_10T_FD_CAPS   |
+	                         NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		DEBUGOUT("Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		DEBUGOUT("Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		DEBUGOUT("Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		DEBUGOUT("Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF) {
+		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
+        }
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		DEBUGOUT("Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc.current_mode) {
+	case e1000_fc_none:
+		/*
+		 * Flow control (Rx & Tx) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled, and Tx Flow control is
+		 * disabled, by a software over-ride.
+		 *
+		 * Since there really isn't a way to advertise that we are
+		 * capable of Rx Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric Rx PAUSE.  Later
+		 * (in e1000_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = phy->ops.write_reg(hw,
+		                              PHY_1000T_CTRL,
+		                              mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_setup_copper_link_generic - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 igb_setup_copper_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("igb_setup_copper_link_generic");
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement and perform
+		 * autonegotiation.
+		 */
+		ret_val = igb_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+#if 0
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+		DEBUGOUT("Forcing Speed and Duplex\n");
+		ret_val = hw->phy.ops.force_speed_duplex(hw);
+		if (ret_val) {
+			DEBUGOUT("Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+#endif
+	}
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = igb_phy_has_link_generic(hw,
+	                                     COPPER_LINK_UP_LIMIT,
+	                                     10,
+	                                     &link);
+	if (ret_val)
+		goto out;
+
+	if (link) {
+		DEBUGOUT("Valid link established!!!\n");
+		igb_config_collision_dist_generic(hw);
+		ret_val = igb_config_fc_after_link_up_generic(hw);
+	} else {
+		DEBUGOUT("Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+#if 0
+/**
+ *  igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("igb_phy_force_speed_duplex_igp");
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = igb_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			DEBUGOUT("Link taking longer than expected.\n");
+                }
+		/* Try once more */
+		ret_val = igb_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  igb_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("igb_phy_force_speed_duplex_m88");
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/* Reset the phy to commit changes. */
+	ret_val = hw->phy.ops.commit(hw);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = phy->ops.write_reg(hw,
+			                              M88E1000_PHY_PAGE_SELECT,
+			                              0x001d);
+			if (ret_val)
+				goto out;
+			ret_val = igb_phy_reset_dsp_generic(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  igb_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+s32 igb_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("igb_phy_force_speed_duplex_ife");
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = igb_phy_force_speed_duplex_igp(hw);
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	igb_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IFE PMC: %X\n", data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = igb_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			DEBUGOUT("Link taking longer than expected.\n");
+                }
+		/* Try once more */
+		ret_val = igb_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+#endif
+
+#if 0
+/**
+ *  igb_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	DEBUGFUNC("igb_phy_force_speed_duplex_setup");
+
+	/* Turn off flow control when forcing speed/duplex */
+	hw->fc.current_mode = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		DEBUGOUT("Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		DEBUGOUT("Forcing 10mb\n");
+	}
+
+	igb_config_collision_dist_generic(hw);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+}
+#endif
+
+/**
+ *  igb_set_d3_lplu_state_generic - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("igb_set_d3_lplu_state_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                              data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_check_downshift_generic - Checks whether a downshift in speed occurred
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 igb_check_downshift_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("igb_check_downshift_generic");
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = false;
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 igb_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("igb_check_polarity_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  igb_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+s32 igb_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	DEBUGFUNC("igb_check_polarity_igp");
+
+	/*
+	 * Polarity is determined based on the speed of
+	 * our connection.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/*
+		 * This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_check_polarity_ife - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reversal feature being enabled.
+ **/
+s32 igb_check_polarity_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("igb_check_polarity_ife");
+
+	/*
+	 * Polarity is determined based on the reversal feature being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask = IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset = IFE_PHY_SPECIAL_CONTROL;
+		mask = IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+		                       ? e1000_rev_polarity_reversed
+		                       : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  igb_wait_autoneg_generic - Wait for auto-neg completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+s32 igb_wait_autoneg_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("igb_wait_autoneg_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msec_delay(100);
+	}
+
+	/*
+	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  igb_phy_has_link_generic - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                               u32 usec_interval, bool *success)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("igb_phy_has_link_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	for (i = 0; i < iterations; i++) {
+		/*
+		 * Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val) {
+			/*
+			 * If the first read fails, another entity may have
+			 * ownership of the resources, wait and try again to
+			 * see if they have relinquished the resources yet.
+			 */
+			usec_delay(usec_interval);
+		}
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			msec_delay_irq(usec_interval/1000);
+		else
+			usec_delay(usec_interval);
+	}
+
+	*success = (i < iterations) ? true : false;
+
+	return ret_val;
+}
+
+#if 0
+/**
+ *  igb_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 igb_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	DEBUGFUNC("igb_get_cable_length_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which represent the
+ *  combination of coarse and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+	                                                 {IGP02E1000_PHY_AGC_A,
+	                                                  IGP02E1000_PHY_AGC_B,
+	                                                  IGP02E1000_PHY_AGC_C,
+	                                                  IGP02E1000_PHY_AGC_D};
+
+	DEBUGFUNC("igb_get_cable_length_igp_2");
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Getting bits 15:9, which represent the combination of
+		 * coarse and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length.
+		 */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+		                IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+	              e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+#endif
+
+/**
+ *  igb_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("igb_get_phy_info_m88");
+
+	if (phy->media_type != e1000_media_type_copper) {
+		DEBUGOUT("Phy info is only valid for copper media\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+	                           ? true : false;
+
+	ret_val = igb_check_polarity_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+#if 0
+		ret_val = hw->phy.ops.get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+#endif
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("igb_get_phy_info_igp");
+
+	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = igb_check_polarity_igp(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+#if 0
+		ret_val = phy->ops.get_cable_length(hw);
+#endif
+		ret_val = -E1000_ERR_CONFIG;
+		if (ret_val)
+			goto out;
+#if 0
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+#endif
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_phy_sw_reset_generic - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 igb_phy_sw_reset_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("igb_phy_sw_reset_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	usec_delay(1);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_phy_hw_reset_generic - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and release the semaphore (if necessary).
+ **/
+s32 igb_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+
+	DEBUGFUNC("igb_phy_hw_reset_generic");
+
+	ret_val = phy->ops.check_reset_block(hw);
+	if (ret_val) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(phy->reset_delay_us);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(150);
+
+	phy->ops.release(hw);
+
+	ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_get_cfg_done_generic - Generic configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Generic function to wait 10 milli-seconds for configuration to complete
+ *  and return success.
+ **/
+s32 igb_get_cfg_done_generic(struct e1000_hw *hw __unused)
+{
+	DEBUGFUNC("igb_get_cfg_done_generic");
+
+	msec_delay_irq(10);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	DEBUGOUT("Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to Tx amplitude in Gig mode */
+	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igb_get_phy_type_from_id - Get PHY type from id
+ *  @phy_id: phy_id read from the phy
+ *
+ *  Returns the phy type from the id.
+ **/
+enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id)
+{
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	switch (phy_id)	{
+	case M88E1000_I_PHY_ID:
+	case M88E1000_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+	case M88E1011_I_PHY_ID:
+		phy_type = e1000_phy_m88;
+		break;
+	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+		phy_type = e1000_phy_igp_2;
+		break;
+	case GG82563_E_PHY_ID:
+		phy_type = e1000_phy_gg82563;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy_type = e1000_phy_igp_3;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy_type = e1000_phy_ife;
+		break;
+	default:
+		phy_type = e1000_phy_unknown;
+		break;
+	}
+	return phy_type;
+}
+
+/**
+ *  igb_determine_phy_address - Determines PHY address.
+ *  @hw: pointer to the HW structure
+ *
+ *  This uses a trial and error method to loop through possible PHY
+ *  addresses. It tests each by reading the PHY ID registers and
+ *  checking for a match.
+ **/
+s32 igb_determine_phy_address(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+	u32 phy_addr = 0;
+	u32 i;
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	hw->phy.id = phy_type;
+
+	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+		hw->phy.addr = phy_addr;
+		i = 0;
+
+		do {
+			igb_get_phy_id(hw);
+			phy_type = igb_get_phy_type_from_id(hw->phy.id);
+
+			/*
+			 * If phy_type is valid, break - we found our
+			 * PHY address
+			 */
+			if (phy_type  != e1000_phy_unknown) {
+				ret_val = E1000_SUCCESS;
+				goto out;
+			}
+			msec_delay(1);
+			i++;
+		} while (i < 10);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * igb_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void igb_power_up_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg &= ~MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * igb_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void igb_power_down_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg |= MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+	msec_delay(1);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.h
new file mode 100644
index 0000000..8e6bc99
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_phy.h
@@ -0,0 +1,171 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_PHY_H_
+#define _IGB_PHY_H_
+
+void igb_init_phy_ops_generic(struct e1000_hw *hw);
+s32  igb_check_downshift_generic(struct e1000_hw *hw);
+s32  igb_check_polarity_m88(struct e1000_hw *hw);
+s32  igb_check_polarity_igp(struct e1000_hw *hw);
+s32  igb_check_polarity_ife(struct e1000_hw *hw);
+s32  igb_check_reset_block_generic(struct e1000_hw *hw);
+s32  igb_copper_link_autoneg(struct e1000_hw *hw);
+s32  igb_copper_link_setup_igp(struct e1000_hw *hw);
+s32  igb_copper_link_setup_m88(struct e1000_hw *hw);
+#if 0
+s32  igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+#endif
+#if 0
+s32  igb_get_cable_length_m88(struct e1000_hw *hw);
+s32  igb_get_cable_length_igp_2(struct e1000_hw *hw);
+#endif
+s32  igb_get_cfg_done_generic(struct e1000_hw *hw);
+s32  igb_get_phy_id(struct e1000_hw *hw);
+s32  igb_get_phy_info_igp(struct e1000_hw *hw);
+s32  igb_get_phy_info_m88(struct e1000_hw *hw);
+s32  igb_phy_sw_reset_generic(struct e1000_hw *hw);
+#if 0
+void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+#endif
+s32  igb_phy_hw_reset_generic(struct e1000_hw *hw);
+s32  igb_phy_reset_dsp_generic(struct e1000_hw *hw);
+s32  igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
+s32  igb_setup_copper_link_generic(struct e1000_hw *hw);
+s32  igb_wait_autoneg_generic(struct e1000_hw *hw);
+s32  igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_phy_reset_dsp(struct e1000_hw *hw);
+s32  igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                                u32 usec_interval, bool *success);
+s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id);
+s32  igb_determine_phy_address(struct e1000_hw *hw);
+void igb_power_up_phy_copper(struct e1000_hw *hw);
+void igb_power_down_phy_copper(struct e1000_hw *hw);
+s32  igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
+
+#define E1000_MAX_PHY_ADDR                4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
+#define IGP_PAGE_SHIFT                    5
+#define PHY_REG_MASK                      0x1F
+
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD          0x0010
+#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0800
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define IGP03E1000_PHY_MISC_CTRL          0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
+#define E1000_KMRNCTRLSTA_REN             0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED    0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
+#define IFE_PSC_FORCE_POLARITY             0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE            0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif /* _IGB_PHY_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_regs.h
new file mode 100644
index 0000000..e549675
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igb/igb_regs.h
@@ -0,0 +1,486 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C  /* Future Extended - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* Rx Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
+#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_GPIE     0x01514  /* General Purpose Interrupt Enable - RW */
+#define E1000_IVAR0    0x01700  /* Interrupt Vector Allocation (array) - RW */
+#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
+#define E1000_TCTL     0x00400  /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
+#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
+#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_TCPTIMER 0x0104C  /* TCP Timer - RW */
+#define E1000_VPDDIAG  0x01060  /* VPD Diagnostic - RO */
+#define E1000_ICR_V2   0x01500  /* Interrupt Cause - new location - RC */
+#define E1000_ICS_V2   0x01504  /* Interrupt Cause Set - new location - WO */
+#define E1000_IMS_V2   0x01508  /* Interrupt Mask Set/Read - new location - RW */
+#define E1000_IMC_V2   0x0150C  /* Interrupt Mask Clear - new location - WO */
+#define E1000_IAM_V2   0x01510  /* Interrupt Ack Auto Mask - new location - RW */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
+#define E1000_PBDIAG   0x02458  /* Packet Buffer Diagnostic - RW */
+#define E1000_RXPBS    0x02404  /* Rx Packet Buffer Size - RW */
+#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
+#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+                                         (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+                                         (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+                                         (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+                                         (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+                                         (0x0C010 + ((_n) * 0x40)))
+#define E1000_RXCTL(_n)      ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+                                         (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
+#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+                                         (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+                                         (0x0C028 + ((_n) * 0x40)))
+#define E1000_RQDPC(_n)      ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
+                                         (0x0C030 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+                                         (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+                                         (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+                                         (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+                                         (0x0E010 + ((_n) * 0x40)))
+#define E1000_TXCTL(_n)      ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+                                         (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
+#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+                                         (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+                                         (0x0E028 + ((_n) * 0x40)))
+#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+                                         (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+                                         (0x0E03C + ((_n) * 0x40)))
+#define E1000_TARC(_n)                   (0x03840 + ((_n) * 0x100))
+#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                                       (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                                       (0x054E4 + ((_i - 16) * 8)))
+#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
+#define E1000_PBSLAC   0x03100  /* Packet Buffer Slave Access Control */
+#define E1000_PBSLAD(_n)  (0x03110 + (0x4 * (_n)))  /* Packet Buffer DWORD (_n) */
+#define E1000_TXPBS    0x03404  /* Tx Packet Buffer Size - RW */
+#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
+#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
+#define E1000_DTXTCPFLGL 0x0359C /* DMA Tx Control flag low - RW */
+#define E1000_DTXTCPFLGH 0x035A0 /* DMA Tx Control flag high - RW */
+#define E1000_DTXMXSZRQ  0x03540 /* DMA Tx Max Total Allow Size Requests - RW */
+#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+
+#define E1000_LSECTXUT        0x04300  /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */
+#define E1000_LSECTXPKTE      0x04304  /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */
+#define E1000_LSECTXPKTP      0x04308  /* LinkSec Protected Tx Packet Count - OutPktsProtected */
+#define E1000_LSECTXOCTE      0x0430C  /* LinkSec Encrypted Tx Octets Count - OutOctetsEncrypted */
+#define E1000_LSECTXOCTP      0x04310  /* LinkSec Protected Tx Octets Count - OutOctetsProtected */
+#define E1000_LSECRXUT        0x04314  /* LinkSec Untagged non-Strict Rx Packet Count - InPktsUntagged/InPktsNoTag */
+#define E1000_LSECRXOCTD      0x0431C  /* LinkSec Rx Octets Decrypted Count - InOctetsDecrypted */
+#define E1000_LSECRXOCTV      0x04320  /* LinkSec Rx Octets Validated - InOctetsValidated */
+#define E1000_LSECRXBAD       0x04324  /* LinkSec Rx Bad Tag - InPktsBadTag */
+#define E1000_LSECRXNOSCI     0x04328  /* LinkSec Rx Packet No SCI Count - InPktsNoSci */
+#define E1000_LSECRXUNSCI     0x0432C  /* LinkSec Rx Packet Unknown SCI Count - InPktsUnknownSci */
+#define E1000_LSECRXUNCH      0x04330  /* LinkSec Rx Unchecked Packets Count - InPktsUnchecked */
+#define E1000_LSECRXDELAY     0x04340  /* LinkSec Rx Delayed Packet Count - InPktsDelayed */
+#define E1000_LSECRXLATE      0x04350  /* LinkSec Rx Late Packets Count - InPktsLate */
+#define E1000_LSECRXOK(_n)    (0x04360 + (0x04 * (_n))) /* LinkSec Rx Packet OK Count - InPktsOk */
+#define E1000_LSECRXINV(_n)   (0x04380 + (0x04 * (_n))) /* LinkSec Rx Invalid Count - InPktsInvalid */
+#define E1000_LSECRXNV(_n)    (0x043A0 + (0x04 * (_n))) /* LinkSec Rx Not Valid Count - InPktsNotValid */
+#define E1000_LSECRXUNSA      0x043C0  /* LinkSec Rx Unused SA Count - InPktsUnusedSa */
+#define E1000_LSECRXNUSA      0x043D0  /* LinkSec Rx Not Using SA Count - InPktsNotUsingSa */
+#define E1000_LSECTXCAP       0x0B000  /* LinkSec Tx Capabilities Register - RO */
+#define E1000_LSECRXCAP       0x0B300  /* LinkSec Rx Capabilities Register - RO */
+#define E1000_LSECTXCTRL      0x0B004  /* LinkSec Tx Control - RW */
+#define E1000_LSECRXCTRL      0x0B304  /* LinkSec Rx Control - RW */
+#define E1000_LSECTXSCL       0x0B008  /* LinkSec Tx SCI Low - RW */
+#define E1000_LSECTXSCH       0x0B00C  /* LinkSec Tx SCI High - RW */
+#define E1000_LSECTXSA        0x0B010  /* LinkSec Tx SA0 - RW */
+#define E1000_LSECTXPN0       0x0B018  /* LinkSec Tx SA PN 0 - RW */
+#define E1000_LSECTXPN1       0x0B01C  /* LinkSec Tx SA PN 1 - RW */
+#define E1000_LSECRXSCL       0x0B3D0  /* LinkSec Rx SCI Low - RW */
+#define E1000_LSECRXSCH       0x0B3E0  /* LinkSec Rx SCI High - RW */
+#define E1000_LSECTXKEY0(_n)  (0x0B020 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 0 - WO */
+#define E1000_LSECTXKEY1(_n)  (0x0B030 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 1 - WO */
+#define E1000_LSECRXSA(_n)    (0x0B310 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+#define E1000_LSECRXPN(_n)    (0x0B330 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
+/*
+ * LinkSec Rx Keys  - where _n is the SA no. and _m the 4 dwords of the 128 bit
+ * key - RW.
+ */
+#define E1000_LSECRXKEY(_n, _m) (0x0B350 + (0x10 * (_n)) + (0x04 * (_m)))
+
+#define E1000_SSVPC             0x041A0  /* Switch Security Violation Packet Count */
+#define E1000_IPSCTRL           0xB430   /* IpSec Control Register */
+#define E1000_IPSRXCMD          0x0B408  /* IPSec Rx Command Register - RW */
+#define E1000_IPSRXIDX          0x0B400  /* IPSec Rx Index - RW */
+#define E1000_IPSRXIPADDR(_n)   (0x0B420+ (0x04 * (_n)))  /* IPSec Rx IPv4/v6 Address - RW */
+#define E1000_IPSRXKEY(_n)      (0x0B410 + (0x04 * (_n))) /* IPSec Rx 128-bit Key - RW */
+#define E1000_IPSRXSALT         0x0B404  /* IPSec Rx Salt - RW */
+#define E1000_IPSRXSPI          0x0B40C  /* IPSec Rx SPI - RW */
+#define E1000_IPSTXKEY(_n)      (0x0B460 + (0x04 * (_n))) /* IPSec Tx 128-bit Key - RW */
+#define E1000_IPSTXSALT         0x0B454  /* IPSec Tx Salt - RW */
+#define E1000_IPSTXIDX          0x0B450  /* IPSec Tx SA IDX - RW */
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_RA2      0x054E0  /* 2nd half of receive address array - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
+#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+#define E1000_FHFT(_n)  (0x09000 + (_n * 0x100)) /* Flexible Host Filter Table */
+#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100)) /* Ext Flexible Host Filter Table */
+
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA      0x0003C /* PHY address - RW */
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR         0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+                                                    * (_i) - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * upper reg - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * vector ctrl reg - RW */
+#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+/* VT Registers */
+#define E1000_SWPBS     0x03004 /* Switch Packet Buffer Size - RW */
+#define E1000_MBVFICR   0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR   0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE     0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE      0x00C8C /* VF Receive Enables */
+#define E1000_VFTE      0x00C90 /* VF Transmit Enables */
+#define E1000_QDE       0x02408 /* Queue Drop Enable - RW */
+#define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_RPLOLR    0x05AF0 /* Replication Offload - RW */
+#define E1000_UTA       0x0A000 /* Unicast Table Array - RW */
+#define E1000_IOVTCL    0x05BBC /* IOV Control Register */
+#define E1000_VMRCTL    0X05D80 /* Virtual Mirror Rule Control */
+/* These act per VF so an array friendly macro is used */
+#define E1000_V2PMAILBOX(_n)   (0x00C40 + (4 * (_n)))
+#define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
+#define E1000_VFVMBMEM(_n)     (0x00800 + (_n))
+#define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
+#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
+                                                       * Filter - RW */
+/* Time Sync */
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
+#define E1000_RXSTMPL    0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH    0x0B628 /* Rx timestamp High - RO */
+#define E1000_RXSATRL    0x0B62C /* Rx timestamp attribute low - RO */
+#define E1000_RXSATRH    0x0B630 /* Rx timestamp attribute high - RO */
+#define E1000_TXSTMPL    0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH    0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML    0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
+
+/* Filtering Registers */
+#define E1000_SAQF(_n)  (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
+#define E1000_DAQF(_n)  (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */
+#define E1000_SPQF(_n)  (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */
+#define E1000_FTQF(_n)  (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
+#define E1000_TTQF(_n)  (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */
+#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
+#define E1000_ETQF(_n)  (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
+
+#define E1000_RTTDCS            0x3600  /* Reedtown Tx Desc plane control and status */
+#define E1000_RTTPCS            0x3474  /* Reedtown Tx Packet Plane control and status */
+#define E1000_RTRPCS            0x2474  /* Rx packet plane control and status */
+#define E1000_RTRUP2TC          0x05AC4 /* Rx User Priority to Traffic Class */
+#define E1000_RTTUP2TC          0x0418  /* Transmit User Priority to Traffic Class */
+#define E1000_RTTDTCRC(_n)      (0x3610 + ((_n) * 4)) /* Tx Desc plane TC Rate-scheduler config */
+#define E1000_RTTPTCRC(_n)      (0x3480 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTRPTCRC(_n)      (0x2480 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Config */
+#define E1000_RTTDTCRS(_n)      (0x3630 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler Status */
+#define E1000_RTTDTCRM(_n)      (0x3650 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler MMW */
+#define E1000_RTTPTCRS(_n)      (0x34A0 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTTPTCRM(_n)      (0x34C0 + ((_n) * 4)) /* Tx Packet plane TC Rate-scheduler MMW */
+#define E1000_RTRPTCRS(_n)      (0x24A0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Status */
+#define E1000_RTRPTCRM(_n)      (0x24C0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler MMW */
+#define E1000_RTTDVMRM(_n)      (0x3670 + ((_n) * 4)) /* Tx Desc plane VM Rate-Scheduler MMW*/
+#define E1000_RTTBCNRM(_n)      (0x3690 + ((_n) * 4)) /* Tx BCN Rate-Scheduler MMW */
+#define E1000_RTTDQSEL          0x3604  /* Tx Desc Plane Queue Select */
+#define E1000_RTTDVMRC          0x3608  /* Tx Desc Plane VM Rate-Scheduler Config */
+#define E1000_RTTDVMRS          0x360C  /* Tx Desc Plane VM Rate-Scheduler Status */
+#define E1000_RTTBCNRC          0x36B0  /* Tx BCN Rate-Scheduler Config */
+#define E1000_RTTBCNRS          0x36B4  /* Tx BCN Rate-Scheduler Status */
+#define E1000_RTTBCNCR          0xB200  /* Tx BCN Control Register */
+#define E1000_RTTBCNTG          0x35A4  /* Tx BCN Tagging */
+#define E1000_RTTBCNCP          0xB208  /* Tx BCN Congestion point */
+#define E1000_RTRBCNCR          0xB20C  /* Rx BCN Control Register */
+#define E1000_RTTBCNRD          0x36B8  /* Tx BCN Rate Drift */
+#define E1000_PFCTOP            0x1080  /* Priority Flow Control Type and Opcode */
+#define E1000_RTTBCNIDX         0xB204  /* Tx BCN Congestion Point */
+#define E1000_RTTBCNACH         0x0B214 /* Tx BCN Control High */
+#define E1000_RTTBCNACL         0x0B210 /* Tx BCN Control Low */
+
+#endif /* _IGB_REGS_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf.h
new file mode 100644
index 0000000..74f99c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf.h
@@ -0,0 +1,377 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _IGBVF_H_
+#define _IGBVF_H_
+
+#include "igbvf_vf.h"
+
+/* Forward declarations */
+struct igbvf_info;
+struct igbvf_adapter;
+
+/* Interrupt defines */
+#define IGBVF_START_ITR                    648 /* ~6000 ints/sec */
+
+/* Tx/Rx descriptor defines */
+#define IGBVF_DEFAULT_TXD		256
+#define IGBVF_MAX_TXD			4096
+#define IGBVF_MIN_TXD			80
+
+#define IGBVF_DEFAULT_RXD		256
+#define IGBVF_MAX_RXD			4096
+#define IGBVF_MIN_RXD			80
+
+#define IGBVF_MIN_ITR_USECS		10 /* 100000 irq/sec */
+#define IGBVF_MAX_ITR_USECS		10000 /* 100    irq/sec */
+
+/* RX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ *           descriptors available in its onboard memory.
+ *           Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ *           available in host memory.
+ *           If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ *           descriptors until either it has this many to write back, or the
+ *           ITR timer expires.
+ */
+#define IGBVF_RX_PTHRESH                    16
+#define IGBVF_RX_HTHRESH                     8
+#define IGBVF_RX_WTHRESH                     1
+
+#define IGBVF_TX_PTHRESH                     8
+#define IGBVF_TX_HTHRESH                     1
+#define IGBVF_TX_WTHRESH                     1
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
+#define IGBVF_FC_PAUSE_TIME		0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define IGBVF_TX_QUEUE_WAKE	32
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGBVF_RX_BUFFER_WRITE		16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES			0
+#define IGBVF_EEPROM_APME		0x0400
+
+#define IGBVF_MNG_VLAN_NONE		(-1)
+
+enum igbvf_boards {
+	board_vf,
+};
+
+struct igbvf_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+/*
+ * wrappers around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct igbvf_buffer {
+#if 0
+	dma_addr_t dma;
+	dma_addr_t page_dma;
+	struct sk_buff *skb;
+	union {
+		/* Tx */
+		struct {
+			unsigned long time_stamp;
+			u16 length;
+			u16 next_to_watch;
+		};
+		/* Rx */
+		struct {
+			struct page *page;
+			unsigned int page_offset;
+		};
+	};
+	struct page *page;
+#endif
+};
+
+struct igbvf_ring {
+#if 0
+	struct igbvf_adapter *adapter;  /* backlink */
+	void *desc;			/* pointer to ring memory  */
+	dma_addr_t dma;			/* phys address of ring    */
+	unsigned int size;		/* length of ring in bytes */
+	unsigned int count;		/* number of desc. in ring */
+
+	u16 next_to_use;
+	u16 next_to_clean;
+
+	u16 head;
+	u16 tail;
+
+	/* array of buffer information structs */
+	struct igbvf_buffer *buffer_info;
+	struct napi_struct napi;
+
+	char name[IFNAMSIZ + 5];
+	u32 eims_value;
+	u32 itr_val;
+	u16 itr_register;
+	int set_itr;
+
+	struct sk_buff *rx_skb_top;
+
+	struct igbvf_queue_stats stats;
+#endif
+};
+
+/* board specific private data structure */
+struct igbvf_adapter {
+#if 0
+	struct timer_list watchdog_timer;
+	struct timer_list blink_timer;
+
+	struct work_struct reset_task;
+	struct work_struct watchdog_task;
+
+	const struct igbvf_info *ei;
+
+	struct vlan_group *vlgrp;
+	u32 bd_number;
+	u32 rx_buffer_len;
+	u32 polling_interval;
+	u16 mng_vlan_id;
+	u16 link_speed;
+	u16 link_duplex;
+
+	spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
+
+	/* track device up/down/testing state */
+	unsigned long state;
+
+	/* Interrupt Throttle Rate */
+	u32 itr;
+	u32 itr_setting;
+	u16 tx_itr;
+	u16 rx_itr;
+
+	/*
+	 * Tx
+	 */
+	struct igbvf_ring *tx_ring /* One per active queue */
+						____cacheline_aligned_in_smp;
+
+	unsigned long tx_queue_len;
+	unsigned int restart_queue;
+	u32 txd_cmd;
+
+	bool detect_tx_hung;
+	u8 tx_timeout_factor;
+
+	unsigned int total_tx_bytes;
+	unsigned int total_tx_packets;
+	unsigned int total_rx_bytes;
+	unsigned int total_rx_packets;
+
+	/* Tx stats */
+	u32 tx_timeout_count;
+	u32 tx_fifo_head;
+	u32 tx_head_addr;
+	u32 tx_fifo_size;
+	u32 tx_dma_failed;
+
+	/*
+	 * Rx
+	 */
+	struct igbvf_ring *rx_ring;
+
+	/* Rx stats */
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+	u64 rx_hdr_split;
+	u32 alloc_rx_buff_failed;
+	u32 rx_dma_failed;
+
+	unsigned int rx_ps_hdr_size;
+	u32 max_frame_size;
+	u32 min_frame_size;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+	spinlock_t stats_lock;      /* prevent concurrent stats updates */
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+
+	/* The VF counters don't clear on read so we have to get a base
+	 * count on driver start up and always subtract that base on
+	 * on the first update, thus the flag..
+	 */
+	struct e1000_vf_stats stats;
+	u64 zero_base;
+
+	struct igbvf_ring test_tx_ring;
+	struct igbvf_ring test_rx_ring;
+	u32 test_icr;
+
+	u32 msg_enable;
+	struct msix_entry *msix_entries;
+	int int_mode;
+	u32 eims_enable_mask;
+	u32 eims_other;
+	u32 int_counter0;
+	u32 int_counter1;
+
+	u32 eeprom_wol;
+	u32 wol;
+	u32 pba;
+
+	bool fc_autoneg;
+
+	unsigned long led_status;
+
+	unsigned int flags;
+	unsigned long last_reset;
+	u32 *config_space;
+#endif
+        /* OS defined structs */
+        struct net_device *netdev;
+        struct pci_device *pdev;
+        struct net_device_stats net_stats;
+
+        /* structs defined in e1000_hw.h */
+        struct e1000_hw hw;
+
+        u32 min_frame_size;
+        u32 max_frame_size;
+
+        u32 max_hw_frame_size;
+
+#define NUM_TX_DESC     8
+#define NUM_RX_DESC     8
+
+        struct io_buffer *tx_iobuf[NUM_TX_DESC];
+        struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+        union e1000_adv_tx_desc *tx_base;
+        union e1000_adv_rx_desc *rx_base;
+
+        uint32_t tx_ring_size;
+        uint32_t rx_ring_size;
+
+        uint32_t tx_head;
+        uint32_t tx_tail;
+        uint32_t tx_fill_ctr;
+
+        uint32_t rx_curr;
+
+        uint32_t ioaddr;
+        uint32_t irqno;
+
+        uint32_t tx_int_delay;
+        uint32_t tx_abs_int_delay;
+        uint32_t txd_cmd;
+};
+
+struct igbvf_info {
+	enum e1000_mac_type	mac;
+	unsigned int		flags;
+	u32			pba;
+	void			(*init_ops)(struct e1000_hw *);
+	s32			(*get_variants)(struct igbvf_adapter *);
+};
+
+/* hardware capability, feature, and workaround flags */
+#define IGBVF_FLAG_RX_CSUM_DISABLED       (1 << 0)
+
+#define IGBVF_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IGBVF_RX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
+#define IGBVF_TX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
+#define IGBVF_TX_CTXTDESC_ADV(R, i)	    \
+	(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+
+enum igbvf_state_t {
+	__IGBVF_TESTING,
+	__IGBVF_RESETTING,
+	__IGBVF_DOWN
+};
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+extern char igbvf_driver_name[];
+extern const char igbvf_driver_version[];
+
+extern void igbvf_check_options(struct igbvf_adapter *adapter);
+extern void igbvf_set_ethtool_ops(struct net_device *netdev);
+#ifdef ETHTOOL_OPS_COMPAT
+extern int ethtool_ioctl(struct ifreq *ifr);
+#endif
+
+extern int igbvf_up(struct igbvf_adapter *adapter);
+extern void igbvf_down(struct igbvf_adapter *adapter);
+extern void igbvf_reinit_locked(struct igbvf_adapter *adapter);
+extern void igbvf_reset(struct igbvf_adapter *adapter);
+extern int igbvf_setup_rx_resources(struct igbvf_adapter *adapter);
+extern int igbvf_setup_tx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_free_rx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_free_tx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_update_stats(struct igbvf_adapter *adapter);
+extern void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter);
+extern void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter);
+
+extern unsigned int copybreak;
+
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
+{
+	return readl(hw->hw_addr + reg);
+}
+
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+	writel(val, hw->hw_addr + reg);
+}
+#define er32(reg)	E1000_READ_REG(hw, E1000_##reg)
+#define ew32(reg,val)	E1000_WRITE_REG(hw, E1000_##reg, (val))
+#define e1e_flush()	er32(STATUS)
+
+#endif /* _IGBVF_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_defines.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_defines.h
new file mode 100644
index 0000000..7cf4ddb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_defines.h
@@ -0,0 +1,1395 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGBVF_DEFINES_H_
+#define _IGBVF_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+#define E1000_WUS_ARP          E1000_WUFC_ARP
+#define E1000_WUS_IPV4         E1000_WUFC_IPV4
+#define E1000_WUS_IPV6         E1000_WUFC_IPV6
+#define E1000_WUS_FLX0         E1000_WUFC_FLX0
+#define E1000_WUS_FLX1         E1000_WUFC_FLX1
+#define E1000_WUS_FLX2         E1000_WUFC_FLX2
+#define E1000_WUS_FLX3         E1000_WUFC_FLX3
+#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
+#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
+                                                  * detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
+                                                  * error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_REG_ADDR         0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_PHY_ADDR         0x07000000
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_RESET            0x10000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK                 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x01
+#define E1000_SWFW_PHY0_SM  0x02
+#define E1000_SWFW_PHY1_SM  0x04
+#define E1000_SWFW_CSR_SM   0x08
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
+                                             * indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
+                                               * PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
+                                           * LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/*
+ * Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_CFG_PCS_EN             8
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_10            0
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
+#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_10          0
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
+                                                 * Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
+                                            * disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME   20
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+#define E1000_RFCTL_LEF                 0x00040000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE       4
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_SPD_EN             0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K  0x0006    /* 6KB */
+#define E1000_PBA_8K  0x0008    /* 8KB */
+#define E1000_PBA_10K 0x000A    /* 10KB */
+#define E1000_PBA_12K 0x000C    /* 12KB */
+#define E1000_PBA_14K 0x000E    /* 14KB */
+#define E1000_PBA_16K 0x0010    /* 16KB */
+#define E1000_PBA_18K 0x0012
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_26K 0x001A
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_35K 0x0023
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB */
+#define E1000_PBA_64K 0x0040    /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
+                                            * should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
+                                            * bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
+                                            * an interrupt */
+#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
+#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
+
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
+                                                         * parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
+                                                         * error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
+                                                         * parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX      15
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
+#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_CC         0x10000000        /* Receive config change */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
+
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
+#define E1000_GCR_CAP_VER2              0x00040000
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                           E1000_GCR_RXDSCW_NO_SNOOP      | \
+                           E1000_GCR_RXDSCR_NO_SNOOP      | \
+                           E1000_GCR_TXD_NO_SNOOP         | \
+                           E1000_GCR_TXDSCW_NO_SNOOP      | \
+                           E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Register */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+
+#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT                 0x0003
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_VERSION                0x0005
+#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
+#define NVM_PHY_CLASS_WORD         0x0007
+#define NVM_INIT_CONTROL1_REG      0x000A
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_FLASH_VERSION          0x0032
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+#define NVM_WORD0F_ANE              0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
+#define NVM_WORD0F_LPLU             0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_MAC_ADDR_OFFSET        0
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_RESERVED_WORD          0xFFFF
+#define NVM_PHY_CLASS_A            0x8000
+#define NVM_SERDES_AMPLITUDE_MASK  0x000F
+#define NVM_SIZE_MASK              0x1C00
+#define NVM_SIZE_SHIFT             10
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+#define NVM_SWDPIO_EXT_SHIFT       4
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+#define NVM_STATUS_WEN_SPI         0x02
+#define NVM_STATUS_BP0_SPI         0x04
+#define NVM_STATUS_BP1_SPI         0x08
+#define NVM_STATUS_WPEN_SPI        0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                              (ID_LED_OFF1_OFF2 <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+#define PCIE_DEVICE_CONTROL2         0x28
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+#define PCIE_DEVICE_CONTROL2_16ms    0x0005
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1011_I_REV_4     0x04
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+        GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS         \
+        GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE          \
+        GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2       \
+        GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR         \
+        GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT         \
+        GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+        GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+        GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL       \
+        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+        GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2     \
+        GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+        GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+        GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET          \
+        GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID         \
+        GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID           \
+        GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+        GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL     \
+        GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+        GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL           \
+        GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL         \
+        GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC     \
+        GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS        \
+        GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY         \
+        GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE       \
+        GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC           \
+        GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+#endif /* _IGBVF_DEFINES_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
new file mode 100644
index 0000000..1f7e1df
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
@@ -0,0 +1,954 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  Copyright(c) 2010 Eric Keller <ekeller at princeton.edu>
+  Copyright(c) 2010 Red Hat Inc.
+	Alex Williamson <alex.williamson at redhat.com>
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igbvf.h"
+
+/**
+ * igbvf_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v adapter   e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter )
+{
+	DBG ( "igbvf_setup_tx_resources\n" );
+
+	/* Allocate transmit descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata #23
+	   so we use malloc_dma() requesting a 128 byte block that is
+	   128 byte aligned. This should guarantee that the memory
+	   allocated will not cross a 64K boundary, because 128 is an
+	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
+	   allocations of 128 bytes on a 128 byte boundary will not
+	   cross 64K bytes.
+	 */
+
+	adapter->tx_base =
+		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
+
+	if ( ! adapter->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
+
+	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
+
+	return 0;
+}
+
+/**
+ * igbvf_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void igbvf_free_tx_resources ( struct igbvf_adapter *adapter )
+{
+	DBG ( "igbvf_free_tx_resources\n" );
+
+	free_dma ( adapter->tx_base, adapter->tx_ring_size );
+}
+
+/**
+ * igbvf_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+void igbvf_free_rx_resources ( struct igbvf_adapter *adapter )
+{
+	int i;
+
+	DBG ( "igbvf_free_rx_resources\n" );
+
+	free_dma ( adapter->rx_base, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		free_iob ( adapter->rx_iobuf[i] );
+	}
+}
+
+/**
+ * igbvf_refill_rx_ring - allocate Rx io_buffers
+ *
+ * @v adapter   e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int igbvf_refill_rx_ring ( struct igbvf_adapter *adapter )
+{
+	int i, rx_curr;
+	int rc = 0;
+	union e1000_adv_rx_desc *rx_curr_desc;
+	struct e1000_hw *hw = &adapter->hw;
+	struct io_buffer *iob;
+
+	DBGP ("igbvf_refill_rx_ring\n");
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
+		rx_curr_desc = adapter->rx_base + rx_curr;
+
+		if ( rx_curr_desc->wb.upper.status_error & E1000_RXD_STAT_DD )
+			continue;
+
+		if ( adapter->rx_iobuf[rx_curr] != NULL )
+			continue;
+
+		DBG2 ( "Refilling rx desc %d\n", rx_curr );
+
+		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+		adapter->rx_iobuf[rx_curr] = iob;
+
+		rx_curr_desc->wb.upper.status_error = 0;
+
+		if ( ! iob ) {
+			DBG ( "alloc_iob failed\n" );
+			rc = -ENOMEM;
+			break;
+		} else {
+			rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
+			rx_curr_desc->read.hdr_addr = 0;
+			ew32 ( RDT(0), rx_curr );
+		}
+	}
+	return rc;
+}
+
+/**
+ * igbvf_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static void igbvf_irq_disable ( struct igbvf_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	ew32 ( EIMC, ~0 );
+}
+
+/**
+ * igbvf_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static void igbvf_irq_enable ( struct igbvf_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	ew32 ( EIAC, IMS_ENABLE_MASK );
+	ew32 ( EIAM, IMS_ENABLE_MASK );
+	ew32 ( EIMS, IMS_ENABLE_MASK );
+}
+
+/**
+ * igbvf_irq - enable or Disable interrupts
+ *
+ * @v adapter   e1000 adapter
+ * @v action    requested interrupt action
+ **/
+static void igbvf_irq ( struct net_device *netdev, int enable )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+
+	DBG ( "igbvf_irq\n" );
+
+	if ( enable ) {
+		igbvf_irq_enable ( adapter );
+	} else {
+		igbvf_irq_disable ( adapter );
+	}
+}
+
+/**
+ * igbvf_process_tx_packets - process transmitted packets
+ *
+ * @v netdev    network interface device structure
+ **/
+static void igbvf_process_tx_packets ( struct net_device *netdev )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+	uint32_t i;
+	uint32_t tx_status;
+	union e1000_adv_tx_desc *tx_curr_desc;
+
+	/* Check status of transmitted packets
+	 */
+	DBGP ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
+	      adapter->tx_tail );
+
+	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
+
+		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
+					   ( i * sizeof ( *adapter->tx_base ) );
+
+		tx_status = tx_curr_desc->wb.status;
+		DBG ( "  tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+		DBG ( "  tx_status = %#08x\n", tx_status );
+
+		/* if the packet at tx_head is not owned by hardware it is for us */
+		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
+			break;
+
+		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
+		      adapter->tx_head, adapter->tx_tail, tx_status );
+
+		netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
+		DBG ( "Success transmitting packet, tx_status: %#08x\n",
+		      tx_status );
+
+		/* Decrement count of used descriptors, clear this descriptor
+		 */
+		adapter->tx_fill_ctr--;
+		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
+	}
+}
+
+/**
+ * igbvf_process_rx_packets - process received packets
+ *
+ * @v netdev    network interface device structure
+ **/
+static void igbvf_process_rx_packets ( struct net_device *netdev )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t i;
+	uint32_t rx_status;
+	uint32_t rx_len;
+	uint32_t rx_err;
+	union e1000_adv_rx_desc *rx_curr_desc;
+
+	DBGP ( "igbvf_process_rx_packets\n" );
+
+	/* Process received packets
+	 */
+	while ( 1 ) {
+		i = adapter->rx_curr;
+
+		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+				  ( i * sizeof ( *adapter->rx_base ) );
+		rx_status = rx_curr_desc->wb.upper.status_error;
+
+		DBG2 ( "Before DD Check RX_status: %#08x, rx_curr: %d\n",
+		       rx_status, i );
+
+		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+			break;
+
+		if ( adapter->rx_iobuf[i] == NULL )
+			break;
+
+		DBG ( "E1000_RCTL = %#08x\n", er32 (RCTL) );
+
+		rx_len = rx_curr_desc->wb.upper.length;
+
+		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
+		      i, rx_status, rx_len );
+
+		rx_err = rx_status;
+
+		iob_put ( adapter->rx_iobuf[i], rx_len );
+
+		if ( rx_err & E1000_RXDEXT_ERR_FRAME_ERR_MASK ) {
+
+			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
+			DBG ( "igbvf_process_rx_packets: Corrupted packet received!"
+			      " rx_err: %#08x\n", rx_err );
+		} else  {
+			/* Add this packet to the receive queue. */
+			netdev_rx ( netdev, adapter->rx_iobuf[i] );
+		}
+		adapter->rx_iobuf[i] = NULL;
+
+		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
+	}
+}
+
+/**
+ * igbvf_poll - Poll for received packets
+ *
+ * @v netdev    Network device
+ */
+static void igbvf_poll ( struct net_device *netdev )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+	uint32_t rx_status;
+	union e1000_adv_rx_desc *rx_curr_desc;
+
+	DBGP ( "igbvf_poll\n" );
+
+	rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+			( adapter->rx_curr * sizeof ( *adapter->rx_base ) );
+	rx_status = rx_curr_desc->wb.upper.status_error;
+
+	if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+		return;
+
+	igbvf_process_tx_packets ( netdev );
+
+	igbvf_process_rx_packets ( netdev );
+
+	igbvf_refill_rx_ring ( adapter );
+}
+
+/**
+ *  igbvf_config_collision_dist_generic - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igbvf_config_collision_dist ( struct e1000_hw *hw )
+{
+	u32 tctl;
+
+	DBG ("igbvf_config_collision_dist");
+
+	tctl = er32 (TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	ew32 (TCTL, tctl);
+	e1e_flush();
+}
+
+/**
+ * igbvf_configure_tx - Configure Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void igbvf_configure_tx ( struct igbvf_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tctl, txdctl;
+
+	DBG ( "igbvf_configure_tx\n" );
+
+	/* disable transmits while setting up the descriptors */
+	tctl = er32 ( TCTL );
+	ew32 ( TCTL, tctl & ~E1000_TCTL_EN );
+	e1e_flush();
+	mdelay (10);
+
+	ew32 ( TDBAH(0), 0 );
+	ew32 ( TDBAL(0), virt_to_bus ( adapter->tx_base ) );
+	ew32 ( TDLEN(0), adapter->tx_ring_size );
+
+	DBG ( "E1000_TDBAL(0): %#08x\n",  er32 ( TDBAL(0) ) );
+	DBG ( "E1000_TDLEN(0): %d\n",     er32 ( TDLEN(0) ) );
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	ew32 ( TDH(0), 0 );
+	ew32 ( TDT(0), 0 );
+
+	adapter->tx_head = 0;
+	adapter->tx_tail = 0;
+	adapter->tx_fill_ctr = 0;
+
+	txdctl = er32(TXDCTL(0));
+	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+	ew32 ( TXDCTL(0), txdctl );
+
+	txdctl = er32 ( TXDCTL(0) );
+	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+	ew32 ( TXDCTL(0), txdctl );
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	adapter->txd_cmd  = E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_IFCS;
+
+	/* Advanced descriptor */
+	adapter->txd_cmd |= E1000_ADVTXD_DCMD_DEXT;
+
+	/* (not part of cmd, but in same 32 bit word...) */
+	adapter->txd_cmd |= E1000_ADVTXD_DTYP_DATA;
+
+	/* enable Report Status bit */
+	adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS;
+
+	/* Program the Transmit Control Register */
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	igbvf_config_collision_dist ( hw );
+
+	/* Enable transmits */
+	tctl |= E1000_TCTL_EN;
+	ew32(TCTL, tctl);
+	e1e_flush();
+}
+
+/* igbvf_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for Rx, Tx etc.
+ */
+void igbvf_reset ( struct igbvf_adapter *adapter )
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* Allow time for pending master requests to run */
+	if ( mac->ops.reset_hw(hw) )
+		DBG ("PF still resetting\n");
+
+	mac->ops.init_hw ( hw );
+
+	if ( is_valid_ether_addr(adapter->hw.mac.addr) ) {
+		memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
+	}
+}
+
+extern void igbvf_init_function_pointers_vf(struct e1000_hw *hw);
+
+/**
+ * igbvf_sw_init - Initialize general software structures (struct igbvf_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igbvf_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit igbvf_sw_init ( struct igbvf_adapter *adapter )
+{
+        struct e1000_hw *hw = &adapter->hw;
+        struct pci_device *pdev = adapter->pdev;
+        int rc;
+
+        /* PCI config space info */
+
+        hw->vendor_id = pdev->vendor;
+        hw->device_id = pdev->device;
+
+        pci_read_config_byte ( pdev, PCI_REVISION_ID, &hw->revision_id );
+
+        pci_read_config_word ( pdev, PCI_COMMAND, &hw->bus.pci_cmd_word );
+
+        adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN;
+        adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	/* Set various function pointers */
+        igbvf_init_function_pointers_vf ( &adapter->hw );
+
+	rc = adapter->hw.mac.ops.init_params ( &adapter->hw );
+	if (rc) {
+                DBG ("hw.mac.ops.init_params(&adapter->hw) Failure\n");
+		return rc;
+        }
+
+	rc = adapter->hw.mbx.ops.init_params ( &adapter->hw );
+	if (rc) {
+                DBG ("hw.mbx.ops.init_params(&adapter->hw) Failure\n");
+		return rc;
+        }
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	igbvf_irq_disable ( adapter );
+
+	return 0;
+}
+
+/**
+ * igbvf_setup_srrctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+static void igbvf_setup_srrctl ( struct igbvf_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 srrctl = 0;
+
+	DBG ( "igbvf_setup_srrctl\n" );
+
+	srrctl &= ~(E1000_SRRCTL_DESCTYPE_MASK |
+		    E1000_SRRCTL_BSIZEHDR_MASK |
+		    E1000_SRRCTL_BSIZEPKT_MASK);
+
+	/* Enable queue drop to avoid head of line blocking */
+	srrctl |= E1000_SRRCTL_DROP_EN;
+
+	/* Setup buffer sizes */
+        srrctl |= 2048 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+	srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+	ew32 ( SRRCTL(0), srrctl );
+}
+
+/**
+ * igbvf_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void igbvf_configure_rx ( struct igbvf_adapter *adapter )
+{
+        struct e1000_hw *hw = &adapter->hw;
+        u32 rxdctl;
+
+	DBG ( "igbvf_configure_rx\n" );
+
+        /* disable receives */
+        rxdctl = er32 ( RXDCTL(0) );
+        ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
+        msleep ( 10 );
+
+        /*
+         * Setup the HW Rx Head and Tail Descriptor Pointers and
+         * the Base and Length of the Rx Descriptor Ring
+         */
+        ew32 ( RDBAL(0), virt_to_bus (adapter->rx_base) );
+        ew32 ( RDBAH(0), 0 );
+        ew32 ( RDLEN(0), adapter->rx_ring_size );
+	adapter->rx_curr = 0;
+        ew32 ( RDH(0), 0 );
+        ew32 ( RDT(0), 0 );
+
+        rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+        rxdctl &= 0xFFF00000;
+        rxdctl |= IGBVF_RX_PTHRESH;
+        rxdctl |= IGBVF_RX_HTHRESH << 8;
+        rxdctl |= IGBVF_RX_WTHRESH << 16;
+
+        igbvf_rlpml_set_vf ( hw, adapter->max_frame_size );
+
+        /* enable receives */
+        ew32 ( RXDCTL(0), rxdctl );
+        ew32 ( RDT(0), NUM_RX_DESC );
+}
+
+/**
+ * igbvf_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v adapter   e1000 private structure
+ **/
+int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter )
+{
+	int i;
+	union e1000_adv_rx_desc *rx_curr_desc;
+        struct io_buffer *iob;
+
+	DBG ( "igbvf_setup_rx_resources\n" );
+
+	/* Allocate receive descriptor ring memory.
+	   It must not cross a 64K boundary because of hardware errata
+	 */
+
+	adapter->rx_base =
+		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
+
+	if ( ! adapter->rx_base ) {
+		return -ENOMEM;
+	}
+	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+                rx_curr_desc = adapter->rx_base + i;
+                iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+                adapter->rx_iobuf[i] = iob;
+                rx_curr_desc->wb.upper.status_error = 0;
+                if ( ! iob ) {
+                        DBG ( "alloc_iob failed\n" );
+                        return -ENOMEM;
+                } else {
+                        rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
+                        rx_curr_desc->read.hdr_addr = 0;
+                }
+	}
+
+	return 0;
+}
+
+/**
+ * igbvf_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int igbvf_open ( struct net_device *netdev )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+	int err;
+
+	DBG ("igbvf_open\n");
+
+	/* allocate transmit descriptors */
+	err = igbvf_setup_tx_resources ( adapter );
+	if (err) {
+		DBG ( "Error setting up TX resources!\n" );
+		goto err_setup_tx;
+	}
+
+	igbvf_configure_tx ( adapter );
+
+	igbvf_setup_srrctl( adapter );
+
+	err = igbvf_setup_rx_resources( adapter );
+	if (err) {
+		DBG ( "Error setting up RX resources!\n" );
+		goto err_setup_rx;
+	}
+
+	igbvf_configure_rx ( adapter );
+
+	return 0;
+
+err_setup_rx:
+	DBG ( "err_setup_rx\n" );
+	igbvf_free_tx_resources ( adapter );
+	return err;
+
+err_setup_tx:
+	DBG ( "err_setup_tx\n" );
+	igbvf_reset ( adapter );
+
+	return err;
+}
+
+/**
+ * igbvf_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static void igbvf_close ( struct net_device *netdev )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+        struct e1000_hw *hw = &adapter->hw;
+        uint32_t rxdctl;
+
+        DBG ( "igbvf_close\n" );
+
+	/* Disable and acknowledge interrupts */
+        igbvf_irq_disable ( adapter );
+        er32(EICR);
+
+        /* disable receives */
+        rxdctl = er32 ( RXDCTL(0) );
+        ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
+        mdelay ( 10 );
+
+        igbvf_reset ( adapter );
+
+	igbvf_free_tx_resources( adapter );
+	igbvf_free_rx_resources( adapter );
+}
+
+/**
+ * igbvf_transmit - Transmit a packet
+ *
+ * @v netdev    Network device
+ * @v iobuf     I/O buffer
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ */
+static int igbvf_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+	struct e1000_hw *hw = &adapter->hw;
+	uint32_t tx_curr = adapter->tx_tail;
+	union e1000_adv_tx_desc *tx_curr_desc;
+
+	DBGP ("igbvf_transmit\n");
+
+	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Save pointer to iobuf we have been given to transmit,
+	   netdev_tx_complete() will need it later
+	 */
+	adapter->tx_iobuf[tx_curr] = iobuf;
+
+	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
+		       ( tx_curr * sizeof ( *adapter->tx_base ) );
+
+	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
+	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+
+	/* Add the packet to TX ring
+	 */
+	tx_curr_desc->read.buffer_addr = virt_to_bus ( iobuf->data );
+	tx_curr_desc->read.cmd_type_len = adapter->txd_cmd |(iob_len ( iobuf )) ;
+	// minus hdr_len ????
+	tx_curr_desc->read.olinfo_status = ((iob_len ( iobuf )) << E1000_ADVTXD_PAYLEN_SHIFT);
+
+	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+
+	/* Point to next free descriptor */
+	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
+	adapter->tx_fill_ctr++;
+
+	/* Write new tail to NIC, making packet available for transmit
+	 */
+	ew32 ( TDT(0), adapter->tx_tail );
+	e1e_flush ();
+
+	return 0;
+}
+
+/** igbvf net device operations */
+static struct net_device_operations igbvf_operations = {
+	.open		= igbvf_open,
+	.close		= igbvf_close,
+	.transmit	= igbvf_transmit,
+	.poll		= igbvf_poll,
+	.irq		= igbvf_irq,
+};
+
+/**
+ * igbvf_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ *
+ **/
+void igbvf_get_hw_control ( struct igbvf_adapter *adapter )
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+
+	/* Let firmware know the driver has taken over */
+	ctrl_ext = er32 ( CTRL_EXT );
+	ew32 ( CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD );
+}
+
+/**
+ * igbvf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igbvf_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * igbvf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+int igbvf_probe ( struct pci_device *pdev )
+{
+	int err;
+	struct net_device *netdev;
+	struct igbvf_adapter *adapter;
+	unsigned long mmio_start, mmio_len;
+	struct e1000_hw *hw;
+
+        DBG ( "igbvf_probe\n" );
+
+	err = -ENOMEM;
+
+	/* Allocate net device ( also allocates memory for netdev->priv
+	  and makes netdev-priv point to it ) */
+	netdev = alloc_etherdev ( sizeof ( struct igbvf_adapter ) );
+	if ( ! netdev )
+		goto err_alloc_etherdev;
+
+	/* Associate igbvf-specific network operations operations with
+	 * generic network device layer */
+	netdev_init ( netdev, &igbvf_operations );
+
+	/* Associate this network device with given PCI device */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Initialize driver private storage */
+	adapter = netdev_priv ( netdev );
+	memset ( adapter, 0, ( sizeof ( *adapter ) ) );
+
+	adapter->pdev = pdev;
+
+	adapter->ioaddr = pdev->ioaddr;
+	adapter->hw.io_base = pdev->ioaddr;
+
+	hw = &adapter->hw;
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+
+	adapter->irqno = pdev->irq;
+	adapter->netdev = netdev;
+	adapter->hw.back = adapter;
+
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+	adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
+	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pdev );
+
+	err = -EIO;
+
+	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
+	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
+
+	DBG ( "mmio_start: %#08lx\n", mmio_start );
+	DBG ( "mmio_len: %#08lx\n", mmio_len );
+
+	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
+	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
+
+	if ( ! adapter->hw.hw_addr ) {
+		DBG ( "err_ioremap\n" );
+		goto err_ioremap;
+	}
+
+	/* setup adapter struct */
+	err = igbvf_sw_init ( adapter );
+	if (err) {
+		DBG ( "err_sw_init\n" );
+		goto err_sw_init;
+	}
+
+	/* reset the controller to put the device in a known good state */
+	err = hw->mac.ops.reset_hw ( hw );
+	if ( err ) {
+		DBG ("PF still in reset state, assigning new address\n");
+		netdev->hw_addr[0] = 0x21;
+		netdev->hw_addr[1] = 0x21;
+		netdev->hw_addr[2] = 0x21;
+		netdev->hw_addr[3] = 0x21;
+		netdev->hw_addr[4] = 0x21;
+		netdev->hw_addr[5] = 0x21;
+		netdev->hw_addr[6] = 0x21;
+	} else {
+		err = hw->mac.ops.read_mac_addr(hw);
+		if (err) {
+			DBG ("Error reading MAC address\n");
+			goto err_hw_init;
+		}
+	}
+
+	memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
+
+	if ( ! is_valid_ether_addr( netdev->hw_addr ) ) {
+		DBG ("Invalid MAC Address: "
+		        "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		        netdev->hw_addr[0], netdev->hw_addr[1],
+		        netdev->hw_addr[2], netdev->hw_addr[3],
+		        netdev->hw_addr[4], netdev->hw_addr[5]);
+		err = -EIO;
+		goto err_hw_init;
+	}
+
+	/* reset the hardware with the new settings */
+	igbvf_reset ( adapter );
+
+	/* let the f/w know that the h/w is now under the control of the
+	 * driver. */
+	igbvf_get_hw_control ( adapter );
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	if ( ( err = register_netdev ( netdev ) ) != 0) {
+		DBG ( "err_register\n" );
+		goto err_register;
+	}
+
+	DBG ("igbvf_probe_succeeded\n");
+
+	return 0;
+
+err_register:
+err_hw_init:
+err_sw_init:
+	iounmap ( adapter->hw.hw_addr );
+err_ioremap:
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return err;
+}
+
+/**
+ * igbvf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * igbvf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+void igbvf_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct igbvf_adapter *adapter = netdev_priv ( netdev );
+
+	DBG ( "igbvf_remove\n" );
+
+	if ( adapter->hw.flash_address )
+		iounmap ( adapter->hw.flash_address );
+	if  ( adapter->hw.hw_addr )
+		iounmap ( adapter->hw.hw_addr );
+
+	unregister_netdev ( netdev );
+	igbvf_reset  ( adapter );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id igbvf_pci_tbl[] = {
+	PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0)
+};
+
+
+struct pci_driver igbvf_driver __pci_driver = {
+	.ids = igbvf_pci_tbl,
+	.id_count = (sizeof(igbvf_pci_tbl) / sizeof(igbvf_pci_tbl[0])),
+	.probe = igbvf_probe,
+	.remove = igbvf_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.c
new file mode 100644
index 0000000..6580938
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.c
@@ -0,0 +1,404 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igbvf_mbx.h"
+
+/**
+ *  igbvf_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+static s32 igbvf_poll_for_msg(struct e1000_hw *hw, u16 mbx_id)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	DEBUGFUNC("igbvf_poll_for_msg");
+
+	if (!countdown || !mbx->ops.check_for_msg)
+		goto out;
+
+	while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
+		countdown--;
+		if (!countdown)
+			break;
+		usec_delay(mbx->usec_delay);
+	}
+
+	/* if we failed, all future posted messages fail until reset */
+	if (!countdown)
+		mbx->timeout = 0;
+out:
+	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
+}
+
+/**
+ *  igbvf_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgement
+ **/
+static s32 igbvf_poll_for_ack(struct e1000_hw *hw, u16 mbx_id)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	DEBUGFUNC("igbvf_poll_for_ack");
+
+	if (!countdown || !mbx->ops.check_for_ack)
+		goto out;
+
+	while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
+		countdown--;
+		if (!countdown)
+			break;
+		usec_delay(mbx->usec_delay);
+	}
+
+	/* if we failed, all future posted messages fail until reset */
+	if (!countdown)
+		mbx->timeout = 0;
+out:
+	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
+}
+
+/**
+ *  igbvf_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+static s32 igbvf_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
+                                 u16 mbx_id)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_read_posted_mbx");
+
+	if (!mbx->ops.read)
+		goto out;
+
+	ret_val = igbvf_poll_for_msg(hw, mbx_id);
+
+	/* if ack received read message, otherwise we timed out */
+	if (!ret_val)
+		ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+out:
+	return ret_val;
+}
+
+/**
+ *  igbvf_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+static s32 igbvf_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
+                                  u16 mbx_id)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_write_posted_mbx");
+
+	/* exit if either we can't write or there isn't a defined timeout */
+	if (!mbx->ops.write || !mbx->timeout)
+		goto out;
+
+	/* send msg */
+	ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+	/* if msg sent wait until we receive an ack */
+	if (!ret_val)
+		ret_val = igbvf_poll_for_ack(hw, mbx_id);
+out:
+	return ret_val;
+}
+
+/**
+ *  igbvf_init_mbx_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void igbvf_init_mbx_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	mbx->ops.read_posted = igbvf_read_posted_mbx;
+	mbx->ops.write_posted = igbvf_write_posted_mbx;
+}
+
+/**
+ *  igbvf_read_v2p_mailbox - read v2p mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  This function is used to read the v2p mailbox without losing the read to
+ *  clear status bits.
+ **/
+static u32 igbvf_read_v2p_mailbox(struct e1000_hw *hw)
+{
+	u32 v2p_mailbox = E1000_READ_REG(hw, E1000_V2PMAILBOX(0));
+
+	v2p_mailbox |= hw->dev_spec.vf.v2p_mailbox;
+	hw->dev_spec.vf.v2p_mailbox |= v2p_mailbox & E1000_V2PMAILBOX_R2C_BITS;
+
+	return v2p_mailbox;
+}
+
+/**
+ *  igbvf_check_for_bit_vf - Determine if a status bit was set
+ *  @hw: pointer to the HW structure
+ *  @mask: bitmask for bits to be tested and cleared
+ *
+ *  This function is used to check for the read to clear bits within
+ *  the V2P mailbox.
+ **/
+static s32 igbvf_check_for_bit_vf(struct e1000_hw *hw, u32 mask)
+{
+	u32 v2p_mailbox = igbvf_read_v2p_mailbox(hw);
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (v2p_mailbox & mask)
+		ret_val = E1000_SUCCESS;
+
+	hw->dev_spec.vf.v2p_mailbox &= ~mask;
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_check_for_msg_vf - checks to see if the PF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the Status bit or else ERR_MBX
+ **/
+static s32 igbvf_check_for_msg_vf(struct e1000_hw *hw, u16 mbx_id __unused)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_check_for_msg_vf");
+
+	if (!igbvf_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFSTS)) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.reqs++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_check_for_ack_vf - checks to see if the PF has ACK'd
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
+ **/
+static s32 igbvf_check_for_ack_vf(struct e1000_hw *hw, u16 mbx_id __unused)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_check_for_ack_vf");
+
+	if (!igbvf_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFACK)) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.acks++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_check_for_rst_vf - checks to see if the PF has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns true if the PF has set the reset done bit or else false
+ **/
+static s32 igbvf_check_for_rst_vf(struct e1000_hw *hw, u16 mbx_id __unused)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_check_for_rst_vf");
+
+	if (!igbvf_check_for_bit_vf(hw, (E1000_V2PMAILBOX_RSTD |
+	                                 E1000_V2PMAILBOX_RSTI))) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.rsts++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_obtain_mbx_lock_vf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+static s32 igbvf_obtain_mbx_lock_vf(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	DEBUGFUNC("igbvf_obtain_mbx_lock_vf");
+
+	/* Take ownership of the buffer */
+	E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
+
+	/* reserve mailbox for vf use */
+	if (igbvf_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU)
+		ret_val = E1000_SUCCESS;
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_write_mbx_vf - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+static s32 igbvf_write_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size,
+                              u16 mbx_id __unused)
+{
+	s32 ret_val;
+	u16 i;
+
+
+	DEBUGFUNC("igbvf_write_mbx_vf");
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	ret_val = igbvf_obtain_mbx_lock_vf(hw);
+	if (ret_val)
+		goto out_no_write;
+
+	/* flush msg and acks as we are overwriting the message buffer */
+	igbvf_check_for_msg_vf(hw, 0);
+	igbvf_check_for_ack_vf(hw, 0);
+
+	/* copy the caller specified message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_VMBMEM(0), i, msg[i]);
+
+	/* update stats */
+	hw->mbx.stats.msgs_tx++;
+
+	/* Drop VFU and interrupt the PF to tell it a message has been sent */
+	E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_REQ);
+
+out_no_write:
+	return ret_val;
+}
+
+/**
+ *  igbvf_read_mbx_vf - Reads a message from the inbox intended for vf
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+static s32 igbvf_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size,
+                             u16 mbx_id __unused)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	DEBUGFUNC("igbvf_read_mbx_vf");
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	ret_val = igbvf_obtain_mbx_lock_vf(hw);
+	if (ret_val)
+		goto out_no_read;
+
+	/* copy the message from the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		msg[i] = E1000_READ_REG_ARRAY(hw, E1000_VMBMEM(0), i);
+
+	/* Acknowledge receipt and release mailbox, then we're done */
+	E1000_WRITE_REG(hw, E1000_V2PMAILBOX(0), E1000_V2PMAILBOX_ACK);
+
+	/* update stats */
+	hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+	return ret_val;
+}
+
+/**
+ *  igbvf_init_mbx_params_vf - set initial values for vf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+s32 igbvf_init_mbx_params_vf(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+
+	/* start mailbox as timed out and let the reset_hw call set the timeout
+	 * value to begin communications */
+	mbx->timeout = 0;
+	mbx->usec_delay = E1000_VF_MBX_INIT_DELAY;
+
+	mbx->size = E1000_VFMAILBOX_SIZE;
+
+	mbx->ops.read = igbvf_read_mbx_vf;
+	mbx->ops.write = igbvf_write_mbx_vf;
+	mbx->ops.read_posted = igbvf_read_posted_mbx;
+	mbx->ops.write_posted = igbvf_write_posted_mbx;
+	mbx->ops.check_for_msg = igbvf_check_for_msg_vf;
+	mbx->ops.check_for_ack = igbvf_check_for_ack_vf;
+	mbx->ops.check_for_rst = igbvf_check_for_rst_vf;
+
+	mbx->stats.msgs_tx = 0;
+	mbx->stats.msgs_rx = 0;
+	mbx->stats.reqs = 0;
+	mbx->stats.acks = 0;
+	mbx->stats.rsts = 0;
+
+	return E1000_SUCCESS;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.h
new file mode 100644
index 0000000..c21af6c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_mbx.h
@@ -0,0 +1,87 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGBVF_MBX_H_
+#define _IGBVF_MBX_H_
+
+#include "igbvf_vf.h"
+
+/* Define mailbox specific registers */
+#define E1000_V2PMAILBOX(_n)   (0x00C40 + (4 * (_n)))
+#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
+
+/* Define mailbox register bits */
+#define E1000_V2PMAILBOX_REQ   0x00000001 /* Request for PF Ready bit */
+#define E1000_V2PMAILBOX_ACK   0x00000002 /* Ack PF message received */
+#define E1000_V2PMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */
+#define E1000_V2PMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */
+#define E1000_V2PMAILBOX_RSTI  0x00000040 /* PF has reset indication */
+#define E1000_V2PMAILBOX_RSTD  0x00000080 /* PF has indicated reset done */
+#define E1000_V2PMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
+
+#define E1000_VFMAILBOX_SIZE   16 /* 16 32 bit words - 64 bytes */
+
+/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is E1000_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define E1000_VT_MSGTYPE_ACK      0x80000000  /* Messages below or'd with
+                                               * this are the ACK */
+#define E1000_VT_MSGTYPE_NACK     0x40000000  /* Messages below or'd with
+                                               * this are the NACK */
+#define E1000_VT_MSGTYPE_CTS      0x20000000  /* Indicates that VF is still
+                                                 clear to send requests */
+#define E1000_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define E1000_VT_MSGINFO_MASK     (0xFF << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_VF_RESET            0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR     0x02 /* VF requests to set MAC addr */
+#define E1000_VF_SET_MULTICAST    0x03 /* VF requests to set MC addr */
+#define E1000_VF_SET_MULTICAST_COUNT_MASK (0x1F << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_MULTICAST_OVERFLOW   (0x80 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_VLAN         0x04 /* VF requests to set VLAN */
+#define E1000_VF_SET_VLAN_ADD             (0x01 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_LPE          0x05 /* VF requests to set VMOLR.LPE */
+#define E1000_VF_SET_PROMISC      0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
+#define E1000_VF_SET_PROMISC_UNICAST      (0x01 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_PROMISC_MULTICAST    (0x02 << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
+#define E1000_VF_MBX_INIT_DELAY   500  /* microseconds between retries */
+
+void igbvf_init_mbx_ops_generic(struct e1000_hw *hw);
+s32 igbvf_init_mbx_params_vf(struct e1000_hw *);
+
+#endif /* _IGBVF_MBX_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h
new file mode 100644
index 0000000..259b9ec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h
@@ -0,0 +1,121 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* glue for the OS-dependent part of igbvf
+ * includes register access macros
+ */
+
+#ifndef _IGBVF_OSDEP_H_
+#define _IGBVF_OSDEP_H_
+
+#define u8         unsigned char
+#define bool       boolean_t
+#define dma_addr_t unsigned long
+#define __le16     uint16_t
+#define __le32     uint32_t
+#define __le64     uint64_t
+
+#define __iomem
+#define __devinit
+#define ____cacheline_aligned_in_smp
+
+#define msleep(x) mdelay(x)
+
+#define ETH_FCS_LEN 4
+
+typedef int spinlock_t;
+typedef enum {
+    false = 0,
+    true = 1
+} boolean_t;
+
+#define TRUE  1
+#define FALSE 0
+
+#define usec_delay(x) udelay(x)
+#define msec_delay(x) mdelay(x)
+#define msec_delay_irq(x) mdelay(x)
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+#define ETH_ADDR_LEN           ETH_ALEN
+
+
+#define DEBUGOUT(S) if (0) { printf(S); }
+#define DEBUGOUT1(S, A...) if (0) { printf(S, A); }
+
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+#define E1000_WRITE_REG(a, reg, value) do { \
+    writel((value), ((a)->hw_addr + reg)); } while (0)
+
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) do { \
+    writel((value), ((a)->hw_addr + reg + ((offset) << 2))); } while (0)
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+    writew((value), ((a)->hw_addr + reg + ((offset) << 1))))
+
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+    readw((a)->hw_addr + reg + ((offset) << 1)))
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+    writeb((value), ((a)->hw_addr + reg + (offset))))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+    readb((a)->hw_addr + reg + (offset)))
+
+#define E1000_WRITE_REG_IO(a, reg, offset) do { \
+    outl(reg, ((a)->io_base));                  \
+    outl(offset, ((a)->io_base + 4));      } while(0)
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
+
+#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
+    writel((value), ((a)->flash_address + reg)))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
+    writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
+
+#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
+
+#endif /* _IGBVF_OSDEP_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_regs.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_regs.h
new file mode 100644
index 0000000..21603d3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_regs.h
@@ -0,0 +1,338 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGBVF_REGS_H_
+#define _IGBVF_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C  /* Future Extended - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* Rx Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
+#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
+#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
+#define E1000_RXCTL(_n)   (0x0C014 + (0x40 * (_n)))
+#define E1000_RQDPC(_n)   (0x0C030 + (0x40 * (_n)))
+#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
+#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+                                         (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+                                         (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+                                         (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
+                                         (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+                                         (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+                                         (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+                                         (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+                                         (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+                                         (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+                                         (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+                                         (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+                                         (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+                                         (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n)       (0x03840 + (_n << 8))
+#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
+#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
+                                         (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
+                                         (0x0E03C + ((_n) * 0x40)))
+#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                                       (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                                       (0x054E4 + ((_i - 16) * 8)))
+#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
+#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
+#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
+#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+
+#define E1000_VFGPRC   0x00F10
+#define E1000_VFGORC   0x00F18
+#define E1000_VFMPRC   0x00F3C
+#define E1000_VFGPTC   0x00F14
+#define E1000_VFGOTC   0x00F34
+#define E1000_VFGOTLBC 0x00F50
+#define E1000_VFGPTLBC 0x00F44
+#define E1000_VFGORLBC 0x00F48
+#define E1000_VFGPRLBC 0x00F40
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
+#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA      0x0003C /* PHY address - RW */
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR         0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
+                                                    * (_i) - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * low reg - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
+                                                       * upper reg - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * message reg - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
+                                                       * vector ctrl reg - RW */
+#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+
+#endif /* _IGBVF_REGS_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.c
new file mode 100644
index 0000000..f2dac8b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.c
@@ -0,0 +1,455 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igbvf_vf.h"
+
+
+static s32       igbvf_init_mac_params_vf(struct e1000_hw *hw);
+static s32       igbvf_check_for_link_vf(struct e1000_hw *hw);
+static s32       igbvf_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex);
+static s32       igbvf_init_hw_vf(struct e1000_hw *hw);
+static s32       igbvf_reset_hw_vf(struct e1000_hw *hw);
+static void      igbvf_update_mc_addr_list_vf(struct e1000_hw *hw, u8 *, u32);
+static void      igbvf_rar_set_vf(struct e1000_hw *, u8 *, u32);
+static s32       igbvf_read_mac_addr_vf(struct e1000_hw *);
+
+/**
+ *  igbvf_init_mac_params_vf - Inits MAC params
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igbvf_init_mac_params_vf(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("igbvf_init_mac_params_vf");
+
+	/* VF's have no MTA Registers - PF feature only */
+	mac->mta_reg_count = 128;
+	/* VF's have no access to RAR entries  */
+	mac->rar_entry_count = 1;
+
+	/* Function pointers */
+	/* reset */
+	mac->ops.reset_hw = igbvf_reset_hw_vf;
+	/* hw initialization */
+	mac->ops.init_hw = igbvf_init_hw_vf;
+	/* check for link */
+	mac->ops.check_for_link = igbvf_check_for_link_vf;
+	/* link info */
+	mac->ops.get_link_up_info = igbvf_get_link_up_info_vf;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = igbvf_update_mc_addr_list_vf;
+	/* set mac address */
+	mac->ops.rar_set = igbvf_rar_set_vf;
+	/* read mac address */
+	mac->ops.read_mac_addr = igbvf_read_mac_addr_vf;
+
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igbvf_init_function_pointers_vf - Inits function pointers
+ *  @hw: pointer to the HW structure
+ **/
+void igbvf_init_function_pointers_vf(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igbvf_init_function_pointers_vf");
+
+	hw->mac.ops.init_params = igbvf_init_mac_params_vf;
+	hw->mbx.ops.init_params = igbvf_init_mbx_params_vf;
+}
+
+/**
+ *  igbvf_get_link_up_info_vf - Gets link info.
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to 16 bit value to store link speed.
+ *  @duplex: pointer to 16 bit value to store duplex.
+ *
+ *  Since we cannot read the PHY and get accurate link info, we must rely upon
+ *  the status register's data which is often stale and inaccurate.
+ **/
+static s32 igbvf_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
+                                     u16 *duplex)
+{
+	s32 status;
+
+	DEBUGFUNC("igbvf_get_link_up_info_vf");
+
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		DEBUGOUT("1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		DEBUGOUT("100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		DEBUGOUT("10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igbvf_reset_hw_vf - Resets the HW
+ *  @hw: pointer to the HW structure
+ *
+ *  VF's provide a function level reset. This is done using bit 26 of ctrl_reg.
+ *  This is all the reset we can perform on a VF.
+ **/
+static s32 igbvf_reset_hw_vf(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 timeout = E1000_VF_INIT_TIMEOUT;
+	s32 ret_val = -E1000_ERR_MAC_INIT;
+	u32 ctrl, msgbuf[3];
+	u8 *addr = (u8 *)(&msgbuf[1]);
+
+	DEBUGFUNC("igbvf_reset_hw_vf");
+
+	DEBUGOUT("Issuing a function level reset to MAC\n");
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	/* we cannot reset while the RSTI / RSTD bits are asserted */
+	while (!mbx->ops.check_for_rst(hw, 0) && timeout) {
+		timeout--;
+		usec_delay(5);
+	}
+
+	if (timeout) {
+		/* mailbox timeout can now become active */
+		mbx->timeout = E1000_VF_MBX_INIT_TIMEOUT;
+
+		msgbuf[0] = E1000_VF_RESET;
+		mbx->ops.write_posted(hw, msgbuf, 1, 0);
+
+		msec_delay(10);
+
+		/* set our "perm_addr" based on info provided by PF */
+		ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
+		if (!ret_val) {
+			if (msgbuf[0] == (E1000_VF_RESET |
+						E1000_VT_MSGTYPE_ACK))
+				memcpy(hw->mac.perm_addr, addr, 6);
+			else
+				ret_val = -E1000_ERR_MAC_INIT;
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_init_hw_vf - Inits the HW
+ *  @hw: pointer to the HW structure
+ *
+ *  Not much to do here except clear the PF Reset indication if there is one.
+ **/
+static s32 igbvf_init_hw_vf(struct e1000_hw *hw)
+{
+	DEBUGFUNC("igbvf_init_hw_vf");
+
+	/* attempt to set and restore our mac address */
+	igbvf_rar_set_vf(hw, hw->mac.addr, 0);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igbvf_rar_set_vf - set device MAC address
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index receive address array register
+ **/
+static void igbvf_rar_set_vf(struct e1000_hw *hw, u8 * addr, u32 index __unused)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf[3];
+	u8 *msg_addr = (u8 *)(&msgbuf[1]);
+	s32 ret_val;
+
+	memset(msgbuf, 0, 12);
+	msgbuf[0] = E1000_VF_SET_MAC_ADDR;
+	memcpy(msg_addr, addr, 6);
+	ret_val = mbx->ops.write_posted(hw, msgbuf, 3, 0);
+
+	if (!ret_val)
+		ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0);
+
+	msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS;
+
+	/* if nacked the address was rejected, use "perm_addr" */
+	if (!ret_val &&
+	    (msgbuf[0] == (E1000_VF_SET_MAC_ADDR | E1000_VT_MSGTYPE_NACK)))
+		igbvf_read_mac_addr_vf(hw);
+}
+
+/**
+ *  igbvf_hash_mc_addr_vf - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  igbvf_mta_set_generic()
+ **/
+static u32 igbvf_hash_mc_addr_vf(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	DEBUGFUNC("igbvf_hash_mc_addr_generic");
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * The bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+	                          (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  igbvf_update_mc_addr_list_vf - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *
+ *  Updates the Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igbvf_update_mc_addr_list_vf(struct e1000_hw *hw,
+                                  u8 *mc_addr_list, u32 mc_addr_count)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf[E1000_VFMAILBOX_SIZE];
+	u16 *hash_list = (u16 *)&msgbuf[1];
+	u32 hash_value;
+	u32 i;
+
+	DEBUGFUNC("igbvf_update_mc_addr_list_vf");
+
+	/* Each entry in the list uses 1 16 bit word.  We have 30
+	 * 16 bit words available in our HW msg buffer (minus 1 for the
+	 * msg type).  That's 30 hash values if we pack 'em right.  If
+	 * there are more than 30 MC addresses to add then punt the
+	 * extras for now and then add code to handle more than 30 later.
+	 * It would be unusual for a server to request that many multi-cast
+	 * addresses except for in large enterprise network environments.
+	 */
+
+	DEBUGOUT1("MC Addr Count = %d\n", mc_addr_count);
+
+	msgbuf[0] = E1000_VF_SET_MULTICAST;
+
+	if (mc_addr_count > 30) {
+		msgbuf[0] |= E1000_VF_SET_MULTICAST_OVERFLOW;
+		mc_addr_count = 30;
+	}
+
+	msgbuf[0] |= mc_addr_count << E1000_VT_MSGINFO_SHIFT;
+
+	for (i = 0; i < mc_addr_count; i++) {
+		hash_value = igbvf_hash_mc_addr_vf(hw, mc_addr_list);
+		DEBUGOUT1("Hash value = 0x%03X\n", hash_value);
+		hash_list[i] = hash_value & 0x0FFF;
+		mc_addr_list += ETH_ADDR_LEN;
+	}
+
+	mbx->ops.write_posted(hw, msgbuf, E1000_VFMAILBOX_SIZE, 0);
+}
+
+/**
+ *  igbvf_vfta_set_vf - Set/Unset vlan filter table address
+ *  @hw: pointer to the HW structure
+ *  @vid: determines the vfta register and bit to set/unset
+ *  @set: if true then set bit, else clear bit
+ **/
+void igbvf_vfta_set_vf(struct e1000_hw *hw, u16 vid, bool set)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf[2];
+
+	msgbuf[0] = E1000_VF_SET_VLAN;
+	msgbuf[1] = vid;
+	/* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
+	if (set)
+		msgbuf[0] |= E1000_VF_SET_VLAN_ADD;
+
+	mbx->ops.write_posted(hw, msgbuf, 2, 0);
+}
+
+/** igbvf_rlpml_set_vf - Set the maximum receive packet length
+ *  @hw: pointer to the HW structure
+ *  @max_size: value to assign to max frame size
+ **/
+void igbvf_rlpml_set_vf(struct e1000_hw *hw, u16 max_size)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf[2];
+
+	msgbuf[0] = E1000_VF_SET_LPE;
+	msgbuf[1] = max_size;
+
+	mbx->ops.write_posted(hw, msgbuf, 2, 0);
+}
+
+/**
+ *  igbvf_promisc_set_vf - Set flags for Unicast or Multicast promisc
+ *  @hw: pointer to the HW structure
+ *  @uni: boolean indicating unicast promisc status
+ *  @multi: boolean indicating multicast promisc status
+ **/
+s32 igbvf_promisc_set_vf(struct e1000_hw *hw, enum e1000_promisc_type type)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf = E1000_VF_SET_PROMISC;
+	s32 ret_val;
+
+	switch (type) {
+	case e1000_promisc_multicast:
+		msgbuf |= E1000_VF_SET_PROMISC_MULTICAST;
+		break;
+	case e1000_promisc_enabled:
+		msgbuf |= E1000_VF_SET_PROMISC_MULTICAST;
+	case e1000_promisc_unicast:
+		msgbuf |= E1000_VF_SET_PROMISC_UNICAST;
+	case e1000_promisc_disabled:
+		break;
+	default:
+		return -E1000_ERR_MAC_INIT;
+	}
+
+	 ret_val = mbx->ops.write_posted(hw, &msgbuf, 1, 0);
+
+	if (!ret_val)
+		ret_val = mbx->ops.read_posted(hw, &msgbuf, 1, 0);
+
+	if (!ret_val && !(msgbuf & E1000_VT_MSGTYPE_ACK))
+		ret_val = -E1000_ERR_MAC_INIT;
+
+	return ret_val;
+}
+
+/**
+ *  igbvf_read_mac_addr_vf - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igbvf_read_mac_addr_vf(struct e1000_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  igbvf_check_for_link_vf - Check for link for a virtual interface
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see if the underlying PF is still talking to the VF and
+ *  if it is then it reports the link state to the hardware, otherwise
+ *  it reports link down and returns an error.
+ **/
+static s32 igbvf_check_for_link_vf(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+	u32 in_msg = 0;
+
+	DEBUGFUNC("igbvf_check_for_link_vf");
+
+	/*
+	 * We only want to run this if there has been a rst asserted.
+	 * in this case that could mean a link change, device reset,
+	 * or a virtual function reset
+	 */
+
+	/* If we were hit with a reset drop the link */
+	if (!mbx->ops.check_for_rst(hw, 0))
+		mac->get_link_status = true;
+
+	if (!mac->get_link_status)
+		goto out;
+
+	/* if link status is down no point in checking to see if pf is up */
+	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU))
+		goto out;
+
+	/* if the read failed it could just be a mailbox collision, best wait
+	 * until we are called again and don't report an error */
+	if (mbx->ops.read(hw, &in_msg, 1, 0))
+		goto out;
+
+	/* if incoming message isn't clear to send we are waiting on response */
+	if (!(in_msg & E1000_VT_MSGTYPE_CTS)) {
+		/* message is not CTS and is NACK we have lost CTS status */
+		if (in_msg & E1000_VT_MSGTYPE_NACK)
+			ret_val = -E1000_ERR_MAC_INIT;
+		goto out;
+	}
+
+	/* at this point we know the PF is talking to us, check and see if
+	 * we are still accepting timeout or if we had a timeout failure.
+	 * if we failed then we will need to reinit */
+	if (!mbx->timeout) {
+		ret_val = -E1000_ERR_MAC_INIT;
+		goto out;
+	}
+
+	/* if we passed all the tests above then the link is up and we no
+	 * longer need to check for link */
+	mac->get_link_status = false;
+
+out:
+	return ret_val;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h
new file mode 100644
index 0000000..ce8ad79
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h
@@ -0,0 +1,345 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics at intel.com>
+  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _IGBVF_VF_H_
+#define _IGBVF_VF_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+#include "igbvf_osdep.h"
+#include "igbvf_regs.h"
+#include "igbvf_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82576_VF                 0x10CA
+
+#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+/* Additional Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK                  0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_LEGACY                    0x00000000
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT                 0x04000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION           0x06000000
+#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define E1000_SRRCTL_DESCTYPE_MASK                      0x0E000000
+#define E1000_SRRCTL_DROP_EN                            0x80000000
+
+#define E1000_SRRCTL_BSIZEPKT_MASK      0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK      0x00003F00
+
+/* Interrupt Defines */
+#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + ((_n) << 2))
+#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_IVAR0    0x01700  /* Interrupt Vector Allocation (array) - RW */
+#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
+#define E1000_IVAR_VALID        0x80
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+	struct {
+		u64 pkt_addr;             /* Packet buffer address */
+		u64 hdr_addr;             /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			union {
+				u32 data;
+				struct {
+					u16 pkt_info; /* RSS type, Packet type */
+					u16 hdr_info; /* Split Header,
+						       * header buffer length */
+				} hs_rss;
+			} lo_dword;
+			union {
+				u32 rss;          /* RSS Hash */
+				struct {
+					u16 ip_id;    /* IP id */
+					u16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length;           /* Packet length */
+			u16 vlan;             /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT     5
+
+/* Transmit Descriptor - Advanced */
+union e1000_adv_tx_desc {
+	struct {
+		u64 buffer_addr;    /* Address of descriptor's data buf */
+		u32 cmd_type_len;
+		u32 olinfo_status;
+	} read;
+	struct {
+		u64 rsvd;       /* Reserved */
+		u32 nxtseq_seed;
+		u32 status;
+	} wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP     0x01000000 /* End of Packet */
+#define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS      0x08000000 /* Report Status */
+#define E1000_ADVTXD_DCMD_DEXT    0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE     0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE     0x80000000 /* TCP Seg enable */
+#define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+	u32 vlan_macip_lens;
+	u32 seqnum_seed;
+	u32 type_tucmd_mlhl;
+	u32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT      16  /* Adv ctxt MSS shift */
+
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_vfadapt,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+struct e1000_vf_stats {
+	u64 base_gprc;
+	u64 base_gptc;
+	u64 base_gorc;
+	u64 base_gotc;
+	u64 base_mprc;
+	u64 base_gotlbc;
+	u64 base_gptlbc;
+	u64 base_gorlbc;
+	u64 base_gprlbc;
+
+	u32 last_gprc;
+	u32 last_gptc;
+	u32 last_gorc;
+	u32 last_gotc;
+	u32 last_mprc;
+	u32 last_gotlbc;
+	u32 last_gptlbc;
+	u32 last_gorlbc;
+	u32 last_gprlbc;
+
+	u64 gprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 mprc;
+	u64 gotlbc;
+	u64 gptlbc;
+	u64 gorlbc;
+	u64 gprlbc;
+};
+
+#include "igbvf_mbx.h"
+
+struct e1000_mac_operations {
+	/* Function pointers for the MAC. */
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*check_for_link)(struct e1000_hw *);
+	void (*clear_vfta)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
+	void (*mta_set)(struct e1000_hw *, u32);
+	void (*rar_set)(struct e1000_hw *, u8*, u32);
+	s32  (*read_mac_addr)(struct e1000_hw *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+
+	u16 mta_reg_count;
+	u16 rar_entry_count;
+
+	bool get_link_status;
+};
+
+enum e1000_bus_type {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_type type;
+	enum e1000_bus_speed speed;
+	enum e1000_bus_width width;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_mbx_operations {
+	s32 (*init_params)(struct e1000_hw *hw);
+	s32 (*read)(struct e1000_hw *, u32 *, u16,  u16);
+	s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
+	s32 (*read_posted)(struct e1000_hw *, u32 *, u16,  u16);
+	s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
+	s32 (*check_for_msg)(struct e1000_hw *, u16);
+	s32 (*check_for_ack)(struct e1000_hw *, u16);
+	s32 (*check_for_rst)(struct e1000_hw *, u16);
+};
+
+struct e1000_mbx_stats {
+	u32 msgs_tx;
+	u32 msgs_rx;
+
+	u32 acks;
+	u32 reqs;
+	u32 rsts;
+};
+
+struct e1000_mbx_info {
+	struct e1000_mbx_operations ops;
+	struct e1000_mbx_stats stats;
+	u32 timeout;
+	u32 usec_delay;
+	u16 size;
+};
+
+struct e1000_dev_spec_vf {
+	u32	vf_number;
+	u32	v2p_mailbox;
+};
+
+struct e1000_hw {
+	void *back;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_bus_info  bus;
+	struct e1000_mbx_info mbx;
+
+	union {
+		struct e1000_dev_spec_vf	vf;
+	} dev_spec;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+enum e1000_promisc_type {
+	e1000_promisc_disabled = 0,   /* all promisc modes disabled */
+	e1000_promisc_unicast = 1,    /* unicast promiscuous enabled */
+	e1000_promisc_multicast = 2,  /* multicast promiscuous enabled */
+	e1000_promisc_enabled = 3,    /* both uni and multicast promisc */
+	e1000_num_promisc_types
+};
+
+/* These functions must be implemented by drivers */
+s32  igbvf_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+void igbvf_vfta_set_vf(struct e1000_hw *, u16, bool);
+void igbvf_rlpml_set_vf(struct e1000_hw *, u16);
+s32 igbvf_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type);
+#endif /* _IGBVF_VF_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ipoib.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ipoib.c
new file mode 100644
index 0000000..4917b58
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ipoib.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/errortab.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_pathrec.h>
+#include <ipxe/ib_mcast.h>
+#include <ipxe/ipoib.h>
+
+/** @file
+ *
+ * IP over Infiniband
+ */
+
+/** Number of IPoIB send work queue entries */
+#define IPOIB_NUM_SEND_WQES 2
+
+/** Number of IPoIB receive work queue entries */
+#define IPOIB_NUM_RECV_WQES 4
+
+/** Number of IPoIB completion entries */
+#define IPOIB_NUM_CQES 8
+
+/** An IPoIB device */
+struct ipoib_device {
+	/** Network device */
+	struct net_device *netdev;
+	/** Underlying Infiniband device */
+	struct ib_device *ibdev;
+	/** Completion queue */
+	struct ib_completion_queue *cq;
+	/** Queue pair */
+	struct ib_queue_pair *qp;
+	/** Broadcast MAC */
+	struct ipoib_mac broadcast;
+	/** Joined to IPv4 broadcast multicast group
+	 *
+	 * This flag indicates whether or not we have initiated the
+	 * join to the IPv4 broadcast multicast group.
+	 */
+	int broadcast_joined;
+	/** IPv4 broadcast multicast group membership */
+	struct ib_mc_membership broadcast_membership;
+};
+
+/** Broadcast IPoIB address */
+static struct ipoib_mac ipoib_broadcast = {
+	.flags__qpn = htonl ( IB_QPN_BROADCAST ),
+	.gid.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+		       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
+};
+
+/** Link status for "broadcast join in progress" */
+#define EINPROGRESS_JOINING __einfo_error ( EINFO_EINPROGRESS_JOINING )
+#define EINFO_EINPROGRESS_JOINING __einfo_uniqify \
+	( EINFO_EINPROGRESS, 0x01, "Joining" )
+
+/** Human-readable message for the link status */
+struct errortab ipoib_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EINPROGRESS_JOINING ),
+};
+
+/****************************************************************************
+ *
+ * IPoIB peer cache
+ *
+ ****************************************************************************
+ */
+
+/**
+ * IPoIB peer address
+ *
+ * The IPoIB link-layer header is only four bytes long and so does not
+ * have sufficient room to store IPoIB MAC address(es).  We therefore
+ * maintain a cache of MAC addresses identified by a single-byte key,
+ * and abuse the spare two bytes within the link-layer header to
+ * communicate these MAC addresses between the link-layer code and the
+ * netdevice driver.
+ */
+struct ipoib_peer {
+	/** Key */
+	uint8_t key;
+	/** MAC address */
+	struct ipoib_mac mac;
+};
+
+/** Number of IPoIB peer cache entries
+ *
+ * Must be a power of two.
+ */
+#define IPOIB_NUM_CACHED_PEERS 4
+
+/** IPoIB peer address cache */
+static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
+
+/** Oldest IPoIB peer cache entry index */
+static unsigned int ipoib_peer_cache_idx = 1;
+
+/**
+ * Look up cached peer by key
+ *
+ * @v key		Peer cache key
+ * @ret peer		Peer cache entry, or NULL
+ */
+static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
+	struct ipoib_peer *peer;
+	unsigned int i;
+
+	for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+		peer = &ipoib_peer_cache[i];
+		if ( peer->key == key )
+			return peer;
+	}
+
+	if ( key != 0 ) {
+		DBG ( "IPoIB warning: peer cache lost track of key %x while "
+		      "still in use\n", key );
+	}
+	return NULL;
+}
+
+/**
+ * Store GID and QPN in peer cache
+ *
+ * @v mac		Peer MAC address
+ * @ret peer		Peer cache entry
+ */
+static struct ipoib_peer * ipoib_cache_peer ( const struct ipoib_mac *mac ) {
+	struct ipoib_peer *peer;
+	unsigned int key;
+	unsigned int i;
+
+	/* Look for existing cache entry */
+	for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+		peer = &ipoib_peer_cache[i];
+		if ( memcmp ( &peer->mac, mac, sizeof ( peer->mac ) ) == 0 )
+			return peer;
+	}
+
+	/* No entry found: create a new one */
+	key = ipoib_peer_cache_idx++;
+	peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
+	if ( peer->key )
+		DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
+
+	memset ( peer, 0, sizeof ( *peer ) );
+	peer->key = key;
+	memcpy ( &peer->mac, mac, sizeof ( peer->mac ) );
+	DBG ( "IPoIB peer %x has MAC %s\n",
+	      peer->key, ipoib_ntoa ( &peer->mac ) );
+	return peer;
+}
+
+/****************************************************************************
+ *
+ * IPoIB link layer
+ *
+ ****************************************************************************
+ */
+
+/**
+ * Add IPoIB link-layer header
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Source link-layer address
+ * @v net_proto		Network-layer protocol, in network-byte order
+ * @ret rc		Return status code
+ */
+static int ipoib_push ( struct net_device *netdev __unused,
+			struct io_buffer *iobuf, const void *ll_dest,
+			const void *ll_source __unused, uint16_t net_proto ) {
+	struct ipoib_hdr *ipoib_hdr =
+		iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
+	const struct ipoib_mac *dest_mac = ll_dest;
+	const struct ipoib_mac *src_mac = ll_source;
+	struct ipoib_peer *dest;
+	struct ipoib_peer *src;
+
+	/* Add link-layer addresses to cache */
+	dest = ipoib_cache_peer ( dest_mac );
+	src = ipoib_cache_peer ( src_mac );
+
+	/* Build IPoIB header */
+	ipoib_hdr->proto = net_proto;
+	ipoib_hdr->u.peer.dest = dest->key;
+	ipoib_hdr->u.peer.src = src->key;
+
+	return 0;
+}
+
+/**
+ * Remove IPoIB link-layer header
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret ll_dest		Link-layer destination address
+ * @ret ll_source	Source link-layer address
+ * @ret net_proto	Network-layer protocol, in network-byte order
+ * @ret rc		Return status code
+ */
+static int ipoib_pull ( struct net_device *netdev,
+			struct io_buffer *iobuf, const void **ll_dest,
+			const void **ll_source, uint16_t *net_proto ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ipoib_hdr *ipoib_hdr = iobuf->data;
+	struct ipoib_peer *dest;
+	struct ipoib_peer *source;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
+		DBG ( "IPoIB packet too short for link-layer header\n" );
+		DBG_HD ( iobuf->data, iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+
+	/* Strip off IPoIB header */
+	iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
+
+	/* Identify source and destination addresses, and clear
+	 * reserved word in IPoIB header
+	 */
+	dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+	source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
+	ipoib_hdr->u.reserved = 0;
+
+	/* Fill in required fields */
+	*ll_dest = ( dest ? &dest->mac : &ipoib->broadcast );
+	*ll_source = ( source ? &source->mac : &ipoib->broadcast );
+	*net_proto = ipoib_hdr->proto;
+
+	return 0;
+}
+
+/**
+ * Initialise IPoIB link-layer address
+ *
+ * @v hw_addr		Hardware address
+ * @v ll_addr		Link-layer address
+ */
+static void ipoib_init_addr ( const void *hw_addr, void *ll_addr ) {
+	const union ib_guid *guid = hw_addr;
+	struct ipoib_mac *mac = ll_addr;
+
+	memset ( mac, 0, sizeof ( *mac ) );
+	memcpy ( &mac->gid.s.guid, guid, sizeof ( mac->gid.s.guid ) );
+}
+
+/**
+ * Transcribe IPoIB link-layer address
+ *
+ * @v ll_addr	Link-layer address
+ * @ret string	Link-layer address in human-readable format
+ */
+const char * ipoib_ntoa ( const void *ll_addr ) {
+	static char buf[45];
+	const struct ipoib_mac *mac = ll_addr;
+
+	snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
+		   htonl ( mac->flags__qpn ), htonl ( mac->gid.dwords[0] ),
+		   htonl ( mac->gid.dwords[1] ),
+		   htonl ( mac->gid.dwords[2] ),
+		   htonl ( mac->gid.dwords[3] ) );
+	return buf;
+}
+
+/**
+ * Hash multicast address
+ *
+ * @v af		Address family
+ * @v net_addr		Network-layer address
+ * @v ll_addr		Link-layer address to fill in
+ * @ret rc		Return status code
+ */
+static int ipoib_mc_hash ( unsigned int af __unused,
+			   const void *net_addr __unused,
+			   void *ll_addr __unused ) {
+
+	return -ENOTSUP;
+}
+
+/**
+ * Generate Mellanox Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr		Link-layer address
+ * @v eth_addr		Ethernet-compatible address to fill in
+ */
+static int ipoib_mlx_eth_addr ( const union ib_guid *guid,
+				uint8_t *eth_addr ) {
+	eth_addr[0] = ( ( guid->bytes[3] == 2 ) ? 0x00 : 0x02 );
+	eth_addr[1] = guid->bytes[1];
+	eth_addr[2] = guid->bytes[2];
+	eth_addr[3] = guid->bytes[5];
+	eth_addr[4] = guid->bytes[6];
+	eth_addr[5] = guid->bytes[7];
+	return 0;
+}
+
+/** An IPoIB Ethernet-compatible compressed link-layer address generator */
+struct ipoib_eth_addr_handler {
+	/** GUID byte 1 */
+	uint8_t byte1;
+	/** GUID byte 2 */
+	uint8_t byte2;
+	/** Handler */
+	int ( * eth_addr ) ( const union ib_guid *guid,
+			     uint8_t *eth_addr );
+};
+
+/** IPoIB Ethernet-compatible compressed link-layer address generators */
+static struct ipoib_eth_addr_handler ipoib_eth_addr_handlers[] = {
+	{ 0x02, 0xc9, ipoib_mlx_eth_addr },
+};
+
+/**
+ * Generate Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr		Link-layer address
+ * @v eth_addr		Ethernet-compatible address to fill in
+ */
+static int ipoib_eth_addr ( const void *ll_addr, void *eth_addr ) {
+	const struct ipoib_mac *ipoib_addr = ll_addr;
+	const union ib_guid *guid = &ipoib_addr->gid.s.guid;
+	struct ipoib_eth_addr_handler *handler;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( ipoib_eth_addr_handlers ) /
+			    sizeof ( ipoib_eth_addr_handlers[0] ) ) ; i++ ) {
+		handler = &ipoib_eth_addr_handlers[i];
+		if ( ( handler->byte1 == guid->bytes[1] ) &&
+		     ( handler->byte2 == guid->bytes[2] ) ) {
+			return handler->eth_addr ( guid, eth_addr );
+		}
+	}
+	return -ENOTSUP;
+}
+
+/** IPoIB protocol */
+struct ll_protocol ipoib_protocol __ll_protocol = {
+	.name		= "IPoIB",
+	.ll_proto	= htons ( ARPHRD_INFINIBAND ),
+	.hw_addr_len	= sizeof ( union ib_guid ),
+	.ll_addr_len	= IPOIB_ALEN,
+	.ll_header_len	= IPOIB_HLEN,
+	.push		= ipoib_push,
+	.pull		= ipoib_pull,
+	.init_addr	= ipoib_init_addr,
+	.ntoa		= ipoib_ntoa,
+	.mc_hash	= ipoib_mc_hash,
+	.eth_addr	= ipoib_eth_addr,
+};
+
+/**
+ * Allocate IPoIB device
+ *
+ * @v priv_size		Size of driver private data
+ * @ret netdev		Network device, or NULL
+ */
+struct net_device * alloc_ipoibdev ( size_t priv_size ) {
+	struct net_device *netdev;
+
+	netdev = alloc_netdev ( priv_size );
+	if ( netdev ) {
+		netdev->ll_protocol = &ipoib_protocol;
+		netdev->ll_broadcast = ( uint8_t * ) &ipoib_broadcast;
+		netdev->max_pkt_len = IB_MAX_PAYLOAD_SIZE;
+	}
+	return netdev;
+}
+
+/****************************************************************************
+ *
+ * IPoIB network device
+ *
+ ****************************************************************************
+ */
+
+/**
+ * Transmit packet via IPoIB network device
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int ipoib_transmit ( struct net_device *netdev,
+			    struct io_buffer *iobuf ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ib_device *ibdev = ipoib->ibdev;
+	struct ipoib_hdr *ipoib_hdr;
+	struct ipoib_peer *dest;
+	struct ib_address_vector av;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
+		DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
+		return -EINVAL;
+	}
+	ipoib_hdr = iobuf->data;
+
+	/* Attempting transmission while link is down will put the
+	 * queue pair into an error state, so don't try it.
+	 */
+	if ( ! ib_link_ok ( ibdev ) )
+		return -ENETUNREACH;
+
+	/* Identify destination address */
+	dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+	if ( ! dest )
+		return -ENXIO;
+	ipoib_hdr->u.reserved = 0;
+
+	/* Construct address vector */
+	memset ( &av, 0, sizeof ( av ) );
+	av.qpn = ( ntohl ( dest->mac.flags__qpn ) & IB_QPN_MASK );
+	av.gid_present = 1;
+	memcpy ( &av.gid, &dest->mac.gid, sizeof ( av.gid ) );
+	if ( ( rc = ib_resolve_path ( ibdev, &av ) ) != 0 ) {
+		/* Path not resolved yet */
+		return rc;
+	}
+
+	return ib_post_send ( ibdev, ipoib->qp, &av, iobuf );
+}
+
+/**
+ * Handle IPoIB send completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void ipoib_complete_send ( struct ib_device *ibdev __unused,
+				  struct ib_queue_pair *qp,
+				  struct io_buffer *iobuf, int rc ) {
+	struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
+
+	netdev_tx_complete_err ( ipoib->netdev, iobuf, rc );
+}
+
+/**
+ * Handle IPoIB receive completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector, or NULL
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void ipoib_complete_recv ( struct ib_device *ibdev __unused,
+				  struct ib_queue_pair *qp,
+				  struct ib_address_vector *av,
+				  struct io_buffer *iobuf, int rc ) {
+	struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
+	struct net_device *netdev = ipoib->netdev;
+	struct ipoib_hdr *ipoib_hdr;
+	struct ipoib_mac ll_src;
+	struct ipoib_peer *src;
+
+	/* Record errors */
+	if ( rc != 0 ) {
+		netdev_rx_err ( netdev, iobuf, rc );
+		return;
+	}
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
+		DBGC ( ipoib, "IPoIB %p received packet too short to "
+		       "contain IPoIB header\n", ipoib );
+		DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
+		netdev_rx_err ( netdev, iobuf, -EIO );
+		return;
+	}
+	ipoib_hdr = iobuf->data;
+	if ( ! av ) {
+		DBGC ( ipoib, "IPoIB %p received packet without address "
+		       "vector\n", ipoib );
+		netdev_rx_err ( netdev, iobuf, -ENOTTY );
+		return;
+	}
+
+	/* Parse source address */
+	if ( av->gid_present ) {
+		ll_src.flags__qpn = htonl ( av->qpn );
+		memcpy ( &ll_src.gid, &av->gid, sizeof ( ll_src.gid ) );
+		src = ipoib_cache_peer ( &ll_src );
+		ipoib_hdr->u.peer.src = src->key;
+	}
+
+	/* Hand off to network layer */
+	netdev_rx ( netdev, iobuf );
+}
+
+/** IPoIB completion operations */
+static struct ib_completion_queue_operations ipoib_cq_op = {
+	.complete_send = ipoib_complete_send,
+	.complete_recv = ipoib_complete_recv,
+};
+
+/**
+ * Poll IPoIB network device
+ *
+ * @v netdev		Network device
+ */
+static void ipoib_poll ( struct net_device *netdev ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ib_device *ibdev = ipoib->ibdev;
+
+	ib_poll_eq ( ibdev );
+}
+
+/**
+ * Handle IPv4 broadcast multicast group join completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v membership	Multicast group membership
+ * @v rc		Status code
+ * @v mad		Response MAD (or NULL on error)
+ */
+void ipoib_join_complete ( struct ib_device *ibdev __unused,
+			   struct ib_queue_pair *qp __unused,
+			   struct ib_mc_membership *membership, int rc,
+			   union ib_mad *mad __unused ) {
+	struct ipoib_device *ipoib = container_of ( membership,
+				   struct ipoib_device, broadcast_membership );
+
+	/* Record join status as link status */
+	netdev_link_err ( ipoib->netdev, rc );
+}
+
+/**
+ * Join IPv4 broadcast multicast group
+ *
+ * @v ipoib		IPoIB device
+ * @ret rc		Return status code
+ */
+static int ipoib_join_broadcast_group ( struct ipoib_device *ipoib ) {
+	int rc;
+
+	if ( ( rc = ib_mcast_join ( ipoib->ibdev, ipoib->qp,
+				    &ipoib->broadcast_membership,
+				    &ipoib->broadcast.gid,
+				    ipoib_join_complete ) ) != 0 ) {
+		DBGC ( ipoib, "IPoIB %p could not join broadcast group: %s\n",
+		       ipoib, strerror ( rc ) );
+		return rc;
+	}
+	ipoib->broadcast_joined = 1;
+
+	return 0;
+}
+
+/**
+ * Leave IPv4 broadcast multicast group
+ *
+ * @v ipoib		IPoIB device
+ */
+static void ipoib_leave_broadcast_group ( struct ipoib_device *ipoib ) {
+
+	if ( ipoib->broadcast_joined ) {
+		ib_mcast_leave ( ipoib->ibdev, ipoib->qp,
+				 &ipoib->broadcast_membership );
+		ipoib->broadcast_joined = 0;
+	}
+}
+
+/**
+ * Handle link status change
+ *
+ * @v ibdev		Infiniband device
+ */
+static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
+	struct net_device *netdev = ib_get_ownerdata ( ibdev );
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
+	int rc;
+
+	/* Leave existing broadcast group */
+	ipoib_leave_broadcast_group ( ipoib );
+
+	/* Update MAC address based on potentially-new GID prefix */
+	memcpy ( &mac->gid.s.prefix, &ibdev->gid.s.prefix,
+		 sizeof ( mac->gid.s.prefix ) );
+
+	/* Update broadcast GID based on potentially-new partition key */
+	ipoib->broadcast.gid.words[2] =
+		htons ( ibdev->pkey | IB_PKEY_FULL );
+
+	/* Set net device link state to reflect Infiniband link state */
+	rc = ib_link_rc ( ibdev );
+	netdev_link_err ( netdev, ( rc ? rc : -EINPROGRESS_JOINING ) );
+
+	/* Join new broadcast group */
+	if ( ib_is_open ( ibdev ) && ib_link_ok ( ibdev ) &&
+	     ( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) ) {
+		DBGC ( ipoib, "IPoIB %p could not rejoin broadcast group: "
+		       "%s\n", ipoib, strerror ( rc ) );
+		netdev_link_err ( netdev, rc );
+		return;
+	}
+}
+
+/**
+ * Open IPoIB network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int ipoib_open ( struct net_device *netdev ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ib_device *ibdev = ipoib->ibdev;
+	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
+	int rc;
+
+	/* Open IB device */
+	if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
+		DBGC ( ipoib, "IPoIB %p could not open device: %s\n",
+		       ipoib, strerror ( rc ) );
+		goto err_ib_open;
+	}
+
+	/* Allocate completion queue */
+	ipoib->cq = ib_create_cq ( ibdev, IPOIB_NUM_CQES, &ipoib_cq_op );
+	if ( ! ipoib->cq ) {
+		DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
+		       ipoib );
+		rc = -ENOMEM;
+		goto err_create_cq;
+	}
+
+	/* Allocate queue pair */
+	ipoib->qp = ib_create_qp ( ibdev, IB_QPT_UD,
+				   IPOIB_NUM_SEND_WQES, ipoib->cq,
+				   IPOIB_NUM_RECV_WQES, ipoib->cq );
+	if ( ! ipoib->qp ) {
+		DBGC ( ipoib, "IPoIB %p could not allocate queue pair\n",
+		       ipoib );
+		rc = -ENOMEM;
+		goto err_create_qp;
+	}
+	ib_qp_set_ownerdata ( ipoib->qp, ipoib );
+
+	/* Update MAC address with QPN */
+	mac->flags__qpn = htonl ( ipoib->qp->qpn );
+
+	/* Fill receive rings */
+	ib_refill_recv ( ibdev, ipoib->qp );
+
+	/* Fake a link status change to join the broadcast group */
+	ipoib_link_state_changed ( ibdev );
+
+	return 0;
+
+	ib_destroy_qp ( ibdev, ipoib->qp );
+ err_create_qp:
+	ib_destroy_cq ( ibdev, ipoib->cq );
+ err_create_cq:
+	ib_close ( ibdev );
+ err_ib_open:
+	return rc;
+}
+
+/**
+ * Close IPoIB network device
+ *
+ * @v netdev		Network device
+ */
+static void ipoib_close ( struct net_device *netdev ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct ib_device *ibdev = ipoib->ibdev;
+	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
+
+	/* Leave broadcast group */
+	ipoib_leave_broadcast_group ( ipoib );
+
+	/* Remove QPN from MAC address */
+	mac->flags__qpn = 0;
+
+	/* Tear down the queues */
+	ib_destroy_qp ( ibdev, ipoib->qp );
+	ib_destroy_cq ( ibdev, ipoib->cq );
+
+	/* Close IB device */
+	ib_close ( ibdev );
+}
+
+/** IPoIB network device operations */
+static struct net_device_operations ipoib_operations = {
+	.open		= ipoib_open,
+	.close		= ipoib_close,
+	.transmit	= ipoib_transmit,
+	.poll		= ipoib_poll,
+};
+
+/**
+ * Probe IPoIB device
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int ipoib_probe ( struct ib_device *ibdev ) {
+	struct net_device *netdev;
+	struct ipoib_device *ipoib;
+	int rc;
+
+	/* Allocate network device */
+	netdev = alloc_ipoibdev ( sizeof ( *ipoib ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &ipoib_operations );
+	ipoib = netdev->priv;
+	ib_set_ownerdata ( ibdev, netdev );
+	netdev->dev = ibdev->dev;
+	memset ( ipoib, 0, sizeof ( *ipoib ) );
+	ipoib->netdev = netdev;
+	ipoib->ibdev = ibdev;
+
+	/* Extract hardware address */
+	memcpy ( netdev->hw_addr, &ibdev->gid.s.guid,
+		 sizeof ( ibdev->gid.s.guid ) );
+
+	/* Set default broadcast address */
+	memcpy ( &ipoib->broadcast, &ipoib_broadcast,
+		 sizeof ( ipoib->broadcast ) );
+	netdev->ll_broadcast = ( ( uint8_t * ) &ipoib->broadcast );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	return 0;
+
+ err_register_netdev:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	return rc;
+}
+
+/**
+ * Remove IPoIB device
+ *
+ * @v ibdev		Infiniband device
+ */
+static void ipoib_remove ( struct ib_device *ibdev ) {
+	struct net_device *netdev = ib_get_ownerdata ( ibdev );
+
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** IPoIB driver */
+struct ib_driver ipoib_driver __ib_driver = {
+	.name = "IPoIB",
+	.probe = ipoib_probe,
+	.notify = ipoib_link_state_changed,
+	.remove = ipoib_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.c
new file mode 100644
index 0000000..5454026
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.c
@@ -0,0 +1,1308 @@
+/*
+ * JMicron JMC2x0 series PCIe Ethernet gPXE Device Driver
+ *
+ * Copyright 2010 Guo-Fu Tseng <cooldavid at cooldavid.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/malloc.h>
+#include <mii.h>
+#include "jme.h"
+
+static int
+jme_mdio_read(struct net_device *netdev, int phy, int reg)
+{
+	struct jme_adapter *jme = netdev->priv;
+	int i, val, again = (reg == MII_BMSR) ? 1 : 0;
+
+read_again:
+	jwrite32(jme, JME_SMI, SMI_OP_REQ |
+				smi_phy_addr(phy) |
+				smi_reg_addr(reg));
+
+	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
+		udelay(20);
+		val = jread32(jme, JME_SMI);
+		if ((val & SMI_OP_REQ) == 0)
+			break;
+	}
+
+	if (i == 0) {
+		DBG("phy(%d) read timeout : %d\n", phy, reg);
+		return 0;
+	}
+
+	if (again--)
+		goto read_again;
+
+	return (val & SMI_DATA_MASK) >> SMI_DATA_SHIFT;
+}
+
+static void
+jme_mdio_write(struct net_device *netdev,
+				int phy, int reg, int val)
+{
+	struct jme_adapter *jme = netdev->priv;
+	int i;
+
+	jwrite32(jme, JME_SMI, SMI_OP_WRITE | SMI_OP_REQ |
+		((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) |
+		smi_phy_addr(phy) | smi_reg_addr(reg));
+
+	wmb();
+	for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) {
+		udelay(20);
+		if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0)
+			break;
+	}
+
+	if (i == 0)
+		DBG("phy(%d) write timeout : %d\n", phy, reg);
+
+	return;
+}
+
+static void
+jme_reset_phy_processor(struct jme_adapter *jme)
+{
+	u32 val;
+
+	jme_mdio_write(jme->mii_if.dev,
+			jme->mii_if.phy_id,
+			MII_ADVERTISE, ADVERTISE_ALL |
+			ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+	if (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250)
+		jme_mdio_write(jme->mii_if.dev,
+				jme->mii_if.phy_id,
+				MII_CTRL1000,
+				ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
+	val = jme_mdio_read(jme->mii_if.dev,
+				jme->mii_if.phy_id,
+				MII_BMCR);
+
+	jme_mdio_write(jme->mii_if.dev,
+			jme->mii_if.phy_id,
+			MII_BMCR, val | BMCR_RESET);
+
+	return;
+}
+
+static void
+jme_phy_init(struct jme_adapter *jme)
+{
+	u16 reg26;
+
+	reg26 = jme_mdio_read(jme->mii_if.dev, jme->mii_if.phy_id, 26);
+	jme_mdio_write(jme->mii_if.dev, jme->mii_if.phy_id, 26, reg26 | 0x1000);
+}
+
+static void
+jme_set_phyfifoa(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->mii_if.dev, jme->mii_if.phy_id, 27, 0x0004);
+}
+
+static void
+jme_set_phyfifob(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->mii_if.dev, jme->mii_if.phy_id, 27, 0x0000);
+}
+
+static void
+jme_phy_off(struct jme_adapter *jme)
+{
+	jme_mdio_write(jme->mii_if.dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN);
+}
+
+static void
+jme_restart_an(struct jme_adapter *jme)
+{
+	uint32_t bmcr;
+
+	bmcr = jme_mdio_read(jme->mii_if.dev, jme->mii_if.phy_id, MII_BMCR);
+	bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	jme_mdio_write(jme->mii_if.dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+}
+
+static void
+jme_reset_ghc_speed(struct jme_adapter *jme)
+{
+	jme->reg_ghc &= ~(GHC_SPEED_1000M | GHC_DPX);
+	jwrite32(jme, JME_GHC, jme->reg_ghc);
+}
+
+static void
+jme_start_irq(struct jme_adapter *jme)
+{
+	/*
+	 * Enable Interrupts
+	 */
+	jwrite32(jme, JME_IENS, INTR_ENABLE);
+}
+
+static void
+jme_stop_irq(struct jme_adapter *jme)
+{
+	/*
+	 * Disable Interrupts
+	 */
+	jwrite32f(jme, JME_IENC, INTR_ENABLE);
+}
+
+static void
+jme_setup_wakeup_frame(struct jme_adapter *jme,
+		u32 *mask, u32 crc, int fnr)
+{
+	int i;
+
+	/*
+	 * Setup CRC pattern
+	 */
+	jwrite32(jme, JME_WFOI, WFOI_CRC_SEL | (fnr & WFOI_FRAME_SEL));
+	wmb();
+	jwrite32(jme, JME_WFODP, crc);
+	wmb();
+
+	/*
+	 * Setup Mask
+	 */
+	for (i = 0 ; i < WAKEUP_FRAME_MASK_DWNR ; ++i) {
+		jwrite32(jme, JME_WFOI,
+				((i << WFOI_MASK_SHIFT) & WFOI_MASK_SEL) |
+				(fnr & WFOI_FRAME_SEL));
+		wmb();
+		jwrite32(jme, JME_WFODP, mask[i]);
+		wmb();
+	}
+}
+
+static void
+jme_reset_mac_processor(struct jme_adapter *jme)
+{
+	u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
+	u32 crc = 0xCDCDCDCD;
+	int i;
+
+	jwrite32(jme, JME_GHC, jme->reg_ghc | GHC_SWRST);
+	udelay(2);
+	jwrite32(jme, JME_GHC, jme->reg_ghc);
+
+	jwrite32(jme, JME_RXDBA_LO, 0x00000000);
+	jwrite32(jme, JME_RXDBA_HI, 0x00000000);
+	jwrite32(jme, JME_RXQDC, 0x00000000);
+	jwrite32(jme, JME_RXNDA, 0x00000000);
+	jwrite32(jme, JME_TXDBA_LO, 0x00000000);
+	jwrite32(jme, JME_TXDBA_HI, 0x00000000);
+	jwrite32(jme, JME_TXQDC, 0x00000000);
+	jwrite32(jme, JME_TXNDA, 0x00000000);
+
+	jwrite32(jme, JME_RXMCHT_LO, 0x00000000);
+	jwrite32(jme, JME_RXMCHT_HI, 0x00000000);
+	for (i = 0 ; i < WAKEUP_FRAME_NR ; ++i)
+		jme_setup_wakeup_frame(jme, mask, crc, i);
+	jwrite32(jme, JME_GPREG0, GPREG0_DEFAULT);
+	jwrite32(jme, JME_GPREG1, GPREG1_DEFAULT);
+}
+
+static void
+jme_free_tx_buffers(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+	struct io_buffer *txbi;
+	unsigned int i;
+
+	for (i = 0; i < jme->tx_ring_size; ++i) {
+		txbi = txring->bufinf[i];
+		if (txbi) {
+			netdev_tx_complete_err(jme->mii_if.dev,
+					txbi, -ENOLINK);
+			txring->bufinf[i] = NULL;
+		}
+	}
+}
+
+static void
+jme_free_tx_resources(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+
+	if (txring->desc) {
+		if (txring->bufinf) {
+			memset(txring->bufinf, 0,
+				sizeof(struct io_buffer *) * jme->tx_ring_size);
+			free(txring->bufinf);
+		}
+		free_dma(txring->desc, jme->tx_ring_size * TX_DESC_SIZE);
+		txring->desc		= NULL;
+		txring->dma		= 0;
+		txring->bufinf		= NULL;
+	}
+	txring->next_to_use	= 0;
+	txring->next_to_clean	= 0;
+	txring->nr_free		= 0;
+}
+
+static int
+jme_alloc_tx_resources(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+
+	txring->desc = malloc_dma(jme->tx_ring_size * TX_DESC_SIZE,
+					RING_DESC_ALIGN);
+	if (!txring->desc) {
+		DBG("Can not allocate transmit ring descriptors.\n");
+		goto err_out;
+	}
+
+	/*
+	 * 16 Bytes align
+	 */
+	txring->dma		= virt_to_bus(txring->desc);
+	txring->bufinf		= malloc(sizeof(struct io_buffer *) *
+					jme->tx_ring_size);
+	if (!(txring->bufinf)) {
+		DBG("Can not allocate transmit buffer info.\n");
+		goto err_out;
+	}
+
+	/*
+	 * Initialize Transmit Buffer Pointers
+	 */
+	memset(txring->bufinf, 0,
+		sizeof(struct io_buffer *) * jme->tx_ring_size);
+
+	return 0;
+
+err_out:
+	jme_free_tx_resources(jme);
+	return -ENOMEM;
+}
+
+static void
+jme_init_tx_ring(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+
+	txring->next_to_clean	= 0;
+	txring->next_to_use	= 0;
+	txring->nr_free		= jme->tx_ring_size;
+
+	/*
+	 * Initialize Transmit Descriptors
+	 */
+	memset(txring->desc, 0, jme->tx_ring_size * TX_DESC_SIZE);
+	jme_free_tx_buffers(jme);
+}
+
+static void
+jme_enable_tx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Select Queue 0
+	 */
+	jwrite32(jme, JME_TXCS, TXCS_DEFAULT | TXCS_SELECT_QUEUE0);
+	wmb();
+
+	/*
+	 * Setup TX Queue 0 DMA Bass Address
+	 */
+	jwrite32(jme, JME_TXDBA_LO, (uint64_t)jme->txring.dma & 0xFFFFFFFFUL);
+	jwrite32(jme, JME_TXDBA_HI, (uint64_t)(jme->txring.dma) >> 32);
+	jwrite32(jme, JME_TXNDA, (uint64_t)jme->txring.dma & 0xFFFFFFFFUL);
+
+	/*
+	 * Setup TX Descptor Count
+	 */
+	jwrite32(jme, JME_TXQDC, jme->tx_ring_size);
+
+	/*
+	 * Enable TX Engine
+	 */
+	wmb();
+	jwrite32(jme, JME_TXCS, jme->reg_txcs |
+				TXCS_SELECT_QUEUE0 |
+				TXCS_ENABLE);
+
+}
+
+static void
+jme_disable_tx_engine(struct jme_adapter *jme)
+{
+	int i;
+	u32 val;
+
+	/*
+	 * Disable TX Engine
+	 */
+	jwrite32(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0);
+	wmb();
+
+	val = jread32(jme, JME_TXCS);
+	for (i = JME_TX_DISABLE_TIMEOUT ; (val & TXCS_ENABLE) && i > 0 ; --i) {
+		mdelay(1);
+		val = jread32(jme, JME_TXCS);
+		rmb();
+	}
+
+	if (!i)
+		DBG("Disable TX engine timeout.\n");
+}
+
+
+static void
+jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
+{
+	struct jme_ring *rxring = &jme->rxring;
+	register struct rxdesc *rxdesc = rxring->desc;
+	struct io_buffer *rxbi = rxring->bufinf[i];
+	uint64_t mapping;
+
+	rxdesc += i;
+	mapping = virt_to_bus(rxbi->data);
+
+	rxdesc->dw[0] = 0;
+	rxdesc->dw[1] = 0;
+	rxdesc->desc1.bufaddrh	= cpu_to_le32(mapping >> 32);
+	rxdesc->desc1.bufaddrl	= cpu_to_le32(mapping & 0xFFFFFFFFUL);
+	rxdesc->desc1.datalen	= cpu_to_le16(RX_ALLOC_LEN);
+	wmb();
+	rxdesc->desc1.flags	|= RXFLAG_OWN | RXFLAG_INT;
+}
+
+static int
+jme_make_new_rx_buf(struct io_buffer **rxbip)
+{
+	struct io_buffer *inbuf;
+
+	/*
+	 * IOB_ALIGN == 2048
+	 */
+	inbuf = alloc_iob(RX_ALLOC_LEN);
+	if (!inbuf) {
+		DBG("Allocate receive iob error.\n");
+		return -ENOMEM;
+	}
+	*rxbip = inbuf;
+
+	return 0;
+}
+
+static void
+jme_free_rx_buf(struct jme_adapter *jme, int i)
+{
+	struct jme_ring *rxring = &jme->rxring;
+	struct io_buffer *rxbi = rxring->bufinf[i];
+
+	if (rxbi) {
+		free_iob(rxbi);
+		rxring->bufinf[i] = NULL;
+	}
+}
+
+static void
+jme_free_rx_resources(struct jme_adapter *jme)
+{
+	unsigned int i;
+	struct jme_ring *rxring = &jme->rxring;
+
+	if (rxring->desc) {
+		if (rxring->bufinf) {
+			for (i = 0 ; i < jme->rx_ring_size ; ++i)
+				jme_free_rx_buf(jme, i);
+			free(rxring->bufinf);
+		}
+
+		free_dma(rxring->desc, jme->rx_ring_size * RX_DESC_SIZE);
+		rxring->desc     = NULL;
+		rxring->dma      = 0;
+		rxring->bufinf   = NULL;
+	}
+	rxring->next_to_fill = 0;
+	rxring->next_to_clean = 0;
+}
+
+static int
+jme_alloc_rx_resources(struct jme_adapter *jme)
+{
+	unsigned int i;
+	struct jme_ring *rxring = &jme->rxring;
+	struct io_buffer **bufinf;
+
+	rxring->desc = malloc_dma(jme->rx_ring_size * RX_DESC_SIZE,
+			RING_DESC_ALIGN);
+	if (!rxring->desc) {
+		DBG("Can not allocate receive ring descriptors.\n");
+		goto err_out;
+	}
+
+	/*
+	 * 16 Bytes align
+	 */
+	rxring->dma		= virt_to_bus(rxring->desc);
+	rxring->bufinf		= malloc(sizeof(struct io_buffer *) *
+					jme->rx_ring_size);
+	if (!(rxring->bufinf)) {
+		DBG("Can not allocate receive buffer info.\n");
+		goto err_out;
+	}
+
+	/*
+	 * Initiallize Receive Buffer Pointers
+	 */
+	bufinf = rxring->bufinf;
+	memset(bufinf, 0, sizeof(struct io_buffer *) * jme->rx_ring_size);
+	for (i = 0 ; i < jme->rx_ring_size ; ++i) {
+		if (jme_make_new_rx_buf(bufinf))
+			goto err_out;
+		++bufinf;
+	}
+
+	return 0;
+
+err_out:
+	jme_free_rx_resources(jme);
+	return -ENOMEM;
+}
+
+static void
+jme_init_rx_ring(struct jme_adapter *jme)
+{
+	unsigned int i;
+	struct jme_ring *rxring = &jme->rxring;
+
+	for (i = 0 ; i < jme->rx_ring_size ; ++i)
+		jme_set_clean_rxdesc(jme, i);
+
+	rxring->next_to_fill = 0;
+	rxring->next_to_clean = 0;
+}
+
+static void
+jme_set_multi(struct jme_adapter *jme)
+{
+	/*
+	 * Just receive all kind of packet for new.
+	 */
+	jme->reg_rxmcs |= RXMCS_ALLFRAME | RXMCS_BRDFRAME | RXMCS_UNIFRAME;
+	jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
+}
+
+static void
+jme_enable_rx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Select Queue 0
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0);
+	wmb();
+
+	/*
+	 * Setup RX DMA Bass Address
+	 */
+	jwrite32(jme, JME_RXDBA_LO, (uint64_t)(jme->rxring.dma) & 0xFFFFFFFFUL);
+	jwrite32(jme, JME_RXDBA_HI, (uint64_t)(jme->rxring.dma) >> 32);
+	jwrite32(jme, JME_RXNDA, (uint64_t)(jme->rxring.dma) & 0xFFFFFFFFUL);
+
+	/*
+	 * Setup RX Descriptor Count
+	 */
+	jwrite32(jme, JME_RXQDC, jme->rx_ring_size);
+
+	/*
+	 * Setup Unicast Filter
+	 */
+	jme_set_multi(jme);
+
+	/*
+	 * Enable RX Engine
+	 */
+	wmb();
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0 |
+				RXCS_ENABLE |
+				RXCS_QST);
+}
+
+static void
+jme_restart_rx_engine(struct jme_adapter *jme)
+{
+	/*
+	 * Start RX Engine
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs |
+				RXCS_QUEUESEL_Q0 |
+				RXCS_ENABLE |
+				RXCS_QST);
+}
+
+static void
+jme_disable_rx_engine(struct jme_adapter *jme)
+{
+	int i;
+	u32 val;
+
+	/*
+	 * Disable RX Engine
+	 */
+	jwrite32(jme, JME_RXCS, jme->reg_rxcs);
+	wmb();
+
+	val = jread32(jme, JME_RXCS);
+	for (i = JME_RX_DISABLE_TIMEOUT ; (val & RXCS_ENABLE) && i > 0 ; --i) {
+		mdelay(1);
+		val = jread32(jme, JME_RXCS);
+		rmb();
+	}
+
+	if (!i)
+		DBG("Disable RX engine timeout.\n");
+
+}
+
+static void
+jme_refill_rx_ring(struct jme_adapter *jme, int curhole)
+{
+	struct jme_ring *rxring = &jme->rxring;
+	int i = rxring->next_to_fill;
+	struct io_buffer **bufinf = rxring->bufinf;
+	int mask = jme->rx_ring_mask;
+	int limit = jme->rx_ring_size;
+
+	while (limit--) {
+		if (!bufinf[i]) {
+			if (jme_make_new_rx_buf(bufinf + i))
+				break;
+			jme_set_clean_rxdesc(jme, i);
+		}
+		if (i == curhole)
+			limit = 0;
+		i = (i + 1) & mask;
+	}
+	rxring->next_to_fill = i;
+}
+
+static void
+jme_alloc_and_feed_iob(struct jme_adapter *jme, int idx)
+{
+	struct jme_ring *rxring = &jme->rxring;
+	struct rxdesc *rxdesc = rxring->desc;
+	struct io_buffer *rxbi = rxring->bufinf[idx];
+	struct net_device *netdev = jme->mii_if.dev;
+	int framesize;
+
+	rxdesc += idx;
+
+	framesize = le16_to_cpu(rxdesc->descwb.framesize);
+	iob_put(rxbi, framesize);
+	netdev_rx(netdev, rxbi);
+
+	rxring->bufinf[idx] = NULL;
+	jme_refill_rx_ring(jme, idx);
+}
+
+static void
+jme_process_receive(struct jme_adapter *jme)
+{
+	struct jme_ring *rxring = &jme->rxring;
+	struct rxdesc *rxdesc = rxring->desc;
+	struct net_device *netdev = jme->mii_if.dev;
+	int i, j, ccnt, desccnt, mask = jme->rx_ring_mask;
+	unsigned int limit = jme->rx_ring_size;
+
+	i = rxring->next_to_clean;
+	rxdesc += i;
+	while (rxring->bufinf[i] &&
+		!(rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_OWN)) &&
+		(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL) &&
+		limit--) {
+
+		rmb();
+		desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
+		DBG2("Cleaning rx desc=%d, cnt=%d\n", i, desccnt);
+
+		if (desccnt > 1 || rxdesc->descwb.errstat & RXWBERR_ALLERR) {
+			for (j = i, ccnt = desccnt ; ccnt-- ; ) {
+				jme_set_clean_rxdesc(jme, j);
+				j = (j + 1) & (mask);
+			}
+			DBG("Dropped packet due to ");
+			if (desccnt > 1)
+				DBG("long packet.(%d descriptors)\n", desccnt);
+			else
+				DBG("Packet error.\n");
+			netdev_rx_err(netdev, NULL, -EINVAL);
+		} else {
+			jme_alloc_and_feed_iob(jme, i);
+		}
+
+		i = (i + desccnt) & (mask);
+		rxdesc = rxring->desc;
+		rxdesc += i;
+	}
+	rxring->next_to_clean = i;
+
+	return;
+}
+
+static void
+jme_set_custom_macaddr(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev->priv;
+	uint8_t *addr = netdev->ll_addr;
+	u32 val;
+
+	val = (addr[3] & 0xff) << 24 |
+	      (addr[2] & 0xff) << 16 |
+	      (addr[1] & 0xff) <<  8 |
+	      (addr[0] & 0xff);
+	jwrite32(jme, JME_RXUMA_LO, val);
+	val = (addr[5] & 0xff) << 8 |
+	      (addr[4] & 0xff);
+	jwrite32(jme, JME_RXUMA_HI, val);
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int
+jme_open(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev->priv;
+	int rc;
+
+	/*
+	 * Allocate receive resources
+	 */
+	rc = jme_alloc_rx_resources(jme);
+	if (rc) {
+		DBG("Allocate receive resources error.\n");
+		goto nomem_out;
+	}
+
+	/*
+	 * Allocate transmit resources
+	 */
+	rc = jme_alloc_tx_resources(jme);
+	if (rc) {
+		DBG("Allocate transmit resources error.\n");
+		goto free_rx_resources_out;
+	}
+
+	jme_set_custom_macaddr(netdev);
+	jme_reset_phy_processor(jme);
+	jme_restart_an(jme);
+
+	return 0;
+
+free_rx_resources_out:
+	jme_free_rx_resources(jme);
+nomem_out:
+	return rc;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void
+jme_close(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev->priv;
+
+	jme_free_tx_resources(jme);
+	jme_free_rx_resources(jme);
+	jme_reset_mac_processor(jme);
+	jme->phylink = 0;
+	jme_phy_off(jme);
+	netdev_link_down(netdev);
+}
+
+static int
+jme_alloc_txdesc(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+	int idx;
+
+	idx = txring->next_to_use;
+	if (txring->nr_free < 1)
+		return -1;
+	--(txring->nr_free);
+	txring->next_to_use = (txring->next_to_use + 1) & jme->tx_ring_mask;
+
+	return idx;
+}
+
+static void
+jme_fill_tx_desc(struct jme_adapter *jme, struct io_buffer *iob, int idx)
+{
+	struct jme_ring *txring = &jme->txring;
+	struct txdesc *txdesc = txring->desc;
+	uint16_t len = iob_len(iob);
+	unsigned long int mapping;
+
+	txdesc += idx;
+	mapping = virt_to_bus(iob->data);
+	DBG2("TX buffer address: %p(%08lx+%x)\n",
+			iob->data, mapping, len);
+	txdesc->dw[0] = 0;
+	txdesc->dw[1] = 0;
+	txdesc->dw[2] = 0;
+	txdesc->dw[3] = 0;
+	txdesc->desc1.datalen	= cpu_to_le16(len);
+	txdesc->desc1.pktsize	= cpu_to_le16(len);
+	txdesc->desc1.bufaddr	= cpu_to_le32(mapping);
+	/*
+	 * Set OWN bit at final.
+	 * When kernel transmit faster than NIC.
+	 * And NIC trying to send this descriptor before we tell
+	 * it to start sending this TX queue.
+	 * Other fields are already filled correctly.
+	 */
+	wmb();
+	txdesc->desc1.flags = TXFLAG_OWN | TXFLAG_INT;
+	/*
+	 * Set tx buffer info after telling NIC to send
+	 * For better tx_clean timing
+	 */
+	wmb();
+	txring->bufinf[idx] = iob;
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int
+jme_transmit(struct net_device *netdev, struct io_buffer *iobuf)
+{
+	struct jme_adapter *jme = netdev->priv;
+	int idx;
+
+	idx = jme_alloc_txdesc(jme);
+	if (idx < 0) {
+		/*
+		 * Pause transmit queue somehow if possible.
+		 */
+		DBG("TX ring full!\n");
+		return -EOVERFLOW;
+	}
+
+	jme_fill_tx_desc(jme, iobuf, idx);
+
+	jwrite32(jme, JME_TXCS, jme->reg_txcs |
+				TXCS_SELECT_QUEUE0 |
+				TXCS_QUEUE0S |
+				TXCS_ENABLE);
+	DBG2("xmit: idx=%d\n", idx);
+
+	return 0;
+}
+
+static int
+jme_check_link(struct net_device *netdev, int testonly)
+{
+	struct jme_adapter *jme = netdev->priv;
+	u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, gpreg1;
+	int rc = 0;
+
+	phylink = jread32(jme, JME_PHY_LINK);
+
+	if (phylink & PHY_LINK_UP) {
+		/*
+		 * Keep polling for speed/duplex resolve complete
+		 */
+		while (!(phylink & PHY_LINK_SPEEDDPU_RESOLVED) &&
+			--cnt) {
+
+			udelay(1);
+			phylink = jread32(jme, JME_PHY_LINK);
+		}
+		if (!cnt)
+			DBG("Waiting speed resolve timeout.\n");
+
+		if (jme->phylink == phylink) {
+			rc = 1;
+			goto out;
+		}
+		if (testonly)
+			goto out;
+
+		jme->phylink = phylink;
+
+		ghc = jme->reg_ghc & ~(GHC_SPEED | GHC_DPX |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE |
+				GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY);
+		switch (phylink & PHY_LINK_SPEED_MASK) {
+		case PHY_LINK_SPEED_10M:
+			ghc |= GHC_SPEED_10M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
+			break;
+		case PHY_LINK_SPEED_100M:
+			ghc |= GHC_SPEED_100M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
+			break;
+		case PHY_LINK_SPEED_1000M:
+			ghc |= GHC_SPEED_1000M |
+				GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY;
+			break;
+		default:
+			break;
+		}
+
+		if (phylink & PHY_LINK_DUPLEX) {
+			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT);
+			ghc |= GHC_DPX;
+		} else {
+			jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT |
+						TXMCS_BACKOFF |
+						TXMCS_CARRIERSENSE |
+						TXMCS_COLLISION);
+			jwrite32(jme, JME_TXTRHD, TXTRHD_TXPEN |
+				((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) |
+				TXTRHD_TXREN |
+				((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL));
+		}
+
+		gpreg1 = GPREG1_DEFAULT;
+		if (is_buggy250(jme->pdev->device, jme->chiprev)) {
+			if (!(phylink & PHY_LINK_DUPLEX))
+				gpreg1 |= GPREG1_HALFMODEPATCH;
+			switch (phylink & PHY_LINK_SPEED_MASK) {
+			case PHY_LINK_SPEED_10M:
+				jme_set_phyfifoa(jme);
+				gpreg1 |= GPREG1_RSSPATCH;
+				break;
+			case PHY_LINK_SPEED_100M:
+				jme_set_phyfifob(jme);
+				gpreg1 |= GPREG1_RSSPATCH;
+				break;
+			case PHY_LINK_SPEED_1000M:
+				jme_set_phyfifoa(jme);
+				break;
+			default:
+				break;
+			}
+		}
+
+		jwrite32(jme, JME_GPREG1, gpreg1);
+		jwrite32(jme, JME_GHC, ghc);
+		jme->reg_ghc = ghc;
+
+		DBG("Link is up at %d Mbps, %s-Duplex, MDI%s.\n",
+		    ((phylink & PHY_LINK_SPEED_MASK)
+			     == PHY_LINK_SPEED_1000M) ? 1000 :
+		    ((phylink & PHY_LINK_SPEED_MASK)
+			     == PHY_LINK_SPEED_100M)  ? 100  : 10,
+		    (phylink & PHY_LINK_DUPLEX) ? "Full" : "Half",
+		    (phylink & PHY_LINK_MDI_STAT) ? "-X" : "");
+		netdev_link_up(netdev);
+	} else {
+		if (testonly)
+			goto out;
+
+		DBG("Link is down.\n");
+		jme->phylink = 0;
+		netdev_link_down(netdev);
+	}
+
+out:
+	return rc;
+}
+
+static void
+jme_link_change(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev->priv;
+
+	/*
+	 * Do nothing if the link status did not change.
+	 */
+	if (jme_check_link(netdev, 1))
+		return;
+
+	if (netdev_link_ok(netdev)) {
+		netdev_link_down(netdev);
+		jme_disable_rx_engine(jme);
+		jme_disable_tx_engine(jme);
+		jme_reset_ghc_speed(jme);
+		jme_reset_mac_processor(jme);
+	}
+
+	jme_check_link(netdev, 0);
+	if (netdev_link_ok(netdev)) {
+		jme_init_rx_ring(jme);
+		jme_enable_rx_engine(jme);
+		jme_init_tx_ring(jme);
+		jme_enable_tx_engine(jme);
+	}
+
+	return;
+}
+
+static void
+jme_tx_clean(struct jme_adapter *jme)
+{
+	struct jme_ring *txring = &jme->txring;
+	struct txdesc *txdesc = txring->desc;
+	struct io_buffer *txbi;
+	struct net_device *netdev = jme->mii_if.dev;
+	int i, cnt = 0, max, err, mask;
+
+	max = jme->tx_ring_size - txring->nr_free;
+	mask = jme->tx_ring_mask;
+
+	for (i = txring->next_to_clean ; cnt < max ; ++cnt) {
+
+		txbi = txring->bufinf[i];
+
+		if (txbi && !(txdesc[i].descwb.flags & TXWBFLAG_OWN)) {
+			DBG2("TX clean address: %08lx(%08lx+%zx)\n",
+					(unsigned long)txbi->data,
+					virt_to_bus(txbi->data),
+					iob_len(txbi));
+			err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR;
+			if (err)
+				netdev_tx_complete_err(netdev, txbi, -EIO);
+			else
+				netdev_tx_complete(netdev, txbi);
+			txring->bufinf[i] = NULL;
+		} else {
+			break;
+		}
+
+		i = (i + 1) & mask;
+	}
+
+	DBG2("txclean: next %d\n", i);
+	txring->next_to_clean = i;
+	txring->nr_free += cnt;
+}
+/**
+ * Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void
+jme_poll(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev->priv;
+	u32 intrstat;
+
+	intrstat = jread32(jme, JME_IEVE);
+
+	/*
+	 * Check if any actions needs to perform.
+	 */
+	if ((intrstat & INTR_ENABLE) == 0)
+		return;
+
+	/*
+	 * Check if the device still exist
+	 */
+	if (intrstat == ~((typeof(intrstat))0))
+		return;
+
+	DBG2("intrstat 0x%08x\n", intrstat);
+	if (intrstat & (INTR_LINKCH | INTR_SWINTR)) {
+		DBG2("Link changed\n");
+		jme_link_change(netdev);
+
+		/*
+		 * Clear all interrupt status
+		 */
+		jwrite32(jme, JME_IEVE, intrstat);
+
+		/*
+		 * Link change event is critical
+		 * all other events are ignored
+		 */
+		return;
+	}
+
+	/*
+	 * Process transmission complete first to free more memory.
+	 */
+	if (intrstat & INTR_TX0) {
+		DBG2("Packet transmit complete\n");
+		jme_tx_clean(jme);
+		jwrite32(jme, JME_IEVE, intrstat & INTR_TX0);
+	}
+
+	if (intrstat & (INTR_RX0 | INTR_RX0EMP)) {
+		DBG2("Packet received\n");
+		jme_process_receive(jme);
+		jwrite32(jme, JME_IEVE,
+			intrstat & (INTR_RX0 | INTR_RX0EMP));
+		if (intrstat & INTR_RX0EMP)
+			jme_restart_rx_engine(jme);
+	}
+
+	/*
+	 * Clean all other interrupt status
+	 */
+	jwrite32(jme, JME_IEVE,
+		intrstat & ~(INTR_RX0 | INTR_RX0EMP | INTR_TX0));
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev	Network device
+ * @v enable	Interrupts should be enabled
+ */
+static void
+jme_irq(struct net_device *netdev, int enable)
+{
+	struct jme_adapter *jme = netdev->priv;
+
+	DBG("jme interrupts %s\n", (enable ? "enabled" : "disabled"));
+	if (enable)
+		jme_start_irq(jme);
+	else
+		jme_stop_irq(jme);
+}
+
+/** JME net device operations */
+static struct net_device_operations jme_operations = {
+	.open		= jme_open,
+	.close		= jme_close,
+	.transmit	= jme_transmit,
+	.poll		= jme_poll,
+	.irq		= jme_irq,
+};
+
+static void
+jme_check_hw_ver(struct jme_adapter *jme)
+{
+	u32 chipmode;
+
+	chipmode = jread32(jme, JME_CHIPMODE);
+
+	jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT;
+	jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT;
+}
+
+static int
+jme_reload_eeprom(struct jme_adapter *jme)
+{
+	u32 val;
+	int i;
+
+	val = jread32(jme, JME_SMBCSR);
+
+	if (val & SMBCSR_EEPROMD) {
+		val |= SMBCSR_CNACK;
+		jwrite32(jme, JME_SMBCSR, val);
+		val |= SMBCSR_RELOAD;
+		jwrite32(jme, JME_SMBCSR, val);
+		mdelay(12);
+
+		for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) {
+			mdelay(1);
+			if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0)
+				break;
+		}
+
+		if (i == 0) {
+			DBG("eeprom reload timeout\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void
+jme_load_macaddr(struct net_device *netdev)
+{
+	struct jme_adapter *jme = netdev_priv(netdev);
+	unsigned char macaddr[6];
+	u32 val;
+
+	val = jread32(jme, JME_RXUMA_LO);
+	macaddr[0] = (val >>  0) & 0xFF;
+	macaddr[1] = (val >>  8) & 0xFF;
+	macaddr[2] = (val >> 16) & 0xFF;
+	macaddr[3] = (val >> 24) & 0xFF;
+	val = jread32(jme, JME_RXUMA_HI);
+	macaddr[4] = (val >>  0) & 0xFF;
+	macaddr[5] = (val >>  8) & 0xFF;
+	memcpy(netdev->hw_addr, macaddr, 6);
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci	PCI device
+ * @v id	PCI ID
+ * @ret rc	Return status code
+ */
+static int
+jme_probe(struct pci_device *pci)
+{
+	struct net_device *netdev;
+	struct jme_adapter *jme;
+	int rc;
+	uint8_t mrrs;
+
+	/* Allocate net device */
+	netdev = alloc_etherdev(sizeof(*jme));
+	if (!netdev)
+		return -ENOMEM;
+	netdev_init(netdev, &jme_operations);
+	jme = netdev->priv;
+	pci_set_drvdata(pci, netdev);
+	netdev->dev = &pci->dev;
+	jme->regs = ioremap(pci->membase, JME_REGS_SIZE);
+	if (!(jme->regs)) {
+		DBG("Mapping PCI resource region error.\n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	jme->reg_ghc = 0;
+	jme->reg_rxcs = RXCS_DEFAULT;
+	jme->reg_rxmcs = RXMCS_DEFAULT;
+	jme->phylink = 0;
+	jme->pdev = pci;
+	jme->mii_if.dev = netdev;
+	jme->mii_if.phy_id = 1;
+	jme->mii_if.mdio_read = jme_mdio_read;
+	jme->mii_if.mdio_write = jme_mdio_write;
+	jme->rx_ring_size = 1 << 4;
+	jme->rx_ring_mask = jme->rx_ring_size - 1;
+	jme->tx_ring_size = 1 << 4;
+	jme->tx_ring_mask = jme->tx_ring_size - 1;
+
+	/* Fix up PCI device */
+	adjust_pci_device(pci);
+
+	/*
+	 * Get Max Read Req Size from PCI Config Space
+	 */
+	pci_read_config_byte(pci, PCI_DCSR_MRRS, &mrrs);
+	mrrs &= PCI_DCSR_MRRS_MASK;
+	switch (mrrs) {
+	case MRRS_128B:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_128B;
+		break;
+	case MRRS_256B:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_256B;
+		break;
+	default:
+		jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B;
+		break;
+	};
+
+	/*
+	 * Get basic hardware info.
+	 */
+	jme_check_hw_ver(jme);
+	if (pci->device == PCI_DEVICE_ID_JMICRON_JMC250)
+		jme->mii_if.supports_gmii = 1;
+	else
+		jme->mii_if.supports_gmii = 0;
+
+	/*
+	 * Initialize PHY
+	 */
+	jme_set_phyfifoa(jme);
+	jme_phy_init(jme);
+
+	/*
+	 * Bring down phy before interface is opened.
+	 */
+	jme_phy_off(jme);
+
+	/*
+	 * Reset MAC processor and reload EEPROM for MAC Address
+	 */
+	jme_reset_mac_processor(jme);
+	rc = jme_reload_eeprom(jme);
+	if (rc) {
+		DBG("Reload eeprom for reading MAC Address error.\n");
+		goto err_unmap;
+	}
+	jme_load_macaddr(netdev);
+
+	/* Register network device */
+	if ((rc = register_netdev(netdev)) != 0) {
+		DBG("Register net_device error.\n");
+		goto err_unmap;
+	}
+
+	return 0;
+
+err_unmap:
+	iounmap(jme->regs);
+err_out:
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci	PCI device
+ */
+static void
+jme_remove(struct pci_device *pci)
+{
+	struct net_device *netdev = pci_get_drvdata(pci);
+	struct jme_adapter *jme = netdev->priv;
+
+	iounmap(jme->regs);
+	unregister_netdev(netdev);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+static struct pci_device_id jm_nics[] = {
+PCI_ROM(0x197b, 0x0250, "jme",  "JMicron Gigabit Ethernet", 0),
+PCI_ROM(0x197b, 0x0260, "jmfe", "JMicron Fast Ethernet",    0),
+};
+
+struct pci_driver jme_driver __pci_driver = {
+        .ids = jm_nics,
+        .id_count = ( sizeof ( jm_nics ) / sizeof ( jm_nics[0] ) ),
+        .probe = jme_probe,
+        .remove = jme_remove,
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.h
new file mode 100644
index 0000000..7e22543
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/jme.h
@@ -0,0 +1,914 @@
+/*
+ * JMicron JMC2x0 series PCIe Ethernet gPXE Device Driver
+ *
+ * Copyright 2010 Guo-Fu Tseng <cooldavid at cooldavid.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef __JME_H_INCLUDED__
+#define __JME_H_INCLUDED__
+
+#define PCI_VENDOR_ID_JMICRON		0x197b
+#define PCI_DEVICE_ID_JMICRON_JMC250	0x0250
+#define PCI_DEVICE_ID_JMICRON_JMC260	0x0260
+
+/*
+ * Extra PCI Configuration space interface
+ */
+#define PCI_DCSR_MRRS		0x59
+#define PCI_DCSR_MRRS_MASK	0x70
+
+enum pci_dcsr_mrrs_vals {
+	MRRS_128B	= 0x00,
+	MRRS_256B	= 0x10,
+	MRRS_512B	= 0x20,
+	MRRS_1024B	= 0x30,
+	MRRS_2048B	= 0x40,
+	MRRS_4096B	= 0x50,
+};
+
+/*
+ * TX/RX Descriptors
+ *
+ * TX/RX Ring DESC Count Must be multiple of 16 and <= 1024
+ */
+#define RING_DESC_ALIGN		16	/* Descriptor alignment */
+#define TX_DESC_SIZE		16
+
+struct txdesc {
+	union {
+		uint8_t		all[16];
+		uint32_t	dw[4];
+		struct {
+			/* DW0 */
+			uint16_t	vlan;
+			uint8_t		rsv1;
+			uint8_t		flags;
+
+			/* DW1 */
+			uint16_t	datalen;
+			uint16_t	mss;
+
+			/* DW2 */
+			uint16_t	pktsize;
+			uint16_t	rsv2;
+
+			/* DW3 */
+			uint32_t	bufaddr;
+		} desc1;
+		struct {
+			/* DW0 */
+			uint16_t	rsv1;
+			uint8_t		rsv2;
+			uint8_t		flags;
+
+			/* DW1 */
+			uint16_t	datalen;
+			uint16_t	rsv3;
+
+			/* DW2 */
+			uint32_t	bufaddrh;
+
+			/* DW3 */
+			uint32_t	bufaddrl;
+		} desc2;
+		struct {
+			/* DW0 */
+			uint8_t		ehdrsz;
+			uint8_t		rsv1;
+			uint8_t		rsv2;
+			uint8_t		flags;
+
+			/* DW1 */
+			uint16_t	trycnt;
+			uint16_t	segcnt;
+
+			/* DW2 */
+			uint16_t	pktsz;
+			uint16_t	rsv3;
+
+			/* DW3 */
+			uint32_t	bufaddrl;
+		} descwb;
+	};
+};
+
+enum jme_txdesc_flags_bits {
+	TXFLAG_OWN	= 0x80,
+	TXFLAG_INT	= 0x40,
+	TXFLAG_64BIT	= 0x20,
+	TXFLAG_TCPCS	= 0x10,
+	TXFLAG_UDPCS	= 0x08,
+	TXFLAG_IPCS	= 0x04,
+	TXFLAG_LSEN	= 0x02,
+	TXFLAG_TAGON	= 0x01,
+};
+
+#define TXDESC_MSS_SHIFT	2
+enum jme_txwbdesc_flags_bits {
+	TXWBFLAG_OWN	= 0x80,
+	TXWBFLAG_INT	= 0x40,
+	TXWBFLAG_TMOUT	= 0x20,
+	TXWBFLAG_TRYOUT	= 0x10,
+	TXWBFLAG_COL	= 0x08,
+
+	TXWBFLAG_ALLERR	= TXWBFLAG_TMOUT |
+			  TXWBFLAG_TRYOUT |
+			  TXWBFLAG_COL,
+};
+
+#define RX_DESC_SIZE		16
+#define RX_BUF_DMA_ALIGN	8
+#define RX_PREPAD_SIZE		10
+#define ETH_CRC_LEN		2
+#define RX_VLANHDR_LEN		2
+#define RX_EXTRA_LEN		(ETH_HLEN + \
+				ETH_CRC_LEN + \
+				RX_VLANHDR_LEN + \
+				RX_BUF_DMA_ALIGN)
+#define FIXED_MTU		1500
+#define RX_ALLOC_LEN		(FIXED_MTU + RX_EXTRA_LEN)
+
+struct rxdesc {
+	union {
+		uint8_t		all[16];
+		uint32_t	dw[4];
+		struct {
+			/* DW0 */
+			uint16_t	rsv2;
+			uint8_t		rsv1;
+			uint8_t		flags;
+
+			/* DW1 */
+			uint16_t	datalen;
+			uint16_t	wbcpl;
+
+			/* DW2 */
+			uint32_t	bufaddrh;
+
+			/* DW3 */
+			uint32_t	bufaddrl;
+		} desc1;
+		struct {
+			/* DW0 */
+			uint16_t	vlan;
+			uint16_t	flags;
+
+			/* DW1 */
+			uint16_t	framesize;
+			uint8_t		errstat;
+			uint8_t		desccnt;
+
+			/* DW2 */
+			uint32_t	rsshash;
+
+			/* DW3 */
+			uint8_t		hashfun;
+			uint8_t		hashtype;
+			uint16_t	resrv;
+		} descwb;
+	};
+};
+
+enum jme_rxdesc_flags_bits {
+	RXFLAG_OWN	= 0x80,
+	RXFLAG_INT	= 0x40,
+	RXFLAG_64BIT	= 0x20,
+};
+
+enum jme_rxwbdesc_flags_bits {
+	RXWBFLAG_OWN		= 0x8000,
+	RXWBFLAG_INT		= 0x4000,
+	RXWBFLAG_MF		= 0x2000,
+	RXWBFLAG_64BIT		= 0x2000,
+	RXWBFLAG_TCPON		= 0x1000,
+	RXWBFLAG_UDPON		= 0x0800,
+	RXWBFLAG_IPCS		= 0x0400,
+	RXWBFLAG_TCPCS		= 0x0200,
+	RXWBFLAG_UDPCS		= 0x0100,
+	RXWBFLAG_TAGON		= 0x0080,
+	RXWBFLAG_IPV4		= 0x0040,
+	RXWBFLAG_IPV6		= 0x0020,
+	RXWBFLAG_PAUSE		= 0x0010,
+	RXWBFLAG_MAGIC		= 0x0008,
+	RXWBFLAG_WAKEUP		= 0x0004,
+	RXWBFLAG_DEST		= 0x0003,
+	RXWBFLAG_DEST_UNI	= 0x0001,
+	RXWBFLAG_DEST_MUL	= 0x0002,
+	RXWBFLAG_DEST_BRO	= 0x0003,
+};
+
+enum jme_rxwbdesc_desccnt_mask {
+	RXWBDCNT_WBCPL	= 0x80,
+	RXWBDCNT_DCNT	= 0x7F,
+};
+
+enum jme_rxwbdesc_errstat_bits {
+	RXWBERR_LIMIT	= 0x80,
+	RXWBERR_MIIER	= 0x40,
+	RXWBERR_NIBON	= 0x20,
+	RXWBERR_COLON	= 0x10,
+	RXWBERR_ABORT	= 0x08,
+	RXWBERR_SHORT	= 0x04,
+	RXWBERR_OVERUN	= 0x02,
+	RXWBERR_CRCERR	= 0x01,
+	RXWBERR_ALLERR	= 0xFF,
+};
+
+/*
+ * The structure holding buffer information and ring descriptors all together.
+ */
+struct jme_ring {
+	void *desc;		/* pointer to ring memory  */
+	unsigned long dma;	/* phys address for ring dma */
+
+	/* Buffer information corresponding to each descriptor */
+	struct io_buffer **bufinf;
+
+	int next_to_clean;
+	int next_to_fill;
+	int next_to_use;
+	int nr_free;
+};
+
+/*
+ * Jmac Adapter Private data
+ */
+struct jme_adapter {
+	void			*regs;
+	struct mii_if_info	mii_if;
+	struct pci_device	*pdev;
+	unsigned int		fpgaver;
+	unsigned int		chiprev;
+	uint32_t		reg_ghc;
+	uint32_t		reg_txcs;
+	uint32_t		reg_rxcs;
+	uint32_t		reg_rxmcs;
+	uint32_t		phylink;
+	struct jme_ring		rxring;
+	uint32_t		rx_ring_size;
+	uint32_t		rx_ring_mask;
+	struct jme_ring		txring;
+	uint32_t		tx_ring_size;
+	uint32_t		tx_ring_mask;
+};
+
+/*
+ * I/O Resters
+ */
+enum jme_iomap_regs_value {
+	JME_REGS_SIZE	= 0x1000,
+};
+
+enum jme_iomap_offsets {
+	JME_MAC		= 0x0000,
+	JME_PHY		= 0x0400,
+	JME_MISC	= 0x0800,
+	JME_RSS		= 0x0C00,
+};
+
+enum jme_iomap_lens {
+	JME_MAC_LEN	= 0x80,
+	JME_PHY_LEN	= 0x58,
+	JME_MISC_LEN	= 0x98,
+	JME_RSS_LEN	= 0xFF,
+};
+
+enum jme_iomap_regs {
+	JME_TXCS	= JME_MAC | 0x00, /* Transmit Control and Status */
+	JME_TXDBA_LO	= JME_MAC | 0x04, /* Transmit Queue Desc Base Addr */
+	JME_TXDBA_HI	= JME_MAC | 0x08, /* Transmit Queue Desc Base Addr */
+	JME_TXQDC	= JME_MAC | 0x0C, /* Transmit Queue Desc Count */
+	JME_TXNDA	= JME_MAC | 0x10, /* Transmit Queue Next Desc Addr */
+	JME_TXMCS	= JME_MAC | 0x14, /* Transmit MAC Control Status */
+	JME_TXPFC	= JME_MAC | 0x18, /* Transmit Pause Frame Control */
+	JME_TXTRHD	= JME_MAC | 0x1C, /* Transmit Timer/Retry at Half-Dup */
+
+	JME_RXCS	= JME_MAC | 0x20, /* Receive Control and Status */
+	JME_RXDBA_LO	= JME_MAC | 0x24, /* Receive Queue Desc Base Addr */
+	JME_RXDBA_HI	= JME_MAC | 0x28, /* Receive Queue Desc Base Addr */
+	JME_RXQDC	= JME_MAC | 0x2C, /* Receive Queue Desc Count */
+	JME_RXNDA	= JME_MAC | 0x30, /* Receive Queue Next Desc Addr */
+	JME_RXMCS	= JME_MAC | 0x34, /* Receive MAC Control Status */
+	JME_RXUMA_LO	= JME_MAC | 0x38, /* Receive Unicast MAC Address */
+	JME_RXUMA_HI	= JME_MAC | 0x3C, /* Receive Unicast MAC Address */
+	JME_RXMCHT_LO	= JME_MAC | 0x40, /* Recv Multicast Addr HashTable */
+	JME_RXMCHT_HI	= JME_MAC | 0x44, /* Recv Multicast Addr HashTable */
+	JME_WFODP	= JME_MAC | 0x48, /* Wakeup Frame Output Data Port */
+	JME_WFOI	= JME_MAC | 0x4C, /* Wakeup Frame Output Interface */
+
+	JME_SMI		= JME_MAC | 0x50, /* Station Management Interface */
+	JME_GHC		= JME_MAC | 0x54, /* Global Host Control */
+	JME_PMCS	= JME_MAC | 0x60, /* Power Management Control/Stat */
+
+
+	JME_PHY_CS	= JME_PHY | 0x28, /* PHY Ctrl and Status Register */
+	JME_PHY_LINK	= JME_PHY | 0x30, /* PHY Link Status Register */
+	JME_SMBCSR	= JME_PHY | 0x40, /* SMB Control and Status */
+	JME_SMBINTF	= JME_PHY | 0x44, /* SMB Interface */
+
+
+	JME_TMCSR	= JME_MISC | 0x00, /* Timer Control/Status Register */
+	JME_GPREG0	= JME_MISC | 0x08, /* General purpose REG-0 */
+	JME_GPREG1	= JME_MISC | 0x0C, /* General purpose REG-1 */
+	JME_IEVE	= JME_MISC | 0x20, /* Interrupt Event Status */
+	JME_IREQ	= JME_MISC | 0x24, /* Intr Req Status(For Debug) */
+	JME_IENS	= JME_MISC | 0x28, /* Intr Enable - Setting Port */
+	JME_IENC	= JME_MISC | 0x2C, /* Interrupt Enable - Clear Port */
+	JME_PCCRX0	= JME_MISC | 0x30, /* PCC Control for RX Queue 0 */
+	JME_PCCTX	= JME_MISC | 0x40, /* PCC Control for TX Queues */
+	JME_CHIPMODE	= JME_MISC | 0x44, /* Identify FPGA Version */
+	JME_SHBA_HI	= JME_MISC | 0x48, /* Shadow Register Base HI */
+	JME_SHBA_LO	= JME_MISC | 0x4C, /* Shadow Register Base LO */
+	JME_TIMER1	= JME_MISC | 0x70, /* Timer1 */
+	JME_TIMER2	= JME_MISC | 0x74, /* Timer2 */
+	JME_APMC	= JME_MISC | 0x7C, /* Aggressive Power Mode Control */
+	JME_PCCSRX0	= JME_MISC | 0x80, /* PCC Status of RX0 */
+};
+
+/*
+ * TX Control/Status Bits
+ */
+enum jme_txcs_bits {
+	TXCS_QUEUE7S	= 0x00008000,
+	TXCS_QUEUE6S	= 0x00004000,
+	TXCS_QUEUE5S	= 0x00002000,
+	TXCS_QUEUE4S	= 0x00001000,
+	TXCS_QUEUE3S	= 0x00000800,
+	TXCS_QUEUE2S	= 0x00000400,
+	TXCS_QUEUE1S	= 0x00000200,
+	TXCS_QUEUE0S	= 0x00000100,
+	TXCS_FIFOTH	= 0x000000C0,
+	TXCS_DMASIZE	= 0x00000030,
+	TXCS_BURST	= 0x00000004,
+	TXCS_ENABLE	= 0x00000001,
+};
+
+enum jme_txcs_value {
+	TXCS_FIFOTH_16QW	= 0x000000C0,
+	TXCS_FIFOTH_12QW	= 0x00000080,
+	TXCS_FIFOTH_8QW		= 0x00000040,
+	TXCS_FIFOTH_4QW		= 0x00000000,
+
+	TXCS_DMASIZE_64B	= 0x00000000,
+	TXCS_DMASIZE_128B	= 0x00000010,
+	TXCS_DMASIZE_256B	= 0x00000020,
+	TXCS_DMASIZE_512B	= 0x00000030,
+
+	TXCS_SELECT_QUEUE0	= 0x00000000,
+	TXCS_SELECT_QUEUE1	= 0x00010000,
+	TXCS_SELECT_QUEUE2	= 0x00020000,
+	TXCS_SELECT_QUEUE3	= 0x00030000,
+	TXCS_SELECT_QUEUE4	= 0x00040000,
+	TXCS_SELECT_QUEUE5	= 0x00050000,
+	TXCS_SELECT_QUEUE6	= 0x00060000,
+	TXCS_SELECT_QUEUE7	= 0x00070000,
+
+	TXCS_DEFAULT		= TXCS_FIFOTH_4QW |
+				  TXCS_BURST,
+};
+
+#define JME_TX_DISABLE_TIMEOUT 10 /* 10 msec */
+
+/*
+ * TX MAC Control/Status Bits
+ */
+enum jme_txmcs_bit_masks {
+	TXMCS_IFG2		= 0xC0000000,
+	TXMCS_IFG1		= 0x30000000,
+	TXMCS_TTHOLD		= 0x00000300,
+	TXMCS_FBURST		= 0x00000080,
+	TXMCS_CARRIEREXT	= 0x00000040,
+	TXMCS_DEFER		= 0x00000020,
+	TXMCS_BACKOFF		= 0x00000010,
+	TXMCS_CARRIERSENSE	= 0x00000008,
+	TXMCS_COLLISION		= 0x00000004,
+	TXMCS_CRC		= 0x00000002,
+	TXMCS_PADDING		= 0x00000001,
+};
+
+enum jme_txmcs_values {
+	TXMCS_IFG2_6_4		= 0x00000000,
+	TXMCS_IFG2_8_5		= 0x40000000,
+	TXMCS_IFG2_10_6		= 0x80000000,
+	TXMCS_IFG2_12_7		= 0xC0000000,
+
+	TXMCS_IFG1_8_4		= 0x00000000,
+	TXMCS_IFG1_12_6		= 0x10000000,
+	TXMCS_IFG1_16_8		= 0x20000000,
+	TXMCS_IFG1_20_10	= 0x30000000,
+
+	TXMCS_TTHOLD_1_8	= 0x00000000,
+	TXMCS_TTHOLD_1_4	= 0x00000100,
+	TXMCS_TTHOLD_1_2	= 0x00000200,
+	TXMCS_TTHOLD_FULL	= 0x00000300,
+
+	TXMCS_DEFAULT		= TXMCS_IFG2_8_5 |
+				  TXMCS_IFG1_16_8 |
+				  TXMCS_TTHOLD_FULL |
+				  TXMCS_DEFER |
+				  TXMCS_CRC |
+				  TXMCS_PADDING,
+};
+
+enum jme_txpfc_bits_masks {
+	TXPFC_VLAN_TAG		= 0xFFFF0000,
+	TXPFC_VLAN_EN		= 0x00008000,
+	TXPFC_PF_EN		= 0x00000001,
+};
+
+enum jme_txtrhd_bits_masks {
+	TXTRHD_TXPEN		= 0x80000000,
+	TXTRHD_TXP		= 0x7FFFFF00,
+	TXTRHD_TXREN		= 0x00000080,
+	TXTRHD_TXRL		= 0x0000007F,
+};
+
+enum jme_txtrhd_shifts {
+	TXTRHD_TXP_SHIFT	= 8,
+	TXTRHD_TXRL_SHIFT	= 0,
+};
+
+/*
+ * RX Control/Status Bits
+ */
+enum jme_rxcs_bit_masks {
+	/* FIFO full threshold for transmitting Tx Pause Packet */
+	RXCS_FIFOTHTP	= 0x30000000,
+	/* FIFO threshold for processing next packet */
+	RXCS_FIFOTHNP	= 0x0C000000,
+	RXCS_DMAREQSZ	= 0x03000000, /* DMA Request Size */
+	RXCS_QUEUESEL	= 0x00030000, /* Queue selection */
+	RXCS_RETRYGAP	= 0x0000F000, /* RX Desc full retry gap */
+	RXCS_RETRYCNT	= 0x00000F00, /* RX Desc full retry counter */
+	RXCS_WAKEUP	= 0x00000040, /* Enable receive wakeup packet */
+	RXCS_MAGIC	= 0x00000020, /* Enable receive magic packet */
+	RXCS_SHORT	= 0x00000010, /* Enable receive short packet */
+	RXCS_ABORT	= 0x00000008, /* Enable receive errorr packet */
+	RXCS_QST	= 0x00000004, /* Receive queue start */
+	RXCS_SUSPEND	= 0x00000002,
+	RXCS_ENABLE	= 0x00000001,
+};
+
+enum jme_rxcs_values {
+	RXCS_FIFOTHTP_16T	= 0x00000000,
+	RXCS_FIFOTHTP_32T	= 0x10000000,
+	RXCS_FIFOTHTP_64T	= 0x20000000,
+	RXCS_FIFOTHTP_128T	= 0x30000000,
+
+	RXCS_FIFOTHNP_16QW	= 0x00000000,
+	RXCS_FIFOTHNP_32QW	= 0x04000000,
+	RXCS_FIFOTHNP_64QW	= 0x08000000,
+	RXCS_FIFOTHNP_128QW	= 0x0C000000,
+
+	RXCS_DMAREQSZ_16B	= 0x00000000,
+	RXCS_DMAREQSZ_32B	= 0x01000000,
+	RXCS_DMAREQSZ_64B	= 0x02000000,
+	RXCS_DMAREQSZ_128B	= 0x03000000,
+
+	RXCS_QUEUESEL_Q0	= 0x00000000,
+	RXCS_QUEUESEL_Q1	= 0x00010000,
+	RXCS_QUEUESEL_Q2	= 0x00020000,
+	RXCS_QUEUESEL_Q3	= 0x00030000,
+
+	RXCS_RETRYGAP_256ns	= 0x00000000,
+	RXCS_RETRYGAP_512ns	= 0x00001000,
+	RXCS_RETRYGAP_1024ns	= 0x00002000,
+	RXCS_RETRYGAP_2048ns	= 0x00003000,
+	RXCS_RETRYGAP_4096ns	= 0x00004000,
+	RXCS_RETRYGAP_8192ns	= 0x00005000,
+	RXCS_RETRYGAP_16384ns	= 0x00006000,
+	RXCS_RETRYGAP_32768ns	= 0x00007000,
+
+	RXCS_RETRYCNT_0		= 0x00000000,
+	RXCS_RETRYCNT_4		= 0x00000100,
+	RXCS_RETRYCNT_8		= 0x00000200,
+	RXCS_RETRYCNT_12	= 0x00000300,
+	RXCS_RETRYCNT_16	= 0x00000400,
+	RXCS_RETRYCNT_20	= 0x00000500,
+	RXCS_RETRYCNT_24	= 0x00000600,
+	RXCS_RETRYCNT_28	= 0x00000700,
+	RXCS_RETRYCNT_32	= 0x00000800,
+	RXCS_RETRYCNT_36	= 0x00000900,
+	RXCS_RETRYCNT_40	= 0x00000A00,
+	RXCS_RETRYCNT_44	= 0x00000B00,
+	RXCS_RETRYCNT_48	= 0x00000C00,
+	RXCS_RETRYCNT_52	= 0x00000D00,
+	RXCS_RETRYCNT_56	= 0x00000E00,
+	RXCS_RETRYCNT_60	= 0x00000F00,
+
+	RXCS_DEFAULT		= RXCS_FIFOTHTP_128T |
+				  RXCS_FIFOTHNP_128QW |
+				  RXCS_DMAREQSZ_128B |
+				  RXCS_RETRYGAP_256ns |
+				  RXCS_RETRYCNT_32,
+};
+
+#define JME_RX_DISABLE_TIMEOUT 10 /* 10 msec */
+
+/*
+ * RX MAC Control/Status Bits
+ */
+enum jme_rxmcs_bits {
+	RXMCS_ALLFRAME		= 0x00000800,
+	RXMCS_BRDFRAME		= 0x00000400,
+	RXMCS_MULFRAME		= 0x00000200,
+	RXMCS_UNIFRAME		= 0x00000100,
+	RXMCS_ALLMULFRAME	= 0x00000080,
+	RXMCS_MULFILTERED	= 0x00000040,
+	RXMCS_RXCOLLDEC		= 0x00000020,
+	RXMCS_FLOWCTRL		= 0x00000008,
+	RXMCS_VTAGRM		= 0x00000004,
+	RXMCS_PREPAD		= 0x00000002,
+	RXMCS_CHECKSUM		= 0x00000001,
+
+	RXMCS_DEFAULT		= RXMCS_VTAGRM |
+				  RXMCS_FLOWCTRL |
+				  RXMCS_CHECKSUM,
+};
+
+/*
+ * Wakeup Frame setup interface registers
+ */
+#define WAKEUP_FRAME_NR	8
+#define WAKEUP_FRAME_MASK_DWNR	4
+
+enum jme_wfoi_bit_masks {
+	WFOI_MASK_SEL		= 0x00000070,
+	WFOI_CRC_SEL		= 0x00000008,
+	WFOI_FRAME_SEL		= 0x00000007,
+};
+
+enum jme_wfoi_shifts {
+	WFOI_MASK_SHIFT		= 4,
+};
+
+/*
+ * SMI Related definitions
+ */
+enum jme_smi_bit_mask {
+	SMI_DATA_MASK		= 0xFFFF0000,
+	SMI_REG_ADDR_MASK	= 0x0000F800,
+	SMI_PHY_ADDR_MASK	= 0x000007C0,
+	SMI_OP_WRITE		= 0x00000020,
+	/* Set to 1, after req done it'll be cleared to 0 */
+	SMI_OP_REQ		= 0x00000010,
+	SMI_OP_MDIO		= 0x00000008, /* Software assess In/Out */
+	SMI_OP_MDOE		= 0x00000004, /* Software Output Enable */
+	SMI_OP_MDC		= 0x00000002, /* Software CLK Control */
+	SMI_OP_MDEN		= 0x00000001, /* Software access Enable */
+};
+
+enum jme_smi_bit_shift {
+	SMI_DATA_SHIFT		= 16,
+	SMI_REG_ADDR_SHIFT	= 11,
+	SMI_PHY_ADDR_SHIFT	= 6,
+};
+
+static inline uint32_t smi_reg_addr(int x)
+{
+	return (x << SMI_REG_ADDR_SHIFT) & SMI_REG_ADDR_MASK;
+}
+
+static inline uint32_t smi_phy_addr(int x)
+{
+	return (x << SMI_PHY_ADDR_SHIFT) & SMI_PHY_ADDR_MASK;
+}
+
+#define JME_PHY_TIMEOUT 100 /* 100 msec */
+#define JME_PHY_REG_NR 32
+
+/*
+ * Global Host Control
+ */
+enum jme_ghc_bit_mask {
+	GHC_SWRST		= 0x40000000,
+	GHC_DPX			= 0x00000040,
+	GHC_SPEED		= 0x00000030,
+	GHC_LINK_POLL		= 0x00000001,
+};
+
+enum jme_ghc_speed_val {
+	GHC_SPEED_10M		= 0x00000010,
+	GHC_SPEED_100M		= 0x00000020,
+	GHC_SPEED_1000M		= 0x00000030,
+};
+
+enum jme_ghc_to_clk {
+	GHC_TO_CLK_OFF		= 0x00000000,
+	GHC_TO_CLK_GPHY		= 0x00400000,
+	GHC_TO_CLK_PCIE		= 0x00800000,
+	GHC_TO_CLK_INVALID	= 0x00C00000,
+};
+
+enum jme_ghc_txmac_clk {
+	GHC_TXMAC_CLK_OFF	= 0x00000000,
+	GHC_TXMAC_CLK_GPHY	= 0x00100000,
+	GHC_TXMAC_CLK_PCIE	= 0x00200000,
+	GHC_TXMAC_CLK_INVALID	= 0x00300000,
+};
+
+/*
+ * Power management control and status register
+ */
+enum jme_pmcs_bit_masks {
+	PMCS_WF7DET	= 0x80000000,
+	PMCS_WF6DET	= 0x40000000,
+	PMCS_WF5DET	= 0x20000000,
+	PMCS_WF4DET	= 0x10000000,
+	PMCS_WF3DET	= 0x08000000,
+	PMCS_WF2DET	= 0x04000000,
+	PMCS_WF1DET	= 0x02000000,
+	PMCS_WF0DET	= 0x01000000,
+	PMCS_LFDET	= 0x00040000,
+	PMCS_LRDET	= 0x00020000,
+	PMCS_MFDET	= 0x00010000,
+	PMCS_WF7EN	= 0x00008000,
+	PMCS_WF6EN	= 0x00004000,
+	PMCS_WF5EN	= 0x00002000,
+	PMCS_WF4EN	= 0x00001000,
+	PMCS_WF3EN	= 0x00000800,
+	PMCS_WF2EN	= 0x00000400,
+	PMCS_WF1EN	= 0x00000200,
+	PMCS_WF0EN	= 0x00000100,
+	PMCS_LFEN	= 0x00000004,
+	PMCS_LREN	= 0x00000002,
+	PMCS_MFEN	= 0x00000001,
+};
+
+/*
+ * Giga PHY Status Registers
+ */
+enum jme_phy_link_bit_mask {
+	PHY_LINK_SPEED_MASK		= 0x0000C000,
+	PHY_LINK_DUPLEX			= 0x00002000,
+	PHY_LINK_SPEEDDPU_RESOLVED	= 0x00000800,
+	PHY_LINK_UP			= 0x00000400,
+	PHY_LINK_AUTONEG_COMPLETE	= 0x00000200,
+	PHY_LINK_MDI_STAT		= 0x00000040,
+};
+
+enum jme_phy_link_speed_val {
+	PHY_LINK_SPEED_10M		= 0x00000000,
+	PHY_LINK_SPEED_100M		= 0x00004000,
+	PHY_LINK_SPEED_1000M		= 0x00008000,
+};
+
+#define JME_SPDRSV_TIMEOUT	500	/* 500 us */
+
+/*
+ * SMB Control and Status
+ */
+enum jme_smbcsr_bit_mask {
+	SMBCSR_CNACK	= 0x00020000,
+	SMBCSR_RELOAD	= 0x00010000,
+	SMBCSR_EEPROMD	= 0x00000020,
+	SMBCSR_INITDONE	= 0x00000010,
+	SMBCSR_BUSY	= 0x0000000F,
+};
+
+enum jme_smbintf_bit_mask {
+	SMBINTF_HWDATR	= 0xFF000000,
+	SMBINTF_HWDATW	= 0x00FF0000,
+	SMBINTF_HWADDR	= 0x0000FF00,
+	SMBINTF_HWRWN	= 0x00000020,
+	SMBINTF_HWCMD	= 0x00000010,
+	SMBINTF_FASTM	= 0x00000008,
+	SMBINTF_GPIOSCL	= 0x00000004,
+	SMBINTF_GPIOSDA	= 0x00000002,
+	SMBINTF_GPIOEN	= 0x00000001,
+};
+
+enum jme_smbintf_vals {
+	SMBINTF_HWRWN_READ	= 0x00000020,
+	SMBINTF_HWRWN_WRITE	= 0x00000000,
+};
+
+enum jme_smbintf_shifts {
+	SMBINTF_HWDATR_SHIFT	= 24,
+	SMBINTF_HWDATW_SHIFT	= 16,
+	SMBINTF_HWADDR_SHIFT	= 8,
+};
+
+#define JME_EEPROM_RELOAD_TIMEOUT 2000 /* 2000 msec */
+#define JME_SMB_BUSY_TIMEOUT 20 /* 20 msec */
+#define JME_SMB_LEN 256
+#define JME_EEPROM_MAGIC 0x250
+
+/*
+ * Timer Control/Status Register
+ */
+enum jme_tmcsr_bit_masks {
+	TMCSR_SWIT	= 0x80000000,
+	TMCSR_EN	= 0x01000000,
+	TMCSR_CNT	= 0x00FFFFFF,
+};
+
+/*
+ * General Purpose REG-0
+ */
+enum jme_gpreg0_masks {
+	GPREG0_DISSH		= 0xFF000000,
+	GPREG0_PCIRLMT		= 0x00300000,
+	GPREG0_PCCNOMUTCLR	= 0x00040000,
+	GPREG0_LNKINTPOLL	= 0x00001000,
+	GPREG0_PCCTMR		= 0x00000300,
+	GPREG0_PHYADDR		= 0x0000001F,
+};
+
+enum jme_gpreg0_vals {
+	GPREG0_DISSH_DW7	= 0x80000000,
+	GPREG0_DISSH_DW6	= 0x40000000,
+	GPREG0_DISSH_DW5	= 0x20000000,
+	GPREG0_DISSH_DW4	= 0x10000000,
+	GPREG0_DISSH_DW3	= 0x08000000,
+	GPREG0_DISSH_DW2	= 0x04000000,
+	GPREG0_DISSH_DW1	= 0x02000000,
+	GPREG0_DISSH_DW0	= 0x01000000,
+	GPREG0_DISSH_ALL	= 0xFF000000,
+
+	GPREG0_PCIRLMT_8	= 0x00000000,
+	GPREG0_PCIRLMT_6	= 0x00100000,
+	GPREG0_PCIRLMT_5	= 0x00200000,
+	GPREG0_PCIRLMT_4	= 0x00300000,
+
+	GPREG0_PCCTMR_16ns	= 0x00000000,
+	GPREG0_PCCTMR_256ns	= 0x00000100,
+	GPREG0_PCCTMR_1us	= 0x00000200,
+	GPREG0_PCCTMR_1ms	= 0x00000300,
+
+	GPREG0_PHYADDR_1	= 0x00000001,
+
+	GPREG0_DEFAULT		= GPREG0_DISSH_ALL |
+				  GPREG0_PCIRLMT_4 |
+				  GPREG0_PCCTMR_1us |
+				  GPREG0_PHYADDR_1,
+};
+
+/*
+ * General Purpose REG-1
+ * Note: All theses bits defined here are for
+ *       Chip mode revision 0x11 only
+ */
+enum jme_gpreg1_masks {
+	GPREG1_INTRDELAYUNIT	= 0x00000018,
+	GPREG1_INTRDELAYENABLE	= 0x00000007,
+};
+
+enum jme_gpreg1_vals {
+	GPREG1_RSSPATCH		= 0x00000040,
+	GPREG1_HALFMODEPATCH	= 0x00000020,
+
+	GPREG1_INTDLYUNIT_16NS	= 0x00000000,
+	GPREG1_INTDLYUNIT_256NS	= 0x00000008,
+	GPREG1_INTDLYUNIT_1US	= 0x00000010,
+	GPREG1_INTDLYUNIT_16US	= 0x00000018,
+
+	GPREG1_INTDLYEN_1U	= 0x00000001,
+	GPREG1_INTDLYEN_2U	= 0x00000002,
+	GPREG1_INTDLYEN_3U	= 0x00000003,
+	GPREG1_INTDLYEN_4U	= 0x00000004,
+	GPREG1_INTDLYEN_5U	= 0x00000005,
+	GPREG1_INTDLYEN_6U	= 0x00000006,
+	GPREG1_INTDLYEN_7U	= 0x00000007,
+
+	GPREG1_DEFAULT		= 0x00000000,
+};
+
+/*
+ * Interrupt Status Bits
+ */
+enum jme_interrupt_bits {
+	INTR_SWINTR	= 0x80000000,
+	INTR_TMINTR	= 0x40000000,
+	INTR_LINKCH	= 0x20000000,
+	INTR_PAUSERCV	= 0x10000000,
+	INTR_MAGICRCV	= 0x08000000,
+	INTR_WAKERCV	= 0x04000000,
+	INTR_PCCRX0TO	= 0x02000000,
+	INTR_PCCRX1TO	= 0x01000000,
+	INTR_PCCRX2TO	= 0x00800000,
+	INTR_PCCRX3TO	= 0x00400000,
+	INTR_PCCTXTO	= 0x00200000,
+	INTR_PCCRX0	= 0x00100000,
+	INTR_PCCRX1	= 0x00080000,
+	INTR_PCCRX2	= 0x00040000,
+	INTR_PCCRX3	= 0x00020000,
+	INTR_PCCTX	= 0x00010000,
+	INTR_RX3EMP	= 0x00008000,
+	INTR_RX2EMP	= 0x00004000,
+	INTR_RX1EMP	= 0x00002000,
+	INTR_RX0EMP	= 0x00001000,
+	INTR_RX3	= 0x00000800,
+	INTR_RX2	= 0x00000400,
+	INTR_RX1	= 0x00000200,
+	INTR_RX0	= 0x00000100,
+	INTR_TX7	= 0x00000080,
+	INTR_TX6	= 0x00000040,
+	INTR_TX5	= 0x00000020,
+	INTR_TX4	= 0x00000010,
+	INTR_TX3	= 0x00000008,
+	INTR_TX2	= 0x00000004,
+	INTR_TX1	= 0x00000002,
+	INTR_TX0	= 0x00000001,
+};
+
+static const uint32_t INTR_ENABLE = INTR_LINKCH |
+				    INTR_RX0EMP |
+				    INTR_RX0 |
+				    INTR_TX0;
+
+/*
+ * PCC Control Registers
+ */
+enum jme_pccrx_masks {
+	PCCRXTO_MASK	= 0xFFFF0000,
+	PCCRX_MASK	= 0x0000FF00,
+};
+
+enum jme_pcctx_masks {
+	PCCTXTO_MASK	= 0xFFFF0000,
+	PCCTX_MASK	= 0x0000FF00,
+	PCCTX_QS_MASK	= 0x000000FF,
+};
+
+enum jme_pccrx_shifts {
+	PCCRXTO_SHIFT	= 16,
+	PCCRX_SHIFT	= 8,
+};
+
+enum jme_pcctx_shifts {
+	PCCTXTO_SHIFT	= 16,
+	PCCTX_SHIFT	= 8,
+};
+
+enum jme_pcctx_bits {
+	PCCTXQ0_EN	= 0x00000001,
+	PCCTXQ1_EN	= 0x00000002,
+	PCCTXQ2_EN	= 0x00000004,
+	PCCTXQ3_EN	= 0x00000008,
+	PCCTXQ4_EN	= 0x00000010,
+	PCCTXQ5_EN	= 0x00000020,
+	PCCTXQ6_EN	= 0x00000040,
+	PCCTXQ7_EN	= 0x00000080,
+};
+
+/*
+ * Chip Mode Register
+ */
+enum jme_chipmode_bit_masks {
+	CM_FPGAVER_MASK		= 0xFFFF0000,
+	CM_CHIPREV_MASK		= 0x0000FF00,
+	CM_CHIPMODE_MASK	= 0x0000000F,
+};
+
+enum jme_chipmode_shifts {
+	CM_FPGAVER_SHIFT	= 16,
+	CM_CHIPREV_SHIFT	= 8,
+};
+
+/*
+ * Workaround
+ */
+static inline int is_buggy250(unsigned short device, unsigned int chiprev)
+{
+	return device == PCI_DEVICE_ID_JMICRON_JMC250 && chiprev == 0x11;
+}
+
+/*
+ * Read/Write I/O Registers
+ */
+static inline uint32_t jread32(struct jme_adapter *jme, uint32_t reg)
+{
+	return readl(jme->regs + reg);
+}
+
+static inline void jwrite32(struct jme_adapter *jme, uint32_t reg, uint32_t val)
+{
+	writel(val, jme->regs + reg);
+}
+
+static void jwrite32f(struct jme_adapter *jme, uint32_t reg, uint32_t val)
+{
+	/*
+	 * Read after write should cause flush
+	 */
+	writel(val, jme->regs + reg);
+	readl(jme->regs + reg);
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/legacy.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/legacy.c
new file mode 100644
index 0000000..4edbef1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/legacy.c
@@ -0,0 +1,157 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <nic.h>
+
+/*
+ * Quick and dirty compatibility layer
+ *
+ * This should allow old-API PCI drivers to at least function until
+ * they are updated.  It will not help non-PCI drivers.
+ *
+ * No drivers should rely on this code.  It will be removed asap.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct nic nic;
+
+static int legacy_registered = 0;
+
+static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
+	struct nic *nic = netdev->priv;
+	struct ethhdr *ethhdr;
+
+	DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
+	iob_pad ( iobuf, ETH_ZLEN );
+	ethhdr = iobuf->data;
+	iob_pull ( iobuf, sizeof ( *ethhdr ) );
+	nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
+				ntohs ( ethhdr->h_protocol ),
+				iob_len ( iobuf ), iobuf->data );
+	netdev_tx_complete ( netdev, iobuf );
+	return 0;
+}
+
+static void legacy_poll ( struct net_device *netdev ) {
+	struct nic *nic = netdev->priv;
+	struct io_buffer *iobuf;
+
+	iobuf = alloc_iob ( ETH_FRAME_LEN );
+	if ( ! iobuf )
+		return;
+
+	nic->packet = iobuf->data;
+	if ( nic->nic_op->poll ( nic, 1 ) ) {
+		DBG ( "Received %d bytes\n", nic->packetlen );
+		iob_put ( iobuf, nic->packetlen );
+		netdev_rx ( netdev, iobuf );
+	} else {
+		free_iob ( iobuf );
+	}
+}
+
+static int legacy_open ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+	return 0;
+}
+
+static void legacy_close ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+}
+
+static void legacy_irq ( struct net_device *netdev __unused, int enable ) {
+	struct nic *nic = netdev->priv;
+
+	nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) );
+}
+
+static struct net_device_operations legacy_operations = {
+	.open		= legacy_open,
+	.close		= legacy_close,
+	.transmit	= legacy_transmit,
+	.poll		= legacy_poll,
+	.irq   		= legacy_irq,
+};
+
+int legacy_probe ( void *hwdev,
+		   void ( * set_drvdata ) ( void *hwdev, void *priv ),
+		   struct device *dev,
+		   int ( * probe ) ( struct nic *nic, void *hwdev ),
+		   void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
+	struct net_device *netdev;
+	int rc;
+
+	if ( legacy_registered )
+		return -EBUSY;
+	
+	netdev = alloc_etherdev ( 0 );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &legacy_operations );
+	netdev->priv = &nic;
+	memset ( &nic, 0, sizeof ( nic ) );
+	set_drvdata ( hwdev, netdev );
+	netdev->dev = dev;
+
+	nic.node_addr = netdev->hw_addr;
+	nic.irqno = dev->desc.irq;
+
+	if ( ! probe ( &nic, hwdev ) ) {
+		rc = -ENODEV;
+		goto err_probe;
+	}
+
+	/* Overwrite the IRQ number.  Some legacy devices set
+	 * nic->irqno to 0 in the probe routine to indicate that they
+	 * don't support interrupts; doing this allows the timer
+	 * interrupt to be used instead.
+	 */
+	dev->desc.irq = nic.irqno;
+
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register;
+
+	/* Mark as link up; legacy devices don't handle link state */
+	netdev_link_up ( netdev );
+
+	/* Do not remove this message */
+	printf ( "WARNING: Using legacy NIC wrapper on %s\n",
+		 netdev->ll_protocol->ntoa ( nic.node_addr ) );
+
+	legacy_registered = 1;
+	return 0;
+
+ err_register:
+	disable ( &nic, hwdev );
+ err_probe:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	return rc;
+}
+
+void legacy_remove ( void *hwdev,
+		     void * ( * get_drvdata ) ( void *hwdev ),
+		     void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
+	struct net_device *netdev = get_drvdata ( hwdev );
+	struct nic *nic = netdev->priv;
+
+	unregister_netdev ( netdev );
+	disable ( nic, hwdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	legacy_registered = 0;
+}
+
+int dummy_connect ( struct nic *nic __unused ) {
+	return 1;
+}
+
+void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
+	return;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/mtd80x.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/mtd80x.c
new file mode 100644
index 0000000..170b5c5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/mtd80x.c
@@ -0,0 +1,1022 @@
+/**************************************************************************
+*
+*    mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
+*    Written 2004-2004 by Erdem Güven <zuencap at yahoo.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*               fealnx.c: A Linux device driver for the mtd80x Ethernet chip
+*               Written 1998-2000 by Donald Becker
+*
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include <mii.h>
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+#define get_unaligned(ptr) (*(ptr))
+
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.           */
+/* The compiler will convert <unsigned>'%'<2^N> into a bit mask.        */
+/* Making the Tx ring too large decreases the effectiveness of channel  */
+/* bonding and packet priority.                                         */
+/* There are no ill effects from too-large receive rings.               */
+#define TX_RING_SIZE 2
+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used.  */
+#define RX_RING_SIZE 4
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define HZ 100
+#define TX_TIME_OUT   (6*HZ)
+
+/* Allocation size of Rx buffers with normal sized Ethernet frames.
+   Do not change this value without good reason.  This is not a limit,
+   but a way to keep a consistent allocation size among drivers.
+ */
+#define PKT_BUF_SZ 1536
+
+/* for different PHY */
+enum phy_type_flags {
+    MysonPHY = 1,
+    AhdocPHY = 2,
+    SeeqPHY = 3,
+    MarvellPHY = 4,
+    Myson981 = 5,
+    LevelOnePHY = 6,
+    OtherPHY = 10,
+};
+
+/* A chip capabilities table*/
+enum chip_capability_flags {
+    HAS_MII_XCVR,
+    HAS_CHIP_XCVR,
+};
+
+#if 0 /* not used */
+static
+struct chip_info
+{
+    u16 dev_id;
+    int flag;
+}
+mtd80x_chips[] = {
+                     {0x0800, HAS_MII_XCVR},
+                     {0x0803, HAS_CHIP_XCVR},
+                     {0x0891, HAS_MII_XCVR}
+                 };
+static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
+#endif
+
+/* Offsets to the Command and Status Registers. */
+enum mtd_offsets {
+    PAR0 = 0x0,        /* physical address 0-3 */
+    PAR1 = 0x04,        /* physical address 4-5 */
+    MAR0 = 0x08,        /* multicast address 0-3 */
+    MAR1 = 0x0C,        /* multicast address 4-7 */
+    FAR0 = 0x10,        /* flow-control address 0-3 */
+    FAR1 = 0x14,        /* flow-control address 4-5 */
+    TCRRCR = 0x18,        /* receive & transmit configuration */
+    BCR = 0x1C,        /* bus command */
+    TXPDR = 0x20,        /* transmit polling demand */
+    RXPDR = 0x24,        /* receive polling demand */
+    RXCWP = 0x28,        /* receive current word pointer */
+    TXLBA = 0x2C,        /* transmit list base address */
+    RXLBA = 0x30,        /* receive list base address */
+    ISR = 0x34,        /* interrupt status */
+    IMR = 0x38,        /* interrupt mask */
+    FTH = 0x3C,        /* flow control high/low threshold */
+    MANAGEMENT = 0x40,    /* bootrom/eeprom and mii management */
+    TALLY = 0x44,        /* tally counters for crc and mpa */
+    TSR = 0x48,        /* tally counter for transmit status */
+    BMCRSR = 0x4c,        /* basic mode control and status */
+    PHYIDENTIFIER = 0x50,    /* phy identifier */
+    ANARANLPAR = 0x54,    /* auto-negotiation advertisement and link
+                                                       partner ability */
+    ANEROCR = 0x58,        /* auto-negotiation expansion and pci conf. */
+    BPREMRPSR = 0x5c,    /* bypass & receive error mask and phy status */
+};
+
+/* Bits in the interrupt status/enable registers. */
+/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
+enum intr_status_bits {
+    RFCON = 0x00020000, /* receive flow control xon packet */
+    RFCOFF = 0x00010000, /* receive flow control xoff packet */
+    LSCStatus = 0x00008000, /* link status change */
+    ANCStatus = 0x00004000, /* autonegotiation completed */
+    FBE = 0x00002000, /* fatal bus error */
+    FBEMask = 0x00001800, /* mask bit12-11 */
+    ParityErr = 0x00000000, /* parity error */
+    TargetErr = 0x00001000, /* target abort */
+    MasterErr = 0x00000800, /* master error */
+    TUNF = 0x00000400, /* transmit underflow */
+    ROVF = 0x00000200, /* receive overflow */
+    ETI = 0x00000100, /* transmit early int */
+    ERI = 0x00000080, /* receive early int */
+    CNTOVF = 0x00000040, /* counter overflow */
+    RBU = 0x00000020, /* receive buffer unavailable */
+    TBU = 0x00000010, /* transmit buffer unavilable */
+    TI = 0x00000008, /* transmit interrupt */
+    RI = 0x00000004, /* receive interrupt */
+    RxErr = 0x00000002, /* receive error */
+};
+
+/* Bits in the NetworkConfig register. */
+enum rx_mode_bits {
+    RxModeMask   = 0xe0,
+    AcceptAllPhys = 0x80,        /* promiscuous mode */
+    AcceptBroadcast = 0x40,        /* accept broadcast */
+    AcceptMulticast = 0x20,        /* accept mutlicast */
+    AcceptRunt   = 0x08,        /* receive runt pkt */
+    ALP          = 0x04,        /* receive long pkt */
+    AcceptErr    = 0x02,        /* receive error pkt */
+
+    AcceptMyPhys = 0x00000000,
+    RxEnable     = 0x00000001,
+    RxFlowCtrl   = 0x00002000,
+    TxEnable     = 0x00040000,
+    TxModeFDX    = 0x00100000,
+    TxThreshold  = 0x00e00000,
+
+    PS1000       = 0x00010000,
+    PS10         = 0x00080000,
+    FD           = 0x00100000,
+};
+
+/* Bits in network_desc.status */
+enum rx_desc_status_bits {
+    RXOWN = 0x80000000, /* own bit */
+    FLNGMASK = 0x0fff0000, /* frame length */
+    FLNGShift = 16,
+    MARSTATUS = 0x00004000, /* multicast address received */
+    BARSTATUS = 0x00002000, /* broadcast address received */
+    PHYSTATUS = 0x00001000, /* physical address received */
+    RXFSD = 0x00000800, /* first descriptor */
+    RXLSD = 0x00000400, /* last descriptor */
+    ErrorSummary = 0x80, /* error summary */
+    RUNT = 0x40,  /* runt packet received */
+    LONG = 0x20,  /* long packet received */
+    FAE = 0x10,  /* frame align error */
+    CRC = 0x08,  /* crc error */
+    RXER = 0x04,  /* receive error */
+};
+
+enum rx_desc_control_bits {
+    RXIC = 0x00800000, /* interrupt control */
+    RBSShift = 0,
+};
+
+enum tx_desc_status_bits {
+    TXOWN = 0x80000000, /* own bit */
+    JABTO = 0x00004000, /* jabber timeout */
+    CSL = 0x00002000, /* carrier sense lost */
+    LC = 0x00001000, /* late collision */
+    EC = 0x00000800, /* excessive collision */
+    UDF = 0x00000400, /* fifo underflow */
+    DFR = 0x00000200, /* deferred */
+    HF = 0x00000100, /* heartbeat fail */
+    NCRMask = 0x000000ff, /* collision retry count */
+    NCRShift = 0,
+};
+
+enum tx_desc_control_bits {
+    TXIC = 0x80000000, /* interrupt control */
+    ETIControl = 0x40000000, /* early transmit interrupt */
+    TXLD = 0x20000000, /* last descriptor */
+    TXFD = 0x10000000, /* first descriptor */
+    CRCEnable = 0x08000000, /* crc control */
+    PADEnable = 0x04000000, /* padding control */
+    RetryTxLC = 0x02000000, /* retry late collision */
+    PKTSMask = 0x3ff800, /* packet size bit21-11 */
+    PKTSShift = 11,
+    TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
+    TBSShift = 0,
+};
+
+/* BootROM/EEPROM/MII Management Register */
+#define MASK_MIIR_MII_READ       0x00000000
+#define MASK_MIIR_MII_WRITE      0x00000008
+#define MASK_MIIR_MII_MDO        0x00000004
+#define MASK_MIIR_MII_MDI        0x00000002
+#define MASK_MIIR_MII_MDC        0x00000001
+
+/* ST+OP+PHYAD+REGAD+TA */
+#define OP_READ             0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
+#define OP_WRITE            0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
+
+/* ------------------------------------------------------------------------- */
+/*      Constants for Myson PHY                                              */
+/* ------------------------------------------------------------------------- */
+#define MysonPHYID      0xd0000302
+/* 89-7-27 add, (begin) */
+#define MysonPHYID0     0x0302
+#define StatusRegister  18
+#define SPEED100        0x0400 // bit10
+#define FULLMODE        0x0800 // bit11
+/* 89-7-27 add, (end) */
+
+/* ------------------------------------------------------------------------- */
+/*      Constants for Seeq 80225 PHY                                         */
+/* ------------------------------------------------------------------------- */
+#define SeeqPHYID0      0x0016
+
+#define MIIRegister18   18
+#define SPD_DET_100     0x80
+#define DPLX_DET_FULL   0x40
+
+/* ------------------------------------------------------------------------- */
+/*      Constants for Ahdoc 101 PHY                                          */
+/* ------------------------------------------------------------------------- */
+#define AhdocPHYID0     0x0022
+
+#define DiagnosticReg   18
+#define DPLX_FULL       0x0800
+#define Speed_100       0x0400
+
+/* 89/6/13 add, */
+/* -------------------------------------------------------------------------- */
+/*      Constants                                                             */
+/* -------------------------------------------------------------------------- */
+#define MarvellPHYID0           0x0141
+#define LevelOnePHYID0  0x0013
+
+#define MII1000BaseTControlReg  9
+#define MII1000BaseTStatusReg   10
+#define SpecificReg  17
+
+/* for 1000BaseT Control Register */
+#define PHYAbletoPerform1000FullDuplex  0x0200
+#define PHYAbletoPerform1000HalfDuplex  0x0100
+#define PHY1000AbilityMask              0x300
+
+// for phy specific status register, marvell phy.
+#define SpeedMask       0x0c000
+#define Speed_1000M     0x08000
+#define Speed_100M      0x4000
+#define Speed_10M       0
+#define Full_Duplex     0x2000
+
+// 89/12/29 add, for phy specific status register, levelone phy, (begin)
+#define LXT1000_100M    0x08000
+#define LXT1000_1000M   0x0c000
+#define LXT1000_Full    0x200
+// 89/12/29 add, for phy specific status register, levelone phy, (end)
+
+#if 0
+/* for 3-in-1 case */
+#define PS10            0x00080000
+#define FD              0x00100000
+#define PS1000          0x00010000
+#endif
+
+/* for PHY */
+#define LinkIsUp        0x0004
+#define LinkIsUp2 0x00040000
+
+/* Create a static buffer of size PKT_BUF_SZ for each
+RX and TX Descriptor.  All descriptors point to a
+part of this buffer */
+struct {
+	u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
+	u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
+} mtd80x_bufs __shared;
+#define txb mtd80x_bufs.txb
+#define rxb mtd80x_bufs.rxb
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct mtd_desc
+{
+    s32 status;
+    s32 control;
+    u32 buffer;
+    u32 next_desc;
+    struct mtd_desc *next_desc_logical;
+    u8* skbuff;
+    u32 reserved1;
+    u32 reserved2;
+};
+
+struct mtd_private
+{
+    struct mtd_desc rx_ring[RX_RING_SIZE];
+    struct mtd_desc tx_ring[TX_RING_SIZE];
+
+    /* Frequently used values: keep some adjacent for cache effect. */
+    int flags;
+    struct pci_dev *pci_dev;
+    unsigned long crvalue;
+    unsigned long bcrvalue;
+    /*unsigned long imrvalue;*/
+    struct mtd_desc *cur_rx;
+    struct mtd_desc *lack_rxbuf;
+    int really_rx_count;
+    struct mtd_desc *cur_tx;
+    struct mtd_desc *cur_tx_copy;
+    int really_tx_count;
+    int free_tx_count;
+    unsigned int rx_buf_sz; /* Based on MTU+slack. */
+
+    /* These values are keep track of the transceiver/media in use. */
+    unsigned int linkok;
+    unsigned int line_speed;
+    unsigned int duplexmode;
+    unsigned int default_port:
+    4; /* Last dev->if_port value. */
+    unsigned int PHYType;
+
+    /* MII transceiver section. */
+    int mii_cnt;  /* MII device addresses. */
+    unsigned char phys[1]; /* MII device addresses. */
+
+    /*other*/
+    const char *nic_name;
+    int ioaddr;
+    u16 dev_id;
+};
+
+static struct mtd_private mtdx;
+
+static int mdio_read(struct nic * , int phy_id, int location);
+static void getlinktype(struct nic * );
+static void getlinkstatus(struct nic * );
+static void set_rx_mode(struct nic *);
+
+/**************************************************************************
+ *  init_ring - setup the tx and rx descriptors
+ *************************************************************************/
+static void init_ring(struct nic *nic __unused)
+{
+    int i;
+
+    mtdx.cur_rx = &mtdx.rx_ring[0];
+
+    mtdx.rx_buf_sz = PKT_BUF_SZ;
+    /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
+
+    /* Initialize all Rx descriptors. */
+    /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+    for (i = 0; i < RX_RING_SIZE; i++)
+    {
+        mtdx.rx_ring[i].status = RXOWN;
+        mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
+        mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
+        mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
+        mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
+        mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
+    }
+    /* Mark the last entry as wrapping the ring. */
+    mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
+    mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
+
+    /* We only use one transmit buffer, but two
+     * descriptors so transmit engines have somewhere
+     * to point should they feel the need */
+    mtdx.tx_ring[0].status = 0x00000000;
+    mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
+    mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
+
+    /* This descriptor is never used */
+    mtdx.tx_ring[1].status = 0x00000000;
+    mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
+    mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
+
+    return;
+}
+
+/**************************************************************************
+RESET - Reset Adapter
+***************************************************************************/
+static void mtd_reset( struct nic *nic )
+{
+    /* Reset the chip to erase previous misconfiguration. */
+    outl(0x00000001, mtdx.ioaddr + BCR);
+
+    init_ring(nic);
+
+    outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
+    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
+
+    /* Initialize other registers. */
+    /* Configure the PCI bus bursts and FIFO thresholds. */
+    mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
+    mtdx.crvalue = 0xa00; /* rx 128 burst length */
+
+	if ( mtdx.dev_id == 0x891 ) {
+		mtdx.bcrvalue |= 0x200;	/* set PROG bit */
+		mtdx.crvalue |= 0x02000000;	/* set enhanced bit */
+	}
+
+    outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
+
+    /* Restart Rx engine if stopped. */
+    outl(0, mtdx.ioaddr + RXPDR);
+
+    getlinkstatus(nic);
+    if (mtdx.linkok)
+    {
+        static const char* texts[]={"half","full","10","100","1000"};
+        getlinktype(nic);
+        DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
+    } else
+    {
+        DBG ( "No link!!!\n" );
+    }
+
+    mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
+    set_rx_mode(nic);
+
+    /* Clear interrupts by setting the interrupt mask. */
+    outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
+    outl( 0, mtdx.ioaddr + IMR);
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int mtd_poll(struct nic *nic, __unused int retrieve)
+{
+    s32 rx_status = mtdx.cur_rx->status;
+    int retval = 0;
+
+    if( ( rx_status & RXOWN ) != 0 )
+    {
+        return 0;
+    }
+
+    if (rx_status & ErrorSummary)
+    { /* there was a fatal error */
+        printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
+                mtdx.nic_name, (unsigned int) rx_status,
+                (rx_status & (LONG | RUNT)) ? "length_error ":"",
+                (rx_status & RXER) ? "frame_error ":"",
+                (rx_status & CRC) ? "crc_error ":"" );
+        retval = 0;
+    } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
+    {
+        /* this pkt is too long, over one rx buffer */
+        printf("Pkt is too long, over one rx buffer.\n");
+        retval = 0;
+    } else
+    { /* this received pkt is ok */
+        /* Omit the four octet CRC from the length. */
+        short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
+
+        DBG ( " netdev_rx() normal Rx pkt length %d"
+ 	      " status %x.\n", pkt_len, (unsigned int) rx_status );
+
+        nic->packetlen = pkt_len;
+        memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
+
+        retval = 1;
+    }
+
+    while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
+    {
+        mtdx.cur_rx->status = RXOWN;
+        mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
+    }
+
+    /* Restart Rx engine if stopped. */
+    outl(0, mtdx.ioaddr + RXPDR);
+
+    return retval;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void mtd_transmit(
+    struct nic *nic,
+    const char *dest,            /* Destination */
+    unsigned int type,            /* Type */
+    unsigned int size,            /* size */
+    const char *data)            /* Packet */
+{
+    u32 to;
+    u32 tx_status;
+    unsigned int nstype = htons ( type );
+
+    memcpy( txb, dest, ETH_ALEN );
+    memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
+    memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
+    memcpy( txb + ETH_HLEN, data, size );
+
+    size += ETH_HLEN;
+    size &= 0x0FFF;
+    while( size < ETH_ZLEN )
+    {
+        txb[size++] = '\0';
+    }
+
+    mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
+    mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
+    mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
+    mtdx.tx_ring[0].status = TXOWN;
+
+    /* Point to transmit descriptor */
+    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
+    /* Enable Tx */
+    outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
+    /* Wake the potentially-idle transmit channel. */
+    outl(0, mtdx.ioaddr + TXPDR);
+
+    to = currticks() + TX_TIME_OUT;
+    while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
+
+    /* Disable Tx */
+    outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
+
+    tx_status = mtdx.tx_ring[0].status;
+    if (currticks() >= to){
+        DBG ( "TX Time Out" );
+    } else if( tx_status & (CSL | LC | EC | UDF | HF)){
+        printf( "Transmit error: %8.8x %s %s %s %s %s\n",
+                (unsigned int) tx_status,
+                tx_status & EC ? "abort" : "",
+                tx_status & CSL ? "carrier" : "",
+                tx_status & LC ? "late" : "",
+                tx_status & UDF ? "fifo" : "",
+                tx_status & HF ? "heartbeat" : "" );
+    }
+
+    /*hex_dump( txb, size );*/
+    /*pause();*/
+
+    DBG ( "TRANSMIT\n" );
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void mtd_disable ( struct nic *nic ) {
+
+    /* Disable Tx Rx*/
+    outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
+
+    /* Reset the chip to erase previous misconfiguration. */
+    mtd_reset(nic);
+
+    DBG ( "DISABLE\n" );
+}
+
+static struct nic_operations mtd_operations = {
+	.connect	= dummy_connect,
+	.poll		= mtd_poll,
+	.transmit	= mtd_transmit,
+	.irq		= dummy_irq,
+
+};
+
+static struct pci_device_id mtd80x_nics[] = {
+        PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0),
+        PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0),
+        PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0),
+};
+
+PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
+
+    int i;
+
+    if (pci->ioaddr == 0)
+	    return 0;
+
+    adjust_pci_device(pci);
+
+    nic->ioaddr = pci->ioaddr;
+    nic->irqno = 0;
+
+    mtdx.nic_name = pci->id->name;
+    mtdx.dev_id = pci->device;
+    mtdx.ioaddr = nic->ioaddr;
+
+    /* read ethernet id */
+    for (i = 0; i < 6; ++i)
+    {
+        nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
+    }
+
+    if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
+    {
+        return 0;
+    }
+
+    DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
+
+    /* Reset the chip to erase previous misconfiguration. */
+    outl(0x00000001, mtdx.ioaddr + BCR);
+
+    /* find the connected MII xcvrs */
+
+    if( mtdx.dev_id != 0x803 )
+    {
+        int phy, phy_idx = 0;
+
+        for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
+            int mii_status = mdio_read(nic, phy, 1);
+
+            if (mii_status != 0xffff && mii_status != 0x0000) {
+                mtdx.phys[phy_idx] = phy;
+
+                DBG ( "%s: MII PHY found at address %d, status "
+		      "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
+                /* get phy type */
+                {
+                    unsigned int data;
+
+                    data = mdio_read(nic, mtdx.phys[phy_idx], 2);
+                    if (data == SeeqPHYID0)
+                        mtdx.PHYType = SeeqPHY;
+                    else if (data == AhdocPHYID0)
+                        mtdx.PHYType = AhdocPHY;
+                    else if (data == MarvellPHYID0)
+                        mtdx.PHYType = MarvellPHY;
+                    else if (data == MysonPHYID0)
+                        mtdx.PHYType = Myson981;
+                    else if (data == LevelOnePHYID0)
+                        mtdx.PHYType = LevelOnePHY;
+                    else
+                        mtdx.PHYType = OtherPHY;
+                }
+                phy_idx++;
+            }
+        }
+
+        mtdx.mii_cnt = phy_idx;
+        if (phy_idx == 0) {
+            printf("%s: MII PHY not found -- this device may "
+                   "not operate correctly.\n", mtdx.nic_name);
+        }
+    } else {
+        mtdx.phys[0] = 32;
+        /* get phy type */
+        if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
+            mtdx.PHYType = MysonPHY;
+            DBG ( "MysonPHY\n" );
+        } else {
+            mtdx.PHYType = OtherPHY;
+            DBG ( "OtherPHY\n" );
+        }
+    }
+
+    getlinkstatus(nic);
+    if( !mtdx.linkok )
+    {
+        printf("No link!!!\n");
+        return 0;
+    }
+
+    mtd_reset( nic );
+
+    /* point to NIC specific routines */
+    nic->nic_op	= &mtd_operations;
+    return 1;
+}
+
+
+/**************************************************************************/
+static void set_rx_mode(struct nic *nic __unused)
+{
+    u32 mc_filter[2];                       /* Multicast hash filter */
+    u32 rx_mode;
+
+    /* Too many to match, or accept all multicasts. */
+    mc_filter[1] = mc_filter[0] = ~0;
+    rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+
+    outl(mc_filter[0], mtdx.ioaddr + MAR0);
+    outl(mc_filter[1], mtdx.ioaddr + MAR1);
+
+    mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
+    outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
+}
+/**************************************************************************/
+static unsigned int m80x_read_tick(void)
+/* function: Reads the Timer tick count register which decrements by 2 from  */
+/*           65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
+/*           count represents 838 nsec's.                                    */
+/* input   : none.                                                           */
+/* output  : none.                                                           */
+{
+    unsigned char tmp;
+    int value;
+
+    outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
+
+    // now read the count.
+    tmp = (unsigned char) inb(0x40);
+    value = ((int) tmp) << 8;
+    tmp = (unsigned char) inb(0x40);
+    value |= (((int) tmp) & 0xff);
+    return (value);
+}
+
+static void m80x_delay(unsigned int interval)
+/* function: to wait for a specified time.                                   */
+/* input   : interval ... the specified time.                                */
+/* output  : none.                                                           */
+{
+    unsigned int interval1, interval2, i = 0;
+
+    interval1 = m80x_read_tick(); // get initial value
+    do
+    {
+        interval2 = m80x_read_tick();
+        if (interval1 < interval2)
+            interval1 += 65536;
+        ++i;
+    } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
+}
+
+
+static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
+{
+    u32 miir;
+    int i;
+    unsigned int mask, data;
+
+    /* enable MII output */
+    miir = (u32) inl(miiport);
+    miir &= 0xfffffff0;
+
+    miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
+
+    /* send 32 1's preamble */
+    for (i = 0; i < 32; i++) {
+        /* low MDC; MDO is already high (miir) */
+        miir &= ~MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+
+        /* high MDC */
+        miir |= MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+    }
+
+    /* calculate ST+OP+PHYAD+REGAD+TA */
+    data = opcode | (phyad << 7) | (regad << 2);
+
+    /* sent out */
+    mask = 0x8000;
+    while (mask) {
+        /* low MDC, prepare MDO */
+        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
+        if (mask & data)
+            miir |= MASK_MIIR_MII_MDO;
+
+        outl(miir, miiport);
+        /* high MDC */
+        miir |= MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+        m80x_delay(30);
+
+        /* next */
+        mask >>= 1;
+        if (mask == 0x2 && opcode == OP_READ)
+            miir &= ~MASK_MIIR_MII_WRITE;
+    }
+    return miir;
+}
+
+static int mdio_read(struct nic *nic __unused, int phyad, int regad)
+{
+    long miiport = mtdx.ioaddr + MANAGEMENT;
+    u32 miir;
+    unsigned int mask, data;
+
+    miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
+
+    /* read data */
+    mask = 0x8000;
+    data = 0;
+    while (mask)
+    {
+        /* low MDC */
+        miir &= ~MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+
+        /* read MDI */
+        miir = inl(miiport);
+        if (miir & MASK_MIIR_MII_MDI)
+            data |= mask;
+
+        /* high MDC, and wait */
+        miir |= MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+        m80x_delay((int) 30);
+
+        /* next */
+        mask >>= 1;
+    }
+
+    /* low MDC */
+    miir &= ~MASK_MIIR_MII_MDC;
+    outl(miir, miiport);
+
+    return data & 0xffff;
+}
+
+#if 0 /* not used */
+static void mdio_write(struct nic *nic __unused, int phyad, int regad,
+		       int data)
+{
+    long miiport = mtdx.ioaddr + MANAGEMENT;
+    u32 miir;
+    unsigned int mask;
+
+    miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
+
+    /* write data */
+    mask = 0x8000;
+    while (mask)
+    {
+        /* low MDC, prepare MDO */
+        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
+        if (mask & data)
+            miir |= MASK_MIIR_MII_MDO;
+        outl(miir, miiport);
+
+        /* high MDC */
+        miir |= MASK_MIIR_MII_MDC;
+        outl(miir, miiport);
+
+        /* next */
+        mask >>= 1;
+    }
+
+    /* low MDC */
+    miir &= ~MASK_MIIR_MII_MDC;
+    outl(miir, miiport);
+
+    return;
+}
+#endif
+
+static void getlinkstatus(struct nic *nic)
+/* function: Routine will read MII Status Register to get link status.       */
+/* input   : dev... pointer to the adapter block.                            */
+/* output  : none.                                                           */
+{
+    unsigned int i, DelayTime = 0x1000;
+
+    mtdx.linkok = 0;
+
+    if (mtdx.PHYType == MysonPHY)
+    {
+        for (i = 0; i < DelayTime; ++i) {
+            if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
+                mtdx.linkok = 1;
+                return;
+            }
+            // delay
+            m80x_delay(100);
+        }
+    } else
+    {
+        for (i = 0; i < DelayTime; ++i) {
+            if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
+                mtdx.linkok = 1;
+                return;
+            }
+            // delay
+            m80x_delay(100);
+        }
+    }
+}
+
+
+static void getlinktype(struct nic *dev)
+{
+    if (mtdx.PHYType == MysonPHY)
+    { /* 3-in-1 case */
+        if (inl(mtdx.ioaddr + TCRRCR) & FD)
+            mtdx.duplexmode = 2; /* full duplex */
+        else
+            mtdx.duplexmode = 1; /* half duplex */
+        if (inl(mtdx.ioaddr + TCRRCR) & PS10)
+            mtdx.line_speed = 1; /* 10M */
+        else
+            mtdx.line_speed = 2; /* 100M */
+    } else
+    {
+        if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
+            unsigned int data;
+
+            data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
+            if (data & SPD_DET_100)
+                mtdx.line_speed = 2; /* 100M */
+            else
+                mtdx.line_speed = 1; /* 10M */
+            if (data & DPLX_DET_FULL)
+                mtdx.duplexmode = 2; /* full duplex mode */
+            else
+                mtdx.duplexmode = 1; /* half duplex mode */
+        } else if (mtdx.PHYType == AhdocPHY) {
+            unsigned int data;
+
+            data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
+            if (data & Speed_100)
+                mtdx.line_speed = 2; /* 100M */
+            else
+                mtdx.line_speed = 1; /* 10M */
+            if (data & DPLX_FULL)
+                mtdx.duplexmode = 2; /* full duplex mode */
+            else
+                mtdx.duplexmode = 1; /* half duplex mode */
+        }
+        /* 89/6/13 add, (begin) */
+        else if (mtdx.PHYType == MarvellPHY) {
+            unsigned int data;
+
+            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
+            if (data & Full_Duplex)
+                mtdx.duplexmode = 2; /* full duplex mode */
+            else
+                mtdx.duplexmode = 1; /* half duplex mode */
+            data &= SpeedMask;
+            if (data == Speed_1000M)
+                mtdx.line_speed = 3; /* 1000M */
+            else if (data == Speed_100M)
+                mtdx.line_speed = 2; /* 100M */
+            else
+                mtdx.line_speed = 1; /* 10M */
+        }
+        /* 89/6/13 add, (end) */
+        /* 89/7/27 add, (begin) */
+        else if (mtdx.PHYType == Myson981) {
+            unsigned int data;
+
+            data = mdio_read(dev, mtdx.phys[0], StatusRegister);
+
+            if (data & SPEED100)
+                mtdx.line_speed = 2;
+            else
+                mtdx.line_speed = 1;
+
+            if (data & FULLMODE)
+                mtdx.duplexmode = 2;
+            else
+                mtdx.duplexmode = 1;
+        }
+        /* 89/7/27 add, (end) */
+        /* 89/12/29 add */
+        else if (mtdx.PHYType == LevelOnePHY) {
+            unsigned int data;
+
+            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
+            if (data & LXT1000_Full)
+                mtdx.duplexmode = 2; /* full duplex mode */
+            else
+                mtdx.duplexmode = 1; /* half duplex mode */
+            data &= SpeedMask;
+            if (data == LXT1000_1000M)
+                mtdx.line_speed = 3; /* 1000M */
+            else if (data == LXT1000_100M)
+                mtdx.line_speed = 2; /* 100M */
+            else
+                mtdx.line_speed = 1; /* 10M */
+        }
+        // chage crvalue
+        // mtdx.crvalue&=(~PS10)&(~FD);
+        mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
+        if (mtdx.line_speed == 1)
+            mtdx.crvalue |= PS10;
+        else if (mtdx.line_speed == 3)
+            mtdx.crvalue |= PS1000;
+        if (mtdx.duplexmode == 2)
+            mtdx.crvalue |= FD;
+    }
+}
+
+DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
+	 mtd_probe, mtd_disable );
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge.c
new file mode 100644
index 0000000..5bb555d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge.c
@@ -0,0 +1,1335 @@
+/************************************************* -*- linux-c -*-
+ * Myricom 10Gb Network Interface Card Software
+ * Copyright 2009, Myricom, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ ****************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * Author: Glenn Brown <glenn at myri.com>
+ */
+
+/*
+ * General Theory of Operation
+ *
+ * This is a minimal Myricom 10 gigabit Ethernet driver for network
+ * boot.
+ *
+ * Initialization
+ *
+ * myri10ge_pci_probe() is called by iPXE during initialization.
+ * Minimal NIC initialization is performed to minimize resources
+ * consumed when the driver is resident but unused.
+ *
+ * Network Boot
+ *
+ * myri10ge_net_open() is called by iPXE before attempting to network
+ * boot from the card.  Packet buffers are allocated and the NIC
+ * interface is initialized.
+ *
+ * Transmit
+ *
+ * myri10ge_net_transmit() enqueues frames for transmission by writing
+ * discriptors to the NIC's tx ring.  For simplicity and to avoid
+ * copies, we always have the NIC DMA up the packet.  The sent I/O
+ * buffer is released once the NIC signals myri10ge_interrupt_handler()
+ * that the send has completed.
+ *
+ * Receive
+ *
+ * Receives are posted to the NIC's receive ring.  The NIC fills a
+ * DMAable receive_completion ring with completion notifications.
+ * myri10ge_net_poll() polls for these receive notifications, posts
+ * replacement receive buffers to the NIC, and passes received frames
+ * to netdev_rx().
+ *
+ * NonVolatile Storage
+ *
+ * This driver supports NonVolatile Storage (nvs) in the NIC EEPROM.
+ * If the last EEPROM block is not otherwise filled, we tell
+ * iPXE it may store NonVolatile Options (nvo) there.
+ */
+
+/*
+ * Debugging levels:
+ *	- DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(),
+ *	  TX overflow, corrupted packets, ...
+ *	- DBG2() is for successful events, like packet received,
+ *	  packet transmitted, and other general notifications.
+ *	- DBGP() prints the name of each called function on entry
+ */
+
+#include <stdint.h>
+
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/nvo.h>
+#include <ipxe/nvs.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+
+#include "myri10ge_mcp.h"
+
+/****************************************************************
+ * Forward declarations
+ ****************************************************************/
+
+/* PCI driver entry points */
+
+static int	myri10ge_pci_probe ( struct pci_device* );
+static void	myri10ge_pci_remove ( struct pci_device* );
+
+/* Network device operations */
+
+static void	myri10ge_net_close ( struct net_device* );
+static void	myri10ge_net_irq ( struct net_device*, int enable );
+static int	myri10ge_net_open ( struct net_device* );
+static void	myri10ge_net_poll ( struct net_device* );
+static int	myri10ge_net_transmit ( struct net_device*, struct io_buffer* );
+
+/****************************************************************
+ * Constants
+ ****************************************************************/
+
+/* Maximum ring indices, used to wrap ring indices.  These must be 2**N-1. */
+
+#define MYRI10GE_TRANSMIT_WRAP                  1U
+#define MYRI10GE_RECEIVE_WRAP                   7U
+#define MYRI10GE_RECEIVE_COMPLETION_WRAP        31U
+
+/****************************************************************
+ * Driver internal data types.
+ ****************************************************************/
+
+/* Structure holding all DMA buffers for a NIC, which we will
+   allocated as contiguous read/write DMAable memory when the NIC is
+   initialized. */
+
+struct myri10ge_dma_buffers
+{
+	/* The NIC DMAs receive completion notifications into this ring */
+
+	mcp_slot_t receive_completion[1+MYRI10GE_RECEIVE_COMPLETION_WRAP];
+
+	/* Interrupt details are DMAd here before interrupting. */
+
+	mcp_irq_data_t irq_data; /* 64B */
+
+	/* NIC command completion status is DMAd here. */
+
+	mcp_cmd_response_t command_response; /* 8B */
+};
+
+struct myri10ge_private
+{
+	/* Interrupt support */
+
+	uint32	*irq_claim;	/* in NIC SRAM */
+	uint32	*irq_deassert;	/* in NIC SRAM */
+
+	/* DMA buffers. */
+
+	struct myri10ge_dma_buffers	*dma;
+
+	/*
+	 * Transmit state.
+	 *
+	 * The counts here are uint32 for easy comparison with
+	 * priv->dma->irq_data.send_done_count and with each other.
+	 */
+
+	mcp_kreq_ether_send_t	*transmit_ring;	/* in NIC SRAM */
+	uint32                   transmit_ring_wrap;
+	uint32                   transmits_posted;
+	uint32                   transmits_done;
+	struct io_buffer	*transmit_iob[1 + MYRI10GE_TRANSMIT_WRAP];
+
+	/*
+	 * Receive state.
+	 */
+
+	mcp_kreq_ether_recv_t	*receive_post_ring;	/* in NIC SRAM */
+	unsigned int             receive_post_ring_wrap;
+	unsigned int             receives_posted;
+	unsigned int             receives_done;
+	struct io_buffer	*receive_iob[1 + MYRI10GE_RECEIVE_WRAP];
+
+	/* Address for writing commands to the firmware.
+	   BEWARE: the value must be written 32 bits at a time. */
+
+	mcp_cmd_t	*command;
+
+	/*
+	 * Nonvolatile Storage for configuration options.
+	 */
+
+	struct nvs_device	nvs;
+	struct nvo_block	nvo;
+	unsigned int		nvo_registered;
+
+	/* Cached PCI capability locations. */
+
+	uint8			pci_cap_vs;
+};
+
+/****************************************************************
+ * Driver internal functions.
+ ****************************************************************/
+
+/* Print ring status when debugging.  Use this only after a printed
+   value changes. */
+
+#define DBG2_RINGS( priv ) 						\
+	DBG2 ( "tx %x/%x rx %x/%x in %s() \n",				\
+	       ( priv ) ->transmits_done, ( priv ) -> transmits_posted,	\
+	       ( priv ) ->receives_done, ( priv ) -> receives_posted,	\
+	       __FUNCTION__ )
+
+/*
+ * Return a pointer to the driver private data for a network device.
+ *
+ * @v netdev	Network device created by this driver.
+ * @ret priv	The corresponding driver private data.
+ */
+static inline struct myri10ge_private *myri10ge_priv ( struct net_device *nd )
+{
+	/* Our private data always follows the network device in memory,
+	   since we use alloc_netdev() to allocate the storage. */
+
+	return ( struct myri10ge_private * ) ( nd + 1 );
+}
+
+/*
+ * Convert a Myri10ge driver private data pointer to a netdev pointer.
+ *
+ * @v p		Myri10ge device private data.
+ * @ret r	The corresponding network device.
+ */
+static inline struct net_device *myri10ge_netdev ( struct myri10ge_private *p )
+{
+	return ( ( struct net_device * ) p ) - 1;
+}
+
+/*
+ * Convert a network device pointer to a PCI device pointer.
+ *
+ * @v netdev	A Network Device.
+ * @ret r	The corresponding PCI device.
+ */
+static inline struct pci_device *myri10ge_pcidev ( struct net_device *netdev )
+{
+	return container_of (netdev->dev, struct pci_device, dev);
+}
+
+/*
+ * Pass a receive buffer to the NIC to be filled.
+ *
+ * @v priv	The network device to receive the buffer.
+ * @v iob	The I/O buffer to fill.
+ *
+ * Receive buffers are filled in FIFO order.
+ */
+static void myri10ge_post_receive ( struct myri10ge_private *priv,
+				    struct io_buffer *iob )
+{
+	unsigned int		 receives_posted;
+	mcp_kreq_ether_recv_t	*request;
+
+	/* Record the posted I/O buffer, to be passed to netdev_rx() on
+	   receive. */
+
+	receives_posted = priv->receives_posted;
+	priv->receive_iob[receives_posted & MYRI10GE_RECEIVE_WRAP] = iob;
+
+	/* Post the receive. */
+
+	request = &priv->receive_post_ring[receives_posted
+					   & priv->receive_post_ring_wrap];
+	request->addr_high = 0;
+	wmb();
+	request->addr_low = htonl ( virt_to_bus ( iob->data ) );
+	priv->receives_posted = ++receives_posted;
+}
+
+/*
+ * Execute a command on the NIC.
+ *
+ * @v priv	NIC to perform the command.
+ * @v cmd	The command to perform.
+ * @v data	I/O copy buffer for parameters/results
+ * @ret rc	0 on success, else an error code.
+ */
+static int myri10ge_command ( struct myri10ge_private *priv,
+			      uint32 cmd,
+			      uint32 data[3] )
+{
+	int				 i;
+	mcp_cmd_t			*command;
+	uint32				 result;
+	unsigned int			 slept_ms;
+	volatile mcp_cmd_response_t	*response;
+
+	DBGP ( "myri10ge_command ( ,%d, ) \n", cmd );
+	command = priv->command;
+	response = &priv->dma->command_response;
+
+	/* Mark the command as incomplete. */
+
+	response->result = 0xFFFFFFFF;
+
+	/* Pass the command to the NIC. */
+
+	command->cmd		    = htonl ( cmd );
+	command->data0		    = htonl ( data[0] );
+	command->data1		    = htonl ( data[1] );
+	command->data2		    = htonl ( data[2] );
+	command->response_addr.high = 0;
+	command->response_addr.low
+		= htonl ( virt_to_bus ( &priv->dma->command_response ) );
+	for ( i=0; i<36; i+=4 )
+		* ( uint32 * ) &command->pad[i] = 0;
+	wmb();
+	* ( uint32 * ) &command->pad[36] = 0;
+
+	/* Wait up to 2 seconds for a response. */
+
+	for ( slept_ms=0; slept_ms<2000; slept_ms++ ) {
+		result = response->result;
+		if ( result == 0 ) {
+			data[0] = ntohl ( response->data );
+			return 0;
+		} else if ( result != 0xFFFFFFFF ) {
+			DBG ( "cmd%d:0x%x\n",
+			      cmd,
+			      ntohl ( response->result ) );
+			return -EIO;
+		}
+		udelay ( 1000 );
+		rmb();
+	}
+	DBG ( "cmd%d:timed out\n", cmd );
+	return -ETIMEDOUT;
+}
+
+/*
+ * Handle any pending interrupt.
+ *
+ * @v netdev		Device being polled for interrupts.
+ *
+ * This is called periodically to let the driver check for interrupts.
+ */
+static void myri10ge_interrupt_handler ( struct net_device *netdev )
+{
+	struct myri10ge_private *priv;
+	mcp_irq_data_t		*irq_data;
+	uint8			 valid;
+
+	priv = myri10ge_priv ( netdev );
+	irq_data = &priv->dma->irq_data;
+
+	/* Return if there was no interrupt. */
+
+	rmb();
+	valid = irq_data->valid;
+	if ( !valid )
+		return;
+	DBG2 ( "irq " );
+
+	/* Tell the NIC to deassert the interrupt and clear
+	   irq_data->valid.*/
+
+	*priv->irq_deassert = 0;	/* any value is OK. */
+	mb();
+
+	/* Handle any new receives. */
+
+	if ( valid & 1 ) {
+
+		/* Pass the receive interrupt token back to the NIC. */
+
+		DBG2 ( "rx " );
+		*priv->irq_claim = htonl ( 3 );
+		wmb();
+	}
+
+	/* Handle any sent packet by freeing its I/O buffer, now that
+	   we know it has been DMAd. */
+
+	if ( valid & 2 ) {
+		unsigned int nic_done_count;
+
+		DBG2 ( "snt " );
+		nic_done_count = ntohl ( priv->dma->irq_data.send_done_count );
+		while ( priv->transmits_done != nic_done_count ) {
+			struct io_buffer *iob;
+
+			iob = priv->transmit_iob [priv->transmits_done
+						  & MYRI10GE_TRANSMIT_WRAP];
+			DBG2 ( "%p ", iob );
+			netdev_tx_complete ( netdev, iob );
+			++priv->transmits_done;
+		}
+	}
+
+	/* Record any statistics update. */
+
+	if ( irq_data->stats_updated ) {
+
+		/* Update the link status. */
+
+		DBG2 ( "stats " );
+		if ( ntohl ( irq_data->link_up ) == MXGEFW_LINK_UP )
+			netdev_link_up ( netdev );
+		else
+			netdev_link_down ( netdev );
+
+		/* Ignore all error counters from the NIC. */
+	}
+
+	/* Wait for the interrupt to be deasserted, as indicated by
+	   irq_data->valid, which is set by the NIC after the deassert. */
+
+	DBG2 ( "wait " );
+	do {
+		mb();
+	} while ( irq_data->valid );
+
+	/* Claim the interrupt to enable future interrupt generation. */
+
+	DBG2 ( "claim\n" );
+	* ( priv->irq_claim + 1 ) = htonl ( 3 );
+	mb();
+}
+
+/* Constants for reading the STRING_SPECS via the Myricom
+   Vendor Specific PCI configuration space capability. */
+
+#define VS_EEPROM_READ_ADDR ( vs + 0x04 )
+#define VS_EEPROM_READ_DATA ( vs + 0x08 )
+#define VS_EEPROM_WRITE     ( vs + 0x0C )
+#define VS_ADDR ( vs + 0x18 )
+#define VS_DATA ( vs + 0x14 )
+#define VS_MODE ( vs + 0x10 )
+#define 	VS_MODE_READ32 0x3
+#define 	VS_MODE_LOCATE 0x8
+#define 		VS_LOCATE_STRING_SPECS 0x3
+#define		VS_MODE_EEPROM_STREAM_WRITE 0xB
+
+/*
+ * Read MAC address from its 'string specs' via the vendor-specific
+ * capability.  (This capability allows NIC SRAM and ROM to be read
+ * before it is mapped.)
+ *
+ * @v pci		The device.
+ * @v vs		Offset of the PCI Vendor-Specific Capability.
+ * @v mac		Buffer to store the MAC address.
+ * @ret rc		Returns 0 on success, else an error code.
+ */
+static int mac_address_from_string_specs ( struct pci_device *pci,
+					   unsigned int vs,
+					   uint8 mac[ETH_ALEN] )
+{
+	char string_specs[256];
+	char *ptr, *limit;
+	char *to = string_specs;
+	uint32 addr;
+	uint32 len;
+	int mac_set = 0;
+
+	/* Locate the String specs in LANai SRAM. */
+
+	pci_write_config_byte ( pci, VS_MODE, VS_MODE_LOCATE );
+	pci_write_config_dword ( pci, VS_ADDR, VS_LOCATE_STRING_SPECS );
+	pci_read_config_dword ( pci, VS_ADDR, &addr );
+	pci_read_config_dword ( pci, VS_DATA, &len );
+	DBG2 ( "ss@%x,%x\n", addr, len );
+
+	/* Copy in the string specs.  Use 32-bit reads for performance. */
+
+	if ( len > sizeof ( string_specs ) || ( len & 3 ) ) {
+		pci_write_config_byte ( pci, VS_MODE, 0 );
+		DBG ( "SS too big\n" );
+		return -ENOTSUP;
+	}
+
+	pci_write_config_byte ( pci, VS_MODE, VS_MODE_READ32 );
+	while ( len >= 4 ) {
+		uint32 tmp;
+
+		pci_write_config_byte ( pci, VS_ADDR, addr );
+		pci_read_config_dword ( pci, VS_DATA, &tmp );
+		tmp = ntohl ( tmp );
+		memcpy ( to, &tmp, 4 );
+		to += 4;
+		addr += 4;
+		len -= 4;
+	}
+	pci_write_config_byte ( pci, VS_MODE, 0 );
+
+	/* Parse the string specs. */
+
+	DBG2 ( "STRING_SPECS:\n" );
+	ptr = string_specs;
+	limit = string_specs + sizeof ( string_specs );
+	while ( *ptr != '\0' && ptr < limit ) {
+		DBG2 ( "%s\n", ptr );
+		if ( memcmp ( ptr, "MAC=", 4 ) == 0 ) {
+			unsigned int i;
+
+			ptr += 4;
+			for ( i=0; i<6; i++ ) {
+				if ( ( ptr + 2 ) > limit ) {
+					DBG ( "bad MAC addr\n" );
+					return -ENOTSUP;
+				}
+				mac[i] = strtoul ( ptr, &ptr, 16 );
+				ptr += 1;
+			}
+			mac_set = 1;
+		}
+		else
+			while ( ptr < limit && *ptr++ );
+	}
+
+	/* Verify we parsed all we need. */
+
+	if ( !mac_set ) {
+		DBG ( "no MAC addr\n" );
+		return -ENOTSUP;
+	}
+
+	DBG2 ( "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
+
+	return 0;
+}
+
+/****************************************************************
+ * NonVolatile Storage support
+ ****************************************************************/
+
+/*
+ * Fill a buffer with data read from nonvolatile storage.
+ *
+ * @v nvs	The NonVolatile Storage device to be read.
+ * @v addr      The first NonVolatile Storage address to be read.
+ * @v _buf	Pointer to the data buffer to be filled.
+ * @v len	The number of bytes to copy.
+ * @ret rc	0 on success, else nonzero.
+ */
+static int myri10ge_nvs_read ( struct nvs_device *nvs,
+			       unsigned int addr,
+			       void *_buf,
+			       size_t len )
+{
+	struct myri10ge_private *priv =
+		container_of (nvs, struct myri10ge_private, nvs);
+	struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
+	unsigned int vs = priv->pci_cap_vs;
+	unsigned char *buf = (unsigned char *) _buf;
+	unsigned int data;
+	unsigned int i, j;
+
+	DBGP ( "myri10ge_nvs_read\n" );
+
+	/* Issue the first read address. */
+
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 3, addr>>16 );
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 2, addr>>8 );
+	pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
+	addr++;
+
+	/* Issue all the reads, and harvest the results every 4th issue. */
+
+	for ( i=0; i<len; ++i,addr++ ) {
+
+		/* Issue the next read address, updating only the
+		   bytes that need updating.  We always update the
+		   LSB, which triggers the read. */
+
+		if ( ( addr & 0xff ) == 0 ) {
+			if ( ( addr & 0xffff ) == 0 ) {
+				pci_write_config_byte ( pci,
+							VS_EEPROM_READ_ADDR + 3,
+							addr >> 16 );
+			}
+			pci_write_config_byte ( pci,
+					        VS_EEPROM_READ_ADDR + 2,
+						addr >> 8 );
+		}
+		pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
+
+		/* If 4 data bytes are available, read them with a single read. */
+
+		if ( ( i & 3 ) == 3 ) {
+			pci_read_config_dword ( pci,
+						VS_EEPROM_READ_DATA,
+						&data );
+			for ( j=0; j<4; j++ ) {
+				buf[i-j] = data;
+				data >>= 8;
+			}
+		}
+	}
+
+	/* Harvest any remaining results. */
+
+	if ( ( i & 3 ) != 0 ) {
+		pci_read_config_dword ( pci, VS_EEPROM_READ_DATA, &data );
+		for ( j=1; j<=(i&3); j++ ) {
+			buf[i-j] = data;
+			data >>= 8;
+		}
+	}
+
+	DBGP_HDA ( addr - len, _buf, len );
+	return 0;
+}
+
+/*
+ * Write a buffer into nonvolatile storage.
+ *
+ * @v nvs	The NonVolatile Storage device to be written.
+ * @v address   The NonVolatile Storage address to be written.
+ * @v _buf	Pointer to the data to be written.
+ * @v len	Length of the buffer to be written.
+ * @ret rc	0 on success, else nonzero.
+ */
+static int myri10ge_nvs_write ( struct nvs_device *nvs,
+				unsigned int addr,
+				const void *_buf,
+				size_t len )
+{
+	struct myri10ge_private *priv =
+		container_of (nvs, struct myri10ge_private, nvs);
+	struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
+	unsigned int vs = priv->pci_cap_vs;
+	const unsigned char *buf = (const unsigned char *)_buf;
+	unsigned int i;
+	uint8 verify;
+
+	DBGP ( "nvs_write " );
+	DBGP_HDA ( addr, _buf, len );
+
+	/* Start erase of the NonVolatile Options block. */
+
+	DBGP ( "erasing " );
+	pci_write_config_dword ( pci, VS_EEPROM_WRITE, ( addr << 8 ) | 0xff );
+
+	/* Wait for erase to complete. */
+
+	DBGP ( "waiting " );
+	pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
+	while ( verify != 0xff ) {
+		pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
+		pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
+	}
+
+	/* Write the data one byte at a time. */
+
+	DBGP ( "writing " );
+	pci_write_config_byte ( pci, VS_MODE, VS_MODE_EEPROM_STREAM_WRITE );
+	pci_write_config_dword ( pci, VS_ADDR, addr );
+	for (i=0; i<len; i++, addr++)
+		pci_write_config_byte ( pci, VS_DATA, buf[i] );
+	pci_write_config_dword ( pci, VS_ADDR, 0xffffffff );
+	pci_write_config_byte ( pci, VS_MODE, 0 );
+
+	DBGP ( "done\n" );
+	return 0;
+}
+
+/*
+ * Initialize NonVolatile storage support for a device.
+ *
+ * @v priv	Device private data for the device.
+ * @ret rc	0 on success, else an error code.
+ */
+
+static int myri10ge_nv_init ( struct myri10ge_private *priv )
+{
+	int rc;
+	struct myri10ge_eeprom_header
+	{
+		uint8 __jump[8];
+		uint32 eeprom_len;
+		uint32 eeprom_segment_len;
+		uint32 mcp1_offset;
+		uint32 mcp2_offset;
+		uint32 version;
+	} hdr;
+	uint32 mcp2_len;
+	unsigned int nvo_fragment_pos;
+
+	DBGP ( "myri10ge_nv_init\n" );
+
+	/* Read the EEPROM header, and byteswap the fields we will use.
+	   This is safe even though priv->nvs is not yet initialized. */
+
+	rc = myri10ge_nvs_read ( &priv->nvs, 0, &hdr, sizeof ( hdr ) );
+	if ( rc ) {
+		DBG ( "EEPROM header unreadable\n" );
+		return rc;
+	}
+	hdr.eeprom_len	       = ntohl ( hdr.eeprom_len );
+	hdr.eeprom_segment_len = ntohl ( hdr.eeprom_segment_len );
+	hdr.mcp2_offset	       = ntohl ( hdr.mcp2_offset );
+	hdr.version	       = ntohl ( hdr.version );
+	DBG2 ( "eelen:%xh seglen:%xh mcp2@%xh ver%d\n", hdr.eeprom_len,
+	       hdr.eeprom_segment_len, hdr.mcp2_offset, hdr.version );
+
+	/* If the firmware does not support EEPROM writes, simply return. */
+
+	if ( hdr.version < 1 ) {
+		DBG ( "No EEPROM write support\n" );
+		return 0;
+	}
+
+	/* Read the length of MCP2. */
+
+	rc = myri10ge_nvs_read ( &priv->nvs, hdr.mcp2_offset, &mcp2_len, 4 );
+	mcp2_len = ntohl ( mcp2_len );
+	DBG2 ( "mcp2len:%xh\n", mcp2_len );
+
+	/* Determine the position of the NonVolatile Options fragment and
+	   simply return if it overlaps other data. */
+
+	nvo_fragment_pos = hdr.eeprom_len -  hdr.eeprom_segment_len;
+	if ( hdr.mcp2_offset + mcp2_len > nvo_fragment_pos ) {
+		DBG ( "EEPROM full\n" );
+		return 0;
+	}
+
+	/* Initilize NonVolatile Storage state. */
+
+	priv->nvs.word_len_log2 = 0;
+	priv->nvs.size		= hdr.eeprom_len;
+	priv->nvs.block_size	= hdr.eeprom_segment_len;
+	priv->nvs.read		= myri10ge_nvs_read;
+	priv->nvs.write		= myri10ge_nvs_write;
+
+	/* Register the NonVolatile Options storage. */
+
+	nvo_init ( &priv->nvo,
+		   &priv->nvs,
+		   nvo_fragment_pos, 0x200,
+		   NULL,
+		   & myri10ge_netdev (priv) -> refcnt );
+	rc = register_nvo ( &priv->nvo,
+			    netdev_settings ( myri10ge_netdev ( priv ) ) );
+	if ( rc ) {
+		DBG ("register_nvo failed");
+		return rc;
+	}
+
+	priv->nvo_registered = 1;
+	DBG2 ( "NVO supported\n" );
+	return 0;
+}
+
+void
+myri10ge_nv_fini ( struct myri10ge_private *priv )
+{
+	/* Simply return if nonvolatile access is not supported. */
+
+	if ( 0 == priv->nvo_registered )
+		return;
+
+	unregister_nvo ( &priv->nvo );
+}
+
+/****************************************************************
+ * iPXE PCI Device Driver API functions
+ ****************************************************************/
+
+/*
+ * Initialize the PCI device.
+ *
+ * @v pci 		The device's associated pci_device structure.
+ * @v id  		The PCI device + vendor id.
+ * @ret rc		Returns zero if successfully initialized.
+ *
+ * This function is called very early on, while iPXE is initializing.
+ * This is a iPXE PCI Device Driver API function.
+ */
+static int myri10ge_pci_probe ( struct pci_device *pci )
+{
+	static struct net_device_operations myri10ge_operations = {
+		.open     = myri10ge_net_open,
+		.close    = myri10ge_net_close,
+		.transmit = myri10ge_net_transmit,
+		.poll     = myri10ge_net_poll,
+		.irq      = myri10ge_net_irq
+	};
+
+	const char *dbg;
+	int rc;
+	struct net_device *netdev;
+	struct myri10ge_private *priv;
+
+	DBGP ( "myri10ge_pci_probe: " );
+
+	netdev = alloc_etherdev ( sizeof ( *priv ) );
+	if ( !netdev ) {
+		rc = -ENOMEM;
+		dbg = "alloc_etherdev";
+		goto abort_with_nothing;
+	}
+
+	netdev_init ( netdev, &myri10ge_operations );
+	priv = myri10ge_priv ( netdev );
+
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+
+	/* Make sure interrupts are disabled. */
+
+	myri10ge_net_irq ( netdev, 0 );
+
+	/* Find the PCI Vendor-Specific capability. */
+
+	priv->pci_cap_vs = pci_find_capability ( pci , PCI_CAP_ID_VNDR );
+	if ( 0 == priv->pci_cap_vs ) {
+		rc = -ENOTSUP;
+		dbg = "no_vs";
+		goto abort_with_netdev_init;
+	}
+
+	/* Read the NIC HW address. */
+
+	rc = mac_address_from_string_specs ( pci,
+					     priv->pci_cap_vs,
+					     netdev->hw_addr );
+	if ( rc ) {
+		dbg = "mac_from_ss";
+		goto abort_with_netdev_init;
+	}
+	DBGP ( "mac " );
+
+	/* Enable bus master, etc. */
+
+	adjust_pci_device ( pci );
+	DBGP ( "pci " );
+
+	/* Register the initialized network device. */
+
+	rc = register_netdev ( netdev );
+	if ( rc ) {
+		dbg = "register_netdev";
+		goto abort_with_netdev_init;
+	}
+
+	/* Initialize NonVolatile Storage support. */
+
+	rc = myri10ge_nv_init ( priv );
+	if ( rc ) {
+		dbg = "myri10ge_nv_init";
+		goto abort_with_registered_netdev;
+	}
+
+	DBGP ( "done\n" );
+
+	return 0;
+
+abort_with_registered_netdev:
+	unregister_netdev ( netdev );
+abort_with_netdev_init:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+abort_with_nothing:
+	DBG ( "%s:%s\n", dbg, strerror ( rc ) );
+	return rc;
+}
+
+/*
+ * Remove a device from the PCI device list.
+ *
+ * @v pci		PCI device to remove.
+ *
+ * This is a PCI Device Driver API function.
+ */
+static void myri10ge_pci_remove ( struct pci_device *pci )
+{
+	struct net_device	*netdev;
+
+	DBGP ( "myri10ge_pci_remove\n" );
+	netdev = pci_get_drvdata ( pci );
+
+	myri10ge_nv_fini ( myri10ge_priv ( netdev ) );
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/****************************************************************
+ * iPXE Network Device Driver Operations
+ ****************************************************************/
+
+/*
+ * Close a network device.
+ *
+ * @v netdev		Device to close.
+ *
+ * This is a iPXE Network Device Driver API function.
+ */
+static void myri10ge_net_close ( struct net_device *netdev )
+{
+	struct myri10ge_private *priv;
+	uint32			 data[3];
+
+	DBGP ( "myri10ge_net_close\n" );
+	priv = myri10ge_priv ( netdev );
+
+	/* disable interrupts */
+
+	myri10ge_net_irq ( netdev, 0 );
+
+	/* Reset the NIC interface, so we won't get any more events from
+	   the NIC. */
+
+	myri10ge_command ( priv, MXGEFW_CMD_RESET, data );
+
+	/* Free receive buffers that were never filled. */
+
+	while ( priv->receives_done != priv->receives_posted ) {
+		free_iob ( priv->receive_iob[priv->receives_done
+					     & MYRI10GE_RECEIVE_WRAP] );
+		++priv->receives_done;
+	}
+
+	/* Release DMAable memory. */
+
+	free_dma ( priv->dma, sizeof ( *priv->dma ) );
+
+	/* Erase all state from the open. */
+
+	memset ( priv, 0, sizeof ( *priv ) );
+
+	DBG2_RINGS ( priv );
+}
+
+/*
+ * Enable or disable IRQ masking.
+ *
+ * @v netdev		Device to control.
+ * @v enable		Zero to mask off IRQ, non-zero to enable IRQ.
+ *
+ * This is a iPXE Network Driver API function.
+ */
+static void myri10ge_net_irq ( struct net_device *netdev, int enable )
+{
+	struct pci_device	*pci_dev;
+	uint16			 val;
+
+	DBGP ( "myri10ge_net_irq\n" );
+	pci_dev = ( struct pci_device * ) netdev->dev;
+
+	/* Adjust the Interrupt Disable bit in the Command register of the
+	   PCI Device. */
+
+	pci_read_config_word ( pci_dev, PCI_COMMAND, &val );
+	if ( enable )
+		val &= ~PCI_COMMAND_INTX_DISABLE;
+	else
+		val |= PCI_COMMAND_INTX_DISABLE;
+	pci_write_config_word ( pci_dev, PCI_COMMAND, val );
+}
+
+/*
+ * Opens a network device.
+ *
+ * @v netdev		Device to be opened.
+ * @ret rc  		Non-zero if failed to open.
+ *
+ * This enables tx and rx on the device.
+ * This is a iPXE Network Device Driver API function.
+ */
+static int myri10ge_net_open ( struct net_device *netdev )
+{
+	const char		*dbg;	/* printed upon error return */
+	int			 rc;
+	struct io_buffer	*iob;
+	struct myri10ge_private *priv;
+	uint32			 data[3];
+	struct pci_device	*pci_dev;
+	void			*membase;
+
+	DBGP ( "myri10ge_net_open\n" );
+	priv	= myri10ge_priv ( netdev );
+	pci_dev = ( struct pci_device * ) netdev->dev;
+	membase = phys_to_virt ( pci_dev->membase );
+
+	/* Compute address for passing commands to the firmware. */
+
+	priv->command = membase + MXGEFW_ETH_CMD;
+
+	/* Ensure interrupts are disabled. */
+
+	myri10ge_net_irq ( netdev, 0 );
+
+	/* Allocate cleared DMAable buffers. */
+
+	priv->dma = malloc_dma ( sizeof ( *priv->dma ) , 128 );
+	if ( !priv->dma ) {
+		rc = -ENOMEM;
+		dbg = "DMA";
+		goto abort_with_nothing;
+	}
+	memset ( priv->dma, 0, sizeof ( *priv->dma ) );
+
+	/* Simplify following code. */
+
+#define TRY( prefix, base, suffix ) do {		\
+		rc = myri10ge_command ( priv,		\
+					MXGEFW_		\
+					## prefix	\
+					## base		\
+					## suffix,	\
+					data );		\
+		if ( rc ) {				\
+			dbg = #base;			\
+			goto abort_with_dma;		\
+		}					\
+	} while ( 0 )
+
+	/* Send a reset command to the card to see if it is alive,
+	   and to reset its queue state. */
+
+	TRY ( CMD_, RESET , );
+
+	/* Set the interrupt queue size. */
+
+	data[0] = ( (uint32_t)( sizeof ( priv->dma->receive_completion ) )
+		    | MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK );
+	TRY ( CMD_SET_ , INTRQ_SIZE , );
+
+	/* Set the interrupt queue DMA address. */
+
+	data[0] = virt_to_bus ( &priv->dma->receive_completion );
+	data[1] = 0;
+	TRY ( CMD_SET_, INTRQ_DMA, );
+
+	/* Get the NIC interrupt claim address. */
+
+	TRY ( CMD_GET_, IRQ_ACK, _OFFSET );
+	priv->irq_claim = membase + data[0];
+
+	/* Get the NIC interrupt assert address. */
+
+	TRY ( CMD_GET_, IRQ_DEASSERT, _OFFSET );
+	priv->irq_deassert = membase + data[0];
+
+	/* Disable interrupt coalescing, which is inappropriate for the
+	   minimal buffering we provide. */
+
+	TRY ( CMD_GET_, INTR_COAL, _DELAY_OFFSET );
+	* ( ( uint32 * ) ( membase + data[0] ) ) = 0;
+
+	/* Set the NIC mac address. */
+
+	data[0] = ( netdev->ll_addr[0] << 24
+		    | netdev->ll_addr[1] << 16
+		    | netdev->ll_addr[2] << 8
+		    | netdev->ll_addr[3] );
+	data[1] = ( ( netdev->ll_addr[4] << 8 )
+		     | netdev->ll_addr[5] );
+	TRY ( SET_ , MAC_ADDRESS , );
+
+	/* Enable multicast receives, because some iPXE clients don't work
+	   without multicast. . */
+
+	TRY ( ENABLE_ , ALLMULTI , );
+
+	/* Disable Ethernet flow control, so the NIC cannot deadlock the
+	   network under any circumstances. */
+
+	TRY ( DISABLE_ , FLOW , _CONTROL );
+
+	/* Compute transmit ring sizes. */
+
+	data[0] = 0;		/* slice 0 */
+	TRY ( CMD_GET_, SEND_RING, _SIZE );
+	priv->transmit_ring_wrap
+		= data[0] / sizeof ( mcp_kreq_ether_send_t ) - 1;
+	if ( priv->transmit_ring_wrap
+	     & ( priv->transmit_ring_wrap + 1 ) ) {
+		rc = -EPROTO;
+		dbg = "TX_RING";
+		goto abort_with_dma;
+	}
+
+	/* Compute receive ring sizes. */
+
+	data[0] = 0;		/* slice 0 */
+	TRY ( CMD_GET_ , RX_RING , _SIZE );
+	priv->receive_post_ring_wrap = data[0] / sizeof ( mcp_dma_addr_t ) - 1;
+	if ( priv->receive_post_ring_wrap
+	     & ( priv->receive_post_ring_wrap + 1 ) ) {
+		rc = -EPROTO;
+		dbg = "RX_RING";
+		goto abort_with_dma;
+	}
+
+	/* Get NIC transmit ring address. */
+
+	data[0] = 0;		/* slice 0. */
+	TRY ( CMD_GET_, SEND, _OFFSET );
+	priv->transmit_ring = membase + data[0];
+
+	/* Get the NIC receive ring address. */
+
+	data[0] = 0;		/* slice 0. */
+	TRY ( CMD_GET_, SMALL_RX, _OFFSET );
+	priv->receive_post_ring = membase + data[0];
+
+	/* Set the Nic MTU. */
+
+	data[0] = ETH_FRAME_LEN;
+	TRY ( CMD_SET_, MTU, );
+
+	/* Tell the NIC our buffer sizes. ( We use only small buffers, so we
+	   set both buffer sizes to the same value, which will force all
+	   received frames to use small buffers. ) */
+
+	data[0] = MXGEFW_PAD + ETH_FRAME_LEN;
+	TRY ( CMD_SET_, SMALL_BUFFER, _SIZE );
+	data[0] = MXGEFW_PAD + ETH_FRAME_LEN;
+	TRY ( CMD_SET_, BIG_BUFFER, _SIZE );
+
+        /* Tell firmware where to DMA IRQ data */
+
+	data[0] = virt_to_bus ( &priv->dma->irq_data );
+	data[1] = 0;
+	data[2] = sizeof ( priv->dma->irq_data );
+	TRY ( CMD_SET_, STATS_DMA_V2, );
+
+	/* Post receives. */
+
+	while ( priv->receives_posted <= MYRI10GE_RECEIVE_WRAP ) {
+
+		/* Reserve 2 extra bytes at the start of packets, since
+		   the firmware always skips the first 2 bytes of the buffer
+		   so TCP headers will be aligned. */
+
+		iob = alloc_iob ( MXGEFW_PAD + ETH_FRAME_LEN );
+		if ( !iob ) {
+			rc = -ENOMEM;
+			dbg = "alloc_iob";
+			goto abort_with_receives_posted;
+		}
+		iob_reserve ( iob, MXGEFW_PAD );
+		myri10ge_post_receive ( priv, iob );
+	}
+
+	/* Bring up the link. */
+
+	TRY ( CMD_, ETHERNET_UP, );
+
+	DBG2_RINGS ( priv );
+	return 0;
+
+abort_with_receives_posted:
+	while ( priv->receives_posted-- )
+		free_iob ( priv->receive_iob[priv->receives_posted] );
+abort_with_dma:
+	/* Because the link is not up, we don't have to reset the NIC here. */
+	free_dma ( priv->dma, sizeof ( *priv->dma ) );
+abort_with_nothing:
+	/* Erase all signs of the failed open. */
+	memset ( priv, 0, sizeof ( *priv ) );
+	DBG ( "%s: %s\n", dbg, strerror ( rc ) );
+	return ( rc );
+}
+
+/*
+ * This function allows a driver to process events during operation.
+ *
+ * @v netdev		Device being polled.
+ *
+ * This is called periodically by iPXE to let the driver check the status of
+ * transmitted packets and to allow the driver to check for received packets.
+ * This is a iPXE Network Device Driver API function.
+ */
+static void myri10ge_net_poll ( struct net_device *netdev )
+{
+	struct io_buffer		*iob;
+	struct io_buffer		*replacement;
+	struct myri10ge_dma_buffers	*dma;
+	struct myri10ge_private		*priv;
+	unsigned int			 length;
+	unsigned int			 orig_receives_posted;
+
+	DBGP ( "myri10ge_net_poll\n" );
+	priv = myri10ge_priv ( netdev );
+	dma  = priv->dma;
+
+	/* Process any pending interrupt. */
+
+	myri10ge_interrupt_handler ( netdev );
+
+	/* Pass up received frames, but limit ourselves to receives posted
+	   before this function was called, so we cannot livelock if
+	   receives are arriving faster than we process them. */
+
+	orig_receives_posted = priv->receives_posted;
+	while ( priv->receives_done != orig_receives_posted ) {
+
+		/* Stop if there is no pending receive. */
+
+		length = ntohs ( dma->receive_completion
+				 [priv->receives_done
+				  & MYRI10GE_RECEIVE_COMPLETION_WRAP]
+				 .length );
+		if ( length == 0 )
+			break;
+
+		/* Allocate a replacement buffer.  If none is available,
+		   stop passing up packets until a buffer is available.
+
+		   Reserve 2 extra bytes at the start of packets, since
+		   the firmware always skips the first 2 bytes of the buffer
+		   so TCP headers will be aligned. */
+
+		replacement = alloc_iob ( MXGEFW_PAD + ETH_FRAME_LEN );
+		if ( !replacement ) {
+			DBG ( "NO RX BUF\n" );
+			break;
+		}
+		iob_reserve ( replacement, MXGEFW_PAD );
+
+		/* Pass up the received frame. */
+
+		iob = priv->receive_iob[priv->receives_done
+					& MYRI10GE_RECEIVE_WRAP];
+		iob_put ( iob, length );
+		netdev_rx ( netdev, iob );
+
+		/* We have consumed the packet, so clear the receive
+		   notification. */
+
+		dma->receive_completion [priv->receives_done
+					 & MYRI10GE_RECEIVE_COMPLETION_WRAP]
+			.length = 0;
+		wmb();
+
+		/* Replace the passed-up I/O buffer. */
+
+		myri10ge_post_receive ( priv, replacement );
+		++priv->receives_done;
+		DBG2_RINGS ( priv );
+	}
+}
+
+/*
+ * This transmits a packet.
+ *
+ * @v netdev		Device to transmit from.
+ * @v iobuf 		Data to transmit.
+ * @ret rc  		Non-zero if failed to transmit.
+ *
+ * This is a iPXE Network Driver API function.
+ */
+static int myri10ge_net_transmit ( struct net_device *netdev,
+				   struct io_buffer *iobuf )
+{
+	mcp_kreq_ether_send_t	*kreq;
+	size_t			 len;
+	struct myri10ge_private *priv;
+	uint32			 transmits_posted;
+
+	DBGP ( "myri10ge_net_transmit\n" );
+	priv = myri10ge_priv ( netdev );
+
+	/* Confirm space in the send ring. */
+
+	transmits_posted = priv->transmits_posted;
+	if ( transmits_posted - priv->transmits_done
+	     > MYRI10GE_TRANSMIT_WRAP ) {
+		DBG ( "TX ring full\n" );
+		return -ENOBUFS;
+	}
+
+	DBG2 ( "TX %p+%zd ", iobuf->data, iob_len ( iobuf ) );
+	DBG2_HD ( iobuf->data, 14 );
+
+	/* Record the packet being transmitted, so we can later report
+	   send completion. */
+
+	priv->transmit_iob[transmits_posted & MYRI10GE_TRANSMIT_WRAP] = iobuf;
+
+	/* Copy and pad undersized frames, because the NIC does not pad,
+	   and we would rather copy small frames than do a gather. */
+
+	len = iob_len ( iobuf );
+	if ( len < ETH_ZLEN ) {
+		iob_pad ( iobuf, ETH_ZLEN );
+		len = ETH_ZLEN;
+	}
+
+	/* Enqueue the packet by writing a descriptor to the NIC.
+	   This is a bit tricky because the HW requires 32-bit writes,
+	   but the structure has smaller fields. */
+
+	kreq = &priv->transmit_ring[transmits_posted
+				    & priv->transmit_ring_wrap];
+	kreq->addr_high = 0;
+	kreq->addr_low = htonl ( virt_to_bus ( iobuf->data ) );
+	( ( uint32 * ) kreq ) [2] = htonl (
+		0x0000 << 16	 /* pseudo_header_offset */
+		| ( len & 0xFFFF ) /* length */
+		);
+	wmb();
+	( ( uint32 * ) kreq ) [3] = htonl (
+		0x00 << 24	/* pad */
+		| 0x01 << 16	/* rdma_count */
+		| 0x00 << 8	/* cksum_offset */
+		| ( MXGEFW_FLAGS_SMALL
+		    | MXGEFW_FLAGS_FIRST
+		    | MXGEFW_FLAGS_NO_TSO ) /* flags */
+		);
+	wmb();
+
+	/* Mark the slot as consumed and return. */
+
+	priv->transmits_posted = ++transmits_posted;
+	DBG2_RINGS ( priv );
+	return 0;
+}
+
+static struct pci_device_id myri10ge_nics[] = {
+	/* Each of these macros must be a single line to satisfy a script. */
+	PCI_ROM ( 0x14c1, 0x0008, "myri10ge", "Myricom 10Gb Ethernet Adapter", 0 ) ,
+};
+
+struct pci_driver myri10ge_driver __pci_driver = {
+	.ids      = myri10ge_nics,
+	.id_count = ( sizeof ( myri10ge_nics ) / sizeof ( myri10ge_nics[0] ) ) ,
+	.probe    = myri10ge_pci_probe,
+	.remove   = myri10ge_pci_remove
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge_mcp.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge_mcp.h
new file mode 100644
index 0000000..397f8b0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/myri10ge_mcp.h
@@ -0,0 +1,514 @@
+/************************************************* -*- linux-c -*-
+ * Myricom 10Gb Network Interface Card Software
+ * Copyright 2005-2010, Myricom, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ ****************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _myri10ge_mcp_h
+#define _myri10ge_mcp_h
+
+#define MXGEFW_VERSION_MAJOR	1
+#define MXGEFW_VERSION_MINOR	4
+
+#ifdef MXGEFW
+#ifndef _stdint_h_
+typedef signed char          int8_t;
+typedef signed short        int16_t;
+typedef signed int          int32_t;
+typedef signed long long    int64_t;
+typedef unsigned char       uint8_t;
+typedef unsigned short     uint16_t;
+typedef unsigned int       uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+#endif
+
+/* 8 Bytes */
+struct mcp_dma_addr {
+  uint32_t high;
+  uint32_t low;
+};
+typedef struct mcp_dma_addr mcp_dma_addr_t;
+
+/* 4 Bytes */
+struct mcp_slot {
+  uint16_t checksum;
+  uint16_t length;
+};
+typedef struct mcp_slot mcp_slot_t;
+
+#ifdef MXGEFW_NDIS
+/* 8-byte descriptor, exclusively used by NDIS drivers. */
+struct mcp_slot_8 {
+  /* Place hash value at the top so it gets written before length.
+   * The driver polls length.
+   */
+  uint32_t hash;
+  uint16_t checksum;
+  uint16_t length;
+};
+typedef struct mcp_slot_8 mcp_slot_8_t;
+
+/* Two bits of length in mcp_slot are used to indicate hash type. */
+#define MXGEFW_RSS_HASH_NULL (0 << 14) /* bit 15:14 = 00 */
+#define MXGEFW_RSS_HASH_IPV4 (1 << 14) /* bit 15:14 = 01 */
+#define MXGEFW_RSS_HASH_TCP_IPV4 (2 << 14) /* bit 15:14 = 10 */
+#define MXGEFW_RSS_HASH_MASK (3 << 14) /* bit 15:14 = 11 */
+#endif
+
+/* 64 Bytes */
+struct mcp_cmd {
+  uint32_t cmd;
+  uint32_t data0;	/* will be low portion if data > 32 bits */
+  /* 8 */
+  uint32_t data1;	/* will be high portion if data > 32 bits */
+  uint32_t data2;	/* currently unused.. */
+  /* 16 */
+  struct mcp_dma_addr response_addr;
+  /* 24 */
+  uint8_t pad[40];
+};
+typedef struct mcp_cmd mcp_cmd_t;
+
+/* 8 Bytes */
+struct mcp_cmd_response {
+  uint32_t data;
+  uint32_t result;
+};
+typedef struct mcp_cmd_response mcp_cmd_response_t;
+
+
+
+/*
+   flags used in mcp_kreq_ether_send_t:
+
+   The SMALL flag is only needed in the first segment. It is raised
+   for packets that are total less or equal 512 bytes.
+
+   The CKSUM flag must be set in all segments.
+
+   The PADDED flags is set if the packet needs to be padded, and it
+   must be set for all segments.
+
+   The  MXGEFW_FLAGS_ALIGN_ODD must be set if the cumulative
+   length of all previous segments was odd.
+*/
+
+
+#define MXGEFW_FLAGS_SMALL      0x1
+#define MXGEFW_FLAGS_TSO_HDR    0x1
+#define MXGEFW_FLAGS_FIRST      0x2
+#define MXGEFW_FLAGS_ALIGN_ODD  0x4
+#define MXGEFW_FLAGS_CKSUM      0x8
+#define MXGEFW_FLAGS_TSO_LAST   0x8
+#define MXGEFW_FLAGS_NO_TSO     0x10
+#define MXGEFW_FLAGS_TSO_CHOP   0x10
+#define MXGEFW_FLAGS_TSO_PLD    0x20
+
+#define MXGEFW_SEND_SMALL_SIZE  1520
+#define MXGEFW_MAX_MTU          9400
+
+union mcp_pso_or_cumlen {
+  uint16_t pseudo_hdr_offset;
+  uint16_t cum_len;
+};
+typedef union mcp_pso_or_cumlen mcp_pso_or_cumlen_t;
+
+#define	MXGEFW_MAX_SEND_DESC 12
+#define MXGEFW_PAD	    2
+
+/* 16 Bytes */
+struct mcp_kreq_ether_send {
+  uint32_t addr_high;
+  uint32_t addr_low;
+  uint16_t pseudo_hdr_offset;
+  uint16_t length;
+  uint8_t  pad;
+  uint8_t  rdma_count;
+  uint8_t  cksum_offset; 	/* where to start computing cksum */
+  uint8_t  flags;	       	/* as defined above */
+};
+typedef struct mcp_kreq_ether_send mcp_kreq_ether_send_t;
+
+/* 8 Bytes */
+struct mcp_kreq_ether_recv {
+  uint32_t addr_high;
+  uint32_t addr_low;
+};
+typedef struct mcp_kreq_ether_recv mcp_kreq_ether_recv_t;
+
+
+/* Commands */
+
+#define	MXGEFW_BOOT_HANDOFF	0xfc0000
+#define	MXGEFW_BOOT_DUMMY_RDMA	0xfc01c0
+
+#define	MXGEFW_ETH_CMD		0xf80000
+#define	MXGEFW_ETH_SEND_4	0x200000
+#define	MXGEFW_ETH_SEND_1	0x240000
+#define	MXGEFW_ETH_SEND_2	0x280000
+#define	MXGEFW_ETH_SEND_3	0x2c0000
+#define	MXGEFW_ETH_RECV_SMALL	0x300000
+#define	MXGEFW_ETH_RECV_BIG	0x340000
+#define	MXGEFW_ETH_SEND_GO	0x380000
+#define	MXGEFW_ETH_SEND_STOP	0x3C0000
+
+#define	MXGEFW_ETH_SEND(n)		(0x200000 + (((n) & 0x03) * 0x40000))
+#define	MXGEFW_ETH_SEND_OFFSET(n)	(MXGEFW_ETH_SEND(n) - MXGEFW_ETH_SEND_4)
+
+enum myri10ge_mcp_cmd_type {
+  MXGEFW_CMD_NONE = 0,
+  /* Reset the mcp, it is left in a safe state, waiting
+     for the driver to set all its parameters */
+  MXGEFW_CMD_RESET = 1,
+
+  /* get the version number of the current firmware..
+     (may be available in the eeprom strings..? */
+  MXGEFW_GET_MCP_VERSION = 2,
+
+
+  /* Parameters which must be set by the driver before it can
+     issue MXGEFW_CMD_ETHERNET_UP. They persist until the next
+     MXGEFW_CMD_RESET is issued */
+
+  MXGEFW_CMD_SET_INTRQ_DMA = 3,
+  /* data0 = LSW of the host address
+   * data1 = MSW of the host address
+   * data2 = slice number if multiple slices are used
+   */
+
+  MXGEFW_CMD_SET_BIG_BUFFER_SIZE = 4,	/* in bytes, power of 2 */
+  MXGEFW_CMD_SET_SMALL_BUFFER_SIZE = 5,	/* in bytes */
+
+
+  /* Parameters which refer to lanai SRAM addresses where the
+     driver must issue PIO writes for various things */
+
+  MXGEFW_CMD_GET_SEND_OFFSET = 6,
+  MXGEFW_CMD_GET_SMALL_RX_OFFSET = 7,
+  MXGEFW_CMD_GET_BIG_RX_OFFSET = 8,
+  /* data0 = slice number if multiple slices are used */
+
+  MXGEFW_CMD_GET_IRQ_ACK_OFFSET = 9,
+  MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET = 10,
+
+  /* Parameters which refer to rings stored on the MCP,
+     and whose size is controlled by the mcp */
+
+  MXGEFW_CMD_GET_SEND_RING_SIZE = 11,	/* in bytes */
+  MXGEFW_CMD_GET_RX_RING_SIZE = 12,	/* in bytes */
+
+  /* Parameters which refer to rings stored in the host,
+     and whose size is controlled by the host.  Note that
+     all must be physically contiguous and must contain
+     a power of 2 number of entries.  */
+
+  MXGEFW_CMD_SET_INTRQ_SIZE = 13, 	/* in bytes */
+#define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK  (1 << 31)
+
+  /* command to bring ethernet interface up.  Above parameters
+     (plus mtu & mac address) must have been exchanged prior
+     to issuing this command  */
+  MXGEFW_CMD_ETHERNET_UP = 14,
+
+  /* command to bring ethernet interface down.  No further sends
+     or receives may be processed until an MXGEFW_CMD_ETHERNET_UP
+     is issued, and all interrupt queues must be flushed prior
+     to ack'ing this command */
+
+  MXGEFW_CMD_ETHERNET_DOWN = 15,
+
+  /* commands the driver may issue live, without resetting
+     the nic.  Note that increasing the mtu "live" should
+     only be done if the driver has already supplied buffers
+     sufficiently large to handle the new mtu.  Decreasing
+     the mtu live is safe */
+
+  MXGEFW_CMD_SET_MTU = 16,
+  MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET = 17,  /* in microseconds */
+  MXGEFW_CMD_SET_STATS_INTERVAL = 18,   /* in microseconds */
+  MXGEFW_CMD_SET_STATS_DMA_OBSOLETE = 19, /* replaced by SET_STATS_DMA_V2 */
+
+  MXGEFW_ENABLE_PROMISC = 20,
+  MXGEFW_DISABLE_PROMISC = 21,
+  MXGEFW_SET_MAC_ADDRESS = 22,
+
+  MXGEFW_ENABLE_FLOW_CONTROL = 23,
+  MXGEFW_DISABLE_FLOW_CONTROL = 24,
+
+  /* do a DMA test
+     data0,data1 = DMA address
+     data2       = RDMA length (MSH), WDMA length (LSH)
+     command return data = repetitions (MSH), 0.5-ms ticks (LSH)
+  */
+  MXGEFW_DMA_TEST = 25,
+
+  MXGEFW_ENABLE_ALLMULTI = 26,
+  MXGEFW_DISABLE_ALLMULTI = 27,
+
+  /* returns MXGEFW_CMD_ERROR_MULTICAST
+     if there is no room in the cache
+     data0,MSH(data1) = multicast group address */
+  MXGEFW_JOIN_MULTICAST_GROUP = 28,
+  /* returns MXGEFW_CMD_ERROR_MULTICAST
+     if the address is not in the cache,
+     or is equal to FF-FF-FF-FF-FF-FF
+     data0,MSH(data1) = multicast group address */
+  MXGEFW_LEAVE_MULTICAST_GROUP = 29,
+  MXGEFW_LEAVE_ALL_MULTICAST_GROUPS = 30,
+
+  MXGEFW_CMD_SET_STATS_DMA_V2 = 31,
+  /* data0, data1 = bus addr,
+   * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows
+   * adding new stuff to mcp_irq_data without changing the ABI
+   *
+   * If multiple slices are used, data2 contains both the size of the
+   * structure (in the lower 16 bits) and the slice number
+   * (in the upper 16 bits).
+   */
+
+  MXGEFW_CMD_UNALIGNED_TEST = 32,
+  /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
+     chipset */
+
+  MXGEFW_CMD_UNALIGNED_STATUS = 33,
+  /* return data = boolean, true if the chipset is known to be unaligned */
+
+  MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS = 34,
+  /* data0 = number of big buffers to use.  It must be 0 or a power of 2.
+   * 0 indicates that the NIC consumes as many buffers as they are required
+   * for packet. This is the default behavior.
+   * A power of 2 number indicates that the NIC always uses the specified
+   * number of buffers for each big receive packet.
+   * It is up to the driver to ensure that this value is big enough for
+   * the NIC to be able to receive maximum-sized packets.
+   */
+
+  MXGEFW_CMD_GET_MAX_RSS_QUEUES = 35,
+  MXGEFW_CMD_ENABLE_RSS_QUEUES = 36,
+  /* data0 = number of slices n (0, 1, ..., n-1) to enable
+   * data1 = interrupt mode | use of multiple transmit queues.
+   * 0=share one INTx/MSI.
+   * 1=use one MSI-X per queue.
+   * If all queues share one interrupt, the driver must have set
+   * RSS_SHARED_INTERRUPT_DMA before enabling queues.
+   * 2=enable both receive and send queues.
+   * Without this bit set, only one send queue (slice 0's send queue)
+   * is enabled.  The receive queues are always enabled.
+   */
+#define MXGEFW_SLICE_INTR_MODE_SHARED          0x0
+#define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE   0x1
+#define MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES 0x2
+
+  MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET = 37,
+  MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA = 38,
+  /* data0, data1 = bus address lsw, msw */
+  MXGEFW_CMD_GET_RSS_TABLE_OFFSET = 39,
+  /* get the offset of the indirection table */
+  MXGEFW_CMD_SET_RSS_TABLE_SIZE = 40,
+  /* set the size of the indirection table */
+  MXGEFW_CMD_GET_RSS_KEY_OFFSET = 41,
+  /* get the offset of the secret key */
+  MXGEFW_CMD_RSS_KEY_UPDATED = 42,
+  /* tell nic that the secret key's been updated */
+  MXGEFW_CMD_SET_RSS_ENABLE = 43,
+  /* data0 = enable/disable rss
+   * 0: disable rss.  nic does not distribute receive packets.
+   * 1: enable rss.  nic distributes receive packets among queues.
+   * data1 = hash type
+   * 1: IPV4            (required by RSS)
+   * 2: TCP_IPV4        (required by RSS)
+   * 3: IPV4 | TCP_IPV4 (required by RSS)
+   * 4: source port
+   * 5: source port + destination port
+   */
+#define MXGEFW_RSS_HASH_TYPE_IPV4      0x1
+#define MXGEFW_RSS_HASH_TYPE_TCP_IPV4  0x2
+#define MXGEFW_RSS_HASH_TYPE_SRC_PORT  0x4
+#define MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT 0x5
+#define MXGEFW_RSS_HASH_TYPE_MAX 0x5
+
+  MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE = 44,
+  /* Return data = the max. size of the entire headers of a IPv6 TSO packet.
+   * If the header size of a IPv6 TSO packet is larger than the specified
+   * value, then the driver must not use TSO.
+   * This size restriction only applies to IPv6 TSO.
+   * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC
+   * always has enough header buffer to store maximum-sized headers.
+   */
+
+  MXGEFW_CMD_SET_TSO_MODE = 45,
+  /* data0 = TSO mode.
+   * 0: Linux/FreeBSD style (NIC default)
+   * 1: NDIS/NetBSD style
+   */
+#define MXGEFW_TSO_MODE_LINUX  0
+#define MXGEFW_TSO_MODE_NDIS   1
+
+  MXGEFW_CMD_MDIO_READ = 46,
+  /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
+  MXGEFW_CMD_MDIO_WRITE = 47,
+  /* data0 = dev_addr,  data1 = register/addr, data2 = value  */
+
+  MXGEFW_CMD_I2C_READ = 48,
+  /* Starts to get a fresh copy of one byte or of the module i2c table, the
+   * obtained data is cached inside the xaui-xfi chip :
+   *   data0 :  0 => get one byte, 1=> get 256 bytes
+   *   data1 :  If data0 == 0: location to refresh
+   *               bit 7:0  register location
+   *               bit 8:15 is the i2c slave addr (0 is interpreted as 0xA1)
+   *               bit 23:16 is the i2c bus number (for multi-port NICs)
+   *            If data0 == 1: unused
+   * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes
+   * During the i2c operation,  MXGEFW_CMD_I2C_READ or MXGEFW_CMD_I2C_BYTE attempts
+   *  will return MXGEFW_CMD_ERROR_BUSY
+   */
+  MXGEFW_CMD_I2C_BYTE = 49,
+  /* Return the last obtained copy of a given byte in the xfp i2c table
+   * (copy cached during the last relevant MXGEFW_CMD_I2C_READ)
+   *   data0 : index of the desired table entry
+   *  Return data = the byte stored at the requested index in the table
+   */
+
+  MXGEFW_CMD_GET_VPUMP_OFFSET = 50,
+  /* Return data = NIC memory offset of mcp_vpump_public_global */
+  MXGEFW_CMD_RESET_VPUMP = 51,
+  /* Resets the VPUMP state */
+
+  MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE = 52,
+  /* data0 = mcp_slot type to use.
+   * 0 = the default 4B mcp_slot
+   * 1 = 8B mcp_slot_8
+   */
+#define MXGEFW_RSS_MCP_SLOT_TYPE_MIN        0
+#define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH  1
+
+  MXGEFW_CMD_SET_THROTTLE_FACTOR = 53,
+  /* set the throttle factor for ethp_z8e
+     data0 = throttle_factor
+     throttle_factor = 256 * pcie-raw-speed / tx_speed
+     tx_speed = 256 * pcie-raw-speed / throttle_factor
+
+     For PCI-E x8: pcie-raw-speed == 16Gb/s
+     For PCI-E x4: pcie-raw-speed == 8Gb/s
+
+     ex1: throttle_factor == 0x1a0 (416), tx_speed == 1.23GB/s == 9.846 Gb/s
+     ex2: throttle_factor == 0x200 (512), tx_speed == 1.0GB/s == 8 Gb/s
+
+     with tx_boundary == 2048, max-throttle-factor == 8191 => min-speed == 500Mb/s
+     with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s
+  */
+
+  MXGEFW_CMD_VPUMP_UP = 54,
+  /* Allocates VPump Connection, Send Request and Zero copy buffer address tables */
+  MXGEFW_CMD_GET_VPUMP_CLK = 55,
+  /* Get the lanai clock */
+
+  MXGEFW_CMD_GET_DCA_OFFSET = 56,
+  /* offset of dca control for WDMAs */
+
+  /* VMWare NetQueue commands */
+  MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE = 57,
+  MXGEFW_CMD_NETQ_ADD_FILTER = 58,
+  /* data0 = filter_id << 16 | queue << 8 | type */
+  /* data1 = MS4 of MAC Addr */
+  /* data2 = LS2_MAC << 16 | VLAN_tag */
+  MXGEFW_CMD_NETQ_DEL_FILTER = 59,
+  /* data0 = filter_id */
+  MXGEFW_CMD_NETQ_QUERY1 = 60,
+  MXGEFW_CMD_NETQ_QUERY2 = 61,
+  MXGEFW_CMD_NETQ_QUERY3 = 62,
+  MXGEFW_CMD_NETQ_QUERY4 = 63,
+
+  MXGEFW_CMD_RELAX_RXBUFFER_ALIGNMENT = 64,
+  /* When set, small receive buffers can cross page boundaries.
+   * Both small and big receive buffers may start at any address.
+   * This option has performance implications, so use with caution.
+   */
+};
+typedef enum myri10ge_mcp_cmd_type myri10ge_mcp_cmd_type_t;
+
+
+enum myri10ge_mcp_cmd_status {
+  MXGEFW_CMD_OK = 0,
+  MXGEFW_CMD_UNKNOWN = 1,
+  MXGEFW_CMD_ERROR_RANGE = 2,
+  MXGEFW_CMD_ERROR_BUSY = 3,
+  MXGEFW_CMD_ERROR_EMPTY = 4,
+  MXGEFW_CMD_ERROR_CLOSED = 5,
+  MXGEFW_CMD_ERROR_HASH_ERROR = 6,
+  MXGEFW_CMD_ERROR_BAD_PORT = 7,
+  MXGEFW_CMD_ERROR_RESOURCES = 8,
+  MXGEFW_CMD_ERROR_MULTICAST = 9,
+  MXGEFW_CMD_ERROR_UNALIGNED = 10,
+  MXGEFW_CMD_ERROR_NO_MDIO = 11,
+  MXGEFW_CMD_ERROR_I2C_FAILURE = 12,
+  MXGEFW_CMD_ERROR_I2C_ABSENT = 13,
+  MXGEFW_CMD_ERROR_BAD_PCIE_LINK = 14
+};
+typedef enum myri10ge_mcp_cmd_status myri10ge_mcp_cmd_status_t;
+
+
+#define MXGEFW_OLD_IRQ_DATA_LEN 40
+
+struct mcp_irq_data {
+  /* add new counters at the beginning */
+  uint32_t future_use[1];
+  uint32_t dropped_pause;
+  uint32_t dropped_unicast_filtered;
+  uint32_t dropped_bad_crc32;
+  uint32_t dropped_bad_phy;
+  uint32_t dropped_multicast_filtered;
+/* 40 Bytes */
+  uint32_t send_done_count;
+
+#define MXGEFW_LINK_DOWN 0
+#define MXGEFW_LINK_UP 1
+#define MXGEFW_LINK_MYRINET 2
+#define MXGEFW_LINK_UNKNOWN 3
+  uint32_t link_up;
+  uint32_t dropped_link_overflow;
+  uint32_t dropped_link_error_or_filtered;
+  uint32_t dropped_runt;
+  uint32_t dropped_overrun;
+  uint32_t dropped_no_small_buffer;
+  uint32_t dropped_no_big_buffer;
+  uint32_t rdma_tags_available;
+
+  uint8_t tx_stopped;
+  uint8_t link_down;
+  uint8_t stats_updated;
+  uint8_t valid;
+};
+typedef struct mcp_irq_data mcp_irq_data_t;
+
+#ifdef MXGEFW_NDIS
+/* Exclusively used by NDIS drivers */
+struct mcp_rss_shared_interrupt {
+  uint8_t pad[2];
+  uint8_t queue;
+  uint8_t valid;
+};
+#endif
+
+/* definitions for NETQ filter type */
+#define MXGEFW_NETQ_FILTERTYPE_NONE 0
+#define MXGEFW_NETQ_FILTERTYPE_MACADDR 1
+#define MXGEFW_NETQ_FILTERTYPE_VLAN 2
+#define MXGEFW_NETQ_FILTERTYPE_VLANMACADDR 3
+
+#endif /* _myri10ge_mcp_h */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.c
new file mode 100644
index 0000000..1715428
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.c
@@ -0,0 +1,604 @@
+/* 
+   natsemi.c - iPXE driver for the NatSemi DP8381x series.
+ 
+   Based on:
+
+   natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
+
+   Copyright (C) 2001 Entity Cyber, Inc.
+   
+   This development of this Etherboot driver was funded by 
+   
+      Sicom Systems: http://www.sicompos.com/
+   
+   Author: Marty Connor <mdc at etherboot.org>
+   Adapted from a Linux driver which was written by Donald Becker
+   
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+   
+   Original Copyright Notice:
+   
+   Written/copyright 1999-2001 by Donald Becker.
+   
+   This software may be used and distributed according to the terms of
+   the GNU General Public License (GPL), incorporated herein by reference.
+   Drivers based on or derived from this code fall under the GPL and must
+   retain the authorship, copyright and license notice.  This file is not
+   a complete program and may only be used when the entire operating
+   system is licensed under the GPL.  License for under other terms may be
+   available.  Contact the original author for details.
+   
+   The original author may be reached as becker at scyld.com, or at
+   Scyld Computing Corporation
+   410 Severn Ave., Suite 210
+   Annapolis MD 21403
+   
+   Support information and updates available at
+   http://www.scyld.com/network/netsemi.html
+   
+   References:
+   
+   http://www.scyld.com/expert/100mbps.html
+   http://www.scyld.com/expert/NWay.html
+   Datasheet is available from:
+   http://www.national.com/pf/DP/DP83815.html
+
+*/
+
+FILE_LICENCE ( GPL_ANY );
+
+/* Revision History */
+
+/*
+  02 Jul 2007  Udayan Kumar	 1.2 ported the driver from etherboot to iPXE API.
+				     Fully rewritten,adapting the old driver.
+		      	      	     Added a circular buffer for transmit and receive.
+		                     transmit routine will not wait for transmission to finish.
+			             poll routine deals with it.
+  13 Dec 2003  Tim Legge         1.1 Enabled Multicast Support
+  29 May 2001  Marty Connor	 1.0 Initial Release. Tested with Netgear FA311 and FA312 boards
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <unistd.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/spi_bit.h>
+#include <ipxe/threewire.h>
+#include <ipxe/nvo.h>
+#include "natsemi.h"
+
+/*  Function Prototypes: */
+ 
+static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int );
+static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); 
+static void natsemi_init_eeprom ( struct natsemi_private * ); 
+static int natsemi_probe (struct pci_device *pci);
+static void natsemi_reset (struct net_device *netdev);
+static int natsemi_open (struct net_device *netdev);
+static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf);
+static void natsemi_poll (struct net_device *netdev);
+static void natsemi_close (struct net_device *netdev);
+static void natsemi_irq (struct net_device *netdev, int enable);
+static void natsemi_remove (struct pci_device *pci);
+
+/** natsemi net device operations */
+static struct net_device_operations natsemi_operations = {
+        .open           = natsemi_open,
+        .close          = natsemi_close,
+        .transmit       = natsemi_transmit,
+        .poll           = natsemi_poll,
+	.irq		= natsemi_irq,
+};
+
+static int natsemi_spi_read_bit ( struct bit_basher *basher,
+			      unsigned int bit_id ) {
+	struct natsemi_private *np = container_of ( basher, struct natsemi_private,
+						 spibit.basher );
+	uint8_t mask = natsemi_ee_bits[bit_id];
+	uint8_t eereg;
+
+	eereg = inb ( np->ioaddr + EE_REG );
+	return ( eereg & mask );
+}
+
+static void natsemi_spi_write_bit ( struct bit_basher *basher,
+				unsigned int bit_id, unsigned long data ) {
+	struct natsemi_private *np = container_of ( basher, struct natsemi_private,
+						 spibit.basher );
+	uint8_t mask = natsemi_ee_bits[bit_id];
+	uint8_t eereg;
+
+	eereg = inb ( np->ioaddr + EE_REG );
+	eereg &= ~mask;
+	eereg |= ( data & mask );
+	outb ( eereg, np->ioaddr + EE_REG );
+}
+
+static struct bit_basher_operations natsemi_basher_ops = {
+	.read = natsemi_spi_read_bit,
+	.write = natsemi_spi_write_bit,
+};
+
+/*
+ * Set up for EEPROM access
+ *
+ * @v NAT		NATSEMI NIC
+ */
+static void natsemi_init_eeprom ( struct natsemi_private *np ) {
+
+	/* Initialise three-wire bus 
+	 */
+	np->spibit.basher.op = &natsemi_basher_ops;
+	np->spibit.bus.mode = SPI_MODE_THREEWIRE;
+	np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
+	init_spi_bit_basher ( &np->spibit );
+
+	/*natsemi DP 83815 only supports at93c46
+	 */
+	init_at93c46 ( &np->eeprom, 16 );
+	np->eeprom.bus = &np->spibit.bus;
+
+	/* It looks that this portion of EEPROM can be used for
+	 * non-volatile stored options. Data sheet does not talk about
+	 * this region.  Currently it is not working. But with some
+	 * efforts it can.
+	 */
+	nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci	PCI device
+ * @v id	PCI ID
+ * @ret rc	Return status code
+ */
+static int natsemi_probe (struct pci_device *pci) {
+	struct net_device *netdev;
+	struct natsemi_private *np = NULL;
+	uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
+	uint8_t last=0,last1=0;
+	uint8_t prev_bytes[2];
+	int i;
+	int rc;
+
+	/* Allocate net device 
+	 */
+	netdev = alloc_etherdev (sizeof (*np));
+	if (! netdev) 
+		return -ENOMEM;
+
+	netdev_init (netdev, &natsemi_operations);
+	np = netdev->priv;
+	pci_set_drvdata (pci, netdev);
+	netdev->dev = &pci->dev;
+	memset (np, 0, sizeof (*np));
+	np->ioaddr = pci->ioaddr;
+
+	adjust_pci_device (pci);
+
+	natsemi_reset (netdev);
+	natsemi_init_eeprom ( np );
+	nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
+	nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
+
+	/* decoding the MAC address read from NVS 
+	 * and save it in netdev->ll_addr
+         */
+	last = prev_bytes[1] >> 7;
+	for ( i = 0 ; i < ETH_ALEN ; i++ ) {
+		last1 = ll_addr_encoded[i] >> 7;
+		netdev->hw_addr[i] = ll_addr_encoded[i] << 1 | last;
+		last = last1;
+	}
+
+	if ((rc = register_netdev (netdev)) != 0)
+		goto err_register_netdev;
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	return 0;
+
+err_register_netdev:
+
+	natsemi_reset (netdev);
+	netdev_put (netdev);
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci	PCI device
+ */
+static void natsemi_remove (struct pci_device *pci) {
+	struct net_device *netdev = pci_get_drvdata (pci);
+ 
+	unregister_netdev (netdev);
+	natsemi_reset (netdev);
+	netdev_nullify ( netdev );
+	netdev_put (netdev);
+}
+
+/**
+ * Reset NIC
+ *
+ * @v		NATSEMI NIC
+ *
+ * Issues a hardware reset and waits for the reset to complete.
+ */
+static void natsemi_reset (struct net_device *netdev) 
+{
+	struct natsemi_private *np = netdev->priv;
+	int i;
+        u32 cfg;
+        u32 wcsr;
+        u32 rfcr;
+        u16 pmatch[3];
+        u16 sopass[3];
+
+	natsemi_irq (netdev, 0);
+
+        /*
+         * Resetting the chip causes some registers to be lost.
+         * Natsemi suggests NOT reloading the EEPROM while live, so instead
+         * we save the state that would have been loaded from EEPROM
+         * on a normal power-up (see the spec EEPROM map).
+         */
+
+        /* CFG */
+        cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE;
+
+        /* WCSR */
+        wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE;
+
+        /* RFCR */
+        rfcr = inl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE;
+
+        /* PMATCH */
+        for (i = 0; i < 3; i++) {
+		outl(i*2, np->ioaddr + RxFilterAddr);
+		pmatch[i] = inw(np->ioaddr + RxFilterData);
+        }
+
+        /* SOPAS */
+        for (i = 0; i < 3; i++) {
+	  	outl(0xa+(i*2), np->ioaddr + RxFilterAddr);
+		sopass[i] = inw(np->ioaddr + RxFilterData);
+        }
+
+        /* now whack the chip */
+        outl(ChipReset, np->ioaddr + ChipCmd);
+        for (i=0; i<NATSEMI_HW_TIMEOUT; i++) {
+		if (! (inl (np->ioaddr + ChipCmd) & ChipReset))
+		       break;
+		udelay(5);
+        }
+        if (i == NATSEMI_HW_TIMEOUT) {
+	  	DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5);
+        }
+
+        /* restore CFG */
+        cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE;
+	cfg &= ~(CfgExtPhy | CfgPhyDis);
+        outl (cfg, np->ioaddr + ChipConfig);
+
+        /* restore WCSR */
+        wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE;
+        outl (wcsr, np->ioaddr + WOLCmd);
+
+        /* read RFCR */
+        rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE;
+
+        /* restore PMATCH */
+        for (i = 0; i < 3; i++) {
+	  	outl (i*2, np->ioaddr + RxFilterAddr);
+		outw (pmatch[i], np->ioaddr + RxFilterData);
+        }
+        for (i = 0; i < 3; i++) {
+		outl (0xa+(i*2), np->ioaddr + RxFilterAddr);
+		outw (sopass[i], np->ioaddr + RxFilterData);
+        }
+        /* restore RFCR */
+        outl (rfcr, np->ioaddr + RxFilterAddr);
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int natsemi_open (struct net_device *netdev)
+{
+	struct natsemi_private *np = netdev->priv;
+	uint32_t tx_config, rx_config;
+	int i;
+	
+	/* Disable PME:
+         * The PME bit is initialized from the EEPROM contents.
+         * PCI cards probably have PME disabled, but motherboard
+         * implementations may have PME set to enable WakeOnLan. 
+         * With PME set the chip will scan incoming packets but
+         * nothing will be written to memory. 
+         */
+        outl (inl (np->ioaddr + ClkRun) & ~0x100, np->ioaddr + ClkRun);
+
+	/* Set MAC address in NIC
+	 */
+	for (i = 0 ; i < ETH_ALEN ; i+=2) {
+		outl (i, np->ioaddr + RxFilterAddr);
+		outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8),
+		       np->ioaddr + RxFilterData);
+	}
+
+	/* Setup Tx Ring 
+	 */
+	np->tx_cur = 0;
+	np->tx_dirty = 0;
+	for (i = 0 ; i < TX_RING_SIZE ; i++) {
+		np->tx[i].link   = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]);
+		np->tx[i].cmdsts = 0;
+		np->tx[i].bufptr = 0;
+	}
+	outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
+
+	DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
+	     inl (np->ioaddr + TxRingPtr));
+
+	/* Setup RX ring
+	 */
+	np->rx_cur = 0;
+	for (i = 0 ; i < NUM_RX_DESC ; i++) {
+		np->iobuf[i] = alloc_iob (RX_BUF_SIZE);
+		if (! np->iobuf[i])
+			goto memory_alloc_err;
+		np->rx[i].link   = virt_to_bus ((i + 1 < NUM_RX_DESC) 
+						? &np->rx[i + 1] : &np->rx[0]);
+		np->rx[i].cmdsts = RX_BUF_SIZE;
+		np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data);
+		DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, 
+		      &np->iobuf[i],  &np->iobuf[i]->data);
+	}
+	outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
+
+	DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
+	      inl (np->ioaddr + RxRingPtr));		
+
+	/* Setup RX Filter 
+	 */
+	outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
+	      np->ioaddr + RxFilterAddr);
+
+	/* Initialize other registers. 
+	 * Configure the PCI bus bursts and FIFO thresholds. 
+	 * Configure for standard, in-spec Ethernet. 
+	 */
+	if (inl (np->ioaddr + ChipConfig) & 0x20000000) {	/* Full duplex */
+		DBG ("Full duplex\n");
+		tx_config = 0xD0801002 |  0xC0000000;
+		rx_config = 0x10000020 |  0x10000000;
+	} else {
+		DBG ("Half duplex\n");
+		tx_config = 0x10801002 & ~0xC0000000;
+		rx_config = 0x00000020 & ~0x10000000;
+	}
+	outl (tx_config, np->ioaddr + TxConfig);
+	outl (rx_config, np->ioaddr + RxConfig);
+
+	DBG ("Tx config register = %#08x Rx config register = %#08x\n", 
+               inl (np->ioaddr + TxConfig),
+	       inl (np->ioaddr + RxConfig));
+
+	/*Set the Interrupt Mask register
+	 */
+	outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask);
+	/*start the receiver 
+	 */
+        outl (RxOn, np->ioaddr + ChipCmd);
+	
+	return 0;
+		       
+memory_alloc_err:
+
+	/* Frees any allocated buffers when memory
+	 * for all buffers requested is not available
+	 */
+	i = 0;
+	while (np->rx[i].cmdsts == RX_BUF_SIZE) {
+		free_iob (np->iobuf[i]);
+		i++;
+	}
+	return -ENOMEM;	
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void natsemi_close (struct net_device *netdev) 
+{
+	struct natsemi_private *np = netdev->priv;
+	int i;
+
+	natsemi_reset (netdev);
+
+	for (i = 0; i < NUM_RX_DESC ; i++) {
+		free_iob (np->iobuf[i]);
+	}
+}
+
+/** 
+ * Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf)
+{
+	struct natsemi_private *np = netdev->priv;
+
+	if (np->tx[np->tx_cur].cmdsts != 0) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/* Used by netdev_tx_complete ()
+	 */
+	np->tx_iobuf[np->tx_cur] = iobuf;
+
+	/* Pad and align packet has not been used because its not required 
+	 * by the hardware.
+	 * 	iob_pad (iobuf, ETH_ZLEN); 
+	 * can be used to achieve it, if required
+	 */
+
+	/* Add the packet to TX ring
+	 */
+	np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data);
+	np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN;
+
+	DBG ("TX id %d at %#08lx + %#08zx\n", np->tx_cur,
+	     virt_to_bus (&iobuf->data), iob_len (iobuf));
+
+	/* increment the circular buffer pointer to the next buffer location
+	 */
+	np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE;
+
+	/*start the transmitter 
+	 */
+        outl (TxOn, np->ioaddr + ChipCmd);
+
+	return 0;
+}
+
+/** 
+ * Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void natsemi_poll (struct net_device *netdev)
+{
+	struct natsemi_private *np = netdev->priv;
+	unsigned int tx_status;
+	unsigned int rx_status;
+	unsigned int intr_status;
+	unsigned int rx_len;
+	struct io_buffer *rx_iob;
+	int i;
+	
+	/* read the interrupt register
+	 */
+	intr_status = inl (np->ioaddr + IntrStatus);
+
+	if (!intr_status)
+		goto end;
+
+        DBG ("natsemi_poll: intr_status = %#08x\n", intr_status);
+
+	/* Check status of transmitted packets
+	 */
+	i = np->tx_dirty;
+	while (i != np->tx_cur) {
+	  	tx_status = np->tx[np->tx_dirty].cmdsts;
+
+		DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
+		     np->tx_dirty, np->tx_cur, tx_status);
+		
+		if (tx_status & OWN) 
+			break;
+
+		if (! (tx_status & DescPktOK)) {
+			netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL);
+			DBG ("Error transmitting packet, tx_status: %#08x\n",
+			     tx_status);
+		} else {
+			netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]);
+			DBG ("Success transmitting packet\n");
+		}
+
+		np->tx[np->tx_dirty].cmdsts = 0;
+		np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE;
+		i = (i + 1) % TX_RING_SIZE;
+	}
+	
+	/* Process received packets 
+	 */
+	rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; 
+	while ((rx_status & OWN)) {
+		rx_len = (rx_status & DSIZE) - CRC_SIZE;
+
+                DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
+                     np->rx_cur, rx_status, rx_len);
+                
+		if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) {
+			netdev_rx_err (netdev, NULL, -EINVAL);
+
+			DBG ("natsemi_poll: Corrupted packet received!"
+			     " Status = %#08x\n",
+			      np->rx[np->rx_cur].cmdsts);
+
+		} else 	{
+
+
+			/* If unable allocate space for this packet,
+			 *  try again next poll
+			 */
+			rx_iob = alloc_iob (rx_len);
+			if (! rx_iob) 
+				goto end;
+			memcpy (iob_put (rx_iob, rx_len), 
+				np->iobuf[np->rx_cur]->data, rx_len);
+			/* Add this packet to the receive queue. 
+			 */
+			netdev_rx (netdev, rx_iob);
+		}
+		np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
+		np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
+		rx_status = np->rx[np->rx_cur].cmdsts; 
+	}
+end:
+	/* re-enable the potentially idle receive state machine 
+	 */
+	outl (RxOn, np->ioaddr + ChipCmd);	
+}				
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev    Network device
+ * @v enable    Non-zero for enable, zero for disable
+ */
+static void natsemi_irq (struct net_device *netdev, int enable)
+{
+        struct natsemi_private *np = netdev->priv;
+
+	outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
+	      np->ioaddr + IntrMask); 
+	outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
+}
+
+static struct pci_device_id natsemi_nics[] = {
+	PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
+};
+
+struct pci_driver natsemi_driver __pci_driver = {
+	.ids = natsemi_nics,
+	.id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
+	.probe = natsemi_probe,
+	.remove = natsemi_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.h
new file mode 100644
index 0000000..ae827ba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/natsemi.h
@@ -0,0 +1,232 @@
+FILE_LICENCE ( GPL_ANY );
+
+#define NATSEMI_HW_TIMEOUT 400
+
+#define TX_RING_SIZE 4
+#define NUM_RX_DESC  4
+#define RX_BUF_SIZE 1536
+#define OWN       0x80000000
+#define DSIZE     0x00000FFF
+#define CRC_SIZE  4
+
+struct natsemi_tx {
+	uint32_t link;
+	uint32_t cmdsts;
+	uint32_t bufptr;
+};
+
+struct natsemi_rx {
+	uint32_t link;
+	uint32_t cmdsts;
+	uint32_t bufptr;
+};
+
+struct natsemi_private {
+	unsigned short ioaddr;
+	unsigned short tx_cur;
+	unsigned short tx_dirty;
+	unsigned short rx_cur;
+	struct natsemi_tx tx[TX_RING_SIZE];
+	struct natsemi_rx rx[NUM_RX_DESC];
+
+	/* need to add iobuf as we cannot free iobuf->data in close without this 
+	 * alternatively substracting sizeof(head) and sizeof(list_head) can also 
+	 * give the same.
+	 */
+	struct io_buffer *iobuf[NUM_RX_DESC];
+
+	/* netdev_tx_complete needs pointer to the iobuf of the data so as to free 
+	 * it from the memory.
+	 */
+	struct io_buffer *tx_iobuf[TX_RING_SIZE];
+	struct spi_bit_basher spibit;
+	struct spi_device eeprom;
+	struct nvo_block nvo;
+};
+
+/*
+ * Support for fibre connections on Am79C874:
+ * This phy needs a special setup when connected to a fibre cable.
+ * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf
+ */
+#define PHYID_AM79C874	0x0022561b
+
+enum {
+	MII_MCTRL	= 0x15,		/* mode control register */
+	MII_FX_SEL	= 0x0001,	/* 100BASE-FX (fiber) */
+	MII_EN_SCRM	= 0x0004,	/* enable scrambler (tp) */
+};
+
+
+
+/* values we might find in the silicon revision register */
+#define SRR_DP83815_C	0x0302
+#define SRR_DP83815_D	0x0403
+#define SRR_DP83816_A4	0x0504
+#define SRR_DP83816_A5	0x0505
+
+/* NATSEMI: Offsets to the device registers.
+ * Unlike software-only systems, device drivers interact with complex hardware.
+ * It's not useful to define symbolic names for every register bit in the
+ * device.
+ */
+enum register_offsets {
+    ChipCmd      = 0x00, 
+    ChipConfig   = 0x04, 
+    EECtrl       = 0x08, 
+    PCIBusCfg    = 0x0C,
+    IntrStatus   = 0x10, 
+    IntrMask     = 0x14, 
+    IntrEnable   = 0x18,
+    TxRingPtr    = 0x20, 
+    TxConfig     = 0x24,
+    RxRingPtr    = 0x30,
+    RxConfig     = 0x34, 
+    ClkRun       = 0x3C,
+    WOLCmd       = 0x40, 
+    PauseCmd     = 0x44,
+    RxFilterAddr = 0x48, 
+    RxFilterData = 0x4C,
+    BootRomAddr  = 0x50, 
+    BootRomData  = 0x54, 
+    SiliconRev   = 0x58, 
+    StatsCtrl    = 0x5C,
+    StatsData    = 0x60, 
+    RxPktErrs    = 0x60, 
+    RxMissed     = 0x68, 
+    RxCRCErrs    = 0x64,
+    PCIPM        = 0x44,
+    PhyStatus    = 0xC0, 
+    MIntrCtrl    = 0xC4, 
+    MIntrStatus  = 0xC8,
+
+    /* These are from the spec, around page 78... on a separate table. 
+     */
+    PGSEL        = 0xCC, 
+    PMDCSR       = 0xE4, 
+    TSTDAT       = 0xFC, 
+    DSPCFG       = 0xF4, 
+    SDCFG        = 0x8C,
+    BasicControl = 0x80,	
+    BasicStatus  = 0x84
+	    
+};
+
+/* the values for the 'magic' registers above (PGSEL=1) */
+#define PMDCSR_VAL	0x189c	/* enable preferred adaptation circuitry */
+#define TSTDAT_VAL	0x0
+#define DSPCFG_VAL	0x5040
+#define SDCFG_VAL	0x008c	/* set voltage thresholds for Signal Detect */
+#define DSPCFG_LOCK	0x20	/* coefficient lock bit in DSPCFG */
+#define DSPCFG_COEF	0x1000	/* see coefficient (in TSTDAT) bit in DSPCFG */
+#define TSTDAT_FIXED	0xe8	/* magic number for bad coefficients */
+
+/* Bit in ChipCmd.
+ */
+enum ChipCmdBits {
+    ChipReset = 0x100, 
+    RxReset   = 0x20, 
+    TxReset   = 0x10, 
+    RxOff     = 0x08, 
+    RxOn      = 0x04,
+    TxOff     = 0x02, 
+    TxOn      = 0x01
+};
+
+enum ChipConfig_bits {
+	CfgPhyDis		= 0x200,
+	CfgPhyRst		= 0x400,
+	CfgExtPhy		= 0x1000,
+	CfgAnegEnable		= 0x2000,
+	CfgAneg100		= 0x4000,
+	CfgAnegFull		= 0x8000,
+	CfgAnegDone		= 0x8000000,
+	CfgFullDuplex		= 0x20000000,
+	CfgSpeed100		= 0x40000000,
+	CfgLink			= 0x80000000,
+};
+
+
+/* Bits in the RxMode register.
+ */
+enum rx_mode_bits {
+    AcceptErr          = 0x20,
+    AcceptRunt         = 0x10,
+    AcceptBroadcast    = 0xC0000000,
+    AcceptMulticast    = 0x00200000, 
+    AcceptAllMulticast = 0x20000000,
+    AcceptAllPhys      = 0x10000000, 
+    AcceptMyPhys       = 0x08000000,
+    RxFilterEnable     = 0x80000000
+};
+
+/* Bits in network_desc.status
+ */
+enum desc_status_bits {
+    DescOwn   = 0x80000000, 
+    DescMore  = 0x40000000, 
+    DescIntr  = 0x20000000,
+    DescNoCRC = 0x10000000,
+    DescPktOK = 0x08000000, 
+    RxTooLong = 0x00400000
+};
+
+/*Bits in Interrupt Mask register
+ */
+enum Intr_mask_register_bits {
+    RxOk       = 0x001,
+    RxErr      = 0x004,
+    TxOk       = 0x040,
+    TxErr      = 0x100 
+};	
+
+enum MIntrCtrl_bits {
+  MICRIntEn               = 0x2,
+};
+
+/* CFG bits [13:16] [18:23] */
+#define CFG_RESET_SAVE 0xfde000
+/* WCSR bits [0:4] [9:10] */
+#define WCSR_RESET_SAVE 0x61f
+/* RFCR bits [20] [22] [27:31] */
+#define RFCR_RESET_SAVE 0xf8500000;
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
+   a delay. */
+#define eeprom_delay(ee_addr)   inl(ee_addr)
+
+enum EEPROM_Ctrl_Bits {
+	EE_ShiftClk   = 0x04,
+	EE_DataIn     = 0x01,
+	EE_ChipSelect = 0x08,
+	EE_DataOut    = 0x02
+};
+
+#define EE_Write0 (EE_ChipSelect)
+#define EE_Write1 (EE_ChipSelect | EE_DataIn)
+
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+  EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
+};
+
+/*  EEPROM access , values are devices specific
+ */
+#define EE_CS		0x08	/* EEPROM chip select */
+#define EE_SK		0x04	/* EEPROM shift clock */
+#define EE_DI		0x01	/* Data in */
+#define EE_DO		0x02	/* Data out */
+
+/* Offsets within EEPROM (these are word offsets)
+ */
+#define EE_MAC 7
+#define EE_REG  EECtrl
+
+static const uint8_t natsemi_ee_bits[] = {
+	[SPI_BIT_SCLK]	= EE_SK,
+	[SPI_BIT_MOSI]	= EE_DI,
+	[SPI_BIT_MISO]	= EE_DO,
+	[SPI_BIT_SS(0)]	= EE_CS,
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ne.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ne.c
new file mode 100644
index 0000000..50347de
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ne.c
@@ -0,0 +1,6 @@
+/* ISA I/O mapped NS8390-based cards, including NE2000 */
+#if 0 /* Currently broken! */
+#define INCLUDE_NE 1
+#define NE_SCAN 0x300,0x280,0x320,0x340,0x380
+#include "ns8390.c"
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ne2k_isa.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ne2k_isa.c
new file mode 100644
index 0000000..a923fd3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ne2k_isa.c
@@ -0,0 +1,375 @@
+/**************************************************************************
+ ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+ Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+ Multicast support added by Timothy Legge (timlegge at users.sourceforge.net) 09/28/2003
+ Relocation support added by Ken Yap (ken_yap at users.sourceforge.net) 28/12/02
+ Card Detect support adapted from the eCos driver (Christian Plessl <cplessl at ee.ethz.ch>)
+ Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss at gmail.com>
+ **************************************************************************/
+
+FILE_LICENCE ( BSD2 );
+
+#include "ns8390.h"
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/ethernet.h>
+#include <ipxe/isa.h>
+#include <errno.h>
+
+#define ASIC_PIO NE_DATA
+
+static unsigned char eth_vendor, eth_flags;
+static unsigned short eth_nic_base, eth_asic_base;
+static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
+static Address eth_bmem, eth_rmem;
+static unsigned char eth_drain_receiver;
+
+static struct nic_operations ne_operations;
+static void ne_reset(struct nic *nic, struct isa_device *isa);
+
+static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
+
+/**************************************************************************
+ ETH_PIO_READ - Read a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
+	outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+	outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+	outb(src, eth_nic_base + D8390_P0_RSAR0);
+	outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
+	outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	if (eth_flags & FLAG_16BIT)
+		cnt = (cnt + 1) >> 1;
+
+	while (cnt--) {
+		if (eth_flags & FLAG_16BIT) {
+			*((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
+			dst += 2;
+		} else
+			*(dst++) = inb(eth_asic_base + ASIC_PIO);
+	}
+}
+
+/**************************************************************************
+ ETH_PIO_WRITE - Write a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_write(const unsigned char *src, unsigned int dst,
+		unsigned int cnt) {
+	outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+	outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+	outb(dst, eth_nic_base + D8390_P0_RSAR0);
+	outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
+	outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	if (eth_flags & FLAG_16BIT)
+		cnt = (cnt + 1) >> 1;
+
+	while (cnt--) {
+
+		if (eth_flags & FLAG_16BIT) {
+			outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
+			src += 2;
+		} else
+			outb(*(src++), eth_asic_base + ASIC_PIO);
+	}
+}
+
+/**************************************************************************
+ enable_multicast - Enable Multicast
+ **************************************************************************/
+static void enable_multicast(unsigned short eth_nic_base) {
+	unsigned char mcfilter[8];
+	int i;
+
+	memset(mcfilter, 0xFF, 8);
+	outb(4, eth_nic_base + D8390_P0_RCR);
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
+	for (i = 0; i < 8; i++) {
+		outb(mcfilter[i], eth_nic_base + 8 + i);
+		if (inb(eth_nic_base + 8 + i) != mcfilter[i])
+			DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
+					i);
+	}
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
+	outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
+}
+
+/**************************************************************************
+ NE_PROBE1 - Look for an adapter on the ISA bus
+ **************************************************************************/
+static int ne_probe1(isa_probe_addr_t ioaddr) {
+	//From the eCos driver
+	unsigned int regd;
+	unsigned int state;
+
+	state = inb(ioaddr);
+	outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
+	regd = inb(ioaddr + D8390_P0_TCR);
+
+	if (inb(ioaddr + D8390_P0_TCR)) {
+		outb(ioaddr, state);
+		outb(ioaddr + 0x0d, regd);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**************************************************************************
+ NE_PROBE - Initialize an adapter ???
+ **************************************************************************/
+static int ne_probe(struct nic *nic, struct isa_device *isa) {
+	int i;
+	unsigned char c;
+	unsigned char romdata[16];
+	unsigned char testbuf[32];
+
+	eth_vendor = VENDOR_NONE;
+	eth_drain_receiver = 0;
+
+	nic->irqno = 0;
+	nic->ioaddr = isa->ioaddr;
+	eth_nic_base = isa->ioaddr;
+
+	/******************************************************************
+	 Search for NE1000/2000 if no WD/SMC or 3com cards
+	 ******************************************************************/
+	if (eth_vendor == VENDOR_NONE) {
+
+		static unsigned char test[] = "NE*000 memory";
+
+		eth_bmem = 0; /* No shared memory */
+
+		eth_flags = FLAG_PIO;
+		eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
+		eth_memsize = MEM_16384;
+		eth_tx_start = 32;
+		eth_rx_start = 32 + D8390_TXBUF_SIZE;
+		c = inb(eth_asic_base + NE_RESET);
+		outb(c, eth_asic_base + NE_RESET);
+		(void) inb(0x84);
+		outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
+				+ D8390_P0_COMMAND);
+		outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
+		outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+		outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+		outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+		eth_pio_write((unsigned char *) test, 8192, sizeof(test));
+		eth_pio_read(8192, testbuf, sizeof(test));
+		if (!memcmp(test, testbuf, sizeof(test)))
+			goto out;
+		eth_flags |= FLAG_16BIT;
+		eth_memsize = MEM_32768;
+		eth_tx_start = 64;
+		eth_rx_start = 64 + D8390_TXBUF_SIZE;
+		outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
+				+ D8390_P0_DCR);
+		outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
+		outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
+		eth_pio_write((unsigned char *) test, 16384, sizeof(test));
+		eth_pio_read(16384, testbuf, sizeof(test));
+		if (!memcmp(testbuf, test, sizeof(test)))
+			goto out;
+
+
+out:
+		if (eth_nic_base == 0)
+			return (0);
+		if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
+			eth_flags |= FLAG_16BIT;
+		eth_vendor = VENDOR_NOVELL;
+		eth_pio_read(0, romdata, sizeof(romdata));
+		for (i = 0; i < ETH_ALEN; i++) {
+			nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
+		}
+		nic->ioaddr = eth_nic_base;
+		DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
+				(eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
+						nic->node_addr));
+	}
+
+	if (eth_vendor == VENDOR_NONE)
+		return (0);
+
+	if (eth_vendor != VENDOR_3COM)
+		eth_rmem = eth_bmem;
+
+	ne_reset(nic, isa);
+	nic->nic_op = &ne_operations;
+	return 1;
+}
+
+
+/**************************************************************************
+ NE_DISABLE - Turn off adapter
+ **************************************************************************/
+static void ne_disable(struct nic *nic, struct isa_device *isa) {
+	ne_reset(nic, isa);
+}
+
+
+/**************************************************************************
+ NE_RESET - Reset adapter
+ **************************************************************************/
+static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
+{
+	int i;
+
+	eth_drain_receiver = 0;
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	if (eth_flags & FLAG_16BIT)
+	outb(0x49, eth_nic_base+D8390_P0_DCR);
+	else
+	outb(0x48, eth_nic_base+D8390_P0_DCR);
+	outb(0, eth_nic_base+D8390_P0_RBCR0);
+	outb(0, eth_nic_base+D8390_P0_RBCR1);
+	outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
+	outb(2, eth_nic_base+D8390_P0_TCR);
+	outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+	outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
+
+	outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
+	outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
+	outb(0xFF, eth_nic_base+D8390_P0_ISR);
+	outb(0, eth_nic_base+D8390_P0_IMR);
+	outb(D8390_COMMAND_PS1 |
+			D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+
+	for (i=0; i<ETH_ALEN; i++)
+	outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
+	for (i=0; i<ETH_ALEN; i++)
+	outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
+	outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
+	outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	outb(0xFF, eth_nic_base+D8390_P0_ISR);
+	outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
+	outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
+
+	enable_multicast(eth_nic_base);
+}
+
+
+/**************************************************************************
+ NE_POLL - Wait for a frame
+ **************************************************************************/
+static int ne_poll(struct nic *nic __unused, int retrieve __unused)
+{
+	int ret = 0;
+	unsigned char rstat, curr, next;
+	unsigned short len, frag;
+	unsigned short pktoff;
+	unsigned char *p;
+	struct ringbuffer pkthdr;
+
+	rstat = inb(eth_nic_base+D8390_P0_RSR);
+	if (!(rstat & D8390_RSTAT_PRX)) return(0);
+	next = inb(eth_nic_base+D8390_P0_BOUND)+1;
+	if (next >= eth_memsize) next = eth_rx_start;
+	outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
+	curr = inb(eth_nic_base+D8390_P1_CURR);
+	outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
+	if (curr >= eth_memsize) curr=eth_rx_start;
+	if (curr == next) return(0);
+
+	if ( ! retrieve ) return 1;
+
+	pktoff = next << 8;
+	if (eth_flags & FLAG_PIO)
+	eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
+	else
+	memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
+	pktoff += sizeof(pkthdr);
+	/* incoming length includes FCS so must sub 4 */
+	len = pkthdr.len - 4;
+	if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
+			|| len> ETH_FRAME_LEN) {
+		DBG("Bogus packet, ignoring\n");
+		return (0);
+	}
+	else {
+		p = nic->packet;
+		nic->packetlen = len; /* available to caller */
+		frag = (eth_memsize << 8) - pktoff;
+		if (len> frag) { /* We have a wrap-around */
+			/* read first part */
+			if (eth_flags & FLAG_PIO)
+			eth_pio_read(pktoff, p, frag);
+			else
+			memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
+			pktoff = eth_rx_start << 8;
+			p += frag;
+			len -= frag;
+		}
+		/* read second part */
+		if (eth_flags & FLAG_PIO)
+		eth_pio_read(pktoff, p, len);
+		else
+		memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
+		ret = 1;
+	}
+	next = pkthdr.next; /* frame number of next packet */
+	if (next == eth_rx_start)
+	next = eth_memsize;
+	outb(next-1, eth_nic_base+D8390_P0_BOUND);
+	return(ret);
+}
+
+
+/**************************************************************************
+ NE_TRANSMIT - Transmit a frame
+ **************************************************************************/
+static void ne_transmit(struct nic *nic, const char *d, /* Destination */
+unsigned int t, /* Type */
+unsigned int s, /* size */
+const char *p) { /* Packet */
+
+	/* Programmed I/O */
+	unsigned short type;
+	type = (t >> 8) | (t << 8);
+	eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
+	eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
+	/* bcc generates worse code without (const+const) below */
+	eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
+			+ ETH_ALEN), 2);
+	eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
+	s += ETH_HLEN;
+	if (s < ETH_ZLEN)
+		s = ETH_ZLEN;
+
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
+			eth_nic_base + D8390_P0_COMMAND);
+	outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
+	outb(s, eth_nic_base + D8390_P0_TBCR0);
+	outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
+
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
+			| D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+}
+
+static struct nic_operations ne_operations = { .connect = dummy_connect,
+		.poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
+};
+
+ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
+		GENERIC_ISAPNP_VENDOR, 0x0600 );
+
+DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
+		ne_probe, ne_disable );
+
+ISA_ROM("ne","NE1000/2000 and clones");
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ns83820.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns83820.c
new file mode 100644
index 0000000..0b92a91
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns83820.c
@@ -0,0 +1,1007 @@
+/**************************************************************************
+*    ns83820.c: Etherboot device driver for the National Semiconductor 83820
+*    Written 2004 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*	ns83820.c by Benjamin LaHaise with contributions
+* 		for Linux kernel 2.4.x.
+*	
+*    Linux Driver Version 0.20, 20020610
+* 
+*    This development of this Etherboot driver was funded by:
+*
+*    NXTV: http://www.nxtv.com/
+*    	
+*    REVISION HISTORY:
+*    ================
+*
+*    v1.0	02-16-2004	timlegge	Initial port of Linux driver
+*    v1.1	02-19-2004	timlegge	More rohbust transmit and poll
+*    
+*    Indent Options: indent -kr -i8
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include <ipxe/pci.h>
+
+#if ARCH == ia64		/* Support 64-bit addressing */
+#define USE_64BIT_ADDR
+#endif
+
+#define HZ 100
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+/* NIC specific static variables go here */
+
+/* Global parameters.  See MODULE_PARM near the bottom. */
+// static int ihr = 2;
+static int reset_phy = 0;
+static int lnksts = 0;		/* CFG_LNKSTS bit polarity */
+
+#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
+#define USE_64BIT_ADDR	"+"
+#endif
+
+#if defined(USE_64BIT_ADDR)
+#define TRY_DAC	1
+#else
+#define TRY_DAC	0
+#endif
+
+/* tunables */
+#define RX_BUF_SIZE	1500	/* 8192 */
+
+/* Must not exceed ~65000. */
+#define NR_RX_DESC	64
+#define NR_TX_DESC	1
+
+		   /* not tunable *//* Extra 6 bytes for 64 bit alignment (divisable by 8) */
+#define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14 + 6)	/* rx/tx mac addr + type */
+
+#define MIN_TX_DESC_FREE	8
+
+/* register defines */
+#define CFGCS		0x04
+
+#define CR_TXE		0x00000001
+#define CR_TXD		0x00000002
+/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE
+ * The Receive engine skips one descriptor and moves
+ * onto the next one!! */
+#define CR_RXE		0x00000004
+#define CR_RXD		0x00000008
+#define CR_TXR		0x00000010
+#define CR_RXR		0x00000020
+#define CR_SWI		0x00000080
+#define CR_RST		0x00000100
+
+#define PTSCR_EEBIST_FAIL       0x00000001
+#define PTSCR_EEBIST_EN         0x00000002
+#define PTSCR_EELOAD_EN         0x00000004
+#define PTSCR_RBIST_FAIL        0x000001b8
+#define PTSCR_RBIST_DONE        0x00000200
+#define PTSCR_RBIST_EN          0x00000400
+#define PTSCR_RBIST_RST         0x00002000
+
+#define MEAR_EEDI		0x00000001
+#define MEAR_EEDO		0x00000002
+#define MEAR_EECLK		0x00000004
+#define MEAR_EESEL		0x00000008
+#define MEAR_MDIO		0x00000010
+#define MEAR_MDDIR		0x00000020
+#define MEAR_MDC		0x00000040
+
+#define ISR_TXDESC3	0x40000000
+#define ISR_TXDESC2	0x20000000
+#define ISR_TXDESC1	0x10000000
+#define ISR_TXDESC0	0x08000000
+#define ISR_RXDESC3	0x04000000
+#define ISR_RXDESC2	0x02000000
+#define ISR_RXDESC1	0x01000000
+#define ISR_RXDESC0	0x00800000
+#define ISR_TXRCMP	0x00400000
+#define ISR_RXRCMP	0x00200000
+#define ISR_DPERR	0x00100000
+#define ISR_SSERR	0x00080000
+#define ISR_RMABT	0x00040000
+#define ISR_RTABT	0x00020000
+#define ISR_RXSOVR	0x00010000
+#define ISR_HIBINT	0x00008000
+#define ISR_PHY		0x00004000
+#define ISR_PME		0x00002000
+#define ISR_SWI		0x00001000
+#define ISR_MIB		0x00000800
+#define ISR_TXURN	0x00000400
+#define ISR_TXIDLE	0x00000200
+#define ISR_TXERR	0x00000100
+#define ISR_TXDESC	0x00000080
+#define ISR_TXOK	0x00000040
+#define ISR_RXORN	0x00000020
+#define ISR_RXIDLE	0x00000010
+#define ISR_RXEARLY	0x00000008
+#define ISR_RXERR	0x00000004
+#define ISR_RXDESC	0x00000002
+#define ISR_RXOK	0x00000001
+
+#define TXCFG_CSI	0x80000000
+#define TXCFG_HBI	0x40000000
+#define TXCFG_MLB	0x20000000
+#define TXCFG_ATP	0x10000000
+#define TXCFG_ECRETRY	0x00800000
+#define TXCFG_BRST_DIS	0x00080000
+#define TXCFG_MXDMA1024	0x00000000
+#define TXCFG_MXDMA512	0x00700000
+#define TXCFG_MXDMA256	0x00600000
+#define TXCFG_MXDMA128	0x00500000
+#define TXCFG_MXDMA64	0x00400000
+#define TXCFG_MXDMA32	0x00300000
+#define TXCFG_MXDMA16	0x00200000
+#define TXCFG_MXDMA8	0x00100000
+
+#define CFG_LNKSTS	0x80000000
+#define CFG_SPDSTS	0x60000000
+#define CFG_SPDSTS1	0x40000000
+#define CFG_SPDSTS0	0x20000000
+#define CFG_DUPSTS	0x10000000
+#define CFG_TBI_EN	0x01000000
+#define CFG_MODE_1000	0x00400000
+/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy.
+ * Read the Phy response and then configure the MAC accordingly */
+#define CFG_AUTO_1000	0x00200000
+#define CFG_PINT_CTL	0x001c0000
+#define CFG_PINT_DUPSTS	0x00100000
+#define CFG_PINT_LNKSTS	0x00080000
+#define CFG_PINT_SPDSTS	0x00040000
+#define CFG_TMRTEST	0x00020000
+#define CFG_MRM_DIS	0x00010000
+#define CFG_MWI_DIS	0x00008000
+#define CFG_T64ADDR	0x00004000
+#define CFG_PCI64_DET	0x00002000
+#define CFG_DATA64_EN	0x00001000
+#define CFG_M64ADDR	0x00000800
+#define CFG_PHY_RST	0x00000400
+#define CFG_PHY_DIS	0x00000200
+#define CFG_EXTSTS_EN	0x00000100
+#define CFG_REQALG	0x00000080
+#define CFG_SB		0x00000040
+#define CFG_POW		0x00000020
+#define CFG_EXD		0x00000010
+#define CFG_PESEL	0x00000008
+#define CFG_BROM_DIS	0x00000004
+#define CFG_EXT_125	0x00000002
+#define CFG_BEM		0x00000001
+
+#define EXTSTS_UDPPKT	0x00200000
+#define EXTSTS_TCPPKT	0x00080000
+#define EXTSTS_IPPKT	0x00020000
+
+#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
+
+#define MIBC_MIBS	0x00000008
+#define MIBC_ACLR	0x00000004
+#define MIBC_FRZ	0x00000002
+#define MIBC_WRN	0x00000001
+
+#define PCR_PSEN	(1 << 31)
+#define PCR_PS_MCAST	(1 << 30)
+#define PCR_PS_DA	(1 << 29)
+#define PCR_STHI_8	(3 << 23)
+#define PCR_STLO_4	(1 << 23)
+#define PCR_FFHI_8K	(3 << 21)
+#define PCR_FFLO_4K	(1 << 21)
+#define PCR_PAUSE_CNT	0xFFFE
+
+#define RXCFG_AEP	0x80000000
+#define RXCFG_ARP	0x40000000
+#define RXCFG_STRIPCRC	0x20000000
+#define RXCFG_RX_FD	0x10000000
+#define RXCFG_ALP	0x08000000
+#define RXCFG_AIRL	0x04000000
+#define RXCFG_MXDMA512	0x00700000
+#define RXCFG_DRTH	0x0000003e
+#define RXCFG_DRTH0	0x00000002
+
+#define RFCR_RFEN	0x80000000
+#define RFCR_AAB	0x40000000
+#define RFCR_AAM	0x20000000
+#define RFCR_AAU	0x10000000
+#define RFCR_APM	0x08000000
+#define RFCR_APAT	0x07800000
+#define RFCR_APAT3	0x04000000
+#define RFCR_APAT2	0x02000000
+#define RFCR_APAT1	0x01000000
+#define RFCR_APAT0	0x00800000
+#define RFCR_AARP	0x00400000
+#define RFCR_MHEN	0x00200000
+#define RFCR_UHEN	0x00100000
+#define RFCR_ULM	0x00080000
+
+#define VRCR_RUDPE	0x00000080
+#define VRCR_RTCPE	0x00000040
+#define VRCR_RIPE	0x00000020
+#define VRCR_IPEN	0x00000010
+#define VRCR_DUTF	0x00000008
+#define VRCR_DVTF	0x00000004
+#define VRCR_VTREN	0x00000002
+#define VRCR_VTDEN	0x00000001
+
+#define VTCR_PPCHK	0x00000008
+#define VTCR_GCHK	0x00000004
+#define VTCR_VPPTI	0x00000002
+#define VTCR_VGTI	0x00000001
+
+#define CR		0x00
+#define CFG		0x04
+#define MEAR		0x08
+#define PTSCR		0x0c
+#define	ISR		0x10
+#define	IMR		0x14
+#define	IER		0x18
+#define	IHR		0x1c
+#define TXDP		0x20
+#define TXDP_HI		0x24
+#define TXCFG		0x28
+#define GPIOR		0x2c
+#define RXDP		0x30
+#define RXDP_HI		0x34
+#define RXCFG		0x38
+#define PQCR		0x3c
+#define WCSR		0x40
+#define PCR		0x44
+#define RFCR		0x48
+#define RFDR		0x4c
+
+#define SRR		0x58
+
+#define VRCR		0xbc
+#define VTCR		0xc0
+#define VDR		0xc4
+#define CCSR		0xcc
+
+#define TBICR		0xe0
+#define TBISR		0xe4
+#define TANAR		0xe8
+#define TANLPAR		0xec
+#define TANER		0xf0
+#define TESR		0xf4
+
+#define TBICR_MR_AN_ENABLE	0x00001000
+#define TBICR_MR_RESTART_AN	0x00000200
+
+#define TBISR_MR_LINK_STATUS	0x00000020
+#define TBISR_MR_AN_COMPLETE	0x00000004
+
+#define TANAR_PS2 		0x00000100
+#define TANAR_PS1 		0x00000080
+#define TANAR_HALF_DUP 		0x00000040
+#define TANAR_FULL_DUP 		0x00000020
+
+#define GPIOR_GP5_OE		0x00000200
+#define GPIOR_GP4_OE		0x00000100
+#define GPIOR_GP3_OE		0x00000080
+#define GPIOR_GP2_OE		0x00000040
+#define GPIOR_GP1_OE		0x00000020
+#define GPIOR_GP3_OUT		0x00000004
+#define GPIOR_GP1_OUT		0x00000001
+
+#define LINK_AUTONEGOTIATE	0x01
+#define LINK_DOWN		0x02
+#define LINK_UP			0x04
+
+
+#define __kick_rx()	writel(CR_RXE, ns->base + CR)
+
+#define kick_rx() do { \
+	DBG("kick_rx: maybe kicking\n"); \
+		writel(virt_to_le32desc(&rx_ring[ns->cur_rx]), ns->base + RXDP); \
+		if (ns->next_rx == ns->next_empty) \
+			printf("uh-oh: next_rx == next_empty???\n"); \
+		__kick_rx(); \
+} while(0)
+
+
+#ifdef USE_64BIT_ADDR
+#define HW_ADDR_LEN	8
+#else
+#define HW_ADDR_LEN	4
+#endif
+
+#define CMDSTS_OWN	0x80000000
+#define CMDSTS_MORE	0x40000000
+#define CMDSTS_INTR	0x20000000
+#define CMDSTS_ERR	0x10000000
+#define CMDSTS_OK	0x08000000
+#define CMDSTS_LEN_MASK	0x0000ffff
+
+#define CMDSTS_DEST_MASK	0x01800000
+#define CMDSTS_DEST_SELF	0x00800000
+#define CMDSTS_DEST_MULTI	0x01000000
+
+#define DESC_SIZE	8	/* Should be cache line sized */
+
+#ifdef USE_64BIT_ADDR
+struct ring_desc {
+	uint64_t link;
+	uint64_t bufptr;
+	u32 cmdsts;
+	u32 extsts;		/* Extended status field */
+};
+#else
+struct ring_desc {
+	u32 link;
+	u32 bufptr;
+	u32 cmdsts;
+	u32 extsts;		/* Extended status field */
+};
+#endif
+
+/* Private Storage for the NIC */
+static struct ns83820_private {
+	u8 *base;
+	int up;
+	long idle;
+	u32 *next_rx_desc;
+	u16 next_rx, next_empty;
+	u32 cur_rx;
+	u32 *descs;
+	unsigned ihr;
+	u32 CFG_cache;
+	u32 MEAR_cache;
+	u32 IMR_cache;
+	int linkstate;
+	u16 tx_done_idx;
+	u16 tx_idx;
+	u16 tx_intr_idx;
+	u32 phy_descs;
+	u32 *tx_descs;
+
+} nsx;
+static struct ns83820_private *ns;
+
+/* Define the TX and RX Descriptor and Buffers */
+struct {
+	struct ring_desc tx_ring[NR_TX_DESC] __attribute__ ((aligned(8)));
+	unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE];
+	struct ring_desc rx_ring[NR_RX_DESC] __attribute__ ((aligned(8)));
+	unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE]
+	__attribute__ ((aligned(8)));
+} ns83820_bufs __shared;
+#define tx_ring ns83820_bufs.tx_ring
+#define rx_ring ns83820_bufs.rx_ring
+#define txb ns83820_bufs.txb
+#define rxb ns83820_bufs.rxb
+
+static void phy_intr(struct nic *nic __unused)
+{
+	static char *speeds[] =
+	    { "10", "100", "1000", "1000(?)", "1000F" };
+	u32 cfg, new_cfg;
+	u32 tbisr, tanar, tanlpar;
+	int speed, fullduplex, newlinkstate;
+
+	cfg = readl(ns->base + CFG) ^ SPDSTS_POLARITY;
+	if (ns->CFG_cache & CFG_TBI_EN) {
+		/* we have an optical transceiver */
+		tbisr = readl(ns->base + TBISR);
+		tanar = readl(ns->base + TANAR);
+		tanlpar = readl(ns->base + TANLPAR);
+		DBG("phy_intr: tbisr=%hX, tanar=%hX, tanlpar=%hX\n",
+		    tbisr, tanar, tanlpar);
+
+		if ((fullduplex = (tanlpar & TANAR_FULL_DUP)
+		     && (tanar & TANAR_FULL_DUP))) {
+
+			/* both of us are full duplex */
+			writel(readl(ns->base + TXCFG)
+			       | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+			       ns->base + TXCFG);
+			writel(readl(ns->base + RXCFG) | RXCFG_RX_FD,
+			       ns->base + RXCFG);
+			/* Light up full duplex LED */
+			writel(readl(ns->base + GPIOR) | GPIOR_GP1_OUT,
+			       ns->base + GPIOR);
+
+		} else if (((tanlpar & TANAR_HALF_DUP)
+			    && (tanar & TANAR_HALF_DUP))
+			   || ((tanlpar & TANAR_FULL_DUP)
+			       && (tanar & TANAR_HALF_DUP))
+			   || ((tanlpar & TANAR_HALF_DUP)
+			       && (tanar & TANAR_FULL_DUP))) {
+
+			/* one or both of us are half duplex */
+			writel((readl(ns->base + TXCFG)
+				& ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
+			       ns->base + TXCFG);
+			writel(readl(ns->base + RXCFG) & ~RXCFG_RX_FD,
+			       ns->base + RXCFG);
+			/* Turn off full duplex LED */
+			writel(readl(ns->base + GPIOR) & ~GPIOR_GP1_OUT,
+			       ns->base + GPIOR);
+		}
+
+		speed = 4;	/* 1000F */
+
+	} else {
+		/* we have a copper transceiver */
+		new_cfg =
+		    ns->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
+
+		if (cfg & CFG_SPDSTS1)
+			new_cfg |= CFG_MODE_1000;
+		else
+			new_cfg &= ~CFG_MODE_1000;
+
+		speed = ((cfg / CFG_SPDSTS0) & 3);
+		fullduplex = (cfg & CFG_DUPSTS);
+
+		if (fullduplex)
+			new_cfg |= CFG_SB;
+
+		if ((cfg & CFG_LNKSTS) &&
+		    ((new_cfg ^ ns->CFG_cache) & CFG_MODE_1000)) {
+			writel(new_cfg, ns->base + CFG);
+			ns->CFG_cache = new_cfg;
+		}
+
+		ns->CFG_cache &= ~CFG_SPDSTS;
+		ns->CFG_cache |= cfg & CFG_SPDSTS;
+	}
+
+	newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN;
+
+	if (newlinkstate & LINK_UP && ns->linkstate != newlinkstate) {
+		printf("link now %s mbps, %s duplex and up.\n",
+		       speeds[speed], fullduplex ? "full" : "half");
+	} else if (newlinkstate & LINK_DOWN
+		   && ns->linkstate != newlinkstate) {
+		printf("link now down.\n");
+	}
+	ns->linkstate = newlinkstate;
+}
+static void ns83820_set_multicast(struct nic *nic __unused);
+static void ns83820_setup_rx(struct nic *nic)
+{
+	unsigned i;
+	ns->idle = 1;
+	ns->next_rx = 0;
+	ns->next_rx_desc = ns->descs;
+	ns->next_empty = 0;
+	ns->cur_rx = 0;
+
+
+	for (i = 0; i < NR_RX_DESC; i++) {
+		rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]);
+		rx_ring[i].bufptr =
+		    virt_to_le32desc(&rxb[i * REAL_RX_BUF_SIZE]);
+		rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE);
+		rx_ring[i].extsts = cpu_to_le32(0);
+	}
+//      No need to wrap the ring 
+//      rx_ring[i].link = virt_to_le32desc(&rx_ring[0]);
+	writel(0, ns->base + RXDP_HI);
+	writel(virt_to_le32desc(&rx_ring[0]), ns->base + RXDP);
+
+	DBG("starting receiver\n");
+
+	writel(0x0001, ns->base + CCSR);
+	writel(0, ns->base + RFCR);
+	writel(0x7fc00000, ns->base + RFCR);
+	writel(0xffc00000, ns->base + RFCR);
+
+	ns->up = 1;
+
+	phy_intr(nic);
+
+	/* Okay, let it rip */
+	ns->IMR_cache |= ISR_PHY;
+	ns->IMR_cache |= ISR_RXRCMP;
+	//dev->IMR_cache |= ISR_RXERR;
+	//dev->IMR_cache |= ISR_RXOK;
+	ns->IMR_cache |= ISR_RXORN;
+	ns->IMR_cache |= ISR_RXSOVR;
+	ns->IMR_cache |= ISR_RXDESC;
+	ns->IMR_cache |= ISR_RXIDLE;
+	ns->IMR_cache |= ISR_TXDESC;
+	ns->IMR_cache |= ISR_TXIDLE;
+
+	// No reason to enable interupts...
+	// writel(ns->IMR_cache, ns->base + IMR);
+	// writel(1, ns->base + IER);
+	ns83820_set_multicast(nic);
+	kick_rx();
+}
+
+
+static void ns83820_do_reset(struct nic *nic __unused, u32 which)
+{
+	DBG("resetting chip...\n");
+	writel(which, ns->base + CR);
+	do {
+
+	} while (readl(ns->base + CR) & which);
+	DBG("okay!\n");
+}
+
+static void ns83820_reset(struct nic *nic)
+{
+	unsigned i;
+	DBG("ns83820_reset\n");
+
+	writel(0, ns->base + PQCR);
+
+	ns83820_setup_rx(nic);
+
+	for (i = 0; i < NR_TX_DESC; i++) {
+		tx_ring[i].link = 0;
+		tx_ring[i].bufptr = 0;
+		tx_ring[i].cmdsts = cpu_to_le32(0);
+		tx_ring[i].extsts = cpu_to_le32(0);
+	}
+
+	ns->tx_idx = 0;
+	ns->tx_done_idx = 0;
+	writel(0, ns->base + TXDP_HI);
+	return;
+}
+static void ns83820_getmac(struct nic *nic __unused, u8 * mac)
+{
+	unsigned i;
+	for (i = 0; i < 3; i++) {
+		u32 data;
+		/* Read from the perfect match memory: this is loaded by
+		 * the chip from the EEPROM via the EELOAD self test.
+		 */
+		writel(i * 2, ns->base + RFCR);
+		data = readl(ns->base + RFDR);
+		*mac++ = data;
+		*mac++ = data >> 8;
+	}
+}
+
+static void ns83820_set_multicast(struct nic *nic __unused)
+{
+	u8 *rfcr = ns->base + RFCR;
+	u32 and_mask = 0xffffffff;
+	u32 or_mask = 0;
+	u32 val;
+
+	/* Support Multicast */
+	and_mask &= ~(RFCR_AAU | RFCR_AAM);
+	or_mask |= RFCR_AAM;
+	val = (readl(rfcr) & and_mask) | or_mask;
+	/* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */
+	writel(val & ~RFCR_RFEN, rfcr);
+	writel(val, rfcr);
+
+}
+static void ns83820_run_bist(struct nic *nic __unused, const char *name,
+			     u32 enable, u32 done, u32 fail)
+{
+	int timed_out = 0;
+	long start;
+	u32 status;
+	int loops = 0;
+
+	DBG("start %s\n", name);
+
+	    start = currticks();
+
+	writel(enable, ns->base + PTSCR);
+	for (;;) {
+		loops++;
+		status = readl(ns->base + PTSCR);
+		if (!(status & enable))
+			break;
+		if (status & done)
+			break;
+		if (status & fail)
+			break;
+		if ((currticks() - start) >= HZ) {
+			timed_out = 1;
+			break;
+		}
+	}
+
+	if (status & fail)
+	  printf("%s failed! (0x%hX & 0x%hX)\n", name, (unsigned int) status, 
+		 (unsigned int) fail);
+	else if (timed_out)
+		printf("run_bist %s timed out! (%hX)\n", name, (unsigned int) status);
+	DBG("done %s in %d loops\n", name, loops);
+}
+
+/*************************************
+Check Link
+*************************************/
+static void ns83820_check_intr(struct nic *nic) {
+	int i;
+	u32 isr = readl(ns->base + ISR);
+	if(ISR_PHY & isr)
+		phy_intr(nic);
+	if(( ISR_RXIDLE | ISR_RXDESC | ISR_RXERR) & isr)
+		kick_rx();
+	for (i = 0; i < NR_RX_DESC; i++) {
+		if (rx_ring[i].cmdsts == CMDSTS_OWN) {
+//			rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]);
+			rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE);
+		}
+	}
+}
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int ns83820_poll(struct nic *nic, int retrieve)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+	u32 cmdsts;
+	int entry = ns->cur_rx;
+
+	ns83820_check_intr(nic);
+
+	cmdsts = le32_to_cpu(rx_ring[entry].cmdsts);
+
+	if ( ! ( (CMDSTS_OWN & (cmdsts)) && (cmdsts != (CMDSTS_OWN)) ) )
+	  return 0;
+
+	if ( ! retrieve ) return 1;
+
+	if (! (CMDSTS_OK & cmdsts) )
+	  return 0;
+
+	nic->packetlen = cmdsts & 0xffff;
+	memcpy(nic->packet,
+	       rxb + (entry * REAL_RX_BUF_SIZE),
+	       nic->packetlen);
+	//			rx_ring[entry].link = 0;
+	rx_ring[entry].cmdsts = cpu_to_le32(CMDSTS_OWN);
+
+	ns->cur_rx = (ns->cur_rx + 1) % NR_RX_DESC;
+
+	if (ns->cur_rx == 0)	/* We have wrapped the ring */
+	  kick_rx();
+
+	return 1;
+}
+
+static inline void kick_tx(struct nic *nic __unused)
+{
+	DBG("kick_tx\n");
+	writel(CR_TXE, ns->base + CR);
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void ns83820_transmit(struct nic *nic, const char *d,	/* Destination */
+			     unsigned int t,	/* Type */
+			     unsigned int s,	/* size */
+			     const char *p)
+{				/* Packet */
+	/* send the packet to destination */
+
+	u16 nstype;
+	u32 cmdsts, extsts;
+	int cur_tx = 0;
+	u32 isr = readl(ns->base + ISR);
+	if (ISR_TXIDLE & isr)
+		kick_tx(nic);
+	/* point to the current txb incase multiple tx_rings are used */
+	memcpy(txb, d, ETH_ALEN);
+	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
+	nstype = htons((u16) t);
+	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
+	memcpy(txb + ETH_HLEN, p, s);
+	s += ETH_HLEN;
+	s &= 0x0FFF;
+	while (s < ETH_ZLEN)
+		txb[s++] = '\0';
+
+	/* Setup the transmit descriptor */
+	extsts = 0;
+	extsts |= EXTSTS_UDPPKT;
+
+	tx_ring[cur_tx].bufptr = virt_to_le32desc(&txb);
+	tx_ring[cur_tx].extsts = cpu_to_le32(extsts);
+
+	cmdsts = cpu_to_le32(0);
+	cmdsts |= cpu_to_le32(CMDSTS_OWN | s);
+	tx_ring[cur_tx].cmdsts = cpu_to_le32(cmdsts);
+
+	writel(virt_to_le32desc(&tx_ring[0]), ns->base + TXDP);
+	kick_tx(nic);
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void ns83820_disable ( struct nic *nic ) {
+
+	/* put the card in its initial state */
+	/* This function serves 3 purposes.
+	 * This disables DMA and interrupts so we don't receive
+	 *  unexpected packets or interrupts from the card after
+	 *  etherboot has finished. 
+	 * This frees resources so etherboot may use
+	 *  this driver on another interface
+	 * This allows etherboot to reinitialize the interface
+	 *  if something is something goes wrong.
+	 */
+	/* disable interrupts */
+	writel(0, ns->base + IMR);
+	writel(0, ns->base + IER);
+	readl(ns->base + IER);
+
+	ns->up = 0;
+
+	ns83820_do_reset(nic, CR_RST);
+
+	ns->IMR_cache &=
+	    ~(ISR_RXOK | ISR_RXDESC | ISR_RXERR | ISR_RXEARLY |
+	      ISR_RXIDLE);
+	writel(ns->IMR_cache, ns->base + IMR);
+
+	/* touch the pci bus... */
+	readl(ns->base + IMR);
+
+	/* assumes the transmitter is already disabled and reset */
+	writel(0, ns->base + RXDP_HI);
+	writel(0, ns->base + RXDP);
+}
+
+/**************************************************************************
+IRQ - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void ns83820_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations ns83820_operations = {
+	.connect	= dummy_connect,
+	.poll		= ns83820_poll,
+	.transmit	= ns83820_transmit,
+	.irq		= ns83820_irq,
+
+};
+
+static struct pci_device_id ns83820_nics[] = {
+	PCI_ROM(0x100b, 0x0022, "ns83820", "National Semiconductor 83820", 0),
+};
+
+PCI_DRIVER ( ns83820_driver, ns83820_nics, PCI_NO_CLASS );
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int ns83820_probe ( struct nic *nic, struct pci_device *pci ) {
+
+	long addr;
+	int using_dac = 0;
+
+	if (pci->ioaddr == 0)
+		return 0;
+
+	printf("ns83820.c: Found %s, vendor=0x%hX, device=0x%hX\n",
+	       pci->id->name, pci->vendor, pci->device);
+
+	/* point to private storage */
+	ns = &nsx;
+
+	adjust_pci_device(pci);
+
+	addr = pci_bar_start(pci, PCI_BASE_ADDRESS_1);
+
+	ns->base = ioremap(addr, (1UL << 12));
+
+	if (!ns->base)
+		return 0;
+
+	nic->irqno  = 0;
+	nic->ioaddr = pci->ioaddr & ~3;
+
+	/* disable interrupts */
+	writel(0, ns->base + IMR);
+	writel(0, ns->base + IER);
+	readl(ns->base + IER);
+
+	ns->IMR_cache = 0;
+
+	ns83820_do_reset(nic, CR_RST);
+
+	/* Must reset the ram bist before running it */
+	writel(PTSCR_RBIST_RST, ns->base + PTSCR);
+	ns83820_run_bist(nic, "sram bist", PTSCR_RBIST_EN,
+			 PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL);
+	ns83820_run_bist(nic, "eeprom bist", PTSCR_EEBIST_EN, 0,
+			 PTSCR_EEBIST_FAIL);
+	ns83820_run_bist(nic, "eeprom load", PTSCR_EELOAD_EN, 0, 0);
+
+	/* I love config registers */
+	ns->CFG_cache = readl(ns->base + CFG);
+
+	if ((ns->CFG_cache & CFG_PCI64_DET)) {
+		printf("%s: detected 64 bit PCI data bus.\n", pci->id->name);
+		/*dev->CFG_cache |= CFG_DATA64_EN; */
+		if (!(ns->CFG_cache & CFG_DATA64_EN))
+			printf
+			    ("%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
+			     pci->id->name);
+	} else
+		ns->CFG_cache &= ~(CFG_DATA64_EN);
+
+	ns->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS |
+			  CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
+			  CFG_M64ADDR);
+	ns->CFG_cache |=
+	    CFG_PINT_DUPSTS | CFG_PINT_LNKSTS | CFG_PINT_SPDSTS |
+	    CFG_EXTSTS_EN | CFG_EXD | CFG_PESEL;
+	ns->CFG_cache |= CFG_REQALG;
+	ns->CFG_cache |= CFG_POW;
+	ns->CFG_cache |= CFG_TMRTEST;
+
+	/* When compiled with 64 bit addressing, we must always enable
+	 * the 64 bit descriptor format.
+	 */
+#ifdef USE_64BIT_ADDR
+	ns->CFG_cache |= CFG_M64ADDR;
+#endif
+
+//FIXME: Enable section on dac or remove this
+	if (using_dac)
+		ns->CFG_cache |= CFG_T64ADDR;
+
+	/* Big endian mode does not seem to do what the docs suggest */
+	ns->CFG_cache &= ~CFG_BEM;
+
+	/* setup optical transceiver if we have one */
+	if (ns->CFG_cache & CFG_TBI_EN) {
+		DBG("%s: enabling optical transceiver\n", pci->id->name);
+		writel(readl(ns->base + GPIOR) | 0x3e8, ns->base + GPIOR);
+
+		/* setup auto negotiation feature advertisement */
+		writel(readl(ns->base + TANAR)
+		       | TANAR_HALF_DUP | TANAR_FULL_DUP,
+		       ns->base + TANAR);
+
+		/* start auto negotiation */
+		writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+		       ns->base + TBICR);
+		writel(TBICR_MR_AN_ENABLE, ns->base + TBICR);
+		ns->linkstate = LINK_AUTONEGOTIATE;
+
+		ns->CFG_cache |= CFG_MODE_1000;
+	}
+	writel(ns->CFG_cache, ns->base + CFG);
+	DBG("CFG: %hX\n", ns->CFG_cache);
+
+	/* FIXME: reset_phy is defaulted to 0, should we reset anyway? */
+	if (reset_phy) {
+		DBG("%s: resetting phy\n", pci->id->name);
+		writel(ns->CFG_cache | CFG_PHY_RST, ns->base + CFG);
+		writel(ns->CFG_cache, ns->base + CFG);
+	}
+#if 0				/* Huh?  This sets the PCI latency register.  Should be done via 
+				 * the PCI layer.  FIXME.
+				 */
+	if (readl(dev->base + SRR))
+		writel(readl(dev->base + 0x20c) | 0xfe00,
+		       dev->base + 0x20c);
+#endif
+
+	/* Note!  The DMA burst size interacts with packet
+	 * transmission, such that the largest packet that
+	 * can be transmitted is 8192 - FLTH - burst size.
+	 * If only the transmit fifo was larger...
+	 */
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems */
+	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
+	       | ((1600 / 32) * 0x100), ns->base + TXCFG);
+
+	/* Set Rx to full duplex, don't accept runt, errored, long or length
+	 * range errored packets.  Use 512 byte DMA.
+	 */
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems 
+	 * Turn on ALP, only we are accpeting Jumbo Packets */
+	writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
+	       | RXCFG_STRIPCRC
+	       //| RXCFG_ALP
+	       | (RXCFG_MXDMA512) | 0, ns->base + RXCFG);
+
+	/* Disable priority queueing */
+	writel(0, ns->base + PQCR);
+
+	/* Enable IP checksum validation and detetion of VLAN headers.
+	 * Note: do not set the reject options as at least the 0x102
+	 * revision of the chip does not properly accept IP fragments
+	 * at least for UDP.
+	 */
+	/* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since
+	 * the MAC it calculates the packetsize AFTER stripping the VLAN
+	 * header, and if a VLAN Tagged packet of 64 bytes is received (like
+	 * a ping with a VLAN header) then the card, strips the 4 byte VLAN
+	 * tag and then checks the packet size, so if RXCFG_ARP is not enabled,
+	 * it discrards it!.  These guys......
+	 */
+	writel(VRCR_IPEN | VRCR_VTDEN, ns->base + VRCR);
+
+	/* Enable per-packet TCP/UDP/IP checksumming */
+	writel(VTCR_PPCHK, ns->base + VTCR);
+
+	/* Ramit : Enable async and sync pause frames */
+//      writel(0, ns->base + PCR); 
+	writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K |
+		PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT),
+	       ns->base + PCR);
+
+	/* Disable Wake On Lan */
+	writel(0, ns->base + WCSR);
+
+	ns83820_getmac(nic, nic->node_addr);
+
+	if (using_dac) {
+		DBG("%s: using 64 bit addressing.\n", pci->id->name);
+	}
+
+	DBG("%s: DP83820 %d.%d: io=%#04lx\n",
+	    pci->id->name,
+	    (unsigned) readl(ns->base + SRR) >> 8,
+	    (unsigned) readl(ns->base + SRR) & 0xff,
+	    pci->ioaddr);
+
+#ifdef PHY_CODE_IS_FINISHED
+	ns83820_probe_phy(dev);
+#endif
+
+	ns83820_reset(nic);
+	/* point to NIC specific routines */
+	nic->nic_op	= &ns83820_operations;
+	return 1;
+}
+
+DRIVER ( "NS83820/PCI", nic_driver, pci_driver, ns83820_driver,
+	 ns83820_probe, ns83820_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.c
new file mode 100644
index 0000000..a30f936
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.c
@@ -0,0 +1,1037 @@
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+  This software may be used, modified, copied, distributed, and sold, in
+  both source and binary form provided that the above copyright and these
+  terms are retained. Under no circumstances are the authors responsible for
+  the proper functioning of this software, nor do the authors assume any
+  responsibility for damages incurred with its use.
+
+Multicast support added by Timothy Legge (timlegge at users.sourceforge.net) 09/28/2003
+Relocation support added by Ken Yap (ken_yap at users.sourceforge.net) 28/12/02
+3c503 support added by Bill Paul (wpaul at ctr.columbia.edu) on 11/15/94
+SMC8416 support added by Bill Paul (wpaul at ctr.columbia.edu) on 12/25/94
+3c503 PIO support added by Jim Hague (jim.hague at acm.org) on 2/17/98
+RX overrun by Klaus Espenlaub (espenlaub at informatik.uni-ulm.de) on 3/10/99
+  parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
+SMC8416 PIO support added by Andrew Bettison (andrewb at zip.com.au) on 4/3/02
+  based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
+
+**************************************************************************/
+
+FILE_LICENCE ( BSD2 );
+
+/* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
+
+#if 1
+
+#if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
+    !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
+  /* The driver named ns8390 is the PCI driver, often called
+     "PCI ne2000 clones". */
+# define INCLUDE_NS8390 1
+#endif
+
+#include "etherboot.h"
+#include "nic.h"
+#include "ns8390.h"
+#include <ipxe/ethernet.h>
+#ifdef	INCLUDE_NS8390
+#include <ipxe/pci.h>
+#else
+#include <ipxe/isa.h>
+#endif
+
+static unsigned char	eth_vendor, eth_flags;
+#ifdef	INCLUDE_WD
+static unsigned char	eth_laar;
+#endif
+static unsigned short	eth_nic_base, eth_asic_base;
+static unsigned char	eth_memsize, eth_rx_start, eth_tx_start;
+static Address		eth_bmem, eth_rmem;
+static unsigned char	eth_drain_receiver;
+
+#ifdef	INCLUDE_WD
+static struct wd_board {
+	const char *name;
+	char id;
+	char flags;
+	char memsize;
+} wd_boards[] = {
+	{"WD8003S",	TYPE_WD8003S,	0,			MEM_8192},
+	{"WD8003E",	TYPE_WD8003E,	0,			MEM_8192},
+	{"WD8013EBT",	TYPE_WD8013EBT,	FLAG_16BIT,		MEM_16384},
+	{"WD8003W",	TYPE_WD8003W,	0,			MEM_8192},
+	{"WD8003EB",	TYPE_WD8003EB,	0,			MEM_8192},
+	{"WD8013W",	TYPE_WD8013W,	FLAG_16BIT,		MEM_16384},
+	{"WD8003EP/WD8013EP",
+			TYPE_WD8013EP,	0,			MEM_8192},
+	{"WD8013WC",	TYPE_WD8013WC,	FLAG_16BIT,		MEM_16384},
+	{"WD8013EPC",	TYPE_WD8013EPC,	FLAG_16BIT,		MEM_16384},
+	{"SMC8216T",	TYPE_SMC8216T,	FLAG_16BIT | FLAG_790,	MEM_16384},
+	{"SMC8216C",	TYPE_SMC8216C,	FLAG_16BIT | FLAG_790,	MEM_16384},
+	{"SMC8416T",	TYPE_SMC8416T,	FLAG_16BIT | FLAG_790,	MEM_8192},
+	{"SMC8416C/BT",	TYPE_SMC8416C,	FLAG_16BIT | FLAG_790,	MEM_8192},
+	{"SMC8013EBP",	TYPE_SMC8013EBP,FLAG_16BIT,		MEM_16384},
+	{NULL,		0,		0,			0}
+};
+#endif
+
+#ifdef	INCLUDE_3C503
+static unsigned char	t503_output;	/* AUI or internal xcvr (Thinnet) */
+#endif
+
+#if	defined(INCLUDE_WD)
+#define	ASIC_PIO	WD_IAR
+#define	eth_probe	wd_probe
+#if	defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
+Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
+#endif
+#endif
+
+#if	defined(INCLUDE_3C503)
+#define	eth_probe	t503_probe
+#if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
+Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
+#endif
+#endif
+
+#if	defined(INCLUDE_NE)
+#define	eth_probe	ne_probe
+#if	defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
+Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
+#endif
+#endif
+
+#if	defined(INCLUDE_NS8390)
+#define	eth_probe	nepci_probe
+#if	defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
+Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
+#endif
+#endif
+
+#if	defined(INCLUDE_3C503)
+#define	ASIC_PIO	_3COM_RFMSB
+#else
+#if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
+#define	ASIC_PIO	NE_DATA
+#endif
+#endif
+
+#if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
+/**************************************************************************
+ETH_PIO_READ - Read a frame via Programmed I/O
+**************************************************************************/
+static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
+{
+#ifdef	INCLUDE_WD
+	outb(src & 0xff, eth_asic_base + WD_GP2);
+	outb(src >> 8, eth_asic_base + WD_GP2);
+#else
+	outb(D8390_COMMAND_RD2 |
+		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+	outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
+	outb(src, eth_nic_base + D8390_P0_RSAR0);
+	outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
+	outb(D8390_COMMAND_RD0 |
+		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+#ifdef	INCLUDE_3C503
+	outb(src & 0xff, eth_asic_base + _3COM_DALSB);
+	outb(src >> 8, eth_asic_base + _3COM_DAMSB);
+	outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
+#endif
+#endif
+
+	if (eth_flags & FLAG_16BIT)
+		cnt = (cnt + 1) >> 1;
+
+	while(cnt--) {
+#ifdef	INCLUDE_3C503
+		while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
+			;
+#endif
+
+		if (eth_flags & FLAG_16BIT) {
+			*((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
+			dst += 2;
+		}
+		else
+			*(dst++) = inb(eth_asic_base + ASIC_PIO);
+	}
+
+#ifdef	INCLUDE_3C503
+	outb(t503_output, eth_asic_base + _3COM_CR);
+#endif
+}
+
+/**************************************************************************
+ETH_PIO_WRITE - Write a frame via Programmed I/O
+**************************************************************************/
+static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
+{
+#ifdef	COMPEX_RL2000_FIX
+	unsigned int x;
+#endif	/* COMPEX_RL2000_FIX */
+#ifdef	INCLUDE_WD
+	outb(dst & 0xff, eth_asic_base + WD_GP2);
+	outb(dst >> 8, eth_asic_base + WD_GP2);
+#else
+	outb(D8390_COMMAND_RD2 |
+		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+	outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+	outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
+	outb(dst, eth_nic_base + D8390_P0_RSAR0);
+	outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
+	outb(D8390_COMMAND_RD1 |
+		D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+#ifdef	INCLUDE_3C503
+	outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
+	outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
+
+	outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
+#endif
+#endif
+
+	if (eth_flags & FLAG_16BIT)
+		cnt = (cnt + 1) >> 1;
+
+	while(cnt--)
+	{
+#ifdef	INCLUDE_3C503
+		while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
+			;
+#endif
+
+		if (eth_flags & FLAG_16BIT) {
+			outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
+			src += 2;
+		}
+		else
+			outb(*(src++), eth_asic_base + ASIC_PIO);
+	}
+
+#ifdef	INCLUDE_3C503
+	outb(t503_output, eth_asic_base + _3COM_CR);
+#else
+#ifdef	COMPEX_RL2000_FIX
+	for (x = 0;
+		x < COMPEX_RL2000_TRIES &&
+		(inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
+		!= D8390_ISR_RDC;
+		++x);
+	if (x >= COMPEX_RL2000_TRIES)
+		printf("Warning: Compex RL2000 aborted wait!\n");
+#endif	/* COMPEX_RL2000_FIX */
+#ifndef	INCLUDE_WD
+	while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
+		!= D8390_ISR_RDC);
+#endif
+#endif
+}
+#else
+/**************************************************************************
+ETH_PIO_READ - Dummy routine when NE2000 not compiled in
+**************************************************************************/
+static void eth_pio_read(unsigned int src __unused, unsigned char *dst  __unused, unsigned int cnt __unused) {}
+#endif
+
+
+/**************************************************************************
+enable_multycast - Enable Multicast
+**************************************************************************/
+static void enable_multicast(unsigned short eth_nic_base) 
+{
+	unsigned char mcfilter[8];
+	int i;
+	memset(mcfilter, 0xFF, 8);
+	outb(4, eth_nic_base+D8390_P0_RCR);	
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
+	for(i=0;i<8;i++)
+	{
+		outb(mcfilter[i], eth_nic_base + 8 + i);
+		if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
+			printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
+	}
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
+	outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
+}
+
+/**************************************************************************
+NS8390_RESET - Reset adapter
+**************************************************************************/
+static void ns8390_reset(struct nic *nic)
+{
+	int i;
+
+	eth_drain_receiver = 0;
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	if (eth_flags & FLAG_16BIT)
+		outb(0x49, eth_nic_base+D8390_P0_DCR);
+	else
+		outb(0x48, eth_nic_base+D8390_P0_DCR);
+	outb(0, eth_nic_base+D8390_P0_RBCR0);
+	outb(0, eth_nic_base+D8390_P0_RBCR1);
+	outb(0x20, eth_nic_base+D8390_P0_RCR);	/* monitor mode */
+	outb(2, eth_nic_base+D8390_P0_TCR);
+	outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+	outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790) {
+#ifdef	WD_790_PIO
+		outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
+		outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
+#else
+		outb(0, eth_nic_base + 0x09);
+#endif
+	}
+#endif
+	outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
+	outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
+	outb(0xFF, eth_nic_base+D8390_P0_ISR);
+	outb(0, eth_nic_base+D8390_P0_IMR);
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS1 |
+			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS1 |
+			D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	for (i=0; i<ETH_ALEN; i++)
+		outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
+	for (i=0; i<ETH_ALEN; i++)
+		outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
+	outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	outb(0xFF, eth_nic_base+D8390_P0_ISR);
+	outb(0, eth_nic_base+D8390_P0_TCR);	/* transmitter on */
+	outb(4, eth_nic_base+D8390_P0_RCR);	/* allow rx broadcast frames */
+
+	enable_multicast(eth_nic_base);
+
+#ifdef	INCLUDE_3C503
+        /*
+         * No way to tell whether or not we're supposed to use
+         * the 3Com's transceiver unless the user tells us.
+         * 'flags' should have some compile time default value
+         * which can be changed from the command menu.
+         */
+	t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
+	outb(t503_output, eth_asic_base + _3COM_CR);
+#endif
+}
+
+static int ns8390_poll(struct nic *nic, int retrieve);
+
+#ifndef	INCLUDE_3C503
+/**************************************************************************
+ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
+**************************************************************************/
+static void eth_rx_overrun(struct nic *nic)
+{
+	int start_time;
+
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+			D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+
+	/* wait for at least 1.6ms - we wait one timer tick */
+	start_time = currticks();
+	while (currticks() - start_time <= 1)
+		/* Nothing */;
+
+	outb(0, eth_nic_base+D8390_P0_RBCR0);	/* reset byte counter */
+	outb(0, eth_nic_base+D8390_P0_RBCR1);
+
+	/*
+	 * Linux driver checks for interrupted TX here. This is not necessary,
+	 * because the transmit routine waits until the frame is sent.
+	 */
+
+	/* enter loopback mode and restart NIC */
+	outb(2, eth_nic_base+D8390_P0_TCR);
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+
+	/* clear the RX ring, acknowledge overrun interrupt */
+	eth_drain_receiver = 1;
+	while (ns8390_poll(nic, 1))
+		/* Nothing */;
+	eth_drain_receiver = 0;
+	outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
+
+	/* leave loopback mode - no packets to be resent (see Linux driver) */
+	outb(0, eth_nic_base+D8390_P0_TCR);
+}
+#endif	/* INCLUDE_3C503 */
+
+/**************************************************************************
+NS8390_TRANSMIT - Transmit a frame
+**************************************************************************/
+static void ns8390_transmit(
+	struct nic *nic,
+	const char *d,			/* Destination */
+	unsigned int t,			/* Type */
+	unsigned int s,			/* size */
+	const char *p)			/* Packet */
+{
+#if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
+	Address		eth_vmem = bus_to_virt(eth_bmem);
+#endif
+#ifdef	INCLUDE_3C503
+        if (!(eth_flags & FLAG_PIO)) {
+                memcpy((char *)eth_vmem, d, ETH_ALEN);	/* dst */
+                memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
+                *((char *)eth_vmem+12) = t>>8;		/* type */
+                *((char *)eth_vmem+13) = t;
+                memcpy((char *)eth_vmem+ETH_HLEN, p, s);
+                s += ETH_HLEN;
+                while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
+        }
+#endif
+
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_16BIT) {
+		outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
+		inb(0x84);
+	}
+#ifndef	WD_790_PIO
+	/* Memory interface */
+	if (eth_flags & FLAG_790) {
+		outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
+		inb(0x84);
+	}
+	inb(0x84);
+	memcpy((char *)eth_vmem, d, ETH_ALEN);	/* dst */
+	memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
+	*((char *)eth_vmem+12) = t>>8;		/* type */
+	*((char *)eth_vmem+13) = t;
+	memcpy((char *)eth_vmem+ETH_HLEN, p, s);
+	s += ETH_HLEN;
+	while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
+	if (eth_flags & FLAG_790) {
+		outb(0, eth_asic_base + WD_MSR);
+		inb(0x84);
+	}
+#else
+	inb(0x84);
+#endif
+#endif
+
+#if	defined(INCLUDE_3C503)
+	if (eth_flags & FLAG_PIO)
+#endif
+#if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
+	{
+		/* Programmed I/O */
+		unsigned short type;
+		type = (t >> 8) | (t << 8);
+		eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN);
+		eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
+		/* bcc generates worse code without (const+const) below */
+		eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
+		eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s);
+		s += ETH_HLEN;
+		if (s < ETH_ZLEN) s = ETH_ZLEN;
+	}
+#endif
+#if	defined(INCLUDE_3C503)
+#endif
+
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_16BIT) {
+		outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
+		inb(0x84);
+	}
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+	outb(s, eth_nic_base+D8390_P0_TBCR0);
+	outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_790)
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+	else
+#endif
+		outb(D8390_COMMAND_PS0 |
+			D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
+			D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+}
+
+/**************************************************************************
+NS8390_POLL - Wait for a frame
+**************************************************************************/
+static int ns8390_poll(struct nic *nic, int retrieve)
+{
+	int ret = 0;
+	unsigned char rstat, curr, next;
+	unsigned short len, frag;
+	unsigned short pktoff;
+	unsigned char *p;
+	struct ringbuffer pkthdr;
+
+#ifndef	INCLUDE_3C503
+	/* avoid infinite recursion: see eth_rx_overrun() */
+	if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
+		eth_rx_overrun(nic);
+		return(0);
+	}
+#endif	/* INCLUDE_3C503 */
+	rstat = inb(eth_nic_base+D8390_P0_RSR);
+	if (!(rstat & D8390_RSTAT_PRX)) return(0);
+	next = inb(eth_nic_base+D8390_P0_BOUND)+1;
+	if (next >= eth_memsize) next = eth_rx_start;
+	outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
+	curr = inb(eth_nic_base+D8390_P1_CURR);
+	outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
+	if (curr >= eth_memsize) curr=eth_rx_start;
+	if (curr == next) return(0);
+
+	if ( ! retrieve ) return 1;
+
+#ifdef	INCLUDE_WD
+	if (eth_flags & FLAG_16BIT) {
+		outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
+		inb(0x84);
+	}
+#ifndef	WD_790_PIO
+	if (eth_flags & FLAG_790) {
+		outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
+		inb(0x84);
+	}
+#endif
+	inb(0x84);
+#endif
+	pktoff = next << 8;
+	if (eth_flags & FLAG_PIO)
+		eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
+	else
+		memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
+	pktoff += sizeof(pkthdr);
+	/* incoming length includes FCS so must sub 4 */
+	len = pkthdr.len - 4;
+	if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
+		|| len > ETH_FRAME_LEN) {
+		printf("Bogus packet, ignoring\n");
+		return (0);
+	}
+	else {
+		p = nic->packet;
+		nic->packetlen = len;		/* available to caller */
+		frag = (eth_memsize << 8) - pktoff;
+		if (len > frag) {		/* We have a wrap-around */
+			/* read first part */
+			if (eth_flags & FLAG_PIO)
+				eth_pio_read(pktoff, p, frag);
+			else
+				memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
+			pktoff = eth_rx_start << 8;
+			p += frag;
+			len -= frag;
+		}
+		/* read second part */
+		if (eth_flags & FLAG_PIO)
+			eth_pio_read(pktoff, p, len);
+		else
+			memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
+		ret = 1;
+	}
+#ifdef	INCLUDE_WD
+#ifndef	WD_790_PIO
+	if (eth_flags & FLAG_790) {
+		outb(0, eth_asic_base + WD_MSR);
+		inb(0x84);
+	}
+#endif
+	if (eth_flags & FLAG_16BIT) {
+		outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
+		inb(0x84);
+	}
+	inb(0x84);
+#endif
+	next = pkthdr.next;		/* frame number of next packet */
+	if (next == eth_rx_start)
+		next = eth_memsize;
+	outb(next-1, eth_nic_base+D8390_P0_BOUND);
+	return(ret);
+}
+
+/**************************************************************************
+NS8390_DISABLE - Turn off adapter
+**************************************************************************/
+static void ns8390_disable ( struct nic *nic ) {
+	ns8390_reset(nic);
+}
+
+/**************************************************************************
+NS8390_IRQ - Enable, Disable, or Force interrupts
+**************************************************************************/
+static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations ns8390_operations;
+static struct nic_operations ns8390_operations = {
+	.connect	= dummy_connect,
+	.poll		= ns8390_poll,
+	.transmit	= ns8390_transmit,
+	.irq		= ns8390_irq,
+};
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+**************************************************************************/
+#ifdef	INCLUDE_NS8390
+static int eth_probe (struct nic *nic, struct pci_device *pci)
+#else
+static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
+#endif
+{
+	int i;
+#ifdef INCLUDE_NS8390
+	unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
+	unsigned short *probe_addrs = pci_probe_addrs;
+#endif
+	eth_vendor = VENDOR_NONE;
+	eth_drain_receiver = 0;
+
+	nic->irqno  = 0;
+
+#ifdef	INCLUDE_WD
+{
+	/******************************************************************
+	Search for WD/SMC cards
+	******************************************************************/
+	struct wd_board *brd;
+	unsigned short chksum;
+	unsigned char c;
+	for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
+		eth_asic_base += 0x20) {
+		chksum = 0;
+		for (i=8; i<16; i++)
+			chksum += inb(eth_asic_base+i);
+		/* Extra checks to avoid soundcard */
+		if ((chksum & 0xFF) == 0xFF &&
+			inb(eth_asic_base+8) != 0xFF &&
+			inb(eth_asic_base+9) != 0xFF)
+			break;
+	}
+	if (eth_asic_base > WD_HIGH_BASE)
+		return (0);
+	/* We've found a board */
+	eth_vendor = VENDOR_WD;
+	eth_nic_base = eth_asic_base + WD_NIC_ADDR;
+
+	nic->ioaddr = eth_nic_base;
+
+	c = inb(eth_asic_base+WD_BID);	/* Get board id */
+	for (brd = wd_boards; brd->name; brd++)
+		if (brd->id == c) break;
+	if (!brd->name) {
+		printf("Unknown WD/SMC NIC type %hhX\n", c);
+		return (0);	/* Unknown type */
+	}
+	eth_flags = brd->flags;
+	eth_memsize = brd->memsize;
+	eth_tx_start = 0;
+	eth_rx_start = D8390_TXBUF_SIZE;
+	if ((c == TYPE_WD8013EP) &&
+		(inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
+			eth_flags = FLAG_16BIT;
+			eth_memsize = MEM_16384;
+	}
+	if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
+		eth_bmem = (0x80000 |
+		 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
+	} else
+		eth_bmem = WD_DEFAULT_MEM;
+	if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
+		/* from Linux driver, 8416BT detects as 8216 sometimes */
+		unsigned int addr = inb(eth_asic_base + 0xb);
+		if (((addr >> 4) & 3) == 0) {
+			brd += 2;
+			eth_memsize = brd->memsize;
+		}
+	}
+	outb(0x80, eth_asic_base + WD_MSR);	/* Reset */
+	for (i=0; i<ETH_ALEN; i++) {
+		nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
+	}
+	DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
+	if (eth_flags & FLAG_790) {
+#ifdef	WD_790_PIO
+		DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
+		eth_bmem = 0;
+		eth_flags |= FLAG_PIO;		/* force PIO mode */
+		outb(0, eth_asic_base+WD_MSR);
+#else
+		DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
+
+		outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
+		outb((inb(eth_asic_base+0x04) |
+			0x80), eth_asic_base+0x04);
+		outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
+			((unsigned)(eth_bmem >> 11) & 0x40) |
+			(inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
+		outb((inb(eth_asic_base+0x04) &
+			~0x80), eth_asic_base+0x04);
+#endif
+	} else {
+
+		DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
+
+		outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
+	}
+	if (eth_flags & FLAG_16BIT) {
+		if (eth_flags & FLAG_790) {
+			eth_laar = inb(eth_asic_base + WD_LAAR);
+			outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
+		} else {
+			outb((eth_laar =
+				WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
+/*
+	The previous line used to be
+				WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
+	jluke at deakin.edu.au reported that removing WD_LAAR_M16EN made
+	it work for WD8013s.  This seems to work for my 8013 boards. I
+	don't know what is really happening.  I wish I had data sheets
+	or more time to decode the Linux driver. - Ken
+*/
+		}
+		inb(0x84);
+	}
+}
+#endif
+#ifdef	INCLUDE_3C503
+#ifdef	T503_AUI
+	nic->flags = 1;		/* aui */
+#else
+	nic->flags = 0;		/* no aui */
+#endif
+        /******************************************************************
+        Search for 3Com 3c503 if no WD/SMC cards
+        ******************************************************************/
+	if (eth_vendor == VENDOR_NONE) {
+		int	idx;
+		int	iobase_reg, membase_reg;
+		static unsigned short	base[] = {
+			0x300, 0x310, 0x330, 0x350,
+			0x250, 0x280, 0x2A0, 0x2E0, 0 };
+
+		/* Loop through possible addresses checking each one */
+
+		for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
+
+			eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
+/*
+ * Note that we use the same settings for both 8 and 16 bit cards:
+ * both have an 8K bank of memory at page 1 while only the 16 bit
+ * cards have a bank at page 0.
+ */
+			eth_memsize = MEM_16384;
+			eth_tx_start = 32;
+			eth_rx_start = 32 + D8390_TXBUF_SIZE;
+
+		/* Check our base address. iobase and membase should */
+		/* both have a maximum of 1 bit set or be 0. */
+
+			iobase_reg = inb(eth_asic_base + _3COM_BCFR);
+			membase_reg = inb(eth_asic_base + _3COM_PCFR);
+
+			if ((iobase_reg & (iobase_reg - 1)) ||
+				(membase_reg & (membase_reg - 1)))
+				continue;		/* nope */
+
+		/* Now get the shared memory address */
+
+			eth_flags = 0;
+
+			switch (membase_reg) {
+				case _3COM_PCFR_DC000:
+					eth_bmem = 0xdc000;
+					break;
+				case _3COM_PCFR_D8000:
+					eth_bmem = 0xd8000;
+					break;
+				case _3COM_PCFR_CC000:
+					eth_bmem = 0xcc000;
+					break;
+				case _3COM_PCFR_C8000:
+					eth_bmem = 0xc8000;
+					break;
+				case _3COM_PCFR_PIO:
+					eth_flags |= FLAG_PIO;
+					eth_bmem = 0;
+					break;
+				default:
+					continue;	/* nope */
+				}
+			break;
+		}
+
+		if (base[idx] == 0)		/* not found */
+			return (0);
+#ifndef	T503_SHMEM
+		eth_flags |= FLAG_PIO;		/* force PIO mode */
+		eth_bmem = 0;
+#endif
+		eth_vendor = VENDOR_3COM;
+
+
+        /* Need this to make ns8390_poll() happy. */
+
+                eth_rmem = eth_bmem - 0x2000;
+
+        /* Reset NIC and ASIC */
+
+                outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
+                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
+
+        /* Get our ethernet address */
+
+                outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
+		nic->ioaddr = eth_nic_base;
+                DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
+                if (eth_flags & FLAG_PIO)
+			DBG ( "PIO mode" );
+                else
+			DBG ( "memory %4.4x", eth_bmem );
+                for (i=0; i<ETH_ALEN; i++) {
+                        nic->node_addr[i] = inb(eth_nic_base+i);
+                }
+                DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
+		      eth_ntoa ( nic->node_addr ) );
+
+                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
+        /*
+         * Initialize GA configuration register. Set bank and enable shared
+         * mem. We always use bank 1. Disable interrupts.
+         */
+                outb(_3COM_GACFR_RSEL |
+			_3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
+
+                outb(0xff, eth_asic_base + _3COM_VPTR2);
+                outb(0xff, eth_asic_base + _3COM_VPTR1);
+                outb(0x00, eth_asic_base + _3COM_VPTR0);
+        /*
+         * Clear memory and verify that it worked (we use only 8K)
+         */
+
+		if (!(eth_flags & FLAG_PIO)) {
+			memset(bus_to_virt(eth_bmem), 0, 0x2000);
+			for(i = 0; i < 0x2000; ++i)
+				if (*((char *)(bus_to_virt(eth_bmem+i)))) {
+					printf ("Failed to clear 3c503 shared mem.\n");
+					return (0);
+				}
+		}
+        /*
+         * Initialize GA page/start/stop registers.
+         */
+                outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
+                outb(eth_memsize, eth_asic_base + _3COM_PSPR);
+        }
+#endif
+#if	defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
+{
+	/******************************************************************
+	Search for NE1000/2000 if no WD/SMC or 3com cards
+	******************************************************************/
+	unsigned char c;
+	if (eth_vendor == VENDOR_NONE) {
+		unsigned char romdata[16];
+		unsigned char testbuf[32];
+		int idx;
+		static unsigned char test[] = "NE*000 memory";
+		static unsigned short base[] = {
+#ifdef	NE_SCAN
+			NE_SCAN,
+#endif
+			0 };
+		/* if no addresses supplied, fall back on defaults */
+		if (probe_addrs == 0 || probe_addrs[0] == 0)
+			probe_addrs = base;
+		eth_bmem = 0;		/* No shared memory */
+		for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
+			eth_flags = FLAG_PIO;
+			eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
+			eth_memsize = MEM_16384;
+			eth_tx_start = 32;
+			eth_rx_start = 32 + D8390_TXBUF_SIZE;
+			c = inb(eth_asic_base + NE_RESET);
+			outb(c, eth_asic_base + NE_RESET);
+			(void) inb(0x84);
+			outb(D8390_COMMAND_STP |
+				D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
+			outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
+			outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+			outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+			outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+#ifdef	NS8390_FORCE_16BIT
+			eth_flags |= FLAG_16BIT;	/* force 16-bit mode */
+#endif
+
+			eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
+			eth_pio_read(8192, testbuf, sizeof(test));
+			if (!memcmp(test, testbuf, sizeof(test)))
+				break;
+			eth_flags |= FLAG_16BIT;
+			eth_memsize = MEM_32768;
+			eth_tx_start = 64;
+			eth_rx_start = 64 + D8390_TXBUF_SIZE;
+			outb(D8390_DCR_WTS |
+				D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+			outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
+			outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
+			eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
+			eth_pio_read(16384, testbuf, sizeof(test));
+			if (!memcmp(testbuf, test, sizeof(test)))
+				break;
+		}
+		if (eth_nic_base == 0)
+			return (0);
+		if (eth_nic_base > ISA_MAX_ADDR)	/* PCI probably */
+			eth_flags |= FLAG_16BIT;
+		eth_vendor = VENDOR_NOVELL;
+		eth_pio_read(0, romdata, sizeof(romdata));
+		for (i=0; i<ETH_ALEN; i++) {
+			nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
+		}
+		nic->ioaddr = eth_nic_base;
+		DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
+		      (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
+		      eth_ntoa ( nic->node_addr ) );
+	}
+}
+#endif
+	if (eth_vendor == VENDOR_NONE)
+		return(0);
+        if (eth_vendor != VENDOR_3COM)
+		eth_rmem = eth_bmem;
+	ns8390_reset(nic);
+	nic->nic_op	= &ns8390_operations;
+
+        /* Based on PnP ISA map */
+#ifdef	INCLUDE_WD
+        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
+        dev->devid.device_id = htons(0x812a);
+#endif
+#ifdef	INCLUDE_3C503
+        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
+        dev->devid.device_id = htons(0x80f3);
+#endif
+#ifdef	INCLUDE_NE
+        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
+        dev->devid.device_id = htons(0x80d6);
+#endif
+	return 1;
+}
+
+#ifdef	INCLUDE_WD
+struct isa_driver wd_driver __isa_driver = {
+	.type    = NIC_DRIVER,
+	.name    = "WD",
+	.probe   = wd_probe,
+	.ioaddrs = 0, 
+};
+ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
+#endif
+
+#ifdef	INCLUDE_3C503
+struct isa_driver t503_driver __isa_driver = {
+	.type    = NIC_DRIVER,
+	.name    = "3C503",
+	.probe   = t503_probe,
+	.ioaddrs = 0, 
+};
+ISA_ROM("3c503","3Com503, Etherlink II[/16]");
+#endif
+
+#ifdef	INCLUDE_NE
+struct isa_driver ne_driver __isa_driver = {
+	.type    = NIC_DRIVER,
+	.name    = "NE*000",
+	.probe   = ne_probe,
+	.ioaddrs = 0, 
+};
+ISA_ROM("ne","NE1000/2000 and clones");
+#endif
+
+#ifdef	INCLUDE_NS8390
+static struct pci_device_id nepci_nics[] = {
+/* A few NE2000 PCI clones, list not exhaustive */
+PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029", 0),
+PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528", 0),
+PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI", 0),		/* Winbond 86C940 / 89C940 */
+PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F", 0),		/* Winbond 89C940F */
+PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
+PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2", 0),
+PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC", 0),
+PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232", 0),
+PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229", 0),
+PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
+PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926", 0),
+};
+
+PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
+
+DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver,
+	 nepci_probe, ns8390_disable );
+
+#endif /* INCLUDE_NS8390 */
+
+#endif
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.h
new file mode 100644
index 0000000..79728e7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/ns8390.h
@@ -0,0 +1,240 @@
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: Jun/94
+
+**************************************************************************/
+
+FILE_LICENCE ( BSD2 );
+
+#define VENDOR_NONE	0
+#define VENDOR_WD	1
+#define VENDOR_NOVELL	2
+#define VENDOR_3COM	3
+
+#define FLAG_PIO	0x01
+#define FLAG_16BIT	0x02
+#define FLAG_790	0x04
+
+#define MEM_8192	32
+#define MEM_16384	64
+#define MEM_32768	128
+
+#define	ISA_MAX_ADDR	0x400
+
+/**************************************************************************
+Western Digital/SMC Board Definitions
+**************************************************************************/
+#define WD_LOW_BASE	0x200
+#define WD_HIGH_BASE	0x3e0
+#ifndef	WD_DEFAULT_MEM
+#define WD_DEFAULT_MEM	0xD0000
+#endif
+#define WD_NIC_ADDR	0x10
+
+/**************************************************************************
+Western Digital/SMC ASIC Addresses
+**************************************************************************/
+#define WD_MSR		0x00
+#define WD_ICR		0x01
+#define WD_IAR		0x02
+#define WD_BIO		0x03
+#define WD_IRR		0x04
+#define WD_LAAR		0x05
+#define WD_IJR		0x06
+#define WD_GP2		0x07
+#define WD_LAR		0x08
+#define WD_BID		0x0E
+
+#define WD_ICR_16BIT	0x01
+
+#define WD_MSR_MENB	0x40
+
+#define WD_LAAR_L16EN	0x40
+#define WD_LAAR_M16EN	0x80
+
+#define WD_SOFTCONFIG	0x20
+
+/**************************************************************************
+Western Digital/SMC Board Types
+**************************************************************************/
+#define TYPE_WD8003S	0x02
+#define TYPE_WD8003E	0x03
+#define TYPE_WD8013EBT	0x05
+#define TYPE_WD8003W	0x24
+#define TYPE_WD8003EB	0x25
+#define TYPE_WD8013W	0x26
+#define TYPE_WD8013EP	0x27
+#define TYPE_WD8013WC	0x28
+#define TYPE_WD8013EPC	0x29
+#define TYPE_SMC8216T	0x2a
+#define TYPE_SMC8216C	0x2b
+#define TYPE_SMC8416T	0x00	/* Bogus entries: the 8416 generates the */
+#define TYPE_SMC8416C	0x00	/* the same codes as the 8216. */
+#define TYPE_SMC8013EBP	0x2c
+
+/**************************************************************************
+3com 3c503 definitions
+**************************************************************************/
+
+#ifndef	_3COM_BASE
+#define _3COM_BASE 0x300
+#endif
+
+#define _3COM_TX_PAGE_OFFSET_8BIT     0x20
+#define _3COM_TX_PAGE_OFFSET_16BIT    0x0
+#define _3COM_RX_PAGE_OFFSET_16BIT    0x20
+
+#define _3COM_ASIC_OFFSET 0x400
+#define _3COM_NIC_OFFSET 0x0
+
+#define _3COM_PSTR            0
+#define _3COM_PSPR            1
+
+#define _3COM_BCFR            3
+#define _3COM_BCFR_2E0        0x01
+#define _3COM_BCFR_2A0        0x02
+#define _3COM_BCFR_280        0x04
+#define _3COM_BCFR_250        0x08
+#define _3COM_BCFR_350        0x10
+#define _3COM_BCFR_330        0x20
+#define _3COM_BCFR_310        0x40
+#define _3COM_BCFR_300        0x80
+#define _3COM_PCFR            4
+#define _3COM_PCFR_PIO        0
+#define _3COM_PCFR_C8000      0x10
+#define _3COM_PCFR_CC000      0x20
+#define _3COM_PCFR_D8000      0x40
+#define _3COM_PCFR_DC000      0x80
+#define _3COM_CR              6
+#define _3COM_CR_RST          0x01    /* Reset GA and NIC */
+#define _3COM_CR_XSEL         0x02    /* Transceiver select. BNC=1(def) AUI=0 */
+#define _3COM_CR_EALO         0x04    /* window EA PROM 0-15 to I/O base */
+#define _3COM_CR_EAHI         0x08    /* window EA PROM 16-31 to I/O base */
+#define _3COM_CR_SHARE        0x10    /* select interrupt sharing option */
+#define _3COM_CR_DBSEL        0x20    /* Double buffer select */
+#define _3COM_CR_DDIR         0x40    /* DMA direction select */
+#define _3COM_CR_START        0x80    /* Start DMA controller */
+#define _3COM_GACFR           5
+#define _3COM_GACFR_MBS0      0x01
+#define _3COM_GACFR_MBS1      0x02
+#define _3COM_GACFR_MBS2      0x04
+#define _3COM_GACFR_RSEL      0x08    /* enable shared memory */
+#define _3COM_GACFR_TEST      0x10    /* for GA testing */
+#define _3COM_GACFR_OWS       0x20    /* select 0WS access to GA */
+#define _3COM_GACFR_TCM       0x40    /* Mask DMA interrupts */
+#define _3COM_GACFR_NIM       0x80    /* Mask NIC interrupts */
+#define _3COM_STREG           7
+#define _3COM_STREG_REV       0x07    /* GA revision */
+#define _3COM_STREG_DIP       0x08    /* DMA in progress */
+#define _3COM_STREG_DTC       0x10    /* DMA terminal count */
+#define _3COM_STREG_OFLW      0x20    /* Overflow */
+#define _3COM_STREG_UFLW      0x40    /* Underflow */
+#define _3COM_STREG_DPRDY     0x80    /* Data port ready */
+#define _3COM_IDCFR           8
+#define _3COM_IDCFR_DRQ0      0x01    /* DMA request 1 select */
+#define _3COM_IDCFR_DRQ1      0x02    /* DMA request 2 select */
+#define _3COM_IDCFR_DRQ2      0x04    /* DMA request 3 select */
+#define _3COM_IDCFR_UNUSED    0x08    /* not used */
+#define _3COM_IDCFR_IRQ2      0x10    /* Interrupt request 2 select */
+#define _3COM_IDCFR_IRQ3      0x20    /* Interrupt request 3 select */
+#define _3COM_IDCFR_IRQ4      0x40    /* Interrupt request 4 select */
+#define _3COM_IDCFR_IRQ5      0x80    /* Interrupt request 5 select */
+#define _3COM_IRQ2      2
+#define _3COM_IRQ3      3
+#define _3COM_IRQ4      4
+#define _3COM_IRQ5      5
+#define _3COM_DAMSB           9
+#define _3COM_DALSB           0x0a
+#define _3COM_VPTR2           0x0b
+#define _3COM_VPTR1           0x0c
+#define _3COM_VPTR0           0x0d
+#define _3COM_RFMSB           0x0e
+#define _3COM_RFLSB           0x0f
+
+/**************************************************************************
+NE1000/2000 definitions
+**************************************************************************/
+#define NE_ASIC_OFFSET	0x10
+#define NE_RESET	0x0F		/* Used to reset card */
+#define NE_DATA		0x00		/* Used to read/write NIC mem */
+
+#define COMPEX_RL2000_TRIES	200
+
+/**************************************************************************
+8390 Register Definitions
+**************************************************************************/
+#define D8390_P0_COMMAND	0x00
+#define D8390_P0_PSTART		0x01
+#define D8390_P0_PSTOP		0x02
+#define D8390_P0_BOUND		0x03
+#define D8390_P0_TSR		0x04
+#define	D8390_P0_TPSR		0x04
+#define D8390_P0_TBCR0		0x05
+#define D8390_P0_TBCR1		0x06
+#define D8390_P0_ISR		0x07
+#define D8390_P0_RSAR0		0x08
+#define D8390_P0_RSAR1		0x09
+#define D8390_P0_RBCR0		0x0A
+#define D8390_P0_RBCR1		0x0B
+#define D8390_P0_RSR		0x0C
+#define D8390_P0_RCR		0x0C
+#define D8390_P0_TCR		0x0D
+#define D8390_P0_DCR		0x0E
+#define D8390_P0_IMR		0x0F
+#define D8390_P1_COMMAND	0x00
+#define D8390_P1_PAR0		0x01
+#define D8390_P1_PAR1		0x02
+#define D8390_P1_PAR2		0x03
+#define D8390_P1_PAR3		0x04
+#define D8390_P1_PAR4		0x05
+#define D8390_P1_PAR5		0x06
+#define D8390_P1_CURR		0x07
+#define D8390_P1_MAR0		0x08
+
+#define D8390_COMMAND_PS0	0x0		/* Page 0 select */
+#define D8390_COMMAND_PS1	0x40		/* Page 1 select */
+#define D8390_COMMAND_PS2	0x80		/* Page 2 select */
+#define	D8390_COMMAND_RD2	0x20		/* Remote DMA control */
+#define D8390_COMMAND_RD1	0x10
+#define D8390_COMMAND_RD0	0x08
+#define D8390_COMMAND_TXP	0x04		/* transmit packet */
+#define D8390_COMMAND_STA	0x02		/* start */
+#define D8390_COMMAND_STP	0x01		/* stop */
+
+#define D8390_RCR_MON		0x20		/* monitor mode */
+
+#define D8390_DCR_FT1		0x40
+#define D8390_DCR_LS		0x08		/* Loopback select */
+#define D8390_DCR_WTS		0x01		/* Word transfer select */
+
+#define D8390_ISR_PRX		0x01		/* successful recv */
+#define D8390_ISR_PTX		0x02		/* successful xmit */
+#define D8390_ISR_RXE		0x04		/* receive error */
+#define D8390_ISR_TXE		0x08		/* transmit error */
+#define D8390_ISR_OVW		0x10		/* Overflow */
+#define D8390_ISR_CNT		0x20		/* Counter overflow */
+#define D8390_ISR_RDC		0x40		/* Remote DMA complete */
+#define D8390_ISR_RST		0x80		/* reset */
+
+#define D8390_RSTAT_PRX		0x01		/* successful recv */
+#define D8390_RSTAT_CRC		0x02		/* CRC error */
+#define D8390_RSTAT_FAE		0x04		/* Frame alignment error */
+#define D8390_RSTAT_OVER	0x08		/* FIFO overrun */
+
+#define D8390_TXBUF_SIZE	6
+#define D8390_RXBUF_END		32
+#define D8390_PAGE_SIZE         256
+
+struct ringbuffer {
+	unsigned char status;
+	unsigned char next;
+	unsigned short len;
+};
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/p80211hdr.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/p80211hdr.h
new file mode 100644
index 0000000..8354671
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/p80211hdr.h
@@ -0,0 +1,301 @@
+/* src/include/wlan/p80211hdr.h
+*
+* Macros, types, and functions for handling 802.11 MAC headers
+*
+* Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+* --------------------------------------------------------------------
+*
+* linux-wlan
+*
+*   The contents of this file are subject to the Mozilla Public
+*   License Version 1.1 (the "License"); you may not use this file
+*   except in compliance with the License. You may obtain a copy of
+*   the License at http://www.mozilla.org/MPL/
+*
+*   Software distributed under the License is distributed on an "AS
+*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+*   implied. See the License for the specific language governing
+*   rights and limitations under the License.
+*
+*   Alternatively, the contents of this file may be used under the
+*   terms of the GNU Public License version 2 (the "GPL"), in which
+*   case the provisions of the GPL are applicable instead of the
+*   above.  If you wish to allow the use of your version of this file
+*   only under the terms of the GPL and not to allow others to use
+*   your version of this file under the MPL, indicate your decision
+*   by deleting the provisions above and replace them with the notice
+*   and other provisions required by the GPL.  If you do not delete
+*   the provisions above, a recipient may use your version of this
+*   file under either the MPL or the GPL.
+*
+* --------------------------------------------------------------------
+*
+* Inquiries regarding the linux-wlan Open Source project can be
+* made directly to:
+*
+* AbsoluteValue Systems Inc.
+* info at linux-wlan.com
+* http://www.linux-wlan.com
+*
+* --------------------------------------------------------------------
+*
+* Portions of the development of this software were funded by 
+* Intersil Corporation as part of PRISM(R) chipset product development.
+*
+* --------------------------------------------------------------------
+*
+* This file declares the constants and types used in the interface
+* between a wlan driver and the user mode utilities.
+*
+* Note: 
+*  - Constant values are always in HOST byte order.  To assign
+*    values to multi-byte fields they _must_ be converted to
+*    ieee byte order.  To retrieve multi-byte values from incoming
+*    frames, they must be converted to host order.
+*
+* All functions declared here are implemented in p80211.c
+* --------------------------------------------------------------------
+*/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _P80211HDR_H
+#define _P80211HDR_H
+
+/*================================================================*/
+/* System Includes */
+
+/*================================================================*/
+/* Project Includes */
+
+#ifndef  _WLAN_COMPAT_H
+#include <wlan/wlan_compat.h>
+#endif
+
+
+/*================================================================*/
+/* Constants */
+
+/*--- Sizes -----------------------------------------------*/
+#define WLAN_ADDR_LEN			6
+#define WLAN_CRC_LEN			4
+#define WLAN_BSSID_LEN			6
+#define WLAN_BSS_TS_LEN			8
+#define WLAN_HDR_A3_LEN			24
+#define WLAN_HDR_A4_LEN			30
+#define WLAN_SSID_MAXLEN		32
+#define WLAN_DATA_MAXLEN		2312
+#define WLAN_A3FR_MAXLEN		(WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)
+#define WLAN_A4FR_MAXLEN		(WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)
+#define WLAN_BEACON_FR_MAXLEN		(WLAN_HDR_A3_LEN + 334)
+#define WLAN_ATIM_FR_MAXLEN		(WLAN_HDR_A3_LEN + 0)
+#define WLAN_DISASSOC_FR_MAXLEN		(WLAN_HDR_A3_LEN + 2)
+#define WLAN_ASSOCREQ_FR_MAXLEN		(WLAN_HDR_A3_LEN + 48)
+#define WLAN_ASSOCRESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 16)
+#define WLAN_REASSOCREQ_FR_MAXLEN	(WLAN_HDR_A3_LEN + 54)
+#define WLAN_REASSOCRESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 16)
+#define WLAN_PROBEREQ_FR_MAXLEN		(WLAN_HDR_A3_LEN + 44)
+#define WLAN_PROBERESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 78)
+#define WLAN_AUTHEN_FR_MAXLEN		(WLAN_HDR_A3_LEN + 261)
+#define WLAN_DEAUTHEN_FR_MAXLEN		(WLAN_HDR_A3_LEN + 2)
+#define WLAN_WEP_NKEYS			4
+#define WLAN_WEP_MAXKEYLEN		13
+#define WLAN_CHALLENGE_IE_LEN		130
+#define WLAN_CHALLENGE_LEN		128
+#define WLAN_WEP_IV_LEN			4
+#define WLAN_WEP_ICV_LEN		4
+
+/*--- Frame Control Field -------------------------------------*/
+/* Frame Types */
+#define WLAN_FTYPE_MGMT			0x00
+#define WLAN_FTYPE_CTL			0x01
+#define WLAN_FTYPE_DATA			0x02
+
+/* Frame subtypes */
+/* Management */
+#define WLAN_FSTYPE_ASSOCREQ		0x00
+#define WLAN_FSTYPE_ASSOCRESP		0x01
+#define WLAN_FSTYPE_REASSOCREQ		0x02
+#define WLAN_FSTYPE_REASSOCRESP		0x03
+#define WLAN_FSTYPE_PROBEREQ		0x04 
+#define WLAN_FSTYPE_PROBERESP		0x05
+#define WLAN_FSTYPE_BEACON		0x08
+#define WLAN_FSTYPE_ATIM		0x09
+#define WLAN_FSTYPE_DISASSOC		0x0a
+#define WLAN_FSTYPE_AUTHEN		0x0b
+#define WLAN_FSTYPE_DEAUTHEN		0x0c
+
+/* Control */
+#define WLAN_FSTYPE_BLOCKACKREQ		0x8
+#define WLAN_FSTYPE_BLOCKACK  		0x9
+#define WLAN_FSTYPE_PSPOLL		0x0a
+#define WLAN_FSTYPE_RTS			0x0b
+#define WLAN_FSTYPE_CTS			0x0c
+#define WLAN_FSTYPE_ACK			0x0d
+#define WLAN_FSTYPE_CFEND		0x0e
+#define WLAN_FSTYPE_CFENDCFACK		0x0f
+
+/* Data */
+#define WLAN_FSTYPE_DATAONLY		0x00
+#define WLAN_FSTYPE_DATA_CFACK		0x01
+#define WLAN_FSTYPE_DATA_CFPOLL		0x02
+#define WLAN_FSTYPE_DATA_CFACK_CFPOLL	0x03
+#define WLAN_FSTYPE_NULL		0x04
+#define WLAN_FSTYPE_CFACK		0x05
+#define WLAN_FSTYPE_CFPOLL		0x06
+#define WLAN_FSTYPE_CFACK_CFPOLL	0x07
+
+
+/*================================================================*/
+/* Macros */
+
+/*--- FC Macros ----------------------------------------------*/
+/* Macros to get/set the bitfields of the Frame Control Field */
+/*  GET_FC_??? - takes the host byte-order value of an FC     */
+/*               and retrieves the value of one of the        */
+/*               bitfields and moves that value so its lsb is */
+/*               in bit 0.                                    */
+/*  SET_FC_??? - takes a host order value for one of the FC   */
+/*               bitfields and moves it to the proper bit     */
+/*               location for ORing into a host order FC.     */
+/*               To send the FC produced from SET_FC_???,     */
+/*               one must put the bytes in IEEE order.        */
+/*  e.g.                                                      */
+/*     printf("the frame subtype is %x",                      */
+/*                 GET_FC_FTYPE( ieee2host( rx.fc )))         */
+/*                                                            */
+/*     tx.fc = host2ieee( SET_FC_FTYPE(WLAN_FTYP_CTL) |       */
+/*                        SET_FC_FSTYPE(WLAN_FSTYPE_RTS) );   */
+/*------------------------------------------------------------*/
+
+#define WLAN_GET_FC_PVER(n)	 (((UINT16)(n)) & (BIT0 | BIT1))
+#define WLAN_GET_FC_FTYPE(n)	((((UINT16)(n)) & (BIT2 | BIT3)) >> 2)
+#define WLAN_GET_FC_FSTYPE(n)	((((UINT16)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
+#define WLAN_GET_FC_TODS(n) 	((((UINT16)(n)) & (BIT8)) >> 8)
+#define WLAN_GET_FC_FROMDS(n)	((((UINT16)(n)) & (BIT9)) >> 9)
+#define WLAN_GET_FC_MOREFRAG(n) ((((UINT16)(n)) & (BIT10)) >> 10)
+#define WLAN_GET_FC_RETRY(n)	((((UINT16)(n)) & (BIT11)) >> 11)
+#define WLAN_GET_FC_PWRMGT(n)	((((UINT16)(n)) & (BIT12)) >> 12)
+#define WLAN_GET_FC_MOREDATA(n) ((((UINT16)(n)) & (BIT13)) >> 13)
+#define WLAN_GET_FC_ISWEP(n)	((((UINT16)(n)) & (BIT14)) >> 14)
+#define WLAN_GET_FC_ORDER(n)	((((UINT16)(n)) & (BIT15)) >> 15)
+
+#define WLAN_SET_FC_PVER(n)	((UINT16)(n))
+#define WLAN_SET_FC_FTYPE(n)	(((UINT16)(n)) << 2)
+#define WLAN_SET_FC_FSTYPE(n)	(((UINT16)(n)) << 4)
+#define WLAN_SET_FC_TODS(n) 	(((UINT16)(n)) << 8)
+#define WLAN_SET_FC_FROMDS(n)	(((UINT16)(n)) << 9)
+#define WLAN_SET_FC_MOREFRAG(n) (((UINT16)(n)) << 10)
+#define WLAN_SET_FC_RETRY(n)	(((UINT16)(n)) << 11)
+#define WLAN_SET_FC_PWRMGT(n)	(((UINT16)(n)) << 12)
+#define WLAN_SET_FC_MOREDATA(n) (((UINT16)(n)) << 13)
+#define WLAN_SET_FC_ISWEP(n)	(((UINT16)(n)) << 14)
+#define WLAN_SET_FC_ORDER(n)	(((UINT16)(n)) << 15)
+
+/*--- Duration Macros ----------------------------------------*/
+/* Macros to get/set the bitfields of the Duration Field      */
+/*  - the duration value is only valid when bit15 is zero     */
+/*  - the firmware handles these values, so I'm not going     */
+/*    these macros right now.                                 */
+/*------------------------------------------------------------*/
+
+/*--- Sequence Control  Macros -------------------------------*/
+/* Macros to get/set the bitfields of the Sequence Control    */
+/* Field.                                                     */
+/*------------------------------------------------------------*/
+#define WLAN_GET_SEQ_FRGNUM(n) (((UINT16)(n)) & (BIT0|BIT1|BIT2|BIT3))
+#define WLAN_GET_SEQ_SEQNUM(n) ((((UINT16)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) 
+
+/*--- Data ptr macro -----------------------------------------*/
+/* Creates a UINT8* to the data portion of a frame            */
+/* Assumes you're passing in a ptr to the beginning of the hdr*/
+/*------------------------------------------------------------*/
+#define WLAN_HDR_A3_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A3_LEN)
+#define WLAN_HDR_A4_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A4_LEN)
+
+#define DOT11_RATE5_ISBASIC_GET(r)     (((UINT8)(r)) & BIT7)
+
+/*================================================================*/
+/* Types */
+
+/* BSS Timestamp */
+typedef UINT8 wlan_bss_ts_t[WLAN_BSS_TS_LEN];
+
+/* Generic 802.11 Header types */
+
+typedef struct p80211_hdr_a3
+{
+	UINT16	fc;
+	UINT16	dur;
+	UINT8	a1[WLAN_ADDR_LEN];
+	UINT8	a2[WLAN_ADDR_LEN];
+	UINT8	a3[WLAN_ADDR_LEN];
+	UINT16	seq;
+} __WLAN_ATTRIB_PACK__ p80211_hdr_a3_t;
+
+typedef struct p80211_hdr_a4
+{
+	UINT16	fc;
+	UINT16	dur;
+	UINT8	a1[WLAN_ADDR_LEN];
+	UINT8	a2[WLAN_ADDR_LEN];
+	UINT8	a3[WLAN_ADDR_LEN];
+	UINT16	seq;
+	UINT8	a4[WLAN_ADDR_LEN];
+} __WLAN_ATTRIB_PACK__ p80211_hdr_a4_t;
+
+typedef union p80211_hdr
+{
+	p80211_hdr_a3_t		a3;
+	p80211_hdr_a4_t		a4;
+} __WLAN_ATTRIB_PACK__ p80211_hdr_t;
+
+
+/*================================================================*/
+/* Extern Declarations */
+
+
+/*================================================================*/
+/* Function Declarations */
+
+/* Frame and header lenght macros */
+
+#define WLAN_CTL_FRAMELEN(fstype) (\
+	(fstype) == WLAN_FSTYPE_BLOCKACKREQ	? 24 : \
+	(fstype) == WLAN_FSTYPE_BLOCKACK   	? 152 : \
+	(fstype) == WLAN_FSTYPE_PSPOLL		? 20 : \
+	(fstype) == WLAN_FSTYPE_RTS		? 20 : \
+	(fstype) == WLAN_FSTYPE_CTS		? 14 : \
+	(fstype) == WLAN_FSTYPE_ACK		? 14 : \
+	(fstype) == WLAN_FSTYPE_CFEND		? 20 : \
+	(fstype) == WLAN_FSTYPE_CFENDCFACK	? 20 : 4)
+
+#define WLAN_FCS_LEN			4
+
+/* ftcl in HOST order */
+inline static UINT16 p80211_headerlen(UINT16 fctl)
+{
+	UINT16 hdrlen = 0;
+
+	switch ( WLAN_GET_FC_FTYPE(fctl) ) {
+	case WLAN_FTYPE_MGMT:
+		hdrlen = WLAN_HDR_A3_LEN;
+		break;
+	case WLAN_FTYPE_DATA:
+		hdrlen = WLAN_HDR_A3_LEN;
+		if ( WLAN_GET_FC_TODS(fctl) && WLAN_GET_FC_FROMDS(fctl) ) {
+			hdrlen += WLAN_ADDR_LEN;
+		}
+		break;
+	case WLAN_FTYPE_CTL:
+		hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) - 
+			WLAN_FCS_LEN; 
+		break;
+	default:
+		hdrlen = WLAN_HDR_A3_LEN;
+	}
+	
+	return hdrlen;
+}
+
+#endif /* _P80211HDR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.c
new file mode 100644
index 0000000..d6da3c5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.c
@@ -0,0 +1,1161 @@
+/*
+ * Copyright (c) 2010 Andrei Faur <da3drus at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+#include <mii.h>
+#include "pcnet32.h"
+
+static u16 pcnet32_wio_read_csr ( unsigned long addr, int index )
+{
+	outw ( index, addr + PCNET32_WIO_RAP );
+	return inw ( addr + PCNET32_WIO_RDP );
+}
+
+static void pcnet32_wio_write_csr ( unsigned long addr, int index, u16 val )
+{
+	outw ( index, addr + PCNET32_WIO_RAP );
+	outw ( val, addr + PCNET32_WIO_RDP );
+}
+
+static u16 pcnet32_wio_read_bcr ( unsigned long addr, int index )
+{
+	outw ( index, addr + PCNET32_WIO_RAP );
+	return inw ( addr + PCNET32_WIO_BDP );
+}
+
+static void pcnet32_wio_write_bcr ( unsigned long addr, int index, u16 val )
+{
+	outw ( index, addr + PCNET32_WIO_RAP );
+	outw ( val, addr + PCNET32_WIO_BDP );
+}
+
+static u16 pcnet32_wio_read_rap ( unsigned long addr )
+{
+	return inw ( addr + PCNET32_WIO_RAP );
+}
+
+static void pcnet32_wio_write_rap ( unsigned long addr , u16 val )
+{
+	outw ( val, addr + PCNET32_WIO_RAP );
+}
+
+static void pcnet32_wio_reset ( unsigned long addr )
+{
+	inw ( addr + PCNET32_WIO_RESET );
+}
+
+static int pcnet32_wio_check ( unsigned long addr )
+{
+	outw ( 88, addr + PCNET32_WIO_RAP );
+	return ( inw ( addr + PCNET32_WIO_RAP ) == 88 );
+}
+
+static struct pcnet32_access pcnet32_wio = {
+	.read_csr	= pcnet32_wio_read_csr,
+	.write_csr	= pcnet32_wio_write_csr,
+	.read_bcr	= pcnet32_wio_read_bcr,
+	.write_bcr	= pcnet32_wio_write_bcr,
+	.read_rap	= pcnet32_wio_read_rap,
+	.write_rap	= pcnet32_wio_write_rap,
+	.reset		= pcnet32_wio_reset,
+};
+
+static u16 pcnet32_dwio_read_csr ( unsigned long addr, int index )
+{
+	outl ( index, addr + PCNET32_DWIO_RAP );
+	return ( inl ( addr + PCNET32_DWIO_RDP ) & 0xffff );
+}
+
+static void pcnet32_dwio_write_csr ( unsigned long addr, int index, u16 val )
+{
+	outl ( index, addr + PCNET32_DWIO_RAP );
+	outl ( val, addr + PCNET32_DWIO_RDP );
+}
+
+static u16 pcnet32_dwio_read_bcr ( unsigned long addr, int index )
+{
+	outl ( index, addr + PCNET32_DWIO_RAP );
+	return ( inl ( addr + PCNET32_DWIO_BDP ) & 0xffff );
+}
+
+static void pcnet32_dwio_write_bcr ( unsigned long addr, int index, u16 val )
+{
+	outl ( index, addr + PCNET32_DWIO_RAP );
+	outl ( val, addr + PCNET32_DWIO_BDP );
+}
+
+static u16 pcnet32_dwio_read_rap ( unsigned long addr )
+{
+	return ( inl ( addr + PCNET32_DWIO_RAP ) & 0xffff );
+}
+
+static void pcnet32_dwio_write_rap ( unsigned long addr , u16 val )
+{
+	outl ( val, addr + PCNET32_DWIO_RAP );
+}
+
+static void pcnet32_dwio_reset ( unsigned long addr )
+{
+	inl ( addr + PCNET32_DWIO_RESET );
+}
+
+static int pcnet32_dwio_check ( unsigned long addr )
+{
+	outl ( 88, addr + PCNET32_DWIO_RAP );
+	return ( ( inl ( addr + PCNET32_DWIO_RAP ) & 0xffff ) == 88 );
+}
+
+
+static struct pcnet32_access pcnet32_dwio = {
+	.read_csr	= pcnet32_dwio_read_csr,
+	.write_csr	= pcnet32_dwio_write_csr,
+	.read_bcr	= pcnet32_dwio_read_bcr,
+	.write_bcr	= pcnet32_dwio_write_bcr,
+	.read_rap	= pcnet32_dwio_read_rap,
+	.write_rap	= pcnet32_dwio_write_rap,
+	.reset		= pcnet32_dwio_reset,
+};
+
+static int
+pcnet32_mdio_read ( struct net_device *netdev, int phy, int reg )
+{
+	struct pcnet32_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	u16 val_out;
+
+	if ( ! priv->mii )
+		return 0;
+
+	/* First, select PHY chip and the register we want to read */
+	priv->a->write_bcr ( ioaddr, 33,
+		( ( phy & 0x1f ) << 5 ) | ( reg & 0x1f ) );
+
+	/* Read the selected register's value */
+	val_out = priv->a->read_bcr ( ioaddr, 34 );
+
+	return val_out;
+}
+
+static void
+__unused pcnet32_mdio_write ( struct net_device *netdev, int phy, int reg, int val )
+{
+	struct pcnet32_private *priv = netdev->priv;
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+
+	if ( ! priv->mii )
+		return;
+
+	/* First, select PHY chip and the register we want to write to */
+	priv->a->write_bcr ( ioaddr, 33,
+		( ( phy & 0x1f ) << 5 ) | ( reg & 0x1f ) );
+
+	/* Write val to the selected register */
+	priv->a->write_bcr ( ioaddr, 34, val );
+}
+
+
+/**
+ * pcnet32_refill_rx_ring - Allocates iobufs for every Rx descriptor
+ * that doesn't have one and isn't in use by the hardware
+ *
+ * @v priv	Driver private structure
+ */
+static void
+pcnet32_refill_rx_ring ( struct pcnet32_private *priv )
+{
+	struct pcnet32_rx_desc *rx_curr_desc;
+	u16 status;
+	int i;
+
+	DBGP ( "pcnet32_refill_rx_ring\n" );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		rx_curr_desc = priv->rx_base + i;
+
+		status = le16_to_cpu ( rx_curr_desc->status );
+
+		/* Don't touch descriptors owned by the hardware */
+		if ( status & DescOwn )
+			continue;
+
+		/* Descriptors with iobufs still need to be processed */
+		if ( priv->rx_iobuf[i] != NULL )
+			continue;
+
+		/* If alloc_iob fails, try again later (next poll) */
+		if ( ! ( priv->rx_iobuf[i] = alloc_iob ( PKT_BUF_SIZE ) ) ) {
+			DBG ( "Refill rx ring failed\n" );
+			break;
+		}
+
+		rx_curr_desc->base =
+			cpu_to_le32 ( virt_to_bus ( priv->rx_iobuf[i]->data ) );
+		rx_curr_desc->buf_length = cpu_to_le16 ( -PKT_BUF_SIZE );
+		rx_curr_desc->msg_length = rx_curr_desc->reserved = 0;
+
+		/* Owner changes after the other status fields are set */
+		wmb();
+		rx_curr_desc->status = cpu_to_le16 ( DescOwn );
+	}
+
+}
+
+/**
+ * pcnet32_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int
+pcnet32_setup_rx_resources ( struct pcnet32_private *priv )
+{
+	DBGP ( "pcnet32_setup_rx_resources\n" );
+
+	priv->rx_base = malloc_dma ( RX_RING_BYTES, RX_RING_ALIGN );
+
+	DBG ( "priv->rx_base = %#08lx\n", virt_to_bus ( priv->rx_base ) );
+
+	if ( ! priv->rx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( priv->rx_base, 0, RX_RING_BYTES );
+
+	pcnet32_refill_rx_ring ( priv );
+
+	priv->rx_curr = 0;
+
+	return 0;
+}
+
+static void
+pcnet32_free_rx_resources ( struct pcnet32_private *priv )
+{
+	int i;
+
+	DBGP ( "pcnet32_free_rx_resources\n" );
+
+	free_dma ( priv->rx_base, RX_RING_BYTES );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		free_iob ( priv->rx_iobuf[i] );
+		priv->rx_iobuf[i] = NULL;
+	}
+}
+
+/**
+ * pcnet32_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int
+pcnet32_setup_tx_resources ( struct pcnet32_private *priv )
+{
+	DBGP ( "pcnet32_setup_tx_resources\n" );
+
+	priv->tx_base = malloc_dma ( TX_RING_BYTES, TX_RING_ALIGN );
+
+	if ( ! priv->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( priv->tx_base, 0, TX_RING_BYTES );
+
+	DBG ( "priv->tx_base = %#08lx\n", virt_to_bus ( priv->tx_base ) );
+
+	priv->tx_curr = 0;
+	priv->tx_fill_ctr = 0;
+	priv->tx_tail = 0;
+
+	return 0;
+}
+
+static void
+pcnet32_free_tx_resources ( struct pcnet32_private *priv )
+{
+	DBGP ( "pcnet32_free_tx_resources\n" );
+
+	free_dma ( priv->tx_base, TX_RING_BYTES );
+}
+
+static int
+pcnet32_chip_detect ( struct pcnet32_private *priv )
+{
+	int fdx, mii, fset;
+	int media;
+	int rc;
+	unsigned long ioaddr;
+	struct pcnet32_access *a;
+	int chip_version;
+	char *chipname;
+
+	ioaddr = priv->pci_dev->ioaddr;
+	a = priv->a;
+
+	chip_version = a->read_csr ( ioaddr, 88 )
+		| ( a->read_csr ( ioaddr, 89 ) << 16 );
+
+	rc = -ENODEV;
+
+	DBG ( "PCnet chip version is 0x%X\n", chip_version );
+	if ( ( chip_version & 0xfff ) != 0x003 )
+		goto err_unsupported;
+
+	fdx = mii = fset = 0;
+	chip_version = ( chip_version >> 12 ) & 0xffff;
+
+	switch (chip_version) {
+	case 0x2420:
+		chipname = "PCnet/PCI 79C970";
+		break;
+	case 0x2430:
+		/* 970 gives the wrong chip id back */
+		chipname = "PCnet/PCI 79C970";
+		break;
+	case 0x2621:
+		chipname = "PCnet/PCI II 79C970A";
+		fdx = 1;
+		break;
+	case 0x2623:
+		chipname = "PCnet/FAST 79C971";
+		fdx = 1;
+		mii = 1;
+		fset = 1;
+		break;
+	case 0x2624:
+		chipname = "PCnet/FAST+ 79C972";
+		fdx = 1;
+		mii = 1;
+		fset = 1;
+		break;
+	case 0x2625:
+		chipname = "PCnet/FAST III 79C973";
+		fdx = 1;
+		mii = 1;
+		break;
+	case 0x2626:
+		chipname = "PCnet/Home 79C978";
+		fdx = 1;
+		/*
+		 * This is based on specs published at www.amd.com. This section
+		 * assumes that a NIC with a 79C978 wants to go into 1Mb HomePNA
+		 * mode. The 79C978 can also go into standard ethernet, and
+		 * there probably should be some sort of module option to select
+		 * the mode by which the card should operate
+		 */
+		/* switch to home wiring mode */
+		media = a->read_bcr(ioaddr, 49);
+
+		DBG ( "media reset to %#x.\n", media );
+		a->write_bcr(ioaddr, 49, media);
+		break;
+	case 0x2627:
+		chipname = "PCnet/FAST III 79C975";
+		fdx = 1;
+		mii = 1;
+		break;
+	case 0x2628:
+		chipname = "PCnet/PRO 79C976";
+		fdx = 1;
+		mii = 1;
+		break;
+	default:
+		chipname = "UNKNOWN";
+		DBG ( "PCnet version %#x, no PCnet32 chip.\n", chip_version );
+		goto err_unsupported;
+	}
+
+	DBG ( "PCnet chipname %s\n", chipname );
+
+	/*
+	 * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
+	 * starting until the packet is loaded. Strike one for reliability, lose
+	 * one for latency - although on PCI this isnt a big loss. Older chips
+	 * have FIFO's smaller than a packet, so you can't do this.
+	 * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.
+	 */
+	if (fset) {
+		a->write_bcr ( ioaddr, 18,
+			( a->read_bcr ( ioaddr, 18 ) | 0x0860 ) );
+		a->write_csr ( ioaddr, 80,
+			( a->read_csr ( ioaddr, 80 ) & 0x0C00) | 0x0C00 );
+	}
+
+	priv->full_duplex = fdx;
+	priv->mii = mii;
+
+	return 0;
+
+err_unsupported:
+	return rc;
+}
+
+/**
+ * pcnet32_set_ops - Determines the ops used to access the registers
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int
+pcnet32_set_ops ( struct pcnet32_private *priv )
+{
+	int rc;
+	unsigned long ioaddr;
+
+	ioaddr = priv->pci_dev->ioaddr;
+
+	/* Check if CSR0 has its default value and perform a write / read
+	   in the RAP register to see if it works. Based on these results
+	   determine what mode the NIC is in (WIO / DWIO)
+	 */
+	rc = -ENODEV;
+
+	if ( pcnet32_wio_read_csr ( ioaddr, 0 ) == 4 &&
+	     pcnet32_wio_check ( ioaddr ) ) {
+		priv->a = &pcnet32_wio;
+	} else {
+		pcnet32_dwio_reset ( ioaddr );
+		if ( pcnet32_dwio_read_csr ( ioaddr, 0 ) == 4 &&
+		     pcnet32_dwio_check ( ioaddr ) ) {
+			priv->a = &pcnet32_dwio;
+		} else {
+			goto err_unsupported;
+		}
+	}
+
+	return 0;
+
+err_unsupported:
+	return rc;
+}
+
+/**
+ * pcnet32_setup_init_block - setup the NICs initialization block
+ *
+ * @v priv	Driver private structure
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static void
+pcnet32_setup_init_block ( struct pcnet32_private *priv )
+{
+	int i;
+
+	/* Configure the network port based on what we've established so far */
+	priv->init_block.mode =
+		cpu_to_le16 ( ( priv->options & PCNET32_PORT_PORTSEL ) << 7 );
+
+	/* Setup RLEN and TLEN fields */
+	priv->init_block.tlen_rlen =
+		cpu_to_le16 ( ( PCNET32_LOG_RX_BUFFERS << 4 ) |
+			      ( PCNET32_LOG_TX_BUFFERS << 12 ) );
+
+	/* Fill in physical address */
+	for ( i = 0; i < ETH_ALEN; i++)
+		priv->init_block.phys_addr[i] = priv->netdev->hw_addr[i];
+
+	/* No multicasting scheme, accept everything */
+	priv->init_block.filter[0] = 0xffffffff;
+	priv->init_block.filter[1] = 0xffffffff;
+
+	priv->init_block.rx_ring =
+		cpu_to_le32 ( virt_to_bus ( priv->rx_base ) );
+	priv->init_block.tx_ring =
+		cpu_to_le32 ( virt_to_bus ( priv->tx_base ) );
+
+	/* Make sure all changes are visible */
+	wmb();
+}
+
+/**
+ * pcnet32_setup_probe_phy - go through all PHYs and see which one is present
+ *
+ * @v priv	Driver private structure
+ */
+static void
+pcnet32_setup_probe_phy ( struct pcnet32_private *priv )
+{
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	unsigned int phycount = 0;
+	int phy_id;
+	int i;
+
+	if ( priv->mii ) {
+		phy_id = ( ( priv->a->read_bcr ( ioaddr, 33 ) ) >> 5 ) & 0x1f;
+		for ( i = 0; i < PCNET32_MAX_PHYS; i++ ) {
+			unsigned short id1, id2;
+			id1 = pcnet32_mdio_read ( priv->netdev, i, MII_PHYSID1 );
+			if ( id1 == 0xffff )
+				continue;
+			id2 = pcnet32_mdio_read ( priv->netdev, i, MII_PHYSID2 );
+			if ( id2 == 0xffff )
+				continue;
+			if ( i == 31 && ( ( priv->chip_version + 1 ) & 0xfffe ) == 0x2624 )
+				continue;
+
+			phycount++;
+			phy_id = i;
+		}
+		priv->a->write_bcr ( ioaddr, 33, phy_id << 5 );
+		if ( phycount > 1 )
+			priv->options |= PCNET32_PORT_MII;
+	}
+}
+
+/**
+ * pcnet32_setup_mac_addr - check for inconsistency between CSR12-14
+ * and PROM addresses
+ *
+ * @v priv	Driver private structure
+ */
+static int
+pcnet32_setup_mac_addr ( struct pcnet32_private *priv )
+{
+	int i;
+	u8 promaddr[ETH_ALEN];
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+
+	/* In most chips, after a chip reset, the ethernet address is read from
+	 * the station address PROM at the base address and programmed into the
+	 * "Physical Address Registers" CSR12-14.
+	 * As a precautionary measure, we read the PROM values and complain if
+	 * they disagree with the CSRs.  If they miscompare, and the PROM addr
+	 * is valid, then the PROM addr is used.
+	 */
+	for ( i = 0; i < 3; i++ ) {
+		unsigned int val;
+		val = priv->a->read_csr ( ioaddr, i + 12 ) & 0x0ffff;
+		/* There may be endianness issues here. */
+		priv->netdev->hw_addr[2 * i] = val & 0x0ff;
+		priv->netdev->hw_addr[2 * i + 1] = ( val >> 8 ) & 0x0ff;
+	}
+
+	for ( i = 0; i < ETH_ALEN; i++ )
+		promaddr[i] = inb ( ioaddr + i );
+
+	if ( memcmp ( promaddr, priv->netdev->hw_addr, ETH_ALEN ) ||
+	     ! is_valid_ether_addr ( priv->netdev->hw_addr ) ) {
+		if ( is_valid_ether_addr ( promaddr ) ) {
+			DBG ( "CSR address is invalid, using PROM addr\n" );
+			memcpy ( priv->netdev->hw_addr, promaddr, ETH_ALEN );
+		}
+	}
+
+	/* If ethernet address is not valid, return error */
+	if ( ! is_valid_ether_addr ( priv->netdev->hw_addr ) )
+		return -EADDRNOTAVAIL;
+
+	return 0;
+}
+
+/**
+ * pcnet32_setup_if_duplex - Sets the NICs used interface and duplex mode
+ *
+ * @v priv	Driver private structure
+ */
+static void
+pcnet32_setup_if_duplex ( struct pcnet32_private *priv )
+{
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	u16 val;
+
+	/* Set/Reset autoselect bit */
+	val = priv->a->read_bcr ( ioaddr, 2 ) & ~2;
+	if ( priv->options & PCNET32_PORT_ASEL )
+		val |= 2;
+	priv->a->write_bcr ( ioaddr, 2, val );
+
+	/* Handle full duplex setting */
+	if ( priv->full_duplex ) {
+		val = priv->a->read_bcr ( ioaddr, 9 ) & ~3;
+		if ( priv->options & PCNET32_PORT_FD ) {
+			val |= 1;
+			if ( priv->options == ( PCNET32_PORT_FD | PCNET32_PORT_AUI ) )
+				val |= 2;
+		} else if ( priv->options & PCNET32_PORT_ASEL ) {
+			/* Workaround of xSeries 250, on for 79C975 only */
+			if ( priv->chip_version == 0x2627 )
+				val |= 3;
+		}
+		priv->a->write_bcr ( ioaddr, 9, val );
+	}
+
+	/* Set/Reset GPSI bit in test register */
+	val = priv->a->read_csr ( ioaddr, 124 ) & ~0x10;
+	if ( ( priv->options & PCNET32_PORT_PORTSEL ) == PCNET32_PORT_GPSI )
+		val |= 0x10;
+	priv->a->write_bcr ( ioaddr, 124, val );
+
+	/* Allied Telesyn AT are 100Mbit only and do not negotiate */
+	u16 subsys_vend_id, subsys_dev_id;
+	pci_read_config_word ( priv->pci_dev,
+			       PCI_SUBSYSTEM_VENDOR_ID,
+			       &subsys_vend_id );
+	pci_read_config_word ( priv->pci_dev,
+			       PCI_SUBSYSTEM_ID,
+			       &subsys_dev_id );
+	if ( subsys_vend_id == PCI_VENDOR_ID_AT &&
+	     ( ( subsys_dev_id == PCI_SUBDEVICE_ID_AT_2700FX ) ||
+	       ( subsys_dev_id == PCI_SUBDEVICE_ID_AT_2701FX ) ) ) {
+		priv->options = PCNET32_PORT_FD | PCNET32_PORT_100;
+	}
+
+	if ( priv->mii && ! ( priv->options & PCNET32_PORT_ASEL ) ) {
+		/* Disable Auto Negotiation, set 10Mbps, HD */
+		val = priv->a->read_bcr ( ioaddr, 32 ) & ~0x38;
+		if ( priv->options & PCNET32_PORT_FD )
+			val |= 0x10;
+		if ( priv->options & PCNET32_PORT_100 )
+			val |= 0x08;
+		priv->a->write_bcr ( ioaddr, 32, val );
+	} else if ( priv->options & PCNET32_PORT_ASEL ) {
+		/* 79C970 chips do not have the BCR32 register */
+		if ( ( priv->chip_version != 0x2420 ) &&
+		     ( priv->chip_version != 0x2621 ) ) {
+			/* Enable Auto Negotiation, setup, disable FD */
+			val = priv->a->read_bcr ( ioaddr, 32 ) & ~0x98;
+			val |= 0x20;
+			priv->a->write_bcr ( ioaddr, 32, val );
+		}
+	}
+}
+
+/**
+ * pcnet32_hw_start - Starts up the NIC
+ *
+ * @v priv	Driver private structure
+ */
+static void
+pcnet32_hw_start ( struct pcnet32_private *priv )
+{
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	int i;
+
+	/* Begin initialization procedure */
+	priv->a->write_csr ( ioaddr, 0, Init );
+
+	/* Wait for the initialization to be done */
+	i = 0;
+	while ( i++ < 100 )
+		if ( priv->a->read_csr ( ioaddr, 0 ) & InitDone )
+			break;
+
+	/* Start the chip */
+	priv->a->write_csr ( ioaddr, 0, Strt );
+}
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev	Network device
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ **/
+static int
+pcnet32_open ( struct net_device *netdev )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	int rc;
+	u16 val;
+
+	/* Setup TX and RX descriptors */
+	if ( ( rc = pcnet32_setup_tx_resources ( priv ) ) != 0 ) {
+		DBG ( "Error setting up TX resources\n" );
+		goto err_setup_tx;
+	}
+
+	if ( ( rc = pcnet32_setup_rx_resources ( priv ) ) != 0 ) {
+		DBG ( "Error setting up RX resources\n" );
+		goto err_setup_rx;
+	}
+
+	/* Reset the chip */
+	priv->a->reset ( ioaddr );
+
+	/* Switch pcnet32 to 32bit mode */
+	priv->a->write_bcr ( ioaddr, 20, PCNET32_SWSTYLE_PCNET32 );
+
+	/* Setup the interface and duplex mode */
+	pcnet32_setup_if_duplex ( priv );
+
+	/* Disable interrupts */
+	val = priv->a->read_csr ( ioaddr, 3 );
+	val |= BablMask | MissFrameMask | RxIntMask | TxIntMask | InitDoneMask;
+	priv->a->write_csr ( ioaddr, 3, val );
+
+	/* Setup initialization block */
+	pcnet32_setup_init_block ( priv );
+
+	/* Fill in the address of the initialization block */
+	priv->a->write_csr ( ioaddr, 1,
+		( virt_to_bus ( &priv->init_block ) ) & 0xffff );
+	priv->a->write_csr ( ioaddr, 2,
+		( virt_to_bus ( &priv->init_block ) ) >> 16 );
+
+	/* Enable Auto-Pad, disable interrupts */
+	priv->a->write_csr ( ioaddr, 4, 0x0915 );
+
+	pcnet32_hw_start ( priv );
+
+	return 0;
+
+err_setup_rx:
+	pcnet32_free_tx_resources ( priv );
+err_setup_tx:
+	priv->a->reset( priv->pci_dev->ioaddr );
+	return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc	Returns 0 on success, negative on failure
+ */
+static int
+pcnet32_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	uint32_t tx_len = iob_len ( iobuf );
+	struct pcnet32_tx_desc *tx_curr_desc;
+
+	DBGP ( "pcnet32_transmit\n" );
+
+	if ( priv->tx_fill_ctr == TX_RING_SIZE ) {
+		DBG ( "Tx overflow\n" );
+		return -ENOTSUP;
+	}
+
+	priv->tx_iobuf[priv->tx_curr] = iobuf;
+
+	tx_curr_desc = priv->tx_base + priv->tx_curr;
+
+	/* Configure current descriptor to transmit packet */
+	tx_curr_desc->length = cpu_to_le16 ( -tx_len );
+	tx_curr_desc->misc = 0x00000000;
+	tx_curr_desc->base = cpu_to_le32 ( virt_to_bus ( iobuf->data ) );
+
+	/* Owner changes after the other status fields are set */
+	wmb();
+	tx_curr_desc->status =
+		cpu_to_le16 ( DescOwn | StartOfPacket | EndOfPacket );
+
+	/* Trigger an immediate send poll */
+	priv->a->write_csr ( ioaddr, 0,
+		( priv->irq_enabled ? IntEnable : 0 ) | TxDemand );
+
+	/* Point to the next free descriptor */
+	priv->tx_curr = ( priv->tx_curr + 1 ) % TX_RING_SIZE;
+
+	/* Increment number of tx descriptors in use */
+	priv->tx_fill_ctr++;
+
+	return 0;
+}
+
+/**
+ * pcnet32_process_tx_packets - Checks for successfully sent packets,
+ * reports them to iPXE with netdev_tx_complete()
+ *
+ * @v netdev	Network device
+ */
+static void
+pcnet32_process_tx_packets ( struct net_device *netdev )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	struct pcnet32_tx_desc *tx_curr_desc;
+
+	DBGP ( "pcnet32_process_tx_packets\n" );
+
+	while ( priv->tx_tail != priv->tx_curr ) {
+		tx_curr_desc = priv->tx_base + priv->tx_tail;
+
+		u16 status = le16_to_cpu ( tx_curr_desc->status );
+
+		DBG ( "Before OWN bit check, status: %#08x\n", status );
+
+		/* Skip this descriptor if hardware still owns it */
+		if ( status & DescOwn )
+			break;
+
+		DBG ( "Transmitted packet.\n" );
+		DBG ( "priv->tx_fill_ctr= %d\n", priv->tx_fill_ctr );
+		DBG ( "priv->tx_tail	= %d\n", priv->tx_tail );
+		DBG ( "priv->tx_curr	= %d\n", priv->tx_curr );
+		DBG ( "tx_curr_desc	= %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+
+		/* This packet is ready for completion */
+		netdev_tx_complete ( netdev, priv->tx_iobuf[priv->tx_tail]);
+
+		/* Clear the descriptor */
+		memset ( tx_curr_desc, 0, sizeof(*tx_curr_desc) );
+
+		/* Reduce the number of tx descriptors in use */
+		priv->tx_fill_ctr--;
+
+		/* Go to next available descriptor */
+		priv->tx_tail = ( priv->tx_tail + 1 ) % TX_RING_SIZE;
+	}
+}
+
+/**
+ * pcnet32_process_rx_packets - Checks for received packets, reports them
+ * to iPXE with netdev_rx() or netdev_rx_err() if there was an error receiving
+ * the packet
+ *
+ * @v netdev	Network device
+ */
+static void
+pcnet32_process_rx_packets ( struct net_device *netdev )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	struct pcnet32_rx_desc *rx_curr_desc;
+	u16 status;
+	u32 len;
+	int i;
+
+	DBGP ( "pcnet32_process_rx_packets\n" );
+
+	for ( i = 0; i < RX_RING_SIZE; i++ ) {
+		rx_curr_desc = priv->rx_base + priv->rx_curr;
+
+		status = le16_to_cpu ( rx_curr_desc->status );
+		rmb();
+
+		DBG ( "Before OWN bit check, status: %#08x\n", status );
+
+		/* Skip this descriptor if hardware still owns it */
+		if ( status & DescOwn )
+			break;
+
+		/* We own the descriptor, but it has not been refilled yet */
+		if ( priv->rx_iobuf[priv->rx_curr] == NULL )
+			break;
+
+		DBG ( "Received packet.\n" );
+		DBG ( "priv->rx_curr	= %d\n", priv->rx_curr );
+		DBG ( "rx_len		= %d\n",
+		      ( le32_to_cpu ( rx_curr_desc->msg_length ) & 0xfff ) - 4 );
+		DBG ( "rx_curr_desc	= %#08lx\n",
+		      virt_to_bus ( rx_curr_desc ) );
+
+		/* Check ERR bit */
+		if ( status & 0x4000 ) {
+			netdev_rx_err ( netdev, priv->rx_iobuf[priv->rx_curr],
+					-EINVAL );
+			DBG ( "Corrupted packet received!\n");
+		} else {
+			/* Adjust size of the iobuf to reflect received data */
+			len = ( le32_to_cpu ( rx_curr_desc->msg_length ) & 0xfff ) - 4;
+			iob_put ( priv->rx_iobuf[priv->rx_curr], len );
+
+			/* Add this packet to the receive queue */
+			netdev_rx ( netdev, priv->rx_iobuf[priv->rx_curr] );
+		}
+
+		/* Invalidate iobuf and descriptor */
+		priv->rx_iobuf[priv->rx_curr] = NULL;
+		memset ( rx_curr_desc, 0, sizeof(*rx_curr_desc) );
+
+		/* Point to the next free descriptor */
+		priv->rx_curr = ( priv->rx_curr + 1 ) % RX_RING_SIZE;
+	}
+
+	/* Allocate new iobufs where needed */
+	pcnet32_refill_rx_ring ( priv );
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void
+pcnet32_poll ( struct net_device *netdev )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	u16 status;
+
+	DBGP ( "pcnet32_poll\n" );
+
+	status = priv->a->read_csr ( ioaddr, 0 );
+
+	/* Clear interrupts */
+	priv->a->write_csr ( ioaddr, 0, status );
+
+	DBG ( "pcnet32_poll: mask = %#04x, status = %#04x\n",
+		priv->a->read_csr ( ioaddr, 3 ), status );
+
+	/* Return when RINT or TINT are not set */
+	if ( ( status & 0x0500 ) == 0x0000 )
+		return;
+
+	/* Process transmitted packets */
+	pcnet32_process_tx_packets ( netdev );
+
+	/* Process received packets */
+	pcnet32_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev	network interface device structure
+ **/
+static void
+pcnet32_close ( struct net_device *netdev )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+
+	DBGP ( "pcnet32_close\n" );
+
+	/* Reset the chip */
+	pcnet32_wio_reset ( ioaddr );
+
+	/* Stop the PCNET32 - it occasionally polls memory if we don't */
+	priv->a->write_csr ( ioaddr, 0, Stop );
+
+	/* Switch back to 16bit mode to avoid problems with dumb
+	 * DOS packet driver after a warm reboot */
+	priv->a->write_bcr ( ioaddr, 20, PCNET32_SWSTYLE_LANCE );
+
+	pcnet32_free_rx_resources ( priv );
+	pcnet32_free_tx_resources ( priv );
+}
+
+static void pcnet32_irq_enable ( struct pcnet32_private *priv )
+{
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+	u16 val;
+
+	DBGP ( "pcnet32_irq_enable\n" );
+
+	/* Enable TINT and RINT masks */
+	val = priv->a->read_csr ( ioaddr, 3 );
+	val &= ~( RxIntMask | TxIntMask );
+	priv->a->write_csr ( ioaddr, 3, val );
+
+	/* Enable interrupts */
+	priv->a->write_csr ( ioaddr, 0, IntEnable );
+
+	priv->irq_enabled = 1;
+}
+
+static void pcnet32_irq_disable ( struct pcnet32_private *priv )
+{
+	unsigned long ioaddr = priv->pci_dev->ioaddr;
+
+	DBGP ( "pcnet32_irq_disable\n" );
+
+	priv->a->write_csr ( ioaddr, 0, 0x0000 );
+
+	priv->irq_enabled = 0;
+}
+
+/**
+ * irq - enable or disable interrupts
+ *
+ * @v netdev    network adapter
+ * @v action    requested interrupt action
+ **/
+static void
+pcnet32_irq ( struct net_device *netdev, int action )
+{
+	struct pcnet32_private *priv = netdev_priv ( netdev );
+
+	DBGP ( "pcnet32_irq\n" );
+
+	switch ( action ) {
+	case 0:
+		pcnet32_irq_disable ( priv );
+		break;
+	default:
+		pcnet32_irq_enable ( priv );
+		break;
+	}
+}
+
+static struct net_device_operations pcnet32_operations = {
+	.open		= pcnet32_open,
+	.transmit	= pcnet32_transmit,
+	.poll		= pcnet32_poll,
+	.close		= pcnet32_close,
+	.irq		= pcnet32_irq,
+};
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pdev	PCI device
+ * @v ent	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+static int
+pcnet32_probe ( struct pci_device *pdev )
+{
+	struct net_device *netdev;
+	struct pcnet32_private *priv;
+	unsigned long ioaddr;
+	int rc;
+
+	DBGP ( "pcnet32_probe\n" );
+
+	DBG ( "Found %s, vendor = %#04x, device = %#04x\n",
+		pdev->id->name, pdev->id->vendor, pdev->id->device );
+
+	/* Allocate our private data */
+	netdev = alloc_etherdev ( sizeof ( *priv ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+
+	/* Link our operations to the netdev struct */
+	netdev_init ( netdev, &pcnet32_operations );
+
+	/* Link the PCI device to the netdev struct */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Get a reference to our private data */
+	priv = netdev_priv ( netdev );
+
+	/* We'll need these set up for the rest of the routines */
+	priv->pci_dev = pdev;
+	priv->netdev = netdev;
+
+	ioaddr = pdev->ioaddr;
+
+	/* Only use irqs under UNDI */
+	priv->irq_enabled = 0;
+
+	/* Reset the chip */
+	pcnet32_wio_reset ( ioaddr );
+
+	if ( ( rc = pcnet32_set_ops ( priv ) ) != 0 ) {
+		DBG ( "Setting driver operations failed\n");
+		goto err_set_ops;
+	}
+
+	if ( ( rc = pcnet32_chip_detect ( priv ) ) != 0 ) {
+		DBG ( "pcnet32_chip_detect failed\n" );
+		goto err_chip_detect;
+	}
+
+	/* Enter bus mastering mode */
+	adjust_pci_device ( pdev );
+
+	/* Verify and get MAC address */
+	if ( ( rc = pcnet32_setup_mac_addr ( priv ) ) != 0 ) {
+		DBG ( "Setting MAC address failed\n" );
+		goto err_mac_addr;
+	}
+
+	DBG ( "IO Addr 0x%lX, MAC Addr %s\n", ioaddr,
+		eth_ntoa ( netdev->hw_addr ) );
+
+	priv->options = PCNET32_PORT_ASEL;
+
+	/* Detect special T1/E1 WAN card by checking for MAC address */
+	if ( netdev->hw_addr[0] == 0x00 &&
+	     netdev->hw_addr[1] == 0xE0 &&
+	     netdev->hw_addr[2] == 0x75 )
+		priv->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
+
+	/* Probe the PHY so we can check link state and speed */
+	pcnet32_setup_probe_phy ( priv );
+
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBG ( "Error registering netdev\n" );
+		goto err_register;
+	}
+
+	netdev_link_up ( netdev );
+
+	return 0;
+
+err_register:
+	netdev_put ( netdev );
+err_chip_detect:
+err_set_ops:
+err_alloc_etherdev:
+err_mac_addr:
+	return rc;
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ **/
+static void
+pcnet32_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	unsigned long ioaddr = pdev->ioaddr;
+
+	DBGP ( "pcnet32_remove\n" );
+
+	/* Reset the chip */
+	pcnet32_wio_reset ( ioaddr );
+
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id pcnet32_nics[] = {
+	PCI_ROM(0x1022, 0x2000, "pcnet32", "AMD PCnet/PCI", 0),
+	PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III", 0),
+	PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD PCnet/HomePNA", 0),
+};
+
+struct pci_driver pcnet32_driver __pci_driver = {
+	.ids		= pcnet32_nics,
+	.id_count	= ARRAY_SIZE ( pcnet32_nics ),
+	.probe		= pcnet32_probe,
+	.remove		= pcnet32_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.h
new file mode 100644
index 0000000..bd03cbc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/pcnet32.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2010 Andrei Faur <da3drus at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _PCNET32_H_
+#define _PCNET32_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Set default values to 16 Tx buffers and 32 Rx buffers.
+ */
+#define PCNET32_LOG_TX_BUFFERS		4
+#define PCNET32_LOG_RX_BUFFERS		5
+
+/* Maximum number of descriptor rings is 512 */
+#define PCNET32_LOG_MAX_TX_BUFFERS	9
+#define PCNET32_LOG_MAX_RX_BUFFERS	9
+
+#define TX_RING_SIZE		( 1 << ( PCNET32_LOG_TX_BUFFERS ) )
+#define TX_MAX_RING_SIZE	( 1 << ( PCNET32_LOG_MAX_TX_BUFFERS ) )
+
+#define RX_RING_SIZE		( 1 << ( PCNET32_LOG_RX_BUFFERS ) )
+#define RX_MAX_RING_SIZE	( 1 << ( PCNET32_LOG_MAX_RX_BUFFERS ) )
+
+#define RX_RING_BYTES		( RX_RING_SIZE * sizeof(struct pcnet32_rx_desc ) )
+#define TX_RING_BYTES		( TX_RING_SIZE * sizeof(struct pcnet32_tx_desc ) )
+
+#define PKT_BUF_SIZE	1536
+
+#define RX_RING_ALIGN		16
+#define TX_RING_ALIGN		16
+
+#define INIT_BLOCK_ALIGN	32
+
+#define PCNET32_WIO_RDP		0x10
+#define PCNET32_WIO_RAP		0x12
+#define PCNET32_WIO_RESET	0x14
+#define PCNET32_WIO_BDP		0x16
+
+#define PCNET32_DWIO_RDP	0x10
+#define PCNET32_DWIO_RAP	0x14
+#define PCNET32_DWIO_RESET	0x18
+#define PCNET32_DWIO_BDP	0x1C
+
+#define PCNET32_PORT_AUI	0x00
+#define PCNET32_PORT_10BT	0x01
+#define PCNET32_PORT_GPSI	0x02
+#define PCNET32_PORT_MII	0x03
+
+#define PCNET32_PORT_PORTSEL	0x03
+#define PCNET32_PORT_ASEL	0x04
+#define PCNET32_PORT_100	0x40
+#define PCNET32_PORT_FD		0x80
+
+#define PCNET32_SWSTYLE_LANCE	0x00
+#define PCNET32_SWSTYLE_ILACC	0x01
+#define PCNET32_SWSTYLE_PCNET32	0x02
+
+#define PCNET32_MAX_PHYS	32
+
+#ifndef PCI_VENDOR_ID_AT
+#define PCI_VENDOR_ID_AT	0x1259
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_AT_2700FX
+#define PCI_SUBDEVICE_ID_AT_2700FX	0x2701
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_AT_2701FX
+#define PCI_SUBDEVICE_ID_AT_2701FX	0x2703
+#endif
+
+struct pcnet32_rx_desc {
+	u32 base;
+	s16 buf_length;
+	s16 status;
+	u32 msg_length;
+	u32 reserved;
+};
+
+struct pcnet32_tx_desc {
+	u32 base;
+	s16 length;
+	s16 status;
+	u32 misc;
+	u32 reserved;
+};
+
+struct pcnet32_init_block {
+	u16 mode;
+	u16 tlen_rlen;
+	u8 phys_addr[6];
+	u16 reserved;
+	u32 filter[2];
+	u32 rx_ring;
+	u32 tx_ring;
+};
+
+struct pcnet32_access {
+	u16 ( *read_csr ) ( unsigned long, int );
+	void ( *write_csr ) ( unsigned long, int, u16 );
+	u16 ( *read_bcr ) ( unsigned long, int );
+	void ( *write_bcr ) ( unsigned long, int, u16 );
+	u16 ( *read_rap ) ( unsigned long );
+	void ( *write_rap ) ( unsigned long, u16 );
+	void ( *reset ) ( unsigned long );
+};
+
+struct pcnet32_private {
+	struct pcnet32_init_block init_block __attribute__((aligned(32)));
+	struct pci_device *pci_dev;
+	struct net_device *netdev;
+
+	struct io_buffer *rx_iobuf[RX_RING_SIZE];
+	struct io_buffer *tx_iobuf[TX_RING_SIZE];
+
+	struct pcnet32_rx_desc *rx_base;
+	struct pcnet32_tx_desc *tx_base;
+	uint32_t rx_curr;
+	uint32_t tx_curr;
+	uint32_t tx_tail;
+	uint32_t tx_fill_ctr;
+
+	struct pcnet32_access *a;
+	int options;
+	unsigned int	mii:1,
+			full_duplex:1;
+
+	unsigned short chip_version;
+
+	char irq_enabled;
+};
+
+enum pcnet32_desc_status_bit {
+	DescOwn		= (1 << 15),
+	StartOfPacket	= (1 << 9),
+	EndOfPacket	= (1 << 8)
+};
+
+enum pcnet32_register_content {
+	/* CSR0 bits - Controller status register */
+	RxInt		= (1 << 10),
+	TxInt		= (1 << 9),
+	InitDone	= (1 << 8),
+	IntFlag		= (1 << 7),
+	IntEnable	= (1 << 6),
+	TxDemand	= (1 << 3),
+	Stop		= (1 << 2),
+	Strt		= (1 << 1),
+	Init		= (1 << 0),
+
+	/* CSR3 bits - Controller status register */
+	BablMask	= (1 << 14),
+	MissFrameMask	= (1 << 12),
+	MemErrMask	= (1 << 11),
+	RxIntMask	= (1 << 10),
+	TxIntMask	= (1 << 9),
+	InitDoneMask	= (1 << 8)
+
+};
+
+#endif /* _PCNET32_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nx_bitops.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
new file mode 100644
index 0000000..4068632
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
@@ -0,0 +1,194 @@
+#ifndef _NX_BITOPS_H
+#define _NX_BITOPS_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * NetXen bit operations
+ *
+ */
+
+/** Datatype used to represent a bit in the pseudo-structures */
+typedef unsigned char pseudo_bit_t;
+
+/**
+ * Wrapper structure for pseudo_bit_t structures
+ *
+ * This structure provides a wrapper around pseudo_bit_t structures.
+ * It has the correct size, and also encapsulates type information
+ * about the underlying pseudo_bit_t-based structure, which allows the
+ * NX_FILL etc. macros to work without requiring explicit type
+ * information.
+ */
+#define NX_PSEUDO_BIT_STRUCT( _structure )				     \
+	union {								     \
+		uint8_t bytes[ sizeof ( _structure ) / 8 ];		     \
+		uint64_t qwords[ sizeof ( _structure ) / 64 ];		     \
+		_structure *dummy[0];					     \
+	} u;
+
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
+#define NX_PSEUDO_STRUCT( _ptr )					     \
+	typeof ( *((_ptr)->u.dummy[0]) )
+
+/** Bit offset of a field within a pseudo_bit_t structure */
+#define NX_BIT_OFFSET( _ptr, _field )					     \
+	offsetof ( NX_PSEUDO_STRUCT ( _ptr ), _field )
+
+/** Bit width of a field within a pseudo_bit_t structure */
+#define NX_BIT_WIDTH( _ptr, _field )					     \
+	sizeof ( ( ( NX_PSEUDO_STRUCT ( _ptr ) * ) NULL )->_field )
+
+/** Qword offset of a field within a pseudo_bit_t structure */
+#define NX_QWORD_OFFSET( _ptr, _field )					     \
+	( NX_BIT_OFFSET ( _ptr, _field ) / 64 )
+
+/** Qword bit offset of a field within a pseudo_bit_t structure
+ *
+ * Yes, using mod-64 would work, but would lose the check for the
+ * error of specifying a mismatched field name and qword index.
+ */
+#define NX_QWORD_BIT_OFFSET( _ptr, _index, _field )			     \
+	( NX_BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
+
+/** Bit mask for a field within a pseudo_bit_t structure */
+#define NX_BIT_MASK( _ptr, _field )					     \
+	( ( ~( ( uint64_t ) 0 ) ) >>					     \
+	  ( 64 - NX_BIT_WIDTH ( _ptr, _field ) ) )
+
+/*
+ * Assemble native-endian qword from named fields and values
+ *
+ */
+
+#define NX_ASSEMBLE_1( _ptr, _index, _field, _value )			     \
+	( ( ( uint64_t) (_value) ) <<					     \
+	  NX_QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define NX_ASSEMBLE_2( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_ASSEMBLE_3( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_ASSEMBLE_4( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_ASSEMBLE_5( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_ASSEMBLE_6( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_ASSEMBLE_7( _ptr, _index, _field, _value, ... )		     \
+	( NX_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		     \
+	  NX_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Build native-endian (positive) qword bitmasks from named fields
+ *
+ */
+
+#define NX_MASK_1( _ptr, _index, _field )			     \
+	( NX_BIT_MASK ( _ptr, _field ) <<			     \
+	  NX_QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define NX_MASK_2( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_MASK_3( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_MASK_4( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_MASK_5( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_MASK_6( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_MASK_7( _ptr, _index, _field, ... )			     \
+	( NX_MASK_1 ( _ptr, _index, _field ) |			     \
+	  NX_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Populate big-endian qwords from named fields and values
+ *
+ */
+
+#define NX_FILL( _ptr, _index, _assembled )				     \
+	do {								     \
+		uint64_t *__ptr = &(_ptr)->u.qwords[(_index)];		     \
+		uint64_t __assembled = (_assembled);			     \
+		*__ptr = cpu_to_le64 ( __assembled );			     \
+	} while ( 0 )
+
+#define NX_FILL_1( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_2( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_3( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_4( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_5( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_6( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define NX_FILL_7( _ptr, _index, ... )					     \
+	NX_FILL ( _ptr, _index, NX_ASSEMBLE_7 ( _ptr, _index, __VA_ARGS__ ) )
+
+/** Extract value of named field */
+#define NX_GET64( _ptr, _field )					     \
+	( {								     \
+		unsigned int __index = NX_QWORD_OFFSET ( _ptr, _field );     \
+		uint64_t *__ptr = &(_ptr)->u.qwords[__index];		     \
+		uint64_t __value = le64_to_cpu ( *__ptr );		     \
+		__value >>=						     \
+		    NX_QWORD_BIT_OFFSET ( _ptr, __index, _field );	     \
+		__value &= NX_BIT_MASK ( _ptr, _field );		     \
+		__value;						     \
+	} )
+
+/** Extract value of named field (for fields up to the size of a long) */
+#define NX_GET( _ptr, _field )						     \
+	( ( unsigned long ) NX_GET64 ( _ptr, _field ) )
+
+#endif /* _NX_BITOPS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nxhal_nic_interface.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nxhal_nic_interface.h
new file mode 100644
index 0000000..f487624
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/nxhal_nic_interface.h
@@ -0,0 +1,501 @@
+FILE_LICENCE ( GPL2_ONLY );
+
+/*
+ * Data types and structure for HAL - NIC interface.
+ *
+ */
+
+#ifndef _NXHAL_NIC_INTERFACE_H_
+#define _NXHAL_NIC_INTERFACE_H_
+
+/*****************************************************************************
+ *        Simple Types
+ *****************************************************************************/
+
+typedef U32     nx_reg_addr_t;
+
+/*****************************************************************************
+ *        Root crb-based firmware commands
+ *****************************************************************************/
+
+/* CRB Root Command
+
+   A single set of crbs is used across all physical/virtual
+   functions for capability queries, initialization, and
+   context creation/destruction. 
+
+   There are 4 CRBS:
+       Command/Response CRB
+       Argument1 CRB
+       Argument2 CRB
+       Argument3 CRB
+       Signature CRB 
+
+       The cmd/rsp crb is always intiated by the host via
+       a command code and always responded by the card with
+       a response code. The cmd and rsp codes are disjoint.
+       The sequence of use is always CMD, RSP, CLEAR CMD.
+
+       The arguments are for passing in command specific
+       and response specific parameters/data. 
+
+       The signature is composed of a magic value, the
+       pci function id, and a command sequence id:
+          [7:0]  = pci function
+         [15:8]  = version
+         [31:16] = magic of 0xcafe
+
+       The pci function allows the card to take correct
+       action for the given particular commands. 
+       The firmware will attempt to detect
+       an errant driver that has died while holding  
+       the root crb hardware lock. Such an error condition
+       shows up as the cmd/rsp crb stuck in a non-clear state.
+
+   Interface Sequence:
+     Host always makes requests and firmware always responds.
+     Note that data field is always set prior to command field.
+
+     [READ]             CMD/RSP CRB      ARGUMENT FIELD
+     Host grab lock
+     Host  ->           CMD              optional parameter
+     FW   <-  (Good)    RSP-OK           DATA
+     FW   <-  (Fail)    RSP-FAIL         optional failure code
+     Host ->            CLEAR
+     Host release lock
+
+     [WRITE]            CMD/RSP CRB      ARGUMENT FIELD
+     Host grab lock
+     Host  ->           CMD              DATA
+     FW   <-  (Good)    RSP-OK           optional write status
+     FW   <-  (Write)   RSP-FAIL         optional failure code
+     Host ->            CLEAR
+     Host release lock
+
+*/
+
+
+/*****************************************************************************
+ *        CMD/RSP
+ *****************************************************************************/
+
+#define NX_CDRP_SIGNATURE_TO_PCIFN(sign)    ((sign) & 0xff)
+#define NX_CDRP_SIGNATURE_TO_VERSION(sign)  (((sign)>>8) & 0xff)
+#define NX_CDRP_SIGNATURE_TO_MAGIC(sign)    (((sign)>>16) & 0xffff)
+#define NX_CDRP_SIGNATURE_VALID(sign)       \
+	( NX_CDRP_SIGNATURE_TO_MAGIC(sign) == 0xcafe && \
+	  NX_CDRP_SIGNATURE_TO_PCIFN(sign) < 8)
+#define NX_CDRP_SIGNATURE_MAKE(pcifn,version) \
+	( ((pcifn) & 0xff) |		      \
+	  (((version) & 0xff) << 8) |	      \
+	  (0xcafe << 16) )
+
+#define	NX_CDRP_CLEAR                       0x00000000
+#define	NX_CDRP_CMD_BIT                     0x80000000
+
+/* All responses must have the NX_CDRP_CMD_BIT cleared
+ * in the crb NX_CDRP_CRB_OFFSET. */
+#define NX_CDRP_FORM_RSP(rsp)              (rsp)
+#define NX_CDRP_IS_RSP(rsp)                (((rsp) & NX_CDRP_CMD_BIT) == 0)
+
+#define	NX_CDRP_RSP_OK                      0x00000001
+#define	NX_CDRP_RSP_FAIL                    0x00000002
+#define	NX_CDRP_RSP_TIMEOUT                 0x00000003
+
+/* All commands must have the NX_CDRP_CMD_BIT set in
+ * the crb NX_CDRP_CRB_OFFSET.
+ * The macros below do not have it explicitly set to
+ * allow their use in lookup tables */
+#define NX_CDRP_FORM_CMD(cmd)               (NX_CDRP_CMD_BIT | (cmd))
+#define NX_CDRP_IS_CMD(cmd)                 (((cmd) & NX_CDRP_CMD_BIT) != 0)
+
+/* [CMD] Capability Vector [RSP] Capability Vector */
+#define NX_CDRP_CMD_SUBMIT_CAPABILITIES     0x00000001
+
+/* [CMD] - [RSP] Query Value */
+#define	NX_CDRP_CMD_READ_MAX_RDS_PER_CTX    0x00000002
+
+/* [CMD] - [RSP] Query Value */
+#define	NX_CDRP_CMD_READ_MAX_SDS_PER_CTX    0x00000003
+
+/* [CMD] - [RSP] Query Value */
+#define	NX_CDRP_CMD_READ_MAX_RULES_PER_CTX  0x00000004
+
+/* [CMD] - [RSP] Query Value */
+#define	NX_CDRP_CMD_READ_MAX_RX_CTX         0x00000005
+
+/* [CMD] - [RSP] Query Value */
+#define	NX_CDRP_CMD_READ_MAX_TX_CTX         0x00000006
+
+/* [CMD] Rx Config DMA Addr [RSP] rcode */
+#define	NX_CDRP_CMD_CREATE_RX_CTX           0x00000007
+
+/* [CMD] Rx Context Handle, Reset Kind [RSP] rcode */
+#define	NX_CDRP_CMD_DESTROY_RX_CTX          0x00000008
+
+/* [CMD] Tx Config DMA Addr [RSP] rcode */
+#define	NX_CDRP_CMD_CREATE_TX_CTX           0x00000009
+
+/* [CMD] Tx Context Handle, Reset Kind [RSP] rcode */
+#define	NX_CDRP_CMD_DESTROY_TX_CTX          0x0000000a
+
+/* [CMD] Stat setup dma addr - [RSP] Handle, rcode */
+#define NX_CDRP_CMD_SETUP_STATISTICS        0x0000000e
+
+/* [CMD] Handle - [RSP] rcode */
+#define NX_CDRP_CMD_GET_STATISTICS          0x0000000f
+
+/* [CMD] Handle - [RSP] rcode */
+#define NX_CDRP_CMD_DELETE_STATISTICS       0x00000010
+
+#define NX_CDRP_CMD_MAX                     0x00000011
+
+/*****************************************************************************
+ *        Capabilities
+ *****************************************************************************/
+
+#define NX_CAP_BIT(class, bit)              (1 << bit)
+
+/* Class 0 (i.e. ARGS 1)
+ */
+#define NX_CAP0_LEGACY_CONTEXT              NX_CAP_BIT(0, 0)
+#define NX_CAP0_MULTI_CONTEXT               NX_CAP_BIT(0, 1)
+#define NX_CAP0_LEGACY_MN                   NX_CAP_BIT(0, 2)
+#define NX_CAP0_LEGACY_MS                   NX_CAP_BIT(0, 3)
+#define NX_CAP0_CUT_THROUGH                 NX_CAP_BIT(0, 4)
+#define NX_CAP0_LRO                         NX_CAP_BIT(0, 5)
+#define NX_CAP0_LSO                         NX_CAP_BIT(0, 6)
+
+/* Class 1 (i.e. ARGS 2)
+ */
+#define NX_CAP1_NIC                         NX_CAP_BIT(1, 0)
+#define NX_CAP1_PXE                         NX_CAP_BIT(1, 1)
+#define NX_CAP1_CHIMNEY                     NX_CAP_BIT(1, 2)
+#define NX_CAP1_LSA                         NX_CAP_BIT(1, 3)
+#define NX_CAP1_RDMA                        NX_CAP_BIT(1, 4)
+#define NX_CAP1_ISCSI                       NX_CAP_BIT(1, 5)
+#define NX_CAP1_FCOE                        NX_CAP_BIT(1, 6)
+
+/* Class 2 (i.e. ARGS 3)
+ */
+
+/*****************************************************************************
+ *        Rules
+ *****************************************************************************/
+
+typedef U32 nx_rx_rule_type_t;
+
+#define	NX_RX_RULETYPE_DEFAULT              0
+#define	NX_RX_RULETYPE_MAC                  1
+#define	NX_RX_RULETYPE_MAC_VLAN             2
+#define	NX_RX_RULETYPE_MAC_RSS              3
+#define	NX_RX_RULETYPE_MAC_VLAN_RSS         4
+#define	NX_RX_RULETYPE_MAX                  5
+
+typedef U32 nx_rx_rule_cmd_t;
+
+#define	NX_RX_RULECMD_ADD                   0
+#define	NX_RX_RULECMD_REMOVE                1
+#define	NX_RX_RULECMD_MAX                   2
+
+typedef struct nx_rx_rule_arg_s {
+	union {
+		struct {
+			char mac[6];
+		} m;
+		struct {
+			char mac[6];
+			char vlan;
+		} mv;
+		struct {
+			char mac[6];
+		} mr;
+		struct {
+			char mac[6];
+			char vlan;
+		} mvr;
+	};
+	/* will be union of all the different args for rules */
+	U64 data;
+} nx_rx_rule_arg_t;
+
+typedef struct nx_rx_rule_s {
+	U32 id;
+	U32 active;
+	nx_rx_rule_arg_t arg;
+	nx_rx_rule_type_t type;
+} nx_rx_rule_t;
+
+/* MSG - REQUIRES TX CONTEXT */
+
+/* The rules can be added/deleted from both the
+ *  host and card sides so rq/rsp are similar. 
+ */
+typedef struct nx_hostmsg_rx_rule_s {
+	nx_rx_rule_cmd_t cmd;
+	nx_rx_rule_t rule;
+} nx_hostmsg_rx_rule_t;
+
+typedef struct nx_cardmsg_rx_rule_s {
+	nx_rcode_t rcode;
+	nx_rx_rule_cmd_t cmd;
+	nx_rx_rule_t rule;
+} nx_cardmsg_rx_rule_t;
+
+
+/*****************************************************************************
+ *        Common to Rx/Tx contexts
+ *****************************************************************************/
+
+/*
+ * Context states
+ */
+
+typedef U32 nx_host_ctx_state_t;
+
+#define	NX_HOST_CTX_STATE_FREED             0	/* Invalid state */
+#define	NX_HOST_CTX_STATE_ALLOCATED         1	/* Not committed */
+/* The following states imply FW is aware of context */
+#define	NX_HOST_CTX_STATE_ACTIVE            2
+#define	NX_HOST_CTX_STATE_DISABLED          3
+#define	NX_HOST_CTX_STATE_QUIESCED          4
+#define	NX_HOST_CTX_STATE_MAX               5
+
+/*
+ * Interrupt mask crb use must be set identically on the Tx 
+ * and Rx context configs across a pci function 
+ */
+
+/* Rx and Tx have unique interrupt/crb */
+#define NX_HOST_INT_CRB_MODE_UNIQUE         0
+/* Rx and Tx share a common interrupt/crb */
+#define NX_HOST_INT_CRB_MODE_SHARED         1	/* <= LEGACY */
+/* Rx does not use a crb */
+#define NX_HOST_INT_CRB_MODE_NORX           2
+/* Tx does not use a crb */
+#define NX_HOST_INT_CRB_MODE_NOTX           3
+/* Neither Rx nor Tx use a crb */
+#define NX_HOST_INT_CRB_MODE_NORXTX         4
+
+/*
+ * Destroy Rx/Tx
+ */
+
+#define NX_DESTROY_CTX_RESET                0
+#define NX_DESTROY_CTX_D3_RESET             1
+#define NX_DESTROY_CTX_MAX                  2
+
+
+/*****************************************************************************
+ *        Tx
+ *****************************************************************************/
+
+/*
+ * Components of the host-request for Tx context creation.
+ * CRB - DOES NOT REQUIRE Rx/TX CONTEXT 
+ */
+
+typedef struct nx_hostrq_cds_ring_s {
+	U64 host_phys_addr;	/* Ring base addr */
+	U32 ring_size;		/* Ring entries */
+	U32 rsvd;		/* Padding */
+} nx_hostrq_cds_ring_t;
+
+typedef struct nx_hostrq_tx_ctx_s {
+	U64 host_rsp_dma_addr;	/* Response dma'd here */
+	U64 cmd_cons_dma_addr;	/*  */
+	U64 dummy_dma_addr;	/*  */
+	U32 capabilities[4];	/* Flag bit vector */
+	U32 host_int_crb_mode;	/* Interrupt crb usage */
+	U32 rsvd1;		/* Padding */
+	U16 rsvd2;		/* Padding */
+	U16 interrupt_ctl;
+	U16 msi_index;
+	U16 rsvd3;		/* Padding */
+	nx_hostrq_cds_ring_t cds_ring;	/* Desc of cds ring */
+	U8  reserved[128];	/* future expansion */
+} nx_hostrq_tx_ctx_t;
+
+typedef struct nx_cardrsp_cds_ring_s {
+	U32 host_producer_crb;	/* Crb to use */
+	U32 interrupt_crb;	/* Crb to use */
+} nx_cardrsp_cds_ring_t;
+
+typedef struct nx_cardrsp_tx_ctx_s {
+	U32 host_ctx_state;	/* Starting state */
+	U16 context_id;		/* Handle for context */
+	U8  phys_port;		/* Physical id of port */
+	U8  virt_port;		/* Virtual/Logical id of port */
+	nx_cardrsp_cds_ring_t cds_ring;	/* Card cds settings */
+	U8  reserved[128];	/* future expansion */
+} nx_cardrsp_tx_ctx_t;
+
+#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) 			\
+		( sizeof(HOSTRQ_TX))
+
+#define SIZEOF_CARDRSP_TX(CARDRSP_TX) 			\
+		( sizeof(CARDRSP_TX)) 
+
+/*****************************************************************************
+ *        Rx
+ *****************************************************************************/
+
+/*
+ * RDS ring mapping to producer crbs
+ */
+
+/* Each ring has a unique crb */
+#define NX_HOST_RDS_CRB_MODE_UNIQUE    0	/* <= LEGACY */
+
+/* All configured RDS Rings share common crb:
+     1 Ring  - same as unique
+     2 Rings - 16, 16
+     3 Rings - 10, 10, 10 */
+#define NX_HOST_RDS_CRB_MODE_SHARED    1
+
+/* Bit usage is specified per-ring using the
+   ring's size. Sum of bit lengths must be <= 32. 
+   Packing is [Ring N] ... [Ring 1][Ring 0] */
+#define NX_HOST_RDS_CRB_MODE_CUSTOM    2
+#define NX_HOST_RDS_CRB_MODE_MAX       3
+
+
+/*
+ * RDS Ting Types 
+ */
+
+#define NX_RDS_RING_TYPE_NORMAL       0
+#define NX_RDS_RING_TYPE_JUMBO        1
+#define NX_RDS_RING_TYPE_LRO          2
+#define NX_RDS_RING_TYPE_MAX          3
+
+/*
+ * Components of the host-request for Rx context creation.
+ * CRB - DOES NOT REQUIRE Rx/TX CONTEXT 
+ */
+
+typedef struct nx_hostrq_sds_ring_s {
+	U64 host_phys_addr;	/* Ring base addr */
+	U32 ring_size;		/* Ring entries */
+	U16 msi_index;
+	U16 rsvd;		/* Padding */
+} nx_hostrq_sds_ring_t;
+
+typedef struct nx_hostrq_rds_ring_s {
+	U64 host_phys_addr;	/* Ring base addr */
+	U64 buff_size;		/* Packet buffer size */
+	U32 ring_size;		/* Ring entries */
+	U32 ring_kind;		/* Class of ring */
+} nx_hostrq_rds_ring_t;
+
+typedef struct nx_hostrq_rx_ctx_s {
+	U64 host_rsp_dma_addr;	/* Response dma'd here */
+	U32 capabilities[4];	/* Flag bit vector */
+	U32 host_int_crb_mode;	/* Interrupt crb usage */
+	U32 host_rds_crb_mode;	/* RDS crb usage */
+	/* These ring offsets are relative to data[0] below */
+	U32 rds_ring_offset;	/* Offset to RDS config */
+	U32 sds_ring_offset;	/* Offset to SDS config */
+	U16 num_rds_rings;	/* Count of RDS rings */
+	U16 num_sds_rings;	/* Count of SDS rings */
+	U16 rsvd1;		/* Padding */
+	U16 rsvd2;		/* Padding */
+	U8  reserved[128]; 	/* reserve space for future expansion*/
+	/* MUST BE 64-bit aligned.
+	   The following is packed:
+	   - N hostrq_rds_rings
+	   - N hostrq_sds_rings */
+	char data[0];
+} nx_hostrq_rx_ctx_t;
+
+typedef struct nx_cardrsp_rds_ring_s {
+	U32 host_producer_crb;	/* Crb to use */
+	U32 rsvd1;		/* Padding */
+} nx_cardrsp_rds_ring_t;
+
+typedef struct nx_cardrsp_sds_ring_s {
+	U32 host_consumer_crb;	/* Crb to use */
+	U32 interrupt_crb;	/* Crb to use */
+} nx_cardrsp_sds_ring_t;
+
+typedef struct nx_cardrsp_rx_ctx_s {
+	/* These ring offsets are relative to data[0] below */
+	U32 rds_ring_offset;	/* Offset to RDS config */
+	U32 sds_ring_offset;	/* Offset to SDS config */
+	U32 host_ctx_state;	/* Starting State */
+	U32 num_fn_per_port;	/* How many PCI fn share the port */
+	U16 num_rds_rings;	/* Count of RDS rings */
+	U16 num_sds_rings;	/* Count of SDS rings */
+	U16 context_id;		/* Handle for context */
+	U8  phys_port;		/* Physical id of port */
+	U8  virt_port;		/* Virtual/Logical id of port */
+	U8  reserved[128];	/* save space for future expansion */
+	/*  MUST BE 64-bit aligned.
+	   The following is packed:
+	   - N cardrsp_rds_rings
+	   - N cardrs_sds_rings */
+	char data[0];
+} nx_cardrsp_rx_ctx_t;
+
+#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings)	\
+	( sizeof(HOSTRQ_RX) + 					\
+	(rds_rings)*(sizeof (nx_hostrq_rds_ring_t)) +		\
+	(sds_rings)*(sizeof (nx_hostrq_sds_ring_t)) )
+
+#define SIZEOF_CARDRSP_RX(CARDRSP_RX, rds_rings, sds_rings) 	\
+	( sizeof(CARDRSP_RX) + 					\
+	(rds_rings)*(sizeof (nx_cardrsp_rds_ring_t)) + 		\
+	(sds_rings)*(sizeof (nx_cardrsp_sds_ring_t)) )
+
+
+/*****************************************************************************
+ *        Statistics
+ *****************************************************************************/
+
+/*
+ * The model of statistics update to use 
+ */
+
+#define NX_STATISTICS_MODE_INVALID       0
+
+/* Permanent setup; Updates are only sent on explicit request 
+   (NX_CDRP_CMD_GET_STATISTICS) */
+#define NX_STATISTICS_MODE_PULL          1
+
+/* Permanent setup; Updates are sent automatically and on 
+   explicit request (NX_CDRP_CMD_GET_STATISTICS) */
+#define NX_STATISTICS_MODE_PUSH          2
+
+/* One time stat update. */
+#define NX_STATISTICS_MODE_SINGLE_SHOT   3
+
+#define NX_STATISTICS_MODE_MAX           4
+
+/*
+ * What set of stats 
+ */
+#define NX_STATISTICS_TYPE_INVALID       0
+#define NX_STATISTICS_TYPE_NIC_RX_CORE   1
+#define NX_STATISTICS_TYPE_NIC_TX_CORE   2
+#define NX_STATISTICS_TYPE_NIC_RX_ALL    3
+#define NX_STATISTICS_TYPE_NIC_TX_ALL    4
+#define NX_STATISTICS_TYPE_MAX           5
+
+
+/*
+ * Request to setup statistics gathering.
+ * CRB - DOES NOT REQUIRE Rx/TX CONTEXT 
+ */
+
+typedef struct nx_hostrq_stat_setup_s {
+	U64 host_stat_buffer;	/* Where to dma stats */
+	U32 host_stat_size;	/* Size of stat buffer */
+	U16 context_id;		/* Which context */
+	U16 stat_type;		/* What class of stats */
+	U16 stat_mode;		/* When to update */
+	U16 stat_interval;	/* Frequency of update */
+} nx_hostrq_stat_setup_t;
+
+
+
+#endif /* _NXHAL_NIC_INTERFACE_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.c
new file mode 100644
index 0000000..a55319e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.c
@@ -0,0 +1,2178 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ * Copyright (C) 2008 NetXen, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/io.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/spi.h>
+#include <ipxe/settings.h>
+#include "phantom.h"
+
+/**
+ * @file
+ *
+ * NetXen Phantom NICs
+ *
+ */
+
+/** Maximum number of ports */
+#define PHN_MAX_NUM_PORTS 8
+
+/** Maximum time to wait for command PEG to initialise
+ *
+ * BUGxxxx
+ *
+ * The command PEG will currently report initialisation complete only
+ * when at least one PHY has detected a link (so that the global PHY
+ * clock can be set to 10G/1G as appropriate).  This can take a very,
+ * very long time.
+ *
+ * A future firmware revision should decouple PHY initialisation from
+ * firmware initialisation, at which point the command PEG will report
+ * initialisation complete much earlier, and this timeout can be
+ * reduced.
+ */
+#define PHN_CMDPEG_INIT_TIMEOUT_SEC 50
+
+/** Maximum time to wait for receive PEG to initialise */
+#define PHN_RCVPEG_INIT_TIMEOUT_SEC 2
+
+/** Maximum time to wait for firmware to accept a command */
+#define PHN_ISSUE_CMD_TIMEOUT_MS 2000
+
+/** Maximum time to wait for test memory */
+#define PHN_TEST_MEM_TIMEOUT_MS 100
+
+/** Maximum time to wait for CLP command to be issued */
+#define PHN_CLP_CMD_TIMEOUT_MS 500
+
+/** Link state poll frequency
+ *
+ * The link state will be checked once in every N calls to poll().
+ */
+#define PHN_LINK_POLL_FREQUENCY 4096
+
+/** Number of RX descriptors */
+#define PHN_NUM_RDS 32
+
+/** RX maximum fill level.  Must be strictly less than PHN_NUM_RDS. */
+#define PHN_RDS_MAX_FILL 16
+
+/** RX buffer size */
+#define PHN_RX_BUFSIZE ( 32 /* max LL padding added by card */ + \
+			 ETH_FRAME_LEN )
+
+/** Number of RX status descriptors */
+#define PHN_NUM_SDS 32
+
+/** Number of TX descriptors */
+#define PHN_NUM_CDS 8
+
+/** A Phantom descriptor ring set */
+struct phantom_descriptor_rings {
+	/** RX descriptors */
+	struct phantom_rds rds[PHN_NUM_RDS];
+	/** RX status descriptors */
+	struct phantom_sds sds[PHN_NUM_SDS];
+	/** TX descriptors */
+	union phantom_cds cds[PHN_NUM_CDS];
+	/** TX consumer index */
+	volatile uint32_t cmd_cons;
+};
+
+/** RX context creation request and response buffers */
+struct phantom_create_rx_ctx_rqrsp {
+	struct {
+		struct nx_hostrq_rx_ctx_s rx_ctx;
+		struct nx_hostrq_rds_ring_s rds;
+		struct nx_hostrq_sds_ring_s sds;
+	} __unm_dma_aligned hostrq;
+	struct {
+		struct nx_cardrsp_rx_ctx_s rx_ctx;
+		struct nx_cardrsp_rds_ring_s rds;
+		struct nx_cardrsp_sds_ring_s sds;
+	} __unm_dma_aligned cardrsp;
+};
+
+/** TX context creation request and response buffers */
+struct phantom_create_tx_ctx_rqrsp {
+	struct {
+		struct nx_hostrq_tx_ctx_s tx_ctx;
+	} __unm_dma_aligned hostrq;
+	struct {
+		struct nx_cardrsp_tx_ctx_s tx_ctx;
+	} __unm_dma_aligned cardrsp;
+};
+
+/** A Phantom NIC */
+struct phantom_nic {
+	/** BAR 0 */
+	void *bar0;
+	/** Current CRB window */
+	unsigned long crb_window;
+	/** CRB window access method */
+	unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
+					unsigned long reg );
+
+
+	/** Port number */
+	unsigned int port;
+
+
+	/** RX context ID */
+	uint16_t rx_context_id;
+	/** RX descriptor producer CRB offset */
+	unsigned long rds_producer_crb;
+	/** RX status descriptor consumer CRB offset */
+	unsigned long sds_consumer_crb;
+	/** RX interrupt mask CRB offset */
+	unsigned long sds_irq_mask_crb;
+	/** RX interrupts enabled */
+	unsigned int sds_irq_enabled;
+
+	/** RX producer index */
+	unsigned int rds_producer_idx;
+	/** RX consumer index */
+	unsigned int rds_consumer_idx;
+	/** RX status consumer index */
+	unsigned int sds_consumer_idx;
+	/** RX I/O buffers */
+	struct io_buffer *rds_iobuf[PHN_RDS_MAX_FILL];
+
+
+	/** TX context ID */
+	uint16_t tx_context_id;
+	/** TX descriptor producer CRB offset */
+	unsigned long cds_producer_crb;
+
+	/** TX producer index */
+	unsigned int cds_producer_idx;
+	/** TX consumer index */
+	unsigned int cds_consumer_idx;
+	/** TX I/O buffers */
+	struct io_buffer *cds_iobuf[PHN_NUM_CDS];
+
+
+	/** Descriptor rings */
+	struct phantom_descriptor_rings *desc;
+
+
+	/** Last known link state */
+	uint32_t link_state;
+	/** Link state poll timer */
+	unsigned long link_poll_timer;
+
+
+	/** Non-volatile settings */
+	struct settings settings;
+};
+
+/** Interrupt mask registers */
+static const unsigned long phantom_irq_mask_reg[PHN_MAX_NUM_PORTS] = {
+	UNM_PCIE_IRQ_MASK_F0,
+	UNM_PCIE_IRQ_MASK_F1,
+	UNM_PCIE_IRQ_MASK_F2,
+	UNM_PCIE_IRQ_MASK_F3,
+	UNM_PCIE_IRQ_MASK_F4,
+	UNM_PCIE_IRQ_MASK_F5,
+	UNM_PCIE_IRQ_MASK_F6,
+	UNM_PCIE_IRQ_MASK_F7,
+};
+
+/** Interrupt status registers */
+static const unsigned long phantom_irq_status_reg[PHN_MAX_NUM_PORTS] = {
+	UNM_PCIE_IRQ_STATUS_F0,
+	UNM_PCIE_IRQ_STATUS_F1,
+	UNM_PCIE_IRQ_STATUS_F2,
+	UNM_PCIE_IRQ_STATUS_F3,
+	UNM_PCIE_IRQ_STATUS_F4,
+	UNM_PCIE_IRQ_STATUS_F5,
+	UNM_PCIE_IRQ_STATUS_F6,
+	UNM_PCIE_IRQ_STATUS_F7,
+};
+
+/***************************************************************************
+ *
+ * CRB register access
+ *
+ */
+
+/**
+ * Prepare for access to CRB register via 128MB BAR
+ *
+ * @v phantom		Phantom NIC
+ * @v reg		Register offset within abstract address space
+ * @ret offset		Register offset within PCI BAR0
+ */
+static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
+					       unsigned long reg ) {
+	unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) );
+	uint32_t window = ( reg & 0x2000000 );
+	uint32_t verify_window;
+
+	if ( phantom->crb_window != window ) {
+
+		/* Write to the CRB window register */
+		writel ( window, phantom->bar0 + UNM_128M_CRB_WINDOW );
+
+		/* Ensure that the write has reached the card */
+		verify_window = readl ( phantom->bar0 + UNM_128M_CRB_WINDOW );
+		assert ( verify_window == window );
+
+		/* Record new window */
+		phantom->crb_window = window;
+	}
+
+	return offset;
+}
+
+/**
+ * Prepare for access to CRB register via 32MB BAR
+ *
+ * @v phantom		Phantom NIC
+ * @v reg		Register offset within abstract address space
+ * @ret offset		Register offset within PCI BAR0
+ */
+static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
+					      unsigned long reg ) {
+	unsigned long offset = ( reg & 0x1ffffff );
+	uint32_t window = ( reg & 0x2000000 );
+	uint32_t verify_window;
+
+	if ( phantom->crb_window != window ) {
+
+		/* Write to the CRB window register */
+		writel ( window, phantom->bar0 + UNM_32M_CRB_WINDOW );
+
+		/* Ensure that the write has reached the card */
+		verify_window = readl ( phantom->bar0 + UNM_32M_CRB_WINDOW );
+		assert ( verify_window == window );
+
+		/* Record new window */
+		phantom->crb_window = window;
+	}
+
+	return offset;
+}
+
+/**
+ * Prepare for access to CRB register via 2MB BAR
+ *
+ * @v phantom		Phantom NIC
+ * @v reg		Register offset within abstract address space
+ * @ret offset		Register offset within PCI BAR0
+ */
+static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom,
+					     unsigned long reg ) {
+	static const struct {
+		uint8_t block;
+		uint16_t window_hi;
+	} reg_window_hi[] = {
+		{ UNM_CRB_BLK_PCIE,	0x773 },
+		{ UNM_CRB_BLK_CAM,	0x416 },
+		{ UNM_CRB_BLK_ROMUSB,	0x421 },
+		{ UNM_CRB_BLK_TEST,	0x295 },
+		{ UNM_CRB_BLK_PEG_0,	0x340 },
+		{ UNM_CRB_BLK_PEG_1,	0x341 },
+		{ UNM_CRB_BLK_PEG_2,	0x342 },
+		{ UNM_CRB_BLK_PEG_3,	0x343 },
+		{ UNM_CRB_BLK_PEG_4,	0x34b },
+	};
+	unsigned int block = UNM_CRB_BLK ( reg );
+	unsigned long offset = UNM_CRB_OFFSET ( reg );
+	uint32_t window;
+	uint32_t verify_window;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( reg_window_hi ) /
+			    sizeof ( reg_window_hi[0] ) ) ; i++ ) {
+
+		if ( reg_window_hi[i].block != block )
+			continue;
+
+		window = ( ( reg_window_hi[i].window_hi << 20 ) |
+			   ( offset & 0x000f0000 ) );
+
+		if ( phantom->crb_window != window ) {
+
+			/* Write to the CRB window register */
+			writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+
+			/* Ensure that the write has reached the card */
+			verify_window = readl ( phantom->bar0 +
+						UNM_2M_CRB_WINDOW );
+			assert ( verify_window == window );
+
+			/* Record new window */
+			phantom->crb_window = window;
+		}
+
+		return ( 0x1e0000 + ( offset & 0xffff ) );
+	}
+
+	assert ( 0 );
+	return 0;
+}
+
+/**
+ * Read from Phantom CRB register
+ *
+ * @v phantom		Phantom NIC
+ * @v reg		Register offset within abstract address space
+ * @ret	value		Register value
+ */
+static uint32_t phantom_readl ( struct phantom_nic *phantom,
+				unsigned long reg ) {
+	unsigned long offset;
+
+	offset = phantom->crb_access ( phantom, reg );
+	return readl ( phantom->bar0 + offset );
+}
+
+/**
+ * Write to Phantom CRB register
+ *
+ * @v phantom		Phantom NIC
+ * @v value		Register value
+ * @v reg		Register offset within abstract address space
+ */
+static void phantom_writel ( struct phantom_nic *phantom, uint32_t value,
+			     unsigned long reg ) {
+	unsigned long offset;
+
+	offset = phantom->crb_access ( phantom, reg );
+	writel ( value, phantom->bar0 + offset );
+}
+
+/**
+ * Write to Phantom CRB HI/LO register pair
+ *
+ * @v phantom		Phantom NIC
+ * @v value		Register value
+ * @v lo_offset		LO register offset within CRB
+ * @v hi_offset		HI register offset within CRB
+ */
+static inline void phantom_write_hilo ( struct phantom_nic *phantom,
+					uint64_t value,
+					unsigned long lo_offset,
+					unsigned long hi_offset ) {
+	uint32_t lo = ( value & 0xffffffffUL );
+	uint32_t hi = ( value >> 32 );
+
+	phantom_writel ( phantom, lo, lo_offset );
+	phantom_writel ( phantom, hi, hi_offset );
+}
+
+/***************************************************************************
+ *
+ * Firmware message buffer access (for debug)
+ *
+ */
+
+/**
+ * Read from Phantom test memory
+ *
+ * @v phantom		Phantom NIC
+ * @v offset		Offset within test memory
+ * @v buf		8-byte buffer to fill
+ * @ret rc		Return status code
+ */
+static int phantom_read_test_mem_block ( struct phantom_nic *phantom,
+					 unsigned long offset,
+					 uint32_t buf[2] ) {
+	unsigned int retries;
+	uint32_t test_control;
+
+	phantom_write_hilo ( phantom, offset, UNM_TEST_ADDR_LO,
+			     UNM_TEST_ADDR_HI );
+	phantom_writel ( phantom, UNM_TEST_CONTROL_ENABLE, UNM_TEST_CONTROL );
+	phantom_writel ( phantom,
+			 ( UNM_TEST_CONTROL_ENABLE | UNM_TEST_CONTROL_START ),
+			 UNM_TEST_CONTROL );
+	
+	for ( retries = 0 ; retries < PHN_TEST_MEM_TIMEOUT_MS ; retries++ ) {
+		test_control = phantom_readl ( phantom, UNM_TEST_CONTROL );
+		if ( ( test_control & UNM_TEST_CONTROL_BUSY ) == 0 ) {
+			buf[0] = phantom_readl ( phantom, UNM_TEST_RDDATA_LO );
+			buf[1] = phantom_readl ( phantom, UNM_TEST_RDDATA_HI );
+			return 0;
+		}
+		mdelay ( 1 );
+	}
+
+	DBGC ( phantom, "Phantom %p timed out waiting for test memory\n",
+	       phantom );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Read single byte from Phantom test memory
+ *
+ * @v phantom		Phantom NIC
+ * @v offset		Offset within test memory
+ * @ret byte		Byte read, or negative error
+ */
+static int phantom_read_test_mem ( struct phantom_nic *phantom,
+				   unsigned long offset ) {
+	static union {
+		uint8_t bytes[8];
+		uint32_t dwords[2];
+	} cache;
+	static unsigned long cache_offset = -1UL;
+	unsigned long sub_offset;
+	int rc;
+
+	sub_offset = ( offset & ( sizeof ( cache ) - 1 ) );
+	offset = ( offset & ~( sizeof ( cache ) - 1 ) );
+
+	if ( cache_offset != offset ) {
+		if ( ( rc = phantom_read_test_mem_block ( phantom, offset,
+							  cache.dwords )) !=0 )
+			return rc;
+		cache_offset = offset;
+	}
+
+	return cache.bytes[sub_offset];
+}
+
+/**
+ * Dump Phantom firmware dmesg log
+ *
+ * @v phantom		Phantom NIC
+ * @v log		Log number
+ * @v max_lines		Maximum number of lines to show, or -1 to show all
+ * @ret rc		Return status code
+ */
+static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log,
+			    unsigned int max_lines ) {
+	uint32_t head;
+	uint32_t tail;
+	uint32_t sig;
+	uint32_t offset;
+	int byte;
+
+	/* Optimise out for non-debug builds */
+	if ( ! DBG_LOG )
+		return 0;
+
+	/* Locate log */
+	head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) );
+	tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) );
+	sig = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_SIG ( log ) );
+	DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08x-%08x)\n",
+	       phantom, log, head, tail );
+	assert ( ( head & 0x07 ) == 0 );
+	if ( sig != UNM_CAM_RAM_DMESG_SIG_MAGIC ) {
+		DBGC ( phantom, "Warning: bad signature %08x (want %08lx)\n",
+		       sig, UNM_CAM_RAM_DMESG_SIG_MAGIC );
+	}
+
+	/* Locate start of last (max_lines) lines */
+	for ( offset = tail ; offset > head ; offset-- ) {
+		if ( ( byte = phantom_read_test_mem ( phantom,
+						      ( offset - 1 ) ) ) < 0 )
+			return byte;
+		if ( ( byte == '\n' ) && ( max_lines-- == 0 ) )
+			break;
+	}
+
+	/* Print lines */
+	for ( ; offset < tail ; offset++ ) {
+		if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 )
+			return byte;
+		DBG ( "%c", byte );
+	}
+	DBG ( "\n" );
+	return 0;
+}
+
+/**
+ * Dump Phantom firmware dmesg logs
+ *
+ * @v phantom		Phantom NIC
+ * @v max_lines		Maximum number of lines to show, or -1 to show all
+ */
+static void __attribute__ (( unused ))
+phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) {
+	unsigned int i;
+
+	for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ )
+		phantom_dmesg ( phantom, i, max_lines );
+}
+
+/***************************************************************************
+ *
+ * Firmware interface
+ *
+ */
+
+/**
+ * Wait for firmware to accept command
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) {
+	unsigned int retries;
+	uint32_t cdrp;
+
+	for ( retries = 0 ; retries < PHN_ISSUE_CMD_TIMEOUT_MS ; retries++ ) {
+		mdelay ( 1 );
+		cdrp = phantom_readl ( phantom, UNM_NIC_REG_NX_CDRP );
+		if ( NX_CDRP_IS_RSP ( cdrp ) ) {
+			switch ( NX_CDRP_FORM_RSP ( cdrp ) ) {
+			case NX_CDRP_RSP_OK:
+				return 0;
+			case NX_CDRP_RSP_FAIL:
+				return -EIO;
+			case NX_CDRP_RSP_TIMEOUT:
+				return -ETIMEDOUT;
+			default:
+				return -EPROTO;
+			}
+		}
+	}
+
+	DBGC ( phantom, "Phantom %p timed out waiting for firmware to accept "
+	       "command\n", phantom );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Issue command to firmware
+ *
+ * @v phantom		Phantom NIC
+ * @v command		Firmware command
+ * @v arg1		Argument 1
+ * @v arg2		Argument 2
+ * @v arg3		Argument 3
+ * @ret rc		Return status code
+ */
+static int phantom_issue_cmd ( struct phantom_nic *phantom,
+			       uint32_t command, uint32_t arg1, uint32_t arg2,
+			       uint32_t arg3 ) {
+	uint32_t signature;
+	int rc;
+
+	/* Issue command */
+	signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port,
+					     NXHAL_VERSION );
+	DBGC2 ( phantom, "Phantom %p issuing command %08x (%08x, %08x, "
+		"%08x)\n", phantom, command, arg1, arg2, arg3 );
+	phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN );
+	phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 );
+	phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 );
+	phantom_writel ( phantom, arg3, UNM_NIC_REG_NX_ARG3 );
+	phantom_writel ( phantom, NX_CDRP_FORM_CMD ( command ),
+			 UNM_NIC_REG_NX_CDRP );
+
+	/* Wait for command to be accepted */
+	if ( ( rc = phantom_wait_for_cmd ( phantom ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not issue command: %s\n",
+		       phantom, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Issue buffer-format command to firmware
+ *
+ * @v phantom		Phantom NIC
+ * @v command		Firmware command
+ * @v buffer		Buffer to pass to firmware
+ * @v len		Length of buffer
+ * @ret rc		Return status code
+ */
+static int phantom_issue_buf_cmd ( struct phantom_nic *phantom,
+				   uint32_t command, void *buffer,
+				   size_t len ) {
+	uint64_t physaddr;
+
+	physaddr = virt_to_bus ( buffer );
+	return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ),
+				   ( physaddr & 0xffffffffUL ), len );
+}
+
+/**
+ * Create Phantom RX context
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
+	struct phantom_create_rx_ctx_rqrsp *buf;
+	int rc;
+
+	/* Allocate context creation buffer */
+	buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+	if ( ! buf ) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset ( buf, 0, sizeof ( *buf ) );
+	
+	/* Prepare request */
+	buf->hostrq.rx_ctx.host_rsp_dma_addr =
+		cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
+	buf->hostrq.rx_ctx.capabilities[0] =
+		cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN );
+	buf->hostrq.rx_ctx.host_int_crb_mode =
+		cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED );
+	buf->hostrq.rx_ctx.host_rds_crb_mode =
+		cpu_to_le32 ( NX_HOST_RDS_CRB_MODE_UNIQUE );
+	buf->hostrq.rx_ctx.rds_ring_offset = cpu_to_le32 ( 0 );
+	buf->hostrq.rx_ctx.sds_ring_offset =
+		cpu_to_le32 ( sizeof ( buf->hostrq.rds ) );
+	buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 );
+	buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 );
+	buf->hostrq.rds.host_phys_addr =
+		cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) );
+	buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE );
+	buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS );
+	buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL );
+	buf->hostrq.sds.host_phys_addr =
+		cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) );
+	buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS );
+
+	DBGC ( phantom, "Phantom %p creating RX context\n", phantom );
+	DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
+		    &buf->hostrq, sizeof ( buf->hostrq ) );
+
+	/* Issue request */
+	if ( ( rc = phantom_issue_buf_cmd ( phantom,
+					    NX_CDRP_CMD_CREATE_RX_CTX,
+					    &buf->hostrq,
+					    sizeof ( buf->hostrq ) ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not create RX context: "
+		       "%s\n", phantom, strerror ( rc ) );
+		DBGC ( phantom, "Request:\n" );
+		DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
+			   &buf->hostrq, sizeof ( buf->hostrq ) );
+		DBGC ( phantom, "Response:\n" );
+		DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
+			   &buf->cardrsp, sizeof ( buf->cardrsp ) );
+		goto out;
+	}
+
+	/* Retrieve context parameters */
+	phantom->rx_context_id =
+		le16_to_cpu ( buf->cardrsp.rx_ctx.context_id );
+	phantom->rds_producer_crb =
+		( UNM_CAM_RAM +
+		  le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ) );
+	phantom->sds_consumer_crb =
+		( UNM_CAM_RAM +
+		  le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ) );
+	phantom->sds_irq_mask_crb =
+		( UNM_CAM_RAM +
+		  le32_to_cpu ( buf->cardrsp.sds.interrupt_crb ) );
+
+	DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys "
+	       "%02x virt %02x)\n", phantom, phantom->rx_context_id,
+	       buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port );
+	DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
+		    &buf->cardrsp, sizeof ( buf->cardrsp ) );
+	DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n",
+	       phantom, phantom->rds_producer_crb );
+	DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n",
+	       phantom, phantom->sds_consumer_crb );
+	DBGC ( phantom, "Phantom %p SDS interrupt mask CRB is %08lx\n",
+	       phantom, phantom->sds_irq_mask_crb );
+
+ out:
+	free_dma ( buf, sizeof ( *buf ) );
+	return rc;
+}
+
+/**
+ * Destroy Phantom RX context
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) {
+	int rc;
+	
+	DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n",
+	       phantom, phantom->rx_context_id );
+
+	/* Issue request */
+	if ( ( rc = phantom_issue_cmd ( phantom,
+					NX_CDRP_CMD_DESTROY_RX_CTX,
+					phantom->rx_context_id,
+					NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not destroy RX context: "
+		       "%s\n", phantom, strerror ( rc ) );
+		/* We're probably screwed */
+		return;
+	}
+
+	/* Clear context parameters */
+	phantom->rx_context_id = 0;
+	phantom->rds_producer_crb = 0;
+	phantom->sds_consumer_crb = 0;
+
+	/* Reset software counters */
+	phantom->rds_producer_idx = 0;
+	phantom->rds_consumer_idx = 0;
+	phantom->sds_consumer_idx = 0;
+}
+
+/**
+ * Create Phantom TX context
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) {
+	struct phantom_create_tx_ctx_rqrsp *buf;
+	int rc;
+
+	/* Allocate context creation buffer */
+	buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+	if ( ! buf ) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset ( buf, 0, sizeof ( *buf ) );
+
+	/* Prepare request */
+	buf->hostrq.tx_ctx.host_rsp_dma_addr =
+		cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
+	buf->hostrq.tx_ctx.cmd_cons_dma_addr =
+		cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) );
+	buf->hostrq.tx_ctx.capabilities[0] =
+		cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN );
+	buf->hostrq.tx_ctx.host_int_crb_mode =
+		cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED );
+	buf->hostrq.tx_ctx.cds_ring.host_phys_addr =
+		cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) );
+	buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS );
+
+	DBGC ( phantom, "Phantom %p creating TX context\n", phantom );
+	DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
+		    &buf->hostrq, sizeof ( buf->hostrq ) );
+
+	/* Issue request */
+	if ( ( rc = phantom_issue_buf_cmd ( phantom,
+					    NX_CDRP_CMD_CREATE_TX_CTX,
+					    &buf->hostrq,
+					    sizeof ( buf->hostrq ) ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not create TX context: "
+		       "%s\n", phantom, strerror ( rc ) );
+		DBGC ( phantom, "Request:\n" );
+		DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
+			   &buf->hostrq, sizeof ( buf->hostrq ) );
+		DBGC ( phantom, "Response:\n" );
+		DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
+			   &buf->cardrsp, sizeof ( buf->cardrsp ) );
+		goto out;
+	}
+
+	/* Retrieve context parameters */
+	phantom->tx_context_id =
+		le16_to_cpu ( buf->cardrsp.tx_ctx.context_id );
+	phantom->cds_producer_crb =
+		( UNM_CAM_RAM +
+		  le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb));
+
+	DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys "
+	       "%02x virt %02x)\n", phantom, phantom->tx_context_id,
+	       buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port );
+	DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
+		    &buf->cardrsp, sizeof ( buf->cardrsp ) );
+	DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n",
+	       phantom, phantom->cds_producer_crb );
+
+ out:
+	free_dma ( buf, sizeof ( *buf ) );
+	return rc;
+}
+
+/**
+ * Destroy Phantom TX context
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) {
+	int rc;
+	
+	DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n",
+	       phantom, phantom->tx_context_id );
+
+	/* Issue request */
+	if ( ( rc = phantom_issue_cmd ( phantom,
+					NX_CDRP_CMD_DESTROY_TX_CTX,
+					phantom->tx_context_id,
+					NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not destroy TX context: "
+		       "%s\n", phantom, strerror ( rc ) );
+		/* We're probably screwed */
+		return;
+	}
+
+	/* Clear context parameters */
+	phantom->tx_context_id = 0;
+	phantom->cds_producer_crb = 0;
+
+	/* Reset software counters */
+	phantom->cds_producer_idx = 0;
+	phantom->cds_consumer_idx = 0;
+}
+
+/***************************************************************************
+ *
+ * Descriptor ring management
+ *
+ */
+
+/**
+ * Allocate Phantom RX descriptor
+ *
+ * @v phantom		Phantom NIC
+ * @ret index		RX descriptor index, or negative error
+ */
+static int phantom_alloc_rds ( struct phantom_nic *phantom ) {
+	unsigned int rds_producer_idx;
+	unsigned int next_rds_producer_idx;
+
+	/* Check for space in the ring.  RX descriptors are consumed
+	 * out of order, but they are *read* by the hardware in strict
+	 * order.  We maintain a pessimistic consumer index, which is
+	 * guaranteed never to be an overestimate of the number of
+	 * descriptors read by the hardware.
+	 */
+	rds_producer_idx = phantom->rds_producer_idx;
+	next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
+	if ( next_rds_producer_idx == phantom->rds_consumer_idx ) {
+		DBGC ( phantom, "Phantom %p RDS ring full (index %d not "
+		       "consumed)\n", phantom, next_rds_producer_idx );
+		return -ENOBUFS;
+	}
+
+	return rds_producer_idx;
+}
+
+/**
+ * Post Phantom RX descriptor
+ *
+ * @v phantom		Phantom NIC
+ * @v rds		RX descriptor
+ */
+static void phantom_post_rds ( struct phantom_nic *phantom,
+			       struct phantom_rds *rds ) {
+	unsigned int rds_producer_idx;
+	unsigned int next_rds_producer_idx;
+	struct phantom_rds *entry;
+
+	/* Copy descriptor to ring */
+	rds_producer_idx = phantom->rds_producer_idx;
+	entry = &phantom->desc->rds[rds_producer_idx];
+	memcpy ( entry, rds, sizeof ( *entry ) );
+	DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n",
+		phantom, NX_GET ( rds, handle ), rds_producer_idx );
+	DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
+
+	/* Update producer index */
+	next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
+	phantom->rds_producer_idx = next_rds_producer_idx;
+	wmb();
+	phantom_writel ( phantom, phantom->rds_producer_idx,
+			 phantom->rds_producer_crb );
+}
+
+/**
+ * Allocate Phantom TX descriptor
+ *
+ * @v phantom		Phantom NIC
+ * @ret index		TX descriptor index, or negative error
+ */
+static int phantom_alloc_cds ( struct phantom_nic *phantom ) {
+	unsigned int cds_producer_idx;
+	unsigned int next_cds_producer_idx;
+
+	/* Check for space in the ring.  TX descriptors are consumed
+	 * in strict order, so we just check for a collision against
+	 * the consumer index.
+	 */
+	cds_producer_idx = phantom->cds_producer_idx;
+	next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
+	if ( next_cds_producer_idx == phantom->cds_consumer_idx ) {
+		DBGC ( phantom, "Phantom %p CDS ring full (index %d not "
+		       "consumed)\n", phantom, next_cds_producer_idx );
+		return -ENOBUFS;
+	}
+
+	return cds_producer_idx;
+}
+
+/**
+ * Post Phantom TX descriptor
+ *
+ * @v phantom		Phantom NIC
+ * @v cds		TX descriptor
+ */
+static void phantom_post_cds ( struct phantom_nic *phantom,
+			       union phantom_cds *cds ) {
+	unsigned int cds_producer_idx;
+	unsigned int next_cds_producer_idx;
+	union phantom_cds *entry;
+
+	/* Copy descriptor to ring */
+	cds_producer_idx = phantom->cds_producer_idx;
+	entry = &phantom->desc->cds[cds_producer_idx];
+	memcpy ( entry, cds, sizeof ( *entry ) );
+	DBGC2 ( phantom, "Phantom %p posting CDS %d:\n",
+		phantom, cds_producer_idx );
+	DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
+
+	/* Update producer index */
+	next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
+	phantom->cds_producer_idx = next_cds_producer_idx;
+	wmb();
+	phantom_writel ( phantom, phantom->cds_producer_idx,
+			 phantom->cds_producer_crb );
+}
+
+/***************************************************************************
+ *
+ * MAC address management
+ *
+ */
+
+/**
+ * Add/remove MAC address
+ *
+ * @v phantom		Phantom NIC
+ * @v ll_addr		MAC address to add or remove
+ * @v opcode		MAC request opcode
+ * @ret rc		Return status code
+ */
+static int phantom_update_macaddr ( struct phantom_nic *phantom,
+				    const uint8_t *ll_addr,
+				    unsigned int opcode ) {
+	union phantom_cds cds;
+	int index;
+
+	/* Get descriptor ring entry */
+	index = phantom_alloc_cds ( phantom );
+	if ( index < 0 )
+		return index;
+
+	/* Fill descriptor ring entry */
+	memset ( &cds, 0, sizeof ( cds ) );
+	NX_FILL_1 ( &cds, 0,
+		    nic_request.common.opcode, UNM_NIC_REQUEST );
+	NX_FILL_2 ( &cds, 1,
+		    nic_request.header.opcode, UNM_MAC_EVENT,
+		    nic_request.header.context_id, phantom->port );
+	NX_FILL_7 ( &cds, 2,
+		    nic_request.body.mac_request.opcode, opcode,
+		    nic_request.body.mac_request.mac_addr_0, ll_addr[0],
+		    nic_request.body.mac_request.mac_addr_1, ll_addr[1],
+		    nic_request.body.mac_request.mac_addr_2, ll_addr[2],
+		    nic_request.body.mac_request.mac_addr_3, ll_addr[3],
+		    nic_request.body.mac_request.mac_addr_4, ll_addr[4],
+		    nic_request.body.mac_request.mac_addr_5, ll_addr[5] );
+
+	/* Post descriptor */
+	phantom_post_cds ( phantom, &cds );
+
+	return 0;
+}
+
+/**
+ * Add MAC address
+ *
+ * @v phantom		Phantom NIC
+ * @v ll_addr		MAC address to add or remove
+ * @ret rc		Return status code
+ */
+static inline int phantom_add_macaddr ( struct phantom_nic *phantom,
+					const uint8_t *ll_addr ) {
+
+	DBGC ( phantom, "Phantom %p adding MAC address %s\n",
+	       phantom, eth_ntoa ( ll_addr ) );
+
+	return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD );
+}
+
+/**
+ * Remove MAC address
+ *
+ * @v phantom		Phantom NIC
+ * @v ll_addr		MAC address to add or remove
+ * @ret rc		Return status code
+ */
+static inline int phantom_del_macaddr ( struct phantom_nic *phantom,
+					const uint8_t *ll_addr ) {
+
+	DBGC ( phantom, "Phantom %p removing MAC address %s\n",
+	       phantom, eth_ntoa ( ll_addr ) );
+
+	return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL );
+}
+
+/***************************************************************************
+ *
+ * Link state detection
+ *
+ */
+
+/**
+ * Poll link state
+ *
+ * @v netdev		Network device
+ */
+static void phantom_poll_link_state ( struct net_device *netdev ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	uint32_t xg_state_p3;
+	unsigned int link;
+
+	/* Read link state */
+	xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 );
+
+	/* If there is no change, do nothing */
+	if ( phantom->link_state == xg_state_p3 )
+		return;
+
+	/* Record new link state */
+	DBGC ( phantom, "Phantom %p new link state %08x (was %08x)\n",
+	       phantom, xg_state_p3, phantom->link_state );
+	phantom->link_state = xg_state_p3;
+
+	/* Indicate link state to iPXE */
+	link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port,
+					      phantom->link_state );
+	switch ( link ) {
+	case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
+		DBGC ( phantom, "Phantom %p link is up\n", phantom );
+		netdev_link_up ( netdev );
+		break;
+	case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
+		DBGC ( phantom, "Phantom %p link is down\n", phantom );
+		netdev_link_down ( netdev );
+		break;
+	default:
+		DBGC ( phantom, "Phantom %p bad link state %d\n",
+		       phantom, link );
+		break;
+	}
+}
+
+/***************************************************************************
+ *
+ * Main driver body
+ *
+ */
+
+/**
+ * Refill descriptor ring
+ *
+ * @v netdev		Net device
+ */
+static void phantom_refill_rx_ring ( struct net_device *netdev ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	struct io_buffer *iobuf;
+	struct phantom_rds rds;
+	unsigned int handle;
+	int index;
+
+	for ( handle = 0 ; handle < PHN_RDS_MAX_FILL ; handle++ ) {
+
+		/* Skip this index if the descriptor has not yet been
+		 * consumed.
+		 */
+		if ( phantom->rds_iobuf[handle] != NULL )
+			continue;
+
+		/* Allocate descriptor ring entry */
+		index = phantom_alloc_rds ( phantom );
+		assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS );
+		assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */
+
+		/* Try to allocate an I/O buffer */
+		iobuf = alloc_iob ( PHN_RX_BUFSIZE );
+		if ( ! iobuf ) {
+			/* Failure is non-fatal; we will retry later */
+			netdev_rx_err ( netdev, NULL, -ENOMEM );
+			break;
+		}
+
+		/* Fill descriptor ring entry */
+		memset ( &rds, 0, sizeof ( rds ) );
+		NX_FILL_2 ( &rds, 0,
+			    handle, handle,
+			    length, iob_len ( iobuf ) );
+		NX_FILL_1 ( &rds, 1,
+			    dma_addr, virt_to_bus ( iobuf->data ) );
+
+		/* Record I/O buffer */
+		assert ( phantom->rds_iobuf[handle] == NULL );
+		phantom->rds_iobuf[handle] = iobuf;
+
+		/* Post descriptor */
+		phantom_post_rds ( phantom, &rds );
+	}
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int phantom_open ( struct net_device *netdev ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	int rc;
+
+	/* Allocate and zero descriptor rings */
+	phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ),
+					  UNM_DMA_BUFFER_ALIGN );
+	if ( ! phantom->desc ) {
+		rc = -ENOMEM;
+		goto err_alloc_desc;
+	}
+	memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) );
+
+	/* Create RX context */
+	if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 )
+		goto err_create_rx_ctx;
+
+	/* Create TX context */
+	if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 )
+		goto err_create_tx_ctx;
+
+	/* Fill the RX descriptor ring */
+	phantom_refill_rx_ring ( netdev );
+
+	/* Add MAC addresses
+	 *
+	 * BUG5583
+	 *
+	 * We would like to be able to enable receiving all multicast
+	 * packets (or, failing that, promiscuous mode), but the
+	 * firmware doesn't currently support this.
+	 */
+	if ( ( rc = phantom_add_macaddr ( phantom,
+					  netdev->ll_broadcast ) ) != 0 )
+		goto err_add_macaddr_broadcast;
+	if ( ( rc = phantom_add_macaddr ( phantom,
+					  netdev->ll_addr ) ) != 0 )
+		goto err_add_macaddr_unicast;
+
+	return 0;
+
+	phantom_del_macaddr ( phantom, netdev->ll_addr );
+ err_add_macaddr_unicast:
+	phantom_del_macaddr ( phantom, netdev->ll_broadcast );
+ err_add_macaddr_broadcast:
+	phantom_destroy_tx_ctx ( phantom );
+ err_create_tx_ctx:
+	phantom_destroy_rx_ctx ( phantom );
+ err_create_rx_ctx:
+	free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+	phantom->desc = NULL;
+ err_alloc_desc:
+	return rc;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void phantom_close ( struct net_device *netdev ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	struct io_buffer *iobuf;
+	unsigned int i;
+
+	/* Shut down the port */
+	phantom_del_macaddr ( phantom, netdev->ll_addr );
+	phantom_del_macaddr ( phantom, netdev->ll_broadcast );
+	phantom_destroy_tx_ctx ( phantom );
+	phantom_destroy_rx_ctx ( phantom );
+	free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+	phantom->desc = NULL;
+
+	/* Flush any uncompleted descriptors */
+	for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) {
+		iobuf = phantom->rds_iobuf[i];
+		if ( iobuf ) {
+			free_iob ( iobuf );
+			phantom->rds_iobuf[i] = NULL;
+		}
+	}
+	for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) {
+		iobuf = phantom->cds_iobuf[i];
+		if ( iobuf ) {
+			netdev_tx_complete_err ( netdev, iobuf, -ECANCELED );
+			phantom->cds_iobuf[i] = NULL;
+		}
+	}
+}
+
+/** 
+ * Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int phantom_transmit ( struct net_device *netdev,
+			      struct io_buffer *iobuf ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	union phantom_cds cds;
+	int index;
+
+	/* Get descriptor ring entry */
+	index = phantom_alloc_cds ( phantom );
+	if ( index < 0 )
+		return index;
+
+	/* Fill descriptor ring entry */
+	memset ( &cds, 0, sizeof ( cds ) );
+	NX_FILL_3 ( &cds, 0,
+		    tx.opcode, UNM_TX_ETHER_PKT,
+		    tx.num_buffers, 1,
+		    tx.length, iob_len ( iobuf ) );
+	NX_FILL_2 ( &cds, 2,
+		    tx.port, phantom->port,
+		    tx.context_id, phantom->port );
+	NX_FILL_1 ( &cds, 4,
+		    tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) );
+	NX_FILL_1 ( &cds, 5,
+		    tx.buffer1_length, iob_len ( iobuf ) );
+
+	/* Record I/O buffer */
+	assert ( phantom->cds_iobuf[index] == NULL );
+	phantom->cds_iobuf[index] = iobuf;
+
+	/* Post descriptor */
+	phantom_post_cds ( phantom, &cds );
+
+	return 0;
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void phantom_poll ( struct net_device *netdev ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+	struct io_buffer *iobuf;
+	unsigned int irq_vector;
+	unsigned int irq_state;
+	unsigned int cds_consumer_idx;
+	unsigned int raw_new_cds_consumer_idx;
+	unsigned int new_cds_consumer_idx;
+	unsigned int rds_consumer_idx;
+	unsigned int sds_consumer_idx;
+	struct phantom_sds *sds;
+	unsigned int sds_handle;
+	unsigned int sds_opcode;
+
+	/* Occasionally poll the link state */
+	if ( phantom->link_poll_timer-- == 0 ) {
+		phantom_poll_link_state ( netdev );
+		/* Reset the link poll timer */
+		phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
+	}
+
+	/* Check for interrupts */
+	if ( phantom->sds_irq_enabled ) {
+
+		/* Do nothing unless an interrupt is asserted */
+		irq_vector = phantom_readl ( phantom, UNM_PCIE_IRQ_VECTOR );
+		if ( ! ( irq_vector & UNM_PCIE_IRQ_VECTOR_BIT( phantom->port )))
+			return;
+
+		/* Do nothing unless interrupt state machine has stabilised */
+		irq_state = phantom_readl ( phantom, UNM_PCIE_IRQ_STATE );
+		if ( ! UNM_PCIE_IRQ_STATE_TRIGGERED ( irq_state ) )
+			return;
+
+		/* Acknowledge interrupt */
+		phantom_writel ( phantom, UNM_PCIE_IRQ_STATUS_MAGIC,
+				 phantom_irq_status_reg[phantom->port] );
+		phantom_readl ( phantom, UNM_PCIE_IRQ_VECTOR );
+	}
+
+	/* Check for TX completions */
+	cds_consumer_idx = phantom->cds_consumer_idx;
+	raw_new_cds_consumer_idx = phantom->desc->cmd_cons;
+	new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx );
+	while ( cds_consumer_idx != new_cds_consumer_idx ) {
+		DBGC2 ( phantom, "Phantom %p CDS %d complete\n",
+			phantom, cds_consumer_idx );
+		/* Completions may be for commands other than TX, so
+		 * there may not always be an associated I/O buffer.
+		 */
+		if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) {
+			netdev_tx_complete ( netdev, iobuf );
+			phantom->cds_iobuf[cds_consumer_idx] = NULL;
+		}
+		cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS );
+		phantom->cds_consumer_idx = cds_consumer_idx;
+	}
+
+	/* Check for received packets */
+	rds_consumer_idx = phantom->rds_consumer_idx;
+	sds_consumer_idx = phantom->sds_consumer_idx;
+	while ( 1 ) {
+		sds = &phantom->desc->sds[sds_consumer_idx];
+		if ( NX_GET ( sds, owner ) == 0 )
+			break;
+
+		DBGC2 ( phantom, "Phantom %p SDS %d status:\n",
+			phantom, sds_consumer_idx );
+		DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) );
+
+		/* Check received opcode */
+		sds_opcode = NX_GET ( sds, opcode );
+		if ( ( sds_opcode == UNM_RXPKT_DESC ) ||
+		     ( sds_opcode == UNM_SYN_OFFLOAD ) ) {
+
+			/* Sanity check: ensure that all of the SDS
+			 * descriptor has been written.
+			 */
+			if ( NX_GET ( sds, total_length ) == 0 ) {
+				DBGC ( phantom, "Phantom %p SDS %d "
+				       "incomplete; deferring\n",
+				       phantom, sds_consumer_idx );
+				/* Leave for next poll() */
+				break;
+			}
+
+			/* Process received packet */
+			sds_handle = NX_GET ( sds, handle );
+			iobuf = phantom->rds_iobuf[sds_handle];
+			assert ( iobuf != NULL );
+			iob_put ( iobuf, NX_GET ( sds, total_length ) );
+			iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) );
+			DBGC2 ( phantom, "Phantom %p RDS %d complete\n",
+				phantom, sds_handle );
+			netdev_rx ( netdev, iobuf );
+			phantom->rds_iobuf[sds_handle] = NULL;
+
+			/* Update RDS consumer counter.  This is a
+			 * lower bound for the number of descriptors
+			 * that have been read by the hardware, since
+			 * the hardware must have read at least one
+			 * descriptor for each completion that we
+			 * receive.
+			 */
+			rds_consumer_idx =
+				( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
+			phantom->rds_consumer_idx = rds_consumer_idx;
+
+		} else {
+
+			DBGC ( phantom, "Phantom %p unexpected SDS opcode "
+			       "%02x\n", phantom, sds_opcode );
+			DBGC_HDA ( phantom, virt_to_bus ( sds ),
+				   sds, sizeof ( *sds ) );
+		}
+			
+		/* Clear status descriptor */
+		memset ( sds, 0, sizeof ( *sds ) );
+
+		/* Update SDS consumer index */
+		sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS );
+		phantom->sds_consumer_idx = sds_consumer_idx;
+		wmb();
+		phantom_writel ( phantom, phantom->sds_consumer_idx,
+				 phantom->sds_consumer_crb );
+	}
+
+	/* Refill the RX descriptor ring */
+	phantom_refill_rx_ring ( netdev );
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev	Network device
+ * @v enable	Interrupts should be enabled
+ */
+static void phantom_irq ( struct net_device *netdev, int enable ) {
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+
+	phantom_writel ( phantom, ( enable ? 1 : 0 ),
+			 phantom->sds_irq_mask_crb );
+	phantom_writel ( phantom, UNM_PCIE_IRQ_MASK_MAGIC,
+			 phantom_irq_mask_reg[phantom->port] );
+	phantom->sds_irq_enabled = enable;
+}
+
+/** Phantom net device operations */
+static struct net_device_operations phantom_operations = {
+	.open		= phantom_open,
+	.close		= phantom_close,
+	.transmit	= phantom_transmit,
+	.poll		= phantom_poll,
+	.irq		= phantom_irq,
+};
+
+/***************************************************************************
+ *
+ * CLP settings
+ *
+ */
+
+/** Phantom CLP settings tag magic */
+#define PHN_CLP_TAG_MAGIC 0xc19c1900UL
+
+/** Phantom CLP settings tag magic mask */
+#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL
+
+/** Phantom CLP data
+ *
+ */
+union phantom_clp_data {
+	/** Data bytes
+	 *
+	 * This field is right-aligned; if only N bytes are present
+	 * then bytes[0]..bytes[7-N] should be zero, and the data
+	 * should be in bytes[7-N+1] to bytes[7];
+	 */
+	uint8_t bytes[8];
+	/** Dwords for the CLP interface */
+	struct {
+		/** High dword, in network byte order */
+		uint32_t hi;
+		/** Low dword, in network byte order */
+		uint32_t lo;
+	} dwords;
+};
+#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) )
+
+/**
+ * Wait for Phantom CLP command to complete
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_clp_wait ( struct phantom_nic *phantom ) {
+	unsigned int retries;
+	uint32_t status;
+
+	for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) {
+		status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+		if ( status & UNM_CAM_RAM_CLP_STATUS_DONE )
+			return 0;
+		mdelay ( 1 );
+	}
+
+	DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n",
+	       phantom );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Issue Phantom CLP command
+ *
+ * @v phantom		Phantom NIC
+ * @v port		Virtual port number
+ * @v opcode		Opcode
+ * @v data_in		Data in, or NULL
+ * @v data_out		Data out, or NULL
+ * @v offset		Offset within data
+ * @v len		Data buffer length
+ * @ret len		Total transfer length (for reads), or negative error
+ */
+static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port,
+			     unsigned int opcode, const void *data_in,
+			     void *data_out, size_t offset, size_t len ) {
+	union phantom_clp_data data;
+	unsigned int index = ( offset / sizeof ( data ) );
+	unsigned int last = 0;
+	size_t in_frag_len;
+	uint8_t *in_frag;
+	uint32_t command;
+	uint32_t status;
+	size_t read_len;
+	unsigned int error;
+	size_t out_frag_len;
+	uint8_t *out_frag;
+	int rc;
+
+	/* Sanity checks */
+	assert ( ( offset % sizeof ( data ) ) == 0 );
+	if ( len > 255 ) {
+		DBGC ( phantom, "Phantom %p invalid CLP length %zd\n",
+		       phantom, len );
+		return -EINVAL;
+	}
+
+	/* Check that CLP interface is ready */
+	if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+		return rc;
+
+	/* Copy data in */
+	memset ( &data, 0, sizeof ( data ) );
+	if ( data_in ) {
+		assert ( offset < len );
+		in_frag_len = ( len - offset );
+		if ( in_frag_len > sizeof ( data ) ) {
+			in_frag_len = sizeof ( data );
+		} else {
+			last = 1;
+		}
+		in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ];
+		memcpy ( in_frag, ( data_in + offset ), in_frag_len );
+		phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ),
+				 UNM_CAM_RAM_CLP_DATA_LO );
+		phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ),
+				 UNM_CAM_RAM_CLP_DATA_HI );
+	}
+
+	/* Issue CLP command */
+	command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) |
+		    ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) );
+	phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND );
+	mb();
+	phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START,
+			 UNM_CAM_RAM_CLP_STATUS );
+
+	/* Wait for command to complete */
+	if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+		return rc;
+
+	/* Get command status */
+	status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+	read_len = ( ( status >> 16 ) & 0xff );
+	error = ( ( status >> 8 ) & 0xff );
+	if ( error ) {
+		DBGC ( phantom, "Phantom %p CLP command error %02x\n",
+		       phantom, error );
+		return -EIO;
+	}
+
+	/* Copy data out */
+	if ( data_out ) {
+		data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom,
+						  UNM_CAM_RAM_CLP_DATA_LO ) );
+		data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom,
+						  UNM_CAM_RAM_CLP_DATA_HI ) );
+		out_frag_len = ( read_len - offset );
+		if ( out_frag_len > sizeof ( data ) )
+			out_frag_len = sizeof ( data );
+		out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ];
+		if ( out_frag_len > ( len - offset ) )
+			out_frag_len = ( len - offset );
+		memcpy ( ( data_out + offset ), out_frag, out_frag_len );
+	}
+
+	return read_len;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v phantom		Phantom NIC
+ * @v port		Virtual port number
+ * @v setting		Setting number
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port,
+			       unsigned int setting, const void *data,
+			       size_t len ) {
+	unsigned int opcode = setting;
+	size_t offset;
+	int rc;
+
+	for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) {
+		if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data,
+					      NULL, offset, len ) ) < 0 )
+			return rc;
+	}
+	return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v phantom		Phantom NIC
+ * @v port		Virtual port number
+ * @v setting		Setting number
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret len		Length of setting, or negative error
+ */
+static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port,
+			       unsigned int setting, void *data, size_t len ) {
+	unsigned int opcode = ( setting + 1 );
+	size_t offset = 0;
+	int read_len;
+
+	while ( 1 ) {
+		read_len = phantom_clp_cmd ( phantom, port, opcode, NULL,
+					     data, offset, len );
+		if ( read_len < 0 )
+			return read_len;
+		offset += PHN_CLP_BLKSIZE;
+		if ( offset >= ( unsigned ) read_len )
+			break;
+		if ( offset >= len )
+			break;
+	}
+	return read_len;
+}
+
+/** A Phantom CLP setting */
+struct phantom_clp_setting {
+	/** iPXE setting */
+	struct setting *setting;
+	/** Setting number */
+	unsigned int clp_setting;
+};
+
+/** Phantom CLP settings */
+static struct phantom_clp_setting clp_settings[] = {
+	{ &mac_setting, 0x01 },
+};
+
+/**
+ * Find Phantom CLP setting
+ *
+ * @v setting		iPXE setting
+ * @v clp_setting	Setting number, or 0 if not found
+ */
+static unsigned int
+phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
+	struct phantom_clp_setting *clp_setting;
+	unsigned int i;
+
+	/* Search the list of explicitly-defined settings */
+	for ( i = 0 ; i < ( sizeof ( clp_settings ) /
+			    sizeof ( clp_settings[0] ) ) ; i++ ) {
+		clp_setting = &clp_settings[i];
+		if ( setting_cmp ( setting, clp_setting->setting ) == 0 )
+			return clp_setting->clp_setting;
+	}
+
+	/* Allow for use of numbered settings */
+	if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC )
+		return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK );
+
+	DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n",
+		phantom, setting->name );
+
+	return 0;
+}
+
+/**
+ * Check applicability of Phantom CLP setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int phantom_setting_applies ( struct settings *settings,
+				     struct setting *setting ) {
+	struct phantom_nic *phantom =
+		container_of ( settings, struct phantom_nic, settings );
+	unsigned int clp_setting;
+
+	/* Find Phantom setting equivalent to iPXE setting */
+	clp_setting = phantom_clp_setting ( phantom, setting );
+	return ( clp_setting != 0 );
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int phantom_store_setting ( struct settings *settings,
+				   struct setting *setting,
+				   const void *data, size_t len ) {
+	struct phantom_nic *phantom =
+		container_of ( settings, struct phantom_nic, settings );
+	unsigned int clp_setting;
+	int rc;
+
+	/* Find Phantom setting equivalent to iPXE setting */
+	clp_setting = phantom_clp_setting ( phantom, setting );
+	assert ( clp_setting != 0 );
+
+	/* Store setting */
+	if ( ( rc = phantom_clp_store ( phantom, phantom->port,
+					clp_setting, data, len ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not store setting \"%s\": "
+		       "%s\n", phantom, setting->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+static int phantom_fetch_setting ( struct settings *settings,
+				   struct setting *setting,
+				   void *data, size_t len ) {
+	struct phantom_nic *phantom =
+		container_of ( settings, struct phantom_nic, settings );
+	unsigned int clp_setting;
+	int read_len;
+	int rc;
+
+	/* Find Phantom setting equivalent to iPXE setting */
+	clp_setting = phantom_clp_setting ( phantom, setting );
+	assert ( clp_setting != 0 );
+
+	/* Fetch setting */
+	if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port,
+					      clp_setting, data, len ) ) < 0 ){
+		rc = read_len;
+		DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": "
+		       "%s\n", phantom, setting->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return read_len;
+}
+
+/** Phantom CLP settings operations */
+static struct settings_operations phantom_settings_operations = {
+	.applies	= phantom_setting_applies,
+	.store		= phantom_store_setting,
+	.fetch		= phantom_fetch_setting,
+};
+
+/***************************************************************************
+ *
+ * Initialisation
+ *
+ */
+
+/**
+ * Map Phantom CRB window
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_map_crb ( struct phantom_nic *phantom,
+			     struct pci_device *pci ) {
+	unsigned long bar0_start;
+	unsigned long bar0_size;
+
+	bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 );
+	bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 );
+	DBGC ( phantom, "Phantom %p is " PCI_FMT " with BAR0 at %08lx+%lx\n",
+	       phantom, PCI_ARGS ( pci ), bar0_start, bar0_size );
+
+	if ( ! bar0_start ) {
+		DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n",
+		       phantom );
+		return -EINVAL;
+	}
+
+	switch ( bar0_size ) {
+	case ( 128 * 1024 * 1024 ) :
+		DBGC ( phantom, "Phantom %p has 128MB BAR\n", phantom );
+		phantom->crb_access = phantom_crb_access_128m;
+		break;
+	case ( 32 * 1024 * 1024 ) :
+		DBGC ( phantom, "Phantom %p has 32MB BAR\n", phantom );
+		phantom->crb_access = phantom_crb_access_32m;
+		break;
+	case ( 2 * 1024 * 1024 ) :
+		DBGC ( phantom, "Phantom %p has 2MB BAR\n", phantom );
+		phantom->crb_access = phantom_crb_access_2m;
+		break;
+	default:
+		DBGC ( phantom, "Phantom %p has bad BAR size\n", phantom );
+		return -EINVAL;
+	}
+
+	phantom->bar0 = ioremap ( bar0_start, bar0_size );
+	if ( ! phantom->bar0 ) {
+		DBGC ( phantom, "Phantom %p could not map BAR0\n", phantom );
+		return -EIO;
+	}
+
+	/* Mark current CRB window as invalid, so that the first
+	 * read/write will set the current window.
+	 */
+	phantom->crb_window = -1UL;
+
+	return 0;
+}
+
+/**
+ * Unhalt all PEGs
+ *
+ * @v phantom		Phantom NIC
+ */
+static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) {
+	uint32_t halt_status;
+
+	halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS );
+	phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS );
+	halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS );
+	phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS );
+	halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS );
+	phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS );
+	halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS );
+	phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS );
+	halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS );
+	phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS );
+}
+
+/**
+ * Initialise the Phantom command PEG
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
+	uint32_t cold_boot;
+	uint32_t sw_reset;
+	unsigned int retries;
+	uint32_t cmdpeg_state;
+	uint32_t last_cmdpeg_state = 0;
+
+	/* Check for a previous initialisation.  This could have
+	 * happened if, for example, the BIOS used the UNDI API to
+	 * drive the NIC prior to a full PXE boot.
+	 */
+	cmdpeg_state = phantom_readl ( phantom, UNM_NIC_REG_CMDPEG_STATE );
+	if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
+		DBGC ( phantom, "Phantom %p command PEG already initialized\n",
+		       phantom );
+		/* Unhalt the PEGs.  Previous firmware (e.g. BOFM) may
+		 * have halted the PEGs to prevent internal bus
+		 * collisions when the BIOS re-reads the expansion ROM.
+		 */
+		phantom_unhalt_pegs ( phantom );
+		return 0;
+	}
+
+	/* If this was a cold boot, check that the hardware came up ok */
+	cold_boot = phantom_readl ( phantom, UNM_CAM_RAM_COLD_BOOT );
+	if ( cold_boot == UNM_CAM_RAM_COLD_BOOT_MAGIC ) {
+		DBGC ( phantom, "Phantom %p coming up from cold boot\n",
+		       phantom );
+		sw_reset = phantom_readl ( phantom, UNM_ROMUSB_GLB_SW_RESET );
+		if ( sw_reset != UNM_ROMUSB_GLB_SW_RESET_MAGIC ) {
+			DBGC ( phantom, "Phantom %p reset failed: %08x\n",
+			       phantom, sw_reset );
+			return -EIO;
+		}
+	} else {
+		DBGC ( phantom, "Phantom %p coming up from warm boot "
+		       "(%08x)\n", phantom, cold_boot );
+	}
+	/* Clear cold-boot flag */
+	phantom_writel ( phantom, 0, UNM_CAM_RAM_COLD_BOOT );
+
+	/* Set port modes */
+	phantom_writel ( phantom, UNM_CAM_RAM_PORT_MODE_AUTO_NEG_1G,
+			 UNM_CAM_RAM_WOL_PORT_MODE );
+
+	/* Pass dummy DMA area to card */
+	phantom_write_hilo ( phantom, 0,
+			     UNM_NIC_REG_DUMMY_BUF_ADDR_LO,
+			     UNM_NIC_REG_DUMMY_BUF_ADDR_HI );
+	phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT,
+			 UNM_NIC_REG_DUMMY_BUF );
+
+	/* Tell the hardware that tuning is complete */
+	phantom_writel ( phantom, UNM_ROMUSB_GLB_PEGTUNE_DONE_MAGIC,
+			 UNM_ROMUSB_GLB_PEGTUNE_DONE );
+
+	/* Wait for command PEG to finish initialising */
+	DBGC ( phantom, "Phantom %p initialising command PEG (will take up to "
+	       "%d seconds)...\n", phantom, PHN_CMDPEG_INIT_TIMEOUT_SEC );
+	for ( retries = 0; retries < PHN_CMDPEG_INIT_TIMEOUT_SEC; retries++ ) {
+		cmdpeg_state = phantom_readl ( phantom,
+					       UNM_NIC_REG_CMDPEG_STATE );
+		if ( cmdpeg_state != last_cmdpeg_state ) {
+			DBGC ( phantom, "Phantom %p command PEG state is "
+			       "%08x after %d seconds...\n",
+			       phantom, cmdpeg_state, retries );
+			last_cmdpeg_state = cmdpeg_state;
+		}
+		if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZED ) {
+			/* Acknowledge the PEG initialisation */
+			phantom_writel ( phantom,
+				       UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK,
+				       UNM_NIC_REG_CMDPEG_STATE );
+			return 0;
+		}
+		mdelay ( 1000 );
+	}
+
+	DBGC ( phantom, "Phantom %p timed out waiting for command PEG to "
+	       "initialise (status %08x)\n", phantom, cmdpeg_state );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Read Phantom MAC address
+ *
+ * @v phanton_port	Phantom NIC
+ * @v hw_addr		Buffer to fill with MAC address
+ */
+static void phantom_get_macaddr ( struct phantom_nic *phantom,
+				  uint8_t *hw_addr ) {
+	union {
+		uint8_t mac_addr[2][ETH_ALEN];
+		uint32_t dwords[3];
+	} u;
+	unsigned long offset;
+	int i;
+
+	/* Read the three dwords that include this MAC address and one other */
+	offset = ( UNM_CAM_RAM_MAC_ADDRS +
+		   ( 12 * ( phantom->port / 2 ) ) );
+	for ( i = 0 ; i < 3 ; i++, offset += 4 ) {
+		u.dwords[i] = phantom_readl ( phantom, offset );
+	}
+
+	/* Copy out the relevant MAC address */
+	for ( i = 0 ; i < ETH_ALEN ; i++ ) {
+		hw_addr[ ETH_ALEN - i - 1 ] =
+			u.mac_addr[ phantom->port & 1 ][i];
+	}
+	DBGC ( phantom, "Phantom %p MAC address is %s\n",
+	       phantom, eth_ntoa ( hw_addr ) );
+}
+
+/**
+ * Check Phantom is enabled for boot
+ *
+ * @v phanton_port	Phantom NIC
+ * @ret rc		Return status code
+ *
+ * This is something of an ugly hack to accommodate an OEM
+ * requirement.  The NIC has only one expansion ROM BAR, rather than
+ * one per port.  To allow individual ports to be selectively
+ * enabled/disabled for PXE boot (as required), we must therefore
+ * leave the expansion ROM always enabled, and place the per-port
+ * enable/disable logic within the iPXE driver.
+ */
+static int phantom_check_boot_enable ( struct phantom_nic *phantom ) {
+	unsigned long boot_enable;
+
+	boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE );
+	if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) {
+		DBGC ( phantom, "Phantom %p PXE boot is disabled\n",
+		       phantom );
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+/**
+ * Initialise Phantom receive PEG
+ *
+ * @v phantom		Phantom NIC
+ * @ret rc		Return status code
+ */
+static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
+	unsigned int retries;
+	uint32_t rcvpeg_state;
+	uint32_t last_rcvpeg_state = 0;
+
+	DBGC ( phantom, "Phantom %p initialising receive PEG (will take up to "
+	       "%d seconds)...\n", phantom, PHN_RCVPEG_INIT_TIMEOUT_SEC );
+	for ( retries = 0; retries < PHN_RCVPEG_INIT_TIMEOUT_SEC; retries++ ) {
+		rcvpeg_state = phantom_readl ( phantom,
+					       UNM_NIC_REG_RCVPEG_STATE );
+		if ( rcvpeg_state != last_rcvpeg_state ) {
+			DBGC ( phantom, "Phantom %p receive PEG state is "
+			       "%08x after %d seconds...\n",
+			       phantom, rcvpeg_state, retries );
+			last_rcvpeg_state = rcvpeg_state;
+		}
+		if ( rcvpeg_state == UNM_NIC_REG_RCVPEG_STATE_INITIALIZED )
+			return 0;
+		mdelay ( 1000 );
+	}
+
+	DBGC ( phantom, "Phantom %p timed out waiting for receive PEG to "
+	       "initialise (status %08x)\n", phantom, rcvpeg_state );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int phantom_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct phantom_nic *phantom;
+	struct settings *parent_settings;
+	int rc;
+
+	/* Allocate Phantom device */
+	netdev = alloc_etherdev ( sizeof ( *phantom ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+	netdev_init ( netdev, &phantom_operations );
+	phantom = netdev_priv ( netdev );
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( phantom, 0, sizeof ( *phantom ) );
+	phantom->port = PCI_FUNC ( pci->busdevfn );
+	assert ( phantom->port < PHN_MAX_NUM_PORTS );
+	settings_init ( &phantom->settings,
+			&phantom_settings_operations,
+			&netdev->refcnt, PHN_CLP_TAG_MAGIC );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map CRB */
+	if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 )
+		goto err_map_crb;
+
+	/* BUG5945 - need to hack PCI config space on P3 B1 silicon.
+	 * B2 will have this fixed; remove this hack when B1 is no
+	 * longer in use.
+	 */
+	if ( PCI_FUNC ( pci->busdevfn ) == 0 ) {
+		unsigned int i;
+		for ( i = 0 ; i < 8 ; i++ ) {
+			uint32_t temp;
+			pci->busdevfn =
+				PCI_BUSDEVFN ( PCI_BUS ( pci->busdevfn ),
+					       PCI_SLOT ( pci->busdevfn ), i );
+			pci_read_config_dword ( pci, 0xc8, &temp );
+			pci_read_config_dword ( pci, 0xc8, &temp );
+			pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+		}
+		pci->busdevfn = PCI_BUSDEVFN ( PCI_BUS ( pci->busdevfn ),
+					       PCI_SLOT ( pci->busdevfn ), 0 );
+	}
+
+	/* Initialise the command PEG */
+	if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 )
+		goto err_init_cmdpeg;
+
+	/* Initialise the receive PEG */
+	if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 )
+		goto err_init_rcvpeg;
+
+	/* Read MAC addresses */
+	phantom_get_macaddr ( phantom, netdev->hw_addr );
+
+	/* Skip if boot disabled on NIC */
+	if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 )
+		goto err_check_boot_enable;
+
+	/* Register network devices */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not register net device: "
+		       "%s\n", phantom, strerror ( rc ) );
+		goto err_register_netdev;
+	}
+
+	/* Register settings blocks */
+	parent_settings = netdev_settings ( netdev );
+	if ( ( rc = register_settings ( &phantom->settings,
+					parent_settings, "clp" ) ) != 0 ) {
+		DBGC ( phantom, "Phantom %p could not register settings: "
+		       "%s\n", phantom, strerror ( rc ) );
+		goto err_register_settings;
+	}
+
+	return 0;
+
+	unregister_settings ( &phantom->settings );
+ err_register_settings:
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_check_boot_enable:
+ err_init_rcvpeg:
+ err_init_cmdpeg:
+ err_map_crb:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc_etherdev:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void phantom_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct phantom_nic *phantom = netdev_priv ( netdev );
+
+	unregister_settings ( &phantom->settings );
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** Phantom PCI IDs */
+static struct pci_device_id phantom_nics[] = {
+	PCI_ROM ( 0x4040, 0x0100, "nx", "NX", 0 ),
+};
+
+/** Phantom PCI driver */
+struct pci_driver phantom_driver __pci_driver = {
+	.ids = phantom_nics,
+	.id_count = ( sizeof ( phantom_nics ) / sizeof ( phantom_nics[0] ) ),
+	.probe = phantom_probe,
+	.remove = phantom_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.h
new file mode 100644
index 0000000..a55f32f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom.h
@@ -0,0 +1,212 @@
+#ifndef _PHANTOM_H
+#define _PHANTOM_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ * Copyright (C) 2008 NetXen, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * NetXen Phantom NICs
+ *
+ */
+
+#include <stdint.h>
+
+/* Drag in hardware definitions */
+#include "nx_bitops.h"
+#include "phantom_hw.h"
+struct phantom_rds { NX_PSEUDO_BIT_STRUCT ( struct phantom_rds_pb ) };
+struct phantom_sds { NX_PSEUDO_BIT_STRUCT ( struct phantom_sds_pb ) };
+union phantom_cds { NX_PSEUDO_BIT_STRUCT ( union phantom_cds_pb ) };
+
+/* Drag in firmware interface definitions */
+typedef uint8_t U8;
+typedef uint16_t U16;
+typedef uint32_t U32;
+typedef uint64_t U64;
+typedef uint32_t nx_rcode_t;
+#define NXHAL_VERSION 1
+#include "nxhal_nic_interface.h"
+
+/** DMA buffer alignment */
+#define UNM_DMA_BUFFER_ALIGN 16
+
+/** Mark structure as DMA-aligned */
+#define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) ))
+
+/******************************************************************************
+ *
+ * Register definitions
+ *
+ */
+
+#define UNM_128M_CRB_WINDOW		0x6110210UL
+#define UNM_32M_CRB_WINDOW		0x0110210UL
+#define UNM_2M_CRB_WINDOW		0x0130060UL
+
+/**
+ * Phantom register blocks
+ *
+ * The upper address bits vary between cards.  We define an abstract
+ * address space in which the upper 8 bits of the 32-bit register
+ * address encode the register block.  This gets translated to a bus
+ * address by the phantom_crb_access_xxx() methods.
+ */
+enum unm_reg_blocks {
+	UNM_CRB_BLK_PCIE	= 0x01,
+	UNM_CRB_BLK_CAM		= 0x22,
+	UNM_CRB_BLK_ROMUSB	= 0x33,
+	UNM_CRB_BLK_TEST	= 0x02,
+	UNM_CRB_BLK_PEG_0	= 0x11,
+	UNM_CRB_BLK_PEG_1	= 0x12,
+	UNM_CRB_BLK_PEG_2	= 0x13,
+	UNM_CRB_BLK_PEG_3	= 0x14,
+	UNM_CRB_BLK_PEG_4	= 0x0f,
+};
+#define UNM_CRB_BASE(blk)		( (blk) << 20 )
+#define UNM_CRB_BLK(reg)		( (reg) >> 20 )
+#define UNM_CRB_OFFSET(reg)		( (reg) & 0x000fffff )
+
+#define UNM_CRB_PCIE			UNM_CRB_BASE ( UNM_CRB_BLK_PCIE )
+#define UNM_PCIE_SEM2_LOCK		( UNM_CRB_PCIE + 0x1c010 )
+#define UNM_PCIE_SEM2_UNLOCK		( UNM_CRB_PCIE + 0x1c014 )
+#define UNM_PCIE_IRQ_VECTOR		( UNM_CRB_PCIE + 0x10100 )
+#define UNM_PCIE_IRQ_VECTOR_BIT(n)		( 1 << ( (n) + 7 ) )
+#define UNM_PCIE_IRQ_STATE		( UNM_CRB_PCIE + 0x1206c )
+#define UNM_PCIE_IRQ_STATE_TRIGGERED(state)	(( (state) & 0x300 ) == 0x200 )
+#define UNM_PCIE_IRQ_MASK_F0		( UNM_CRB_PCIE + 0x10128 )
+#define UNM_PCIE_IRQ_MASK_F1		( UNM_CRB_PCIE + 0x10170 )
+#define UNM_PCIE_IRQ_MASK_F2		( UNM_CRB_PCIE + 0x10174 )
+#define UNM_PCIE_IRQ_MASK_F3		( UNM_CRB_PCIE + 0x10178 )
+#define UNM_PCIE_IRQ_MASK_F4		( UNM_CRB_PCIE + 0x10370 )
+#define UNM_PCIE_IRQ_MASK_F5		( UNM_CRB_PCIE + 0x10374 )
+#define UNM_PCIE_IRQ_MASK_F6		( UNM_CRB_PCIE + 0x10378 )
+#define UNM_PCIE_IRQ_MASK_F7		( UNM_CRB_PCIE + 0x1037c )
+#define UNM_PCIE_IRQ_MASK_MAGIC			0x0000fbffUL
+#define UNM_PCIE_IRQ_STATUS_F0		( UNM_CRB_PCIE + 0x10118 )
+#define UNM_PCIE_IRQ_STATUS_F1		( UNM_CRB_PCIE + 0x10160 )
+#define UNM_PCIE_IRQ_STATUS_F2		( UNM_CRB_PCIE + 0x10164 )
+#define UNM_PCIE_IRQ_STATUS_F3		( UNM_CRB_PCIE + 0x10168 )
+#define UNM_PCIE_IRQ_STATUS_F4		( UNM_CRB_PCIE + 0x10360 )
+#define UNM_PCIE_IRQ_STATUS_F5		( UNM_CRB_PCIE + 0x10364 )
+#define UNM_PCIE_IRQ_STATUS_F6		( UNM_CRB_PCIE + 0x10368 )
+#define UNM_PCIE_IRQ_STATUS_F7		( UNM_CRB_PCIE + 0x1036c )
+#define UNM_PCIE_IRQ_STATUS_MAGIC		0xffffffffUL
+
+#define UNM_CRB_CAM			UNM_CRB_BASE ( UNM_CRB_BLK_CAM )
+
+#define UNM_CAM_RAM			( UNM_CRB_CAM + 0x02000 )
+#define UNM_CAM_RAM_PORT_MODE		( UNM_CAM_RAM + 0x00024 )
+#define UNM_CAM_RAM_PORT_MODE_AUTO_NEG		4
+#define UNM_CAM_RAM_PORT_MODE_AUTO_NEG_1G	5
+#define UNM_CAM_RAM_DMESG_HEAD(n)	( UNM_CAM_RAM + 0x00030 + (n) * 0x10 )
+#define UNM_CAM_RAM_DMESG_LEN(n)	( UNM_CAM_RAM + 0x00034 + (n) * 0x10 )
+#define UNM_CAM_RAM_DMESG_TAIL(n)	( UNM_CAM_RAM + 0x00038 + (n) * 0x10 )
+#define UNM_CAM_RAM_DMESG_SIG(n)	( UNM_CAM_RAM + 0x0003c + (n) * 0x10 )
+#define UNM_CAM_RAM_DMESG_SIG_MAGIC		0xcafebabeUL
+#define UNM_CAM_RAM_NUM_DMESG_BUFFERS		5
+#define UNM_CAM_RAM_CLP_COMMAND		( UNM_CAM_RAM + 0x000c0 )
+#define UNM_CAM_RAM_CLP_COMMAND_LAST		0x00000080UL
+#define UNM_CAM_RAM_CLP_DATA_LO		( UNM_CAM_RAM + 0x000c4 )
+#define UNM_CAM_RAM_CLP_DATA_HI		( UNM_CAM_RAM + 0x000c8 )
+#define UNM_CAM_RAM_CLP_STATUS		( UNM_CAM_RAM + 0x000cc )
+#define UNM_CAM_RAM_CLP_STATUS_START		0x00000001UL
+#define UNM_CAM_RAM_CLP_STATUS_DONE		0x00000002UL
+#define UNM_CAM_RAM_CLP_STATUS_ERROR		0x0000ff00UL
+#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED	0xffffffffUL
+#define UNM_CAM_RAM_BOOT_ENABLE		( UNM_CAM_RAM + 0x000fc )
+#define UNM_CAM_RAM_WOL_PORT_MODE	( UNM_CAM_RAM + 0x00198 )
+#define UNM_CAM_RAM_MAC_ADDRS		( UNM_CAM_RAM + 0x001c0 )
+#define UNM_CAM_RAM_COLD_BOOT		( UNM_CAM_RAM + 0x001fc )
+#define UNM_CAM_RAM_COLD_BOOT_MAGIC		0x55555555UL
+
+#define UNM_NIC_REG			( UNM_CRB_CAM + 0x02200 )
+#define UNM_NIC_REG_NX_CDRP		( UNM_NIC_REG + 0x00018 )
+#define UNM_NIC_REG_NX_ARG1		( UNM_NIC_REG + 0x0001c )
+#define UNM_NIC_REG_NX_ARG2		( UNM_NIC_REG + 0x00020 )
+#define UNM_NIC_REG_NX_ARG3		( UNM_NIC_REG + 0x00024 )
+#define UNM_NIC_REG_NX_SIGN		( UNM_NIC_REG + 0x00028 )
+#define UNM_NIC_REG_DUMMY_BUF_ADDR_HI	( UNM_NIC_REG + 0x0003c )
+#define UNM_NIC_REG_DUMMY_BUF_ADDR_LO	( UNM_NIC_REG + 0x00040 )
+#define UNM_NIC_REG_CMDPEG_STATE	( UNM_NIC_REG + 0x00050 )
+#define UNM_NIC_REG_CMDPEG_STATE_INITIALIZED	0xff01
+#define UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK	0xf00f
+#define UNM_NIC_REG_DUMMY_BUF		( UNM_NIC_REG + 0x000fc )
+#define UNM_NIC_REG_DUMMY_BUF_INIT		0
+#define UNM_NIC_REG_XG_STATE_P3		( UNM_NIC_REG + 0x00098 )
+#define UNM_NIC_REG_XG_STATE_P3_LINK( port, state_p3 ) \
+	( ( (state_p3) >> ( (port) * 4 ) ) & 0x0f )
+#define UNM_NIC_REG_XG_STATE_P3_LINK_UP		0x01
+#define UNM_NIC_REG_XG_STATE_P3_LINK_DOWN	0x02
+#define UNM_NIC_REG_RCVPEG_STATE	( UNM_NIC_REG + 0x0013c )
+#define UNM_NIC_REG_RCVPEG_STATE_INITIALIZED	0xff01
+
+#define UNM_CRB_ROMUSB			UNM_CRB_BASE ( UNM_CRB_BLK_ROMUSB )
+
+#define UNM_ROMUSB_GLB			( UNM_CRB_ROMUSB + 0x00000 )
+#define UNM_ROMUSB_GLB_STATUS		( UNM_ROMUSB_GLB + 0x00004 )
+#define UNM_ROMUSB_GLB_STATUS_ROM_DONE		( 1 << 1 )
+#define UNM_ROMUSB_GLB_SW_RESET		( UNM_ROMUSB_GLB + 0x00008 )
+#define UNM_ROMUSB_GLB_SW_RESET_MAGIC		0x0080000fUL
+#define UNM_ROMUSB_GLB_PEGTUNE_DONE	( UNM_ROMUSB_GLB + 0x0005c )
+#define UNM_ROMUSB_GLB_PEGTUNE_DONE_MAGIC	0x31
+
+#define UNM_ROMUSB_ROM			( UNM_CRB_ROMUSB + 0x10000 )
+#define UNM_ROMUSB_ROM_INSTR_OPCODE	( UNM_ROMUSB_ROM + 0x00004 )
+#define UNM_ROMUSB_ROM_ADDRESS		( UNM_ROMUSB_ROM + 0x00008 )
+#define UNM_ROMUSB_ROM_WDATA		( UNM_ROMUSB_ROM + 0x0000c )
+#define UNM_ROMUSB_ROM_ABYTE_CNT	( UNM_ROMUSB_ROM + 0x00010 )
+#define UNM_ROMUSB_ROM_DUMMY_BYTE_CNT	( UNM_ROMUSB_ROM + 0x00014 )
+#define UNM_ROMUSB_ROM_RDATA		( UNM_ROMUSB_ROM + 0x00018 )
+
+#define UNM_CRB_TEST			UNM_CRB_BASE ( UNM_CRB_BLK_TEST )
+
+#define UNM_TEST_CONTROL		( UNM_CRB_TEST + 0x00090 )
+#define UNM_TEST_CONTROL_START			0x01
+#define UNM_TEST_CONTROL_ENABLE			0x02
+#define UNM_TEST_CONTROL_BUSY			0x08
+#define UNM_TEST_ADDR_LO		( UNM_CRB_TEST + 0x00094 )
+#define UNM_TEST_ADDR_HI		( UNM_CRB_TEST + 0x00098 )
+#define UNM_TEST_RDDATA_LO		( UNM_CRB_TEST + 0x000a8 )
+#define UNM_TEST_RDDATA_HI		( UNM_CRB_TEST + 0x000ac )
+
+#define UNM_CRB_PEG_0			UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 )
+#define UNM_PEG_0_HALT_STATUS		( UNM_CRB_PEG_0 + 0x00030 )
+#define UNM_PEG_0_HALT			( UNM_CRB_PEG_0 + 0x0003c )
+
+#define UNM_CRB_PEG_1			UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 )
+#define UNM_PEG_1_HALT_STATUS		( UNM_CRB_PEG_1 + 0x00030 )
+#define UNM_PEG_1_HALT			( UNM_CRB_PEG_1 + 0x0003c )
+
+#define UNM_CRB_PEG_2			UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 )
+#define UNM_PEG_2_HALT_STATUS		( UNM_CRB_PEG_2 + 0x00030 )
+#define UNM_PEG_2_HALT			( UNM_CRB_PEG_2 + 0x0003c )
+
+#define UNM_CRB_PEG_3			UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 )
+#define UNM_PEG_3_HALT_STATUS		( UNM_CRB_PEG_3 + 0x00030 )
+#define UNM_PEG_3_HALT			( UNM_CRB_PEG_3 + 0x0003c )
+
+#define UNM_CRB_PEG_4			UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 )
+#define UNM_PEG_4_HALT_STATUS		( UNM_CRB_PEG_4 + 0x00030 )
+#define UNM_PEG_4_HALT			( UNM_CRB_PEG_4 + 0x0003c )
+
+#endif /* _PHANTOM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom_hw.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
new file mode 100644
index 0000000..950f36a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
@@ -0,0 +1,184 @@
+#ifndef _PHANTOM_HW_H
+#define _PHANTOM_HW_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ * Copyright (C) 2008 NetXen, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Phantom hardware definitions
+ *
+ */
+
+/** A Phantom RX descriptor */
+struct phantom_rds_pb {
+	pseudo_bit_t handle[16];		/**< Reference handle */
+	pseudo_bit_t flags[16];			/**< Flags */
+	pseudo_bit_t length[32];		/**< Buffer length */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t dma_addr[64];		/**< Buffer DMA address */
+
+};
+
+/** A Phantom RX status descriptor */
+struct phantom_sds_pb {
+	pseudo_bit_t port[4];			/**< Port number */
+	pseudo_bit_t status[4];			/**< Checksum status */
+	pseudo_bit_t type[4];			/**< Type */
+	pseudo_bit_t total_length[16];		/**< Total packet length */
+	pseudo_bit_t handle[16];		/**< Reference handle */
+	pseudo_bit_t protocol[4];		/**< Protocol */
+	pseudo_bit_t pkt_offset[5];		/**< Offset to packet start */
+	pseudo_bit_t desc_cnt[3];		/**< Descriptor count */
+	pseudo_bit_t owner[2];			/**< Owner */
+	pseudo_bit_t opcode[6];			/**< Opcode */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t hash_value[32];		/**< RSS hash value */
+	pseudo_bit_t hash_type[8];		/**< RSS hash type */
+	pseudo_bit_t lro[8];			/**< LRO data */
+};
+
+/** Phantom RX status opcodes */
+enum phantom_sds_opcode {
+	UNM_SYN_OFFLOAD = 0x03,
+	UNM_RXPKT_DESC = 0x04,
+};
+
+/** A Phantom TX descriptor */
+struct phantom_tx_cds_pb {
+	pseudo_bit_t tcp_hdr_offset[8];		/**< TCP header offset (LSO) */
+        pseudo_bit_t ip_hdr_offset[8];		/**< IP header offset (LSO) */
+	pseudo_bit_t flags[7];			/**< Flags */
+	pseudo_bit_t opcode[6];			/**< Opcode */
+	pseudo_bit_t hw_rsvd_0[3];		/**< (Reserved) */
+	pseudo_bit_t num_buffers[8];		/**< Total number of buffers */
+	pseudo_bit_t length[24];		/**< Total length */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t buffer2_dma_addr[64];	/**< Buffer 2 DMA address */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t handle[16];		/**< Reference handle (n/a) */
+	pseudo_bit_t port_mss[16];		/**< TCP MSS (LSO) */
+	pseudo_bit_t port[4];			/**< Port */
+	pseudo_bit_t context_id[4];		/**< Context ID */
+	pseudo_bit_t total_hdr_length[8];	/**< MAC+IP+TCP header (LSO) */
+	pseudo_bit_t conn_id[16];		/**< IPSec connection ID */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t buffer3_dma_addr[64];	/**< Buffer 3 DMA address */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t buffer1_dma_addr[64];	/**< Buffer 1 DMA address */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t buffer1_length[16];	/**< Buffer 1 length */
+	pseudo_bit_t buffer2_length[16];	/**< Buffer 2 length */
+	pseudo_bit_t buffer3_length[16];	/**< Buffer 3 length */
+	pseudo_bit_t buffer4_length[16];	/**< Buffer 4 length */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t buffer4_dma_addr[64];	/**< Buffer 4 DMA address */
+
+	/* --------------------------------------------------------------- */
+
+	pseudo_bit_t hw_rsvd_1[64];		/**< (Reserved) */
+};
+
+/** A Phantom MAC address request body */
+struct phantom_nic_request_body_mac_request_pb {
+	pseudo_bit_t opcode[8];			/**< Opcode */
+	pseudo_bit_t tag[8];			/**< Tag */
+	pseudo_bit_t mac_addr_0[8];		/**< MAC address byte 0 */
+	pseudo_bit_t mac_addr_1[8];		/**< MAC address byte 1 */
+	pseudo_bit_t mac_addr_2[8];		/**< MAC address byte 2 */
+	pseudo_bit_t mac_addr_3[8];		/**< MAC address byte 3 */
+	pseudo_bit_t mac_addr_4[8];		/**< MAC address byte 4 */
+	pseudo_bit_t mac_addr_5[8];		/**< MAC address byte 5 */
+};
+
+/** Phantom MAC request opcodes */
+enum phantom_mac_request_opcode {
+	UNM_MAC_ADD = 0x01,			/**< Add MAC address */
+	UNM_MAC_DEL = 0x02,			/**< Delete MAC address */
+};
+
+/** A Phantom NIC request command descriptor */
+struct phantom_nic_request_cds_pb {
+	struct {
+		pseudo_bit_t dst_minor[18];
+		pseudo_bit_t dst_subq[1];
+		pseudo_bit_t dst_major[4];
+		pseudo_bit_t opcode[6];
+		pseudo_bit_t hw_rsvd_0[3];
+		pseudo_bit_t msginfo[24];
+		pseudo_bit_t hw_rsvd_1[2];
+		pseudo_bit_t qmsg_type[6];
+	} common;
+
+	/* --------------------------------------------------------------- */
+
+	struct {
+		pseudo_bit_t opcode[8];
+		pseudo_bit_t comp_id [8];
+		pseudo_bit_t context_id[16];
+		pseudo_bit_t need_completion[1];
+		pseudo_bit_t hw_rsvd_0[23];
+		pseudo_bit_t sub_opcode[8];
+	} header;
+
+	/* --------------------------------------------------------------- */
+
+	union {
+		struct phantom_nic_request_body_mac_request_pb mac_request;
+		pseudo_bit_t padding[384];
+	} body;
+};
+
+/** Phantom NIC request opcodes */
+enum phantom_nic_request_opcode {
+	UNM_MAC_EVENT = 0x01,			/**< Add/delete MAC address */
+};
+
+/** A Phantom command descriptor */
+union phantom_cds_pb {
+	struct phantom_tx_cds_pb tx;
+	struct phantom_nic_request_cds_pb nic_request;
+};
+
+/** Phantom command descriptor opcodes */
+enum phantom_cds_opcode {
+	UNM_TX_ETHER_PKT = 0x01,		/**< Transmit raw Ethernet */
+	UNM_NIC_REQUEST = 0x14,			/**< NIC request */
+};
+
+#endif /* _PHANTOM_HW_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic.c
new file mode 100644
index 0000000..4170cc6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic.c
@@ -0,0 +1,280 @@
+/**************************************************************************
+Etherboot -  BOOTP/TFTP Bootstrap Program
+Bochs Pseudo NIC driver for Etherboot
+***************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * See pnic_api.h for an explanation of the Bochs Pseudo NIC.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+#include "pnic_api.h"
+
+struct pnic {
+	unsigned short ioaddr;
+};
+
+/* 
+ * Utility functions: issue a PNIC command, retrieve result.  Use
+ * pnic_command_quiet if you don't want failure codes to be
+ * automatically printed.  Returns the PNIC status code.
+ * 
+ * Set output_length to NULL only if you expect to receive exactly
+ * output_max_length bytes, otherwise it'll complain that you didn't
+ * get enough data (on the assumption that if you not interested in
+ * discovering the output length then you're expecting a fixed amount
+ * of data).
+ */
+
+static uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command,
+				     const void *input, uint16_t input_length,
+				     void *output, uint16_t output_max_length,
+				     uint16_t *output_length ) {
+	uint16_t status;
+	uint16_t _output_length;
+
+	if ( input != NULL ) {
+		/* Write input length */
+		outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
+		/* Write input data */
+		outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length );
+	}
+	/* Write command */
+	outw ( command, pnic->ioaddr + PNIC_REG_CMD );
+	/* Retrieve status */
+	status = inw ( pnic->ioaddr + PNIC_REG_STAT );
+	/* Retrieve output length */
+	_output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
+	if ( output_length == NULL ) {
+		if ( _output_length != output_max_length ) {
+			printf ( "pnic_command %#hx: wrong data length "
+				 "returned (expected %d, got %d)\n", command,
+				 output_max_length, _output_length );
+		}
+	} else {
+		*output_length = _output_length;
+	}
+	if ( output != NULL ) {
+		if ( _output_length > output_max_length ) {
+			printf ( "pnic_command %#hx: output buffer too small "
+				 "(have %d, need %d)\n", command,
+				 output_max_length, _output_length );
+			_output_length = output_max_length;
+		}
+		/* Retrieve output data */
+		insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length );
+	}
+	return status;
+}
+
+static uint16_t pnic_command ( struct pnic *pnic, uint16_t command,
+			       const void *input, uint16_t input_length,
+			       void *output, uint16_t output_max_length,
+			       uint16_t *output_length ) {
+	uint16_t status = pnic_command_quiet ( pnic, command,
+					       input, input_length,
+					       output, output_max_length,
+					       output_length );
+	if ( status == PNIC_STATUS_OK ) return status;
+	printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n",
+		 command, input_length, status );
+	return status;
+}
+
+/* Check API version matches that of NIC */
+static int pnic_api_check ( uint16_t api_version ) {
+	if ( api_version != PNIC_API_VERSION ) {
+		printf ( "Warning: API version mismatch! "
+			 "(NIC's is %d.%d, ours is %d.%d)\n",
+			 api_version >> 8, api_version & 0xff,
+			 PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
+	}
+	if ( api_version < PNIC_API_VERSION ) {
+		printf ( "** You may need to update your copy of Bochs **\n" );
+	}
+	return ( api_version == PNIC_API_VERSION );
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static void pnic_poll ( struct net_device *netdev ) {
+	struct pnic *pnic = netdev->priv;
+	struct io_buffer *iobuf;
+	uint16_t length;
+	uint16_t qlen;
+
+	/* Fetch all available packets */
+	while ( 1 ) {
+		if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
+				    &qlen, sizeof ( qlen ), NULL )
+		     != PNIC_STATUS_OK )
+			return;
+		if ( qlen == 0 )
+			return;
+		iobuf = alloc_iob ( ETH_FRAME_LEN );
+		if ( ! iobuf ) {
+			DBG ( "could not allocate buffer\n" );
+			netdev_rx_err ( netdev, NULL, -ENOMEM );
+			return;
+		}
+		if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
+				    iobuf->data, ETH_FRAME_LEN, &length )
+		     != PNIC_STATUS_OK ) {
+			netdev_rx_err ( netdev, iobuf, -EIO );
+			return;
+		}
+		iob_put ( iobuf, length );
+		netdev_rx ( netdev, iobuf );
+	}
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
+	struct pnic *pnic = netdev->priv;
+
+	/* Pad the packet */
+	iob_pad ( iobuf, ETH_ZLEN );
+
+	/* Send packet */
+	pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ),
+		       NULL, 0, NULL );
+
+	netdev_tx_complete ( netdev, iobuf );
+	return 0;
+}
+
+/**************************************************************************
+OPEN - Open network device
+***************************************************************************/
+static int pnic_open ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+	return 0;
+}
+
+/**************************************************************************
+CLOSE - Close network device
+***************************************************************************/
+static void pnic_close ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+}
+
+/**************************************************************************
+IRQ - Enable/disable interrupts
+***************************************************************************/
+static void pnic_irq ( struct net_device *netdev, int enable ) {
+	struct pnic *pnic = netdev->priv;
+	uint8_t mask = ( enable ? 1 : 0 );
+	
+	pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ),
+		       NULL, 0, NULL );
+}
+
+/**************************************************************************
+OPERATIONS TABLE
+***************************************************************************/
+static struct net_device_operations pnic_operations = {
+	.open		= pnic_open,
+	.close		= pnic_close,
+	.transmit	= pnic_transmit,
+	.poll		= pnic_poll,
+	.irq   		= pnic_irq,
+};
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void pnic_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct pnic *pnic = netdev->priv;
+
+	unregister_netdev ( netdev );
+	pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int pnic_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct pnic *pnic;
+	uint16_t api_version;
+	uint16_t status;
+	int rc;
+
+	/* Allocate net device */
+	netdev = alloc_etherdev ( sizeof ( *pnic ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &pnic_operations );
+	pnic = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	pnic->ioaddr = pci->ioaddr;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+	
+	/* API version check */
+	status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
+				      &api_version,
+				      sizeof ( api_version ), NULL );
+	if ( status != PNIC_STATUS_OK ) {
+		printf ( "PNIC failed installation check, code %#hx\n",
+			 status );
+		rc = -EIO;
+		goto err;
+	}
+	pnic_api_check ( api_version );
+
+	/* Get MAC address */
+	status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
+				netdev->hw_addr, ETH_ALEN, NULL );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err;
+
+	/* Mark as link up; PNIC has no concept of link state */
+	netdev_link_up ( netdev );
+
+	return 0;
+
+ err:
+	/* Free net device */
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	return rc;
+}
+
+static struct pci_device_id pnic_nics[] = {
+/* genrules.pl doesn't let us use macros for PCI IDs...*/
+PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
+};
+
+struct pci_driver pnic_driver __pci_driver = {
+	.ids = pnic_nics,
+	.id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
+	.probe = pnic_probe,
+	.remove = pnic_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic_api.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic_api.h
new file mode 100644
index 0000000..27e0236
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/pnic_api.h
@@ -0,0 +1,61 @@
+/*
+ * Constants etc. for the Bochs/Etherboot pseudo-NIC
+ * 
+ * This header file must be valid C and C++.
+ *
+ * Operation of the pseudo-NIC (PNIC) is pretty simple.  To write a
+ * command plus data, first write the length of the data to
+ * PNIC_REG_LEN, then write the data a byte at a type to
+ * PNIC_REG_DATA, then write the command code to PNIC_REG_CMD.  The
+ * status will be available from PNIC_REG_STAT.  The length of any
+ * data returned will be in PNIC_REG_LEN and can be read a byte at a
+ * time from PNIC_REG_DATA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * PCI parameters
+ */
+#define PNIC_PCI_VENDOR	0xfefe	/* Hopefully these won't clash with */
+#define PNIC_PCI_DEVICE 0xefef	/* any real PCI device IDs.         */
+
+/*
+ * 'Hardware' register addresses, offset from io_base
+ */
+#define PNIC_REG_CMD	0x00	/* Command register, 2 bytes, write only */
+#define PNIC_REG_STAT	0x00	/* Status register, 2 bytes, read only */
+#define PNIC_REG_LEN	0x02	/* Length register, 2 bytes, read-write */
+#define PNIC_REG_DATA	0x04	/* Data port, 1 byte, read-write */
+/*
+ * PNIC_MAX_REG used in Bochs to claim i/o space
+ */
+#define PNIC_MAX_REG	0x04
+
+/*
+ * Command code definitions: write these into PNIC_REG_CMD
+ */
+#define PNIC_CMD_NOOP		0x0000
+#define PNIC_CMD_API_VER	0x0001
+#define PNIC_CMD_READ_MAC	0x0002
+#define PNIC_CMD_RESET		0x0003
+#define PNIC_CMD_XMIT		0x0004
+#define PNIC_CMD_RECV		0x0005
+#define PNIC_CMD_RECV_QLEN	0x0006
+#define PNIC_CMD_MASK_IRQ	0x0007
+#define PNIC_CMD_FORCE_IRQ	0x0008
+
+/*
+ * Status code definitions: read these from PNIC_REG_STAT
+ *
+ * We avoid using status codes that might be confused with
+ * randomly-read data (e.g. 0x0000, 0xffff etc.)
+ */
+#define PNIC_STATUS_OK		0x4f4b		/* 'OK' */
+#define PNIC_STATUS_UNKNOWN_CMD	0x3f3f		/* '??' */
+
+/*
+ * Other miscellaneous information
+ */
+
+#define PNIC_API_VERSION	0x0101		/* 1.1 */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2.c
new file mode 100644
index 0000000..d216014
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2.c
@@ -0,0 +1,857 @@
+/**************************************************************************
+Etherboot -  BOOTP/TFTP Bootstrap Program
+Prism2 NIC driver for Etherboot
+
+Written by Michael Brown of Fen Systems Ltd
+$Id$
+***************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <etherboot.h>
+#include <nic.h>
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+/*
+ * Hard-coded SSID
+ * Leave blank in order to connect to any available SSID
+ */
+
+static const char hardcoded_ssid[] = "";
+
+/*
+ * Maximum number of info packets to wait for on a join attempt.
+ * Some APs (including the Linksys WAP11) will send a "you are disconnected" packet
+ * before sending the "you are connected" packet, if the card has previously been
+ * attached to the AP.
+ *
+ * 2 is probably a sensible value, but YMMV.
+ */
+
+#define MAX_JOIN_INFO_COUNT 2
+
+/*
+ * Type of Prism2 interface to support
+ * If not already defined, select PLX
+ */
+#ifndef WLAN_HOSTIF
+#define WLAN_HOSTIF WLAN_PLX
+#endif
+
+/*
+ * Include wlan_compat, p80211 and hfa384x header files from Linux Prism2 driver
+ * We need to hack some defines in order to avoid compiling kernel-specific routines
+ */
+
+#define __LINUX_WLAN__
+#undef __KERNEL__
+#define __I386__
+#include "wlan_compat.h"
+#include "p80211hdr.h"
+#include "hfa384x.h"
+#define BAP_TIMEOUT ( 5000 )
+
+/*
+ * A few hacks to make the coding environment more Linux-like.  This makes it somewhat
+ * quicker to convert code from the Linux Prism2 driver.
+ */
+#include <errno.h>
+#define __le16_to_cpu(x) (x)
+#define __le32_to_cpu(x) (x)
+#define __cpu_to_le16(x) (x)
+#define __cpu_to_le32(x) (x)
+
+#define hfa384x2host_16(n)	(__le16_to_cpu((UINT16)(n)))
+#define hfa384x2host_32(n)	(__le32_to_cpu((UINT32)(n)))
+#define host2hfa384x_16(n)	(__cpu_to_le16((UINT16)(n)))
+#define host2hfa384x_32(n)	(__cpu_to_le32((UINT32)(n)))
+
+/*
+ * PLX9052 PCI register offsets
+ * Taken from PLX9052 datasheet available from http://www.plxtech.com/download/9052/databook/9052db-20.pdf
+ */
+
+#define PLX_LOCAL_CONFIG_REGISTER_BASE ( PCI_BASE_ADDRESS_1 )
+#define PLX_LOCAL_ADDRESS_SPACE_0_BASE ( PCI_BASE_ADDRESS_2 )
+#define PLX_LOCAL_ADDRESS_SPACE_1_BASE ( PCI_BASE_ADDRESS_3 )
+#define PLX_LOCAL_ADDRESS_SPACE_2_BASE ( PCI_BASE_ADDRESS_4 )
+#define PLX_LOCAL_ADDRESS_SPACE_3_BASE ( PCI_BASE_ADDRESS_5 )
+
+#define PRISM2_PLX_ATTR_MEM_BASE       ( PLX_LOCAL_ADDRESS_SPACE_0_BASE )
+#define PRISM2_PLX_IO_BASE             ( PLX_LOCAL_ADDRESS_SPACE_1_BASE )
+
+#define PRISM2_PCI_MEM_BASE            ( PCI_BASE_ADDRESS_0 )
+
+/*
+ * PCMCIA CIS types
+ * Taken from cistpl.h in pcmcia-cs
+ */
+
+#define CISTPL_VERS_1           ( 0x15 )
+#define CISTPL_END              ( 0xff )
+
+#define CIS_STEP                ( 2 )
+#define CISTPL_HEADER_LEN       ( 2 * CIS_STEP )
+#define CISTPL_LEN_OFF          ( 1 * CIS_STEP )
+#define CISTPL_VERS_1_STR_OFF   ( 4 * CIS_STEP )
+
+/*
+ * Prism2 constants
+ * Taken from prism2sta.c in linux-wlan-ng
+ */
+
+#define COR_OFFSET      ( 0x3e0 )   /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE       ( 0x41 )    /* Enable PC card with irq in level trigger (but interrupts disabled) */
+
+/* NIC specific static variables */
+
+/* The hfa384x_t structure is used extensively in the Linux driver but is ifdef'd out in our include since __KERNEL__ is not defined.
+ * This is a dummy version that contains only the fields we are interested in.
+ */
+
+typedef struct hfa384x
+{
+  UINT32 iobase;
+  void *membase;
+  UINT16 lastcmd;
+  UINT16 status;         /* in host order */
+  UINT16 resp0;          /* in host order */
+  UINT16 resp1;          /* in host order */
+  UINT16 resp2;          /* in host order */
+  UINT8  bssid[WLAN_BSSID_LEN];
+} hfa384x_t;
+
+/* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */
+static hfa384x_t hw_global = {
+  0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0}
+};
+
+/*
+ * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP)
+ * Taken from p80211conv.h
+ */
+
+typedef struct wlan_llc
+{
+  UINT8   dsap;
+  UINT8   ssap;
+  UINT8   ctl;
+}  wlan_llc_t;
+
+static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */
+
+#define WLAN_IEEE_OUI_LEN 3
+typedef struct wlan_snap
+{
+  UINT8   oui[WLAN_IEEE_OUI_LEN];
+  UINT16  type;
+} wlan_snap_t;
+
+typedef struct wlan_80211hdr
+{
+  wlan_llc_t llc;
+  wlan_snap_t snap;
+} wlan_80211hdr_t;
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Hardware-level hfa384x functions
+ * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined).
+ * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions. 
+ */
+
+/* Retrieve the value of one of the MAC registers. */
+static inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg )
+{
+#if (WLAN_HOSTIF == WLAN_PLX)
+  return inw ( hw->iobase + reg );
+#elif (WLAN_HOSTIF == WLAN_PCI)
+  return readw ( hw->membase + reg );
+#endif
+}
+
+/* Set the value of one of the MAC registers. */
+static inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg )
+{
+#if (WLAN_HOSTIF == WLAN_PLX)
+  outw ( val, hw->iobase + reg );
+#elif (WLAN_HOSTIF == WLAN_PCI)
+  writew ( val, hw->membase + reg );
+#endif
+  return;
+}
+
+/* 
+ * Noswap versions
+ * Etherboot is i386 only, so swap and noswap are the same...
+ */
+static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg )
+{
+  return hfa384x_getreg ( hw, reg );
+}
+static inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg )
+{
+  hfa384x_setreg ( hw, val, reg );
+}
+
+/*
+ * Low-level hfa384x functions
+ * These are based on the ones in hfa384x.c, modified to work in the Etherboot environment.
+ */
+
+/*
+ * hfa384x_docmd_wait
+ *
+ * Waits for availability of the Command register, then
+ * issues the given command.  Then polls the Evstat register
+ * waiting for command completion.
+ * Arguments:
+ *       hw              device structure
+ *       cmd             Command in host order
+ *       parm0           Parameter0 in host order
+ *       parm1           Parameter1 in host order
+ *       parm2           Parameter2 in host order
+ * Returns:
+ *       0               success
+ *       >0              command indicated error, Status and Resp0-2 are
+ *                       in hw structure.
+ */
+static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2)
+{
+  UINT16 reg = 0;
+  UINT16 counter = 0;
+  
+  /* wait for the busy bit to clear */	
+  counter = 0;
+  reg = hfa384x_getreg(hw, HFA384x_CMD);
+  while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) {
+    reg = hfa384x_getreg(hw, HFA384x_CMD);
+    counter++;
+    udelay(10);
+  }
+  if (HFA384x_CMD_ISBUSY(reg)) {
+    printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg);
+    return -ETIMEDOUT;
+  }
+
+  /* busy bit clear, write command */
+  hfa384x_setreg(hw, parm0, HFA384x_PARAM0);
+  hfa384x_setreg(hw, parm1, HFA384x_PARAM1);
+  hfa384x_setreg(hw, parm2, HFA384x_PARAM2);
+  hw->lastcmd = cmd;
+  hfa384x_setreg(hw, cmd, HFA384x_CMD);
+  
+  /* Now wait for completion */
+  counter = 0;
+  reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
+  /* Initialization is the problem.  It takes about
+     100ms. "normal" commands are typically is about
+     200-400 us (I've never seen less than 200).  Longer
+     is better so that we're not hammering the bus. */
+  while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) {
+    reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
+    counter++;
+    udelay(200);
+  }
+  if ( ! HFA384x_EVSTAT_ISCMD(reg) ) {
+    printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg);
+    return -ETIMEDOUT;
+  }
+
+  /* Read status and response */
+  hw->status = hfa384x_getreg(hw, HFA384x_STATUS);
+  hw->resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
+  hw->resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
+  hw->resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
+  hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK);
+  return HFA384x_STATUS_RESULT_GET(hw->status);
+}
+
+/*
+ * Prepare BAP for access.  Assigns FID and RID, sets offset register
+ * and waits for BAP to become available.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	id		FID or RID, destined for the select register (host order)
+ *	offset		An _even_ offset into the buffer for the given FID/RID.
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset)
+{
+  int result = 0;
+  UINT16 reg;
+  UINT16 i;
+
+  /* Validate offset, buf, and len */
+  if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) {
+    result = -EINVAL;
+  } else {
+    /* Write fid/rid and offset */
+    hfa384x_setreg(hw, id, HFA384x_SELECT0);
+    udelay(10);
+    hfa384x_setreg(hw, offset, HFA384x_OFFSET0);
+    /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
+    i = 0; 
+    do {
+      reg = hfa384x_getreg(hw, HFA384x_OFFSET0);
+      if ( i > 0 ) udelay(2);
+      i++;
+    } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg));
+    if ( i >= BAP_TIMEOUT ) {
+      /* failure */
+      result = reg;
+    } else if ( HFA384x_OFFSET_ISERR(reg) ){
+      /* failure */
+      result = reg;
+    }
+  }
+  return result;
+}
+
+/*
+ * Copy data from BAP to memory.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	id		FID or RID, destined for the select register (host order)
+ *	offset		An _even_ offset into the buffer for the given FID/RID.
+ *	buf		ptr to array of bytes
+ *	len		length of data to transfer in bytes
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
+			  void *buf, UINT len)
+{
+  int result = 0;
+  UINT8	*d = (UINT8*)buf;
+  UINT16 i;
+  UINT16 reg = 0;
+  
+  /* Prepare BAP */
+  result = hfa384x_prepare_bap ( hw, id, offset );
+  if ( result == 0 ) {
+    /* Read even(len) buf contents from data reg */
+    for ( i = 0; i < (len & 0xfffe); i+=2 ) {
+      *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
+    }
+    /* If len odd, handle last byte */
+    if ( len % 2 ){
+      reg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
+      d[len-1] = ((UINT8*)(&reg))[0];
+    }
+  }
+  if (result) {
+    printf ( "copy_from_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
+  }
+  return result;
+}
+
+/*
+ * Copy data from memory to BAP.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	id		FID or RID, destined for the select register (host order)
+ *	offset		An _even_ offset into the buffer for the given FID/RID.
+ *	buf		ptr to array of bytes
+ *	len		length of data to transfer in bytes
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
+			void *buf, UINT len)
+{
+  int result = 0;
+  UINT8	*d = (UINT8*)buf;
+  UINT16 i;
+  UINT16 savereg;
+
+  /* Prepare BAP */
+  result = hfa384x_prepare_bap ( hw, id, offset );
+  if ( result == 0 ) {
+    /* Write even(len) buf contents to data reg */
+    for ( i = 0; i < (len & 0xfffe); i+=2 ) {
+      hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), HFA384x_DATA0);
+    }
+    /* If len odd, handle last byte */
+    if ( len % 2 ){
+      savereg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
+      result = hfa384x_prepare_bap ( hw, id, offset + (len & 0xfffe) );
+      if ( result == 0 ) {
+	((UINT8*)(&savereg))[0] = d[len-1];
+	hfa384x_setreg_noswap(hw, savereg, HFA384x_DATA0);
+      }
+    }
+  }
+  if (result) {
+    printf ( "copy_to_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
+  }
+  return result;
+}
+
+/*
+ * Request a given record to be copied to/from the record buffer.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	write		[0|1] copy the record buffer to the given
+ *			configuration record. (host order)
+ *	rid		RID of the record to read/write. (host order)
+ *
+ * Returns: 
+ *	0		success
+ */
+static inline int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid)
+{
+  return hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | HFA384x_CMD_WRITE_SET(write), rid, 0, 0);
+}
+
+/*
+ * Performs the sequence necessary to read a config/info item.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	rid		config/info record id (host order)
+ *	buf		host side record buffer.  Upon return it will
+ *			contain the body portion of the record (minus the 
+ *			RID and len).
+ *	len		buffer length (in bytes, should match record length)
+ *
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
+{
+  int result = 0;
+  hfa384x_rec_t	rec;
+
+  /* Request read of RID */
+  result = hfa384x_cmd_access( hw, 0, rid);
+  if ( result ) {
+    printf("Call to hfa384x_cmd_access failed\n");
+    return -1;
+  }
+  /* Copy out record length */
+  result = hfa384x_copy_from_bap( hw, rid, 0, &rec, sizeof(rec));
+  if ( result ) {
+    return -1;
+  }
+  /* Validate the record length */
+  if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) {  /* note body len calculation in bytes */
+    printf ( "RID len mismatch, rid=%#hx hlen=%d fwlen=%d\n", rid, len, (hfa384x2host_16(rec.reclen)-1)*2);
+    return -1;
+  }
+  /* Copy out record data */
+  result = hfa384x_copy_from_bap( hw, rid, sizeof(rec), buf, len);
+  return result;
+}
+
+/*
+ * Performs the sequence necessary to read a 16/32 bit config/info item
+ * and convert it to host order.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	rid		config/info record id (in host order)
+ *	val		ptr to 16/32 bit buffer to receive value (in host order)
+ *
+ * Returns: 
+ *	0		success
+ */
+#if 0 /* Not actually used anywhere */
+static int hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val)
+{
+  int result = 0;
+  result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16));
+  if ( result == 0 ) {
+    *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val));
+  }
+  return result;
+}
+#endif
+#if 0 /* Not actually used anywhere */
+static int hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val)
+{
+  int result = 0;
+  result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32));
+  if ( result == 0 ) {
+    *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val));
+  }
+  return result;
+}
+#endif
+
+/*
+ * Performs the sequence necessary to write a config/info item.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	rid		config/info record id (in host order)
+ *	buf		host side record buffer
+ *	len		buffer length (in bytes)
+ *
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
+{
+  int result = 0;
+  hfa384x_rec_t	rec;
+
+  rec.rid = host2hfa384x_16(rid);
+  rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */
+  /* write the record header */
+  result = hfa384x_copy_to_bap( hw, rid, 0, &rec, sizeof(rec));
+  if ( result ) {
+    printf("Failure writing record header\n");
+    return -1;
+  }
+  /* write the record data (if there is any) */
+  if ( len > 0 ) {
+    result = hfa384x_copy_to_bap( hw, rid, sizeof(rec), buf, len);
+    if ( result ) {
+      printf("Failure writing record data\n");
+      return -1;
+    }
+  }
+  /* Trigger setting of record */
+  result = hfa384x_cmd_access( hw, 1, rid);
+  return result;
+}
+
+/*
+ * Performs the sequence necessary to write a 16/32 bit config/info item.
+ *
+ * Arguments:
+ *	hw		device structure
+ *	rid		config/info record id (in host order)
+ *	val		16/32 bit value to store (in host order)
+ *
+ * Returns: 
+ *	0		success
+ */
+static int hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 *val)
+{
+  UINT16 value;
+  value = host2hfa384x_16(*val);
+  return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT16));
+}
+#if 0 /* Not actually used anywhere */
+static int hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 *val)
+{
+  UINT32 value;
+  value = host2hfa384x_32(*val);
+  return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT32));
+}
+#endif
+
+/*
+ * Wait for an event, with specified checking interval and timeout.
+ * Automatically acknolwedges events.
+ *
+ * Arguments:
+ *	hw		device structure
+ *      event_mask      EVSTAT register mask of events to wait for
+ *	event_ack	EVACK register set of events to be acknowledged if they happen (can be
+ *			used to acknowledge "ignorable" events in addition to the "main" event)
+ *      wait            Time (in us) to wait between each poll of the register
+ *      timeout         Maximum number of polls before timing out
+ *      descr           Descriptive text string of what is being waited for
+ *                      (will be printed out if a timeout happens)
+ *
+ * Returns: 
+ *      value of EVSTAT register, or 0 on failure 
+ */
+static int hfa384x_wait_for_event(hfa384x_t *hw, UINT16 event_mask, UINT16 event_ack, int wait, int timeout, const char *descr)
+{
+  UINT16 reg;
+  int count = 0;
+  
+  do {
+    reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
+    if ( count > 0 ) udelay(wait);
+    count++;
+  } while ( !(reg & event_mask) && count < timeout);
+  if ( count >= timeout ) {
+    printf("hfa384x: Timed out waiting for %s\n", descr);
+    return 0; /* Return failure */
+  }
+  /* Acknowledge all events that we were waiting on */
+  hfa384x_setreg(hw, reg & ( event_mask | event_ack ), HFA384x_EVACK);
+  return reg;
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int prism2_poll(struct nic *nic, int retrieve)
+{
+  UINT16 reg;
+  UINT16 rxfid;
+  UINT16 result;
+  hfa384x_rx_frame_t rxdesc;
+  hfa384x_t *hw = &hw_global;
+  
+  /* Check for received packet */
+  reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
+  if ( ! HFA384x_EVSTAT_ISRX(reg) ) {
+    /* No packet received - return 0 */
+    return 0;
+  }
+
+  if ( ! retrieve ) return 1;
+
+  /* Acknowledge RX event */
+  hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK);
+  /* Get RX FID */  
+  rxfid = hfa384x_getreg(hw, HFA384x_RXFID);
+  /* Get the descriptor (including headers) */
+  result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc));
+  if ( result ) {
+    return 0; /* fail */
+  }
+  /* Byte order convert once up front. */
+  rxdesc.status = hfa384x2host_16(rxdesc.status);
+  rxdesc.time = hfa384x2host_32(rxdesc.time);
+  rxdesc.data_len = hfa384x2host_16(rxdesc.data_len);
+
+  /* Fill in nic->packetlen */
+  nic->packetlen = rxdesc.data_len;
+  if ( nic->packetlen > 0 ) {
+    /* Fill in nic->packet */
+    /*
+     * NOTE: Packets as received have an 8-byte header (LLC+SNAP(?)) terminating with the packet type.
+     * Etherboot expects a 14-byte header terminating with the packet type (it ignores the rest of the
+     * header), so we use a quick hack to achieve this.
+     */
+    result = hfa384x_copy_from_bap(hw, rxfid, HFA384x_RX_DATA_OFF,
+				   nic->packet + ETH_HLEN - sizeof(wlan_80211hdr_t), nic->packetlen);
+    if ( result ) {
+      return 0; /* fail */
+    }
+  }
+  return 1; /* Packet successfully received */
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void prism2_transmit(
+			    struct nic *nic,
+			    const char *d,			/* Destination */
+			    unsigned int t,			/* Type */
+			    unsigned int s,			/* size */
+			    const char *p)			/* Packet */
+{
+  hfa384x_t *hw = &hw_global;
+  hfa384x_tx_frame_t txdesc;
+  wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} };
+  UINT16 fid;
+  UINT16 status;
+  int result;
+
+  // Request FID allocation
+  result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC), HFA384x_DRVR_TXBUF_MAX, 0, 0);
+  if (result != 0) {
+    printf("hfa384x: Tx FID allocate command failed: Aborting transmit..\n");
+    return;
+  }
+  if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_ALLOC, HFA384x_EVACK_INFO, 10, 50, "Tx FID to be allocated\n" ) ) return;
+  fid = hfa384x_getreg(hw, HFA384x_ALLOCFID);
+
+  /* Build Tx frame structure */
+  memset(&txdesc, 0, sizeof(txdesc));
+  txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | 
+				       HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1) );
+  txdesc.frame_control =  host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
+				       WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY) |
+				       WLAN_SET_FC_TODS(1) );
+  memcpy(txdesc.address1, hw->bssid, WLAN_ADDR_LEN);
+  memcpy(txdesc.address2, nic->node_addr, WLAN_ADDR_LEN);
+  memcpy(txdesc.address3, d, WLAN_ADDR_LEN);
+  txdesc.data_len = host2hfa384x_16( sizeof(txdesc) + sizeof(p80211hdr) + s );
+  /* Set up SNAP header */
+  /* Let OUI default to RFC1042 (0x000000) */
+  p80211hdr.snap.type = htons(t);
+  
+  /* Copy txdesc, p80211hdr and payload parts to FID */
+  result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc));
+  if ( result ) return; /* fail */
+  result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) );
+  if ( result ) return; /* fail */
+  result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (UINT8*)p, s );
+  if ( result ) return; /* fail */
+
+  /* Issue Tx command */
+  result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX), fid, 0, 0);
+  if ( result != 0 ) {
+    printf("hfa384x: Transmit failed with result %#hx.\n", result);
+    return;
+  }
+  
+  /* Wait for transmit completion (or exception) */
+  result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO,
+				  200, 500, "Tx to complete\n" );
+  if ( !result ) return; /* timeout failure */
+  if ( HFA384x_EVSTAT_ISTXEXC(result) ) {
+    fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID);
+    printf ( "Tx exception occurred with fid %#hx\n", fid );
+    result = hfa384x_copy_from_bap(hw, fid, 0, &status, sizeof(status));
+    if ( result ) return; /* fail */
+    printf("hfa384x: Tx error occurred (status %#hx):\n", status);
+    if ( HFA384x_TXSTATUS_ISACKERR(status) ) { printf(" ...acknowledgement error\n"); }
+    if ( HFA384x_TXSTATUS_ISFORMERR(status) ) { printf(" ...format error\n"); }
+    if ( HFA384x_TXSTATUS_ISDISCON(status) ) { printf(" ...disconnected error\n"); }
+    if ( HFA384x_TXSTATUS_ISAGEDERR(status) ) { printf(" ...AGED error\n"); }
+    if ( HFA384x_TXSTATUS_ISRETRYERR(status) ) { printf(" ...retry error\n"); }
+    return; /* fail */
+  }
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void prism2_disable ( struct nic *nic __unused ) {
+  /* put the card in its initial state */
+}
+
+/**************************************************************************
+IRQ - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void prism2_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+/**************************************************************************
+Operations table
+***************************************************************************/
+static struct nic_operations prism2_operations = {
+	.connect	= dummy_connect,
+	.poll		= prism2_poll,
+	.transmit	= prism2_transmit,
+	.irq		= prism2_irq,
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+You should omit the last argument struct pci_device * for a non-PCI NIC
+***************************************************************************/
+static int prism2_probe ( struct nic *nic, hfa384x_t *hw ) {
+  int result;
+  UINT16 tmp16 = 0;
+  UINT16 infofid;
+  hfa384x_InfFrame_t inf;
+  char ssid[HFA384x_RID_CNFDESIREDSSID_LEN];
+  int info_count = 0;
+
+  nic->irqno  = 0;
+
+  /* Initialize card */
+  result = hfa384x_docmd_wait(hw, HFA384x_CMDCODE_INIT, 0,0,0); /* Send initialize command */
+  if ( result ) printf ( "Initialize command returned %#hx\n", result );
+  hfa384x_setreg(hw, 0, HFA384x_INTEN); /* Disable interrupts */
+  hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); /* Acknowledge any spurious events */
+
+  DBG ( "MAC address %s\n", eth_ntoa ( nic->node_addr ) );
+
+  /* Retrieve MAC address (and fill out nic->node_addr) */
+  hfa384x_drvr_getconfig ( hw, HFA384x_RID_CNFOWNMACADDR, nic->node_addr, HFA384x_RID_CNFOWNMACADDR_LEN );
+
+  /* Prepare card for autojoin */
+  /* This procedure is reverse-engineered from a register-level trace of the Linux driver's join process */
+  tmp16 = WLAN_DATA_MAXLEN; /* Set maximum data length */
+  result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, &tmp16);
+  if ( result ) printf ( "Set Max Data Length command returned %#hx\n", result );
+  tmp16 = 0x000f; /* Set transmit rate(?) */
+  result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, &tmp16);
+  if ( result ) printf ( "Set Transmit Rate command returned %#hx\n", result );
+  tmp16 = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; /* Set authentication type to OpenSystem */
+  result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, &tmp16);
+  if ( result ) printf ( "Set Authentication Type command returned %#hx\n", result );
+  /* Set SSID */
+  memset(ssid, 0, HFA384x_RID_CNFDESIREDSSID_LEN);
+  for ( tmp16=0; tmp16<sizeof(hardcoded_ssid); tmp16++ ) { ssid[2+tmp16] = hardcoded_ssid[tmp16]; }
+  ssid[0] = sizeof(hardcoded_ssid) - 1; /* Ignore terminating zero */
+  result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, ssid, HFA384x_RID_CNFDESIREDSSID_LEN); /* Set the SSID */
+  if ( result ) printf ( "Set SSID command returned %#hx\n", result );
+  tmp16 = 1; /* Set port type to ESS port */
+  result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, &tmp16);
+  if ( result ) printf ( "Set port type command returned %#hx\n", result );
+  /* Enable card */
+  result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | HFA384x_CMD_MACPORT_SET(0), 0,0,0);
+  if ( result ) printf ( "Enable command returned %#hx\n", result );
+
+  do {
+    /* Increment info_count, abort if too many attempts.
+     * See comment next to definition of MAX_JOIN_INFO_COUNT for explanation.
+     */
+    info_count++;
+    if ( info_count > MAX_JOIN_INFO_COUNT ) {
+      printf ( "Too many failed attempts - aborting\n" );
+      return 0;
+    }
+
+    /* Wait for info frame to indicate link status */
+    if ( sizeof(hardcoded_ssid) == 1 ) {
+      /* Empty SSID => join to any SSID */
+      printf ( "Attempting to autojoin to any available access point (attempt %d)...", info_count );
+    } else {
+      printf ( "Attempting to autojoin to SSID %s (attempt %d)...", &ssid[2], info_count );
+    }
+    
+    if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_INFO, 0, 1000, 2000, "Info event" ) ) return 0;
+    printf("done\n");
+    infofid = hfa384x_getreg(hw, HFA384x_INFOFID);
+    /* Retrieve the length */
+    result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(UINT16));
+    if ( result ) return 0; /* fail */
+    inf.framelen = hfa384x2host_16(inf.framelen);
+    /* Retrieve the rest */
+    result = hfa384x_copy_from_bap( hw, infofid, sizeof(UINT16),
+				    &(inf.infotype), inf.framelen * sizeof(UINT16));
+    if ( result ) return 0; /* fail */
+    if ( inf.infotype != HFA384x_IT_LINKSTATUS ) {
+      /* Not a Link Status info frame: die */
+      printf ( "Unexpected info frame type %#hx (not LinkStatus type)\n", inf.infotype );
+      return 0;
+    }
+    inf.info.linkstatus.linkstatus = hfa384x2host_16(inf.info.linkstatus.linkstatus);
+    if ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED ) {
+      /* Link not connected - retry */
+      printf ( "Link not connected (status %#hx)\n", inf.info.linkstatus.linkstatus );
+    }
+  } while ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED );
+    
+  /* Retrieve BSSID and print Connected message */
+  result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CURRENTBSSID, hw->bssid, WLAN_BSSID_LEN);
+
+  DBG ( "Link connected (BSSID %s - ", eth_ntoa ( hw->bssid ) );
+  DBG ( " MAC address %s)\n", eth_ntoa (nic->node_addr ) );
+  
+  /* point to NIC specific routines */
+  nic->nic_op	= &prism2_operations;
+  return 1;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_pci.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_pci.c
new file mode 100644
index 0000000..72549ba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_pci.c
@@ -0,0 +1,58 @@
+/**************************************************************************
+Etherboot -  BOOTP/TFTP Bootstrap Program
+Prism2 NIC driver for Etherboot
+Wrapper for prism2_pci
+
+Written by Michael Brown of Fen Systems Ltd
+$Id$
+***************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/pci.h>
+#include <nic.h>
+
+#define WLAN_HOSTIF WLAN_PCI
+#include "prism2.c"
+
+static int prism2_pci_probe ( struct nic *nic, struct pci_device *pci ) {
+  hfa384x_t *hw = &hw_global;
+
+  printf ( "Prism2.5 has registers at %#lx\n", pci->membase );
+  hw->membase = ioremap ( pci->membase, 0x100 );
+
+  nic->ioaddr = pci->membase;
+  nic->irqno = 0;
+
+  return prism2_probe ( nic, hw );
+}
+
+static void prism2_pci_disable ( struct nic *nic ) {
+  prism2_disable ( nic );
+}
+
+static struct pci_device_id prism2_pci_nics[] = {
+PCI_ROM(0x1260, 0x3873, "prism2_pci",	"Harris Semiconductor Prism2.5 clone", 0),
+PCI_ROM(0x1260, 0x3873, "hwp01170",	"ActionTec HWP01170", 0),
+PCI_ROM(0x1260, 0x3873, "dwl520",	"DLink DWL-520", 0),
+};
+
+PCI_DRIVER ( prism2_pci_driver, prism2_pci_nics, PCI_NO_CLASS );
+
+DRIVER ( "Prism2/PCI", nic_driver, pci_driver, prism2_pci_driver,
+	 prism2_pci_probe, prism2_pci_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_plx.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_plx.c
new file mode 100644
index 0000000..2098f7f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/prism2_plx.c
@@ -0,0 +1,122 @@
+/**************************************************************************
+Etherboot -  BOOTP/TFTP Bootstrap Program
+Prism2 NIC driver for Etherboot
+Wrapper for prism2_plx
+
+Written by Michael Brown of Fen Systems Ltd
+$Id$
+***************************************************************************/
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/pci.h>
+#include <nic.h>
+
+#define WLAN_HOSTIF WLAN_PLX
+#include "prism2.c"
+
+/*
+ * Find PLX card.  Prints out information strings from PCMCIA CIS as visual
+ * confirmation of presence of card.
+ *
+ * Arguments:
+ *	hw		device structure to be filled in
+ *      p               PCI device structure
+ *
+ * Returns:
+ *      1               Success
+ */
+static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p )
+{
+  int found = 0;
+  uint32_t plx_lcr  = 0; /* PLX9052 Local Configuration Register Base (I/O) */
+  uint32_t attr_mem = 0; /* Prism2 Attribute Memory Base */
+  uint32_t iobase   = 0; /* Prism2 I/O Base */
+  unsigned char *cis_tpl  = NULL;
+  unsigned char *cis_string;
+  
+  /* Obtain all memory and IO base addresses */
+  pci_read_config_dword( p, PLX_LOCAL_CONFIG_REGISTER_BASE, &plx_lcr);
+  plx_lcr &= PCI_BASE_ADDRESS_IO_MASK;
+  pci_read_config_dword( p, PRISM2_PLX_ATTR_MEM_BASE, &attr_mem);
+  pci_read_config_dword( p, PRISM2_PLX_IO_BASE, &iobase);
+  iobase &= PCI_BASE_ADDRESS_IO_MASK;
+
+  /* Fill out hw structure */
+  hw->iobase = iobase;
+  printf ( "PLX9052 has local config registers at %#x\n", plx_lcr );
+  printf ( "Prism2 has attribute memory at %#x and I/O base at %#x\n", attr_mem, iobase );
+
+  /* Search for CIS strings */
+  printf ( "Searching for PCMCIA card...\n" );
+  cis_tpl = bus_to_virt(attr_mem);
+  while ( *cis_tpl != CISTPL_END ) {
+    if ( *cis_tpl == CISTPL_VERS_1 ) {
+      /* CISTPL_VERS_1 contains some nice text strings */
+      printf ( "...found " );
+      found = 1;
+      cis_string = cis_tpl + CISTPL_VERS_1_STR_OFF;
+      while ( ! ( ( *cis_string == 0 ) && ( *(cis_string+CIS_STEP) == 0 ) ) ) {
+	printf ( "%c", *cis_string == 0 ? ' ' : *cis_string );
+	cis_string += CIS_STEP;
+      }
+      printf ( "\n" );
+    }
+    /* printf ( "CIS tuple type %#hhx, length %#hhx\n", *cis_tpl, *(cis_tpl+CISTPL_LEN_OFF) ); */
+    cis_tpl += CISTPL_HEADER_LEN + CIS_STEP * ( *(cis_tpl+CISTPL_LEN_OFF) );
+  }
+  if ( found == 0 ) {
+    printf ( "...nothing found\n" );
+  }
+  ((unsigned char *)bus_to_virt(attr_mem))[COR_OFFSET] = COR_VALUE; /* Write COR to enable PC card */
+  return found;
+}
+
+static int prism2_plx_probe ( struct nic *nic, struct pci_device *pci ) {
+  hfa384x_t *hw = &hw_global;
+  
+  /* Find and intialise PLX Prism2 card */
+  if ( ! prism2_find_plx ( hw, pci ) ) return 0;
+  nic->ioaddr = hw->iobase;
+  nic->irqno  = 0;
+  return prism2_probe ( nic, hw );
+}
+
+static void prism2_plx_disable ( struct nic *nic ) {
+  prism2_disable ( nic );
+}
+
+static struct pci_device_id prism2_plx_nics[] = {
+PCI_ROM(0x1385, 0x4100, "ma301",         "Netgear MA301", 0),
+PCI_ROM(0x10b7, 0x7770, "3c-airconnect", "3Com AirConnect", 0),
+PCI_ROM(0x111a, 0x1023, "ss1023",        "Siemens SpeedStream SS1023", 0),
+PCI_ROM(0x15e8, 0x0130, "correga",       "Correga", 0),
+PCI_ROM(0x1638, 0x1100, "smc2602w",      "SMC EZConnect SMC2602W", 0),	/* or Eumitcom PCI WL11000, Addtron AWA-100 */
+PCI_ROM(0x16ab, 0x1100, "gl24110p",      "Global Sun Tech GL24110P", 0),
+PCI_ROM(0x16ab, 0x1101, "16ab-1101",     "Unknown", 0),
+PCI_ROM(0x16ab, 0x1102, "wdt11",         "Linksys WDT11", 0),
+PCI_ROM(0x16ec, 0x3685, "usr2415",       "USR 2415", 0),
+PCI_ROM(0xec80, 0xec00, "f5d6000",       "Belkin F5D6000", 0),
+PCI_ROM(0x126c, 0x8030, "emobility",     "Nortel emobility", 0),
+};
+
+PCI_DRIVER ( prism2_plx_driver, prism2_plx_nics, PCI_NO_CLASS );
+
+
+DRIVER ( "Prism2/PLX", nic_driver, pci_driver, prism2_plx_driver,
+	 prism2_plx_probe, prism2_plx_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.c
new file mode 100644
index 0000000..13ab65b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.c
@@ -0,0 +1,2232 @@
+/*
+ * Copyright (c) 2008 Marty Connor <mdc at etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen at realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu at fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+#include <mii.h>
+
+#include "r8169.h"
+
+/*** Low level hardware routines ***/
+
+static void mdio_write(void *ioaddr, int reg_addr, int value)
+{
+	int i;
+
+	DBGP ( "mdio_write\n" );
+
+	RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
+
+	for (i = 20; i > 0; i--) {
+		/*
+		 * Check if the RTL8169 has completed writing to the specified
+		 * MII register.
+		 */
+		if (!(RTL_R32(PHYAR) & 0x80000000))
+			break;
+		udelay(25);
+	}
+}
+
+static int mdio_read(void *ioaddr, int reg_addr)
+{
+	int i, value = -1;
+
+	DBGP ( "mdio_read\n" );
+
+	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
+
+	for (i = 20; i > 0; i--) {
+		/*
+		 * Check if the RTL8169 has completed retrieving data from
+		 * the specified MII register.
+		 */
+		if (RTL_R32(PHYAR) & 0x80000000) {
+			value = RTL_R32(PHYAR) & 0xffff;
+			break;
+		}
+		udelay(25);
+	}
+	return value;
+}
+
+static void mdio_patch(void *ioaddr, int reg_addr, int value)
+{
+	DBGP ( "mdio_patch\n" );
+
+	mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
+
+static void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
+{
+	unsigned int i;
+
+	DBGP ( "rtl_ephy_write\n" );
+
+	RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
+			break;
+		udelay(10);
+	}
+}
+
+static u16 rtl_ephy_read(void *ioaddr, int reg_addr)
+{
+	u16 value = 0xffff;
+	unsigned int i;
+
+	DBGP ( "rtl_ephy_read\n" );
+
+	RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+			value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
+			break;
+		}
+		udelay(10);
+	}
+
+	return value;
+}
+
+static void rtl_csi_write(void *ioaddr, int addr, int value)
+{
+	unsigned int i;
+
+	DBGP ( "rtl_csi_write\n" );
+
+	RTL_W32(CSIDR, value);
+	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+			break;
+		udelay(10);
+	}
+}
+
+static u32 rtl_csi_read(void *ioaddr, int addr)
+{
+	u32 value = ~0x00;
+	unsigned int i;
+
+	DBGP ( "rtl_csi_read\n" );
+
+	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+	for (i = 0; i < 100; i++) {
+		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+			value = RTL_R32(CSIDR);
+			break;
+		}
+		udelay(10);
+	}
+
+	return value;
+}
+
+static void rtl8169_irq_mask_and_ack(void *ioaddr)
+{
+	DBGP ( "rtl8169_irq_mask_and_ack\n" );
+
+	RTL_W16(IntrMask, 0x0000);
+
+	RTL_W16(IntrStatus, 0xffff);
+}
+
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
+{
+	DBGP ( "rtl8169_tbi_reset_pending\n" );
+
+	return RTL_R32(TBICSR) & TBIReset;
+}
+
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+	DBGP ( "rtl8169_xmii_reset_pending\n" );
+
+	return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
+}
+
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
+{
+	DBGP ( "rtl8169_tbi_link_ok\n" );
+
+	return RTL_R32(TBICSR) & TBILinkOk;
+}
+
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+	DBGP ( "rtl8169_xmii_link_ok\n" );
+
+	return RTL_R8(PHYstatus) & LinkStatus;
+}
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
+{
+	DBGP ( "rtl8169_tbi_reset_enable\n" );
+
+	RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
+
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+	unsigned int val;
+
+	DBGP ( "rtl8169_xmii_reset_enable\n" );
+
+	val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+	mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+}
+
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+				 u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int ret = 0;
+	u32 reg;
+
+	DBGP ( "rtl8169_set_speed_tbi\n" );
+
+	reg = RTL_R32(TBICSR);
+	if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+	    (duplex == DUPLEX_FULL)) {
+		RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+	} else if (autoneg == AUTONEG_ENABLE)
+		RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+	else {
+		DBG ( "incorrect speed setting refused in TBI mode\n" );
+		ret = -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+				  u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int auto_nego, giga_ctrl;
+
+	DBGP ( "rtl8169_set_speed_xmii\n" );
+
+	auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+	auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+		       ADVERTISE_100HALF | ADVERTISE_100FULL);
+	giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+	giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
+	if (autoneg == AUTONEG_ENABLE) {
+		auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+			      ADVERTISE_100HALF | ADVERTISE_100FULL);
+		giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+	} else {
+		if (speed == SPEED_10)
+			auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+		else if (speed == SPEED_100)
+			auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+		else if (speed == SPEED_1000)
+			giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+
+		if (duplex == DUPLEX_HALF)
+			auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
+
+		if (duplex == DUPLEX_FULL)
+			auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
+
+		/* This tweak comes straight from Realtek's driver. */
+		if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
+		    ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+		     (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
+			auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
+		}
+	}
+
+	/* The 8100e/8101e/8102e do Fast Ethernet only. */
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+		if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) {
+			DBG ( "PHY does not support 1000Mbps.\n" );
+		}
+		giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+	}
+
+	auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+	    (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+		/*
+		 * Wake up the PHY.
+		 * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+		 */
+		mdio_write(ioaddr, 0x1f, 0x0000);
+		mdio_write(ioaddr, 0x0e, 0x0000);
+	}
+
+	tp->phy_auto_nego_reg = auto_nego;
+	tp->phy_1000_ctrl_reg = giga_ctrl;
+
+	mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+	mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+	mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+	return 0;
+}
+
+static int rtl8169_set_speed(struct net_device *dev,
+			     u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int ret;
+
+	DBGP ( "rtl8169_set_speed\n" );
+
+	ret = tp->set_speed(dev, autoneg, speed, duplex);
+
+	return ret;
+}
+
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
+				       int bitnum, int bitval)
+{
+	int val;
+
+	DBGP ( "rtl8169_write_gmii_reg_bit\n" );
+
+	val = mdio_read(ioaddr, reg);
+	val = (bitval == 1) ?
+		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);
+	mdio_write(ioaddr, reg, val & 0xffff);
+}
+
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+				    void *ioaddr)
+{
+	/*
+	 * The driver currently handles the 8168Bf and the 8168Be identically
+	 * but they can be identified more specifically through the test below
+	 * if needed:
+	 *
+	 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+	 *
+	 * Same thing for the 8101Eb and the 8101Ec:
+	 *
+	 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
+	 */
+	const struct {
+		u32 mask;
+		u32 val;
+		int mac_version;
+	} mac_info[] = {
+		/* 8168D family. */
+		{ 0x7c800000, 0x28000000,	RTL_GIGA_MAC_VER_25 },
+
+		/* 8168C family. */
+		{ 0x7cf00000, 0x3ca00000,	RTL_GIGA_MAC_VER_24 },
+		{ 0x7cf00000, 0x3c900000,	RTL_GIGA_MAC_VER_23 },
+		{ 0x7cf00000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },
+		{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_24 },
+		{ 0x7cf00000, 0x3c000000,	RTL_GIGA_MAC_VER_19 },
+		{ 0x7cf00000, 0x3c200000,	RTL_GIGA_MAC_VER_20 },
+		{ 0x7cf00000, 0x3c300000,	RTL_GIGA_MAC_VER_21 },
+		{ 0x7cf00000, 0x3c400000,	RTL_GIGA_MAC_VER_22 },
+		{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_22 },
+
+		/* 8168B family. */
+		{ 0x7cf00000, 0x38000000,	RTL_GIGA_MAC_VER_12 },
+		{ 0x7cf00000, 0x38500000,	RTL_GIGA_MAC_VER_17 },
+		{ 0x7c800000, 0x38000000,	RTL_GIGA_MAC_VER_17 },
+		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
+
+		/* 8101 family. */
+		{ 0x7cf00000, 0x34a00000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7cf00000, 0x24a00000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7cf00000, 0x34900000,	RTL_GIGA_MAC_VER_08 },
+		{ 0x7cf00000, 0x24900000,	RTL_GIGA_MAC_VER_08 },
+		{ 0x7cf00000, 0x34800000,	RTL_GIGA_MAC_VER_07 },
+		{ 0x7cf00000, 0x24800000,	RTL_GIGA_MAC_VER_07 },
+		{ 0x7cf00000, 0x34000000,	RTL_GIGA_MAC_VER_13 },
+		{ 0x7cf00000, 0x34300000,	RTL_GIGA_MAC_VER_10 },
+		{ 0x7cf00000, 0x34200000,	RTL_GIGA_MAC_VER_16 },
+		{ 0x7c800000, 0x34800000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7c800000, 0x24800000,	RTL_GIGA_MAC_VER_09 },
+		{ 0x7c800000, 0x34000000,	RTL_GIGA_MAC_VER_16 },
+		/* FIXME: where did these entries come from ? -- FR */
+		{ 0xfc800000, 0x38800000,	RTL_GIGA_MAC_VER_15 },
+		{ 0xfc800000, 0x30800000,	RTL_GIGA_MAC_VER_14 },
+
+		/* 8110 family. */
+		{ 0xfc800000, 0x98000000,	RTL_GIGA_MAC_VER_06 },
+		{ 0xfc800000, 0x18000000,	RTL_GIGA_MAC_VER_05 },
+		{ 0xfc800000, 0x10000000,	RTL_GIGA_MAC_VER_04 },
+		{ 0xfc800000, 0x04000000,	RTL_GIGA_MAC_VER_03 },
+		{ 0xfc800000, 0x00800000,	RTL_GIGA_MAC_VER_02 },
+		{ 0xfc800000, 0x00000000,	RTL_GIGA_MAC_VER_01 },
+
+		{ 0x00000000, 0x00000000,	RTL_GIGA_MAC_VER_01 }	/* Catch-all */
+	}, *p = mac_info;
+	u32 reg;
+
+	DBGP ( "rtl8169_get_mac_version\n" );
+
+	reg = RTL_R32(TxConfig);
+	while ((reg & p->mask) != p->val)
+		p++;
+	tp->mac_version = p->mac_version;
+
+	DBG ( "tp->mac_version = %d\n", tp->mac_version );
+
+	if (p->mask == 0x00000000) {
+		DBG ( "unknown MAC (%08x)\n", reg );
+	}
+}
+
+struct phy_reg {
+	u16 reg;
+	u16 val;
+};
+
+static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
+{
+	DBGP ( "rtl_phy_write\n" );
+
+	while (len-- > 0) {
+		mdio_write(ioaddr, regs->reg, regs->val);
+		regs++;
+	}
+}
+
+static void rtl8169s_hw_phy_config(void *ioaddr)
+{
+	struct {
+		u16 regs[5]; /* Beware of bit-sign propagation */
+	} phy_magic[5] = { {
+		{ 0x0000,	//w 4 15 12 0
+		  0x00a1,	//w 3 15 0 00a1
+		  0x0008,	//w 2 15 0 0008
+		  0x1020,	//w 1 15 0 1020
+		  0x1000 } },{	//w 0 15 0 1000
+		{ 0x7000,	//w 4 15 12 7
+		  0xff41,	//w 3 15 0 ff41
+		  0xde60,	//w 2 15 0 de60
+		  0x0140,	//w 1 15 0 0140
+		  0x0077 } },{	//w 0 15 0 0077
+		{ 0xa000,	//w 4 15 12 a
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xfa00 } },{	//w 0 15 0 fa00
+		{ 0xb000,	//w 4 15 12 b
+		  0xff41,	//w 3 15 0 ff41
+		  0xde20,	//w 2 15 0 de20
+		  0x0140,	//w 1 15 0 0140
+		  0x00bb } },{	//w 0 15 0 00bb
+		{ 0xf000,	//w 4 15 12 f
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xbf00 }	//w 0 15 0 bf00
+		}
+	}, *p = phy_magic;
+	unsigned int i;
+
+	DBGP ( "rtl8169s_hw_phy_config\n" );
+
+	mdio_write(ioaddr, 0x1f, 0x0001);		//w 31 2 0 1
+	mdio_write(ioaddr, 0x15, 0x1000);		//w 21 15 0 1000
+	mdio_write(ioaddr, 0x18, 0x65c7);		//w 24 15 0 65c7
+	rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);	//w 4 11 11 0
+
+	for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
+		int val, pos = 4;
+
+		val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+		mdio_write(ioaddr, pos, val);
+		while (--pos >= 0)
+			mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
+	}
+	mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169sb_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0002 },
+		{ 0x01, 0x90d0 },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8169sb_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bb_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x10, 0xf41b },
+		{ 0x1f, 0x0000 }
+	};
+
+	mdio_write(ioaddr, 0x1f, 0x0001);
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+
+	DBGP ( "rtl8168bb_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x10, 0xf41b },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8168bef_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_1_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0000 },
+		{ 0x1d, 0x0f00 },
+		{ 0x1f, 0x0002 },
+		{ 0x0c, 0x1ec8 },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8168cp_1_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_2_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x1d, 0x3d98 },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8168cp_2_hw_phy_config\n" );
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_1_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x12, 0x2300 },
+		{ 0x1f, 0x0002 },
+		{ 0x00, 0x88d4 },
+		{ 0x01, 0x82b1 },
+		{ 0x03, 0x7002 },
+		{ 0x08, 0x9e30 },
+		{ 0x09, 0x01f0 },
+		{ 0x0a, 0x5500 },
+		{ 0x0c, 0x00c8 },
+		{ 0x1f, 0x0003 },
+		{ 0x12, 0xc096 },
+		{ 0x16, 0x000a },
+		{ 0x1f, 0x0000 },
+		{ 0x1f, 0x0000 },
+		{ 0x09, 0x2000 },
+		{ 0x09, 0x0000 }
+	};
+
+	DBGP ( "rtl8168c_1_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_2_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x12, 0x2300 },
+		{ 0x03, 0x802f },
+		{ 0x02, 0x4f02 },
+		{ 0x01, 0x0409 },
+		{ 0x00, 0xf099 },
+		{ 0x04, 0x9800 },
+		{ 0x04, 0x9000 },
+		{ 0x1d, 0x3d98 },
+		{ 0x1f, 0x0002 },
+		{ 0x0c, 0x7eb8 },
+		{ 0x06, 0x0761 },
+		{ 0x1f, 0x0003 },
+		{ 0x16, 0x0f0a },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8168c_2_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_3_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x12, 0x2300 },
+		{ 0x1d, 0x3d98 },
+		{ 0x1f, 0x0002 },
+		{ 0x0c, 0x7eb8 },
+		{ 0x06, 0x5461 },
+		{ 0x1f, 0x0003 },
+		{ 0x16, 0x0f0a },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8168c_3_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	mdio_patch(ioaddr, 0x16, 1 << 0);
+	mdio_patch(ioaddr, 0x14, 1 << 5);
+	mdio_patch(ioaddr, 0x0d, 1 << 5);
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void *ioaddr)
+{
+	DBGP ( "rtl8168c_4_hw_phy_config\n" );
+
+	rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init_0[] = {
+		{ 0x1f, 0x0001 },
+		{ 0x09, 0x2770 },
+		{ 0x08, 0x04d0 },
+		{ 0x0b, 0xad15 },
+		{ 0x0c, 0x5bf0 },
+		{ 0x1c, 0xf101 },
+		{ 0x1f, 0x0003 },
+		{ 0x14, 0x94d7 },
+		{ 0x12, 0xf4d6 },
+		{ 0x09, 0xca0f },
+		{ 0x1f, 0x0002 },
+		{ 0x0b, 0x0b10 },
+		{ 0x0c, 0xd1f7 },
+		{ 0x1f, 0x0002 },
+		{ 0x06, 0x5461 },
+		{ 0x1f, 0x0002 },
+		{ 0x05, 0x6662 },
+		{ 0x1f, 0x0000 },
+		{ 0x14, 0x0060 },
+		{ 0x1f, 0x0000 },
+		{ 0x0d, 0xf8a0 },
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0xffc2 }
+	};
+
+	DBGP ( "rtl8168d_hw_phy_config\n" );
+
+	rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+	if (mdio_read(ioaddr, 0x06) == 0xc400) {
+		struct phy_reg phy_reg_init_1[] = {
+			{ 0x1f, 0x0005 },
+			{ 0x01, 0x0300 },
+			{ 0x1f, 0x0000 },
+			{ 0x11, 0x401c },
+			{ 0x16, 0x4100 },
+			{ 0x1f, 0x0005 },
+			{ 0x07, 0x0010 },
+			{ 0x05, 0x83dc },
+			{ 0x06, 0x087d },
+			{ 0x05, 0x8300 },
+			{ 0x06, 0x0101 },
+			{ 0x06, 0x05f8 },
+			{ 0x06, 0xf9fa },
+			{ 0x06, 0xfbef },
+			{ 0x06, 0x79e2 },
+			{ 0x06, 0x835f },
+			{ 0x06, 0xe0f8 },
+			{ 0x06, 0x9ae1 },
+			{ 0x06, 0xf89b },
+			{ 0x06, 0xef31 },
+			{ 0x06, 0x3b65 },
+			{ 0x06, 0xaa07 },
+			{ 0x06, 0x81e4 },
+			{ 0x06, 0xf89a },
+			{ 0x06, 0xe5f8 },
+			{ 0x06, 0x9baf },
+			{ 0x06, 0x06ae },
+			{ 0x05, 0x83dc },
+			{ 0x06, 0x8300 },
+		};
+
+		rtl_phy_write(ioaddr, phy_reg_init_1,
+			      ARRAY_SIZE(phy_reg_init_1));
+	}
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void *ioaddr)
+{
+	struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0003 },
+		{ 0x08, 0x441d },
+		{ 0x01, 0x9100 },
+		{ 0x1f, 0x0000 }
+	};
+
+	DBGP ( "rtl8102e_hw_phy_config\n" );
+
+	mdio_write(ioaddr, 0x1f, 0x0000);
+	mdio_patch(ioaddr, 0x11, 1 << 12);
+	mdio_patch(ioaddr, 0x19, 1 << 13);
+
+	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl_hw_phy_config(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "rtl_hw_phy_config\n" );
+
+	DBG ( "mac_version = 0x%02x\n", tp->mac_version );
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_01:
+		break;
+	case RTL_GIGA_MAC_VER_02:
+	case RTL_GIGA_MAC_VER_03:
+		rtl8169s_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_04:
+		rtl8169sb_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_07:
+	case RTL_GIGA_MAC_VER_08:
+	case RTL_GIGA_MAC_VER_09:
+		rtl8102e_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_11:
+		rtl8168bb_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_12:
+		rtl8168bef_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_17:
+		rtl8168bef_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_18:
+		rtl8168cp_1_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_19:
+		rtl8168c_1_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_20:
+		rtl8168c_2_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_21:
+		rtl8168c_3_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_22:
+		rtl8168c_4_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_23:
+	case RTL_GIGA_MAC_VER_24:
+		rtl8168cp_2_hw_phy_config(ioaddr);
+		break;
+	case RTL_GIGA_MAC_VER_25:
+		rtl8168d_hw_phy_config(ioaddr);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void rtl8169_phy_reset(struct net_device *dev __unused,
+			      struct rtl8169_private *tp)
+{
+	void *ioaddr = tp->mmio_addr;
+	unsigned int i;
+
+	DBGP ( "rtl8169_phy_reset\n" );
+
+	tp->phy_reset_enable(ioaddr);
+	for (i = 0; i < 100; i++) {
+		if (!tp->phy_reset_pending(ioaddr))
+			return;
+		mdelay ( 1 );
+	}
+	DBG ( "PHY reset failed.\n" );
+}
+
+static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+{
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "rtl8169_init_phy\n" );
+
+	rtl_hw_phy_config(dev);
+
+	if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+		DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+		RTL_W8(0x82, 0x01);
+	}
+
+	pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+		pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
+		DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+		RTL_W8(0x82, 0x01);
+		DBG ( "Set PHY Reg 0x0bh = 0x00h\n" );
+		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+	}
+
+	rtl8169_phy_reset(dev, tp);
+
+	/*
+	 * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+	 * only 8101. Don't panic.
+	 */
+	rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
+
+	if ((RTL_R8(PHYstatus) & TBI_Enable))
+		DBG ( "TBI auto-negotiating\n" );
+}
+
+static const struct rtl_cfg_info {
+	void (*hw_start)(struct net_device *);
+	unsigned int region;
+	unsigned int align;
+	u16 intr_event;
+	u16 napi_event;
+	unsigned features;
+} rtl_cfg_infos [] = {
+	[RTL_CFG_0] = {
+		.hw_start	= rtl_hw_start_8169,
+		.region		= 1,
+		.align		= 0,
+		.intr_event	= SYSErr | LinkChg | RxOverflow |
+				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+		.features	= RTL_FEATURE_GMII
+	},
+	[RTL_CFG_1] = {
+		.hw_start	= rtl_hw_start_8168,
+		.region		= 2,
+		.align		= 8,
+		.intr_event	= SYSErr | LinkChg | RxOverflow |
+				  TxErr | TxOK | RxOK | RxErr,
+		.napi_event	= TxErr | TxOK | RxOK | RxOverflow,
+		.features	= RTL_FEATURE_GMII
+	},
+	[RTL_CFG_2] = {
+		.hw_start	= rtl_hw_start_8101,
+		.region		= 2,
+		.align		= 8,
+		.intr_event	= SYSErr | LinkChg | RxOverflow | PCSTimeout |
+				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+	}
+};
+
+static void rtl8169_hw_reset(void *ioaddr)
+{
+	DBGP ( "rtl8169_hw_reset\n" );
+
+	/* Disable interrupts */
+	rtl8169_irq_mask_and_ack(ioaddr);
+
+	/* Reset the chipset */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* PCI commit */
+	RTL_R8(ChipCmd);
+}
+
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
+{
+	void *ioaddr = tp->mmio_addr;
+	u32 cfg = rtl8169_rx_config;
+
+	DBGP ( "rtl_set_rx_tx_config_registers\n" );
+
+	cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+	RTL_W32(RxConfig, cfg);
+
+	/* Set DMA burst size and Interframe Gap Time */
+	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+		(InterFrameGap << TxInterFrameGapShift));
+}
+
+static void rtl_soft_reset ( struct net_device *dev )
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	unsigned int i;
+
+	DBGP ( "rtl_hw_soft_reset\n" );
+
+	/* Soft reset the chip. */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 0; i < 100; i++) {
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		mdelay ( 1 );
+	}
+
+	if ( i == 100 ) {
+		DBG ( "Reset Failed! (> 100 iterations)\n" );
+	}
+}
+
+static void rtl_hw_start ( struct net_device *dev )
+{
+	struct rtl8169_private *tp = netdev_priv ( dev );
+
+	DBGP ( "rtl_hw_start\n" );
+
+	/* Soft reset NIC */
+	rtl_soft_reset ( dev );
+
+	tp->hw_start ( dev );
+}
+
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+					 void *ioaddr)
+{
+	DBGP ( "rtl_set_rx_tx_desc_registers\n" );
+
+	/*
+	 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+	 * register to be written before TxDescAddrLow to work.
+	 * Switching from MMIO to I/O access fixes the issue as well.
+	 */
+	RTL_W32 ( TxDescStartAddrHigh, 0 );
+	RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) );
+	RTL_W32 ( RxDescAddrHigh, 0 );
+	RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) );
+}
+
+static u16 rtl_rw_cpluscmd(void *ioaddr)
+{
+	u16 cmd;
+
+	DBGP ( "rtl_rw_cpluscmd\n" );
+
+	cmd = RTL_R16(CPlusCmd);
+	RTL_W16(CPlusCmd, cmd);
+	return cmd;
+}
+
+static void rtl_set_rx_max_size(void *ioaddr)
+{
+	DBGP ( "rtl_set_rx_max_size\n" );
+
+	RTL_W16 ( RxMaxSize, RX_BUF_SIZE );
+}
+
+static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version)
+{
+	struct {
+		u32 mac_version;
+		u32 clk;
+		u32 val;
+	} cfg2_info [] = {
+		{ RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+		{ RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+		{ RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+		{ RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+	}, *p = cfg2_info;
+	unsigned int i;
+	u32 clk;
+
+	DBGP ( "rtl8169_set_magic_reg\n" );
+
+	clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+	for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
+		if ((p->mac_version == mac_version) && (p->clk == clk)) {
+			RTL_W32(0x7c, p->val);
+			break;
+		}
+	}
+}
+
+static void rtl_set_rx_mode ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+	u32 tmp;
+
+	DBGP ( "rtl_set_rx_mode\n" );
+
+	/* Accept all Multicast Packets */
+
+	RTL_W32 ( MAR0 + 0, 0xffffffff );
+	RTL_W32 ( MAR0 + 4, 0xffffffff );
+
+	tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+	      ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask );
+
+	RTL_W32 ( RxConfig, tmp );
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	struct pci_device *pdev = tp->pci_dev;
+
+	DBGP ( "rtl_hw_start_8169\n" );
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+		RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
+	}
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_04))
+		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_set_rx_max_size(ioaddr);
+
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_04))
+		rtl_set_rx_tx_config_registers(tp);
+
+	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+		DBG ( "Set MAC Reg C+CR Offset 0xE0. "
+			"Bit-3 and bit-14 MUST be 1\n" );
+		tp->cp_cmd |= (1 << 14);
+	}
+
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+
+	rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
+	/*
+	 * Undocumented corner. Supposedly:
+	 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
+	 */
+	RTL_W16(IntrMitigate, 0x0000);
+
+	rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+	if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+		rtl_set_rx_tx_config_registers(tp);
+	}
+
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+
+	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+	RTL_R8(IntrMask);
+
+	RTL_W32(RxMissed, 0);
+
+	rtl_set_rx_mode(dev);
+
+	/* no early-rx interrupts */
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+	//        RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int cap = tp->pcie_cap;
+
+	DBGP ( "rtl_tx_performance_tweak\n" );
+
+	if (cap) {
+		u16 ctl;
+
+		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+	}
+}
+
+static void rtl_csi_access_enable(void *ioaddr)
+{
+	u32 csi;
+
+	DBGP ( "rtl_csi_access_enable\n" );
+
+	csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+	rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+	unsigned int offset;
+	u16 mask;
+	u16 bits;
+};
+
+static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len)
+{
+	u16 w;
+
+	DBGP ( "rtl_ephy_init\n" );
+
+	while (len-- > 0) {
+		w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+		rtl_ephy_write(ioaddr, e->offset, w);
+		e++;
+	}
+}
+
+static void rtl_disable_clock_request(struct pci_device *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int cap = tp->pcie_cap;
+
+	DBGP ( "rtl_disable_clock_request\n" );
+
+	if (cap) {
+		u16 ctl;
+
+		pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+		ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+		pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+	}
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+	EnableBist | \
+	Mac_dbgo_oe | \
+	Force_half_dup | \
+	Force_rxflow_en | \
+	Force_txflow_en | \
+	Cxpl_dbg_sel | \
+	ASF | \
+	PktCntrDisable | \
+	Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168bb\n" );
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+	rtl_tx_performance_tweak(pdev,
+		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168bef\n" );
+
+	rtl_hw_start_8168bb(ioaddr, pdev);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "__rtl_hw_start_8168cp\n" );
+
+	RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev)
+{
+	static struct ephy_info e_info_8168cp[] = {
+		{ 0x01, 0,	0x0001 },
+		{ 0x02, 0x0800,	0x1000 },
+		{ 0x03, 0,	0x0042 },
+		{ 0x06, 0x0080,	0x0000 },
+		{ 0x07, 0,	0x2000 }
+	};
+
+	DBGP ( "rtl_hw_start_8168cp_1\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168cp_2\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168cp_3\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	/* Magic. */
+	RTL_W8(DBG_REG, 0x20);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev)
+{
+	static struct ephy_info e_info_8168c_1[] = {
+		{ 0x02, 0x0800,	0x1000 },
+		{ 0x03, 0,	0x0002 },
+		{ 0x06, 0x0080,	0x0000 }
+	};
+
+	DBGP ( "rtl_hw_start_8168c_1\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+	rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev)
+{
+	static struct ephy_info e_info_8168c_2[] = {
+		{ 0x01, 0,	0x0001 },
+		{ 0x03, 0x0400,	0x0220 }
+	};
+
+	DBGP ( "rtl_hw_start_8168c_2\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168c_3\n" );
+
+	rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168c_4\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	__rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8168d\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	struct pci_device *pdev = tp->pci_dev;
+
+	DBGP ( "rtl_hw_start_8168\n" );
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_set_rx_max_size(ioaddr);
+
+	tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+
+	RTL_W16(IntrMitigate, 0x5151);
+
+	/* Work around for RxFIFO overflow. */
+	if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+		tp->intr_event |= RxFIFOOver | PCSTimeout;
+		tp->intr_event &= ~RxOverflow;
+	}
+
+	rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+	rtl_set_rx_mode(dev);
+
+	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+		(InterFrameGap << TxInterFrameGapShift));
+
+	RTL_R8(IntrMask);
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_11:
+		rtl_hw_start_8168bb(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_12:
+	case RTL_GIGA_MAC_VER_17:
+		rtl_hw_start_8168bef(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_18:
+		rtl_hw_start_8168cp_1(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_19:
+		rtl_hw_start_8168c_1(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_20:
+		rtl_hw_start_8168c_2(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_21:
+		rtl_hw_start_8168c_3(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_22:
+		rtl_hw_start_8168c_4(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_23:
+		rtl_hw_start_8168cp_2(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_24:
+		rtl_hw_start_8168cp_3(ioaddr, pdev);
+	break;
+
+	case RTL_GIGA_MAC_VER_25:
+		rtl_hw_start_8168d(ioaddr, pdev);
+	break;
+
+	default:
+		DBG ( "Unknown chipset (mac_version = %d).\n",
+		      tp->mac_version );
+	break;
+	}
+
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+	//        RTL_W16(IntrMask, tp->intr_event);
+}
+
+#define R810X_CPCMD_QUIRK_MASK (\
+	EnableBist | \
+	Mac_dbgo_oe | \
+	Force_half_dup | \
+	Force_half_dup | \
+	Force_txflow_en | \
+	Cxpl_dbg_sel | \
+	ASF | \
+	PktCntrDisable | \
+	PCIDAC | \
+	PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev)
+{
+	static struct ephy_info e_info_8102e_1[] = {
+		{ 0x01,	0, 0x6e65 },
+		{ 0x02,	0, 0x091f },
+		{ 0x03,	0, 0xc2f9 },
+		{ 0x06,	0, 0xafb5 },
+		{ 0x07,	0, 0x0e00 },
+		{ 0x19,	0, 0xec80 },
+		{ 0x01,	0, 0x2e65 },
+		{ 0x01,	0, 0x6e65 }
+	};
+	u8 cfg1;
+
+	DBGP ( "rtl_hw_start_8102e_1\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	RTL_W8(DBG_REG, FIX_NAK_1);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W8(Config1,
+	       LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	cfg1 = RTL_R8(Config1);
+	if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+		RTL_W8(Config1, cfg1 & ~LEDS0);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+	rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8102e_2\n" );
+
+	rtl_csi_access_enable(ioaddr);
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev)
+{
+	DBGP ( "rtl_hw_start_8102e_3\n" );
+
+	rtl_hw_start_8102e_2(ioaddr, pdev);
+
+	rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	struct pci_device *pdev = tp->pci_dev;
+
+	DBGP ( "rtl_hw_start_8101\n" );
+
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+		int cap = tp->pcie_cap;
+
+		if (cap) {
+			pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+					      PCI_EXP_DEVCTL_NOSNOOP_EN);
+		}
+	}
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_07:
+		rtl_hw_start_8102e_1(ioaddr, pdev);
+		break;
+
+	case RTL_GIGA_MAC_VER_08:
+		rtl_hw_start_8102e_3(ioaddr, pdev);
+		break;
+
+	case RTL_GIGA_MAC_VER_09:
+		rtl_hw_start_8102e_2(ioaddr, pdev);
+		break;
+	}
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	rtl_set_rx_max_size(ioaddr);
+
+	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+
+	RTL_W16(IntrMitigate, 0x0000);
+
+	rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	rtl_set_rx_tx_config_registers(tp);
+
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+
+	RTL_R8(IntrMask);
+
+	rtl_set_rx_mode(dev);
+
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+	//        RTL_W16(IntrMask, tp->intr_event);
+}
+
+/*** iPXE API Support Routines ***/
+
+/**
+ * setup_tx_resources - allocate tx resources (descriptors)
+ *
+ * @v tp	 Driver private storage
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int
+rtl8169_setup_tx_resources ( struct rtl8169_private *tp )
+{
+	DBGP ( "rtl8169_setup_tx_resources\n" );
+
+	tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
+
+	if ( ! tp->tx_base ) {
+		return -ENOMEM;
+	}
+
+	memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
+
+	DBG ( "tp->tx_base      = %#08lx\n", virt_to_bus ( tp->tx_base ) );
+
+	tp->tx_fill_ctr = 0;
+	tp->tx_curr = 0;
+	tp->tx_tail = 0;
+
+	return 0;
+}
+
+static void
+rtl8169_process_tx_packets ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+
+	uint32_t tx_status;
+	struct TxDesc *tx_curr_desc;
+
+	DBGP ( "rtl8169_process_tx_packets\n" );
+
+	while ( tp->tx_tail != tp->tx_curr ) {
+
+		tx_curr_desc = tp->tx_base  + tp->tx_tail;
+
+		tx_status = tx_curr_desc->opts1;
+
+		DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status );
+
+		/* if the packet at tx_tail is not owned by hardware it is for us */
+		if ( tx_status & DescOwn )
+			break;
+
+		DBG ( "Transmitted packet.\n" );
+		DBG ( "tp->tx_fill_ctr     = %d\n", tp->tx_fill_ctr );
+		DBG ( "tp->tx_tail         = %d\n", tp->tx_tail );
+		DBG ( "tp->tx_curr         = %d\n", tp->tx_curr );
+		DBG ( "tx_status           = %d\n", tx_status );
+		DBG ( "tx_curr_desc        = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+
+		/* Pass packet to core for processing */
+		netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
+
+		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+		/* Decrement count of used descriptors */
+		tp->tx_fill_ctr--;
+
+		/* Increment sent packets index */
+		tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
+	}
+}
+
+static void
+rtl8169_free_tx_resources ( struct rtl8169_private *tp )
+{
+	DBGP ( "rtl8169_free_tx_resources\n" );
+
+	free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
+}
+
+static void
+rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
+{
+	DBGP ( "rtl8169_populate_rx_descriptor\n" );
+
+	DBG ( "Populating rx descriptor %d\n", index );
+
+	memset ( rx_desc, 0, sizeof ( *rx_desc ) );
+
+	rx_desc->addr_hi = 0;
+	rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
+	rx_desc->opts2 = 0;
+	rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
+		RX_BUF_SIZE;
+	rx_desc->opts1 |= DescOwn;
+}
+
+/**
+ * Refill descriptor ring
+ *
+ * @v netdev		Net device
+ */
+static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
+{
+	struct RxDesc *rx_curr_desc;
+	int i;
+
+	DBGP ( "rtl8169_refill_rx_ring\n" );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+		rx_curr_desc = ( tp->rx_base ) + i;
+
+		/* Don't touch descriptors owned by the NIC */
+		if ( rx_curr_desc->opts1 & DescOwn )
+			continue;
+
+		/* Don't touch descriptors with iobufs, they still need to be
+		   processed by the poll routine */
+		if ( tp->rx_iobuf[tp->rx_curr] != NULL )
+			continue;
+
+		/** If we can't get an iobuf for this descriptor
+		    try again later (next poll).
+		 */
+		if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
+			DBG ( "Refill rx ring failed!!\n" );
+			break;
+		}
+
+		rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
+	}
+}
+
+/**
+ * setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v tp:	 Driver private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ *
+ **/
+static int
+rtl8169_setup_rx_resources ( struct rtl8169_private *tp )
+{
+	DBGP ( "rtl8169_setup_rx_resources\n" );
+
+	tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
+
+	DBG ( "tp->rx_base      = %#08lx\n", virt_to_bus ( tp->rx_base ) );
+
+	if ( ! tp->rx_base ) {
+		return -ENOMEM;
+	}
+	memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
+
+	rtl8169_refill_rx_ring ( tp );
+
+	tp->rx_curr = 0;
+
+	return 0;
+}
+
+static void
+rtl8169_process_rx_packets ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	uint32_t rx_status;
+	uint16_t rx_len;
+	struct RxDesc *rx_curr_desc;
+	int i;
+
+	DBGP ( "rtl8169_process_rx_packets\n" );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+		rx_curr_desc = tp->rx_base  + tp->rx_curr;
+
+		rx_status = rx_curr_desc->opts1;
+
+		DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status );
+
+		/* Hardware still owns the descriptor */
+		if ( rx_status & DescOwn )
+			break;
+
+		/* We own the descriptor, but it has not been refilled yet */
+		if ( tp->rx_iobuf[tp->rx_curr] == NULL )
+			break;
+
+		rx_len = rx_status & 0x3fff;
+
+		DBG ( "Received packet.\n" );
+		DBG ( "tp->rx_curr         = %d\n", tp->rx_curr );
+		DBG ( "rx_len              = %d\n", rx_len );
+		DBG ( "rx_status           = %#08x\n", rx_status );
+		DBG ( "rx_curr_desc        = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
+
+		if ( rx_status & RxRES ) {
+
+			netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
+
+			DBG ( "rtl8169_poll: Corrupted packet received!\n"
+			       " rx_status: %#08x\n", rx_status );
+
+		} else 	{
+
+			/* Adjust size of the iobuf to reflect received data */
+			iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
+
+			/* Add this packet to the receive queue.  */
+			netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
+		}
+
+		/* Invalidate this iobuf and descriptor */
+		tp->rx_iobuf[tp->rx_curr] = NULL;
+		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+		/* Update pointer to next available rx descriptor */
+		tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
+	}
+	rtl8169_refill_rx_ring ( tp );
+}
+
+static void
+rtl8169_free_rx_resources ( struct rtl8169_private *tp )
+{
+	int i;
+
+	DBGP ( "rtl8169_free_rx_resources\n" );
+
+	free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
+
+	for ( i = 0; i < NUM_RX_DESC; i++ ) {
+		free_iob ( tp->rx_iobuf[i] );
+		tp->rx_iobuf[i] = NULL;
+	}
+}
+
+static void rtl8169_irq_enable ( struct rtl8169_private *tp )
+{
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "rtl8169_irq_enable\n" );
+
+	RTL_W16 ( IntrMask, tp->intr_event );
+}
+
+static void rtl8169_irq_disable ( struct rtl8169_private *tp )
+{
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "rtl8169_irq_disable\n" );
+
+	RTL_W16 ( IntrMask, 0x0000 );
+}
+
+/*** iPXE Core API Routines ***/
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev	network interface device structure
+ * @ret rc	Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int
+rtl8169_open ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+	int rc;
+
+	DBGP ( "rtl8169_open\n" );
+
+	/* allocate transmit descriptors */
+	rc = rtl8169_setup_tx_resources ( tp );
+	if ( rc ) {
+		DBG ( "Error setting up TX resources!\n" );
+		goto err_setup_tx;
+	}
+
+	/* allocate receive descriptors */
+	rc = rtl8169_setup_rx_resources ( tp );
+	if ( rc ) {
+		DBG ( "Error setting up RX resources!\n" );
+		goto err_setup_rx;
+	}
+
+	rtl_hw_start ( netdev );
+
+	DBG ( "TxDescStartAddrHigh   = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
+	DBG ( "TxDescStartAddrLow    = %#08lx\n", RTL_R32 ( TxDescStartAddrLow  ) );
+	DBG ( "RxDescAddrHigh        = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
+	DBG ( "RxDescAddrLow         = %#08lx\n", RTL_R32 ( RxDescAddrLow  ) );
+
+	return 0;
+
+err_setup_rx:
+	rtl8169_free_tx_resources ( tp );
+err_setup_tx:
+	rtl8169_hw_reset ( ioaddr );
+
+	return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ */
+static int
+rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+	uint32_t tx_len = iob_len ( iobuf );
+
+	struct TxDesc *tx_curr_desc;
+
+	DBGP ("rtl8169_transmit\n");
+
+	if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
+		DBG ("TX overflow\n");
+		return -ENOBUFS;
+	}
+
+	/**
+	 *  The rtl8169 family automatically pads short packets to a
+	 *  minimum size, but if it did not, like some older cards,
+	 *  we could do:
+	 *  iob_pad ( iobuf, ETH_ZLEN );
+	 */
+
+	/* Save pointer to this iobuf we have been given to transmit so
+	   we can pass it to netdev_tx_complete() later */
+	tp->tx_iobuf[tp->tx_curr] = iobuf;
+
+	tx_curr_desc = tp->tx_base + tp->tx_curr;
+
+	DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
+	DBG ( "tp->tx_curr     = %d\n", tp->tx_curr );
+	DBG ( "tx_curr_desc    = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+	DBG ( "iobuf->data     = %#08lx\n", virt_to_bus ( iobuf->data ) );
+	DBG ( "tx_len          = %d\n", tx_len );
+
+	/* Configure current descriptor to transmit supplied packet */
+	tx_curr_desc->addr_hi = 0;
+	tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
+	tx_curr_desc->opts2 = 0;
+	tx_curr_desc->opts1 = FirstFrag | LastFrag |
+		( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
+		tx_len;
+
+	/* Mark descriptor as owned by NIC */
+	tx_curr_desc->opts1 |= DescOwn;
+
+	DBG ( "tx_curr_desc->opts1   = %#08x\n", tx_curr_desc->opts1 );
+	DBG ( "tx_curr_desc->opts2   = %#08x\n", tx_curr_desc->opts2 );
+	DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi );
+	DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo );
+
+	RTL_W8 ( TxPoll, NPQ );	/* set polling bit */
+
+	/* Point to next free descriptor */
+	tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
+
+	/* Increment number of tx descriptors in use */
+	tp->tx_fill_ctr++;
+
+	return 0;
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void
+rtl8169_poll ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+
+	uint16_t intr_status;
+	uint16_t intr_mask;
+
+	DBGP ( "rtl8169_poll\n" );
+
+	intr_status = RTL_R16 ( IntrStatus );
+	intr_mask   = RTL_R16 ( IntrMask );
+
+	DBG2 ( "rtl8169_poll (before): intr_mask = %#04x  intr_status = %#04x\n",
+	      intr_mask, intr_status );
+
+	RTL_W16 ( IntrStatus, 0xffff );
+
+	/* hotplug / major error / no more work / shared irq */
+	if ( intr_status == 0xffff )
+		return;
+
+	/* Process transmitted packets */
+	rtl8169_process_tx_packets ( netdev );
+
+	/* Process received packets  */
+	rtl8169_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev	network interface device structure
+ *
+ **/
+static void
+rtl8169_close ( struct net_device *netdev )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "r8169_close\n" );
+
+	rtl8169_hw_reset ( ioaddr );
+
+	rtl8169_free_tx_resources ( tp );
+	rtl8169_free_rx_resources ( tp );
+}
+
+/**
+ * irq - enable or Disable interrupts
+ *
+ * @v netdev    network adapter
+ * @v action    requested interrupt action
+ *
+ **/
+static void
+rtl8169_irq ( struct net_device *netdev, int action )
+{
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+
+	DBGP ( "rtl8169_irq\n" );
+
+	switch ( action ) {
+	case 0 :
+		rtl8169_irq_disable ( tp );
+		break;
+	default :
+		rtl8169_irq_enable ( tp );
+		break;
+	}
+}
+
+static struct net_device_operations rtl8169_operations = {
+	.open           = rtl8169_open,
+	.transmit       = rtl8169_transmit,
+	.poll           = rtl8169_poll,
+	.close          = rtl8169_close,
+	.irq            = rtl8169_irq,
+};
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pci	PCI device
+ * @v id	PCI IDs
+ *
+ * @ret rc	Return status code
+ **/
+static int
+rtl8169_probe ( struct pci_device *pdev )
+{
+	int i, rc;
+	struct net_device *netdev;
+	struct rtl8169_private *tp;
+	void *ioaddr;
+
+	const struct rtl_cfg_info *cfg = rtl_cfg_infos + pdev->id->driver_data;
+
+	DBGP ( "rtl8169_probe\n" );
+
+	DBG ( "id->vendor = %#04x, id->device = %#04x\n",
+	      pdev->id->vendor, pdev->id->device );
+
+	DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event );
+
+	rc = -ENOMEM;
+
+	/* Allocate net device ( also allocates memory for netdev->priv
+	   and makes netdev-priv point to it )
+	 */
+	netdev = alloc_etherdev ( sizeof ( *tp ) );
+
+	if ( ! netdev )
+		goto err_alloc_etherdev;
+
+	/* Associate driver-specific network operations with
+	   generic network device layer
+	 */
+	netdev_init ( netdev, &rtl8169_operations );
+
+	/* Associate this network device with the given PCI device */
+	pci_set_drvdata ( pdev, netdev );
+	netdev->dev = &pdev->dev;
+
+	/* Initialize driver private storage */
+	tp = netdev_priv ( netdev );
+	memset ( tp, 0, ( sizeof ( *tp ) ) );
+
+	tp->pci_dev    = pdev;
+	tp->irqno      = pdev->irq;
+	tp->netdev     = netdev;
+	tp->intr_event = cfg->intr_event;
+	tp->cp_cmd     = PCIMulRW;
+
+	tp->hw_start = cfg->hw_start;
+
+	rc = -EIO;
+
+	adjust_pci_device ( pdev );
+
+	/* ioremap MMIO region */
+	ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE );
+
+	if ( ! ioaddr ) {
+		DBG ( "cannot remap MMIO\n" );
+		rc = -EIO;
+		goto err_ioremap;
+	}
+
+	tp->mmio_addr = ioaddr;
+
+	tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP );
+	if ( tp->pcie_cap ) {
+		DBG (  "PCI Express capability\n" );
+	} else {
+		DBG (  "No PCI Express capability\n" );
+	}
+
+	/* Mask interrupts just in case */
+	rtl8169_irq_mask_and_ack ( ioaddr );
+
+	/* Soft reset NIC */
+	rtl_soft_reset ( netdev );
+
+	/* Identify chip attached to board */
+	rtl8169_get_mac_version ( tp, ioaddr );
+
+	for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) {
+		if ( tp->mac_version == rtl_chip_info[i].mac_version )
+			break;
+	}
+	if ( i == ARRAY_SIZE(rtl_chip_info ) ) {
+		/* Unknown chip: assume array element #0, original RTL-8169 */
+		DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name );
+		i = 0;
+	}
+	tp->chipset = i;
+
+	if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+	    (RTL_R8(PHYstatus) & TBI_Enable)) {
+		tp->set_speed = rtl8169_set_speed_tbi;
+		tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+		tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+		tp->link_ok = rtl8169_tbi_link_ok;
+
+		tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
+	} else {
+		tp->set_speed = rtl8169_set_speed_xmii;
+		tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+		tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+		tp->link_ok = rtl8169_xmii_link_ok;
+	}
+
+	/* Get MAC address */
+	for ( i = 0; i < MAC_ADDR_LEN; i++ )
+		netdev->hw_addr[i] = RTL_R8 ( MAC0 + i );
+
+	DBG ( "%s\n", eth_ntoa ( netdev->hw_addr ) );
+
+	rtl8169_init_phy ( netdev, tp );
+
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register;
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	DBG ( "rtl8169_probe succeeded!\n" );
+
+	/* No errors, return success */
+	return 0;
+
+/* Error return paths */
+err_register:
+err_ioremap:
+	netdev_put ( netdev );
+err_alloc_etherdev:
+	return rc;
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+static void
+rtl8169_remove ( struct pci_device *pdev )
+{
+	struct net_device *netdev = pci_get_drvdata ( pdev );
+	struct rtl8169_private *tp = netdev_priv ( netdev );
+	void *ioaddr = tp->mmio_addr;
+
+	DBGP ( "rtl8169_remove\n" );
+
+	rtl8169_hw_reset ( ioaddr );
+
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id rtl8169_nics[] = {
+	PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129", RTL_CFG_0),
+	PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136", RTL_CFG_2),
+	PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167", RTL_CFG_0),
+	PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_1),
+	PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169", RTL_CFG_0),
+	PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300", RTL_CFG_0),
+	PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107", RTL_CFG_0),
+	PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116", RTL_CFG_0),
+	PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032", RTL_CFG_0),
+	PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_2),
+};
+
+struct pci_driver rtl8169_driver __pci_driver = {
+  .ids = rtl8169_nics,
+  .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ),
+  .probe = rtl8169_probe,
+  .remove = rtl8169_remove,
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.h
new file mode 100644
index 0000000..bcf3df0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/r8169.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2008 Marty Connor <mdc at etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen at realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu at fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef _R8169_H_
+#define _R8169_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe
+	   we need such a file in iPXE?
+**/
+#define  PCI_EXP_DEVCTL	        8	/* Device Control */
+#define  PCI_EXP_DEVCTL_READRQ	0x7000	/* Max_Read_Request_Size */
+#define  PCI_EXP_LNKCTL		16	/* Link Control */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100	/* Enable clkreq */
+#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+
+/** FIXME: update mii.h in src/include/mii.h from Linux sources
+	   so we don't have to include these definitiions.
+**/
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10		10
+#define SPEED_100		100
+#define SPEED_1000		1000
+#define SPEED_2500		2500
+#define SPEED_10000		10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+/* MAC address length */
+#define MAC_ADDR_LEN	6
+
+#define MAX_READ_REQUEST_SHIFT	12
+#define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld	0x3F	/* 0x3F means NO early transmit */
+#define RxPacketMaxSize	0x3FE8	/* 16K - 1 - ETH_HLEN - VLAN - CRC... */
+#define SafeMtu		0x1c20	/* ... actually life sucks beyond ~7k */
+#define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
+
+#define R8169_REGS_SIZE		256
+#define R8169_NAPI_WEIGHT	64
+#define NUM_TX_DESC	8	/* Number of Tx descriptor registers */
+#define NUM_RX_DESC	8	/* Number of Rx descriptor registers */
+#define RX_BUF_SIZE	1536	/* Rx Buffer size */
+#define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
+
+#define TX_RING_ALIGN		256
+#define RX_RING_ALIGN		256
+
+#define RTL8169_TX_TIMEOUT	(6*HZ)
+#define RTL8169_PHY_TIMEOUT	(10*HZ)
+
+#define RTL_EEPROM_SIG		cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK	cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG_ADDR	0x0000
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg)		readb (ioaddr + (reg))
+#define RTL_R16(reg)		readw (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+
+enum mac_version {
+	RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+	RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+	RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+	RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+	RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+	RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+	RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+	RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+	RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+	RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
+	RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+	RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+	RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+	RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+	RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+	RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+	RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+	RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+	RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+	RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+	RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+	RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+	RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+	RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+	RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
+};
+
+#define _R(NAME,MAC,MASK) \
+	{ .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+static const struct {
+	const char *name;
+	u8 mac_version;
+	u32 RxConfigMask;	/* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+	_R("RTL8169",		RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+	_R("RTL8169s",		RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+	_R("RTL8110s",		RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+	_R("RTL8169sb/8110sb",	RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+	_R("RTL8169sc/8110sc",	RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+	_R("RTL8169sc/8110sc",	RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+	_R("RTL8102e",		RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+	_R("RTL8101e",		RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
+	_R("RTL8168b/8111b",	RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
+	_R("RTL8168b/8111b",	RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
+	_R("RTL8101e",		RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
+	_R("RTL8100e",		RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
+	_R("RTL8100e",		RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+	_R("RTL8168b/8111b",	RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+	_R("RTL8101e",		RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+	_R("RTL8168c/8111c",	RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+	_R("RTL8168cp/8111cp",	RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+	_R("RTL8168d/8111d",	RTL_GIGA_MAC_VER_25, 0xff7e1880)  // PCI-E
+};
+#undef _R
+
+enum cfg_version {
+	RTL_CFG_0 = 0x00,
+	RTL_CFG_1,
+	RTL_CFG_2
+};
+
+#if 0
+/** Device Table from Linux Driver **/
+static struct pci_device_id rtl8169_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8129), 0, 0, RTL_CFG_0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8136), 0, 0, RTL_CFG_2 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8167), 0, 0, RTL_CFG_0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8168), 0, 0, RTL_CFG_1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8169), 0, 0, RTL_CFG_0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK,	0x4300), 0, 0, RTL_CFG_0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AT,		0xc107), 0, 0, RTL_CFG_0 },
+	{ PCI_DEVICE(0x16ec,			0x0116), 0, 0, RTL_CFG_0 },
+	{ PCI_VENDOR_ID_LINKSYS,		0x1032,
+		PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+	{ 0x0001,				0x8168,
+		PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
+	{0,},
+};
+#endif
+
+enum rtl_registers {
+	MAC0		= 0,	/* Ethernet hardware address. */
+	MAC4		= 4,
+	MAR0		= 8,	/* Multicast filter. */
+	CounterAddrLow		= 0x10,
+	CounterAddrHigh		= 0x14,
+	TxDescStartAddrLow	= 0x20,
+	TxDescStartAddrHigh	= 0x24,
+	TxHDescStartAddrLow	= 0x28,
+	TxHDescStartAddrHigh	= 0x2c,
+	FLASH		= 0x30,
+	ERSR		= 0x36,
+	ChipCmd		= 0x37,
+	TxPoll		= 0x38,
+	IntrMask	= 0x3c,
+	IntrStatus	= 0x3e,
+	TxConfig	= 0x40,
+	RxConfig	= 0x44,
+	RxMissed	= 0x4c,
+	Cfg9346		= 0x50,
+	Config0		= 0x51,
+	Config1		= 0x52,
+	Config2		= 0x53,
+	Config3		= 0x54,
+	Config4		= 0x55,
+	Config5		= 0x56,
+	MultiIntr	= 0x5c,
+	PHYAR		= 0x60,
+	PHYstatus	= 0x6c,
+	RxMaxSize	= 0xda,
+	CPlusCmd	= 0xe0,
+	IntrMitigate	= 0xe2,
+	RxDescAddrLow	= 0xe4,
+	RxDescAddrHigh	= 0xe8,
+	EarlyTxThres	= 0xec,
+	FuncEvent	= 0xf0,
+	FuncEventMask	= 0xf4,
+	FuncPresetState	= 0xf8,
+	FuncForceEvent	= 0xfc,
+};
+
+enum rtl8110_registers {
+	TBICSR			= 0x64,
+	TBI_ANAR		= 0x68,
+	TBI_LPAR		= 0x6a,
+};
+
+enum rtl8168_8101_registers {
+	CSIDR			= 0x64,
+	CSIAR			= 0x68,
+#define	CSIAR_FLAG			0x80000000
+#define	CSIAR_WRITE_CMD			0x80000000
+#define	CSIAR_BYTE_ENABLE		0x0f
+#define	CSIAR_BYTE_ENABLE_SHIFT		12
+#define	CSIAR_ADDR_MASK			0x0fff
+
+	EPHYAR			= 0x80,
+#define	EPHYAR_FLAG			0x80000000
+#define	EPHYAR_WRITE_CMD		0x80000000
+#define	EPHYAR_REG_MASK			0x1f
+#define	EPHYAR_REG_SHIFT		16
+#define	EPHYAR_DATA_MASK		0xffff
+	DBG_REG			= 0xd1,
+#define	FIX_NAK_1			(1 << 4)
+#define	FIX_NAK_2			(1 << 3)
+};
+
+enum rtl_register_content {
+	/* InterruptStatusBits */
+	SYSErr		= 0x8000,
+	PCSTimeout	= 0x4000,
+	SWInt		= 0x0100,
+	TxDescUnavail	= 0x0080,
+	RxFIFOOver	= 0x0040,
+	LinkChg		= 0x0020,
+	RxOverflow	= 0x0010,
+	TxErr		= 0x0008,
+	TxOK		= 0x0004,
+	RxErr		= 0x0002,
+	RxOK		= 0x0001,
+
+	/* RxStatusDesc */
+	RxFOVF	= (1 << 23),
+	RxRWT	= (1 << 22),
+	RxRES	= (1 << 21),
+	RxRUNT	= (1 << 20),
+	RxCRC	= (1 << 19),
+
+	/* ChipCmdBits */
+	CmdReset	= 0x10,
+	CmdRxEnb	= 0x08,
+	CmdTxEnb	= 0x04,
+	RxBufEmpty	= 0x01,
+
+	/* TXPoll register p.5 */
+	HPQ		= 0x80,		/* Poll cmd on the high prio queue */
+	NPQ		= 0x40,		/* Poll cmd on the low prio queue */
+	FSWInt		= 0x01,		/* Forced software interrupt */
+
+	/* Cfg9346Bits */
+	Cfg9346_Lock	= 0x00,
+	Cfg9346_Unlock	= 0xc0,
+
+	/* rx_mode_bits */
+	AcceptErr	= 0x20,
+	AcceptRunt	= 0x10,
+	AcceptBroadcast	= 0x08,
+	AcceptMulticast	= 0x04,
+	AcceptMyPhys	= 0x02,
+	AcceptAllPhys	= 0x01,
+
+	/* RxConfigBits */
+	RxCfgFIFOShift	= 13,
+	RxCfgDMAShift	=  8,
+
+	/* TxConfigBits */
+	TxInterFrameGapShift = 24,
+	TxDMAShift = 8,	/* DMA burst value (0-7) is shift this many bits */
+
+	/* Config1 register p.24 */
+	LEDS1		= (1 << 7),
+	LEDS0		= (1 << 6),
+	MSIEnable	= (1 << 5),	/* Enable Message Signaled Interrupt */
+	Speed_down	= (1 << 4),
+	MEMMAP		= (1 << 3),
+	IOMAP		= (1 << 2),
+	VPD		= (1 << 1),
+	PMEnable	= (1 << 0),	/* Power Management Enable */
+
+	/* Config2 register p. 25 */
+	PCI_Clock_66MHz = 0x01,
+	PCI_Clock_33MHz = 0x00,
+
+	/* Config3 register p.25 */
+	MagicPacket	= (1 << 5),	/* Wake up when receives a Magic Packet */
+	LinkUp		= (1 << 4),	/* Wake up when the cable connection is re-established */
+	Beacon_en	= (1 << 0),	/* 8168 only. Reserved in the 8168b */
+
+	/* Config5 register p.27 */
+	BWF		= (1 << 6),	/* Accept Broadcast wakeup frame */
+	MWF		= (1 << 5),	/* Accept Multicast wakeup frame */
+	UWF		= (1 << 4),	/* Accept Unicast wakeup frame */
+	LanWake		= (1 << 1),	/* LanWake enable/disable */
+	PMEStatus	= (1 << 0),	/* PME status can be reset by PCI RST# */
+
+	/* TBICSR p.28 */
+	TBIReset	= 0x80000000,
+	TBILoopback	= 0x40000000,
+	TBINwEnable	= 0x20000000,
+	TBINwRestart	= 0x10000000,
+	TBILinkOk	= 0x02000000,
+	TBINwComplete	= 0x01000000,
+
+	/* CPlusCmd p.31 */
+	EnableBist	= (1 << 15),	// 8168 8101
+	Mac_dbgo_oe	= (1 << 14),	// 8168 8101
+	Normal_mode	= (1 << 13),	// unused
+	Force_half_dup	= (1 << 12),	// 8168 8101
+	Force_rxflow_en	= (1 << 11),	// 8168 8101
+	Force_txflow_en	= (1 << 10),	// 8168 8101
+	Cxpl_dbg_sel	= (1 << 9),	// 8168 8101
+	ASF		= (1 << 8),	// 8168 8101
+	PktCntrDisable	= (1 << 7),	// 8168 8101
+	Mac_dbgo_sel	= 0x001c,	// 8168
+	RxVlan		= (1 << 6),
+	RxChkSum	= (1 << 5),
+	PCIDAC		= (1 << 4),
+	PCIMulRW	= (1 << 3),
+	INTT_0		= 0x0000,	// 8168
+	INTT_1		= 0x0001,	// 8168
+	INTT_2		= 0x0002,	// 8168
+	INTT_3		= 0x0003,	// 8168
+
+	/* rtl8169_PHYstatus */
+	TBI_Enable	= 0x80,
+	TxFlowCtrl	= 0x40,
+	RxFlowCtrl	= 0x20,
+	_1000bpsF	= 0x10,
+	_100bps		= 0x08,
+	_10bps		= 0x04,
+	LinkStatus	= 0x02,
+	FullDup		= 0x01,
+
+	/* _TBICSRBit */
+	TBILinkOK	= 0x02000000,
+
+	/* DumpCounterCommand */
+	CounterDump	= 0x8,
+};
+
+enum desc_status_bit {
+	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */
+	RingEnd		= (1 << 30), /* End of descriptor ring */
+	FirstFrag	= (1 << 29), /* First segment of a packet */
+	LastFrag	= (1 << 28), /* Final segment of a packet */
+
+	/* Tx private */
+	LargeSend	= (1 << 27), /* TCP Large Send Offload (TSO) */
+	MSSShift	= 16,        /* MSS value position */
+	MSSMask		= 0xfff,     /* MSS value + LargeSend bit: 12 bits */
+	IPCS		= (1 << 18), /* Calculate IP checksum */
+	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */
+	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */
+	TxVlanTag	= (1 << 17), /* Add VLAN tag */
+
+	/* Rx private */
+	PID1		= (1 << 18), /* Protocol ID bit 1/2 */
+	PID0		= (1 << 17), /* Protocol ID bit 2/2 */
+
+#define RxProtoUDP	(PID1)
+#define RxProtoTCP	(PID0)
+#define RxProtoIP	(PID1 | PID0)
+#define RxProtoMask	RxProtoIP
+
+	IPFail		= (1 << 16), /* IP checksum failed */
+	UDPFail		= (1 << 15), /* UDP/IP checksum failed */
+	TCPFail		= (1 << 14), /* TCP/IP checksum failed */
+	RxVlanTag	= (1 << 16), /* VLAN tag available */
+};
+
+#define RsvdMask	0x3fffc000
+
+struct TxDesc {
+	volatile uint32_t opts1;
+	volatile uint32_t opts2;
+	volatile uint32_t addr_lo;
+	volatile uint32_t addr_hi;
+};
+
+struct RxDesc {
+	volatile uint32_t opts1;
+	volatile uint32_t opts2;
+	volatile uint32_t addr_lo;
+	volatile uint32_t addr_hi;
+};
+
+enum features {
+	RTL_FEATURE_WOL		= (1 << 0),
+	RTL_FEATURE_MSI		= (1 << 1),
+	RTL_FEATURE_GMII	= (1 << 2),
+};
+
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
+
+struct rtl8169_private {
+
+	struct pci_device *pci_dev;
+	struct net_device *netdev;
+	uint8_t *hw_addr;
+	void *mmio_addr;
+	uint32_t irqno;
+
+	int chipset;
+	int mac_version;
+	u16 intr_event;
+
+	struct io_buffer *tx_iobuf[NUM_TX_DESC];
+	struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+	struct TxDesc *tx_base;
+	struct RxDesc *rx_base;
+
+	uint32_t tx_curr;
+	uint32_t rx_curr;
+
+	uint32_t tx_tail;
+
+	uint32_t tx_fill_ctr;
+
+	u16 cp_cmd;
+
+	int phy_auto_nego_reg;
+	int phy_1000_ctrl_reg;
+
+	int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex );
+	void ( *phy_reset_enable ) ( void *ioaddr );
+	void ( *hw_start ) ( struct net_device * );
+	unsigned int ( *phy_reset_pending ) ( void *ioaddr );
+	unsigned int ( *link_ok ) ( void *ioaddr );
+
+	int pcie_cap;
+
+	unsigned features;
+
+};
+
+static const unsigned int rtl8169_rx_config =
+	(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+#endif /* _R8169_H_ */
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl8139.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl8139.c
new file mode 100644
index 0000000..ebe84fb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl8139.c
@@ -0,0 +1,596 @@
+/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
+
+  ported from the linux driver written by Donald Becker
+  by Rainer Bawidamann (Rainer.Bawidamann at informatik.uni-ulm.de) 1999
+
+  This software may be used and distributed according to the terms
+  of the GNU Public License, incorporated herein by reference.
+
+  changes to the original driver:
+  - removed support for interrupts, switching to polling mode (yuck!)
+  - removed support for the 8129 chip (external MII)
+
+*/
+
+FILE_LICENCE ( GPL_ANY );
+
+/*********************************************************************/
+/* Revision History                                                  */
+/*********************************************************************/
+
+/*
+  27 May 2006	mcb30 at users.sourceforge.net (Michael Brown)
+     Rewrote to use the new net driver API, the updated PCI API, and
+     the generic three-wire serial device support for EEPROM access.
+
+  28 Dec 2002	ken_yap at users.sourceforge.net (Ken Yap)
+     Put in virt_to_bus calls to allow Etherboot relocation.
+
+  06 Apr 2001	ken_yap at users.sourceforge.net (Ken Yap)
+     Following email from Hyun-Joon Cha, added a disable routine, otherwise
+     NIC remains live and can crash the kernel later.
+
+  4 Feb 2000	espenlaub at informatik.uni-ulm.de (Klaus Espenlaub)
+     Shuffled things around, removed the leftovers from the 8129 support
+     that was in the Linux driver and added a bit more 8139 definitions.
+     Moved the 8K receive buffer to a fixed, available address outside the
+     0x98000-0x9ffff range.  This is a bit of a hack, but currently the only
+     way to make room for the Etherboot features that need substantial amounts
+     of code like the ANSI console support.  Currently the buffer is just below
+     0x10000, so this even conforms to the tagged boot image specification,
+     which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000.  My
+     interpretation of this "reserved" is that Etherboot may do whatever it
+     likes, as long as its environment is kept intact (like the BIOS
+     variables).  Hopefully fixed rtl_poll() once and for all.  The symptoms
+     were that if Etherboot was left at the boot menu for several minutes, the
+     first eth_poll failed.  Seems like I am the only person who does this.
+     First of all I fixed the debugging code and then set out for a long bug
+     hunting session.  It took me about a week full time work - poking around
+     various places in the driver, reading Don Becker's and Jeff Garzik's Linux
+     driver and even the FreeBSD driver (what a piece of crap!) - and
+     eventually spotted the nasty thing: the transmit routine was acknowledging
+     each and every interrupt pending, including the RxOverrun and RxFIFIOver
+     interrupts.  This confused the RTL8139 thoroughly.  It destroyed the
+     Rx ring contents by dumping the 2K FIFO contents right where we wanted to
+     get the next packet.  Oh well, what fun.
+
+  18 Jan 2000   mdc at etherboot.org (Marty Connor)
+     Drastically simplified error handling.  Basically, if any error
+     in transmission or reception occurs, the card is reset.
+     Also, pointed all transmit descriptors to the same buffer to
+     save buffer space.  This should decrease driver size and avoid
+     corruption because of exceeding 32K during runtime.
+
+  28 Jul 1999   (Matthias Meixner - meixner at rbg.informatik.tu-darmstadt.de)
+     rtl_poll was quite broken: it used the RxOK interrupt flag instead
+     of the RxBufferEmpty flag which often resulted in very bad
+     transmission performace - below 1kBytes/s.
+
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/spi_bit.h>
+#include <ipxe/threewire.h>
+#include <ipxe/nvo.h>
+
+#define TX_RING_SIZE 4
+#define TX_MAX_LEN 8192
+
+struct rtl8139_tx {
+	unsigned int next;
+	struct io_buffer *iobuf[TX_RING_SIZE];
+};
+
+struct rtl8139_rx {
+	void *ring;
+	unsigned int offset;
+};
+
+struct rtl8139_nic {
+	unsigned short ioaddr;
+	struct rtl8139_tx tx;
+	struct rtl8139_rx rx;
+	struct spi_bit_basher spibit;
+	struct spi_device eeprom;
+	struct nvo_block nvo;
+};
+
+/* Tuning Parameters */
+#define TX_FIFO_THRESH	256	/* In bytes, rounded down to 32 byte units. */
+#define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4	/* Calculate as 16<<val. */
+#define TX_IPG		3	/* This is the only valid value */
+#define RX_BUF_LEN_IDX	0	/* 0, 1, 2 is allowed - 8,16,32K rx buffer */
+#define RX_BUF_LEN ( (8192 << RX_BUF_LEN_IDX) )
+#define RX_BUF_PAD 4
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+	MAC0=0,			/* Ethernet hardware address. */
+	MAR0=8,			/* Multicast filter. */
+	TxStatus0=0x10,		/* Transmit status (four 32bit registers). */
+	TxAddr0=0x20,		/* Tx descriptors (also four 32bit). */
+	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+	IntrMask=0x3C, IntrStatus=0x3E,
+	TxConfig=0x40, RxConfig=0x44,
+	Timer=0x48,		/* general-purpose counter. */
+	RxMissed=0x4C,		/* 24 bits valid, write clears. */
+	Cfg9346=0x50, Config0=0x51, Config1=0x52,
+	TimerIntrReg=0x54,	/* intr if gp counter reaches this value */
+	MediaStatus=0x58,
+	Config3=0x59,
+	MultiIntr=0x5C,
+	RevisionID=0x5E,	/* revision of the RTL8139 chip */
+	TxSummary=0x60,
+	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
+	NWayExpansion=0x6A,
+	DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
+	NWayTestReg=0x70,
+	RxCnt=0x72,		/* packet received counter */
+	CSCR=0x74,		/* chip status and configuration register */
+	PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80,	/* undocumented */
+	/* from 0x84 onwards are a number of power management/wakeup frame
+	 * definitions we will probably never need to know about.  */
+};
+
+enum RxEarlyStatusBits {
+	ERGood=0x08, ERBad=0x04, EROVW=0x02, EROK=0x01
+};
+
+enum ChipCmdBits {
+	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+enum IntrMaskBits {
+	SERR=0x8000, TimeOut=0x4000, LenChg=0x2000,
+	FOVW=0x40, PUN_LinkChg=0x20, RXOVW=0x10,
+	TER=0x08, TOK=0x04, RER=0x02, ROK=0x01
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
+	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+	TxOutOfWindow=0x20000000, TxAborted=0x40000000,
+	TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+	RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+enum MediaStatusBits {
+	MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
+	MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
+};
+
+enum MIIBMCRBits {
+	BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
+	BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
+};
+
+enum CSCRBits {
+	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+	CSCR_LinkDownCmd=0x0f3c0,
+};
+
+enum RxConfigBits {
+	RxCfgWrap=0x80,
+	Eeprom9356=0x40,
+	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+
+enum Config1Bits {
+	VPDEnable=0x02,
+};
+
+/*  EEPROM access */
+#define EE_M1		0x80	/* Mode select bit 1 */
+#define EE_M0		0x40	/* Mode select bit 0 */
+#define EE_CS		0x08	/* EEPROM chip select */
+#define EE_SK		0x04	/* EEPROM shift clock */
+#define EE_DI		0x02	/* Data in */
+#define EE_DO		0x01	/* Data out */
+
+/* Offsets within EEPROM (these are word offsets) */
+#define EE_MAC 7
+
+static const uint8_t rtl_ee_bits[] = {
+	[SPI_BIT_SCLK]	= EE_SK,
+	[SPI_BIT_MOSI]	= EE_DI,
+	[SPI_BIT_MISO]	= EE_DO,
+	[SPI_BIT_SS(0)]	= ( EE_CS | EE_M1 ),
+};
+
+static int rtl_spi_read_bit ( struct bit_basher *basher,
+			      unsigned int bit_id ) {
+	struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
+						 spibit.basher );
+	uint8_t mask = rtl_ee_bits[bit_id];
+	uint8_t eereg;
+
+	eereg = inb ( rtl->ioaddr + Cfg9346 );
+	return ( eereg & mask );
+}
+
+static void rtl_spi_write_bit ( struct bit_basher *basher,
+				unsigned int bit_id, unsigned long data ) {
+	struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
+						 spibit.basher );
+	uint8_t mask = rtl_ee_bits[bit_id];
+	uint8_t eereg;
+
+	eereg = inb ( rtl->ioaddr + Cfg9346 );
+	eereg &= ~mask;
+	eereg |= ( data & mask );
+	outb ( eereg, rtl->ioaddr + Cfg9346 );
+}
+
+static struct bit_basher_operations rtl_basher_ops = {
+	.read = rtl_spi_read_bit,
+	.write = rtl_spi_write_bit,
+};
+
+/**
+ * Set up for EEPROM access
+ *
+ * @v netdev		Net device
+ */
+static void rtl_init_eeprom ( struct net_device *netdev ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+	int ee9356;
+	int vpd;
+
+	/* Initialise three-wire bus */
+	rtl->spibit.basher.op = &rtl_basher_ops;
+	rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
+	init_spi_bit_basher ( &rtl->spibit );
+
+	/* Detect EEPROM type and initialise three-wire device */
+	ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 );
+	if ( ee9356 ) {
+		DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C56\n", rtl );
+		init_at93c56 ( &rtl->eeprom, 16 );
+	} else {
+		DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C46\n", rtl );
+		init_at93c46 ( &rtl->eeprom, 16 );
+	}
+	rtl->eeprom.bus = &rtl->spibit.bus;
+
+	/* Initialise space for non-volatile options, if available
+	 *
+	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
+	 * block is marked as VPD in the rtl8139 datasheets, so we use
+	 * it only if we detect that the card is not supporting VPD.
+	 */
+	vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable );
+	if ( vpd ) {
+		DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
+		       "for options\n", rtl );
+	} else {
+		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL,
+			   &netdev->refcnt );
+	}
+}
+
+/**
+ * Reset NIC
+ *
+ * @v netdev		Net device
+ *
+ * Issues a hardware reset and waits for the reset to complete.
+ */
+static void rtl_reset ( struct net_device *netdev ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+
+	/* Reset chip */
+	outb ( CmdReset, rtl->ioaddr + ChipCmd );
+	mdelay ( 10 );
+	memset ( &rtl->tx, 0, sizeof ( rtl->tx ) );
+	rtl->rx.offset = 0;
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Net device
+ * @ret rc		Return status code
+ */
+static int rtl_open ( struct net_device *netdev ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+	int i;
+
+	/* Program the MAC address */
+	for ( i = 0 ; i < ETH_ALEN ; i++ )
+		outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i );
+
+	/* Set up RX ring */
+	rtl->rx.ring = malloc ( RX_BUF_LEN + RX_BUF_PAD );
+	if ( ! rtl->rx.ring )
+		return -ENOMEM;
+	outl ( virt_to_bus ( rtl->rx.ring ), rtl->ioaddr + RxBuf );
+	DBGC ( rtl, "rtl8139 %p RX ring at %lx\n",
+	       rtl, virt_to_bus ( rtl->rx.ring ) );
+
+	/* Enable TX and RX */
+	outb ( ( CmdRxEnb | CmdTxEnb ), rtl->ioaddr + ChipCmd );
+	outl ( ( ( RX_FIFO_THRESH << 13 ) | ( RX_BUF_LEN_IDX << 11 ) |
+		 ( RX_DMA_BURST << 8 ) | AcceptBroadcast | AcceptMulticast |
+		 AcceptMyPhys | AcceptAllPhys ), rtl->ioaddr + RxConfig );
+	outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 0 );
+	outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 4 );
+	outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ),
+	       rtl->ioaddr + TxConfig );
+
+	return 0;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Net device
+ */
+static void rtl_close ( struct net_device *netdev ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+
+	/* Reset the hardware to disable everything in one go */
+	rtl_reset ( netdev );
+
+	/* Free RX ring */
+	free ( rtl->rx.ring );
+	rtl->rx.ring = NULL;
+}
+
+/** 
+ * Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int rtl_transmit ( struct net_device *netdev,
+			  struct io_buffer *iobuf ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+
+	/* Check for space in TX ring */
+	if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) {
+		DBGC ( rtl, "rtl8139 %p TX overflow\n", rtl );
+		return -ENOBUFS;
+	}
+
+	/* Check for oversized packets */
+	if ( iob_len ( iobuf ) >= TX_MAX_LEN ) {
+		DBGC ( rtl, "rtl8139 %p TX too large (%zd bytes)\n",
+		       rtl, iob_len ( iobuf ) );
+		return -ERANGE;
+	}
+
+	/* Pad and align packet */
+	iob_pad ( iobuf, ETH_ZLEN );
+
+	/* Add to TX ring */
+	DBGC2 ( rtl, "rtl8139 %p TX id %d at %lx+%zx\n", rtl, rtl->tx.next,
+		virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+	rtl->tx.iobuf[rtl->tx.next] = iobuf;
+	outl ( virt_to_bus ( iobuf->data ),
+	       rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next );
+	outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ),
+	       rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next );
+	rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE;
+
+	return 0;
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev	Network device
+ */
+static void rtl_poll ( struct net_device *netdev ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+	unsigned int status;
+	unsigned int tsad;
+	unsigned int rx_status;
+	unsigned int rx_len;
+	struct io_buffer *rx_iob;
+	int wrapped_len;
+	int i;
+
+	/* Acknowledge interrupts */
+	status = inw ( rtl->ioaddr + IntrStatus );
+	if ( ! status )
+		return;
+	outw ( status, rtl->ioaddr + IntrStatus );
+
+	/* Handle TX completions */
+	tsad = inw ( rtl->ioaddr + TxSummary );
+	for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
+		if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) {
+			DBGC2 ( rtl, "rtl8139 %p TX id %d complete\n",
+				rtl, i );
+			netdev_tx_complete ( netdev, rtl->tx.iobuf[i] );
+			rtl->tx.iobuf[i] = NULL;
+		}
+	}
+
+	/* Handle received packets */
+	while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) {
+		rx_status = * ( ( uint16_t * )
+				( rtl->rx.ring + rtl->rx.offset ) );
+		rx_len = * ( ( uint16_t * )
+			     ( rtl->rx.ring + rtl->rx.offset + 2 ) );
+		if ( rx_status & RxOK ) {
+			DBGC2 ( rtl, "rtl8139 %p RX packet at offset "
+				"%x+%x\n", rtl, rtl->rx.offset, rx_len );
+
+			rx_iob = alloc_iob ( rx_len );
+			if ( ! rx_iob ) {
+				netdev_rx_err ( netdev, NULL, -ENOMEM );
+				/* Leave packet for next call to poll() */
+				break;
+			}
+
+			wrapped_len = ( ( rtl->rx.offset + 4 + rx_len )
+					- RX_BUF_LEN );
+			if ( wrapped_len < 0 )
+				wrapped_len = 0;
+
+			memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ),
+				 rtl->rx.ring + rtl->rx.offset + 4,
+				 rx_len - wrapped_len );
+			memcpy ( iob_put ( rx_iob, wrapped_len ),
+				 rtl->rx.ring, wrapped_len );
+			iob_unput ( rx_iob, 4 ); /* Strip CRC */
+
+			netdev_rx ( netdev, rx_iob );
+		} else {
+			DBGC ( rtl, "rtl8139 %p RX bad packet (status %#04x "
+			       "len %d)\n", rtl, rx_status, rx_len );
+			netdev_rx_err ( netdev, NULL, -EINVAL );
+		}
+		rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 )
+				   % RX_BUF_LEN );
+		outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr );
+	}
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev	Network device
+ * @v enable	Interrupts should be enabled
+ */
+static void rtl_irq ( struct net_device *netdev, int enable ) {
+	struct rtl8139_nic *rtl = netdev->priv;
+
+	DBGC ( rtl, "rtl8139 %p interrupts %s\n",
+	       rtl, ( enable ? "enabled" : "disabled" ) );
+	outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ),
+	       rtl->ioaddr + IntrMask );
+}
+
+/** RTL8139 net device operations */
+static struct net_device_operations rtl_operations = {
+	.open		= rtl_open,
+	.close		= rtl_close,
+	.transmit	= rtl_transmit,
+	.poll		= rtl_poll,
+	.irq		= rtl_irq,
+};
+
+/**
+ * Probe PCI device
+ *
+ * @v pci	PCI device
+ * @v id	PCI ID
+ * @ret rc	Return status code
+ */
+static int rtl_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct rtl8139_nic *rtl;
+	int rc;
+
+	/* Allocate net device */
+	netdev = alloc_etherdev ( sizeof ( *rtl ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &rtl_operations );
+	rtl = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( rtl, 0, sizeof ( *rtl ) );
+	rtl->ioaddr = pci->ioaddr;
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Reset the NIC, set up EEPROM access and read MAC address */
+	rtl_reset ( netdev );
+	rtl_init_eeprom ( netdev );
+	nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->hw_addr, ETH_ALEN );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	/* Register non-volatile storage */
+	if ( rtl->nvo.nvs ) {
+		if ( ( rc = register_nvo ( &rtl->nvo,
+					   netdev_settings ( netdev ) ) ) != 0)
+			goto err_register_nvo;
+	}
+
+	return 0;
+
+ err_register_nvo:
+	unregister_netdev ( netdev );
+ err_register_netdev:
+	rtl_reset ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci	PCI device
+ */
+static void rtl_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct rtl8139_nic *rtl = netdev->priv;
+
+	if ( rtl->nvo.nvs )
+		unregister_nvo ( &rtl->nvo );
+	unregister_netdev ( netdev );
+	rtl_reset ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id rtl8139_nics[] = {
+PCI_ROM(0x10ec, 0x8129, "rtl8129",       "Realtek 8129", 0),
+PCI_ROM(0x10ec, 0x8139, "rtl8139",       "Realtek 8139", 0),
+PCI_ROM(0x10ec, 0x8138, "rtl8139b",      "Realtek 8139B", 0),
+PCI_ROM(0x1186, 0x1300, "dfe538",        "DFE530TX+/DFE538TX", 0),
+PCI_ROM(0x1113, 0x1211, "smc1211-1",     "SMC EZ10/100", 0),
+PCI_ROM(0x1112, 0x1211, "smc1211",       "SMC EZ10/100", 0),
+PCI_ROM(0x1500, 0x1360, "delta8139",     "Delta Electronics 8139", 0),
+PCI_ROM(0x4033, 0x1360, "addtron8139",   "Addtron Technology 8139", 0),
+PCI_ROM(0x1186, 0x1340, "dfe690txd",     "D-Link DFE690TXD", 0),
+PCI_ROM(0x13d1, 0xab06, "fe2000vx",      "AboCom FE2000VX", 0),
+PCI_ROM(0x1259, 0xa117, "allied8139",    "Allied Telesyn 8139", 0),
+PCI_ROM(0x14ea, 0xab06, "fnw3603tx",     "Planex FNW-3603-TX", 0),
+PCI_ROM(0x14ea, 0xab07, "fnw3800tx",     "Planex FNW-3800-TX", 0),
+PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139", 0),
+};
+
+struct pci_driver rtl8139_driver __pci_driver = {
+	.ids = rtl8139_nics,
+	.id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ),
+	.probe = rtl_probe,
+	.remove = rtl_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
new file mode 100644
index 0000000..8851d1b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
@@ -0,0 +1,17 @@
+/* Realtek 8180 card: rtl818x driver + rtl8180 RF modules */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/pci.h>
+
+REQUIRE_OBJECT(rtl818x);
+REQUIRE_OBJECT(rtl8180_grf5101);
+REQUIRE_OBJECT(rtl8180_max2820);
+REQUIRE_OBJECT(rtl8180_sa2400);
+
+static struct pci_device_id rtl8180_nics[] __unused = {
+	PCI_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0),
+	PCI_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0),
+	PCI_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0),
+	PCI_ROM(0x1186, 0x3300, "dwl510",  "D-Link DWL-510", 0),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_grf5101.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_grf5101.c
new file mode 100644
index 0000000..2b99503
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_grf5101.c
@@ -0,0 +1,186 @@
+/*
+ * Radio tuning for GCT GRF5101 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified slightly for iPXE, June 2009 by Joshua Oreman.
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <ipxe/pci.h>
+#include <ipxe/net80211.h>
+
+#include "rtl818x.h"
+
+FILE_LICENCE(GPL2_ONLY);
+
+#define GRF5101_ANTENNA 0xA3
+
+static const int grf5101_encode[] = {
+	0x0, 0x8, 0x4, 0xC,
+	0x2, 0xA, 0x6, 0xE,
+	0x1, 0x9, 0x5, 0xD,
+	0x3, 0xB, 0x7, 0xF
+};
+
+static void write_grf5101(struct net80211_device *dev, u8 addr, u32 data)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u32 phy_config;
+
+	phy_config =  grf5101_encode[(data >> 8) & 0xF];
+	phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4;
+	phy_config |= grf5101_encode[data & 0xF] << 8;
+	phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12;
+	phy_config |= (addr & 1) << 16;
+	phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24;
+
+	/* MAC will bang bits to the chip */
+	phy_config |= 0x90000000;
+
+	/* This was originally a 32-bit write to a typecast
+	   RFPinsOutput, but gcc complained about aliasing rules. -JBO */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, phy_config & 0xffff);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, phy_config >> 16);
+
+	mdelay(3);
+}
+
+static void grf5101_write_phy_antenna(struct net80211_device *dev, short chan)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 ant = GRF5101_ANTENNA;
+
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl818x_write_phy(dev, 0x10, ant);
+}
+
+static void grf5101_rf_set_channel(struct net80211_device *dev,
+				   struct net80211_channel *channelp)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int channel = channelp->channel_nr;
+	u32 txpw = priv->txpower[channel - 1] & 0xFF;
+	u32 chan = channel - 1;
+
+	/* set TX power */
+	write_grf5101(dev, 0x15, 0x0);
+	write_grf5101(dev, 0x06, txpw);
+	write_grf5101(dev, 0x15, 0x10);
+	write_grf5101(dev, 0x15, 0x0);
+
+	/* set frequency */
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x0B, chan);
+	write_grf5101(dev, 0x07, 0x1000);
+
+	grf5101_write_phy_antenna(dev, channel);
+}
+
+static void grf5101_rf_stop(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u32 anaparam;
+
+	anaparam = priv->anaparam;
+	anaparam &= 0x000fffff;
+	anaparam |= 0x3f900000;
+	rtl818x_set_anaparam(priv, anaparam);
+
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x1f, 0x45);
+	write_grf5101(dev, 0x1f, 0x5);
+	write_grf5101(dev, 0x00, 0x8e4);
+}
+
+static void grf5101_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+
+	rtl818x_set_anaparam(priv, priv->anaparam);
+
+	write_grf5101(dev, 0x1f, 0x0);
+	write_grf5101(dev, 0x1f, 0x0);
+	write_grf5101(dev, 0x1f, 0x40);
+	write_grf5101(dev, 0x1f, 0x60);
+	write_grf5101(dev, 0x1f, 0x61);
+	write_grf5101(dev, 0x1f, 0x61);
+	write_grf5101(dev, 0x00, 0xae4);
+	write_grf5101(dev, 0x1f, 0x1);
+	write_grf5101(dev, 0x1f, 0x41);
+	write_grf5101(dev, 0x1f, 0x61);
+
+	write_grf5101(dev, 0x01, 0x1a23);
+	write_grf5101(dev, 0x02, 0x4971);
+	write_grf5101(dev, 0x03, 0x41de);
+	write_grf5101(dev, 0x04, 0x2d80);
+	write_grf5101(dev, 0x05, 0x68ff);	/* 0x61ff original value */
+	write_grf5101(dev, 0x06, 0x0);
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x08, 0x7533);
+	write_grf5101(dev, 0x09, 0xc401);
+	write_grf5101(dev, 0x0a, 0x0);
+	write_grf5101(dev, 0x0c, 0x1c7);
+	write_grf5101(dev, 0x0d, 0x29d3);
+	write_grf5101(dev, 0x0e, 0x2e8);
+	write_grf5101(dev, 0x10, 0x192);
+	write_grf5101(dev, 0x11, 0x248);
+	write_grf5101(dev, 0x12, 0x0);
+	write_grf5101(dev, 0x13, 0x20c4);
+	write_grf5101(dev, 0x14, 0xf4fc);
+	write_grf5101(dev, 0x15, 0x0);
+	write_grf5101(dev, 0x16, 0x1500);
+
+	write_grf5101(dev, 0x07, 0x1000);
+
+	/* baseband configuration */
+	rtl818x_write_phy(dev, 0, 0xa8);
+	rtl818x_write_phy(dev, 3, 0x0);
+	rtl818x_write_phy(dev, 4, 0xc0);
+	rtl818x_write_phy(dev, 5, 0x90);
+	rtl818x_write_phy(dev, 6, 0x1e);
+	rtl818x_write_phy(dev, 7, 0x64);
+
+	grf5101_write_phy_antenna(dev, 1);
+
+	rtl818x_write_phy(dev, 0x11, 0x88);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl818x_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */
+	else
+		rtl818x_write_phy(dev, 0x12, 0x40); /* disable ant diversity */
+
+	rtl818x_write_phy(dev, 0x13, 0x90 | priv->csthreshold);
+
+	rtl818x_write_phy(dev, 0x19, 0x0);
+	rtl818x_write_phy(dev, 0x1a, 0xa0);
+	rtl818x_write_phy(dev, 0x1b, 0x44);
+}
+
+struct rtl818x_rf_ops grf5101_rf_ops __rtl818x_rf_driver = {
+	.name		= "GCT GRF5101",
+	.id             = 5,
+	.init		= grf5101_rf_init,
+	.stop		= grf5101_rf_stop,
+	.set_chan	= grf5101_rf_set_channel
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_max2820.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_max2820.c
new file mode 100644
index 0000000..ab380fc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_max2820.c
@@ -0,0 +1,158 @@
+/*
+ * Radio tuning for Maxim max2820 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified slightly for iPXE, June 2009 by Joshua Oreman.
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <ipxe/pci.h>
+#include <ipxe/net80211.h>
+
+#include "rtl818x.h"
+
+FILE_LICENCE(GPL2_ONLY);
+
+#define MAXIM_ANTENNA 0xb3
+
+static const u32 max2820_chan[] = {
+	12, /* CH 1 */
+	17,
+	22,
+	27,
+	32,
+	37,
+	42,
+	47,
+	52,
+	57,
+	62,
+	67,
+	72,
+	84, /* CH 14 */
+};
+
+static void write_max2820(struct net80211_device *dev, u8 addr, u32 data)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u32 phy_config;
+
+	phy_config = 0x90 + (data & 0xf);
+	phy_config <<= 16;
+	phy_config += addr;
+	phy_config <<= 8;
+	phy_config += (data >> 4) & 0xff;
+
+	/* This was originally a 32-bit write to a typecast
+	   RFPinsOutput, but gcc complained about aliasing rules. -JBO */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, phy_config & 0xffff);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, phy_config >> 16);
+
+	mdelay(1);
+}
+
+static void max2820_write_phy_antenna(struct net80211_device *dev, short chan)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 ant;
+
+	ant = MAXIM_ANTENNA;
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl818x_write_phy(dev, 0x10, ant);
+}
+
+static void max2820_rf_set_channel(struct net80211_device *dev,
+				   struct net80211_channel *channelp)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int channel = channelp->channel_nr;
+	unsigned int chan_idx = channel - 1;
+	u32 txpw = priv->txpower[chan_idx] & 0xFF;
+	u32 chan = max2820_chan[chan_idx];
+
+	/* While philips SA2400 drive the PA bias from
+	 * sa2400, for MAXIM we do this directly from BB */
+	rtl818x_write_phy(dev, 3, txpw);
+
+	max2820_write_phy_antenna(dev, channel);
+	write_max2820(dev, 3, chan);
+}
+
+static void max2820_rf_stop(struct net80211_device *dev)
+{
+	rtl818x_write_phy(dev, 3, 0x8);
+	write_max2820(dev, 1, 0);
+}
+
+
+static void max2820_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+
+	/* MAXIM from netbsd driver */
+	write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */
+	write_max2820(dev, 1, 0x01e); /* enable register */
+	write_max2820(dev, 2, 0x001); /* synt register */
+
+	max2820_rf_set_channel(dev, NULL);
+
+	write_max2820(dev, 4, 0x313); /* rx register */
+
+	/* PA is driven directly by the BB, we keep the MAXIM bias
+	 * at the highest value in case that setting it to lower
+	 * values may introduce some further attenuation somewhere..
+	 */
+	write_max2820(dev, 5, 0x00f);
+
+	/* baseband configuration */
+	rtl818x_write_phy(dev, 0, 0x88); /* sys1       */
+	rtl818x_write_phy(dev, 3, 0x08); /* txagc      */
+	rtl818x_write_phy(dev, 4, 0xf8); /* lnadet     */
+	rtl818x_write_phy(dev, 5, 0x90); /* ifagcinit  */
+	rtl818x_write_phy(dev, 6, 0x1a); /* ifagclimit */
+	rtl818x_write_phy(dev, 7, 0x64); /* ifagcdet   */
+
+	max2820_write_phy_antenna(dev, 1);
+
+	rtl818x_write_phy(dev, 0x11, 0x88); /* trl */
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl818x_write_phy(dev, 0x12, 0xc7);
+	else
+		rtl818x_write_phy(dev, 0x12, 0x47);
+
+	rtl818x_write_phy(dev, 0x13, 0x9b);
+
+	rtl818x_write_phy(dev, 0x19, 0x0);  /* CHESTLIM */
+	rtl818x_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM  */
+
+	max2820_rf_set_channel(dev, NULL);
+}
+
+struct rtl818x_rf_ops max2820_rf_ops __rtl818x_rf_driver = {
+	.name		= "Maxim max2820",
+	.id		= 4,
+	.init		= max2820_rf_init,
+	.stop		= max2820_rf_stop,
+	.set_chan	= max2820_rf_set_channel
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_sa2400.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_sa2400.c
new file mode 100644
index 0000000..9bd62be
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8180_sa2400.c
@@ -0,0 +1,217 @@
+/*
+ * Radio tuning for Philips SA2400 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified slightly for iPXE, June 2009 by Joshua Oreman.
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <ipxe/pci.h>
+#include <ipxe/net80211.h>
+
+#include "rtl818x.h"
+
+FILE_LICENCE(GPL2_ONLY);
+
+#define SA2400_ANTENNA 0x91
+#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8
+#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28
+#define SA2400_ANAPARAM_PWR0_ON 0x3
+
+/* RX sensitivity in dbm */
+#define SA2400_MAX_SENS 85
+
+#define SA2400_REG4_FIRDAC_SHIFT 7
+
+static const u32 sa2400_chan[] = {
+	0x00096c, /* ch1 */
+	0x080970,
+	0x100974,
+	0x180978,
+	0x000980,
+	0x080984,
+	0x100988,
+	0x18098c,
+	0x000994,
+	0x080998,
+	0x10099c,
+	0x1809a0,
+	0x0009a8,
+	0x0009b4, /* ch 14 */
+};
+
+static void write_sa2400(struct net80211_device *dev, u8 addr, u32 data)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u32 phy_config;
+
+	/* MAC will bang bits to the sa2400. sw 3-wire is NOT used */
+	phy_config = 0xb0000000;
+
+	phy_config |= ((u32)(addr & 0xf)) << 24;
+	phy_config |= data & 0xffffff;
+
+	/* This was originally a 32-bit write to a typecast
+	   RFPinsOutput, but gcc complained about aliasing rules. -JBO */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, phy_config & 0xffff);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, phy_config >> 16);
+
+	mdelay(3);
+}
+
+static void sa2400_write_phy_antenna(struct net80211_device *dev, short chan)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 ant = SA2400_ANTENNA;
+
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl818x_write_phy(dev, 0x10, ant);
+
+}
+
+static void sa2400_rf_set_channel(struct net80211_device *dev,
+				  struct net80211_channel *channelp)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int channel = channelp->channel_nr;
+	u32 txpw = priv->txpower[channel - 1] & 0xFF;
+	u32 chan = sa2400_chan[channel - 1];
+
+	write_sa2400(dev, 7, txpw);
+
+	sa2400_write_phy_antenna(dev, channel);
+
+	write_sa2400(dev, 0, chan);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+}
+
+static void sa2400_rf_stop(struct net80211_device *dev)
+{
+	write_sa2400(dev, 4, 0);
+}
+
+static void sa2400_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u32 anaparam, txconf;
+	u8 firdac;
+	int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY;
+
+	anaparam = priv->anaparam;
+	anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT);
+	anaparam &= ~ANAPARAM_PWR1_MASK;
+	anaparam &= ~ANAPARAM_PWR0_MASK;
+
+	if (analogphy) {
+		anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT;
+		firdac = 0;
+	} else {
+		anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT);
+		anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT);
+		firdac = 1 << SA2400_REG4_FIRDAC_SHIFT;
+	}
+
+	rtl818x_set_anaparam(priv, anaparam);
+
+	write_sa2400(dev, 0, sa2400_chan[0]);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+	write_sa2400(dev, 4, 0x19340 | firdac);
+	write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15);
+	write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */
+
+	if (!analogphy)
+		write_sa2400(dev, 4, 0x1938c); /*???*/
+
+	write_sa2400(dev, 4, 0x19340 | firdac);
+
+	write_sa2400(dev, 0, sa2400_chan[0]);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+	write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */
+
+	/* new from rtl8180 embedded driver (rtl8181 project) */
+	write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */
+	write_sa2400(dev, 8, 0); /* VCO */
+
+	if (analogphy) {
+		rtl818x_set_anaparam(priv, anaparam |
+				     (1 << ANAPARAM_TXDACOFF_SHIFT));
+
+		txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+		rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+			txconf | RTL818X_TX_CONF_LOOPBACK_CONT);
+
+		write_sa2400(dev, 4, 0x19341); /* calibrates DC */
+
+		/* a 5us delay is required here,
+		 * we rely on the 3ms delay introduced in write_sa2400 */
+
+		write_sa2400(dev, 4, 0x19345);
+
+		/* a 20us delay is required here,
+		 * we rely on the 3ms delay introduced in write_sa2400 */
+
+		rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf);
+
+		rtl818x_set_anaparam(priv, anaparam);
+	}
+	/* end new code */
+
+	write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */
+
+	/* baseband configuration */
+	rtl818x_write_phy(dev, 0, 0x98);
+	rtl818x_write_phy(dev, 3, 0x38);
+	rtl818x_write_phy(dev, 4, 0xe0);
+	rtl818x_write_phy(dev, 5, 0x90);
+	rtl818x_write_phy(dev, 6, 0x1a);
+	rtl818x_write_phy(dev, 7, 0x64);
+
+	sa2400_write_phy_antenna(dev, 1);
+
+	rtl818x_write_phy(dev, 0x11, 0x80);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl818x_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */
+	else
+		rtl818x_write_phy(dev, 0x12, 0x47); /* disable ant diversity */
+
+	rtl818x_write_phy(dev, 0x13, 0x90 | priv->csthreshold);
+
+	rtl818x_write_phy(dev, 0x19, 0x0);
+	rtl818x_write_phy(dev, 0x1a, 0xa0);
+}
+
+struct rtl818x_rf_ops sa2400_rf_ops __rtl818x_rf_driver = {
+	.name		= "Philips SA2400",
+	.id		= 3,
+	.init		= sa2400_rf_init,
+	.stop		= sa2400_rf_stop,
+	.set_chan	= sa2400_rf_set_channel
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
new file mode 100644
index 0000000..fd27e5c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
@@ -0,0 +1,14 @@
+/* Realtek 8185 card: rtl818x driver + rtl8185_rtl8225 RF module */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/pci.h>
+
+REQUIRE_OBJECT(rtl818x);
+REQUIRE_OBJECT(rtl8185_rtl8225);
+
+static struct pci_device_id rtl8185_nics[] __unused = {
+	PCI_ROM(0x10ec, 0x8185, "rtl8185", "Realtek 8185", 0),
+	PCI_ROM(0x1799, 0x700f, "f5d7000", "Belkin F5D7000", 0),
+	PCI_ROM(0x1799, 0x701f, "f5d7010", "Belkin F5D7010", 0),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c
new file mode 100644
index 0000000..50cc84a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c
@@ -0,0 +1,804 @@
+/*
+ * Radio tuning for RTL8225 on RTL8185
+ *
+ * Copyright 2007 Michael Wu <flamingice at sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified slightly for iPXE, June 2009 by Joshua Oreman
+ *
+ * Based on the r8180 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl at tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <ipxe/pci.h>
+#include <ipxe/net80211.h>
+
+#include "rtl818x.h"
+
+FILE_LICENCE(GPL2_ONLY);
+
+#define RTL8225_ANAPARAM_ON	0xa0000b59
+#define RTL8225_ANAPARAM2_ON	0x860dec11
+#define RTL8225_ANAPARAM_OFF	0xa00beb59
+#define RTL8225_ANAPARAM2_OFF	0x840dec11
+
+#define min(a,b) (((a)<(b))?(a):(b))
+#define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof((a)[0]))
+
+static inline void rtl8225_write_phy_ofdm(struct net80211_device *dev,
+					  u8 addr, u8 data)
+{
+	rtl818x_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225_write_phy_cck(struct net80211_device *dev,
+					 u8 addr, u8 data)
+{
+	rtl818x_write_phy(dev, addr, data | 0x10000);
+}
+
+static void rtl8225_write(struct net80211_device *dev, u8 addr, u16 data)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u16 reg80, reg84, reg82;
+	u32 bangdata;
+	int i;
+
+	bangdata = (data << 4) | (addr & 0xf);
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
+
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	for (i = 15; i >= 0; i--) {
+		u16 reg = reg80 | !!(bangdata & (1 << i));
+
+		if (i & 1)
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+
+		if (!(i & 1))
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+}
+
+static u16 rtl8225_read(struct net80211_device *dev, u8 addr)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u16 reg80, reg82, reg84, out;
+	int i;
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400;
+
+	reg80 &= ~0xF;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(4);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(5);
+
+	for (i = 4; i >= 0; i--) {
+		u16 reg = reg80 | ((addr >> i) & 1);
+
+		if (!(i & 1)) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+			udelay(1);
+		}
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+
+		if (i & 1) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+			udelay(1);
+		}
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 1));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+
+	out = 0;
+	for (i = 11; i >= 0; i--) {
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(1);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+
+		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
+			out |= 1 << i;
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
+
+	return out;
+}
+
+static const u16 rtl8225bcd_rxgain[] = {
+	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static const u8 rtl8225_agc[] = {
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
+	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
+	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
+	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
+	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
+	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
+	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
+	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
+	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const u8 rtl8225_gain[] = {
+	0x23, 0x88, 0x7c, 0xa5, /* -82dbm */
+	0x23, 0x88, 0x7c, 0xb5, /* -82dbm */
+	0x23, 0x88, 0x7c, 0xc5, /* -82dbm */
+	0x33, 0x80, 0x79, 0xc5, /* -78dbm */
+	0x43, 0x78, 0x76, 0xc5, /* -74dbm */
+	0x53, 0x60, 0x73, 0xc5, /* -70dbm */
+	0x63, 0x58, 0x70, 0xc5, /* -66dbm */
+};
+
+static const u8 rtl8225_threshold[] = {
+	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
+};
+
+static const u8 rtl8225_tx_gain_cck_ofdm[] = {
+	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225_tx_power_cck[] = {
+	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225_tx_power_cck_ch14[] = {
+	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225_tx_power_ofdm[] = {
+	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225_chan[] = {
+	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
+	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
+};
+
+static void rtl8225_rf_set_tx_power(struct net80211_device *dev, int channel)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	u32 reg;
+	int i;
+
+	cck_power = priv->txpower[channel - 1] & 0xFF;
+	ofdm_power = priv->txpower[channel - 1] >> 8;
+
+	cck_power = min(cck_power, (u8)35);
+	ofdm_power = min(ofdm_power, (u8)35);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
+
+	if (channel == 14)
+		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
+	else
+		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	mdelay(1); /* FIXME: optional? */
+
+	/* anaparam2 on */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+			 rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1);
+
+	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
+
+	rtl8225_write_phy_ofdm(dev, 5, *tmp);
+	rtl8225_write_phy_ofdm(dev, 7, *tmp);
+
+	mdelay(1);
+}
+
+static void rtl8225_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	rtl818x_set_anaparam(priv, RTL8225_ANAPARAM_ON);
+
+	/* host_pci_init */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	mdelay(200);	/* FIXME: ehh?? */
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
+
+	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
+
+	/* TODO: check if we need really to change BRSR to do RF config */
+	rtl818x_ioread16(priv, &priv->map->BRSR);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl8225_write(dev, 0x0, 0x067);
+	rtl8225_write(dev, 0x1, 0xFE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8BE);
+	rtl8225_write(dev, 0x5, 0xBF0);		/* TODO: minipci */
+	rtl8225_write(dev, 0x6, 0xAE6);
+	rtl8225_write(dev, 0x7, rtl8225_chan[0]);
+	rtl8225_write(dev, 0x8, 0x01F);
+	rtl8225_write(dev, 0x9, 0x334);
+	rtl8225_write(dev, 0xA, 0xFD4);
+	rtl8225_write(dev, 0xB, 0x391);
+	rtl8225_write(dev, 0xC, 0x050);
+	rtl8225_write(dev, 0xD, 0x6DB);
+	rtl8225_write(dev, 0xE, 0x029);
+	rtl8225_write(dev, 0xF, 0x914); mdelay(1);
+
+	rtl8225_write(dev, 0x2, 0xC4D); mdelay(100);
+
+	rtl8225_write(dev, 0x0, 0x127);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x0, 0x027);
+	rtl8225_write(dev, 0x0, 0x22F);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		mdelay(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		mdelay(1);
+	}
+
+	mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x03); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x93); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x1f); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x1e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x1a); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x10); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x0a); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x05); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x02); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
+
+	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); mdelay(1);
+
+	rtl8225_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	mdelay(1);
+	rtl818x_iowrite32(priv, (u32 *)((u8 *)priv->map + 0x94), 0x15c00002);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	rtl8225_write(dev, 0x0c, 0x50);
+	/* set OFDM initial gain */
+	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]);
+	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]);
+	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]);
+	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]);
+	/* set CCK threshold */
+	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]);
+}
+
+static const u8 rtl8225z2_tx_power_cck_ch14[] = {
+	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225z2_tx_power_cck_B[] = {
+	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_cck_A[] = {
+	0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_cck[] = {
+	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static void rtl8225z2_rf_set_tx_power(struct net80211_device *dev, int channel)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	int i;
+
+	cck_power = priv->txpower[channel - 1] & 0xFF;
+	ofdm_power = priv->txpower[channel - 1] >> 8;
+
+	if (channel == 14)
+		tmp = rtl8225z2_tx_power_cck_ch14;
+	else if (cck_power == 12)
+		tmp = rtl8225z2_tx_power_cck_B;
+	else if (cck_power == 13)
+		tmp = rtl8225z2_tx_power_cck_A;
+	else
+		tmp = rtl8225z2_tx_power_cck;
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	cck_power = min(cck_power, (u8)35);
+	if (cck_power == 13 || cck_power == 14)
+		cck_power = 12;
+	if (cck_power >= 15)
+		cck_power -= 2;
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power);
+	rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK);
+	mdelay(1);
+
+	ofdm_power = min(ofdm_power, (u8)35);
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power);
+
+	rtl8225_write_phy_ofdm(dev, 2, 0x62);
+	rtl8225_write_phy_ofdm(dev, 5, 0x00);
+	rtl8225_write_phy_ofdm(dev, 6, 0x40);
+	rtl8225_write_phy_ofdm(dev, 7, 0x00);
+	rtl8225_write_phy_ofdm(dev, 8, 0x40);
+
+	mdelay(1);
+}
+
+static const u16 rtl8225z2_rxgain[] = {
+	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
+	0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
+	0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
+	0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
+	0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
+	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
+	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
+	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
+	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
+	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
+	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static void rtl8225z2_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	rtl818x_set_anaparam(priv, RTL8225_ANAPARAM_ON);
+
+	/* host_pci_init */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	mdelay(200);	/* FIXME: ehh?? */
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
+
+	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008);
+
+	/* TODO: check if we need really to change BRSR to do RF config */
+	rtl818x_ioread16(priv, &priv->map->BRSR);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	rtl8225_write(dev, 0x0, 0x0B7); mdelay(1);
+	rtl8225_write(dev, 0x1, 0xEE0); mdelay(1);
+	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
+	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
+	rtl8225_write(dev, 0x4, 0x8C3); mdelay(1);
+	rtl8225_write(dev, 0x5, 0xC72); mdelay(1);
+	rtl8225_write(dev, 0x6, 0x0E6); mdelay(1);
+	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
+	rtl8225_write(dev, 0x8, 0x03F); mdelay(1);
+	rtl8225_write(dev, 0x9, 0x335); mdelay(1);
+	rtl8225_write(dev, 0xa, 0x9D4); mdelay(1);
+	rtl8225_write(dev, 0xb, 0x7BB); mdelay(1);
+	rtl8225_write(dev, 0xc, 0x850); mdelay(1);
+	rtl8225_write(dev, 0xd, 0xCDF); mdelay(1);
+	rtl8225_write(dev, 0xe, 0x02B); mdelay(1);
+	rtl8225_write(dev, 0xf, 0x114); mdelay(100);
+
+	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+		rtl8225_write(dev, 0x02, 0x0C4D);
+		mdelay(200);
+		rtl8225_write(dev, 0x02, 0x044D);
+		mdelay(100);
+		/* TODO: readd calibration failure message when the calibration
+		   check works */
+	}
+
+	rtl8225_write(dev, 0x0, 0x1B7);
+	rtl8225_write(dev, 0x3, 0x002);
+	rtl8225_write(dev, 0x5, 0x004);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x0, 0x0B7); mdelay(100);
+	rtl8225_write(dev, 0x2, 0xC4D);
+
+	mdelay(200);
+	rtl8225_write(dev, 0x2, 0x44D);
+	mdelay(100);
+
+	rtl8225_write(dev, 0x00, 0x2BF);
+	rtl8225_write(dev, 0xFF, 0xFFFF);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		mdelay(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		mdelay(1);
+	}
+
+	mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); mdelay(1); /* FIXME: not needed? */
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x93); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8a); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x36); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x35); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x25); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x1c); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x09); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x04); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
+
+	rtl818x_iowrite8(priv, (u8 *)priv->map + 0x5B, 0x0D); mdelay(1);
+
+	rtl8225z2_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	mdelay(1);
+	rtl818x_iowrite32(priv, (u32 *)((u8 *)priv->map + 0x94), 0x15c00002);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+}
+
+static void rtl8225x_rf_init(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u16 reg8, reg9;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	mdelay(100);
+
+	rtl8225_write(dev, 0, 0x1B7);
+
+	reg8 = rtl8225_read(dev, 8);
+	reg9 = rtl8225_read(dev, 9);
+
+	rtl8225_write(dev, 0, 0x0B7);
+
+	if (reg8 != 0x588 || reg9 != 0x700) {
+		priv->rf_flag = 0;
+		rtl8225_rf_init(dev);
+	} else {
+		priv->rf_flag = 1;
+		rtl8225z2_rf_init(dev);
+	}
+}
+
+static void rtl8225_rf_stop(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 reg;
+
+	rtl8225_write(dev, 0x4, 0x1f); mdelay(1);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+static void rtl8225_rf_set_channel(struct net80211_device *dev,
+				   struct net80211_channel *channelp)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int chan = channelp->channel_nr;
+
+	if (priv->rf_flag)
+		rtl8225z2_rf_set_tx_power(dev, chan);
+	else
+		rtl8225_rf_set_tx_power(dev, chan);
+
+	rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
+	mdelay(10);
+}
+
+static void rtl8225_rf_conf_erp(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+
+	if (dev->phy_flags & NET80211_PHY_USE_SHORT_SLOT) {
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
+	} else {
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44);
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
+	}
+}
+
+struct rtl818x_rf_ops rtl8225_ops __rtl818x_rf_driver = {
+	.name		= "rtl8225",
+	.id		= 9,
+	.init		= rtl8225x_rf_init,
+	.stop		= rtl8225_rf_stop,
+	.set_chan	= rtl8225_rf_set_channel,
+	.conf_erp	= rtl8225_rf_conf_erp,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
new file mode 100644
index 0000000..cf4c755
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
@@ -0,0 +1,854 @@
+
+/*
+ * Linux device driver for RTL8180 / RTL8185
+ *
+ * Copyright 2007 Michael Wu <flamingice at sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified for iPXE, June 2009, by Joshua Oreman <oremanj at rwcr.net>
+ *
+ * Based on the r8180 driver, which is:
+ * Copyright 2004-2005 Andrea Merello <andreamrl at tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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.
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/net80211.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/threewire.h>
+
+#include "rtl818x.h"
+
+/* rtl818x_rates[hw rate number] = rate in 100kbps units */
+static const u16 rtl818x_rates[] = {
+	10, 20, 55, 110, /* 802.11b */
+	60, 90, 120, 180, 240, 360, 480, 540, /* 802.11g */
+	0, 0, 0, 0,		/* index safely using a value masked with 0xF */
+};
+#define RTL818X_NR_B_RATES  4
+#define RTL818X_NR_RATES    12
+
+/* used by RF drivers */
+void rtl818x_write_phy(struct net80211_device *dev, u8 addr, u32 data)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i = 10;
+	u32 buf;
+
+	buf = (data << 8) | addr;
+
+	rtl818x_iowrite32(priv, (u32 *)&priv->map->PHY[0], buf | 0x80);
+	while (i--) {
+		rtl818x_iowrite32(priv, (u32 *)&priv->map->PHY[0], buf);
+		if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF))
+			return;
+	}
+}
+
+static void rtl818x_handle_rx(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	unsigned int count = RTL818X_RX_RING_SIZE;
+
+	while (count--) {
+		struct rtl818x_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
+		struct io_buffer *iob = priv->rx_buf[priv->rx_idx];
+		u32 flags = le32_to_cpu(entry->flags);
+
+		if (flags & RTL818X_RX_DESC_FLAG_OWN)
+			return;
+
+		if (flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
+			     RTL818X_RX_DESC_FLAG_FOF |
+			     RTL818X_RX_DESC_FLAG_RX_ERR)) {
+			/* This is crappy hardware. The Linux driver
+			   doesn't even log these. */
+			goto done;
+		} else if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) {
+			/* This is actually a corrupt packet. */
+			DBG2("rtl818x RX:%d CRC fail: flags %08x\n",
+			     priv->rx_idx, flags);
+			net80211_rx_err(dev, NULL, EIO);
+		} else {
+			u32 flags2 = le32_to_cpu(entry->flags2);
+			struct io_buffer *new_iob = alloc_iob(MAX_RX_SIZE);
+			if (!new_iob) {
+				net80211_rx_err(dev, NULL, ENOMEM);
+				goto done;
+			}
+
+			DBGP("rtl818x RX:%d success: flags %08x %08x\n",
+			     priv->rx_idx, flags, flags2);
+
+			iob_put(iob, flags & 0xFFF);
+
+			net80211_rx(dev, iob, (flags2 >> 8) & 0x7f,
+				    rtl818x_rates[(flags >> 20) & 0xf]);
+
+			iob = new_iob;
+			priv->rx_buf[priv->rx_idx] = iob;
+		}
+
+	done:
+		entry->rx_buf = cpu_to_le32(virt_to_bus(iob->data));
+		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE);
+
+		if (priv->rx_idx == RTL818X_RX_RING_SIZE - 1)
+			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
+
+		priv->rx_idx = (priv->rx_idx + 1) % RTL818X_RX_RING_SIZE;
+	}
+}
+
+static void rtl818x_handle_tx(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	unsigned int count = RTL818X_TX_RING_SIZE;
+
+	while (count--) {
+		struct rtl818x_tx_desc *entry = &priv->tx_ring[priv->tx_cons];
+		struct io_buffer *iob = priv->tx_buf[priv->tx_cons];
+		u32 flags = le32_to_cpu(entry->flags);
+		int rc;
+
+		if ((flags & RTL818X_TX_DESC_FLAG_OWN) || !iob)
+			return;
+
+		rc = 0;
+		if (!(flags & RTL818X_TX_DESC_FLAG_TX_OK)) {
+			/* our packet was not ACKed properly */
+			rc = EIO;
+		}
+
+		net80211_tx_complete(dev, iob, flags & 0xFF, rc);
+
+		priv->tx_buf[priv->tx_cons] = NULL;
+		priv->tx_cons = (priv->tx_cons + 1) % RTL818X_TX_RING_SIZE;
+	}
+}
+
+static void rtl818x_poll(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u16 reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
+
+	if (reg == 0xFFFF)
+		return;
+
+	rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
+
+	if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
+		rtl818x_handle_tx(dev);
+
+	if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
+		rtl818x_handle_rx(dev);
+}
+
+#define DIV_ROUND_UP(n,d) (((n)+(d)-1)/(d))
+
+static int rtl818x_tx(struct net80211_device *dev, struct io_buffer *iob)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	struct rtl818x_tx_desc *entry;
+	u32 tx_flags;
+	u16 plcp_len = 0;
+	int len = iob_len(iob);
+
+	tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
+		RTL818X_TX_DESC_FLAG_LS | (priv->hw_rate << 24) | len;
+
+	if (priv->r8185) {
+		tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
+			    RTL818X_TX_DESC_FLAG_NO_ENC;
+	} else {
+		unsigned int remainder;
+
+		plcp_len = DIV_ROUND_UP(16 * (len + 4),
+					(dev->rates[dev->rate] * 2) / 10);
+		remainder = (16 * (len + 4)) %
+			    ((dev->rates[dev->rate] * 2) / 10);
+
+		if (remainder > 0 && remainder <= 6)
+			plcp_len |= 1 << 15;
+	}
+
+	entry = &priv->tx_ring[priv->tx_prod];
+
+	if (dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
+		tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
+		tx_flags |= priv->hw_rtscts_rate << 19;
+		entry->rts_duration = net80211_cts_duration(dev, len);
+	} else {
+		entry->rts_duration = 0;
+	}
+
+	if (entry->flags & RTL818X_TX_DESC_FLAG_OWN) {
+		/* card hasn't processed the old packet yet! */
+		return -EBUSY;
+	}
+
+	priv->tx_buf[priv->tx_prod] = iob;
+	priv->tx_prod = (priv->tx_prod + 1) % RTL818X_TX_RING_SIZE;
+
+	entry->plcp_len = cpu_to_le16(plcp_len);
+	entry->tx_buf = cpu_to_le32(virt_to_bus(iob->data));
+	entry->frame_len = cpu_to_le32(len);
+	entry->flags2 = /* alternate retry rate in 100kbps << 4 */ 0;
+	entry->retry_limit = RTL818X_MAX_RETRIES;
+	entry->flags = cpu_to_le32(tx_flags);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << 5));
+
+	return 0;
+}
+
+void rtl818x_set_anaparam(struct rtl818x_priv *priv, u32 anaparam)
+{
+	u8 reg;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+		 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+		 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+static int rtl818x_init_hw(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u16 reg;
+
+	rtl818x_iowrite8(priv, &priv->map->CMD, 0);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	mdelay(10);
+
+	/* reset */
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= (1 << 1);
+	reg |= RTL818X_CMD_RESET;
+	rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	mdelay(200);
+
+	/* check success of reset */
+	if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) {
+		DBG("rtl818x %s: reset timeout!\n", dev->netdev->name);
+		return -ETIMEDOUT;
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	mdelay(200);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) {
+		/* For cardbus */
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+		reg |= 1 << 1;
+		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
+		reg = rtl818x_ioread16(priv, &priv->map->FEMR);
+		reg |= (1 << 15) | (1 << 14) | (1 << 4);
+		rtl818x_iowrite16(priv, &priv->map->FEMR, reg);
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->MSR, 0);
+
+	if (!priv->r8185)
+		rtl818x_set_anaparam(priv, priv->anaparam);
+
+	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
+	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring_dma);
+
+	/* TODO: necessary? specs indicate not */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3));
+	if (priv->r8185) {
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
+		rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4));
+	}
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	/* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */
+
+	/* TODO: turn off hw wep on rtl8180 */
+
+	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+
+	if (priv->r8185) {
+		rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
+		rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+		rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+		/* TODO: set ClkRun enable? necessary? */
+		reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE);
+		rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6));
+		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2));
+		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+	} else {
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1);
+		rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
+
+		rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
+		rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+	}
+
+	priv->rf->init(dev);
+	if (priv->r8185)
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+	return 0;
+}
+
+static int rtl818x_init_rx_ring(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	struct rtl818x_rx_desc *entry;
+	int i;
+
+	priv->rx_ring = malloc_dma(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE,
+				   RTL818X_RING_ALIGN);
+	priv->rx_ring_dma = virt_to_bus(priv->rx_ring);
+	if (!priv->rx_ring) {
+		DBG("rtl818x %s: cannot allocate RX ring\n", dev->netdev->name);
+		return -ENOMEM;
+	}
+
+	memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE);
+	priv->rx_idx = 0;
+
+	for (i = 0; i < RTL818X_RX_RING_SIZE; i++) {
+		struct io_buffer *iob = alloc_iob(MAX_RX_SIZE);
+		entry = &priv->rx_ring[i];
+		if (!iob)
+			return -ENOMEM;
+
+		priv->rx_buf[i] = iob;
+		entry->rx_buf = cpu_to_le32(virt_to_bus(iob->data));
+		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
+					   MAX_RX_SIZE);
+	}
+	entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
+	return 0;
+}
+
+static void rtl818x_free_rx_ring(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	for (i = 0; i < RTL818X_RX_RING_SIZE; i++) {
+		free_iob(priv->rx_buf[i]);
+		priv->rx_buf[i] = NULL;
+	}
+
+	free_dma(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE);
+	priv->rx_ring = NULL;
+}
+
+static int rtl818x_init_tx_ring(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	priv->tx_ring = malloc_dma(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE,
+				   RTL818X_RING_ALIGN);
+	priv->tx_ring_dma = virt_to_bus(priv->tx_ring);
+	if (!priv->tx_ring) {
+		DBG("rtl818x %s: cannot allocate TX ring\n", dev->netdev->name);
+		return -ENOMEM;
+	}
+
+	memset(priv->tx_ring, 0, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE);
+	priv->tx_prod = priv->tx_cons = 0;
+
+	for (i = 0; i < RTL818X_TX_RING_SIZE; i++)
+		priv->tx_ring[i].next_tx_desc = cpu_to_le32(priv->tx_ring_dma +
+				((i + 1) % RTL818X_TX_RING_SIZE) * sizeof(*priv->tx_ring));
+
+	return 0;
+}
+
+static void rtl818x_free_tx_ring(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	for (i = 0; i < RTL818X_TX_RING_SIZE; i++) {
+		if (priv->tx_buf[i])
+			net80211_tx_complete(dev, priv->tx_buf[i], 0, ECANCELED);
+		priv->tx_buf[i] = NULL;
+	}
+
+	free_dma(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE);
+	priv->tx_ring = NULL;
+}
+
+static void rtl818x_irq(struct net80211_device *dev, int enable)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, enable? 0xFFFF : 0);
+}
+
+/* Sets the MAC address of the card. */
+static void rtl818x_set_hwaddr(struct net80211_device *dev, u8 *hwaddr)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite32(priv, (u32 *)&priv->map->MAC[0],
+			  le32_to_cpu(*(u32 *)hwaddr));
+	rtl818x_iowrite16(priv, (u16 *)&priv->map->MAC[4],
+			  le16_to_cpu(*(u16 *)(hwaddr + 4)));
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+static int rtl818x_start(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int ret;
+	u32 reg;
+
+	ret = rtl818x_init_rx_ring(dev);
+	if (ret)
+		return ret;
+
+	ret = rtl818x_init_tx_ring(dev);
+	if (ret)
+		goto err_free_rings;
+
+	ret = rtl818x_init_hw(dev);
+	if (ret)
+		goto err_free_rings;
+
+	rtl818x_set_hwaddr(dev, dev->netdev->ll_addr);
+
+	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
+	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring_dma);
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+	rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
+	rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+
+	reg = RTL818X_RX_CONF_ONLYERLPKT |
+	      RTL818X_RX_CONF_RX_AUTORESETPHY |
+	      RTL818X_RX_CONF_MGMT |
+	      RTL818X_RX_CONF_DATA |
+	      (7 << 8 /* MAX RX DMA */) |
+	      RTL818X_RX_CONF_BROADCAST |
+	      RTL818X_RX_CONF_NICMAC;
+
+	if (priv->r8185)
+		reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2;
+	else {
+		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1)
+			? RTL818X_RX_CONF_CSDM1 : 0;
+		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2)
+			? RTL818X_RX_CONF_CSDM2 : 0;
+	}
+
+	priv->rx_conf = reg;
+	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+
+	if (priv->r8185) {
+		reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+		reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
+		reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+		rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
+
+		reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+		reg |=  RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+		rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
+		/* disable early TX */
+		rtl818x_iowrite8(priv, (u8 *)priv->map + 0xec, 0x3f);
+	}
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	reg |= (6 << 21 /* MAX TX DMA */) |
+	       RTL818X_TX_CONF_NO_ICV;
+
+	if (priv->r8185)
+		reg &= ~RTL818X_TX_CONF_PROBE_DTS;
+	else
+		reg &= ~RTL818X_TX_CONF_HW_SEQNUM;
+
+	/* different meaning, same value on both rtl8185 and rtl8180 */
+	reg &= ~RTL818X_TX_CONF_SAT_HWPLCP;
+
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg |= RTL818X_CMD_RX_ENABLE;
+	reg |= RTL818X_CMD_TX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	DBG("%s rtl818x: started\n", dev->netdev->name);
+
+	return 0;
+
+ err_free_rings:
+	rtl818x_free_rx_ring(dev);
+	if (priv->tx_ring)
+		rtl818x_free_tx_ring(dev);
+
+	DBG("%s rtl818x: failed to start\n", dev->netdev->name);
+
+	return ret;
+}
+
+static void rtl818x_stop(struct net80211_device *dev)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	u8 reg;
+
+	rtl818x_irq(dev, 0);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= ~RTL818X_CMD_TX_ENABLE;
+	reg &= ~RTL818X_CMD_RX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	priv->rf->stop(dev);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_free_rx_ring(dev);
+	rtl818x_free_tx_ring(dev);
+}
+
+static int rtl818x_config(struct net80211_device *dev, int changed)
+{
+	struct rtl818x_priv *priv = dev->priv;
+	int i;
+
+	if (changed & NET80211_CFG_CHANNEL)
+		priv->rf->set_chan(dev, &dev->channels[dev->channel]);
+
+	if (changed & NET80211_CFG_ASSOC) {
+		for (i = 0; i < ETH_ALEN; i++)
+			rtl818x_iowrite8(priv, &priv->map->BSSID[i], dev->bssid[i]);
+		rtl818x_iowrite8(priv, &priv->map->MSR,
+				 dev->state & NET80211_ASSOCIATED?
+					RTL818X_MSR_INFRA : RTL818X_MSR_NO_LINK);
+	}
+
+	if (changed & NET80211_CFG_PHY_PARAMS)
+		priv->rf->conf_erp(dev);
+
+	if (changed & NET80211_CFG_RATE) {
+		/* figure out the hardware rate number for the new
+		   logical rate */
+		int hw_rate;
+		for (hw_rate = 0; hw_rate < RTL818X_NR_RATES &&
+			     rtl818x_rates[hw_rate] != dev->rates[dev->rate];
+		     hw_rate++)
+			;
+		if (hw_rate >= RTL818X_NR_RATES)
+			return -EINVAL;
+
+		priv->hw_rate = hw_rate;
+
+		/* and the RTS/CTS rate */
+		for (hw_rate = 0; hw_rate < RTL818X_NR_RATES &&
+			     rtl818x_rates[hw_rate] !=
+				dev->rates[dev->rtscts_rate];
+		     hw_rate++)
+			;
+		if (hw_rate >= RTL818X_NR_RATES)
+			hw_rate = priv->hw_rate;
+
+		priv->hw_rtscts_rate = hw_rate;
+	}
+
+	return 0;
+}
+
+static const u8 rtl818x_eeprom_bits[] = {
+	[SPI_BIT_SCLK] = RTL818X_EEPROM_CMD_CK,
+	[SPI_BIT_MISO] = RTL818X_EEPROM_CMD_READ,
+	[SPI_BIT_MOSI] = RTL818X_EEPROM_CMD_WRITE,
+	[SPI_BIT_SS(0)] = RTL818X_EEPROM_CMD_CS,
+};
+
+static int rtl818x_spi_read_bit(struct bit_basher *basher, unsigned int bit_id)
+{
+	struct rtl818x_priv *priv = container_of(basher, struct rtl818x_priv,
+						 spibit.basher);
+
+	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	return reg & rtl818x_eeprom_bits[bit_id];
+}
+
+static void rtl818x_spi_write_bit(struct bit_basher *basher,
+				  unsigned int bit_id, unsigned long data)
+{
+	struct rtl818x_priv *priv = container_of(basher, struct rtl818x_priv,
+						 spibit.basher);
+
+	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	u8 mask = rtl818x_eeprom_bits[bit_id];
+	reg = (reg & ~mask) | (data & mask);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
+
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+}
+
+static struct bit_basher_operations rtl818x_basher_ops = {
+	.read = rtl818x_spi_read_bit,
+	.write = rtl818x_spi_write_bit,
+};
+
+#if DBGLVL_MAX
+static const char *rtl818x_rf_names[] = {
+	NULL,			/* no 0 */
+	"Intersil", "RFMD",	/* unsupported 1-2 */
+	"SA2400", "max2820", "GRF5101",	/* supported 3-5 */
+	NULL, NULL, NULL,	/* no 6-8 */
+	"RTL8225",		/* supported 9 */
+	"RTL8255",		/* unsupported 10 */
+};
+#define RTL818X_NR_RF_NAMES 11
+#endif
+
+struct net80211_device_operations rtl818x_operations = {
+	.open = rtl818x_start,
+	.close = rtl818x_stop,
+	.transmit = rtl818x_tx,
+	.poll = rtl818x_poll,
+	.irq = rtl818x_irq,
+	.config = rtl818x_config,
+};
+
+static int rtl818x_probe(struct pci_device *pdev )
+{
+	struct net80211_device *dev;
+	struct rtl818x_priv *priv;
+	struct rtl818x_rf_ops *rf;
+	int err, i;
+	const char *chip_name;
+	u32 reg;
+	u16 eeprom_val;
+	struct net80211_hw_info *hwinfo;
+
+	hwinfo = zalloc(sizeof(*hwinfo));
+	if (!hwinfo) {
+		DBG("rtl818x: hwinfo alloc failed\n");
+		return -ENOMEM;
+	}
+
+	adjust_pci_device(pdev);
+
+	dev = net80211_alloc(sizeof(*priv));
+	if (!dev) {
+		DBG("rtl818x: net80211 alloc failed\n");
+		return -ENOMEM;
+	}
+
+	priv = dev->priv;
+	priv->pdev = pdev;
+	dev->netdev->dev = &pdev->dev;
+
+	priv->map = (struct rtl818x_csr *)pdev->ioaddr;
+	if (!priv->map) {
+		DBG("rtl818x: cannot find device memory\n");
+		err = -ENXIO;
+		goto err_free_dev;
+	}
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	reg &= RTL818X_TX_CONF_HWVER_MASK;
+	switch (reg) {
+	case RTL818X_TX_CONF_R8180_ABCD:
+		chip_name = "0";
+		break;
+	case RTL818X_TX_CONF_R8180_F:
+		chip_name = "0vF";
+		break;
+	case RTL818X_TX_CONF_R8185_ABC:
+		chip_name = "5";
+		break;
+	case RTL818X_TX_CONF_R8185_D:
+		chip_name = "5vD";
+		break;
+	default:
+		DBG("rtl818x: Unknown chip! (0x%x)\n", reg >> 25);
+		err = -ENOSYS;
+		goto err_free_dev;
+	}
+
+	priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC;
+
+	hwinfo->bands = NET80211_BAND_BIT_2GHZ;
+	hwinfo->flags = NET80211_HW_RX_HAS_FCS;
+	hwinfo->signal_type = NET80211_SIGNAL_ARBITRARY;
+	hwinfo->signal_max = 65;
+	hwinfo->channel_change_time = 1000;
+
+	memcpy(hwinfo->rates[NET80211_BAND_2GHZ], rtl818x_rates,
+	       sizeof(*rtl818x_rates) * RTL818X_NR_RATES);
+
+	if (priv->r8185) {
+		hwinfo->modes = NET80211_MODE_B | NET80211_MODE_G;
+		hwinfo->nr_rates[NET80211_BAND_2GHZ] = RTL818X_NR_RATES;
+	} else {
+		hwinfo->modes = NET80211_MODE_B;
+		hwinfo->nr_rates[NET80211_BAND_2GHZ] = RTL818X_NR_B_RATES;
+	}
+
+	priv->spibit.basher.op = &rtl818x_basher_ops;
+	priv->spibit.bus.mode = SPI_MODE_THREEWIRE;
+	init_spi_bit_basher(&priv->spibit);
+
+	DBG2("rtl818x RX_CONF: %08x\n", rtl818x_ioread32(priv, &priv->map->RX_CONF));
+
+	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+		init_at93c66(&priv->eeprom, 16);
+	else
+		init_at93c46(&priv->eeprom, 16);
+	priv->eeprom.bus = &priv->spibit.bus;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	nvs_read(&priv->eeprom.nvs, 0x06, &eeprom_val, 2);
+	DBG2("rtl818x eeprom val = %04x\n", eeprom_val);
+	eeprom_val &= 0xFF;
+
+	priv->rf = NULL;
+	for_each_table_entry(rf, RTL818X_RF_DRIVERS) {
+		if (rf->id == eeprom_val) {
+			priv->rf = rf;
+			break;
+		}
+	}
+
+	if (!priv->rf) {
+#if DBGLVL_MAX
+		if (eeprom_val < RTL818X_NR_RF_NAMES &&
+		    rtl818x_rf_names[eeprom_val] != NULL)
+			DBG("rtl818x: %s RF frontend not supported!\n",
+			    rtl818x_rf_names[eeprom_val]);
+		else
+			DBG("rtl818x: RF frontend #%d not recognized!\n",
+			    eeprom_val);
+#endif
+
+		err = -ENOSYS;
+		goto err_free_dev;
+	}
+
+	nvs_read(&priv->eeprom.nvs, 0x17, &eeprom_val, 2);
+	priv->csthreshold = eeprom_val >> 8;
+	if (!priv->r8185) {
+		nvs_read(&priv->eeprom.nvs, 0xD, &priv->anaparam, 4);
+		nvs_read(&priv->eeprom.nvs, 0x19, &priv->rfparam, 2);
+		priv->anaparam = le32_to_cpu(priv->anaparam);
+		priv->rfparam = le16_to_cpu(priv->rfparam);
+	}
+
+	/* read the MAC address */
+	nvs_read(&priv->eeprom.nvs, 0x7, hwinfo->hwaddr, 6);
+
+	/* CCK TX power */
+	for (i = 0; i < 14; i += 2) {
+		u16 txpwr;
+		nvs_read(&priv->eeprom.nvs, 0x10 + (i >> 1), &txpwr, 2);
+		priv->txpower[i] = txpwr & 0xFF;
+		priv->txpower[i + 1] = txpwr >> 8;
+	}
+
+	/* OFDM TX power */
+	if (priv->r8185) {
+		for (i = 0; i < 14; i += 2) {
+			u16 txpwr;
+			nvs_read(&priv->eeprom.nvs, 0x20 + (i >> 1), &txpwr, 2);
+			priv->txpower[i] |= (txpwr & 0xFF) << 8;
+			priv->txpower[i + 1] |= txpwr & 0xFF00;
+		}
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	err = net80211_register(dev, &rtl818x_operations, hwinfo);
+	if (err) {
+		DBG("rtl818x: cannot register device\n");
+		goto err_free_dev;
+	}
+
+	free(hwinfo);
+
+	DBG("rtl818x: Realtek RTL818%s (RF chip %s) with address %s\n",
+	    chip_name, priv->rf->name, netdev_addr(dev->netdev));
+
+	return 0;
+
+ err_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	net80211_free(dev);
+	free(hwinfo);
+	return err;
+}
+
+static void rtl818x_remove(struct pci_device *pdev)
+{
+	struct net80211_device *dev = pci_get_drvdata(pdev);
+
+	if (!dev)
+		return;
+
+	net80211_unregister(dev);
+	net80211_free(dev);
+}
+
+/* Hide PCI_ROM definitions in here from parserom.pl; the definitions
+   that should be used are in rtl8180.c and rtl8185.c. */
+#define RTL_ROM PCI_ROM
+
+static struct pci_device_id rtl818x_nics[] = {
+	RTL_ROM(0x10ec, 0x8185, "rtl8185", "Realtek 8185", 0),
+	RTL_ROM(0x1799, 0x700f, "f5d7000", "Belkin F5D7000", 0),
+	RTL_ROM(0x1799, 0x701f, "f5d7010", "Belkin F5D7010", 0),
+
+	RTL_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0),
+	RTL_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0),
+	RTL_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0),
+	RTL_ROM(0x1186, 0x3300, "dwl510",  "D-Link DWL-510", 0),
+};
+
+struct pci_driver rtl818x_driver __pci_driver = {
+	.ids            = rtl818x_nics,
+	.id_count       = sizeof(rtl818x_nics) / sizeof(rtl818x_nics[0]),
+	.probe		= rtl818x_probe,
+	.remove		= rtl818x_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
new file mode 100644
index 0000000..4e57d0b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
@@ -0,0 +1,359 @@
+/*
+ * Definitions for RTL818x hardware
+ *
+ * Copyright 2007 Michael Wu <flamingice at sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl at tiscali.it>
+ *
+ * Modified for iPXE, June 2009, by Joshua Oreman <oremanj at rwcr.net>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl at tiscali.it>, et al.
+ *
+ * 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.
+ */
+
+#ifndef RTL818X_H
+#define RTL818X_H
+
+#include <ipxe/spi_bit.h>
+#include <ipxe/tables.h>
+
+FILE_LICENCE(GPL2_ONLY);
+
+struct rtl818x_csr {
+	u8	MAC[6];
+	u8	reserved_0[2];
+	u32	MAR[2];
+	u8	RX_FIFO_COUNT;
+	u8	reserved_1;
+	u8	TX_FIFO_COUNT;
+	u8	BQREQ;
+	u8	reserved_2[4];
+	u32	TSFT[2];
+	u32	TLPDA;
+	u32	TNPDA;
+	u32	THPDA;
+	u16	BRSR;
+	u8	BSSID[6];
+	u8	RESP_RATE;
+	u8	EIFS;
+	u8	reserved_3[1];
+	u8	CMD;
+#define RTL818X_CMD_TX_ENABLE		(1 << 2)
+#define RTL818X_CMD_RX_ENABLE		(1 << 3)
+#define RTL818X_CMD_RESET		(1 << 4)
+	u8	reserved_4[4];
+	u16	INT_MASK;
+	u16	INT_STATUS;
+#define RTL818X_INT_RX_OK		(1 <<  0)
+#define RTL818X_INT_RX_ERR		(1 <<  1)
+#define RTL818X_INT_TXL_OK		(1 <<  2)
+#define RTL818X_INT_TXL_ERR		(1 <<  3)
+#define RTL818X_INT_RX_DU		(1 <<  4)
+#define RTL818X_INT_RX_FO		(1 <<  5)
+#define RTL818X_INT_TXN_OK		(1 <<  6)
+#define RTL818X_INT_TXN_ERR		(1 <<  7)
+#define RTL818X_INT_TXH_OK		(1 <<  8)
+#define RTL818X_INT_TXH_ERR		(1 <<  9)
+#define RTL818X_INT_TXB_OK		(1 << 10)
+#define RTL818X_INT_TXB_ERR		(1 << 11)
+#define RTL818X_INT_ATIM		(1 << 12)
+#define RTL818X_INT_BEACON		(1 << 13)
+#define RTL818X_INT_TIME_OUT		(1 << 14)
+#define RTL818X_INT_TX_FO		(1 << 15)
+	u32	TX_CONF;
+#define RTL818X_TX_CONF_LOOPBACK_MAC	(1 << 17)
+#define RTL818X_TX_CONF_LOOPBACK_CONT	(3 << 17)
+#define RTL818X_TX_CONF_NO_ICV		(1 << 19)
+#define RTL818X_TX_CONF_DISCW		(1 << 20)
+#define RTL818X_TX_CONF_SAT_HWPLCP	(1 << 24)
+#define RTL818X_TX_CONF_R8180_ABCD	(2 << 25)
+#define RTL818X_TX_CONF_R8180_F		(3 << 25)
+#define RTL818X_TX_CONF_R8185_ABC	(4 << 25)
+#define RTL818X_TX_CONF_R8185_D		(5 << 25)
+#define RTL818X_TX_CONF_R8187vD		(5 << 25)
+#define RTL818X_TX_CONF_R8187vD_B	(6 << 25)
+#define RTL818X_TX_CONF_HWVER_MASK	(7 << 25)
+#define RTL818X_TX_CONF_DISREQQSIZE	(1 << 28)
+#define RTL818X_TX_CONF_PROBE_DTS	(1 << 29)
+#define RTL818X_TX_CONF_HW_SEQNUM	(1 << 30)
+#define RTL818X_TX_CONF_CW_MIN		(1 << 31)
+	u32	RX_CONF;
+#define RTL818X_RX_CONF_MONITOR		(1 <<  0)
+#define RTL818X_RX_CONF_NICMAC		(1 <<  1)
+#define RTL818X_RX_CONF_MULTICAST	(1 <<  2)
+#define RTL818X_RX_CONF_BROADCAST	(1 <<  3)
+#define RTL818X_RX_CONF_FCS		(1 <<  5)
+#define RTL818X_RX_CONF_DATA		(1 << 18)
+#define RTL818X_RX_CONF_CTRL		(1 << 19)
+#define RTL818X_RX_CONF_MGMT		(1 << 20)
+#define RTL818X_RX_CONF_ADDR3		(1 << 21)
+#define RTL818X_RX_CONF_PM		(1 << 22)
+#define RTL818X_RX_CONF_BSSID		(1 << 23)
+#define RTL818X_RX_CONF_RX_AUTORESETPHY	(1 << 28)
+#define RTL818X_RX_CONF_CSDM1		(1 << 29)
+#define RTL818X_RX_CONF_CSDM2		(1 << 30)
+#define RTL818X_RX_CONF_ONLYERLPKT	(1 << 31)
+	u32	INT_TIMEOUT;
+	u32	TBDA;
+	u8	EEPROM_CMD;
+#define RTL818X_EEPROM_CMD_READ		(1 << 0)
+#define RTL818X_EEPROM_CMD_WRITE	(1 << 1)
+#define RTL818X_EEPROM_CMD_CK		(1 << 2)
+#define RTL818X_EEPROM_CMD_CS		(1 << 3)
+#define RTL818X_EEPROM_CMD_NORMAL	(0 << 6)
+#define RTL818X_EEPROM_CMD_LOAD		(1 << 6)
+#define RTL818X_EEPROM_CMD_PROGRAM	(2 << 6)
+#define RTL818X_EEPROM_CMD_CONFIG	(3 << 6)
+	u8	CONFIG0;
+	u8	CONFIG1;
+	u8	CONFIG2;
+#define RTL818X_CONFIG2_ANTENNA_DIV	(1 << 6)
+	u32	ANAPARAM;
+	u8	MSR;
+#define RTL818X_MSR_NO_LINK		(0 << 2)
+#define RTL818X_MSR_ADHOC		(1 << 2)
+#define RTL818X_MSR_INFRA		(2 << 2)
+#define RTL818X_MSR_MASTER		(3 << 2)
+#define RTL818X_MSR_ENEDCA		(4 << 2)
+	u8	CONFIG3;
+#define RTL818X_CONFIG3_ANAPARAM_WRITE	(1 << 6)
+#define RTL818X_CONFIG3_GNT_SELECT	(1 << 7)
+	u8	CONFIG4;
+#define RTL818X_CONFIG4_POWEROFF	(1 << 6)
+#define RTL818X_CONFIG4_VCOOFF		(1 << 7)
+	u8	TESTR;
+	u8	reserved_9[2];
+	u8	PGSELECT;
+	u8	SECURITY;
+	u32	ANAPARAM2;
+	u8	reserved_10[12];
+	u16	BEACON_INTERVAL;
+	u16	ATIM_WND;
+	u16	BEACON_INTERVAL_TIME;
+	u16	ATIMTR_INTERVAL;
+	u8	PHY_DELAY;
+	u8	CARRIER_SENSE_COUNTER;
+	u8	reserved_11[2];
+	u8	PHY[4];
+	u16	RFPinsOutput;
+	u16	RFPinsEnable;
+	u16	RFPinsSelect;
+	u16	RFPinsInput;
+	u32	RF_PARA;
+	u32	RF_TIMING;
+	u8	GP_ENABLE;
+	u8	GPIO;
+	u8	reserved_12[2];
+	u32	HSSI_PARA;
+	u8	reserved_13[4];
+	u8	TX_AGC_CTL;
+#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT		(1 << 0)
+#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT	(1 << 1)
+#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT			(1 << 2)
+	u8	TX_GAIN_CCK;
+	u8	TX_GAIN_OFDM;
+	u8	TX_ANTENNA;
+	u8	reserved_14[16];
+	u8	WPA_CONF;
+	u8	reserved_15[3];
+	u8	SIFS;
+	u8	DIFS;
+	u8	SLOT;
+	u8	reserved_16[5];
+	u8	CW_CONF;
+#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT	(1 << 0)
+#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT	(1 << 1)
+	u8	CW_VAL;
+	u8	RATE_FALLBACK;
+#define RTL818X_RATE_FALLBACK_ENABLE	(1 << 7)
+	u8	ACM_CONTROL;
+	u8	reserved_17[24];
+	u8	CONFIG5;
+	u8	TX_DMA_POLLING;
+	u8	reserved_18[2];
+	u16	CWR;
+	u8	RETRY_CTR;
+	u8	reserved_19[3];
+	u16	INT_MIG;
+/* RTL818X_R8187B_*: magic numbers from ioregisters */
+#define RTL818X_R8187B_B	0
+#define RTL818X_R8187B_D	1
+#define RTL818X_R8187B_E	2
+	u32	RDSAR;
+	u16	TID_AC_MAP;
+	u8	reserved_20[4];
+	u8	ANAPARAM3;
+	u8	reserved_21[5];
+	u16	FEMR;
+	u8	reserved_22[4];
+	u16	TALLY_CNT;
+	u8	TALLY_SEL;
+} __attribute__((packed));
+
+#define MAX_RX_SIZE IEEE80211_MAX_FRAME_LEN
+
+#define RF_PARAM_ANALOGPHY	(1 << 0)
+#define RF_PARAM_ANTBDEFAULT	(1 << 1)
+#define RF_PARAM_CARRIERSENSE1	(1 << 2)
+#define RF_PARAM_CARRIERSENSE2	(1 << 3)
+
+#define BB_ANTATTEN_CHAN14	0x0C
+#define BB_ANTENNA_B 		0x40
+
+#define BB_HOST_BANG 		(1 << 30)
+#define BB_HOST_BANG_EN 	(1 << 2)
+#define BB_HOST_BANG_CLK 	(1 << 1)
+#define BB_HOST_BANG_DATA	1
+
+#define ANAPARAM_TXDACOFF_SHIFT	27
+#define ANAPARAM_PWR0_SHIFT	28
+#define ANAPARAM_PWR0_MASK 	(0x07 << ANAPARAM_PWR0_SHIFT)
+#define ANAPARAM_PWR1_SHIFT	20
+#define ANAPARAM_PWR1_MASK	(0x7F << ANAPARAM_PWR1_SHIFT)
+
+#define RTL818X_RX_RING_SIZE	8 /* doesn't have to be a power of 2 */
+#define RTL818X_TX_RING_SIZE	8 /* nor this [but 2^n is very slightly faster] */
+#define RTL818X_RING_ALIGN	256
+
+#define RTL818X_MAX_RETRIES     4
+
+enum rtl818x_tx_desc_flags {
+	RTL818X_TX_DESC_FLAG_NO_ENC	= (1 << 15),
+	RTL818X_TX_DESC_FLAG_TX_OK	= (1 << 15),
+	RTL818X_TX_DESC_FLAG_SPLCP	= (1 << 16),
+	RTL818X_TX_DESC_FLAG_RX_UNDER	= (1 << 16),
+	RTL818X_TX_DESC_FLAG_MOREFRAG	= (1 << 17),
+	RTL818X_TX_DESC_FLAG_CTS	= (1 << 18),
+	RTL818X_TX_DESC_FLAG_RTS	= (1 << 23),
+	RTL818X_TX_DESC_FLAG_LS		= (1 << 28),
+	RTL818X_TX_DESC_FLAG_FS		= (1 << 29),
+	RTL818X_TX_DESC_FLAG_DMA	= (1 << 30),
+	RTL818X_TX_DESC_FLAG_OWN	= (1 << 31)
+};
+
+struct rtl818x_tx_desc {
+	u32 flags;
+	u16 rts_duration;
+	u16 plcp_len;
+	u32 tx_buf;
+	u32 frame_len;
+	u32 next_tx_desc;
+	u8 cw;
+	u8 retry_limit;
+	u8 agc;
+	u8 flags2;
+	u32 reserved[2];
+} __attribute__ ((packed));
+
+enum rtl818x_rx_desc_flags {
+	RTL818X_RX_DESC_FLAG_ICV_ERR	= (1 << 12),
+	RTL818X_RX_DESC_FLAG_CRC32_ERR	= (1 << 13),
+	RTL818X_RX_DESC_FLAG_PM		= (1 << 14),
+	RTL818X_RX_DESC_FLAG_RX_ERR	= (1 << 15),
+	RTL818X_RX_DESC_FLAG_BCAST	= (1 << 16),
+	RTL818X_RX_DESC_FLAG_PAM	= (1 << 17),
+	RTL818X_RX_DESC_FLAG_MCAST	= (1 << 18),
+	RTL818X_RX_DESC_FLAG_QOS	= (1 << 19), /* RTL8187(B) only */
+	RTL818X_RX_DESC_FLAG_TRSW	= (1 << 24), /* RTL8187(B) only */
+	RTL818X_RX_DESC_FLAG_SPLCP	= (1 << 25),
+	RTL818X_RX_DESC_FLAG_FOF	= (1 << 26),
+	RTL818X_RX_DESC_FLAG_DMA_FAIL	= (1 << 27),
+	RTL818X_RX_DESC_FLAG_LS		= (1 << 28),
+	RTL818X_RX_DESC_FLAG_FS		= (1 << 29),
+	RTL818X_RX_DESC_FLAG_EOR	= (1 << 30),
+	RTL818X_RX_DESC_FLAG_OWN	= (1 << 31)
+};
+
+struct rtl818x_rx_desc {
+	u32 flags;
+	u32 flags2;
+	union {
+		u32 rx_buf;
+		u64 tsft;
+	};
+} __attribute__ ((packed));
+
+struct rtl818x_priv {
+	struct rtl818x_csr *map;
+	const struct rtl818x_rf_ops *rf;
+	int rf_flag; /* whatever RF driver wishes to use it for */
+	int hw_rate;
+	int hw_rtscts_rate;
+
+	struct spi_bit_basher spibit;
+	struct spi_device eeprom;
+
+	struct rtl818x_rx_desc *rx_ring;
+	u32 rx_ring_dma;
+	unsigned int rx_idx;	/* next desc to be filled by card */
+	struct io_buffer *rx_buf[RTL818X_RX_RING_SIZE];
+
+	struct rtl818x_tx_desc *tx_ring;
+	u32 tx_ring_dma;
+	unsigned int tx_cons;	/* next desc to be filled by card */
+	unsigned int tx_prod;	/* next desc to be filled by driver */
+	struct io_buffer *tx_buf[RTL818X_TX_RING_SIZE];
+
+	struct pci_device *pdev;
+	u32 rx_conf;
+
+	u16 txpower[14];
+
+	int r8185;
+	u32 anaparam;
+	u16 rfparam;
+	u8 csthreshold;
+};
+
+void rtl818x_write_phy(struct net80211_device *dev, u8 addr, u32 data);
+void rtl818x_set_anaparam(struct rtl818x_priv *priv, u32 anaparam);
+
+static inline u8 rtl818x_ioread8(struct rtl818x_priv *priv __unused, u8 *addr)
+{
+	return inb(addr);
+}
+
+static inline u16 rtl818x_ioread16(struct rtl818x_priv *priv __unused, u16 *addr)
+{
+	return inw(addr);
+}
+
+static inline u32 rtl818x_ioread32(struct rtl818x_priv *priv __unused, u32 *addr)
+{
+	return inl(addr);
+}
+
+static inline void rtl818x_iowrite8(struct rtl818x_priv *priv __unused,
+				    u8 *addr, u8 val)
+{
+	outb(val, addr);
+}
+
+static inline void rtl818x_iowrite16(struct rtl818x_priv *priv __unused,
+				     u16 *addr, u16 val)
+{
+	outw(val, addr);
+}
+
+static inline void rtl818x_iowrite32(struct rtl818x_priv *priv __unused,
+				     u32 *addr, u32 val)
+{
+	outl(val, addr);
+}
+
+#define RTL818X_RF_DRIVERS __table(struct rtl818x_rf_ops, "rtl818x_rf_drivers")
+#define __rtl818x_rf_driver __table_entry(RTL818X_RF_DRIVERS, 01)
+
+struct rtl818x_rf_ops {
+	char *name;
+	u8 id;			/* as identified in EEPROM */
+	void (*init)(struct net80211_device *dev);
+	void (*stop)(struct net80211_device *dev);
+	void (*set_chan)(struct net80211_device *dev, struct net80211_channel *chan);
+	void (*conf_erp)(struct net80211_device *dev); /* set based on dev->erp_flags */
+};
+
+#endif /* RTL818X_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.c
new file mode 100644
index 0000000..991c30f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.c
@@ -0,0 +1,1174 @@
+/*
+   sis190.c: Silicon Integrated Systems SiS190 ethernet driver
+
+   Copyright (c) 2003 K.M. Liu <kmliu at sis.com>
+   Copyright (c) 2003, 2004 Jeff Garzik <jgarzik at pobox.com>
+   Copyright (c) 2003, 2004, 2005 Francois Romieu <romieu at fr.zoreil.com>
+
+   Modified for iPXE 2009 by Thomas Miletich <thomas.miletich at gmail.com>
+
+   Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191
+   genuine driver.
+
+   This software may be used and distributed according to the terms of
+   the GNU General Public License (GPL), incorporated herein by reference.
+   Drivers based on or derived from this code fall under the GPL and must
+   retain the authorship, copyright and license notice.  This file is not
+   a complete program and may only be used when the entire operating
+   system is licensed under the GPL.
+
+   See the file COPYING in this distribution for more information.
+
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+#include "sis190.h"
+
+static struct pci_device_id sis190_pci_tbl[] = {
+	PCI_ROM (0x1039, 0x0190, "sis190", "sis190", 0),
+	PCI_ROM (0x1039, 0x0191, "sis191", "sis191", 0),
+};
+
+/******************************************************************************
+ *************** HACK to keep ISA bridge in the PCI device list ***************
+ ******************************************************************************/
+
+/* Some sis190 variants store the MAC address in the BIOS CMOS. To read it, we
+ * have to use a PCI to ISA bridge. To access the bridge we need a few things
+ * from it's struct pci_device. We fake the successful probe of a driver to
+ * keep the bridge's struct pci_device in the list of pci_devices.
+ * See details in sis190_get_mac_addr_from_apc().
+ */
+
+static struct pci_device_id sis190_isa_bridge_tbl[] = {
+	PCI_ID (0x1039, 0x0965, "", "", 0),
+	PCI_ID (0x1039, 0x0966, "", "", 0),
+	PCI_ID (0x1039, 0x0968, "", "", 0),
+};
+
+static int sis190_isa_bridge_probe(struct pci_device *pdev __unused)
+{
+	return 0;
+}
+
+static void sis190_isa_bridge_remove(struct pci_device *pdev __unused)
+{
+	return;
+}
+
+struct pci_driver sis190_isa_bridge_driver __pci_driver = {
+	.ids		= sis190_isa_bridge_tbl,
+	.id_count	= (sizeof(sis190_isa_bridge_tbl) /
+	                   sizeof(sis190_isa_bridge_tbl[0])),
+	.probe		= sis190_isa_bridge_probe,
+	.remove		= sis190_isa_bridge_remove,
+};
+
+/******************************************************************************
+ *********************************** </HACK> **********************************
+ ******************************************************************************/
+
+static const u32 sis190_intr_mask =
+	RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
+
+/*
+ * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ * The chips use a 64 element hash table based on the Ethernet CRC.
+ */
+static const int multicast_filter_limit = 32;
+
+static void __mdio_cmd(void *ioaddr, u32 ctl)
+{
+	unsigned int i;
+
+	SIS_W32(GMIIControl, ctl);
+
+	mdelay(1);
+
+	for (i = 0; i < 100; i++) {
+		if (!(SIS_R32(GMIIControl) & EhnMIInotDone))
+			break;
+		mdelay(1);
+	}
+
+	if (i > 99)
+		DBG("sis190: PHY command timed out !\n");
+}
+
+static void mdio_write(void *ioaddr, int phy_id, int reg, int val)
+{
+	__mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite |
+		(((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) |
+		(((u32) val) << EhnMIIdataShift));
+}
+
+static int mdio_read(void *ioaddr, int phy_id, int reg)
+{
+	__mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread |
+		(((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift));
+
+	return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift);
+}
+
+static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+
+	mdio_write(tp->mmio_addr, phy_id, reg, val);
+}
+
+static int __mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+
+	return mdio_read(tp->mmio_addr, phy_id, reg);
+}
+
+static u16 mdio_read_latched(void *ioaddr, int phy_id, int reg)
+{
+	mdio_read(ioaddr, phy_id, reg);
+	return mdio_read(ioaddr, phy_id, reg);
+}
+
+static u16 sis190_read_eeprom(void *ioaddr, u32 reg)
+{
+	u16 data = 0xffff;
+	unsigned int i;
+
+	if (!(SIS_R32(ROMControl) & 0x0002))
+		return 0;
+
+	SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10));
+
+	for (i = 0; i < 200; i++) {
+		if (!(SIS_R32(ROMInterface) & EEREQ)) {
+			data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16;
+			break;
+		}
+		mdelay(1);
+	}
+
+	return data;
+}
+
+static void sis190_irq_mask_and_ack(void *ioaddr)
+{
+	SIS_W32(IntrMask, 0x00);
+	SIS_W32(IntrStatus, 0xffffffff);
+	SIS_PCI_COMMIT();
+}
+
+static void sis190_asic_down(void *ioaddr)
+{
+	/* Stop the chip's Tx and Rx DMA processes. */
+
+	SIS_W32(TxControl, 0x1a00);
+	SIS_W32(RxControl, 0x1a00);
+
+	sis190_irq_mask_and_ack(ioaddr);
+}
+
+static inline void sis190_mark_as_last_descriptor(struct RxDesc *desc)
+{
+	desc->size |= cpu_to_le32(RingEnd);
+}
+
+static inline void sis190_give_to_asic(struct RxDesc *desc)
+{
+	u32 eor = le32_to_cpu(desc->size) & RingEnd;
+
+	desc->PSize = 0x0;
+	desc->size = cpu_to_le32((RX_BUF_SIZE & RX_BUF_MASK) | eor);
+	wmb();
+	desc->status = cpu_to_le32(OWNbit | INTbit);
+}
+
+static inline void sis190_map_to_asic(struct RxDesc *desc, u32 mapping)
+{
+	desc->addr = cpu_to_le32(mapping);
+	sis190_give_to_asic(desc);
+}
+
+static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
+{
+	desc->PSize = 0x0;
+	desc->addr = cpu_to_le32(0xdeadbeef);
+	desc->size &= cpu_to_le32(RingEnd);
+	wmb();
+	desc->status = 0x0;
+}
+
+static struct io_buffer *sis190_alloc_rx_iob(struct RxDesc *desc)
+{
+	struct io_buffer *iob;
+
+	iob = alloc_iob(RX_BUF_SIZE);
+	if (iob) {
+		u32 mapping;
+
+		mapping = virt_to_bus(iob->data);
+		sis190_map_to_asic(desc, mapping);
+	} else {
+		DBG("sis190: alloc_iob failed\n");
+		sis190_make_unusable_by_asic(desc);
+	}
+
+	return iob;
+}
+
+static u32 sis190_rx_fill(struct sis190_private *tp, u32 start, u32 end)
+{
+	u32 cur;
+
+	for (cur = start; cur < end; cur++) {
+		unsigned int i = cur % NUM_RX_DESC;
+
+		if (tp->Rx_iobuf[i])
+			continue;
+
+		tp->Rx_iobuf[i] = sis190_alloc_rx_iob(tp->RxDescRing + i);
+
+		if (!tp->Rx_iobuf[i])
+			break;
+	}
+	return cur - start;
+}
+
+static inline int sis190_rx_pkt_err(u32 status)
+{
+#define ErrMask	(OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT)
+
+	if ((status & CRCOK) && !(status & ErrMask))
+		return 0;
+
+	return -1;
+}
+
+static int sis190_process_rx(struct sis190_private *tp)
+{
+	u32 rx_left, cur_rx = tp->cur_rx;
+	u32 delta, count;
+
+	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
+
+	for (; rx_left > 0; rx_left--, cur_rx++) {
+		unsigned int entry = cur_rx % NUM_RX_DESC;
+		struct RxDesc *desc = tp->RxDescRing + entry;
+		u32 status;
+
+		if (le32_to_cpu(desc->status) & OWNbit)
+			break;
+
+		status = le32_to_cpu(desc->PSize);
+
+		if (sis190_rx_pkt_err(status) < 0) {
+			sis190_give_to_asic(desc);
+		} else {
+			struct io_buffer *iob = tp->Rx_iobuf[entry];
+			unsigned int pkt_size = (status & RxSizeMask) - 4;
+
+			if (pkt_size > RX_BUF_SIZE) {
+				DBG("sis190: (frag) status = %08x.\n", status);
+				sis190_give_to_asic(desc);
+				continue;
+			}
+
+			sis190_make_unusable_by_asic(desc);
+
+			iob_put(iob, pkt_size);
+
+			DBG2("sis190: received packet. len: %d\n", pkt_size);
+			netdev_rx(tp->dev, iob);
+			DBGIO_HD(iob->data, 60);
+			tp->Rx_iobuf[entry] = NULL;
+		}
+	}
+	count = cur_rx - tp->cur_rx;
+	tp->cur_rx = cur_rx;
+
+	delta = sis190_rx_fill(tp, tp->dirty_rx, tp->cur_rx);
+	if (!delta && count)
+		DBG("sis190: no Rx buffer allocated.\n");
+	tp->dirty_rx += delta;
+
+	if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx))
+		DBG("sis190: Rx buffers exhausted.\n");
+
+	return count;
+}
+
+static inline int sis190_tx_pkt_err(u32 status)
+{
+#define TxErrMask (WND | TABRT | FIFO | LINK)
+
+	if (!(status & TxErrMask))
+		return 0;
+
+	return -1;
+}
+
+static void sis190_process_tx(struct sis190_private *tp)
+{
+	u32 pending, dirty_tx = tp->dirty_tx;
+
+	pending = tp->cur_tx - dirty_tx;
+
+	for (; pending; pending--, dirty_tx++) {
+		unsigned int entry = dirty_tx % NUM_TX_DESC;
+		struct TxDesc *txd = tp->TxDescRing + entry;
+		u32 status = le32_to_cpu(txd->status);
+		struct io_buffer *iob;
+
+		if (status & OWNbit)
+			break;
+
+		iob = tp->Tx_iobuf[entry];
+
+		if (!iob)
+			break;
+
+		if (sis190_tx_pkt_err(status) == 0) {
+			DBG2("sis190: Transmitted packet: %#08x\n", status);
+			netdev_tx_complete(tp->dev, iob);
+		} else {
+			DBG("sis190: Transmit error: %#08x\n", status);
+			netdev_tx_complete_err(tp->dev, iob, -EINVAL);
+		}
+
+		tp->Tx_iobuf[entry] = NULL;
+	}
+
+	if (tp->dirty_tx != dirty_tx)
+		tp->dirty_tx = dirty_tx;
+}
+
+/*
+ * The interrupt handler does all of the Rx thread work and cleans up after
+ * the Tx thread.
+ */
+static void sis190_poll(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void  *ioaddr = tp->mmio_addr;
+	u32 status;
+
+	status = SIS_R32(IntrStatus);
+
+	if ((status == 0xffffffff) || !status)
+		return;
+
+	SIS_W32(IntrStatus, status);
+
+	/* sis190_phy_task() needs to be called in event of a LinkChange and
+	 * after auto-negotiation is finished. Finishing auto-neg won't generate
+	 * any indication, hence we call it every time if the link is bad. */
+	if ((status & LinkChange) || !netdev_link_ok(dev))
+		sis190_phy_task(tp);
+
+	if (status & RxQInt)
+		sis190_process_rx(tp);
+
+	if (status & TxQ0Int)
+		sis190_process_tx(tp);
+}
+
+static inline void sis190_init_ring_indexes(struct sis190_private *tp)
+{
+	tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
+}
+
+static int sis190_init_ring(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+
+	sis190_init_ring_indexes(tp);
+
+	memset(tp->Tx_iobuf, 0, NUM_TX_DESC * sizeof(struct io_buffer *));
+	memset(tp->Rx_iobuf, 0, NUM_RX_DESC * sizeof(struct io_buffer *));
+
+	if (sis190_rx_fill(tp, 0, NUM_RX_DESC) != NUM_RX_DESC)
+		goto err;
+
+	sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1);
+
+	return 0;
+
+err:
+	sis190_free(dev);
+	return -ENOMEM;
+}
+
+static void sis190_set_rx_mode(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	u16 rx_mode;
+
+	rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
+	mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+	SIS_W16(RxMacControl, rx_mode | 0x2);
+	SIS_W32(RxHashTable, mc_filter[0]);
+	SIS_W32(RxHashTable + 4, mc_filter[1]);
+
+}
+
+static void sis190_soft_reset(void  *ioaddr)
+{
+	SIS_W32(IntrControl, 0x8000);
+	SIS_PCI_COMMIT();
+	SIS_W32(IntrControl, 0x0);
+	sis190_asic_down(ioaddr);
+}
+
+static void sis190_hw_start(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+
+	sis190_soft_reset(ioaddr);
+
+	SIS_W32(TxDescStartAddr, tp->tx_dma);
+	SIS_W32(RxDescStartAddr, tp->rx_dma);
+
+	SIS_W32(IntrStatus, 0xffffffff);
+	SIS_W32(IntrMask, 0x0);
+	SIS_W32(GMIIControl, 0x0);
+	SIS_W32(TxMacControl, 0x60);
+	SIS_W16(RxMacControl, 0x02);
+	SIS_W32(RxHashTable, 0x0);
+	SIS_W32(0x6c, 0x0);
+	SIS_W32(RxWolCtrl, 0x0);
+	SIS_W32(RxWolData, 0x0);
+
+	SIS_PCI_COMMIT();
+
+	sis190_set_rx_mode(dev);
+
+	SIS_W32(TxControl, 0x1a00 | CmdTxEnb);
+	SIS_W32(RxControl, 0x1a1d);
+}
+
+static void sis190_phy_task(struct sis190_private *tp)
+{
+	struct net_device *dev = tp->dev;
+	void *ioaddr = tp->mmio_addr;
+	int phy_id = tp->mii_if.phy_id;
+	int cnt = 0;
+	u16 val;
+
+	val = mdio_read(ioaddr, phy_id, MII_BMCR);
+
+	/* 100ms timeout is completely arbitrary. I have no datasheet to
+	 * check whether that's a sensible value or not.
+	 */
+	while ((val & BMCR_RESET) && (cnt < 100)) {
+		val = mdio_read(ioaddr, phy_id, MII_BMCR);
+		mdelay(1);
+		cnt++;
+	}
+
+	if (cnt > 99) {
+		DBG("sis190: BMCR_RESET timeout\n");
+		return;
+	}
+
+	if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
+		     BMSR_ANEGCOMPLETE)) {
+		DBG("sis190: auto-negotiating...\n");
+		netdev_link_down(dev);
+	} else {
+		/* Rejoice ! */
+		struct {
+			int val;
+			u32 ctl;
+			const char *msg;
+		} reg31[] = {
+			{ LPA_1000FULL, 0x07000c00 | 0x00001000,
+				"1000 Mbps Full Duplex" },
+			{ LPA_1000HALF, 0x07000c00,
+				"1000 Mbps Half Duplex" },
+			{ LPA_100FULL, 0x04000800 | 0x00001000,
+				"100 Mbps Full Duplex" },
+			{ LPA_100HALF, 0x04000800,
+				"100 Mbps Half Duplex" },
+			{ LPA_10FULL, 0x04000400 | 0x00001000,
+				"10 Mbps Full Duplex" },
+			{ LPA_10HALF, 0x04000400,
+				"10 Mbps Half Duplex" },
+			{ 0, 0x04000400, "unknown" }
+		}, *p = NULL;
+		u16 adv, autoexp, gigadv, gigrec;
+
+		val = mdio_read(ioaddr, phy_id, 0x1f);
+
+		val = mdio_read(ioaddr, phy_id, MII_LPA);
+		adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
+
+		autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION);
+
+		if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) {
+			/* check for gigabit speed */
+			gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000);
+			gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000);
+			val = (gigadv & (gigrec >> 2));
+			if (val & ADVERTISE_1000FULL)
+				p = reg31;
+			else if (val & ADVERTISE_1000HALF)
+				p = reg31 + 1;
+		}
+
+		if (!p) {
+			val &= adv;
+
+			for (p = reg31; p->val; p++) {
+				if ((val & p->val) == p->val)
+					break;
+			}
+		}
+
+		p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
+
+		if ((tp->features & F_HAS_RGMII) &&
+		    (tp->features & F_PHY_BCM5461)) {
+			// Set Tx Delay in RGMII mode.
+			mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
+			udelay(200);
+			mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
+			p->ctl |= 0x03000000;
+		}
+
+		SIS_W32(StationControl, p->ctl);
+
+		if (tp->features & F_HAS_RGMII) {
+			SIS_W32(RGDelay, 0x0441);
+			SIS_W32(RGDelay, 0x0440);
+		}
+
+		DBG("sis190: link on %s mode.\n", p->msg);
+		netdev_link_up(dev);
+	}
+}
+
+static int sis190_open(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	int rc;
+
+	/* Allocate TX ring */
+	tp->TxDescRing = malloc_dma(TX_RING_BYTES, RING_ALIGNMENT);
+	if (!tp->TxDescRing) {
+		DBG("sis190: TX ring allocation failed\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	tp->tx_dma = cpu_to_le32(virt_to_bus(tp->TxDescRing));
+
+	/* Allocate RX ring */
+	tp->RxDescRing = malloc_dma(RX_RING_BYTES, RING_ALIGNMENT);
+	if (!tp->RxDescRing) {
+		DBG("sis190: RX ring allocation failed\n");
+		rc = -ENOMEM;
+		goto error;
+	}
+	tp->rx_dma = cpu_to_le32(virt_to_bus(tp->RxDescRing));
+
+	rc = sis190_init_ring(dev);
+	if (rc < 0)
+		goto error;
+
+	/* init rx filter, also program MAC address to card */
+	sis190_init_rxfilter(dev);
+
+	sis190_hw_start(dev);
+out:
+	return rc;
+
+error:
+	sis190_free(dev);
+	goto out;
+}
+
+static void sis190_down(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void  *ioaddr = tp->mmio_addr;
+
+	do {
+		sis190_asic_down(ioaddr);
+	} while (SIS_R32(IntrMask));
+}
+
+static void sis190_free(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	int i;
+
+	free_dma(tp->TxDescRing, TX_RING_BYTES);
+	free_dma(tp->RxDescRing, RX_RING_BYTES);
+
+	tp->TxDescRing = NULL;
+	tp->RxDescRing = NULL;
+
+	tp->tx_dma = 0;
+	tp->rx_dma = 0;
+
+	tp->cur_tx = tp->dirty_tx = 0;
+	tp->cur_rx = tp->dirty_rx = 0;
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		free_iob(tp->Rx_iobuf[i]);
+		tp->Rx_iobuf[i] = NULL;
+	}
+
+	/* tx io_buffers aren't owned by the driver, so don't free them */
+	for(i = 0; i < NUM_TX_DESC; i++)
+		tp->Tx_iobuf[i] = NULL;
+}
+
+static void sis190_close(struct net_device *dev)
+{
+	sis190_down(dev);
+	sis190_free(dev);
+}
+
+static int sis190_transmit(struct net_device *dev, struct io_buffer *iob)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void  *ioaddr = tp->mmio_addr;
+	u32 len, entry;
+	struct TxDesc *desc;
+
+	len = iob_len(iob);
+	if (len < ETH_ZLEN) {
+		iob_pad(iob, ETH_ZLEN);
+		len = ETH_ZLEN;
+	}
+
+	entry = tp->cur_tx % NUM_TX_DESC;
+	desc = tp->TxDescRing + entry;
+
+	if (le32_to_cpu(desc->status) & OWNbit) {
+		DBG("sis190: Tx Ring full\n");
+		return -EINVAL;
+	}
+
+	tp->Tx_iobuf[entry] = iob;
+
+	desc->PSize = cpu_to_le32(len);
+	desc->addr = cpu_to_le32(virt_to_bus(iob->data));
+
+	desc->size = cpu_to_le32(len);
+	if (entry == (NUM_TX_DESC - 1))
+		desc->size |= cpu_to_le32(RingEnd);
+
+	wmb();
+
+	desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
+
+	tp->cur_tx++;
+
+	SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb);
+
+	return 0;
+}
+
+static void sis190_free_phy(struct list_head *first_phy)
+{
+	struct sis190_phy *cur, *next;
+
+	list_for_each_entry_safe(cur, next, first_phy, list) {
+		free(cur);
+	}
+}
+
+/**
+ *	sis190_default_phy - Select default PHY for sis190 mac.
+ *	@dev: the net device to probe for
+ *
+ *	Select first detected PHY with link as default.
+ *	If no one is link on, select PHY whose types is HOME as default.
+ *	If HOME doesn't exist, select LAN.
+ */
+static u16 sis190_default_phy(struct sis190_private *tp)
+{
+	struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan;
+	struct mii_if_info *mii_if = &tp->mii_if;
+	void  *ioaddr = tp->mmio_addr;
+	u16 status;
+
+	phy_home = phy_default = phy_lan = NULL;
+
+	list_for_each_entry(phy, &tp->first_phy, list) {
+		status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR);
+
+		// Link ON & Not select default PHY & not ghost PHY.
+		if ((status & BMSR_LSTATUS) &&
+		    !phy_default &&
+		    (phy->type != UNKNOWN)) {
+			phy_default = phy;
+		} else {
+			status = mdio_read(ioaddr, phy->phy_id, MII_BMCR);
+			mdio_write(ioaddr, phy->phy_id, MII_BMCR,
+				   status | BMCR_ANENABLE | BMCR_ISOLATE);
+			if (phy->type == HOME)
+				phy_home = phy;
+			else if (phy->type == LAN)
+				phy_lan = phy;
+		}
+	}
+
+	if (!phy_default) {
+		if (phy_home)
+			phy_default = phy_home;
+		else if (phy_lan)
+			phy_default = phy_lan;
+		else
+			phy_default = list_entry(&tp->first_phy,
+						 struct sis190_phy, list);
+	}
+
+	if (mii_if->phy_id != phy_default->phy_id) {
+		mii_if->phy_id = phy_default->phy_id;
+		DBG("sis190: Using transceiver at address %d as default.\n",
+		     mii_if->phy_id);
+	}
+
+	status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR);
+	status &= (~BMCR_ISOLATE);
+
+	mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status);
+	status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR);
+
+	return status;
+}
+
+static void sis190_init_phy(struct sis190_private *tp,
+			    struct sis190_phy *phy, unsigned int phy_id,
+			    u16 mii_status)
+{
+	void *ioaddr = tp->mmio_addr;
+	struct mii_chip_info *p;
+
+	INIT_LIST_HEAD(&phy->list);
+	phy->status = mii_status;
+	phy->phy_id = phy_id;
+
+	phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1);
+	phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2);
+
+	for (p = mii_chip_table; p->type; p++) {
+		if ((p->id[0] == phy->id[0]) &&
+		    (p->id[1] == (phy->id[1] & 0xfff0))) {
+			break;
+		}
+	}
+
+	if (p->id[1]) {
+		phy->type = (p->type == MIX) ?
+			((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
+				LAN : HOME) : p->type;
+		tp->features |= p->feature;
+
+		DBG("sis190: %s transceiver at address %d.\n", p->name, phy_id);
+	} else {
+		phy->type = UNKNOWN;
+
+		DBG("sis190: unknown PHY 0x%x:0x%x transceiver at address %d\n",
+		    phy->id[0], (phy->id[1] & 0xfff0), phy_id);
+	}
+}
+
+static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
+{
+	if (tp->features & F_PHY_88E1111) {
+		void *ioaddr = tp->mmio_addr;
+		int phy_id = tp->mii_if.phy_id;
+		u16 reg[2][2] = {
+			{ 0x808b, 0x0ce1 },
+			{ 0x808f, 0x0c60 }
+		}, *p;
+
+		p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
+
+		mdio_write(ioaddr, phy_id, 0x1b, p[0]);
+		udelay(200);
+		mdio_write(ioaddr, phy_id, 0x14, p[1]);
+		udelay(200);
+	}
+}
+
+/**
+ *	sis190_mii_probe - Probe MII PHY for sis190
+ *	@dev: the net device to probe for
+ *
+ *	Search for total of 32 possible mii phy addresses.
+ *	Identify and set current phy if found one,
+ *	return error if it failed to found.
+ */
+static int sis190_mii_probe(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	struct mii_if_info *mii_if = &tp->mii_if;
+	void *ioaddr = tp->mmio_addr;
+	int phy_id;
+	int rc = 0;
+
+	INIT_LIST_HEAD(&tp->first_phy);
+
+	for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+		struct sis190_phy *phy;
+		u16 status;
+
+		status = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
+
+		// Try next mii if the current one is not accessible.
+		if (status == 0xffff || status == 0x0000)
+			continue;
+
+		phy = zalloc(sizeof(*phy));
+		if (!phy) {
+			sis190_free_phy(&tp->first_phy);
+			rc = -ENOMEM;
+			goto out;
+		}
+
+		DBG("sis190: found PHY\n");
+
+		sis190_init_phy(tp, phy, phy_id, status);
+
+		list_add(&tp->first_phy, &phy->list);
+	}
+
+	if (list_empty(&tp->first_phy)) {
+		DBG("sis190: No MII transceivers found!\n");
+		rc = -EIO;
+		goto out;
+	}
+
+	/* Select default PHY for mac */
+	sis190_default_phy(tp);
+
+	sis190_mii_probe_88e1111_fixup(tp);
+
+	mii_if->dev = dev;
+	mii_if->mdio_read = __mdio_read;
+	mii_if->mdio_write = __mdio_write;
+	mii_if->phy_id_mask = PHY_ID_ANY;
+	mii_if->reg_num_mask = MII_REG_ANY;
+out:
+	return rc;
+}
+
+static void sis190_mii_remove(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+
+	sis190_free_phy(&tp->first_phy);
+}
+
+static int sis190_init_board(struct pci_device *pdev, struct net_device **netdev)
+{
+	struct sis190_private *tp;
+	struct net_device *dev;
+	void *ioaddr;
+	int rc;
+
+	dev = alloc_etherdev(sizeof(*tp));
+	if (!dev) {
+		DBG("sis190: unable to alloc new etherdev\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	dev->dev = &pdev->dev;
+
+	tp = netdev_priv(dev);
+	memset(tp, 0, sizeof(*tp));
+
+	tp->dev = dev;
+
+	adjust_pci_device(pdev);
+
+	ioaddr = ioremap(pdev->membase, SIS190_REGS_SIZE);
+	if (!ioaddr) {
+		DBG("sis190: cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err;
+	}
+
+	tp->pci_device = pdev;
+	tp->mmio_addr = ioaddr;
+
+	sis190_irq_mask_and_ack(ioaddr);
+
+	sis190_soft_reset(ioaddr);
+
+	*netdev = dev;
+
+	return 0;
+
+err:
+	return rc;
+}
+
+static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
+{
+	tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
+}
+
+static int sis190_get_mac_addr_from_eeprom(struct pci_device *pdev __unused,
+						     struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u16 sig;
+	int i;
+
+	DBG("sis190: Read MAC address from EEPROM\n");
+
+	/* Check to see if there is a sane EEPROM */
+	sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature);
+
+	if ((sig == 0xffff) || (sig == 0x0000)) {
+		DBG("sis190: Error EEPROM read.\n");
+		return -EIO;
+	}
+
+	/* Get MAC address from EEPROM */
+	for (i = 0; i < ETH_ALEN / 2; i++) {
+		u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
+
+		((u16 *)dev->hw_addr)[i] = cpu_to_le16(w);
+	}
+
+	sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
+
+	return 0;
+}
+
+/**
+ *	sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
+ *	@pdev: PCI device
+ *	@dev:  network device to get address for
+ *
+ *	SiS96x model, use APC CMOS RAM to store MAC address.
+ *	APC CMOS RAM is accessed through ISA bridge.
+ *	MAC address is read into @net_dev->dev_addr.
+ */
+static int sis190_get_mac_addr_from_apc(struct pci_device *pdev,
+					struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	struct pci_device *isa_bridge = NULL;
+	struct device *d;
+	u8 reg, tmp8;
+	unsigned int i;
+
+	DBG("sis190: Read MAC address from APC.\n");
+
+	list_for_each_entry(d, &(pdev->dev.siblings), siblings) {
+		unsigned int i;
+		isa_bridge = container_of(d, struct pci_device, dev);
+		for(i = 0; i < sis190_isa_bridge_driver.id_count; i++) {
+			if(isa_bridge->vendor ==
+			     sis190_isa_bridge_driver.ids[i].vendor
+			     && isa_bridge->device ==
+			     sis190_isa_bridge_driver.ids[i].device) {
+				DBG("sis190: ISA bridge found\n");
+				break;
+			} else {
+				isa_bridge = NULL;
+			}
+		}
+		if(isa_bridge)
+			break;
+	}
+
+	if (!isa_bridge) {
+		DBG("sis190: Can not find ISA bridge.\n");
+		return -EIO;
+	}
+
+	/* Enable port 78h & 79h to access APC Registers. */
+	pci_read_config_byte(isa_bridge, 0x48, &tmp8);
+	reg = (tmp8 & ~0x02);
+	pci_write_config_byte(isa_bridge, 0x48, reg);
+	udelay(50);
+	pci_read_config_byte(isa_bridge, 0x48, &reg);
+
+        for (i = 0; i < ETH_ALEN; i++) {
+                outb(0x9 + i, 0x78);
+                dev->hw_addr[i] = inb(0x79);
+        }
+
+	outb(0x12, 0x78);
+	reg = inb(0x79);
+
+	sis190_set_rgmii(tp, reg);
+
+	/* Restore the value to ISA Bridge */
+	pci_write_config_byte(isa_bridge, 0x48, tmp8);
+
+	return 0;
+}
+
+/**
+ *      sis190_init_rxfilter - Initialize the Rx filter
+ *      @dev: network device to initialize
+ *
+ *      Set receive filter address to our MAC address
+ *      and enable packet filtering.
+ */
+static inline void sis190_init_rxfilter(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u16 ctl;
+	int i;
+
+	ctl = SIS_R16(RxMacControl);
+	/*
+	 * Disable packet filtering before setting filter.
+	 * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits
+	 * only and followed by RxMacAddr (6 bytes). Strange. -- FR
+	 */
+	SIS_W16(RxMacControl, ctl & ~0x0f00);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		SIS_W8(RxMacAddr + i, dev->ll_addr[i]);
+
+	SIS_W16(RxMacControl, ctl);
+	SIS_PCI_COMMIT();
+}
+
+static int sis190_get_mac_addr(struct pci_device *pdev,
+					 struct net_device *dev)
+{
+	int rc;
+
+	rc = sis190_get_mac_addr_from_eeprom(pdev, dev);
+	if (rc < 0) {
+		u8 reg;
+
+		pci_read_config_byte(pdev, 0x73, &reg);
+
+		if (reg & 0x00000001)
+			rc = sis190_get_mac_addr_from_apc(pdev, dev);
+	}
+	return rc;
+}
+
+static void sis190_set_speed_auto(struct net_device *dev)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int phy_id = tp->mii_if.phy_id;
+	int val;
+
+	DBG("sis190: Enabling Auto-negotiation.\n");
+
+	val = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
+
+	// Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0
+	// unchanged.
+	mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) |
+		   ADVERTISE_100FULL | ADVERTISE_10FULL |
+		   ADVERTISE_100HALF | ADVERTISE_10HALF);
+
+	// Enable 1000 Full Mode.
+	mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL);
+
+	// Enable auto-negotiation and restart auto-negotiation.
+	mdio_write(ioaddr, phy_id, MII_BMCR,
+		   BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET);
+}
+
+static void sis190_irq(struct net_device *dev, int enable)
+{
+	struct sis190_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+
+	SIS_W32(IntrStatus, 0xffffffff);
+
+	if (enable == 0)
+		SIS_W32(IntrMask, 0x00);
+	else
+		SIS_W32(IntrMask, sis190_intr_mask);
+
+	SIS_PCI_COMMIT();
+}
+
+static struct net_device_operations sis190_netdev_ops = {
+	.open = sis190_open,
+	.close = sis190_close,
+	.poll = sis190_poll,
+	.transmit = sis190_transmit,
+	.irq = sis190_irq,
+};
+
+static int sis190_probe(struct pci_device *pdev)
+{
+	struct sis190_private *tp;
+	struct net_device *dev;
+	int rc;
+
+	rc = sis190_init_board(pdev, &dev);
+	if (rc < 0)
+		goto out;
+	netdev_init(dev, &sis190_netdev_ops);
+
+	pci_set_drvdata(pdev, dev);
+
+	tp = netdev_priv(dev);
+
+	rc = sis190_get_mac_addr(pdev, dev);
+	if (rc < 0)
+		goto err;
+
+	rc = sis190_mii_probe(dev);
+	if (rc < 0)
+		goto err;
+
+	rc = register_netdev(dev);
+	if (rc < 0)
+		goto err;
+
+	sis190_set_speed_auto(dev);
+	sis190_phy_task(tp);
+
+out:
+	return rc;
+
+err:
+	sis190_mii_remove(dev);
+	iounmap(tp->mmio_addr);
+	goto out;
+}
+
+static void sis190_remove(struct pci_device *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct sis190_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+
+	sis190_mii_remove(dev);
+
+	/* shutdown chip, disable interrupts, etc */
+	sis190_soft_reset(ioaddr);
+
+	iounmap(tp->mmio_addr);
+
+	unregister_netdev(dev);
+	netdev_nullify(dev);
+	netdev_put(dev);
+}
+
+struct pci_driver sis190_pci_driver __pci_driver = {
+	.ids		= sis190_pci_tbl,
+	.id_count	= (sizeof(sis190_pci_tbl) / sizeof(sis190_pci_tbl[0])),
+	.probe		= sis190_probe,
+	.remove		= sis190_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.h
new file mode 100644
index 0000000..fc6cb4b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis190.h
@@ -0,0 +1,311 @@
+#ifndef __SIS190_H__
+#define __SIS190_H__
+
+FILE_LICENCE ( GPL_ANY );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <mii.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/io.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/timer.h>
+
+#define PCI_VENDOR_ID_SI	0x1039
+
+#define PHY_MAX_ADDR		32
+#define PHY_ID_ANY		0x1f
+#define MII_REG_ANY		0x1f
+
+#define DRV_VERSION		"1.3"
+#define DRV_NAME		"sis190"
+#define SIS190_DRIVER_NAME	DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
+
+#define sis190_rx_quota(count, quota)	count
+
+#define NUM_TX_DESC		8	/* [8..1024] */
+#define NUM_RX_DESC		8	/* [8..8192] */
+#define TX_RING_BYTES		(NUM_TX_DESC * sizeof(struct TxDesc))
+#define RX_RING_BYTES		(NUM_RX_DESC * sizeof(struct RxDesc))
+#define RX_BUF_SIZE		1536
+#define RX_BUF_MASK		0xfff8
+
+#define RING_ALIGNMENT		256
+
+#define SIS190_REGS_SIZE	0x80
+
+/* Enhanced PHY access register bit definitions */
+#define EhnMIIread		0x0000
+#define EhnMIIwrite		0x0020
+#define EhnMIIdataShift		16
+#define EhnMIIpmdShift		6	/* 7016 only */
+#define EhnMIIregShift		11
+#define EhnMIIreq		0x0010
+#define EhnMIInotDone		0x0010
+
+/* Write/read MMIO register */
+#define SIS_W8(reg, val)	writeb ((val), ioaddr + (reg))
+#define SIS_W16(reg, val)	writew ((val), ioaddr + (reg))
+#define SIS_W32(reg, val)	writel ((val), ioaddr + (reg))
+#define SIS_R8(reg)		readb (ioaddr + (reg))
+#define SIS_R16(reg)		readw (ioaddr + (reg))
+#define SIS_R32(reg)		readl (ioaddr + (reg))
+
+#define SIS_PCI_COMMIT()	SIS_R32(IntrControl)
+
+enum sis190_registers {
+	TxControl		= 0x00,
+	TxDescStartAddr		= 0x04,
+	rsv0			= 0x08,	// reserved
+	TxSts			= 0x0c,	// unused (Control/Status)
+	RxControl		= 0x10,
+	RxDescStartAddr		= 0x14,
+	rsv1			= 0x18,	// reserved
+	RxSts			= 0x1c,	// unused
+	IntrStatus		= 0x20,
+	IntrMask		= 0x24,
+	IntrControl		= 0x28,
+	IntrTimer		= 0x2c,	// unused (Interupt Timer)
+	PMControl		= 0x30,	// unused (Power Mgmt Control/Status)
+	rsv2			= 0x34,	// reserved
+	ROMControl		= 0x38,
+	ROMInterface		= 0x3c,
+	StationControl		= 0x40,
+	GMIIControl		= 0x44,
+	GIoCR			= 0x48, // unused (GMAC IO Compensation)
+	GIoCtrl			= 0x4c, // unused (GMAC IO Control)
+	TxMacControl		= 0x50,
+	TxLimit			= 0x54, // unused (Tx MAC Timer/TryLimit)
+	RGDelay			= 0x58, // unused (RGMII Tx Internal Delay)
+	rsv3			= 0x5c, // reserved
+	RxMacControl		= 0x60,
+	RxMacAddr		= 0x62,
+	RxHashTable		= 0x68,
+	// Undocumented		= 0x6c,
+	RxWolCtrl		= 0x70,
+	RxWolData		= 0x74, // unused (Rx WOL Data Access)
+	RxMPSControl		= 0x78,	// unused (Rx MPS Control)
+	rsv4			= 0x7c, // reserved
+};
+
+enum sis190_register_content {
+	/* IntrStatus */
+	SoftInt			= 0x40000000,	// unused
+	Timeup			= 0x20000000,	// unused
+	PauseFrame		= 0x00080000,	// unused
+	MagicPacket		= 0x00040000,	// unused
+	WakeupFrame		= 0x00020000,	// unused
+	LinkChange		= 0x00010000,
+	RxQEmpty		= 0x00000080,
+	RxQInt			= 0x00000040,
+	TxQ1Empty		= 0x00000020,	// unused
+	TxQ1Int			= 0x00000010,
+	TxQ0Empty		= 0x00000008,	// unused
+	TxQ0Int			= 0x00000004,
+	RxHalt			= 0x00000002,
+	TxHalt			= 0x00000001,
+
+	/* {Rx/Tx}CmdBits */
+	CmdReset		= 0x10,
+	CmdRxEnb		= 0x08,		// unused
+	CmdTxEnb		= 0x01,
+	RxBufEmpty		= 0x01,		// unused
+
+	/* Cfg9346Bits */
+	Cfg9346_Lock		= 0x00,		// unused
+	Cfg9346_Unlock		= 0xc0,		// unused
+
+	/* RxMacControl */
+	AcceptErr		= 0x20,		// unused
+	AcceptRunt		= 0x10,		// unused
+	AcceptBroadcast		= 0x0800,
+	AcceptMulticast		= 0x0400,
+	AcceptMyPhys		= 0x0200,
+	AcceptAllPhys		= 0x0100,
+
+	/* RxConfigBits */
+	RxCfgFIFOShift		= 13,
+	RxCfgDMAShift		= 8,		// 0x1a in RxControl ?
+
+	/* TxConfigBits */
+	TxInterFrameGapShift	= 24,
+	TxDMAShift		= 8, /* DMA burst value (0-7) is shift this many bits */
+
+	LinkStatus		= 0x02,		// unused
+	FullDup			= 0x01,		// unused
+
+	/* TBICSRBit */
+	TBILinkOK		= 0x02000000,	// unused
+};
+
+struct TxDesc {
+	volatile u32 PSize;
+	volatile u32 status;
+	volatile u32 addr;
+	volatile u32 size;
+};
+
+struct RxDesc {
+	volatile u32 PSize;
+	volatile u32 status;
+	volatile u32 addr;
+	volatile u32 size;
+};
+
+enum _DescStatusBit {
+	/* _Desc.status */
+	OWNbit		= 0x80000000, // RXOWN/TXOWN
+	INTbit		= 0x40000000, // RXINT/TXINT
+	CRCbit		= 0x00020000, // CRCOFF/CRCEN
+	PADbit		= 0x00010000, // PREADD/PADEN
+	/* _Desc.size */
+	RingEnd		= 0x80000000,
+	/* TxDesc.status */
+	LSEN		= 0x08000000, // TSO ? -- FR
+	IPCS		= 0x04000000,
+	TCPCS		= 0x02000000,
+	UDPCS		= 0x01000000,
+	BSTEN		= 0x00800000,
+	EXTEN		= 0x00400000,
+	DEFEN		= 0x00200000,
+	BKFEN		= 0x00100000,
+	CRSEN		= 0x00080000,
+	COLEN		= 0x00040000,
+	THOL3		= 0x30000000,
+	THOL2		= 0x20000000,
+	THOL1		= 0x10000000,
+	THOL0		= 0x00000000,
+
+	WND		= 0x00080000,
+	TABRT		= 0x00040000,
+	FIFO		= 0x00020000,
+	LINK		= 0x00010000,
+	ColCountMask	= 0x0000ffff,
+	/* RxDesc.status */
+	IPON		= 0x20000000,
+	TCPON		= 0x10000000,
+	UDPON		= 0x08000000,
+	Wakup		= 0x00400000,
+	Magic		= 0x00200000,
+	Pause		= 0x00100000,
+	DEFbit		= 0x00200000,
+	BCAST		= 0x000c0000,
+	MCAST		= 0x00080000,
+	UCAST		= 0x00040000,
+	/* RxDesc.PSize */
+	TAGON		= 0x80000000,
+	RxDescCountMask	= 0x7f000000, // multi-desc pkt when > 1 ? -- FR
+	ABORT		= 0x00800000,
+	SHORT		= 0x00400000,
+	LIMIT		= 0x00200000,
+	MIIER		= 0x00100000,
+	OVRUN		= 0x00080000,
+	NIBON		= 0x00040000,
+	COLON		= 0x00020000,
+	CRCOK		= 0x00010000,
+	RxSizeMask	= 0x0000ffff
+	/*
+	* The asic could apparently do vlan, TSO, jumbo (sis191 only) and
+	* provide two (unused with Linux) Tx queues. No publically
+	* available documentation alas.
+	*/
+};
+
+enum sis190_eeprom_access_register_bits {
+	EECS	= 0x00000001,	// unused
+	EECLK	= 0x00000002,	// unused
+	EEDO	= 0x00000008,	// unused
+	EEDI	= 0x00000004,	// unused
+	EEREQ	= 0x00000080,
+	EEROP	= 0x00000200,
+	EEWOP	= 0x00000100	// unused
+};
+
+/* EEPROM Addresses */
+enum sis190_eeprom_address {
+	EEPROMSignature	= 0x00,
+	EEPROMCLK	= 0x01,	// unused
+	EEPROMInfo	= 0x02,
+	EEPROMMACAddr	= 0x03
+};
+
+enum sis190_feature {
+	F_HAS_RGMII	= 1,
+	F_PHY_88E1111	= 2,
+	F_PHY_BCM5461	= 4
+};
+
+struct sis190_private {
+	void *mmio_addr;
+	struct pci_device *pci_device;
+	struct net_device *dev;
+	u32 cur_rx;
+	u32 cur_tx;
+	u32 dirty_rx;
+	u32 dirty_tx;
+	u32 rx_dma;
+	u32 tx_dma;
+	struct RxDesc *RxDescRing;
+	struct TxDesc *TxDescRing;
+	struct io_buffer *Rx_iobuf[NUM_RX_DESC];
+	struct io_buffer *Tx_iobuf[NUM_TX_DESC];
+	struct mii_if_info mii_if;
+	struct list_head first_phy;
+	u32 features;
+};
+
+struct sis190_phy {
+	struct list_head list;
+	int phy_id;
+	u16 id[2];
+	u16 status;
+	u8  type;
+};
+
+enum sis190_phy_type {
+	UNKNOWN	= 0x00,
+	HOME	= 0x01,
+	LAN	= 0x02,
+	MIX	= 0x03
+};
+
+static struct mii_chip_info {
+	const char *name;
+	u16 id[2];
+	unsigned int type;
+	u32 feature;
+} mii_chip_table[] = {
+	{ "Atheros PHY",          { 0x004d, 0xd010 }, LAN, 0 },
+	{ "Atheros PHY AR8012",   { 0x004d, 0xd020 }, LAN, 0 },
+	{ "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
+	{ "Broadcom PHY AC131",   { 0x0143, 0xbc70 }, LAN, 0 },
+	{ "Agere PHY ET1101B",    { 0x0282, 0xf010 }, LAN, 0 },
+	{ "Marvell PHY 88E1111",  { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 },
+	{ "Realtek PHY RTL8201",  { 0x0000, 0x8200 }, LAN, 0 },
+	{ NULL, { 0x00, 0x00 }, 0, 0 }
+};
+
+static const struct {
+	const char *name;
+} sis_chip_info[] = {
+	{ "SiS 190 PCI Fast Ethernet adapter" },
+	{ "SiS 191 PCI Gigabit Ethernet adapter" },
+};
+
+static void sis190_phy_task(struct sis190_private *tp);
+static void sis190_free(struct net_device *dev);
+static inline void sis190_init_rxfilter(struct net_device *dev);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.c
new file mode 100644
index 0000000..92eb5ce
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.c
@@ -0,0 +1,1303 @@
+/* -*- Mode:C; c-basic-offset:4; -*- */
+
+/* 
+   sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot
+   Copyright (C) 2001 Entity Cyber, Inc.
+
+   Revision:	1.0	March 1, 2001
+   
+   Author: Marty Connor (mdc at etherboot.org)
+
+   Adapted from a Linux driver which was written by Donald Becker
+   and modified by Ollie Lho and Chin-Shan Li of SiS Corporation.
+   Rewritten for Etherboot by Marty Connor.
+   
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+   
+   References:
+   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+   preliminary Rev. 1.0 Jan. 14, 1998
+   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+   preliminary Rev. 1.0 Nov. 10, 1998
+   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+   preliminary Rev. 1.0 Jan. 18, 1998
+   http://www.sis.com.tw/support/databook.htm */
+
+FILE_LICENCE ( GPL_ANY );
+
+/* Revision History */
+
+/*
+  07 Dec 2003  timlegge - Enabled Multicast Support
+  06 Dec 2003  timlegge - Fixed relocation issue in 5.2
+  04 Jan 2002  Chien-Yu Chen, Doug Ambrisko, Marty Connor  Patch to Etherboot 5.0.5
+     Added support for the SiS 630ET plus various bug fixes from linux kernel
+     source 2.4.17.
+  01 March 2001  mdc     1.0
+     Initial Release.  Tested with PCI based sis900 card and ThinkNIC
+     computer.
+  20 March 2001 P.Koegel
+     added support for sis630e and PHY ICS1893 and RTL8201
+     Testet with SIS730S chipset + ICS1893
+*/
+
+
+/* Includes */
+
+#include "etherboot.h"
+#include <ipxe/pci.h>
+#include "nic.h"
+
+#include "sis900.h"
+
+/* Globals */
+
+static struct nic_operations sis900_operations;
+
+static int sis900_debug = 0;
+
+static unsigned short vendor, dev_id;
+static unsigned long ioaddr;
+static u8 pci_revision;
+
+static unsigned int cur_phy;
+
+static unsigned int cur_rx;
+
+struct {
+    BufferDesc txd;
+    BufferDesc rxd[NUM_RX_DESC];
+    unsigned char txb[TX_BUF_SIZE];
+    unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
+} sis900_bufs __shared;
+#define txd sis900_bufs.txd
+#define rxd sis900_bufs.rxd
+#define txb sis900_bufs.txb
+#define rxb sis900_bufs.rxb
+
+#if 0
+static struct mac_chip_info {
+    const char *name;
+    u16 vendor_id, device_id, flags;
+    int io_size;
+} mac_chip_table[] = {
+    { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
+      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
+    { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
+      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
+    {0,0,0,0,0} /* 0 terminated list. */
+};
+#endif
+
+static void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
+static void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
+static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
+static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
+static void vt6103_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
+
+static struct mii_chip_info {
+    const char * name;
+    u16 phy_id0;
+    u16 phy_id1;
+    void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex);
+} mii_chip_table[] = {
+    {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
+    {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
+    {"SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, sis900_read_mode},
+    {"AMD 79C901 10BASE-T PHY",  0x0000, 0x6B70, amd79c901_read_mode},
+    {"AMD 79C901 HomePNA PHY",   0x0000, 0x6B90, amd79c901_read_mode},
+    {"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf440,ics1893_read_mode},
+//  {"NS 83851 PHY",0x2000, 0x5C20, MIX },
+    {"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8200,rtl8201_read_mode},
+    {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode},
+    {0,0,0,0}
+};
+
+static struct mii_phy {
+    struct mii_phy * next;
+    struct mii_chip_info * chip_info;
+    int phy_addr;
+    u16 status;
+} mii;
+
+
+
+#if 0
+// PCI to ISA bridge for SIS640E access
+static struct pci_device_id pci_isa_bridge_list[] = {
+	{ .vendor = 0x1039, .device = 0x0008,
+		.name = "SIS 85C503/5513 PCI to ISA bridge"},
+};
+
+PCI_DRIVER( sis_bridge_pci_driver, pci_isa_bridge_list, PCI_NO_CLASS );
+
+static struct device_driver sis_bridge_driver = {
+    .name = "SIS ISA bridge",
+    .bus_driver = &pci_driver,
+    .bus_driver_info = ( struct bus_driver_info * ) &sis_bridge_pci_driver,
+};
+#endif
+
+/* Function Prototypes */
+
+static int sis900_probe(struct nic *nic,struct pci_device *pci);
+
+static u16  sis900_read_eeprom(int location);
+static void sis900_mdio_reset(long mdio_addr);
+static void sis900_mdio_idle(long mdio_addr);
+static u16  sis900_mdio_read(int phy_id, int location);
+#if 0
+static void sis900_mdio_write(int phy_id, int location, int val);
+#endif
+static void sis900_init(struct nic *nic);
+
+static void sis900_reset(struct nic *nic);
+
+static void sis900_init_rxfilter(struct nic *nic);
+static void sis900_init_txd(struct nic *nic);
+static void sis900_init_rxd(struct nic *nic);
+static void sis900_set_rx_mode(struct nic *nic);
+static void sis900_check_mode(struct nic *nic);
+
+static void sis900_transmit(struct nic *nic, const char *d, 
+                            unsigned int t, unsigned int s, const char *p);
+static int  sis900_poll(struct nic *nic, int retrieve);
+
+static void sis900_disable(struct nic *nic);
+
+static void sis900_irq(struct nic *nic, irq_action_t action);
+
+/**
+ *	sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
+ *	@pci_dev: the sis900 pci device
+ *	@net_dev: the net device to get address for
+ *
+ *	Older SiS900 and friends, use EEPROM to store MAC address.
+ *	MAC address is read from read_eeprom() into @net_dev->dev_addr.
+ */
+
+static int sis900_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
+{
+	u16 signature;
+	int i;
+
+	/* check to see if we have sane EEPROM */
+	signature = (u16) sis900_read_eeprom( EEPROMSignature);
+	if (signature == 0xffff || signature == 0x0000) {
+		printf ("sis900_probe: Error EERPOM read %hX\n", signature);
+		return 0;
+	}
+
+	/* get MAC address from EEPROM */
+	for (i = 0; i < 3; i++)
+			((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
+	return 1;
+}
+
+/**
+ *	sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
+ *	@pci_dev: the sis900 pci device
+ *	@net_dev: the net device to get address for 
+ *
+ *	SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM 
+ *	is shared by
+ *	LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
+ *	and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
+ *	by LAN, otherwise is not. After MAC address is read from EEPROM, send
+ *	EEDONE signal to refuse EEPROM access by LAN. 
+ *	The EEPROM map of SiS962 or SiS963 is different to SiS900. 
+ *	The signature field in SiS962 or SiS963 spec is meaningless. 
+ *	MAC address is read into @net_dev->dev_addr.
+ */
+
+static int sis96x_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
+{
+/* 	long ioaddr = net_dev->base_addr; */
+	long ee_addr = ioaddr + mear;
+	u32 waittime = 0;
+	int i;
+	
+	printf("Alternate function\n");
+
+	outl(EEREQ, ee_addr);
+	while(waittime < 2000) {
+		if(inl(ee_addr) & EEGNT) {
+
+			/* get MAC address from EEPROM */
+			for (i = 0; i < 3; i++)
+			        ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
+
+			outl(EEDONE, ee_addr);
+			return 1;
+		} else {
+			udelay(1);	
+			waittime ++;
+		}
+	}
+	outl(EEDONE, ee_addr);
+	return 0;
+}
+
+/**
+ *	sis630e_get_mac_addr: - Get MAC address for SiS630E model
+ *	@pci_dev: the sis900 pci device
+ *	@net_dev: the net device to get address for
+ *
+ *	SiS630E model, use APC CMOS RAM to store MAC address.
+ *	APC CMOS RAM is accessed through ISA bridge.
+ *	MAC address is read into @net_dev->dev_addr.
+ */
+
+static int sis630e_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
+{
+#if 0
+	u8 reg;
+	int i;
+	struct bus_loc bus_loc;
+	union {
+	    struct bus_dev bus_dev;
+	    struct pci_device isa_bridge;
+	} u;
+
+	/* find PCI to ISA bridge */
+	memset(&bus_loc, 0, sizeof(bus_loc));
+	if ( ! find_by_driver ( &bus_loc, &u.bus_dev, &sis_bridge_driver, 0 ) )
+	    return 0;
+
+	pci_read_config_byte(&u.isa_bridge, 0x48, &reg);
+	pci_write_config_byte(&u.isa_bridge, 0x48, reg | 0x40);
+
+	for (i = 0; i < ETH_ALEN; i++)
+	{
+		outb(0x09 + i, 0x70);
+		((u8 *)(nic->node_addr))[i] = inb(0x71);
+	}
+	pci_write_config_byte(&u.isa_bridge, 0x48, reg & ~0x40);
+
+	return 1;
+#endif
+
+	/* Does not work with current bus/device model */
+	memset ( nic->node_addr, 0, sizeof ( nic->node_addr ) );
+	return 0;
+}
+
+/**
+ *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
+ *      @pci_dev: the sis900 pci device
+ *      @net_dev: the net device to get address for
+ *
+ *      SiS630E model, use APC CMOS RAM to store MAC address.
+ *      APC CMOS RAM is accessed through ISA bridge.
+ *      MAC address is read into @net_dev->dev_addr.
+ */
+
+static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
+{
+        u32 rfcrSave;
+        u32 i;
+	
+	
+        rfcrSave = inl(rfcr + ioaddr);
+
+        outl(rfcrSave | RELOAD, ioaddr + cr);
+        outl(0, ioaddr + cr);
+
+        /* disable packet filtering before setting filter */
+        outl(rfcrSave & ~RFEN, rfcr + ioaddr);
+
+        /* load MAC addr to filter data register */
+        for (i = 0 ; i < 3 ; i++) {
+                outl((i << RFADDR_shift), ioaddr + rfcr);
+                *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
+        }
+
+        /* enable packet filitering */
+        outl(rfcrSave | RFEN, rfcr + ioaddr);
+
+        return 1;
+}
+
+/* 
+ * Function: sis900_probe
+ *
+ * Description: initializes initializes the NIC, retrieves the
+ *    MAC address of the card, and sets up some globals required by 
+ *    other routines.
+ *
+ * Side effects:
+ *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
+ *            leaves the sis900 initialized, and ready to recieve packets.
+ *
+ * Returns:   struct nic *:          pointer to NIC data structure
+ */
+
+static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
+
+    int i;
+    int found=0;
+    int phy_addr;
+    u8 revision;
+    int ret;
+
+    if (pci->ioaddr == 0)
+        return 0;
+
+    nic->irqno  = 0;
+    nic->ioaddr = pci->ioaddr;
+
+    ioaddr  = pci->ioaddr;
+    vendor  = pci->vendor;
+    dev_id  = pci->device;
+
+    /* wakeup chip */
+    pci_write_config_dword(pci, 0x40, 0x00000000);
+
+    adjust_pci_device(pci);
+
+    /* get MAC address */
+    ret = 0;
+    pci_read_config_byte(pci, PCI_REVISION, &revision);
+    
+    /* save for use later in sis900_reset() */
+    pci_revision = revision; 
+
+    if (revision == SIS630E_900_REV)
+        ret = sis630e_get_mac_addr(pci, nic);
+    else if ((revision > 0x81) && (revision <= 0x90))
+        ret = sis635_get_mac_addr(pci, nic);
+    else if (revision == SIS96x_900_REV)
+	ret = sis96x_get_mac_addr(pci, nic);
+    else
+        ret = sis900_get_mac_addr(pci, nic);
+
+    if (ret == 0)
+    {
+        printf ("sis900_probe: Error MAC address not found\n");
+        return 0;
+    }
+
+    /* 630ET : set the mii access mode as software-mode */
+    if (revision == SIS630ET_900_REV)
+	outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
+
+    DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
+
+    /* probe for mii transceiver */
+    /* search for total of 32 possible mii phy addresses */
+
+    found = 0;
+    for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+        u16 mii_status;
+        u16 phy_id0, phy_id1;
+
+        mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
+        if (mii_status == 0xffff || mii_status == 0x0000)
+            /* the mii is not accessable, try next one */
+            continue;
+                
+        phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
+        phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
+
+        /* search our mii table for the current mii */ 
+        for (i = 0; mii_chip_table[i].phy_id1; i++) {
+
+            if ((phy_id0 == mii_chip_table[i].phy_id0) &&
+                ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
+
+                printf("sis900_probe: %s transceiver found at address %d.\n",
+                       mii_chip_table[i].name, phy_addr);
+
+                mii.chip_info = &mii_chip_table[i];
+                mii.phy_addr  = phy_addr;
+                mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
+                mii.next      = NULL;
+
+                found=1;
+                break;
+            }
+        }
+    }
+        
+    if (found == 0) {
+        printf("sis900_probe: No MII transceivers found!\n");
+        return 0;
+    }
+
+    /* Arbitrarily select the last PHY found as current PHY */
+    cur_phy = mii.phy_addr;
+    printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
+
+    /* initialize device */
+    sis900_init(nic);
+    nic->nic_op	= &sis900_operations;
+
+    return 1;
+}
+
+
+
+
+/* 
+ * EEPROM Routines:  These functions read and write to EEPROM for 
+ *    retrieving the MAC address and other configuration information about 
+ *    the card.
+ */
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay()  inl(ee_addr)
+
+
+/* Function: sis900_read_eeprom
+ *
+ * Description: reads and returns a given location from EEPROM
+ *
+ * Arguments: int location:       requested EEPROM location
+ *
+ * Returns:   u16:                contents of requested EEPROM location
+ *
+ */
+
+/* Read Serial EEPROM through EEPROM Access Register, Note that location is 
+   in word (16 bits) unit */
+static u16 sis900_read_eeprom(int location)
+{
+    int i;
+    u16 retval = 0;
+    long ee_addr = ioaddr + mear;
+    u32 read_cmd = location | EEread;
+
+    outl(0, ee_addr);
+    eeprom_delay();
+    outl(EECS, ee_addr);
+    eeprom_delay();
+
+    /* Shift the read command (9) bits out. */
+    for (i = 8; i >= 0; i--) {
+        u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
+        outl(dataval, ee_addr);
+        eeprom_delay();
+        outl(dataval | EECLK, ee_addr);
+        eeprom_delay();
+    }
+    outl(EECS, ee_addr);
+    eeprom_delay();
+
+    /* read the 16-bits data in */
+    for (i = 16; i > 0; i--) {
+        outl(EECS, ee_addr);
+        eeprom_delay();
+        outl(EECS | EECLK, ee_addr);
+        eeprom_delay();
+        retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
+        eeprom_delay();
+    }
+                
+    /* Terminate the EEPROM access. */
+    outl(0, ee_addr);
+    eeprom_delay();
+//  outl(EECLK, ee_addr);
+
+    return (retval);
+}
+
+#define sis900_mdio_delay()    inl(mdio_addr)
+
+
+/* 
+   Read and write the MII management registers using software-generated
+   serial MDIO protocol. Note that the command bits and data bits are
+   send out seperately 
+*/
+
+static void sis900_mdio_idle(long mdio_addr)
+{
+    outl(MDIO | MDDIR, mdio_addr);
+    sis900_mdio_delay();
+    outl(MDIO | MDDIR | MDC, mdio_addr);
+}
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void sis900_mdio_reset(long mdio_addr)
+{
+    int i;
+
+    for (i = 31; i >= 0; i--) {
+        outl(MDDIR | MDIO, mdio_addr);
+        sis900_mdio_delay();
+        outl(MDDIR | MDIO | MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+    return;
+}
+
+static u16 sis900_mdio_read(int phy_id, int location)
+{
+    long mdio_addr = ioaddr + mear;
+    int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
+    u16 retval = 0;
+    int i;
+
+    sis900_mdio_reset(mdio_addr);
+    sis900_mdio_idle(mdio_addr);
+
+    for (i = 15; i >= 0; i--) {
+        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
+        outl(dataval, mdio_addr);
+        sis900_mdio_delay();
+        outl(dataval | MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+
+    /* Read the 16 data bits. */
+    for (i = 16; i > 0; i--) {
+        outl(0, mdio_addr);
+        sis900_mdio_delay();
+        retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
+        outl(MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+    outl(0x00, mdio_addr);
+    return retval;
+}
+
+#if 0
+static void sis900_mdio_write(int phy_id, int location, int value)
+{
+    long mdio_addr = ioaddr + mear;
+    int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
+    int i;
+
+    sis900_mdio_reset(mdio_addr);
+    sis900_mdio_idle(mdio_addr);
+
+    /* Shift the command bits out. */
+    for (i = 15; i >= 0; i--) {
+        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
+        outb(dataval, mdio_addr);
+        sis900_mdio_delay();
+        outb(dataval | MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+    sis900_mdio_delay();
+
+    /* Shift the value bits out. */
+    for (i = 15; i >= 0; i--) {
+        int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
+        outl(dataval, mdio_addr);
+        sis900_mdio_delay();
+        outl(dataval | MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+    sis900_mdio_delay();
+        
+    /* Clear out extra bits. */
+    for (i = 2; i > 0; i--) {
+        outb(0, mdio_addr);
+        sis900_mdio_delay();
+        outb(MDC, mdio_addr);
+        sis900_mdio_delay();
+    }
+    outl(0x00, mdio_addr);
+    return;
+}
+#endif
+
+
+/* Function: sis900_init
+ *
+ * Description: resets the ethernet controller chip and various
+ *    data structures required for sending and receiving packets.
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * returns:   void.
+ */
+
+static void
+sis900_init(struct nic *nic)
+{
+    /* Soft reset the chip. */
+    sis900_reset(nic);
+
+    sis900_init_rxfilter(nic);
+
+    sis900_init_txd(nic);
+    sis900_init_rxd(nic);
+
+    sis900_set_rx_mode(nic);
+
+    sis900_check_mode(nic);
+
+    outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
+}
+
+
+/* 
+ * Function: sis900_reset
+ *
+ * Description: disables interrupts and soft resets the controller chip
+ *
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void 
+sis900_reset(struct nic *nic __unused)
+{
+    int i = 0;
+    u32 status = TxRCMP | RxRCMP;
+
+    outl(0, ioaddr + ier);
+    outl(0, ioaddr + imr);
+    outl(0, ioaddr + rfcr);
+
+    outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
+
+    /* Check that the chip has finished the reset. */
+    while (status && (i++ < 1000)) {
+        status ^= (inl(isr + ioaddr) & status);
+    }
+
+    if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
+            outl(PESEL | RND_CNT, ioaddr + cfg);
+    else
+            outl(PESEL, ioaddr + cfg);
+}
+
+
+/* Function: sis_init_rxfilter
+ *
+ * Description: sets receive filter address to our MAC address
+ *
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * returns:   void.
+ */
+
+static void
+sis900_init_rxfilter(struct nic *nic)
+{
+    u32 rfcrSave;
+    int i;
+        
+    rfcrSave = inl(rfcr + ioaddr);
+
+    /* disable packet filtering before setting filter */
+    outl(rfcrSave & ~RFEN, rfcr + ioaddr);
+
+    /* load MAC addr to filter data register */
+    for (i = 0 ; i < 3 ; i++) {
+        u32 w;
+
+        w = (u32) *((u16 *)(nic->node_addr)+i);
+        outl((i << RFADDR_shift), ioaddr + rfcr);
+        outl(w, ioaddr + rfdr);
+
+        if (sis900_debug > 0)
+            printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
+                   i, inl(ioaddr + rfdr));
+    }
+
+    /* enable packet filitering */
+    outl(rfcrSave | RFEN, rfcr + ioaddr);
+}
+
+
+/* 
+ * Function: sis_init_txd
+ *
+ * Description: initializes the Tx descriptor
+ *
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * returns:   void.
+ */
+
+static void
+sis900_init_txd(struct nic *nic __unused)
+{
+    txd.link   = (u32) 0;
+    txd.cmdsts = (u32) 0;
+    txd.bufptr = virt_to_bus(&txb[0]);
+
+    /* load Transmit Descriptor Register */
+    outl(virt_to_bus(&txd), ioaddr + txdp); 
+    if (sis900_debug > 0)
+        printf("sis900_init_txd: TX descriptor register loaded with: %X\n", 
+               inl(ioaddr + txdp));
+}
+
+
+/* Function: sis_init_rxd
+ *
+ * Description: initializes the Rx descriptor ring
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void 
+sis900_init_rxd(struct nic *nic __unused) 
+{ 
+    int i;
+
+    cur_rx = 0; 
+
+    /* init RX descriptor */
+    for (i = 0; i < NUM_RX_DESC; i++) {
+        rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
+        rxd[i].cmdsts = (u32) RX_BUF_SIZE;
+        rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
+        if (sis900_debug > 0)
+            printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n", 
+                   i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
+		   (unsigned int) rxd[i].bufptr);
+    }
+
+    /* load Receive Descriptor Register */
+    outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
+
+    if (sis900_debug > 0)
+        printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", 
+               inl(ioaddr + rxdp));
+
+}
+
+
+/* Function: sis_init_rxd
+ *
+ * Description: 
+ *    sets the receive mode to accept all broadcast packets and packets
+ *    with our MAC address, and reject all multicast packets.      
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void sis900_set_rx_mode(struct nic *nic __unused)
+{
+    int i, table_entries;
+    u32 rx_mode; 
+    u16 mc_filter[16] = {0};	/* 256/128 bits multicast hash table */
+    	
+    if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
+	table_entries = 16;
+    else
+	table_entries = 8;
+
+    /* accept all multicast packet */
+    rx_mode = RFAAB | RFAAM;
+    for (i = 0; i < table_entries; i++)
+		mc_filter[i] = 0xffff;
+					
+    /* update Multicast Hash Table in Receive Filter */
+    for (i = 0; i < table_entries; i++) {
+        /* why plus 0x04? That makes the correct value for hash table. */
+        outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
+        outl(mc_filter[i], ioaddr + rfdr);
+    }
+
+    /* Accept Broadcast and multicast packets, destination addresses that match 
+       our MAC address */
+    outl(RFEN | rx_mode, ioaddr + rfcr);
+
+    return;
+}
+
+
+/* Function: sis900_check_mode
+ *
+ * Description: checks the state of transmit and receive
+ *    parameters on the NIC, and updates NIC registers to match
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+sis900_check_mode(struct nic *nic)
+{
+    int speed, duplex;
+    u32 tx_flags = 0, rx_flags = 0;
+
+    mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
+
+    if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
+        tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
+	rx_flags = DMA_BURST_64 << RxMXDMA_shift;
+    }
+    else {
+            tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
+            rx_flags = DMA_BURST_512 << RxMXDMA_shift;
+    }
+
+    if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
+        rx_flags |= (RxDRNT_10 << RxDRNT_shift);
+        tx_flags |= (TxDRNT_10 << TxDRNT_shift);
+    }
+    else {
+        rx_flags |= (RxDRNT_100 << RxDRNT_shift);
+        tx_flags |= (TxDRNT_100 << TxDRNT_shift);
+    }
+
+    if (duplex == FDX_CAPABLE_FULL_SELECTED) {
+        tx_flags |= (TxCSI | TxHBI);
+        rx_flags |= RxATX;
+    }
+
+    outl (tx_flags, ioaddr + txcfg);
+    outl (rx_flags, ioaddr + rxcfg);
+}
+
+
+/* Function: sis900_read_mode
+ *
+ * Description: retrieves and displays speed and duplex
+ *    parameters from the NIC
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+sis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
+{
+    int i = 0;
+    u32 status;
+    u16 phy_id0, phy_id1;
+        
+    /* STSOUT register is Latched on Transition, read operation updates it */
+    do {
+        status = sis900_mdio_read(phy_addr, MII_STSOUT);
+    } while (i++ < 2);
+
+    *speed = HW_SPEED_10_MBPS;
+    *duplex = FDX_CAPABLE_HALF_SELECTED;
+    
+    if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
+	*speed = HW_SPEED_100_MBPS;
+    if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
+	*duplex = FDX_CAPABLE_FULL_SELECTED;
+	
+    /* Workaround for Realtek RTL8201 PHY issue */
+    phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
+    phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
+    if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
+	if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
+	    *duplex = FDX_CAPABLE_FULL_SELECTED;
+	if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
+	    *speed = HW_SPEED_100_MBPS;
+    }
+
+    if (status & MII_STSOUT_LINK_FAIL)
+        printf("sis900_read_mode: Media Link Off\n");
+    else
+        printf("sis900_read_mode: Media Link On %s %s-duplex \n", 
+               *speed == HW_SPEED_100_MBPS ? 
+               "100mbps" : "10mbps",
+               *duplex == FDX_CAPABLE_FULL_SELECTED ?
+               "full" : "half");
+}
+
+
+/* Function: amd79c901_read_mode
+ *
+ * Description: retrieves and displays speed and duplex
+ *    parameters from the NIC
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+amd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
+{
+    int i;
+    u16 status;
+        
+    for (i = 0; i < 2; i++)
+        status = sis900_mdio_read(phy_addr, MII_STATUS);
+
+    if (status & MII_STAT_CAN_AUTO) {
+        /* 10BASE-T PHY */
+        for (i = 0; i < 2; i++)
+            status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
+        if (status & MII_STSSUM_SPD)
+            *speed = HW_SPEED_100_MBPS;
+        else
+            *speed = HW_SPEED_10_MBPS;
+        if (status & MII_STSSUM_DPLX)
+            *duplex = FDX_CAPABLE_FULL_SELECTED;
+        else
+            *duplex = FDX_CAPABLE_HALF_SELECTED;
+
+        if (status & MII_STSSUM_LINK)
+            printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", 
+                   *speed == HW_SPEED_100_MBPS ? 
+                   "100mbps" : "10mbps",
+                   *duplex == FDX_CAPABLE_FULL_SELECTED ?
+                   "full" : "half");
+        else
+            printf("amd79c901_read_mode: Media Link Off\n");
+    }
+    else {
+        /* HomePNA */
+        *speed = HW_SPEED_HOME;
+        *duplex = FDX_CAPABLE_HALF_SELECTED;
+        if (status & MII_STAT_LINK)
+            printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
+        else
+            printf("amd79c901_read_mode: Media Link Off\n");
+    }
+}
+
+
+/**
+ *	ics1893_read_mode: - read media mode for ICS1893 PHY
+ *	@net_dev: the net device to read mode for
+ *	@phy_addr: mii phy address
+ *	@speed: the transmit speed to be determined
+ *	@duplex: the duplex mode to be determined
+ *
+ *	ICS1893 PHY use Quick Poll Detailed Status register
+ *	to determine the speed and duplex mode for sis900
+ */
+
+static void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
+{
+	int i = 0;
+	u32 status;
+
+	/* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
+	for (i = 0; i < 2; i++)
+		status = sis900_mdio_read(phy_addr, MII_QPDSTS);
+
+	if (status & MII_STSICS_SPD)
+		*speed = HW_SPEED_100_MBPS;
+	else
+		*speed = HW_SPEED_10_MBPS;
+
+	if (status & MII_STSICS_DPLX)
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	else
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+
+	if (status & MII_STSICS_LINKSTS)
+		printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
+		       *speed == HW_SPEED_100_MBPS ?
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+	else
+		printf("ics1893_read_mode: Media Link Off\n");
+}
+
+/**
+ *	rtl8201_read_mode: - read media mode for rtl8201 phy
+ *	@nic: the net device to read mode for
+ *	@phy_addr: mii phy address
+ *	@speed: the transmit speed to be determined
+ *	@duplex: the duplex mode to be determined
+ *
+ *	read MII_STATUS register from rtl8201 phy
+ *	to determine the speed and duplex mode for sis900
+ */
+
+static void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
+{
+	u32 status;
+
+	status = sis900_mdio_read(phy_addr, MII_STATUS);
+
+	if (status & MII_STAT_CAN_TX_FDX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_TX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T_FDX) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+
+	if (status & MII_STAT_LINK)
+		printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
+		       *speed == HW_SPEED_100_MBPS ?
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+	else
+		printf("rtl8201_read_config_mode: Media Link Off\n");
+}
+
+/**
+ *	vt6103_read_mode: - read media mode for vt6103 phy
+ *	@nic: the net device to read mode for
+ *	@phy_addr: mii phy address
+ *	@speed: the transmit speed to be determined
+ *	@duplex: the duplex mode to be determined
+ *
+ *	read MII_STATUS register from rtl8201 phy
+ *	to determine the speed and duplex mode for sis900
+ */
+
+static void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
+{
+	u32 status;
+
+	status = sis900_mdio_read(phy_addr, MII_STATUS);
+
+	if (status & MII_STAT_CAN_TX_FDX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_TX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T_FDX) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+
+	if (status & MII_STAT_LINK)
+		printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
+		       *speed == HW_SPEED_100_MBPS ?
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+	else
+		printf("vt6103_read_config_mode: Media Link Off\n");
+}
+
+/* Function: sis900_transmit
+ *
+ * Description: transmits a packet and waits for completion or timeout.
+ *
+ * Arguments: char d[6]:          destination ethernet address.
+ *            unsigned short t:   ethernet protocol type.
+ *            unsigned short s:   size of the data-part of the packet.
+ *            char *p:            the data for the packet.
+ *    
+ * Returns:   void.
+ */
+
+static void
+sis900_transmit(struct nic  *nic,
+                const char  *d,     /* Destination */
+                unsigned int t,     /* Type */
+                unsigned int s,     /* size */
+                const char  *p)     /* Packet */
+{
+    u32 to, nstype;
+    volatile u32 tx_status;
+    
+    /* Stop the transmitter */
+    outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
+
+    /* load Transmit Descriptor Register */
+    outl(virt_to_bus(&txd), ioaddr + txdp); 
+    if (sis900_debug > 1)
+        printf("sis900_transmit: TX descriptor register loaded with: %X\n", 
+               inl(ioaddr + txdp));
+
+    memcpy(txb, d, ETH_ALEN);
+    memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
+    nstype = htons(t);
+    memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
+    memcpy(txb + ETH_HLEN, p, s);
+
+    s += ETH_HLEN;
+    s &= DSIZE;
+
+    if (sis900_debug > 1)
+        printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
+
+    /* pad to minimum packet size */
+    while (s < ETH_ZLEN)  
+        txb[s++] = '\0';
+
+    /* set the transmit buffer descriptor and enable Transmit State Machine */
+    txd.bufptr = virt_to_bus(&txb[0]);
+    txd.cmdsts = (u32) OWN | s;
+
+    /* restart the transmitter */
+    outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
+
+    if (sis900_debug > 1)
+        printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
+
+    to = currticks() + TX_TIMEOUT;
+
+    while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
+        /* wait */ ;
+
+    if (currticks() >= to) {
+        printf("sis900_transmit: TX Timeout! Tx status %X.\n", 
+	       (unsigned int) tx_status);
+    }
+    
+    if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
+        /* packet unsuccessfully transmited */
+        printf("sis900_transmit: Transmit error, Tx status %X.\n", 
+	       (unsigned int) tx_status);
+    }
+    /* Disable interrupts by clearing the interrupt mask. */
+    outl(0, ioaddr + imr);
+}
+
+
+/* Function: sis900_poll
+ *
+ * Description: checks for a received packet and returns it if found.
+ *
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   1 if a packet was recieved.
+ *            0 if no pacet was recieved.
+ *
+ * Side effects:
+ *            Returns (copies) the packet to the array nic->packet.
+ *            Returns the length of the packet in nic->packetlen.
+ */
+
+static int
+sis900_poll(struct nic *nic, int retrieve)
+{
+    u32 rx_status = rxd[cur_rx].cmdsts;
+    int retstat = 0;
+
+     /* acknowledge interrupts by reading interrupt status register */
+    inl(ioaddr + isr);
+
+    if (sis900_debug > 2)
+        printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, 
+	       (unsigned int) rx_status);
+
+    if (!(rx_status & OWN))
+        return retstat;
+
+    if (sis900_debug > 1)
+        printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
+               cur_rx, (unsigned int) rx_status);
+
+    if ( ! retrieve ) return 1;
+    
+    nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
+
+    if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
+        /* corrupted packet received */
+        printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
+               (unsigned int) rx_status);
+        retstat = 0;
+    } else {
+        /* give packet to higher level routine */
+        memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
+        retstat = 1;
+    }
+
+    /* return the descriptor and buffer to receive ring */
+    rxd[cur_rx].cmdsts = RX_BUF_SIZE;
+    rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
+        
+    if (++cur_rx == NUM_RX_DESC)
+        cur_rx = 0;
+
+    /* re-enable the potentially idle receive state machine */
+    outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
+
+    return retstat;
+
+}
+
+
+/* Function: sis900_disable
+ *
+ * Description: Turns off interrupts and stops Tx and Rx engines
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *
+ * Returns:   void.
+ */
+
+static void
+sis900_disable ( struct nic *nic ) {
+
+    sis900_init(nic);
+
+    /* Disable interrupts by clearing the interrupt mask. */
+    outl(0, ioaddr + imr);
+    outl(0, ioaddr + ier);
+    
+    /* Stop the chip's Tx and Rx Status Machine */
+    outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
+}
+
+
+/* Function: sis900_irq
+ *
+ * Description: Enable, Disable, or Force, interrupts
+ *    
+ * Arguments: struct nic *nic:          NIC data structure
+ *            irq_action_t action:      Requested action       
+ *
+ * Returns:   void.
+ */
+
+static void
+sis900_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    outl(0, ioaddr + imr);
+    break;
+  case ENABLE :
+    outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations sis900_operations = {
+	.connect	= dummy_connect,
+	.poll		= sis900_poll,
+	.transmit	= sis900_transmit,
+	.irq		= sis900_irq,
+};
+
+static struct pci_device_id sis900_nics[] = {
+PCI_ROM(0x1039, 0x0900, "sis900",  "SIS900", 0),
+PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016", 0),
+};
+
+PCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
+
+DRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
+	 sis900_probe, sis900_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.h
new file mode 100644
index 0000000..7a5c6b5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sis900.h
@@ -0,0 +1,375 @@
+/* -*- Mode:C; c-basic-offset:4; -*- */
+
+/* Definitions for SiS ethernet controllers including 7014/7016 and 900 
+ * References:
+ *   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+ *      preliminary Rev. 1.0 Jan. 14, 1998
+ *   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+ *      preliminary Rev. 1.0 Nov. 10, 1998
+ *   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+ *      preliminary Rev. 1.0 Jan. 18, 1998
+ *   http://www.sis.com.tw/support/databook.htm
+ */
+
+FILE_LICENCE ( GPL_ANY );
+
+/* MAC operationl registers of SiS 7016 and SiS 900 ethernet controller */
+/* The I/O extent, SiS 900 needs 256 bytes of io address */
+#define SIS900_TOTAL_SIZE 0x100
+
+/* Symbolic offsets to registers. */
+enum sis900_registers {
+    cr=0x0,                 /* Command Register */
+    cfg=0x4,                /* Configuration Register */
+    mear=0x8,               /* EEPROM Access Register */
+    ptscr=0xc,              /* PCI Test Control Register */
+    isr=0x10,               /* Interrupt Status Register */
+    imr=0x14,               /* Interrupt Mask Register */
+    ier=0x18,               /* Interrupt Enable Register */
+    epar=0x18,              /* Enhanced PHY Access Register */
+    txdp=0x20,              /* Transmit Descriptor Pointer Register */
+    txcfg=0x24,             /* Transmit Configuration Register */
+    rxdp=0x30,              /* Receive Descriptor Pointer Register */
+    rxcfg=0x34,             /* Receive Configuration Register */
+    flctrl=0x38,            /* Flow Control Register */
+    rxlen=0x3c,             /* Receive Packet Length Register */
+    rfcr=0x48,              /* Receive Filter Control Register */
+    rfdr=0x4C,              /* Receive Filter Data Register */
+    pmctrl=0xB0,            /* Power Management Control Register */
+    pmer=0xB4               /* Power Management Wake-up Event Register */
+};
+
+/* Symbolic names for bits in various registers */
+enum sis900_command_register_bits {
+    RELOAD     = 0x00000400,
+    ACCESSMODE = 0x00000200,
+    RESET      = 0x00000100, 
+    SWI        = 0x00000080, 
+    RxRESET    = 0x00000020,
+    TxRESET    = 0x00000010, 
+    RxDIS      = 0x00000008, 
+    RxENA      = 0x00000004,
+    TxDIS      = 0x00000002, 
+    TxENA      = 0x00000001
+};
+
+enum sis900_configuration_register_bits {
+    DESCRFMT = 0x00000100, /* 7016 specific */
+    REQALG   = 0x00000080, 
+    SB       = 0x00000040, 
+    POW      = 0x00000020, 
+    EXD      = 0x00000010, 
+    PESEL    = 0x00000008, 
+    LPM      = 0x00000004, 
+    BEM      = 0x00000001,
+    RND_CNT  = 0x00000400,
+    FAIR_BACKOFF = 0x00000200,
+    EDB_MASTER_EN = 0x00002000
+};
+
+enum sis900_eeprom_access_reigster_bits {
+    MDC   = 0x00000040, 
+    MDDIR = 0x00000020, 
+    MDIO  = 0x00000010, /* 7016 specific */ 
+    EECS  = 0x00000008, 
+    EECLK = 0x00000004, 
+    EEDO  = 0x00000002,
+    EEDI  = 0x00000001
+};
+
+enum sis900_interrupt_register_bits {
+    WKEVT      = 0x10000000, 
+    TxPAUSEEND = 0x08000000,
+    TxPAUSE    = 0x04000000,
+    TxRCMP     = 0x02000000,
+    RxRCMP     = 0x01000000,
+    DPERR      = 0x00800000,
+    SSERR      = 0x00400000,
+    RMABT      = 0x00200000,
+    RTABT      = 0x00100000,
+    RxSOVR     = 0x00010000, 
+    HIBERR     = 0x00008000, 
+    SWINT      = 0x00001000,
+    MIBINT     = 0x00000800, 
+    TxURN      = 0x00000400,
+    TxIDLE     = 0x00000200,
+    TxERR      = 0x00000100,
+    TxDESC     = 0x00000080,
+    TxOK       = 0x00000040,
+    RxORN      = 0x00000020, 
+    RxIDLE     = 0x00000010,
+    RxEARLY    = 0x00000008,
+    RxERR      = 0x00000004,
+    RxDESC     = 0x00000002,
+    RxOK       = 0x00000001
+};
+
+enum sis900_interrupt_enable_reigster_bits {
+    IE = 0x00000001
+};
+
+/* maximum dma burst fro transmission and receive*/
+#define MAX_DMA_RANGE   7       /* actually 0 means MAXIMUM !! */
+#define TxMXDMA_shift   20
+#define RxMXDMA_shift   20
+#define TX_DMA_BURST    0
+#define RX_DMA_BURST    0
+
+enum sis900_tx_rx_dma{
+	        DMA_BURST_512 = 0,      DMA_BURST_64 = 5
+};
+
+/* transmit FIFO threshholds */
+#define TX_FILL_THRESH  16      /* 1/4 FIFO size */
+#define TxFILLT_shift   8
+#define TxDRNT_shift    0
+#define TxDRNT_100      48      /* 3/4 FIFO size */
+#define TxDRNT_10       16      /* 1/2 FIFO size */
+
+enum sis900_transmit_config_register_bits {
+    TxCSI   = 0x80000000,
+    TxHBI   = 0x40000000,
+    TxMLB   = 0x20000000,
+    TxATP   = 0x10000000,
+    TxIFG   = 0x0C000000,
+    TxFILLT = 0x00003F00,
+    TxDRNT  = 0x0000003F
+};
+
+/* recevie FIFO thresholds */
+#define RxDRNT_shift     1
+#define RxDRNT_100      16      /* 1/2 FIFO size */
+#define RxDRNT_10       24      /* 3/4 FIFO size */
+
+enum sis900_reveive_config_register_bits {
+    RxAEP  = 0x80000000, 
+    RxARP  = 0x40000000, 
+    RxATX  = 0x10000000,
+    RxAJAB = 0x08000000, 
+    RxDRNT = 0x0000007F
+};
+
+#define RFAA_shift      28
+#define RFADDR_shift    16
+
+enum sis900_receive_filter_control_register_bits {
+    RFEN  = 0x80000000, 
+    RFAAB = 0x40000000, 
+    RFAAM = 0x20000000,
+    RFAAP = 0x10000000, 
+    RFPromiscuous = (RFAAB|RFAAM|RFAAP)
+};
+
+enum sis900_reveive_filter_data_mask {
+    RFDAT =  0x0000FFFF
+};
+
+/* EEPROM Addresses */
+enum sis900_eeprom_address {
+    EEPROMSignature = 0x00, 
+    EEPROMVendorID  = 0x02, 
+    EEPROMDeviceID  = 0x03,
+    EEPROMMACAddr   = 0x08, 
+    EEPROMChecksum  = 0x0b
+};
+
+/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
+enum sis900_eeprom_command {
+    EEread          = 0x0180, 
+    EEwrite         = 0x0140, 
+    EEerase         = 0x01C0, 
+    EEwriteEnable   = 0x0130,
+    EEwriteDisable  = 0x0100,
+    EEeraseAll      = 0x0120,
+    EEwriteAll      = 0x0110, 
+    EEaddrMask      = 0x013F, 
+    EEcmdShift 	    = 16
+};
+/* For SiS962 or SiS963, request the eeprom software access */
+enum sis96x_eeprom_command {
+	EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
+};
+
+/* Manamgement Data I/O (mdio) frame */
+#define MIIread         0x6000
+#define MIIwrite        0x5002
+#define MIIpmdShift     7
+#define MIIregShift     2
+#define MIIcmdLen       16
+#define MIIcmdShift     16
+
+/* Buffer Descriptor Status*/
+enum sis900_buffer_status {
+    OWN    = 0x80000000, 
+    MORE   = 0x40000000, 
+    INTR   = 0x20000000,
+    SUPCRC = 0x10000000, 
+    INCCRC = 0x10000000,
+    OK     = 0x08000000, 
+    DSIZE  = 0x00000FFF
+};
+
+/* Status for TX Buffers */
+enum sis900_tx_buffer_status {
+    ABORT      = 0x04000000,
+    UNDERRUN   = 0x02000000, 
+    NOCARRIER  = 0x01000000,
+    DEFERD     = 0x00800000, 
+    EXCDEFER   = 0x00400000, 
+    OWCOLL     = 0x00200000,
+    EXCCOLL    = 0x00100000, 
+    COLCNT     = 0x000F0000
+};
+
+enum sis900_rx_bufer_status {
+    OVERRUN    = 0x02000000,
+    DEST       = 0x00800000,
+    BCAST      = 0x01800000,
+    MCAST      = 0x01000000,
+    UNIMATCH   = 0x00800000,
+    TOOLONG    = 0x00400000,
+    RUNT       = 0x00200000,
+    RXISERR    = 0x00100000,
+    CRCERR     = 0x00080000,
+    FAERR      = 0x00040000,
+    LOOPBK     = 0x00020000,
+    RXCOL      = 0x00010000
+};
+
+/* MII register offsets */
+enum mii_registers {
+    MII_CONTROL = 0x0000, 
+    MII_STATUS  = 0x0001,
+    MII_PHY_ID0 = 0x0002,
+    MII_PHY_ID1 = 0x0003,
+    MII_ANADV   = 0x0004,
+    MII_ANLPAR  = 0x0005,
+    MII_ANEXT   = 0x0006
+};
+
+/* mii registers specific to SiS 900 */
+enum sis_mii_registers {
+    MII_CONFIG1 = 0x0010,
+    MII_CONFIG2 = 0x0011,
+    MII_STSOUT  = 0x0012,
+    MII_MASK    = 0x0013,
+    MII_RESV    = 0x0014
+};
+
+/* mii registers specific to AMD 79C901 */
+enum amd_mii_registers {
+    MII_STATUS_SUMMARY = 0x0018
+};
+
+/* mii registers specific to ICS 1893 */
+enum ics_mii_registers {
+	MII_EXTCTRL  = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012,
+	MII_EXTCTRL2 = 0x0013
+};
+
+
+
+/* MII Control register bit definitions. */
+enum mii_control_register_bits {
+    MII_CNTL_FDX      = 0x0100,
+    MII_CNTL_RST_AUTO = 0x0200, 
+    MII_CNTL_ISOLATE  = 0x0400,
+    MII_CNTL_PWRDWN   = 0x0800,
+    MII_CNTL_AUTO     = 0x1000,
+    MII_CNTL_SPEED    = 0x2000,
+    MII_CNTL_LPBK     = 0x4000,
+    MII_CNTL_RESET    = 0x8000
+};
+
+/* MII Status register bit  */
+enum mii_status_register_bits {
+    MII_STAT_EXT        = 0x0001,
+    MII_STAT_JAB        = 0x0002, 
+    MII_STAT_LINK       = 0x0004,
+    MII_STAT_CAN_AUTO   = 0x0008, 
+    MII_STAT_FAULT      = 0x0010,
+    MII_STAT_AUTO_DONE  = 0x0020,
+    MII_STAT_CAN_T      = 0x0800, 
+    MII_STAT_CAN_T_FDX  = 0x1000,
+    MII_STAT_CAN_TX     = 0x2000, 
+    MII_STAT_CAN_TX_FDX = 0x4000,
+    MII_STAT_CAN_T4     = 0x8000
+};
+
+#define         MII_ID1_OUI_LO          0xFC00  /* low bits of OUI mask */
+#define         MII_ID1_MODEL           0x03F0  /* model number */
+#define         MII_ID1_REV             0x000F  /* model number */
+
+/* MII NWAY Register Bits ...
+   valid for the ANAR (Auto-Negotiation Advertisement) and
+   ANLPAR (Auto-Negotiation Link Partner) registers */
+enum mii_nway_register_bits {
+    MII_NWAY_NODE_SEL = 0x001f,
+    MII_NWAY_CSMA_CD  = 0x0001,
+    MII_NWAY_T        = 0x0020,
+    MII_NWAY_T_FDX    = 0x0040,
+    MII_NWAY_TX       = 0x0080,
+    MII_NWAY_TX_FDX   = 0x0100,
+    MII_NWAY_T4       = 0x0200,
+    MII_NWAY_PAUSE    = 0x0400,
+    MII_NWAY_RF       = 0x2000,
+    MII_NWAY_ACK      = 0x4000,
+    MII_NWAY_NP       = 0x8000
+};
+
+enum mii_stsout_register_bits {
+    MII_STSOUT_LINK_FAIL = 0x4000,
+    MII_STSOUT_SPD       = 0x0080,
+    MII_STSOUT_DPLX      = 0x0040
+};
+
+enum mii_stsics_register_bits {
+	MII_STSICS_SPD  = 0x8000, MII_STSICS_DPLX = 0x4000,
+	MII_STSICS_LINKSTS = 0x0001
+};
+
+enum mii_stssum_register_bits {
+    MII_STSSUM_LINK = 0x0008,
+    MII_STSSUM_DPLX = 0x0004,
+    MII_STSSUM_AUTO = 0x0002,
+    MII_STSSUM_SPD  = 0x0001
+};
+
+enum sis900_revision_id {
+	SIS630A_900_REV = 0x80,		SIS630E_900_REV = 0x81,
+	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83,
+	SIS630ET_900_REV = 0x84,        SIS635A_900_REV = 0x90,
+	SIS96x_900_REV = 0X91,		SIS900B_900_REV = 0x03
+};
+
+enum sis630_revision_id {
+	SIS630A0    = 0x00, SIS630A1      = 0x01,
+	SIS630B0    = 0x10, SIS630B1      = 0x11
+};
+
+#define FDX_CAPABLE_DUPLEX_UNKNOWN      0
+#define FDX_CAPABLE_HALF_SELECTED       1
+#define FDX_CAPABLE_FULL_SELECTED       2
+
+#define HW_SPEED_UNCONFIG               0
+#define HW_SPEED_HOME                   1
+#define HW_SPEED_10_MBPS                10
+#define HW_SPEED_100_MBPS               100
+#define HW_SPEED_DEFAULT                (HW_SPEED_100_MBPS)
+
+#define CRC_SIZE        4
+#define MAC_HEADER_SIZE 14
+
+#define TX_BUF_SIZE     1536
+#define RX_BUF_SIZE     1536
+
+#define NUM_RX_DESC     4              /* Number of Rx descriptor registers. */
+
+/* Time in ticks before concluding the transmitter is hung. */
+#define TX_TIMEOUT       (4*TICKS_PER_SEC)
+
+typedef struct _BufferDesc {
+    u32              link;
+    volatile u32     cmdsts;
+    u32              bufptr;
+} BufferDesc;
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.c
new file mode 100755
index 0000000..fea3384
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.c
@@ -0,0 +1,2468 @@
+/*
+ * iPXE driver for Marvell Yukon chipset and SysKonnect Gigabit
+ * Ethernet adapters. Derived from Linux skge driver (v1.13), which was
+ * based on earlier sk98lin, e100 and FreeBSD if_sk drivers.
+ *
+ * This driver intentionally does not support all the features of the
+ * original driver such as link fail-over and link management because
+ * those should be done at higher levels.
+ *
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger at osdl.org>
+ *
+ * Modified for iPXE, July 2008 by Michael Decker <mrd999 at gmail.com>
+ * Tested and Modified in December 2009 by
+ *    Thomas Miletich <thomas.miletich at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+
+#include "skge.h"
+
+static struct pci_device_id skge_id_table[] = {
+	PCI_ROM(0x10b7, 0x1700,     "3C940",     "3COM 3C940", 0),
+	PCI_ROM(0x10b7, 0x80eb,     "3C940B",    "3COM 3C940", 0),
+	PCI_ROM(0x1148, 0x4300,     "GE",        "Syskonnect GE", 0),
+	PCI_ROM(0x1148, 0x4320,     "YU",        "Syskonnect YU", 0),
+	PCI_ROM(0x1186, 0x4C00,     "DGE510T",   "DLink DGE-510T", 0),
+	PCI_ROM(0x1186, 0x4b01,     "DGE530T",   "DLink DGE-530T", 0),
+	PCI_ROM(0x11ab, 0x4320,     "id4320",    "Marvell id4320", 0),
+	PCI_ROM(0x11ab, 0x5005,     "id5005",    "Marvell id5005", 0), /* Belkin */
+	PCI_ROM(0x1371, 0x434e,     "Gigacard",  "CNET Gigacard", 0),
+	PCI_ROM(0x1737, 0x1064,     "EG1064",    "Linksys EG1064", 0),
+	PCI_ROM(0x1737, 0xffff,     "id_any",    "Linksys [any]", 0)
+};
+
+static int skge_up(struct net_device *dev);
+static void skge_down(struct net_device *dev);
+static void skge_tx_clean(struct net_device *dev);
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void yukon_init(struct skge_hw *hw, int port);
+static void genesis_mac_init(struct skge_hw *hw, int port);
+static void genesis_link_up(struct skge_port *skge);
+
+static void skge_phyirq(struct skge_hw *hw);
+static void skge_poll(struct net_device *dev);
+static int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob);
+static void skge_net_irq ( struct net_device *dev, int enable );
+
+static void skge_rx_refill(struct net_device *dev);
+
+static struct net_device_operations skge_operations = {
+	.open     = skge_up,
+	.close    = skge_down,
+	.transmit = skge_xmit_frame,
+	.poll     = skge_poll,
+	.irq      = skge_net_irq
+};
+
+/* Avoid conditionals by using array */
+static const int txqaddr[] = { Q_XA1, Q_XA2 };
+static const int rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
+static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 napimask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
+static const u32 portmask[] = { IS_PORT_1, IS_PORT_2 };
+
+/* Determine supported/advertised modes based on hardware.
+ * Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx
+ */
+static u32 skge_supported_modes(const struct skge_hw *hw)
+{
+	u32 supported;
+
+	if (hw->copper) {
+		supported = SUPPORTED_10baseT_Half
+			| SUPPORTED_10baseT_Full
+			| SUPPORTED_100baseT_Half
+			| SUPPORTED_100baseT_Full
+			| SUPPORTED_1000baseT_Half
+			| SUPPORTED_1000baseT_Full
+			| SUPPORTED_Autoneg| SUPPORTED_TP;
+
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			supported &= ~(SUPPORTED_10baseT_Half
+					     | SUPPORTED_10baseT_Full
+					     | SUPPORTED_100baseT_Half
+					     | SUPPORTED_100baseT_Full);
+
+		else if (hw->chip_id == CHIP_ID_YUKON)
+			supported &= ~SUPPORTED_1000baseT_Half;
+	} else
+		supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half
+			| SUPPORTED_FIBRE | SUPPORTED_Autoneg;
+
+	return supported;
+}
+
+/* Chip internal frequency for clock calculations */
+static inline u32 hwkhz(const struct skge_hw *hw)
+{
+	return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125;
+}
+
+/* Microseconds to chip HZ */
+static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec)
+{
+	return hwkhz(hw) * usec / 1000;
+}
+
+enum led_mode { LED_MODE_OFF, LED_MODE_ON, LED_MODE_TST };
+static void skge_led(struct skge_port *skge, enum led_mode mode)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		switch (mode) {
+		case LED_MODE_OFF:
+			if (hw->phy_type == SK_PHY_BCOM)
+				xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
+			else {
+				skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
+				skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
+			}
+			skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
+			skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+			skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
+			break;
+
+		case LED_MODE_ON:
+			skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
+			skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
+
+			skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+			skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
+
+			break;
+
+		case LED_MODE_TST:
+			skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON);
+			skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
+			skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+
+			if (hw->phy_type == SK_PHY_BCOM)
+				xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
+			else {
+				skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
+				skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
+				skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
+			}
+
+		}
+	} else {
+		switch (mode) {
+		case LED_MODE_OFF:
+			gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+			gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+				     PHY_M_LED_MO_DUP(MO_LED_OFF)  |
+				     PHY_M_LED_MO_10(MO_LED_OFF)   |
+				     PHY_M_LED_MO_100(MO_LED_OFF)  |
+				     PHY_M_LED_MO_1000(MO_LED_OFF) |
+				     PHY_M_LED_MO_RX(MO_LED_OFF));
+			break;
+		case LED_MODE_ON:
+			gm_phy_write(hw, port, PHY_MARV_LED_CTRL,
+				     PHY_M_LED_PULS_DUR(PULS_170MS) |
+				     PHY_M_LED_BLINK_RT(BLINK_84MS) |
+				     PHY_M_LEDC_TX_CTRL |
+				     PHY_M_LEDC_DP_CTRL);
+
+			gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+				     PHY_M_LED_MO_RX(MO_LED_OFF) |
+				     (skge->speed == SPEED_100 ?
+				      PHY_M_LED_MO_100(MO_LED_ON) : 0));
+			break;
+		case LED_MODE_TST:
+			gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+			gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+				     PHY_M_LED_MO_DUP(MO_LED_ON)  |
+				     PHY_M_LED_MO_10(MO_LED_ON)   |
+				     PHY_M_LED_MO_100(MO_LED_ON)  |
+				     PHY_M_LED_MO_1000(MO_LED_ON) |
+				     PHY_M_LED_MO_RX(MO_LED_ON));
+		}
+	}
+}
+
+/*
+ * I've left in these EEPROM and VPD functions, as someone may desire to
+ * integrate them in the future. -mdeck
+ *
+ * static int skge_get_eeprom_len(struct net_device *dev)
+ * {
+ * 	struct skge_port *skge = netdev_priv(dev);
+ * 	u32 reg2;
+ *
+ * 	pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, &reg2);
+ * 	return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
+ * }
+ *
+ * static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
+ * {
+ * 	u32 val;
+ *
+ * 	pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
+ *
+ * 	do {
+ * 		pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ * 	} while (!(offset & PCI_VPD_ADDR_F));
+ *
+ * 	pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+ * 	return val;
+ * }
+ *
+ * static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
+ * {
+ * 	pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val);
+ * 	pci_write_config_word(pdev, cap + PCI_VPD_ADDR,
+ * 			      offset | PCI_VPD_ADDR_F);
+ *
+ * 	do {
+ * 		pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ * 	} while (offset & PCI_VPD_ADDR_F);
+ * }
+ *
+ * static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ * 			   u8 *data)
+ * {
+ * 	struct skge_port *skge = netdev_priv(dev);
+ * 	struct pci_dev *pdev = skge->hw->pdev;
+ * 	int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+ * 	int length = eeprom->len;
+ * 	u16 offset = eeprom->offset;
+ *
+ * 	if (!cap)
+ * 		return -EINVAL;
+ *
+ * 	eeprom->magic = SKGE_EEPROM_MAGIC;
+ *
+ * 	while (length > 0) {
+ * 		u32 val = skge_vpd_read(pdev, cap, offset);
+ * 		int n = min_t(int, length, sizeof(val));
+ *
+ * 		memcpy(data, &val, n);
+ * 		length -= n;
+ * 		data += n;
+ * 		offset += n;
+ * 	}
+ * 	return 0;
+ * }
+ *
+ * static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ * 			   u8 *data)
+ * {
+ * 	struct skge_port *skge = netdev_priv(dev);
+ * 	struct pci_dev *pdev = skge->hw->pdev;
+ * 	int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+ * 	int length = eeprom->len;
+ * 	u16 offset = eeprom->offset;
+ *
+ * 	if (!cap)
+ * 		return -EINVAL;
+ *
+ * 	if (eeprom->magic != SKGE_EEPROM_MAGIC)
+ * 		return -EINVAL;
+ *
+ * 	while (length > 0) {
+ * 		u32 val;
+ * 		int n = min_t(int, length, sizeof(val));
+ *
+ * 		if (n < sizeof(val))
+ * 			val = skge_vpd_read(pdev, cap, offset);
+ * 		memcpy(&val, data, n);
+ *
+ * 		skge_vpd_write(pdev, cap, offset, val);
+ *
+ * 		length -= n;
+ * 		data += n;
+ * 		offset += n;
+ * 	}
+ * 	return 0;
+ * }
+ */
+
+/*
+ * Allocate ring elements and chain them together
+ * One-to-one association of board descriptors with ring elements
+ */
+static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base,
+                           size_t num)
+{
+	struct skge_tx_desc *d;
+	struct skge_element *e;
+	unsigned int i;
+
+	ring->start = zalloc(num*sizeof(*e));
+	if (!ring->start)
+		return -ENOMEM;
+
+	for (i = 0, e = ring->start, d = vaddr; i < num; i++, e++, d++) {
+		e->desc = d;
+		if (i == num - 1) {
+			e->next = ring->start;
+			d->next_offset = base;
+		} else {
+			e->next = e + 1;
+			d->next_offset = base + (i+1) * sizeof(*d);
+		}
+	}
+	ring->to_use = ring->to_clean = ring->start;
+
+	return 0;
+}
+
+/* Allocate and setup a new buffer for receiving */
+static void skge_rx_setup(struct skge_port *skge __unused,
+			  struct skge_element *e,
+			  struct io_buffer *iob, unsigned int bufsize)
+{
+	struct skge_rx_desc *rd = e->desc;
+	u64 map;
+
+	map = ( iob != NULL ) ? virt_to_bus(iob->data) : 0;
+
+	rd->dma_lo = map;
+	rd->dma_hi = map >> 32;
+	e->iob = iob;
+	rd->csum1_start = ETH_HLEN;
+	rd->csum2_start = ETH_HLEN;
+	rd->csum1 = 0;
+	rd->csum2 = 0;
+
+	wmb();
+
+	rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
+}
+
+/* Resume receiving using existing skb,
+ * Note: DMA address is not changed by chip.
+ * 	 MTU not changed while receiver active.
+ */
+static inline void skge_rx_reuse(struct skge_element *e, unsigned int size)
+{
+	struct skge_rx_desc *rd = e->desc;
+
+	rd->csum2 = 0;
+	rd->csum2_start = ETH_HLEN;
+
+	wmb();
+
+	rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size;
+}
+
+
+/* Free all  buffers in receive ring, assumes receiver stopped */
+static void skge_rx_clean(struct skge_port *skge)
+{
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_element *e;
+
+	e = ring->start;
+	do {
+		struct skge_rx_desc *rd = e->desc;
+		rd->control = 0;
+		if (e->iob) {
+			free_iob(e->iob);
+			e->iob = NULL;
+		}
+	} while ((e = e->next) != ring->start);
+}
+
+static void skge_link_up(struct skge_port *skge)
+{
+	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG),
+		    LED_BLK_OFF|LED_SYNC_OFF|LED_ON);
+
+	netdev_link_up(skge->netdev);
+
+	DBG2(PFX "%s: Link is up at %d Mbps, %s duplex\n",
+	     skge->netdev->name, skge->speed,
+	     skge->duplex == DUPLEX_FULL ? "full" : "half");
+}
+
+static void skge_link_down(struct skge_port *skge)
+{
+	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
+	netdev_link_down(skge->netdev);
+
+	DBG2(PFX "%s: Link is down.\n", skge->netdev->name);
+}
+
+
+static void xm_link_down(struct skge_hw *hw, int port)
+{
+	struct net_device *dev = hw->dev[port];
+	struct skge_port *skge = netdev_priv(dev);
+
+	xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE);
+
+	if (netdev_link_ok(dev))
+		skge_link_down(skge);
+}
+
+static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
+{
+	int i;
+
+	xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+	*val = xm_read16(hw, port, XM_PHY_DATA);
+
+	if (hw->phy_type == SK_PHY_XMAC)
+		goto ready;
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
+			goto ready;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+ ready:
+	*val = xm_read16(hw, port, XM_PHY_DATA);
+
+	return 0;
+}
+
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+	u16 v = 0;
+	if (__xm_phy_read(hw, port, reg, &v))
+		DBG(PFX "%s: phy read timed out\n",
+		       hw->dev[port]->name);
+	return v;
+}
+
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+	int i;
+
+	xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+	for (i = 0; i < PHY_RETRIES; i++) {
+		if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+			goto ready;
+		udelay(1);
+	}
+	return -EIO;
+
+ ready:
+	xm_write16(hw, port, XM_PHY_DATA, val);
+	for (i = 0; i < PHY_RETRIES; i++) {
+		if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+			return 0;
+		udelay(1);
+	}
+	return -ETIMEDOUT;
+}
+
+static void genesis_init(struct skge_hw *hw)
+{
+	/* set blink source counter */
+	skge_write32(hw, B2_BSC_INI, (SK_BLK_DUR * SK_FACT_53) / 100);
+	skge_write8(hw, B2_BSC_CTRL, BSC_START);
+
+	/* configure mac arbiter */
+	skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure mac arbiter timeout values */
+	skge_write8(hw, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+	skge_write8(hw, B3_MA_RCINI_RX1, 0);
+	skge_write8(hw, B3_MA_RCINI_RX2, 0);
+	skge_write8(hw, B3_MA_RCINI_TX1, 0);
+	skge_write8(hw, B3_MA_RCINI_TX2, 0);
+
+	/* configure packet arbiter timeout */
+	skge_write16(hw, B3_PA_CTRL, PA_RST_CLR);
+	skge_write16(hw, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+}
+
+static void genesis_reset(struct skge_hw *hw, int port)
+{
+	const u8 zero[8]  = { 0 };
+	u32 reg;
+
+	skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
+
+	/* reset the statistics module */
+	xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
+	xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE);
+	xm_write32(hw, port, XM_MODE, 0);		/* clear Mode Reg */
+	xm_write16(hw, port, XM_TX_CMD, 0);	/* reset TX CMD Reg */
+	xm_write16(hw, port, XM_RX_CMD, 0);	/* reset RX CMD Reg */
+
+	/* disable Broadcom PHY IRQ */
+	if (hw->phy_type == SK_PHY_BCOM)
+		xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+
+	xm_outhash(hw, port, XM_HSM, zero);
+
+	/* Flush TX and RX fifo */
+	reg = xm_read32(hw, port, XM_MODE);
+	xm_write32(hw, port, XM_MODE, reg | XM_MD_FTF);
+	xm_write32(hw, port, XM_MODE, reg | XM_MD_FRF);
+}
+
+
+/* Convert mode to MII values  */
+static const u16 phy_pause_map[] = {
+	[FLOW_MODE_NONE] =	0,
+	[FLOW_MODE_LOC_SEND] =	PHY_AN_PAUSE_ASYM,
+	[FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
+	[FLOW_MODE_SYM_OR_REM]  = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+/* special defines for FIBER (88E1011S only) */
+static const u16 fiber_pause_map[] = {
+	[FLOW_MODE_NONE]	= PHY_X_P_NO_PAUSE,
+	[FLOW_MODE_LOC_SEND]	= PHY_X_P_ASYM_MD,
+	[FLOW_MODE_SYMMETRIC]	= PHY_X_P_SYM_MD,
+	[FLOW_MODE_SYM_OR_REM]	= PHY_X_P_BOTH_MD,
+};
+
+
+/* Check status of Broadcom phy link */
+static void bcom_check_link(struct skge_hw *hw, int port)
+{
+	struct net_device *dev = hw->dev[port];
+	struct skge_port *skge = netdev_priv(dev);
+	u16 status;
+
+	/* read twice because of latch */
+	xm_phy_read(hw, port, PHY_BCOM_STAT);
+	status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+	if ((status & PHY_ST_LSYNC) == 0) {
+		xm_link_down(hw, port);
+		return;
+	}
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		u16 lpa, aux;
+
+		if (!(status & PHY_ST_AN_OVER))
+			return;
+
+		lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+		if (lpa & PHY_B_AN_RF) {
+			DBG(PFX "%s: remote fault\n",
+			       dev->name);
+			return;
+		}
+
+		aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+		/* Check Duplex mismatch */
+		switch (aux & PHY_B_AS_AN_RES_MSK) {
+		case PHY_B_RES_1000FD:
+			skge->duplex = DUPLEX_FULL;
+			break;
+		case PHY_B_RES_1000HD:
+			skge->duplex = DUPLEX_HALF;
+			break;
+		default:
+			DBG(PFX "%s: duplex mismatch\n",
+			       dev->name);
+			return;
+		}
+
+		/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+		switch (aux & PHY_B_AS_PAUSE_MSK) {
+		case PHY_B_AS_PAUSE_MSK:
+			skge->flow_status = FLOW_STAT_SYMMETRIC;
+			break;
+		case PHY_B_AS_PRR:
+			skge->flow_status = FLOW_STAT_REM_SEND;
+			break;
+		case PHY_B_AS_PRT:
+			skge->flow_status = FLOW_STAT_LOC_SEND;
+			break;
+		default:
+			skge->flow_status = FLOW_STAT_NONE;
+		}
+		skge->speed = SPEED_1000;
+	}
+
+	if (!netdev_link_ok(dev))
+		genesis_link_up(skge);
+}
+
+/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
+ * Phy on for 100 or 10Mbit operation
+ */
+static void bcom_phy_init(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	unsigned int i;
+	u16 id1, r, ext, ctl;
+
+	/* magic workaround patterns for Broadcom */
+	static const struct {
+		u16 reg;
+		u16 val;
+	} A1hack[] = {
+		{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 },
+		{ 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 },
+		{ 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 },
+		{ 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+	}, C0hack[] = {
+		{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 },
+		{ 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+	};
+
+	/* read Id from external PHY (all have the same address) */
+	id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+	/* Optimize MDIO transfer by suppressing preamble. */
+	r = xm_read16(hw, port, XM_MMU_CMD);
+	r |=  XM_MMU_NO_PRE;
+	xm_write16(hw, port, XM_MMU_CMD,r);
+
+	switch (id1) {
+	case PHY_BCOM_ID1_C0:
+		/*
+		 * Workaround BCOM Errata for the C0 type.
+		 * Write magic patterns to reserved registers.
+		 */
+		for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+			xm_phy_write(hw, port,
+				     C0hack[i].reg, C0hack[i].val);
+
+		break;
+	case PHY_BCOM_ID1_A1:
+		/*
+		 * Workaround BCOM Errata for the A1 type.
+		 * Write magic patterns to reserved registers.
+		 */
+		for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+			xm_phy_write(hw, port,
+				     A1hack[i].reg, A1hack[i].val);
+		break;
+	}
+
+	/*
+	 * Workaround BCOM Errata (#10523) for all BCom PHYs.
+	 * Disable Power Management after reset.
+	 */
+	r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+	r |= PHY_B_AC_DIS_PM;
+	xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r);
+
+	/* Dummy read */
+	xm_read16(hw, port, XM_ISRC);
+
+	ext = PHY_B_PEC_EN_LTR; /* enable tx led */
+	ctl = PHY_CT_SP1000;	/* always 1000mbit */
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		/*
+		 * Workaround BCOM Errata #1 for the C5 type.
+		 * 1000Base-T Link Acquisition Failure in Slave Mode
+		 * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+		 */
+		u16 adv = PHY_B_1000C_RD;
+		if (skge->advertising & ADVERTISED_1000baseT_Half)
+			adv |= PHY_B_1000C_AHD;
+		if (skge->advertising & ADVERTISED_1000baseT_Full)
+			adv |= PHY_B_1000C_AFD;
+		xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv);
+
+		ctl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	} else {
+		if (skge->duplex == DUPLEX_FULL)
+			ctl |= PHY_CT_DUP_MD;
+		/* Force to slave */
+		xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE);
+	}
+
+	/* Set autonegotiation pause parameters */
+	xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV,
+		     phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+	xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
+	xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
+
+	/* Use link status change interrupt */
+	xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+}
+
+static void xm_phy_init(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 ctrl = 0;
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		if (skge->advertising & ADVERTISED_1000baseT_Half)
+			ctrl |= PHY_X_AN_HD;
+		if (skge->advertising & ADVERTISED_1000baseT_Full)
+			ctrl |= PHY_X_AN_FD;
+
+		ctrl |= fiber_pause_map[skge->flow_control];
+
+		xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
+
+		/* Restart Auto-negotiation */
+		ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+	} else {
+		/* Set DuplexMode in Config register */
+		if (skge->duplex == DUPLEX_FULL)
+			ctrl |= PHY_CT_DUP_MD;
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLEs are transmitted
+		 */
+	}
+
+	xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
+
+	/* Poll PHY for status changes */
+	skge->use_xm_link_timer = 1;
+}
+
+static int xm_check_link(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 status;
+
+	/* read twice because of latch */
+	xm_phy_read(hw, port, PHY_XMAC_STAT);
+	status = xm_phy_read(hw, port, PHY_XMAC_STAT);
+
+	if ((status & PHY_ST_LSYNC) == 0) {
+		xm_link_down(hw, port);
+		return 0;
+	}
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		u16 lpa, res;
+
+		if (!(status & PHY_ST_AN_OVER))
+			return 0;
+
+		lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+		if (lpa & PHY_B_AN_RF) {
+			DBG(PFX "%s: remote fault\n",
+			       dev->name);
+			return 0;
+		}
+
+		res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
+
+		/* Check Duplex mismatch */
+		switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
+		case PHY_X_RS_FD:
+			skge->duplex = DUPLEX_FULL;
+			break;
+		case PHY_X_RS_HD:
+			skge->duplex = DUPLEX_HALF;
+			break;
+		default:
+			DBG(PFX "%s: duplex mismatch\n",
+			       dev->name);
+			return 0;
+		}
+
+		/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+		if ((skge->flow_control == FLOW_MODE_SYMMETRIC ||
+		     skge->flow_control == FLOW_MODE_SYM_OR_REM) &&
+		    (lpa & PHY_X_P_SYM_MD))
+			skge->flow_status = FLOW_STAT_SYMMETRIC;
+		else if (skge->flow_control == FLOW_MODE_SYM_OR_REM &&
+			 (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
+			/* Enable PAUSE receive, disable PAUSE transmit */
+			skge->flow_status  = FLOW_STAT_REM_SEND;
+		else if (skge->flow_control == FLOW_MODE_LOC_SEND &&
+			 (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
+			/* Disable PAUSE receive, enable PAUSE transmit */
+			skge->flow_status = FLOW_STAT_LOC_SEND;
+		else
+			skge->flow_status = FLOW_STAT_NONE;
+
+		skge->speed = SPEED_1000;
+	}
+
+	if (!netdev_link_ok(dev))
+		genesis_link_up(skge);
+	return 1;
+}
+
+/* Poll to check for link coming up.
+ *
+ * Since internal PHY is wired to a level triggered pin, can't
+ * get an interrupt when carrier is detected, need to poll for
+ * link coming up.
+ */
+static void xm_link_timer(struct skge_port *skge)
+{
+	struct net_device *dev = skge->netdev;
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	int i;
+
+	/*
+	 * Verify that the link by checking GPIO register three times.
+	 * This pin has the signal from the link_sync pin connected to it.
+	 */
+	for (i = 0; i < 3; i++) {
+		if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
+			return;
+	}
+
+        /* Re-enable interrupt to detect link down */
+	if (xm_check_link(dev)) {
+		u16 msk = xm_read16(hw, port, XM_IMSK);
+		msk &= ~XM_IS_INP_ASS;
+		xm_write16(hw, port, XM_IMSK, msk);
+		xm_read16(hw, port, XM_ISRC);
+	}
+}
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+	struct net_device *dev = hw->dev[port];
+	struct skge_port *skge = netdev_priv(dev);
+	int i;
+	u32 r;
+	const u8 zero[6]  = { 0 };
+
+	for (i = 0; i < 10; i++) {
+		skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
+			     MFF_SET_MAC_RST);
+		if (skge_read16(hw, SK_REG(port, TX_MFF_CTRL1)) & MFF_SET_MAC_RST)
+			goto reset_ok;
+		udelay(1);
+	}
+
+	DBG(PFX "%s: genesis reset failed\n", dev->name);
+
+ reset_ok:
+	/* Unreset the XMAC. */
+	skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+	/*
+	 * Perform additional initialization for external PHYs,
+	 * namely for the 1000baseTX cards that use the XMAC's
+	 * GMII mode.
+	 */
+	if (hw->phy_type != SK_PHY_XMAC) {
+		/* Take external Phy out of reset */
+		r = skge_read32(hw, B2_GP_IO);
+		if (port == 0)
+			r |= GP_DIR_0|GP_IO_0;
+		else
+			r |= GP_DIR_2|GP_IO_2;
+
+		skge_write32(hw, B2_GP_IO, r);
+
+		/* Enable GMII interface */
+		xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+	}
+
+
+	switch(hw->phy_type) {
+	case SK_PHY_XMAC:
+		xm_phy_init(skge);
+		break;
+	case SK_PHY_BCOM:
+		bcom_phy_init(skge);
+		bcom_check_link(hw, port);
+	}
+
+	/* Set Station Address */
+	xm_outaddr(hw, port, XM_SA, dev->ll_addr);
+
+	/* We don't use match addresses so clear */
+	for (i = 1; i < 16; i++)
+		xm_outaddr(hw, port, XM_EXM(i), zero);
+
+	/* Clear MIB counters */
+	xm_write16(hw, port, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+	/* Clear two times according to Errata #3 */
+	xm_write16(hw, port, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+	/* configure Rx High Water Mark (XM_RX_HI_WM) */
+	xm_write16(hw, port, XM_RX_HI_WM, 1450);
+
+	/* We don't need the FCS appended to the packet. */
+	r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+
+	if (skge->duplex == DUPLEX_HALF) {
+		/*
+		 * If in manual half duplex mode the other side might be in
+		 * full duplex mode, so ignore if a carrier extension is not seen
+		 * on frames received
+		 */
+		r |= XM_RX_DIS_CEXT;
+	}
+	xm_write16(hw, port, XM_RX_CMD, r);
+
+	/* We want short frames padded to 60 bytes. */
+	xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+	xm_write16(hw, port, XM_TX_THR, 512);
+
+	/*
+	 * Enable the reception of all error frames. This is is
+	 * a necessary evil due to the design of the XMAC. The
+	 * XMAC's receive FIFO is only 8K in size, however jumbo
+	 * frames can be up to 9000 bytes in length. When bad
+	 * frame filtering is enabled, the XMAC's RX FIFO operates
+	 * in 'store and forward' mode. For this to work, the
+	 * entire frame has to fit into the FIFO, but that means
+	 * that jumbo frames larger than 8192 bytes will be
+	 * truncated. Disabling all bad frame filtering causes
+	 * the RX FIFO to operate in streaming mode, in which
+	 * case the XMAC will start transferring frames out of the
+	 * RX FIFO as soon as the FIFO threshold is reached.
+	 */
+	xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
+
+
+	/*
+	 * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Rx OK Low CntOv'
+	 *	  and 'Octets Rx OK Hi Cnt Ov'.
+	 */
+	xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+	/*
+	 * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Tx OK Low CntOv'
+	 *	  and 'Octets Tx OK Hi Cnt Ov'.
+	 */
+	xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+	/* Configure MAC arbiter */
+	skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure timeout values */
+	skge_write8(hw, B3_MA_TOINI_RX1, 72);
+	skge_write8(hw, B3_MA_TOINI_RX2, 72);
+	skge_write8(hw, B3_MA_TOINI_TX1, 72);
+	skge_write8(hw, B3_MA_TOINI_TX2, 72);
+
+	skge_write8(hw, B3_MA_RCINI_RX1, 0);
+	skge_write8(hw, B3_MA_RCINI_RX2, 0);
+	skge_write8(hw, B3_MA_RCINI_TX1, 0);
+	skge_write8(hw, B3_MA_RCINI_TX2, 0);
+
+	/* Configure Rx MAC FIFO */
+	skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
+	skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
+	skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	/* Configure Tx MAC FIFO */
+	skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
+	skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+	skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	/* enable timeout timers */
+	skge_write16(hw, B3_PA_CTRL,
+		     (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+}
+
+static void genesis_stop(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	unsigned retries = 1000;
+	u16 cmd;
+
+	/* Disable Tx and Rx */
+	cmd = xm_read16(hw, port, XM_MMU_CMD);
+	cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+	xm_write16(hw, port, XM_MMU_CMD, cmd);
+
+	genesis_reset(hw, port);
+
+	/* Clear Tx packet arbiter timeout IRQ */
+	skge_write16(hw, B3_PA_CTRL,
+		     port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2);
+
+	/* Reset the MAC */
+	skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+	do {
+		skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+		if (!(skge_read16(hw, SK_REG(port, TX_MFF_CTRL1)) & MFF_SET_MAC_RST))
+			break;
+	} while (--retries > 0);
+
+	/* For external PHYs there must be special handling */
+	if (hw->phy_type != SK_PHY_XMAC) {
+		u32 reg = skge_read32(hw, B2_GP_IO);
+		if (port == 0) {
+			reg |= GP_DIR_0;
+			reg &= ~GP_IO_0;
+		} else {
+			reg |= GP_DIR_2;
+			reg &= ~GP_IO_2;
+		}
+		skge_write32(hw, B2_GP_IO, reg);
+		skge_read32(hw, B2_GP_IO);
+	}
+
+	xm_write16(hw, port, XM_MMU_CMD,
+			xm_read16(hw, port, XM_MMU_CMD)
+			& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+	xm_read16(hw, port, XM_MMU_CMD);
+}
+
+static void genesis_link_up(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 cmd, msk;
+	u32 mode;
+
+	cmd = xm_read16(hw, port, XM_MMU_CMD);
+
+	/*
+	 * enabling pause frame reception is required for 1000BT
+	 * because the XMAC is not reset if the link is going down
+	 */
+	if (skge->flow_status == FLOW_STAT_NONE ||
+	    skge->flow_status == FLOW_STAT_LOC_SEND)
+		/* Disable Pause Frame Reception */
+		cmd |= XM_MMU_IGN_PF;
+	else
+		/* Enable Pause Frame Reception */
+		cmd &= ~XM_MMU_IGN_PF;
+
+	xm_write16(hw, port, XM_MMU_CMD, cmd);
+
+	mode = xm_read32(hw, port, XM_MODE);
+	if (skge->flow_status== FLOW_STAT_SYMMETRIC ||
+	    skge->flow_status == FLOW_STAT_LOC_SEND) {
+		/*
+		 * Configure Pause Frame Generation
+		 * Use internal and external Pause Frame Generation.
+		 * Sending pause frames is edge triggered.
+		 * Send a Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition occurs.
+		 * Send a zero pause time frame to re-start transmission.
+		 */
+		/* XM_PAUSE_DA = '010000C28001' (default) */
+		/* XM_MAC_PTIME = 0xffff (maximum) */
+		/* remember this value is defined in big endian (!) */
+		xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+
+		mode |= XM_PAUSE_MODE;
+		skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+	} else {
+		/*
+		 * disable pause frame generation is required for 1000BT
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Disable Pause Mode in Mode Register */
+		mode &= ~XM_PAUSE_MODE;
+
+		skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+
+	xm_write32(hw, port, XM_MODE, mode);
+
+	/* Turn on detection of Tx underrun */
+	msk = xm_read16(hw, port, XM_IMSK);
+	msk &= ~XM_IS_TXF_UR;
+	xm_write16(hw, port, XM_IMSK, msk);
+
+	xm_read16(hw, port, XM_ISRC);
+
+	/* get MMU Command Reg. */
+	cmd = xm_read16(hw, port, XM_MMU_CMD);
+	if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+		cmd |= XM_MMU_GMII_FD;
+
+	/*
+	 * Workaround BCOM Errata (#10523) for all BCom Phys
+	 * Enable Power Management after link up
+	 */
+	if (hw->phy_type == SK_PHY_BCOM) {
+		xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+			     xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+			     & ~PHY_B_AC_DIS_PM);
+		xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+	}
+
+	/* enable Rx/Tx */
+	xm_write16(hw, port, XM_MMU_CMD,
+			cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+	skge_link_up(skge);
+}
+
+
+static inline void bcom_phy_intr(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 isrc;
+
+	isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+	DBGIO(PFX "%s: phy interrupt status 0x%x\n",
+	     skge->netdev->name, isrc);
+
+	if (isrc & PHY_B_IS_PSE)
+		DBG(PFX "%s: uncorrectable pair swap error\n",
+		    hw->dev[port]->name);
+
+	/* Workaround BCom Errata:
+	 *	enable and disable loopback mode if "NO HCD" occurs.
+	 */
+	if (isrc & PHY_B_IS_NO_HDCL) {
+		u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL);
+		xm_phy_write(hw, port, PHY_BCOM_CTRL,
+				  ctrl | PHY_CT_LOOP);
+		xm_phy_write(hw, port, PHY_BCOM_CTRL,
+				  ctrl & ~PHY_CT_LOOP);
+	}
+
+	if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+		bcom_check_link(hw, port);
+
+}
+
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_DATA, val);
+	gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+
+		if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+			return 0;
+	}
+
+	DBG(PFX "%s: phy write timeout port %x reg %x val %x\n",
+	    hw->dev[port]->name,
+	    port, reg, val);
+	return -EIO;
+}
+
+static int __gm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr)
+			 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+		if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+			goto ready;
+	}
+
+	return -ETIMEDOUT;
+ ready:
+	*val = gma_read16(hw, port, GM_SMI_DATA);
+	return 0;
+}
+
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+	u16 v = 0;
+	if (__gm_phy_read(hw, port, reg, &v))
+		DBG(PFX "%s: phy read timeout port %x reg %x val %x\n",
+	       hw->dev[port]->name,
+	       port, reg, v);
+	return v;
+}
+
+/* Marvell Phy Initialization */
+static void yukon_init(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	u16 ctrl, ct1000, adv;
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+
+		ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			  PHY_M_EC_MAC_S_MSK);
+		ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
+
+		ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+
+		gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+	}
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+	if (skge->autoneg == AUTONEG_DISABLE)
+		ctrl &= ~PHY_CT_ANE;
+
+	ctrl |= PHY_CT_RESET;
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	ctrl = 0;
+	ct1000 = 0;
+	adv = PHY_AN_CSMA;
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		if (hw->copper) {
+			if (skge->advertising & ADVERTISED_1000baseT_Full)
+				ct1000 |= PHY_M_1000C_AFD;
+			if (skge->advertising & ADVERTISED_1000baseT_Half)
+				ct1000 |= PHY_M_1000C_AHD;
+			if (skge->advertising & ADVERTISED_100baseT_Full)
+				adv |= PHY_M_AN_100_FD;
+			if (skge->advertising & ADVERTISED_100baseT_Half)
+				adv |= PHY_M_AN_100_HD;
+			if (skge->advertising & ADVERTISED_10baseT_Full)
+				adv |= PHY_M_AN_10_FD;
+			if (skge->advertising & ADVERTISED_10baseT_Half)
+				adv |= PHY_M_AN_10_HD;
+
+			/* Set Flow-control capabilities */
+			adv |= phy_pause_map[skge->flow_control];
+		} else {
+			if (skge->advertising & ADVERTISED_1000baseT_Full)
+				adv |= PHY_M_AN_1000X_AFD;
+			if (skge->advertising & ADVERTISED_1000baseT_Half)
+				adv |= PHY_M_AN_1000X_AHD;
+
+			adv |= fiber_pause_map[skge->flow_control];
+		}
+
+		/* Restart Auto-negotiation */
+		ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	} else {
+		/* forced speed/duplex settings */
+		ct1000 = PHY_M_1000C_MSE;
+
+		if (skge->duplex == DUPLEX_FULL)
+			ctrl |= PHY_CT_DUP_MD;
+
+		switch (skge->speed) {
+		case SPEED_1000:
+			ctrl |= PHY_CT_SP1000;
+			break;
+		case SPEED_100:
+			ctrl |= PHY_CT_SP100;
+			break;
+		}
+
+		ctrl |= PHY_CT_RESET;
+	}
+
+	gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+
+	gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	/* Enable phy interrupt on autonegotiation complete (or link up) */
+	if (skge->autoneg == AUTONEG_ENABLE)
+		gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_MSK);
+	else
+		gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_DEF_MSK);
+}
+
+static void yukon_reset(struct skge_hw *hw, int port)
+{
+	gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
+	gma_write16(hw, port, GM_MC_ADDR_H1, 0);	/* clear MC hash */
+	gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+	gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+	gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+
+	gma_write16(hw, port, GM_RX_CTRL,
+			 gma_read16(hw, port, GM_RX_CTRL)
+			 | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+}
+
+/* Apparently, early versions of Yukon-Lite had wrong chip_id? */
+static int is_yukon_lite_a0(struct skge_hw *hw)
+{
+	u32 reg;
+	int ret;
+
+	if (hw->chip_id != CHIP_ID_YUKON)
+		return 0;
+
+	reg = skge_read32(hw, B2_FAR);
+	skge_write8(hw, B2_FAR + 3, 0xff);
+	ret = (skge_read8(hw, B2_FAR + 3) != 0);
+	skge_write32(hw, B2_FAR, reg);
+	return ret;
+}
+
+static void yukon_mac_init(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	int i;
+	u32 reg;
+	const u8 *addr = hw->dev[port]->ll_addr;
+
+	/* WA code for COMA mode -- set PHY reset */
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    hw->chip_rev >= CHIP_REV_YU_LITE_A3) {
+		reg = skge_read32(hw, B2_GP_IO);
+		reg |= GP_DIR_9 | GP_IO_9;
+		skge_write32(hw, B2_GP_IO, reg);
+	}
+
+	/* hard reset */
+	skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+	skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
+
+	/* WA code for COMA mode -- clear PHY reset */
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    hw->chip_rev >= CHIP_REV_YU_LITE_A3) {
+		reg = skge_read32(hw, B2_GP_IO);
+		reg |= GP_DIR_9;
+		reg &= ~GP_IO_9;
+		skge_write32(hw, B2_GP_IO, reg);
+	}
+
+	/* Set hardware config mode */
+	reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+		GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE;
+	reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
+
+	/* Clear GMC reset */
+	skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
+	skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
+	skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+	if (skge->autoneg == AUTONEG_DISABLE) {
+		reg = GM_GPCR_AU_ALL_DIS;
+		gma_write16(hw, port, GM_GP_CTRL,
+				 gma_read16(hw, port, GM_GP_CTRL) | reg);
+
+		switch (skge->speed) {
+		case SPEED_1000:
+			reg &= ~GM_GPCR_SPEED_100;
+			reg |= GM_GPCR_SPEED_1000;
+			break;
+		case SPEED_100:
+			reg &= ~GM_GPCR_SPEED_1000;
+			reg |= GM_GPCR_SPEED_100;
+			break;
+		case SPEED_10:
+			reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
+			break;
+		}
+
+		if (skge->duplex == DUPLEX_FULL)
+			reg |= GM_GPCR_DUP_FULL;
+	} else
+		reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
+
+	switch (skge->flow_control) {
+	case FLOW_MODE_NONE:
+		skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+		reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+		break;
+	case FLOW_MODE_LOC_SEND:
+		/* disable Rx flow-control */
+		reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+		break;
+	case FLOW_MODE_SYMMETRIC:
+	case FLOW_MODE_SYM_OR_REM:
+		/* enable Tx & Rx flow-control */
+		break;
+	}
+
+	gma_write16(hw, port, GM_GP_CTRL, reg);
+	skge_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+	yukon_init(hw, port);
+
+	/* MIB clear */
+	reg = gma_read16(hw, port, GM_PHY_ADDR);
+	gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+
+	for (i = 0; i < GM_MIB_CNT_SIZE; i++)
+		gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+	gma_write16(hw, port, GM_PHY_ADDR, reg);
+
+	/* transmit control */
+	gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+
+	/* receive control reg: unicast + multicast + no FCS  */
+	gma_write16(hw, port, GM_RX_CTRL,
+			 GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
+
+	/* transmit flow control */
+	gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* transmit parameter */
+	gma_write16(hw, port, GM_TX_PARAM,
+			 TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
+			 TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
+			 TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
+
+	/* configure the Serial Mode Register */
+	reg = DATA_BLIND_VAL(DATA_BLIND_DEF)
+		| GM_SMOD_VLAN_ENA
+		| IPG_DATA_VAL(IPG_DATA_DEF);
+
+	gma_write16(hw, port, GM_SERIAL_MODE, reg);
+
+	/* physical address: used for pause frames */
+	gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+	/* virtual address for data */
+	gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+
+	/* enable interrupt mask for counter overflows */
+	gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+	gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+	gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+
+	/* Initialize Mac Fifo */
+
+	/* Configure Rx MAC FIFO */
+	skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+	reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+
+	/* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
+	if (is_yukon_lite_a0(hw))
+		reg &= ~GMF_RX_F_FL_ON;
+
+	skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+	skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+	/*
+	 * because Pause Packet Truncation in GMAC is not working
+	 * we have to increase the Flush Threshold to 64 bytes
+	 * in order to flush pause packets in Rx FIFO on Yukon-1
+	 */
+	skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
+
+	/* Configure Tx MAC FIFO */
+	skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+	skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+}
+
+/* Go into power down mode */
+static void yukon_suspend(struct skge_hw *hw, int port)
+{
+	u16 ctrl;
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+	ctrl |= PHY_M_PC_POL_R_DIS;
+	gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+	ctrl |= PHY_CT_RESET;
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	/* switch IEEE compatible power down mode on */
+	ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+	ctrl |= PHY_CT_PDOWN;
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+}
+
+static void yukon_stop(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
+	yukon_reset(hw, port);
+
+	gma_write16(hw, port, GM_GP_CTRL,
+			 gma_read16(hw, port, GM_GP_CTRL)
+			 & ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA));
+	gma_read16(hw, port, GM_GP_CTRL);
+
+	yukon_suspend(hw, port);
+
+	/* set GPHY Control reset */
+	skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+	skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
+}
+
+static u16 yukon_speed(const struct skge_hw *hw __unused, u16 aux)
+{
+	switch (aux & PHY_M_PS_SPEED_MSK) {
+	case PHY_M_PS_SPEED_1000:
+		return SPEED_1000;
+	case PHY_M_PS_SPEED_100:
+		return SPEED_100;
+	default:
+		return SPEED_10;
+	}
+}
+
+static void yukon_link_up(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 reg;
+
+	/* Enable Transmit FIFO Underrun */
+	skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
+
+	reg = gma_read16(hw, port, GM_GP_CTRL);
+	if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE)
+		reg |= GM_GPCR_DUP_FULL;
+
+	/* enable Rx/Tx */
+	reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
+	gma_write16(hw, port, GM_GP_CTRL, reg);
+
+	gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_DEF_MSK);
+	skge_link_up(skge);
+}
+
+static void yukon_link_down(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 ctrl;
+
+	ctrl = gma_read16(hw, port, GM_GP_CTRL);
+	ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+	gma_write16(hw, port, GM_GP_CTRL, ctrl);
+
+	if (skge->flow_status == FLOW_STAT_REM_SEND) {
+		ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
+		ctrl |= PHY_M_AN_ASP;
+		/* restore Asymmetric Pause bit */
+		gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl);
+	}
+
+	skge_link_down(skge);
+
+	yukon_init(hw, port);
+}
+
+static void yukon_phy_intr(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	const char *reason = NULL;
+	u16 istatus, phystat;
+
+	istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+	phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+	DBGIO(PFX "%s: phy interrupt status 0x%x 0x%x\n",
+	     skge->netdev->name, istatus, phystat);
+
+	if (istatus & PHY_M_IS_AN_COMPL) {
+		if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+		    & PHY_M_AN_RF) {
+			reason = "remote fault";
+			goto failed;
+		}
+
+		if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
+			reason = "master/slave fault";
+			goto failed;
+		}
+
+		if (!(phystat & PHY_M_PS_SPDUP_RES)) {
+			reason = "speed/duplex";
+			goto failed;
+		}
+
+		skge->duplex = (phystat & PHY_M_PS_FULL_DUP)
+			? DUPLEX_FULL : DUPLEX_HALF;
+		skge->speed = yukon_speed(hw, phystat);
+
+		/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+		switch (phystat & PHY_M_PS_PAUSE_MSK) {
+		case PHY_M_PS_PAUSE_MSK:
+			skge->flow_status = FLOW_STAT_SYMMETRIC;
+			break;
+		case PHY_M_PS_RX_P_EN:
+			skge->flow_status = FLOW_STAT_REM_SEND;
+			break;
+		case PHY_M_PS_TX_P_EN:
+			skge->flow_status = FLOW_STAT_LOC_SEND;
+			break;
+		default:
+			skge->flow_status = FLOW_STAT_NONE;
+		}
+
+		if (skge->flow_status == FLOW_STAT_NONE ||
+		    (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
+			skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+		else
+			skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+		yukon_link_up(skge);
+		return;
+	}
+
+	if (istatus & PHY_M_IS_LSP_CHANGE)
+		skge->speed = yukon_speed(hw, phystat);
+
+	if (istatus & PHY_M_IS_DUP_CHANGE)
+		skge->duplex = (phystat & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+	if (istatus & PHY_M_IS_LST_CHANGE) {
+		if (phystat & PHY_M_PS_LINK_UP)
+			yukon_link_up(skge);
+		else
+			yukon_link_down(skge);
+	}
+	return;
+ failed:
+	DBG(PFX "%s: autonegotiation failed (%s)\n",
+	       skge->netdev->name, reason);
+
+	/* XXX restart autonegotiation? */
+}
+
+static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len)
+{
+	u32 end;
+
+	start /= 8;
+	len /= 8;
+	end = start + len - 1;
+
+	skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR);
+	skge_write32(hw, RB_ADDR(q, RB_START), start);
+	skge_write32(hw, RB_ADDR(q, RB_WP), start);
+	skge_write32(hw, RB_ADDR(q, RB_RP), start);
+	skge_write32(hw, RB_ADDR(q, RB_END), end);
+
+	if (q == Q_R1 || q == Q_R2) {
+		/* Set thresholds on receive queue's */
+		skge_write32(hw, RB_ADDR(q, RB_RX_UTPP),
+			     start + (2*len)/3);
+		skge_write32(hw, RB_ADDR(q, RB_RX_LTPP),
+			     start + (len/3));
+	} else {
+		/* Enable store & forward on Tx queue's because
+		 * Tx FIFO is only 4K on Genesis and 1K on Yukon
+		 */
+		skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD);
+	}
+
+	skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD);
+}
+
+/* Setup Bus Memory Interface */
+static void skge_qset(struct skge_port *skge, u16 q,
+		      const struct skge_element *e)
+{
+	struct skge_hw *hw = skge->hw;
+	u32 watermark = 0x600;
+	u64 base = skge->dma + (e->desc - skge->mem);
+
+	/* optimization to reduce window on 32bit/33mhz */
+	if ((skge_read16(hw, B0_CTST) & (CS_BUS_CLOCK | CS_BUS_SLOT_SZ)) == 0)
+		watermark /= 2;
+
+	skge_write32(hw, Q_ADDR(q, Q_CSR), CSR_CLR_RESET);
+	skge_write32(hw, Q_ADDR(q, Q_F), watermark);
+	skge_write32(hw, Q_ADDR(q, Q_DA_H), (u32)(base >> 32));
+	skge_write32(hw, Q_ADDR(q, Q_DA_L), (u32)base);
+}
+
+void skge_free(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	free(skge->rx_ring.start);
+	skge->rx_ring.start = NULL;
+
+	free(skge->tx_ring.start);
+	skge->tx_ring.start = NULL;
+
+	free_dma(skge->mem, RING_SIZE);
+	skge->mem = NULL;
+	skge->dma = 0;
+}
+
+static int skge_up(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u32 chunk, ram_addr;
+	int err;
+
+	DBG2(PFX "%s: enabling interface\n", dev->name);
+
+	skge->mem = malloc_dma(RING_SIZE, SKGE_RING_ALIGN);
+	skge->dma = virt_to_bus(skge->mem);
+	if (!skge->mem)
+		return -ENOMEM;
+	memset(skge->mem, 0, RING_SIZE);
+
+	assert(!(skge->dma & 7));
+
+	/* FIXME: find out whether 64 bit iPXE will be loaded > 4GB */
+	if ((u64)skge->dma >> 32 != ((u64) skge->dma + RING_SIZE) >> 32) {
+		DBG(PFX "pci_alloc_consistent region crosses 4G boundary\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma, NUM_RX_DESC);
+	if (err)
+		goto err;
+
+	/* this call relies on e->iob and d->control to be 0
+	 * This is assured by calling memset() on skge->mem and using zalloc()
+	 * for the skge_element structures.
+	 */
+	skge_rx_refill(dev);
+
+	err = skge_ring_alloc(&skge->tx_ring, skge->mem + RX_RING_SIZE,
+			      skge->dma + RX_RING_SIZE, NUM_TX_DESC);
+	if (err)
+		goto err;
+
+	/* Initialize MAC */
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_mac_init(hw, port);
+	else
+		yukon_mac_init(hw, port);
+
+	/* Configure RAMbuffers - equally between ports and tx/rx */
+	chunk = (hw->ram_size  - hw->ram_offset) / (hw->ports * 2);
+	ram_addr = hw->ram_offset + 2 * chunk * port;
+
+	skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
+	skge_qset(skge, rxqaddr[port], skge->rx_ring.to_clean);
+
+	assert(!(skge->tx_ring.to_use != skge->tx_ring.to_clean));
+	skge_ramset(hw, txqaddr[port], ram_addr+chunk, chunk);
+	skge_qset(skge, txqaddr[port], skge->tx_ring.to_use);
+
+	/* Start receiver BMU */
+	wmb();
+	skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F);
+	skge_led(skge, LED_MODE_ON);
+
+	hw->intr_mask |= portmask[port];
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+
+	return 0;
+
+ err:
+	skge_rx_clean(skge);
+	skge_free(dev);
+
+	return err;
+}
+
+/* stop receiver */
+static void skge_rx_stop(struct skge_hw *hw, int port)
+{
+	skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP);
+	skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL),
+		     RB_RST_SET|RB_DIS_OP_MD);
+	skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
+}
+
+static void skge_down(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (skge->mem == NULL)
+		return;
+
+	DBG2(PFX "%s: disabling interface\n", dev->name);
+
+	if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
+		skge->use_xm_link_timer = 0;
+
+	netdev_link_down(dev);
+
+	hw->intr_mask &= ~portmask[port];
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+
+	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_stop(skge);
+	else
+		yukon_stop(skge);
+
+	/* Stop transmitter */
+	skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
+	skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
+		     RB_RST_SET|RB_DIS_OP_MD);
+
+
+	/* Disable Force Sync bit and Enable Alloc bit */
+	skge_write8(hw, SK_REG(port, TXA_CTRL),
+		    TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+	/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+	skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+	skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
+
+	/* Reset PCI FIFO */
+	skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
+	skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET);
+
+	/* Reset the RAM Buffer async Tx queue */
+	skge_write8(hw, RB_ADDR(port == 0 ? Q_XA1 : Q_XA2, RB_CTRL), RB_RST_SET);
+
+	skge_rx_stop(hw, port);
+
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
+		skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
+	} else {
+		skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+		skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+	}
+
+	skge_led(skge, LED_MODE_OFF);
+
+	skge_tx_clean(dev);
+
+	skge_rx_clean(skge);
+
+	skge_free(dev);
+	return;
+}
+
+static inline int skge_tx_avail(const struct skge_ring *ring)
+{
+	mb();
+	return ((ring->to_clean > ring->to_use) ? 0 : NUM_TX_DESC)
+		+ (ring->to_clean - ring->to_use) - 1;
+}
+
+static int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	struct skge_element *e;
+	struct skge_tx_desc *td;
+	u32 control, len;
+	u64 map;
+
+	if (skge_tx_avail(&skge->tx_ring) < 1)
+		return -EBUSY;
+
+	e = skge->tx_ring.to_use;
+	td = e->desc;
+	assert(!(td->control & BMU_OWN));
+	e->iob = iob;
+	len = iob_len(iob);
+	map = virt_to_bus(iob->data);
+
+	td->dma_lo = map;
+	td->dma_hi = map >> 32;
+
+	control = BMU_CHECK;
+
+	control |= BMU_EOF| BMU_IRQ_EOF;
+	/* Make sure all the descriptors written */
+	wmb();
+	td->control = BMU_OWN | BMU_SW | BMU_STF | control | len;
+	wmb();
+
+	skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START);
+
+	DBGIO(PFX "%s: tx queued, slot %td, len %d\n",
+	     dev->name, e - skge->tx_ring.start, (unsigned int)len);
+
+	skge->tx_ring.to_use = e->next;
+	wmb();
+
+	if (skge_tx_avail(&skge->tx_ring) <= 1) {
+		DBG(PFX "%s: transmit queue full\n", dev->name);
+	}
+
+	return 0;
+}
+
+/* Free all buffers in transmit ring */
+static void skge_tx_clean(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_element *e;
+
+	for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
+		struct skge_tx_desc *td = e->desc;
+		td->control = 0;
+	}
+
+	skge->tx_ring.to_clean = e;
+}
+
+static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
+
+static inline u16 phy_length(const struct skge_hw *hw, u32 status)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		return status >> XMR_FS_LEN_SHIFT;
+	else
+		return status >> GMR_FS_LEN_SHIFT;
+}
+
+static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		return (status & (XMR_FS_ERR | XMR_FS_2L_VLAN)) != 0;
+	else
+		return (status & GMR_FS_ANY_ERR) ||
+			(status & GMR_FS_RX_OK) == 0;
+}
+
+/* Free all buffers in Tx ring which are no longer owned by device */
+static void skge_tx_done(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_ring *ring = &skge->tx_ring;
+	struct skge_element *e;
+
+	skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
+	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+		u32 control = ((const struct skge_tx_desc *) e->desc)->control;
+
+		if (control & BMU_OWN)
+			break;
+
+		netdev_tx_complete(dev, e->iob);
+	}
+	skge->tx_ring.to_clean = e;
+
+	/* Can run lockless until we need to synchronize to restart queue. */
+	mb();
+}
+
+static void skge_rx_refill(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_element *e;
+	struct io_buffer *iob;
+	struct skge_rx_desc *rd;
+	u32 control;
+	int i;
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		e = ring->to_clean;
+		rd = e->desc;
+		iob = e->iob;
+		control = rd->control;
+
+		/* nothing to do here */
+		if (iob || (control & BMU_OWN))
+			continue;
+
+		DBG2("refilling rx desc %zd: ", (ring->to_clean - ring->start));
+
+		iob = alloc_iob(RX_BUF_SIZE);
+		if (iob) {
+			skge_rx_setup(skge, e, iob, RX_BUF_SIZE);
+		} else {
+			DBG("descr %zd: alloc_iob() failed\n",
+			     (ring->to_clean - ring->start));
+			/* We pass the descriptor to the NIC even if the
+			 * allocation failed. The card will stop as soon as it
+			 * encounters a descriptor with the OWN bit set to 0,
+			 * thus never getting to the next descriptor that might
+			 * contain a valid io_buffer. This would effectively
+			 * stall the receive.
+			 */
+			skge_rx_setup(skge, e, NULL, 0);
+		}
+
+		ring->to_clean = e->next;
+	}
+}
+
+static void skge_rx_done(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_rx_desc *rd;
+	struct skge_element *e;
+	struct io_buffer *iob;
+	u32 control;
+	u16 len;
+	int i;
+
+	e = ring->to_clean;
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		iob = e->iob;
+		rd = e->desc;
+
+		rmb();
+		control = rd->control;
+
+		if ((control & BMU_OWN))
+			break;
+
+		if (!iob)
+			continue;
+
+		len = control & BMU_BBC;
+
+		/* catch RX errors */
+		if ((bad_phy_status(skge->hw, rd->status)) ||
+		   (phy_length(skge->hw, rd->status) != len)) {
+			/* report receive errors */
+			DBG("rx error\n");
+			netdev_rx_err(dev, iob, -EIO);
+		} else {
+			DBG2("received packet, len %d\n", len);
+			iob_put(iob, len);
+			netdev_rx(dev, iob);
+		}
+
+		/* io_buffer passed to core, make sure we don't reuse it */
+		e->iob = NULL;
+
+		e = e->next;
+	}
+	skge_rx_refill(dev);
+}
+
+static void skge_poll(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	u32 status;
+
+	/* reading this register ACKs interrupts */
+	status = skge_read32(hw, B0_SP_ISRC);
+
+	/* Link event? */
+	if (status & IS_EXT_REG) {
+		skge_phyirq(hw);
+		if (skge->use_xm_link_timer)
+			xm_link_timer(skge);
+	}
+
+	skge_tx_done(dev);
+
+	skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
+	skge_rx_done(dev);
+
+	/* restart receiver */
+	wmb();
+	skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START);
+
+	skge_read32(hw, B0_IMSK);
+
+	return;
+}
+
+static void skge_phyirq(struct skge_hw *hw)
+{
+	int port;
+
+	for (port = 0; port < hw->ports; port++) {
+		struct net_device *dev = hw->dev[port];
+		struct skge_port *skge = netdev_priv(dev);
+
+		if (hw->chip_id != CHIP_ID_GENESIS)
+			yukon_phy_intr(skge);
+		else if (hw->phy_type == SK_PHY_BCOM)
+			bcom_phy_intr(skge);
+	}
+
+	hw->intr_mask |= IS_EXT_REG;
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+	skge_read32(hw, B0_IMSK);
+}
+
+static const struct {
+	u8 id;
+	const char *name;
+} skge_chips[] = {
+	{ CHIP_ID_GENESIS,	"Genesis" },
+	{ CHIP_ID_YUKON,	 "Yukon" },
+	{ CHIP_ID_YUKON_LITE,	 "Yukon-Lite"},
+	{ CHIP_ID_YUKON_LP,	 "Yukon-LP"},
+};
+
+static const char *skge_board_name(const struct skge_hw *hw)
+{
+	unsigned int i;
+	static char buf[16];
+
+	for (i = 0; i < ARRAY_SIZE(skge_chips); i++)
+		if (skge_chips[i].id == hw->chip_id)
+			return skge_chips[i].name;
+
+	snprintf(buf, sizeof buf, "chipid 0x%x", hw->chip_id);
+	return buf;
+}
+
+
+/*
+ * Setup the board data structure, but don't bring up
+ * the port(s)
+ */
+static int skge_reset(struct skge_hw *hw)
+{
+	u32 reg;
+	u16 ctst, pci_status;
+	u8 t8, mac_cfg, pmd_type;
+	int i;
+
+	ctst = skge_read16(hw, B0_CTST);
+
+	/* do a SW reset */
+	skge_write8(hw, B0_CTST, CS_RST_SET);
+	skge_write8(hw, B0_CTST, CS_RST_CLR);
+
+	/* clear PCI errors, if any */
+	skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	skge_write8(hw, B2_TST_CTRL2, 0);
+
+	pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+	pci_write_config_word(hw->pdev, PCI_STATUS,
+			      pci_status | PCI_STATUS_ERROR_BITS);
+	skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	skge_write8(hw, B0_CTST, CS_MRST_CLR);
+
+	/* restore CLK_RUN bits (for Yukon-Lite) */
+	skge_write16(hw, B0_CTST,
+		     ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
+
+	hw->chip_id = skge_read8(hw, B2_CHIP_ID);
+	hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
+	pmd_type = skge_read8(hw, B2_PMD_TYP);
+	hw->copper = (pmd_type == 'T' || pmd_type == '1');
+
+	switch (hw->chip_id) {
+	case CHIP_ID_GENESIS:
+		switch (hw->phy_type) {
+		case SK_PHY_XMAC:
+			hw->phy_addr = PHY_ADDR_XMAC;
+			break;
+		case SK_PHY_BCOM:
+			hw->phy_addr = PHY_ADDR_BCOM;
+			break;
+		default:
+			DBG(PFX "unsupported phy type 0x%x\n",
+			       hw->phy_type);
+			return -EOPNOTSUPP;
+		}
+		break;
+
+	case CHIP_ID_YUKON:
+	case CHIP_ID_YUKON_LITE:
+	case CHIP_ID_YUKON_LP:
+		if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
+			hw->copper = 1;
+
+		hw->phy_addr = PHY_ADDR_MARV;
+		break;
+
+	default:
+		DBG(PFX "unsupported chip type 0x%x\n",
+		       hw->chip_id);
+		return -EOPNOTSUPP;
+	}
+
+	mac_cfg = skge_read8(hw, B2_MAC_CFG);
+	hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2;
+	hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4;
+
+	/* read the adapters RAM size */
+	t8 = skge_read8(hw, B2_E_0);
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		if (t8 == 3) {
+			/* special case: 4 x 64k x 36, offset = 0x80000 */
+			hw->ram_size = 0x100000;
+			hw->ram_offset = 0x80000;
+		} else
+			hw->ram_size = t8 * 512;
+	}
+	else if (t8 == 0)
+		hw->ram_size = 0x20000;
+	else
+		hw->ram_size = t8 * 4096;
+
+	hw->intr_mask = IS_HW_ERR;
+
+	/* Use PHY IRQ for all but fiber based Genesis board */
+	if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
+		hw->intr_mask |= IS_EXT_REG;
+
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_init(hw);
+	else {
+		/* switch power to VCC (WA for VAUX problem) */
+		skge_write8(hw, B0_POWER_CTRL,
+			    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+
+		/* avoid boards with stuck Hardware error bits */
+		if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
+		    (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
+			DBG(PFX "stuck hardware sensor bit\n");
+			hw->intr_mask &= ~IS_HW_ERR;
+		}
+
+		/* Clear PHY COMA */
+		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg);
+		reg &= ~PCI_PHY_COMA;
+		pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg);
+		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+
+		for (i = 0; i < hw->ports; i++) {
+			skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+			skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+		}
+	}
+
+	/* turn off hardware timer (unused) */
+	skge_write8(hw, B2_TI_CTRL, TIM_STOP);
+	skge_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ);
+	skge_write8(hw, B0_LED, LED_STAT_ON);
+
+	/* enable the Tx Arbiters */
+	for (i = 0; i < hw->ports; i++)
+		skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
+
+	/* Initialize ram interface */
+	skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
+
+	skge_write8(hw, B3_RI_WTO_R1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XA1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XS1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_R1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XA1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XS1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_R2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XA2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XS2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_R2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XA2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+	skge_write32(hw, B0_HWE_IMSK, IS_ERR_MSK);
+
+	/* Set interrupt moderation for Transmit only
+	 * Receive interrupts avoided by NAPI
+	 */
+	skge_write32(hw, B2_IRQM_MSK, IS_XA1_F|IS_XA2_F);
+	skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
+	skge_write32(hw, B2_IRQM_CTRL, TIM_START);
+
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+
+	for (i = 0; i < hw->ports; i++) {
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			genesis_reset(hw, i);
+		else
+			yukon_reset(hw, i);
+	}
+
+	return 0;
+}
+
+/* Initialize network device */
+static struct net_device *skge_devinit(struct skge_hw *hw, int port,
+				       int highmem __unused)
+{
+	struct skge_port *skge;
+	struct net_device *dev = alloc_etherdev(sizeof(*skge));
+
+	if (!dev) {
+		DBG(PFX "etherdev alloc failed\n");
+		return NULL;
+	}
+
+	dev->dev = &hw->pdev->dev;
+
+	skge = netdev_priv(dev);
+	skge->netdev = dev;
+	skge->hw = hw;
+
+	/* Auto speed and flow control */
+	skge->autoneg = AUTONEG_ENABLE;
+	skge->flow_control = FLOW_MODE_SYM_OR_REM;
+	skge->duplex = -1;
+	skge->speed = -1;
+	skge->advertising = skge_supported_modes(hw);
+
+	hw->dev[port] = dev;
+
+	skge->port = port;
+
+	/* read the mac address */
+	memcpy(dev->hw_addr, (void *) (hw->regs + B2_MAC_1 + port*8), ETH_ALEN);
+
+	return dev;
+}
+
+static void skge_show_addr(struct net_device *dev)
+{
+	DBG2(PFX "%s: addr %s\n",
+	     dev->name, netdev_addr(dev));
+}
+
+static int skge_probe(struct pci_device *pdev)
+{
+	struct net_device *dev, *dev1;
+	struct skge_hw *hw;
+	int err, using_dac = 0;
+
+	adjust_pci_device(pdev);
+
+	err = -ENOMEM;
+	hw = zalloc(sizeof(*hw));
+	if (!hw) {
+		DBG(PFX "cannot allocate hardware struct\n");
+		goto err_out_free_regions;
+	}
+
+	hw->pdev = pdev;
+
+	hw->regs = (unsigned long)ioremap(pci_bar_start(pdev, PCI_BASE_ADDRESS_0),
+				SKGE_REG_SIZE);
+	if (!hw->regs) {
+		DBG(PFX "cannot map device registers\n");
+		goto err_out_free_hw;
+	}
+
+	err = skge_reset(hw);
+	if (err)
+		goto err_out_iounmap;
+
+	DBG(PFX " addr 0x%llx irq %d chip %s rev %d\n",
+	    (unsigned long long)pdev->ioaddr, pdev->irq,
+	    skge_board_name(hw), hw->chip_rev);
+
+	dev = skge_devinit(hw, 0, using_dac);
+	if (!dev)
+		goto err_out_led_off;
+
+	netdev_init ( dev, &skge_operations );
+
+	err = register_netdev(dev);
+	if (err) {
+		DBG(PFX "cannot register net device\n");
+		goto err_out_free_netdev;
+	}
+
+	skge_show_addr(dev);
+
+	if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
+		if (register_netdev(dev1) == 0)
+			skge_show_addr(dev1);
+		else {
+			/* Failure to register second port need not be fatal */
+			DBG(PFX "register of second port failed\n");
+			hw->dev[1] = NULL;
+			netdev_nullify(dev1);
+			netdev_put(dev1);
+		}
+	}
+	pci_set_drvdata(pdev, hw);
+
+	return 0;
+
+err_out_free_netdev:
+	netdev_nullify(dev);
+	netdev_put(dev);
+err_out_led_off:
+	skge_write16(hw, B0_LED, LED_STAT_OFF);
+err_out_iounmap:
+	iounmap((void*)hw->regs);
+err_out_free_hw:
+	free(hw);
+err_out_free_regions:
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void skge_remove(struct pci_device *pdev)
+{
+	struct skge_hw *hw  = pci_get_drvdata(pdev);
+	struct net_device *dev0, *dev1;
+
+	if (!hw)
+		return;
+
+	if ((dev1 = hw->dev[1]))
+		unregister_netdev(dev1);
+	dev0 = hw->dev[0];
+	unregister_netdev(dev0);
+
+	hw->intr_mask = 0;
+	skge_write32(hw, B0_IMSK, 0);
+	skge_read32(hw, B0_IMSK);
+
+	skge_write16(hw, B0_LED, LED_STAT_OFF);
+	skge_write8(hw, B0_CTST, CS_RST_SET);
+
+	if (dev1) {
+		netdev_nullify(dev1);
+		netdev_put(dev1);
+	}
+	netdev_nullify(dev0);
+	netdev_put(dev0);
+
+	iounmap((void*)hw->regs);
+	free(hw);
+	pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Enable or disable IRQ masking.
+ *
+ * @v netdev		Device to control.
+ * @v enable		Zero to mask off IRQ, non-zero to enable IRQ.
+ *
+ * This is a iPXE Network Driver API function.
+ */
+static void skge_net_irq ( struct net_device *dev, int enable ) {
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	if (enable)
+		hw->intr_mask |= portmask[skge->port];
+	else
+		hw->intr_mask &= ~portmask[skge->port];
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+}
+
+struct pci_driver skge_driver __pci_driver = {
+	.ids      = skge_id_table,
+	.id_count = ( sizeof (skge_id_table) / sizeof (skge_id_table[0]) ),
+	.probe    = skge_probe,
+	.remove   = skge_remove
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.h
new file mode 100755
index 0000000..8a6ba6b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/skge.h
@@ -0,0 +1,2623 @@
+/*
+ * Definitions for the new Marvell Yukon / SysKonnect driver.
+ */
+#ifndef _SKGE_H
+#define _SKGE_H
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* PCI config registers */
+#define PCI_DEV_REG1	0x40
+#define  PCI_PHY_COMA	0x8000000
+#define  PCI_VIO	0x2000000
+
+#define PCI_DEV_REG2	0x44
+#define  PCI_VPD_ROM_SZ	7L<<14	/* VPD ROM size 0=256, 1=512, ... */
+#define  PCI_REV_DESC	1<<2	/* Reverse Descriptor bytes */
+
+#define DRV_NAME		"skge"
+#define DRV_VERSION		"1.13"
+#define PFX			DRV_NAME " "
+
+#define NUM_TX_DESC		8
+#define NUM_RX_DESC		8
+
+/* mdeck used a 16 byte alignment, but datasheet says 8 bytes is sufficient */
+#define SKGE_RING_ALIGN		8
+#define RX_BUF_SIZE		1536
+#define PHY_RETRIES	        1000
+
+#define TX_RING_SIZE	( NUM_TX_DESC * sizeof ( struct skge_rx_desc ) )
+#define RX_RING_SIZE	( NUM_RX_DESC * sizeof ( struct skge_tx_desc ) )
+#define RING_SIZE	( TX_RING_SIZE + RX_RING_SIZE )
+
+#define SKGE_REG_SIZE	0x4000
+
+#define SKGE_EEPROM_MAGIC	0x9933aabb
+
+/* Added for iPXE ------------------ */
+
+/* from ethtool.h */
+#define AUTONEG_DISABLE	0x00
+#define AUTONEG_ENABLE	0x01
+
+#define DUPLEX_HALF	0x00
+#define DUPLEX_FULL	0x01
+
+#define SPEED_10	10
+#define SPEED_100	100
+#define SPEED_1000	1000
+
+#define ADVERTISED_10baseT_Half  	(1 << 0)
+#define ADVERTISED_10baseT_Full  	(1 << 1)
+#define ADVERTISED_100baseT_Half 	(1 << 2)
+#define ADVERTISED_100baseT_Full 	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+
+#define SUPPORTED_10baseT_Half  	(1 << 0)
+#define SUPPORTED_10baseT_Full  	(1 << 1)
+#define SUPPORTED_100baseT_Half 	(1 << 2)
+#define SUPPORTED_100baseT_Full 	(1 << 3)
+#define SUPPORTED_1000baseT_Half	(1 << 4)
+#define SUPPORTED_1000baseT_Full	(1 << 5)
+#define SUPPORTED_Autoneg		(1 << 6)
+#define SUPPORTED_TP			(1 << 7)
+#define SUPPORTED_FIBRE			(1 << 10)
+
+/* from kernel.h */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/* ----------------------------------- */
+
+#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
+			       PCI_STATUS_SIG_SYSTEM_ERROR | \
+			       PCI_STATUS_REC_MASTER_ABORT | \
+			       PCI_STATUS_REC_TARGET_ABORT | \
+			       PCI_STATUS_PARITY)
+
+enum csr_regs {
+	B0_RAP	= 0x0000,
+	B0_CTST	= 0x0004,
+	B0_LED	= 0x0006,
+	B0_POWER_CTRL	= 0x0007,
+	B0_ISRC	= 0x0008,
+	B0_IMSK	= 0x000c,
+	B0_HWE_ISRC	= 0x0010,
+	B0_HWE_IMSK	= 0x0014,
+	B0_SP_ISRC	= 0x0018,
+	B0_XM1_IMSK	= 0x0020,
+	B0_XM1_ISRC	= 0x0028,
+	B0_XM1_PHY_ADDR	= 0x0030,
+	B0_XM1_PHY_DATA	= 0x0034,
+	B0_XM2_IMSK	= 0x0040,
+	B0_XM2_ISRC	= 0x0048,
+	B0_XM2_PHY_ADDR	= 0x0050,
+	B0_XM2_PHY_DATA	= 0x0054,
+	B0_R1_CSR	= 0x0060,
+	B0_R2_CSR	= 0x0064,
+	B0_XS1_CSR	= 0x0068,
+	B0_XA1_CSR	= 0x006c,
+	B0_XS2_CSR	= 0x0070,
+	B0_XA2_CSR	= 0x0074,
+
+	B2_MAC_1	= 0x0100,
+	B2_MAC_2	= 0x0108,
+	B2_MAC_3	= 0x0110,
+	B2_CONN_TYP	= 0x0118,
+	B2_PMD_TYP	= 0x0119,
+	B2_MAC_CFG	= 0x011a,
+	B2_CHIP_ID	= 0x011b,
+	B2_E_0		= 0x011c,
+	B2_E_1		= 0x011d,
+	B2_E_2		= 0x011e,
+	B2_E_3		= 0x011f,
+	B2_FAR		= 0x0120,
+	B2_FDP		= 0x0124,
+	B2_LD_CTRL	= 0x0128,
+	B2_LD_TEST	= 0x0129,
+	B2_TI_INI	= 0x0130,
+	B2_TI_VAL	= 0x0134,
+	B2_TI_CTRL	= 0x0138,
+	B2_TI_TEST	= 0x0139,
+	B2_IRQM_INI	= 0x0140,
+	B2_IRQM_VAL	= 0x0144,
+	B2_IRQM_CTRL	= 0x0148,
+	B2_IRQM_TEST	= 0x0149,
+	B2_IRQM_MSK	= 0x014c,
+	B2_IRQM_HWE_MSK	= 0x0150,
+	B2_TST_CTRL1	= 0x0158,
+	B2_TST_CTRL2	= 0x0159,
+	B2_GP_IO	= 0x015c,
+	B2_I2C_CTRL	= 0x0160,
+	B2_I2C_DATA	= 0x0164,
+	B2_I2C_IRQ	= 0x0168,
+	B2_I2C_SW	= 0x016c,
+	B2_BSC_INI	= 0x0170,
+	B2_BSC_VAL	= 0x0174,
+	B2_BSC_CTRL	= 0x0178,
+	B2_BSC_STAT	= 0x0179,
+	B2_BSC_TST	= 0x017a,
+
+	B3_RAM_ADDR	= 0x0180,
+	B3_RAM_DATA_LO	= 0x0184,
+	B3_RAM_DATA_HI	= 0x0188,
+	B3_RI_WTO_R1	= 0x0190,
+	B3_RI_WTO_XA1	= 0x0191,
+	B3_RI_WTO_XS1	= 0x0192,
+	B3_RI_RTO_R1	= 0x0193,
+	B3_RI_RTO_XA1	= 0x0194,
+	B3_RI_RTO_XS1	= 0x0195,
+	B3_RI_WTO_R2	= 0x0196,
+	B3_RI_WTO_XA2	= 0x0197,
+	B3_RI_WTO_XS2	= 0x0198,
+	B3_RI_RTO_R2	= 0x0199,
+	B3_RI_RTO_XA2	= 0x019a,
+	B3_RI_RTO_XS2	= 0x019b,
+	B3_RI_TO_VAL	= 0x019c,
+	B3_RI_CTRL	= 0x01a0,
+	B3_RI_TEST	= 0x01a2,
+	B3_MA_TOINI_RX1	= 0x01b0,
+	B3_MA_TOINI_RX2	= 0x01b1,
+	B3_MA_TOINI_TX1	= 0x01b2,
+	B3_MA_TOINI_TX2	= 0x01b3,
+	B3_MA_TOVAL_RX1	= 0x01b4,
+	B3_MA_TOVAL_RX2	= 0x01b5,
+	B3_MA_TOVAL_TX1	= 0x01b6,
+	B3_MA_TOVAL_TX2	= 0x01b7,
+	B3_MA_TO_CTRL	= 0x01b8,
+	B3_MA_TO_TEST	= 0x01ba,
+	B3_MA_RCINI_RX1	= 0x01c0,
+	B3_MA_RCINI_RX2	= 0x01c1,
+	B3_MA_RCINI_TX1	= 0x01c2,
+	B3_MA_RCINI_TX2	= 0x01c3,
+	B3_MA_RCVAL_RX1	= 0x01c4,
+	B3_MA_RCVAL_RX2	= 0x01c5,
+	B3_MA_RCVAL_TX1	= 0x01c6,
+	B3_MA_RCVAL_TX2	= 0x01c7,
+	B3_MA_RC_CTRL	= 0x01c8,
+	B3_MA_RC_TEST	= 0x01ca,
+	B3_PA_TOINI_RX1	= 0x01d0,
+	B3_PA_TOINI_RX2	= 0x01d4,
+	B3_PA_TOINI_TX1	= 0x01d8,
+	B3_PA_TOINI_TX2	= 0x01dc,
+	B3_PA_TOVAL_RX1	= 0x01e0,
+	B3_PA_TOVAL_RX2	= 0x01e4,
+	B3_PA_TOVAL_TX1	= 0x01e8,
+	B3_PA_TOVAL_TX2	= 0x01ec,
+	B3_PA_CTRL	= 0x01f0,
+	B3_PA_TEST	= 0x01f2,
+};
+
+/*	B0_CTST			16 bit	Control/Status register */
+enum {
+	CS_CLK_RUN_HOT	= 1<<13,/* CLK_RUN hot m. (YUKON-Lite only) */
+	CS_CLK_RUN_RST	= 1<<12,/* CLK_RUN reset  (YUKON-Lite only) */
+	CS_CLK_RUN_ENA	= 1<<11,/* CLK_RUN enable (YUKON-Lite only) */
+	CS_VAUX_AVAIL	= 1<<10,/* VAUX available (YUKON only) */
+	CS_BUS_CLOCK	= 1<<9,	/* Bus Clock 0/1 = 33/66 MHz */
+	CS_BUS_SLOT_SZ	= 1<<8,	/* Slot Size 0/1 = 32/64 bit slot */
+	CS_ST_SW_IRQ	= 1<<7,	/* Set IRQ SW Request */
+	CS_CL_SW_IRQ	= 1<<6,	/* Clear IRQ SW Request */
+	CS_STOP_DONE	= 1<<5,	/* Stop Master is finished */
+	CS_STOP_MAST	= 1<<4,	/* Command Bit to stop the master */
+	CS_MRST_CLR	= 1<<3,	/* Clear Master reset	*/
+	CS_MRST_SET	= 1<<2,	/* Set Master reset	*/
+	CS_RST_CLR	= 1<<1,	/* Clear Software reset	*/
+	CS_RST_SET	= 1,	/* Set   Software reset	*/
+
+/*	B0_LED			 8 Bit	LED register */
+/* Bit  7.. 2:	reserved */
+	LED_STAT_ON	= 1<<1,	/* Status LED on	*/
+	LED_STAT_OFF	= 1,		/* Status LED off	*/
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+	PC_VAUX_ENA	= 1<<7,	/* Switch VAUX Enable  */
+	PC_VAUX_DIS	= 1<<6,	/* Switch VAUX Disable */
+	PC_VCC_ENA	= 1<<5,	/* Switch VCC Enable  */
+	PC_VCC_DIS	= 1<<4,	/* Switch VCC Disable */
+	PC_VAUX_ON	= 1<<3,	/* Switch VAUX On  */
+	PC_VAUX_OFF	= 1<<2,	/* Switch VAUX Off */
+	PC_VCC_ON	= 1<<1,	/* Switch VCC On  */
+	PC_VCC_OFF	= 1<<0,	/* Switch VCC Off */
+};
+
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+enum {
+	IS_ALL_MSK	= 0xbffffffful,	/* All Interrupt bits */
+	IS_HW_ERR	= 1<<31,	/* Interrupt HW Error */
+					/* Bit 30:	reserved */
+	IS_PA_TO_RX1	= 1<<29,	/* Packet Arb Timeout Rx1 */
+	IS_PA_TO_RX2	= 1<<28,	/* Packet Arb Timeout Rx2 */
+	IS_PA_TO_TX1	= 1<<27,	/* Packet Arb Timeout Tx1 */
+	IS_PA_TO_TX2	= 1<<26,	/* Packet Arb Timeout Tx2 */
+	IS_I2C_READY	= 1<<25,	/* IRQ on end of I2C Tx */
+	IS_IRQ_SW	= 1<<24,	/* SW forced IRQ	*/
+	IS_EXT_REG	= 1<<23,	/* IRQ from LM80 or PHY (GENESIS only) */
+					/* IRQ from PHY (YUKON only) */
+	IS_TIMINT	= 1<<22,	/* IRQ from Timer	*/
+	IS_MAC1		= 1<<21,	/* IRQ from MAC 1	*/
+	IS_LNK_SYNC_M1	= 1<<20,	/* Link Sync Cnt wrap MAC 1 */
+	IS_MAC2		= 1<<19,	/* IRQ from MAC 2	*/
+	IS_LNK_SYNC_M2	= 1<<18,	/* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+	IS_R1_B		= 1<<17,	/* Q_R1 End of Buffer */
+	IS_R1_F		= 1<<16,	/* Q_R1 End of Frame */
+	IS_R1_C		= 1<<15,	/* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+	IS_R2_B		= 1<<14,	/* Q_R2 End of Buffer */
+	IS_R2_F		= 1<<13,	/* Q_R2 End of Frame */
+	IS_R2_C		= 1<<12,	/* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+	IS_XS1_B	= 1<<11,	/* Q_XS1 End of Buffer */
+	IS_XS1_F	= 1<<10,	/* Q_XS1 End of Frame */
+	IS_XS1_C	= 1<<9,		/* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+	IS_XA1_B	= 1<<8,		/* Q_XA1 End of Buffer */
+	IS_XA1_F	= 1<<7,		/* Q_XA1 End of Frame */
+	IS_XA1_C	= 1<<6,		/* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+	IS_XS2_B	= 1<<5,		/* Q_XS2 End of Buffer */
+	IS_XS2_F	= 1<<4,		/* Q_XS2 End of Frame */
+	IS_XS2_C	= 1<<3,		/* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+	IS_XA2_B	= 1<<2,		/* Q_XA2 End of Buffer */
+	IS_XA2_F	= 1<<1,		/* Q_XA2 End of Frame */
+	IS_XA2_C	= 1<<0,		/* Q_XA2 Encoding Error */
+
+	IS_TO_PORT1	= IS_PA_TO_RX1 | IS_PA_TO_TX1,
+	IS_TO_PORT2	= IS_PA_TO_RX2 | IS_PA_TO_TX2,
+
+	IS_PORT_1	= IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1,
+	IS_PORT_2	= IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2,
+};
+
+
+/*	B2_IRQM_HWE_MSK	32 bit	IRQ Moderation HW Error Mask */
+enum {
+	IS_IRQ_TIST_OV	= 1<<13, /* Time Stamp Timer Overflow (YUKON only) */
+	IS_IRQ_SENSOR	= 1<<12, /* IRQ from Sensor (YUKON only) */
+	IS_IRQ_MST_ERR	= 1<<11, /* IRQ master error detected */
+	IS_IRQ_STAT	= 1<<10, /* IRQ status exception */
+	IS_NO_STAT_M1	= 1<<9,	/* No Rx Status from MAC 1 */
+	IS_NO_STAT_M2	= 1<<8,	/* No Rx Status from MAC 2 */
+	IS_NO_TIST_M1	= 1<<7,	/* No Time Stamp from MAC 1 */
+	IS_NO_TIST_M2	= 1<<6,	/* No Time Stamp from MAC 2 */
+	IS_RAM_RD_PAR	= 1<<5,	/* RAM Read  Parity Error */
+	IS_RAM_WR_PAR	= 1<<4,	/* RAM Write Parity Error */
+	IS_M1_PAR_ERR	= 1<<3,	/* MAC 1 Parity Error */
+	IS_M2_PAR_ERR	= 1<<2,	/* MAC 2 Parity Error */
+	IS_R1_PAR_ERR	= 1<<1,	/* Queue R1 Parity Error */
+	IS_R2_PAR_ERR	= 1<<0,	/* Queue R2 Parity Error */
+
+	IS_ERR_MSK	= IS_IRQ_MST_ERR | IS_IRQ_STAT
+			| IS_RAM_RD_PAR | IS_RAM_WR_PAR
+			| IS_M1_PAR_ERR | IS_M2_PAR_ERR
+			| IS_R1_PAR_ERR | IS_R2_PAR_ERR,
+};
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+enum {
+	TST_FRC_DPERR_MR = 1<<7, /* force DATAPERR on MST RD */
+	TST_FRC_DPERR_MW = 1<<6, /* force DATAPERR on MST WR */
+	TST_FRC_DPERR_TR = 1<<5, /* force DATAPERR on TRG RD */
+	TST_FRC_DPERR_TW = 1<<4, /* force DATAPERR on TRG WR */
+	TST_FRC_APERR_M	 = 1<<3, /* force ADDRPERR on MST */
+	TST_FRC_APERR_T	 = 1<<2, /* force ADDRPERR on TRG */
+	TST_CFG_WRITE_ON = 1<<1, /* Enable  Config Reg WR */
+	TST_CFG_WRITE_OFF= 1<<0, /* Disable Config Reg WR */
+};
+
+/*	B2_MAC_CFG		 8 bit	MAC Configuration / Chip Revision */
+enum {
+	CFG_CHIP_R_MSK	  = 0xf<<4,	/* Bit 7.. 4: Chip Revision */
+					/* Bit 3.. 2:	reserved */
+	CFG_DIS_M2_CLK	  = 1<<1,	/* Disable Clock for 2nd MAC */
+	CFG_SNG_MAC	  = 1<<0,	/* MAC Config: 0=2 MACs / 1=1 MAC*/
+};
+
+/*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
+enum {
+	CHIP_ID_GENESIS	   = 0x0a, /* Chip ID for GENESIS */
+	CHIP_ID_YUKON	   = 0xb0, /* Chip ID for YUKON */
+	CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
+	CHIP_ID_YUKON_LP   = 0xb2, /* Chip ID for YUKON-LP */
+	CHIP_ID_YUKON_XL   = 0xb3, /* Chip ID for YUKON-2 XL */
+	CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
+	CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
+
+	CHIP_REV_YU_LITE_A1  = 3,	/* Chip Rev. for YUKON-Lite A1,A2 */
+	CHIP_REV_YU_LITE_A3  = 7,	/* Chip Rev. for YUKON-Lite A3 */
+};
+
+/*	B2_TI_CTRL		 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+enum {
+	TIM_START	= 1<<2,	/* Start Timer */
+	TIM_STOP	= 1<<1,	/* Stop  Timer */
+	TIM_CLR_IRQ	= 1<<0,	/* Clear Timer IRQ (!IRQM) */
+};
+
+/*	B2_TI_TEST		 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST		 8 bit	Descriptor Poll Timer Test Reg */
+enum {
+	TIM_T_ON	= 1<<2,	/* Test mode on */
+	TIM_T_OFF	= 1<<1,	/* Test mode off */
+	TIM_T_STEP	= 1<<0,	/* Test step */
+};
+
+/*	B2_GP_IO		32 bit	General Purpose I/O Register */
+enum {
+	GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */
+	GP_DIR_8 = 1<<24, /* IO_8 direct, 0=In/1=Out */
+	GP_DIR_7 = 1<<23, /* IO_7 direct, 0=In/1=Out */
+	GP_DIR_6 = 1<<22, /* IO_6 direct, 0=In/1=Out */
+	GP_DIR_5 = 1<<21, /* IO_5 direct, 0=In/1=Out */
+	GP_DIR_4 = 1<<20, /* IO_4 direct, 0=In/1=Out */
+	GP_DIR_3 = 1<<19, /* IO_3 direct, 0=In/1=Out */
+	GP_DIR_2 = 1<<18, /* IO_2 direct, 0=In/1=Out */
+	GP_DIR_1 = 1<<17, /* IO_1 direct, 0=In/1=Out */
+	GP_DIR_0 = 1<<16, /* IO_0 direct, 0=In/1=Out */
+
+	GP_IO_9	= 1<<9,	/* IO_9 pin */
+	GP_IO_8	= 1<<8,	/* IO_8 pin */
+	GP_IO_7	= 1<<7,	/* IO_7 pin */
+	GP_IO_6	= 1<<6,	/* IO_6 pin */
+	GP_IO_5	= 1<<5,	/* IO_5 pin */
+	GP_IO_4	= 1<<4,	/* IO_4 pin */
+	GP_IO_3	= 1<<3,	/* IO_3 pin */
+	GP_IO_2	= 1<<2,	/* IO_2 pin */
+	GP_IO_1	= 1<<1,	/* IO_1 pin */
+	GP_IO_0	= 1<<0,	/* IO_0 pin */
+};
+
+/* Descriptor Bit Definition */
+/*	TxCtrl		Transmit Buffer Control Field */
+/*	RxCtrl		Receive  Buffer Control Field */
+enum {
+	BMU_OWN		= 1<<31, /* OWN bit: 0=host/1=BMU */
+	BMU_STF		= 1<<30, /* Start of Frame */
+	BMU_EOF		= 1<<29, /* End of Frame */
+	BMU_IRQ_EOB	= 1<<28, /* Req "End of Buffer" IRQ */
+	BMU_IRQ_EOF	= 1<<27, /* Req "End of Frame" IRQ */
+				/* TxCtrl specific bits */
+	BMU_STFWD	= 1<<26, /* (Tx)	Store & Forward Frame */
+	BMU_NO_FCS	= 1<<25, /* (Tx) Disable MAC FCS (CRC) generation */
+	BMU_SW	= 1<<24, /* (Tx)	1 bit res. for SW use */
+				/* RxCtrl specific bits */
+	BMU_DEV_0	= 1<<26, /* (Rx)	Transfer data to Dev0 */
+	BMU_STAT_VAL	= 1<<25, /* (Rx)	Rx Status Valid */
+	BMU_TIST_VAL	= 1<<24, /* (Rx)	Rx TimeStamp Valid */
+			/* Bit 23..16:	BMU Check Opcodes */
+	BMU_CHECK	= 0x55<<16, /* Default BMU check */
+	BMU_TCP_CHECK	= 0x56<<16, /* Descr with TCP ext */
+	BMU_UDP_CHECK	= 0x57<<16, /* Descr with UDP ext (YUKON only) */
+	BMU_BBC		= 0xffffL, /* Bit 15.. 0:	Buffer Byte Counter */
+};
+
+/*	B2_BSC_CTRL		 8 bit	Blink Source Counter Control */
+enum {
+	 BSC_START	= 1<<1,	/* Start Blink Source Counter */
+	 BSC_STOP	= 1<<0,	/* Stop  Blink Source Counter */
+};
+
+/*	B2_BSC_STAT		 8 bit	Blink Source Counter Status */
+enum {
+	BSC_SRC		= 1<<0,	/* Blink Source, 0=Off / 1=On */
+};
+
+/*	B2_BSC_TST		16 bit	Blink Source Counter Test Reg */
+enum {
+	BSC_T_ON	= 1<<2,	/* Test mode on */
+	BSC_T_OFF	= 1<<1,	/* Test mode off */
+	BSC_T_STEP	= 1<<0,	/* Test step */
+};
+
+/*	B3_RAM_ADDR		32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+/* RAM Interface Registers */
+
+/*	B3_RI_CTRL		16 bit	RAM Iface Control Register */
+enum {
+	RI_CLR_RD_PERR	= 1<<9,	/* Clear IRQ RAM Read Parity Err */
+	RI_CLR_WR_PERR	= 1<<8,	/* Clear IRQ RAM Write Parity Err*/
+
+	RI_RST_CLR	= 1<<1,	/* Clear RAM Interface Reset */
+	RI_RST_SET	= 1<<0,	/* Set   RAM Interface Reset */
+};
+
+/* MAC Arbiter Registers */
+/*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
+enum {
+	MA_FOE_ON	= 1<<3,	/* XMAC Fast Output Enable ON */
+	MA_FOE_OFF	= 1<<2,	/* XMAC Fast Output Enable OFF */
+	MA_RST_CLR	= 1<<1,	/* Clear MAC Arbiter Reset */
+	MA_RST_SET	= 1<<0,	/* Set   MAC Arbiter Reset */
+
+};
+
+/* Timeout values */
+#define SK_MAC_TO_53	72		/* MAC arbiter timeout */
+#define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
+#define SK_PKT_TO_MAX	0xffff		/* Maximum value */
+#define SK_RI_TO_53	36		/* RAM interface timeout */
+
+/* Packet Arbiter Registers */
+/*	B3_PA_CTRL		16 bit	Packet Arbiter Ctrl Register */
+enum {
+	PA_CLR_TO_TX2	= 1<<13,/* Clear IRQ Packet Timeout TX2 */
+	PA_CLR_TO_TX1	= 1<<12,/* Clear IRQ Packet Timeout TX1 */
+	PA_CLR_TO_RX2	= 1<<11,/* Clear IRQ Packet Timeout RX2 */
+	PA_CLR_TO_RX1	= 1<<10,/* Clear IRQ Packet Timeout RX1 */
+	PA_ENA_TO_TX2	= 1<<9,	/* Enable  Timeout Timer TX2 */
+	PA_DIS_TO_TX2	= 1<<8,	/* Disable Timeout Timer TX2 */
+	PA_ENA_TO_TX1	= 1<<7,	/* Enable  Timeout Timer TX1 */
+	PA_DIS_TO_TX1	= 1<<6,	/* Disable Timeout Timer TX1 */
+	PA_ENA_TO_RX2	= 1<<5,	/* Enable  Timeout Timer RX2 */
+	PA_DIS_TO_RX2	= 1<<4,	/* Disable Timeout Timer RX2 */
+	PA_ENA_TO_RX1	= 1<<3,	/* Enable  Timeout Timer RX1 */
+	PA_DIS_TO_RX1	= 1<<2,	/* Disable Timeout Timer RX1 */
+	PA_RST_CLR	= 1<<1,	/* Clear MAC Arbiter Reset */
+	PA_RST_SET	= 1<<0,	/* Set   MAC Arbiter Reset */
+};
+
+#define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+						PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
+/*	TXA_ITI_INI		32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL		32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI		32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL		32 bit	Tx Arb Limit Counter Value */
+
+#define TXA_MAX_VAL	0x00ffffffUL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL		 8 bit	Tx Arbiter Control Register */
+enum {
+	TXA_ENA_FSYNC	= 1<<7,	/* Enable  force of sync Tx queue */
+	TXA_DIS_FSYNC	= 1<<6,	/* Disable force of sync Tx queue */
+	TXA_ENA_ALLOC	= 1<<5,	/* Enable  alloc of free bandwidth */
+	TXA_DIS_ALLOC	= 1<<4,	/* Disable alloc of free bandwidth */
+	TXA_START_RC	= 1<<3,	/* Start sync Rate Control */
+	TXA_STOP_RC	= 1<<2,	/* Stop  sync Rate Control */
+	TXA_ENA_ARB	= 1<<1,	/* Enable  Tx Arbiter */
+	TXA_DIS_ARB	= 1<<0,	/* Disable Tx Arbiter */
+};
+
+/*
+ *	Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
+enum {
+	TXA_ITI_INI	= 0x0200,/* 32 bit	Tx Arb Interval Timer Init Val*/
+	TXA_ITI_VAL	= 0x0204,/* 32 bit	Tx Arb Interval Timer Value */
+	TXA_LIM_INI	= 0x0208,/* 32 bit	Tx Arb Limit Counter Init Val */
+	TXA_LIM_VAL	= 0x020c,/* 32 bit	Tx Arb Limit Counter Value */
+	TXA_CTRL	= 0x0210,/*  8 bit	Tx Arbiter Control Register */
+	TXA_TEST	= 0x0211,/*  8 bit	Tx Arbiter Test Register */
+	TXA_STAT	= 0x0212,/*  8 bit	Tx Arbiter Status Register */
+};
+
+
+enum {
+	B6_EXT_REG	= 0x0300,/* External registers (GENESIS only) */
+	B7_CFG_SPC	= 0x0380,/* copy of the Configuration register */
+	B8_RQ1_REGS	= 0x0400,/* Receive Queue 1 */
+	B8_RQ2_REGS	= 0x0480,/* Receive Queue 2 */
+	B8_TS1_REGS	= 0x0600,/* Transmit sync queue 1 */
+	B8_TA1_REGS	= 0x0680,/* Transmit async queue 1 */
+	B8_TS2_REGS	= 0x0700,/* Transmit sync queue 2 */
+	B8_TA2_REGS	= 0x0780,/* Transmit sync queue 2 */
+	B16_RAM_REGS	= 0x0800,/* RAM Buffer Registers */
+};
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+enum {
+	B8_Q_REGS = 0x0400, /* base of Queue registers */
+	Q_D	= 0x00,	/* 8*32	bit	Current Descriptor */
+	Q_DA_L	= 0x20,	/* 32 bit	Current Descriptor Address Low dWord */
+	Q_DA_H	= 0x24,	/* 32 bit	Current Descriptor Address High dWord */
+	Q_AC_L	= 0x28,	/* 32 bit	Current Address Counter Low dWord */
+	Q_AC_H	= 0x2c,	/* 32 bit	Current Address Counter High dWord */
+	Q_BC	= 0x30,	/* 32 bit	Current Byte Counter */
+	Q_CSR	= 0x34,	/* 32 bit	BMU Control/Status Register */
+	Q_F	= 0x38,	/* 32 bit	Flag Register */
+	Q_T1	= 0x3c,	/* 32 bit	Test Register 1 */
+	Q_T1_TR	= 0x3c,	/*  8 bit	Test Register 1 Transfer SM */
+	Q_T1_WR	= 0x3d,	/*  8 bit	Test Register 1 Write Descriptor SM */
+	Q_T1_RD	= 0x3e,	/*  8 bit	Test Register 1 Read Descriptor SM */
+	Q_T1_SV	= 0x3f,	/*  8 bit	Test Register 1 Supervisor SM */
+	Q_T2	= 0x40,	/* 32 bit	Test Register 2	*/
+	Q_T3	= 0x44,	/* 32 bit	Test Register 3	*/
+
+};
+#define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
+
+/* RAM Buffer Register Offsets */
+enum {
+
+	RB_START= 0x00,/* 32 bit	RAM Buffer Start Address */
+	RB_END	= 0x04,/* 32 bit	RAM Buffer End Address */
+	RB_WP	= 0x08,/* 32 bit	RAM Buffer Write Pointer */
+	RB_RP	= 0x0c,/* 32 bit	RAM Buffer Read Pointer */
+	RB_RX_UTPP= 0x10,/* 32 bit	Rx Upper Threshold, Pause Packet */
+	RB_RX_LTPP= 0x14,/* 32 bit	Rx Lower Threshold, Pause Packet */
+	RB_RX_UTHP= 0x18,/* 32 bit	Rx Upper Threshold, High Prio */
+	RB_RX_LTHP= 0x1c,/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+	RB_PC	= 0x20,/* 32 bit	RAM Buffer Packet Counter */
+	RB_LEV	= 0x24,/* 32 bit	RAM Buffer Level Register */
+	RB_CTRL	= 0x28,/* 32 bit	RAM Buffer Control Register */
+	RB_TST1	= 0x29,/*  8 bit	RAM Buffer Test Register 1 */
+	RB_TST2	= 0x2a,/*  8 bit	RAM Buffer Test Register 2 */
+};
+
+/* Receive and Transmit Queues */
+enum {
+	Q_R1	= 0x0000,	/* Receive Queue 1 */
+	Q_R2	= 0x0080,	/* Receive Queue 2 */
+	Q_XS1	= 0x0200,	/* Synchronous Transmit Queue 1 */
+	Q_XA1	= 0x0280,	/* Asynchronous Transmit Queue 1 */
+	Q_XS2	= 0x0300,	/* Synchronous Transmit Queue 2 */
+	Q_XA2	= 0x0380,	/* Asynchronous Transmit Queue 2 */
+};
+
+/* Different MAC Types */
+enum {
+	SK_MAC_XMAC =	0,	/* Xaqti XMAC II */
+	SK_MAC_GMAC =	1,	/* Marvell GMAC */
+};
+
+/* Different PHY Types */
+enum {
+	SK_PHY_XMAC	= 0,/* integrated in XMAC II */
+	SK_PHY_BCOM	= 1,/* Broadcom BCM5400 */
+	SK_PHY_LONE	= 2,/* Level One LXT1000  [not supported]*/
+	SK_PHY_NAT	= 3,/* National DP83891  [not supported] */
+	SK_PHY_MARV_COPPER= 4,/* Marvell 88E1011S */
+	SK_PHY_MARV_FIBER = 5,/* Marvell 88E1011S working on fiber */
+};
+
+/* PHY addresses (bits 12..8 of PHY address reg) */
+enum {
+	PHY_ADDR_XMAC	= 0<<8,
+	PHY_ADDR_BCOM	= 1<<8,
+
+/* GPHY address (bits 15..11 of SMI control reg) */
+	PHY_ADDR_MARV	= 0,
+};
+
+#define RB_ADDR(offs, queue) ((u16)B16_RAM_REGS + (u16)(queue) + (offs))
+
+/* Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only) */
+enum {
+	RX_MFF_EA	= 0x0c00,/* 32 bit	Receive MAC FIFO End Address */
+	RX_MFF_WP	= 0x0c04,/* 32 bit	Receive MAC FIFO Write Pointer */
+
+	RX_MFF_RP	= 0x0c0c,/* 32 bit	Receive MAC FIFO Read Pointer */
+	RX_MFF_PC	= 0x0c10,/* 32 bit	Receive MAC FIFO Packet Cnt */
+	RX_MFF_LEV	= 0x0c14,/* 32 bit	Receive MAC FIFO Level */
+	RX_MFF_CTRL1	= 0x0c18,/* 16 bit	Receive MAC FIFO Control Reg 1*/
+	RX_MFF_STAT_TO	= 0x0c1a,/*  8 bit	Receive MAC Status Timeout */
+	RX_MFF_TIST_TO	= 0x0c1b,/*  8 bit	Receive MAC Time Stamp Timeout */
+	RX_MFF_CTRL2	= 0x0c1c,/*  8 bit	Receive MAC FIFO Control Reg 2*/
+	RX_MFF_TST1	= 0x0c1d,/*  8 bit	Receive MAC FIFO Test Reg 1 */
+	RX_MFF_TST2	= 0x0c1e,/*  8 bit	Receive MAC FIFO Test Reg 2 */
+
+	RX_LED_INI	= 0x0c20,/* 32 bit	Receive LED Cnt Init Value */
+	RX_LED_VAL	= 0x0c24,/* 32 bit	Receive LED Cnt Current Value */
+	RX_LED_CTRL	= 0x0c28,/*  8 bit	Receive LED Cnt Control Reg */
+	RX_LED_TST	= 0x0c29,/*  8 bit	Receive LED Cnt Test Register */
+
+	LNK_SYNC_INI	= 0x0c30,/* 32 bit	Link Sync Cnt Init Value */
+	LNK_SYNC_VAL	= 0x0c34,/* 32 bit	Link Sync Cnt Current Value */
+	LNK_SYNC_CTRL	= 0x0c38,/*  8 bit	Link Sync Cnt Control Register */
+	LNK_SYNC_TST	= 0x0c39,/*  8 bit	Link Sync Cnt Test Register */
+	LNK_LED_REG	= 0x0c3c,/*  8 bit	Link LED Register */
+};
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+/*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
+enum {
+	MFF_ENA_RDY_PAT	= 1<<13,	/* Enable  Ready Patch */
+	MFF_DIS_RDY_PAT	= 1<<12,	/* Disable Ready Patch */
+	MFF_ENA_TIM_PAT	= 1<<11,	/* Enable  Timing Patch */
+	MFF_DIS_TIM_PAT	= 1<<10,	/* Disable Timing Patch */
+	MFF_ENA_ALM_FUL	= 1<<9,	/* Enable  AlmostFull Sign */
+	MFF_DIS_ALM_FUL	= 1<<8,	/* Disable AlmostFull Sign */
+	MFF_ENA_PAUSE	= 1<<7,	/* Enable  Pause Signaling */
+	MFF_DIS_PAUSE	= 1<<6,	/* Disable Pause Signaling */
+	MFF_ENA_FLUSH	= 1<<5,	/* Enable  Frame Flushing */
+	MFF_DIS_FLUSH	= 1<<4,	/* Disable Frame Flushing */
+	MFF_ENA_TIST	= 1<<3,	/* Enable  Time Stamp Gener */
+	MFF_DIS_TIST	= 1<<2,	/* Disable Time Stamp Gener */
+	MFF_CLR_INTIST	= 1<<1,	/* Clear IRQ No Time Stamp */
+	MFF_CLR_INSTAT	= 1<<0,	/* Clear IRQ No Status */
+	MFF_RX_CTRL_DEF = MFF_ENA_TIM_PAT,
+};
+
+/*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
+enum {
+	MFF_CLR_PERR	= 1<<15, /* Clear Parity Error IRQ */
+
+	MFF_ENA_PKT_REC	= 1<<13, /* Enable  Packet Recovery */
+	MFF_DIS_PKT_REC	= 1<<12, /* Disable Packet Recovery */
+
+	MFF_ENA_W4E	= 1<<7,	/* Enable  Wait for Empty */
+	MFF_DIS_W4E	= 1<<6,	/* Disable Wait for Empty */
+
+	MFF_ENA_LOOPB	= 1<<3,	/* Enable  Loopback */
+	MFF_DIS_LOOPB	= 1<<2,	/* Disable Loopback */
+	MFF_CLR_MAC_RST	= 1<<1,	/* Clear XMAC Reset */
+	MFF_SET_MAC_RST	= 1<<0,	/* Set   XMAC Reset */
+
+	MFF_TX_CTRL_DEF	 = MFF_ENA_PKT_REC | (u16) MFF_ENA_TIM_PAT | MFF_ENA_FLUSH,
+};
+
+
+/*	RX_MFF_TST2	 	 8 bit	Receive MAC FIFO Test Register 2 */
+/*	TX_MFF_TST2	 	 8 bit	Transmit MAC FIFO Test Register 2 */
+enum {
+	MFF_WSP_T_ON	= 1<<6,	/* Tx: Write Shadow Ptr TestOn */
+	MFF_WSP_T_OFF	= 1<<5,	/* Tx: Write Shadow Ptr TstOff */
+	MFF_WSP_INC	= 1<<4,	/* Tx: Write Shadow Ptr Increment */
+	MFF_PC_DEC	= 1<<3,	/* Packet Counter Decrement */
+	MFF_PC_T_ON	= 1<<2,	/* Packet Counter Test On */
+	MFF_PC_T_OFF	= 1<<1,	/* Packet Counter Test Off */
+	MFF_PC_INC	= 1<<0,	/* Packet Counter Increment */
+};
+
+/*	RX_MFF_TST1	 	 8 bit	Receive MAC FIFO Test Register 1 */
+/*	TX_MFF_TST1	 	 8 bit	Transmit MAC FIFO Test Register 1 */
+enum {
+	MFF_WP_T_ON	= 1<<6,	/* Write Pointer Test On */
+	MFF_WP_T_OFF	= 1<<5,	/* Write Pointer Test Off */
+	MFF_WP_INC	= 1<<4,	/* Write Pointer Increm */
+
+	MFF_RP_T_ON	= 1<<2,	/* Read Pointer Test On */
+	MFF_RP_T_OFF	= 1<<1,	/* Read Pointer Test Off */
+	MFF_RP_DEC	= 1<<0,	/* Read Pointer Decrement */
+};
+
+/*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
+/*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
+enum {
+	MFF_ENA_OP_MD	= 1<<3,	/* Enable  Operation Mode */
+	MFF_DIS_OP_MD	= 1<<2,	/* Disable Operation Mode */
+	MFF_RST_CLR	= 1<<1,	/* Clear MAC FIFO Reset */
+	MFF_RST_SET	= 1<<0,	/* Set   MAC FIFO Reset */
+};
+
+
+/*	Link LED Counter Registers (GENESIS only) */
+
+/*	RX_LED_CTRL		 8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL		 8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
+enum {
+	LED_START	= 1<<2,	/* Start Timer */
+	LED_STOP	= 1<<1,	/* Stop Timer */
+	LED_STATE	= 1<<0,	/* Rx/Tx: LED State, 1=LED on */
+};
+
+/*	RX_LED_TST		 8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST		 8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
+enum {
+	LED_T_ON	= 1<<2,	/* LED Counter Test mode On */
+	LED_T_OFF	= 1<<1,	/* LED Counter Test mode Off */
+	LED_T_STEP	= 1<<0,	/* LED Counter Step */
+};
+
+/*	LNK_LED_REG	 	 8 bit	Link LED Register */
+enum {
+	LED_BLK_ON	= 1<<5,	/* Link LED Blinking On */
+	LED_BLK_OFF	= 1<<4,	/* Link LED Blinking Off */
+	LED_SYNC_ON	= 1<<3,	/* Use Sync Wire to switch LED */
+	LED_SYNC_OFF	= 1<<2,	/* Disable Sync Wire Input */
+	LED_ON	= 1<<1,	/* switch LED on */
+	LED_OFF	= 1<<0,	/* switch LED off */
+};
+
+/* Receive GMAC FIFO (YUKON) */
+enum {
+	RX_GMF_EA	= 0x0c40,/* 32 bit	Rx GMAC FIFO End Address */
+	RX_GMF_AF_THR	= 0x0c44,/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+	RX_GMF_CTRL_T	= 0x0c48,/* 32 bit	Rx GMAC FIFO Control/Test */
+	RX_GMF_FL_MSK	= 0x0c4c,/* 32 bit	Rx GMAC FIFO Flush Mask */
+	RX_GMF_FL_THR	= 0x0c50,/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	RX_GMF_WP	= 0x0c60,/* 32 bit	Rx GMAC FIFO Write Pointer */
+	RX_GMF_WLEV	= 0x0c68,/* 32 bit	Rx GMAC FIFO Write Level */
+	RX_GMF_RP	= 0x0c70,/* 32 bit	Rx GMAC FIFO Read Pointer */
+	RX_GMF_RLEV	= 0x0c78,/* 32 bit	Rx GMAC FIFO Read Level */
+};
+
+
+/*	TXA_TEST		 8 bit	Tx Arbiter Test Register */
+enum {
+	TXA_INT_T_ON	= 1<<5,	/* Tx Arb Interval Timer Test On */
+	TXA_INT_T_OFF	= 1<<4,	/* Tx Arb Interval Timer Test Off */
+	TXA_INT_T_STEP	= 1<<3,	/* Tx Arb Interval Timer Step */
+	TXA_LIM_T_ON	= 1<<2,	/* Tx Arb Limit Timer Test On */
+	TXA_LIM_T_OFF	= 1<<1,	/* Tx Arb Limit Timer Test Off */
+	TXA_LIM_T_STEP	= 1<<0,	/* Tx Arb Limit Timer Step */
+};
+
+/*	TXA_STAT		 8 bit	Tx Arbiter Status Register */
+enum {
+	TXA_PRIO_XS	= 1<<0,	/* sync queue has prio to send */
+};
+
+
+/*	Q_BC			32 bit	Current Byte Counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR		32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR		32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR			32 bit	BMU Control/Status Register */
+
+enum {
+	CSR_SV_IDLE	= 1<<24,	/* BMU SM Idle */
+
+	CSR_DESC_CLR	= 1<<21,	/* Clear Reset for Descr */
+	CSR_DESC_SET	= 1<<20,	/* Set   Reset for Descr */
+	CSR_FIFO_CLR	= 1<<19,	/* Clear Reset for FIFO */
+	CSR_FIFO_SET	= 1<<18,	/* Set   Reset for FIFO */
+	CSR_HPI_RUN	= 1<<17,	/* Release HPI SM */
+	CSR_HPI_RST	= 1<<16,	/* Reset   HPI SM to Idle */
+	CSR_SV_RUN	= 1<<15,	/* Release Supervisor SM */
+	CSR_SV_RST	= 1<<14,	/* Reset   Supervisor SM */
+	CSR_DREAD_RUN	= 1<<13,	/* Release Descr Read SM */
+	CSR_DREAD_RST	= 1<<12,	/* Reset   Descr Read SM */
+	CSR_DWRITE_RUN	= 1<<11,	/* Release Descr Write SM */
+	CSR_DWRITE_RST	= 1<<10,	/* Reset   Descr Write SM */
+	CSR_TRANS_RUN	= 1<<9,		/* Release Transfer SM */
+	CSR_TRANS_RST	= 1<<8,		/* Reset   Transfer SM */
+	CSR_ENA_POL	= 1<<7,		/* Enable  Descr Polling */
+	CSR_DIS_POL	= 1<<6,		/* Disable Descr Polling */
+	CSR_STOP	= 1<<5,		/* Stop  Rx/Tx Queue */
+	CSR_START	= 1<<4,		/* Start Rx/Tx Queue */
+	CSR_IRQ_CL_P	= 1<<3,		/* (Rx)	Clear Parity IRQ */
+	CSR_IRQ_CL_B	= 1<<2,		/* Clear EOB IRQ */
+	CSR_IRQ_CL_F	= 1<<1,		/* Clear EOF IRQ */
+	CSR_IRQ_CL_C	= 1<<0,		/* Clear ERR IRQ */
+};
+
+#define CSR_SET_RESET	(CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+			CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+			CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+			CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+			CSR_TRANS_RUN)
+
+/*	Q_F				32 bit	Flag Register */
+enum {
+	F_ALM_FULL	= 1<<27,	/* Rx FIFO: almost full */
+	F_EMPTY		= 1<<27,	/* Tx FIFO: empty flag */
+	F_FIFO_EOF	= 1<<26,	/* Tag (EOF Flag) bit in FIFO */
+	F_WM_REACHED	= 1<<25,	/* Watermark reached */
+
+	F_FIFO_LEVEL	= 0x1fL<<16,	/* Bit 23..16:	# of Qwords in FIFO */
+	F_WATER_MARK	= 0x0007ffL,	/* Bit 10.. 0:	Watermark */
+};
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*	RB_START		32 bit	RAM Buffer Start Address */
+/*	RB_END			32 bit	RAM Buffer End Address */
+/*	RB_WP			32 bit	RAM Buffer Write Pointer */
+/*	RB_RP			32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP		32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP		32 bit	Rx Lower Threshold, Pause Pack */
+/*	RB_RX_UTHP		32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP		32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC			32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV			32 bit	RAM Buffer Level Register */
+
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+enum {
+	RB_ENA_STFWD	= 1<<5,	/* Enable  Store & Forward */
+	RB_DIS_STFWD	= 1<<4,	/* Disable Store & Forward */
+	RB_ENA_OP_MD	= 1<<3,	/* Enable  Operation Mode */
+	RB_DIS_OP_MD	= 1<<2,	/* Disable Operation Mode */
+	RB_RST_CLR	= 1<<1,	/* Clear RAM Buf STM Reset */
+	RB_RST_SET	= 1<<0,	/* Set   RAM Buf STM Reset */
+};
+
+/* Transmit MAC FIFO and Transmit LED Registers (GENESIS only), */
+enum {
+	TX_MFF_EA	= 0x0d00,/* 32 bit	Transmit MAC FIFO End Address */
+	TX_MFF_WP	= 0x0d04,/* 32 bit	Transmit MAC FIFO WR Pointer */
+	TX_MFF_WSP	= 0x0d08,/* 32 bit	Transmit MAC FIFO WR Shadow Ptr */
+	TX_MFF_RP	= 0x0d0c,/* 32 bit	Transmit MAC FIFO RD Pointer */
+	TX_MFF_PC	= 0x0d10,/* 32 bit	Transmit MAC FIFO Packet Cnt */
+	TX_MFF_LEV	= 0x0d14,/* 32 bit	Transmit MAC FIFO Level */
+	TX_MFF_CTRL1	= 0x0d18,/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
+	TX_MFF_WAF	= 0x0d1a,/*  8 bit	Transmit MAC Wait after flush */
+
+	TX_MFF_CTRL2	= 0x0d1c,/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
+	TX_MFF_TST1	= 0x0d1d,/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+	TX_MFF_TST2	= 0x0d1e,/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+
+	TX_LED_INI	= 0x0d20,/* 32 bit	Transmit LED Cnt Init Value */
+	TX_LED_VAL	= 0x0d24,/* 32 bit	Transmit LED Cnt Current Val */
+	TX_LED_CTRL	= 0x0d28,/*  8 bit	Transmit LED Cnt Control Reg */
+	TX_LED_TST	= 0x0d29,/*  8 bit	Transmit LED Cnt Test Reg */
+};
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR		0x002faf08UL	/*  50 ms */
+#define SK_BLK_DUR		0x01dcd650UL	/* 500 ms */
+
+#define SK_DPOLL_DEF	0x00ee6b28UL	/* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX	0x00ffffffUL	/* 268 ms at 62.5 MHz */
+					/* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62		100	/* is given in percent */
+#define SK_FACT_53		 85     /* on GENESIS:	53.12 MHz */
+#define SK_FACT_78		125	/* on YUKON:	78.12 MHz */
+
+
+/* Transmit GMAC FIFO (YUKON only) */
+enum {
+	TX_GMF_EA	= 0x0d40,/* 32 bit	Tx GMAC FIFO End Address */
+	TX_GMF_AE_THR	= 0x0d44,/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+	TX_GMF_CTRL_T	= 0x0d48,/* 32 bit	Tx GMAC FIFO Control/Test */
+
+	TX_GMF_WP	= 0x0d60,/* 32 bit 	Tx GMAC FIFO Write Pointer */
+	TX_GMF_WSP	= 0x0d64,/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+	TX_GMF_WLEV	= 0x0d68,/* 32 bit 	Tx GMAC FIFO Write Level */
+
+	TX_GMF_RP	= 0x0d70,/* 32 bit 	Tx GMAC FIFO Read Pointer */
+	TX_GMF_RSTP	= 0x0d74,/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+	TX_GMF_RLEV	= 0x0d78,/* 32 bit 	Tx GMAC FIFO Read Level */
+
+	/* Descriptor Poll Timer Registers */
+	B28_DPT_INI	= 0x0e00,/* 24 bit	Descriptor Poll Timer Init Val */
+	B28_DPT_VAL	= 0x0e04,/* 24 bit	Descriptor Poll Timer Curr Val */
+	B28_DPT_CTRL	= 0x0e08,/*  8 bit	Descriptor Poll Timer Ctrl Reg */
+
+	B28_DPT_TST	= 0x0e0a,/*  8 bit	Descriptor Poll Timer Test Reg */
+
+	/* Time Stamp Timer Registers (YUKON only) */
+	GMAC_TI_ST_VAL	= 0x0e14,/* 32 bit	Time Stamp Timer Curr Val */
+	GMAC_TI_ST_CTRL	= 0x0e18,/*  8 bit	Time Stamp Timer Ctrl Reg */
+	GMAC_TI_ST_TST	= 0x0e1a,/*  8 bit	Time Stamp Timer Test Reg */
+};
+
+
+enum {
+	LINKLED_OFF 	     = 0x01,
+	LINKLED_ON  	     = 0x02,
+	LINKLED_LINKSYNC_OFF = 0x04,
+	LINKLED_LINKSYNC_ON  = 0x08,
+	LINKLED_BLINK_OFF    = 0x10,
+	LINKLED_BLINK_ON     = 0x20,
+};
+
+/* GMAC and GPHY Control Registers (YUKON only) */
+enum {
+	GMAC_CTRL	= 0x0f00,/* 32 bit	GMAC Control Reg */
+	GPHY_CTRL	= 0x0f04,/* 32 bit	GPHY Control Reg */
+	GMAC_IRQ_SRC	= 0x0f08,/*  8 bit	GMAC Interrupt Source Reg */
+	GMAC_IRQ_MSK	= 0x0f0c,/*  8 bit	GMAC Interrupt Mask Reg */
+	GMAC_LINK_CTRL	= 0x0f10,/* 16 bit	Link Control Reg */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+	WOL_REG_OFFS	= 0x20,/* HW-Bug: Address is + 0x20 against spec. */
+
+	WOL_CTRL_STAT	= 0x0f20,/* 16 bit	WOL Control/Status Reg */
+	WOL_MATCH_CTL	= 0x0f22,/*  8 bit	WOL Match Control Reg */
+	WOL_MATCH_RES	= 0x0f23,/*  8 bit	WOL Match Result Reg */
+	WOL_MAC_ADDR	= 0x0f24,/* 32 bit	WOL MAC Address */
+	WOL_PATT_RPTR	= 0x0f2c,/*  8 bit	WOL Pattern Read Pointer */
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+	WOL_PATT_LEN_LO	= 0x0f30,/* 32 bit	WOL Pattern Length 3..0 */
+	WOL_PATT_LEN_HI	= 0x0f34,/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+	WOL_PATT_CNT_0	= 0x0f38,/* 32 bit	WOL Pattern Counter 3..0 */
+	WOL_PATT_CNT_4	= 0x0f3c,/* 24 bit	WOL Pattern Counter 6..4 */
+};
+#define WOL_REGS(port, x)	(x + (port)*0x80)
+
+enum {
+	WOL_PATT_RAM_1	= 0x1000,/*  WOL Pattern RAM Link 1 */
+	WOL_PATT_RAM_2	= 0x1400,/*  WOL Pattern RAM Link 2 */
+};
+#define WOL_PATT_RAM_BASE(port)	(WOL_PATT_RAM_1 + (port)*0x400)
+
+enum {
+	BASE_XMAC_1	= 0x2000,/* XMAC 1 registers */
+	BASE_GMAC_1	= 0x2800,/* GMAC 1 registers */
+	BASE_XMAC_2	= 0x3000,/* XMAC 2 registers */
+	BASE_GMAC_2	= 0x3800,/* GMAC 2 registers */
+};
+
+/*
+ * Receive Frame Status Encoding
+ */
+enum {
+	XMR_FS_LEN	= 0x3fff<<18,	/* Bit 31..18:	Rx Frame Length */
+	XMR_FS_LEN_SHIFT = 18,
+	XMR_FS_2L_VLAN	= 1<<17, /* Bit 17:	tagged wh 2Lev VLAN ID*/
+	XMR_FS_1_VLAN	= 1<<16, /* Bit 16:	tagged wh 1ev VLAN ID*/
+	XMR_FS_BC	= 1<<15, /* Bit 15:	Broadcast Frame */
+	XMR_FS_MC	= 1<<14, /* Bit 14:	Multicast Frame */
+	XMR_FS_UC	= 1<<13, /* Bit 13:	Unicast Frame */
+
+	XMR_FS_BURST	= 1<<11, /* Bit 11:	Burst Mode */
+	XMR_FS_CEX_ERR	= 1<<10, /* Bit 10:	Carrier Ext. Error */
+	XMR_FS_802_3	= 1<<9, /* Bit  9:	802.3 Frame */
+	XMR_FS_COL_ERR	= 1<<8, /* Bit  8:	Collision Error */
+	XMR_FS_CAR_ERR	= 1<<7, /* Bit  7:	Carrier Event Error */
+	XMR_FS_LEN_ERR	= 1<<6, /* Bit  6:	In-Range Length Error */
+	XMR_FS_FRA_ERR	= 1<<5, /* Bit  5:	Framing Error */
+	XMR_FS_RUNT	= 1<<4, /* Bit  4:	Runt Frame */
+	XMR_FS_LNG_ERR	= 1<<3, /* Bit  3:	Giant (Jumbo) Frame */
+	XMR_FS_FCS_ERR	= 1<<2, /* Bit  2:	Frame Check Sequ Err */
+	XMR_FS_ERR	= 1<<1, /* Bit  1:	Frame Error */
+	XMR_FS_MCTRL	= 1<<0, /* Bit  0:	MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *	XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *	XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+};
+
+/*
+,* XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+enum {
+	PHY_XMAC_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_XMAC_STAT		= 0x01,/* 16 bit r/w	PHY Status Register */
+	PHY_XMAC_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_XMAC_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_XMAC_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_XMAC_AUNE_LP	= 0x05,/* 16 bit r/o	Link Partner Abi Reg */
+	PHY_XMAC_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_XMAC_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_XMAC_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+
+	PHY_XMAC_EXT_STAT	= 0x0f,/* 16 bit r/o	Ext Status Register */
+	PHY_XMAC_RES_ABI	= 0x10,/* 16 bit r/o	PHY Resolved Ability */
+};
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+enum {
+	PHY_BCOM_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_BCOM_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_BCOM_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_BCOM_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_BCOM_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_BCOM_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_BCOM_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_BCOM_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_BCOM_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Broadcom-specific registers */
+	PHY_BCOM_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_BCOM_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_BCOM_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_BCOM_P_EXT_CTRL	= 0x10,/* 16 bit r/w	PHY Extended Ctrl Reg */
+	PHY_BCOM_P_EXT_STAT	= 0x11,/* 16 bit r/o	PHY Extended Stat Reg */
+	PHY_BCOM_RE_CTR		= 0x12,/* 16 bit r/w	Receive Error Counter */
+	PHY_BCOM_FC_CTR		= 0x13,/* 16 bit r/w	False Carrier Sense Cnt */
+	PHY_BCOM_RNO_CTR	= 0x14,/* 16 bit r/w	Receiver NOT_OK Cnt */
+
+	PHY_BCOM_AUX_CTRL	= 0x18,/* 16 bit r/w	Auxiliary Control Reg */
+	PHY_BCOM_AUX_STAT	= 0x19,/* 16 bit r/o	Auxiliary Stat Summary */
+	PHY_BCOM_INT_STAT	= 0x1a,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_BCOM_INT_MASK	= 0x1b,/* 16 bit r/w	Interrupt Mask Reg */
+};
+
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+enum {
+	PHY_MARV_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_MARV_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_MARV_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_MARV_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_MARV_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_MARV_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_MARV_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_MARV_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_MARV_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Marvel-specific registers */
+	PHY_MARV_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_MARV_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_MARV_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_MARV_PHY_CTRL	= 0x10,/* 16 bit r/w	PHY Specific Ctrl Reg */
+	PHY_MARV_PHY_STAT	= 0x11,/* 16 bit r/o	PHY Specific Stat Reg */
+	PHY_MARV_INT_MASK	= 0x12,/* 16 bit r/w	Interrupt Mask Reg */
+	PHY_MARV_INT_STAT	= 0x13,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_MARV_EXT_CTRL	= 0x14,/* 16 bit r/w	Ext. PHY Specific Ctrl */
+	PHY_MARV_RXE_CNT	= 0x15,/* 16 bit r/w	Receive Error Counter */
+	PHY_MARV_EXT_ADR	= 0x16,/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	PHY_MARV_PORT_IRQ	= 0x17,/* 16 bit r/o	Port 0 IRQ (88E1111 only) */
+	PHY_MARV_LED_CTRL	= 0x18,/* 16 bit r/w	LED Control Reg */
+	PHY_MARV_LED_OVER	= 0x19,/* 16 bit r/w	Manual LED Override Reg */
+	PHY_MARV_EXT_CTRL_2	= 0x1a,/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+	PHY_MARV_EXT_P_STAT	= 0x1b,/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+	PHY_MARV_CABLE_DIAG	= 0x1c,/* 16 bit r/o	Cable Diagnostic Reg */
+	PHY_MARV_PAGE_ADDR	= 0x1d,/* 16 bit r/w	Extended Page Address Reg */
+	PHY_MARV_PAGE_DATA	= 0x1e,/* 16 bit r/w	Extended Page Data Reg */
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+	PHY_MARV_FE_LED_PAR	= 0x16,/* 16 bit r/w	LED Parallel Select Reg. */
+	PHY_MARV_FE_LED_SER	= 0x17,/* 16 bit r/w	LED Stream Select S. LED */
+	PHY_MARV_FE_VCT_TX	= 0x1a,/* 16 bit r/w	VCT Reg. for TXP/N Pins */
+	PHY_MARV_FE_VCT_RX	= 0x1b,/* 16 bit r/o	VCT Reg. for RXP/N Pins */
+	PHY_MARV_FE_SPEC_2	= 0x1c,/* 16 bit r/w	Specific Control Reg. 2 */
+};
+
+enum {
+	PHY_CT_RESET	= 1<<15, /* Bit 15: (sc)	clear all PHY related regs */
+	PHY_CT_LOOP	= 1<<14, /* Bit 14:	enable Loopback over PHY */
+	PHY_CT_SPS_LSB	= 1<<13, /* Bit 13:	Speed select, lower bit */
+	PHY_CT_ANE	= 1<<12, /* Bit 12:	Auto-Negotiation Enabled */
+	PHY_CT_PDOWN	= 1<<11, /* Bit 11:	Power Down Mode */
+	PHY_CT_ISOL	= 1<<10, /* Bit 10:	Isolate Mode */
+	PHY_CT_RE_CFG	= 1<<9, /* Bit  9:	(sc) Restart Auto-Negotiation */
+	PHY_CT_DUP_MD	= 1<<8, /* Bit  8:	Duplex Mode */
+	PHY_CT_COL_TST	= 1<<7, /* Bit  7:	Collision Test enabled */
+	PHY_CT_SPS_MSB	= 1<<6, /* Bit  6:	Speed select, upper bit */
+};
+
+enum {
+	PHY_CT_SP1000	= PHY_CT_SPS_MSB, /* enable speed of 1000 Mbps */
+	PHY_CT_SP100	= PHY_CT_SPS_LSB, /* enable speed of  100 Mbps */
+	PHY_CT_SP10	= 0,		  /* enable speed of   10 Mbps */
+};
+
+enum {
+	PHY_ST_EXT_ST	= 1<<8, /* Bit  8:	Extended Status Present */
+
+	PHY_ST_PRE_SUP	= 1<<6, /* Bit  6:	Preamble Suppression */
+	PHY_ST_AN_OVER	= 1<<5, /* Bit  5:	Auto-Negotiation Over */
+	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occured */
+	PHY_ST_AN_CAP	= 1<<3, /* Bit  3:	Auto-Negotiation Capability */
+	PHY_ST_LSYNC	= 1<<2, /* Bit  2:	Link Synchronized */
+	PHY_ST_JAB_DET	= 1<<1, /* Bit  1:	Jabber Detected */
+	PHY_ST_EXT_REG	= 1<<0, /* Bit  0:	Extended Register available */
+};
+
+enum {
+	PHY_I1_OUI_MSK	= 0x3f<<10, /* Bit 15..10:	Organization Unique ID */
+	PHY_I1_MOD_NUM	= 0x3f<<4, /* Bit  9.. 4:	Model Number */
+	PHY_I1_REV_MSK	= 0xf, /* Bit  3.. 0:	Revision Number */
+};
+
+/* different Broadcom PHY Ids */
+enum {
+	PHY_BCOM_ID1_A1	= 0x6041,
+	PHY_BCOM_ID1_B2 = 0x6043,
+	PHY_BCOM_ID1_C0	= 0x6044,
+	PHY_BCOM_ID1_C5	= 0x6047,
+};
+
+/* different Marvell PHY Ids */
+enum {
+	PHY_MARV_ID0_VAL= 0x0141, /* Marvell Unique Identifier */
+	PHY_MARV_ID1_B0	= 0x0C23, /* Yukon (PHY 88E1011) */
+	PHY_MARV_ID1_B2	= 0x0C25, /* Yukon-Plus (PHY 88E1011) */
+	PHY_MARV_ID1_C2	= 0x0CC2, /* Yukon-EC (PHY 88E1111) */
+	PHY_MARV_ID1_Y2	= 0x0C91, /* Yukon-2 (PHY 88E1112) */
+};
+
+/* Advertisement register bits */
+enum {
+	PHY_AN_NXT_PG	= 1<<15, /* Bit 15:	Request Next Page */
+	PHY_AN_ACK	= 1<<14, /* Bit 14:	(ro) Acknowledge Received */
+	PHY_AN_RF	= 1<<13, /* Bit 13:	Remote Fault Bits */
+
+	PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11:	Try for asymmetric */
+	PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10:	Try for pause */
+	PHY_AN_100BASE4	= 1<<9, /* Bit 9:	Try for 100mbps 4k packets */
+	PHY_AN_100FULL	= 1<<8, /* Bit 8:	Try for 100mbps full-duplex */
+	PHY_AN_100HALF	= 1<<7, /* Bit 7:	Try for 100mbps half-duplex */
+	PHY_AN_10FULL	= 1<<6, /* Bit 6:	Try for 10mbps full-duplex */
+	PHY_AN_10HALF	= 1<<5, /* Bit 5:	Try for 10mbps half-duplex */
+	PHY_AN_CSMA	= 1<<0, /* Bit 0:	Only selector supported */
+	PHY_AN_SEL	= 0x1f, /* Bit 4..0:	Selector Field, 00001=Ethernet*/
+	PHY_AN_FULL	= PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA,
+	PHY_AN_ALL	= PHY_AN_10HALF | PHY_AN_10FULL |
+			  PHY_AN_100HALF | PHY_AN_100FULL,
+};
+
+/* Xmac Specific */
+enum {
+	PHY_X_AN_NXT_PG	= 1<<15, /* Bit 15:	Request Next Page */
+	PHY_X_AN_ACK	= 1<<14, /* Bit 14:	(ro) Acknowledge Received */
+	PHY_X_AN_RFB	= 3<<12,/* Bit 13..12:	Remote Fault Bits */
+
+	PHY_X_AN_PAUSE	= 3<<7,/* Bit  8.. 7:	Pause Bits */
+	PHY_X_AN_HD	= 1<<6, /* Bit  6:	Half Duplex */
+	PHY_X_AN_FD	= 1<<5, /* Bit  5:	Full Duplex */
+};
+
+/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
+enum {
+	PHY_X_P_NO_PAUSE= 0<<7,/* Bit  8..7:	no Pause Mode */
+	PHY_X_P_SYM_MD	= 1<<7, /* Bit  8..7:	symmetric Pause Mode */
+	PHY_X_P_ASYM_MD	= 2<<7,/* Bit  8..7:	asymmetric Pause Mode */
+	PHY_X_P_BOTH_MD	= 3<<7,/* Bit  8..7:	both Pause Mode */
+};
+
+
+/*****  PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
+enum {
+	PHY_X_EX_FD	= 1<<15, /* Bit 15:	Device Supports Full Duplex */
+	PHY_X_EX_HD	= 1<<14, /* Bit 14:	Device Supports Half Duplex */
+};
+
+/*****  PHY_XMAC_RES_ABI	16 bit r/o	PHY Resolved Ability *****/
+enum {
+	PHY_X_RS_PAUSE	= 3<<7,	/* Bit  8..7:	selected Pause Mode */
+	PHY_X_RS_HD	= 1<<6,	/* Bit  6:	Half Duplex Mode selected */
+	PHY_X_RS_FD	= 1<<5,	/* Bit  5:	Full Duplex Mode selected */
+	PHY_X_RS_ABLMIS = 1<<4,	/* Bit  4:	duplex or pause cap mismatch */
+	PHY_X_RS_PAUMIS = 1<<3,	/* Bit  3:	pause capability mismatch */
+};
+
+/* Remote Fault Bits (PHY_X_AN_RFB) encoding */
+enum {
+	X_RFB_OK	= 0<<12,/* Bit 13..12	No errors, Link OK */
+	X_RFB_LF	= 1<<12,/* Bit 13..12	Link Failure */
+	X_RFB_OFF	= 2<<12,/* Bit 13..12	Offline */
+	X_RFB_AN_ERR	= 3<<12,/* Bit 13..12	Auto-Negotiation Error */
+};
+
+/* Broadcom-Specific */
+/*****  PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_B_1000C_TEST	= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_B_1000C_MSE	= 1<<12, /* Bit 12:	Master/Slave Enable */
+	PHY_B_1000C_MSC	= 1<<11, /* Bit 11:	M/S Configuration */
+	PHY_B_1000C_RD	= 1<<10, /* Bit 10:	Repeater/DTE */
+	PHY_B_1000C_AFD	= 1<<9, /* Bit  9:	Advertise Full Duplex */
+	PHY_B_1000C_AHD	= 1<<8, /* Bit  8:	Advertise Half Duplex */
+};
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+/*****  PHY_MARV_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+enum {
+	PHY_B_1000S_MSF	= 1<<15, /* Bit 15:	Master/Slave Fault */
+	PHY_B_1000S_MSR	= 1<<14, /* Bit 14:	Master/Slave Result */
+	PHY_B_1000S_LRS	= 1<<13, /* Bit 13:	Local Receiver Status */
+	PHY_B_1000S_RRS	= 1<<12, /* Bit 12:	Remote Receiver Status */
+	PHY_B_1000S_LP_FD	= 1<<11, /* Bit 11:	Link Partner can FD */
+	PHY_B_1000S_LP_HD	= 1<<10, /* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+	PHY_B_1000S_IEC	= 0xff, /* Bit  7..0:	Idle Error Count */
+};
+
+/*****  PHY_BCOM_EXT_STAT	16 bit r/o	Extended Status Register *****/
+enum {
+	PHY_B_ES_X_FD_CAP	= 1<<15, /* Bit 15:	1000Base-X FD capable */
+	PHY_B_ES_X_HD_CAP	= 1<<14, /* Bit 14:	1000Base-X HD capable */
+	PHY_B_ES_T_FD_CAP	= 1<<13, /* Bit 13:	1000Base-T FD capable */
+	PHY_B_ES_T_HD_CAP	= 1<<12, /* Bit 12:	1000Base-T HD capable */
+};
+
+/*****  PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+enum {
+	PHY_B_PEC_MAC_PHY	= 1<<15, /* Bit 15:	10BIT/GMI-Interface */
+	PHY_B_PEC_DIS_CROSS	= 1<<14, /* Bit 14:	Disable MDI Crossover */
+	PHY_B_PEC_TX_DIS	= 1<<13, /* Bit 13:	Tx output Disabled */
+	PHY_B_PEC_INT_DIS	= 1<<12, /* Bit 12:	Interrupts Disabled */
+	PHY_B_PEC_F_INT	= 1<<11, /* Bit 11:	Force Interrupt */
+	PHY_B_PEC_BY_45	= 1<<10, /* Bit 10:	Bypass 4B5B-Decoder */
+	PHY_B_PEC_BY_SCR	= 1<<9, /* Bit  9:	Bypass Scrambler */
+	PHY_B_PEC_BY_MLT3	= 1<<8, /* Bit  8:	Bypass MLT3 Encoder */
+	PHY_B_PEC_BY_RXA	= 1<<7, /* Bit  7:	Bypass Rx Alignm. */
+	PHY_B_PEC_RES_SCR	= 1<<6, /* Bit  6:	Reset Scrambler */
+	PHY_B_PEC_EN_LTR	= 1<<5, /* Bit  5:	Ena LED Traffic Mode */
+	PHY_B_PEC_LED_ON	= 1<<4, /* Bit  4:	Force LED's on */
+	PHY_B_PEC_LED_OFF	= 1<<3, /* Bit  3:	Force LED's off */
+	PHY_B_PEC_EX_IPG	= 1<<2, /* Bit  2:	Extend Tx IPG Mode */
+	PHY_B_PEC_3_LED	= 1<<1, /* Bit  1:	Three Link LED mode */
+	PHY_B_PEC_HIGH_LA	= 1<<0, /* Bit  0:	GMII FIFO Elasticy */
+};
+
+/*****  PHY_BCOM_P_EXT_STAT	16 bit r/o	PHY Extended Status Reg *****/
+enum {
+	PHY_B_PES_CROSS_STAT	= 1<<13, /* Bit 13:	MDI Crossover Status */
+	PHY_B_PES_INT_STAT	= 1<<12, /* Bit 12:	Interrupt Status */
+	PHY_B_PES_RRS	= 1<<11, /* Bit 11:	Remote Receiver Stat. */
+	PHY_B_PES_LRS	= 1<<10, /* Bit 10:	Local Receiver Stat. */
+	PHY_B_PES_LOCKED	= 1<<9, /* Bit  9:	Locked */
+	PHY_B_PES_LS	= 1<<8, /* Bit  8:	Link Status */
+	PHY_B_PES_RF	= 1<<7, /* Bit  7:	Remote Fault */
+	PHY_B_PES_CE_ER	= 1<<6, /* Bit  6:	Carrier Ext Error */
+	PHY_B_PES_BAD_SSD	= 1<<5, /* Bit  5:	Bad SSD */
+	PHY_B_PES_BAD_ESD	= 1<<4, /* Bit  4:	Bad ESD */
+	PHY_B_PES_RX_ER	= 1<<3, /* Bit  3:	Receive Error */
+	PHY_B_PES_TX_ER	= 1<<2, /* Bit  2:	Transmit Error */
+	PHY_B_PES_LOCK_ER	= 1<<1, /* Bit  1:	Lock Error */
+	PHY_B_PES_MLT3_ER	= 1<<0, /* Bit  0:	MLT3 code Error */
+};
+
+/*  PHY_BCOM_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*  PHY_BCOM_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+enum {
+	PHY_B_AN_RF	= 1<<13, /* Bit 13:	Remote Fault */
+
+	PHY_B_AN_ASP	= 1<<11, /* Bit 11:	Asymmetric Pause */
+	PHY_B_AN_PC	= 1<<10, /* Bit 10:	Pause Capable */
+};
+
+
+/*****  PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
+enum {
+	PHY_B_FC_CTR	= 0xff, /* Bit  7..0:	False Carrier Counter */
+
+/*****  PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+	PHY_B_RC_LOC_MSK	= 0xff00, /* Bit 15..8:	Local Rx NOT_OK cnt */
+	PHY_B_RC_REM_MSK	= 0x00ff, /* Bit  7..0:	Remote Rx NOT_OK cnt */
+
+/*****  PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+	PHY_B_AC_L_SQE		= 1<<15, /* Bit 15:	Low Squelch */
+	PHY_B_AC_LONG_PACK	= 1<<14, /* Bit 14:	Rx Long Packets */
+	PHY_B_AC_ER_CTRL	= 3<<12,/* Bit 13..12:	Edgerate Control */
+									/* Bit 11:	reserved */
+	PHY_B_AC_TX_TST	= 1<<10, /* Bit 10:	Tx test bit, always 1 */
+									/* Bit  9.. 8:	reserved */
+	PHY_B_AC_DIS_PRF	= 1<<7, /* Bit  7:	dis part resp filter */
+									/* Bit  6:	reserved */
+	PHY_B_AC_DIS_PM	= 1<<5, /* Bit  5:	dis power management */
+									/* Bit  4:	reserved */
+	PHY_B_AC_DIAG	= 1<<3, /* Bit  3:	Diagnostic Mode */
+};
+
+/*****  PHY_BCOM_AUX_STAT	16 bit r/o	Auxiliary Status Reg *****/
+enum {
+	PHY_B_AS_AN_C	= 1<<15, /* Bit 15:	AutoNeg complete */
+	PHY_B_AS_AN_CA	= 1<<14, /* Bit 14:	AN Complete Ack */
+	PHY_B_AS_ANACK_D	= 1<<13, /* Bit 13:	AN Ack Detect */
+	PHY_B_AS_ANAB_D	= 1<<12, /* Bit 12:	AN Ability Detect */
+	PHY_B_AS_NPW	= 1<<11, /* Bit 11:	AN Next Page Wait */
+	PHY_B_AS_AN_RES_MSK	= 7<<8,/* Bit 10..8:	AN HDC */
+	PHY_B_AS_PDF	= 1<<7, /* Bit  7:	Parallel Detect. Fault */
+	PHY_B_AS_RF	= 1<<6, /* Bit  6:	Remote Fault */
+	PHY_B_AS_ANP_R	= 1<<5, /* Bit  5:	AN Page Received */
+	PHY_B_AS_LP_ANAB	= 1<<4, /* Bit  4:	LP AN Ability */
+	PHY_B_AS_LP_NPAB	= 1<<3, /* Bit  3:	LP Next Page Ability */
+	PHY_B_AS_LS	= 1<<2, /* Bit  2:	Link Status */
+	PHY_B_AS_PRR	= 1<<1, /* Bit  1:	Pause Resolution-Rx */
+	PHY_B_AS_PRT	= 1<<0, /* Bit  0:	Pause Resolution-Tx */
+};
+#define PHY_B_AS_PAUSE_MSK	(PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+enum {
+	PHY_B_IS_PSE	= 1<<14, /* Bit 14:	Pair Swap Error */
+	PHY_B_IS_MDXI_SC	= 1<<13, /* Bit 13:	MDIX Status Change */
+	PHY_B_IS_HCT	= 1<<12, /* Bit 12:	counter above 32k */
+	PHY_B_IS_LCT	= 1<<11, /* Bit 11:	counter above 128 */
+	PHY_B_IS_AN_PR	= 1<<10, /* Bit 10:	Page Received */
+	PHY_B_IS_NO_HDCL	= 1<<9, /* Bit  9:	No HCD Link */
+	PHY_B_IS_NO_HDC	= 1<<8, /* Bit  8:	No HCD */
+	PHY_B_IS_NEG_USHDC	= 1<<7, /* Bit  7:	Negotiated Unsup. HCD */
+	PHY_B_IS_SCR_S_ER	= 1<<6, /* Bit  6:	Scrambler Sync Error */
+	PHY_B_IS_RRS_CHANGE	= 1<<5, /* Bit  5:	Remote Rx Stat Change */
+	PHY_B_IS_LRS_CHANGE	= 1<<4, /* Bit  4:	Local Rx Stat Change */
+	PHY_B_IS_DUP_CHANGE	= 1<<3, /* Bit  3:	Duplex Mode Change */
+	PHY_B_IS_LSP_CHANGE	= 1<<2, /* Bit  2:	Link Speed Change */
+	PHY_B_IS_LST_CHANGE	= 1<<1, /* Bit  1:	Link Status Changed */
+	PHY_B_IS_CRC_ER	= 1<<0, /* Bit  0:	CRC Error */
+};
+#define PHY_B_DEF_MSK	\
+	(~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \
+	    PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+enum {
+	PHY_B_P_NO_PAUSE	= 0<<10,/* Bit 11..10:	no Pause Mode */
+	PHY_B_P_SYM_MD	= 1<<10, /* Bit 11..10:	symmetric Pause Mode */
+	PHY_B_P_ASYM_MD	= 2<<10,/* Bit 11..10:	asymmetric Pause Mode */
+	PHY_B_P_BOTH_MD	= 3<<10,/* Bit 11..10:	both Pause Mode */
+};
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+enum {
+	PHY_B_RES_1000FD	= 7<<8,/* Bit 10..8:	1000Base-T Full Dup. */
+	PHY_B_RES_1000HD	= 6<<8,/* Bit 10..8:	1000Base-T Half Dup. */
+};
+
+/** Marvell-Specific */
+enum {
+	PHY_M_AN_NXT_PG	= 1<<15, /* Request Next Page */
+	PHY_M_AN_ACK	= 1<<14, /* (ro)	Acknowledge Received */
+	PHY_M_AN_RF	= 1<<13, /* Remote Fault */
+
+	PHY_M_AN_ASP	= 1<<11, /* Asymmetric Pause */
+	PHY_M_AN_PC	= 1<<10, /* MAC Pause implemented */
+	PHY_M_AN_100_T4	= 1<<9, /* Not cap. 100Base-T4 (always 0) */
+	PHY_M_AN_100_FD	= 1<<8, /* Advertise 100Base-TX Full Duplex */
+	PHY_M_AN_100_HD	= 1<<7, /* Advertise 100Base-TX Half Duplex */
+	PHY_M_AN_10_FD	= 1<<6, /* Advertise 10Base-TX Full Duplex */
+	PHY_M_AN_10_HD	= 1<<5, /* Advertise 10Base-TX Half Duplex */
+	PHY_M_AN_SEL_MSK =0x1f<<4,	/* Bit  4.. 0: Selector Field Mask */
+};
+
+/* special defines for FIBER (88E1011S only) */
+enum {
+	PHY_M_AN_ASP_X		= 1<<8, /* Asymmetric Pause */
+	PHY_M_AN_PC_X		= 1<<7, /* MAC Pause implemented */
+	PHY_M_AN_1000X_AHD	= 1<<6, /* Advertise 10000Base-X Half Duplex */
+	PHY_M_AN_1000X_AFD	= 1<<5, /* Advertise 10000Base-X Full Duplex */
+};
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+enum {
+	PHY_M_P_NO_PAUSE_X	= 0<<7,/* Bit  8.. 7:	no Pause Mode */
+	PHY_M_P_SYM_MD_X	= 1<<7, /* Bit  8.. 7:	symmetric Pause Mode */
+	PHY_M_P_ASYM_MD_X	= 2<<7,/* Bit  8.. 7:	asymmetric Pause Mode */
+	PHY_M_P_BOTH_MD_X	= 3<<7,/* Bit  8.. 7:	both Pause Mode */
+};
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_M_1000C_TEST= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_M_1000C_MSE	= 1<<12, /* Manual Master/Slave Enable */
+	PHY_M_1000C_MSC	= 1<<11, /* M/S Configuration (1=Master) */
+	PHY_M_1000C_MPD	= 1<<10, /* Multi-Port Device */
+	PHY_M_1000C_AFD	= 1<<9, /* Advertise Full Duplex */
+	PHY_M_1000C_AHD	= 1<<8, /* Advertise Half Duplex */
+};
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+enum {
+	PHY_M_PC_TX_FFD_MSK	= 3<<14,/* Bit 15..14: Tx FIFO Depth Mask */
+	PHY_M_PC_RX_FFD_MSK	= 3<<12,/* Bit 13..12: Rx FIFO Depth Mask */
+	PHY_M_PC_ASS_CRS_TX	= 1<<11, /* Assert CRS on Transmit */
+	PHY_M_PC_FL_GOOD	= 1<<10, /* Force Link Good */
+	PHY_M_PC_EN_DET_MSK	= 3<<8,/* Bit  9.. 8: Energy Detect Mask */
+	PHY_M_PC_ENA_EXT_D	= 1<<7, /* Enable Ext. Distance (10BT) */
+	PHY_M_PC_MDIX_MSK	= 3<<5,/* Bit  6.. 5: MDI/MDIX Config. Mask */
+	PHY_M_PC_DIS_125CLK	= 1<<4, /* Disable 125 CLK */
+	PHY_M_PC_MAC_POW_UP	= 1<<3, /* MAC Power up */
+	PHY_M_PC_SQE_T_ENA	= 1<<2, /* SQE Test Enabled */
+	PHY_M_PC_POL_R_DIS	= 1<<1, /* Polarity Reversal Disabled */
+	PHY_M_PC_DIS_JABBER	= 1<<0, /* Disable Jabber */
+};
+
+enum {
+	PHY_M_PC_EN_DET		= 2<<8,	/* Energy Detect (Mode 1) */
+	PHY_M_PC_EN_DET_PLUS	= 3<<8, /* Energy Detect Plus (Mode 2) */
+};
+
+enum {
+	PHY_M_PC_MAN_MDI	= 0, /* 00 = Manual MDI configuration */
+	PHY_M_PC_MAN_MDIX	= 1, /* 01 = Manual MDIX configuration */
+	PHY_M_PC_ENA_AUTO	= 3, /* 11 = Enable Automatic Crossover */
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PC_ENA_DTE_DT	= 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */
+	PHY_M_PC_ENA_ENE_DT	= 1<<14, /* Enable Energy Detect (sense & pulse) */
+	PHY_M_PC_DIS_NLP_CK	= 1<<13, /* Disable Normal Link Puls (NLP) Check */
+	PHY_M_PC_ENA_LIP_NP	= 1<<12, /* Enable Link Partner Next Page Reg. */
+	PHY_M_PC_DIS_NLP_GN	= 1<<11, /* Disable Normal Link Puls Generation */
+
+	PHY_M_PC_DIS_SCRAMB	= 1<<9, /* Disable Scrambler */
+	PHY_M_PC_DIS_FEFI	= 1<<8, /* Disable Far End Fault Indic. (FEFI) */
+
+	PHY_M_PC_SH_TP_SEL	= 1<<6, /* Shielded Twisted Pair Select */
+	PHY_M_PC_RX_FD_MSK	= 3<<2,/* Bit  3.. 2: Rx FIFO Depth Mask */
+};
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+enum {
+	PHY_M_PS_SPEED_MSK	= 3<<14, /* Bit 15..14: Speed Mask */
+	PHY_M_PS_SPEED_1000	= 1<<15, /*		10 = 1000 Mbps */
+	PHY_M_PS_SPEED_100	= 1<<14, /*		01 =  100 Mbps */
+	PHY_M_PS_SPEED_10	= 0,	 /*		00 =   10 Mbps */
+	PHY_M_PS_FULL_DUP	= 1<<13, /* Full Duplex */
+	PHY_M_PS_PAGE_REC	= 1<<12, /* Page Received */
+	PHY_M_PS_SPDUP_RES	= 1<<11, /* Speed & Duplex Resolved */
+	PHY_M_PS_LINK_UP	= 1<<10, /* Link Up */
+	PHY_M_PS_CABLE_MSK	= 7<<7,  /* Bit  9.. 7: Cable Length Mask */
+	PHY_M_PS_MDI_X_STAT	= 1<<6,  /* MDI Crossover Stat (1=MDIX) */
+	PHY_M_PS_DOWNS_STAT	= 1<<5,  /* Downshift Status (1=downsh.) */
+	PHY_M_PS_ENDET_STAT	= 1<<4,  /* Energy Detect Status (1=act) */
+	PHY_M_PS_TX_P_EN	= 1<<3,  /* Tx Pause Enabled */
+	PHY_M_PS_RX_P_EN	= 1<<2,  /* Rx Pause Enabled */
+	PHY_M_PS_POL_REV	= 1<<1,  /* Polarity Reversed */
+	PHY_M_PS_JABBER		= 1<<0,  /* Jabber */
+};
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PS_DTE_DETECT	= 1<<15, /* Data Terminal Equipment (DTE) Detected */
+	PHY_M_PS_RES_SPEED	= 1<<14, /* Resolved Speed (1=100 Mbps, 0=10 Mbps */
+};
+
+enum {
+	PHY_M_IS_AN_ERROR	= 1<<15, /* Auto-Negotiation Error */
+	PHY_M_IS_LSP_CHANGE	= 1<<14, /* Link Speed Changed */
+	PHY_M_IS_DUP_CHANGE	= 1<<13, /* Duplex Mode Changed */
+	PHY_M_IS_AN_PR		= 1<<12, /* Page Received */
+	PHY_M_IS_AN_COMPL	= 1<<11, /* Auto-Negotiation Completed */
+	PHY_M_IS_LST_CHANGE	= 1<<10, /* Link Status Changed */
+	PHY_M_IS_SYMB_ERROR	= 1<<9, /* Symbol Error */
+	PHY_M_IS_FALSE_CARR	= 1<<8, /* False Carrier */
+	PHY_M_IS_FIFO_ERROR	= 1<<7, /* FIFO Overflow/Underrun Error */
+	PHY_M_IS_MDI_CHANGE	= 1<<6, /* MDI Crossover Changed */
+	PHY_M_IS_DOWNSH_DET	= 1<<5, /* Downshift Detected */
+	PHY_M_IS_END_CHANGE	= 1<<4, /* Energy Detect Changed */
+
+	PHY_M_IS_DTE_CHANGE	= 1<<2, /* DTE Power Det. Status Changed */
+	PHY_M_IS_POL_CHANGE	= 1<<1, /* Polarity Changed */
+	PHY_M_IS_JABBER		= 1<<0, /* Jabber */
+
+	PHY_M_IS_DEF_MSK	= PHY_M_IS_AN_ERROR | PHY_M_IS_LSP_CHANGE |
+				  PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR,
+
+	PHY_M_IS_AN_MSK		= PHY_M_IS_AN_ERROR | PHY_M_IS_AN_COMPL,
+};
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+enum {
+	PHY_M_EC_ENA_BC_EXT = 1<<15, /* Enable Block Carr. Ext. (88E1111 only) */
+	PHY_M_EC_ENA_LIN_LB = 1<<14, /* Enable Line Loopback (88E1111 only) */
+
+	PHY_M_EC_DIS_LINK_P = 1<<12, /* Disable Link Pulses (88E1111 only) */
+	PHY_M_EC_M_DSC_MSK  = 3<<10, /* Bit 11..10:	Master Downshift Counter */
+					/* (88E1011 only) */
+	PHY_M_EC_S_DSC_MSK  = 3<<8,  /* Bit  9.. 8:	Slave  Downshift Counter */
+				       /* (88E1011 only) */
+	PHY_M_EC_M_DSC_MSK2  = 7<<9, /* Bit 11.. 9:	Master Downshift Counter */
+					/* (88E1111 only) */
+	PHY_M_EC_DOWN_S_ENA  = 1<<8, /* Downshift Enable (88E1111 only) */
+					/* !!! Errata in spec. (1 = disable) */
+	PHY_M_EC_RX_TIM_CT   = 1<<7, /* RGMII Rx Timing Control*/
+	PHY_M_EC_MAC_S_MSK   = 7<<4, /* Bit  6.. 4:	Def. MAC interface speed */
+	PHY_M_EC_FIB_AN_ENA  = 1<<3, /* Fiber Auto-Neg. Enable (88E1011S only) */
+	PHY_M_EC_DTE_D_ENA   = 1<<2, /* DTE Detect Enable (88E1111 only) */
+	PHY_M_EC_TX_TIM_CT   = 1<<1, /* RGMII Tx Timing Control */
+	PHY_M_EC_TRANS_DIS   = 1<<0, /* Transmitter Disable (88E1111 only) */};
+
+#define PHY_M_EC_M_DSC(x)	((u16)(x)<<10) /* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)	((u16)(x)<<8) /* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)	((u16)(x)<<4) /* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define PHY_M_EC_M_DSC_2(x)	((u16)(x)<<9) /* 000=1x; 001=2x; 010=3x; 011=4x */
+											/* 100=5x; 101=6x; 110=7x; 111=8x */
+enum {
+	MAC_TX_CLK_0_MHZ	= 2,
+	MAC_TX_CLK_2_5_MHZ	= 6,
+	MAC_TX_CLK_25_MHZ 	= 7,
+};
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+enum {
+	PHY_M_LEDC_DIS_LED	= 1<<15, /* Disable LED */
+	PHY_M_LEDC_PULS_MSK	= 7<<12,/* Bit 14..12: Pulse Stretch Mask */
+	PHY_M_LEDC_F_INT	= 1<<11, /* Force Interrupt */
+	PHY_M_LEDC_BL_R_MSK	= 7<<8,/* Bit 10.. 8: Blink Rate Mask */
+	PHY_M_LEDC_DP_C_LSB	= 1<<7, /* Duplex Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_TX_C_LSB	= 1<<6, /* Tx Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_LK_C_MSK	= 7<<3,/* Bit  5.. 3: Link Control Mask */
+					/* (88E1111 only) */
+};
+#define PHY_M_LED_PULS_DUR(x)	(((u16)(x)<<12) & PHY_M_LEDC_PULS_MSK)
+#define PHY_M_LED_BLINK_RT(x)	(((u16)(x)<<8) & PHY_M_LEDC_BL_R_MSK)
+
+enum {
+	PHY_M_LEDC_LINK_MSK	= 3<<3, /* Bit  4.. 3: Link Control Mask */
+					/* (88E1011 only) */
+	PHY_M_LEDC_DP_CTRL	= 1<<2, /* Duplex Control */
+	PHY_M_LEDC_DP_C_MSB	= 1<<2, /* Duplex Control (MSB, 88E1111 only) */
+	PHY_M_LEDC_RX_CTRL	= 1<<1, /* Rx Activity / Link */
+	PHY_M_LEDC_TX_CTRL	= 1<<0, /* Tx Activity / Link */
+	PHY_M_LEDC_TX_C_MSB	= 1<<0, /* Tx Control (MSB, 88E1111 only) */
+};
+
+enum {
+	PULS_NO_STR	= 0, /* no pulse stretching */
+	PULS_21MS	= 1, /* 21 ms to 42 ms */
+	PULS_42MS	= 2, /* 42 ms to 84 ms */
+	PULS_84MS	= 3, /* 84 ms to 170 ms */
+	PULS_170MS	= 4, /* 170 ms to 340 ms */
+	PULS_340MS	= 5, /* 340 ms to 670 ms */
+	PULS_670MS	= 6, /* 670 ms to 1.3 s */
+	PULS_1300MS	= 7, /* 1.3 s to 2.7 s */
+};
+
+
+enum {
+	BLINK_42MS	= 0, /* 42 ms */
+	BLINK_84MS	= 1, /* 84 ms */
+	BLINK_170MS	= 2, /* 170 ms */
+	BLINK_340MS	= 3, /* 340 ms */
+	BLINK_670MS	= 4, /* 670 ms */
+};
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_SGMII(x)	((x)<<14) /* Bit 15..14:  SGMII AN Timer */
+										/* Bit 13..12:	reserved */
+#define PHY_M_LED_MO_DUP(x)	((x)<<10) /* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)	((x)<<8) /* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)	((x)<<6) /* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	((x)<<4) /* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)	((x)<<2) /* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)	((x)<<0) /* Bit  1.. 0:  Tx */
+
+enum {
+	MO_LED_NORM	= 0,
+	MO_LED_BLINK	= 1,
+	MO_LED_OFF	= 2,
+	MO_LED_ON	= 3,
+};
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+enum {
+	PHY_M_EC2_FI_IMPED	= 1<<6, /* Fiber Input  Impedance */
+	PHY_M_EC2_FO_IMPED	= 1<<5, /* Fiber Output Impedance */
+	PHY_M_EC2_FO_M_CLK	= 1<<4, /* Fiber Mode Clock Enable */
+	PHY_M_EC2_FO_BOOST	= 1<<3, /* Fiber Output Boost */
+	PHY_M_EC2_FO_AM_MSK	= 7, /* Bit  2.. 0:	Fiber Output Amplitude */
+};
+
+/*****  PHY_MARV_EXT_P_STAT 16 bit r/w	Ext. PHY Specific Status *****/
+enum {
+	PHY_M_FC_AUTO_SEL	= 1<<15, /* Fiber/Copper Auto Sel. Dis. */
+	PHY_M_FC_AN_REG_ACC	= 1<<14, /* Fiber/Copper AN Reg. Access */
+	PHY_M_FC_RESOLUTION	= 1<<13, /* Fiber/Copper Resolution */
+	PHY_M_SER_IF_AN_BP	= 1<<12, /* Ser. IF AN Bypass Enable */
+	PHY_M_SER_IF_BP_ST	= 1<<11, /* Ser. IF AN Bypass Status */
+	PHY_M_IRQ_POLARITY	= 1<<10, /* IRQ polarity */
+	PHY_M_DIS_AUT_MED	= 1<<9, /* Disable Aut. Medium Reg. Selection */
+									/* (88E1111 only) */
+								/* Bit  9.. 4: reserved (88E1011 only) */
+	PHY_M_UNDOC1	= 1<<7, /* undocumented bit !! */
+	PHY_M_DTE_POW_STAT	= 1<<4, /* DTE Power Status (88E1111 only) */
+	PHY_M_MODE_MASK	= 0xf, /* Bit  3.. 0: copy of HWCFG MODE[3:0] */
+};
+
+/*****  PHY_MARV_CABLE_DIAG	16 bit r/o	Cable Diagnostic Reg *****/
+enum {
+	PHY_M_CABD_ENA_TEST	= 1<<15, /* Enable Test (Page 0) */
+	PHY_M_CABD_DIS_WAIT	= 1<<15, /* Disable Waiting Period (Page 1) */
+					/* (88E1111 only) */
+	PHY_M_CABD_STAT_MSK	= 3<<13, /* Bit 14..13: Status Mask */
+	PHY_M_CABD_AMPL_MSK	= 0x1f<<8, /* Bit 12.. 8: Amplitude Mask */
+					/* (88E1111 only) */
+	PHY_M_CABD_DIST_MSK	= 0xff, /* Bit  7.. 0: Distance Mask */
+};
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+enum {
+	CABD_STAT_NORMAL= 0,
+	CABD_STAT_SHORT	= 1,
+	CABD_STAT_OPEN	= 2,
+	CABD_STAT_FAIL	= 3,
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+/*****  PHY_MARV_FE_LED_PAR		16 bit r/w	LED Parallel Select Reg. *****/
+									/* Bit 15..12: reserved (used internally) */
+enum {
+	PHY_M_FELP_LED2_MSK = 0xf<<8,	/* Bit 11.. 8: LED2 Mask (LINK) */
+	PHY_M_FELP_LED1_MSK = 0xf<<4,	/* Bit  7.. 4: LED1 Mask (ACT) */
+	PHY_M_FELP_LED0_MSK = 0xf, /* Bit  3.. 0: LED0 Mask (SPEED) */
+};
+
+#define PHY_M_FELP_LED2_CTRL(x)	(((x)<<8) & PHY_M_FELP_LED2_MSK)
+#define PHY_M_FELP_LED1_CTRL(x)	(((x)<<4) & PHY_M_FELP_LED1_MSK)
+#define PHY_M_FELP_LED0_CTRL(x)	(((x)<<0) & PHY_M_FELP_LED0_MSK)
+
+enum {
+	LED_PAR_CTRL_COLX	= 0x00,
+	LED_PAR_CTRL_ERROR	= 0x01,
+	LED_PAR_CTRL_DUPLEX	= 0x02,
+	LED_PAR_CTRL_DP_COL	= 0x03,
+	LED_PAR_CTRL_SPEED	= 0x04,
+	LED_PAR_CTRL_LINK	= 0x05,
+	LED_PAR_CTRL_TX		= 0x06,
+	LED_PAR_CTRL_RX		= 0x07,
+	LED_PAR_CTRL_ACT	= 0x08,
+	LED_PAR_CTRL_LNK_RX	= 0x09,
+	LED_PAR_CTRL_LNK_AC	= 0x0a,
+	LED_PAR_CTRL_ACT_BL	= 0x0b,
+	LED_PAR_CTRL_TX_BL	= 0x0c,
+	LED_PAR_CTRL_RX_BL	= 0x0d,
+	LED_PAR_CTRL_COL_BL	= 0x0e,
+	LED_PAR_CTRL_INACT	= 0x0f
+};
+
+/*****,PHY_MARV_FE_SPEC_2		16 bit r/w	Specific Control Reg. 2 *****/
+enum {
+	PHY_M_FESC_DIS_WAIT	= 1<<2, /* Disable TDR Waiting Period */
+	PHY_M_FESC_ENA_MCLK	= 1<<1, /* Enable MAC Rx Clock in sleep mode */
+	PHY_M_FESC_SEL_CL_A	= 1<<0, /* Select Class A driver (100B-TX) */
+};
+
+
+/*****  PHY_MARV_PHY_CTRL (page 3)		16 bit r/w	LED Control Reg. *****/
+enum {
+	PHY_M_LEDC_LOS_MSK	= 0xf<<12, /* Bit 15..12: LOS LED Ctrl. Mask */
+	PHY_M_LEDC_INIT_MSK	= 0xf<<8, /* Bit 11.. 8: INIT LED Ctrl. Mask */
+	PHY_M_LEDC_STA1_MSK	= 0xf<<4, /* Bit  7.. 4: STAT1 LED Ctrl. Mask */
+	PHY_M_LEDC_STA0_MSK	= 0xf, /* Bit  3.. 0: STAT0 LED Ctrl. Mask */
+};
+
+#define PHY_M_LEDC_LOS_CTRL(x)	(((x)<<12) & PHY_M_LEDC_LOS_MSK)
+#define PHY_M_LEDC_INIT_CTRL(x)	(((x)<<8) & PHY_M_LEDC_INIT_MSK)
+#define PHY_M_LEDC_STA1_CTRL(x)	(((x)<<4) & PHY_M_LEDC_STA1_MSK)
+#define PHY_M_LEDC_STA0_CTRL(x)	(((x)<<0) & PHY_M_LEDC_STA0_MSK)
+
+/* GMAC registers  */
+/* Port Registers */
+enum {
+	GM_GP_STAT	= 0x0000,	/* 16 bit r/o	General Purpose Status */
+	GM_GP_CTRL	= 0x0004,	/* 16 bit r/w	General Purpose Control */
+	GM_TX_CTRL	= 0x0008,	/* 16 bit r/w	Transmit Control Reg. */
+	GM_RX_CTRL	= 0x000c,	/* 16 bit r/w	Receive Control Reg. */
+	GM_TX_FLOW_CTRL	= 0x0010,	/* 16 bit r/w	Transmit Flow-Control */
+	GM_TX_PARAM	= 0x0014,	/* 16 bit r/w	Transmit Parameter Reg. */
+	GM_SERIAL_MODE	= 0x0018,	/* 16 bit r/w	Serial Mode Register */
+/* Source Address Registers */
+	GM_SRC_ADDR_1L	= 0x001c,	/* 16 bit r/w	Source Address 1 (low) */
+	GM_SRC_ADDR_1M	= 0x0020,	/* 16 bit r/w	Source Address 1 (middle) */
+	GM_SRC_ADDR_1H	= 0x0024,	/* 16 bit r/w	Source Address 1 (high) */
+	GM_SRC_ADDR_2L	= 0x0028,	/* 16 bit r/w	Source Address 2 (low) */
+	GM_SRC_ADDR_2M	= 0x002c,	/* 16 bit r/w	Source Address 2 (middle) */
+	GM_SRC_ADDR_2H	= 0x0030,	/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+	GM_MC_ADDR_H1	= 0x0034,	/* 16 bit r/w	Multicast Address Hash 1 */
+	GM_MC_ADDR_H2	= 0x0038,	/* 16 bit r/w	Multicast Address Hash 2 */
+	GM_MC_ADDR_H3	= 0x003c,	/* 16 bit r/w	Multicast Address Hash 3 */
+	GM_MC_ADDR_H4	= 0x0040,	/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+	GM_TX_IRQ_SRC	= 0x0044,	/* 16 bit r/o	Tx Overflow IRQ Source */
+	GM_RX_IRQ_SRC	= 0x0048,	/* 16 bit r/o	Rx Overflow IRQ Source */
+	GM_TR_IRQ_SRC	= 0x004c,	/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+	GM_TX_IRQ_MSK	= 0x0050,	/* 16 bit r/w	Tx Overflow IRQ Mask */
+	GM_RX_IRQ_MSK	= 0x0054,	/* 16 bit r/w	Rx Overflow IRQ Mask */
+	GM_TR_IRQ_MSK	= 0x0058,	/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+	GM_SMI_CTRL	= 0x0080,	/* 16 bit r/w	SMI Control Register */
+	GM_SMI_DATA	= 0x0084,	/* 16 bit r/w	SMI Data Register */
+	GM_PHY_ADDR	= 0x0088,	/* 16 bit r/w	GPHY Address Register */
+};
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE	0x0100		/* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE	44		/* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+enum {
+	GM_RXF_UC_OK  = GM_MIB_CNT_BASE + 0,	/* Unicast Frames Received OK */
+	GM_RXF_BC_OK	= GM_MIB_CNT_BASE + 8,	/* Broadcast Frames Received OK */
+	GM_RXF_MPAUSE	= GM_MIB_CNT_BASE + 16,	/* Pause MAC Ctrl Frames Received */
+	GM_RXF_MC_OK	= GM_MIB_CNT_BASE + 24,	/* Multicast Frames Received OK */
+	GM_RXF_FCS_ERR	= GM_MIB_CNT_BASE + 32,	/* Rx Frame Check Seq. Error */
+	/* GM_MIB_CNT_BASE + 40:	reserved */
+	GM_RXO_OK_LO	= GM_MIB_CNT_BASE + 48,	/* Octets Received OK Low */
+	GM_RXO_OK_HI	= GM_MIB_CNT_BASE + 56,	/* Octets Received OK High */
+	GM_RXO_ERR_LO	= GM_MIB_CNT_BASE + 64,	/* Octets Received Invalid Low */
+	GM_RXO_ERR_HI	= GM_MIB_CNT_BASE + 72,	/* Octets Received Invalid High */
+	GM_RXF_SHT	= GM_MIB_CNT_BASE + 80,	/* Frames <64 Byte Received OK */
+	GM_RXE_FRAG	= GM_MIB_CNT_BASE + 88,	/* Frames <64 Byte Received with FCS Err */
+	GM_RXF_64B	= GM_MIB_CNT_BASE + 96,	/* 64 Byte Rx Frame */
+	GM_RXF_127B	= GM_MIB_CNT_BASE + 104,	/* 65-127 Byte Rx Frame */
+	GM_RXF_255B	= GM_MIB_CNT_BASE + 112,	/* 128-255 Byte Rx Frame */
+	GM_RXF_511B	= GM_MIB_CNT_BASE + 120,	/* 256-511 Byte Rx Frame */
+	GM_RXF_1023B	= GM_MIB_CNT_BASE + 128,	/* 512-1023 Byte Rx Frame */
+	GM_RXF_1518B	= GM_MIB_CNT_BASE + 136,	/* 1024-1518 Byte Rx Frame */
+	GM_RXF_MAX_SZ	= GM_MIB_CNT_BASE + 144,	/* 1519-MaxSize Byte Rx Frame */
+	GM_RXF_LNG_ERR	= GM_MIB_CNT_BASE + 152,	/* Rx Frame too Long Error */
+	GM_RXF_JAB_PKT	= GM_MIB_CNT_BASE + 160,	/* Rx Jabber Packet Frame */
+	/* GM_MIB_CNT_BASE + 168:	reserved */
+	GM_RXE_FIFO_OV	= GM_MIB_CNT_BASE + 176,	/* Rx FIFO overflow Event */
+	/* GM_MIB_CNT_BASE + 184:	reserved */
+	GM_TXF_UC_OK	= GM_MIB_CNT_BASE + 192,	/* Unicast Frames Xmitted OK */
+	GM_TXF_BC_OK	= GM_MIB_CNT_BASE + 200,	/* Broadcast Frames Xmitted OK */
+	GM_TXF_MPAUSE	= GM_MIB_CNT_BASE + 208,	/* Pause MAC Ctrl Frames Xmitted */
+	GM_TXF_MC_OK	= GM_MIB_CNT_BASE + 216,	/* Multicast Frames Xmitted OK */
+	GM_TXO_OK_LO	= GM_MIB_CNT_BASE + 224,	/* Octets Transmitted OK Low */
+	GM_TXO_OK_HI	= GM_MIB_CNT_BASE + 232,	/* Octets Transmitted OK High */
+	GM_TXF_64B	= GM_MIB_CNT_BASE + 240,	/* 64 Byte Tx Frame */
+	GM_TXF_127B	= GM_MIB_CNT_BASE + 248,	/* 65-127 Byte Tx Frame */
+	GM_TXF_255B	= GM_MIB_CNT_BASE + 256,	/* 128-255 Byte Tx Frame */
+	GM_TXF_511B	= GM_MIB_CNT_BASE + 264,	/* 256-511 Byte Tx Frame */
+	GM_TXF_1023B	= GM_MIB_CNT_BASE + 272,	/* 512-1023 Byte Tx Frame */
+	GM_TXF_1518B	= GM_MIB_CNT_BASE + 280,	/* 1024-1518 Byte Tx Frame */
+	GM_TXF_MAX_SZ	= GM_MIB_CNT_BASE + 288,	/* 1519-MaxSize Byte Tx Frame */
+
+	GM_TXF_COL	= GM_MIB_CNT_BASE + 304,	/* Tx Collision */
+	GM_TXF_LAT_COL	= GM_MIB_CNT_BASE + 312,	/* Tx Late Collision */
+	GM_TXF_ABO_COL	= GM_MIB_CNT_BASE + 320,	/* Tx aborted due to Exces. Col. */
+	GM_TXF_MUL_COL	= GM_MIB_CNT_BASE + 328,	/* Tx Multiple Collision */
+	GM_TXF_SNG_COL	= GM_MIB_CNT_BASE + 336,	/* Tx Single Collision */
+	GM_TXE_FIFO_UR	= GM_MIB_CNT_BASE + 344,	/* Tx FIFO Underrun Event */
+};
+
+/* GMAC Bit Definitions */
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+enum {
+	GM_GPSR_SPEED		= 1<<15, /* Bit 15:	Port Speed (1 = 100 Mbps) */
+	GM_GPSR_DUPLEX		= 1<<14, /* Bit 14:	Duplex Mode (1 = Full) */
+	GM_GPSR_FC_TX_DIS	= 1<<13, /* Bit 13:	Tx Flow-Control Mode Disabled */
+	GM_GPSR_LINK_UP		= 1<<12, /* Bit 12:	Link Up Status */
+	GM_GPSR_PAUSE		= 1<<11, /* Bit 11:	Pause State */
+	GM_GPSR_TX_ACTIVE	= 1<<10, /* Bit 10:	Tx in Progress */
+	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occured */
+	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occured */
+
+	GM_GPSR_PHY_ST_CH	= 1<<5,	/* Bit  5:	PHY Status Change */
+	GM_GPSR_GIG_SPEED	= 1<<4,	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+	GM_GPSR_PART_MODE	= 1<<3,	/* Bit  3:	Partition mode */
+	GM_GPSR_FC_RX_DIS	= 1<<2,	/* Bit  2:	Rx Flow-Control Mode Disabled */
+	GM_GPSR_PROM_EN		= 1<<1,	/* Bit  1:	Promiscuous Mode Enabled */
+};
+
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+enum {
+	GM_GPCR_PROM_ENA	= 1<<14,	/* Bit 14:	Enable Promiscuous Mode */
+	GM_GPCR_FC_TX_DIS	= 1<<13, /* Bit 13:	Disable Tx Flow-Control Mode */
+	GM_GPCR_TX_ENA		= 1<<12, /* Bit 12:	Enable Transmit */
+	GM_GPCR_RX_ENA		= 1<<11, /* Bit 11:	Enable Receive */
+	GM_GPCR_BURST_ENA	= 1<<10, /* Bit 10:	Enable Burst Mode */
+	GM_GPCR_LOOP_ENA	= 1<<9,	/* Bit  9:	Enable MAC Loopback Mode */
+	GM_GPCR_PART_ENA	= 1<<8,	/* Bit  8:	Enable Partition Mode */
+	GM_GPCR_GIGS_ENA	= 1<<7,	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+	GM_GPCR_FL_PASS		= 1<<6,	/* Bit  6:	Force Link Pass */
+	GM_GPCR_DUP_FULL	= 1<<5,	/* Bit  5:	Full Duplex Mode */
+	GM_GPCR_FC_RX_DIS	= 1<<4,	/* Bit  4:	Disable Rx Flow-Control Mode */
+	GM_GPCR_SPEED_100	= 1<<3,   /* Bit  3:	Port Speed 100 Mbps */
+	GM_GPCR_AU_DUP_DIS	= 1<<2,	/* Bit  2:	Disable Auto-Update Duplex */
+	GM_GPCR_AU_FCT_DIS	= 1<<1,	/* Bit  1:	Disable Auto-Update Flow-C. */
+	GM_GPCR_AU_SPD_DIS	= 1<<0,	/* Bit  0:	Disable Auto-Update Speed */
+};
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
+
+/*	GM_TX_CTRL			16 bit r/w	Transmit Control Register */
+enum {
+	GM_TXCR_FORCE_JAM	= 1<<15, /* Bit 15:	Force Jam / Flow-Control */
+	GM_TXCR_CRC_DIS		= 1<<14, /* Bit 14:	Disable insertion of CRC */
+	GM_TXCR_PAD_DIS		= 1<<13, /* Bit 13:	Disable padding of packets */
+	GM_TXCR_COL_THR_MSK	= 7<<10, /* Bit 12..10:	Collision Threshold */
+};
+
+#define TX_COL_THR(x)		(((x)<<10) & GM_TXCR_COL_THR_MSK)
+#define TX_COL_DEF		0x04	/* late collision after 64 byte */
+
+/*	GM_RX_CTRL			16 bit r/w	Receive Control Register */
+enum {
+	GM_RXCR_UCF_ENA	= 1<<15, /* Bit 15:	Enable Unicast filtering */
+	GM_RXCR_MCF_ENA	= 1<<14, /* Bit 14:	Enable Multicast filtering */
+	GM_RXCR_CRC_DIS	= 1<<13, /* Bit 13:	Remove 4-byte CRC */
+	GM_RXCR_PASS_FC	= 1<<12, /* Bit 12:	Pass FC packets to FIFO */
+};
+
+/*	GM_TX_PARAM		16 bit r/w	Transmit Parameter Register */
+enum {
+	GM_TXPA_JAMLEN_MSK	= 0x03<<14,	/* Bit 15..14:	Jam Length */
+	GM_TXPA_JAMIPG_MSK	= 0x1f<<9,	/* Bit 13..9:	Jam IPG */
+	GM_TXPA_JAMDAT_MSK	= 0x1f<<4,	/* Bit  8..4:	IPG Jam to Data */
+
+	TX_JAM_LEN_DEF		= 0x03,
+	TX_JAM_IPG_DEF		= 0x0b,
+	TX_IPG_JAM_DEF		= 0x1c,
+};
+
+#define TX_JAM_LEN_VAL(x)	(((x)<<14) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x)	(((x)<<9)  & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x)	(((x)<<4)  & GM_TXPA_JAMDAT_MSK)
+
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+enum {
+	GM_SMOD_DATABL_MSK	= 0x1f<<11, /* Bit 15..11:	Data Blinder (r/o) */
+	GM_SMOD_LIMIT_4		= 1<<10, /* Bit 10:	4 consecutive Tx trials */
+	GM_SMOD_VLAN_ENA	= 1<<9,	/* Bit  9:	Enable VLAN  (Max. Frame Len) */
+	GM_SMOD_JUMBO_ENA	= 1<<8,	/* Bit  8:	Enable Jumbo (Max. Frame Len) */
+	 GM_SMOD_IPG_MSK	= 0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+};
+
+#define DATA_BLIND_VAL(x)	(((x)<<11) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF		0x04
+
+#define IPG_DATA_VAL(x)		(x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF		0x1e
+
+/*	GM_SMI_CTRL			16 bit r/w	SMI Control Register */
+enum {
+	GM_SMI_CT_PHY_A_MSK	= 0x1f<<11, /* Bit 15..11:	PHY Device Address */
+	GM_SMI_CT_REG_A_MSK	= 0x1f<<6, /* Bit 10.. 6:	PHY Register Address */
+	GM_SMI_CT_OP_RD		= 1<<5,	/* Bit  5:	OpCode Read (0=Write)*/
+	GM_SMI_CT_RD_VAL	= 1<<4,	/* Bit  4:	Read Valid (Read completed) */
+	GM_SMI_CT_BUSY		= 1<<3,	/* Bit  3:	Busy (Operation in progress) */
+};
+
+#define GM_SMI_CT_PHY_AD(x)	(((x)<<11) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x)	(((x)<<6) & GM_SMI_CT_REG_A_MSK)
+
+/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+enum {
+	GM_PAR_MIB_CLR	= 1<<5,	/* Bit  5:	Set MIB Clear Counter Mode */
+	GM_PAR_MIB_TST	= 1<<4,	/* Bit  4:	MIB Load Counter (Test Mode) */
+};
+
+/* Receive Frame Status Encoding */
+enum {
+	GMR_FS_LEN	= 0xffff<<16, /* Bit 31..16:	Rx Frame Length */
+	GMR_FS_LEN_SHIFT = 16,
+	GMR_FS_VLAN	= 1<<13, /* Bit 13:	VLAN Packet */
+	GMR_FS_JABBER	= 1<<12, /* Bit 12:	Jabber Packet */
+	GMR_FS_UN_SIZE	= 1<<11, /* Bit 11:	Undersize Packet */
+	GMR_FS_MC	= 1<<10, /* Bit 10:	Multicast Packet */
+	GMR_FS_BC	= 1<<9, /* Bit  9:	Broadcast Packet */
+	GMR_FS_RX_OK	= 1<<8, /* Bit  8:	Receive OK (Good Packet) */
+	GMR_FS_GOOD_FC	= 1<<7, /* Bit  7:	Good Flow-Control Packet */
+	GMR_FS_BAD_FC	= 1<<6, /* Bit  6:	Bad  Flow-Control Packet */
+	GMR_FS_MII_ERR	= 1<<5, /* Bit  5:	MII Error */
+	GMR_FS_LONG_ERR	= 1<<4, /* Bit  4:	Too Long Packet */
+	GMR_FS_FRAGMENT	= 1<<3, /* Bit  3:	Fragment */
+
+	GMR_FS_CRC_ERR	= 1<<1, /* Bit  1:	CRC Error */
+	GMR_FS_RX_FF_OV	= 1<<0, /* Bit  0:	Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+	GMR_FS_ANY_ERR	= GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
+			  GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
+			  GMR_FS_JABBER,
+/* Rx GMAC FIFO Flush Mask (default) */
+	RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
+			   GMR_FS_BAD_FC |  GMR_FS_UN_SIZE | GMR_FS_JABBER,
+};
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+enum {
+	GMF_WP_TST_ON	= 1<<14,	/* Write Pointer Test On */
+	GMF_WP_TST_OFF	= 1<<13,	/* Write Pointer Test Off */
+	GMF_WP_STEP	= 1<<12,	/* Write Pointer Step/Increment */
+
+	GMF_RP_TST_ON	= 1<<10,	/* Read Pointer Test On */
+	GMF_RP_TST_OFF	= 1<<9,		/* Read Pointer Test Off */
+	GMF_RP_STEP	= 1<<8,		/* Read Pointer Step/Increment */
+	GMF_RX_F_FL_ON	= 1<<7,		/* Rx FIFO Flush Mode On */
+	GMF_RX_F_FL_OFF	= 1<<6,		/* Rx FIFO Flush Mode Off */
+	GMF_CLI_RX_FO	= 1<<5,		/* Clear IRQ Rx FIFO Overrun */
+	GMF_CLI_RX_FC	= 1<<4,		/* Clear IRQ Rx Frame Complete */
+	GMF_OPER_ON	= 1<<3,		/* Operational Mode On */
+	GMF_OPER_OFF	= 1<<2,		/* Operational Mode Off */
+	GMF_RST_CLR	= 1<<1,		/* Clear GMAC FIFO Reset */
+	GMF_RST_SET	= 1<<0,		/* Set   GMAC FIFO Reset */
+
+	RX_GMF_FL_THR_DEF = 0xa,	/* flush threshold (default) */
+};
+
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+enum {
+	GMF_WSP_TST_ON	= 1<<18, /* Write Shadow Pointer Test On */
+	GMF_WSP_TST_OFF	= 1<<17, /* Write Shadow Pointer Test Off */
+	GMF_WSP_STEP	= 1<<16, /* Write Shadow Pointer Step/Increment */
+
+	GMF_CLI_TX_FU	= 1<<6,	/* Clear IRQ Tx FIFO Underrun */
+	GMF_CLI_TX_FC	= 1<<5,	/* Clear IRQ Tx Frame Complete */
+	GMF_CLI_TX_PE	= 1<<4,	/* Clear IRQ Tx Parity Error */
+};
+
+/*	GMAC_TI_ST_CTRL	 8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+enum {
+	GMT_ST_START	= 1<<2,	/* Start Time Stamp Timer */
+	GMT_ST_STOP	= 1<<1,	/* Stop  Time Stamp Timer */
+	GMT_ST_CLR_IRQ	= 1<<0,	/* Clear Time Stamp Timer IRQ */
+};
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+enum {
+	GMC_H_BURST_ON	= 1<<7,	/* Half Duplex Burst Mode On */
+	GMC_H_BURST_OFF	= 1<<6,	/* Half Duplex Burst Mode Off */
+	GMC_F_LOOPB_ON	= 1<<5,	/* FIFO Loopback On */
+	GMC_F_LOOPB_OFF	= 1<<4,	/* FIFO Loopback Off */
+	GMC_PAUSE_ON	= 1<<3,	/* Pause On */
+	GMC_PAUSE_OFF	= 1<<2,	/* Pause Off */
+	GMC_RST_CLR	= 1<<1,	/* Clear GMAC Reset */
+	GMC_RST_SET	= 1<<0,	/* Set   GMAC Reset */
+};
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+enum {
+	GPC_SEL_BDT	= 1<<28, /* Select Bi-Dir. Transfer for MDC/MDIO */
+	GPC_INT_POL_HI	= 1<<27, /* IRQ Polarity is Active HIGH */
+	GPC_75_OHM	= 1<<26, /* Use 75 Ohm Termination instead of 50 */
+	GPC_DIS_FC	= 1<<25, /* Disable Automatic Fiber/Copper Detection */
+	GPC_DIS_SLEEP	= 1<<24, /* Disable Energy Detect */
+	GPC_HWCFG_M_3	= 1<<23, /* HWCFG_MODE[3] */
+	GPC_HWCFG_M_2	= 1<<22, /* HWCFG_MODE[2] */
+	GPC_HWCFG_M_1	= 1<<21, /* HWCFG_MODE[1] */
+	GPC_HWCFG_M_0	= 1<<20, /* HWCFG_MODE[0] */
+	GPC_ANEG_0	= 1<<19, /* ANEG[0] */
+	GPC_ENA_XC	= 1<<18, /* Enable MDI crossover */
+	GPC_DIS_125	= 1<<17, /* Disable 125 MHz clock */
+	GPC_ANEG_3	= 1<<16, /* ANEG[3] */
+	GPC_ANEG_2	= 1<<15, /* ANEG[2] */
+	GPC_ANEG_1	= 1<<14, /* ANEG[1] */
+	GPC_ENA_PAUSE	= 1<<13, /* Enable Pause (SYM_OR_REM) */
+	GPC_PHYADDR_4	= 1<<12, /* Bit 4 of Phy Addr */
+	GPC_PHYADDR_3	= 1<<11, /* Bit 3 of Phy Addr */
+	GPC_PHYADDR_2	= 1<<10, /* Bit 2 of Phy Addr */
+	GPC_PHYADDR_1	= 1<<9,	 /* Bit 1 of Phy Addr */
+	GPC_PHYADDR_0	= 1<<8,	 /* Bit 0 of Phy Addr */
+						/* Bits  7..2:	reserved */
+	GPC_RST_CLR	= 1<<1,	/* Clear GPHY Reset */
+	GPC_RST_SET	= 1<<0,	/* Set   GPHY Reset */
+};
+
+#define GPC_HWCFG_GMII_COP (GPC_HWCFG_M_3|GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+#define GPC_HWCFG_GMII_FIB (GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+#define GPC_ANEG_ADV_ALL_M  (GPC_ANEG_3 | GPC_ANEG_2 | GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF	0
+#define GPC_FRC10MBIT_FULL	GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF	GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL	(GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF	GPC_ANEG_2
+#define GPC_ADV_1000_FULL	GPC_ANEG_3
+#define GPC_ADV_ALL		(GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER	0
+#define GPC_FORCE_SLAVE		GPC_ANEG_0
+#define GPC_PREF_MASTER		GPC_ANEG_1
+#define GPC_PREF_SLAVE		(GPC_ANEG_1 | GPC_ANEG_0)
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+enum {
+	GM_IS_TX_CO_OV	= 1<<5,	/* Transmit Counter Overflow IRQ */
+	GM_IS_RX_CO_OV	= 1<<4,	/* Receive Counter Overflow IRQ */
+	GM_IS_TX_FF_UR	= 1<<3,	/* Transmit FIFO Underrun */
+	GM_IS_TX_COMPL	= 1<<2,	/* Frame Transmission Complete */
+	GM_IS_RX_FF_OR	= 1<<1,	/* Receive FIFO Overrun */
+	GM_IS_RX_COMPL	= 1<<0,	/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK	(GM_IS_RX_FF_OR | GM_IS_TX_FF_UR)
+
+/*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */
+						/* Bits 15.. 2:	reserved */
+	GMLC_RST_CLR	= 1<<1,	/* Clear GMAC Link Reset */
+	GMLC_RST_SET	= 1<<0,	/* Set   GMAC Link Reset */
+
+
+/*	WOL_CTRL_STAT	16 bit	WOL Control/Status Reg */
+	WOL_CTL_LINK_CHG_OCC		= 1<<15,
+	WOL_CTL_MAGIC_PKT_OCC		= 1<<14,
+	WOL_CTL_PATTERN_OCC		= 1<<13,
+	WOL_CTL_CLEAR_RESULT		= 1<<12,
+	WOL_CTL_ENA_PME_ON_LINK_CHG	= 1<<11,
+	WOL_CTL_DIS_PME_ON_LINK_CHG	= 1<<10,
+	WOL_CTL_ENA_PME_ON_MAGIC_PKT	= 1<<9,
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT	= 1<<8,
+	WOL_CTL_ENA_PME_ON_PATTERN	= 1<<7,
+	WOL_CTL_DIS_PME_ON_PATTERN	= 1<<6,
+	WOL_CTL_ENA_LINK_CHG_UNIT	= 1<<5,
+	WOL_CTL_DIS_LINK_CHG_UNIT	= 1<<4,
+	WOL_CTL_ENA_MAGIC_PKT_UNIT	= 1<<3,
+	WOL_CTL_DIS_MAGIC_PKT_UNIT	= 1<<2,
+	WOL_CTL_ENA_PATTERN_UNIT	= 1<<1,
+	WOL_CTL_DIS_PATTERN_UNIT	= 1<<0,
+};
+
+#define WOL_CTL_DEFAULT				\
+	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
+	WOL_CTL_DIS_PME_ON_PATTERN |	\
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
+	WOL_CTL_DIS_LINK_CHG_UNIT |		\
+	WOL_CTL_DIS_PATTERN_UNIT |		\
+	WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/*	WOL_MATCH_CTL	 8 bit	WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)	(1 << (x))
+
+
+/* XMAC II registers				      */
+enum {
+	XM_MMU_CMD	= 0x0000, /* 16 bit r/w	MMU Command Register */
+	XM_POFF		= 0x0008, /* 32 bit r/w	Packet Offset Register */
+	XM_BURST	= 0x000c, /* 32 bit r/w	Burst Register for half duplex*/
+	XM_1L_VLAN_TAG	= 0x0010, /* 16 bit r/w	One Level VLAN Tag ID */
+	XM_2L_VLAN_TAG	= 0x0014, /* 16 bit r/w	Two Level VLAN Tag ID */
+	XM_TX_CMD	= 0x0020, /* 16 bit r/w	Transmit Command Register */
+	XM_TX_RT_LIM	= 0x0024, /* 16 bit r/w	Transmit Retry Limit Register */
+	XM_TX_STIME	= 0x0028, /* 16 bit r/w	Transmit Slottime Register */
+	XM_TX_IPG	= 0x002c, /* 16 bit r/w	Transmit Inter Packet Gap */
+	XM_RX_CMD	= 0x0030, /* 16 bit r/w	Receive Command Register */
+	XM_PHY_ADDR	= 0x0034, /* 16 bit r/w	PHY Address Register */
+	XM_PHY_DATA	= 0x0038, /* 16 bit r/w	PHY Data Register */
+	XM_GP_PORT	= 0x0040, /* 32 bit r/w	General Purpose Port Register */
+	XM_IMSK		= 0x0044, /* 16 bit r/w	Interrupt Mask Register */
+	XM_ISRC		= 0x0048, /* 16 bit r/o	Interrupt Status Register */
+	XM_HW_CFG	= 0x004c, /* 16 bit r/w	Hardware Config Register */
+	XM_TX_LO_WM	= 0x0060, /* 16 bit r/w	Tx FIFO Low Water Mark */
+	XM_TX_HI_WM	= 0x0062, /* 16 bit r/w	Tx FIFO High Water Mark */
+	XM_TX_THR	= 0x0064, /* 16 bit r/w	Tx Request Threshold */
+	XM_HT_THR	= 0x0066, /* 16 bit r/w	Host Request Threshold */
+	XM_PAUSE_DA	= 0x0068, /* NA reg r/w	Pause Destination Address */
+	XM_CTL_PARA	= 0x0070, /* 32 bit r/w	Control Parameter Register */
+	XM_MAC_OPCODE	= 0x0074, /* 16 bit r/w	Opcode for MAC control frames */
+	XM_MAC_PTIME	= 0x0076, /* 16 bit r/w	Pause time for MAC ctrl frames*/
+	XM_TX_STAT	= 0x0078, /* 32 bit r/o	Tx Status LIFO Register */
+
+	XM_EXM_START	= 0x0080, /* r/w	Start Address of the EXM Regs */
+#define XM_EXM(reg)	(XM_EXM_START + ((reg) << 3))
+};
+
+enum {
+	XM_SRC_CHK	= 0x0100, /* NA reg r/w	Source Check Address Register */
+	XM_SA		= 0x0108, /* NA reg r/w	Station Address Register */
+	XM_HSM		= 0x0110, /* 64 bit r/w	Hash Match Address Registers */
+	XM_RX_LO_WM	= 0x0118, /* 16 bit r/w	Receive Low Water Mark */
+	XM_RX_HI_WM	= 0x011a, /* 16 bit r/w	Receive High Water Mark */
+	XM_RX_THR	= 0x011c, /* 32 bit r/w	Receive Request Threshold */
+	XM_DEV_ID	= 0x0120, /* 32 bit r/o	Device ID Register */
+	XM_MODE		= 0x0124, /* 32 bit r/w	Mode Register */
+	XM_LSA		= 0x0128, /* NA reg r/o	Last Source Register */
+	XM_TS_READ	= 0x0130, /* 32 bit r/o	Time Stamp Read Register */
+	XM_TS_LOAD	= 0x0134, /* 32 bit r/o	Time Stamp Load Value */
+	XM_STAT_CMD	= 0x0200, /* 16 bit r/w	Statistics Command Register */
+	XM_RX_CNT_EV	= 0x0204, /* 32 bit r/o	Rx Counter Event Register */
+	XM_TX_CNT_EV	= 0x0208, /* 32 bit r/o	Tx Counter Event Register */
+	XM_RX_EV_MSK	= 0x020c, /* 32 bit r/w	Rx Counter Event Mask */
+	XM_TX_EV_MSK	= 0x0210, /* 32 bit r/w	Tx Counter Event Mask */
+	XM_TXF_OK	= 0x0280, /* 32 bit r/o	Frames Transmitted OK Conuter */
+	XM_TXO_OK_HI	= 0x0284, /* 32 bit r/o	Octets Transmitted OK High Cnt*/
+	XM_TXO_OK_LO	= 0x0288, /* 32 bit r/o	Octets Transmitted OK Low Cnt */
+	XM_TXF_BC_OK	= 0x028c, /* 32 bit r/o	Broadcast Frames Xmitted OK */
+	XM_TXF_MC_OK	= 0x0290, /* 32 bit r/o	Multicast Frames Xmitted OK */
+	XM_TXF_UC_OK	= 0x0294, /* 32 bit r/o	Unicast Frames Xmitted OK */
+	XM_TXF_LONG	= 0x0298, /* 32 bit r/o	Tx Long Frame Counter */
+	XM_TXE_BURST	= 0x029c, /* 32 bit r/o	Tx Burst Event Counter */
+	XM_TXF_MPAUSE	= 0x02a0, /* 32 bit r/o	Tx Pause MAC Ctrl Frame Cnt */
+	XM_TXF_MCTRL	= 0x02a4, /* 32 bit r/o	Tx MAC Ctrl Frame Counter */
+	XM_TXF_SNG_COL	= 0x02a8, /* 32 bit r/o	Tx Single Collision Counter */
+	XM_TXF_MUL_COL	= 0x02ac, /* 32 bit r/o	Tx Multiple Collision Counter */
+	XM_TXF_ABO_COL	= 0x02b0, /* 32 bit r/o	Tx aborted due to Exces. Col. */
+	XM_TXF_LAT_COL	= 0x02b4, /* 32 bit r/o	Tx Late Collision Counter */
+	XM_TXF_DEF	= 0x02b8, /* 32 bit r/o	Tx Deferred Frame Counter */
+	XM_TXF_EX_DEF	= 0x02bc, /* 32 bit r/o	Tx Excessive Deferall Counter */
+	XM_TXE_FIFO_UR	= 0x02c0, /* 32 bit r/o	Tx FIFO Underrun Event Cnt */
+	XM_TXE_CS_ERR	= 0x02c4, /* 32 bit r/o	Tx Carrier Sense Error Cnt */
+	XM_TXP_UTIL	= 0x02c8, /* 32 bit r/o	Tx Utilization in % */
+	XM_TXF_64B	= 0x02d0, /* 32 bit r/o	64 Byte Tx Frame Counter */
+	XM_TXF_127B	= 0x02d4, /* 32 bit r/o	65-127 Byte Tx Frame Counter */
+	XM_TXF_255B	= 0x02d8, /* 32 bit r/o	128-255 Byte Tx Frame Counter */
+	XM_TXF_511B	= 0x02dc, /* 32 bit r/o	256-511 Byte Tx Frame Counter */
+	XM_TXF_1023B	= 0x02e0, /* 32 bit r/o	512-1023 Byte Tx Frame Counter*/
+	XM_TXF_MAX_SZ	= 0x02e4, /* 32 bit r/o	1024-MaxSize Byte Tx Frame Cnt*/
+	XM_RXF_OK	= 0x0300, /* 32 bit r/o	Frames Received OK */
+	XM_RXO_OK_HI	= 0x0304, /* 32 bit r/o	Octets Received OK High Cnt */
+	XM_RXO_OK_LO	= 0x0308, /* 32 bit r/o	Octets Received OK Low Counter*/
+	XM_RXF_BC_OK	= 0x030c, /* 32 bit r/o	Broadcast Frames Received OK */
+	XM_RXF_MC_OK	= 0x0310, /* 32 bit r/o	Multicast Frames Received OK */
+	XM_RXF_UC_OK	= 0x0314, /* 32 bit r/o	Unicast Frames Received OK */
+	XM_RXF_MPAUSE	= 0x0318, /* 32 bit r/o	Rx Pause MAC Ctrl Frame Cnt */
+	XM_RXF_MCTRL	= 0x031c, /* 32 bit r/o	Rx MAC Ctrl Frame Counter */
+	XM_RXF_INV_MP	= 0x0320, /* 32 bit r/o	Rx invalid Pause Frame Cnt */
+	XM_RXF_INV_MOC	= 0x0324, /* 32 bit r/o	Rx Frames with inv. MAC Opcode*/
+	XM_RXE_BURST	= 0x0328, /* 32 bit r/o	Rx Burst Event Counter */
+	XM_RXE_FMISS	= 0x032c, /* 32 bit r/o	Rx Missed Frames Event Cnt */
+	XM_RXF_FRA_ERR	= 0x0330, /* 32 bit r/o	Rx Framing Error Counter */
+	XM_RXE_FIFO_OV	= 0x0334, /* 32 bit r/o	Rx FIFO overflow Event Cnt */
+	XM_RXF_JAB_PKT	= 0x0338, /* 32 bit r/o	Rx Jabber Packet Frame Cnt */
+	XM_RXE_CAR_ERR	= 0x033c, /* 32 bit r/o	Rx Carrier Event Error Cnt */
+	XM_RXF_LEN_ERR	= 0x0340, /* 32 bit r/o	Rx in Range Length Error */
+	XM_RXE_SYM_ERR	= 0x0344, /* 32 bit r/o	Rx Symbol Error Counter */
+	XM_RXE_SHT_ERR	= 0x0348, /* 32 bit r/o	Rx Short Event Error Cnt */
+	XM_RXE_RUNT	= 0x034c, /* 32 bit r/o	Rx Runt Event Counter */
+	XM_RXF_LNG_ERR	= 0x0350, /* 32 bit r/o	Rx Frame too Long Error Cnt */
+	XM_RXF_FCS_ERR	= 0x0354, /* 32 bit r/o	Rx Frame Check Seq. Error Cnt */
+	XM_RXF_CEX_ERR	= 0x035c, /* 32 bit r/o	Rx Carrier Ext Error Frame Cnt*/
+	XM_RXP_UTIL	= 0x0360, /* 32 bit r/o	Rx Utilization in % */
+	XM_RXF_64B	= 0x0368, /* 32 bit r/o	64 Byte Rx Frame Counter */
+	XM_RXF_127B	= 0x036c, /* 32 bit r/o	65-127 Byte Rx Frame Counter */
+	XM_RXF_255B	= 0x0370, /* 32 bit r/o	128-255 Byte Rx Frame Counter */
+	XM_RXF_511B	= 0x0374, /* 32 bit r/o	256-511 Byte Rx Frame Counter */
+	XM_RXF_1023B	= 0x0378, /* 32 bit r/o	512-1023 Byte Rx Frame Counter*/
+	XM_RXF_MAX_SZ	= 0x037c, /* 32 bit r/o	1024-MaxSize Byte Rx Frame Cnt*/
+};
+
+/*	XM_MMU_CMD	16 bit r/w	MMU Command Register */
+enum {
+	XM_MMU_PHY_RDY	= 1<<12, /* Bit 12:	PHY Read Ready */
+	XM_MMU_PHY_BUSY	= 1<<11, /* Bit 11:	PHY Busy */
+	XM_MMU_IGN_PF	= 1<<10, /* Bit 10:	Ignore Pause Frame */
+	XM_MMU_MAC_LB	= 1<<9,	 /* Bit  9:	Enable MAC Loopback */
+	XM_MMU_FRC_COL	= 1<<7,	 /* Bit  7:	Force Collision */
+	XM_MMU_SIM_COL	= 1<<6,	 /* Bit  6:	Simulate Collision */
+	XM_MMU_NO_PRE	= 1<<5,	 /* Bit  5:	No MDIO Preamble */
+	XM_MMU_GMII_FD	= 1<<4,	 /* Bit  4:	GMII uses Full Duplex */
+	XM_MMU_RAT_CTRL	= 1<<3,	 /* Bit  3:	Enable Rate Control */
+	XM_MMU_GMII_LOOP= 1<<2,	 /* Bit  2:	PHY is in Loopback Mode */
+	XM_MMU_ENA_RX	= 1<<1,	 /* Bit  1:	Enable Receiver */
+	XM_MMU_ENA_TX	= 1<<0,	 /* Bit  0:	Enable Transmitter */
+};
+
+
+/*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
+enum {
+	XM_TX_BK2BK	= 1<<6,	/* Bit  6:	Ignor Carrier Sense (Tx Bk2Bk)*/
+	XM_TX_ENC_BYP	= 1<<5,	/* Bit  5:	Set Encoder in Bypass Mode */
+	XM_TX_SAM_LINE	= 1<<4,	/* Bit  4: (sc)	Start utilization calculation */
+	XM_TX_NO_GIG_MD	= 1<<3,	/* Bit  3:	Disable Carrier Extension */
+	XM_TX_NO_PRE	= 1<<2,	/* Bit  2:	Disable Preamble Generation */
+	XM_TX_NO_CRC	= 1<<1,	/* Bit  1:	Disable CRC Generation */
+	XM_TX_AUTO_PAD	= 1<<0,	/* Bit  0:	Enable Automatic Padding */
+};
+
+/*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
+#define XM_RT_LIM_MSK	0x1f	/* Bit  4..0:	Tx Retry Limit */
+
+
+/*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
+#define XM_STIME_MSK	0x7f	/* Bit  6..0:	Tx Slottime bits */
+
+
+/*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
+#define XM_IPG_MSK		0xff	/* Bit  7..0:	IPG value bits */
+
+
+/*	XM_RX_CMD	16 bit r/w	Receive Command Register */
+enum {
+	XM_RX_LENERR_OK	= 1<<8,	/* Bit  8	don't set Rx Err bit for */
+				/*		inrange error packets */
+	XM_RX_BIG_PK_OK	= 1<<7,	/* Bit  7	don't set Rx Err bit for */
+				/*		jumbo packets */
+	XM_RX_IPG_CAP	= 1<<6,	/* Bit  6	repl. type field with IPG */
+	XM_RX_TP_MD	= 1<<5,	/* Bit  5:	Enable transparent Mode */
+	XM_RX_STRIP_FCS	= 1<<4,	/* Bit  4:	Enable FCS Stripping */
+	XM_RX_SELF_RX	= 1<<3,	/* Bit  3: 	Enable Rx of own packets */
+	XM_RX_SAM_LINE	= 1<<2,	/* Bit  2: (sc)	Start utilization calculation */
+	XM_RX_STRIP_PAD	= 1<<1,	/* Bit  1:	Strip pad bytes of Rx frames */
+	XM_RX_DIS_CEXT	= 1<<0,	/* Bit  0:	Disable carrier ext. check */
+};
+
+
+/*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
+enum {
+	XM_GP_ANIP	= 1<<6,	/* Bit  6: (ro)	Auto-Neg. in progress */
+	XM_GP_FRC_INT	= 1<<5,	/* Bit  5: (sc)	Force Interrupt */
+	XM_GP_RES_MAC	= 1<<3,	/* Bit  3: (sc)	Reset MAC and FIFOs */
+	XM_GP_RES_STAT	= 1<<2,	/* Bit  2: (sc)	Reset the statistics module */
+	XM_GP_INP_ASS	= 1<<0,	/* Bit  0: (ro) GP Input Pin asserted */
+};
+
+
+/*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
+/*	XM_ISRC		16 bit r/o	Interrupt Status Register */
+enum {
+	XM_IS_LNK_AE	= 1<<14, /* Bit 14:	Link Asynchronous Event */
+	XM_IS_TX_ABORT	= 1<<13, /* Bit 13:	Transmit Abort, late Col. etc */
+	XM_IS_FRC_INT	= 1<<12, /* Bit 12:	Force INT bit set in GP */
+	XM_IS_INP_ASS	= 1<<11, /* Bit 11:	Input Asserted, GP bit 0 set */
+	XM_IS_LIPA_RC	= 1<<10, /* Bit 10:	Link Partner requests config */
+	XM_IS_RX_PAGE	= 1<<9,	/* Bit  9:	Page Received */
+	XM_IS_TX_PAGE	= 1<<8,	/* Bit  8:	Next Page Loaded for Transmit */
+	XM_IS_AND	= 1<<7,	/* Bit  7:	Auto-Negotiation Done */
+	XM_IS_TSC_OV	= 1<<6,	/* Bit  6:	Time Stamp Counter Overflow */
+	XM_IS_RXC_OV	= 1<<5,	/* Bit  5:	Rx Counter Event Overflow */
+	XM_IS_TXC_OV	= 1<<4,	/* Bit  4:	Tx Counter Event Overflow */
+	XM_IS_RXF_OV	= 1<<3,	/* Bit  3:	Receive FIFO Overflow */
+	XM_IS_TXF_UR	= 1<<2,	/* Bit  2:	Transmit FIFO Underrun */
+	XM_IS_TX_COMP	= 1<<1,	/* Bit  1:	Frame Tx Complete */
+	XM_IS_RX_COMP	= 1<<0,	/* Bit  0:	Frame Rx Complete */
+
+	XM_IMSK_DISABLE	= 0xffff,
+};
+
+/*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
+enum {
+	XM_HW_GEN_EOP	= 1<<3,	/* Bit  3:	generate End of Packet pulse */
+	XM_HW_COM4SIG	= 1<<2,	/* Bit  2:	use Comma Detect for Sig. Det.*/
+	XM_HW_GMII_MD	= 1<<0,	/* Bit  0:	GMII Interface selected */
+};
+
+
+/*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
+/*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_WM_MSK	0x01ff	/* Bit  9.. 0	Tx FIFO Watermark bits */
+
+/*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
+/*	XM_HT_THR	16 bit r/w	Host Request Threshold */
+/*	XM_RX_THR	16 bit r/w	Rx Request Threshold */
+#define XM_THR_MSK		0x03ff	/* Bit 10.. 0	Rx/Tx Request Threshold bits */
+
+
+/*	XM_TX_STAT	32 bit r/o	Tx Status LIFO Register */
+enum {
+	XM_ST_VALID	= (1UL<<31),	/* Bit 31:	Status Valid */
+	XM_ST_BYTE_CNT	= (0x3fffL<<17),	/* Bit 30..17:	Tx frame Length */
+	XM_ST_RETRY_CNT	= (0x1fL<<12),	/* Bit 16..12:	Retry Count */
+	XM_ST_EX_COL	= 1<<11,	/* Bit 11:	Excessive Collisions */
+	XM_ST_EX_DEF	= 1<<10,	/* Bit 10:	Excessive Deferral */
+	XM_ST_BURST	= 1<<9,		/* Bit  9:	p. xmitted in burst md*/
+	XM_ST_DEFER	= 1<<8,		/* Bit  8:	packet was defered */
+	XM_ST_BC	= 1<<7,		/* Bit  7:	Broadcast packet */
+	XM_ST_MC	= 1<<6,		/* Bit  6:	Multicast packet */
+	XM_ST_UC	= 1<<5,		/* Bit  5:	Unicast packet */
+	XM_ST_TX_UR	= 1<<4,		/* Bit  4:	FIFO Underrun occured */
+	XM_ST_CS_ERR	= 1<<3,		/* Bit  3:	Carrier Sense Error */
+	XM_ST_LAT_COL	= 1<<2,		/* Bit  2:	Late Collision Error */
+	XM_ST_MUL_COL	= 1<<1,		/* Bit  1:	Multiple Collisions */
+	XM_ST_SGN_COL	= 1<<0,		/* Bit  0:	Single Collision */
+};
+
+/*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
+/*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
+#define XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
+
+
+/*	XM_DEV_ID	32 bit r/o	Device ID Register */
+#define XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit  7..5:	Chip Rev Num */
+
+
+/*	XM_MODE		32 bit r/w	Mode Register */
+enum {
+	XM_MD_ENA_REJ	= 1<<26, /* Bit 26:	Enable Frame Reject */
+	XM_MD_SPOE_E	= 1<<25, /* Bit 25:	Send Pause on Edge */
+									/* 		extern generated */
+	XM_MD_TX_REP	= 1<<24, /* Bit 24:	Transmit Repeater Mode */
+	XM_MD_SPOFF_I	= 1<<23, /* Bit 23:	Send Pause on FIFO full */
+									/*		intern generated */
+	XM_MD_LE_STW	= 1<<22, /* Bit 22:	Rx Stat Word in Little Endian */
+	XM_MD_TX_CONT	= 1<<21, /* Bit 21:	Send Continuous */
+	XM_MD_TX_PAUSE	= 1<<20, /* Bit 20: (sc)	Send Pause Frame */
+	XM_MD_ATS	= 1<<19, /* Bit 19:	Append Time Stamp */
+	XM_MD_SPOL_I	= 1<<18, /* Bit 18:	Send Pause on Low */
+									/*		intern generated */
+	XM_MD_SPOH_I	= 1<<17, /* Bit 17:	Send Pause on High */
+									/*		intern generated */
+	XM_MD_CAP	= 1<<16, /* Bit 16:	Check Address Pair */
+	XM_MD_ENA_HASH	= 1<<15, /* Bit 15:	Enable Hashing */
+	XM_MD_CSA	= 1<<14, /* Bit 14:	Check Station Address */
+	XM_MD_CAA	= 1<<13, /* Bit 13:	Check Address Array */
+	XM_MD_RX_MCTRL	= 1<<12, /* Bit 12:	Rx MAC Control Frame */
+	XM_MD_RX_RUNT	= 1<<11, /* Bit 11:	Rx Runt Frames */
+	XM_MD_RX_IRLE	= 1<<10, /* Bit 10:	Rx in Range Len Err Frame */
+	XM_MD_RX_LONG	= 1<<9,  /* Bit  9:	Rx Long Frame */
+	XM_MD_RX_CRCE	= 1<<8,  /* Bit  8:	Rx CRC Error Frame */
+	XM_MD_RX_ERR	= 1<<7,  /* Bit  7:	Rx Error Frame */
+	XM_MD_DIS_UC	= 1<<6,  /* Bit  6:	Disable Rx Unicast */
+	XM_MD_DIS_MC	= 1<<5,  /* Bit  5:	Disable Rx Multicast */
+	XM_MD_DIS_BC	= 1<<4,  /* Bit  4:	Disable Rx Broadcast */
+	XM_MD_ENA_PROM	= 1<<3,  /* Bit  3:	Enable Promiscuous */
+	XM_MD_ENA_BE	= 1<<2,  /* Bit  2:	Enable Big Endian */
+	XM_MD_FTF	= 1<<1,  /* Bit  1: (sc)	Flush Tx FIFO */
+	XM_MD_FRF	= 1<<0,  /* Bit  0: (sc)	Flush Rx FIFO */
+};
+
+#define XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE	(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+			 XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA)
+
+/*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
+enum {
+	XM_SC_SNP_RXC	= 1<<5,	/* Bit  5: (sc)	Snap Rx Counters */
+	XM_SC_SNP_TXC	= 1<<4,	/* Bit  4: (sc)	Snap Tx Counters */
+	XM_SC_CP_RXC	= 1<<3,	/* Bit  3: 	Copy Rx Counters Continuously */
+	XM_SC_CP_TXC	= 1<<2,	/* Bit  2:	Copy Tx Counters Continuously */
+	XM_SC_CLR_RXC	= 1<<1,	/* Bit  1: (sc)	Clear Rx Counters */
+	XM_SC_CLR_TXC	= 1<<0,	/* Bit  0: (sc) Clear Tx Counters */
+};
+
+
+/*	XM_RX_CNT_EV	32 bit r/o	Rx Counter Event Register */
+/*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
+enum {
+	XMR_MAX_SZ_OV	= 1<<31, /* Bit 31:	1024-MaxSize Rx Cnt Ov*/
+	XMR_1023B_OV	= 1<<30, /* Bit 30:	512-1023Byte Rx Cnt Ov*/
+	XMR_511B_OV	= 1<<29, /* Bit 29:	256-511 Byte Rx Cnt Ov*/
+	XMR_255B_OV	= 1<<28, /* Bit 28:	128-255 Byte Rx Cnt Ov*/
+	XMR_127B_OV	= 1<<27, /* Bit 27:	65-127 Byte Rx Cnt Ov */
+	XMR_64B_OV	= 1<<26, /* Bit 26:	64 Byte Rx Cnt Ov */
+	XMR_UTIL_OV	= 1<<25, /* Bit 25:	Rx Util Cnt Overflow */
+	XMR_UTIL_UR	= 1<<24, /* Bit 24:	Rx Util Cnt Underrun */
+	XMR_CEX_ERR_OV	= 1<<23, /* Bit 23:	CEXT Err Cnt Ov */
+	XMR_FCS_ERR_OV	= 1<<21, /* Bit 21:	Rx FCS Error Cnt Ov */
+	XMR_LNG_ERR_OV	= 1<<20, /* Bit 20:	Rx too Long Err Cnt Ov*/
+	XMR_RUNT_OV	= 1<<19, /* Bit 19:	Runt Event Cnt Ov */
+	XMR_SHT_ERR_OV	= 1<<18, /* Bit 18:	Rx Short Ev Err Cnt Ov*/
+	XMR_SYM_ERR_OV	= 1<<17, /* Bit 17:	Rx Sym Err Cnt Ov */
+	XMR_CAR_ERR_OV	= 1<<15, /* Bit 15:	Rx Carr Ev Err Cnt Ov */
+	XMR_JAB_PKT_OV	= 1<<14, /* Bit 14:	Rx Jabb Packet Cnt Ov */
+	XMR_FIFO_OV	= 1<<13, /* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+	XMR_FRA_ERR_OV	= 1<<12, /* Bit 12:	Rx Framing Err Cnt Ov */
+	XMR_FMISS_OV	= 1<<11, /* Bit 11:	Rx Missed Ev Cnt Ov */
+	XMR_BURST	= 1<<10, /* Bit 10:	Rx Burst Event Cnt Ov */
+	XMR_INV_MOC	= 1<<9,  /* Bit  9:	Rx with inv. MAC OC Ov*/
+	XMR_INV_MP	= 1<<8,  /* Bit  8:	Rx inv Pause Frame Ov */
+	XMR_MCTRL_OV	= 1<<7,  /* Bit  7:	Rx MAC Ctrl-F Cnt Ov */
+	XMR_MPAUSE_OV	= 1<<6,  /* Bit  6:	Rx Pause MAC Ctrl-F Ov*/
+	XMR_UC_OK_OV	= 1<<5,  /* Bit  5:	Rx Unicast Frame CntOv*/
+	XMR_MC_OK_OV	= 1<<4,  /* Bit  4:	Rx Multicast Cnt Ov */
+	XMR_BC_OK_OV	= 1<<3,  /* Bit  3:	Rx Broadcast Cnt Ov */
+	XMR_OK_LO_OV	= 1<<2,  /* Bit  2:	Octets Rx OK Low CntOv*/
+	XMR_OK_HI_OV	= 1<<1,  /* Bit  1:	Octets Rx OK Hi Cnt Ov*/
+	XMR_OK_OV	= 1<<0,  /* Bit  0:	Frames Received Ok Ov */
+};
+
+#define XMR_DEF_MSK		(XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/*	XM_TX_CNT_EV	32 bit r/o	Tx Counter Event Register */
+/*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
+enum {
+	XMT_MAX_SZ_OV	= 1<<25,	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
+	XMT_1023B_OV	= 1<<24,	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
+	XMT_511B_OV	= 1<<23,	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+	XMT_255B_OV	= 1<<22,	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+	XMT_127B_OV	= 1<<21,	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+	XMT_64B_OV	= 1<<20,	/* Bit 20:	64 Byte Tx Cnt Ov */
+	XMT_UTIL_OV	= 1<<19,	/* Bit 19:	Tx Util Cnt Overflow */
+	XMT_UTIL_UR	= 1<<18,	/* Bit 18:	Tx Util Cnt Underrun */
+	XMT_CS_ERR_OV	= 1<<17,	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
+	XMT_FIFO_UR_OV	= 1<<16,	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
+	XMT_EX_DEF_OV	= 1<<15,	/* Bit 15:	Tx Ex Deferall Cnt Ov */
+	XMT_DEF	= 1<<14,	/* Bit 14:	Tx Deferred Cnt Ov */
+	XMT_LAT_COL_OV	= 1<<13,	/* Bit 13:	Tx Late Col Cnt Ov */
+	XMT_ABO_COL_OV	= 1<<12,	/* Bit 12:	Tx abo dueto Ex Col Ov*/
+	XMT_MUL_COL_OV	= 1<<11,	/* Bit 11:	Tx Mult Col Cnt Ov */
+	XMT_SNG_COL	= 1<<10,	/* Bit 10:	Tx Single Col Cnt Ov */
+	XMT_MCTRL_OV	= 1<<9,		/* Bit  9:	Tx MAC Ctrl Counter Ov*/
+	XMT_MPAUSE	= 1<<8,		/* Bit  8:	Tx Pause MAC Ctrl-F Ov*/
+	XMT_BURST	= 1<<7,		/* Bit  7:	Tx Burst Event Cnt Ov */
+	XMT_LONG	= 1<<6,		/* Bit  6:	Tx Long Frame Cnt Ov */
+	XMT_UC_OK_OV	= 1<<5,		/* Bit  5:	Tx Unicast Cnt Ov */
+	XMT_MC_OK_OV	= 1<<4,		/* Bit  4:	Tx Multicast Cnt Ov */
+	XMT_BC_OK_OV	= 1<<3,		/* Bit  3:	Tx Broadcast Cnt Ov */
+	XMT_OK_LO_OV	= 1<<2,		/* Bit  2:	Octets Tx OK Low CntOv*/
+	XMT_OK_HI_OV	= 1<<1,		/* Bit  1:	Octets Tx OK Hi Cnt Ov*/
+	XMT_OK_OV	= 1<<0,		/* Bit  0:	Frames Tx Ok Ov */
+};
+
+
+#define XMT_DEF_MSK		(XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+struct skge_rx_desc {
+	u32		control;
+	u32		next_offset;
+	u32		dma_lo;
+	u32		dma_hi;
+	u32		status;
+	u32		timestamp;
+	u16		csum2;
+	u16		csum1;
+	u16		csum2_start;
+	u16		csum1_start;
+};
+
+struct skge_tx_desc {
+	u32		control;
+	u32		next_offset;
+	u32		dma_lo;
+	u32		dma_hi;
+	u32		status;
+	u32		csum_offs;
+	u16		csum_write;
+	u16		csum_start;
+	u32		rsvd;
+};
+
+struct skge_element {
+	struct skge_element	*next;
+	void			*desc;
+	struct io_buffer	*iob;
+};
+
+struct skge_ring {
+	struct skge_element *to_clean;
+	struct skge_element *to_use;
+	struct skge_element *start;
+};
+
+
+struct skge_hw {
+	unsigned long	     regs;
+	struct pci_device    *pdev;
+	u32		     intr_mask;
+	struct net_device    *dev[2];
+
+	u8	     	     chip_id;
+	u8		     chip_rev;
+	u8		     copper;
+	u8		     ports;
+	u8		     phy_type;
+
+	u32	     	     ram_size;
+	u32	     	     ram_offset;
+	u16		     phy_addr;
+};
+
+enum pause_control {
+	FLOW_MODE_NONE 		= 1, /* No Flow-Control */
+	FLOW_MODE_LOC_SEND	= 2, /* Local station sends PAUSE */
+	FLOW_MODE_SYMMETRIC	= 3, /* Both stations may send PAUSE */
+	FLOW_MODE_SYM_OR_REM	= 4, /* Both stations may send PAUSE or
+				      * just the remote station may send PAUSE
+				      */
+};
+
+enum pause_status {
+	FLOW_STAT_INDETERMINATED=0,	/* indeterminated */
+	FLOW_STAT_NONE,			/* No Flow Control */
+	FLOW_STAT_REM_SEND,		/* Remote Station sends PAUSE */
+	FLOW_STAT_LOC_SEND,		/* Local station sends PAUSE */
+	FLOW_STAT_SYMMETRIC,		/* Both station may send PAUSE */
+};
+
+
+struct skge_port {
+	struct skge_hw	     *hw;
+	struct net_device    *netdev;
+	int		     port;
+
+	struct skge_ring     tx_ring;
+	struct skge_ring     rx_ring;
+
+	enum pause_control   flow_control;
+	enum pause_status    flow_status;
+	u8		     autoneg;	/* AUTONEG_ENABLE, AUTONEG_DISABLE */
+	u8		     duplex;	/* DUPLEX_HALF, DUPLEX_FULL */
+	u16		     speed;	/* SPEED_1000, SPEED_100, ... */
+	u32		     advertising;
+
+	void		     *mem;	/* PCI memory for rings */
+	u32		     dma;
+	int		     use_xm_link_timer;
+};
+
+
+/* Register accessor for memory mapped device */
+static inline u32 skge_read32(const struct skge_hw *hw, int reg)
+{
+	return readl(hw->regs + reg);
+}
+
+static inline u16 skge_read16(const struct skge_hw *hw, int reg)
+{
+	return readw(hw->regs + reg);
+}
+
+static inline u8 skge_read8(const struct skge_hw *hw, int reg)
+{
+	return readb(hw->regs + reg);
+}
+
+static inline void skge_write32(const struct skge_hw *hw, int reg, u32 val)
+{
+	writel(val, hw->regs + reg);
+}
+
+static inline void skge_write16(const struct skge_hw *hw, int reg, u16 val)
+{
+	writew(val, hw->regs + reg);
+}
+
+static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
+{
+	writeb(val, hw->regs + reg);
+}
+
+/* MAC Related Registers inside the device. */
+#define SK_REG(port,reg)	(((port)<<7)+(u16)(reg))
+#define SK_XMAC_REG(port, reg) \
+	((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
+
+static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg)
+{
+	u32 v;
+	v = skge_read16(hw, SK_XMAC_REG(port, reg));
+	v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16;
+	return v;
+}
+
+static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read16(hw, SK_XMAC_REG(port,reg));
+}
+
+static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+{
+	skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff);
+	skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16);
+}
+
+static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+{
+	skge_write16(hw, SK_XMAC_REG(port,r), v);
+}
+
+static inline void xm_outhash(const struct skge_hw *hw, int port, int reg,
+				   const u8 *hash)
+{
+	xm_write16(hw, port, reg,   (u16)hash[0] | ((u16)hash[1] << 8));
+	xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8));
+	xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8));
+	xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8));
+}
+
+static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg,
+				   const u8 *addr)
+{
+	xm_write16(hw, port, reg,   (u16)addr[0] | ((u16)addr[1] << 8));
+	xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8));
+	xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8));
+}
+
+#define SK_GMAC_REG(port,reg) \
+	(BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg))
+
+static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read16(hw, SK_GMAC_REG(port,reg));
+}
+
+static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg)
+{
+	return (u32) skge_read16(hw, SK_GMAC_REG(port,reg))
+		| ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16);
+}
+
+static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+{
+	skge_write16(hw, SK_GMAC_REG(port,r), v);
+}
+
+static inline void gma_set_addr(struct skge_hw *hw, int port, int reg,
+				    const u8 *addr)
+{
+	gma_write16(hw, port, reg,  (u16) addr[0] | ((u16) addr[1] << 8));
+	gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
+	gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.c
new file mode 100644
index 0000000..5b5bd6b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.c
@@ -0,0 +1,2393 @@
+/*
+ * iPXE driver for Marvell Yukon 2 chipset. Derived from Linux sky2 driver
+ * (v1.22), which was based on earlier sk98lin and skge drivers.
+ *
+ * This driver intentionally does not support all the features
+ * of the original driver such as link fail-over and link management because
+ * those should be done at higher levels.
+ *
+ * Copyright (C) 2005 Stephen Hemminger <shemminger at osdl.org>
+ *
+ * Modified for iPXE, April 2009 by Joshua Oreman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <byteswap.h>
+#include <mii.h>
+
+#include "sky2.h"
+
+#define DRV_NAME		"sky2"
+#define DRV_VERSION		"1.22"
+#define PFX			DRV_NAME " "
+
+/*
+ * The Yukon II chipset takes 64 bit command blocks (called list elements)
+ * that are organized into three (receive, transmit, status) different rings
+ * similar to Tigon3.
+ *
+ * Each ring start must be aligned to a 4k boundary. You will get mysterious
+ * "invalid LE" errors if they're not.
+ *
+ * The card silently forces each ring size to be at least 128. If you
+ * act as though one of them is smaller (by setting the below
+ * #defines) you'll get bad bugs.
+ */
+
+#define RX_LE_SIZE	    	128
+#define RX_LE_BYTES		(RX_LE_SIZE*sizeof(struct sky2_rx_le))
+#define RX_RING_ALIGN		4096
+#define RX_PENDING		(RX_LE_SIZE/6 - 2)
+
+#define TX_RING_SIZE		128
+#define TX_PENDING		(TX_RING_SIZE - 1)
+#define TX_RING_ALIGN		4096
+#define MAX_SKB_TX_LE		4
+
+#define STATUS_RING_SIZE	512	/* 2 ports * (TX + RX) */
+#define STATUS_LE_BYTES		(STATUS_RING_SIZE*sizeof(struct sky2_status_le))
+#define STATUS_RING_ALIGN       4096
+#define PHY_RETRIES		1000
+
+#define SKY2_EEPROM_MAGIC	0x9955aabb
+
+
+#define RING_NEXT(x,s)	(((x)+1) & ((s)-1))
+
+static struct pci_device_id sky2_id_table[] = {
+	PCI_ROM(0x1148, 0x9000, "sk9sxx", "Syskonnect SK-9Sxx", 0),
+	PCI_ROM(0x1148, 0x9e00, "sk9exx", "Syskonnect SK-9Exx", 0),
+	PCI_ROM(0x1186, 0x4b00, "dge560t", "D-Link DGE-560T", 0),
+	PCI_ROM(0x1186, 0x4001, "dge550sx", "D-Link DGE-550SX", 0),
+	PCI_ROM(0x1186, 0x4b02, "dge560sx", "D-Link DGE-560SX", 0),
+	PCI_ROM(0x1186, 0x4b03, "dge550t", "D-Link DGE-550T", 0),
+	PCI_ROM(0x11ab, 0x4340, "m88e8021", "Marvell 88E8021", 0),
+	PCI_ROM(0x11ab, 0x4341, "m88e8022", "Marvell 88E8022", 0),
+	PCI_ROM(0x11ab, 0x4342, "m88e8061", "Marvell 88E8061", 0),
+	PCI_ROM(0x11ab, 0x4343, "m88e8062", "Marvell 88E8062", 0),
+	PCI_ROM(0x11ab, 0x4344, "m88e8021b", "Marvell 88E8021", 0),
+	PCI_ROM(0x11ab, 0x4345, "m88e8022b", "Marvell 88E8022", 0),
+	PCI_ROM(0x11ab, 0x4346, "m88e8061b", "Marvell 88E8061", 0),
+	PCI_ROM(0x11ab, 0x4347, "m88e8062b", "Marvell 88E8062", 0),
+	PCI_ROM(0x11ab, 0x4350, "m88e8035", "Marvell 88E8035", 0),
+	PCI_ROM(0x11ab, 0x4351, "m88e8036", "Marvell 88E8036", 0),
+	PCI_ROM(0x11ab, 0x4352, "m88e8038", "Marvell 88E8038", 0),
+	PCI_ROM(0x11ab, 0x4353, "m88e8039", "Marvell 88E8039", 0),
+	PCI_ROM(0x11ab, 0x4354, "m88e8040", "Marvell 88E8040", 0),
+	PCI_ROM(0x11ab, 0x4355, "m88e8040t", "Marvell 88E8040T", 0),
+	PCI_ROM(0x11ab, 0x4356, "m88ec033", "Marvel 88EC033", 0),
+	PCI_ROM(0x11ab, 0x4357, "m88e8042", "Marvell 88E8042", 0),
+	PCI_ROM(0x11ab, 0x435a, "m88e8048", "Marvell 88E8048", 0),
+	PCI_ROM(0x11ab, 0x4360, "m88e8052", "Marvell 88E8052", 0),
+	PCI_ROM(0x11ab, 0x4361, "m88e8050", "Marvell 88E8050", 0),
+	PCI_ROM(0x11ab, 0x4362, "m88e8053", "Marvell 88E8053", 0),
+	PCI_ROM(0x11ab, 0x4363, "m88e8055", "Marvell 88E8055", 0),
+	PCI_ROM(0x11ab, 0x4364, "m88e8056", "Marvell 88E8056", 0),
+	PCI_ROM(0x11ab, 0x4365, "m88e8070", "Marvell 88E8070", 0),
+	PCI_ROM(0x11ab, 0x4366, "m88ec036", "Marvell 88EC036", 0),
+	PCI_ROM(0x11ab, 0x4367, "m88ec032", "Marvell 88EC032", 0),
+	PCI_ROM(0x11ab, 0x4368, "m88ec034", "Marvell 88EC034", 0),
+	PCI_ROM(0x11ab, 0x4369, "m88ec042", "Marvell 88EC042", 0),
+	PCI_ROM(0x11ab, 0x436a, "m88e8058", "Marvell 88E8058", 0),
+	PCI_ROM(0x11ab, 0x436b, "m88e8071", "Marvell 88E8071", 0),
+	PCI_ROM(0x11ab, 0x436c, "m88e8072", "Marvell 88E8072", 0),
+	PCI_ROM(0x11ab, 0x436d, "m88e8055b", "Marvell 88E8055", 0),
+	PCI_ROM(0x11ab, 0x4370, "m88e8075", "Marvell 88E8075", 0),
+	PCI_ROM(0x11ab, 0x4380, "m88e8057", "Marvell 88E8057", 0)
+};
+
+/* Avoid conditionals by using array */
+static const unsigned txqaddr[] = { Q_XA1, Q_XA2 };
+static const unsigned rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
+
+static void sky2_set_multicast(struct net_device *dev);
+
+/* Access to PHY via serial interconnect */
+static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_DATA, val);
+	gma_write16(hw, port, GM_SMI_CTRL,
+		    GM_SMI_CT_PHY_AD(PHY_ADDR_MARV) | GM_SMI_CT_REG_AD(reg));
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL);
+		if (ctrl == 0xffff)
+			goto io_error;
+
+		if (!(ctrl & GM_SMI_CT_BUSY))
+			return 0;
+
+		udelay(10);
+	}
+
+	DBG(PFX "%s: phy write timeout\n", hw->dev[port]->name);
+	return -ETIMEDOUT;
+
+io_error:
+	DBG(PFX "%s: phy I/O error\n", hw->dev[port]->name);
+	return -EIO;
+}
+
+static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_CTRL, GM_SMI_CT_PHY_AD(PHY_ADDR_MARV)
+		    | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL);
+		if (ctrl == 0xffff)
+			goto io_error;
+
+		if (ctrl & GM_SMI_CT_RD_VAL) {
+			*val = gma_read16(hw, port, GM_SMI_DATA);
+			return 0;
+		}
+
+		udelay(10);
+	}
+
+	DBG(PFX "%s: phy read timeout\n", hw->dev[port]->name);
+	return -ETIMEDOUT;
+io_error:
+	DBG(PFX "%s: phy I/O error\n", hw->dev[port]->name);
+	return -EIO;
+}
+
+static inline u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
+{
+	u16 v = 0;
+	__gm_phy_read(hw, port, reg, &v);
+	return v;
+}
+
+
+static void sky2_power_on(struct sky2_hw *hw)
+{
+	/* switch power to VCC (WA for VAUX problem) */
+	sky2_write8(hw, B0_POWER_CTRL,
+		    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+
+	/* disable Core Clock Division, */
+	sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
+
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		/* enable bits are inverted */
+		sky2_write8(hw, B2_Y2_CLK_GATE,
+			    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+			    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+			    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+	else
+		sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+
+	if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+		u32 reg;
+
+		sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
+		reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+		/* set all bits to 0 except bits 15..12 and 8 */
+		reg &= P_ASPM_CONTROL_MSK;
+		sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+
+		reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+		/* set all bits to 0 except bits 28 & 27 */
+		reg &= P_CTL_TIM_VMAIN_AV_MSK;
+		sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+
+		sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+
+		/* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
+		reg = sky2_read32(hw, B2_GP_IO);
+		reg |= GLB_GPIO_STAT_RACE_DIS;
+		sky2_write32(hw, B2_GP_IO, reg);
+
+		sky2_read32(hw, B2_GP_IO);
+	}
+}
+
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+	else
+		/* enable bits are inverted */
+		sky2_write8(hw, B2_Y2_CLK_GATE,
+			    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+			    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+			    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+	/* switch power to VAUX */
+	if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+		sky2_write8(hw, B0_POWER_CTRL,
+			    (PC_VAUX_ENA | PC_VCC_ENA |
+			     PC_VAUX_ON | PC_VCC_OFF));
+}
+
+static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
+{
+	u16 reg;
+
+	/* disable all GMAC IRQ's */
+	sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
+
+	gma_write16(hw, port, GM_MC_ADDR_H1, 0);	/* clear MC hash */
+	gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+	gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+	gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+
+	reg = gma_read16(hw, port, GM_RX_CTRL);
+	reg |= GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA;
+	gma_write16(hw, port, GM_RX_CTRL, reg);
+}
+
+/* flow control to advertise bits */
+static const u16 copper_fc_adv[] = {
+	[FC_NONE]	= 0,
+	[FC_TX]		= PHY_M_AN_ASP,
+	[FC_RX]		= PHY_M_AN_PC,
+	[FC_BOTH]	= PHY_M_AN_PC | PHY_M_AN_ASP,
+};
+
+/* flow control to advertise bits when using 1000BaseX */
+static const u16 fiber_fc_adv[] = {
+	[FC_NONE] = PHY_M_P_NO_PAUSE_X,
+	[FC_TX]   = PHY_M_P_ASYM_MD_X,
+	[FC_RX]	  = PHY_M_P_SYM_MD_X,
+	[FC_BOTH] = PHY_M_P_BOTH_MD_X,
+};
+
+/* flow control to GMA disable bits */
+static const u16 gm_fc_disable[] = {
+	[FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS,
+	[FC_TX]	  = GM_GPCR_FC_RX_DIS,
+	[FC_RX]	  = GM_GPCR_FC_TX_DIS,
+	[FC_BOTH] = 0,
+};
+
+
+static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
+{
+	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
+	u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
+
+	if (sky2->autoneg == AUTONEG_ENABLE &&
+	    !(hw->flags & SKY2_HW_NEWER_PHY)) {
+		u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+
+		ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			   PHY_M_EC_MAC_S_MSK);
+		ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
+
+		/* on PHY 88E1040 Rev.D0 (and newer) downshift control changed */
+		if (hw->chip_id == CHIP_ID_YUKON_EC)
+			/* set downshift counter to 3x and enable downshift */
+			ectrl |= PHY_M_EC_DSC_2(2) | PHY_M_EC_DOWN_S_ENA;
+		else
+			/* set master & slave downshift counter to 1x */
+			ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+
+		gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+	}
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+	if (sky2_is_copper(hw)) {
+		if (!(hw->flags & SKY2_HW_GIGABIT)) {
+			/* enable automatic crossover */
+			ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
+
+			if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+			    hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+				u16 spec;
+
+				/* Enable Class A driver for FE+ A0 */
+				spec = gm_phy_read(hw, port, PHY_MARV_FE_SPEC_2);
+				spec |= PHY_M_FESC_SEL_CL_A;
+				gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec);
+			}
+		} else {
+			/* disable energy detect */
+			ctrl &= ~PHY_M_PC_EN_DET_MSK;
+
+			/* enable automatic crossover */
+			ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
+
+			/* downshift on PHY 88E1112 and 88E1149 is changed */
+			if (sky2->autoneg == AUTONEG_ENABLE
+			    && (hw->flags & SKY2_HW_NEWER_PHY)) {
+				/* set downshift counter to 3x and enable downshift */
+				ctrl &= ~PHY_M_PC_DSC_MSK;
+				ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
+			}
+		}
+	} else {
+		/* workaround for deviation #4.88 (CRC errors) */
+		/* disable Automatic Crossover */
+
+		ctrl &= ~PHY_M_PC_MDIX_MSK;
+	}
+
+	gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+	/* special setup for PHY 88E1112 Fiber */
+	if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) {
+		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+		/* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+		ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+		ctrl &= ~PHY_M_MAC_MD_MSK;
+		ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX);
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+		if (hw->pmd_type  == 'P') {
+			/* select page 1 to access Fiber registers */
+			gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 1);
+
+			/* for SFP-module set SIGDET polarity to low */
+			ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+			ctrl |= PHY_M_FIB_SIGD_POL;
+			gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+		}
+
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+	}
+
+	ctrl = PHY_CT_RESET;
+	ct1000 = 0;
+	adv = PHY_AN_CSMA;
+	reg = 0;
+
+	if (sky2->autoneg == AUTONEG_ENABLE) {
+		if (sky2_is_copper(hw)) {
+			if (sky2->advertising & ADVERTISED_1000baseT_Full)
+				ct1000 |= PHY_M_1000C_AFD;
+			if (sky2->advertising & ADVERTISED_1000baseT_Half)
+				ct1000 |= PHY_M_1000C_AHD;
+			if (sky2->advertising & ADVERTISED_100baseT_Full)
+				adv |= PHY_M_AN_100_FD;
+			if (sky2->advertising & ADVERTISED_100baseT_Half)
+				adv |= PHY_M_AN_100_HD;
+			if (sky2->advertising & ADVERTISED_10baseT_Full)
+				adv |= PHY_M_AN_10_FD;
+			if (sky2->advertising & ADVERTISED_10baseT_Half)
+				adv |= PHY_M_AN_10_HD;
+
+			adv |= copper_fc_adv[sky2->flow_mode];
+		} else {	/* special defines for FIBER (88E1040S only) */
+			if (sky2->advertising & ADVERTISED_1000baseT_Full)
+				adv |= PHY_M_AN_1000X_AFD;
+			if (sky2->advertising & ADVERTISED_1000baseT_Half)
+				adv |= PHY_M_AN_1000X_AHD;
+
+			adv |= fiber_fc_adv[sky2->flow_mode];
+		}
+
+		/* Restart Auto-negotiation */
+		ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	} else {
+		/* forced speed/duplex settings */
+		ct1000 = PHY_M_1000C_MSE;
+
+		/* Disable auto update for duplex flow control and speed */
+		reg |= GM_GPCR_AU_ALL_DIS;
+
+		switch (sky2->speed) {
+		case SPEED_1000:
+			ctrl |= PHY_CT_SP1000;
+			reg |= GM_GPCR_SPEED_1000;
+			break;
+		case SPEED_100:
+			ctrl |= PHY_CT_SP100;
+			reg |= GM_GPCR_SPEED_100;
+			break;
+		}
+
+		if (sky2->duplex == DUPLEX_FULL) {
+			reg |= GM_GPCR_DUP_FULL;
+			ctrl |= PHY_CT_DUP_MD;
+		} else if (sky2->speed < SPEED_1000)
+			sky2->flow_mode = FC_NONE;
+
+
+		reg |= gm_fc_disable[sky2->flow_mode];
+
+		/* Forward pause packets to GMAC? */
+		if (sky2->flow_mode & FC_RX)
+			sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+		else
+			sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+	}
+
+	gma_write16(hw, port, GM_GP_CTRL, reg);
+
+	if (hw->flags & SKY2_HW_GIGABIT)
+		gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+
+	gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	/* Setup Phy LED's */
+	ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
+	ledover = 0;
+
+	switch (hw->chip_id) {
+	case CHIP_ID_YUKON_FE:
+		/* on 88E3082 these bits are at 11..9 (shifted left) */
+		ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
+
+		ctrl = gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR);
+
+		/* delete ACT LED control bits */
+		ctrl &= ~PHY_M_FELP_LED1_MSK;
+		/* change ACT LED control to blink mode */
+		ctrl |= PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL);
+		gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
+		break;
+
+	case CHIP_ID_YUKON_FE_P:
+		/* Enable Link Partner Next Page */
+		ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+		ctrl |= PHY_M_PC_ENA_LIP_NP;
+
+		/* disable Energy Detect and enable scrambler */
+		ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB);
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+		/* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */
+		ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) |
+			PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) |
+			PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED);
+
+		gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
+		break;
+
+	case CHIP_ID_YUKON_XL:
+		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+		/* select page 3 to access LED control register */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
+
+		/* set LED Function Control register */
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+			     (PHY_M_LEDC_LOS_CTRL(1) |	/* LINK/ACT */
+			      PHY_M_LEDC_INIT_CTRL(7) |	/* 10 Mbps */
+			      PHY_M_LEDC_STA1_CTRL(7) |	/* 100 Mbps */
+			      PHY_M_LEDC_STA0_CTRL(7)));	/* 1000 Mbps */
+
+		/* set Polarity Control register */
+		gm_phy_write(hw, port, PHY_MARV_PHY_STAT,
+			     (PHY_M_POLC_LS1_P_MIX(4) |
+			      PHY_M_POLC_IS0_P_MIX(4) |
+			      PHY_M_POLC_LOS_CTRL(2) |
+			      PHY_M_POLC_INIT_CTRL(2) |
+			      PHY_M_POLC_STA1_CTRL(2) |
+			      PHY_M_POLC_STA0_CTRL(2)));
+
+		/* restore page register */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+		break;
+
+	case CHIP_ID_YUKON_EC_U:
+	case CHIP_ID_YUKON_EX:
+	case CHIP_ID_YUKON_SUPR:
+		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+		/* select page 3 to access LED control register */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
+
+		/* set LED Function Control register */
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+			     (PHY_M_LEDC_LOS_CTRL(1) |	/* LINK/ACT */
+			      PHY_M_LEDC_INIT_CTRL(8) |	/* 10 Mbps */
+			      PHY_M_LEDC_STA1_CTRL(7) |	/* 100 Mbps */
+			      PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */
+
+		/* set Blink Rate in LED Timer Control Register */
+		gm_phy_write(hw, port, PHY_MARV_INT_MASK,
+			     ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS));
+		/* restore page register */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+		break;
+
+	default:
+		/* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
+		ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+
+		/* turn off the Rx LED (LED_RX) */
+		ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
+	}
+
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_UL_2) {
+		/* apply fixes in PHY AFE */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
+
+		/* increase differential signal amplitude in 10BASE-T */
+		gm_phy_write(hw, port, 0x18, 0xaa99);
+		gm_phy_write(hw, port, 0x17, 0x2011);
+
+		if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+			/* fix for IEEE A/B Symmetry failure in 1000BASE-T */
+			gm_phy_write(hw, port, 0x18, 0xa204);
+			gm_phy_write(hw, port, 0x17, 0x2002);
+		}
+
+		/* set page register to 0 */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+	} else if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+		   hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+		/* apply workaround for integrated resistors calibration */
+		gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17);
+		gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60);
+	} else if (hw->chip_id != CHIP_ID_YUKON_EX &&
+		   hw->chip_id < CHIP_ID_YUKON_SUPR) {
+		/* no effect on Yukon-XL */
+		gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+
+		if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
+			/* turn on 100 Mbps LED (LED_LINK100) */
+			ledover |= PHY_M_LED_MO_100(MO_LED_ON);
+		}
+
+		if (ledover)
+			gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+
+	}
+
+	/* Enable phy interrupt on auto-negotiation complete (or link up) */
+	if (sky2->autoneg == AUTONEG_ENABLE)
+		gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+	else
+		gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+}
+
+static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
+
+static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
+{
+	u32 reg1;
+
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+	reg1 &= ~phy_power[port];
+
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		reg1 |= coma_mode[port];
+
+	sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	sky2_pci_read32(hw, PCI_DEV_REG1);
+
+	if (hw->chip_id == CHIP_ID_YUKON_FE)
+		gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_ANE);
+	else if (hw->flags & SKY2_HW_ADV_POWER_CTL)
+		sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+}
+
+static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
+{
+	u32 reg1;
+	u16 ctrl;
+
+	/* release GPHY Control reset */
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+
+	/* release GMAC reset */
+	sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+	if (hw->flags & SKY2_HW_NEWER_PHY) {
+		/* select page 2 to access MAC control register */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+
+		ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+		/* allow GMII Power Down */
+		ctrl &= ~PHY_M_MAC_GMIF_PUP;
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+		/* set page register back to 0 */
+		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+	}
+
+	/* setup General Purpose Control Register */
+	gma_write16(hw, port, GM_GP_CTRL,
+		    GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS);
+
+	if (hw->chip_id != CHIP_ID_YUKON_EC) {
+		if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+			/* select page 2 to access MAC control register */
+			gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+
+			ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+			/* enable Power Down */
+			ctrl |= PHY_M_PC_POW_D_ENA;
+			gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+			/* set page register back to 0 */
+			gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+		}
+
+		/* set IEEE compatible Power Down Mode (dev. #4.99) */
+		gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN);
+	}
+
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+	reg1 |= phy_power[port];		/* set PHY to PowerDown/COMA Mode */
+	sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+}
+
+static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
+{
+	if ( (hw->chip_id == CHIP_ID_YUKON_EX &&
+	      hw->chip_rev != CHIP_REV_YU_EX_A0) ||
+	     hw->chip_id == CHIP_ID_YUKON_FE_P ||
+	     hw->chip_id == CHIP_ID_YUKON_SUPR) {
+		/* disable jumbo frames on devices that support them */
+		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+			     TX_JUMBO_DIS | TX_STFW_ENA);
+	} else {
+		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
+	}
+}
+
+static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
+{
+	u16 reg;
+	u32 rx_reg;
+	int i;
+	const u8 *addr = hw->dev[port]->ll_addr;
+
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+
+	sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && port == 1) {
+		/* WA DEV_472 -- looks like crossed wires on port 2 */
+		/* clear GMAC 1 Control reset */
+		sky2_write8(hw, SK_REG(0, GMAC_CTRL), GMC_RST_CLR);
+		do {
+			sky2_write8(hw, SK_REG(1, GMAC_CTRL), GMC_RST_SET);
+			sky2_write8(hw, SK_REG(1, GMAC_CTRL), GMC_RST_CLR);
+		} while (gm_phy_read(hw, 1, PHY_MARV_ID0) != PHY_MARV_ID0_VAL ||
+			 gm_phy_read(hw, 1, PHY_MARV_ID1) != PHY_MARV_ID1_Y2 ||
+			 gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
+	}
+
+	sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+	/* Enable Transmit FIFO Underrun */
+	sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
+
+	sky2_phy_power_up(hw, port);
+	sky2_phy_init(hw, port);
+
+	/* MIB clear */
+	reg = gma_read16(hw, port, GM_PHY_ADDR);
+	gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+
+	for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4)
+		gma_read16(hw, port, i);
+	gma_write16(hw, port, GM_PHY_ADDR, reg);
+
+	/* transmit control */
+	gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+
+	/* receive control reg: unicast + multicast + no FCS  */
+	gma_write16(hw, port, GM_RX_CTRL,
+		    GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
+
+	/* transmit flow control */
+	gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* transmit parameter */
+	gma_write16(hw, port, GM_TX_PARAM,
+		    TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
+		    TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
+		    TX_IPG_JAM_DATA(TX_IPG_JAM_DEF) |
+		    TX_BACK_OFF_LIM(TX_BOF_LIM_DEF));
+
+	/* serial mode register */
+	reg = DATA_BLIND_VAL(DATA_BLIND_DEF) |
+		GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
+
+	gma_write16(hw, port, GM_SERIAL_MODE, reg);
+
+	/* virtual address for data */
+	gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+
+	/* physical address: used for pause frames */
+	gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+
+	/* ignore counter overflows */
+	gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+	gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+	gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+
+	/* Configure Rx MAC FIFO */
+	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+	rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+	if (hw->chip_id == CHIP_ID_YUKON_EX ||
+	    hw->chip_id == CHIP_ID_YUKON_FE_P)
+		rx_reg |= GMF_RX_OVER_ON;
+
+	sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
+
+	if (hw->chip_id == CHIP_ID_YUKON_XL) {
+		/* Hardware errata - clear flush mask */
+		sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), 0);
+	} else {
+		/* Flush Rx MAC FIFO on any flow control or error */
+		sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
+	}
+
+	/* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug  */
+	reg = RX_GMF_FL_THR_DEF + 1;
+	/* Another magic mystery workaround from sk98lin */
+	if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	    hw->chip_rev == CHIP_REV_YU_FE2_A0)
+		reg = 0x178;
+	sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg);
+
+	/* Configure Tx MAC FIFO */
+	sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+	sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+
+	/* On chips without ram buffer, pause is controled by MAC level */
+	if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
+		sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
+		sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
+
+		sky2_set_tx_stfwd(hw, port);
+	}
+
+	if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	    hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+		/* disable dynamic watermark */
+		reg = sky2_read16(hw, SK_REG(port, TX_GMF_EA));
+		reg &= ~TX_DYN_WM_ENA;
+		sky2_write16(hw, SK_REG(port, TX_GMF_EA), reg);
+	}
+}
+
+/* Assign Ram Buffer allocation to queue */
+static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space)
+{
+	u32 end;
+
+	/* convert from K bytes to qwords used for hw register */
+	start *= 1024/8;
+	space *= 1024/8;
+	end = start + space - 1;
+
+	sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR);
+	sky2_write32(hw, RB_ADDR(q, RB_START), start);
+	sky2_write32(hw, RB_ADDR(q, RB_END), end);
+	sky2_write32(hw, RB_ADDR(q, RB_WP), start);
+	sky2_write32(hw, RB_ADDR(q, RB_RP), start);
+
+	if (q == Q_R1 || q == Q_R2) {
+		u32 tp = space - space/4;
+
+		/* On receive queue's set the thresholds
+		 * give receiver priority when > 3/4 full
+		 * send pause when down to 2K
+		 */
+		sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp);
+		sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2);
+
+		tp = space - 2048/8;
+		sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp);
+		sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4);
+	} else {
+		/* Enable store & forward on Tx queue's because
+		 * Tx FIFO is only 1K on Yukon
+		 */
+		sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD);
+	}
+
+	sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD);
+	sky2_read8(hw, RB_ADDR(q, RB_CTRL));
+}
+
+/* Setup Bus Memory Interface */
+static void sky2_qset(struct sky2_hw *hw, u16 q)
+{
+	sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_RESET);
+	sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_OPER_INIT);
+	sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_FIFO_OP_ON);
+	sky2_write32(hw, Q_ADDR(q, Q_WM),  BMU_WM_DEFAULT);
+}
+
+/* Setup prefetch unit registers. This is the interface between
+ * hardware and driver list elements
+ */
+static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
+				      u64 addr, u32 last)
+{
+	sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+	sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_CLR);
+	sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), addr >> 32);
+	sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), (u32) addr);
+	sky2_write16(hw, Y2_QADDR(qaddr, PREF_UNIT_LAST_IDX), last);
+	sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_OP_ON);
+
+	sky2_read32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL));
+}
+
+static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2)
+{
+	struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod;
+
+	sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE);
+	le->ctrl = 0;
+	return le;
+}
+
+static void tx_init(struct sky2_port *sky2)
+{
+	struct sky2_tx_le *le;
+
+	sky2->tx_prod = sky2->tx_cons = 0;
+
+	le = get_tx_le(sky2);
+	le->addr = 0;
+	le->opcode = OP_ADDR64 | HW_OWNER;
+}
+
+static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
+					    struct sky2_tx_le *le)
+{
+	return sky2->tx_ring + (le - sky2->tx_le);
+}
+
+/* Update chip's next pointer */
+static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
+{
+	/* Make sure write' to descriptors are complete before we tell hardware */
+	wmb();
+	sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx);
+	DBGIO(PFX "queue %#x idx <- %d\n", q, idx);
+}
+
+
+static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
+{
+	struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put;
+
+	sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE);
+	le->ctrl = 0;
+	return le;
+}
+
+/* Build description to hardware for one receive segment */
+static void sky2_rx_add(struct sky2_port *sky2,  u8 op,
+			u32 map, unsigned len)
+{
+	struct sky2_rx_le *le;
+
+	le = sky2_next_rx(sky2);
+	le->addr = cpu_to_le32(map);
+	le->length = cpu_to_le16(len);
+	le->opcode = op | HW_OWNER;
+}
+
+/* Build description to hardware for one possibly fragmented skb */
+static void sky2_rx_submit(struct sky2_port *sky2,
+			   const struct rx_ring_info *re)
+{
+	sky2_rx_add(sky2, OP_PACKET, re->data_addr, sky2->rx_data_size);
+}
+
+
+static void sky2_rx_map_iob(struct pci_device *pdev __unused,
+			    struct rx_ring_info *re,
+			    unsigned size __unused)
+{
+	struct io_buffer *iob = re->iob;
+	re->data_addr = virt_to_bus(iob->data);
+}
+
+/* Diable the checksum offloading.
+ */
+static void rx_set_checksum(struct sky2_port *sky2)
+{
+	struct sky2_rx_le *le = sky2_next_rx(sky2);
+
+	le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+	le->ctrl = 0;
+	le->opcode = OP_TCPSTART | HW_OWNER;
+
+	sky2_write32(sky2->hw,
+		     Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+		     BMU_DIS_RX_CHKSUM);
+}
+
+/*
+ * The RX Stop command will not work for Yukon-2 if the BMU does not
+ * reach the end of packet and since we can't make sure that we have
+ * incoming data, we must reset the BMU while it is not doing a DMA
+ * transfer. Since it is possible that the RX path is still active,
+ * the RX RAM buffer will be stopped first, so any possible incoming
+ * data will not trigger a DMA. After the RAM buffer is stopped, the
+ * BMU is polled until any DMA in progress is ended and only then it
+ * will be reset.
+ */
+static void sky2_rx_stop(struct sky2_port *sky2)
+{
+	struct sky2_hw *hw = sky2->hw;
+	unsigned rxq = rxqaddr[sky2->port];
+	int i;
+
+	/* disable the RAM Buffer receive queue */
+	sky2_write8(hw, RB_ADDR(rxq, RB_CTRL), RB_DIS_OP_MD);
+
+	for (i = 0; i < 0xffff; i++)
+		if (sky2_read8(hw, RB_ADDR(rxq, Q_RSL))
+		    == sky2_read8(hw, RB_ADDR(rxq, Q_RL)))
+			goto stopped;
+
+	DBG(PFX "%s: receiver stop failed\n", sky2->netdev->name);
+stopped:
+	sky2_write32(hw, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST);
+
+	/* reset the Rx prefetch unit */
+	sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+	wmb();
+}
+
+/* Clean out receive buffer area, assumes receiver hardware stopped */
+static void sky2_rx_clean(struct sky2_port *sky2)
+{
+	unsigned i;
+
+	memset(sky2->rx_le, 0, RX_LE_BYTES);
+	for (i = 0; i < RX_PENDING; i++) {
+		struct rx_ring_info *re = sky2->rx_ring + i;
+
+		if (re->iob) {
+			free_iob(re->iob);
+			re->iob = NULL;
+		}
+	}
+}
+
+/*
+ * Allocate an iob for receiving.
+ */
+static struct io_buffer *sky2_rx_alloc(struct sky2_port *sky2)
+{
+	struct io_buffer *iob;
+
+	iob = alloc_iob(sky2->rx_data_size + ETH_DATA_ALIGN);
+	if (!iob)
+		return NULL;
+
+	/*
+	 * Cards with a RAM buffer hang in the rx FIFO if the
+	 * receive buffer isn't aligned to (Linux module comments say
+	 * 64 bytes, Linux module code says 8 bytes). Since io_buffers
+	 * are always 2kb-aligned under iPXE, just leave it be
+	 * without ETH_DATA_ALIGN in those cases.
+	 *
+	 * XXX This causes unaligned access to the IP header,
+	 * which is undesirable, but it's less undesirable than the
+	 * card hanging.
+	 */
+	if (!(sky2->hw->flags & SKY2_HW_RAM_BUFFER)) {
+		iob_reserve(iob, ETH_DATA_ALIGN);
+	}
+
+	return iob;
+}
+
+static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
+{
+	sky2_put_idx(sky2->hw, rxq, sky2->rx_put);
+}
+
+/*
+ * Allocate and setup receiver buffer pool.
+ * Normal case this ends up creating one list element for skb
+ * in the receive ring. One element is used for checksum
+ * enable/disable, and one extra to avoid wrap.
+ */
+static int sky2_rx_start(struct sky2_port *sky2)
+{
+	struct sky2_hw *hw = sky2->hw;
+	struct rx_ring_info *re;
+	unsigned rxq = rxqaddr[sky2->port];
+	unsigned i, size, thresh;
+
+	sky2->rx_put = sky2->rx_next = 0;
+	sky2_qset(hw, rxq);
+
+	/* On PCI express lowering the watermark gives better performance */
+	if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP))
+		sky2_write32(hw, Q_ADDR(rxq, Q_WM), BMU_WM_PEX);
+
+	/* These chips have no ram buffer?
+	 * MAC Rx RAM Read is controlled by hardware */
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
+	    (hw->chip_rev == CHIP_REV_YU_EC_U_A1
+	     || hw->chip_rev == CHIP_REV_YU_EC_U_B0))
+		sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS);
+
+	sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
+
+	if (!(hw->flags & SKY2_HW_NEW_LE))
+		rx_set_checksum(sky2);
+
+	/* Space needed for frame data + headers rounded up */
+	size = (ETH_FRAME_LEN + 8) & ~7;
+
+	/* Stopping point for hardware truncation */
+	thresh = (size - 8) / sizeof(u32);
+
+	sky2->rx_data_size = size;
+
+	/* Fill Rx ring */
+	for (i = 0; i < RX_PENDING; i++) {
+		re = sky2->rx_ring + i;
+
+		re->iob = sky2_rx_alloc(sky2);
+		if (!re->iob)
+			goto nomem;
+
+		sky2_rx_map_iob(hw->pdev, re, sky2->rx_data_size);
+		sky2_rx_submit(sky2, re);
+	}
+
+	/*
+	 * The receiver hangs if it receives frames larger than the
+	 * packet buffer. As a workaround, truncate oversize frames, but
+	 * the register is limited to 9 bits, so if you do frames > 2052
+	 * you better get the MTU right!
+	 */
+	if (thresh > 0x1ff)
+		sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
+	else {
+		sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), thresh);
+		sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+	}
+
+	/* Tell chip about available buffers */
+	sky2_rx_update(sky2, rxq);
+	return 0;
+nomem:
+	sky2_rx_clean(sky2);
+	return -ENOMEM;
+}
+
+/* Free the le and ring buffers */
+static void sky2_free_rings(struct sky2_port *sky2)
+{
+	free_dma(sky2->rx_le, RX_LE_BYTES);
+	free(sky2->rx_ring);
+
+	free_dma(sky2->tx_le, TX_RING_SIZE * sizeof(struct sky2_tx_le));
+	free(sky2->tx_ring);
+
+	sky2->tx_le = NULL;
+	sky2->rx_le = NULL;
+
+	sky2->rx_ring = NULL;
+	sky2->tx_ring = NULL;
+}
+
+/* Bring up network interface. */
+static int sky2_up(struct net_device *dev)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u32 imask, ramsize;
+	int err = -ENOMEM;
+
+	netdev_link_down(dev);
+
+	/* must be power of 2 */
+	sky2->tx_le = malloc_dma(TX_RING_SIZE * sizeof(struct sky2_tx_le), TX_RING_ALIGN);
+	sky2->tx_le_map = virt_to_bus(sky2->tx_le);
+	if (!sky2->tx_le)
+		goto err_out;
+	memset(sky2->tx_le, 0, TX_RING_SIZE * sizeof(struct sky2_tx_le));
+
+	sky2->tx_ring = zalloc(TX_RING_SIZE * sizeof(struct tx_ring_info));
+	if (!sky2->tx_ring)
+		goto err_out;
+
+	tx_init(sky2);
+
+	sky2->rx_le = malloc_dma(RX_LE_BYTES, RX_RING_ALIGN);
+	sky2->rx_le_map = virt_to_bus(sky2->rx_le);
+	if (!sky2->rx_le)
+		goto err_out;
+	memset(sky2->rx_le, 0, RX_LE_BYTES);
+
+	sky2->rx_ring = zalloc(RX_PENDING * sizeof(struct rx_ring_info));
+	if (!sky2->rx_ring)
+		goto err_out;
+
+	sky2_mac_init(hw, port);
+
+	/* Register is number of 4K blocks on internal RAM buffer. */
+	ramsize = sky2_read8(hw, B2_E_0) * 4;
+	if (ramsize > 0) {
+		u32 rxspace;
+
+		hw->flags |= SKY2_HW_RAM_BUFFER;
+		DBG2(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
+		if (ramsize < 16)
+			rxspace = ramsize / 2;
+		else
+			rxspace = 8 + (2*(ramsize - 16))/3;
+
+		sky2_ramset(hw, rxqaddr[port], 0, rxspace);
+		sky2_ramset(hw, txqaddr[port], rxspace, ramsize - rxspace);
+
+		/* Make sure SyncQ is disabled */
+		sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL),
+			    RB_RST_SET);
+	}
+
+	sky2_qset(hw, txqaddr[port]);
+
+	/* This is copied from sk98lin 10.0.5.3; no one tells me about erratta's */
+	if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev == CHIP_REV_YU_EX_B0)
+		sky2_write32(hw, Q_ADDR(txqaddr[port], Q_TEST), F_TX_CHK_AUTO_OFF);
+
+	/* Set almost empty threshold */
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U
+	    && hw->chip_rev == CHIP_REV_YU_EC_U_A0)
+		sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV);
+
+	sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
+			   TX_RING_SIZE - 1);
+
+	err = sky2_rx_start(sky2);
+	if (err)
+		goto err_out;
+
+	/* Enable interrupts from phy/mac for port */
+	imask = sky2_read32(hw, B0_IMSK);
+	imask |= portirq_msk[port];
+	sky2_write32(hw, B0_IMSK, imask);
+
+	DBGIO(PFX "%s: le bases: st %p [%x], rx %p [%x], tx %p [%x]\n",
+	      dev->name, hw->st_le, hw->st_dma, sky2->rx_le, sky2->rx_le_map,
+	      sky2->tx_le, sky2->tx_le_map);
+
+	sky2_set_multicast(dev);
+	return 0;
+
+err_out:
+	sky2_free_rings(sky2);
+	return err;
+}
+
+/* Modular subtraction in ring */
+static inline int tx_dist(unsigned tail, unsigned head)
+{
+	return (head - tail) & (TX_RING_SIZE - 1);
+}
+
+/* Number of list elements available for next tx */
+static inline int tx_avail(const struct sky2_port *sky2)
+{
+	return TX_PENDING - tx_dist(sky2->tx_cons, sky2->tx_prod);
+}
+
+
+/*
+ * Put one packet in ring for transmit.
+ * A single packet can generate multiple list elements, and
+ * the number of ring elements will probably be less than the number
+ * of list elements used.
+ */
+static int sky2_xmit_frame(struct net_device *dev, struct io_buffer *iob)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	struct sky2_tx_le *le = NULL;
+	struct tx_ring_info *re;
+	unsigned len;
+	u32 mapping;
+	u8 ctrl;
+
+	if (tx_avail(sky2) < 1)
+		return -EBUSY;
+
+	len = iob_len(iob);
+	mapping = virt_to_bus(iob->data);
+
+	DBGIO(PFX "%s: tx queued, slot %d, len %d\n", dev->name,
+	      sky2->tx_prod, len);
+
+	ctrl = 0;
+
+	le = get_tx_le(sky2);
+	le->addr = cpu_to_le32((u32) mapping);
+	le->length = cpu_to_le16(len);
+	le->ctrl = ctrl;
+	le->opcode = (OP_PACKET | HW_OWNER);
+
+	re = tx_le_re(sky2, le);
+	re->iob = iob;
+
+	le->ctrl |= EOP;
+
+	sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod);
+
+	return 0;
+}
+
+/*
+ * Free ring elements from starting at tx_cons until "done"
+ *
+ * NB: the hardware will tell us about partial completion of multi-part
+ *     buffers so make sure not to free iob too early.
+ */
+static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
+{
+	struct net_device *dev = sky2->netdev;
+	unsigned idx;
+
+	assert(done < TX_RING_SIZE);
+
+	for (idx = sky2->tx_cons; idx != done;
+	     idx = RING_NEXT(idx, TX_RING_SIZE)) {
+		struct sky2_tx_le *le = sky2->tx_le + idx;
+		struct tx_ring_info *re = sky2->tx_ring + idx;
+
+		if (le->ctrl & EOP) {
+			DBGIO(PFX "%s: tx done %d\n", dev->name, idx);
+			netdev_tx_complete(dev, re->iob);
+		}
+	}
+
+	sky2->tx_cons = idx;
+	mb();
+}
+
+/* Cleanup all untransmitted buffers, assume transmitter not running */
+static void sky2_tx_clean(struct net_device *dev)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+
+	sky2_tx_complete(sky2, sky2->tx_prod);
+}
+
+/* Network shutdown */
+static void sky2_down(struct net_device *dev)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u16 ctrl;
+	u32 imask;
+
+	/* Never really got started! */
+	if (!sky2->tx_le)
+		return;
+
+	DBG2(PFX "%s: disabling interface\n", dev->name);
+
+	/* Disable port IRQ */
+	imask = sky2_read32(hw, B0_IMSK);
+	imask &= ~portirq_msk[port];
+	sky2_write32(hw, B0_IMSK, imask);
+
+	sky2_gmac_reset(hw, port);
+
+	/* Stop transmitter */
+	sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_STOP);
+	sky2_read32(hw, Q_ADDR(txqaddr[port], Q_CSR));
+
+	sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
+		     RB_RST_SET | RB_DIS_OP_MD);
+
+	ctrl = gma_read16(hw, port, GM_GP_CTRL);
+	ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA);
+	gma_write16(hw, port, GM_GP_CTRL, ctrl);
+
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+
+	/* Workaround shared GMAC reset */
+	if (!(hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0
+	      && port == 0 && hw->dev[1]))
+		sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
+
+	/* Disable Force Sync bit and Enable Alloc bit */
+	sky2_write8(hw, SK_REG(port, TXA_CTRL),
+		    TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+	/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+	sky2_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+	sky2_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
+
+	/* Reset the PCI FIFO of the async Tx queue */
+	sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR),
+		     BMU_RST_SET | BMU_FIFO_RST);
+
+	/* Reset the Tx prefetch units */
+	sky2_write32(hw, Y2_QADDR(txqaddr[port], PREF_UNIT_CTRL),
+		     PREF_UNIT_RST_SET);
+
+	sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET);
+
+	sky2_rx_stop(sky2);
+
+	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+	sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+
+	sky2_phy_power_down(hw, port);
+
+	/* turn off LED's */
+	sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
+
+	sky2_tx_clean(dev);
+	sky2_rx_clean(sky2);
+
+	sky2_free_rings(sky2);
+
+	return;
+}
+
+static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
+{
+	if (hw->flags & SKY2_HW_FIBRE_PHY)
+		return SPEED_1000;
+
+	if (!(hw->flags & SKY2_HW_GIGABIT)) {
+		if (aux & PHY_M_PS_SPEED_100)
+			return SPEED_100;
+		else
+			return SPEED_10;
+	}
+
+	switch (aux & PHY_M_PS_SPEED_MSK) {
+	case PHY_M_PS_SPEED_1000:
+		return SPEED_1000;
+	case PHY_M_PS_SPEED_100:
+		return SPEED_100;
+	default:
+		return SPEED_10;
+	}
+}
+
+static void sky2_link_up(struct sky2_port *sky2)
+{
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u16 reg;
+	static const char *fc_name[] = {
+		[FC_NONE]	= "none",
+		[FC_TX]		= "tx",
+		[FC_RX]		= "rx",
+		[FC_BOTH]	= "both",
+	};
+
+	/* enable Rx/Tx */
+	reg = gma_read16(hw, port, GM_GP_CTRL);
+	reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
+	gma_write16(hw, port, GM_GP_CTRL, reg);
+
+	gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+
+	netdev_link_up(sky2->netdev);
+
+	/* Turn on link LED */
+	sky2_write8(hw, SK_REG(port, LNK_LED_REG),
+		    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
+
+	DBG(PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
+	    sky2->netdev->name, sky2->speed,
+	    sky2->duplex == DUPLEX_FULL ? "full" : "half",
+	    fc_name[sky2->flow_status]);
+}
+
+static void sky2_link_down(struct sky2_port *sky2)
+{
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u16 reg;
+
+	gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
+
+	reg = gma_read16(hw, port, GM_GP_CTRL);
+	reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+	gma_write16(hw, port, GM_GP_CTRL, reg);
+
+	netdev_link_down(sky2->netdev);
+
+	/* Turn on link LED */
+	sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
+
+	DBG(PFX "%s: Link is down.\n", sky2->netdev->name);
+
+	sky2_phy_init(hw, port);
+}
+
+static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
+{
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u16 advert, lpa;
+
+	advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
+	lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP);
+	if (lpa & PHY_M_AN_RF) {
+		DBG(PFX "%s: remote fault\n", sky2->netdev->name);
+		return -1;
+	}
+
+	if (!(aux & PHY_M_PS_SPDUP_RES)) {
+		DBG(PFX "%s: speed/duplex mismatch\n", sky2->netdev->name);
+		return -1;
+	}
+
+	sky2->speed = sky2_phy_speed(hw, aux);
+	sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+
+	/* Since the pause result bits seem to in different positions on
+	 * different chips. look at registers.
+	 */
+
+	sky2->flow_status = FC_NONE;
+	if (advert & ADVERTISE_PAUSE_CAP) {
+		if (lpa & LPA_PAUSE_CAP)
+			sky2->flow_status = FC_BOTH;
+		else if (advert & ADVERTISE_PAUSE_ASYM)
+			sky2->flow_status = FC_RX;
+	} else if (advert & ADVERTISE_PAUSE_ASYM) {
+		if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM))
+			sky2->flow_status = FC_TX;
+	}
+
+	if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
+	    && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
+		sky2->flow_status = FC_NONE;
+
+	if (sky2->flow_status & FC_TX)
+		sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+	else
+		sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+
+	return 0;
+}
+
+/* Interrupt from PHY */
+static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
+{
+	struct net_device *dev = hw->dev[port];
+	struct sky2_port *sky2 = netdev_priv(dev);
+	u16 istatus, phystat;
+
+	istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+	phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+	DBGIO(PFX "%s: phy interrupt status 0x%x 0x%x\n",
+	      sky2->netdev->name, istatus, phystat);
+
+	if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) {
+		if (sky2_autoneg_done(sky2, phystat) == 0)
+			sky2_link_up(sky2);
+		return;
+	}
+
+	if (istatus & PHY_M_IS_LSP_CHANGE)
+		sky2->speed = sky2_phy_speed(hw, phystat);
+
+	if (istatus & PHY_M_IS_DUP_CHANGE)
+		sky2->duplex =
+		    (phystat & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+
+	if (istatus & PHY_M_IS_LST_CHANGE) {
+		if (phystat & PHY_M_PS_LINK_UP)
+			sky2_link_up(sky2);
+		else
+			sky2_link_down(sky2);
+	}
+}
+
+/* Normal packet - take iob from ring element and put in a new one  */
+static struct io_buffer *receive_new(struct sky2_port *sky2,
+				     struct rx_ring_info *re,
+				     unsigned int length)
+{
+	struct io_buffer *iob, *niob;
+	unsigned hdr_space = sky2->rx_data_size;
+
+	/* Don't be tricky about reusing pages (yet) */
+	niob = sky2_rx_alloc(sky2);
+	if (!niob)
+		return NULL;
+
+	iob = re->iob;
+
+	re->iob = niob;
+	sky2_rx_map_iob(sky2->hw->pdev, re, hdr_space);
+
+	iob_put(iob, length);
+	return iob;
+}
+
+/*
+ * Receive one packet.
+ * For larger packets, get new buffer.
+ */
+static struct io_buffer *sky2_receive(struct net_device *dev,
+				      u16 length, u32 status)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
+	struct io_buffer *iob = NULL;
+	u16 count = (status & GMR_FS_LEN) >> 16;
+
+	DBGIO(PFX "%s: rx slot %d status 0x%x len %d\n",
+	      dev->name, sky2->rx_next, status, length);
+
+	sky2->rx_next = (sky2->rx_next + 1) % RX_PENDING;
+
+	/* This chip has hardware problems that generates bogus status.
+	 * So do only marginal checking and expect higher level protocols
+	 * to handle crap frames.
+	 */
+	if (sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	    sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0 &&
+	    length == count)
+		goto okay;
+
+	if (status & GMR_FS_ANY_ERR)
+		goto error;
+
+	if (!(status & GMR_FS_RX_OK))
+		goto resubmit;
+
+	/* if length reported by DMA does not match PHY, packet was truncated */
+	if (length != count)
+		goto len_error;
+
+okay:
+	iob = receive_new(sky2, re, length);
+resubmit:
+	sky2_rx_submit(sky2, re);
+
+	return iob;
+
+len_error:
+	/* Truncation of overlength packets
+	   causes PHY length to not match MAC length */
+	DBG2(PFX "%s: rx length error: status %#x length %d\n",
+	     dev->name, status, length);
+
+	/* Pass NULL as iob because we want to keep our iob in the
+	   ring for the next packet. */
+	netdev_rx_err(dev, NULL, -EINVAL);
+	goto resubmit;
+
+error:
+	if (status & GMR_FS_RX_FF_OV) {
+		DBG2(PFX "%s: FIFO overflow error\n", dev->name);
+		netdev_rx_err(dev, NULL, -EBUSY);
+		goto resubmit;
+	}
+
+	DBG2(PFX "%s: rx error, status 0x%x length %d\n",
+	     dev->name, status, length);
+	netdev_rx_err(dev, NULL, -EIO);
+
+	goto resubmit;
+}
+
+/* Transmit complete */
+static inline void sky2_tx_done(struct net_device *dev, u16 last)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+
+	sky2_tx_complete(sky2, last);
+}
+
+/* Process status response ring */
+static void sky2_status_intr(struct sky2_hw *hw, u16 idx)
+{
+	unsigned rx[2] = { 0, 0 };
+
+	rmb();
+	do {
+		struct sky2_status_le *le  = hw->st_le + hw->st_idx;
+		unsigned port;
+		struct net_device *dev;
+		struct io_buffer *iob;
+		u32 status;
+		u16 length;
+		u8 opcode = le->opcode;
+
+		if (!(opcode & HW_OWNER))
+			break;
+
+		port = le->css & CSS_LINK_BIT;
+		dev = hw->dev[port];
+		length = le16_to_cpu(le->length);
+		status = le32_to_cpu(le->status);
+
+		hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
+
+		le->opcode = 0;
+		switch (opcode & ~HW_OWNER) {
+		case OP_RXSTAT:
+			++rx[port];
+			iob = sky2_receive(dev, length, status);
+			if (!iob) {
+				netdev_rx_err(dev, NULL, -ENOMEM);
+				break;
+			}
+
+			netdev_rx(dev, iob);
+			break;
+
+		case OP_RXCHKS:
+			DBG2(PFX "status OP_RXCHKS but checksum offloading disabled\n");
+			break;
+
+		case OP_TXINDEXLE:
+			/* TX index reports status for both ports */
+			assert(TX_RING_SIZE <= 0x1000);
+			sky2_tx_done(hw->dev[0], status & 0xfff);
+			if (hw->dev[1])
+				sky2_tx_done(hw->dev[1],
+				     ((status >> 24) & 0xff)
+					     | (u16)(length & 0xf) << 8);
+			break;
+
+		default:
+			DBG(PFX "unknown status opcode 0x%x\n", opcode);
+		}
+	} while (hw->st_idx != idx);
+
+	/* Fully processed status ring so clear irq */
+	sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+
+	if (rx[0])
+		sky2_rx_update(netdev_priv(hw->dev[0]), Q_R1);
+
+	if (rx[1])
+		sky2_rx_update(netdev_priv(hw->dev[1]), Q_R2);
+}
+
+static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
+{
+	struct net_device *dev = hw->dev[port];
+
+	DBGIO(PFX "%s: hw error interrupt status 0x%x\n", dev->name, status);
+
+	if (status & Y2_IS_PAR_RD1) {
+		DBG(PFX "%s: ram data read parity error\n", dev->name);
+		/* Clear IRQ */
+		sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_RD_PERR);
+	}
+
+	if (status & Y2_IS_PAR_WR1) {
+		DBG(PFX "%s: ram data write parity error\n", dev->name);
+		sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_WR_PERR);
+	}
+
+	if (status & Y2_IS_PAR_MAC1) {
+		DBG(PFX "%s: MAC parity error\n", dev->name);
+		sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_PE);
+	}
+
+	if (status & Y2_IS_PAR_RX1) {
+		DBG(PFX "%s: RX parity error\n", dev->name);
+		sky2_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_CLR_IRQ_PAR);
+	}
+
+	if (status & Y2_IS_TCP_TXA1) {
+		DBG(PFX "%s: TCP segmentation error\n", dev->name);
+		sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_CLR_IRQ_TCP);
+	}
+}
+
+static void sky2_hw_intr(struct sky2_hw *hw)
+{
+	u32 status = sky2_read32(hw, B0_HWE_ISRC);
+	u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
+
+	status &= hwmsk;
+
+	if (status & Y2_IS_TIST_OV)
+		sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
+
+	if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
+		u16 pci_err;
+
+		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		pci_err = sky2_pci_read16(hw, PCI_STATUS);
+		DBG(PFX "PCI hardware error (0x%x)\n", pci_err);
+
+		sky2_pci_write16(hw, PCI_STATUS,
+				 pci_err | PCI_STATUS_ERROR_BITS);
+		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	}
+
+	if (status & Y2_IS_PCI_EXP) {
+		/* PCI-Express uncorrectable Error occurred */
+		u32 err;
+
+		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+		sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
+			     0xfffffffful);
+		DBG(PFX "PCI-Express error (0x%x)\n", err);
+
+		sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	}
+
+	if (status & Y2_HWE_L1_MASK)
+		sky2_hw_error(hw, 0, status);
+	status >>= 8;
+	if (status & Y2_HWE_L1_MASK)
+		sky2_hw_error(hw, 1, status);
+}
+
+static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
+{
+	struct net_device *dev = hw->dev[port];
+	u8 status = sky2_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+	DBGIO(PFX "%s: mac interrupt status 0x%x\n", dev->name, status);
+
+	if (status & GM_IS_RX_CO_OV)
+		gma_read16(hw, port, GM_RX_IRQ_SRC);
+
+	if (status & GM_IS_TX_CO_OV)
+		gma_read16(hw, port, GM_TX_IRQ_SRC);
+
+	if (status & GM_IS_RX_FF_OR) {
+		sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
+	}
+
+	if (status & GM_IS_TX_FF_UR) {
+		sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
+	}
+}
+
+/* This should never happen it is a bug. */
+static void sky2_le_error(struct sky2_hw *hw, unsigned port,
+			  u16 q, unsigned ring_size __unused)
+{
+	struct net_device *dev = hw->dev[port];
+	struct sky2_port *sky2 = netdev_priv(dev);
+	int idx;
+	const u64 *le = (q == Q_R1 || q == Q_R2)
+		? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le;
+
+	idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX));
+	DBG(PFX "%s: descriptor error q=%#x get=%d [%llx] last=%d put=%d should be %d\n",
+	    dev->name, (unsigned) q, idx, (unsigned long long) le[idx],
+	    (int) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_LAST_IDX)),
+	    (int) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)),
+	    le == (u64 *)sky2->rx_le? sky2->rx_put : sky2->tx_prod);
+
+	sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
+}
+
+/* Hardware/software error handling */
+static void sky2_err_intr(struct sky2_hw *hw, u32 status)
+{
+	DBG(PFX "error interrupt status=%#x\n", status);
+
+	if (status & Y2_IS_HW_ERR)
+		sky2_hw_intr(hw);
+
+	if (status & Y2_IS_IRQ_MAC1)
+		sky2_mac_intr(hw, 0);
+
+	if (status & Y2_IS_IRQ_MAC2)
+		sky2_mac_intr(hw, 1);
+
+	if (status & Y2_IS_CHK_RX1)
+		sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE);
+
+	if (status & Y2_IS_CHK_RX2)
+		sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE);
+
+	if (status & Y2_IS_CHK_TXA1)
+		sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE);
+
+	if (status & Y2_IS_CHK_TXA2)
+		sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
+}
+
+static void sky2_poll(struct net_device *dev)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+	u16 idx;
+
+	if (status & Y2_IS_ERROR)
+		sky2_err_intr(hw, status);
+
+	if (status & Y2_IS_IRQ_PHY1)
+		sky2_phy_intr(hw, 0);
+
+	if (status & Y2_IS_IRQ_PHY2)
+		sky2_phy_intr(hw, 1);
+
+	while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) {
+		sky2_status_intr(hw, idx);
+	}
+
+	/* Bug/Errata workaround?
+	 * Need to kick the TX irq moderation timer.
+	 */
+	if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) {
+		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
+		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
+	}
+	sky2_read32(hw, B0_Y2_SP_LISR);
+}
+
+/* Chip internal frequency for clock calculations */
+static u32 sky2_mhz(const struct sky2_hw *hw)
+{
+	switch (hw->chip_id) {
+	case CHIP_ID_YUKON_EC:
+	case CHIP_ID_YUKON_EC_U:
+	case CHIP_ID_YUKON_EX:
+	case CHIP_ID_YUKON_SUPR:
+	case CHIP_ID_YUKON_UL_2:
+		return 125;
+
+	case CHIP_ID_YUKON_FE:
+		return 100;
+
+	case CHIP_ID_YUKON_FE_P:
+		return 50;
+
+	case CHIP_ID_YUKON_XL:
+		return 156;
+
+	default:
+		DBG(PFX "unknown chip ID!\n");
+		return 100;	/* bogus */
+	}
+}
+
+static inline u32 sky2_us2clk(const struct sky2_hw *hw, u32 us)
+{
+	return sky2_mhz(hw) * us;
+}
+
+static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
+{
+	return clk / sky2_mhz(hw);
+}
+
+static int sky2_init(struct sky2_hw *hw)
+{
+	u8 t8;
+
+	/* Enable all clocks and check for bad PCI access */
+	sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
+	sky2_write8(hw, B0_CTST, CS_RST_CLR);
+
+	hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
+	hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+
+	switch(hw->chip_id) {
+	case CHIP_ID_YUKON_XL:
+		hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
+		break;
+
+	case CHIP_ID_YUKON_EC_U:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	case CHIP_ID_YUKON_EX:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	case CHIP_ID_YUKON_EC:
+		/* This rev is really old, and requires untested workarounds */
+		if (hw->chip_rev == CHIP_REV_YU_EC_A1) {
+			DBG(PFX "unsupported revision Yukon-EC rev A1\n");
+			return -EOPNOTSUPP;
+		}
+		hw->flags = SKY2_HW_GIGABIT;
+		break;
+
+	case CHIP_ID_YUKON_FE:
+		break;
+
+	case CHIP_ID_YUKON_FE_P:
+		hw->flags = SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_AUTO_TX_SUM
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	case CHIP_ID_YUKON_SUPR:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_AUTO_TX_SUM
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	case CHIP_ID_YUKON_UL_2:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	default:
+		DBG(PFX "unsupported chip type 0x%x\n", hw->chip_id);
+		return -EOPNOTSUPP;
+	}
+
+	hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+	if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
+		hw->flags |= SKY2_HW_FIBRE_PHY;
+
+	hw->ports = 1;
+	t8 = sky2_read8(hw, B2_Y2_HW_RES);
+	if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+		if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+			++hw->ports;
+	}
+
+	return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+	u16 status;
+	int i, cap;
+	u32 hwe_mask = Y2_HWE_ALL_MASK;
+
+	/* disable ASF */
+	if (hw->chip_id == CHIP_ID_YUKON_EX) {
+		status = sky2_read16(hw, HCU_CCSR);
+		status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+			    HCU_CCSR_UC_STATE_MSK);
+		sky2_write16(hw, HCU_CCSR, status);
+	} else
+		sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+	sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
+
+	/* do a SW reset */
+	sky2_write8(hw, B0_CTST, CS_RST_SET);
+	sky2_write8(hw, B0_CTST, CS_RST_CLR);
+
+	/* allow writes to PCI config */
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+
+	/* clear PCI errors, if any */
+	status = sky2_pci_read16(hw, PCI_STATUS);
+	status |= PCI_STATUS_ERROR_BITS;
+	sky2_pci_write16(hw, PCI_STATUS, status);
+
+	sky2_write8(hw, B0_CTST, CS_MRST_CLR);
+
+	cap = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP);
+	if (cap) {
+		sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
+			     0xfffffffful);
+
+		/* If an error bit is stuck on ignore it */
+		if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP)
+			DBG(PFX "ignoring stuck error report bit\n");
+		else
+			hwe_mask |= Y2_IS_PCI_EXP;
+	}
+
+	sky2_power_on(hw);
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	for (i = 0; i < hw->ports; i++) {
+		sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+		sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+		if (hw->chip_id == CHIP_ID_YUKON_EX ||
+		    hw->chip_id == CHIP_ID_YUKON_SUPR)
+			sky2_write16(hw, SK_REG(i, GMAC_CTRL),
+				     GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON
+				     | GMC_BYP_RETR_ON);
+	}
+
+	/* Clear I2C IRQ noise */
+	sky2_write32(hw, B2_I2C_IRQ, 1);
+
+	/* turn off hardware timer (unused) */
+	sky2_write8(hw, B2_TI_CTRL, TIM_STOP);
+	sky2_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ);
+
+	sky2_write8(hw, B0_Y2LED, LED_STAT_ON);
+
+	/* Turn off descriptor polling */
+	sky2_write32(hw, B28_DPT_CTRL, DPT_STOP);
+
+	/* Turn off receive timestamp */
+	sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_STOP);
+	sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
+
+	/* enable the Tx Arbiters */
+	for (i = 0; i < hw->ports; i++)
+		sky2_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
+
+	/* Initialize ram interface */
+	for (i = 0; i < hw->ports; i++) {
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_CTRL), RI_RST_CLR);
+
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_R1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_XA1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_XS1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_R1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XA1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS1), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_R2), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_XA2), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_WTO_XS2), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_R2), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XA2), SK_RI_TO_53);
+		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53);
+	}
+
+	sky2_write32(hw, B0_HWE_IMSK, hwe_mask);
+
+	for (i = 0; i < hw->ports; i++)
+		sky2_gmac_reset(hw, i);
+
+	memset(hw->st_le, 0, STATUS_LE_BYTES);
+	hw->st_idx = 0;
+
+	sky2_write32(hw, STAT_CTRL, SC_STAT_RST_SET);
+	sky2_write32(hw, STAT_CTRL, SC_STAT_RST_CLR);
+
+	sky2_write32(hw, STAT_LIST_ADDR_LO, hw->st_dma);
+	sky2_write32(hw, STAT_LIST_ADDR_HI, (u64) hw->st_dma >> 32);
+
+	/* Set the list last index */
+	sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1);
+
+	sky2_write16(hw, STAT_TX_IDX_TH, 10);
+	sky2_write8(hw, STAT_FIFO_WM, 16);
+
+	/* set Status-FIFO ISR watermark */
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0)
+		sky2_write8(hw, STAT_FIFO_ISR_WM, 4);
+	else
+		sky2_write8(hw, STAT_FIFO_ISR_WM, 16);
+
+	sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000));
+	sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 20));
+	sky2_write32(hw, STAT_LEV_TIMER_INI, sky2_us2clk(hw, 100));
+
+	/* enable status unit */
+	sky2_write32(hw, STAT_CTRL, SC_STAT_OP_ON);
+
+	sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
+	sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
+	sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
+
+static u32 sky2_supported_modes(const struct sky2_hw *hw)
+{
+	if (sky2_is_copper(hw)) {
+		u32 modes = SUPPORTED_10baseT_Half
+			| SUPPORTED_10baseT_Full
+			| SUPPORTED_100baseT_Half
+			| SUPPORTED_100baseT_Full
+			| SUPPORTED_Autoneg | SUPPORTED_TP;
+
+		if (hw->flags & SKY2_HW_GIGABIT)
+			modes |= SUPPORTED_1000baseT_Half
+				| SUPPORTED_1000baseT_Full;
+		return modes;
+	} else
+		return  SUPPORTED_1000baseT_Half
+			| SUPPORTED_1000baseT_Full
+			| SUPPORTED_Autoneg
+			| SUPPORTED_FIBRE;
+}
+
+static void sky2_set_multicast(struct net_device *dev)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	u16 reg;
+	u8 filter[8];
+
+	reg = gma_read16(hw, port, GM_RX_CTRL);
+	reg |= GM_RXCR_UCF_ENA;
+
+	memset(filter, 0xff, sizeof(filter));
+
+	gma_write16(hw, port, GM_MC_ADDR_H1,
+		    (u16) filter[0] | ((u16) filter[1] << 8));
+	gma_write16(hw, port, GM_MC_ADDR_H2,
+		    (u16) filter[2] | ((u16) filter[3] << 8));
+	gma_write16(hw, port, GM_MC_ADDR_H3,
+		    (u16) filter[4] | ((u16) filter[5] << 8));
+	gma_write16(hw, port, GM_MC_ADDR_H4,
+		    (u16) filter[6] | ((u16) filter[7] << 8));
+
+	gma_write16(hw, port, GM_RX_CTRL, reg);
+}
+
+/* Initialize network device */
+static struct net_device *sky2_init_netdev(struct sky2_hw *hw,
+						     unsigned port)
+{
+	struct sky2_port *sky2;
+	struct net_device *dev = alloc_etherdev(sizeof(*sky2));
+
+	if (!dev) {
+		DBG(PFX "etherdev alloc failed\n");
+		return NULL;
+	}
+
+	dev->dev = &hw->pdev->dev;
+
+	sky2 = netdev_priv(dev);
+	sky2->netdev = dev;
+	sky2->hw = hw;
+
+	/* Auto speed and flow control */
+	sky2->autoneg = AUTONEG_ENABLE;
+	sky2->flow_mode = FC_BOTH;
+
+	sky2->duplex = -1;
+	sky2->speed = -1;
+	sky2->advertising = sky2_supported_modes(hw);
+
+	hw->dev[port] = dev;
+
+	sky2->port = port;
+
+	/* read the mac address */
+	memcpy(dev->hw_addr, (void *)(hw->regs + B2_MAC_1 + port * 8), ETH_ALEN);
+
+	return dev;
+}
+
+static void sky2_show_addr(struct net_device *dev)
+{
+	DBG2(PFX "%s: addr %s\n", dev->name, netdev_addr(dev));
+}
+
+#if DBGLVL_MAX
+/* This driver supports yukon2 chipset only */
+static const char *sky2_name(u8 chipid, char *buf, int sz)
+{
+	const char *name[] = {
+		"XL",		/* 0xb3 */
+		"EC Ultra", 	/* 0xb4 */
+		"Extreme",	/* 0xb5 */
+		"EC",		/* 0xb6 */
+		"FE",		/* 0xb7 */
+		"FE+",		/* 0xb8 */
+		"Supreme",	/* 0xb9 */
+		"UL 2",		/* 0xba */
+	};
+
+	if (chipid >= CHIP_ID_YUKON_XL && chipid <= CHIP_ID_YUKON_UL_2)
+		strncpy(buf, name[chipid - CHIP_ID_YUKON_XL], sz);
+	else
+		snprintf(buf, sz, "(chip %#x)", chipid);
+	return buf;
+}
+#endif
+
+static void sky2_net_irq(struct net_device *dev, int enable)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+
+	u32 imask = sky2_read32(hw, B0_IMSK);
+	if (enable)
+		imask |= portirq_msk[sky2->port];
+	else
+		imask &= ~portirq_msk[sky2->port];
+	sky2_write32(hw, B0_IMSK, imask);
+}
+
+static struct net_device_operations sky2_operations = {
+	.open     = sky2_up,
+	.close    = sky2_down,
+	.transmit = sky2_xmit_frame,
+	.poll     = sky2_poll,
+	.irq      = sky2_net_irq
+};
+
+static int sky2_probe(struct pci_device *pdev)
+{
+	struct net_device *dev;
+	struct sky2_hw *hw;
+	int err;
+	char buf1[16] __unused;	/* only for debugging */
+
+	adjust_pci_device(pdev);
+
+	err = -ENOMEM;
+	hw = zalloc(sizeof(*hw));
+	if (!hw) {
+		DBG(PFX "cannot allocate hardware struct\n");
+		goto err_out;
+	}
+
+	hw->pdev = pdev;
+
+	hw->regs = (unsigned long)ioremap(pci_bar_start(pdev, PCI_BASE_ADDRESS_0), 0x4000);
+	if (!hw->regs) {
+		DBG(PFX "cannot map device registers\n");
+		goto err_out_free_hw;
+	}
+
+	/* ring for status responses */
+	hw->st_le = malloc_dma(STATUS_LE_BYTES, STATUS_RING_ALIGN);
+	if (!hw->st_le)
+		goto err_out_iounmap;
+	hw->st_dma = virt_to_bus(hw->st_le);
+	memset(hw->st_le, 0, STATUS_LE_BYTES);
+
+	err = sky2_init(hw);
+	if (err)
+		goto err_out_iounmap;
+
+#if DBGLVL_MAX
+	DBG2(PFX "Yukon-2 %s chip revision %d\n",
+	     sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
+#endif
+
+	sky2_reset(hw);
+
+	dev = sky2_init_netdev(hw, 0);
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out_free_pci;
+	}
+
+	netdev_init(dev, &sky2_operations);
+
+	err = register_netdev(dev);
+	if (err) {
+		DBG(PFX "cannot register net device\n");
+		goto err_out_free_netdev;
+	}
+
+	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+
+	sky2_show_addr(dev);
+
+	if (hw->ports > 1) {
+		struct net_device *dev1;
+
+		dev1 = sky2_init_netdev(hw, 1);
+		if (!dev1)
+			DBG(PFX "allocation for second device failed\n");
+		else if ((err = register_netdev(dev1))) {
+			DBG(PFX "register of second port failed (%d)\n", err);
+			hw->dev[1] = NULL;
+			netdev_nullify(dev1);
+			netdev_put(dev1);
+		} else
+			sky2_show_addr(dev1);
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_out_free_netdev:
+	netdev_nullify(dev);
+	netdev_put(dev);
+err_out_free_pci:
+	sky2_write8(hw, B0_CTST, CS_RST_SET);
+	free_dma(hw->st_le, STATUS_LE_BYTES);
+err_out_iounmap:
+	iounmap((void *)hw->regs);
+err_out_free_hw:
+	free(hw);
+err_out:
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void sky2_remove(struct pci_device *pdev)
+{
+	struct sky2_hw *hw = pci_get_drvdata(pdev);
+	int i;
+
+	if (!hw)
+		return;
+
+	for (i = hw->ports-1; i >= 0; --i)
+		unregister_netdev(hw->dev[i]);
+
+	sky2_write32(hw, B0_IMSK, 0);
+
+	sky2_power_aux(hw);
+
+	sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
+	sky2_write8(hw, B0_CTST, CS_RST_SET);
+	sky2_read8(hw, B0_CTST);
+
+	free_dma(hw->st_le, STATUS_LE_BYTES);
+
+	for (i = hw->ports-1; i >= 0; --i) {
+		netdev_nullify(hw->dev[i]);
+		netdev_put(hw->dev[i]);
+	}
+
+	iounmap((void *)hw->regs);
+	free(hw);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+struct pci_driver sky2_driver __pci_driver = {
+	.ids      = sky2_id_table,
+	.id_count = (sizeof (sky2_id_table) / sizeof (sky2_id_table[0])),
+	.probe    = sky2_probe,
+	.remove   = sky2_remove
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.h
new file mode 100644
index 0000000..3e86b1d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sky2.h
@@ -0,0 +1,2176 @@
+/*
+ * Definitions for the new Marvell Yukon 2 driver.
+ */
+#ifndef _SKY2_H
+#define _SKY2_H
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* Added for iPXE ------------------ */
+
+/* These were defined in Linux ethtool.h. Their values are arbitrary;
+   they aid only in bookkeeping for the driver. */
+
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+#define DUPLEX_HALF    0x00
+#define DUPLEX_FULL    0x01
+
+#define SPEED_10       10
+#define SPEED_100      100
+#define SPEED_1000     1000
+
+#define ADVERTISED_10baseT_Half        (1 << 0)
+#define ADVERTISED_10baseT_Full        (1 << 1)
+#define ADVERTISED_100baseT_Half       (1 << 2)
+#define ADVERTISED_100baseT_Full       (1 << 3)
+#define ADVERTISED_1000baseT_Half      (1 << 4)
+#define ADVERTISED_1000baseT_Full      (1 << 5)
+
+#define SUPPORTED_10baseT_Half         (1 << 0)
+#define SUPPORTED_10baseT_Full         (1 << 1)
+#define SUPPORTED_100baseT_Half        (1 << 2)
+#define SUPPORTED_100baseT_Full        (1 << 3)
+#define SUPPORTED_1000baseT_Half       (1 << 4)
+#define SUPPORTED_1000baseT_Full       (1 << 5)
+#define SUPPORTED_Autoneg              (1 << 6)
+#define SUPPORTED_TP                   (1 << 7)
+#define SUPPORTED_FIBRE                (1 << 10)
+
+/* ----------------------------------- */
+
+/* PCI config registers */
+enum {
+	PCI_DEV_REG1	= 0x40,
+	PCI_DEV_REG2	= 0x44,
+	PCI_DEV_STATUS  = 0x7c,
+	PCI_DEV_REG3	= 0x80,
+	PCI_DEV_REG4	= 0x84,
+	PCI_DEV_REG5    = 0x88,
+	PCI_CFG_REG_0	= 0x90,
+	PCI_CFG_REG_1	= 0x94,
+};
+
+/* Yukon-2 */
+enum pci_dev_reg_1 {
+	PCI_Y2_PIG_ENA	 = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
+	PCI_Y2_DLL_DIS	 = 1<<30, /* Disable PCI DLL (YUKON-2) */
+	PCI_SW_PWR_ON_RST= 1<<30, /* SW Power on Reset (Yukon-EX) */
+	PCI_Y2_PHY2_COMA = 1<<29, /* Set PHY 2 to Coma Mode (YUKON-2) */
+	PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
+	PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
+	PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+	PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
+
+	PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit  9.. 8:	GPHY Link Trigger Timer */
+	PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */
+	PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */
+	PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */
+};
+
+enum pci_dev_reg_2 {
+	PCI_VPD_WR_THR	= 0xffL<<24,	/* Bit 31..24:	VPD Write Threshold */
+	PCI_DEV_SEL	= 0x7fL<<17,	/* Bit 23..17:	EEPROM Device Select */
+	PCI_VPD_ROM_SZ	= 7L<<14,	/* Bit 16..14:	VPD ROM Size	*/
+
+	PCI_PATCH_DIR	= 0xfL<<8,	/* Bit 11.. 8:	Ext Patches dir 3..0 */
+	PCI_EXT_PATCHS	= 0xfL<<4,	/* Bit	7.. 4:	Extended Patches 3..0 */
+	PCI_EN_DUMMY_RD	= 1<<3,		/* Enable Dummy Read */
+	PCI_REV_DESC	= 1<<2,		/* Reverse Desc. Bytes */
+
+	PCI_USEDATA64	= 1<<0,		/* Use 64Bit Data bus ext */
+};
+
+/*	PCI_OUR_REG_4		32 bit	Our Register 4 (Yukon-ECU only) */
+enum pci_dev_reg_4 {
+				/* (Link Training & Status State Machine) */
+	P_PEX_LTSSM_STAT_MSK	= 0x7fL<<25,	/* Bit 31..25:	PEX LTSSM Mask */
+#define P_PEX_LTSSM_STAT(x)	((x << 25) & P_PEX_LTSSM_STAT_MSK)
+	P_PEX_LTSSM_L1_STAT	= 0x34,
+	P_PEX_LTSSM_DET_STAT	= 0x01,
+	P_TIMER_VALUE_MSK	= 0xffL<<16,	/* Bit 23..16:	Timer Value Mask */
+					/* (Active State Power Management) */
+	P_FORCE_ASPM_REQUEST	= 1<<15, /* Force ASPM Request (A1 only) */
+	P_ASPM_GPHY_LINK_DOWN	= 1<<14, /* GPHY Link Down (A1 only) */
+	P_ASPM_INT_FIFO_EMPTY	= 1<<13, /* Internal FIFO Empty (A1 only) */
+	P_ASPM_CLKRUN_REQUEST	= 1<<12, /* CLKRUN Request (A1 only) */
+
+	P_ASPM_FORCE_CLKREQ_ENA	= 1<<4,	/* Force CLKREQ Enable (A1b only) */
+	P_ASPM_CLKREQ_PAD_CTL	= 1<<3,	/* CLKREQ PAD Control (A1 only) */
+	P_ASPM_A1_MODE_SELECT	= 1<<2,	/* A1 Mode Select (A1 only) */
+	P_CLK_GATE_PEX_UNIT_ENA	= 1<<1,	/* Enable Gate PEX Unit Clock */
+	P_CLK_GATE_ROOT_COR_ENA	= 1<<0,	/* Enable Gate Root Core Clock */
+	P_ASPM_CONTROL_MSK	= P_FORCE_ASPM_REQUEST | P_ASPM_GPHY_LINK_DOWN
+				  | P_ASPM_CLKRUN_REQUEST | P_ASPM_INT_FIFO_EMPTY,
+};
+
+/*	PCI_OUR_REG_5		32 bit	Our Register 5 (Yukon-ECU only) */
+enum pci_dev_reg_5 {
+					/* Bit 31..27:	for A3 & later */
+	P_CTL_DIV_CORE_CLK_ENA	= 1<<31, /* Divide Core Clock Enable */
+	P_CTL_SRESET_VMAIN_AV	= 1<<30, /* Soft Reset for Vmain_av De-Glitch */
+	P_CTL_BYPASS_VMAIN_AV	= 1<<29, /* Bypass En. for Vmain_av De-Glitch */
+	P_CTL_TIM_VMAIN_AV_MSK	= 3<<27, /* Bit 28..27: Timer Vmain_av Mask */
+					 /* Bit 26..16: Release Clock on Event */
+	P_REL_PCIE_RST_DE_ASS	= 1<<26, /* PCIe Reset De-Asserted */
+	P_REL_GPHY_REC_PACKET	= 1<<25, /* GPHY Received Packet */
+	P_REL_INT_FIFO_N_EMPTY	= 1<<24, /* Internal FIFO Not Empty */
+	P_REL_MAIN_PWR_AVAIL	= 1<<23, /* Main Power Available */
+	P_REL_CLKRUN_REQ_REL	= 1<<22, /* CLKRUN Request Release */
+	P_REL_PCIE_RESET_ASS	= 1<<21, /* PCIe Reset Asserted */
+	P_REL_PME_ASSERTED	= 1<<20, /* PME Asserted */
+	P_REL_PCIE_EXIT_L1_ST	= 1<<19, /* PCIe Exit L1 State */
+	P_REL_LOADER_NOT_FIN	= 1<<18, /* EPROM Loader Not Finished */
+	P_REL_PCIE_RX_EX_IDLE	= 1<<17, /* PCIe Rx Exit Electrical Idle State */
+	P_REL_GPHY_LINK_UP	= 1<<16, /* GPHY Link Up */
+
+					/* Bit 10.. 0: Mask for Gate Clock */
+	P_GAT_PCIE_RST_ASSERTED	= 1<<10,/* PCIe Reset Asserted */
+	P_GAT_GPHY_N_REC_PACKET	= 1<<9, /* GPHY Not Received Packet */
+	P_GAT_INT_FIFO_EMPTY	= 1<<8, /* Internal FIFO Empty */
+	P_GAT_MAIN_PWR_N_AVAIL	= 1<<7, /* Main Power Not Available */
+	P_GAT_CLKRUN_REQ_REL	= 1<<6, /* CLKRUN Not Requested */
+	P_GAT_PCIE_RESET_ASS	= 1<<5, /* PCIe Reset Asserted */
+	P_GAT_PME_DE_ASSERTED	= 1<<4, /* PME De-Asserted */
+	P_GAT_PCIE_ENTER_L1_ST	= 1<<3, /* PCIe Enter L1 State */
+	P_GAT_LOADER_FINISHED	= 1<<2, /* EPROM Loader Finished */
+	P_GAT_PCIE_RX_EL_IDLE	= 1<<1, /* PCIe Rx Electrical Idle State */
+	P_GAT_GPHY_LINK_DOWN	= 1<<0,	/* GPHY Link Down */
+
+	PCIE_OUR5_EVENT_CLK_D3_SET = P_REL_GPHY_REC_PACKET |
+				     P_REL_INT_FIFO_N_EMPTY |
+				     P_REL_PCIE_EXIT_L1_ST |
+				     P_REL_PCIE_RX_EX_IDLE |
+				     P_GAT_GPHY_N_REC_PACKET |
+				     P_GAT_INT_FIFO_EMPTY |
+				     P_GAT_PCIE_ENTER_L1_ST |
+				     P_GAT_PCIE_RX_EL_IDLE,
+};
+
+#/*	PCI_CFG_REG_1			32 bit	Config Register 1 (Yukon-Ext only) */
+enum pci_cfg_reg1 {
+	P_CF1_DIS_REL_EVT_RST	= 1<<24, /* Dis. Rel. Event during PCIE reset */
+										/* Bit 23..21: Release Clock on Event */
+	P_CF1_REL_LDR_NOT_FIN	= 1<<23, /* EEPROM Loader Not Finished */
+	P_CF1_REL_VMAIN_AVLBL	= 1<<22, /* Vmain available */
+	P_CF1_REL_PCIE_RESET	= 1<<21, /* PCI-E reset */
+										/* Bit 20..18: Gate Clock on Event */
+	P_CF1_GAT_LDR_NOT_FIN	= 1<<20, /* EEPROM Loader Finished */
+	P_CF1_GAT_PCIE_RX_IDLE	= 1<<19, /* PCI-E Rx Electrical idle */
+	P_CF1_GAT_PCIE_RESET	= 1<<18, /* PCI-E Reset */
+	P_CF1_PRST_PHY_CLKREQ	= 1<<17, /* Enable PCI-E rst & PM2PHY gen. CLKREQ */
+	P_CF1_PCIE_RST_CLKREQ	= 1<<16, /* Enable PCI-E rst generate CLKREQ */
+
+	P_CF1_ENA_CFG_LDR_DONE	= 1<<8, /* Enable core level Config loader done */
+
+	P_CF1_ENA_TXBMU_RD_IDLE	= 1<<1, /* Enable TX BMU Read  IDLE for ASPM */
+	P_CF1_ENA_TXBMU_WR_IDLE	= 1<<0, /* Enable TX BMU Write IDLE for ASPM */
+
+	PCIE_CFG1_EVENT_CLK_D3_SET = P_CF1_DIS_REL_EVT_RST |
+					P_CF1_REL_LDR_NOT_FIN |
+					P_CF1_REL_VMAIN_AVLBL |
+					P_CF1_REL_PCIE_RESET |
+					P_CF1_GAT_LDR_NOT_FIN |
+					P_CF1_GAT_PCIE_RESET |
+					P_CF1_PRST_PHY_CLKREQ |
+					P_CF1_ENA_CFG_LDR_DONE |
+					P_CF1_ENA_TXBMU_RD_IDLE |
+					P_CF1_ENA_TXBMU_WR_IDLE,
+};
+
+
+#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
+			       PCI_STATUS_SIG_SYSTEM_ERROR | \
+			       PCI_STATUS_REC_MASTER_ABORT | \
+			       PCI_STATUS_REC_TARGET_ABORT | \
+			       PCI_STATUS_PARITY)
+
+enum csr_regs {
+	B0_RAP		= 0x0000,
+	B0_CTST		= 0x0004,
+	B0_Y2LED	= 0x0005,
+	B0_POWER_CTRL	= 0x0007,
+	B0_ISRC		= 0x0008,
+	B0_IMSK		= 0x000c,
+	B0_HWE_ISRC	= 0x0010,
+	B0_HWE_IMSK	= 0x0014,
+
+	/* Special ISR registers (Yukon-2 only) */
+	B0_Y2_SP_ISRC2	= 0x001c,
+	B0_Y2_SP_ISRC3	= 0x0020,
+	B0_Y2_SP_EISR	= 0x0024,
+	B0_Y2_SP_LISR	= 0x0028,
+	B0_Y2_SP_ICR	= 0x002c,
+
+	B2_MAC_1	= 0x0100,
+	B2_MAC_2	= 0x0108,
+	B2_MAC_3	= 0x0110,
+	B2_CONN_TYP	= 0x0118,
+	B2_PMD_TYP	= 0x0119,
+	B2_MAC_CFG	= 0x011a,
+	B2_CHIP_ID	= 0x011b,
+	B2_E_0		= 0x011c,
+
+	B2_Y2_CLK_GATE  = 0x011d,
+	B2_Y2_HW_RES	= 0x011e,
+	B2_E_3		= 0x011f,
+	B2_Y2_CLK_CTRL	= 0x0120,
+
+	B2_TI_INI	= 0x0130,
+	B2_TI_VAL	= 0x0134,
+	B2_TI_CTRL	= 0x0138,
+	B2_TI_TEST	= 0x0139,
+
+	B2_TST_CTRL1	= 0x0158,
+	B2_TST_CTRL2	= 0x0159,
+	B2_GP_IO	= 0x015c,
+
+	B2_I2C_CTRL	= 0x0160,
+	B2_I2C_DATA	= 0x0164,
+	B2_I2C_IRQ	= 0x0168,
+	B2_I2C_SW	= 0x016c,
+
+	B3_RAM_ADDR	= 0x0180,
+	B3_RAM_DATA_LO	= 0x0184,
+	B3_RAM_DATA_HI	= 0x0188,
+
+/* RAM Interface Registers */
+/* Yukon-2: use RAM_BUFFER() to access the RAM buffer */
+/*
+ * The HW-Spec. calls this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transferred continuously.
+ */
+#define RAM_BUFFER(port, reg)	(reg | (port <<6))
+
+	B3_RI_WTO_R1	= 0x0190,
+	B3_RI_WTO_XA1	= 0x0191,
+	B3_RI_WTO_XS1	= 0x0192,
+	B3_RI_RTO_R1	= 0x0193,
+	B3_RI_RTO_XA1	= 0x0194,
+	B3_RI_RTO_XS1	= 0x0195,
+	B3_RI_WTO_R2	= 0x0196,
+	B3_RI_WTO_XA2	= 0x0197,
+	B3_RI_WTO_XS2	= 0x0198,
+	B3_RI_RTO_R2	= 0x0199,
+	B3_RI_RTO_XA2	= 0x019a,
+	B3_RI_RTO_XS2	= 0x019b,
+	B3_RI_TO_VAL	= 0x019c,
+	B3_RI_CTRL	= 0x01a0,
+	B3_RI_TEST	= 0x01a2,
+	B3_MA_TOINI_RX1	= 0x01b0,
+	B3_MA_TOINI_RX2	= 0x01b1,
+	B3_MA_TOINI_TX1	= 0x01b2,
+	B3_MA_TOINI_TX2	= 0x01b3,
+	B3_MA_TOVAL_RX1	= 0x01b4,
+	B3_MA_TOVAL_RX2	= 0x01b5,
+	B3_MA_TOVAL_TX1	= 0x01b6,
+	B3_MA_TOVAL_TX2	= 0x01b7,
+	B3_MA_TO_CTRL	= 0x01b8,
+	B3_MA_TO_TEST	= 0x01ba,
+	B3_MA_RCINI_RX1	= 0x01c0,
+	B3_MA_RCINI_RX2	= 0x01c1,
+	B3_MA_RCINI_TX1	= 0x01c2,
+	B3_MA_RCINI_TX2	= 0x01c3,
+	B3_MA_RCVAL_RX1	= 0x01c4,
+	B3_MA_RCVAL_RX2	= 0x01c5,
+	B3_MA_RCVAL_TX1	= 0x01c6,
+	B3_MA_RCVAL_TX2	= 0x01c7,
+	B3_MA_RC_CTRL	= 0x01c8,
+	B3_MA_RC_TEST	= 0x01ca,
+	B3_PA_TOINI_RX1	= 0x01d0,
+	B3_PA_TOINI_RX2	= 0x01d4,
+	B3_PA_TOINI_TX1	= 0x01d8,
+	B3_PA_TOINI_TX2	= 0x01dc,
+	B3_PA_TOVAL_RX1	= 0x01e0,
+	B3_PA_TOVAL_RX2	= 0x01e4,
+	B3_PA_TOVAL_TX1	= 0x01e8,
+	B3_PA_TOVAL_TX2	= 0x01ec,
+	B3_PA_CTRL	= 0x01f0,
+	B3_PA_TEST	= 0x01f2,
+
+	Y2_CFG_SPC	= 0x1c00,	/* PCI config space region */
+	Y2_CFG_AER      = 0x1d00,	/* PCI Advanced Error Report region */
+};
+
+/*	B0_CTST			16 bit	Control/Status register */
+enum {
+	Y2_VMAIN_AVAIL	= 1<<17,/* VMAIN available (YUKON-2 only) */
+	Y2_VAUX_AVAIL	= 1<<16,/* VAUX available (YUKON-2 only) */
+	Y2_HW_WOL_ON	= 1<<15,/* HW WOL On  (Yukon-EC Ultra A1 only) */
+	Y2_HW_WOL_OFF	= 1<<14,/* HW WOL On  (Yukon-EC Ultra A1 only) */
+	Y2_ASF_ENABLE	= 1<<13,/* ASF Unit Enable (YUKON-2 only) */
+	Y2_ASF_DISABLE	= 1<<12,/* ASF Unit Disable (YUKON-2 only) */
+	Y2_CLK_RUN_ENA	= 1<<11,/* CLK_RUN Enable  (YUKON-2 only) */
+	Y2_CLK_RUN_DIS	= 1<<10,/* CLK_RUN Disable (YUKON-2 only) */
+	Y2_LED_STAT_ON	= 1<<9, /* Status LED On  (YUKON-2 only) */
+	Y2_LED_STAT_OFF	= 1<<8, /* Status LED Off (YUKON-2 only) */
+
+	CS_ST_SW_IRQ	= 1<<7,	/* Set IRQ SW Request */
+	CS_CL_SW_IRQ	= 1<<6,	/* Clear IRQ SW Request */
+	CS_STOP_DONE	= 1<<5,	/* Stop Master is finished */
+	CS_STOP_MAST	= 1<<4,	/* Command Bit to stop the master */
+	CS_MRST_CLR	= 1<<3,	/* Clear Master reset	*/
+	CS_MRST_SET	= 1<<2,	/* Set Master reset	*/
+	CS_RST_CLR	= 1<<1,	/* Clear Software reset	*/
+	CS_RST_SET	= 1,	/* Set   Software reset	*/
+};
+
+/*	B0_LED			 8 Bit	LED register */
+enum {
+/* Bit  7.. 2:	reserved */
+	LED_STAT_ON	= 1<<1,	/* Status LED on	*/
+	LED_STAT_OFF	= 1,	/* Status LED off	*/
+};
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+enum {
+	PC_VAUX_ENA	= 1<<7,	/* Switch VAUX Enable  */
+	PC_VAUX_DIS	= 1<<6,	/* Switch VAUX Disable */
+	PC_VCC_ENA	= 1<<5,	/* Switch VCC Enable  */
+	PC_VCC_DIS	= 1<<4,	/* Switch VCC Disable */
+	PC_VAUX_ON	= 1<<3,	/* Switch VAUX On  */
+	PC_VAUX_OFF	= 1<<2,	/* Switch VAUX Off */
+	PC_VCC_ON	= 1<<1,	/* Switch VCC On  */
+	PC_VCC_OFF	= 1<<0,	/* Switch VCC Off */
+};
+
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+
+/*	B0_Y2_SP_ISRC2	32 bit	Special Interrupt Source Reg 2 */
+/*	B0_Y2_SP_ISRC3	32 bit	Special Interrupt Source Reg 3 */
+/*	B0_Y2_SP_EISR	32 bit	Enter ISR Reg */
+/*	B0_Y2_SP_LISR	32 bit	Leave ISR Reg */
+enum {
+	Y2_IS_HW_ERR	= 1<<31,	/* Interrupt HW Error */
+	Y2_IS_STAT_BMU	= 1<<30,	/* Status BMU Interrupt */
+	Y2_IS_ASF	= 1<<29,	/* ASF subsystem Interrupt */
+
+	Y2_IS_POLL_CHK	= 1<<27,	/* Check IRQ from polling unit */
+	Y2_IS_TWSI_RDY	= 1<<26,	/* IRQ on end of TWSI Tx */
+	Y2_IS_IRQ_SW	= 1<<25,	/* SW forced IRQ	*/
+	Y2_IS_TIMINT	= 1<<24,	/* IRQ from Timer	*/
+
+	Y2_IS_IRQ_PHY2	= 1<<12,	/* Interrupt from PHY 2 */
+	Y2_IS_IRQ_MAC2	= 1<<11,	/* Interrupt from MAC 2 */
+	Y2_IS_CHK_RX2	= 1<<10,	/* Descriptor error Rx 2 */
+	Y2_IS_CHK_TXS2	= 1<<9,		/* Descriptor error TXS 2 */
+	Y2_IS_CHK_TXA2	= 1<<8,		/* Descriptor error TXA 2 */
+
+	Y2_IS_IRQ_PHY1	= 1<<4,		/* Interrupt from PHY 1 */
+	Y2_IS_IRQ_MAC1	= 1<<3,		/* Interrupt from MAC 1 */
+	Y2_IS_CHK_RX1	= 1<<2,		/* Descriptor error Rx 1 */
+	Y2_IS_CHK_TXS1	= 1<<1,		/* Descriptor error TXS 1 */
+	Y2_IS_CHK_TXA1	= 1<<0,		/* Descriptor error TXA 1 */
+
+	Y2_IS_BASE	= Y2_IS_HW_ERR | Y2_IS_STAT_BMU,
+	Y2_IS_PORT_1	= Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1
+		          | Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1,
+	Y2_IS_PORT_2	= Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2
+			  | Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2,
+	Y2_IS_ERROR     = Y2_IS_HW_ERR |
+			  Y2_IS_IRQ_MAC1 | Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1 |
+			  Y2_IS_IRQ_MAC2 | Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2,
+};
+
+/*	B2_IRQM_HWE_MSK	32 bit	IRQ Moderation HW Error Mask */
+enum {
+	IS_ERR_MSK	= 0x00003fff,/* 		All Error bits */
+
+	IS_IRQ_TIST_OV	= 1<<13, /* Time Stamp Timer Overflow (YUKON only) */
+	IS_IRQ_SENSOR	= 1<<12, /* IRQ from Sensor (YUKON only) */
+	IS_IRQ_MST_ERR	= 1<<11, /* IRQ master error detected */
+	IS_IRQ_STAT	= 1<<10, /* IRQ status exception */
+	IS_NO_STAT_M1	= 1<<9,	/* No Rx Status from MAC 1 */
+	IS_NO_STAT_M2	= 1<<8,	/* No Rx Status from MAC 2 */
+	IS_NO_TIST_M1	= 1<<7,	/* No Time Stamp from MAC 1 */
+	IS_NO_TIST_M2	= 1<<6,	/* No Time Stamp from MAC 2 */
+	IS_RAM_RD_PAR	= 1<<5,	/* RAM Read  Parity Error */
+	IS_RAM_WR_PAR	= 1<<4,	/* RAM Write Parity Error */
+	IS_M1_PAR_ERR	= 1<<3,	/* MAC 1 Parity Error */
+	IS_M2_PAR_ERR	= 1<<2,	/* MAC 2 Parity Error */
+	IS_R1_PAR_ERR	= 1<<1,	/* Queue R1 Parity Error */
+	IS_R2_PAR_ERR	= 1<<0,	/* Queue R2 Parity Error */
+};
+
+/* Hardware error interrupt mask for Yukon 2 */
+enum {
+	Y2_IS_TIST_OV	= 1<<29,/* Time Stamp Timer overflow interrupt */
+	Y2_IS_SENSOR	= 1<<28, /* Sensor interrupt */
+	Y2_IS_MST_ERR	= 1<<27, /* Master error interrupt */
+	Y2_IS_IRQ_STAT	= 1<<26, /* Status exception interrupt */
+	Y2_IS_PCI_EXP	= 1<<25, /* PCI-Express interrupt */
+	Y2_IS_PCI_NEXP	= 1<<24, /* PCI-Express error similar to PCI error */
+						/* Link 2 */
+	Y2_IS_PAR_RD2	= 1<<13, /* Read RAM parity error interrupt */
+	Y2_IS_PAR_WR2	= 1<<12, /* Write RAM parity error interrupt */
+	Y2_IS_PAR_MAC2	= 1<<11, /* MAC hardware fault interrupt */
+	Y2_IS_PAR_RX2	= 1<<10, /* Parity Error Rx Queue 2 */
+	Y2_IS_TCP_TXS2	= 1<<9, /* TCP length mismatch sync Tx queue IRQ */
+	Y2_IS_TCP_TXA2	= 1<<8, /* TCP length mismatch async Tx queue IRQ */
+						/* Link 1 */
+	Y2_IS_PAR_RD1	= 1<<5, /* Read RAM parity error interrupt */
+	Y2_IS_PAR_WR1	= 1<<4, /* Write RAM parity error interrupt */
+	Y2_IS_PAR_MAC1	= 1<<3, /* MAC hardware fault interrupt */
+	Y2_IS_PAR_RX1	= 1<<2, /* Parity Error Rx Queue 1 */
+	Y2_IS_TCP_TXS1	= 1<<1, /* TCP length mismatch sync Tx queue IRQ */
+	Y2_IS_TCP_TXA1	= 1<<0, /* TCP length mismatch async Tx queue IRQ */
+
+	Y2_HWE_L1_MASK	= Y2_IS_PAR_RD1 | Y2_IS_PAR_WR1 | Y2_IS_PAR_MAC1 |
+			  Y2_IS_PAR_RX1 | Y2_IS_TCP_TXS1| Y2_IS_TCP_TXA1,
+	Y2_HWE_L2_MASK	= Y2_IS_PAR_RD2 | Y2_IS_PAR_WR2 | Y2_IS_PAR_MAC2 |
+			  Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2,
+
+	Y2_HWE_ALL_MASK	= Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT |
+			  Y2_HWE_L1_MASK | Y2_HWE_L2_MASK,
+};
+
+/*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
+enum {
+	DPT_START	= 1<<1,
+	DPT_STOP	= 1<<0,
+};
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+enum {
+	TST_FRC_DPERR_MR = 1<<7, /* force DATAPERR on MST RD */
+	TST_FRC_DPERR_MW = 1<<6, /* force DATAPERR on MST WR */
+	TST_FRC_DPERR_TR = 1<<5, /* force DATAPERR on TRG RD */
+	TST_FRC_DPERR_TW = 1<<4, /* force DATAPERR on TRG WR */
+	TST_FRC_APERR_M	 = 1<<3, /* force ADDRPERR on MST */
+	TST_FRC_APERR_T	 = 1<<2, /* force ADDRPERR on TRG */
+	TST_CFG_WRITE_ON = 1<<1, /* Enable  Config Reg WR */
+	TST_CFG_WRITE_OFF= 1<<0, /* Disable Config Reg WR */
+};
+
+/* 	B2_GPIO */
+enum {
+	GLB_GPIO_CLK_DEB_ENA = 1<<31,	/* Clock Debug Enable */
+	GLB_GPIO_CLK_DBG_MSK = 0xf<<26, /* Clock Debug */
+
+	GLB_GPIO_INT_RST_D3_DIS = 1<<15, /* Disable Internal Reset After D3 to D0 */
+	GLB_GPIO_LED_PAD_SPEED_UP = 1<<14, /* LED PAD Speed Up */
+	GLB_GPIO_STAT_RACE_DIS	= 1<<13, /* Status Race Disable */
+	GLB_GPIO_TEST_SEL_MSK	= 3<<11, /* Testmode Select */
+	GLB_GPIO_TEST_SEL_BASE	= 1<<11,
+	GLB_GPIO_RAND_ENA	= 1<<10, /* Random Enable */
+	GLB_GPIO_RAND_BIT_1	= 1<<9,  /* Random Bit 1 */
+};
+
+/*	B2_MAC_CFG		 8 bit	MAC Configuration / Chip Revision */
+enum {
+	CFG_CHIP_R_MSK	  = 0xf<<4,	/* Bit 7.. 4: Chip Revision */
+					/* Bit 3.. 2:	reserved */
+	CFG_DIS_M2_CLK	  = 1<<1,	/* Disable Clock for 2nd MAC */
+	CFG_SNG_MAC	  = 1<<0,	/* MAC Config: 0=2 MACs / 1=1 MAC*/
+};
+
+/*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
+enum {
+	CHIP_ID_YUKON_XL   = 0xb3, /* YUKON-2 XL */
+	CHIP_ID_YUKON_EC_U = 0xb4, /* YUKON-2 EC Ultra */
+	CHIP_ID_YUKON_EX   = 0xb5, /* YUKON-2 Extreme */
+	CHIP_ID_YUKON_EC   = 0xb6, /* YUKON-2 EC */
+	CHIP_ID_YUKON_FE   = 0xb7, /* YUKON-2 FE */
+	CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
+	CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */
+	CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */
+};
+enum yukon_ec_rev {
+	CHIP_REV_YU_EC_A1    = 0,  /* Chip Rev. for Yukon-EC A1/A0 */
+	CHIP_REV_YU_EC_A2    = 1,  /* Chip Rev. for Yukon-EC A2 */
+	CHIP_REV_YU_EC_A3    = 2,  /* Chip Rev. for Yukon-EC A3 */
+};
+enum yukon_ec_u_rev {
+	CHIP_REV_YU_EC_U_A0  = 1,
+	CHIP_REV_YU_EC_U_A1  = 2,
+	CHIP_REV_YU_EC_U_B0  = 3,
+};
+enum yukon_fe_rev {
+	CHIP_REV_YU_FE_A1    = 1,
+	CHIP_REV_YU_FE_A2    = 2,
+};
+enum yukon_fe_p_rev {
+	CHIP_REV_YU_FE2_A0   = 0,
+};
+enum yukon_ex_rev {
+	CHIP_REV_YU_EX_A0    = 1,
+	CHIP_REV_YU_EX_B0    = 2,
+};
+enum yukon_supr_rev {
+	CHIP_REV_YU_SU_A0    = 0,
+};
+
+
+/*	B2_Y2_CLK_GATE	 8 bit	Clock Gating (Yukon-2 only) */
+enum {
+	Y2_STATUS_LNK2_INAC	= 1<<7, /* Status Link 2 inactive (0 = active) */
+	Y2_CLK_GAT_LNK2_DIS	= 1<<6, /* Disable clock gating Link 2 */
+	Y2_COR_CLK_LNK2_DIS	= 1<<5, /* Disable Core clock Link 2 */
+	Y2_PCI_CLK_LNK2_DIS	= 1<<4, /* Disable PCI clock Link 2 */
+	Y2_STATUS_LNK1_INAC	= 1<<3, /* Status Link 1 inactive (0 = active) */
+	Y2_CLK_GAT_LNK1_DIS	= 1<<2, /* Disable clock gating Link 1 */
+	Y2_COR_CLK_LNK1_DIS	= 1<<1, /* Disable Core clock Link 1 */
+	Y2_PCI_CLK_LNK1_DIS	= 1<<0, /* Disable PCI clock Link 1 */
+};
+
+/*	B2_Y2_HW_RES	8 bit	HW Resources (Yukon-2 only) */
+enum {
+	CFG_LED_MODE_MSK	= 7<<2,	/* Bit  4.. 2:	LED Mode Mask */
+	CFG_LINK_2_AVAIL	= 1<<1,	/* Link 2 available */
+	CFG_LINK_1_AVAIL	= 1<<0,	/* Link 1 available */
+};
+#define CFG_LED_MODE(x)		(((x) & CFG_LED_MODE_MSK) >> 2)
+#define CFG_DUAL_MAC_MSK	(CFG_LINK_2_AVAIL | CFG_LINK_1_AVAIL)
+
+
+/* B2_Y2_CLK_CTRL	32 bit	Clock Frequency Control Register (Yukon-2/EC) */
+enum {
+	Y2_CLK_DIV_VAL_MSK	= 0xff<<16,/* Bit 23..16: Clock Divisor Value */
+#define	Y2_CLK_DIV_VAL(x)	(((x)<<16) & Y2_CLK_DIV_VAL_MSK)
+	Y2_CLK_DIV_VAL2_MSK	= 7<<21,   /* Bit 23..21: Clock Divisor Value */
+	Y2_CLK_SELECT2_MSK	= 0x1f<<16,/* Bit 20..16: Clock Select */
+#define Y2_CLK_DIV_VAL_2(x)	(((x)<<21) & Y2_CLK_DIV_VAL2_MSK)
+#define Y2_CLK_SEL_VAL_2(x)	(((x)<<16) & Y2_CLK_SELECT2_MSK)
+	Y2_CLK_DIV_ENA		= 1<<1, /* Enable  Core Clock Division */
+	Y2_CLK_DIV_DIS		= 1<<0,	/* Disable Core Clock Division */
+};
+
+/*	B2_TI_CTRL		 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+enum {
+	TIM_START	= 1<<2,	/* Start Timer */
+	TIM_STOP	= 1<<1,	/* Stop  Timer */
+	TIM_CLR_IRQ	= 1<<0,	/* Clear Timer IRQ (!IRQM) */
+};
+
+/*	B2_TI_TEST		 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST		 8 bit	Descriptor Poll Timer Test Reg */
+enum {
+	TIM_T_ON	= 1<<2,	/* Test mode on */
+	TIM_T_OFF	= 1<<1,	/* Test mode off */
+	TIM_T_STEP	= 1<<0,	/* Test step */
+};
+
+/*	B3_RAM_ADDR		32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+/* RAM Interface Registers */
+
+/*	B3_RI_CTRL		16 bit	RAM Interface Control Register */
+enum {
+	RI_CLR_RD_PERR	= 1<<9,	/* Clear IRQ RAM Read Parity Err */
+	RI_CLR_WR_PERR	= 1<<8,	/* Clear IRQ RAM Write Parity Err*/
+
+	RI_RST_CLR	= 1<<1,	/* Clear RAM Interface Reset */
+	RI_RST_SET	= 1<<0,	/* Set   RAM Interface Reset */
+};
+
+#define SK_RI_TO_53	36		/* RAM interface timeout */
+
+
+/* Port related registers FIFO, and Arbiter */
+#define SK_REG(port,reg)	(((port)<<7)+(reg))
+
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
+/*	TXA_ITI_INI		32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL		32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI		32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL		32 bit	Tx Arb Limit Counter Value */
+
+#define TXA_MAX_VAL	0x00ffffffUL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL		 8 bit	Tx Arbiter Control Register */
+enum {
+	TXA_ENA_FSYNC	= 1<<7,	/* Enable  force of sync Tx queue */
+	TXA_DIS_FSYNC	= 1<<6,	/* Disable force of sync Tx queue */
+	TXA_ENA_ALLOC	= 1<<5,	/* Enable  alloc of free bandwidth */
+	TXA_DIS_ALLOC	= 1<<4,	/* Disable alloc of free bandwidth */
+	TXA_START_RC	= 1<<3,	/* Start sync Rate Control */
+	TXA_STOP_RC	= 1<<2,	/* Stop  sync Rate Control */
+	TXA_ENA_ARB	= 1<<1,	/* Enable  Tx Arbiter */
+	TXA_DIS_ARB	= 1<<0,	/* Disable Tx Arbiter */
+};
+
+/*
+ *	Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
+enum {
+	TXA_ITI_INI	= 0x0200,/* 32 bit	Tx Arb Interval Timer Init Val*/
+	TXA_ITI_VAL	= 0x0204,/* 32 bit	Tx Arb Interval Timer Value */
+	TXA_LIM_INI	= 0x0208,/* 32 bit	Tx Arb Limit Counter Init Val */
+	TXA_LIM_VAL	= 0x020c,/* 32 bit	Tx Arb Limit Counter Value */
+	TXA_CTRL	= 0x0210,/*  8 bit	Tx Arbiter Control Register */
+	TXA_TEST	= 0x0211,/*  8 bit	Tx Arbiter Test Register */
+	TXA_STAT	= 0x0212,/*  8 bit	Tx Arbiter Status Register */
+};
+
+
+enum {
+	B6_EXT_REG	= 0x0300,/* External registers (GENESIS only) */
+	B7_CFG_SPC	= 0x0380,/* copy of the Configuration register */
+	B8_RQ1_REGS	= 0x0400,/* Receive Queue 1 */
+	B8_RQ2_REGS	= 0x0480,/* Receive Queue 2 */
+	B8_TS1_REGS	= 0x0600,/* Transmit sync queue 1 */
+	B8_TA1_REGS	= 0x0680,/* Transmit async queue 1 */
+	B8_TS2_REGS	= 0x0700,/* Transmit sync queue 2 */
+	B8_TA2_REGS	= 0x0780,/* Transmit sync queue 2 */
+	B16_RAM_REGS	= 0x0800,/* RAM Buffer Registers */
+};
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+enum {
+	B8_Q_REGS = 0x0400, /* base of Queue registers */
+	Q_D	= 0x00,	/* 8*32	bit	Current Descriptor */
+	Q_VLAN  = 0x20, /* 16 bit	Current VLAN Tag */
+	Q_DONE	= 0x24,	/* 16 bit	Done Index */
+	Q_AC_L	= 0x28,	/* 32 bit	Current Address Counter Low dWord */
+	Q_AC_H	= 0x2c,	/* 32 bit	Current Address Counter High dWord */
+	Q_BC	= 0x30,	/* 32 bit	Current Byte Counter */
+	Q_CSR	= 0x34,	/* 32 bit	BMU Control/Status Register */
+	Q_TEST	= 0x38,	/* 32 bit	Test/Control Register */
+
+/* Yukon-2 */
+	Q_WM	= 0x40,	/* 16 bit	FIFO Watermark */
+	Q_AL	= 0x42,	/*  8 bit	FIFO Alignment */
+	Q_RSP	= 0x44,	/* 16 bit	FIFO Read Shadow Pointer */
+	Q_RSL	= 0x46,	/*  8 bit	FIFO Read Shadow Level */
+	Q_RP	= 0x48,	/*  8 bit	FIFO Read Pointer */
+	Q_RL	= 0x4a,	/*  8 bit	FIFO Read Level */
+	Q_WP	= 0x4c,	/*  8 bit	FIFO Write Pointer */
+	Q_WSP	= 0x4d,	/*  8 bit	FIFO Write Shadow Pointer */
+	Q_WL	= 0x4e,	/*  8 bit	FIFO Write Level */
+	Q_WSL	= 0x4f,	/*  8 bit	FIFO Write Shadow Level */
+};
+#define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
+
+/*	Q_TEST				32 bit	Test Register */
+enum {
+	/* Transmit */
+	F_TX_CHK_AUTO_OFF = 1<<31, /* Tx checksum auto calc off (Yukon EX) */
+	F_TX_CHK_AUTO_ON  = 1<<30, /* Tx checksum auto calc off (Yukon EX) */
+
+	/* Receive */
+	F_M_RX_RAM_DIS	= 1<<24, /* MAC Rx RAM Read Port disable */
+
+	/* Hardware testbits not used */
+};
+
+/* Queue Prefetch Unit Offsets, use Y2_QADDR() to address (Yukon-2 only)*/
+enum {
+	Y2_B8_PREF_REGS		= 0x0450,
+
+	PREF_UNIT_CTRL		= 0x00,	/* 32 bit	Control register */
+	PREF_UNIT_LAST_IDX	= 0x04,	/* 16 bit	Last Index */
+	PREF_UNIT_ADDR_LO	= 0x08,	/* 32 bit	List start addr, low part */
+	PREF_UNIT_ADDR_HI	= 0x0c,	/* 32 bit	List start addr, high part*/
+	PREF_UNIT_GET_IDX	= 0x10,	/* 16 bit	Get Index */
+	PREF_UNIT_PUT_IDX	= 0x14,	/* 16 bit	Put Index */
+	PREF_UNIT_FIFO_WP	= 0x20,	/*  8 bit	FIFO write pointer */
+	PREF_UNIT_FIFO_RP	= 0x24,	/*  8 bit	FIFO read pointer */
+	PREF_UNIT_FIFO_WM	= 0x28,	/*  8 bit	FIFO watermark */
+	PREF_UNIT_FIFO_LEV	= 0x2c,	/*  8 bit	FIFO level */
+
+	PREF_UNIT_MASK_IDX	= 0x0fff,
+};
+#define Y2_QADDR(q,reg)		(Y2_B8_PREF_REGS + (q) + (reg))
+
+/* RAM Buffer Register Offsets */
+enum {
+
+	RB_START	= 0x00,/* 32 bit	RAM Buffer Start Address */
+	RB_END	= 0x04,/* 32 bit	RAM Buffer End Address */
+	RB_WP	= 0x08,/* 32 bit	RAM Buffer Write Pointer */
+	RB_RP	= 0x0c,/* 32 bit	RAM Buffer Read Pointer */
+	RB_RX_UTPP	= 0x10,/* 32 bit	Rx Upper Threshold, Pause Packet */
+	RB_RX_LTPP	= 0x14,/* 32 bit	Rx Lower Threshold, Pause Packet */
+	RB_RX_UTHP	= 0x18,/* 32 bit	Rx Upper Threshold, High Prio */
+	RB_RX_LTHP	= 0x1c,/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+	RB_PC	= 0x20,/* 32 bit	RAM Buffer Packet Counter */
+	RB_LEV	= 0x24,/* 32 bit	RAM Buffer Level Register */
+	RB_CTRL	= 0x28,/* 32 bit	RAM Buffer Control Register */
+	RB_TST1	= 0x29,/*  8 bit	RAM Buffer Test Register 1 */
+	RB_TST2	= 0x2a,/*  8 bit	RAM Buffer Test Register 2 */
+};
+
+/* Receive and Transmit Queues */
+enum {
+	Q_R1	= 0x0000,	/* Receive Queue 1 */
+	Q_R2	= 0x0080,	/* Receive Queue 2 */
+	Q_XS1	= 0x0200,	/* Synchronous Transmit Queue 1 */
+	Q_XA1	= 0x0280,	/* Asynchronous Transmit Queue 1 */
+	Q_XS2	= 0x0300,	/* Synchronous Transmit Queue 2 */
+	Q_XA2	= 0x0380,	/* Asynchronous Transmit Queue 2 */
+};
+
+/* Different PHY Types */
+enum {
+	PHY_ADDR_MARV	= 0,
+};
+
+#define RB_ADDR(offs, queue) ((u16) B16_RAM_REGS + (queue) + (offs))
+
+
+enum {
+	LNK_SYNC_INI	= 0x0c30,/* 32 bit	Link Sync Cnt Init Value */
+	LNK_SYNC_VAL	= 0x0c34,/* 32 bit	Link Sync Cnt Current Value */
+	LNK_SYNC_CTRL	= 0x0c38,/*  8 bit	Link Sync Cnt Control Register */
+	LNK_SYNC_TST	= 0x0c39,/*  8 bit	Link Sync Cnt Test Register */
+
+	LNK_LED_REG	= 0x0c3c,/*  8 bit	Link LED Register */
+
+/* Receive GMAC FIFO (YUKON and Yukon-2) */
+
+	RX_GMF_EA	= 0x0c40,/* 32 bit	Rx GMAC FIFO End Address */
+	RX_GMF_AF_THR	= 0x0c44,/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+	RX_GMF_CTRL_T	= 0x0c48,/* 32 bit	Rx GMAC FIFO Control/Test */
+	RX_GMF_FL_MSK	= 0x0c4c,/* 32 bit	Rx GMAC FIFO Flush Mask */
+	RX_GMF_FL_THR	= 0x0c50,/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	RX_GMF_TR_THR	= 0x0c54,/* 32 bit	Rx Truncation Threshold (Yukon-2) */
+	RX_GMF_UP_THR	= 0x0c58,/*  8 bit	Rx Upper Pause Thr (Yukon-EC_U) */
+	RX_GMF_LP_THR	= 0x0c5a,/*  8 bit	Rx Lower Pause Thr (Yukon-EC_U) */
+	RX_GMF_VLAN	= 0x0c5c,/* 32 bit	Rx VLAN Type Register (Yukon-2) */
+	RX_GMF_WP	= 0x0c60,/* 32 bit	Rx GMAC FIFO Write Pointer */
+
+	RX_GMF_WLEV	= 0x0c68,/* 32 bit	Rx GMAC FIFO Write Level */
+
+	RX_GMF_RP	= 0x0c70,/* 32 bit	Rx GMAC FIFO Read Pointer */
+
+	RX_GMF_RLEV	= 0x0c78,/* 32 bit	Rx GMAC FIFO Read Level */
+};
+
+
+/*	Q_BC			32 bit	Current Byte Counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR		32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR		32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR			32 bit	BMU Control/Status Register */
+
+/* Rx BMU Control / Status Registers (Yukon-2) */
+enum {
+	BMU_IDLE	= 1<<31, /* BMU Idle State */
+	BMU_RX_TCP_PKT	= 1<<30, /* Rx TCP Packet (when RSS Hash enabled) */
+	BMU_RX_IP_PKT	= 1<<29, /* Rx IP  Packet (when RSS Hash enabled) */
+
+	BMU_ENA_RX_RSS_HASH = 1<<15, /* Enable  Rx RSS Hash */
+	BMU_DIS_RX_RSS_HASH = 1<<14, /* Disable Rx RSS Hash */
+	BMU_ENA_RX_CHKSUM = 1<<13, /* Enable  Rx TCP/IP Checksum Check */
+	BMU_DIS_RX_CHKSUM = 1<<12, /* Disable Rx TCP/IP Checksum Check */
+	BMU_CLR_IRQ_PAR	= 1<<11, /* Clear IRQ on Parity errors (Rx) */
+	BMU_CLR_IRQ_TCP	= 1<<11, /* Clear IRQ on TCP segment. error (Tx) */
+	BMU_CLR_IRQ_CHK	= 1<<10, /* Clear IRQ Check */
+	BMU_STOP	= 1<<9, /* Stop  Rx/Tx Queue */
+	BMU_START	= 1<<8, /* Start Rx/Tx Queue */
+	BMU_FIFO_OP_ON	= 1<<7, /* FIFO Operational On */
+	BMU_FIFO_OP_OFF	= 1<<6, /* FIFO Operational Off */
+	BMU_FIFO_ENA	= 1<<5, /* Enable FIFO */
+	BMU_FIFO_RST	= 1<<4, /* Reset  FIFO */
+	BMU_OP_ON	= 1<<3, /* BMU Operational On */
+	BMU_OP_OFF	= 1<<2, /* BMU Operational Off */
+	BMU_RST_CLR	= 1<<1, /* Clear BMU Reset (Enable) */
+	BMU_RST_SET	= 1<<0, /* Set   BMU Reset */
+
+	BMU_CLR_RESET	= BMU_FIFO_RST | BMU_OP_OFF | BMU_RST_CLR,
+	BMU_OPER_INIT	= BMU_CLR_IRQ_PAR | BMU_CLR_IRQ_CHK | BMU_START |
+			  BMU_FIFO_ENA | BMU_OP_ON,
+
+	BMU_WM_DEFAULT = 0x600,
+	BMU_WM_PEX     = 0x80,
+};
+
+/* Tx BMU Control / Status Registers (Yukon-2) */
+								/* Bit 31: same as for Rx */
+enum {
+	BMU_TX_IPIDINCR_ON	= 1<<13, /* Enable  IP ID Increment */
+	BMU_TX_IPIDINCR_OFF	= 1<<12, /* Disable IP ID Increment */
+	BMU_TX_CLR_IRQ_TCP	= 1<<11, /* Clear IRQ on TCP segment length mismatch */
+};
+
+/* Queue Prefetch Unit Offsets, use Y2_QADDR() to address (Yukon-2 only)*/
+/* PREF_UNIT_CTRL	32 bit	Prefetch Control register */
+enum {
+	PREF_UNIT_OP_ON		= 1<<3,	/* prefetch unit operational */
+	PREF_UNIT_OP_OFF	= 1<<2,	/* prefetch unit not operational */
+	PREF_UNIT_RST_CLR	= 1<<1,	/* Clear Prefetch Unit Reset */
+	PREF_UNIT_RST_SET	= 1<<0,	/* Set   Prefetch Unit Reset */
+};
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*	RB_START		32 bit	RAM Buffer Start Address */
+/*	RB_END			32 bit	RAM Buffer End Address */
+/*	RB_WP			32 bit	RAM Buffer Write Pointer */
+/*	RB_RP			32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP		32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP		32 bit	Rx Lower Threshold, Pause Pack */
+/*	RB_RX_UTHP		32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP		32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC			32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV			32 bit	RAM Buffer Level Register */
+
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+enum {
+	RB_ENA_STFWD	= 1<<5,	/* Enable  Store & Forward */
+	RB_DIS_STFWD	= 1<<4,	/* Disable Store & Forward */
+	RB_ENA_OP_MD	= 1<<3,	/* Enable  Operation Mode */
+	RB_DIS_OP_MD	= 1<<2,	/* Disable Operation Mode */
+	RB_RST_CLR	= 1<<1,	/* Clear RAM Buf STM Reset */
+	RB_RST_SET	= 1<<0,	/* Set   RAM Buf STM Reset */
+};
+
+
+/* Transmit GMAC FIFO (YUKON only) */
+enum {
+	TX_GMF_EA	= 0x0d40,/* 32 bit	Tx GMAC FIFO End Address */
+	TX_GMF_AE_THR	= 0x0d44,/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+	TX_GMF_CTRL_T	= 0x0d48,/* 32 bit	Tx GMAC FIFO Control/Test */
+
+	TX_GMF_WP	= 0x0d60,/* 32 bit 	Tx GMAC FIFO Write Pointer */
+	TX_GMF_WSP	= 0x0d64,/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+	TX_GMF_WLEV	= 0x0d68,/* 32 bit 	Tx GMAC FIFO Write Level */
+
+	TX_GMF_RP	= 0x0d70,/* 32 bit 	Tx GMAC FIFO Read Pointer */
+	TX_GMF_RSTP	= 0x0d74,/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+	TX_GMF_RLEV	= 0x0d78,/* 32 bit 	Tx GMAC FIFO Read Level */
+
+	/* Threshold values for Yukon-EC Ultra and Extreme */
+	ECU_AE_THR	= 0x0070, /* Almost Empty Threshold */
+	ECU_TXFF_LEV	= 0x01a0, /* Tx BMU FIFO Level */
+	ECU_JUMBO_WM	= 0x0080, /* Jumbo Mode Watermark */
+};
+
+/* Descriptor Poll Timer Registers */
+enum {
+	B28_DPT_INI	= 0x0e00,/* 24 bit	Descriptor Poll Timer Init Val */
+	B28_DPT_VAL	= 0x0e04,/* 24 bit	Descriptor Poll Timer Curr Val */
+	B28_DPT_CTRL	= 0x0e08,/*  8 bit	Descriptor Poll Timer Ctrl Reg */
+
+	B28_DPT_TST	= 0x0e0a,/*  8 bit	Descriptor Poll Timer Test Reg */
+};
+
+/* Time Stamp Timer Registers (YUKON only) */
+enum {
+	GMAC_TI_ST_VAL	= 0x0e14,/* 32 bit	Time Stamp Timer Curr Val */
+	GMAC_TI_ST_CTRL	= 0x0e18,/*  8 bit	Time Stamp Timer Ctrl Reg */
+	GMAC_TI_ST_TST	= 0x0e1a,/*  8 bit	Time Stamp Timer Test Reg */
+};
+
+/* Polling Unit Registers (Yukon-2 only) */
+enum {
+	POLL_CTRL	= 0x0e20, /* 32 bit	Polling Unit Control Reg */
+	POLL_LAST_IDX	= 0x0e24,/* 16 bit	Polling Unit List Last Index */
+
+	POLL_LIST_ADDR_LO= 0x0e28,/* 32 bit	Poll. List Start Addr (low) */
+	POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit	Poll. List Start Addr (high) */
+};
+
+enum {
+	SMB_CFG		 = 0x0e40, /* 32 bit	SMBus Config Register */
+	SMB_CSR		 = 0x0e44, /* 32 bit	SMBus Control/Status Register */
+};
+
+enum {
+	CPU_WDOG	 = 0x0e48, /* 32 bit	Watchdog Register  */
+	CPU_CNTR	 = 0x0e4C, /* 32 bit	Counter Register  */
+	CPU_TIM		 = 0x0e50,/* 32 bit	Timer Compare Register  */
+	CPU_AHB_ADDR	 = 0x0e54, /* 32 bit	CPU AHB Debug  Register  */
+	CPU_AHB_WDATA	 = 0x0e58, /* 32 bit	CPU AHB Debug  Register  */
+	CPU_AHB_RDATA	 = 0x0e5C, /* 32 bit	CPU AHB Debug  Register  */
+	HCU_MAP_BASE	 = 0x0e60, /* 32 bit	Reset Mapping Base */
+	CPU_AHB_CTRL	 = 0x0e64, /* 32 bit	CPU AHB Debug  Register  */
+	HCU_CCSR	 = 0x0e68, /* 32 bit	CPU Control and Status Register */
+	HCU_HCSR	 = 0x0e6C, /* 32 bit	Host Control and Status Register */
+};
+
+/* ASF Subsystem Registers (Yukon-2 only) */
+enum {
+	B28_Y2_SMB_CONFIG  = 0x0e40,/* 32 bit	ASF SMBus Config Register */
+	B28_Y2_SMB_CSD_REG = 0x0e44,/* 32 bit	ASF SMB Control/Status/Data */
+	B28_Y2_ASF_IRQ_V_BASE=0x0e60,/* 32 bit	ASF IRQ Vector Base */
+
+	B28_Y2_ASF_STAT_CMD= 0x0e68,/* 32 bit	ASF Status and Command Reg */
+	B28_Y2_ASF_HOST_COM= 0x0e6c,/* 32 bit	ASF Host Communication Reg */
+	B28_Y2_DATA_REG_1  = 0x0e70,/* 32 bit	ASF/Host Data Register 1 */
+	B28_Y2_DATA_REG_2  = 0x0e74,/* 32 bit	ASF/Host Data Register 2 */
+	B28_Y2_DATA_REG_3  = 0x0e78,/* 32 bit	ASF/Host Data Register 3 */
+	B28_Y2_DATA_REG_4  = 0x0e7c,/* 32 bit	ASF/Host Data Register 4 */
+};
+
+/* Status BMU Registers (Yukon-2 only)*/
+enum {
+	STAT_CTRL	= 0x0e80,/* 32 bit	Status BMU Control Reg */
+	STAT_LAST_IDX	= 0x0e84,/* 16 bit	Status BMU Last Index */
+
+	STAT_LIST_ADDR_LO= 0x0e88,/* 32 bit	Status List Start Addr (low) */
+	STAT_LIST_ADDR_HI= 0x0e8c,/* 32 bit	Status List Start Addr (high) */
+	STAT_TXA1_RIDX	= 0x0e90,/* 16 bit	Status TxA1 Report Index Reg */
+	STAT_TXS1_RIDX	= 0x0e92,/* 16 bit	Status TxS1 Report Index Reg */
+	STAT_TXA2_RIDX	= 0x0e94,/* 16 bit	Status TxA2 Report Index Reg */
+	STAT_TXS2_RIDX	= 0x0e96,/* 16 bit	Status TxS2 Report Index Reg */
+	STAT_TX_IDX_TH	= 0x0e98,/* 16 bit	Status Tx Index Threshold Reg */
+	STAT_PUT_IDX	= 0x0e9c,/* 16 bit	Status Put Index Reg */
+
+/* FIFO Control/Status Registers (Yukon-2 only)*/
+	STAT_FIFO_WP	= 0x0ea0,/*  8 bit	Status FIFO Write Pointer Reg */
+	STAT_FIFO_RP	= 0x0ea4,/*  8 bit	Status FIFO Read Pointer Reg */
+	STAT_FIFO_RSP	= 0x0ea6,/*  8 bit	Status FIFO Read Shadow Ptr */
+	STAT_FIFO_LEVEL	= 0x0ea8,/*  8 bit	Status FIFO Level Reg */
+	STAT_FIFO_SHLVL	= 0x0eaa,/*  8 bit	Status FIFO Shadow Level Reg */
+	STAT_FIFO_WM	= 0x0eac,/*  8 bit	Status FIFO Watermark Reg */
+	STAT_FIFO_ISR_WM= 0x0ead,/*  8 bit	Status FIFO ISR Watermark Reg */
+
+/* Level and ISR Timer Registers (Yukon-2 only)*/
+	STAT_LEV_TIMER_INI= 0x0eb0,/* 32 bit	Level Timer Init. Value Reg */
+	STAT_LEV_TIMER_CNT= 0x0eb4,/* 32 bit	Level Timer Counter Reg */
+	STAT_LEV_TIMER_CTRL= 0x0eb8,/*  8 bit	Level Timer Control Reg */
+	STAT_LEV_TIMER_TEST= 0x0eb9,/*  8 bit	Level Timer Test Reg */
+	STAT_TX_TIMER_INI  = 0x0ec0,/* 32 bit	Tx Timer Init. Value Reg */
+	STAT_TX_TIMER_CNT  = 0x0ec4,/* 32 bit	Tx Timer Counter Reg */
+	STAT_TX_TIMER_CTRL = 0x0ec8,/*  8 bit	Tx Timer Control Reg */
+	STAT_TX_TIMER_TEST = 0x0ec9,/*  8 bit	Tx Timer Test Reg */
+	STAT_ISR_TIMER_INI = 0x0ed0,/* 32 bit	ISR Timer Init. Value Reg */
+	STAT_ISR_TIMER_CNT = 0x0ed4,/* 32 bit	ISR Timer Counter Reg */
+	STAT_ISR_TIMER_CTRL= 0x0ed8,/*  8 bit	ISR Timer Control Reg */
+	STAT_ISR_TIMER_TEST= 0x0ed9,/*  8 bit	ISR Timer Test Reg */
+};
+
+enum {
+	LINKLED_OFF 	     = 0x01,
+	LINKLED_ON  	     = 0x02,
+	LINKLED_LINKSYNC_OFF = 0x04,
+	LINKLED_LINKSYNC_ON  = 0x08,
+	LINKLED_BLINK_OFF    = 0x10,
+	LINKLED_BLINK_ON     = 0x20,
+};
+
+/* GMAC and GPHY Control Registers (YUKON only) */
+enum {
+	GMAC_CTRL	= 0x0f00,/* 32 bit	GMAC Control Reg */
+	GPHY_CTRL	= 0x0f04,/* 32 bit	GPHY Control Reg */
+	GMAC_IRQ_SRC	= 0x0f08,/*  8 bit	GMAC Interrupt Source Reg */
+	GMAC_IRQ_MSK	= 0x0f0c,/*  8 bit	GMAC Interrupt Mask Reg */
+	GMAC_LINK_CTRL	= 0x0f10,/* 16 bit	Link Control Reg */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+	WOL_CTRL_STAT	= 0x0f20,/* 16 bit	WOL Control/Status Reg */
+	WOL_MATCH_CTL	= 0x0f22,/*  8 bit	WOL Match Control Reg */
+	WOL_MATCH_RES	= 0x0f23,/*  8 bit	WOL Match Result Reg */
+	WOL_MAC_ADDR	= 0x0f24,/* 32 bit	WOL MAC Address */
+	WOL_PATT_RPTR	= 0x0f2c,/*  8 bit	WOL Pattern Read Pointer */
+
+/* WOL Pattern Length Registers (YUKON only) */
+	WOL_PATT_LEN_LO	= 0x0f30,/* 32 bit	WOL Pattern Length 3..0 */
+	WOL_PATT_LEN_HI	= 0x0f34,/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+	WOL_PATT_CNT_0	= 0x0f38,/* 32 bit	WOL Pattern Counter 3..0 */
+	WOL_PATT_CNT_4	= 0x0f3c,/* 24 bit	WOL Pattern Counter 6..4 */
+};
+#define WOL_REGS(port, x)	(x + (port)*0x80)
+
+enum {
+	WOL_PATT_RAM_1	= 0x1000,/*  WOL Pattern RAM Link 1 */
+	WOL_PATT_RAM_2	= 0x1400,/*  WOL Pattern RAM Link 2 */
+};
+#define WOL_PATT_RAM_BASE(port)	(WOL_PATT_RAM_1 + (port)*0x400)
+
+enum {
+	BASE_GMAC_1	= 0x2800,/* GMAC 1 registers */
+	BASE_GMAC_2	= 0x3800,/* GMAC 2 registers */
+};
+
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+enum {
+	PHY_MARV_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_MARV_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_MARV_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_MARV_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_MARV_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_MARV_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_MARV_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_MARV_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_MARV_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Marvel-specific registers */
+	PHY_MARV_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_MARV_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_MARV_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_MARV_PHY_CTRL	= 0x10,/* 16 bit r/w	PHY Specific Ctrl Reg */
+	PHY_MARV_PHY_STAT	= 0x11,/* 16 bit r/o	PHY Specific Stat Reg */
+	PHY_MARV_INT_MASK	= 0x12,/* 16 bit r/w	Interrupt Mask Reg */
+	PHY_MARV_INT_STAT	= 0x13,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_MARV_EXT_CTRL	= 0x14,/* 16 bit r/w	Ext. PHY Specific Ctrl */
+	PHY_MARV_RXE_CNT	= 0x15,/* 16 bit r/w	Receive Error Counter */
+	PHY_MARV_EXT_ADR	= 0x16,/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	PHY_MARV_PORT_IRQ	= 0x17,/* 16 bit r/o	Port 0 IRQ (88E1111 only) */
+	PHY_MARV_LED_CTRL	= 0x18,/* 16 bit r/w	LED Control Reg */
+	PHY_MARV_LED_OVER	= 0x19,/* 16 bit r/w	Manual LED Override Reg */
+	PHY_MARV_EXT_CTRL_2	= 0x1a,/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+	PHY_MARV_EXT_P_STAT	= 0x1b,/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+	PHY_MARV_CABLE_DIAG	= 0x1c,/* 16 bit r/o	Cable Diagnostic Reg */
+	PHY_MARV_PAGE_ADDR	= 0x1d,/* 16 bit r/w	Extended Page Address Reg */
+	PHY_MARV_PAGE_DATA	= 0x1e,/* 16 bit r/w	Extended Page Data Reg */
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+	PHY_MARV_FE_LED_PAR	= 0x16,/* 16 bit r/w	LED Parallel Select Reg. */
+	PHY_MARV_FE_LED_SER	= 0x17,/* 16 bit r/w	LED Stream Select S. LED */
+	PHY_MARV_FE_VCT_TX	= 0x1a,/* 16 bit r/w	VCT Reg. for TXP/N Pins */
+	PHY_MARV_FE_VCT_RX	= 0x1b,/* 16 bit r/o	VCT Reg. for RXP/N Pins */
+	PHY_MARV_FE_SPEC_2	= 0x1c,/* 16 bit r/w	Specific Control Reg. 2 */
+};
+
+enum {
+	PHY_CT_RESET	= 1<<15, /* Bit 15: (sc)	clear all PHY related regs */
+	PHY_CT_LOOP	= 1<<14, /* Bit 14:	enable Loopback over PHY */
+	PHY_CT_SPS_LSB	= 1<<13, /* Bit 13:	Speed select, lower bit */
+	PHY_CT_ANE	= 1<<12, /* Bit 12:	Auto-Negotiation Enabled */
+	PHY_CT_PDOWN	= 1<<11, /* Bit 11:	Power Down Mode */
+	PHY_CT_ISOL	= 1<<10, /* Bit 10:	Isolate Mode */
+	PHY_CT_RE_CFG	= 1<<9, /* Bit  9:	(sc) Restart Auto-Negotiation */
+	PHY_CT_DUP_MD	= 1<<8, /* Bit  8:	Duplex Mode */
+	PHY_CT_COL_TST	= 1<<7, /* Bit  7:	Collision Test enabled */
+	PHY_CT_SPS_MSB	= 1<<6, /* Bit  6:	Speed select, upper bit */
+};
+
+enum {
+	PHY_CT_SP1000	= PHY_CT_SPS_MSB, /* enable speed of 1000 Mbps */
+	PHY_CT_SP100	= PHY_CT_SPS_LSB, /* enable speed of  100 Mbps */
+	PHY_CT_SP10	= 0,		  /* enable speed of   10 Mbps */
+};
+
+enum {
+	PHY_ST_EXT_ST	= 1<<8, /* Bit  8:	Extended Status Present */
+
+	PHY_ST_PRE_SUP	= 1<<6, /* Bit  6:	Preamble Suppression */
+	PHY_ST_AN_OVER	= 1<<5, /* Bit  5:	Auto-Negotiation Over */
+	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occured */
+	PHY_ST_AN_CAP	= 1<<3, /* Bit  3:	Auto-Negotiation Capability */
+	PHY_ST_LSYNC	= 1<<2, /* Bit  2:	Link Synchronized */
+	PHY_ST_JAB_DET	= 1<<1, /* Bit  1:	Jabber Detected */
+	PHY_ST_EXT_REG	= 1<<0, /* Bit  0:	Extended Register available */
+};
+
+enum {
+	PHY_I1_OUI_MSK	= 0x3f<<10, /* Bit 15..10:	Organization Unique ID */
+	PHY_I1_MOD_NUM	= 0x3f<<4, /* Bit  9.. 4:	Model Number */
+	PHY_I1_REV_MSK	= 0xf, /* Bit  3.. 0:	Revision Number */
+};
+
+/* different Marvell PHY Ids */
+enum {
+	PHY_MARV_ID0_VAL= 0x0141, /* Marvell Unique Identifier */
+
+	PHY_BCOM_ID1_A1	= 0x6041,
+	PHY_BCOM_ID1_B2	= 0x6043,
+	PHY_BCOM_ID1_C0	= 0x6044,
+	PHY_BCOM_ID1_C5	= 0x6047,
+
+	PHY_MARV_ID1_B0	= 0x0C23, /* Yukon 	(PHY 88E1011) */
+	PHY_MARV_ID1_B2	= 0x0C25, /* Yukon-Plus (PHY 88E1011) */
+	PHY_MARV_ID1_C2	= 0x0CC2, /* Yukon-EC	(PHY 88E1111) */
+	PHY_MARV_ID1_Y2	= 0x0C91, /* Yukon-2	(PHY 88E1112) */
+	PHY_MARV_ID1_FE = 0x0C83, /* Yukon-FE   (PHY 88E3082 Rev.A1) */
+	PHY_MARV_ID1_ECU= 0x0CB0, /* Yukon-ECU  (PHY 88E1149 Rev.B2?) */
+};
+
+/* Advertisement register bits */
+enum {
+	PHY_AN_NXT_PG	= 1<<15, /* Bit 15:	Request Next Page */
+	PHY_AN_ACK	= 1<<14, /* Bit 14:	(ro) Acknowledge Received */
+	PHY_AN_RF	= 1<<13, /* Bit 13:	Remote Fault Bits */
+
+	PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11:	Try for asymmetric */
+	PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10:	Try for pause */
+	PHY_AN_100BASE4	= 1<<9, /* Bit 9:	Try for 100mbps 4k packets */
+	PHY_AN_100FULL	= 1<<8, /* Bit 8:	Try for 100mbps full-duplex */
+	PHY_AN_100HALF	= 1<<7, /* Bit 7:	Try for 100mbps half-duplex */
+	PHY_AN_10FULL	= 1<<6, /* Bit 6:	Try for 10mbps full-duplex */
+	PHY_AN_10HALF	= 1<<5, /* Bit 5:	Try for 10mbps half-duplex */
+	PHY_AN_CSMA	= 1<<0, /* Bit 0:	Only selector supported */
+	PHY_AN_SEL	= 0x1f, /* Bit 4..0:	Selector Field, 00001=Ethernet*/
+	PHY_AN_FULL	= PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA,
+	PHY_AN_ALL	= PHY_AN_10HALF | PHY_AN_10FULL |
+			  PHY_AN_100HALF | PHY_AN_100FULL,
+};
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+/*****  PHY_MARV_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+enum {
+	PHY_B_1000S_MSF	= 1<<15, /* Bit 15:	Master/Slave Fault */
+	PHY_B_1000S_MSR	= 1<<14, /* Bit 14:	Master/Slave Result */
+	PHY_B_1000S_LRS	= 1<<13, /* Bit 13:	Local Receiver Status */
+	PHY_B_1000S_RRS	= 1<<12, /* Bit 12:	Remote Receiver Status */
+	PHY_B_1000S_LP_FD	= 1<<11, /* Bit 11:	Link Partner can FD */
+	PHY_B_1000S_LP_HD	= 1<<10, /* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+	PHY_B_1000S_IEC	= 0xff, /* Bit  7..0:	Idle Error Count */
+};
+
+/** Marvell-Specific */
+enum {
+	PHY_M_AN_NXT_PG	= 1<<15, /* Request Next Page */
+	PHY_M_AN_ACK	= 1<<14, /* (ro)	Acknowledge Received */
+	PHY_M_AN_RF	= 1<<13, /* Remote Fault */
+
+	PHY_M_AN_ASP	= 1<<11, /* Asymmetric Pause */
+	PHY_M_AN_PC	= 1<<10, /* MAC Pause implemented */
+	PHY_M_AN_100_T4	= 1<<9, /* Not cap. 100Base-T4 (always 0) */
+	PHY_M_AN_100_FD	= 1<<8, /* Advertise 100Base-TX Full Duplex */
+	PHY_M_AN_100_HD	= 1<<7, /* Advertise 100Base-TX Half Duplex */
+	PHY_M_AN_10_FD	= 1<<6, /* Advertise 10Base-TX Full Duplex */
+	PHY_M_AN_10_HD	= 1<<5, /* Advertise 10Base-TX Half Duplex */
+	PHY_M_AN_SEL_MSK =0x1f<<4,	/* Bit  4.. 0: Selector Field Mask */
+};
+
+/* special defines for FIBER (88E1011S only) */
+enum {
+	PHY_M_AN_ASP_X	= 1<<8, /* Asymmetric Pause */
+	PHY_M_AN_PC_X	= 1<<7, /* MAC Pause implemented */
+	PHY_M_AN_1000X_AHD	= 1<<6, /* Advertise 10000Base-X Half Duplex */
+	PHY_M_AN_1000X_AFD	= 1<<5, /* Advertise 10000Base-X Full Duplex */
+};
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+enum {
+	PHY_M_P_NO_PAUSE_X	= 0<<7,/* Bit  8.. 7:	no Pause Mode */
+	PHY_M_P_SYM_MD_X	= 1<<7, /* Bit  8.. 7:	symmetric Pause Mode */
+	PHY_M_P_ASYM_MD_X	= 2<<7,/* Bit  8.. 7:	asymmetric Pause Mode */
+	PHY_M_P_BOTH_MD_X	= 3<<7,/* Bit  8.. 7:	both Pause Mode */
+};
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_M_1000C_TEST	= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_M_1000C_MSE	= 1<<12, /* Manual Master/Slave Enable */
+	PHY_M_1000C_MSC	= 1<<11, /* M/S Configuration (1=Master) */
+	PHY_M_1000C_MPD	= 1<<10, /* Multi-Port Device */
+	PHY_M_1000C_AFD	= 1<<9, /* Advertise Full Duplex */
+	PHY_M_1000C_AHD	= 1<<8, /* Advertise Half Duplex */
+};
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+enum {
+	PHY_M_PC_TX_FFD_MSK	= 3<<14,/* Bit 15..14: Tx FIFO Depth Mask */
+	PHY_M_PC_RX_FFD_MSK	= 3<<12,/* Bit 13..12: Rx FIFO Depth Mask */
+	PHY_M_PC_ASS_CRS_TX	= 1<<11, /* Assert CRS on Transmit */
+	PHY_M_PC_FL_GOOD	= 1<<10, /* Force Link Good */
+	PHY_M_PC_EN_DET_MSK	= 3<<8,/* Bit  9.. 8: Energy Detect Mask */
+	PHY_M_PC_ENA_EXT_D	= 1<<7, /* Enable Ext. Distance (10BT) */
+	PHY_M_PC_MDIX_MSK	= 3<<5,/* Bit  6.. 5: MDI/MDIX Config. Mask */
+	PHY_M_PC_DIS_125CLK	= 1<<4, /* Disable 125 CLK */
+	PHY_M_PC_MAC_POW_UP	= 1<<3, /* MAC Power up */
+	PHY_M_PC_SQE_T_ENA	= 1<<2, /* SQE Test Enabled */
+	PHY_M_PC_POL_R_DIS	= 1<<1, /* Polarity Reversal Disabled */
+	PHY_M_PC_DIS_JABBER	= 1<<0, /* Disable Jabber */
+};
+
+enum {
+	PHY_M_PC_EN_DET		= 2<<8,	/* Energy Detect (Mode 1) */
+	PHY_M_PC_EN_DET_PLUS	= 3<<8, /* Energy Detect Plus (Mode 2) */
+};
+
+#define PHY_M_PC_MDI_XMODE(x)	(((u16)(x)<<5) & PHY_M_PC_MDIX_MSK)
+
+enum {
+	PHY_M_PC_MAN_MDI	= 0, /* 00 = Manual MDI configuration */
+	PHY_M_PC_MAN_MDIX	= 1, /* 01 = Manual MDIX configuration */
+	PHY_M_PC_ENA_AUTO	= 3, /* 11 = Enable Automatic Crossover */
+};
+
+/* for Yukon-EC Ultra Gigabit Ethernet PHY (88E1149 only) */
+enum {
+	PHY_M_PC_COP_TX_DIS	= 1<<3, /* Copper Transmitter Disable */
+	PHY_M_PC_POW_D_ENA	= 1<<2,	/* Power Down Enable */
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PC_ENA_DTE_DT	= 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */
+	PHY_M_PC_ENA_ENE_DT	= 1<<14, /* Enable Energy Detect (sense & pulse) */
+	PHY_M_PC_DIS_NLP_CK	= 1<<13, /* Disable Normal Link Puls (NLP) Check */
+	PHY_M_PC_ENA_LIP_NP	= 1<<12, /* Enable Link Partner Next Page Reg. */
+	PHY_M_PC_DIS_NLP_GN	= 1<<11, /* Disable Normal Link Puls Generation */
+
+	PHY_M_PC_DIS_SCRAMB	= 1<<9, /* Disable Scrambler */
+	PHY_M_PC_DIS_FEFI	= 1<<8, /* Disable Far End Fault Indic. (FEFI) */
+
+	PHY_M_PC_SH_TP_SEL	= 1<<6, /* Shielded Twisted Pair Select */
+	PHY_M_PC_RX_FD_MSK	= 3<<2,/* Bit  3.. 2: Rx FIFO Depth Mask */
+};
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+enum {
+	PHY_M_PS_SPEED_MSK	= 3<<14, /* Bit 15..14: Speed Mask */
+	PHY_M_PS_SPEED_1000	= 1<<15, /*		10 = 1000 Mbps */
+	PHY_M_PS_SPEED_100	= 1<<14, /*		01 =  100 Mbps */
+	PHY_M_PS_SPEED_10	= 0,	 /*		00 =   10 Mbps */
+	PHY_M_PS_FULL_DUP	= 1<<13, /* Full Duplex */
+	PHY_M_PS_PAGE_REC	= 1<<12, /* Page Received */
+	PHY_M_PS_SPDUP_RES	= 1<<11, /* Speed & Duplex Resolved */
+	PHY_M_PS_LINK_UP	= 1<<10, /* Link Up */
+	PHY_M_PS_CABLE_MSK	= 7<<7,  /* Bit  9.. 7: Cable Length Mask */
+	PHY_M_PS_MDI_X_STAT	= 1<<6,  /* MDI Crossover Stat (1=MDIX) */
+	PHY_M_PS_DOWNS_STAT	= 1<<5,  /* Downshift Status (1=downsh.) */
+	PHY_M_PS_ENDET_STAT	= 1<<4,  /* Energy Detect Status (1=act) */
+	PHY_M_PS_TX_P_EN	= 1<<3,  /* Tx Pause Enabled */
+	PHY_M_PS_RX_P_EN	= 1<<2,  /* Rx Pause Enabled */
+	PHY_M_PS_POL_REV	= 1<<1,  /* Polarity Reversed */
+	PHY_M_PS_JABBER		= 1<<0,  /* Jabber */
+};
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PS_DTE_DETECT	= 1<<15, /* Data Terminal Equipment (DTE) Detected */
+	PHY_M_PS_RES_SPEED	= 1<<14, /* Resolved Speed (1=100 Mbps, 0=10 Mbps */
+};
+
+enum {
+	PHY_M_IS_AN_ERROR	= 1<<15, /* Auto-Negotiation Error */
+	PHY_M_IS_LSP_CHANGE	= 1<<14, /* Link Speed Changed */
+	PHY_M_IS_DUP_CHANGE	= 1<<13, /* Duplex Mode Changed */
+	PHY_M_IS_AN_PR		= 1<<12, /* Page Received */
+	PHY_M_IS_AN_COMPL	= 1<<11, /* Auto-Negotiation Completed */
+	PHY_M_IS_LST_CHANGE	= 1<<10, /* Link Status Changed */
+	PHY_M_IS_SYMB_ERROR	= 1<<9, /* Symbol Error */
+	PHY_M_IS_FALSE_CARR	= 1<<8, /* False Carrier */
+	PHY_M_IS_FIFO_ERROR	= 1<<7, /* FIFO Overflow/Underrun Error */
+	PHY_M_IS_MDI_CHANGE	= 1<<6, /* MDI Crossover Changed */
+	PHY_M_IS_DOWNSH_DET	= 1<<5, /* Downshift Detected */
+	PHY_M_IS_END_CHANGE	= 1<<4, /* Energy Detect Changed */
+
+	PHY_M_IS_DTE_CHANGE	= 1<<2, /* DTE Power Det. Status Changed */
+	PHY_M_IS_POL_CHANGE	= 1<<1, /* Polarity Changed */
+	PHY_M_IS_JABBER		= 1<<0, /* Jabber */
+
+	PHY_M_DEF_MSK		= PHY_M_IS_LSP_CHANGE | PHY_M_IS_LST_CHANGE
+				 | PHY_M_IS_DUP_CHANGE,
+	PHY_M_AN_MSK	       = PHY_M_IS_AN_ERROR | PHY_M_IS_AN_COMPL,
+};
+
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+enum {
+	PHY_M_EC_ENA_BC_EXT = 1<<15, /* Enable Block Carr. Ext. (88E1111 only) */
+	PHY_M_EC_ENA_LIN_LB = 1<<14, /* Enable Line Loopback (88E1111 only) */
+
+	PHY_M_EC_DIS_LINK_P = 1<<12, /* Disable Link Pulses (88E1111 only) */
+	PHY_M_EC_M_DSC_MSK  = 3<<10, /* Bit 11..10:	Master Downshift Counter */
+					/* (88E1011 only) */
+	PHY_M_EC_S_DSC_MSK  = 3<<8,/* Bit  9.. 8:	Slave  Downshift Counter */
+				       /* (88E1011 only) */
+	PHY_M_EC_M_DSC_MSK2 = 7<<9,/* Bit 11.. 9:	Master Downshift Counter */
+					/* (88E1111 only) */
+	PHY_M_EC_DOWN_S_ENA = 1<<8, /* Downshift Enable (88E1111 only) */
+					/* !!! Errata in spec. (1 = disable) */
+	PHY_M_EC_RX_TIM_CT  = 1<<7, /* RGMII Rx Timing Control*/
+	PHY_M_EC_MAC_S_MSK  = 7<<4,/* Bit  6.. 4:	Def. MAC interface speed */
+	PHY_M_EC_FIB_AN_ENA = 1<<3, /* Fiber Auto-Neg. Enable (88E1011S only) */
+	PHY_M_EC_DTE_D_ENA  = 1<<2, /* DTE Detect Enable (88E1111 only) */
+	PHY_M_EC_TX_TIM_CT  = 1<<1, /* RGMII Tx Timing Control */
+	PHY_M_EC_TRANS_DIS  = 1<<0, /* Transmitter Disable (88E1111 only) */};
+
+#define PHY_M_EC_M_DSC(x)	((u16)(x)<<10 & PHY_M_EC_M_DSC_MSK)
+					/* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)	((u16)(x)<<8 & PHY_M_EC_S_DSC_MSK)
+					/* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_DSC_2(x)	((u16)(x)<<9 & PHY_M_EC_M_DSC_MSK2)
+					/* 000=1x; 001=2x; 010=3x; 011=4x */
+#define PHY_M_EC_MAC_S(x)	((u16)(x)<<4 & PHY_M_EC_MAC_S_MSK)
+					/* 01X=0; 110=2.5; 111=25 (MHz) */
+
+/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+enum {
+	PHY_M_PC_DIS_LINK_Pa	= 1<<15,/* Disable Link Pulses */
+	PHY_M_PC_DSC_MSK	= 7<<12,/* Bit 14..12:	Downshift Counter */
+	PHY_M_PC_DOWN_S_ENA	= 1<<11,/* Downshift Enable */
+};
+/* !!! Errata in spec. (1 = disable) */
+
+#define PHY_M_PC_DSC(x)			(((u16)(x)<<12) & PHY_M_PC_DSC_MSK)
+											/* 100=5x; 101=6x; 110=7x; 111=8x */
+enum {
+	MAC_TX_CLK_0_MHZ	= 2,
+	MAC_TX_CLK_2_5_MHZ	= 6,
+	MAC_TX_CLK_25_MHZ 	= 7,
+};
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+enum {
+	PHY_M_LEDC_DIS_LED	= 1<<15, /* Disable LED */
+	PHY_M_LEDC_PULS_MSK	= 7<<12,/* Bit 14..12: Pulse Stretch Mask */
+	PHY_M_LEDC_F_INT	= 1<<11, /* Force Interrupt */
+	PHY_M_LEDC_BL_R_MSK	= 7<<8,/* Bit 10.. 8: Blink Rate Mask */
+	PHY_M_LEDC_DP_C_LSB	= 1<<7, /* Duplex Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_TX_C_LSB	= 1<<6, /* Tx Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_LK_C_MSK	= 7<<3,/* Bit  5.. 3: Link Control Mask */
+					/* (88E1111 only) */
+};
+
+enum {
+	PHY_M_LEDC_LINK_MSK	= 3<<3,/* Bit  4.. 3: Link Control Mask */
+									/* (88E1011 only) */
+	PHY_M_LEDC_DP_CTRL	= 1<<2, /* Duplex Control */
+	PHY_M_LEDC_DP_C_MSB	= 1<<2, /* Duplex Control (MSB, 88E1111 only) */
+	PHY_M_LEDC_RX_CTRL	= 1<<1, /* Rx Activity / Link */
+	PHY_M_LEDC_TX_CTRL	= 1<<0, /* Tx Activity / Link */
+	PHY_M_LEDC_TX_C_MSB	= 1<<0, /* Tx Control (MSB, 88E1111 only) */
+};
+
+#define PHY_M_LED_PULS_DUR(x)	(((u16)(x)<<12) & PHY_M_LEDC_PULS_MSK)
+
+/*****  PHY_MARV_PHY_STAT (page 3)16 bit r/w	Polarity Control Reg. *****/
+enum {
+	PHY_M_POLC_LS1M_MSK	= 0xf<<12, /* Bit 15..12: LOS,STAT1 Mix % Mask */
+	PHY_M_POLC_IS0M_MSK	= 0xf<<8,  /* Bit 11.. 8: INIT,STAT0 Mix % Mask */
+	PHY_M_POLC_LOS_MSK	= 0x3<<6,  /* Bit  7.. 6: LOS Pol. Ctrl. Mask */
+	PHY_M_POLC_INIT_MSK	= 0x3<<4,  /* Bit  5.. 4: INIT Pol. Ctrl. Mask */
+	PHY_M_POLC_STA1_MSK	= 0x3<<2,  /* Bit  3.. 2: STAT1 Pol. Ctrl. Mask */
+	PHY_M_POLC_STA0_MSK	= 0x3,     /* Bit  1.. 0: STAT0 Pol. Ctrl. Mask */
+};
+
+#define PHY_M_POLC_LS1_P_MIX(x)	(((x)<<12) & PHY_M_POLC_LS1M_MSK)
+#define PHY_M_POLC_IS0_P_MIX(x)	(((x)<<8) & PHY_M_POLC_IS0M_MSK)
+#define PHY_M_POLC_LOS_CTRL(x)	(((x)<<6) & PHY_M_POLC_LOS_MSK)
+#define PHY_M_POLC_INIT_CTRL(x)	(((x)<<4) & PHY_M_POLC_INIT_MSK)
+#define PHY_M_POLC_STA1_CTRL(x)	(((x)<<2) & PHY_M_POLC_STA1_MSK)
+#define PHY_M_POLC_STA0_CTRL(x)	(((x)<<0) & PHY_M_POLC_STA0_MSK)
+
+enum {
+	PULS_NO_STR	= 0,/* no pulse stretching */
+	PULS_21MS	= 1,/* 21 ms to 42 ms */
+	PULS_42MS	= 2,/* 42 ms to 84 ms */
+	PULS_84MS	= 3,/* 84 ms to 170 ms */
+	PULS_170MS	= 4,/* 170 ms to 340 ms */
+	PULS_340MS	= 5,/* 340 ms to 670 ms */
+	PULS_670MS	= 6,/* 670 ms to 1.3 s */
+	PULS_1300MS	= 7,/* 1.3 s to 2.7 s */
+};
+
+#define PHY_M_LED_BLINK_RT(x)	(((u16)(x)<<8) & PHY_M_LEDC_BL_R_MSK)
+
+enum {
+	BLINK_42MS	= 0,/* 42 ms */
+	BLINK_84MS	= 1,/* 84 ms */
+	BLINK_170MS	= 2,/* 170 ms */
+	BLINK_340MS	= 3,/* 340 ms */
+	BLINK_670MS	= 4,/* 670 ms */
+};
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_SGMII(x)	((x)<<14)	/* Bit 15..14:  SGMII AN Timer */
+
+#define PHY_M_LED_MO_DUP(x)	((x)<<10)	/* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)	((x)<<8)	/* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)	((x)<<6)	/* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	((x)<<4)	/* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)	((x)<<2)	/* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)	((x)<<0)	/* Bit  1.. 0:  Tx */
+
+enum led_mode {
+	MO_LED_NORM  = 0,
+	MO_LED_BLINK = 1,
+	MO_LED_OFF   = 2,
+	MO_LED_ON    = 3,
+};
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+enum {
+	PHY_M_EC2_FI_IMPED	= 1<<6, /* Fiber Input  Impedance */
+	PHY_M_EC2_FO_IMPED	= 1<<5, /* Fiber Output Impedance */
+	PHY_M_EC2_FO_M_CLK	= 1<<4, /* Fiber Mode Clock Enable */
+	PHY_M_EC2_FO_BOOST	= 1<<3, /* Fiber Output Boost */
+	PHY_M_EC2_FO_AM_MSK	= 7,/* Bit  2.. 0:	Fiber Output Amplitude */
+};
+
+/*****  PHY_MARV_EXT_P_STAT 16 bit r/w	Ext. PHY Specific Status *****/
+enum {
+	PHY_M_FC_AUTO_SEL	= 1<<15, /* Fiber/Copper Auto Sel. Dis. */
+	PHY_M_FC_AN_REG_ACC	= 1<<14, /* Fiber/Copper AN Reg. Access */
+	PHY_M_FC_RESOLUTION	= 1<<13, /* Fiber/Copper Resolution */
+	PHY_M_SER_IF_AN_BP	= 1<<12, /* Ser. IF AN Bypass Enable */
+	PHY_M_SER_IF_BP_ST	= 1<<11, /* Ser. IF AN Bypass Status */
+	PHY_M_IRQ_POLARITY	= 1<<10, /* IRQ polarity */
+	PHY_M_DIS_AUT_MED	= 1<<9, /* Disable Aut. Medium Reg. Selection */
+	/* (88E1111 only) */
+
+	PHY_M_UNDOC1		= 1<<7, /* undocumented bit !! */
+	PHY_M_DTE_POW_STAT	= 1<<4, /* DTE Power Status (88E1111 only) */
+	PHY_M_MODE_MASK	= 0xf, /* Bit  3.. 0: copy of HWCFG MODE[3:0] */
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+/*****  PHY_MARV_FE_LED_PAR		16 bit r/w	LED Parallel Select Reg. *****/
+									/* Bit 15..12: reserved (used internally) */
+enum {
+	PHY_M_FELP_LED2_MSK = 0xf<<8,	/* Bit 11.. 8: LED2 Mask (LINK) */
+	PHY_M_FELP_LED1_MSK = 0xf<<4,	/* Bit  7.. 4: LED1 Mask (ACT) */
+	PHY_M_FELP_LED0_MSK = 0xf, /* Bit  3.. 0: LED0 Mask (SPEED) */
+};
+
+#define PHY_M_FELP_LED2_CTRL(x)	(((u16)(x)<<8) & PHY_M_FELP_LED2_MSK)
+#define PHY_M_FELP_LED1_CTRL(x)	(((u16)(x)<<4) & PHY_M_FELP_LED1_MSK)
+#define PHY_M_FELP_LED0_CTRL(x)	(((u16)(x)<<0) & PHY_M_FELP_LED0_MSK)
+
+enum {
+	LED_PAR_CTRL_COLX	= 0x00,
+	LED_PAR_CTRL_ERROR	= 0x01,
+	LED_PAR_CTRL_DUPLEX	= 0x02,
+	LED_PAR_CTRL_DP_COL	= 0x03,
+	LED_PAR_CTRL_SPEED	= 0x04,
+	LED_PAR_CTRL_LINK	= 0x05,
+	LED_PAR_CTRL_TX		= 0x06,
+	LED_PAR_CTRL_RX		= 0x07,
+	LED_PAR_CTRL_ACT	= 0x08,
+	LED_PAR_CTRL_LNK_RX	= 0x09,
+	LED_PAR_CTRL_LNK_AC	= 0x0a,
+	LED_PAR_CTRL_ACT_BL	= 0x0b,
+	LED_PAR_CTRL_TX_BL	= 0x0c,
+	LED_PAR_CTRL_RX_BL	= 0x0d,
+	LED_PAR_CTRL_COL_BL	= 0x0e,
+	LED_PAR_CTRL_INACT	= 0x0f
+};
+
+/*****,PHY_MARV_FE_SPEC_2		16 bit r/w	Specific Control Reg. 2 *****/
+enum {
+	PHY_M_FESC_DIS_WAIT	= 1<<2, /* Disable TDR Waiting Period */
+	PHY_M_FESC_ENA_MCLK	= 1<<1, /* Enable MAC Rx Clock in sleep mode */
+	PHY_M_FESC_SEL_CL_A	= 1<<0, /* Select Class A driver (100B-TX) */
+};
+
+/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+/*****  PHY_MARV_PHY_CTRL (page 1)		16 bit r/w	Fiber Specific Ctrl *****/
+enum {
+	PHY_M_FIB_FORCE_LNK	= 1<<10,/* Force Link Good */
+	PHY_M_FIB_SIGD_POL	= 1<<9,	/* SIGDET Polarity */
+	PHY_M_FIB_TX_DIS	= 1<<3,	/* Transmitter Disable */
+};
+
+/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+/*****  PHY_MARV_PHY_CTRL (page 2)		16 bit r/w	MAC Specific Ctrl *****/
+enum {
+	PHY_M_MAC_MD_MSK	= 7<<7, /* Bit  9.. 7: Mode Select Mask */
+	PHY_M_MAC_GMIF_PUP	= 1<<3,	/* GMII Power Up (88E1149 only) */
+	PHY_M_MAC_MD_AUTO	= 3,/* Auto Copper/1000Base-X */
+	PHY_M_MAC_MD_COPPER	= 5,/* Copper only */
+	PHY_M_MAC_MD_1000BX	= 7,/* 1000Base-X only */
+};
+#define PHY_M_MAC_MODE_SEL(x)	(((x)<<7) & PHY_M_MAC_MD_MSK)
+
+/*****  PHY_MARV_PHY_CTRL (page 3)		16 bit r/w	LED Control Reg. *****/
+enum {
+	PHY_M_LEDC_LOS_MSK	= 0xf<<12,/* Bit 15..12: LOS LED Ctrl. Mask */
+	PHY_M_LEDC_INIT_MSK	= 0xf<<8, /* Bit 11.. 8: INIT LED Ctrl. Mask */
+	PHY_M_LEDC_STA1_MSK	= 0xf<<4,/* Bit  7.. 4: STAT1 LED Ctrl. Mask */
+	PHY_M_LEDC_STA0_MSK	= 0xf, /* Bit  3.. 0: STAT0 LED Ctrl. Mask */
+};
+
+#define PHY_M_LEDC_LOS_CTRL(x)	(((x)<<12) & PHY_M_LEDC_LOS_MSK)
+#define PHY_M_LEDC_INIT_CTRL(x)	(((x)<<8) & PHY_M_LEDC_INIT_MSK)
+#define PHY_M_LEDC_STA1_CTRL(x)	(((x)<<4) & PHY_M_LEDC_STA1_MSK)
+#define PHY_M_LEDC_STA0_CTRL(x)	(((x)<<0) & PHY_M_LEDC_STA0_MSK)
+
+/* GMAC registers  */
+/* Port Registers */
+enum {
+	GM_GP_STAT	= 0x0000,	/* 16 bit r/o	General Purpose Status */
+	GM_GP_CTRL	= 0x0004,	/* 16 bit r/w	General Purpose Control */
+	GM_TX_CTRL	= 0x0008,	/* 16 bit r/w	Transmit Control Reg. */
+	GM_RX_CTRL	= 0x000c,	/* 16 bit r/w	Receive Control Reg. */
+	GM_TX_FLOW_CTRL	= 0x0010,	/* 16 bit r/w	Transmit Flow-Control */
+	GM_TX_PARAM	= 0x0014,	/* 16 bit r/w	Transmit Parameter Reg. */
+	GM_SERIAL_MODE	= 0x0018,	/* 16 bit r/w	Serial Mode Register */
+/* Source Address Registers */
+	GM_SRC_ADDR_1L	= 0x001c,	/* 16 bit r/w	Source Address 1 (low) */
+	GM_SRC_ADDR_1M	= 0x0020,	/* 16 bit r/w	Source Address 1 (middle) */
+	GM_SRC_ADDR_1H	= 0x0024,	/* 16 bit r/w	Source Address 1 (high) */
+	GM_SRC_ADDR_2L	= 0x0028,	/* 16 bit r/w	Source Address 2 (low) */
+	GM_SRC_ADDR_2M	= 0x002c,	/* 16 bit r/w	Source Address 2 (middle) */
+	GM_SRC_ADDR_2H	= 0x0030,	/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+	GM_MC_ADDR_H1	= 0x0034,	/* 16 bit r/w	Multicast Address Hash 1 */
+	GM_MC_ADDR_H2	= 0x0038,	/* 16 bit r/w	Multicast Address Hash 2 */
+	GM_MC_ADDR_H3	= 0x003c,	/* 16 bit r/w	Multicast Address Hash 3 */
+	GM_MC_ADDR_H4	= 0x0040,	/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+	GM_TX_IRQ_SRC	= 0x0044,	/* 16 bit r/o	Tx Overflow IRQ Source */
+	GM_RX_IRQ_SRC	= 0x0048,	/* 16 bit r/o	Rx Overflow IRQ Source */
+	GM_TR_IRQ_SRC	= 0x004c,	/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+	GM_TX_IRQ_MSK	= 0x0050,	/* 16 bit r/w	Tx Overflow IRQ Mask */
+	GM_RX_IRQ_MSK	= 0x0054,	/* 16 bit r/w	Rx Overflow IRQ Mask */
+	GM_TR_IRQ_MSK	= 0x0058,	/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+	GM_SMI_CTRL	= 0x0080,	/* 16 bit r/w	SMI Control Register */
+	GM_SMI_DATA	= 0x0084,	/* 16 bit r/w	SMI Data Register */
+	GM_PHY_ADDR	= 0x0088,	/* 16 bit r/w	GPHY Address Register */
+/* MIB Counters */
+	GM_MIB_CNT_BASE	= 0x0100,	/* Base Address of MIB Counters */
+	GM_MIB_CNT_END	= 0x025C,	/* Last MIB counter */
+};
+
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+enum {
+	GM_RXF_UC_OK    = GM_MIB_CNT_BASE + 0,	/* Unicast Frames Received OK */
+	GM_RXF_BC_OK	= GM_MIB_CNT_BASE + 8,	/* Broadcast Frames Received OK */
+	GM_RXF_MPAUSE	= GM_MIB_CNT_BASE + 16,	/* Pause MAC Ctrl Frames Received */
+	GM_RXF_MC_OK	= GM_MIB_CNT_BASE + 24,	/* Multicast Frames Received OK */
+	GM_RXF_FCS_ERR	= GM_MIB_CNT_BASE + 32,	/* Rx Frame Check Seq. Error */
+
+	GM_RXO_OK_LO	= GM_MIB_CNT_BASE + 48,	/* Octets Received OK Low */
+	GM_RXO_OK_HI	= GM_MIB_CNT_BASE + 56,	/* Octets Received OK High */
+	GM_RXO_ERR_LO	= GM_MIB_CNT_BASE + 64,	/* Octets Received Invalid Low */
+	GM_RXO_ERR_HI	= GM_MIB_CNT_BASE + 72,	/* Octets Received Invalid High */
+	GM_RXF_SHT	= GM_MIB_CNT_BASE + 80,	/* Frames <64 Byte Received OK */
+	GM_RXE_FRAG	= GM_MIB_CNT_BASE + 88,	/* Frames <64 Byte Received with FCS Err */
+	GM_RXF_64B	= GM_MIB_CNT_BASE + 96,	/* 64 Byte Rx Frame */
+	GM_RXF_127B	= GM_MIB_CNT_BASE + 104,/* 65-127 Byte Rx Frame */
+	GM_RXF_255B	= GM_MIB_CNT_BASE + 112,/* 128-255 Byte Rx Frame */
+	GM_RXF_511B	= GM_MIB_CNT_BASE + 120,/* 256-511 Byte Rx Frame */
+	GM_RXF_1023B	= GM_MIB_CNT_BASE + 128,/* 512-1023 Byte Rx Frame */
+	GM_RXF_1518B	= GM_MIB_CNT_BASE + 136,/* 1024-1518 Byte Rx Frame */
+	GM_RXF_MAX_SZ	= GM_MIB_CNT_BASE + 144,/* 1519-MaxSize Byte Rx Frame */
+	GM_RXF_LNG_ERR	= GM_MIB_CNT_BASE + 152,/* Rx Frame too Long Error */
+	GM_RXF_JAB_PKT	= GM_MIB_CNT_BASE + 160,/* Rx Jabber Packet Frame */
+
+	GM_RXE_FIFO_OV	= GM_MIB_CNT_BASE + 176,/* Rx FIFO overflow Event */
+	GM_TXF_UC_OK	= GM_MIB_CNT_BASE + 192,/* Unicast Frames Xmitted OK */
+	GM_TXF_BC_OK	= GM_MIB_CNT_BASE + 200,/* Broadcast Frames Xmitted OK */
+	GM_TXF_MPAUSE	= GM_MIB_CNT_BASE + 208,/* Pause MAC Ctrl Frames Xmitted */
+	GM_TXF_MC_OK	= GM_MIB_CNT_BASE + 216,/* Multicast Frames Xmitted OK */
+	GM_TXO_OK_LO	= GM_MIB_CNT_BASE + 224,/* Octets Transmitted OK Low */
+	GM_TXO_OK_HI	= GM_MIB_CNT_BASE + 232,/* Octets Transmitted OK High */
+	GM_TXF_64B	= GM_MIB_CNT_BASE + 240,/* 64 Byte Tx Frame */
+	GM_TXF_127B	= GM_MIB_CNT_BASE + 248,/* 65-127 Byte Tx Frame */
+	GM_TXF_255B	= GM_MIB_CNT_BASE + 256,/* 128-255 Byte Tx Frame */
+	GM_TXF_511B	= GM_MIB_CNT_BASE + 264,/* 256-511 Byte Tx Frame */
+	GM_TXF_1023B	= GM_MIB_CNT_BASE + 272,/* 512-1023 Byte Tx Frame */
+	GM_TXF_1518B	= GM_MIB_CNT_BASE + 280,/* 1024-1518 Byte Tx Frame */
+	GM_TXF_MAX_SZ	= GM_MIB_CNT_BASE + 288,/* 1519-MaxSize Byte Tx Frame */
+
+	GM_TXF_COL	= GM_MIB_CNT_BASE + 304,/* Tx Collision */
+	GM_TXF_LAT_COL	= GM_MIB_CNT_BASE + 312,/* Tx Late Collision */
+	GM_TXF_ABO_COL	= GM_MIB_CNT_BASE + 320,/* Tx aborted due to Exces. Col. */
+	GM_TXF_MUL_COL	= GM_MIB_CNT_BASE + 328,/* Tx Multiple Collision */
+	GM_TXF_SNG_COL	= GM_MIB_CNT_BASE + 336,/* Tx Single Collision */
+	GM_TXE_FIFO_UR	= GM_MIB_CNT_BASE + 344,/* Tx FIFO Underrun Event */
+};
+
+/* GMAC Bit Definitions */
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+enum {
+	GM_GPSR_SPEED		= 1<<15, /* Bit 15:	Port Speed (1 = 100 Mbps) */
+	GM_GPSR_DUPLEX		= 1<<14, /* Bit 14:	Duplex Mode (1 = Full) */
+	GM_GPSR_FC_TX_DIS	= 1<<13, /* Bit 13:	Tx Flow-Control Mode Disabled */
+	GM_GPSR_LINK_UP		= 1<<12, /* Bit 12:	Link Up Status */
+	GM_GPSR_PAUSE		= 1<<11, /* Bit 11:	Pause State */
+	GM_GPSR_TX_ACTIVE	= 1<<10, /* Bit 10:	Tx in Progress */
+	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occured */
+	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occured */
+
+	GM_GPSR_PHY_ST_CH	= 1<<5,	/* Bit  5:	PHY Status Change */
+	GM_GPSR_GIG_SPEED	= 1<<4,	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+	GM_GPSR_PART_MODE	= 1<<3,	/* Bit  3:	Partition mode */
+	GM_GPSR_FC_RX_DIS	= 1<<2,	/* Bit  2:	Rx Flow-Control Mode Disabled */
+	GM_GPSR_PROM_EN		= 1<<1,	/* Bit  1:	Promiscuous Mode Enabled */
+};
+
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+enum {
+	GM_GPCR_PROM_ENA	= 1<<14,	/* Bit 14:	Enable Promiscuous Mode */
+	GM_GPCR_FC_TX_DIS	= 1<<13, /* Bit 13:	Disable Tx Flow-Control Mode */
+	GM_GPCR_TX_ENA		= 1<<12, /* Bit 12:	Enable Transmit */
+	GM_GPCR_RX_ENA		= 1<<11, /* Bit 11:	Enable Receive */
+	GM_GPCR_BURST_ENA	= 1<<10, /* Bit 10:	Enable Burst Mode */
+	GM_GPCR_LOOP_ENA	= 1<<9,	/* Bit  9:	Enable MAC Loopback Mode */
+	GM_GPCR_PART_ENA	= 1<<8,	/* Bit  8:	Enable Partition Mode */
+	GM_GPCR_GIGS_ENA	= 1<<7,	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+	GM_GPCR_FL_PASS		= 1<<6,	/* Bit  6:	Force Link Pass */
+	GM_GPCR_DUP_FULL	= 1<<5,	/* Bit  5:	Full Duplex Mode */
+	GM_GPCR_FC_RX_DIS	= 1<<4,	/* Bit  4:	Disable Rx Flow-Control Mode */
+	GM_GPCR_SPEED_100	= 1<<3,   /* Bit  3:	Port Speed 100 Mbps */
+	GM_GPCR_AU_DUP_DIS	= 1<<2,	/* Bit  2:	Disable Auto-Update Duplex */
+	GM_GPCR_AU_FCT_DIS	= 1<<1,	/* Bit  1:	Disable Auto-Update Flow-C. */
+	GM_GPCR_AU_SPD_DIS	= 1<<0,	/* Bit  0:	Disable Auto-Update Speed */
+};
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
+
+/*	GM_TX_CTRL			16 bit r/w	Transmit Control Register */
+enum {
+	GM_TXCR_FORCE_JAM	= 1<<15, /* Bit 15:	Force Jam / Flow-Control */
+	GM_TXCR_CRC_DIS		= 1<<14, /* Bit 14:	Disable insertion of CRC */
+	GM_TXCR_PAD_DIS		= 1<<13, /* Bit 13:	Disable padding of packets */
+	GM_TXCR_COL_THR_MSK	= 7<<10, /* Bit 12..10:	Collision Threshold */
+};
+
+#define TX_COL_THR(x)		(((x)<<10) & GM_TXCR_COL_THR_MSK)
+#define TX_COL_DEF		0x04
+
+/*	GM_RX_CTRL			16 bit r/w	Receive Control Register */
+enum {
+	GM_RXCR_UCF_ENA	= 1<<15, /* Bit 15:	Enable Unicast filtering */
+	GM_RXCR_MCF_ENA	= 1<<14, /* Bit 14:	Enable Multicast filtering */
+	GM_RXCR_CRC_DIS	= 1<<13, /* Bit 13:	Remove 4-byte CRC */
+	GM_RXCR_PASS_FC	= 1<<12, /* Bit 12:	Pass FC packets to FIFO */
+};
+
+/*	GM_TX_PARAM		16 bit r/w	Transmit Parameter Register */
+enum {
+	GM_TXPA_JAMLEN_MSK	= 0x03<<14,	/* Bit 15..14:	Jam Length */
+	GM_TXPA_JAMIPG_MSK	= 0x1f<<9,	/* Bit 13..9:	Jam IPG */
+	GM_TXPA_JAMDAT_MSK	= 0x1f<<4,	/* Bit  8..4:	IPG Jam to Data */
+	GM_TXPA_BO_LIM_MSK	= 0x0f,		/* Bit  3.. 0: Backoff Limit Mask */
+
+	TX_JAM_LEN_DEF		= 0x03,
+	TX_JAM_IPG_DEF		= 0x0b,
+	TX_IPG_JAM_DEF		= 0x1c,
+	TX_BOF_LIM_DEF		= 0x04,
+};
+
+#define TX_JAM_LEN_VAL(x)	(((x)<<14) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x)	(((x)<<9)  & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x)	(((x)<<4)  & GM_TXPA_JAMDAT_MSK)
+#define TX_BACK_OFF_LIM(x)	((x) & GM_TXPA_BO_LIM_MSK)
+
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+enum {
+	GM_SMOD_DATABL_MSK	= 0x1f<<11, /* Bit 15..11:	Data Blinder (r/o) */
+	GM_SMOD_LIMIT_4		= 1<<10, /* Bit 10:	4 consecutive Tx trials */
+	GM_SMOD_VLAN_ENA	= 1<<9,	/* Bit  9:	Enable VLAN  (Max. Frame Len) */
+	GM_SMOD_JUMBO_ENA	= 1<<8,	/* Bit  8:	Enable Jumbo (Max. Frame Len) */
+	 GM_SMOD_IPG_MSK	= 0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+};
+
+#define DATA_BLIND_VAL(x)	(((x)<<11) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF		0x04
+
+#define IPG_DATA_VAL(x)		(x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF		0x1e
+
+/*	GM_SMI_CTRL			16 bit r/w	SMI Control Register */
+enum {
+	GM_SMI_CT_PHY_A_MSK	= 0x1f<<11,/* Bit 15..11:	PHY Device Address */
+	GM_SMI_CT_REG_A_MSK	= 0x1f<<6,/* Bit 10.. 6:	PHY Register Address */
+	GM_SMI_CT_OP_RD		= 1<<5,	/* Bit  5:	OpCode Read (0=Write)*/
+	GM_SMI_CT_RD_VAL	= 1<<4,	/* Bit  4:	Read Valid (Read completed) */
+	GM_SMI_CT_BUSY		= 1<<3,	/* Bit  3:	Busy (Operation in progress) */
+};
+
+#define GM_SMI_CT_PHY_AD(x)	(((u16)(x)<<11) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x)	(((u16)(x)<<6) & GM_SMI_CT_REG_A_MSK)
+
+/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+enum {
+	GM_PAR_MIB_CLR	= 1<<5,	/* Bit  5:	Set MIB Clear Counter Mode */
+	GM_PAR_MIB_TST	= 1<<4,	/* Bit  4:	MIB Load Counter (Test Mode) */
+};
+
+/* Receive Frame Status Encoding */
+enum {
+	GMR_FS_LEN	= 0x7fff<<16, /* Bit 30..16:	Rx Frame Length */
+	GMR_FS_VLAN	= 1<<13, /* VLAN Packet */
+	GMR_FS_JABBER	= 1<<12, /* Jabber Packet */
+	GMR_FS_UN_SIZE	= 1<<11, /* Undersize Packet */
+	GMR_FS_MC	= 1<<10, /* Multicast Packet */
+	GMR_FS_BC	= 1<<9,  /* Broadcast Packet */
+	GMR_FS_RX_OK	= 1<<8,  /* Receive OK (Good Packet) */
+	GMR_FS_GOOD_FC	= 1<<7,  /* Good Flow-Control Packet */
+	GMR_FS_BAD_FC	= 1<<6,  /* Bad  Flow-Control Packet */
+	GMR_FS_MII_ERR	= 1<<5,  /* MII Error */
+	GMR_FS_LONG_ERR	= 1<<4,  /* Too Long Packet */
+	GMR_FS_FRAGMENT	= 1<<3,  /* Fragment */
+
+	GMR_FS_CRC_ERR	= 1<<1,  /* CRC Error */
+	GMR_FS_RX_FF_OV	= 1<<0,  /* Rx FIFO Overflow */
+
+	GMR_FS_ANY_ERR	= GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
+			  GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
+			  GMR_FS_MII_ERR | GMR_FS_BAD_FC |
+			  GMR_FS_UN_SIZE | GMR_FS_JABBER,
+};
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+enum {
+	RX_TRUNC_ON	= 1<<27,  	/* enable  packet truncation */
+	RX_TRUNC_OFF	= 1<<26, 	/* disable packet truncation */
+	RX_VLAN_STRIP_ON = 1<<25,	/* enable  VLAN stripping */
+	RX_VLAN_STRIP_OFF = 1<<24,	/* disable VLAN stripping */
+
+	RX_MACSEC_FLUSH_ON  = 1<<23,
+	RX_MACSEC_FLUSH_OFF = 1<<22,
+	RX_MACSEC_ASF_FLUSH_ON = 1<<21,
+	RX_MACSEC_ASF_FLUSH_OFF = 1<<20,
+
+	GMF_RX_OVER_ON      = 1<<19,	/* enable flushing on receive overrun */
+	GMF_RX_OVER_OFF     = 1<<18,	/* disable flushing on receive overrun */
+	GMF_ASF_RX_OVER_ON  = 1<<17,	/* enable flushing of ASF when overrun */
+	GMF_ASF_RX_OVER_OFF = 1<<16,	/* disable flushing of ASF when overrun */
+
+	GMF_WP_TST_ON	= 1<<14,	/* Write Pointer Test On */
+	GMF_WP_TST_OFF	= 1<<13,	/* Write Pointer Test Off */
+	GMF_WP_STEP	= 1<<12,	/* Write Pointer Step/Increment */
+
+	GMF_RP_TST_ON	= 1<<10,	/* Read Pointer Test On */
+	GMF_RP_TST_OFF	= 1<<9,		/* Read Pointer Test Off */
+	GMF_RP_STEP	= 1<<8,		/* Read Pointer Step/Increment */
+	GMF_RX_F_FL_ON	= 1<<7,		/* Rx FIFO Flush Mode On */
+	GMF_RX_F_FL_OFF	= 1<<6,		/* Rx FIFO Flush Mode Off */
+	GMF_CLI_RX_FO	= 1<<5,		/* Clear IRQ Rx FIFO Overrun */
+	GMF_CLI_RX_C	= 1<<4,		/* Clear IRQ Rx Frame Complete */
+
+	GMF_OPER_ON	= 1<<3,		/* Operational Mode On */
+	GMF_OPER_OFF	= 1<<2,		/* Operational Mode Off */
+	GMF_RST_CLR	= 1<<1,		/* Clear GMAC FIFO Reset */
+	GMF_RST_SET	= 1<<0,		/* Set   GMAC FIFO Reset */
+
+	RX_GMF_FL_THR_DEF = 0xa,	/* flush threshold (default) */
+
+	GMF_RX_CTRL_DEF	= GMF_OPER_ON | GMF_RX_F_FL_ON,
+};
+
+/*	TX_GMF_EA		32 bit	Tx GMAC FIFO End Address */
+enum {
+	TX_DYN_WM_ENA	= 3,	/* Yukon-FE+ specific */
+};
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+enum {
+	TX_STFW_DIS	= 1<<31,/* Disable Store & Forward (Yukon-EC Ultra) */
+	TX_STFW_ENA	= 1<<30,/* Enable  Store & Forward (Yukon-EC Ultra) */
+
+	TX_VLAN_TAG_ON	= 1<<25,/* enable  VLAN tagging */
+	TX_VLAN_TAG_OFF	= 1<<24,/* disable VLAN tagging */
+
+	TX_JUMBO_ENA	= 1<<23,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */
+	TX_JUMBO_DIS	= 1<<22,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */
+
+	GMF_WSP_TST_ON	= 1<<18,/* Write Shadow Pointer Test On */
+	GMF_WSP_TST_OFF	= 1<<17,/* Write Shadow Pointer Test Off */
+	GMF_WSP_STEP	= 1<<16,/* Write Shadow Pointer Step/Increment */
+
+	GMF_CLI_TX_FU	= 1<<6,	/* Clear IRQ Tx FIFO Underrun */
+	GMF_CLI_TX_FC	= 1<<5,	/* Clear IRQ Tx Frame Complete */
+	GMF_CLI_TX_PE	= 1<<4,	/* Clear IRQ Tx Parity Error */
+};
+
+/*	GMAC_TI_ST_CTRL	 8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+enum {
+	GMT_ST_START	= 1<<2,	/* Start Time Stamp Timer */
+	GMT_ST_STOP	= 1<<1,	/* Stop  Time Stamp Timer */
+	GMT_ST_CLR_IRQ	= 1<<0,	/* Clear Time Stamp Timer IRQ */
+};
+
+/* B28_Y2_ASF_STAT_CMD		32 bit	ASF Status and Command Reg */
+enum {
+	Y2_ASF_OS_PRES	= 1<<4,	/* ASF operation system present */
+	Y2_ASF_RESET	= 1<<3,	/* ASF system in reset state */
+	Y2_ASF_RUNNING	= 1<<2,	/* ASF system operational */
+	Y2_ASF_CLR_HSTI = 1<<1,	/* Clear ASF IRQ */
+	Y2_ASF_IRQ	= 1<<0,	/* Issue an IRQ to ASF system */
+
+	Y2_ASF_UC_STATE = 3<<2,	/* ASF uC State */
+	Y2_ASF_CLK_HALT	= 0,	/* ASF system clock stopped */
+};
+
+/* B28_Y2_ASF_HOST_COM	32 bit	ASF Host Communication Reg */
+enum {
+	Y2_ASF_CLR_ASFI = 1<<1,	/* Clear host IRQ */
+	Y2_ASF_HOST_IRQ = 1<<0,	/* Issue an IRQ to HOST system */
+};
+/*	HCU_CCSR	CPU Control and Status Register */
+enum {
+	HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+	HCU_CCSR_CPU_SLEEP	= 1<<26, /* CPU sleep status */
+	/* Clock Stretching Timeout */
+	HCU_CCSR_CS_TO		= 1<<25,
+	HCU_CCSR_WDOG		= 1<<24, /* Watchdog Reset */
+
+	HCU_CCSR_CLR_IRQ_HOST	= 1<<17, /* Clear IRQ_HOST */
+	HCU_CCSR_SET_IRQ_HCU	= 1<<16, /* Set IRQ_HCU */
+
+	HCU_CCSR_AHB_RST	= 1<<9, /* Reset AHB bridge */
+	HCU_CCSR_CPU_RST_MODE	= 1<<8, /* CPU Reset Mode */
+
+	HCU_CCSR_SET_SYNC_CPU	= 1<<5,
+	HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+	HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+	HCU_CCSR_OS_PRSNT	= 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+	HCU_CCSR_UC_STATE_MSK	= 3,
+	HCU_CCSR_UC_STATE_BASE	= 1<<0,
+	HCU_CCSR_ASF_RESET	= 0,
+	HCU_CCSR_ASF_HALTED	= 1<<1,
+	HCU_CCSR_ASF_RUNNING	= 1<<0,
+};
+
+/*	HCU_HCSR	Host Control and Status Register */
+enum {
+	HCU_HCSR_SET_IRQ_CPU	= 1<<16, /* Set IRQ_CPU */
+
+	HCU_HCSR_CLR_IRQ_HCU	= 1<<1, /* Clear IRQ_HCU */
+	HCU_HCSR_SET_IRQ_HOST	= 1<<0,	/* Set IRQ_HOST */
+};
+
+/*	STAT_CTRL		32 bit	Status BMU control register (Yukon-2 only) */
+enum {
+	SC_STAT_CLR_IRQ	= 1<<4,	/* Status Burst IRQ clear */
+	SC_STAT_OP_ON	= 1<<3,	/* Operational Mode On */
+	SC_STAT_OP_OFF	= 1<<2,	/* Operational Mode Off */
+	SC_STAT_RST_CLR	= 1<<1,	/* Clear Status Unit Reset (Enable) */
+	SC_STAT_RST_SET	= 1<<0,	/* Set   Status Unit Reset */
+};
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+enum {
+	GMC_SET_RST	    = 1<<15,/* MAC SEC RST */
+	GMC_SEC_RST_OFF     = 1<<14,/* MAC SEC RSt OFF */
+	GMC_BYP_MACSECRX_ON = 1<<13,/* Bypass macsec RX */
+	GMC_BYP_MACSECRX_OFF= 1<<12,/* Bypass macsec RX off */
+	GMC_BYP_MACSECTX_ON = 1<<11,/* Bypass macsec TX */
+	GMC_BYP_MACSECTX_OFF= 1<<10,/* Bypass macsec TX  off*/
+	GMC_BYP_RETR_ON	= 1<<9, /* Bypass retransmit FIFO On */
+	GMC_BYP_RETR_OFF= 1<<8, /* Bypass retransmit FIFO Off */
+
+	GMC_H_BURST_ON	= 1<<7,	/* Half Duplex Burst Mode On */
+	GMC_H_BURST_OFF	= 1<<6,	/* Half Duplex Burst Mode Off */
+	GMC_F_LOOPB_ON	= 1<<5,	/* FIFO Loopback On */
+	GMC_F_LOOPB_OFF	= 1<<4,	/* FIFO Loopback Off */
+	GMC_PAUSE_ON	= 1<<3,	/* Pause On */
+	GMC_PAUSE_OFF	= 1<<2,	/* Pause Off */
+	GMC_RST_CLR	= 1<<1,	/* Clear GMAC Reset */
+	GMC_RST_SET	= 1<<0,	/* Set   GMAC Reset */
+};
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+enum {
+	GPC_TX_PAUSE	= 1<<30, /* Tx pause enabled (ro) */
+	GPC_RX_PAUSE	= 1<<29, /* Rx pause enabled (ro) */
+	GPC_SPEED	= 3<<27, /* PHY speed (ro) */
+	GPC_LINK	= 1<<26, /* Link up (ro) */
+	GPC_DUPLEX	= 1<<25, /* Duplex (ro) */
+	GPC_CLOCK	= 1<<24, /* 125Mhz clock stable (ro) */
+
+	GPC_PDOWN	= 1<<23, /* Internal regulator 2.5 power down */
+	GPC_TSTMODE	= 1<<22, /* Test mode */
+	GPC_REG18	= 1<<21, /* Reg18 Power down */
+	GPC_REG12SEL	= 3<<19, /* Reg12 power setting */
+	GPC_REG18SEL	= 3<<17, /* Reg18 power setting */
+	GPC_SPILOCK	= 1<<16, /* SPI lock (ASF) */
+
+	GPC_LEDMUX	= 3<<14, /* LED Mux */
+	GPC_INTPOL	= 1<<13, /* Interrupt polarity */
+	GPC_DETECT	= 1<<12, /* Energy detect */
+	GPC_1000HD	= 1<<11, /* Enable 1000Mbit HD */
+	GPC_SLAVE	= 1<<10, /* Slave mode */
+	GPC_PAUSE	= 1<<9, /* Pause enable */
+	GPC_LEDCTL	= 3<<6, /* GPHY Leds */
+
+	GPC_RST_CLR	= 1<<1,	/* Clear GPHY Reset */
+	GPC_RST_SET	= 1<<0,	/* Set   GPHY Reset */
+};
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+enum {
+	GM_IS_TX_CO_OV	= 1<<5,	/* Transmit Counter Overflow IRQ */
+	GM_IS_RX_CO_OV	= 1<<4,	/* Receive Counter Overflow IRQ */
+	GM_IS_TX_FF_UR	= 1<<3,	/* Transmit FIFO Underrun */
+	GM_IS_TX_COMPL	= 1<<2,	/* Frame Transmission Complete */
+	GM_IS_RX_FF_OR	= 1<<1,	/* Receive FIFO Overrun */
+	GM_IS_RX_COMPL	= 1<<0,	/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK     GM_IS_TX_FF_UR
+};
+
+/*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */
+enum {						/* Bits 15.. 2:	reserved */
+	GMLC_RST_CLR	= 1<<1,	/* Clear GMAC Link Reset */
+	GMLC_RST_SET	= 1<<0,	/* Set   GMAC Link Reset */
+};
+
+
+/*	WOL_CTRL_STAT	16 bit	WOL Control/Status Reg */
+enum {
+	WOL_CTL_LINK_CHG_OCC		= 1<<15,
+	WOL_CTL_MAGIC_PKT_OCC		= 1<<14,
+	WOL_CTL_PATTERN_OCC		= 1<<13,
+	WOL_CTL_CLEAR_RESULT		= 1<<12,
+	WOL_CTL_ENA_PME_ON_LINK_CHG	= 1<<11,
+	WOL_CTL_DIS_PME_ON_LINK_CHG	= 1<<10,
+	WOL_CTL_ENA_PME_ON_MAGIC_PKT	= 1<<9,
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT	= 1<<8,
+	WOL_CTL_ENA_PME_ON_PATTERN	= 1<<7,
+	WOL_CTL_DIS_PME_ON_PATTERN	= 1<<6,
+	WOL_CTL_ENA_LINK_CHG_UNIT	= 1<<5,
+	WOL_CTL_DIS_LINK_CHG_UNIT	= 1<<4,
+	WOL_CTL_ENA_MAGIC_PKT_UNIT	= 1<<3,
+	WOL_CTL_DIS_MAGIC_PKT_UNIT	= 1<<2,
+	WOL_CTL_ENA_PATTERN_UNIT	= 1<<1,
+	WOL_CTL_DIS_PATTERN_UNIT	= 1<<0,
+};
+
+
+/* Control flags */
+enum {
+	UDPTCP	= 1<<0,
+	CALSUM	= 1<<1,
+	WR_SUM	= 1<<2,
+	INIT_SUM= 1<<3,
+	LOCK_SUM= 1<<4,
+	INS_VLAN= 1<<5,
+	EOP	= 1<<7,
+};
+
+enum {
+	HW_OWNER 	= 1<<7,
+	OP_TCPWRITE	= 0x11,
+	OP_TCPSTART	= 0x12,
+	OP_TCPINIT	= 0x14,
+	OP_TCPLCK	= 0x18,
+	OP_TCPCHKSUM	= OP_TCPSTART,
+	OP_TCPIS	= OP_TCPINIT | OP_TCPSTART,
+	OP_TCPLW	= OP_TCPLCK | OP_TCPWRITE,
+	OP_TCPLSW	= OP_TCPLCK | OP_TCPSTART | OP_TCPWRITE,
+	OP_TCPLISW	= OP_TCPLCK | OP_TCPINIT | OP_TCPSTART | OP_TCPWRITE,
+
+	OP_ADDR64	= 0x21,
+	OP_VLAN		= 0x22,
+	OP_ADDR64VLAN	= OP_ADDR64 | OP_VLAN,
+	OP_LRGLEN	= 0x24,
+	OP_LRGLENVLAN	= OP_LRGLEN | OP_VLAN,
+	OP_MSS		= 0x28,
+	OP_MSSVLAN	= OP_MSS | OP_VLAN,
+
+	OP_BUFFER	= 0x40,
+	OP_PACKET	= 0x41,
+	OP_LARGESEND	= 0x43,
+	OP_LSOV2	= 0x45,
+
+/* YUKON-2 STATUS opcodes defines */
+	OP_RXSTAT	= 0x60,
+	OP_RXTIMESTAMP	= 0x61,
+	OP_RXVLAN	= 0x62,
+	OP_RXCHKS	= 0x64,
+	OP_RXCHKSVLAN	= OP_RXCHKS | OP_RXVLAN,
+	OP_RXTIMEVLAN	= OP_RXTIMESTAMP | OP_RXVLAN,
+	OP_RSS_HASH	= 0x65,
+	OP_TXINDEXLE	= 0x68,
+	OP_MACSEC	= 0x6c,
+	OP_PUTIDX	= 0x70,
+};
+
+enum status_css {
+	CSS_TCPUDPCSOK	= 1<<7,	/* TCP / UDP checksum is ok */
+	CSS_ISUDP	= 1<<6, /* packet is a UDP packet */
+	CSS_ISTCP	= 1<<5, /* packet is a TCP packet */
+	CSS_ISIPFRAG	= 1<<4, /* packet is a TCP/UDP frag, CS calc not done */
+	CSS_ISIPV6	= 1<<3, /* packet is a IPv6 packet */
+	CSS_IPV4CSUMOK	= 1<<2, /* IP v4: TCP header checksum is ok */
+	CSS_ISIPV4	= 1<<1, /* packet is a IPv4 packet */
+	CSS_LINK_BIT	= 1<<0, /* port number (legacy) */
+};
+
+/* Yukon 2 hardware interface */
+struct sky2_tx_le {
+	u32	addr;
+	u16	length;	/* also vlan tag or checksum start */
+	u8	ctrl;
+	u8	opcode;
+} __attribute((packed));
+
+struct sky2_rx_le {
+	u32	addr;
+	u16	length;
+	u8	ctrl;
+	u8	opcode;
+} __attribute((packed));
+
+struct sky2_status_le {
+	u32	status;	/* also checksum */
+	u16	length;	/* also vlan tag */
+	u8	css;
+	u8	opcode;
+} __attribute((packed));
+
+struct tx_ring_info {
+	struct io_buffer *iob;
+	u32 mapaddr;
+	u32 maplen;
+};
+
+struct rx_ring_info {
+	struct io_buffer *iob;
+	u32	data_addr;
+	u32	data_size;
+};
+
+enum flow_control {
+	FC_NONE	= 0,
+	FC_TX	= 1,
+	FC_RX	= 2,
+	FC_BOTH	= 3,
+};
+
+struct sky2_port {
+	struct sky2_hw	     *hw;
+	struct net_device    *netdev;
+	unsigned	     port;
+
+	struct tx_ring_info  *tx_ring;
+	struct sky2_tx_le    *tx_le;
+	u16		     tx_cons;		/* next le to check */
+	u16		     tx_prod;		/* next le to use */
+
+	struct rx_ring_info  *rx_ring;
+	struct sky2_rx_le    *rx_le;
+
+	u16		     rx_next;		/* next re to check */
+	u16		     rx_put;		/* next le index to use */
+	u16		     rx_data_size;
+
+	u32		     rx_le_map;
+	u32		     tx_le_map;
+	u16		     advertising;	/* ADVERTISED_ bits */
+	u16		     speed;	/* SPEED_1000, SPEED_100, ... */
+	u8		     autoneg;	/* AUTONEG_ENABLE, AUTONEG_DISABLE */
+	u8		     duplex;	/* DUPLEX_HALF, DUPLEX_FULL */
+	enum flow_control    flow_mode;
+	enum flow_control    flow_status;
+};
+
+struct sky2_hw {
+	unsigned long	     regs;
+	struct pci_device    *pdev;
+	struct net_device    *dev[2];
+	unsigned long	     flags;
+#define SKY2_HW_USE_MSI		0x00000001
+#define SKY2_HW_FIBRE_PHY	0x00000002
+#define SKY2_HW_GIGABIT		0x00000004
+#define SKY2_HW_NEWER_PHY	0x00000008
+#define SKY2_HW_RAM_BUFFER	0x00000010
+#define SKY2_HW_NEW_LE		0x00000020	/* new LSOv2 format */
+#define SKY2_HW_AUTO_TX_SUM	0x00000040	/* new IP decode for Tx */
+#define SKY2_HW_ADV_POWER_CTL	0x00000080	/* additional PHY power regs */
+
+	u8	     	     chip_id;
+	u8		     chip_rev;
+	u8		     pmd_type;
+	u8		     ports;
+
+	struct sky2_status_le *st_le;
+	u32		     st_idx;
+	u32		     st_dma;
+};
+
+static inline int sky2_is_copper(const struct sky2_hw *hw)
+{
+	return !(hw->flags & SKY2_HW_FIBRE_PHY);
+}
+
+/* Register accessor for memory mapped device */
+static inline u32 sky2_read32(const struct sky2_hw *hw, unsigned reg)
+{
+	return readl(hw->regs + reg);
+}
+
+static inline u16 sky2_read16(const struct sky2_hw *hw, unsigned reg)
+{
+	return readw(hw->regs + reg);
+}
+
+static inline u8 sky2_read8(const struct sky2_hw *hw, unsigned reg)
+{
+	return readb(hw->regs + reg);
+}
+
+static inline void sky2_write32(const struct sky2_hw *hw, unsigned reg, u32 val)
+{
+	writel(val, hw->regs + reg);
+}
+
+static inline void sky2_write16(const struct sky2_hw *hw, unsigned reg, u16 val)
+{
+	writew(val, hw->regs + reg);
+}
+
+static inline void sky2_write8(const struct sky2_hw *hw, unsigned reg, u8 val)
+{
+	writeb(val, hw->regs + reg);
+}
+
+/* Yukon PHY related registers */
+#define SK_GMAC_REG(port,reg) \
+	(BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg))
+#define GM_PHY_RETRIES	100
+
+static inline u16 gma_read16(const struct sky2_hw *hw, unsigned port, unsigned reg)
+{
+	return sky2_read16(hw, SK_GMAC_REG(port,reg));
+}
+
+static inline u32 gma_read32(struct sky2_hw *hw, unsigned port, unsigned reg)
+{
+	unsigned base = SK_GMAC_REG(port, reg);
+	return (u32) sky2_read16(hw, base)
+		| (u32) sky2_read16(hw, base+4) << 16;
+}
+
+static inline void gma_write16(const struct sky2_hw *hw, unsigned port, int r, u16 v)
+{
+	sky2_write16(hw, SK_GMAC_REG(port,r), v);
+}
+
+static inline void gma_set_addr(struct sky2_hw *hw, unsigned port, unsigned reg,
+				    const u8 *addr)
+{
+	gma_write16(hw, port, reg,  (u16) addr[0] | ((u16) addr[1] << 8));
+	gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
+	gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
+}
+
+/* PCI config space access */
+static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg)
+{
+	return sky2_read32(hw, Y2_CFG_SPC + reg);
+}
+
+static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg)
+{
+	return sky2_read16(hw, Y2_CFG_SPC + reg);
+}
+
+static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val)
+{
+	sky2_write32(hw, Y2_CFG_SPC + reg, val);
+}
+
+static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val)
+{
+	sky2_write16(hw, Y2_CFG_SPC + reg, val);
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.c
new file mode 100644
index 0000000..31e418a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.c
@@ -0,0 +1,952 @@
+#ifdef ALLMULTI
+#error multicast support is not yet implemented
+#endif
+ /*------------------------------------------------------------------------
+ * smc9000.c
+ * This is a Etherboot driver for SMC's 9000 series of Ethernet cards.
+ *
+ * Copyright (C) 1998 Daniel Engström <daniel.engstrom at riksnett.no>
+ * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman
+ * Copyright (C) 1996 by Erik Stahlman <eric at vt.edu>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * "Features" of the SMC chip:
+ *   4608 byte packet memory. ( for the 91C92/4.  Others have more )
+ *   EEPROM for configuration
+ *   AUI/TP selection
+ *
+ * Authors
+ *	Erik Stahlman				<erik at vt.edu>
+ *      Daniel Engström                         <daniel.engstrom at riksnett.no>
+ *
+ * History
+ * 98-09-25              Daniel Engström Etherboot driver crated from Eric's
+ *                                       Linux driver.
+ *
+ *---------------------------------------------------------------------------*/
+
+FILE_LICENCE ( GPL_ANY );
+
+#define LINUX_OUT_MACROS 1
+#define SMC9000_DEBUG    0
+
+#if SMC9000_DEBUG > 1
+#define PRINTK2 printf
+#else
+#define PRINTK2(args...)
+#endif
+
+#include <ipxe/ethernet.h>
+#include <errno.h>
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/isa.h>
+#include "smc9000.h"
+
+# define _outb outb
+# define _outw outw
+
+static const char       smc9000_version[] = "Version 0.99 98-09-30";
+static const char       *interfaces[ 2 ] = { "TP", "AUI" };
+static const char       *chip_ids[ 15 ] =  {
+   NULL, NULL, NULL,
+   /* 3 */ "SMC91C90/91C92",
+   /* 4 */ "SMC91C94",
+   /* 5 */ "SMC91C95",
+   NULL,
+   /* 7 */ "SMC91C100",
+   /* 8 */ "SMC91C100FD",
+   /* 9 */ "SMC91C11xFD",
+   NULL, NULL,
+   NULL, NULL, NULL
+};
+static const char      smc91c96_id[] = "SMC91C96";
+
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg)
+{
+    int oldBank;
+    unsigned int i;
+    byte mask;
+    word mii_reg;
+    byte bits[64];
+    int clk_idx = 0;
+    int input_idx;
+    word phydata;
+
+    // 32 consecutive ones on MDO to establish sync
+    for (i = 0; i < 32; ++i)
+        bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Start code <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Read command <10>
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+    bits[clk_idx++] = MII_MDOE;
+
+    // Output the PHY address, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyaddr & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Output the phy register number, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyreg & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Tristate and turnaround (2 bit times)
+    bits[clk_idx++] = 0;
+    //bits[clk_idx++] = 0;
+
+    // Input starts at this bit time
+    input_idx = clk_idx;
+
+    // Will input 16 bits
+    for (i = 0; i < 16; ++i)
+        bits[clk_idx++] = 0;
+
+    // Final clock bit
+    bits[clk_idx++] = 0;
+
+    // Save the current bank
+    oldBank = inw( ioaddr+BANK_SELECT );
+
+    // Select bank 3
+    SMC_SELECT_BANK(ioaddr, 3);
+
+    // Get the current MII register value
+    mii_reg = inw( ioaddr+MII_REG );
+
+    // Turn off all MII Interface bits
+    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+    // Clock all 64 cycles
+    for (i = 0; i < sizeof(bits); ++i)
+    {
+        // Clock Low - output data
+        outw( mii_reg | bits[i], ioaddr+MII_REG );
+        udelay(50);
+
+
+        // Clock Hi - input data
+        outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+        udelay(50);
+        bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+    }
+
+    // Return to idle state
+    // Set clock to low, data to low, and output tristated
+    outw( mii_reg, ioaddr+MII_REG );
+    udelay(50);
+
+    // Restore original bank select
+    SMC_SELECT_BANK(ioaddr, oldBank);
+
+    // Recover input data
+    phydata = 0;
+    for (i = 0; i < 16; ++i)
+    {
+        phydata <<= 1;
+
+        if (bits[input_idx++] & MII_MDI)
+            phydata |= 0x0001;
+    }
+
+#if (SMC_DEBUG > 2 )
+        printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+               phyaddr, phyreg, phydata);
+#endif
+
+        return(phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register(int ioaddr,
+                                   byte phyaddr, byte phyreg, word phydata)
+{
+    int oldBank;
+    unsigned int i;
+    word mask;
+    word mii_reg;
+    byte bits[65];
+    int clk_idx = 0;
+
+    // 32 consecutive ones on MDO to establish sync
+    for (i = 0; i < 32; ++i)
+        bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Start code <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Write command <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Output the PHY address, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyaddr & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+                // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Output the phy register number, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyreg & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Tristate and turnaround (2 bit times)
+    bits[clk_idx++] = 0;
+    bits[clk_idx++] = 0;
+
+    // Write out 16 bits of data, msb first
+    mask = 0x8000;
+    for (i = 0; i < 16; ++i)
+    {
+        if (phydata & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Final clock bit (tristate)
+    bits[clk_idx++] = 0;
+
+    // Save the current bank
+    oldBank = inw( ioaddr+BANK_SELECT );
+
+    // Select bank 3
+    SMC_SELECT_BANK(ioaddr, 3);
+
+    // Get the current MII register value
+    mii_reg = inw( ioaddr+MII_REG );
+
+    // Turn off all MII Interface bits
+    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+    // Clock all cycles
+    for (i = 0; i < sizeof(bits); ++i)
+    {
+        // Clock Low - output data
+        outw( mii_reg | bits[i], ioaddr+MII_REG );
+        udelay(50);
+
+
+        // Clock Hi - input data
+        outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+        udelay(50);
+        bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+    }
+
+    // Return to idle state
+    // Set clock to low, data to low, and output tristated
+    outw( mii_reg, ioaddr+MII_REG );
+    udelay(50);
+
+    // Restore original bank select
+    SMC_SELECT_BANK(ioaddr, oldBank);
+
+#if (SMC_DEBUG > 2 )
+        printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+               phyaddr, phyreg, phydata);
+#endif
+}
+
+
+/*------------------------------------------------------------
+ . Finds and reports the PHY address
+ .-------------------------------------------------------------*/
+static int smc_detect_phy(int ioaddr, byte *pphyaddr)
+{
+    word phy_id1;
+    word phy_id2;
+    int phyaddr;
+    int found = 0;
+
+    // Scan all 32 PHY addresses if necessary
+    for (phyaddr = 0; phyaddr < 32; ++phyaddr)
+    {
+        // Read the PHY identifiers
+        phy_id1  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
+        phy_id2  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
+
+        // Make sure it is a valid identifier
+        if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
+             (phy_id1 > 0x0000) && (phy_id1 < 0xffff))
+        {
+            if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000))
+            {
+                // Save the PHY's address
+                *pphyaddr = phyaddr;
+                found = 1;
+                break;
+            }
+        }
+    }
+
+    if (!found)
+    {
+        printf("No PHY found\n");
+        return(0);
+    }
+
+    // Set the PHY type
+    if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) )
+    {
+        printf("PHY=LAN83C183 (LAN91C111 Internal)\n");
+    }
+
+    if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) )
+    {
+        printf("PHY=LAN83C180\n");
+    }
+
+    return(1);
+}
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+static void smc_phy_configure(int ioaddr)
+{
+    int timeout;
+    byte phyaddr;
+    word my_phy_caps; // My PHY capabilities
+    word my_ad_caps; // My Advertised capabilities
+    word status;
+    int rpc_cur_mode = RPC_DEFAULT;
+    int lastPhy18;
+
+    // Find the address and type of our phy
+    if (!smc_detect_phy(ioaddr, &phyaddr))
+    {
+        return;
+    }
+
+    // Reset the PHY, setting all other bits to zero
+    smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
+
+    // Wait for the reset to complete, or time out
+    timeout = 6; // Wait up to 3 seconds
+    while (timeout--)
+    {
+        if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
+              & PHY_CNTL_RST))
+        {
+            // reset complete
+            break;
+        }
+
+        mdelay(500); // wait 500 millisecs
+    }
+
+    if (timeout < 1)
+    {
+        PRINTK2("PHY reset timed out\n");
+        return;
+    }
+
+    // Read PHY Register 18, Status Output
+    lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+    // Enable PHY Interrupts (for register 18)
+    // Interrupts listed here are disabled
+    smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
+                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+                                   PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+                                   PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+    /* Configure the Receive/Phy Control register */
+    SMC_SELECT_BANK(ioaddr, 0);
+    outw( rpc_cur_mode, ioaddr + RPC_REG );
+
+    // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
+    my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+    my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
+
+    if (my_phy_caps & PHY_STAT_CAP_T4)
+        my_ad_caps |= PHY_AD_T4;
+
+    if (my_phy_caps & PHY_STAT_CAP_TXF)
+        my_ad_caps |= PHY_AD_TX_FDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TXH)
+        my_ad_caps |= PHY_AD_TX_HDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TF)
+        my_ad_caps |= PHY_AD_10_FDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TH)
+        my_ad_caps |= PHY_AD_10_HDX;
+
+    // Update our Auto-Neg Advertisement Register
+    smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
+
+    PRINTK2("phy caps=%x\n", my_phy_caps);
+    PRINTK2("phy advertised caps=%x\n", my_ad_caps);
+
+    // Restart auto-negotiation process in order to advertise my caps
+    smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+                            PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
+
+    // Wait for the auto-negotiation to complete.  This may take from
+    // 2 to 3 seconds.
+    // Wait for the reset to complete, or time out
+    timeout = 20; // Wait up to 10 seconds
+    while (timeout--)
+    {
+        status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+        if (status & PHY_STAT_ANEG_ACK)
+        {
+            // auto-negotiate complete
+            break;
+        }
+
+        mdelay(500); // wait 500 millisecs
+
+        // Restart auto-negotiation if remote fault
+        if (status & PHY_STAT_REM_FLT)
+        {
+            PRINTK2("PHY remote fault detected\n");
+
+            // Restart auto-negotiation
+            PRINTK2("PHY restarting auto-negotiation\n");
+            smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+                                    PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
+                                    PHY_CNTL_SPEED | PHY_CNTL_DPLX);
+        }
+    }
+
+    if (timeout < 1)
+    {
+        PRINTK2("PHY auto-negotiate timed out\n");
+    }
+
+    // Fail if we detected an auto-negotiate remote fault
+    if (status & PHY_STAT_REM_FLT)
+    {
+        PRINTK2("PHY remote fault detected\n");
+    }
+
+    // Set our sysctl parameters to match auto-negotiation results
+    if ( lastPhy18 & PHY_INT_SPDDET )
+    {
+        PRINTK2("PHY 100BaseT\n");
+        rpc_cur_mode |= RPC_SPEED;
+    }
+    else
+    {
+        PRINTK2("PHY 10BaseT\n");
+        rpc_cur_mode &= ~RPC_SPEED;
+    }
+
+    if ( lastPhy18 & PHY_INT_DPLXDET )
+    {
+        PRINTK2("PHY Full Duplex\n");
+        rpc_cur_mode |= RPC_DPLX;
+    }
+    else
+    {
+        PRINTK2("PHY Half Duplex\n");
+        rpc_cur_mode &= ~RPC_DPLX;
+    }
+
+    // Re-Configure the Receive/Phy Control register
+    outw( rpc_cur_mode, ioaddr + RPC_REG );
+}
+
+/*
+ * Function: smc_reset( int ioaddr )
+ * Purpose:
+ *	This sets the SMC91xx chip to its normal state, hopefully from whatever
+ *	mess that any other DOS driver has put it in.
+ *
+ * Maybe I should reset more registers to defaults in here?  SOFTRESET  should
+ * do that for me.
+ *
+ * Method:
+ *	1.  send a SOFT RESET
+ *	2.  wait for it to finish
+ *	3.  reset the memory management unit
+ *      4.  clear all interrupts
+ *
+*/
+static void smc_reset(int ioaddr)
+{
+   /* This resets the registers mostly to defaults, but doesn't
+    * affect EEPROM.  That seems unnecessary */
+   SMC_SELECT_BANK(ioaddr, 0);
+   _outw( RCR_SOFTRESET, ioaddr + RCR );
+
+   /* this should pause enough for the chip to be happy */
+   SMC_DELAY(ioaddr);
+
+   /* Set the transmit and receive configuration registers to
+    * default values */
+   _outw(RCR_CLEAR, ioaddr + RCR);
+   _outw(TCR_CLEAR, ioaddr + TCR);
+
+   /* Reset the MMU */
+   SMC_SELECT_BANK(ioaddr, 2);
+   _outw( MC_RESET, ioaddr + MMU_CMD );
+
+   /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+    * but this is a place where future chipsets _COULD_ break.  Be wary
+    * of issuing another MMU command right after this */
+   _outb(0, ioaddr + INT_MASK);
+}
+
+
+/*----------------------------------------------------------------------
+ * Function: smc9000_probe_addr( int ioaddr )
+ *
+ * Purpose:
+ *	Tests to see if a given ioaddr points to an SMC9xxx chip.
+ *	Returns a 1 on success
+ *
+ * Algorithm:
+ *	(1) see if the high byte of BANK_SELECT is 0x33
+ *	(2) compare the ioaddr with the base register's address
+ *	(3) see if I recognize the chip ID in the appropriate register
+ *
+ * ---------------------------------------------------------------------
+ */
+static int smc9000_probe_addr( isa_probe_addr_t ioaddr )
+{
+   word bank;
+   word	revision_register;
+   word base_address_register;
+
+   /* First, see if the high byte is 0x33 */
+   bank = inw(ioaddr + BANK_SELECT);
+   if ((bank & 0xFF00) != 0x3300) {
+      return 0;
+   }
+   /* The above MIGHT indicate a device, but I need to write to further
+    *	test this.  */
+   _outw(0x0, ioaddr + BANK_SELECT);
+   bank = inw(ioaddr + BANK_SELECT);
+   if ((bank & 0xFF00) != 0x3300) {
+      return 0;
+   }
+
+   /* well, we've already written once, so hopefully another time won't
+    *  hurt.  This time, I need to switch the bank register to bank 1,
+    *  so I can access the base address register */
+   SMC_SELECT_BANK(ioaddr, 1);
+   base_address_register = inw(ioaddr + BASE);
+
+   if (ioaddr != (base_address_register >> 3 & 0x3E0))  {
+      DBG("SMC9000: IOADDR %hX doesn't match configuration (%hX)."
+	  "Probably not a SMC chip\n",
+	  ioaddr, base_address_register >> 3 & 0x3E0);
+      /* well, the base address register didn't match.  Must not have
+       * been a SMC chip after all. */
+      return 0;
+   }
+
+
+   /* check if the revision register is something that I recognize.
+    * These might need to be added to later, as future revisions
+    * could be added.  */
+   SMC_SELECT_BANK(ioaddr, 3);
+   revision_register  = inw(ioaddr + REVISION);
+   if (!chip_ids[(revision_register >> 4) & 0xF]) {
+      /* I don't recognize this chip, so... */
+      DBG( "SMC9000: IO %hX: Unrecognized revision register:"
+	   " %hX, Contact author.\n", ioaddr, revision_register );
+      return 0;
+   }
+
+   /* at this point I'll assume that the chip is an SMC9xxx.
+    * It might be prudent to check a listing of MAC addresses
+    * against the hardware address, or do some other tests. */
+   return 1;
+}
+
+
+/**************************************************************************
+ * ETH_TRANSMIT - Transmit a frame
+ ***************************************************************************/
+static void smc9000_transmit(
+	struct nic *nic,
+	const char *d,			/* Destination */
+	unsigned int t,			/* Type */
+	unsigned int s,			/* size */
+	const char *p)			/* Packet */
+{
+   word length; /* real, length incl. header */
+   word numPages;
+   unsigned long time_out;
+   byte	packet_no;
+   word status;
+   int i;
+
+   /* We dont pad here since we can have the hardware doing it for us */
+   length = (s + ETH_HLEN + 1)&~1;
+
+   /* convert to MMU pages */
+   numPages = length / 256;
+
+   if (numPages > 7 ) {
+      DBG("SMC9000: Far too big packet error. \n");
+      return;
+   }
+
+   /* dont try more than, say 30 times */
+   for (i=0;i<30;i++) {
+      /* now, try to allocate the memory */
+      SMC_SELECT_BANK(nic->ioaddr, 2);
+      _outw(MC_ALLOC | numPages, nic->ioaddr + MMU_CMD);
+
+      status = 0;
+      /* wait for the memory allocation to finnish */
+      for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {
+	 status = inb(nic->ioaddr + INTERRUPT);
+	 if ( status & IM_ALLOC_INT ) {
+	    /* acknowledge the interrupt */
+	    _outb(IM_ALLOC_INT, nic->ioaddr + INTERRUPT);
+	    break;
+	 }
+      }
+
+      if ((status & IM_ALLOC_INT) != 0 ) {
+	 /* We've got the memory */
+	 break;
+      } else {
+	 printf("SMC9000: Memory allocation timed out, resetting MMU.\n");
+	 _outw(MC_RESET, nic->ioaddr + MMU_CMD);
+      }
+   }
+
+   /* If I get here, I _know_ there is a packet slot waiting for me */
+   packet_no = inb(nic->ioaddr + PNR_ARR + 1);
+   if (packet_no & 0x80) {
+      /* or isn't there?  BAD CHIP! */
+      printf("SMC9000: Memory allocation failed. \n");
+      return;
+   }
+
+   /* we have a packet address, so tell the card to use it */
+   _outb(packet_no, nic->ioaddr + PNR_ARR);
+
+   /* point to the beginning of the packet */
+   _outw(PTR_AUTOINC, nic->ioaddr + POINTER);
+
+#if	SMC9000_DEBUG > 2
+   printf("Trying to xmit packet of length %hX\n", length );
+#endif
+
+   /* send the packet length ( +6 for status, length and ctl byte )
+    * and the status word ( set to zeros ) */
+   _outw(0, nic->ioaddr + DATA_1 );
+
+   /* send the packet length ( +6 for status words, length, and ctl) */
+   _outb((length+6) & 0xFF,  nic->ioaddr + DATA_1);
+   _outb((length+6) >> 8 ,   nic->ioaddr + DATA_1);
+
+   /* Write the contents of the packet */
+
+   /* The ethernet header first... */
+   outsw(nic->ioaddr + DATA_1, d, ETH_ALEN >> 1);
+   outsw(nic->ioaddr + DATA_1, nic->node_addr, ETH_ALEN >> 1);
+   _outw(htons(t), nic->ioaddr + DATA_1);
+
+   /* ... the data ... */
+   outsw(nic->ioaddr + DATA_1 , p, s >> 1);
+
+   /* ... and the last byte, if there is one.   */
+   if ((s & 1) == 0) {
+      _outw(0, nic->ioaddr + DATA_1);
+   } else {
+      _outb(p[s-1], nic->ioaddr + DATA_1);
+      _outb(0x20, nic->ioaddr + DATA_1);
+   }
+
+   /* and let the chipset deal with it */
+   _outw(MC_ENQUEUE , nic->ioaddr + MMU_CMD);
+
+   status = 0; time_out = currticks() + 5*TICKS_PER_SEC;
+   do {
+      status = inb(nic->ioaddr + INTERRUPT);
+
+      if ((status & IM_TX_INT ) != 0) {
+	 word tx_status;
+
+	 /* ack interrupt */
+	 _outb(IM_TX_INT, nic->ioaddr + INTERRUPT);
+
+	 packet_no = inw(nic->ioaddr + FIFO_PORTS);
+	 packet_no &= 0x7F;
+
+	 /* select this as the packet to read from */
+	 _outb( packet_no, nic->ioaddr + PNR_ARR );
+
+	 /* read the first word from this packet */
+	 _outw( PTR_AUTOINC | PTR_READ, nic->ioaddr + POINTER );
+
+	 tx_status = inw( nic->ioaddr + DATA_1 );
+
+	 if (0 == (tx_status & TS_SUCCESS)) {
+	    DBG("SMC9000: TX FAIL STATUS: %hX \n", tx_status);
+	    /* re-enable transmit */
+	    SMC_SELECT_BANK(nic->ioaddr, 0);
+	    _outw(inw(nic->ioaddr + TCR ) | TCR_ENABLE, nic->ioaddr + TCR );
+	 }
+
+	 /* kill the packet */
+	 SMC_SELECT_BANK(nic->ioaddr, 2);
+	 _outw(MC_FREEPKT, nic->ioaddr + MMU_CMD);
+
+	 return;
+      }
+   }while(currticks() < time_out);
+
+   printf("SMC9000: TX timed out, resetting board\n");
+   smc_reset(nic->ioaddr);
+   return;
+}
+
+/**************************************************************************
+ * ETH_POLL - Wait for a frame
+ ***************************************************************************/
+static int smc9000_poll(struct nic *nic, int retrieve)
+{
+   SMC_SELECT_BANK(nic->ioaddr, 2);
+   if (inw(nic->ioaddr + FIFO_PORTS) & FP_RXEMPTY)
+     return 0;
+   
+   if ( ! retrieve ) return 1;
+
+   /*  start reading from the start of the packet */
+   _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, nic->ioaddr + POINTER);
+
+   /* First read the status and check that we're ok */
+   if (!(inw(nic->ioaddr + DATA_1) & RS_ERRORS)) {
+      /* Next: read the packet length and mask off the top bits */
+      nic->packetlen = (inw(nic->ioaddr + DATA_1) & 0x07ff);
+
+      /* the packet length includes the 3 extra words */
+      nic->packetlen -= 6;
+#if	SMC9000_DEBUG > 2
+      printf(" Reading %d words (and %d byte(s))\n",
+	       (nic->packetlen >> 1), nic->packetlen & 1);
+#endif
+      /* read the packet (and the last "extra" word) */
+      insw(nic->ioaddr + DATA_1, nic->packet, (nic->packetlen+2) >> 1);
+      /* is there an odd last byte ? */
+      if (nic->packet[nic->packetlen+1] & 0x20)
+	 nic->packetlen++;
+
+      /*  error or good, tell the card to get rid of this packet */
+      _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
+      return 1;
+   }
+
+   printf("SMC9000: RX error\n");
+   /*  error or good, tell the card to get rid of this packet */
+   _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
+   return 0;
+}
+
+static void smc9000_disable ( struct nic *nic, struct isa_device *isa __unused ) {
+
+   smc_reset(nic->ioaddr);
+
+   /* no more interrupts for me */
+   SMC_SELECT_BANK(nic->ioaddr, 2);
+   _outb( 0, nic->ioaddr + INT_MASK);
+
+   /* and tell the card to stay away from that nasty outside world */
+   SMC_SELECT_BANK(nic->ioaddr, 0);
+   _outb( RCR_CLEAR, nic->ioaddr + RCR );
+   _outb( TCR_CLEAR, nic->ioaddr + TCR );
+}
+
+static void smc9000_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations smc9000_operations = {
+	.connect	= dummy_connect,
+	.poll		= smc9000_poll,
+	.transmit	= smc9000_transmit,
+	.irq		= smc9000_irq,
+
+};
+
+/**************************************************************************
+ * ETH_PROBE - Look for an adapter
+ ***************************************************************************/
+
+static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) {
+
+   unsigned short   revision;
+   int	            memory;
+   int              media;
+   const char *	    version_string;
+   const char *	    if_string;
+   int              i;
+
+   nic->irqno  = 0;
+   nic->ioaddr = isa->ioaddr;
+
+   /*
+    * Get the MAC address ( bank 1, regs 4 - 9 )
+    */
+   SMC_SELECT_BANK(nic->ioaddr, 1);
+   for ( i = 0; i < 6; i += 2 ) {
+      word address;
+
+      address = inw(nic->ioaddr + ADDR0 + i);
+      nic->node_addr[i+1] = address >> 8;
+      nic->node_addr[i] = address & 0xFF;
+   }
+
+   /* get the memory information */
+   SMC_SELECT_BANK(nic->ioaddr, 0);
+   memory = ( inw(nic->ioaddr + MCR) >> 9 )  & 0x7;  /* multiplier */
+   memory *= 256 * (inw(nic->ioaddr + MIR) & 0xFF);
+
+   /*
+    * Now, I want to find out more about the chip.  This is sort of
+    * redundant, but it's cleaner to have it in both, rather than having
+    * one VERY long probe procedure.
+    */
+   SMC_SELECT_BANK(nic->ioaddr, 3);
+   revision  = inw(nic->ioaddr + REVISION);
+   version_string = chip_ids[(revision >> 4) & 0xF];
+
+   if (((revision & 0xF0) >> 4 == CHIP_9196) &&
+       ((revision & 0x0F) >= REV_9196)) {
+      /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but
+       * a revision starting at 6 */
+      version_string = smc91c96_id;
+   }
+
+   if ( !version_string ) {
+      /* I shouldn't get here because this call was done before.... */
+      return 0;
+   }
+
+   /* is it using AUI or 10BaseT ? */
+   SMC_SELECT_BANK(nic->ioaddr, 1);
+   if (inw(nic->ioaddr + CONFIG) & CFG_AUI_SELECT)
+     media = 2;
+   else
+     media = 1;
+
+   if_string = interfaces[media - 1];
+
+   /* now, reset the chip, and put it into a known state */
+   smc_reset(nic->ioaddr);
+
+   printf("SMC9000 %s\n", smc9000_version);
+   DBG("Copyright (C) 1998 Daniel Engstr\x94m\n");
+   DBG("Copyright (C) 1996 Eric Stahlman\n");
+
+   printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n",
+	  version_string, revision & 0xF,
+	  nic->ioaddr, if_string, memory );
+
+   DBG ( "Ethernet MAC address: %s\n", eth_ntoa ( nic->node_addr ) );
+
+   SMC_SELECT_BANK(nic->ioaddr, 0);
+
+   /* see the header file for options in TCR/RCR NORMAL*/
+   _outw(TCR_NORMAL, nic->ioaddr + TCR);
+   _outw(RCR_NORMAL, nic->ioaddr + RCR);
+
+   /* Select which interface to use */
+   SMC_SELECT_BANK(nic->ioaddr, 1);
+   if ( media == 1 ) {
+      _outw( inw( nic->ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
+	   nic->ioaddr + CONFIG );
+   }
+   else if ( media == 2 ) {
+      _outw( inw( nic->ioaddr + CONFIG ) | CFG_AUI_SELECT,
+	   nic->ioaddr + CONFIG );
+   }
+
+   smc_phy_configure(nic->ioaddr);
+ 
+   nic->nic_op	= &smc9000_operations;
+   return 1;
+}
+
+/*
+ * The SMC9000 can be at any of the following port addresses.  To
+ * change for a slightly different card, you can add it to the array.
+ *
+ */
+static isa_probe_addr_t smc9000_probe_addrs[] = {
+   0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
+   0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0,
+};
+
+ISA_DRIVER ( smc9000_driver, smc9000_probe_addrs, smc9000_probe_addr,
+		     GENERIC_ISAPNP_VENDOR, 0x8228 );
+
+DRIVER ( "SMC9000", nic_driver, isa_driver, smc9000_driver,
+	 smc9000_probe, smc9000_disable );
+
+ISA_ROM ( "smc9000", "SMC9000" );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.h
new file mode 100644
index 0000000..22b0e18
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/smc9000.h
@@ -0,0 +1,428 @@
+/*------------------------------------------------------------------------
+ * smc9000.h
+ *
+ * Copyright (C) 1998 by Daniel Engström
+ * Copyright (C) 1996 by Erik Stahlman
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * This file contains register information and access macros for
+ * the SMC91xxx chipset.
+ *
+ * Information contained in this file was obtained from the SMC91C94
+ * manual from SMC.  To get a copy, if you really want one, you can find
+ * information under www.smsc.com in the components division.
+ * ( this thanks to advice from Donald Becker ).
+ *
+ * Authors
+ *      Daniel Engström                         <daniel.engstrom at riksnett.no>
+ *	Erik Stahlman				<erik at vt.edu>
+ *
+ * History
+ * 96-01-06		 Erik Stahlman   moved definitions here from main .c
+ *                                       file
+ * 96-01-19		 Erik Stahlman	 polished this up some, and added
+ *                                       better error handling
+ * 98-09-25              Daniel Engström adjusted for Etherboot
+ * 98-09-27              Daniel Engström moved some static strings back to the
+ *                                       main .c file
+ * --------------------------------------------------------------------------*/
+
+FILE_LICENCE ( GPL_ANY );
+
+#ifndef	_SMC9000_H_
+# define _SMC9000_H_
+
+/* I want some simple types */
+typedef unsigned char			byte;
+typedef unsigned short			word;
+typedef unsigned long int		dword;
+
+/*---------------------------------------------------------------
+ *
+ * A description of the SMC registers is probably in order here,
+ * although for details, the SMC datasheet is invaluable.
+ *
+ * Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ * are accessed by writing a number into the BANK_SELECT register
+ * ( I also use a SMC_SELECT_BANK macro for this ).
+ *
+ * The banks are configured so that for most purposes, bank 2 is all
+ * that is needed for simple run time tasks.
+ * ----------------------------------------------------------------------*/
+
+/*
+ * Bank Select Register:
+ *
+ *		yyyy yyyy 0000 00xx
+ *		xx		= bank number
+ *		yyyy yyyy	= 0x33, for identification purposes.
+ */
+#define	BANK_SELECT		14
+
+/* BANK 0  */
+
+#define	TCR		0	/* transmit control register */
+#define TCR_ENABLE	0x0001	/* if this is 1, we can transmit */
+#define TCR_FDUPLX	0x0800	/* receive packets sent out */
+#define TCR_STP_SQET	0x1000	/* stop transmitting if Signal quality error */
+#define	TCR_MON_CNS	0x0400	/* monitors the carrier status */
+#define	TCR_PAD_ENABLE	0x0080	/* pads short packets to 64 bytes */
+
+#define	TCR_CLEAR	0	/* do NOTHING */
+/* the normal settings for the TCR register : */
+#define	TCR_NORMAL	(TCR_ENABLE | TCR_PAD_ENABLE)
+
+
+#define EPH_STATUS	2
+#define ES_LINK_OK	0x4000	/* is the link integrity ok ? */
+
+#define	RCR		4
+#define RCR_SOFTRESET	0x8000	/* resets the chip */
+#define	RCR_STRIP_CRC	0x200	/* strips CRC */
+#define RCR_ENABLE	0x100	/* IFF this is set, we can receive packets */
+#define RCR_ALMUL	0x4	/* receive all multicast packets */
+#define	RCR_PROMISC	0x2	/* enable promiscuous mode */
+
+/* the normal settings for the RCR register : */
+#define	RCR_NORMAL	(RCR_STRIP_CRC | RCR_ENABLE)
+#define RCR_CLEAR	0x0		/* set it to a base state */
+
+#define	COUNTER		6
+#define	MIR		8
+#define	MCR		10
+/* 12 is reserved */
+
+// Receive/Phy Control Register
+/* BANK 0  */
+#define RPC_REG         0x000A
+#define RPC_SPEED       0x2000  // When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX        0x1000  // When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG        0x0800  // When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT   5       // Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT   2       // Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10  (0x00)  // LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES     (0x01)  // LED = Reserved
+#define RPC_LED_10      (0x02)  // LED = 10Mbps link detect
+#define RPC_LED_FD      (0x03)  // LED = Full Duplex Mode
+#define RPC_LED_TX_RX   (0x04)  // LED = TX or RX packet occurred
+#define RPC_LED_100     (0x05)  // LED = 100Mbps link dectect
+#define RPC_LED_TX      (0x06)  // LED = TX packet occurred
+#define RPC_LED_RX      (0x07)  // LED = RX packet occurred
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+
+// Receive/Phy Control Register
+/* BANK 0  */
+#define RPC_REG         0x000A
+#define RPC_SPEED       0x2000  // When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX        0x1000  // When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG        0x0800  // When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT   5       // Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT   2       // Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10  (0x00)  // LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES     (0x01)  // LED = Reserved
+#define RPC_LED_10      (0x02)  // LED = 10Mbps link detect
+#define RPC_LED_FD      (0x03)  // LED = Full Duplex Mode
+#define RPC_LED_TX_RX   (0x04)  // LED = TX or RX packet occurred
+#define RPC_LED_100     (0x05)  // LED = 100Mbps link dectect
+#define RPC_LED_TX      (0x06)  // LED = TX packet occurred
+#define RPC_LED_RX      (0x07)  // LED = RX packet occurred
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+
+/* BANK 1 */
+#define CONFIG			0
+#define CFG_AUI_SELECT		0x100
+#define	BASE			2
+#define	ADDR0			4
+#define	ADDR1			6
+#define	ADDR2			8
+#define	GENERAL			10
+#define	CONTROL			12
+#define	CTL_POWERDOWN		0x2000
+#define	CTL_LE_ENABLE		0x80
+#define	CTL_CR_ENABLE		0x40
+#define	CTL_TE_ENABLE		0x0020
+#define CTL_AUTO_RELEASE	0x0800
+#define	CTL_EPROM_ACCESS	0x0003 /* high if Eprom is being read */
+
+/* BANK 2 */
+#define MMU_CMD		0
+#define MC_BUSY		1	/* only readable bit in the register */
+#define MC_NOP		0
+#define	MC_ALLOC	0x20	/* or with number of 256 byte packets */
+#define	MC_RESET	0x40
+#define	MC_REMOVE	0x60	/* remove the current rx packet */
+#define MC_RELEASE	0x80	/* remove and release the current rx packet */
+#define MC_FREEPKT	0xA0	/* Release packet in PNR register */
+#define MC_ENQUEUE	0xC0	/* Enqueue the packet for transmit */
+
+#define	PNR_ARR		2
+#define FIFO_PORTS	4
+
+#define FP_RXEMPTY	0x8000
+#define FP_TXEMPTY	0x80
+
+#define	POINTER		6
+#define PTR_READ	0x2000
+#define	PTR_RCV		0x8000
+#define	PTR_AUTOINC	0x4000
+#define PTR_AUTO_INC	0x0040
+
+#define	DATA_1		8
+#define	DATA_2		10
+#define	INTERRUPT	12
+
+#define INT_MASK	13
+#define IM_RCV_INT	0x1
+#define	IM_TX_INT	0x2
+#define	IM_TX_EMPTY_INT	0x4
+#define	IM_ALLOC_INT	0x8
+#define	IM_RX_OVRN_INT	0x10
+#define	IM_EPH_INT	0x20
+#define	IM_ERCV_INT	0x40 /* not on SMC9192 */
+
+/* BANK 3 */
+#define	MULTICAST1	0
+#define	MULTICAST2	2
+#define	MULTICAST3	4
+#define	MULTICAST4	6
+#define	MGMT		8
+#define	REVISION	10 /* ( hi: chip id   low: rev # ) */
+
+// Management Interface Register (MII)
+#define MII_REG         0x0008
+#define MII_MSK_CRS100  0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE        0x0008 // MII Output Enable
+#define MII_MCLK        0x0004 // MII Clock, pin MDCLK
+#define MII_MDI         0x0002 // MII Input, pin MDI
+#define MII_MDO         0x0001 // MII Output, pin MDO
+
+/* this is NOT on SMC9192 */
+#define	ERCV		12
+
+/* Note that 9194 and 9196 have the smame chip id,
+ * the 9196 will have revisions starting at 6 */
+#define CHIP_9190	3
+#define CHIP_9194	4
+#define CHIP_9195	5
+#define CHIP_9196	4
+#define CHIP_91100	7
+#define CHIP_91100FD	8
+
+#define REV_9196	6
+
+/*
+ * Transmit status bits
+ */
+#define TS_SUCCESS	0x0001
+#define TS_LOSTCAR	0x0400
+#define TS_LATCOL	0x0200
+#define TS_16COL	0x0010
+
+/*
+ * Receive status bits
+ */
+#define RS_ALGNERR	0x8000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG            0x00
+#define PHY_CNTL_RST            0x8000  // 1=PHY Reset
+#define PHY_CNTL_LPBK           0x4000  // 1=PHY Loopback
+#define PHY_CNTL_SPEED          0x2000  // 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN        0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN            0x0800  // 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS        0x0400  // 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST       0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX           0x0100  // 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST         0x0080  // 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG            0x01
+#define PHY_STAT_CAP_T4         0x8000  // 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF        0x4000  // 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH        0x2000  // 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF         0x1000  // 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH         0x0800  // 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR       0x0040  // 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK       0x0020  // 1=ANEG has completed
+#define PHY_STAT_REM_FLT        0x0010  // 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG       0x0008  // 1=Auto negotiate capable
+#define PHY_STAT_LINK           0x0004  // 1=valid link
+#define PHY_STAT_JAB            0x0002  // 1=10Mbps jabber condition
+#define PHY_STAT_EXREG          0x0001  // 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG             0x02    // PHY Identifier 1
+#define PHY_ID2_REG             0x03    // PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG              0x04
+#define PHY_AD_NP               0x8000  // 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK              0x4000  // 1=got link code word from remote
+#define PHY_AD_RF               0x2000  // 1=advertise remote fault
+#define PHY_AD_T4               0x0200  // 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX           0x0100  // 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX           0x0080  // 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX           0x0040  // 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX           0x0020  // 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA             0x0001  // 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG             0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG            0x10
+#define PHY_CFG1_LNKDIS         0x8000  // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS         0x4000  // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN         0x2000  // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR         0x0400  // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS         0x0200  // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR          0x0100  // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE          0x0080  // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0          0x0040  // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT     2       // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK      0x003C
+#define PHY_CFG1_TRF_MASK       0x0003  // Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG            0x11
+#define PHY_CFG2_APOLDIS        0x0020  // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS         0x0010  // 1=Jabber disabled
+#define PHY_CFG2_MREG           0x0008  // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO        0x0004  // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG             0x12    // Status Output (Interrupt Status)
+#define PHY_INT_INT             0x8000  // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL         0x4000  // 1=Link Not detected
+#define PHY_INT_LOSSSYNC        0x2000  // 1=Descrambler has lost sync
+#define PHY_INT_CWRD            0x1000  // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD             0x0800  // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD             0x0400  // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL            0x0200  // 1=Reverse Polarity detected
+#define PHY_INT_JAB             0x0100  // 1=Jabber detected
+#define PHY_INT_SPDDET          0x0080  // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET         0x0040  // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG            0x13    // Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG            0x00
+#define PHY_CNTL_RST            0x8000  // 1=PHY Reset
+#define PHY_CNTL_LPBK           0x4000  // 1=PHY Loopback
+#define PHY_CNTL_SPEED          0x2000  // 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN        0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN            0x0800  // 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS        0x0400  // 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST       0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX           0x0100  // 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST         0x0080  // 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG            0x01
+#define PHY_STAT_CAP_T4         0x8000  // 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF        0x4000  // 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH        0x2000  // 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF         0x1000  // 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH         0x0800  // 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR       0x0040  // 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK       0x0020  // 1=ANEG has completed
+#define PHY_STAT_REM_FLT        0x0010  // 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG       0x0008  // 1=Auto negotiate capable
+#define PHY_STAT_LINK           0x0004  // 1=valid link
+#define PHY_STAT_JAB            0x0002  // 1=10Mbps jabber condition
+#define PHY_STAT_EXREG          0x0001  // 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG             0x02    // PHY Identifier 1
+#define PHY_ID2_REG             0x03    // PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG              0x04
+#define PHY_AD_NP               0x8000  // 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK              0x4000  // 1=got link code word from remote
+#define PHY_AD_RF               0x2000  // 1=advertise remote fault
+#define PHY_AD_T4               0x0200  // 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX           0x0100  // 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX           0x0080  // 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX           0x0040  // 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX           0x0020  // 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA             0x0001  // 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG             0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG            0x10
+#define PHY_CFG1_LNKDIS         0x8000  // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS         0x4000  // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN         0x2000  // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR         0x0400  // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS         0x0200  // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR          0x0100  // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE          0x0080  // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0          0x0040  // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT     2       // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK      0x003C
+#define PHY_CFG1_TRF_MASK       0x0003  // Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG            0x11
+#define PHY_CFG2_APOLDIS        0x0020  // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS         0x0010  // 1=Jabber disabled
+#define PHY_CFG2_MREG           0x0008  // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO        0x0004  // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG             0x12    // Status Output (Interrupt Status)
+#define PHY_INT_INT             0x8000  // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL         0x4000  // 1=Link Not detected
+#define PHY_INT_LOSSSYNC        0x2000  // 1=Descrambler has lost sync
+#define PHY_INT_CWRD            0x1000  // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD             0x0800  // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD             0x0400  // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL            0x0200  // 1=Reverse Polarity detected
+#define PHY_INT_JAB             0x0100  // 1=Jabber detected
+#define PHY_INT_SPDDET          0x0080  // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET         0x0040  // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG            0x13    // Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
+/*-------------------------------------------------------------------------
+ *  I define some macros to make it easier to do somewhat common
+ * or slightly complicated, repeated tasks.
+ --------------------------------------------------------------------------*/
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x, y) { _outw( y, x + BANK_SELECT ); }
+
+/* define a small delay for the reset */
+#define SMC_DELAY(x) { inw( x + RCR );\
+			inw( x + RCR );\
+			inw( x + RCR ); }
+
+
+#endif	/* _SMC_9000_H_ */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/sundance.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/sundance.c
new file mode 100644
index 0000000..63a9ea5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/sundance.c
@@ -0,0 +1,898 @@
+/**************************************************************************
+*
+*    sundance.c -- Etherboot device driver for the Sundance ST201 "Alta".
+*    Written 2002-2002 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*               sundance.c: A Linux device driver for the Sundance ST201 "Alta"
+*               Written 1999-2002 by Donald Becker
+*
+*               tulip.c: Tulip and Clone Etherboot Driver
+*               By Marty Conner
+*               Copyright (C) 2001 Entity Cyber, Inc.
+*
+*    Linux Driver Version LK1.09a, 10-Jul-2003 (2.4.25)
+*
+*    REVISION HISTORY:
+*    ================
+*    v1.1	01-01-2003	timlegge	Initial implementation
+*    v1.7	04-10-2003	timlegge	Transfers Linux Kernel (30 sec)
+*    v1.8	04-13-2003	timlegge	Fix multiple transmission bug
+*    v1.9	08-19-2003	timlegge	Support Multicast
+*    v1.10	01-17-2004	timlegge	Initial driver output cleanup
+*    v1.11	03-21-2004	timlegge	Remove unused variables
+*    v1.12	03-21-2004	timlegge	Remove excess MII defines
+*    v1.13	03-24-2004	timlegge	Update to Linux 2.4.25 driver
+*
+****************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include <ipxe/pci.h>
+#include "mii.h"
+
+#define drv_version "v1.12"
+#define drv_date "2004-03-21"
+
+#define HZ 100
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+/* Set the mtu */
+static int mtu = 1514;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   The sundance uses a 64 element hash table based on the Ethernet CRC.  */
+// static int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature.
+   This chip can receive into any byte alignment buffers, so word-oriented
+   archs do not need a copy-align of the IP header. */
+static int rx_copybreak = 0;
+static int flowctrl = 1;
+
+/* Allow forcing the media type */
+/* media[] specifies the media type the NIC operates at.
+		 autosense	Autosensing active media.
+		 10mbps_hd 	10Mbps half duplex.
+		 10mbps_fd 	10Mbps full duplex.
+		 100mbps_hd 	100Mbps half duplex.
+		 100mbps_fd 	100Mbps full duplex.
+*/
+static char media[] = "autosense";
+
+/* Operational parameters that are set at compile time. */
+
+/* As Etherboot uses a Polling driver  we can keep the number of rings
+to the minimum number required.  In general that is 1 transmit and 4 receive receive rings.  However some cards require that
+there be a minimum of 2 rings  */
+#define TX_RING_SIZE	2
+#define TX_QUEUE_LEN	10	/* Limit ring entries actually used.  */
+#define RX_RING_SIZE	4
+
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIME_OUT	  (4*HZ)
+#define PKT_BUF_SZ	1536
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum alta_offsets {
+	DMACtrl = 0x00,
+	TxListPtr = 0x04,
+	TxDMABurstThresh = 0x08,
+	TxDMAUrgentThresh = 0x09,
+	TxDMAPollPeriod = 0x0a,
+	RxDMAStatus = 0x0c,
+	RxListPtr = 0x10,
+	DebugCtrl0 = 0x1a,
+	DebugCtrl1 = 0x1c,
+	RxDMABurstThresh = 0x14,
+	RxDMAUrgentThresh = 0x15,
+	RxDMAPollPeriod = 0x16,
+	LEDCtrl = 0x1a,
+	ASICCtrl = 0x30,
+	EEData = 0x34,
+	EECtrl = 0x36,
+	TxStartThresh = 0x3c,
+	RxEarlyThresh = 0x3e,
+	FlashAddr = 0x40,
+	FlashData = 0x44,
+	TxStatus = 0x46,
+	TxFrameId = 0x47,
+	DownCounter = 0x18,
+	IntrClear = 0x4a,
+	IntrEnable = 0x4c,
+	IntrStatus = 0x4e,
+	MACCtrl0 = 0x50,
+	MACCtrl1 = 0x52,
+	StationAddr = 0x54,
+	MaxFrameSize = 0x5A,
+	RxMode = 0x5c,
+	MIICtrl = 0x5e,
+	MulticastFilter0 = 0x60,
+	MulticastFilter1 = 0x64,
+	RxOctetsLow = 0x68,
+	RxOctetsHigh = 0x6a,
+	TxOctetsLow = 0x6c,
+	TxOctetsHigh = 0x6e,
+	TxFramesOK = 0x70,
+	RxFramesOK = 0x72,
+	StatsCarrierError = 0x74,
+	StatsLateColl = 0x75,
+	StatsMultiColl = 0x76,
+	StatsOneColl = 0x77,
+	StatsTxDefer = 0x78,
+	RxMissed = 0x79,
+	StatsTxXSDefer = 0x7a,
+	StatsTxAbort = 0x7b,
+	StatsBcastTx = 0x7c,
+	StatsBcastRx = 0x7d,
+	StatsMcastTx = 0x7e,
+	StatsMcastRx = 0x7f,
+	/* Aliased and bogus values! */
+	RxStatus = 0x0c,
+};
+enum ASICCtrl_HiWord_bit {
+	GlobalReset = 0x0001,
+	RxReset = 0x0002,
+	TxReset = 0x0004,
+	DMAReset = 0x0008,
+	FIFOReset = 0x0010,
+	NetworkReset = 0x0020,
+	HostReset = 0x0040,
+	ResetBusy = 0x0400,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008,
+	IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020,
+	IntrDrvRqst = 0x0040,
+	StatsMax = 0x0080, LinkChange = 0x0100,
+	IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400,
+};
+
+/* Bits in the RxMode register. */
+enum rx_mode_bits {
+	AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08,
+	AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys =
+	    0x01,
+};
+/* Bits in MACCtrl. */
+enum mac_ctrl0_bits {
+	EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40,
+	EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200,
+};
+enum mac_ctrl1_bits {
+	StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080,
+	TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400,
+	RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000,
+};
+
+/* The Rx and Tx buffer descriptors.
+   Using only 32 bit fields simplifies software endian correction.
+   This structure must be aligned, and should avoid spanning cache lines.
+*/
+struct netdev_desc {
+	u32 next_desc;
+	u32 status;
+	u32 addr;
+	u32 length;
+};
+
+/* Bits in netdev_desc.status */
+enum desc_status_bits {
+	DescOwn = 0x8000,
+	DescEndPacket = 0x4000,
+	DescEndRing = 0x2000,
+	LastFrag = 0x80000000,
+	DescIntrOnTx = 0x8000,
+	DescIntrOnDMADone = 0x80000000,
+	DisableAlign = 0x00000001,
+};
+
+/**********************************************
+* Descriptor Ring and Buffer defination
+***********************************************/
+/* Define the TX Descriptor */
+static struct netdev_desc tx_ring[TX_RING_SIZE];
+
+/* Define the RX Descriptor */
+static struct netdev_desc rx_ring[RX_RING_SIZE];
+
+/* Create a static buffer of size PKT_BUF_SZ for each RX and TX descriptor.
+   All descriptors point to a part of this buffer */
+struct {
+	unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE];
+	unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ];
+} rx_tx_buf __shared;
+#define rxb rx_tx_buf.rxb
+#define txb rx_tx_buf.txb
+
+/* FIXME: Move BASE to the private structure */
+static u32 BASE;
+#define EEPROM_SIZE	128
+
+enum pci_id_flags_bits {
+	PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
+	PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 =
+	    2 << 4, PCI_ADDR3 = 3 << 4,
+};
+
+enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, };
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
+
+#define MII_CNT		4
+static struct sundance_private {
+	const char *nic_name;
+	/* Frequently used values */
+
+	unsigned int cur_rx;	/* Producer/consumer ring indicies */
+	unsigned int mtu;
+
+	/* These values keep track of the tranceiver/media in use */
+	unsigned int flowctrl:1;
+	unsigned int an_enable:1;
+
+	unsigned int speed;
+
+	/* MII tranceiver section */
+	struct mii_if_info mii_if;
+	int mii_preamble_required;
+	unsigned char phys[MII_CNT];
+	unsigned char pci_rev_id;
+} sdx;
+
+static struct sundance_private *sdc;
+
+/* Station Address location within the EEPROM */
+#define EEPROM_SA_OFFSET	0x10
+#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
+                        IntrDrvRqst | IntrTxDone | StatsMax | \
+                        LinkChange)
+
+static int eeprom_read(long ioaddr, int location);
+static int mdio_read(struct nic *nic, int phy_id, unsigned int location);
+static void mdio_write(struct nic *nic, int phy_id, unsigned int location,
+		       int value);
+static void set_rx_mode(struct nic *nic);
+
+static void check_duplex(struct nic *nic)
+{
+	int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
+	int negotiated = mii_lpa & sdc->mii_if.advertising;
+	int duplex;
+
+	/* Force media */
+	if (!sdc->an_enable || mii_lpa == 0xffff) {
+		if (sdc->mii_if.full_duplex)
+			outw(inw(BASE + MACCtrl0) | EnbFullDuplex,
+			     BASE + MACCtrl0);
+		return;
+	}
+
+	/* Autonegotiation */
+	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+	if (sdc->mii_if.full_duplex != duplex) {
+		sdc->mii_if.full_duplex = duplex;
+		DBG ("%s: Setting %s-duplex based on MII #%d "
+			 "negotiated capability %4.4x.\n", sdc->nic_name,
+			 duplex ? "full" : "half", sdc->phys[0],
+			 negotiated );
+		outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0,
+		     BASE + MACCtrl0);
+	}
+}
+
+
+/**************************************************************************
+ *  init_ring - setup the tx and rx descriptors
+ *************************************************************************/
+static void init_ring(struct nic *nic __unused)
+{
+	int i;
+
+	sdc->cur_rx = 0;
+
+	/* Initialize all the Rx descriptors */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]);
+		rx_ring[i].status = 0;
+		rx_ring[i].length = 0;
+		rx_ring[i].addr = 0;
+	}
+
+	/* Mark the last entry as wrapping the ring */
+	rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]);
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
+		rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
+	}
+
+	/* We only use one transmit buffer, but two
+	 * descriptors so transmit engines have somewhere
+	 * to point should they feel the need */
+	tx_ring[0].status = 0x00000000;
+	tx_ring[0].addr = virt_to_bus(&txb[0]);
+	tx_ring[0].next_desc = 0;	/* virt_to_bus(&tx_ring[1]); */
+
+	/* This descriptor is never used */
+	tx_ring[1].status = 0x00000000;
+	tx_ring[1].addr = 0;	/*virt_to_bus(&txb[0]); */
+	tx_ring[1].next_desc = 0;
+
+	/* Mark the last entry as wrapping the ring,
+	 * though this should never happen */
+	tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ);
+}
+
+/**************************************************************************
+ *  RESET - Reset Adapter
+ * ***********************************************************************/
+static void sundance_reset(struct nic *nic)
+{
+	int i;
+
+	init_ring(nic);
+
+	outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr);
+	/* The Tx List Pointer is written as packets are queued */
+
+	/* Initialize other registers. */
+	/* __set_mac_addr(dev); */
+	{
+		u16 addr16;
+
+		addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8));
+		outw(addr16, BASE + StationAddr);
+		addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8));
+		outw(addr16, BASE + StationAddr + 2);
+		addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8));
+		outw(addr16, BASE + StationAddr + 4);
+	}
+
+	outw(sdc->mtu + 14, BASE + MaxFrameSize);
+	if (sdc->mtu > 2047)	/* this will never happen with default options */
+		outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl);
+
+	set_rx_mode(nic);
+
+	outw(0, BASE + DownCounter);
+	/* Set the chip to poll every N*30nsec */
+	outb(100, BASE + RxDMAPollPeriod);
+
+	/* Fix DFE-580TX packet drop issue */
+	if (sdc->pci_rev_id >= 0x14)
+		writeb(0x01, BASE + DebugCtrl1);
+
+	outw(RxEnable | TxEnable, BASE + MACCtrl1);
+
+	/* Construct a perfect filter frame with the mac address as first match
+	 * and broadcast for all others */
+	for (i = 0; i < 192; i++)
+		txb[i] = 0xFF;
+
+	txb[0] = nic->node_addr[0];
+	txb[1] = nic->node_addr[1];
+	txb[2] = nic->node_addr[2];
+	txb[3] = nic->node_addr[3];
+	txb[4] = nic->node_addr[4];
+	txb[5] = nic->node_addr[5];
+
+	DBG ( "%s: Done sundance_reset, status: Rx %hX Tx %hX "
+	      "MAC Control %hX, %hX %hX\n",
+	      sdc->nic_name, (int) inl(BASE + RxStatus),
+	      (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0),
+	      (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0) );
+}
+
+/**************************************************************************
+IRQ - Wait for a frame
+***************************************************************************/
+static void sundance_irq ( struct nic *nic, irq_action_t action ) {
+        unsigned int intr_status;
+
+	switch ( action ) {
+	case DISABLE :
+	case ENABLE :
+		intr_status = inw(nic->ioaddr + IntrStatus);
+		intr_status = intr_status & ~DEFAULT_INTR;
+		if ( action == ENABLE ) 
+			intr_status = intr_status | DEFAULT_INTR;
+		outw(intr_status, nic->ioaddr + IntrEnable);
+		break;
+        case FORCE :
+		outw(0x0200, BASE + ASICCtrl);
+		break;
+        }
+}
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int sundance_poll(struct nic *nic, int retreive)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+	int entry = sdc->cur_rx % RX_RING_SIZE;
+	u32 frame_status = le32_to_cpu(rx_ring[entry].status);
+	int intr_status;
+	int pkt_len = 0;
+
+	if (!(frame_status & DescOwn))
+		return 0;
+
+	/* There is a packet ready */
+	if(!retreive)
+		return 1;
+
+	intr_status = inw(nic->ioaddr + IntrStatus);
+	outw(intr_status, nic->ioaddr + IntrStatus);
+
+	pkt_len = frame_status & 0x1fff;
+
+	if (frame_status & 0x001f4000) {
+		DBG ( "Polling frame_status error\n" );	/* Do we really care about this */
+	} else {
+		if (pkt_len < rx_copybreak) {
+			/* FIXME: What should happen Will this ever occur */
+			printf("Poll Error: pkt_len < rx_copybreak");
+		} else {
+			nic->packetlen = pkt_len;
+			memcpy(nic->packet, rxb +
+			       (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen);
+
+		}
+	}
+	rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
+	rx_ring[entry].status = 0;
+	entry++;
+	sdc->cur_rx = entry % RX_RING_SIZE;
+	outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), 
+		nic->ioaddr + IntrStatus);
+	return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void sundance_transmit(struct nic *nic, const char *d,	/* Destination */
+			      unsigned int t,	/* Type */
+			      unsigned int s,	/* size */
+			      const char *p)
+{				/* Packet */
+	u16 nstype;
+	u32 to;
+
+	/* Disable the Tx */
+	outw(TxDisable, BASE + MACCtrl1);
+
+	memcpy(txb, d, ETH_ALEN);
+	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
+	nstype = htons((u16) t);
+	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
+	memcpy(txb + ETH_HLEN, p, s);
+
+	s += ETH_HLEN;
+	s &= 0x0FFF;
+	while (s < ETH_ZLEN)
+		txb[s++] = '\0';
+
+	/* Setup the transmit descriptor */
+	tx_ring[0].length = cpu_to_le32(s | LastFrag);
+	tx_ring[0].status = cpu_to_le32(0x00000001);
+
+	/* Point to transmit descriptor */
+	outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr);
+
+	/* Enable Tx */
+	outw(TxEnable, BASE + MACCtrl1);
+	/* Trigger an immediate send */
+	outw(0, BASE + TxStatus);
+
+	to = currticks() + TX_TIME_OUT;
+	while (!(tx_ring[0].status & 0x00010000) && (currticks() < to));	/* wait */
+
+	if (currticks() >= to) {
+		printf("TX Time Out");
+	}
+	/* Disable Tx */
+	outw(TxDisable, BASE + MACCtrl1);
+
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void sundance_disable ( struct nic *nic __unused ) {
+	/* put the card in its initial state */
+	/* This function serves 3 purposes.
+	 * This disables DMA and interrupts so we don't receive
+	 *  unexpected packets or interrupts from the card after
+	 *  etherboot has finished.
+	 * This frees resources so etherboot may use
+	 *  this driver on another interface
+	 * This allows etherboot to reinitialize the interface
+	 *  if something is something goes wrong.
+	 */
+	outw(0x0000, BASE + IntrEnable);
+	/* Stop the Chipchips Tx and Rx Status */
+	outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1);
+}
+
+static struct nic_operations sundance_operations = {
+	.connect	= dummy_connect,
+	.poll		= sundance_poll,
+	.transmit	= sundance_transmit,
+	.irq		= sundance_irq,
+
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
+
+	u8 ee_data[EEPROM_SIZE];
+	u16 mii_ctl;
+	int i;
+	int speed;
+
+	if (pci->ioaddr == 0)
+		return 0;
+
+	/* BASE is used throughout to address the card */
+	BASE = pci->ioaddr;
+	printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n",
+	       pci->id->name, pci->vendor, pci->device);
+
+	/* Get the MAC Address by reading the EEPROM */
+	for (i = 0; i < 3; i++) {
+		((u16 *) ee_data)[i] =
+		    le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET));
+	}
+	/* Update the nic structure with the MAC Address */
+	for (i = 0; i < ETH_ALEN; i++) {
+		nic->node_addr[i] = ee_data[i];
+	}
+
+	/* Set the card as PCI Bus Master */
+	adjust_pci_device(pci);
+
+//      sdc->mii_if.dev = pci;
+//      sdc->mii_if.phy_id_mask = 0x1f;
+//      sdc->mii_if.reg_num_mask = 0x1f;
+
+	/* point to private storage */
+	sdc = &sdx;
+
+	sdc->nic_name = pci->id->name;
+	sdc->mtu = mtu;
+
+	pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id);
+
+	DBG ( "Device revision id: %hx\n", sdc->pci_rev_id );
+
+	/* Print out some hardware info */
+	DBG ( "%s: %s at ioaddr %hX, ",
+	      pci->id->name, nic->node_addr, (unsigned int) BASE);
+
+	sdc->mii_preamble_required = 0;
+	if (1) {
+		int phy, phy_idx = 0;
+		sdc->phys[0] = 1;	/* Default Setting */
+		sdc->mii_preamble_required++;
+		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(nic, phy, MII_BMSR);
+			if (mii_status != 0xffff && mii_status != 0x0000) {
+				sdc->phys[phy_idx++] = phy;
+				sdc->mii_if.advertising =
+				    mdio_read(nic, phy, MII_ADVERTISE);
+				if ((mii_status & 0x0040) == 0)
+					sdc->mii_preamble_required++;
+				DBG 
+				    ( "%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising );
+			}
+		}
+		sdc->mii_preamble_required--;
+		if (phy_idx == 0)
+			printf("%s: No MII transceiver found!\n",
+			       sdc->nic_name);
+		sdc->mii_if.phy_id = sdc->phys[0];
+	}
+
+	/* Parse override configuration */
+	sdc->an_enable = 1;
+	if (strcasecmp(media, "autosense") != 0) {
+		sdc->an_enable = 0;
+		if (strcasecmp(media, "100mbps_fd") == 0 ||
+		    strcasecmp(media, "4") == 0) {
+			sdc->speed = 100;
+			sdc->mii_if.full_duplex = 1;
+		} else if (strcasecmp(media, "100mbps_hd") == 0
+			   || strcasecmp(media, "3") == 0) {
+			sdc->speed = 100;
+			sdc->mii_if.full_duplex = 0;
+		} else if (strcasecmp(media, "10mbps_fd") == 0 ||
+			   strcasecmp(media, "2") == 0) {
+			sdc->speed = 10;
+			sdc->mii_if.full_duplex = 1;
+		} else if (strcasecmp(media, "10mbps_hd") == 0 ||
+			   strcasecmp(media, "1") == 0) {
+			sdc->speed = 10;
+			sdc->mii_if.full_duplex = 0;
+		} else {
+			sdc->an_enable = 1;
+		}
+	}
+	if (flowctrl == 1)
+		sdc->flowctrl = 1;
+
+	/* Fibre PHY? */
+	if (inl(BASE + ASICCtrl) & 0x80) {
+		/* Default 100Mbps Full */
+		if (sdc->an_enable) {
+			sdc->speed = 100;
+			sdc->mii_if.full_duplex = 1;
+			sdc->an_enable = 0;
+		}
+	}
+
+	/* The Linux driver uses flow control and resets the link here.  This means the
+	   mii section from above would need to be re done I believe.  Since it serves
+	   no real purpose leave it out. */
+
+	/* Force media type */
+	if (!sdc->an_enable) {
+		mii_ctl = 0;
+		mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0;
+		mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
+		mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl);
+		printf("Override speed=%d, %s duplex\n",
+		       sdc->speed,
+		       sdc->mii_if.full_duplex ? "Full" : "Half");
+	}
+
+	/* Reset the chip to erase previous misconfiguration */
+	DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) );
+	outw(0x007f, BASE + ASICCtrl + 2);
+
+	/*
+	* wait for reset to complete
+	* this is heavily inspired by the linux sundance driver
+	* according to the linux driver it can take up to 1ms for the reset
+	* to complete
+	*/
+	i = 0;
+	while(inl(BASE + ASICCtrl) & (ResetBusy << 16)) {
+		if(i++ >= 10) {
+			DBG("sundance: NIC reset did not complete.\n");
+			break;
+		}
+		udelay(100);
+	}
+
+	DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) );
+
+	sundance_reset(nic);
+	if (sdc->an_enable) {
+		u16 mii_advertise, mii_lpa;
+		mii_advertise =
+		    mdio_read(nic, sdc->phys[0], MII_ADVERTISE);
+		mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
+		mii_advertise &= mii_lpa;
+		if (mii_advertise & ADVERTISE_100FULL)
+			sdc->speed = 100;
+		else if (mii_advertise & ADVERTISE_100HALF)
+			sdc->speed = 100;
+		else if (mii_advertise & ADVERTISE_10FULL)
+			sdc->speed = 10;
+		else if (mii_advertise & ADVERTISE_10HALF)
+			sdc->speed = 10;
+	} else {
+		mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR);
+		speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+		sdc->speed = speed;
+		printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed);
+		printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
+		       "full" : "half");
+	}
+	check_duplex(nic);
+	if (sdc->flowctrl && sdc->mii_if.full_duplex) {
+		outw(inw(BASE + MulticastFilter1 + 2) | 0x0200,
+		     BASE + MulticastFilter1 + 2);
+		outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0);
+	}
+	printf("%dMbps, %s-Duplex\n", sdc->speed,
+	       sdc->mii_if.full_duplex ? "Full" : "Half");
+
+	/* point to NIC specific routines */
+	nic->nic_op	= &sundance_operations;
+
+	nic->irqno  = pci->irq;
+	nic->ioaddr = BASE;
+
+	return 1;
+}
+
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
+static int eeprom_read(long ioaddr, int location)
+{
+	int boguscnt = 10000;	/* Typical 1900 ticks */
+	outw(0x0200 | (location & 0xff), ioaddr + EECtrl);
+	do {
+		if (!(inw(ioaddr + EECtrl) & 0x8000)) {
+			return inw(ioaddr + EEData);
+		}
+	}
+	while (--boguscnt > 0);
+	return 0;
+}
+
+/*  MII transceiver control section.
+	Read and write the MII registers using software-generated serial
+	MDIO protocol.  See the MII specifications or DP83840A data sheet
+	for details.
+
+	The maximum data clock rate is 2.5 Mhz.
+	The timing is decoupled from the processor clock by flushing the write
+	from the CPU write buffer with a following read, and using PCI
+	transaction time. */
+
+#define mdio_in(mdio_addr) inb(mdio_addr)
+#define mdio_out(value, mdio_addr) outb(value, mdio_addr)
+#define mdio_delay(mdio_addr) inb(mdio_addr)
+
+enum mii_reg_bits {
+	MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput =
+	    0x0004,
+};
+#define MDIO_EnbIn  (0)
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(long mdio_addr)
+{
+	int bits = 32;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (--bits >= 0) {
+		mdio_out(MDIO_WRITE1, mdio_addr);
+		mdio_delay(mdio_addr);
+		mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+}
+
+static int
+mdio_read(struct nic *nic __unused, int phy_id, unsigned int location)
+{
+	long mdio_addr = BASE + MIICtrl;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int i, retval = 0;
+
+	if (sdc->mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval =
+		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		mdio_out(dataval, mdio_addr);
+		mdio_delay(mdio_addr);
+		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		mdio_out(MDIO_EnbIn, mdio_addr);
+		mdio_delay(mdio_addr);
+		retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data)
+					  ? 1 : 0);
+		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	return (retval >> 1) & 0xffff;
+}
+
+static void
+mdio_write(struct nic *nic __unused, int phy_id,
+	   unsigned int location, int value)
+{
+	long mdio_addr = BASE + MIICtrl;
+	int mii_cmd =
+	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int i;
+
+	if (sdc->mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval =
+		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+		mdio_out(dataval, mdio_addr);
+		mdio_delay(mdio_addr);
+		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		mdio_out(MDIO_EnbIn, mdio_addr);
+		mdio_delay(mdio_addr);
+		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	return;
+}
+
+static void set_rx_mode(struct nic *nic __unused)
+{
+	int i;
+	u16 mc_filter[4];	/* Multicast hash filter */
+	u32 rx_mode;
+
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+
+	if (sdc->mii_if.full_duplex && sdc->flowctrl)
+		mc_filter[3] |= 0x0200;
+	for (i = 0; i < 4; i++)
+		outw(mc_filter[i], BASE + MulticastFilter0 + i * 2);
+	outb(rx_mode, BASE + RxMode);
+	return;
+}
+
+static struct pci_device_id sundance_nics[] = {
+	PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0),
+	PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)", 0),
+	PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A", 0),
+};
+
+PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS );
+
+DRIVER ( "SUNDANCE/PCI", nic_driver, pci_driver, sundance_driver,
+	 sundance_probe, sundance_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.c
new file mode 100644
index 0000000..e1562d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.c
@@ -0,0 +1,3435 @@
+/* $Id$
+ * tg3.c: Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002 David S. Miller (davem at redhat.com)
+ * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik at mandrakesoft.com)
+ * Copyright (C) 2003 Eric Biederman (ebiederman at lnxi.com)  [etherboot port]
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* 11-13-2003	timlegge	Fix Issue with NetGear GA302T 
+ * 11-18-2003   ebiederm        Generalize NetGear Fix to what the code was supposed to be.
+ * 01-06-2005   Alf (Frederic Olivie) Add Dell bcm 5751 (0x1677) support
+ * 04-15-2005   Martin Vogt Add Fujitsu Siemens Computer (FSC) 0x1734 bcm 5751 0x105d support
+ */
+
+#include "etherboot.h"
+#include "nic.h"
+#include <errno.h>
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include "string.h"
+#include <mii.h>
+#include "tg3.h"
+
+#define SUPPORT_COPPER_PHY  1
+#define SUPPORT_FIBER_PHY   1
+#define SUPPORT_LINK_REPORT 1
+#define SUPPORT_PARTNO_STR  1
+#define SUPPORT_PHY_STR     1
+
+static struct tg3 tg3;
+
+/* These numbers seem to be hard coded in the NIC firmware somehow.
+ * You can't change the ring sizes, but you can change where you place
+ * them in the NIC onboard memory.
+ */
+#define TG3_RX_RING_SIZE		512
+#define TG3_DEF_RX_RING_PENDING		20	/* RX_RING_PENDING seems to be o.k. at 20 and 200 */
+#define TG3_RX_RCB_RING_SIZE	1024
+
+/*	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \
+	 512 : 1024) */
+#define TG3_TX_RING_SIZE		512
+#define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
+
+#define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RING_SIZE)
+#define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RCB_RING_SIZE)
+
+#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * TG3_TX_RING_SIZE)
+#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
+#define PREV_TX(N)		(((N) - 1) & (TG3_TX_RING_SIZE - 1))
+
+#define RX_PKT_BUF_SZ		(1536 + 2 + 64)
+
+struct eth_frame {
+	uint8_t  dst_addr[ETH_ALEN];
+	uint8_t  src_addr[ETH_ALEN];
+	uint16_t type;
+	uint8_t  data [ETH_FRAME_LEN - ETH_HLEN];
+};
+
+struct bss {
+	struct tg3_rx_buffer_desc rx_std[TG3_RX_RING_SIZE];
+	struct tg3_rx_buffer_desc rx_rcb[TG3_RX_RCB_RING_SIZE];
+	struct tg3_tx_buffer_desc tx_ring[TG3_TX_RING_SIZE];
+	struct tg3_hw_status      hw_status;
+	struct tg3_hw_stats       hw_stats;
+	unsigned char             rx_bufs[TG3_DEF_RX_RING_PENDING][RX_PKT_BUF_SZ];
+	struct eth_frame	  tx_frame[2];
+} tg3_bss __shared;
+
+/**
+ * pci_save_state - save the PCI configuration space of a device before suspending
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - buffer to hold config space context
+ *
+ * @buffer must be large enough to hold the entire PCI 2.2 config space 
+ * (>= 64 bytes).
+ */
+static int pci_save_state(struct pci_device *dev, uint32_t *buffer)
+{
+	int i;
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(dev, i * 4,&buffer[i]);
+	return 0;
+}
+
+/** 
+ * pci_restore_state - Restore the saved state of a PCI device
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - saved PCI config space
+ *
+ */
+static int pci_restore_state(struct pci_device *dev, uint32_t *buffer)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		pci_write_config_dword(dev,i * 4, buffer[i]);
+	return 0;
+}
+
+static void tg3_write_indirect_reg32(uint32_t off, uint32_t val)
+{
+	pci_write_config_dword(tg3.pdev, TG3PCI_REG_BASE_ADDR, off);
+	pci_write_config_dword(tg3.pdev, TG3PCI_REG_DATA, val);
+}
+
+#define tw32(reg,val)		tg3_write_indirect_reg32((reg),(val))
+#define tw32_mailbox(reg, val)	writel(((val) & 0xffffffff), tg3.regs + (reg))
+#define tw16(reg,val)		writew(((val) & 0xffff), tg3.regs + (reg))
+#define tw8(reg,val)		writeb(((val) & 0xff), tg3.regs + (reg))
+#define tr32(reg)		readl(tg3.regs + (reg))
+#define tr16(reg)		readw(tg3.regs + (reg))
+#define tr8(reg)		readb(tg3.regs + (reg))
+
+static void tw32_carefully(uint32_t reg, uint32_t val)
+{
+	tw32(reg, val);
+	tr32(reg);
+	udelay(100);
+}
+
+static void tw32_mailbox2(uint32_t reg, uint32_t val)
+{
+	tw32_mailbox(reg, val);
+	tr32(reg);
+}
+
+static void tg3_write_mem(uint32_t off, uint32_t val)
+{
+	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+}
+
+static void tg3_read_mem(uint32_t off, uint32_t *val)
+{
+	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_read_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+}
+
+static void tg3_disable_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+	tw32_mailbox2(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+}
+
+static void tg3_switch_clocks(struct tg3 *tp)
+{
+	uint32_t orig_clock_ctrl, clock_ctrl;
+
+	clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
+
+	orig_clock_ctrl = clock_ctrl;
+	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | 0x1f);
+	tp->pci_clock_ctrl = clock_ctrl;
+	
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
+	    (!((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	       && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) &&
+		(orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE)!=0) {
+		tw32_carefully(TG3PCI_CLOCK_CTRL, 
+			clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
+		tw32_carefully(TG3PCI_CLOCK_CTRL, 
+			clock_ctrl | (CLOCK_CTRL_ALTCLK));
+	}
+	tw32_carefully(TG3PCI_CLOCK_CTRL, clock_ctrl);
+}
+
+#define PHY_BUSY_LOOPS	5000
+
+static int tg3_readphy(struct tg3 *tp, int reg, uint32_t *val)
+{
+	uint32_t frame_val;
+	int loops, ret;
+
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
+
+	*val = 0xffffffff;
+
+	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
+	
+	tw32_carefully(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops-- > 0) {
+		udelay(10);
+		frame_val = tr32(MAC_MI_COM);
+
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+	}
+
+	ret = -EBUSY;
+	if (loops > 0) {
+		*val = frame_val & MI_COM_DATA_MASK;
+		ret = 0;
+	}
+
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+
+	return ret;
+}
+
+static int tg3_writephy(struct tg3 *tp, int reg, uint32_t val)
+{
+	uint32_t frame_val;
+	int loops, ret;
+
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
+
+	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (val & MI_COM_DATA_MASK);
+	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
+	
+	tw32_carefully(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops-- > 0) {
+		udelay(10);
+		frame_val = tr32(MAC_MI_COM);
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+	}
+
+	ret = -EBUSY;
+	if (loops > 0)
+		ret = 0;
+
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+
+	return ret;
+}
+
+static int tg3_writedsp(struct tg3 *tp, uint16_t addr, uint16_t val)
+{
+	int err;
+	err  = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, addr);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+	return err;
+}
+
+
+static void tg3_phy_set_wirespeed(struct tg3 *tp)
+{
+	uint32_t val;
+
+	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
+		return;
+
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
+	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+}
+
+static int tg3_bmcr_reset(struct tg3 *tp)
+{
+	uint32_t phy_control;
+	int limit, err;
+
+	/* OK, reset it, and poll the BMCR_RESET bit until it
+	 * clears or we time out.
+	 */
+	phy_control = BMCR_RESET;
+	err = tg3_writephy(tp, MII_BMCR, phy_control);
+	if (err != 0)
+		return -EBUSY;
+
+	limit = 5000;
+	while (limit--) {
+		err = tg3_readphy(tp, MII_BMCR, &phy_control);
+		if (err != 0)
+			return -EBUSY;
+
+		if ((phy_control & BMCR_RESET) == 0) {
+			udelay(40);
+			break;
+		}
+		udelay(10);
+	}
+	if (limit <= 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_wait_macro_done(struct tg3 *tp)
+{
+	int limit = 100;
+
+	while (limit--) {
+		uint32_t tmp32;
+
+		tg3_readphy(tp, 0x16, &tmp32);
+		if ((tmp32 & 0x1000) == 0)
+			break;
+	}
+	if (limit <= 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
+{
+	static const uint32_t test_pat[4][6] = {
+	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
+	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
+	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
+	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
+	};
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			(chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0002);
+
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
+				test_pat[chan][i]);
+
+		tg3_writephy(tp, 0x16, 0x0202);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0082);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, 0x16, 0x0802);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		for (i = 0; i < 6; i += 2) {
+			uint32_t low, high;
+
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
+			if (tg3_wait_macro_done(tp)) {
+				*resetp = 1;
+				return -EBUSY;
+			}
+			low &= 0x7fff;
+			high &= 0x000f;
+			if (low != test_pat[chan][i] ||
+			    high != test_pat[chan][i+1]) {
+				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
+
+				return -EBUSY;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int tg3_phy_reset_chanpat(struct tg3 *tp)
+{
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0002);
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
+		tg3_writephy(tp, 0x16, 0x0202);
+		if (tg3_wait_macro_done(tp))
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
+{
+	uint32_t reg32, phy9_orig;
+	int retries, do_phy_reset, err;
+
+	retries = 10;
+	do_phy_reset = 1;
+	do {
+		if (do_phy_reset) {
+			err = tg3_bmcr_reset(tp);
+			if (err)
+				return err;
+			do_phy_reset = 0;
+		}
+		
+		/* Disable transmitter and interrupt.  */
+		tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+		reg32 |= 0x3000;
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+		/* Set full-duplex, 1000 mbps.  */
+		tg3_writephy(tp, MII_BMCR,
+			BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
+
+		/* Set to master mode.  */
+		tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
+		tg3_writephy(tp, MII_TG3_CTRL,
+			(MII_TG3_CTRL_AS_MASTER |
+				MII_TG3_CTRL_ENABLE_AS_MASTER));
+
+		/* Enable SM_DSP_CLOCK and 6dB.  */
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+
+		/* Block the PHY control access.  */
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
+
+		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
+		if (!err)
+			break;
+	} while (--retries);
+
+	err = tg3_phy_reset_chanpat(tp);
+	if (err)
+		return err;
+
+	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
+	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
+
+	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
+	tg3_writephy(tp, 0x16, 0x0000);
+
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+
+	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
+
+	tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+	reg32 &= ~0x3000;
+	tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+	return err;
+}
+
+/* This will reset the tigon3 PHY if there is no valid
+ * link.
+ */
+static int tg3_phy_reset(struct tg3 *tp)
+{
+	uint32_t phy_status;
+	int err;
+
+	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
+	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
+	if (err != 0)
+		return -EBUSY;
+
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
+		err = tg3_phy_reset_5703_4_5(tp);
+		if (err)
+			return err;
+		goto out;
+	}
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+	  // Taken from Broadcom's source code
+	  tg3_writephy(tp, 0x18, 0x0c00);
+	  tg3_writephy(tp, 0x17, 0x000a);
+	  tg3_writephy(tp, 0x15, 0x310b);
+	  tg3_writephy(tp, 0x17, 0x201f);
+	  tg3_writephy(tp, 0x15, 0x9506);
+	  tg3_writephy(tp, 0x17, 0x401f);
+	  tg3_writephy(tp, 0x15, 0x14e2);
+	  tg3_writephy(tp, 0x18, 0x0400);
+	}
+	err = tg3_bmcr_reset(tp);
+	if (err)
+		return err;
+ out:
+	tg3_phy_set_wirespeed(tp);
+	return 0;
+}
+
+static void tg3_set_power_state_0(struct tg3 *tp)
+{
+	uint16_t power_control;
+	int pm = tp->pm_cap;
+
+	/* Make sure register accesses (indirect or otherwise)
+	 * will function correctly.
+	 */
+	pci_write_config_dword(tp->pdev,  TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+
+	pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control);
+
+	power_control |= PCI_PM_CTRL_PME_STATUS;
+	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
+	power_control |= 0;
+	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
+
+	tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+
+	return;
+}
+
+
+#if SUPPORT_LINK_REPORT
+static void tg3_link_report(struct tg3 *tp)
+{
+	if (!tp->carrier_ok) {
+		printf("Link is down.\n");
+	} else {
+		printf("Link is up at %d Mbps, %s duplex. %s %s %s\n",
+			(tp->link_config.active_speed == SPEED_1000 ?
+			       1000 :
+			(tp->link_config.active_speed == SPEED_100 ?
+				100 : 10)),
+			(tp->link_config.active_duplex == DUPLEX_FULL ?  
+				"full" : "half"),
+			(tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "TX" : "",
+			(tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "RX" : "",
+			(tp->tg3_flags & (TG3_FLAG_TX_PAUSE |TG3_FLAG_RX_PAUSE)) ? "flow control" : "");
+	}
+}
+#else
+#define tg3_link_report(tp)
+#endif
+
+static void tg3_setup_flow_control(struct tg3 *tp, uint32_t local_adv, uint32_t remote_adv)
+{
+	uint32_t new_tg3_flags = 0;
+
+	if (local_adv & ADVERTISE_PAUSE_CAP) {
+		if (local_adv & ADVERTISE_PAUSE_ASYM) {
+			if (remote_adv & LPA_PAUSE_CAP)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE |
+					 TG3_FLAG_TX_PAUSE);
+			else if (remote_adv & LPA_PAUSE_ASYM)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE);
+		} else {
+			if (remote_adv & LPA_PAUSE_CAP)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE |
+					 TG3_FLAG_TX_PAUSE);
+		}
+	} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+		if ((remote_adv & LPA_PAUSE_CAP) &&
+		    (remote_adv & LPA_PAUSE_ASYM))
+			new_tg3_flags |= TG3_FLAG_TX_PAUSE;
+	}
+
+	tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
+	tp->tg3_flags |= new_tg3_flags;
+
+	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
+		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+}
+
+#if SUPPORT_COPPER_PHY
+static void tg3_aux_stat_to_speed_duplex(
+	struct tg3 *tp __unused, uint32_t val, uint8_t *speed, uint8_t *duplex)
+{
+	static const uint8_t map[] = {
+		[0] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
+		[MII_TG3_AUX_STAT_10HALF >> 8]   = (SPEED_10 << 2) | DUPLEX_HALF,
+		[MII_TG3_AUX_STAT_10FULL >> 8]   = (SPEED_10 << 2) | DUPLEX_FULL,
+		[MII_TG3_AUX_STAT_100HALF >> 8]  = (SPEED_100 << 2) | DUPLEX_HALF,
+		[MII_TG3_AUX_STAT_100_4 >> 8] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
+		[MII_TG3_AUX_STAT_100FULL >> 8]  = (SPEED_100 << 2) | DUPLEX_FULL,
+		[MII_TG3_AUX_STAT_1000HALF >> 8] = (SPEED_1000 << 2) | DUPLEX_HALF,
+		[MII_TG3_AUX_STAT_1000FULL >> 8] = (SPEED_1000 << 2) | DUPLEX_FULL,
+	};
+	uint8_t result;
+	result = map[(val & MII_TG3_AUX_STAT_SPDMASK) >> 8];
+	*speed = result >> 2;
+	*duplex = result & 3;
+}
+
+static int tg3_phy_copper_begin(struct tg3 *tp)
+{
+	uint32_t new_adv;
+
+	tp->link_config.advertising =
+		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+			ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
+			ADVERTISED_Autoneg | ADVERTISED_MII);
+	
+	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) {
+		tp->link_config.advertising &=
+			~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
+	}
+	
+	new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	if (tp->link_config.advertising & ADVERTISED_10baseT_Half) {
+		new_adv |= ADVERTISE_10HALF;
+	}
+	if (tp->link_config.advertising & ADVERTISED_10baseT_Full) {
+		new_adv |= ADVERTISE_10FULL;
+	}
+	if (tp->link_config.advertising & ADVERTISED_100baseT_Half) {
+		new_adv |= ADVERTISE_100HALF;
+	}
+	if (tp->link_config.advertising & ADVERTISED_100baseT_Full) {
+		new_adv |= ADVERTISE_100FULL;
+	}
+	tg3_writephy(tp, MII_ADVERTISE, new_adv);
+	
+	if (tp->link_config.advertising &
+		(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
+		new_adv = 0;
+		if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) {
+			new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
+		}
+		if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) {
+			new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
+		}
+		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+				tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
+			new_adv |= (MII_TG3_CTRL_AS_MASTER |
+				MII_TG3_CTRL_ENABLE_AS_MASTER);
+		}
+		tg3_writephy(tp, MII_TG3_CTRL, new_adv);
+	} else {
+		tg3_writephy(tp, MII_TG3_CTRL, 0);
+	}
+
+	tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+
+	return 0;
+}
+
+static int tg3_init_5401phy_dsp(struct tg3 *tp)
+{
+	int err;
+
+	/* Turn off tap power management. */
+	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
+	
+	err |= tg3_writedsp(tp, 0x0012, 0x1804);
+	err |= tg3_writedsp(tp, 0x0013, 0x1204);
+	err |= tg3_writedsp(tp, 0x8006, 0x0132);
+	err |= tg3_writedsp(tp, 0x8006, 0x0232);
+	err |= tg3_writedsp(tp, 0x201f, 0x0a20);
+
+	udelay(40);
+
+	return err;
+}
+
+static int tg3_setup_copper_phy(struct tg3 *tp)
+{
+	int current_link_up;
+	uint32_t bmsr, dummy;
+	int i, err;
+
+	tw32_carefully(MAC_STATUS,
+		(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED
+		 | MAC_STATUS_LNKSTATE_CHANGED));
+
+	tp->mi_mode = MAC_MI_MODE_BASE;
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+
+	/* Some third-party PHYs need to be reset on link going
+	 * down.
+	 */
+	if (	(	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+			(tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)) &&
+		(tp->carrier_ok)) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (!(bmsr & BMSR_LSTATUS))
+			tg3_phy_reset(tp);
+	}
+
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+
+		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+			bmsr = 0;
+
+		if (!(bmsr & BMSR_LSTATUS)) {
+			err = tg3_init_5401phy_dsp(tp);
+			if (err)
+				return err;
+
+			tg3_readphy(tp, MII_BMSR, &bmsr);
+			for (i = 0; i < 1000; i++) {
+				udelay(10);
+				tg3_readphy(tp, MII_BMSR, &bmsr);
+				if (bmsr & BMSR_LSTATUS) {
+					udelay(40);
+					break;
+				}
+			}
+
+			if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
+			    !(bmsr & BMSR_LSTATUS) &&
+			    tp->link_config.active_speed == SPEED_1000) {
+				err = tg3_phy_reset(tp);
+				if (!err)
+					err = tg3_init_5401phy_dsp(tp);
+				if (err)
+					return err;
+			}
+		}
+	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+		/* 5701 {A0,B0} CRC bug workaround */
+		tg3_writephy(tp, 0x15, 0x0a75);
+		tg3_writephy(tp, 0x1c, 0x8c68);
+		tg3_writephy(tp, 0x1c, 0x8d68);
+		tg3_writephy(tp, 0x1c, 0x8c68);
+	}
+
+	/* Clear pending interrupts... */
+	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
+	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
+
+	tg3_writephy(tp, MII_TG3_IMASK, ~0);
+
+	if (tp->led_mode == led_mode_three_link)
+		tg3_writephy(tp, MII_TG3_EXT_CTRL,
+			     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
+	else
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
+
+	current_link_up = 0;
+
+	tg3_readphy(tp, MII_BMSR, &bmsr);
+	tg3_readphy(tp, MII_BMSR, &bmsr);
+
+	if (bmsr & BMSR_LSTATUS) {
+		uint32_t aux_stat, bmcr;
+
+		tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+		for (i = 0; i < 2000; i++) {
+			udelay(10);
+			tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+			if (aux_stat)
+				break;
+		}
+
+		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
+			&tp->link_config.active_speed,
+			&tp->link_config.active_duplex);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		if (bmcr & BMCR_ANENABLE) {
+			uint32_t gig_ctrl;
+			
+			current_link_up = 1;
+			
+			/* Force autoneg restart if we are exiting
+			 * low power mode.
+			 */
+			tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
+			if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
+				      MII_TG3_CTRL_ADV_1000_FULL))) {
+				current_link_up = 0;
+			}
+		} else {
+			current_link_up = 0;
+		}
+	}
+
+	if (current_link_up == 1 &&
+		(tp->link_config.active_duplex == DUPLEX_FULL)) {
+		uint32_t local_adv, remote_adv;
+
+		tg3_readphy(tp, MII_ADVERTISE, &local_adv);
+		local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+		tg3_readphy(tp, MII_LPA, &remote_adv);
+		remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
+
+		/* If we are not advertising full pause capability,
+		 * something is wrong.  Bring the link down and reconfigure.
+		 */
+		if (local_adv != ADVERTISE_PAUSE_CAP) {
+			current_link_up = 0;
+		} else {
+			tg3_setup_flow_control(tp, local_adv, remote_adv);
+		}
+	}
+
+	if (current_link_up == 0) {
+		uint32_t tmp;
+
+		tg3_phy_copper_begin(tp);
+
+		tg3_readphy(tp, MII_BMSR, &tmp);
+		tg3_readphy(tp, MII_BMSR, &tmp);
+		if (tmp & BMSR_LSTATUS)
+			current_link_up = 1;
+	}
+
+	tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
+	if (current_link_up == 1) {
+		if (tp->link_config.active_speed == SPEED_100 ||
+		    tp->link_config.active_speed == SPEED_10)
+			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+		else
+			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+	} else
+		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
+	if (tp->link_config.active_duplex == DUPLEX_HALF)
+		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
+
+	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+		if ((tp->led_mode == led_mode_link10) ||
+		    (current_link_up == 1 &&
+		     tp->link_config.active_speed == SPEED_10))
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+	} else {
+		if (current_link_up == 1)
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
+	}
+
+	/* ??? Without this setting Netgear GA302T PHY does not
+	 * ??? send/receive packets...
+	 * With this other PHYs cannot bring up the link
+	 */
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
+		tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
+		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
+		tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+	}
+
+	tw32_carefully(MAC_MODE, tp->mac_mode);
+
+	/* Link change polled. */
+	tw32_carefully(MAC_EVENT, 0);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
+	    current_link_up == 1 &&
+	    tp->link_config.active_speed == SPEED_1000 &&
+	    ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
+	     (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
+		udelay(120);
+		tw32_carefully(MAC_STATUS,
+			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
+		tg3_write_mem(
+			      NIC_SRAM_FIRMWARE_MBOX,
+			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
+	}
+
+	if (current_link_up != tp->carrier_ok) {
+		tp->carrier_ok = current_link_up;
+		tg3_link_report(tp);
+	}
+
+	return 0;
+}
+#else
+#define tg3_setup_copper_phy(TP) (-EINVAL)
+#endif /* SUPPORT_COPPER_PHY */
+
+#if SUPPORT_FIBER_PHY
+struct tg3_fiber_aneginfo {
+	int state;
+#define ANEG_STATE_UNKNOWN		0
+#define ANEG_STATE_AN_ENABLE		1
+#define ANEG_STATE_RESTART_INIT		2
+#define ANEG_STATE_RESTART		3
+#define ANEG_STATE_DISABLE_LINK_OK	4
+#define ANEG_STATE_ABILITY_DETECT_INIT	5
+#define ANEG_STATE_ABILITY_DETECT	6
+#define ANEG_STATE_ACK_DETECT_INIT	7
+#define ANEG_STATE_ACK_DETECT		8
+#define ANEG_STATE_COMPLETE_ACK_INIT	9
+#define ANEG_STATE_COMPLETE_ACK		10
+#define ANEG_STATE_IDLE_DETECT_INIT	11
+#define ANEG_STATE_IDLE_DETECT		12
+#define ANEG_STATE_LINK_OK		13
+#define ANEG_STATE_NEXT_PAGE_WAIT_INIT	14
+#define ANEG_STATE_NEXT_PAGE_WAIT	15
+
+	uint32_t flags;
+#define MR_AN_ENABLE		0x00000001
+#define MR_RESTART_AN		0x00000002
+#define MR_AN_COMPLETE		0x00000004
+#define MR_PAGE_RX		0x00000008
+#define MR_NP_LOADED		0x00000010
+#define MR_TOGGLE_TX		0x00000020
+#define MR_LP_ADV_FULL_DUPLEX	0x00000040
+#define MR_LP_ADV_HALF_DUPLEX	0x00000080
+#define MR_LP_ADV_SYM_PAUSE	0x00000100
+#define MR_LP_ADV_ASYM_PAUSE	0x00000200
+#define MR_LP_ADV_REMOTE_FAULT1	0x00000400
+#define MR_LP_ADV_REMOTE_FAULT2	0x00000800
+#define MR_LP_ADV_NEXT_PAGE	0x00001000
+#define MR_TOGGLE_RX		0x00002000
+#define MR_NP_RX		0x00004000
+
+#define MR_LINK_OK		0x80000000
+
+	unsigned long link_time, cur_time;
+
+	uint32_t ability_match_cfg;
+	int ability_match_count;
+
+	char ability_match, idle_match, ack_match;
+
+	uint32_t txconfig, rxconfig;
+#define ANEG_CFG_NP		0x00000080
+#define ANEG_CFG_ACK		0x00000040
+#define ANEG_CFG_RF2		0x00000020
+#define ANEG_CFG_RF1		0x00000010
+#define ANEG_CFG_PS2		0x00000001
+#define ANEG_CFG_PS1		0x00008000
+#define ANEG_CFG_HD		0x00004000
+#define ANEG_CFG_FD		0x00002000
+#define ANEG_CFG_INVAL		0x00001f06
+
+};
+#define ANEG_OK		0
+#define ANEG_DONE	1
+#define ANEG_TIMER_ENAB	2
+#define ANEG_FAILED	-1
+
+#define ANEG_STATE_SETTLE_TIME	10000
+
+static int tg3_fiber_aneg_smachine(struct tg3 *tp,
+				   struct tg3_fiber_aneginfo *ap)
+{
+	unsigned long delta;
+	uint32_t rx_cfg_reg;
+	int ret;
+
+	if (ap->state == ANEG_STATE_UNKNOWN) {
+		ap->rxconfig = 0;
+		ap->link_time = 0;
+		ap->cur_time = 0;
+		ap->ability_match_cfg = 0;
+		ap->ability_match_count = 0;
+		ap->ability_match = 0;
+		ap->idle_match = 0;
+		ap->ack_match = 0;
+	}
+	ap->cur_time++;
+
+	if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) {
+		rx_cfg_reg = tr32(MAC_RX_AUTO_NEG);
+
+		if (rx_cfg_reg != ap->ability_match_cfg) {
+			ap->ability_match_cfg = rx_cfg_reg;
+			ap->ability_match = 0;
+			ap->ability_match_count = 0;
+		} else {
+			if (++ap->ability_match_count > 1) {
+				ap->ability_match = 1;
+				ap->ability_match_cfg = rx_cfg_reg;
+			}
+		}
+		if (rx_cfg_reg & ANEG_CFG_ACK)
+			ap->ack_match = 1;
+		else
+			ap->ack_match = 0;
+
+		ap->idle_match = 0;
+	} else {
+		ap->idle_match = 1;
+		ap->ability_match_cfg = 0;
+		ap->ability_match_count = 0;
+		ap->ability_match = 0;
+		ap->ack_match = 0;
+
+		rx_cfg_reg = 0;
+	}
+
+	ap->rxconfig = rx_cfg_reg;
+	ret = ANEG_OK;
+
+	switch(ap->state) {
+	case ANEG_STATE_UNKNOWN:
+		if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
+			ap->state = ANEG_STATE_AN_ENABLE;
+
+		/* fallthru */
+	case ANEG_STATE_AN_ENABLE:
+		ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
+		if (ap->flags & MR_AN_ENABLE) {
+			ap->link_time = 0;
+			ap->cur_time = 0;
+			ap->ability_match_cfg = 0;
+			ap->ability_match_count = 0;
+			ap->ability_match = 0;
+			ap->idle_match = 0;
+			ap->ack_match = 0;
+
+			ap->state = ANEG_STATE_RESTART_INIT;
+		} else {
+			ap->state = ANEG_STATE_DISABLE_LINK_OK;
+		}
+		break;
+
+	case ANEG_STATE_RESTART_INIT:
+		ap->link_time = ap->cur_time;
+		ap->flags &= ~(MR_NP_LOADED);
+		ap->txconfig = 0;
+		tw32(MAC_TX_AUTO_NEG, 0);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32_carefully(MAC_MODE, tp->mac_mode);
+
+		ret = ANEG_TIMER_ENAB;
+		ap->state = ANEG_STATE_RESTART;
+
+		/* fallthru */
+	case ANEG_STATE_RESTART:
+		delta = ap->cur_time - ap->link_time;
+		if (delta > ANEG_STATE_SETTLE_TIME) {
+			ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
+		} else {
+			ret = ANEG_TIMER_ENAB;
+		}
+		break;
+
+	case ANEG_STATE_DISABLE_LINK_OK:
+		ret = ANEG_DONE;
+		break;
+
+	case ANEG_STATE_ABILITY_DETECT_INIT:
+		ap->flags &= ~(MR_TOGGLE_TX);
+		ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32_carefully(MAC_MODE, tp->mac_mode);
+
+		ap->state = ANEG_STATE_ABILITY_DETECT;
+		break;
+
+	case ANEG_STATE_ABILITY_DETECT:
+		if (ap->ability_match != 0 && ap->rxconfig != 0) {
+			ap->state = ANEG_STATE_ACK_DETECT_INIT;
+		}
+		break;
+
+	case ANEG_STATE_ACK_DETECT_INIT:
+		ap->txconfig |= ANEG_CFG_ACK;
+		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32_carefully(MAC_MODE, tp->mac_mode);
+
+		ap->state = ANEG_STATE_ACK_DETECT;
+
+		/* fallthru */
+	case ANEG_STATE_ACK_DETECT:
+		if (ap->ack_match != 0) {
+			if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
+			    (ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
+				ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
+			} else {
+				ap->state = ANEG_STATE_AN_ENABLE;
+			}
+		} else if (ap->ability_match != 0 &&
+			   ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+		}
+		break;
+
+	case ANEG_STATE_COMPLETE_ACK_INIT:
+		if (ap->rxconfig & ANEG_CFG_INVAL) {
+			ret = ANEG_FAILED;
+			break;
+		}
+		ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
+			       MR_LP_ADV_HALF_DUPLEX |
+			       MR_LP_ADV_SYM_PAUSE |
+			       MR_LP_ADV_ASYM_PAUSE |
+			       MR_LP_ADV_REMOTE_FAULT1 |
+			       MR_LP_ADV_REMOTE_FAULT2 |
+			       MR_LP_ADV_NEXT_PAGE |
+			       MR_TOGGLE_RX |
+			       MR_NP_RX);
+		if (ap->rxconfig & ANEG_CFG_FD)
+			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
+		if (ap->rxconfig & ANEG_CFG_HD)
+			ap->flags |= MR_LP_ADV_HALF_DUPLEX;
+		if (ap->rxconfig & ANEG_CFG_PS1)
+			ap->flags |= MR_LP_ADV_SYM_PAUSE;
+		if (ap->rxconfig & ANEG_CFG_PS2)
+			ap->flags |= MR_LP_ADV_ASYM_PAUSE;
+		if (ap->rxconfig & ANEG_CFG_RF1)
+			ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
+		if (ap->rxconfig & ANEG_CFG_RF2)
+			ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
+		if (ap->rxconfig & ANEG_CFG_NP)
+			ap->flags |= MR_LP_ADV_NEXT_PAGE;
+
+		ap->link_time = ap->cur_time;
+
+		ap->flags ^= (MR_TOGGLE_TX);
+		if (ap->rxconfig & 0x0008)
+			ap->flags |= MR_TOGGLE_RX;
+		if (ap->rxconfig & ANEG_CFG_NP)
+			ap->flags |= MR_NP_RX;
+		ap->flags |= MR_PAGE_RX;
+
+		ap->state = ANEG_STATE_COMPLETE_ACK;
+		ret = ANEG_TIMER_ENAB;
+		break;
+
+	case ANEG_STATE_COMPLETE_ACK:
+		if (ap->ability_match != 0 &&
+		    ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+			break;
+		}
+		delta = ap->cur_time - ap->link_time;
+		if (delta > ANEG_STATE_SETTLE_TIME) {
+			if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
+				ap->state = ANEG_STATE_IDLE_DETECT_INIT;
+			} else {
+				if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
+				    !(ap->flags & MR_NP_RX)) {
+					ap->state = ANEG_STATE_IDLE_DETECT_INIT;
+				} else {
+					ret = ANEG_FAILED;
+				}
+			}
+		}
+		break;
+
+	case ANEG_STATE_IDLE_DETECT_INIT:
+		ap->link_time = ap->cur_time;
+		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
+		tw32_carefully(MAC_MODE, tp->mac_mode);
+
+		ap->state = ANEG_STATE_IDLE_DETECT;
+		ret = ANEG_TIMER_ENAB;
+		break;
+
+	case ANEG_STATE_IDLE_DETECT:
+		if (ap->ability_match != 0 &&
+		    ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+			break;
+		}
+		delta = ap->cur_time - ap->link_time;
+		if (delta > ANEG_STATE_SETTLE_TIME) {
+			/* XXX another gem from the Broadcom driver :( */
+			ap->state = ANEG_STATE_LINK_OK;
+		}
+		break;
+
+	case ANEG_STATE_LINK_OK:
+		ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
+		ret = ANEG_DONE;
+		break;
+
+	case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
+		/* ??? unimplemented */
+		break;
+
+	case ANEG_STATE_NEXT_PAGE_WAIT:
+		/* ??? unimplemented */
+		break;
+
+	default:
+		ret = ANEG_FAILED;
+		break;
+	};
+
+	return ret;
+}
+
+static int tg3_setup_fiber_phy(struct tg3 *tp)
+{
+	uint32_t orig_pause_cfg;
+	uint16_t orig_active_speed;
+	uint8_t orig_active_duplex;
+	int current_link_up;
+	int i;
+
+	orig_pause_cfg =
+		(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
+				  TG3_FLAG_TX_PAUSE));
+	orig_active_speed = tp->link_config.active_speed;
+	orig_active_duplex = tp->link_config.active_duplex;
+
+	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
+	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+	tw32_carefully(MAC_MODE, tp->mac_mode);
+
+	/* Reset when initting first time or we have a link. */
+	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+	    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
+		/* Set PLL lock range. */
+		tg3_writephy(tp, 0x16, 0x8007);
+
+		/* SW reset */
+		tg3_writephy(tp, MII_BMCR, BMCR_RESET);
+
+		/* Wait for reset to complete. */
+		mdelay(5);
+
+		/* Config mode; select PMA/Ch 1 regs. */
+		tg3_writephy(tp, 0x10, 0x8411);
+
+		/* Enable auto-lock and comdet, select txclk for tx. */
+		tg3_writephy(tp, 0x11, 0x0a10);
+
+		tg3_writephy(tp, 0x18, 0x00a0);
+		tg3_writephy(tp, 0x16, 0x41ff);
+
+		/* Assert and deassert POR. */
+		tg3_writephy(tp, 0x13, 0x0400);
+		udelay(40);
+		tg3_writephy(tp, 0x13, 0x0000);
+
+		tg3_writephy(tp, 0x11, 0x0a50);
+		udelay(40);
+		tg3_writephy(tp, 0x11, 0x0a10);
+
+		/* Wait for signal to stabilize */
+		mdelay(150);
+
+		/* Deselect the channel register so we can read the PHYID
+		 * later.
+		 */
+		tg3_writephy(tp, 0x10, 0x8011);
+	}
+
+	/* Disable link change interrupt.  */
+	tw32_carefully(MAC_EVENT, 0);
+
+	current_link_up = 0;
+	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
+		if (!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) {
+			struct tg3_fiber_aneginfo aninfo;
+			int status = ANEG_FAILED;
+			unsigned int tick;
+			uint32_t tmp;
+
+			memset(&aninfo, 0, sizeof(aninfo));
+			aninfo.flags |= (MR_AN_ENABLE);
+
+			tw32(MAC_TX_AUTO_NEG, 0);
+
+			tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
+			tw32_carefully(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
+
+			tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
+
+			aninfo.state = ANEG_STATE_UNKNOWN;
+			aninfo.cur_time = 0;
+			tick = 0;
+			while (++tick < 195000) {
+				status = tg3_fiber_aneg_smachine(tp, &aninfo);
+				if (status == ANEG_DONE ||
+				    status == ANEG_FAILED)
+					break;
+
+				udelay(1);
+			}
+
+			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
+			tw32_carefully(MAC_MODE, tp->mac_mode);
+
+			if (status == ANEG_DONE &&
+			    (aninfo.flags &
+			     (MR_AN_COMPLETE | MR_LINK_OK |
+			      MR_LP_ADV_FULL_DUPLEX))) {
+				uint32_t local_adv, remote_adv;
+
+				local_adv = ADVERTISE_PAUSE_CAP;
+				remote_adv = 0;
+				if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
+					remote_adv |= LPA_PAUSE_CAP;
+				if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
+					remote_adv |= LPA_PAUSE_ASYM;
+
+				tg3_setup_flow_control(tp, local_adv, remote_adv);
+
+				tp->tg3_flags |=
+					TG3_FLAG_GOT_SERDES_FLOWCTL;
+				current_link_up = 1;
+			}
+			for (i = 0; i < 60; i++) {
+				udelay(20);
+				tw32_carefully(MAC_STATUS,
+					(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
+				if ((tr32(MAC_STATUS) &
+				     (MAC_STATUS_SYNC_CHANGED |
+				      MAC_STATUS_CFG_CHANGED)) == 0)
+					break;
+			}
+			if (current_link_up == 0 &&
+			    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
+				current_link_up = 1;
+			}
+		} else {
+			/* Forcing 1000FD link up. */
+			current_link_up = 1;
+		}
+	}
+
+	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+	tw32_carefully(MAC_MODE, tp->mac_mode);
+
+	tp->hw_status->status =
+		(SD_STATUS_UPDATED |
+		 (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
+
+	for (i = 0; i < 100; i++) {
+		udelay(20);
+		tw32_carefully(MAC_STATUS,
+			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
+		if ((tr32(MAC_STATUS) &
+		     (MAC_STATUS_SYNC_CHANGED |
+		      MAC_STATUS_CFG_CHANGED)) == 0)
+			break;
+	}
+
+	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
+		current_link_up = 0;
+
+	if (current_link_up == 1) {
+		tp->link_config.active_speed = SPEED_1000;
+		tp->link_config.active_duplex = DUPLEX_FULL;
+	} else {
+		tp->link_config.active_speed = SPEED_INVALID;
+		tp->link_config.active_duplex = DUPLEX_INVALID;
+	}
+
+	if (current_link_up != tp->carrier_ok) {
+		tp->carrier_ok = current_link_up;
+		tg3_link_report(tp);
+	} else {
+		uint32_t now_pause_cfg =
+			tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
+					 TG3_FLAG_TX_PAUSE);
+		if (orig_pause_cfg != now_pause_cfg ||
+		    orig_active_speed != tp->link_config.active_speed ||
+		    orig_active_duplex != tp->link_config.active_duplex)
+			tg3_link_report(tp);
+	}
+
+	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
+		tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
+		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
+			tw32_carefully(MAC_MODE, tp->mac_mode);
+		}
+	}
+
+	return 0;
+}
+#else
+#define tg3_setup_fiber_phy(TP) (-EINVAL)
+#endif /* SUPPORT_FIBER_PHY */
+
+static int tg3_setup_phy(struct tg3 *tp)
+{
+	int err;
+
+	if (tp->phy_id == PHY_ID_SERDES) {
+		err = tg3_setup_fiber_phy(tp);
+	} else {
+		err = tg3_setup_copper_phy(tp);
+	}
+
+	if (tp->link_config.active_speed == SPEED_1000 &&
+	    tp->link_config.active_duplex == DUPLEX_HALF)
+		tw32(MAC_TX_LENGTHS,
+		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+		      (6 << TX_LENGTHS_IPG_SHIFT) |
+		      (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+	else
+		tw32(MAC_TX_LENGTHS,
+		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+		      (6 << TX_LENGTHS_IPG_SHIFT) |
+		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+
+	return err;
+}
+
+
+#define MAX_WAIT_CNT 1000
+
+/* To stop a block, clear the enable bit and poll till it
+ * clears.  
+ */
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit)
+{
+	unsigned int i;
+	uint32_t val;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+		switch(ofs) {
+		case RCVLSC_MODE:
+		case DMAC_MODE:
+		case MBFREE_MODE:
+		case BUFMGR_MODE:
+		case MEMARB_MODE:
+			/* We can't enable/disable these bits of the
+			 * 5705 or 5787, just say success.
+			 */
+			return 0;
+		default:
+			break;
+		}
+	}
+	val = tr32(ofs);
+	val &= ~enable_bit;
+	tw32(ofs, val);
+	tr32(ofs);
+
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
+		val = tr32(ofs);
+		if ((val & enable_bit) == 0)
+			break;
+	}
+
+	if (i == MAX_WAIT_CNT) {
+		printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3x\n",
+		       ofs, enable_bit );
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int tg3_abort_hw(struct tg3 *tp)
+{
+	int i, err;
+	uint32_t val;
+
+	tg3_disable_ints(tp);
+
+	tp->rx_mode &= ~RX_MODE_ENABLE;
+	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
+
+	err  = tg3_stop_block(tp, RCVBDI_MODE,   RCVBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLPC_MODE,   RCVLPC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLSC_MODE,   RCVLSC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDBDI_MODE,  RCVDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDCC_MODE,   RCVDCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVCC_MODE,    RCVCC_MODE_ENABLE);
+
+	err |= tg3_stop_block(tp, SNDBDS_MODE,   SNDBDS_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDI_MODE,   SNDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RDMAC_MODE,    RDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDC_MODE,   SNDBDC_MODE_ENABLE);
+	if (err)
+		goto out;
+
+	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+	tw32_carefully(MAC_MODE, tp->mac_mode);
+
+	tp->tx_mode &= ~TX_MODE_ENABLE;
+	tw32_carefully(MAC_TX_MODE, tp->tx_mode);
+
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
+		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
+			break;
+	}
+	if (i >= MAX_WAIT_CNT) {
+		printf("tg3_abort_hw timed out TX_MODE_ENABLE will not clear MAC_TX_MODE=%x\n",
+		       (unsigned int) tr32(MAC_TX_MODE));
+		return -ENODEV;
+	}
+
+	err  = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, WDMAC_MODE,  WDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
+
+	val = tr32(FTQ_RESET);
+	val |= FTQ_RESET_DMA_READ_QUEUE | FTQ_RESET_DMA_HIGH_PRI_READ |
+	       FTQ_RESET_SEND_BD_COMPLETION | FTQ_RESET_DMA_WRITE |
+	       FTQ_RESET_DMA_HIGH_PRI_WRITE | FTQ_RESET_SEND_DATA_COMPLETION |
+	       FTQ_RESET_HOST_COALESCING | FTQ_RESET_MAC_TX |
+	       FTQ_RESET_RX_BD_COMPLETE | FTQ_RESET_RX_LIST_PLCMT |
+               FTQ_RESET_RX_DATA_COMPLETION;
+	tw32(FTQ_RESET, val);
+
+	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
+	if (err)
+		goto out;
+
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+out:
+	return err;
+}
+
+static void tg3_chip_reset(struct tg3 *tp)
+{
+	uint32_t val;
+
+	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
+		/* Force NVRAM to settle.
+		 * This deals with a chip bug which can result in EEPROM
+		 * corruption.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+			int i;
+	
+			tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+			for (i = 0; i < 100000; i++) {
+				if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+					break;
+				udelay(10);
+			}
+		}
+	}
+	/* In Etherboot we don't need to worry about the 5701
+	 * REG_WRITE_BUG because we do all register writes indirectly.
+	 */
+
+	// Alf: here patched
+	/* do the reset */
+	val = GRC_MISC_CFG_CORECLK_RESET;
+	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+		if (tr32(0x7e2c) == 0x60) {
+			tw32(0x7e2c, 0x20);
+		}
+		if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+			tw32(GRC_MISC_CFG, (1 << 29));
+			val |= (1 << 29);
+		}
+	}
+	
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
+		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+	}
+
+	// Alf : Please VALIDATE THIS.
+	// It is necessary in my case (5751) to prevent a reboot, but
+	// I have no idea about a side effect on any other version.
+	// It appears to be what's done in tigon3.c from Broadcom
+	if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+	  tw32(GRC_MISC_CFG, 0x20000000) ;
+	  val |= 0x20000000 ;
+	}
+
+	tw32(GRC_MISC_CFG, val);
+
+	/* Flush PCI posted writes.  The normal MMIO registers
+	 * are inaccessible at this time so this is the only
+	 * way to make this reliably.  I tried to use indirect
+	 * register read/write but this upset some 5701 variants.
+	 */
+	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
+
+	udelay(120);
+
+	/* Re-enable indirect register accesses. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* Set MAX PCI retry to zero. */
+	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+		val |= PCISTATE_RETRY_SAME_DMA;
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+	pci_restore_state(tp->pdev, tp->pci_cfg_state);
+
+	/* Make sure PCI-X relaxed ordering bit is clear. */
+	pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
+	val &= ~PCIX_CAPS_RELAXED_ORDERING;
+	pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+
+	tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+
+	if (((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0) &&
+		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
+		tp->pci_clock_ctrl |=
+			(CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE);
+		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	}
+
+	tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+}
+
+static void tg3_stop_fw(struct tg3 *tp)
+{
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		uint32_t val;
+		int i;
+
+		tg3_write_mem(NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
+		val = tr32(GRC_RX_CPU_EVENT);
+		val |= (1 << 14);
+		tw32(GRC_RX_CPU_EVENT, val);
+
+		/* Wait for RX cpu to ACK the event.  */
+		for (i = 0; i < 100; i++) {
+			if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
+				break;
+			udelay(1);
+		}
+	}
+}
+
+static int tg3_restart_fw(struct tg3 *tp, uint32_t state)
+{
+	uint32_t val;
+	int i;
+	
+	tg3_write_mem(NIC_SRAM_FIRMWARE_MBOX, 
+		NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+	/* Wait for firmware initialization to complete. */
+	for (i = 0; i < 100000; i++) {
+		tg3_read_mem(NIC_SRAM_FIRMWARE_MBOX, &val);
+		if (val == (uint32_t) ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+			break;
+		udelay(10);
+	}
+	if (i >= 100000 &&
+		    !(tp->tg3_flags2 & TG3_FLG2_SUN_5704) &&
+		    !(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
+		printf ( "Firmware will not restart magic=%#x\n",
+			val );
+		return -ENODEV;
+	}
+	if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+	  state = DRV_STATE_SUSPEND;
+	}
+
+	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+	    (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)) {
+	  // Enable PCIE bug fix
+	  tg3_read_mem(0x7c00, &val);
+	  tg3_write_mem(0x7c00, val | 0x02000000);
+	}
+	tg3_write_mem(NIC_SRAM_FW_DRV_STATE_MBOX, state);
+	return 0;
+}
+
+static int tg3_halt(struct tg3 *tp)
+{
+	tg3_stop_fw(tp);
+	tg3_abort_hw(tp);
+	tg3_chip_reset(tp);
+	return tg3_restart_fw(tp, DRV_STATE_UNLOAD);
+}
+
+static void __tg3_set_mac_addr(struct tg3 *tp)
+{
+	uint32_t addr_high, addr_low;
+	int i;
+
+	addr_high = ((tp->nic->node_addr[0] << 8) |
+		     tp->nic->node_addr[1]);
+	addr_low = ((tp->nic->node_addr[2] << 24) |
+		    (tp->nic->node_addr[3] << 16) |
+		    (tp->nic->node_addr[4] <<  8) |
+		    (tp->nic->node_addr[5] <<  0));
+	for (i = 0; i < 4; i++) {
+		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
+		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
+	}
+
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
+		(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
+		(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)) {
+		for(i = 0; i < 12; i++) {
+			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
+			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
+		}
+	}
+	addr_high = (tp->nic->node_addr[0] +
+		     tp->nic->node_addr[1] +
+		     tp->nic->node_addr[2] +
+		     tp->nic->node_addr[3] +
+		     tp->nic->node_addr[4] +
+		     tp->nic->node_addr[5]) &
+		TX_BACKOFF_SEED_MASK;
+	tw32(MAC_TX_BACKOFF_SEED, addr_high);
+}
+
+static void tg3_set_bdinfo(struct tg3 *tp, uint32_t bdinfo_addr,
+			   dma_addr_t mapping, uint32_t maxlen_flags,
+			   uint32_t nic_addr)
+{
+	tg3_write_mem((bdinfo_addr +
+		       TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
+		      ((uint64_t) mapping >> 32));
+	tg3_write_mem((bdinfo_addr +
+		       TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
+		      ((uint64_t) mapping & 0xffffffff));
+	tg3_write_mem((bdinfo_addr +
+		       TG3_BDINFO_MAXLEN_FLAGS),
+		       maxlen_flags);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		tg3_write_mem((bdinfo_addr + TG3_BDINFO_NIC_ADDR), nic_addr);
+	}
+}
+
+
+static void tg3_init_rings(struct tg3 *tp)
+{
+	unsigned i;
+
+	/* Zero out the tg3 variables */
+	memset(&tg3_bss, 0, sizeof(tg3_bss));
+	tp->rx_std    = &tg3_bss.rx_std[0];
+	tp->rx_rcb    = &tg3_bss.rx_rcb[0];
+	tp->tx_ring   = &tg3_bss.tx_ring[0];
+	tp->hw_status = &tg3_bss.hw_status;
+	tp->hw_stats  = &tg3_bss.hw_stats;
+	tp->mac_mode  = 0;
+
+
+	/* Initialize tx/rx rings for packet processing.
+	 *
+	 * The chip has been shut down and the driver detached from
+	 * the networking, so no interrupts or new tx packets will
+	 * end up in the driver.
+	 */
+
+	/* Initialize invariants of the rings, we only set this
+	 * stuff once.  This works because the card does not
+	 * write into the rx buffer posting rings.
+	 */
+	for (i = 0; i < TG3_RX_RING_SIZE; i++) {
+		struct tg3_rx_buffer_desc *rxd;
+
+		rxd = &tp->rx_std[i];
+		rxd->idx_len = (RX_PKT_BUF_SZ - 2 - 64)	<< RXD_LEN_SHIFT;
+		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
+		rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT));
+
+		/* Note where the receive buffer for the ring is placed */
+		rxd->addr_hi = 0;
+		rxd->addr_lo = virt_to_bus(
+			&tg3_bss.rx_bufs[i%TG3_DEF_RX_RING_PENDING][2]);
+	}
+}
+
+#define TG3_WRITE_SETTINGS(TABLE) \
+do { \
+	const uint32_t *_table, *_end; \
+	_table = TABLE; \
+	_end = _table + sizeof(TABLE)/sizeof(TABLE[0]);  \
+	for(; _table < _end; _table += 2) { \
+		tw32(_table[0], _table[1]); \
+	} \
+} while(0)
+
+
+/* initialize/reset the tg3 */
+static int tg3_setup_hw(struct tg3 *tp)
+{
+	uint32_t val, rdmac_mode;
+	int i, err, limit;
+
+	/* Simply don't support setups with extremly buggy firmware in etherboot */
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+		printf("Error 5701_A0 firmware bug detected\n");
+		return -EINVAL;
+	}
+
+	tg3_disable_ints(tp);
+
+	/* Originally this was all in tg3_init_hw */
+
+	/* Force the chip into D0. */
+	tg3_set_power_state_0(tp);
+
+	tg3_switch_clocks(tp);
+
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	// This should go somewhere else
+#define T3_PCIE_CAPABILITY_ID_REG           0xD0
+#define T3_PCIE_CAPABILITY_ID               0x10
+#define T3_PCIE_CAPABILITY_REG              0xD2
+
+	/* Originally this was all in tg3_reset_hw */
+
+	tg3_stop_fw(tp);
+
+	/* No need to call tg3_abort_hw here, it is called before tg3_setup_hw. */
+
+	tg3_chip_reset(tp);
+
+	tw32(GRC_MODE, tp->grc_mode);  /* Redundant? */
+
+	err = tg3_restart_fw(tp, DRV_STATE_START);
+	if (err)
+		return err;
+
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
+	}
+	tw32_carefully(MAC_MODE, tp->mac_mode);
+
+
+	/* This works around an issue with Athlon chipsets on
+	 * B3 tigon3 silicon.  This bit has no effect on any
+	 * other revision.
+	 * Alf: Except 5750 ! (which reboots)
+	 */
+
+        if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+	  tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+	tw32_carefully(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+		val = tr32(TG3PCI_PCISTATE);
+		val |= PCISTATE_RETRY_SAME_DMA;
+		tw32(TG3PCI_PCISTATE, val);
+	}
+
+	/* Descriptor ring init may make accesses to the
+	 * NIC SRAM area to setup the TX descriptors, so we
+	 * can only do this after the hardware has been
+	 * successfully reset.
+	 */
+	tg3_init_rings(tp);
+
+	/* Clear statistics/status block in chip */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		for (i = NIC_SRAM_STATS_BLK;
+		     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
+		     i += sizeof(uint32_t)) {
+			tg3_write_mem(i, 0);
+			udelay(40);
+		}
+	}
+
+	/* This value is determined during the probe time DMA
+	 * engine test, tg3_setup_dma.
+	 */
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
+			  GRC_MODE_4X_NIC_SEND_RINGS |
+			  GRC_MODE_NO_TX_PHDR_CSUM |
+			  GRC_MODE_NO_RX_PHDR_CSUM);
+	tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
+	tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
+	tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
+
+	tw32(GRC_MODE,
+		tp->grc_mode | 
+		(GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
+
+	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
+	tw32(GRC_MISC_CFG,
+	     (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
+
+	/* Initialize MBUF/DESC pool. */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+		/* Do nothing. */
+	} else if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
+		(tp->pci_chip_rev_id != CHIPREV_ID_5721)) {
+		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
+		else
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
+		tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
+		tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
+	}
+	if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) {
+		tw32(BUFMGR_MB_RDMA_LOW_WATER,
+		     tp->bufmgr_config.mbuf_read_dma_low_water);
+		tw32(BUFMGR_MB_MACRX_LOW_WATER,
+		     tp->bufmgr_config.mbuf_mac_rx_low_water);
+		tw32(BUFMGR_MB_HIGH_WATER,
+		     tp->bufmgr_config.mbuf_high_water);
+	} else {
+		tw32(BUFMGR_MB_RDMA_LOW_WATER,
+		     tp->bufmgr_config.mbuf_read_dma_low_water_jumbo);
+		tw32(BUFMGR_MB_MACRX_LOW_WATER,
+		     tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo);
+		tw32(BUFMGR_MB_HIGH_WATER,
+		     tp->bufmgr_config.mbuf_high_water_jumbo);
+	}
+	tw32(BUFMGR_DMA_LOW_WATER,
+	     tp->bufmgr_config.dma_low_water);
+	tw32(BUFMGR_DMA_HIGH_WATER,
+	     tp->bufmgr_config.dma_high_water);
+
+	tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
+	for (i = 0; i < 2000; i++) {
+		if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
+			break;
+		udelay(10);
+	}
+	if (i >= 2000) {
+		printf("tg3_setup_hw cannot enable BUFMGR\n");
+		return -ENODEV;
+	}
+
+	tw32(FTQ_RESET, 0xffffffff);
+	tw32(FTQ_RESET, 0x00000000);
+	for (i = 0; i < 2000; i++) {
+		if (tr32(FTQ_RESET) == 0x00000000)
+			break;
+		udelay(10);
+	}
+	if (i >= 2000) {
+		printf("tg3_setup_hw cannot reset FTQ\n");
+		return -ENODEV;
+	}
+
+	/* Initialize TG3_BDINFO's at:
+	 *  RCVDBDI_STD_BD:	standard eth size rx ring
+	 *  RCVDBDI_JUMBO_BD:	jumbo frame rx ring
+	 *  RCVDBDI_MINI_BD:	small frame rx ring (??? does not work)
+	 *
+	 * like so:
+	 *  TG3_BDINFO_HOST_ADDR:	high/low parts of DMA address of ring
+	 *  TG3_BDINFO_MAXLEN_FLAGS:	(rx max buffer size << 16) |
+	 *                              ring attribute flags
+	 *  TG3_BDINFO_NIC_ADDR:	location of descriptors in nic SRAM
+	 *
+	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
+	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
+	 *
+	 * ??? No space allocated for mini receive ring? :(
+	 *
+	 * The size of each ring is fixed in the firmware, but the location is
+	 * configurable.
+	 */
+	{
+		static const uint32_t table_all[] = {
+			/* Setup replenish thresholds. */
+			RCVBDI_STD_THRESH, TG3_DEF_RX_RING_PENDING / 8,
+
+			/* Etherboot lives below 4GB */
+			RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
+			RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC,
+		};
+		static const uint32_t table_not_5705[] = {
+			/* Buffer maximum length */
+			RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT,
+			
+			/* Disable the mini frame rx ring */
+			RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,	BDINFO_FLAGS_DISABLED,
+			
+			/* Disable the jumbo frame rx ring */
+			RCVBDI_JUMBO_THRESH, 0,
+			RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED,
+			
+			
+		};
+		TG3_WRITE_SETTINGS(table_all);
+		tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, 
+			virt_to_bus(tp->rx_std));
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+			tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
+				RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT);
+		} else {
+			TG3_WRITE_SETTINGS(table_not_5705);
+		}
+	}
+
+	
+	/* There is only one send ring on 5705 and 5787, no need to explicitly
+	 * disable the others.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
+		/* Clear out send RCB ring in SRAM. */
+		for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
+			tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED);
+	}
+
+	tp->tx_prod = 0;
+	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	tw32_mailbox2(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+
+	tg3_set_bdinfo(tp,
+		NIC_SRAM_SEND_RCB,
+		virt_to_bus(tp->tx_ring),
+		(TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
+		NIC_SRAM_TX_BUFFER_DESC);
+
+	/* There is only one receive return ring on 5705 and 5787, no need to
+	 * explicitly disable the others.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
+		for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) {
+			tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS,
+				BDINFO_FLAGS_DISABLED);
+		}
+	}
+
+	tp->rx_rcb_ptr = 0;
+	tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
+
+	tg3_set_bdinfo(tp,
+		NIC_SRAM_RCV_RET_RCB,
+		virt_to_bus(tp->rx_rcb),
+		(TG3_RX_RCB_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
+		0);
+
+	tp->rx_std_ptr = TG3_DEF_RX_RING_PENDING;
+	tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
+		     tp->rx_std_ptr);
+
+	tw32_mailbox2(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, 0);
+
+	/* Initialize MAC address and backoff seed. */
+	__tg3_set_mac_addr(tp);
+
+	/* Calculate RDMAC_MODE setting early, we need it to determine
+	 * the RCVLPC_STATE_ENABLE mask.
+	 */
+	rdmac_mode = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+		RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+		RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+		RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+		RDMAC_MODE_LNGREAD_ENAB);
+	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+		rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		if (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+			if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
+				!(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+				rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+			}
+		}
+	}
+
+	/* Setup host coalescing engine. */
+	tw32(HOSTCC_MODE, 0);
+	for (i = 0; i < 2000; i++) {
+		if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE))
+			break;
+		udelay(10);
+	}
+
+	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
+		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+	tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
+
+	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+				       GRC_LCLCTRL_GPIO_OUTPUT1);
+	tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
+	tr32(MAILBOX_INTERRUPT_0);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		tw32_carefully(DMAC_MODE, DMAC_MODE_ENABLE);
+	}
+
+	val = (	WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
+		WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
+		WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
+		WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
+		WDMAC_MODE_LNGREAD_ENAB);
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
+		((tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0) &&
+		!(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+		val |= WDMAC_MODE_RX_ACCEL;
+	}
+
+	/* Host coalescing bug fix */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+		val |= (1 << 29);
+
+	tw32_carefully(WDMAC_MODE, val);
+
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
+		val = tr32(TG3PCI_X_CAPS);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+			val &= PCIX_CAPS_BURST_MASK;
+			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
+			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+			if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+				val |= (tp->split_mode_max_reqs <<
+					PCIX_CAPS_SPLIT_SHIFT);
+		}
+		tw32(TG3PCI_X_CAPS, val);
+	}
+
+	tw32_carefully(RDMAC_MODE, rdmac_mode);
+	{
+		static const uint32_t table_all[] = {
+			/* MTU + ethernet header + FCS + optional VLAN tag */
+			MAC_RX_MTU_SIZE, ETH_MAX_MTU + ETH_HLEN + 8,
+			
+			/* The slot time is changed by tg3_setup_phy if we
+			 * run at gigabit with half duplex.
+			 */
+			MAC_TX_LENGTHS,	
+			(2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+			(6 << TX_LENGTHS_IPG_SHIFT) |
+			(32 << TX_LENGTHS_SLOT_TIME_SHIFT),
+			
+			/* Receive rules. */
+			MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS,
+			RCVLPC_CONFIG, 0x0181,
+			
+			/* Receive/send statistics. */
+			RCVLPC_STATS_ENABLE, 0xffffff,
+			RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE,
+			SNDDATAI_STATSENAB, 0xffffff,
+			SNDDATAI_STATSCTRL, (SNDDATAI_SCTRL_ENABLE |SNDDATAI_SCTRL_FASTUPD),
+			
+			/* Host coalescing engine */
+			HOSTCC_RXCOL_TICKS, 0,
+			HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS,
+			HOSTCC_RXMAX_FRAMES, 1,
+			HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES,
+			HOSTCC_RXCOAL_MAXF_INT, 1,
+			HOSTCC_TXCOAL_MAXF_INT, 0,
+			
+			/* Status/statistics block address. */
+			/* Etherboot lives below 4GB, so HIGH == 0 */
+			HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
+
+			/* No need to enable 32byte coalesce mode. */
+			HOSTCC_MODE, HOSTCC_MODE_ENABLE | 0,
+			
+			RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE,
+			RCVLPC_MODE, RCVLPC_MODE_ENABLE,
+			
+			RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE,
+
+			SNDDATAC_MODE, SNDDATAC_MODE_ENABLE,
+			SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE,
+			RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB,
+			RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ,
+			SNDDATAI_MODE, SNDDATAI_MODE_ENABLE,
+			SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE,
+			SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE,
+			
+			/* Accept all multicast frames. */
+			MAC_HASH_REG_0, 0xffffffff,
+			MAC_HASH_REG_1, 0xffffffff,
+			MAC_HASH_REG_2, 0xffffffff,
+			MAC_HASH_REG_3, 0xffffffff,
+		};
+		static const uint32_t table_not_5705[] = {
+			/* Host coalescing engine */
+			HOSTCC_RXCOAL_TICK_INT, 0,
+			HOSTCC_TXCOAL_TICK_INT, 0,
+
+			/* Status/statistics block address. */
+			/* Etherboot lives below 4GB, so HIGH == 0 */
+			HOSTCC_STAT_COAL_TICKS, DEFAULT_STAT_COAL_TICKS,
+			HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
+			HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK,
+			HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK,
+
+			RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE,
+
+			MBFREE_MODE, MBFREE_MODE_ENABLE,
+		};
+		TG3_WRITE_SETTINGS(table_all);
+		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+			virt_to_bus(tp->hw_stats));
+		tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+			virt_to_bus(tp->hw_status));
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
+			TG3_WRITE_SETTINGS(table_not_5705);
+		}
+	}
+
+	tp->tx_mode = TX_MODE_ENABLE;
+	tw32_carefully(MAC_TX_MODE, tp->tx_mode);
+
+	tp->rx_mode = RX_MODE_ENABLE;
+	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
+
+	tp->mi_mode = MAC_MI_MODE_BASE;
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+
+	tw32(MAC_LED_CTRL, 0);
+	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tw32_carefully(MAC_RX_MODE, RX_MODE_RESET);
+	}
+	tp->rx_mode |= RX_MODE_KEEP_VLAN_TAG; /* drop tagged vlan packets */
+	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
+		tw32(MAC_SERDES_CFG, 0x616000);
+
+	/* Prevent chip from dropping frames when flow control
+	 * is enabled.
+	 */
+	tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
+	tr32(MAC_LOW_WMARK_MAX_RX_FRAME);
+
+	err = tg3_setup_phy(tp);
+
+	/* Ignore CRC stats */
+
+	/* Initialize receive rules. */
+	tw32(MAC_RCV_RULE_0,  0xc2000000 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
+
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750))
+		limit = 8;
+	else
+		limit = 16;
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+		limit -= 4;
+	switch (limit) {
+	case 16:	tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
+	case 15:	tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
+	case 14:	tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
+	case 13:	tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
+	case 12:	tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
+	case 11:	tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
+	case 10:	tw32(MAC_RCV_RULE_9,  0);  tw32(MAC_RCV_VALUE_9,  0);
+	case 9:		tw32(MAC_RCV_RULE_8,  0);  tw32(MAC_RCV_VALUE_8,  0);
+	case 8:		tw32(MAC_RCV_RULE_7,  0);  tw32(MAC_RCV_VALUE_7,  0);
+	case 7:		tw32(MAC_RCV_RULE_6,  0);  tw32(MAC_RCV_VALUE_6,  0);
+	case 6:		tw32(MAC_RCV_RULE_5,  0);  tw32(MAC_RCV_VALUE_5,  0);
+	case 5:		tw32(MAC_RCV_RULE_4,  0);  tw32(MAC_RCV_VALUE_4,  0);
+	case 4:		/* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
+	case 3:		/* tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0); */
+	case 2:
+	case 1:
+	default:
+		break;
+	};
+
+	return err;
+}
+
+
+
+/* Chips other than 5700/5701 use the NVRAM for fetching info. */
+static void tg3_nvram_init(struct tg3 *tp)
+{
+	tw32(GRC_EEPROM_ADDR,
+	     (EEPROM_ADDR_FSM_RESET |
+	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
+	       EEPROM_ADDR_CLKPERD_SHIFT)));
+
+	mdelay(1);
+
+	/* Enable seeprom accesses. */
+	tw32_carefully(GRC_LOCAL_CTRL,
+		tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+		uint32_t nvcfg1 = tr32(NVRAM_CFG1);
+
+		tp->tg3_flags |= TG3_FLAG_NVRAM;
+		if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
+			if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
+				tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+		} else {
+			nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+			tw32(NVRAM_CFG1, nvcfg1);
+		}
+
+	} else {
+		tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
+	}
+}
+
+
+static int tg3_nvram_read_using_eeprom(
+	struct tg3 *tp __unused, uint32_t offset, uint32_t *val)
+{
+	uint32_t tmp;
+	int i;
+
+	if (offset > EEPROM_ADDR_ADDR_MASK ||
+		(offset % 4) != 0) {
+		return -EINVAL;
+	}
+
+	tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
+					EEPROM_ADDR_DEVID_MASK |
+					EEPROM_ADDR_READ);
+	tw32(GRC_EEPROM_ADDR,
+	     tmp |
+	     (0 << EEPROM_ADDR_DEVID_SHIFT) |
+	     ((offset << EEPROM_ADDR_ADDR_SHIFT) &
+	      EEPROM_ADDR_ADDR_MASK) |
+	     EEPROM_ADDR_READ | EEPROM_ADDR_START);
+
+	for (i = 0; i < 10000; i++) {
+		tmp = tr32(GRC_EEPROM_ADDR);
+
+		if (tmp & EEPROM_ADDR_COMPLETE)
+			break;
+		udelay(100);
+	}
+	if (!(tmp & EEPROM_ADDR_COMPLETE)) {
+		return -EBUSY;
+	}
+
+	*val = tr32(GRC_EEPROM_DATA);
+	return 0;
+}
+
+static int tg3_nvram_read(struct tg3 *tp, uint32_t offset, uint32_t *val)
+{
+	int i, saw_done_clear;
+
+	if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
+		return tg3_nvram_read_using_eeprom(tp, offset, val);
+
+	if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
+		offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
+			  NVRAM_BUFFERED_PAGE_POS) +
+			(offset % NVRAM_BUFFERED_PAGE_SIZE);
+
+	if (offset > NVRAM_ADDR_MSK)
+		return -EINVAL;
+
+	tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+	for (i = 0; i < 1000; i++) {
+		if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+			break;
+		udelay(20);
+	}
+
+	tw32(NVRAM_ADDR, offset);
+	tw32(NVRAM_CMD,
+	     NVRAM_CMD_RD | NVRAM_CMD_GO |
+	     NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+
+	/* Wait for done bit to clear then set again. */
+	saw_done_clear = 0;
+	for (i = 0; i < 1000; i++) {
+		udelay(10);
+		if (!saw_done_clear &&
+		    !(tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
+			saw_done_clear = 1;
+		else if (saw_done_clear &&
+			 (tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
+			break;
+	}
+	if (i >= 1000) {
+		tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
+		return -EBUSY;
+	}
+
+	*val = bswap_32(tr32(NVRAM_RDDATA));
+	tw32(NVRAM_SWARB, 0x20);
+
+	return 0;
+}
+
+struct subsys_tbl_ent {
+	uint16_t subsys_vendor, subsys_devid;
+	uint32_t phy_id;
+};
+
+static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
+	/* Broadcom boards. */
+	{ 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
+	{ 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
+	{ 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
+	{ 0x14e4, 0x0003, PHY_ID_SERDES  }, /* BCM95700A9 */
+	{ 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
+	{ 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
+	{ 0x14e4, 0x0007, PHY_ID_SERDES  }, /* BCM95701A7 */
+	{ 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
+	{ 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
+	{ 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */
+	{ 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */
+
+	/* 3com boards. */
+	{ PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
+	{ PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
+	/* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX },     3C996CT */
+	/* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX },     3C997T */
+	{ PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES  }, /* 3C996SX */
+	/* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX },     3C997SZ */
+	{ PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
+	{ PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
+
+	/* DELL boards. */
+	{ PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
+	{ PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
+	{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
+	{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
+	{ PCI_VENDOR_ID_DELL, 0x0179, PHY_ID_BCM5751 }, /* EtherXpress */
+	
+	/* Fujitsu Siemens Computer */
+	{ PCI_VENDOR_ID_FSC, 0x105d, PHY_ID_BCM5751 }, /* Futro C200 */	
+
+	/* Compaq boards. */
+	{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
+	{ PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
+	{ PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES  }, /* CHANGELING */
+	{ PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
+	{ PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }  /* NC7780_2 */
+};
+
+static int tg3_phy_probe(struct tg3 *tp)
+{
+	uint32_t eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
+	uint32_t hw_phy_id, hw_phy_id_masked;
+	enum phy_led_mode eeprom_led_mode;
+	uint32_t val;
+	unsigned i;
+	int eeprom_signature_found, err;
+
+	tp->phy_id = PHY_ID_INVALID;
+
+	for (i = 0; i < sizeof(subsys_id_to_phy_id)/sizeof(subsys_id_to_phy_id[0]); i++) {
+		if ((subsys_id_to_phy_id[i].subsys_vendor == tp->subsystem_vendor) &&
+			(subsys_id_to_phy_id[i].subsys_devid == tp->subsystem_device)) {
+			tp->phy_id = subsys_id_to_phy_id[i].phy_id;
+			break;
+		}
+	}
+
+	eeprom_phy_id = PHY_ID_INVALID;
+	eeprom_led_mode = led_mode_auto;
+	eeprom_signature_found = 0;
+	tg3_read_mem(NIC_SRAM_DATA_SIG, &val);
+	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+		uint32_t nic_cfg;
+
+		tg3_read_mem(NIC_SRAM_DATA_CFG, &nic_cfg);
+		tp->nic_sram_data_cfg = nic_cfg;
+
+		eeprom_signature_found = 1;
+
+		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
+		    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) {
+			eeprom_phy_id = PHY_ID_SERDES;
+		} else {
+			uint32_t nic_phy_id;
+
+			tg3_read_mem(NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
+			if (nic_phy_id != 0) {
+				uint32_t id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
+				uint32_t id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
+
+				eeprom_phy_id  = (id1 >> 16) << 10;
+				eeprom_phy_id |= (id2 & 0xfc00) << 16;
+				eeprom_phy_id |= (id2 & 0x03ff) <<  0;
+			}
+		}
+
+		switch (nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK) {
+		case NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD:
+			eeprom_led_mode = led_mode_three_link;
+			break;
+
+		case NIC_SRAM_DATA_CFG_LED_LINK_SPD:
+			eeprom_led_mode = led_mode_link10;
+			break;
+
+		default:
+			eeprom_led_mode = led_mode_auto;
+			break;
+		};
+		if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
+			(nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) {
+			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+		}
+
+		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
+			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
+			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
+	}
+
+	/* Now read the physical PHY_ID from the chip and verify
+	 * that it is sane.  If it doesn't look good, we fall back
+	 * to either the hard-coded table based PHY_ID and failing
+	 * that the value found in the eeprom area.
+	 */
+	err  = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
+	err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
+
+	hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
+	hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
+	hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
+
+	hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
+
+	if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
+		tp->phy_id = hw_phy_id;
+	} else {
+		/* phy_id currently holds the value found in the
+		 * subsys_id_to_phy_id[] table or PHY_ID_INVALID
+		 * if a match was not found there.
+		 */
+		if (tp->phy_id == PHY_ID_INVALID) {
+			if (!eeprom_signature_found ||
+			    !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK))
+				return -ENODEV;
+			tp->phy_id = eeprom_phy_id;
+		}
+	}
+
+	err = tg3_phy_reset(tp);
+	if (err)
+		return err;
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+		uint32_t mii_tg3_ctrl;
+		
+		/* These chips, when reset, only advertise 10Mb
+		 * capabilities.  Fix that.
+		 */
+		err  = tg3_writephy(tp, MII_ADVERTISE,
+				    (ADVERTISE_CSMA |
+				     ADVERTISE_PAUSE_CAP |
+				     ADVERTISE_10HALF |
+				     ADVERTISE_10FULL |
+				     ADVERTISE_100HALF |
+				     ADVERTISE_100FULL));
+		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
+				MII_TG3_CTRL_ADV_1000_FULL |
+				MII_TG3_CTRL_AS_MASTER |
+				MII_TG3_CTRL_ENABLE_AS_MASTER);
+		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+			mii_tg3_ctrl = 0;
+
+		err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl);
+		err |= tg3_writephy(tp, MII_BMCR,
+				    (BMCR_ANRESTART | BMCR_ANENABLE));
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+		tg3_writedsp(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		tg3_writephy(tp, 0x1c, 0x8d68);
+		tg3_writephy(tp, 0x1c, 0x8d68);
+	}
+
+	/* Enable Ethernet at WireSpeed */
+	tg3_phy_set_wirespeed(tp);
+
+	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
+		err = tg3_init_5401phy_dsp(tp);
+	}
+
+	/* Determine the PHY led mode. 
+	 * Be careful if this gets set wrong it can result in an inability to 
+	 * establish a link.
+	 */
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tp->led_mode = led_mode_three_link;
+	}
+	else if (tp->subsystem_vendor == PCI_VENDOR_ID_DELL) {
+		tp->led_mode = led_mode_link10;
+	} else {
+		tp->led_mode = led_mode_three_link;
+		if (eeprom_signature_found &&
+		    eeprom_led_mode != led_mode_auto)
+			tp->led_mode = eeprom_led_mode;
+	}
+
+	if (tp->phy_id == PHY_ID_SERDES)
+		tp->link_config.advertising =
+			(ADVERTISED_1000baseT_Half |
+			 ADVERTISED_1000baseT_Full |
+			 ADVERTISED_Autoneg |
+			 ADVERTISED_FIBRE);
+	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+		tp->link_config.advertising &=
+			~(ADVERTISED_1000baseT_Half |
+			  ADVERTISED_1000baseT_Full);
+
+	return err;
+}
+
+#if SUPPORT_PARTNO_STR
+static void tg3_read_partno(struct tg3 *tp)
+{
+	unsigned char vpd_data[256];
+	int i;
+
+	for (i = 0; i < 256; i += 4) {
+		uint32_t tmp;
+
+		if (tg3_nvram_read(tp, 0x100 + i, &tmp))
+			goto out_not_found;
+
+		vpd_data[i + 0] = ((tmp >>  0) & 0xff);
+		vpd_data[i + 1] = ((tmp >>  8) & 0xff);
+		vpd_data[i + 2] = ((tmp >> 16) & 0xff);
+		vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+	}
+
+	/* Now parse and find the part number. */
+	for (i = 0; i < 256; ) {
+		unsigned char val = vpd_data[i];
+		int block_end;
+
+		if (val == 0x82 || val == 0x91) {
+			i = (i + 3 +
+			     (vpd_data[i + 1] +
+			      (vpd_data[i + 2] << 8)));
+			continue;
+		}
+
+		if (val != 0x90)
+			goto out_not_found;
+
+		block_end = (i + 3 +
+			     (vpd_data[i + 1] +
+			      (vpd_data[i + 2] << 8)));
+		i += 3;
+		while (i < block_end) {
+			if (vpd_data[i + 0] == 'P' &&
+			    vpd_data[i + 1] == 'N') {
+				int partno_len = vpd_data[i + 2];
+
+				if (partno_len > 24)
+					goto out_not_found;
+
+				memcpy(tp->board_part_number,
+				       &vpd_data[i + 3],
+				       partno_len);
+
+				/* Success. */
+				return;
+			}
+		}
+
+		/* Part number not found. */
+		goto out_not_found;
+	}
+
+out_not_found:
+	memcpy(tp->board_part_number, "none", sizeof("none"));
+}
+#else
+#define tg3_read_partno(TP) ((TP)->board_part_number[0] = '\0')
+#endif
+
+static int tg3_get_invariants(struct tg3 *tp)
+{
+	uint32_t misc_ctrl_reg;
+	uint32_t pci_state_reg, grc_misc_cfg;
+	uint16_t pci_cmd;
+	uint8_t  pci_latency;
+	uint32_t val ;
+	int err;
+
+	/* Read the subsystem vendor and device ids */
+	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_VENDOR_ID, &tp->subsystem_vendor);
+	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_ID, &tp->subsystem_device);
+
+	/* The sun_5704 code needs infrastructure etherboot does have
+	 * ignore it for now.
+	 */
+
+	/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
+	 * reordering to the mailbox registers done by the host
+	 * controller can cause major troubles.  We read back from
+	 * every mailbox register write to force the writes to be
+	 * posted to the chip in order.
+	 *
+	 * TG3_FLAG_MBOX_WRITE_REORDER has been forced on.
+	 */
+
+	/* Force memory write invalidate off.  If we leave it on,
+	 * then on 5700_BX chips we have to enable a workaround.
+	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
+	 * to match the cacheline size.  The Broadcom driver have this
+	 * workaround but turns MWI off all the times so never uses
+	 * it.  This seems to suggest that the workaround is insufficient.
+	 */
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
+	/* Also, force SERR#/PERR# in PCI command. */
+	pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+
+	/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
+	 * has the register indirect write enable bit set before
+	 * we try to access any of the MMIO registers.  It is also
+	 * critical that the PCI-X hw workaround situation is decided
+	 * before that as well.
+	 */
+	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, &misc_ctrl_reg);
+
+	tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT);
+
+	/* Initialize misc host control in PCI block. */
+	tp->misc_host_ctrl |= (misc_ctrl_reg &
+			       MISC_HOST_CTRL_CHIPREV);
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER, &pci_latency);
+	if (pci_latency < 64) {
+		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, 64);
+	}
+
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg);
+
+	/* If this is a 5700 BX chipset, and we are in PCI-X
+	 * mode, enable register write workaround.
+	 *
+	 * The workaround is to use indirect register accesses
+	 * for all chip writes not to mailbox registers.
+	 *
+	 * In etherboot to simplify things we just always use this work around.
+	 */
+	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
+		tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
+	}
+	/* Back to back register writes can cause problems on the 5701,
+	 * the workaround is to read back all reg writes except those to
+	 * mailbox regs.
+	 * In etherboot we always use indirect register accesses so
+	 * we don't see this.
+	 */
+
+	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
+		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
+	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
+		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
+
+	/* Chip-specific fixup from Broadcom driver */
+	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
+		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
+	}
+
+	/* determine if it is PCIE system */
+	// Alf : I have no idea what this is about...
+	// But it's definitely usefull
+	val = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
+	if (val)
+		tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+
+	/* Force the chip into D0. */
+	tg3_set_power_state_0(tp);
+
+	/* Etherboot does not ask the tg3 to do checksums */
+	/* Etherboot does not ask the tg3 to do jumbo frames */
+	/* Ehterboot does not ask the tg3 to use WakeOnLan. */
+
+	/* A few boards don't want Ethernet at WireSpeed phy feature */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
+		((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+			(tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
+			(tp->pci_chip_rev_id != CHIPREV_ID_5705_A1))) {
+		tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
+	}
+
+	/* Avoid tagged irq status etherboot does not use irqs */
+
+	/* Only 5701 and later support tagged irq status mode.
+	 * Also, 5788 chips cannot use tagged irq status.
+	 *
+	 * However, since etherboot does not use irqs avoid tagged irqs
+	 * status  because the interrupt condition is more difficult to
+	 * fully clear in that mode.
+	 */
+	
+	/* Since some 5700_AX && 5700_BX have problems with 32BYTE
+	 * coalesce_mode, and the rest work fine anything set.
+	 * Don't enable HOST_CC_MODE_32BYTE in etherboot.
+	 */
+
+	/* Initialize MAC MI mode, polling disabled. */
+	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
+
+	/* Initialize data/descriptor byte/word swapping. */
+	tw32(GRC_MODE, tp->grc_mode);
+
+	tg3_switch_clocks(tp);
+
+	/* Clear this out for sanity. */
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	/* Etherboot does not need to check if the PCIX_TARGET_HWBUG
+	 * is needed.  It always uses it.
+	 */
+	
+	udelay(50);
+	tg3_nvram_init(tp);
+
+	/* The TX descriptors will reside in main memory.
+	 */
+
+	/* See which board we are using.
+	 */
+	grc_misc_cfg = tr32(GRC_MISC_CFG);
+	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
+		tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
+		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	    (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
+	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
+		tp->tg3_flags2 |= TG3_FLG2_IS_5788;
+
+#define PCI_DEVICE_ID_TIGON3_5901	0x170d
+#define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
+
+	/* these are limited to 10/100 only */
+	if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) &&
+		    ((grc_misc_cfg == 0x8000) || (grc_misc_cfg == 0x4000))) ||
+		((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+			(tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM) &&
+			((tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901) ||
+				(tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2)))) {
+		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
+	}
+
+	err = tg3_phy_probe(tp);
+	if (err) {
+		printf("phy probe failed, err %d\n", err);
+	}
+
+	tg3_read_partno(tp);
+
+
+	/* 5700 BX chips need to have their TX producer index mailboxes
+	 * written twice to workaround a bug.
+	 * In etherboot we do this unconditionally to simplify things.
+	 */
+
+	/* 5700 chips can get confused if TX buffers straddle the
+	 * 4GB address boundary in some cases.
+	 * 
+	 * In etherboot we can ignore the problem as etherboot lives below 4GB.
+	 */
+
+	/* In etherboot wake-on-lan is unconditionally disabled */
+	return err;
+}
+
+static int  tg3_get_device_address(struct tg3 *tp)
+{
+	struct nic *nic = tp->nic;
+	uint32_t hi, lo, mac_offset;
+
+	if (PCI_FUNC(tp->pdev->busdevfn) == 0)
+		mac_offset = 0x7c;
+	else
+		mac_offset = 0xcc;
+
+	/* First try to get it from MAC address mailbox. */
+	tg3_read_mem(NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
+	if ((hi >> 16) == 0x484b) {
+		nic->node_addr[0] = (hi >>  8) & 0xff;
+		nic->node_addr[1] = (hi >>  0) & 0xff;
+
+		tg3_read_mem(NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo);
+		nic->node_addr[2] = (lo >> 24) & 0xff;
+		nic->node_addr[3] = (lo >> 16) & 0xff;
+		nic->node_addr[4] = (lo >>  8) & 0xff;
+		nic->node_addr[5] = (lo >>  0) & 0xff;
+	}
+	/* Next, try NVRAM. */
+	else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
+		nic->node_addr[0] = ((hi >> 16) & 0xff);
+		nic->node_addr[1] = ((hi >> 24) & 0xff);
+		nic->node_addr[2] = ((lo >>  0) & 0xff);
+		nic->node_addr[3] = ((lo >>  8) & 0xff);
+		nic->node_addr[4] = ((lo >> 16) & 0xff);
+		nic->node_addr[5] = ((lo >> 24) & 0xff);
+	}
+	/* Finally just fetch it out of the MAC control regs. */
+	else {
+		hi = tr32(MAC_ADDR_0_HIGH);
+		lo = tr32(MAC_ADDR_0_LOW);
+
+		nic->node_addr[5] = lo & 0xff;
+		nic->node_addr[4] = (lo >> 8) & 0xff;
+		nic->node_addr[3] = (lo >> 16) & 0xff;
+		nic->node_addr[2] = (lo >> 24) & 0xff;
+		nic->node_addr[1] = hi & 0xff;
+		nic->node_addr[0] = (hi >> 8) & 0xff;
+	}
+
+	return 0;
+}
+
+
+static int tg3_setup_dma(struct tg3 *tp)
+{
+	tw32(TG3PCI_CLOCK_CTRL, 0);
+
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) {
+		tp->dma_rwctrl =
+			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+			(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
+			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
+		}
+	} else {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x00 << DMA_RWCTRL_MIN_DMA_SHIFT);
+		else
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+
+		/* Wheee, some more chip bugs... */
+		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
+			uint32_t ccval = tr32(TG3PCI_CLOCK_CTRL) & 0x1f;
+
+			if ((ccval == 0x6) || (ccval == 0x7)) {
+				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+			}
+		}
+	}
+
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
+		tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
+	}
+
+	/*
+	  Alf : Tried that, but it does not work. Should be this way though :-(
+	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+    	  tp->dma_rwctrl |= 0x001f0000;
+	}
+	*/
+	tp->dma_rwctrl |= DMA_RWCTRL_ASSERT_ALL_BE;
+
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	return 0;
+}
+
+static void tg3_init_link_config(struct tg3 *tp)
+{
+	tp->link_config.advertising =
+		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+		 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+		 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
+		 ADVERTISED_Autoneg | ADVERTISED_MII);
+	tp->carrier_ok = 0;
+	tp->link_config.active_speed = SPEED_INVALID;
+	tp->link_config.active_duplex = DUPLEX_INVALID;
+}
+
+
+#if SUPPORT_PHY_STR
+static const char * tg3_phy_string(struct tg3 *tp)
+{
+	switch (tp->phy_id & PHY_ID_MASK) {
+	case PHY_ID_BCM5400:	return "5400";
+	case PHY_ID_BCM5401:	return "5401";
+	case PHY_ID_BCM5411:	return "5411";
+	case PHY_ID_BCM5701:	return "5701";
+	case PHY_ID_BCM5703:	return "5703";
+	case PHY_ID_BCM5704:	return "5704";
+        case PHY_ID_BCM5705:    return "5705";
+        case PHY_ID_BCM5750:    return "5750";
+	case PHY_ID_BCM5751:	return "5751"; 
+	case PHY_ID_BCM5787:	return "5787";
+	case PHY_ID_BCM8002:	return "8002/serdes";
+	case PHY_ID_SERDES:	return "serdes";
+	default:		return "unknown";
+	};
+}
+#else
+#define tg3_phy_string(TP) "?"
+#endif
+
+
+static void tg3_poll_link(struct tg3 *tp)
+{
+	uint32_t mac_stat;
+
+	mac_stat = tr32(MAC_STATUS);
+	if (tp->phy_id == PHY_ID_SERDES) {
+		if (tp->carrier_ok?
+			(mac_stat & MAC_STATUS_LNKSTATE_CHANGED):
+			(mac_stat & MAC_STATUS_PCS_SYNCED)) {
+			tw32_carefully(MAC_MODE, tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK);
+			tw32_carefully(MAC_MODE, tp->mac_mode);
+
+			tg3_setup_phy(tp);
+		}
+	}
+	else {
+		if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED) {
+			tg3_setup_phy(tp);
+		}
+	}
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static void tg3_ack_irqs(struct tg3 *tp)
+{
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+		/*
+		 * writing any value to intr-mbox-0 clears PCI INTA# and
+		 * chip-internal interrupt pending events.
+		 * writing non-zero to intr-mbox-0 additional tells the
+		 * NIC to stop sending us irqs, engaging "in-intr-handler"
+		 * event coalescing.
+		 */
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 
+			0x00000001);
+		/*
+		 * Flush PCI write.  This also guarantees that our
+		 * status block has been flushed to host memory.
+		 */
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		tp->hw_status->status &= ~SD_STATUS_UPDATED;
+	}
+}
+
+static int tg3_poll(struct nic *nic, int retrieve)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+
+	struct tg3 *tp = &tg3;
+	int result;
+
+	result = 0;
+
+	if ( (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) && !retrieve ) 
+	  return 1;
+
+	tg3_ack_irqs(tp);
+
+	if (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) {
+		struct tg3_rx_buffer_desc *desc;
+		unsigned int len;
+		desc = &tp->rx_rcb[tp->rx_rcb_ptr];
+		if ((desc->opaque & RXD_OPAQUE_RING_MASK) == RXD_OPAQUE_RING_STD) {
+			len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
+			
+			nic->packetlen = len;
+			memcpy(nic->packet, bus_to_virt(desc->addr_lo), len);
+			result = 1;
+		}
+		tp->rx_rcb_ptr = (tp->rx_rcb_ptr + 1) % TG3_RX_RCB_RING_SIZE;
+		
+		/* ACK the status ring */
+		tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, tp->rx_rcb_ptr);
+
+		/* Refill RX ring. */
+		if (result) {
+			tp->rx_std_ptr = (tp->rx_std_ptr + 1) % TG3_RX_RING_SIZE;
+			tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_std_ptr);
+		}
+	}
+	tg3_poll_link(tp);
+	return result;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+#if 0
+static void tg3_set_txd(struct tg3 *tp, int entry,
+	dma_addr_t mapping, int len, uint32_t flags,
+	uint32_t mss_and_is_end)
+{
+	struct tg3_tx_buffer_desc *txd =  &tp->tx_ring[entry];
+	int is_end = (mss_and_is_end & 0x1);
+	if (is_end) {
+		flags |= TXD_FLAG_END;
+	}
+
+	txd->addr_hi   = 0;
+	txd->addr_lo   = mapping & 0xffffffff;
+	txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+	txd->vlan_tag  = 0 << TXD_VLAN_TAG_SHIFT;
+}
+#endif
+
+static void tg3_transmit(struct nic *nic, const char *dst_addr,
+	unsigned int type, unsigned int size, const char *packet)
+{
+	static int frame_idx;
+	struct eth_frame *frame;
+	
+	/* send the packet to destination */
+	struct tg3_tx_buffer_desc *txd;
+	struct tg3 *tp;
+	uint32_t entry;
+	int i;
+
+	/* Wait until there is a free packet frame */
+	tp = &tg3;
+	i = 0;
+	entry = tp->tx_prod;
+	while((tp->hw_status->idx[0].tx_consumer != entry) &&
+		(tp->hw_status->idx[0].tx_consumer != PREV_TX(entry))) {
+		mdelay(10);	/* give the nick a chance */
+		if (++i > 500) { /* timeout 5s for transmit */
+			printf("transmit timed out\n");
+			tg3_halt(tp);
+			tg3_setup_hw(tp);
+			return;
+		}
+	}
+	if (i != 0) {
+		printf("#");
+	}
+	
+	/* Copy the packet to the our local buffer */
+	frame = &tg3_bss.tx_frame[frame_idx];
+	memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
+	memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
+	frame->type = htons(type);
+	memset(frame->data, 0, sizeof(frame->data));
+	memcpy(frame->data, packet, size);
+
+	/* Setup the ring buffer entry to transmit */
+	txd            = &tp->tx_ring[entry];
+	txd->addr_hi   = 0; /* Etherboot runs under 4GB */
+	txd->addr_lo   = virt_to_bus(frame);
+	txd->len_flags = ((size + ETH_HLEN) << TXD_LEN_SHIFT) | TXD_FLAG_END;
+	txd->vlan_tag  = 0 << TXD_VLAN_TAG_SHIFT;
+
+	/* Advance to the next entry */
+	entry = NEXT_TX(entry);
+	frame_idx ^= 1;
+
+	/* Packets are ready, update Tx producer idx local and on card */
+	tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
+	tw32_mailbox2((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
+	tp->tx_prod = entry;
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void tg3_disable ( struct nic *nic __unused ) {
+	struct tg3 *tp = &tg3;
+	/* put the card in its initial state */
+	/* This function serves 3 purposes.
+	 * This disables DMA and interrupts so we don't receive
+	 *  unexpected packets or interrupts from the card after
+	 *  etherboot has finished. 
+	 * This frees resources so etherboot may use
+	 *  this driver on another interface
+	 * This allows etherboot to reinitialize the interface
+	 *  if something is something goes wrong.
+	 */
+	tg3_halt(tp);
+	tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE|TG3_FLAG_GOT_SERDES_FLOWCTL);
+	tp->carrier_ok = 0;
+	iounmap((void *)tp->regs);
+}
+
+/**************************************************************************
+IRQ - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void tg3_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations tg3_operations = {
+	.connect	= dummy_connect,
+	.poll		= tg3_poll,
+	.transmit	= tg3_transmit,
+	.irq		= tg3_irq,
+
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+You should omit the last argument struct pci_device * for a non-PCI NIC
+***************************************************************************/
+static int tg3_probe ( struct nic *nic, struct pci_device *pdev ) {
+
+	struct tg3 *tp = &tg3;
+	unsigned long tg3reg_base, tg3reg_len;
+	int i, err, pm_cap;
+
+	memset(tp, 0, sizeof(*tp));
+
+	adjust_pci_device(pdev);
+
+	nic->irqno  = 0;
+        nic->ioaddr = pdev->ioaddr;
+
+	/* Find power-management capability. */
+	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm_cap == 0) {
+		printf("Cannot find PowerManagement capability, aborting.\n");
+		return 0;
+	}
+	tg3reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	if (tg3reg_base == -1UL) {
+		printf("Unuseable bar\n");
+		return 0;
+	}
+	tg3reg_len  = pci_bar_size(pdev,  PCI_BASE_ADDRESS_0);
+
+	tp->pdev       = pdev;
+	tp->nic        = nic;
+	tp->pm_cap     = pm_cap;
+	tp->rx_mode    = 0;
+	tp->tx_mode    = 0;
+	tp->mi_mode    = MAC_MI_MODE_BASE;
+	tp->tg3_flags  = 0 & ~TG3_FLAG_INIT_COMPLETE; 
+	
+	/* The word/byte swap controls here control register access byte
+	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
+	 * setting below.
+	 */
+	tp->misc_host_ctrl =
+		MISC_HOST_CTRL_MASK_PCI_INT |
+		MISC_HOST_CTRL_WORD_SWAP |
+		MISC_HOST_CTRL_INDIR_ACCESS |
+		MISC_HOST_CTRL_PCISTATE_RW;
+
+	/* The NONFRM (non-frame) byte/word swap controls take effect
+	 * on descriptor entries, anything which isn't packet data.
+	 *
+	 * The StrongARM chips on the board (one for tx, one for rx)
+	 * are running in big-endian mode.
+	 */
+	tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
+			GRC_MODE_WSWAP_NONFRM_DATA);
+#if __BYTE_ORDER == __BIG_ENDIAN
+	tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
+#endif
+	tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
+	if (tp->regs == 0UL) {
+		printf("Cannot map device registers, aborting\n");
+		return 0;
+	}
+
+	tg3_init_link_config(tp);
+
+	err = tg3_get_invariants(tp);
+	if (err) {
+		printf("Problem fetching invariants of chip, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	err = tg3_get_device_address(tp);
+	if (err) {
+		printf("Could not obtain valid ethernet address, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
+
+	tg3_setup_dma(tp);
+
+	/* Now that we have fully setup the chip, save away a snapshot
+	 * of the PCI config space.  We need to restore this after
+	 * GRC_MISC_CFG core clock resets and some resume events.
+	 */
+	pci_save_state(tp->pdev, tp->pci_cfg_state);
+
+	printf("Tigon3 [partno(%s) rev %hx PHY(%s)] (PCI%s:%s:%s)\n",
+		tp->board_part_number,
+		tp->pci_chip_rev_id,
+		tg3_phy_string(tp),
+		((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""),
+		((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ?
+			((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") :
+			((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")),
+		((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"));
+
+
+	err = tg3_setup_hw(tp); 
+	if (err) {
+		goto err_out_disable;
+	} 
+	tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+
+	/* Wait for a reasonable time for the link to come up */
+	tg3_poll_link(tp);
+	for(i = 0; !tp->carrier_ok && (i < VALID_LINK_TIMEOUT*100); i++) {
+		mdelay(1);
+		tg3_poll_link(tp);
+	}
+	if (!tp->carrier_ok){
+		printf("Valid link not established\n");
+		goto err_out_disable;
+	}
+
+	nic->nic_op	= &tg3_operations;
+	return 1;
+
+ err_out_iounmap:
+	iounmap((void *)tp->regs);
+	return 0;
+ err_out_disable:
+	tg3_disable(nic);
+	return 0;
+}
+
+
+static struct pci_device_id tg3_nics[] = {
+PCI_ROM(0x14e4, 0x1644, "tg3-5700",        "Broadcom Tigon 3 5700", 0),
+PCI_ROM(0x14e4, 0x1645, "tg3-5701",        "Broadcom Tigon 3 5701", 0),
+PCI_ROM(0x14e4, 0x1646, "tg3-5702",        "Broadcom Tigon 3 5702", 0),
+PCI_ROM(0x14e4, 0x1647, "tg3-5703",        "Broadcom Tigon 3 5703", 0),
+PCI_ROM(0x14e4, 0x1648, "tg3-5704",        "Broadcom Tigon 3 5704", 0),
+PCI_ROM(0x14e4, 0x164d, "tg3-5702FE",      "Broadcom Tigon 3 5702FE", 0),
+PCI_ROM(0x14e4, 0x1653, "tg3-5705",        "Broadcom Tigon 3 5705", 0),
+PCI_ROM(0x14e4, 0x1654, "tg3-5705_2",      "Broadcom Tigon 3 5705_2", 0),
+PCI_ROM(0x14e4, 0x1659, "tg3-5721",        "Broadcom Tigon 3 5721", 0),
+PCI_ROM(0x14e4, 0x165d, "tg3-5705M",       "Broadcom Tigon 3 5705M", 0),
+PCI_ROM(0x14e4, 0x165e, "tg3-5705M_2",     "Broadcom Tigon 3 5705M_2", 0),
+PCI_ROM(0x14e4, 0x1677, "tg3-5751",        "Broadcom Tigon 3 5751", 0),
+PCI_ROM(0x14e4, 0x167a, "tg3-5754",        "Broadcom Tigon 3 5754", 0),
+PCI_ROM(0x14e4, 0x1693, "tg3-5787",	   "Broadcom Tigon 3 5787", 0),
+PCI_ROM(0x14e4, 0x1696, "tg3-5782",        "Broadcom Tigon 3 5782", 0),
+PCI_ROM(0x14e4, 0x169a, "tg3-5786",        "Broadcom Tigon 3 5786", 0),
+PCI_ROM(0x14e4, 0x169c, "tg3-5788",        "Broadcom Tigon 3 5788", 0),
+PCI_ROM(0x14e4, 0x169d, "tg3-5789",        "Broadcom Tigon 3 5789", 0),
+PCI_ROM(0x14e4, 0x16a6, "tg3-5702X",       "Broadcom Tigon 3 5702X", 0),
+PCI_ROM(0x14e4, 0x16a7, "tg3-5703X",       "Broadcom Tigon 3 5703X", 0),
+PCI_ROM(0x14e4, 0x16a8, "tg3-5704S",       "Broadcom Tigon 3 5704S", 0),
+PCI_ROM(0x14e4, 0x16c6, "tg3-5702A3",      "Broadcom Tigon 3 5702A3", 0),
+PCI_ROM(0x14e4, 0x16c7, "tg3-5703A3",      "Broadcom Tigon 3 5703A3", 0),
+PCI_ROM(0x14e4, 0x170d, "tg3-5901",        "Broadcom Tigon 3 5901", 0),
+PCI_ROM(0x14e4, 0x170e, "tg3-5901_2",      "Broadcom Tigon 3 5901_2", 0),
+PCI_ROM(0x1148, 0x4400, "tg3-9DXX",        "Syskonnect 9DXX", 0),
+PCI_ROM(0x1148, 0x4500, "tg3-9MXX",        "Syskonnect 9MXX", 0),
+PCI_ROM(0x173b, 0x03e8, "tg3-ac1000",      "Altima AC1000", 0),
+PCI_ROM(0x173b, 0x03e9, "tg3-ac1001",      "Altima AC1001", 0),
+PCI_ROM(0x173b, 0x03ea, "tg3-ac9100",      "Altima AC9100", 0),
+PCI_ROM(0x173b, 0x03eb, "tg3-ac1003",      "Altima AC1003", 0),
+PCI_ROM(0x0e11, 0x00ca, "tg3-hp",	   "HP Tigon 3", 0),
+};
+
+PCI_DRIVER ( tg3_driver, tg3_nics, PCI_NO_CLASS );
+
+DRIVER ( "TG3", nic_driver, pci_driver, tg3_driver,
+	 tg3_probe, tg3_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.h
new file mode 100644
index 0000000..deeb0ad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tg3.h
@@ -0,0 +1,2121 @@
+/* $Id$
+ * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002 David S. Miller (davem at redhat.com)
+ * Copyright (C) 2001 Jeff Garzik (jgarzik at mandrakesoft.com)
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _T3_H
+#define _T3_H
+
+#include "stdint.h"
+
+typedef unsigned long dma_addr_t;
+
+/* From mii.h */
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
+#define ADVERTISED_100baseT_Half	(1 << 2)
+#define ADVERTISED_100baseT_Full	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+#define ADVERTISED_Autoneg		(1 << 6)
+#define ADVERTISED_TP			(1 << 7)
+#define ADVERTISED_AUI			(1 << 8)
+#define ADVERTISED_MII			(1 << 9)
+#define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_BNC			(1 << 11)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit. */
+#define SPEED_10		0
+#define SPEED_100		1
+#define SPEED_1000		2
+#define SPEED_INVALID           3
+
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+#define DUPLEX_INVALID          0x02
+
+/* Which connector port. */
+#define PORT_TP			0x00
+#define PORT_AUI		0x01
+#define PORT_MII		0x02
+#define PORT_FIBRE		0x03
+#define PORT_BNC		0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL		0x00
+#define XCVR_EXTERNAL		0x01
+#define XCVR_DUMMY1		0x02
+#define XCVR_DUMMY2		0x03
+#define XCVR_DUMMY3		0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY		(1 << 0)
+#define WAKE_UCAST		(1 << 1)
+#define WAKE_MCAST		(1 << 2)
+#define WAKE_BCAST		(1 << 3)
+#define WAKE_ARP		(1 << 4)
+#define WAKE_MAGIC		(1 << 5)
+#define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* From tg3.h */
+
+#define TG3_64BIT_REG_HIGH		0x00UL
+#define TG3_64BIT_REG_LOW		0x04UL
+
+/* Descriptor block info. */
+#define TG3_BDINFO_HOST_ADDR		0x0UL /* 64-bit */
+#define TG3_BDINFO_MAXLEN_FLAGS		0x8UL /* 32-bit */
+#define  BDINFO_FLAGS_USE_EXT_RECV	 0x00000001 /* ext rx_buffer_desc */
+#define  BDINFO_FLAGS_DISABLED		 0x00000002
+#define  BDINFO_FLAGS_MAXLEN_MASK	 0xffff0000
+#define  BDINFO_FLAGS_MAXLEN_SHIFT	 16
+#define TG3_BDINFO_NIC_ADDR		0xcUL /* 32-bit */
+#define TG3_BDINFO_SIZE			0x10UL
+
+#define RX_COPY_THRESHOLD  		256
+
+#define RX_STD_MAX_SIZE			1536
+#define RX_STD_MAX_SIZE_5705		512
+#define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
+
+/* First 256 bytes are a mirror of PCI config space. */
+#define TG3PCI_VENDOR			0x00000000
+#define  TG3PCI_VENDOR_BROADCOM		 0x14e4
+#define TG3PCI_DEVICE			0x00000002
+#define  TG3PCI_DEVICE_TIGON3_1		 0x1644 /* BCM5700 */
+#define  TG3PCI_DEVICE_TIGON3_2		 0x1645 /* BCM5701 */
+#define  TG3PCI_DEVICE_TIGON3_3		 0x1646 /* BCM5702 */
+#define  TG3PCI_DEVICE_TIGON3_4		 0x1647 /* BCM5703 */
+#define TG3PCI_COMMAND			0x00000004
+#define TG3PCI_STATUS			0x00000006
+#define TG3PCI_CCREVID			0x00000008
+#define TG3PCI_CACHELINESZ		0x0000000c
+#define TG3PCI_LATTIMER			0x0000000d
+#define TG3PCI_HEADERTYPE		0x0000000e
+#define TG3PCI_BIST			0x0000000f
+#define TG3PCI_BASE0_LOW		0x00000010
+#define TG3PCI_BASE0_HIGH		0x00000014
+/* 0x18 --> 0x2c unused */
+#define TG3PCI_SUBSYSVENID		0x0000002c
+#define TG3PCI_SUBSYSID			0x0000002e
+#define TG3PCI_ROMADDR			0x00000030
+#define TG3PCI_CAPLIST			0x00000034
+/* 0x35 --> 0x3c unused */
+#define TG3PCI_IRQ_LINE			0x0000003c
+#define TG3PCI_IRQ_PIN			0x0000003d
+#define TG3PCI_MIN_GNT			0x0000003e
+#define TG3PCI_MAX_LAT			0x0000003f
+#define TG3PCI_X_CAPS			0x00000040
+#define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
+#define  PCIX_CAPS_SPLIT_MASK		 0x00700000
+#define  PCIX_CAPS_SPLIT_SHIFT		 20
+#define  PCIX_CAPS_BURST_MASK		 0x000c0000
+#define  PCIX_CAPS_BURST_SHIFT		 18
+#define  PCIX_CAPS_MAX_BURST_CPIOB	 2
+#define TG3PCI_PM_CAP_PTR		0x00000041
+#define TG3PCI_X_COMMAND		0x00000042
+#define TG3PCI_X_STATUS			0x00000044
+#define TG3PCI_PM_CAP_ID		0x00000048
+#define TG3PCI_VPD_CAP_PTR		0x00000049
+#define TG3PCI_PM_CAPS			0x0000004a
+#define TG3PCI_PM_CTRL_STAT		0x0000004c
+#define TG3PCI_BR_SUPP_EXT		0x0000004e
+#define TG3PCI_PM_DATA			0x0000004f
+#define TG3PCI_VPD_CAP_ID		0x00000050
+#define TG3PCI_MSI_CAP_PTR		0x00000051
+#define TG3PCI_VPD_ADDR_FLAG		0x00000052
+#define  VPD_ADDR_FLAG_WRITE		0x00008000
+#define TG3PCI_VPD_DATA			0x00000054
+#define TG3PCI_MSI_CAP_ID		0x00000058
+#define TG3PCI_NXT_CAP_PTR		0x00000059
+#define TG3PCI_MSI_CTRL			0x0000005a
+#define TG3PCI_MSI_ADDR_LOW		0x0000005c
+#define TG3PCI_MSI_ADDR_HIGH		0x00000060
+#define TG3PCI_MSI_DATA			0x00000064
+/* 0x66 --> 0x68 unused */
+#define TG3PCI_MISC_HOST_CTRL		0x00000068
+#define  MISC_HOST_CTRL_CLEAR_INT	 0x00000001
+#define  MISC_HOST_CTRL_MASK_PCI_INT	 0x00000002
+#define  MISC_HOST_CTRL_BYTE_SWAP	 0x00000004
+#define  MISC_HOST_CTRL_WORD_SWAP	 0x00000008
+#define  MISC_HOST_CTRL_PCISTATE_RW	 0x00000010
+#define  MISC_HOST_CTRL_CLKREG_RW	 0x00000020
+#define  MISC_HOST_CTRL_REGWORD_SWAP	 0x00000040
+#define  MISC_HOST_CTRL_INDIR_ACCESS	 0x00000080
+#define  MISC_HOST_CTRL_IRQ_MASK_MODE	 0x00000100
+#define  MISC_HOST_CTRL_TAGGED_STATUS	 0x00000200
+#define  MISC_HOST_CTRL_CHIPREV		 0xffff0000
+#define  MISC_HOST_CTRL_CHIPREV_SHIFT	 16
+#define  GET_CHIP_REV_ID(MISC_HOST_CTRL) \
+	 (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
+	  MISC_HOST_CTRL_CHIPREV_SHIFT)
+#define  CHIPREV_ID_5700_A0		 0x7000
+#define  CHIPREV_ID_5700_A1		 0x7001
+#define  CHIPREV_ID_5700_B0		 0x7100
+#define  CHIPREV_ID_5700_B1		 0x7101
+#define  CHIPREV_ID_5700_B3		 0x7102
+#define  CHIPREV_ID_5700_ALTIMA		 0x7104
+#define  CHIPREV_ID_5700_C0		 0x7200
+#define  CHIPREV_ID_5701_A0		 0x0000
+#define  CHIPREV_ID_5701_B0		 0x0100
+#define  CHIPREV_ID_5701_B2		 0x0102
+#define  CHIPREV_ID_5701_B5		 0x0105
+#define  CHIPREV_ID_5703_A0		 0x1000
+#define  CHIPREV_ID_5703_A1		 0x1001
+#define  CHIPREV_ID_5703_A2		 0x1002
+#define  CHIPREV_ID_5703_A3		 0x1003
+#define  CHIPREV_ID_5704_A0		 0x2000
+#define  CHIPREV_ID_5704_A1		 0x2001
+#define  CHIPREV_ID_5704_A2		 0x2002
+#define  CHIPREV_ID_5705_A0		 0x3000
+#define  CHIPREV_ID_5705_A1		 0x3001
+#define	 CHIPREV_ID_5705_A2              0x3002
+#define  CHIPREV_ID_5705_A3              0x3003
+#define  CHIPREV_ID_5721                 0x4101
+#define  CHIPREV_ID_5750_A0              0x4000
+#define  CHIPREV_ID_5750_A1              0x4001
+#define  CHIPREV_ID_5750_A3              0x4003
+#define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
+#define   ASIC_REV_5700			 0x07
+#define   ASIC_REV_5701			 0x00
+#define   ASIC_REV_5703			 0x01
+#define   ASIC_REV_5704			 0x02
+#define   ASIC_REV_5705			 0x03
+#define   ASIC_REV_5750			 0x04
+#define   ASIC_REV_5787			 0x0b
+#define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
+#define   CHIPREV_5700_AX		 0x70
+#define   CHIPREV_5700_BX		 0x71
+#define   CHIPREV_5700_CX		 0x72
+#define   CHIPREV_5701_AX		 0x00
+#define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
+#define   METAL_REV_A0			 0x00
+#define   METAL_REV_A1			 0x01
+#define   METAL_REV_B0			 0x00
+#define   METAL_REV_B1			 0x01
+#define   METAL_REV_B2			 0x02
+#define TG3PCI_DMA_RW_CTRL		0x0000006c
+#define  DMA_RWCTRL_MIN_DMA		 0x000000ff
+#define  DMA_RWCTRL_MIN_DMA_SHIFT	 0
+#define  DMA_RWCTRL_READ_BNDRY_MASK	 0x00000700
+#define  DMA_RWCTRL_READ_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_READ_BNDRY_16	 0x00000100
+#define  DMA_RWCTRL_READ_BNDRY_32	 0x00000200
+#define  DMA_RWCTRL_READ_BNDRY_64	 0x00000300
+#define  DMA_RWCTRL_READ_BNDRY_128	 0x00000400
+#define  DMA_RWCTRL_READ_BNDRY_256	 0x00000500
+#define  DMA_RWCTRL_READ_BNDRY_512	 0x00000600
+#define  DMA_RWCTRL_READ_BNDRY_1024	 0x00000700
+#define  DMA_RWCTRL_WRITE_BNDRY_MASK	 0x00003800
+#define  DMA_RWCTRL_WRITE_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_WRITE_BNDRY_16	 0x00000800
+#define  DMA_RWCTRL_WRITE_BNDRY_32	 0x00001000
+#define  DMA_RWCTRL_WRITE_BNDRY_64	 0x00001800
+#define  DMA_RWCTRL_WRITE_BNDRY_128	 0x00002000
+#define  DMA_RWCTRL_WRITE_BNDRY_256	 0x00002800
+#define  DMA_RWCTRL_WRITE_BNDRY_512	 0x00003000
+#define  DMA_RWCTRL_WRITE_BNDRY_1024	 0x00003800
+#define  DMA_RWCTRL_ONE_DMA		 0x00004000
+#define  DMA_RWCTRL_READ_WATER		 0x00070000
+#define  DMA_RWCTRL_READ_WATER_SHIFT	 16
+#define  DMA_RWCTRL_WRITE_WATER		 0x00380000
+#define  DMA_RWCTRL_WRITE_WATER_SHIFT	 19
+#define  DMA_RWCTRL_USE_MEM_READ_MULT	 0x00400000
+#define  DMA_RWCTRL_ASSERT_ALL_BE	 0x00800000
+#define  DMA_RWCTRL_PCI_READ_CMD	 0x0f000000
+#define  DMA_RWCTRL_PCI_READ_CMD_SHIFT	 24
+#define  DMA_RWCTRL_PCI_WRITE_CMD	 0xf0000000
+#define  DMA_RWCTRL_PCI_WRITE_CMD_SHIFT	 28
+#define TG3PCI_PCISTATE			0x00000070
+#define  PCISTATE_FORCE_RESET		 0x00000001
+#define  PCISTATE_INT_NOT_ACTIVE	 0x00000002
+#define  PCISTATE_CONV_PCI_MODE		 0x00000004
+#define  PCISTATE_BUS_SPEED_HIGH	 0x00000008
+#define  PCISTATE_BUS_32BIT		 0x00000010
+#define  PCISTATE_ROM_ENABLE		 0x00000020
+#define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
+#define  PCISTATE_FLAT_VIEW		 0x00000100
+#define  PCISTATE_RETRY_SAME_DMA	 0x00002000
+#define TG3PCI_CLOCK_CTRL		0x00000074
+#define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
+#define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
+#define  CLOCK_CTRL_TXCLK_DISABLE	 0x00000800
+#define  CLOCK_CTRL_ALTCLK		 0x00001000
+#define  CLOCK_CTRL_PWRDOWN_PLL133	 0x00008000
+#define  CLOCK_CTRL_44MHZ_CORE		 0x00040000
+#define  CLOCK_CTRL_625_CORE		 0x00100000
+#define  CLOCK_CTRL_FORCE_CLKRUN	 0x00200000
+#define  CLOCK_CTRL_CLKRUN_OENABLE	 0x00400000
+#define  CLOCK_CTRL_DELAY_PCI_GRANT	 0x80000000
+#define TG3PCI_REG_BASE_ADDR		0x00000078
+#define TG3PCI_MEM_WIN_BASE_ADDR	0x0000007c
+#define TG3PCI_REG_DATA			0x00000080
+#define TG3PCI_MEM_WIN_DATA		0x00000084
+#define TG3PCI_MODE_CTRL		0x00000088
+#define TG3PCI_MISC_CFG			0x0000008c
+#define TG3PCI_MISC_LOCAL_CTRL		0x00000090
+/* 0x94 --> 0x98 unused */
+#define TG3PCI_STD_RING_PROD_IDX	0x00000098 /* 64-bit */
+#define TG3PCI_RCV_RET_RING_CON_IDX	0x000000a0 /* 64-bit */
+#define TG3PCI_SND_PROD_IDX		0x000000a8 /* 64-bit */
+/* 0xb0 --> 0x100 unused */
+
+/* 0x100 --> 0x200 unused */
+
+/* Mailbox registers */
+#define MAILBOX_INTERRUPT_0		0x00000200 /* 64-bit */
+#define MAILBOX_INTERRUPT_1		0x00000208 /* 64-bit */
+#define MAILBOX_INTERRUPT_2		0x00000210 /* 64-bit */
+#define MAILBOX_INTERRUPT_3		0x00000218 /* 64-bit */
+#define MAILBOX_GENERAL_0		0x00000220 /* 64-bit */
+#define MAILBOX_GENERAL_1		0x00000228 /* 64-bit */
+#define MAILBOX_GENERAL_2		0x00000230 /* 64-bit */
+#define MAILBOX_GENERAL_3		0x00000238 /* 64-bit */
+#define MAILBOX_GENERAL_4		0x00000240 /* 64-bit */
+#define MAILBOX_GENERAL_5		0x00000248 /* 64-bit */
+#define MAILBOX_GENERAL_6		0x00000250 /* 64-bit */
+#define MAILBOX_GENERAL_7		0x00000258 /* 64-bit */
+#define MAILBOX_RELOAD_STAT		0x00000260 /* 64-bit */
+#define MAILBOX_RCV_STD_PROD_IDX	0x00000268 /* 64-bit */
+#define MAILBOX_RCV_JUMBO_PROD_IDX	0x00000270 /* 64-bit */
+#define MAILBOX_RCV_MINI_PROD_IDX	0x00000278 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_0	0x00000280 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_1	0x00000288 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_2	0x00000290 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_3	0x00000298 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_4	0x000002a0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_5	0x000002a8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_6	0x000002b0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_7	0x000002b8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_8	0x000002c0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_9	0x000002c8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_10	0x000002d0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_11	0x000002d8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_12	0x000002e0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_13	0x000002e8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_14	0x000002f0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_15	0x000002f8 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_0	0x00000300 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_1	0x00000308 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_2	0x00000310 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_3	0x00000318 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_4	0x00000320 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_5	0x00000328 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_6	0x00000330 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_7	0x00000338 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_8	0x00000340 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_9	0x00000348 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_10	0x00000350 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_11	0x00000358 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_12	0x00000360 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_13	0x00000368 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_14	0x00000370 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_15	0x00000378 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_0	0x00000380 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_1	0x00000388 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_2	0x00000390 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_3	0x00000398 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_4	0x000003a0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_5	0x000003a8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_6	0x000003b0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_7	0x000003b8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_8	0x000003c0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_9	0x000003c8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_10	0x000003d0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_11	0x000003d8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_12	0x000003e0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_13	0x000003e8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_14	0x000003f0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_15	0x000003f8 /* 64-bit */
+
+/* MAC control registers */
+#define MAC_MODE			0x00000400
+#define  MAC_MODE_RESET			 0x00000001
+#define  MAC_MODE_HALF_DUPLEX		 0x00000002
+#define  MAC_MODE_PORT_MODE_MASK	 0x0000000c
+#define  MAC_MODE_PORT_MODE_TBI		 0x0000000c
+#define  MAC_MODE_PORT_MODE_GMII	 0x00000008
+#define  MAC_MODE_PORT_MODE_MII		 0x00000004
+#define  MAC_MODE_PORT_MODE_NONE	 0x00000000
+#define  MAC_MODE_PORT_INT_LPBACK	 0x00000010
+#define  MAC_MODE_TAGGED_MAC_CTRL	 0x00000080
+#define  MAC_MODE_TX_BURSTING		 0x00000100
+#define  MAC_MODE_MAX_DEFER		 0x00000200
+#define  MAC_MODE_LINK_POLARITY		 0x00000400
+#define  MAC_MODE_RXSTAT_ENABLE		 0x00000800
+#define  MAC_MODE_RXSTAT_CLEAR		 0x00001000
+#define  MAC_MODE_RXSTAT_FLUSH		 0x00002000
+#define  MAC_MODE_TXSTAT_ENABLE		 0x00004000
+#define  MAC_MODE_TXSTAT_CLEAR		 0x00008000
+#define  MAC_MODE_TXSTAT_FLUSH		 0x00010000
+#define  MAC_MODE_SEND_CONFIGS		 0x00020000
+#define  MAC_MODE_MAGIC_PKT_ENABLE	 0x00040000
+#define  MAC_MODE_ACPI_ENABLE		 0x00080000
+#define  MAC_MODE_MIP_ENABLE		 0x00100000
+#define  MAC_MODE_TDE_ENABLE		 0x00200000
+#define  MAC_MODE_RDE_ENABLE		 0x00400000
+#define  MAC_MODE_FHDE_ENABLE		 0x00800000
+#define MAC_STATUS			0x00000404
+#define  MAC_STATUS_PCS_SYNCED		 0x00000001
+#define  MAC_STATUS_SIGNAL_DET		 0x00000002
+#define  MAC_STATUS_RCVD_CFG		 0x00000004
+#define  MAC_STATUS_CFG_CHANGED		 0x00000008
+#define  MAC_STATUS_SYNC_CHANGED	 0x00000010
+#define  MAC_STATUS_PORT_DEC_ERR	 0x00000400
+#define  MAC_STATUS_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_STATUS_MI_COMPLETION	 0x00400000
+#define  MAC_STATUS_MI_INTERRUPT	 0x00800000
+#define  MAC_STATUS_AP_ERROR		 0x01000000
+#define  MAC_STATUS_ODI_ERROR		 0x02000000
+#define  MAC_STATUS_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_STATUS_TXSTAT_OVERRUN	 0x08000000
+#define MAC_EVENT			0x00000408
+#define  MAC_EVENT_PORT_DECODE_ERR	 0x00000400
+#define  MAC_EVENT_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_EVENT_MI_COMPLETION	 0x00400000
+#define  MAC_EVENT_MI_INTERRUPT		 0x00800000
+#define  MAC_EVENT_AP_ERROR		 0x01000000
+#define  MAC_EVENT_ODI_ERROR		 0x02000000
+#define  MAC_EVENT_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_EVENT_TXSTAT_OVERRUN	 0x08000000
+#define MAC_LED_CTRL			0x0000040c
+#define  LED_CTRL_LNKLED_OVERRIDE	 0x00000001
+#define  LED_CTRL_1000MBPS_ON		 0x00000002
+#define  LED_CTRL_100MBPS_ON		 0x00000004
+#define  LED_CTRL_10MBPS_ON		 0x00000008
+#define  LED_CTRL_TRAFFIC_OVERRIDE	 0x00000010
+#define  LED_CTRL_TRAFFIC_BLINK		 0x00000020
+#define  LED_CTRL_TRAFFIC_LED		 0x00000040
+#define  LED_CTRL_1000MBPS_STATUS	 0x00000080
+#define  LED_CTRL_100MBPS_STATUS	 0x00000100
+#define  LED_CTRL_10MBPS_STATUS		 0x00000200
+#define  LED_CTRL_TRAFFIC_STATUS	 0x00000400
+#define  LED_CTRL_MAC_MODE		 0x00000000
+#define  LED_CTRL_PHY_MODE_1		 0x00000800
+#define  LED_CTRL_PHY_MODE_2		 0x00001000
+#define  LED_CTRL_BLINK_RATE_MASK	 0x7ff80000
+#define  LED_CTRL_BLINK_RATE_SHIFT	 19
+#define  LED_CTRL_BLINK_PER_OVERRIDE	 0x00080000
+#define  LED_CTRL_BLINK_RATE_OVERRIDE	 0x80000000
+#define MAC_ADDR_0_HIGH			0x00000410 /* upper 2 bytes */
+#define MAC_ADDR_0_LOW			0x00000414 /* lower 4 bytes */
+#define MAC_ADDR_1_HIGH			0x00000418 /* upper 2 bytes */
+#define MAC_ADDR_1_LOW			0x0000041c /* lower 4 bytes */
+#define MAC_ADDR_2_HIGH			0x00000420 /* upper 2 bytes */
+#define MAC_ADDR_2_LOW			0x00000424 /* lower 4 bytes */
+#define MAC_ADDR_3_HIGH			0x00000428 /* upper 2 bytes */
+#define MAC_ADDR_3_LOW			0x0000042c /* lower 4 bytes */
+#define MAC_ACPI_MBUF_PTR		0x00000430
+#define MAC_ACPI_LEN_OFFSET		0x00000434
+#define  ACPI_LENOFF_LEN_MASK		 0x0000ffff
+#define  ACPI_LENOFF_LEN_SHIFT		 0
+#define  ACPI_LENOFF_OFF_MASK		 0x0fff0000
+#define  ACPI_LENOFF_OFF_SHIFT		 16
+#define MAC_TX_BACKOFF_SEED		0x00000438
+#define  TX_BACKOFF_SEED_MASK		 0x000003ff
+#define MAC_RX_MTU_SIZE			0x0000043c
+#define  RX_MTU_SIZE_MASK		 0x0000ffff
+#define MAC_PCS_TEST			0x00000440
+#define  PCS_TEST_PATTERN_MASK		 0x000fffff
+#define  PCS_TEST_PATTERN_SHIFT		 0
+#define  PCS_TEST_ENABLE		 0x00100000
+#define MAC_TX_AUTO_NEG			0x00000444
+#define  TX_AUTO_NEG_MASK		 0x0000ffff
+#define  TX_AUTO_NEG_SHIFT		 0
+#define MAC_RX_AUTO_NEG			0x00000448
+#define  RX_AUTO_NEG_MASK		 0x0000ffff
+#define  RX_AUTO_NEG_SHIFT		 0
+#define MAC_MI_COM			0x0000044c
+#define  MI_COM_CMD_MASK		 0x0c000000
+#define  MI_COM_CMD_WRITE		 0x04000000
+#define  MI_COM_CMD_READ		 0x08000000
+#define  MI_COM_READ_FAILED		 0x10000000
+#define  MI_COM_START			 0x20000000
+#define  MI_COM_BUSY			 0x20000000
+#define  MI_COM_PHY_ADDR_MASK		 0x03e00000
+#define  MI_COM_PHY_ADDR_SHIFT		 21
+#define  MI_COM_REG_ADDR_MASK		 0x001f0000
+#define  MI_COM_REG_ADDR_SHIFT		 16
+#define  MI_COM_DATA_MASK		 0x0000ffff
+#define MAC_MI_STAT			0x00000450
+#define  MAC_MI_STAT_LNKSTAT_ATTN_ENAB	 0x00000001
+#define MAC_MI_MODE			0x00000454
+#define  MAC_MI_MODE_CLK_10MHZ		 0x00000001
+#define  MAC_MI_MODE_SHORT_PREAMBLE	 0x00000002
+#define  MAC_MI_MODE_AUTO_POLL		 0x00000010
+#define  MAC_MI_MODE_CORE_CLK_62MHZ	 0x00008000
+#define  MAC_MI_MODE_BASE		 0x000c0000 /* XXX magic values XXX */
+#define MAC_AUTO_POLL_STATUS		0x00000458
+#define  MAC_AUTO_POLL_ERROR		 0x00000001
+#define MAC_TX_MODE			0x0000045c
+#define  TX_MODE_RESET			 0x00000001
+#define  TX_MODE_ENABLE			 0x00000002
+#define  TX_MODE_FLOW_CTRL_ENABLE	 0x00000010
+#define  TX_MODE_BIG_BCKOFF_ENABLE	 0x00000020
+#define  TX_MODE_LONG_PAUSE_ENABLE	 0x00000040
+#define MAC_TX_STATUS			0x00000460
+#define  TX_STATUS_XOFFED		 0x00000001
+#define  TX_STATUS_SENT_XOFF		 0x00000002
+#define  TX_STATUS_SENT_XON		 0x00000004
+#define  TX_STATUS_LINK_UP		 0x00000008
+#define  TX_STATUS_ODI_UNDERRUN		 0x00000010
+#define  TX_STATUS_ODI_OVERRUN		 0x00000020
+#define MAC_TX_LENGTHS			0x00000464
+#define  TX_LENGTHS_SLOT_TIME_MASK	 0x000000ff
+#define  TX_LENGTHS_SLOT_TIME_SHIFT	 0
+#define  TX_LENGTHS_IPG_MASK		 0x00000f00
+#define  TX_LENGTHS_IPG_SHIFT		 8
+#define  TX_LENGTHS_IPG_CRS_MASK	 0x00003000
+#define  TX_LENGTHS_IPG_CRS_SHIFT	 12
+#define MAC_RX_MODE			0x00000468
+#define  RX_MODE_RESET			 0x00000001
+#define  RX_MODE_ENABLE			 0x00000002
+#define  RX_MODE_FLOW_CTRL_ENABLE	 0x00000004
+#define  RX_MODE_KEEP_MAC_CTRL		 0x00000008
+#define  RX_MODE_KEEP_PAUSE		 0x00000010
+#define  RX_MODE_ACCEPT_OVERSIZED	 0x00000020
+#define  RX_MODE_ACCEPT_RUNTS		 0x00000040
+#define  RX_MODE_LEN_CHECK		 0x00000080
+#define  RX_MODE_PROMISC		 0x00000100
+#define  RX_MODE_NO_CRC_CHECK		 0x00000200
+#define  RX_MODE_KEEP_VLAN_TAG		 0x00000400
+#define MAC_RX_STATUS			0x0000046c
+#define  RX_STATUS_REMOTE_TX_XOFFED	 0x00000001
+#define  RX_STATUS_XOFF_RCVD		 0x00000002
+#define  RX_STATUS_XON_RCVD		 0x00000004
+#define MAC_HASH_REG_0			0x00000470
+#define MAC_HASH_REG_1			0x00000474
+#define MAC_HASH_REG_2			0x00000478
+#define MAC_HASH_REG_3			0x0000047c
+#define MAC_RCV_RULE_0			0x00000480
+#define MAC_RCV_VALUE_0			0x00000484
+#define MAC_RCV_RULE_1			0x00000488
+#define MAC_RCV_VALUE_1			0x0000048c
+#define MAC_RCV_RULE_2			0x00000490
+#define MAC_RCV_VALUE_2			0x00000494
+#define MAC_RCV_RULE_3			0x00000498
+#define MAC_RCV_VALUE_3			0x0000049c
+#define MAC_RCV_RULE_4			0x000004a0
+#define MAC_RCV_VALUE_4			0x000004a4
+#define MAC_RCV_RULE_5			0x000004a8
+#define MAC_RCV_VALUE_5			0x000004ac
+#define MAC_RCV_RULE_6			0x000004b0
+#define MAC_RCV_VALUE_6			0x000004b4
+#define MAC_RCV_RULE_7			0x000004b8
+#define MAC_RCV_VALUE_7			0x000004bc
+#define MAC_RCV_RULE_8			0x000004c0
+#define MAC_RCV_VALUE_8			0x000004c4
+#define MAC_RCV_RULE_9			0x000004c8
+#define MAC_RCV_VALUE_9			0x000004cc
+#define MAC_RCV_RULE_10			0x000004d0
+#define MAC_RCV_VALUE_10		0x000004d4
+#define MAC_RCV_RULE_11			0x000004d8
+#define MAC_RCV_VALUE_11		0x000004dc
+#define MAC_RCV_RULE_12			0x000004e0
+#define MAC_RCV_VALUE_12		0x000004e4
+#define MAC_RCV_RULE_13			0x000004e8
+#define MAC_RCV_VALUE_13		0x000004ec
+#define MAC_RCV_RULE_14			0x000004f0
+#define MAC_RCV_VALUE_14		0x000004f4
+#define MAC_RCV_RULE_15			0x000004f8
+#define MAC_RCV_VALUE_15		0x000004fc
+#define  RCV_RULE_DISABLE_MASK		 0x7fffffff
+#define MAC_RCV_RULE_CFG		0x00000500
+#define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
+#define MAC_LOW_WMARK_MAX_RX_FRAME	0x00000504
+/* 0x508 --> 0x520 unused */
+#define MAC_HASHREGU_0			0x00000520
+#define MAC_HASHREGU_1			0x00000524
+#define MAC_HASHREGU_2			0x00000528
+#define MAC_HASHREGU_3			0x0000052c
+#define MAC_EXTADDR_0_HIGH		0x00000530
+#define MAC_EXTADDR_0_LOW		0x00000534
+#define MAC_EXTADDR_1_HIGH		0x00000538
+#define MAC_EXTADDR_1_LOW		0x0000053c
+#define MAC_EXTADDR_2_HIGH		0x00000540
+#define MAC_EXTADDR_2_LOW		0x00000544
+#define MAC_EXTADDR_3_HIGH		0x00000548
+#define MAC_EXTADDR_3_LOW		0x0000054c
+#define MAC_EXTADDR_4_HIGH		0x00000550
+#define MAC_EXTADDR_4_LOW		0x00000554
+#define MAC_EXTADDR_5_HIGH		0x00000558
+#define MAC_EXTADDR_5_LOW		0x0000055c
+#define MAC_EXTADDR_6_HIGH		0x00000560
+#define MAC_EXTADDR_6_LOW		0x00000564
+#define MAC_EXTADDR_7_HIGH		0x00000568
+#define MAC_EXTADDR_7_LOW		0x0000056c
+#define MAC_EXTADDR_8_HIGH		0x00000570
+#define MAC_EXTADDR_8_LOW		0x00000574
+#define MAC_EXTADDR_9_HIGH		0x00000578
+#define MAC_EXTADDR_9_LOW		0x0000057c
+#define MAC_EXTADDR_10_HIGH		0x00000580
+#define MAC_EXTADDR_10_LOW		0x00000584
+#define MAC_EXTADDR_11_HIGH		0x00000588
+#define MAC_EXTADDR_11_LOW		0x0000058c
+#define MAC_SERDES_CFG			0x00000590
+#define MAC_SERDES_STAT			0x00000594
+/* 0x598 --> 0x600 unused */
+#define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
+#define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
+/* 0x624 --> 0x800 unused */
+#define MAC_TX_STATS_OCTETS		0x00000800
+#define MAC_TX_STATS_RESV1		0x00000804
+#define MAC_TX_STATS_COLLISIONS		0x00000808
+#define MAC_TX_STATS_XON_SENT		0x0000080c
+#define MAC_TX_STATS_XOFF_SENT		0x00000810
+#define MAC_TX_STATS_RESV2		0x00000814
+#define MAC_TX_STATS_MAC_ERRORS		0x00000818
+#define MAC_TX_STATS_SINGLE_COLLISIONS	0x0000081c
+#define MAC_TX_STATS_MULT_COLLISIONS	0x00000820
+#define MAC_TX_STATS_DEFERRED		0x00000824
+#define MAC_TX_STATS_RESV3		0x00000828
+#define MAC_TX_STATS_EXCESSIVE_COL	0x0000082c
+#define MAC_TX_STATS_LATE_COL		0x00000830
+#define MAC_TX_STATS_RESV4_1		0x00000834
+#define MAC_TX_STATS_RESV4_2		0x00000838
+#define MAC_TX_STATS_RESV4_3		0x0000083c
+#define MAC_TX_STATS_RESV4_4		0x00000840
+#define MAC_TX_STATS_RESV4_5		0x00000844
+#define MAC_TX_STATS_RESV4_6		0x00000848
+#define MAC_TX_STATS_RESV4_7		0x0000084c
+#define MAC_TX_STATS_RESV4_8		0x00000850
+#define MAC_TX_STATS_RESV4_9		0x00000854
+#define MAC_TX_STATS_RESV4_10		0x00000858
+#define MAC_TX_STATS_RESV4_11		0x0000085c
+#define MAC_TX_STATS_RESV4_12		0x00000860
+#define MAC_TX_STATS_RESV4_13		0x00000864
+#define MAC_TX_STATS_RESV4_14		0x00000868
+#define MAC_TX_STATS_UCAST		0x0000086c
+#define MAC_TX_STATS_MCAST		0x00000870
+#define MAC_TX_STATS_BCAST		0x00000874
+#define MAC_TX_STATS_RESV5_1		0x00000878
+#define MAC_TX_STATS_RESV5_2		0x0000087c
+#define MAC_RX_STATS_OCTETS		0x00000880
+#define MAC_RX_STATS_RESV1		0x00000884
+#define MAC_RX_STATS_FRAGMENTS		0x00000888
+#define MAC_RX_STATS_UCAST		0x0000088c
+#define MAC_RX_STATS_MCAST		0x00000890
+#define MAC_RX_STATS_BCAST		0x00000894
+#define MAC_RX_STATS_FCS_ERRORS		0x00000898
+#define MAC_RX_STATS_ALIGN_ERRORS	0x0000089c
+#define MAC_RX_STATS_XON_PAUSE_RECVD	0x000008a0
+#define MAC_RX_STATS_XOFF_PAUSE_RECVD	0x000008a4
+#define MAC_RX_STATS_MAC_CTRL_RECVD	0x000008a8
+#define MAC_RX_STATS_XOFF_ENTERED	0x000008ac
+#define MAC_RX_STATS_FRAME_TOO_LONG	0x000008b0
+#define MAC_RX_STATS_JABBERS		0x000008b4
+#define MAC_RX_STATS_UNDERSIZE		0x000008b8
+/* 0x8bc --> 0xc00 unused */
+
+/* Send data initiator control registers */
+#define SNDDATAI_MODE			0x00000c00
+#define  SNDDATAI_MODE_RESET		 0x00000001
+#define  SNDDATAI_MODE_ENABLE		 0x00000002
+#define  SNDDATAI_MODE_STAT_OFLOW_ENAB	 0x00000004
+#define SNDDATAI_STATUS			0x00000c04
+#define  SNDDATAI_STATUS_STAT_OFLOW	 0x00000004
+#define SNDDATAI_STATSCTRL		0x00000c08
+#define  SNDDATAI_SCTRL_ENABLE		 0x00000001
+#define  SNDDATAI_SCTRL_FASTUPD		 0x00000002
+#define  SNDDATAI_SCTRL_CLEAR		 0x00000004
+#define  SNDDATAI_SCTRL_FLUSH		 0x00000008
+#define  SNDDATAI_SCTRL_FORCE_ZERO	 0x00000010
+#define SNDDATAI_STATSENAB		0x00000c0c
+#define SNDDATAI_STATSINCMASK		0x00000c10
+/* 0xc14 --> 0xc80 unused */
+#define SNDDATAI_COS_CNT_0		0x00000c80
+#define SNDDATAI_COS_CNT_1		0x00000c84
+#define SNDDATAI_COS_CNT_2		0x00000c88
+#define SNDDATAI_COS_CNT_3		0x00000c8c
+#define SNDDATAI_COS_CNT_4		0x00000c90
+#define SNDDATAI_COS_CNT_5		0x00000c94
+#define SNDDATAI_COS_CNT_6		0x00000c98
+#define SNDDATAI_COS_CNT_7		0x00000c9c
+#define SNDDATAI_COS_CNT_8		0x00000ca0
+#define SNDDATAI_COS_CNT_9		0x00000ca4
+#define SNDDATAI_COS_CNT_10		0x00000ca8
+#define SNDDATAI_COS_CNT_11		0x00000cac
+#define SNDDATAI_COS_CNT_12		0x00000cb0
+#define SNDDATAI_COS_CNT_13		0x00000cb4
+#define SNDDATAI_COS_CNT_14		0x00000cb8
+#define SNDDATAI_COS_CNT_15		0x00000cbc
+#define SNDDATAI_DMA_RDQ_FULL_CNT	0x00000cc0
+#define SNDDATAI_DMA_PRIO_RDQ_FULL_CNT	0x00000cc4
+#define SNDDATAI_SDCQ_FULL_CNT		0x00000cc8
+#define SNDDATAI_NICRNG_SSND_PIDX_CNT	0x00000ccc
+#define SNDDATAI_STATS_UPDATED_CNT	0x00000cd0
+#define SNDDATAI_INTERRUPTS_CNT		0x00000cd4
+#define SNDDATAI_AVOID_INTERRUPTS_CNT	0x00000cd8
+#define SNDDATAI_SND_THRESH_HIT_CNT	0x00000cdc
+/* 0xce0 --> 0x1000 unused */
+
+/* Send data completion control registers */
+#define SNDDATAC_MODE			0x00001000
+#define  SNDDATAC_MODE_RESET		 0x00000001
+#define  SNDDATAC_MODE_ENABLE		 0x00000002
+/* 0x1004 --> 0x1400 unused */
+
+/* Send BD ring selector */
+#define SNDBDS_MODE			0x00001400
+#define  SNDBDS_MODE_RESET		 0x00000001
+#define  SNDBDS_MODE_ENABLE		 0x00000002
+#define  SNDBDS_MODE_ATTN_ENABLE	 0x00000004
+#define SNDBDS_STATUS			0x00001404
+#define  SNDBDS_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDS_HWDIAG			0x00001408
+/* 0x140c --> 0x1440 */
+#define SNDBDS_SEL_CON_IDX_0		0x00001440
+#define SNDBDS_SEL_CON_IDX_1		0x00001444
+#define SNDBDS_SEL_CON_IDX_2		0x00001448
+#define SNDBDS_SEL_CON_IDX_3		0x0000144c
+#define SNDBDS_SEL_CON_IDX_4		0x00001450
+#define SNDBDS_SEL_CON_IDX_5		0x00001454
+#define SNDBDS_SEL_CON_IDX_6		0x00001458
+#define SNDBDS_SEL_CON_IDX_7		0x0000145c
+#define SNDBDS_SEL_CON_IDX_8		0x00001460
+#define SNDBDS_SEL_CON_IDX_9		0x00001464
+#define SNDBDS_SEL_CON_IDX_10		0x00001468
+#define SNDBDS_SEL_CON_IDX_11		0x0000146c
+#define SNDBDS_SEL_CON_IDX_12		0x00001470
+#define SNDBDS_SEL_CON_IDX_13		0x00001474
+#define SNDBDS_SEL_CON_IDX_14		0x00001478
+#define SNDBDS_SEL_CON_IDX_15		0x0000147c
+/* 0x1480 --> 0x1800 unused */
+
+/* Send BD initiator control registers */
+#define SNDBDI_MODE			0x00001800
+#define  SNDBDI_MODE_RESET		 0x00000001
+#define  SNDBDI_MODE_ENABLE		 0x00000002
+#define  SNDBDI_MODE_ATTN_ENABLE	 0x00000004
+#define SNDBDI_STATUS			0x00001804
+#define  SNDBDI_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDI_IN_PROD_IDX_0		0x00001808
+#define SNDBDI_IN_PROD_IDX_1		0x0000180c
+#define SNDBDI_IN_PROD_IDX_2		0x00001810
+#define SNDBDI_IN_PROD_IDX_3		0x00001814
+#define SNDBDI_IN_PROD_IDX_4		0x00001818
+#define SNDBDI_IN_PROD_IDX_5		0x0000181c
+#define SNDBDI_IN_PROD_IDX_6		0x00001820
+#define SNDBDI_IN_PROD_IDX_7		0x00001824
+#define SNDBDI_IN_PROD_IDX_8		0x00001828
+#define SNDBDI_IN_PROD_IDX_9		0x0000182c
+#define SNDBDI_IN_PROD_IDX_10		0x00001830
+#define SNDBDI_IN_PROD_IDX_11		0x00001834
+#define SNDBDI_IN_PROD_IDX_12		0x00001838
+#define SNDBDI_IN_PROD_IDX_13		0x0000183c
+#define SNDBDI_IN_PROD_IDX_14		0x00001840
+#define SNDBDI_IN_PROD_IDX_15		0x00001844
+/* 0x1848 --> 0x1c00 unused */
+
+/* Send BD completion control registers */
+#define SNDBDC_MODE			0x00001c00
+#define SNDBDC_MODE_RESET		 0x00000001
+#define SNDBDC_MODE_ENABLE		 0x00000002
+#define SNDBDC_MODE_ATTN_ENABLE		 0x00000004
+/* 0x1c04 --> 0x2000 unused */
+
+/* Receive list placement control registers */
+#define RCVLPC_MODE			0x00002000
+#define  RCVLPC_MODE_RESET		 0x00000001
+#define  RCVLPC_MODE_ENABLE		 0x00000002
+#define  RCVLPC_MODE_CLASS0_ATTN_ENAB	 0x00000004
+#define  RCVLPC_MODE_MAPOOR_AATTN_ENAB	 0x00000008
+#define  RCVLPC_MODE_STAT_OFLOW_ENAB	 0x00000010
+#define RCVLPC_STATUS			0x00002004
+#define  RCVLPC_STATUS_CLASS0		 0x00000004
+#define  RCVLPC_STATUS_MAPOOR		 0x00000008
+#define  RCVLPC_STATUS_STAT_OFLOW	 0x00000010
+#define RCVLPC_LOCK			0x00002008
+#define  RCVLPC_LOCK_REQ_MASK		 0x0000ffff
+#define  RCVLPC_LOCK_REQ_SHIFT		 0
+#define  RCVLPC_LOCK_GRANT_MASK		 0xffff0000
+#define  RCVLPC_LOCK_GRANT_SHIFT	 16
+#define RCVLPC_NON_EMPTY_BITS		0x0000200c
+#define  RCVLPC_NON_EMPTY_BITS_MASK	 0x0000ffff
+#define RCVLPC_CONFIG			0x00002010
+#define RCVLPC_STATSCTRL		0x00002014
+#define  RCVLPC_STATSCTRL_ENABLE	 0x00000001
+#define  RCVLPC_STATSCTRL_FASTUPD	 0x00000002
+#define RCVLPC_STATS_ENABLE		0x00002018
+#define  RCVLPC_STATSENAB_LNGBRST_RFIX	 0x00400000
+#define RCVLPC_STATS_INCMASK		0x0000201c
+/* 0x2020 --> 0x2100 unused */
+#define RCVLPC_SELLST_BASE		0x00002100 /* 16 16-byte entries */
+#define  SELLST_TAIL			0x00000004
+#define  SELLST_CONT			0x00000008
+#define  SELLST_UNUSED			0x0000000c
+#define RCVLPC_COS_CNTL_BASE		0x00002200 /* 16 4-byte entries */
+#define RCVLPC_DROP_FILTER_CNT		0x00002240
+#define RCVLPC_DMA_WQ_FULL_CNT		0x00002244
+#define RCVLPC_DMA_HIPRIO_WQ_FULL_CNT	0x00002248
+#define RCVLPC_NO_RCV_BD_CNT		0x0000224c
+#define RCVLPC_IN_DISCARDS_CNT		0x00002250
+#define RCVLPC_IN_ERRORS_CNT		0x00002254
+#define RCVLPC_RCV_THRESH_HIT_CNT	0x00002258
+/* 0x225c --> 0x2400 unused */
+
+/* Receive Data and Receive BD Initiator Control */
+#define RCVDBDI_MODE			0x00002400
+#define  RCVDBDI_MODE_RESET		 0x00000001
+#define  RCVDBDI_MODE_ENABLE		 0x00000002
+#define  RCVDBDI_MODE_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_MODE_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_MODE_INV_RING_SZ	 0x00000010
+#define RCVDBDI_STATUS			0x00002404
+#define  RCVDBDI_STATUS_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_STATUS_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_STATUS_INV_RING_SZ	 0x00000010
+#define RCVDBDI_SPLIT_FRAME_MINSZ	0x00002408
+/* 0x240c --> 0x2440 unused */
+#define RCVDBDI_JUMBO_BD		0x00002440 /* TG3_BDINFO_... */
+#define RCVDBDI_STD_BD			0x00002450 /* TG3_BDINFO_... */
+#define RCVDBDI_MINI_BD			0x00002460 /* TG3_BDINFO_... */
+#define RCVDBDI_JUMBO_CON_IDX		0x00002470
+#define RCVDBDI_STD_CON_IDX		0x00002474
+#define RCVDBDI_MINI_CON_IDX		0x00002478
+/* 0x247c --> 0x2480 unused */
+#define RCVDBDI_BD_PROD_IDX_0		0x00002480
+#define RCVDBDI_BD_PROD_IDX_1		0x00002484
+#define RCVDBDI_BD_PROD_IDX_2		0x00002488
+#define RCVDBDI_BD_PROD_IDX_3		0x0000248c
+#define RCVDBDI_BD_PROD_IDX_4		0x00002490
+#define RCVDBDI_BD_PROD_IDX_5		0x00002494
+#define RCVDBDI_BD_PROD_IDX_6		0x00002498
+#define RCVDBDI_BD_PROD_IDX_7		0x0000249c
+#define RCVDBDI_BD_PROD_IDX_8		0x000024a0
+#define RCVDBDI_BD_PROD_IDX_9		0x000024a4
+#define RCVDBDI_BD_PROD_IDX_10		0x000024a8
+#define RCVDBDI_BD_PROD_IDX_11		0x000024ac
+#define RCVDBDI_BD_PROD_IDX_12		0x000024b0
+#define RCVDBDI_BD_PROD_IDX_13		0x000024b4
+#define RCVDBDI_BD_PROD_IDX_14		0x000024b8
+#define RCVDBDI_BD_PROD_IDX_15		0x000024bc
+#define RCVDBDI_HWDIAG			0x000024c0
+/* 0x24c4 --> 0x2800 unused */
+
+/* Receive Data Completion Control */
+#define RCVDCC_MODE			0x00002800
+#define  RCVDCC_MODE_RESET		 0x00000001
+#define  RCVDCC_MODE_ENABLE		 0x00000002
+#define  RCVDCC_MODE_ATTN_ENABLE	 0x00000004
+/* 0x2804 --> 0x2c00 unused */
+
+/* Receive BD Initiator Control Registers */
+#define RCVBDI_MODE			0x00002c00
+#define  RCVBDI_MODE_RESET		 0x00000001
+#define  RCVBDI_MODE_ENABLE		 0x00000002
+#define  RCVBDI_MODE_RCB_ATTN_ENAB	 0x00000004
+#define RCVBDI_STATUS			0x00002c04
+#define  RCVBDI_STATUS_RCB_ATTN		 0x00000004
+#define RCVBDI_JUMBO_PROD_IDX		0x00002c08
+#define RCVBDI_STD_PROD_IDX		0x00002c0c
+#define RCVBDI_MINI_PROD_IDX		0x00002c10
+#define RCVBDI_MINI_THRESH		0x00002c14
+#define RCVBDI_STD_THRESH		0x00002c18
+#define RCVBDI_JUMBO_THRESH		0x00002c1c
+/* 0x2c20 --> 0x3000 unused */
+
+/* Receive BD Completion Control Registers */
+#define RCVCC_MODE			0x00003000
+#define  RCVCC_MODE_RESET		 0x00000001
+#define  RCVCC_MODE_ENABLE		 0x00000002
+#define  RCVCC_MODE_ATTN_ENABLE		 0x00000004
+#define RCVCC_STATUS			0x00003004
+#define  RCVCC_STATUS_ERROR_ATTN	 0x00000004
+#define RCVCC_JUMP_PROD_IDX		0x00003008
+#define RCVCC_STD_PROD_IDX		0x0000300c
+#define RCVCC_MINI_PROD_IDX		0x00003010
+/* 0x3014 --> 0x3400 unused */
+
+/* Receive list selector control registers */
+#define RCVLSC_MODE			0x00003400
+#define  RCVLSC_MODE_RESET		 0x00000001
+#define  RCVLSC_MODE_ENABLE		 0x00000002
+#define  RCVLSC_MODE_ATTN_ENABLE	 0x00000004
+#define RCVLSC_STATUS			0x00003404
+#define  RCVLSC_STATUS_ERROR_ATTN	 0x00000004
+/* 0x3408 --> 0x3800 unused */
+
+/* Mbuf cluster free registers */
+#define MBFREE_MODE			0x00003800
+#define  MBFREE_MODE_RESET		 0x00000001
+#define  MBFREE_MODE_ENABLE		 0x00000002
+#define MBFREE_STATUS			0x00003804
+/* 0x3808 --> 0x3c00 unused */
+
+/* Host coalescing control registers */
+#define HOSTCC_MODE			0x00003c00
+#define  HOSTCC_MODE_RESET		 0x00000001
+#define  HOSTCC_MODE_ENABLE		 0x00000002
+#define  HOSTCC_MODE_ATTN		 0x00000004
+#define  HOSTCC_MODE_NOW		 0x00000008
+#define  HOSTCC_MODE_FULL_STATUS	 0x00000000
+#define  HOSTCC_MODE_64BYTE		 0x00000080
+#define  HOSTCC_MODE_32BYTE		 0x00000100
+#define  HOSTCC_MODE_CLRTICK_RXBD	 0x00000200
+#define  HOSTCC_MODE_CLRTICK_TXBD	 0x00000400
+#define  HOSTCC_MODE_NOINT_ON_NOW	 0x00000800
+#define  HOSTCC_MODE_NOINT_ON_FORCE	 0x00001000
+#define HOSTCC_STATUS			0x00003c04
+#define  HOSTCC_STATUS_ERROR_ATTN	 0x00000004
+#define HOSTCC_RXCOL_TICKS		0x00003c08
+#define  LOW_RXCOL_TICKS		 0x00000032
+#define  DEFAULT_RXCOL_TICKS		 0x00000048
+#define  HIGH_RXCOL_TICKS		 0x00000096
+#define HOSTCC_TXCOL_TICKS		0x00003c0c
+#define  LOW_TXCOL_TICKS		 0x00000096
+#define  DEFAULT_TXCOL_TICKS		 0x0000012c
+#define  HIGH_TXCOL_TICKS		 0x00000145
+#define HOSTCC_RXMAX_FRAMES		0x00003c10
+#define  LOW_RXMAX_FRAMES		 0x00000005
+#define  DEFAULT_RXMAX_FRAMES		 0x00000008
+#define  HIGH_RXMAX_FRAMES		 0x00000012
+#define HOSTCC_TXMAX_FRAMES		0x00003c14
+#define  LOW_TXMAX_FRAMES		 0x00000035
+#define  DEFAULT_TXMAX_FRAMES		 0x0000004b
+#define  HIGH_TXMAX_FRAMES		 0x00000052
+#define HOSTCC_RXCOAL_TICK_INT		0x00003c18
+#define  DEFAULT_RXCOAL_TICK_INT	 0x00000019
+#define HOSTCC_TXCOAL_TICK_INT		0x00003c1c
+#define  DEFAULT_TXCOAL_TICK_INT	 0x00000019
+#define HOSTCC_RXCOAL_MAXF_INT		0x00003c20
+#define  DEFAULT_RXCOAL_MAXF_INT	 0x00000005
+#define HOSTCC_TXCOAL_MAXF_INT		0x00003c24
+#define  DEFAULT_TXCOAL_MAXF_INT	 0x00000005
+#define HOSTCC_STAT_COAL_TICKS		0x00003c28
+#define  DEFAULT_STAT_COAL_TICKS	 0x000f4240
+/* 0x3c2c --> 0x3c30 unused */
+#define HOSTCC_STATS_BLK_HOST_ADDR	0x00003c30 /* 64-bit */
+#define HOSTCC_STATUS_BLK_HOST_ADDR	0x00003c38 /* 64-bit */
+#define HOSTCC_STATS_BLK_NIC_ADDR	0x00003c40
+#define HOSTCC_STATUS_BLK_NIC_ADDR	0x00003c44
+#define HOSTCC_FLOW_ATTN		0x00003c48
+/* 0x3c4c --> 0x3c50 unused */
+#define HOSTCC_JUMBO_CON_IDX		0x00003c50
+#define HOSTCC_STD_CON_IDX		0x00003c54
+#define HOSTCC_MINI_CON_IDX		0x00003c58
+/* 0x3c5c --> 0x3c80 unused */
+#define HOSTCC_RET_PROD_IDX_0		0x00003c80
+#define HOSTCC_RET_PROD_IDX_1		0x00003c84
+#define HOSTCC_RET_PROD_IDX_2		0x00003c88
+#define HOSTCC_RET_PROD_IDX_3		0x00003c8c
+#define HOSTCC_RET_PROD_IDX_4		0x00003c90
+#define HOSTCC_RET_PROD_IDX_5		0x00003c94
+#define HOSTCC_RET_PROD_IDX_6		0x00003c98
+#define HOSTCC_RET_PROD_IDX_7		0x00003c9c
+#define HOSTCC_RET_PROD_IDX_8		0x00003ca0
+#define HOSTCC_RET_PROD_IDX_9		0x00003ca4
+#define HOSTCC_RET_PROD_IDX_10		0x00003ca8
+#define HOSTCC_RET_PROD_IDX_11		0x00003cac
+#define HOSTCC_RET_PROD_IDX_12		0x00003cb0
+#define HOSTCC_RET_PROD_IDX_13		0x00003cb4
+#define HOSTCC_RET_PROD_IDX_14		0x00003cb8
+#define HOSTCC_RET_PROD_IDX_15		0x00003cbc
+#define HOSTCC_SND_CON_IDX_0		0x00003cc0
+#define HOSTCC_SND_CON_IDX_1		0x00003cc4
+#define HOSTCC_SND_CON_IDX_2		0x00003cc8
+#define HOSTCC_SND_CON_IDX_3		0x00003ccc
+#define HOSTCC_SND_CON_IDX_4		0x00003cd0
+#define HOSTCC_SND_CON_IDX_5		0x00003cd4
+#define HOSTCC_SND_CON_IDX_6		0x00003cd8
+#define HOSTCC_SND_CON_IDX_7		0x00003cdc
+#define HOSTCC_SND_CON_IDX_8		0x00003ce0
+#define HOSTCC_SND_CON_IDX_9		0x00003ce4
+#define HOSTCC_SND_CON_IDX_10		0x00003ce8
+#define HOSTCC_SND_CON_IDX_11		0x00003cec
+#define HOSTCC_SND_CON_IDX_12		0x00003cf0
+#define HOSTCC_SND_CON_IDX_13		0x00003cf4
+#define HOSTCC_SND_CON_IDX_14		0x00003cf8
+#define HOSTCC_SND_CON_IDX_15		0x00003cfc
+/* 0x3d00 --> 0x4000 unused */
+
+/* Memory arbiter control registers */
+#define MEMARB_MODE			0x00004000
+#define  MEMARB_MODE_RESET		 0x00000001
+#define  MEMARB_MODE_ENABLE		 0x00000002
+#define MEMARB_STATUS			0x00004004
+#define MEMARB_TRAP_ADDR_LOW		0x00004008
+#define MEMARB_TRAP_ADDR_HIGH		0x0000400c
+/* 0x4010 --> 0x4400 unused */
+
+/* Buffer manager control registers */
+#define BUFMGR_MODE			0x00004400
+#define  BUFMGR_MODE_RESET		 0x00000001
+#define  BUFMGR_MODE_ENABLE		 0x00000002
+#define  BUFMGR_MODE_ATTN_ENABLE	 0x00000004
+#define  BUFMGR_MODE_BM_TEST		 0x00000008
+#define  BUFMGR_MODE_MBLOW_ATTN_ENAB	 0x00000010
+#define BUFMGR_STATUS			0x00004404
+#define  BUFMGR_STATUS_ERROR		 0x00000004
+#define  BUFMGR_STATUS_MBLOW		 0x00000010
+#define BUFMGR_MB_POOL_ADDR		0x00004408
+#define BUFMGR_MB_POOL_SIZE		0x0000440c
+#define BUFMGR_MB_RDMA_LOW_WATER	0x00004410
+#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000050
+#define  DEFAULT_MB_RDMA_LOW_WATER_5705	 0x00000000
+#define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130
+#define BUFMGR_MB_MACRX_LOW_WATER	0x00004414
+#define  DEFAULT_MB_MACRX_LOW_WATER	  0x00000020
+#define  DEFAULT_MB_MACRX_LOW_WATER_5705  0x00000010
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
+#define BUFMGR_MB_HIGH_WATER		0x00004418
+#define  DEFAULT_MB_HIGH_WATER		 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_5705	 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_JUMBO	 0x0000017c
+#define BUFMGR_RX_MB_ALLOC_REQ		0x0000441c
+#define  BUFMGR_MB_ALLOC_BIT		 0x10000000
+#define BUFMGR_RX_MB_ALLOC_RESP		0x00004420
+#define BUFMGR_TX_MB_ALLOC_REQ		0x00004424
+#define BUFMGR_TX_MB_ALLOC_RESP		0x00004428
+#define BUFMGR_DMA_DESC_POOL_ADDR	0x0000442c
+#define BUFMGR_DMA_DESC_POOL_SIZE	0x00004430
+#define BUFMGR_DMA_LOW_WATER		0x00004434
+#define  DEFAULT_DMA_LOW_WATER		 0x00000005
+#define BUFMGR_DMA_HIGH_WATER		0x00004438
+#define  DEFAULT_DMA_HIGH_WATER		 0x0000000a
+#define BUFMGR_RX_DMA_ALLOC_REQ		0x0000443c
+#define BUFMGR_RX_DMA_ALLOC_RESP	0x00004440
+#define BUFMGR_TX_DMA_ALLOC_REQ		0x00004444
+#define BUFMGR_TX_DMA_ALLOC_RESP	0x00004448
+#define BUFMGR_HWDIAG_0			0x0000444c
+#define BUFMGR_HWDIAG_1			0x00004450
+#define BUFMGR_HWDIAG_2			0x00004454
+/* 0x4458 --> 0x4800 unused */
+
+/* Read DMA control registers */
+#define RDMAC_MODE			0x00004800
+#define  RDMAC_MODE_RESET		 0x00000001
+#define  RDMAC_MODE_ENABLE		 0x00000002
+#define  RDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  RDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  RDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  RDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  RDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
+#define  RDMAC_MODE_SPLIT_RESET		 0x00001000
+#define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
+#define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
+#define RDMAC_STATUS			0x00004804
+#define  RDMAC_STATUS_TGTABORT		 0x00000004
+#define  RDMAC_STATUS_MSTABORT		 0x00000008
+#define  RDMAC_STATUS_PARITYERR		 0x00000010
+#define  RDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  RDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  RDMAC_STATUS_FIFOURUN		 0x00000080
+#define  RDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  RDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4808 --> 0x4c00 unused */
+
+/* Write DMA control registers */
+#define WDMAC_MODE			0x00004c00
+#define  WDMAC_MODE_RESET		 0x00000001
+#define  WDMAC_MODE_ENABLE		 0x00000002
+#define  WDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  WDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  WDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  WDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  WDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  WDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  WDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  WDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  WDMAC_MODE_RX_ACCEL	 	 0x00000400
+#define WDMAC_STATUS			0x00004c04
+#define  WDMAC_STATUS_TGTABORT		 0x00000004
+#define  WDMAC_STATUS_MSTABORT		 0x00000008
+#define  WDMAC_STATUS_PARITYERR		 0x00000010
+#define  WDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  WDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  WDMAC_STATUS_FIFOURUN		 0x00000080
+#define  WDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  WDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4c08 --> 0x5000 unused */
+
+/* Per-cpu register offsets (arm9) */
+#define CPU_MODE			0x00000000
+#define  CPU_MODE_RESET			 0x00000001
+#define  CPU_MODE_HALT			 0x00000400
+#define CPU_STATE			0x00000004
+#define CPU_EVTMASK			0x00000008
+/* 0xc --> 0x1c reserved */
+#define CPU_PC				0x0000001c
+#define CPU_INSN			0x00000020
+#define CPU_SPAD_UFLOW			0x00000024
+#define CPU_WDOG_CLEAR			0x00000028
+#define CPU_WDOG_VECTOR			0x0000002c
+#define CPU_WDOG_PC			0x00000030
+#define CPU_HW_BP			0x00000034
+/* 0x38 --> 0x44 unused */
+#define CPU_WDOG_SAVED_STATE		0x00000044
+#define CPU_LAST_BRANCH_ADDR		0x00000048
+#define CPU_SPAD_UFLOW_SET		0x0000004c
+/* 0x50 --> 0x200 unused */
+#define CPU_R0				0x00000200
+#define CPU_R1				0x00000204
+#define CPU_R2				0x00000208
+#define CPU_R3				0x0000020c
+#define CPU_R4				0x00000210
+#define CPU_R5				0x00000214
+#define CPU_R6				0x00000218
+#define CPU_R7				0x0000021c
+#define CPU_R8				0x00000220
+#define CPU_R9				0x00000224
+#define CPU_R10				0x00000228
+#define CPU_R11				0x0000022c
+#define CPU_R12				0x00000230
+#define CPU_R13				0x00000234
+#define CPU_R14				0x00000238
+#define CPU_R15				0x0000023c
+#define CPU_R16				0x00000240
+#define CPU_R17				0x00000244
+#define CPU_R18				0x00000248
+#define CPU_R19				0x0000024c
+#define CPU_R20				0x00000250
+#define CPU_R21				0x00000254
+#define CPU_R22				0x00000258
+#define CPU_R23				0x0000025c
+#define CPU_R24				0x00000260
+#define CPU_R25				0x00000264
+#define CPU_R26				0x00000268
+#define CPU_R27				0x0000026c
+#define CPU_R28				0x00000270
+#define CPU_R29				0x00000274
+#define CPU_R30				0x00000278
+#define CPU_R31				0x0000027c
+/* 0x280 --> 0x400 unused */
+
+#define RX_CPU_BASE			0x00005000
+#define TX_CPU_BASE			0x00005400
+
+/* Mailboxes */
+#define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
+#define GRCMBOX_INTERRUPT_1		0x00005808 /* 64-bit */
+#define GRCMBOX_INTERRUPT_2		0x00005810 /* 64-bit */
+#define GRCMBOX_INTERRUPT_3		0x00005818 /* 64-bit */
+#define GRCMBOX_GENERAL_0		0x00005820 /* 64-bit */
+#define GRCMBOX_GENERAL_1		0x00005828 /* 64-bit */
+#define GRCMBOX_GENERAL_2		0x00005830 /* 64-bit */
+#define GRCMBOX_GENERAL_3		0x00005838 /* 64-bit */
+#define GRCMBOX_GENERAL_4		0x00005840 /* 64-bit */
+#define GRCMBOX_GENERAL_5		0x00005848 /* 64-bit */
+#define GRCMBOX_GENERAL_6		0x00005850 /* 64-bit */
+#define GRCMBOX_GENERAL_7		0x00005858 /* 64-bit */
+#define GRCMBOX_RELOAD_STAT		0x00005860 /* 64-bit */
+#define GRCMBOX_RCVSTD_PROD_IDX		0x00005868 /* 64-bit */
+#define GRCMBOX_RCVJUMBO_PROD_IDX	0x00005870 /* 64-bit */
+#define GRCMBOX_RCVMINI_PROD_IDX	0x00005878 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_0	0x00005880 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_1	0x00005888 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_2	0x00005890 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_3	0x00005898 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_4	0x000058a0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_5	0x000058a8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_6	0x000058b0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_7	0x000058b8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_8	0x000058c0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_9	0x000058c8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_10	0x000058d0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_11	0x000058d8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_12	0x000058e0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_13	0x000058e8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_14	0x000058f0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_15	0x000058f8 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_0	0x00005900 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_1	0x00005908 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_2	0x00005910 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_3	0x00005918 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_4	0x00005920 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_5	0x00005928 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_6	0x00005930 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_7	0x00005938 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_8	0x00005940 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_9	0x00005948 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_10	0x00005950 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_11	0x00005958 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_12	0x00005960 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_13	0x00005968 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_14	0x00005970 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_15	0x00005978 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_0	0x00005980 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_1	0x00005988 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_2	0x00005990 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_3	0x00005998 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_4	0x000059a0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_5	0x000059a8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_6	0x000059b0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_7	0x000059b8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_8	0x000059c0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_9	0x000059c8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_10	0x000059d0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_11	0x000059d8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_12	0x000059e0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_13	0x000059e8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_14	0x000059f0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_15	0x000059f8 /* 64-bit */
+#define GRCMBOX_HIGH_PRIO_EV_VECTOR	0x00005a00
+#define GRCMBOX_HIGH_PRIO_EV_MASK	0x00005a04
+#define GRCMBOX_LOW_PRIO_EV_VEC		0x00005a08
+#define GRCMBOX_LOW_PRIO_EV_MASK	0x00005a0c
+/* 0x5a10 --> 0x5c00 */
+
+/* Flow Through queues */
+#define FTQ_RESET			0x00005c00
+#define FTQ_RESET_DMA_READ_QUEUE	(1 << 1)
+#define FTQ_RESET_DMA_HIGH_PRI_READ	(1 << 2)
+#define FTQ_RESET_SEND_BD_COMPLETION	(1 << 4)
+#define FTQ_RESET_DMA_WRITE		(1 << 6)
+#define FTQ_RESET_DMA_HIGH_PRI_WRITE	(1 << 7)
+#define FTQ_RESET_SEND_DATA_COMPLETION	(1 << 9)
+#define FTQ_RESET_HOST_COALESCING	(1 << 10)
+#define FTQ_RESET_MAC_TX		(1 << 11)
+#define FTQ_RESET_RX_BD_COMPLETE	(1 << 13)
+#define FTQ_RESET_RX_LIST_PLCMT		(1 << 14)
+#define FTQ_RESET_RX_DATA_COMPLETION	(1 << 16)
+/* 0x5c04 --> 0x5c10 unused */
+#define FTQ_DMA_NORM_READ_CTL		0x00005c10
+#define FTQ_DMA_NORM_READ_FULL_CNT	0x00005c14
+#define FTQ_DMA_NORM_READ_FIFO_ENQDEQ	0x00005c18
+#define FTQ_DMA_NORM_READ_WRITE_PEEK	0x00005c1c
+#define FTQ_DMA_HIGH_READ_CTL		0x00005c20
+#define FTQ_DMA_HIGH_READ_FULL_CNT	0x00005c24
+#define FTQ_DMA_HIGH_READ_FIFO_ENQDEQ	0x00005c28
+#define FTQ_DMA_HIGH_READ_WRITE_PEEK	0x00005c2c
+#define FTQ_DMA_COMP_DISC_CTL		0x00005c30
+#define FTQ_DMA_COMP_DISC_FULL_CNT	0x00005c34
+#define FTQ_DMA_COMP_DISC_FIFO_ENQDEQ	0x00005c38
+#define FTQ_DMA_COMP_DISC_WRITE_PEEK	0x00005c3c
+#define FTQ_SEND_BD_COMP_CTL		0x00005c40
+#define FTQ_SEND_BD_COMP_FULL_CNT	0x00005c44
+#define FTQ_SEND_BD_COMP_FIFO_ENQDEQ	0x00005c48
+#define FTQ_SEND_BD_COMP_WRITE_PEEK	0x00005c4c
+#define FTQ_SEND_DATA_INIT_CTL		0x00005c50
+#define FTQ_SEND_DATA_INIT_FULL_CNT	0x00005c54
+#define FTQ_SEND_DATA_INIT_FIFO_ENQDEQ	0x00005c58
+#define FTQ_SEND_DATA_INIT_WRITE_PEEK	0x00005c5c
+#define FTQ_DMA_NORM_WRITE_CTL		0x00005c60
+#define FTQ_DMA_NORM_WRITE_FULL_CNT	0x00005c64
+#define FTQ_DMA_NORM_WRITE_FIFO_ENQDEQ	0x00005c68
+#define FTQ_DMA_NORM_WRITE_WRITE_PEEK	0x00005c6c
+#define FTQ_DMA_HIGH_WRITE_CTL		0x00005c70
+#define FTQ_DMA_HIGH_WRITE_FULL_CNT	0x00005c74
+#define FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ	0x00005c78
+#define FTQ_DMA_HIGH_WRITE_WRITE_PEEK	0x00005c7c
+#define FTQ_SWTYPE1_CTL			0x00005c80
+#define FTQ_SWTYPE1_FULL_CNT		0x00005c84
+#define FTQ_SWTYPE1_FIFO_ENQDEQ		0x00005c88
+#define FTQ_SWTYPE1_WRITE_PEEK		0x00005c8c
+#define FTQ_SEND_DATA_COMP_CTL		0x00005c90
+#define FTQ_SEND_DATA_COMP_FULL_CNT	0x00005c94
+#define FTQ_SEND_DATA_COMP_FIFO_ENQDEQ	0x00005c98
+#define FTQ_SEND_DATA_COMP_WRITE_PEEK	0x00005c9c
+#define FTQ_HOST_COAL_CTL		0x00005ca0
+#define FTQ_HOST_COAL_FULL_CNT		0x00005ca4
+#define FTQ_HOST_COAL_FIFO_ENQDEQ	0x00005ca8
+#define FTQ_HOST_COAL_WRITE_PEEK	0x00005cac
+#define FTQ_MAC_TX_CTL			0x00005cb0
+#define FTQ_MAC_TX_FULL_CNT		0x00005cb4
+#define FTQ_MAC_TX_FIFO_ENQDEQ		0x00005cb8
+#define FTQ_MAC_TX_WRITE_PEEK		0x00005cbc
+#define FTQ_MB_FREE_CTL			0x00005cc0
+#define FTQ_MB_FREE_FULL_CNT		0x00005cc4
+#define FTQ_MB_FREE_FIFO_ENQDEQ		0x00005cc8
+#define FTQ_MB_FREE_WRITE_PEEK		0x00005ccc
+#define FTQ_RCVBD_COMP_CTL		0x00005cd0
+#define FTQ_RCVBD_COMP_FULL_CNT		0x00005cd4
+#define FTQ_RCVBD_COMP_FIFO_ENQDEQ	0x00005cd8
+#define FTQ_RCVBD_COMP_WRITE_PEEK	0x00005cdc
+#define FTQ_RCVLST_PLMT_CTL		0x00005ce0
+#define FTQ_RCVLST_PLMT_FULL_CNT	0x00005ce4
+#define FTQ_RCVLST_PLMT_FIFO_ENQDEQ	0x00005ce8
+#define FTQ_RCVLST_PLMT_WRITE_PEEK	0x00005cec
+#define FTQ_RCVDATA_INI_CTL		0x00005cf0
+#define FTQ_RCVDATA_INI_FULL_CNT	0x00005cf4
+#define FTQ_RCVDATA_INI_FIFO_ENQDEQ	0x00005cf8
+#define FTQ_RCVDATA_INI_WRITE_PEEK	0x00005cfc
+#define FTQ_RCVDATA_COMP_CTL		0x00005d00
+#define FTQ_RCVDATA_COMP_FULL_CNT	0x00005d04
+#define FTQ_RCVDATA_COMP_FIFO_ENQDEQ	0x00005d08
+#define FTQ_RCVDATA_COMP_WRITE_PEEK	0x00005d0c
+#define FTQ_SWTYPE2_CTL			0x00005d10
+#define FTQ_SWTYPE2_FULL_CNT		0x00005d14
+#define FTQ_SWTYPE2_FIFO_ENQDEQ		0x00005d18
+#define FTQ_SWTYPE2_WRITE_PEEK		0x00005d1c
+/* 0x5d20 --> 0x6000 unused */
+
+/* Message signaled interrupt registers */
+#define MSGINT_MODE			0x00006000
+#define  MSGINT_MODE_RESET		 0x00000001
+#define  MSGINT_MODE_ENABLE		 0x00000002
+#define MSGINT_STATUS			0x00006004
+#define MSGINT_FIFO			0x00006008
+/* 0x600c --> 0x6400 unused */
+
+/* DMA completion registers */
+#define DMAC_MODE			0x00006400
+#define  DMAC_MODE_RESET		 0x00000001
+#define  DMAC_MODE_ENABLE		 0x00000002
+/* 0x6404 --> 0x6800 unused */
+
+/* GRC registers */
+#define GRC_MODE			0x00006800
+#define  GRC_MODE_UPD_ON_COAL		0x00000001
+#define  GRC_MODE_BSWAP_NONFRM_DATA	0x00000002
+#define  GRC_MODE_WSWAP_NONFRM_DATA	0x00000004
+#define  GRC_MODE_BSWAP_DATA		0x00000010
+#define  GRC_MODE_WSWAP_DATA		0x00000020
+#define  GRC_MODE_SPLITHDR		0x00000100
+#define  GRC_MODE_NOFRM_CRACKING	0x00000200
+#define  GRC_MODE_INCL_CRC		0x00000400
+#define  GRC_MODE_ALLOW_BAD_FRMS	0x00000800
+#define  GRC_MODE_NOIRQ_ON_SENDS	0x00002000
+#define  GRC_MODE_NOIRQ_ON_RCV		0x00004000
+#define  GRC_MODE_FORCE_PCI32BIT	0x00008000
+#define  GRC_MODE_HOST_STACKUP		0x00010000
+#define  GRC_MODE_HOST_SENDBDS		0x00020000
+#define  GRC_MODE_NO_TX_PHDR_CSUM	0x00100000
+#define  GRC_MODE_NO_RX_PHDR_CSUM	0x00800000
+#define  GRC_MODE_IRQ_ON_TX_CPU_ATTN	0x01000000
+#define  GRC_MODE_IRQ_ON_RX_CPU_ATTN	0x02000000
+#define  GRC_MODE_IRQ_ON_MAC_ATTN	0x04000000
+#define  GRC_MODE_IRQ_ON_DMA_ATTN	0x08000000
+#define  GRC_MODE_IRQ_ON_FLOW_ATTN	0x10000000
+#define  GRC_MODE_4X_NIC_SEND_RINGS	0x20000000
+#define  GRC_MODE_MCAST_FRM_ENABLE	0x40000000
+#define GRC_MISC_CFG			0x00006804
+#define  GRC_MISC_CFG_CORECLK_RESET	0x00000001
+#define  GRC_MISC_CFG_PRESCALAR_MASK	0x000000fe
+#define  GRC_MISC_CFG_PRESCALAR_SHIFT	1
+#define  GRC_MISC_CFG_BOARD_ID_MASK	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5700	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5701	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
+#define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
+#define  GRC_MISC_CFG_BOARD_ID_5788	0x00010000
+#define  GRC_MISC_CFG_BOARD_ID_5788M	0x00018000
+#define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
+#define  GRC_MISC_CFG_KEEP_GPHY_POWER	0x04000000
+#define GRC_LOCAL_CTRL			0x00006808
+#define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
+#define  GRC_LCLCTRL_CLEARINT		0x00000002
+#define  GRC_LCLCTRL_SETINT		0x00000004
+#define  GRC_LCLCTRL_INT_ON_ATTN	0x00000008
+#define  GRC_LCLCTRL_GPIO_INPUT0	0x00000100
+#define  GRC_LCLCTRL_GPIO_INPUT1	0x00000200
+#define  GRC_LCLCTRL_GPIO_INPUT2	0x00000400
+#define  GRC_LCLCTRL_GPIO_OE0		0x00000800
+#define  GRC_LCLCTRL_GPIO_OE1		0x00001000
+#define  GRC_LCLCTRL_GPIO_OE2		0x00002000
+#define  GRC_LCLCTRL_GPIO_OUTPUT0	0x00004000
+#define  GRC_LCLCTRL_GPIO_OUTPUT1	0x00008000
+#define  GRC_LCLCTRL_GPIO_OUTPUT2	0x00010000
+#define  GRC_LCLCTRL_EXTMEM_ENABLE	0x00020000
+#define  GRC_LCLCTRL_MEMSZ_MASK		0x001c0000
+#define  GRC_LCLCTRL_MEMSZ_256K		0x00000000
+#define  GRC_LCLCTRL_MEMSZ_512K		0x00040000
+#define  GRC_LCLCTRL_MEMSZ_1M		0x00080000
+#define  GRC_LCLCTRL_MEMSZ_2M		0x000c0000
+#define  GRC_LCLCTRL_MEMSZ_4M		0x00100000
+#define  GRC_LCLCTRL_MEMSZ_8M		0x00140000
+#define  GRC_LCLCTRL_MEMSZ_16M		0x00180000
+#define  GRC_LCLCTRL_BANK_SELECT	0x00200000
+#define  GRC_LCLCTRL_SSRAM_TYPE		0x00400000
+#define  GRC_LCLCTRL_AUTO_SEEPROM	0x01000000
+#define GRC_TIMER			0x0000680c
+#define GRC_RX_CPU_EVENT		0x00006810
+#define GRC_RX_TIMER_REF		0x00006814
+#define GRC_RX_CPU_SEM			0x00006818
+#define GRC_REMOTE_RX_CPU_ATTN		0x0000681c
+#define GRC_TX_CPU_EVENT		0x00006820
+#define GRC_TX_TIMER_REF		0x00006824
+#define GRC_TX_CPU_SEM			0x00006828
+#define GRC_REMOTE_TX_CPU_ATTN		0x0000682c
+#define GRC_MEM_POWER_UP		0x00006830 /* 64-bit */
+#define GRC_EEPROM_ADDR			0x00006838
+#define  EEPROM_ADDR_WRITE		0x00000000
+#define  EEPROM_ADDR_READ		0x80000000
+#define  EEPROM_ADDR_COMPLETE		0x40000000
+#define  EEPROM_ADDR_FSM_RESET		0x20000000
+#define  EEPROM_ADDR_DEVID_MASK		0x1c000000
+#define  EEPROM_ADDR_DEVID_SHIFT	26
+#define  EEPROM_ADDR_START		0x02000000
+#define  EEPROM_ADDR_CLKPERD_SHIFT	16
+#define  EEPROM_ADDR_ADDR_MASK		0x0000ffff
+#define  EEPROM_ADDR_ADDR_SHIFT		0
+#define  EEPROM_DEFAULT_CLOCK_PERIOD	0x60
+#define  EEPROM_CHIP_SIZE		(64 * 1024)
+#define GRC_EEPROM_DATA			0x0000683c
+#define GRC_EEPROM_CTRL			0x00006840
+#define GRC_MDI_CTRL			0x00006844
+#define GRC_SEEPROM_DELAY		0x00006848
+/* 0x684c --> 0x6c00 unused */
+
+/* 0x6c00 --> 0x7000 unused */
+
+/* NVRAM Control registers */
+#define NVRAM_CMD			0x00007000
+#define  NVRAM_CMD_RESET		 0x00000001
+#define  NVRAM_CMD_DONE			 0x00000008
+#define  NVRAM_CMD_GO			 0x00000010
+#define  NVRAM_CMD_WR			 0x00000020
+#define  NVRAM_CMD_RD			 0x00000000
+#define  NVRAM_CMD_ERASE		 0x00000040
+#define  NVRAM_CMD_FIRST		 0x00000080
+#define  NVRAM_CMD_LAST			 0x00000100
+#define NVRAM_STAT			0x00007004
+#define NVRAM_WRDATA			0x00007008
+#define NVRAM_ADDR			0x0000700c
+#define  NVRAM_ADDR_MSK			0x00ffffff
+#define NVRAM_RDDATA			0x00007010
+#define NVRAM_CFG1			0x00007014
+#define  NVRAM_CFG1_FLASHIF_ENAB	 0x00000001
+#define  NVRAM_CFG1_BUFFERED_MODE	 0x00000002
+#define  NVRAM_CFG1_PASS_THRU		 0x00000004
+#define  NVRAM_CFG1_BIT_BANG		 0x00000008
+#define  NVRAM_CFG1_COMPAT_BYPASS	 0x80000000
+#define NVRAM_CFG2			0x00007018
+#define NVRAM_CFG3			0x0000701c
+#define NVRAM_SWARB			0x00007020
+#define  SWARB_REQ_SET0			 0x00000001
+#define  SWARB_REQ_SET1			 0x00000002
+#define  SWARB_REQ_SET2			 0x00000004
+#define  SWARB_REQ_SET3			 0x00000008
+#define  SWARB_REQ_CLR0			 0x00000010
+#define  SWARB_REQ_CLR1			 0x00000020
+#define  SWARB_REQ_CLR2			 0x00000040
+#define  SWARB_REQ_CLR3			 0x00000080
+#define  SWARB_GNT0			 0x00000100
+#define  SWARB_GNT1			 0x00000200
+#define  SWARB_GNT2			 0x00000400
+#define  SWARB_GNT3			 0x00000800
+#define  SWARB_REQ0			 0x00001000
+#define  SWARB_REQ1			 0x00002000
+#define  SWARB_REQ2			 0x00004000
+#define  SWARB_REQ3			 0x00008000
+#define    NVRAM_BUFFERED_PAGE_SIZE	   264
+#define    NVRAM_BUFFERED_PAGE_POS	   9
+/* 0x7024 --> 0x7400 unused */
+
+/* 0x7400 --> 0x8000 unused */
+
+/* 32K Window into NIC internal memory */
+#define NIC_SRAM_WIN_BASE		0x00008000
+
+/* Offsets into first 32k of NIC internal memory. */
+#define NIC_SRAM_PAGE_ZERO		0x00000000
+#define NIC_SRAM_SEND_RCB		0x00000100 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_RCV_RET_RCB		0x00000200 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_STATS_BLK		0x00000300
+#define NIC_SRAM_STATUS_BLK		0x00000b00
+
+#define NIC_SRAM_FIRMWARE_MBOX		0x00000b50
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC1	 0x4B657654
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC2	 0x4861764b /* !dma on linkchg */
+
+#define NIC_SRAM_DATA_SIG		0x00000b54
+#define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
+
+#define NIC_SRAM_DATA_CFG			0x00000b58
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x0000000c
+#define  NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000008
+#define  NIC_SRAM_DATA_CFG_LED_OUTPUT		 0x00000008
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000010
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000020
+#define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
+#define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
+#define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
+#define  NIC_SRAM_DATA_CFG_MINI_PCI		 0x00001000
+#define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
+
+#define NIC_SRAM_DATA_PHY_ID		0x00000b74
+#define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
+#define  NIC_SRAM_DATA_PHY_ID2_MASK	 0x0000ffff
+
+#define NIC_SRAM_FW_CMD_MBOX		0x00000b78
+#define  FWCMD_NICDRV_ALIVE		 0x00000001
+#define  FWCMD_NICDRV_PAUSE_FW		 0x00000002
+#define  FWCMD_NICDRV_IPV4ADDR_CHG	 0x00000003
+#define  FWCMD_NICDRV_IPV6ADDR_CHG	 0x00000004
+#define  FWCMD_NICDRV_FIX_DMAR		 0x00000005
+#define  FWCMD_NICDRV_FIX_DMAW		 0x00000006
+#define NIC_SRAM_FW_CMD_LEN_MBOX	0x00000b7c
+#define NIC_SRAM_FW_CMD_DATA_MBOX	0x00000b80
+#define NIC_SRAM_FW_ASF_STATUS_MBOX	0x00000c00
+#define NIC_SRAM_FW_DRV_STATE_MBOX	0x00000c04
+#define  DRV_STATE_START		 0x00000001
+#define  DRV_STATE_UNLOAD		 0x00000002
+#define  DRV_STATE_WOL			 0x00000003
+#define  DRV_STATE_SUSPEND		 0x00000004
+
+#define NIC_SRAM_FW_RESET_TYPE_MBOX	0x00000c08
+
+#define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
+#define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
+
+#define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
+
+#define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
+#define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
+#define NIC_SRAM_TX_BUFFER_DESC		0x00004000 /* 512 entries */
+#define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
+#define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
+#define NIC_SRAM_MBUF_POOL_BASE		0x00008000
+#define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
+#define  NIC_SRAM_MBUF_POOL_BASE5705	0x00010000
+#define  NIC_SRAM_MBUF_POOL_SIZE5705	0x0000e000
+
+/* Currently this is fixed. */
+#define PHY_ADDR		0x01
+
+/* Tigon3 specific PHY MII registers. */
+#define  TG3_BMCR_SPEED1000		0x0040
+
+#define MII_TG3_CTRL			0x09 /* 1000-baseT control register */
+#define  MII_TG3_CTRL_ADV_1000_HALF	0x0100
+#define  MII_TG3_CTRL_ADV_1000_FULL	0x0200
+#define  MII_TG3_CTRL_AS_MASTER		0x0800
+#define  MII_TG3_CTRL_ENABLE_AS_MASTER	0x1000
+
+#define MII_TG3_EXT_CTRL		0x10 /* Extended control register */
+#define  MII_TG3_EXT_CTRL_LNK3_LED_MODE	0x0002
+#define  MII_TG3_EXT_CTRL_TBI		0x8000
+
+#define MII_TG3_EXT_STAT		0x11 /* Extended status register */
+#define  MII_TG3_EXT_STAT_LPASS		0x0100
+
+#define MII_TG3_DSP_RW_PORT		0x15 /* DSP coefficient read/write port */
+
+#define MII_TG3_DSP_ADDRESS		0x17 /* DSP address register */
+
+#define MII_TG3_AUX_CTRL		0x18 /* auxilliary control register */
+
+#define MII_TG3_AUX_STAT		0x19 /* auxilliary status register */
+#define MII_TG3_AUX_STAT_LPASS		0x0004
+#define MII_TG3_AUX_STAT_SPDMASK	0x0700
+#define MII_TG3_AUX_STAT_10HALF		0x0100
+#define MII_TG3_AUX_STAT_10FULL		0x0200
+#define MII_TG3_AUX_STAT_100HALF	0x0300
+#define MII_TG3_AUX_STAT_100_4		0x0400
+#define MII_TG3_AUX_STAT_100FULL	0x0500
+#define MII_TG3_AUX_STAT_1000HALF	0x0600
+#define MII_TG3_AUX_STAT_1000FULL	0x0700
+
+#define MII_TG3_ISTAT			0x1a /* IRQ status register */
+#define MII_TG3_IMASK			0x1b /* IRQ mask register */
+
+/* ISTAT/IMASK event bits */
+#define MII_TG3_INT_LINKCHG		0x0002
+#define MII_TG3_INT_SPEEDCHG		0x0004
+#define MII_TG3_INT_DUPLEXCHG		0x0008
+#define MII_TG3_INT_ANEG_PAGE_RX	0x0400
+
+
+/* There are two ways to manage the TX descriptors on the tigon3.
+ * Either the descriptors are in host DMA'able memory, or they
+ * exist only in the cards on-chip SRAM.  All 16 send bds are under
+ * the same mode, they may not be configured individually.
+ *
+ * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags.
+ *
+ * To use host memory TX descriptors:
+ *	1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register.
+ *	   Make sure GRC_MODE_4X_NIC_SEND_RINGS is clear.
+ *	2) Allocate DMA'able memory.
+ *	3) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to DMA address of memory
+ *	      obtained in step 2
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC.
+ *	   c) Set len field of TG3_BDINFO_MAXLEN_FLAGS to number
+ *            of TX descriptors.  Leave flags field clear.
+ *	4) Access TX descriptors via host memory.  The chip
+ *	   will refetch into local SRAM as needed when producer
+ *	   index mailboxes are updated.
+ *
+ * To use on-chip TX descriptors:
+ *	1) Set GRC_MODE_4X_NIC_SEND_RINGS in GRC_MODE register.
+ *	   Make sure GRC_MODE_HOST_SENDBDS is clear.
+ *	2) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to zero.
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC
+ *	   c) TG3_BDINFO_MAXLEN_FLAGS is don't care.
+ *	3) Access TX descriptors directly in on-chip SRAM
+ *	   using normal {read,write}l().  (and not using
+ *         pointer dereferencing of ioremap()'d memory like
+ *	   the broken Broadcom driver does)
+ *
+ * Note that BDINFO_FLAGS_DISABLED should be set in the flags field of
+ * TG3_BDINFO_MAXLEN_FLAGS of all unused SEND_RCB indices.
+ */
+struct tg3_tx_buffer_desc {
+	uint32_t			addr_hi;
+	uint32_t			addr_lo;
+
+	uint32_t			len_flags;
+#define TXD_FLAG_TCPUDP_CSUM		0x0001
+#define TXD_FLAG_IP_CSUM		0x0002
+#define TXD_FLAG_END			0x0004
+#define TXD_FLAG_IP_FRAG		0x0008
+#define TXD_FLAG_IP_FRAG_END		0x0010
+#define TXD_FLAG_VLAN			0x0040
+#define TXD_FLAG_COAL_NOW		0x0080
+#define TXD_FLAG_CPU_PRE_DMA		0x0100
+#define TXD_FLAG_CPU_POST_DMA		0x0200
+#define TXD_FLAG_ADD_SRC_ADDR		0x1000
+#define TXD_FLAG_CHOOSE_SRC_ADDR	0x6000
+#define TXD_FLAG_NO_CRC			0x8000
+#define TXD_LEN_SHIFT			16
+
+	uint32_t			vlan_tag;
+#define TXD_VLAN_TAG_SHIFT		0
+#define TXD_MSS_SHIFT			16
+};
+
+#define TXD_ADDR			0x00UL /* 64-bit */
+#define TXD_LEN_FLAGS			0x08UL /* 32-bit (upper 16-bits are len) */
+#define TXD_VLAN_TAG			0x0cUL /* 32-bit (upper 16-bits are tag) */
+#define TXD_SIZE			0x10UL
+
+struct tg3_rx_buffer_desc {
+	uint32_t			addr_hi;
+	uint32_t			addr_lo;
+
+	uint32_t			idx_len;
+#define RXD_IDX_MASK	0xffff0000
+#define RXD_IDX_SHIFT	16
+#define RXD_LEN_MASK	0x0000ffff
+#define RXD_LEN_SHIFT	0
+
+	uint32_t			type_flags;
+#define RXD_TYPE_SHIFT	16
+#define RXD_FLAGS_SHIFT	0
+
+#define RXD_FLAG_END			0x0004
+#define RXD_FLAG_MINI			0x0800
+#define RXD_FLAG_JUMBO			0x0020
+#define RXD_FLAG_VLAN			0x0040
+#define RXD_FLAG_ERROR			0x0400
+#define RXD_FLAG_IP_CSUM		0x1000
+#define RXD_FLAG_TCPUDP_CSUM		0x2000
+#define RXD_FLAG_IS_TCP			0x4000
+
+	uint32_t			ip_tcp_csum;
+#define RXD_IPCSUM_MASK		0xffff0000
+#define RXD_IPCSUM_SHIFT	16
+#define RXD_TCPCSUM_MASK	0x0000ffff
+#define RXD_TCPCSUM_SHIFT	0
+
+	uint32_t			err_vlan;
+
+#define RXD_VLAN_MASK			0x0000ffff
+
+#define RXD_ERR_BAD_CRC			0x00010000
+#define RXD_ERR_COLLISION		0x00020000
+#define RXD_ERR_LINK_LOST		0x00040000
+#define RXD_ERR_PHY_DECODE		0x00080000
+#define RXD_ERR_ODD_NIBBLE_RCVD_MII	0x00100000
+#define RXD_ERR_MAC_ABRT		0x00200000
+#define RXD_ERR_TOO_SMALL		0x00400000
+#define RXD_ERR_NO_RESOURCES		0x00800000
+#define RXD_ERR_HUGE_FRAME		0x01000000
+#define RXD_ERR_MASK			0xffff0000
+
+	uint32_t			reserved;
+	uint32_t			opaque;
+#define RXD_OPAQUE_INDEX_MASK		0x0000ffff
+#define RXD_OPAQUE_INDEX_SHIFT		0
+#define RXD_OPAQUE_RING_STD		0x00010000
+#define RXD_OPAQUE_RING_JUMBO		0x00020000
+#define RXD_OPAQUE_RING_MINI		0x00040000
+#define RXD_OPAQUE_RING_MASK		0x00070000
+};
+
+struct tg3_ext_rx_buffer_desc {
+	struct {
+		uint32_t		addr_hi;
+		uint32_t		addr_lo;
+	}				addrlist[3];
+	uint32_t			len2_len1;
+	uint32_t			resv_len3;
+	struct tg3_rx_buffer_desc	std;
+};
+
+/* We only use this when testing out the DMA engine
+ * at probe time.  This is the internal format of buffer
+ * descriptors used by the chip at NIC_SRAM_DMA_DESCS.
+ */
+struct tg3_internal_buffer_desc {
+	uint32_t			addr_hi;
+	uint32_t			addr_lo;
+	uint32_t			nic_mbuf;
+	/* XXX FIX THIS */
+#if __BYTE_ORDER == __BIG_ENDIAN
+	uint16_t			cqid_sqid;
+	uint16_t			len;
+#else
+	uint16_t			len;
+	uint16_t			cqid_sqid;
+#endif
+	uint32_t			flags;
+	uint32_t			__cookie1;
+	uint32_t			__cookie2;
+	uint32_t			__cookie3;
+};
+
+#define TG3_HW_STATUS_SIZE		0x50
+struct tg3_hw_status {
+	uint32_t			status;
+#define SD_STATUS_UPDATED		0x00000001
+#define SD_STATUS_LINK_CHG		0x00000002
+#define SD_STATUS_ERROR			0x00000004
+
+	uint32_t			status_tag;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	uint16_t			rx_consumer;
+	uint16_t			rx_jumbo_consumer;
+#else
+	uint16_t			rx_jumbo_consumer;
+	uint16_t			rx_consumer;
+#endif
+
+#if __BYTE_ORDER ==  __BIG_ENDIAN
+	uint16_t			reserved;
+	uint16_t			rx_mini_consumer;
+#else
+	uint16_t			rx_mini_consumer;
+	uint16_t			reserved;
+#endif
+	struct {
+#if __BYTE_ORDER ==  __BIG_ENDIAN
+		uint16_t		tx_consumer;
+		uint16_t		rx_producer;
+#else
+		uint16_t		rx_producer;
+		uint16_t		tx_consumer;
+#endif
+	}				idx[16];
+};
+
+typedef struct {
+	uint32_t high, low;
+} tg3_stat64_t;
+
+struct tg3_hw_stats {
+	uint8_t				__reserved0[0x400-0x300];
+
+	/* Statistics maintained by Receive MAC. */
+	tg3_stat64_t			rx_octets;
+	uint64_t			__reserved1;
+	tg3_stat64_t			rx_fragments;
+	tg3_stat64_t			rx_ucast_packets;
+	tg3_stat64_t			rx_mcast_packets;
+	tg3_stat64_t			rx_bcast_packets;
+	tg3_stat64_t			rx_fcs_errors;
+	tg3_stat64_t			rx_align_errors;
+	tg3_stat64_t			rx_xon_pause_rcvd;
+	tg3_stat64_t			rx_xoff_pause_rcvd;
+	tg3_stat64_t			rx_mac_ctrl_rcvd;
+	tg3_stat64_t			rx_xoff_entered;
+	tg3_stat64_t			rx_frame_too_long_errors;
+	tg3_stat64_t			rx_jabbers;
+	tg3_stat64_t			rx_undersize_packets;
+	tg3_stat64_t			rx_in_length_errors;
+	tg3_stat64_t			rx_out_length_errors;
+	tg3_stat64_t			rx_64_or_less_octet_packets;
+	tg3_stat64_t			rx_65_to_127_octet_packets;
+	tg3_stat64_t			rx_128_to_255_octet_packets;
+	tg3_stat64_t			rx_256_to_511_octet_packets;
+	tg3_stat64_t			rx_512_to_1023_octet_packets;
+	tg3_stat64_t			rx_1024_to_1522_octet_packets;
+	tg3_stat64_t			rx_1523_to_2047_octet_packets;
+	tg3_stat64_t			rx_2048_to_4095_octet_packets;
+	tg3_stat64_t			rx_4096_to_8191_octet_packets;
+	tg3_stat64_t			rx_8192_to_9022_octet_packets;
+
+	uint64_t			__unused0[37];
+
+	/* Statistics maintained by Transmit MAC. */
+	tg3_stat64_t			tx_octets;
+	uint64_t			__reserved2;
+	tg3_stat64_t			tx_collisions;
+	tg3_stat64_t			tx_xon_sent;
+	tg3_stat64_t			tx_xoff_sent;
+	tg3_stat64_t			tx_flow_control;
+	tg3_stat64_t			tx_mac_errors;
+	tg3_stat64_t			tx_single_collisions;
+	tg3_stat64_t			tx_mult_collisions;
+	tg3_stat64_t			tx_deferred;
+	uint64_t			__reserved3;
+	tg3_stat64_t			tx_excessive_collisions;
+	tg3_stat64_t			tx_late_collisions;
+	tg3_stat64_t			tx_collide_2times;
+	tg3_stat64_t			tx_collide_3times;
+	tg3_stat64_t			tx_collide_4times;
+	tg3_stat64_t			tx_collide_5times;
+	tg3_stat64_t			tx_collide_6times;
+	tg3_stat64_t			tx_collide_7times;
+	tg3_stat64_t			tx_collide_8times;
+	tg3_stat64_t			tx_collide_9times;
+	tg3_stat64_t			tx_collide_10times;
+	tg3_stat64_t			tx_collide_11times;
+	tg3_stat64_t			tx_collide_12times;
+	tg3_stat64_t			tx_collide_13times;
+	tg3_stat64_t			tx_collide_14times;
+	tg3_stat64_t			tx_collide_15times;
+	tg3_stat64_t			tx_ucast_packets;
+	tg3_stat64_t			tx_mcast_packets;
+	tg3_stat64_t			tx_bcast_packets;
+	tg3_stat64_t			tx_carrier_sense_errors;
+	tg3_stat64_t			tx_discards;
+	tg3_stat64_t			tx_errors;
+
+	uint64_t			__unused1[31];
+
+	/* Statistics maintained by Receive List Placement. */
+	tg3_stat64_t			COS_rx_packets[16];
+	tg3_stat64_t			COS_rx_filter_dropped;
+	tg3_stat64_t			dma_writeq_full;
+	tg3_stat64_t			dma_write_prioq_full;
+	tg3_stat64_t			rxbds_empty;
+	tg3_stat64_t			rx_discards;
+	tg3_stat64_t			rx_errors;
+	tg3_stat64_t			rx_threshold_hit;
+
+	uint64_t			__unused2[9];
+
+	/* Statistics maintained by Send Data Initiator. */
+	tg3_stat64_t			COS_out_packets[16];
+	tg3_stat64_t			dma_readq_full;
+	tg3_stat64_t			dma_read_prioq_full;
+	tg3_stat64_t			tx_comp_queue_full;
+
+	/* Statistics maintained by Host Coalescing. */
+	tg3_stat64_t			ring_set_send_prod_index;
+	tg3_stat64_t			ring_status_update;
+	tg3_stat64_t			nic_irqs;
+	tg3_stat64_t			nic_avoided_irqs;
+	tg3_stat64_t			nic_tx_threshold_hit;
+
+	uint8_t				__reserved4[0xb00-0x9c0];
+};
+
+enum phy_led_mode {
+	led_mode_auto,
+	led_mode_three_link,
+	led_mode_link10
+};
+
+#if 0
+/* 'mapping' is superfluous as the chip does not write into
+ * the tx/rx post rings so we could just fetch it from there.
+ * But the cache behavior is better how we are doing it now.
+ */
+struct ring_info {
+	struct sk_buff			*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+struct tx_ring_info {
+	struct sk_buff			*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	uint32_t			prev_vlan_tag;
+};
+#endif
+
+struct tg3_config_info {
+	uint32_t			flags;
+};
+
+struct tg3_link_config {
+	/* Describes what we're trying to get. */
+	uint32_t			advertising;
+#if 0
+	uint16_t			speed;
+	uint8_t				duplex;
+	uint8_t				autoneg;
+#define SPEED_INVALID		0xffff
+#define DUPLEX_INVALID		0xff
+#define AUTONEG_INVALID		0xff
+#endif
+
+	/* Describes what we actually have. */
+	uint8_t				active_speed;
+	uint8_t				active_duplex;
+
+	/* When we go in and out of low power mode we need
+	 * to swap with this state.
+	 */
+#if 0
+	int				phy_is_low_power;
+	uint16_t			orig_speed;
+	uint8_t				orig_duplex;
+	uint8_t				orig_autoneg;
+#endif
+};
+
+struct tg3_bufmgr_config {
+	uint32_t		mbuf_read_dma_low_water;
+	uint32_t		mbuf_mac_rx_low_water;
+	uint32_t		mbuf_high_water;
+
+	uint32_t		mbuf_read_dma_low_water_jumbo;
+	uint32_t		mbuf_mac_rx_low_water_jumbo;
+	uint32_t		mbuf_high_water_jumbo;
+
+	uint32_t		dma_low_water;
+	uint32_t		dma_high_water;
+};
+
+struct tg3 {
+#if 0
+	/* SMP locking strategy:
+	 *
+	 * lock: Held during all operations except TX packet
+	 *       processing.
+	 *
+	 * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx
+	 *
+	 * If you want to shut up all asynchronous processing you must
+	 * acquire both locks, 'lock' taken before 'tx_lock'.  IRQs must
+	 * be disabled to take 'lock' but only softirq disabling is
+	 * necessary for acquisition of 'tx_lock'.
+	 */
+	spinlock_t			lock;
+	spinlock_t			tx_lock;
+#endif
+
+	uint32_t			tx_prod;
+#if 0
+	uint32_t			tx_cons;
+#endif
+	uint32_t			rx_rcb_ptr;
+	uint32_t			rx_std_ptr;
+#if 0
+	uint32_t			rx_jumbo_ptr;
+	spinlock_t			indirect_lock;
+
+	struct net_device_stats		net_stats;
+	struct net_device_stats		net_stats_prev;
+#endif
+	unsigned long			phy_crc_errors;
+
+#if 0
+	uint32_t			rx_offset;
+#endif
+	uint32_t			tg3_flags;
+#if 0
+#define TG3_FLAG_HOST_TXDS		0x00000001
+#endif
+#define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
+#define TG3_FLAG_RX_CHECKSUMS		0x00000004
+#define TG3_FLAG_USE_LINKCHG_REG	0x00000008
+#define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
+#define TG3_FLAG_ENABLE_ASF		0x00000020
+#define TG3_FLAG_5701_REG_WRITE_BUG	0x00000040
+#define TG3_FLAG_POLL_SERDES		0x00000080
+#define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
+#define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
+#define TG3_FLAG_WOL_SPEED_100MB	0x00000400
+#define TG3_FLAG_WOL_ENABLE		0x00000800
+#define TG3_FLAG_EEPROM_WRITE_PROT	0x00001000
+#define TG3_FLAG_NVRAM			0x00002000
+#define TG3_FLAG_NVRAM_BUFFERED		0x00004000
+#define TG3_FLAG_RX_PAUSE		0x00008000
+#define TG3_FLAG_TX_PAUSE		0x00010000
+#define TG3_FLAG_PCIX_MODE		0x00020000
+#define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
+#define TG3_FLAG_PCI_32BIT		0x00080000
+#define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
+#define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
+#define TG3_FLAG_SERDES_WOL_CAP		0x00400000
+#define TG3_FLAG_JUMBO_ENABLE		0x00800000
+#define TG3_FLAG_10_100_ONLY		0x01000000
+#define TG3_FLAG_PAUSE_AUTONEG		0x02000000
+#define TG3_FLAG_PAUSE_RX		0x04000000
+#define TG3_FLAG_PAUSE_TX		0x08000000
+#define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
+#define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
+#define TG3_FLAG_SPLIT_MODE		0x40000000
+#define TG3_FLAG_INIT_COMPLETE		0x80000000
+
+	uint32_t			tg3_flags2;
+#define TG3_FLG2_RESTART_TIMER		0x00000001
+#define TG3_FLG2_SUN_5704		0x00000002
+#define TG3_FLG2_NO_ETH_WIRE_SPEED	0x00000004
+#define TG3_FLG2_IS_5788		0x00000008
+#define TG3_FLG2_MAX_RXPEND_64		0x00000010
+#define TG3_FLG2_TSO_CAPABLE		0x00000020
+  // Alf: Hope I'm not breaking anything here !
+#define TG3_FLG2_PCI_EXPRESS            0x00000040
+
+
+
+	uint32_t			split_mode_max_reqs;
+#define SPLIT_MODE_5704_MAX_REQ		3
+
+#if 0
+	struct timer_list		timer;
+	uint16_t			timer_counter;
+	uint16_t			timer_multiplier;
+	uint32_t			timer_offset;
+	uint16_t			asf_counter;
+	uint16_t			asf_multiplier;
+#endif
+
+	struct tg3_link_config		link_config;
+	struct tg3_bufmgr_config	bufmgr_config;
+
+#if 0
+	uint32_t			rx_pending;
+	uint32_t			rx_jumbo_pending;
+	uint32_t			tx_pending;
+#endif
+
+	/* cache h/w values, often passed straight to h/w */
+	uint32_t			rx_mode;
+	uint32_t			tx_mode;
+	uint32_t			mac_mode;
+	uint32_t			mi_mode;
+	uint32_t			misc_host_ctrl;
+	uint32_t			grc_mode;
+	uint32_t			grc_local_ctrl;
+	uint32_t			dma_rwctrl;
+#if 0
+	uint32_t			coalesce_mode;
+#endif
+
+	/* PCI block */
+	uint16_t			pci_chip_rev_id;
+#if 0
+	uint8_t				pci_cacheline_sz;
+	uint8_t				pci_lat_timer;
+	uint8_t				pci_hdr_type;
+	uint8_t				pci_bist;
+#endif
+	uint32_t			pci_cfg_state[64 / sizeof(uint32_t)];
+
+	int				pm_cap;
+
+	/* PHY info */
+	uint32_t			phy_id;
+#define PHY_ID_MASK			0xfffffff0
+#define PHY_ID_BCM5400			0x60008040
+#define PHY_ID_BCM5401			0x60008050
+#define PHY_ID_BCM5411			0x60008070
+#define PHY_ID_BCM5701			0x60008110
+#define PHY_ID_BCM5703			0x60008160
+#define PHY_ID_BCM5704			0x60008190
+#define PHY_ID_BCM5705			0x600081a0
+#define PHY_ID_BCM5750			0x60008180
+#define PHY_ID_BCM5787			0xbc050ce0
+#define PHY_ID_BCM8002			0x60010140
+#define PHY_ID_BCM5751			0x00206180
+#define PHY_ID_SERDES			0xfeedbee0
+#define PHY_ID_INVALID			0xffffffff
+#define PHY_ID_REV_MASK			0x0000000f
+#define PHY_REV_BCM5401_B0		0x1
+#define PHY_REV_BCM5401_B2		0x3
+#define PHY_REV_BCM5401_C0		0x6
+#define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
+
+	enum phy_led_mode		led_mode;
+
+	char				board_part_number[24];
+	uint32_t			nic_sram_data_cfg;
+	uint32_t			pci_clock_ctrl;
+#if 0
+	struct pci_device		*pdev_peer;
+#endif
+
+	/* This macro assumes the passed PHY ID is already masked
+	 * with PHY_ID_MASK.
+	 */
+#define KNOWN_PHY_ID(X)		\
+	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
+	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
+	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
+	 (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
+	 (X) == PHY_ID_BCM5751 || (X) == PHY_ID_BCM5787 || \
+	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
+
+	unsigned long			regs;
+	struct pci_device		*pdev;
+	struct nic			*nic;
+#if 0
+	struct net_device		*dev;
+#endif
+#if TG3_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
+#endif
+
+	struct tg3_rx_buffer_desc	*rx_std;
+#if 0
+	struct ring_info		*rx_std_buffers;
+	dma_addr_t			rx_std_mapping;
+	struct tg3_rx_buffer_desc	*rx_jumbo;
+	struct ring_info		*rx_jumbo_buffers;
+	dma_addr_t			rx_jumbo_mapping;
+#endif
+
+	struct tg3_rx_buffer_desc	*rx_rcb;
+#if 0
+	dma_addr_t			rx_rcb_mapping;
+#endif
+
+	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
+	struct tg3_tx_buffer_desc	*tx_ring;
+#if 0
+	struct tx_ring_info		*tx_buffers;
+	dma_addr_t			tx_desc_mapping;
+#endif
+
+	struct tg3_hw_status		*hw_status;
+#if 0
+	dma_addr_t			status_mapping;
+#endif
+#if 0
+	uint32_t			msg_enable;
+#endif
+
+	struct tg3_hw_stats		*hw_stats;
+#if 0
+	dma_addr_t			stats_mapping;
+#endif
+
+	int				carrier_ok;
+	uint16_t			subsystem_vendor;
+	uint16_t			subsystem_device;
+};
+
+#endif /* !(_T3_H) */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.c
new file mode 100644
index 0000000..b1a09d1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.c
@@ -0,0 +1,1723 @@
+/**************************************************************************
+*
+*    tlan.c -- Etherboot device driver for the Texas Instruments ThunderLAN
+*    Written 2003-2003 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code based on:
+*	lan.c: Linux ThunderLan Driver:
+*
+*	by James Banks
+*
+*  	(C) 1997-1998 Caldera, Inc.
+*	(C) 1998 James Banks
+*	(C) 1999-2001 Torben Mathiasen
+*	(C) 2002 Samuel Chessman
+*
+*    REVISION HISTORY:
+*    ================
+*    v1.0	07-08-2003	timlegge	Initial not quite working version
+*    v1.1	07-27-2003	timlegge	Sync 5.0 and 5.1 versions
+*    v1.2	08-19-2003	timlegge	Implement Multicast Support
+*    v1.3	08-23-2003	timlegge	Fix the transmit Function
+*    v1.4	01-17-2004	timlegge	Initial driver output cleanup    
+*    
+*    Indent Options: indent -kr -i8
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include <mii.h>
+#include "tlan.h"
+
+#define drv_version "v1.4"
+#define drv_date "01-17-2004"
+
+/* NIC specific static variables go here */
+#define HZ 100
+#define TX_TIME_OUT	  (6*HZ)
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+static void TLan_ResetLists(struct nic *nic __unused);
+static void TLan_ResetAdapter(struct nic *nic __unused);
+static void TLan_FinishReset(struct nic *nic __unused);
+
+static void TLan_EeSendStart(u16);
+static int TLan_EeSendByte(u16, u8, int);
+static void TLan_EeReceiveByte(u16, u8 *, int);
+static int TLan_EeReadByte(u16 io_base, u8, u8 *);
+
+static void TLan_PhyDetect(struct nic *nic);
+static void TLan_PhyPowerDown(struct nic *nic);
+static void TLan_PhyPowerUp(struct nic *nic);
+
+
+static void TLan_SetMac(struct nic *nic __unused, int areg, unsigned char *mac);
+
+static void TLan_PhyReset(struct nic *nic);
+static void TLan_PhyStartLink(struct nic *nic);
+static void TLan_PhyFinishAutoNeg(struct nic *nic);
+
+#ifdef MONITOR
+static void TLan_PhyMonitor(struct nic *nic);
+#endif
+
+
+static void refill_rx(struct nic *nic __unused);
+
+static int TLan_MiiReadReg(struct nic *nic __unused, u16, u16, u16 *);
+static void TLan_MiiSendData(u16, u32, unsigned);
+static void TLan_MiiSync(u16);
+static void TLan_MiiWriteReg(struct nic *nic __unused, u16, u16, u16);
+
+
+static const char *media[] = {
+	"10BaseT-HD ", "10BaseT-FD ", "100baseTx-HD ",
+	"100baseTx-FD", "100baseT4", 0
+};
+
+/* This much match tlan_pci_tbl[]!  */
+enum tlan_nics {
+	NETEL10 = 0, NETEL100 = 1, NETFLEX3I = 2, THUNDER = 3, NETFLEX3B =
+	    4, NETEL100PI = 5,
+	NETEL100D = 6, NETEL100I = 7, OC2183 = 8, OC2325 = 9, OC2326 =
+	    10, NETELLIGENT_10_100_WS_5100 = 11,
+	NETELLIGENT_10_T2 = 12
+};
+
+struct pci_id_info {
+	const char *name;
+	int nic_id;
+	struct match_info {
+		u32 pci, pci_mask, subsystem, subsystem_mask;
+		u32 revision, revision_mask;	/* Only 8 bits. */
+	} id;
+	u32 flags;
+	u16 addrOfs;		/* Address Offset */
+};
+
+static const struct pci_id_info tlan_pci_tbl[] = {
+	{"Compaq Netelligent 10 T PCI UTP", NETEL10,
+	 {0xae340e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
+	{"Compaq Netelligent 10/100 TX PCI UTP", NETEL100,
+	 {0xae320e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
+	{"Compaq Integrated NetFlex-3/P", NETFLEX3I,
+	 {0xae350e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_NONE, 0x83},
+	{"Compaq NetFlex-3/P", THUNDER,
+	 {0xf1300e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
+	{"Compaq NetFlex-3/P", NETFLEX3B,
+	 {0xf1500e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_NONE, 0x83},
+	{"Compaq Netelligent Integrated 10/100 TX UTP", NETEL100PI,
+	 {0xae430e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
+	{"Compaq Netelligent Dual 10/100 TX PCI UTP", NETEL100D,
+	 {0xae400e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_NONE, 0x83},
+	{"Compaq Netelligent 10/100 TX Embedded UTP", NETEL100I,
+	 {0xb0110e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_NONE, 0x83},
+	{"Olicom OC-2183/2185", OC2183,
+	 {0x0013108d, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_USE_INTERN_10, 0x83},
+	{"Olicom OC-2325", OC2325,
+	 {0x0012108d, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_UNMANAGED_PHY, 0xF8},
+	{"Olicom OC-2326", OC2326,
+	 {0x0014108d, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_USE_INTERN_10, 0xF8},
+	{"Compaq Netelligent 10/100 TX UTP", NETELLIGENT_10_100_WS_5100,
+	 {0xb0300e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
+	{"Compaq Netelligent 10 T/2 PCI UTP/Coax", NETELLIGENT_10_T2,
+	 {0xb0120e11, 0xffffffff, 0, 0, 0, 0},
+	 TLAN_ADAPTER_NONE, 0x83},
+	{"Compaq NetFlex-3/E", 0,	/* EISA card */
+	 {0, 0, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED | TLAN_ADAPTER_UNMANAGED_PHY |
+	 TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
+	{"Compaq NetFlex-3/E", 0,	/* EISA card */
+	 {0, 0, 0, 0, 0, 0},
+	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
+	{0, 0,
+	 {0, 0, 0, 0, 0, 0},
+	 0, 0},
+};
+
+struct TLanList {
+	u32 forward;
+	u16 cStat;
+	u16 frameSize;
+	struct {
+		u32 count;
+		u32 address;
+	} buffer[TLAN_BUFFERS_PER_LIST];
+};
+
+struct {
+	struct TLanList tx_ring[TLAN_NUM_TX_LISTS];
+	unsigned char txb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_TX_LISTS];
+	struct TLanList rx_ring[TLAN_NUM_RX_LISTS];
+	unsigned char rxb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_RX_LISTS];
+} tlan_buffers __shared;
+#define tx_ring tlan_buffers.tx_ring
+#define txb tlan_buffers.txb
+#define rx_ring tlan_buffers.rx_ring
+#define rxb tlan_buffers.rxb
+
+typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
+
+static int chip_idx;
+
+/*****************************************************************
+* TLAN Private Information Structure
+*
+****************************************************************/
+static struct tlan_private {
+	unsigned short vendor_id;	/* PCI Vendor code */
+	unsigned short dev_id;	/* PCI Device code */
+	const char *nic_name;
+	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indicies */
+	unsigned rx_buf_sz;	/* Based on mtu + Slack */
+	struct TLanList *txList;
+	u32 txHead;
+	u32 txInProgress;
+	u32 txTail;
+	int eoc;
+	u32 phyOnline;
+	u32 aui;
+	u32 duplex;
+	u32 phy[2];
+	u32 phyNum;
+	u32 speed;
+	u8 tlanRev;
+	u8 tlanFullDuplex;
+	u8 link;
+	u8 neg_be_verbose;
+} TLanPrivateInfo;
+
+static struct tlan_private *priv;
+
+static u32 BASE;
+
+/***************************************************************
+*	TLan_ResetLists
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		dev	The device structure with the list
+*			stuctures to be reset.
+*
+*	This routine sets the variables associated with managing
+*	the TLAN lists to their initial values.
+*
+**************************************************************/
+
+static void TLan_ResetLists(struct nic *nic __unused)
+{
+
+	int i;
+	struct TLanList *list;
+	priv->txHead = 0;
+	priv->txTail = 0;
+
+	for (i = 0; i < TLAN_NUM_TX_LISTS; i++) {
+		list = &tx_ring[i];
+		list->cStat = TLAN_CSTAT_UNUSED;
+		list->buffer[0].address = virt_to_bus(txb + 
+				(i * TLAN_MAX_FRAME_SIZE)); 
+		list->buffer[2].count = 0;
+		list->buffer[2].address = 0;
+		list->buffer[9].address = 0;
+	}
+
+	priv->cur_rx = 0;
+	priv->rx_buf_sz = (TLAN_MAX_FRAME_SIZE);
+//	priv->rx_head_desc = &rx_ring[0];
+
+	/* Initialize all the Rx descriptors */
+	for (i = 0; i < TLAN_NUM_RX_LISTS; i++) {
+		rx_ring[i].forward = virt_to_le32desc(&rx_ring[i + 1]);
+		rx_ring[i].cStat = TLAN_CSTAT_READY;
+		rx_ring[i].frameSize = TLAN_MAX_FRAME_SIZE;
+		rx_ring[i].buffer[0].count =
+		    TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
+		rx_ring[i].buffer[0].address =
+		    virt_to_le32desc(&rxb[i * TLAN_MAX_FRAME_SIZE]);
+		rx_ring[i].buffer[1].count = 0;
+		rx_ring[i].buffer[1].address = 0;
+	}
+
+	/* Mark the last entry as wrapping the ring */
+	rx_ring[i - 1].forward = virt_to_le32desc(&rx_ring[0]);
+	priv->dirty_rx = (unsigned int) (i - TLAN_NUM_RX_LISTS);
+
+} /* TLan_ResetLists */
+
+/***************************************************************
+*	TLan_Reset
+*
+*	Returns:
+*		0
+*	Parms:
+*		dev	Pointer to device structure of adapter
+*			to be reset.
+*
+*	This function resets the adapter and it's physical
+*	device.  See Chap. 3, pp. 9-10 of the "ThunderLAN
+*	Programmer's Guide" for details.  The routine tries to
+*	implement what is detailed there, though adjustments
+*	have been made.
+*
+**************************************************************/
+
+void TLan_ResetAdapter(struct nic *nic __unused)
+{
+	int i;
+	u32 addr;
+	u32 data;
+	u8 data8;
+
+	priv->tlanFullDuplex = FALSE;
+	priv->phyOnline = 0;
+/*  1.	Assert reset bit. */
+
+	data = inl(BASE + TLAN_HOST_CMD);
+	data |= TLAN_HC_AD_RST;
+	outl(data, BASE + TLAN_HOST_CMD);
+
+	udelay(1000);
+
+/*  2.	Turn off interrupts. ( Probably isn't necessary ) */
+
+	data = inl(BASE + TLAN_HOST_CMD);
+	data |= TLAN_HC_INT_OFF;
+	outl(data, BASE + TLAN_HOST_CMD);
+/*  3.	Clear AREGs and HASHs. */
+
+	for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) {
+		TLan_DioWrite32(BASE, (u16) i, 0);
+	}
+
+/*  4.	Setup NetConfig register. */
+
+	data =
+	    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
+	TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
+
+/*  5.	Load Ld_Tmr and Ld_Thr in HOST_CMD. */
+
+	outl(TLAN_HC_LD_TMR | 0x3f, BASE + TLAN_HOST_CMD);
+	outl(TLAN_HC_LD_THR | 0x0, BASE + TLAN_HOST_CMD);
+
+/*  6.	Unreset the MII by setting NMRST (in NetSio) to 1. */
+
+	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
+	addr = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
+	TLan_SetBit(TLAN_NET_SIO_NMRST, addr);
+
+/*  7.	Setup the remaining registers. */
+
+	if (priv->tlanRev >= 0x30) {
+		data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
+		TLan_DioWrite8(BASE, TLAN_INT_DIS, data8);
+	}
+	TLan_PhyDetect(nic);
+	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
+
+	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_BIT_RATE_PHY) {
+		data |= TLAN_NET_CFG_BIT;
+		if (priv->aui == 1) {
+			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x0a);
+		} else if (priv->duplex == TLAN_DUPLEX_FULL) {
+			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x00);
+			priv->tlanFullDuplex = TRUE;
+		} else {
+			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x08);
+		}
+	}
+
+	if (priv->phyNum == 0) {
+		data |= TLAN_NET_CFG_PHY_EN;
+	}
+	TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
+
+	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
+		TLan_FinishReset(nic);
+	} else {
+		TLan_PhyPowerDown(nic);
+	}
+
+}	/* TLan_ResetAdapter */
+
+void TLan_FinishReset(struct nic *nic)
+{
+
+	u8 data;
+	u32 phy;
+	u8 sio;
+	u16 status;
+	u16 partner;
+	u16 tlphy_ctl;
+	u16 tlphy_par;
+	u16 tlphy_id1, tlphy_id2;
+	int i;
+
+	phy = priv->phy[priv->phyNum];
+
+	data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
+	if (priv->tlanFullDuplex) {
+		data |= TLAN_NET_CMD_DUPLEX;
+	}
+	TLan_DioWrite8(BASE, TLAN_NET_CMD, data);
+	data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
+	if (priv->phyNum == 0) {
+		data |= TLAN_NET_MASK_MASK7;
+	}
+	TLan_DioWrite8(BASE, TLAN_NET_MASK, data);
+	TLan_DioWrite16(BASE, TLAN_MAX_RX, ((1536) + 7) & ~7);
+	TLan_MiiReadReg(nic, phy, MII_PHYSID1, &tlphy_id1);
+	TLan_MiiReadReg(nic, phy, MII_PHYSID2, &tlphy_id2);
+
+	if ((tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY)
+	    || (priv->aui)) {
+		status = BMSR_LSTATUS;
+		DBG ( "TLAN:  %s: Link forced.\n", priv->nic_name );
+	} else {
+		TLan_MiiReadReg(nic, phy, MII_BMSR, &status);
+		udelay(1000);
+		TLan_MiiReadReg(nic, phy, MII_BMSR, &status);
+		if ((status & BMSR_LSTATUS) &&	/* We only support link info on Nat.Sem. PHY's */
+		    (tlphy_id1 == NAT_SEM_ID1)
+		    && (tlphy_id2 == NAT_SEM_ID2)) {
+			TLan_MiiReadReg(nic, phy, MII_LPA, &partner);
+			TLan_MiiReadReg(nic, phy, TLAN_TLPHY_PAR,
+					&tlphy_par);
+
+			DBG ( "TLAN: %s: Link active with ",
+			       priv->nic_name );
+			if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
+				DBG ( "forced 10%sMbps %s-Duplex\n",
+				       tlphy_par & TLAN_PHY_SPEED_100 ? ""
+				       : "0",
+				       tlphy_par & TLAN_PHY_DUPLEX_FULL ?
+				       "Full" : "Half" );
+			} else {
+				DBG 
+				    ( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n",
+				     tlphy_par & TLAN_PHY_SPEED_100 ? "" :
+				     "0",
+				     tlphy_par & TLAN_PHY_DUPLEX_FULL ?
+				     "Full" : "Half" );
+				DBG ( "TLAN: Partner capability: " );
+				for (i = 5; i <= 10; i++)
+					if (partner & (1 << i)) {
+						DBG ( "%s", media[i - 5] );
+					}
+				DBG ( "\n" );
+			}
+
+			TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
+#ifdef MONITOR
+			/* We have link beat..for now anyway */
+			priv->link = 1;
+			/*Enabling link beat monitoring */
+			/* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_LINK_BEAT ); */
+			mdelay(10000);
+			TLan_PhyMonitor(nic);
+#endif
+		} else if (status & BMSR_LSTATUS) {
+			DBG ( "TLAN: %s: Link active\n", priv->nic_name );
+			TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
+		}
+	}
+
+	if (priv->phyNum == 0) {
+		TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tlphy_ctl);
+		tlphy_ctl |= TLAN_TC_INTEN;
+		TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tlphy_ctl);
+		sio = TLan_DioRead8(BASE, TLAN_NET_SIO);
+		sio |= TLAN_NET_SIO_MINTEN;
+		TLan_DioWrite8(BASE, TLAN_NET_SIO, sio);
+	}
+
+	if (status & BMSR_LSTATUS) {
+		TLan_SetMac(nic, 0, nic->node_addr);
+		priv->phyOnline = 1;
+		outb((TLAN_HC_INT_ON >> 8), BASE + TLAN_HOST_CMD + 1);
+		outl(virt_to_bus(&rx_ring), BASE + TLAN_CH_PARM);
+		outl(TLAN_HC_GO | TLAN_HC_RT, BASE + TLAN_HOST_CMD);
+	} else {
+		DBG 
+		    ( "TLAN: %s: Link inactive, will retry in 10 secs...\n",
+		     priv->nic_name );
+		/* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_FINISH_RESET ); */
+		mdelay(10000);
+		TLan_FinishReset(nic);
+		return;
+
+	}
+
+}	/* TLan_FinishReset */
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int tlan_poll(struct nic *nic, int retrieve)
+{
+	/* return true if there's an ethernet packet ready to read */
+	/* nic->packet should contain data on return */
+	/* nic->packetlen should contain length of data */
+	u32 framesize;
+	u32 host_cmd = 0;
+	u32 ack = 1;
+	int eoc = 0;
+	int entry = priv->cur_rx % TLAN_NUM_RX_LISTS;
+	u16 tmpCStat = le32_to_cpu(rx_ring[entry].cStat);
+	u16 host_int = inw(BASE + TLAN_HOST_INT);
+
+	if ((tmpCStat & TLAN_CSTAT_FRM_CMP) && !retrieve)
+	  return 1;
+
+	outw(host_int, BASE + TLAN_HOST_INT);
+
+	if (!(tmpCStat & TLAN_CSTAT_FRM_CMP))
+		return 0;
+
+	/* printf("PI-1: 0x%hX\n", host_int); */
+	if (tmpCStat & TLAN_CSTAT_EOC)
+		eoc = 1;
+
+	framesize = rx_ring[entry].frameSize;
+
+	nic->packetlen = framesize;
+
+	DBG ( ".%d.", (unsigned int) framesize ); 
+     
+	memcpy(nic->packet, rxb +
+	       (priv->cur_rx * TLAN_MAX_FRAME_SIZE), nic->packetlen);
+
+	rx_ring[entry].cStat = 0;
+
+	DBG ( "%d", entry );  
+
+	entry = (entry + 1) % TLAN_NUM_RX_LISTS;
+	priv->cur_rx = entry;
+	if (eoc) {
+		if ((rx_ring[entry].cStat & TLAN_CSTAT_READY) ==
+		    TLAN_CSTAT_READY) {
+			ack |= TLAN_HC_GO | TLAN_HC_RT;
+			host_cmd = TLAN_HC_ACK | ack | 0x001C0000;
+			outl(host_cmd, BASE + TLAN_HOST_CMD);
+		}
+	} else {
+		host_cmd = TLAN_HC_ACK | ack | (0x000C0000);
+		outl(host_cmd, BASE + TLAN_HOST_CMD);
+		
+		DBG ( "AC: 0x%hX\n", inw(BASE + TLAN_CH_PARM) ); 
+		DBG ( "PI-2: 0x%hX\n", inw(BASE + TLAN_HOST_INT) );
+	}
+	refill_rx(nic);
+	return (1);		/* initially as this is called to flush the input */
+}
+
+static void refill_rx(struct nic *nic __unused)
+{
+	int entry = 0;
+
+	for (;
+	     (priv->cur_rx - priv->dirty_rx +
+	      TLAN_NUM_RX_LISTS) % TLAN_NUM_RX_LISTS > 0;
+	     priv->dirty_rx = (priv->dirty_rx + 1) % TLAN_NUM_RX_LISTS) {
+		entry = priv->dirty_rx % TLAN_NUM_TX_LISTS;
+		rx_ring[entry].frameSize = TLAN_MAX_FRAME_SIZE;
+		rx_ring[entry].cStat = TLAN_CSTAT_READY;
+	}
+
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void tlan_transmit(struct nic *nic, const char *d,	/* Destination */
+			  unsigned int t,	/* Type */
+			  unsigned int s,	/* size */
+			  const char *p)
+{				/* Packet */
+	u16 nstype;
+	u32 to;
+	struct TLanList *tail_list;
+	struct TLanList *head_list;
+	u8 *tail_buffer;
+	u32 ack = 0;
+	u32 host_cmd;
+	int eoc = 0;
+	u16 tmpCStat;
+	u16 host_int = inw(BASE + TLAN_HOST_INT);
+
+	int entry = 0;
+
+	DBG ( "INT0-0x%hX\n", host_int );
+
+	if (!priv->phyOnline) {
+		printf("TRANSMIT:  %s PHY is not ready\n", priv->nic_name);
+		return;
+	}
+
+	tail_list = priv->txList + priv->txTail;
+
+	if (tail_list->cStat != TLAN_CSTAT_UNUSED) {
+		printf("TRANSMIT: %s is busy (Head=%p Tail=%x)\n",
+		       priv->nic_name, priv->txList, (unsigned int) priv->txTail);
+		tx_ring[entry].cStat = TLAN_CSTAT_UNUSED;
+//		priv->txBusyCount++;
+		return;
+	}
+
+	tail_list->forward = 0;
+
+	tail_buffer = txb + (priv->txTail * TLAN_MAX_FRAME_SIZE);
+
+	/* send the packet to destination */
+	memcpy(tail_buffer, d, ETH_ALEN);
+	memcpy(tail_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN);
+	nstype = htons((u16) t);
+	memcpy(tail_buffer + 2 * ETH_ALEN, (u8 *) & nstype, 2);
+	memcpy(tail_buffer + ETH_HLEN, p, s);
+
+	s += ETH_HLEN;
+	s &= 0x0FFF;
+	while (s < ETH_ZLEN)
+		tail_buffer[s++] = '\0';
+
+	/*=====================================================*/
+	/* Receive
+	 * 0000 0000 0001 1100
+	 * 0000 0000 0000 1100
+	 * 0000 0000 0000 0011 = 0x0003
+	 *
+	 * 0000 0000 0000 0000 0000 0000 0000 0011
+	 * 0000 0000 0000 1100 0000 0000 0000 0000 = 0x000C0000
+	 *
+	 * Transmit
+	 * 0000 0000 0001 1100
+	 * 0000 0000 0000 0100
+	 * 0000 0000 0000 0001 = 0x0001
+	 *
+	 * 0000 0000 0000 0000 0000 0000 0000 0001
+	 * 0000 0000 0000 0100 0000 0000 0000 0000 = 0x00040000
+	 * */
+
+	/* Setup the transmit descriptor */
+	tail_list->frameSize = (u16) s;
+	tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) s;
+	tail_list->buffer[1].count = 0;
+	tail_list->buffer[1].address = 0;
+
+	tail_list->cStat = TLAN_CSTAT_READY;
+
+	DBG ( "INT1-0x%hX\n", inw(BASE + TLAN_HOST_INT) );
+
+	if (!priv->txInProgress) {
+		priv->txInProgress = 1;
+		outl(virt_to_le32desc(tail_list), BASE + TLAN_CH_PARM);
+		outl(TLAN_HC_GO, BASE + TLAN_HOST_CMD);
+	} else {
+		if (priv->txTail == 0) {
+			DBG ( "Out buffer\n" );
+			(priv->txList + (TLAN_NUM_TX_LISTS - 1))->forward =
+			    virt_to_le32desc(tail_list);
+		} else {
+			DBG ( "Fix this \n" );
+			(priv->txList + (priv->txTail - 1))->forward =
+			    virt_to_le32desc(tail_list);
+		}
+	}
+	
+	CIRC_INC(priv->txTail, TLAN_NUM_TX_LISTS);
+
+	DBG ( "INT2-0x%hX\n", inw(BASE + TLAN_HOST_INT) );
+
+	to = currticks() + TX_TIME_OUT;
+	while ((tail_list->cStat == TLAN_CSTAT_READY) && currticks() < to);
+
+	head_list = priv->txList + priv->txHead;
+	while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) 
+			&& (ack < 255)) {
+		ack++;
+		if(tmpCStat & TLAN_CSTAT_EOC)
+			eoc =1;
+		head_list->cStat = TLAN_CSTAT_UNUSED;
+		CIRC_INC(priv->txHead, TLAN_NUM_TX_LISTS);
+		head_list = priv->txList + priv->txHead;
+		
+	}
+	if(!ack)
+		printf("Incomplete TX Frame\n");
+
+	if(eoc) {
+		head_list = priv->txList + priv->txHead;
+		if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
+			outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
+			ack |= TLAN_HC_GO;
+		} else {
+			priv->txInProgress = 0;
+		}
+	}
+	if(ack) {
+		host_cmd = TLAN_HC_ACK | ack;
+		outl(host_cmd, BASE + TLAN_HOST_CMD);
+	}
+	
+	if(priv->tlanRev < 0x30 ) {
+		ack = 1;
+		head_list = priv->txList + priv->txHead;
+		if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
+			outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
+			ack |= TLAN_HC_GO;
+		} else {
+			priv->txInProgress = 0;
+		}
+		host_cmd = TLAN_HC_ACK | ack | 0x00140000;
+		outl(host_cmd, BASE + TLAN_HOST_CMD);
+		
+	}
+			
+	if (currticks() >= to) {
+		printf("TX Time Out");
+	}
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void tlan_disable ( struct nic *nic __unused ) {
+	/* put the card in its initial state */
+	/* This function serves 3 purposes.
+	 * This disables DMA and interrupts so we don't receive
+	 *  unexpected packets or interrupts from the card after
+	 *  etherboot has finished.
+	 * This frees resources so etherboot may use
+	 *  this driver on another interface
+	 * This allows etherboot to reinitialize the interface
+	 *  if something is something goes wrong.
+	 *
+	 */
+	outl(TLAN_HC_AD_RST, BASE + TLAN_HOST_CMD);
+}
+
+/**************************************************************************
+IRQ - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void tlan_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations tlan_operations = {
+	.connect	= dummy_connect,
+	.poll		= tlan_poll,
+	.transmit	= tlan_transmit,
+	.irq		= tlan_irq,
+
+};
+
+static void TLan_SetMulticastList(struct nic *nic) {
+	int i;
+	u8 tmp;
+
+	/* !IFF_PROMISC */
+	tmp = TLan_DioRead8(BASE, TLAN_NET_CMD);
+	TLan_DioWrite8(BASE, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF);
+
+	/* IFF_ALLMULTI */
+	for(i = 0; i< 3; i++)
+		TLan_SetMac(nic, i + 1, NULL);
+	TLan_DioWrite32(BASE, TLAN_HASH_1, 0xFFFFFFFF);
+	TLan_DioWrite32(BASE, TLAN_HASH_2, 0xFFFFFFFF);
+
+	
+}
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+#define board_found 1
+#define valid_link 0
+static int tlan_probe ( struct nic *nic, struct pci_device *pci ) {
+
+	u16 data = 0;
+	int err;
+	int i;
+
+	if (pci->ioaddr == 0)
+		return 0;
+
+	nic->irqno  = 0;
+	nic->ioaddr = pci->ioaddr;
+
+	BASE = pci->ioaddr;
+
+	/* Set nic as PCI bus master */
+	adjust_pci_device(pci);
+	
+	/* Point to private storage */
+	priv = &TLanPrivateInfo;
+
+	/* Figure out which chip we're dealing with */
+	i = 0;
+	chip_idx = -1;
+	while (tlan_pci_tbl[i].name) {
+		if ((((u32) pci->device << 16) | pci->vendor) ==
+		    (tlan_pci_tbl[i].id.pci & 0xffffffff)) {
+			chip_idx = i;
+			break;
+		}
+		i++;
+	}
+
+	priv->vendor_id = pci->vendor;
+	priv->dev_id = pci->device;
+	priv->nic_name = pci->id->name;
+	priv->eoc = 0;
+
+	err = 0;
+	for (i = 0; i < 6; i++)
+		err |= TLan_EeReadByte(BASE,
+				       (u8) tlan_pci_tbl[chip_idx].
+				       addrOfs + i,
+				       (u8 *) & nic->node_addr[i]);
+	if (err) {
+  	    printf ( "TLAN: %s: Error reading MAC from eeprom: %d\n",
+		    pci->id->name, err);
+	} else {
+	    DBG ( "%s: %s at ioaddr %#lX, ", 
+		  pci->id->name, eth_ntoa ( nic->node_addr ), pci->ioaddr );
+	}
+
+	priv->tlanRev = TLan_DioRead8(BASE, TLAN_DEF_REVISION);
+	printf("revision: 0x%hX\n", priv->tlanRev);
+
+	TLan_ResetLists(nic);
+	TLan_ResetAdapter(nic);
+
+	data = inl(BASE + TLAN_HOST_CMD);
+	data |= TLAN_HC_INT_OFF;
+	outw(data, BASE + TLAN_HOST_CMD);
+
+	TLan_SetMulticastList(nic);
+	udelay(100); 
+	priv->txList = tx_ring;
+
+/*	if (board_found && valid_link)
+	{*/
+	/* point to NIC specific routines */
+	nic->nic_op	= &tlan_operations;
+	return 1;
+}
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Eeprom routines
+
+	The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A
+	EEPROM.  These functions are based on information in Microchip's
+	data sheet.  I don't know how well this functions will work with
+	other EEPROMs.
+
+******************************************************************************
+*****************************************************************************/
+
+
+/***************************************************************
+*	TLan_EeSendStart
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		io_base		The IO port base address for the
+*				TLAN device with the EEPROM to
+*				use.
+*
+*	This function sends a start cycle to an EEPROM attached
+*	to a TLAN chip.
+*
+**************************************************************/
+
+void TLan_EeSendStart(u16 io_base)
+{
+	u16 sio;
+
+	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+	TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
+	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
+	TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
+	TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+
+}	/* TLan_EeSendStart */
+
+/***************************************************************
+*	TLan_EeSendByte
+*
+*	Returns:
+*		If the correct ack was received, 0, otherwise 1
+*	Parms:	io_base		The IO port base address for the
+*				TLAN device with the EEPROM to
+*				use.
+*		data		The 8 bits of information to
+*				send to the EEPROM.
+*		stop		If TLAN_EEPROM_STOP is passed, a
+*				stop cycle is sent after the
+*				byte is sent after the ack is
+*				read.
+*
+*	This function sends a byte on the serial EEPROM line,
+*	driving the clock to send each bit. The function then
+*	reverses transmission direction and reads an acknowledge
+*	bit.
+*
+**************************************************************/
+
+int TLan_EeSendByte(u16 io_base, u8 data, int stop)
+{
+	int err;
+	u8 place;
+	u16 sio;
+
+	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	/* Assume clock is low, tx is enabled; */
+	for (place = 0x80; place != 0; place >>= 1) {
+		if (place & data)
+			TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
+		else
+			TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+	}
+	TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
+	TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+	err = TLan_GetBit(TLAN_NET_SIO_EDATA, sio);
+	TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
+
+	if ((!err) && stop) {
+		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* STOP, raise data while clock is high */
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
+	}
+
+	return (err);
+
+}	/* TLan_EeSendByte */
+
+/***************************************************************
+*	TLan_EeReceiveByte
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		io_base		The IO port base address for the
+*				TLAN device with the EEPROM to
+*				use.
+*		data		An address to a char to hold the
+*				data sent from the EEPROM.
+*		stop		If TLAN_EEPROM_STOP is passed, a
+*				stop cycle is sent after the
+*				byte is received, and no ack is
+*				sent.
+*
+*	This function receives 8 bits of data from the EEPROM
+*	over the serial link.  It then sends and ack bit, or no
+*	ack and a stop bit.  This function is used to retrieve
+*	data after the address of a byte in the EEPROM has been
+*	sent.
+*
+**************************************************************/
+
+void TLan_EeReceiveByte(u16 io_base, u8 * data, int stop)
+{
+	u8 place;
+	u16 sio;
+
+	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
+	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+	*data = 0;
+
+	/* Assume clock is low, tx is enabled; */
+	TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
+	for (place = 0x80; place; place >>= 1) {
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		if (TLan_GetBit(TLAN_NET_SIO_EDATA, sio))
+			*data |= place;
+		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+	}
+
+	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
+	if (!stop) {
+		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* Ack = 0 */
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+	} else {
+		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);	/* No ack = 1 (?) */
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* STOP, raise data while clock is high */
+		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
+		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
+	}
+
+}	/* TLan_EeReceiveByte */
+
+/***************************************************************
+*	TLan_EeReadByte
+*
+*	Returns:
+*		No error = 0, else, the stage at which the error
+*		occurred.
+*	Parms:
+*		io_base		The IO port base address for the
+*				TLAN device with the EEPROM to
+*				use.
+*		ee_addr		The address of the byte in the
+*				EEPROM whose contents are to be
+*				retrieved.
+*		data		An address to a char to hold the
+*				data obtained from the EEPROM.
+*
+*	This function reads a byte of information from an byte
+*	cell in the EEPROM.
+*
+**************************************************************/
+
+int TLan_EeReadByte(u16 io_base, u8 ee_addr, u8 * data)
+{
+	int err;
+	int ret = 0;
+
+
+	TLan_EeSendStart(io_base);
+	err = TLan_EeSendByte(io_base, 0xA0, TLAN_EEPROM_ACK);
+	if (err) {
+		ret = 1;
+		goto fail;
+	}
+	err = TLan_EeSendByte(io_base, ee_addr, TLAN_EEPROM_ACK);
+	if (err) {
+		ret = 2;
+		goto fail;
+	}
+	TLan_EeSendStart(io_base);
+	err = TLan_EeSendByte(io_base, 0xA1, TLAN_EEPROM_ACK);
+	if (err) {
+		ret = 3;
+		goto fail;
+	}
+	TLan_EeReceiveByte(io_base, data, TLAN_EEPROM_STOP);
+      fail:
+
+	return ret;
+
+}	/* TLan_EeReadByte */
+
+
+/*****************************************************************************
+******************************************************************************
+
+ThunderLAN Driver MII Routines
+
+These routines are based on the information in Chap. 2 of the
+"ThunderLAN Programmer's Guide", pp. 15-24.
+
+******************************************************************************
+*****************************************************************************/
+
+
+/***************************************************************
+*	TLan_MiiReadReg
+*
+*	Returns:
+*		0	if ack received ok
+*		1	otherwise.
+*
+*	Parms:
+*		dev		The device structure containing
+*				The io address and interrupt count
+*				for this device.
+*		phy		The address of the PHY to be queried.
+*		reg		The register whose contents are to be
+*				retreived.
+*		val		A pointer to a variable to store the
+*				retrieved value.
+*
+*	This function uses the TLAN's MII bus to retreive the contents
+*	of a given register on a PHY.  It sends the appropriate info
+*	and then reads the 16-bit register value from the MII bus via
+*	the TLAN SIO register.
+*
+**************************************************************/
+
+int TLan_MiiReadReg(struct nic *nic __unused, u16 phy, u16 reg, u16 * val)
+{
+	u8 nack;
+	u16 sio, tmp;
+	u32 i;
+	int err;
+	int minten;
+
+	err = FALSE;
+	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
+	sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_MiiSync(BASE);
+
+	minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
+	if (minten)
+		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
+
+	TLan_MiiSendData(BASE, 0x1, 2);	/* Start ( 01b ) */
+	TLan_MiiSendData(BASE, 0x2, 2);	/* Read  ( 10b ) */
+	TLan_MiiSendData(BASE, phy, 5);	/* Device #      */
+	TLan_MiiSendData(BASE, reg, 5);	/* Register #    */
+
+
+	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);	/* Change direction */
+
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Clock Idle bit */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Wait 300ns */
+
+	nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio);	/* Check for ACK */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);	/* Finish ACK */
+	if (nack) {		/* No ACK, so fake it */
+		for (i = 0; i < 16; i++) {
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+		}
+		tmp = 0xffff;
+		err = TRUE;
+	} else {		/* ACK, so read data */
+		for (tmp = 0, i = 0x8000; i; i >>= 1) {
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+			if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio))
+				tmp |= i;
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+		}
+	}
+
+
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Idle cycle */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+
+	if (minten)
+		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
+
+	*val = tmp;
+
+	return err;
+
+}				/* TLan_MiiReadReg */
+
+/***************************************************************
+*	TLan_MiiSendData
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		base_port	The base IO port of the adapter	in
+*				question.
+*		dev		The address of the PHY to be queried.
+*		data		The value to be placed on the MII bus.
+*		num_bits	The number of bits in data that are to
+*				be placed on the MII bus.
+*
+*	This function sends on sequence of bits on the MII
+*	configuration bus.
+*
+**************************************************************/
+
+void TLan_MiiSendData(u16 base_port, u32 data, unsigned num_bits)
+{
+	u16 sio;
+	u32 i;
+
+	if (num_bits == 0)
+		return;
+
+	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+	TLan_SetBit(TLAN_NET_SIO_MTXEN, sio);
+
+	for (i = (0x1 << (num_bits - 1)); i; i >>= 1) {
+		TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+		(void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
+		if (data & i)
+			TLan_SetBit(TLAN_NET_SIO_MDATA, sio);
+		else
+			TLan_ClearBit(TLAN_NET_SIO_MDATA, sio);
+		TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+		(void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
+	}
+
+}				/* TLan_MiiSendData */
+
+/***************************************************************
+*	TLan_MiiSync
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		base_port	The base IO port of the adapter in
+*				question.
+*
+*	This functions syncs all PHYs in terms of the MII configuration
+*	bus.
+*
+**************************************************************/
+
+void TLan_MiiSync(u16 base_port)
+{
+	int i;
+	u16 sio;
+
+	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);
+	for (i = 0; i < 32; i++) {
+		TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+		TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+	}
+
+}				/* TLan_MiiSync */
+
+/***************************************************************
+*	TLan_MiiWriteReg
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		dev		The device structure for the device
+*				to write to.
+*		phy		The address of the PHY to be written to.
+*		reg		The register whose contents are to be
+*				written.
+*		val		The value to be written to the register.
+*
+*	This function uses the TLAN's MII bus to write the contents of a
+*	given register on a PHY.  It sends the appropriate info and then
+*	writes the 16-bit register value from the MII configuration bus
+*	via the TLAN SIO register.
+*
+**************************************************************/
+
+void TLan_MiiWriteReg(struct nic *nic __unused, u16 phy, u16 reg, u16 val)
+{
+	u16 sio;
+	int minten;
+
+	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
+	sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+	TLan_MiiSync(BASE);
+
+	minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
+	if (minten)
+		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
+
+	TLan_MiiSendData(BASE, 0x1, 2);	/* Start ( 01b ) */
+	TLan_MiiSendData(BASE, 0x1, 2);	/* Write ( 01b ) */
+	TLan_MiiSendData(BASE, phy, 5);	/* Device #      */
+	TLan_MiiSendData(BASE, reg, 5);	/* Register #    */
+
+	TLan_MiiSendData(BASE, 0x2, 2);	/* Send ACK */
+	TLan_MiiSendData(BASE, val, 16);	/* Send Data */
+
+	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Idle cycle */
+	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+
+	if (minten)
+		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
+
+
+}				/* TLan_MiiWriteReg */
+
+/***************************************************************
+*	TLan_SetMac
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		dev	Pointer to device structure of adapter
+*			on which to change the AREG.
+*		areg	The AREG to set the address in (0 - 3).
+*		mac	A pointer to an array of chars.  Each
+*			element stores one byte of the address.
+*			IE, it isn't in ascii.
+*
+*	This function transfers a MAC address to one of the
+*	TLAN AREGs (address registers).  The TLAN chip locks
+*	the register on writing to offset 0 and unlocks the
+*	register after writing to offset 5.  If NULL is passed
+*	in mac, then the AREG is filled with 0's.
+*
+**************************************************************/
+
+void TLan_SetMac(struct nic *nic __unused, int areg, unsigned char *mac)
+{
+	int i;
+
+	areg *= 6;
+
+	if (mac != NULL) {
+		for (i = 0; i < 6; i++)
+			TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i,
+				       mac[i]);
+	} else {
+		for (i = 0; i < 6; i++)
+			TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i, 0);
+	}
+
+}				/* TLan_SetMac */
+
+/*********************************************************************
+*	TLan_PhyDetect
+*
+*	Returns:
+*		Nothing
+*	Parms:
+*		dev	A pointer to the device structure of the adapter
+*			for which the PHY needs determined.
+*
+*	So far I've found that adapters which have external PHYs
+*	may also use the internal PHY for part of the functionality.
+*	(eg, AUI/Thinnet).  This function finds out if this TLAN
+*	chip has an internal PHY, and then finds the first external
+*	PHY (starting from address 0) if it exists).
+*
+********************************************************************/
+
+void TLan_PhyDetect(struct nic *nic)
+{
+	u16 control;
+	u16 hi;
+	u16 lo;
+	u32 phy;
+
+	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
+		priv->phyNum = 0xFFFF;
+		return;
+	}
+
+	TLan_MiiReadReg(nic, TLAN_PHY_MAX_ADDR, MII_PHYSID1, &hi);
+
+	if (hi != 0xFFFF) {
+		priv->phy[0] = TLAN_PHY_MAX_ADDR;
+	} else {
+		priv->phy[0] = TLAN_PHY_NONE;
+	}
+
+	priv->phy[1] = TLAN_PHY_NONE;
+	for (phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++) {
+		TLan_MiiReadReg(nic, phy, MII_BMCR, &control);
+		TLan_MiiReadReg(nic, phy, MII_PHYSID1, &hi);
+		TLan_MiiReadReg(nic, phy, MII_PHYSID2, &lo);
+		if ((control != 0xFFFF) || (hi != 0xFFFF)
+		    || (lo != 0xFFFF)) {
+			printf("PHY found at %hX %hX %hX %hX\n", 
+			       (unsigned int) phy, control, hi, lo);
+			if ((priv->phy[1] == TLAN_PHY_NONE)
+			    && (phy != TLAN_PHY_MAX_ADDR)) {
+				priv->phy[1] = phy;
+			}
+		}
+	}
+
+	if (priv->phy[1] != TLAN_PHY_NONE) {
+		priv->phyNum = 1;
+	} else if (priv->phy[0] != TLAN_PHY_NONE) {
+		priv->phyNum = 0;
+	} else {
+		printf
+		    ("TLAN:  Cannot initialize device, no PHY was found!\n");
+	}
+
+}				/* TLan_PhyDetect */
+
+void TLan_PhyPowerDown(struct nic *nic)
+{
+
+	u16 value;
+	DBG ( "%s: Powering down PHY(s).\n", priv->nic_name );
+	value = BMCR_PDOWN | BMCR_LOOPBACK | BMCR_ISOLATE;
+	TLan_MiiSync(BASE);
+	TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_BMCR, value);
+	if ((priv->phyNum == 0) && (priv->phy[1] != TLAN_PHY_NONE)
+	    &&
+	    (!(tlan_pci_tbl[chip_idx].
+	       flags & TLAN_ADAPTER_USE_INTERN_10))) {
+		TLan_MiiSync(BASE);
+		TLan_MiiWriteReg(nic, priv->phy[1], MII_BMCR, value);
+	}
+
+	/* Wait for 50 ms and powerup
+	 * This is abitrary.  It is intended to make sure the
+	 * tranceiver settles.
+	 */
+	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); */
+	mdelay(50);
+	TLan_PhyPowerUp(nic);
+
+}				/* TLan_PhyPowerDown */
+
+
+void TLan_PhyPowerUp(struct nic *nic)
+{
+	u16 value;
+
+	DBG ( "%s: Powering up PHY.\n", priv->nic_name );
+	TLan_MiiSync(BASE);
+	value = BMCR_LOOPBACK;
+	TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_BMCR, value);
+	TLan_MiiSync(BASE);
+	/* Wait for 500 ms and reset the
+	 * tranceiver.  The TLAN docs say both 50 ms and
+	 * 500 ms, so do the longer, just in case.
+	 */
+	mdelay(500);
+	TLan_PhyReset(nic);
+	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); */
+
+}				/* TLan_PhyPowerUp */
+
+void TLan_PhyReset(struct nic *nic)
+{
+	u16 phy;
+	u16 value;
+
+	phy = priv->phy[priv->phyNum];
+
+	DBG ( "%s: Reseting PHY.\n", priv->nic_name );
+	TLan_MiiSync(BASE);
+	value = BMCR_LOOPBACK | BMCR_RESET;
+	TLan_MiiWriteReg(nic, phy, MII_BMCR, value);
+	TLan_MiiReadReg(nic, phy, MII_BMCR, &value);
+	while (value & BMCR_RESET) {
+		TLan_MiiReadReg(nic, phy, MII_BMCR, &value);
+	}
+
+	/* Wait for 500 ms and initialize.
+	 * I don't remember why I wait this long.
+	 * I've changed this to 50ms, as it seems long enough.
+	 */
+	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); */
+	mdelay(50);
+	TLan_PhyStartLink(nic);
+
+}				/* TLan_PhyReset */
+
+
+void TLan_PhyStartLink(struct nic *nic)
+{
+
+	u16 ability;
+	u16 control;
+	u16 data;
+	u16 phy;
+	u16 status;
+	u16 tctl;
+
+	phy = priv->phy[priv->phyNum];
+	DBG ( "%s: Trying to activate link.\n", priv->nic_name );
+	TLan_MiiReadReg(nic, phy, MII_BMSR, &status);
+	TLan_MiiReadReg(nic, phy, MII_BMSR, &ability);
+
+	if ((status & BMSR_ANEGCAPABLE) && (!priv->aui)) {
+		ability = status >> 11;
+		if (priv->speed == TLAN_SPEED_10 &&
+		    priv->duplex == TLAN_DUPLEX_HALF) {
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x0000);
+		} else if (priv->speed == TLAN_SPEED_10 &&
+			   priv->duplex == TLAN_DUPLEX_FULL) {
+			priv->tlanFullDuplex = TRUE;
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x0100);
+		} else if (priv->speed == TLAN_SPEED_100 &&
+			   priv->duplex == TLAN_DUPLEX_HALF) {
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x2000);
+		} else if (priv->speed == TLAN_SPEED_100 &&
+			   priv->duplex == TLAN_DUPLEX_FULL) {
+			priv->tlanFullDuplex = TRUE;
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x2100);
+		} else {
+
+			/* Set Auto-Neg advertisement */
+			TLan_MiiWriteReg(nic, phy, MII_ADVERTISE,
+					 (ability << 5) | 1);
+			/* Enablee Auto-Neg */
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x1000);
+			/* Restart Auto-Neg */
+			TLan_MiiWriteReg(nic, phy, MII_BMCR, 0x1200);
+			/* Wait for 4 sec for autonegotiation
+			 * to complete.  The max spec time is less than this
+			 * but the card need additional time to start AN.
+			 * .5 sec should be plenty extra.
+			 */
+			DBG ( "TLAN: %s: Starting autonegotiation.\n",
+			       priv->nic_name );
+			mdelay(4000);
+			TLan_PhyFinishAutoNeg(nic);
+			/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
+			return;
+		}
+
+	}
+
+	if ((priv->aui) && (priv->phyNum != 0)) {
+		priv->phyNum = 0;
+		data =
+		    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
+		    TLAN_NET_CFG_PHY_EN;
+		TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
+		mdelay(50);
+		/* TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
+		TLan_PhyPowerDown(nic);
+		return;
+	} else if (priv->phyNum == 0) {
+		control = 0;
+		TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tctl);
+		if (priv->aui) {
+			tctl |= TLAN_TC_AUISEL;
+		} else {
+			tctl &= ~TLAN_TC_AUISEL;
+			if (priv->duplex == TLAN_DUPLEX_FULL) {
+				control |= BMCR_FULLDPLX;
+				priv->tlanFullDuplex = TRUE;
+			}
+			if (priv->speed == TLAN_SPEED_100) {
+				control |= BMCR_SPEED100;
+			}
+		}
+		TLan_MiiWriteReg(nic, phy, MII_BMCR, control);
+		TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tctl);
+	}
+
+	/* Wait for 2 sec to give the tranceiver time
+	 * to establish link.
+	 */
+	/* TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); */
+	mdelay(2000);
+	TLan_FinishReset(nic);
+
+}				/* TLan_PhyStartLink */
+
+void TLan_PhyFinishAutoNeg(struct nic *nic)
+{
+
+	u16 an_adv;
+	u16 an_lpa;
+	u16 data;
+	u16 mode;
+	u16 phy;
+	u16 status;
+
+	phy = priv->phy[priv->phyNum];
+
+	TLan_MiiReadReg(nic, phy, MII_BMSR, &status);
+	udelay(1000);
+	TLan_MiiReadReg(nic, phy, MII_BMSR, &status);
+
+	if (!(status & BMSR_ANEGCOMPLETE)) {
+		/* Wait for 8 sec to give the process
+		 * more time.  Perhaps we should fail after a while.
+		 */
+		if (!priv->neg_be_verbose++) {
+			printf
+			    ("TLAN:  Giving autonegotiation more time.\n");
+			printf
+			    ("TLAN:  Please check that your adapter has\n");
+			printf
+			    ("TLAN:  been properly connected to a HUB or Switch.\n");
+			printf
+			    ("TLAN:  Trying to establish link in the background...\n");
+		}
+		mdelay(8000);
+		TLan_PhyFinishAutoNeg(nic);
+		/* TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
+		return;
+	}
+
+	DBG ( "TLAN: %s: Autonegotiation complete.\n", priv->nic_name );
+	TLan_MiiReadReg(nic, phy, MII_ADVERTISE, &an_adv);
+	TLan_MiiReadReg(nic, phy, MII_LPA, &an_lpa);
+	mode = an_adv & an_lpa & 0x03E0;
+	if (mode & 0x0100) {
+		printf("Full Duplex\n");
+		priv->tlanFullDuplex = TRUE;
+	} else if (!(mode & 0x0080) && (mode & 0x0040)) {
+		priv->tlanFullDuplex = TRUE;
+		printf("Full Duplex\n");
+	}
+
+	if ((!(mode & 0x0180))
+	    && (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_USE_INTERN_10)
+	    && (priv->phyNum != 0)) {
+		priv->phyNum = 0;
+		data =
+		    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
+		    TLAN_NET_CFG_PHY_EN;
+		TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
+		/* TLan_SetTimer( nic, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
+		mdelay(400);
+		TLan_PhyPowerDown(nic);
+		return;
+	}
+
+	if (priv->phyNum == 0) {
+		if ((priv->duplex == TLAN_DUPLEX_FULL)
+		    || (an_adv & an_lpa & 0x0040)) {
+			TLan_MiiWriteReg(nic, phy, MII_BMCR,
+					 BMCR_ANENABLE | BMCR_FULLDPLX);
+			DBG 
+			    ( "TLAN:  Starting internal PHY with FULL-DUPLEX\n" );
+		} else {
+			TLan_MiiWriteReg(nic, phy, MII_BMCR,
+					 BMCR_ANENABLE);
+			DBG 
+			    ( "TLAN:  Starting internal PHY with HALF-DUPLEX\n" );
+		}
+	}
+
+	/* Wait for 100 ms.  No reason in partiticular.
+	 */
+	/* TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); */
+	mdelay(100);
+	TLan_FinishReset(nic);
+
+}				/* TLan_PhyFinishAutoNeg */
+
+#ifdef MONITOR
+
+/*********************************************************************
+*
+*      TLan_phyMonitor
+*
+*      Returns:
+*              None
+*
+*      Params:
+*              dev             The device structure of this device.
+*
+*
+*      This function monitors PHY condition by reading the status
+*      register via the MII bus. This can be used to give info
+*      about link changes (up/down), and possible switch to alternate
+*      media.
+*
+********************************************************************/
+
+void TLan_PhyMonitor(struct net_device *dev)
+{
+	TLanPrivateInfo *priv = dev->priv;
+	u16 phy;
+	u16 phy_status;
+
+	phy = priv->phy[priv->phyNum];
+
+	/* Get PHY status register */
+	TLan_MiiReadReg(nic, phy, MII_BMSR, &phy_status);
+
+	/* Check if link has been lost */
+	if (!(phy_status & BMSR_LSTATUS)) {
+		if (priv->link) {
+			priv->link = 0;
+			printf("TLAN: %s has lost link\n", priv->nic_name);
+			priv->flags &= ~IFF_RUNNING;
+			mdelay(2000);
+			TLan_PhyMonitor(nic);
+			/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
+			return;
+		}
+	}
+
+	/* Link restablished? */
+	if ((phy_status & BMSR_LSTATUS) && !priv->link) {
+		priv->link = 1;
+		printf("TLAN: %s has reestablished link\n",
+		       priv->nic_name);
+		priv->flags |= IFF_RUNNING;
+	}
+
+	/* Setup a new monitor */
+	/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
+	mdelay(2000);
+	TLan_PhyMonitor(nic);
+}
+
+#endif				/* MONITOR */
+
+static struct pci_device_id tlan_nics[] = {
+	PCI_ROM(0x0e11, 0xae34, "netel10", "Compaq Netelligent 10 T PCI UTP", 0),
+	PCI_ROM(0x0e11, 0xae32, "netel100","Compaq Netelligent 10/100 TX PCI UTP", 0),
+	PCI_ROM(0x0e11, 0xae35, "netflex3i", "Compaq Integrated NetFlex-3/P", 0),
+	PCI_ROM(0x0e11, 0xf130, "thunder", "Compaq NetFlex-3/P", 0),
+	PCI_ROM(0x0e11, 0xf150, "netflex3b", "Compaq NetFlex-3/P", 0),
+	PCI_ROM(0x0e11, 0xae43, "netel100pi", "Compaq Netelligent Integrated 10/100 TX UTP", 0),
+	PCI_ROM(0x0e11, 0xae40, "netel100d", "Compaq Netelligent Dual 10/100 TX PCI UTP", 0),
+	PCI_ROM(0x0e11, 0xb011, "netel100i", "Compaq Netelligent 10/100 TX Embedded UTP", 0),
+	PCI_ROM(0x108d, 0x0013, "oc2183", "Olicom OC-2183/2185", 0),
+	PCI_ROM(0x108d, 0x0012, "oc2325", "Olicom OC-2325", 0),
+	PCI_ROM(0x108d, 0x0014, "oc2326", "Olicom OC-2326", 0),
+	PCI_ROM(0x0e11, 0xb030, "netelligent_10_100_ws_5100", "Compaq Netelligent 10/100 TX UTP", 0),
+	PCI_ROM(0x0e11, 0xb012, "netelligent_10_t2", "Compaq Netelligent 10 T/2 PCI UTP/Coax", 0),
+};
+
+PCI_DRIVER ( tlan_driver, tlan_nics, PCI_NO_CLASS );
+
+DRIVER ( "TLAN/PCI", nic_driver, pci_driver, tlan_driver,
+	 tlan_probe, tlan_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.h
new file mode 100644
index 0000000..31b3c8f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tlan.h
@@ -0,0 +1,491 @@
+/**************************************************************************
+*
+*    tlan.c -- Etherboot device driver for the Texas Instruments ThunderLAN
+*    Written 2003-2003 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code (almost all) based on:
+*               tlan.c: Linux ThunderLan Driver:
+*
+*				by James Banks
+*
+*  				(C) 1997-1998 Caldera, Inc.
+*			  	(C) 1998 James Banks
+*				(C) 1999-2001 Torben Mathiasen
+*				(C) 2002 Samuel Chessman
+*
+*    REVISION HISTORY:
+*    ================
+*    v1.0	07-08-2003	timlegge	Initial not quite working version
+*
+* Indent Style: indent -kr -i8
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*****************************************************************
+* TLan Definitions
+*
+****************************************************************/
+
+#define FALSE			0
+#define TRUE			1
+
+#define TLAN_MIN_FRAME_SIZE	64
+#define TLAN_MAX_FRAME_SIZE	1600
+
+#define TLAN_NUM_RX_LISTS	4
+#define TLAN_NUM_TX_LISTS	2
+
+#define TLAN_IGNORE		0
+#define TLAN_RECORD		1
+/*
+#define TLAN_DBG(lvl, format, args...)	if (debug&lvl) printf("TLAN: " format, ##args );
+*/
+#define TLAN_DEBUG_GNRL		0x0001
+#define TLAN_DEBUG_TX		0x0002
+#define TLAN_DEBUG_RX		0x0004
+#define TLAN_DEBUG_LIST		0x0008
+#define TLAN_DEBUG_PROBE	0x0010
+
+#define TX_TIMEOUT		(10*HZ)	/* We need time for auto-neg */
+#define MAX_TLAN_BOARDS		8	/* Max number of boards installed at a time */
+
+
+	/*****************************************************************
+	 * Device Identification Definitions
+	 *
+	 ****************************************************************/
+
+#define PCI_DEVICE_ID_NETELLIGENT_10_T2			0xB012
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100	0xB030
+#ifndef PCI_DEVICE_ID_OLICOM_OC2183
+#define PCI_DEVICE_ID_OLICOM_OC2183			0x0013
+#endif
+#ifndef PCI_DEVICE_ID_OLICOM_OC2325
+#define PCI_DEVICE_ID_OLICOM_OC2325			0x0012
+#endif
+#ifndef PCI_DEVICE_ID_OLICOM_OC2326
+#define PCI_DEVICE_ID_OLICOM_OC2326			0x0014
+#endif
+
+typedef struct tlan_adapter_entry {
+	u16 vendorId;
+	u16 deviceId;
+	char *deviceLabel;
+	u32 flags;
+	u16 addrOfs;
+} TLanAdapterEntry;
+
+#define TLAN_ADAPTER_NONE		0x00000000
+#define TLAN_ADAPTER_UNMANAGED_PHY	0x00000001
+#define TLAN_ADAPTER_BIT_RATE_PHY	0x00000002
+#define TLAN_ADAPTER_USE_INTERN_10	0x00000004
+#define TLAN_ADAPTER_ACTIVITY_LED	0x00000008
+
+#define TLAN_SPEED_DEFAULT	0
+#define TLAN_SPEED_10		10
+#define TLAN_SPEED_100		100
+
+#define TLAN_DUPLEX_DEFAULT	0
+#define TLAN_DUPLEX_HALF	1
+#define TLAN_DUPLEX_FULL	2
+
+
+
+	/*****************************************************************
+	 * EISA Definitions
+	 *
+	 ****************************************************************/
+
+#define EISA_ID      0xc80	/* EISA ID Registers */
+#define EISA_ID0     0xc80	/* EISA ID Register 0 */
+#define EISA_ID1     0xc81	/* EISA ID Register 1 */
+#define EISA_ID2     0xc82	/* EISA ID Register 2 */
+#define EISA_ID3     0xc83	/* EISA ID Register 3 */
+#define EISA_CR      0xc84	/* EISA Control Register */
+#define EISA_REG0    0xc88	/* EISA Configuration Register 0 */
+#define EISA_REG1    0xc89	/* EISA Configuration Register 1 */
+#define EISA_REG2    0xc8a	/* EISA Configuration Register 2 */
+#define EISA_REG3    0xc8f	/* EISA Configuration Register 3 */
+#define EISA_APROM   0xc90	/* Ethernet Address PROM */
+
+
+
+	/*****************************************************************
+	 * Rx/Tx List Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_BUFFERS_PER_LIST	10
+#define TLAN_LAST_BUFFER	0x80000000
+#define TLAN_CSTAT_UNUSED	0x8000
+#define TLAN_CSTAT_FRM_CMP	0x4000
+#define TLAN_CSTAT_READY	0x3000
+#define TLAN_CSTAT_EOC		0x0800
+#define TLAN_CSTAT_RX_ERROR	0x0400
+#define TLAN_CSTAT_PASS_CRC	0x0200
+#define TLAN_CSTAT_DP_PR	0x0100
+
+
+
+
+
+
+	/*****************************************************************
+	 * PHY definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_PHY_MAX_ADDR	0x1F
+#define TLAN_PHY_NONE		0x20
+
+
+
+	/*****************************************************************
+	 * TLan Driver Timer Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_TIMER_LINK_BEAT		1
+#define TLAN_TIMER_ACTIVITY		2
+#define TLAN_TIMER_PHY_PDOWN		3
+#define TLAN_TIMER_PHY_PUP		4
+#define TLAN_TIMER_PHY_RESET		5
+#define TLAN_TIMER_PHY_START_LINK	6
+#define TLAN_TIMER_PHY_FINISH_AN	7
+#define TLAN_TIMER_FINISH_RESET		8
+
+#define TLAN_TIMER_ACT_DELAY		(HZ/10)
+
+
+
+
+	/*****************************************************************
+	 * TLan Driver Eeprom Definitions
+	 *
+	 ****************************************************************/
+
+#define TLAN_EEPROM_ACK		0
+#define TLAN_EEPROM_STOP	1
+
+
+
+
+	/*****************************************************************
+	 * Host Register Offsets and Contents
+	 *
+	 ****************************************************************/
+
+#define TLAN_HOST_CMD			0x00
+#define 	TLAN_HC_GO		0x80000000
+#define		TLAN_HC_STOP		0x40000000
+#define		TLAN_HC_ACK		0x20000000
+#define		TLAN_HC_CS_MASK		0x1FE00000
+#define		TLAN_HC_EOC		0x00100000
+#define		TLAN_HC_RT		0x00080000
+#define		TLAN_HC_NES		0x00040000
+#define		TLAN_HC_AD_RST		0x00008000
+#define		TLAN_HC_LD_TMR		0x00004000
+#define		TLAN_HC_LD_THR		0x00002000
+#define		TLAN_HC_REQ_INT		0x00001000
+#define		TLAN_HC_INT_OFF		0x00000800
+#define		TLAN_HC_INT_ON		0x00000400
+#define		TLAN_HC_AC_MASK		0x000000FF
+#define TLAN_CH_PARM			0x04
+#define TLAN_DIO_ADR			0x08
+#define		TLAN_DA_ADR_INC		0x8000
+#define		TLAN_DA_RAM_ADR		0x4000
+#define TLAN_HOST_INT			0x0A
+#define		TLAN_HI_IV_MASK		0x1FE0
+#define		TLAN_HI_IT_MASK		0x001C
+#define TLAN_DIO_DATA			0x0C
+
+
+/* ThunderLAN Internal Register DIO Offsets */
+
+#define TLAN_NET_CMD			0x00
+#define		TLAN_NET_CMD_NRESET	0x80
+#define		TLAN_NET_CMD_NWRAP	0x40
+#define		TLAN_NET_CMD_CSF	0x20
+#define		TLAN_NET_CMD_CAF	0x10
+#define		TLAN_NET_CMD_NOBRX	0x08
+#define		TLAN_NET_CMD_DUPLEX	0x04
+#define		TLAN_NET_CMD_TRFRAM	0x02
+#define		TLAN_NET_CMD_TXPACE	0x01
+#define TLAN_NET_SIO			0x01
+#define 	TLAN_NET_SIO_MINTEN	0x80
+#define		TLAN_NET_SIO_ECLOK	0x40
+#define		TLAN_NET_SIO_ETXEN	0x20
+#define		TLAN_NET_SIO_EDATA	0x10
+#define		TLAN_NET_SIO_NMRST	0x08
+#define		TLAN_NET_SIO_MCLK	0x04
+#define		TLAN_NET_SIO_MTXEN	0x02
+#define		TLAN_NET_SIO_MDATA	0x01
+#define TLAN_NET_STS			0x02
+#define		TLAN_NET_STS_MIRQ	0x80
+#define		TLAN_NET_STS_HBEAT	0x40
+#define		TLAN_NET_STS_TXSTOP	0x20
+#define		TLAN_NET_STS_RXSTOP	0x10
+#define		TLAN_NET_STS_RSRVD	0x0F
+#define TLAN_NET_MASK			0x03
+#define		TLAN_NET_MASK_MASK7	0x80
+#define		TLAN_NET_MASK_MASK6	0x40
+#define		TLAN_NET_MASK_MASK5	0x20
+#define		TLAN_NET_MASK_MASK4	0x10
+#define		TLAN_NET_MASK_RSRVD	0x0F
+#define TLAN_NET_CONFIG			0x04
+#define 	TLAN_NET_CFG_RCLK	0x8000
+#define		TLAN_NET_CFG_TCLK	0x4000
+#define		TLAN_NET_CFG_BIT	0x2000
+#define		TLAN_NET_CFG_RXCRC	0x1000
+#define		TLAN_NET_CFG_PEF	0x0800
+#define		TLAN_NET_CFG_1FRAG	0x0400
+#define		TLAN_NET_CFG_1CHAN	0x0200
+#define		TLAN_NET_CFG_MTEST	0x0100
+#define		TLAN_NET_CFG_PHY_EN	0x0080
+#define		TLAN_NET_CFG_MSMASK	0x007F
+#define TLAN_MAN_TEST			0x06
+#define TLAN_DEF_VENDOR_ID		0x08
+#define TLAN_DEF_DEVICE_ID		0x0A
+#define TLAN_DEF_REVISION		0x0C
+#define TLAN_DEF_SUBCLASS		0x0D
+#define TLAN_DEF_MIN_LAT		0x0E
+#define TLAN_DEF_MAX_LAT		0x0F
+#define TLAN_AREG_0			0x10
+#define TLAN_AREG_1			0x16
+#define TLAN_AREG_2			0x1C
+#define TLAN_AREG_3			0x22
+#define TLAN_HASH_1			0x28
+#define TLAN_HASH_2			0x2C
+#define TLAN_GOOD_TX_FRMS		0x30
+#define TLAN_TX_UNDERUNS		0x33
+#define TLAN_GOOD_RX_FRMS		0x34
+#define TLAN_RX_OVERRUNS		0x37
+#define TLAN_DEFERRED_TX		0x38
+#define TLAN_CRC_ERRORS			0x3A
+#define TLAN_CODE_ERRORS		0x3B
+#define TLAN_MULTICOL_FRMS		0x3C
+#define TLAN_SINGLECOL_FRMS		0x3E
+#define TLAN_EXCESSCOL_FRMS		0x40
+#define TLAN_LATE_COLS			0x41
+#define TLAN_CARRIER_LOSS		0x42
+#define TLAN_ACOMMIT			0x43
+#define TLAN_LED_REG			0x44
+#define		TLAN_LED_ACT		0x10
+#define		TLAN_LED_LINK		0x01
+#define TLAN_BSIZE_REG			0x45
+#define TLAN_MAX_RX			0x46
+#define TLAN_INT_DIS			0x48
+#define		TLAN_ID_TX_EOC		0x04
+#define		TLAN_ID_RX_EOF		0x02
+#define		TLAN_ID_RX_EOC		0x01
+
+
+
+/* ThunderLAN Interrupt Codes */
+
+#define TLAN_INT_NUMBER_OF_INTS	8
+
+#define TLAN_INT_NONE			0x0000
+#define TLAN_INT_TX_EOF			0x0001
+#define TLAN_INT_STAT_OVERFLOW		0x0002
+#define TLAN_INT_RX_EOF			0x0003
+#define TLAN_INT_DUMMY			0x0004
+#define TLAN_INT_TX_EOC			0x0005
+#define TLAN_INT_STATUS_CHECK		0x0006
+#define TLAN_INT_RX_EOC			0x0007
+
+
+
+/* ThunderLAN MII Registers */
+
+/* ThunderLAN Specific MII/PHY Registers */
+
+#define TLAN_TLPHY_ID			0x10
+#define TLAN_TLPHY_CTL			0x11
+#define 	TLAN_TC_IGLINK		0x8000
+#define		TLAN_TC_SWAPOL		0x4000
+#define		TLAN_TC_AUISEL		0x2000
+#define		TLAN_TC_SQEEN		0x1000
+#define		TLAN_TC_MTEST		0x0800
+#define		TLAN_TC_RESERVED	0x07F8
+#define		TLAN_TC_NFEW		0x0004
+#define		TLAN_TC_INTEN		0x0002
+#define		TLAN_TC_TINT		0x0001
+#define TLAN_TLPHY_STS			0x12
+#define		TLAN_TS_MINT		0x8000
+#define		TLAN_TS_PHOK		0x4000
+#define		TLAN_TS_POLOK		0x2000
+#define		TLAN_TS_TPENERGY	0x1000
+#define		TLAN_TS_RESERVED	0x0FFF
+#define TLAN_TLPHY_PAR			0x19
+#define		TLAN_PHY_CIM_STAT	0x0020
+#define		TLAN_PHY_SPEED_100	0x0040
+#define		TLAN_PHY_DUPLEX_FULL	0x0080
+#define		TLAN_PHY_AN_EN_STAT     0x0400
+
+/* National Sem. & Level1 PHY id's */
+#define NAT_SEM_ID1			0x2000
+#define NAT_SEM_ID2			0x5C01
+#define LEVEL1_ID1			0x7810
+#define LEVEL1_ID2			0x0000
+
+#define CIRC_INC( a, b ) if ( ++a >= b ) a = 0
+
+/* Routines to access internal registers. */
+
+static inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
+
+}				/* TLan_DioRead8 */
+
+
+
+
+static inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2)));
+
+}				/* TLan_DioRead16 */
+
+
+
+
+static inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inl(base_addr + TLAN_DIO_DATA));
+
+}				/* TLan_DioRead32 */
+
+
+
+
+static inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3));
+
+}
+
+
+
+
+static inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+
+static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+#if 0
+static inline void TLan_ClearBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) & ~bit, port);
+}
+
+
+
+
+static inline int TLan_GetBit(u8 bit, u16 port)
+{
+	return ((int) (inb_p(port) & bit));
+}
+
+
+
+
+static inline void TLan_SetBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) | bit, port);
+}
+#endif
+
+#define TLan_ClearBit( bit, port )	outb_p(inb_p(port) & ~bit, port)
+#define TLan_GetBit( bit, port )	((int) (inb_p(port) & bit))
+#define TLan_SetBit( bit, port )	outb_p(inb_p(port) | bit, port)
+
+#ifdef I_LIKE_A_FAST_HASH_FUNCTION
+/* given 6 bytes, view them as 8 6-bit numbers and return the XOR of those */
+/* the code below is about seven times as fast as the original code */
+static inline u32 TLan_HashFunc(u8 * a)
+{
+	u8 hash;
+
+	hash = (a[0] ^ a[3]);	/* & 077 */
+	hash ^= ((a[0] ^ a[3]) >> 6);	/* & 003 */
+	hash ^= ((a[1] ^ a[4]) << 2);	/* & 074 */
+	hash ^= ((a[1] ^ a[4]) >> 4);	/* & 017 */
+	hash ^= ((a[2] ^ a[5]) << 4);	/* & 060 */
+	hash ^= ((a[2] ^ a[5]) >> 2);	/* & 077 */
+
+	return (hash & 077);
+}
+
+#else				/* original code */
+
+static inline u32 xor(u32 a, u32 b)
+{
+	return ((a && !b) || (!a && b));
+}
+
+#define XOR8( a, b, c, d, e, f, g, h )	xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) )
+#define DA( a, bit )					( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) )
+
+static inline u32 TLan_HashFunc(u8 * a)
+{
+	u32 hash;
+
+	hash =
+	    XOR8(DA(a, 0), DA(a, 6), DA(a, 12), DA(a, 18), DA(a, 24),
+		 DA(a, 30), DA(a, 36), DA(a, 42));
+	hash |=
+	    XOR8(DA(a, 1), DA(a, 7), DA(a, 13), DA(a, 19), DA(a, 25),
+		 DA(a, 31), DA(a, 37), DA(a, 43)) << 1;
+	hash |=
+	    XOR8(DA(a, 2), DA(a, 8), DA(a, 14), DA(a, 20), DA(a, 26),
+		 DA(a, 32), DA(a, 38), DA(a, 44)) << 2;
+	hash |=
+	    XOR8(DA(a, 3), DA(a, 9), DA(a, 15), DA(a, 21), DA(a, 27),
+		 DA(a, 33), DA(a, 39), DA(a, 45)) << 3;
+	hash |=
+	    XOR8(DA(a, 4), DA(a, 10), DA(a, 16), DA(a, 22), DA(a, 28),
+		 DA(a, 34), DA(a, 40), DA(a, 46)) << 4;
+	hash |=
+	    XOR8(DA(a, 5), DA(a, 11), DA(a, 17), DA(a, 23), DA(a, 29),
+		 DA(a, 35), DA(a, 41), DA(a, 47)) << 5;
+
+	return hash;
+
+}
+
+#endif				/* I_LIKE_A_FAST_HASH_FUNCTION */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.c
new file mode 100644
index 0000000..7a23b7e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.c
@@ -0,0 +1,1969 @@
+/* -*- Mode:C; c-basic-offset:4; -*- */
+
+/*
+  Tulip and clone Etherboot Driver
+
+  By Marty Connor (mdc at etherboot.org)
+  Copyright (C) 2001 Entity Cyber, Inc.
+
+  This software may be used and distributed according to the terms
+  of the GNU Public License, incorporated herein by reference.
+
+  As of April 2001 this driver should support most tulip cards that 
+  the Linux tulip driver supports because Donald Becker's Linux media 
+  detection code is now included.
+
+  Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's
+  Linux Tulip Driver. Supports N-Way speed auto-configuration on
+  MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards
+  based on the Macronix MX987x5 chip, such as the SOHOware Fast
+  model SFA110A, and the LinkSYS model LNE100TX. The NetGear
+  model FA310X, based on the LC82C168 chip is supported.
+  The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD
+  chipset is supported. Also, Davicom DM9102's.
+
+  Documentation and source code used:
+  Source for Etherboot driver at
+  http://etherboot.sourceforge.net/
+  MX98715A Data Sheet and MX98715A Application Note
+  on http://www.macronix.com/  (PDF format files)
+  Source for Linux tulip driver at
+  http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+
+  Adapted by Ken Yap from
+  FreeBSD netboot DEC 21143 driver
+  Author: David Sharp
+  date: Nov/98
+
+  Some code fragments were taken from verious places, Ken Yap's
+  etherboot, FreeBSD's if_de.c, and various Linux related files.
+  DEC's manuals for the 21143 and SROM format were very helpful.
+  The Linux de driver development page has a number of links to
+  useful related information.  Have a look at:
+  ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html
+*/
+
+FILE_LICENCE ( GPL_ANY );
+
+/*********************************************************************/
+/* Revision History                                                  */
+/*********************************************************************/
+
+/*
+  08 Feb 2005  Ramesh Chander chhabaramesh at yahoo.co.in added table entries
+               for SGThomson STE10/100A
+  07 Sep 2003  timlegge	Multicast Support Added
+  11 Apr 2001  mdc     [patch to etherboot 4.7.24]
+     Major rewrite to include Linux tulip driver media detection
+     code.  This driver should support a lot more cards now.
+  16 Jul 2000  mdc     0.75b11
+     Added support for ADMtek 0985 Centaur-P, a "Comet" tulip clone
+     which is used on the LinkSYS LNE100TX v4.x cards.  We already
+     support LNE100TX v2.0 cards, which use a different controller.
+  04 Jul 2000   jam     ?
+     Added test of status after receiving a packet from the card.
+     Also uncommented the tulip_disable routine.  Stray packets
+     seemed to be causing problems.
+  27 Apr 2000   njl     ?
+  29 Feb 2000   mdc     0.75b7
+     Increased reset delay to 3 seconds because Macronix cards seem to
+     need more reset time before card comes back to a usable state.
+  26 Feb 2000   mdc     0.75b6
+     Added a 1 second delay after initializing the transmitter because
+     some cards seem to need the time or they drop the first packet 
+     transmitted.
+  23 Feb 2000   mdc     0.75b5
+     removed udelay code and used currticks() for more reliable delay
+     code in reset pause and sanity timeouts.  Added function prototypes
+     and TX debugging code.
+  21 Feb 2000   mdc     patch to Etherboot 4.4.3
+     Incorporated patches from Bob Edwards and Paul Mackerras of 
+     Linuxcare's OZLabs to deal with inefficiencies in tulip_transmit
+     and udelay.  We now wait for packet transmission to complete
+     (or sanity timeout).
+  04 Feb 2000   Robert.Edwards at anu.edu.au patch to Etherboot 4.4.2
+     patch to tulip.c that implements the automatic selection of the MII
+     interface on cards using the Intel/DEC 21143 reference design, in
+     particular, the TRENDnet TE100-PCIA NIC which uses a genuine Intel
+     21143-PD chipset.
+  11 Jan 2000   mdc     0.75b4
+     Added support for NetGear FA310TX card based on the LC82C168
+     chip.  This should also support Lite-On LC82C168 boards.
+     Added simple MII support. Re-arranged code to better modularize
+     initializations.
+  04 Dec 1999   mdc     0.75b3
+     Added preliminary support for LNE100TX PCI cards.  Should work for
+     PNIC2 cards. No MII support, but single interface (RJ45) tulip
+     cards seem to not care.
+  03 Dec 1999   mdc     0.75b2
+     Renamed from mx987x5 to tulip, merged in original tulip init code
+     from tulip.c to support other tulip compatible cards.
+  02 Dec 1999   mdc     0.75b1
+     Released Beta MX987x5 Driver for code review and testing to netboot
+     and thinguin mailing lists.
+*/
+
+
+/*********************************************************************/
+/* Declarations                                                      */
+/*********************************************************************/
+
+#include "etherboot.h"
+#include "nic.h"
+
+#include <ipxe/ethernet.h>
+#include <ipxe/pci.h>
+
+/* User settable parameters */
+
+#define TX_TIME_OUT       2*TICKS_PER_SEC
+
+/* helpful macros if on a big_endian machine for changing byte order.
+   not strictly needed on Intel */
+#define get_unaligned(ptr) (*(ptr))
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+#define get_u16(ptr) (*(u16 *)(ptr))
+#define virt_to_le32desc(addr)  virt_to_bus(addr)
+
+#define TULIP_IOTYPE  PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0
+#define TULIP_SIZE 0x80
+
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+   to support a pre-NWay full-duplex signaling mechanism using short frames.
+   No one knows what it should be, but if left at its default value some
+   10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC       0x6969
+
+static const int csr0 = 0x01A00000 | 0x8000;
+
+/*  The possible media types that can be set in options[] are: */
+#define MEDIA_MASK 31
+static const char * const medianame[32] = {
+    "10baseT", "10base2", "AUI", "100baseTx",
+    "10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx",
+    "100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII",
+    "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4",
+    "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19",
+};
+
+/* This much match tulip_tbl[]!  Note 21142 == 21143. */
+enum tulip_chips {
+    DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+    LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET,
+    COMPEX9881, I21145, XIRCOM, SGThomson,	/*Ramesh Chander*/
+};
+
+enum pci_id_flags_bits {
+    /* Set PCI command register bits before calling probe1(). */
+    PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+    /* Read and map the single following PCI BAR. */
+    PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
+    PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
+    PCI_UNUSED_IRQ=0x800,
+};
+
+struct pci_id_info {
+    char *name;
+    struct match_info {
+        u32 pci, pci_mask, subsystem, subsystem_mask;
+        u32 revision, revision_mask;                            /* Only 8 bits. */
+    } id;
+    enum pci_id_flags_bits pci_flags;
+    int io_size;                                /* Needed for I/O region check or ioremap(). */
+    int drv_flags;                              /* Driver use, intended as capability flags. */
+};
+
+static const struct pci_id_info pci_id_tbl[] = {
+    { "Digital DC21040 Tulip", { 0x00021011, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 0x80, DC21040 },
+    { "Digital DC21041 Tulip", { 0x00141011, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 0x80, DC21041 },
+    { "Digital DS21140A Tulip", { 0x00091011, 0xffffffff, 0,0, 0x20,0xf0 },
+      TULIP_IOTYPE, 0x80, DC21140 },
+    { "Digital DS21140 Tulip", { 0x00091011, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 0x80, DC21140 },
+    { "Digital DS21143 Tulip", { 0x00191011, 0xffffffff, 0,0, 65,0xff },
+      TULIP_IOTYPE, TULIP_SIZE, DC21142 },
+    { "Digital DS21142 Tulip", { 0x00191011, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, TULIP_SIZE, DC21142 },
+    { "Kingston KNE110tx (PNIC)", { 0x000211AD, 0xffffffff, 0xf0022646, 0xffffffff, 0, 0 },
+      TULIP_IOTYPE, 256, LC82C168 },
+    { "Lite-On 82c168 PNIC", { 0x000211AD, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, LC82C168 },
+    { "Macronix 98713 PMAC", { 0x051210d9, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, MX98713 },
+    { "Macronix 98715 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, MX98715 },
+    { "Macronix 98725 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, MX98725 },
+    { "ASIX AX88141", { 0x1400125B, 0xffffffff, 0,0, 0x10, 0xf0 },
+      TULIP_IOTYPE, 128, AX88141 },
+    { "ASIX AX88140", { 0x1400125B, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 128, AX88140 },
+    { "Lite-On LC82C115 PNIC-II", { 0xc11511AD, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, PNIC2 },
+    { "ADMtek AN981 Comet", { 0x09811317, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },
+    { "ADMTek AN983 Comet", { 0x12161113, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },
+    { "ADMTek Comet AN983b", { 0x95111317, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },
+    { "ADMtek Centaur-P", { 0x09851317, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },
+    { "ADMtek Centaur-C", { 0x19851317, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },
+    { "Compex RL100-TX", { 0x988111F6, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 128, COMPEX9881 },
+    { "Intel 21145 Tulip", { 0x00398086, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 128, I21145 },
+    { "Xircom Tulip clone", { 0x0003115d, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 128, XIRCOM },
+    { "Davicom DM9102", { 0x91021282, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 0x80, DC21140 },
+    { "Davicom DM9100", { 0x91001282, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 0x80, DC21140 },
+    { "Macronix mxic-98715 (EN1217)", { 0x12171113, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, MX98715 },
+    { "3Com 3cSOHO100B-TX (ADMtek Centuar)", { 0x930010b7, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, TULIP_SIZE, COMET },
+    { "SG Thomson STE10/100A", { 0x2774104a, 0xffffffff, 0, 0, 0, 0 },
+      TULIP_IOTYPE, 256, COMET },	/*Ramesh Chander*/
+    { 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 },
+};
+
+enum tbl_flag {
+    HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+    HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+    HAS_PNICNWAY=0x80, HAS_NWAY=0x40,   /* Uses internal NWay xcvr. */
+    HAS_INTR_MITIGATION=0x100, IS_ASIX=0x200, HAS_8023X=0x400,
+};
+
+/* Note: this table must match  enum tulip_chips  above. */
+static struct tulip_chip_table {
+    char *chip_name;
+    int flags;
+} tulip_tbl[] = {
+    { "Digital DC21040 Tulip", 0},
+    { "Digital DC21041 Tulip", HAS_MEDIA_TABLE | HAS_NWAY },
+    { "Digital DS21140 Tulip", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM },
+    { "Digital DS21143 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII 
+      | HAS_PWRDWN | HAS_NWAY   | HAS_INTR_MITIGATION },
+    { "Lite-On 82c168 PNIC", HAS_MII | HAS_PNICNWAY },
+    { "Macronix 98713 PMAC", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM },
+    { "Macronix 98715 PMAC", HAS_MEDIA_TABLE },
+    { "Macronix 98725 PMAC", HAS_MEDIA_TABLE },
+    { "ASIX AX88140", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM 
+      | MC_HASH_ONLY | IS_ASIX },
+    { "ASIX AX88141", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY 
+      | IS_ASIX },
+    { "Lite-On PNIC-II", HAS_MII | HAS_NWAY | HAS_8023X },
+    { "ADMtek Comet", HAS_MII | MC_HASH_ONLY },
+    { "Compex 9881 PMAC",       HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM },
+    { "Intel DS21145 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII 
+      | HAS_PWRDWN | HAS_NWAY },
+    { "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII 
+      | HAS_PWRDWN | HAS_NWAY },
+    { "SGThomson STE10/100A", HAS_MII | MC_HASH_ONLY },	/*Ramesh Chander*/   
+    { 0, 0 },
+};
+
+/* A full-duplex map for media types. */
+enum MediaIs {
+    MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+    MediaIs100=16};
+
+static const char media_cap[32] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20, 20,31,0,0, };
+static u8 t21040_csr13[] = {2,0x0C,8,4,  4,0,0,0, 0,0,0,0, 4,0,0,0};
+
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD */
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+/* not used
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+*/
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+/* not used
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+*/
+
+/* Offsets to the Command and Status Registers, "CSRs".  All accesses
+   must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+    CSR0=0,     CSR1=0x08,  CSR2=0x10,  CSR3=0x18,  CSR4=0x20,  CSR5=0x28,
+    CSR6=0x30,  CSR7=0x38,  CSR8=0x40,  CSR9=0x48, CSR10=0x50, CSR11=0x58,
+    CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0
+};
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+    TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+    NormalIntr=0x10000, AbnormalIntr=0x8000,
+    RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+    TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+/* The configuration bits in CSR6. */
+enum csr6_mode_bits {
+	TxOn=0x2000, RxOn=0x0002, FullDuplex=0x0200,
+	AcceptBroadcast=0x0100, AcceptAllMulticast=0x0080,
+	AcceptAllPhys=0x0040, AcceptRunt=0x0008,
+};
+
+
+enum desc_status_bits {
+    DescOwnded=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+struct medialeaf {
+    u8 type;
+    u8 media;
+    unsigned char *leafdata;
+};
+
+struct mediatable {
+    u16 defaultmedia;
+    u8 leafcount, csr12dir;                             /* General purpose pin directions. */
+    unsigned has_mii:1, has_nonmii:1, has_reset:6;
+    u32 csr15dir, csr15val;                             /* 21143 NWay setting. */
+    struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+    struct mediainfo *next;
+    int info_type;
+    int index;
+    unsigned char *info;
+};
+
+/* EEPROM Address width definitions */
+#define EEPROM_ADDRLEN 6
+#define EEPROM_SIZE    128              /* 2 << EEPROM_ADDRLEN */
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD    (5 << addr_len)
+#define EE_READ_CMD     (6 << addr_len)
+#define EE_ERASE_CMD    (7 << addr_len)
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK    0x02    /* EEPROM shift clock. */
+#define EE_CS           0x01    /* EEPROM chip select. */
+#define EE_DATA_WRITE   0x04    /* EEPROM chip data in. */
+#define EE_WRITE_0      0x01
+#define EE_WRITE_1      0x05
+#define EE_DATA_READ    0x08    /* EEPROM chip data out. */
+#define EE_ENB          (0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.  Even at 33Mhz current PCI
+   implementations don't overrun the EEPROM clock.  We add a bus
+   turn-around to insure that this remains true.  */
+#define eeprom_delay()  inl(ee_addr)
+
+/* Size of transmit and receive buffers */
+#define BUFLEN 1536
+
+/* Ring-wrap flag in length field, use for last ring entry.
+   0x01000000 means chain on buffer2 address,
+   0x02000000 means use the ring start address in CSR2/3.
+   Note: Some work-alike chips do not function correctly in chained mode.
+   The ASIX chip works only in chained mode.
+   Thus we indicate ring mode, but always write the 'next' field for
+   chained mode as well. */
+#define DESC_RING_WRAP 0x02000000
+
+/* transmit and receive descriptor format */
+struct tulip_rx_desc {
+    volatile u32 status;
+    u32 length;
+    u32 buffer1, buffer2;
+};
+
+struct tulip_tx_desc {
+    volatile u32 status;
+    u32 length;
+    u32 buffer1, buffer2;
+};
+
+/*********************************************************************/
+/* Global Storage                                                    */
+/*********************************************************************/
+
+static u32 ioaddr;
+
+struct tulip_private {
+    int cur_rx;
+    int chip_id;                        /* index into tulip_tbl[]  */
+    int pci_id_idx;                     /* index into pci_id_tbl[] */
+    int revision;
+    int flags;
+    unsigned short vendor_id;           /* PCI card vendor code */
+    unsigned short dev_id;              /* PCI card device code */
+    unsigned char ehdr[ETH_HLEN];       /* buffer for ethernet header */
+    const char *nic_name;
+    unsigned int csr0, csr6;            /* Current CSR0, CSR6 settings. */
+    unsigned int if_port;
+    unsigned int full_duplex;         /* Full-duplex operation requested. */
+    unsigned int full_duplex_lock;
+    unsigned int medialock;           /* Do not sense media type. */
+    unsigned int mediasense;          /* Media sensing in progress. */
+    unsigned int nway, nwayset;     /* 21143 internal NWay. */
+    unsigned int default_port;
+    unsigned char eeprom[EEPROM_SIZE];  /* Serial EEPROM contents. */
+    u8 media_table_storage[(sizeof(struct mediatable) + 32*sizeof(struct medialeaf))];
+    u16 sym_advertise, mii_advertise;   /* NWay to-advertise. */
+    struct mediatable *mtable;
+    u16 lpar;                           /* 21143 Link partner ability. */
+    u16 advertising[4];                 /* MII advertise, from SROM table. */
+    signed char phys[4], mii_cnt;       /* MII device addresses. */
+    int cur_index;                      /* Current media index. */
+    int saved_if_port;
+};
+
+/* Note: transmit and receive buffers must be longword aligned and
+   longword divisable */
+
+#define TX_RING_SIZE	2
+#define RX_RING_SIZE	4
+struct {
+    struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+    unsigned char txb[BUFLEN];
+    struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+    unsigned char rxb[RX_RING_SIZE * BUFLEN];
+    struct tulip_private tpx;
+} tulip_bss __shared __attribute__ ((aligned(4)));
+#define tx_ring tulip_bss.tx_ring
+#define txb tulip_bss.txb
+#define rx_ring tulip_bss.rx_ring
+#define rxb tulip_bss.rxb
+
+static struct tulip_private *tp;
+
+/* Known cards that have old-style EEPROMs.
+   Writing this table is described at
+   http://cesdis.gsfc.nasa.gov/linux/drivers/tulip-drivers/tulip-media.html */
+static struct fixups {
+    char *name;
+    unsigned char addr0, addr1, addr2;
+    u16 newtable[32];                           /* Max length below. */
+} eeprom_fixups[] = {
+    {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+                            0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+    {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
+                                 0x0000, 0x009E, /* 10baseT */
+                                 0x0004, 0x009E, /* 10baseT-FD */
+                                 0x0903, 0x006D, /* 100baseTx */
+                                 0x0905, 0x006D, /* 100baseTx-FD */ }},
+    {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
+                                   0x0107, 0x8021, /* 100baseFx */
+                                   0x0108, 0x8021, /* 100baseFx-FD */
+                                   0x0100, 0x009E, /* 10baseT */
+                                   0x0104, 0x009E, /* 10baseT-FD */
+                                   0x0103, 0x006D, /* 100baseTx */
+                                   0x0105, 0x006D, /* 100baseTx-FD */ }},
+    {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
+                                     0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+                                     0x0000, 0x009E, /* 10baseT */
+                                     0x0004, 0x009E, /* 10baseT-FD */
+                                     0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+                                     0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+    {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
+                                    0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */
+                                    0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */
+                                    0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+                                    0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+                                    0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
+    }},
+    {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+                                    "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+
+/*********************************************************************/
+/* Function Prototypes                                               */
+/*********************************************************************/
+static int mdio_read(struct nic *nic, int phy_id, int location);
+static void mdio_write(struct nic *nic, int phy_id, int location, int value);
+static int read_eeprom(unsigned long ioaddr, int location, int addr_len);
+static void parse_eeprom(struct nic *nic);
+static int tulip_probe(struct nic *nic,struct pci_device *pci);
+static void tulip_init_ring(struct nic *nic);
+static void tulip_reset(struct nic *nic);
+static void tulip_transmit(struct nic *nic, const char *d, unsigned int t,
+                           unsigned int s, const char *p);
+static int tulip_poll(struct nic *nic, int retrieve);
+static void tulip_disable(struct nic *nic);
+static void nway_start(struct nic *nic);
+static void pnic_do_nway(struct nic *nic);
+static void select_media(struct nic *nic, int startup);
+static void init_media(struct nic *nic);
+static void start_link(struct nic *nic);
+static int tulip_check_duplex(struct nic *nic);
+
+static void tulip_wait(unsigned int nticks);
+
+
+/*********************************************************************/
+/* Utility Routines                                                  */
+/*********************************************************************/
+
+static void whereami (const char *str)
+{
+    DBGP("%s\n", str);
+    /* sleep(2); */
+}
+
+static void tulip_wait(unsigned int nticks)
+{
+    unsigned int to = currticks() + nticks;
+    while (currticks() < to)
+        /* wait */ ;
+}
+
+
+/*********************************************************************/
+/* Media Descriptor Code                                             */
+/*********************************************************************/
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK  0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB                0x00000         /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN             0x40000
+#define MDIO_DATA_READ  0x80000
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+int mdio_read(struct nic *nic __unused, int phy_id, int location)
+{
+    int i;
+    int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+    int retval = 0;
+    long mdio_addr = ioaddr + CSR9;
+
+    whereami("mdio_read\n");
+
+    if (tp->chip_id == LC82C168) {
+	int i = 1000;
+	outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+	inl(ioaddr + 0xA0);
+	inl(ioaddr + 0xA0);
+	while (--i > 0)
+	    if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+		return retval & 0xffff;
+	return 0xffff;
+    }
+
+    if (tp->chip_id == COMET) {
+	if (phy_id == 1) {
+	    if (location < 7)
+		return inl(ioaddr + 0xB4 + (location<<2));
+	    else if (location == 17)
+		return inl(ioaddr + 0xD0);
+	    else if (location >= 29 && location <= 31)
+		return inl(ioaddr + 0xD4 + ((location-29)<<2));
+	}
+	return 0xffff;
+    }
+
+    /* Establish sync by sending at least 32 logic ones. */
+    for (i = 32; i >= 0; i--) {
+	outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+	mdio_delay();
+	outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+    /* Shift the read command bits out. */
+    for (i = 15; i >= 0; i--) {
+	int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+	outl(MDIO_ENB | dataval, mdio_addr);
+	mdio_delay();
+	outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+    /* Read the two transition, 16 data, and wire-idle bits. */
+    for (i = 19; i > 0; i--) {
+	outl(MDIO_ENB_IN, mdio_addr);
+	mdio_delay();
+	retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+	outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+    return (retval>>1) & 0xffff;
+}
+
+void mdio_write(struct nic *nic __unused, int phy_id, int location, int value)
+{
+    int i;
+    int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+    long mdio_addr = ioaddr + CSR9;
+
+    whereami("mdio_write\n");
+
+    if (tp->chip_id == LC82C168) {
+	int i = 1000;
+	outl(cmd, ioaddr + 0xA0);
+	do
+	    if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+		break;
+	while (--i > 0);
+	return;
+    }
+
+    if (tp->chip_id == COMET) {
+	if (phy_id != 1)
+	    return;
+	if (location < 7)
+	    outl(value, ioaddr + 0xB4 + (location<<2));
+	else if (location == 17)
+	    outl(value, ioaddr + 0xD0);
+	else if (location >= 29 && location <= 31)
+	    outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+	return;
+    }
+
+    /* Establish sync by sending 32 logic ones. */
+    for (i = 32; i >= 0; i--) {
+	outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+	mdio_delay();
+	outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+    /* Shift the command bits out. */
+    for (i = 31; i >= 0; i--) {
+	int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+	outl(MDIO_ENB | dataval, mdio_addr);
+	mdio_delay();
+	outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+    /* Clear out extra bits. */
+    for (i = 2; i > 0; i--) {
+	outl(MDIO_ENB_IN, mdio_addr);
+	mdio_delay();
+	outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	mdio_delay();
+    }
+}
+
+
+/*********************************************************************/
+/* EEPROM Reading Code                                               */
+/*********************************************************************/
+/* EEPROM routines adapted from the Linux Tulip Code */
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way
+   through:->.
+*/
+static int read_eeprom(unsigned long ioaddr, int location, int addr_len)
+{
+    int i;
+    unsigned short retval = 0;
+    long ee_addr = ioaddr + CSR9;
+    int read_cmd = location | EE_READ_CMD;
+
+    whereami("read_eeprom\n");
+
+    outl(EE_ENB & ~EE_CS, ee_addr);
+    outl(EE_ENB, ee_addr);
+
+    /* Shift the read command bits out. */
+    for (i = 4 + addr_len; i >= 0; i--) {
+        short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+        outl(EE_ENB | dataval, ee_addr);
+        eeprom_delay();
+        outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay();
+    }
+    outl(EE_ENB, ee_addr);
+
+    for (i = 16; i > 0; i--) {
+        outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay();
+        retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+        outl(EE_ENB, ee_addr);
+        eeprom_delay();
+    }
+
+    /* Terminate the EEPROM access. */
+    outl(EE_ENB & ~EE_CS, ee_addr);
+    return retval;
+}
+
+
+/*********************************************************************/
+/* EEPROM Parsing Code                                               */
+/*********************************************************************/
+static void parse_eeprom(struct nic *nic)
+{
+    unsigned char *p, *ee_data = tp->eeprom;
+    int new_advertise = 0;
+    int i;
+
+    whereami("parse_eeprom\n");
+
+    tp->mtable = 0;
+    /* Detect an old-style (SA only) EEPROM layout:
+       memcmp(ee_data, ee_data+16, 8). */
+    for (i = 0; i < 8; i ++)
+        if (ee_data[i] != ee_data[16+i])
+            break;
+    if (i >= 8) {
+        /* Do a fix-up based on the vendor half of the station address. */
+        for (i = 0; eeprom_fixups[i].name; i++) {
+            if (nic->node_addr[0] == eeprom_fixups[i].addr0
+                &&  nic->node_addr[1] == eeprom_fixups[i].addr1
+                &&  nic->node_addr[2] == eeprom_fixups[i].addr2) {
+                if (nic->node_addr[2] == 0xE8  &&  ee_data[0x1a] == 0x55)
+                    i++;                /* An Accton EN1207, not an outlaw Maxtech. */
+                memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+                       sizeof(eeprom_fixups[i].newtable));
+                DBG("%s: Old format EEPROM on '%s' board.\n%s: Using substitute media control info.\n",
+                       tp->nic_name, eeprom_fixups[i].name, tp->nic_name);
+                break;
+            }
+        }
+        if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+            DBG("%s: Old style EEPROM with no media selection information.\n",
+                   tp->nic_name);
+            return;
+        }
+    }
+
+    if (ee_data[19] > 1) {
+        DBG("%s:  Multiport cards (%d ports) may not work correctly.\n",
+               tp->nic_name, ee_data[19]);
+    }
+
+    p = (void *)ee_data + ee_data[27];
+
+    if (ee_data[27] == 0) {             /* No valid media table. */
+            DBG2("%s:  No Valid Media Table. ee_data[27] = %hhX\n",
+		 tp->nic_name, ee_data[27]);
+    } else if (tp->chip_id == DC21041) {
+        int media = get_u16(p);
+        int count = p[2];
+        p += 3;
+
+        DBG("%s: 21041 Media table, default media %hX (%s).\n",
+               tp->nic_name, media,
+               media & 0x0800 ? "Autosense" : medianame[media & 15]);
+        for (i = 0; i < count; i++) {
+            unsigned char media_block = *p++;
+            int media_code = media_block & MEDIA_MASK;
+            if (media_block & 0x40)
+                p += 6;
+            switch(media_code) {
+            case 0: new_advertise |= 0x0020; break;
+            case 4: new_advertise |= 0x0040; break;
+            }
+            DBG("%s:  21041 media #%d, %s.\n",
+                   tp->nic_name, media_code, medianame[media_code]);
+        }
+    } else {
+        unsigned char csr12dir = 0;
+        int count;
+        struct mediatable *mtable;
+        u16 media = get_u16(p);
+
+        p += 2;
+        if (tp->flags & CSR12_IN_SROM)
+            csr12dir = *p++;
+        count = *p++;
+
+        tp->mtable = mtable = (struct mediatable *)&tp->media_table_storage[0];
+
+        mtable->defaultmedia = media;
+        mtable->leafcount = count;
+        mtable->csr12dir = csr12dir;
+        mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+        mtable->csr15dir = mtable->csr15val = 0;
+
+        DBG("%s:  EEPROM default media type %s.\n", tp->nic_name,
+               media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
+
+        for (i = 0; i < count; i++) {
+            struct medialeaf *leaf = &mtable->mleaf[i];
+
+            if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+                leaf->type = 0;
+                leaf->media = p[0] & 0x3f;
+                leaf->leafdata = p;
+                if ((p[2] & 0x61) == 0x01)      /* Bogus, but Znyx boards do it. */
+                    mtable->has_mii = 1;
+                p += 4;
+            } else {
+                switch(leaf->type = p[1]) {
+                case 5:
+                    mtable->has_reset = i;
+                    leaf->media = p[2] & 0x0f;
+                    break;
+                case 1: case 3:
+                    mtable->has_mii = 1;
+                    leaf->media = 11;
+                    break;
+                case 2:
+                    if ((p[2] & 0x3f) == 0) {
+                        u32 base15 = (p[2] & 0x40) ? get_u16(p + 7) : 0x0008;
+                        u16 *p1 = (u16 *)(p + (p[2] & 0x40 ? 9 : 3));
+                        mtable->csr15dir = (get_unaligned(p1 + 0)<<16) + base15;
+                        mtable->csr15val = (get_unaligned(p1 + 1)<<16) + base15;
+                    }
+                    /* Fall through. */
+                case 0: case 4:
+                    mtable->has_nonmii = 1;
+                    leaf->media = p[2] & MEDIA_MASK;
+                    switch (leaf->media) {
+                    case 0: new_advertise |= 0x0020; break;
+                    case 4: new_advertise |= 0x0040; break;
+                    case 3: new_advertise |= 0x0080; break;
+                    case 5: new_advertise |= 0x0100; break;
+                    case 6: new_advertise |= 0x0200; break;
+                    }
+                    break;
+                default:
+                    leaf->media = 19;
+                }
+                leaf->leafdata = p + 2;
+                p += (p[0] & 0x3f) + 1;
+            }
+            if (leaf->media == 11) {
+                unsigned char *bp = leaf->leafdata;
+                DBG2("%s:  MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %hhX %hhX.\n",
+		     tp->nic_name, bp[0], bp[1], bp[2 + bp[1]*2],
+		     bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+            }
+            DBG("%s:  Index #%d - Media %s (#%d) described "
+                   "by a %s (%d) block.\n",
+                   tp->nic_name, i, medianame[leaf->media], leaf->media,
+                   leaf->type < 6 ? block_name[leaf->type] : "UNKNOWN",
+                   leaf->type);
+        }
+        if (new_advertise)
+            tp->sym_advertise = new_advertise;
+    }
+}
+
+
+/*********************************************************************/
+/* tulip_init_ring - setup the tx and rx descriptors                */
+/*********************************************************************/
+static void tulip_init_ring(struct nic *nic __unused)
+{
+    int i;
+
+    whereami("tulip_init_ring\n");
+
+    tp->cur_rx = 0;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	rx_ring[i].status  = cpu_to_le32(0x80000000);
+	rx_ring[i].length  = cpu_to_le32(BUFLEN);
+	rx_ring[i].buffer1 = virt_to_le32desc(&rxb[i * BUFLEN]);
+	rx_ring[i].buffer2 = virt_to_le32desc(&rx_ring[i+1]);
+    }
+    /* Mark the last entry as wrapping the ring. */
+    rx_ring[i-1].length    = cpu_to_le32(DESC_RING_WRAP | BUFLEN);
+    rx_ring[i-1].buffer2   = virt_to_le32desc(&rx_ring[0]);
+
+    /* We only use 1 transmit buffer, but we use 2 descriptors so
+       transmit engines have somewhere to point to if they feel the need */
+
+    tx_ring[0].status  = 0x00000000;
+    tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]);
+    tx_ring[0].buffer2 = virt_to_le32desc(&tx_ring[1]);
+
+    /* this descriptor should never get used, since it will never be owned
+       by the machine (status will always == 0) */
+    tx_ring[1].status  = 0x00000000;
+    tx_ring[1].buffer1 = virt_to_le32desc(&txb[0]);
+    tx_ring[1].buffer2 = virt_to_le32desc(&tx_ring[0]);
+
+    /* Mark the last entry as wrapping the ring, though this should never happen */
+    tx_ring[1].length  = cpu_to_le32(DESC_RING_WRAP | BUFLEN);
+}
+
+
+static void set_rx_mode(struct nic *nic __unused) {
+	int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+
+	tp->csr6 &= ~0x00D5;
+ 
+	/* !IFF_PROMISC */
+	tp->csr6 |= AcceptAllMulticast;
+	csr6 |= AcceptAllMulticast;
+
+	outl(csr6, ioaddr + CSR6);
+
+	
+	
+}
+
+/*********************************************************************/
+/* eth_reset - Reset adapter                                         */
+/*********************************************************************/
+static void tulip_reset(struct nic *nic)
+{
+    int i;
+    unsigned long to;
+
+    whereami("tulip_reset\n");
+
+    /* Stop Tx and RX */
+    outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+    /* On some chip revs we must set the MII/SYM port before the reset!? */
+    if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii)) {
+	outl(0x814C0000, ioaddr + CSR6);
+    }
+ 
+    /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+    outl(0x00000001, ioaddr + CSR0);
+    tulip_wait(1);
+
+    /* turn off reset and set cache align=16lword, burst=unlimit */
+    outl(tp->csr0, ioaddr + CSR0);
+
+    /*  Wait the specified 50 PCI cycles after a reset */
+    tulip_wait(1);
+
+    /* set up transmit and receive descriptors */
+    tulip_init_ring(nic);
+
+    if (tp->chip_id == PNIC2) {
+        u32 addr_high = (nic->node_addr[1]<<8) + (nic->node_addr[0]<<0);
+        /* This address setting does not appear to impact chip operation?? */
+        outl((nic->node_addr[5]<<8) + nic->node_addr[4] +
+             (nic->node_addr[3]<<24) + (nic->node_addr[2]<<16),
+             ioaddr + 0xB0);
+        outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
+    }
+
+    /* MC_HASH_ONLY boards don't support setup packets */
+    if (tp->flags & MC_HASH_ONLY) {
+        u32 addr_low = cpu_to_le32(get_unaligned((u32 *)nic->node_addr));
+        u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(nic->node_addr+4)));
+
+	/* clear multicast hash filters and setup MAC address filters */
+	if (tp->flags & IS_ASIX) {
+            outl(0, ioaddr + CSR13);
+            outl(addr_low,  ioaddr + CSR14);
+            outl(1, ioaddr + CSR13);
+            outl(addr_high, ioaddr + CSR14);
+	    outl(2, ioaddr + CSR13);
+	    outl(0, ioaddr + CSR14);
+	    outl(3, ioaddr + CSR13);
+	    outl(0, ioaddr + CSR14);
+	} else if (tp->chip_id == COMET) {
+            outl(addr_low,  ioaddr + 0xA4);
+            outl(addr_high, ioaddr + 0xA8);
+            outl(0, ioaddr + 0xAC);
+            outl(0, ioaddr + 0xB0);
+	}
+    } else {
+	/* for other boards we send a setup packet to initialize
+	   the filters */
+	u32 tx_flags = 0x08000000 | 192;
+
+	/* construct perfect filter frame with mac address as first match
+	   and broadcast address for all others */
+	for (i=0; i<192; i++) 
+	    txb[i] = 0xFF;
+	txb[0] = nic->node_addr[0];
+	txb[1] = nic->node_addr[1];
+	txb[4] = nic->node_addr[2];
+	txb[5] = nic->node_addr[3];
+	txb[8] = nic->node_addr[4];
+	txb[9] = nic->node_addr[5];
+
+	tx_ring[0].length  = cpu_to_le32(tx_flags);
+	tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]);
+	tx_ring[0].status  = cpu_to_le32(0x80000000);
+    }
+
+    /* Point to rx and tx descriptors */
+    outl(virt_to_le32desc(&rx_ring[0]), ioaddr + CSR3);
+    outl(virt_to_le32desc(&tx_ring[0]), ioaddr + CSR4);
+
+    init_media(nic);
+
+    /* set the chip's operating mode (but don't turn on xmit and recv yet) */
+    outl((tp->csr6 & ~0x00002002), ioaddr + CSR6);
+
+    /* send setup packet for cards that support it */
+    if (!(tp->flags & MC_HASH_ONLY)) {
+	/* enable transmit  wait for completion */
+	outl(tp->csr6 | 0x00002000, ioaddr + CSR6);
+	/* immediate transmit demand */
+	outl(0, ioaddr + CSR1);
+
+	to = currticks() + TX_TIME_OUT;
+	while ((tx_ring[0].status & 0x80000000) && (currticks() < to))
+	    /* wait */ ;
+
+	if (currticks() >= to) {
+	    DBG ("%s: TX Setup Timeout.\n", tp->nic_name);
+	}
+    }
+
+    if (tp->chip_id == LC82C168)
+	tulip_check_duplex(nic);
+
+    set_rx_mode(nic); 	
+        
+    /* enable transmit and receive */
+    outl(tp->csr6 | 0x00002002, ioaddr + CSR6);
+}
+
+
+/*********************************************************************/
+/* eth_transmit - Transmit a frame                                   */
+/*********************************************************************/
+static void tulip_transmit(struct nic *nic, const char *d, unsigned int t,
+                           unsigned int s, const char *p)
+{
+    u16 nstype;
+    u32 to;
+    u32 csr6 = inl(ioaddr + CSR6);
+
+    whereami("tulip_transmit\n");
+
+    /* Disable Tx */
+    outl(csr6 & ~0x00002000, ioaddr + CSR6);
+
+    memcpy(txb, d, ETH_ALEN);
+    memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
+    nstype = htons((u16) t);
+    memcpy(txb + 2 * ETH_ALEN, (u8 *)&nstype, 2);
+    memcpy(txb + ETH_HLEN, p, s);
+
+    s += ETH_HLEN;
+    s &= 0x0FFF;
+
+    /* pad to minimum packet size */
+    while (s < ETH_ZLEN)  
+        txb[s++] = '\0';
+
+    DBG2("%s: sending %d bytes ethtype %hX\n", tp->nic_name, s, t);
+        
+    /* setup the transmit descriptor */
+    /* 0x60000000 = no interrupt on completion */
+    tx_ring[0].length = cpu_to_le32(0x60000000 | s);
+    tx_ring[0].status = cpu_to_le32(0x80000000);
+
+    /* Point to transmit descriptor */
+    outl(virt_to_le32desc(&tx_ring[0]), ioaddr + CSR4);
+
+    /* Enable Tx */
+    outl(csr6 | 0x00002000, ioaddr + CSR6);
+    /* immediate transmit demand */
+    outl(0, ioaddr + CSR1);
+
+    to = currticks() + TX_TIME_OUT;
+    while ((tx_ring[0].status & 0x80000000) && (currticks() < to))
+        /* wait */ ;
+
+    if (currticks() >= to) {
+        DBG ("TX Timeout!\n");
+    }
+
+    /* Disable Tx */
+    outl(csr6 & ~0x00002000, ioaddr + CSR6);
+}
+
+/*********************************************************************/
+/* eth_poll - Wait for a frame                                       */
+/*********************************************************************/
+static int tulip_poll(struct nic *nic, int retrieve)
+{
+
+    whereami("tulip_poll\n");
+
+    /* no packet waiting. packet still owned by NIC */
+    if (rx_ring[tp->cur_rx].status & 0x80000000)
+        return 0;
+
+    if ( ! retrieve ) return 1;
+
+    whereami("tulip_poll got one\n");
+
+    nic->packetlen = (rx_ring[tp->cur_rx].status & 0x3FFF0000) >> 16;
+
+    /* if we get a corrupted packet. throw it away and move on */
+    if (rx_ring[tp->cur_rx].status & 0x00008000) {
+	/* return the descriptor and buffer to receive ring */
+        rx_ring[tp->cur_rx].status = 0x80000000;
+	tp->cur_rx = (tp->cur_rx + 1) % RX_RING_SIZE;
+        return 0;
+    }
+
+    /* copy packet to working buffer */
+    memcpy(nic->packet, rxb + tp->cur_rx * BUFLEN, nic->packetlen);
+
+    /* return the descriptor and buffer to receive ring */
+    rx_ring[tp->cur_rx].status = 0x80000000;
+    tp->cur_rx = (tp->cur_rx + 1) % RX_RING_SIZE;
+
+    return 1;
+}
+
+/*********************************************************************/
+/* eth_disable - Disable the interface                               */
+/*********************************************************************/
+static void tulip_disable ( struct nic *nic ) {
+
+    whereami("tulip_disable\n");
+
+    tulip_reset(nic);
+
+    /* disable interrupts */
+    outl(0x00000000, ioaddr + CSR7);
+
+    /* Stop the chip's Tx and Rx processes. */
+    outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+    /* Clear the missed-packet counter. */
+    inl(ioaddr + CSR8);
+}
+
+/*********************************************************************/
+/*IRQ - Enable, Disable, or Force interrupts                         */
+/*********************************************************************/
+static void tulip_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations tulip_operations = {
+	.connect	= dummy_connect,
+	.poll		= tulip_poll,
+	.transmit	= tulip_transmit,
+	.irq		= tulip_irq,
+
+};
+
+/*********************************************************************/
+/* eth_probe - Look for an adapter                                   */
+/*********************************************************************/
+static int tulip_probe ( struct nic *nic, struct pci_device *pci ) {
+
+    u32 i;
+    u8  chip_rev;
+    u8 ee_data[EEPROM_SIZE];
+    unsigned short sum;
+    int chip_idx;
+    static unsigned char last_phys_addr[ETH_ALEN] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+
+    if (pci->ioaddr == 0)
+        return 0;
+
+    ioaddr         = pci->ioaddr;
+    nic->ioaddr    = pci->ioaddr & ~3;
+    nic->irqno     = 0;
+
+    /* point to private storage */
+    tp = &tulip_bss.tpx;
+
+    tp->vendor_id  = pci->vendor;
+    tp->dev_id     = pci->device;
+    tp->nic_name   = pci->id->name;
+
+    tp->if_port = 0;
+    tp->default_port = 0;
+
+    adjust_pci_device(pci);
+
+    /* disable interrupts */
+    outl(0x00000000, ioaddr + CSR7);
+
+    /* Stop the chip's Tx and Rx processes. */
+    outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
+
+    /* Clear the missed-packet counter. */
+    inl(ioaddr + CSR8);
+
+    DBG("\n");                /* so we start on a fresh line */
+    whereami("tulip_probe\n");
+
+    DBG2 ("%s: Looking for Tulip Chip: Vendor=%hX  Device=%hX\n", tp->nic_name,
+	  tp->vendor_id, tp->dev_id);
+
+    /* Figure out which chip we're dealing with */
+    i = 0;
+    chip_idx = -1;
+  
+    while (pci_id_tbl[i].name) {
+        if ( (((u32) tp->dev_id << 16) | tp->vendor_id) == 
+             (pci_id_tbl[i].id.pci & pci_id_tbl[i].id.pci_mask) ) {
+            chip_idx = pci_id_tbl[i].drv_flags;
+            break;
+        }
+        i++;
+    }
+
+    if (chip_idx == -1) {
+        DBG ("%s: Unknown Tulip Chip: Vendor=%hX  Device=%hX\n", tp->nic_name,
+                tp->vendor_id, tp->dev_id);
+        return 0;
+    }
+
+    tp->pci_id_idx = i;
+    tp->flags = tulip_tbl[chip_idx].flags;
+
+    DBG2 ("%s: tp->pci_id_idx == %d,  name == %s\n", tp->nic_name,
+	  tp->pci_id_idx, pci_id_tbl[tp->pci_id_idx].name);
+    DBG2 ("%s: chip_idx == %d, name == %s\n", tp->nic_name, chip_idx,
+	  tulip_tbl[chip_idx].chip_name);
+  
+    /* Bring the 21041/21143 out of sleep mode.
+       Caution: Snooze mode does not work with some boards! */
+    if (tp->flags & HAS_PWRDWN)
+        pci_write_config_dword(pci, 0x40, 0x00000000);
+
+    if (inl(ioaddr + CSR5) == 0xFFFFFFFF) {
+        DBG("%s: The Tulip chip at %X is not functioning.\n",
+               tp->nic_name, (unsigned int) ioaddr);
+        return 0;
+    }
+   
+    pci_read_config_byte(pci, PCI_REVISION, &chip_rev);
+
+    DBG("%s: [chip: %s] rev %d at %hX\n", tp->nic_name,
+           tulip_tbl[chip_idx].chip_name, chip_rev, (unsigned int) ioaddr);
+    DBG("%s: Vendor=%hX  Device=%hX", tp->nic_name, tp->vendor_id, tp->dev_id);
+
+    if (chip_idx == DC21041  &&  inl(ioaddr + CSR9) & 0x8000) {
+        DBG(" 21040 compatible mode.");
+        chip_idx = DC21040;
+    }
+
+    DBG("\n");
+
+    /* The SROM/EEPROM interface varies dramatically. */
+    sum = 0;
+    if (chip_idx == DC21040) {
+        outl(0, ioaddr + CSR9);         /* Reset the pointer with a dummy write. */
+        for (i = 0; i < ETH_ALEN; i++) {
+            int value, boguscnt = 100000;
+            do
+                value = inl(ioaddr + CSR9);
+            while (value < 0  && --boguscnt > 0);
+            nic->node_addr[i] = value;
+            sum += value & 0xff;
+        }
+    } else if (chip_idx == LC82C168) {
+        for (i = 0; i < 3; i++) {
+            int value, boguscnt = 100000;
+            outl(0x600 | i, ioaddr + 0x98);
+            do
+                value = inl(ioaddr + CSR9);
+            while (value < 0  && --boguscnt > 0);
+            put_unaligned(le16_to_cpu(value), ((u16*)nic->node_addr) + i);
+            sum += value & 0xffff;
+        }
+    } else if (chip_idx == COMET) {
+        /* No need to read the EEPROM. */
+        put_unaligned(inl(ioaddr + 0xA4), (u32 *)nic->node_addr);
+        put_unaligned(inl(ioaddr + 0xA8), (u16 *)(nic->node_addr + 4));
+        for (i = 0; i < ETH_ALEN; i ++)
+            sum += nic->node_addr[i];
+    } else {
+        /* A serial EEPROM interface, we read now and sort it out later. */
+        int sa_offset = 0;
+        int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+        for (i = 0; i < sizeof(ee_data)/2; i++)
+            ((u16 *)ee_data)[i] =
+                le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
+
+        /* DEC now has a specification (see Notes) but early board makers
+           just put the address in the first EEPROM locations. */
+        /* This does  memcmp(eedata, eedata+16, 8) */
+        for (i = 0; i < 8; i ++)
+            if (ee_data[i] != ee_data[16+i])
+                sa_offset = 20;
+        if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+            sa_offset = 2;              /* Grrr, damn Matrox boards. */
+        }
+        for (i = 0; i < ETH_ALEN; i ++) {
+            nic->node_addr[i] = ee_data[i + sa_offset];
+            sum += ee_data[i + sa_offset];
+        }
+    }
+    /* Lite-On boards have the address byte-swapped. */
+    if ((nic->node_addr[0] == 0xA0  ||  nic->node_addr[0] == 0xC0)
+        &&  nic->node_addr[1] == 0x00)
+        for (i = 0; i < ETH_ALEN; i+=2) {
+            char tmp = nic->node_addr[i];
+            nic->node_addr[i] = nic->node_addr[i+1];
+            nic->node_addr[i+1] = tmp;
+        }
+
+    if (sum == 0  || sum == ETH_ALEN*0xff) {
+        DBG("%s: EEPROM not present!\n", tp->nic_name);
+        for (i = 0; i < ETH_ALEN-1; i++)
+            nic->node_addr[i] = last_phys_addr[i];
+        nic->node_addr[i] = last_phys_addr[i] + 1;
+    }
+
+    for (i = 0; i < ETH_ALEN; i++)
+        last_phys_addr[i] = nic->node_addr[i];
+
+    DBG ( "%s: %s at ioaddr %hX\n", tp->nic_name, eth_ntoa ( nic->node_addr ), 
+	  (unsigned int) ioaddr );
+
+    tp->chip_id = chip_idx;
+    tp->revision = chip_rev;
+    tp->csr0 = csr0;
+
+    /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+       And the ASIX must have a burst limit or horrible things happen. */
+    if (chip_idx == DC21143  &&  chip_rev == 65)
+        tp->csr0 &= ~0x01000000;
+    else if (tp->flags & IS_ASIX)
+        tp->csr0 |= 0x2000;
+
+    if (media_cap[tp->default_port] & MediaIsMII) {
+        static const u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60,
+					    0x80, 0x100, 0x200 };
+        tp->mii_advertise = media2advert[tp->default_port - 9];
+        tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */
+    }
+
+    /* This is logically part of the probe routine, but too complex
+       to write inline. */
+    if (tp->flags & HAS_MEDIA_TABLE) {
+        memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+        parse_eeprom(nic);
+    }
+
+    start_link(nic);
+
+    /* reset the device and make ready for tx and rx of packets */
+    tulip_reset(nic);
+    nic->nic_op	= &tulip_operations;
+
+    /* give the board a chance to reset before returning */
+    tulip_wait(4*TICKS_PER_SEC);
+
+    return 1;
+}
+
+static void start_link(struct nic *nic)
+{
+    int i;
+
+    whereami("start_link\n");
+
+    if ((tp->flags & ALWAYS_CHECK_MII) ||
+        (tp->mtable  &&  tp->mtable->has_mii) ||
+        ( ! tp->mtable  &&  (tp->flags & HAS_MII))) {
+        unsigned int phy, phy_idx;
+        if (tp->mtable  &&  tp->mtable->has_mii) {
+            for (i = 0; i < tp->mtable->leafcount; i++)
+                if (tp->mtable->mleaf[i].media == 11) {
+                    tp->cur_index = i;
+                    tp->saved_if_port = tp->if_port;
+                    select_media(nic, 2);
+                    tp->if_port = tp->saved_if_port;
+                    break;
+                }
+        }
+
+        /* Find the connected MII xcvrs. */
+        for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+             phy++) {
+            int mii_status = mdio_read(nic, phy, 1);
+            if ((mii_status & 0x8301) == 0x8001 ||
+                ((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {
+                int mii_reg0 = mdio_read(nic, phy, 0);
+                int mii_advert = mdio_read(nic, phy, 4);
+                int to_advert;
+
+                if (tp->mii_advertise)
+                    to_advert = tp->mii_advertise;
+                else if (tp->advertising[phy_idx])
+                    to_advert = tp->advertising[phy_idx];
+                else                    /* Leave unchanged. */
+                    tp->mii_advertise = to_advert = mii_advert;
+
+                tp->phys[phy_idx++] = phy;
+                DBG("%s:  MII transceiver %d config %hX status %hX advertising %hX.\n",
+                       tp->nic_name, phy, mii_reg0, mii_status, mii_advert);
+                                /* Fixup for DLink with miswired PHY. */
+                if (mii_advert != to_advert) {
+                    DBG("%s:  Advertising %hX on PHY %d previously advertising %hX.\n",
+                           tp->nic_name, to_advert, phy, mii_advert);
+                    mdio_write(nic, phy, 4, to_advert);
+                }
+                                /* Enable autonegotiation: some boards default to off. */
+                mdio_write(nic, phy, 0, mii_reg0 |
+                           (tp->full_duplex ? 0x1100 : 0x1000) |
+                           (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+            }
+        }
+        tp->mii_cnt = phy_idx;
+        if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
+            DBG("%s: ***WARNING***: No MII transceiver found!\n",
+                   tp->nic_name);
+            tp->phys[0] = 1;
+        }
+    }
+
+    /* Reset the xcvr interface and turn on heartbeat. */
+    switch (tp->chip_id) {
+    case DC21040:
+        outl(0x00000000, ioaddr + CSR13);
+        outl(0x00000004, ioaddr + CSR13);
+        break;
+    case DC21041:
+        /* This is nway_start(). */
+        if (tp->sym_advertise == 0)
+            tp->sym_advertise = 0x0061;
+        outl(0x00000000, ioaddr + CSR13);
+        outl(0xFFFFFFFF, ioaddr + CSR14);
+        outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+        outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
+        outl(0x0000EF01, ioaddr + CSR13);
+        break;
+    case DC21140: default:
+        if (tp->mtable)
+            outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+        break;
+    case DC21142:
+    case PNIC2:
+        if (tp->mii_cnt  ||  media_cap[tp->if_port] & MediaIsMII) {
+            outl(0x82020000, ioaddr + CSR6);
+            outl(0x0000, ioaddr + CSR13);
+            outl(0x0000, ioaddr + CSR14);
+            outl(0x820E0000, ioaddr + CSR6);
+        } else
+            nway_start(nic);
+        break;
+    case LC82C168:
+        if ( ! tp->mii_cnt) {
+            tp->nway = 1;
+            tp->nwayset = 0;
+            outl(0x00420000, ioaddr + CSR6);
+            outl(0x30, ioaddr + CSR12);
+            outl(0x0001F078, ioaddr + 0xB8);
+            outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+        }
+        break;
+    case MX98713: case COMPEX9881:
+        outl(0x00000000, ioaddr + CSR6);
+        outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+        outl(0x00000001, ioaddr + CSR13);
+        break;
+    case MX98715: case MX98725:
+        outl(0x01a80000, ioaddr + CSR6);
+        outl(0xFFFFFFFF, ioaddr + CSR14);
+        outl(0x00001000, ioaddr + CSR12);
+        break;
+    case COMET:
+        /* No initialization necessary. */
+        break;
+    }
+}
+
+static void nway_start(struct nic *nic __unused)
+{
+    int csr14 = ((tp->sym_advertise & 0x0780) << 9)  |
+        ((tp->sym_advertise&0x0020)<<1) | 0xffbf;
+
+    whereami("nway_start\n");
+
+    tp->if_port = 0;
+    tp->nway = tp->mediasense = 1;
+    tp->nwayset = tp->lpar = 0;
+    if (tp->chip_id == PNIC2) {
+        tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0);
+        return;
+    }
+    DBG2("%s: Restarting internal NWay autonegotiation, %X.\n",
+	 tp->nic_name, csr14);
+    outl(0x0001, ioaddr + CSR13);
+    outl(csr14, ioaddr + CSR14);
+    tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0);
+    outl(tp->csr6, ioaddr + CSR6);
+    if (tp->mtable  &&  tp->mtable->csr15dir) {
+        outl(tp->mtable->csr15dir, ioaddr + CSR15);
+        outl(tp->mtable->csr15val, ioaddr + CSR15);
+    } else if (tp->chip_id != PNIC2)
+        outw(0x0008, ioaddr + CSR15);
+    if (tp->chip_id == DC21041)                 /* Trigger NWAY. */
+        outl(0xEF01, ioaddr + CSR12);
+    else
+        outl(0x1301, ioaddr + CSR12);
+}
+
+static void init_media(struct nic *nic)
+{
+    int i;
+
+    whereami("init_media\n");
+
+    tp->saved_if_port = tp->if_port;
+    if (tp->if_port == 0)
+        tp->if_port = tp->default_port;
+
+    /* Allow selecting a default media. */
+    i = 0;
+    if (tp->mtable == NULL)
+        goto media_picked;
+    if (tp->if_port) {
+        int looking_for = media_cap[tp->if_port] & MediaIsMII ? 11 :
+            (tp->if_port == 12 ? 0 : tp->if_port);
+        for (i = 0; i < tp->mtable->leafcount; i++)
+            if (tp->mtable->mleaf[i].media == looking_for) {
+                DBG("%s: Using user-specified media %s.\n",
+                       tp->nic_name, medianame[tp->if_port]);
+                goto media_picked;
+            }
+    }
+    if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+        int looking_for = tp->mtable->defaultmedia & 15;
+        for (i = 0; i < tp->mtable->leafcount; i++)
+            if (tp->mtable->mleaf[i].media == looking_for) {
+                DBG("%s: Using EEPROM-set media %s.\n",
+                       tp->nic_name, medianame[looking_for]);
+                goto media_picked;
+            }
+    }
+    /* Start sensing first non-full-duplex media. */
+    for (i = tp->mtable->leafcount - 1;
+         (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+        ;
+ media_picked:
+
+    tp->csr6 = 0;
+    tp->cur_index = i;
+    tp->nwayset = 0;
+
+    if (tp->if_port) {
+        if (tp->chip_id == DC21143  &&  media_cap[tp->if_port] & MediaIsMII) {
+            /* We must reset the media CSRs when we force-select MII mode. */
+            outl(0x0000, ioaddr + CSR13);
+            outl(0x0000, ioaddr + CSR14);
+            outl(0x0008, ioaddr + CSR15);
+        }
+        select_media(nic, 1);
+        return;
+    }
+    switch(tp->chip_id) {
+    case DC21041:
+        /* tp->nway = 1;*/
+        nway_start(nic);
+        break;
+    case DC21142:
+        if (tp->mii_cnt) {
+            select_media(nic, 1);
+	    DBG2("%s: Using MII transceiver %d, status %hX.\n",
+		 tp->nic_name, tp->phys[0], mdio_read(nic, tp->phys[0], 1));
+            outl(0x82020000, ioaddr + CSR6);
+            tp->csr6 = 0x820E0000;
+            tp->if_port = 11;
+            outl(0x0000, ioaddr + CSR13);
+            outl(0x0000, ioaddr + CSR14);
+        } else
+            nway_start(nic);
+        break;
+    case PNIC2:
+        nway_start(nic);
+        break;
+    case LC82C168:
+        if (tp->mii_cnt) {
+            tp->if_port = 11;
+            tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+            outl(0x0001, ioaddr + CSR15);
+        } else if (inl(ioaddr + CSR5) & TPLnkPass)
+            pnic_do_nway(nic);
+        else {
+            /* Start with 10mbps to do autonegotiation. */
+            outl(0x32, ioaddr + CSR12);
+            tp->csr6 = 0x00420000;
+            outl(0x0001B078, ioaddr + 0xB8);
+            outl(0x0201B078, ioaddr + 0xB8);
+        }
+        break;
+    case MX98713: case COMPEX9881:
+        tp->if_port = 0;
+        tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+        outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+        break;
+    case MX98715: case MX98725:
+        /* Provided by BOLO, Macronix - 12/10/1998. */
+        tp->if_port = 0;
+        tp->csr6 = 0x01a80200;
+        outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+        outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+        break;
+    case COMET:
+        /* Enable automatic Tx underrun recovery */
+        outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
+        tp->if_port = 0;
+	tp->csr6 = 0x00040000;
+        break;
+    case AX88140: case AX88141:
+        tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
+        break;
+    default:
+        select_media(nic, 1);
+    }
+}
+
+static void pnic_do_nway(struct nic *nic __unused)
+{
+    u32 phy_reg = inl(ioaddr + 0xB8);
+    u32 new_csr6 = tp->csr6 & ~0x40C40200;
+
+    whereami("pnic_do_nway\n");
+
+    if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+        if (phy_reg & 0x20000000)               tp->if_port = 5;
+        else if (phy_reg & 0x40000000)  tp->if_port = 3;
+        else if (phy_reg & 0x10000000)  tp->if_port = 4;
+        else if (phy_reg & 0x08000000)  tp->if_port = 0;
+        tp->nwayset = 1;
+        new_csr6 = (tp->if_port & 1) ? 0x01860000 : 0x00420000;
+        outl(0x32 | (tp->if_port & 1), ioaddr + CSR12);
+        if (tp->if_port & 1)
+            outl(0x1F868, ioaddr + 0xB8);
+        if (phy_reg & 0x30000000) {
+            tp->full_duplex = 1;
+            new_csr6 |= 0x00000200;
+        }
+	DBG2("%s: PNIC autonegotiated status %X, %s.\n",
+	     tp->nic_name, phy_reg, medianame[tp->if_port]);
+        if (tp->csr6 != new_csr6) {
+            tp->csr6 = new_csr6;
+            outl(tp->csr6 | 0x0002, ioaddr + CSR6);     /* Restart Tx */
+            outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+        }
+    }
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct nic *nic, int startup)
+{
+    struct mediatable *mtable = tp->mtable;
+    u32 new_csr6;
+    int i;
+
+    whereami("select_media\n");
+
+    if (mtable) {
+        struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+        unsigned char *p = mleaf->leafdata;
+        switch (mleaf->type) {
+        case 0:                                 /* 21140 non-MII xcvr. */
+            DBG2("%s: Using a 21140 non-MII transceiver"
+		 " with control setting %hhX.\n",
+		 tp->nic_name, p[1]);
+            tp->if_port = p[0];
+            if (startup)
+                outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+            outl(p[1], ioaddr + CSR12);
+            new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+            break;
+        case 2: case 4: {
+            u16 setup[5];
+            u32 csr13val, csr14val, csr15dir, csr15val;
+            for (i = 0; i < 5; i++)
+                setup[i] = get_u16(&p[i*2 + 1]);
+
+            tp->if_port = p[0] & 15;
+            if (media_cap[tp->if_port] & MediaAlwaysFD)
+                tp->full_duplex = 1;
+
+            if (startup && mtable->has_reset) {
+                struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+                unsigned char *rst = rleaf->leafdata;
+		DBG2("%s: Resetting the transceiver.\n",
+		     tp->nic_name);
+                for (i = 0; i < rst[0]; i++)
+                    outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+            }
+	    DBG2("%s: 21143 non-MII %s transceiver control %hX/%hX.\n",
+		 tp->nic_name, medianame[tp->if_port], setup[0], setup[1]);
+            if (p[0] & 0x40) {  /* SIA (CSR13-15) setup values are provided. */
+                csr13val = setup[0];
+                csr14val = setup[1];
+                csr15dir = (setup[3]<<16) | setup[2];
+                csr15val = (setup[4]<<16) | setup[2];
+                outl(0, ioaddr + CSR13);
+                outl(csr14val, ioaddr + CSR14);
+                outl(csr15dir, ioaddr + CSR15); /* Direction */
+                outl(csr15val, ioaddr + CSR15); /* Data */
+                outl(csr13val, ioaddr + CSR13);
+            } else {
+                csr13val = 1;
+                csr14val = 0x0003FF7F;
+                csr15dir = (setup[0]<<16) | 0x0008;
+                csr15val = (setup[1]<<16) | 0x0008;
+                if (tp->if_port <= 4)
+                    csr14val = t21142_csr14[tp->if_port];
+                if (startup) {
+                    outl(0, ioaddr + CSR13);
+                    outl(csr14val, ioaddr + CSR14);
+                }
+                outl(csr15dir, ioaddr + CSR15); /* Direction */
+                outl(csr15val, ioaddr + CSR15); /* Data */
+                if (startup) outl(csr13val, ioaddr + CSR13);
+            }
+	    DBG2("%s:  Setting CSR15 to %X/%X.\n",
+		 tp->nic_name, csr15dir, csr15val);
+            if (mleaf->type == 4)
+                new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+            else
+                new_csr6 = 0x82420000;
+            break;
+        }
+        case 1: case 3: {
+            int phy_num = p[0];
+            int init_length = p[1];
+            u16 *misc_info;
+
+            tp->if_port = 11;
+            new_csr6 = 0x020E0000;
+            if (mleaf->type == 3) {     /* 21142 */
+                u16 *init_sequence = (u16*)(p+2);
+                u16 *reset_sequence = &((u16*)(p+3))[init_length];
+                int reset_length = p[2 + init_length*2];
+                misc_info = reset_sequence + reset_length;
+                if (startup)
+                    for (i = 0; i < reset_length; i++)
+                        outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+                for (i = 0; i < init_length; i++)
+                    outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+            } else {
+                u8 *init_sequence = p + 2;
+                u8 *reset_sequence = p + 3 + init_length;
+                int reset_length = p[2 + init_length];
+                misc_info = (u16*)(reset_sequence + reset_length);
+                if (startup) {
+                    outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+                    for (i = 0; i < reset_length; i++)
+                        outl(reset_sequence[i], ioaddr + CSR12);
+                }
+                for (i = 0; i < init_length; i++)
+                    outl(init_sequence[i], ioaddr + CSR12);
+            }
+            tp->advertising[phy_num] = get_u16(&misc_info[1]) | 1;
+            if (startup < 2) {
+                if (tp->mii_advertise == 0)
+                    tp->mii_advertise = tp->advertising[phy_num];
+		DBG2("%s:  Advertising %hX on MII %d.\n",
+		     tp->nic_name, tp->mii_advertise, tp->phys[phy_num]);
+                mdio_write(nic, tp->phys[phy_num], 4, tp->mii_advertise);
+            }
+            break;
+        }
+        default:
+            DBG("%s:  Invalid media table selection %d.\n",
+                   tp->nic_name, mleaf->type);
+            new_csr6 = 0x020E0000;
+        }
+	DBG2("%s: Using media type %s, CSR12 is %hhX.\n",
+	     tp->nic_name, medianame[tp->if_port],
+	     inl(ioaddr + CSR12) & 0xff);
+    } else if (tp->chip_id == DC21041) {
+        int port = tp->if_port <= 4 ? tp->if_port : 0;
+	DBG2("%s: 21041 using media %s, CSR12 is %hX.\n",
+	     tp->nic_name, medianame[port == 3 ? 12: port],
+	     inl(ioaddr + CSR12));
+        outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+        outl(t21041_csr14[port], ioaddr + CSR14);
+        outl(t21041_csr15[port], ioaddr + CSR15);
+        outl(t21041_csr13[port], ioaddr + CSR13);
+        new_csr6 = 0x80020000;
+    } else if (tp->chip_id == LC82C168) {
+        if (startup && ! tp->medialock)
+            tp->if_port = tp->mii_cnt ? 11 : 0;
+	DBG2("%s: PNIC PHY status is %hX, media %s.\n",
+	     tp->nic_name, inl(ioaddr + 0xB8), medianame[tp->if_port]);
+        if (tp->mii_cnt) {
+            new_csr6 = 0x810C0000;
+            outl(0x0001, ioaddr + CSR15);
+            outl(0x0201B07A, ioaddr + 0xB8);
+        } else if (startup) {
+            /* Start with 10mbps to do autonegotiation. */
+            outl(0x32, ioaddr + CSR12);
+            new_csr6 = 0x00420000;
+            outl(0x0001B078, ioaddr + 0xB8);
+            outl(0x0201B078, ioaddr + 0xB8);
+        } else if (tp->if_port == 3  ||  tp->if_port == 5) {
+            outl(0x33, ioaddr + CSR12);
+            new_csr6 = 0x01860000;
+            /* Trigger autonegotiation. */
+            outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
+        } else {
+            outl(0x32, ioaddr + CSR12);
+            new_csr6 = 0x00420000;
+            outl(0x1F078, ioaddr + 0xB8);
+        }
+    } else if (tp->chip_id == DC21040) {                                        /* 21040 */
+        /* Turn on the xcvr interface. */
+        int csr12 = inl(ioaddr + CSR12);
+	DBG2("%s: 21040 media type is %s, CSR12 is %hhX.\n",
+	     tp->nic_name, medianame[tp->if_port], csr12);
+        if (media_cap[tp->if_port] & MediaAlwaysFD)
+            tp->full_duplex = 1;
+        new_csr6 = 0x20000;
+        /* Set the full duplux match frame. */
+        outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+        outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+        if (t21040_csr13[tp->if_port] & 8) {
+            outl(0x0705, ioaddr + CSR14);
+            outl(0x0006, ioaddr + CSR15);
+        } else {
+            outl(0xffff, ioaddr + CSR14);
+            outl(0x0000, ioaddr + CSR15);
+        }
+        outl(0x8f01 | t21040_csr13[tp->if_port], ioaddr + CSR13);
+    } else {                                    /* Unknown chip type with no media table. */
+        if (tp->default_port == 0)
+            tp->if_port = tp->mii_cnt ? 11 : 3;
+        if (media_cap[tp->if_port] & MediaIsMII) {
+            new_csr6 = 0x020E0000;
+        } else if (media_cap[tp->if_port] & MediaIsFx) {
+            new_csr6 = 0x028600000;
+        } else
+            new_csr6 = 0x038600000;
+	DBG2("%s: No media description table, assuming "
+	     "%s transceiver, CSR12 %hhX.\n",
+	     tp->nic_name, medianame[tp->if_port],
+	     inl(ioaddr + CSR12));
+    }
+
+    tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+    return;
+}
+
+/*
+  Check the MII negotiated duplex and change the CSR6 setting if
+  required.
+  Return 0 if everything is OK.
+  Return < 0 if the transceiver is missing or has no link beat.
+*/
+static int tulip_check_duplex(struct nic *nic)
+{
+        unsigned int bmsr, lpa, negotiated, new_csr6;
+
+        bmsr = mdio_read(nic, tp->phys[0], 1);
+        lpa = mdio_read(nic, tp->phys[0], 5);
+
+	DBG2("%s: MII status %#x, Link partner report %#x.\n",
+	     tp->nic_name, bmsr, lpa);
+
+        if (bmsr == 0xffff)
+                return -2;
+        if ((bmsr & 4) == 0) { 
+                int new_bmsr = mdio_read(nic, tp->phys[0], 1); 
+                if ((new_bmsr & 4) == 0) { 
+			DBG2("%s: No link beat on the MII interface,"
+			     " status %#x.\n", tp->nic_name,
+			     new_bmsr);
+                        return -1;
+                }
+        }
+        tp->full_duplex = lpa & 0x140;
+
+        new_csr6 = tp->csr6;
+        negotiated = lpa & tp->advertising[0];
+
+        if(negotiated & 0x380) new_csr6 &= ~0x400000; 
+        else                   new_csr6 |= 0x400000;
+        if (tp->full_duplex)   new_csr6 |= 0x200; 
+        else                   new_csr6 &= ~0x200;
+
+        if (new_csr6 != tp->csr6) {
+                tp->csr6 = new_csr6;
+
+		DBG("%s: Setting %s-duplex based on MII"
+		    "#%d link partner capability of %#x.\n",
+		    tp->nic_name,
+		    tp->full_duplex ? "full" : "half",
+		    tp->phys[0], lpa);
+                return 1;
+        }
+
+        return 0;
+}
+
+static struct pci_device_id tulip_nics[] = {
+PCI_ROM(0x1011, 0x0002, "dc21040",     "Digital Tulip", 0),
+PCI_ROM(0x1011, 0x0009, "ds21140",     "Digital Tulip Fast", 0),
+PCI_ROM(0x1011, 0x0014, "dc21041",     "Digital Tulip+", 0),
+PCI_ROM(0x1011, 0x0019, "ds21142",     "Digital Tulip 21142", 0),
+PCI_ROM(0x10b7, 0x9300, "3csoho100b-tx","3ComSOHO100B-TX", 0),
+PCI_ROM(0x10b9, 0x5261, "ali1563",     "ALi 1563 integrated ethernet", 0),
+PCI_ROM(0x10d9, 0x0512, "mx98713",     "Macronix MX987x3", 0),
+PCI_ROM(0x10d9, 0x0531, "mx98715",     "Macronix MX987x5", 0),
+PCI_ROM(0x1113, 0x1217, "mxic-98715",  "Macronix MX987x5", 0),
+PCI_ROM(0x11ad, 0xc115, "lc82c115",    "LinkSys LNE100TX", 0),
+PCI_ROM(0x11ad, 0x0002, "82c168",      "Netgear FA310TX", 0),
+PCI_ROM(0x1282, 0x9100, "dm9100",      "Davicom 9100", 0),
+PCI_ROM(0x1282, 0x9102, "dm9102",      "Davicom 9102", 0),
+PCI_ROM(0x1282, 0x9009, "dm9009",      "Davicom 9009", 0),
+PCI_ROM(0x1282, 0x9132, "dm9132",      "Davicom 9132", 0),
+PCI_ROM(0x1317, 0x0985, "centaur-p",   "ADMtek Centaur-P", 0),
+PCI_ROM(0x1317, 0x0981, "an981",       "ADMtek AN981 Comet", 0),		/* ADMTek Centaur-P (stmicro) */
+PCI_ROM(0x1113, 0x1216, "an983",       "ADMTek AN983 Comet", 0),
+PCI_ROM(0x1317, 0x9511, "an983b",      "ADMTek Comet 983b", 0),
+PCI_ROM(0x1317, 0x1985, "centaur-c",   "ADMTek Centaur-C", 0),
+PCI_ROM(0x8086, 0x0039, "intel21145",  "Intel Tulip", 0),
+PCI_ROM(0x125b, 0x1400, "ax88140",     "ASIX AX88140", 0),
+PCI_ROM(0x11f6, 0x9881, "rl100tx",     "Compex RL100-TX", 0),
+PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip", 0),
+PCI_ROM(0x104a, 0x0981, "tulip-0981",  "Tulip 0x104a 0x0981", 0),
+PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774", 0),	/*Modified by Ramesh Chander*/
+PCI_ROM(0x1113, 0x9511, "tulip-9511",  "Tulip 0x1113 0x9511", 0),
+PCI_ROM(0x1186, 0x1561, "tulip-1561",  "Tulip 0x1186 0x1561", 0),
+PCI_ROM(0x1259, 0xa120, "tulip-a120",  "Tulip 0x1259 0xa120", 0),
+PCI_ROM(0x13d1, 0xab02, "tulip-ab02",  "Tulip 0x13d1 0xab02", 0),
+PCI_ROM(0x13d1, 0xab03, "tulip-ab03",  "Tulip 0x13d1 0xab03", 0),
+PCI_ROM(0x13d1, 0xab08, "tulip-ab08",  "Tulip 0x13d1 0xab08", 0),
+PCI_ROM(0x14f1, 0x1803, "lanfinity",   "Conexant LANfinity", 0),
+PCI_ROM(0x1626, 0x8410, "tulip-8410",  "Tulip 0x1626 0x8410", 0),
+PCI_ROM(0x1737, 0xab08, "tulip-1737-ab08","Tulip 0x1737 0xab08", 0),
+PCI_ROM(0x1737, 0xab09, "tulip-ab09",  "Tulip 0x1737 0xab09", 0),
+};
+
+PCI_DRIVER ( tulip_driver, tulip_nics, PCI_NO_CLASS );
+
+DRIVER ( "Tulip", nic_driver, pci_driver, tulip_driver,
+	 tulip_probe, tulip_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.txt b/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.txt
new file mode 100644
index 0000000..b4f6756
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/tulip.txt
@@ -0,0 +1,54 @@
+This software may be used and distributed according to the terms of
+the GNU Public License, incorporated herein by reference.
+
+This is a tulip and clone driver for Etherboot.  See the revision
+history in the tulip.c file for information on changes.  This version
+of the driver incorporates changes from Bob Edwards and Paul Mackerras
+who cantributed changes to support the TRENDnet TE100-PCIA NIC which
+uses a genuine Intel 21143-PD chipset.  There are also various code
+cleanups to make time-based activities more reliable.
+
+Of course you have to have all the usual Etherboot environment
+(bootp/dhcp/NFS) set up, and you need a Linux kernel with v0.91g
+(7.16.99) or later of the tulip.c driver compiled in to support some
+MX98715 based cards.  That file is available at:
+
+  http://cesdis.gsfc.nasa.gov/linux/drivers/test/tulip.c
+
+NOTES
+
+I've tested this driver with a SOHOware Fast 10/100 Model SDA110A,
+a Linksys LNE100TX v2.0, and a Netgear FA310TX card, and it worked at
+both 10 and 100 mbits. Other cards based on the tulip family may work as
+well.
+
+These cards are about 20$US, are supported by Linux and now Etherboot,
+and being PCI, they auto-configure IRQ and IOADDR and auto-negotiate
+10/100 half/full duplex. It seems like a pretty good value compared to
+some of the pricier cards, and can lower the cost of building/adapting
+thin client workstations substantially while giving a considerable
+performance increase.
+
+On some PCI tulip clone chipsets (MX987x5, LC82C115, LC82C168) this driver 
+lets the card choose the fastest speed it can negotiate with the peer
+device.  On other cards, it chooses 10mbit half-duplex.
+
+I burned an AM27C256 (32KByte) EPROM with mx987x5.lzrom and it worked.
+According to the data sheet the MX98715A supports up to 64K (27C512)
+EPROMs, 
+
+I've liberally commented the code and header files in the hope that it
+will help the next person who hacks the code or needs to support some
+tulip clone card, or wishes to add functionality.
+
+Anyway, please test this if you can on your tulip based card, and let
+me (mdc at etherboot.org) and the Etherboot-Discuss list
+(etherboot-discuss at lists.sourceforge.net) know how things go.  I also
+would appreciate code review by people who program.  I'm a strong
+believer in "another set of eyes".
+
+Regards,
+
+Marty Connor
+mdc at etherboot.org
+http://www.etherboot.org/
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/via-rhine.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-rhine.c
new file mode 100644
index 0000000..439a4a5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-rhine.c
@@ -0,0 +1,1447 @@
+/* rhine.c:Fast Ethernet driver for Linux. */
+/*
+	Adapted 09-jan-2000 by Paolo Marini (paolom at prisma-eng.it)
+
+        originally written by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License (GPL), incorporated herein by reference.
+	Drivers derived from this code also fall under the GPL and must retain
+	this authorship and copyright notice.
+
+	Under no circumstances are the authors responsible for
+	the proper functioning of this software, nor do the authors assume any
+	responsibility for damages incurred with its use.
+
+	This driver is designed for the VIA VT86C100A Rhine-II PCI Fast Ethernet
+	controller.
+
+*/
+
+static const char *version = "rhine.c v1.0.2 2004-10-29\n";
+
+/* A few user-configurable values. */
+
+// max time out delay time
+#define W_MAX_TIMEOUT	0x0FFFU
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX	3	/* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	1536
+#define RX_BUF_SIZE	1536
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((2000*HZ)/1000)
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+/* define all ioaddr */
+
+#define byPAR0				ioaddr
+#define byRCR				ioaddr + 6
+#define byTCR				ioaddr + 7
+#define byCR0				ioaddr + 8
+#define byCR1				ioaddr + 9
+#define byISR0				ioaddr + 0x0c
+#define byISR1				ioaddr + 0x0d
+#define byIMR0				ioaddr + 0x0e
+#define byIMR1				ioaddr + 0x0f
+#define byMAR0				ioaddr + 0x10
+#define byMAR1				ioaddr + 0x11
+#define byMAR2				ioaddr + 0x12
+#define byMAR3				ioaddr + 0x13
+#define byMAR4				ioaddr + 0x14
+#define byMAR5				ioaddr + 0x15
+#define byMAR6				ioaddr + 0x16
+#define byMAR7				ioaddr + 0x17
+#define dwCurrentRxDescAddr		ioaddr + 0x18
+#define dwCurrentTxDescAddr		ioaddr + 0x1c
+#define dwCurrentRDSE0			ioaddr + 0x20
+#define dwCurrentRDSE1			ioaddr + 0x24
+#define dwCurrentRDSE2			ioaddr + 0x28
+#define dwCurrentRDSE3			ioaddr + 0x2c
+#define dwNextRDSE0			ioaddr + 0x30
+#define dwNextRDSE1			ioaddr + 0x34
+#define dwNextRDSE2			ioaddr + 0x38
+#define dwNextRDSE3			ioaddr + 0x3c
+#define dwCurrentTDSE0			ioaddr + 0x40
+#define dwCurrentTDSE1			ioaddr + 0x44
+#define dwCurrentTDSE2			ioaddr + 0x48
+#define dwCurrentTDSE3			ioaddr + 0x4c
+#define dwNextTDSE0			ioaddr + 0x50
+#define dwNextTDSE1			ioaddr + 0x54
+#define dwNextTDSE2			ioaddr + 0x58
+#define dwNextTDSE3			ioaddr + 0x5c
+#define dwCurrRxDMAPtr			ioaddr + 0x60
+#define dwCurrTxDMAPtr			ioaddr + 0x64
+#define byMPHY				ioaddr + 0x6c
+#define byMIISR				ioaddr + 0x6d
+#define byBCR0				ioaddr + 0x6e
+#define byBCR1				ioaddr + 0x6f
+#define byMIICR				ioaddr + 0x70
+#define byMIIAD				ioaddr + 0x71
+#define wMIIDATA			ioaddr + 0x72
+#define byEECSR				ioaddr + 0x74
+#define byTEST				ioaddr + 0x75
+#define byGPIO				ioaddr + 0x76
+#define byCFGA				ioaddr + 0x78
+#define byCFGB				ioaddr + 0x79
+#define byCFGC				ioaddr + 0x7a
+#define byCFGD				ioaddr + 0x7b
+#define wTallyCntMPA			ioaddr + 0x7c
+#define wTallyCntCRC			ioaddr + 0x7d
+#define bySTICKHW			ioaddr + 0x83
+#define byWOLcrClr			ioaddr + 0xA4
+#define byWOLcgClr			ioaddr + 0xA7
+#define byPwrcsrClr			ioaddr + 0xAC
+
+/*---------------------  Exioaddr Definitions -------------------------*/
+
+/*
+ * Bits in the RCR register
+ */
+
+#define RCR_RRFT2		0x80
+#define RCR_RRFT1		0x40
+#define RCR_RRFT0		0x20
+#define RCR_PROM		0x10
+#define RCR_AB			0x08
+#define RCR_AM			0x04
+#define RCR_AR			0x02
+#define RCR_SEP			0x01
+
+/*
+ * Bits in the TCR register
+ */
+
+#define TCR_RTSF		0x80
+#define TCR_RTFT1		0x40
+#define TCR_RTFT0		0x20
+#define TCR_OFSET		0x08
+#define TCR_LB1			0x04	/* loopback[1] */
+#define TCR_LB0			0x02	/* loopback[0] */
+
+/*
+ * Bits in the CR0 register
+ */
+
+#define CR0_RDMD		0x40	/* rx descriptor polling demand */
+#define CR0_TDMD		0x20	/* tx descriptor polling demand */
+#define CR0_TXON		0x10
+#define CR0_RXON		0x08
+#define CR0_STOP		0x04	/* stop NIC, default = 1 */
+#define CR0_STRT		0x02	/* start NIC */
+#define CR0_INIT		0x01	/* start init process */
+
+
+/*
+ * Bits in the CR1 register
+ */
+
+#define CR1_SFRST		0x80	/* software reset */
+#define CR1_RDMD1		0x40	/* RDMD1 */
+#define CR1_TDMD1		0x20	/* TDMD1 */
+#define CR1_KEYPAG		0x10	/* turn on par/key */
+#define CR1_DPOLL		0x08	/* disable rx/tx auto polling */
+#define CR1_FDX			0x04	/* full duplex mode */
+#define CR1_ETEN		0x02	/* early tx mode */
+#define CR1_EREN		0x01	/* early rx mode */
+
+/*
+ * Bits in the CR register
+ */
+
+#define CR_RDMD			0x0040	/* rx descriptor polling demand */
+#define CR_TDMD			0x0020	/* tx descriptor polling demand */
+#define CR_TXON			0x0010
+#define CR_RXON			0x0008
+#define CR_STOP			0x0004	/* stop NIC, default = 1 */
+#define CR_STRT			0x0002	/* start NIC */
+#define CR_INIT			0x0001	/* start init process */
+#define CR_SFRST		0x8000	/* software reset */
+#define CR_RDMD1		0x4000	/* RDMD1 */
+#define CR_TDMD1		0x2000	/* TDMD1 */
+#define CR_KEYPAG		0x1000	/* turn on par/key */
+#define CR_DPOLL		0x0800	/* disable rx/tx auto polling */
+#define CR_FDX			0x0400	/* full duplex mode */
+#define CR_ETEN			0x0200	/* early tx mode */
+#define CR_EREN			0x0100	/* early rx mode */
+
+/*
+ * Bits in the IMR0 register
+ */
+
+#define IMR0_CNTM		0x80
+#define IMR0_BEM		0x40
+#define IMR0_RUM		0x20
+#define IMR0_TUM		0x10
+#define IMR0_TXEM		0x08
+#define IMR0_RXEM		0x04
+#define IMR0_PTXM		0x02
+#define IMR0_PRXM		0x01
+
+/* define imrshadow */
+
+#define IMRShadow		0x5AFF
+
+/*
+ * Bits in the IMR1 register
+ */
+
+#define IMR1_INITM		0x80
+#define IMR1_SRCM		0x40
+#define IMR1_NBFM		0x10
+#define IMR1_PRAIM		0x08
+#define IMR1_RES0M		0x04
+#define IMR1_ETM		0x02
+#define IMR1_ERM		0x01
+
+/*
+ * Bits in the ISR register
+ */
+
+#define ISR_INITI		0x8000
+#define ISR_SRCI		0x4000
+#define ISR_ABTI		0x2000
+#define ISR_NORBF		0x1000
+#define ISR_PKTRA		0x0800
+#define ISR_RES0		0x0400
+#define ISR_ETI			0x0200
+#define ISR_ERI			0x0100
+#define ISR_CNT			0x0080
+#define ISR_BE			0x0040
+#define ISR_RU			0x0020
+#define ISR_TU			0x0010
+#define ISR_TXE			0x0008
+#define ISR_RXE			0x0004
+#define ISR_PTX			0x0002
+#define ISR_PRX			0x0001
+
+/*
+ * Bits in the ISR0 register
+ */
+
+#define ISR0_CNT		0x80
+#define ISR0_BE			0x40
+#define ISR0_RU			0x20
+#define ISR0_TU			0x10
+#define ISR0_TXE		0x08
+#define ISR0_RXE		0x04
+#define ISR0_PTX		0x02
+#define ISR0_PRX		0x01
+
+/*
+ * Bits in the ISR1 register
+ */
+
+#define ISR1_INITI		0x80
+#define ISR1_SRCI		0x40
+#define ISR1_NORBF		0x10
+#define ISR1_PKTRA		0x08
+#define ISR1_ETI		0x02
+#define ISR1_ERI		0x01
+
+/* ISR ABNORMAL CONDITION */
+
+#define ISR_ABNORMAL ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA
+
+/*
+ * Bits in the MIISR register
+ */
+
+#define MIISR_MIIERR		0x08
+#define MIISR_MRERR		0x04
+#define MIISR_LNKFL		0x02
+#define MIISR_SPEED		0x01
+
+/*
+ * Bits in the MIICR register
+ */
+
+#define MIICR_MAUTO		0x80
+#define MIICR_RCMD		0x40
+#define MIICR_WCMD		0x20
+#define MIICR_MDPM		0x10
+#define MIICR_MOUT		0x08
+#define MIICR_MDO		0x04
+#define MIICR_MDI		0x02
+#define MIICR_MDC		0x01
+
+/*
+ * Bits in the EECSR register
+ */
+
+#define EECSR_EEPR		0x80	/* eeprom programed status, 73h means programed */
+#define EECSR_EMBP		0x40	/* eeprom embeded programming */
+#define EECSR_AUTOLD		0x20	/* eeprom content reload */
+#define EECSR_DPM		0x10	/* eeprom direct programming */
+#define EECSR_CS		0x08	/* eeprom CS pin */
+#define EECSR_SK		0x04	/* eeprom SK pin */
+#define EECSR_DI		0x02	/* eeprom DI pin */
+#define EECSR_DO		0x01	/* eeprom DO pin */
+
+/*
+ * Bits in the BCR0 register
+ */
+
+#define BCR0_CRFT2		0x20
+#define BCR0_CRFT1		0x10
+#define BCR0_CRFT0		0x08
+#define BCR0_DMAL2		0x04
+#define BCR0_DMAL1		0x02
+#define BCR0_DMAL0		0x01
+
+/*
+ * Bits in the BCR1 register
+ */
+
+#define BCR1_CTSF		0x20
+#define BCR1_CTFT1		0x10
+#define BCR1_CTFT0		0x08
+#define BCR1_POT2		0x04
+#define BCR1_POT1		0x02
+#define BCR1_POT0		0x01
+
+/*
+ * Bits in the CFGA register
+ */
+
+#define CFGA_EELOAD		0x80	/* enable eeprom embeded and direct programming */
+#define CFGA_JUMPER		0x40
+#define CFGA_MTGPIO		0x08
+#define CFGA_T10EN		0x02
+#define CFGA_AUTO		0x01
+
+/*
+ * Bits in the CFGB register
+ */
+
+#define CFGB_PD			0x80
+#define CFGB_POLEN		0x02
+#define CFGB_LNKEN		0x01
+
+/*
+ * Bits in the CFGC register
+ */
+
+#define CFGC_M10TIO		0x80
+#define CFGC_M10POL		0x40
+#define CFGC_PHY1		0x20
+#define CFGC_PHY0		0x10
+#define CFGC_BTSEL		0x08
+#define CFGC_BPS2		0x04	/* bootrom select[2] */
+#define CFGC_BPS1		0x02	/* bootrom select[1] */
+#define CFGC_BPS0		0x01	/* bootrom select[0] */
+
+/*
+ * Bits in the CFGD register
+ */
+
+#define CFGD_GPIOEN		0x80
+#define CFGD_DIAG		0x40
+#define CFGD_MAGIC		0x10
+#define CFGD_RANDOM		0x08
+#define CFGD_CFDX		0x04
+#define CFGD_CEREN		0x02
+#define CFGD_CETEN		0x01
+
+/* Bits in RSR */
+#define RSR_RERR		0x00000001
+#define RSR_CRC			0x00000002
+#define RSR_FAE			0x00000004
+#define RSR_FOV			0x00000008
+#define RSR_LONG		0x00000010
+#define RSR_RUNT		0x00000020
+#define RSR_SERR		0x00000040
+#define RSR_BUFF		0x00000080
+#define RSR_EDP			0x00000100
+#define RSR_STP			0x00000200
+#define RSR_CHN			0x00000400
+#define RSR_PHY			0x00000800
+#define RSR_BAR			0x00001000
+#define RSR_MAR			0x00002000
+#define RSR_RXOK		0x00008000
+#define RSR_ABNORMAL		RSR_RERR+RSR_LONG+RSR_RUNT
+
+/* Bits in TSR */
+#define TSR_NCR0		0x00000001
+#define TSR_NCR1		0x00000002
+#define TSR_NCR2		0x00000004
+#define TSR_NCR3		0x00000008
+#define TSR_COLS		0x00000010
+#define TSR_CDH			0x00000080
+#define TSR_ABT			0x00000100
+#define TSR_OWC			0x00000200
+#define TSR_CRS			0x00000400
+#define TSR_UDF			0x00000800
+#define TSR_TBUFF		0x00001000
+#define TSR_SERR		0x00002000
+#define TSR_JAB			0x00004000
+#define TSR_TERR		0x00008000
+#define TSR_ABNORMAL		TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS
+#define TSR_OWN_BIT		0x80000000
+
+#define CB_DELAY_LOOP_WAIT	10	/* 10ms */
+/* enabled mask value of irq */
+
+#define W_IMR_MASK_VALUE	0x1BFF	/* initial value of IMR */
+
+/* Ethernet address filter type */
+#define PKT_TYPE_DIRECTED	0x0001	/* obsolete, directed address is always accepted */
+#define PKT_TYPE_MULTICAST	0x0002
+#define PKT_TYPE_ALL_MULTICAST	0x0004
+#define PKT_TYPE_BROADCAST	0x0008
+#define PKT_TYPE_PROMISCUOUS	0x0020
+#define PKT_TYPE_LONG		0x2000
+#define PKT_TYPE_RUNT		0x4000
+#define PKT_TYPE_ERROR		0x8000	/* accept error packets, e.g. CRC error */
+
+/* Loopback mode */
+
+#define NIC_LB_NONE		0x00
+#define NIC_LB_INTERNAL		0x01
+#define NIC_LB_PHY		0x02	/* MII or Internal-10BaseT loopback */
+
+#define TX_RING_SIZE		2
+#define RX_RING_SIZE		2
+#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
+
+#define PCI_REG_MODE3		0x53
+#define MODE3_MIION		0x04    /* in PCI_REG_MOD3 OF PCI space */
+
+enum rhine_revs {
+    VT86C100A       = 0x00,
+    VTunknown0      = 0x20,
+    VT6102          = 0x40,
+    VT8231          = 0x50, /* Integrated MAC */
+    VT8233          = 0x60, /* Integrated MAC */
+    VT8235          = 0x74, /* Integrated MAC */
+    VT8237          = 0x78, /* Integrated MAC */
+    VTunknown1      = 0x7C,
+    VT6105          = 0x80,
+    VT6105_B0       = 0x83,
+    VT6105L 	    = 0x8A,
+    VT6107          = 0x8C,
+    VTunknown2      = 0x8E,
+    VT6105M         = 0x90,
+};
+
+/* Transmit and receive descriptors definition */
+
+struct rhine_tx_desc
+{
+    union VTC_tx_status_tag
+    {
+	struct
+	{
+	    unsigned long ncro:1;
+	    unsigned long ncr1:1;
+	    unsigned long ncr2:1;
+	    unsigned long ncr3:1;
+	    unsigned long cols:1;
+	    unsigned long reserve_1:2;
+	    unsigned long cdh:1;
+	    unsigned long abt:1;
+	    unsigned long owc:1;
+	    unsigned long crs:1;
+	    unsigned long udf:1;
+	    unsigned long tbuff:1;
+	    unsigned long serr:1;
+	    unsigned long jab:1;
+	    unsigned long terr:1;
+	    unsigned long reserve_2:15;
+	    unsigned long own_bit:1;
+	}
+	bits;
+	unsigned long lw;
+    }
+    tx_status;
+
+    union VTC_tx_ctrl_tag
+    {
+	struct
+	{
+	    unsigned long tx_buf_size:11;
+	    unsigned long extend_tx_buf_size:4;
+	    unsigned long chn:1;
+	    unsigned long crc:1;
+	    unsigned long reserve_1:4;
+	    unsigned long stp:1;
+	    unsigned long edp:1;
+	    unsigned long ic:1;
+	    unsigned long reserve_2:8;
+	}
+	bits;
+	unsigned long lw;
+    }
+    tx_ctrl;
+
+    unsigned long buf_addr_1:32;
+    unsigned long buf_addr_2:32;
+
+};
+
+struct rhine_rx_desc
+{
+    union VTC_rx_status_tag
+    {
+	struct
+	{
+	    unsigned long rerr:1;
+	    unsigned long crc_error:1;
+	    unsigned long fae:1;
+	    unsigned long fov:1;
+	    unsigned long toolong:1;
+	    unsigned long runt:1;
+	    unsigned long serr:1;
+	    unsigned long buff:1;
+	    unsigned long edp:1;
+	    unsigned long stp:1;
+	    unsigned long chn:1;
+	    unsigned long phy:1;
+	    unsigned long bar:1;
+	    unsigned long mar:1;
+	    unsigned long reserve_1:1;
+	    unsigned long rxok:1;
+	    unsigned long frame_length:11;
+	    unsigned long reverve_2:4;
+	    unsigned long own_bit:1;
+	}
+	bits;
+	unsigned long lw;
+    }
+    rx_status;
+
+    union VTC_rx_ctrl_tag
+    {
+	struct
+	{
+	    unsigned long rx_buf_size:11;
+	    unsigned long extend_rx_buf_size:4;
+	    unsigned long reserved_1:17;
+	}
+	bits;
+	unsigned long lw;
+    }
+    rx_ctrl;
+
+    unsigned long buf_addr_1:32;
+    unsigned long buf_addr_2:32;
+
+};
+
+struct {
+	char txbuf[TX_RING_SIZE * PKT_BUF_SZ + 32];
+	char rxbuf[RX_RING_SIZE * PKT_BUF_SZ + 32];
+	char txdesc[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32];
+	char rxdesc[RX_RING_SIZE * sizeof (struct rhine_rx_desc) + 32];
+} rhine_buffers __shared;
+
+/* The I/O extent. */
+#define rhine_TOTAL_SIZE 0x80
+
+#ifdef	HAVE_DEVLIST
+struct netdev_entry rhine_drv =
+    { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL };
+#endif
+
+static int rhine_debug = 1;
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet
+controller.
+
+II. Board-specific settings
+
+Boards with this chip are functional only in a bus-master PCI slot.
+
+Many operational settings are loaded from the EEPROM to the Config word at
+offset 0x78.  This driver assumes that they are correct.
+If this driver is compiled to use PCI memory space operations the EEPROM
+must be configured to enable memory ops.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+This driver uses two statically allocated fixed-size descriptor lists
+formed into rings by a branch from the final descriptor to the beginning of
+the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
+
+IIIb/c. Transmit/Receive Structure
+
+This driver attempts to use a zero-copy receive and transmit scheme.
+
+Alas, all data buffers are required to start on a 32 bit boundary, so
+the driver must often copy transmit packets into bounce buffers.
+
+The driver allocates full frame size skbuffs for the Rx ring buffers at
+open() time and passes the skb->data field to the chip as receive data
+buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
+a fresh skbuff is allocated and the frame is copied to the new skbuff.
+When the incoming frame is larger, the skbuff is passed directly up the
+protocol stack.  Buffers consumed this way are replaced by newly allocated
+skbuffs in the last phase of netdev_rx().
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  New boards are typically used in generously configured machines
+and the underfilled buffers have negligible impact compared to the benefit of
+a single allocation size, so the default value of zero results in never
+copying packets.  When copying is done, the cost is usually mitigated by using
+a combined copy/checksum routine.  Copying also preloads the cache, which is
+most useful with small frames.
+
+Since the VIA chips are only able to transfer data to buffers on 32 bit
+boundaries, the the IP header at offset 14 in an ethernet frame isn't
+longword aligned for further processing.  Copying these unaligned buffers
+has the beneficial effect of 16-byte aligning the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+Preliminary VT86C100A manual from http://www.via.com.tw/
+http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+The VT86C100A manual is not reliable information.
+The chip does not handle unaligned transmit or receive buffers, resulting
+in significant performance degradation for bounce buffer copies on transmit
+and unaligned IP headers on receive.
+The chip does not pad to minimum transmit length.
+
+*/
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC	2	/* Number of Tx descriptor registers. */
+
+static struct rhine_private
+{
+    char devname[8];		/* Used only for kernel debugging. */
+    const char *product_name;
+    struct rhine_rx_desc *rx_ring;
+    struct rhine_tx_desc *tx_ring;
+    char *rx_buffs[RX_RING_SIZE];
+    char *tx_buffs[TX_RING_SIZE];
+
+    /* temporary Rx buffers. */
+
+    int chip_id;
+    int chip_revision;
+    unsigned short ioaddr;
+    unsigned int cur_rx, cur_tx;	/* The next free and used entries */
+    unsigned int dirty_rx, dirty_tx;
+    /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+    struct sk_buff *tx_skbuff[TX_RING_SIZE];
+    unsigned char mc_filter[8];	/* Current multicast filter. */
+    char phys[4];		/* MII device addresses. */
+    unsigned int tx_full:1;	/* The Tx queue is full. */
+    unsigned int full_duplex:1;	/* Full-duplex operation requested. */
+    unsigned int default_port:4;	/* Last dev->if_port value. */
+    unsigned int media2:4;	/* Secondary monitored media port. */
+    unsigned int medialock:1;	/* Don't sense media type. */
+    unsigned int mediasense:1;	/* Media sensing in progress. */
+}
+rhine;
+
+static void rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr,
+				 int chip_id, int options);
+static int QueryAuto (int);
+static int ReadMII (int byMIIIndex, int);
+static void WriteMII (char, char, char, int);
+static void MIIDelay (void);
+static void rhine_init_ring (struct nic *dev);
+static void rhine_disable (struct nic *nic);
+static void rhine_reset (struct nic *nic);
+static int rhine_poll (struct nic *nic, int retreive);
+static void rhine_transmit (struct nic *nic, const char *d, unsigned int t,
+			    unsigned int s, const char *p);
+static void reload_eeprom(int ioaddr);
+
+
+static void reload_eeprom(int ioaddr)
+{
+	int i;
+	outb(0x20, byEECSR);
+	/* Typically 2 cycles to reload. */
+	for (i = 0; i < 150; i++)
+		if (! (inb(byEECSR) & 0x20))
+			break;
+}
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+rhine_init_ring (struct nic *nic)
+{
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    int i;
+
+    tp->tx_full = 0;
+    tp->cur_rx = tp->cur_tx = 0;
+    tp->dirty_rx = tp->dirty_tx = 0;
+
+    for (i = 0; i < RX_RING_SIZE; i++)
+    {
+
+	tp->rx_ring[i].rx_status.bits.own_bit = 1;
+	tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536;
+
+	tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]);
+	tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]);
+	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */
+    }
+    /* Mark the last entry as wrapping the ring. */
+    /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */
+    tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]);
+    /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */
+
+    /* The Tx buffer descriptor is filled in as needed, but we
+       do need to clear the ownership bit. */
+
+    for (i = 0; i < TX_RING_SIZE; i++)
+    {
+
+	tp->tx_ring[i].tx_status.lw = 0;
+	tp->tx_ring[i].tx_ctrl.lw = 0x00e08000;
+	tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]);
+	tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]);
+	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */
+    }
+
+    tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]);
+    /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */
+}
+
+int
+QueryAuto (int ioaddr)
+{
+    int byMIIIndex;
+    int MIIReturn;
+
+	int advertising,mii_reg5;
+	int negociated;
+
+    byMIIIndex = 0x04;
+    MIIReturn = ReadMII (byMIIIndex, ioaddr);
+	advertising=MIIReturn;
+
+    byMIIIndex = 0x05;
+    MIIReturn = ReadMII (byMIIIndex, ioaddr);
+	mii_reg5=MIIReturn;
+
+	negociated=mii_reg5 & advertising;
+
+	if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 )
+		return 1;
+	else
+		return 0;
+
+}
+
+int
+ReadMII (int byMIIIndex, int ioaddr)
+{
+    int ReturnMII;
+    char byMIIAdrbak;
+    char byMIICRbak;
+    char byMIItemp;
+    unsigned long ct;
+
+    byMIIAdrbak = inb (byMIIAD);
+    byMIICRbak = inb (byMIICR);
+    outb (byMIICRbak & 0x7f, byMIICR);
+    MIIDelay ();
+
+    outb (byMIIIndex, byMIIAD);
+    MIIDelay ();
+
+    outb (inb (byMIICR) | 0x40, byMIICR);
+
+    byMIItemp = inb (byMIICR);
+    byMIItemp = byMIItemp & 0x40;
+
+    ct = currticks();
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
+    {
+	byMIItemp = inb (byMIICR);
+	byMIItemp = byMIItemp & 0x40;
+    }
+    MIIDelay ();
+
+    ReturnMII = inw (wMIIDATA);
+
+    outb (byMIIAdrbak, byMIIAD);
+    outb (byMIICRbak, byMIICR);
+    MIIDelay ();
+
+    return (ReturnMII);
+
+}
+
+void
+WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
+{
+    int ReadMIItmp;
+    int MIIMask;
+    char byMIIAdrbak;
+    char byMIICRbak;
+    char byMIItemp;
+    unsigned long ct;
+
+
+    byMIIAdrbak = inb (byMIIAD);
+
+    byMIICRbak = inb (byMIICR);
+    outb (byMIICRbak & 0x7f, byMIICR);
+    MIIDelay ();
+    outb (byMIISetByte, byMIIAD);
+    MIIDelay ();
+
+    outb (inb (byMIICR) | 0x40, byMIICR);
+
+    byMIItemp = inb (byMIICR);
+    byMIItemp = byMIItemp & 0x40;
+
+    ct = currticks();
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
+    {
+	byMIItemp = inb (byMIICR);
+	byMIItemp = byMIItemp & 0x40;
+    }
+    MIIDelay ();
+
+    ReadMIItmp = inw (wMIIDATA);
+    MIIMask = 0x0001;
+    MIIMask = MIIMask << byMIISetBit;
+
+
+    if (byMIIOP == 0)
+    {
+	MIIMask = ~MIIMask;
+	ReadMIItmp = ReadMIItmp & MIIMask;
+    }
+    else
+    {
+	ReadMIItmp = ReadMIItmp | MIIMask;
+
+    }
+    outw (ReadMIItmp, wMIIDATA);
+    MIIDelay ();
+
+    outb (inb (byMIICR) | 0x20, byMIICR);
+    byMIItemp = inb (byMIICR);
+    byMIItemp = byMIItemp & 0x20;
+
+    ct = currticks();
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
+    {
+	byMIItemp = inb (byMIICR);
+	byMIItemp = byMIItemp & 0x20;
+    }
+    MIIDelay ();
+
+    outb (byMIIAdrbak & 0x7f, byMIIAD);
+    outb (byMIICRbak, byMIICR);
+    MIIDelay ();
+
+}
+
+void
+MIIDelay (void)
+{
+    int i;
+    for (i = 0; i < 0x7fff; i++)
+    {
+        ( void ) inb (0x61);
+        ( void ) inb (0x61);
+        ( void ) inb (0x61);
+        ( void ) inb (0x61);
+    }
+}
+
+/* Offsets to the device registers. */
+enum register_offsets {
+        StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
+        IntrStatus=0x0C, IntrEnable=0x0E,
+        MulticastFilter0=0x10, MulticastFilter1=0x14,
+        RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
+        MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
+        MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
+        ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
+        RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
+        StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7,
+        PwrcsrClr=0xAC,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+        IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
+        IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
+        IntrPCIErr=0x0040,
+        IntrStatsMax=0x0080, IntrRxEarly=0x0100,
+        IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
+        IntrTxAborted=0x2000, IntrLinkChange=0x4000,
+        IntrRxWakeUp=0x8000,
+        IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
+        IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
+        IntrTxErrSummary=0x082218,
+};
+#define DEFAULT_INTR (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | \
+                   IntrRxDropped | IntrRxNoBuf) 
+
+/***************************************************************************
+ IRQ - PXE IRQ Handler
+***************************************************************************/
+void rhine_irq ( struct nic *nic, irq_action_t action ) {
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    /* Enable interrupts by setting the interrupt mask. */
+    unsigned int intr_status;
+
+    switch ( action ) {
+        case DISABLE :
+        case ENABLE :
+            intr_status = inw(nic->ioaddr + IntrStatus);
+            /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
+
+            /* added comment by guard */
+            /* For supporting VT6107, please use revision id to recognize different chips in driver */
+            // if (tp->chip_id == 0x3065)
+            if( tp->chip_revision < 0x80 && tp->chip_revision >=0x40 )
+                intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
+                intr_status = (intr_status & ~DEFAULT_INTR);
+                if ( action == ENABLE ) 
+                    intr_status = intr_status | DEFAULT_INTR;
+                    outw(intr_status, nic->ioaddr + IntrEnable);
+                break;
+        case FORCE :
+            outw(0x0010, nic->ioaddr + 0x84);
+           break;
+        }
+}
+
+static struct nic_operations rhine_operations;
+
+static int
+rhine_probe ( struct nic *nic, struct pci_device *pci ) {
+
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+
+    if (!pci->ioaddr)
+	return 0;
+
+    rhine_probe1 (nic, pci, pci->ioaddr, pci->device, -1);
+
+    adjust_pci_device ( pci );
+
+    rhine_reset (nic);
+
+    nic->nic_op	= &rhine_operations;
+
+    nic->irqno	  = pci->irq;
+    nic->ioaddr   = tp->ioaddr;
+
+    return 1;
+}
+
+static void set_rx_mode(struct nic *nic __unused) {
+    	struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+	unsigned char rx_mode;
+    	int ioaddr = tp->ioaddr;
+
+	/* ! IFF_PROMISC */
+	outl(0xffffffff, byMAR0);
+	outl(0xffffffff, byMAR4);
+	rx_mode = 0x0C;
+
+	outb(0x60 /* thresh */ | rx_mode, byRCR );
+}
+
+static void
+rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id, int options)
+{
+    struct rhine_private *tp;
+    static int did_version = 0;	/* Already printed version info. */
+    unsigned int i, ww;
+    unsigned int timeout;
+    int FDXFlag;
+    int byMIIvalue, LineSpeed, MIICRbak;
+    uint8_t revision_id;    
+    unsigned char mode3_reg;
+
+    if (rhine_debug > 0 && did_version++ == 0)
+	printf ("%s",version);
+
+    // get revision id.
+    pci_read_config_byte(pci, PCI_REVISION, &revision_id);
+
+    /* D-Link provided reset code (with comment additions) */
+    if (revision_id >= 0x40) {
+	unsigned char byOrgValue;
+	
+	if(rhine_debug > 0)
+		printf("Enabling Sticky Bit Workaround for Chip_id: 0x%hX\n"
+				, chip_id);
+	/* clear sticky bit before reset & read ethernet address */
+	byOrgValue = inb(bySTICKHW);
+	byOrgValue = byOrgValue & 0xFC;
+	outb(byOrgValue, bySTICKHW);
+
+	/* (bits written are cleared?) */
+	/* disable force PME-enable */
+	outb(0x80, byWOLcgClr);
+	/* disable power-event config bit */
+	outb(0xFF, byWOLcrClr);
+	/* clear power status (undocumented in vt6102 docs?) */
+	outb(0xFF, byPwrcsrClr);
+	
+    }
+
+    /* Reset the chip to erase previous misconfiguration. */
+    outw(CR_SFRST, byCR0);
+    // if vt3043 delay after reset
+    if (revision_id <0x40) {
+       udelay(10000);
+    }
+    // polling till software reset complete
+    // W_MAX_TIMEOUT is the timeout period
+    for(ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+        if ((inw(byCR0) & CR_SFRST) == 0)
+		break;
+        }
+
+    // issue AUTOLoad in EECSR to reload eeprom
+    outb(0x20, byEECSR );
+
+    // if vt3065 delay after reset
+    if (revision_id >=0x40) {
+	// delay 8ms to let MAC stable
+	mdelay(8);
+        /*
+         * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA
+         * turned on.  it makes MAC receive magic packet
+         * automatically. So, we turn it off. (D-Link)
+         */
+         outb(inb(byCFGA) & 0xFE, byCFGA);
+    }
+
+    /* turn on bit2 in PCI configuration register 0x53 , only for 3065*/
+    if (revision_id >= 0x40) {
+        pci_read_config_byte(pci, PCI_REG_MODE3, &mode3_reg);
+        pci_write_config_byte(pci, PCI_REG_MODE3, mode3_reg|MODE3_MIION);
+    }
+
+
+    /* back off algorithm ,disable the right-most 4-bit off CFGD*/
+    outb(inb(byCFGD) & (~(CFGD_RANDOM | CFGD_CFDX | CFGD_CEREN | CFGD_CETEN)), byCFGD);
+
+    /* reload eeprom */
+    reload_eeprom(ioaddr);
+
+    /* Perhaps this should be read from the EEPROM? */
+    for (i = 0; i < ETH_ALEN; i++)
+	nic->node_addr[i] = inb (byPAR0 + i);
+
+    DBG ( "IO address %#hX Ethernet Address: %s\n", ioaddr, eth_ntoa ( nic->node_addr ) );
+
+    /* restart MII auto-negotiation */
+    WriteMII (0, 9, 1, ioaddr);
+    printf ("Analyzing Media type,this may take several seconds... ");
+    for (i = 0; i < 5; i++)
+    {
+	/* need to wait 1 millisecond - we will round it up to 50-100ms */
+	timeout = currticks() + 2;
+	for (timeout = currticks() + 2; currticks() < timeout;)
+	    /* nothing */;
+	if (ReadMII (1, ioaddr) & 0x0020)
+	    break;
+    }
+    printf ("OK.\n");
+
+#if 0
+	/* JJM : for Debug */
+	printf("MII : Address %hhX ",inb(ioaddr+0x6c));
+	{
+	 unsigned char st1,st2,adv1,adv2,l1,l2;
+	
+	 st1=ReadMII(1,ioaddr)>>8;
+	 st2=ReadMII(1,ioaddr)&0xFF;
+	 adv1=ReadMII(4,ioaddr)>>8;
+	 adv2=ReadMII(4,ioaddr)&0xFF;
+	 l1=ReadMII(5,ioaddr)>>8;
+	 l2=ReadMII(5,ioaddr)&0xFF;
+	 printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2);
+	}
+#endif
+
+    
+    /* query MII to know LineSpeed,duplex mode */
+    byMIIvalue = inb (ioaddr + 0x6d);
+    LineSpeed = byMIIvalue & MIISR_SPEED;
+    if (LineSpeed != 0)						//JJM
+    {
+	printf ("Linespeed=10Mbs");
+    }
+    else
+    {
+	printf ("Linespeed=100Mbs");
+    }
+	
+    FDXFlag = QueryAuto (ioaddr);
+    if (FDXFlag == 1)
+    {
+	printf (" Fullduplex\n");
+	outw (CR_FDX, byCR0);
+    }
+    else
+    {
+	printf (" Halfduplex\n");
+    }
+
+
+    /* set MII 10 FULL ON, only apply in vt3043 */
+    if(chip_id == 0x3043)
+        WriteMII (0x17, 1, 1, ioaddr);
+
+    /* turn on MII link change */
+    MIICRbak = inb (byMIICR);
+    outb (MIICRbak & 0x7F, byMIICR);
+    MIIDelay ();
+    outb (0x41, byMIIAD);
+    MIIDelay ();
+
+    /* while((inb(byMIIAD)&0x20)==0) ; */
+    outb (MIICRbak | 0x80, byMIICR);
+
+    nic->priv_data = &rhine;
+    tp = &rhine;
+    tp->chip_id = chip_id;
+    tp->ioaddr = ioaddr;
+    tp->phys[0] = -1;
+    tp->chip_revision = revision_id;
+
+    /* The lower four bits are the media type. */
+    if (options > 0)
+    {
+	tp->full_duplex = (options & 16) ? 1 : 0;
+	tp->default_port = options & 15;
+	if (tp->default_port)
+	    tp->medialock = 1;
+    }
+    return;
+}
+
+static void 
+rhine_disable ( struct nic *nic ) {
+
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    int ioaddr = tp->ioaddr;
+
+    rhine_reset(nic);
+
+    printf ("rhine disable\n");
+    /* Switch to loopback mode to avoid hardware races. */
+    outb(0x60 | 0x01, byTCR);
+    /* Stop the chip's Tx and Rx processes. */
+    outw(CR_STOP, byCR0);
+}
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+***************************************************************************/
+static void
+rhine_reset (struct nic *nic)
+{
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    int ioaddr = tp->ioaddr;
+    int i, j;
+    int FDXFlag, CRbak;
+    void *rx_ring_tmp;
+    void *tx_ring_tmp;
+    void *rx_bufs_tmp;
+    void *tx_bufs_tmp;
+    unsigned long rx_ring_tmp1;
+    unsigned long tx_ring_tmp1;
+    unsigned long rx_bufs_tmp1;
+    unsigned long tx_bufs_tmp1;
+
+    /* printf ("rhine_reset\n"); */
+    /* Soft reset the chip. */
+    /*outb(CmdReset, ioaddr + ChipCmd); */
+
+    tx_bufs_tmp = rhine_buffers.txbuf;
+    tx_ring_tmp = rhine_buffers.txdesc;
+    rx_bufs_tmp = rhine_buffers.rxbuf;
+    rx_ring_tmp = rhine_buffers.rxdesc;
+
+    /* tune RD TD 32 byte alignment */
+    rx_ring_tmp1 = virt_to_bus ( rx_ring_tmp );
+    j = (rx_ring_tmp1 + 32) & (~0x1f);
+    /* printf ("txring[%d]", j); */
+    tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j);
+
+    tx_ring_tmp1 = virt_to_bus ( tx_ring_tmp );
+    j = (tx_ring_tmp1 + 32) & (~0x1f);
+    tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j);
+    /* printf ("rxring[%X]", j); */
+
+
+    tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp );
+    j = (int) (tx_bufs_tmp1 + 32) & (~0x1f);
+    tx_bufs_tmp = bus_to_virt (j);
+    /* printf ("txb[%X]", j); */
+
+    rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp );
+    j = (int) (rx_bufs_tmp1 + 32) & (~0x1f);
+    rx_bufs_tmp = bus_to_virt (j);
+    /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */
+
+    for (i = 0; i < RX_RING_SIZE; i++)
+    {
+	tp->rx_buffs[i] = (char *) rx_bufs_tmp;
+	/* printf("r[%X]",tp->rx_buffs[i]); */
+	rx_bufs_tmp += 1536;
+    }
+
+    for (i = 0; i < TX_RING_SIZE; i++)
+    {
+	tp->tx_buffs[i] = (char *) tx_bufs_tmp;
+	/* printf("t[%X]",tp->tx_buffs[i]);  */
+	tx_bufs_tmp += 1536;
+    }
+
+    /* software reset */
+    outb (CR1_SFRST, byCR1);
+    MIIDelay ();
+
+    /* printf ("init ring"); */
+    rhine_init_ring (nic);
+    /*write TD RD Descriptor to MAC */
+    outl (virt_to_bus (tp->rx_ring), dwCurrentRxDescAddr);
+    outl (virt_to_bus (tp->tx_ring), dwCurrentTxDescAddr);
+
+    /* Setup Multicast */	
+    set_rx_mode(nic);
+
+    /* set TCR RCR threshold to store and forward*/
+    outb (0x3e, byBCR0);
+    outb (0x38, byBCR1);
+    outb (0x2c, byRCR);
+    outb (0x60, byTCR);
+    /* Set Fulldupex */
+    FDXFlag = QueryAuto (ioaddr);
+    if (FDXFlag == 1)
+    {
+	outb (CFGD_CFDX, byCFGD);
+	outw (CR_FDX, byCR0);
+    }
+
+    /* KICK NIC to WORK */
+    CRbak = inw (byCR0);
+    CRbak = CRbak & 0xFFFB;	/* not CR_STOP */
+    outw ((CRbak | CR_STRT | CR_TXON | CR_RXON | CR_DPOLL), byCR0);
+
+    /* disable all known interrupt */
+    outw (0, byIMR0);
+}
+/* Beware of PCI posted writes */
+#define IOSYNC  do { inb(nic->ioaddr + StationAddr); } while (0)
+
+static int
+rhine_poll (struct nic *nic, int retreive)
+{
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    int rxstatus, good = 0;;
+
+    if (tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit == 0)
+    {
+        unsigned int intr_status;
+        /* There is a packet ready */
+        if(!retreive)
+            return 1;
+
+        intr_status = inw(nic->ioaddr + IntrStatus);
+        /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
+#if 0
+	if (tp->chip_id == 0x3065)
+	  intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
+#endif
+        /* Acknowledge all of the current interrupt sources ASAP. */
+        if (intr_status & IntrTxDescRace)
+           outb(0x08, nic->ioaddr + IntrStatus2);
+        outw(intr_status & 0xffff, nic->ioaddr + IntrStatus);
+	IOSYNC;
+
+	rxstatus = tp->rx_ring[tp->cur_rx].rx_status.lw;
+	if ((rxstatus & 0x0300) != 0x0300)
+	{
+	    printf("rhine_poll: bad status\n");
+	}
+	else if (rxstatus & (RSR_ABNORMAL))
+	{
+	    printf ("rxerr[%X]\n", rxstatus);
+	}
+	else
+	    good = 1;
+
+	if (good)
+	{
+	    nic->packetlen = tp->rx_ring[tp->cur_rx].rx_status.bits.frame_length;
+	    memcpy (nic->packet, tp->rx_buffs[tp->cur_rx], nic->packetlen);
+	    /* printf ("Packet RXed\n"); */
+	}
+	tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit = 1;
+	tp->cur_rx++;
+	tp->cur_rx = tp->cur_rx % RX_RING_SIZE;
+    }
+        /* Acknowledge all of the current interrupt sources ASAP. */
+        outw(DEFAULT_INTR & ~IntrRxDone, nic->ioaddr + IntrStatus);
+
+        IOSYNC;
+
+    return good;
+}
+
+static void
+rhine_transmit (struct nic *nic,
+		const char *d, unsigned int t, unsigned int s, const char *p)
+{
+    struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
+    int ioaddr = tp->ioaddr;
+    int entry;
+    unsigned char CR1bak;
+    unsigned char CR0bak;
+    unsigned int nstype;
+    unsigned long ct;
+
+
+    /*printf ("rhine_transmit\n"); */
+    /* setup ethernet header */
+
+
+    /* Calculate the next Tx descriptor entry. */
+    entry = tp->cur_tx % TX_RING_SIZE;
+
+    memcpy (tp->tx_buffs[entry], d, ETH_ALEN);	/* dst */
+    memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN);	/* src */
+    
+    nstype=htons(t);
+    memcpy(tp->tx_buffs[entry] + 2 * ETH_ALEN, (char*)&nstype, 2);
+
+    memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s);
+    s += ETH_HLEN;
+    while (s < ETH_ZLEN)
+	*((char *) tp->tx_buffs[entry] + (s++)) = 0;
+
+    tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = s;
+
+    tp->tx_ring[entry].tx_status.bits.own_bit = 1;
+
+
+    CR1bak = inb (byCR1);
+
+    CR1bak = CR1bak | CR1_TDMD1;
+    /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */
+    /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */
+    /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */
+    /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */
+    /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */
+    /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */
+    /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */
+    /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */
+
+    outb (CR1bak, byCR1);
+    do
+    {
+	ct = currticks();
+        /* Wait until transmit is finished or timeout*/
+        while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) &&
+		ct + 10*1000 < currticks())
+        ;
+
+        if(tp->tx_ring[entry].tx_status.bits.terr == 0)
+            break;
+
+        if(tp->tx_ring[entry].tx_status.bits.abt == 1)
+        {
+            // turn on TX
+            CR0bak = inb(byCR0);
+            CR0bak = CR0bak|CR_TXON;
+            outb(CR0bak,byCR0);
+        }
+    }while(0);
+    tp->cur_tx++;
+
+    /*outw(IMRShadow,byIMR0); */
+    /*dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); */
+    /*tp->tx_skbuff[entry] = 0; */
+}
+
+static struct nic_operations rhine_operations = {
+	.connect	= dummy_connect,
+	.poll		= rhine_poll,
+	.transmit	= rhine_transmit,
+	.irq		= rhine_irq,
+
+};
+
+static struct pci_device_id rhine_nics[] = {
+PCI_ROM(0x1106, 0x3065, "dlink-530tx",     "VIA 6102", 0),
+PCI_ROM(0x1106, 0x3106, "via-rhine-6105",  "VIA 6105", 0),
+PCI_ROM(0x1106, 0x3043, "dlink-530tx-old", "VIA 3043", 0),		/* Rhine-I 86c100a */
+PCI_ROM(0x1106, 0x3053, "via6105m",        "VIA 6105M", 0),
+PCI_ROM(0x1106, 0x6100, "via-rhine-old",   "VIA 86C100A", 0),	/* Rhine-II */
+};
+
+PCI_DRIVER ( rhine_driver, rhine_nics, PCI_NO_CLASS );
+
+DRIVER ( "VIA 86C100", nic_driver, pci_driver, rhine_driver,
+	 rhine_probe, rhine_disable );
+
+/* EOF via-rhine.c */
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.c
new file mode 100644
index 0000000..fa90f9b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.c
@@ -0,0 +1,1926 @@
+/**************************************************************************
+*    via-velocity.c: Etherboot device driver for the VIA 6120 Gigabit
+*    Changes for Etherboot port:
+*       Copyright (c) 2006 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    This driver is based on:
+*         via-velocity.c: VIA Velocity VT6120, VT6122 Ethernet driver 
+*             The changes are (c) Copyright 2004, Red Hat Inc. 
+*                <alan at redhat.com>
+*             Additional fixes and clean up: Francois Romieu
+*
+*     Original code:
+*         Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+*         All rights reserved.
+*             Author: Chuang Liang-Shing, AJ Jiang
+* 
+*    Linux Driver Version 2.6.15.4
+* 
+*    REVISION HISTORY:
+*    ================
+*
+*    v1.0	03-06-2006	timlegge	Initial port of Linux driver
+*    
+*    Indent Options: indent -kr -i8
+*************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+#include "via-velocity.h"
+
+typedef int pci_power_t;
+
+#define PCI_D0  ((int) 0)
+#define PCI_D1  ((int) 1)
+#define PCI_D2  ((int) 2)
+#define PCI_D3hot       ((int) 3)
+#define PCI_D3cold      ((int) 4)
+#define PCI_POWER_ERROR ((int) -1)
+
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+//FIXME: Move to pci.c
+int pci_set_power_state(struct pci_device *dev, int state);
+
+/* FIXME: Move BASE to the private structure */
+static u32 BASE;
+
+/* NIC specific static variables go here */
+#define VELOCITY_PARAM(N,D) \
+        static const int N[MAX_UNITS]=OPTION_DEFAULT;
+/*        MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\
+        MODULE_PARM_DESC(N, D); */
+
+VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
+VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+
+#define VLAN_ID_MIN     0
+#define VLAN_ID_MAX     4095
+#define VLAN_ID_DEF     0
+/* VID_setting[] is used for setting the VID of NIC.
+   0: default VID.
+   1-4094: other VIDs.
+*/
+VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
+
+#define RX_THRESH_MIN   0
+#define RX_THRESH_MAX   3
+#define RX_THRESH_DEF   0
+/* rx_thresh[] is used for controlling the receive fifo threshold.
+   0: indicate the rxfifo threshold is 128 bytes.
+   1: indicate the rxfifo threshold is 512 bytes.
+   2: indicate the rxfifo threshold is 1024 bytes.
+   3: indicate the rxfifo threshold is store & forward.
+*/
+VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
+
+#define DMA_LENGTH_MIN  0
+#define DMA_LENGTH_MAX  7
+#define DMA_LENGTH_DEF  0
+
+/* DMA_length[] is used for controlling the DMA length
+   0: 8 DWORDs
+   1: 16 DWORDs
+   2: 32 DWORDs
+   3: 64 DWORDs
+   4: 128 DWORDs
+   5: 256 DWORDs
+   6: SF(flush till emply)
+   7: SF(flush till emply)
+*/
+VELOCITY_PARAM(DMA_length, "DMA length");
+
+#define TAGGING_DEF     0
+/* enable_tagging[] is used for enabling 802.1Q VID tagging.
+   0: disable VID seeting(default).
+   1: enable VID setting.
+*/
+VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
+
+#define IP_ALIG_DEF     0
+/* IP_byte_align[] is used for IP header DWORD byte aligned
+   0: indicate the IP header won't be DWORD byte aligned.(Default) .
+   1: indicate the IP header will be DWORD byte aligned.
+      In some enviroment, the IP header should be DWORD byte aligned,
+      or the packet will be droped when we receive it. (eg: IPVS)
+*/
+VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
+
+#define TX_CSUM_DEF     1
+/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
+   (We only support RX checksum offload now)
+   0: disable csum_offload[checksum offload
+   1: enable checksum offload. (Default)
+*/
+VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
+
+#define FLOW_CNTL_DEF   1
+#define FLOW_CNTL_MIN   1
+#define FLOW_CNTL_MAX   5
+
+/* flow_control[] is used for setting the flow control ability of NIC.
+   1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
+   2: enable TX flow control.
+   3: enable RX flow control.
+   4: enable RX/TX flow control.
+   5: disable
+*/
+VELOCITY_PARAM(flow_control, "Enable flow control ability");
+
+#define MED_LNK_DEF 0
+#define MED_LNK_MIN 0
+#define MED_LNK_MAX 4
+/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
+   0: indicate autonegotiation for both speed and duplex mode
+   1: indicate 100Mbps half duplex mode
+   2: indicate 100Mbps full duplex mode
+   3: indicate 10Mbps half duplex mode
+   4: indicate 10Mbps full duplex mode
+
+   Note:
+        if EEPROM have been set to the force mode, this option is ignored
+            by driver.
+*/
+VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
+
+#define VAL_PKT_LEN_DEF     0
+/* ValPktLen[] is used for setting the checksum offload ability of NIC.
+   0: Receive frame with invalid layer 2 length (Default)
+   1: Drop frame with invalid layer 2 length
+*/
+VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
+
+#define WOL_OPT_DEF     0
+#define WOL_OPT_MIN     0
+#define WOL_OPT_MAX     7
+/* wol_opts[] is used for controlling wake on lan behavior.
+   0: Wake up if recevied a magic packet. (Default)
+   1: Wake up if link status is on/off.
+   2: Wake up if recevied an arp packet.
+   4: Wake up if recevied any unicast packet.
+   Those value can be sumed up to support more than one option.
+*/
+VELOCITY_PARAM(wol_opts, "Wake On Lan options");
+
+#define INT_WORKS_DEF   20
+#define INT_WORKS_MIN   10
+#define INT_WORKS_MAX   64
+
+VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
+
+/* The descriptors for this card are required to be aligned on
+64 byte boundaries.  As the align attribute does not guarantee alignment
+greater than the alignment of the start address (which for Etherboot
+is 16 bytes of alignment) it requires some extra steps.  Add 64 to the 
+size of the array and the init_ring adjusts the alignment */
+
+/* Define the TX Descriptor */
+static u8 tx_ring[TX_DESC_DEF * sizeof(struct tx_desc) + 64];
+
+/* Create a static buffer of size PKT_BUF_SZ for each TX Descriptor.  
+All descriptors point to a part of this buffer */
+static u8 txb[(TX_DESC_DEF * PKT_BUF_SZ) + 64];
+
+/* Define the RX Descriptor */
+static u8 rx_ring[RX_DESC_DEF * sizeof(struct rx_desc) + 64];
+
+/* Create a static buffer of size PKT_BUF_SZ for each RX Descriptor
+   All descriptors point to a part of this buffer */
+static u8 rxb[(RX_DESC_DEF * PKT_BUF_SZ) + 64];
+
+static void velocity_init_info(struct pci_device *pdev,
+			       struct velocity_info *vptr,
+			       struct velocity_info_tbl *info);
+static int velocity_get_pci_info(struct velocity_info *,
+				 struct pci_device *pdev);
+static int velocity_open(struct nic *nic, struct pci_device *pci);
+
+static int velocity_soft_reset(struct velocity_info *vptr);
+static void velocity_init_cam_filter(struct velocity_info *vptr);
+static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
+static void velocity_print_link_status(struct velocity_info *vptr);
+static void safe_disable_mii_autopoll(struct mac_regs *regs);
+static void enable_flow_control_ability(struct velocity_info *vptr);
+static void enable_mii_autopoll(struct mac_regs *regs);
+static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
+static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
+static u32 mii_check_media_mode(struct mac_regs *regs);
+static u32 check_connection_type(struct mac_regs *regs);
+static int velocity_set_media_mode(struct velocity_info *vptr,
+				   u32 mii_status);
+
+
+/*
+ *	Internal board variants. At the moment we have only one
+ */
+
+static struct velocity_info_tbl chip_info_table[] = {
+	{CHIP_TYPE_VT6110,
+	 "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1,
+	 0x00FFFFFFUL},
+	{0, NULL, 0, 0, 0}
+};
+
+/**
+ *	velocity_set_int_opt	-	parser for integer options
+ *	@opt: pointer to option value
+ *	@val: value the user requested (or -1 for default)
+ *	@min: lowest value allowed
+ *	@max: highest value allowed
+ *	@def: default value
+ *	@name: property name
+ *	@dev: device name
+ *
+ *	Set an integer property in the module options. This function does
+ *	all the verification and checking as well as reporting so that
+ *	we don't duplicate code for each option.
+ */
+
+static void velocity_set_int_opt(int *opt, int val, int min, int max,
+				 int def, char *name, const char *devname)
+{
+	if (val == -1) {
+		printf("%s: set value of parameter %s to %d\n",
+		       devname, name, def);
+		*opt = def;
+	} else if (val < min || val > max) {
+		printf
+		    ("%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n",
+		     devname, name, min, max);
+		*opt = def;
+	} else {
+		printf("%s: set value of parameter %s to %d\n",
+		       devname, name, val);
+		*opt = val;
+	}
+}
+
+/**
+ *	velocity_set_bool_opt	-	parser for boolean options
+ *	@opt: pointer to option value
+ *	@val: value the user requested (or -1 for default)
+ *	@def: default value (yes/no)
+ *	@flag: numeric value to set for true.
+ *	@name: property name
+ *	@dev: device name
+ *
+ *	Set a boolean property in the module options. This function does
+ *	all the verification and checking as well as reporting so that
+ *	we don't duplicate code for each option.
+ */
+
+static void velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag,
+				  char *name, const char *devname)
+{
+	(*opt) &= (~flag);
+	if (val == -1) {
+		printf("%s: set parameter %s to %s\n",
+		       devname, name, def ? "TRUE" : "FALSE");
+		*opt |= (def ? flag : 0);
+	} else if (val < 0 || val > 1) {
+		printf
+		    ("%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
+		     devname, name);
+		*opt |= (def ? flag : 0);
+	} else {
+		printf("%s: set parameter %s to %s\n",
+		       devname, name, val ? "TRUE" : "FALSE");
+		*opt |= (val ? flag : 0);
+	}
+}
+
+/**
+ *	velocity_get_options	-	set options on device
+ *	@opts: option structure for the device
+ *	@index: index of option to use in module options array
+ *	@devname: device name
+ *
+ *	Turn the module and command options into a single structure
+ *	for the current device
+ */
+
+static void velocity_get_options(struct velocity_opt *opts, int index,
+				 const char *devname)
+{
+
+	/* FIXME Do the options need to be configurable */
+	velocity_set_int_opt(&opts->rx_thresh, -1, RX_THRESH_MIN,
+			     RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh",
+			     devname);
+	velocity_set_int_opt(&opts->DMA_length, DMA_length[index],
+			     DMA_LENGTH_MIN, DMA_LENGTH_MAX,
+			     DMA_LENGTH_DEF, "DMA_length", devname);
+	velocity_set_int_opt(&opts->numrx, RxDescriptors[index],
+			     RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF,
+			     "RxDescriptors", devname);
+	velocity_set_int_opt(&opts->numtx, TxDescriptors[index],
+			     TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF,
+			     "TxDescriptors", devname);
+	velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN,
+			     VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting",
+			     devname);
+	velocity_set_bool_opt(&opts->flags, enable_tagging[index],
+			      TAGGING_DEF, VELOCITY_FLAGS_TAGGING,
+			      "enable_tagging", devname);
+	velocity_set_bool_opt(&opts->flags, txcsum_offload[index],
+			      TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM,
+			      "txcsum_offload", devname);
+	velocity_set_int_opt(&opts->flow_cntl, flow_control[index],
+			     FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF,
+			     "flow_control", devname);
+	velocity_set_bool_opt(&opts->flags, IP_byte_align[index],
+			      IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN,
+			      "IP_byte_align", devname);
+	velocity_set_bool_opt(&opts->flags, ValPktLen[index],
+			      VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN,
+			      "ValPktLen", devname);
+	velocity_set_int_opt((void *) &opts->spd_dpx, speed_duplex[index],
+			     MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF,
+			     "Media link mode", devname);
+	velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index],
+			     WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF,
+			     "Wake On Lan options", devname);
+	velocity_set_int_opt((int *) &opts->int_works, int_works[index],
+			     INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF,
+			     "Interrupt service works", devname);
+	opts->numrx = (opts->numrx & ~3);
+}
+
+/**
+ *	velocity_init_cam_filter	-	initialise CAM
+ *	@vptr: velocity to program
+ *
+ *	Initialize the content addressable memory used for filters. Load
+ *	appropriately according to the presence of VLAN
+ */
+
+static void velocity_init_cam_filter(struct velocity_info *vptr)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+
+	/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
+	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
+	WORD_REG_BITS_ON(MCFG_VIDFR, &regs->MCFG);
+
+	/* Disable all CAMs */
+	memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
+	memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
+	mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+	mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+	/* Enable first VCAM */
+	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+		/* If Tagging option is enabled and VLAN ID is not zero, then
+		   turn on MCFG_RTGOPT also */
+		if (vptr->options.vid != 0)
+			WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+		mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid),
+			    VELOCITY_VLAN_ID_CAM);
+		vptr->vCAMmask[0] |= 1;
+		mac_set_cam_mask(regs, vptr->vCAMmask,
+				 VELOCITY_VLAN_ID_CAM);
+	} else {
+		u16 temp = 0;
+		mac_set_cam(regs, 0, (u8 *) & temp, VELOCITY_VLAN_ID_CAM);
+		temp = 1;
+		mac_set_cam_mask(regs, (u8 *) & temp,
+				 VELOCITY_VLAN_ID_CAM);
+	}
+}
+
+static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+	int avail, dirty, unusable;
+
+	/*
+	 * RD number must be equal to 4X per hardware spec
+	 * (programming guide rev 1.20, p.13)
+	 */
+	if (vptr->rd_filled < 4)
+		return;
+
+	wmb();
+
+	unusable = vptr->rd_filled & 0x0003;
+	dirty = vptr->rd_dirty - unusable;
+	for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
+		dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+//              printf("return dirty: %d\n", dirty);
+		vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
+	}
+
+	writew(vptr->rd_filled & 0xfffc, &regs->RBRDU);
+	vptr->rd_filled = unusable;
+}
+
+static int velocity_rx_refill(struct velocity_info *vptr)
+{
+	int dirty = vptr->rd_dirty, done = 0, ret = 0;
+
+//      printf("rx_refill - rd_curr = %d, dirty = %d\n", vptr->rd_curr, dirty);
+	do {
+		struct rx_desc *rd = vptr->rd_ring + dirty;
+
+		/* Fine for an all zero Rx desc at init time as well */
+		if (rd->rdesc0.owner == OWNED_BY_NIC)
+			break;
+//              printf("rx_refill - after owner %d\n", dirty);
+
+		rd->inten = 1;
+		rd->pa_high = 0;
+		rd->rdesc0.len = cpu_to_le32(vptr->rx_buf_sz);;
+
+		done++;
+		dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+	} while (dirty != vptr->rd_curr);
+
+	if (done) {
+//              printf("\nGive Back Desc\n");
+		vptr->rd_dirty = dirty;
+		vptr->rd_filled += done;
+		velocity_give_many_rx_descs(vptr);
+	}
+
+	return ret;
+}
+
+extern void hex_dump(const char *data, const unsigned int len);
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int velocity_poll(struct nic *nic, int retrieve)
+{
+	/* Work out whether or not there's an ethernet packet ready to
+	 * read.  Return 0 if not.
+	 */
+
+	int rd_curr = vptr->rd_curr % RX_DESC_DEF;
+	struct rx_desc *rd = &(vptr->rd_ring[rd_curr]);
+
+	if (rd->rdesc0.owner == OWNED_BY_NIC)
+		return 0;
+	rmb();
+
+	if ( ! retrieve ) return 1;
+
+	/*
+	 *      Don't drop CE or RL error frame although RXOK is off
+	 */
+	if ((rd->rdesc0.RSR & RSR_RXOK)
+	    || (!(rd->rdesc0.RSR & RSR_RXOK)
+		&& (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+
+		nic->packetlen = rd->rdesc0.len;
+		// ptr->rxb + (rd_curr * PKT_BUF_SZ)
+		memcpy(nic->packet, bus_to_virt(rd->pa_low),
+		       nic->packetlen - 4);
+
+		vptr->rd_curr++;
+		vptr->rd_curr = vptr->rd_curr % RX_DESC_DEF;
+		velocity_rx_refill(vptr);
+		return 1;	/* Remove this line once this method is implemented */
+	}
+	return 0;
+}
+
+#define TX_TIMEOUT  (1000);
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void velocity_transmit(struct nic *nic, const char *dest,	/* Destination */
+			      unsigned int type,	/* Type */
+			      unsigned int size,	/* size */
+			      const char *packet)
+{				/* Packet */
+	u16 nstype;
+	u32 to;
+	u8 *ptxb;
+	unsigned int pktlen;
+	struct tx_desc *td_ptr;
+
+	int entry = vptr->td_curr % TX_DESC_DEF;
+	td_ptr = &(vptr->td_rings[entry]);
+
+	/* point to the current txb incase multiple tx_rings are used */
+	ptxb = vptr->txb + (entry * PKT_BUF_SZ);
+	memcpy(ptxb, dest, ETH_ALEN);	/* Destination */
+	memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);	/* Source */
+	nstype = htons((u16) type);	/* Type */
+	memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);	/* Type */
+	memcpy(ptxb + ETH_HLEN, packet, size);
+
+	td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
+	td_ptr->tdesc1.TCR = TCR0_TIC;
+	td_ptr->td_buf[0].queue = 0;
+
+	size += ETH_HLEN;
+	while (size < ETH_ZLEN)	/* pad to min length */
+		ptxb[size++] = '\0';
+
+	if (size < ETH_ZLEN) {
+//              printf("Padd that packet\n");
+		pktlen = ETH_ZLEN;
+//                memcpy(ptxb, skb->data, skb->len);
+		memset(ptxb + size, 0, ETH_ZLEN - size);
+
+		vptr->td_rings[entry].tdesc0.pktsize = pktlen;
+		vptr->td_rings[entry].td_buf[0].pa_low = virt_to_bus(ptxb);
+		vptr->td_rings[entry].td_buf[0].pa_high &=
+		    cpu_to_le32(0xffff0000UL);
+		vptr->td_rings[entry].td_buf[0].bufsize =
+		    vptr->td_rings[entry].tdesc0.pktsize;
+		vptr->td_rings[entry].tdesc1.CMDZ = 2;
+	} else {
+//              printf("Correct size packet\n");
+		td_ptr->tdesc0.pktsize = size;
+		td_ptr->td_buf[0].pa_low = virt_to_bus(ptxb);
+		td_ptr->td_buf[0].pa_high = 0;
+		td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+//                tdinfo->nskb_dma = 1;
+		td_ptr->tdesc1.CMDZ = 2;
+	}
+
+	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+		td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+		td_ptr->tdesc1.pqinf.priority = 0;
+		td_ptr->tdesc1.pqinf.CFI = 0;
+		td_ptr->tdesc1.TCR |= TCR0_VETAG;
+	}
+
+	vptr->td_curr = (entry + 1);
+
+	{
+
+		int prev = entry - 1;
+
+		if (prev < 0)
+			prev = TX_DESC_DEF - 1;
+		td_ptr->tdesc0.owner |= OWNED_BY_NIC;
+		td_ptr = &(vptr->td_rings[prev]);
+		td_ptr->td_buf[0].queue = 1;
+		mac_tx_queue_wake(vptr->mac_regs, 0);
+
+	}
+
+	to = currticks() + TX_TIMEOUT;
+	while ((td_ptr->tdesc0.owner & OWNED_BY_NIC) && (currticks() < to));	/* wait */
+
+	if (currticks() >= to) {
+		printf("TX Time Out");
+	}
+
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void velocity_disable(struct nic *nic __unused)
+{
+	/* put the card in its initial state */
+	/* This function serves 3 purposes.
+	 * This disables DMA and interrupts so we don't receive
+	 *  unexpected packets or interrupts from the card after
+	 *  etherboot has finished. 
+	 * This frees resources so etherboot may use
+	 *  this driver on another interface
+	 * This allows etherboot to reinitialize the interface
+	 *  if something is something goes wrong.
+	 */
+	struct mac_regs *regs = vptr->mac_regs;
+	mac_disable_int(regs);
+	writel(CR0_STOP, &regs->CR0Set);
+	writew(0xFFFF, &regs->TDCSRClr);
+	writeb(0xFF, &regs->RDCSRClr);
+	safe_disable_mii_autopoll(regs);
+	mac_clear_isr(regs);
+
+	/* Power down the chip */
+//      pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+	vptr->flags &= (~VELOCITY_FLAGS_OPENED);
+}
+
+/**************************************************************************
+IRQ - handle interrupts
+***************************************************************************/
+static void velocity_irq(struct nic *nic __unused, irq_action_t action)
+{
+	/* This routine is somewhat optional.  Etherboot itself
+	 * doesn't use interrupts, but they are required under some
+	 * circumstances when we're acting as a PXE stack.
+	 *
+	 * If you don't implement this routine, the only effect will
+	 * be that your driver cannot be used via Etherboot's UNDI
+	 * API.  This won't affect programs that use only the UDP
+	 * portion of the PXE API, such as pxelinux.
+	 */
+
+	switch (action) {
+	case DISABLE:
+	case ENABLE:
+		/* Set receive interrupt enabled/disabled state */
+		/*
+		   outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled,
+		   nic->ioaddr + IntrMaskRegister );
+		 */
+		break;
+	case FORCE:
+		/* Force NIC to generate a receive interrupt */
+		/*
+		   outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister );
+		 */
+		break;
+	}
+}
+
+static struct nic_operations velocity_operations = {
+	.connect	= dummy_connect,
+	.poll		= velocity_poll,
+	.transmit	= velocity_transmit,
+	.irq		= velocity_irq,
+};
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int velocity_probe( struct nic *nic, struct pci_device *pci)
+{
+	int ret, i;
+	struct mac_regs *regs;
+
+	printf("via-velocity.c: Found %s Vendor=0x%hX Device=0x%hX\n",
+	       pci->id->name, pci->vendor, pci->device);
+
+	/* point to private storage */
+	vptr = &vptx;
+	info = chip_info_table;
+
+	velocity_init_info(pci, vptr, info);
+
+//FIXME: pci_enable_device(pci);
+//FIXME: pci_set_power_state(pci, PCI_D0);
+
+	ret = velocity_get_pci_info(vptr, pci);
+	if (ret < 0) {
+		printf("Failed to find PCI device.\n");
+		return 0;
+	}
+
+	regs = ioremap(vptr->memaddr, vptr->io_size);
+	if (regs == NULL) {
+		printf("Unable to remap io\n");
+		return 0;
+	}
+
+	vptr->mac_regs = regs;
+
+	BASE = vptr->ioaddr;
+
+	printf("Chip ID: %hX\n", vptr->chip_id);
+
+	for (i = 0; i < 6; i++)
+		nic->node_addr[i] = readb(&regs->PAR[i]);
+
+	DBG ( "%s: %s at ioaddr %#hX\n", pci->id->name, eth_ntoa ( nic->node_addr ),
+	      (unsigned int) BASE );
+
+	velocity_get_options(&vptr->options, 0, pci->id->name);
+
+	/* 
+	 *      Mask out the options cannot be set to the chip
+	 */
+	vptr->options.flags &= 0x00FFFFFFUL;	//info->flags = 0x00FFFFFFUL;
+
+	/*
+	 *      Enable the chip specified capbilities
+	 */
+
+	vptr->flags =
+	    vptr->options.
+	    flags | (0x00FFFFFFUL /*info->flags */  & 0xFF000000UL);
+
+	vptr->wol_opts = vptr->options.wol_opts;
+	vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+
+	vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
+
+	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+		printf("features missing\n");
+	}
+
+	/* and leave the chip powered down */
+// FIXME:       pci_set_power_state(pci, PCI_D3hot);
+
+	check_connection_type(vptr->mac_regs);
+	velocity_open(nic, pci);
+
+	/* store NIC parameters */
+	nic->nic_op = &velocity_operations;
+	return 1;
+}
+
+//#define IORESOURCE_IO              0x00000100      /* Resource type */
+
+/**
+ *	velocity_init_info	-	init private data
+ *	@pdev: PCI device
+ *	@vptr: Velocity info
+ *	@info: Board type
+ *
+ *	Set up the initial velocity_info struct for the device that has been
+ *	discovered.
+ */
+
+static void velocity_init_info(struct pci_device *pdev,
+			       struct velocity_info *vptr,
+			       struct velocity_info_tbl *info)
+{
+	memset(vptr, 0, sizeof(struct velocity_info));
+
+	vptr->pdev = pdev;
+	vptr->chip_id = info->chip_id;
+	vptr->io_size = info->io_size;
+	vptr->num_txq = info->txqueue;
+	vptr->multicast_limit = MCAM_SIZE;
+
+	printf
+	    ("chip_id: 0x%hX, io_size: %d, num_txq %d, multicast_limit: %d\n",
+	     vptr->chip_id, (unsigned int) vptr->io_size, vptr->num_txq,
+	     vptr->multicast_limit);
+	printf("Name: %s\n", info->name);
+
+//      spin_lock_init(&vptr->lock);
+//      INIT_LIST_HEAD(&vptr->list);
+}
+
+/**
+ *	velocity_get_pci_info	-	retrieve PCI info for device
+ *	@vptr: velocity device
+ *	@pdev: PCI device it matches
+ *
+ *	Retrieve the PCI configuration space data that interests us from
+ *	the kernel PCI layer
+ */
+
+#define IORESOURCE_IO   0x00000100	/* Resource type */
+#define IORESOURCE_PREFETCH        0x00001000	/* No side effects */
+
+#define IORESOURCE_MEM             0x00000200
+#define BAR_0           0
+#define BAR_1           1
+#define BAR_5           5
+#define  PCI_BASE_ADDRESS_SPACE 0x01	/* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32   0x00	/* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M   0x02	/* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64   0x04	/* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH  0x08	/* prefetchable? */
+//#define  PCI_BASE_ADDRESS_MEM_MASK      (~0x0fUL)
+// #define  PCI_BASE_ADDRESS_IO_MASK       (~0x03UL)
+
+unsigned long pci_resource_flags(struct pci_device *pdev, unsigned int bar)
+{
+	uint32_t l, sz;
+	unsigned long flags = 0;
+
+	pci_read_config_dword(pdev, bar, &l);
+	pci_write_config_dword(pdev, bar, ~0);
+	pci_read_config_dword(pdev, bar, &sz);
+	pci_write_config_dword(pdev, bar, l);
+
+	if (!sz || sz == 0xffffffff)
+		printf("Weird size\n");
+	if (l == 0xffffffff)
+		l = 0;
+	if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+		/*    sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
+		   if (!sz)
+		   continue;
+		   res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+		 */ flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+		printf("Memory Resource\n");
+	} else {
+		//            sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+		///         if (!sz)
+		///              continue;
+//              res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+		flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+		printf("I/O Resource\n");
+	}
+	if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
+		printf("Why is it here\n");
+		flags |= IORESOURCE_IO;
+	} else {
+		printf("here\n");
+//flags &= ~IORESOURCE_IO;
+	}
+
+
+	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+		flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+
+	return flags;
+}
+static int velocity_get_pci_info(struct velocity_info *vptr,
+				 struct pci_device *pdev)
+{
+	if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) {
+		printf("DEBUG: pci_read_config_byte failed\n");
+		return -1;
+	}
+
+	adjust_pci_device(pdev);
+
+	vptr->ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	vptr->memaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
+
+	printf("Looking for I/O Resource - Found:");
+	if (!
+	    (pci_resource_flags(pdev, PCI_BASE_ADDRESS_0) & IORESOURCE_IO))
+	{
+		printf
+		    ("DEBUG: region #0 is not an I/O resource, aborting.\n");
+		return -1;
+	}
+
+	printf("Looking for Memory Resource - Found:");
+	if ((pci_resource_flags(pdev, PCI_BASE_ADDRESS_1) & IORESOURCE_IO)) {
+		printf("DEBUG: region #1 is an I/O resource, aborting.\n");
+		return -1;
+	}
+
+	if (pci_bar_size(pdev, PCI_BASE_ADDRESS_1) < 256) {
+		printf("DEBUG: region #1 is too small.\n");
+		return -1;
+	}
+	vptr->pdev = pdev;
+
+	return 0;
+}
+
+/**
+ *	velocity_print_link_status	-	link status reporting
+ *	@vptr: velocity to report on
+ *
+ *	Turn the link status of the velocity card into a kernel log
+ *	description of the new link state, detailing speed and duplex
+ *	status
+ */
+
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+	if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+		printf("failed to detect cable link\n");
+	} else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+		printf("Link autonegation");
+
+		if (vptr->mii_status & VELOCITY_SPEED_1000)
+			printf(" speed 1000M bps");
+		else if (vptr->mii_status & VELOCITY_SPEED_100)
+			printf(" speed 100M bps");
+		else
+			printf(" speed 10M bps");
+
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			printf(" full duplex\n");
+		else
+			printf(" half duplex\n");
+	} else {
+		printf("Link forced");
+		switch (vptr->options.spd_dpx) {
+		case SPD_DPX_100_HALF:
+			printf(" speed 100M bps half duplex\n");
+			break;
+		case SPD_DPX_100_FULL:
+			printf(" speed 100M bps full duplex\n");
+			break;
+		case SPD_DPX_10_HALF:
+			printf(" speed 10M bps half duplex\n");
+			break;
+		case SPD_DPX_10_FULL:
+			printf(" speed 10M bps full duplex\n");
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ *	velocity_rx_reset	-	handle a receive reset
+ *	@vptr: velocity we are resetting
+ *
+ *	Reset the ownership and status for the receive ring side.
+ *	Hand all the receive queue to the NIC.
+ */
+
+static void velocity_rx_reset(struct velocity_info *vptr)
+{
+
+	struct mac_regs *regs = vptr->mac_regs;
+	int i;
+
+//ptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0;
+
+	/*
+	 *      Init state, all RD entries belong to the NIC
+	 */
+	for (i = 0; i < vptr->options.numrx; ++i)
+		vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
+
+	writew(RX_DESC_DEF, &regs->RBRDU);
+	writel(virt_to_le32desc(vptr->rd_ring), &regs->RDBaseLo);
+	writew(0, &regs->RDIdx);
+	writew(RX_DESC_DEF - 1, &regs->RDCSize);
+}
+
+/**
+ *	velocity_init_registers	-	initialise MAC registers
+ *	@vptr: velocity to init
+ *	@type: type of initialisation (hot or cold)
+ *
+ *	Initialise the MAC on a reset or on first set up on the
+ *	hardware.
+ */
+
+static void velocity_init_registers(struct nic *nic,
+				    struct velocity_info *vptr,
+				    enum velocity_init_type type)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+	int i, mii_status;
+
+	mac_wol_reset(regs);
+
+	switch (type) {
+	case VELOCITY_INIT_RESET:
+	case VELOCITY_INIT_WOL:
+
+//netif_stop_queue(vptr->dev);
+
+		/*
+		 *      Reset RX to prevent RX pointer not on the 4X location
+		 */
+		velocity_rx_reset(vptr);
+		mac_rx_queue_run(regs);
+		mac_rx_queue_wake(regs);
+
+		mii_status = velocity_get_opt_media_mode(vptr);
+
+		if (velocity_set_media_mode(vptr, mii_status) !=
+		    VELOCITY_LINK_CHANGE) {
+			velocity_print_link_status(vptr);
+			if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+				printf("Link Failed\n");
+//                              netif_wake_queue(vptr->dev);
+		}
+
+		enable_flow_control_ability(vptr);
+
+		mac_clear_isr(regs);
+		writel(CR0_STOP, &regs->CR0Clr);
+		//writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), 
+		writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+		       &regs->CR0Set);
+		break;
+
+	case VELOCITY_INIT_COLD:
+	default:
+		/*
+		 *      Do reset
+		 */
+		velocity_soft_reset(vptr);
+		mdelay(5);
+
+		mac_eeprom_reload(regs);
+		for (i = 0; i < 6; i++) {
+			writeb(nic->node_addr[i], &(regs->PAR[i]));
+		}
+		/*
+		 *      clear Pre_ACPI bit.
+		 */
+		BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
+		mac_set_rx_thresh(regs, vptr->options.rx_thresh);
+		mac_set_dma_length(regs, vptr->options.DMA_length);
+
+		writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
+		/*
+		 *      Back off algorithm use original IEEE standard
+		 */
+		BYTE_REG_BITS_SET(CFGB_OFSET,
+				  (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA |
+				   CFGB_BAKOPT), &regs->CFGB);
+
+		/*
+		 *      Init CAM filter
+		 */
+		velocity_init_cam_filter(vptr);
+
+		/*
+		 *      Set packet filter: Receive directed and broadcast address
+		 */
+//FIXME Multicast               velocity_set_multi(nic);
+
+		/*
+		 *      Enable MII auto-polling
+		 */
+		enable_mii_autopoll(regs);
+
+		vptr->int_mask = INT_MASK_DEF;
+
+		writel(virt_to_le32desc(vptr->rd_ring), &regs->RDBaseLo);
+		writew(vptr->options.numrx - 1, &regs->RDCSize);
+		mac_rx_queue_run(regs);
+		mac_rx_queue_wake(regs);
+
+		writew(vptr->options.numtx - 1, &regs->TDCSize);
+
+//              for (i = 0; i < vptr->num_txq; i++) {
+		writel(virt_to_le32desc(vptr->td_rings),
+		       &(regs->TDBaseLo[0]));
+		mac_tx_queue_run(regs, 0);
+//              }
+
+		init_flow_control_register(vptr);
+
+		writel(CR0_STOP, &regs->CR0Clr);
+		writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+		       &regs->CR0Set);
+
+		mii_status = velocity_get_opt_media_mode(vptr);
+//              netif_stop_queue(vptr->dev);
+
+		mii_init(vptr, mii_status);
+
+		if (velocity_set_media_mode(vptr, mii_status) !=
+		    VELOCITY_LINK_CHANGE) {
+			velocity_print_link_status(vptr);
+			if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+				printf("Link Faaailll\n");
+//                              netif_wake_queue(vptr->dev);
+		}
+
+		enable_flow_control_ability(vptr);
+		mac_hw_mibs_init(regs);
+		mac_write_int_mask(vptr->int_mask, regs);
+		mac_clear_isr(regs);
+
+
+	}
+	velocity_print_link_status(vptr);
+}
+
+/**
+ *	velocity_soft_reset	-	soft reset
+ *	@vptr: velocity to reset
+ *
+ *	Kick off a soft reset of the velocity adapter and then poll
+ *	until the reset sequence has completed before returning.
+ */
+
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+	unsigned int i = 0;
+
+	writel(CR0_SFRST, &regs->CR0Set);
+
+	for (i = 0; i < W_MAX_TIMEOUT; i++) {
+		udelay(5);
+		if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+			break;
+	}
+
+	if (i == W_MAX_TIMEOUT) {
+		writel(CR0_FORSRST, &regs->CR0Set);
+		/* FIXME: PCI POSTING */
+		/* delay 2ms */
+		mdelay(2);
+	}
+	return 0;
+}
+
+/**
+ *	velocity_init_rings	-	set up DMA rings
+ *	@vptr: Velocity to set up
+ *
+ *	Allocate PCI mapped DMA rings for the receive and transmit layer
+ *	to use.
+ */
+
+static int velocity_init_rings(struct velocity_info *vptr)
+{
+
+	int idx;
+
+	vptr->rd_curr = 0;
+	vptr->td_curr = 0;
+	memset(vptr->td_rings, 0, TX_DESC_DEF * sizeof(struct tx_desc));
+	memset(vptr->rd_ring, 0, RX_DESC_DEF * sizeof(struct rx_desc));
+//      memset(vptr->tx_buffs, 0, TX_DESC_DEF * PKT_BUF_SZ);
+
+
+	for (idx = 0; idx < RX_DESC_DEF; idx++) {
+		vptr->rd_ring[idx].rdesc0.RSR = 0;
+		vptr->rd_ring[idx].rdesc0.len = 0;
+		vptr->rd_ring[idx].rdesc0.reserved = 0;
+		vptr->rd_ring[idx].rdesc0.owner = 0;
+		vptr->rd_ring[idx].len = cpu_to_le32(vptr->rx_buf_sz);
+		vptr->rd_ring[idx].inten = 1;
+		vptr->rd_ring[idx].pa_low =
+		    virt_to_bus(vptr->rxb + (RX_DESC_DEF * idx));
+		vptr->rd_ring[idx].pa_high = 0;
+		vptr->rd_ring[idx].rdesc0.owner = OWNED_BY_NIC;
+	}
+
+/*	for (i = 0; idx < TX_DESC_DEF; idx++ ) {
+		vptr->td_rings[idx].tdesc1.TCPLS = TCPLS_NORMAL;
+		vptr->td_rings[idx].tdesc1.TCR = TCR0_TIC;
+		vptr->td_rings[idx].td_buf[0].queue = 0;
+		vptr->td_rings[idx].tdesc0.owner = ~OWNED_BY_NIC;
+		vptr->td_rings[idx].tdesc0.pktsize = 0;
+		vptr->td_rings[idx].td_buf[0].pa_low = cpu_to_le32(virt_to_bus(vptr->txb + (idx * PKT_BUF_SZ)));
+		vptr->td_rings[idx].td_buf[0].pa_high = 0;
+		vptr->td_rings[idx].td_buf[0].bufsize = 0;
+		vptr->td_rings[idx].tdesc1.CMDZ = 2;
+	}
+*/
+	return 0;
+}
+
+/**
+ *	velocity_open		-	interface activation callback
+ *	@dev: network layer device to open
+ *
+ *	Called when the network layer brings the interface up. Returns
+ *	a negative posix error code on failure, or zero on success.
+ *
+ *	All the ring allocation and set up is done on open for this
+ *	adapter to minimise memory usage when inactive
+ */
+
+#define PCI_BYTE_REG_BITS_ON(x,i,p) do{\
+    u8 byReg;\
+    pci_read_config_byte((p), (i), &(byReg));\
+    (byReg) |= (x);\
+    pci_write_config_byte((p), (i), (byReg));\
+} while (0)
+
+//
+// Registers in the PCI configuration space
+//
+#define PCI_REG_COMMAND         0x04	//
+#define PCI_REG_MODE0           0x60	//
+#define PCI_REG_MODE1           0x61	//
+#define PCI_REG_MODE2           0x62	//
+#define PCI_REG_MODE3           0x63	//
+#define PCI_REG_DELAY_TIMER     0x64	//
+
+// Bits in the (MODE2, 0x62) register
+//
+#define MODE2_PCEROPT       0x80	// take PCI bus ERror as a fatal and shutdown from software control
+#define MODE2_TXQ16         0x40	// TX write-back Queue control. 0->32 entries available in Tx write-back queue, 1->16 entries
+#define MODE2_TXPOST        0x08	// (Not support in VT3119)
+#define MODE2_AUTOOPT       0x04	// (VT3119 GHCI without such behavior)
+#define MODE2_MODE10T       0x02	// used to control tx Threshold for 10M case
+#define MODE2_TCPLSOPT      0x01	// TCP large send field update disable, hardware will not update related fields, leave it to software.
+
+//
+// Bits in the MODE3 register
+//
+#define MODE3_MIION         0x04	// MII symbol codine error detect enable ??
+
+// Bits in the (COMMAND, 0x04) register
+#define COMMAND_BUSM        0x04
+#define COMMAND_WAIT        0x80
+static int velocity_open(struct nic *nic, struct pci_device *pci __unused)
+{
+	u8 diff;
+	u32 TxPhyAddr, RxPhyAddr;
+	u32 TxBufPhyAddr, RxBufPhyAddr;
+	vptr->TxDescArrays = tx_ring;
+	if (vptr->TxDescArrays == 0)
+		printf("Allot Error");
+
+	/* Tx Descriptor needs 64 bytes alignment; */
+	TxPhyAddr = virt_to_bus(vptr->TxDescArrays);
+	printf("Unaligned Address : %X\n", TxPhyAddr);
+	diff = 64 - (TxPhyAddr - ((TxPhyAddr >> 6) << 6));
+	TxPhyAddr += diff;
+	vptr->td_rings = (struct tx_desc *) (vptr->TxDescArrays + diff);
+
+	printf("Aligned Address: %lX\n", virt_to_bus(vptr->td_rings));
+	vptr->tx_buffs = txb;
+	/* Rx Buffer needs 64 bytes alignment; */
+	TxBufPhyAddr = virt_to_bus(vptr->tx_buffs);
+	diff = 64 - (TxBufPhyAddr - ((TxBufPhyAddr >> 6) << 6));
+	TxBufPhyAddr += diff;
+	vptr->txb = (unsigned char *) (vptr->tx_buffs + diff);
+
+	vptr->RxDescArrays = rx_ring;
+	/* Rx Descriptor needs 64 bytes alignment; */
+	RxPhyAddr = virt_to_bus(vptr->RxDescArrays);
+	diff = 64 - (RxPhyAddr - ((RxPhyAddr >> 6) << 6));
+	RxPhyAddr += diff;
+	vptr->rd_ring = (struct rx_desc *) (vptr->RxDescArrays + diff);
+
+	vptr->rx_buffs = rxb;
+	/* Rx Buffer needs 64 bytes alignment; */
+	RxBufPhyAddr = virt_to_bus(vptr->rx_buffs);
+	diff = 64 - (RxBufPhyAddr - ((RxBufPhyAddr >> 6) << 6));
+	RxBufPhyAddr += diff;
+	vptr->rxb = (unsigned char *) (vptr->rx_buffs + diff);
+
+	if (vptr->RxDescArrays == NULL || vptr->RxDescArrays == NULL) {
+		printf("Allocate tx_ring or rd_ring failed\n");
+		return 0;
+	}
+
+	vptr->rx_buf_sz = PKT_BUF_SZ;
+/*
+    // turn this on to avoid retry forever
+    PCI_BYTE_REG_BITS_ON(MODE2_PCEROPT, PCI_REG_MODE2, pci);
+    // for some legacy BIOS and OS don't open BusM
+    // bit in PCI configuration space. So, turn it on.
+    PCI_BYTE_REG_BITS_ON(COMMAND_BUSM, PCI_REG_COMMAND, pci);
+    // turn this on to detect MII coding error
+    PCI_BYTE_REG_BITS_ON(MODE3_MIION, PCI_REG_MODE3, pci);
+ */
+	velocity_init_rings(vptr);
+
+	/* Ensure chip is running */
+//FIXME:        pci_set_power_state(vptr->pdev, PCI_D0);
+
+	velocity_init_registers(nic, vptr, VELOCITY_INIT_COLD);
+	mac_write_int_mask(0, vptr->mac_regs);
+//      _int(vptr->mac_regs);
+	//mac_enable_int(vptr->mac_regs);
+
+	vptr->flags |= VELOCITY_FLAGS_OPENED;
+	return 1;
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+
+/**
+ *	mii_init	-	set up MII
+ *	@vptr: velocity adapter
+ *	@mii_status:  links tatus
+ *
+ *	Set up the PHY for the current link state.
+ */
+
+static void mii_init(struct velocity_info *vptr, u32 mii_status __unused)
+{
+	u16 BMCR;
+
+	switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+	case PHYID_CICADA_CS8201:
+		/*
+		 *      Reset to hardware default
+		 */
+		MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+				 vptr->mac_regs);
+		/*
+		 *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *      off it in NWay-forced half mode for NWay-forced v.s. 
+		 *      legacy-forced issue.
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR,
+					vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR,
+					 vptr->mac_regs);
+		/*
+		 *      Turn on Link/Activity LED enable bit for CIS8201
+		 */
+		MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+		break;
+	case PHYID_VT3216_32BIT:
+	case PHYID_VT3216_64BIT:
+		/*
+		 *      Reset to hardware default
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+				vptr->mac_regs);
+		/*
+		 *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *      off it in NWay-forced half mode for NWay-forced v.s. 
+		 *      legacy-forced issue
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR,
+					vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR,
+					 vptr->mac_regs);
+		break;
+
+	case PHYID_MARVELL_1000:
+	case PHYID_MARVELL_1000S:
+		/*
+		 *      Assert CRS on Transmit 
+		 */
+		MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+		/*
+		 *      Reset to hardware default 
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR,
+				vptr->mac_regs);
+		break;
+	default:
+		;
+	}
+	velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+	if (BMCR & BMCR_ISO) {
+		BMCR &= ~BMCR_ISO;
+		velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+	}
+}
+
+/**
+ *	safe_disable_mii_autopoll	-	autopoll off
+ *	@regs: velocity registers
+ *
+ *	Turn off the autopoll and wait for it to disable on the chip
+ */
+
+static void safe_disable_mii_autopoll(struct mac_regs *regs)
+{
+	u16 ww;
+
+	/*  turn off MAUTO */
+	writeb(0, &regs->MIICR);
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+}
+
+/**
+ *	enable_mii_autopoll	-	turn on autopolling
+ *	@regs: velocity registers
+ *
+ *	Enable the MII link status autopoll feature on the Velocity
+ *	hardware. Wait for it to enable.
+ */
+
+static void enable_mii_autopoll(struct mac_regs *regs)
+{
+	unsigned int ii;
+
+	writeb(0, &(regs->MIICR));
+	writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+	writeb(MIICR_MAUTO, &regs->MIICR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+}
+
+/**
+ *	velocity_mii_read	-	read MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: buffer for received data
+ *
+ *	Perform a single read of an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_read(struct mac_regs *regs, u8 index, u16 * data)
+{
+	u16 ww;
+
+	/*
+	 *      Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	writeb(index, &regs->MIIADR);
+
+	BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		if (!(readb(&regs->MIICR) & MIICR_RCMD))
+			break;
+	}
+
+	*data = readw(&regs->MIIDATA);
+
+	enable_mii_autopoll(regs);
+	if (ww == W_MAX_TIMEOUT)
+		return -1;
+	return 0;
+}
+
+/**
+ *	velocity_mii_write	-	write MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: 16bit data for the MII register
+ *
+ *	Perform a single write to an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_write(struct mac_regs *regs, u8 mii_addr, u16 data)
+{
+	u16 ww;
+
+	/*
+	 *      Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	/* MII reg offset */
+	writeb(mii_addr, &regs->MIIADR);
+	/* set MII data */
+	writew(data, &regs->MIIDATA);
+
+	/* turn on MIICR_WCMD */
+	BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+	/* W_MAX_TIMEOUT is the timeout period */
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(5);
+		if (!(readb(&regs->MIICR) & MIICR_WCMD))
+			break;
+	}
+	enable_mii_autopoll(regs);
+
+	if (ww == W_MAX_TIMEOUT)
+		return -1;
+	return 0;
+}
+
+/**
+ *	velocity_get_opt_media_mode	-	get media selection
+ *	@vptr: velocity adapter
+ *
+ *	Get the media mode stored in EEPROM or module options and load
+ *	mii_status accordingly. The requested link state information
+ *	is also returned.
+ */
+
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+	u32 status = 0;
+
+	switch (vptr->options.spd_dpx) {
+	case SPD_DPX_AUTO:
+		status = VELOCITY_AUTONEG_ENABLE;
+		break;
+	case SPD_DPX_100_FULL:
+		status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_10_FULL:
+		status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_100_HALF:
+		status = VELOCITY_SPEED_100;
+		break;
+	case SPD_DPX_10_HALF:
+		status = VELOCITY_SPEED_10;
+		break;
+	}
+	vptr->mii_status = status;
+	return status;
+}
+
+/**
+ *	mii_set_auto_on		-	autonegotiate on
+ *	@vptr: velocity
+ *
+ *	Enable autonegotation on this interface
+ */
+
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+	else
+		MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+
+/*
+static void mii_set_auto_off(struct velocity_info * vptr)
+{
+    MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+*/
+
+/**
+ *	set_mii_flow_control	-	flow control setup
+ *	@vptr: velocity interface
+ *
+ *	Set up the flow control on this interface according to
+ *	the supplied user/eeprom options.
+ */
+
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+	/*Enable or Disable PAUSE in ANAR */
+	switch (vptr->options.flow_cntl) {
+	case FLOW_CNTL_TX:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR,
+				 vptr->mac_regs);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ *	velocity_set_media_mode		-	set media mode
+ *	@mii_status: old MII link state
+ *
+ *	Check the media link state and configure the flow control
+ *	PHY and also velocity hardware setup accordingly. In particular
+ *	we need to set up CD polling and frame bursting.
+ */
+
+static int velocity_set_media_mode(struct velocity_info *vptr,
+				   u32 mii_status)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+
+	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+
+	/* Set mii link status */
+	set_mii_flow_control(vptr);
+
+	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
+		MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR,
+				vptr->mac_regs);
+	}
+
+	/*
+	 *      If connection type is AUTO
+	 */
+	if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+		printf("Velocity is AUTO mode\n");
+		/* clear force MAC mode bit */
+		BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+		/* set duplex mode of MAC according to duplex mode of MII */
+		MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10,
+				MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000,
+				MII_REG_G1000CR, vptr->mac_regs);
+		MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR,
+				vptr->mac_regs);
+
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+	} else {
+		u16 ANAR;
+		u8 CHIPGCR;
+
+		/*
+		 * 1. if it's 3119, disable frame bursting in halfduplex mode
+		 *    and enable it in fullduplex mode
+		 * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+		 * 3. only enable CD heart beat counter in 10HD mode
+		 */
+
+		/* set force MAC mode bit */
+		BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+		CHIPGCR = readb(&regs->CHIPGCR);
+		CHIPGCR &= ~CHIPGCR_FCGMII;
+
+		if (mii_status & VELOCITY_DUPLEX_FULL) {
+			CHIPGCR |= CHIPGCR_FCFDX;
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			printf
+			    ("DEBUG: set Velocity to forced full mode\n");
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+		} else {
+			CHIPGCR &= ~CHIPGCR_FCFDX;
+			printf
+			    ("DEBUG: set Velocity to forced half mode\n");
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+		}
+
+		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000,
+				 MII_REG_G1000CR, vptr->mac_regs);
+
+		if (!(mii_status & VELOCITY_DUPLEX_FULL)
+		    && (mii_status & VELOCITY_SPEED_10)) {
+			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+		} else {
+			BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+		}
+		/* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+		velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+		ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+		if (mii_status & VELOCITY_SPEED_100) {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_TXFD;
+			else
+				ANAR |= ANAR_TX;
+		} else {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_10FD;
+			else
+				ANAR |= ANAR_10;
+		}
+		velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+		/* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+	}
+	/* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+	/* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+	return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ *	mii_check_media_mode	-	check media state
+ *	@regs: velocity registers
+ *
+ *	Check the current MII status and determine the link status
+ *	accordingly
+ */
+
+static u32 mii_check_media_mode(struct mac_regs *regs)
+{
+	u32 status = 0;
+	u16 ANAR;
+
+	if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+		status |= VELOCITY_LINK_FAIL;
+
+	if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+		status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+	else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+		status |= (VELOCITY_SPEED_1000);
+	else {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if (ANAR & ANAR_TXFD)
+			status |=
+			    (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+		else if (ANAR & ANAR_TX)
+			status |= VELOCITY_SPEED_100;
+		else if (ANAR & ANAR_10FD)
+			status |=
+			    (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+		else
+			status |= (VELOCITY_SPEED_10);
+	}
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON
+			    (G1000CR_1000 | G1000CR_1000FD,
+			     MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+static u32 check_connection_type(struct mac_regs *regs)
+{
+	u32 status = 0;
+	u8 PHYSR0;
+	u16 ANAR;
+	PHYSR0 = readb(&regs->PHYSR0);
+
+	/*
+	   if (!(PHYSR0 & PHYSR0_LINKGD))
+	   status|=VELOCITY_LINK_FAIL;
+	 */
+
+	if (PHYSR0 & PHYSR0_FDPX)
+		status |= VELOCITY_DUPLEX_FULL;
+
+	if (PHYSR0 & PHYSR0_SPDG)
+		status |= VELOCITY_SPEED_1000;
+	if (PHYSR0 & PHYSR0_SPD10)
+		status |= VELOCITY_SPEED_10;
+	else
+		status |= VELOCITY_SPEED_100;
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON
+			    (G1000CR_1000 | G1000CR_1000FD,
+			     MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *	enable_flow_control_ability	-	flow control
+ *	@vptr: veloity to configure
+ *
+ *	Set up flow control according to the flow control options
+ *	determined by the eeprom/configuration.
+ */
+
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+	struct mac_regs *regs = vptr->mac_regs;
+
+	switch (vptr->options.flow_cntl) {
+
+	case FLOW_CNTL_DEFAULT:
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+			writel(CR0_FDXRFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+			writel(CR0_FDXTFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_RX:
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	default:
+		break;
+	}
+
+}
+
+/* FIXME: Move to pci.c */
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: Power state we're entering
+ *
+ * Transition a device to a new power state, using the Power Management 
+ * Capabilities in the device's config space.
+ *
+ * RETURN VALUE: 
+ * -EINVAL if trying to enter a lower state than we're already in.
+ * 0 if we're already in the requested state.
+ * -EIO if device does not support PCI PM.
+ * 0 if we can successfully change the power state.
+ */
+
+int pci_set_power_state(struct pci_device *dev, int state)
+{
+	int pm;
+	u16 pmcsr;
+	int current_state = 0;
+
+	/* bound the state we're entering */
+	if (state > 3)
+		state = 3;
+
+	/* Validate current state:
+	 * Can enter D0 from any state, but if we can only go deeper 
+	 * to sleep if we're already in a low power state
+	 */
+	if (state > 0 && current_state > state)
+		return -1;
+	else if (current_state == state)
+		return 0;	/* we're already there */
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+	/* abort if the device doesn't support PM capabilities */
+	if (!pm)
+		return -2;
+
+	/* check if this device supports the desired state */
+	if (state == 1 || state == 2) {
+		u16 pmc;
+		pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
+		if (state == 1 && !(pmc & PCI_PM_CAP_D1))
+			return -2;
+		else if (state == 2 && !(pmc & PCI_PM_CAP_D2))
+			return -2;
+	}
+
+	/* If we're in D3, force entire word to 0.
+	 * This doesn't affect PME_Status, disables PME_En, and
+	 * sets PowerState to 0.
+	 */
+	if (current_state >= 3)
+		pmcsr = 0;
+	else {
+		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= state;
+	}
+
+	/* enter specified state */
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+
+	/* Mandatory power management transition delays */
+	/* see PCI PM 1.1 5.6.1 table 18 */
+	if (state == 3 || current_state == 3)
+		mdelay(10);
+	else if (state == 2 || current_state == 2)
+		udelay(200);
+	current_state = state;
+
+	return 0;
+}
+
+static struct pci_device_id velocity_nics[] = {
+	PCI_ROM(0x1106, 0x3119, "via-velocity", "VIA Networking Velocity Family Gigabit Ethernet Adapter", 0),
+};
+
+PCI_DRIVER ( velocity_driver, velocity_nics, PCI_NO_CLASS );
+
+DRIVER ( "VIA-VELOCITY/PCI", nic_driver, pci_driver, velocity_driver,
+         velocity_probe, velocity_disable );
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.h
new file mode 100644
index 0000000..b657224
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/via-velocity.h
@@ -0,0 +1,1932 @@
+/*
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software may be redistributed and/or modified under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * File: via-velocity.h
+ *
+ * Purpose: Header file to define driver's private structures.
+ *
+ * Author: Chuang Liang-Shing, AJ Jiang
+ *
+ * Date: Jan 24, 2003
+ *
+ * Changes for Etherboot Port: 
+ *       Copyright (c) 2006 by Timothy Legge <tlegge at rogers.com>
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef VELOCITY_H
+#define VELOCITY_H
+
+#define VELOCITY_TX_CSUM_SUPPORT
+
+#define VELOCITY_NAME          "via-velocity"
+#define VELOCITY_FULL_DRV_NAM  "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
+#define VELOCITY_VERSION       "1.13"
+
+#define PKT_BUF_SZ          1564
+
+#define MAX_UNITS           8
+#define OPTION_DEFAULT      { [0 ... MAX_UNITS-1] = -1}
+
+#define REV_ID_VT6110       (0)
+
+#define BYTE_REG_BITS_ON(x,p)       do { writeb(readb((p))|(x),(p));} while (0)
+#define WORD_REG_BITS_ON(x,p)       do { writew(readw((p))|(x),(p));} while (0)
+#define DWORD_REG_BITS_ON(x,p)      do { writel(readl((p))|(x),(p));} while (0)
+
+#define BYTE_REG_BITS_IS_ON(x,p)    (readb((p)) & (x))
+#define WORD_REG_BITS_IS_ON(x,p)    (readw((p)) & (x))
+#define DWORD_REG_BITS_IS_ON(x,p)   (readl((p)) & (x))
+
+#define BYTE_REG_BITS_OFF(x,p)      do { writeb(readb((p)) & (~(x)),(p));} while (0)
+#define WORD_REG_BITS_OFF(x,p)      do { writew(readw((p)) & (~(x)),(p));} while (0)
+#define DWORD_REG_BITS_OFF(x,p)     do { writel(readl((p)) & (~(x)),(p));} while (0)
+
+#define BYTE_REG_BITS_SET(x,m,p)    do { writeb( (readb((p)) & (~(m))) |(x),(p));} while (0)
+#define WORD_REG_BITS_SET(x,m,p)    do { writew( (readw((p)) & (~(m))) |(x),(p));} while (0)
+#define DWORD_REG_BITS_SET(x,m,p)   do { writel( (readl((p)) & (~(m)))|(x),(p));}  while (0)
+
+#define VAR_USED(p)     do {(p)=(p);} while (0)
+
+/*
+ * Purpose: Structures for MAX RX/TX descriptors.
+ */
+
+
+#define B_OWNED_BY_CHIP     1
+#define B_OWNED_BY_HOST     0
+
+/*
+ * Bits in the RSR0 register
+ */
+
+#define RSR_DETAG          0x0080
+#define RSR_SNTAG          0x0040
+#define RSR_RXER           0x0020
+#define RSR_RL             0x0010
+#define RSR_CE             0x0008
+#define RSR_FAE            0x0004
+#define RSR_CRC            0x0002
+#define RSR_VIDM           0x0001
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR_RXOK           0x8000	// rx OK
+#define RSR_PFT            0x4000	// Perfect filtering address match
+#define RSR_MAR            0x2000	// MAC accept multicast address packet
+#define RSR_BAR            0x1000	// MAC accept broadcast address packet
+#define RSR_PHY            0x0800	// MAC accept physical address packet
+#define RSR_VTAG           0x0400	// 802.1p/1q tagging packet indicator
+#define RSR_STP            0x0200	// start of packet
+#define RSR_EDP            0x0100	// end of packet
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR1_RXOK           0x80	// rx OK
+#define RSR1_PFT            0x40	// Perfect filtering address match
+#define RSR1_MAR            0x20	// MAC accept multicast address packet
+#define RSR1_BAR            0x10	// MAC accept broadcast address packet
+#define RSR1_PHY            0x08	// MAC accept physical address packet
+#define RSR1_VTAG           0x04	// 802.1p/1q tagging packet indicator
+#define RSR1_STP            0x02	// start of packet
+#define RSR1_EDP            0x01	// end of packet
+
+/*
+ * Bits in the CSM register
+ */
+
+#define CSM_IPOK            0x40	//IP Checkusm validatiaon ok
+#define CSM_TUPOK           0x20	//TCP/UDP Checkusm validatiaon ok
+#define CSM_FRAG            0x10	//Fragment IP datagram
+#define CSM_IPKT            0x04	//Received an IP packet
+#define CSM_TCPKT           0x02	//Received a TCP packet
+#define CSM_UDPKT           0x01	//Received a UDP packet
+
+/*
+ * Bits in the TSR0 register
+ */
+
+#define TSR0_ABT            0x0080	// Tx abort because of excessive collision
+#define TSR0_OWT            0x0040	// Jumbo frame Tx abort
+#define TSR0_OWC            0x0020	// Out of window collision
+#define TSR0_COLS           0x0010	// experience collision in this transmit event
+#define TSR0_NCR3           0x0008	// collision retry counter[3]
+#define TSR0_NCR2           0x0004	// collision retry counter[2]
+#define TSR0_NCR1           0x0002	// collision retry counter[1]
+#define TSR0_NCR0           0x0001	// collision retry counter[0]
+#define TSR0_TERR           0x8000	//
+#define TSR0_FDX            0x4000	// current transaction is serviced by full duplex mode
+#define TSR0_GMII           0x2000	// current transaction is serviced by GMII mode
+#define TSR0_LNKFL          0x1000	// packet serviced during link down
+#define TSR0_SHDN           0x0400	// shutdown case
+#define TSR0_CRS            0x0200	// carrier sense lost
+#define TSR0_CDH            0x0100	// AQE test fail (CD heartbeat)
+
+/*
+ * Bits in the TSR1 register
+ */
+
+#define TSR1_TERR           0x80	//
+#define TSR1_FDX            0x40	// current transaction is serviced by full duplex mode
+#define TSR1_GMII           0x20	// current transaction is serviced by GMII mode
+#define TSR1_LNKFL          0x10	// packet serviced during link down
+#define TSR1_SHDN           0x04	// shutdown case
+#define TSR1_CRS            0x02	// carrier sense lost
+#define TSR1_CDH            0x01	// AQE test fail (CD heartbeat)
+
+//
+// Bits in the TCR0 register
+//
+#define TCR0_TIC            0x80	// assert interrupt immediately while descriptor has been send complete
+#define TCR0_PIC            0x40	// priority interrupt request, INA# is issued over adaptive interrupt scheme
+#define TCR0_VETAG          0x20	// enable VLAN tag
+#define TCR0_IPCK           0x10	// request IP  checksum calculation.
+#define TCR0_UDPCK          0x08	// request UDP checksum calculation.
+#define TCR0_TCPCK          0x04	// request TCP checksum calculation.
+#define TCR0_JMBO           0x02	// indicate a jumbo packet in GMAC side
+#define TCR0_CRC            0x01	// disable CRC generation
+
+#define TCPLS_NORMAL        3
+#define TCPLS_START         2
+#define TCPLS_END           1
+#define TCPLS_MED           0
+
+
+// max transmit or receive buffer size
+#define CB_RX_BUF_SIZE     2048UL	// max buffer size
+					// NOTE: must be multiple of 4
+
+#define CB_MAX_RD_NUM       512	// MAX # of RD
+#define CB_MAX_TD_NUM       256	// MAX # of TD
+
+#define CB_INIT_RD_NUM_3119 128	// init # of RD, for setup VT3119
+#define CB_INIT_TD_NUM_3119 64	// init # of TD, for setup VT3119
+
+#define CB_INIT_RD_NUM      128	// init # of RD, for setup default
+#define CB_INIT_TD_NUM      64	// init # of TD, for setup default
+
+// for 3119
+#define CB_TD_RING_NUM      4	// # of TD rings.
+#define CB_MAX_SEG_PER_PKT  7	// max data seg per packet (Tx)
+
+
+/*
+ *	If collisions excess 15 times , tx will abort, and
+ *	if tx fifo underflow, tx will fail
+ *	we should try to resend it
+ */
+
+#define CB_MAX_TX_ABORT_RETRY   3
+
+/*
+ *	Receive descriptor
+ */
+
+struct rdesc0 {
+	u16 RSR;		/* Receive status */
+	u16 len:14;		/* Received packet length */
+	u16 reserved:1;
+	u16 owner:1;		/* Who owns this buffer ? */
+};
+
+struct rdesc1 {
+	u16 PQTAG;
+	u8 CSM;
+	u8 IPKT;
+};
+
+struct rx_desc {
+	struct rdesc0 rdesc0;
+	struct rdesc1 rdesc1;
+	u32 pa_low;		/* Low 32 bit PCI address */
+	u16 pa_high;		/* Next 16 bit PCI address (48 total) */
+	u16 len:15;		/* Frame size */
+	u16 inten:1;		/* Enable interrupt */
+} __attribute__ ((__packed__));
+
+/*
+ *	Transmit descriptor
+ */
+
+struct tdesc0 {
+	u16 TSR;		/* Transmit status register */
+	u16 pktsize:14;		/* Size of frame */
+	u16 reserved:1;
+	u16 owner:1;		/* Who owns the buffer */
+};
+
+struct pqinf {			/* Priority queue info */
+	u16 VID:12;
+	u16 CFI:1;
+	u16 priority:3;
+} __attribute__ ((__packed__));
+
+struct tdesc1 {
+	struct pqinf pqinf;
+	u8 TCR;
+	u8 TCPLS:2;
+	u8 reserved:2;
+	u8 CMDZ:4;
+} __attribute__ ((__packed__));
+
+struct td_buf {
+	u32 pa_low;
+	u16 pa_high;
+	u16 bufsize:14;
+	u16 reserved:1;
+	u16 queue:1;
+} __attribute__ ((__packed__));
+
+struct tx_desc {
+	struct tdesc0 tdesc0;
+	struct tdesc1 tdesc1;
+	struct td_buf td_buf[7];
+};
+
+#ifdef LINUX
+struct velocity_rd_info {
+	struct sk_buff *skb;
+	dma_addr_t skb_dma;
+};
+
+
+/**
+ *	alloc_rd_info		-	allocate an rd info block
+ *
+ *	Alocate and initialize a receive info structure used for keeping
+ *	track of kernel side information related to each receive
+ *	descriptor we are using
+ */
+
+static inline struct velocity_rd_info *alloc_rd_info(void)
+{
+	struct velocity_rd_info *ptr;
+	if ((ptr =
+	     kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
+		return NULL;
+	else {
+		memset(ptr, 0, sizeof(struct velocity_rd_info));
+		return ptr;
+	}
+}
+
+/*
+ *	Used to track transmit side buffers.
+ */
+
+struct velocity_td_info {
+	struct sk_buff *skb;
+	u8 *buf;
+	int nskb_dma;
+	dma_addr_t skb_dma[7];
+	dma_addr_t buf_dma;
+};
+
+#endif
+enum {
+	OWNED_BY_HOST = 0,
+	OWNED_BY_NIC = 1
+} velocity_owner;
+
+
+/*
+ *	MAC registers and macros.
+ */
+
+
+#define MCAM_SIZE           64
+#define VCAM_SIZE           64
+#define TX_QUEUE_NO         4
+
+#define MAX_HW_MIB_COUNTER  32
+#define VELOCITY_MIN_MTU    (1514-14)
+#define VELOCITY_MAX_MTU    (9000)
+
+/*
+ *	Registers in the MAC
+ */
+
+#define MAC_REG_PAR         0x00	// physical address
+#define MAC_REG_RCR         0x06
+#define MAC_REG_TCR         0x07
+#define MAC_REG_CR0_SET     0x08
+#define MAC_REG_CR1_SET     0x09
+#define MAC_REG_CR2_SET     0x0A
+#define MAC_REG_CR3_SET     0x0B
+#define MAC_REG_CR0_CLR     0x0C
+#define MAC_REG_CR1_CLR     0x0D
+#define MAC_REG_CR2_CLR     0x0E
+#define MAC_REG_CR3_CLR     0x0F
+#define MAC_REG_MAR         0x10
+#define MAC_REG_CAM         0x10
+#define MAC_REG_DEC_BASE_HI 0x18
+#define MAC_REG_DBF_BASE_HI 0x1C
+#define MAC_REG_ISR_CTL     0x20
+#define MAC_REG_ISR_HOTMR   0x20
+#define MAC_REG_ISR_TSUPTHR 0x20
+#define MAC_REG_ISR_RSUPTHR 0x20
+#define MAC_REG_ISR_CTL1    0x21
+#define MAC_REG_TXE_SR      0x22
+#define MAC_REG_RXE_SR      0x23
+#define MAC_REG_ISR         0x24
+#define MAC_REG_ISR0        0x24
+#define MAC_REG_ISR1        0x25
+#define MAC_REG_ISR2        0x26
+#define MAC_REG_ISR3        0x27
+#define MAC_REG_IMR         0x28
+#define MAC_REG_IMR0        0x28
+#define MAC_REG_IMR1        0x29
+#define MAC_REG_IMR2        0x2A
+#define MAC_REG_IMR3        0x2B
+#define MAC_REG_TDCSR_SET   0x30
+#define MAC_REG_RDCSR_SET   0x32
+#define MAC_REG_TDCSR_CLR   0x34
+#define MAC_REG_RDCSR_CLR   0x36
+#define MAC_REG_RDBASE_LO   0x38
+#define MAC_REG_RDINDX      0x3C
+#define MAC_REG_TDBASE_LO   0x40
+#define MAC_REG_RDCSIZE     0x50
+#define MAC_REG_TDCSIZE     0x52
+#define MAC_REG_TDINDX      0x54
+#define MAC_REG_TDIDX0      0x54
+#define MAC_REG_TDIDX1      0x56
+#define MAC_REG_TDIDX2      0x58
+#define MAC_REG_TDIDX3      0x5A
+#define MAC_REG_PAUSE_TIMER 0x5C
+#define MAC_REG_RBRDU       0x5E
+#define MAC_REG_FIFO_TEST0  0x60
+#define MAC_REG_FIFO_TEST1  0x64
+#define MAC_REG_CAMADDR     0x68
+#define MAC_REG_CAMCR       0x69
+#define MAC_REG_GFTEST      0x6A
+#define MAC_REG_FTSTCMD     0x6B
+#define MAC_REG_MIICFG      0x6C
+#define MAC_REG_MIISR       0x6D
+#define MAC_REG_PHYSR0      0x6E
+#define MAC_REG_PHYSR1      0x6F
+#define MAC_REG_MIICR       0x70
+#define MAC_REG_MIIADR      0x71
+#define MAC_REG_MIIDATA     0x72
+#define MAC_REG_SOFT_TIMER0 0x74
+#define MAC_REG_SOFT_TIMER1 0x76
+#define MAC_REG_CFGA        0x78
+#define MAC_REG_CFGB        0x79
+#define MAC_REG_CFGC        0x7A
+#define MAC_REG_CFGD        0x7B
+#define MAC_REG_DCFG0       0x7C
+#define MAC_REG_DCFG1       0x7D
+#define MAC_REG_MCFG0       0x7E
+#define MAC_REG_MCFG1       0x7F
+
+#define MAC_REG_TBIST       0x80
+#define MAC_REG_RBIST       0x81
+#define MAC_REG_PMCC        0x82
+#define MAC_REG_STICKHW     0x83
+#define MAC_REG_MIBCR       0x84
+#define MAC_REG_EERSV       0x85
+#define MAC_REG_REVID       0x86
+#define MAC_REG_MIBREAD     0x88
+#define MAC_REG_BPMA        0x8C
+#define MAC_REG_EEWR_DATA   0x8C
+#define MAC_REG_BPMD_WR     0x8F
+#define MAC_REG_BPCMD       0x90
+#define MAC_REG_BPMD_RD     0x91
+#define MAC_REG_EECHKSUM    0x92
+#define MAC_REG_EECSR       0x93
+#define MAC_REG_EERD_DATA   0x94
+#define MAC_REG_EADDR       0x96
+#define MAC_REG_EMBCMD      0x97
+#define MAC_REG_JMPSR0      0x98
+#define MAC_REG_JMPSR1      0x99
+#define MAC_REG_JMPSR2      0x9A
+#define MAC_REG_JMPSR3      0x9B
+#define MAC_REG_CHIPGSR     0x9C
+#define MAC_REG_TESTCFG     0x9D
+#define MAC_REG_DEBUG       0x9E
+#define MAC_REG_CHIPGCR     0x9F
+#define MAC_REG_WOLCR0_SET  0xA0
+#define MAC_REG_WOLCR1_SET  0xA1
+#define MAC_REG_PWCFG_SET   0xA2
+#define MAC_REG_WOLCFG_SET  0xA3
+#define MAC_REG_WOLCR0_CLR  0xA4
+#define MAC_REG_WOLCR1_CLR  0xA5
+#define MAC_REG_PWCFG_CLR   0xA6
+#define MAC_REG_WOLCFG_CLR  0xA7
+#define MAC_REG_WOLSR0_SET  0xA8
+#define MAC_REG_WOLSR1_SET  0xA9
+#define MAC_REG_WOLSR0_CLR  0xAC
+#define MAC_REG_WOLSR1_CLR  0xAD
+#define MAC_REG_PATRN_CRC0  0xB0
+#define MAC_REG_PATRN_CRC1  0xB2
+#define MAC_REG_PATRN_CRC2  0xB4
+#define MAC_REG_PATRN_CRC3  0xB6
+#define MAC_REG_PATRN_CRC4  0xB8
+#define MAC_REG_PATRN_CRC5  0xBA
+#define MAC_REG_PATRN_CRC6  0xBC
+#define MAC_REG_PATRN_CRC7  0xBE
+#define MAC_REG_BYTEMSK0_0  0xC0
+#define MAC_REG_BYTEMSK0_1  0xC4
+#define MAC_REG_BYTEMSK0_2  0xC8
+#define MAC_REG_BYTEMSK0_3  0xCC
+#define MAC_REG_BYTEMSK1_0  0xD0
+#define MAC_REG_BYTEMSK1_1  0xD4
+#define MAC_REG_BYTEMSK1_2  0xD8
+#define MAC_REG_BYTEMSK1_3  0xDC
+#define MAC_REG_BYTEMSK2_0  0xE0
+#define MAC_REG_BYTEMSK2_1  0xE4
+#define MAC_REG_BYTEMSK2_2  0xE8
+#define MAC_REG_BYTEMSK2_3  0xEC
+#define MAC_REG_BYTEMSK3_0  0xF0
+#define MAC_REG_BYTEMSK3_1  0xF4
+#define MAC_REG_BYTEMSK3_2  0xF8
+#define MAC_REG_BYTEMSK3_3  0xFC
+
+/*
+ *	Bits in the RCR register
+ */
+
+#define RCR_AS              0x80
+#define RCR_AP              0x40
+#define RCR_AL              0x20
+#define RCR_PROM            0x10
+#define RCR_AB              0x08
+#define RCR_AM              0x04
+#define RCR_AR              0x02
+#define RCR_SEP             0x01
+
+/*
+ *	Bits in the TCR register
+ */
+
+#define TCR_TB2BDIS         0x80
+#define TCR_COLTMC1         0x08
+#define TCR_COLTMC0         0x04
+#define TCR_LB1             0x02	/* loopback[1] */
+#define TCR_LB0             0x01	/* loopback[0] */
+
+/*
+ *	Bits in the CR0 register
+ */
+
+#define CR0_TXON            0x00000008UL
+#define CR0_RXON            0x00000004UL
+#define CR0_STOP            0x00000002UL	/* stop MAC, default = 1 */
+#define CR0_STRT            0x00000001UL	/* start MAC */
+#define CR0_SFRST           0x00008000UL	/* software reset */
+#define CR0_TM1EN           0x00004000UL
+#define CR0_TM0EN           0x00002000UL
+#define CR0_DPOLL           0x00000800UL	/* disable rx/tx auto polling */
+#define CR0_DISAU           0x00000100UL
+#define CR0_XONEN           0x00800000UL
+#define CR0_FDXTFCEN        0x00400000UL	/* full-duplex TX flow control enable */
+#define CR0_FDXRFCEN        0x00200000UL	/* full-duplex RX flow control enable */
+#define CR0_HDXFCEN         0x00100000UL	/* half-duplex flow control enable */
+#define CR0_XHITH1          0x00080000UL	/* TX XON high threshold 1 */
+#define CR0_XHITH0          0x00040000UL	/* TX XON high threshold 0 */
+#define CR0_XLTH1           0x00020000UL	/* TX pause frame low threshold 1 */
+#define CR0_XLTH0           0x00010000UL	/* TX pause frame low threshold 0 */
+#define CR0_GSPRST          0x80000000UL
+#define CR0_FORSRST         0x40000000UL
+#define CR0_FPHYRST         0x20000000UL
+#define CR0_DIAG            0x10000000UL
+#define CR0_INTPCTL         0x04000000UL
+#define CR0_GINTMSK1        0x02000000UL
+#define CR0_GINTMSK0        0x01000000UL
+
+/*
+ *	Bits in the CR1 register
+ */
+
+#define CR1_SFRST           0x80	/* software reset */
+#define CR1_TM1EN           0x40
+#define CR1_TM0EN           0x20
+#define CR1_DPOLL           0x08	/* disable rx/tx auto polling */
+#define CR1_DISAU           0x01
+
+/*
+ *	Bits in the CR2 register
+ */
+
+#define CR2_XONEN           0x80
+#define CR2_FDXTFCEN        0x40	/* full-duplex TX flow control enable */
+#define CR2_FDXRFCEN        0x20	/* full-duplex RX flow control enable */
+#define CR2_HDXFCEN         0x10	/* half-duplex flow control enable */
+#define CR2_XHITH1          0x08	/* TX XON high threshold 1 */
+#define CR2_XHITH0          0x04	/* TX XON high threshold 0 */
+#define CR2_XLTH1           0x02	/* TX pause frame low threshold 1 */
+#define CR2_XLTH0           0x01	/* TX pause frame low threshold 0 */
+
+/*
+ *	Bits in the CR3 register
+ */
+
+#define CR3_GSPRST          0x80
+#define CR3_FORSRST         0x40
+#define CR3_FPHYRST         0x20
+#define CR3_DIAG            0x10
+#define CR3_INTPCTL         0x04
+#define CR3_GINTMSK1        0x02
+#define CR3_GINTMSK0        0x01
+
+#define ISRCTL_UDPINT       0x8000
+#define ISRCTL_TSUPDIS      0x4000
+#define ISRCTL_RSUPDIS      0x2000
+#define ISRCTL_PMSK1        0x1000
+#define ISRCTL_PMSK0        0x0800
+#define ISRCTL_INTPD        0x0400
+#define ISRCTL_HCRLD        0x0200
+#define ISRCTL_SCRLD        0x0100
+
+/*
+ *	Bits in the ISR_CTL1 register
+ */
+
+#define ISRCTL1_UDPINT      0x80
+#define ISRCTL1_TSUPDIS     0x40
+#define ISRCTL1_RSUPDIS     0x20
+#define ISRCTL1_PMSK1       0x10
+#define ISRCTL1_PMSK0       0x08
+#define ISRCTL1_INTPD       0x04
+#define ISRCTL1_HCRLD       0x02
+#define ISRCTL1_SCRLD       0x01
+
+/*
+ *	Bits in the TXE_SR register
+ */
+
+#define TXESR_TFDBS         0x08
+#define TXESR_TDWBS         0x04
+#define TXESR_TDRBS         0x02
+#define TXESR_TDSTR         0x01
+
+/*
+ *	Bits in the RXE_SR register
+ */
+
+#define RXESR_RFDBS         0x08
+#define RXESR_RDWBS         0x04
+#define RXESR_RDRBS         0x02
+#define RXESR_RDSTR         0x01
+
+/*
+ *	Bits in the ISR register
+ */
+
+#define ISR_ISR3            0x80000000UL
+#define ISR_ISR2            0x40000000UL
+#define ISR_ISR1            0x20000000UL
+#define ISR_ISR0            0x10000000UL
+#define ISR_TXSTLI          0x02000000UL
+#define ISR_RXSTLI          0x01000000UL
+#define ISR_HFLD            0x00800000UL
+#define ISR_UDPI            0x00400000UL
+#define ISR_MIBFI           0x00200000UL
+#define ISR_SHDNI           0x00100000UL
+#define ISR_PHYI            0x00080000UL
+#define ISR_PWEI            0x00040000UL
+#define ISR_TMR1I           0x00020000UL
+#define ISR_TMR0I           0x00010000UL
+#define ISR_SRCI            0x00008000UL
+#define ISR_LSTPEI          0x00004000UL
+#define ISR_LSTEI           0x00002000UL
+#define ISR_OVFI            0x00001000UL
+#define ISR_FLONI           0x00000800UL
+#define ISR_RACEI           0x00000400UL
+#define ISR_TXWB1I          0x00000200UL
+#define ISR_TXWB0I          0x00000100UL
+#define ISR_PTX3I           0x00000080UL
+#define ISR_PTX2I           0x00000040UL
+#define ISR_PTX1I           0x00000020UL
+#define ISR_PTX0I           0x00000010UL
+#define ISR_PTXI            0x00000008UL
+#define ISR_PRXI            0x00000004UL
+#define ISR_PPTXI           0x00000002UL
+#define ISR_PPRXI           0x00000001UL
+
+/*
+ *	Bits in the IMR register
+ */
+
+#define IMR_TXSTLM          0x02000000UL
+#define IMR_UDPIM           0x00400000UL
+#define IMR_MIBFIM          0x00200000UL
+#define IMR_SHDNIM          0x00100000UL
+#define IMR_PHYIM           0x00080000UL
+#define IMR_PWEIM           0x00040000UL
+#define IMR_TMR1IM          0x00020000UL
+#define IMR_TMR0IM          0x00010000UL
+
+#define IMR_SRCIM           0x00008000UL
+#define IMR_LSTPEIM         0x00004000UL
+#define IMR_LSTEIM          0x00002000UL
+#define IMR_OVFIM           0x00001000UL
+#define IMR_FLONIM          0x00000800UL
+#define IMR_RACEIM          0x00000400UL
+#define IMR_TXWB1IM         0x00000200UL
+#define IMR_TXWB0IM         0x00000100UL
+
+#define IMR_PTX3IM          0x00000080UL
+#define IMR_PTX2IM          0x00000040UL
+#define IMR_PTX1IM          0x00000020UL
+#define IMR_PTX0IM          0x00000010UL
+#define IMR_PTXIM           0x00000008UL
+#define IMR_PRXIM           0x00000004UL
+#define IMR_PPTXIM          0x00000002UL
+#define IMR_PPRXIM          0x00000001UL
+
+/* 0x0013FB0FUL  =  initial value of IMR */
+
+#define INT_MASK_DEF        ( IMR_PPTXIM|IMR_PPRXIM| IMR_PTXIM|IMR_PRXIM | \
+                            IMR_PWEIM|IMR_TXWB0IM|IMR_TXWB1IM|IMR_FLONIM|  \
+                            IMR_OVFIM|IMR_LSTEIM|IMR_LSTPEIM|IMR_SRCIM|IMR_MIBFIM|\
+                            IMR_SHDNIM |IMR_TMR1IM|IMR_TMR0IM|IMR_TXSTLM )
+
+/*
+ *	Bits in the TDCSR0/1, RDCSR0 register
+ */
+
+#define TRDCSR_DEAD         0x0008
+#define TRDCSR_WAK          0x0004
+#define TRDCSR_ACT          0x0002
+#define TRDCSR_RUN	    0x0001
+
+/*
+ *	Bits in the CAMADDR register
+ */
+
+#define CAMADDR_CAMEN       0x80
+#define CAMADDR_VCAMSL      0x40
+
+/*
+ *	Bits in the CAMCR register
+ */
+
+#define CAMCR_PS1           0x80
+#define CAMCR_PS0           0x40
+#define CAMCR_AITRPKT       0x20
+#define CAMCR_AITR16        0x10
+#define CAMCR_CAMRD         0x08
+#define CAMCR_CAMWR         0x04
+#define CAMCR_PS_CAM_MASK   0x40
+#define CAMCR_PS_CAM_DATA   0x80
+#define CAMCR_PS_MAR        0x00
+
+/*
+ *	Bits in the MIICFG register
+ */
+
+#define MIICFG_MPO1         0x80
+#define MIICFG_MPO0         0x40
+#define MIICFG_MFDC         0x20
+
+/*
+ *	Bits in the MIISR register
+ */
+
+#define MIISR_MIDLE         0x80
+
+/*
+ *	 Bits in the PHYSR0 register
+ */
+
+#define PHYSR0_PHYRST       0x80
+#define PHYSR0_LINKGD       0x40
+#define PHYSR0_FDPX         0x10
+#define PHYSR0_SPDG         0x08
+#define PHYSR0_SPD10        0x04
+#define PHYSR0_RXFLC        0x02
+#define PHYSR0_TXFLC        0x01
+
+/*
+ *	Bits in the PHYSR1 register
+ */
+
+#define PHYSR1_PHYTBI       0x01
+
+/*
+ *	Bits in the MIICR register
+ */
+
+#define MIICR_MAUTO         0x80
+#define MIICR_RCMD          0x40
+#define MIICR_WCMD          0x20
+#define MIICR_MDPM          0x10
+#define MIICR_MOUT          0x08
+#define MIICR_MDO           0x04
+#define MIICR_MDI           0x02
+#define MIICR_MDC           0x01
+
+/*
+ *	Bits in the MIIADR register
+ */
+
+#define MIIADR_SWMPL        0x80
+
+/*
+ *	Bits in the CFGA register
+ */
+
+#define CFGA_PMHCTG         0x08
+#define CFGA_GPIO1PD        0x04
+#define CFGA_ABSHDN         0x02
+#define CFGA_PACPI          0x01
+
+/*
+ *	Bits in the CFGB register
+ */
+
+#define CFGB_GTCKOPT        0x80
+#define CFGB_MIIOPT         0x40
+#define CFGB_CRSEOPT        0x20
+#define CFGB_OFSET          0x10
+#define CFGB_CRANDOM        0x08
+#define CFGB_CAP            0x04
+#define CFGB_MBA            0x02
+#define CFGB_BAKOPT         0x01
+
+/*
+ *	Bits in the CFGC register
+ */
+
+#define CFGC_EELOAD         0x80
+#define CFGC_BROPT          0x40
+#define CFGC_DLYEN          0x20
+#define CFGC_DTSEL          0x10
+#define CFGC_BTSEL          0x08
+#define CFGC_BPS2           0x04	/* bootrom select[2] */
+#define CFGC_BPS1           0x02	/* bootrom select[1] */
+#define CFGC_BPS0           0x01	/* bootrom select[0] */
+
+/*
+ * Bits in the CFGD register
+ */
+
+#define CFGD_IODIS          0x80
+#define CFGD_MSLVDACEN      0x40
+#define CFGD_CFGDACEN       0x20
+#define CFGD_PCI64EN        0x10
+#define CFGD_HTMRL4         0x08
+
+/*
+ *	Bits in the DCFG1 register
+ */
+
+#define DCFG_XMWI           0x8000
+#define DCFG_XMRM           0x4000
+#define DCFG_XMRL           0x2000
+#define DCFG_PERDIS         0x1000
+#define DCFG_MRWAIT         0x0400
+#define DCFG_MWWAIT         0x0200
+#define DCFG_LATMEN         0x0100
+
+/*
+ *	Bits in the MCFG0 register
+ */
+
+#define MCFG_RXARB          0x0080
+#define MCFG_RFT1           0x0020
+#define MCFG_RFT0           0x0010
+#define MCFG_LOWTHOPT       0x0008
+#define MCFG_PQEN           0x0004
+#define MCFG_RTGOPT         0x0002
+#define MCFG_VIDFR          0x0001
+
+/*
+ *	Bits in the MCFG1 register
+ */
+
+#define MCFG_TXARB          0x8000
+#define MCFG_TXQBK1         0x0800
+#define MCFG_TXQBK0         0x0400
+#define MCFG_TXQNOBK        0x0200
+#define MCFG_SNAPOPT        0x0100
+
+/*
+ *	Bits in the PMCC  register
+ */
+
+#define PMCC_DSI            0x80
+#define PMCC_D2_DIS         0x40
+#define PMCC_D1_DIS         0x20
+#define PMCC_D3C_EN         0x10
+#define PMCC_D3H_EN         0x08
+#define PMCC_D2_EN          0x04
+#define PMCC_D1_EN          0x02
+#define PMCC_D0_EN          0x01
+
+/*
+ *	Bits in STICKHW
+ */
+
+#define STICKHW_SWPTAG      0x10
+#define STICKHW_WOLSR       0x08
+#define STICKHW_WOLEN       0x04
+#define STICKHW_DS1         0x02	/* R/W by software/cfg cycle */
+#define STICKHW_DS0         0x01	/* suspend well DS write port */
+
+/*
+ *	Bits in the MIBCR register
+ */
+
+#define MIBCR_MIBISTOK      0x80
+#define MIBCR_MIBISTGO      0x40
+#define MIBCR_MIBINC        0x20
+#define MIBCR_MIBHI         0x10
+#define MIBCR_MIBFRZ        0x08
+#define MIBCR_MIBFLSH       0x04
+#define MIBCR_MPTRINI       0x02
+#define MIBCR_MIBCLR        0x01
+
+/*
+ *	Bits in the EERSV register
+ */
+
+#define EERSV_BOOT_RPL      ((u8) 0x01)	/* Boot method selection for VT6110 */
+
+#define EERSV_BOOT_MASK     ((u8) 0x06)
+#define EERSV_BOOT_INT19    ((u8) 0x00)
+#define EERSV_BOOT_INT18    ((u8) 0x02)
+#define EERSV_BOOT_LOCAL    ((u8) 0x04)
+#define EERSV_BOOT_BEV      ((u8) 0x06)
+
+
+/*
+ *	Bits in BPCMD
+ */
+
+#define BPCMD_BPDNE         0x80
+#define BPCMD_EBPWR         0x02
+#define BPCMD_EBPRD         0x01
+
+/*
+ *	Bits in the EECSR register
+ */
+
+#define EECSR_EMBP          0x40	/* eeprom embeded programming */
+#define EECSR_RELOAD        0x20	/* eeprom content reload */
+#define EECSR_DPM           0x10	/* eeprom direct programming */
+#define EECSR_ECS           0x08	/* eeprom CS pin */
+#define EECSR_ECK           0x04	/* eeprom CK pin */
+#define EECSR_EDI           0x02	/* eeprom DI pin */
+#define EECSR_EDO           0x01	/* eeprom DO pin */
+
+/*
+ *	Bits in the EMBCMD register
+ */
+
+#define EMBCMD_EDONE        0x80
+#define EMBCMD_EWDIS        0x08
+#define EMBCMD_EWEN         0x04
+#define EMBCMD_EWR          0x02
+#define EMBCMD_ERD          0x01
+
+/*
+ *	Bits in TESTCFG register
+ */
+
+#define TESTCFG_HBDIS       0x80
+
+/*
+ *	Bits in CHIPGCR register
+ */
+
+#define CHIPGCR_FCGMII      0x80
+#define CHIPGCR_FCFDX       0x40
+#define CHIPGCR_FCRESV      0x20
+#define CHIPGCR_FCMODE      0x10
+#define CHIPGCR_LPSOPT      0x08
+#define CHIPGCR_TM1US       0x04
+#define CHIPGCR_TM0US       0x02
+#define CHIPGCR_PHYINTEN    0x01
+
+/*
+ *	Bits in WOLCR0
+ */
+
+#define WOLCR_MSWOLEN7      0x0080	/* enable pattern match filtering */
+#define WOLCR_MSWOLEN6      0x0040
+#define WOLCR_MSWOLEN5      0x0020
+#define WOLCR_MSWOLEN4      0x0010
+#define WOLCR_MSWOLEN3      0x0008
+#define WOLCR_MSWOLEN2      0x0004
+#define WOLCR_MSWOLEN1      0x0002
+#define WOLCR_MSWOLEN0      0x0001
+#define WOLCR_ARP_EN        0x0001
+
+/*
+ *	Bits in WOLCR1
+ */
+
+#define WOLCR_LINKOFF_EN      0x0800	/* link off detected enable */
+#define WOLCR_LINKON_EN       0x0400	/* link on detected enable */
+#define WOLCR_MAGIC_EN        0x0200	/* magic packet filter enable */
+#define WOLCR_UNICAST_EN      0x0100	/* unicast filter enable */
+
+
+/*
+ *	Bits in PWCFG
+ */
+
+#define PWCFG_PHYPWOPT          0x80	/* internal MII I/F timing */
+#define PWCFG_PCISTICK          0x40	/* PCI sticky R/W enable */
+#define PWCFG_WOLTYPE           0x20	/* pulse(1) or button (0) */
+#define PWCFG_LEGCY_WOL         0x10
+#define PWCFG_PMCSR_PME_SR      0x08
+#define PWCFG_PMCSR_PME_EN      0x04	/* control by PCISTICK */
+#define PWCFG_LEGACY_WOLSR      0x02	/* Legacy WOL_SR shadow */
+#define PWCFG_LEGACY_WOLEN      0x01	/* Legacy WOL_EN shadow */
+
+/*
+ *	Bits in WOLCFG
+ */
+
+#define WOLCFG_PMEOVR           0x80	/* for legacy use, force PMEEN always */
+#define WOLCFG_SAM              0x20	/* accept multicast case reset, default=0 */
+#define WOLCFG_SAB              0x10	/* accept broadcast case reset, default=0 */
+#define WOLCFG_SMIIACC          0x08	/* ?? */
+#define WOLCFG_SGENWH           0x02
+#define WOLCFG_PHYINTEN         0x01	/* 0:PHYINT trigger enable, 1:use internal MII
+					   to report status change */
+/*
+ *	Bits in WOLSR1
+ */
+
+#define WOLSR_LINKOFF_INT      0x0800
+#define WOLSR_LINKON_INT       0x0400
+#define WOLSR_MAGIC_INT        0x0200
+#define WOLSR_UNICAST_INT      0x0100
+
+/*
+ *	Ethernet address filter type
+ */
+
+#define PKT_TYPE_NONE               0x0000	/* Turn off receiver */
+#define PKT_TYPE_DIRECTED           0x0001	/* obselete, directed address is always accepted */
+#define PKT_TYPE_MULTICAST          0x0002
+#define PKT_TYPE_ALL_MULTICAST      0x0004
+#define PKT_TYPE_BROADCAST          0x0008
+#define PKT_TYPE_PROMISCUOUS        0x0020
+#define PKT_TYPE_LONG               0x2000	/* NOTE.... the definition of LONG is >2048 bytes in our chip */
+#define PKT_TYPE_RUNT               0x4000
+#define PKT_TYPE_ERROR              0x8000	/* Accept error packets, e.g. CRC error */
+
+/*
+ *	Loopback mode
+ */
+
+#define MAC_LB_NONE         0x00
+#define MAC_LB_INTERNAL     0x01
+#define MAC_LB_EXTERNAL     0x02
+
+/*
+ *	Enabled mask value of irq
+ */
+
+#if defined(_SIM)
+#define IMR_MASK_VALUE      0x0033FF0FUL	/* initial value of IMR
+						   set IMR0 to 0x0F according to spec */
+
+#else
+#define IMR_MASK_VALUE      0x0013FB0FUL	/* initial value of IMR
+						   ignore MIBFI,RACEI to
+						   reduce intr. frequency
+						   NOTE.... do not enable NoBuf int mask at driver driver
+						   when (1) NoBuf -> RxThreshold = SF
+						   (2) OK    -> RxThreshold = original value
+						 */
+#endif
+
+/*
+ *	Revision id
+ */
+
+#define REV_ID_VT3119_A0	0x00
+#define REV_ID_VT3119_A1	0x01
+#define REV_ID_VT3216_A0	0x10
+
+/*
+ *	Max time out delay time
+ */
+
+#define W_MAX_TIMEOUT       0x0FFFU
+
+
+/*
+ *	MAC registers as a structure. Cannot be directly accessed this
+ *	way but generates offsets for readl/writel() calls
+ */
+
+struct mac_regs {
+	volatile u8 PAR[6];	/* 0x00 */
+	volatile u8 RCR;
+	volatile u8 TCR;
+
+	volatile u32 CR0Set;	/* 0x08 */
+	volatile u32 CR0Clr;	/* 0x0C */
+
+	volatile u8 MARCAM[8];	/* 0x10 */
+
+	volatile u32 DecBaseHi;	/* 0x18 */
+	volatile u16 DbfBaseHi;	/* 0x1C */
+	volatile u16 reserved_1E;
+
+	volatile u16 ISRCTL;	/* 0x20 */
+	volatile u8 TXESR;
+	volatile u8 RXESR;
+
+	volatile u32 ISR;	/* 0x24 */
+	volatile u32 IMR;
+
+	volatile u32 TDStatusPort;	/* 0x2C */
+
+	volatile u16 TDCSRSet;	/* 0x30 */
+	volatile u8 RDCSRSet;
+	volatile u8 reserved_33;
+	volatile u16 TDCSRClr;
+	volatile u8 RDCSRClr;
+	volatile u8 reserved_37;
+
+	volatile u32 RDBaseLo;	/* 0x38 */
+	volatile u16 RDIdx;	/* 0x3C */
+	volatile u16 reserved_3E;
+
+	volatile u32 TDBaseLo[4];	/* 0x40 */
+
+	volatile u16 RDCSize;	/* 0x50 */
+	volatile u16 TDCSize;	/* 0x52 */
+	volatile u16 TDIdx[4];	/* 0x54 */
+	volatile u16 tx_pause_timer;	/* 0x5C */
+	volatile u16 RBRDU;	/* 0x5E */
+
+	volatile u32 FIFOTest0;	/* 0x60 */
+	volatile u32 FIFOTest1;	/* 0x64 */
+
+	volatile u8 CAMADDR;	/* 0x68 */
+	volatile u8 CAMCR;	/* 0x69 */
+	volatile u8 GFTEST;	/* 0x6A */
+	volatile u8 FTSTCMD;	/* 0x6B */
+
+	volatile u8 MIICFG;	/* 0x6C */
+	volatile u8 MIISR;
+	volatile u8 PHYSR0;
+	volatile u8 PHYSR1;
+	volatile u8 MIICR;
+	volatile u8 MIIADR;
+	volatile u16 MIIDATA;
+
+	volatile u16 SoftTimer0;	/* 0x74 */
+	volatile u16 SoftTimer1;
+
+	volatile u8 CFGA;	/* 0x78 */
+	volatile u8 CFGB;
+	volatile u8 CFGC;
+	volatile u8 CFGD;
+
+	volatile u16 DCFG;	/* 0x7C */
+	volatile u16 MCFG;
+
+	volatile u8 TBIST;	/* 0x80 */
+	volatile u8 RBIST;
+	volatile u8 PMCPORT;
+	volatile u8 STICKHW;
+
+	volatile u8 MIBCR;	/* 0x84 */
+	volatile u8 reserved_85;
+	volatile u8 rev_id;
+	volatile u8 PORSTS;
+
+	volatile u32 MIBData;	/* 0x88 */
+
+	volatile u16 EEWrData;
+
+	volatile u8 reserved_8E;
+	volatile u8 BPMDWr;
+	volatile u8 BPCMD;
+	volatile u8 BPMDRd;
+
+	volatile u8 EECHKSUM;	/* 0x92 */
+	volatile u8 EECSR;
+
+	volatile u16 EERdData;	/* 0x94 */
+	volatile u8 EADDR;
+	volatile u8 EMBCMD;
+
+
+	volatile u8 JMPSR0;	/* 0x98 */
+	volatile u8 JMPSR1;
+	volatile u8 JMPSR2;
+	volatile u8 JMPSR3;
+	volatile u8 CHIPGSR;	/* 0x9C */
+	volatile u8 TESTCFG;
+	volatile u8 DEBUG;
+	volatile u8 CHIPGCR;
+
+	volatile u16 WOLCRSet;	/* 0xA0 */
+	volatile u8 PWCFGSet;
+	volatile u8 WOLCFGSet;
+
+	volatile u16 WOLCRClr;	/* 0xA4 */
+	volatile u8 PWCFGCLR;
+	volatile u8 WOLCFGClr;
+
+	volatile u16 WOLSRSet;	/* 0xA8 */
+	volatile u16 reserved_AA;
+
+	volatile u16 WOLSRClr;	/* 0xAC */
+	volatile u16 reserved_AE;
+
+	volatile u16 PatternCRC[8];	/* 0xB0 */
+	volatile u32 ByteMask[4][4];	/* 0xC0 */
+} __attribute__ ((__packed__));
+
+
+enum hw_mib {
+	HW_MIB_ifRxAllPkts = 0,
+	HW_MIB_ifRxOkPkts,
+	HW_MIB_ifTxOkPkts,
+	HW_MIB_ifRxErrorPkts,
+	HW_MIB_ifRxRuntOkPkt,
+	HW_MIB_ifRxRuntErrPkt,
+	HW_MIB_ifRx64Pkts,
+	HW_MIB_ifTx64Pkts,
+	HW_MIB_ifRx65To127Pkts,
+	HW_MIB_ifTx65To127Pkts,
+	HW_MIB_ifRx128To255Pkts,
+	HW_MIB_ifTx128To255Pkts,
+	HW_MIB_ifRx256To511Pkts,
+	HW_MIB_ifTx256To511Pkts,
+	HW_MIB_ifRx512To1023Pkts,
+	HW_MIB_ifTx512To1023Pkts,
+	HW_MIB_ifRx1024To1518Pkts,
+	HW_MIB_ifTx1024To1518Pkts,
+	HW_MIB_ifTxEtherCollisions,
+	HW_MIB_ifRxPktCRCE,
+	HW_MIB_ifRxJumboPkts,
+	HW_MIB_ifTxJumboPkts,
+	HW_MIB_ifRxMacControlFrames,
+	HW_MIB_ifTxMacControlFrames,
+	HW_MIB_ifRxPktFAE,
+	HW_MIB_ifRxLongOkPkt,
+	HW_MIB_ifRxLongPktErrPkt,
+	HW_MIB_ifTXSQEErrors,
+	HW_MIB_ifRxNobuf,
+	HW_MIB_ifRxSymbolErrors,
+	HW_MIB_ifInRangeLengthErrors,
+	HW_MIB_ifLateCollisions,
+	HW_MIB_SIZE
+};
+
+enum chip_type {
+	CHIP_TYPE_VT6110 = 1,
+};
+
+struct velocity_info_tbl {
+	enum chip_type chip_id;
+	char *name;
+	int io_size;
+	int txqueue;
+	u32 flags;
+};
+
+static struct velocity_info_tbl *info;
+
+#define mac_hw_mibs_init(regs) {\
+	BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+	BYTE_REG_BITS_ON(MIBCR_MIBCLR,&((regs)->MIBCR));\
+	do {}\
+		while (BYTE_REG_BITS_IS_ON(MIBCR_MIBCLR,&((regs)->MIBCR)));\
+	BYTE_REG_BITS_OFF(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+}
+
+#define mac_read_isr(regs)  		readl(&((regs)->ISR))
+#define mac_write_isr(regs, x)  	writel((x),&((regs)->ISR))
+#define mac_clear_isr(regs) 		writel(0xffffffffL,&((regs)->ISR))
+
+#define mac_write_int_mask(mask, regs) 	writel((mask),&((regs)->IMR));
+#define mac_disable_int(regs)       	writel(CR0_GINTMSK1,&((regs)->CR0Clr))
+#define mac_enable_int(regs)    	writel(CR0_GINTMSK1,&((regs)->CR0Set))
+
+#define mac_hw_mibs_read(regs, MIBs) {\
+	int i;\
+	BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
+	for (i=0;i<HW_MIB_SIZE;i++) {\
+		(MIBs)[i]=readl(&((regs)->MIBData));\
+	}\
+}
+
+#define mac_set_dma_length(regs, n) {\
+	BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
+}
+
+#define mac_set_rx_thresh(regs, n) {\
+	BYTE_REG_BITS_SET((n),(MCFG_RFT0|MCFG_RFT1),&((regs)->MCFG));\
+}
+
+#define mac_rx_queue_run(regs) {\
+	writeb(TRDCSR_RUN, &((regs)->RDCSRSet));\
+}
+
+#define mac_rx_queue_wake(regs) {\
+	writeb(TRDCSR_WAK, &((regs)->RDCSRSet));\
+}
+
+#define mac_tx_queue_run(regs, n) {\
+	writew(TRDCSR_RUN<<((n)*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_tx_queue_wake(regs, n) {\
+	writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_eeprom_reload(regs) {\
+	int i=0;\
+	BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
+	do {\
+		udelay(10);\
+		if (i++>0x1000) {\
+			break;\
+		}\
+	}while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
+}
+
+enum velocity_cam_type {
+	VELOCITY_VLAN_ID_CAM = 0,
+	VELOCITY_MULTICAST_CAM
+};
+
+/**
+ *	mac_get_cam_mask	-	Read a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: buffer to store mask
+ *	@cam_type: CAM to fetch
+ *
+ *	Fetch the mask bits of the selected CAM and store them into the
+ *	provided mask buffer.
+ */
+
+static inline void mac_get_cam_mask(struct mac_regs *regs, u8 * mask,
+				    enum velocity_cam_type cam_type)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
+	else
+		writeb(0, &regs->CAMADDR);
+
+	/* read mask */
+	for (i = 0; i < 8; i++)
+		*mask++ = readb(&(regs->MARCAM[i]));
+
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+
+}
+
+/**
+ *	mac_set_cam_mask	-	Set a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: CAM mask to load
+ *	@cam_type: CAM to store
+ *
+ *	Store a new mask into a CAM
+ */
+
+static inline void mac_set_cam_mask(struct mac_regs *regs, u8 * mask,
+				    enum velocity_cam_type cam_type)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+	for (i = 0; i < 8; i++) {
+		writeb(*mask++, &(regs->MARCAM[i]));
+	}
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+}
+
+/**
+ *	mac_set_cam	-	set CAM data
+ *	@regs: register block of this velocity
+ *	@idx: Cam index
+ *	@addr: 2 or 6 bytes of CAM data
+ *	@cam_type: CAM to load
+ *
+ *	Load an address or vlan tag into a CAM
+ */
+
+static inline void mac_set_cam(struct mac_regs *regs, int idx, u8 * addr,
+			       enum velocity_cam_type cam_type)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx,
+		       &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writew(*((u16 *) addr), &regs->MARCAM[0]);
+	else {
+		for (i = 0; i < 6; i++) {
+			writeb(*addr++, &(regs->MARCAM[i]));
+		}
+	}
+	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+	udelay(10);
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+}
+
+/**
+ *	mac_get_cam	-	fetch CAM data
+ *	@regs: register block of this velocity
+ *	@idx: Cam index
+ *	@addr: buffer to hold up to 6 bytes of CAM data
+ *	@cam_type: CAM to load
+ *
+ *	Load an address or vlan tag from a CAM into the buffer provided by
+ *	the caller. VLAN tags are 2 bytes the address cam entries are 6.
+ */
+
+static inline void mac_get_cam(struct mac_regs *regs, int idx, u8 * addr,
+			       enum velocity_cam_type cam_type)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx,
+		       &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+	BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
+
+	udelay(10);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		*((u16 *) addr) = readw(&(regs->MARCAM[0]));
+	else
+		for (i = 0; i < 6; i++, addr++)
+			*((u8 *) addr) = readb(&(regs->MARCAM[i]));
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0,
+			  &regs->CAMCR);
+}
+
+/**
+ *	mac_wol_reset	-	reset WOL after exiting low power
+ *	@regs: register block of this velocity
+ *
+ *	Called after we drop out of wake on lan mode in order to
+ *	reset the Wake on lan features. This function doesn't restore
+ *	the rest of the logic from the result of sleep/wakeup
+ */
+
+inline static void mac_wol_reset(struct mac_regs *regs)
+{
+
+	/* Turn off SWPTAG right after leaving power mode */
+	BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+	/* clear sticky bits */
+	BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+	BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+	BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+	/* disable force PME-enable */
+	writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+	/* disable power-event config bit */
+	writew(0xFFFF, &regs->WOLCRClr);
+	/* clear power status */
+	writew(0xFFFF, &regs->WOLSRClr);
+}
+
+
+/*
+ * Header for WOL definitions. Used to compute hashes
+ */
+
+typedef u8 MCAM_ADDR[ETH_ALEN];
+
+struct arp_packet {
+	u8 dest_mac[ETH_ALEN];
+	u8 src_mac[ETH_ALEN];
+	u16 type;
+	u16 ar_hrd;
+	u16 ar_pro;
+	u8 ar_hln;
+	u8 ar_pln;
+	u16 ar_op;
+	u8 ar_sha[ETH_ALEN];
+	u8 ar_sip[4];
+	u8 ar_tha[ETH_ALEN];
+	u8 ar_tip[4];
+} __attribute__ ((__packed__));
+
+struct _magic_packet {
+	u8 dest_mac[6];
+	u8 src_mac[6];
+	u16 type;
+	u8 MAC[16][6];
+	u8 password[6];
+} __attribute__ ((__packed__));
+
+/*
+ *	Store for chip context when saving and restoring status. Not
+ *	all fields are saved/restored currently.
+ */
+
+struct velocity_context {
+	u8 mac_reg[256];
+	MCAM_ADDR cam_addr[MCAM_SIZE];
+	u16 vcam[VCAM_SIZE];
+	u32 cammask[2];
+	u32 patcrc[2];
+	u32 pattern[8];
+};
+
+
+/*
+ *	MII registers.
+ */
+
+
+/*
+ *	Registers in the MII (offset unit is WORD)
+ */
+
+#define MII_REG_BMCR        0x00	// physical address
+#define MII_REG_BMSR        0x01	//
+#define MII_REG_PHYID1      0x02	// OUI
+#define MII_REG_PHYID2      0x03	// OUI + Module ID + REV ID
+#define MII_REG_ANAR        0x04	//
+#define MII_REG_ANLPAR      0x05	//
+#define MII_REG_G1000CR     0x09	//
+#define MII_REG_G1000SR     0x0A	//
+#define MII_REG_MODCFG      0x10	//
+#define MII_REG_TCSR        0x16	//
+#define MII_REG_PLED        0x1B	//
+// NS, MYSON only
+#define MII_REG_PCR         0x17	//
+// ESI only
+#define MII_REG_PCSR        0x17	//
+#define MII_REG_AUXCR       0x1C	//
+
+// Marvell 88E1000/88E1000S
+#define MII_REG_PSCR        0x10	// PHY specific control register
+
+//
+// Bits in the BMCR register
+//
+#define BMCR_RESET          0x8000	//
+#define BMCR_LBK            0x4000	//
+#define BMCR_SPEED100       0x2000	//
+#define BMCR_AUTO           0x1000	//
+#define BMCR_PD             0x0800	//
+#define BMCR_ISO            0x0400	//
+#define BMCR_REAUTO         0x0200	//
+#define BMCR_FDX            0x0100	//
+#define BMCR_SPEED1G        0x0040	//
+//
+// Bits in the BMSR register
+//
+#define BMSR_AUTOCM         0x0020	//
+#define BMSR_LNK            0x0004	//
+
+//
+// Bits in the ANAR register
+//
+#define ANAR_ASMDIR         0x0800	// Asymmetric PAUSE support
+#define ANAR_PAUSE          0x0400	// Symmetric PAUSE Support
+#define ANAR_T4             0x0200	//
+#define ANAR_TXFD           0x0100	//
+#define ANAR_TX             0x0080	//
+#define ANAR_10FD           0x0040	//
+#define ANAR_10             0x0020	//
+//
+// Bits in the ANLPAR register
+//
+#define ANLPAR_ASMDIR       0x0800	// Asymmetric PAUSE support
+#define ANLPAR_PAUSE        0x0400	// Symmetric PAUSE Support
+#define ANLPAR_T4           0x0200	//
+#define ANLPAR_TXFD         0x0100	//
+#define ANLPAR_TX           0x0080	//
+#define ANLPAR_10FD         0x0040	//
+#define ANLPAR_10           0x0020	//
+
+//
+// Bits in the G1000CR register
+//
+#define G1000CR_1000FD      0x0200	// PHY is 1000-T Full-duplex capable
+#define G1000CR_1000        0x0100	// PHY is 1000-T Half-duplex capable
+
+//
+// Bits in the G1000SR register
+//
+#define G1000SR_1000FD      0x0800	// LP PHY is 1000-T Full-duplex capable
+#define G1000SR_1000        0x0400	// LP PHY is 1000-T Half-duplex capable
+
+#define TCSR_ECHODIS        0x2000	//
+#define AUXCR_MDPPS         0x0004	//
+
+// Bits in the PLED register
+#define PLED_LALBE			0x0004	//
+
+// Marvell 88E1000/88E1000S Bits in the PHY specific control register (10h)
+#define PSCR_ACRSTX         0x0800	// Assert CRS on Transmit
+
+#define PHYID_CICADA_CS8201 0x000FC410UL
+#define PHYID_VT3216_32BIT  0x000FC610UL
+#define PHYID_VT3216_64BIT  0x000FC600UL
+#define PHYID_MARVELL_1000  0x01410C50UL
+#define PHYID_MARVELL_1000S 0x01410C40UL
+
+#define PHYID_REV_ID_MASK   0x0000000FUL
+
+#define PHYID_GET_PHY_REV_ID(i)     ((i) & PHYID_REV_ID_MASK)
+#define PHYID_GET_PHY_ID(i)         ((i) & ~PHYID_REV_ID_MASK)
+
+#define MII_REG_BITS_ON(x,i,p) do {\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    (w)|=(x);\
+    velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_OFF(x,i,p) do {\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    (w)&=(~(x));\
+    velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_IS_ON(x,i,p) ({\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    ((int) ((w) & (x)));})
+
+#define MII_GET_PHY_ID(p) ({\
+    u32 id;  \
+    u16 id2; \
+    u16 id1; \
+    velocity_mii_read((p),MII_REG_PHYID2, &id2);\
+    velocity_mii_read((p),MII_REG_PHYID1, &id1);\
+    id = ( ( (u32)id2 ) << 16 ) | id1;		\
+    (id);})
+
+#ifdef LINUX
+/*
+ * Inline debug routine
+ */
+
+
+enum velocity_msg_level {
+	MSG_LEVEL_ERR = 0,	//Errors that will cause abnormal operation.
+	MSG_LEVEL_NOTICE = 1,	//Some errors need users to be notified.
+	MSG_LEVEL_INFO = 2,	//Normal message.
+	MSG_LEVEL_VERBOSE = 3,	//Will report all trival errors.
+	MSG_LEVEL_DEBUG = 4	//Only for debug purpose.
+};
+
+#ifdef VELOCITY_DEBUG
+#define ASSERT(x) { \
+	if (!(x)) { \
+		printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
+			__FUNCTION__, __LINE__);\
+		BUG(); \
+	}\
+}
+#define VELOCITY_DBG(p,args...) printk(p, ##args)
+#else
+#define ASSERT(x)
+#define VELOCITY_DBG(x)
+#endif
+
+#define VELOCITY_PRT(l, p, args...) do {if (l<=msglevel) printf( p ,##args);} while (0)
+
+#define VELOCITY_PRT_CAMMASK(p,t) {\
+	int i;\
+	if ((t)==VELOCITY_MULTICAST_CAM) {\
+        	for (i=0;i<(MCAM_SIZE/8);i++)\
+			printk("%02X",(p)->mCAMmask[i]);\
+	}\
+	else {\
+		for (i=0;i<(VCAM_SIZE/8);i++)\
+			printk("%02X",(p)->vCAMmask[i]);\
+	}\
+	printk("\n");\
+}
+
+#endif
+
+#define     VELOCITY_WOL_MAGIC             0x00000000UL
+#define     VELOCITY_WOL_PHY               0x00000001UL
+#define     VELOCITY_WOL_ARP               0x00000002UL
+#define     VELOCITY_WOL_UCAST             0x00000004UL
+#define     VELOCITY_WOL_BCAST             0x00000010UL
+#define     VELOCITY_WOL_MCAST             0x00000020UL
+#define     VELOCITY_WOL_MAGIC_SEC         0x00000040UL
+
+/*
+ *	Flags for options
+ */
+
+#define     VELOCITY_FLAGS_TAGGING         0x00000001UL
+#define     VELOCITY_FLAGS_TX_CSUM         0x00000002UL
+#define     VELOCITY_FLAGS_RX_CSUM         0x00000004UL
+#define     VELOCITY_FLAGS_IP_ALIGN        0x00000008UL
+#define     VELOCITY_FLAGS_VAL_PKT_LEN     0x00000010UL
+
+#define     VELOCITY_FLAGS_FLOW_CTRL       0x01000000UL
+
+/*
+ *	Flags for driver status
+ */
+
+#define     VELOCITY_FLAGS_OPENED          0x00010000UL
+#define     VELOCITY_FLAGS_VMNS_CONNECTED  0x00020000UL
+#define     VELOCITY_FLAGS_VMNS_COMMITTED  0x00040000UL
+#define     VELOCITY_FLAGS_WOL_ENABLED     0x00080000UL
+
+/*
+ *	Flags for MII status
+ */
+
+#define     VELOCITY_LINK_FAIL             0x00000001UL
+#define     VELOCITY_SPEED_10              0x00000002UL
+#define     VELOCITY_SPEED_100             0x00000004UL
+#define     VELOCITY_SPEED_1000            0x00000008UL
+#define     VELOCITY_DUPLEX_FULL           0x00000010UL
+#define     VELOCITY_AUTONEG_ENABLE        0x00000020UL
+#define     VELOCITY_FORCED_BY_EEPROM      0x00000040UL
+
+/*
+ *	For velocity_set_media_duplex
+ */
+
+#define     VELOCITY_LINK_CHANGE           0x00000001UL
+
+enum speed_opt {
+	SPD_DPX_AUTO = 0,
+	SPD_DPX_100_HALF = 1,
+	SPD_DPX_100_FULL = 2,
+	SPD_DPX_10_HALF = 3,
+	SPD_DPX_10_FULL = 4
+};
+
+enum velocity_init_type {
+	VELOCITY_INIT_COLD = 0,
+	VELOCITY_INIT_RESET,
+	VELOCITY_INIT_WOL
+};
+
+enum velocity_flow_cntl_type {
+	FLOW_CNTL_DEFAULT = 1,
+	FLOW_CNTL_TX,
+	FLOW_CNTL_RX,
+	FLOW_CNTL_TX_RX,
+	FLOW_CNTL_DISABLE,
+};
+
+struct velocity_opt {
+	int numrx;		/* Number of RX descriptors */
+	int numtx;		/* Number of TX descriptors */
+	enum speed_opt spd_dpx;	/* Media link mode */
+	int vid;		/* vlan id */
+	int DMA_length;		/* DMA length */
+	int rx_thresh;		/* RX_THRESH */
+	int flow_cntl;
+	int wol_opts;		/* Wake on lan options */
+	int td_int_count;
+	int int_works;
+	int rx_bandwidth_hi;
+	int rx_bandwidth_lo;
+	int rx_bandwidth_en;
+	u32 flags;
+};
+
+#define RX_DESC_MIN     4
+#define RX_DESC_MAX     255
+#define RX_DESC_DEF     RX_DESC_MIN
+
+#define TX_DESC_MIN     1
+#define TX_DESC_MAX     256
+#define TX_DESC_DEF     TX_DESC_MIN
+
+static struct velocity_info {
+//      struct list_head list;
+
+	struct pci_device *pdev;
+//      struct net_device *dev;
+//      struct net_device_stats stats;
+
+#ifdef CONFIG_PM
+	u32 pci_state[16];
+#endif
+
+//      dma_addr_t rd_pool_dma;
+//      dma_addr_t td_pool_dma[TX_QUEUE_NO];
+
+//      dma_addr_t tx_bufs_dma;
+	u8 *tx_bufs;
+
+	u8 ip_addr[4];
+	enum chip_type chip_id;
+
+	struct mac_regs *mac_regs;
+	unsigned long memaddr;
+	unsigned long ioaddr;
+	u32 io_size;
+
+	u8 rev_id;
+
+#define AVAIL_TD(p,q)   ((p)->options.numtx-((p)->td_used[(q)]))
+
+	int num_txq;
+
+	volatile int td_used[TX_QUEUE_NO];
+	int td_curr;
+	int td_tail[TX_QUEUE_NO];
+	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
+	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	unsigned char *tx_buffs;
+	unsigned char *rx_buffs;
+
+	unsigned char *txb;
+	unsigned char *rxb;
+	struct tx_desc *td_rings;
+	struct velocity_td_info *td_infos[TX_QUEUE_NO];
+
+	int rd_curr;
+	int rd_dirty;
+	u32 rd_filled;
+	struct rx_desc *rd_ring;
+	struct velocity_rd_info *rd_info;	/* It's an array */
+
+#define GET_RD_BY_IDX(vptr, idx)   (vptr->rd_ring[idx])
+	u32 mib_counter[MAX_HW_MIB_COUNTER];
+	struct velocity_opt options;
+
+	u32 int_mask;
+
+	u32 flags;
+
+	int rx_buf_sz;
+	u32 mii_status;
+	u32 phy_id;
+	int multicast_limit;
+
+	u8 vCAMmask[(VCAM_SIZE / 8)];
+	u8 mCAMmask[(MCAM_SIZE / 8)];
+
+//      spinlock_t lock;
+
+	int wol_opts;
+	u8 wol_passwd[6];
+
+	struct velocity_context context;
+
+	u32 ticks;
+	u32 rx_bytes;
+
+} vptx;
+
+static struct velocity_info *vptr;
+
+#ifdef LINUX
+/**
+ *	velocity_get_ip		-	find an IP address for the device
+ *	@vptr: Velocity to query
+ *
+ *	Dig out an IP address for this interface so that we can
+ *	configure wakeup with WOL for ARP. If there are multiple IP
+ *	addresses on this chain then we use the first - multi-IP WOL is not
+ *	supported.
+ *
+ *	CHECK ME: locking
+ */
+
+inline static int velocity_get_ip(struct velocity_info *vptr)
+{
+	struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr;
+	struct in_ifaddr *ifa;
+
+	if (in_dev != NULL) {
+		ifa = (struct in_ifaddr *) in_dev->ifa_list;
+		if (ifa != NULL) {
+			memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ *	velocity_update_hw_mibs	-	fetch MIB counters from chip
+ *	@vptr: velocity to update
+ *
+ *	The velocity hardware keeps certain counters in the hardware
+ * 	side. We need to read these when the user asks for statistics
+ *	or when they overflow (causing an interrupt). The read of the
+ *	statistic clears it, so we keep running master counters in user
+ *	space.
+ */
+
+static inline void velocity_update_hw_mibs(struct velocity_info *vptr)
+{
+	u32 tmp;
+	int i;
+	BYTE_REG_BITS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR));
+
+	while (BYTE_REG_BITS_IS_ON
+	       (MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR)));
+
+	BYTE_REG_BITS_ON(MIBCR_MPTRINI, &(vptr->mac_regs->MIBCR));
+	for (i = 0; i < HW_MIB_SIZE; i++) {
+		tmp = readl(&(vptr->mac_regs->MIBData)) & 0x00FFFFFFUL;
+		vptr->mib_counter[i] += tmp;
+	}
+}
+#endif
+/**
+ *	init_flow_control_register 	-	set up flow control
+ *	@vptr: velocity to configure
+ *
+ *	Configure the flow control registers for this velocity device.
+ */
+
+static inline void init_flow_control_register(struct velocity_info *vptr)
+{
+	struct mac_regs *regs = vptr->mac_regs;
+
+	/* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1}
+	   depend on RD=64, and Turn on XNOEN in FlowCR1 */
+	writel((CR0_XONEN | CR0_XHITH1 | CR0_XLTH1 | CR0_XLTH0),
+	       &regs->CR0Set);
+	writel((CR0_FDXTFCEN | CR0_FDXRFCEN | CR0_HDXFCEN | CR0_XHITH0),
+	       &regs->CR0Clr);
+
+	/* Set TxPauseTimer to 0xFFFF */
+	writew(0xFFFF, &regs->tx_pause_timer);
+
+	/* Initialize RBRDU to Rx buffer count. */
+	writew(vptr->options.numrx, &regs->RBRDU);
+}
+
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.c
new file mode 100644
index 0000000..54e962d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.c
@@ -0,0 +1,419 @@
+/*
+ * (c) Copyright 2010 Stefan Hajnoczi <stefanha at gmail.com>
+ *
+ * based on the Etherboot virtio-net driver
+ *
+ *  (c) Copyright 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ *  Copyright IBM Corp. 2007
+ *  Authors: Anthony Liguori  <aliguori at us.ibm.com>
+ *
+ *  some parts from Linux Virtio Ring
+ *
+ *  Copyright Rusty Russell IBM Corporation 2007
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <stdlib.h>
+#include <ipxe/list.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/virtio-ring.h>
+#include <ipxe/virtio-pci.h>
+#include "virtio-net.h"
+
+/*
+ * Virtio network device driver
+ *
+ * Specification:
+ * http://ozlabs.org/~rusty/virtio-spec/
+ *
+ * The virtio network device is supported by Linux virtualization software
+ * including QEMU/KVM and lguest.  This driver supports the virtio over PCI
+ * transport; virtual machines have one virtio-net PCI adapter per NIC.
+ *
+ * Virtio-net is different from hardware NICs because virtio devices
+ * communicate with the hypervisor via virtqueues, not traditional descriptor
+ * rings.  Virtqueues are unordered queues, they support add_buf() and
+ * get_buf() operations.  To transmit a packet, the driver has to add the
+ * packet buffer onto the virtqueue.  To receive a packet, the driver must
+ * first add an empty buffer to the virtqueue and then get the filled packet
+ * buffer on completion.
+ *
+ * Virtqueues are an abstraction that is commonly implemented using the vring
+ * descriptor ring layout.  The vring is the actual shared memory structure
+ * that allows the virtual machine to communicate buffers with the hypervisor.
+ * Because the vring layout is optimized for flexibility and performance rather
+ * than space, it is heavy-weight and allocated like traditional descriptor
+ * rings in the open() function of the driver and not in probe().
+ *
+ * There is no true interrupt enable/disable.  Virtqueues have callback
+ * enable/disable flags but these are only hints.  The hypervisor may still
+ * raise an interrupt.  Nevertheless, this driver disables callbacks in the
+ * hopes of avoiding interrupts.
+ */
+
+/* Driver types are declared here so virtio-net.h can be easily synced with its
+ * Linux source.
+ */
+
+/* Virtqueue indicies */
+enum {
+	RX_INDEX = 0,
+	TX_INDEX,
+	QUEUE_NB
+};
+
+enum {
+	/** Max number of pending rx packets */
+	NUM_RX_BUF = 8,
+
+	/** Max Ethernet frame length, including FCS and VLAN tag */
+	RX_BUF_SIZE = 1522,
+};
+
+struct virtnet_nic {
+	/** Base pio register address */
+	unsigned long ioaddr;
+
+	/** RX/TX virtqueues */
+	struct vring_virtqueue *virtqueue;
+
+	/** RX packets handed to the NIC waiting to be filled in */
+	struct list_head rx_iobufs;
+
+	/** Pending rx packet count */
+	unsigned int rx_num_iobufs;
+
+	/** Virtio net packet header, we only need one */
+	struct virtio_net_hdr empty_header;
+};
+
+/** Add an iobuf to a virtqueue
+ *
+ * @v netdev		Network device
+ * @v vq_idx		Virtqueue index (RX_INDEX or TX_INDEX)
+ * @v iobuf		I/O buffer
+ *
+ * The virtqueue is kicked after the iobuf has been added.
+ */
+static void virtnet_enqueue_iob ( struct net_device *netdev,
+				  int vq_idx, struct io_buffer *iobuf ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
+	unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
+	unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
+	struct vring_list list[] = {
+		{
+			/* Share a single zeroed virtio net header between all
+			 * rx and tx packets.  This works because this driver
+			 * does not use any advanced features so none of the
+			 * header fields get used.
+			 */
+			.addr = ( char* ) &virtnet->empty_header,
+			.length = sizeof ( virtnet->empty_header ),
+		},
+		{
+			.addr = ( char* ) iobuf->data,
+			.length = iob_len ( iobuf ),
+		},
+	};
+
+	DBGC ( virtnet, "VIRTIO-NET %p enqueuing iobuf %p on vq %d\n",
+	       virtnet, iobuf, vq_idx );
+
+	vring_add_buf ( vq, list, out, in, iobuf, 0 );
+	vring_kick ( virtnet->ioaddr, vq, 1 );
+}
+
+/** Try to keep rx virtqueue filled with iobufs
+ *
+ * @v netdev		Network device
+ */
+static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+
+	while ( virtnet->rx_num_iobufs < NUM_RX_BUF ) {
+		struct io_buffer *iobuf;
+
+		/* Try to allocate a buffer, stop for now if out of memory */
+		iobuf = alloc_iob ( RX_BUF_SIZE );
+		if ( ! iobuf )
+			break;
+
+		/* Keep track of iobuf so close() can free it */
+		list_add ( &iobuf->list, &virtnet->rx_iobufs );
+
+		/* Mark packet length until we know the actual size */
+		iob_put ( iobuf, RX_BUF_SIZE );
+
+		virtnet_enqueue_iob ( netdev, RX_INDEX, iobuf );
+		virtnet->rx_num_iobufs++;
+	}
+}
+
+/** Open network device
+ *
+ * @v netdev	Network device
+ * @ret rc	Return status code
+ */
+static int virtnet_open ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	unsigned long ioaddr = virtnet->ioaddr;
+	u32 features;
+	int i;
+
+	/* Reset for sanity */
+	vp_reset ( ioaddr );
+
+	/* Allocate virtqueues */
+	virtnet->virtqueue = zalloc ( QUEUE_NB *
+				      sizeof ( *virtnet->virtqueue ) );
+	if ( ! virtnet->virtqueue )
+		return -ENOMEM;
+
+	/* Initialize rx/tx virtqueues */
+	for ( i = 0; i < QUEUE_NB; i++ ) {
+		if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) {
+			DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n",
+			       virtnet, i );
+			free ( virtnet->virtqueue );
+			virtnet->virtqueue = NULL;
+			return -ENOENT;
+		}
+	}
+
+	/* Initialize rx packets */
+	INIT_LIST_HEAD ( &virtnet->rx_iobufs );
+	virtnet->rx_num_iobufs = 0;
+	virtnet_refill_rx_virtqueue ( netdev );
+
+	/* Disable interrupts before starting */
+	netdev_irq ( netdev, 0 );
+
+	/* Driver is ready */
+	features = vp_get_features ( ioaddr );
+	vp_set_features ( ioaddr, features & ( 1 << VIRTIO_NET_F_MAC ) );
+	vp_set_status ( ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK );
+	return 0;
+}
+
+/** Close network device
+ *
+ * @v netdev	Network device
+ */
+static void virtnet_close ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	struct io_buffer *iobuf;
+	struct io_buffer *next_iobuf;
+
+	vp_reset ( virtnet->ioaddr );
+
+	/* Virtqueues can be freed now that NIC is reset */
+	free ( virtnet->virtqueue );
+	virtnet->virtqueue = NULL;
+
+	/* Free rx iobufs */
+	list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) {
+		free_iob ( iobuf );
+	}
+	INIT_LIST_HEAD ( &virtnet->rx_iobufs );
+	virtnet->rx_num_iobufs = 0;
+}
+
+/** Transmit packet
+ *
+ * @v netdev	Network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ */
+static int virtnet_transmit ( struct net_device *netdev,
+			      struct io_buffer *iobuf ) {
+	virtnet_enqueue_iob ( netdev, TX_INDEX, iobuf );
+	return 0;
+}
+
+/** Complete packet transmission
+ *
+ * @v netdev	Network device
+ */
+static void virtnet_process_tx_packets ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	struct vring_virtqueue *tx_vq = &virtnet->virtqueue[TX_INDEX];
+
+	while ( vring_more_used ( tx_vq ) ) {
+		struct io_buffer *iobuf = vring_get_buf ( tx_vq, NULL );
+
+		DBGC ( virtnet, "VIRTIO-NET %p tx complete iobuf %p\n",
+		       virtnet, iobuf );
+
+		netdev_tx_complete ( netdev, iobuf );
+	}
+}
+
+/** Complete packet reception
+ *
+ * @v netdev	Network device
+ */
+static void virtnet_process_rx_packets ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	struct vring_virtqueue *rx_vq = &virtnet->virtqueue[RX_INDEX];
+
+	while ( vring_more_used ( rx_vq ) ) {
+		unsigned int len;
+		struct io_buffer *iobuf = vring_get_buf ( rx_vq, &len );
+
+		/* Release ownership of iobuf */
+		list_del ( &iobuf->list );
+		virtnet->rx_num_iobufs--;
+
+		/* Update iobuf length */
+		iob_unput ( iobuf, RX_BUF_SIZE );
+		iob_put ( iobuf, len - sizeof ( struct virtio_net_hdr ) );
+
+		DBGC ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n",
+		       virtnet, iobuf, iob_len ( iobuf ) );
+
+		/* Pass completed packet to the network stack */
+		netdev_rx ( netdev, iobuf );
+	}
+
+	virtnet_refill_rx_virtqueue ( netdev );
+}
+
+/** Poll for completed and received packets
+ *
+ * @v netdev	Network device
+ */
+static void virtnet_poll ( struct net_device *netdev ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+
+	/* Acknowledge interrupt.  This is necessary for UNDI operation and
+	 * interrupts that are raised despite VRING_AVAIL_F_NO_INTERRUPT being
+	 * set (that flag is just a hint and the hypervisor not not have to
+	 * honor it).
+	 */
+	vp_get_isr ( virtnet->ioaddr );
+
+	virtnet_process_tx_packets ( netdev );
+	virtnet_process_rx_packets ( netdev );
+}
+
+/** Enable or disable interrupts
+ *
+ * @v netdev	Network device
+ * @v enable	Interrupts should be enabled
+ */
+static void virtnet_irq ( struct net_device *netdev, int enable ) {
+	struct virtnet_nic *virtnet = netdev->priv;
+	int i;
+
+	for ( i = 0; i < QUEUE_NB; i++ ) {
+		if ( enable )
+			vring_enable_cb ( &virtnet->virtqueue[i] );
+		else
+			vring_disable_cb ( &virtnet->virtqueue[i] );
+	}
+}
+
+/** virtio-net device operations */
+static struct net_device_operations virtnet_operations = {
+	.open = virtnet_open,
+	.close = virtnet_close,
+	.transmit = virtnet_transmit,
+	.poll = virtnet_poll,
+	.irq = virtnet_irq,
+};
+
+/**
+ * Probe PCI device
+ *
+ * @v pci	PCI device
+ * @v id	PCI ID
+ * @ret rc	Return status code
+ */
+static int virtnet_probe ( struct pci_device *pci ) {
+	unsigned long ioaddr = pci->ioaddr;
+	struct net_device *netdev;
+	struct virtnet_nic *virtnet;
+	u32 features;
+	int rc;
+
+	/* Allocate and hook up net device */
+	netdev = alloc_etherdev ( sizeof ( *virtnet ) );
+	if ( ! netdev )
+		return -ENOMEM;
+	netdev_init ( netdev, &virtnet_operations );
+	virtnet = netdev->priv;
+	virtnet->ioaddr = ioaddr;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+
+	DBGC ( virtnet, "VIRTIO-NET %p busaddr=%s ioaddr=%#lx irq=%d\n",
+	       virtnet, pci->dev.name, ioaddr, pci->irq );
+
+	/* Enable PCI bus master and reset NIC */
+	adjust_pci_device ( pci );
+	vp_reset ( ioaddr );
+
+	/* Load MAC address */
+	features = vp_get_features ( ioaddr );
+	if ( features & ( 1 << VIRTIO_NET_F_MAC ) ) {
+		vp_get ( ioaddr, offsetof ( struct virtio_net_config, mac ),
+			 netdev->hw_addr, ETH_ALEN );
+		DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet,
+		       eth_ntoa ( netdev->hw_addr ) );
+	}
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Mark link as up, control virtqueue is not used */
+	netdev_link_up ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+	vp_reset ( ioaddr );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v pci	PCI device
+ */
+static void virtnet_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+
+	unregister_netdev ( netdev );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+static struct pci_device_id virtnet_nics[] = {
+PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0),
+};
+
+struct pci_driver virtnet_driver __pci_driver = {
+	.ids = virtnet_nics,
+	.id_count = ( sizeof ( virtnet_nics ) / sizeof ( virtnet_nics[0] ) ),
+	.probe = virtnet_probe,
+	.remove = virtnet_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.h
new file mode 100644
index 0000000..3abef28
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/virtio-net.h
@@ -0,0 +1,44 @@
+#ifndef _VIRTIO_NET_H_
+# define _VIRTIO_NET_H_
+
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
+
+struct virtio_net_config
+{
+   /* The config defining mac address (if VIRTIO_NET_F_MAC) */
+   u8 mac[6];
+} __attribute__((packed));
+
+/* This is the first element of the scatter-gather list.  If you don't
+ * specify GSO or CSUM features, you can simply ignore the header. */
+
+struct virtio_net_hdr
+{
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM     1       // Use csum_start, csum_offset
+   uint8_t flags;
+#define VIRTIO_NET_HDR_GSO_NONE         0       // Not a GSO frame
+#define VIRTIO_NET_HDR_GSO_TCPV4        1       // GSO frame, IPv4 TCP (TSO)
+/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
+#define VIRTIO_NET_HDR_GSO_TCPV4_ECN    2       // GSO frame, IPv4 TCP w/ ECN
+#define VIRTIO_NET_HDR_GSO_UDP          3       // GSO frame, IPv4 UDP (UFO)
+#define VIRTIO_NET_HDR_GSO_TCPV6        4       // GSO frame, IPv6 TCP
+#define VIRTIO_NET_HDR_GSO_ECN          0x80    // TCP has ECN set
+   uint8_t gso_type;
+   uint16_t hdr_len;
+   uint16_t gso_size;
+   uint16_t csum_start;
+   uint16_t csum_offset;
+};
+#endif /* _VIRTIO_NET_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge.c
new file mode 100644
index 0000000..bf20ec4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge.c
@@ -0,0 +1,18 @@
+/** @file Stub file for vxge driver
+ *
+ * This file drags in the rest of the driver for Neterion Inc's X3100 Series
+ * 10GbE PCIe I/O Virtualized Server Adapter, allowing the driver to be built
+ * as "vxge" even though the code is in vxge_* named files.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/pci.h>
+
+REQUIRE_OBJECT(vxge_main);
+
+/** vxge PCI IDs for util/parserom.pl which are put into bin/NIC */
+static struct pci_device_id vxge_nics[] __unused = {
+	/* If you change this, also adjust vxge_main_nics[] in vxge_main.c */
+	PCI_ROM(0x17d5, 0x5833, "vxge-x3100", "Neterion X3100 Series", 0),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.c
new file mode 100644
index 0000000..ba62b50
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.c
@@ -0,0 +1,1868 @@
+/*
+ * vxge-config.c: iPXE driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *              Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ethernet.h>
+#include <byteswap.h>
+
+#include "vxge_traffic.h"
+#include "vxge_config.h"
+#include "vxge_main.h"
+
+void
+vxge_hw_vpath_set_zero_rx_frm_len(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vpath = &hldev->virtual_path;
+	vp_reg = vpath->vp_reg;
+
+	val64 = readq(&vp_reg->rxmac_vcfg0);
+	val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
+	writeq(val64, &vp_reg->rxmac_vcfg0);
+	val64 = readq(&vp_reg->rxmac_vcfg0);
+	return;
+}
+
+enum vxge_hw_status
+vxge_hw_set_fw_api(struct __vxge_hw_device *hldev,
+		u64 vp_id,
+		u32 action,
+		u32 offset,
+		u64 data0,
+		u64 data1)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u64 val64;
+	u32 fw_memo = VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO;
+
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vp_reg = (struct vxge_hw_vpath_reg __iomem *)hldev->vpath_reg[vp_id];
+
+	writeq(data0, &vp_reg->rts_access_steer_data0);
+	writeq(data1, &vp_reg->rts_access_steer_data1);
+
+	wmb();
+
+	val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(fw_memo) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE;
+
+	writeq(val64, &vp_reg->rts_access_steer_ctrl);
+
+	wmb();
+
+	status = __vxge_hw_device_register_poll(
+			&vp_reg->rts_access_steer_ctrl,
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+			WAIT_FACTOR *
+			VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	if (status != VXGE_HW_OK)
+		return VXGE_HW_FAIL;
+
+	val64 = readq(&vp_reg->rts_access_steer_ctrl);
+
+	if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS)
+		status = VXGE_HW_OK;
+	else
+		status = VXGE_HW_FAIL;
+
+	return status;
+}
+
+/* Get function mode */
+enum vxge_hw_status
+vxge_hw_get_func_mode(struct __vxge_hw_device *hldev, u32 *func_mode)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+	u64 val64;
+	int vp_id;
+
+	/* get the first vpath number assigned to this function */
+	vp_id = hldev->first_vp_id;
+
+	vp_reg = (struct vxge_hw_vpath_reg __iomem *)hldev->vpath_reg[vp_id];
+
+	status = vxge_hw_set_fw_api(hldev, vp_id,
+				VXGE_HW_FW_API_GET_FUNC_MODE, 0, 0, 0);
+
+	if (status == VXGE_HW_OK) {
+		val64 = readq(&vp_reg->rts_access_steer_data0);
+		*func_mode = VXGE_HW_GET_FUNC_MODE_VAL(val64);
+	}
+
+	return status;
+}
+
+/*
+ * __vxge_hw_device_pci_e_init
+ * Initialize certain PCI/PCI-X configuration registers
+ * with recommended values. Save config space for future hw resets.
+ */
+void
+__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
+{
+	u16 cmd = 0;
+	struct pci_device *pdev = hldev->pdev;
+
+	vxge_trace();
+
+	/* Set the PErr Repconse bit and SERR in PCI command register. */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd |= 0x140;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	return;
+}
+
+/*
+ * __vxge_hw_device_register_poll
+ * Will poll certain register for specified amount of time.
+ * Will poll until masked bit is not cleared.
+ */
+enum vxge_hw_status
+__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
+{
+	u64 val64;
+	u32 i = 0;
+	enum vxge_hw_status ret = VXGE_HW_FAIL;
+
+	udelay(10);
+
+	do {
+		val64 = readq(reg);
+		if (!(val64 & mask))
+			return VXGE_HW_OK;
+		udelay(100);
+	} while (++i <= 9);
+
+	i = 0;
+	do {
+		val64 = readq(reg);
+		if (!(val64 & mask))
+			return VXGE_HW_OK;
+		udelay(1000);
+	} while (++i <= max_millis);
+
+	return ret;
+}
+
+ /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset
+ * in progress
+ * This routine checks the vpath reset in progress register is turned zero
+ */
+enum vxge_hw_status
+__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
+{
+	enum vxge_hw_status status;
+
+	vxge_trace();
+
+	status = __vxge_hw_device_register_poll(vpath_rst_in_prog,
+			VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff),
+			VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+	return status;
+}
+
+/*
+ * __vxge_hw_device_get_legacy_reg
+ * This routine gets the legacy register section's memory mapped address
+ * and sets the swapper.
+ */
+static struct vxge_hw_legacy_reg __iomem *
+__vxge_hw_device_get_legacy_reg(struct pci_device *pdev, void __iomem *bar0)
+{
+	enum vxge_hw_status status;
+	struct vxge_hw_legacy_reg __iomem *legacy_reg;
+	/*
+	 * If the length of Bar0 is 16MB, then assume that we are configured
+	 * in MF8P_VP2 mode and then add 8MB to the legacy_reg offsets
+	 */
+	if (pci_bar_size(pdev, PCI_BASE_ADDRESS_0) == 0x1000000)
+		legacy_reg = (struct vxge_hw_legacy_reg __iomem *)
+				(bar0 + 0x800000);
+	else
+		legacy_reg = (struct vxge_hw_legacy_reg __iomem *)bar0;
+
+	status = __vxge_hw_legacy_swapper_set(legacy_reg);
+	if (status != VXGE_HW_OK)
+		return NULL;
+
+	return legacy_reg;
+}
+/*
+ * __vxge_hw_device_toc_get
+ * This routine sets the swapper and reads the toc pointer and returns the
+ * memory mapped address of the toc
+ */
+struct vxge_hw_toc_reg __iomem *
+__vxge_hw_device_toc_get(void __iomem *bar0,
+	struct vxge_hw_legacy_reg __iomem *legacy_reg)
+{
+	u64 val64;
+	struct vxge_hw_toc_reg __iomem *toc = NULL;
+
+	val64 =	readq(&legacy_reg->toc_first_pointer);
+	toc = (struct vxge_hw_toc_reg __iomem *)(bar0+val64);
+
+	return toc;
+}
+
+/*
+ * __vxge_hw_device_reg_addr_get
+ * This routine sets the swapper and reads the toc pointer and initializes the
+ * register location pointers in the device object. It waits until the ric is
+ * completed initializing registers.
+ */
+enum vxge_hw_status
+__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	u32 i;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	hldev->legacy_reg = __vxge_hw_device_get_legacy_reg(hldev->pdev,
+					hldev->bar0);
+	if (hldev->legacy_reg  == NULL) {
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0,
+					hldev->legacy_reg);
+	if (hldev->toc_reg  == NULL) {
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_common_pointer);
+	hldev->common_reg =
+		(struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64);
+
+	val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer);
+	hldev->mrpcim_reg =
+		(struct vxge_hw_mrpcim_reg __iomem *)(hldev->bar0 + val64);
+
+	for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) {
+		val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]);
+		hldev->srpcim_reg[i] =
+			(struct vxge_hw_srpcim_reg __iomem *)
+				(hldev->bar0 + val64);
+	}
+
+	for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) {
+		val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]);
+		hldev->vpmgmt_reg[i] =
+		(struct vxge_hw_vpmgmt_reg __iomem *)(hldev->bar0 + val64);
+	}
+
+	for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) {
+		val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]);
+		hldev->vpath_reg[i] =
+			(struct vxge_hw_vpath_reg __iomem *)
+				(hldev->bar0 + val64);
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_kdfc);
+
+	switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) {
+	case 0:
+		hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
+			VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
+		break;
+	default:
+		break;
+	}
+
+	status = __vxge_hw_device_vpath_reset_in_prog_check(
+			(u64 __iomem *)&hldev->common_reg->vpath_rst_in_prog);
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_device_access_rights_get: Get Access Rights of the driver
+ * This routine returns the Access Rights of the driver
+ */
+static u32
+__vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
+{
+	u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH;
+
+	switch (host_type) {
+	case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
+		if (func_id == 0) {
+			access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+					VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		}
+		break;
+	case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+				VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	case VXGE_HW_NO_MR_SR_VH0_FUNCTION0:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+				VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION:
+	case VXGE_HW_SR_VH_VIRTUAL_FUNCTION:
+	case VXGE_HW_MR_SR_VH0_INVALID_CONFIG:
+		break;
+	case VXGE_HW_SR_VH_FUNCTION0:
+	case VXGE_HW_VH_NORMAL_FUNCTION:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	}
+
+	return access_rights;
+}
+
+/*
+ * __vxge_hw_device_host_info_get
+ * This routine returns the host type assignments
+ */
+void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	u32 i;
+
+	val64 = readq(&hldev->common_reg->host_type_assignments);
+
+	hldev->host_type =
+	   (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+	hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!(hldev->vpath_assignments & vxge_mBIT(i)))
+			continue;
+
+		hldev->func_id =
+			__vxge_hw_vpath_func_id_get(hldev->vpmgmt_reg[i]);
+
+		hldev->access_rights = __vxge_hw_device_access_rights_get(
+			hldev->host_type, hldev->func_id);
+
+		hldev->first_vp_id = i;
+		break;
+	}
+
+	return;
+}
+
+/**
+ * vxge_hw_device_hw_info_get - Get the hw information
+ * Returns the vpath mask that has the bits set for each vpath allocated
+ * for the driver, FW version information and the first mac addresse for
+ * each vpath
+ */
+enum vxge_hw_status
+vxge_hw_device_hw_info_get(struct pci_device *pdev, void __iomem *bar0,
+				struct vxge_hw_device_hw_info *hw_info)
+{
+	u32 i;
+	u64 val64;
+	struct vxge_hw_toc_reg __iomem *toc;
+	struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg;
+	struct vxge_hw_common_reg __iomem *common_reg;
+	struct vxge_hw_vpath_reg __iomem *vpath_reg;
+	struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
+	struct vxge_hw_legacy_reg __iomem *legacy_reg;
+	enum vxge_hw_status status;
+
+	vxge_trace();
+
+	memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
+
+	legacy_reg = __vxge_hw_device_get_legacy_reg(pdev, bar0);
+	if (legacy_reg == NULL) {
+		status = VXGE_HW_ERR_CRITICAL;
+		goto exit;
+	}
+
+	toc = __vxge_hw_device_toc_get(bar0, legacy_reg);
+	if (toc == NULL) {
+		status = VXGE_HW_ERR_CRITICAL;
+		goto exit;
+	}
+
+	val64 = readq(&toc->toc_common_pointer);
+	common_reg = (struct vxge_hw_common_reg __iomem *)(bar0 + val64);
+
+	status = __vxge_hw_device_vpath_reset_in_prog_check(
+		(u64 __iomem *)&common_reg->vpath_rst_in_prog);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	hw_info->vpath_mask = readq(&common_reg->vpath_assignments);
+
+	val64 = readq(&common_reg->host_type_assignments);
+
+	hw_info->host_type =
+	   (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+			continue;
+
+		val64 = readq(&toc->toc_vpmgmt_pointer[i]);
+
+		vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *)
+				(bar0 + val64);
+
+		hw_info->func_id = __vxge_hw_vpath_func_id_get(vpmgmt_reg);
+		if (__vxge_hw_device_access_rights_get(hw_info->host_type,
+			hw_info->func_id) &
+			VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
+
+			val64 = readq(&toc->toc_mrpcim_pointer);
+
+			mrpcim_reg = (struct vxge_hw_mrpcim_reg __iomem *)
+					(bar0 + val64);
+
+			writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask);
+			wmb();
+		}
+
+		val64 = readq(&toc->toc_vpath_pointer[i]);
+
+		vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+
+		status = __vxge_hw_vpath_fw_ver_get(vpath_reg, hw_info);
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+		status = __vxge_hw_vpath_card_info_get(vpath_reg, hw_info);
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+		break;
+	}
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+			continue;
+
+		val64 = readq(&toc->toc_vpath_pointer[i]);
+		vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+
+		status =  __vxge_hw_vpath_addr_get(vpath_reg,
+				hw_info->mac_addrs[i],
+				hw_info->mac_addr_masks[i]);
+		if (status != VXGE_HW_OK)
+			goto exit;
+	}
+exit:
+	return status;
+}
+
+/*
+ * vxge_hw_device_initialize - Initialize Titan device.
+ * Initialize Titan device. Note that all the arguments of this public API
+ * are 'IN', including @hldev. Driver cooperates with
+ * OS to find new Titan device, locate its PCI and memory spaces.
+ *
+ * When done, the driver allocates sizeof(struct __vxge_hw_device) bytes for HW
+ * to enable the latter to perform Titan hardware initialization.
+ */
+enum vxge_hw_status
+vxge_hw_device_initialize(
+	struct __vxge_hw_device **devh,
+	void *bar0,
+	struct pci_device *pdev,
+	u8 titan1)
+{
+	struct __vxge_hw_device *hldev = NULL;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	hldev = (struct __vxge_hw_device *)
+			zalloc(sizeof(struct __vxge_hw_device));
+	if (hldev == NULL) {
+		vxge_debug(VXGE_ERR, "hldev allocation failed\n");
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+
+	hldev->magic = VXGE_HW_DEVICE_MAGIC;
+
+	hldev->bar0 = bar0;
+	hldev->pdev = pdev;
+	hldev->titan1 = titan1;
+
+	__vxge_hw_device_pci_e_init(hldev);
+
+	status = __vxge_hw_device_reg_addr_get(hldev);
+	if (status != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR, "%s:%d __vxge_hw_device_reg_addr_get "
+			"failed\n", __func__, __LINE__);
+		vxge_hw_device_terminate(hldev);
+		goto exit;
+	}
+
+	__vxge_hw_device_host_info_get(hldev);
+
+	*devh = hldev;
+exit:
+	return status;
+}
+
+/*
+ * vxge_hw_device_terminate - Terminate Titan device.
+ * Terminate HW device.
+ */
+void
+vxge_hw_device_terminate(struct __vxge_hw_device *hldev)
+{
+	vxge_trace();
+
+	assert(hldev->magic == VXGE_HW_DEVICE_MAGIC);
+
+	hldev->magic = VXGE_HW_DEVICE_DEAD;
+	free(hldev);
+}
+
+/*
+ *vxge_hw_ring_replenish - Initial replenish of RxDs
+ * This function replenishes the RxDs from reserve array to work array
+ */
+enum vxge_hw_status
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring)
+{
+	struct __vxge_hw_device *hldev;
+	struct vxge_hw_ring_rxd_1 *rxd;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u8 offset = 0;
+	struct __vxge_hw_ring_block *block;
+	u8 i, iob_off;
+
+	vxge_trace();
+
+	hldev = ring->vpathh->hldev;
+	/*
+	 * We allocate all the dma buffers first and then share the
+	 * these buffers among the all rx descriptors in the block.
+	 */
+	for (i = 0; i < ARRAY_SIZE(ring->iobuf); i++) {
+		ring->iobuf[i] = alloc_iob(VXGE_LL_MAX_FRAME_SIZE(hldev->vdev));
+		if (!ring->iobuf[i]) {
+			while (i) {
+				free_iob(ring->iobuf[--i]);
+				ring->iobuf[i] = NULL;
+			}
+			status = VXGE_HW_ERR_OUT_OF_MEMORY;
+			goto iobuf_err;
+		}
+	}
+
+	for (offset = 0; offset < VXGE_HW_MAX_RXDS_PER_BLOCK_1; offset++) {
+
+		rxd = &ring->rxdl->rxd[offset];
+		if (offset == (VXGE_HW_MAX_RXDS_PER_BLOCK_1 - 1))
+			iob_off = VXGE_HW_RING_BUF_PER_BLOCK;
+		else
+			iob_off = offset % ring->buf_per_block;
+
+		rxd->control_0 = rxd->control_1 = 0;
+		vxge_hw_ring_rxd_1b_set(rxd, ring->iobuf[iob_off],
+				VXGE_LL_MAX_FRAME_SIZE(hldev->vdev));
+
+		vxge_hw_ring_rxd_post(ring, rxd);
+	}
+	/* linking the block to itself as we use only one rx block*/
+	block = ring->rxdl;
+	block->reserved_2_pNext_RxD_block = (unsigned long) block;
+	block->pNext_RxD_Blk_physical = (u64)virt_to_bus(block);
+
+	ring->rxd_offset = 0;
+iobuf_err:
+	return status;
+}
+
+/*
+ * __vxge_hw_ring_create - Create a Ring
+ * This function creates Ring and initializes it.
+ *
+ */
+enum vxge_hw_status
+__vxge_hw_ring_create(struct __vxge_hw_virtualpath *vpath,
+		      struct __vxge_hw_ring *ring)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_device *hldev;
+	u32 vp_id;
+
+	vxge_trace();
+
+	hldev = vpath->hldev;
+	vp_id = vpath->vp_id;
+
+	ring->rxdl = malloc_dma(sizeof(struct __vxge_hw_ring_block),
+			sizeof(struct __vxge_hw_ring_block));
+	if (!ring->rxdl) {
+		vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n",
+				__func__, __LINE__);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+	ring->rxd_offset = 0;
+	ring->vpathh = vpath;
+	ring->buf_per_block = VXGE_HW_RING_BUF_PER_BLOCK;
+	ring->rx_poll_weight = VXGE_HW_RING_RX_POLL_WEIGHT;
+	ring->vp_id = vp_id;
+	ring->vp_reg = vpath->vp_reg;
+	ring->common_reg = hldev->common_reg;
+
+	ring->rxd_qword_limit = VXGE_HW_RING_RXD_QWORD_LIMIT;
+
+	status = vxge_hw_ring_replenish(ring);
+	if (status != VXGE_HW_OK) {
+		__vxge_hw_ring_delete(ring);
+		goto exit;
+	}
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_ring_delete - Removes the ring
+ * This function freeup the memory pool and removes the ring
+ */
+enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_ring *ring)
+{
+	u8 i;
+
+	vxge_trace();
+
+	for (i = 0; (i < ARRAY_SIZE(ring->iobuf)) && ring->iobuf[i]; i++) {
+		free_iob(ring->iobuf[i]);
+		ring->iobuf[i] = NULL;
+	}
+
+	if (ring->rxdl) {
+		free_dma(ring->rxdl, sizeof(struct __vxge_hw_ring_block));
+		ring->rxdl = NULL;
+	}
+	ring->rxd_offset = 0;
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
+ * Set the swapper bits appropriately for the legacy section.
+ */
+enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	val64 = readq(&legacy_reg->toc_swapper_fb);
+
+	wmb();
+
+	switch (val64) {
+
+	case VXGE_HW_SWAPPER_INITIAL_VALUE:
+		return status;
+
+	case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED:
+		writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+			&legacy_reg->pifm_rd_swap_en);
+		writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+			&legacy_reg->pifm_rd_flip_en);
+		writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+			&legacy_reg->pifm_wr_swap_en);
+		writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+			&legacy_reg->pifm_wr_flip_en);
+		break;
+
+	case VXGE_HW_SWAPPER_BYTE_SWAPPED:
+		writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+			&legacy_reg->pifm_rd_swap_en);
+		writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+			&legacy_reg->pifm_wr_swap_en);
+		break;
+
+	case VXGE_HW_SWAPPER_BIT_FLIPPED:
+		writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+			&legacy_reg->pifm_rd_flip_en);
+		writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+			&legacy_reg->pifm_wr_flip_en);
+		break;
+	}
+
+	wmb();
+
+	val64 = readq(&legacy_reg->toc_swapper_fb);
+	if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE)
+		status = VXGE_HW_ERR_SWAPPER_CTRL;
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath.
+ * Set the swapper bits appropriately for the vpath.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
+{
+	vxge_trace();
+
+#if (__BYTE_ORDER != __BIG_ENDIAN)
+	u64 val64;
+
+	val64 = readq(&vpath_reg->vpath_general_cfg1);
+	wmb();
+	val64 |= VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN;
+	writeq(val64, &vpath_reg->vpath_general_cfg1);
+	wmb();
+#endif
+	return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_kdfc_swapper_set - Set the swapper bits for the kdfc.
+ * Set the swapper bits appropriately for the vpath.
+ */
+enum vxge_hw_status
+__vxge_hw_kdfc_swapper_set(
+	struct vxge_hw_legacy_reg __iomem *legacy_reg,
+	struct vxge_hw_vpath_reg __iomem *vpath_reg)
+{
+	u64 val64;
+
+	vxge_trace();
+
+	val64 = readq(&legacy_reg->pifm_wr_swap_en);
+
+	if (val64 == VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE) {
+		val64 = readq(&vpath_reg->kdfcctl_cfg0);
+		wmb();
+
+		val64 |= VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0	|
+			VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1	|
+			VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2;
+
+		writeq(val64, &vpath_reg->kdfcctl_cfg0);
+		wmb();
+	}
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * vxge_hw_vpath_strip_fcs_check - Check for FCS strip.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask)
+{
+	struct vxge_hw_vpmgmt_reg	__iomem *vpmgmt_reg;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	int i = 0, j = 0;
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+		if (!((vpath_mask) & vxge_mBIT(i)))
+			continue;
+		vpmgmt_reg = hldev->vpmgmt_reg[i];
+		for (j = 0; j < VXGE_HW_MAC_MAX_MAC_PORT_ID; j++) {
+			if (readq(&vpmgmt_reg->rxmac_cfg0_port_vpmgmt_clone[j])
+			& VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS)
+				return VXGE_HW_FAIL;
+		}
+	}
+	return status;
+}
+
+/*
+ * __vxge_hw_fifo_create - Create a FIFO
+ * This function creates FIFO and initializes it.
+ */
+enum vxge_hw_status
+__vxge_hw_fifo_create(struct __vxge_hw_virtualpath *vpath,
+			struct __vxge_hw_fifo *fifo)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	fifo->vpathh = vpath;
+	fifo->depth = VXGE_HW_FIFO_TXD_DEPTH;
+	fifo->hw_offset = fifo->sw_offset = 0;
+	fifo->nofl_db = vpath->nofl_db;
+	fifo->vp_id = vpath->vp_id;
+	fifo->vp_reg = vpath->vp_reg;
+	fifo->tx_intr_num = (vpath->vp_id * VXGE_HW_MAX_INTR_PER_VP)
+				+ VXGE_HW_VPATH_INTR_TX;
+
+	fifo->txdl = malloc_dma(sizeof(struct vxge_hw_fifo_txd)
+				* fifo->depth, fifo->depth);
+	if (!fifo->txdl) {
+		vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n",
+				__func__, __LINE__);
+		return VXGE_HW_ERR_OUT_OF_MEMORY;
+	}
+	memset(fifo->txdl, 0, sizeof(struct vxge_hw_fifo_txd) * fifo->depth);
+	return status;
+}
+
+/*
+ * __vxge_hw_fifo_delete - Removes the FIFO
+ * This function freeup the memory pool and removes the FIFO
+ */
+enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_fifo *fifo)
+{
+	vxge_trace();
+
+	if (fifo->txdl)
+		free_dma(fifo->txdl,
+			sizeof(struct vxge_hw_fifo_txd) * fifo->depth);
+
+	fifo->txdl = NULL;
+	fifo->hw_offset = fifo->sw_offset = 0;
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_vpath_pci_read - Read the content of given address
+ *                          in pci config space.
+ * Read from the vpath pci config space.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_pci_read(struct __vxge_hw_virtualpath *vpath,
+			 u32 phy_func_0, u32 offset, u32 *val)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
+
+	val64 =	VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(offset);
+
+	if (phy_func_0)
+		val64 |= VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0;
+
+	writeq(val64, &vp_reg->pci_config_access_cfg1);
+	wmb();
+	writeq(VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ,
+			&vp_reg->pci_config_access_cfg2);
+	wmb();
+
+	status = __vxge_hw_device_register_poll(
+			&vp_reg->pci_config_access_cfg2,
+			VXGE_HW_INTR_MASK_ALL, VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 = readq(&vp_reg->pci_config_access_status);
+
+	if (val64 & VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR) {
+		status = VXGE_HW_FAIL;
+		*val = 0;
+	} else
+		*val = (u32)vxge_bVALn(val64, 32, 32);
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
+ * Returns the function number of the vpath.
+ */
+u32
+__vxge_hw_vpath_func_id_get(struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
+{
+	u64 val64;
+
+	val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1);
+
+	return
+	 (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64);
+}
+
+/*
+ * __vxge_hw_read_rts_ds - Program RTS steering critieria
+ */
+static inline void
+__vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg,
+				u64 dta_struct_sel)
+{
+	writeq(0, &vpath_reg->rts_access_steer_ctrl);
+	wmb();
+	writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0);
+	writeq(0, &vpath_reg->rts_access_steer_data1);
+	wmb();
+	return;
+}
+
+/*
+ * __vxge_hw_vpath_card_info_get - Get the serial numbers,
+ * part number and product description.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(
+	struct vxge_hw_vpath_reg __iomem *vpath_reg,
+	struct vxge_hw_device_hw_info *hw_info)
+{
+	u32 i, j;
+	u64 val64;
+	u64 data1 = 0ULL;
+	u64 data2 = 0ULL;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u8 *serial_number = hw_info->serial_number;
+	u8 *part_number = hw_info->part_number;
+	u8 *product_desc = hw_info->product_desc;
+
+	__vxge_hw_read_rts_ds(vpath_reg,
+		VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER);
+
+	val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+	status = __vxge_hw_pio_mem_write64(val64,
+				&vpath_reg->rts_access_steer_ctrl,
+				VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+				VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	if (status != VXGE_HW_OK)
+		return status;
+
+	val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+	if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+		data1 = readq(&vpath_reg->rts_access_steer_data0);
+		((u64 *)serial_number)[0] = be64_to_cpu(data1);
+
+		data2 = readq(&vpath_reg->rts_access_steer_data1);
+		((u64 *)serial_number)[1] = be64_to_cpu(data2);
+		status = VXGE_HW_OK;
+	} else
+		*serial_number = 0;
+
+	__vxge_hw_read_rts_ds(vpath_reg,
+			VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER);
+
+	val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+	status = __vxge_hw_pio_mem_write64(val64,
+				&vpath_reg->rts_access_steer_ctrl,
+				VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+				VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	if (status != VXGE_HW_OK)
+		return status;
+
+	val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+	if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+		data1 = readq(&vpath_reg->rts_access_steer_data0);
+		((u64 *)part_number)[0] = be64_to_cpu(data1);
+
+		data2 = readq(&vpath_reg->rts_access_steer_data1);
+		((u64 *)part_number)[1] = be64_to_cpu(data2);
+
+		status = VXGE_HW_OK;
+
+	} else
+		*part_number = 0;
+
+	j = 0;
+
+	for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0;
+	     i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) {
+
+		__vxge_hw_read_rts_ds(vpath_reg, i);
+
+		val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+		status = __vxge_hw_pio_mem_write64(val64,
+				&vpath_reg->rts_access_steer_ctrl,
+				VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+				VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+		if (status != VXGE_HW_OK)
+			return status;
+
+		val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+		if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+			data1 = readq(&vpath_reg->rts_access_steer_data0);
+			((u64 *)product_desc)[j++] = be64_to_cpu(data1);
+
+			data2 = readq(&vpath_reg->rts_access_steer_data1);
+			((u64 *)product_desc)[j++] = be64_to_cpu(data2);
+
+			status = VXGE_HW_OK;
+		} else
+			*product_desc = 0;
+	}
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_fw_ver_get - Get the fw version
+ * Returns FW Version
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(
+	struct vxge_hw_vpath_reg __iomem *vpath_reg,
+	struct vxge_hw_device_hw_info *hw_info)
+{
+	u64 val64;
+	u64 data1 = 0ULL;
+	u64 data2 = 0ULL;
+	struct vxge_hw_device_version *fw_version = &hw_info->fw_version;
+	struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
+	struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
+	struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+		VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+	status = __vxge_hw_pio_mem_write64(val64,
+				&vpath_reg->rts_access_steer_ctrl,
+				VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+				VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+	if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+		data1 = readq(&vpath_reg->rts_access_steer_data0);
+		data2 = readq(&vpath_reg->rts_access_steer_data1);
+
+		fw_date->day =
+			(u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(
+						data1);
+		fw_date->month =
+			(u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(
+						data1);
+		fw_date->year =
+			(u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(
+						data1);
+
+		snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%d/%d/%d",
+			fw_date->month, fw_date->day, fw_date->year);
+
+		fw_version->major =
+		    (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data1);
+		fw_version->minor =
+		    (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data1);
+		fw_version->build =
+		    (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data1);
+
+		snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+		    fw_version->major, fw_version->minor, fw_version->build);
+
+		flash_date->day =
+		  (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data2);
+		flash_date->month =
+		 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data2);
+		flash_date->year =
+		 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data2);
+
+		snprintf(flash_date->date, VXGE_HW_FW_STRLEN, "%d/%d/%d",
+			flash_date->month, flash_date->day, flash_date->year);
+
+		flash_version->major =
+		 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data2);
+		flash_version->minor =
+		 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data2);
+		flash_version->build =
+		 (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data2);
+
+		snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+			flash_version->major, flash_version->minor,
+			flash_version->build);
+
+		status = VXGE_HW_OK;
+
+	} else
+		status = VXGE_HW_FAIL;
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
+ *               from MAC address table.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_addr_get(
+	struct vxge_hw_vpath_reg *vpath_reg,
+	u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN])
+{
+	u32 i;
+	u64 val64;
+	u64 data1 = 0ULL;
+	u64 data2 = 0ULL;
+	u64 action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	while (1) {
+		val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+			VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
+
+		status = __vxge_hw_pio_mem_write64(val64,
+					&vpath_reg->rts_access_steer_ctrl,
+					VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+					VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+		if (status != VXGE_HW_OK)
+			break;
+
+		val64 = readq(&vpath_reg->rts_access_steer_ctrl);
+
+		if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+
+			data1 = readq(&vpath_reg->rts_access_steer_data0);
+			data2 = readq(&vpath_reg->rts_access_steer_data1);
+
+			data1 =
+			 VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
+			data2 =
+			 VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(
+								data2);
+
+			for (i = ETH_ALEN; i > 0; i--) {
+				macaddr[i-1] = (u8)(data1 & 0xFF);
+				data1 >>= 8;
+
+				macaddr_mask[i-1] = (u8)(data2 & 0xFF);
+				data2 >>= 8;
+			}
+			if (is_valid_ether_addr(macaddr)) {
+				status = VXGE_HW_OK;
+				break;
+			}
+			action =
+			  VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY;
+		} else
+			status = VXGE_HW_FAIL;
+	}
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_mgmt_read
+ * This routine reads the vpath_mgmt registers
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_mgmt_read(
+	struct __vxge_hw_virtualpath *vpath)
+{
+	u32 i, mtu = 0, max_pyld = 0;
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	for (i = 0; i < VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
+
+		val64 = readq(&vpath->vpmgmt_reg->
+				rxmac_cfg0_port_vpmgmt_clone[i]);
+		max_pyld =
+			(u32)
+			VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN
+			(val64);
+		if (mtu < max_pyld)
+			mtu = max_pyld;
+	}
+
+	vpath->max_mtu = mtu + VXGE_HW_MAC_HEADER_MAX_SIZE;
+
+	val64 = readq(&vpath->vpmgmt_reg->xgmac_gen_status_vpmgmt_clone);
+
+	if (val64 & VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK)
+		VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_UP);
+	else
+		VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_DOWN);
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_reset_check - Check if resetting the vpath completed
+ * This routine checks the vpath_rst_in_prog register to see if
+ * adapter completed the reset process for the vpath
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath)
+{
+	enum vxge_hw_status status;
+
+	vxge_trace();
+
+	status = __vxge_hw_device_register_poll(
+			&vpath->hldev->common_reg->vpath_rst_in_prog,
+			VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(
+				1 << (16 - vpath->vp_id)),
+			VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_reset
+ * This routine resets the vpath on the device
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	val64 = VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(1 << (16 - vp_id));
+
+	__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+				&hldev->common_reg->cmn_rsthdlr_cfg0);
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_prc_configure
+ * This routine configures the prc registers of virtual path using the config
+ * passed
+ */
+void
+__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vxge_trace();
+
+	vpath = &hldev->virtual_path;
+	vp_reg = vpath->vp_reg;
+
+	val64 = readq(&vp_reg->prc_cfg1);
+	val64 |= VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE;
+	writeq(val64, &vp_reg->prc_cfg1);
+
+	val64 = readq(&vpath->vp_reg->prc_cfg6);
+	val64 &= ~VXGE_HW_PRC_CFG6_RXD_CRXDT(0x1ff);
+	val64 &= ~VXGE_HW_PRC_CFG6_RXD_SPAT(0x1ff);
+	val64 |= VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN;
+	val64 |= VXGE_HW_PRC_CFG6_RXD_CRXDT(0x3);
+	val64 |= VXGE_HW_PRC_CFG6_RXD_SPAT(0xf);
+	writeq(val64, &vpath->vp_reg->prc_cfg6);
+
+	writeq(VXGE_HW_PRC_CFG5_RXD0_ADD(
+			(u64)virt_to_bus(vpath->ringh.rxdl) >> 3),
+			&vp_reg->prc_cfg5);
+
+	val64 = readq(&vp_reg->prc_cfg4);
+	val64 |= VXGE_HW_PRC_CFG4_IN_SVC;
+	val64 &= ~VXGE_HW_PRC_CFG4_RING_MODE(0x3);
+	val64 |= VXGE_HW_PRC_CFG4_RING_MODE(
+			VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER);
+	val64 |= VXGE_HW_PRC_CFG4_RTH_DISABLE;
+
+	writeq(val64, &vp_reg->prc_cfg4);
+	return;
+}
+
+/*
+ * __vxge_hw_vpath_kdfc_configure
+ * This routine configures the kdfc registers of virtual path using the
+ * config passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+	u64 val64;
+	u64 vpath_stride;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vxge_trace();
+
+	vpath = &hldev->virtual_path;
+	vp_reg = vpath->vp_reg;
+	status = __vxge_hw_kdfc_swapper_set(hldev->legacy_reg, vp_reg);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 = readq(&vp_reg->kdfc_drbl_triplet_total);
+
+	vpath->max_kdfc_db =
+		(u32)VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(
+			val64+1)/2;
+
+	vpath->max_nofl_db = vpath->max_kdfc_db;
+
+	val64 = VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(
+				(vpath->max_nofl_db*2)-1);
+
+	writeq(val64, &vp_reg->kdfc_fifo_trpl_partition);
+
+	writeq(VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE,
+		&vp_reg->kdfc_fifo_trpl_ctrl);
+
+	val64 = readq(&vp_reg->kdfc_trpl_fifo_0_ctrl);
+
+	val64 &= ~(VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(0x3) |
+		   VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0xFF));
+
+	val64 |= VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(
+		 VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY) |
+#if (__BYTE_ORDER != __BIG_ENDIAN)
+		 VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN |
+#endif
+		 VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0);
+
+	writeq(val64, &vp_reg->kdfc_trpl_fifo_0_ctrl);
+	writeq((u64)0, &vp_reg->kdfc_trpl_fifo_0_wb_address);
+	wmb();
+	vpath_stride = readq(&hldev->toc_reg->toc_kdfc_vpath_stride);
+
+	vpath->nofl_db =
+		(struct __vxge_hw_non_offload_db_wrapper __iomem *)
+		(hldev->kdfc + (vp_id *
+		VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(
+					vpath_stride)));
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_mac_configure
+ * This routine configures the mac of virtual path using the config passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vxge_trace();
+
+	vpath = &hldev->virtual_path;
+	vp_reg = vpath->vp_reg;
+
+	writeq(VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(
+			vpath->vsport_number), &vp_reg->xmac_vsport_choice);
+
+	val64 = readq(&vp_reg->rxmac_vcfg1);
+
+	val64 &= ~(VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(0x3) |
+		VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE);
+
+	writeq(val64, &vp_reg->rxmac_vcfg1);
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_tim_configure
+ * This routine configures the tim registers of virtual path using the config
+ * passed
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	vxge_trace();
+
+	vpath = &hldev->virtual_path;
+	vp_reg = vpath->vp_reg;
+
+	writeq((u64)0, &vp_reg->tim_dest_addr);
+	writeq((u64)0, &vp_reg->tim_vpath_map);
+	writeq((u64)0, &vp_reg->tim_bitmap);
+	writeq((u64)0, &vp_reg->tim_remap);
+
+	writeq(VXGE_HW_TIM_RING_ASSN_INT_NUM(
+		(vp_id * VXGE_HW_MAX_INTR_PER_VP) +
+		VXGE_HW_VPATH_INTR_RX), &vp_reg->tim_ring_assn);
+
+	val64 = readq(&vp_reg->tim_pci_cfg);
+	val64 |= VXGE_HW_TIM_PCI_CFG_ADD_PAD;
+	writeq(val64, &vp_reg->tim_pci_cfg);
+
+	/* TX configuration */
+	val64 = VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+			(VXGE_TTI_BTIMER_VAL * 1000) / 272);
+	val64 |= (VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC |
+			VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI |
+			VXGE_HW_TIM_CFG1_INT_NUM_TXFRM_CNT_EN);
+	val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(TTI_TX_URANGE_A) |
+			VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(TTI_TX_URANGE_B) |
+			VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(TTI_TX_URANGE_C);
+	writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+	val64 = VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(TTI_TX_UFC_A) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(TTI_TX_UFC_B) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(TTI_TX_UFC_C) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(TTI_TX_UFC_D);
+	writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+	val64 = VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
+			VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL);
+	val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+			(VXGE_TTI_LTIMER_VAL * 1000) / 272);
+	writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+	/* RX configuration */
+	val64 = VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
+			(VXGE_RTI_BTIMER_VAL * 1000) / 272);
+	val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
+	val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(RTI_RX_URANGE_A) |
+			VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(RTI_RX_URANGE_B) |
+			VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(RTI_RX_URANGE_C);
+	writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+	val64 = VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(RTI_RX_UFC_A) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(RTI_RX_UFC_B) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(RTI_RX_UFC_C) |
+			VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(RTI_RX_UFC_D);
+	writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+	val64 = VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
+			VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL);
+	val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
+			(VXGE_RTI_LTIMER_VAL * 1000) / 272);
+	writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
+
+	val64 = 0;
+	writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+	writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+	writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_EINTA]);
+	writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+	writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+	writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+
+	return status;
+}
+
+/*
+ * __vxge_hw_vpath_initialize
+ * This routine is the final phase of init which initializes the
+ * registers of the vpath using the configuration passed.
+ */
+enum vxge_hw_status
+__vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+	u64 val64;
+	u32 val32;
+	int i;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_virtualpath *vpath;
+	struct vxge_hw_vpath_reg *vp_reg;
+
+	vxge_trace();
+
+	vpath = &hldev->virtual_path;
+
+	if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
+		status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
+		goto exit;
+	}
+	vp_reg = vpath->vp_reg;
+	status = __vxge_hw_legacy_swapper_set(hldev->legacy_reg);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	status = __vxge_hw_vpath_swapper_set(vpath->vp_reg);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+	val64 = readq(&vpath->vpmgmt_reg->xmac_vsport_choices_vp);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+		if (val64 & vxge_mBIT(i))
+			vpath->vsport_number = i;
+	}
+
+	status = __vxge_hw_vpath_mac_configure(hldev);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	status = __vxge_hw_vpath_kdfc_configure(hldev, vp_id);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	status = __vxge_hw_vpath_tim_configure(hldev, vp_id);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 = readq(&vp_reg->rtdma_rd_optimization_ctrl);
+
+	/* Get MRRS value from device control */
+	status = __vxge_hw_vpath_pci_read(vpath, 1, 0x78, &val32);
+
+	if (status == VXGE_HW_OK) {
+		val32 = (val32 & VXGE_HW_PCI_EXP_DEVCTL_READRQ) >> 12;
+		val64 &=
+		    ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(7));
+		val64 |=
+		    VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val32);
+
+		val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE;
+	}
+
+	val64 &= ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(7));
+	val64 |=
+	    VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(
+		    VXGE_HW_MAX_PAYLOAD_SIZE_512);
+
+	val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN;
+	writeq(val64, &vp_reg->rtdma_rd_optimization_ctrl);
+
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_vp_initialize - Initialize Virtual Path structure
+ * This routine is the initial phase of init which resets the vpath and
+ * initializes the software support structures.
+ */
+enum vxge_hw_status
+__vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
+			struct __vxge_hw_virtualpath *vpath)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
+		status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
+		goto exit;
+	}
+
+	vpath->vp_id = vp_id;
+	vpath->vp_open = VXGE_HW_VP_OPEN;
+	vpath->hldev = hldev;
+	vpath->vp_reg = hldev->vpath_reg[vp_id];
+	vpath->vpmgmt_reg = hldev->vpmgmt_reg[vp_id];
+
+	__vxge_hw_vpath_reset(hldev, vp_id);
+
+	status = __vxge_hw_vpath_reset_check(vpath);
+	if (status != VXGE_HW_OK) {
+		memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+		goto exit;
+	}
+
+	VXGE_HW_DEVICE_TIM_INT_MASK_SET(hldev->tim_int_mask0,
+		hldev->tim_int_mask1, vp_id);
+
+	status = __vxge_hw_vpath_initialize(hldev, vp_id);
+
+	if (status != VXGE_HW_OK) {
+		__vxge_hw_vp_terminate(hldev, vpath);
+		goto exit;
+	}
+
+	status = __vxge_hw_vpath_mgmt_read(vpath);
+exit:
+	return status;
+}
+
+/*
+ * __vxge_hw_vp_terminate - Terminate Virtual Path structure
+ * This routine closes all channels it opened and freeup memory
+ */
+void
+__vxge_hw_vp_terminate(struct __vxge_hw_device *hldev,
+			struct __vxge_hw_virtualpath *vpath)
+{
+	vxge_trace();
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN)
+		return;
+
+	VXGE_HW_DEVICE_TIM_INT_MASK_RESET(hldev->tim_int_mask0,
+		hldev->tim_int_mask1, vpath->vp_id);
+
+	memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+}
+
+/*
+ * vxge_hw_vpath_mtu_set - Set MTU.
+ * Set new MTU value. Example, to use jumbo frames:
+ * vxge_hw_vpath_mtu_set(my_device, 9600);
+ */
+enum vxge_hw_status
+vxge_hw_vpath_mtu_set(struct __vxge_hw_virtualpath *vpath, u32 new_mtu)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	new_mtu += VXGE_HW_MAC_HEADER_MAX_SIZE;
+
+	if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > vpath->max_mtu))
+		status = VXGE_HW_ERR_INVALID_MTU_SIZE;
+
+	val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
+
+	val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
+	val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(new_mtu);
+
+	writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
+
+	return status;
+}
+
+/*
+ * vxge_hw_vpath_open - Open a virtual path on a given adapter
+ * This function is used to open access to virtual path of an
+ * adapter for offload, GRO operations. This function returns
+ * synchronously.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_open(struct __vxge_hw_device *hldev, struct vxge_vpath *vpath)
+{
+	struct __vxge_hw_virtualpath *vpathh;
+	enum vxge_hw_status status;
+
+	vxge_trace();
+
+	vpathh = &hldev->virtual_path;
+
+	if (vpath->vp_open == VXGE_HW_VP_OPEN) {
+		status = VXGE_HW_ERR_INVALID_STATE;
+		goto vpath_open_exit1;
+	}
+
+	status = __vxge_hw_vp_initialize(hldev, hldev->first_vp_id, vpathh);
+	if (status != VXGE_HW_OK)
+		goto vpath_open_exit1;
+
+	status = __vxge_hw_fifo_create(vpathh, &vpathh->fifoh);
+	if (status != VXGE_HW_OK)
+		goto vpath_open_exit2;
+
+	status = __vxge_hw_ring_create(vpathh, &vpathh->ringh);
+	if (status != VXGE_HW_OK)
+		goto vpath_open_exit3;
+
+	__vxge_hw_vpath_prc_configure(hldev);
+
+	return VXGE_HW_OK;
+
+vpath_open_exit3:
+	__vxge_hw_fifo_delete(&vpathh->fifoh);
+vpath_open_exit2:
+	__vxge_hw_vp_terminate(hldev, vpathh);
+vpath_open_exit1:
+	return status;
+}
+
+/*
+ * vxge_hw_vpath_rx_doorbell_init -  Post the count of the refreshed region
+ * of RxD list
+ * @vp: vpath handle
+ *
+ * This function decides on the Rxd replenish count depending on the
+ * descriptor memory that has been allocated to this VPath.
+ */
+void
+vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_virtualpath *vpath)
+{
+	u64 new_count, val64;
+
+	vxge_trace();
+
+	if (vpath->hldev->titan1) {
+		new_count = readq(&vpath->vp_reg->rxdmem_size);
+		new_count &= 0x1fff;
+	} else
+		new_count = VXGE_HW_RING_RXD_QWORDS_MODE_1 * 4;
+
+	val64 = (VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count));
+
+	writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val64),
+		&vpath->vp_reg->prc_rxd_doorbell);
+}
+
+/*
+ * vxge_hw_vpath_close - Close the handle got from previous vpath (vpath) open
+ * This function is used to close access to virtual path opened
+ * earlier.
+ */
+enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_virtualpath *vpath)
+{
+	struct __vxge_hw_device *devh = NULL;
+	u32 vp_id = vpath->vp_id;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_trace();
+
+	devh = vpath->hldev;
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+		status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+		goto vpath_close_exit;
+	}
+
+	devh->vpaths_deployed &= ~vxge_mBIT(vp_id);
+
+	__vxge_hw_ring_delete(&vpath->ringh);
+
+	__vxge_hw_fifo_delete(&vpath->fifoh);
+
+	__vxge_hw_vp_terminate(devh, vpath);
+
+	vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
+
+vpath_close_exit:
+	return status;
+}
+
+/*
+ * vxge_hw_vpath_reset - Resets vpath
+ * This function is used to request a reset of vpath
+ */
+enum vxge_hw_status vxge_hw_vpath_reset(struct __vxge_hw_virtualpath *vpath)
+{
+	enum vxge_hw_status status;
+	u32 vp_id;
+
+	vxge_trace();
+
+	vp_id = vpath->vp_id;
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+		status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+		goto exit;
+	}
+
+	status = __vxge_hw_vpath_reset(vpath->hldev, vp_id);
+exit:
+	return status;
+}
+
+/*
+ * vxge_hw_vpath_recover_from_reset - Poll for reset complete and re-initialize.
+ * This function poll's for the vpath reset completion and re initializes
+ * the vpath.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_recover_from_reset(struct __vxge_hw_virtualpath *vpath)
+{
+	enum vxge_hw_status status;
+	struct __vxge_hw_device *hldev;
+	u32 vp_id;
+
+	vxge_trace();
+
+	vp_id = vpath->vp_id;
+	hldev = vpath->hldev;
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+		status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+		goto exit;
+	}
+
+	status = __vxge_hw_vpath_reset_check(vpath);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	status = __vxge_hw_vpath_initialize(hldev, vp_id);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	__vxge_hw_vpath_prc_configure(hldev);
+
+exit:
+	return status;
+}
+
+/*
+ * vxge_hw_vpath_enable - Enable vpath.
+ * This routine clears the vpath reset thereby enabling a vpath
+ * to start forwarding frames and generating interrupts.
+ */
+void
+vxge_hw_vpath_enable(struct __vxge_hw_virtualpath *vpath)
+{
+	struct __vxge_hw_device *hldev;
+	u64 val64;
+
+	vxge_trace();
+
+	hldev = vpath->hldev;
+
+	val64 = VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(
+		1 << (16 - vpath->vp_id));
+
+	__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+		&hldev->common_reg->cmn_rsthdlr_cfg1);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.h
new file mode 100644
index 0000000..bf25134
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_config.h
@@ -0,0 +1,783 @@
+/*
+ * vxge-config.h: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#ifndef VXGE_CONFIG_H
+#define VXGE_CONFIG_H
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/pci.h>
+
+#ifndef VXGE_CACHE_LINE_SIZE
+#define VXGE_CACHE_LINE_SIZE 4096
+#endif
+
+#define WAIT_FACTOR          1
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a)  (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#define VXGE_HW_MAC_MAX_WIRE_PORTS      2
+#define VXGE_HW_MAC_MAX_AGGR_PORTS      2
+#define VXGE_HW_MAC_MAX_PORTS           3
+
+#define VXGE_HW_MIN_MTU				68
+#define VXGE_HW_MAX_MTU				9600
+#define VXGE_HW_DEFAULT_MTU			1500
+
+#ifndef __iomem
+#define __iomem
+#endif
+
+#ifndef ____cacheline_aligned
+#define ____cacheline_aligned
+#endif
+
+/**
+ * debug filtering masks
+ */
+#define	VXGE_NONE	0x00
+#define	VXGE_INFO	0x01
+#define	VXGE_INTR	0x02
+#define	VXGE_XMIT	0x04
+#define VXGE_POLL	0x08
+#define	VXGE_ERR	0x10
+#define VXGE_TRACE	0x20
+#define VXGE_ALL	(VXGE_INFO|VXGE_INTR|VXGE_XMIT\
+			|VXGE_POLL|VXGE_ERR|VXGE_TRACE)
+
+#define NULL_VPID					0xFFFFFFFF
+
+#define VXGE_HW_EVENT_BASE                      0
+#define VXGE_LL_EVENT_BASE                      100
+
+#define VXGE_HW_BASE_INF	100
+#define VXGE_HW_BASE_ERR	200
+#define VXGE_HW_BASE_BADCFG	300
+#define VXGE_HW_DEF_DEVICE_POLL_MILLIS            1000
+#define VXGE_HW_MAX_PAYLOAD_SIZE_512            2
+
+enum vxge_hw_status {
+	VXGE_HW_OK				  = 0,
+	VXGE_HW_FAIL				  = 1,
+	VXGE_HW_PENDING				  = 2,
+	VXGE_HW_COMPLETIONS_REMAIN		  = 3,
+
+	VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS = VXGE_HW_BASE_INF + 1,
+	VXGE_HW_INF_OUT_OF_DESCRIPTORS		  = VXGE_HW_BASE_INF + 2,
+	VXGE_HW_INF_SW_LRO_BEGIN		  = VXGE_HW_BASE_INF + 3,
+	VXGE_HW_INF_SW_LRO_CONT			  = VXGE_HW_BASE_INF + 4,
+	VXGE_HW_INF_SW_LRO_UNCAPABLE		  = VXGE_HW_BASE_INF + 5,
+	VXGE_HW_INF_SW_LRO_FLUSH_SESSION	  = VXGE_HW_BASE_INF + 6,
+	VXGE_HW_INF_SW_LRO_FLUSH_BOTH		  = VXGE_HW_BASE_INF + 7,
+
+	VXGE_HW_ERR_INVALID_HANDLE		  = VXGE_HW_BASE_ERR + 1,
+	VXGE_HW_ERR_OUT_OF_MEMORY		  = VXGE_HW_BASE_ERR + 2,
+	VXGE_HW_ERR_VPATH_NOT_AVAILABLE	  	  = VXGE_HW_BASE_ERR + 3,
+	VXGE_HW_ERR_VPATH_NOT_OPEN		  = VXGE_HW_BASE_ERR + 4,
+	VXGE_HW_ERR_WRONG_IRQ			  = VXGE_HW_BASE_ERR + 5,
+	VXGE_HW_ERR_SWAPPER_CTRL		  = VXGE_HW_BASE_ERR + 6,
+	VXGE_HW_ERR_INVALID_MTU_SIZE		  = VXGE_HW_BASE_ERR + 7,
+	VXGE_HW_ERR_INVALID_INDEX		  = VXGE_HW_BASE_ERR + 8,
+	VXGE_HW_ERR_INVALID_TYPE		  = VXGE_HW_BASE_ERR + 9,
+	VXGE_HW_ERR_INVALID_OFFSET		  = VXGE_HW_BASE_ERR + 10,
+	VXGE_HW_ERR_INVALID_DEVICE		  = VXGE_HW_BASE_ERR + 11,
+	VXGE_HW_ERR_VERSION_CONFLICT		  = VXGE_HW_BASE_ERR + 12,
+	VXGE_HW_ERR_INVALID_PCI_INFO		  = VXGE_HW_BASE_ERR + 13,
+	VXGE_HW_ERR_INVALID_TCODE 		  = VXGE_HW_BASE_ERR + 14,
+	VXGE_HW_ERR_INVALID_BLOCK_SIZE		  = VXGE_HW_BASE_ERR + 15,
+	VXGE_HW_ERR_INVALID_STATE		  = VXGE_HW_BASE_ERR + 16,
+	VXGE_HW_ERR_PRIVILAGED_OPEARATION	  = VXGE_HW_BASE_ERR + 17,
+	VXGE_HW_ERR_INVALID_PORT 		  = VXGE_HW_BASE_ERR + 18,
+	VXGE_HW_ERR_FIFO		 	  = VXGE_HW_BASE_ERR + 19,
+	VXGE_HW_ERR_VPATH			  = VXGE_HW_BASE_ERR + 20,
+	VXGE_HW_ERR_CRITICAL			  = VXGE_HW_BASE_ERR + 21,
+	VXGE_HW_ERR_SLOT_FREEZE 		  = VXGE_HW_BASE_ERR + 22,
+	VXGE_HW_ERR_INVALID_MIN_BANDWIDTH	  = VXGE_HW_BASE_ERR + 25,
+	VXGE_HW_ERR_INVALID_MAX_BANDWIDTH	  = VXGE_HW_BASE_ERR + 26,
+	VXGE_HW_ERR_INVALID_TOTAL_BANDWIDTH	  = VXGE_HW_BASE_ERR + 27,
+	VXGE_HW_ERR_INVALID_BANDWIDTH_LIMIT	  = VXGE_HW_BASE_ERR + 28,
+	VXGE_HW_ERR_RESET_IN_PROGRESS		  = VXGE_HW_BASE_ERR + 29,
+	VXGE_HW_ERR_OUT_OF_SPACE		  = VXGE_HW_BASE_ERR + 30,
+	VXGE_HW_ERR_INVALID_FUNC_MODE		  = VXGE_HW_BASE_ERR + 31,
+	VXGE_HW_ERR_INVALID_DP_MODE		  = VXGE_HW_BASE_ERR + 32,
+	VXGE_HW_ERR_INVALID_FAILURE_BEHAVIOUR	  = VXGE_HW_BASE_ERR + 33,
+	VXGE_HW_ERR_INVALID_L2_SWITCH_STATE	  = VXGE_HW_BASE_ERR + 34,
+	VXGE_HW_ERR_INVALID_CATCH_BASIN_MODE	  = VXGE_HW_BASE_ERR + 35,
+
+	VXGE_HW_BADCFG_RING_INDICATE_MAX_PKTS	  = VXGE_HW_BASE_BADCFG + 1,
+	VXGE_HW_BADCFG_FIFO_BLOCKS		  = VXGE_HW_BASE_BADCFG + 2,
+	VXGE_HW_BADCFG_VPATH_MTU		  = VXGE_HW_BASE_BADCFG + 3,
+	VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG	  = VXGE_HW_BASE_BADCFG + 4,
+	VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH	  = VXGE_HW_BASE_BADCFG + 5,
+	VXGE_HW_BADCFG_VPATH_BANDWIDTH_LIMIT	  = VXGE_HW_BASE_BADCFG + 6,
+	VXGE_HW_BADCFG_INTR_MODE		  = VXGE_HW_BASE_BADCFG + 7,
+	VXGE_HW_BADCFG_RTS_MAC_EN		  = VXGE_HW_BASE_BADCFG + 8,
+	VXGE_HW_BADCFG_VPATH_AGGR_ACK		  = VXGE_HW_BASE_BADCFG + 9,
+	VXGE_HW_BADCFG_VPATH_PRIORITY		  = VXGE_HW_BASE_BADCFG + 10,
+
+	VXGE_HW_EOF_TRACE_BUF			  = -1
+};
+
+/**
+ * enum enum vxge_hw_device_link_state - Link state enumeration.
+ * @VXGE_HW_LINK_NONE: Invalid link state.
+ * @VXGE_HW_LINK_DOWN: Link is down.
+ * @VXGE_HW_LINK_UP: Link is up.
+ *
+ */
+enum vxge_hw_device_link_state {
+	VXGE_HW_LINK_NONE,
+	VXGE_HW_LINK_DOWN,
+	VXGE_HW_LINK_UP
+};
+
+/*forward declaration*/
+struct vxge_vpath;
+struct __vxge_hw_virtualpath;
+
+/**
+ * struct vxge_hw_ring_rxd_1 - One buffer mode RxD for ring
+ *
+ * One buffer mode RxD for ring structure
+ */
+struct vxge_hw_ring_rxd_1 {
+	u64 host_control;
+	u64 control_0;
+#define VXGE_HW_RING_RXD_RTH_BUCKET_GET(ctrl0)		vxge_bVALn(ctrl0, 0, 7)
+
+#define VXGE_HW_RING_RXD_LIST_OWN_ADAPTER		vxge_mBIT(7)
+
+#define VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(ctrl0)	vxge_bVALn(ctrl0, 8, 1)
+
+#define VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(ctrl0)	vxge_bVALn(ctrl0, 9, 1)
+
+#define VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(ctrl0)	vxge_bVALn(ctrl0, 10, 1)
+
+#define VXGE_HW_RING_RXD_T_CODE_GET(ctrl0)		vxge_bVALn(ctrl0, 12, 4)
+#define VXGE_HW_RING_RXD_T_CODE(val) 			vxge_vBIT(val, 12, 4)
+
+#define VXGE_HW_RING_RXD_T_CODE_UNUSED		VXGE_HW_RING_T_CODE_UNUSED
+
+#define VXGE_HW_RING_RXD_SYN_GET(ctrl0)		vxge_bVALn(ctrl0, 16, 1)
+
+#define VXGE_HW_RING_RXD_IS_ICMP_GET(ctrl0)		vxge_bVALn(ctrl0, 17, 1)
+
+#define VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(ctrl0)	vxge_bVALn(ctrl0, 18, 1)
+
+#define VXGE_HW_RING_RXD_RTH_IT_HIT_GET(ctrl0)		vxge_bVALn(ctrl0, 19, 1)
+
+#define VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(ctrl0)	vxge_bVALn(ctrl0, 20, 4)
+
+#define VXGE_HW_RING_RXD_IS_VLAN_GET(ctrl0)		vxge_bVALn(ctrl0, 24, 1)
+
+#define VXGE_HW_RING_RXD_ETHER_ENCAP_GET(ctrl0)		vxge_bVALn(ctrl0, 25, 2)
+
+#define VXGE_HW_RING_RXD_FRAME_PROTO_GET(ctrl0)		vxge_bVALn(ctrl0, 27, 5)
+
+#define VXGE_HW_RING_RXD_L3_CKSUM_GET(ctrl0)	vxge_bVALn(ctrl0, 32, 16)
+
+#define VXGE_HW_RING_RXD_L4_CKSUM_GET(ctrl0)	vxge_bVALn(ctrl0, 48, 16)
+
+	u64 control_1;
+
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(ctrl1)	vxge_bVALn(ctrl1, 2, 14)
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE(val) vxge_vBIT(val, 2, 14)
+#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK		vxge_vBIT(0x3FFF, 2, 14)
+
+#define VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(ctrl1)    vxge_bVALn(ctrl1, 16, 32)
+
+#define VXGE_HW_RING_RXD_VLAN_TAG_GET(ctrl1)	vxge_bVALn(ctrl1, 48, 16)
+
+	u64 buffer0_ptr;
+};
+
+/**
+ * struct vxge_hw_fifo_txd - Transmit Descriptor
+ *
+ * Transmit descriptor (TxD).Fifo descriptor contains configured number
+ * (list) of TxDs. * For more details please refer to Titan User Guide,
+ * Section 5.4.2 "Transmit Descriptor (TxD) Format".
+ */
+struct vxge_hw_fifo_txd {
+	u64 control_0;
+#define VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER		vxge_mBIT(7)
+
+#define VXGE_HW_FIFO_TXD_T_CODE_GET(ctrl0)		vxge_bVALn(ctrl0, 12, 4)
+#define VXGE_HW_FIFO_TXD_T_CODE(val) 			vxge_vBIT(val, 12, 4)
+#define VXGE_HW_FIFO_TXD_T_CODE_UNUSED		VXGE_HW_FIFO_T_CODE_UNUSED
+
+#define VXGE_HW_FIFO_TXD_GATHER_CODE(val) 		vxge_vBIT(val, 22, 2)
+#define VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST	VXGE_HW_FIFO_GATHER_CODE_FIRST
+#define VXGE_HW_FIFO_TXD_GATHER_CODE_LAST	VXGE_HW_FIFO_GATHER_CODE_LAST
+
+#define VXGE_HW_FIFO_TXD_LSO_EN				vxge_mBIT(30)
+#define VXGE_HW_FIFO_TXD_LSO_MSS(val) 			vxge_vBIT(val, 34, 14)
+#define VXGE_HW_FIFO_TXD_BUFFER_SIZE(val) 		vxge_vBIT(val, 48, 16)
+
+	u64 control_1;
+#define VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN			vxge_mBIT(5)
+#define VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN			vxge_mBIT(6)
+#define VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN			vxge_mBIT(7)
+#define VXGE_HW_FIFO_TXD_VLAN_ENABLE			vxge_mBIT(15)
+
+#define VXGE_HW_FIFO_TXD_VLAN_TAG(val) 			vxge_vBIT(val, 16, 16)
+#define VXGE_HW_FIFO_TXD_NO_BW_LIMIT			vxge_mBIT(43)
+
+#define VXGE_HW_FIFO_TXD_INT_NUMBER(val) 		vxge_vBIT(val, 34, 6)
+
+#define VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST		vxge_mBIT(46)
+#define VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ			vxge_mBIT(47)
+
+	u64 buffer_pointer;
+
+	u64 host_control;
+};
+
+/**
+ * struct vxge_hw_device_date - Date Format
+ * @day: Day
+ * @month: Month
+ * @year: Year
+ * @date: Date in string format
+ *
+ * Structure for returning date
+ */
+
+#define VXGE_HW_FW_STRLEN	32
+struct vxge_hw_device_date {
+	u32     day;
+	u32     month;
+	u32     year;
+	char    date[VXGE_HW_FW_STRLEN];
+};
+
+struct vxge_hw_device_version {
+	u32     major;
+	u32     minor;
+	u32     build;
+	char    version[VXGE_HW_FW_STRLEN];
+};
+
+u64 __vxge_hw_vpath_pci_func_mode_get(
+	u32 vp_id,
+	struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+/*
+ * struct __vxge_hw_non_offload_db_wrapper - Non-offload Doorbell Wrapper
+ * @control_0: Bits 0 to 7 - Doorbell type.
+ *             Bits 8 to 31 - Reserved.
+ *             Bits 32 to 39 - The highest TxD in this TxDL.
+ *             Bits 40 to 47 - Reserved.
+ *	       Bits 48 to 55 - Reserved.
+ *             Bits 56 to 63 - No snoop flags.
+ * @txdl_ptr:  The starting location of the TxDL in host memory.
+ *
+ * Created by the host and written to the adapter via PIO to a Kernel Doorbell
+ * FIFO. All non-offload doorbell wrapper fields must be written by the host as
+ * part of a doorbell write. Consumed by the adapter but is not written by the
+ * adapter.
+ */
+struct __vxge_hw_non_offload_db_wrapper {
+	u64		control_0;
+#define	VXGE_HW_NODBW_GET_TYPE(ctrl0)			vxge_bVALn(ctrl0, 0, 8)
+#define VXGE_HW_NODBW_TYPE(val) vxge_vBIT(val, 0, 8)
+#define	VXGE_HW_NODBW_TYPE_NODBW				0
+
+#define	VXGE_HW_NODBW_GET_LAST_TXD_NUMBER(ctrl0)	vxge_bVALn(ctrl0, 32, 8)
+#define VXGE_HW_NODBW_LAST_TXD_NUMBER(val) vxge_vBIT(val, 32, 8)
+
+#define	VXGE_HW_NODBW_GET_NO_SNOOP(ctrl0)		vxge_bVALn(ctrl0, 56, 8)
+#define VXGE_HW_NODBW_LIST_NO_SNOOP(val) vxge_vBIT(val, 56, 8)
+#define	VXGE_HW_NODBW_LIST_NO_SNOOP_TXD_READ_TXD0_WRITE		0x2
+#define	VXGE_HW_NODBW_LIST_NO_SNOOP_TX_FRAME_DATA_READ		0x1
+
+	u64		txdl_ptr;
+};
+
+/*
+ * struct __vxge_hw_fifo - Fifo.
+ * @vp_id: Virtual path id
+ * @tx_intr_num: Interrupt Number associated with the TX
+ * @txdl: Start pointer of the txdl list of this fifo.
+ *        iPXE does not support tx fragmentation, so we need
+ *        only one txd in a list
+ * @depth: total number of lists in this fifo
+ * @hw_offset: txd index from where adapter owns the txd list
+ * @sw_offset: txd index from where driver owns the txd list
+ *
+ * @stats: Statistics of this fifo
+ *
+ */
+struct __vxge_hw_fifo {
+	struct vxge_hw_vpath_reg		*vp_reg;
+	struct __vxge_hw_non_offload_db_wrapper	*nofl_db;
+	u32					vp_id;
+	u32					tx_intr_num;
+
+	struct vxge_hw_fifo_txd		*txdl;
+#define VXGE_HW_FIFO_TXD_DEPTH 128
+	u16				depth;
+	u16				hw_offset;
+	u16				sw_offset;
+
+	struct __vxge_hw_virtualpath    *vpathh;
+};
+
+/* Structure that represents the Rx descriptor block which contains
+ * 128 Rx descriptors.
+ */
+struct __vxge_hw_ring_block {
+#define VXGE_HW_MAX_RXDS_PER_BLOCK_1            127
+	struct vxge_hw_ring_rxd_1 rxd[VXGE_HW_MAX_RXDS_PER_BLOCK_1];
+
+	u64 reserved_0;
+#define END_OF_BLOCK    0xFEFFFFFFFFFFFFFFULL
+	/* 0xFEFFFFFFFFFFFFFF to mark last Rxd in this blk */
+	u64 reserved_1;
+	/* Logical ptr to next */
+	u64 reserved_2_pNext_RxD_block;
+	/* Buff0_ptr.In a 32 bit arch the upper 32 bits should be 0 */
+	u64 pNext_RxD_Blk_physical;
+};
+
+/*
+ * struct __vxge_hw_ring - Ring channel.
+ *
+ * Note: The structure is cache line aligned to better utilize
+ *       CPU cache performance.
+ */
+struct __vxge_hw_ring {
+	struct vxge_hw_vpath_reg		*vp_reg;
+	struct vxge_hw_common_reg		*common_reg;
+	u32					vp_id;
+#define VXGE_HW_RING_RXD_QWORDS_MODE_1	4
+	u32					doorbell_cnt;
+	u32					total_db_cnt;
+#define VXGE_HW_RING_RXD_QWORD_LIMIT	16
+	u64					rxd_qword_limit;
+
+	struct __vxge_hw_ring_block		*rxdl;
+#define VXGE_HW_RING_BUF_PER_BLOCK 	9
+	u16					buf_per_block;
+	u16					rxd_offset;
+
+#define VXGE_HW_RING_RX_POLL_WEIGHT	8
+	u16					rx_poll_weight;
+
+	struct io_buffer *iobuf[VXGE_HW_RING_BUF_PER_BLOCK + 1];
+	struct __vxge_hw_virtualpath *vpathh;
+};
+
+/*
+ * struct __vxge_hw_virtualpath - Virtual Path
+ *
+ * Virtual path structure to encapsulate the data related to a virtual path.
+ * Virtual paths are allocated by the HW upon getting configuration from the
+ * driver and inserted into the list of virtual paths.
+ */
+struct __vxge_hw_virtualpath {
+	u32				vp_id;
+
+	u32				vp_open;
+#define VXGE_HW_VP_NOT_OPEN	0
+#define	VXGE_HW_VP_OPEN		1
+
+	struct __vxge_hw_device		*hldev;
+	struct vxge_hw_vpath_reg	*vp_reg;
+	struct vxge_hw_vpmgmt_reg	*vpmgmt_reg;
+	struct __vxge_hw_non_offload_db_wrapper	*nofl_db;
+
+	u32				max_mtu;
+	u32				vsport_number;
+	u32				max_kdfc_db;
+	u32				max_nofl_db;
+
+	struct __vxge_hw_ring ringh;
+	struct __vxge_hw_fifo fifoh;
+};
+#define VXGE_HW_INFO_LEN	64
+#define VXGE_HW_PMD_INFO_LEN	16
+#define VXGE_MAX_PRINT_BUF_SIZE	128
+/**
+ * struct vxge_hw_device_hw_info - Device information
+ * @host_type: Host Type
+ * @func_id: Function Id
+ * @vpath_mask: vpath bit mask
+ * @fw_version: Firmware version
+ * @fw_date: Firmware Date
+ * @flash_version: Firmware version
+ * @flash_date: Firmware Date
+ * @mac_addrs: Mac addresses for each vpath
+ * @mac_addr_masks: Mac address masks for each vpath
+ *
+ * Returns the vpath mask that has the bits set for each vpath allocated
+ * for the driver and the first mac address for each vpath
+ */
+struct vxge_hw_device_hw_info {
+	u32		host_type;
+#define VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION			0
+#define VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION			1
+#define VXGE_HW_NO_MR_SR_VH0_FUNCTION0				2
+#define VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION			3
+#define VXGE_HW_MR_SR_VH0_INVALID_CONFIG			4
+#define VXGE_HW_SR_VH_FUNCTION0					5
+#define VXGE_HW_SR_VH_VIRTUAL_FUNCTION				6
+#define VXGE_HW_VH_NORMAL_FUNCTION				7
+	u64		function_mode;
+#define VXGE_HW_FUNCTION_MODE_MIN				0
+#define VXGE_HW_FUNCTION_MODE_MAX				11
+
+#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION			0
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION			1
+#define VXGE_HW_FUNCTION_MODE_SRIOV				2
+#define VXGE_HW_FUNCTION_MODE_MRIOV				3
+#define VXGE_HW_FUNCTION_MODE_MRIOV_8				4
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17			5
+#define VXGE_HW_FUNCTION_MODE_SRIOV_8				6
+#define VXGE_HW_FUNCTION_MODE_SRIOV_4				7
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2			8
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_4			9
+#define VXGE_HW_FUNCTION_MODE_MRIOV_4				10
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_DIRECT_IO		11
+
+	u32		func_id;
+	u64		vpath_mask;
+	struct vxge_hw_device_version fw_version;
+	struct vxge_hw_device_date    fw_date;
+	struct vxge_hw_device_version flash_version;
+	struct vxge_hw_device_date    flash_date;
+	u8		serial_number[VXGE_HW_INFO_LEN];
+	u8		part_number[VXGE_HW_INFO_LEN];
+	u8		product_desc[VXGE_HW_INFO_LEN];
+	u8 (mac_addrs)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+	u8 (mac_addr_masks)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+};
+
+/**
+ * struct __vxge_hw_device  - Hal device object
+ * @magic: Magic Number
+ * @bar0: BAR0 virtual address.
+ * @pdev: Physical device handle
+ * @config: Confguration passed by the LL driver at initialization
+ * @link_state: Link state
+ *
+ * HW device object. Represents Titan adapter
+ */
+struct __vxge_hw_device {
+	u32				magic;
+#define VXGE_HW_DEVICE_MAGIC		0x12345678
+#define VXGE_HW_DEVICE_DEAD		0xDEADDEAD
+	void __iomem			*bar0;
+	struct pci_device		*pdev;
+	struct net_device		*ndev;
+	struct vxgedev 			*vdev;
+
+	enum vxge_hw_device_link_state	link_state;
+
+	u32				host_type;
+	u32				func_id;
+	u8				titan1;
+	u32				access_rights;
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH      0x1
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM     0x2
+#define VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM     0x4
+	struct vxge_hw_legacy_reg	*legacy_reg;
+	struct vxge_hw_toc_reg		*toc_reg;
+	struct vxge_hw_common_reg	*common_reg;
+	struct vxge_hw_mrpcim_reg	*mrpcim_reg;
+	struct vxge_hw_srpcim_reg	*srpcim_reg \
+					[VXGE_HW_TITAN_SRPCIM_REG_SPACES];
+	struct vxge_hw_vpmgmt_reg	*vpmgmt_reg \
+					[VXGE_HW_TITAN_VPMGMT_REG_SPACES];
+	struct vxge_hw_vpath_reg	*vpath_reg \
+					[VXGE_HW_TITAN_VPATH_REG_SPACES];
+	u8				*kdfc;
+	u8				*usdc;
+	struct __vxge_hw_virtualpath	virtual_path;
+	u64				vpath_assignments;
+	u64				vpaths_deployed;
+	u32				first_vp_id;
+	u64				tim_int_mask0[4];
+	u32				tim_int_mask1[4];
+
+	struct vxge_hw_device_hw_info   hw_info;
+};
+
+#define VXGE_HW_DEVICE_LINK_STATE_SET(hldev, ls) (hldev->link_state = ls)
+
+#define VXGE_HW_DEVICE_TIM_INT_MASK_SET(m0, m1, i) {	\
+	if (i < 16) {					\
+		m0[0] |= vxge_vBIT(0x8, (i*4), 4);	\
+		m0[1] |= vxge_vBIT(0x4, (i*4), 4);	\
+	}			       		\
+	else {					\
+		m1[0] = 0x80000000;		\
+		m1[1] = 0x40000000;		\
+	}					\
+}
+
+#define VXGE_HW_DEVICE_TIM_INT_MASK_RESET(m0, m1, i) {	\
+	if (i < 16) {					\
+		m0[0] &= ~vxge_vBIT(0x8, (i*4), 4);	\
+		m0[1] &= ~vxge_vBIT(0x4, (i*4), 4);	\
+	}						\
+	else {						\
+		m1[0] = 0;				\
+		m1[1] = 0;				\
+	}						\
+}
+
+/**
+ * enum enum vxge_hw_txdl_state - Descriptor (TXDL) state.
+ * @VXGE_HW_TXDL_STATE_NONE: Invalid state.
+ * @VXGE_HW_TXDL_STATE_AVAIL: Descriptor is available for reservation.
+ * @VXGE_HW_TXDL_STATE_POSTED: Descriptor is posted for processing by the
+ * device.
+ * @VXGE_HW_TXDL_STATE_FREED: Descriptor is free and can be reused for
+ * filling-in and posting later.
+ *
+ * Titan/HW descriptor states.
+ *
+ */
+enum vxge_hw_txdl_state {
+	VXGE_HW_TXDL_STATE_NONE	= 0,
+	VXGE_HW_TXDL_STATE_AVAIL	= 1,
+	VXGE_HW_TXDL_STATE_POSTED	= 2,
+	VXGE_HW_TXDL_STATE_FREED	= 3
+};
+
+
+/* fifo and ring circular buffer offset tracking apis */
+static inline void __vxge_hw_desc_offset_up(u16 upper_limit,
+			u16 *offset)
+{
+	if (++(*offset) >= upper_limit)
+		*offset = 0;
+}
+
+/* rxd offset handling apis */
+static inline void vxge_hw_ring_rxd_offset_up(u16 *offset)
+{
+	__vxge_hw_desc_offset_up(VXGE_HW_MAX_RXDS_PER_BLOCK_1,
+			offset);
+}
+/* txd offset handling apis */
+static inline void vxge_hw_fifo_txd_offset_up(u16 *offset)
+{
+	__vxge_hw_desc_offset_up(VXGE_HW_FIFO_TXD_DEPTH, offset);
+}
+
+/**
+ * vxge_hw_ring_rxd_1b_set - Prepare 1-buffer-mode descriptor.
+ * @rxdh: Descriptor handle.
+ * @dma_pointer: DMA address of	a single receive buffer	this descriptor
+ * should carry. Note that by the time vxge_hw_ring_rxd_1b_set is called,
+ * the receive buffer should be already mapped to the device
+ * @size: Size of the receive @dma_pointer buffer.
+ *
+ * Prepare 1-buffer-mode Rx	descriptor for posting
+ * (via	vxge_hw_ring_rxd_post()).
+ *
+ * This	inline helper-function does not	return any parameters and always
+ * succeeds.
+ *
+ */
+static inline
+void vxge_hw_ring_rxd_1b_set(struct vxge_hw_ring_rxd_1 *rxdp,
+	struct io_buffer *iob, u32 size)
+{
+	rxdp->host_control = (intptr_t)(iob);
+	rxdp->buffer0_ptr = virt_to_bus(iob->data);
+	rxdp->control_1	&= ~VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK;
+	rxdp->control_1	|= VXGE_HW_RING_RXD_1_BUFFER0_SIZE(size);
+}
+
+enum vxge_hw_status vxge_hw_device_hw_info_get(
+	struct pci_device *pdev,
+	void __iomem *bar0,
+	struct vxge_hw_device_hw_info *hw_info);
+
+enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(
+	struct vxge_hw_vpath_reg __iomem *vpath_reg,
+	struct vxge_hw_device_hw_info *hw_info);
+
+enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(
+	struct vxge_hw_vpath_reg __iomem *vpath_reg,
+	struct vxge_hw_device_hw_info *hw_info);
+
+/**
+ * vxge_hw_device_link_state_get - Get link state.
+ * @devh: HW device handle.
+ *
+ * Get link state.
+ * Returns: link state.
+ */
+static inline
+enum vxge_hw_device_link_state vxge_hw_device_link_state_get(
+	struct __vxge_hw_device *devh)
+{
+	return devh->link_state;
+}
+
+void vxge_hw_device_terminate(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status vxge_hw_device_initialize(
+	struct __vxge_hw_device **devh,
+	void *bar0,
+	struct pci_device *pdev,
+	u8 titan1);
+
+enum vxge_hw_status
+vxge_hw_vpath_open(struct __vxge_hw_device *hldev, struct vxge_vpath *vpath);
+
+enum vxge_hw_status
+__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog);
+
+enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_virtualpath *vpath);
+
+enum vxge_hw_status vxge_hw_vpath_reset(struct __vxge_hw_virtualpath *vpath);
+
+enum vxge_hw_status
+vxge_hw_vpath_recover_from_reset(struct __vxge_hw_virtualpath *vpath);
+
+void
+vxge_hw_vpath_enable(struct __vxge_hw_virtualpath *vpath);
+
+enum vxge_hw_status
+vxge_hw_vpath_mtu_set(struct __vxge_hw_virtualpath *vpath, u32 new_mtu);
+
+void
+vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_virtualpath *vpath);
+
+void
+__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg);
+
+enum vxge_hw_status
+__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+enum vxge_hw_status
+__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg,
+	struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+enum vxge_hw_status
+__vxge_hw_device_register_poll(
+	void __iomem	*reg,
+	u64 mask, u32 max_millis);
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+	u64 ret = 0;
+	ret = readl(addr + 4);
+	ret <<= 32;
+	ret |= readl(addr);
+
+	return ret;
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+	writel((u32) (val), addr);
+	writel((u32) (val >> 32), (addr + 4));
+}
+#endif
+
+static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr)
+{
+	writel(val, addr + 4);
+}
+
+static inline void __vxge_hw_pio_mem_write32_lower(u32 val, void __iomem *addr)
+{
+	writel(val, addr);
+}
+
+static inline enum vxge_hw_status
+__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
+			  u64 mask, u32 max_millis)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	__vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
+	wmb();
+	__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
+	wmb();
+
+	status = __vxge_hw_device_register_poll(addr, mask, max_millis);
+	return status;
+}
+
+void
+__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_device_initialize(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_vpath_pci_read(
+	struct __vxge_hw_virtualpath	*vpath,
+	u32			phy_func_0,
+	u32			offset,
+	u32			*val);
+
+enum vxge_hw_status
+__vxge_hw_vpath_addr_get(
+	struct vxge_hw_vpath_reg __iomem *vpath_reg,
+	u8 (macaddr)[ETH_ALEN],
+	u8 (macaddr_mask)[ETH_ALEN]);
+
+u32
+__vxge_hw_vpath_func_id_get(struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg);
+
+enum vxge_hw_status
+__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath);
+
+enum vxge_hw_status
+vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
+
+/**
+ * vxge_debug
+ * @mask: mask for the debug
+ * @fmt: printf like format string
+ */
+static const u16 debug_filter = VXGE_ERR;
+#define vxge_debug(mask, fmt...) 	do { 	\
+		if (debug_filter & mask)	\
+			DBG(fmt); 		\
+	} while (0);
+
+#define vxge_trace() 	vxge_debug(VXGE_TRACE, "%s:%d\n", __func__, __LINE__);
+
+enum vxge_hw_status
+vxge_hw_get_func_mode(struct __vxge_hw_device *hldev, u32 *func_mode);
+
+enum vxge_hw_status
+vxge_hw_set_fw_api(struct __vxge_hw_device *hldev,
+		u64 vp_id, u32 action,
+		u32 offset, u64 data0, u64 data1);
+void
+vxge_hw_vpath_set_zero_rx_frm_len(struct __vxge_hw_device *hldev);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.c
new file mode 100644
index 0000000..b8533d3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.c
@@ -0,0 +1,718 @@
+/*
+ * vxge-main.c: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/io.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/timer.h>
+#include <nic.h>
+
+#include "vxge_main.h"
+#include "vxge_reg.h"
+
+/* function modes strings */
+static char *vxge_func_mode_names[] = {
+	"Single Function - 1 func, 17 vpath",
+	"Multi Function 8 - 8 func, 2 vpath per func",
+	"SRIOV 17 - 17 VF, 1 vpath per VF",
+	"WLPEX/SharedIO 17 - 17 VH, 1 vpath/func/hierarchy",
+	"WLPEX/SharedIO 8 - 8 VH, 2 vpath/func/hierarchy",
+	"Multi Function 17 - 17 func, 1 vpath per func",
+	"SRIOV 8 - 1 PF, 7 VF, 2 vpath per VF",
+	"SRIOV 4 - 1 PF, 3 VF, 4 vpath per VF",
+	"Multi Function 2 - 2 func, 8 vpath per func",
+	"Multi Function 4 - 4 func, 4 vpath per func",
+	"WLPEX/SharedIO 4 - 17 func, 1 vpath per func (PCIe ARI)",
+	"Multi Function 8 - For ESX DirectIO - 8 func, 2 vpath per func",
+};
+
+static inline int is_vxge_card_up(struct vxgedev *vdev)
+{
+	return test_bit(__VXGE_STATE_CARD_UP, vdev->state);
+}
+
+/*
+ * vxge_xmit_compl
+ *
+ * If an interrupt was raised to indicate DMA complete of the Tx packet,
+ * this function is called. It identifies the last TxD whose buffer was
+ * freed and frees all skbs whose data have already DMA'ed into the NICs
+ * internal memory.
+ */
+enum vxge_hw_status
+vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw,
+		struct vxge_hw_fifo_txd *txdp, enum vxge_hw_fifo_tcode tcode)
+{
+	struct net_device *netdev;
+	struct io_buffer *tx_iob = NULL;
+
+	vxge_trace();
+
+	netdev = fifo_hw->vpathh->hldev->ndev;
+
+	tx_iob = (struct io_buffer *)(intptr_t)txdp->host_control;
+
+	if (tcode == VXGE_HW_FIFO_T_CODE_OK) {
+		netdev_tx_complete(netdev, tx_iob);
+	} else {
+		netdev_tx_complete_err(netdev, tx_iob, -EINVAL);
+		vxge_debug(VXGE_ERR, "%s: transmit failed, tcode %d\n",
+				netdev->name, tcode);
+	}
+
+	memset(txdp, 0, sizeof(struct vxge_hw_fifo_txd));
+
+	return VXGE_HW_OK;
+}
+
+/* reset vpaths */
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_virtualpath *vpath;
+
+	vxge_trace();
+
+	vpath = vdev->vpath.vpathh;
+
+	if (vpath) {
+		if ((status = vxge_hw_vpath_reset(vpath)) == VXGE_HW_OK) {
+			if (is_vxge_card_up(vdev) &&
+				(status = vxge_hw_vpath_recover_from_reset(
+					vpath))	!= VXGE_HW_OK) {
+				vxge_debug(VXGE_ERR, "vxge_hw_vpath_recover_"
+					"from_reset failed\n");
+				return status;
+			} else {
+				status = __vxge_hw_vpath_reset_check(vpath);
+				if (status != VXGE_HW_OK) {
+					vxge_debug(VXGE_ERR,
+					"__vxge_hw_vpath_reset_check error\n");
+					return status;
+				}
+			}
+		} else {
+			vxge_debug(VXGE_ERR, "vxge_hw_vpath_reset failed\n");
+			return status;
+		}
+	}
+	return status;
+}
+
+/* close vpaths */
+void vxge_close_vpaths(struct vxgedev *vdev)
+{
+
+	if (vdev->vpath.vpathh && vdev->vpath.is_open)
+		vxge_hw_vpath_close(vdev->vpath.vpathh);
+
+	vdev->vpath.is_open = 0;
+	vdev->vpath.vpathh = NULL;
+}
+
+/* open vpaths */
+int vxge_open_vpaths(struct vxgedev *vdev)
+{
+	enum vxge_hw_status status;
+	struct __vxge_hw_device *hldev;
+
+	hldev = (struct __vxge_hw_device  *)pci_get_drvdata(vdev->pdev);
+
+	vdev->vpath.vpathh = &hldev->virtual_path;
+	vdev->vpath.fifo.ndev = vdev->ndev;
+	vdev->vpath.fifo.pdev = vdev->pdev;
+	vdev->vpath.fifo.fifoh = &hldev->virtual_path.fifoh;
+	vdev->vpath.ring.ndev = vdev->ndev;
+	vdev->vpath.ring.pdev = vdev->pdev;
+	vdev->vpath.ring.ringh = &hldev->virtual_path.ringh;
+
+	status = vxge_hw_vpath_open(vdev->devh,	&vdev->vpath);
+	if (status == VXGE_HW_OK) {
+		vdev->vpath.is_open = 1;
+	} else {
+		vxge_debug(VXGE_ERR,
+			"%s: vpath: %d failed to open "
+			"with status: %d\n",
+			vdev->ndev->name, vdev->vpath.device_id,
+			status);
+		vxge_close_vpaths(vdev);
+		return status;
+	}
+
+	hldev->vpaths_deployed |= vxge_mBIT(vdev->vpath.vpathh->vp_id);
+
+	return VXGE_HW_OK;
+}
+
+/** Functions that implement the iPXE driver API **/
+
+/**
+ * vxge_xmit
+ * @skb : the socket buffer containing the Tx data.
+ * @dev : device pointer.
+ *
+ * This function is the Tx entry point of the driver. Neterion NIC supports
+ * certain protocol assist features on Tx side, namely  CSO, S/G, LSO.
+ */
+static int
+vxge_xmit(struct net_device *dev, struct io_buffer *iobuf)
+{
+	struct vxge_fifo *fifo = NULL;
+	struct vxgedev *vdev = NULL;
+	struct __vxge_hw_fifo *fifoh;
+	struct vxge_hw_fifo_txd *txdp;
+
+	vxge_trace();
+
+	vdev = (struct vxgedev *)netdev_priv(dev);
+
+	if (!is_vxge_card_up(vdev)) {
+		vxge_debug(VXGE_ERR,
+			"%s: vdev not initialized\n", dev->name);
+		return -EIO;
+	}
+
+	if (!netdev_link_ok(dev)) {
+		vxge_debug(VXGE_ERR,
+			"%s: Link down, transmit failed\n", dev->name);
+		return -ENETDOWN;
+	}
+
+	fifo = &vdev->vpath.fifo;
+	fifoh = fifo->fifoh;
+
+	txdp = vxge_hw_fifo_free_txdl_get(fifoh);
+	if (!txdp) {
+		vxge_debug(VXGE_ERR,
+			"%s: Out of tx descriptors\n", dev->name);
+		return -ENOBUFS;
+	}
+
+	vxge_debug(VXGE_XMIT, "%s: %s:%d fifoh offset= %d\n",
+		dev->name, __func__, __LINE__, fifoh->sw_offset);
+
+	vxge_hw_fifo_txdl_buffer_set(fifoh, txdp, iobuf);
+
+	vxge_hw_fifo_txdl_post(fifoh, txdp);
+
+	return 0;
+}
+
+/*
+ *  vxge_poll
+ *  @ndev: net device pointer
+ *
+ *  This function acks the interrupt. It polls for rx packets
+ *  and send to upper layer. It also checks for tx completion
+ *  and frees iobs.
+ */
+static void vxge_poll(struct net_device *ndev)
+{
+	struct __vxge_hw_device  *hldev;
+	struct vxgedev *vdev;
+
+	vxge_debug(VXGE_POLL, "%s:%d \n", __func__, __LINE__);
+
+	vdev = (struct vxgedev *)netdev_priv(ndev);
+	hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+
+	if (!is_vxge_card_up(vdev))
+		return;
+
+	/* process alarm and acknowledge the interrupts */
+	vxge_hw_device_begin_irq(hldev);
+
+	vxge_hw_vpath_poll_tx(&hldev->virtual_path.fifoh);
+
+	vxge_hw_vpath_poll_rx(&hldev->virtual_path.ringh);
+}
+
+/*
+ * vxge_irq - enable or Disable interrupts
+ *
+ * @netdev   netdevice sturcture reference
+ * @action   requested interrupt action
+ */
+static void vxge_irq(struct net_device *netdev __unused, int action)
+{
+	struct __vxge_hw_device  *hldev;
+	struct vxgedev *vdev;
+
+	vxge_debug(VXGE_INFO,
+		"%s:%d action(%d)\n", __func__, __LINE__, action);
+
+	vdev = (struct vxgedev *)netdev_priv(netdev);
+	hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+
+	switch (action) {
+	case DISABLE:
+		vxge_hw_device_mask_all(hldev);
+		break;
+	default:
+		vxge_hw_device_unmask_all(hldev);
+		break;
+	}
+}
+
+/**
+ * vxge_open
+ * @dev: pointer to the device structure.
+ *
+ * This function is the open entry point of the driver. It mainly calls a
+ * function to allocate Rx buffers and inserts them into the buffer
+ * descriptors and then enables the Rx part of the NIC.
+ * Return value: '0' on success and an appropriate (-)ve integer as
+ * defined in errno.h file on failure.
+ */
+int
+vxge_open(struct net_device *dev)
+{
+	enum vxge_hw_status status;
+	struct vxgedev *vdev;
+	struct __vxge_hw_device *hldev;
+	int ret = 0;
+
+	vxge_debug(VXGE_INFO, "%s: %s:%d\n",
+			VXGE_DRIVER_NAME, __func__, __LINE__);
+
+	vdev = (struct vxgedev *)netdev_priv(dev);
+	hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+
+	/* make sure you have link off by default every time Nic is
+	 * initialized */
+	netdev_link_down(dev);
+
+	/* Open VPATHs */
+	status = vxge_open_vpaths(vdev);
+	if (status != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR, "%s: fatal: Vpath open failed\n",
+				VXGE_DRIVER_NAME);
+		ret = -EPERM;
+		goto out0;
+	}
+
+	vdev->mtu = VXGE_HW_DEFAULT_MTU;
+	/* set initial mtu before enabling the device */
+	status = vxge_hw_vpath_mtu_set(vdev->vpath.vpathh, vdev->mtu);
+	if (status != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR,
+			"%s: fatal: can not set new MTU\n", dev->name);
+		ret = -EPERM;
+		goto out2;
+	}
+	vxge_debug(VXGE_INFO,
+		"%s: MTU is %d\n", vdev->ndev->name, vdev->mtu);
+
+	set_bit(__VXGE_STATE_CARD_UP, vdev->state);
+
+	wmb();
+
+	if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
+		netdev_link_up(vdev->ndev);
+		vxge_debug(VXGE_INFO, "%s: Link Up\n", vdev->ndev->name);
+	}
+
+	vxge_hw_device_intr_enable(hldev);
+
+	vxge_hw_vpath_enable(vdev->vpath.vpathh);
+	wmb();
+	vxge_hw_vpath_rx_doorbell_init(vdev->vpath.vpathh);
+
+	goto out0;
+
+out2:
+	vxge_close_vpaths(vdev);
+out0:
+	vxge_debug(VXGE_INFO, "%s: %s:%d  Exiting...\n",
+				dev->name, __func__, __LINE__);
+	return ret;
+}
+
+/**
+ * vxge_close
+ * @dev: device pointer.
+ *
+ * This is the stop entry point of the driver. It needs to undo exactly
+ * whatever was done by the open entry point, thus it's usually referred to
+ * as the close function.Among other things this function mainly stops the
+ * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
+ * Return value: '0' on success and an appropriate (-)ve integer as
+ * defined in errno.h file on failure.
+ */
+static void vxge_close(struct net_device *dev)
+{
+	struct vxgedev *vdev;
+	struct __vxge_hw_device *hldev;
+
+	vxge_debug(VXGE_INFO, "%s: %s:%d\n",
+		dev->name, __func__, __LINE__);
+
+	vdev = (struct vxgedev *)netdev_priv(dev);
+	hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+
+	if (!is_vxge_card_up(vdev))
+		return;
+
+	clear_bit(__VXGE_STATE_CARD_UP, vdev->state);
+
+	vxge_hw_vpath_set_zero_rx_frm_len(hldev);
+
+	netdev_link_down(vdev->ndev);
+	vxge_debug(VXGE_INFO, "%s: Link Down\n", vdev->ndev->name);
+
+	/* Note that at this point xmit() is stopped by upper layer */
+	vxge_hw_device_intr_disable(hldev);
+
+	/* Multi function shares INTA, hence we should
+	 * leave it in enabled state
+	 */
+	if (is_mf(hldev->hw_info.function_mode))
+		vxge_hw_device_unmask_all(hldev);
+
+	vxge_reset_all_vpaths(vdev);
+
+	vxge_close_vpaths(vdev);
+
+	vxge_debug(VXGE_INFO,
+		"%s: %s:%d  Exiting...\n", dev->name, __func__, __LINE__);
+}
+
+static struct net_device_operations vxge_operations;
+
+int vxge_device_register(struct __vxge_hw_device *hldev,
+				struct vxgedev **vdev_out)
+{
+	struct net_device *ndev;
+	struct vxgedev *vdev;
+	int ret = 0;
+
+	*vdev_out = NULL;
+
+	ndev = alloc_etherdev(sizeof(struct vxgedev));
+	if (ndev == NULL) {
+		vxge_debug(VXGE_ERR, "%s : device allocation failed\n",
+				__func__);
+		ret = -ENODEV;
+		goto _out0;
+	}
+
+	vxge_debug(VXGE_INFO, "%s:%d  netdev registering\n",
+		__func__, __LINE__);
+	vdev = netdev_priv(ndev);
+	memset(vdev, 0, sizeof(struct vxgedev));
+
+	vdev->ndev = ndev;
+	vdev->devh = hldev;
+	vdev->pdev = hldev->pdev;
+
+	ndev->dev = &vdev->pdev->dev;
+	/* Associate vxge-specific network operations operations with
+	 * generic network device layer */
+	netdev_init(ndev, &vxge_operations);
+
+	memcpy(ndev->hw_addr,
+		(u8 *)hldev->hw_info.mac_addrs[hldev->first_vp_id], ETH_ALEN);
+
+	if (register_netdev(ndev)) {
+		vxge_debug(VXGE_ERR, "%s : device registration failed!\n",
+			__func__);
+		ret = -ENODEV;
+		goto _out2;
+	}
+
+	/* Leave link state as off at this point, when the link change
+	 * interrupt comes the state will be automatically changed to
+	 * the right state.
+	 */
+
+	vxge_debug(VXGE_INFO, "%s: Ethernet device registered\n",
+		VXGE_DRIVER_NAME);
+
+	*vdev_out = vdev;
+
+	return ret;
+_out2:
+	netdev_put(ndev);
+_out0:
+	return ret;
+}
+
+/*
+ * vxge_device_unregister
+ *
+ * This function will unregister and free network device
+ */
+void
+vxge_device_unregister(struct __vxge_hw_device *hldev)
+{
+	struct net_device *ndev;
+
+	ndev = hldev->ndev;
+
+	unregister_netdev(ndev);
+	netdev_nullify(ndev);
+	netdev_put(ndev);
+
+	vxge_debug(VXGE_INFO, "%s: ethernet device unregistered\n",
+				VXGE_DRIVER_NAME);
+}
+
+/**
+ * vxge_probe
+ * @pdev : structure containing the PCI related information of the device.
+ * @id: List of PCI devices supported by the driver listed in vxge_id_table.
+ * Description:
+ * This function is called when a new PCI device gets detected and initializes
+ * it.
+ * Return value:
+ * returns 0 on success and negative on failure.
+ *
+ */
+static int
+vxge_probe(struct pci_device *pdev)
+{
+	struct __vxge_hw_device  *hldev;
+	enum vxge_hw_status status;
+	int ret = 0;
+	u64 vpath_mask = 0;
+	struct vxgedev *vdev;
+	int i;
+	u8 revision, titan1;
+	u32 function_mode;
+	unsigned long mmio_start, mmio_len;
+	void *bar0;
+	struct vxge_hw_device_hw_info hw_info;
+	struct vxge_hw_device_version *fw_version;
+
+	vxge_debug(VXGE_INFO, "vxge_probe for device " PCI_FMT "\n",
+			PCI_ARGS(pdev));
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
+	titan1 = is_titan1(pdev->device, revision);
+
+	mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	mmio_len   = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
+	vxge_debug(VXGE_INFO, "mmio_start: %#08lx, mmio_len: %#08lx\n",
+			mmio_start, mmio_len);
+
+	/* sets the bus master */
+	adjust_pci_device(pdev);
+
+	bar0 = ioremap(mmio_start, mmio_len);
+	if (!bar0) {
+		vxge_debug(VXGE_ERR,
+			"%s : cannot remap io memory bar0\n", __func__);
+		ret = -ENODEV;
+		goto _exit0;
+	}
+
+	status = vxge_hw_device_hw_info_get(pdev, bar0, &hw_info);
+	if (status != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR,
+			"%s: Reading of hardware info failed.\n",
+			VXGE_DRIVER_NAME);
+		ret = -EINVAL;
+		goto _exit1;
+	}
+
+	if (hw_info.func_id != 0) {
+		/* Non zero function, So do not load the driver */
+		iounmap(bar0);
+		pci_set_drvdata(pdev, NULL);
+		return -EINVAL;
+	}
+
+
+	vpath_mask = hw_info.vpath_mask;
+	if (vpath_mask == 0) {
+		vxge_debug(VXGE_ERR,
+			"%s: No vpaths available in device\n",
+			VXGE_DRIVER_NAME);
+		ret = -EINVAL;
+		goto _exit1;
+	}
+	vxge_debug(VXGE_INFO,
+		"%s:%d  Vpath mask = %llx\n", __func__, __LINE__,
+		(unsigned long long)vpath_mask);
+
+	fw_version = &hw_info.fw_version;
+	/* fail the driver loading if firmware is incompatible */
+	if ((fw_version->major != VXGE_CERT_FW_VER_MAJOR) ||
+		(fw_version->minor < VXGE_CERT_FW_VER_MINOR)) {
+		printf("%s: Adapter's current firmware version: %d.%d.%d\n",
+			VXGE_DRIVER_NAME, fw_version->major,
+			fw_version->minor, fw_version->build);
+
+		printf("%s: Upgrade firmware to version %d.%d.%d\n",
+			VXGE_DRIVER_NAME, VXGE_CERT_FW_VER_MAJOR,
+			VXGE_CERT_FW_VER_MINOR,	VXGE_CERT_FW_VER_BUILD);
+
+		ret = -EACCES;
+		goto _exit1;
+	}
+
+	status = vxge_hw_device_initialize(&hldev, bar0, pdev, titan1);
+	if (status != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR,
+			"Failed to initialize device (%d)\n", status);
+			ret = -EINVAL;
+			goto _exit1;
+	}
+	memcpy(&hldev->hw_info, &hw_info,
+		sizeof(struct vxge_hw_device_hw_info));
+
+	/* find the vpath id of the first available one */
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
+		if (vpath_mask & vxge_mBIT(i)) {
+			hldev->first_vp_id = i;
+			break;
+		}
+	/* if FCS stripping is not disabled in MAC fail driver load */
+	if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) {
+		vxge_debug(VXGE_ERR,
+			"%s: FCS stripping is not disabled in MAC"
+			" failing driver load\n", VXGE_DRIVER_NAME);
+		ret = -EINVAL;
+		goto _exit2;
+	}
+
+	/* Read function mode */
+	status = vxge_hw_get_func_mode(hldev, &function_mode);
+	if (status != VXGE_HW_OK)
+		goto _exit2;
+
+	hldev->hw_info.function_mode = function_mode;
+
+	/* set private device info */
+	pci_set_drvdata(pdev, hldev);
+
+	if (vxge_device_register(hldev,	&vdev)) {
+		ret = -EINVAL;
+		goto _exit2;
+	}
+
+	/* set private HW device info */
+	hldev->ndev = vdev->ndev;
+	hldev->vdev = vdev;
+	hldev->pdev = pdev;
+	vdev->mtu = VXGE_HW_DEFAULT_MTU;
+	vdev->bar0 = bar0;
+	vdev->titan1 = titan1;
+	/* Virtual Path count */
+	vdev->vpath.device_id = hldev->first_vp_id;
+	vdev->vpath.vdev = vdev;
+	memcpy((u8 *)vdev->vpath.macaddr,
+			(u8 *)hldev->hw_info.mac_addrs[hldev->first_vp_id],
+			ETH_ALEN);
+
+	hldev->hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
+	hldev->hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
+	hldev->hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
+
+	vxge_debug(VXGE_INFO, "%s: Neterion %s Server Adapter\n",
+		VXGE_DRIVER_NAME, hldev->hw_info.product_desc);
+	vxge_debug(VXGE_INFO, "%s: SERIAL NUMBER: %s\n",
+		VXGE_DRIVER_NAME, hldev->hw_info.serial_number);
+	vxge_debug(VXGE_INFO, "%s: PART NUMBER: %s\n",
+		VXGE_DRIVER_NAME, hldev->hw_info.part_number);
+	vxge_debug(VXGE_INFO, "%s: MAC ADDR: %s\n",
+		VXGE_DRIVER_NAME, eth_ntoa(vdev->vpath.macaddr));
+	vxge_debug(VXGE_INFO,
+		"%s: Firmware version : %s Date : %s\n", VXGE_DRIVER_NAME,
+		hldev->hw_info.fw_version.version,
+		hldev->hw_info.fw_date.date);
+	vxge_debug(VXGE_INFO, "%s: %s Enabled\n",
+			VXGE_DRIVER_NAME, vxge_func_mode_names[function_mode]);
+
+	vxge_debug(VXGE_INFO, "%s: %s:%d  Probe Exiting...\n",
+		VXGE_DRIVER_NAME, __func__, __LINE__);
+
+	return 0;
+
+_exit2:
+	vxge_hw_device_terminate(hldev);
+_exit1:
+	iounmap(bar0);
+_exit0:
+	pci_set_drvdata(pdev, NULL);
+	printf("%s: WARNING!! Driver loading failed!!\n",
+		VXGE_DRIVER_NAME);
+
+	return ret;
+}
+
+/**
+ * vxge_remove - Free the PCI device
+ * @pdev: structure containing the PCI related information of the device.
+ * Description: This function is called by the Pci subsystem to release a
+ * PCI device and free up all resource held up by the device.
+ */
+static void
+vxge_remove(struct pci_device *pdev)
+{
+	struct __vxge_hw_device  *hldev;
+	struct vxgedev *vdev = NULL;
+	struct net_device *ndev;
+
+	vxge_debug(VXGE_INFO,
+		"%s:%d\n", __func__, __LINE__);
+	hldev = (struct __vxge_hw_device  *) pci_get_drvdata(pdev);
+	if (hldev == NULL)
+		return;
+
+	ndev = hldev->ndev;
+	vdev = netdev_priv(ndev);
+
+	iounmap(vdev->bar0);
+
+	vxge_device_unregister(hldev);
+
+	vxge_debug(VXGE_INFO,
+		"%s:%d  Device unregistered\n", __func__, __LINE__);
+
+	vxge_hw_device_terminate(hldev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+/* vxge net device operations */
+static struct net_device_operations vxge_operations = {
+	.open           = vxge_open,
+	.close          = vxge_close,
+	.transmit       = vxge_xmit,
+	.poll           = vxge_poll,
+	.irq            = vxge_irq,
+};
+
+static struct pci_device_id vxge_main_nics[] = {
+	/* If you change this, also adjust vxge_nics[] in vxge.c */
+	PCI_ID(0x17d5, 0x5833, "vxge-x3100", "Neterion X3100 Series", 0),
+};
+
+struct pci_driver vxge_driver __pci_driver = {
+	.ids = vxge_main_nics,
+	.id_count = (sizeof(vxge_main_nics) / sizeof(vxge_main_nics[0])),
+	.probe = vxge_probe,
+	.remove = vxge_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.h
new file mode 100644
index 0000000..550dcef
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_main.h
@@ -0,0 +1,230 @@
+/*
+ * vxge-main.h: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#ifndef VXGE_MAIN_H
+#define VXGE_MAIN_H
+
+#include <unistd.h>
+#include "vxge_traffic.h"
+#include "vxge_config.h"
+
+#define VXGE_DRIVER_NAME		"vxge"
+#define VXGE_DRIVER_VENDOR		"Neterion, Inc"
+
+#ifndef PCI_VENDOR_ID_S2IO
+#define PCI_VENDOR_ID_S2IO		0x17D5
+#endif
+
+#ifndef PCI_DEVICE_ID_TITAN_WIN
+#define PCI_DEVICE_ID_TITAN_WIN		0x5733
+#endif
+
+#ifndef PCI_DEVICE_ID_TITAN_UNI
+#define PCI_DEVICE_ID_TITAN_UNI		0x5833
+#endif
+
+#define VXGE_HW_TITAN1_PCI_REVISION	1
+#define	VXGE_HW_TITAN1A_PCI_REVISION	2
+
+#define	VXGE_HP_ISS_SUBSYS_VENDORID	0x103C
+#define	VXGE_HP_ISS_SUBSYS_DEVICEID_1	0x323B
+#define	VXGE_HP_ISS_SUBSYS_DEVICEID_2	0x323C
+
+#define	VXGE_USE_DEFAULT		0xffffffff
+#define VXGE_HW_VPATH_MSIX_ACTIVE	4
+#define VXGE_ALARM_MSIX_ID		2
+#define VXGE_HW_RXSYNC_FREQ_CNT		4
+#define VXGE_LL_RX_COPY_THRESHOLD	256
+#define VXGE_DEF_FIFO_LENGTH		84
+
+#define NO_STEERING		0
+#define PORT_STEERING		0x1
+#define RTH_TCP_UDP_STEERING	0x2
+#define RTH_IPV4_STEERING	0x3
+#define RTH_IPV6_EX_STEERING	0x4
+#define RTH_BUCKET_SIZE		8
+
+#define	TX_PRIORITY_STEERING		1
+#define	TX_VLAN_STEERING		2
+#define	TX_PORT_STEERING		3
+#define	TX_MULTIQ_STEERING		4
+
+#define VXGE_HW_PROM_MODE_ENABLE	1
+#define VXGE_HW_PROM_MODE_DISABLE	0
+
+#define VXGE_HW_FW_UPGRADE_DISABLE	0
+#define VXGE_HW_FW_UPGRADE_ALL		1
+#define VXGE_HW_FW_UPGRADE_FORCE	2
+#define VXGE_HW_FUNC_MODE_DISABLE	0
+
+#define VXGE_TTI_BTIMER_VAL 250000
+#define VXGE_T1A_TTI_LTIMER_VAL 80
+#define VXGE_T1A_TTI_RTIMER_VAL 400
+
+#define VXGE_TTI_LTIMER_VAL 1000
+#define VXGE_TTI_RTIMER_VAL 0
+#define VXGE_RTI_BTIMER_VAL 250
+#define VXGE_RTI_LTIMER_VAL 100
+#define VXGE_RTI_RTIMER_VAL 0
+#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH
+#define VXGE_ISR_POLLING_CNT 	8
+#define VXGE_MAX_CONFIG_DEV	0xFF
+#define VXGE_EXEC_MODE_DISABLE	0
+#define VXGE_EXEC_MODE_ENABLE	1
+#define VXGE_MAX_CONFIG_PORT	1
+#define VXGE_ALL_VID_DISABLE	0
+#define VXGE_ALL_VID_ENABLE	1
+#define VXGE_PAUSE_CTRL_DISABLE	0
+#define VXGE_PAUSE_CTRL_ENABLE	1
+
+#define TTI_TX_URANGE_A	5
+#define TTI_TX_URANGE_B	15
+#define TTI_TX_URANGE_C	40
+#define TTI_TX_UFC_A	5
+#define TTI_TX_UFC_B	40
+#define TTI_TX_UFC_C	60
+#define TTI_TX_UFC_D	100
+#define TTI_T1A_TX_UFC_A	30
+#define TTI_T1A_TX_UFC_B	80
+
+/* Slope - (max_mtu - min_mtu)/(max_mtu_ufc - min_mtu_ufc) */
+/* Slope - 93 */
+/* 60 - 9k Mtu, 140 - 1.5k mtu */
+#define TTI_T1A_TX_UFC_C(mtu)	(60 + ((VXGE_HW_MAX_MTU - mtu)/93))
+
+/* Slope - 37 */
+/* 100 - 9k Mtu, 300 - 1.5k mtu */
+#define TTI_T1A_TX_UFC_D(mtu)	(100 + ((VXGE_HW_MAX_MTU - mtu)/37))
+
+#define RTI_RX_URANGE_A		5
+#define RTI_RX_URANGE_B		15
+#define RTI_RX_URANGE_C		40
+#define RTI_T1A_RX_URANGE_A	1
+#define RTI_T1A_RX_URANGE_B	20
+#define RTI_T1A_RX_URANGE_C	50
+#define RTI_RX_UFC_A		1
+#define RTI_RX_UFC_B		5
+#define RTI_RX_UFC_C		10
+#define RTI_RX_UFC_D		15
+#define RTI_T1A_RX_UFC_B	20
+#define RTI_T1A_RX_UFC_C	50
+#define RTI_T1A_RX_UFC_D	60
+
+/*
+ * The interrupt rate is maintained at 3k per second with the moderation
+ * parameters for most traffics but not all. This is the maximum interrupt
+ * count per allowed per function with INTA or per vector in the case of in a
+ * MSI-X 10 millisecond time period. Enabled only for Titan 1A.
+ */
+#define VXGE_T1A_MAX_INTERRUPT_COUNT 100
+
+#define VXGE_ENABLE_NAPI	1
+#define VXGE_DISABLE_NAPI	0
+#define VXGE_LRO_MAX_BYTES 0x4000
+#define VXGE_T1A_LRO_MAX_BYTES 0xC000
+
+#define VXGE_HW_MIN_VPATH_TX_BW_SUPPORT 0
+#define VXGE_HW_MAX_VPATH_TX_BW_SUPPORT 7
+
+/* Milli secs timer period */
+#define VXGE_TIMER_DELAY		10000
+
+#define VXGE_TIMER_COUNT    	(2 * 60)
+
+#define VXGE_LL_MAX_FRAME_SIZE(dev) ((dev)->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE)
+
+#define VXGE_REG_DUMP_BUFSIZE           65000
+
+#define is_mf(function_mode) \
+	((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) ||   \
+	(function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17) || \
+	(function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2) ||  \
+	(function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_4))
+
+#define is_titan1(dev_id, rev) (((dev_id == PCI_DEVICE_ID_TITAN_UNI) || \
+				(dev_id == PCI_DEVICE_ID_TITAN_WIN)) && \
+				(rev == VXGE_HW_TITAN1_PCI_REVISION))
+
+/* These flags represent the devices temporary state */
+#define __VXGE_STATE_RESET_CARD 	0x01
+#define __VXGE_STATE_CARD_UP		0x02
+
+#define test_bit(bit, loc) 	((bit) & (loc))
+#define set_bit(bit, loc) 	do { (loc) |= (bit); } while (0);
+#define clear_bit(bit, loc) 	do { (loc) &= ~(bit); } while (0);
+
+#define msleep(n)       mdelay(n)
+
+struct vxge_fifo {
+	struct net_device	*ndev;
+	struct pci_device	*pdev;
+	struct __vxge_hw_fifo   *fifoh;
+};
+
+struct vxge_ring {
+	struct net_device	*ndev;
+	struct pci_device	*pdev;
+	struct __vxge_hw_ring	*ringh;
+};
+
+struct vxge_vpath {
+
+	struct vxge_fifo fifo;
+	struct vxge_ring ring;
+
+	/* Actual vpath id for this vpath in the device - 0 to 16 */
+	int device_id;
+	int is_open;
+	int vp_open;
+	u8 (macaddr)[ETH_ALEN];
+	u8 (macmask)[ETH_ALEN];
+	struct vxgedev *vdev;
+	struct __vxge_hw_virtualpath *vpathh;
+};
+
+struct vxgedev {
+	struct net_device	*ndev;
+	struct pci_device	*pdev;
+	struct __vxge_hw_device *devh;
+	u8			titan1;
+
+	unsigned long		state;
+
+	struct vxge_vpath 	vpath;
+
+	void __iomem 		*bar0;
+	int			mtu;
+
+	char			fw_version[VXGE_HW_FW_STRLEN];
+};
+
+void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id);
+
+void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id);
+
+int vxge_reset(struct vxgedev *vdev);
+
+enum vxge_hw_status
+vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw,
+	struct vxge_hw_fifo_txd *txdp, enum vxge_hw_fifo_tcode tcode);
+
+void vxge_close_vpaths(struct vxgedev *vdev);
+
+int vxge_open_vpaths(struct vxgedev *vdev);
+
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_reg.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_reg.h
new file mode 100644
index 0000000..a76f24e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_reg.h
@@ -0,0 +1,4700 @@
+/*
+ * vxge-reg.h: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#ifndef VXGE_REG_H
+#define VXGE_REG_H
+
+#include <stdint.h>
+/*
+ * vxge_mBIT(loc) - set bit at offset
+ */
+#define vxge_mBIT(loc)		(0x8000000000000000ULL >> (loc))
+
+/*
+ * vxge_vBIT(val, loc, sz) - set bits at offset
+ */
+#define vxge_vBIT(val, loc, sz)	(((u64)(val)) << (64-(loc)-(sz)))
+#define vxge_vBIT32(val, loc, sz)	(((u32)(val)) << (32-(loc)-(sz)))
+
+/*
+ * vxge_bVALn(bits, loc, n) - Get the value of n bits at location
+ */
+#define vxge_bVALn(bits, loc, n) \
+	((((u64)bits) >> (64-(loc+n))) & ((0x1ULL << n) - 1))
+
+#define	VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(bits) \
+							vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(bits) \
+							vxge_bVALn(bits, 48, 8)
+#define	VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(bits) \
+							vxge_bVALn(bits, 56, 8)
+
+#define	VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(bits) \
+							vxge_bVALn(bits, 3, 5)
+#define	VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(bits) \
+							vxge_bVALn(bits, 5, 3)
+#define VXGE_HW_PF_SW_RESET_COMMAND				0xA5
+
+#define VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES		17
+#define VXGE_HW_TITAN_SRPCIM_REG_SPACES			17
+#define VXGE_HW_TITAN_VPMGMT_REG_SPACES			17
+#define VXGE_HW_TITAN_VPATH_REG_SPACES			17
+
+
+#define VXGE_HW_PRIV_FN_ACTION			8
+#define VXGE_HW_PRIV_VP_ACTION			5
+#define VXGE_HW_PRIV_FN_MEMO			13
+#define VXGE_HW_EN_DIS_UDP_RTH			10
+#define VXGE_HW_BW_CONTROL			12
+#define VXGE_HW_RTS_ACCESS_FW_MEMO_ACTION_PRIV_NWIF	17
+
+#define VXGE_HW_FW_API_FUNC_MODE		11
+#define VXGE_HW_FW_API_GET_FUNC_MODE		29
+#define VXGE_HW_FW_API_FUNC_MODE_COMMIT		21
+#define VXGE_HW_GET_FUNC_MODE_VAL(val)		(val & 0xFF)
+
+#define VXGE_HW_BYTES_PER_U64			8
+#define VXGE_HW_FW_UPGRADE_MEMO			13
+#define VXGE_HW_FW_UPGRADE_ACTION		16
+#define VXGE_HW_FW_UPGRADE_OFFSET_START		2 /* Start upgrade */
+#define VXGE_HW_FW_UPGRADE_OFFSET_SEND		3 /* Send upgrade data */
+#define VXGE_HW_FW_UPGRADE_OFFSET_COMMIT	4 /* Commit upgrade */
+#define VXGE_HW_FW_UPGRADE_OFFSET_READ		5 /* Read upgrade version */
+
+#define VXGE_HW_FW_UPGRADE_BLK_SIZE		16 /* Bytes to write */
+#define VXGE_HW_UPGRADE_GET_RET_ERR_CODE(val)	(val & 0xff)
+#define VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(val)	((val >> 8) & 0xff)
+
+#define VXGE_HW_ASIC_MODE_RESERVED				0
+#define VXGE_HW_ASIC_MODE_NO_IOV				1
+#define VXGE_HW_ASIC_MODE_SR_IOV				2
+#define VXGE_HW_ASIC_MODE_MR_IOV				3
+
+#define	VXGE_HW_TXMAC_GEN_CFG1_TMAC_PERMA_STOP_EN		vxge_mBIT(3)
+#define	VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_WIRE		vxge_mBIT(19)
+#define	VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_SWITCH	vxge_mBIT(23)
+#define	VXGE_HW_TXMAC_GEN_CFG1_HOST_APPEND_FCS			vxge_mBIT(31)
+
+#define	VXGE_HW_VPATH_IS_FIRST_GET_VPATH_IS_FIRST(bits)	vxge_bVALn(bits, 3, 1)
+
+#define	VXGE_HW_TIM_VPATH_ASSIGNMENT_GET_BMAP_ROOT(bits) \
+						vxge_bVALn(bits, 0, 32)
+
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN(bits) \
+							vxge_bVALn(bits, 50, 14)
+
+#define	VXGE_HW_XMAC_VSPORT_CHOICES_VP_GET_VSPORT_VECTOR(bits) \
+							vxge_bVALn(bits, 0, 17)
+
+#define	VXGE_HW_XMAC_VPATH_TO_VSPORT_VPMGMT_CLONE_GET_VSPORT_NUMBER(bits) \
+							vxge_bVALn(bits, 3, 5)
+
+#define	VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(bits) \
+							vxge_bVALn(bits, 17, 15)
+
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_LEGACY_MODE			0
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY		1
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_MULTI_OP_MODE		2
+
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MESSAGES_ONLY		0
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MULTI_OP_MODE		1
+
+#define	VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val) \
+				(val&~VXGE_HW_TOC_KDFC_INITIAL_BIR(7))
+#define	VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val) \
+				vxge_bVALn(val, 61, 3)
+#define	VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val) \
+				(val&~VXGE_HW_TOC_USDC_INITIAL_BIR(7))
+#define	VXGE_HW_TOC_GET_USDC_INITIAL_BIR(val) \
+				vxge_bVALn(val, 61, 3)
+
+#define	VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(bits)	bits
+#define	VXGE_HW_TOC_KDFC_FIFO_STRIDE_GET_TOC_KDFC_FIFO_STRIDE(bits)	bits
+
+#define	VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR0(bits) \
+						vxge_bVALn(bits, 1, 15)
+#define	VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR1(bits) \
+						vxge_bVALn(bits, 17, 15)
+#define	VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR2(bits) \
+						vxge_bVALn(bits, 33, 15)
+
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_VAPTH_NUM(val) vxge_vBIT(val, 42, 5)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_NUM(val) vxge_vBIT(val, 47, 2)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_OFFSET(val) \
+					vxge_vBIT(val, 49, 15)
+
+#define VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER			0
+#define VXGE_HW_PRC_CFG4_RING_MODE_THREE_BUFFER			1
+#define VXGE_HW_PRC_CFG4_RING_MODE_FIVE_BUFFER			2
+
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_A				0
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_B				2
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE_C				1
+
+#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_READ                             0
+#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_WRITE                            1
+
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DA                  0
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_VID                 1
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_ETYPE               2
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_PN                  3
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RANGE_PN            4
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG         5
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT         6
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG       7
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK            8
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY             9
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_QOS                 10
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DS                  11
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT        12
+#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_FW_VERSION          13
+
+#define VXGE_HW_RTS_MGR_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
+							vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
+							vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MASK(val) vxge_vBIT(val, 0, 48)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_PRIVILEGED_MODE \
+								vxge_mBIT(54)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_VPATH(bits) \
+							vxge_bVALn(bits, 55, 5)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_VPATH(val) \
+							vxge_vBIT(val, 55, 5)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_MODE(bits) \
+							vxge_bVALn(bits, 62, 2)
+#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MODE(val) vxge_vBIT(val, 62, 2)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY			0
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY		1
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY		2
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY		3
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY			0
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY		1
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY		3
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL		4
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ALL_CLEAR			172
+
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA		0
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID		1
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE		2
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN		3
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG	5
+#define	VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT	6
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG	7
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK		8
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY		9
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS		10
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS		11
+#define	VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT	12
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO		13
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
+							vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_SEND_TO_NW       vxge_mBIT(51)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(bits) vxge_bVALn(bits, 0, 12)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(val) vxge_vBIT(val, 0, 12)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_ETYPE(bits)	vxge_bVALn(bits, 0, 11)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_ETYPE(val) vxge_vBIT(val, 0, 16)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_SRC_DEST_SEL(bits) \
+							vxge_bVALn(bits, 3, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_SRC_DEST_SEL		vxge_mBIT(3)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_TCP_UDP_SEL(bits) \
+							vxge_bVALn(bits, 7, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_TCP_UDP_SEL		vxge_mBIT(7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_PORT_NUM(bits) \
+							vxge_bVALn(bits, 8, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_PORT_NUM(val) vxge_vBIT(val, 8, 16)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_EN(bits) \
+							vxge_bVALn(bits, 3, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN		vxge_mBIT(3)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_BUCKET_SIZE(bits) \
+							vxge_bVALn(bits, 4, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(val) \
+							vxge_vBIT(val, 4, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ALG_SEL(bits) \
+							vxge_bVALn(bits, 10, 2)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(val) \
+							vxge_vBIT(val, 10, 2)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_JENKINS	0
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_MS_RSS	1
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_CRC32C	2
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV4_EN(bits) \
+							vxge_bVALn(bits, 15, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN	vxge_mBIT(15)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV4_EN(bits) \
+							vxge_bVALn(bits, 19, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN	vxge_mBIT(19)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EN(bits) \
+							vxge_bVALn(bits, 23, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN	vxge_mBIT(23)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EN(bits) \
+							vxge_bVALn(bits, 27, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN	vxge_mBIT(27)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EX_EN(bits) \
+							vxge_bVALn(bits, 31, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN vxge_mBIT(31)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EX_EN(bits) \
+							vxge_bVALn(bits, 35, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN	vxge_mBIT(35)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(bits) \
+							vxge_bVALn(bits, 39, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE	vxge_mBIT(39)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_REPL_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 43, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_REPL_ENTRY_EN	vxge_mBIT(43)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 3, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN	vxge_mBIT(3)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(val) \
+							vxge_vBIT(val, 9, 7)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(val) \
+							vxge_vBIT(val, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 8, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN	vxge_mBIT(8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(val) \
+							vxge_vBIT(val, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(val) \
+							vxge_vBIT(val, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 24, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN	vxge_mBIT(24)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 25, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(val) \
+							vxge_vBIT(val, 25, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(val) \
+							vxge_vBIT(val, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 8, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN	vxge_mBIT(8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(val) \
+							vxge_vBIT(val, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(val) \
+							vxge_vBIT(val, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 24, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN	vxge_mBIT(24)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 25, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(val) \
+							vxge_vBIT(val, 25, 7)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_GOLDEN_RATIO(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_GOLDEN_RATIO(val) \
+							vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_INIT_VALUE(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_INIT_VALUE(val) \
+							vxge_vBIT(val, 32, 32)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_SA_MASK(bits) \
+							vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_SA_MASK(val) \
+							vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_DA_MASK(bits) \
+							vxge_bVALn(bits, 16, 16)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_DA_MASK(val) \
+							vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_SA_MASK(bits) \
+							vxge_bVALn(bits, 32, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_SA_MASK(val) \
+							vxge_vBIT(val, 32, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_DA_MASK(bits) \
+							vxge_bVALn(bits, 36, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_DA_MASK(val) \
+							vxge_vBIT(val, 36, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4SP_MASK(bits) \
+							vxge_bVALn(bits, 40, 2)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4SP_MASK(val) \
+							vxge_vBIT(val, 40, 2)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4DP_MASK(bits) \
+							vxge_bVALn(bits, 42, 2)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4DP_MASK(val) \
+							vxge_vBIT(val, 42, 2)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_KEY_KEY(bits) \
+							vxge_bVALn(bits, 0, 64)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_KEY_KEY vxge_vBIT(val, 0, 64)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_QOS_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 3, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_QOS_ENTRY_EN		vxge_mBIT(3)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DS_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 3, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_DS_ENTRY_EN		vxge_mBIT(3)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
+							vxge_bVALn(bits, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(val) \
+							vxge_vBIT(val, 0, 48)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(val) \
+							vxge_vBIT(val, 62, 2)
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_NUM(val) \
+							vxge_vBIT(val, 0, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 8, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_ENTRY_EN	vxge_mBIT(8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_DATA(val) \
+							vxge_vBIT(val, 9, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_NUM(val) \
+							vxge_vBIT(val, 16, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 24, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_ENTRY_EN	vxge_mBIT(24)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 25, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_DATA(val) \
+							vxge_vBIT(val, 25, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 32, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_NUM(val) \
+							vxge_vBIT(val, 32, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 40, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_ENTRY_EN	vxge_mBIT(40)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 41, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_DATA(val) \
+							vxge_vBIT(val, 41, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_NUM(bits) \
+							vxge_bVALn(bits, 48, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_NUM(val) \
+							vxge_vBIT(val, 48, 8)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_ENTRY_EN(bits) \
+							vxge_bVALn(bits, 56, 1)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_ENTRY_EN	vxge_mBIT(56)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_DATA(bits) \
+							vxge_bVALn(bits, 57, 7)
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_DATA(val) \
+							vxge_vBIT(val, 57, 7)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER           0
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER         1
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_VERSION               2
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE              3
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0                4
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_1                5
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_2                6
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3                7
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORTS			8
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT0_PMD_TYPE		10
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT0_PMD_VENDOR	11
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT0_PMD_PARTNO	13
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT0_PMD_SERNO	14
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT1_PMD_TYPE		20
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT1_PMD_VENDOR	21
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT1_PMD_PARTNO	23
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PORT1_PMD_SERNO	24
+
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_ON			1
+#define	VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_OFF			0
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_DAY(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(bits) \
+							vxge_bVALn(bits, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MONTH(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(bits) \
+						vxge_bVALn(bits, 16, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_YEAR(val) \
+							vxge_vBIT(val, 16, 16)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(bits) \
+						vxge_bVALn(bits, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MAJOR vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(bits) \
+						vxge_bVALn(bits, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MINOR vxge_vBIT(val, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(bits) \
+						vxge_bVALn(bits, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(bits) \
+						vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_BUILD vxge_vBIT(val, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(bits) \
+						vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_DAY(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(bits) \
+							vxge_bVALn(bits, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MONTH(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(bits) \
+							vxge_bVALn(bits, 16, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_YEAR(val) \
+							vxge_vBIT(val, 16, 16)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(bits) \
+							vxge_bVALn(bits, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MAJOR vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(bits) \
+							vxge_bVALn(bits, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MINOR vxge_vBIT(val, 40, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \
+							vxge_bVALn(bits, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16)
+
+/* Netork port control API related */
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_SET_NWIF_CMD(val) \
+						vxge_vBIT(val, 0, 8)
+
+/* Bandwidth & priority related MACROS */
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_API_VER(bits) \
+						vxge_bVALn(bits, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_TX_PRIORITY(bits) \
+							vxge_bVALn(bits, 21, 3)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_TX_MIN_BW(bits) \
+							vxge_bVALn(bits, 24, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_TX_MAX_BW(bits) \
+							vxge_bVALn(bits, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RX_PRIORITY(bits) \
+							vxge_bVALn(bits, 45, 3)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RX_MIN_BW(bits) \
+							vxge_bVALn(bits, 48, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RX_MAX_BW(bits) \
+							vxge_bVALn(bits, 56, 8)
+
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_VPATH_OR_FUNC(val) \
+							vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_TX_PRIORITY(val) \
+							vxge_vBIT(val, 21, 3)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_TX_MIN_BW(val) \
+							vxge_vBIT(val, 24, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_TX_MAX_BW(val) \
+							vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_RX_PRIORITY(val) \
+							vxge_vBIT(val, 45, 3)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_RX_MIN_BW(val) \
+							vxge_vBIT(val, 48, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_SET_RX_MAX_BW(val) \
+							vxge_vBIT(val, 56, 8)
+
+#define	VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\
+							vxge_bVALn(bits, 0, 18)
+
+#define	VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(bits) \
+							vxge_bVALn(bits, 48, 16)
+#define	VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(bits)	vxge_bVALn(bits, 48, 16)
+#define	VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(bits)	(bits)
+#define	VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(bits)	(bits)
+#define	VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(bits\
+) vxge_bVALn(bits, 48, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(bits) vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(bits) \
+							vxge_bVALn(bits, 16, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(bits) \
+							vxge_bVALn(bits, 32, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(bits)	vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(bits) \
+							vxge_bVALn(bits, 16, 16)
+#define	VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(bits) \
+							vxge_bVALn(bits, 32, 16)
+
+#define	VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_WR_DROP(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_RD_DROP(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS1_GET_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(bits\
+) vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS2_GET_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(bits\
+) vxge_bVALn(bits, 32, 32)
+#define \
+VXGE_HW_MRPCIM_DEBUG_STATS3_GET_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(bits) \
+	vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_WR_VPIN_DROP(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_RD_VPIN_DROP(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT1(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT0(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT3(bits) \
+							vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT2(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_GENSTATS_COUNT4_GET_GENSTATS_COUNT4(bits) \
+							vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_GENSTATS_COUNT5_GET_GENSTATS_COUNT5(bits) \
+							vxge_bVALn(bits, 32, 32)
+
+#define	VXGE_HW_DEBUG_STATS0_GET_RSTDROP_MSG(bits)	vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_DEBUG_STATS0_GET_RSTDROP_CPL(bits)	vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT0(bits)	vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT1(bits)	vxge_bVALn(bits, 32, 32)
+#define	VXGE_HW_DEBUG_STATS2_GET_RSTDROP_CLIENT2(bits)	vxge_bVALn(bits, 0, 32)
+#define	VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_PH(bits)	vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_NPH(bits)	vxge_bVALn(bits, 16, 16)
+#define	VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_CPLH(bits)	vxge_bVALn(bits, 32, 16)
+#define	VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_PD(bits)	vxge_bVALn(bits, 0, 16)
+#define	VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_NPD(bits)	vxge_bVALn(bits, 16, 16)
+#define	VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_CPLD(bits)	vxge_bVALn(bits, 32, 16)
+
+#define	VXGE_HW_DBG_STATS_TPA_TX_PATH_GET_TX_PERMITTED_FRMS(bits) \
+							vxge_bVALn(bits, 32, 32)
+
+#define	VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT0_TX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define	VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT1_TX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 8, 8)
+#define	VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT2_TX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 16, 8)
+
+#define	VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT0_RX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 0, 8)
+#define	VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT1_RX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 8, 8)
+#define	VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT2_RX_ANY_FRMS(bits) \
+							vxge_bVALn(bits, 16, 8)
+
+#define VXGE_HW_CONFIG_PRIV_H
+
+#define VXGE_HW_SWAPPER_INITIAL_VALUE			0x0123456789abcdefULL
+#define VXGE_HW_SWAPPER_BYTE_SWAPPED			0xefcdab8967452301ULL
+#define VXGE_HW_SWAPPER_BIT_FLIPPED			0x80c4a2e691d5b3f7ULL
+#define VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED	0xf7b3d591e6a2c480ULL
+
+#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE		0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_DISABLE		0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE		0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_READ_BIT_FLAP_DISABLE		0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE		0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_DISABLE		0x0000000000000000ULL
+
+#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE		0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_DISABLE		0x0000000000000000ULL
+
+/*
+ * The registers are memory mapped and are native big-endian byte order. The
+ * little-endian hosts are handled by enabling hardware byte-swapping for
+ * register and dma operations.
+ */
+struct vxge_hw_legacy_reg {
+
+	u8	unused00010[0x00010];
+
+/*0x00010*/	u64	toc_swapper_fb;
+#define VXGE_HW_TOC_SWAPPER_FB_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00018*/	u64	pifm_rd_swap_en;
+#define VXGE_HW_PIFM_RD_SWAP_EN_PIFM_RD_SWAP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00020*/	u64	pifm_rd_flip_en;
+#define VXGE_HW_PIFM_RD_FLIP_EN_PIFM_RD_FLIP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00028*/	u64	pifm_wr_swap_en;
+#define VXGE_HW_PIFM_WR_SWAP_EN_PIFM_WR_SWAP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00030*/	u64	pifm_wr_flip_en;
+#define VXGE_HW_PIFM_WR_FLIP_EN_PIFM_WR_FLIP_EN(val) vxge_vBIT(val, 0, 64)
+/*0x00038*/	u64	toc_first_pointer;
+#define VXGE_HW_TOC_FIRST_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00040*/	u64	host_access_en;
+#define VXGE_HW_HOST_ACCESS_EN_HOST_ACCESS_EN(val) vxge_vBIT(val, 0, 64)
+
+} __attribute((packed));
+
+struct vxge_hw_toc_reg {
+
+	u8	unused00050[0x00050];
+
+/*0x00050*/	u64	toc_common_pointer;
+#define VXGE_HW_TOC_COMMON_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00058*/	u64	toc_memrepair_pointer;
+#define VXGE_HW_TOC_MEMREPAIR_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x00060*/	u64	toc_pcicfgmgmt_pointer[17];
+#define VXGE_HW_TOC_PCICFGMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+	u8	unused001e0[0x001e0-0x000e8];
+
+/*0x001e0*/	u64	toc_mrpcim_pointer;
+#define VXGE_HW_TOC_MRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+/*0x001e8*/	u64	toc_srpcim_pointer[17];
+#define VXGE_HW_TOC_SRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+	u8	unused00278[0x00278-0x00270];
+
+/*0x00278*/	u64	toc_vpmgmt_pointer[17];
+#define VXGE_HW_TOC_VPMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+	u8	unused00390[0x00390-0x00300];
+
+/*0x00390*/	u64	toc_vpath_pointer[17];
+#define VXGE_HW_TOC_VPATH_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
+	u8	unused004a0[0x004a0-0x00418];
+
+/*0x004a0*/	u64	toc_kdfc;
+#define VXGE_HW_TOC_KDFC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
+#define VXGE_HW_TOC_KDFC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
+/*0x004a8*/	u64	toc_usdc;
+#define VXGE_HW_TOC_USDC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
+#define VXGE_HW_TOC_USDC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
+/*0x004b0*/	u64	toc_kdfc_vpath_stride;
+#define	VXGE_HW_TOC_KDFC_VPATH_STRIDE_INITIAL_TOC_KDFC_VPATH_STRIDE(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x004b8*/	u64	toc_kdfc_fifo_stride;
+#define	VXGE_HW_TOC_KDFC_FIFO_STRIDE_INITIAL_TOC_KDFC_FIFO_STRIDE(val) \
+							vxge_vBIT(val, 0, 64)
+
+} __attribute((packed));
+
+struct vxge_hw_common_reg {
+
+	u8	unused00a00[0x00a00];
+
+/*0x00a00*/	u64	prc_status1;
+#define VXGE_HW_PRC_STATUS1_PRC_VP_QUIESCENT(n)	vxge_mBIT(n)
+/*0x00a08*/	u64	rxdcm_reset_in_progress;
+#define VXGE_HW_RXDCM_RESET_IN_PROGRESS_PRC_VP(n)	vxge_mBIT(n)
+/*0x00a10*/	u64	replicq_flush_in_progress;
+#define VXGE_HW_REPLICQ_FLUSH_IN_PROGRESS_NOA_VP(n)	vxge_mBIT(n)
+/*0x00a18*/	u64	rxpe_cmds_reset_in_progress;
+#define VXGE_HW_RXPE_CMDS_RESET_IN_PROGRESS_NOA_VP(n)	vxge_mBIT(n)
+/*0x00a20*/	u64	mxp_cmds_reset_in_progress;
+#define VXGE_HW_MXP_CMDS_RESET_IN_PROGRESS_NOA_VP(n)	vxge_mBIT(n)
+/*0x00a28*/	u64	noffload_reset_in_progress;
+#define VXGE_HW_NOFFLOAD_RESET_IN_PROGRESS_PRC_VP(n)	vxge_mBIT(n)
+/*0x00a30*/	u64	rd_req_in_progress;
+#define VXGE_HW_RD_REQ_IN_PROGRESS_VP(n)	vxge_mBIT(n)
+/*0x00a38*/	u64	rd_req_outstanding;
+#define VXGE_HW_RD_REQ_OUTSTANDING_VP(n)	vxge_mBIT(n)
+/*0x00a40*/	u64	kdfc_reset_in_progress;
+#define VXGE_HW_KDFC_RESET_IN_PROGRESS_NOA_VP(n)	vxge_mBIT(n)
+	u8	unused00b00[0x00b00-0x00a48];
+
+/*0x00b00*/	u64	one_cfg_vp;
+#define VXGE_HW_ONE_CFG_VP_RDY(n)	vxge_mBIT(n)
+/*0x00b08*/	u64	one_common;
+#define VXGE_HW_ONE_COMMON_PET_VPATH_RESET_IN_PROGRESS(n)	vxge_mBIT(n)
+	u8	unused00b80[0x00b80-0x00b10];
+
+/*0x00b80*/	u64	tim_int_en;
+#define VXGE_HW_TIM_INT_EN_TIM_VP(n)	vxge_mBIT(n)
+/*0x00b88*/	u64	tim_set_int_en;
+#define VXGE_HW_TIM_SET_INT_EN_VP(n)	vxge_mBIT(n)
+/*0x00b90*/	u64	tim_clr_int_en;
+#define VXGE_HW_TIM_CLR_INT_EN_VP(n)	vxge_mBIT(n)
+/*0x00b98*/	u64	tim_mask_int_during_reset;
+#define VXGE_HW_TIM_MASK_INT_DURING_RESET_VPATH(n)	vxge_mBIT(n)
+/*0x00ba0*/	u64	tim_reset_in_progress;
+#define VXGE_HW_TIM_RESET_IN_PROGRESS_TIM_VPATH(n)	vxge_mBIT(n)
+/*0x00ba8*/	u64	tim_outstanding_bmap;
+#define VXGE_HW_TIM_OUTSTANDING_BMAP_TIM_VPATH(n)	vxge_mBIT(n)
+	u8	unused00c00[0x00c00-0x00bb0];
+
+/*0x00c00*/	u64	msg_reset_in_progress;
+#define VXGE_HW_MSG_RESET_IN_PROGRESS_MSG_COMPOSITE(val) vxge_vBIT(val, 0, 17)
+/*0x00c08*/	u64	msg_mxp_mr_ready;
+#define VXGE_HW_MSG_MXP_MR_READY_MP_BOOTED(n)	vxge_mBIT(n)
+/*0x00c10*/	u64	msg_uxp_mr_ready;
+#define VXGE_HW_MSG_UXP_MR_READY_UP_BOOTED(n)	vxge_mBIT(n)
+/*0x00c18*/	u64	msg_dmq_noni_rtl_prefetch;
+#define VXGE_HW_MSG_DMQ_NONI_RTL_PREFETCH_BYPASS_ENABLE(n)	vxge_mBIT(n)
+/*0x00c20*/	u64	msg_umq_rtl_bwr;
+#define VXGE_HW_MSG_UMQ_RTL_BWR_PREFETCH_DISABLE(n)	vxge_mBIT(n)
+	u8	unused00d00[0x00d00-0x00c28];
+
+/*0x00d00*/	u64	cmn_rsthdlr_cfg0;
+#define VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(val) vxge_vBIT(val, 0, 17)
+/*0x00d08*/	u64	cmn_rsthdlr_cfg1;
+#define VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(val) vxge_vBIT(val, 0, 17)
+/*0x00d10*/	u64	cmn_rsthdlr_cfg2;
+#define VXGE_HW_CMN_RSTHDLR_CFG2_SW_RESET_FIFO0(val) vxge_vBIT(val, 0, 17)
+/*0x00d18*/	u64	cmn_rsthdlr_cfg3;
+#define VXGE_HW_CMN_RSTHDLR_CFG3_SW_RESET_FIFO1(val) vxge_vBIT(val, 0, 17)
+/*0x00d20*/	u64	cmn_rsthdlr_cfg4;
+#define VXGE_HW_CMN_RSTHDLR_CFG4_SW_RESET_FIFO2(val) vxge_vBIT(val, 0, 17)
+	u8	unused00d40[0x00d40-0x00d28];
+
+/*0x00d40*/	u64	cmn_rsthdlr_cfg8;
+#define VXGE_HW_CMN_RSTHDLR_CFG8_INCR_VPATH_INST_NUM(val) vxge_vBIT(val, 0, 17)
+/*0x00d48*/	u64	stats_cfg0;
+#define VXGE_HW_STATS_CFG0_STATS_ENABLE(val) vxge_vBIT(val, 0, 17)
+	u8	unused00da8[0x00da8-0x00d50];
+
+/*0x00da8*/	u64	clear_msix_mask_vect[4];
+#define VXGE_HW_CLEAR_MSIX_MASK_VECT_CLEAR_MSIX_MASK_VECT(val) \
+						vxge_vBIT(val, 0, 17)
+/*0x00dc8*/	u64	set_msix_mask_vect[4];
+#define VXGE_HW_SET_MSIX_MASK_VECT_SET_MSIX_MASK_VECT(val) vxge_vBIT(val, 0, 17)
+/*0x00de8*/	u64	clear_msix_mask_all_vect;
+#define	VXGE_HW_CLEAR_MSIX_MASK_ALL_VECT_CLEAR_MSIX_MASK_ALL_VECT(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x00df0*/	u64	set_msix_mask_all_vect;
+#define	VXGE_HW_SET_MSIX_MASK_ALL_VECT_SET_MSIX_MASK_ALL_VECT(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x00df8*/	u64	mask_vector[4];
+#define VXGE_HW_MASK_VECTOR_MASK_VECTOR(val) vxge_vBIT(val, 0, 17)
+/*0x00e18*/	u64	msix_pending_vector[4];
+#define VXGE_HW_MSIX_PENDING_VECTOR_MSIX_PENDING_VECTOR(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x00e38*/	u64	clr_msix_one_shot_vec[4];
+#define	VXGE_HW_CLR_MSIX_ONE_SHOT_VEC_CLR_MSIX_ONE_SHOT_VEC(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x00e58*/	u64	titan_asic_id;
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_DEVICE_ID(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MAJOR_REVISION(val) vxge_vBIT(val, 48, 8)
+#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MINOR_REVISION(val) vxge_vBIT(val, 56, 8)
+/*0x00e60*/	u64	titan_general_int_status;
+#define	VXGE_HW_TITAN_GENERAL_INT_STATUS_MRPCIM_ALARM_INT	vxge_mBIT(0)
+#define	VXGE_HW_TITAN_GENERAL_INT_STATUS_SRPCIM_ALARM_INT	vxge_mBIT(1)
+#define	VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT	vxge_mBIT(2)
+#define	VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(val) \
+							vxge_vBIT(val, 3, 17)
+	u8	unused00e70[0x00e70-0x00e68];
+
+/*0x00e70*/	u64	titan_mask_all_int;
+#define	VXGE_HW_TITAN_MASK_ALL_INT_ALARM	vxge_mBIT(7)
+#define	VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC	vxge_mBIT(15)
+	u8	unused00e80[0x00e80-0x00e78];
+
+/*0x00e80*/	u64	tim_int_status0;
+#define VXGE_HW_TIM_INT_STATUS0_TIM_INT_STATUS0(val) vxge_vBIT(val, 0, 64)
+/*0x00e88*/	u64	tim_int_mask0;
+#define VXGE_HW_TIM_INT_MASK0_TIM_INT_MASK0(val) vxge_vBIT(val, 0, 64)
+/*0x00e90*/	u64	tim_int_status1;
+#define VXGE_HW_TIM_INT_STATUS1_TIM_INT_STATUS1(val) vxge_vBIT(val, 0, 4)
+/*0x00e98*/	u64	tim_int_mask1;
+#define VXGE_HW_TIM_INT_MASK1_TIM_INT_MASK1(val) vxge_vBIT(val, 0, 4)
+/*0x00ea0*/	u64	rti_int_status;
+#define VXGE_HW_RTI_INT_STATUS_RTI_INT_STATUS(val) vxge_vBIT(val, 0, 17)
+/*0x00ea8*/	u64	rti_int_mask;
+#define VXGE_HW_RTI_INT_MASK_RTI_INT_MASK(val) vxge_vBIT(val, 0, 17)
+/*0x00eb0*/	u64	adapter_status;
+#define	VXGE_HW_ADAPTER_STATUS_RTDMA_RTDMA_READY	vxge_mBIT(0)
+#define	VXGE_HW_ADAPTER_STATUS_WRDMA_WRDMA_READY	vxge_mBIT(1)
+#define	VXGE_HW_ADAPTER_STATUS_KDFC_KDFC_READY	vxge_mBIT(2)
+#define	VXGE_HW_ADAPTER_STATUS_TPA_TMAC_BUF_EMPTY	vxge_mBIT(3)
+#define	VXGE_HW_ADAPTER_STATUS_RDCTL_PIC_QUIESCENT	vxge_mBIT(4)
+#define	VXGE_HW_ADAPTER_STATUS_XGMAC_NETWORK_FAULT	vxge_mBIT(5)
+#define	VXGE_HW_ADAPTER_STATUS_ROCRC_OFFLOAD_QUIESCENT	vxge_mBIT(6)
+#define	VXGE_HW_ADAPTER_STATUS_G3IF_FB_G3IF_FB_GDDR3_READY	vxge_mBIT(7)
+#define	VXGE_HW_ADAPTER_STATUS_G3IF_CM_G3IF_CM_GDDR3_READY	vxge_mBIT(8)
+#define	VXGE_HW_ADAPTER_STATUS_RIC_RIC_RUNNING	vxge_mBIT(9)
+#define	VXGE_HW_ADAPTER_STATUS_CMG_C_PLL_IN_LOCK	vxge_mBIT(10)
+#define	VXGE_HW_ADAPTER_STATUS_XGMAC_X_PLL_IN_LOCK	vxge_mBIT(11)
+#define	VXGE_HW_ADAPTER_STATUS_FBIF_M_PLL_IN_LOCK	vxge_mBIT(12)
+#define VXGE_HW_ADAPTER_STATUS_PCC_PCC_IDLE(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_ADAPTER_STATUS_ROCRC_RC_PRC_QUIESCENT(val) vxge_vBIT(val, 44, 8)
+/*0x00eb8*/	u64	gen_ctrl;
+#define	VXGE_HW_GEN_CTRL_SPI_MRPCIM_WR_DIS	vxge_mBIT(0)
+#define	VXGE_HW_GEN_CTRL_SPI_MRPCIM_RD_DIS	vxge_mBIT(1)
+#define	VXGE_HW_GEN_CTRL_SPI_SRPCIM_WR_DIS	vxge_mBIT(2)
+#define	VXGE_HW_GEN_CTRL_SPI_SRPCIM_RD_DIS	vxge_mBIT(3)
+#define	VXGE_HW_GEN_CTRL_SPI_DEBUG_DIS	vxge_mBIT(4)
+#define	VXGE_HW_GEN_CTRL_SPI_APP_LTSSM_TIMER_DIS	vxge_mBIT(5)
+#define VXGE_HW_GEN_CTRL_SPI_NOT_USED(val) vxge_vBIT(val, 6, 4)
+	u8	unused00ed0[0x00ed0-0x00ec0];
+
+/*0x00ed0*/	u64	adapter_ready;
+#define	VXGE_HW_ADAPTER_READY_ADAPTER_READY	vxge_mBIT(63)
+/*0x00ed8*/	u64	outstanding_read;
+#define VXGE_HW_OUTSTANDING_READ_OUTSTANDING_READ(val) vxge_vBIT(val, 0, 17)
+/*0x00ee0*/	u64	vpath_rst_in_prog;
+#define VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(val) vxge_vBIT(val, 0, 17)
+/*0x00ee8*/	u64	vpath_reg_modified;
+#define VXGE_HW_VPATH_REG_MODIFIED_VPATH_REG_MODIFIED(val) vxge_vBIT(val, 0, 17)
+	u8	unused00fc0[0x00fc0-0x00ef0];
+
+/*0x00fc0*/	u64	cp_reset_in_progress;
+#define VXGE_HW_CP_RESET_IN_PROGRESS_CP_VPATH(n)	vxge_mBIT(n)
+	u8	unused01080[0x01080-0x00fc8];
+
+/*0x01080*/	u64	xgmac_ready;
+#define VXGE_HW_XGMAC_READY_XMACJ_READY(val) vxge_vBIT(val, 0, 17)
+	u8	unused010c0[0x010c0-0x01088];
+
+/*0x010c0*/	u64	fbif_ready;
+#define VXGE_HW_FBIF_READY_FAU_READY(val) vxge_vBIT(val, 0, 17)
+	u8	unused01100[0x01100-0x010c8];
+
+/*0x01100*/	u64	vplane_assignments;
+#define VXGE_HW_VPLANE_ASSIGNMENTS_VPLANE_ASSIGNMENTS(val) vxge_vBIT(val, 3, 5)
+/*0x01108*/	u64	vpath_assignments;
+#define VXGE_HW_VPATH_ASSIGNMENTS_VPATH_ASSIGNMENTS(val) vxge_vBIT(val, 0, 17)
+/*0x01110*/	u64	resource_assignments;
+#define VXGE_HW_RESOURCE_ASSIGNMENTS_RESOURCE_ASSIGNMENTS(val) \
+						vxge_vBIT(val, 0, 17)
+/*0x01118*/	u64	host_type_assignments;
+#define	VXGE_HW_HOST_TYPE_ASSIGNMENTS_HOST_TYPE_ASSIGNMENTS(val) \
+							vxge_vBIT(val, 5, 3)
+	u8	unused01128[0x01128-0x01120];
+
+/*0x01128*/	u64	max_resource_assignments;
+#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPLANE(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPATHS(val) \
+						vxge_vBIT(val, 11, 5)
+/*0x01130*/	u64	pf_vpath_assignments;
+#define VXGE_HW_PF_VPATH_ASSIGNMENTS_PF_VPATH_ASSIGNMENTS(val) \
+						vxge_vBIT(val, 0, 17)
+	u8	unused01200[0x01200-0x01138];
+
+/*0x01200*/	u64	rts_access_icmp;
+#define VXGE_HW_RTS_ACCESS_ICMP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01208*/	u64	rts_access_tcpsyn;
+#define VXGE_HW_RTS_ACCESS_TCPSYN_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01210*/	u64	rts_access_zl4pyld;
+#define VXGE_HW_RTS_ACCESS_ZL4PYLD_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01218*/	u64	rts_access_l4prtcl_tcp;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_TCP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01220*/	u64	rts_access_l4prtcl_udp;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_UDP_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01228*/	u64	rts_access_l4prtcl_flex;
+#define VXGE_HW_RTS_ACCESS_L4PRTCL_FLEX_EN(val) vxge_vBIT(val, 0, 17)
+/*0x01230*/	u64	rts_access_ipfrag;
+#define VXGE_HW_RTS_ACCESS_IPFRAG_EN(val) vxge_vBIT(val, 0, 17)
+
+} __attribute((packed));
+
+struct vxge_hw_memrepair_reg {
+	u64	unused1;
+	u64	unused2;
+} __attribute((packed));
+
+struct vxge_hw_pcicfgmgmt_reg {
+
+/*0x00000*/	u64	resource_no;
+#define	VXGE_HW_RESOURCE_NO_PFN_OR_VF	BIT(3)
+/*0x00008*/	u64	bargrp_pf_or_vf_bar0_mask;
+#define	VXGE_HW_BARGRP_PF_OR_VF_BAR0_MASK_BARGRP_PF_OR_VF_BAR0_MASK(val) \
+							vxge_vBIT(val, 2, 6)
+/*0x00010*/	u64	bargrp_pf_or_vf_bar1_mask;
+#define	VXGE_HW_BARGRP_PF_OR_VF_BAR1_MASK_BARGRP_PF_OR_VF_BAR1_MASK(val) \
+							vxge_vBIT(val, 2, 6)
+/*0x00018*/	u64	bargrp_pf_or_vf_bar2_mask;
+#define	VXGE_HW_BARGRP_PF_OR_VF_BAR2_MASK_BARGRP_PF_OR_VF_BAR2_MASK(val) \
+							vxge_vBIT(val, 2, 6)
+/*0x00020*/	u64	msixgrp_no;
+#define VXGE_HW_MSIXGRP_NO_TABLE_SIZE(val) vxge_vBIT(val, 5, 11)
+
+} __attribute((packed));
+
+struct vxge_hw_mrpcim_reg {
+/*0x00000*/	u64	g3fbct_int_status;
+#define	VXGE_HW_G3FBCT_INT_STATUS_ERR_G3IF_INT	vxge_mBIT(0)
+/*0x00008*/	u64	g3fbct_int_mask;
+/*0x00010*/	u64	g3fbct_err_reg;
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_SM_ERR	vxge_mBIT(4)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_DECC	vxge_mBIT(5)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_DECC	vxge_mBIT(6)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_DECC	vxge_mBIT(7)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_SECC	vxge_mBIT(29)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_SECC	vxge_mBIT(30)
+#define	VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_SECC	vxge_mBIT(31)
+/*0x00018*/	u64	g3fbct_err_mask;
+/*0x00020*/	u64	g3fbct_err_alarm;
+
+	u8	unused00a00[0x00a00-0x00028];
+
+/*0x00a00*/	u64	wrdma_int_status;
+#define	VXGE_HW_WRDMA_INT_STATUS_RC_ALARM_RC_INT	vxge_mBIT(0)
+#define	VXGE_HW_WRDMA_INT_STATUS_RXDRM_SM_ERR_RXDRM_INT	vxge_mBIT(1)
+#define	VXGE_HW_WRDMA_INT_STATUS_RXDCM_SM_ERR_RXDCM_SM_INT	vxge_mBIT(2)
+#define	VXGE_HW_WRDMA_INT_STATUS_RXDWM_SM_ERR_RXDWM_INT	vxge_mBIT(3)
+#define	VXGE_HW_WRDMA_INT_STATUS_RDA_ERR_RDA_INT	vxge_mBIT(6)
+#define	VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_DB_RDA_ECC_DB_INT	vxge_mBIT(8)
+#define	VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_SG_RDA_ECC_SG_INT	vxge_mBIT(9)
+#define	VXGE_HW_WRDMA_INT_STATUS_FRF_ALARM_FRF_INT	vxge_mBIT(12)
+#define	VXGE_HW_WRDMA_INT_STATUS_ROCRC_ALARM_ROCRC_INT	vxge_mBIT(13)
+#define	VXGE_HW_WRDMA_INT_STATUS_WDE0_ALARM_WDE0_INT	vxge_mBIT(14)
+#define	VXGE_HW_WRDMA_INT_STATUS_WDE1_ALARM_WDE1_INT	vxge_mBIT(15)
+#define	VXGE_HW_WRDMA_INT_STATUS_WDE2_ALARM_WDE2_INT	vxge_mBIT(16)
+#define	VXGE_HW_WRDMA_INT_STATUS_WDE3_ALARM_WDE3_INT	vxge_mBIT(17)
+/*0x00a08*/	u64	wrdma_int_mask;
+/*0x00a10*/	u64	rc_alarm_reg;
+#define	VXGE_HW_RC_ALARM_REG_FTC_SM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_RC_ALARM_REG_FTC_SM_PHASE_ERR	vxge_mBIT(1)
+#define	VXGE_HW_RC_ALARM_REG_BTDWM_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_RC_ALARM_REG_BTC_SM_ERR	vxge_mBIT(3)
+#define	VXGE_HW_RC_ALARM_REG_BTDCM_SM_ERR	vxge_mBIT(4)
+#define	VXGE_HW_RC_ALARM_REG_BTDRM_SM_ERR	vxge_mBIT(5)
+#define	VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_DB_ERR	vxge_mBIT(6)
+#define	VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_SG_ERR	vxge_mBIT(7)
+#define	VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_DB_ERR	vxge_mBIT(8)
+#define	VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_SG_ERR	vxge_mBIT(9)
+#define	VXGE_HW_RC_ALARM_REG_RMM_SM_ERR	vxge_mBIT(10)
+#define	VXGE_HW_RC_ALARM_REG_BTC_VPATH_MISMATCH_ERR	vxge_mBIT(12)
+/*0x00a18*/	u64	rc_alarm_mask;
+/*0x00a20*/	u64	rc_alarm_alarm;
+/*0x00a28*/	u64	rxdrm_sm_err_reg;
+#define VXGE_HW_RXDRM_SM_ERR_REG_PRC_VP(n)	vxge_mBIT(n)
+/*0x00a30*/	u64	rxdrm_sm_err_mask;
+/*0x00a38*/	u64	rxdrm_sm_err_alarm;
+/*0x00a40*/	u64	rxdcm_sm_err_reg;
+#define VXGE_HW_RXDCM_SM_ERR_REG_PRC_VP(n)	vxge_mBIT(n)
+/*0x00a48*/	u64	rxdcm_sm_err_mask;
+/*0x00a50*/	u64	rxdcm_sm_err_alarm;
+/*0x00a58*/	u64	rxdwm_sm_err_reg;
+#define VXGE_HW_RXDWM_SM_ERR_REG_PRC_VP(n)	vxge_mBIT(n)
+/*0x00a60*/	u64	rxdwm_sm_err_mask;
+/*0x00a68*/	u64	rxdwm_sm_err_alarm;
+/*0x00a70*/	u64	rda_err_reg;
+#define	VXGE_HW_RDA_ERR_REG_RDA_SM0_ERR_ALARM	vxge_mBIT(0)
+#define	VXGE_HW_RDA_ERR_REG_RDA_MISC_ERR	vxge_mBIT(1)
+#define	VXGE_HW_RDA_ERR_REG_RDA_PCIX_ERR	vxge_mBIT(2)
+#define	VXGE_HW_RDA_ERR_REG_RDA_RXD_ECC_DB_ERR	vxge_mBIT(3)
+#define	VXGE_HW_RDA_ERR_REG_RDA_FRM_ECC_DB_ERR	vxge_mBIT(4)
+#define	VXGE_HW_RDA_ERR_REG_RDA_UQM_ECC_DB_ERR	vxge_mBIT(5)
+#define	VXGE_HW_RDA_ERR_REG_RDA_IMM_ECC_DB_ERR	vxge_mBIT(6)
+#define	VXGE_HW_RDA_ERR_REG_RDA_TIM_ECC_DB_ERR	vxge_mBIT(7)
+/*0x00a78*/	u64	rda_err_mask;
+/*0x00a80*/	u64	rda_err_alarm;
+/*0x00a88*/	u64	rda_ecc_db_reg;
+#define VXGE_HW_RDA_ECC_DB_REG_RDA_RXD_ERR(n)	vxge_mBIT(n)
+/*0x00a90*/	u64	rda_ecc_db_mask;
+/*0x00a98*/	u64	rda_ecc_db_alarm;
+/*0x00aa0*/	u64	rda_ecc_sg_reg;
+#define VXGE_HW_RDA_ECC_SG_REG_RDA_RXD_ERR(n)	vxge_mBIT(n)
+/*0x00aa8*/	u64	rda_ecc_sg_mask;
+/*0x00ab0*/	u64	rda_ecc_sg_alarm;
+/*0x00ab8*/	u64	rqa_err_reg;
+#define	VXGE_HW_RQA_ERR_REG_RQA_SM_ERR_ALARM	vxge_mBIT(0)
+/*0x00ac0*/	u64	rqa_err_mask;
+/*0x00ac8*/	u64	rqa_err_alarm;
+/*0x00ad0*/	u64	frf_alarm_reg;
+#define VXGE_HW_FRF_ALARM_REG_PRC_VP_FRF_SM_ERR(n)	vxge_mBIT(n)
+/*0x00ad8*/	u64	frf_alarm_mask;
+/*0x00ae0*/	u64	frf_alarm_alarm;
+/*0x00ae8*/	u64	rocrc_alarm_reg;
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_DB	vxge_mBIT(0)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_SG	vxge_mBIT(1)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_NMA_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_DB	vxge_mBIT(3)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_SG	vxge_mBIT(4)
+#define	VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_DB	vxge_mBIT(5)
+#define	VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_SG	vxge_mBIT(6)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_DB	vxge_mBIT(11)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_SG	vxge_mBIT(12)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_RSVD_ERR	vxge_mBIT(13)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_OWN_ERR	vxge_mBIT(14)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_BYP_OWN_ERR	vxge_mBIT(15)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_NOT_ASSIGNED_ERR	vxge_mBIT(16)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_RSVD_SYNC_ERR	vxge_mBIT(17)
+#define	VXGE_HW_ROCRC_ALARM_REG_QCQ_LOST_EGB_ERR	vxge_mBIT(18)
+#define	VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ0_OVERFLOW	vxge_mBIT(19)
+#define	VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ1_OVERFLOW	vxge_mBIT(20)
+#define	VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ2_OVERFLOW	vxge_mBIT(21)
+#define	VXGE_HW_ROCRC_ALARM_REG_NOA_WCT_CMD_FIFO_ERR	vxge_mBIT(22)
+/*0x00af0*/	u64	rocrc_alarm_mask;
+/*0x00af8*/	u64	rocrc_alarm_alarm;
+/*0x00b00*/	u64	wde0_alarm_reg;
+#define	VXGE_HW_WDE0_ALARM_REG_WDE0_DCC_SM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_WDE0_ALARM_REG_WDE0_PRM_SM_ERR	vxge_mBIT(1)
+#define	VXGE_HW_WDE0_ALARM_REG_WDE0_CP_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_WDE0_ALARM_REG_WDE0_CP_CMD_ERR	vxge_mBIT(3)
+#define	VXGE_HW_WDE0_ALARM_REG_WDE0_PCR_SM_ERR	vxge_mBIT(4)
+/*0x00b08*/	u64	wde0_alarm_mask;
+/*0x00b10*/	u64	wde0_alarm_alarm;
+/*0x00b18*/	u64	wde1_alarm_reg;
+#define	VXGE_HW_WDE1_ALARM_REG_WDE1_DCC_SM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_WDE1_ALARM_REG_WDE1_PRM_SM_ERR	vxge_mBIT(1)
+#define	VXGE_HW_WDE1_ALARM_REG_WDE1_CP_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_WDE1_ALARM_REG_WDE1_CP_CMD_ERR	vxge_mBIT(3)
+#define	VXGE_HW_WDE1_ALARM_REG_WDE1_PCR_SM_ERR	vxge_mBIT(4)
+/*0x00b20*/	u64	wde1_alarm_mask;
+/*0x00b28*/	u64	wde1_alarm_alarm;
+/*0x00b30*/	u64	wde2_alarm_reg;
+#define	VXGE_HW_WDE2_ALARM_REG_WDE2_DCC_SM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_WDE2_ALARM_REG_WDE2_PRM_SM_ERR	vxge_mBIT(1)
+#define	VXGE_HW_WDE2_ALARM_REG_WDE2_CP_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_WDE2_ALARM_REG_WDE2_CP_CMD_ERR	vxge_mBIT(3)
+#define	VXGE_HW_WDE2_ALARM_REG_WDE2_PCR_SM_ERR	vxge_mBIT(4)
+/*0x00b38*/	u64	wde2_alarm_mask;
+/*0x00b40*/	u64	wde2_alarm_alarm;
+/*0x00b48*/	u64	wde3_alarm_reg;
+#define	VXGE_HW_WDE3_ALARM_REG_WDE3_DCC_SM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_WDE3_ALARM_REG_WDE3_PRM_SM_ERR	vxge_mBIT(1)
+#define	VXGE_HW_WDE3_ALARM_REG_WDE3_CP_SM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_WDE3_ALARM_REG_WDE3_CP_CMD_ERR	vxge_mBIT(3)
+#define	VXGE_HW_WDE3_ALARM_REG_WDE3_PCR_SM_ERR	vxge_mBIT(4)
+/*0x00b50*/	u64	wde3_alarm_mask;
+/*0x00b58*/	u64	wde3_alarm_alarm;
+
+	u8	unused00be8[0x00be8-0x00b60];
+
+/*0x00be8*/	u64	rx_w_round_robin_0;
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(val) vxge_vBIT(val, 59, 5)
+/*0x00bf0*/	u64	rx_w_round_robin_1;
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_8(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_9(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_10(val) \
+						vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_11(val) \
+						vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_12(val) \
+						vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_13(val) \
+						vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_14(val) \
+						vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_15(val) \
+						vxge_vBIT(val, 59, 5)
+/*0x00bf8*/	u64	rx_w_round_robin_2;
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_16(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_17(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_18(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_19(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_20(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_21(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_22(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_23(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c00*/	u64	rx_w_round_robin_3;
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_24(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_25(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_26(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_27(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_28(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_29(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_30(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_31(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c08*/	u64	rx_w_round_robin_4;
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_32(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_33(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_34(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_35(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_36(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_37(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_38(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_39(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c10*/	u64	rx_w_round_robin_5;
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_40(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_41(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_42(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_43(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_44(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_45(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_46(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_47(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c18*/	u64	rx_w_round_robin_6;
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_48(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_49(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_50(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_51(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_52(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_53(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_54(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_55(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c20*/	u64	rx_w_round_robin_7;
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_56(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_57(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_58(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_59(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_60(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_61(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_62(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_63(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c28*/	u64	rx_w_round_robin_8;
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_64(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_65(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_66(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_67(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_68(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_69(val) \
+						vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_70(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_71(val) \
+						vxge_vBIT(val, 59, 5)
+/*0x00c30*/	u64	rx_w_round_robin_9;
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_72(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_73(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_74(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_75(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_76(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_77(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_78(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_79(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c38*/	u64	rx_w_round_robin_10;
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_80(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_81(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_82(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_83(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_84(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_85(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_86(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_87(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c40*/	u64	rx_w_round_robin_11;
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_88(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_89(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_90(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_91(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_92(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_93(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_94(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_95(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c48*/	u64	rx_w_round_robin_12;
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_96(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_97(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_98(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_99(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_100(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_101(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_102(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_103(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c50*/	u64	rx_w_round_robin_13;
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_104(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_105(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_106(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_107(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_108(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_109(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_110(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_111(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c58*/	u64	rx_w_round_robin_14;
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_112(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_113(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_114(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_115(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_116(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_117(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_118(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_119(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c60*/	u64	rx_w_round_robin_15;
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_120(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_121(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_122(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_123(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_124(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_125(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_126(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_127(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c68*/	u64	rx_w_round_robin_16;
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_128(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_129(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_130(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_131(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_132(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_133(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_134(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_135(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c70*/	u64	rx_w_round_robin_17;
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_136(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_137(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_138(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_139(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_140(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_141(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_142(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_143(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c78*/	u64	rx_w_round_robin_18;
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_144(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_145(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_146(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_147(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_148(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_149(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_150(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_151(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c80*/	u64	rx_w_round_robin_19;
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_152(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_153(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_154(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_155(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_156(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_157(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_158(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_159(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c88*/	u64	rx_w_round_robin_20;
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_160(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_161(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_162(val) \
+							vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_163(val) \
+							vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_164(val) \
+							vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_165(val) \
+							vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_166(val) \
+							vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_167(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00c90*/	u64	rx_w_round_robin_21;
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_168(val) \
+							vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_169(val) \
+							vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_170(val) \
+							vxge_vBIT(val, 19, 5)
+
+#define VXGE_HW_WRR_RING_SERVICE_STATES			171
+#define VXGE_HW_WRR_RING_COUNT				22
+
+/*0x00c98*/	u64	rx_queue_priority_0;
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+/*0x00ca0*/	u64	rx_queue_priority_1;
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(val) vxge_vBIT(val, 59, 5)
+/*0x00ca8*/	u64	rx_queue_priority_2;
+#define VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(val) vxge_vBIT(val, 3, 5)
+	u8	unused00cc8[0x00cc8-0x00cb0];
+
+/*0x00cc8*/	u64	replication_queue_priority;
+#define	VXGE_HW_REPLICATION_QUEUE_PRIORITY_REPLICATION_QUEUE_PRIORITY(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00cd0*/	u64	rx_queue_select;
+#define VXGE_HW_RX_QUEUE_SELECT_NUMBER(n)	vxge_mBIT(n)
+#define	VXGE_HW_RX_QUEUE_SELECT_ENABLE_CODE	vxge_mBIT(15)
+#define	VXGE_HW_RX_QUEUE_SELECT_ENABLE_HIERARCHICAL_PRTY	vxge_mBIT(23)
+/*0x00cd8*/	u64	rqa_vpbp_ctrl;
+#define	VXGE_HW_RQA_VPBP_CTRL_WR_XON_DIS	vxge_mBIT(15)
+#define	VXGE_HW_RQA_VPBP_CTRL_ROCRC_DIS	vxge_mBIT(23)
+#define	VXGE_HW_RQA_VPBP_CTRL_TXPE_DIS	vxge_mBIT(31)
+/*0x00ce0*/	u64	rx_multi_cast_ctrl;
+#define	VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_DIS	vxge_mBIT(0)
+#define	VXGE_HW_RX_MULTI_CAST_CTRL_FRM_DROP_DIS	vxge_mBIT(1)
+#define VXGE_HW_RX_MULTI_CAST_CTRL_NO_RXD_TIME_OUT_CNT(val) \
+							vxge_vBIT(val, 2, 30)
+#define VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_CNT(val) vxge_vBIT(val, 32, 32)
+/*0x00ce8*/	u64	wde_prm_ctrl;
+#define VXGE_HW_WDE_PRM_CTRL_SPAV_THRESHOLD(val) vxge_vBIT(val, 2, 10)
+#define VXGE_HW_WDE_PRM_CTRL_SPLIT_THRESHOLD(val) vxge_vBIT(val, 18, 14)
+#define	VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_1ST_ROW	vxge_mBIT(32)
+#define	VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_ROW_BNDRY	vxge_mBIT(33)
+#define VXGE_HW_WDE_PRM_CTRL_FB_ROW_SIZE(val) vxge_vBIT(val, 46, 2)
+/*0x00cf0*/	u64	noa_ctrl;
+#define VXGE_HW_NOA_CTRL_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_NOA_CTRL_NON_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 11, 5)
+#define	VXGE_HW_NOA_CTRL_IGNORE_KDFC_IF_STATUS	vxge_mBIT(16)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE0(val) vxge_vBIT(val, 37, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE1(val) vxge_vBIT(val, 45, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE2(val) vxge_vBIT(val, 53, 4)
+#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE3(val) vxge_vBIT(val, 60, 4)
+/*0x00cf8*/	u64	phase_cfg;
+#define	VXGE_HW_PHASE_CFG_QCC_WR_PHASE_EN	vxge_mBIT(0)
+#define	VXGE_HW_PHASE_CFG_QCC_RD_PHASE_EN	vxge_mBIT(3)
+#define	VXGE_HW_PHASE_CFG_IMMM_WR_PHASE_EN	vxge_mBIT(7)
+#define	VXGE_HW_PHASE_CFG_IMMM_RD_PHASE_EN	vxge_mBIT(11)
+#define	VXGE_HW_PHASE_CFG_UMQM_WR_PHASE_EN	vxge_mBIT(15)
+#define	VXGE_HW_PHASE_CFG_UMQM_RD_PHASE_EN	vxge_mBIT(19)
+#define	VXGE_HW_PHASE_CFG_RCBM_WR_PHASE_EN	vxge_mBIT(23)
+#define	VXGE_HW_PHASE_CFG_RCBM_RD_PHASE_EN	vxge_mBIT(27)
+#define	VXGE_HW_PHASE_CFG_RXD_RC_WR_PHASE_EN	vxge_mBIT(31)
+#define	VXGE_HW_PHASE_CFG_RXD_RC_RD_PHASE_EN	vxge_mBIT(35)
+#define	VXGE_HW_PHASE_CFG_RXD_RHS_WR_PHASE_EN	vxge_mBIT(39)
+#define	VXGE_HW_PHASE_CFG_RXD_RHS_RD_PHASE_EN	vxge_mBIT(43)
+/*0x00d00*/	u64	rcq_bypq_cfg;
+#define VXGE_HW_RCQ_BYPQ_CFG_OVERFLOW_THRESHOLD(val) vxge_vBIT(val, 10, 22)
+#define VXGE_HW_RCQ_BYPQ_CFG_BYP_ON_THRESHOLD(val) vxge_vBIT(val, 39, 9)
+#define VXGE_HW_RCQ_BYPQ_CFG_BYP_OFF_THRESHOLD(val) vxge_vBIT(val, 55, 9)
+	u8	unused00e00[0x00e00-0x00d08];
+
+/*0x00e00*/	u64	doorbell_int_status;
+#define	VXGE_HW_DOORBELL_INT_STATUS_KDFC_ERR_REG_TXDMA_KDFC_INT	vxge_mBIT(7)
+#define	VXGE_HW_DOORBELL_INT_STATUS_USDC_ERR_REG_TXDMA_USDC_INT	vxge_mBIT(15)
+/*0x00e08*/	u64	doorbell_int_mask;
+/*0x00e10*/	u64	kdfc_err_reg;
+#define	VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_SG_ERR	vxge_mBIT(7)
+#define	VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_DB_ERR	vxge_mBIT(15)
+#define	VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_SM_ERR_ALARM	vxge_mBIT(23)
+#define	VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_MISC_ERR_1	vxge_mBIT(32)
+#define	VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_PCIX_ERR	vxge_mBIT(39)
+/*0x00e18*/	u64	kdfc_err_mask;
+/*0x00e20*/	u64	kdfc_err_reg_alarm;
+#define	VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_SG_ERR	vxge_mBIT(7)
+#define	VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_DB_ERR	vxge_mBIT(15)
+#define	VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_SM_ERR_ALARM	vxge_mBIT(23)
+#define	VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_MISC_ERR_1	vxge_mBIT(32)
+#define	VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_PCIX_ERR	vxge_mBIT(39)
+	u8	unused00e40[0x00e40-0x00e28];
+/*0x00e40*/	u64	kdfc_vp_partition_0;
+#define	VXGE_HW_KDFC_VP_PARTITION_0_ENABLE	vxge_mBIT(0)
+#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_0(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_0(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_1(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_1(val) vxge_vBIT(val, 49, 15)
+/*0x00e48*/	u64	kdfc_vp_partition_1;
+#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_2(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_2(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_3(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_3(val) vxge_vBIT(val, 49, 15)
+/*0x00e50*/	u64	kdfc_vp_partition_2;
+#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_4(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_4(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_5(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_5(val) vxge_vBIT(val, 49, 15)
+/*0x00e58*/	u64	kdfc_vp_partition_3;
+#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_6(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_6(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_7(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_7(val) vxge_vBIT(val, 49, 15)
+/*0x00e60*/	u64	kdfc_vp_partition_4;
+#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_8(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_9(val) vxge_vBIT(val, 49, 15)
+/*0x00e68*/	u64	kdfc_vp_partition_5;
+#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_10(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_11(val) vxge_vBIT(val, 49, 15)
+/*0x00e70*/	u64	kdfc_vp_partition_6;
+#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_12(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_13(val) vxge_vBIT(val, 49, 15)
+/*0x00e78*/	u64	kdfc_vp_partition_7;
+#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_14(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_15(val) vxge_vBIT(val, 49, 15)
+/*0x00e80*/	u64	kdfc_vp_partition_8;
+#define VXGE_HW_KDFC_VP_PARTITION_8_LENGTH_16(val) vxge_vBIT(val, 17, 15)
+/*0x00e88*/	u64	kdfc_w_round_robin_0;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+	u8	unused0f28[0x0f28-0x0e90];
+
+/*0x00f28*/	u64	kdfc_w_round_robin_20;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+#define VXGE_HW_WRR_FIFO_COUNT				20
+
+	u8	unused0fc8[0x0fc8-0x0f30];
+
+/*0x00fc8*/	u64	kdfc_w_round_robin_40;
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_0(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_1(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_2(val) vxge_vBIT(val, 19, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_3(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_4(val) vxge_vBIT(val, 35, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_5(val) vxge_vBIT(val, 43, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_6(val) vxge_vBIT(val, 51, 5)
+#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_7(val) vxge_vBIT(val, 59, 5)
+
+	u8	unused1068[0x01068-0x0fd0];
+
+/*0x01068*/	u64	kdfc_entry_type_sel_0;
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(val) vxge_vBIT(val, 14, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(val) vxge_vBIT(val, 22, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(val) vxge_vBIT(val, 30, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(val) vxge_vBIT(val, 38, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(val) vxge_vBIT(val, 46, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(val) vxge_vBIT(val, 54, 2)
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(val) vxge_vBIT(val, 62, 2)
+/*0x01070*/	u64	kdfc_entry_type_sel_1;
+#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(val) vxge_vBIT(val, 6, 2)
+/*0x01078*/	u64	kdfc_fifo_0_ctrl;
+#define VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_WEIGHTED_RR_SERVICE_STATES		176
+#define VXGE_HW_WRR_FIFO_SERVICE_STATES			153
+
+	u8	unused1100[0x01100-0x1080];
+
+/*0x01100*/	u64	kdfc_fifo_17_ctrl;
+#define VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
+
+	u8	unused1600[0x01600-0x1108];
+
+/*0x01600*/	u64	rxmac_int_status;
+#define	VXGE_HW_RXMAC_INT_STATUS_RXMAC_GEN_ERR_RXMAC_GEN_INT	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_INT_STATUS_RXMAC_ECC_ERR_RXMAC_ECC_INT	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_INT_STATUS_RXMAC_VARIOUS_ERR_RXMAC_VARIOUS_INT \
+								vxge_mBIT(11)
+/*0x01608*/	u64	rxmac_int_mask;
+	u8	unused01618[0x01618-0x01610];
+
+/*0x01618*/	u64	rxmac_gen_err_reg;
+/*0x01620*/	u64	rxmac_gen_err_mask;
+/*0x01628*/	u64	rxmac_gen_err_alarm;
+/*0x01630*/	u64	rxmac_ecc_err_reg;
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_SG_ERR(val) \
+							vxge_vBIT(val, 0, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_DB_ERR(val) \
+							vxge_vBIT(val, 4, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_SG_ERR(val) \
+							vxge_vBIT(val, 8, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_DB_ERR(val) \
+							vxge_vBIT(val, 12, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_SG_ERR(val) \
+							vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_DB_ERR(val) \
+							vxge_vBIT(val, 20, 4)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_SG_ERR(val) \
+							vxge_vBIT(val, 24, 2)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_DB_ERR(val) \
+							vxge_vBIT(val, 26, 2)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_SG_ERR(val) \
+							vxge_vBIT(val, 28, 2)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_DB_ERR(val) \
+							vxge_vBIT(val, 30, 2)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_SG_ERR	vxge_mBIT(32)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_DB_ERR	vxge_mBIT(33)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_SG_ERR	vxge_mBIT(34)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_DB_ERR	vxge_mBIT(35)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_SG_ERR	vxge_mBIT(36)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_DB_ERR	vxge_mBIT(37)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_SG_ERR	vxge_mBIT(38)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_DB_ERR	vxge_mBIT(39)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_SG_ERR(val) \
+							vxge_vBIT(val, 40, 7)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_DB_ERR(val) \
+							vxge_vBIT(val, 47, 7)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_SG_ERR(val) \
+							vxge_vBIT(val, 54, 3)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_DB_ERR(val) \
+							vxge_vBIT(val, 57, 3)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_SG_ERR \
+							vxge_mBIT(60)
+#define	VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_DB_ERR \
+							vxge_mBIT(61)
+/*0x01638*/	u64	rxmac_ecc_err_mask;
+/*0x01640*/	u64	rxmac_ecc_err_alarm;
+/*0x01648*/	u64	rxmac_various_err_reg;
+#define	VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT0_FSM_ERR	vxge_mBIT(0)
+#define	VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT1_FSM_ERR	vxge_mBIT(1)
+#define	VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT2_FSM_ERR	vxge_mBIT(2)
+#define	VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMACJ_RMACJ_FSM_ERR	vxge_mBIT(3)
+/*0x01650*/	u64	rxmac_various_err_mask;
+/*0x01658*/	u64	rxmac_various_err_alarm;
+/*0x01660*/	u64	rxmac_gen_cfg;
+#define	VXGE_HW_RXMAC_GEN_CFG_SCALE_RMAC_UTIL	vxge_mBIT(11)
+/*0x01668*/	u64	rxmac_authorize_all_addr;
+#define VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(n)	vxge_mBIT(n)
+/*0x01670*/	u64	rxmac_authorize_all_vid;
+#define VXGE_HW_RXMAC_AUTHORIZE_ALL_VID_VP(n)	vxge_mBIT(n)
+	u8	unused016c0[0x016c0-0x01678];
+
+/*0x016c0*/	u64	rxmac_red_rate_repl_queue;
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
+#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
+#define	VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_TRICKLE_EN	vxge_mBIT(35)
+	u8	unused016e0[0x016e0-0x016c8];
+
+/*0x016e0*/	u64	rxmac_cfg0_port[3];
+#define	VXGE_HW_RXMAC_CFG0_PORT_RMAC_EN	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_CFG0_PORT_STRIP_FCS	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_CFG0_PORT_DISCARD_PFRM	vxge_mBIT(11)
+#define	VXGE_HW_RXMAC_CFG0_PORT_IGNORE_FCS_ERR	vxge_mBIT(15)
+#define	VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LONG_ERR	vxge_mBIT(19)
+#define	VXGE_HW_RXMAC_CFG0_PORT_IGNORE_USIZED_ERR	vxge_mBIT(23)
+#define	VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LEN_MISMATCH	vxge_mBIT(27)
+#define VXGE_HW_RXMAC_CFG0_PORT_MAX_PYLD_LEN(val) vxge_vBIT(val, 50, 14)
+	u8	unused01710[0x01710-0x016f8];
+
+/*0x01710*/	u64	rxmac_cfg2_port[3];
+#define	VXGE_HW_RXMAC_CFG2_PORT_PROM_EN	vxge_mBIT(3)
+/*0x01728*/	u64	rxmac_pause_cfg_port[3];
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN	vxge_mBIT(7)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_ACCEL_SEND(val) vxge_vBIT(val, 9, 3)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_DUAL_THR	vxge_mBIT(15)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_HIGH_PTIME(val) vxge_vBIT(val, 20, 16)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_FCS_ERR	vxge_mBIT(39)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_LEN_ERR	vxge_mBIT(43)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_LIMITER_EN	vxge_mBIT(47)
+#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_MAX_LIMIT(val) vxge_vBIT(val, 48, 8)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_PERMIT_RATEMGMT_CTRL	vxge_mBIT(59)
+	u8	unused01758[0x01758-0x01740];
+
+/*0x01758*/	u64	rxmac_red_cfg0_port[3];
+#define VXGE_HW_RXMAC_RED_CFG0_PORT_RED_EN_VP(n)	vxge_mBIT(n)
+/*0x01770*/	u64	rxmac_red_cfg1_port[3];
+#define	VXGE_HW_RXMAC_RED_CFG1_PORT_FINE_EN	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_RED_CFG1_PORT_RED_EN_REPL_QUEUE	vxge_mBIT(11)
+/*0x01788*/	u64	rxmac_red_cfg2_port[3];
+#define VXGE_HW_RXMAC_RED_CFG2_PORT_TRICKLE_EN_VP(n)	vxge_mBIT(n)
+/*0x017a0*/	u64	rxmac_link_util_port[3];
+#define	VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_UTILIZATION(val) \
+							vxge_vBIT(val, 1, 7)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_FRAC_UTIL(val) \
+							vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_SCALE_FACTOR	vxge_mBIT(23)
+	u8	unused017d0[0x017d0-0x017b8];
+
+/*0x017d0*/	u64	rxmac_status_port[3];
+#define	VXGE_HW_RXMAC_STATUS_PORT_RMAC_RX_FRM_RCVD	vxge_mBIT(3)
+	u8	unused01800[0x01800-0x017e8];
+
+/*0x01800*/	u64	rxmac_rx_pa_cfg0;
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_IGNORE_FRAME_ERR	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_SNAP_AB_N	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_HAO	vxge_mBIT(18)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_MOBILE_IPV6_HDRS	vxge_mBIT(19)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_IPV6_STOP_SEARCHING	vxge_mBIT(23)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_NO_PS_IF_UNKNOWN	vxge_mBIT(27)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_ETYPE	vxge_mBIT(35)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L3_CSUM_ERR	vxge_mBIT(39)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR	vxge_mBIT(43)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L4_CSUM_ERR	vxge_mBIT(47)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR	vxge_mBIT(51)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_RPA_ERR	vxge_mBIT(55)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_RPA_ERR	vxge_mBIT(59)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_JUMBO_SNAP_EN	vxge_mBIT(63)
+/*0x01808*/	u64	rxmac_rx_pa_cfg1;
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_TCP_INCL_PH	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_TCP_INCL_PH	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_UDP_INCL_PH	vxge_mBIT(11)
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_UDP_INCL_PH	vxge_mBIT(15)
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_L4_INCL_CF	vxge_mBIT(19)
+#define	VXGE_HW_RXMAC_RX_PA_CFG1_REPL_STRIP_VLAN_TAG	vxge_mBIT(23)
+	u8	unused01828[0x01828-0x01810];
+
+/*0x01828*/	u64	rts_mgr_cfg0;
+#define	VXGE_HW_RTS_MGR_CFG0_RTS_DP_SP_PRIORITY	vxge_mBIT(3)
+#define VXGE_HW_RTS_MGR_CFG0_FLEX_L4PRTCL_VALUE(val) vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_RTS_MGR_CFG0_ICMP_TRASH	vxge_mBIT(35)
+#define	VXGE_HW_RTS_MGR_CFG0_TCPSYN_TRASH	vxge_mBIT(39)
+#define	VXGE_HW_RTS_MGR_CFG0_ZL4PYLD_TRASH	vxge_mBIT(43)
+#define	VXGE_HW_RTS_MGR_CFG0_L4PRTCL_TCP_TRASH	vxge_mBIT(47)
+#define	VXGE_HW_RTS_MGR_CFG0_L4PRTCL_UDP_TRASH	vxge_mBIT(51)
+#define	VXGE_HW_RTS_MGR_CFG0_L4PRTCL_FLEX_TRASH	vxge_mBIT(55)
+#define	VXGE_HW_RTS_MGR_CFG0_IPFRAG_TRASH	vxge_mBIT(59)
+/*0x01830*/	u64	rts_mgr_cfg1;
+#define	VXGE_HW_RTS_MGR_CFG1_DA_ACTIVE_TABLE	vxge_mBIT(3)
+#define	VXGE_HW_RTS_MGR_CFG1_PN_ACTIVE_TABLE	vxge_mBIT(7)
+/*0x01838*/	u64	rts_mgr_criteria_priority;
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ETYPE(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ICMP_TCPSYN(val) vxge_vBIT(val, 9, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PN(val) vxge_vBIT(val, 13, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RANGE_L4PN(val) vxge_vBIT(val, 17, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RTH_IT(val) vxge_vBIT(val, 21, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_DS(val) vxge_vBIT(val, 25, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_QOS(val) vxge_vBIT(val, 29, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ZL4PYLD(val) vxge_vBIT(val, 33, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PRTCL(val) vxge_vBIT(val, 37, 3)
+/*0x01840*/	u64	rts_mgr_da_pause_cfg;
+#define VXGE_HW_RTS_MGR_DA_PAUSE_CFG_VPATH_VECTOR(val) vxge_vBIT(val, 0, 17)
+/*0x01848*/	u64	rts_mgr_da_slow_proto_cfg;
+#define VXGE_HW_RTS_MGR_DA_SLOW_PROTO_CFG_VPATH_VECTOR(val) \
+							vxge_vBIT(val, 0, 17)
+	u8	unused01890[0x01890-0x01850];
+/*0x01890*/     u64     rts_mgr_cbasin_cfg;
+	u8	unused01968[0x01968-0x01898];
+
+/*0x01968*/	u64	dbg_stat_rx_any_frms;
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT0_RX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT1_RX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT2_RX_ANY_FRMS(val) \
+							vxge_vBIT(val, 16, 8)
+	u8	unused01a00[0x01a00-0x01970];
+
+/*0x01a00*/	u64	rxmac_red_rate_vp[17];
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
+#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
+	u8	unused01e00[0x01e00-0x01a88];
+
+/*0x01e00*/	u64	xgmac_int_status;
+#define	VXGE_HW_XGMAC_INT_STATUS_XMAC_GEN_ERR_XMAC_GEN_INT	vxge_mBIT(3)
+#define	VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT0_XMAC_LINK_INT_PORT0 \
+								vxge_mBIT(7)
+#define	VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT1_XMAC_LINK_INT_PORT1 \
+								vxge_mBIT(11)
+#define	VXGE_HW_XGMAC_INT_STATUS_XGXS_GEN_ERR_XGXS_GEN_INT	vxge_mBIT(15)
+#define	VXGE_HW_XGMAC_INT_STATUS_ASIC_NTWK_ERR_ASIC_NTWK_INT	vxge_mBIT(19)
+#define	VXGE_HW_XGMAC_INT_STATUS_ASIC_GPIO_ERR_ASIC_GPIO_INT	vxge_mBIT(23)
+/*0x01e08*/	u64	xgmac_int_mask;
+/*0x01e10*/	u64	xmac_gen_err_reg;
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_ACTOR_CHURN_DETECTED \
+								vxge_mBIT(7)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_PARTNER_CHURN_DETECTED \
+								vxge_mBIT(11)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_RECEIVED_LACPDU	vxge_mBIT(15)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_ACTOR_CHURN_DETECTED \
+								vxge_mBIT(19)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_PARTNER_CHURN_DETECTED \
+								vxge_mBIT(23)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_RECEIVED_LACPDU	vxge_mBIT(27)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XLCM_LAG_FAILOVER_DETECTED	vxge_mBIT(31)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_SG_ERR(val) \
+							vxge_vBIT(val, 40, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_DB_ERR(val) \
+							vxge_vBIT(val, 42, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_SG_ERR(val) \
+							vxge_vBIT(val, 44, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_DB_ERR(val) \
+							vxge_vBIT(val, 46, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_SG_ERR(val) \
+							vxge_vBIT(val, 48, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_DB_ERR(val) \
+							vxge_vBIT(val, 50, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_SG_ERR(val) \
+							vxge_vBIT(val, 52, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_DB_ERR(val) \
+							vxge_vBIT(val, 54, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_SG_ERR(val) \
+							vxge_vBIT(val, 56, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_DB_ERR(val) \
+							vxge_vBIT(val, 58, 2)
+#define	VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR	vxge_mBIT(63)
+/*0x01e18*/	u64	xmac_gen_err_mask;
+/*0x01e20*/	u64	xmac_gen_err_alarm;
+/*0x01e28*/	u64	xmac_link_err_port0_reg;
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN	vxge_mBIT(3)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP	vxge_mBIT(7)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN	vxge_mBIT(11)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_UP	vxge_mBIT(15)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_FAULT \
+								vxge_mBIT(19)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_OK	vxge_mBIT(23)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_DOWN	vxge_mBIT(27)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_UP	vxge_mBIT(31)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_RATE_CHANGE	vxge_mBIT(35)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV	vxge_mBIT(39)
+#define	VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
+								vxge_mBIT(47)
+/*0x01e30*/	u64	xmac_link_err_port0_mask;
+/*0x01e38*/	u64	xmac_link_err_port0_alarm;
+/*0x01e40*/	u64	xmac_link_err_port1_reg;
+/*0x01e48*/	u64	xmac_link_err_port1_mask;
+/*0x01e50*/	u64	xmac_link_err_port1_alarm;
+/*0x01e58*/	u64	xgxs_gen_err_reg;
+#define	VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR	vxge_mBIT(63)
+/*0x01e60*/	u64	xgxs_gen_err_mask;
+/*0x01e68*/	u64	xgxs_gen_err_alarm;
+/*0x01e70*/	u64	asic_ntwk_err_reg;
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_DOWN	vxge_mBIT(3)
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_UP	vxge_mBIT(7)
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_DOWN	vxge_mBIT(11)
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_UP	vxge_mBIT(15)
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT	vxge_mBIT(19)
+#define	VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK	vxge_mBIT(23)
+/*0x01e78*/	u64	asic_ntwk_err_mask;
+/*0x01e80*/	u64	asic_ntwk_err_alarm;
+/*0x01e88*/	u64	asic_gpio_err_reg;
+#define VXGE_HW_ASIC_GPIO_ERR_REG_XMACJ_GPIO_INT(n)	vxge_mBIT(n)
+/*0x01e90*/	u64	asic_gpio_err_mask;
+/*0x01e98*/	u64	asic_gpio_err_alarm;
+/*0x01ea0*/	u64	xgmac_gen_status;
+#define	VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_OK	vxge_mBIT(3)
+#define	VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_DATA_RATE	vxge_mBIT(11)
+/*0x01ea8*/	u64	xgmac_gen_fw_memo_status;
+#define	VXGE_HW_XGMAC_GEN_FW_MEMO_STATUS_XMACJ_EVENTS_PENDING(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x01eb0*/	u64	xgmac_gen_fw_memo_mask;
+#define VXGE_HW_XGMAC_GEN_FW_MEMO_MASK_MASK(val) vxge_vBIT(val, 0, 64)
+/*0x01eb8*/	u64	xgmac_gen_fw_vpath_to_vsport_status;
+#define	VXGE_HW_XGMAC_GEN_FW_VPATH_TO_VSPORT_STATUS_XMACJ_EVENTS_PENDING(val) \
+						vxge_vBIT(val, 0, 17)
+/*0x01ec0*/	u64	xgmac_main_cfg_port[2];
+#define	VXGE_HW_XGMAC_MAIN_CFG_PORT_PORT_EN	vxge_mBIT(3)
+	u8	unused01f40[0x01f40-0x01ed0];
+
+/*0x01f40*/	u64	xmac_gen_cfg;
+#define VXGE_HW_XMAC_GEN_CFG_RATEMGMT_MAC_RATE_SEL(val) vxge_vBIT(val, 2, 2)
+#define	VXGE_HW_XMAC_GEN_CFG_TX_HEAD_DROP_WHEN_FAULT	vxge_mBIT(7)
+#define	VXGE_HW_XMAC_GEN_CFG_FAULT_BEHAVIOUR	vxge_mBIT(27)
+#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_UP(val) vxge_vBIT(val, 28, 4)
+#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_DOWN(val) vxge_vBIT(val, 32, 4)
+/*0x01f48*/	u64	xmac_timestamp;
+#define	VXGE_HW_XMAC_TIMESTAMP_EN	vxge_mBIT(3)
+#define VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_XMAC_TIMESTAMP_INTERVAL(val) vxge_vBIT(val, 12, 4)
+#define	VXGE_HW_XMAC_TIMESTAMP_TIMER_RESTART	vxge_mBIT(19)
+#define VXGE_HW_XMAC_TIMESTAMP_XMACJ_ROLLOVER_CNT(val) vxge_vBIT(val, 32, 16)
+/*0x01f50*/	u64	xmac_stats_gen_cfg;
+#define VXGE_HW_XMAC_STATS_GEN_CFG_PRTAGGR_CUM_TIMER(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_XMAC_STATS_GEN_CFG_VPATH_CUM_TIMER(val) vxge_vBIT(val, 8, 4)
+#define	VXGE_HW_XMAC_STATS_GEN_CFG_VLAN_HANDLING	vxge_mBIT(15)
+/*0x01f58*/	u64	xmac_stats_sys_cmd;
+#define VXGE_HW_XMAC_STATS_SYS_CMD_OP(val) vxge_vBIT(val, 5, 3)
+#define	VXGE_HW_XMAC_STATS_SYS_CMD_STROBE	vxge_mBIT(15)
+#define VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(val) vxge_vBIT(val, 27, 5)
+#define VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
+/*0x01f60*/	u64	xmac_stats_sys_data;
+#define VXGE_HW_XMAC_STATS_SYS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
+	u8	unused01f80[0x01f80-0x01f68];
+
+/*0x01f80*/	u64	asic_ntwk_ctrl;
+#define	VXGE_HW_ASIC_NTWK_CTRL_REQ_TEST_NTWK	vxge_mBIT(3)
+#define	VXGE_HW_ASIC_NTWK_CTRL_PORT0_REQ_TEST_PORT	vxge_mBIT(11)
+#define	VXGE_HW_ASIC_NTWK_CTRL_PORT1_REQ_TEST_PORT	vxge_mBIT(15)
+/*0x01f88*/	u64	asic_ntwk_cfg_show_port_info;
+#define VXGE_HW_ASIC_NTWK_CFG_SHOW_PORT_INFO_VP(n)	vxge_mBIT(n)
+/*0x01f90*/	u64	asic_ntwk_cfg_port_num;
+#define VXGE_HW_ASIC_NTWK_CFG_PORT_NUM_VP(n)	vxge_mBIT(n)
+/*0x01f98*/	u64	xmac_cfg_port[3];
+#define	VXGE_HW_XMAC_CFG_PORT_XGMII_LOOPBACK	vxge_mBIT(3)
+#define	VXGE_HW_XMAC_CFG_PORT_XGMII_REVERSE_LOOPBACK	vxge_mBIT(7)
+#define	VXGE_HW_XMAC_CFG_PORT_XGMII_TX_BEHAV	vxge_mBIT(11)
+#define	VXGE_HW_XMAC_CFG_PORT_XGMII_RX_BEHAV	vxge_mBIT(15)
+/*0x01fb0*/	u64	xmac_station_addr_port[2];
+#define VXGE_HW_XMAC_STATION_ADDR_PORT_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
+	u8	unused02020[0x02020-0x01fc0];
+
+/*0x02020*/	u64	lag_cfg;
+#define	VXGE_HW_LAG_CFG_EN	vxge_mBIT(3)
+#define VXGE_HW_LAG_CFG_MODE(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_LAG_CFG_TX_DISCARD_BEHAV	vxge_mBIT(11)
+#define	VXGE_HW_LAG_CFG_RX_DISCARD_BEHAV	vxge_mBIT(15)
+#define	VXGE_HW_LAG_CFG_PREF_INDIV_PORT_NUM	vxge_mBIT(19)
+/*0x02028*/	u64	lag_status;
+#define	VXGE_HW_LAG_STATUS_XLCM_WAITING_TO_FAILBACK	vxge_mBIT(3)
+#define VXGE_HW_LAG_STATUS_XLCM_TIMER_VAL_COLD_FAILOVER(val) \
+							vxge_vBIT(val, 8, 8)
+/*0x02030*/	u64	lag_active_passive_cfg;
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_HOT_STANDBY	vxge_mBIT(3)
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_LACP_DECIDES	vxge_mBIT(7)
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_PREF_ACTIVE_PORT_NUM	vxge_mBIT(11)
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_AUTO_FAILBACK	vxge_mBIT(15)
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_FAILBACK_EN	vxge_mBIT(19)
+#define	VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_COLD_FAILOVER_TIMEOUT(val) \
+							vxge_vBIT(val, 32, 16)
+	u8	unused02040[0x02040-0x02038];
+
+/*0x02040*/	u64	lag_lacp_cfg;
+#define	VXGE_HW_LAG_LACP_CFG_EN	vxge_mBIT(3)
+#define	VXGE_HW_LAG_LACP_CFG_LACP_BEGIN	vxge_mBIT(7)
+#define	VXGE_HW_LAG_LACP_CFG_DISCARD_LACP	vxge_mBIT(11)
+#define	VXGE_HW_LAG_LACP_CFG_LIBERAL_LEN_CHK	vxge_mBIT(15)
+/*0x02048*/	u64	lag_timer_cfg_1;
+#define VXGE_HW_LAG_TIMER_CFG_1_FAST_PER(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_SLOW_PER(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_SHORT_TIMEOUT(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_TIMER_CFG_1_LONG_TIMEOUT(val) vxge_vBIT(val, 48, 16)
+/*0x02050*/	u64	lag_timer_cfg_2;
+#define VXGE_HW_LAG_TIMER_CFG_2_CHURN_DET(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_AGGR_WAIT(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_SHORT_TIMER_SCALE(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_TIMER_CFG_2_LONG_TIMER_SCALE(val)  vxge_vBIT(val, 48, 16)
+/*0x02058*/	u64	lag_sys_id;
+#define VXGE_HW_LAG_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
+#define	VXGE_HW_LAG_SYS_ID_USE_PORT_ADDR	vxge_mBIT(51)
+#define	VXGE_HW_LAG_SYS_ID_ADDR_SEL	vxge_mBIT(55)
+/*0x02060*/	u64	lag_sys_cfg;
+#define VXGE_HW_LAG_SYS_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+	u8	unused02070[0x02070-0x02068];
+
+/*0x02070*/	u64	lag_aggr_addr_cfg[2];
+#define VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR(val) vxge_vBIT(val, 0, 48)
+#define	VXGE_HW_LAG_AGGR_ADDR_CFG_USE_PORT_ADDR	vxge_mBIT(51)
+#define	VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR_SEL	vxge_mBIT(55)
+/*0x02080*/	u64	lag_aggr_id_cfg[2];
+#define VXGE_HW_LAG_AGGR_ID_CFG_ID(val) vxge_vBIT(val, 0, 16)
+/*0x02090*/	u64	lag_aggr_admin_key[2];
+#define VXGE_HW_LAG_AGGR_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x020a0*/	u64	lag_aggr_alt_admin_key;
+#define VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_ALT_AGGR	vxge_mBIT(19)
+/*0x020a8*/	u64	lag_aggr_oper_key[2];
+#define VXGE_HW_LAG_AGGR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x020b8*/	u64	lag_aggr_partner_sys_id[2];
+#define VXGE_HW_LAG_AGGR_PARTNER_SYS_ID_LAGC_ADDR(val) vxge_vBIT(val, 0, 48)
+/*0x020c8*/	u64	lag_aggr_partner_info[2];
+#define VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_OPER_KEY(val) \
+						vxge_vBIT(val, 16, 16)
+/*0x020d8*/	u64	lag_aggr_state[2];
+#define	VXGE_HW_LAG_AGGR_STATE_LAGC_TX	vxge_mBIT(3)
+#define	VXGE_HW_LAG_AGGR_STATE_LAGC_RX	vxge_mBIT(7)
+#define	VXGE_HW_LAG_AGGR_STATE_LAGC_READY	vxge_mBIT(11)
+#define	VXGE_HW_LAG_AGGR_STATE_LAGC_INDIVIDUAL	vxge_mBIT(15)
+	u8	unused020f0[0x020f0-0x020e8];
+
+/*0x020f0*/	u64	lag_port_cfg[2];
+#define	VXGE_HW_LAG_PORT_CFG_EN	vxge_mBIT(3)
+#define	VXGE_HW_LAG_PORT_CFG_DISCARD_SLOW_PROTO	vxge_mBIT(7)
+#define	VXGE_HW_LAG_PORT_CFG_HOST_CHOSEN_AGGR	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_CFG_DISCARD_UNKNOWN_SLOW_PROTO	vxge_mBIT(15)
+/*0x02100*/	u64	lag_port_actor_admin_cfg[2];
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_NUM(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_PRI(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_10G(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_1G(val) vxge_vBIT(val, 48, 16)
+/*0x02110*/	u64	lag_port_actor_admin_state[2];
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_ACTIVITY	vxge_mBIT(3)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_TIMEOUT	vxge_mBIT(7)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_AGGREGATION	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_SYNCHRONIZATION	vxge_mBIT(15)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_COLLECTING	vxge_mBIT(19)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DISTRIBUTING	vxge_mBIT(23)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DEFAULTED	vxge_mBIT(27)
+#define	VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_EXPIRED	vxge_mBIT(31)
+/*0x02120*/	u64	lag_port_partner_admin_sys_id[2];
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
+/*0x02130*/	u64	lag_port_partner_admin_cfg[2];
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_KEY(val) vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_NUM(val) \
+							vxge_vBIT(val, 32, 16)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_PRI(val) \
+							vxge_vBIT(val, 48, 16)
+/*0x02140*/	u64	lag_port_partner_admin_state[2];
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_ACTIVITY	vxge_mBIT(3)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_TIMEOUT	vxge_mBIT(7)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_AGGREGATION	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_SYNCHRONIZATION	vxge_mBIT(15)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_COLLECTING	vxge_mBIT(19)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DISTRIBUTING	vxge_mBIT(23)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DEFAULTED	vxge_mBIT(27)
+#define	VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_EXPIRED	vxge_mBIT(31)
+/*0x02150*/	u64	lag_port_to_aggr[2];
+#define VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_ID(val) vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_VLD_ID	vxge_mBIT(19)
+/*0x02160*/	u64	lag_port_actor_oper_key[2];
+#define VXGE_HW_LAG_PORT_ACTOR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
+/*0x02170*/	u64	lag_port_actor_oper_state[2];
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_ACTIVITY	vxge_mBIT(3)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_TIMEOUT	vxge_mBIT(7)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_AGGREGATION	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_SYNCHRONIZATION	vxge_mBIT(15)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_COLLECTING	vxge_mBIT(19)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DISTRIBUTING	vxge_mBIT(23)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DEFAULTED	vxge_mBIT(27)
+#define	VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_EXPIRED	vxge_mBIT(31)
+/*0x02180*/	u64	lag_port_partner_oper_sys_id[2];
+#define VXGE_HW_LAG_PORT_PARTNER_OPER_SYS_ID_LAGC_ADDR(val) \
+						vxge_vBIT(val, 0, 48)
+/*0x02190*/	u64	lag_port_partner_oper_info[2];
+#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_SYS_PRI(val) \
+						vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_KEY(val) \
+						vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_NUM(val) \
+						vxge_vBIT(val, 32, 16)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_PRI(val) \
+						vxge_vBIT(val, 48, 16)
+/*0x021a0*/	u64	lag_port_partner_oper_state[2];
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_ACTIVITY	vxge_mBIT(3)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_TIMEOUT	vxge_mBIT(7)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_AGGREGATION	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_SYNCHRONIZATION \
+								vxge_mBIT(15)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_COLLECTING	vxge_mBIT(19)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DISTRIBUTING	vxge_mBIT(23)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DEFAULTED	vxge_mBIT(27)
+#define	VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_EXPIRED	vxge_mBIT(31)
+/*0x021b0*/	u64	lag_port_state_vars[2];
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_READY	vxge_mBIT(3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_SELECTED(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_AGGR_NUM	vxge_mBIT(11)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_MOVED	vxge_mBIT(15)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_ENABLED	vxge_mBIT(18)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_DISABLED	vxge_mBIT(19)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_NTT	vxge_mBIT(23)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN	vxge_mBIT(27)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN	vxge_mBIT(31)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_INFO_LEN_MISMATCH \
+								vxge_mBIT(32)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_INFO_LEN_MISMATCH \
+								vxge_mBIT(33)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_COLL_INFO_LEN_MISMATCH	vxge_mBIT(34)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_TERM_INFO_LEN_MISMATCH	vxge_mBIT(35)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_RX_FSM_STATE(val) vxge_vBIT(val, 37, 3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_FSM_STATE(val) \
+							vxge_vBIT(val, 41, 3)
+#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_REASON(val) vxge_vBIT(val, 44, 4)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_STATE	vxge_mBIT(54)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_STATE	vxge_mBIT(55)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_COUNT(val) \
+							vxge_vBIT(val, 56, 4)
+#define	VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_COUNT(val) \
+							vxge_vBIT(val, 60, 4)
+/*0x021c0*/	u64	lag_port_timer_cntr[2];
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_CURRENT_WHILE(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PERIODIC_WHILE(val) \
+							vxge_vBIT(val, 8, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_WAIT_WHILE(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_TX_LACP(val) vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_SYNC_TRANSITION_COUNT(val) \
+							vxge_vBIT(val, 32, 8)
+#define	VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_SYNC_TRANSITION_COUNT(val) \
+							vxge_vBIT(val, 40, 8)
+#define	VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_CHANGE_COUNT(val) \
+							vxge_vBIT(val, 48, 8)
+#define	VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_CHANGE_COUNT(val) \
+							vxge_vBIT(val, 56, 8)
+	u8	unused02208[0x02700-0x021d0];
+
+/*0x02700*/	u64	rtdma_int_status;
+#define	VXGE_HW_RTDMA_INT_STATUS_PDA_ALARM_PDA_INT	vxge_mBIT(1)
+#define	VXGE_HW_RTDMA_INT_STATUS_PCC_ERROR_PCC_INT	vxge_mBIT(2)
+#define	VXGE_HW_RTDMA_INT_STATUS_LSO_ERROR_LSO_INT	vxge_mBIT(4)
+#define	VXGE_HW_RTDMA_INT_STATUS_SM_ERROR_SM_INT	vxge_mBIT(5)
+/*0x02708*/	u64	rtdma_int_mask;
+/*0x02710*/	u64	pda_alarm_reg;
+#define	VXGE_HW_PDA_ALARM_REG_PDA_HSC_FIFO_ERR	vxge_mBIT(0)
+#define	VXGE_HW_PDA_ALARM_REG_PDA_SM_ERR	vxge_mBIT(1)
+/*0x02718*/	u64	pda_alarm_mask;
+/*0x02720*/	u64	pda_alarm_alarm;
+/*0x02728*/	u64	pcc_error_reg;
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_SBE(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_SBE(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_DBE(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_DBE(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FSM_ERR_ALARM(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_SERR(n)	vxge_mBIT(n)
+/*0x02730*/	u64	pcc_error_mask;
+/*0x02738*/	u64	pcc_error_alarm;
+/*0x02740*/	u64	lso_error_reg;
+#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_ABORT(n)	vxge_mBIT(n)
+#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_FSM_ERR_ALARM(n)	vxge_mBIT(n)
+/*0x02748*/	u64	lso_error_mask;
+/*0x02750*/	u64	lso_error_alarm;
+/*0x02758*/	u64	sm_error_reg;
+#define	VXGE_HW_SM_ERROR_REG_SM_FSM_ERR_ALARM	vxge_mBIT(15)
+/*0x02760*/	u64	sm_error_mask;
+/*0x02768*/	u64	sm_error_alarm;
+
+	u8	unused027a8[0x027a8-0x02770];
+
+/*0x027a8*/	u64	txd_ownership_ctrl;
+#define	VXGE_HW_TXD_OWNERSHIP_CTRL_KEEP_OWNERSHIP	vxge_mBIT(7)
+/*0x027b0*/	u64	pcc_cfg;
+#define VXGE_HW_PCC_CFG_PCC_ENABLE(n)	vxge_mBIT(n)
+#define VXGE_HW_PCC_CFG_PCC_ECC_ENABLE_N(n)	vxge_mBIT(n)
+/*0x027b8*/	u64	pcc_control;
+#define VXGE_HW_PCC_CONTROL_FE_ENABLE(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_PCC_CONTROL_EARLY_ASSIGN_EN	vxge_mBIT(15)
+#define	VXGE_HW_PCC_CONTROL_UNBLOCK_DB_ERR	vxge_mBIT(31)
+/*0x027c0*/	u64	pda_status1;
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_0_CTR(val) vxge_vBIT(val, 4, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_1_CTR(val) vxge_vBIT(val, 12, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_2_CTR(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_3_CTR(val) vxge_vBIT(val, 28, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_4_CTR(val) vxge_vBIT(val, 36, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_5_CTR(val) vxge_vBIT(val, 44, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_6_CTR(val) vxge_vBIT(val, 52, 4)
+#define VXGE_HW_PDA_STATUS1_PDA_WRAP_7_CTR(val) vxge_vBIT(val, 60, 4)
+/*0x027c8*/	u64	rtdma_bw_timer;
+#define VXGE_HW_RTDMA_BW_TIMER_TIMER_CTRL(val) vxge_vBIT(val, 12, 4)
+
+	u8	unused02900[0x02900-0x027d0];
+/*0x02900*/	u64	g3cmct_int_status;
+#define	VXGE_HW_G3CMCT_INT_STATUS_ERR_G3IF_INT	vxge_mBIT(0)
+/*0x02908*/	u64	g3cmct_int_mask;
+/*0x02910*/	u64	g3cmct_err_reg;
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_SM_ERR	vxge_mBIT(4)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_DECC	vxge_mBIT(5)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_DECC	vxge_mBIT(6)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_DECC	vxge_mBIT(7)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_SECC	vxge_mBIT(29)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_SECC	vxge_mBIT(30)
+#define	VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_SECC	vxge_mBIT(31)
+/*0x02918*/	u64	g3cmct_err_mask;
+/*0x02920*/	u64	g3cmct_err_alarm;
+	u8	unused03000[0x03000-0x02928];
+
+/*0x03000*/	u64	mc_int_status;
+#define	VXGE_HW_MC_INT_STATUS_MC_ERR_MC_INT	vxge_mBIT(3)
+#define	VXGE_HW_MC_INT_STATUS_GROCRC_ALARM_ROCRC_INT	vxge_mBIT(7)
+#define	VXGE_HW_MC_INT_STATUS_FAU_GEN_ERR_FAU_GEN_INT	vxge_mBIT(11)
+#define	VXGE_HW_MC_INT_STATUS_FAU_ECC_ERR_FAU_ECC_INT	vxge_mBIT(15)
+/*0x03008*/	u64	mc_int_mask;
+/*0x03010*/	u64	mc_err_reg;
+#define	VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_A	vxge_mBIT(3)
+#define	VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_B	vxge_mBIT(4)
+#define	VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_SG_ERR	vxge_mBIT(5)
+#define	VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_0	vxge_mBIT(6)
+#define	VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_1	vxge_mBIT(7)
+#define	VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_A	vxge_mBIT(10)
+#define	VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_B	vxge_mBIT(11)
+#define	VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_DB_ERR	vxge_mBIT(12)
+#define	VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_0	vxge_mBIT(13)
+#define	VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_1	vxge_mBIT(14)
+#define	VXGE_HW_MC_ERR_REG_MC_SM_ERR	vxge_mBIT(15)
+/*0x03018*/	u64	mc_err_mask;
+/*0x03020*/	u64	mc_err_alarm;
+/*0x03028*/	u64	grocrc_alarm_reg;
+#define	VXGE_HW_GROCRC_ALARM_REG_XFMD_WR_FIFO_ERR	vxge_mBIT(3)
+#define	VXGE_HW_GROCRC_ALARM_REG_WDE2MSR_RD_FIFO_ERR	vxge_mBIT(7)
+/*0x03030*/	u64	grocrc_alarm_mask;
+/*0x03038*/	u64	grocrc_alarm_alarm;
+	u8	unused03100[0x03100-0x03040];
+
+/*0x03100*/	u64	rx_thresh_cfg_repl;
+#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_0(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_1(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_2(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_3(val) vxge_vBIT(val, 40, 8)
+#define	VXGE_HW_RX_THRESH_CFG_REPL_GLOBAL_WOL_EN	vxge_mBIT(62)
+#define	VXGE_HW_RX_THRESH_CFG_REPL_EXACT_VP_MATCH_REQ	vxge_mBIT(63)
+	u8	unused033b8[0x033b8-0x03108];
+
+/*0x033b8*/	u64	fbmc_ecc_cfg;
+#define VXGE_HW_FBMC_ECC_CFG_ENABLE(val) vxge_vBIT(val, 3, 5)
+	u8	unused03400[0x03400-0x033c0];
+
+/*0x03400*/	u64	pcipif_int_status;
+#define	VXGE_HW_PCIPIF_INT_STATUS_DBECC_ERR_DBECC_ERR_INT	vxge_mBIT(3)
+#define	VXGE_HW_PCIPIF_INT_STATUS_SBECC_ERR_SBECC_ERR_INT	vxge_mBIT(7)
+#define	VXGE_HW_PCIPIF_INT_STATUS_GENERAL_ERR_GENERAL_ERR_INT	vxge_mBIT(11)
+#define	VXGE_HW_PCIPIF_INT_STATUS_SRPCIM_MSG_SRPCIM_MSG_INT	vxge_mBIT(15)
+#define	VXGE_HW_PCIPIF_INT_STATUS_MRPCIM_SPARE_R1_MRPCIM_SPARE_R1_INT \
+								vxge_mBIT(19)
+/*0x03408*/	u64	pcipif_int_mask;
+/*0x03410*/	u64	dbecc_err_reg;
+#define	VXGE_HW_DBECC_ERR_REG_PCI_RETRY_BUF_DB_ERR	vxge_mBIT(3)
+#define	VXGE_HW_DBECC_ERR_REG_PCI_RETRY_SOT_DB_ERR	vxge_mBIT(7)
+#define	VXGE_HW_DBECC_ERR_REG_PCI_P_HDR_DB_ERR	vxge_mBIT(11)
+#define	VXGE_HW_DBECC_ERR_REG_PCI_P_DATA_DB_ERR	vxge_mBIT(15)
+#define	VXGE_HW_DBECC_ERR_REG_PCI_NP_HDR_DB_ERR	vxge_mBIT(19)
+#define	VXGE_HW_DBECC_ERR_REG_PCI_NP_DATA_DB_ERR	vxge_mBIT(23)
+/*0x03418*/	u64	dbecc_err_mask;
+/*0x03420*/	u64	dbecc_err_alarm;
+/*0x03428*/	u64	sbecc_err_reg;
+#define	VXGE_HW_SBECC_ERR_REG_PCI_RETRY_BUF_SG_ERR	vxge_mBIT(3)
+#define	VXGE_HW_SBECC_ERR_REG_PCI_RETRY_SOT_SG_ERR	vxge_mBIT(7)
+#define	VXGE_HW_SBECC_ERR_REG_PCI_P_HDR_SG_ERR	vxge_mBIT(11)
+#define	VXGE_HW_SBECC_ERR_REG_PCI_P_DATA_SG_ERR	vxge_mBIT(15)
+#define	VXGE_HW_SBECC_ERR_REG_PCI_NP_HDR_SG_ERR	vxge_mBIT(19)
+#define	VXGE_HW_SBECC_ERR_REG_PCI_NP_DATA_SG_ERR	vxge_mBIT(23)
+/*0x03430*/	u64	sbecc_err_mask;
+/*0x03438*/	u64	sbecc_err_alarm;
+/*0x03440*/	u64	general_err_reg;
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_DROPPED_ILLEGAL_CFG	vxge_mBIT(3)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_ILLEGAL_MEM_MAP_PROG	vxge_mBIT(7)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_LINK_RST_FSM_ERR	vxge_mBIT(11)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_RX_ILLEGAL_TLP_VPLANE	vxge_mBIT(15)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_TRAINING_RESET_DET	vxge_mBIT(19)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_PCI_LINK_DOWN_DET	vxge_mBIT(23)
+#define	VXGE_HW_GENERAL_ERR_REG_PCI_RESET_ACK_DLLP	vxge_mBIT(27)
+/*0x03448*/	u64	general_err_mask;
+/*0x03450*/	u64	general_err_alarm;
+/*0x03458*/	u64	srpcim_msg_reg;
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE0_RMSG_INT \
+								vxge_mBIT(0)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE1_RMSG_INT \
+								vxge_mBIT(1)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE2_RMSG_INT \
+								vxge_mBIT(2)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE3_RMSG_INT \
+								vxge_mBIT(3)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE4_RMSG_INT \
+								vxge_mBIT(4)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE5_RMSG_INT \
+								vxge_mBIT(5)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE6_RMSG_INT \
+								vxge_mBIT(6)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE7_RMSG_INT \
+								vxge_mBIT(7)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE8_RMSG_INT \
+								vxge_mBIT(8)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE9_RMSG_INT \
+								vxge_mBIT(9)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE10_RMSG_INT \
+								vxge_mBIT(10)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE11_RMSG_INT \
+								vxge_mBIT(11)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE12_RMSG_INT \
+								vxge_mBIT(12)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE13_RMSG_INT \
+								vxge_mBIT(13)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE14_RMSG_INT \
+								vxge_mBIT(14)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE15_RMSG_INT \
+								vxge_mBIT(15)
+#define	VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE16_RMSG_INT \
+								vxge_mBIT(16)
+/*0x03460*/	u64	srpcim_msg_mask;
+/*0x03468*/	u64	srpcim_msg_alarm;
+	u8	unused03600[0x03600-0x03470];
+
+/*0x03600*/	u64	gcmg1_int_status;
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSCC_ERR_GSSCC_INT	vxge_mBIT(0)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR0_GSSC0_0_INT	vxge_mBIT(1)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR1_GSSC0_1_INT	vxge_mBIT(2)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR0_GSSC1_0_INT	vxge_mBIT(3)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR1_GSSC1_1_INT	vxge_mBIT(4)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR0_GSSC2_0_INT	vxge_mBIT(5)
+#define	VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR1_GSSC2_1_INT	vxge_mBIT(6)
+#define	VXGE_HW_GCMG1_INT_STATUS_UQM_ERR_UQM_INT	vxge_mBIT(7)
+#define	VXGE_HW_GCMG1_INT_STATUS_GQCC_ERR_GQCC_INT	vxge_mBIT(8)
+/*0x03608*/	u64	gcmg1_int_mask;
+	u8	unused03a00[0x03a00-0x03610];
+
+/*0x03a00*/	u64	pcmg1_int_status;
+#define	VXGE_HW_PCMG1_INT_STATUS_PSSCC_ERR_PSSCC_INT	vxge_mBIT(0)
+#define	VXGE_HW_PCMG1_INT_STATUS_PQCC_ERR_PQCC_INT	vxge_mBIT(1)
+#define	VXGE_HW_PCMG1_INT_STATUS_PQCC_CQM_ERR_PQCC_CQM_INT	vxge_mBIT(2)
+#define	VXGE_HW_PCMG1_INT_STATUS_PQCC_SQM_ERR_PQCC_SQM_INT	vxge_mBIT(3)
+/*0x03a08*/	u64	pcmg1_int_mask;
+	u8	unused04000[0x04000-0x03a10];
+
+/*0x04000*/	u64	one_int_status;
+#define	VXGE_HW_ONE_INT_STATUS_RXPE_ERR_RXPE_INT	vxge_mBIT(7)
+#define	VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_SG_ECC_ERR_TXPE_BCC_MEM_SG_ECC_INT \
+							vxge_mBIT(13)
+#define	VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_DB_ECC_ERR_TXPE_BCC_MEM_DB_ECC_INT \
+							vxge_mBIT(14)
+#define	VXGE_HW_ONE_INT_STATUS_TXPE_ERR_TXPE_INT	vxge_mBIT(15)
+#define	VXGE_HW_ONE_INT_STATUS_DLM_ERR_DLM_INT	vxge_mBIT(23)
+#define	VXGE_HW_ONE_INT_STATUS_PE_ERR_PE_INT	vxge_mBIT(31)
+#define	VXGE_HW_ONE_INT_STATUS_RPE_ERR_RPE_INT	vxge_mBIT(39)
+#define	VXGE_HW_ONE_INT_STATUS_RPE_FSM_ERR_RPE_FSM_INT	vxge_mBIT(47)
+#define	VXGE_HW_ONE_INT_STATUS_OES_ERR_OES_INT	vxge_mBIT(55)
+/*0x04008*/	u64	one_int_mask;
+	u8	unused04818[0x04818-0x04010];
+
+/*0x04818*/	u64	noa_wct_ctrl;
+#define	VXGE_HW_NOA_WCT_CTRL_VP_INT_NUM	vxge_mBIT(0)
+/*0x04820*/	u64	rc_cfg2;
+#define VXGE_HW_RC_CFG2_BUFF1_SIZE(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_RC_CFG2_BUFF2_SIZE(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_RC_CFG2_BUFF3_SIZE(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_RC_CFG2_BUFF4_SIZE(val) vxge_vBIT(val, 48, 16)
+/*0x04828*/	u64	rc_cfg3;
+#define VXGE_HW_RC_CFG3_BUFF5_SIZE(val) vxge_vBIT(val, 0, 16)
+/*0x04830*/	u64	rx_multi_cast_ctrl1;
+#define	VXGE_HW_RX_MULTI_CAST_CTRL1_ENABLE	vxge_mBIT(7)
+#define VXGE_HW_RX_MULTI_CAST_CTRL1_DELAY_COUNT(val) vxge_vBIT(val, 11, 5)
+/*0x04838*/	u64	rxdm_dbg_rd;
+#define VXGE_HW_RXDM_DBG_RD_ADDR(val) vxge_vBIT(val, 0, 12)
+#define	VXGE_HW_RXDM_DBG_RD_ENABLE	vxge_mBIT(31)
+/*0x04840*/	u64	rxdm_dbg_rd_data;
+#define VXGE_HW_RXDM_DBG_RD_DATA_RMC_RXDM_DBG_RD_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x04848*/	u64	rqa_top_prty_for_vh[17];
+#define VXGE_HW_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
+							vxge_vBIT(val, 59, 5)
+	u8	unused04900[0x04900-0x048d0];
+
+/*0x04900*/	u64	tim_status;
+#define	VXGE_HW_TIM_STATUS_TIM_RESET_IN_PROGRESS	vxge_mBIT(0)
+/*0x04908*/	u64	tim_ecc_enable;
+#define	VXGE_HW_TIM_ECC_ENABLE_VBLS_N	vxge_mBIT(7)
+#define	VXGE_HW_TIM_ECC_ENABLE_BMAP_N	vxge_mBIT(15)
+#define	VXGE_HW_TIM_ECC_ENABLE_BMAP_MSG_N	vxge_mBIT(23)
+/*0x04910*/	u64	tim_bp_ctrl;
+#define	VXGE_HW_TIM_BP_CTRL_RD_XON	vxge_mBIT(7)
+#define	VXGE_HW_TIM_BP_CTRL_WR_XON	vxge_mBIT(15)
+#define	VXGE_HW_TIM_BP_CTRL_ROCRC_BYP	vxge_mBIT(23)
+/*0x04918*/	u64	tim_resource_assignment_vh[17];
+#define VXGE_HW_TIM_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+/*0x049a0*/	u64	tim_bmap_mapping_vp_err[17];
+#define VXGE_HW_TIM_BMAP_MAPPING_VP_ERR_TIM_DEST_VPATH(val) vxge_vBIT(val, 3, 5)
+	u8	unused04b00[0x04b00-0x04a28];
+
+/*0x04b00*/	u64	gcmg2_int_status;
+#define	VXGE_HW_GCMG2_INT_STATUS_GXTMC_ERR_GXTMC_INT	vxge_mBIT(7)
+#define	VXGE_HW_GCMG2_INT_STATUS_GCP_ERR_GCP_INT	vxge_mBIT(15)
+#define	VXGE_HW_GCMG2_INT_STATUS_CMC_ERR_CMC_INT	vxge_mBIT(23)
+/*0x04b08*/	u64	gcmg2_int_mask;
+/*0x04b10*/	u64	gxtmc_err_reg;
+#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_DB_ERR(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_SG_ERR(val) vxge_vBIT(val, 4, 4)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMC_RD_DATA_DB_ERR	vxge_mBIT(8)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_FIFO_ERR	vxge_mBIT(9)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR	vxge_mBIT(10)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR	vxge_mBIT(11)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR	vxge_mBIT(12)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_FIFO_ERR	vxge_mBIT(13)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_ERR	vxge_mBIT(14)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_FIFO_ERR	vxge_mBIT(15)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_ERR	vxge_mBIT(16)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_DATA_SM_ERR	vxge_mBIT(17)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_CMC0_IF_ERR	vxge_mBIT(18)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_ARB_SM_ERR	vxge_mBIT(19)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_CFC_SM_ERR	vxge_mBIT(20)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_OVERFLOW \
+							vxge_mBIT(21)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_UNDERFLOW \
+							vxge_mBIT(22)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_SM_ERR	vxge_mBIT(23)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_OVERFLOW \
+							vxge_mBIT(24)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_UNDERFLOW \
+							vxge_mBIT(25)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_SM_ERR	vxge_mBIT(26)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_SM_ERR	vxge_mBIT(27)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_TAG_ERR	vxge_mBIT(28)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_SM_ERR	vxge_mBIT(29)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_FIFO_ERR	vxge_mBIT(30)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_POP_ERR	vxge_mBIT(31)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_CMI_OP_ERR	vxge_mBIT(32)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFETCH_OP_ERR	vxge_mBIT(33)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFIFO_ERR	vxge_mBIT(34)
+#define	VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_ARB_SM_ERR	vxge_mBIT(35)
+/*0x04b18*/	u64	gxtmc_err_mask;
+/*0x04b20*/	u64	gxtmc_err_alarm;
+/*0x04b28*/	u64	cmc_err_reg;
+#define	VXGE_HW_CMC_ERR_REG_CMC_CMC_SM_ERR	vxge_mBIT(0)
+/*0x04b30*/	u64	cmc_err_mask;
+/*0x04b38*/	u64	cmc_err_alarm;
+/*0x04b40*/	u64	gcp_err_reg;
+#define	VXGE_HW_GCP_ERR_REG_CP_H2L2CP_FIFO_ERR	vxge_mBIT(0)
+#define	VXGE_HW_GCP_ERR_REG_CP_STC2CP_FIFO_ERR	vxge_mBIT(1)
+#define	VXGE_HW_GCP_ERR_REG_CP_STE2CP_FIFO_ERR	vxge_mBIT(2)
+#define	VXGE_HW_GCP_ERR_REG_CP_TTE2CP_FIFO_ERR	vxge_mBIT(3)
+/*0x04b48*/	u64	gcp_err_mask;
+/*0x04b50*/	u64	gcp_err_alarm;
+	u8	unused04f00[0x04f00-0x04b58];
+
+/*0x04f00*/	u64	pcmg2_int_status;
+#define	VXGE_HW_PCMG2_INT_STATUS_PXTMC_ERR_PXTMC_INT	vxge_mBIT(7)
+#define	VXGE_HW_PCMG2_INT_STATUS_CP_EXC_CP_XT_EXC_INT	vxge_mBIT(15)
+#define	VXGE_HW_PCMG2_INT_STATUS_CP_ERR_CP_ERR_INT	vxge_mBIT(23)
+/*0x04f08*/	u64	pcmg2_int_mask;
+/*0x04f10*/	u64	pxtmc_err_reg;
+#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_DB_ERR(val) vxge_vBIT(val, 0, 2)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FIFO_ERR	vxge_mBIT(2)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_PRSP_FIFO_ERR	vxge_mBIT(3)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_WRSP_FIFO_ERR	vxge_mBIT(4)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FIFO_ERR	vxge_mBIT(5)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_PRSP_FIFO_ERR	vxge_mBIT(6)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_WRSP_FIFO_ERR	vxge_mBIT(7)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FIFO_ERR	vxge_mBIT(8)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_PRSP_FIFO_ERR	vxge_mBIT(9)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_WRSP_FIFO_ERR	vxge_mBIT(10)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_FIFO_ERR	vxge_mBIT(11)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR	vxge_mBIT(12)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR	vxge_mBIT(13)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR	vxge_mBIT(14)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_SHADOW_ERR	vxge_mBIT(15)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_SHADOW_ERR	vxge_mBIT(16)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_SHADOW_ERR	vxge_mBIT(17)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_SHADOW_ERR	vxge_mBIT(18)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_SHADOW_ERR	vxge_mBIT(19)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_SHADOW_ERR	vxge_mBIT(20)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_SHADOW_ERR	vxge_mBIT(21)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_SHADOW_ERR	vxge_mBIT(22)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_RAM_SHADOW_ERR	vxge_mBIT(23)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_SHADOW_ERR	vxge_mBIT(24)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_SHADOW_ERR	vxge_mBIT(25)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FSM_ERR	vxge_mBIT(26)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_FSM_ERR	vxge_mBIT(27)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FSM_ERR	vxge_mBIT(28)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_FSM_ERR	vxge_mBIT(29)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FSM_ERR	vxge_mBIT(30)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_FSM_ERR	vxge_mBIT(31)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_FSM_ERR	vxge_mBIT(32)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_FSM_ERR	vxge_mBIT(33)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_FSM_ERR	vxge_mBIT(34)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_FSM_ERR	vxge_mBIT(35)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_ERR	vxge_mBIT(36)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_ERR	vxge_mBIT(37)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_ERR	vxge_mBIT(38)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_ERR	vxge_mBIT(39)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_ERR	vxge_mBIT(40)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_ERR	vxge_mBIT(41)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_ERR	vxge_mBIT(42)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_ERR	vxge_mBIT(43)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_ERR	vxge_mBIT(44)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_INFO_ERR	vxge_mBIT(45)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_INFO_ERR	vxge_mBIT(46)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_INFO_ERR	vxge_mBIT(47)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_INFO_ERR	vxge_mBIT(48)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_INFO_ERR	vxge_mBIT(49)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_INFO_ERR	vxge_mBIT(50)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_INFO_ERR	vxge_mBIT(51)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_INFO_ERR	vxge_mBIT(52)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_INFO_ERR	vxge_mBIT(53)
+#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_SG_ERR(val) vxge_vBIT(val, 54, 2)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_DFIFO_PUSH_ERR	vxge_mBIT(56)
+#define	VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_PUSH_ERR	vxge_mBIT(57)
+/*0x04f18*/	u64	pxtmc_err_mask;
+/*0x04f20*/	u64	pxtmc_err_alarm;
+/*0x04f28*/	u64	cp_err_reg;
+#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_SG_ERR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_SG_ERR(val) vxge_vBIT(val, 8, 2)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_DTAG_SG_ERR	vxge_mBIT(10)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_ITAG_SG_ERR	vxge_mBIT(11)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_TRACE_SG_ERR	vxge_mBIT(12)
+#define	VXGE_HW_CP_ERR_REG_CP_DMA2CP_SG_ERR	vxge_mBIT(13)
+#define	VXGE_HW_CP_ERR_REG_CP_MP2CP_SG_ERR	vxge_mBIT(14)
+#define	VXGE_HW_CP_ERR_REG_CP_QCC2CP_SG_ERR	vxge_mBIT(15)
+#define VXGE_HW_CP_ERR_REG_CP_STC2CP_SG_ERR(val) vxge_vBIT(val, 16, 2)
+#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_DB_ERR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_DB_ERR(val) vxge_vBIT(val, 32, 2)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_DTAG_DB_ERR	vxge_mBIT(34)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_ITAG_DB_ERR	vxge_mBIT(35)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_TRACE_DB_ERR	vxge_mBIT(36)
+#define	VXGE_HW_CP_ERR_REG_CP_DMA2CP_DB_ERR	vxge_mBIT(37)
+#define	VXGE_HW_CP_ERR_REG_CP_MP2CP_DB_ERR	vxge_mBIT(38)
+#define	VXGE_HW_CP_ERR_REG_CP_QCC2CP_DB_ERR	vxge_mBIT(39)
+#define VXGE_HW_CP_ERR_REG_CP_STC2CP_DB_ERR(val) vxge_vBIT(val, 40, 2)
+#define	VXGE_HW_CP_ERR_REG_CP_H2L2CP_FIFO_ERR	vxge_mBIT(48)
+#define	VXGE_HW_CP_ERR_REG_CP_STC2CP_FIFO_ERR	vxge_mBIT(49)
+#define	VXGE_HW_CP_ERR_REG_CP_STE2CP_FIFO_ERR	vxge_mBIT(50)
+#define	VXGE_HW_CP_ERR_REG_CP_TTE2CP_FIFO_ERR	vxge_mBIT(51)
+#define	VXGE_HW_CP_ERR_REG_CP_SWIF2CP_FIFO_ERR	vxge_mBIT(52)
+#define	VXGE_HW_CP_ERR_REG_CP_CP2DMA_FIFO_ERR	vxge_mBIT(53)
+#define	VXGE_HW_CP_ERR_REG_CP_DAM2CP_FIFO_ERR	vxge_mBIT(54)
+#define	VXGE_HW_CP_ERR_REG_CP_MP2CP_FIFO_ERR	vxge_mBIT(55)
+#define	VXGE_HW_CP_ERR_REG_CP_QCC2CP_FIFO_ERR	vxge_mBIT(56)
+#define	VXGE_HW_CP_ERR_REG_CP_DMA2CP_FIFO_ERR	vxge_mBIT(57)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_WAKE_FSM_INTEGRITY_ERR	vxge_mBIT(60)
+#define	VXGE_HW_CP_ERR_REG_CP_CP_PMON_FSM_INTEGRITY_ERR	vxge_mBIT(61)
+#define	VXGE_HW_CP_ERR_REG_CP_DMA_RD_SHADOW_ERR	vxge_mBIT(62)
+#define	VXGE_HW_CP_ERR_REG_CP_PIFT_CREDIT_ERR	vxge_mBIT(63)
+/*0x04f30*/	u64	cp_err_mask;
+/*0x04f38*/	u64	cp_err_alarm;
+	u8	unused04fe8[0x04f50-0x04f40];
+
+/*0x04f50*/	u64	cp_exc_reg;
+#define	VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_INFO_INT	vxge_mBIT(47)
+#define	VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_CRIT_INT	vxge_mBIT(55)
+#define	VXGE_HW_CP_EXC_REG_CP_CP_SERR	vxge_mBIT(63)
+/*0x04f58*/	u64	cp_exc_mask;
+/*0x04f60*/	u64	cp_exc_alarm;
+/*0x04f68*/	u64	cp_exc_cause;
+#define VXGE_HW_CP_EXC_CAUSE_CP_CP_CAUSE(val) vxge_vBIT(val, 32, 32)
+	u8	unused05200[0x05200-0x04f70];
+
+/*0x05200*/	u64	msg_int_status;
+#define	VXGE_HW_MSG_INT_STATUS_TIM_ERR_TIM_INT	vxge_mBIT(7)
+#define	VXGE_HW_MSG_INT_STATUS_MSG_EXC_MSG_XT_EXC_INT	vxge_mBIT(60)
+#define	VXGE_HW_MSG_INT_STATUS_MSG_ERR3_MSG_ERR3_INT	vxge_mBIT(61)
+#define	VXGE_HW_MSG_INT_STATUS_MSG_ERR2_MSG_ERR2_INT	vxge_mBIT(62)
+#define	VXGE_HW_MSG_INT_STATUS_MSG_ERR_MSG_ERR_INT	vxge_mBIT(63)
+/*0x05208*/	u64	msg_int_mask;
+/*0x05210*/	u64	tim_err_reg;
+#define	VXGE_HW_TIM_ERR_REG_TIM_VBLS_SG_ERR	vxge_mBIT(4)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_SG_ERR	vxge_mBIT(5)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_SG_ERR	vxge_mBIT(6)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_SG_ERR	vxge_mBIT(7)
+#define	VXGE_HW_TIM_ERR_REG_TIM_VBLS_DB_ERR	vxge_mBIT(12)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_DB_ERR	vxge_mBIT(13)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_DB_ERR	vxge_mBIT(14)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_DB_ERR	vxge_mBIT(15)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_MEM_CNTRL_SM_ERR	vxge_mBIT(18)
+#define	VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_MEM_CNTRL_SM_ERR	vxge_mBIT(19)
+#define	VXGE_HW_TIM_ERR_REG_TIM_MPIF_PCIWR_ERR	vxge_mBIT(20)
+#define	VXGE_HW_TIM_ERR_REG_TIM_ROCRC_BMAP_UPDT_FIFO_ERR	vxge_mBIT(22)
+#define	VXGE_HW_TIM_ERR_REG_TIM_CREATE_BMAPMSG_FIFO_ERR	vxge_mBIT(23)
+#define	VXGE_HW_TIM_ERR_REG_TIM_ROCRCIF_MISMATCH	vxge_mBIT(46)
+#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MAPPING_VP_ERR(n)	vxge_mBIT(n)
+/*0x05218*/	u64	tim_err_mask;
+/*0x05220*/	u64	tim_err_alarm;
+/*0x05228*/	u64	msg_err_reg;
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_WAKE_FSM_INTEGRITY_ERR	vxge_mBIT(0)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_WAKE_FSM_INTEGRITY_ERR	vxge_mBIT(1)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_READ_CMD_FSM_INTEGRITY_ERR \
+								vxge_mBIT(2)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_RESP_FSM_INTEGRITY_ERR \
+								vxge_mBIT(3)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_OWN_FSM_INTEGRITY_ERR	vxge_mBIT(4)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_PDA_ACC_FSM_INTEGRITY_ERR	vxge_mBIT(5)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_PMON_FSM_INTEGRITY_ERR	vxge_mBIT(6)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_PMON_FSM_INTEGRITY_ERR	vxge_mBIT(7)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_SG_ERR	vxge_mBIT(8)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_SG_ERR	vxge_mBIT(10)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_SG_ERR	vxge_mBIT(12)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_SG_ERR	vxge_mBIT(14)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_SG_ERR	vxge_mBIT(16)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_SG_ERR	vxge_mBIT(17)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_SG_ERR	vxge_mBIT(18)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_SG_ERR	vxge_mBIT(19)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_SG_ERR	vxge_mBIT(20)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_SG_ERR	vxge_mBIT(21)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_SG_ERR	vxge_mBIT(26)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_SG_ERR	vxge_mBIT(27)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_SG_ERR	vxge_mBIT(29)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_SG_ERR	vxge_mBIT(31)
+#define	VXGE_HW_MSG_ERR_REG_MSG_XFMDQRY_FSM_INTEGRITY_ERR	vxge_mBIT(33)
+#define	VXGE_HW_MSG_ERR_REG_MSG_FRMQRY_FSM_INTEGRITY_ERR	vxge_mBIT(34)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_WRITE_FSM_INTEGRITY_ERR	vxge_mBIT(35)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_BWR_PF_FSM_INTEGRITY_ERR \
+								vxge_mBIT(36)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_RESP_FIFO_ERR	vxge_mBIT(38)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_DB_ERR	vxge_mBIT(39)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_DB_ERR	vxge_mBIT(41)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_DB_ERR	vxge_mBIT(43)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_DB_ERR	vxge_mBIT(45)
+#define	VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_DB_ERR	vxge_mBIT(47)
+#define	VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_DB_ERR	vxge_mBIT(48)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_DB_ERR	vxge_mBIT(49)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_DB_ERR	vxge_mBIT(50)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_DB_ERR	vxge_mBIT(51)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_DB_ERR	vxge_mBIT(52)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_READ_FIFO_ERR	vxge_mBIT(53)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_MXP2UXP_FIFO_ERR	vxge_mBIT(54)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_KDFC_SIF_FIFO_ERR	vxge_mBIT(55)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_CXP2SWIF_FIFO_ERR	vxge_mBIT(56)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_DB_ERR	vxge_mBIT(57)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_DB_ERR	vxge_mBIT(58)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_SIF_FIFO_ERR	vxge_mBIT(59)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_DB_ERR	vxge_mBIT(60)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_READ_FIFO_ERR	vxge_mBIT(61)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_DB_ERR	vxge_mBIT(62)
+#define	VXGE_HW_MSG_ERR_REG_MSG_QUE_UXP2MXP_FIFO_ERR	vxge_mBIT(63)
+/*0x05230*/	u64	msg_err_mask;
+/*0x05238*/	u64	msg_err_alarm;
+	u8	unused05340[0x05340-0x05240];
+
+/*0x05340*/	u64	msg_exc_reg;
+#define	VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_INFO_INT	vxge_mBIT(50)
+#define	VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_CRIT_INT	vxge_mBIT(51)
+#define	VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_INFO_INT	vxge_mBIT(54)
+#define	VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_CRIT_INT	vxge_mBIT(55)
+#define	VXGE_HW_MSG_EXC_REG_MP_MXP_SERR	vxge_mBIT(62)
+#define	VXGE_HW_MSG_EXC_REG_UP_UXP_SERR	vxge_mBIT(63)
+/*0x05348*/	u64	msg_exc_mask;
+/*0x05350*/	u64	msg_exc_alarm;
+/*0x05358*/	u64	msg_exc_cause;
+#define VXGE_HW_MSG_EXC_CAUSE_MP_MXP(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_MSG_EXC_CAUSE_UP_UXP(val) vxge_vBIT(val, 32, 32)
+	u8	unused05368[0x05380-0x05360];
+
+/*0x05380*/	u64	msg_err2_reg;
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_CMG2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+							vxge_mBIT(0)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMQ_DISPATCH_FSM_INTEGRITY_ERR \
+								vxge_mBIT(1)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_DISPATCH_FSM_INTEGRITY_ERR \
+								vxge_mBIT(2)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_PIC_WRITE_FSM_INTEGRITY_ERR \
+								vxge_mBIT(3)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIFREG_FSM_INTEGRITY_ERR	vxge_mBIT(4)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_TIM_WRITE_FSM_INTEGRITY_ERR \
+								vxge_mBIT(5)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ_TA_FSM_INTEGRITY_ERR	vxge_mBIT(6)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE_TA_FSM_INTEGRITY_ERR	vxge_mBIT(7)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE_TA_FSM_INTEGRITY_ERR	vxge_mBIT(8)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_TA_FSM_INTEGRITY_ERR	vxge_mBIT(9)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMA_TA_FSM_INTEGRITY_ERR	vxge_mBIT(10)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_CP_TA_FSM_INTEGRITY_ERR	vxge_mBIT(11)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA16_FSM_INTEGRITY_ERR \
+							vxge_mBIT(12)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA15_FSM_INTEGRITY_ERR \
+							vxge_mBIT(13)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA14_FSM_INTEGRITY_ERR \
+							vxge_mBIT(14)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA13_FSM_INTEGRITY_ERR \
+							vxge_mBIT(15)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA12_FSM_INTEGRITY_ERR \
+							vxge_mBIT(16)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA11_FSM_INTEGRITY_ERR \
+							vxge_mBIT(17)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA10_FSM_INTEGRITY_ERR \
+							vxge_mBIT(18)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA9_FSM_INTEGRITY_ERR \
+							vxge_mBIT(19)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA8_FSM_INTEGRITY_ERR \
+							vxge_mBIT(20)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA7_FSM_INTEGRITY_ERR \
+							vxge_mBIT(21)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA6_FSM_INTEGRITY_ERR \
+							vxge_mBIT(22)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA5_FSM_INTEGRITY_ERR \
+							vxge_mBIT(23)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA4_FSM_INTEGRITY_ERR \
+							vxge_mBIT(24)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA3_FSM_INTEGRITY_ERR \
+							vxge_mBIT(25)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA2_FSM_INTEGRITY_ERR \
+							vxge_mBIT(26)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA1_FSM_INTEGRITY_ERR \
+							vxge_mBIT(27)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA0_FSM_INTEGRITY_ERR \
+							vxge_mBIT(28)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_FBMC_OWN_FSM_INTEGRITY_ERR	vxge_mBIT(29)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+							vxge_mBIT(30)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+							vxge_mBIT(31)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_RPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
+							vxge_mBIT(32)
+#define	VXGE_HW_MSG_ERR2_REG_MP_MP_PIFT_IF_CREDIT_CNT_ERR	vxge_mBIT(33)
+#define	VXGE_HW_MSG_ERR2_REG_UP_UP_PIFT_IF_CREDIT_CNT_ERR	vxge_mBIT(34)
+#define	VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ2PIC_CMD_FIFO_ERR	vxge_mBIT(62)
+#define	VXGE_HW_MSG_ERR2_REG_TIM_TIM2MSG_CMD_FIFO_ERR	vxge_mBIT(63)
+/*0x05388*/	u64	msg_err2_mask;
+/*0x05390*/	u64	msg_err2_alarm;
+/*0x05398*/	u64	msg_err3_reg;
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR0	vxge_mBIT(0)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR1	vxge_mBIT(1)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR2	vxge_mBIT(2)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR3	vxge_mBIT(3)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR4	vxge_mBIT(4)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR5	vxge_mBIT(5)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR6	vxge_mBIT(6)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR7	vxge_mBIT(7)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR0	vxge_mBIT(8)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR1	vxge_mBIT(9)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR0	vxge_mBIT(16)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR1	vxge_mBIT(17)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR2	vxge_mBIT(18)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR3	vxge_mBIT(19)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR4	vxge_mBIT(20)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR5	vxge_mBIT(21)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR6	vxge_mBIT(22)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR7	vxge_mBIT(23)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR0	vxge_mBIT(24)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR1	vxge_mBIT(25)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR0	vxge_mBIT(32)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR1	vxge_mBIT(33)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR2	vxge_mBIT(34)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR3	vxge_mBIT(35)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR4	vxge_mBIT(36)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR5	vxge_mBIT(37)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR6	vxge_mBIT(38)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR7	vxge_mBIT(39)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR0	vxge_mBIT(40)
+#define	VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR1	vxge_mBIT(41)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR0	vxge_mBIT(48)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR1	vxge_mBIT(49)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR2	vxge_mBIT(50)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR3	vxge_mBIT(51)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR4	vxge_mBIT(52)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR5	vxge_mBIT(53)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR6	vxge_mBIT(54)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR7	vxge_mBIT(55)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR0	vxge_mBIT(56)
+#define	VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR1	vxge_mBIT(57)
+/*0x053a0*/	u64	msg_err3_mask;
+/*0x053a8*/	u64	msg_err3_alarm;
+	u8	unused05600[0x05600-0x053b0];
+
+/*0x05600*/	u64	fau_gen_err_reg;
+#define	VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT0_PERMANENT_STOP	vxge_mBIT(3)
+#define	VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT1_PERMANENT_STOP	vxge_mBIT(7)
+#define	VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT2_PERMANENT_STOP	vxge_mBIT(11)
+#define	VXGE_HW_FAU_GEN_ERR_REG_FALR_AUTO_LRO_NOTIFICATION	vxge_mBIT(15)
+/*0x05608*/	u64	fau_gen_err_mask;
+/*0x05610*/	u64	fau_gen_err_alarm;
+/*0x05618*/	u64	fau_ecc_err_reg;
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_SG_ERR	vxge_mBIT(0)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_DB_ERR	vxge_mBIT(1)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_SG_ERR(val) \
+							vxge_vBIT(val, 2, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_DB_ERR(val) \
+							vxge_vBIT(val, 4, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_SG_ERR	vxge_mBIT(6)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_DB_ERR	vxge_mBIT(7)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_SG_ERR(val) \
+							vxge_vBIT(val, 8, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_DB_ERR(val) \
+							vxge_vBIT(val, 10, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_SG_ERR	vxge_mBIT(12)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_DB_ERR	vxge_mBIT(13)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_SG_ERR(val) \
+							vxge_vBIT(val, 14, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_DB_ERR(val) \
+							vxge_vBIT(val, 16, 2)
+#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_SG_ERR(val) \
+							vxge_vBIT(val, 18, 2)
+#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_DB_ERR(val) \
+							vxge_vBIT(val, 20, 2)
+#define	VXGE_HW_FAU_ECC_ERR_REG_FAUJ_FAU_FSM_ERR	vxge_mBIT(31)
+/*0x05620*/	u64	fau_ecc_err_mask;
+/*0x05628*/	u64	fau_ecc_err_alarm;
+	u8	unused05658[0x05658-0x05630];
+/*0x05658*/	u64	fau_pa_cfg;
+#define	VXGE_HW_FAU_PA_CFG_REPL_L4_COMP_CSUM	vxge_mBIT(3)
+#define	VXGE_HW_FAU_PA_CFG_REPL_L3_INCL_CF	vxge_mBIT(7)
+#define	VXGE_HW_FAU_PA_CFG_REPL_L3_COMP_CSUM	vxge_mBIT(11)
+	u8	unused05668[0x05668-0x05660];
+
+/*0x05668*/	u64	dbg_stats_fau_rx_path;
+#define	VXGE_HW_DBG_STATS_FAU_RX_PATH_RX_PERMITTED_FRMS(val) \
+						vxge_vBIT(val, 32, 32)
+	u8	unused056c0[0x056c0-0x05670];
+
+/*0x056c0*/	u64	fau_lag_cfg;
+#define VXGE_HW_FAU_LAG_CFG_COLL_ALG(val) vxge_vBIT(val, 2, 2)
+#define	VXGE_HW_FAU_LAG_CFG_INCR_RX_AGGR_STATS	vxge_mBIT(7)
+	u8	unused05800[0x05800-0x056c8];
+
+/*0x05800*/	u64	tpa_int_status;
+#define	VXGE_HW_TPA_INT_STATUS_ORP_ERR_ORP_INT	vxge_mBIT(15)
+#define	VXGE_HW_TPA_INT_STATUS_PTM_ALARM_PTM_INT	vxge_mBIT(23)
+#define	VXGE_HW_TPA_INT_STATUS_TPA_ERROR_TPA_INT	vxge_mBIT(31)
+/*0x05808*/	u64	tpa_int_mask;
+/*0x05810*/	u64	orp_err_reg;
+#define	VXGE_HW_ORP_ERR_REG_ORP_FIFO_SG_ERR	vxge_mBIT(3)
+#define	VXGE_HW_ORP_ERR_REG_ORP_FIFO_DB_ERR	vxge_mBIT(7)
+#define	VXGE_HW_ORP_ERR_REG_ORP_XFMD_FIFO_UFLOW_ERR	vxge_mBIT(11)
+#define	VXGE_HW_ORP_ERR_REG_ORP_FRM_FIFO_UFLOW_ERR	vxge_mBIT(15)
+#define	VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_FSM_ERR	vxge_mBIT(19)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_FSM_ERR	vxge_mBIT(23)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_FSM_ERR	vxge_mBIT(27)
+#define	VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_SHADOW_ERR	vxge_mBIT(31)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_SHADOW_ERR	vxge_mBIT(35)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_SHADOW_ERR	vxge_mBIT(39)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OUTFRM_SHADOW_ERR	vxge_mBIT(43)
+#define	VXGE_HW_ORP_ERR_REG_ORP_OPTPRS_SHADOW_ERR	vxge_mBIT(47)
+/*0x05818*/	u64	orp_err_mask;
+/*0x05820*/	u64	orp_err_alarm;
+/*0x05828*/	u64	ptm_alarm_reg;
+#define	VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_SYNC_ERR	vxge_mBIT(3)
+#define	VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_FIFO_ERR	vxge_mBIT(7)
+#define	VXGE_HW_PTM_ALARM_REG_XFMD_RD_FIFO_ERR	vxge_mBIT(11)
+#define	VXGE_HW_PTM_ALARM_REG_WDE2MSR_WR_FIFO_ERR	vxge_mBIT(15)
+#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_DB_ERR(val) vxge_vBIT(val, 18, 2)
+#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_SG_ERR(val) vxge_vBIT(val, 22, 2)
+/*0x05830*/	u64	ptm_alarm_mask;
+/*0x05838*/	u64	ptm_alarm_alarm;
+/*0x05840*/	u64	tpa_error_reg;
+#define	VXGE_HW_TPA_ERROR_REG_TPA_FSM_ERR_ALARM	vxge_mBIT(3)
+#define	VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_DB_ERR	vxge_mBIT(7)
+#define	VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_SG_ERR	vxge_mBIT(11)
+/*0x05848*/	u64	tpa_error_mask;
+/*0x05850*/	u64	tpa_error_alarm;
+/*0x05858*/	u64	tpa_global_cfg;
+#define	VXGE_HW_TPA_GLOBAL_CFG_SUPPORT_SNAP_AB_N	vxge_mBIT(7)
+#define	VXGE_HW_TPA_GLOBAL_CFG_ECC_ENABLE_N	vxge_mBIT(35)
+	u8	unused05868[0x05870-0x05860];
+
+/*0x05870*/	u64	ptm_ecc_cfg;
+#define	VXGE_HW_PTM_ECC_CFG_PTM_FRMM_ECC_EN_N	vxge_mBIT(3)
+/*0x05878*/	u64	ptm_phase_cfg;
+#define	VXGE_HW_PTM_PHASE_CFG_FRMM_WR_PHASE_EN	vxge_mBIT(3)
+#define	VXGE_HW_PTM_PHASE_CFG_FRMM_RD_PHASE_EN	vxge_mBIT(7)
+	u8	unused05898[0x05898-0x05880];
+
+/*0x05898*/	u64	dbg_stats_tpa_tx_path;
+#define	VXGE_HW_DBG_STATS_TPA_TX_PATH_TX_PERMITTED_FRMS(val) \
+							vxge_vBIT(val, 32, 32)
+	u8	unused05900[0x05900-0x058a0];
+
+/*0x05900*/	u64	tmac_int_status;
+#define	VXGE_HW_TMAC_INT_STATUS_TXMAC_GEN_ERR_TXMAC_GEN_INT	vxge_mBIT(3)
+#define	VXGE_HW_TMAC_INT_STATUS_TXMAC_ECC_ERR_TXMAC_ECC_INT	vxge_mBIT(7)
+/*0x05908*/	u64	tmac_int_mask;
+/*0x05910*/	u64	txmac_gen_err_reg;
+#define	VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_PERMANENT_STOP	vxge_mBIT(3)
+#define	VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_NO_VALID_VSPORT	vxge_mBIT(7)
+/*0x05918*/	u64	txmac_gen_err_mask;
+/*0x05920*/	u64	txmac_gen_err_alarm;
+/*0x05928*/	u64	txmac_ecc_err_reg;
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_SG_ERR	vxge_mBIT(3)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_DB_ERR	vxge_mBIT(7)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_SG_ERR	vxge_mBIT(11)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_DB_ERR	vxge_mBIT(15)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_SG_ERR	vxge_mBIT(19)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_DB_ERR	vxge_mBIT(23)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT0_FSM_ERR	vxge_mBIT(27)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT1_FSM_ERR	vxge_mBIT(31)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT2_FSM_ERR	vxge_mBIT(35)
+#define	VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMACJ_FSM_ERR	vxge_mBIT(39)
+/*0x05930*/	u64	txmac_ecc_err_mask;
+/*0x05938*/	u64	txmac_ecc_err_alarm;
+	u8	unused05978[0x05978-0x05940];
+
+/*0x05978*/	u64	dbg_stat_tx_any_frms;
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT0_TX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT1_TX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT2_TX_ANY_FRMS(val) \
+							vxge_vBIT(val, 16, 8)
+	u8	unused059a0[0x059a0-0x05980];
+
+/*0x059a0*/	u64	txmac_link_util_port[3];
+#define	VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_UTILIZATION(val) \
+							vxge_vBIT(val, 1, 7)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_FRAC_UTIL(val) \
+							vxge_vBIT(val, 12, 4)
+#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_SCALE_FACTOR	vxge_mBIT(23)
+/*0x059b8*/	u64	txmac_cfg0_port[3];
+#define	VXGE_HW_TXMAC_CFG0_PORT_TMAC_EN	vxge_mBIT(3)
+#define	VXGE_HW_TXMAC_CFG0_PORT_APPEND_PAD	vxge_mBIT(7)
+#define VXGE_HW_TXMAC_CFG0_PORT_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
+/*0x059d0*/	u64	txmac_cfg1_port[3];
+#define VXGE_HW_TXMAC_CFG1_PORT_AVG_IPG(val) vxge_vBIT(val, 40, 8)
+/*0x059e8*/	u64	txmac_status_port[3];
+#define	VXGE_HW_TXMAC_STATUS_PORT_TMAC_TX_FRM_SENT	vxge_mBIT(3)
+	u8	unused05a20[0x05a20-0x05a00];
+
+/*0x05a20*/	u64	lag_distrib_dest;
+#define VXGE_HW_LAG_DISTRIB_DEST_MAP_VPATH(n)	vxge_mBIT(n)
+/*0x05a28*/	u64	lag_marker_cfg;
+#define	VXGE_HW_LAG_MARKER_CFG_GEN_RCVR_EN	vxge_mBIT(3)
+#define	VXGE_HW_LAG_MARKER_CFG_RESP_EN	vxge_mBIT(7)
+#define VXGE_HW_LAG_MARKER_CFG_RESP_TIMEOUT(val) vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_LAG_MARKER_CFG_SLOW_PROTO_MRKR_MIN_INTERVAL(val) \
+							vxge_vBIT(val, 32, 16)
+#define	VXGE_HW_LAG_MARKER_CFG_THROTTLE_MRKR_RESP	vxge_mBIT(51)
+/*0x05a30*/	u64	lag_tx_cfg;
+#define	VXGE_HW_LAG_TX_CFG_INCR_TX_AGGR_STATS	vxge_mBIT(3)
+#define VXGE_HW_LAG_TX_CFG_DISTRIB_ALG_SEL(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_LAG_TX_CFG_DISTRIB_REMAP_IF_FAIL	vxge_mBIT(11)
+#define VXGE_HW_LAG_TX_CFG_COLL_MAX_DELAY(val) vxge_vBIT(val, 16, 16)
+/*0x05a38*/	u64	lag_tx_status;
+#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_EMPTIED_LINK(val) \
+							vxge_vBIT(val, 0, 8)
+#define	VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKR(val) \
+							vxge_vBIT(val, 8, 8)
+#define	VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKRRESP(val) \
+							vxge_vBIT(val, 16, 8)
+	u8	unused05d48[0x05d48-0x05a40];
+
+/*0x05d48*/	u64	srpcim_to_mrpcim_vplane_rmsg[17];
+#define	\
+VXGE_HAL_SRPCIM_TO_MRPCIM_VPLANE_RMSG_SWIF_SRPCIM_TO_MRPCIM_VPLANE_RMSG(val)\
+ vxge_vBIT(val, 0, 64)
+		u8	unused06420[0x06420-0x05dd0];
+
+/*0x06420*/	u64	mrpcim_to_srpcim_vplane_wmsg[17];
+#define	VXGE_HW_MRPCIM_TO_SRPCIM_VPLANE_WMSG_MRPCIM_TO_SRPCIM_VPLANE_WMSG(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x064a8*/	u64	mrpcim_to_srpcim_vplane_wmsg_trig[17];
+
+/*0x06530*/	u64	debug_stats0;
+#define VXGE_HW_DEBUG_STATS0_RSTDROP_MSG(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_DEBUG_STATS0_RSTDROP_CPL(val) vxge_vBIT(val, 32, 32)
+/*0x06538*/	u64	debug_stats1;
+#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT0(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT1(val) vxge_vBIT(val, 32, 32)
+/*0x06540*/	u64	debug_stats2;
+#define VXGE_HW_DEBUG_STATS2_RSTDROP_CLIENT2(val) vxge_vBIT(val, 0, 32)
+/*0x06548*/	u64	debug_stats3_vplane[17];
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_PH(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_NPH(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_CPLH(val) vxge_vBIT(val, 32, 16)
+/*0x065d0*/	u64	debug_stats4_vplane[17];
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_PD(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_NPD(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_CPLD(val) vxge_vBIT(val, 32, 16)
+
+	u8	unused07000[0x07000-0x06658];
+
+/*0x07000*/	u64	mrpcim_general_int_status;
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PIC_INT	vxge_mBIT(0)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCI_INT	vxge_mBIT(1)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RTDMA_INT	vxge_mBIT(2)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_WRDMA_INT	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMCT_INT	vxge_mBIT(4)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG1_INT	vxge_mBIT(5)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG2_INT	vxge_mBIT(6)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG3_INT	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFL_INT	vxge_mBIT(8)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFU_INT	vxge_mBIT(9)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG1_INT	vxge_mBIT(10)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG2_INT	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG3_INT	vxge_mBIT(12)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_XMAC_INT	vxge_mBIT(13)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RXMAC_INT	vxge_mBIT(14)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TMAC_INT	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBIF_INT	vxge_mBIT(16)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_FBMC_INT	vxge_mBIT(17)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBCT_INT	vxge_mBIT(18)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TPA_INT	vxge_mBIT(19)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_DRBELL_INT	vxge_mBIT(20)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_ONE_INT	vxge_mBIT(21)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_STATUS_MSG_INT	vxge_mBIT(22)
+/*0x07008*/	u64	mrpcim_general_int_mask;
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_PIC_INT	vxge_mBIT(0)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCI_INT	vxge_mBIT(1)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_RTDMA_INT	vxge_mBIT(2)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_WRDMA_INT	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMCT_INT	vxge_mBIT(4)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG1_INT	vxge_mBIT(5)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG2_INT	vxge_mBIT(6)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG3_INT	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFL_INT	vxge_mBIT(8)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFU_INT	vxge_mBIT(9)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG1_INT	vxge_mBIT(10)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG2_INT	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG3_INT	vxge_mBIT(12)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_XMAC_INT	vxge_mBIT(13)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_RXMAC_INT	vxge_mBIT(14)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_TMAC_INT	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBIF_INT	vxge_mBIT(16)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_FBMC_INT	vxge_mBIT(17)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBCT_INT	vxge_mBIT(18)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_TPA_INT	vxge_mBIT(19)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_DRBELL_INT	vxge_mBIT(20)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_ONE_INT	vxge_mBIT(21)
+#define	VXGE_HW_MRPCIM_GENERAL_INT_MASK_MSG_INT	vxge_mBIT(22)
+/*0x07010*/	u64	mrpcim_ppif_int_status;
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_INI_ERRORS_INI_INT	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_DMA_ERRORS_DMA_INT	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_TGT_ERRORS_TGT_INT	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CONFIG_ERRORS_CONFIG_INT	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_CRDT_INT	vxge_mBIT(19)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_PLL_ERRORS_PLL_INT	vxge_mBIT(27)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE0_CRD_INT_VPLANE0_INT\
+							vxge_mBIT(31)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE1_CRD_INT_VPLANE1_INT\
+							vxge_mBIT(32)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE2_CRD_INT_VPLANE2_INT\
+							vxge_mBIT(33)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE3_CRD_INT_VPLANE3_INT\
+							vxge_mBIT(34)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE4_CRD_INT_VPLANE4_INT\
+							vxge_mBIT(35)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE5_CRD_INT_VPLANE5_INT\
+							vxge_mBIT(36)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE6_CRD_INT_VPLANE6_INT\
+							vxge_mBIT(37)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE7_CRD_INT_VPLANE7_INT\
+							vxge_mBIT(38)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE8_CRD_INT_VPLANE8_INT\
+							vxge_mBIT(39)
+#define	VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE9_CRD_INT_VPLANE9_INT\
+							vxge_mBIT(40)
+#define \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE10_CRD_INT_VPLANE10_INT \
+							vxge_mBIT(41)
+#define \
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE11_CRD_INT_VPLANE11_INT \
+							vxge_mBIT(42)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE12_CRD_INT_VPLANE12_INT \
+							vxge_mBIT(43)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE13_CRD_INT_VPLANE13_INT \
+							vxge_mBIT(44)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE14_CRD_INT_VPLANE14_INT \
+							vxge_mBIT(45)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE15_CRD_INT_VPLANE15_INT \
+							vxge_mBIT(46)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE16_CRD_INT_VPLANE16_INT \
+							vxge_mBIT(47)
+#define	\
+VXGE_HW_MRPCIM_PPIF_INT_STATUS_VPATH_TO_MRPCIM_ALARM_VPATH_TO_MRPCIM_ALARM_INT \
+							vxge_mBIT(55)
+/*0x07018*/	u64	mrpcim_ppif_int_mask;
+	u8	unused07028[0x07028-0x07020];
+
+/*0x07028*/	u64	ini_errors_reg;
+#define	VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT_UNUSED_TAG	vxge_mBIT(3)
+#define	VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT	vxge_mBIT(7)
+#define	VXGE_HW_INI_ERRORS_REG_DCPL_FSM_ERR	vxge_mBIT(11)
+#define	VXGE_HW_INI_ERRORS_REG_DCPL_POISON	vxge_mBIT(12)
+#define	VXGE_HW_INI_ERRORS_REG_DCPL_UNSUPPORTED	vxge_mBIT(15)
+#define	VXGE_HW_INI_ERRORS_REG_DCPL_ABORT	vxge_mBIT(19)
+#define	VXGE_HW_INI_ERRORS_REG_INI_TLP_ABORT	vxge_mBIT(23)
+#define	VXGE_HW_INI_ERRORS_REG_INI_DLLP_ABORT	vxge_mBIT(27)
+#define	VXGE_HW_INI_ERRORS_REG_INI_ECRC_ERR	vxge_mBIT(31)
+#define	VXGE_HW_INI_ERRORS_REG_INI_BUF_DB_ERR	vxge_mBIT(35)
+#define	VXGE_HW_INI_ERRORS_REG_INI_BUF_SG_ERR	vxge_mBIT(39)
+#define	VXGE_HW_INI_ERRORS_REG_INI_DATA_OVERFLOW	vxge_mBIT(43)
+#define	VXGE_HW_INI_ERRORS_REG_INI_HDR_OVERFLOW	vxge_mBIT(47)
+#define	VXGE_HW_INI_ERRORS_REG_INI_MRD_SYS_DROP	vxge_mBIT(51)
+#define	VXGE_HW_INI_ERRORS_REG_INI_MWR_SYS_DROP	vxge_mBIT(55)
+#define	VXGE_HW_INI_ERRORS_REG_INI_MRD_CLIENT_DROP	vxge_mBIT(59)
+#define	VXGE_HW_INI_ERRORS_REG_INI_MWR_CLIENT_DROP	vxge_mBIT(63)
+/*0x07030*/	u64	ini_errors_mask;
+/*0x07038*/	u64	ini_errors_alarm;
+/*0x07040*/	u64	dma_errors_reg;
+#define	VXGE_HW_DMA_ERRORS_REG_RDARB_FSM_ERR	vxge_mBIT(3)
+#define	VXGE_HW_DMA_ERRORS_REG_WRARB_FSM_ERR	vxge_mBIT(7)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_OVERFLOW	vxge_mBIT(8)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_UNDERFLOW	vxge_mBIT(9)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_OVERFLOW	vxge_mBIT(10)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_UNDERFLOW	vxge_mBIT(11)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_OVERFLOW	vxge_mBIT(12)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_UNDERFLOW	vxge_mBIT(13)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_OVERFLOW	vxge_mBIT(14)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_UNDERFLOW	vxge_mBIT(15)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_OVERFLOW	vxge_mBIT(16)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_UNDERFLOW	vxge_mBIT(17)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_OVERFLOW	vxge_mBIT(18)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_UNDERFLOW	vxge_mBIT(19)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_OVERFLOW	vxge_mBIT(20)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_UNDERFLOW	vxge_mBIT(21)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_OVERFLOW	vxge_mBIT(22)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_UNDERFLOW	vxge_mBIT(23)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_OVERFLOW	vxge_mBIT(24)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_UNDERFLOW	vxge_mBIT(25)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_OVERFLOW	vxge_mBIT(28)
+#define	VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_UNDERFLOW	vxge_mBIT(29)
+#define	VXGE_HW_DMA_ERRORS_REG_DBLGEN_FSM_ERR	vxge_mBIT(32)
+#define	VXGE_HW_DMA_ERRORS_REG_DBLGEN_CREDIT_FSM_ERR	vxge_mBIT(33)
+#define	VXGE_HW_DMA_ERRORS_REG_DBLGEN_DMA_WRR_SM_ERR	vxge_mBIT(34)
+/*0x07048*/	u64	dma_errors_mask;
+/*0x07050*/	u64	dma_errors_alarm;
+/*0x07058*/	u64	tgt_errors_reg;
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_VENDOR_MSG	vxge_mBIT(0)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_MSG_UNLOCK	vxge_mBIT(1)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_ILLEGAL_TLP_BE	vxge_mBIT(2)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_BOOT_WRITE	vxge_mBIT(3)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_PIF_WR_CROSS_QWRANGE	vxge_mBIT(4)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_PIF_READ_CROSS_QWRANGE	vxge_mBIT(5)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_READ	vxge_mBIT(6)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_USDC_READ	vxge_mBIT(7)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_USDC_WR_CROSS_QWRANGE	vxge_mBIT(8)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_MSIX_BEYOND_RANGE	vxge_mBIT(9)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_KDFC_POISON	vxge_mBIT(10)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_USDC_POISON	vxge_mBIT(11)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_PIF_POISON	vxge_mBIT(12)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MSIX_POISON	vxge_mBIT(13)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MRIOV_POISON	vxge_mBIT(14)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_NOT_MEM_TLP	vxge_mBIT(15)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_UNKNOWN_MEM_TLP	vxge_mBIT(16)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_REQ_FSM_ERR	vxge_mBIT(17)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_CPL_FSM_ERR	vxge_mBIT(18)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_PROT_ERR	vxge_mBIT(19)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_SWIF_PROT_ERR	vxge_mBIT(20)
+#define	VXGE_HW_TGT_ERRORS_REG_TGT_MRIOV_MEM_MAP_CFG_ERR	vxge_mBIT(21)
+/*0x07060*/	u64	tgt_errors_mask;
+/*0x07068*/	u64	tgt_errors_alarm;
+/*0x07070*/	u64	config_errors_reg;
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_STOP_COND	vxge_mBIT(3)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_START_COND	vxge_mBIT(7)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_EXP_RD_CNT	vxge_mBIT(11)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_EXTRA_CYCLE	vxge_mBIT(15)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_MAIN_FSM_ERR	vxge_mBIT(19)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_REQ_COLLISION	vxge_mBIT(23)
+#define	VXGE_HW_CONFIG_ERRORS_REG_I2C_REG_FSM_ERR	vxge_mBIT(27)
+#define	VXGE_HW_CONFIG_ERRORS_REG_CFGM_I2C_TIMEOUT	vxge_mBIT(31)
+#define	VXGE_HW_CONFIG_ERRORS_REG_RIC_I2C_TIMEOUT	vxge_mBIT(35)
+#define	VXGE_HW_CONFIG_ERRORS_REG_CFGM_FSM_ERR	vxge_mBIT(39)
+#define	VXGE_HW_CONFIG_ERRORS_REG_RIC_FSM_ERR	vxge_mBIT(43)
+#define	VXGE_HW_CONFIG_ERRORS_REG_PIFM_ILLEGAL_ACCESS	vxge_mBIT(47)
+#define	VXGE_HW_CONFIG_ERRORS_REG_PIFM_TIMEOUT	vxge_mBIT(51)
+#define	VXGE_HW_CONFIG_ERRORS_REG_PIFM_FSM_ERR	vxge_mBIT(55)
+#define	VXGE_HW_CONFIG_ERRORS_REG_PIFM_TO_FSM_ERR	vxge_mBIT(59)
+#define	VXGE_HW_CONFIG_ERRORS_REG_RIC_RIC_RD_TIMEOUT	vxge_mBIT(63)
+/*0x07078*/	u64	config_errors_mask;
+/*0x07080*/	u64	config_errors_alarm;
+	u8	unused07090[0x07090-0x07088];
+
+/*0x07090*/	u64	crdt_errors_reg;
+#define	VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_FSM_ERR	vxge_mBIT(11)
+#define	VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_INTCTL_ILLEGAL_CRD_DEAL \
+							vxge_mBIT(15)
+#define	VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PDA_ILLEGAL_CRD_DEAL	vxge_mBIT(19)
+#define	VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PCI_MSG_ILLEGAL_CRD_DEAL \
+							vxge_mBIT(23)
+#define	VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_FSM_ERR	vxge_mBIT(35)
+#define	VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_RDA_ILLEGAL_CRD_DEAL	vxge_mBIT(39)
+#define	VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_PDA_ILLEGAL_CRD_DEAL	vxge_mBIT(43)
+#define	VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_DBLGEN_ILLEGAL_CRD_DEAL \
+							vxge_mBIT(47)
+/*0x07098*/	u64	crdt_errors_mask;
+/*0x070a0*/	u64	crdt_errors_alarm;
+	u8	unused070b0[0x070b0-0x070a8];
+
+/*0x070b0*/	u64	mrpcim_general_errors_reg;
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_STATSB_FSM_ERR	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XGEN_FSM_ERR	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XMEM_FSM_ERR	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_KDFCCTL_FSM_ERR	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_MRIOVCTL_FSM_ERR	vxge_mBIT(19)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_FLSH_ERR	vxge_mBIT(23)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_ACK_ERR	vxge_mBIT(27)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_CHKSUM_ERR	vxge_mBIT(31)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INI_SERR_DET	vxge_mBIT(35)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSIX_FSM_ERR	vxge_mBIT(39)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSI_OVERFLOW	vxge_mBIT(43)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_PCI_NOT_FLUSH_DURING_SW_RESET \
+							vxge_mBIT(47)
+#define	VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_SW_RESET_FSM_ERR	vxge_mBIT(51)
+/*0x070b8*/	u64	mrpcim_general_errors_mask;
+/*0x070c0*/	u64	mrpcim_general_errors_alarm;
+	u8	unused070d0[0x070d0-0x070c8];
+
+/*0x070d0*/	u64	pll_errors_reg;
+#define	VXGE_HW_PLL_ERRORS_REG_CORE_CMG_PLL_OOL	vxge_mBIT(3)
+#define	VXGE_HW_PLL_ERRORS_REG_CORE_FB_PLL_OOL	vxge_mBIT(7)
+#define	VXGE_HW_PLL_ERRORS_REG_CORE_X_PLL_OOL	vxge_mBIT(11)
+/*0x070d8*/	u64	pll_errors_mask;
+/*0x070e0*/	u64	pll_errors_alarm;
+/*0x070e8*/	u64	srpcim_to_mrpcim_alarm_reg;
+#define	VXGE_HW_SRPCIM_TO_MRPCIM_ALARM_REG_PPIF_SRPCIM_TO_MRPCIM_ALARM(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x070f0*/	u64	srpcim_to_mrpcim_alarm_mask;
+/*0x070f8*/	u64	srpcim_to_mrpcim_alarm_alarm;
+/*0x07100*/	u64	vpath_to_mrpcim_alarm_reg;
+#define	VXGE_HW_VPATH_TO_MRPCIM_ALARM_REG_PPIF_VPATH_TO_MRPCIM_ALARM(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x07108*/	u64	vpath_to_mrpcim_alarm_mask;
+/*0x07110*/	u64	vpath_to_mrpcim_alarm_alarm;
+	u8	unused07128[0x07128-0x07118];
+
+/*0x07128*/	u64	crdt_errors_vplane_reg[17];
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_CONSUME_CRDT_ERR \
+							vxge_mBIT(3)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_CONSUME_CRDT_ERR \
+							vxge_mBIT(7)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_RETURN_CRDT_ERR \
+							vxge_mBIT(11)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_RETURN_CRDT_ERR \
+							vxge_mBIT(15)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_CONSUME_CRDT_ERR \
+							vxge_mBIT(19)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_RETURN_CRDT_ERR \
+							vxge_mBIT(23)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_CONSUME_TAG_ERR \
+							vxge_mBIT(27)
+#define	VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_RETURN_TAG_ERR \
+							vxge_mBIT(31)
+/*0x07130*/	u64	crdt_errors_vplane_mask[17];
+/*0x07138*/	u64	crdt_errors_vplane_alarm[17];
+	u8	unused072f0[0x072f0-0x072c0];
+
+/*0x072f0*/	u64	mrpcim_rst_in_prog;
+#define	VXGE_HW_MRPCIM_RST_IN_PROG_MRPCIM_RST_IN_PROG	vxge_mBIT(7)
+/*0x072f8*/	u64	mrpcim_reg_modified;
+#define	VXGE_HW_MRPCIM_REG_MODIFIED_MRPCIM_REG_MODIFIED	vxge_mBIT(7)
+
+	u8	unused07378[0x07378-0x07300];
+
+/*0x07378*/	u64	write_arb_pending;
+#define	VXGE_HW_WRITE_ARB_PENDING_WRARB_WRDMA	vxge_mBIT(3)
+#define	VXGE_HW_WRITE_ARB_PENDING_WRARB_RTDMA	vxge_mBIT(7)
+#define	VXGE_HW_WRITE_ARB_PENDING_WRARB_MSG	vxge_mBIT(11)
+#define	VXGE_HW_WRITE_ARB_PENDING_WRARB_STATSB	vxge_mBIT(15)
+#define	VXGE_HW_WRITE_ARB_PENDING_WRARB_INTCTL	vxge_mBIT(19)
+/*0x07380*/	u64	read_arb_pending;
+#define	VXGE_HW_READ_ARB_PENDING_RDARB_WRDMA	vxge_mBIT(3)
+#define	VXGE_HW_READ_ARB_PENDING_RDARB_RTDMA	vxge_mBIT(7)
+#define	VXGE_HW_READ_ARB_PENDING_RDARB_DBLGEN	vxge_mBIT(11)
+/*0x07388*/	u64	dmaif_dmadbl_pending;
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_WR	vxge_mBIT(0)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_RD	vxge_mBIT(1)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_WR	vxge_mBIT(2)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_RD	vxge_mBIT(3)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_MSG_WR	vxge_mBIT(4)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_STATS_WR	vxge_mBIT(5)
+#define	VXGE_HW_DMAIF_DMADBL_PENDING_DBLGEN_IN_PROG(val) \
+							vxge_vBIT(val, 13, 51)
+/*0x07390*/	u64	wrcrdtarb_status0_vplane[17];
+#define	VXGE_HW_WRCRDTARB_STATUS0_VPLANE_WRCRDTARB_ABS_AVAIL_P_H(val) \
+							vxge_vBIT(val, 0, 8)
+/*0x07418*/	u64	wrcrdtarb_status1_vplane[17];
+#define	VXGE_HW_WRCRDTARB_STATUS1_VPLANE_WRCRDTARB_ABS_AVAIL_P_D(val) \
+							vxge_vBIT(val, 4, 12)
+	u8	unused07500[0x07500-0x074a0];
+
+/*0x07500*/	u64	mrpcim_general_cfg1;
+#define	VXGE_HW_MRPCIM_GENERAL_CFG1_CLEAR_SERR	vxge_mBIT(7)
+/*0x07508*/	u64	mrpcim_general_cfg2;
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_WR_TD	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_RD_TD	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_CPL_TD	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MWR	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MRD	vxge_mBIT(19)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_IGNORE_VPATH_RST_FOR_MSIX	vxge_mBIT(23)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_FLASH_READ_MSB	vxge_mBIT(27)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_HOST_PIPELINE_WR	vxge_mBIT(31)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_ENABLE	vxge_mBIT(43)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_MAP_TO_VPATH(val) \
+							vxge_vBIT(val, 47, 5)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_EN_BLOCK_MSIX_DUE_TO_SERR	vxge_mBIT(55)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_FORCE_SENDING_INTA	vxge_mBIT(59)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_SWIF_PROT_ON_RDS	vxge_mBIT(63)
+/*0x07510*/	u64	mrpcim_general_cfg3;
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_PROTECTION_CA_OR_UNSUPN	vxge_mBIT(0)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_ILLEGAL_RD_CA_OR_UNSUPN	vxge_mBIT(3)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BYTE_SWAPEN	vxge_mBIT(7)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BIT_FLIPEN	vxge_mBIT(11)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BYTE_SWAPEN	vxge_mBIT(15)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BIT_FLIPEN	vxge_mBIT(19)
+#define VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MAX_MVFS(val) vxge_vBIT(val, 20, 16)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MVF_TBL_SIZE(val) \
+							vxge_vBIT(val, 36, 16)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_PF0_SW_RESET_EN	vxge_mBIT(55)
+#define VXGE_HW_MRPCIM_GENERAL_CFG3_REG_MODIFIED_CFG(val) vxge_vBIT(val, 56, 2)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_CPL_ECC_ENABLE_N	vxge_mBIT(59)
+#define	VXGE_HW_MRPCIM_GENERAL_CFG3_BYPASS_DAISY_CHAIN	vxge_mBIT(63)
+/*0x07518*/	u64	mrpcim_stats_start_host_addr;
+#define	VXGE_HW_MRPCIM_STATS_START_HOST_ADDR_MRPCIM_STATS_START_HOST_ADDR(val)\
+							vxge_vBIT(val, 0, 57)
+
+	u8	unused07950[0x07950-0x07520];
+
+/*0x07950*/	u64	rdcrdtarb_cfg0;
+#define VXGE_HW_RDCRDTARB_CFG0_RDA_MAX_OUTSTANDING_RDS(val) \
+						vxge_vBIT(val, 18, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_PDA_MAX_OUTSTANDING_RDS(val) \
+						vxge_vBIT(val, 26, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_DBLGEN_MAX_OUTSTANDING_RDS(val) \
+						vxge_vBIT(val, 34, 6)
+#define VXGE_HW_RDCRDTARB_CFG0_WAIT_CNT(val) vxge_vBIT(val, 48, 4)
+#define VXGE_HW_RDCRDTARB_CFG0_MAX_OUTSTANDING_RDS(val) vxge_vBIT(val, 54, 6)
+#define	VXGE_HW_RDCRDTARB_CFG0_EN_XON	vxge_mBIT(63)
+	u8	unused07be8[0x07be8-0x07958];
+
+/*0x07be8*/	u64	bf_sw_reset;
+#define VXGE_HW_BF_SW_RESET_BF_SW_RESET(val) vxge_vBIT(val, 0, 8)
+/*0x07bf0*/	u64	sw_reset_status;
+#define	VXGE_HW_SW_RESET_STATUS_RESET_CMPLT	vxge_mBIT(7)
+#define	VXGE_HW_SW_RESET_STATUS_INIT_CMPLT	vxge_mBIT(15)
+	u8	unused07c20[0x07c20-0x07bf8];
+
+/* 0x07c20 */   u64     sw_reset_cfg1;
+#define VXGE_HW_SW_RESET_CFG1_TYPE	vxge_mBIT(0)
+#define VXGE_HW_SW_RESET_CFG1_WAIT_TIME_FOR_FLUSH_PCI(val) \
+						vxge_vBIT(val, 7, 25)
+#define VXGE_HW_SW_RESET_CFG1_SOPR_ASSERT_TIME(val)	vxge_vBIT(val, 32, 4)
+#define VXGE_HW_SW_RESET_CFG1_WAIT_TIME_AFTER_RESET(val) \
+						vxge_vBIT(val, 38, 25)
+	u8	unused07d30[0x07d30-0x07c28];
+
+/*0x07d30*/	u64	mrpcim_debug_stats0;
+#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_WR_DROP(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_RD_DROP(val) vxge_vBIT(val, 32, 32)
+/*0x07d38*/	u64	mrpcim_debug_stats1_vplane[17];
+#define	VXGE_HW_MRPCIM_DEBUG_STATS1_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x07dc0*/	u64	mrpcim_debug_stats2_vplane[17];
+#define	VXGE_HW_MRPCIM_DEBUG_STATS2_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x07e48*/	u64	mrpcim_debug_stats3_vplane[17];
+#define	VXGE_HW_MRPCIM_DEBUG_STATS3_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x07ed0*/	u64	mrpcim_debug_stats4;
+#define VXGE_HW_MRPCIM_DEBUG_STATS4_INI_WR_VPIN_DROP(val) vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_MRPCIM_DEBUG_STATS4_INI_RD_VPIN_DROP(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x07ed8*/	u64	genstats_count01;
+#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT1(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT0(val) vxge_vBIT(val, 32, 32)
+/*0x07ee0*/	u64	genstats_count23;
+#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT3(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT2(val) vxge_vBIT(val, 32, 32)
+/*0x07ee8*/	u64	genstats_count4;
+#define VXGE_HW_GENSTATS_COUNT4_GENSTATS_COUNT4(val) vxge_vBIT(val, 32, 32)
+/*0x07ef0*/	u64	genstats_count5;
+#define VXGE_HW_GENSTATS_COUNT5_GENSTATS_COUNT5(val) vxge_vBIT(val, 32, 32)
+
+	u8	unused07f08[0x07f08-0x07ef8];
+
+/*0x07f08*/	u64	genstats_cfg[6];
+#define VXGE_HW_GENSTATS_CFG_DTYPE_SEL(val) vxge_vBIT(val, 3, 5)
+#define VXGE_HW_GENSTATS_CFG_CLIENT_NO_SEL(val) vxge_vBIT(val, 9, 3)
+#define VXGE_HW_GENSTATS_CFG_WR_RD_CPL_SEL(val) vxge_vBIT(val, 14, 2)
+#define VXGE_HW_GENSTATS_CFG_VPATH_SEL(val) vxge_vBIT(val, 31, 17)
+/*0x07f38*/	u64	genstat_64bit_cfg;
+#define	VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS0	vxge_mBIT(3)
+#define	VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS2	vxge_mBIT(7)
+	u8	unused08000[0x08000-0x07f40];
+/*0x08000*/	u64	gcmg3_int_status;
+#define	VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR0_GSTC0_INT	vxge_mBIT(0)
+#define	VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR1_GSTC1_INT	vxge_mBIT(1)
+#define	VXGE_HW_GCMG3_INT_STATUS_GH2L_ERR0_GH2L0_INT	vxge_mBIT(2)
+#define	VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR_GH2L1_INT	vxge_mBIT(3)
+#define	VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR2_GH2L2_INT	vxge_mBIT(4)
+#define	VXGE_HW_GCMG3_INT_STATUS_GH2L_SMERR0_GH2L3_INT	vxge_mBIT(5)
+#define	VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR3_GH2L4_INT	vxge_mBIT(6)
+/*0x08008*/	u64	gcmg3_int_mask;
+	u8	unused09000[0x09000-0x8010];
+
+/*0x09000*/	u64	g3ifcmd_fb_int_status;
+#define	VXGE_HW_G3IFCMD_FB_INT_STATUS_ERR_G3IF_INT	vxge_mBIT(0)
+/*0x09008*/	u64	g3ifcmd_fb_int_mask;
+/*0x09010*/	u64	g3ifcmd_fb_err_reg;
+#define	VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_CK_DLL_LOCK	vxge_mBIT(6)
+#define	VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_SM_ERR	vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+						vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_IOCAL_FAULT	vxge_mBIT(55)
+/*0x09018*/	u64	g3ifcmd_fb_err_mask;
+/*0x09020*/	u64	g3ifcmd_fb_err_alarm;
+
+	u8	unused09400[0x09400-0x09028];
+
+/*0x09400*/	u64	g3ifcmd_cmu_int_status;
+#define	VXGE_HW_G3IFCMD_CMU_INT_STATUS_ERR_G3IF_INT	vxge_mBIT(0)
+/*0x09408*/	u64	g3ifcmd_cmu_int_mask;
+/*0x09410*/	u64	g3ifcmd_cmu_err_reg;
+#define	VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_CK_DLL_LOCK	vxge_mBIT(6)
+#define	VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_SM_ERR	vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+							vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_IOCAL_FAULT	vxge_mBIT(55)
+/*0x09418*/	u64	g3ifcmd_cmu_err_mask;
+/*0x09420*/	u64	g3ifcmd_cmu_err_alarm;
+
+	u8	unused09800[0x09800-0x09428];
+
+/*0x09800*/	u64	g3ifcmd_cml_int_status;
+#define	VXGE_HW_G3IFCMD_CML_INT_STATUS_ERR_G3IF_INT	vxge_mBIT(0)
+/*0x09808*/	u64	g3ifcmd_cml_int_mask;
+/*0x09810*/	u64	g3ifcmd_cml_err_reg;
+#define	VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_CK_DLL_LOCK	vxge_mBIT(6)
+#define	VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_SM_ERR	vxge_mBIT(7)
+#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
+						vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_IOCAL_FAULT	vxge_mBIT(55)
+/*0x09818*/	u64	g3ifcmd_cml_err_mask;
+/*0x09820*/	u64	g3ifcmd_cml_err_alarm;
+	u8	unused09b00[0x09b00-0x09828];
+
+/*0x09b00*/	u64	vpath_to_vplane_map[17];
+#define VXGE_HW_VPATH_TO_VPLANE_MAP_VPATH_TO_VPLANE_MAP(val) \
+							vxge_vBIT(val, 3, 5)
+	u8	unused09c30[0x09c30-0x09b88];
+
+/*0x09c30*/	u64	xgxs_cfg_port[2];
+#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_LOS(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_VALID(val) vxge_vBIT(val, 20, 4)
+#define	VXGE_HW_XGXS_CFG_PORT_SEL_INFO_0	vxge_mBIT(27)
+#define VXGE_HW_XGXS_CFG_PORT_SEL_INFO_1(val) vxge_vBIT(val, 29, 3)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE0_SKEW(val) vxge_vBIT(val, 32, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE1_SKEW(val) vxge_vBIT(val, 36, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE2_SKEW(val) vxge_vBIT(val, 40, 4)
+#define VXGE_HW_XGXS_CFG_PORT_TX_LANE3_SKEW(val) vxge_vBIT(val, 44, 4)
+/*0x09c40*/	u64	xgxs_rxber_cfg_port[2];
+#define VXGE_HW_XGXS_RXBER_CFG_PORT_INTERVAL_DUR(val) vxge_vBIT(val, 0, 4)
+#define	VXGE_HW_XGXS_RXBER_CFG_PORT_RXGXS_INTERVAL_CNT(val) \
+							vxge_vBIT(val, 16, 48)
+/*0x09c50*/	u64	xgxs_rxber_status_port[2];
+#define	VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_A_ERR_CNT(val)	\
+							vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_B_ERR_CNT(val)	\
+							vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_C_ERR_CNT(val)	\
+							vxge_vBIT(val, 32, 16)
+#define	VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_D_ERR_CNT(val)	\
+							vxge_vBIT(val, 48, 16)
+/*0x09c60*/	u64	xgxs_status_port[2];
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_TX_ACTIVITY(val) vxge_vBIT(val, 0, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_RX_ACTIVITY(val) vxge_vBIT(val, 4, 4)
+#define	VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_FIFO_ERR	BIT(11)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_BYTE_SYNC_LOST(val) \
+							vxge_vBIT(val, 12, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_ERR(val) vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_ALIGNMENT_ERR	vxge_mBIT(23)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_DEC_ERR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_INS_REQ(val) \
+							vxge_vBIT(val, 32, 4)
+#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_DEL_REQ(val) \
+							vxge_vBIT(val, 36, 4)
+/*0x09c70*/	u64	xgxs_pma_reset_port[2];
+#define VXGE_HW_XGXS_PMA_RESET_PORT_SERDES_RESET(val) vxge_vBIT(val, 0, 8)
+	u8	unused09c90[0x09c90-0x09c80];
+
+/*0x09c90*/	u64	xgxs_static_cfg_port[2];
+#define	VXGE_HW_XGXS_STATIC_CFG_PORT_FW_CTRL_SERDES	vxge_mBIT(3)
+	u8	unused09d40[0x09d40-0x09ca0];
+
+/*0x09d40*/	u64	xgxs_info_port[2];
+#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_0(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_1(val) vxge_vBIT(val, 32, 32)
+/*0x09d50*/	u64	ratemgmt_cfg_port[2];
+#define VXGE_HW_RATEMGMT_CFG_PORT_MODE(val) vxge_vBIT(val, 2, 2)
+#define	VXGE_HW_RATEMGMT_CFG_PORT_RATE	vxge_mBIT(7)
+#define	VXGE_HW_RATEMGMT_CFG_PORT_FIXED_USE_FSM	vxge_mBIT(11)
+#define	VXGE_HW_RATEMGMT_CFG_PORT_ANTP_USE_FSM	vxge_mBIT(15)
+#define	VXGE_HW_RATEMGMT_CFG_PORT_ANBE_USE_FSM	vxge_mBIT(19)
+/*0x09d60*/	u64	ratemgmt_status_port[2];
+#define	VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_COMPLETE	vxge_mBIT(3)
+#define	VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_RATE	vxge_mBIT(7)
+#define	VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_MAC_MATCHES_PHY	vxge_mBIT(11)
+	u8	unused09d80[0x09d80-0x09d70];
+
+/*0x09d80*/	u64	ratemgmt_fixed_cfg_port[2];
+#define	VXGE_HW_RATEMGMT_FIXED_CFG_PORT_RESTART	vxge_mBIT(7)
+/*0x09d90*/	u64	ratemgmt_antp_cfg_port[2];
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_RESTART	vxge_mBIT(7)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_PREAMBLE_EXT_PHY	vxge_mBIT(11)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_ACT_SEL	vxge_mBIT(15)
+#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_RETRY_PHY_QUERY(val) \
+							vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_WAIT_MDIO_RESPONSE(val) \
+							vxge_vBIT(val, 20, 4)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_LDOWN_REAUTO_RESPONSE(val) \
+							vxge_vBIT(val, 24, 4)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_10G	vxge_mBIT(31)
+#define	VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_1G	vxge_mBIT(35)
+/*0x09da0*/	u64	ratemgmt_anbe_cfg_port[2];
+#define	VXGE_HW_RATEMGMT_ANBE_CFG_PORT_RESTART	vxge_mBIT(7)
+#define	VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_10G_KX4_ENABLE \
+								vxge_mBIT(11)
+#define	VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_1G_KX_ENABLE \
+								vxge_mBIT(15)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_10G_KX4(val) vxge_vBIT(val, 16, 4)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_1G_KX(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_DME_EXCHANGE(val) vxge_vBIT(val, 24, 4)
+#define	VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_10G_KX4	vxge_mBIT(31)
+#define	VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_1G_KX	vxge_mBIT(35)
+/*0x09db0*/	u64	anbe_cfg_port[2];
+#define VXGE_HW_ANBE_CFG_PORT_RESET_CFG_REGS(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_ANBE_CFG_PORT_ALIGN_10G_KX4_OVERRIDE(val) vxge_vBIT(val, 10, 2)
+#define VXGE_HW_ANBE_CFG_PORT_SYNC_1G_KX_OVERRIDE(val) vxge_vBIT(val, 14, 2)
+/*0x09dc0*/	u64	anbe_mgr_ctrl_port[2];
+#define	VXGE_HW_ANBE_MGR_CTRL_PORT_WE	vxge_mBIT(3)
+#define	VXGE_HW_ANBE_MGR_CTRL_PORT_STROBE	vxge_mBIT(7)
+#define VXGE_HW_ANBE_MGR_CTRL_PORT_ADDR(val) vxge_vBIT(val, 15, 9)
+#define VXGE_HW_ANBE_MGR_CTRL_PORT_DATA(val) vxge_vBIT(val, 32, 32)
+	u8	unused09de0[0x09de0-0x09dd0];
+
+/*0x09de0*/	u64	anbe_fw_mstr_port[2];
+#define	VXGE_HW_ANBE_FW_MSTR_PORT_CONNECT_BEAN_TO_SERDES	vxge_mBIT(3)
+#define	VXGE_HW_ANBE_FW_MSTR_PORT_TX_ZEROES_TO_SERDES	vxge_mBIT(7)
+/*0x09df0*/	u64	anbe_hwfsm_gen_status_port[2];
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_PD \
+							vxge_mBIT(3)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_DME \
+							vxge_mBIT(7)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_PD \
+							vxge_mBIT(11)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_DME \
+							vxge_mBIT(15)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANBEFSM_STATE(val)	\
+							vxge_vBIT(val, 18, 6)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_NEXT_PAGE_RECEIVED \
+							vxge_mBIT(27)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_BASE_PAGE_RECEIVED \
+							vxge_mBIT(35)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_AUTONEG_COMPLETE \
+							vxge_mBIT(39)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NP_BEFORE_BP \
+							vxge_mBIT(43)
+#define	\
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_BP \
+							vxge_mBIT(47)
+#define	\
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_NP \
+vxge_mBIT(51)
+#define	\
+VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MODE_WHEN_AN_COMPLETE \
+							vxge_mBIT(55)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_BP(val) \
+							vxge_vBIT(val, 56, 4)
+#define	VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_NP(val) \
+							vxge_vBIT(val, 60, 4)
+/*0x09e00*/	u64	anbe_hwfsm_bp_status_port[2];
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ENABLE \
+							vxge_mBIT(32)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ABILITY \
+							vxge_mBIT(33)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KR_CAPABLE \
+							vxge_mBIT(40)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KX4_CAPABLE \
+							vxge_mBIT(41)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_1G_KX_CAPABLE \
+							vxge_mBIT(42)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_TX_NONCE(val)	\
+							vxge_vBIT(val, 43, 5)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP	vxge_mBIT(48)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK	vxge_mBIT(49)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_REMOTE_FAULT \
+							vxge_mBIT(50)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ASM_DIR	vxge_mBIT(51)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_PAUSE	vxge_mBIT(53)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ECHOED_NONCE(val) \
+							vxge_vBIT(val, 54, 5)
+#define	VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x09e10*/	u64	anbe_hwfsm_np_status_port[2];
+#define	VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_47_TO_32(val) \
+							vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_31_TO_0(val) \
+							vxge_vBIT(val, 32, 32)
+	u8	unused09e30[0x09e30-0x09e20];
+
+/*0x09e30*/	u64	antp_gen_cfg_port[2];
+/*0x09e40*/	u64	antp_hwfsm_gen_status_port[2];
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G	vxge_mBIT(3)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G	vxge_mBIT(7)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANTPFSM_STATE(val)	\
+							vxge_vBIT(val, 10, 6)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_AUTONEG_COMPLETE \
+								vxge_mBIT(23)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_LP_XNP \
+							vxge_mBIT(27)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_GOT_LP_XNP	vxge_mBIT(31)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MESSAGE_CODE \
+							vxge_mBIT(35)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_HCD \
+							vxge_mBIT(43)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_FOUND_HCD	vxge_mBIT(47)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_INVALID_RATE \
+							vxge_mBIT(51)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_VALID_RATE	vxge_mBIT(55)
+#define	VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_PERSISTENT_LDOWN \
+							vxge_mBIT(59)
+/*0x09e50*/	u64	antp_hwfsm_bp_status_port[2];
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP	vxge_mBIT(0)
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK	vxge_mBIT(1)
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_RF	vxge_mBIT(2)
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_XNP	vxge_mBIT(3)
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ABILITY_FIELD(val) \
+							vxge_vBIT(val, 4, 7)
+#define	VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
+							vxge_vBIT(val, 11, 5)
+/*0x09e60*/	u64	antp_hwfsm_xnp_status_port[2];
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_NP	vxge_mBIT(0)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK	vxge_mBIT(1)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MP	vxge_mBIT(2)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK2	vxge_mBIT(3)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_TOGGLE	vxge_mBIT(4)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MESSAGE_CODE(val) \
+							vxge_vBIT(val, 5, 11)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD1(val) \
+							vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD2(val) \
+							vxge_vBIT(val, 32, 16)
+/*0x09e70*/	u64	mdio_mgr_access_port[2];
+#define	VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_ONE	BIT(3)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_OP_TYPE(val) vxge_vBIT(val, 5, 3)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DEVAD(val) vxge_vBIT(val, 11, 5)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ADDR(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DATA(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ST_PATTERN(val) vxge_vBIT(val, 49, 2)
+#define	VXGE_HW_MDIO_MGR_ACCESS_PORT_PREAMBLE	vxge_mBIT(51)
+#define VXGE_HW_MDIO_MGR_ACCESS_PORT_PRTAD(val) vxge_vBIT(val, 55, 5)
+#define	VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_TWO	vxge_mBIT(63)
+	u8	unused0a200[0x0a200-0x09e80];
+/*0x0a200*/	u64	xmac_vsport_choices_vh[17];
+#define VXGE_HW_XMAC_VSPORT_CHOICES_VH_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
+	u8	unused0a400[0x0a400-0x0a288];
+
+/*0x0a400*/	u64	rx_thresh_cfg_vp[17];
+#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_0(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_1(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_2(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_3(val) vxge_vBIT(val, 40, 8)
+	u8	unused0ac90[0x0ac90-0x0a488];
+} __attribute((packed));
+
+/*VXGE_HW_SRPCIM_REGS_H*/
+struct vxge_hw_srpcim_reg {
+
+/*0x00000*/	u64	tim_mr2sr_resource_assignment_vh;
+#define	VXGE_HW_TIM_MR2SR_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) \
+							vxge_vBIT(val, 0, 32)
+	u8	unused00100[0x00100-0x00008];
+
+/*0x00100*/	u64	srpcim_pcipif_int_status;
+#define	VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_MRPCIM_MSG_MRPCIM_MSG_INT	BIT(3)
+#define	VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_VPATH_MSG_VPATH_MSG_INT	BIT(7)
+#define	VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_SRPCIM_SPARE_R1_SRPCIM_SPARE_R1_INT \
+									BIT(11)
+/*0x00108*/	u64	srpcim_pcipif_int_mask;
+/*0x00110*/	u64	mrpcim_msg_reg;
+#define	VXGE_HW_MRPCIM_MSG_REG_SWIF_MRPCIM_TO_SRPCIM_RMSG_INT	BIT(3)
+/*0x00118*/	u64	mrpcim_msg_mask;
+/*0x00120*/	u64	mrpcim_msg_alarm;
+/*0x00128*/	u64	vpath_msg_reg;
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH0_TO_SRPCIM_RMSG_INT	BIT(0)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH1_TO_SRPCIM_RMSG_INT	BIT(1)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH2_TO_SRPCIM_RMSG_INT	BIT(2)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH3_TO_SRPCIM_RMSG_INT	BIT(3)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH4_TO_SRPCIM_RMSG_INT	BIT(4)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH5_TO_SRPCIM_RMSG_INT	BIT(5)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH6_TO_SRPCIM_RMSG_INT	BIT(6)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH7_TO_SRPCIM_RMSG_INT	BIT(7)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH8_TO_SRPCIM_RMSG_INT	BIT(8)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH9_TO_SRPCIM_RMSG_INT	BIT(9)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH10_TO_SRPCIM_RMSG_INT	BIT(10)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH11_TO_SRPCIM_RMSG_INT	BIT(11)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH12_TO_SRPCIM_RMSG_INT	BIT(12)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH13_TO_SRPCIM_RMSG_INT	BIT(13)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH14_TO_SRPCIM_RMSG_INT	BIT(14)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH15_TO_SRPCIM_RMSG_INT	BIT(15)
+#define	VXGE_HW_VPATH_MSG_REG_SWIF_VPATH16_TO_SRPCIM_RMSG_INT	BIT(16)
+/*0x00130*/	u64	vpath_msg_mask;
+/*0x00138*/	u64	vpath_msg_alarm;
+	u8	unused00160[0x00160-0x00140];
+
+/*0x00160*/	u64	srpcim_to_mrpcim_wmsg;
+#define	VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_SRPCIM_TO_MRPCIM_WMSG(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x00168*/	u64	srpcim_to_mrpcim_wmsg_trig;
+#define	VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_TRIG_SRPCIM_TO_MRPCIM_WMSG_TRIG	BIT(0)
+/*0x00170*/	u64	mrpcim_to_srpcim_rmsg;
+#define	VXGE_HW_MRPCIM_TO_SRPCIM_RMSG_SWIF_MRPCIM_TO_SRPCIM_RMSG(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x00178*/	u64	vpath_to_srpcim_rmsg_sel;
+#define	VXGE_HW_VPATH_TO_SRPCIM_RMSG_SEL_VPATH_TO_SRPCIM_RMSG_SEL(val) \
+							vxge_vBIT(val, 0, 5)
+/*0x00180*/	u64	vpath_to_srpcim_rmsg;
+#define	VXGE_HW_VPATH_TO_SRPCIM_RMSG_SWIF_VPATH_TO_SRPCIM_RMSG(val) \
+							vxge_vBIT(val, 0, 64)
+	u8	unused00200[0x00200-0x00188];
+
+/*0x00200*/	u64	srpcim_general_int_status;
+#define	VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PIC_INT	BIT(0)
+#define	VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PCI_INT	BIT(3)
+#define	VXGE_HW_SRPCIM_GENERAL_INT_STATUS_XMAC_INT	BIT(7)
+	u8	unused00210[0x00210-0x00208];
+
+/*0x00210*/	u64	srpcim_general_int_mask;
+#define	VXGE_HW_SRPCIM_GENERAL_INT_MASK_PIC_INT	BIT(0)
+#define	VXGE_HW_SRPCIM_GENERAL_INT_MASK_PCI_INT	BIT(3)
+#define	VXGE_HW_SRPCIM_GENERAL_INT_MASK_XMAC_INT	BIT(7)
+	u8	unused00220[0x00220-0x00218];
+
+/*0x00220*/	u64	srpcim_ppif_int_status;
+
+/*0x00228*/	u64	srpcim_ppif_int_mask;
+/*0x00230*/	u64	srpcim_gen_errors_reg;
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_STATUS_ERR	BIT(3)
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_UNCOR_ERR	BIT(7)
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_COR_ERR	BIT(11)
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_INTCTRL_SCHED_INT	BIT(15)
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_INI_SERR_DET	BIT(19)
+#define	VXGE_HW_SRPCIM_GEN_ERRORS_REG_TGT_PF_ILLEGAL_ACCESS	BIT(23)
+/*0x00238*/	u64	srpcim_gen_errors_mask;
+/*0x00240*/	u64	srpcim_gen_errors_alarm;
+/*0x00248*/	u64	mrpcim_to_srpcim_alarm_reg;
+#define	VXGE_HW_MRPCIM_TO_SRPCIM_ALARM_REG_PPIF_MRPCIM_TO_SRPCIM_ALARM	BIT(3)
+/*0x00250*/	u64	mrpcim_to_srpcim_alarm_mask;
+/*0x00258*/	u64	mrpcim_to_srpcim_alarm_alarm;
+/*0x00260*/	u64	vpath_to_srpcim_alarm_reg;
+
+/*0x00268*/	u64	vpath_to_srpcim_alarm_mask;
+/*0x00270*/	u64	vpath_to_srpcim_alarm_alarm;
+	u8	unused00280[0x00280-0x00278];
+
+/*0x00280*/	u64	pf_sw_reset;
+#define VXGE_HW_PF_SW_RESET_PF_SW_RESET(val) vxge_vBIT(val, 0, 8)
+/*0x00288*/	u64	srpcim_general_cfg1;
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BYTE_SWAPEN	BIT(19)
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BIT_FLIPEN	BIT(23)
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_SWAPEN	BIT(27)
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_FLIPEN	BIT(31)
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_SWAPEN	BIT(35)
+#define	VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_FLIPEN	BIT(39)
+/*0x00290*/	u64	srpcim_interrupt_cfg1;
+#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_TRAFFIC_CLASS(val) vxge_vBIT(val, 9, 3)
+	u8	unused002a8[0x002a8-0x00298];
+
+/*0x002a8*/	u64	srpcim_clear_msix_mask;
+#define	VXGE_HW_SRPCIM_CLEAR_MSIX_MASK_SRPCIM_CLEAR_MSIX_MASK	BIT(0)
+/*0x002b0*/	u64	srpcim_set_msix_mask;
+#define	VXGE_HW_SRPCIM_SET_MSIX_MASK_SRPCIM_SET_MSIX_MASK	BIT(0)
+/*0x002b8*/	u64	srpcim_clr_msix_one_shot;
+#define	VXGE_HW_SRPCIM_CLR_MSIX_ONE_SHOT_SRPCIM_CLR_MSIX_ONE_SHOT	BIT(0)
+/*0x002c0*/	u64	srpcim_rst_in_prog;
+#define	VXGE_HW_SRPCIM_RST_IN_PROG_SRPCIM_RST_IN_PROG	BIT(7)
+/*0x002c8*/	u64	srpcim_reg_modified;
+#define	VXGE_HW_SRPCIM_REG_MODIFIED_SRPCIM_REG_MODIFIED	BIT(7)
+/*0x002d0*/	u64	tgt_pf_illegal_access;
+#define VXGE_HW_TGT_PF_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
+/*0x002d8*/	u64	srpcim_msix_status;
+#define	VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_MASK	BIT(3)
+#define	VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_PENDING_VECTOR	BIT(7)
+	u8	unused00880[0x00880-0x002e0];
+
+/*0x00880*/	u64	xgmac_sr_int_status;
+#define	VXGE_HW_XGMAC_SR_INT_STATUS_ASIC_NTWK_SR_ERR_ASIC_NTWK_SR_INT	BIT(3)
+/*0x00888*/	u64	xgmac_sr_int_mask;
+/*0x00890*/	u64	asic_ntwk_sr_err_reg;
+#define	VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT	BIT(3)
+#define	VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK	BIT(7)
+#define	VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT_OCCURRED \
+									BIT(11)
+#define	VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK_OCCURRED	BIT(15)
+/*0x00898*/	u64	asic_ntwk_sr_err_mask;
+/*0x008a0*/	u64	asic_ntwk_sr_err_alarm;
+	u8	unused008c0[0x008c0-0x008a8];
+
+/*0x008c0*/	u64	xmac_vsport_choices_sr_clone;
+#define	VXGE_HW_XMAC_VSPORT_CHOICES_SR_CLONE_VSPORT_VECTOR(val) \
+							vxge_vBIT(val, 0, 17)
+	u8	unused00900[0x00900-0x008c8];
+
+/*0x00900*/	u64	mr_rqa_top_prty_for_vh;
+#define	VXGE_HW_MR_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00908*/	u64	umq_vh_data_list_empty;
+#define	VXGE_HW_UMQ_VH_DATA_LIST_EMPTY_ROCRC_UMQ_VH_DATA_LIST_EMPTY \
+							BIT(0)
+/*0x00910*/	u64	wde_cfg;
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_MWB_START	BIT(0)
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_MWB_END	BIT(1)
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_QB_START	BIT(2)
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_QB_END	BIT(3)
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_START	BIT(4)
+#define	VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_END	BIT(5)
+#define	VXGE_HW_WDE_CFG_NS0_MWB_OPT_EN	BIT(6)
+#define	VXGE_HW_WDE_CFG_NS0_QB_OPT_EN	BIT(7)
+#define	VXGE_HW_WDE_CFG_NS0_MPSB_OPT_EN	BIT(8)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_MWB_START	BIT(9)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_MWB_END	BIT(10)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_QB_START	BIT(11)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_QB_END	BIT(12)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_START	BIT(13)
+#define	VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_END	BIT(14)
+#define	VXGE_HW_WDE_CFG_NS1_MWB_OPT_EN	BIT(15)
+#define	VXGE_HW_WDE_CFG_NS1_QB_OPT_EN	BIT(16)
+#define	VXGE_HW_WDE_CFG_NS1_MPSB_OPT_EN	BIT(17)
+#define	VXGE_HW_WDE_CFG_DISABLE_QPAD_FOR_UNALIGNED_ADDR	BIT(19)
+#define VXGE_HW_WDE_CFG_ALIGNMENT_PREFERENCE(val) vxge_vBIT(val, 30, 2)
+#define VXGE_HW_WDE_CFG_MEM_WORD_SIZE(val) vxge_vBIT(val, 46, 2)
+
+} __attribute((packed));
+
+/*VXGE_HW_VPMGMT_REGS_H*/
+struct vxge_hw_vpmgmt_reg {
+
+	u8	unused00040[0x00040-0x00000];
+
+/*0x00040*/	u64	vpath_to_func_map_cfg1;
+#define	VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_VPATH_TO_FUNC_MAP_CFG1(val) \
+							vxge_vBIT(val, 3, 5)
+/*0x00048*/	u64	vpath_is_first;
+#define	VXGE_HW_VPATH_IS_FIRST_VPATH_IS_FIRST	vxge_mBIT(3)
+/*0x00050*/	u64	srpcim_to_vpath_wmsg;
+#define	VXGE_HW_SRPCIM_TO_VPATH_WMSG_SRPCIM_TO_VPATH_WMSG(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x00058*/	u64	srpcim_to_vpath_wmsg_trig;
+#define	VXGE_HW_SRPCIM_TO_VPATH_WMSG_TRIG_SRPCIM_TO_VPATH_WMSG_TRIG \
+								vxge_mBIT(0)
+	u8	unused00100[0x00100-0x00060];
+
+/*0x00100*/	u64	tim_vpath_assignment;
+#define VXGE_HW_TIM_VPATH_ASSIGNMENT_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+	u8	unused00140[0x00140-0x00108];
+
+/*0x00140*/	u64	rqa_top_prty_for_vp;
+#define VXGE_HW_RQA_TOP_PRTY_FOR_VP_RQA_TOP_PRTY_FOR_VP(val) \
+							vxge_vBIT(val, 59, 5)
+	u8	unused001c0[0x001c0-0x00148];
+
+/*0x001c0*/	u64	rxmac_rx_pa_cfg0_vpmgmt_clone;
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IGNORE_FRAME_ERR	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_SNAP_AB_N	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_HAO	vxge_mBIT(18)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_MOBILE_IPV6_HDRS \
+								vxge_mBIT(19)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IPV6_STOP_SEARCHING \
+								vxge_mBIT(23)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_NO_PS_IF_UNKNOWN	vxge_mBIT(27)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_ETYPE	vxge_mBIT(35)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L3_CSUM_ERR \
+								vxge_mBIT(39)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR \
+								vxge_mBIT(43)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L4_CSUM_ERR \
+								vxge_mBIT(47)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR \
+								vxge_mBIT(51)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_RPA_ERR \
+								vxge_mBIT(55)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_RPA_ERR \
+								vxge_mBIT(59)
+#define	VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_JUMBO_SNAP_EN	vxge_mBIT(63)
+/*0x001c8*/	u64	rts_mgr_cfg0_vpmgmt_clone;
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_RTS_DP_SP_PRIORITY	vxge_mBIT(3)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_FLEX_L4PRTCL_VALUE(val) \
+							vxge_vBIT(val, 24, 8)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ICMP_TRASH	vxge_mBIT(35)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_TCPSYN_TRASH	vxge_mBIT(39)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ZL4PYLD_TRASH	vxge_mBIT(43)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_TCP_TRASH	vxge_mBIT(47)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_UDP_TRASH	vxge_mBIT(51)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_FLEX_TRASH	vxge_mBIT(55)
+#define	VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_IPFRAG_TRASH	vxge_mBIT(59)
+/*0x001d0*/	u64	rts_mgr_criteria_priority_vpmgmt_clone;
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ETYPE(val) \
+							vxge_vBIT(val, 5, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ICMP_TCPSYN(val) \
+							vxge_vBIT(val, 9, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PN(val) \
+							vxge_vBIT(val, 13, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RANGE_L4PN(val) \
+							vxge_vBIT(val, 17, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RTH_IT(val) \
+							vxge_vBIT(val, 21, 3)
+#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_DS(val) \
+							vxge_vBIT(val, 25, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_QOS(val) \
+							vxge_vBIT(val, 29, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ZL4PYLD(val) \
+							vxge_vBIT(val, 33, 3)
+#define	VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PRTCL(val) \
+							vxge_vBIT(val, 37, 3)
+/*0x001d8*/	u64	rxmac_cfg0_port_vpmgmt_clone[3];
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_RMAC_EN	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_DISCARD_PFRM	vxge_mBIT(11)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_FCS_ERR	vxge_mBIT(15)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LONG_ERR	vxge_mBIT(19)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_USIZED_ERR	vxge_mBIT(23)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LEN_MISMATCH \
+								vxge_mBIT(27)
+#define	VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_MAX_PYLD_LEN(val) \
+							vxge_vBIT(val, 50, 14)
+/*0x001f0*/	u64	rxmac_pause_cfg_port_vpmgmt_clone[3];
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_GEN_EN	vxge_mBIT(3)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_RCV_EN	vxge_mBIT(7)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_ACCEL_SEND(val) \
+							vxge_vBIT(val, 9, 3)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_DUAL_THR	vxge_mBIT(15)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_HIGH_PTIME(val) \
+							vxge_vBIT(val, 20, 16)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_FCS_ERR \
+								vxge_mBIT(39)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_LEN_ERR \
+								vxge_mBIT(43)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_LIMITER_EN	vxge_mBIT(47)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_MAX_LIMIT(val) \
+							vxge_vBIT(val, 48, 8)
+#define	VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_PERMIT_RATEMGMT_CTRL \
+							vxge_mBIT(59)
+	u8	unused00240[0x00240-0x00208];
+
+/*0x00240*/	u64	xmac_vsport_choices_vp;
+#define VXGE_HW_XMAC_VSPORT_CHOICES_VP_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
+	u8	unused00260[0x00260-0x00248];
+
+/*0x00260*/	u64	xgmac_gen_status_vpmgmt_clone;
+#define	VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK	vxge_mBIT(3)
+#define	VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_DATA_RATE \
+								vxge_mBIT(11)
+/*0x00268*/	u64	xgmac_status_port_vpmgmt_clone[2];
+#define	VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_REMOTE_FAULT \
+								vxge_mBIT(3)
+#define	VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_LOCAL_FAULT	vxge_mBIT(7)
+#define	VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_MAC_PHY_LAYER_AVAIL \
+								vxge_mBIT(11)
+#define	VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_PORT_OK	vxge_mBIT(15)
+/*0x00278*/	u64	xmac_gen_cfg_vpmgmt_clone;
+#define	VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_RATEMGMT_MAC_RATE_SEL(val) \
+							vxge_vBIT(val, 2, 2)
+#define	VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_TX_HEAD_DROP_WHEN_FAULT \
+							vxge_mBIT(7)
+#define	VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_FAULT_BEHAVIOUR	vxge_mBIT(27)
+#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_UP(val) \
+							vxge_vBIT(val, 28, 4)
+#define	VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_DOWN(val) \
+							vxge_vBIT(val, 32, 4)
+/*0x00280*/	u64	xmac_timestamp_vpmgmt_clone;
+#define	VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_EN	vxge_mBIT(3)
+#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_USE_LINK_ID(val) \
+							vxge_vBIT(val, 6, 2)
+#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_INTERVAL(val) vxge_vBIT(val, 12, 4)
+#define	VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_TIMER_RESTART	vxge_mBIT(19)
+#define	VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_XMACJ_ROLLOVER_CNT(val) \
+							vxge_vBIT(val, 32, 16)
+/*0x00288*/	u64	xmac_stats_gen_cfg_vpmgmt_clone;
+#define	VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_PRTAGGR_CUM_TIMER(val) \
+							vxge_vBIT(val, 4, 4)
+#define	VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VPATH_CUM_TIMER(val) \
+							vxge_vBIT(val, 8, 4)
+#define	VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VLAN_HANDLING	vxge_mBIT(15)
+/*0x00290*/	u64	xmac_cfg_port_vpmgmt_clone[3];
+#define	VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_LOOPBACK	vxge_mBIT(3)
+#define	VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_REVERSE_LOOPBACK \
+								vxge_mBIT(7)
+#define	VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_TX_BEHAV	vxge_mBIT(11)
+#define	VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_RX_BEHAV	vxge_mBIT(15)
+	u8	unused002c0[0x002c0-0x002a8];
+
+/*0x002c0*/	u64	txmac_gen_cfg0_vpmgmt_clone;
+#define	VXGE_HW_TXMAC_GEN_CFG0_VPMGMT_CLONE_CHOSEN_TX_PORT	vxge_mBIT(7)
+/*0x002c8*/	u64	txmac_cfg0_port_vpmgmt_clone[3];
+#define	VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_TMAC_EN	vxge_mBIT(3)
+#define	VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_APPEND_PAD	vxge_mBIT(7)
+#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
+	u8	unused00300[0x00300-0x002e0];
+
+/*0x00300*/	u64	wol_mp_crc;
+#define VXGE_HW_WOL_MP_CRC_CRC(val) vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_WOL_MP_CRC_RC_EN	vxge_mBIT(63)
+/*0x00308*/	u64	wol_mp_mask_a;
+#define VXGE_HW_WOL_MP_MASK_A_MASK(val) vxge_vBIT(val, 0, 64)
+/*0x00310*/	u64	wol_mp_mask_b;
+#define VXGE_HW_WOL_MP_MASK_B_MASK(val) vxge_vBIT(val, 0, 64)
+	u8	unused00360[0x00360-0x00318];
+
+/*0x00360*/	u64	fau_pa_cfg_vpmgmt_clone;
+#define	VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L4_COMP_CSUM	vxge_mBIT(3)
+#define	VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_INCL_CF	vxge_mBIT(7)
+#define	VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_COMP_CSUM	vxge_mBIT(11)
+/*0x00368*/	u64	rx_datapath_util_vp_clone;
+#define	VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_UTILIZATION(val) \
+							vxge_vBIT(val, 7, 9)
+#define	VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_UTIL_CFG(val) \
+							vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_FRAC_UTIL(val) \
+							vxge_vBIT(val, 20, 4)
+#define	VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_PKT_WEIGHT(val) \
+							vxge_vBIT(val, 24, 4)
+	u8	unused00380[0x00380-0x00370];
+
+/*0x00380*/	u64	tx_datapath_util_vp_clone;
+#define	VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_UTILIZATION(val) \
+							vxge_vBIT(val, 7, 9)
+#define	VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_UTIL_CFG(val) \
+							vxge_vBIT(val, 16, 4)
+#define	VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_FRAC_UTIL(val) \
+							vxge_vBIT(val, 20, 4)
+#define	VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_PKT_WEIGHT(val) \
+							vxge_vBIT(val, 24, 4)
+
+} __attribute((packed));
+
+struct vxge_hw_vpath_reg {
+
+	u8	unused00300[0x00300];
+
+/*0x00300*/	u64	usdc_vpath;
+#define VXGE_HW_USDC_VPATH_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 32)
+	u8	unused00a00[0x00a00-0x00308];
+
+/*0x00a00*/	u64	wrdma_alarm_status;
+#define	VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT	vxge_mBIT(1)
+/*0x00a08*/	u64	wrdma_alarm_mask;
+	u8	unused00a30[0x00a30-0x00a10];
+
+/*0x00a30*/	u64	prc_alarm_reg;
+#define	VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP	vxge_mBIT(0)
+#define	VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR	vxge_mBIT(1)
+#define	VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT	vxge_mBIT(2)
+#define	VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR	vxge_mBIT(3)
+/*0x00a38*/	u64	prc_alarm_mask;
+/*0x00a40*/	u64	prc_alarm_alarm;
+/*0x00a48*/	u64	prc_cfg1;
+#define VXGE_HW_PRC_CFG1_RX_TIMER_VAL(val) vxge_vBIT(val, 3, 29)
+#define	VXGE_HW_PRC_CFG1_TIM_RING_BUMP_INT_ENABLE	vxge_mBIT(34)
+#define	VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE	vxge_mBIT(35)
+#define	VXGE_HW_PRC_CFG1_GREEDY_RETURN	vxge_mBIT(36)
+#define	VXGE_HW_PRC_CFG1_QUICK_SHOT	vxge_mBIT(37)
+#define	VXGE_HW_PRC_CFG1_RX_TIMER_CI	vxge_mBIT(39)
+#define VXGE_HW_PRC_CFG1_RESET_TIMER_ON_RXD_RET(val) vxge_vBIT(val, 40, 2)
+	u8	unused00a60[0x00a60-0x00a50];
+
+/*0x00a60*/	u64	prc_cfg4;
+#define	VXGE_HW_PRC_CFG4_IN_SVC	vxge_mBIT(7)
+#define VXGE_HW_PRC_CFG4_RING_MODE(val) vxge_vBIT(val, 14, 2)
+#define	VXGE_HW_PRC_CFG4_RXD_NO_SNOOP	vxge_mBIT(22)
+#define	VXGE_HW_PRC_CFG4_FRM_NO_SNOOP	vxge_mBIT(23)
+#define	VXGE_HW_PRC_CFG4_RTH_DISABLE	vxge_mBIT(31)
+#define	VXGE_HW_PRC_CFG4_IGNORE_OWNERSHIP	vxge_mBIT(32)
+#define	VXGE_HW_PRC_CFG4_SIGNAL_BENIGN_OVFLW	vxge_mBIT(36)
+#define	VXGE_HW_PRC_CFG4_BIMODAL_INTERRUPT	vxge_mBIT(37)
+#define VXGE_HW_PRC_CFG4_BACKOFF_INTERVAL(val) vxge_vBIT(val, 40, 24)
+/*0x00a68*/	u64	prc_cfg5;
+#define VXGE_HW_PRC_CFG5_RXD0_ADD(val) vxge_vBIT(val, 0, 61)
+/*0x00a70*/	u64	prc_cfg6;
+#define	VXGE_HW_PRC_CFG6_FRM_PAD_EN	vxge_mBIT(0)
+#define	VXGE_HW_PRC_CFG6_QSIZE_ALIGNED_RXD	vxge_mBIT(2)
+#define	VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN	vxge_mBIT(5)
+#define	VXGE_HW_PRC_CFG6_L3_CPC_TRSFR_CODE_EN	vxge_mBIT(8)
+#define	VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN	vxge_mBIT(9)
+#define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9)
+#define VXGE_HW_PRC_CFG6_GET_RXD_CRXDT(val) vxge_bVALn(val, 23, 9)
+#define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9)
+#define VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val) vxge_bVALn(val, 36, 9)
+/*0x00a78*/	u64	prc_cfg7;
+#define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_PRC_CFG7_SMART_SCAT_EN	vxge_mBIT(11)
+#define	VXGE_HW_PRC_CFG7_RXD_NS_CHG_EN	vxge_mBIT(12)
+#define	VXGE_HW_PRC_CFG7_NO_HDR_SEPARATION	vxge_mBIT(14)
+#define VXGE_HW_PRC_CFG7_RXD_BUFF_SIZE_MASK(val) vxge_vBIT(val, 20, 4)
+#define VXGE_HW_PRC_CFG7_BUFF_SIZE0_MASK(val) vxge_vBIT(val, 27, 5)
+/*0x00a80*/	u64	tim_dest_addr;
+#define VXGE_HW_TIM_DEST_ADDR_TIM_DEST_ADDR(val) vxge_vBIT(val, 0, 64)
+/*0x00a88*/	u64	prc_rxd_doorbell;
+#define VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val) vxge_vBIT(val, 48, 16)
+/*0x00a90*/	u64	rqa_prty_for_vp;
+#define VXGE_HW_RQA_PRTY_FOR_VP_RQA_PRTY_FOR_VP(val) vxge_vBIT(val, 59, 5)
+/*0x00a98*/	u64	rxdmem_size;
+#define VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(val) vxge_vBIT(val, 51, 13)
+/*0x00aa0*/	u64	frm_in_progress_cnt;
+#define	VXGE_HW_FRM_IN_PROGRESS_CNT_PRC_FRM_IN_PROGRESS_CNT(val) \
+							vxge_vBIT(val, 59, 5)
+/*0x00aa8*/	u64	rx_multi_cast_stats;
+#define VXGE_HW_RX_MULTI_CAST_STATS_FRAME_DISCARD(val) vxge_vBIT(val, 48, 16)
+/*0x00ab0*/	u64	rx_frm_transferred;
+#define	VXGE_HW_RX_FRM_TRANSFERRED_RX_FRM_TRANSFERRED(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x00ab8*/	u64	rxd_returned;
+#define VXGE_HW_RXD_RETURNED_RXD_RETURNED(val) vxge_vBIT(val, 48, 16)
+	u8	unused00c00[0x00c00-0x00ac0];
+
+/*0x00c00*/	u64	kdfc_fifo_trpl_partition;
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_1(val) vxge_vBIT(val, 33, 15)
+#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_2(val) vxge_vBIT(val, 49, 15)
+/*0x00c08*/	u64	kdfc_fifo_trpl_ctrl;
+#define	VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE	vxge_mBIT(7)
+/*0x00c10*/	u64	kdfc_trpl_fifo_0_ctrl;
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_FLIP_EN	vxge_mBIT(22)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN	vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_CTRL_STRUC	vxge_mBIT(28)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_ADD_PAD	vxge_mBIT(29)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_NO_SNOOP	vxge_mBIT(30)
+#define	VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_RLX_ORD	vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c18*/	u64	kdfc_trpl_fifo_1_ctrl;
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_FLIP_EN	vxge_mBIT(22)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SWAP_EN	vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_CTRL_STRUC	vxge_mBIT(28)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_ADD_PAD	vxge_mBIT(29)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_NO_SNOOP	vxge_mBIT(30)
+#define	VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_RLX_ORD	vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c20*/	u64	kdfc_trpl_fifo_2_ctrl;
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_FLIP_EN	vxge_mBIT(22)
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SWAP_EN	vxge_mBIT(23)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_CTRL_STRUC	vxge_mBIT(28)
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_ADD_PAD	vxge_mBIT(29)
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_NO_SNOOP	vxge_mBIT(30)
+#define	VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_RLX_ORD	vxge_mBIT(31)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
+/*0x00c28*/	u64	kdfc_trpl_fifo_0_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_0_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c30*/	u64	kdfc_trpl_fifo_1_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_1_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c38*/	u64	kdfc_trpl_fifo_2_wb_address;
+#define VXGE_HW_KDFC_TRPL_FIFO_2_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x00c40*/	u64	kdfc_trpl_fifo_offset;
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR0(val) vxge_vBIT(val, 1, 15)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR1(val) vxge_vBIT(val, 17, 15)
+#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR2(val) vxge_vBIT(val, 33, 15)
+/*0x00c48*/	u64	kdfc_drbl_triplet_total;
+#define	VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_KDFC_MAX_SIZE(val) \
+							vxge_vBIT(val, 17, 15)
+	u8	unused00c60[0x00c60-0x00c50];
+
+/*0x00c60*/	u64	usdc_drbl_ctrl;
+#define	VXGE_HW_USDC_DRBL_CTRL_FLIP_EN	vxge_mBIT(22)
+#define	VXGE_HW_USDC_DRBL_CTRL_SWAP_EN	vxge_mBIT(23)
+/*0x00c68*/	u64	usdc_vp_ready;
+#define	VXGE_HW_USDC_VP_READY_USDC_HTN_READY	vxge_mBIT(7)
+#define	VXGE_HW_USDC_VP_READY_USDC_SRQ_READY	vxge_mBIT(15)
+#define	VXGE_HW_USDC_VP_READY_USDC_CQRQ_READY	vxge_mBIT(23)
+/*0x00c70*/	u64	kdfc_status;
+#define	VXGE_HW_KDFC_STATUS_KDFC_WRR_0_READY	vxge_mBIT(0)
+#define	VXGE_HW_KDFC_STATUS_KDFC_WRR_1_READY	vxge_mBIT(1)
+#define	VXGE_HW_KDFC_STATUS_KDFC_WRR_2_READY	vxge_mBIT(2)
+	u8	unused00c80[0x00c80-0x00c78];
+
+/*0x00c80*/	u64	xmac_rpa_vcfg;
+#define	VXGE_HW_XMAC_RPA_VCFG_IPV4_TCP_INCL_PH	vxge_mBIT(3)
+#define	VXGE_HW_XMAC_RPA_VCFG_IPV6_TCP_INCL_PH	vxge_mBIT(7)
+#define	VXGE_HW_XMAC_RPA_VCFG_IPV4_UDP_INCL_PH	vxge_mBIT(11)
+#define	VXGE_HW_XMAC_RPA_VCFG_IPV6_UDP_INCL_PH	vxge_mBIT(15)
+#define	VXGE_HW_XMAC_RPA_VCFG_L4_INCL_CF	vxge_mBIT(19)
+#define	VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG	vxge_mBIT(23)
+/*0x00c88*/	u64	rxmac_vcfg0;
+#define VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(val) vxge_vBIT(val, 2, 14)
+#define	VXGE_HW_RXMAC_VCFG0_RTS_USE_MIN_LEN	vxge_mBIT(19)
+#define VXGE_HW_RXMAC_VCFG0_RTS_MIN_FRM_LEN(val) vxge_vBIT(val, 26, 14)
+#define	VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN	vxge_mBIT(43)
+#define	VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN	vxge_mBIT(47)
+#define	VXGE_HW_RXMAC_VCFG0_BCAST_EN	vxge_mBIT(51)
+#define	VXGE_HW_RXMAC_VCFG0_ALL_VID_EN	vxge_mBIT(55)
+/*0x00c90*/	u64	rxmac_vcfg1;
+#define VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(val) vxge_vBIT(val, 42, 2)
+#define	VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE	vxge_mBIT(47)
+#define	VXGE_HW_RXMAC_VCFG1_CONTRIB_L2_FLOW	vxge_mBIT(51)
+/*0x00c98*/	u64	rts_access_steer_ctrl;
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(val) vxge_vBIT(val, 8, 4)
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE	vxge_mBIT(15)
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_BEHAV_TBL_SEL	vxge_mBIT(23)
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL	vxge_mBIT(27)
+#define	VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS	vxge_mBIT(0)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(val) vxge_vBIT(val, 40, 8)
+/* To be used by the privileged driver */
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_VHN(val) vxge_vBIT(val, 48, 8)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_VFID(val) vxge_vBIT(val, 56, 8)
+/*0x00ca0*/	u64	rts_access_steer_data0;
+#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x00ca8*/	u64	rts_access_steer_data1;
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DATA(val) vxge_vBIT(val, 0, 64)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_PRIV_MODE_EN vxge_mBIT(54)
+#define VXGE_HW_RTS_ACCESS_STEER_DATA1_PRIV_MODE_VPN(val) vxge_vBIT(val, 55, 5)
+	u8	unused00d00[0x00d00-0x00cb0];
+
+/*0x00d00*/	u64	xmac_vsport_choice;
+#define VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(val) vxge_vBIT(val, 3, 5)
+/*0x00d08*/	u64	xmac_stats_cfg;
+/*0x00d10*/	u64	xmac_stats_access_cmd;
+#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(val) vxge_vBIT(val, 6, 2)
+#define	VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE	vxge_mBIT(15)
+#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
+/*0x00d18*/	u64	xmac_stats_access_data;
+#define VXGE_HW_XMAC_STATS_ACCESS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
+/*0x00d20*/	u64	asic_ntwk_vp_ctrl;
+#define	VXGE_HW_ASIC_NTWK_VP_CTRL_REQ_TEST_NTWK	vxge_mBIT(3)
+#define	VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_SHOW_PORT_INFO	vxge_mBIT(55)
+#define	VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_PORT_NUM	vxge_mBIT(63)
+	u8	unused00d30[0x00d30-0x00d28];
+
+/*0x00d30*/	u64	xgmac_vp_int_status;
+#define	VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT \
+								vxge_mBIT(3)
+/*0x00d38*/	u64	xgmac_vp_int_mask;
+/*0x00d40*/	u64	asic_ntwk_vp_err_reg;
+#define	VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT	vxge_mBIT(3)
+#define	VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK	vxge_mBIT(7)
+#define	VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR \
+								vxge_mBIT(11)
+#define	VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR \
+							vxge_mBIT(15)
+#define	VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT \
+							vxge_mBIT(19)
+#define	VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK	vxge_mBIT(23)
+/*0x00d48*/	u64	asic_ntwk_vp_err_mask;
+/*0x00d50*/	u64	asic_ntwk_vp_err_alarm;
+	u8	unused00d80[0x00d80-0x00d58];
+
+/*0x00d80*/	u64	rtdma_bw_ctrl;
+#define	VXGE_HW_RTDMA_BW_CTRL_BW_CTRL_EN	vxge_mBIT(39)
+#define VXGE_HW_RTDMA_BW_CTRL_DESIRED_BW(val) vxge_vBIT(val, 46, 18)
+/*0x00d88*/	u64	rtdma_rd_optimization_ctrl;
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_GEN_INT_AFTER_ABORT	vxge_mBIT(3)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_MODE(val) vxge_vBIT(val, 6, 2)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_PATTERN(val) vxge_vBIT(val, 8, 8)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE	vxge_mBIT(19)
+#define VXGE_HW_PCI_EXP_DEVCTL_READRQ   0x7000  /* Max_Read_Request_Size */
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val) \
+							vxge_vBIT(val, 21, 3)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK_EN	vxge_mBIT(28)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK(val) \
+							vxge_vBIT(val, 29, 3)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN	vxge_mBIT(35)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(val) \
+							vxge_vBIT(val, 37, 3)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_WAIT_FOR_SPACE	vxge_mBIT(43)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_FILL_THRESH(val) \
+							vxge_vBIT(val, 51, 5)
+#define	VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY_EN	vxge_mBIT(59)
+#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY(val) \
+							vxge_vBIT(val, 61, 3)
+/*0x00d90*/	u64	pda_pcc_job_monitor;
+#define	VXGE_HW_PDA_PCC_JOB_MONITOR_PDA_PCC_JOB_STATUS	vxge_mBIT(7)
+/*0x00d98*/	u64	tx_protocol_assist_cfg;
+#define	VXGE_HW_TX_PROTOCOL_ASSIST_CFG_LSOV2_EN	vxge_mBIT(6)
+#define	VXGE_HW_TX_PROTOCOL_ASSIST_CFG_IPV6_KEEP_SEARCHING	vxge_mBIT(7)
+	u8	unused01000[0x01000-0x00da0];
+
+/*0x01000*/	u64	tim_cfg1_int_num[4];
+#define VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(val) vxge_vBIT(val, 6, 26)
+#define	VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN	vxge_mBIT(35)
+#define	VXGE_HW_TIM_CFG1_INT_NUM_TXFRM_CNT_EN	vxge_mBIT(36)
+#define	VXGE_HW_TIM_CFG1_INT_NUM_TXD_CNT_EN	vxge_mBIT(37)
+#define	VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC	vxge_mBIT(38)
+#define	VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI	vxge_mBIT(39)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(val) vxge_vBIT(val, 41, 7)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(val) vxge_vBIT(val, 49, 7)
+#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(val) vxge_vBIT(val, 57, 7)
+/*0x01020*/	u64	tim_cfg2_int_num[4];
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(val) vxge_vBIT(val, 32, 16)
+#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(val) vxge_vBIT(val, 48, 16)
+/*0x01040*/	u64	tim_cfg3_int_num[4];
+#define	VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI	vxge_mBIT(0)
+#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(val) vxge_vBIT(val, 1, 4)
+#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(val) vxge_vBIT(val, 6, 26)
+#define VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(val) vxge_vBIT(val, 32, 6)
+#define VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(val) vxge_vBIT(val, 38, 26)
+/*0x01060*/	u64	tim_wrkld_clc;
+#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(val) vxge_vBIT(val, 0, 32)
+#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(val) vxge_vBIT(val, 35, 5)
+#define	VXGE_HW_TIM_WRKLD_CLC_CNT_FRM_BYTE	vxge_mBIT(40)
+#define VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(val) vxge_vBIT(val, 41, 2)
+#define	VXGE_HW_TIM_WRKLD_CLC_CNT_LNK_EN	vxge_mBIT(43)
+#define VXGE_HW_TIM_WRKLD_CLC_HOST_UTIL(val) vxge_vBIT(val, 57, 7)
+/*0x01068*/	u64	tim_bitmap;
+#define VXGE_HW_TIM_BITMAP_MASK(val) vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_TIM_BITMAP_LLROOT_RXD_EN	vxge_mBIT(32)
+#define	VXGE_HW_TIM_BITMAP_LLROOT_TXD_EN	vxge_mBIT(33)
+/*0x01070*/	u64	tim_ring_assn;
+#define VXGE_HW_TIM_RING_ASSN_INT_NUM(val) vxge_vBIT(val, 6, 2)
+/*0x01078*/	u64	tim_remap;
+#define	VXGE_HW_TIM_REMAP_TX_EN	vxge_mBIT(5)
+#define	VXGE_HW_TIM_REMAP_RX_EN	vxge_mBIT(6)
+#define	VXGE_HW_TIM_REMAP_OFFLOAD_EN	vxge_mBIT(7)
+#define VXGE_HW_TIM_REMAP_TO_VPATH_NUM(val) vxge_vBIT(val, 11, 5)
+/*0x01080*/	u64	tim_vpath_map;
+#define VXGE_HW_TIM_VPATH_MAP_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
+/*0x01088*/	u64	tim_pci_cfg;
+#define	VXGE_HW_TIM_PCI_CFG_ADD_PAD	vxge_mBIT(7)
+#define	VXGE_HW_TIM_PCI_CFG_NO_SNOOP	vxge_mBIT(15)
+#define	VXGE_HW_TIM_PCI_CFG_RELAXED	vxge_mBIT(23)
+#define	VXGE_HW_TIM_PCI_CFG_CTL_STR	vxge_mBIT(31)
+	u8	unused01100[0x01100-0x01090];
+
+/*0x01100*/	u64	sgrp_assign;
+#define VXGE_HW_SGRP_ASSIGN_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 64)
+/*0x01108*/	u64	sgrp_aoa_and_result;
+#define	VXGE_HW_SGRP_AOA_AND_RESULT_PET_SGRP_AOA_AND_RESULT(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x01110*/	u64	rpe_pci_cfg;
+#define	VXGE_HW_RPE_PCI_CFG_PAD_LRO_DATA_ENABLE	vxge_mBIT(7)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_LRO_HDR_ENABLE	vxge_mBIT(8)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_LRO_CQE_ENABLE	vxge_mBIT(9)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_NONLL_CQE_ENABLE	vxge_mBIT(10)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_BASE_LL_CQE_ENABLE	vxge_mBIT(11)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_LL_CQE_IDATA_ENABLE	vxge_mBIT(12)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_CQRQ_IR_ENABLE	vxge_mBIT(13)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_CQSQ_IR_ENABLE	vxge_mBIT(14)
+#define	VXGE_HW_RPE_PCI_CFG_PAD_CQRR_IR_ENABLE	vxge_mBIT(15)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_DATA	vxge_mBIT(18)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_NONLL_CQE	vxge_mBIT(19)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_LL_CQE	vxge_mBIT(20)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRQ_IR	vxge_mBIT(21)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQSQ_IR	vxge_mBIT(22)
+#define	VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRR_IR	vxge_mBIT(23)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_DATA	vxge_mBIT(26)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_NONLL_CQE	vxge_mBIT(27)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_LL_CQE	vxge_mBIT(28)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_CQRQ_IR	vxge_mBIT(29)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_CQSQ_IR	vxge_mBIT(30)
+#define	VXGE_HW_RPE_PCI_CFG_RELAXED_CQRR_IR	vxge_mBIT(31)
+/*0x01118*/	u64	rpe_lro_cfg;
+#define	VXGE_HW_RPE_LRO_CFG_SUPPRESS_LRO_ETH_TRLR	vxge_mBIT(7)
+#define	VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_SNAP_SNAPJUMBO_MRG	vxge_mBIT(11)
+#define	VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_LLC_LLCJUMBO_MRG	vxge_mBIT(15)
+#define	VXGE_HW_RPE_LRO_CFG_INCL_ACK_CNT_IN_CQE	vxge_mBIT(23)
+/*0x01120*/	u64	pe_mr2vp_ack_blk_limit;
+#define VXGE_HW_PE_MR2VP_ACK_BLK_LIMIT_BLK_LIMIT(val) vxge_vBIT(val, 32, 32)
+/*0x01128*/	u64	pe_mr2vp_rirr_lirr_blk_limit;
+#define	VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_RIRR_BLK_LIMIT(val) \
+							vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_LIRR_BLK_LIMIT(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x01130*/	u64	txpe_pci_nce_cfg;
+#define VXGE_HW_TXPE_PCI_NCE_CFG_NCE_THRESH(val) vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_TXPE_PCI_NCE_CFG_PAD_TOWI_ENABLE	vxge_mBIT(55)
+#define	VXGE_HW_TXPE_PCI_NCE_CFG_NOSNOOP_TOWI	vxge_mBIT(63)
+	u8	unused01180[0x01180-0x01138];
+
+/*0x01180*/	u64	msg_qpad_en_cfg;
+#define	VXGE_HW_MSG_QPAD_EN_CFG_UMQ_BWR_READ	vxge_mBIT(3)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_DMQ_BWR_READ	vxge_mBIT(7)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_READ	vxge_mBIT(11)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_READ	vxge_mBIT(15)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_UMQ_MSG_WRITE	vxge_mBIT(19)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_UMQDMQ_IR_WRITE	vxge_mBIT(23)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_WRITE	vxge_mBIT(27)
+#define	VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_WRITE	vxge_mBIT(31)
+/*0x01188*/	u64	msg_pci_cfg;
+#define	VXGE_HW_MSG_PCI_CFG_GENDMA_NO_SNOOP	vxge_mBIT(3)
+#define	VXGE_HW_MSG_PCI_CFG_UMQDMQ_IR_NO_SNOOP	vxge_mBIT(7)
+#define	VXGE_HW_MSG_PCI_CFG_UMQ_NO_SNOOP	vxge_mBIT(11)
+#define	VXGE_HW_MSG_PCI_CFG_DMQ_NO_SNOOP	vxge_mBIT(15)
+/*0x01190*/	u64	umqdmq_ir_init;
+#define VXGE_HW_UMQDMQ_IR_INIT_HOST_WRITE_ADD(val) vxge_vBIT(val, 0, 64)
+/*0x01198*/	u64	dmq_ir_int;
+#define	VXGE_HW_DMQ_IR_INT_IMMED_ENABLE	vxge_mBIT(6)
+#define	VXGE_HW_DMQ_IR_INT_EVENT_ENABLE	vxge_mBIT(7)
+#define VXGE_HW_DMQ_IR_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_DMQ_IR_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
+/*0x011a0*/	u64	dmq_bwr_init_add;
+#define VXGE_HW_DMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
+/*0x011a8*/	u64	dmq_bwr_init_byte;
+#define VXGE_HW_DMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
+/*0x011b0*/	u64	dmq_ir;
+#define VXGE_HW_DMQ_IR_POLICY(val) vxge_vBIT(val, 0, 8)
+/*0x011b8*/	u64	umq_int;
+#define	VXGE_HW_UMQ_INT_IMMED_ENABLE	vxge_mBIT(6)
+#define	VXGE_HW_UMQ_INT_EVENT_ENABLE	vxge_mBIT(7)
+#define VXGE_HW_UMQ_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_UMQ_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
+/*0x011c0*/	u64	umq_mr2vp_bwr_pfch_init;
+#define VXGE_HW_UMQ_MR2VP_BWR_PFCH_INIT_NUMBER(val) vxge_vBIT(val, 0, 8)
+/*0x011c8*/	u64	umq_bwr_pfch_ctrl;
+#define	VXGE_HW_UMQ_BWR_PFCH_CTRL_POLL_EN	vxge_mBIT(3)
+/*0x011d0*/	u64	umq_mr2vp_bwr_eol;
+#define VXGE_HW_UMQ_MR2VP_BWR_EOL_POLL_LATENCY(val) vxge_vBIT(val, 32, 32)
+/*0x011d8*/	u64	umq_bwr_init_add;
+#define VXGE_HW_UMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
+/*0x011e0*/	u64	umq_bwr_init_byte;
+#define VXGE_HW_UMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
+/*0x011e8*/	u64	gendma_int;
+/*0x011f0*/	u64	umqdmq_ir_init_notify;
+#define	VXGE_HW_UMQDMQ_IR_INIT_NOTIFY_PULSE	vxge_mBIT(3)
+/*0x011f8*/	u64	dmq_init_notify;
+#define	VXGE_HW_DMQ_INIT_NOTIFY_PULSE	vxge_mBIT(3)
+/*0x01200*/	u64	umq_init_notify;
+#define	VXGE_HW_UMQ_INIT_NOTIFY_PULSE	vxge_mBIT(3)
+	u8	unused01380[0x01380-0x01208];
+
+/*0x01380*/	u64	tpa_cfg;
+#define	VXGE_HW_TPA_CFG_IGNORE_FRAME_ERR	vxge_mBIT(3)
+#define	VXGE_HW_TPA_CFG_IPV6_STOP_SEARCHING	vxge_mBIT(7)
+#define	VXGE_HW_TPA_CFG_L4_PSHDR_PRESENT	vxge_mBIT(11)
+#define	VXGE_HW_TPA_CFG_SUPPORT_MOBILE_IPV6_HDRS	vxge_mBIT(15)
+	u8	unused01400[0x01400-0x01388];
+
+/*0x01400*/	u64	tx_vp_reset_discarded_frms;
+#define	VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_TX_VP_RESET_DISCARDED_FRMS(val) \
+							vxge_vBIT(val, 48, 16)
+	u8	unused01480[0x01480-0x01408];
+
+/*0x01480*/	u64	fau_rpa_vcfg;
+#define	VXGE_HW_FAU_RPA_VCFG_L4_COMP_CSUM	vxge_mBIT(7)
+#define	VXGE_HW_FAU_RPA_VCFG_L3_INCL_CF	vxge_mBIT(11)
+#define	VXGE_HW_FAU_RPA_VCFG_L3_COMP_CSUM	vxge_mBIT(15)
+	u8	unused014d0[0x014d0-0x01488];
+
+/*0x014d0*/	u64	dbg_stats_rx_mpa;
+#define VXGE_HW_DBG_STATS_RX_MPA_CRC_FAIL_FRMS(val) vxge_vBIT(val, 0, 16)
+#define VXGE_HW_DBG_STATS_RX_MPA_MRK_FAIL_FRMS(val) vxge_vBIT(val, 16, 16)
+#define VXGE_HW_DBG_STATS_RX_MPA_LEN_FAIL_FRMS(val) vxge_vBIT(val, 32, 16)
+/*0x014d8*/	u64	dbg_stats_rx_fau;
+#define VXGE_HW_DBG_STATS_RX_FAU_RX_WOL_FRMS(val) vxge_vBIT(val, 0, 16)
+#define	VXGE_HW_DBG_STATS_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val) \
+							vxge_vBIT(val, 16, 16)
+#define	VXGE_HW_DBG_STATS_RX_FAU_RX_PERMITTED_FRMS(val) \
+							vxge_vBIT(val, 32, 32)
+	u8	unused014f0[0x014f0-0x014e0];
+
+/*0x014f0*/	u64	fbmc_vp_rdy;
+#define	VXGE_HW_FBMC_VP_RDY_QUEUE_SPAV_FM	vxge_mBIT(0)
+	u8	unused01e00[0x01e00-0x014f8];
+
+/*0x01e00*/	u64	vpath_pcipif_int_status;
+#define \
+VXGE_HW_VPATH_PCIPIF_INT_STATUS_SRPCIM_MSG_TO_VPATH_SRPCIM_MSG_TO_VPATH_INT \
+								vxge_mBIT(3)
+#define	VXGE_HW_VPATH_PCIPIF_INT_STATUS_VPATH_SPARE_R1_VPATH_SPARE_R1_INT \
+								vxge_mBIT(7)
+/*0x01e08*/	u64	vpath_pcipif_int_mask;
+	u8	unused01e20[0x01e20-0x01e10];
+
+/*0x01e20*/	u64	srpcim_msg_to_vpath_reg;
+#define	VXGE_HW_SRPCIM_MSG_TO_VPATH_REG_SWIF_SRPCIM_TO_VPATH_RMSG_INT \
+								vxge_mBIT(3)
+/*0x01e28*/	u64	srpcim_msg_to_vpath_mask;
+/*0x01e30*/	u64	srpcim_msg_to_vpath_alarm;
+	u8	unused01ea0[0x01ea0-0x01e38];
+
+/*0x01ea0*/	u64	vpath_to_srpcim_wmsg;
+#define VXGE_HW_VPATH_TO_SRPCIM_WMSG_VPATH_TO_SRPCIM_WMSG(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x01ea8*/	u64	vpath_to_srpcim_wmsg_trig;
+#define	VXGE_HW_VPATH_TO_SRPCIM_WMSG_TRIG_VPATH_TO_SRPCIM_WMSG_TRIG \
+							vxge_mBIT(0)
+	u8	unused02000[0x02000-0x01eb0];
+
+/*0x02000*/	u64	vpath_general_int_status;
+#define	VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT	vxge_mBIT(3)
+#define	VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT	vxge_mBIT(7)
+#define	VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT	vxge_mBIT(15)
+#define	VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT	vxge_mBIT(19)
+/*0x02008*/	u64	vpath_general_int_mask;
+#define	VXGE_HW_VPATH_GENERAL_INT_MASK_PIC_INT	vxge_mBIT(3)
+#define	VXGE_HW_VPATH_GENERAL_INT_MASK_PCI_INT	vxge_mBIT(7)
+#define	VXGE_HW_VPATH_GENERAL_INT_MASK_WRDMA_INT	vxge_mBIT(15)
+#define	VXGE_HW_VPATH_GENERAL_INT_MASK_XMAC_INT	vxge_mBIT(19)
+/*0x02010*/	u64	vpath_ppif_int_status;
+#define	VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT \
+							vxge_mBIT(3)
+#define	VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT \
+							vxge_mBIT(7)
+#define	VXGE_HW_VPATH_PPIF_INT_STATUS_PCI_CONFIG_ERRORS_PCI_CONFIG_INT \
+							vxge_mBIT(11)
+#define \
+VXGE_HW_VPATH_PPIF_INT_STATUS_MRPCIM_TO_VPATH_ALARM_MRPCIM_TO_VPATH_ALARM_INT \
+							vxge_mBIT(15)
+#define \
+VXGE_HW_VPATH_PPIF_INT_STATUS_SRPCIM_TO_VPATH_ALARM_SRPCIM_TO_VPATH_ALARM_INT \
+							vxge_mBIT(19)
+/*0x02018*/	u64	vpath_ppif_int_mask;
+/*0x02020*/	u64	kdfcctl_errors_reg;
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR	vxge_mBIT(3)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR	vxge_mBIT(7)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR	vxge_mBIT(11)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON	vxge_mBIT(15)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON	vxge_mBIT(19)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON	vxge_mBIT(23)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR	vxge_mBIT(31)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR	vxge_mBIT(35)
+#define	VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR	vxge_mBIT(39)
+/*0x02028*/	u64	kdfcctl_errors_mask;
+/*0x02030*/	u64	kdfcctl_errors_alarm;
+	u8	unused02040[0x02040-0x02038];
+
+/*0x02040*/	u64	general_errors_reg;
+#define	VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW	vxge_mBIT(3)
+#define	VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW	vxge_mBIT(7)
+#define	VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW	vxge_mBIT(11)
+#define	VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR	vxge_mBIT(15)
+#define	VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ	vxge_mBIT(19)
+#define	VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS	vxge_mBIT(27)
+#define	VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET	vxge_mBIT(31)
+/*0x02048*/	u64	general_errors_mask;
+/*0x02050*/	u64	general_errors_alarm;
+/*0x02058*/	u64	pci_config_errors_reg;
+#define	VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_STATUS_ERR	vxge_mBIT(3)
+#define	VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_UNCOR_ERR	vxge_mBIT(7)
+#define	VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_COR_ERR	vxge_mBIT(11)
+/*0x02060*/	u64	pci_config_errors_mask;
+/*0x02068*/	u64	pci_config_errors_alarm;
+/*0x02070*/	u64	mrpcim_to_vpath_alarm_reg;
+#define	VXGE_HW_MRPCIM_TO_VPATH_ALARM_REG_PPIF_MRPCIM_TO_VPATH_ALARM \
+								vxge_mBIT(3)
+/*0x02078*/	u64	mrpcim_to_vpath_alarm_mask;
+/*0x02080*/	u64	mrpcim_to_vpath_alarm_alarm;
+/*0x02088*/	u64	srpcim_to_vpath_alarm_reg;
+#define	VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_PPIF_SRPCIM_TO_VPATH_ALARM(val) \
+							vxge_vBIT(val, 0, 17)
+/*0x02090*/	u64	srpcim_to_vpath_alarm_mask;
+/*0x02098*/	u64	srpcim_to_vpath_alarm_alarm;
+	u8	unused02108[0x02108-0x020a0];
+
+/*0x02108*/	u64	kdfcctl_status;
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_PRES(val) vxge_vBIT(val, 0, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_PRES(val) vxge_vBIT(val, 8, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_PRES(val) vxge_vBIT(val, 16, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_OVRWR(val) vxge_vBIT(val, 24, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_OVRWR(val) vxge_vBIT(val, 32, 8)
+#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_OVRWR(val) vxge_vBIT(val, 40, 8)
+/*0x02110*/	u64	rsthdlr_status;
+#define	VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_RESET	vxge_mBIT(3)
+#define VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_VPIN(val) vxge_vBIT(val, 6, 2)
+/*0x02118*/	u64	fifo0_status;
+#define VXGE_HW_FIFO0_STATUS_DBLGEN_FIFO0_RDIDX(val) vxge_vBIT(val, 0, 12)
+/*0x02120*/	u64	fifo1_status;
+#define VXGE_HW_FIFO1_STATUS_DBLGEN_FIFO1_RDIDX(val) vxge_vBIT(val, 0, 12)
+/*0x02128*/	u64	fifo2_status;
+#define VXGE_HW_FIFO2_STATUS_DBLGEN_FIFO2_RDIDX(val) vxge_vBIT(val, 0, 12)
+	u8	unused02158[0x02158-0x02130];
+
+/*0x02158*/	u64	tgt_illegal_access;
+#define VXGE_HW_TGT_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
+	u8	unused02200[0x02200-0x02160];
+
+/*0x02200*/	u64	vpath_general_cfg1;
+#define VXGE_HW_VPATH_GENERAL_CFG1_TC_VALUE(val) vxge_vBIT(val, 1, 3)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_DATA_BYTE_SWAPEN	vxge_mBIT(7)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_DATA_FLIPEN	vxge_mBIT(11)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN	vxge_mBIT(15)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_CTL_FLIPEN	vxge_mBIT(23)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_SWAPEN	vxge_mBIT(51)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_FLIPEN	vxge_mBIT(55)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_SWAPEN	vxge_mBIT(59)
+#define	VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_FLIPEN	vxge_mBIT(63)
+/*0x02208*/	u64	vpath_general_cfg2;
+#define VXGE_HW_VPATH_GENERAL_CFG2_SIZE_QUANTUM(val) vxge_vBIT(val, 1, 3)
+/*0x02210*/	u64	vpath_general_cfg3;
+#define	VXGE_HW_VPATH_GENERAL_CFG3_IGNORE_VPATH_RST_FOR_INTA	vxge_mBIT(3)
+	u8	unused02220[0x02220-0x02218];
+
+/*0x02220*/	u64	kdfcctl_cfg0;
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0	vxge_mBIT(1)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1	vxge_mBIT(2)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2	vxge_mBIT(3)
+#define	VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO0	vxge_mBIT(5)
+#define	VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO1	vxge_mBIT(6)
+#define	VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO2	vxge_mBIT(7)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO0	vxge_mBIT(9)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO1	vxge_mBIT(10)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO2	vxge_mBIT(11)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO0	vxge_mBIT(13)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO1	vxge_mBIT(14)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO2	vxge_mBIT(15)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO0	vxge_mBIT(17)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO1	vxge_mBIT(18)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO2	vxge_mBIT(19)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO0	vxge_mBIT(21)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO1	vxge_mBIT(22)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO2	vxge_mBIT(23)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO0	vxge_mBIT(25)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO1	vxge_mBIT(26)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO2	vxge_mBIT(27)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO0	vxge_mBIT(29)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO1	vxge_mBIT(30)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO2	vxge_mBIT(31)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO0	vxge_mBIT(33)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO1	vxge_mBIT(34)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO2	vxge_mBIT(35)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO0	vxge_mBIT(37)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO1	vxge_mBIT(38)
+#define	VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO2	vxge_mBIT(39)
+
+	u8	unused02268[0x02268-0x02228];
+
+/*0x02268*/	u64	stats_cfg;
+#define VXGE_HW_STATS_CFG_START_HOST_ADDR(val) vxge_vBIT(val, 0, 57)
+/*0x02270*/	u64	interrupt_cfg0;
+#define VXGE_HW_INTERRUPT_CFG0_MSIX_FOR_RXTI(val) vxge_vBIT(val, 1, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(val) vxge_vBIT(val, 9, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(val) vxge_vBIT(val, 17, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(val) vxge_vBIT(val, 25, 7)
+#define VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(val) vxge_vBIT(val, 33, 7)
+	u8	unused02280[0x02280-0x02278];
+
+/*0x02280*/	u64	interrupt_cfg2;
+#define VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
+/*0x02288*/	u64	one_shot_vect0_en;
+#define	VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN	vxge_mBIT(3)
+/*0x02290*/	u64	one_shot_vect1_en;
+#define	VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN	vxge_mBIT(3)
+/*0x02298*/	u64	one_shot_vect2_en;
+#define	VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN	vxge_mBIT(3)
+/*0x022a0*/	u64	one_shot_vect3_en;
+#define	VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN	vxge_mBIT(3)
+	u8	unused022b0[0x022b0-0x022a8];
+
+/*0x022b0*/	u64	pci_config_access_cfg1;
+#define VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(val) vxge_vBIT(val, 0, 12)
+#define	VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0	vxge_mBIT(15)
+/*0x022b8*/	u64	pci_config_access_cfg2;
+#define	VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ	vxge_mBIT(0)
+/*0x022c0*/	u64	pci_config_access_status;
+#define	VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR	vxge_mBIT(0)
+#define VXGE_HW_PCI_CONFIG_ACCESS_STATUS_DATA(val) vxge_vBIT(val, 32, 32)
+	u8	unused02300[0x02300-0x022c8];
+
+/*0x02300*/	u64	vpath_debug_stats0;
+#define VXGE_HW_VPATH_DEBUG_STATS0_INI_NUM_MWR_SENT(val) vxge_vBIT(val, 0, 32)
+/*0x02308*/	u64	vpath_debug_stats1;
+#define VXGE_HW_VPATH_DEBUG_STATS1_INI_NUM_MRD_SENT(val) vxge_vBIT(val, 0, 32)
+/*0x02310*/	u64	vpath_debug_stats2;
+#define VXGE_HW_VPATH_DEBUG_STATS2_INI_NUM_CPL_RCVD(val) vxge_vBIT(val, 0, 32)
+/*0x02318*/	u64	vpath_debug_stats3;
+#define VXGE_HW_VPATH_DEBUG_STATS3_INI_NUM_MWR_BYTE_SENT(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x02320*/	u64	vpath_debug_stats4;
+#define VXGE_HW_VPATH_DEBUG_STATS4_INI_NUM_CPL_BYTE_RCVD(val) \
+							vxge_vBIT(val, 0, 64)
+/*0x02328*/	u64	vpath_debug_stats5;
+#define VXGE_HW_VPATH_DEBUG_STATS5_WRCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
+/*0x02330*/	u64	vpath_debug_stats6;
+#define VXGE_HW_VPATH_DEBUG_STATS6_RDCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
+/*0x02338*/	u64	vpath_genstats_count01;
+#define	VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT1(val) \
+							vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT0(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x02340*/	u64	vpath_genstats_count23;
+#define	VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT3(val) \
+							vxge_vBIT(val, 0, 32)
+#define	VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT2(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x02348*/	u64	vpath_genstats_count4;
+#define	VXGE_HW_VPATH_GENSTATS_COUNT4_PPIF_VPATH_GENSTATS_COUNT4(val) \
+							vxge_vBIT(val, 32, 32)
+/*0x02350*/	u64	vpath_genstats_count5;
+#define	VXGE_HW_VPATH_GENSTATS_COUNT5_PPIF_VPATH_GENSTATS_COUNT5(val) \
+							vxge_vBIT(val, 32, 32)
+	u8	unused02648[0x02648-0x02358];
+} __attribute((packed));
+
+#define VXGE_HW_EEPROM_SIZE	(0x01 << 11)
+
+/* Capability lists */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED    0xf  /* Supported Link speeds */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH    0x3f0 /* Supported Link speeds. */
+#define  VXGE_HW_PCI_EXP_LNKCAP_LW_RES       0x0  /* Reserved. */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.c
new file mode 100644
index 0000000..0b1caf1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.c
@@ -0,0 +1,738 @@
+/*
+ * vxge-traffic.c: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#include <ipxe/netdevice.h>
+#include <errno.h>
+
+#include "vxge_traffic.h"
+#include "vxge_config.h"
+#include "vxge_main.h"
+
+/*
+ * vxge_hw_vpath_intr_enable - Enable vpath interrupts.
+ * @vpath: Virtual Path handle.
+ *
+ * Enable vpath interrupts. The function is to be executed the last in
+ * vpath initialization sequence.
+ *
+ * See also: vxge_hw_vpath_intr_disable()
+ */
+enum vxge_hw_status
+vxge_hw_vpath_intr_enable(struct __vxge_hw_virtualpath *vpath)
+{
+	struct vxge_hw_vpath_reg *vp_reg;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+		status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+	goto exit;
+	}
+
+	vp_reg = vpath->vp_reg;
+
+	writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->general_errors_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->pci_config_errors_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->mrpcim_to_vpath_alarm_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->srpcim_to_vpath_alarm_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->vpath_ppif_int_status);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->srpcim_msg_to_vpath_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->vpath_pcipif_int_status);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->prc_alarm_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->wrdma_alarm_status);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->asic_ntwk_vp_err_reg);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->xgmac_vp_int_status);
+
+	readq(&vp_reg->vpath_general_int_status);
+
+	/* Mask unwanted interrupts */
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->vpath_pcipif_int_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->srpcim_msg_to_vpath_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->srpcim_to_vpath_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->mrpcim_to_vpath_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->pci_config_errors_mask);
+
+	/* Unmask the individual interrupts */
+	writeq((u32)vxge_bVALn((VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW|
+		VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW|
+		VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ|
+		VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR), 0, 32),
+		&vp_reg->general_errors_mask);
+
+	__vxge_hw_pio_mem_write32_upper(
+		(u32)vxge_bVALn((VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR|
+		VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR|
+		VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON|
+		VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON|
+		VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR|
+		VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR), 0, 32),
+		&vp_reg->kdfcctl_errors_mask);
+
+	__vxge_hw_pio_mem_write32_upper(0, &vp_reg->vpath_ppif_int_mask);
+
+	__vxge_hw_pio_mem_write32_upper(
+		(u32)vxge_bVALn(VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP, 0, 32),
+		&vp_reg->prc_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper(0, &vp_reg->wrdma_alarm_mask);
+	__vxge_hw_pio_mem_write32_upper(0, &vp_reg->xgmac_vp_int_mask);
+
+	if (vpath->hldev->first_vp_id != vpath->vp_id)
+		__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->asic_ntwk_vp_err_mask);
+	else
+		__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn((
+		VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT|
+			VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK),
+			0, 32), &vp_reg->asic_ntwk_vp_err_mask);
+
+	__vxge_hw_pio_mem_write32_upper(0, &vp_reg->vpath_general_int_mask);
+exit:
+	return status;
+
+}
+
+/*
+ * vxge_hw_vpath_intr_disable - Disable vpath interrupts.
+ * @vpath: Virtual Path handle.
+ *
+ * Disable vpath interrupts. The function is to be executed the last in
+ * vpath initialization sequence.
+ *
+ * See also: vxge_hw_vpath_intr_enable()
+ */
+enum vxge_hw_status
+vxge_hw_vpath_intr_disable(struct __vxge_hw_virtualpath *vpath)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+	if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+		status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+		goto exit;
+	}
+	vp_reg = vpath->vp_reg;
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->vpath_general_int_mask);
+
+	writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->general_errors_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->pci_config_errors_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->mrpcim_to_vpath_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->srpcim_to_vpath_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->vpath_ppif_int_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->srpcim_msg_to_vpath_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->vpath_pcipif_int_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->wrdma_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->prc_alarm_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->xgmac_vp_int_mask);
+
+	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
+			&vp_reg->asic_ntwk_vp_err_mask);
+
+exit:
+	return status;
+}
+
+/**
+ * vxge_hw_device_mask_all - Mask all device interrupts.
+ * @hldev: HW device handle.
+ *
+ * Mask all device interrupts.
+ *
+ * See also: vxge_hw_device_unmask_all()
+ */
+void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+
+	val64 = VXGE_HW_TITAN_MASK_ALL_INT_ALARM |
+			VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
+
+	__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+			&hldev->common_reg->titan_mask_all_int);
+
+	return;
+}
+
+/**
+ * vxge_hw_device_unmask_all - Unmask all device interrupts.
+ * @hldev: HW device handle.
+ *
+ * Unmask all device interrupts.
+ *
+ * See also: vxge_hw_device_mask_all()
+ */
+void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev)
+{
+	u64 val64 = VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
+
+	__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
+			&hldev->common_reg->titan_mask_all_int);
+
+	return;
+}
+
+/**
+ * vxge_hw_device_intr_enable - Enable interrupts.
+ * @hldev: HW device handle.
+ *
+ * Enable Titan interrupts. The function is to be executed the last in
+ * Titan initialization sequence.
+ *
+ * See also: vxge_hw_device_intr_disable()
+ */
+void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	u32 val32;
+
+	vxge_hw_device_mask_all(hldev);
+
+	vxge_hw_vpath_intr_enable(&hldev->virtual_path);
+
+	val64 = hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+			hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX];
+
+	if (val64 != 0) {
+		writeq(val64, &hldev->common_reg->tim_int_status0);
+
+		writeq(~val64, &hldev->common_reg->tim_int_mask0);
+	}
+
+	val32 = hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+			hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX];
+
+	if (val32 != 0) {
+		__vxge_hw_pio_mem_write32_upper(val32,
+				&hldev->common_reg->tim_int_status1);
+
+		__vxge_hw_pio_mem_write32_upper(~val32,
+				&hldev->common_reg->tim_int_mask1);
+	}
+
+	val64 = readq(&hldev->common_reg->titan_general_int_status);
+
+	/* We have not enabled the top level interrupt yet.
+	 * This will be controlled from vxge_irq() entry api.
+	 */
+	return;
+}
+
+/**
+ * vxge_hw_device_intr_disable - Disable Titan interrupts.
+ * @hldev: HW device handle.
+ *
+ * Disable Titan interrupts.
+ *
+ * See also: vxge_hw_device_intr_enable()
+ */
+void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev)
+{
+	vxge_hw_device_mask_all(hldev);
+
+	/* mask all the tim interrupts */
+	writeq(VXGE_HW_INTR_MASK_ALL, &hldev->common_reg->tim_int_mask0);
+	__vxge_hw_pio_mem_write32_upper(VXGE_HW_DEFAULT_32,
+				&hldev->common_reg->tim_int_mask1);
+
+	vxge_hw_vpath_intr_disable(&hldev->virtual_path);
+
+	return;
+}
+
+/**
+ * vxge_hw_ring_rxd_post - Post descriptor on the ring.
+ * @ring: Handle to the ring object used for receive
+ * @rxdh: Descriptor obtained via vxge_hw_ring_rxd_reserve().
+ *
+ * Post	descriptor on the ring.
+ * Prior to posting the	descriptor should be filled in accordance with
+ * Host/Titan interface specification for a given service (LL, etc.).
+ */
+void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring __unused,
+				struct vxge_hw_ring_rxd_1 *rxdp)
+{
+	rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+}
+
+/**
+ * __vxge_hw_non_offload_db_post - Post non offload doorbell
+ *
+ * @fifo: fifohandle
+ * @txdl_ptr: The starting location of the TxDL in host memory
+ * @num_txds: The highest TxD in this TxDL (0 to 255 means 1 to 256)
+ *
+ * This function posts a non-offload doorbell to doorbell FIFO
+ *
+ */
+static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo,
+	u64 txdl_ptr, u32 num_txds)
+{
+	writeq(VXGE_HW_NODBW_TYPE(VXGE_HW_NODBW_TYPE_NODBW) |
+		VXGE_HW_NODBW_LAST_TXD_NUMBER(num_txds),
+		&fifo->nofl_db->control_0);
+
+	wmb();
+
+	writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr);
+
+	wmb();
+}
+
+/**
+ * vxge_hw_fifo_free_txdl_get: fetch next available txd in the fifo
+ *
+ * @fifo: tx channel handle
+ */
+struct vxge_hw_fifo_txd *
+	vxge_hw_fifo_free_txdl_get(struct __vxge_hw_fifo *fifo)
+{
+	struct vxge_hw_fifo_txd *txdp;
+
+	txdp = fifo->txdl + fifo->sw_offset;
+	if (txdp->control_0 & VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER) {
+		vxge_debug(VXGE_ERR, "%s:%d, error: txd(%d) owned by hw\n",
+				__func__, __LINE__, fifo->sw_offset);
+		return NULL;
+	}
+
+	return txdp;
+}
+/**
+ * vxge_hw_fifo_txdl_buffer_set - Set transmit buffer pointer in the
+ * descriptor.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdlh: Descriptor handle.
+ * @iob: data buffer.
+ */
+void vxge_hw_fifo_txdl_buffer_set(struct __vxge_hw_fifo *fifo,
+			struct vxge_hw_fifo_txd *txdp,
+			struct io_buffer *iob)
+{
+	txdp->control_0 = VXGE_HW_FIFO_TXD_GATHER_CODE(
+			VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST);
+	txdp->control_0 |= VXGE_HW_FIFO_TXD_BUFFER_SIZE(iob_len(iob));
+
+	txdp->control_1 = VXGE_HW_FIFO_TXD_INT_NUMBER(fifo->tx_intr_num);
+	txdp->control_1 |= VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST;
+
+	txdp->host_control = (intptr_t)iob;
+	txdp->buffer_pointer = virt_to_bus(iob->data);
+}
+
+/**
+ * vxge_hw_fifo_txdl_post - Post descriptor on the fifo channel.
+ * @fifo: Handle to the fifo object used for non offload send
+ * @txdp: Tx Descriptor
+ *
+ * Post descriptor on the 'fifo' type channel for transmission.
+ * Prior to posting the descriptor should be filled in accordance with
+ * Host/Titan interface specification for a given service (LL, etc.).
+ *
+ */
+void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo,
+			struct vxge_hw_fifo_txd *txdp)
+{
+	txdp->control_0 |= VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER;
+
+	__vxge_hw_non_offload_db_post(fifo, (u64) virt_to_bus(txdp), 0);
+
+	vxge_hw_fifo_txd_offset_up(&fifo->sw_offset);
+}
+
+/*
+ * __vxge_hw_vpath_alarm_process - Process Alarms.
+ * @vpath: Virtual Path.
+ * @skip_alarms: Do not clear the alarms
+ *
+ * Process vpath alarms.
+ *
+ */
+static enum vxge_hw_status __vxge_hw_vpath_alarm_process(
+			struct __vxge_hw_virtualpath *vpath)
+{
+	u64 val64;
+	u64 alarm_status;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __vxge_hw_device *hldev = NULL;
+	struct vxge_hw_vpath_reg *vp_reg;
+
+	hldev = vpath->hldev;
+	vp_reg = vpath->vp_reg;
+	alarm_status = readq(&vp_reg->vpath_general_int_status);
+
+	if (alarm_status == VXGE_HW_ALL_FOXES) {
+
+		vxge_debug(VXGE_ERR, "%s: %s:%d, slot freeze error\n",
+			hldev->ndev->name, __func__, __LINE__);
+		status = VXGE_HW_ERR_SLOT_FREEZE;
+		goto out;
+	}
+
+	if (alarm_status & ~(
+		VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT |
+		VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT |
+		VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT |
+		VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) {
+
+		vxge_debug(VXGE_ERR, "%s: %s:%d, Unknown vpath alarm\n",
+			hldev->ndev->name, __func__, __LINE__);
+		status = VXGE_HW_FAIL;
+		goto out;
+	}
+
+	if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) {
+
+		val64 = readq(&vp_reg->xgmac_vp_int_status);
+
+		if (val64 &
+		VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) {
+
+			val64 = readq(&vp_reg->asic_ntwk_vp_err_reg);
+
+			if (((val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) &&
+			    (!(val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) ||
+			    ((val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
+				&& (!(val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
+			))) {
+				writeq(VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT,
+					&vp_reg->asic_ntwk_vp_err_mask);
+
+				netdev_link_down(hldev->ndev);
+				vxge_debug(VXGE_INTR, "%s: %s:%d link down\n",
+					hldev->ndev->name, __func__, __LINE__);
+			}
+
+			if (((val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) &&
+			    (!(val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) ||
+			    ((val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
+				&& (!(val64 &
+				VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
+			))) {
+				writeq(VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK,
+					&vp_reg->asic_ntwk_vp_err_mask);
+
+				netdev_link_up(hldev->ndev);
+				vxge_debug(VXGE_INTR, "%s: %s:%d link up\n",
+					hldev->ndev->name, __func__, __LINE__);
+			}
+
+			writeq(VXGE_HW_INTR_MASK_ALL,
+				&vp_reg->asic_ntwk_vp_err_reg);
+		}
+	} else {
+		vxge_debug(VXGE_INFO, "%s: %s:%d unhandled alarm %llx\n",
+				hldev->ndev->name, __func__, __LINE__,
+				alarm_status);
+	}
+out:
+	return status;
+}
+
+/**
+ * vxge_hw_device_clear_tx_rx - Acknowledge (that is, clear) the
+ * condition that has caused the Tx and RX interrupt.
+ * @hldev: HW device.
+ *
+ * Acknowledge (that is, clear) the condition that has caused
+ * the Tx and Rx interrupt.
+ * See also: vxge_hw_device_begin_irq(),
+ * vxge_hw_device_mask_tx_rx(), vxge_hw_device_unmask_tx_rx().
+ */
+void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
+{
+
+	if ((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
+			(hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
+		writeq((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
+			hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX]),
+			&hldev->common_reg->tim_int_status0);
+	}
+
+	if ((hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
+			(hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
+		__vxge_hw_pio_mem_write32_upper(
+			(hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
+			hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]),
+			&hldev->common_reg->tim_int_status1);
+	}
+
+	return;
+}
+
+
+/**
+ * vxge_hw_device_begin_irq - Begin IRQ processing.
+ * @hldev: HW device handle.
+ *
+ * The function performs two actions, It first checks whether (shared IRQ) the
+ * interrupt was raised by the device. Next, it masks the device interrupts.
+ *
+ * Note:
+ * vxge_hw_device_begin_irq() does not flush MMIO writes through the
+ * bridge. Therefore, two back-to-back interrupts are potentially possible.
+ *
+ * Returns: 0, if the interrupt is not "ours" (note that in this case the
+ * device remain enabled).
+ * Otherwise, vxge_hw_device_begin_irq() returns 64bit general adapter
+ * status.
+ */
+enum vxge_hw_status
+vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev)
+{
+	u64 val64;
+	u64 adapter_status;
+	u64 vpath_mask;
+	enum vxge_hw_status ret = VXGE_HW_OK;
+
+	val64 = readq(&hldev->common_reg->titan_general_int_status);
+
+	if (!val64) {
+		ret = VXGE_HW_ERR_WRONG_IRQ;
+		goto exit;
+	}
+
+	if (val64 == VXGE_HW_ALL_FOXES) {
+
+		adapter_status = readq(&hldev->common_reg->adapter_status);
+
+		if (adapter_status == VXGE_HW_ALL_FOXES) {
+
+			vxge_debug(VXGE_ERR, "%s: %s:%d critical error "
+				"occurred\n", hldev->ndev->name,
+				__func__, __LINE__);
+			ret = VXGE_HW_ERR_SLOT_FREEZE;
+			goto exit;
+		}
+	}
+
+	vpath_mask = hldev->vpaths_deployed >>
+				(64 - VXGE_HW_MAX_VIRTUAL_PATHS);
+	if (val64 & VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(
+				vpath_mask))
+		vxge_hw_device_clear_tx_rx(hldev);
+
+	if (val64 & VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT)
+		ret = __vxge_hw_vpath_alarm_process(&hldev->virtual_path);
+
+exit:
+	return ret;
+}
+
+/**
+ * vxge_hw_vpath_doorbell_rx - Indicates to hw the qwords of receive
+ * descriptors posted.
+ * @ring: Handle to the ring object used for receive
+ *
+ * The function writes the number of qwords of rxds posted during replishment.
+ * Since the function is called frequently, a flush is not required to post the
+ * write transaction. At the very least, the previous write will be flushed
+ * once the subsequent write is made.
+ *
+ * Returns: None.
+ */
+void vxge_hw_vpath_doorbell_rx(struct __vxge_hw_ring *ring)
+{
+	u32 rxds_qw_per_block = VXGE_HW_MAX_RXDS_PER_BLOCK_1 *
+		VXGE_HW_RING_RXD_QWORDS_MODE_1;
+
+	ring->doorbell_cnt += VXGE_HW_RING_RXD_QWORDS_MODE_1;
+
+	ring->total_db_cnt += VXGE_HW_RING_RXD_QWORDS_MODE_1;
+
+	if (ring->total_db_cnt >= rxds_qw_per_block) {
+		/* For each block add 4 more qwords */
+		ring->doorbell_cnt += VXGE_HW_RING_RXD_QWORDS_MODE_1;
+
+		/* Reset total count */
+		ring->total_db_cnt -= rxds_qw_per_block;
+	}
+
+	if (ring->doorbell_cnt >= ring->rxd_qword_limit) {
+		wmb();
+		writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(
+			ring->doorbell_cnt),
+			&ring->vp_reg->prc_rxd_doorbell);
+		ring->doorbell_cnt = 0;
+	}
+}
+
+/**
+ * vxge_hw_vpath_poll_rx - Poll Rx Virtual Path for completed
+ * descriptors and process the same.
+ * @ring: Handle to the ring object used for receive
+ *
+ * The function	polls the Rx for the completed	descriptors.
+ */
+#define ETH_FCS_LEN	4
+enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring)
+{
+	struct __vxge_hw_device *hldev;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_ring_rxd_1 *rxd;
+	unsigned int len;
+	enum vxge_hw_ring_tcode tcode;
+	struct io_buffer *rx_iob, *iobuf = NULL;
+	u16 poll_count = 0;
+
+	hldev = ring->vpathh->hldev;
+
+	do {
+		rxd = &ring->rxdl->rxd[ring->rxd_offset];
+		tcode = VXGE_HW_RING_RXD_T_CODE_GET(rxd->control_0);
+
+		/* if tcode is VXGE_HW_RING_T_CODE_FRM_DROP, it is
+		 * possible the ownership bit still set to adapter
+		 */
+		if ((rxd->control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER)
+			&& (tcode == VXGE_HW_RING_T_CODE_OK)) {
+
+			status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
+			goto err0;
+		}
+
+		vxge_debug(VXGE_INFO, "%s: rx frame received at offset %d\n",
+			hldev->ndev->name, ring->rxd_offset);
+
+		if (tcode != VXGE_HW_RING_T_CODE_OK) {
+			netdev_rx_err(hldev->ndev, NULL, -EINVAL);
+			vxge_debug(VXGE_ERR, "%s:%d, rx error tcode %d\n",
+				__func__, __LINE__, tcode);
+			status = VXGE_HW_FAIL;
+			goto err1;
+		}
+
+		iobuf = (struct io_buffer *)(intptr_t)rxd->host_control;
+
+		len = VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(rxd->control_1);
+		len -= ETH_FCS_LEN;
+
+		rx_iob = alloc_iob(len);
+		if (!rx_iob) {
+			netdev_rx_err(hldev->ndev, NULL, -ENOMEM);
+			vxge_debug(VXGE_ERR, "%s:%d, alloc_iob error\n",
+				__func__, __LINE__);
+			status = VXGE_HW_ERR_OUT_OF_MEMORY;
+			goto err1;
+		}
+
+		memcpy(iob_put(rx_iob, len), iobuf->data, len);
+		/* Add this packet to the receive queue. */
+		netdev_rx(hldev->ndev, rx_iob);
+
+err1:
+		/* repost the rxd */
+		rxd->control_0 = rxd->control_1 = 0;
+		vxge_hw_ring_rxd_1b_set(rxd, iobuf,
+				VXGE_LL_MAX_FRAME_SIZE(hldev->vdev));
+		vxge_hw_ring_rxd_post(ring, rxd);
+
+		/* repost the qword count for doorbell */
+		vxge_hw_vpath_doorbell_rx(ring);
+
+		/* increment the descriptor offset */
+		vxge_hw_ring_rxd_offset_up(&ring->rxd_offset);
+
+	} while (++poll_count < ring->rx_poll_weight);
+err0:
+	return status;
+}
+
+/**
+ * vxge_hw_vpath_poll_tx - Poll Tx for completed descriptors and process
+ * the same.
+ * @fifo: Handle to the fifo object used for non offload send
+ *
+ * The function	polls the Tx for the completed	descriptors and	calls
+ * the driver via supplied completion callback.
+ */
+enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_fifo_txd *txdp;
+
+	txdp = fifo->txdl + fifo->hw_offset;
+	if (!(txdp->control_0 & VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER)
+		&& (txdp->host_control)) {
+
+		vxge_xmit_compl(fifo, txdp,
+			VXGE_HW_FIFO_TXD_T_CODE_GET(txdp->control_0));
+
+		vxge_hw_fifo_txd_offset_up(&fifo->hw_offset);
+	}
+
+	return status;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.h
new file mode 100644
index 0000000..ed72be1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_traffic.h
@@ -0,0 +1,309 @@
+/*
+ * vxge-traffic.h: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#ifndef VXGE_TRAFFIC_H
+#define VXGE_TRAFFIC_H
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+
+#include "vxge_reg.h"
+#include "vxge_version.h"
+
+#define VXGE_HW_DTR_MAX_T_CODE		16
+#define VXGE_HW_ALL_FOXES		0xFFFFFFFFFFFFFFFFULL
+#define VXGE_HW_INTR_MASK_ALL		0xFFFFFFFFFFFFFFFFULL
+#define	VXGE_HW_MAX_VIRTUAL_PATHS	17
+
+#define VXGE_HW_MAX_VIRTUAL_FUNCTIONS	8
+
+#define VXGE_HW_MAC_MAX_MAC_PORT_ID	3
+
+#define VXGE_HW_DEFAULT_32		0xffffffff
+/* frames sizes */
+#define VXGE_HW_HEADER_802_2_SIZE	3
+#define VXGE_HW_HEADER_SNAP_SIZE	5
+#define VXGE_HW_HEADER_VLAN_SIZE	4
+#define VXGE_HW_MAC_HEADER_MAX_SIZE \
+			(ETH_HLEN + \
+			VXGE_HW_HEADER_802_2_SIZE + \
+			VXGE_HW_HEADER_VLAN_SIZE + \
+			VXGE_HW_HEADER_SNAP_SIZE)
+
+/* 32bit alignments */
+
+/* A receive data corruption can occur resulting in either a single-bit or
+double-bit ECC error being flagged in the ASIC if the starting offset of a
+buffer in single buffer mode is 0x2 to 0xa. The single bit ECC error will not
+lock up the card but can hide the data corruption while the double-bit ECC
+error will lock up the card. Limiting the starting offset of the buffers to
+0x0, 0x1 or to a value greater than 0xF will workaround this issue.
+VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN of 2 causes the starting offset of
+buffer to be 0x2, 0x12 and so on, to have the start of the ip header dword
+aligned. The start of buffer of 0x2 will cause this problem to occur. To
+avoid this problem in all cases, add 0x10 to 0x2, to ensure that the start of
+buffer is outside of the problem causing offsets.
+*/
+#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN		0x12
+#define VXGE_HW_HEADER_802_2_SNAP_ALIGN			2
+#define VXGE_HW_HEADER_802_2_ALIGN			3
+#define VXGE_HW_HEADER_SNAP_ALIGN			1
+
+#define VXGE_HW_L3_CKSUM_OK				0xFFFF
+#define VXGE_HW_L4_CKSUM_OK				0xFFFF
+
+/* Forward declarations */
+struct __vxge_hw_device;
+struct __vxge_hw_virtualpath;
+struct __vxge_hw_fifo;
+struct __vxge_hw_ring;
+struct vxge_hw_ring_rxd_1;
+struct vxge_hw_fifo_txd;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*VXGE_HW_STATUS_H*/
+#define VXGE_HW_EVENT_BASE                      0
+#define VXGE_LL_EVENT_BASE                      100
+
+/**
+ * enum vxge_hw_event- Enumerates slow-path HW events.
+ * @VXGE_HW_EVENT_UNKNOWN: Unknown (and invalid) event.
+ * @VXGE_HW_EVENT_SERR: Serious vpath hardware error event.
+ * @VXGE_HW_EVENT_ECCERR: vpath ECC error event.
+ * @VXGE_HW_EVENT_VPATH_ERR: Error local to the respective vpath
+ * @VXGE_HW_EVENT_FIFO_ERR: FIFO Doorbell fifo error.
+ * @VXGE_HW_EVENT_SRPCIM_SERR: srpcim hardware error event.
+ * @VXGE_HW_EVENT_MRPCIM_SERR: mrpcim hardware error event.
+ * @VXGE_HW_EVENT_MRPCIM_ECCERR: mrpcim ecc error event.
+ * @VXGE_HW_EVENT_RESET_START: Privileged entity is starting device reset
+ * @VXGE_HW_EVENT_RESET_COMPLETE: Device reset has been completed
+ * @VXGE_HW_EVENT_SLOT_FREEZE: Slot-freeze event. Driver tries to distinguish
+ * slot-freeze from the rest critical events (e.g. ECC) when it is
+ * impossible to PIO read "through" the bus, i.e. when getting all-foxes.
+ *
+ * enum vxge_hw_event enumerates slow-path HW eventis.
+ *
+ * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{},
+ * vxge_uld_link_down_f{}.
+ */
+enum vxge_hw_event {
+	VXGE_HW_EVENT_UNKNOWN           = 0,
+	/* HW events */
+	VXGE_HW_EVENT_RESET_START       = VXGE_HW_EVENT_BASE + 1,
+	VXGE_HW_EVENT_RESET_COMPLETE    = VXGE_HW_EVENT_BASE + 2,
+	VXGE_HW_EVENT_LINK_DOWN         = VXGE_HW_EVENT_BASE + 3,
+	VXGE_HW_EVENT_LINK_UP           = VXGE_HW_EVENT_BASE + 4,
+	VXGE_HW_EVENT_ALARM_CLEARED     = VXGE_HW_EVENT_BASE + 5,
+	VXGE_HW_EVENT_ECCERR            = VXGE_HW_EVENT_BASE + 6,
+	VXGE_HW_EVENT_MRPCIM_ECCERR     = VXGE_HW_EVENT_BASE + 7,
+	VXGE_HW_EVENT_FIFO_ERR          = VXGE_HW_EVENT_BASE + 8,
+	VXGE_HW_EVENT_VPATH_ERR         = VXGE_HW_EVENT_BASE + 9,
+	VXGE_HW_EVENT_CRITICAL_ERR      = VXGE_HW_EVENT_BASE + 10,
+	VXGE_HW_EVENT_SERR              = VXGE_HW_EVENT_BASE + 11,
+	VXGE_HW_EVENT_SRPCIM_SERR       = VXGE_HW_EVENT_BASE + 12,
+	VXGE_HW_EVENT_MRPCIM_SERR       = VXGE_HW_EVENT_BASE + 13,
+	VXGE_HW_EVENT_SLOT_FREEZE       = VXGE_HW_EVENT_BASE + 14,
+};
+
+#define VXGE_HW_MAX_INTR_PER_VP        4
+#define VXGE_HW_VPATH_INTR_TX          0
+#define VXGE_HW_VPATH_INTR_RX          1
+#define VXGE_HW_VPATH_INTR_EINTA       2
+#define VXGE_HW_VPATH_INTR_BMAP        3
+
+#define VXGE_HW_BLOCK_SIZE             4096
+
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL         17
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL         18
+#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_RX_AVE_NET_UTIL  19
+#define VXGE_HW_TIM_UTIL_SEL_PER_VPATH                  63
+
+/**
+ * enum vxge_hw_ring_tcode - Transfer codes returned by adapter
+ * @VXGE_HW_RING_T_CODE_OK: Transfer ok.
+ * @VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH: Layer 3 checksum presentation
+ *		configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH: Layer 4 checksum presentation
+ *		configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH: Layer 3 and Layer 4 checksum
+ *		presentation configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L3_PKT_ERR: Layer 3 error unparseable packet,
+ *		such as unknown IPv6 header.
+ * @VXGE_HW_RING_T_CODE_L2_FRM_ERR: Layer 2 error frame integrity
+ *		error, such as FCS or ECC).
+ * @VXGE_HW_RING_T_CODE_BUF_SIZE_ERR: Buffer size error the RxD buffer(
+ *		s) were not appropriately sized and data loss occurred.
+ * @VXGE_HW_RING_T_CODE_INT_ECC_ERR: Internal ECC error RxD corrupted.
+ * @VXGE_HW_RING_T_CODE_BENIGN_OVFLOW: Benign overflow the contents of
+ *		Segment1 exceeded the capacity of Buffer1 and the remainder
+ *		was placed in Buffer2. Segment2 now starts in Buffer3.
+ *		No data loss or errors occurred.
+ * @VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF: Buffer size 0 one of the RxDs
+ *		assigned buffers has a size of 0 bytes.
+ * @VXGE_HW_RING_T_CODE_FRM_DROP: Frame dropped either due to
+ *		VPath Reset or because of a VPIN mismatch.
+ * @VXGE_HW_RING_T_CODE_UNUSED: Unused
+ * @VXGE_HW_RING_T_CODE_MULTI_ERR: Multiple errors more than one
+ *		transfer code condition occurred.
+ *
+ * Transfer codes returned by adapter.
+ */
+enum vxge_hw_ring_tcode {
+	VXGE_HW_RING_T_CODE_OK				= 0x0,
+	VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH		= 0x1,
+	VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH		= 0x2,
+	VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH	= 0x3,
+	VXGE_HW_RING_T_CODE_L3_PKT_ERR			= 0x5,
+	VXGE_HW_RING_T_CODE_L2_FRM_ERR			= 0x6,
+	VXGE_HW_RING_T_CODE_BUF_SIZE_ERR		= 0x7,
+	VXGE_HW_RING_T_CODE_INT_ECC_ERR			= 0x8,
+	VXGE_HW_RING_T_CODE_BENIGN_OVFLOW		= 0x9,
+	VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF		= 0xA,
+	VXGE_HW_RING_T_CODE_FRM_DROP			= 0xC,
+	VXGE_HW_RING_T_CODE_UNUSED			= 0xE,
+	VXGE_HW_RING_T_CODE_MULTI_ERR			= 0xF
+};
+
+
+/**
+ * enum enum vxge_hw_fifo_gather_code - Gather codes used in fifo TxD
+ * @VXGE_HW_FIFO_GATHER_CODE_FIRST: First TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_MIDDLE: Middle TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_LAST: Last TxDL
+ * @VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST: First and Last TxDL.
+ *
+ * These gather codes are used to indicate the position of a TxD in a TxD list
+ */
+enum vxge_hw_fifo_gather_code {
+	VXGE_HW_FIFO_GATHER_CODE_FIRST		= 0x2,
+	VXGE_HW_FIFO_GATHER_CODE_MIDDLE		= 0x0,
+	VXGE_HW_FIFO_GATHER_CODE_LAST		= 0x1,
+	VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST	= 0x3
+};
+
+/**
+ * enum enum vxge_hw_fifo_tcode - tcodes used in fifo
+ * @VXGE_HW_FIFO_T_CODE_OK: Transfer OK
+ * @VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT: PCI read transaction (either TxD or
+ *             frame data) returned with corrupt data.
+ * @VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL:PCI read transaction was returned
+ *             with no data.
+ * @VXGE_HW_FIFO_T_CODE_INVALID_MSS: The host attempted to send either a
+ *             frame or LSO MSS that was too long (>9800B).
+ * @VXGE_HW_FIFO_T_CODE_LSO_ERROR: Error detected during TCP/UDP Large Send
+	*	       Offload operation, due to improper header template,
+	*	       unsupported protocol, etc.
+ * @VXGE_HW_FIFO_T_CODE_UNUSED: Unused
+ * @VXGE_HW_FIFO_T_CODE_MULTI_ERROR: Set to 1 by the adapter if multiple
+ *             data buffer transfer errors are encountered (see below).
+ *             Otherwise it is set to 0.
+ *
+ * These tcodes are returned in various API for TxD status
+ */
+enum vxge_hw_fifo_tcode {
+	VXGE_HW_FIFO_T_CODE_OK			= 0x0,
+	VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT	= 0x1,
+	VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL	= 0x2,
+	VXGE_HW_FIFO_T_CODE_INVALID_MSS		= 0x3,
+	VXGE_HW_FIFO_T_CODE_LSO_ERROR		= 0x4,
+	VXGE_HW_FIFO_T_CODE_UNUSED		= 0x7,
+	VXGE_HW_FIFO_T_CODE_MULTI_ERROR		= 0x8
+};
+
+enum vxge_hw_status
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring);
+
+void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring_handle,
+		struct vxge_hw_ring_rxd_1 *rxdp);
+
+void vxge_hw_fifo_txdl_buffer_set(struct __vxge_hw_fifo *fifo,
+		struct vxge_hw_fifo_txd *txdp,
+		struct io_buffer *iob);
+
+void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo,
+		struct vxge_hw_fifo_txd *txdp);
+
+enum vxge_hw_status __vxge_hw_ring_create(
+	struct __vxge_hw_virtualpath *vpath,
+	struct __vxge_hw_ring *ring);
+
+enum vxge_hw_status __vxge_hw_ring_delete(
+	struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status __vxge_hw_fifo_create(
+	struct __vxge_hw_virtualpath *vpath,
+	struct __vxge_hw_fifo *fifo);
+
+enum vxge_hw_status
+__vxge_hw_fifo_delete(struct __vxge_hw_fifo *fifo);
+
+enum vxge_hw_status __vxge_hw_vpath_reset(
+	struct __vxge_hw_device *devh, u32 vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_enable(struct __vxge_hw_device *devh, u32 vp_id);
+
+void
+__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *devh, u32 vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh);
+
+enum vxge_hw_status
+__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *devh, u32 vp_id);
+
+enum vxge_hw_status
+__vxge_hw_vpath_initialize(struct __vxge_hw_device *devh, u32 vp_id);
+
+enum vxge_hw_status __vxge_hw_vp_initialize(
+	struct __vxge_hw_device *hldev, u32 vp_id,
+	struct __vxge_hw_virtualpath *vpath);
+
+void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev,
+			struct __vxge_hw_virtualpath *vpath);
+
+enum vxge_hw_status
+vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev);
+
+void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev);
+
+void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev);
+
+void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev);
+
+void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev);
+
+void vxge_hw_vpath_doorbell_rx(struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ringh);
+
+enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo);
+
+struct vxge_hw_fifo_txd *
+vxge_hw_fifo_free_txdl_get(struct __vxge_hw_fifo *fifo);
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_version.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_version.h
new file mode 100644
index 0000000..1475b77
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/vxge/vxge_version.h
@@ -0,0 +1,40 @@
+/*
+ * vxge-version.h: iPXE driver for Neterion Inc's X3100 Series 10GbE
+ *              PCIe I/O Virtualized Server Adapter.
+ *
+ * Copyright(c) 2002-2010 Neterion Inc.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference.  Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ */
+
+FILE_LICENCE(GPL2_ONLY);
+
+#ifndef VXGE_VERSION_H
+
+#define VXGE_VERSION_H
+
+/* ipxe vxge driver version fields.
+ * Note: Each field must be a nibble size
+ */
+#define VXGE_VERSION_MAJOR	3
+#define VXGE_VERSION_MINOR	5
+#define VXGE_VERSION_FIX	0
+#define VXGE_VERSION_BUILD	1
+
+#define VXGE_FW_VER(major, minor, build) \
+	(((major) << 16) + ((minor) << 8) + (build))
+
+/* Certified FW version. */
+#define VXGE_CERT_FW_VER_MAJOR	1
+#define VXGE_CERT_FW_VER_MINOR	6
+#define VXGE_CERT_FW_VER_BUILD	0
+
+#define VXGE_CERT_FW_VER 	VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, 	\
+				VXGE_CERT_FW_VER_MINOR,	VXGE_CERT_FW_VER_BUILD)
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/w89c840.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/w89c840.c
new file mode 100644
index 0000000..b314955
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/w89c840.c
@@ -0,0 +1,964 @@
+/*
+ * Etherboot -  BOOTP/TFTP Bootstrap Program
+ *
+ * w89c840.c -- This file implements the winbond-840 driver for etherboot.
+ *
+ */
+
+/*
+ * Adapted by Igor V. Kovalenko
+ *  -- <garrison at mail.ru>
+ *   OR
+ *  -- <iko at crec.mipt.ru>
+ * Initial adaptaion stage, including testing, completed 23 August 2000.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ *              date       version  by   what
+ *  Written:    Aug 20 2000  V0.10  iko  Initial revision.
+ * changes:     Aug 22 2000  V0.90  iko  Works!
+ *              Aug 23 2000  V0.91  iko  Cleanup, posted to etherboot
+ *                                       maintainer.
+ *              Aug 26 2000  V0.92  iko  Fixed Rx ring handling.
+ *                                       First Linux Kernel (TM)
+ *                                       successfully loaded using
+ *                                       this driver.
+ *              Jan 07 2001  V0.93  iko  Transmitter timeouts are handled
+ *                                       using timer2 routines. Proposed
+ *                                       by Ken Yap to eliminate CPU speed
+ *                                       dependency.
+ *             Dec 12 2003  V0.94   timlegge	Fixed issues in 5.2, removed 
+ *             					interrupt usage, enabled
+ *             					multicast support
+ *
+ * This is the etherboot driver for cards based on Winbond W89c840F chip.
+ *
+ * It was written from skeleton source, with Donald Becker's winbond-840.c
+ * kernel driver as a guideline. Mostly the w89c840 related definitions
+ * and the lower level routines have been cut-and-pasted into this source.
+ *
+ * Frankly speaking, about 90% of the code was obtained using cut'n'paste
+ * sequence :) while the remainder appeared while brainstorming
+ * Linux Kernel 2.4.0-testX source code. Thanks, Donald and Linus!
+ *
+ * There was a demand for using this card in a rather large
+ * remote boot environment at MSKP OVTI Lab of
+ * Moscow Institute for Physics and Technology (MIPT) -- http://www.mipt.ru/
+ * so you may count that for motivation.
+ *
+ */
+
+/*
+ * If you want to see debugging output then define W89C840_DEBUG
+ */
+
+/*
+#define W89C840_DEBUG
+*/
+
+/*
+ * Keep using IO_OPS for Etherboot driver!
+ */
+#define USE_IO_OPS
+
+#include "etherboot.h"
+#include "nic.h"
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+
+static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
+
+/* Linux support functions */
+#define virt_to_le32desc(addr)  virt_to_bus(addr)
+#define le32desc_to_virt(addr)  bus_to_virt(addr)
+
+/*
+#define cpu_to_le32(val) (val)
+#define le32_to_cpu(val) (val)
+*/
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.
+   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE    2
+#define RX_RING_SIZE    2
+
+/* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
+   To avoid overflowing we don't queue again until we have room for a
+   full-size packet.
+ */
+#define TX_FIFO_SIZE (2048)
+#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (10*1000)
+
+#define PKT_BUF_SZ  1536  /* Size of each temporary Rx buffer.*/
+
+/*
+ * Used to be this much CPU loops on Celeron at 400 (?),
+ * now using real timer and TX_TIMEOUT!
+ * #define TX_LOOP_COUNT 10000000
+ */
+
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
+
+#ifdef USE_IO_OPS
+#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
+#else
+#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
+#endif
+
+static u32 driver_flags = CanHaveMII | HasBrokenTx;
+
+/* This driver was written to use PCI memory space, however some x86 systems
+   work only with I/O space accesses.  Pass -DUSE_IO_OPS to use PCI I/O space
+   accesses instead of memory space. */
+
+#ifdef USE_IO_OPS
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the Command and Status Registers, "CSRs".
+   While similar to the Tulip, these registers are longword aligned.
+   Note: It's not useful to define symbolic names for every register bit in
+   the device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+*/
+enum w840_offsets {
+    PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
+    RxRingPtr=0x0C, TxRingPtr=0x10,
+    IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
+    RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
+    CurRxDescAddr=0x30, CurRxBufAddr=0x34,            /* Debug use */
+    MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
+    CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
+};
+
+/* Bits in the interrupt status/enable registers. */
+/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
+enum intr_status_bits {
+    NormalIntr=0x10000, AbnormalIntr=0x8000,
+    IntrPCIErr=0x2000, TimerInt=0x800,
+    IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
+    TxFIFOUnderflow=0x20, RxErrIntr=0x10,
+    TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
+};
+
+/* Bits in the NetworkConfig register. */
+enum rx_mode_bits {
+    AcceptErr=0x80, AcceptRunt=0x40,
+    AcceptBroadcast=0x20, AcceptMulticast=0x10,
+    AcceptAllPhys=0x08, AcceptMyPhys=0x02,
+};
+
+enum mii_reg_bits {
+    MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
+    MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
+};
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct w840_rx_desc {
+    s32 status;
+    s32 length;
+    u32 buffer1;
+    u32 next_desc;
+};
+
+struct w840_tx_desc {
+    s32 status;
+    s32 length;
+    u32 buffer1, buffer2;                /* We use only buffer 1.  */
+};
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+    DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
+    DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
+    DescIntr=0x80000000,
+};
+#define PRIV_ALIGN    15     /* Required alignment mask */
+#define PRIV_ALIGN_BYTES 32
+
+static struct winbond_private
+{
+    /* Descriptor rings first for alignment. */
+    struct w840_rx_desc rx_ring[RX_RING_SIZE];
+    struct w840_tx_desc tx_ring[TX_RING_SIZE];
+    struct net_device *next_module;        /* Link for devices of this type. */
+    void *priv_addr;                    /* Unaligned address for kfree */
+    const char *product_name;
+    /* Frequently used values: keep some adjacent for cache effect. */
+    int chip_id, drv_flags;
+    struct pci_dev *pci_dev;
+    int csr6;
+    struct w840_rx_desc *rx_head_desc;
+    unsigned int cur_rx, dirty_rx;        /* Producer/consumer ring indices */
+    unsigned int rx_buf_sz;                /* Based on MTU+slack. */
+    unsigned int cur_tx, dirty_tx;
+    int tx_q_bytes;
+    unsigned int tx_full:1;                /* The Tx queue is full. */
+    /* These values are keep track of the transceiver/media in use. */
+    unsigned int full_duplex:1;            /* Full-duplex operation requested. */
+    unsigned int duplex_lock:1;
+    unsigned int medialock:1;            /* Do not sense media. */
+    unsigned int default_port:4;        /* Last dev->if_port value. */
+    /* MII transceiver section. */
+    int mii_cnt;                        /* MII device addresses. */
+    u16 advertising;                    /* NWay media advertisement */
+    unsigned char phys[2];                /* MII device addresses. */
+} w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES)));
+
+/* NIC specific static variables go here */
+
+static int ioaddr;
+static unsigned short eeprom [0x40];
+struct {
+	char        rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
+	char        tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
+} w89c840_buf __shared;
+
+static int  eeprom_read(long ioaddr, int location);
+static int  mdio_read(int base_address, int phy_id, int location);
+#if 0
+static void mdio_write(int base_address, int phy_id, int location, int value);
+#endif
+
+static void check_duplex(void);
+static void set_rx_mode(void);
+static void init_ring(void);
+
+#if defined(W89C840_DEBUG)
+static void decode_interrupt(u32 intr_status)
+{
+    printf("Interrupt status: ");
+
+#define TRACE_INTR(_intr_) \
+    if (intr_status & (_intr_)) { printf (" " #_intr_); }
+
+    TRACE_INTR(NormalIntr);
+    TRACE_INTR(AbnormalIntr);
+    TRACE_INTR(IntrPCIErr);
+    TRACE_INTR(TimerInt);
+    TRACE_INTR(IntrRxDied);
+    TRACE_INTR(RxNoBuf);
+    TRACE_INTR(IntrRxDone);
+    TRACE_INTR(TxFIFOUnderflow);
+    TRACE_INTR(RxErrIntr);
+    TRACE_INTR(TxIdle);
+    TRACE_INTR(IntrTxStopped);
+    TRACE_INTR(IntrTxDone);
+
+    printf("\n");
+    /*sleep(1);*/
+}
+#endif
+
+/**************************************************************************
+w89c840_reset - Reset adapter
+***************************************************************************/
+static void w89c840_reset(struct nic *nic)
+{
+    int i;
+
+    /* Reset the chip to erase previous misconfiguration.
+       No hold time required! */
+    writel(0x00000001, ioaddr + PCIBusCfg);
+
+    init_ring();
+
+    writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
+    writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
+
+    for (i = 0; i < ETH_ALEN; i++)
+        writeb(nic->node_addr[i], ioaddr + StationAddr + i);
+
+    /* Initialize other registers. */
+    /* Configure the PCI bus bursts and FIFO thresholds.
+       486: Set 8 longword cache alignment, 8 longword burst.
+       586: Set 16 longword cache alignment, no burst limit.
+       Cache alignment bits 15:14         Burst length 13:8
+        0000    <not allowed>         0000 align to cache    0800 8 longwords
+        4000    8  longwords        0100 1 longword        1000 16 longwords
+        8000    16 longwords        0200 2 longwords    2000 32 longwords
+        C000    32  longwords        0400 4 longwords
+       Wait the specified 50 PCI cycles after a reset by initializing
+       Tx and Rx queues and the address filter list. */
+
+    writel(0xE010, ioaddr + PCIBusCfg);
+
+    writel(0, ioaddr + RxStartDemand);
+    w840private.csr6 = 0x20022002;
+    check_duplex();
+    set_rx_mode();
+
+    /* Do not enable the interrupts Etherboot doesn't need them */
+/*
+    writel(0x1A0F5, ioaddr + IntrStatus);
+    writel(0x1A0F5, ioaddr + IntrEnable);
+*/
+#if defined(W89C840_DEBUG)
+    printf("winbond-840 : Done reset.\n");
+#endif
+}
+
+#if 0
+static void handle_intr(u32 intr_stat)
+{
+    if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) {
+        /* we are polling, do not return now */
+        /*return 0;*/
+    } else {
+        /* Acknowledge all of the current interrupt sources ASAP. */
+        writel(intr_stat & 0x001ffff, ioaddr + IntrStatus);
+    }
+
+    if (intr_stat & AbnormalIntr) {
+        /* There was an abnormal interrupt */
+        printf("\n-=- Abnormal interrupt.\n");
+
+#if defined(W89C840_DEBUG)
+        decode_interrupt(intr_stat);
+#endif
+
+        if (intr_stat & RxNoBuf) {
+            /* There was an interrupt */
+            printf("-=- <=> No receive buffers available.\n");
+            writel(0, ioaddr + RxStartDemand);
+        }
+    }
+}
+#endif
+
+/**************************************************************************
+w89c840_poll - Wait for a frame
+***************************************************************************/
+static int w89c840_poll(struct nic *nic, int retrieve)
+{
+    /* return true if there's an ethernet packet ready to read */
+    /* nic->packet should contain data on return */
+    /* nic->packetlen should contain length of data */
+    int packet_received = 0;
+
+#if defined(W89C840_DEBUG)
+    u32 intr_status = readl(ioaddr + IntrStatus);
+#endif
+
+    do {
+        /* Code from netdev_rx(dev) */
+
+        int entry = w840private.cur_rx % RX_RING_SIZE;
+
+        struct w840_rx_desc *desc = w840private.rx_head_desc;
+        s32 status = desc->status;
+
+        if (status & DescOwn) {
+            /* DescOwn bit is still set, we should wait for RX to complete */
+            packet_received = 0;
+            break;
+        }
+
+        if ( !retrieve ) {
+            packet_received = 1;
+            break;
+        }
+
+        if ((status & 0x38008300) != 0x0300) {
+            if ((status & 0x38000300) != 0x0300) {
+                /* Ingore earlier buffers. */
+                if ((status & 0xffff) != 0x7fff) {
+                    printf("winbond-840 : Oversized Ethernet frame spanned "
+                           "multiple buffers, entry %d status %X !\n",
+                           w840private.cur_rx, (unsigned int) status);
+                }
+            } else if (status & 0x8000) {
+                /* There was a fatal error. */
+#if defined(W89C840_DEBUG)
+                printf("winbond-840 : Receive error, Rx status %X :", status);
+                if (status & 0x0890) {
+                    printf(" RXLEN_ERROR");
+                }
+                if (status & 0x004C) {
+                    printf(", FRAME_ERROR");
+                }
+                if (status & 0x0002) {
+                    printf(", CRC_ERROR");
+                }
+                printf("\n");
+#endif
+
+                /* Simpy do a reset now... */
+                w89c840_reset(nic);
+
+                packet_received = 0;
+                break;
+            }
+        } else {
+            /* Omit the four octet CRC from the length. */
+            int pkt_len = ((status >> 16) & 0x7ff) - 4;
+
+#if defined(W89C840_DEBUG)
+            printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
+#endif
+
+            nic->packetlen = pkt_len;
+
+            /* Check if the packet is long enough to accept without copying
+               to a minimally-sized skbuff. */
+
+            memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
+            packet_received = 1;
+
+            /* Release buffer to NIC */
+            w840private.rx_ring[entry].status = DescOwn;
+
+#if defined(W89C840_DEBUG)
+            /* You will want this info for the initial debug. */
+            printf("  Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
+                   "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
+                   "%hhX.%hhX.%hhX.%hhX.\n",
+                   nic->packet[0],  nic->packet[1],  nic->packet[2], nic->packet[3],
+                   nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],
+                   nic->packet[8],  nic->packet[9],  nic->packet[10],
+                   nic->packet[11], nic->packet[12], nic->packet[13],
+                   nic->packet[14], nic->packet[15], nic->packet[16],
+                   nic->packet[17]);
+#endif
+
+        }
+
+        entry = (++w840private.cur_rx) % RX_RING_SIZE;
+        w840private.rx_head_desc = &w840private.rx_ring[entry];
+    } while (0);
+    
+    return packet_received;
+}
+
+/**************************************************************************
+w89c840_transmit - Transmit a frame
+***************************************************************************/
+
+static void w89c840_transmit(
+    struct nic *nic,
+    const char *d,            /* Destination */
+    unsigned int t,            /* Type */
+    unsigned int s,            /* size */
+    const char *p)            /* Packet */
+{
+    /* send the packet to destination */
+    unsigned entry;
+    int transmit_status;
+    unsigned long ct;
+
+    /* Caution: the write order is important here, set the field
+       with the "ownership" bits last. */
+
+    /* Fill in our transmit buffer */
+    entry = w840private.cur_tx % TX_RING_SIZE;
+
+    memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);    /* dst */
+    memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/
+
+    *((char *) w89c840_buf.tx_packet + 12) = t >> 8;    /* type */
+    *((char *) w89c840_buf.tx_packet + 13) = t;
+
+    memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
+    s += ETH_HLEN;
+
+    while (s < ETH_ZLEN)
+    *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;
+
+    w840private.tx_ring[entry].buffer1
+	    = virt_to_le32desc(w89c840_buf.tx_packet);
+
+    w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
+    if (entry >= TX_RING_SIZE-1)         /* Wrap ring */
+        w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
+    w840private.tx_ring[entry].status = (DescOwn);
+    w840private.cur_tx++;
+
+    w840private.tx_q_bytes = (u16) s;
+    writel(0, ioaddr + TxStartDemand);
+
+    /* Work around horrible bug in the chip by marking the queue as full
+       when we do not have FIFO room for a maximum sized packet. */
+
+    if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
+        /* Actually this is left to help finding error tails later in debugging...
+         * See Linux kernel driver in winbond-840.c for details.
+         */
+        w840private.tx_full = 1;
+    }
+
+#if defined(W89C840_DEBUG)
+    printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
+#endif
+
+    /* Now wait for TX to complete. */
+    transmit_status = w840private.tx_ring[entry].status;
+
+    ct = currticks();
+    {
+#if defined W89C840_DEBUG
+        u32 intr_stat = 0;
+#endif
+        while (1) {
+
+#if defined(W89C840_DEBUG)
+	      decode_interrupt(intr_stat);
+#endif
+
+                while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {
+
+                    transmit_status = w840private.tx_ring[entry].status;
+                }
+
+                break;
+        }
+    }
+
+    if ((transmit_status & DescOwn) == 0) {
+
+#if defined(W89C840_DEBUG)
+        printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
+                w840private.tx_ring[entry].status);
+#endif
+
+        return;
+    }
+
+    /* Transmit timed out... */
+
+    printf("winbond-840 : transmission TIMEOUT : status %X\n", 
+	   (unsigned int) w840private.tx_ring[entry].status);
+
+    return;
+}
+
+/**************************************************************************
+w89c840_disable - Turn off ethernet interface
+***************************************************************************/
+static void w89c840_disable ( struct nic *nic ) {
+
+    w89c840_reset(nic);
+
+    /* Don't know what to do to disable the board. Is this needed at all? */
+    /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
+    /* Stop the chip's Tx and Rx processes. */
+    writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
+}
+
+/**************************************************************************
+w89c840_irq - Enable, Disable, or Force interrupts
+***************************************************************************/
+static void w89c840_irq(struct nic *nic __unused, irq_action_t action __unused)
+{
+  switch ( action ) {
+  case DISABLE :
+    break;
+  case ENABLE :
+    break;
+  case FORCE :
+    break;
+  }
+}
+
+static struct nic_operations w89c840_operations = {
+	.connect	= dummy_connect,
+	.poll		= w89c840_poll,
+	.transmit	= w89c840_transmit,
+	.irq		= w89c840_irq,
+
+};
+
+static struct pci_device_id w89c840_nics[] = {
+PCI_ROM(0x1050, 0x0840, "winbond840",     "Winbond W89C840F", 0),
+PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX", 0),
+};
+
+PCI_DRIVER ( w89c840_driver, w89c840_nics, PCI_NO_CLASS );
+
+/**************************************************************************
+w89c840_probe - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+static int w89c840_probe ( struct nic *nic, struct pci_device *p ) {
+
+
+    u16 sum = 0;
+    int i;
+    unsigned short value;
+
+    if (p->ioaddr == 0)
+        return 0;
+
+    nic->ioaddr = p->ioaddr;
+    nic->irqno  = 0;
+
+#if defined(W89C840_DEBUG)
+    printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
+#endif
+
+    ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
+
+#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
+#define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011
+
+    /* From Matt Hortman <mbhortman at acpthinclient.com> */
+    if (p->vendor == PCI_VENDOR_ID_WINBOND2
+        && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {
+
+        /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */
+
+    } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
+                && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {
+
+        /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */
+
+    } else {
+        /* Gee, guess what? They missed again. */
+        printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
+	       p->device);
+        return 0;
+    }
+
+    printf(" %s\n", w89c840_version);
+
+    adjust_pci_device(p);
+
+    /* Ok. Got one. Read the eeprom. */
+    for (i = 0; i < 0x40; i++) {
+        value = eeprom_read(ioaddr, i);
+        eeprom[i] = value;
+        sum += value;
+    }
+
+    for (i=0;i<ETH_ALEN;i++) {
+        nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
+    }
+
+    DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
+
+#if defined(W89C840_DEBUG)
+    printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
+#endif
+
+    /* Reset the chip to erase previous misconfiguration.
+       No hold time required! */
+    writel(0x00000001, ioaddr + PCIBusCfg);
+
+    if (driver_flags & CanHaveMII) {
+        int phy, phy_idx = 0;
+        for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
+            int mii_status = mdio_read(ioaddr, phy, 1);
+            if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+                w840private.phys[phy_idx++] = phy;
+                w840private.advertising = mdio_read(ioaddr, phy, 4);
+
+#if defined(W89C840_DEBUG)
+                printf("winbond-840 : MII PHY found at address %d, status "
+                       "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
+#endif
+
+            }
+        }
+
+        w840private.mii_cnt = phy_idx;
+
+        if (phy_idx == 0) {
+                printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
+        }
+    }
+
+    /* point to NIC specific routines */
+    nic->nic_op	= &w89c840_operations;
+
+    w89c840_reset(nic);
+
+    return 1;
+}
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
+   often serial bit streams generated by the host processor.
+   The example below is for the common 93c46 EEPROM, 64 16 bit words. */
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
+   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
+   made udelay() unreliable.
+   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
+   depricated.
+*/
+#define eeprom_delay(ee_addr)    readl(ee_addr)
+
+enum EEPROM_Ctrl_Bits {
+    EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
+    EE_ChipSelect=0x801, EE_DataIn=0x08,
+};
+
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+    EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
+};
+
+static int eeprom_read(long addr, int location)
+{
+    int i;
+    int retval = 0;
+    int ee_addr = addr + EECtrl;
+    int read_cmd = location | EE_ReadCmd;
+    writel(EE_ChipSelect, ee_addr);
+
+    /* Shift the read command bits out. */
+    for (i = 10; i >= 0; i--) {
+        short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+        writel(dataval, ee_addr);
+        eeprom_delay(ee_addr);
+        writel(dataval | EE_ShiftClk, ee_addr);
+        eeprom_delay(ee_addr);
+    }
+    writel(EE_ChipSelect, ee_addr);
+
+    for (i = 16; i > 0; i--) {
+        writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
+        eeprom_delay(ee_addr);
+        retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
+        writel(EE_ChipSelect, ee_addr);
+        eeprom_delay(ee_addr);
+    }
+
+    /* Terminate the EEPROM access. */
+    writel(0, ee_addr);
+    return retval;
+}
+
+/*  MII transceiver control section.
+    Read and write the MII registers using software-generated serial
+    MDIO protocol.  See the MII specifications or DP83840A data sheet
+    for details.
+
+    The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+    met by back-to-back 33Mhz PCI cycles. */
+#define mdio_delay(mdio_addr) readl(mdio_addr)
+
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with older tranceivers, so the extra
+   code size of a per-interface flag is not worthwhile. */
+static char mii_preamble_required = 1;
+
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(long mdio_addr)
+{
+    int bits = 32;
+
+    /* Establish sync by sending at least 32 logic ones. */
+    while (--bits >= 0) {
+        writel(MDIO_WRITE1, mdio_addr);
+        mdio_delay(mdio_addr);
+        writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+        mdio_delay(mdio_addr);
+    }
+}
+
+static int mdio_read(int base_address, int phy_id, int location)
+{
+    long mdio_addr = base_address + MIICtrl;
+    int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+    int i, retval = 0;
+
+    if (mii_preamble_required)
+        mdio_sync(mdio_addr);
+
+    /* Shift the read command bits out. */
+    for (i = 15; i >= 0; i--) {
+        int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+        writel(dataval, mdio_addr);
+        mdio_delay(mdio_addr);
+        writel(dataval | MDIO_ShiftClk, mdio_addr);
+        mdio_delay(mdio_addr);
+    }
+    /* Read the two transition, 16 data, and wire-idle bits. */
+    for (i = 20; i > 0; i--) {
+        writel(MDIO_EnbIn, mdio_addr);
+        mdio_delay(mdio_addr);
+        retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
+        writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+        mdio_delay(mdio_addr);
+    }
+    return (retval>>1) & 0xffff;
+}
+
+#if 0
+static void mdio_write(int base_address, int phy_id, int location, int value)
+{
+    long mdio_addr = base_address + MIICtrl;
+    int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+    int i;
+
+    if (location == 4  &&  phy_id == w840private.phys[0])
+        w840private.advertising = value;
+
+    if (mii_preamble_required)
+        mdio_sync(mdio_addr);
+
+    /* Shift the command bits out. */
+    for (i = 31; i >= 0; i--) {
+        int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+        writel(dataval, mdio_addr);
+        mdio_delay(mdio_addr);
+        writel(dataval | MDIO_ShiftClk, mdio_addr);
+        mdio_delay(mdio_addr);
+    }
+    /* Clear out extra bits. */
+    for (i = 2; i > 0; i--) {
+        writel(MDIO_EnbIn, mdio_addr);
+        mdio_delay(mdio_addr);
+        writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+        mdio_delay(mdio_addr);
+    }
+    return;
+}
+#endif
+
+static void check_duplex(void)
+{
+    int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
+    int negotiated =  mii_reg5 & w840private.advertising;
+    int duplex;
+
+    if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)
+        return;
+
+    duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+    if (w840private.full_duplex != duplex) {
+        w840private.full_duplex = duplex;       
+
+#if defined(W89C840_DEBUG)
+        printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
+               duplex ? "full" : "half", w840private.phys[0], negotiated);
+#endif
+
+        w840private.csr6 &= ~0x200;
+        w840private.csr6 |= duplex ? 0x200 : 0;
+    }
+}
+
+static void set_rx_mode(void)
+{
+    u32 mc_filter[2];            /* Multicast hash filter */
+    u32 rx_mode;
+
+    /* Accept all multicasts from now on. */
+    memset(mc_filter, 0xff, sizeof(mc_filter));
+
+/*
+ * works OK with multicast enabled. 
+ */
+
+    rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
+
+    writel(mc_filter[0], ioaddr + MulticastFilter0);
+    writel(mc_filter[1], ioaddr + MulticastFilter1);
+    w840private.csr6 &= ~0x00F8;
+    w840private.csr6 |= rx_mode;
+    writel(w840private.csr6, ioaddr + NetworkConfig);
+
+#if defined(W89C840_DEBUG)
+    printf("winbond-840 : Done setting RX mode.\n");
+#endif
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(void)
+{
+    int i;
+    char * p;
+
+    w840private.tx_full = 0;
+    w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
+    w840private.dirty_rx = w840private.dirty_tx = 0;
+
+    w840private.rx_buf_sz = PKT_BUF_SZ;
+    w840private.rx_head_desc = &w840private.rx_ring[0];
+
+    /* Initial all Rx descriptors. Fill in the Rx buffers. */
+
+    p = &w89c840_buf.rx_packet[0];
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        w840private.rx_ring[i].length = w840private.rx_buf_sz;
+        w840private.rx_ring[i].status = 0;
+        w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
+
+        w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
+        w840private.rx_ring[i].status = DescOwn | DescIntr;
+    }
+
+    /* Mark the last entry as wrapping the ring. */
+    w840private.rx_ring[i-1].length |= DescEndRing;
+    w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
+
+    w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+    for (i = 0; i < TX_RING_SIZE; i++) {
+        w840private.tx_ring[i].status = 0;
+    }
+    return;
+}
+
+
+DRIVER ( "W89C840F", nic_driver, pci_driver, w89c840_driver,
+	 w89c840_probe, w89c840_disable );
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/wd.c b/qemu-0.15.x/roms/ipxe/src/drivers/net/wd.c
new file mode 100644
index 0000000..9939aa0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/wd.c
@@ -0,0 +1,6 @@
+/* ISA memory-mapped NS8390-based cards, including WD80x3 */
+#if 0 /* Currently broken! */
+#define INCLUDE_WD
+#define WD_DEFAULT_MEM 0xCC000
+#include "ns8390.c"
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/net/wlan_compat.h b/qemu-0.15.x/roms/ipxe/src/drivers/net/wlan_compat.h
new file mode 100644
index 0000000..9b7693b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/net/wlan_compat.h
@@ -0,0 +1,577 @@
+/* src/include/wlan/wlan_compat.h
+*
+* Types and macros to aid in portability
+*
+* Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+* --------------------------------------------------------------------
+*
+* linux-wlan
+*
+*   The contents of this file are subject to the Mozilla Public
+*   License Version 1.1 (the "License"); you may not use this file
+*   except in compliance with the License. You may obtain a copy of
+*   the License at http://www.mozilla.org/MPL/
+*
+*   Software distributed under the License is distributed on an "AS
+*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+*   implied. See the License for the specific language governing
+*   rights and limitations under the License.
+*
+*   Alternatively, the contents of this file may be used under the
+*   terms of the GNU Public License version 2 (the "GPL"), in which
+*   case the provisions of the GPL are applicable instead of the
+*   above.  If you wish to allow the use of your version of this file
+*   only under the terms of the GPL and not to allow others to use
+*   your version of this file under the MPL, indicate your decision
+*   by deleting the provisions above and replace them with the notice
+*   and other provisions required by the GPL.  If you do not delete
+*   the provisions above, a recipient may use your version of this
+*   file under either the MPL or the GPL.
+*
+* --------------------------------------------------------------------
+*
+* Inquiries regarding the linux-wlan Open Source project can be
+* made directly to:
+*
+* AbsoluteValue Systems Inc.
+* info at linux-wlan.com
+* http://www.linux-wlan.com
+*
+* --------------------------------------------------------------------
+*
+* Portions of the development of this software were funded by 
+* Intersil Corporation as part of PRISM(R) chipset product development.
+*
+* --------------------------------------------------------------------
+*/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _WLAN_COMPAT_H
+#define _WLAN_COMPAT_H
+
+/*=============================================================*/
+/*------ Establish Platform Identity --------------------------*/
+/*=============================================================*/
+/* Key macros: */
+/* WLAN_CPU_FAMILY */
+	#define WLAN_Ix86			1
+	#define WLAN_PPC			2
+	#define WLAN_Ix96			3
+	#define WLAN_ARM			4
+	#define WLAN_ALPHA			5
+	#define WLAN_MIPS			6
+	#define WLAN_HPPA			7
+/* WLAN_CPU_CORE */
+	#define WLAN_I386CORE			1
+	#define WLAN_PPCCORE			2
+	#define WLAN_I296			3
+	#define WLAN_ARMCORE			4
+	#define WLAN_ALPHACORE			5
+	#define WLAN_MIPSCORE			6
+	#define WLAN_HPPACORE			7
+/* WLAN_CPU_PART */
+	#define WLAN_I386PART			1
+	#define WLAN_MPC860			2
+	#define WLAN_MPC823			3
+	#define WLAN_I296SA			4
+	#define WLAN_PPCPART			5
+	#define WLAN_ARMPART			6
+	#define WLAN_ALPHAPART			7
+	#define WLAN_MIPSPART			8
+	#define WLAN_HPPAPART			9
+/* WLAN_SYSARCH */
+	#define WLAN_PCAT			1
+	#define WLAN_MBX			2
+	#define WLAN_RPX			3
+	#define WLAN_LWARCH			4
+	#define WLAN_PMAC			5
+	#define WLAN_SKIFF			6
+	#define WLAN_BITSY			7
+	#define WLAN_ALPHAARCH			7
+	#define WLAN_MIPSARCH			9
+	#define WLAN_HPPAARCH			10
+/* WLAN_OS */
+	#define WLAN_LINUX_KERNEL		1
+	#define WLAN_LINUX_USER			2
+/* WLAN_HOSTIF (generally set on the command line, not detected) */
+	#define WLAN_PCMCIA			1
+	#define WLAN_ISA			2
+	#define WLAN_PCI			3
+	#define WLAN_USB			4
+	#define WLAN_PLX			5
+
+/* Note: the PLX HOSTIF above refers to some vendors implementations for */
+/*       PCI.  It's a PLX chip that is a PCI to PCMCIA adapter, but it   */
+/*       isn't a real PCMCIA host interface adapter providing all the    */
+/*       card&socket services.                                           */
+
+/* Lets try to figure out what we've got.  Kernel mode or User mode? */
+#if defined(__KERNEL__)
+	#define WLAN_OS				WLAN_LINUX_KERNEL
+#else 
+	#define WLAN_OS				WLAN_LINUX_USER
+#endif
+
+#ifdef __powerpc__
+#ifndef __ppc__
+#define __ppc__
+#endif
+#endif
+
+#if (defined(CONFIG_PPC) || defined(CONFIG_8xx))
+#ifndef __ppc__
+#define __ppc__
+#endif
+#endif
+
+#if defined(__KERNEL__)
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+	#define WLAN_CPU_FAMILY		WLAN_Ix86
+	#define WLAN_CPU_CORE		WLAN_I386CORE
+	#define WLAN_CPU_PART		WLAN_I386PART
+	#define WLAN_SYSARCH		WLAN_PCAT
+#elif defined(__ppc__)
+	#define WLAN_CPU_FAMILY		WLAN_PPC
+	#define WLAN_CPU_CORE		WLAN_PPCCORE
+	#if defined(CONFIG_MBX)
+		#define WLAN_CPU_PART	WLAN_MPC860
+		#define WLAN_SYSARCH	WLAN_MBX
+	#elif defined(CONFIG_RPXLITE)
+		#define WLAN_CPU_PART	WLAN_MPC823
+		#define WLAN_SYSARCH	WLAN_RPX
+	#elif defined(CONFIG_RPXCLASSIC)
+		#define WLAN_CPU_PART	WLAN_MPC860
+		#define WLAN_SYSARCH	WLAN_RPX
+	#else
+		#define WLAN_CPU_PART	WLAN_PPCPART
+		#define WLAN_SYSARCH	WLAN_PMAC
+	#endif
+#elif defined(__arm__)
+	#define WLAN_CPU_FAMILY		WLAN_ARM
+	#define WLAN_CPU_CORE		WLAN_ARMCORE
+        #define WLAN_CPU_PART		WLAN_ARM_PART
+	#define WLAN_SYSARCH		WLAN_SKIFF
+#elif defined(__alpha__)
+	#define WLAN_CPU_FAMILY		WLAN_ALPHA
+	#define WLAN_CPU_CORE		WLAN_ALPHACORE
+	#define WLAN_CPU_PART		WLAN_ALPHAPART
+	#define WLAN_SYSARCH		WLAN_ALPHAARCH
+#elif defined(__mips__)
+	#define WLAN_CPU_FAMILY		WLAN_MIPS
+	#define WLAN_CPU_CORE		WLAN_MIPSCORE
+        #define WLAN_CPU_PART		WLAN_MIPSPART
+	#define WLAN_SYSARCH		WLAN_MIPSARCH
+#elif defined(__hppa__)
+	#define WLAN_CPU_FAMILY		WLAN_HPPA
+	#define WLAN_CPU_CORE		WLAN_HPPACORE
+	#define WLAN_CPU_PART		WLAN_HPPAPART
+	#define WLAN_SYSARCH		WLAN_HPPAARCH
+#else
+	#error "No CPU identified!"
+#endif
+#endif /* __KERNEL__ */
+
+/*
+   Some big endian machines implicitly do all I/O in little endian mode.
+
+   In particular:
+          Linux/PPC on PowerMacs (PCI)
+	  Arm/Intel Xscale (PCI)
+
+   This may also affect PLX boards and other BE &| PPC platforms; 
+   as new ones are discovered, add them below. 
+*/
+
+#if (WLAN_HOSTIF == WLAN_PCI)
+#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC))
+#define REVERSE_ENDIAN
+#endif
+#endif
+
+/*=============================================================*/
+/*------ Bit settings -----------------------------------------*/
+/*=============================================================*/
+
+#define BIT0	0x00000001
+#define BIT1	0x00000002
+#define BIT2	0x00000004
+#define BIT3	0x00000008
+#define BIT4	0x00000010
+#define BIT5	0x00000020
+#define BIT6	0x00000040
+#define BIT7	0x00000080
+#define BIT8	0x00000100
+#define BIT9	0x00000200
+#define BIT10	0x00000400
+#define BIT11	0x00000800
+#define BIT12	0x00001000
+#define BIT13	0x00002000
+#define BIT14	0x00004000
+#define BIT15	0x00008000
+#define BIT16	0x00010000
+#define BIT17	0x00020000
+#define BIT18	0x00040000
+#define BIT19	0x00080000
+#define BIT20	0x00100000
+#define BIT21	0x00200000
+#define BIT22	0x00400000
+#define BIT23	0x00800000
+#define BIT24	0x01000000
+#define BIT25	0x02000000
+#define BIT26	0x04000000
+#define BIT27	0x08000000
+#define BIT28	0x10000000
+#define BIT29	0x20000000
+#define BIT30	0x40000000
+#define BIT31	0x80000000
+
+typedef unsigned char   UINT8;
+typedef unsigned short  UINT16;
+typedef unsigned long   UINT32;
+
+typedef signed char     INT8;
+typedef signed short    INT16;
+typedef signed long     INT32;
+
+typedef unsigned int    UINT;
+typedef signed int      INT;
+
+typedef unsigned long long	UINT64;
+typedef signed long long	INT64;
+
+#define UINT8_MAX	(0xffUL)
+#define UINT16_MAX	(0xffffUL)
+#define UINT32_MAX	(0xffffffffUL)
+
+#define INT8_MAX	(0x7fL)
+#define INT16_MAX	(0x7fffL)
+#define INT32_MAX	(0x7fffffffL)
+
+/*=============================================================*/
+/*------ Compiler Portability Macros --------------------------*/
+/*=============================================================*/
+#define __WLAN_ATTRIB_PACK__		__attribute__ ((packed))
+#define __WLAN_PRAGMA_PACK1__
+#define __WLAN_PRAGMA_PACKDFLT__
+#define __WLAN_INLINE__			inline
+#define WLAN_MIN_ARRAY			0
+
+/*=============================================================*/
+/*------ OS Portability Macros --------------------------------*/
+/*=============================================================*/
+
+#ifndef WLAN_DBVAR
+#define WLAN_DBVAR	wlan_debug
+#endif
+
+#if (WLAN_OS == WLAN_LINUX_KERNEL)
+	#define WLAN_LOG_ERROR0(x) printk(KERN_ERR "%s: " x , __FUNCTION__ );
+	#define WLAN_LOG_ERROR1(x,n) printk(KERN_ERR "%s: " x , __FUNCTION__ , (n));
+	#define WLAN_LOG_ERROR2(x,n1,n2) printk(KERN_ERR "%s: " x , __FUNCTION__ , (n1), (n2));
+	#define WLAN_LOG_ERROR3(x,n1,n2,n3) printk(KERN_ERR "%s: " x , __FUNCTION__, (n1), (n2), (n3));
+	#define WLAN_LOG_ERROR4(x,n1,n2,n3,n4) printk(KERN_ERR "%s: " x , __FUNCTION__, (n1), (n2), (n3), (n4));
+
+	#define WLAN_LOG_WARNING0(x) printk(KERN_WARNING "%s: " x , __FUNCTION__);
+	#define WLAN_LOG_WARNING1(x,n) printk(KERN_WARNING "%s: " x , __FUNCTION__, (n));
+	#define WLAN_LOG_WARNING2(x,n1,n2) printk(KERN_WARNING "%s: " x , __FUNCTION__, (n1), (n2));
+	#define WLAN_LOG_WARNING3(x,n1,n2,n3) printk(KERN_WARNING "%s: " x , __FUNCTION__, (n1), (n2), (n3));
+	#define WLAN_LOG_WARNING4(x,n1,n2,n3,n4) printk(KERN_WARNING "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4));
+
+	#define WLAN_LOG_NOTICE0(x) printk(KERN_NOTICE "%s: " x , __FUNCTION__);
+	#define WLAN_LOG_NOTICE1(x,n) printk(KERN_NOTICE "%s: " x , __FUNCTION__, (n));
+	#define WLAN_LOG_NOTICE2(x,n1,n2) printk(KERN_NOTICE "%s: " x , __FUNCTION__, (n1), (n2));
+	#define WLAN_LOG_NOTICE3(x,n1,n2,n3) printk(KERN_NOTICE "%s: " x , __FUNCTION__, (n1), (n2), (n3));
+	#define WLAN_LOG_NOTICE4(x,n1,n2,n3,n4) printk(KERN_NOTICE "%s: " x , __FUNCTION__, (n1), (n2), (n3), (n4));
+
+	#define WLAN_LOG_INFO0(x) printk(KERN_INFO x);
+	#define WLAN_LOG_INFO1(x,n) printk(KERN_INFO x, (n));
+	#define WLAN_LOG_INFO2(x,n1,n2) printk(KERN_INFO x, (n1), (n2));
+	#define WLAN_LOG_INFO3(x,n1,n2,n3) printk(KERN_INFO x, (n1), (n2), (n3));
+	#define WLAN_LOG_INFO4(x,n1,n2,n3,n4) printk(KERN_INFO x, (n1), (n2), (n3), (n4));
+	#define WLAN_LOG_INFO5(x,n1,n2,n3,n4,n5) printk(KERN_INFO x, (n1), (n2), (n3), (n4), (n5));
+
+	#if defined(WLAN_INCLUDE_DEBUG)
+		#define WLAN_ASSERT(c) if ((!(c)) && WLAN_DBVAR >= 1) { \
+			WLAN_LOG_DEBUG0(1, "Assertion failure!\n"); }
+		#define WLAN_HEX_DUMP( l, x, p, n)	if( WLAN_DBVAR >= (l) ){ \
+			int __i__; \
+			printk(KERN_DEBUG x ":"); \
+			for( __i__=0; __i__ < (n); __i__++) \
+				printk( " %02x", ((UINT8*)(p))[__i__]); \
+			printk("\n"); }
+
+		#define DBFENTER { if ( WLAN_DBVAR >= 4 ){ WLAN_LOG_DEBUG0(3,"Enter\n"); } }
+		#define DBFEXIT  { if ( WLAN_DBVAR >= 4 ){ WLAN_LOG_DEBUG0(3,"Exit\n"); } }
+
+		#define WLAN_LOG_DEBUG0(l,x) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x ,  __FUNCTION__ );
+		#define WLAN_LOG_DEBUG1(l,x,n) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n));
+		#define WLAN_LOG_DEBUG2(l,x,n1,n2) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2));
+		#define WLAN_LOG_DEBUG3(l,x,n1,n2,n3) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3));
+		#define WLAN_LOG_DEBUG4(l,x,n1,n2,n3,n4) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4));
+		#define WLAN_LOG_DEBUG5(l,x,n1,n2,n3,n4,n5) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4), (n5));
+		#define WLAN_LOG_DEBUG6(l,x,n1,n2,n3,n4,n5,n6) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4), (n5), (n6));
+	#else
+		#define WLAN_ASSERT(c) 
+		#define WLAN_HEX_DUMP( l, s, p, n)
+
+		#define DBFENTER 
+		#define DBFEXIT 
+
+		#define WLAN_LOG_DEBUG0(l, s)
+		#define WLAN_LOG_DEBUG1(l, s,n)
+		#define WLAN_LOG_DEBUG2(l, s,n1,n2)
+		#define WLAN_LOG_DEBUG3(l, s,n1,n2,n3)
+		#define WLAN_LOG_DEBUG4(l, s,n1,n2,n3,n4)
+		#define WLAN_LOG_DEBUG5(l, s,n1,n2,n3,n4,n5)
+	#endif
+#else
+	#define WLAN_LOG_ERROR0(s)
+	#define WLAN_LOG_ERROR1(s,n)
+	#define WLAN_LOG_ERROR2(s,n1,n2)
+	#define WLAN_LOG_ERROR3(s,n1,n2,n3)
+	#define WLAN_LOG_ERROR4(s,n1,n2,n3,n4)
+
+	#define WLAN_LOG_WARNING0(s)
+	#define WLAN_LOG_WARNING1(s,n)
+	#define WLAN_LOG_WARNING2(s,n1,n2)
+	#define WLAN_LOG_WARNING3(s,n1,n2,n3)
+	#define WLAN_LOG_WARNING4(s,n1,n2,n3,n4)
+
+	#define WLAN_LOG_NOTICE0(s)
+	#define WLAN_LOG_NOTICE1(s,n)
+	#define WLAN_LOG_NOTICE2(s,n1,n2)
+	#define WLAN_LOG_NOTICE3(s,n1,n2,n3)
+	#define WLAN_LOG_NOTICE4(s,n1,n2,n3,n4)
+
+		#define WLAN_ASSERT(c) 
+		#define WLAN_HEX_DUMP( l, s, p, n)
+
+		#define DBFENTER 
+		#define DBFEXIT 
+
+		#define WLAN_LOG_INFO0(s)
+		#define WLAN_LOG_INFO1(s,n)
+		#define WLAN_LOG_INFO2(s,n1,n2)
+		#define WLAN_LOG_INFO3(s,n1,n2,n3)
+		#define WLAN_LOG_INFO4(s,n1,n2,n3,n4)
+		#define WLAN_LOG_INFO5(s,n1,n2,n3,n4,n5)
+
+		#define WLAN_LOG_DEBUG0(l, s)
+		#define WLAN_LOG_DEBUG1(l, s,n)
+		#define WLAN_LOG_DEBUG2(l, s,n1,n2)
+		#define WLAN_LOG_DEBUG3(l, s,n1,n2,n3)
+		#define WLAN_LOG_DEBUG4(l, s,n1,n2,n3,n4)
+		#define WLAN_LOG_DEBUG5(l, s,n1,n2,n3,n4,n5)
+#endif
+
+#define wlan_ms_per_tick		(1000UL / (wlan_ticks_per_sec))
+#define wlan_ms_to_ticks(n)		( (n) / (wlan_ms_per_tick))
+#define wlan_tu2ticks(n)		( (n) / (wlan_ms_per_tick))
+#define WLAN_INT_DISABLE(n)		{ save_flags((n)); cli(); }
+#define WLAN_INT_ENABLE(n)		{ sti(); restore_flags((n)); }
+
+#ifdef CONFIG_MODVERSIONS
+#define MODVERSIONS		1
+#include <linux/modversions.h>
+#endif
+
+#ifdef CONFIG_SMP
+#define __SMP__			1
+#endif	
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17))
+#define CONFIG_NETLINK		1
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+#define kfree_s(a, b)	kfree((a))
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18))
+#ifndef init_waitqueue_head
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,0,16))
+#define init_waitqueue_head(p)  (*(p) = NULL)
+#else
+#define init_waitqueue_head(p)  init_waitqueue(p)
+#endif
+typedef struct wait_queue *wait_queue_head_t;
+typedef struct wait_queue wait_queue_t;
+#define set_current_state(b)  { current->state = (b); mb(); }
+#define init_waitqueue_entry(a, b) { (a)->task = current; }
+#endif
+#endif
+
+#ifndef wait_event_interruptible_timeout
+// retval == 0; signal met; we're good.
+// retval < 0; interrupted by signal.
+// retval > 0; timed out.
+#define __wait_event_interruptible_timeout(wq, condition, timeout, ret)   \
+do {                                                                      \
+        int __ret = 0;                                                    \
+        if (!(condition)) {                                               \
+          wait_queue_t __wait;                                            \
+          unsigned long expire;                                           \
+          init_waitqueue_entry(&__wait, current);                         \
+	                                                                  \
+          expire = timeout + jiffies;                                     \
+          add_wait_queue(&wq, &__wait);                                   \
+          for (;;) {                                                      \
+                  set_current_state(TASK_INTERRUPTIBLE);                  \
+                  if (condition)                                          \
+                          break;                                          \
+                  if (jiffies > expire) {                                 \
+                          ret = jiffies - expire;                         \
+                          break;                                          \
+                  }                                                       \
+                  if (!signal_pending(current)) {                         \
+                          schedule_timeout(timeout);                      \
+                          continue;                                       \
+                  }                                                       \
+                  ret = -ERESTARTSYS;                                     \
+                  break;                                                  \
+          }                                                               \
+          set_current_state(TASK_RUNNING);                                \
+          remove_wait_queue(&wq, &__wait);                                \
+	}                                                                 \
+} while (0)
+
+#define wait_event_interruptible_timeout(wq, condition, timeout)	\
+({									\
+	int __ret = 0;							\
+	if (!(condition))						\
+		__wait_event_interruptible_timeout(wq, condition,	\
+						timeout, __ret);	\
+	__ret;								\
+})
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,90))
+#define spin_lock(l)            do { } while (0)
+#define spin_unlock(l)          do { } while (0)
+#define spin_lock_irqsave(l,f)  do { save_flags(f); cli(); } while (0)
+#define spin_unlock_irqrestore(l,f) do { restore_flags(f); } while (0)
+#define spin_lock_init(s)       do { } while (0)
+#define spin_trylock(l)         (1)
+typedef int spinlock_t;
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#ifdef CONFIG_SMP
+#define spin_is_locked(x)       (*(volatile char *)(&(x)->lock) <= 0)
+#else
+#define spin_is_locked(l)       (0)
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38))
+typedef struct device netdevice_t;
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4))
+typedef struct net_device netdevice_t;
+#else
+#undef netdevice_t
+typedef struct net_device netdevice_t;
+#endif
+
+#ifdef WIRELESS_EXT
+#if (WIRELESS_EXT < 13)
+struct iw_request_info
+{
+        __u16           cmd;            /* Wireless Extension command */
+        __u16           flags;          /* More to come ;-) */
+};
+#endif
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18))
+#define MODULE_PARM(a,b)        extern int __bogus_decl
+#define MODULE_AUTHOR(a)        extern int __bogus_decl
+#define MODULE_DESCRIPTION(a)   extern int __bogus_decl
+#define MODULE_SUPPORTED_DEVICE(a) extern int __bogus_decl
+#undef  GET_USE_COUNT
+#define GET_USE_COUNT(m)        mod_use_count_
+#endif
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(m)       extern int __bogus_decl
+#endif
+
+/* TODO:  Do we care about this? */
+#ifndef MODULE_DEVICE_TABLE
+#define MODULE_DEVICE_TABLE(foo,bar)
+#endif
+
+#define wlan_minutes2ticks(a) ((a)*(wlan_ticks_per_sec *  60))
+#define wlan_seconds2ticks(a) ((a)*(wlan_ticks_per_sec))
+
+/*=============================================================*/
+/*------ Hardware Portability Macros --------------------------*/
+/*=============================================================*/
+
+#define ieee2host16(n)	__le16_to_cpu(n)
+#define ieee2host32(n)	__le32_to_cpu(n)
+#define host2ieee16(n)	__cpu_to_le16(n)
+#define host2ieee32(n)	__cpu_to_le32(n)
+
+#if (WLAN_CPU_FAMILY == WLAN_PPC)
+       #define wlan_inw(a)                     in_be16((unsigned short *)((a)+_IO_BASE))
+       #define wlan_inw_le16_to_cpu(a)         inw((a))
+       #define wlan_outw(v,a)                  out_be16((unsigned short *)((a)+_IO_BASE), (v))
+       #define wlan_outw_cpu_to_le16(v,a)      outw((v),(a))
+#else
+       #define wlan_inw(a)                     inw((a))
+       #define wlan_inw_le16_to_cpu(a)         __cpu_to_le16(inw((a)))
+       #define wlan_outw(v,a)                  outw((v),(a))
+       #define wlan_outw_cpu_to_le16(v,a)      outw(__cpu_to_le16((v)),(a))
+#endif
+
+/*=============================================================*/
+/*--- General Macros ------------------------------------------*/
+/*=============================================================*/
+
+#define wlan_max(a, b) (((a) > (b)) ? (a) : (b))
+#define wlan_min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define wlan_isprint(c)	(((c) > (0x19)) && ((c) < (0x7f)))
+
+#define wlan_hexchar(x) (((x) < 0x0a) ? ('0' + (x)) : ('a' + ((x) - 0x0a)))
+
+/* Create a string of printable chars from something that might not be */
+/* It's recommended that the str be 4*len + 1 bytes long */
+#define wlan_mkprintstr(buf, buflen, str, strlen) \
+{ \
+	int i = 0; \
+	int j = 0; \
+	memset(str, 0, (strlen)); \
+	for (i = 0; i < (buflen); i++) { \
+		if ( wlan_isprint((buf)[i]) ) { \
+			(str)[j] = (buf)[i]; \
+			j++; \
+		} else { \
+			(str)[j] = '\\'; \
+			(str)[j+1] = 'x'; \
+			(str)[j+2] = wlan_hexchar(((buf)[i] & 0xf0) >> 4); \
+			(str)[j+3] = wlan_hexchar(((buf)[i] & 0x0f)); \
+			j += 4; \
+		} \
+	} \
+}
+
+/*=============================================================*/
+/*--- Variables -----------------------------------------------*/
+/*=============================================================*/
+
+extern int wlan_debug;
+extern int wlan_ethconv;		/* What's the default ethconv? */
+
+/*=============================================================*/
+/*--- Functions -----------------------------------------------*/
+/*=============================================================*/
+#endif /* _WLAN_COMPAT_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvs.c b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvs.c
new file mode 100644
index 0000000..a4a06cc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvs.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/nvs.h>
+
+/** @file
+ *
+ * Non-volatile storage
+ *
+ */
+
+/**
+ * Calculate length up to next block boundary
+ *
+ * @v nvs		NVS device
+ * @v address		Starting address
+ * @v max_len		Maximum length
+ * @ret len		Length to use, stopping at block boundaries
+ */
+static size_t nvs_frag_len ( struct nvs_device *nvs, unsigned int address,
+			     size_t max_len ) {
+	size_t frag_len;
+
+	/* If there are no block boundaries, return the maximum length */
+	if ( ! nvs->block_size )
+		return max_len;
+
+	/* Calculate space remaining up to next block boundary */
+	frag_len = ( ( nvs->block_size -
+		       ( address & ( nvs->block_size - 1 ) ) )
+		     << nvs->word_len_log2 );
+
+	/* Limit to maximum length */
+	if ( max_len < frag_len )
+		return max_len;
+
+	return frag_len;
+}
+
+/**
+ * Read from non-volatile storage device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int nvs_read ( struct nvs_device *nvs, unsigned int address,
+	       void *data, size_t len ) {
+	size_t frag_len;
+	int rc;
+
+	/* We don't even attempt to handle buffer lengths that aren't
+	 * an integral number of words.
+	 */
+	assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
+
+	while ( len ) {
+
+		/* Calculate length to read, stopping at block boundaries */
+		frag_len = nvs_frag_len ( nvs, address, len );
+
+		/* Read this portion of the buffer from the device */
+		if ( ( rc = nvs->read ( nvs, address, data, frag_len ) ) != 0 )
+			return rc;
+
+		/* Update parameters */
+		data += frag_len;
+		address += ( frag_len >> nvs->word_len_log2 );
+		len -= frag_len;
+	}
+
+	return 0;
+}
+
+/**
+ * Verify content of non-volatile storage device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data to compare against
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int nvs_verify ( struct nvs_device *nvs, unsigned int address,
+			const void *data, size_t len ) {
+	uint8_t read_data[len];
+	int rc;
+
+	/* Read data into temporary buffer */
+	if ( ( rc = nvs_read ( nvs, address, read_data, len ) ) != 0 )
+		return rc;
+
+	/* Compare data */
+	if ( memcmp ( data, read_data, len ) != 0 ) {
+		DBG ( "NVS %p verification failed at %#04x+%zd\n",
+		      nvs, address, len );
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Write to non-volatile storage device
+ *
+ * @v nvs		NVS device
+ * @v address		Address to which to write
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int nvs_write ( struct nvs_device *nvs, unsigned int address,
+		const void *data, size_t len ) {
+	size_t frag_len;
+	int rc;
+
+	/* We don't even attempt to handle buffer lengths that aren't
+	 * an integral number of words.
+	 */
+	assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
+
+	while ( len ) {
+
+		/* Calculate length to write, stopping at block boundaries */
+		frag_len = nvs_frag_len ( nvs, address, len );
+
+		/* Write this portion of the buffer to the device */
+		if ( ( rc = nvs->write ( nvs, address, data, frag_len ) ) != 0)
+			return rc;
+
+		/* Read back and verify data */
+		if ( ( rc = nvs_verify ( nvs, address, data, frag_len ) ) != 0)
+			return rc;
+
+		/* Update parameters */
+		data += frag_len;
+		address += ( frag_len >> nvs->word_len_log2 );
+		len -= frag_len;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvsvpd.c b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvsvpd.c
new file mode 100644
index 0000000..a22ec82
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/nvsvpd.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/nvs.h>
+#include <ipxe/pci.h>
+#include <ipxe/pcivpd.h>
+#include <ipxe/nvo.h>
+#include <ipxe/nvsvpd.h>
+
+/** @file
+ *
+ * Non-Volatile Storage using Vital Product Data
+ *
+ */
+
+/**
+ * Read from VPD field
+ *
+ * @v nvs		NVS device
+ * @v field		VPD field descriptor
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
+			  void *data, size_t len ) {
+	struct nvs_vpd_device *nvsvpd =
+		container_of ( nvs, struct nvs_vpd_device, nvs );
+	struct pci_device *pci = nvsvpd->vpd.pci;
+	unsigned int address;
+	size_t max_len;
+	int rc;
+
+	/* Allow reading non-existent field */
+	if ( len == 0 )
+		return 0;
+
+	/* Locate VPD field */
+	if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
+				   &max_len ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
+		       PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
+		       PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
+		return rc;
+	}
+
+	/* Sanity check */
+	if ( len > max_len ) {
+		DBGC ( pci, PCI_FMT " NVS VPD cannot read %#02zx bytes "
+		       "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
+		       PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
+		       address, ( address + max_len ) );
+		return -ENXIO;
+	}
+
+	/* Read from VPD field */
+	if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, address, data, len ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD could not read field "
+		       PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
+		       PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
+		       address, ( address + len ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Write to VPD field
+ *
+ * @v nvs		NVS device
+ * @v field		VPD field descriptor
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
+			   const void *data, size_t len ) {
+	struct nvs_vpd_device *nvsvpd =
+		container_of ( nvs, struct nvs_vpd_device, nvs );
+	struct pci_device *pci = nvsvpd->vpd.pci;
+	unsigned int address;
+	size_t max_len;
+	int rc;
+
+	/* Locate VPD field */
+	if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
+				   &max_len ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
+		       PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
+		       PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
+		return rc;
+	}
+
+	/* Sanity check */
+	if ( len > max_len ) {
+		DBGC ( pci, PCI_FMT " NVS VPD cannot write %#02zx bytes "
+		       "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
+		       PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
+		       address, ( address + max_len ) );
+		return -ENXIO;
+	}
+
+	/* Write field */
+	if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, address, data,
+				    len ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD could not write field "
+		       PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
+		       PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
+		       address, ( address + len ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Resize VPD field
+ *
+ * @v nvs		NVS device
+ * @v field		VPD field descriptor
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int nvs_vpd_resize ( struct nvs_device *nvs, unsigned int field,
+			    size_t len ) {
+	struct nvs_vpd_device *nvsvpd =
+		container_of ( nvs, struct nvs_vpd_device, nvs );
+	struct pci_device *pci = nvsvpd->vpd.pci;
+	unsigned int address;
+	int rc;
+
+	/* Resize field */
+	if ( ( rc = pci_vpd_resize ( &nvsvpd->vpd, field, len,
+				     &address ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD could not resize field "
+		       PCI_VPD_FIELD_FMT " to %#02zx bytes: %s\n",
+		       PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
+		       len, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Initialise NVS VPD device
+ *
+ * @v nvsvpd		NVS VPD device
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
+	int rc;
+
+	/* Initialise VPD device */
+	if ( ( rc = pci_vpd_init ( &nvsvpd->vpd, pci ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS could not initialise "
+		       "VPD: %s\n", PCI_ARGS ( pci ), strerror ( rc ) );
+		return rc;
+	}
+
+	/* Initialise NVS device */
+	nvsvpd->nvs.read = nvs_vpd_read;
+	nvsvpd->nvs.write = nvs_vpd_write;
+
+	return 0;
+}
+
+/**
+ * Resize non-volatile option storage within NVS VPD device
+ *
+ * @v nvo		Non-volatile options block
+ * @v len		New length
+ * @ret rc		Return status code
+ */
+static int nvs_vpd_nvo_resize ( struct nvo_block *nvo, size_t len ) {
+	int rc;
+
+	/* Resize VPD field */
+	if ( ( rc = nvs_vpd_resize ( nvo->nvs, nvo->address, len ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Initialise non-volatile option storage within NVS VPD device
+ *
+ * @v nvsvpd		NVS VPD device
+ * @v field		VPD field descriptor
+ * @v nvo		Non-volatile options block
+ * @v refcnt		Containing object reference counter, or NULL
+ */
+void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd, unsigned int field,
+			struct nvo_block *nvo, struct refcnt *refcnt ) {
+	struct pci_device *pci = nvsvpd->vpd.pci;
+	unsigned int address;
+	size_t len;
+	int rc;
+
+	/* Locate VPD field, if present */
+	if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
+				   &len ) ) != 0 ) {
+		DBGC ( pci, PCI_FMT " NVS VPD field " PCI_VPD_FIELD_FMT
+		       " not present; assuming empty\n",
+		       PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ) );
+		len = 0;
+	}
+
+	/* Initialise non-volatile options block */
+	nvo_init ( nvo, &nvsvpd->nvs, field, len, nvs_vpd_nvo_resize, refcnt );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/nvs/spi.c b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/spi.c
new file mode 100644
index 0000000..e12aeff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/spi.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ipxe/spi.h>
+
+/** @file
+ *
+ * SPI devices
+ *
+ */
+
+/**
+ * Munge SPI device address into command
+ *
+ * @v command		SPI command
+ * @v address		Address
+ * @v munge_address	Device requires address munging
+ * @ret command		Actual SPI command to use
+ *
+ * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) use bit 3
+ * of the command byte as address bit A8, rather than having a
+ * two-byte address.  This function takes care of generating the
+ * appropriate command.
+ */
+static inline unsigned int spi_command ( unsigned int command,
+					 unsigned int address,
+					 int munge_address ) {
+	return ( command | ( ( ( address >> 8 ) & munge_address ) << 3 ) );
+}
+
+/**
+ * Wait for SPI device to complete operation
+ *
+ * @v device		SPI device
+ * @ret rc		Return status code
+ */
+static int spi_wait ( struct spi_device *device ) {
+	struct spi_bus *bus = device->bus;
+	uint8_t status;
+	int i;
+	int rc;
+
+	for ( i = 0 ; i < 50 ; i++ ) {
+		udelay ( 20 );
+		if ( ( rc = bus->rw ( bus, device, SPI_RDSR, -1, NULL,
+				      &status, sizeof ( status ) ) ) != 0 )
+			return rc;
+		if ( ! ( status & SPI_STATUS_NRDY ) )
+			return 0;
+	}
+	DBG ( "SPI %p timed out\n", device );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Read data from SPI device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int spi_read ( struct nvs_device *nvs, unsigned int address,
+	       void *data, size_t len ) {
+	struct spi_device *device = nvs_to_spi ( nvs );
+	struct spi_bus *bus = device->bus;
+	unsigned int command = spi_command ( SPI_READ, address,
+					     device->munge_address );
+	int rc;
+
+	DBG ( "SPI %p reading %zd bytes from %#04x\n", device, len, address );
+	if ( ( rc = bus->rw ( bus, device, command, address,
+			      NULL, data, len ) ) != 0 ) {
+		DBG ( "SPI %p failed to read data from device\n", device );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Write data to SPI device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int spi_write ( struct nvs_device *nvs, unsigned int address,
+		const void *data, size_t len ) {
+	struct spi_device *device = nvs_to_spi ( nvs );
+	struct spi_bus *bus = device->bus;
+	unsigned int command = spi_command ( SPI_WRITE, address,
+					     device->munge_address );
+	int rc;
+
+	DBG ( "SPI %p writing %zd bytes to %#04x\n", device, len, address );
+
+	if ( ( rc = bus->rw ( bus, device, SPI_WREN, -1,
+			      NULL, NULL, 0 ) ) != 0 ) {
+		DBG ( "SPI %p failed to write-enable device\n", device );
+		return rc;
+	}
+
+	if ( ( rc = bus->rw ( bus, device, command, address,
+			      data, NULL, len ) ) != 0 ) {
+		DBG ( "SPI %p failed to write data to device\n", device );
+		return rc;
+	}
+	
+	if ( ( rc = spi_wait ( device ) ) != 0 ) {
+		DBG ( "SPI %p failed to complete write operation\n", device );
+		return rc;
+	}
+
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/drivers/nvs/threewire.c b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/threewire.c
new file mode 100644
index 0000000..047091f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/drivers/nvs/threewire.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ipxe/threewire.h>
+
+/** @file
+ *
+ * Three-wire serial devices
+ *
+ */
+
+/**
+ * Read data from three-wire device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int threewire_read ( struct nvs_device *nvs, unsigned int address,
+		     void *data, size_t len ) {
+	struct spi_device *device = nvs_to_spi ( nvs );
+	struct spi_bus *bus = device->bus;
+	int rc;
+
+	assert ( bus->mode == SPI_MODE_THREEWIRE );
+
+	DBGC ( device, "3wire %p reading %zd bytes at %04x\n",
+	       device, len, address );
+
+	if ( ( rc = bus->rw ( bus, device, THREEWIRE_READ, address,
+			      NULL, data, len ) ) != 0 ) {
+		DBGC ( device, "3wire %p could not read: %s\n",
+		       device, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Write data to three-wire device
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+int threewire_write ( struct nvs_device *nvs, unsigned int address,
+		      const void *data, size_t len ) {
+	struct spi_device *device = nvs_to_spi ( nvs );
+	struct spi_bus *bus = device->bus;
+	int rc;
+
+	assert ( bus->mode == SPI_MODE_THREEWIRE );
+
+	DBGC ( device, "3wire %p writing %zd bytes at %04x\n",
+	       device, len, address );
+
+	/* Enable device for writing */
+	if ( ( rc = bus->rw ( bus, device, THREEWIRE_EWEN,
+			      THREEWIRE_EWEN_ADDRESS, NULL, NULL, 0 ) ) != 0 ){
+		DBGC ( device, "3wire %p could not enable writing: %s\n",
+		       device, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Write data */
+	if ( ( rc = bus->rw ( bus, device, THREEWIRE_WRITE, address,
+			      data, NULL, len ) ) != 0 ) {
+		DBGC ( device, "3wire %p could not write: %s\n",
+		       device, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Our model of an SPI bus doesn't provide a mechanism for
+	 * "assert CS, wait for MISO to become high, so just wait for
+	 * long enough to ensure that the write has completed.
+	 */
+	mdelay ( THREEWIRE_WRITE_MDELAY );
+
+	return 0;
+}
+
+/**
+ * Autodetect device address length
+ *
+ * @v device		SPI device
+ * @ret rc		Return status code
+ */
+int threewire_detect_address_len ( struct spi_device *device ) {
+	struct nvs_device *nvs = &device->nvs;
+	int rc;
+
+	DBGC ( device, "3wire %p autodetecting address length\n", device );
+
+	device->address_len = SPI_AUTODETECT_ADDRESS_LEN;
+	if ( ( rc = threewire_read ( nvs, 0, NULL,
+				     ( 1 << nvs->word_len_log2 ) ) ) != 0 ) {
+		DBGC ( device, "3wire %p could not autodetect address "
+		       "length: %s\n", device, strerror ( rc ) );
+		return rc;
+	}
+
+	DBGC ( device, "3wire %p autodetected address length %d\n",
+	       device, device->address_len );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/autoboot_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/autoboot_cmd.c
new file mode 100644
index 0000000..0917f6f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/autoboot_cmd.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/netdevice.h>
+#include <hci/ifmgmt_cmd.h>
+#include <usr/autoboot.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Booting commands
+ *
+ */
+
+/** "autoboot" command descriptor */
+static struct command_descriptor autoboot_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "autoboot" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int autoboot_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &autoboot_cmd, netboot, 0 );
+}
+
+/** Booting commands */
+struct command autoboot_commands[] __command = {
+	{
+		.name = "autoboot",
+		.exec = autoboot_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/config_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/config_cmd.c
new file mode 100644
index 0000000..e447d6a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/config_cmd.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/settings.h>
+#include <ipxe/settings_ui.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Configuration UI commands
+ *
+ */
+
+/** "config" options */
+struct config_options {};
+
+/** "config" option list */
+static struct option_descriptor config_opts[] = {};
+
+/** "config" command descriptor */
+static struct command_descriptor config_cmd =
+	COMMAND_DESC ( struct config_options, config_opts, 0, 1, "[<scope>]" );
+
+/**
+ * Parse settings scope name
+ *
+ * @v text		Text
+ * @ret value		Integer value
+ * @ret rc		Return status code
+ */
+static int parse_settings ( const char *text, struct settings **value ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Parse scope name */
+	*value = find_settings ( text );
+	if ( ! *value ) {
+		printf ( "\"%s\": no such scope\n", text );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * "config" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int config_exec ( int argc, char **argv ) {
+	struct config_options opts;
+	struct settings *settings;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &config_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse settings option, if present */
+	if ( ( rc = parse_settings ( ( ( optind < argc ) ? argv[optind] : "" ),
+				     &settings ) ) != 0 )
+		return rc;
+
+	/* Run settings UI */
+	if ( ( rc = settings_ui ( settings ) ) != 0 ) {
+		printf ( "Could not save settings: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** Configuration UI commands */
+struct command config_command __command = {
+	.name = "config",
+	.exec = config_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/dhcp_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/dhcp_cmd.c
new file mode 100644
index 0000000..acf3cfd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/dhcp_cmd.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/in.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/dhcpmgmt.h>
+#include <hci/ifmgmt_cmd.h>
+
+/** @file
+ *
+ * DHCP management commands
+ *
+ */
+
+/** "dhcp" command descriptor */
+static struct command_descriptor dhcp_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * Execute "dhcp" command for a network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int dhcp_payload ( struct net_device *netdev ) {
+	int rc;
+
+	if ( ( rc = dhcp ( netdev ) ) != 0 ) {
+		printf ( "Could not configure %s: %s\n",
+			 netdev->name, strerror ( rc ) );
+
+		/* Close device on failure, to avoid memory exhaustion */
+		netdev_close ( netdev );
+
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * The "dhcp" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int dhcp_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &dhcp_cmd, dhcp_payload, 1 );
+}
+
+/** "pxebs" options */
+struct pxebs_options {};
+
+/** "pxebs" option list */
+static struct option_descriptor pxebs_opts[] = {};
+
+/** "pxebs" command descriptor */
+static struct command_descriptor pxebs_cmd =
+	COMMAND_DESC ( struct pxebs_options, pxebs_opts, 2, 2,
+		       "<interface> <server type>" );
+
+/**
+ * The "pxebs" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int pxebs_exec ( int argc, char **argv ) {
+	struct pxebs_options opts;
+	struct net_device *netdev;
+	unsigned int pxe_type;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &pxebs_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse net device name */
+	if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 )
+		return rc;
+
+	/* Parse boot server type */
+	if ( ( rc = parse_integer ( argv[ optind + 1 ], &pxe_type ) ) != 0 )
+		return rc;
+
+	/* Perform Boot Server Discovery */
+	if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) {
+		printf ( "Could not discover boot server on %s: %s\n",
+			 netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** DHCP management commands */
+struct command dhcp_commands[] __command = {
+	{
+		.name = "dhcp",
+		.exec = dhcp_exec,
+	},
+	{
+		.name = "pxebs",
+		.exec = pxebs_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/digest_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/digest_cmd.c
new file mode 100644
index 0000000..6ca12ef
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/digest_cmd.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/image.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+
+/** @file
+ *
+ * Digest commands
+ *
+ */
+
+/** "digest" options */
+struct digest_options {};
+
+/** "digest" option list */
+static struct option_descriptor digest_opts[] = {};
+
+/** "digest" command descriptor */
+static struct command_descriptor digest_cmd =
+	COMMAND_DESC ( struct digest_options, digest_opts, 1, MAX_ARGUMENTS,
+		       "<image> [<image>...]" );
+
+/**
+ * The "digest" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v digest		Digest algorithm
+ * @ret rc		Return status code
+ */
+static int digest_exec ( int argc, char **argv,
+			 struct digest_algorithm *digest ) {
+	struct digest_options opts;
+	struct image *image;
+	uint8_t digest_ctx[digest->ctxsize];
+	uint8_t digest_out[digest->digestsize];
+	uint8_t buf[128];
+	size_t offset;
+	size_t len;
+	size_t frag_len;
+	int i;
+	unsigned j;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &digest_cmd, &opts ) ) != 0 )
+		return rc;
+
+	for ( i = optind ; i < argc ; i++ ) {
+
+		/* find image */
+		if ( ( rc = parse_image ( argv[i], &image ) ) != 0 )
+			continue;
+		offset = 0;
+		len = image->len;
+
+		/* calculate digest */
+		digest_init ( digest, digest_ctx );
+		while ( len ) {
+			frag_len = len;
+			if ( frag_len > sizeof ( buf ) )
+				frag_len = sizeof ( buf );
+			copy_from_user ( buf, image->data, offset, frag_len );
+			digest_update ( digest, digest_ctx, buf, frag_len );
+			len -= frag_len;
+			offset += frag_len;
+		}
+		digest_final ( digest, digest_ctx, digest_out );
+
+		for ( j = 0 ; j < sizeof ( digest_out ) ; j++ )
+			printf ( "%02x", digest_out[j] );
+
+		printf ( "  %s\n", image->name );
+	}
+
+	return 0;
+}
+
+static int md5sum_exec ( int argc, char **argv ) {
+	return digest_exec ( argc, argv, &md5_algorithm );
+}
+
+static int sha1sum_exec ( int argc, char **argv ) {
+	return digest_exec ( argc, argv, &sha1_algorithm );
+}
+
+struct command md5sum_command __command = {
+	.name = "md5sum",
+	.exec = md5sum_exec,
+};
+
+struct command sha1sum_command __command = {
+	.name = "sha1sum",
+	.exec = sha1sum_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/fcmgmt_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
new file mode 100644
index 0000000..a2b818e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <strings.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/tables.h>
+#include <usr/fcmgmt.h>
+
+/** @file
+ *
+ * Fibre Channel management commands
+ *
+ */
+
+/**
+ * Parse Fibre Channel port name
+ *
+ * @v text		Text
+ * @ret port		Fibre Channel port
+ * @ret rc		Return status code
+ */
+static int parse_fc_port ( const char *text, struct fc_port **port ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Find Fibre Channel port */
+	*port = fc_port_find ( text );
+	if ( ! *port ) {
+		printf ( "\"%s\": no such port\n", text );
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse Fibre Channel port ID
+ *
+ * @v text		Text
+ * @ret port_id		Fibre Channel port ID
+ * @ret rc		Return status code
+ */
+static int parse_fc_port_id ( const char *text, struct fc_port_id *port_id ) {
+	int rc;
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Parse port ID */
+	if ( ( rc = fc_id_aton ( text, port_id ) ) != 0 ) {
+		printf ( "\"%s\": invalid port ID\n", text );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse Fibre Channel ELS handler name
+ *
+ * @v text		Text
+ * @ret handler		Fibre Channel ELS handler
+ * @ret rc		Return status code
+ */
+static int parse_fc_els_handler ( const char *text,
+				  struct fc_els_handler **handler ) {
+
+	for_each_table_entry ( (*handler), FC_ELS_HANDLERS ) {
+		if ( strcasecmp ( (*handler)->name, text ) == 0 )
+			return 0;
+	}
+
+	printf ( "\"%s\": unrecognised ELS\n", text );
+	return -ENOENT;
+}
+
+/** "fcstat" options */
+struct fcstat_options {};
+
+/** "fcstat" option list */
+static struct option_descriptor fcstat_opts[] = {};
+
+/** "fcstat" command descriptor */
+static struct command_descriptor fcstat_cmd =
+	COMMAND_DESC ( struct fcstat_options, fcstat_opts, 0, 0, "" );
+
+/**
+ * The "fcstat" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int fcstat_exec ( int argc, char **argv ) {
+	struct fcstat_options opts;
+	struct fc_port *port;
+	struct fc_peer *peer;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &fcstat_cmd, &opts ) ) != 0 )
+		return rc;
+
+	list_for_each_entry ( port, &fc_ports, list )
+		fcportstat ( port );
+	list_for_each_entry ( peer, &fc_peers, list )
+		fcpeerstat ( peer );
+
+	return 0;
+}
+
+/** "fcels" options */
+struct fcels_options {
+	/** Fibre Channel port */
+	struct fc_port *port;
+	/** Fibre Channel peer port ID */
+	struct fc_port_id peer_port_id;
+};
+
+/** "fcels" option list */
+static struct option_descriptor fcels_opts[] = {
+	OPTION_DESC ( "port", 'p', required_argument,
+		      struct fcels_options, port, parse_fc_port ),
+	OPTION_DESC ( "id", 'i', required_argument,
+		      struct fcels_options, peer_port_id, parse_fc_port_id ),
+};
+
+/** "fcels" command descriptor */
+static struct command_descriptor fcels_cmd =
+	COMMAND_DESC ( struct fcels_options, fcels_opts, 1, 1,
+		       "[--port <port>] [--id <peer port id>] <request>" );
+
+/**
+ * The "fcels" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int fcels_exec ( int argc, char **argv ) {
+	struct fcels_options opts;
+	struct fc_els_handler *handler;
+	struct fc_port_id *id;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &fcels_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse ELS handler */
+	if ( ( rc = parse_fc_els_handler ( argv[optind], &handler ) ) != 0 )
+		return rc;
+
+	/* Use first port if no port specified */
+	if ( ! opts.port ) {
+		opts.port = list_first_entry ( &fc_ports, struct fc_port,
+					       list );
+		if ( ! opts.port ) {
+			printf ( "No ports\n" );
+			return -ENODEV;
+		}
+	}
+
+	/* Use link peer port ID if no peer port ID specified */
+	id = &opts.peer_port_id;
+	if ( memcmp ( id, &fc_empty_port_id, sizeof ( *id ) ) == 0 ) {
+		if ( fc_link_ok ( &opts.port->link ) &&
+		     ! ( opts.port->flags & FC_PORT_HAS_FABRIC ) ) {
+			id = &opts.port->ptp_link_port_id;
+		} else {
+			id = &fc_f_port_id;
+		}
+	}
+
+	/** Issue ELS */
+	if ( ( rc = fcels ( opts.port, id, handler ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** Fibre Channel management commands */
+struct command fcmgmt_commands[] __command = {
+	{
+		.name = "fcstat",
+		.exec = fcstat_exec,
+	},
+	{
+		.name = "fcels",
+		.exec = fcels_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/gdbstub_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/gdbstub_cmd.c
new file mode 100644
index 0000000..f35f014
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/gdbstub_cmd.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha at gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/gdbstub.h>
+
+/** @file
+ *
+ * GDB stub command
+ *
+ */
+
+/**
+ * Parse GDB transport name
+ *
+ * @v text		Text
+ * @ret trans		GDB transport
+ * @ret rc		Return status code
+ */
+static int parse_gdb_transport ( const char *text,
+				 struct gdb_transport **trans ) {
+
+	/* Sanity check */
+	assert ( text != NULL );
+
+	/* Find transport */
+	*trans = find_gdb_transport ( text );
+	if ( ! *trans ) {
+		printf ( "\"%s\": no such transport (is it compiled in?)\n",
+			 text );
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+/** "gdbstub" options */
+struct gdbstub_options {};
+
+/** "gdbstub" option list */
+static struct option_descriptor gdbstub_opts[] = {};
+
+/** "gdbstub" command descriptor */
+static struct command_descriptor gdbstub_cmd =
+	COMMAND_DESC ( struct gdbstub_options, gdbstub_opts, 1, MAX_ARGUMENTS,
+		       "<transport> [<options>...]" );
+
+/**
+ * The "gdbstub" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int gdbstub_exec ( int argc, char **argv ) {
+	struct gdbstub_options opts;
+	struct gdb_transport *trans;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &gdbstub_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse transport name */
+	if ( ( rc = parse_gdb_transport ( argv[optind++], &trans ) ) != 0 )
+		return rc;
+
+	/* Initialise transport */
+	if ( trans->init ) {
+		if ( ( rc = trans->init ( argc - optind,
+					  &argv[optind] ) ) != 0 ) {
+			return rc;
+		}
+	}
+
+	/* Enter GDB stub */
+	gdbstub_start ( trans );
+
+	return 0;
+}
+
+/** GDB stub commands */
+struct command gdbstub_commands[] __command = {
+	{
+		.name = "gdbstub",
+		.exec = gdbstub_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/ifmgmt_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
new file mode 100644
index 0000000..29691d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/ifmgmt.h>
+#include <hci/ifmgmt_cmd.h>
+
+/** @file
+ *
+ * Network interface management commands
+ *
+ */
+
+/** "if<xxx>" command options */
+struct option_descriptor ifcommon_opts[0];
+
+/**
+ * Execute if<xxx> command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v cmd		Command descriptor
+ * @v payload		Command to execute
+ * @v verb		Verb describing the action of the command
+ * @ret rc		Return status code
+ */
+int ifcommon_exec ( int argc, char **argv,
+		    struct command_descriptor *cmd,
+		    int ( * payload ) ( struct net_device * ),
+		    int stop_on_first_success ) {
+	struct ifcommon_options opts;
+	struct net_device *netdev;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
+		return rc;
+
+	if ( optind != argc ) {
+		/* Treat arguments as a list of interfaces to try */
+		while ( optind != argc ) {
+			if ( ( rc = parse_netdev ( argv[optind++],
+						   &netdev ) ) != 0 ) {
+				continue;
+			}
+			if ( ( ( rc = payload ( netdev ) ) == 0 ) &&
+			     stop_on_first_success ) {
+				return 0;
+			}
+		}
+	} else {
+		/* Try all interfaces */
+		rc = -ENODEV;
+		for_each_netdev ( netdev ) {
+			if ( ( ( rc = payload ( netdev ) ) == 0 ) &&
+			     stop_on_first_success ) {
+				return 0;
+			}
+		}
+	}
+
+	return rc;
+}
+
+/** "ifopen" command descriptor */
+static struct command_descriptor ifopen_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "ifopen" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int ifopen_payload ( struct net_device *netdev ) {
+	return ifopen ( netdev );
+}
+
+/**
+ * The "ifopen" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int ifopen_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &ifopen_cmd, ifopen_payload, 0 );
+}
+
+/** "ifclose" command descriptor */
+static struct command_descriptor ifclose_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "ifclose" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int ifclose_payload ( struct net_device *netdev ) {
+	ifclose ( netdev );
+	return 0;
+}
+
+/**
+ * The "ifclose" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int ifclose_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &ifclose_cmd, ifclose_payload, 0 );
+}
+
+/** "ifstat" command descriptor */
+static struct command_descriptor ifstat_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "ifstat" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int ifstat_payload ( struct net_device *netdev ) {
+	ifstat ( netdev );
+	return 0;
+}
+
+/**
+ * The "ifstat" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int ifstat_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &ifstat_cmd, ifstat_payload, 0 );
+}
+
+/** Interface management commands */
+struct command ifmgmt_commands[] __command = {
+	{
+		.name = "ifopen",
+		.exec = ifopen_exec,
+	},
+	{
+		.name = "ifclose",
+		.exec = ifclose_exec,
+	},
+	{
+		.name = "ifstat",
+		.exec = ifstat_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/image_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/image_cmd.c
new file mode 100644
index 0000000..1ff3ff4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/image_cmd.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/image.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+
+/** @file
+ *
+ * Image management commands
+ *
+ */
+
+/** "imgfetch" options */
+struct imgfetch_options {
+	/** Image name */
+	const char *name;
+};
+
+/** "imgfetch" option list */
+static struct option_descriptor imgfetch_opts[] = {
+	OPTION_DESC ( "name", 'n', required_argument,
+		      struct imgfetch_options, name, parse_string ),
+};
+
+/** "imgfetch" command descriptor */
+static struct command_descriptor imgfetch_cmd =
+	COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
+		       "[--name <name>] <uri> [<arguments>...]" );
+
+/**
+ * The "imgfetch" and friends command body
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v cmd		Command descriptor
+ * @v action_name	Action name (for error messages)
+ * @v action		Action to take upon a successful download
+ * @ret rc		Return status code
+ */
+static int imgfetch_core_exec ( int argc, char **argv,
+				const char *action_name,
+				int ( * action ) ( struct image *image ) ) {
+	struct imgfetch_options opts;
+	char *uri_string;
+	char *cmdline = NULL;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgfetch_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse URI string */
+	uri_string = argv[optind];
+
+	/* Parse command line */
+	if ( argv[ optind + 1 ] != NULL ) {
+		cmdline = concat_args ( &argv[ optind + 1 ] );
+		if ( ! cmdline ) {
+			rc = -ENOMEM;
+			goto err_cmdline;
+		}
+	}
+
+	/* Fetch the image */
+	if ( ( rc = imgdownload_string ( uri_string, opts.name, cmdline,
+					 action ) ) != 0 ) {
+		printf ( "Could not %s %s: %s\n",
+			 action_name, uri_string, strerror ( rc ) );
+		goto err_imgdownload;
+	}
+
+	/* Free command line */
+	free ( cmdline );
+
+	return 0;
+
+ err_imgdownload:
+	free ( cmdline );
+ err_cmdline:
+ err_parse_options:
+	return rc;
+}
+
+/**
+ * The "imgfetch"/"module" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgfetch_exec ( int argc, char **argv ) {
+
+	return imgfetch_core_exec ( argc, argv, "fetch",
+				    register_and_put_image );
+}
+
+/**
+ * The "kernel" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int kernel_exec ( int argc, char **argv ) {
+
+	return imgfetch_core_exec ( argc, argv, "select",
+				    register_and_select_image );
+}
+
+/**
+ * The "chain" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int chain_exec ( int argc, char **argv) {
+
+	return imgfetch_core_exec ( argc, argv, "boot",
+				    register_and_boot_image );
+}
+
+/** "imgselect" options */
+struct imgselect_options {};
+
+/** "imgselect" option list */
+static struct option_descriptor imgselect_opts[] = {};
+
+/** "imgselect" command descriptor */
+static struct command_descriptor imgselect_cmd =
+	COMMAND_DESC ( struct imgselect_options, imgselect_opts, 1, 1,
+		       "<image>" );
+
+/**
+ * The "imgselect" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgselect_exec ( int argc, char **argv ) {
+	struct imgselect_options opts;
+	struct image *image;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgselect_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse image name */
+	if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
+		return rc;
+
+	/* Load image */
+	if ( ( rc = imgselect ( image ) ) != 0 ) {
+		printf ( "Could not select %s: %s\n",
+			 image->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** "imgargs" options */
+struct imgargs_options {};
+
+/** "imgargs" option list */
+static struct option_descriptor imgargs_opts[] = {};
+
+/** "imgargs" command descriptor */
+static struct command_descriptor imgargs_cmd =
+	COMMAND_DESC ( struct imgargs_options, imgargs_opts, 1, MAX_ARGUMENTS,
+		       "<image> [<arguments>...]" );
+
+/**
+ * The "imgargs" command body
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgargs_exec ( int argc, char **argv ) {
+	struct imgargs_options opts;
+	struct image *image;
+	char *cmdline = NULL;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgargs_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse image name */
+	if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
+		goto err_parse_image;
+
+	/* Parse command line */
+	if ( argv[ optind + 1 ] != NULL ) {
+		cmdline = concat_args ( &argv[ optind + 1 ] );
+		if ( ! cmdline ) {
+			rc = -ENOMEM;
+			goto err_cmdline;
+		}
+	}
+
+	/* Set command line */
+	if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 )
+		goto err_set_cmdline;
+
+	/* Free command line */
+	free ( cmdline );
+
+	return 0;
+
+ err_set_cmdline:
+	free ( cmdline );
+ err_cmdline:
+ err_parse_image:
+ err_parse_options:
+	return rc;
+}
+
+/** "imgexec" options */
+struct imgexec_options {};
+
+/** "imgexec" option list */
+static struct option_descriptor imgexec_opts[] = {};
+
+/** "imgexec" command descriptor */
+static struct command_descriptor imgexec_cmd =
+	COMMAND_DESC ( struct imgexec_options, imgexec_opts, 0, 1,
+		       "[<image>]" );
+
+/**
+ * The "imgexec" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgexec_exec ( int argc, char **argv ) {
+	struct imgexec_options opts;
+	struct image *image;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgexec_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse image name */
+	if ( optind < argc ) {
+		if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
+			return rc;
+	} else {
+		image = imgautoselect();
+		if ( ! image ) {
+			rc = -ENOTTY;
+			printf ( "No image selected: %s\n", strerror ( rc ) );
+			return rc;
+		}
+	}
+
+	/* Execute image */
+	if ( ( rc = imgexec ( image ) ) != 0 ) {
+		printf ( "Could not execute %s: %s\n",
+			 image->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** "imgstat" options */
+struct imgstat_options {};
+
+/** "imgstat" option list */
+static struct option_descriptor imgstat_opts[] = {};
+
+/** "imgstat" command descriptor */
+static struct command_descriptor imgstat_cmd =
+	COMMAND_DESC ( struct imgstat_options, imgstat_opts, 0, 0, "" );
+
+/**
+ * The "imgstat" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgstat_exec ( int argc, char **argv ) {
+	struct imgstat_options opts;
+	struct image *image;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgstat_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Show status of all images */
+	for_each_image ( image ) {
+		imgstat ( image );
+	}
+
+	return 0;
+}
+
+/** "imgfree" options */
+struct imgfree_options {};
+
+/** "imgfree" option list */
+static struct option_descriptor imgfree_opts[] = {};
+
+/** "imgfree" command descriptor */
+static struct command_descriptor imgfree_cmd =
+	COMMAND_DESC ( struct imgfree_options, imgfree_opts, 0, 1,
+		       "[<image>]" );
+
+/**
+ * The "imgfree" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgfree_exec ( int argc, char **argv ) {
+	struct imgfree_options opts;
+	struct image *image;
+	struct image *tmp;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgfree_cmd, &opts ) ) != 0 )
+		return rc;
+
+	if ( optind < argc ) {
+		/* Free specified image */
+		if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
+			return rc;
+		imgfree ( image );
+	} else {
+		/* Free all images */
+		list_for_each_entry_safe ( image, tmp, &images, list ) {
+			imgfree ( image );
+		}
+	}
+
+	return 0;
+}
+
+/** Image management commands */
+struct command image_commands[] __command = {
+	{
+		.name = "imgfetch",
+		.exec = imgfetch_exec,
+	},
+	{
+		.name = "module",
+		.exec = imgfetch_exec, /* synonym for "imgfetch" */
+	},
+	{
+		.name = "initrd",
+		.exec = imgfetch_exec, /* synonym for "imgfetch" */
+	},
+	{
+		.name = "kernel",
+		.exec = kernel_exec,
+	},
+	{
+		.name = "chain",
+		.exec = chain_exec,
+	},
+	{
+		.name = "imgselect",
+		.exec = imgselect_exec,
+	},
+	{
+		.name = "imgload", /* synonym for "imgselect" */
+		.exec = imgselect_exec,
+	},
+	{
+		.name = "imgargs",
+		.exec = imgargs_exec,
+	},
+	{
+		.name = "imgexec",
+		.exec = imgexec_exec,
+	},
+	{
+		.name = "boot", /* synonym for "imgexec" */
+		.exec = imgexec_exec,
+	},
+	{
+		.name = "imgstat",
+		.exec = imgstat_exec,
+	},
+	{
+		.name = "imgfree",
+		.exec = imgfree_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/iwmgmt_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/iwmgmt_cmd.c
new file mode 100644
index 0000000..00a8360
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/iwmgmt_cmd.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/netdevice.h>
+#include <ipxe/net80211.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/iwmgmt.h>
+#include <hci/ifmgmt_cmd.h>
+
+/** @file
+ *
+ * Wireless interface management commands
+ *
+ */
+
+/** "iwstat" command descriptor */
+static struct command_descriptor iwstat_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "iwstat" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int iwstat_payload ( struct net_device *netdev ) {
+	struct net80211_device *dev = net80211_get ( netdev );
+
+	if ( dev )
+		iwstat ( dev );
+
+	return 0;
+}
+
+/**
+ * The "iwstat" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int iwstat_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &iwstat_cmd, iwstat_payload, 0 );
+}
+
+/** "iwlist" command descriptor */
+static struct command_descriptor iwlist_cmd =
+	COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS,
+		       "[<interface>...]" );
+
+/**
+ * "iwlist" payload
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int iwlist_payload ( struct net_device *netdev ) {
+	struct net80211_device *dev = net80211_get ( netdev );
+
+	if ( dev )
+		return iwlist ( dev );
+
+	return 0;
+}
+
+/**
+ * The "iwlist" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int iwlist_exec ( int argc, char **argv ) {
+	return ifcommon_exec ( argc, argv, &iwlist_cmd, iwlist_payload, 0 );
+}
+
+/** Wireless interface management commands */
+struct command iwmgmt_commands[] __command = {
+	{
+		.name = "iwstat",
+		.exec = iwstat_exec,
+	},
+	{
+		.name = "iwlist",
+		.exec = iwlist_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/login_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/login_cmd.c
new file mode 100644
index 0000000..3286932
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/login_cmd.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/login_ui.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Login commands
+ *
+ */
+
+/** "login" options */
+struct login_options {};
+
+/** "login" option list */
+static struct option_descriptor login_opts[] = {};
+
+/** "login" command descriptor */
+static struct command_descriptor login_cmd =
+	COMMAND_DESC ( struct login_options, login_opts, 0, 0, "" );
+
+/**
+ * "login" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int login_exec ( int argc, char **argv ) {
+	struct login_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &login_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Show login UI */
+	if ( ( rc = login_ui() ) != 0 ) {
+		printf ( "Could not set credentials: %s\n",
+			 strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** Login commands */
+struct command login_command __command = {
+	.name = "login",
+	.exec = login_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/lotest_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/lotest_cmd.c
new file mode 100644
index 0000000..172be2d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/lotest_cmd.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/if_ether.h>
+#include <usr/lotest.h>
+
+/** @file
+ *
+ * Loopback testing commands
+ *
+ */
+
+/** "lotest" options */
+struct lotest_options {
+	/** MTU */
+	unsigned int mtu;
+};
+
+/** "lotest" option list */
+static struct option_descriptor lotest_opts[] = {
+	OPTION_DESC ( "mtu", 'm', required_argument,
+		      struct lotest_options, mtu, parse_integer ),
+};
+
+/** "lotest" command descriptor */
+static struct command_descriptor lotest_cmd =
+	COMMAND_DESC ( struct lotest_options, lotest_opts, 2, 2,
+		       "[--mtu <mtu>] <sending interface> "
+		       "<receiving interface>" );
+
+/**
+ * "lotest" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int lotest_exec ( int argc, char **argv ) {
+	struct lotest_options opts;
+	struct net_device *sender;
+	struct net_device *receiver;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &lotest_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse sending interface name */
+	if ( ( rc = parse_netdev ( argv[optind], &sender ) ) != 0 )
+		return rc;
+
+	/* Parse receiving interface name */
+	if ( ( rc = parse_netdev ( argv[ optind + 1 ], &receiver ) ) != 0 )
+		return rc;
+
+	/* Use default MTU if none specified */
+	if ( ! opts.mtu )
+		opts.mtu = ETH_MAX_MTU;
+
+	/* Perform loopback test */
+	if ( ( rc = loopback_test ( sender, receiver, opts.mtu ) ) != 0 ) {
+		printf ( "Test failed: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** Loopback testing commands */
+struct command lotest_command __command = {
+	.name = "lotest",
+	.exec = lotest_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/nvo_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/nvo_cmd.c
new file mode 100644
index 0000000..a7e0f4a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/nvo_cmd.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/settings.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <readline/readline.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Non-volatile option commands
+ *
+ */
+
+/** "show" options */
+struct show_options {};
+
+/** "show" option list */
+static struct option_descriptor show_opts[] = {};
+
+/** "show" command descriptor */
+static struct command_descriptor show_cmd =
+	COMMAND_DESC ( struct show_options, show_opts, 1, 1, "<setting>" );
+
+/**
+ * "show" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int show_exec ( int argc, char **argv ) {
+	struct show_options opts;
+	const char *name;
+	char name_buf[32];
+	char value_buf[256];
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &show_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse setting name */
+	name = argv[optind];
+
+	/* Fetch setting */
+	if ( ( rc = fetchf_named_setting ( name, name_buf, sizeof ( name_buf ),
+					   value_buf,
+					   sizeof ( value_buf ) ) ) < 0 ) {
+		printf ( "Could not find \"%s\": %s\n",
+			 name, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Print setting value */
+	printf ( "%s = %s\n", name_buf, value_buf );
+
+	return 0;
+}
+
+/** "set", "clear", and "read" options */
+struct set_core_options {};
+
+/** "set", "clear", and "read" option list */
+static struct option_descriptor set_core_opts[] = {};
+
+/** "set" command descriptor */
+static struct command_descriptor set_cmd =
+	COMMAND_DESC ( struct set_core_options, set_core_opts, 1, MAX_ARGUMENTS,
+		       "<setting> <value>" );
+
+/** "clear" and "read" command descriptor */
+static struct command_descriptor clear_read_cmd =
+	COMMAND_DESC ( struct set_core_options, set_core_opts, 1, 1,
+		       "<setting>" );
+
+/**
+ * "set", "clear", and "read" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v cmd		Command descriptor
+ * @v get_value		Method to obtain setting value
+ * @ret rc		Return status code
+ */
+static int set_core_exec ( int argc, char **argv,
+			   struct command_descriptor *cmd,
+			   int ( * get_value ) ( char **args, char **value ) ) {
+	struct set_core_options opts;
+	const char *name;
+	char *value;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse setting name */
+	name = argv[optind];
+
+	/* Parse setting value */
+	if ( ( rc = get_value ( &argv[ optind + 1 ], &value ) ) != 0 )
+		goto err_get_value;
+
+	/* Determine total length of command line */
+	if ( ( rc = storef_named_setting ( name, value ) ) != 0 ) {
+		printf ( "Could not %s \"%s\": %s\n",
+			 argv[0], name, strerror ( rc ) );
+		goto err_store;
+	}
+
+	free ( value );
+	return 0;
+
+ err_store:
+	free ( value );
+ err_get_value:
+ err_parse_options:
+	return rc;
+}
+
+/**
+ * Get setting value for "set" command
+ *
+ * @v args		Remaining arguments
+ * @ret value		Setting value
+ * @ret rc		Return status code
+ */
+static int set_value ( char **args, char **value ) {
+
+	*value = concat_args ( args );
+	if ( ! *value )
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * "set" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int set_exec ( int argc, char **argv ) {
+	return set_core_exec ( argc, argv, &set_cmd, set_value );
+}
+
+/**
+ * Get setting value for "clear" command
+ *
+ * @v args		Remaining arguments
+ * @ret value		Setting value
+ * @ret rc		Return status code
+ */
+static int clear_value ( char **args __unused, char **value ) {
+
+	*value = NULL;
+	return 0;
+}
+
+/**
+ * "clear" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int clear_exec ( int argc, char **argv ) {
+	return set_core_exec ( argc, argv, &clear_read_cmd, clear_value );
+}
+
+/**
+ * Get setting value for "read" command
+ *
+ * @ret value		Setting value
+ * @ret rc		Return status code
+ */
+static int read_value ( char **args __unused, char **value ) {
+
+	*value = readline ( NULL );
+	if ( ! *value )
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * "read" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int read_exec ( int argc, char **argv ) {
+	return set_core_exec ( argc, argv, &clear_read_cmd, read_value );
+}
+
+/** Non-volatile option commands */
+struct command nvo_commands[] __command = {
+	{
+		.name = "show",
+		.exec = show_exec,
+	},
+	{
+		.name = "set",
+		.exec = set_exec,
+	},	
+	{
+		.name = "clear",
+		.exec = clear_exec,
+	},
+	{
+		.name = "read",
+		.exec = read_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/route_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/route_cmd.c
new file mode 100644
index 0000000..f839d53
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/route_cmd.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/route.h>
+
+/** @file
+ *
+ * Routing table management commands
+ *
+ */
+
+/** "route" options */
+struct route_options {};
+
+/** "route" option list */
+static struct option_descriptor route_opts[] = {};
+
+/** "route" command descriptor */
+static struct command_descriptor route_cmd =
+	COMMAND_DESC ( struct route_options, route_opts, 0, 0, "" );
+
+/**
+ * The "route" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int route_exec ( int argc, char **argv ) {
+	struct route_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &route_cmd, &opts ) ) != 0 )
+		return rc;
+
+	route();
+
+	return 0;
+}
+
+/** Routing table management commands */
+struct command route_commands[] __command = {
+	{
+		.name = "route",
+		.exec = route_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/sanboot_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/sanboot_cmd.c
new file mode 100644
index 0000000..198a732
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/sanboot_cmd.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/uri.h>
+#include <usr/autoboot.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SAN commands
+ *
+ */
+
+/** "sanboot" options */
+struct sanboot_options {};
+
+/** "sanboot" option list */
+static struct option_descriptor sanboot_opts[] = {};
+
+/** "sanboot" command descriptor */
+static struct command_descriptor sanboot_cmd =
+	COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1,
+		       "<root-path>" );
+
+/**
+ * The "sanboot" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sanboot_exec ( int argc, char **argv ) {
+	struct sanboot_options opts;
+	const char *root_path;
+	struct uri *uri;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &sanboot_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse root path */
+	root_path = argv[optind];
+	uri = parse_uri ( root_path );
+	if ( ! uri ) {
+		rc = -ENOMEM;
+		goto err_parse_uri;
+	}
+
+	/* Boot from root path */
+	if ( ( rc = uriboot ( NULL, uri ) ) != 0 ) {
+		printf ( "Could not boot from %s: %s\n",
+			 root_path, strerror ( rc ) );
+		goto err_uriboot;
+	}
+
+ err_uriboot:
+	uri_put ( uri );
+ err_parse_uri:
+ err_parse_options:
+	return rc;
+}
+
+/** SAN commands */
+struct command sanboot_command __command = {
+	.name = "sanboot",
+	.exec = sanboot_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/time_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/time_cmd.c
new file mode 100644
index 0000000..1dd1757
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/time_cmd.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2009 Daniel Verkamp <daniel at drv.nu>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * March-19-2009 @ 02:44: Added sleep command.
+ * Shao Miller <shao.miller at yrdsb.edu.on.ca>.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/nap.h>
+#include <ipxe/timer.h>
+
+/** @file
+ *
+ * Time commands
+ *
+ */
+
+/** "time" options */
+struct time_options {};
+
+/** "time" option list */
+static struct option_descriptor time_opts[] = {};
+
+/** "time" command descriptor */
+static struct command_descriptor time_cmd =
+	COMMAND_DESC ( struct time_options, time_opts, 1, MAX_ARGUMENTS,
+		       "<command>" );
+
+/**
+ * "time" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int time_exec ( int argc, char **argv ) {
+	struct time_options opts;
+	unsigned long start;
+	int secs;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &time_cmd, &opts ) ) != 0 )
+		return rc;
+
+	start = currticks();
+	rc = execv ( argv[1], argv + 1 );
+	secs = (currticks() - start) / ticks_per_sec();
+
+	printf ( "%s: %ds\n", argv[0], secs );
+
+	return rc;
+}
+
+/** "time" command */
+struct command time_command __command = {
+	.name = "time",
+	.exec = time_exec,
+};
+
+/** "sleep" options */
+struct sleep_options {};
+
+/** "sleep" option list */
+static struct option_descriptor sleep_opts[] = {};
+
+/** "sleep" command descriptor */
+static struct command_descriptor sleep_cmd =
+	COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1, "<seconds>" );
+
+/**
+ * "sleep" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sleep_exec ( int argc, char **argv ) {
+	struct sleep_options opts;
+	unsigned long start, delay;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 )
+		return rc;
+
+	start = currticks();
+	delay = strtoul ( argv[1], NULL, 0 ) * ticks_per_sec();
+	while ( ( currticks() - start ) <= delay )
+		cpu_nap();
+	return 0;
+}
+
+/** "sleep" command */
+struct command sleep_command __command = {
+	.name = "sleep",
+	.exec = sleep_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/commands/vlan_cmd.c b/qemu-0.15.x/roms/ipxe/src/hci/commands/vlan_cmd.c
new file mode 100644
index 0000000..28638ae
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/commands/vlan_cmd.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/vlan.h>
+
+/** @file
+ *
+ * VLAN commands
+ *
+ */
+
+/** "vcreate" options */
+struct vcreate_options {
+	/** VLAN tag */
+	unsigned int tag;
+	/** VLAN default priority */
+	unsigned int priority;
+};
+
+/** "vcreate" option list */
+static struct option_descriptor vcreate_opts[] = {
+	OPTION_DESC ( "tag", 't', required_argument,
+		      struct vcreate_options, tag, parse_integer ),
+	OPTION_DESC ( "priority", 'p', required_argument,
+		      struct vcreate_options, priority, parse_integer ),
+};
+
+/** "vcreate" command descriptor */
+static struct command_descriptor vcreate_cmd =
+	COMMAND_DESC ( struct vcreate_options, vcreate_opts, 1, 1,
+		       "--tag <tag> [--priority <priority>] "
+		       "<trunk interface>" );
+
+/**
+ * "vcreate" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int vcreate_exec ( int argc, char **argv ) {
+	struct vcreate_options opts;
+	struct net_device *trunk;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &vcreate_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse trunk interface */
+	if ( ( rc = parse_netdev ( argv[optind], &trunk ) ) != 0 )
+		return rc;
+
+	/* Create VLAN device */
+	if ( ( rc = vlan_create ( trunk, opts.tag, opts.priority ) ) != 0 ) {
+		printf ( "Could not create VLAN device: %s\n",
+			 strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** "vdestroy" options */
+struct vdestroy_options {};
+
+/** "vdestroy" option list */
+static struct option_descriptor vdestroy_opts[] = {};
+
+/** "vdestroy" command descriptor */
+static struct command_descriptor vdestroy_cmd =
+	COMMAND_DESC ( struct vdestroy_options, vdestroy_opts, 1, 1,
+		       "<VLAN interface>" );
+
+/**
+ * "vdestroy" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int vdestroy_exec ( int argc, char **argv ) {
+	struct vdestroy_options opts;
+	struct net_device *netdev;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &vdestroy_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse trunk interface */
+	if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 )
+		return rc;
+
+	/* Destroy VLAN device */
+	if ( ( rc = vlan_destroy ( netdev ) ) != 0 ) {
+		printf ( "Could not destroy VLAN device: %s\n",
+			 strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** VLAN commands */
+struct command vlan_commands[] __command = {
+	{
+		.name = "vcreate",
+		.exec = vcreate_exec,
+	},
+	{
+		.name = "vdestroy",
+		.exec = vdestroy_exec,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/editstring.c b/qemu-0.15.x/roms/ipxe/src/hci/editstring.c
new file mode 100644
index 0000000..996528f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/editstring.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/keys.h>
+#include <ipxe/editstring.h>
+
+/** @file
+ *
+ * Editable strings
+ *
+ */
+
+static void insert_delete ( struct edit_string *string, size_t delete_len,
+                            const char *insert_text ) 
+			    __attribute__ (( nonnull (1) ));
+static void insert_character ( struct edit_string *string,
+                               unsigned int character ) __nonnull;
+static void delete_character ( struct edit_string *string ) __nonnull;
+static void backspace ( struct edit_string *string ) __nonnull;
+static void kill_eol ( struct edit_string *string ) __nonnull;
+
+/**
+ * Insert and/or delete text within an editable string
+ *
+ * @v string		Editable string
+ * @v delete_len	Length of text to delete from current cursor position
+ * @v insert_text	Text to insert at current cursor position, or NULL
+ */
+static void insert_delete ( struct edit_string *string, size_t delete_len,
+			    const char *insert_text ) {
+	size_t old_len, max_delete_len, insert_len, max_insert_len, new_len;
+
+	/* Calculate lengths */
+	old_len = strlen ( string->buf );
+	assert ( string->cursor <= old_len );
+	max_delete_len = ( old_len - string->cursor );
+	if ( delete_len > max_delete_len )
+		delete_len = max_delete_len;
+	insert_len = ( insert_text ? strlen ( insert_text ) : 0 );
+	max_insert_len = ( ( string->len - 1 ) - ( old_len - delete_len ) );
+	if ( insert_len > max_insert_len )
+		insert_len = max_insert_len;
+	new_len = ( old_len - delete_len + insert_len );
+
+	/* Fill in edit history */
+	string->mod_start = string->cursor;
+	string->mod_end = ( ( new_len > old_len ) ? new_len : old_len );
+
+	/* Move data following the cursor */
+	memmove ( ( string->buf + string->cursor + insert_len ),
+		  ( string->buf + string->cursor + delete_len ),
+		  ( max_delete_len + 1 - delete_len ) );
+
+	/* Copy inserted text to cursor position */
+	memcpy ( ( string->buf + string->cursor ), insert_text, insert_len );
+	string->cursor += insert_len;
+}
+
+/**
+ * Insert character at current cursor position
+ *
+ * @v string		Editable string
+ * @v character		Character to insert
+ */
+static void insert_character ( struct edit_string *string,
+			      unsigned int character ) {
+	char insert_text[2] = { character, '\0' };
+	insert_delete ( string, 0, insert_text );
+}
+
+/**
+ * Delete character at current cursor position
+ *
+ * @v string		Editable string
+ */
+static void delete_character ( struct edit_string *string ) {
+	insert_delete ( string, 1, NULL );
+}
+
+/**
+ * Delete character to left of current cursor position
+ *
+ * @v string		Editable string
+ */
+static void backspace ( struct edit_string *string ) {
+	if ( string->cursor > 0 ) {
+		string->cursor--;
+		delete_character ( string );
+	}
+}
+
+/**
+ * Delete to end of line
+ *
+ * @v string		Editable string
+ */
+static void kill_eol ( struct edit_string *string ) {
+	insert_delete ( string, ~( ( size_t ) 0 ), NULL );
+}
+
+/**
+ * Replace editable string
+ *
+ * @v string		Editable string
+ * @v replacement	Replacement string
+ */
+void replace_string ( struct edit_string *string, const char *replacement ) {
+	string->cursor = 0;
+	insert_delete ( string, ~( ( size_t ) 0 ), replacement );
+}
+
+/**
+ * Edit editable string
+ *
+ * @v string		Editable string
+ * @v key		Key pressed by user
+ * @ret key		Key returned to application, or zero
+ *
+ * Handles keypresses and updates the content of the editable string.
+ * Basic line editing facilities (delete/insert/cursor) are supported.
+ * If edit_string() understands and uses the keypress it will return
+ * zero, otherwise it will return the original key.
+ *
+ * This function does not update the display in any way.
+ *
+ * The string's edit history will be updated to allow the caller to
+ * efficiently bring the display into sync with the string content.
+ */
+int edit_string ( struct edit_string *string, int key ) {
+	int retval = 0;
+	size_t len = strlen ( string->buf );
+
+	/* Prepare edit history */
+	string->last_cursor = string->cursor;
+	string->mod_start = string->cursor;
+	string->mod_end = string->cursor;
+
+	/* Interpret key */
+	if ( ( key >= 0x20 ) && ( key <= 0x7e ) ) {
+		/* Printable character; insert at current position */
+		insert_character ( string, key );
+	} else switch ( key ) {
+	case KEY_BACKSPACE:
+		/* Backspace */
+		backspace ( string );
+		break;
+	case KEY_DC:
+	case CTRL_D:
+		/* Delete character */
+		delete_character ( string );
+		break;
+	case CTRL_K:
+		/* Delete to end of line */
+		kill_eol ( string );
+		break;
+	case KEY_HOME:
+	case CTRL_A:
+		/* Start of line */
+		string->cursor = 0;
+		break;
+	case KEY_END:
+	case CTRL_E:
+		/* End of line */
+		string->cursor = len;
+		break;
+	case KEY_LEFT:
+	case CTRL_B:
+		/* Cursor left */
+		if ( string->cursor > 0 )
+			string->cursor--;
+		break;
+	case KEY_RIGHT:
+	case CTRL_F:
+		/* Cursor right */
+		if ( string->cursor < len )
+			string->cursor++;
+		break;
+	default:
+		retval = key;
+		break;
+	}
+
+	return retval;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_al.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_al.c
new file mode 100644
index 0000000..caf295e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_al.c
@@ -0,0 +1,32 @@
+/** @file
+ *
+ * "al" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "al" keyboard mapping */
+struct key_mapping al_mapping[] __keymap = {
+	{ 0x19, 0x1a },	/* Ctrl-Y => Ctrl-Z */
+	{ 0x1a, 0x19 },	/* Ctrl-Z => Ctrl-Y */
+	{ 0x22, 0x7b },	/* '"' => '{' */
+	{ 0x27, 0x5b },	/* '\'' => '[' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x59, 0x5a },	/* 'Y' => 'Z' */
+	{ 0x5a, 0x59 },	/* 'Z' => 'Y' */
+	{ 0x5c, 0x5d },	/* '\\' => ']' */
+	{ 0x5d, 0x40 },	/* ']' => '@' */
+	{ 0x60, 0x5c },	/* '`' => '\\' */
+	{ 0x79, 0x7a },	/* 'y' => 'z' */
+	{ 0x7a, 0x79 },	/* 'z' => 'y' */
+	{ 0x7c, 0x7d },	/* '|' => '}' */
+	{ 0x7d, 0x27 },	/* '}' => '\'' */
+	{ 0x7e, 0x7c },	/* '~' => '|' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_az.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_az.c
new file mode 100644
index 0000000..27ce91e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_az.c
@@ -0,0 +1,24 @@
+/** @file
+ *
+ * "az" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "az" keyboard mapping */
+struct key_mapping az_mapping[] __keymap = {
+	{ 0x23, 0x27 },	/* '#' => '\'' */
+	{ 0x24, 0x3b },	/* '$' => ';' */
+	{ 0x26, 0x3f },	/* '&' => '?' */
+	{ 0x2f, 0x2e },	/* '/' => '.' */
+	{ 0x3a, 0x49 },	/* ':' => 'I' */
+	{ 0x3f, 0x2c },	/* '?' => ',' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5e, 0x3a },	/* '^' => ':' */
+	{ 0x7c, 0x2f },	/* '|' => '/' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_bg.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_bg.c
new file mode 100644
index 0000000..62b6bae
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_bg.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "bg" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "bg" keyboard mapping */
+struct key_mapping bg_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_by.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_by.c
new file mode 100644
index 0000000..514d0b5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_by.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "by" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "by" keyboard mapping */
+struct key_mapping by_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cf.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cf.c
new file mode 100644
index 0000000..d7e63b9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cf.c
@@ -0,0 +1,24 @@
+/** @file
+ *
+ * "cf" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "cf" keyboard mapping */
+struct key_mapping cf_mapping[] __keymap = {
+	{ 0x23, 0x2f },	/* '#' => '/' */
+	{ 0x3c, 0x27 },	/* '<' => '\'' */
+	{ 0x3e, 0x2e },	/* '>' => '.' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x3c },	/* '\\' => '<' */
+	{ 0x5e, 0x3f },	/* '^' => '?' */
+	{ 0x60, 0x23 },	/* '`' => '#' */
+	{ 0x7c, 0x3e },	/* '|' => '>' */
+	{ 0x7e, 0x7c },	/* '~' => '|' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cz.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cz.c
new file mode 100644
index 0000000..9280f84
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_cz.c
@@ -0,0 +1,27 @@
+/** @file
+ *
+ * "cz" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "cz" keyboard mapping */
+struct key_mapping cz_mapping[] __keymap = {
+	{ 0x21, 0x2b },	/* '!' => '+' */
+	{ 0x2d, 0x3d },	/* '-' => '=' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x31, 0x2b },	/* '1' => '+' */
+	{ 0x3c, 0x2c },	/* '<' => ',' */
+	{ 0x3e, 0x2e },	/* '>' => '.' */
+	{ 0x3f, 0x2d },	/* '?' => '-' */
+	{ 0x5d, 0x29 },	/* ']' => ')' */
+	{ 0x5f, 0x3d },	/* '_' => '=' */
+	{ 0x60, 0x3b },	/* '`' => ';' */
+	{ 0x7d, 0x29 },	/* '}' => ')' */
+	{ 0x7e, 0x3b },	/* '~' => ';' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_de.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_de.c
new file mode 100644
index 0000000..ffcf912
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_de.c
@@ -0,0 +1,46 @@
+/** @file
+ *
+ * "de" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "de" keyboard mapping */
+struct key_mapping de_mapping[] __keymap = {
+	{ 0x19, 0x1a },	/* Ctrl-Y => Ctrl-Z */
+	{ 0x1a, 0x19 },	/* Ctrl-Z => Ctrl-Y */
+	{ 0x22, 0x7d },	/* '"' => '}' */
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x27, 0x5d },	/* '\'' => ']' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2d, 0x5c },	/* '-' => '\\' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3a, 0x7b },	/* ':' => '{' */
+	{ 0x3b, 0x5b },	/* ';' => '[' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3d, 0x27 },	/* '=' => '\'' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x59, 0x5a },	/* 'Y' => 'Z' */
+	{ 0x5a, 0x59 },	/* 'Z' => 'Y' */
+	{ 0x5b, 0x40 },	/* '[' => '@' */
+	{ 0x5c, 0x23 },	/* '\\' => '#' */
+	{ 0x5d, 0x2b },	/* ']' => '+' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x60, 0x5e },	/* '`' => '^' */
+	{ 0x79, 0x7a },	/* 'y' => 'z' */
+	{ 0x7a, 0x79 },	/* 'z' => 'y' */
+	{ 0x7b, 0x5c },	/* '{' => '\\' */
+	{ 0x7c, 0x27 },	/* '|' => '\'' */
+	{ 0x7d, 0x2a },	/* '}' => '*' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_dk.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_dk.c
new file mode 100644
index 0000000..e409018
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_dk.c
@@ -0,0 +1,31 @@
+/** @file
+ *
+ * "dk" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "dk" keyboard mapping */
+struct key_mapping dk_mapping[] __keymap = {
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2d, 0x2b },	/* '-' => '+' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x27 },	/* '\\' => '\'' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x7c, 0x2a },	/* '|' => '*' */
+	{ 0x7d, 0x5e },	/* '}' => '^' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_es.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_es.c
new file mode 100644
index 0000000..c1fe013
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_es.c
@@ -0,0 +1,29 @@
+/** @file
+ *
+ * "es" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "es" keyboard mapping */
+struct key_mapping es_mapping[] __keymap = {
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2d, 0x27 },	/* '-' => '\'' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5d, 0x2b },	/* ']' => '+' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x7d, 0x2a },	/* '}' => '*' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_et.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_et.c
new file mode 100644
index 0000000..ad88cec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_et.c
@@ -0,0 +1,30 @@
+/** @file
+ *
+ * "et" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "et" keyboard mapping */
+struct key_mapping et_mapping[] __keymap = {
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2d, 0x2b },	/* '-' => '+' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x27 },	/* '\\' => '\'' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x7c, 0x2a },	/* '|' => '*' */
+	{ 0x7f, 0x1b },	/* 0x7f => 0x1b */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fi.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fi.c
new file mode 100644
index 0000000..c8f6c3a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fi.c
@@ -0,0 +1,38 @@
+/** @file
+ *
+ * "fi" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "fi" keyboard mapping */
+struct key_mapping fi_mapping[] __keymap = {
+	{ 0x22, 0x5b },	/* '"' => '[' */
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x27, 0x7b },	/* '\'' => '{' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2d, 0x2b },	/* '-' => '+' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3a, 0x5c },	/* ':' => '\\' */
+	{ 0x3b, 0x7c },	/* ';' => '|' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3d, 0x27 },	/* '=' => '\'' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5b, 0x7d },	/* '[' => '}' */
+	{ 0x5c, 0x27 },	/* '\\' => '\'' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x7b, 0x5d },	/* '{' => ']' */
+	{ 0x7c, 0x2a },	/* '|' => '*' */
+	{ 0x7d, 0x5e },	/* '}' => '^' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fr.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fr.c
new file mode 100644
index 0000000..fd615a4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_fr.c
@@ -0,0 +1,68 @@
+/** @file
+ *
+ * "fr" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "fr" keyboard mapping */
+struct key_mapping fr_mapping[] __keymap = {
+	{ 0x01, 0x11 },	/* Ctrl-A => Ctrl-Q */
+	{ 0x11, 0x01 },	/* Ctrl-Q => Ctrl-A */
+	{ 0x17, 0x1a },	/* Ctrl-W => Ctrl-Z */
+	{ 0x1a, 0x17 },	/* Ctrl-Z => Ctrl-W */
+	{ 0x21, 0x31 },	/* '!' => '1' */
+	{ 0x22, 0x25 },	/* '"' => '%' */
+	{ 0x23, 0x33 },	/* '#' => '3' */
+	{ 0x24, 0x34 },	/* '$' => '4' */
+	{ 0x25, 0x35 },	/* '%' => '5' */
+	{ 0x26, 0x37 },	/* '&' => '7' */
+	{ 0x27, 0x7c },	/* '\'' => '|' */
+	{ 0x28, 0x39 },	/* '(' => '9' */
+	{ 0x29, 0x30 },	/* ')' => '0' */
+	{ 0x2a, 0x38 },	/* '*' => '8' */
+	{ 0x2c, 0x3b },	/* ',' => ';' */
+	{ 0x2d, 0x29 },	/* '-' => ')' */
+	{ 0x2e, 0x3a },	/* '.' => ':' */
+	{ 0x2f, 0x21 },	/* '/' => '!' */
+	{ 0x30, 0x40 },	/* '0' => '@' */
+	{ 0x31, 0x26 },	/* '1' => '&' */
+	{ 0x32, 0x7b },	/* '2' => '{' */
+	{ 0x33, 0x22 },	/* '3' => '"' */
+	{ 0x34, 0x27 },	/* '4' => '\'' */
+	{ 0x35, 0x28 },	/* '5' => '(' */
+	{ 0x36, 0x2d },	/* '6' => '-' */
+	{ 0x37, 0x7d },	/* '7' => '}' */
+	{ 0x38, 0x5f },	/* '8' => '_' */
+	{ 0x39, 0x2f },	/* '9' => '/' */
+	{ 0x3a, 0x4d },	/* ':' => 'M' */
+	{ 0x3b, 0x6d },	/* ';' => 'm' */
+	{ 0x3c, 0x2e },	/* '<' => '.' */
+	{ 0x3e, 0x2f },	/* '>' => '/' */
+	{ 0x3f, 0x5c },	/* '?' => '\\' */
+	{ 0x40, 0x32 },	/* '@' => '2' */
+	{ 0x41, 0x51 },	/* 'A' => 'Q' */
+	{ 0x4d, 0x3f },	/* 'M' => '?' */
+	{ 0x51, 0x41 },	/* 'Q' => 'A' */
+	{ 0x57, 0x5a },	/* 'W' => 'Z' */
+	{ 0x5a, 0x57 },	/* 'Z' => 'W' */
+	{ 0x5b, 0x5e },	/* '[' => '^' */
+	{ 0x5c, 0x2a },	/* '\\' => '*' */
+	{ 0x5d, 0x24 },	/* ']' => '$' */
+	{ 0x5e, 0x36 },	/* '^' => '6' */
+	{ 0x5f, 0x5d },	/* '_' => ']' */
+	{ 0x60, 0x2a },	/* '`' => '*' */
+	{ 0x61, 0x71 },	/* 'a' => 'q' */
+	{ 0x6d, 0x2c },	/* 'm' => ',' */
+	{ 0x71, 0x61 },	/* 'q' => 'a' */
+	{ 0x77, 0x7a },	/* 'w' => 'z' */
+	{ 0x7a, 0x77 },	/* 'z' => 'w' */
+	{ 0x7b, 0x3c },	/* '{' => '<' */
+	{ 0x7c, 0x23 },	/* '|' => '#' */
+	{ 0x7d, 0x3e },	/* '}' => '>' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_gr.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_gr.c
new file mode 100644
index 0000000..42b6418
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_gr.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "gr" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "gr" keyboard mapping */
+struct key_mapping gr_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_hu.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_hu.c
new file mode 100644
index 0000000..68eff2f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_hu.c
@@ -0,0 +1,34 @@
+/** @file
+ *
+ * "hu" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "hu" keyboard mapping */
+struct key_mapping hu_mapping[] __keymap = {
+	{ 0x19, 0x1a },	/* Ctrl-Y => Ctrl-Z */
+	{ 0x1a, 0x19 },	/* Ctrl-Z => Ctrl-Y */
+	{ 0x21, 0x27 },	/* '!' => '\'' */
+	{ 0x23, 0x2b },	/* '#' => '+' */
+	{ 0x24, 0x21 },	/* '$' => '!' */
+	{ 0x26, 0x3d },	/* '&' => '=' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3f },	/* '<' => '?' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x59, 0x5a },	/* 'Y' => 'Z' */
+	{ 0x5a, 0x59 },	/* 'Z' => 'Y' */
+	{ 0x5e, 0x2f },	/* '^' => '/' */
+	{ 0x60, 0x30 },	/* '`' => '0' */
+	{ 0x79, 0x7a },	/* 'y' => 'z' */
+	{ 0x7a, 0x79 },	/* 'z' => 'y' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_il.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_il.c
new file mode 100644
index 0000000..478330c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_il.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "il" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "il" keyboard mapping */
+struct key_mapping il_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_it.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_it.c
new file mode 100644
index 0000000..5bb0547
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_it.c
@@ -0,0 +1,32 @@
+/** @file
+ *
+ * "it" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "it" keyboard mapping */
+struct key_mapping it_mapping[] __keymap = {
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x5e },	/* '+' => '^' */
+	{ 0x2d, 0x27 },	/* '-' => '\'' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5d, 0x2b },	/* ']' => '+' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x60, 0x5c },	/* '`' => '\\' */
+	{ 0x7d, 0x2a },	/* '}' => '*' */
+	{ 0x7e, 0x7c },	/* '~' => '|' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_lt.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_lt.c
new file mode 100644
index 0000000..3e99d8c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_lt.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "lt" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "lt" keyboard mapping */
+struct key_mapping lt_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mk.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mk.c
new file mode 100644
index 0000000..8f50607
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mk.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "mk" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "mk" keyboard mapping */
+struct key_mapping mk_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mt.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mt.c
new file mode 100644
index 0000000..094a6fc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_mt.c
@@ -0,0 +1,20 @@
+/** @file
+ *
+ * "mt" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "mt" keyboard mapping */
+struct key_mapping mt_mapping[] __keymap = {
+	{ 0x22, 0x40 },	/* '"' => '@' */
+	{ 0x23, 0x04 },	/* '#' => Ctrl-D */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x23 },	/* '\\' => '#' */
+	{ 0x7c, 0x7e },	/* '|' => '~' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_nl.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_nl.c
new file mode 100644
index 0000000..ba05170
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_nl.c
@@ -0,0 +1,34 @@
+/** @file
+ *
+ * "nl" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "nl" keyboard mapping */
+struct key_mapping nl_mapping[] __keymap = {
+	{ 0x26, 0x5f },	/* '&' => '_' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x27 },	/* ')' => '\'' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x7e },	/* '+' => '~' */
+	{ 0x2d, 0x2f },	/* '-' => '/' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3b, 0x2b },	/* ';' => '+' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x3d },	/* '?' => '=' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x3c },	/* '\\' => '<' */
+	{ 0x5d, 0x2a },	/* ']' => '*' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x60, 0x40 },	/* '`' => '@' */
+	{ 0x7c, 0x3e },	/* '|' => '>' */
+	{ 0x7d, 0x7c },	/* '}' => '|' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_no.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_no.c
new file mode 100644
index 0000000..45cf9e8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_no.c
@@ -0,0 +1,105 @@
+/** @file
+ *
+ * "no" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "no" keyboard mapping */
+struct key_mapping no_mapping[] __keymap = {
+	{ 0x02, 0x18 },	/* Ctrl-B => Ctrl-X */
+	{ 0x03, 0x0a },	/* Ctrl-C => Ctrl-J */
+	{ 0x04, 0x05 },	/* Ctrl-D => Ctrl-E */
+	{ 0x06, 0x15 },	/* Ctrl-F => Ctrl-U */
+	{ 0x07, 0x09 },	/* Ctrl-G => Ctrl-I */
+	{ 0x08, 0x04 },	/* Ctrl-H => Ctrl-D */
+	{ 0x0a, 0x08 },	/* Ctrl-J => Ctrl-H */
+	{ 0x0b, 0x14 },	/* Ctrl-K => Ctrl-T */
+	{ 0x0c, 0x0e },	/* Ctrl-L => Ctrl-N */
+	{ 0x0e, 0x02 },	/* Ctrl-N => Ctrl-B */
+	{ 0x0f, 0x12 },	/* Ctrl-O => Ctrl-R */
+	{ 0x10, 0x0c },	/* Ctrl-P => Ctrl-L */
+	{ 0x12, 0x10 },	/* Ctrl-R => Ctrl-P */
+	{ 0x13, 0x0f },	/* Ctrl-S => Ctrl-O */
+	{ 0x14, 0x19 },	/* Ctrl-T => Ctrl-Y */
+	{ 0x15, 0x07 },	/* Ctrl-U => Ctrl-G */
+	{ 0x16, 0x0b },	/* Ctrl-V => Ctrl-K */
+	{ 0x18, 0x11 },	/* Ctrl-X => Ctrl-Q */
+	{ 0x19, 0x06 },	/* Ctrl-Y => Ctrl-F */
+	{ 0x22, 0x5f },	/* '"' => '_' */
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x27, 0x2d },	/* '\'' => '-' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2c, 0x77 },	/* ',' => 'w' */
+	{ 0x2d, 0x2b },	/* '-' => '+' */
+	{ 0x2e, 0x76 },	/* '.' => 'v' */
+	{ 0x2f, 0x7a },	/* '/' => 'z' */
+	{ 0x3a, 0x53 },	/* ':' => 'S' */
+	{ 0x3b, 0x73 },	/* ';' => 's' */
+	{ 0x3c, 0x57 },	/* '<' => 'W' */
+	{ 0x3d, 0x5c },	/* '=' => '\\' */
+	{ 0x3e, 0x56 },	/* '>' => 'V' */
+	{ 0x3f, 0x5a },	/* '?' => 'Z' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x42, 0x58 },	/* 'B' => 'X' */
+	{ 0x43, 0x4a },	/* 'C' => 'J' */
+	{ 0x44, 0x45 },	/* 'D' => 'E' */
+	{ 0x45, 0x3a },	/* 'E' => ':' */
+	{ 0x46, 0x55 },	/* 'F' => 'U' */
+	{ 0x47, 0x49 },	/* 'G' => 'I' */
+	{ 0x48, 0x44 },	/* 'H' => 'D' */
+	{ 0x49, 0x43 },	/* 'I' => 'C' */
+	{ 0x4a, 0x48 },	/* 'J' => 'H' */
+	{ 0x4b, 0x54 },	/* 'K' => 'T' */
+	{ 0x4c, 0x4e },	/* 'L' => 'N' */
+	{ 0x4e, 0x42 },	/* 'N' => 'B' */
+	{ 0x4f, 0x52 },	/* 'O' => 'R' */
+	{ 0x50, 0x4c },	/* 'P' => 'L' */
+	{ 0x52, 0x50 },	/* 'R' => 'P' */
+	{ 0x53, 0x4f },	/* 'S' => 'O' */
+	{ 0x54, 0x59 },	/* 'T' => 'Y' */
+	{ 0x55, 0x47 },	/* 'U' => 'G' */
+	{ 0x56, 0x4b },	/* 'V' => 'K' */
+	{ 0x57, 0x3b },	/* 'W' => ';' */
+	{ 0x58, 0x51 },	/* 'X' => 'Q' */
+	{ 0x59, 0x46 },	/* 'Y' => 'F' */
+	{ 0x5b, 0x27 },	/* '[' => '\'' */
+	{ 0x5c, 0x3c },	/* '\\' => '<' */
+	{ 0x5d, 0x7e },	/* ']' => '~' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x60, 0x7c },	/* '`' => '|' */
+	{ 0x62, 0x78 },	/* 'b' => 'x' */
+	{ 0x63, 0x6a },	/* 'c' => 'j' */
+	{ 0x64, 0x65 },	/* 'd' => 'e' */
+	{ 0x65, 0x2e },	/* 'e' => '.' */
+	{ 0x66, 0x75 },	/* 'f' => 'u' */
+	{ 0x67, 0x69 },	/* 'g' => 'i' */
+	{ 0x68, 0x64 },	/* 'h' => 'd' */
+	{ 0x69, 0x63 },	/* 'i' => 'c' */
+	{ 0x6a, 0x68 },	/* 'j' => 'h' */
+	{ 0x6b, 0x74 },	/* 'k' => 't' */
+	{ 0x6c, 0x6e },	/* 'l' => 'n' */
+	{ 0x6e, 0x62 },	/* 'n' => 'b' */
+	{ 0x6f, 0x72 },	/* 'o' => 'r' */
+	{ 0x70, 0x6c },	/* 'p' => 'l' */
+	{ 0x72, 0x70 },	/* 'r' => 'p' */
+	{ 0x73, 0x6f },	/* 's' => 'o' */
+	{ 0x74, 0x79 },	/* 't' => 'y' */
+	{ 0x75, 0x67 },	/* 'u' => 'g' */
+	{ 0x76, 0x6b },	/* 'v' => 'k' */
+	{ 0x77, 0x2c },	/* 'w' => ',' */
+	{ 0x78, 0x71 },	/* 'x' => 'q' */
+	{ 0x79, 0x66 },	/* 'y' => 'f' */
+	{ 0x7b, 0x2a },	/* '{' => '*' */
+	{ 0x7c, 0x3e },	/* '|' => '>' */
+	{ 0x7d, 0x5e },	/* '}' => '^' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pl.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pl.c
new file mode 100644
index 0000000..51822e0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pl.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "pl" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "pl" keyboard mapping */
+struct key_mapping pl_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pt.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pt.c
new file mode 100644
index 0000000..a8e44b6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_pt.c
@@ -0,0 +1,29 @@
+/** @file
+ *
+ * "pt" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "pt" keyboard mapping */
+struct key_mapping pt_mapping[] __keymap = {
+	{ 0x1c, 0x1d },	/* 0x1c => 0x1d */
+	{ 0x1d, 0x1b },	/* 0x1d => 0x1b */
+	{ 0x22, 0x5e },	/* '"' => '^' */
+	{ 0x27, 0x7e },	/* '\'' => '~' */
+	{ 0x2f, 0x3b },	/* '/' => ';' */
+	{ 0x3f, 0x3a },	/* '?' => ':' */
+	{ 0x5b, 0x27 },	/* '[' => '\'' */
+	{ 0x5c, 0x5d },	/* '\\' => ']' */
+	{ 0x5d, 0x5b },	/* ']' => '[' */
+	{ 0x60, 0x27 },	/* '`' => '\'' */
+	{ 0x7b, 0x60 },	/* '{' => '`' */
+	{ 0x7c, 0x7d },	/* '|' => '}' */
+	{ 0x7d, 0x7b },	/* '}' => '{' */
+	{ 0x7e, 0x22 },	/* '~' => '"' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ro.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ro.c
new file mode 100644
index 0000000..0eef7d5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ro.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "ro" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "ro" keyboard mapping */
+struct key_mapping ro_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ru.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ru.c
new file mode 100644
index 0000000..422b6c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ru.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "ru" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "ru" keyboard mapping */
+struct key_mapping ru_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sg.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sg.c
new file mode 100644
index 0000000..0b08209
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sg.c
@@ -0,0 +1,41 @@
+/** @file
+ *
+ * "sg" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "sg" keyboard mapping */
+struct key_mapping sg_mapping[] __keymap = {
+	{ 0x19, 0x1a },	/* Ctrl-Y => Ctrl-Z */
+	{ 0x1a, 0x19 },	/* Ctrl-Z => Ctrl-Y */
+	{ 0x21, 0x2b },	/* '!' => '+' */
+	{ 0x23, 0x2a },	/* '#' => '*' */
+	{ 0x24, 0x34 },	/* '$' => '4' */
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2d, 0x27 },	/* '-' => '\'' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3d, 0x5e },	/* '=' => '^' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x59, 0x5a },	/* 'Y' => 'Z' */
+	{ 0x5a, 0x59 },	/* 'Z' => 'Y' */
+	{ 0x5c, 0x24 },	/* '\\' => '$' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x79, 0x7a },	/* 'y' => 'z' */
+	{ 0x7a, 0x79 },	/* 'z' => 'y' */
+	{ 0x7c, 0x24 },	/* '|' => '$' */
+	{ 0x7d, 0x21 },	/* '}' => '!' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sr.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sr.c
new file mode 100644
index 0000000..0552f4d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_sr.c
@@ -0,0 +1,35 @@
+/** @file
+ *
+ * "sr" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "sr" keyboard mapping */
+struct key_mapping sr_mapping[] __keymap = {
+	{ 0x19, 0x1a },	/* Ctrl-Y => Ctrl-Z */
+	{ 0x1a, 0x19 },	/* Ctrl-Z => Ctrl-Y */
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x2a },	/* '+' => '*' */
+	{ 0x2d, 0x27 },	/* '-' => '\'' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3d, 0x2b },	/* '=' => '+' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x59, 0x5a },	/* 'Y' => 'Z' */
+	{ 0x5a, 0x59 },	/* 'Z' => 'Y' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x79, 0x7a },	/* 'y' => 'z' */
+	{ 0x7a, 0x79 },	/* 'z' => 'y' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_th.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_th.c
new file mode 100644
index 0000000..e8b44d1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_th.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "th" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "th" keyboard mapping */
+struct key_mapping th_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ua.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ua.c
new file mode 100644
index 0000000..1106a8b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_ua.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "ua" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "ua" keyboard mapping */
+struct key_mapping ua_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_uk.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_uk.c
new file mode 100644
index 0000000..6550d8e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_uk.c
@@ -0,0 +1,19 @@
+/** @file
+ *
+ * "uk" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "uk" keyboard mapping */
+struct key_mapping uk_mapping[] __keymap = {
+	{ 0x22, 0x40 },	/* '"' => '@' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x23 },	/* '\\' => '#' */
+	{ 0x7c, 0x7e },	/* '|' => '~' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_us.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_us.c
new file mode 100644
index 0000000..73d01a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_us.c
@@ -0,0 +1,15 @@
+/** @file
+ *
+ * "us" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "us" keyboard mapping */
+struct key_mapping us_mapping[] __keymap = {
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_wo.c b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_wo.c
new file mode 100644
index 0000000..b453576
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/keymap/keymap_wo.c
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * "wo" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "wo" keyboard mapping */
+struct key_mapping wo_mapping[] __keymap = {
+	{ 0x01, 0x11 },	/* Ctrl-A => Ctrl-Q */
+	{ 0x11, 0x01 },	/* Ctrl-Q => Ctrl-A */
+	{ 0x17, 0x1a },	/* Ctrl-W => Ctrl-Z */
+	{ 0x1a, 0x17 },	/* Ctrl-Z => Ctrl-W */
+	{ 0x21, 0x31 },	/* '!' => '1' */
+	{ 0x23, 0x33 },	/* '#' => '3' */
+	{ 0x24, 0x34 },	/* '$' => '4' */
+	{ 0x25, 0x35 },	/* '%' => '5' */
+	{ 0x26, 0x37 },	/* '&' => '7' */
+	{ 0x28, 0x39 },	/* '(' => '9' */
+	{ 0x29, 0x30 },	/* ')' => '0' */
+	{ 0x2a, 0x38 },	/* '*' => '8' */
+	{ 0x2c, 0x3b },	/* ',' => ';' */
+	{ 0x2d, 0x29 },	/* '-' => ')' */
+	{ 0x2e, 0x3a },	/* '.' => ':' */
+	{ 0x2f, 0x21 },	/* '/' => '!' */
+	{ 0x31, 0x26 },	/* '1' => '&' */
+	{ 0x33, 0x22 },	/* '3' => '"' */
+	{ 0x34, 0x27 },	/* '4' => '\'' */
+	{ 0x35, 0x28 },	/* '5' => '(' */
+	{ 0x36, 0x2d },	/* '6' => '-' */
+	{ 0x38, 0x5f },	/* '8' => '_' */
+	{ 0x3a, 0x4d },	/* ':' => 'M' */
+	{ 0x3b, 0x6d },	/* ';' => 'm' */
+	{ 0x3c, 0x2e },	/* '<' => '.' */
+	{ 0x3e, 0x2f },	/* '>' => '/' */
+	{ 0x40, 0x32 },	/* '@' => '2' */
+	{ 0x41, 0x51 },	/* 'A' => 'Q' */
+	{ 0x4d, 0x3f },	/* 'M' => '?' */
+	{ 0x51, 0x41 },	/* 'Q' => 'A' */
+	{ 0x57, 0x5a },	/* 'W' => 'Z' */
+	{ 0x5a, 0x57 },	/* 'Z' => 'W' */
+	{ 0x5d, 0x24 },	/* ']' => '$' */
+	{ 0x5e, 0x36 },	/* '^' => '6' */
+	{ 0x61, 0x71 },	/* 'a' => 'q' */
+	{ 0x6d, 0x2c },	/* 'm' => ',' */
+	{ 0x71, 0x61 },	/* 'q' => 'a' */
+	{ 0x77, 0x7a },	/* 'w' => 'z' */
+	{ 0x7a, 0x77 },	/* 'z' => 'w' */
+	{ 0x7e, 0x25 },	/* '~' => '%' */
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/linux_args.c b/qemu-0.15.x/roms/ipxe/src/hci/linux_args.c
new file mode 100644
index 0000000..0bce4af
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/linux_args.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <hci/linux_args.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/settings.h>
+#include <ipxe/linux.h>
+#include <ipxe/malloc.h>
+#include <ipxe/init.h>
+
+/** Saved argc */
+static int saved_argc = 0;
+/** Saved argv */
+static char ** saved_argv;
+
+/**
+ * Save argc and argv for later access.
+ *
+ * To be called by linuxprefix
+ */
+__asmcall void save_args(int argc, char **argv)
+{
+	saved_argc = argc;
+	saved_argv = argv;
+}
+
+/** Supported command-line options */
+static struct option options[] = {
+	{"net", 1, 0, 'n'},
+	{"settings", 1, 0, 's'},
+	{0, 0, 0, 0}
+};
+
+/**
+ * Parse k1=v1[,k2=v2]* into linux_settings
+ */
+static int parse_kv(char *kv, struct list_head *list)
+{
+	char *token;
+	char *name;
+	char *value;
+	struct linux_setting *setting;
+
+	while ((token = strsep(&kv, ",")) != NULL) {
+		name = strsep(&token, "=");
+		if (name == NULL)
+			continue;
+		value = token;
+		if (value == NULL) {
+			DBG("Bad parameter: '%s'\n", name);
+			continue;
+		}
+
+		setting = malloc(sizeof(*setting));
+
+		if (! setting)
+			return -1;
+
+		setting->name = name;
+		setting->value = value;
+		setting->applied = 0;
+		list_add(&setting->list, list);
+	}
+
+	return 0;
+}
+
+/**
+ * Parse --net arguments
+ *
+ * Format is --net driver_name[,name=value]*
+ */
+static int parse_net_args(char *args)
+{
+	char *driver;
+	struct linux_device_request *dev_request;
+	int rc;
+
+	driver = strsep(&args, ",");
+
+	if (strlen(driver) == 0) {
+		printf("Missing driver name");
+		return -1;
+	}
+
+	dev_request = malloc(sizeof(*dev_request));
+
+	dev_request->driver = driver;
+	INIT_LIST_HEAD(&dev_request->settings);
+	list_add_tail(&dev_request->list, &linux_device_requests);
+
+	/* Parse rest of the settings */
+	rc = parse_kv(args, &dev_request->settings);
+
+	if (rc)
+		printf("Parsing net settings failed");
+
+	return rc;
+}
+
+/**
+ * Parse --settings arguments
+ *
+ * Format is --settings name=value[,name=value]*
+ */
+static int parse_settings_args(char *args)
+{
+	return parse_kv(args, &linux_global_settings);
+}
+
+
+/** Parse passed command-line arguments */
+void linux_args_parse()
+{
+	int c;
+	int rc;
+
+	reset_getopt();
+	while (1) {
+		int option_index = 0;
+
+		c = getopt_long(saved_argc, saved_argv, "", options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'n':
+			if ((rc = parse_net_args(optarg)) != 0)
+				return;
+			break;
+		case 's':
+			if ((rc = parse_settings_args(optarg)) != 0)
+				return;
+			break;
+		default:
+			return;
+		}
+	}
+
+	return;
+}
+
+/** Clean up requests and settings */
+void linux_args_cleanup(int flags __unused)
+{
+	struct linux_device_request *request;
+	struct linux_device_request *rtmp;
+	struct linux_setting *setting;
+	struct linux_setting *stmp;
+
+	/* Clean up requests and their settings */
+	list_for_each_entry_safe(request, rtmp, &linux_device_requests, list) {
+		list_for_each_entry_safe(setting, stmp, &request->settings, list) {
+			list_del(&setting->list);
+			free(setting);
+		}
+		list_del(&request->list);
+		free(request);
+	}
+
+	/* Clean up global settings */
+	list_for_each_entry_safe(setting, stmp, &linux_global_settings, list) {
+		list_del(&setting->list);
+		free(setting);
+	}
+}
+
+struct startup_fn startup_linux_args __startup_fn(STARTUP_EARLY) = {
+	.startup = linux_args_parse,
+	.shutdown = linux_args_cleanup,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/alert.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/alert.c
new file mode 100644
index 0000000..00e959a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/alert.c
@@ -0,0 +1,18 @@
+#include <curses.h>
+#include <stdio.h>
+
+/** @file
+ *
+ * MuCurses alert functions
+ *
+ */
+
+/**
+ * Audible signal
+ *
+ * @ret rc	return status code
+ */
+int beep ( void ) {
+	printf("\a");
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/ansi_screen.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/ansi_screen.c
new file mode 100644
index 0000000..cc342f7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/ansi_screen.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <curses.h>
+#include <ipxe/console.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+static void ansiscr_reset(struct _curses_screen *scr) __nonnull;
+static void ansiscr_movetoyx(struct _curses_screen *scr,
+                               unsigned int y, unsigned int x) __nonnull;
+static void ansiscr_putc(struct _curses_screen *scr, chtype c) __nonnull;
+
+unsigned short _COLS = 80;
+unsigned short _LINES = 24;
+
+static void ansiscr_reset ( struct _curses_screen *scr ) {
+	/* Reset terminal attributes and clear screen */
+	scr->attrs = 0;
+	scr->curs_x = 0;
+	scr->curs_y = 0;
+	printf ( "\033[0m" );
+}
+
+static void ansiscr_movetoyx ( struct _curses_screen *scr,
+			       unsigned int y, unsigned int x ) {
+	if ( ( x != scr->curs_x ) || ( y != scr->curs_y ) ) {
+		/* ANSI escape sequence to update cursor position */
+		printf ( "\033[%d;%dH", ( y + 1 ), ( x + 1 ) );
+		scr->curs_x = x;
+		scr->curs_y = y;
+	}
+}
+
+static void ansiscr_putc ( struct _curses_screen *scr, chtype c ) {
+	unsigned int character = ( c & A_CHARTEXT );
+	attr_t attrs = ( c & ( A_ATTRIBUTES | A_COLOR ) );
+	int bold = ( attrs & A_BOLD );
+	attr_t cpair = PAIR_NUMBER ( attrs );
+	short fcol;
+	short bcol;
+
+	/* Update attributes if changed */
+	if ( attrs != scr->attrs ) {
+		scr->attrs = attrs;
+		pair_content ( cpair, &fcol, &bcol );
+		/* ANSI escape sequence to update character attributes */
+		printf ( "\033[0;%d;3%d;4%dm", ( bold ? 1 : 22 ), fcol, bcol );
+	}
+
+	/* Print the actual character */
+	putchar ( character );
+
+	/* Update expected cursor position */
+	if ( ++(scr->curs_x) == _COLS ) {
+		scr->curs_x = 0;
+		++scr->curs_y;
+	}
+}
+
+static int ansiscr_getc ( struct _curses_screen *scr __unused ) {
+	return getchar();
+}
+
+static bool ansiscr_peek ( struct _curses_screen *scr __unused ) {
+	return iskey();
+}
+
+SCREEN _ansi_screen = {
+	.init		= ansiscr_reset,
+	.exit		= ansiscr_reset,
+	.movetoyx	= ansiscr_movetoyx,
+	.putc		= ansiscr_putc,
+	.getc		= ansiscr_getc,
+	.peek		= ansiscr_peek,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/clear.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/clear.c
new file mode 100644
index 0000000..79b296c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/clear.c
@@ -0,0 +1,90 @@
+#include <curses.h>
+#include "mucurses.h"
+#include "cursor.h"
+
+/** @file
+ *
+ * MuCurses clearing functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Clear a window to the bottom from current cursor position
+ *
+ * @v *win	subject window
+ * @ret rc	return status code
+ */
+int wclrtobot ( WINDOW *win ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos( win, &pos );
+	do {
+		_wputc( win, ' ', WRAP );
+	} while ( win->curs_y + win->curs_x );
+	_restore_curs_pos( win, &pos );
+
+	return OK;
+}
+
+/**
+ * Clear a window to the end of the current line
+ *
+ * @v *win	subject window
+ * @ret rc	return status code
+ */
+int wclrtoeol ( WINDOW *win ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos( win, &pos );
+	while ( ( win->curs_y - pos.y ) == 0 ) {
+		_wputc( win, ' ', WRAP );
+	}
+	_restore_curs_pos( win, &pos );
+
+	return OK;
+}
+
+/**
+ * Delete character under the cursor in a window
+ *
+ * @v *win	subject window
+ * @ret rc	return status code
+ */
+int wdelch ( WINDOW *win ) {
+	_wputc( win, ' ', NOWRAP );
+	_wcursback( win );
+
+	return OK;
+}
+
+/**
+ * Delete line under a window's cursor
+ *
+ * @v *win	subject window
+ * @ret rc	return status code
+ */
+int wdeleteln ( WINDOW *win ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos( win, &pos );
+	/* let's just set the cursor to the beginning of the line and
+	   let wclrtoeol do the work :) */
+	wmove( win, win->curs_y, 0 );
+	wclrtoeol( win );
+	_restore_curs_pos( win, &pos );
+	return OK;
+}
+
+/**
+ * Completely clear a window
+ *
+ * @v *win	subject window
+ * @ret rc	return status code
+ */
+int werase ( WINDOW *win ) {
+	wmove( win, 0, 0 );
+	wclrtobot( win );
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/colour.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/colour.c
new file mode 100644
index 0000000..c1359c8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/colour.c
@@ -0,0 +1,66 @@
+#include <curses.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct colour_pair {
+	short fcol;
+	short bcol;
+};
+
+static struct colour_pair cpairs[COLOUR_PAIRS] = {
+	[0] = { COLOUR_WHITE, COLOUR_BLACK },
+};
+
+/**
+ * Identify the RGB components of a given colour value
+ *
+ * @v colour	colour value
+ * @v *red	address to store red component
+ * @v *green	address to store green component
+ * @v *blue	address to store blue component
+ * @ret rc	return status code
+ */
+int colour_content ( short colour, short *red, short *green, short *blue ) {
+	*red = ( ( colour & COLOUR_RED ) ? 1 : 0 );
+	*green = ( ( colour & COLOUR_GREEN ) ? 1 : 0 );
+	*blue = ( ( colour & COLOUR_BLUE ) ? 1 : 0 );
+	return OK;
+}
+
+/**
+ * Initialise colour pair
+ *
+ * @v pair	colour pair number
+ * @v fcol	foreground colour
+ * @v bcol	background colour
+ */
+int init_pair ( short pair, short fcol, short bcol ) {
+	struct colour_pair *cpair;
+
+	if ( ( pair < 1 ) || ( pair >= COLOUR_PAIRS ) )
+		return ERR;
+	
+	cpair = &cpairs[pair];
+	cpair->fcol = fcol;
+	cpair->bcol = bcol;
+	return OK;
+}
+
+/**
+ * Get colours of colour pair
+ *
+ * @v pair	colour pair number
+ * @ret fcol	foreground colour
+ * @ret bcol	background colour
+ */
+int pair_content ( short pair, short *fcol, short *bcol ) {
+	struct colour_pair *cpair;
+
+	if ( ( pair < 0 ) || ( pair >= COLOUR_PAIRS ) )
+		return ERR;
+	
+	cpair = &cpairs[pair];
+	*fcol = cpair->fcol;
+	*bcol = cpair->bcol;
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/cursor.h b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/cursor.h
new file mode 100644
index 0000000..16b7d27
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/cursor.h
@@ -0,0 +1,37 @@
+#ifndef CURSOR_H
+#define CURSOR_H
+
+/** @file
+ *
+ * MuCurses cursor implementation specific header file
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct cursor_pos {
+	unsigned int y, x;
+};
+
+/**
+ * Restore cursor position from encoded backup variable
+ *
+ * @v *win	window on which to operate
+ * @v *pos	pointer to struct in which original cursor position is stored
+ */
+static inline void _restore_curs_pos ( WINDOW *win, struct cursor_pos *pos ) {
+	wmove ( win, pos->y, pos->x );
+}
+
+/**
+ * Store cursor position for later restoration
+ *
+ * @v *win	window on which to operate
+ * @v *pos	pointer to struct in which to store cursor position
+ */
+static inline void _store_curs_pos ( WINDOW *win, struct cursor_pos *pos ) {
+	pos->y = win->curs_y;
+	pos->x = win->curs_x;
+}
+
+#endif /* CURSOR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/edging.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/edging.c
new file mode 100644
index 0000000..eccd324
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/edging.c
@@ -0,0 +1,111 @@
+#include <curses.h>
+#include "mucurses.h"
+#include "cursor.h"
+
+/** @file
+ *
+ * MuCurses edging functions
+ *
+ */
+
+/**
+ * Draw borders from single-byte characters and renditions around a
+ * window
+ *
+ * @v *win	window to be bordered
+ * @v verch	vertical chtype
+ * @v horch	horizontal chtype
+ * @ret rc	return status code
+ */
+int box ( WINDOW *win, chtype verch, chtype horch ) {
+	chtype corner = '+' | win->attrs; /* default corner character */
+	return wborder( win, verch, verch, horch, horch,
+			corner, corner, corner, corner );
+}
+
+/**
+ * Draw borders from single-byte characters and renditions around a
+ * window
+ *
+ * @v *win	window to be bordered
+ * @v ls	left side
+ * @v rs	right side
+ * @v ts	top
+ * @v bs	bottom
+ * @v tl	top left corner
+ * @v tr	top right corner
+ * @v bl	bottom left corner
+ * @v br	bottom right corner
+ * @ret rc	return status code
+ */
+int wborder ( WINDOW *win, chtype ls, chtype rs,
+	      chtype ts, chtype bs, chtype tl,
+	      chtype tr, chtype bl, chtype br ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos( win, &pos );
+	wmove(win,0,0);
+
+	_wputch(win,tl,WRAP);
+	while ( ( win->width - 1 ) - win->curs_x ) {
+		_wputch(win,ts,WRAP);
+	}
+	_wputch(win,tr,WRAP);
+
+	while ( ( win->height - 1 ) - win->curs_y ) {
+		_wputch(win,ls,WRAP);
+		wmove(win,win->curs_y,(win->width)-1);
+		_wputch(win,rs,WRAP);
+	}
+
+	_wputch(win,bl,WRAP);
+	while ( ( win->width -1 ) - win->curs_x ) {
+		_wputch(win,bs,WRAP);
+	}
+	_wputch(win,br,NOWRAP); /* do not wrap last char to leave
+				   cursor in last position */
+	_restore_curs_pos( win, &pos );
+
+	return OK;
+}
+
+/**
+ * Create a horizontal line in a window
+ *
+ * @v *win	subject window
+ * @v ch	rendition and character
+ * @v n		max number of chars (wide) to render
+ * @ret rc	return status code
+ */
+int whline ( WINDOW *win, chtype ch, int n ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos ( win, &pos );
+	while ( ( win->curs_x - win->width ) && n-- ) {
+		_wputch ( win, ch, NOWRAP );
+	}
+	_restore_curs_pos ( win, &pos );
+
+	return OK;
+}
+
+/**
+ * Create a vertical line in a window
+ *
+ * @v *win	subject window
+ * @v ch	rendition and character
+ * @v n		max number of chars (high) to render
+ * @ret rc	return status code
+ */
+int wvline ( WINDOW *win, chtype ch, int n ) {
+	struct cursor_pos pos;
+
+	_store_curs_pos ( win, &pos );
+	while ( ( win->curs_y - win->height ) && n-- ) {
+		_wputch ( win, ch, NOWRAP );
+		wmove( win, ++(win->curs_y), pos.x);
+	}
+	_restore_curs_pos ( win, &pos );
+
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/kb.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/kb.c
new file mode 100644
index 0000000..cada729
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/kb.c
@@ -0,0 +1,143 @@
+#include <curses.h>
+#include <stddef.h>
+#include <unistd.h>
+#include "mucurses.h"
+
+/** @file
+ *
+ * MuCurses keyboard input handling functions
+ */
+
+#define INPUT_DELAY 		200 // half-blocking delay timer resolution (ms)
+#define INPUT_DELAY_TIMEOUT 	1000 // half-blocking delay timeout
+
+int m_delay; /* 
+		< 0 : blocking read
+		0   : non-blocking read
+		> 0 : timed blocking read
+	     */
+bool m_echo;
+bool m_cbreak;
+
+static int _wgetc ( WINDOW *win ) {
+	int timer, c;
+
+	if ( win == NULL )
+		return ERR;
+
+	timer = INPUT_DELAY_TIMEOUT;
+	while ( ! win->scr->peek( win->scr ) ) {
+		if ( m_delay == 0 ) // non-blocking read
+			return ERR;
+		if ( timer > 0 ) {  // time-limited blocking read
+			if ( m_delay > 0 )
+				timer -= INPUT_DELAY;
+			mdelay( INPUT_DELAY );
+		} else { return ERR; } // non-blocking read
+	}
+
+	c = win->scr->getc( win->scr );
+
+	if ( m_echo && ( c >= 32 && c <= 126 ) ) // printable ASCII characters
+		_wputch( win, (chtype) ( c | win->attrs ), WRAP );
+
+	return c;
+}
+
+/**
+ * Pop a character from the FIFO into a window
+ *
+ * @v *win	window in which to echo input
+ * @ret c	char from input stream
+ */
+int wgetch ( WINDOW *win ) {
+	int c;
+
+	c = _wgetc( win );
+
+	if ( m_echo ) {
+		if ( c >= KEY_MIN ) {
+			switch(c) {
+			case KEY_LEFT :
+			case KEY_BACKSPACE :
+				_wcursback( win );
+				wdelch( win );
+				break;
+			default :
+				beep();
+				break;
+			}
+		} else {
+			_wputch( win, (chtype)( c | win->attrs ), WRAP );
+		}
+	}
+
+	return c;
+}
+
+/**
+ * Read at most n characters from the FIFO into a window
+ *
+ * @v *win	window in which to echo input
+ * @v *str	pointer to string in which to store result
+ * @v n		maximum number of characters to read into string (inc. NUL)
+ * @ret rc	return status code
+ */
+int wgetnstr ( WINDOW *win, char *str, int n ) {
+	char *_str;
+	int c;
+
+	if ( n == 0 ) {
+		str = '\0';
+		return OK;
+	}
+
+	_str = str;
+
+	while ( ( c = _wgetc( win ) ) != ERR ) {
+		/* termination enforcement - don't let us go past the
+		   end of the allocated buffer... */
+		if ( n == 0 && ( c >= 32 && c <= 126 ) ) {
+			_wcursback( win );
+			wdelch( win );
+		} else {
+			if ( c >= KEY_MIN ) {
+				switch(c) {
+				case KEY_LEFT :
+				case KEY_BACKSPACE :
+					_wcursback( win );
+					wdelch( win );
+					break;
+				case KEY_ENTER :
+					*_str = '\0';
+					return OK;
+				default :
+					beep();
+					break;
+				}
+			}
+			if ( c >= 32 && c <= 126 ) {
+				*(_str++) = c; n--;
+			}
+		}
+	}
+
+	return ERR;
+}
+
+
+/**
+ *
+ */
+int echo ( void ) {
+	m_echo = TRUE;
+	return OK;
+}
+
+/**
+ *
+ */
+int noecho ( void ) {
+	m_echo = FALSE;
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.c
new file mode 100644
index 0000000..7c16202
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.c
@@ -0,0 +1,147 @@
+#include <ipxe/console.h>
+#include <curses.h>
+#include "mucurses.h"
+
+/** @file
+ *
+ * MuCurses core functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+static void _wupdcurs ( WINDOW *win ) __nonnull;
+void _wputch ( WINDOW *win, chtype ch, int wrap ) __nonnull;
+void _wputc ( WINDOW *win, char c, int wrap ) __nonnull;
+void _wcursback ( WINDOW *win ) __nonnull;
+void _wputchstr ( WINDOW *win, const chtype *chstr, int wrap, int n ) __nonnull;
+void _wputstr ( WINDOW *win, const char *str, int wrap, int n ) __nonnull;
+int wmove ( WINDOW *win, int y, int x ) __nonnull;
+
+WINDOW _stdscr = {
+	.attrs = A_DEFAULT,
+	.ori_y = 0,
+	.ori_x = 0,
+	.curs_y = 0,
+	.curs_x = 0,
+	.scr = &_ansi_screen,
+};
+
+/*
+ *  Primitives
+ */
+
+/**
+ * Update cursor position
+ *
+ * @v *win	window in which to update position
+ */
+static void _wupdcurs ( WINDOW *win ) {
+	win->scr->movetoyx ( win->scr, win->ori_y + win->curs_y,
+			     win->ori_x + win->curs_x );
+}
+
+/**
+ * Write a single character rendition to a window
+ *
+ * @v *win	window in which to write
+ * @v ch	character rendition to write
+ * @v wrap	wrap "switch"
+ */
+void _wputch ( WINDOW *win, chtype ch, int wrap ) {
+	/* make sure we set the screen cursor to the right position
+	   first! */
+	_wupdcurs(win);
+	win->scr->putc(win->scr, ch);
+	if ( ++(win->curs_x) - win->width == 0 ) {
+		if ( wrap == WRAP ) {
+			win->curs_x = 0;
+			/* specification says we should really scroll,
+			   but we have no buffer to scroll with, so we
+			   can only overwrite back at the beginning of
+			   the window */
+			if ( ++(win->curs_y) - win->height == 0 )
+				win->curs_y = 0;
+		} else {
+			(win->curs_x)--;
+		}
+	}
+}
+
+/**
+ * Write a single character to a window
+ *
+ * @v *win	window in which to write
+ * @v c		character rendition to write
+ * @v wrap	wrap "switch"
+ */
+void _wputc ( WINDOW *win, char c, int wrap ) {
+	_wputch ( win, ( c | win->attrs ), wrap );
+}
+
+/**
+ * Retreat the cursor back one position (useful for a whole host of
+ * ops)
+ *
+ * @v *win	window in which to retreat
+ */
+void _wcursback ( WINDOW *win ) {
+	if ( win->curs_x == 0 ) {
+		if ( win->curs_y == 0 )
+			win->curs_y = win->height - 1;
+		win->curs_x = win->width = 1;
+	} else {
+		win->curs_x--;
+	}
+
+	_wupdcurs(win);
+}
+
+/**
+ * Write a chtype string to a window
+ *
+ * @v *win	window in which to write
+ * @v *chstr	chtype string
+ * @v wrap	wrap "switch"
+ * @v n		write at most n chtypes
+ */
+void _wputchstr ( WINDOW *win, const chtype *chstr, int wrap, int n ) {
+	for ( ; *chstr && n-- ; chstr++ ) {
+		_wputch(win,*chstr,wrap);
+	}
+}
+
+/**
+ * Write a standard c-style string to a window
+ *
+ * @v *win	window in which to write
+ * @v *str	string
+ * @v wrap	wrap "switch"
+ * @v n		write at most n chars from *str
+ */
+void _wputstr ( WINDOW *win, const char *str, int wrap, int n ) {
+	for ( ; *str && n-- ; str++ ) {
+		_wputc ( win, *str, wrap );
+	}
+}
+
+/**
+ * Move a window's cursor to the specified position
+ *
+ * @v *win	window to be operated on
+ * @v y		Y position
+ * @v x		X position
+ * @ret rc	return status code
+ */
+int wmove ( WINDOW *win, int y, int x ) {
+	/* chech for out-of-bounds errors */
+	if ( ( (unsigned)y >= win->height ) ||
+	     ( (unsigned)x >= win->width ) ) {
+		return ERR;
+	}
+
+	win->curs_y = y;
+	win->curs_x = x;
+	_wupdcurs(win);
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.h b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.h
new file mode 100644
index 0000000..7ac1086
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/mucurses.h
@@ -0,0 +1,23 @@
+#ifndef _MUCURSES_H
+#define _MUCURSES_H
+
+/** @file
+ *
+ * MuCurses core implementation specific header file
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define WRAP 0
+#define NOWRAP 1
+
+extern SCREEN _ansi_screen;
+
+extern void _wputch ( WINDOW *win, chtype ch, int wrap ) __nonnull;
+extern void _wputc ( WINDOW *win, char c, int wrap ) __nonnull;
+extern void _wputchstr ( WINDOW *win, const chtype *chstr, int wrap, int n ) __nonnull;
+extern void _wputstr ( WINDOW *win, const char *str, int wrap, int n ) __nonnull;
+extern void _wcursback ( WINDOW *win ) __nonnull;
+
+#endif /* _MUCURSES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print.c
new file mode 100644
index 0000000..9c68258
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print.c
@@ -0,0 +1,86 @@
+#include <curses.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <ipxe/vsprintf.h>
+#include "mucurses.h"
+
+/** @file
+ *
+ * MuCurses printing functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Add a single-byte character and rendition to a window and advance
+ * the cursor
+ *
+ * @v *win	window to be rendered in
+ * @v ch	character to be added at cursor
+ * @ret rc	return status code
+ */
+int waddch ( WINDOW *win, const chtype ch ) {
+	_wputch( win, ch, WRAP );
+	return OK;
+}
+
+/**
+ * Add string of single-byte characters to a window
+ *
+ * @v *win	window to be rendered in
+ * @v *str	standard c-style string
+ * @v n		max number of chars from string to render
+ * @ret rc	return status code
+ */
+int waddnstr ( WINDOW *win, const char *str, int n ) {
+	_wputstr( win, str, WRAP, n );
+	return OK;
+}
+
+struct printw_context {
+	struct printf_context ctx;
+	WINDOW *win;
+};
+
+static void _printw_handler ( struct printf_context *ctx, unsigned int c ) {
+	struct printw_context *wctx =
+		container_of ( ctx, struct printw_context, ctx );
+
+	_wputch( wctx->win, c | wctx->win->attrs, WRAP );
+}
+
+/**
+ * Print formatted output in a window
+ *
+ * @v *win	subject window
+ * @v *fmt	formatted string
+ * @v varglist	argument list
+ * @ret rc	return status code
+ */
+int vw_printw ( WINDOW *win, const char *fmt, va_list varglist ) {
+	struct printw_context wctx;
+
+	wctx.win = win;
+	wctx.ctx.handler = _printw_handler;
+	vcprintf ( &(wctx.ctx), fmt, varglist );
+	return OK;
+}
+
+/**
+ * Print formatted output to a window
+ *
+ * @v *win	subject window
+ * @v *fmt	formatted string
+ * @v ...	string arguments
+ * @ret rc	return status code
+ */
+int wprintw ( WINDOW *win, const char *fmt, ... ) {
+	va_list args;
+	int i;
+
+	va_start ( args, fmt );
+	i = vw_printw ( win, fmt, args );
+	va_end ( args );
+	return i;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print_nadv.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print_nadv.c
new file mode 100644
index 0000000..ee472e6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/print_nadv.c
@@ -0,0 +1,26 @@
+#include <curses.h>
+#include "mucurses.h"
+#include "cursor.h"
+
+/** @file
+ *
+ * MuCurses printing functions (no cursor advance)
+ *
+ */
+
+/**
+ * Add string of single-byte characters and renditions to a window
+ *
+ * @v *win	window to be rendered in
+ * @v *chstr	pointer to first chtype in "string"
+ * @v n		max number of chars from chstr to render
+ * @ret rc	return status code
+ */
+int waddchnstr ( WINDOW *win, const chtype *chstr, int n ) {
+	struct cursor_pos pos;	
+
+	_store_curs_pos( win, &pos );
+	_wputchstr( win, chstr, NOWRAP, n );
+	_restore_curs_pos( win, &pos );
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/slk.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/slk.c
new file mode 100644
index 0000000..600658e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/slk.c
@@ -0,0 +1,363 @@
+#include <curses.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mucurses.h"
+#include "cursor.h"
+
+/** @file
+ *
+ * Soft label key functions
+ */
+
+#define MIN_SPACE_SIZE 2
+
+#define SLK_MAX_LABEL_LEN 8
+
+#define SLK_MAX_NUM_LABELS 12
+
+#define SLK_MAX_NUM_SPACES 2
+
+struct _softlabel {
+	// label string
+	char label[SLK_MAX_LABEL_LEN];
+	/* Format of soft label 
+	   0: left justify
+	   1: centre justify
+	   2: right justify
+	 */
+	unsigned int fmt;
+};
+
+struct _softlabelkeys {
+	struct _softlabel fkeys[SLK_MAX_NUM_LABELS];
+	attr_t attrs;
+	/* Soft label layout format
+	   0: 3-2-3
+	   1: 4-4
+	   2: 4-4-4
+	   3: 4-4-4 with index line
+	*/
+	unsigned int fmt;
+	unsigned int max_label_len;
+	unsigned int maj_space_len;
+	unsigned int num_labels;
+	unsigned int num_spaces;
+	unsigned int spaces[SLK_MAX_NUM_SPACES];
+	struct cursor_pos saved_cursor;
+	attr_t saved_attrs;
+	short saved_pair;
+};
+
+static struct _softlabelkeys *slks;
+
+/*
+  I either need to break the primitives here, or write a collection of
+  functions specifically for SLKs that directly access the screen
+  functions - since this technically isn't part of stdscr, I think
+  this should be ok...
+ */
+
+static void _enter_slk ( void ) {
+	_store_curs_pos ( stdscr, &slks->saved_cursor );
+	wattr_get ( stdscr, &slks->saved_attrs, &slks->saved_pair, NULL );
+	LINES++;
+	wmove ( stdscr, LINES, 0 );
+	wattrset ( stdscr, slks->attrs );
+}
+
+static void _leave_slk ( void ) {
+	LINES--;
+	wattr_set ( stdscr, slks->saved_attrs, slks->saved_pair, NULL );
+	_restore_curs_pos ( stdscr, &slks->saved_cursor );
+}
+
+static void _print_label ( struct _softlabel sl ) {
+	int space_ch;
+	char str[SLK_MAX_LABEL_LEN + 1];
+
+	assert ( slks->max_label_len <= SLK_MAX_LABEL_LEN );
+	space_ch = ' ';
+
+	// protect against gaps in the soft label keys array
+	if ( sl.label == NULL ) {
+		memset( str, space_ch, (size_t)(slks->max_label_len) );
+	} else {
+		/* we need to pad the label with varying amounts of leading
+		   pad depending on the format of the label */
+		if ( sl.fmt == 1 ) {
+			memset( str, space_ch, 
+				(size_t)(slks->max_label_len 
+					 - strlen(sl.label)) / 2 );
+		}
+		if ( sl.fmt == 2 ) {
+			memset( str, space_ch,
+				(size_t)(slks->max_label_len 
+					 - strlen(sl.label)) );
+		}
+		strcat(str,sl.label);
+		
+		// post-padding
+		memset(str+strlen(str), space_ch,
+		       (size_t)(slks->max_label_len - strlen(str)) );
+	}
+
+	// print the formatted label
+	_wputstr ( stdscr, str, NOWRAP, slks->max_label_len );
+}
+
+/**
+ * Return the attribute used for the soft function keys
+ *
+ * @ret attrs	the current attributes of the soft function keys
+ */
+attr_t slk_attr ( void ) {
+	return ( slks == NULL ? 0 : slks->attrs );
+}
+
+/**
+ * Turn off soft function key attributes
+ *
+ * @v attrs	attribute bit mask
+ * @ret rc	return status code
+ */
+int slk_attroff ( const chtype attrs ) {
+	if ( slks == NULL ) 
+		return ERR;
+	slks->attrs &= ~( attrs & A_ATTRIBUTES );
+	return OK;
+}
+
+/**
+ * Turn on soft function key attributes
+ *
+ * @v attrs	attribute bit mask
+ * @ret rc	return status code
+ */
+int slk_attron ( const chtype attrs ) {
+	if ( slks == NULL )
+		return ERR;
+	slks->attrs |= ( attrs & A_ATTRIBUTES );
+	return OK;
+}
+
+/**
+ * Set soft function key attributes
+ *
+ * @v attrs	attribute bit mask
+ * @ret rc	return status code
+ */
+int slk_attrset ( const chtype attrs ) {
+	if ( slks == NULL ) 
+		return ERR;
+	slks->attrs = ( attrs & A_ATTRIBUTES );
+	return OK;
+}
+
+/**
+ * Turn off soft function key attributes
+ *
+ * @v attrs	attribute bit mask
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status code
+ */
+int slk_attr_off ( const attr_t attrs, void *opts __unused ) {
+	return slk_attroff( attrs );
+}
+
+/**
+ * Turn on soft function key attributes
+ *
+ * @v attrs	attribute bit mask
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status code
+ */
+int slk_attr_on ( attr_t attrs, void *opts __unused ) {
+	return slk_attron( attrs );
+}
+
+/**
+ * Set soft function key attributes
+ *
+ * @v attrs			attribute bit mask
+ * @v colour_pair_number	colour pair integer
+ * @v *opts			undefined (for future implementation)
+ * @ret rc			return status code
+ */
+int slk_attr_set ( const attr_t attrs, short colour_pair_number,
+		   void *opts __unused ) {
+	if ( slks == NULL ) 
+		return ERR;
+
+	if ( ( unsigned short )colour_pair_number > COLORS )
+		return ERR;
+
+	slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
+		( attrs & A_ATTRIBUTES );
+	return OK;
+}
+
+/**
+ * Clear the soft function key labels from the screen
+ *
+ * @ret rc	return status code
+ */
+int slk_clear ( void ) {
+	if ( slks == NULL )
+		return ERR;
+
+	_enter_slk();
+	wclrtoeol ( stdscr );
+	_leave_slk();
+
+	return OK;
+}
+
+/**
+ * Set soft label colour pair
+ */
+int slk_colour ( short colour_pair_number ) {
+	if ( slks == NULL ) 
+		return ERR;
+	if ( ( unsigned short )colour_pair_number > COLORS )
+		return ERR;
+
+	slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT )
+		| ( slks->attrs & A_ATTRIBUTES );
+
+	return OK;
+}
+
+/**
+ * Initialise the soft function keys
+ *
+ * @v fmt	format of keys
+ * @ret rc	return status code
+ */
+int slk_init ( int fmt ) {
+	unsigned short nmaj, nmin, nblocks, available_width;
+
+	if ( (unsigned)fmt > 3 ) {
+		return ERR;
+	}
+
+	/* There seems to be no API call to free this data structure... */
+	if ( ! slks )
+		slks = calloc(1,sizeof(*slks));
+	if ( ! slks )
+		return ERR;
+
+	slks->attrs = A_DEFAULT;
+	slks->fmt = fmt;
+	switch(fmt) {
+	case 0:
+		nblocks = 8; nmaj = 2; nmin = 5;
+		slks->spaces[0] = 2; slks->spaces[1] = 4;
+		break;
+	case 1:
+		nblocks = 8; nmaj = 1; nmin = 6;
+		slks->spaces[0] = 3;
+		break;
+	case 2:
+		// same allocations as format 3
+	case 3:
+		nblocks = 12; nmaj = 2; nmin = 9;
+		slks->spaces[0] = 3; slks->spaces[1] = 7;
+		break;
+	default:
+		nblocks = 0; nmaj = 0; nmin = 0;
+		break;
+	}
+
+	// determine maximum label length and major space size
+	available_width = COLS - ( ( MIN_SPACE_SIZE * nmaj ) + nmin );
+	slks->max_label_len = available_width / nblocks;
+	slks->maj_space_len = MIN_SPACE_SIZE + 
+		( available_width % nblocks ) / nmaj;
+	slks->num_spaces = nmaj;
+	slks->num_labels = nblocks;
+
+	// strip a line from the screen
+	LINES -= 1;
+
+	return OK;
+}
+
+/**
+ * Return the label for the specified soft key
+ *
+ * @v labnum	soft key identifier
+ * @ret label	return label
+ */
+char* slk_label ( int labnum ) {
+	if ( slks == NULL ) 
+		return NULL;
+
+	return slks->fkeys[labnum].label;
+}
+
+/**
+ * Restore soft function key labels to the screen
+ *
+ * @ret rc	return status code
+ */
+int slk_restore ( void ) {
+	unsigned int i, j, pos_x,
+		*next_space, *last_space;
+	chtype space_ch;
+
+	if ( slks == NULL )
+		return ERR;
+
+	pos_x = 0;
+
+	_enter_slk();
+
+	space_ch = (chtype)' ' | slks->attrs;
+	next_space = &(slks->spaces[0]);
+	last_space = &(slks->spaces[slks->num_spaces-1]);
+
+	for ( i = 0; i < slks->num_labels ; i++ ) {
+		_print_label( slks->fkeys[i] );
+		pos_x += slks->max_label_len;
+
+		if ( i == *next_space ) {
+			for ( j = 0; j < slks->maj_space_len; j++, pos_x++ )
+				_wputch ( stdscr, space_ch, NOWRAP );
+			if ( next_space < last_space )
+				next_space++;
+		} else {
+			if ( pos_x < COLS )
+				_wputch ( stdscr, space_ch, NOWRAP );
+			pos_x++;
+		}
+	}
+
+	_leave_slk();
+
+	return OK;
+}
+
+/**
+ * Configure specified soft key
+ *
+ * @v labnum	soft label position to configure
+ * @v *label	string to use as soft key label
+ * @v fmt	justification format of label
+ * @ret rc	return status code
+ */
+int slk_set ( int labnum, const char *label, int fmt ) {
+	if ( slks == NULL ) 
+		return ERR;
+	if ( (unsigned short)labnum >= slks->num_labels )
+		return ERR;
+	if ( (unsigned short)fmt >= 3 )
+		return ERR;
+
+	strncpy(slks->fkeys[labnum].label, label,
+		sizeof(slks->fkeys[labnum].label));
+	slks->fkeys[labnum].fmt = fmt;
+
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/widgets/editbox.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/widgets/editbox.c
new file mode 100644
index 0000000..5d2ba56
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/widgets/editbox.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/editbox.h>
+
+/** @file
+ *
+ * Editable text box widget
+ *
+ */
+
+#define EDITBOX_MIN_CHARS 3
+
+/**
+ * Initialise text box widget
+ *
+ * @v box		Editable text box widget
+ * @v buf		Text buffer
+ * @v len		Size of text buffer
+ * @v win		Containing window
+ * @v row		Row
+ * @v col		Starting column
+ * @v width		Width
+ * @v flags		Flags
+ */
+void init_editbox ( struct edit_box *box, char *buf, size_t len,
+		    WINDOW *win, unsigned int row, unsigned int col,
+		    unsigned int width, unsigned int flags ) {
+	memset ( box, 0, sizeof ( *box ) );
+	init_editstring ( &box->string, buf, len );
+	box->string.cursor = strlen ( buf );
+	box->win = ( win ? win : stdscr );
+	box->row = row;
+	box->col = col;
+	box->width = width;
+	box->flags = flags;
+}
+
+/**
+ * Draw text box widget
+ *
+ * @v box		Editable text box widget
+ *
+ */
+void draw_editbox ( struct edit_box *box ) {
+	size_t width = box->width;
+	char buf[ width + 1 ];
+	signed int cursor_offset, underflow, overflow, first;
+	size_t len;
+
+	/* Adjust starting offset so that cursor remains within box */
+	cursor_offset = ( box->string.cursor - box->first );
+	underflow = ( EDITBOX_MIN_CHARS - cursor_offset );
+	overflow = ( cursor_offset - ( width - 1 ) );
+	first = box->first;
+	if ( underflow > 0 ) {
+		first -= underflow;
+		if ( first < 0 )
+			first = 0;
+	} else if ( overflow > 0 ) {
+		first += overflow;
+	}
+	box->first = first;
+	cursor_offset = ( box->string.cursor - first );
+
+	/* Construct underscore-padded string portion */
+	memset ( buf, '_', width );
+	buf[width] = '\0';
+	len = ( strlen ( box->string.buf ) - first );
+	if ( len > width )
+		len = width;
+	if ( box->flags & EDITBOX_STARS ) {
+		memset ( buf, '*', len );
+	} else {
+		memcpy ( buf, ( box->string.buf + first ), len );
+	}
+
+	/* Print box content and move cursor */
+	if ( ! box->win )
+		box->win = stdscr;
+	mvwprintw ( box->win, box->row, box->col, "%s", buf );
+	wmove ( box->win, box->row, ( box->col + cursor_offset ) );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/winattrs.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/winattrs.c
new file mode 100644
index 0000000..f549d75
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/winattrs.c
@@ -0,0 +1,133 @@
+#include <curses.h>
+
+/** @file
+ *
+ * MuCurses window attribute functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Get the background rendition attributes for a window
+ *
+ * @v *win	subject window
+ * @ret ch	chtype rendition representation
+ */
+inline chtype getbkgd ( WINDOW *win ) {
+	return win->attrs;
+}
+
+/**
+ * Turn off attributes in a window
+ *
+ * @v win	subject window
+ * @v attrs	attributes to enable
+ * @ret rc	return status code
+ */
+int wattroff ( WINDOW *win, int attrs ) {
+	win->attrs &= ~attrs;
+	return OK;
+}
+
+/**
+ * Turn on attributes in a window
+ *
+ * @v win	subject window
+ * @v attrs	attributes to enable
+ * @ret rc	return status code
+ */
+int wattron ( WINDOW *win, int attrs ) {
+	win->attrs |= attrs;
+	return OK;
+}
+
+/**
+ * Set attributes in a window
+ *
+ * @v win	subject window
+ * @v attrs	attributes to enable
+ * @ret rc	return status code
+ */
+int wattrset ( WINDOW *win, int attrs ) {
+	win->attrs = ( attrs | ( win->attrs & A_COLOR ) );
+	return OK;
+}
+
+/**
+ * Get attributes and colour pair information
+ *
+ * @v *win	window to obtain information from
+ * @v *attrs	address in which to store attributes
+ * @v *pair	address in which to store colour pair
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status cude
+ */
+int wattr_get ( WINDOW *win, attr_t *attrs, short *pair, 
+		void *opts __unused ) {
+	*attrs = win->attrs & A_ATTRIBUTES;
+	*pair = PAIR_NUMBER ( win->attrs );
+	return OK;
+}
+
+/**
+ * Turn off attributes in a window
+ *
+ * @v *win	subject window
+ * @v attrs	attributes to toggle
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status code
+ */
+int wattr_off ( WINDOW *win, attr_t attrs, 
+		void *opts __unused ) {
+	wattroff( win, attrs );
+	return OK;
+}
+
+/**
+ * Turn on attributes in a window
+ *
+ * @v *win	subject window
+ * @v attrs	attributes to toggle
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status code
+ */
+int wattr_on ( WINDOW *win, attr_t attrs, 
+	       void *opts __unused ) {
+	wattron( win, attrs );
+	return OK;
+}
+
+/**
+ * Set attributes and colour pair information in a window
+ *
+ * @v *win	subject window
+ * @v attrs	attributes to set
+ * @v cpair	colour pair to set
+ * @v *opts	undefined (for future implementation)
+ * @ret rc	return status code
+ */
+int wattr_set ( WINDOW *win, attr_t attrs, short cpair, 
+		void *opts __unused ) {
+	wattrset( win, attrs | COLOUR_PAIR ( cpair ) );
+	return OK;
+}
+
+/**
+ * Set colour pair for a window
+ *
+ * @v *win			subject window
+ * @v colour_pair_number	colour pair integer
+ * @v *opts			undefined (for future implementation)
+ * @ret rc			return status code
+ */
+int wcolour_set ( WINDOW *win, short colour_pair_number, 
+		  void *opts __unused ) {
+	if ( ( unsigned short )colour_pair_number > COLOUR_PAIRS )
+		return ERR;
+
+	win->attrs = ( ( win->attrs & A_ATTRIBUTES ) |
+		       COLOUR_PAIR ( colour_pair_number ) );
+	return OK;
+}
+
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/windows.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/windows.c
new file mode 100644
index 0000000..63d0af0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/windows.c
@@ -0,0 +1,158 @@
+#include <curses.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "mucurses.h"
+
+/** @file
+ *
+ * MuCurses windows instance functions
+ *
+ */
+
+/**
+ * Delete a window
+ *
+ * @v *win	pointer to window being deleted
+ * @ret rc	return status code
+ */
+int delwin ( WINDOW *win ) {
+	if ( win == NULL )
+		return ERR;
+
+	/* I think we should blank the region covered by the window -
+	   ncurses doesn't do this, but they have a buffer, so they
+	   may just be deleting from an offscreen context whereas we
+	   are guaranteed to be deleting something onscreen */
+	wmove( win, 0, 0 );
+	chtype killch = (chtype)' ';
+	do {
+		_wputch( win, killch, WRAP );
+	} while ( win->curs_x + win->curs_y );
+
+	free( win );
+
+	wmove ( stdscr, 0, 0 );
+
+	return OK;
+}
+
+/**
+ * Create a new derived window
+ *
+ * @v parent	parent window
+ * @v nlines	window height
+ * @v ncols	window width
+ * @v begin_y	window y origin (relative to parent)
+ * @v begin_x	window x origin (relative to parent)
+ * @ret ptr	return pointer to child window
+ */
+WINDOW *derwin ( WINDOW *parent, int nlines, int ncols,
+	     		  	 int begin_y, int begin_x ) {
+	WINDOW *child;
+	if ( parent == NULL )
+		return NULL;
+	if ( ( child = malloc( sizeof( WINDOW ) ) ) == NULL )
+		return NULL;
+	if ( ( (unsigned)ncols > parent->width ) || 
+	     ( (unsigned)nlines > parent->height ) )
+		return NULL;
+	child->ori_y = parent->ori_y + begin_y;
+	child->ori_x = parent->ori_x + begin_x;
+	child->height = nlines;
+	child->width = ncols;
+	child->parent = parent;
+	child->scr = parent->scr;
+	return child;
+}
+
+/**
+ * Create a duplicate of the specified window
+ *
+ * @v orig	original window
+ * @ret ptr	pointer to duplicate window
+ */
+WINDOW *dupwin ( WINDOW *orig ) {
+	WINDOW *copy;
+	if ( orig == NULL )
+		return NULL;
+	if ( ( copy = malloc( sizeof( WINDOW ) ) ) == NULL )
+		return NULL;
+	copy->scr = orig->scr;
+	copy->attrs = orig->attrs;
+	copy->ori_y = orig->ori_y;
+	copy->ori_x = orig->ori_x;
+	copy->curs_y = orig->curs_y;
+	copy->curs_x = orig->curs_x;
+	copy->height = orig->height;
+	copy->width = orig->width;
+	return copy;
+}
+
+/**
+ * Move window origin to specified coordinates
+ *
+ * @v *win	window to move
+ * @v y		Y position
+ * @v x		X position
+ * @ret rc	return status code
+ */
+int mvwin ( WINDOW *win, int y, int x ) {
+	if ( win == NULL )
+		return ERR;
+	if ( ( ( (unsigned)y + win->height ) > LINES ) ||
+	     ( ( (unsigned)x + win->width ) > COLS ) )
+		return ERR;
+
+	win->ori_y = y;
+	win->ori_x = x;
+
+	return OK;
+}
+
+/**
+ * Create new WINDOW
+ *
+ * @v nlines	number of lines
+ * @v ncols	number of columns
+ * @v begin_y	column origin
+ * @v begin_x	line origin
+ * @ret *win	return pointer to new window
+ */
+WINDOW *newwin ( int nlines, int ncols, int begin_y, int begin_x ) {
+	WINDOW *win;
+	if ( ( win = malloc( sizeof(WINDOW) ) ) == NULL )
+		return NULL;
+	if ( ( (unsigned)( begin_y + nlines ) > stdscr->height ) &&
+	     ( (unsigned)( begin_x + ncols ) > stdscr->width ) )
+		return NULL;
+	win->ori_y = begin_y;
+	win->ori_x = begin_x;
+	win->height = nlines;
+	win->width = ncols;
+	win->scr = stdscr->scr;
+	win->parent = stdscr;
+	return win;
+}
+
+/**
+ * Create a new sub-window
+ *
+ * @v orig	parent window
+ * @v nlines	window height
+ * @v ncols	window width
+ * @v begin_y	window y origin (absolute)
+ * @v begin_x	window x origin (absolute)
+ * @ret ptr	return pointer to child window
+ */
+WINDOW *subwin ( WINDOW *parent, int nlines, int ncols,
+			         int begin_y, int begin_x ) {
+	WINDOW *child;
+	if ( parent == NULL )
+		return NULL;
+	if ( ( child = malloc( sizeof( WINDOW ) ) ) == NULL )
+		return NULL;
+	child = newwin( nlines, ncols, begin_y, begin_x );
+	child->parent = parent;
+	child->scr = parent->scr;
+	return child;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/mucurses/wininit.c b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/wininit.c
new file mode 100644
index 0000000..782e7b5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/mucurses/wininit.c
@@ -0,0 +1,37 @@
+#include <stddef.h>
+#include <curses.h>
+
+/** @file
+ *
+ * MuCurses initialisation functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Initialise console environment
+ *
+ * @ret *win	return pointer to stdscr
+ */
+WINDOW *initscr ( void ) {
+	/* determine console size */
+	/* initialise screen */
+	stdscr->scr->init( stdscr->scr );
+	stdscr->height = LINES;
+	stdscr->width = COLS;
+	move ( 0, 0 );
+	return stdscr;
+}
+
+/**
+ * Finalise console environment
+ *
+ */
+int endwin ( void ) {
+	attrset ( 0 );
+	color_set ( 0, NULL );
+	mvprintw ( ( LINES - 1 ), 0, "\n" );
+	stdscr->scr->exit( stdscr->scr );
+	return OK;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/readline.c b/qemu-0.15.x/roms/ipxe/src/hci/readline.c
new file mode 100644
index 0000000..32793ab
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/readline.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ipxe/console.h>
+#include <ipxe/keys.h>
+#include <ipxe/editstring.h>
+#include <readline/readline.h>
+
+/** @file
+ *
+ * Minimal readline
+ *
+ */
+
+#define READLINE_MAX 256
+
+/**
+ * Synchronise console with edited string
+ *
+ * @v string		Editable string
+ */
+static void sync_console ( struct edit_string *string ) {
+	unsigned int mod_start = string->mod_start;
+	unsigned int mod_end = string->mod_end;
+	unsigned int cursor = string->last_cursor;
+	size_t len = strlen ( string->buf );
+
+	/* Expand region back to old cursor position if applicable */
+	if ( mod_start > string->last_cursor )
+		mod_start = string->last_cursor;
+
+	/* Expand region forward to new cursor position if applicable */
+	if ( mod_end < string->cursor )
+		mod_end = string->cursor;
+
+	/* Backspace to start of region */
+	while ( cursor > mod_start ) {
+		putchar ( '\b' );
+		cursor--;
+	}
+
+	/* Print modified region */
+	while ( cursor < mod_end ) {
+		putchar ( ( cursor >= len ) ? ' ' : string->buf[cursor] );
+		cursor++;
+	}
+
+	/* Backspace to new cursor position */
+	while ( cursor > string->cursor ) {
+		putchar ( '\b' );
+		cursor--;
+	}
+}
+
+/**
+ * Locate history entry
+ *
+ * @v history		History buffer
+ * @v depth		Depth within history buffer
+ * @ret entry		History entry
+ */
+static struct readline_history_entry *
+history_entry ( struct readline_history *history, unsigned int depth ) {
+	unsigned int offset;
+
+	offset = ( ( history->next - depth ) %
+		   ( sizeof ( history->entries ) /
+		     sizeof ( history->entries[0] ) ) );
+	return &history->entries[offset];
+}
+
+/**
+ * Read string from history buffer
+ *
+ * @v history		History buffer
+ * @v depth		Depth within history buffer
+ * @ret string		String
+ */
+static const char * history_fetch ( struct readline_history *history,
+				    unsigned int depth ) {
+	struct readline_history_entry *entry;
+
+	/* Return the temporary copy if it exists, otherwise return
+	 * the persistent copy.
+	 */
+	entry = history_entry ( history, depth );
+	return ( entry->temp ? entry->temp : entry->string );
+}
+
+/**
+ * Write temporary string copy to history buffer
+ *
+ * @v history		History buffer
+ * @v depth		Depth within history buffer
+ * @v string		String
+ */
+static void history_store ( struct readline_history *history,
+			    unsigned int depth, const char *string ) {
+	struct readline_history_entry *entry;
+	char *temp;
+
+	/* Create temporary copy of string */
+	temp = strdup ( string );
+	if ( ! temp ) {
+		/* Just discard the string; there's nothing we can do */
+		DBGC ( history, "READLINE %p could not store string\n",
+		       history );
+		return;
+	}
+
+	/* Store temporary copy */
+	entry = history_entry ( history, depth );
+	free ( entry->temp );
+	entry->temp = temp;
+}
+
+/**
+ * Move to new history depth
+ *
+ * @v history		History buffer
+ * @v offset		Offset by which to change depth
+ * @v old_string	String (possibly modified) at current depth
+ * @ret new_string	String at new depth, or NULL for no movement
+ */
+static const char * history_move ( struct readline_history *history,
+				   int offset, const char *old_string ) {
+	unsigned int new_depth = ( history->depth + offset );
+	const char * new_string = history_fetch ( history, new_depth );
+
+	/* Depth checks */
+	if ( new_depth > READLINE_HISTORY_MAX_DEPTH )
+		return NULL;
+	if ( ! new_string )
+		return NULL;
+
+	/* Store temporary copy of old string at current depth */
+	history_store ( history, history->depth, old_string );
+
+	/* Update depth */
+	history->depth = new_depth;
+
+	/* Return new string */
+	return new_string;
+}
+
+/**
+ * Append new history entry
+ *
+ * @v history		History buffer
+ * @v string		String
+ */
+static void history_append ( struct readline_history *history,
+			     const char *string ) {
+	struct readline_history_entry *entry;
+
+	/* Store new entry */
+	entry = history_entry ( history, 0 );
+	assert ( entry->string == NULL );
+	entry->string = strdup ( string );
+	if ( ! entry->string ) {
+		/* Just discard the string; there's nothing we can do */
+		DBGC ( history, "READLINE %p could not append string\n",
+		       history );
+		return;
+	}
+
+	/* Increment history position */
+	history->next++;
+
+	/* Prepare empty "next" slot */
+	entry = history_entry ( history, 0 );
+	free ( entry->string );
+	entry->string = NULL;
+}
+
+/**
+ * Clean up history after editing
+ *
+ * @v history		History buffer
+ */
+static void history_cleanup ( struct readline_history *history ) {
+	struct readline_history_entry *entry;
+	unsigned int i;
+
+	/* Discard any temporary strings */
+	for ( i = 0 ; i < ( sizeof ( history->entries ) /
+			    sizeof ( history->entries[0] ) ) ; i++ ) {
+		entry = &history->entries[i];
+		free ( entry->temp );
+		entry->temp = NULL;
+	}
+
+	/* Reset depth */
+	history->depth = 0;
+
+	/* Sanity check */
+	entry = history_entry ( history, 0 );
+	assert ( entry->string == NULL );
+}
+
+/**
+ * Free history buffer
+ *
+ * @v history		History buffer
+ */
+void history_free ( struct readline_history *history ) {
+	struct readline_history_entry *entry;
+	unsigned int i;
+
+	/* Discard any temporary strings */
+	for ( i = 0 ; i < ( sizeof ( history->entries ) /
+			    sizeof ( history->entries[0] ) ) ; i++ ) {
+		entry = &history->entries[i];
+		assert ( entry->temp == NULL );
+		free ( entry->string );
+	}
+}
+
+/**
+ * Read line from console (with history)
+ *
+ * @v prompt		Prompt string
+ * @v history		History buffer, or NULL for no history
+ * @ret line		Line read from console (excluding terminating newline)
+ *
+ * The returned line is allocated with malloc(); the caller must
+ * eventually call free() to release the storage.
+ */
+char * readline_history ( const char *prompt,
+			  struct readline_history *history ) {
+	char buf[READLINE_MAX];
+	struct edit_string string;
+	int key;
+	int move_by;
+	const char *new_string;
+	char *line;
+
+	/* Display prompt, if applicable */
+	if ( prompt )
+		printf ( "%s", prompt );
+
+	/* Initialise editable string */
+	memset ( &string, 0, sizeof ( string ) );
+	init_editstring ( &string, buf, sizeof ( buf ) );
+	buf[0] = '\0';
+
+	while ( 1 ) {
+		/* Handle keypress */
+		key = edit_string ( &string, getkey ( 0 ) );
+		sync_console ( &string );
+		move_by = 0;
+		switch ( key ) {
+		case CR:
+		case LF:
+			line = strdup ( buf );
+			if ( ! line )
+				printf ( "\nOut of memory" );
+			goto done;
+		case CTRL_C:
+			line = NULL;
+			goto done;
+		case KEY_UP:
+			move_by = 1;
+			break;
+		case KEY_DOWN:
+			move_by = -1;
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+
+		/* Handle history movement, if applicable */
+		if ( move_by && history ) {
+			new_string = history_move ( history, move_by, buf );
+			if ( new_string ) {
+				replace_string ( &string, new_string );
+				sync_console ( &string );
+			}
+		}
+	}
+
+ done:
+	putchar ( '\n' );
+	if ( history ) {
+		if ( line && line[0] )
+			history_append ( history, line );
+		history_cleanup ( history );
+	}
+	return line;
+}
+
+/**
+ * Read line from console
+ *
+ * @v prompt		Prompt string
+ * @ret line		Line read from console (excluding terminating newline)
+ *
+ * The returned line is allocated with malloc(); the caller must
+ * eventually call free() to release the storage.
+ */
+char * readline ( const char *prompt ) {
+	return readline_history ( prompt, NULL );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/shell.c b/qemu-0.15.x/roms/ipxe/src/hci/shell.c
new file mode 100644
index 0000000..e426ba9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/shell.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <readline/readline.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/shell.h>
+
+/** @file
+ *
+ * Minimal command shell
+ *
+ */
+
+/** The shell prompt string */
+static const char shell_prompt[] = "iPXE> ";
+
+/**
+ * "help" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int help_exec ( int argc __unused, char **argv __unused ) {
+	struct command *command;
+	unsigned int hpos = 0;
+
+	printf ( "\nAvailable commands:\n\n" );
+	for_each_table_entry ( command, COMMANDS ) {
+		hpos += printf ( "  %s", command->name );
+		if ( hpos > ( 16 * 4 ) ) {
+			printf ( "\n" );
+			hpos = 0;
+		} else {
+			while ( hpos % 16 ) {
+				printf ( " " );
+				hpos++;
+			}
+		}
+	}
+	printf ( "\n\nType \"<command> --help\" for further information\n\n" );
+	return 0;
+}
+
+/** "help" command */
+struct command help_command __command = {
+	.name = "help",
+	.exec = help_exec,
+};
+
+/**
+ * Start command shell
+ *
+ */
+int shell ( void ) {
+	struct readline_history history;
+	char *line;
+	int rc = 0;
+
+	/* Initialise shell history */
+	memset ( &history, 0, sizeof ( history ) );
+
+	/* Read and execute commands */
+	do {
+		line = readline_history ( shell_prompt, &history );
+		if ( line ) {
+			rc = system ( line );
+			free ( line );
+		}
+	} while ( ! shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) );
+
+	/* Discard shell history */
+	history_free ( &history );
+
+	return rc;
+}
+
+/** "shell" options */
+struct shell_options {};
+
+/** "shell" option list */
+static struct option_descriptor shell_opts[] = {};
+
+/** "shell" command descriptor */
+static struct command_descriptor shell_cmd =
+	COMMAND_DESC ( struct shell_options, shell_opts, 0, 0, "" );
+
+/**
+ * "shell" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int shell_exec ( int argc, char **argv ) {
+	struct shell_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &shell_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Start shell */
+	if ( ( rc = shell() ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** "shell" command */
+struct command shell_command __command = {
+	.name = "shell",
+	.exec = shell_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/strerror.c b/qemu-0.15.x/roms/ipxe/src/hci/strerror.c
new file mode 100644
index 0000000..9356e9e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/strerror.c
@@ -0,0 +1,125 @@
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/errortab.h>
+
+/** @file
+ *
+ * Error descriptions.
+ *
+ * The error numbers used by Etherboot are a superset of those defined
+ * by the PXE specification version 2.1.  See errno.h for a listing of
+ * the error values.
+ *
+ * To save space in ROM images, error string tables are optional.  Use
+ * the ERRORMSG_XXX options in config.h to select which error string
+ * tables you want to include.  If an error string table is omitted,
+ * strerror() will simply return the text "Error 0x<errno>".
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Find error description
+ *
+ * @v errno		Error number
+ * @ret errortab	Error description, or NULL
+ */
+static struct errortab * find_error ( int errno ) {
+	struct errortab *errortab;
+
+	for_each_table_entry ( errortab, ERRORTAB ) {
+		if ( errortab->errno == errno )
+			return errortab;
+	}
+
+	return NULL;
+}
+
+/**
+ * Find closest error description
+ *
+ * @v errno		Error number
+ * @ret errortab	Error description, or NULL
+ *
+ * 
+ */
+static struct errortab * find_closest_error ( int errno ) {
+	struct errortab *errortab;
+
+	/* First, look for an exact match */
+	if ( ( errortab = find_error ( errno ) ) != NULL )
+		return errortab;
+
+	/* Second, try masking off the iPXE-specific bit and seeing if
+	 * we have an entry for the generic POSIX error message.
+	 */
+	if ( ( errortab = find_error ( errno & 0x7f0000ff ) ) != NULL )
+		return errortab;
+
+	return NULL;
+}
+
+/**
+ * Retrieve string representation of error number.
+ *
+ * @v errno/rc		Error number or return status code
+ * @ret strerror	Pointer to error text
+ *
+ * If the error is not found in the linked-in error tables, generates
+ * a generic "Error 0x<errno>" message.
+ *
+ * The pointer returned by strerror() is valid only until the next
+ * call to strerror().
+ *
+ */
+const char * strerror ( int errno ) {
+	static char errbuf[64];
+	struct errortab *errortab;
+
+	/* Allow for strerror(rc) as well as strerror(errno) */
+	if ( errno < 0 )
+		errno = -errno;
+
+	/* Find the error description, if one exists */
+	errortab = find_closest_error ( errno );
+
+	/* Construct the error message */
+	if ( errortab ) {
+		snprintf ( errbuf, sizeof ( errbuf ),
+			   "%s (http://ipxe.org/%08x)",
+			   errortab->text, errno );
+	} else {
+		snprintf ( errbuf, sizeof ( errbuf ),
+			   "Error %#08x (http://ipxe.org/%08x)",
+			   errno, errno );
+	}
+
+	return errbuf;
+}
+
+/* Do not include ERRFILE portion in the numbers in the error table */
+#undef ERRFILE
+#define ERRFILE 0
+
+/** The most common errors */
+struct errortab common_errors[] __errortab = {
+	__einfo_errortab ( EINFO_ENOERR ),
+	__einfo_errortab ( EINFO_EACCES ),
+	__einfo_errortab ( EINFO_ECANCELED ),
+	__einfo_errortab ( EINFO_ECONNRESET ),
+	__einfo_errortab ( EINFO_EINVAL ),
+	__einfo_errortab ( EINFO_EIO ),
+	__einfo_errortab ( EINFO_ENETUNREACH ),
+	__einfo_errortab ( EINFO_ENODEV ),
+	__einfo_errortab ( EINFO_ENOENT ),
+	__einfo_errortab ( EINFO_ENOEXEC ),
+	__einfo_errortab ( EINFO_ENOMEM ),
+	__einfo_errortab ( EINFO_ENOSPC ),
+	__einfo_errortab ( EINFO_ENOTCONN ),
+	__einfo_errortab ( EINFO_ENOTSUP ),
+	__einfo_errortab ( EINFO_EPERM ),
+	__einfo_errortab ( EINFO_ERANGE ),
+	__einfo_errortab ( EINFO_ETIMEDOUT ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/tui/login_ui.c b/qemu-0.15.x/roms/ipxe/src/hci/tui/login_ui.c
new file mode 100644
index 0000000..04aabfa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/tui/login_ui.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Login UI
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <curses.h>
+#include <ipxe/console.h>
+#include <ipxe/settings.h>
+#include <ipxe/editbox.h>
+#include <ipxe/keys.h>
+#include <ipxe/login_ui.h>
+
+/* Colour pairs */
+#define CPAIR_NORMAL		1
+#define CPAIR_LABEL		2
+#define CPAIR_EDITBOX		3
+
+/* Screen layout */
+#define USERNAME_LABEL_ROW	8
+#define USERNAME_ROW		10
+#define PASSWORD_LABEL_ROW	14
+#define PASSWORD_ROW		16
+#define LABEL_COL		36
+#define EDITBOX_COL		30
+#define EDITBOX_WIDTH		20
+
+int login_ui ( void ) {
+	char username[64];
+	char password[64];
+	struct edit_box username_box;
+	struct edit_box password_box;
+	struct edit_box *current_box = &username_box;
+	int key;
+	int rc = -EINPROGRESS;
+
+	/* Fetch current setting values */
+	fetch_string_setting ( NULL, &username_setting, username,
+			       sizeof ( username ) );
+	fetch_string_setting ( NULL, &password_setting, password,
+			       sizeof ( password ) );
+
+	/* Initialise UI */
+	initscr();
+	start_color();
+	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
+	init_pair ( CPAIR_LABEL, COLOR_WHITE, COLOR_BLACK );
+	init_pair ( CPAIR_EDITBOX, COLOR_WHITE, COLOR_BLUE );
+	init_editbox ( &username_box, username, sizeof ( username ), NULL,
+		       USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 );
+	init_editbox ( &password_box, password, sizeof ( password ), NULL,
+		       PASSWORD_ROW, EDITBOX_COL, EDITBOX_WIDTH,
+		       EDITBOX_STARS );
+
+	/* Draw initial UI */
+	erase();
+	color_set ( CPAIR_LABEL, NULL );
+	mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" );
+	mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" );
+	color_set ( CPAIR_EDITBOX, NULL );
+	draw_editbox ( &username_box );
+	draw_editbox ( &password_box );
+
+	/* Main loop */
+	while ( rc == -EINPROGRESS ) {
+
+		draw_editbox ( current_box );
+
+		key = getkey ( 0 );
+		switch ( key ) {
+		case KEY_DOWN:
+			current_box = &password_box;
+			break;
+		case KEY_UP:
+			current_box = &username_box;
+			break;
+		case TAB:
+			current_box = ( ( current_box == &username_box ) ?
+					&password_box : &username_box );
+			break;
+		case KEY_ENTER:
+			if ( current_box == &username_box ) {
+				current_box = &password_box;
+			} else {
+				rc = 0;
+			}
+			break;
+		case CTRL_C:
+		case ESC:
+			rc = -ECANCELED;
+			break;
+		default:
+			edit_editbox ( current_box, key );
+			break;
+		}
+	}
+
+	/* Terminate UI */
+	color_set ( CPAIR_NORMAL, NULL );
+	erase();
+	endwin();
+
+	if ( rc != 0 )
+		return rc;
+
+	/* Store settings */
+	if ( ( rc = store_setting ( NULL, &username_setting, username,
+				    strlen ( username ) ) ) != 0 )
+		return rc;
+	if ( ( rc = store_setting ( NULL, &password_setting, password,
+				    strlen ( password ) ) ) != 0 )
+		return rc;
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/tui/settings_ui.c b/qemu-0.15.x/roms/ipxe/src/hci/tui/settings_ui.c
new file mode 100644
index 0000000..ed07610
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/tui/settings_ui.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <curses.h>
+#include <ipxe/console.h>
+#include <ipxe/settings.h>
+#include <ipxe/editbox.h>
+#include <ipxe/keys.h>
+#include <ipxe/settings_ui.h>
+
+/** @file
+ *
+ * Option configuration console
+ *
+ */
+
+/* Colour pairs */
+#define CPAIR_NORMAL	1
+#define CPAIR_SELECT	2
+#define CPAIR_EDIT	3
+#define CPAIR_ALERT	4
+#define CPAIR_URL	5
+
+/* Screen layout */
+#define TITLE_ROW		1
+#define SETTINGS_LIST_ROW	3
+#define SETTINGS_LIST_COL	1
+#define SETTINGS_LIST_ROWS	15
+#define INFO_ROW		19
+#define ALERT_ROW		22
+#define INSTRUCTION_ROW		22
+#define INSTRUCTION_PAD "     "
+
+/** Layout of text within a setting widget */
+struct setting_row_text {
+	char start[0];
+	char pad1[1];
+	char name[15];
+	char pad2[1];
+	char value[60];
+	char pad3[1];
+	char nul;
+} __attribute__ (( packed ));
+
+/** A setting row widget */
+struct setting_row_widget {
+	/** Target configuration settings block
+	 *
+	 * Valid only for rows that lead to new settings blocks.
+	 */
+	struct settings *settings;
+	/** Configuration setting
+	 *
+	 * Valid only for rows that represent individual settings.
+	 */
+	struct setting *setting;
+	/** Screen row */
+	unsigned int row;
+	/** Screen column */
+	unsigned int col;
+	/** Edit box widget used for editing setting */
+	struct edit_box editbox;
+	/** Editing in progress flag */
+	int editing;
+	/** Setting originates from this block flag */
+	int originates_here;
+	/** Buffer for setting's value */
+	char value[256]; /* enough size for a DHCP string */
+};
+
+/** A settings widget */
+struct setting_widget {
+	/** Settings block */
+	struct settings *settings;
+	/** Number of rows */
+	unsigned int num_rows;
+	/** Current row index */
+	unsigned int current;
+        /** Index of the first visible row, for scrolling. */
+	unsigned int first_visible;
+	/** Active row */
+	struct setting_row_widget row;
+};
+
+/**
+ * Select a setting row
+ *
+ * @v widget		Setting widget
+ * @v index		Index of setting row
+ * @ret count		Number of settings rows
+ */
+static unsigned int select_setting_row ( struct setting_widget *widget,
+					 unsigned int index ) {
+	struct settings *settings;
+	struct settings *origin;
+	struct setting *setting;
+	unsigned int count = 0;
+
+	/* Initialise structure */
+	memset ( &widget->row, 0, sizeof ( widget->row ) );
+	widget->current = index;
+	widget->row.row = ( SETTINGS_LIST_ROW + index - widget->first_visible );
+	widget->row.col = SETTINGS_LIST_COL;
+
+	/* Include parent settings block, if applicable */
+	if ( widget->settings->parent && ( count++ == index ) ) {
+		widget->row.settings = widget->settings->parent;
+		snprintf ( widget->row.value, sizeof ( widget->row.value ),
+			   "../" );
+	}
+
+	/* Include any child settings blocks, if applicable */
+	list_for_each_entry ( settings, &widget->settings->children, siblings ){
+		if ( count++ == index ) {
+			widget->row.settings = settings;
+			snprintf ( widget->row.value,
+				   sizeof ( widget->row.value ), "%s/",
+				   settings->name );
+		}
+	}
+
+	/* Include any applicable settings */
+	for_each_table_entry ( setting, SETTINGS ) {
+		if ( ! setting_applies ( widget->settings, setting ) )
+			continue;
+		if ( count++ == index ) {
+			widget->row.setting = setting;
+
+			/* Read current setting value */
+			fetchf_setting ( widget->settings, widget->row.setting,
+					 widget->row.value,
+					 sizeof ( widget->row.value ) );
+
+			/* Check setting's origin */
+			origin = fetch_setting_origin ( widget->settings,
+							widget->row.setting );
+			widget->row.originates_here =
+				( origin == widget->settings );
+		}
+	}
+
+	/* Initialise edit box */
+	init_editbox ( &widget->row.editbox, widget->row.value,
+		       sizeof ( widget->row.value ), NULL, widget->row.row,
+		       ( widget->row.col +
+			 offsetof ( struct setting_row_text, value ) ),
+		       sizeof ( ( ( struct setting_row_text * ) NULL )->value ),
+		       0 );
+
+	return count;
+}
+
+static size_t string_copy ( char *dest, const char *src, size_t len ) {
+	size_t src_len;
+
+	src_len = strlen ( src );
+	if ( len > src_len )
+		len = src_len;
+	memcpy ( dest, src, len );
+	return len;
+}
+
+/**
+ * Draw setting row
+ *
+ * @v widget		Setting widget
+ */
+static void draw_setting_row ( struct setting_widget *widget ) {
+	struct setting_row_text text;
+	unsigned int curs_offset;
+	char *value;
+
+	/* Fill row with spaces */
+	memset ( &text, ' ', sizeof ( text ) );
+	text.nul = '\0';
+
+	/* Construct row content */
+	if ( widget->row.settings ) {
+
+		/* Construct space-padded name */
+		curs_offset = ( offsetof ( typeof ( text ), name ) +
+				string_copy ( text.name, widget->row.value,
+					      sizeof ( text.name ) ) );
+
+	} else {
+
+		/* Construct dot-padded name */
+		memset ( text.name, '.', sizeof ( text.name ) );
+		string_copy ( text.name, widget->row.setting->name,
+			      sizeof ( text.name ) );
+
+		/* Construct space-padded value */
+		value = widget->row.value;
+		if ( ! *value )
+			value = "<not specified>";
+		curs_offset = ( offsetof ( typeof ( text ), value ) +
+				string_copy ( text.value, value,
+					      sizeof ( text.value ) ) );
+	}
+
+	/* Print row */
+	if ( widget->row.originates_here || widget->row.settings )
+		attron ( A_BOLD );
+	mvprintw ( widget->row.row, widget->row.col, "%s", text.start );
+	attroff ( A_BOLD );
+	move ( widget->row.row, widget->row.col + curs_offset );
+}
+
+/**
+ * Edit setting widget
+ *
+ * @v widget		Setting widget
+ * @v key		Key pressed by user
+ * @ret key		Key returned to application, or zero
+ */
+static int edit_setting ( struct setting_widget *widget, int key ) {
+	assert ( widget->row.setting != NULL );
+	widget->row.editing = 1;
+	return edit_editbox ( &widget->row.editbox, key );
+}
+
+/**
+ * Save setting widget value back to configuration settings
+ *
+ * @v widget		Setting widget
+ */
+static int save_setting ( struct setting_widget *widget ) {
+	assert ( widget->row.setting != NULL );
+	return storef_setting ( widget->settings, widget->row.setting,
+				widget->row.value );
+}
+
+/**
+ * Print message centred on specified row
+ *
+ * @v row		Row
+ * @v fmt		printf() format string
+ * @v args		printf() argument list
+ */
+static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
+	char buf[COLS];
+	size_t len;
+
+	len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
+	mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
+}
+
+/**
+ * Print message centred on specified row
+ *
+ * @v row		Row
+ * @v fmt		printf() format string
+ * @v ..		printf() arguments
+ */
+static void msg ( unsigned int row, const char *fmt, ... ) {
+	va_list args;
+
+	va_start ( args, fmt );
+	vmsg ( row, fmt, args );
+	va_end ( args );
+}
+
+/**
+ * Clear message on specified row
+ *
+ * @v row		Row
+ */
+static void clearmsg ( unsigned int row ) {
+	move ( row, 0 );
+	clrtoeol();
+}
+
+/**
+ * Print alert message
+ *
+ * @v fmt		printf() format string
+ * @v args		printf() argument list
+ */
+static void valert ( const char *fmt, va_list args ) {
+	clearmsg ( ALERT_ROW );
+	color_set ( CPAIR_ALERT, NULL );
+	vmsg ( ALERT_ROW, fmt, args );
+	sleep ( 2 );
+	color_set ( CPAIR_NORMAL, NULL );
+	clearmsg ( ALERT_ROW );
+}
+
+/**
+ * Print alert message
+ *
+ * @v fmt		printf() format string
+ * @v ...		printf() arguments
+ */
+static void alert ( const char *fmt, ... ) {
+	va_list args;
+
+	va_start ( args, fmt );
+	valert ( fmt, args );
+	va_end ( args );
+}
+
+/**
+ * Draw title row
+ *
+ * @v widget		Setting widget
+ */
+static void draw_title_row ( struct setting_widget *widget ) {
+	const char *name;
+
+	clearmsg ( TITLE_ROW );
+	name = settings_name ( widget->settings );
+	attron ( A_BOLD );
+	msg ( TITLE_ROW, "iPXE configuration settings%s%s",
+	      ( name[0] ? " - " : "" ), name );
+	attroff ( A_BOLD );
+}
+
+/**
+ * Draw information row
+ *
+ * @v widget		Setting widget
+ */
+static void draw_info_row ( struct setting_widget *widget ) {
+	struct settings *origin;
+	char buf[32];
+
+	/* Draw nothing unless this row represents a setting */
+	clearmsg ( INFO_ROW );
+	clearmsg ( INFO_ROW + 1 );
+	if ( ! widget->row.setting )
+		return;
+
+	/* Determine a suitable setting name */
+	origin = fetch_setting_origin ( widget->settings, widget->row.setting );
+	if ( ! origin )
+		origin = widget->settings;
+	setting_name ( origin, widget->row.setting, buf, sizeof ( buf ) );
+
+	/* Draw row */
+	attron ( A_BOLD );
+	msg ( INFO_ROW, "%s - %s", buf, widget->row.setting->description );
+	attroff ( A_BOLD );
+	color_set ( CPAIR_URL, NULL );
+	msg ( ( INFO_ROW + 1 ), "http://ipxe.org/cfg/%s",
+	      widget->row.setting->name );
+	color_set ( CPAIR_NORMAL, NULL );
+}
+
+/**
+ * Draw instruction row
+ *
+ * @v widget		Setting widget
+ */
+static void draw_instruction_row ( struct setting_widget *widget ) {
+
+	clearmsg ( INSTRUCTION_ROW );
+	if ( widget->row.editing ) {
+		msg ( INSTRUCTION_ROW,
+		      "Enter - accept changes" INSTRUCTION_PAD
+		      "Ctrl-C - discard changes" );
+	} else {
+		msg ( INSTRUCTION_ROW,
+		      "%sCtrl-X - exit configuration utility",
+		      ( widget->row.originates_here ?
+			"Ctrl-D - delete setting" INSTRUCTION_PAD : "" ) );
+	}
+}
+
+/**
+ * Reveal setting row
+ *
+ * @v widget		Setting widget
+ * @v index		Index of setting row
+ */
+static void reveal_setting_row ( struct setting_widget *widget,
+				 unsigned int index ) {
+	unsigned int i;
+
+	/* Simply return if setting N is already on-screen. */
+	if ( index - widget->first_visible < SETTINGS_LIST_ROWS )
+		return;
+
+	/* Jump scroll to make the specified setting row visible. */
+	while ( widget->first_visible < index )
+		widget->first_visible += SETTINGS_LIST_ROWS;
+	while ( widget->first_visible > index )
+		widget->first_visible -= SETTINGS_LIST_ROWS;
+
+	/* Draw ellipses before and/or after the settings list to
+	 * represent any invisible settings.
+	 */
+	mvaddstr ( SETTINGS_LIST_ROW - 1,
+		   SETTINGS_LIST_COL + 1,
+		   widget->first_visible > 0 ? "..." : "   " );
+	mvaddstr ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS,
+		   SETTINGS_LIST_COL + 1,
+		   ( ( widget->first_visible + SETTINGS_LIST_ROWS )
+		     < widget->num_rows ? "..." : "   " ) );
+
+	/* Draw visible settings. */
+	for ( i = 0; i < SETTINGS_LIST_ROWS; i++ ) {
+		if ( ( widget->first_visible + i ) < widget->num_rows ) {
+			select_setting_row ( widget,
+					     widget->first_visible + i );
+			draw_setting_row ( widget );
+		} else {
+			clearmsg ( SETTINGS_LIST_ROW + i );
+		}
+	}
+}
+
+/**
+ * Reveal setting row
+ *
+ * @v widget		Setting widget
+ * @v settings		Settings block
+ */
+static void init_widget ( struct setting_widget *widget,
+			  struct settings *settings ) {
+
+	widget->settings = settings;
+	widget->num_rows = select_setting_row ( widget, 0 );
+	widget->first_visible = SETTINGS_LIST_ROWS;
+	draw_title_row ( widget );
+	reveal_setting_row ( widget, 0 );
+	select_setting_row ( widget, 0 );
+}
+
+static int main_loop ( struct settings *settings ) {
+	struct setting_widget widget;
+	int redraw = 1;
+	int move;
+	unsigned int next;
+	int key;
+	int rc;
+
+	/* Print initial screen content */
+	color_set ( CPAIR_NORMAL, NULL );
+	memset ( &widget, 0, sizeof ( widget ) );
+	init_widget ( &widget, settings );
+
+	while ( 1 ) {
+
+		/* Redraw rows if necessary */
+		if ( redraw ) {
+			draw_info_row ( &widget );
+			draw_instruction_row ( &widget );
+			color_set ( ( widget.row.editing ?
+				      CPAIR_EDIT : CPAIR_SELECT ), NULL );
+			draw_setting_row ( &widget );
+			color_set ( CPAIR_NORMAL, NULL );
+			redraw = 0;
+		}
+
+		if ( widget.row.editing ) {
+
+			/* Sanity check */
+			assert ( widget.row.setting != NULL );
+
+			/* Redraw edit box */
+			color_set ( CPAIR_EDIT, NULL );
+			draw_editbox ( &widget.row.editbox );
+			color_set ( CPAIR_NORMAL, NULL );
+
+			/* Process keypress */
+			key = edit_setting ( &widget, getkey ( 0 ) );
+			switch ( key ) {
+			case CR:
+			case LF:
+				if ( ( rc = save_setting ( &widget ) ) != 0 )
+					alert ( " %s ", strerror ( rc ) );
+				/* Fall through */
+			case CTRL_C:
+				select_setting_row ( &widget, widget.current );
+				redraw = 1;
+				break;
+			default:
+				/* Do nothing */
+				break;
+			}
+
+		} else {
+
+			/* Process keypress */
+			key = getkey ( 0 );
+			move = 0;
+			switch ( key ) {
+			case KEY_DOWN:
+				if ( widget.current < ( widget.num_rows - 1 ) )
+					move = +1;
+				break;
+			case KEY_UP:
+				if ( widget.current > 0 )
+					move = -1;
+				break;
+			case CTRL_D:
+				if ( ! widget.row.setting )
+					break;
+				if ( ( rc = delete_setting ( widget.settings,
+						widget.row.setting ) ) != 0 ) {
+					alert ( " %s ", strerror ( rc ) );
+				}
+				select_setting_row ( &widget, widget.current );
+				redraw = 1;
+				break;
+			case CTRL_X:
+				return 0;
+			case CR:
+			case LF:
+				if ( widget.row.settings ) {
+					init_widget ( &widget,
+						      widget.row.settings );
+					redraw = 1;
+				}
+				/* Fall through */
+			default:
+				if ( widget.row.setting ) {
+					edit_setting ( &widget, key );
+					redraw = 1;
+				}
+				break;
+			}
+			if ( move ) {
+				next = ( widget.current + move );
+				draw_setting_row ( &widget );
+				redraw = 1;
+				reveal_setting_row ( &widget, next );
+				select_setting_row ( &widget, next );
+			}
+		}
+	}
+}
+
+int settings_ui ( struct settings *settings ) {
+	int rc;
+
+	initscr();
+	start_color();
+	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
+	init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
+	init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
+	init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
+	init_pair ( CPAIR_URL, COLOR_CYAN, COLOR_BLUE );
+	color_set ( CPAIR_NORMAL, NULL );
+	erase();
+	
+	rc = main_loop ( settings );
+
+	endwin();
+
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/hci/wireless_errors.c b/qemu-0.15.x/roms/ipxe/src/hci/wireless_errors.c
new file mode 100644
index 0000000..63c6251
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/hci/wireless_errors.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/errortab.h>
+#include <ipxe/net80211_err.h>
+
+/* Record errors as though they come from the 802.11 stack */
+#undef ERRFILE
+#define ERRFILE ERRFILE_net80211
+
+/** All 802.11 errors
+ */
+struct errortab wireless_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EINVAL_PKT_TOO_SHORT ),
+	__einfo_errortab ( EINFO_EINVAL_PKT_VERSION ),
+	__einfo_errortab ( EINFO_EINVAL_PKT_NOT_DATA ),
+	__einfo_errortab ( EINFO_EINVAL_PKT_NOT_FROMDS ),
+	__einfo_errortab ( EINFO_EINVAL_PKT_LLC_HEADER ),
+	__einfo_errortab ( EINFO_EINVAL_CRYPTO_REQUEST ),
+	__einfo_errortab ( EINFO_EINVAL_ACTIVE_SCAN ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_FAILURE ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_CAPAB_UNSUPP ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_REASSOC_INVALID ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_DENIED ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_SEQ_INVALID ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_CHALL_INVALID ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_TIMEOUT ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NO_ROOM ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_RATE ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_PMBL ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_PBCC ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_BAD_POWER ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_BAD_CHANNELS ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_SLOT ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_NEED_DSSS_OFDM ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_QOS_FAILURE ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_QOS_NO_ROOM ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_LINK_IS_HORRIBLE ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_ASSOC_NEED_QOS ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_REQUEST_DECLINED ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_REQUEST_INVALID ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_TS_NOT_CREATED_AGAIN ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_INVALID_IE ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_GROUP_CIPHER_INVALID ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_PAIR_CIPHER_INVALID ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_AKMP_INVALID ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_RSN_VERSION_UNSUPP ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_RSN_CAPAB_INVALID ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_CIPHER_REJECTED ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_TS_NOT_CREATED_WAIT ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_DIRECT_LINK_FORBIDDEN ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_DEST_NOT_PRESENT ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_DEST_NOT_QOS ),
+	__einfo_errortab ( EINFO_EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH ),
+	__einfo_errortab ( EINFO_ECONNRESET_UNSPECIFIED ),
+	__einfo_errortab ( EINFO_ECONNRESET_AUTH_NO_LONGER_VALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_LEAVING ),
+	__einfo_errortab ( EINFO_ECONNRESET_INACTIVITY ),
+	__einfo_errortab ( EINFO_ECONNRESET_OUT_OF_RESOURCES ),
+	__einfo_errortab ( EINFO_ECONNRESET_NEED_AUTH ),
+	__einfo_errortab ( EINFO_ECONNRESET_NEED_ASSOC ),
+	__einfo_errortab ( EINFO_ECONNRESET_LEAVING_TO_ROAM ),
+	__einfo_errortab ( EINFO_ECONNRESET_REASSOC_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_BAD_POWER ),
+	__einfo_errortab ( EINFO_ECONNRESET_BAD_CHANNELS ),
+	__einfo_errortab ( EINFO_ECONNRESET_INVALID_IE ),
+	__einfo_errortab ( EINFO_ECONNRESET_MIC_FAILURE ),
+	__einfo_errortab ( EINFO_ECONNRESET_4WAY_TIMEOUT ),
+	__einfo_errortab ( EINFO_ECONNRESET_GROUPKEY_TIMEOUT ),
+	__einfo_errortab ( EINFO_ECONNRESET_4WAY_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_GROUP_CIPHER_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_PAIR_CIPHER_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_AKMP_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_RSN_VERSION_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_RSN_CAPAB_INVALID ),
+	__einfo_errortab ( EINFO_ECONNRESET_8021X_FAILURE ),
+	__einfo_errortab ( EINFO_ECONNRESET_CIPHER_REJECTED ),
+	__einfo_errortab ( EINFO_ENETRESET_QOS_UNSPECIFIED ),
+	__einfo_errortab ( EINFO_ENETRESET_QOS_OUT_OF_RESOURCES ),
+	__einfo_errortab ( EINFO_ENETRESET_LINK_IS_HORRIBLE ),
+	__einfo_errortab ( EINFO_ENETRESET_INVALID_TXOP ),
+	__einfo_errortab ( EINFO_ENETRESET_REQUESTED_LEAVING ),
+	__einfo_errortab ( EINFO_ENETRESET_REQUESTED_NO_USE ),
+	__einfo_errortab ( EINFO_ENETRESET_REQUESTED_NEED_SETUP ),
+	__einfo_errortab ( EINFO_ENETRESET_REQUESTED_TIMEOUT ),
+	__einfo_errortab ( EINFO_ENETRESET_CIPHER_UNSUPPORTED ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/image/efi_image.c b/qemu-0.15.x/roms/ipxe/src/image/efi_image.c
new file mode 100644
index 0000000..0575496
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/image/efi_image.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/image.h>
+#include <ipxe/init.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
+
+/**
+ * Execute EFI image
+ *
+ * @v image		EFI image
+ * @ret rc		Return status code
+ */
+static int efi_image_exec ( struct image *image ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_HANDLE handle;
+	UINTN exit_data_size;
+	CHAR16 *exit_data;
+	EFI_STATUS efirc;
+	int rc;
+
+	/* Attempt loading image */
+	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+				       user_to_virt ( image->data, 0 ),
+				       image->len, &handle ) ) != 0 ) {
+		/* Not an EFI image */
+		DBGC ( image, "EFIIMAGE %p could not load: %s\n",
+		       image, efi_strerror ( efirc ) );
+		return -ENOEXEC;
+	}
+
+	/* Start the image */
+	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
+					&exit_data ) ) != 0 ) {
+		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
+		       image, efi_strerror ( efirc ) );
+	}
+	rc = EFIRC_TO_RC ( efirc );
+
+	/* Unload the image.  We can't leave it loaded, because we
+	 * have no "unload" operation.
+	 */
+	bs->UnloadImage ( handle );
+
+	return rc;
+}
+
+/**
+ * Probe EFI image
+ *
+ * @v image		EFI file
+ * @ret rc		Return status code
+ */
+static int efi_image_probe ( struct image *image ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_HANDLE handle;
+	EFI_STATUS efirc;
+
+	/* Attempt loading image */
+	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+				       user_to_virt ( image->data, 0 ),
+				       image->len, &handle ) ) != 0 ) {
+		/* Not an EFI image */
+		DBGC ( image, "EFIIMAGE %p could not load: %s\n",
+		       image, efi_strerror ( efirc ) );
+		return -ENOEXEC;
+	}
+
+	/* Unload the image.  We can't leave it loaded, because we
+	 * have no "unload" operation.
+	 */
+	bs->UnloadImage ( handle );
+
+	return 0;
+}
+
+/** EFI image type */
+struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "EFI",
+	.probe = efi_image_probe,
+	.exec = efi_image_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/image/elf.c b/qemu-0.15.x/roms/ipxe/src/image/elf.c
new file mode 100644
index 0000000..406a8d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/image/elf.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * ELF image format
+ *
+ * A "pure" ELF image is not a bootable image.  There are various
+ * bootable formats based upon ELF (e.g. Multiboot), which share
+ * common ELF-related functionality.
+ */
+
+#include <errno.h>
+#include <elf.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/segment.h>
+#include <ipxe/image.h>
+#include <ipxe/elf.h>
+
+typedef Elf32_Ehdr	Elf_Ehdr;
+typedef Elf32_Phdr	Elf_Phdr;
+typedef Elf32_Off	Elf_Off;
+
+/**
+ * Load ELF segment into memory
+ *
+ * @v image		ELF file
+ * @v phdr		ELF program header
+ * @v ehdr		ELF executable header
+ * @ret entry		Entry point, if found
+ * @ret rc		Return status code
+ */
+static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
+			      Elf_Ehdr *ehdr, physaddr_t *entry ) {
+	physaddr_t dest;
+	userptr_t buffer;
+	unsigned long e_offset;
+	int rc;
+
+	/* Do nothing for non-PT_LOAD segments */
+	if ( phdr->p_type != PT_LOAD )
+		return 0;
+
+	/* Check segment lies within image */
+	if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
+		DBGC ( image, "ELF %p segment outside image\n", image );
+		return -ENOEXEC;
+	}
+
+	/* Find start address: use physical address for preference,
+	 * fall back to virtual address if no physical address
+	 * supplied.
+	 */
+	dest = phdr->p_paddr;
+	if ( ! dest )
+		dest = phdr->p_vaddr;
+	if ( ! dest ) {
+		DBGC ( image, "ELF %p segment loads to physical address 0\n",
+		       image );
+		return -ENOEXEC;
+	}
+	buffer = phys_to_user ( dest );
+
+	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
+	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
+	       phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
+	       ( phdr->p_paddr + phdr->p_memsz ) );
+
+	/* Verify and prepare segment */
+	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
+				   phdr->p_memsz ) ) != 0 ) {
+		DBGC ( image, "ELF %p could not prepare segment: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Copy image to segment */
+	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
+
+	/* Set execution address, if it lies within this segment */
+	if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
+		*entry = ehdr->e_entry;
+		DBGC ( image, "ELF %p found physical entry point at %lx\n",
+		       image, *entry );
+	} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
+		    < phdr->p_filesz ) {
+		if ( ! *entry ) {
+			*entry = ( dest + e_offset );
+			DBGC ( image, "ELF %p found virtual entry point at %lx"
+			       " (virt %lx)\n", image, *entry,
+			       ( ( unsigned long ) ehdr->e_entry ) );
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Load ELF image into memory
+ *
+ * @v image		ELF file
+ * @ret entry		Entry point
+ * @ret rc		Return status code
+ */
+int elf_load ( struct image *image, physaddr_t *entry ) {
+	Elf_Ehdr ehdr;
+	Elf_Phdr phdr;
+	Elf_Off phoff;
+	unsigned int phnum;
+	int rc;
+
+	/* Read ELF header */
+	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
+	if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
+		DBGC ( image, "ELF %p has invalid signature\n", image );
+		return -ENOEXEC;
+	}
+
+	/* Invalidate entry point */
+	*entry = 0;
+
+	/* Read ELF program headers */
+	for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
+	      phoff += ehdr.e_phentsize, phnum-- ) {
+		if ( phoff > image->len ) {
+			DBGC ( image, "ELF %p program header %d outside "
+			       "image\n", image, phnum );
+			return -ENOEXEC;
+		}
+		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
+		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
+					       entry ) ) != 0 ) {
+			return rc;
+		}
+	}
+
+	/* Check for a valid execution address */
+	if ( ! *entry ) {
+		DBGC ( image, "ELF %p entry point %lx outside image\n",
+		       image, ( ( unsigned long ) ehdr.e_entry ) );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/image/embedded.c b/qemu-0.15.x/roms/ipxe/src/image/embedded.c
new file mode 100644
index 0000000..6358378
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/image/embedded.c
@@ -0,0 +1,91 @@
+/** @file
+ *
+ * Embedded image support
+ *
+ * Embedded images are images built into the iPXE binary and do not require
+ * fetching over the network.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/image.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/init.h>
+
+/* Raw image data for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name )					\
+	extern char embedded_image_ ## _index ## _data[];		\
+	extern char embedded_image_ ## _index ## _len[];		\
+	__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"		\
+		  "\nembedded_image_" #_index "_data:\n\t"		\
+		  ".incbin \"" _path "\"\n\t"				\
+		  "\nembedded_image_" #_index "_end:\n\t"		\
+		  ".equ embedded_image_" #_index "_len, "		\
+			"( embedded_image_" #_index "_end - "		\
+			"  embedded_image_" #_index "_data )\n\t"	\
+		  ".previous\n\t" );
+EMBED_ALL
+
+/* Image structures for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name ) {					\
+	.refcnt = REF_INIT ( ref_no_free ),				\
+	.name = _name,							\
+	.data = ( userptr_t ) ( embedded_image_ ## _index ## _data ),	\
+	.len = ( size_t ) embedded_image_ ## _index ## _len,		\
+},
+static struct image embedded_images[] = {
+	EMBED_ALL
+};
+
+/**
+ * Register all embedded images
+ */
+static void embedded_init ( void ) {
+	int i;
+	struct image *image;
+	void *data;
+	int rc;
+
+	/* Skip if we have no embedded images */
+	if ( ! sizeof ( embedded_images ) )
+		return;
+
+	/* Fix up data pointers and register images */
+	for ( i = 0 ; i < ( int ) ( sizeof ( embedded_images ) /
+				    sizeof ( embedded_images[0] ) ) ; i++ ) {
+		image = &embedded_images[i];
+
+		/* virt_to_user() cannot be used in a static
+		 * initialiser, so we cast the pointer to a userptr_t
+		 * in the initialiser and fix it up here.  (This will
+		 * actually be a no-op on most platforms.)
+		 */
+		data = ( ( void * ) image->data );
+		image->data = virt_to_user ( data );
+
+		DBG ( "Embedded image \"%s\": %zd bytes at %p\n",
+		      image->name, image->len, data );
+
+		if ( ( rc = register_image ( image ) ) != 0 ) {
+			DBG ( "Could not register embedded image \"%s\": "
+			      "%s\n", image->name, strerror ( rc ) );
+			return;
+		}
+	}
+
+	/* Select the first image */
+	image = &embedded_images[0];
+	if ( ( rc = image_select ( image ) ) != 0 ) {
+		DBG ( "Could not select embedded image \"%s\": %s\n",
+		      image->name, strerror ( rc ) );
+		return;
+	}
+}
+
+/** Embedded image initialisation function */
+struct init_fn embedded_init_fn __init_fn ( INIT_LATE ) = {
+	.initialise = embedded_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/image/script.c b/qemu-0.15.x/roms/ipxe/src/image/script.c
new file mode 100644
index 0000000..161ac68
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/image/script.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * iPXE scripts
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/image.h>
+#include <ipxe/shell.h>
+#include <usr/prompt.h>
+#include <ipxe/script.h>
+
+/** Offset within current script
+ *
+ * This is a global in order to allow goto_exec() to update the
+ * offset.
+ */
+static size_t script_offset;
+
+/**
+ * Process script lines
+ *
+ * @v image		Script
+ * @v process_line	Line processor
+ * @v terminate		Termination check
+ * @ret rc		Return status code
+ */
+static int process_script ( struct image *image,
+			    int ( * process_line ) ( const char *line ),
+			    int ( * terminate ) ( int rc ) ) {
+	off_t eol;
+	size_t len;
+	int rc;
+
+	script_offset = 0;
+
+	do {
+	
+		/* Find length of next line, excluding any terminating '\n' */
+		eol = memchr_user ( image->data, script_offset, '\n',
+				    ( image->len - script_offset ) );
+		if ( eol < 0 )
+			eol = image->len;
+		len = ( eol - script_offset );
+
+		/* Copy line, terminate with NUL, and execute command */
+		{
+			char cmdbuf[ len + 1 ];
+
+			copy_from_user ( cmdbuf, image->data,
+					 script_offset, len );
+			cmdbuf[len] = '\0';
+			DBG ( "$ %s\n", cmdbuf );
+
+			/* Move to next line */
+			script_offset += ( len + 1 );
+
+			/* Process line */
+			rc = process_line ( cmdbuf );
+			if ( terminate ( rc ) )
+				return rc;
+		}
+
+	} while ( script_offset < image->len );
+
+	return rc;
+}
+
+/**
+ * Terminate script processing on shell exit or command failure
+ *
+ * @v rc		Line processing status
+ * @ret terminate	Terminate script processing
+ */
+static int terminate_on_exit_or_failure ( int rc ) {
+
+	return ( shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) ||
+		 ( rc != 0 ) );
+}
+
+/**
+ * Execute script line
+ *
+ * @v line		Line of script
+ * @ret rc		Return status code
+ */
+static int script_exec_line ( const char *line ) {
+	int rc;
+
+	/* Skip label lines */
+	if ( line[0] == ':' )
+		return 0;
+
+	/* Execute command */
+	if ( ( rc = system ( line ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Execute script
+ *
+ * @v image		Script
+ * @ret rc		Return status code
+ */
+static int script_exec ( struct image *image ) {
+	size_t saved_offset;
+	int rc;
+
+	/* Temporarily de-register image, so that a "boot" command
+	 * doesn't throw us into an execution loop.
+	 */
+	unregister_image ( image );
+
+	/* Preserve state of any currently-running script */
+	saved_offset = script_offset;
+
+	/* Process script */
+	rc = process_script ( image, script_exec_line,
+			      terminate_on_exit_or_failure );
+
+	/* Restore saved state */
+	script_offset = saved_offset;
+
+	/* Re-register image (unless we have been replaced) */
+	if ( ! image->replacement )
+		register_image ( image );
+
+	return rc;
+}
+
+/**
+ * Probe script image
+ *
+ * @v image		Script
+ * @ret rc		Return status code
+ */
+static int script_probe ( struct image *image ) {
+	static const char ipxe_magic[] = "#!ipxe";
+	static const char gpxe_magic[] = "#!gpxe";
+	linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ),
+			magic_size_mismatch );
+	char test[ sizeof ( ipxe_magic ) - 1 /* NUL */
+		   + 1 /* terminating space */];
+
+	/* Sanity check */
+	if ( image->len < sizeof ( test ) ) {
+		DBG ( "Too short to be a script\n" );
+		return -ENOEXEC;
+	}
+
+	/* Check for magic signature */
+	copy_from_user ( test, image->data, 0, sizeof ( test ) );
+	if ( ! ( ( ( memcmp ( test, ipxe_magic, sizeof ( test ) - 1 ) == 0 ) ||
+		   ( memcmp ( test, gpxe_magic, sizeof ( test ) - 1 ) == 0 )) &&
+		 isspace ( test[ sizeof ( test ) - 1 ] ) ) ) {
+		DBG ( "Invalid magic signature\n" );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/** Script image type */
+struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "script",
+	.probe = script_probe,
+	.exec = script_exec,
+};
+
+/** "goto" options */
+struct goto_options {};
+
+/** "goto" option list */
+static struct option_descriptor goto_opts[] = {};
+
+/** "goto" command descriptor */
+static struct command_descriptor goto_cmd =
+	COMMAND_DESC ( struct goto_options, goto_opts, 1, 1, "<label>" );
+
+/**
+ * Current "goto" label
+ *
+ * Valid only during goto_exec().  Consider this part of a closure.
+ */
+static const char *goto_label;
+
+/**
+ * Check for presence of label
+ *
+ * @v line		Script line
+ * @ret rc		Return status code
+ */
+static int goto_find_label ( const char *line ) {
+
+	if ( line[0] != ':' )
+		return -ENOENT;
+	if ( strcmp ( goto_label, &line[1] ) != 0 )
+		return -ENOENT;
+	return 0;
+}
+
+/**
+ * Terminate script processing when label is found
+ *
+ * @v rc		Line processing status
+ * @ret terminate	Terminate script processing
+ */
+static int terminate_on_label_found ( int rc ) {
+	return ( rc == 0 );
+}
+
+/**
+ * "goto" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int goto_exec ( int argc, char **argv ) {
+	struct goto_options opts;
+	size_t saved_offset;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &goto_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Sanity check */
+	if ( ! current_image ) {
+		rc = -ENOTTY;
+		printf ( "Not in a script: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	/* Parse label */
+	goto_label = argv[optind];
+
+	/* Find label */
+	saved_offset = script_offset;
+	if ( ( rc = process_script ( current_image, goto_find_label,
+				     terminate_on_label_found ) ) != 0 ) {
+		script_offset = saved_offset;
+		return rc;
+	}
+
+	/* Terminate processing of current command */
+	shell_stop ( SHELL_STOP_COMMAND );
+
+	return 0;
+}
+
+/** "goto" command */
+struct command goto_command __command = {
+	.name = "goto",
+	.exec = goto_exec,
+};
+
+/** "prompt" options */
+struct prompt_options {
+	/** Key to wait for */
+	unsigned int key;
+	/** Timeout */
+	unsigned int timeout;
+};
+
+/** "prompt" option list */
+static struct option_descriptor prompt_opts[] = {
+	OPTION_DESC ( "key", 'k', required_argument,
+		      struct prompt_options, key, parse_integer ),
+	OPTION_DESC ( "timeout", 't', required_argument,
+		      struct prompt_options, timeout, parse_integer ),
+};
+
+/** "prompt" command descriptor */
+static struct command_descriptor prompt_cmd =
+	COMMAND_DESC ( struct prompt_options, prompt_opts, 0, MAX_ARGUMENTS,
+		       "[--key <key>] [--timeout <timeout>] [<text>]" );
+
+/**
+ * "prompt" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int prompt_exec ( int argc, char **argv ) {
+	struct prompt_options opts;
+	char *text;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &prompt_cmd, &opts ) ) != 0 )
+		goto err_parse;
+
+	/* Parse prompt text */
+	text = concat_args ( &argv[optind] );
+	if ( ! text ) {
+		rc = -ENOMEM;
+		goto err_concat;
+	}
+
+	/* Display prompt and wait for key */
+	if ( ( rc = prompt ( text, opts.timeout, opts.key ) ) != 0 )
+		goto err_prompt;
+
+	/* Free prompt text */
+	free ( text );
+
+	return 0;
+
+ err_prompt:
+	free ( text );
+ err_concat:
+ err_parse:
+	return rc;
+}
+
+/** "prompt" command */
+struct command prompt_command __command = {
+	.name = "prompt",
+	.exec = prompt_exec,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/image/segment.c b/qemu-0.15.x/roms/ipxe/src/image/segment.c
new file mode 100644
index 0000000..97f6a99
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/image/segment.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Executable image segments
+ *
+ */
+
+#include <errno.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/io.h>
+#include <ipxe/errortab.h>
+#include <ipxe/segment.h>
+
+/**
+ * Segment-specific error messages
+ *
+ * This error happens sufficiently often to merit a user-friendly
+ * description.
+ */
+#define ERANGE_SEGMENT __einfo_error ( EINFO_ERANGE_SEGMENT )
+#define EINFO_ERANGE_SEGMENT \
+	__einfo_uniqify ( EINFO_ERANGE, 0x01, "Requested memory not available" )
+struct errortab segment_errors[] __errortab = {
+	__einfo_errortab ( EINFO_ERANGE_SEGMENT ),
+};
+
+/**
+ * Prepare segment for loading
+ *
+ * @v segment		Segment start
+ * @v filesz		Size of the "allocated bytes" portion of the segment
+ * @v memsz		Size of the segment
+ * @ret rc		Return status code
+ */
+int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) {
+	struct memory_map memmap;
+	physaddr_t start = user_to_phys ( segment, 0 );
+	physaddr_t mid = user_to_phys ( segment, filesz );
+	physaddr_t end = user_to_phys ( segment, memsz );
+	unsigned int i;
+
+	DBG ( "Preparing segment [%lx,%lx,%lx)\n", start, mid, end );
+
+	/* Sanity check */
+	if ( filesz > memsz ) {
+		DBG ( "Insane segment [%lx,%lx,%lx)\n", start, mid, end );
+		return -EINVAL;
+	}
+
+	/* Get a fresh memory map.  This allows us to automatically
+	 * avoid treading on any regions that Etherboot is currently
+	 * editing out of the memory map.
+	 */
+	get_memmap ( &memmap );
+
+	/* Look for a suitable memory region */
+	for ( i = 0 ; i < memmap.count ; i++ ) {
+		if ( ( start >= memmap.regions[i].start ) &&
+		     ( end <= memmap.regions[i].end ) ) {
+			/* Found valid region: zero bss and return */
+			memset_user ( segment, filesz, 0, ( memsz - filesz ) );
+			return 0;
+		}
+	}
+
+	/* No suitable memory region found */
+	DBG ( "Segment [%lx,%lx,%lx) does not fit into available memory\n",
+	      start, mid, end );
+	return -ERANGE_SEGMENT;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/include/.gitignore b/qemu-0.15.x/roms/ipxe/src/include/.gitignore
new file mode 100644
index 0000000..de1598e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/.gitignore
@@ -0,0 +1 @@
+.buildserial.h
diff --git a/qemu-0.15.x/roms/ipxe/src/include/alloca.h b/qemu-0.15.x/roms/ipxe/src/include/alloca.h
new file mode 100644
index 0000000..08398fb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/alloca.h
@@ -0,0 +1,25 @@
+#ifndef _ALLOCA_H
+#define _ALLOCA_H
+
+/**
+ * @file
+ *
+ * Temporary memory allocation
+ *
+ */
+
+#include <stdint.h>
+
+/**
+ * Allocate temporary memory from the stack
+ *
+ * @v size		Size to allocate
+ * @ret ptr		Allocated memory
+ *
+ * This memory will be freed automatically when the containing
+ * function returns.  There are several caveats regarding use of
+ * alloca(); use it only if you already know what they are.
+ */
+#define alloca(size) __builtin_alloca ( size )
+
+#endif /* _ALLOCA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/assert.h b/qemu-0.15.x/roms/ipxe/src/include/assert.h
new file mode 100644
index 0000000..40a00a2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/assert.h
@@ -0,0 +1,67 @@
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+/** @file
+ *
+ * Assertions
+ *
+ * This file provides two assertion macros: assert() (for run-time
+ * assertions) and linker_assert() (for link-time assertions).
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef NDEBUG
+#define ASSERTING 0
+#else
+#define ASSERTING 1
+#endif
+
+/** printf() for assertions
+ *
+ * This function exists so that the assert() macro can expand to
+ * printf() calls without dragging the printf() prototype into scope.
+ *
+ * As far as the compiler is concerned, assert_printf() and printf() are
+ * completely unrelated calls; it's only at the assembly stage that
+ * references to the assert_printf symbol are collapsed into references
+ * to the printf symbol.
+ */
+extern int __attribute__ (( format ( printf, 1, 2 ) )) 
+assert_printf ( const char *fmt, ... ) asm ( "printf" );
+
+/**
+ * Assert a condition at run-time.
+ *
+ * If the condition is not true, a debug message will be printed.
+ * Assertions only take effect in debug-enabled builds (see DBG()).
+ *
+ * @todo Make an assertion failure abort the program
+ *
+ */
+#define assert( condition ) 						     \
+	do { 								     \
+		if ( ASSERTING && ! (condition) ) { 			     \
+			assert_printf ( "assert(%s) failed at %s line %d\n", \
+					#condition, __FILE__, __LINE__ );    \
+		} 							     \
+	} while ( 0 )
+
+/**
+ * Assert a condition at link-time.
+ *
+ * If the condition is not true, the link will fail with an unresolved
+ * symbol (error_symbol).
+ *
+ * This macro is iPXE-specific.  Do not use this macro in code
+ * intended to be portable.
+ *
+ */
+#define linker_assert( condition, error_symbol )	\
+        if ( ! (condition) ) {				\
+                extern void error_symbol ( void );	\
+                error_symbol();				\
+        }
+
+#endif /* _ASSERT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/big_bswap.h b/qemu-0.15.x/roms/ipxe/src/include/big_bswap.h
new file mode 100644
index 0000000..3775fac
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/big_bswap.h
@@ -0,0 +1,33 @@
+#ifndef ETHERBOOT_BIG_BSWAP_H
+#define ETHERBOOT_BIG_BSWAP_H
+
+#define ntohl(x) 	(x)
+#define htonl(x) 	(x)
+#define ntohs(x) 	(x)
+#define htons(x) 	(x)
+#define cpu_to_le64(x)	__bswap_64(x)
+#define cpu_to_le32(x)	__bswap_32(x)
+#define cpu_to_le16(x)	__bswap_16(x)
+#define cpu_to_be64(x)	(x)
+#define cpu_to_be32(x)	(x)
+#define cpu_to_be16(x)	(x)
+#define le64_to_cpu(x)	__bswap_64(x)
+#define le32_to_cpu(x)	__bswap_32(x)
+#define le16_to_cpu(x)	__bswap_16(x)
+#define be64_to_cpu(x)	(x)
+#define be32_to_cpu(x)	(x)
+#define be16_to_cpu(x)	(x)
+#define cpu_to_le64s(x) __bswap_64s(x)
+#define cpu_to_le32s(x) __bswap_32s(x)
+#define cpu_to_le16s(x) __bswap_16s(x)
+#define cpu_to_be64s(x) do {} while (0)
+#define cpu_to_be32s(x) do {} while (0)
+#define cpu_to_be16s(x) do {} while (0)
+#define le64_to_cpus(x) __bswap_64s(x)
+#define le32_to_cpus(x) __bswap_32s(x)
+#define le16_to_cpus(x) __bswap_16s(x)
+#define be64_to_cpus(x) do {} while (0)
+#define be32_to_cpus(x) do {} while (0)
+#define be16_to_cpus(x) do {} while (0)
+
+#endif /* ETHERBOOT_BIG_BSWAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/bootp.h b/qemu-0.15.x/roms/ipxe/src/include/bootp.h
new file mode 100644
index 0000000..0e65477
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/bootp.h
@@ -0,0 +1,230 @@
+#ifndef	_BOOTP_H
+#define	_BOOTP_H
+
+#ifdef	ALTERNATE_DHCP_PORTS_1067_1068
+#undef	NON_STANDARD_BOOTP_SERVER
+#define	NON_STANDARD_BOOTP_SERVER	1067
+#undef	NON_STANDARD_BOOTP_CLIENT
+#define	NON_STANDARD_BOOTP_CLIENT	1068
+#endif
+
+#ifdef	NON_STANDARD_BOOTP_SERVER
+#define	BOOTP_SERVER	NON_STANDARD_BOOTP_SERVER
+#else
+#define BOOTP_SERVER	67
+#endif
+#ifdef	NON_STANDARD_BOOTP_CLIENT
+#define	BOOTP_CLIENT	NON_STANDARD_BOOTP_CLIENT
+#else
+#define BOOTP_CLIENT	68
+#endif
+#define PROXYDHCP_SERVER	4011 /* For PXE */
+
+#define BOOTP_REQUEST	1
+#define BOOTP_REPLY	2
+
+#define TAG_LEN(p)		(*((p)+1))
+#define RFC1533_COOKIE		99, 130, 83, 99
+#define RFC1533_PAD		0
+#define RFC1533_NETMASK		1
+#define RFC1533_TIMEOFFSET	2
+#define RFC1533_GATEWAY		3
+#define RFC1533_TIMESERVER	4
+#define RFC1533_IEN116NS	5
+#define RFC1533_DNS		6
+#define RFC1533_LOGSERVER	7
+#define RFC1533_COOKIESERVER	8
+#define RFC1533_LPRSERVER	9
+#define RFC1533_IMPRESSSERVER	10
+#define RFC1533_RESOURCESERVER	11
+#define RFC1533_HOSTNAME	12
+#define RFC1533_BOOTFILESIZE	13
+#define RFC1533_MERITDUMPFILE	14
+#define RFC1533_DOMAINNAME	15
+#define RFC1533_SWAPSERVER	16
+#define RFC1533_ROOTPATH	17
+#define RFC1533_EXTENSIONPATH	18
+#define RFC1533_IPFORWARDING	19
+#define RFC1533_IPSOURCEROUTING	20
+#define RFC1533_IPPOLICYFILTER	21
+#define RFC1533_IPMAXREASSEMBLY	22
+#define RFC1533_IPTTL		23
+#define RFC1533_IPMTU		24
+#define RFC1533_IPMTUPLATEAU	25
+#define RFC1533_INTMTU		26
+#define RFC1533_INTLOCALSUBNETS	27
+#define RFC1533_INTBROADCAST	28
+#define RFC1533_INTICMPDISCOVER	29
+#define RFC1533_INTICMPRESPOND	30
+#define RFC1533_INTROUTEDISCOVER 31
+#define RFC1533_INTROUTESOLICIT	32
+#define RFC1533_INTSTATICROUTES	33
+#define RFC1533_LLTRAILERENCAP	34
+#define RFC1533_LLARPCACHETMO	35
+#define RFC1533_LLETHERNETENCAP	36
+#define RFC1533_TCPTTL		37
+#define RFC1533_TCPKEEPALIVETMO	38
+#define RFC1533_TCPKEEPALIVEGB	39
+#define RFC1533_NISDOMAIN	40
+#define RFC1533_NISSERVER	41
+#define RFC1533_NTPSERVER	42
+#define RFC1533_VENDOR		43
+#define RFC1533_NBNS		44
+#define RFC1533_NBDD		45
+#define RFC1533_NBNT		46
+#define RFC1533_NBSCOPE		47
+#define RFC1533_XFS		48
+#define RFC1533_XDM		49
+#ifndef	NO_DHCP_SUPPORT
+#define RFC2132_REQ_ADDR	50
+#define RFC2132_MSG_TYPE	53
+#define RFC2132_SRV_ID		54
+#define RFC2132_PARAM_LIST	55
+#define RFC2132_MAX_SIZE	57
+#define	RFC2132_VENDOR_CLASS_ID	60
+#define RFC2132_CLIENT_ID       61
+#define	RFC2132_TFTP_SERVER_NAME 66
+#define	RFC2132_BOOTFILE_NAME	67
+#define RFC3004_USER_CLASS      77
+
+#ifdef PXE_DHCP_STRICT
+/*
+ * The following options are acknowledged in RFC3679 because they are
+ * widely used by PXE implementations, but have never been properly
+ * allocated. Despite other PXE options being correctly packed in a
+ * vendor encapsulated field, these are exposed. Sigh.  Note that the
+ * client UUID (option 97) is also noted in the PXE spec as using
+ * option 61.
+ */
+#define RFC3679_PXE_CLIENT_ARCH 93
+#define RFC3679_PXE_CLIENT_NDI  94
+#define RFC3679_PXE_CLIENT_UUID 97
+
+/* The lengths are fixed. */
+#define RFC3679_PXE_CLIENT_ARCH_LENGTH 2
+#define RFC3679_PXE_CLIENT_NDI_LENGTH 3
+#define RFC3679_PXE_CLIENT_UUID_LENGTH 17
+
+/*
+ * Values of RFC3679_PXE_CLIENT_ARCH can apparently be one of the
+ * following, according to the PXE spec. The spec only actually
+ * described the 2nd octet, not the first. Duh... assume 0.
+ */
+#define RFC3679_PXE_CLIENT_ARCH_IAX86PC   0,0
+#define RFC3679_PXE_CLIENT_ARCH_NECPC98   0,1
+#define RFC3679_PXE_CLIENT_ARCH_IA64PC    0,2
+#define RFC3679_PXE_CLIENT_ARCH_DECALPHA  0,3
+#define RFC3679_PXE_CLIENT_ARCH_ARCX86    0,4
+#define RFC3679_PXE_CLIENT_ARCH_INTELLEAN 0,5
+
+/* 
+ * Only one valid value of NDI type (must be 1) and UNDI version (must
+ * be 2.1)
+ */
+#define RFC3679_PXE_CLIENT_NDI_21 1,2,1
+
+/*
+ * UUID - type must be 1 and then 16 octets of UID, as with the client ID.
+ * The value is a default for testing only
+ */
+#define RFC3679_PXE_CLIENT_UUID_TYPE 0
+#warning "UUID is a default for testing ONLY!"
+#define RFC3679_PXE_CLIENT_UUID_DEFAULT \
+        RFC3679_PXE_CLIENT_UUID_TYPE, \
+        0xDE,0xAD,0xBE,0xEF, \
+        0xDE,0xAD,0xBE,0xEF, \
+        0xDE,0xAD,0xBE,0xEF, \
+        0xDE,0xAD,0xBE,0xEF
+/*
+ * The Vendor Class ID. Note that the Arch and UNDI version numbers
+ * are fixed and must be same as the ARCH and NDI above.
+ */
+#define RFC2132_VENDOR_CLASS_ID_PXE_LENGTH 32
+#define RFC2132_VENDOR_CLASS_ID_PXE \
+        'P','X','E','C','l','i','e','n','t',':', \
+        'A','r','c','h',':','0','0','0','0','0',':', \
+        'U','N','D','I',':','0','0','2','0','0','1'
+
+/*
+ * The following vendor options are required in the PXE spec to pull
+ * options for the *next* image. The PXE spec doesn't help us with
+ * this (like explaining why).
+ */
+#define RFC1533_VENDOR_PXE_OPT128 128
+#define RFC1533_VENDOR_PXE_OPT129 129
+#define RFC1533_VENDOR_PXE_OPT130 130
+#define RFC1533_VENDOR_PXE_OPT131 131
+#define RFC1533_VENDOR_PXE_OPT132 132
+#define RFC1533_VENDOR_PXE_OPT133 133
+#define RFC1533_VENDOR_PXE_OPT134 134
+#define RFC1533_VENDOR_PXE_OPT135 135
+
+#endif /* PXE_DHCP_STRICT */
+
+#define DHCPDISCOVER		1
+#define DHCPOFFER		2
+#define DHCPREQUEST		3
+#define DHCPACK			5
+#endif	/* NO_DHCP_SUPPORT */
+
+#define RFC1533_VENDOR_MAJOR	0
+#define RFC1533_VENDOR_MINOR	0
+
+#define RFC1533_VENDOR_MAGIC	128
+#define RFC1533_VENDOR_ADDPARM	129
+#define	RFC1533_VENDOR_ETHDEV	130
+/* We should really apply for an official Etherboot encap option */
+#define RFC1533_VENDOR_ETHERBOOT_ENCAP 150
+/* I'll leave it to FREEBSD to decide if they want to renumber */
+#ifdef	IMAGE_FREEBSD
+#define RFC1533_VENDOR_HOWTO    132
+#define RFC1533_VENDOR_KERNEL_ENV    133
+#endif
+#define RFC1533_VENDOR_NIC_DEV_ID 175
+#define RFC1533_VENDOR_ARCH     177
+
+#define RFC1533_END		255
+
+#define BOOTP_VENDOR_LEN	64
+#ifndef	NO_DHCP_SUPPORT
+#define DHCP_OPT_LEN		312
+#endif	/* NO_DHCP_SUPPORT */
+
+/* Format of a bootp packet */
+struct bootp_t {
+	uint8_t  bp_op;
+	uint8_t  bp_htype;
+	uint8_t  bp_hlen;
+	uint8_t  bp_hops;
+	uint32_t bp_xid;
+	uint16_t bp_secs;
+	uint16_t unused;
+	in_addr bp_ciaddr;
+	in_addr bp_yiaddr;
+	in_addr bp_siaddr;
+	in_addr bp_giaddr;
+	uint8_t  bp_hwaddr[16];
+	uint8_t  bp_sname[64];
+	char     bp_file[128];
+#ifdef	NO_DHCP_SUPPORT
+	uint8_t  bp_vend[BOOTP_VENDOR_LEN];
+#else
+	uint8_t  bp_vend[DHCP_OPT_LEN];
+#endif	/* NO_DHCP_SUPPORT */
+};
+
+/* Format of a bootp IP packet */
+struct bootpip_t
+{
+	struct iphdr ip;
+	struct udphdr udp;
+	struct bootp_t bp;
+};
+
+/* Format of bootp packet with extensions */
+struct bootpd_t {
+	struct bootp_t bootp_reply;
+	uint8_t bootp_extension[MAX_BOOTP_EXTLEN];
+};
+
+#endif	/* _BOOTP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/btext.h b/qemu-0.15.x/roms/ipxe/src/include/btext.h
new file mode 100644
index 0000000..1d3f9e5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/btext.h
@@ -0,0 +1,62 @@
+/*
+ * This file describes the structure passed from the BootX application
+ * (for MacOS) when it is used to boot Linux.
+ *
+ * Written by Benjamin Herrenschmidt.
+ *  
+ * Move to LinuxBIOS by LYH  yhlu at tyan.com
+ *
+ */
+
+
+#ifndef _BTEXT_H__
+#define _BTEXT_H__
+
+#if 1
+#define u32 unsigned int
+#define u16 unsigned short
+#define u8 unsigned char
+#endif
+
+/* Here are the boot informations that are passed to the bootstrap
+ * Note that the kernel arguments and the device tree are appended
+ * at the end of this structure. */
+typedef struct boot_infos
+{
+
+    /* NEW (vers. 2) this holds the current _logical_ base addr of
+       the frame buffer (for use by early boot message) */
+    u8*       logicalDisplayBase;
+
+
+    /* Some infos about the current MacOS display */
+    u32       dispDeviceRect[4];       /* left,top,right,bottom */
+    u32       dispDeviceDepth;         /* (8, 16 or 32) */
+    u32       dispDeviceBase;          /* base address (physical) */
+    u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
+    u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
+
+
+    /* The framebuffer size (optional, currently 0) */
+    u32       frameBufferSize;         /* Represents a max size, can be 0. */
+
+
+} boot_infos_t;
+
+/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index is represented
+ * by 3 short words containing a 16 bits (unsigned) color component.
+ * Later versions may contain the gamma table for direct-color devices here.
+ */
+#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
+
+
+/*
+ * Definitions for using the procedures in btext.c.
+ *
+ * Benjamin Herrenschmidt <benh at kernel.crashing.org>
+ */
+
+extern boot_infos_t disp_bi;
+extern u32 boot_text_mapped;
+
+#endif /* _BTEXT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/byteswap.h b/qemu-0.15.x/roms/ipxe/src/include/byteswap.h
new file mode 100644
index 0000000..466759c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/byteswap.h
@@ -0,0 +1,59 @@
+#ifndef ETHERBOOT_BYTESWAP_H
+#define ETHERBOOT_BYTESWAP_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "endian.h"
+#include "bits/byteswap.h"
+
+#define __bswap_constant_16(x) \
+	((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
+		    (((uint16_t)(x) & 0xff00) >> 8)))
+
+#define __bswap_constant_32(x) \
+	((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
+		    (((uint32_t)(x) & 0x0000ff00U) <<  8) | \
+		    (((uint32_t)(x) & 0x00ff0000U) >>  8) | \
+		    (((uint32_t)(x) & 0xff000000U) >> 24)))
+
+#define __bswap_constant_64(x) \
+	((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \
+		    (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+		    (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+		    (((uint64_t)(x) & 0x00000000ff000000ULL) <<  8) | \
+		    (((uint64_t)(x) & 0x000000ff00000000ULL) >>  8) | \
+		    (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+		    (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+		    (((uint64_t)(x) & 0xff00000000000000ULL) >> 56)))
+
+#define __bswap_16(x) \
+	((uint16_t)(__builtin_constant_p(x) ? \
+	__bswap_constant_16(x) : \
+	__bswap_variable_16(x)))
+
+#define __bswap_32(x) \
+	((uint32_t)(__builtin_constant_p(x) ? \
+	__bswap_constant_32(x) : \
+	__bswap_variable_32(x)))
+
+#define __bswap_64(x) \
+	((uint64_t)(__builtin_constant_p(x) ? \
+	__bswap_constant_64(x) : \
+	__bswap_variable_64(x)))
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#include "little_bswap.h"
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN
+#include "big_bswap.h"
+#endif
+
+/* Make routines available to all */
+#define swap64(x)	__bswap_64(x)
+#define swap32(x)	__bswap_32(x)
+#define swap16(x)	__bswap_16(x)
+#define bswap_64(x)	__bswap_64(x)
+#define bswap_32(x)	__bswap_32(x)
+#define bswap_16(x)	__bswap_16(x)
+	
+#endif /* ETHERBOOT_BYTESWAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/coff.h b/qemu-0.15.x/roms/ipxe/src/include/coff.h
new file mode 100644
index 0000000..a73fda5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/coff.h
@@ -0,0 +1,73 @@
+#ifndef COFF_H
+#define COFF_H
+/* Based on the elf.h file
+ * Changed accordingly to support COFF file support
+ */
+
+
+/* Values for f_flags. */
+#define F_RELFLG	0x0001 	/* If set, not reloc. info. Clear for executables */
+#define F_EXEC		0x0002	/* No unresolved symbols. Executable file ! */
+#define F_LNNO		0x0004	/* If set, line information numbers removed  */
+#define F_LSYMS		0x0008	/* If set, local symbols removed  */
+#define F_AR32WR	0x0100	/* Indicates little endian file */
+
+/* Values for e_machine (architecute). */
+#define EM_E1		0x17a 	/* Magic number for Hyperstone. Big endian format */
+
+/* Values for f_flags. */
+#define	O_MAGIC		0x017c	/* Optional's header magic number for Hyperstone */
+
+/* Values for s_flags. */
+#define S_TYPE_TEXT	0x0020 	/* If set, the section contains only executable */
+#define S_TYPE_DATA	0x0040 	/* If set, the section contains only initialized data */
+#define S_TYPE_BSS	0x0080 	/* If set, the section is BSS no data stored */
+
+
+typedef struct
+{
+	unsigned short 	f_magic;	/* magic number				*/
+	unsigned short 	f_nscns;	/* number of sections		*/
+	unsigned long 	f_timdat;	/* time & date stamp		*/
+	unsigned long 	f_symptr;	/* file pointer to symtab	*/
+	unsigned long 	f_nsyms;	/* number of symtab entries	*/
+	unsigned short	f_opthdr;	/* sizeof(optional hdr)		*/
+	unsigned short 	f_flags;	/* flags					*/
+}
+COFF_filehdr;
+
+/*
+ * Optional header.
+ */
+typedef struct 
+{
+  unsigned short	magic;		/* type of file				*/
+  unsigned short	vstamp;		/* version stamp			*/
+  unsigned long		tsize;		/* text size in bytes, padded to FW bdry*/
+  unsigned long		dsize;		/* initialized data "  "		*/
+  unsigned long		bsize;		/* uninitialized data "   "		*/
+  unsigned long		entry;		/* entry pt.				*/
+  unsigned long		text_start;	/* base of text used for this file */
+  unsigned long 	data_start;	/* base of data used for this file */
+}	
+COFF_opthdr;
+
+/*
+ * Section header.
+ */
+typedef struct 
+{
+	char				s_name[8];	/* section name			*/
+	unsigned long		s_paddr;	/* physical address, aliased s_nlib */
+	unsigned long		s_vaddr;	/* virtual address		*/
+	unsigned long		s_size;		/* section size			*/
+	unsigned long		s_scnptr;	/* file ptr to raw data for section */
+	unsigned long		s_relptr;	/* file ptr to relocation	*/
+	unsigned long		s_lnnoptr;	/* file ptr to line numbers	*/
+	unsigned short		s_nreloc;	/* number of relocation entries	*/
+	unsigned short		s_nlnno;	/* number of line number entries*/
+	unsigned long		s_flags;	/* flags			*/
+}
+COFF_scnhdr;
+
+#endif /* COFF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/compiler.h b/qemu-0.15.x/roms/ipxe/src/include/compiler.h
new file mode 100644
index 0000000..feea516
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/compiler.h
@@ -0,0 +1,759 @@
+#ifndef COMPILER_H
+#define COMPILER_H
+
+/*
+ * Doxygen can't cope with some of the more esoteric areas of C, so we
+ * make its life simpler.
+ *
+ */
+#ifdef DOXYGEN
+#define __attribute__(x)
+#endif
+
+/** @file
+ *
+ * Global compiler definitions.
+ *
+ * This file is implicitly included by every @c .c file in Etherboot.
+ * It defines global macros such as DBG().
+ *
+ * We arrange for each object to export the symbol @c obj_OBJECT
+ * (where @c OBJECT is the object name, e.g. @c rtl8139) as a global
+ * symbol, so that the linker can drag in selected object files from
+ * the library using <tt> -u obj_OBJECT </tt>.
+ *
+ */
+
+/* Force visibility of all symbols to "hidden", i.e. inform gcc that
+ * all symbol references resolve strictly within our final binary.
+ * This avoids unnecessary PLT/GOT entries on x86_64.
+ *
+ * This is a stronger claim than specifying "-fvisibility=hidden",
+ * since it also affects symbols marked with "extern".
+ */
+#ifndef ASSEMBLY
+#if __GNUC__ >= 4
+#pragma GCC visibility push(hidden)
+#endif
+#endif /* ASSEMBLY */
+
+#undef _S1
+#undef _S2
+#undef _C1
+#undef _C2
+
+/** Concatenate non-expanded arguments */
+#define _C1( x, y ) x ## y
+/** Concatenate expanded arguments */
+#define _C2( x, y ) _C1 ( x, y )
+
+/** Stringify non-expanded argument */
+#define _S1( x ) #x
+/** Stringify expanded argument */
+#define _S2( x ) _S1 ( x )
+
+/**
+ * @defgroup symmacros Macros to provide or require explicit symbols
+ * @{
+ */
+
+/** Provide a symbol within this object file */
+#ifdef ASSEMBLY
+#define PROVIDE_SYMBOL( _sym )				\
+	.globl	_sym ;					\
+	.comm	_sym, 0
+#else /* ASSEMBLY */
+#define PROVIDE_SYMBOL( _sym )				\
+	char _sym[0]
+#endif /* ASSEMBLY */
+
+/** Require a symbol within this object file
+ *
+ * The symbol is referenced by a relocation in a discarded section, so
+ * if it is not available at link time the link will fail.
+ */
+#ifdef ASSEMBLY
+#define REQUIRE_SYMBOL( _sym )				\
+	.section ".discard", "a", @progbits ;		\
+	.extern	_sym ;					\
+	.long	_sym ;					\
+	.previous
+#else /* ASSEMBLY */
+#define REQUIRE_SYMBOL( _sym )				\
+	extern char _sym;				\
+	static char * _C2 ( _C2 ( __require_, _sym ), _C2 ( _, __LINE__ ) ) \
+		__attribute__ (( section ( ".discard" ), used )) \
+		= &_sym
+#endif
+
+/** Request that a symbol be available at runtime
+ *
+ * The requested symbol is entered as undefined into the symbol table
+ * for this object, so the linker will pull in other object files as
+ * necessary to satisfy the reference. However, the undefined symbol
+ * is not referenced in any relocations, so the link can still succeed
+ * if no file contains it.
+ *
+ * A symbol passed to this macro may not be referenced anywhere
+ * else in the file. If you want to do that, see IMPORT_SYMBOL().
+ */
+#ifdef ASSEMBLY
+#define REQUEST_SYMBOL( _sym )				\
+	.equ	__need_ ## _sym, _sym
+#else /* ASSEMBLY */
+#define REQUEST_SYMBOL( _sym )				\
+	__asm__ ( ".equ\t__need_" #_sym ", " #_sym )
+#endif /* ASSEMBLY */
+
+/** Set up a symbol to be usable in another file by IMPORT_SYMBOL()
+ *
+ * The symbol must already be marked as global.
+ */
+#define EXPORT_SYMBOL( _sym )	PROVIDE_SYMBOL ( __export_ ## _sym )
+
+/** Make a symbol usable to this file if available at link time
+ *
+ * If no file passed to the linker contains the symbol, it will have
+ * @c NULL value to future uses. Keep in mind that the symbol value is
+ * really the @e address of a variable or function; see the code
+ * snippet below.
+ *
+ * In C using IMPORT_SYMBOL, you must specify the declaration as the
+ * second argument, for instance
+ *
+ * @code
+ *   IMPORT_SYMBOL ( my_func, int my_func ( int arg ) );
+ *   IMPORT_SYMBOL ( my_var, int my_var );
+ *
+ *   void use_imports ( void ) {
+ * 	if ( my_func && &my_var )
+ * 	   my_var = my_func ( my_var );
+ *   }
+ * @endcode
+ *
+ * GCC considers a weak declaration to override a strong one no matter
+ * which comes first, so it is safe to include a header file declaring
+ * the imported symbol normally, but providing the declaration to
+ * IMPORT_SYMBOL is still required.
+ *
+ * If no EXPORT_SYMBOL declaration exists for the imported symbol in
+ * another file, the behavior will be most likely be identical to that
+ * for an unavailable symbol.
+ */
+#ifdef ASSEMBLY
+#define IMPORT_SYMBOL( _sym )				\
+	REQUEST_SYMBOL ( __export_ ## _sym ) ;		\
+	.weak	_sym
+#else /* ASSEMBLY */
+#define IMPORT_SYMBOL( _sym, _decl )			\
+	REQUEST_SYMBOL ( __export_ ## _sym ) ;		\
+	extern _decl __attribute__ (( weak ))
+#endif
+
+/** @} */
+
+/**
+ * @defgroup objmacros Macros to provide or require explicit objects
+ * @{
+ */
+
+#define PREFIX_OBJECT( _prefix ) _C2 ( _prefix, OBJECT )
+#define OBJECT_SYMBOL PREFIX_OBJECT ( obj_ )
+#define REQUEST_EXPANDED( _sym ) REQUEST_SYMBOL ( _sym )
+#define CONFIG_SYMBOL PREFIX_OBJECT ( obj_config_ )
+
+/** Always provide the symbol for the current object (defined by -DOBJECT) */
+PROVIDE_SYMBOL ( OBJECT_SYMBOL );
+
+/** Pull in an object-specific configuration file if available */
+REQUEST_EXPANDED ( CONFIG_SYMBOL );
+
+/** Explicitly require another object */
+#define REQUIRE_OBJECT( _obj ) REQUIRE_SYMBOL ( obj_ ## _obj )
+
+/** Pull in another object if it exists */
+#define REQUEST_OBJECT( _obj ) REQUEST_SYMBOL ( obj_ ## _obj )
+
+/** @} */
+
+/** Select file identifier for errno.h (if used) */
+#define ERRFILE PREFIX_OBJECT ( ERRFILE_ )
+
+#ifndef ASSEMBLY
+
+/** Declare a function as weak (use *before* the definition)
+ *
+ * Due to a bug in at least GCC 4.4.4 and earlier, weak symbols may be
+ * inlined if they have hidden visibility (see above for why hidden
+ * visibility is used).  This results in the non-weak symbol never
+ * being used, so explicitly mark the function as noinline to prevent
+ * inlining.
+ */
+#define __weak		__attribute__ (( weak, noinline ))
+
+/** Prevent a function from being optimized away without inlining
+ *
+ * Calls to functions with void return type that contain no code in their body
+ * may be removed by gcc's optimizer even when inlining is inhibited. Placing
+ * this macro in the body of the function prevents that from occurring.
+ */
+#define __keepme	asm("");
+
+#endif
+
+/** @defgroup dbg Debugging infrastructure
+ * @{
+ */
+
+/** @def DBG
+ *
+ * Print a debugging message.
+ *
+ * The debug level is set at build time by specifying the @c DEBUG=
+ * parameter on the @c make command line.  For example, to enable
+ * debugging for the PCI bus functions (in pci.c) in a @c .dsk image
+ * for the @c rtl8139 card, you could use the command line
+ *
+ * @code
+ *
+ *   make bin/rtl8139.dsk DEBUG=pci
+ *
+ * @endcode
+ *
+ * This will enable the debugging statements (DBG()) in pci.c.  If
+ * debugging is not enabled, DBG() statements will be ignored.
+ *
+ * You can enable debugging in several objects simultaneously by
+ * separating them with commas, as in
+ *
+ * @code
+ *
+ *   make bin/rtl8139.dsk DEBUG=pci,buffer,heap
+ *
+ * @endcode
+ *
+ * You can increase the debugging level for an object by specifying it
+ * with @c :N, where @c N is the level, as in
+ *
+ * @code
+ *
+ *   make bin/rtl8139.dsk DEBUG=pci,buffer:2,heap
+ *
+ * @endcode
+ *
+ * which would enable debugging for the PCI, buffer-handling and
+ * heap-allocation code, with the buffer-handling code at level 2.
+ *
+ */
+
+/*
+ * If debug_OBJECT is set to a true value, the macro DBG(...) will
+ * expand to printf(...) when compiling OBJECT, and the symbol
+ * DEBUG_LEVEL will be inserted into the object file.
+ *
+ */
+#define DEBUG_SYMBOL PREFIX_OBJECT ( debug_ )
+
+#if DEBUG_SYMBOL == 0
+#define NDEBUG
+#endif
+
+#ifndef ASSEMBLY
+
+/** printf() for debugging
+ *
+ * This function exists so that the DBG() macros can expand to
+ * printf() calls without dragging the printf() prototype into scope.
+ *
+ * As far as the compiler is concerned, dbg_printf() and printf() are
+ * completely unrelated calls; it's only at the assembly stage that
+ * references to the dbg_printf symbol are collapsed into references
+ * to the printf symbol.
+ */
+extern int __attribute__ (( format ( printf, 1, 2 ) )) 
+dbg_printf ( const char *fmt, ... ) asm ( "printf" );
+
+extern void dbg_autocolourise ( unsigned long id );
+extern void dbg_decolourise ( void );
+extern void dbg_hex_dump_da ( unsigned long dispaddr,
+			      const void *data, unsigned long len );
+extern void dbg_md5_da ( unsigned long dispaddr,
+			 const void *data, unsigned long len );
+extern void dbg_pause ( void );
+extern void dbg_more ( void );
+
+#if DEBUG_SYMBOL
+#define DBGLVL_MAX DEBUG_SYMBOL
+#else
+#define DBGLVL_MAX 0
+#endif
+
+/* Allow for selective disabling of enabled debug levels */
+#if DBGLVL_MAX
+int __debug_disable;
+#define DBGLVL ( DBGLVL_MAX & ~__debug_disable )
+#define DBG_DISABLE( level ) do {				\
+	__debug_disable |= (level);				\
+	} while ( 0 )
+#define DBG_ENABLE( level ) do {				\
+	__debug_disable &= ~(level);				\
+	} while ( 0 )
+#else
+#define DBGLVL 0
+#define DBG_DISABLE( level ) do { } while ( 0 )
+#define DBG_ENABLE( level ) do { } while ( 0 )
+#endif
+
+#define DBGLVL_LOG	1
+#define DBG_LOG		( DBGLVL & DBGLVL_LOG )
+#define DBGLVL_EXTRA	2
+#define DBG_EXTRA	( DBGLVL & DBGLVL_EXTRA )
+#define DBGLVL_PROFILE	4
+#define DBG_PROFILE	( DBGLVL & DBGLVL_PROFILE )
+#define DBGLVL_IO	8
+#define DBG_IO		( DBGLVL & DBGLVL_IO )
+
+/**
+ * Print debugging message if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v ...		printf() argument list
+ */
+#define DBG_IF( level, ... ) do {				\
+		if ( DBG_ ## level ) {				\
+			dbg_printf ( __VA_ARGS__ );		\
+		}						\
+	} while ( 0 )
+
+/**
+ * Print a hex dump if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v dispaddr		Display address
+ * @v data		Data to print
+ * @v len		Length of data
+ */
+#define DBG_HDA_IF( level, dispaddr, data, len )  do {		\
+		if ( DBG_ ## level ) {				\
+			union {					\
+				unsigned long ul;		\
+				typeof ( dispaddr ) raw;	\
+			} da;					\
+			da.raw = dispaddr;			\
+			dbg_hex_dump_da ( da.ul, data, len );	\
+		}						\
+	} while ( 0 )
+
+/**
+ * Print a hex dump if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v data		Data to print
+ * @v len		Length of data
+ */
+#define DBG_HD_IF( level, data, len ) do {			\
+		const void *_data = data;			\
+		DBG_HDA_IF ( level, _data, _data, len );	\
+	} while ( 0 )
+
+/**
+ * Print an MD5 checksum if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v dispaddr		Display address
+ * @v data		Data to print
+ * @v len		Length of data
+ */
+#define DBG_MD5A_IF( level, dispaddr, data, len )  do {		\
+		if ( DBG_ ## level ) {				\
+			union {					\
+				unsigned long ul;		\
+				typeof ( dispaddr ) raw;	\
+			} da;					\
+			da.raw = dispaddr;			\
+			dbg_md5_da ( da.ul, data, len );	\
+		}						\
+	} while ( 0 )
+
+/**
+ * Print an MD5 checksum if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v data		Data to print
+ * @v len		Length of data
+ */
+#define DBG_MD5_IF( level, data, len ) do {			\
+		const void *_data = data;			\
+		DBG_MD5A_IF ( level, _data, _data, len );	\
+	} while ( 0 )
+
+/**
+ * Prompt for key press if we are at a certain debug level
+ *
+ * @v level		Debug level
+ */
+#define DBG_PAUSE_IF( level ) do {				\
+		if ( DBG_ ## level ) {				\
+			dbg_pause();				\
+		}						\
+	} while ( 0 )
+
+/**
+ * Prompt for more output data if we are at a certain debug level
+ *
+ * @v level		Debug level
+ */
+#define DBG_MORE_IF( level ) do {				\
+		if ( DBG_ ## level ) {				\
+			dbg_more();				\
+		}						\
+	} while ( 0 )
+
+/**
+ * Select colour for debug messages if we are at a certain debug level
+ *
+ * @v level		Debug level
+ * @v id		Message stream ID
+ */
+#define DBG_AC_IF( level, id ) do {				\
+		if ( DBG_ ## level ) {				\
+			union {					\
+				unsigned long ul;		\
+				typeof ( id ) raw;		\
+			} dbg_stream;				\
+			dbg_stream.raw = id;			\
+			dbg_autocolourise ( dbg_stream.ul );	\
+		}						\
+	} while ( 0 )
+
+/**
+ * Revert colour for debug messages if we are at a certain debug level
+ *
+ * @v level		Debug level
+ */
+#define DBG_DC_IF( level ) do {					\
+		if ( DBG_ ## level ) {				\
+			dbg_decolourise();			\
+		}						\
+	} while ( 0 )
+
+/* Autocolourising versions of the DBGxxx_IF() macros */
+
+#define DBGC_IF( level, id, ... ) do {				\
+		DBG_AC_IF ( level, id );			\
+		DBG_IF ( level, __VA_ARGS__ );			\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_HDA_IF( level, id, ... ) do {			\
+		DBG_AC_IF ( level, id );			\
+		DBG_HDA_IF ( level, __VA_ARGS__ );		\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_HD_IF( level, id, ... ) do {			\
+		DBG_AC_IF ( level, id );			\
+		DBG_HD_IF ( level, __VA_ARGS__ );		\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_MD5A_IF( level, id, ... ) do {			\
+		DBG_AC_IF ( level, id );			\
+		DBG_MD5A_IF ( level, __VA_ARGS__ );		\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_MD5_IF( level, id, ... ) do {			\
+		DBG_AC_IF ( level, id );			\
+		DBG_MD5_IF ( level, __VA_ARGS__ );		\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_PAUSE_IF( level, id ) do {				\
+		DBG_AC_IF ( level, id );			\
+		DBG_PAUSE_IF ( level );				\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_MORE_IF( level, id ) do {				\
+		DBG_AC_IF ( level, id );			\
+		DBG_MORE_IF ( level );				\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( LOG, ... )*/
+
+#define DBG( ... )		DBG_IF		( LOG, ##__VA_ARGS__ )
+#define DBG_HDA( ... )		DBG_HDA_IF	( LOG, ##__VA_ARGS__ )
+#define DBG_HD( ... )		DBG_HD_IF	( LOG, ##__VA_ARGS__ )
+#define DBG_MD5A( ... )		DBG_MD5A_IF	( LOG, ##__VA_ARGS__ )
+#define DBG_MD5( ... )		DBG_MD5_IF	( LOG, ##__VA_ARGS__ )
+#define DBG_PAUSE( ... )	DBG_PAUSE_IF	( LOG, ##__VA_ARGS__ )
+#define DBG_MORE( ... )		DBG_MORE_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC( ... )		DBGC_IF		( LOG, ##__VA_ARGS__ )
+#define DBGC_HDA( ... )		DBGC_HDA_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC_HD( ... )		DBGC_HD_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC_MD5A( ... )	DBGC_MD5A_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC_MD5( ... )		DBGC_MD5_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC_PAUSE( ... )	DBGC_PAUSE_IF	( LOG, ##__VA_ARGS__ )
+#define DBGC_MORE( ... )	DBGC_MORE_IF	( LOG, ##__VA_ARGS__ )
+
+/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( EXTRA, ... )*/
+
+#define DBG2( ... )		DBG_IF		( EXTRA, ##__VA_ARGS__ )
+#define DBG2_HDA( ... )		DBG_HDA_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBG2_HD( ... )		DBG_HD_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBG2_MD5A( ... )	DBG_MD5A_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBG2_MD5( ... )		DBG_MD5_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBG2_PAUSE( ... )	DBG_PAUSE_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBG2_MORE( ... )	DBG_MORE_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2( ... )		DBGC_IF		( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_HDA( ... )	DBGC_HDA_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_HD( ... )		DBGC_HD_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_MD5A( ... )	DBGC_MD5A_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_MD5( ... )	DBGC_MD5_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_PAUSE( ... )	DBGC_PAUSE_IF	( EXTRA, ##__VA_ARGS__ )
+#define DBGC2_MORE( ... )	DBGC_MORE_IF	( EXTRA, ##__VA_ARGS__ )
+
+/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( PROFILE, ... )*/
+
+#define DBGP( ... )		DBG_IF		( PROFILE, ##__VA_ARGS__ )
+#define DBGP_HDA( ... )		DBG_HDA_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGP_HD( ... )		DBG_HD_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGP_MD5A( ... )	DBG_MD5A_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGP_MD5( ... )		DBG_MD5_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGP_PAUSE( ... )	DBG_PAUSE_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGP_MORE( ... )	DBG_MORE_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP( ... )		DBGC_IF		( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_HDA( ... )	DBGC_HDA_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_HD( ... )		DBGC_HD_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_MD5A( ... )	DBGC_MD5A_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_MD5( ... )	DBGC_MD5_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_PAUSE( ... )	DBGC_PAUSE_IF	( PROFILE, ##__VA_ARGS__ )
+#define DBGCP_MORE( ... )	DBGC_MORE_IF	( PROFILE, ##__VA_ARGS__ )
+
+/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( IO, ... )*/
+
+#define DBGIO( ... )		DBG_IF		( IO, ##__VA_ARGS__ )
+#define DBGIO_HDA( ... )	DBG_HDA_IF	( IO, ##__VA_ARGS__ )
+#define DBGIO_HD( ... )		DBG_HD_IF	( IO, ##__VA_ARGS__ )
+#define DBGIO_MD5A( ... )	DBG_MD5A_IF	( IO, ##__VA_ARGS__ )
+#define DBGIO_MD5( ... )	DBG_MD5_IF	( IO, ##__VA_ARGS__ )
+#define DBGIO_PAUSE( ... )	DBG_PAUSE_IF	( IO, ##__VA_ARGS__ )
+#define DBGIO_MORE( ... )	DBG_MORE_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO( ... )		DBGC_IF		( IO, ##__VA_ARGS__ )
+#define DBGCIO_HDA( ... )	DBGC_HDA_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO_HD( ... )	DBGC_HD_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO_MD5A( ... )	DBGC_MD5A_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO_MD5( ... )	DBGC_MD5_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO_PAUSE( ... )	DBGC_PAUSE_IF	( IO, ##__VA_ARGS__ )
+#define DBGCIO_MORE( ... )	DBGC_MORE_IF	( IO, ##__VA_ARGS__ )
+
+#endif /* ASSEMBLY */
+/** @} */
+
+/** @defgroup attrs Miscellaneous attributes
+ * @{
+ */
+#ifndef ASSEMBLY
+
+/** Declare a variable or data structure as unused. */
+#define __unused __attribute__ (( unused ))
+
+/**
+ * Declare a function as pure - i.e. without side effects
+ */
+#define __pure __attribute__ (( pure ))
+
+/**
+ * Declare a function as const - i.e. it does not access global memory
+ * (including dereferencing pointers passed to it) at all.
+ * Must also not call any non-const functions.
+ */
+#define __const __attribute__ (( const ))
+
+/**
+ * Declare a function's pointer parameters as non-null - i.e. force
+ * compiler to check pointers at compile time and enable possible
+ * optimizations based on that fact
+ */
+#define __nonnull __attribute__ (( nonnull ))
+
+/**
+ * Declare a pointer returned by a function as a unique memory address
+ * as returned by malloc-type functions.
+ */
+#define __malloc __attribute__ (( malloc ))
+
+/**
+ * Declare a function as used.
+ *
+ * Necessary only if the function is called only from assembler code.
+ */
+#define __used __attribute__ (( used ))
+
+/** Declare a data structure to be aligned with 16-byte alignment */
+#define __aligned __attribute__ (( aligned ( 16 ) ))
+
+/** Declare a function to be always inline */
+#define __always_inline __attribute__ (( always_inline ))
+
+/* Force all inline functions to not be instrumented
+ *
+ * This is required to cope with what seems to be a long-standing gcc
+ * bug, in which -finstrument-functions will cause instances of
+ * inlined functions to be reported as further calls to the
+ * *containing* function.  This makes instrumentation very difficult
+ * to use.
+ *
+ * Work around this problem by adding the no_instrument_function
+ * attribute to all inlined functions.
+ */
+#define inline inline __attribute__ (( no_instrument_function ))
+
+/**
+ * Shared data.
+ *
+ * To save space in the binary when multiple-driver images are
+ * compiled, uninitialised data areas can be shared between drivers.
+ * This will typically be used to share statically-allocated receive
+ * and transmit buffers between drivers.
+ *
+ * Use as e.g.
+ *
+ * @code
+ *
+ *   struct {
+ *	char	rx_buf[NUM_RX_BUF][RX_BUF_SIZE];
+ *	char	tx_buf[TX_BUF_SIZE];
+ *   } my_static_data __shared;
+ *
+ * @endcode
+ *
+ */
+#define __shared __asm__ ( "_shared_bss" ) __aligned
+
+#endif /* ASSEMBLY */
+/** @} */
+
+/**
+ * Optimisation barrier
+ */
+#ifndef ASSEMBLY
+#define barrier() __asm__ __volatile__ ( "" : : : "memory" )
+#endif /* ASSEMBLY */
+
+/**
+ * @defgroup licences Licence declarations
+ *
+ * For reasons that are partly historical, various different files
+ * within the iPXE codebase have differing licences.
+ *
+ * @{
+ */
+
+/** Declare a file as being in the public domain
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be in the public domain.
+ */
+#define FILE_LICENCE_PUBLIC_DOMAIN \
+	PROVIDE_SYMBOL ( __licence_public_domain )
+
+/** Declare a file as being under version 2 (or later) of the GNU GPL
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under the GNU GPL; "either version 2 of the License, or
+ * (at your option) any later version".
+ */
+#define FILE_LICENCE_GPL2_OR_LATER \
+	PROVIDE_SYMBOL ( __licence_gpl2_or_later )
+
+/** Declare a file as being under version 2 of the GNU GPL
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under version 2 of the GPL, and does not include the
+ * "or, at your option, any later version" clause.
+ */
+#define FILE_LICENCE_GPL2_ONLY \
+	PROVIDE_SYMBOL ( __licence_gpl2_only )
+
+/** Declare a file as being under any version of the GNU GPL
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under the GPL, but does not specify a version.
+ *
+ * According to section 9 of the GPLv2, "If the Program does not
+ * specify a version number of this License, you may choose any
+ * version ever published by the Free Software Foundation".
+ */
+#define FILE_LICENCE_GPL_ANY \
+	PROVIDE_SYMBOL ( __licence_gpl_any )
+
+/** Declare a file as being under the three-clause BSD licence
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under terms allowing redistribution in source and
+ * binary forms (with or without modification) provided that:
+ *
+ *     redistributions of source code retain the copyright notice,
+ *     list of conditions and any attached disclaimers
+ *
+ *     redistributions in binary form reproduce the copyright notice,
+ *     list of conditions and any attached disclaimers in the
+ *     documentation and/or other materials provided with the
+ *     distribution
+ *
+ *     the name of the author is not used to endorse or promote
+ *     products derived from the software without specific prior
+ *     written permission
+ *
+ * It is not necessary for the file to explicitly state that it is
+ * under a "BSD" licence; only that the licensing terms be
+ * functionally equivalent to the standard three-clause BSD licence.
+ */
+#define FILE_LICENCE_BSD3 \
+	PROVIDE_SYMBOL ( __licence_bsd3 )
+
+/** Declare a file as being under the two-clause BSD licence
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under terms allowing redistribution in source and
+ * binary forms (with or without modification) provided that:
+ *
+ *     redistributions of source code retain the copyright notice,
+ *     list of conditions and any attached disclaimers
+ *
+ *     redistributions in binary form reproduce the copyright notice,
+ *     list of conditions and any attached disclaimers in the
+ *     documentation and/or other materials provided with the
+ *     distribution
+ *
+ * It is not necessary for the file to explicitly state that it is
+ * under a "BSD" licence; only that the licensing terms be
+ * functionally equivalent to the standard two-clause BSD licence.
+ */
+#define FILE_LICENCE_BSD2 \
+	PROVIDE_SYMBOL ( __licence_bsd2 )
+
+/** Declare a file as being under the one-clause MIT-style licence
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under terms allowing redistribution for any purpose
+ * with or without fee, provided that the copyright notice and
+ * permission notice appear in all copies.
+ */
+#define FILE_LICENCE_MIT \
+	PROVIDE_SYMBOL ( __licence_mit )
+
+/** Declare a particular licence as applying to a file */
+#define FILE_LICENCE( _licence ) FILE_LICENCE_ ## _licence
+
+/** @} */
+
+/* This file itself is under GPLv2-or-later */
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <bits/compiler.h>
+
+#endif /* COMPILER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/cpu.h b/qemu-0.15.x/roms/ipxe/src/include/cpu.h
new file mode 100644
index 0000000..b2c428f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/cpu.h
@@ -0,0 +1,6 @@
+#ifndef CPU_H
+#define CPU_H
+
+#include "bits/cpu.h"
+
+#endif /* CPU_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ctype.h b/qemu-0.15.x/roms/ipxe/src/include/ctype.h
new file mode 100644
index 0000000..9f5127b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ctype.h
@@ -0,0 +1,32 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+/** @file
+ *
+ * Character types
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define isdigit(c)	((c) >= '0' && (c) <= '9')
+#define islower(c)	((c) >= 'a' && (c) <= 'z')
+#define isupper(c)	((c) >= 'A' && (c) <= 'Z')
+#define isxdigit(c)	(isdigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
+
+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;
+}
+
+extern int isspace ( int c );
+
+#endif /* _CTYPE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/curses.h b/qemu-0.15.x/roms/ipxe/src/include/curses.h
new file mode 100644
index 0000000..2069779
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/curses.h
@@ -0,0 +1,755 @@
+#ifndef CURSES_H
+#define CURSES_H
+
+#include <stdint.h>
+#include <stdarg.h>
+
+/** @file
+ *
+ * MuCurses header file
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#undef  ERR
+#define ERR	(-1)
+
+#undef  FALSE
+#define FALSE	(0)
+
+#undef  OK
+#define OK	(0)
+
+#undef  TRUE
+#define TRUE	(1)
+
+typedef int bool;
+typedef uint32_t chtype;
+typedef uint32_t attr_t;
+
+/** Curses SCREEN object */
+typedef struct _curses_screen {
+	/** Current cursor position */
+	unsigned int curs_x, curs_y;
+	/** Current attribute */
+	attr_t attrs;
+
+	void ( *init ) ( struct _curses_screen *scr );
+	void ( *exit ) ( struct _curses_screen *scr );
+	/**
+	 * Move cursor to position specified by x,y coords
+	 *
+	 * @v scr	screen on which to operate
+	 * @v y		Y position
+	 * @v x		X position
+	 */
+	void ( * movetoyx ) ( struct _curses_screen *scr,
+			      unsigned int y, unsigned int x );
+	/**
+	 * Write character to current cursor position
+	 *
+	 * @v scr	screen on which to operate
+	 * @v c		character to be written
+	 */
+	void ( * putc ) ( struct _curses_screen *scr, chtype c );
+	/**
+	 * Pop a character from the keyboard input stream
+	 *
+	 * @v scr	screen on which to operate
+	 * @ret c	popped character
+	 */
+	int ( * getc ) ( struct _curses_screen *scr );
+	/**
+	 * Checks to see whether a character is waiting in the input stream
+	 *
+	 * @v scr	screen on which to operate
+	 * @ret TRUE	character waiting in stream
+	 * @ret FALSE	no character waiting in stream
+	 */
+	bool ( *peek ) ( struct _curses_screen *scr );
+} SCREEN;
+
+/** Curses Window struct */
+typedef struct _curses_window {
+	/** screen with which window associates */
+	SCREEN *scr;
+	/** window attributes */
+	attr_t attrs;
+	/** window origin coordinates */
+	unsigned int ori_x, ori_y;
+	/** window cursor position */
+	unsigned int curs_x, curs_y;
+	/** window dimensions */
+	unsigned int width, height;
+	/** parent window */
+	struct _curses_window *parent;
+	/** windows that share the same parent as this one */
+	//struct list_head siblings;
+	/** windows der'd or sub'd from this one */
+	//struct list_head children;
+} WINDOW;
+
+extern WINDOW _stdscr;
+extern unsigned short _COLS;
+extern unsigned short _LINES;
+
+#define stdscr ( &_stdscr )
+#define COLS _COLS
+#define LINES _LINES
+
+#define MUCURSES_BITS( mask, shift ) (( mask ) << (shift))
+#define CPAIR_SHIFT	8
+#define ATTRS_SHIFT	16
+
+#define WA_DEFAULT	( 0x0000 << ATTRS_SHIFT )
+#define WA_ALTCHARSET	( 0x0001 << ATTRS_SHIFT )
+#define WA_BLINK	( 0x0002 << ATTRS_SHIFT )
+#define WA_BOLD		( 0x0004 << ATTRS_SHIFT )
+#define WA_DIM		( 0x0008 << ATTRS_SHIFT )
+#define WA_INVIS	( 0x0010 << ATTRS_SHIFT )
+#define WA_PROTECT	( 0x0020 << ATTRS_SHIFT )
+#define WA_REVERSE	( 0x0040 << ATTRS_SHIFT )
+#define WA_STANDOUT	( 0x0080 << ATTRS_SHIFT )
+#define WA_UNDERLINE	( 0x0100 << ATTRS_SHIFT )
+#define WA_HORIZONTAL	( 0x0200 << ATTRS_SHIFT )
+#define WA_VERTICAL	( 0x0400 << ATTRS_SHIFT )
+#define WA_LEFT		( 0x0800 << ATTRS_SHIFT )
+#define WA_RIGHT	( 0x1000 << ATTRS_SHIFT )
+#define WA_LOW		( 0x2000 << ATTRS_SHIFT )
+#define WA_TOP		( 0x4000 << ATTRS_SHIFT )
+
+#define A_DEFAULT	WA_DEFAULT
+#define A_ALTCHARSET	WA_ALTCHARSET
+#define A_BLINK		WA_BLINK
+#define A_BOLD		WA_BOLD
+#define A_DIM		WA_DIM
+#define A_INVIS		WA_INVIS
+#define A_PROTECT	WA_PROTECT
+#define A_REVERSE	WA_REVERSE
+#define A_STANDOUT	WA_STANDOUT
+#define A_UNDERLINE	WA_UNDERLINE
+
+#define A_ATTRIBUTES	( 0xffff << ATTRS_SHIFT )
+#define A_CHARTEXT	( 0xff )
+#define A_COLOUR	( 0xff << CPAIR_SHIFT )
+#define A_COLOR		A_COLOUR
+
+#define COLOUR_PAIR(n)	( (n) << CPAIR_SHIFT )
+#define COLOR_PAIR(n)	COLOUR_PAIR(n)
+#define PAIR_NUMBER(attrs) ( ( (attrs) & A_COLOUR ) >> CPAIR_SHIFT )
+
+#define COLOUR_PAIRS	8 /* Arbitrary limit */
+#define COLOR_PAIRS	COLOUR_PAIRS
+
+#define ACS_ULCORNER	'+'
+#define ACS_LLCORNER	'+'
+#define ACS_URCORNER	'+'
+#define ACS_LRCORNER	'+'
+#define ACS_RTEE	'+'
+#define ACS_LTEE	'+'
+#define ACS_BTEE	'+'
+#define ACS_TTEE	'+'
+#define ACS_HLINE	'-'
+#define ACS_VLINE	'|'
+#define ACS_PLUS	'+'
+#define ACS_S1		'-'
+#define ACS_S9		'_'
+#define ACS_DIAMOND	'+'
+#define ACS_CKBOARD	':'
+#define ACS_DEGREE	'\''
+#define ACS_PLMINUS	'#'
+#define ACS_BULLET	'o'
+#define ACS_LARROW	'<'
+#define ACS_RARROW	'>'
+#define ACS_DARROW	'v'
+#define ACS_UARROW	'^'
+#define ACS_BOARD	'#'
+#define ACS_LANTERN	'#'
+#define ACS_BLOCK	'#'
+
+#define COLOUR_BLACK	0
+#define COLOUR_RED	1
+#define COLOUR_GREEN	2
+#define COLOUR_YELLOW	3
+#define COLOUR_BLUE	4
+#define COLOUR_MAGENTA	5
+#define COLOUR_CYAN	6
+#define COLOUR_WHITE	7
+#define COLOURS		7
+
+#define COLOUR_FG	30
+#define COLOUR_BG	40
+#define COLOR_FG	COLOUR_FG
+#define COLOR_BG	COLOUR_BG
+
+#define COLOR_BLACK	COLOUR_BLACK
+#define COLOR_BLUE	COLOUR_BLUE
+#define COLOR_GREEN	COLOUR_GREEN
+#define COLOR_CYAN	COLOUR_CYAN
+#define COLOR_RED	COLOUR_RED
+#define COLOR_MAGENTA	COLOUR_MAGENTA
+#define COLOR_YELLOW	COLOUR_YELLOW
+#define COLOR_WHITE	COLOUR_WHITE
+#define COLORS		COLOURS
+
+/*
+ * KEY code constants are define in ipxe/keys.h
+ */
+#include <ipxe/keys.h>
+
+//extern int addch ( const chtype * );
+//extern int addchnstr ( const chtype *, int );
+//extern int addchstr ( const chtype * );
+//extern int addnstr ( const char *, int );
+//extern int addstr ( const char * );
+//extern int attroff ( int );
+//extern int attron ( int );
+//extern int attrset ( int );
+//extern int attr_get ( attr_t *, short *, void * );
+//extern int attr_off ( attr_t, void * );
+//extern int attr_on ( attr_t, void * );
+//extern int attr_set ( attr_t, short, void * );
+extern int baudrate ( void );
+extern int beep ( void );
+//extern void bkgdset ( chtype );
+/*extern int border ( chtype, chtype, chtype, chtype, chtype, chtype, chtype,
+  chtype );*/
+extern int box ( WINDOW *, chtype, chtype ) __nonnull;
+//extern bool can_change_colour ( void );
+#define can_change_color() can_change_colour()
+extern int cbreak ( void ); 
+//extern int clrtobot ( void );
+//extern int clrtoeol ( void );
+extern int colour_content ( short, short *, short *, short * ) __nonnull;
+#define color_content( c, r, g, b ) colour_content( (c), (r), (g), (b) )
+//extern int colour_set ( short, void * );
+#define color_set( cpno, opts ) colour_set( (cpno), (opts) )
+extern int copywin ( const WINDOW *, WINDOW *, int, int, int, 
+		     int, int, int, int );
+extern int curs_set ( int );
+extern int def_prog_mode ( void );
+extern int def_shell_mode ( void );
+extern int delay_output ( int );
+//extern int delch ( void );
+//extern int deleteln ( void );
+extern void delscreen ( SCREEN * );
+extern int delwin ( WINDOW * ) __nonnull;
+extern WINDOW *derwin ( WINDOW *, int, int, int, int ) __nonnull;
+//extern int doupdate ( void );
+extern WINDOW *dupwin ( WINDOW * ) __nonnull;
+extern int echo ( void );
+extern int echochar ( const chtype );
+extern int endwin ( void );
+extern char erasechar ( void );
+//extern int erase ( void );
+extern void filter ( void );
+extern int flash ( void );
+extern int flushinp ( void );
+extern __pure chtype getbkgd ( WINDOW * ) __nonnull;
+//extern int getch ( void );
+//extern int getnstr ( char *, int );
+//extern int getstr ( char * );
+extern int halfdelay ( int );
+//extern bool has_colors ( void );
+extern bool has_ic ( void );
+extern bool has_il ( void );
+//extern int hline ( chtype, int );
+extern void idcok ( WINDOW *, bool );
+extern int idlok ( WINDOW *, bool );
+//extern void immedok ( WINDOW *, bool );
+//extern chtype inch ( void );
+//extern int inchnstr ( chtype *, int );
+//extern int inchstr ( chtype * );
+extern WINDOW *initscr ( void );
+extern int init_colour ( short, short, short, short );
+#define init_color ( c, r, g, b ) init_colour ( (c), (r), (g), (b) )
+extern int init_pair ( short, short, short );
+//extern int innstr ( char *, int );
+//extern int insch ( chtype );
+//extern int insnstr ( const char *, int );
+//extern int insstr ( const char * );
+//extern int instr ( char * );
+extern int intrflush ( WINDOW *, bool );
+extern bool isendwin ( void );
+//extern bool is_linetouched ( WINDOW *, int );
+//extern bool is_wintouched ( WINDOW * );
+extern char *keyname ( int );
+extern int keypad ( WINDOW *, bool );
+extern char killchar ( void );
+extern int leaveok ( WINDOW *, bool );
+extern char *longname ( void );
+extern int meta ( WINDOW *, bool );
+//extern int move ( int, int );
+//extern int mvaddch ( int, int, const chtype );
+//extern int mvaddchnstr ( int, int, const chtype *, int );
+//extern int mvaddchstr ( int, int, const chtype * );
+//extern int mvaddnstr ( int, int, const char *, int );
+//extern int mvaddstr ( int, int, const char * );
+extern int mvcur ( int, int, int, int );
+//extern int mvdelch ( int, int );
+extern int mvderwin ( WINDOW *, int, int );
+//extern int mvgetch ( int, int );
+//extern int mvgetnstr ( int, int, char *, int );
+//extern int mvgetstr ( int, int, char * );
+//extern int mvhline ( int, int, chtype, int );
+//extern chtype mvinch ( int, int );
+//extern int mvinchnstr ( int, int, chtype *, int );
+//extern int mvinchstr ( int, int, chtype * );
+//extern int mvinnstr ( int, int, char *, int );
+//extern int mvinsch ( int, int, chtype );
+//extern int mvinsnstr ( int, int, const char *, int );
+//extern int mvinsstr ( int, int, const char * );
+//extern int mvinstr ( int, int, char * );
+//extern int mvprintw ( int, int, char *,  ... );
+//extern int mvscanw ( int, int, char *, ... );
+//extern int mvvline ( int, int, chtype, int );
+//extern int mvwaddch ( WINDOW *, int, int, const chtype );
+//extern int mvwaddchnstr ( WINDOW *, int, int, const chtype *, int );
+//extern int mvwaddchstr ( WINDOW *, int, int, const chtype * );
+//extern int mvwaddnstr ( WINDOW *, int, int, const char *, int );
+//extern int mvwaddstr ( WINDOW *, int, int, const char * );
+//extern int mvwdelch ( WINDOW *, int, int );
+//extern int mvwgetch ( WINDOW *, int, int );
+//extern int mvwgetnstr ( WINDOW *, int, int, char *, int );
+//extern int mvwgetstr ( WINDOW *, int, int, char * );
+//extern int mvwhline ( WINDOW *, int, int, chtype, int );
+extern int mvwin ( WINDOW *, int, int ) __nonnull;
+//extern chtype mvwinch ( WINDOW *, int, int );
+//extern int mvwinchnstr ( WINDOW *, int, int, chtype *, int );
+//extern int mvwinchstr ( WINDOW *, int, int, chtype * );
+//extern int mvwinnstr ( WINDOW *, int, int, char *, int );
+//extern int mvwinsch ( WINDOW *, int, int, chtype );
+//extern int mvwinsnstr ( WINDOW *, int, int, const char *, int );
+//extern int mvwinsstr ( WINDOW *, int, int, const char * );
+//extern int mvwinstr ( WINDOW *, int, int, char * );
+//extern int mvwprintw ( WINDOW *, int, int, char *, ... );
+//extern int mvwscanw ( WINDOW *, int, int, char *, ... );
+//extern int mvwvline ( WINDOW *, int, int, chtype, int );
+extern int napms ( int );
+//extern WINDOW *newpad ( int, int );
+extern WINDOW *newwin ( int, int, int, int );
+extern int nl ( void );
+extern int nocbreak ( void );
+extern int nodelay ( WINDOW *, bool );
+extern int noecho ( void );
+extern int nonl ( void );
+extern void noqiflush ( void );
+extern int noraw ( void );
+extern int notimeout ( WINDOW *, bool );
+extern int overlay ( const WINDOW *, WINDOW * );
+extern int overwrite ( const WINDOW *, WINDOW * );
+extern int pair_content ( short, short *, short * ) __nonnull;
+//extern int pechochar ( WINDOW *, chtype );
+//extern int pnoutrefresh ( WINDOW *, int, int, int, int, int, int );
+//extern int prefresh ( WINDOW *, int, int, int, int, int, int );
+extern int printw ( char *, ... );
+extern int putp ( const char * );
+extern void qiflush ( void );
+extern int raw ( void );
+//extern int redrawwin ( WINDOW * );
+//extern int refresh ( void );
+extern int reset_prog_mode ( void );
+extern int reset_shell_mode ( void );
+extern int resetty ( void );
+extern int ripoffline ( int, int  (*) ( WINDOW *, int) );
+extern int savetty ( void );
+//extern int scanw ( char *, ... );
+//extern int scrl ( int );
+//extern int scroll ( WINDOW * );
+//extern int scrollok ( WINDOW *, bool );
+//extern int setscrreg ( int, int );
+extern SCREEN *set_term ( SCREEN * );
+extern int setupterm ( char *, int, int * );
+extern int slk_attr_off ( const attr_t, void * );
+extern int slk_attroff ( const chtype );
+extern int slk_attr_on ( const attr_t, void * );
+extern int slk_attron ( const chtype );
+extern int slk_attr_set ( const attr_t, short, void * );
+extern int slk_attrset ( const chtype );
+extern int slk_clear ( void );
+extern int slk_colour ( short );
+#define slk_color( c ) slk_colour( (c) )
+extern int slk_init ( int );
+extern char *slk_label ( int );
+extern int slk_noutrefresh ( void );
+//extern int slk_refresh ( void );
+extern int slk_restore ( void );
+extern int slk_set ( int, const char *, int ) __nonnull;
+extern int slk_touch ( void );
+extern int standend ( void );
+extern int standout ( void );
+//extern int start_colour ( void );
+#define start_color() start_colour()
+//extern WINDOW *subpad ( WINDOW *, int, int, int, int );
+extern WINDOW *subwin ( WINDOW *, int, int, int, int ) __nonnull;
+extern int syncok ( WINDOW *, bool );
+extern chtype termattrs ( void );
+extern attr_t term_attrs ( void );
+extern char *termname ( void );
+extern int tigetflag ( char * );
+extern int tigetnum ( char * );
+extern char *tigetstr ( char * );
+extern void timeout ( int );
+//extern int touchline ( WINDOW *, int, int );
+//extern int touchwin ( WINDOW * );
+extern char *tparm ( char *, long, long, long, long, long, long, long, long,
+		   long );
+extern int typeahead ( int );
+//extern int ungetch ( int );
+//extern int untouchwin ( WINDOW * );
+extern void use_env ( bool );
+extern int vid_attr ( attr_t, short, void * );
+extern int vidattr ( chtype );
+extern int vid_puts ( attr_t, short, void *, int  ( *) ( int) );
+extern int vidputs ( chtype, int  ( *) ( int) );
+//extern int vline ( chtype, int );
+//extern int vwprintw ( WINDOW *, const char *, va_list );
+extern int vw_printw ( WINDOW *, const char *, va_list ) __nonnull;
+//extern int vwscanw ( WINDOW *, char *, va_list );
+//extern int vw_scanw ( WINDOW *, char *, va_list );
+extern int waddch ( WINDOW *, const chtype ) __nonnull;
+extern int waddchnstr ( WINDOW *, const chtype *, int ) __nonnull;
+//extern int waddchstr ( WINDOW *, const chtype * );
+extern int waddnstr ( WINDOW *, const char *, int ) __nonnull;
+//extern int waddstr ( WINDOW *, const char * );
+extern int wattroff ( WINDOW *, int ) __nonnull;
+extern int wattron ( WINDOW *, int ) __nonnull;
+extern int wattrset ( WINDOW *, int ) __nonnull;
+extern int wattr_get ( WINDOW *, attr_t *, short *, void * )
+	__attribute__ (( nonnull (1, 2, 3)));
+extern int wattr_off ( WINDOW *, attr_t, void * )
+	__attribute__ (( nonnull (1)));
+extern int wattr_on ( WINDOW *, attr_t, void * )
+	__attribute__ (( nonnull (1)));
+extern int wattr_set ( WINDOW *, attr_t, short, void * )
+	__attribute__ (( nonnull (1)));
+//extern void wbkgdset ( WINDOW *, chtype );
+extern int wborder ( WINDOW *, chtype, chtype, chtype, chtype, chtype, chtype,
+		   chtype, chtype ) __nonnull;
+extern int wclrtobot ( WINDOW * ) __nonnull;
+extern int wclrtoeol ( WINDOW * ) __nonnull;
+extern void wcursyncup ( WINDOW * );
+extern int wcolour_set ( WINDOW *, short, void * ) __nonnull;
+#define wcolor_set(w,s,v) wcolour_set((w),(s),(v))
+extern int wdelch ( WINDOW * ) __nonnull;
+extern int wdeleteln ( WINDOW * ) __nonnull;
+extern int wechochar ( WINDOW *, const chtype );
+extern int werase ( WINDOW * ) __nonnull;
+extern int wgetch ( WINDOW * );
+extern int wgetnstr ( WINDOW *, char *, int );
+//extern int wgetstr ( WINDOW *, char * );
+extern int whline ( WINDOW *, chtype, int ) __nonnull;
+//extern chtype winch ( WINDOW * );
+//extern int winchnstr ( WINDOW *, chtype *, int );
+//extern int winchstr ( WINDOW *, chtype * );
+//extern int winnstr ( WINDOW *, char *, int );
+//extern int winsch ( WINDOW *, chtype );
+//extern int winsnstr ( WINDOW *, const char *, int );
+//extern int winsstr ( WINDOW *, const char * );
+//extern int winstr ( WINDOW *, char * );
+extern int wmove ( WINDOW *, int, int );
+//extern int wnoutrefresh ( WINDOW * );
+extern int wprintw ( WINDOW *, const char *, ... ) __nonnull;
+//extern int wredrawln ( WINDOW *, int, int );
+//extern int wrefresh ( WINDOW * );
+//extern int wscanw ( WINDOW *, char *, ... );
+//extern int wscrl ( WINDOW *, int );
+//extern int wsetscrreg ( WINDOW *, int, int );
+//extern int wstandend ( WINDOW * );
+//extern int wstandout ( WINDOW * );
+extern void wsyncup ( WINDOW * );
+extern void wsyncdown ( WINDOW * );
+extern void wtimeout ( WINDOW *, int );
+//extern int wtouchln ( WINDOW *, int, int, int );
+extern int wvline ( WINDOW *, chtype, int ) __nonnull;
+
+/*
+ * There is frankly a ridiculous amount of redundancy within the
+ * curses API - ncurses decided to get around this by using #define
+ * macros, but I've decided to be type-safe and implement them all as
+ * static inlines instead...
+ */
+
+static inline int addch ( const chtype ch ) {
+	return waddch( stdscr, ch );
+}
+
+static inline int addchnstr ( const chtype *chstr, int n ) {
+	return waddchnstr ( stdscr, chstr, n );
+}
+
+static inline int addchstr ( const chtype *chstr ) {
+	return waddchnstr ( stdscr, chstr, -1 );
+}
+
+static inline int addnstr ( const char *str, int n ) {
+	return waddnstr ( stdscr, str, n );
+}
+
+static inline int addstr ( const char *str ) {
+	return waddnstr ( stdscr, str, -1 );
+}
+
+static inline int attroff ( int attrs ) {
+	return wattroff ( stdscr, attrs );
+}
+
+static inline int attron ( int attrs ) {
+	return wattron ( stdscr, attrs );
+}
+
+static inline int attrset ( int attrs ) {
+	return wattrset ( stdscr, attrs );
+}
+
+static inline int attr_get ( attr_t *attrs, short *pair, void *opts ) {
+	return wattr_get ( stdscr, attrs, pair, opts );
+}
+
+static inline int attr_off ( attr_t attrs, void *opts ) {
+	return wattr_off ( stdscr, attrs, opts );
+}
+
+static inline int attr_on ( attr_t attrs, void *opts ) {
+	return wattr_on ( stdscr, attrs, opts );
+}
+
+static inline int attr_set ( attr_t attrs, short cpair, void *opts ) {
+	return wattr_set ( stdscr, attrs, cpair, opts );
+}
+
+static inline void bkgdset ( chtype ch ) {
+	wattrset ( stdscr, ch );
+}
+
+static inline int border ( chtype ls, chtype rs, chtype ts, chtype bs,
+			   chtype tl, chtype tr, chtype bl, chtype br ) {
+	return wborder ( stdscr, ls, rs, ts, bs, tl, tr, bl, br );
+}
+
+static inline bool can_change_colour ( void ) {
+	return FALSE;
+}
+
+static inline int clrtobot ( void ) {
+	return wclrtobot( stdscr );
+}
+
+static inline int clrtoeol ( void ) {
+	return wclrtoeol( stdscr );
+}
+
+static inline int colour_set ( short colour_pair_number, void *opts ) {
+	return wcolour_set ( stdscr, colour_pair_number, opts );
+}
+
+static inline int delch ( void ) {
+	return wdelch ( stdscr );
+}
+
+static inline int deleteln ( void ) {
+	return wdeleteln( stdscr );
+}
+
+static inline int erase ( void ) {
+	return werase ( stdscr );
+}
+
+static inline int getch ( void ) {
+	return wgetch ( stdscr );
+}
+
+static inline int getnstr ( char *str, int n ) {
+	return wgetnstr ( stdscr, str, n );
+}
+
+static inline int getstr ( char *str ) {
+	return wgetnstr ( stdscr, str, -1 );
+}
+
+static inline bool has_colors ( void ) {
+	return TRUE;
+}
+
+static inline int has_key ( int kc __unused ) {
+	return TRUE;
+}
+
+static inline int hline ( chtype ch, int n ) {
+	return whline ( stdscr, ch, n );
+}
+
+static inline int move ( int y, int x ) {
+	return wmove ( stdscr, y, x );
+}
+
+static inline int mvaddch ( int y, int x, const chtype ch ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? waddch( stdscr, ch ) : ERR );
+}
+
+static inline int mvaddchnstr ( int y, int x, const chtype *chstr, int n ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? waddchnstr ( stdscr, chstr, n ) : ERR );
+}
+
+static inline int mvaddchstr ( int y, int x, const chtype *chstr ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? waddchnstr ( stdscr, chstr, -1 ) : ERR );
+}
+
+static inline int mvaddnstr ( int y, int x, const char *str, int n ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? waddnstr ( stdscr, str, n ) : ERR );
+}
+
+static inline int mvaddstr ( int y, int x, const char *str ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? waddnstr ( stdscr, str, -1 ) : ERR );
+}
+
+static inline int mvdelch ( int y, int x ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? wdelch ( stdscr ) : ERR );
+}
+
+static inline int mvgetch ( int y, int x ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? wgetch ( stdscr ) : ERR );
+}
+
+static inline int mvgetnstr ( int y, int x, char *str, int n ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? wgetnstr ( stdscr, str, n ) : ERR );
+}
+
+static inline int mvgetstr ( int y, int x, char *str ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? wgetnstr ( stdscr, str, -1 ) : ERR );
+}
+
+static inline int mvhline ( int y, int x, chtype ch, int n ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? whline ( stdscr, ch, n ) : ERR );
+}
+
+// OK, so maybe a few I did with macros...
+#define mvprintw( y, x, fmt, ... ) \
+	( wmove(stdscr,(y),(x)) == OK \
+	  ? wprintw( stdscr,(fmt), ## __VA_ARGS__ ) : ERR )
+
+static inline int mvvline ( int y, int x, chtype ch, int n ) {
+	return ( wmove ( stdscr, y, x ) == OK
+		 ? wvline ( stdscr, ch, n ) : ERR );
+}
+
+static inline int mvwaddch ( WINDOW *win, int y, int x, const chtype ch ) {
+	return ( wmove( win, y, x ) == OK
+		 ? waddch ( win, ch ) : ERR );
+}
+
+static inline int mvwaddchnstr ( WINDOW *win, int y, int x, const chtype *chstr, int n ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? waddchnstr ( win, chstr, n ) : ERR );
+}
+
+static inline int mvwaddchstr ( WINDOW *win, int y, int x, const chtype *chstr ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? waddchnstr ( win, chstr, -1 ) : ERR );
+}
+
+static inline int mvwaddnstr ( WINDOW *win, int y, int x, const char *str, int n ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? waddnstr ( win, str, n ) : ERR );
+}
+
+static inline int mvwaddstr ( WINDOW *win, int y, int x, const char *str ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? waddnstr ( win, str, -1 ) : ERR );
+}
+
+static inline int mvwdelch ( WINDOW *win, int y, int x ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? wdelch ( win ) : ERR );
+}
+
+static inline int mvwgetch ( WINDOW *win, int y, int x ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? wgetch ( win ) : ERR );
+}
+
+static inline int mvwgetnstr ( WINDOW *win, int y, int x, char *str, int n ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? wgetnstr ( win, str, n ) : ERR );
+}
+
+static inline int mvwgetstr ( WINDOW *win, int y, int x, char *str ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? wgetnstr ( win, str, -1 ) : ERR );
+}
+
+static inline int mvwhline ( WINDOW *win, int y, int x, chtype ch, int n ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? whline ( win, ch, n ) : ERR );
+}
+
+#define mvwprintw( win, y, x, fmt, ... ) \
+	( wmove((win),(y),(x)) == OK \
+	  ? wprintw((win),(fmt), ## __VA_ARGS__) : ERR )
+
+static inline int mvwvline ( WINDOW *win, int y, int x, chtype ch, int n ) {
+	return ( wmove ( win, y, x ) == OK
+		 ? wvline ( win, ch, n ) : ERR );
+}
+
+#define printw( fmt, ... ) wprintw(stdscr,(fmt), ## __VA_ARGS__ )
+
+static inline int slk_refresh ( void ) {
+	if ( slk_clear() == OK )
+		return slk_restore();
+	else
+		return ERR;
+}
+
+#define standend() wstandend( stdscr )
+#define standout() wstandout( stdscr )
+
+static inline int start_colour ( void ) {
+	return OK;
+}
+
+static inline int vline ( chtype ch, int n ) {
+	return wvline ( stdscr, ch, n );
+}
+
+// marked for removal
+static inline int vwprintw ( WINDOW *win, const char *fmt, va_list varglist ) {
+	return vw_printw ( win, fmt, varglist );
+}
+
+static inline int waddchstr ( WINDOW *win, const chtype *chstr ) {
+	return waddchnstr ( win, chstr, -1 );
+}
+
+static inline int waddstr ( WINDOW *win, const char *str ) {
+	return waddnstr ( win, str, -1 );
+}
+
+static inline int wbkgdset ( WINDOW *win, chtype ch ) {
+	return wattrset( win, ch );
+}
+
+static inline int wgetstr ( WINDOW *win, char *str ) {
+	return wgetnstr ( win, str, -1 );
+}
+
+static inline int wstandend ( WINDOW *win ) {
+	return wattrset ( win, A_DEFAULT );
+}
+
+static inline int wstandout ( WINDOW *win ) {
+	return wattrset ( win, A_STANDOUT );
+}
+
+#endif /* CURSES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/elf.h b/qemu-0.15.x/roms/ipxe/src/include/elf.h
new file mode 100644
index 0000000..04022b6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/elf.h
@@ -0,0 +1,234 @@
+#ifndef ELF_H
+#define ELF_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define EI_NIDENT	16	/* Size of e_ident array. */
+
+/* Values for e_type. */
+#define ET_NONE		0	/* No file type */
+#define ET_REL		1	/* Relocatable file */
+#define ET_EXEC		2	/* Executable file */
+#define ET_DYN		3	/* Shared object file */
+#define ET_CORE		4	/* Core file */
+
+/* Values for e_machine (architecute). */
+#define EM_NONE		 0		/* No machine */
+#define EM_M32		 1		/* AT&T WE 32100 */
+#define EM_SPARC	 2		/* SUN SPARC */
+#define EM_386		 3		/* Intel 80386+ */
+#define EM_68K		 4		/* Motorola m68k family */
+#define EM_88K		 5		/* Motorola m88k family */
+#define EM_486		 6		/* Perhaps disused */
+#define EM_860		 7		/* Intel 80860 */
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_S370		 9		/* IBM System/370 */
+#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
+
+#define EM_PARISC	15		/* HPPA */
+#define EM_VPP500	17		/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
+#define EM_960		19		/* Intel 80960 */
+#define EM_PPC		20		/* PowerPC */
+#define EM_PPC64	21		/* PowerPC 64-bit */
+#define EM_S390		22		/* IBM S390 */
+
+#define EM_V800		36		/* NEC V800 series */
+#define EM_FR20		37		/* Fujitsu FR20 */
+#define EM_RH32		38		/* TRW RH-32 */
+#define EM_RCE		39		/* Motorola RCE */
+#define EM_ARM		40		/* ARM */
+#define EM_FAKE_ALPHA	41		/* Digital Alpha */
+#define EM_SH		42		/* Hitachi SH */
+#define EM_SPARCV9	43		/* SPARC v9 64-bit */
+#define EM_TRICORE	44		/* Siemens Tricore */
+#define EM_ARC		45		/* Argonaut RISC Core */
+#define EM_H8_300	46		/* Hitachi H8/300 */
+#define EM_H8_300H	47		/* Hitachi H8/300H */
+#define EM_H8S		48		/* Hitachi H8S */
+#define EM_H8_500	49		/* Hitachi H8/500 */
+#define EM_IA_64	50		/* Intel Merced */
+#define EM_MIPS_X	51		/* Stanford MIPS-X */
+#define EM_COLDFIRE	52		/* Motorola Coldfire */
+#define EM_68HC12	53		/* Motorola M68HC12 */
+#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP		55		/* Siemens PCP */
+#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
+#define EM_NDR1		57		/* Denso NDR1 microprocessor */
+#define EM_STARCORE	58		/* Motorola Start*Core processor */
+#define EM_ME16		59		/* Toyota ME16 processor */
+#define EM_ST100	60		/* STMicroelectronic ST100 processor */
+#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64	62		/* AMD x86-64 architecture */
+#define EM_PDSP		63		/* Sony DSP Processor */
+
+#define EM_FX66		66		/* Siemens FX66 microcontroller */
+#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
+#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
+#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
+#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
+#define EM_SVX		73		/* Silicon Graphics SVx */
+#define EM_AT19		74		/* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX		75		/* Digital VAX */
+#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
+#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY	81		/* Harvard University machine-independent object files */
+#define EM_PRISM	82		/* SiTera Prism */
+#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
+#define EM_FR30		84		/* Fujitsu FR30 */
+#define EM_D10V		85		/* Mitsubishi D10V */
+#define EM_D30V		86		/* Mitsubishi D30V */
+#define EM_V850		87		/* NEC v850 */
+#define EM_M32R		88		/* Mitsubishi M32R */
+#define EM_MN10300	89		/* Matsushita MN10300 */
+#define EM_MN10200	90		/* Matsushita MN10200 */
+#define EM_PJ		91		/* picoJava */
+#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
+#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
+#define EM_NUM		95
+
+/* Values for p_type. */
+#define PT_NULL		0	/* Unused entry. */
+#define PT_LOAD		1	/* Loadable segment. */
+#define PT_DYNAMIC	2	/* Dynamic linking information segment. */
+#define PT_INTERP	3	/* Pathname of interpreter. */
+#define PT_NOTE		4	/* Auxiliary information. */
+#define PT_SHLIB	5	/* Reserved (not used). */
+#define PT_PHDR		6	/* Location of program header itself. */
+
+/* Values for p_flags. */
+#define PF_X		0x1	/* Executable. */
+#define PF_W		0x2	/* Writable. */
+#define PF_R		0x4	/* Readable. */
+
+
+#define	ELF_PROGRAM_RETURNS_BIT	0x8000000	/* e_flags bit 31 */
+
+#define EI_MAG0		0
+#define ELFMAG0		0x7f
+
+#define EI_MAG1		1
+#define ELFMAG1		'E'
+
+#define EI_MAG2		2
+#define ELFMAG2		'L'
+
+#define EI_MAG3		3
+#define ELFMAG3		'F'
+
+#define ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define EI_CLASS	4	/* File class byte index */
+#define ELFCLASSNONE	0	/* Invalid class */
+#define ELFCLASS32	1	/* 32-bit objects */
+#define ELFCLASS64	2	/* 64-bit objects */
+
+#define EI_DATA		5	/* Data encodeing byte index */
+#define ELFDATANONE	0	/* Invalid data encoding */
+#define ELFDATA2LSB	1	/* 2's complement little endian */
+#define ELFDATA2MSB	2	/* 2's complement big endian */
+
+#define EI_VERSION	6	/* File version byte index */
+				/* Value must be EV_CURRENT */
+
+#define EV_NONE		0	/* Invalid ELF Version */
+#define EV_CURRENT	1	/* Current version */
+
+#define ELF32_PHDR_SIZE (8*4)	/* Size of an elf program header */
+
+#ifndef ASSEMBLY
+
+#include <stdint.h>
+
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef uint32_t	Elf32_Addr;
+typedef uint16_t	Elf32_Half;
+typedef uint32_t	Elf32_Off;
+typedef int32_t		Elf32_Sword;
+typedef uint32_t	Elf32_Word;
+typedef uint32_t	Elf32_Size;
+
+typedef uint64_t	Elf64_Addr;
+typedef uint16_t	Elf64_Half;
+typedef uint64_t	Elf64_Off;
+typedef int32_t		Elf64_Sword;
+typedef uint32_t	Elf64_Word;
+typedef uint64_t	Elf64_Size;
+
+/*
+ * ELF header.
+ */
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf32_Half	e_type;		/* File type. */
+	Elf32_Half	e_machine;	/* Machine architecture. */
+	Elf32_Word	e_version;	/* ELF format version. */
+	Elf32_Addr	e_entry;	/* Entry point. */
+	Elf32_Off	e_phoff;	/* Program header file offset. */
+	Elf32_Off	e_shoff;	/* Section header file offset. */
+	Elf32_Word	e_flags;	/* Architecture-specific flags. */
+	Elf32_Half	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf32_Half	e_phentsize;	/* Size of program header entry. */
+	Elf32_Half	e_phnum;	/* Number of program header entries. */
+	Elf32_Half	e_shentsize;	/* Size of section header entry. */
+	Elf32_Half	e_shnum;	/* Number of section header entries. */
+	Elf32_Half	e_shstrndx;	/* Section name strings section. */
+} Elf32_Ehdr;
+
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf64_Half	e_type;		/* File type. */
+	Elf64_Half	e_machine;	/* Machine architecture. */
+	Elf64_Word	e_version;	/* ELF format version. */
+	Elf64_Addr	e_entry;	/* Entry point. */
+	Elf64_Off	e_phoff;	/* Program header file offset. */
+	Elf64_Off	e_shoff;	/* Section header file offset. */
+	Elf64_Word	e_flags;	/* Architecture-specific flags. */
+	Elf64_Half	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf64_Half	e_phentsize;	/* Size of program header entry. */
+	Elf64_Half	e_phnum;	/* Number of program header entries. */
+	Elf64_Half	e_shentsize;	/* Size of section header entry. */
+	Elf64_Half	e_shnum;	/* Number of section header entries. */
+	Elf64_Half	e_shstrndx;	/* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Program header.
+ */
+typedef struct {
+	Elf32_Word	p_type;		/* Entry type. */
+	Elf32_Off	p_offset;	/* File offset of contents. */
+	Elf32_Addr	p_vaddr;	/* Virtual address (not used). */
+	Elf32_Addr	p_paddr;	/* Physical address. */
+	Elf32_Size	p_filesz;	/* Size of contents in file. */
+	Elf32_Size	p_memsz;	/* Size of contents in memory. */
+	Elf32_Word	p_flags;	/* Access permission flags. */
+	Elf32_Size	p_align;	/* Alignment in memory and file. */
+} Elf32_Phdr;
+
+typedef struct {
+	Elf64_Word	p_type;		/* Entry type. */
+	Elf64_Word	p_flags;	/* Access permission flags. */
+	Elf64_Off	p_offset;	/* File offset of contents. */
+	Elf64_Addr	p_vaddr;	/* Virtual address (not used). */
+	Elf64_Addr	p_paddr;	/* Physical address. */
+	Elf64_Size	p_filesz;	/* Size of contents in file. */
+	Elf64_Size	p_memsz;	/* Size of contents in memory. */
+	Elf64_Size	p_align;	/* Alignment in memory and file. */
+} Elf64_Phdr;
+
+/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
+
+#endif /* ASSEMBLY */
+
+#endif /* ELF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/endian.h b/qemu-0.15.x/roms/ipxe/src/include/endian.h
new file mode 100644
index 0000000..9682cf9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/endian.h
@@ -0,0 +1,21 @@
+#ifndef ETHERBOOT_ENDIAN_H
+#define ETHERBOOT_ENDIAN_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* Definitions for byte order, according to significance of bytes,
+   from low addresses to high addresses.  The value is what you get by
+   putting '4' in the most significant byte, '3' in the second most
+   significant byte, '2' in the second least significant byte, and '1'
+   in the least significant byte, and then writing down one digit for
+   each byte, starting with the byte at the lowest address at the left,
+   and proceeding to the byte with the highest address at the right.  */
+
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN    4321
+#define __PDP_ENDIAN    3412
+
+#include "bits/endian.h"
+
+
+#endif /* ETHERBOOT_ENDIAN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/errno.h b/qemu-0.15.x/roms/ipxe/src/include/errno.h
new file mode 100644
index 0000000..a86573f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/errno.h
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef ERRNO_H
+#define ERRNO_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Error codes
+ *
+ * Return status codes as used within iPXE are designed to allow for
+ * maximum visibility into the source of an error even in an end-user
+ * build with no debugging.  They are constructed as follows:
+ *
+ * Bits 7-0 : PXE error code
+ *
+ * This is the closest equivalent PXE error code
+ * (e.g. PXENV_STATUS_OUT_OF_RESOURCES), and is the only part of the
+ * error that will be returned via the PXE API, since PXE has
+ * predefined error codes.
+ *
+ * Bits 12-8 : Per-file disambiguator
+ *
+ * When the same error number can be generated from multiple points
+ * within a file, this field can be used to identify the unique
+ * instance.
+ *
+ * Bits 23-13 : File identifier
+ *
+ * This is a unique identifier for the file generating the error
+ * (e.g. ERRFILE_tcp for tcp.c).
+ *
+ * Bits 30-24 : POSIX error code
+ *
+ * This is the closest equivalent POSIX error code (e.g. ENOMEM).
+ *
+ * Bit 31 : Reserved
+ *
+ * Errors are usually return as negative error numbers (e.g. -EINVAL);
+ * bit 31 is therefore unusable.
+ *
+ *
+ * The convention within the code is that errors are negative and
+ * expressed using the POSIX error, e.g.
+ *
+ *     return -EINVAL;
+ *
+ * By various bits of preprocessor magic, the PXE error code and file
+ * identifier are already incorporated into the definition of the
+ * POSIX error macro, which keeps the code relatively clean.
+ *
+ *
+ * Functions that wish to return failures should be declared as
+ * returning an integer @c rc "Return status code".  A return value of
+ * zero indicates success, a non-zero value indicates failure.  The
+ * return value can be passed directly to strerror() in order to
+ * generate a human-readable error message, e.g.
+ *
+ *     if ( ( rc = some_function ( ... ) ) != 0 ) {
+ *         DBG ( "Whatever I was trying to do failed: %s\n", strerror ( rc ) );
+ *         return rc;
+ *     }
+ *
+ * As illustrated in the above example, error returns should generally
+ * be directly propagated upward to the calling function.
+ *
+ *
+ * Individual files may declare localised errors using
+ * __einfo_uniqify().  For example, iscsi.c declares a localised
+ * version of EACCES for the error of "access denied due to incorrect
+ * target username":
+ *
+ *     #define EACCES_INCORRECT_TARGET_USERNAME	\
+ *         __einfo_error ( EINFO_EACCES_INCORRECT_TARGET_USERNAME )
+ *     #define EINFO_EACCES_INCORRECT_TARGET_USERNAME \
+ *         __einfo_uniqify ( EINFO_EACCESS, 0x01, "Incorrect target username" )
+ *
+ * which can then be used as:
+ *
+ *     return -EACCES_INCORRECT_TARGET_USERNAME;
+ *
+ */
+
+/* Get definitions for file identifiers */
+#include <ipxe/errfile.h>
+
+/* If we do not have a valid file identifier, generate a compiler
+ * warning upon usage of any error codes.  (Don't just use a #warning,
+ * because some files include errno.h but don't ever actually use any
+ * error codes.)
+ */
+#if ! ERRFILE
+extern char missing_errfile_declaration[] __attribute__ (( deprecated ));
+#undef ERRFILE
+#define ERRFILE ( 0 * ( ( int ) missing_errfile_declaration ) )
+#endif
+
+/**
+ * Declare error information
+ *
+ * @v pxe		PXE error number (0x00-0xff)
+ * @v posix		POSIX error number (0x00-0x7f)
+ * @v uniq		Error disambiguator (0x00-0x1f)
+ * @v desc		Error description
+ * @ret einfo		Error information
+ */
+#define __einfo( pxe, posix, uniq, desc ) ( pxe, posix, uniq, desc )
+
+/**
+ * Get PXE error number
+ *
+ * @v einfo		Error information
+ * @ret pxe		PXE error number
+ */
+#define __einfo_pxe( einfo ) __einfo_extract_pxe einfo
+#define __einfo_extract_pxe( pxe, posix, uniq, desc ) pxe
+
+/**
+ * Get POSIX error number
+ *
+ * @v einfo		Error information
+ * @ret posix		POSIX error number
+ */
+#define __einfo_posix( einfo ) __einfo_extract_posix einfo
+#define __einfo_extract_posix( pxe, posix, uniq, desc ) posix
+
+/**
+ * Get error disambiguator
+ *
+ * @v einfo		Error information
+ * @ret uniq		Error disambiguator
+ */
+#define __einfo_uniq( einfo ) __einfo_extract_uniq einfo
+#define __einfo_extract_uniq( pxe, posix, uniq, desc ) uniq
+
+/**
+ * Get error description
+ *
+ * @v einfo		Error information
+ * @ret desc		Error description
+ */
+#define __einfo_desc( einfo ) __einfo_extract_desc einfo
+#define __einfo_extract_desc( pxe, posix, uniq, desc ) desc
+
+/**
+ * Declare disambiguated error
+ *
+ * @v einfo_base	Base error information
+ * @v uniq		Error disambiguator
+ * @v desc		Error description
+ * @ret einfo		Error information
+ */
+#define __einfo_uniqify( einfo_base, uniq, desc )			\
+	__einfo ( __einfo_pxe ( einfo_base ),				\
+		  __einfo_posix ( einfo_base ),				\
+		  uniq, desc )
+
+/**
+ * Get error number
+ *
+ * @v einfo		Error information
+ * @ret errno		Error number
+ */
+#define __einfo_errno( einfo )						\
+	( ( __einfo_posix ( einfo ) << 24 ) | ( ERRFILE ) |		\
+	  ( __einfo_uniq ( einfo ) << 8 ) |				\
+	  ( __einfo_pxe ( einfo ) << 0 ) )
+
+/**
+ * Disambiguate a base error based on non-constant information
+ *
+ * @v error_base	Base error
+ * @v uniq		Error disambiguator
+ * @v ...		List of expected possible disambiguated errors
+ * @ret error		Error
+ *
+ * EUNIQ() should be used when information from an external source is
+ * being incorporated into an error.  For example, the 802.11 stack
+ * uses EUNIQ() to incorporate 802.11 status codes returned by an
+ * access point into an error.
+ *
+ * EUNIQ() should not be used for constant error disambiguators; use
+ * __einfo_uniqify() instead.
+ */
+#define EUNIQ( errno, uniq, ... ) ( {					\
+	euniq_discard ( 0, ##__VA_ARGS__);				\
+	( ( int ) ( (errno) | ( (uniq) << 8 ) ) ); } )
+static inline void euniq_discard ( int dummy __unused, ... ) {}
+
+/**
+ * Declare error
+ *
+ * @v einfo		Error information
+ * @ret error		Error
+ */
+#define __einfo_error( einfo ) ( {					\
+	__asm__ ( ".section \".einfo\", \"\", @progbits\n\t"		\
+		  ".align 8\n\t"					\
+		  "\n1:\n\t"						\
+		  ".long ( 4f - 1b )\n\t"				\
+		  ".long %c0\n\t"					\
+		  ".long ( 2f - 1b )\n\t"				\
+		  ".long ( 3f - 1b )\n\t"				\
+		  ".long %c1\n\t"					\
+		  "\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t"	\
+		  "\n3:\t.asciz \"" __FILE__ "\"\n\t"			\
+		  ".align 8\n\t"					\
+		  "\n4:\n\t"						\
+		  ".previous\n\t" : :					\
+		  "i" ( __einfo_errno ( einfo) ),			\
+		  "i" ( __LINE__ ) );					\
+	__einfo_errno ( einfo ); } )
+
+/**
+ * @defgroup pxeerrors PXE error codes
+ *
+ * The names, meanings and values of these error codes are defined by
+ * the PXE specification.
+ *
+ * @{
+ */
+
+/* Generic errors */
+#define	PXENV_STATUS_SUCCESS					       0x0000
+#define	PXENV_STATUS_FAILURE					       0x0001
+#define	PXENV_STATUS_BAD_FUNC					       0x0002
+#define	PXENV_STATUS_UNSUPPORTED				       0x0003
+#define	PXENV_STATUS_KEEP_UNDI					       0x0004
+#define	PXENV_STATUS_KEEP_ALL					       0x0005
+#define	PXENV_STATUS_OUT_OF_RESOURCES				       0x0006
+
+/* ARP errors (0x0010 to 0x001f) */
+#define	PXENV_STATUS_ARP_TIMEOUT				       0x0011
+
+/* Base-Code state errors */
+#define	PXENV_STATUS_UDP_CLOSED					       0x0018
+#define	PXENV_STATUS_UDP_OPEN					       0x0019
+#define	PXENV_STATUS_TFTP_CLOSED				       0x001a
+#define	PXENV_STATUS_TFTP_OPEN					       0x001b
+
+/* BIOS/system errors (0x0020 to 0x002f) */
+#define	PXENV_STATUS_MCOPY_PROBLEM				       0x0020
+#define	PXENV_STATUS_BIS_INTEGRITY_FAILURE			       0x0021
+#define	PXENV_STATUS_BIS_VALIDATE_FAILURE			       0x0022
+#define	PXENV_STATUS_BIS_INIT_FAILURE				       0x0023
+#define	PXENV_STATUS_BIS_SHUTDOWN_FAILURE			       0x0024
+#define	PXENV_STATUS_BIS_GBOA_FAILURE				       0x0025
+#define	PXENV_STATUS_BIS_FREE_FAILURE				       0x0026
+#define	PXENV_STATUS_BIS_GSI_FAILURE				       0x0027
+#define	PXENV_STATUS_BIS_BAD_CKSUM				       0x0028
+
+/* TFTP/MTFTP errors (0x0030 to 0x003f) */
+#define	PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS			       0x0030
+#define	PXENV_STATUS_TFTP_OPEN_TIMEOUT				       0x0032
+#define	PXENV_STATUS_TFTP_UNKNOWN_OPCODE			       0x0033
+#define	PXENV_STATUS_TFTP_READ_TIMEOUT				       0x0035
+#define	PXENV_STATUS_TFTP_ERROR_OPCODE				       0x0036
+#define	PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION		       0x0038
+#define	PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION		       0x0039
+#define	PXENV_STATUS_TFTP_TOO_MANY_PACKAGES			       0x003a
+#define	PXENV_STATUS_TFTP_FILE_NOT_FOUND			       0x003b
+#define	PXENV_STATUS_TFTP_ACCESS_VIOLATION			       0x003c
+#define	PXENV_STATUS_TFTP_NO_MCAST_ADDRESS			       0x003d
+#define	PXENV_STATUS_TFTP_NO_FILESIZE				       0x003e
+#define	PXENV_STATUS_TFTP_INVALID_PACKET_SIZE			       0x003f
+
+/* Reserved errors 0x0040 to 0x004f) */
+
+/* DHCP/BOOTP errors (0x0050 to 0x005f) */
+#define	PXENV_STATUS_DHCP_TIMEOUT				       0x0051
+#define	PXENV_STATUS_DHCP_NO_IP_ADDRESS				       0x0052
+#define	PXENV_STATUS_DHCP_NO_BOOTFILE_NAME			       0x0053
+#define	PXENV_STATUS_DHCP_BAD_IP_ADDRESS			       0x0054
+
+/* Driver errors (0x0060 to 0x006f) */
+#define	PXENV_STATUS_UNDI_INVALID_FUNCTION			       0x0060
+#define	PXENV_STATUS_UNDI_MEDIATEST_FAILED			       0x0061
+#define	PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST		       0x0062
+#define	PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC			       0x0063
+#define	PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY			       0x0064
+#define	PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA		       0x0065
+#define	PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA			       0x0066
+#define	PXENV_STATUS_UNDI_BAD_MAC_ADDRESS			       0x0067
+#define	PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM			       0x0068
+#define	PXENV_STATUS_UNDI_ERROR_SETTING_ISR			       0x0069
+#define	PXENV_STATUS_UNDI_INVALID_STATE				       0x006a
+#define	PXENV_STATUS_UNDI_TRANSMIT_ERROR			       0x006b
+#define	PXENV_STATUS_UNDI_INVALID_PARAMETER			       0x006c
+
+/* ROM and NBP bootstrap errors (0x0070 to 0x007f) */
+#define	PXENV_STATUS_BSTRAP_PROMPT_MENU				       0x0074
+#define	PXENV_STATUS_BSTRAP_MCAST_ADDR				       0x0076
+#define	PXENV_STATUS_BSTRAP_MISSING_LIST			       0x0077
+#define	PXENV_STATUS_BSTRAP_NO_RESPONSE				       0x0078
+#define	PXENV_STATUS_BSTRAP_FILE_TOO_BIG			       0x0079
+
+/* Environment NBP errors (0x0080 to 0x008f) */
+
+/* Reserved errors (0x0090 to 0x009f) */
+
+/* Miscellaneous errors (0x00a0 to 0x00af) */
+#define	PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE			       0x00a0
+#define	PXENV_STATUS_BINL_NO_PXE_SERVER				       0x00a1
+#define	PXENV_STATUS_NOT_AVAILABLE_IN_PMODE			       0x00a2
+#define	PXENV_STATUS_NOT_AVAILABLE_IN_RMODE			       0x00a3
+
+/* BUSD errors (0x00b0 to 0x00bf) */
+#define	PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED			       0x00b0
+
+/* Loader errors (0x00c0 to 0x00cf) */
+#define	PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY			       0x00c0
+#define	PXENV_STATUS_LOADER_NO_BC_ROMID				       0x00c1
+#define	PXENV_STATUS_LOADER_BAD_BC_ROMID			       0x00c2
+#define	PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE		       0x00c3
+#define	PXENV_STATUS_LOADER_NO_UNDI_ROMID			       0x00c4
+#define	PXENV_STATUS_LOADER_BAD_UNDI_ROMID			       0x00c5
+#define	PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE		       0x00c6
+#define	PXENV_STATUS_LOADER_NO_PXE_STRUCT			       0x00c8
+#define	PXENV_STATUS_LOADER_NO_PXENV_STRUCT			       0x00c9
+#define	PXENV_STATUS_LOADER_UNDI_START				       0x00ca
+#define	PXENV_STATUS_LOADER_BC_START				       0x00cb
+
+/** @} */
+
+/** Derive PXENV_STATUS code from iPXE error number */
+#define PXENV_STATUS( rc ) ( (-(rc)) & 0x00ff )
+
+/**
+ * @defgroup posixerrors POSIX error codes
+ *
+ * The names and meanings (but not the values) of these error codes
+ * are defined by POSIX.
+ *
+ * @{
+ */
+
+/** Operation completed successfully */
+#define ENOERR __einfo_error ( EINFO_ENOERR )
+#define EINFO_ENOERR __einfo ( PXENV_STATUS_SUCCESS, 0x00, 0, \
+			       "Operation completed successfully" )
+
+/** Argument list too long */
+#define E2BIG __einfo_error ( EINFO_E2BIG )
+#define EINFO_E2BIG __einfo ( PXENV_STATUS_BAD_FUNC, 0x01, 0, \
+			      "Argument list too long" )
+
+/** Permission denied */
+#define EACCES __einfo_error ( EINFO_EACCES )
+#define EINFO_EACCES __einfo ( PXENV_STATUS_TFTP_ACCESS_VIOLATION, 0x02, 0, \
+			       "Permission denied" )
+
+/** Address already in use */
+#define EADDRINUSE __einfo_error ( EINFO_EADDRINUSE )
+#define EINFO_EADDRINUSE __einfo ( PXENV_STATUS_UDP_OPEN, 0x03, 0, \
+				   "Address already in use" )
+
+/** Address not available */
+#define EADDRNOTAVAIL __einfo_error ( EINFO_EADDRNOTAVAIL )
+#define EINFO_EADDRNOTAVAIL __einfo ( PXENV_STATUS_UDP_OPEN, 0x04, 0, \
+				      "Address not available" )
+
+/** Address family not supported */
+#define EAFNOSUPPORT __einfo_error ( EINFO_EAFNOSUPPORT )
+#define EINFO_EAFNOSUPPORT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x05, 0, \
+				     "Address family not supported" )
+
+/** Resource temporarily unavailable */
+#define EAGAIN __einfo_error ( EINFO_EAGAIN )
+#define EINFO_EAGAIN __einfo ( PXENV_STATUS_FAILURE, 0x06, 0, \
+			       "Resource temporarily unavailable" )
+
+/** Connection already in progress */
+#define EALREADY __einfo_error ( EINFO_EALREADY )
+#define EINFO_EALREADY __einfo ( PXENV_STATUS_UDP_OPEN, 0x07, 0, \
+				 "Connection already in progress" )
+
+/** Bad file descriptor */
+#define EBADF __einfo_error ( EINFO_EBADF )
+#define EINFO_EBADF __einfo ( PXENV_STATUS_TFTP_CLOSED, 0x08, 0, \
+			      "Bad file descriptor" )
+
+/** Bad message */
+#define EBADMSG __einfo_error ( EINFO_EBADMSG )
+#define EINFO_EBADMSG __einfo ( PXENV_STATUS_FAILURE, 0x09, 0, \
+				"Bad message" )
+
+/** Device or resource busy */
+#define EBUSY __einfo_error ( EINFO_EBUSY )
+#define EINFO_EBUSY __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x0a, 0, \
+			      "Device or resource busy" )
+
+/** Operation canceled */
+#define ECANCELED __einfo_error ( EINFO_ECANCELED )
+#define EINFO_ECANCELED __einfo ( PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE, \
+				  0x0b, 0, "Operation canceled" )
+
+/** No child processes */
+#define ECHILD __einfo_error ( EINFO_ECHILD )
+#define EINFO_ECHILD __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x0c, 0, \
+			       "No child processes" )
+
+/** Connection aborted */
+#define ECONNABORTED __einfo_error ( EINFO_ECONNABORTED )
+#define EINFO_ECONNABORTED						  \
+	__einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, 0x0d, 0, \
+		  "Connection aborted" )
+
+/** Connection refused */
+#define ECONNREFUSED __einfo_error ( EINFO_ECONNREFUSED )
+#define EINFO_ECONNREFUSED __einfo ( PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION, \
+				     0x0e, 0, "Connection refused" )
+
+/** Connection reset */
+#define ECONNRESET __einfo_error ( EINFO_ECONNRESET )
+#define EINFO_ECONNRESET						  \
+	__einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, 0x0f, 0, \
+		  "Connection reset" )
+
+/** Resource deadlock avoided */
+#define EDEADLK __einfo_error ( EINFO_EDEADLK )
+#define EINFO_EDEADLK __einfo ( PXENV_STATUS_FAILURE, 0x10, 0, \
+				"Resource deadlock avoided" )
+
+/** Destination address required */
+#define EDESTADDRREQ __einfo_error ( EINFO_EDESTADDRREQ )
+#define EINFO_EDESTADDRREQ __einfo ( PXENV_STATUS_BAD_FUNC, 0x11, 0, \
+				     "Destination address required" )
+
+/** Mathematics argument out of domain of function */
+#define EDOM __einfo_error ( EINFO_EDOM )
+#define EINFO_EDOM __einfo ( PXENV_STATUS_FAILURE, 0x12, 0, \
+			     "Mathematics argument out of domain of function" )
+
+/** Disk quota exceeded */
+#define EDQUOT __einfo_error ( EINFO_EDQUOT )
+#define EINFO_EDQUOT __einfo ( PXENV_STATUS_FAILURE, 0x13, 0, \
+			       "Disk quote exceeded" )
+
+/** File exists */
+#define EEXIST __einfo_error ( EINFO_EEXIST )
+#define EINFO_EEXIST __einfo ( PXENV_STATUS_FAILURE, 0x14, 0, \
+			       "File exists" )
+
+/** Bad address */
+#define EFAULT __einfo_error ( EINFO_EFAULT )
+#define EINFO_EFAULT __einfo ( PXENV_STATUS_MCOPY_PROBLEM, 0x15, 0, \
+			       "Bad address" )
+
+/** File too large */
+#define EFBIG __einfo_error ( EINFO_EFBIG )
+#define EINFO_EFBIG __einfo ( PXENV_STATUS_MCOPY_PROBLEM, 0x16, 0, \
+			      "File too large" )
+
+/** Host is unreachable */
+#define EHOSTUNREACH __einfo_error ( EINFO_EHOSTUNREACH )
+#define EINFO_EHOSTUNREACH __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x17, 0, \
+				     "Host is unreachable" )
+
+/** Identifier removed */
+#define EIDRM __einfo_error ( EINFO_EIDRM )
+#define EINFO_EIDRM __einfo ( PXENV_STATUS_FAILURE, 0x18, 0, \
+			      "Identifier removed" )
+
+/** Illegal byte sequence */
+#define EILSEQ __einfo_error ( EINFO_EILSEQ )
+#define EINFO_EILSEQ __einfo ( PXENV_STATUS_FAILURE, 0x19, 0, \
+			       "Illegal byte sequence" )
+
+/** Operation in progress */
+#define EINPROGRESS __einfo_error ( EINFO_EINPROGRESS )
+#define EINFO_EINPROGRESS __einfo ( PXENV_STATUS_FAILURE, 0x1a, 0, \
+				    "Operation in progress" )
+
+/** Interrupted function call */
+#define EINTR __einfo_error ( EINFO_EINTR )
+#define EINFO_EINTR __einfo ( PXENV_STATUS_FAILURE, 0x1b, 0, \
+			      "Interrupted function call" )
+
+/** Invalid argument */
+#define EINVAL __einfo_error ( EINFO_EINVAL )
+#define EINFO_EINVAL __einfo ( PXENV_STATUS_BAD_FUNC, 0x1c, 0, \
+			       "Invalid argument" )
+
+/** Input/output error */
+#define EIO __einfo_error ( EINFO_EIO )
+#define EINFO_EIO __einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, \
+			    0x1d, 0, "Input/output error" )
+
+/** Socket is connected */
+#define EISCONN __einfo_error ( EINFO_EISCONN )
+#define EINFO_EISCONN __einfo ( PXENV_STATUS_UDP_OPEN, 0x1e, 0, \
+				"Socket is connected" )
+
+/** Is a directory */
+#define EISDIR __einfo_error ( EINFO_EISDIR )
+#define EINFO_EISDIR __einfo ( PXENV_STATUS_FAILURE, 0x1f, 0, \
+			       "Is a directory" )
+
+/** Too many levels of symbolic links */
+#define ELOOP __einfo_error ( EINFO_ELOOP )
+#define EINFO_ELOOP __einfo ( PXENV_STATUS_FAILURE, 0x20, 0, \
+			      "Too many levels of symbolic links" )
+
+/** Too many open files */
+#define EMFILE __einfo_error ( EINFO_EMFILE )
+#define EINFO_EMFILE __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x21, 0, \
+			       "Too many open files" )
+
+/** Too many links */
+#define EMLINK __einfo_error ( EINFO_EMLINK )
+#define EINFO_EMLINK __einfo ( PXENV_STATUS_FAILURE, 0x22, 0, \
+			       "Too many links" )
+
+/** Message too long */
+#define EMSGSIZE __einfo_error ( EINFO_EMSGSIZE )
+#define EINFO_EMSGSIZE __einfo ( PXENV_STATUS_BAD_FUNC, 0x23, 0, \
+				 "Message too long" )
+
+/** Multihop attempted */
+#define EMULTIHOP __einfo_error ( EINFO_EMULTIHOP )
+#define EINFO_EMULTIHOP __einfo ( PXENV_STATUS_FAILURE, 0x24, 0, \
+				  "Multihop attempted" )
+
+/** Filename too long */
+#define ENAMETOOLONG __einfo_error ( EINFO_ENAMETOOLONG )
+#define EINFO_ENAMETOOLONG __einfo ( PXENV_STATUS_FAILURE, 0x25, 0, \
+				     "Filename too long" )
+
+/** Network is down */
+#define ENETDOWN __einfo_error ( EINFO_ENETDOWN )
+#define EINFO_ENETDOWN __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x26, 0, \
+				 "Network is down" )
+
+/** Connection aborted by network */
+#define ENETRESET __einfo_error ( EINFO_ENETRESET )
+#define EINFO_ENETRESET __einfo ( PXENV_STATUS_FAILURE, 0x27, 0, \
+				  "Connection aborted by network" )
+
+/** Network unreachable */
+#define ENETUNREACH __einfo_error ( EINFO_ENETUNREACH )
+#define EINFO_ENETUNREACH __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x28, 0, \
+				    "Network unreachable" )
+
+/** Too many open files in system */
+#define ENFILE __einfo_error ( EINFO_ENFILE )
+#define EINFO_ENFILE __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x29, 0, \
+			       "Too many open files in system" )
+
+/** No buffer space available */
+#define ENOBUFS __einfo_error ( EINFO_ENOBUFS )
+#define EINFO_ENOBUFS __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x2a, 0, \
+				"No buffer space available" )
+
+/** No message is available on the STREAM head read queue */
+#define ENODATA __einfo_error ( EINFO_ENODATA )
+#define EINFO_ENODATA				 \
+	__einfo ( PXENV_STATUS_FAILURE, 0x2b, 0, \
+		  "No message is available on the STREAM head read queue" )
+
+/** No such device */
+#define ENODEV __einfo_error ( EINFO_ENODEV )
+#define EINFO_ENODEV __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x2c, 0, \
+			       "No such device" )
+
+/** No such file or directory */
+#define ENOENT __einfo_error ( EINFO_ENOENT )
+#define EINFO_ENOENT __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x2d, 0, \
+			       "No such file or directory" )
+
+/** Exec format error */
+#define ENOEXEC __einfo_error ( EINFO_ENOEXEC )
+#define EINFO_ENOEXEC __einfo ( PXENV_STATUS_FAILURE, 0x2e, 0, \
+				"Exec format error" )
+
+/** No locks available */
+#define ENOLCK __einfo_error ( EINFO_ENOLCK )
+#define EINFO_ENOLCK __einfo ( PXENV_STATUS_FAILURE, 0x2f, 0, \
+			       "No locks available" )
+
+/** Link has been severed */
+#define ENOLINK __einfo_error ( EINFO_ENOLINK )
+#define EINFO_ENOLINK __einfo ( PXENV_STATUS_FAILURE, 0x30, 0, \
+				"Link has been severed" )
+
+/** Not enough space */
+#define ENOMEM __einfo_error ( EINFO_ENOMEM )
+#define EINFO_ENOMEM __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x31, 0, \
+			       "Not enough space" )
+
+/** No message of the desired type */
+#define ENOMSG __einfo_error ( EINFO_ENOMSG )
+#define EINFO_ENOMSG __einfo ( PXENV_STATUS_FAILURE, 0x32, 0, \
+			       "No message of the desired type" )
+
+/** Protocol not available */
+#define ENOPROTOOPT __einfo_error ( EINFO_ENOPROTOOPT )
+#define EINFO_ENOPROTOOPT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x33, 0, \
+				    "Protocol not available" )
+
+/** No space left on device */
+#define ENOSPC __einfo_error ( EINFO_ENOSPC )
+#define EINFO_ENOSPC __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x34, 0, \
+			       "No space left on device" )
+
+/** No STREAM resources */
+#define ENOSR __einfo_error ( EINFO_ENOSR )
+#define EINFO_ENOSR __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x35, 0, \
+			      "No STREAM resources" )
+
+/** Not a STREAM */
+#define ENOSTR __einfo_error ( EINFO_ENOSTR )
+#define EINFO_ENOSTR __einfo ( PXENV_STATUS_FAILURE, 0x36, 0, \
+			       "Not a STREAM" )
+
+/** Function not implemented */
+#define ENOSYS __einfo_error ( EINFO_ENOSYS )
+#define EINFO_ENOSYS __einfo ( PXENV_STATUS_UNSUPPORTED, 0x37, 0, \
+			       "Function not implemented" )
+
+/** The socket is not connected */
+#define ENOTCONN __einfo_error ( EINFO_ENOTCONN )
+#define EINFO_ENOTCONN __einfo ( PXENV_STATUS_FAILURE, 0x38, 0, \
+				 "The socket is not connected" )
+
+/** Not a directory */
+#define ENOTDIR __einfo_error ( EINFO_ENOTDIR )
+#define EINFO_ENOTDIR __einfo ( PXENV_STATUS_FAILURE, 0x39, 0, \
+				"Not a directory" )
+
+/** Directory not empty */
+#define ENOTEMPTY __einfo_error ( EINFO_ENOTEMPTY )
+#define EINFO_ENOTEMPTY __einfo ( PXENV_STATUS_FAILURE, 0x3a, 0, \
+				  "Directory not empty" )
+
+/** Not a socket */
+#define ENOTSOCK __einfo_error ( EINFO_ENOTSOCK )
+#define EINFO_ENOTSOCK __einfo ( PXENV_STATUS_FAILURE, 0x3b, 0, \
+				 "Not a socket" )
+
+/** Operation not supported */
+#define ENOTSUP __einfo_error ( EINFO_ENOTSUP )
+#define EINFO_ENOTSUP __einfo ( PXENV_STATUS_UNSUPPORTED, 0x3c, 0, \
+				"Operation not supported" )
+
+/** Inappropriate I/O control operation */
+#define ENOTTY __einfo_error ( EINFO_ENOTTY )
+#define EINFO_ENOTTY __einfo ( PXENV_STATUS_FAILURE, 0x3d, 0, \
+			       "Inappropriate I/O control operation" )
+
+/** No such device or address */
+#define ENXIO __einfo_error ( EINFO_ENXIO )
+#define EINFO_ENXIO __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x3e, 0, \
+			      "No such device or address" )
+
+/** Operation not supported on socket */
+#define EOPNOTSUPP __einfo_error ( EINFO_EOPNOTSUPP )
+#define EINFO_EOPNOTSUPP __einfo ( PXENV_STATUS_UNSUPPORTED, 0x3f, 0, \
+				   "Operation not supported on socket" )
+
+/** Value too large to be stored in data type */
+#define EOVERFLOW __einfo_error ( EINFO_EOVERFLOW )
+#define EINFO_EOVERFLOW __einfo ( PXENV_STATUS_FAILURE, 0x40, 0, \
+				  "Value too large to be stored in data type" )
+
+/** Operation not permitted */
+#define EPERM __einfo_error ( EINFO_EPERM )
+#define EINFO_EPERM __einfo ( PXENV_STATUS_TFTP_ACCESS_VIOLATION, 0x41, 0, \
+			      "Operation not permitted" )
+
+/** Broken pipe */
+#define EPIPE __einfo_error ( EINFO_EPIPE )
+#define EINFO_EPIPE __einfo ( PXENV_STATUS_FAILURE, 0x42, 0, \
+			      "Broken pipe" )
+
+/** Protocol error */
+#define EPROTO __einfo_error ( EINFO_EPROTO )
+#define EINFO_EPROTO __einfo ( PXENV_STATUS_FAILURE, 0x43, 0, \
+			       "Protocol error" )
+
+/** Protocol not supported */
+#define EPROTONOSUPPORT __einfo_error ( EINFO_EPROTONOSUPPORT )
+#define EINFO_EPROTONOSUPPORT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x44, 0, \
+					"Protocol not supported" )
+
+/** Protocol wrong type for socket */
+#define EPROTOTYPE __einfo_error ( EINFO_EPROTOTYPE )
+#define EINFO_EPROTOTYPE __einfo ( PXENV_STATUS_FAILURE, 0x45, 0, \
+				   "Protocol wrong type for socket" )
+
+/** Result too large */
+#define ERANGE __einfo_error ( EINFO_ERANGE )
+#define EINFO_ERANGE __einfo ( PXENV_STATUS_FAILURE, 0x46, 0, \
+			       "Result too large" )
+
+/** Read-only file system */
+#define EROFS __einfo_error ( EINFO_EROFS )
+#define EINFO_EROFS __einfo ( PXENV_STATUS_FAILURE, 0x47, 0, \
+			      "Read-only file system" )
+
+/** Invalid seek */
+#define ESPIPE __einfo_error ( EINFO_ESPIPE )
+#define EINFO_ESPIPE __einfo ( PXENV_STATUS_FAILURE, 0x48, 0, \
+			       "Invalid seek" )
+
+/** No such process */
+#define ESRCH __einfo_error ( EINFO_ESRCH )
+#define EINFO_ESRCH __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x49, 0, \
+			      "No such process" )
+
+/** Stale file handle */
+#define ESTALE __einfo_error ( EINFO_ESTALE )
+#define EINFO_ESTALE __einfo ( PXENV_STATUS_FAILURE, 0x4a, 0, \
+			       "Stale file handle" )
+
+/** Timer expired */
+#define ETIME __einfo_error ( EINFO_ETIME )
+#define EINFO_ETIME __einfo ( PXENV_STATUS_FAILURE, 0x4b, 0, \
+			      "Timer expired" )
+
+/** Connection timed out */
+#define ETIMEDOUT __einfo_error ( EINFO_ETIMEDOUT )
+#define EINFO_ETIMEDOUT __einfo ( PXENV_STATUS_TFTP_READ_TIMEOUT, 0x4c, 0, \
+				  "Connection timed out" )
+
+/** Text file busy */
+#define ETXTBSY __einfo_error ( EINFO_ETXTBSY )
+#define EINFO_ETXTBSY __einfo ( PXENV_STATUS_FAILURE, 0x4d, 0, \
+				"Text file busy" )
+
+/** Operation would block */
+#define EWOULDBLOCK __einfo_error ( EINFO_EWOULDBLOCK )
+#define EINFO_EWOULDBLOCK __einfo ( PXENV_STATUS_TFTP_OPEN, 0x4e, 0, \
+				    "Operation would block" )
+
+/** Improper link */
+#define EXDEV __einfo_error ( EINFO_EXDEV )
+#define EINFO_EXDEV __einfo ( PXENV_STATUS_FAILURE, 0x4f, 0, \
+			      "Improper link" )
+
+/** @} */
+
+extern int errno;
+
+#endif /* ERRNO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/etherboot.h b/qemu-0.15.x/roms/ipxe/src/include/etherboot.h
new file mode 100644
index 0000000..b2fbe4f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/etherboot.h
@@ -0,0 +1,44 @@
+#ifndef ETHERBOOT_H
+#define ETHERBOOT_H
+
+/*
+ * Standard includes that we always want
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <ipxe/console.h>
+#include <ipxe/timer.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/if_ether.h>
+
+typedef unsigned long Address;
+
+/*
+ * IMPORTANT!!!!!!!!!!!!!!
+ *
+ * Everything below this point is cruft left over from older versions
+ * of Etherboot.  Do not add *anything* below this point.  Things are
+ * gradually being moved to individual header files.
+ *
+ */
+
+/* Link configuration time in tenths of a second */
+#ifndef VALID_LINK_TIMEOUT
+#define VALID_LINK_TIMEOUT	100 /* 10.0 seconds */
+#endif
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+
+#endif /* ETHERBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/fs.h b/qemu-0.15.x/roms/ipxe/src/include/fs.h
new file mode 100644
index 0000000..1dfe8fd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/fs.h
@@ -0,0 +1,41 @@
+#ifndef FS_H
+#define FS_H
+
+#include <stdint.h>
+
+//typedef uint64_t sector_t;
+
+#ifdef IDE_DISK
+int ide_probe(int drive);
+int ide_read(int drive, sector_t sector, void *buffer);
+#endif
+
+#ifdef USB_DISK
+int usb_probe(int drive);
+int usb_read(int drive, sector_t sector, void *buffer);
+#endif
+
+#define DISK_IDE 1
+#define DISK_MEM 2
+#define DISK_USB 3
+
+int devopen(const char *name, int *reopen);
+int devread(unsigned long sector, unsigned long byte_offset,
+	unsigned long byte_len, void *buf);
+
+int file_open(const char *filename);
+int file_read(void *buf, unsigned long len);
+int file_seek(unsigned long offset);
+unsigned long file_size(void);
+
+#define PARTITION_UNKNOWN 0xbad6a7
+
+#ifdef ELTORITO
+int open_eltorito_image(int part, unsigned long *start, unsigned long *length);
+#else
+# define open_eltorito_image(x,y,z) PARTITION_UNKNOWN
+#endif
+
+extern int using_devsize;
+
+#endif /* FS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/getopt.h b/qemu-0.15.x/roms/ipxe/src/include/getopt.h
new file mode 100644
index 0000000..0fe4356
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/getopt.h
@@ -0,0 +1,94 @@
+#ifndef _GETOPT_H
+#define _GETOPT_H
+
+/** @file
+ *
+ * Parse command-line options
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+
+enum getopt_argument_requirement {
+	/** Option does not take an argument */
+	no_argument = 0,
+	/** Option requires an argument */
+	required_argument = 1,
+	/** Option may have an argument */
+	optional_argument = 2,
+};
+
+/** A long option, as used for getopt_long() */
+struct option {
+	/** Long name of this option */
+	const char *name;
+	/** Option takes an argument
+	 *
+	 * Must be one of @c no_argument, @c required_argument, or @c
+	 * optional_argument.
+	 */
+	int has_arg;
+	/** Location into which to store @c val, or NULL.
+	 *
+	 * See the description for @c val for more details.
+	 */
+	int *flag;
+	/** Value to return
+	 *
+	 * If @c flag is NULL, then this is the value that will be
+	 * returned by getopt_long() when this option is found, and
+	 * should therefore be set to the equivalent short option
+	 * character.
+	 *
+	 * If @c flag is non-NULL, then this value will be written to
+	 * the location pointed to by @flag, and getopt_long() will
+	 * return 0.
+	 */
+	int val;
+};
+
+extern char *optarg;
+extern int optind;
+extern int nextchar;
+extern int optopt;
+
+extern int getopt_long ( int argc, char * const argv[], const char *optstring,
+			 const struct option *longopts, int *longindex );
+
+/**
+ * Parse command-line options
+ *
+ * @v argv		Argument count
+ * @v argv		Argument list
+ * @v optstring		Option specification string
+ * @ret option		Option found, or -1 for no more options
+ *
+ * See getopt_long() for full details.
+ */
+static inline int getopt ( int argc, char * const argv[],
+			   const char *optstring ) {
+	static const struct option no_options[] = {
+		{ NULL, 0, NULL, 0 }
+	};
+	return getopt_long ( argc, argv, optstring, no_options, NULL );
+}
+
+/**
+ * Reset getopt() internal state
+ *
+ * Due to a limitation of the POSIX getopt() API, it is necessary to
+ * add a call to reset_getopt() before each set of calls to getopt()
+ * or getopt_long().  This arises because POSIX assumes that each
+ * process will parse command line arguments no more than once; this
+ * assumption is not valid within Etherboot.  We work around the
+ * limitation by arranging for execv() to call reset_getopt() before
+ * executing the command.
+ */
+static inline void reset_getopt ( void ) {
+	optind = 1;
+	nextchar = 0;
+}
+
+#endif /* _GETOPT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/hci/ifmgmt_cmd.h b/qemu-0.15.x/roms/ipxe/src/include/hci/ifmgmt_cmd.h
new file mode 100644
index 0000000..a7751cb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/hci/ifmgmt_cmd.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _IFMGMT_CMD_H
+#define _IFMGMT_CMD_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/parseopt.h>
+
+struct net_device;
+
+struct ifcommon_options {};
+
+extern struct option_descriptor ifcommon_opts[0];
+
+extern int ifcommon_exec (  int argc, char **argv,
+			    struct command_descriptor *cmd,
+			    int ( * payload ) ( struct net_device * ),
+			    int stop_on_first_success );
+
+#endif /* _IFMGMT_CMD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/hci/linux_args.h b/qemu-0.15.x/roms/ipxe/src/include/hci/linux_args.h
new file mode 100644
index 0000000..ae1ed05
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/hci/linux_args.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _HCI_LINUX_ARGS_H
+#define _HCI_LINUX_ARGS_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/**
+ * Save argc and argv for later access.
+ *
+ * To be called by linuxprefix
+ */
+extern __asmcall void save_args(int argc, char **argv);
+
+#endif /* _HCI_LINUX_ARGS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/i82365.h b/qemu-0.15.x/roms/ipxe/src/include/i82365.h
new file mode 100644
index 0000000..a6f2b17
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/i82365.h
@@ -0,0 +1,452 @@
+/*
+ * i82365.h 1.15 1999/10/25 20:03:34
+ *
+ * The contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL").
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds at users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT	0x00	/* Identification and revision */
+#define I365_STATUS	0x01	/* Interface status */
+#define I365_POWER	0x02	/* Power and RESETDRV control */
+#define I365_INTCTL	0x03	/* Interrupt and general control */
+#define I365_CSC	0x04	/* Card status change */
+#define I365_CSCINT	0x05	/* Card status change interrupt control */
+#define I365_ADDRWIN	0x06	/* Address window enable */
+#define I365_IOCTL	0x07	/* I/O control */
+#define I365_GENCTL	0x16	/* Card detect and general control */
+#define I365_GBLCTL	0x1E	/* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map)	(0x08+((map)<<2))
+#define I365_MEM(map)	(0x10+((map)<<3))
+#define I365_W_START	0
+#define I365_W_STOP	2
+#define I365_W_OFF	4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1	0x01
+#define I365_CS_STSCHG	0x01
+#define I365_CS_BVD2	0x02
+#define I365_CS_SPKR	0x02
+#define I365_CS_DETECT	0x0C
+#define I365_CS_WRPROT	0x10
+#define I365_CS_READY	0x20	/* Inverted */
+#define I365_CS_POWERON	0x40
+#define I365_CS_GPI	0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF	0x00	/* Turn off the socket */
+#define I365_PWR_OUT	0x80	/* Output enable */
+#define I365_PWR_NORESET 0x40	/* Disable RESETDRV on resume */
+#define I365_PWR_AUTO	0x20	/* Auto pwr switch enable */
+#define I365_VCC_MASK	0x18	/* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+   step has independent Vpp1/Vpp2 control, and the DF step has only
+   Vpp1 control, plus 3V control */
+#define I365_VCC_5V	0x10	/* Vcc = 5.0v */
+#define I365_VCC_3V	0x18	/* Vcc = 3.3v */
+#define I365_VPP2_MASK	0x0c	/* Mask for turning off Vpp2 */
+#define I365_VPP2_5V	0x04	/* Vpp2 = 5.0v */
+#define I365_VPP2_12V	0x08	/* Vpp2 = 12.0v */
+#define I365_VPP1_MASK	0x03	/* Mask for turning off Vpp1 */
+#define I365_VPP1_5V	0x01	/* Vpp2 = 5.0v */
+#define I365_VPP1_12V	0x02	/* Vpp2 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA	0x80
+#define I365_PC_RESET	0x40
+#define I365_PC_IOCARD	0x20
+#define I365_INTR_ENA	0x10
+#define I365_IRQ_MASK	0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1	0x01
+#define I365_CSC_STSCHG	0x01
+#define I365_CSC_BVD2	0x02
+#define I365_CSC_READY	0x04
+#define I365_CSC_DETECT	0x08
+#define I365_CSC_ANY	0x0F
+#define I365_CSC_GPI	0x10
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map)	(0x40 << (map))
+#define I365_ENA_MEM(map)	(0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map)	(0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map)	(0x08 << (map<<2))
+#define I365_IOCTL_0WS(map)	(0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map)	(0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map)	(0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY	0x01
+#define I365_CTL_RESET		0x02
+#define I365_CTL_GPI_ENA	0x04
+#define I365_CTL_GPI_CTL	0x08
+#define I365_CTL_RESUME		0x10
+#define I365_CTL_SW_IRQ		0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN	0x01
+#define I365_GBL_CSC_LEV	0x02
+#define I365_GBL_WRBACK		0x04
+#define I365_GBL_IRQ_0_LEV	0x08
+#define I365_GBL_IRQ_1_LEV	0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT	0x8000	/* In memory start high byte */
+#define I365_MEM_0WS	0x4000
+#define I365_MEM_WS1	0x8000	/* In memory stop high byte */
+#define I365_MEM_WS0	0x4000
+#define I365_MEM_WRPROT	0x8000	/* In offset high byte */
+#define I365_MEM_REG	0x4000
+
+#define I365_REG(slot, reg)	(((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
+
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+// Beginning vg468.h (for VADEM chipset)
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM        0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK         0x0c
+#define VG468_VPP2_5V           0x04
+#define VG468_VPP2_12V          0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE            0x1f    /* Card voltage sense */
+#define VG469_VSELECT           0x2f    /* Card voltage select */
+#define VG468_CTL               0x38    /* Control register */
+#define VG468_TIMER             0x39    /* Timer control */
+#define VG468_MISC              0x3a    /* Miscellaneous */
+#define VG468_GPIO_CFG          0x3b    /* GPIO configuration */
+#define VG469_EXT_MODE          0x3c    /* Extended mode register */
+#define VG468_SELECT            0x3d    /* Programmable chip select */
+#define VG468_SELECT_CFG        0x3e    /* Chip select configuration */
+#define VG468_ATA               0x3f    /* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1      0x01
+#define VG469_VSENSE_A_VS2      0x02
+#define VG469_VSENSE_B_VS1      0x04
+#define VG469_VSENSE_B_VS2      0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC          0x03
+#define VG469_VSEL_5V           0x00
+#define VG469_VSEL_3V           0x03
+#define VG469_VSEL_MAX          0x0c
+#define VG469_VSEL_EXT_STAT     0x10
+#define VG469_VSEL_EXT_BUS      0x20
+#define VG469_VSEL_MIXED        0x40
+#define VG469_VSEL_ISA          0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW          0x01    /* 600ns memory timing */
+#define VG468_CTL_ASYNC         0x02    /* Asynchronous bus clocking */
+#define VG468_CTL_TSSI          0x08    /* Tri-state some outputs */
+#define VG468_CTL_DELAY         0x10    /* Card detect debounce */
+#define VG468_CTL_INPACK        0x20    /* Obey INPACK signal? */
+#define VG468_CTL_POLARITY      0x40    /* VCCEN polarity */
+#define VG468_CTL_COMPAT        0x80    /* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT     0x04    /* Wait state compatibility */
+#define VG469_CTL_STRETCH       0x10    /* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR     0x10    /* Zero power control */
+#define VG468_TIMER_SIGEN       0x20    /* Power up */
+#define VG468_TIMER_STATUS      0x40    /* Activity timer status */
+#define VG468_TIMER_RES         0x80    /* Timer resolution */
+#define VG468_TIMER_MASK        0x0f    /* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO         0x04    /* General-purpose IO */
+#define VG468_MISC_DMAWSB       0x08    /* DMA wait state control */
+#define VG469_MISC_LEDENA       0x10    /* LED enable */
+#define VG468_MISC_VADEMREV     0x40    /* Vadem revision control */
+#define VG468_MISC_UNLOCK       0x80    /* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST        0x03    /* Vpp steering control */
+#define VG469_MODE_INT_SENSE    0x04    /* Internal voltage sense */
+#define VG469_MODE_CABLE        0x08
+#define VG469_MODE_COMPAT       0x10    /* i82365sl B or DF step */
+#define VG469_MODE_TEST         0x20
+#define VG469_MODE_RIO          0x40    /* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V         0x01    /* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
+
+
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+// Beginning ricoh.h (RICOH chipsets)
+
+#ifndef _LINUX_RICOH_H
+#define _LINUX_RICOH_H
+
+
+#define RF5C_MODE_CTL           0x1f    /* Mode control */
+#define RF5C_PWR_CTL            0x2f    /* Mixed voltage control */
+#define RF5C_CHIP_ID            0x3a    /* Chip identification */
+#define RF5C_MODE_CTL_3         0x3b    /* Mode control 3 */
+
+/* I/O window address offset */
+#define RF5C_IO_OFF(w)          (0x36+((w)<<1))
+
+/* Flags for RF5C_MODE_CTL */
+#define RF5C_MODE_ATA           0x01    /* ATA mode */
+#define RF5C_MODE_LED_ENA       0x02    /* IRQ 12 is LED */
+#define RF5C_MODE_CA21          0x04
+#define RF5C_MODE_CA22          0x08
+#define RF5C_MODE_CA23          0x10
+#define RF5C_MODE_CA24          0x20
+#define RF5C_MODE_CA25          0x40
+#define RF5C_MODE_3STATE_BIT7   0x80
+
+/* Flags for RF5C_PWR_CTL */
+#define RF5C_PWR_VCC_3V         0x01
+#define RF5C_PWR_IREQ_HIGH      0x02
+#define RF5C_PWR_INPACK_ENA     0x04
+#define RF5C_PWR_5V_DET         0x08
+#define RF5C_PWR_TC_SEL         0x10    /* Terminal Count: irq 11 or 15 */
+#define RF5C_PWR_DREQ_LOW       0x20
+#define RF5C_PWR_DREQ_OFF       0x00    /* DREQ steering control */
+#define RF5C_PWR_DREQ_INPACK    0x40
+#define RF5C_PWR_DREQ_SPKR      0x80
+#define RF5C_PWR_DREQ_IOIS16    0xc0
+
+/* Values for RF5C_CHIP_ID */
+#define RF5C_CHIP_RF5C296       0x32
+#define RF5C_CHIP_RF5C396       0xb2
+
+/* Flags for RF5C_MODE_CTL_3 */
+#define RF5C_MCTL3_DISABLE      0x01    /* Disable PCMCIA interface */
+#define RF5C_MCTL3_DMA_ENA      0x02
+
+/* Register definitions for Ricoh PCI-to-CardBus bridges */
+
+/* Extra bits in CB_BRIDGE_CONTROL */
+#define RL5C46X_BCR_3E0_ENA             0x0800
+#define RL5C46X_BCR_3E2_ENA             0x1000
+
+/* Bridge Configuration Register */
+#define RL5C4XX_CONFIG                  0x80    /* 16 bit */
+#define  RL5C4XX_CONFIG_IO_1_MODE       0x0200
+#define  RL5C4XX_CONFIG_IO_0_MODE       0x0100
+#define  RL5C4XX_CONFIG_PREFETCH        0x0001
+
+
+/* Misc Control Register */
+#define RL5C4XX_MISC                    0x0082  /* 16 bit */
+#define  RL5C4XX_MISC_HW_SUSPEND_ENA    0x0002
+#define  RL5C4XX_MISC_VCCEN_POL         0x0100
+#define  RL5C4XX_MISC_VPPEN_POL         0x0200
+#define  RL5C46X_MISC_SUSPEND           0x0001
+#define  RL5C46X_MISC_PWR_SAVE_2        0x0004
+#define  RL5C46X_MISC_IFACE_BUSY        0x0008
+#define  RL5C46X_MISC_B_LOCK            0x0010
+#define  RL5C46X_MISC_A_LOCK            0x0020
+#define  RL5C46X_MISC_PCI_LOCK          0x0040
+#define  RL5C47X_MISC_IFACE_BUSY        0x0004
+#define  RL5C47X_MISC_PCI_INT_MASK      0x0018
+#define  RL5C47X_MISC_PCI_INT_DIS       0x0020
+#define  RL5C47X_MISC_SUBSYS_WR         0x0040
+#define  RL5C47X_MISC_SRIRQ_ENA         0x0080
+#define  RL5C47X_MISC_5V_DISABLE        0x0400
+#define  RL5C47X_MISC_LED_POL           0x0800
+
+/* 16-bit Interface Control Register */
+#define RL5C4XX_16BIT_CTL               0x0084  /* 16 bit */
+#define  RL5C4XX_16CTL_IO_TIMING        0x0100
+#define  RL5C4XX_16CTL_MEM_TIMING       0x0200
+#define  RL5C46X_16CTL_LEVEL_1          0x0010
+#define  RL5C46X_16CTL_LEVEL_2          0x0020
+
+/* 16-bit IO and memory timing registers */
+#define RL5C4XX_16BIT_IO_0              0x0088  /* 16 bit */
+#define RL5C4XX_16BIT_MEM_0             0x0088  /* 16 bit */
+#define  RL5C4XX_SETUP_MASK             0x0007
+#define  RL5C4XX_SETUP_SHIFT            0
+#define  RL5C4XX_CMD_MASK               0x01f0
+#define  RL5C4XX_CMD_SHIFT              4
+#define  RL5C4XX_HOLD_MASK              0x1c00
+#define  RL5C4XX_HOLD_SHIFT             10
+#define  RL5C4XX_MISC_CONTROL           0x2F /* 8 bit */
+#define  RL5C4XX_ZV_ENABLE              0x08
+
+#endif /* _LINUX_RICOH_H */
+
+
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+//*****************************************************************************
+// Beginning cirrus.h (CIRRUS chipsets)
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS            0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6729
+#define PCI_DEVICE_ID_CIRRUS_6729       0x1100
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6832
+#define PCI_DEVICE_ID_CIRRUS_6832       0x1110
+#endif
+
+#define PD67_MISC_CTL_1         0x16    /* Misc control 1 */
+#define PD67_FIFO_CTL           0x17    /* FIFO control */
+#define PD67_MISC_CTL_2         0x1E    /* Misc control 2 */
+#define PD67_CHIP_INFO          0x1f    /* Chip information */
+#define PD67_ATA_CTL            0x026   /* 6730: ATA control */
+#define PD67_EXT_INDEX          0x2e    /* Extension index */
+#define PD67_EXT_DATA           0x2f    /* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0         0x01    /* Data mask 0 */
+#define PD67_DATA_MASK1         0x02    /* Data mask 1 */
+#define PD67_DMA_CTL            0x03    /* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1          0x03    /* Extension control 1 */
+#define PD67_MEM_PAGE(n)        ((n)+5) /* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA        0x0a
+#define PD67_MISC_CTL_3         0x25
+#define PD67_SMB_PWR_CTL        0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w)          (0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n)      (0x3a + 3*(n))
+#define PD67_TIME_CMD(n)        (0x3b + 3*(n))
+#define PD67_TIME_RECOV(n)      (0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET         0x01    /* 5v detect */
+#define PD67_MC1_MEDIA_ENA      0x01    /* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V         0x02    /* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT     0x04
+#define PD67_MC1_PULSE_IRQ      0x08
+#define PD67_MC1_SPKR_ENA       0x10
+#define PD67_MC1_INPACK_ENA     0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY         0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS    0x01
+#define PD67_MC2_DYNAMIC_MODE   0x02
+#define PD67_MC2_SUSPEND        0x04
+#define PD67_MC2_5V_CORE        0x08
+#define PD67_MC2_LED_ENA        0x10    /* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI       0x10    /* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7    0x20    /* Floppy change bit */
+#define PD67_MC2_DMA_MODE       0x40
+#define PD67_MC2_IRQ15_RI       0x80    /* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS         0x20    /* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID       0xc0
+#define PD67_INFO_REV           0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE         0xc0
+#define PD67_TIME_SCALE_1       0x00
+#define PD67_TIME_SCALE_16      0x40
+#define PD67_TIME_SCALE_256     0x80
+#define PD67_TIME_SCALE_4096    0xc0
+#define PD67_TIME_MULT          0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE           0xc0
+#define PD67_DMA_OFF            0x00
+#define PD67_DMA_DREQ_INPACK    0x40
+#define PD67_DMA_DREQ_WP        0x80
+#define PD67_DMA_DREQ_BVD2      0xc0
+#define PD67_DMA_PULLUP         0x20    /* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK   0x01
+#define PD67_EC1_AUTO_PWR_CLEAR 0x02
+#define PD67_EC1_LED_ENA        0x04
+#define PD67_EC1_INV_CARD_IRQ   0x08
+#define PD67_EC1_INV_MGMT_IRQ   0x10
+#define PD67_EC1_PULLUP_CTL     0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK       0x03
+#define PD67_MC3_IRQ_PCPCI      0x00
+#define PD67_MC3_IRQ_EXTERN     0x01
+#define PD67_MC3_IRQ_PCIWAY     0x02
+#define PD67_MC3_IRQ_PCI        0x03
+#define PD67_MC3_PWR_MASK       0x0c
+#define PD67_MC3_PWR_SERIAL     0x00
+#define PD67_MC3_PWR_TI2202     0x08
+#define PD67_MC3_PWR_SMB        0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2                  0x0b
+#define PD68_PCI_SPACE                  0x22
+#define PD68_PCCARD_SPACE               0x23
+#define PD68_WINDOW_TYPE                0x24
+#define PD68_EXT_CSC                    0x2e
+#define PD68_MISC_CTL_4                 0x2f
+#define PD68_MISC_CTL_5                 0x30
+#define PD68_MISC_CTL_6                 0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP                0x10
+#define PD68_MC3_MM_EXPAND              0x40
+#define PD68_MC3_MM_ARM                 0x80
+
+/* Bridge Control Register */
+#define  PD6832_BCR_MGMT_IRQ_ENA        0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER            0x004c  /* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
+
+
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/acpi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/acpi.h
new file mode 100644
index 0000000..282b6d9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/acpi.h
@@ -0,0 +1,63 @@
+#ifndef _IPXE_ACPI_H
+#define _IPXE_ACPI_H
+
+/** @file
+ *
+ * ACPI data structures
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/interface.h>
+
+/**
+ * An ACPI description header
+ *
+ * This is the structure common to the start of all ACPI system
+ * description tables.
+ */
+struct acpi_description_header {
+	/** ACPI signature (4 ASCII characters) */
+	uint32_t signature;
+	/** Length of table, in bytes, including header */
+	uint32_t length;
+	/** ACPI Specification minor version number */
+	uint8_t revision;
+	/** To make sum of entire table == 0 */
+	uint8_t checksum;
+	/** OEM identification */
+	char oem_id[6];
+	/** OEM table identification */
+	char oem_table_id[8];
+	/** OEM revision number */
+	uint32_t oem_revision;
+	/** ASL compiler vendor ID */
+	char asl_compiler_id[4];
+	/** ASL compiler revision number */
+	uint32_t asl_compiler_revision;
+} __attribute__ (( packed ));
+
+/**
+ * Build ACPI signature
+ *
+ * @v a			First character of ACPI signature
+ * @v b			Second character of ACPI signature
+ * @v c			Third character of ACPI signature
+ * @v d			Fourth character of ACPI signature
+ * @ret signature	ACPI signature
+ */
+#define ACPI_SIGNATURE( a, b, c, d ) \
+	( ( (a) << 0 ) | ( (b) << 8 ) | ( (c) << 16 ) | ( (d) << 24 ) )
+
+extern int acpi_describe ( struct interface *interface,
+			   struct acpi_description_header *acpi, size_t len );
+#define acpi_describe_TYPE( object_type )				\
+	typeof ( int ( object_type,					\
+		       struct acpi_description_header *acpi,		\
+		       size_t len ) )
+
+extern void acpi_fix_checksum ( struct acpi_description_header *acpi );
+
+#endif /* _IPXE_ACPI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/aes.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/aes.h
new file mode 100644
index 0000000..5d645b2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/aes.h
@@ -0,0 +1,30 @@
+#ifndef _IPXE_AES_H
+#define _IPXE_AES_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct cipher_algorithm;
+
+/** Basic AES blocksize */
+#define AES_BLOCKSIZE 16
+
+#include "crypto/axtls/crypto.h"
+
+/** AES context */
+struct aes_context {
+	/** AES context for AXTLS */
+	AES_CTX axtls_ctx;
+	/** Cipher is being used for decrypting */
+	int decrypting;
+};
+
+/** AES context size */
+#define AES_CTX_SIZE sizeof ( struct aes_context )
+
+extern struct cipher_algorithm aes_algorithm;
+extern struct cipher_algorithm aes_cbc_algorithm;
+
+int aes_wrap ( const void *kek, const void *src, void *dest, int nblk );
+int aes_unwrap ( const void *kek, const void *src, void *dest, int nblk );
+
+#endif /* _IPXE_AES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ansiesc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ansiesc.h
new file mode 100644
index 0000000..35438e4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ansiesc.h
@@ -0,0 +1,120 @@
+#ifndef _IPXE_ANSIESC_H
+#define _IPXE_ANSIESC_H
+
+/** @file
+ *
+ * ANSI escape sequences
+ *
+ * ANSI X3.64 (aka ECMA-48 or ISO/IEC 6429, available from
+ * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf)
+ * defines escape sequences consisting of:
+ *
+ *     A Control Sequence Introducer (CSI)
+ *
+ *     Zero or more Parameter Bytes (P)
+ *
+ *     Zero or more Intermediate Bytes (I)
+ *
+ *     A Final Byte (F)
+ *
+ * The CSI consists of ESC (0x1b) followed by "[" (0x5b).  The
+ * Parameter Bytes, for a standardised (i.e. not private or
+ * experimental) sequence, consist of a list of ASCII decimal integers
+ * separated by semicolons.  The Intermediate Bytes (in the range 0x20
+ * to 0x2f) and the Final Byte (in the range 0x40 to 0x4f) determine
+ * the control function.
+ * 
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A handler for an escape sequence */
+struct ansiesc_handler {
+	/** The control function identifier
+	 *
+	 * The control function identifier consists of the
+	 * Intermediate Bytes (if any) and the Final Byte.  In
+	 * practice, no more than one immediate byte is ever used, so
+	 * the byte combination can be efficiently expressed as a
+	 * single integer, in the obvious way (with the Final Byte
+	 * being the least significant byte).
+	 */
+	unsigned int function;
+	/** Handle escape sequence
+	 *
+	 * @v count		Parameter count
+	 * @v params		Parameter list
+	 *
+	 * A negative parameter value indicates that the parameter was
+	 * omitted and that the default value for this control
+	 * function should be used.
+	 *
+	 * Since all parameters are optional, there is no way to
+	 * distinguish between "zero parameters" and "single parameter
+	 * omitted".  Consequently, the parameter list will always
+	 * contain at least one item.
+	 */
+	void ( * handle ) ( unsigned int count, int params[] );
+};
+
+/** Maximum number of parameters within a single escape sequence */
+#define ANSIESC_MAX_PARAMS 4
+
+/**
+ * ANSI escape sequence context
+ *
+ * This provides temporary storage for processing escape sequences,
+ * and points to the list of escape sequence handlers.
+ */
+struct ansiesc_context {
+	/** Array of handlers
+	 *
+	 * Must be terminated by a handler with @c function set to
+	 * zero.
+	 */
+	struct ansiesc_handler *handlers;
+	/** Parameter count
+	 *
+	 * Will be zero when not currently in an escape sequence.
+	 */
+	unsigned int count;
+	/** Parameter list */ 
+	int params[ANSIESC_MAX_PARAMS];
+	/** Control function identifier */
+	unsigned int function;
+};
+
+/** Escape character */
+#define ESC 0x1b
+
+/** Control Sequence Introducer */
+#define CSI "\033["
+
+/**
+ * @defgroup ansifuncs ANSI escape sequence function identifiers
+ * @{
+ */
+
+/** Cursor position */
+#define ANSIESC_CUP 'H'
+
+/** Erase in page */
+#define ANSIESC_ED 'J'
+
+/** Erase from cursor to end of page */
+#define ANSIESC_ED_TO_END 0
+
+/** Erase from start of page to cursor */
+#define ANSIESC_ED_FROM_START 1
+
+/** Erase whole page */
+#define ANSIESC_ED_ALL 2
+
+/** Select graphic rendition */
+#define ANSIESC_SGR 'm'
+
+/** @} */
+
+extern int ansiesc_process ( struct ansiesc_context *ctx, int c );
+
+#endif /* _IPXE_ANSIESC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/aoe.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/aoe.h
new file mode 100644
index 0000000..60f3bd9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/aoe.h
@@ -0,0 +1,131 @@
+#ifndef _IPXE_AOE_H
+#define _IPXE_AOE_H
+
+/** @file
+ *
+ * AoE protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/retry.h>
+#include <ipxe/ata.h>
+#include <ipxe/acpi.h>
+
+/** An AoE config command */
+struct aoecfg {
+	/** AoE queue depth */
+	uint16_t bufcnt;
+	/** ATA target firmware version */
+	uint16_t fwver;
+	/** ATA target sector count */
+	uint8_t scnt;
+	/** AoE config string subcommand */
+	uint8_t aoeccmd;
+	/** AoE config string length */
+	uint16_t cfglen;
+	/** AoE config string */
+	uint8_t data[0];
+} __attribute__ (( packed ));
+
+/** An AoE ATA command */
+struct aoeata {
+	/** AoE command flags */
+	uint8_t aflags;
+	/** ATA error/feature register */
+	uint8_t err_feat;
+	/** ATA sector count register */
+	uint8_t count;
+	/** ATA command/status register */
+	uint8_t cmd_stat;
+	/** Logical block address, in little-endian order */
+	union {
+		uint64_t u64;
+		uint8_t bytes[6];
+	} lba;
+	/** Data payload */
+	uint8_t data[0];
+} __attribute__ (( packed ));
+
+#define AOE_FL_EXTENDED	0x40	/**< LBA48 extended addressing */
+#define AOE_FL_DEV_HEAD	0x10	/**< Device/head flag */
+#define AOE_FL_ASYNC	0x02	/**< Asynchronous write */
+#define AOE_FL_WRITE	0x01	/**< Write command */
+
+/** An AoE command */
+union aoecmd {
+	/** Config command */
+	struct aoecfg cfg;
+	/** ATA command */
+	struct aoeata ata;
+};
+
+/** An AoE header */
+struct aoehdr {
+	/** Protocol version number and flags */
+	uint8_t ver_flags;
+	/** Error code */
+	uint8_t error;
+	/** Major device number, in network byte order */
+	uint16_t major;
+	/** Minor device number */
+	uint8_t minor;
+	/** Command number */
+	uint8_t command;
+	/** Tag, in network byte order */
+	uint32_t tag;
+	/** Payload */
+	union aoecmd payload[0];
+} __attribute__ (( packed ));
+
+#define AOE_VERSION	0x10	/**< Version 1 */
+#define AOE_VERSION_MASK 0xf0	/**< Version part of ver_flags field */
+
+#define AOE_FL_RESPONSE	0x08	/**< Message is a response */
+#define AOE_FL_ERROR	0x04	/**< Command generated an error */
+
+#define AOE_MAJOR_BROADCAST 0xffff
+#define AOE_MINOR_BROADCAST 0xff
+
+#define AOE_CMD_ATA	0x00	/**< Issue ATA command */
+#define AOE_CMD_CONFIG	0x01	/**< Query Config Information */
+
+#define AOE_ERR_BAD_COMMAND	1 /**< Unrecognised command code */
+#define AOE_ERR_BAD_PARAMETER	2 /**< Bad argument parameter */
+#define AOE_ERR_UNAVAILABLE	3 /**< Device unavailable */
+#define AOE_ERR_CONFIG_EXISTS	4 /**< Config string present */
+#define AOE_ERR_BAD_VERSION	5 /**< Unsupported version */
+
+#define AOE_STATUS_ERR_MASK	0x0f /**< Error portion of status code */ 
+#define AOE_STATUS_PENDING	0x80 /**< Command pending */
+
+/** AoE tag magic marker */
+#define AOE_TAG_MAGIC 0x18ae0000
+
+/** Maximum number of sectors per packet */
+#define AOE_MAX_COUNT 2
+
+/** AoE boot firmware table signature */
+#define ABFT_SIG ACPI_SIGNATURE ( 'a', 'B', 'F', 'T' )
+
+/**
+ * AoE Boot Firmware Table (aBFT)
+ */
+struct abft_table {
+	/** ACPI header */
+	struct acpi_description_header acpi;
+	/** AoE shelf */
+	uint16_t shelf;
+	/** AoE slot */
+	uint8_t slot;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** MAC address */
+	uint8_t mac[ETH_ALEN];
+} __attribute__ (( packed ));
+
+#endif /* _IPXE_AOE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/api.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/api.h
new file mode 100644
index 0000000..838b893
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/api.h
@@ -0,0 +1,84 @@
+#ifndef _IPXE_API_H
+#define _IPXE_API_H
+
+/** @file
+ *
+ * iPXE internal APIs
+ *
+ * There are various formally-defined APIs internal to iPXE, with
+ * several differing implementations specific to particular execution
+ * environments (e.g. PC BIOS, EFI, LinuxBIOS).
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @defgroup Single-implementation APIs
+ *
+ * These are APIs for which only a single implementation may be
+ * compiled in at any given time.
+ *
+ * @{
+ */
+
+/**
+ * Calculate function implementation name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ *
+ * The subsystem prefix should be an empty string for the currently
+ * selected subsystem, and should be a subsystem-unique string for all
+ * other subsystems.
+ */
+#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func
+
+/**
+ * Calculate static inline function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define SINGLE_API_INLINE( _prefix, _api_func )	\
+	SINGLE_API_NAME ( _prefix, _api_func )
+
+/**
+ * Provide an API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_SINGLE_API( _prefix, _api_func, _func )			      \
+	/* Ensure that _api_func exists */				      \
+	typeof ( _api_func ) _api_func;					      \
+	/* Ensure that _func exists */					      \
+	typeof ( _func ) _func;						      \
+	/* Ensure that _func is type-compatible with _api_func */	      \
+	typeof ( _api_func ) _func;					      \
+	/* Ensure that _subsys_func is non-static */			      \
+	extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func );   \
+	/* Provide symbol alias from _subsys_func to _func */		      \
+	typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func )	      \
+		__attribute__ (( alias ( #_func ) ));
+
+/**
+ * Provide a static inline API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func )			      \
+	/* Ensure that _api_func exists */				      \
+	typeof ( _api_func ) _api_func;					      \
+	/* Ensure that _subsys_func exists and is static */		      \
+	static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) )	      \
+		SINGLE_API_INLINE ( _prefix, _api_func );		      \
+	/* Ensure that _subsys_func is type-compatible with _api_func */      \
+	typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func );
+
+/** @} */
+
+#endif /* _IPXE_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/arc4.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/arc4.h
new file mode 100644
index 0000000..9da972b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/arc4.h
@@ -0,0 +1,22 @@
+#ifndef _IPXE_ARC4_H
+#define _IPXE_ARC4_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct cipher_algorithm;
+
+#include <stdint.h>
+
+struct arc4_ctx {
+	int i, j;
+	u8 state[256];
+};
+
+#define ARC4_CTX_SIZE sizeof ( struct arc4_ctx )
+
+extern struct cipher_algorithm arc4_algorithm;
+
+void arc4_skip ( const void *key, size_t keylen, size_t skip,
+		 const void *src, void *dst, size_t msglen );
+
+#endif /* _IPXE_ARC4_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/arp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/arp.h
new file mode 100644
index 0000000..f7b99c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/arp.h
@@ -0,0 +1,44 @@
+#ifndef _IPXE_ARP_H
+#define _IPXE_ARP_H
+
+/** @file
+ *
+ * Address Resolution Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+#include <ipxe/netdevice.h>
+
+/** A network-layer protocol that relies upon ARP */
+struct arp_net_protocol {
+	/** Network-layer protocol */
+	struct net_protocol *net_protocol;
+	/** Check existence of address
+	 *
+	 * @v netdev	Network device
+	 * @v net_addr	Network-layer address
+	 * @ret rc	Return status code
+	 */
+	int ( * check ) ( struct net_device *netdev,
+			  const void *net_addr );
+};
+
+/** ARP protocol table */
+#define ARP_NET_PROTOCOLS \
+	__table ( struct arp_net_protocol, "arp_net_protocols" )
+
+/** Declare an ARP protocol */
+#define __arp_net_protocol __table_entry ( ARP_NET_PROTOCOLS, 01 )
+
+extern struct net_protocol arp_protocol __net_protocol;
+
+extern int arp_resolve ( struct net_device *netdev,
+			 struct net_protocol *net_protocol,
+			 const void *dest_net_addr,
+			 const void *source_net_addr,
+			 void *dest_ll_addr );
+
+#endif /* _IPXE_ARP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/asn1.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/asn1.h
new file mode 100644
index 0000000..85e480e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/asn1.h
@@ -0,0 +1,34 @@
+#ifndef _IPXE_ASN1_H
+#define _IPXE_ASN1_H
+
+/** @file
+ *
+ * ASN.1 encoding
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define ASN1_INTEGER 0x02
+#define ASN1_BIT_STRING 0x03
+#define ASN1_OCTET_STRING 0x04
+#define ASN1_NULL 0x05
+#define ASN1_OID 0x06
+#define ASN1_SEQUENCE 0x30
+#define ASN1_IP_ADDRESS 0x40
+#define ASN1_EXPLICIT_TAG 0xa0
+
+/**
+ * A DER-encoded ASN.1 object cursor
+ */
+struct asn1_cursor {
+	/** Start of data */
+	void *data;
+	/** Length of data */
+	size_t len;
+};
+
+extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
+
+#endif /* _IPXE_ASN1_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ata.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ata.h
new file mode 100644
index 0000000..b7f02d6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ata.h
@@ -0,0 +1,204 @@
+#ifndef _IPXE_ATA_H
+#define _IPXE_ATA_H
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/interface.h>
+
+/** @file
+ *
+ * ATA devices
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * An ATA Logical Block Address
+ *
+ * ATA controllers have three byte-wide registers for specifying the
+ * block address: LBA Low, LBA Mid and LBA High.  This allows for a
+ * 24-bit address.  Some devices support the "48-bit address feature
+ * set" (LBA48), in which case each of these byte-wide registers is
+ * actually a two-entry FIFO, and the "previous" byte pushed into the
+ * FIFO is used as the corresponding high-order byte.  So, to set up
+ * the 48-bit address 0x123456abcdef, you would issue
+ *
+ *     0x56 -> LBA Low register
+ *     0xef -> LBA Low register
+ *     0x34 -> LBA Mid register
+ *     0xcd -> LBA Mid register
+ *     0x12 -> LBA High register
+ *     0xab -> LBA High register
+ *
+ * This structure encapsulates this information by providing a single
+ * 64-bit integer in native byte order, unioned with bytes named so
+ * that the sequence becomes
+ *
+ *     low_prev  -> LBA Low register
+ *     low_cur   -> LBA Low register
+ *     mid_prev  -> LBA Mid register
+ *     mid_cur   -> LBA Mid register
+ *     high_prev -> LBA High register
+ *     high_cur  -> LBA High register
+ *
+ * Just to complicate matters further, in non-LBA48 mode it is
+ * possible to have a 28-bit address, in which case bits 27:24 must be
+ * written into the low four bits of the Device register.
+ */
+union ata_lba {
+	/** LBA as a 64-bit integer in native-endian order */
+	uint64_t native;
+	/** ATA registers */
+	struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		uint8_t low_cur;
+		uint8_t mid_cur;
+		uint8_t high_cur;
+		uint8_t low_prev;
+		uint8_t mid_prev;
+		uint8_t high_prev;
+		uint16_t pad;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+		uint16_t pad;
+		uint8_t high_prev;
+		uint8_t mid_prev;
+		uint8_t low_prev;
+		uint8_t high_cur;
+		uint8_t mid_cur;
+		uint8_t low_cur;
+#else
+#error "I need a byte order"
+#endif
+	} bytes;
+};
+
+/** An ATA 2-byte FIFO register */
+union ata_fifo {
+	/** Value in native-endian order */
+	uint16_t native;
+	/** ATA registers */
+	struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		uint8_t cur;
+		uint8_t prev;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+		uint8_t prev;
+		uint8_t cur;
+#else
+#error "I need a byte order"
+#endif
+	} bytes;
+};
+
+/** ATA command block */
+struct ata_cb {
+	/** Logical block address */
+	union ata_lba lba;
+	/** Sector count */
+	union ata_fifo count;
+	/** Error/feature register */
+	union ata_fifo err_feat;
+	/** Device register */
+	uint8_t device;
+	/** Command/status register */
+	uint8_t cmd_stat;
+	/** Use LBA48 extended addressing */
+	int lba48;
+};
+
+/** Obsolete bits in the ATA device register */
+#define ATA_DEV_OBSOLETE 0xa0
+
+/** LBA flag in the ATA device register */
+#define ATA_DEV_LBA 0x40
+
+/** Slave ("device 1") flag in the ATA device register */
+#define ATA_DEV_SLAVE 0x10
+
+/** Master ("device 0") flag in the ATA device register */
+#define ATA_DEV_MASTER 0x00
+
+/** Mask of non-LBA portion of device register */
+#define ATA_DEV_MASK 0xf0
+
+/** "Read sectors" command */
+#define ATA_CMD_READ 0x20
+
+/** "Read sectors (ext)" command */
+#define ATA_CMD_READ_EXT 0x24
+
+/** "Write sectors" command */
+#define ATA_CMD_WRITE 0x30
+
+/** "Write sectors (ext)" command */
+#define ATA_CMD_WRITE_EXT 0x34
+
+/** "Identify" command */
+#define ATA_CMD_IDENTIFY 0xec
+
+/** Command completed in error */
+#define ATA_STAT_ERR 0x01
+
+/**
+ * Structure returned by ATA IDENTIFY command
+ *
+ * This is a huge structure with many fields that we don't care about,
+ * so we implement only a few fields.
+ */
+struct ata_identity {
+	uint16_t ignore_a[27]; /* words 0-26 */
+	uint16_t model[20]; /* words 27-46 */
+	uint16_t ignore_b[13]; /* words 47-59 */
+	uint32_t lba_sectors; /* words 60-61 */
+	uint16_t ignore_c[21]; /* words 62-82 */
+	uint16_t supports_lba48; /* word 83 */
+	uint16_t ignore_d[16]; /* words 84-99 */
+	uint64_t lba48_sectors; /* words 100-103 */
+	uint16_t ignore_e[152]; /* words 104-255 */
+};
+
+/** Supports LBA48 flag */
+#define ATA_SUPPORTS_LBA48 ( 1 << 10 )
+
+/** ATA sector size */
+#define ATA_SECTOR_SIZE 512
+
+/** An ATA command information unit */
+struct ata_cmd {
+	/** ATA command block */
+	struct ata_cb cb;
+	/** Data-out buffer (may be NULL)
+	 *
+	 * If non-NULL, this buffer must be ata_command::cb::count
+	 * sectors in size.
+	 */
+	userptr_t data_out;
+	/** Data-out buffer length
+	 *
+	 * Must be zero if @c data_out is NULL
+	 */
+	size_t data_out_len;
+	/** Data-in buffer (may be NULL)
+	 *
+	 * If non-NULL, this buffer must be ata_command::cb::count
+	 * sectors in size.
+	 */
+	userptr_t data_in;
+	/** Data-in buffer length
+	 *
+	 * Must be zero if @c data_in is NULL
+	 */
+	size_t data_in_len;
+};
+
+extern int ata_command ( struct interface *control, struct interface *data,
+			 struct ata_cmd *command );
+#define ata_command_TYPE( object_type )					\
+	typeof ( int ( object_type, struct interface *data,		\
+		       struct ata_cmd *command ) )
+
+extern int ata_open ( struct interface *block, struct interface *ata,
+		      unsigned int device, unsigned int max_count );
+
+#endif /* _IPXE_ATA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/base16.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/base16.h
new file mode 100644
index 0000000..f0c9842
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/base16.h
@@ -0,0 +1,38 @@
+#ifndef _IPXE_BASE16_H
+#define _IPXE_BASE16_H
+
+/** @file
+ *
+ * Base16 encoding
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * Calculate length of base16-encoded data
+ *
+ * @v raw_len		Raw data length
+ * @ret encoded_len	Encoded string length (excluding NUL)
+ */
+static inline size_t base16_encoded_len ( size_t raw_len ) {
+	return ( 2 * raw_len );
+}
+
+/**
+ * Calculate maximum length of base16-decoded string
+ *
+ * @v encoded		Encoded string
+ * @v max_raw_len	Maximum length of raw data
+ */
+static inline size_t base16_decoded_max_len ( const char *encoded ) {
+	return ( ( strlen ( encoded ) + 1 ) / 2 );
+}
+
+extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded );
+extern int base16_decode ( const char *encoded, uint8_t *raw );
+
+#endif /* _IPXE_BASE16_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/base64.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/base64.h
new file mode 100644
index 0000000..5fe134d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/base64.h
@@ -0,0 +1,41 @@
+#ifndef _IPXE_BASE64_H
+#define _IPXE_BASE64_H
+
+/** @file
+ *
+ * Base64 encoding
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * Calculate length of base64-encoded data
+ *
+ * @v raw_len		Raw data length
+ * @ret encoded_len	Encoded string length (excluding NUL)
+ */
+static inline size_t base64_encoded_len ( size_t raw_len ) {
+	return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 );
+}
+
+/**
+ * Calculate maximum length of base64-decoded string
+ *
+ * @v encoded		Encoded string
+ * @v max_raw_len	Maximum length of raw data
+ *
+ * Note that the exact length of the raw data cannot be known until
+ * the string is decoded.
+ */
+static inline size_t base64_decoded_max_len ( const char *encoded ) {
+	return ( ( ( strlen ( encoded ) + 4 - 1 ) / 4 ) * 3 );
+}
+
+extern void base64_encode ( const uint8_t *raw, size_t len, char *encoded );
+extern int base64_decode ( const char *encoded, uint8_t *raw );
+
+#endif /* _IPXE_BASE64_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitbash.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitbash.h
new file mode 100644
index 0000000..62b54b1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitbash.h
@@ -0,0 +1,52 @@
+#ifndef _IPXE_BITBASH_H
+#define _IPXE_BITBASH_H
+
+/** @file
+ *
+ * Bit-bashing interfaces
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct bit_basher;
+
+/** Bit-bashing operations */
+struct bit_basher_operations {
+	/**
+	 * Set/clear output bit
+	 *
+	 * @v basher		Bit-bashing interface
+	 * @v bit_id		Bit number
+	 * @v data		Value to write
+	 * 
+	 * @c data will be 0 if a logic 0 should be written (i.e. the
+	 * bit should be cleared), or -1UL if a logic 1 should be
+	 * written (i.e. the bit should be set).  This is done so that
+	 * the method may simply binary-AND @c data with the
+	 * appropriate bit mask.
+	 */
+	void ( * write ) ( struct bit_basher *basher, unsigned int bit_id,
+			   unsigned long data );
+	/**
+	 * Read input bit
+	 *
+	 * @v basher		Bit-bashing interface
+	 * @v bit_id		Bit number
+	 * @ret zero		Input is a logic 0
+	 * @ret non-zero	Input is a logic 1
+	 */
+	int ( * read ) ( struct bit_basher *basher, unsigned int bit_id );
+};
+
+/** A bit-bashing interface */
+struct bit_basher {
+	/** Bit-bashing operations */
+	struct bit_basher_operations *op;
+};
+
+extern void write_bit ( struct bit_basher *basher, unsigned int bit_id,
+			unsigned long data );
+extern int read_bit ( struct bit_basher *basher, unsigned int bit_id );
+
+#endif /* _IPXE_BITBASH_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitmap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitmap.h
new file mode 100644
index 0000000..b18584c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitmap.h
@@ -0,0 +1,85 @@
+#ifndef _IPXE_BITMAP_H
+#define _IPXE_BITMAP_H
+
+/** @file
+ *
+ * Bitmaps for multicast downloads
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/** A single block of bits within a bitmap */
+typedef unsigned long bitmap_block_t;
+
+/** Size of a block of bits (in bits) */
+#define BITMAP_BLKSIZE ( sizeof ( bitmap_block_t ) * 8 )
+
+/**
+ * Block index within bitmap
+ *
+ * @v bit		Bit index
+ * @ret index		Block index
+ */
+#define BITMAP_INDEX( bit ) ( (bit) / BITMAP_BLKSIZE )
+
+/**
+ * Block mask within bitmap
+ *
+ * @v bit		Bit index
+ * @ret mask		Block mask
+ */
+#define BITMAP_MASK( bit ) ( 1UL << ( (bit) % BITMAP_BLKSIZE ) )
+
+/** A bitmap */
+struct bitmap {
+	/** Bitmap data */
+	bitmap_block_t *blocks;
+	/** Length of the bitmap, in bits */
+	unsigned int length;
+	/** Index of first gap in the bitmap */
+	unsigned int first_gap;
+};
+
+extern int bitmap_resize ( struct bitmap *bitmap, unsigned int new_length );
+extern int bitmap_test ( struct bitmap *bitmap, unsigned int bit );
+extern void bitmap_set ( struct bitmap *bitmap, unsigned int bit );
+
+/**
+ * Free bitmap resources
+ *
+ * @v bitmap		Bitmap
+ */
+static inline void bitmap_free ( struct bitmap *bitmap ) {
+	free ( bitmap->blocks );
+}
+
+/**
+ * Get first gap within bitmap
+ *
+ * @v bitmap		Bitmap
+ * @ret first_gap	First gap
+ *
+ * The first gap is the first unset bit within the bitmap.
+ */
+static inline unsigned int bitmap_first_gap ( struct bitmap *bitmap ) {
+	return bitmap->first_gap;
+}
+
+/**
+ * Check to see if bitmap is full
+ *
+ * @v bitmap		Bitmap
+ * @ret is_full		Bitmap is full
+ *
+ * The bitmap is full if it has no gaps (i.e. no unset bits).
+ */
+static inline int bitmap_full ( struct bitmap *bitmap ) {
+	return ( bitmap->first_gap == bitmap->length );
+}
+
+#endif /* _IPXE_BITMAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitops.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitops.h
new file mode 100644
index 0000000..4118ef8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bitops.h
@@ -0,0 +1,230 @@
+#ifndef _IPXE_BITOPS_H
+#define _IPXE_BITOPS_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Bit operations
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+
+/* Endianness selection.
+ *
+ * This is a property of the NIC, not a property of the host CPU.
+ */
+#ifdef BITOPS_LITTLE_ENDIAN
+#define cpu_to_BIT64	cpu_to_le64
+#define cpu_to_BIT32	cpu_to_le32
+#define BIT64_to_cpu	le64_to_cpu
+#define BIT32_to_cpu	le32_to_cpu
+#endif
+#ifdef BITOPS_BIG_ENDIAN
+#define cpu_to_BIT64	cpu_to_be64
+#define cpu_to_BIT32	cpu_to_be32
+#define BIT64_to_cpu	be64_to_cpu
+#define BIT32_to_cpu	be32_to_cpu
+#endif
+
+/** Datatype used to represent a bit in the pseudo-structures */
+typedef unsigned char pseudo_bit_t;
+
+/**
+ * Wrapper structure for pseudo_bit_t structures
+ *
+ * This structure provides a wrapper around pseudo_bit_t structures.
+ * It has the correct size, and also encapsulates type information
+ * about the underlying pseudo_bit_t-based structure, which allows the
+ * BIT_FILL() etc. macros to work without requiring explicit type
+ * information.
+ */
+#define PSEUDO_BIT_STRUCT( _structure )					      \
+	union {								      \
+		uint8_t bytes[ sizeof ( _structure ) / 8 ];		      \
+		uint32_t dwords[ sizeof ( _structure ) / 32 ];		      \
+		uint64_t qwords[ sizeof ( _structure ) / 64 ];		      \
+		_structure *dummy[0];					      \
+	} __attribute__ (( packed )) u
+
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
+#define PSEUDO_BIT_STRUCT_TYPE( _ptr )					      \
+	typeof ( *((_ptr)->u.dummy[0]) )
+
+/** Bit offset of a field within a pseudo_bit_t structure */
+#define BIT_OFFSET( _ptr, _field )					      \
+	offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
+
+/** Bit width of a field within a pseudo_bit_t structure */
+#define BIT_WIDTH( _ptr, _field )					      \
+	sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
+
+/** Qword offset of a field within a pseudo_bit_t structure */
+#define QWORD_OFFSET( _ptr, _field )					      \
+	( BIT_OFFSET ( _ptr, _field ) / 64 )
+
+/** Qword bit offset of a field within a pseudo_bit_t structure */
+#define QWORD_BIT_OFFSET( _ptr, _index, _field )			      \
+	( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
+
+/** Bit mask for a field within a pseudo_bit_t structure */
+#define BIT_MASK( _ptr, _field )					      \
+	( ( ~( ( uint64_t ) 0 ) ) >>					      \
+	  ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
+
+/*
+ * Assemble native-endian qword from named fields and values
+ *
+ */
+
+#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value )			      \
+	( ( ( uint64_t) (_value) ) <<					      \
+	  QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... )		      \
+	( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) |		      \
+	  BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Build native-endian (positive) qword bitmasks from named fields
+ *
+ */
+
+#define BIT_MASK_1( _ptr, _index, _field )				      \
+	( BIT_MASK ( _ptr, _field ) <<					      \
+	  QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_MASK_2( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_3( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_4( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_5( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_6( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_7( _ptr, _index, _field, ... )				      \
+	( BIT_MASK_1 ( _ptr, _index, _field ) |				      \
+	  BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Populate little-endian qwords from named fields and values
+ *
+ */
+
+#define BIT_FILL( _ptr, _index, _assembled ) do {			      \
+		uint64_t *__ptr = &(_ptr)->u.qwords[(_index)];		      \
+		uint64_t __assembled = (_assembled);			      \
+		*__ptr = cpu_to_BIT64 ( __assembled );			      \
+	} while ( 0 )
+
+#define BIT_FILL_1( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_2( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_3( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_4( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_5( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_6( _ptr, _field1, ... )				      \
+	BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),		      \
+		   BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ),     \
+				    _field1, __VA_ARGS__ ) )
+
+/** Extract value of named field */
+#define BIT_GET64( _ptr, _field )					      \
+	( {								      \
+		unsigned int __index = QWORD_OFFSET ( _ptr, _field );	      \
+		uint64_t *__ptr = &(_ptr)->u.qwords[__index];		      \
+		uint64_t __value = BIT64_to_cpu ( *__ptr );		      \
+		__value >>=						      \
+		    QWORD_BIT_OFFSET ( _ptr, __index, _field );		      \
+		__value &= BIT_MASK ( _ptr, _field );			      \
+		__value;						      \
+	} )
+
+/** Extract value of named field (for fields up to the size of a long) */
+#define BIT_GET( _ptr, _field )						      \
+	( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
+
+#define BIT_SET( _ptr, _field, _value ) do {				      \
+		unsigned int __index = QWORD_OFFSET ( _ptr, _field );	      \
+		uint64_t *__ptr = &(_ptr)->u.qwords[__index];		      \
+		unsigned int __shift =					      \
+			QWORD_BIT_OFFSET ( _ptr, __index, _field );	      \
+		uint64_t __value = (_value);				      \
+		*__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) <<      \
+					    __shift ) );		      \
+		*__ptr |= cpu_to_BIT64 ( __value << __shift );		      \
+	} while ( 0 )
+
+#endif /* _IPXE_BITOPS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/blockdev.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/blockdev.h
new file mode 100644
index 0000000..9f0a9f7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/blockdev.h
@@ -0,0 +1,55 @@
+#ifndef _IPXE_BLOCKDEV_H
+#define _IPXE_BLOCKDEV_H
+
+/**
+ * @file
+ *
+ * Block devices
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/interface.h>
+
+/** Block device capacity */
+struct block_device_capacity {
+	/** Total number of blocks */
+	uint64_t blocks;
+	/** Block size */
+	size_t blksize;
+	/** Maximum number of blocks per single transfer */
+	unsigned int max_count;
+};
+
+extern int block_read ( struct interface *control, struct interface *data,
+			uint64_t lba, unsigned int count,
+			userptr_t buffer, size_t len );
+#define block_read_TYPE( object_type )					\
+	typeof ( int ( object_type, struct interface *data,		\
+		       uint64_t lba, unsigned int count,		\
+		       userptr_t buffer, size_t len ) )
+
+extern int block_write ( struct interface *control, struct interface *data,
+			 uint64_t lba, unsigned int count,
+			 userptr_t buffer, size_t len );
+#define block_write_TYPE( object_type )					\
+	typeof ( int ( object_type, struct interface *data,		\
+		       uint64_t lba, unsigned int count,		\
+		       userptr_t buffer, size_t len ) )
+
+extern int block_read_capacity ( struct interface *control,
+				 struct interface *data );
+#define block_read_capacity_TYPE( object_type )				\
+	typeof ( int ( object_type, struct interface *data ) )
+
+extern void block_capacity ( struct interface *intf,
+			     struct block_device_capacity *capacity );
+#define block_capacity_TYPE( object_type )				\
+	typeof ( void ( object_type,					\
+			struct block_device_capacity *capacity ) )
+
+
+#endif /* _IPXE_BLOCKDEV_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/bofm.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bofm.h
new file mode 100644
index 0000000..1da47f6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/bofm.h
@@ -0,0 +1,351 @@
+#ifndef _IPXE_BOFM_H
+#define _IPXE_BOFM_H
+
+/**
+ * @file
+ *
+ * IBM BladeCenter Open Fabric Manager (BOFM)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/pci.h>
+#include <config/sideband.h>
+
+/** 'IBM ' signature
+ *
+ * Present in %edi when the BIOS initialisation entry point is called,
+ * with the BOFM table pointer in %esi.
+ *
+ * Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
+ * Re-Assignment Architecture document.
+ */
+#define IBMs_SIGNATURE ( ( 'I' << 24 ) + ( 'B' << 16 ) + ( 'M' << 8 ) + ' ' )
+
+/** ' IBM' signature
+ *
+ * Returned in %edi from the BIOS initialisation entry point, with the
+ * return code in %dl.
+ *
+ * Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
+ * Re-Assignment Architecture document.
+ */
+#define sIBM_SIGNATURE ( ( ' ' << 24 ) + ( 'I' << 16 ) + ( 'B' << 8 ) + 'M' )
+
+/** @defgroup bofmrc BOFM return codes
+ *
+ * Defined in section 4.1.3 of the POST/BIOS BOFM I/O Address
+ * Re-Assignment Architecture document.
+ *
+ * @{
+ */
+
+/** Successful */
+#define BOFM_SUCCESS 0x00
+
+/** Invalid action string */
+#define BOFM_ERR_INVALID_ACTION 0x01
+
+/** Unsupported parameter structure version */
+#define BOFM_ERR_UNSUPPORTED 0x02
+
+/** Device error prohibited MAC/WWN update */
+#define BOFM_ERR_DEVICE_ERROR 0x03
+
+/** PCI reset required (may be combined with another return code) */
+#define BOFM_PCI_RESET 0x80
+
+/** @} */
+
+/** Skip option ROM initialisation
+ *
+ * A BOFM BIOS may call the initialisation entry point multiple times;
+ * only the last call should result in actual initialisation.
+ *
+ * This flag is internal to iPXE.
+ */
+#define BOFM_SKIP_INIT 0x80000000UL
+
+/** BOFM table header
+ *
+ * Defined in section 4.1 of the Open Fabric Manager Parameter
+ * Specification document.
+ */
+struct bofm_global_header {
+	/** Signature */
+	uint32_t magic;
+	/** Subsignature (action string) */
+	uint32_t action;
+	/** Data structure version */
+	uint8_t version;
+	/** Data structure level */
+	uint8_t level;
+	/** Data structure length */
+	uint16_t length;
+	/** Data structure checksum */
+	uint8_t checksum;
+	/** Data structure profile */
+	char profile[32];
+	/** Data structure global options */
+	uint32_t options;
+	/** Data structure sequence stamp */
+	uint32_t sequence;
+} __attribute__ (( packed ));
+
+/** BOFM table header signature
+ *
+ * Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
+ * Re-Assignment Architecture document.
+ */
+#define BOFM_IOAA_MAGIC	 ( 'I' + ( 'O' << 8 ) + ( 'A' << 16 ) + ( 'A' << 24 ) )
+
+/** @defgroup bofmaction BOFM header subsignatures (action strings)
+ *
+ * Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
+ * Re-Assignment Architecture document.
+ *
+ * @{
+ */
+
+/** Update MAC/WWN */
+#define BOFM_ACTION_UPDT ( 'U' + ( 'P' << 8 ) + ( 'D' << 16 ) + ( 'T' << 24 ) )
+
+/** Restore MAC/WWN to factory default */
+#define BOFM_ACTION_DFLT ( 'D' + ( 'F' << 8 ) + ( 'L' << 16 ) + ( 'T' << 24 ) )
+
+/** Harvest MAC/WWN */
+#define BOFM_ACTION_HVST ( 'H' + ( 'V' << 8 ) + ( 'S' << 16 ) + ( 'T' << 24 ) )
+
+/** Update MAC/WWN and initialise device */
+#define BOFM_ACTION_PARM ( 'P' + ( 'A' << 8 ) + ( 'R' << 16 ) + ( 'M' << 24 ) )
+
+/** Just initialise the device */
+#define BOFM_ACTION_NONE ( 'N' + ( 'O' << 8 ) + ( 'N' << 16 ) + ( 'E' << 24 ) )
+
+/** @} */
+
+/** BOFM section header
+ *
+ * Defined in section 4.2 of the Open Fabric Manager Parameter
+ * Specification document.
+ */
+struct bofm_section_header {
+	/** Signature */
+	uint32_t magic;
+	/** Length */
+	uint16_t length;
+} __attribute__ (( packed ));
+
+/** @defgroup bofmsections BOFM section header signatures
+ *
+ * Defined in section 4.2 of the Open Fabric Manager Parameter
+ * Specification document.
+ *
+ * @{
+ */
+
+/** EN start marker */
+#define BOFM_EN_MAGIC    ( ' ' + ( ' ' << 8 ) + ( 'E' << 16 ) + ( 'N' << 24 ) )
+
+/** End marker */
+#define BOFM_DONE_MAGIC	 ( 'D' + ( 'O' << 8 ) + ( 'N' << 16 ) + ( 'E' << 24 ) )
+
+/** @} */
+
+/** BOFM Ethernet parameter entry
+ *
+ * Defined in section 5.1 of the Open Fabric Manager Parameter
+ * Specification document.
+ */
+struct bofm_en {
+	/** Options */
+	uint16_t options;
+	/** PCI bus:dev.fn
+	 *
+	 * Valid only if @c options indicates @c BOFM_EN_MAP_PFA
+	 */
+	uint16_t busdevfn;
+	/** Slot or mezzanine number
+	 *
+	 * Valid only if @c options indicates @c BOFM_EN_MAP_SLOT_PORT
+	 */
+	uint8_t slot;
+	/** Port number
+	 *
+	 * Valid only if @c options indicates @c BOFM_EN_MAP_SLOT_PORT
+	 */
+	uint8_t port;
+	/** Multi-port index */
+	uint8_t mport;
+	/** VLAN tag for MAC address A */
+	uint16_t vlan_a;
+	/** MAC address A
+	 *
+	 * MAC address A is the sole MAC address, or the lower
+	 * (inclusive) bound of a range of MAC addresses.
+	 */
+	uint8_t mac_a[6];
+	/** VLAN tag for MAC address B */
+	uint16_t vlan_b;
+	/** MAC address B
+	 *
+	 * MAC address B is unset, or the upper (inclusive) bound of a
+	 * range of MAC addresses
+	 */
+	uint8_t mac_b[6];
+} __attribute__ (( packed ));
+
+/** @defgroup bofmenopts BOFM Ethernet parameter entry options
+ *
+ * Defined in section 5.1 of the Open Fabric Manager Parameter
+ * Specification document.
+ *
+ * @{
+ */
+
+/** Port mapping mask */
+#define BOFM_EN_MAP_MASK	0x0001
+
+/** Port mapping is by PCI bus:dev.fn */
+#define BOFM_EN_MAP_PFA			0x0000
+
+/** Port mapping is by slot/port */
+#define BOFM_EN_MAP_SLOT_PORT		0x0001
+
+/** MAC address B is present */
+#define BOFM_EN_EN_B		0x0002
+
+/** VLAN tag for MAC address B is present */
+#define BOFM_EN_VLAN_B		0x0004
+
+/** MAC address A is present */
+#define BOFM_EN_EN_A		0x0008
+
+/** VLAN tag for MAC address A is present */
+#define BOFM_EN_VLAN_A		0x0010
+
+/** Entry consumption indicator mask */
+#define BOFM_EN_CSM_MASK	0x00c0
+
+/** Entry has not been used */
+#define BOFM_EN_CSM_UNUSED		0x0000
+
+/** Entry has been used successfully */
+#define BOFM_EN_CSM_SUCCESS		0x0040
+
+/** Entry has been used but failed */
+#define BOFM_EN_CSM_FAILED		0x0080
+
+/** Consumed entry change mask */
+#define BOFM_EN_CHG_MASK	0x0100
+
+/** Consumed entry is same as previous active entry */
+#define BOFM_EN_CHG_UNCHANGED		0x0000
+
+/** Consumed entry is different than previous active entry */
+#define BOFM_EN_CHG_CHANGED		0x0100
+
+/** Ignore values - it's harvest time */
+#define BOFM_EN_USAGE_HARVEST	0x1000
+
+/** Use entry values for assignment */
+#define BOFM_EN_USAGE_ENTRY	0x0800
+
+/** Use factory default values */
+#define BOFM_EN_USAGE_DEFAULT	0x0400
+
+/** Harvest complete */
+#define BOFM_EN_HVST		0x2000
+
+/** Harvest request mask */
+#define BOFM_EN_RQ_HVST_MASK	0xc000
+
+/** Do not harvest */
+#define BOFM_EN_RQ_HVST_NONE		0x0000
+
+/** Harvest factory default values */
+#define BOFM_EN_RQ_HVST_DEFAULT		0x4000
+
+/** Harvest active values */
+#define BOFM_EN_RQ_HVST_ACTIVE		0xc000
+
+/** @} */
+
+/** BOFM magic value debug message format */
+#define BOFM_MAGIC_FMT "'%c%c%c%c'"
+
+/** BOFM magic value debug message arguments */
+#define BOFM_MAGIC_ARGS( magic )					\
+	( ( (magic) >> 0 ) & 0xff ), ( ( (magic) >> 8 ) & 0xff ),	\
+	( ( (magic) >> 16 ) & 0xff ), ( ( (magic) >> 24 ) & 0xff )
+
+/** A BOFM device */
+struct bofm_device {
+	/** Underlying PCI device */
+	struct pci_device *pci;
+	/** BOFM device operations */
+	struct bofm_operations *op;
+	/** List of BOFM devices */
+	struct list_head list;
+};
+
+/** BOFM device operations */
+struct bofm_operations {
+	/** Harvest Ethernet MAC
+	 *
+	 * @v bofm		BOFM device
+	 * @v mport		Multi-port index
+	 * @v mac		MAC to fill in
+	 * @ret rc		Return status code
+	 */
+	int ( * harvest ) ( struct bofm_device *bofm, unsigned int mport,
+			    uint8_t *mac );
+	/** Update Ethernet MAC
+	 *
+	 * @v bofm		BOFM device
+	 * @v mport		Multi-port index
+	 * @v mac		New MAC
+	 * @ret rc		Return status code
+	 */
+	int ( * update ) ( struct bofm_device *bofm, unsigned int mport,
+			   const uint8_t *mac );
+};
+
+/** BOFM driver table */
+#define BOFM_DRIVERS __table ( struct pci_driver, "bofm_drivers" )
+
+/** Declare a BOFM driver
+ *
+ * In the common case of non-BOFM-enabled builds, allow any BOFM code
+ * to be garbage-collected at link time to save space.
+ */
+#ifdef CONFIG_BOFM
+#define __bofm_driver __table_entry ( BOFM_DRIVERS, 01 )
+#else
+#define __bofm_driver
+#endif
+
+/**
+ * Initialise BOFM device
+ *
+ * @v bofm		BOFM device
+ * @v pci		PCI device
+ * @v op		BOFM device operations
+ */
+static inline __attribute__ (( always_inline )) void
+bofm_init ( struct bofm_device *bofm, struct pci_device *pci,
+	    struct bofm_operations *op ) {
+	bofm->pci = pci;
+	bofm->op = op;
+}
+
+extern int bofm_register ( struct bofm_device *bofm );
+extern void bofm_unregister ( struct bofm_device *bofm );
+extern int bofm_find_driver ( struct pci_device *pci );
+extern int bofm ( userptr_t bofmtab, struct pci_device *pci );
+extern void bofm_test ( struct pci_device *pci );
+
+#endif /* _IPXE_BOFM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/cbc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/cbc.h
new file mode 100644
index 0000000..fae3765
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/cbc.h
@@ -0,0 +1,100 @@
+#ifndef _IPXE_CBC_H
+#define _IPXE_CBC_H
+
+/** @file
+ *
+ * Cipher-block chaining
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crypto.h>
+
+/**
+ * Set key
+ *
+ * @v ctx		Context
+ * @v key		Key
+ * @v keylen		Key length
+ * @v raw_cipher	Underlying cipher algorithm
+ * @v cbc_ctx		CBC context
+ * @ret rc		Return status code
+ */
+static inline int cbc_setkey ( void *ctx, const void *key, size_t keylen,
+			       struct cipher_algorithm *raw_cipher,
+			       void *cbc_ctx __unused ) {
+
+	return cipher_setkey ( raw_cipher, ctx, key, keylen );
+}
+
+/**
+ * Set initialisation vector
+ *
+ * @v ctx		Context
+ * @v iv		Initialisation vector
+ * @v raw_cipher	Underlying cipher algorithm
+ * @v cbc_ctx		CBC context
+ */
+static inline void cbc_setiv ( void *ctx __unused, const void *iv,
+			       struct cipher_algorithm *raw_cipher,
+			       void *cbc_ctx ) {
+	memcpy ( cbc_ctx, iv, raw_cipher->blocksize );
+}
+
+extern void cbc_encrypt ( void *ctx, const void *src, void *dst,
+			  size_t len, struct cipher_algorithm *raw_cipher,
+			  void *cbc_ctx );
+extern void cbc_decrypt ( void *ctx, const void *src, void *dst,
+			  size_t len, struct cipher_algorithm *raw_cipher,
+			  void *cbc_ctx );
+
+/**
+ * Create a cipher-block chaining mode of behaviour of an existing cipher
+ *
+ * @v _cbc_name		Name for the new CBC cipher
+ * @v _cbc_cipher	New cipher algorithm
+ * @v _raw_cipher	Underlying cipher algorithm
+ * @v _raw_context	Context structure for the underlying cipher
+ * @v _blocksize	Cipher block size
+ */
+#define CBC_CIPHER( _cbc_name, _cbc_cipher, _raw_cipher, _raw_context,	\
+		    _blocksize )					\
+struct _cbc_name ## _context {						\
+	_raw_context raw_ctx;						\
+	uint8_t cbc_ctx[_blocksize];					\
+};									\
+static int _cbc_name ## _setkey ( void *ctx, const void *key,		\
+				  size_t keylen ) {			\
+	struct _cbc_name ## _context * _cbc_name ## _ctx = ctx;		\
+	return cbc_setkey ( &_cbc_name ## _ctx->raw_ctx, key, keylen,	\
+			    &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx );\
+}									\
+static void _cbc_name ## _setiv ( void *ctx, const void *iv ) {		\
+	struct _cbc_name ## _context * _cbc_name ## _ctx = ctx;		\
+	cbc_setiv ( &_cbc_name ## _ctx->raw_ctx, iv,			\
+		    &_raw_cipher, &aes_cbc_ctx->cbc_ctx );		\
+}									\
+static void _cbc_name ## _encrypt ( void *ctx, const void *src,		\
+				    void *dst, size_t len ) {		\
+	struct _cbc_name ## _context * _cbc_name ## _ctx = ctx;		\
+	cbc_encrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len,	\
+		      &_raw_cipher, &aes_cbc_ctx->cbc_ctx );		\
+}									\
+static void _cbc_name ## _decrypt ( void *ctx, const void *src,		\
+				    void *dst, size_t len ) {		\
+	struct _cbc_name ## _context * _cbc_name ## _ctx = ctx;		\
+	cbc_decrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len,	\
+		      &_raw_cipher, &aes_cbc_ctx->cbc_ctx );		\
+}									\
+struct cipher_algorithm _cbc_cipher = {					\
+	.name		= #_cbc_name,					\
+	.ctxsize	= sizeof ( struct _cbc_name ## _context ),	\
+	.blocksize	= _blocksize,					\
+	.setkey		= _cbc_name ## _setkey,				\
+	.setiv		= _cbc_name ## _setiv,				\
+	.encrypt	= _cbc_name ## _encrypt,			\
+	.decrypt	= _cbc_name ## _decrypt,			\
+};
+
+#endif /* _IPXE_CBC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/chap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/chap.h
new file mode 100644
index 0000000..fce48f3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/chap.h
@@ -0,0 +1,53 @@
+#ifndef _IPXE_CHAP_H
+#define _IPXE_CHAP_H
+
+/** @file
+ *
+ * CHAP protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/md5.h>
+
+struct digest_algorithm;
+
+/** A CHAP response */
+struct chap_response {
+	/** Digest algorithm used for the response */
+	struct digest_algorithm *digest;
+	/** Context used by the digest algorithm */
+	uint8_t *digest_context;
+	/** CHAP response */
+	uint8_t *response;
+	/** Length of CHAP response */
+	size_t response_len;
+};
+
+extern int chap_init ( struct chap_response *chap,
+		       struct digest_algorithm *digest );
+extern void chap_update ( struct chap_response *chap, const void *data,
+			  size_t len );
+extern void chap_respond ( struct chap_response *chap );
+extern void chap_finish ( struct chap_response *chap );
+
+/**
+ * Add identifier data to the CHAP challenge
+ *
+ * @v chap		CHAP response
+ * @v identifier	CHAP identifier
+ *
+ * The CHAP identifier is the first byte of the CHAP challenge.  This
+ * function is a notational convenience for calling chap_update() for
+ * the identifier byte.
+ */
+static inline void chap_set_identifier ( struct chap_response *chap,
+					 unsigned int identifier ) {
+	uint8_t ident_byte = identifier;
+
+	chap_update ( chap, &ident_byte, sizeof ( ident_byte ) );
+}
+
+#endif /* _IPXE_CHAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/command.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/command.h
new file mode 100644
index 0000000..432da1a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/command.h
@@ -0,0 +1,28 @@
+#ifndef _IPXE_COMMAND_H
+#define _IPXE_COMMAND_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+
+/** A command-line command */
+struct command {
+	/** Name of the command */
+	const char *name;
+	/**
+	 * Function implementing the command
+	 *
+	 * @v argc		Argument count
+	 * @v argv		Argument list
+	 * @ret rc		Return status code
+	 */
+	int ( * exec ) ( int argc, char **argv );
+};
+
+#define COMMANDS __table ( struct command, "commands" )
+
+#define __command __table_entry ( COMMANDS, 01 )
+
+extern char * concat_args ( char **args );
+
+#endif /* _IPXE_COMMAND_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/console.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/console.h
new file mode 100644
index 0000000..3bfa503
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/console.h
@@ -0,0 +1,108 @@
+#ifndef _IPXE_CONSOLE_H
+#define _IPXE_CONSOLE_H
+
+#include <ipxe/tables.h>
+
+/** @file
+ *
+ * User interaction.
+ *
+ * Various console devices can be selected via the build options
+ * CONSOLE_FIRMWARE, CONSOLE_SERIAL etc.  The console functions
+ * putchar(), getchar() and iskey() delegate to the individual console
+ * drivers.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * A console driver
+ *
+ * Defines the functions that implement a particular console type.
+ * Must be made part of the console drivers table by using
+ * #__console_driver.
+ *
+ * @note Consoles that cannot be used before their initialisation
+ * function has completed should set #disabled=1 initially.  This
+ * allows other console devices to still be used to print out early
+ * debugging messages.
+ *
+ */
+struct console_driver {
+	/** Console is disabled.
+	 *
+	 * The console's putchar(), getchar() and iskey() methods will
+	 * not be called while #disabled==1.  Typically the console's
+	 * initialisation functions will set #disabled=0 upon
+	 * completion.
+	 *
+	 */
+	int disabled;
+
+	/** Write a character to the console.
+	 *
+	 * @v character		Character to be written
+	 * @ret None		-
+	 * @err None		-
+	 *
+	 */
+	void ( *putchar ) ( int character );
+
+	/** Read a character from the console.
+	 *
+	 * @v None		-
+	 * @ret character	Character read
+	 * @err None		-
+	 *
+	 * If no character is available to be read, this method will
+	 * block.  The character read should not be echoed back to the
+	 * console.
+	 *
+	 */
+	int ( *getchar ) ( void );
+
+	/** Check for available input.
+	 *
+	 * @v None		-
+	 * @ret True		Input is available
+	 * @ret False		Input is not available
+	 * @err None		-
+	 *
+	 * This should return True if a subsequent call to getchar()
+	 * will not block.
+	 *
+	 */
+	int ( *iskey ) ( void );
+};
+
+/** Console driver table */
+#define CONSOLES __table ( struct console_driver, "consoles" )
+
+/**
+ * Mark a <tt> struct console_driver </tt> as being part of the
+ * console drivers table.
+ *
+ * Use as e.g.
+ *
+ * @code
+ *
+ *   struct console_driver my_console __console_driver = {
+ *      .putchar = my_putchar,
+ *	.getchar = my_getchar,
+ *	.iskey = my_iskey,
+ *   };
+ *
+ * @endcode
+ *
+ */
+#define __console_driver __table_entry ( CONSOLES, 01 )
+
+/* Function prototypes */
+
+extern void putchar ( int character );
+extern int getchar ( void );
+extern int iskey ( void );
+extern int getkey ( unsigned long timeout );
+
+#endif /* _IPXE_CONSOLE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/cpio.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/cpio.h
new file mode 100644
index 0000000..2772328
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/cpio.h
@@ -0,0 +1,53 @@
+#ifndef _IPXE_CPIO_H
+#define _IPXE_CPIO_H
+
+/** @file
+ *
+ * CPIO archives
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A CPIO archive header
+ *
+ * All field are hexadecimal ASCII numbers padded with '0' on the
+ * left to the full width of the field.
+ */
+struct cpio_header {
+	/** The string "070701" or "070702" */
+	char c_magic[6];
+	/** File inode number */
+	char c_ino[8];
+	/** File mode and permissions */
+	char c_mode[8];
+	/** File uid */
+	char c_uid[8];
+	/** File gid */
+	char c_gid[8];
+	/** Number of links */
+	char c_nlink[8];
+	/** Modification time */
+	char c_mtime[8];
+	/** Size of data field */
+	char c_filesize[8];
+	/** Major part of file device number */
+	char c_maj[8];
+	/** Minor part of file device number */
+	char c_min[8];
+	/** Major part of device node reference */
+	char c_rmaj[8];
+	/** Minor part of device node reference */
+	char c_rmin[8];
+	/** Length of filename, including final NUL */
+	char c_namesize[8];
+	/** Checksum of data field if c_magic is 070702, othersize zero */
+	char c_chksum[8];
+} __attribute__ (( packed ));
+
+/** CPIO magic */
+#define CPIO_MAGIC "070701"
+
+extern void cpio_set_field ( char *field, unsigned long value );
+
+#endif /* _IPXE_CPIO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/crc32.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/crc32.h
new file mode 100644
index 0000000..38ac1b3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/crc32.h
@@ -0,0 +1,10 @@
+#ifndef _IPXE_CRC32_H
+#define _IPXE_CRC32_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+u32 crc32_le ( u32 seed, const void *data, size_t len );
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/crypto.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/crypto.h
new file mode 100644
index 0000000..9383c07
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/crypto.h
@@ -0,0 +1,156 @@
+#ifndef _IPXE_CRYPTO_H
+#define _IPXE_CRYPTO_H
+
+/** @file
+ *
+ * Cryptographic API
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+
+/** A message digest algorithm */
+struct digest_algorithm {
+	/** Algorithm name */
+	const char *name;
+	/** Context size */
+	size_t ctxsize;
+	/** Block size */
+	size_t blocksize;
+	/** Digest size */
+	size_t digestsize;
+	/** Initialise digest
+	 *
+	 * @v ctx		Context
+	 */
+	void ( * init ) ( void *ctx );
+	/** Update digest with new data
+	 *
+	 * @v ctx		Context
+	 * @v src		Data to digest
+	 * @v len		Length of data
+	 *
+	 * @v len is not necessarily a multiple of @c blocksize.
+	 */
+	void ( * update ) ( void *ctx, const void *src, size_t len );
+	/** Finalise digest
+	 *
+	 * @v ctx		Context
+	 * @v out		Buffer for digest output
+	 */
+	void ( * final ) ( void *ctx, void *out );
+};
+
+/** A cipher algorithm */
+struct cipher_algorithm {
+	/** Algorithm name */
+	const char *name;
+	/** Context size */
+	size_t ctxsize;
+	/** Block size */
+	size_t blocksize;
+	/** Set key
+	 *
+	 * @v ctx		Context
+	 * @v key		Key
+	 * @v keylen		Key length
+	 * @ret rc		Return status code
+	 */
+	int ( * setkey ) ( void *ctx, const void *key, size_t keylen );
+	/** Set initialisation vector
+	 *
+	 * @v ctx		Context
+	 * @v iv		Initialisation vector
+	 */
+	void ( * setiv ) ( void *ctx, const void *iv );
+	/** Encrypt data
+	 *
+	 * @v ctx		Context
+	 * @v src		Data to encrypt
+	 * @v dst		Buffer for encrypted data
+	 * @v len		Length of data
+	 *
+	 * @v len is guaranteed to be a multiple of @c blocksize.
+	 */
+	void ( * encrypt ) ( void *ctx, const void *src, void *dst,
+			     size_t len );
+	/** Decrypt data
+	 *
+	 * @v ctx		Context
+	 * @v src		Data to decrypt
+	 * @v dst		Buffer for decrypted data
+	 * @v len		Length of data
+	 *
+	 * @v len is guaranteed to be a multiple of @c blocksize.
+	 */
+	void ( * decrypt ) ( void *ctx, const void *src, void *dst,
+			     size_t len );
+};
+
+/** A public key algorithm */
+struct pubkey_algorithm {
+	/** Algorithm name */
+	const char *name;
+	/** Context size */
+	size_t ctxsize;
+};
+
+static inline void digest_init ( struct digest_algorithm *digest,
+				 void *ctx ) {
+	digest->init ( ctx );
+}
+
+static inline void digest_update ( struct digest_algorithm *digest,
+				   void *ctx, const void *data, size_t len ) {
+	digest->update ( ctx, data, len );
+}
+
+static inline void digest_final ( struct digest_algorithm *digest,
+				  void *ctx, void *out ) {
+	digest->final ( ctx, out );
+}
+
+static inline int cipher_setkey ( struct cipher_algorithm *cipher,
+				  void *ctx, const void *key, size_t keylen ) {
+	return cipher->setkey ( ctx, key, keylen );
+}
+
+static inline void cipher_setiv ( struct cipher_algorithm *cipher,
+				  void *ctx, const void *iv ) {
+	cipher->setiv ( ctx, iv );
+}
+
+static inline void cipher_encrypt ( struct cipher_algorithm *cipher,
+				    void *ctx, const void *src, void *dst,
+				    size_t len ) {
+	cipher->encrypt ( ctx, src, dst, len );
+}
+#define cipher_encrypt( cipher, ctx, src, dst, len ) do {		\
+	assert ( ( (len) & ( (cipher)->blocksize - 1 ) ) == 0 );	\
+	cipher_encrypt ( (cipher), (ctx), (src), (dst), (len) );	\
+	} while ( 0 )
+
+static inline void cipher_decrypt ( struct cipher_algorithm *cipher,
+				    void *ctx, const void *src, void *dst,
+				    size_t len ) {
+	cipher->decrypt ( ctx, src, dst, len );
+}
+#define cipher_decrypt( cipher, ctx, src, dst, len ) do {		\
+	assert ( ( (len) & ( (cipher)->blocksize - 1 ) ) == 0 );	\
+	cipher_decrypt ( (cipher), (ctx), (src), (dst), (len) );	\
+	} while ( 0 )
+
+static inline int is_stream_cipher ( struct cipher_algorithm *cipher ) {
+	return ( cipher->blocksize == 1 );
+}
+
+extern struct digest_algorithm digest_null;
+extern struct cipher_algorithm cipher_null;
+extern struct pubkey_algorithm pubkey_null;
+
+void get_random_bytes ( void *buf, size_t len );
+
+#endif /* _IPXE_CRYPTO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/device.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/device.h
new file mode 100644
index 0000000..435af6e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/device.h
@@ -0,0 +1,139 @@
+#ifndef _IPXE_DEVICE_H
+#define _IPXE_DEVICE_H
+
+/**
+ * @file
+ *
+ * Device model
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+
+struct interface;
+
+/** A hardware device description */
+struct device_description {
+	/** Bus type
+	 *
+	 * This must be a BUS_TYPE_XXX constant.
+	 */
+	unsigned int bus_type;
+	/** Location
+	 *
+	 * The interpretation of this field is bus-type-specific.
+	 */
+	unsigned int location;
+	/** Vendor ID */
+	unsigned int vendor;
+	/** Device ID */
+	unsigned int device;
+	/** Device class */
+	unsigned long class;
+	/** I/O address */
+	unsigned long ioaddr;
+	/** IRQ */
+	unsigned int irq;
+};
+
+/** PCI bus type */
+#define BUS_TYPE_PCI 1
+
+/** ISAPnP bus type */
+#define BUS_TYPE_ISAPNP 2
+
+/** EISA bus type */
+#define BUS_TYPE_EISA 3
+
+/** MCA bus type */
+#define BUS_TYPE_MCA 4
+
+/** ISA bus type */
+#define BUS_TYPE_ISA 5
+
+/** A hardware device */
+struct device {
+	/** Name */
+	char name[16];
+	/** Driver name */
+	const char *driver_name;
+	/** Device description */
+	struct device_description desc;
+	/** Devices on the same bus */
+	struct list_head siblings;
+	/** Devices attached to this device */
+	struct list_head children;
+	/** Bus device */
+	struct device *parent;
+};
+
+/**
+ * A root device
+ *
+ * Root devices are system buses such as PCI, EISA, etc.
+ *
+ */
+struct root_device {
+	/** Device chain
+	 *
+	 * A root device has a NULL parent field.
+	 */
+	struct device dev;
+	/** Root device driver */
+	struct root_driver *driver;
+};
+
+/** A root device driver */
+struct root_driver {
+	/**
+	 * Add root device
+	 *
+	 * @v rootdev	Root device
+	 * @ret rc	Return status code
+	 *
+	 * Called from probe_devices() for all root devices in the build.
+	 */
+	int ( * probe ) ( struct root_device *rootdev );
+	/**
+	 * Remove root device
+	 *
+	 * @v rootdev	Root device
+	 *
+	 * Called from remove_device() for all successfully-probed
+	 * root devices.
+	 */
+	void ( * remove ) ( struct root_device *rootdev );
+};
+
+/** Root device table */
+#define ROOT_DEVICES __table ( struct root_device, "root_devices" )
+
+/** Declare a root device */
+#define __root_device __table_entry ( ROOT_DEVICES, 01 )
+
+extern int device_keep_count;
+
+/**
+ * Prevent devices from being removed on shutdown
+ *
+ */
+static inline void devices_get ( void ) {
+	device_keep_count++;
+}
+
+/**
+ * Allow devices to be removed on shutdown
+ *
+ */
+static inline void devices_put ( void ) {
+	device_keep_count--;
+}
+
+extern struct device * identify_device ( struct interface *intf );
+#define identify_device_TYPE( object_type ) \
+	typeof ( struct device * ( object_type ) )
+
+#endif /* _IPXE_DEVICE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcp.h
new file mode 100644
index 0000000..148e3d6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcp.h
@@ -0,0 +1,652 @@
+#ifndef _IPXE_DHCP_H
+#define _IPXE_DHCP_H
+
+/** @file
+ *
+ * Dynamic Host Configuration Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/in.h>
+#include <ipxe/list.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/tables.h>
+#include <ipxe/uuid.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/uaccess.h>
+
+struct interface;
+struct dhcp_options;
+struct dhcp_packet;
+
+/** BOOTP/DHCP server port */
+#define BOOTPS_PORT 67
+
+/** BOOTP/DHCP client port */
+#define BOOTPC_PORT 68
+
+/** PXE server port */
+#define PXE_PORT 4011
+
+/** Construct a tag value for an encapsulated option
+ *
+ * This tag value can be passed to Etherboot functions when searching
+ * for DHCP options in order to search for a tag within an
+ * encapsulated options block.
+ */
+#define DHCP_ENCAP_OPT( encapsulator, encapsulated ) \
+	( ( (encapsulator) << 8 ) | (encapsulated) )
+/** Extract encapsulating option block tag from encapsulated tag value */
+#define DHCP_ENCAPSULATOR( encap_opt ) ( (encap_opt) >> 8 )
+/** Extract encapsulated option tag from encapsulated tag value */
+#define DHCP_ENCAPSULATED( encap_opt ) ( (encap_opt) & 0xff )
+/** Option is encapsulated */
+#define DHCP_IS_ENCAP_OPT( opt ) DHCP_ENCAPSULATOR( opt )
+
+/**
+ * @defgroup dhcpopts DHCP option tags
+ * @{
+ */
+
+/** Padding
+ *
+ * This tag does not have a length field; it is always only a single
+ * byte in length.
+ */
+#define DHCP_PAD 0
+
+/** Minimum normal DHCP option */
+#define DHCP_MIN_OPTION 1
+
+/** Subnet mask */
+#define DHCP_SUBNET_MASK 1
+
+/** Routers */
+#define DHCP_ROUTERS 3
+
+/** DNS servers */
+#define DHCP_DNS_SERVERS 6
+
+/** Syslog servers */
+#define DHCP_LOG_SERVERS 7
+
+/** Host name */
+#define DHCP_HOST_NAME 12
+
+/** Domain name */
+#define DHCP_DOMAIN_NAME 15
+
+/** Root path */
+#define DHCP_ROOT_PATH 17
+
+/** Vendor encapsulated options */
+#define DHCP_VENDOR_ENCAP 43
+
+/** PXE boot server discovery control */
+#define DHCP_PXE_DISCOVERY_CONTROL DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 6 )
+
+/** PXE boot server discovery control bits */
+enum dhcp_pxe_discovery_control {
+	/** Inhibit broadcast discovery */
+	PXEBS_NO_BROADCAST = 1,
+	/** Inhibit multicast discovery */
+	PXEBS_NO_MULTICAST = 2,
+	/** Accept only servers in DHCP_PXE_BOOT_SERVERS list */
+	PXEBS_NO_UNKNOWN_SERVERS = 4,
+	/** Skip discovery if filename present */
+	PXEBS_SKIP = 8,
+};
+
+/** PXE boot server multicast address */
+#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
+
+/** PXE boot servers */
+#define DHCP_PXE_BOOT_SERVERS DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 8 )
+
+/** PXE boot server */
+struct dhcp_pxe_boot_server {
+	/** "Type" */
+	uint16_t type;
+	/** Number of IPv4 addresses */
+	uint8_t num_ip;
+	/** IPv4 addresses */
+	struct in_addr ip[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu */
+#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
+
+/** PXE boot menu */
+struct dhcp_pxe_boot_menu {
+	/** "Type" */
+	uint16_t type;
+	/** Description length */
+	uint8_t desc_len;
+	/** Description */
+	char desc[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu prompt */
+#define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 )
+
+/** PXE boot menu prompt */
+struct dhcp_pxe_boot_menu_prompt {
+	/** Timeout
+	 *
+	 * A value of 0 means "time out immediately and select first
+	 * boot item, without displaying the prompt".  A value of 255
+	 * means "display menu immediately with no timeout".  Any
+	 * other value means "display prompt, wait this many seconds
+	 * for keypress, if key is F8, display menu, otherwise select
+	 * first boot item".
+	 */
+	uint8_t timeout;
+	/** Prompt to press F8 */
+	char prompt[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu item */
+#define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )
+
+/** PXE boot menu item */
+struct dhcp_pxe_boot_menu_item {
+	/** "Type"
+	 *
+	 * This field actually identifies the specific boot server (or
+	 * cluster of boot servers offering identical boot files).
+	 */
+	uint16_t type;
+	/** "Layer"
+	 *
+	 * Just don't ask.
+	 */
+	uint16_t layer;
+} __attribute__ (( packed ));
+
+/** Requested IP address */
+#define DHCP_REQUESTED_ADDRESS 50
+
+/** Lease time */
+#define DHCP_LEASE_TIME 51
+
+/** Option overloading
+ *
+ * The value of this option is the bitwise-OR of zero or more
+ * DHCP_OPTION_OVERLOAD_XXX constants.
+ */
+#define DHCP_OPTION_OVERLOAD 52
+
+/** The "file" field is overloaded to contain extra DHCP options */
+#define DHCP_OPTION_OVERLOAD_FILE 1
+
+/** The "sname" field is overloaded to contain extra DHCP options */
+#define DHCP_OPTION_OVERLOAD_SNAME 2
+
+/** DHCP message type */
+#define DHCP_MESSAGE_TYPE 53
+#define DHCPNONE 0
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+/** DHCP server identifier */
+#define DHCP_SERVER_IDENTIFIER 54
+
+/** Parameter request list */
+#define DHCP_PARAMETER_REQUEST_LIST 55
+
+/** Maximum DHCP message size */
+#define DHCP_MAX_MESSAGE_SIZE 57
+
+/** Vendor class identifier */
+#define DHCP_VENDOR_CLASS_ID 60
+
+/** Client identifier */
+#define DHCP_CLIENT_ID 61
+
+/** Client identifier */
+struct dhcp_client_id {
+	/** Link-layer protocol */
+	uint8_t ll_proto;
+	/** Link-layer address */
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
+} __attribute__ (( packed ));
+
+/** TFTP server name
+ *
+ * This option replaces the fixed "sname" field, when that field is
+ * used to contain overloaded options.
+ */
+#define DHCP_TFTP_SERVER_NAME 66
+
+/** Bootfile name
+ *
+ * This option replaces the fixed "file" field, when that field is
+ * used to contain overloaded options.
+ */
+#define DHCP_BOOTFILE_NAME 67
+
+/** User class identifier */
+#define DHCP_USER_CLASS_ID 77
+
+/** Client system architecture */
+#define DHCP_CLIENT_ARCHITECTURE 93
+
+/** Client network device interface */
+#define DHCP_CLIENT_NDI 94
+
+/** UUID client identifier */
+#define DHCP_CLIENT_UUID 97
+
+/** UUID client identifier */
+struct dhcp_client_uuid {
+	/** Identifier type */
+	uint8_t type;
+	/** UUID */
+	union uuid uuid;
+} __attribute__ (( packed ));
+
+#define DHCP_CLIENT_UUID_TYPE 0
+
+/** Etherboot-specific encapsulated options
+ *
+ * This encapsulated options field is used to contain all options
+ * specific to Etherboot (i.e. not assigned by IANA or other standards
+ * bodies).
+ */
+#define DHCP_EB_ENCAP 175
+
+/** Priority of this options block
+ *
+ * This is a signed 8-bit integer field indicating the priority of
+ * this block of options.  It can be used to specify the relative
+ * priority of multiple option blocks (e.g. options from non-volatile
+ * storage versus options from a DHCP server).
+ */
+#define DHCP_EB_PRIORITY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x01 )
+
+/** "Your" IP address
+ *
+ * This option is used internally to contain the value of the "yiaddr"
+ * field, in order to provide a consistent approach to storing and
+ * processing options.  It should never be present in a DHCP packet.
+ */
+#define DHCP_EB_YIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x02 )
+
+/** "Server" IP address
+ *
+ * This option is used internally to contain the value of the "siaddr"
+ * field, in order to provide a consistent approach to storing and
+ * processing options.  It should never be present in a DHCP packet.
+ */
+#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x03 )
+
+/** Keep SAN drive registered
+ *
+ * If set to a non-zero value, iPXE will not detach any SAN drive
+ * after failing to boot from it.  (This option is required in order
+ * to perform an installation direct to an iSCSI target.)
+ */
+#define DHCP_EB_KEEP_SAN DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x08 )
+
+/** Skip booting from SAN drive
+ *
+ * If set to a non-zero value, iPXE will skip booting from any SAN
+ * drive.  (This option is sometimes required in conjunction with @c
+ * DHCP_EB_KEEP_SAN in order to perform an installation direct to an
+ * iSCSI target.)
+ */
+#define DHCP_EB_SKIP_SAN_BOOT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x09 )
+
+/*
+ * Tags in the range 0x10-0x4f are reserved for feature markers
+ *
+ */
+
+/** Scriptlet
+ *
+ * If a scriptlet exists, it will be executed in place of the usual
+ * call to autoboot()
+ */
+#define DHCP_EB_SCRIPTLET DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x51 )
+
+/** Skip PXE DHCP protocol extensions such as ProxyDHCP
+ *
+ * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers
+ * and will ignore any PXE-specific DHCP options that it receives.
+ */
+#define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )
+
+/** Network device descriptor
+ *
+ * Byte 0 is the bus type ID; remaining bytes depend on the bus type.
+ *
+ * PCI devices:
+ * Byte 0 : 1 (PCI)
+ * Byte 1 : PCI vendor ID MSB
+ * Byte 2 : PCI vendor ID LSB
+ * Byte 3 : PCI device ID MSB
+ * Byte 4 : PCI device ID LSB
+ */
+#define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )
+
+/** Network device descriptor */
+struct dhcp_netdev_desc {
+	/** Bus type ID */
+	uint8_t type;
+	/** Vendor ID */
+	uint16_t vendor;
+	/** Device ID */
+	uint16_t device;
+} __attribute__ (( packed ));
+
+/** Use cached network settings
+ *
+ * Cached network settings may be available from a prior DHCP request
+ * (if running as a PXE NBP), non-volatile storage on the NIC, or
+ * settings set via the command line or an embedded image. If this
+ * flag is not set, it will be assumed that those sources are
+ * insufficient and that DHCP should still be run when autobooting.
+ */
+#define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 )
+
+/** BIOS drive number
+ *
+ * This is the drive number for a drive emulated via INT 13.  0x80 is
+ * the first hard disk, 0x81 is the second hard disk, etc.
+ */
+#define DHCP_EB_BIOS_DRIVE DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbd )
+
+/** Username
+ *
+ * This will be used as the username for any required authentication.
+ * It is expected that this option's value will be held in
+ * non-volatile storage, rather than transmitted as part of a DHCP
+ * packet.
+ */
+#define DHCP_EB_USERNAME DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbe )
+
+/** Password
+ *
+ * This will be used as the password for any required authentication.
+ * It is expected that this option's value will be held in
+ * non-volatile storage, rather than transmitted as part of a DHCP
+ * packet.
+ */
+#define DHCP_EB_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbf )
+
+/** Reverse username
+ *
+ * This will be used as the reverse username (i.e. the username
+ * provided by the server) for any required authentication.  It is
+ * expected that this option's value will be held in non-volatile
+ * storage, rather than transmitted as part of a DHCP packet.
+ */
+#define DHCP_EB_REVERSE_USERNAME DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc0 )
+
+/** Reverse password
+ *
+ * This will be used as the reverse password (i.e. the password
+ * provided by the server) for any required authentication.  It is
+ * expected that this option's value will be held in non-volatile
+ * storage, rather than transmitted as part of a DHCP packet.
+ */
+#define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 )
+
+/** iPXE version number */
+#define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb )
+
+/** iSCSI primary target IQN */
+#define DHCP_ISCSI_PRIMARY_TARGET_IQN 201
+
+/** iSCSI secondary target IQN */
+#define DHCP_ISCSI_SECONDARY_TARGET_IQN 202
+
+/** iSCSI initiator IQN */
+#define DHCP_ISCSI_INITIATOR_IQN 203
+
+/** Maximum normal DHCP option */
+#define DHCP_MAX_OPTION 254
+
+/** End of options
+ *
+ * This tag does not have a length field; it is always only a single
+ * byte in length.
+ */
+#define DHCP_END 255
+
+/** @} */
+
+/**
+ * Count number of arguments to a variadic macro
+ *
+ * This rather neat, non-iterative solution is courtesy of Laurent
+ * Deniau.
+ *
+ */
+#define _VA_ARG_COUNT(  _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,		\
+		        _9, _10, _11, _12, _13, _14, _15, _16,		\
+		       _17, _18, _19, _20, _21, _22, _23, _24,		\
+		       _25, _26, _27, _28, _29, _30, _31, _32,		\
+		       _33, _34, _35, _36, _37, _38, _39, _40,		\
+		       _41, _42, _43, _44, _45, _46, _47, _48,		\
+		       _49, _50, _51, _52, _53, _54, _55, _56,		\
+		       _57, _58, _59, _60, _61, _62, _63,   N, ... ) N
+#define VA_ARG_COUNT( ... )						\
+	_VA_ARG_COUNT ( __VA_ARGS__, 					\
+			63, 62, 61, 60, 59, 58, 57, 56,			\
+			55, 54, 53, 52, 51, 50, 49, 48,			\
+			47, 46, 45, 44, 43, 42, 41, 40,			\
+			39, 38, 37, 36, 35, 34, 33, 32,			\
+			31, 30, 29, 28, 27, 26, 25, 24,			\
+			23, 22, 21, 20, 19, 18, 17, 16,			\
+			15, 14, 13, 12, 11, 10,  9,  8,			\
+			 7,  6,  5,  4,  3,  2,  1,  0 )
+
+/** Construct a DHCP option from a list of bytes */
+#define DHCP_OPTION( ... ) VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__
+
+/** Construct a DHCP option from a list of characters */
+#define DHCP_STRING( ... ) DHCP_OPTION ( __VA_ARGS__ )
+
+/** Construct a byte-valued DHCP option */
+#define DHCP_BYTE( value ) DHCP_OPTION ( value )
+
+/** Construct a word-valued DHCP option */
+#define DHCP_WORD( value ) DHCP_OPTION ( ( ( (value) >> 8 ) & 0xff ),   \
+					 ( ( (value) >> 0 ) & 0xff ) )
+
+/** Construct a dword-valued DHCP option */
+#define DHCP_DWORD( value ) DHCP_OPTION ( ( ( (value) >> 24 ) & 0xff ), \
+					  ( ( (value) >> 16 ) & 0xff ), \
+					  ( ( (value) >> 8  ) & 0xff ), \
+					  ( ( (value) >> 0  ) & 0xff ) )
+
+/** Construct a DHCP encapsulated options field */
+#define DHCP_ENCAP( ... ) DHCP_OPTION ( __VA_ARGS__, DHCP_END )
+
+/**
+ * A DHCP option
+ *
+ * DHCP options consist of a mandatory tag, a length field that is
+ * mandatory for all options except @c DHCP_PAD and @c DHCP_END, and a
+ * payload.  
+ */
+struct dhcp_option {
+	/** Tag
+	 *
+	 * Must be a @c DHCP_XXX value.
+	 */
+	uint8_t tag;
+	/** Length
+	 *
+	 * This is the length of the data field (i.e. excluding the
+	 * tag and length fields).  For the two tags @c DHCP_PAD and
+	 * @c DHCP_END, the length field is implicitly zero and is
+	 * also missing, i.e. these DHCP options are only a single
+	 * byte in length.
+	 */
+	uint8_t len;
+	/** Option data */
+	uint8_t data[0];
+} __attribute__ (( packed ));
+
+/**
+ * Length of a DHCP option header
+ *
+ * The header is the portion excluding the data, i.e. the tag and the
+ * length.
+ */
+#define DHCP_OPTION_HEADER_LEN ( offsetof ( struct dhcp_option, data ) )
+
+/** Maximum length for a single DHCP option */
+#define DHCP_MAX_LEN 0xff
+
+/**
+ * A DHCP header
+ *
+ */
+struct dhcphdr {
+	/** Operation
+	 *
+	 * This must be either @c BOOTP_REQUEST or @c BOOTP_REPLY.
+	 */
+	uint8_t op;
+	/** Hardware address type
+	 *
+	 * This is an ARPHRD_XXX constant.  Note that ARPHRD_XXX
+	 * constants are nominally 16 bits wide; this could be
+	 * considered to be a bug in the BOOTP/DHCP specification.
+	 */
+	uint8_t htype;
+	/** Hardware address length */
+	uint8_t hlen;
+	/** Number of hops from server */
+	uint8_t hops;
+	/** Transaction ID */
+	uint32_t xid;
+	/** Seconds since start of acquisition */
+	uint16_t secs;
+	/** Flags */
+	uint16_t flags;
+	/** "Client" IP address
+	 *
+	 * This is filled in if the client already has an IP address
+	 * assigned and can respond to ARP requests.
+	 */
+	struct in_addr ciaddr;
+	/** "Your" IP address
+	 *
+	 * This is the IP address assigned by the server to the client.
+	 */
+	struct in_addr yiaddr;
+	/** "Server" IP address
+	 *
+	 * This is the IP address of the next server to be used in the
+	 * boot process.
+	 */
+	struct in_addr siaddr;
+	/** "Gateway" IP address
+	 *
+	 * This is the IP address of the DHCP relay agent, if any.
+	 */
+	struct in_addr giaddr;
+	/** Client hardware address */
+	uint8_t chaddr[16];
+	/** Server host name (null terminated)
+	 *
+	 * This field may be overridden and contain DHCP options
+	 */
+	char sname[64];
+	/** Boot file name (null terminated)
+	 *
+	 * This field may be overridden and contain DHCP options
+	 */
+	char file[128];
+	/** DHCP magic cookie
+	 *
+	 * Must have the value @c DHCP_MAGIC_COOKIE.
+	 */
+	uint32_t magic;
+	/** DHCP options
+	 *
+	 * Variable length; extends to the end of the packet.  Minimum
+	 * length (for the sake of sanity) is 1, to allow for a single
+	 * @c DHCP_END tag.
+	 */
+	uint8_t options[0];
+};
+
+/** Opcode for a request from client to server */
+#define BOOTP_REQUEST 1
+
+/** Opcode for a reply from server to client */
+#define BOOTP_REPLY 2
+
+/** BOOTP reply must be broadcast
+ *
+ * Clients that cannot accept unicast BOOTP replies must set this
+ * flag.
+ */
+#define BOOTP_FL_BROADCAST 0x8000
+
+/** DHCP magic cookie */
+#define DHCP_MAGIC_COOKIE 0x63825363UL
+
+/** DHCP minimum packet length
+ *
+ * This is the mandated minimum packet length that a DHCP participant
+ * must be prepared to receive.
+ */
+#define DHCP_MIN_LEN 552
+
+/** Timeouts for sending DHCP packets */
+#define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC )
+#define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
+
+/** Maximum time that we will wait for ProxyDHCP responses */
+#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
+
+/** Maximum time that we will wait for Boot Server responses */
+#define PXEBS_MAX_TIMEOUT ( 3 * TICKS_PER_SEC )
+
+/** Settings block name used for DHCP responses */
+#define DHCP_SETTINGS_NAME "dhcp"
+
+/** Settings block name used for ProxyDHCP responses */
+#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
+
+/** Setting block name used for BootServerDHCP responses */
+#define PXEBS_SETTINGS_NAME "pxebs"
+
+extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
+				  uint16_t *flags );
+extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
+				struct net_device *netdev, uint8_t msgtype,
+				const void *options, size_t options_len,
+				void *data, size_t max_len );
+extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
+				 struct net_device *netdev,
+				 unsigned int msgtype, struct in_addr ciaddr,
+				 void *data, size_t max_len );
+extern int start_dhcp ( struct interface *job, struct net_device *netdev );
+extern int start_pxebs ( struct interface *job, struct net_device *netdev,
+			 unsigned int pxe_type );
+
+/* In environments that can provide cached DHCP packets, this function
+ * should look for such a packet and call store_cached_dhcpack() with
+ * it if it exists.
+ */
+extern void get_cached_dhcpack ( void );
+
+extern void store_cached_dhcpack ( userptr_t data, size_t len );
+
+#endif /* _IPXE_DHCP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcpopts.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcpopts.h
new file mode 100644
index 0000000..c5af5d7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcpopts.h
@@ -0,0 +1,43 @@
+#ifndef _IPXE_DHCPOPTS_H
+#define _IPXE_DHCPOPTS_H
+
+/** @file
+ *
+ * DHCP options
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** A DHCP options block */
+struct dhcp_options {
+	/** Option block raw data */
+	void *data;
+	/** Option block used length */
+	size_t used_len;
+	/** Option block allocated length */
+	size_t alloc_len;
+	/** Reallocate option block raw data
+	 *
+	 * @v options		DHCP option block
+	 * @v len		New length
+	 * @ret rc		Return status code
+	 */
+	int ( * realloc ) ( struct dhcp_options *options, size_t len );
+};
+
+extern int dhcpopt_applies ( unsigned int tag );
+extern int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
+			   const void *data, size_t len );
+extern int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
+			   void *data, size_t len );
+extern void dhcpopt_init ( struct dhcp_options *options,
+			   void *data, size_t alloc_len,
+			   int ( * realloc ) ( struct dhcp_options *options,
+					       size_t len ) );
+extern void dhcpopt_update_used_len ( struct dhcp_options *options );
+extern int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len );
+
+#endif /* _IPXE_DHCPOPTS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcppkt.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcppkt.h
new file mode 100644
index 0000000..3179a6b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dhcppkt.h
@@ -0,0 +1,71 @@
+#ifndef _IPXE_DHCPPKT_H
+#define _IPXE_DHCPPKT_H
+
+/** @file
+ *
+ * DHCP packets
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
+#include <ipxe/refcnt.h>
+
+/**
+ * A DHCP packet
+ *
+ */
+struct dhcp_packet {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** The DHCP packet contents */
+	struct dhcphdr *dhcphdr;
+	/** DHCP options */
+	struct dhcp_options options;
+	/** Settings interface */
+	struct settings settings;
+};
+
+/**
+ * Increment reference count on DHCP packet
+ *
+ * @v dhcppkt		DHCP packet
+ * @ret dhcppkt		DHCP packet
+ */
+static inline __attribute__ (( always_inline )) struct dhcp_packet *
+dhcppkt_get ( struct dhcp_packet *dhcppkt ) {
+	ref_get ( &dhcppkt->refcnt );
+	return dhcppkt;
+}
+
+/**
+ * Decrement reference count on DHCP packet
+ *
+ * @v dhcppkt		DHCP packet
+ */
+static inline __attribute__ (( always_inline )) void
+dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
+	ref_put ( &dhcppkt->refcnt );
+}
+
+/**
+ * Get used length of DHCP packet
+ *
+ * @v dhcppkt		DHCP packet
+ * @ret len		Used length
+ */
+static inline int dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
+	return ( offsetof ( struct dhcphdr, options ) +
+		 dhcppkt->options.used_len );
+}
+
+extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
+			   const void *data, size_t len );
+extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
+			   void *data, size_t len );
+extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, 
+			   struct dhcphdr *data, size_t len );
+
+#endif /* _IPXE_DHCPPKT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/dns.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dns.h
new file mode 100644
index 0000000..1c42760
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/dns.h
@@ -0,0 +1,92 @@
+#ifndef _IPXE_DNS_H
+#define _IPXE_DNS_H
+
+/** @file
+ *
+ * DNS protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/in.h>
+
+/*
+ * Constants
+ *
+ */
+
+#define DNS_TYPE_A		1
+#define DNS_TYPE_CNAME		5
+#define DNS_TYPE_ANY		255
+
+#define DNS_CLASS_IN		1
+#define DNS_CLASS_CS		2
+#define DNS_CLASS_CH		3
+#define DNS_CLASS_HS		4
+
+#define DNS_FLAG_QUERY		( 0x00 << 15 )
+#define DNS_FLAG_RESPONSE	( 0x01 << 15 )
+#define DNS_FLAG_QR(flags)	( (flags) & ( 0x01 << 15 ) )
+#define DNS_FLAG_OPCODE_QUERY	( 0x00 << 11 )
+#define DNS_FLAG_OPCODE_IQUERY	( 0x01 << 11 )
+#define DNS_FLAG_OPCODE_STATUS	( 0x02 << 11 )
+#define DNS_FLAG_OPCODE(flags)	( (flags) & ( 0x0f << 11 ) )
+#define DNS_FLAG_RD		( 0x01 << 8 )
+#define DNS_FLAG_RA		( 0x01 << 7 )
+#define DNS_FLAG_RCODE_OK	( 0x00 << 0 )
+#define DNS_FLAG_RCODE_NX	( 0x03 << 0 )
+#define DNS_FLAG_RCODE(flags)	( (flags) & ( 0x0f << 0 ) )
+
+#define	DNS_PORT		53
+#define	DNS_MAX_RETRIES		3
+#define	DNS_MAX_CNAME_RECURSION	0x30
+
+/*
+ * DNS protocol structures
+ *
+ */
+struct dns_header {
+	uint16_t	id;
+	uint16_t	flags;
+	uint16_t	qdcount;
+	uint16_t	ancount;
+	uint16_t	nscount;
+	uint16_t	arcount;
+} __attribute__ (( packed ));
+
+struct dns_query_info {
+	uint16_t	qtype;
+	uint16_t	qclass;
+} __attribute__ (( packed ));
+
+struct dns_query {
+	struct dns_header dns;
+	char		payload[ 256 + sizeof ( struct dns_query_info ) ];
+} __attribute__ (( packed ));
+
+struct dns_rr_info_common {
+	uint16_t	type;
+	uint16_t	class;
+	uint32_t	ttl;
+	uint16_t	rdlength;
+} __attribute__ (( packed ));
+
+struct dns_rr_info_a {
+	struct dns_rr_info_common common;
+	struct in_addr in_addr;
+} __attribute__ (( packed ));
+
+struct dns_rr_info_cname {
+	struct dns_rr_info_common common;
+	char cname[0];
+} __attribute__ (( packed ));
+
+union dns_rr_info {
+	struct dns_rr_info_common common;
+	struct dns_rr_info_a a;
+	struct dns_rr_info_cname cname;
+};
+
+#endif /* _IPXE_DNS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/downloader.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/downloader.h
new file mode 100644
index 0000000..a7efa3f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/downloader.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_DOWNLOADER_H
+#define _IPXE_DOWNLOADER_H
+
+/** @file
+ *
+ * Image downloader
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct interface;
+struct image;
+
+extern int create_downloader ( struct interface *job, struct image *image,
+			       int type, ... );
+
+#endif /* _IPXE_DOWNLOADER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/eapol.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eapol.h
new file mode 100644
index 0000000..3fad442
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eapol.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _IPXE_EAPOL_H
+#define _IPXE_EAPOL_H
+
+/** @file
+ *
+ * Definitions for EAPOL (Extensible Authentication Protocol over
+ * LANs) frames. Definitions for the packets usually encapsulated in
+ * them are elsewhere.
+ */
+
+#include <ipxe/tables.h>
+#include <stdint.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+
+/**
+ * @defgroup eapol_type EAPOL archetype identifiers
+ * @{
+ */
+#define EAPOL_TYPE_EAP		0 /**< EAP authentication handshake packet */
+#define EAPOL_TYPE_START	1 /**< Request by Peer to begin (no data) */
+#define EAPOL_TYPE_LOGOFF	2 /**< Request by Peer to terminate (no data) */
+#define EAPOL_TYPE_KEY		3 /**< EAPOL-Key packet */
+/** @} */
+
+/** Expected EAPOL version field value
+ *
+ * Version 2 is often seen and has no format differences from version 1;
+ * however, many older APs will completely drop version-2 packets, so
+ * we advertise ourselves as version 1.
+ */
+#define EAPOL_THIS_VERSION	1
+
+/** Length of an EAPOL frame header */
+#define EAPOL_HDR_LEN		4
+
+/** An EAPOL frame
+ *
+ * This may encapsulate an eap_pkt, an eapol_key_pkt, or a Start or
+ * Logoff request with no data attached. It is transmitted directly in
+ * an Ethernet frame, with no IP packet header.
+ */
+struct eapol_frame
+{
+	/** EAPOL version identifier, always 1 */
+	u8 version;
+
+	/** EAPOL archetype identifier indicating format of payload */
+	u8 type;
+
+	/** Length of payload, in network byte order */
+	u16 length;
+
+	/** Payload, if @a type is EAP or EAPOL-Key */
+	u8 data[0];
+} __attribute__ (( packed ));
+
+
+/** An EAPOL frame type handler
+ *
+ * Normally there will be at most two of these, one for EAP and one
+ * for EAPOL-Key frames. The EAPOL interface code handles Start and
+ * Logoff directly.
+ */
+struct eapol_handler
+{
+	/** EAPOL archetype identifier for payload this handler will handle */
+	u8 type;
+
+	/** Receive EAPOL-encapsulated packet of specified type
+	 *
+	 * @v iob	I/O buffer containing packet payload
+	 * @v netdev	Network device from which packet was received
+	 * @V ll_dest	Destination link-layer address
+	 * @v ll_source	Source link-layer address
+	 * @ret rc	Return status code
+	 *
+	 * The I/O buffer will have the EAPOL header pulled off it, so
+	 * @c iob->data points to the first byte of the payload.
+	 *
+	 * This function takes ownership of the I/O buffer passed to it.
+	 */
+	int ( * rx ) ( struct io_buffer *iob, struct net_device *netdev,
+		       const void *ll_dest, const void *ll_source );
+};
+
+#define EAPOL_HANDLERS	__table ( struct eapol_handler, "eapol_handlers" )
+#define __eapol_handler	__table_entry ( EAPOL_HANDLERS, 01 )
+
+
+extern struct net_protocol eapol_protocol __net_protocol;
+
+
+#endif /* _IPXE_EAPOL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/edd.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/edd.h
new file mode 100644
index 0000000..0c25593
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/edd.h
@@ -0,0 +1,193 @@
+#ifndef _IPXE_EDD_H
+#define _IPXE_EDD_H
+
+/** @file
+ *
+ * Enhanced Disk Drive specification
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/interface.h>
+
+/** An EDD host bus type */
+struct edd_host_bus_type {
+	/** Type */
+	uint32_t type;
+} __attribute__ (( packed ));
+
+/** EDD bus type */
+#define EDD_BUS_TYPE_FIXED( a, b, c, d, ... )				    \
+	( ( (a) << 0 ) | ( (b) << 8 ) | ( (c) << 16 ) | ( (d) << 24 ) )
+#define EDD_BUS_TYPE( ... )						    \
+	EDD_BUS_TYPE_FIXED ( __VA_ARGS__, ' ', ' ', ' ', ' ' )
+/** EDD PCI bus type */
+#define EDD_BUS_TYPE_PCI EDD_BUS_TYPE ( 'P', 'C', 'I' )
+/** EDD ISA bus type */
+#define EDD_BUS_TYPE_ISA EDD_BUS_TYPE ( 'I', 'S', 'A' )
+/** EDD PCI-X bus type */
+#define EDD_BUS_TYPE_PCIX EDD_BUS_TYPE ( 'P', 'C', 'I', 'X' )
+/** EDD Infiniband bus type */
+#define EDD_BUS_TYPE_IBND EDD_BUS_TYPE ( 'I', 'B', 'N', 'D' )
+/** EDD PCI Express bus type */
+#define EDD_BUS_TYPE_XPRS EDD_BUS_TYPE ( 'X', 'P', 'R', 'S' )
+/** EDD HyperTransport bus type */
+#define EDD_BUS_TYPE_HTPT EDD_BUS_TYPE ( 'H', 'T', 'P', 'T' )
+
+/** An EDD interface type */
+struct edd_interface_type {
+	/** Type */
+	uint64_t type;
+} __attribute__ (( packed ));
+
+/** EDD interface type */
+#define EDD_INTF_TYPE_FIXED( a, b, c, d, e, f, g, h, ... )		    \
+	( ( ( ( uint64_t ) (a) ) <<  0 ) | ( ( ( uint64_t ) (b) ) <<  8 ) | \
+	  ( ( ( uint64_t ) (c) ) << 16 ) | ( ( ( uint64_t ) (d) ) << 24 ) | \
+	  ( ( ( uint64_t ) (e) ) << 32 ) | ( ( ( uint64_t ) (f) ) << 40 ) | \
+	  ( ( ( uint64_t ) (g) ) << 48 ) | ( ( ( uint64_t ) (h) ) << 56 ) )
+#define EDD_INTF_TYPE( ... )						    \
+	EDD_INTF_TYPE_FIXED ( __VA_ARGS__,				    \
+			      ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' )
+/** EDD ATA interface type */
+#define EDD_INTF_TYPE_ATA EDD_INTF_TYPE ( 'A', 'T', 'A' )
+/** EDD ATAPI interface type */
+#define EDD_INTF_TYPE_ATAPI EDD_INTF_TYPE ( 'A', 'T', 'A', 'P', 'I' )
+/** EDD SCSI interface type */
+#define EDD_INTF_TYPE_SCSI EDD_INTF_TYPE ( 'S', 'C', 'S', 'I' )
+/** EDD USB interface type */
+#define EDD_INTF_TYPE_USB EDD_INTF_TYPE ( 'U', 'S', 'B' )
+/** EDD 1394 interface type */
+#define EDD_INTF_TYPE_1394 EDD_INTF_TYPE ( '1', '3', '9', '4' )
+/** EDD Fibre Channel interface type */
+#define EDD_INTF_TYPE_FIBRE EDD_INTF_TYPE ( 'F', 'I', 'B', 'R', 'E' )
+/** EDD I2O interface type */
+#define EDD_INTF_TYPE_I2O EDD_INTF_TYPE ( 'I', '2', 'O' )
+/** EDD RAID interface type */
+#define EDD_INTF_TYPE_RAID EDD_INTF_TYPE ( 'R', 'A', 'I', 'D' )
+/** EDD SATA interface type */
+#define EDD_INTF_TYPE_SATA EDD_INTF_TYPE ( 'S', 'A', 'T', 'A' )
+/** EDD SAS interface type */
+#define EDD_INTF_TYPE_SAS EDD_INTF_TYPE ( 'S', 'A', 'S' )
+
+/** An EDD interface path */
+union edd_interface_path {
+	/** Legacy bus type */
+	struct {
+		/** Base address */
+		uint16_t base;
+	} __attribute__ (( packed )) legacy;
+	/** PCI, PCI-X, PCI Express, or HyperTransport bus type */
+	struct {
+		/** Bus */
+		uint8_t bus;
+		/** Slot */
+		uint8_t slot;
+		/** Function */
+		uint8_t function;
+		/** Channel number */
+		uint8_t channel;
+	} __attribute__ (( packed )) pci;
+	/** Padding */
+	uint8_t pad[8];
+} __attribute__ (( packed ));
+
+/** An EDD device path */
+union edd_device_path {
+	/** ATA interface type */
+	struct {
+		/** Slave */
+		uint8_t slave;
+	} __attribute__ (( packed )) ata;
+	/** ATAPI interface type */
+	struct {
+		/** Slave */
+		uint8_t slave;
+		/** Logical Unit Number */
+		uint8_t lun;
+	} __attribute__ (( packed )) atapi;
+	/** SCSI interface type */
+	struct {
+		/** SCSI ID */
+		uint16_t id;
+		/** Logical Unit Number */
+		uint64_t lun;
+	} __attribute__ (( packed )) scsi;
+	/** USB interface type */
+	struct {
+		/** Serial number */
+		uint64_t serial;
+	} __attribute__ (( packed )) usb;
+	/** IEEE1394 interface type */
+	struct {
+		/** GUID */
+		uint64_t guid;
+	} __attribute__ (( packed )) ieee1394;
+	/** Fibre Channel interface type */
+	struct {
+		/** WWN */
+		uint64_t wwn;
+		/** Logical Unit Number */
+		uint64_t lun;
+	} __attribute__ (( packed )) fibre;
+	/** I2O interface type */
+	struct {
+		/** Identity tag */
+		uint64_t tag;
+	} __attribute__ (( packed )) i2o;
+	/** RAID interface type */
+	struct {
+		/** Array number */
+		uint32_t array;
+	} __attribute__ (( packed )) raid;
+	/** SATA interface type */
+	struct {
+		/** Port number */
+		uint8_t port;
+		/** Port multiplier number */
+		uint8_t multiplier;
+	} __attribute__ (( packed )) sata;
+	/** SAS interface type */
+	struct {
+		/** Address */
+		uint64_t address;
+	} __attribute__ (( packed )) sas;
+	/** Padding */
+	uint8_t pad[16];
+} __attribute__ (( packed ));
+
+/** EDD device path information */
+struct edd_device_path_information {
+	/** Key */
+	uint16_t key;
+	/** Length of this structure */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved_a[3];
+	/** Host bus type */
+	struct edd_host_bus_type host_bus_type;
+	/** Interface type */
+	struct edd_interface_type interface_type;
+	/** Interface path */
+	union edd_interface_path interface_path;
+	/** Device path */
+	union edd_device_path device_path;
+	/** Reserved */
+	uint8_t reserved_b;
+	/** Checksum */
+	uint8_t checksum;
+} __attribute__ (( packed ));
+
+/** EDD device path information key */
+#define EDD_DEVICE_PATH_INFO_KEY 0xbedd
+
+extern int edd_describe ( struct interface *intf,
+			  struct edd_interface_type *type,
+			  union edd_device_path *path );
+#define edd_describe_TYPE( object_type )				\
+	typeof ( int ( object_type, struct edd_interface_type *type,	\
+		       union edd_device_path *path ) )
+
+#endif /* _IPXE_EDD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/editbox.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/editbox.h
new file mode 100644
index 0000000..9122dbb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/editbox.h
@@ -0,0 +1,61 @@
+#ifndef _IPXE_EDITBOX_H
+#define _IPXE_EDITBOX_H
+
+/** @file
+ *
+ * Editable text box widget
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <curses.h>
+#include <ipxe/editstring.h>
+
+/** An editable text box widget */
+struct edit_box {
+	/** Editable string */
+	struct edit_string string;
+	/** Containing window */
+	WINDOW *win;
+	/** Row */
+	unsigned int row;
+	/** Starting column */
+	unsigned int col;
+	/** Width */
+	unsigned int width;
+	/** First displayed character */
+	unsigned int first;
+	/** Flags */
+	unsigned int flags;
+};
+
+/** Editable text box widget flags */
+enum edit_box_flags {
+	/** Show stars instead of contents (for password widgets) */
+	EDITBOX_STARS = 0x0001,
+};
+
+extern void init_editbox ( struct edit_box *box, char *buf, size_t len,
+			   WINDOW *win, unsigned int row, unsigned int col,
+			   unsigned int width, unsigned int flags )
+			   __attribute__ (( nonnull (1, 2) ));
+extern void draw_editbox ( struct edit_box *box ) __nonnull;
+static inline int edit_editbox ( struct edit_box *box, int key ) __nonnull;
+
+/**
+ * Edit text box widget
+ *
+ * @v box		Editable text box widget
+ * @v key		Key pressed by user
+ * @ret key		Key returned to application, or zero
+ *
+ * You must call draw_editbox() to update the display after calling
+ * edit_editbox().
+ *
+ */
+static inline int edit_editbox ( struct edit_box *box, int key ) {
+	return edit_string ( &box->string, key );
+}
+
+#endif /* _IPXE_EDITBOX_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/editstring.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/editstring.h
new file mode 100644
index 0000000..2ef546a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/editstring.h
@@ -0,0 +1,48 @@
+#ifndef _IPXE_EDITSTRING_H
+#define _IPXE_EDITSTRING_H
+
+/** @file
+ *
+ * Editable strings
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** An editable string */
+struct edit_string {
+	/** Buffer for string */
+	char *buf;
+	/** Size of buffer (including terminating NUL) */
+	size_t len;
+	/** Cursor position */
+	unsigned int cursor;
+
+	/* The following items are the edit history */
+
+	/** Last cursor position */
+	unsigned int last_cursor;
+	/** Start of modified portion of string */
+	unsigned int mod_start;
+	/** End of modified portion of string */
+	unsigned int mod_end;
+};
+
+/**
+ * Initialise editable string
+ *
+ * @v string		Editable string
+ * @v buf		Buffer for string
+ * @v len		Length of buffer
+ */
+static inline void init_editstring ( struct edit_string *string, char *buf,
+				     size_t len ) {
+	string->buf = buf;
+	string->len = len;
+}
+
+extern void replace_string ( struct edit_string *string,
+			     const char *replacement ) __nonnull;
+extern int edit_string ( struct edit_string *string, int key ) __nonnull;
+
+#endif /* _IPXE_EDITSTRING_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Base.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Base.h
new file mode 100644
index 0000000..999b414
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Base.h
@@ -0,0 +1,965 @@
+/** @file
+  Root include file for Mde Package Base type modules
+
+  This is the include file for any module of type base. Base modules only use
+  types defined via this include file and can be ported easily to any
+  environment. There are a set of base libraries in the Mde Package that can
+  be used to implement base modules.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __BASE_H__
+#define __BASE_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// Include processor specific binding
+//
+#include <ipxe/efi/ProcessorBind.h>
+
+
+/**
+  Verifies the storage size of a given data type.
+
+  This macro generates a divide by zero error or a zero size array declaration in
+  the preprocessor if the size is incorrect.  These are declared as "extern" so
+  the space for these arrays will not be in the modules.
+
+  @param  TYPE  The date type to determine the size of.
+  @param  Size  The expected size for the TYPE.
+
+**/
+#define VERIFY_SIZE_OF(TYPE, Size) extern UINT8 _VerifySizeof##TYPE[(sizeof(TYPE) == (Size)) / (sizeof(TYPE) == (Size))]
+
+//
+// Verify that ProcessorBind.h produced UEFI Data Types that are compliant with
+// Section 2.3.1 of the UEFI 2.3 Specification.
+//
+VERIFY_SIZE_OF (BOOLEAN, 1);
+VERIFY_SIZE_OF (INT8, 1);
+VERIFY_SIZE_OF (UINT8, 1);
+VERIFY_SIZE_OF (INT16, 2);
+VERIFY_SIZE_OF (UINT16, 2);
+VERIFY_SIZE_OF (INT32, 4);
+VERIFY_SIZE_OF (UINT32, 4);
+VERIFY_SIZE_OF (INT64, 8);
+VERIFY_SIZE_OF (UINT64, 8);
+VERIFY_SIZE_OF (CHAR8, 1);
+VERIFY_SIZE_OF (CHAR16, 2);
+
+//
+// The Microsoft* C compiler can removed references to unreferenced data items
+//  if the /OPT:REF linker option is used. We defined a macro as this is a
+//  a non standard extension
+//
+#if defined(_MSC_EXTENSIONS) && !defined (MDE_CPU_EBC)
+  ///
+  /// Remove global variable from the linked image if there are no references to
+  /// it after all compiler and linker optimizations have been performed.
+  ///
+  ///
+  #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany)
+#else
+  ///
+  /// Remove the global variable from the linked image if there are no references
+  ///  to it after all compiler and linker optimizations have been performed.
+  ///
+  ///
+  #define GLOBAL_REMOVE_IF_UNREFERENCED
+#endif
+
+//
+// For symbol name in GNU assembly code, an extra "_" is necessary
+//
+#if defined(__GNUC__)
+  ///
+  /// Private worker functions for ASM_PFX()
+  ///
+  #define _CONCATENATE(a, b)  __CONCATENATE(a, b)
+  #define __CONCATENATE(a, b) a ## b
+
+  ///
+  /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix
+  /// on symbols in assembly language.
+  ///
+  #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name)
+#endif
+
+#if __APPLE__
+  //
+  // Apple extension that is used by the linker to optimize code size
+  // with assembly functions. Put at the end of your .S files
+  //
+  #define ASM_FUNCTION_REMOVE_IF_UNREFERENCED  .subsections_via_symbols
+#else
+  #define ASM_FUNCTION_REMOVE_IF_UNREFERENCED
+#endif
+
+#ifdef __CC_ARM
+  //
+  // Older RVCT ARM compilers don't fully support #pragma pack and require __packed
+  // as a prefix for the structure.
+  //
+  #define PACKED  __packed
+#else
+  #define PACKED
+#endif
+
+///
+/// 128 bit buffer containing a unique identifier value.
+/// Unless otherwise specified, aligned on a 64 bit boundary.
+///
+typedef struct {
+  UINT32  Data1;
+  UINT16  Data2;
+  UINT16  Data3;
+  UINT8   Data4[8];
+} GUID;
+
+//
+// 8-bytes unsigned value that represents a physical system address.
+//
+typedef UINT64 PHYSICAL_ADDRESS;
+
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY LIST_ENTRY;
+
+///
+/// _LIST_ENTRY structure definition.
+///
+struct _LIST_ENTRY {
+  LIST_ENTRY  *ForwardLink;
+  LIST_ENTRY  *BackLink;
+};
+
+//
+// Modifiers to abstract standard types to aid in debug of problems
+//
+
+///
+/// Datum is read-only.
+///
+#define CONST     const
+
+///
+/// Datum is scoped to the current file or function.
+///
+#define STATIC    static
+
+///
+/// Undeclared type.
+///
+#define VOID      void
+
+//
+// Modifiers for Data Types used to self document code.
+// This concept is borrowed for UEFI specification.
+//
+
+///
+/// Datum is passed to the function.
+///
+#define IN
+
+///
+/// Datum is returned from the function.
+///
+#define OUT
+
+///
+/// Passing the datum to the function is optional, and a NULL
+/// is passed if the value is not supplied.
+///
+#define OPTIONAL
+
+//
+//  UEFI specification claims 1 and 0. We are concerned about the
+//  complier portability so we did it this way.
+//
+
+///
+/// Boolean true value.  UEFI Specification defines this value to be 1,
+/// but this form is more portable.
+///
+#define TRUE  ((BOOLEAN)(1==1))
+
+///
+/// Boolean false value.  UEFI Specification defines this value to be 0,
+/// but this form is more portable.
+///
+#define FALSE ((BOOLEAN)(0==1))
+
+///
+/// NULL pointer (VOID *)
+///
+#define NULL  ((VOID *) 0)
+
+
+#define  BIT0     0x00000001
+#define  BIT1     0x00000002
+#define  BIT2     0x00000004
+#define  BIT3     0x00000008
+#define  BIT4     0x00000010
+#define  BIT5     0x00000020
+#define  BIT6     0x00000040
+#define  BIT7     0x00000080
+#define  BIT8     0x00000100
+#define  BIT9     0x00000200
+#define  BIT10    0x00000400
+#define  BIT11    0x00000800
+#define  BIT12    0x00001000
+#define  BIT13    0x00002000
+#define  BIT14    0x00004000
+#define  BIT15    0x00008000
+#define  BIT16    0x00010000
+#define  BIT17    0x00020000
+#define  BIT18    0x00040000
+#define  BIT19    0x00080000
+#define  BIT20    0x00100000
+#define  BIT21    0x00200000
+#define  BIT22    0x00400000
+#define  BIT23    0x00800000
+#define  BIT24    0x01000000
+#define  BIT25    0x02000000
+#define  BIT26    0x04000000
+#define  BIT27    0x08000000
+#define  BIT28    0x10000000
+#define  BIT29    0x20000000
+#define  BIT30    0x40000000
+#define  BIT31    0x80000000
+#define  BIT32    0x0000000100000000ULL
+#define  BIT33    0x0000000200000000ULL
+#define  BIT34    0x0000000400000000ULL
+#define  BIT35    0x0000000800000000ULL
+#define  BIT36    0x0000001000000000ULL
+#define  BIT37    0x0000002000000000ULL
+#define  BIT38    0x0000004000000000ULL
+#define  BIT39    0x0000008000000000ULL
+#define  BIT40    0x0000010000000000ULL
+#define  BIT41    0x0000020000000000ULL
+#define  BIT42    0x0000040000000000ULL
+#define  BIT43    0x0000080000000000ULL
+#define  BIT44    0x0000100000000000ULL
+#define  BIT45    0x0000200000000000ULL
+#define  BIT46    0x0000400000000000ULL
+#define  BIT47    0x0000800000000000ULL
+#define  BIT48    0x0001000000000000ULL
+#define  BIT49    0x0002000000000000ULL
+#define  BIT50    0x0004000000000000ULL
+#define  BIT51    0x0008000000000000ULL
+#define  BIT52    0x0010000000000000ULL
+#define  BIT53    0x0020000000000000ULL
+#define  BIT54    0x0040000000000000ULL
+#define  BIT55    0x0080000000000000ULL
+#define  BIT56    0x0100000000000000ULL
+#define  BIT57    0x0200000000000000ULL
+#define  BIT58    0x0400000000000000ULL
+#define  BIT59    0x0800000000000000ULL
+#define  BIT60    0x1000000000000000ULL
+#define  BIT61    0x2000000000000000ULL
+#define  BIT62    0x4000000000000000ULL
+#define  BIT63    0x8000000000000000ULL
+
+#define  SIZE_1KB    0x00000400
+#define  SIZE_2KB    0x00000800
+#define  SIZE_4KB    0x00001000
+#define  SIZE_8KB    0x00002000
+#define  SIZE_16KB   0x00004000
+#define  SIZE_32KB   0x00008000
+#define  SIZE_64KB   0x00010000
+#define  SIZE_128KB  0x00020000
+#define  SIZE_256KB  0x00040000
+#define  SIZE_512KB  0x00080000
+#define  SIZE_1MB    0x00100000
+#define  SIZE_2MB    0x00200000
+#define  SIZE_4MB    0x00400000
+#define  SIZE_8MB    0x00800000
+#define  SIZE_16MB   0x01000000
+#define  SIZE_32MB   0x02000000
+#define  SIZE_64MB   0x04000000
+#define  SIZE_128MB  0x08000000
+#define  SIZE_256MB  0x10000000
+#define  SIZE_512MB  0x20000000
+#define  SIZE_1GB    0x40000000
+#define  SIZE_2GB    0x80000000
+#define  SIZE_4GB    0x0000000100000000ULL
+#define  SIZE_8GB    0x0000000200000000ULL
+#define  SIZE_16GB   0x0000000400000000ULL
+#define  SIZE_32GB   0x0000000800000000ULL
+#define  SIZE_64GB   0x0000001000000000ULL
+#define  SIZE_128GB  0x0000002000000000ULL
+#define  SIZE_256GB  0x0000004000000000ULL
+#define  SIZE_512GB  0x0000008000000000ULL
+#define  SIZE_1TB    0x0000010000000000ULL
+#define  SIZE_2TB    0x0000020000000000ULL
+#define  SIZE_4TB    0x0000040000000000ULL
+#define  SIZE_8TB    0x0000080000000000ULL
+#define  SIZE_16TB   0x0000100000000000ULL
+#define  SIZE_32TB   0x0000200000000000ULL
+#define  SIZE_64TB   0x0000400000000000ULL
+#define  SIZE_128TB  0x0000800000000000ULL
+#define  SIZE_256TB  0x0001000000000000ULL
+#define  SIZE_512TB  0x0002000000000000ULL
+#define  SIZE_1PB    0x0004000000000000ULL
+#define  SIZE_2PB    0x0008000000000000ULL
+#define  SIZE_4PB    0x0010000000000000ULL
+#define  SIZE_8PB    0x0020000000000000ULL
+#define  SIZE_16PB   0x0040000000000000ULL
+#define  SIZE_32PB   0x0080000000000000ULL
+#define  SIZE_64PB   0x0100000000000000ULL
+#define  SIZE_128PB  0x0200000000000000ULL
+#define  SIZE_256PB  0x0400000000000000ULL
+#define  SIZE_512PB  0x0800000000000000ULL
+#define  SIZE_1EB    0x1000000000000000ULL
+#define  SIZE_2EB    0x2000000000000000ULL
+#define  SIZE_4EB    0x4000000000000000ULL
+#define  SIZE_8EB    0x8000000000000000ULL
+
+#define  BASE_1KB    0x00000400
+#define  BASE_2KB    0x00000800
+#define  BASE_4KB    0x00001000
+#define  BASE_8KB    0x00002000
+#define  BASE_16KB   0x00004000
+#define  BASE_32KB   0x00008000
+#define  BASE_64KB   0x00010000
+#define  BASE_128KB  0x00020000
+#define  BASE_256KB  0x00040000
+#define  BASE_512KB  0x00080000
+#define  BASE_1MB    0x00100000
+#define  BASE_2MB    0x00200000
+#define  BASE_4MB    0x00400000
+#define  BASE_8MB    0x00800000
+#define  BASE_16MB   0x01000000
+#define  BASE_32MB   0x02000000
+#define  BASE_64MB   0x04000000
+#define  BASE_128MB  0x08000000
+#define  BASE_256MB  0x10000000
+#define  BASE_512MB  0x20000000
+#define  BASE_1GB    0x40000000
+#define  BASE_2GB    0x80000000
+#define  BASE_4GB    0x0000000100000000ULL
+#define  BASE_8GB    0x0000000200000000ULL
+#define  BASE_16GB   0x0000000400000000ULL
+#define  BASE_32GB   0x0000000800000000ULL
+#define  BASE_64GB   0x0000001000000000ULL
+#define  BASE_128GB  0x0000002000000000ULL
+#define  BASE_256GB  0x0000004000000000ULL
+#define  BASE_512GB  0x0000008000000000ULL
+#define  BASE_1TB    0x0000010000000000ULL
+#define  BASE_2TB    0x0000020000000000ULL
+#define  BASE_4TB    0x0000040000000000ULL
+#define  BASE_8TB    0x0000080000000000ULL
+#define  BASE_16TB   0x0000100000000000ULL
+#define  BASE_32TB   0x0000200000000000ULL
+#define  BASE_64TB   0x0000400000000000ULL
+#define  BASE_128TB  0x0000800000000000ULL
+#define  BASE_256TB  0x0001000000000000ULL
+#define  BASE_512TB  0x0002000000000000ULL
+#define  BASE_1PB    0x0004000000000000ULL
+#define  BASE_2PB    0x0008000000000000ULL
+#define  BASE_4PB    0x0010000000000000ULL
+#define  BASE_8PB    0x0020000000000000ULL
+#define  BASE_16PB   0x0040000000000000ULL
+#define  BASE_32PB   0x0080000000000000ULL
+#define  BASE_64PB   0x0100000000000000ULL
+#define  BASE_128PB  0x0200000000000000ULL
+#define  BASE_256PB  0x0400000000000000ULL
+#define  BASE_512PB  0x0800000000000000ULL
+#define  BASE_1EB    0x1000000000000000ULL
+#define  BASE_2EB    0x2000000000000000ULL
+#define  BASE_4EB    0x4000000000000000ULL
+#define  BASE_8EB    0x8000000000000000ULL
+
+//
+//  Support for variable length argument lists using the ANSI standard.
+//
+//  Since we are using the ANSI standard we used the standard naming and
+//  did not follow the coding convention
+//
+//  VA_LIST  - typedef for argument list.
+//  VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use.
+//  VA_END (VA_LIST Marker) - Clear Marker
+//  VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argument from
+//    the ... list. You must know the size and pass it in this macro.
+//
+//  example:
+//
+//  UINTN
+//  ExampleVarArg (
+//    IN UINTN  NumberOfArgs,
+//    ...
+//    )
+//  {
+//    VA_LIST Marker;
+//    UINTN   Index;
+//    UINTN   Result;
+//
+//    //
+//    // Initialize the Marker
+//    //
+//    VA_START (Marker, NumberOfArgs);
+//    for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
+//      //
+//      // The ... list is a series of UINTN values, so average them up.
+//      //
+//      Result += VA_ARG (Marker, UINTN);
+//    }
+//
+//    VA_END (Marker);
+//    return Result
+//  }
+//
+
+/**
+  Return the size of argument that has been aligned to sizeof (UINTN).
+
+  @param  n    The parameter size to be aligned.
+
+  @return The aligned size.
+**/
+#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1))
+
+#if defined(__CC_ARM)
+//
+// RVCT ARM variable argument list support.
+//
+
+///
+/// Variable used to traverse the list of arguments. This type can vary by
+/// implementation and could be an array or structure.
+///
+#ifdef __APCS_ADSABI
+  typedef int         *va_list[1];
+  #define VA_LIST     va_list
+#else
+  typedef struct __va_list { void *__ap; } va_list;
+  #define VA_LIST                          va_list
+#endif
+
+#define VA_START(Marker, Parameter)   __va_start(Marker, Parameter)
+
+#define VA_ARG(Marker, TYPE)          __va_arg(Marker, TYPE)
+
+#define VA_END(Marker)                ((void)0)
+
+#elif defined(__GNUC__) && !defined(NO_BUILTIN_VA_FUNCS)
+//
+// Use GCC built-in macros for variable argument lists.
+//
+
+///
+/// Variable used to traverse the list of arguments. This type can vary by
+/// implementation and could be an array or structure.
+///
+typedef __builtin_va_list VA_LIST;
+
+#define VA_START(Marker, Parameter)  __builtin_va_start (Marker, Parameter)
+
+#define VA_ARG(Marker, TYPE)         ((sizeof (TYPE) < sizeof (UINTN)) ? (TYPE)(__builtin_va_arg (Marker, UINTN)) : (TYPE)(__builtin_va_arg (Marker, TYPE)))
+
+#define VA_END(Marker)               __builtin_va_end (Marker)
+
+#else
+///
+/// Variable used to traverse the list of arguments. This type can vary by
+/// implementation and could be an array or structure.
+///
+typedef CHAR8 *VA_LIST;
+
+/**
+  Retrieves a pointer to the beginning of a variable argument list, based on
+  the name of the parameter that immediately precedes the variable argument list.
+
+  This function initializes Marker to point to the beginning of the variable
+  argument list that immediately follows Parameter.  The method for computing the
+  pointer to the next argument in the argument list is CPU-specific following the
+  EFIAPI ABI.
+
+  @param   Marker       The VA_LIST used to traverse the list of arguments.
+  @param   Parameter    The name of the parameter that immediately precedes
+                        the variable argument list.
+
+  @return  A pointer to the beginning of a variable argument list.
+
+**/
+#define VA_START(Marker, Parameter) (Marker = (VA_LIST) ((UINTN) & (Parameter) + _INT_SIZE_OF (Parameter)))
+
+/**
+  Returns an argument of a specified type from a variable argument list and updates
+  the pointer to the variable argument list to point to the next argument.
+
+  This function returns an argument of the type specified by TYPE from the beginning
+  of the variable argument list specified by Marker.  Marker is then updated to point
+  to the next argument in the variable argument list.  The method for computing the
+  pointer to the next argument in the argument list is CPU-specific following the EFIAPI ABI.
+
+  @param   Marker   VA_LIST used to traverse the list of arguments.
+  @param   TYPE     The type of argument to retrieve from the beginning
+                    of the variable argument list.
+
+  @return  An argument of the type specified by TYPE.
+
+**/
+#define VA_ARG(Marker, TYPE)   (*(TYPE *) ((Marker += _INT_SIZE_OF (TYPE)) - _INT_SIZE_OF (TYPE)))
+
+/**
+  Terminates the use of a variable argument list.
+
+  This function initializes Marker so it can no longer be used with VA_ARG().
+  After this macro is used, the only way to access the variable argument list is
+  by using VA_START() again.
+
+  @param   Marker   VA_LIST used to traverse the list of arguments.
+
+**/
+#define VA_END(Marker)      (Marker = (VA_LIST) 0)
+
+#endif
+
+///
+/// Pointer to the start of a variable argument list stored in a memory buffer. Same as UINT8 *.
+///
+typedef UINTN  *BASE_LIST;
+
+/**
+  Returns the size of a data type in sizeof(UINTN) units rounded up to the nearest UINTN boundary.
+
+  @param  TYPE  The date type to determine the size of.
+
+  @return The size of TYPE in sizeof (UINTN) units rounded up to the nearest UINTN boundary.
+**/
+#define _BASE_INT_SIZE_OF(TYPE) ((sizeof (TYPE) + sizeof (UINTN) - 1) / sizeof (UINTN))
+
+/**
+  Returns an argument of a specified type from a variable argument list and updates
+  the pointer to the variable argument list to point to the next argument.
+
+  This function returns an argument of the type specified by TYPE from the beginning
+  of the variable argument list specified by Marker.  Marker is then updated to point
+  to the next argument in the variable argument list.  The method for computing the
+  pointer to the next argument in the argument list is CPU specific following the EFIAPI ABI.
+
+  @param   Marker   The pointer to the beginning of a variable argument list.
+  @param   TYPE     The type of argument to retrieve from the beginning
+                    of the variable argument list.
+
+  @return  An argument of the type specified by TYPE.
+
+**/
+#define BASE_ARG(Marker, TYPE)   (*(TYPE *) ((Marker += _BASE_INT_SIZE_OF (TYPE)) - _BASE_INT_SIZE_OF (TYPE)))
+
+/**
+  The macro that returns the byte offset of a field in a data structure.
+
+  This function returns the offset, in bytes, of field specified by Field from the
+  beginning of the  data structure specified by TYPE. If TYPE does not contain Field,
+  the module will not compile.
+
+  @param   TYPE     The name of the data structure that contains the field specified by Field.
+  @param   Field    The name of the field in the data structure.
+
+  @return  Offset, in bytes, of field.
+
+**/
+#ifdef __GNUC__
+#if __GNUC__ >= 4
+#define OFFSET_OF(TYPE, Field) ((UINTN) __builtin_offsetof(TYPE, Field))
+#endif
+#endif
+
+#ifndef OFFSET_OF
+#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
+#endif
+
+/**
+  Macro that returns a pointer to the data structure that contains a specified field of
+  that data structure.  This is a lightweight method to hide information by placing a
+  public data structure inside a larger private data structure and using a pointer to
+  the public data structure to retrieve a pointer to the private data structure.
+
+  This function computes the offset, in bytes, of field specified by Field from the beginning
+  of the  data structure specified by TYPE.  This offset is subtracted from Record, and is
+  used to return a pointer to a data structure of the type specified by TYPE. If the data type
+  specified by TYPE does not contain the field specified by Field, then the module will not compile.
+
+  @param   Record   Pointer to the field specified by Field within a data structure of type TYPE.
+  @param   TYPE     The name of the data structure type to return.  This data structure must
+                    contain the field specified by Field.
+  @param   Field    The name of the field in the data structure specified by TYPE to which Record points.
+
+  @return  A pointer to the structure from one of it's elements.
+
+**/
+#define BASE_CR(Record, TYPE, Field)  ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+
+/**
+  Rounds a value up to the next boundary using a specified alignment.
+
+  This function rounds Value up to the next boundary using the specified Alignment.
+  This aligned value is returned.
+
+  @param   Value      The value to round up.
+  @param   Alignment  The alignment boundary used to return the aligned value.
+
+  @return  A value up to the next boundary.
+
+**/
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+
+/**
+  Adjust a pointer by adding the minimum offset required for it to be aligned on
+  a specified alignment boundary.
+
+  This function rounds the pointer specified by Pointer to the next alignment boundary
+  specified by Alignment. The pointer to the aligned address is returned.
+
+  @param   Pointer    The pointer to round up.
+  @param   Alignment  The alignment boundary to use to return an aligned pointer.
+
+  @return  Pointer to the aligned address.
+
+**/
+#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))
+
+/**
+  Rounds a value up to the next natural boundary for the current CPU.
+  This is 4-bytes for 32-bit CPUs and 8-bytes for 64-bit CPUs.
+
+  This function rounds the value specified by Value up to the next natural boundary for the
+  current CPU. This rounded value is returned.
+
+  @param   Value      The value to round up.
+
+  @return  Rounded value specified by Value.
+
+**/
+#define ALIGN_VARIABLE(Value)  ALIGN_VALUE ((Value), sizeof (UINTN))
+
+
+/**
+  Return the maximum of two operands.
+
+  This macro returns the maximum of two operand specified by a and b.
+  Both a and b must be the same numerical types, signed or unsigned.
+
+  @param   a        The first operand with any numerical type.
+  @param   b        The second operand. Can be any numerical type as long as is
+                    the same type as a.
+
+  @return  Maximum of two operands.
+
+**/
+#define MAX(a, b)                       \
+  (((a) > (b)) ? (a) : (b))
+
+/**
+  Return the minimum of two operands.
+
+  This macro returns the minimal of two operand specified by a and b.
+  Both a and b must be the same numerical types, signed or unsigned.
+
+  @param   a        The first operand with any numerical type.
+  @param   b        The second operand. It should be the same any numerical type with a.
+
+  @return  Minimum of two operands.
+
+**/
+
+#define MIN(a, b)                       \
+  (((a) < (b)) ? (a) : (b))
+
+//
+// Status codes common to all execution phases
+//
+typedef UINTN RETURN_STATUS;
+
+/**
+  Produces a RETURN_STATUS code with the highest bit set.
+
+  @param  StatusCode    The status code value to convert into a warning code.
+                        StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+  @return The value specified by StatusCode with the highest bit set.
+
+**/
+#define ENCODE_ERROR(StatusCode)     ((RETURN_STATUS)(MAX_BIT | (StatusCode)))
+
+/**
+  Produces a RETURN_STATUS code with the highest bit clear.
+
+  @param  StatusCode    The status code value to convert into a warning code.
+                        StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+  @return The value specified by StatusCode with the highest bit clear.
+
+**/
+#define ENCODE_WARNING(StatusCode)   ((RETURN_STATUS)(StatusCode))
+
+/**
+  Returns TRUE if a specified RETURN_STATUS code is an error code.
+
+  This function returns TRUE if StatusCode has the high bit set.  Otherwise, FALSE is returned.
+
+  @param  StatusCode    The status code value to evaluate.
+
+  @retval TRUE          The high bit of StatusCode is set.
+  @retval FALSE         The high bit of StatusCode is clear.
+
+**/
+#define RETURN_ERROR(StatusCode)     (((INTN)(RETURN_STATUS)(StatusCode)) < 0)
+
+///
+/// The operation completed successfully.
+///
+#define RETURN_SUCCESS               0
+
+///
+/// The image failed to load.
+///
+#define RETURN_LOAD_ERROR            ENCODE_ERROR (1)
+
+///
+/// The parameter was incorrect.
+///
+#define RETURN_INVALID_PARAMETER     ENCODE_ERROR (2)
+
+///
+/// The operation is not supported.
+///
+#define RETURN_UNSUPPORTED           ENCODE_ERROR (3)
+
+///
+/// The buffer was not the proper size for the request.
+///
+#define RETURN_BAD_BUFFER_SIZE       ENCODE_ERROR (4)
+
+///
+/// The buffer was not large enough to hold the requested data.
+/// The required buffer size is returned in the appropriate
+/// parameter when this error occurs.
+///
+#define RETURN_BUFFER_TOO_SMALL      ENCODE_ERROR (5)
+
+///
+/// There is no data pending upon return.
+///
+#define RETURN_NOT_READY             ENCODE_ERROR (6)
+
+///
+/// The physical device reported an error while attempting the
+/// operation.
+///
+#define RETURN_DEVICE_ERROR          ENCODE_ERROR (7)
+
+///
+/// The device can not be written to.
+///
+#define RETURN_WRITE_PROTECTED       ENCODE_ERROR (8)
+
+///
+/// The resource has run out.
+///
+#define RETURN_OUT_OF_RESOURCES      ENCODE_ERROR (9)
+
+///
+/// An inconsistency was detected on the file system causing the
+/// operation to fail.
+///
+#define RETURN_VOLUME_CORRUPTED      ENCODE_ERROR (10)
+
+///
+/// There is no more space on the file system.
+///
+#define RETURN_VOLUME_FULL           ENCODE_ERROR (11)
+
+///
+/// The device does not contain any medium to perform the
+/// operation.
+///
+#define RETURN_NO_MEDIA              ENCODE_ERROR (12)
+
+///
+/// The medium in the device has changed since the last
+/// access.
+///
+#define RETURN_MEDIA_CHANGED         ENCODE_ERROR (13)
+
+///
+/// The item was not found.
+///
+#define RETURN_NOT_FOUND             ENCODE_ERROR (14)
+
+///
+/// Access was denied.
+///
+#define RETURN_ACCESS_DENIED         ENCODE_ERROR (15)
+
+///
+/// The server was not found or did not respond to the request.
+///
+#define RETURN_NO_RESPONSE           ENCODE_ERROR (16)
+
+///
+/// A mapping to the device does not exist.
+///
+#define RETURN_NO_MAPPING            ENCODE_ERROR (17)
+
+///
+/// A timeout time expired.
+///
+#define RETURN_TIMEOUT               ENCODE_ERROR (18)
+
+///
+/// The protocol has not been started.
+///
+#define RETURN_NOT_STARTED           ENCODE_ERROR (19)
+
+///
+/// The protocol has already been started.
+///
+#define RETURN_ALREADY_STARTED       ENCODE_ERROR (20)
+
+///
+/// The operation was aborted.
+///
+#define RETURN_ABORTED               ENCODE_ERROR (21)
+
+///
+/// An ICMP error occurred during the network operation.
+///
+#define RETURN_ICMP_ERROR            ENCODE_ERROR (22)
+
+///
+/// A TFTP error occurred during the network operation.
+///
+#define RETURN_TFTP_ERROR            ENCODE_ERROR (23)
+
+///
+/// A protocol error occurred during the network operation.
+///
+#define RETURN_PROTOCOL_ERROR        ENCODE_ERROR (24)
+
+///
+/// A function encountered an internal version that was
+/// incompatible with a version requested by the caller.
+///
+#define RETURN_INCOMPATIBLE_VERSION  ENCODE_ERROR (25)
+
+///
+/// The function was not performed due to a security violation.
+///
+#define RETURN_SECURITY_VIOLATION    ENCODE_ERROR (26)
+
+///
+/// A CRC error was detected.
+///
+#define RETURN_CRC_ERROR             ENCODE_ERROR (27)
+
+///
+/// The beginning or end of media was reached.
+///
+#define RETURN_END_OF_MEDIA          ENCODE_ERROR (28)
+
+///
+/// The end of the file was reached.
+///
+#define RETURN_END_OF_FILE           ENCODE_ERROR (31)
+
+///
+/// The language specified was invalid.
+///
+#define RETURN_INVALID_LANGUAGE      ENCODE_ERROR (32)
+
+
+///
+/// The string contained one or more characters that
+/// the device could not render and were skipped.
+///
+#define RETURN_WARN_UNKNOWN_GLYPH    ENCODE_WARNING (1)
+
+///
+/// The handle was closed, but the file was not deleted.
+///
+#define RETURN_WARN_DELETE_FAILURE   ENCODE_WARNING (2)
+
+///
+/// The handle was closed, but the data to the file was not
+/// flushed properly.
+///
+#define RETURN_WARN_WRITE_FAILURE    ENCODE_WARNING (3)
+
+///
+/// The resulting buffer was too small, and the data was
+/// truncated to the buffer size.
+///
+#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4)
+
+/**
+  Returns a 16-bit signature built from 2 ASCII characters.
+
+  This macro returns a 16-bit value built from the two ASCII characters specified
+  by A and B.
+
+  @param  A    The first ASCII character.
+  @param  B    The second ASCII character.
+
+  @return A 16-bit value built from the two ASCII characters specified by A and B.
+
+**/
+#define SIGNATURE_16(A, B)        ((A) | (B << 8))
+
+/**
+  Returns a 32-bit signature built from 4 ASCII characters.
+
+  This macro returns a 32-bit value built from the four ASCII characters specified
+  by A, B, C, and D.
+
+  @param  A    The first ASCII character.
+  @param  B    The second ASCII character.
+  @param  C    The third ASCII character.
+  @param  D    The fourth ASCII character.
+
+  @return A 32-bit value built from the two ASCII characters specified by A, B,
+          C and D.
+
+**/
+#define SIGNATURE_32(A, B, C, D)  (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+/**
+  Returns a 64-bit signature built from 8 ASCII characters.
+
+  This macro returns a 64-bit value built from the eight ASCII characters specified
+  by A, B, C, D, E, F, G,and H.
+
+  @param  A    The first ASCII character.
+  @param  B    The second ASCII character.
+  @param  C    The third ASCII character.
+  @param  D    The fourth ASCII character.
+  @param  E    The fifth ASCII character.
+  @param  F    The sixth ASCII character.
+  @param  G    The seventh ASCII character.
+  @param  H    The eighth ASCII character.
+
+  @return A 64-bit value built from the two ASCII characters specified by A, B,
+          C, D, E, F, G and H.
+
+**/
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+    (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32))
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiFormMapMethodGuid.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiFormMapMethodGuid.h
new file mode 100644
index 0000000..c8f3721
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiFormMapMethodGuid.h
@@ -0,0 +1,27 @@
+/** @file
+  Guid used to identify HII FormMap configuration method.
+
+  Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUID defined in UEFI 2.2 spec.
+**/
+
+#ifndef __EFI_HII_FORMMAP_GUID_H__
+#define __EFI_HII_FORMMAP_GUID_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_HII_STANDARD_FORM_GUID \
+  { 0x3bd2f4ec, 0xe524, 0x46e4, { 0xa9, 0xd8, 0x51, 0x1, 0x17, 0x42, 0x55, 0x62 } }
+
+extern EFI_GUID gEfiHiiStandardFormGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h
new file mode 100644
index 0000000..fa81736
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h
@@ -0,0 +1,37 @@
+/** @file
+  GUID indicates that the form set contains forms designed to be used
+  for platform configuration and this form set will be displayed.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUID defined in UEFI 2.1.
+
+**/
+
+#ifndef __HII_PLATFORM_SETUP_FORMSET_GUID_H__
+#define __HII_PLATFORM_SETUP_FORMSET_GUID_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \
+  { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } }
+
+#define EFI_HII_DRIVER_HEALTH_FORMSET_GUID \
+  { 0xf22fc20c, 0x8cf4, 0x45eb, { 0x8e, 0x6, 0xad, 0x4e, 0x50, 0xb9, 0x5d, 0xd3 } }
+
+#define EFI_HII_USER_CREDENTIAL_FORMSET_GUID \
+  { 0x337f4407, 0x5aee, 0x4b83, { 0xb2, 0xa7, 0x4e, 0xad, 0xca, 0x30, 0x88, 0xcd } }
+
+extern EFI_GUID gEfiHiiPlatformSetupFormsetGuid;
+extern EFI_GUID gEfiHiiDriverHealthFormsetGuid;
+extern EFI_GUID gEfiHiiUserCredentialFormsetGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/MdeModuleHii.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/MdeModuleHii.h
new file mode 100644
index 0000000..76890b7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/MdeModuleHii.h
@@ -0,0 +1,222 @@
+/** @file
+  EDKII extented HII IFR guid opcodes.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __MDEMODULE_HII_H__
+#define __MDEMODULE_HII_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define NARROW_CHAR         0xFFF0
+#define WIDE_CHAR           0xFFF1
+#define NON_BREAKING_CHAR   0xFFF2
+
+///
+/// State defined for password statemachine .
+///
+#define BROWSER_STATE_VALIDATE_PASSWORD  0
+#define BROWSER_STATE_SET_PASSWORD       1
+
+///
+/// GUIDed opcodes defined for EDKII implementation.
+///
+#define EFI_IFR_TIANO_GUID \
+  { 0xf0b1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce} }
+
+#pragma pack(1)
+
+///
+/// EDKII implementation extension opcodes, new extension can be added here later.
+///
+#define EFI_IFR_EXTEND_OP_LABEL       0x0
+#define EFI_IFR_EXTEND_OP_BANNER      0x1
+#define EFI_IFR_EXTEND_OP_TIMEOUT     0x2
+#define EFI_IFR_EXTEND_OP_CLASS       0x3
+#define EFI_IFR_EXTEND_OP_SUBCLASS    0x4
+
+///
+/// Label opcode.
+///
+typedef struct _EFI_IFR_GUID_LABEL {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_LABEL.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// Label Number.
+  ///
+  UINT16              Number;
+} EFI_IFR_GUID_LABEL;
+
+#define EFI_IFR_BANNER_ALIGN_LEFT     0
+#define EFI_IFR_BANNER_ALIGN_CENTER   1
+#define EFI_IFR_BANNER_ALIGN_RIGHT    2
+
+///
+/// Banner opcode.
+///
+typedef struct _EFI_IFR_GUID_BANNER {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_BANNER
+  ///
+  UINT8               ExtendOpCode;
+  EFI_STRING_ID       Title;        ///< The string token for the banner title.
+  UINT16              LineNumber;   ///< 1-based line number.
+  UINT8               Alignment;    ///< left, center, or right-aligned.
+} EFI_IFR_GUID_BANNER;
+
+///
+/// Timeout opcode.
+///
+typedef struct _EFI_IFR_GUID_TIMEOUT {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_TIMEOUT.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              TimeOut;       ///< TimeOut Value.
+} EFI_IFR_GUID_TIMEOUT;
+
+#define EFI_NON_DEVICE_CLASS              0x00
+#define EFI_DISK_DEVICE_CLASS             0x01
+#define EFI_VIDEO_DEVICE_CLASS            0x02
+#define EFI_NETWORK_DEVICE_CLASS          0x04
+#define EFI_INPUT_DEVICE_CLASS            0x08
+#define EFI_ON_BOARD_DEVICE_CLASS         0x10
+#define EFI_OTHER_DEVICE_CLASS            0x20
+
+///
+/// Device Class opcode.
+///
+typedef struct _EFI_IFR_GUID_CLASS {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_CLASS.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              Class;           ///< Device Class from the above.
+} EFI_IFR_GUID_CLASS;
+
+#define EFI_SETUP_APPLICATION_SUBCLASS    0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS  0x01
+#define EFI_FRONT_PAGE_SUBCLASS           0x02
+#define EFI_SINGLE_USE_SUBCLASS           0x03
+
+///
+/// SubClass opcode
+///
+typedef struct _EFI_IFR_GUID_SUBCLASS {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_SUBCLASS.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              SubClass;      ///< Sub Class type from the above.
+} EFI_IFR_GUID_SUBCLASS;
+
+///
+/// GUIDed opcodes support for framework vfr.
+///
+#define EFI_IFR_FRAMEWORK_GUID \
+  { 0x31ca5d1a, 0xd511, 0x4931, { 0xb7, 0x82, 0xae, 0x6b, 0x2b, 0x17, 0x8c, 0xd7 } }
+
+///
+/// Two extended opcodes are added, and new extensions can be added here later.
+/// One is for framework OneOf question Option Key value;
+/// another is for framework vareqval.
+///
+#define EFI_IFR_EXTEND_OP_OPTIONKEY   0x0
+#define EFI_IFR_EXTEND_OP_VAREQNAME   0x1
+
+///
+/// Store the framework vfr option key value.
+///
+typedef struct _EFI_IFR_GUID_OPTIONKEY {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_FRAMEWORK_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_OPTIONKEY.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// OneOf Questiond ID binded by OneOf Option.
+  ///
+  EFI_QUESTION_ID     QuestionId;
+  ///
+  /// The OneOf Option Value.
+  ///
+  EFI_IFR_TYPE_VALUE  OptionValue;
+  ///
+  /// The Framework OneOf Option Key Value.
+  ///
+  UINT16              KeyValue;
+} EFI_IFR_GUID_OPTIONKEY;
+
+///
+/// Store the framework vfr vareqval name number.
+///
+typedef struct _EFI_IFR_GUID_VAREQNAME {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_FRAMEWORK_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_VAREQNAME.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// Question ID of the Numeric Opcode created.
+  ///
+  EFI_QUESTION_ID     QuestionId;
+  ///
+  /// For vareqval (0x100), NameId is 0x100.
+  /// This value will convert to a Unicode String following this rule;
+  ///            sprintf(StringBuffer, "%d", NameId) .
+  /// The the Unicode String will be used as a EFI Variable Name.
+  ///
+  UINT16              NameId;
+} EFI_IFR_GUID_VAREQNAME;
+
+#pragma pack()
+
+extern EFI_GUID gEfiIfrTianoGuid;
+extern EFI_GUID gEfiIfrFrameworkGuid;
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/PcAnsi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/PcAnsi.h
new file mode 100644
index 0000000..8b3e63f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/PcAnsi.h
@@ -0,0 +1,60 @@
+/** @file
+  Terminal Device Path Vendor Guid.
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUIDs defined in UEFI 2.0 spec.
+
+**/
+
+#ifndef __PC_ANSI_H__
+#define __PC_ANSI_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_PC_ANSI_GUID \
+  { \
+    0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+  }
+
+#define EFI_VT_100_GUID \
+  { \
+    0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+  }
+
+#define EFI_VT_100_PLUS_GUID \
+  { \
+    0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 } \
+  }
+
+#define EFI_VT_UTF8_GUID \
+  { \
+    0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 } \
+  }
+
+#define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL \
+  { \
+    0x37499a9d, 0x542f, 0x4c89, {0xa0, 0x26, 0x35, 0xda, 0x14, 0x20, 0x94, 0xe4 } \
+  }
+
+#define EFI_SAS_DEVICE_PATH_GUID \
+  { \
+    0xd487ddb4, 0x008b, 0x11d9, {0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d } \
+  }
+
+extern EFI_GUID gEfiPcAnsiGuid;
+extern EFI_GUID gEfiVT100Guid;
+extern EFI_GUID gEfiVT100PlusGuid;
+extern EFI_GUID gEfiVTUTF8Guid;
+extern EFI_GUID gEfiUartDevicePathGuid;
+extern EFI_GUID gEfiSasDevicePathGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/SmBios.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/SmBios.h
new file mode 100644
index 0000000..cc4a1f9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/SmBios.h
@@ -0,0 +1,34 @@
+/** @file
+  GUIDs used to locate the SMBIOS tables in the UEFI 2.0 system table.
+
+  This GUID in the system table is the only legal way to search for and
+  locate the SMBIOS tables. Do not search the 0xF0000 segment to find SMBIOS
+  tables.
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUIDs defined in UEFI 2.0 spec.
+
+**/
+
+#ifndef __SMBIOS_GUID_H__
+#define __SMBIOS_GUID_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define SMBIOS_TABLE_GUID \
+  { \
+    0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+  }
+
+extern EFI_GUID       gEfiSmbiosTableGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h
new file mode 100644
index 0000000..75fc642
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h
@@ -0,0 +1,130 @@
+/** @file
+  GUID for UEFI WIN_CERTIFICATE structure.
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUID defined in UEFI 2.0 spec.
+**/
+
+#ifndef __EFI_WIN_CERTIFICATE_H__
+#define __EFI_WIN_CERTIFICATE_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// _WIN_CERTIFICATE.wCertificateType
+//
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
+#define WIN_CERT_TYPE_EFI_PKCS115      0x0EF0
+#define WIN_CERT_TYPE_EFI_GUID         0x0EF1
+
+///
+/// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
+///
+typedef struct {
+  ///
+  /// The length of the entire certificate,
+  /// including the length of the header, in bytes.
+  ///
+  UINT32  dwLength;
+  ///
+  /// The revision level of the WIN_CERTIFICATE
+  /// structure. The current revision level is 0x0200.
+  ///
+  UINT16  wRevision;
+  ///
+  /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
+  /// certificate types. The UEFI specification reserves the range of
+  /// certificate type values from 0x0EF0 to 0x0EFF.
+  ///
+  UINT16  wCertificateType;
+  ///
+  /// The following is the actual certificate. The format of
+  /// the certificate depends on wCertificateType.
+  ///
+  /// UINT8 bCertificate[ANYSIZE_ARRAY];
+  ///
+} WIN_CERTIFICATE;
+
+///
+/// WIN_CERTIFICATE_UEFI_GUID.CertType
+///
+#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \
+  {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } }
+
+///
+/// WIN_CERTIFICATE_UEFI_GUID.CertData
+///
+typedef struct {
+  EFI_GUID  HashType;
+  UINT8     PublicKey[256];
+  UINT8     Signature[256];
+} EFI_CERT_BLOCK_RSA_2048_SHA256;
+
+
+///
+/// Certificate which encapsulates a GUID-specific digital signature
+///
+typedef struct {
+  ///
+  /// This is the standard WIN_CERTIFICATE header, where
+  /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID.
+  ///
+  WIN_CERTIFICATE   Hdr;
+  ///
+  /// This is the unique id which determines the
+  /// format of the CertData. .
+  ///
+  EFI_GUID          CertType;
+  ///
+  /// The following is the certificate data. The format of
+  /// the data is determined by the CertType.
+  /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID,
+  /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
+  ///
+  UINT8            CertData[1];
+} WIN_CERTIFICATE_UEFI_GUID;
+
+
+///
+/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature.
+///
+/// The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from
+/// WIN_CERTIFICATE and encapsulate the information needed to
+/// implement the RSASSA-PKCS1-v1_5 digital signature algorithm as
+/// specified in RFC2437.
+///
+typedef struct {
+  ///
+  /// This is the standard WIN_CERTIFICATE header, where
+  /// wCertificateType is set to WIN_CERT_TYPE_UEFI_PKCS1_15.
+  ///
+  WIN_CERTIFICATE Hdr;
+  ///
+  /// This is the hashing algorithm which was performed on the
+  /// UEFI executable when creating the digital signature.
+  ///
+  EFI_GUID        HashAlgorithm;
+  ///
+  /// The following is the actual digital signature. The
+  /// size of the signature is the same size as the key
+  /// (1024-bit key is 128 bytes) and can be determined by
+  /// subtracting the length of the other parts of this header
+  /// from the total length of the certificate as found in
+  /// Hdr.dwLength.
+  ///
+  /// UINT8 Signature[];
+  ///
+} WIN_CERTIFICATE_EFI_PKCS1_15;
+
+extern EFI_GUID gEfiCertTypeRsa2048Sha256Guid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h
new file mode 100644
index 0000000..20cf407
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h
@@ -0,0 +1,280 @@
+/** @file
+  Processor or Compiler specific defines and types for IA-32 architecture.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PROCESSOR_BIND_H__
+#define __PROCESSOR_BIND_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Define the processor type so other code can make processor based choices.
+///
+#define MDE_CPU_IA32
+
+//
+// Make sure we are using the correct packing rules per EFI specification
+//
+#if !defined(__GNUC__)
+#pragma pack()
+#endif
+
+#if defined(__INTEL_COMPILER)
+//
+// Disable ICC's remark #869: "Parameter" was never referenced warning.
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 869 )
+
+//
+// Disable ICC's remark #1418: external function definition with no prior declaration.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1418 )
+
+//
+// Disable ICC's remark #1419: external declaration in primary source file
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1419 )
+
+//
+// Disable ICC's remark #593: "Variable" was set but never used.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 593 )
+
+#endif
+
+
+#if defined(_MSC_EXTENSIONS)
+
+//
+// Disable warning that make it impossible to compile at /W4
+// This only works for Microsoft* tools
+//
+
+//
+// Disabling bitfield type checking warnings.
+//
+#pragma warning ( disable : 4214 )
+
+//
+// Disabling the unreferenced formal parameter warnings.
+//
+#pragma warning ( disable : 4100 )
+
+//
+// Disable slightly different base types warning as CHAR8 * can not be set
+// to a constant string.
+//
+#pragma warning ( disable : 4057 )
+
+//
+// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
+//
+#pragma warning ( disable : 4127 )
+
+//
+// This warning is caused by functions defined but not used. For precompiled header only.
+//
+#pragma warning ( disable : 4505 )
+
+//
+// This warning is caused by empty (after preprocessing) source file. For precompiled header only.
+//
+#pragma warning ( disable : 4206 )
+
+#endif
+
+
+#if defined(_MSC_EXTENSIONS)
+
+  //
+  // use Microsoft C complier dependent integer width types
+  //
+
+  ///
+  /// 8-byte unsigned value.
+  ///
+  typedef unsigned __int64    UINT64;
+  ///
+  /// 8-byte signed value.
+  ///
+  typedef __int64             INT64;
+  ///
+  /// 4-byte unsigned value.
+  ///
+  typedef unsigned __int32    UINT32;
+  ///
+  /// 4-byte signed value.
+  ///
+  typedef __int32             INT32;
+  ///
+  /// 2-byte unsigned value.
+  ///
+  typedef unsigned short      UINT16;
+  ///
+  /// 2-byte Character.  Unless otherwise specified all strings are stored in the
+  /// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
+  ///
+  typedef unsigned short      CHAR16;
+  ///
+  /// 2-byte signed value.
+  ///
+  typedef short               INT16;
+  ///
+  /// Logical Boolean.  1-byte value containing 0 for FALSE or a 1 for TRUE.  Other
+  /// values are undefined.
+  ///
+  typedef unsigned char       BOOLEAN;
+  ///
+  /// 1-byte unsigned value.
+  ///
+  typedef unsigned char       UINT8;
+  ///
+  /// 1-byte Character.
+  ///
+  typedef char                CHAR8;
+  ///
+  /// 1-byte signed value.
+  ///
+  typedef char                INT8;
+#else
+  ///
+  /// 8-byte unsigned value.
+  ///
+  typedef unsigned long long  UINT64;
+  ///
+  /// 8-byte signed value.
+  ///
+  typedef long long           INT64;
+  ///
+  /// 4-byte unsigned value.
+  ///
+  typedef unsigned int        UINT32;
+  ///
+  /// 4-byte signed value.
+  ///
+  typedef int                 INT32;
+  ///
+  /// 2-byte unsigned value.
+  ///
+  typedef unsigned short      UINT16;
+  ///
+  /// 2-byte Character.  Unless otherwise specified all strings are stored in the
+  /// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
+  ///
+  typedef unsigned short      CHAR16;
+  ///
+  /// 2-byte signed value.
+  ///
+  typedef short               INT16;
+  ///
+  /// Logical Boolean.  1-byte value containing 0 for FALSE or a 1 for TRUE.  Other
+  /// values are undefined.
+  ///
+  typedef unsigned char       BOOLEAN;
+  ///
+  /// 1-byte unsigned value.
+  ///
+  typedef unsigned char       UINT8;
+  ///
+  /// 1-byte Character
+  ///
+  typedef char                CHAR8;
+  ///
+  /// 1-byte signed value
+  ///
+  typedef char                INT8;
+#endif
+
+///
+/// Unsigned value of native width.  (4 bytes on supported 32-bit processor instructions;
+/// 8 bytes on supported 64-bit processor instructions.)
+///
+typedef UINT32  UINTN;
+///
+/// Signed value of native width.  (4 bytes on supported 32-bit processor instructions;
+/// 8 bytes on supported 64-bit processor instructions.)
+///
+typedef INT32   INTN;
+
+//
+// Processor specific defines
+//
+
+///
+/// A value of native width with the highest bit set.
+///
+#define MAX_BIT     0x80000000
+///
+/// A value of native width with the two highest bits set.
+///
+#define MAX_2_BITS  0xC0000000
+
+///
+/// Maximum legal IA-32 address.
+///
+#define MAX_ADDRESS   0xFFFFFFFF
+
+///
+/// The stack alignment required for IA-32.
+///
+#define CPU_STACK_ALIGNMENT   sizeof(UINTN)
+
+//
+// Modifier to ensure that all protocol member functions and EFI intrinsics
+// use the correct C calling convention. All protocol member functions and
+// EFI intrinsics are required to modify their member functions with EFIAPI.
+//
+#ifdef EFIAPI
+  ///
+  /// If EFIAPI is already defined, then we use that definition.
+  ///
+#elif defined(_MSC_EXTENSIONS)
+  ///
+  /// Microsoft* compiler specific method for EFIAPI calling convention.
+  ///
+  #define EFIAPI __cdecl
+#else
+  #if defined(__GNUC__)
+    ///
+    /// GCC specific method for EFIAPI calling convention.
+    ///
+    #define EFIAPI __attribute__((cdecl))
+  #endif
+#endif
+
+#if defined(__GNUC__)
+  ///
+  /// For GNU assembly code, .global or .globl can declare global symbols.
+  /// Define this macro to unify the usage.
+  ///
+  #define ASM_GLOBAL .globl
+#endif
+
+/**
+  Return the pointer to the first instruction of a function given a function pointer.
+  On IA-32 CPU architectures, these two pointer values are the same,
+  so the implementation of this macro is very simple.
+
+  @param  FunctionPointer   A pointer to a function.
+
+  @return The pointer to the first instruction of a function given a function pointer.
+
+**/
+#define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer)
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h
new file mode 100644
index 0000000..b57059a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h
@@ -0,0 +1,817 @@
+/** @file
+  Support for PCI 2.2 standard.
+
+  This file includes the definitions in the following specifications,
+    PCI Local Bus Specification, 2.2
+    PCI-to-PCI Bridge Architecture Specification, Revision 1.2
+    PC Card Standard, 8.0
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PCI22_H_
+#define _PCI22_H_
+
+FILE_LICENCE ( BSD3 );
+
+#define PCI_MAX_BUS     255
+#define PCI_MAX_DEVICE  31
+#define PCI_MAX_FUNC    7
+
+#pragma pack(1)
+
+///
+/// Common header region in PCI Configuration Space
+/// Section 6.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  UINT16  VendorId;
+  UINT16  DeviceId;
+  UINT16  Command;
+  UINT16  Status;
+  UINT8   RevisionID;
+  UINT8   ClassCode[3];
+  UINT8   CacheLineSize;
+  UINT8   LatencyTimer;
+  UINT8   HeaderType;
+  UINT8   BIST;
+} PCI_DEVICE_INDEPENDENT_REGION;
+
+///
+/// PCI Device header region in PCI Configuration Space
+/// Section 6.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  UINT32  Bar[6];
+  UINT32  CISPtr;
+  UINT16  SubsystemVendorID;
+  UINT16  SubsystemID;
+  UINT32  ExpansionRomBar;
+  UINT8   CapabilityPtr;
+  UINT8   Reserved1[3];
+  UINT32  Reserved2;
+  UINT8   InterruptLine;
+  UINT8   InterruptPin;
+  UINT8   MinGnt;
+  UINT8   MaxLat;
+} PCI_DEVICE_HEADER_TYPE_REGION;
+
+///
+/// PCI Device Configuration Space
+/// Section 6.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  PCI_DEVICE_INDEPENDENT_REGION Hdr;
+  PCI_DEVICE_HEADER_TYPE_REGION Device;
+} PCI_TYPE00;
+
+///
+/// PCI-PCI Bridge header region in PCI Configuration Space
+/// Section 3.2, PCI-PCI Bridge Architecture, Version 1.2
+///
+typedef struct {
+  UINT32  Bar[2];
+  UINT8   PrimaryBus;
+  UINT8   SecondaryBus;
+  UINT8   SubordinateBus;
+  UINT8   SecondaryLatencyTimer;
+  UINT8   IoBase;
+  UINT8   IoLimit;
+  UINT16  SecondaryStatus;
+  UINT16  MemoryBase;
+  UINT16  MemoryLimit;
+  UINT16  PrefetchableMemoryBase;
+  UINT16  PrefetchableMemoryLimit;
+  UINT32  PrefetchableBaseUpper32;
+  UINT32  PrefetchableLimitUpper32;
+  UINT16  IoBaseUpper16;
+  UINT16  IoLimitUpper16;
+  UINT8   CapabilityPtr;
+  UINT8   Reserved[3];
+  UINT32  ExpansionRomBAR;
+  UINT8   InterruptLine;
+  UINT8   InterruptPin;
+  UINT16  BridgeControl;
+} PCI_BRIDGE_CONTROL_REGISTER;
+
+///
+/// PCI-to-PCI Bridge Configuration Space
+/// Section 3.2, PCI-PCI Bridge Architecture, Version 1.2
+///
+typedef struct {
+  PCI_DEVICE_INDEPENDENT_REGION Hdr;
+  PCI_BRIDGE_CONTROL_REGISTER   Bridge;
+} PCI_TYPE01;
+
+typedef union {
+  PCI_TYPE00  Device;
+  PCI_TYPE01  Bridge;
+} PCI_TYPE_GENERIC;
+
+///
+/// CardBus Conroller Configuration Space,
+/// Section 4.5.1, PC Card Standard. 8.0
+///
+typedef struct {
+  UINT32  CardBusSocketReg;     ///< Cardus Socket/ExCA Base
+  UINT8   Cap_Ptr;
+  UINT8   Reserved;
+  UINT16  SecondaryStatus;      ///< Secondary Status
+  UINT8   PciBusNumber;         ///< PCI Bus Number
+  UINT8   CardBusBusNumber;     ///< CardBus Bus Number
+  UINT8   SubordinateBusNumber; ///< Subordinate Bus Number
+  UINT8   CardBusLatencyTimer;  ///< CardBus Latency Timer
+  UINT32  MemoryBase0;          ///< Memory Base Register 0
+  UINT32  MemoryLimit0;         ///< Memory Limit Register 0
+  UINT32  MemoryBase1;
+  UINT32  MemoryLimit1;
+  UINT32  IoBase0;
+  UINT32  IoLimit0;             ///< I/O Base Register 0
+  UINT32  IoBase1;              ///< I/O Limit Register 0
+  UINT32  IoLimit1;
+  UINT8   InterruptLine;        ///< Interrupt Line
+  UINT8   InterruptPin;         ///< Interrupt Pin
+  UINT16  BridgeControl;        ///< Bridge Control
+} PCI_CARDBUS_CONTROL_REGISTER;
+
+//
+// Definitions of PCI class bytes and manipulation macros.
+//
+#define PCI_CLASS_OLD                 0x00
+#define   PCI_CLASS_OLD_OTHER           0x00
+#define   PCI_CLASS_OLD_VGA             0x01
+
+#define PCI_CLASS_MASS_STORAGE        0x01
+#define   PCI_CLASS_MASS_STORAGE_SCSI   0x00
+#define   PCI_CLASS_MASS_STORAGE_IDE    0x01
+#define   PCI_CLASS_MASS_STORAGE_FLOPPY 0x02
+#define   PCI_CLASS_MASS_STORAGE_IPI    0x03
+#define   PCI_CLASS_MASS_STORAGE_RAID   0x04
+#define   PCI_CLASS_MASS_STORAGE_OTHER  0x80
+
+#define PCI_CLASS_NETWORK             0x02
+#define   PCI_CLASS_NETWORK_ETHERNET    0x00
+#define   PCI_CLASS_NETWORK_TOKENRING   0x01
+#define   PCI_CLASS_NETWORK_FDDI        0x02
+#define   PCI_CLASS_NETWORK_ATM         0x03
+#define   PCI_CLASS_NETWORK_ISDN        0x04
+#define   PCI_CLASS_NETWORK_OTHER       0x80
+
+#define PCI_CLASS_DISPLAY             0x03
+#define   PCI_CLASS_DISPLAY_VGA         0x00
+#define     PCI_IF_VGA_VGA                0x00
+#define     PCI_IF_VGA_8514               0x01
+#define   PCI_CLASS_DISPLAY_XGA         0x01
+#define   PCI_CLASS_DISPLAY_3D          0x02
+#define   PCI_CLASS_DISPLAY_OTHER       0x80
+
+#define PCI_CLASS_MEDIA               0x04
+#define   PCI_CLASS_MEDIA_VIDEO         0x00
+#define   PCI_CLASS_MEDIA_AUDIO         0x01
+#define   PCI_CLASS_MEDIA_TELEPHONE     0x02
+#define   PCI_CLASS_MEDIA_OTHER         0x80
+
+#define PCI_CLASS_MEMORY_CONTROLLER   0x05
+#define   PCI_CLASS_MEMORY_RAM          0x00
+#define   PCI_CLASS_MEMORY_FLASH        0x01
+#define   PCI_CLASS_MEMORY_OTHER        0x80
+
+#define PCI_CLASS_BRIDGE              0x06
+#define   PCI_CLASS_BRIDGE_HOST         0x00
+#define   PCI_CLASS_BRIDGE_ISA          0x01
+#define   PCI_CLASS_BRIDGE_EISA         0x02
+#define   PCI_CLASS_BRIDGE_MCA          0x03
+#define   PCI_CLASS_BRIDGE_P2P          0x04
+#define     PCI_IF_BRIDGE_P2P             0x00
+#define     PCI_IF_BRIDGE_P2P_SUBTRACTIVE 0x01
+#define   PCI_CLASS_BRIDGE_PCMCIA       0x05
+#define   PCI_CLASS_BRIDGE_NUBUS        0x06
+#define   PCI_CLASS_BRIDGE_CARDBUS      0x07
+#define   PCI_CLASS_BRIDGE_RACEWAY      0x08
+#define   PCI_CLASS_BRIDGE_OTHER        0x80
+#define   PCI_CLASS_BRIDGE_ISA_PDECODE  0x80
+
+#define PCI_CLASS_SCC                 0x07  ///< Simple communications controllers
+#define   PCI_SUBCLASS_SERIAL           0x00
+#define     PCI_IF_GENERIC_XT             0x00
+#define     PCI_IF_16450                  0x01
+#define     PCI_IF_16550                  0x02
+#define     PCI_IF_16650                  0x03
+#define     PCI_IF_16750                  0x04
+#define     PCI_IF_16850                  0x05
+#define     PCI_IF_16950                  0x06
+#define   PCI_SUBCLASS_PARALLEL         0x01
+#define     PCI_IF_PARALLEL_PORT          0x00
+#define     PCI_IF_BI_DIR_PARALLEL_PORT   0x01
+#define     PCI_IF_ECP_PARALLEL_PORT      0x02
+#define     PCI_IF_1284_CONTROLLER        0x03
+#define     PCI_IF_1284_DEVICE            0xFE
+#define   PCI_SUBCLASS_MULTIPORT_SERIAL 0x02
+#define   PCI_SUBCLASS_MODEM            0x03
+#define     PCI_IF_GENERIC_MODEM          0x00
+#define     PCI_IF_16450_MODEM            0x01
+#define     PCI_IF_16550_MODEM            0x02
+#define     PCI_IF_16650_MODEM            0x03
+#define     PCI_IF_16750_MODEM            0x04
+#define   PCI_SUBCLASS_SCC_OTHER          0x80
+
+#define PCI_CLASS_SYSTEM_PERIPHERAL   0x08
+#define   PCI_SUBCLASS_PIC              0x00
+#define     PCI_IF_8259_PIC               0x00
+#define     PCI_IF_ISA_PIC                0x01
+#define     PCI_IF_EISA_PIC               0x02
+#define     PCI_IF_APIC_CONTROLLER        0x10  ///< I/O APIC interrupt controller , 32 bye none-prefectable memory.
+#define     PCI_IF_APIC_CONTROLLER2       0x20
+#define   PCI_SUBCLASS_DMA              0x01
+#define     PCI_IF_8237_DMA               0x00
+#define     PCI_IF_ISA_DMA                0x01
+#define     PCI_IF_EISA_DMA               0x02
+#define   PCI_SUBCLASS_TIMER            0x02
+#define     PCI_IF_8254_TIMER             0x00
+#define     PCI_IF_ISA_TIMER              0x01
+#define     PCI_IF_EISA_TIMER             0x02
+#define   PCI_SUBCLASS_RTC              0x03
+#define     PCI_IF_GENERIC_RTC            0x00
+#define     PCI_IF_ISA_RTC                0x00
+#define   PCI_SUBCLASS_PNP_CONTROLLER   0x04    ///< HotPlug Controller
+#define   PCI_SUBCLASS_PERIPHERAL_OTHER 0x80
+
+#define PCI_CLASS_INPUT_DEVICE        0x09
+#define   PCI_SUBCLASS_KEYBOARD         0x00
+#define   PCI_SUBCLASS_PEN              0x01
+#define   PCI_SUBCLASS_MOUSE_CONTROLLER 0x02
+#define   PCI_SUBCLASS_SCAN_CONTROLLER  0x03
+#define   PCI_SUBCLASS_GAMEPORT         0x04
+#define     PCI_IF_GAMEPORT               0x00
+#define     PCI_IF_GAMEPORT1              0x01
+#define   PCI_SUBCLASS_INPUT_OTHER      0x80
+
+#define PCI_CLASS_DOCKING_STATION     0x0A
+
+#define PCI_CLASS_PROCESSOR           0x0B
+#define   PCI_SUBCLASS_PROC_386         0x00
+#define   PCI_SUBCLASS_PROC_486         0x01
+#define   PCI_SUBCLASS_PROC_PENTIUM     0x02
+#define   PCI_SUBCLASS_PROC_ALPHA       0x10
+#define   PCI_SUBCLASS_PROC_POWERPC     0x20
+#define   PCI_SUBCLASS_PROC_MIPS        0x30
+#define   PCI_SUBCLASS_PROC_CO_PORC     0x40 ///< Co-Processor
+
+#define PCI_CLASS_SERIAL              0x0C
+#define   PCI_CLASS_SERIAL_FIREWIRE     0x00
+#define     PCI_IF_1394                   0x00
+#define     PCI_IF_1394_OPEN_HCI          0x10
+#define   PCI_CLASS_SERIAL_ACCESS_BUS   0x01
+#define   PCI_CLASS_SERIAL_SSA          0x02
+#define   PCI_CLASS_SERIAL_USB          0x03
+#define     PCI_IF_UHCI                   0x00
+#define     PCI_IF_OHCI                   0x10
+#define     PCI_IF_USB_OTHER              0x80
+#define     PCI_IF_USB_DEVICE             0xFE
+#define   PCI_CLASS_SERIAL_FIBRECHANNEL 0x04
+#define   PCI_CLASS_SERIAL_SMB          0x05
+
+#define PCI_CLASS_WIRELESS            0x0D
+#define   PCI_SUBCLASS_IRDA             0x00
+#define   PCI_SUBCLASS_IR               0x01
+#define   PCI_SUBCLASS_RF               0x02
+#define   PCI_SUBCLASS_WIRELESS_OTHER   0x80
+
+#define PCI_CLASS_INTELLIGENT_IO      0x0E
+
+#define PCI_CLASS_SATELLITE           0x0F
+#define   PCI_SUBCLASS_TV               0x01
+#define   PCI_SUBCLASS_AUDIO            0x02
+#define   PCI_SUBCLASS_VOICE            0x03
+#define   PCI_SUBCLASS_DATA             0x04
+
+#define PCI_SECURITY_CONTROLLER       0x10   ///< Encryption and decryption controller
+#define   PCI_SUBCLASS_NET_COMPUT       0x00
+#define   PCI_SUBCLASS_ENTERTAINMENT    0x10
+#define   PCI_SUBCLASS_SECURITY_OTHER   0x80
+
+#define PCI_CLASS_DPIO                0x11
+#define   PCI_SUBCLASS_DPIO             0x00
+#define   PCI_SUBCLASS_DPIO_OTHER       0x80
+
+/**
+  Macro that checks whether the Base Class code of device matched.
+
+  @param  _p      Specified device.
+  @param  c       Base Class code needs matching.
+
+  @retval TRUE    Base Class code matches the specified device.
+  @retval FALSE   Base Class code doesn't match the specified device.
+
+**/
+#define IS_CLASS1(_p, c)              ((_p)->Hdr.ClassCode[2] == (c))
+/**
+  Macro that checks whether the Base Class code and Sub-Class code of device matched.
+
+  @param  _p      Specified device.
+  @param  c       Base Class code needs matching.
+  @param  s       Sub-Class code needs matching.
+
+  @retval TRUE    Base Class code and Sub-Class code match the specified device.
+  @retval FALSE   Base Class code and Sub-Class code don't match the specified device.
+
+**/
+#define IS_CLASS2(_p, c, s)           (IS_CLASS1 (_p, c) && ((_p)->Hdr.ClassCode[1] == (s)))
+/**
+  Macro that checks whether the Base Class code, Sub-Class code and Interface code of device matched.
+
+  @param  _p      Specified device.
+  @param  c       Base Class code needs matching.
+  @param  s       Sub-Class code needs matching.
+  @param  p       Interface code needs matching.
+
+  @retval TRUE    Base Class code, Sub-Class code and Interface code match the specified device.
+  @retval FALSE   Base Class code, Sub-Class code and Interface code don't match the specified device.
+
+**/
+#define IS_CLASS3(_p, c, s, p)        (IS_CLASS2 (_p, c, s) && ((_p)->Hdr.ClassCode[0] == (p)))
+
+/**
+  Macro that checks whether device is a display controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a display controller.
+  @retval FALSE   Device is not a display controller.
+
+**/
+#define IS_PCI_DISPLAY(_p)            IS_CLASS1 (_p, PCI_CLASS_DISPLAY)
+/**
+  Macro that checks whether device is a VGA-compatible controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a VGA-compatible controller.
+  @retval FALSE   Device is not a VGA-compatible controller.
+
+**/
+#define IS_PCI_VGA(_p)                IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, PCI_IF_VGA_VGA)
+/**
+  Macro that checks whether device is an 8514-compatible controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is an 8514-compatible controller.
+  @retval FALSE   Device is not an 8514-compatible controller.
+
+**/
+#define IS_PCI_8514(_p)               IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, PCI_IF_VGA_8514)
+/**
+  Macro that checks whether device is built before the Class Code field was defined.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is an old device.
+  @retval FALSE   Device is not an old device.
+
+**/
+#define IS_PCI_OLD(_p)                IS_CLASS1 (_p, PCI_CLASS_OLD)
+/**
+  Macro that checks whether device is a VGA-compatible device built before the Class Code field was defined.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is an old VGA-compatible device.
+  @retval FALSE   Device is not an old VGA-compatible device.
+
+**/
+#define IS_PCI_OLD_VGA(_p)            IS_CLASS2 (_p, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA)
+/**
+  Macro that checks whether device is an IDE controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is an IDE controller.
+  @retval FALSE   Device is not an IDE controller.
+
+**/
+#define IS_PCI_IDE(_p)                IS_CLASS2 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_IDE)
+/**
+  Macro that checks whether device is a SCSI bus controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a SCSI bus controller.
+  @retval FALSE   Device is not a SCSI bus controller.
+
+**/
+#define IS_PCI_SCSI(_p)               IS_CLASS2 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_SCSI)
+/**
+  Macro that checks whether device is a RAID controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a RAID controller.
+  @retval FALSE   Device is not a RAID controller.
+
+**/
+#define IS_PCI_RAID(_p)               IS_CLASS2 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_RAID)
+/**
+  Macro that checks whether device is an ISA bridge.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is an ISA bridge.
+  @retval FALSE   Device is not an ISA bridge.
+
+**/
+#define IS_PCI_LPC(_p)                IS_CLASS2 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA)
+/**
+  Macro that checks whether device is a PCI-to-PCI bridge.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a PCI-to-PCI bridge.
+  @retval FALSE   Device is not a PCI-to-PCI bridge.
+
+**/
+#define IS_PCI_P2P(_p)                IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, PCI_IF_BRIDGE_P2P)
+/**
+  Macro that checks whether device is a Subtractive Decode PCI-to-PCI bridge.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a Subtractive Decode PCI-to-PCI bridge.
+  @retval FALSE   Device is not a Subtractive Decode PCI-to-PCI bridge.
+
+**/
+#define IS_PCI_P2P_SUB(_p)            IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, PCI_IF_BRIDGE_P2P_SUBTRACTIVE)
+/**
+  Macro that checks whether device is a 16550-compatible serial controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a 16550-compatible serial controller.
+  @retval FALSE   Device is not a 16550-compatible serial controller.
+
+**/
+#define IS_PCI_16550_SERIAL(_p)       IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550)
+/**
+  Macro that checks whether device is a Universal Serial Bus controller.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a Universal Serial Bus controller.
+  @retval FALSE   Device is not a Universal Serial Bus controller.
+
+**/
+#define IS_PCI_USB(_p)                IS_CLASS2 (_p, PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB)
+
+//
+// the definition of Header Type
+//
+#define HEADER_TYPE_DEVICE            0x00
+#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01
+#define HEADER_TYPE_CARDBUS_BRIDGE    0x02
+#define HEADER_TYPE_MULTI_FUNCTION    0x80
+//
+// Mask of Header type
+//
+#define HEADER_LAYOUT_CODE            0x7f
+/**
+  Macro that checks whether device is a PCI-PCI bridge.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a PCI-PCI bridge.
+  @retval FALSE   Device is not a PCI-PCI bridge.
+
+**/
+#define IS_PCI_BRIDGE(_p)             (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_PCI_TO_PCI_BRIDGE))
+/**
+  Macro that checks whether device is a CardBus bridge.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a CardBus bridge.
+  @retval FALSE   Device is not a CardBus bridge.
+
+**/
+#define IS_CARDBUS_BRIDGE(_p)         (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE))
+/**
+  Macro that checks whether device is a multiple functions device.
+
+  @param  _p      Specified device.
+
+  @retval TRUE    Device is a multiple functions device.
+  @retval FALSE   Device is not a multiple functions device.
+
+**/
+#define IS_PCI_MULTI_FUNC(_p)         ((_p)->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)
+
+///
+/// Rom Base Address in Bridge, defined in PCI-to-PCI Bridge Architecure Specification,
+///
+#define PCI_BRIDGE_ROMBAR             0x38
+
+#define PCI_MAX_BAR                   0x0006
+#define PCI_MAX_CONFIG_OFFSET         0x0100
+
+#define PCI_VENDOR_ID_OFFSET                        0x00
+#define PCI_DEVICE_ID_OFFSET                        0x02
+#define PCI_COMMAND_OFFSET                          0x04
+#define PCI_PRIMARY_STATUS_OFFSET                   0x06
+#define PCI_REVISION_ID_OFFSET                      0x08
+#define PCI_CLASSCODE_OFFSET                        0x09
+#define PCI_CACHELINE_SIZE_OFFSET                   0x0C
+#define PCI_LATENCY_TIMER_OFFSET                    0x0D
+#define PCI_HEADER_TYPE_OFFSET                      0x0E
+#define PCI_BIST_OFFSET                             0x0F
+#define PCI_BASE_ADDRESSREG_OFFSET                  0x10
+#define PCI_CARDBUS_CIS_OFFSET                      0x28
+#define PCI_SVID_OFFSET                             0x2C ///< SubSystem Vendor id
+#define PCI_SUBSYSTEM_VENDOR_ID_OFFSET              0x2C
+#define PCI_SID_OFFSET                              0x2E ///< SubSystem ID
+#define PCI_SUBSYSTEM_ID_OFFSET                     0x2E
+#define PCI_EXPANSION_ROM_BASE                      0x30
+#define PCI_CAPBILITY_POINTER_OFFSET                0x34
+#define PCI_INT_LINE_OFFSET                         0x3C ///< Interrupt Line Register
+#define PCI_INT_PIN_OFFSET                          0x3D ///< Interrupt Pin Register
+#define PCI_MAXGNT_OFFSET                           0x3E ///< Max Grant Register
+#define PCI_MAXLAT_OFFSET                           0x3F ///< Max Latency Register
+
+//
+// defined in PCI-to-PCI Bridge Architecture Specification
+//
+#define PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET      0x18
+#define PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET    0x19
+#define PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET  0x1a
+#define PCI_BRIDGE_STATUS_REGISTER_OFFSET           0x1E
+#define PCI_BRIDGE_CONTROL_REGISTER_OFFSET          0x3E
+
+///
+/// Interrupt Line "Unknown" or "No connection" value defined for x86 based system
+///
+#define PCI_INT_LINE_UNKNOWN                        0xFF
+
+///
+/// PCI Access Data Format
+///
+typedef union {
+  struct {
+    UINT32  Reg : 8;
+    UINT32  Func : 3;
+    UINT32  Dev : 5;
+    UINT32  Bus : 8;
+    UINT32  Reserved : 7;
+    UINT32  Enable : 1;
+  } Bits;
+  UINT32  Uint32;
+} PCI_CONFIG_ACCESS_CF8;
+
+#pragma pack()
+
+#define EFI_PCI_COMMAND_IO_SPACE                        BIT0   ///< 0x0001
+#define EFI_PCI_COMMAND_MEMORY_SPACE                    BIT1   ///< 0x0002
+#define EFI_PCI_COMMAND_BUS_MASTER                      BIT2   ///< 0x0004
+#define EFI_PCI_COMMAND_SPECIAL_CYCLE                   BIT3   ///< 0x0008
+#define EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE     BIT4   ///< 0x0010
+#define EFI_PCI_COMMAND_VGA_PALETTE_SNOOP               BIT5   ///< 0x0020
+#define EFI_PCI_COMMAND_PARITY_ERROR_RESPOND            BIT6   ///< 0x0040
+#define EFI_PCI_COMMAND_STEPPING_CONTROL                BIT7   ///< 0x0080
+#define EFI_PCI_COMMAND_SERR                            BIT8   ///< 0x0100
+#define EFI_PCI_COMMAND_FAST_BACK_TO_BACK               BIT9   ///< 0x0200
+
+//
+// defined in PCI-to-PCI Bridge Architecture Specification
+//
+#define EFI_PCI_BRIDGE_CONTROL_PARITY_ERROR_RESPONSE    BIT0   ///< 0x0001
+#define EFI_PCI_BRIDGE_CONTROL_SERR                     BIT1   ///< 0x0002
+#define EFI_PCI_BRIDGE_CONTROL_ISA                      BIT2   ///< 0x0004
+#define EFI_PCI_BRIDGE_CONTROL_VGA                      BIT3   ///< 0x0008
+#define EFI_PCI_BRIDGE_CONTROL_VGA_16                   BIT4   ///< 0x0010
+#define EFI_PCI_BRIDGE_CONTROL_MASTER_ABORT             BIT5   ///< 0x0020
+#define EFI_PCI_BRIDGE_CONTROL_RESET_SECONDARY_BUS      BIT6   ///< 0x0040
+#define EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK        BIT7   ///< 0x0080
+#define EFI_PCI_BRIDGE_CONTROL_PRIMARY_DISCARD_TIMER    BIT8   ///< 0x0100
+#define EFI_PCI_BRIDGE_CONTROL_SECONDARY_DISCARD_TIMER  BIT9   ///< 0x0200
+#define EFI_PCI_BRIDGE_CONTROL_TIMER_STATUS             BIT10  ///< 0x0400
+#define EFI_PCI_BRIDGE_CONTROL_DISCARD_TIMER_SERR       BIT11  ///< 0x0800
+
+//
+// Following are the PCI-CARDBUS bridge control bit, defined in PC Card Standard
+//
+#define EFI_PCI_BRIDGE_CONTROL_IREQINT_ENABLE           BIT7   ///< 0x0080
+#define EFI_PCI_BRIDGE_CONTROL_RANGE0_MEMORY_TYPE       BIT8   ///< 0x0100
+#define EFI_PCI_BRIDGE_CONTROL_RANGE1_MEMORY_TYPE       BIT9   ///< 0x0200
+#define EFI_PCI_BRIDGE_CONTROL_WRITE_POSTING_ENABLE     BIT10  ///< 0x0400
+
+//
+// Following are the PCI status control bit
+//
+#define EFI_PCI_STATUS_CAPABILITY                       BIT4   ///< 0x0010
+#define EFI_PCI_STATUS_66MZ_CAPABLE                     BIT5   ///< 0x0020
+#define EFI_PCI_FAST_BACK_TO_BACK_CAPABLE               BIT7   ///< 0x0080
+#define EFI_PCI_MASTER_DATA_PARITY_ERROR                BIT8   ///< 0x0100
+
+///
+/// defined in PC Card Standard
+///
+#define EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR 0x14
+
+#pragma pack(1)
+//
+// PCI Capability List IDs and records
+//
+#define EFI_PCI_CAPABILITY_ID_PMI     0x01
+#define EFI_PCI_CAPABILITY_ID_AGP     0x02
+#define EFI_PCI_CAPABILITY_ID_VPD     0x03
+#define EFI_PCI_CAPABILITY_ID_SLOTID  0x04
+#define EFI_PCI_CAPABILITY_ID_MSI     0x05
+#define EFI_PCI_CAPABILITY_ID_HOTPLUG 0x06
+
+///
+/// Capabilities List Header
+/// Section 6.7, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  UINT8 CapabilityID;
+  UINT8 NextItemPtr;
+} EFI_PCI_CAPABILITY_HDR;
+
+///
+/// Power Management Register Block Definition
+/// Section 3.2, PCI Power Management Interface Specifiction, Revision 1.2
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT16                  PMC;
+  UINT16                  PMCSR;
+  UINT8                   BridgeExtention;
+  UINT8                   Data;
+} EFI_PCI_CAPABILITY_PMI;
+
+///
+/// A.G.P Capability
+/// Section 6.1.4, Accelerated Graphics Port Interface Specification, Revision 1.0
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT8                   Rev;
+  UINT8                   Reserved;
+  UINT32                  Status;
+  UINT32                  Command;
+} EFI_PCI_CAPABILITY_AGP;
+
+///
+/// VPD Capability Structure
+/// Appendix I, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT16                  AddrReg;
+  UINT32                  DataReg;
+} EFI_PCI_CAPABILITY_VPD;
+
+///
+/// Slot Numbering Capabilities Register
+/// Section 3.2.6, PCI-to-PCI Bridge Architeture Specification, Revision 1.2
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT8                   ExpnsSlotReg;
+  UINT8                   ChassisNo;
+} EFI_PCI_CAPABILITY_SLOTID;
+
+///
+/// Message Capability Structure for 32-bit Message Address
+/// Section 6.8.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT16                  MsgCtrlReg;
+  UINT32                  MsgAddrReg;
+  UINT16                  MsgDataReg;
+} EFI_PCI_CAPABILITY_MSI32;
+
+///
+/// Message Capability Structure for 64-bit Message Address
+/// Section 6.8.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  UINT16                  MsgCtrlReg;
+  UINT32                  MsgAddrRegLsdw;
+  UINT32                  MsgAddrRegMsdw;
+  UINT16                  MsgDataReg;
+} EFI_PCI_CAPABILITY_MSI64;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_HOTPLUG,
+/// CompactPCI Hot Swap Specification PICMG 2.1, R1.0
+///
+typedef struct {
+  EFI_PCI_CAPABILITY_HDR  Hdr;
+  ///
+  /// not finished - fields need to go here
+  ///
+} EFI_PCI_CAPABILITY_HOTPLUG;
+
+#define DEVICE_ID_NOCARE    0xFFFF
+
+#define PCI_ACPI_UNUSED     0
+#define PCI_BAR_NOCHANGE    0
+#define PCI_BAR_OLD_ALIGN   0xFFFFFFFFFFFFFFFFULL
+#define PCI_BAR_EVEN_ALIGN  0xFFFFFFFFFFFFFFFEULL
+#define PCI_BAR_SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
+#define PCI_BAR_DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
+
+#define PCI_BAR_IDX0        0x00
+#define PCI_BAR_IDX1        0x01
+#define PCI_BAR_IDX2        0x02
+#define PCI_BAR_IDX3        0x03
+#define PCI_BAR_IDX4        0x04
+#define PCI_BAR_IDX5        0x05
+#define PCI_BAR_ALL         0xFF
+
+///
+/// EFI PCI Option ROM definitions
+///
+#define EFI_ROOT_BRIDGE_LIST                            'eprb'
+#define EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE       0x0EF1  ///< defined in UEFI Spec.
+
+#define PCI_EXPANSION_ROM_HEADER_SIGNATURE              0xaa55
+#define PCI_DATA_STRUCTURE_SIGNATURE                    SIGNATURE_32 ('P', 'C', 'I', 'R')
+#define PCI_CODE_TYPE_PCAT_IMAGE                        0x00
+#define EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED         0x0001  ///< defined in UEFI spec.
+
+///
+/// Standard PCI Expansion ROM Header
+/// Section 13.4.2, Unified Extensible Firmware Interface Specification, Version 2.1
+///
+typedef struct {
+  UINT16  Signature;    ///< 0xaa55
+  UINT8   Reserved[0x16];
+  UINT16  PcirOffset;
+} PCI_EXPANSION_ROM_HEADER;
+
+///
+/// Legacy ROM Header Extensions
+/// Section 6.3.3.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  UINT16  Signature;    ///< 0xaa55
+  UINT8   Size512;
+  UINT8   InitEntryPoint[3];
+  UINT8   Reserved[0x12];
+  UINT16  PcirOffset;
+} EFI_LEGACY_EXPANSION_ROM_HEADER;
+
+///
+/// PCI Data Structure Format
+/// Section 6.3.1.2, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+  UINT32  Signature;    ///< "PCIR"
+  UINT16  VendorId;
+  UINT16  DeviceId;
+  UINT16  Reserved0;
+  UINT16  Length;
+  UINT8   Revision;
+  UINT8   ClassCode[3];
+  UINT16  ImageLength;
+  UINT16  CodeRevision;
+  UINT8   CodeType;
+  UINT8   Indicator;
+  UINT16  Reserved1;
+} PCI_DATA_STRUCTURE;
+
+///
+/// EFI PCI Expansion ROM Header
+/// Section 13.4.2, Unified Extensible Firmware Interface Specification, Version 2.1
+///
+typedef struct {
+  UINT16  Signature;    ///< 0xaa55
+  UINT16  InitializationSize;
+  UINT32  EfiSignature; ///< 0x0EF1
+  UINT16  EfiSubsystem;
+  UINT16  EfiMachineType;
+  UINT16  CompressionType;
+  UINT8   Reserved[8];
+  UINT16  EfiImageHeaderOffset;
+  UINT16  PcirOffset;
+} EFI_PCI_EXPANSION_ROM_HEADER;
+
+typedef union {
+  UINT8                           *Raw;
+  PCI_EXPANSION_ROM_HEADER        *Generic;
+  EFI_PCI_EXPANSION_ROM_HEADER    *Efi;
+  EFI_LEGACY_EXPANSION_ROM_HEADER *PcAt;
+} EFI_PCI_ROM_HEADER;
+
+#pragma pack()
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h
new file mode 100644
index 0000000..fb4c2aa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h
@@ -0,0 +1,757 @@
+/** @file
+  EFI image format for PE32, PE32+ and TE. Please note some data structures are
+  different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+  EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+  This file is coded to the Visual Studio, Microsoft Portable Executable and
+  Common Object File Format Specification, Revision 8.0 - May 16, 2006.
+  This file also includes some definitions in PI Specification, Revision 1.0.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PE_IMAGE_H__
+#define __PE_IMAGE_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// PE32+ Subsystem type for EFI images
+//
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION         10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER      12
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER      13 ///< defined PI Specification, 1.0
+
+
+//
+// PE32+ Machine type for EFI images
+//
+#define IMAGE_FILE_MACHINE_I386            0x014c
+#define IMAGE_FILE_MACHINE_IA64            0x0200
+#define IMAGE_FILE_MACHINE_EBC             0x0EBC
+#define IMAGE_FILE_MACHINE_X64             0x8664
+#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED  0x01c2
+
+//
+// EXE file formats
+//
+#define EFI_IMAGE_DOS_SIGNATURE     SIGNATURE_16('M', 'Z')
+#define EFI_IMAGE_OS2_SIGNATURE     SIGNATURE_16('N', 'E')
+#define EFI_IMAGE_OS2_SIGNATURE_LE  SIGNATURE_16('L', 'E')
+#define EFI_IMAGE_NT_SIGNATURE      SIGNATURE_32('P', 'E', '\0', '\0')
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+  UINT16  e_magic;    ///< Magic number.
+  UINT16  e_cblp;     ///< Bytes on last page of file.
+  UINT16  e_cp;       ///< Pages in file.
+  UINT16  e_crlc;     ///< Relocations.
+  UINT16  e_cparhdr;  ///< Size of header in paragraphs.
+  UINT16  e_minalloc; ///< Minimum extra paragraphs needed.
+  UINT16  e_maxalloc; ///< Maximum extra paragraphs needed.
+  UINT16  e_ss;       ///< Initial (relative) SS value.
+  UINT16  e_sp;       ///< Initial SP value.
+  UINT16  e_csum;     ///< Checksum.
+  UINT16  e_ip;       ///< Initial IP value.
+  UINT16  e_cs;       ///< Initial (relative) CS value.
+  UINT16  e_lfarlc;   ///< File address of relocation table.
+  UINT16  e_ovno;     ///< Overlay number.
+  UINT16  e_res[4];   ///< Reserved words.
+  UINT16  e_oemid;    ///< OEM identifier (for e_oeminfo).
+  UINT16  e_oeminfo;  ///< OEM information; e_oemid specific.
+  UINT16  e_res2[10]; ///< Reserved words.
+  UINT32  e_lfanew;   ///< File address of new exe header.
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// COFF File Header (Object and Image).
+///
+typedef struct {
+  UINT16  Machine;
+  UINT16  NumberOfSections;
+  UINT32  TimeDateStamp;
+  UINT32  PointerToSymbolTable;
+  UINT32  NumberOfSymbols;
+  UINT16  SizeOfOptionalHeader;
+  UINT16  Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+///
+/// Size of EFI_IMAGE_FILE_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_FILE_HEADER        20
+
+//
+// Characteristics
+//
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED      BIT0     ///< 0x0001  Relocation info stripped from file.
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE     BIT1     ///< 0x0002  File is executable  (i.e. no unresolved externel references).
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED   BIT2     ///< 0x0004  Line nunbers stripped from file.
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED  BIT3     ///< 0x0008  Local symbols stripped from file.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO    BIT7     ///< 0x0080  Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_32BIT_MACHINE        BIT8     ///< 0x0100  32 bit word machine.
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED       BIT9     ///< 0x0200  Debugging info stripped from file in .DBG file.
+#define EFI_IMAGE_FILE_SYSTEM               BIT12    ///< 0x1000  System File.
+#define EFI_IMAGE_FILE_DLL                  BIT13    ///< 0x2000  File is a DLL.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI    BIT15    ///< 0x8000  Bytes of machine word are reversed.
+
+///
+/// Header Data Directories.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+//
+// Directory Entries
+//
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT      0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT      1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE    2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION   3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY    4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC   5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG       6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT   7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR   8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS         9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+
+///
+/// Optional Header Standard Fields for PE32.
+///
+typedef struct {
+  ///
+  /// Standard fields.
+  ///
+  UINT16                    Magic;
+  UINT8                     MajorLinkerVersion;
+  UINT8                     MinorLinkerVersion;
+  UINT32                    SizeOfCode;
+  UINT32                    SizeOfInitializedData;
+  UINT32                    SizeOfUninitializedData;
+  UINT32                    AddressOfEntryPoint;
+  UINT32                    BaseOfCode;
+  UINT32                    BaseOfData;  ///< PE32 contains this additional field, which is absent in PE32+.
+  ///
+  /// Optional Header Windows-Specific Fields.
+  ///
+  UINT32                    ImageBase;
+  UINT32                    SectionAlignment;
+  UINT32                    FileAlignment;
+  UINT16                    MajorOperatingSystemVersion;
+  UINT16                    MinorOperatingSystemVersion;
+  UINT16                    MajorImageVersion;
+  UINT16                    MinorImageVersion;
+  UINT16                    MajorSubsystemVersion;
+  UINT16                    MinorSubsystemVersion;
+  UINT32                    Win32VersionValue;
+  UINT32                    SizeOfImage;
+  UINT32                    SizeOfHeaders;
+  UINT32                    CheckSum;
+  UINT16                    Subsystem;
+  UINT16                    DllCharacteristics;
+  UINT32                    SizeOfStackReserve;
+  UINT32                    SizeOfStackCommit;
+  UINT32                    SizeOfHeapReserve;
+  UINT32                    SizeOfHeapCommit;
+  UINT32                    LoaderFlags;
+  UINT32                    NumberOfRvaAndSizes;
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER32;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+///
+/// Optional Header Standard Fields for PE32+.
+///
+typedef struct {
+  ///
+  /// Standard fields.
+  ///
+  UINT16                    Magic;
+  UINT8                     MajorLinkerVersion;
+  UINT8                     MinorLinkerVersion;
+  UINT32                    SizeOfCode;
+  UINT32                    SizeOfInitializedData;
+  UINT32                    SizeOfUninitializedData;
+  UINT32                    AddressOfEntryPoint;
+  UINT32                    BaseOfCode;
+  ///
+  /// Optional Header Windows-Specific Fields.
+  ///
+  UINT64                    ImageBase;
+  UINT32                    SectionAlignment;
+  UINT32                    FileAlignment;
+  UINT16                    MajorOperatingSystemVersion;
+  UINT16                    MinorOperatingSystemVersion;
+  UINT16                    MajorImageVersion;
+  UINT16                    MinorImageVersion;
+  UINT16                    MajorSubsystemVersion;
+  UINT16                    MinorSubsystemVersion;
+  UINT32                    Win32VersionValue;
+  UINT32                    SizeOfImage;
+  UINT32                    SizeOfHeaders;
+  UINT32                    CheckSum;
+  UINT16                    Subsystem;
+  UINT16                    DllCharacteristics;
+  UINT64                    SizeOfStackReserve;
+  UINT64                    SizeOfStackCommit;
+  UINT64                    SizeOfHeapReserve;
+  UINT64                    SizeOfHeapCommit;
+  UINT32                    LoaderFlags;
+  UINT32                    NumberOfRvaAndSizes;
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER64;
+
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
+///
+typedef struct {
+  UINT32                      Signature;
+  EFI_IMAGE_FILE_HEADER       FileHeader;
+  EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS32;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
+
+///
+/// @attention
+/// EFI_IMAGE_HEADERS64 is for use ONLY by tools.
+///
+typedef struct {
+  UINT32                      Signature;
+  EFI_IMAGE_FILE_HEADER       FileHeader;
+  EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS64;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
+
+//
+// Other Windows Subsystem Values
+//
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN     0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE      1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI     5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI   7
+
+///
+/// Length of ShortName.
+///
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+///
+/// Section Table. This table immediately follows the optional header.
+///
+typedef struct {
+  UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+  union {
+    UINT32  PhysicalAddress;
+    UINT32  VirtualSize;
+  } Misc;
+  UINT32  VirtualAddress;
+  UINT32  SizeOfRawData;
+  UINT32  PointerToRawData;
+  UINT32  PointerToRelocations;
+  UINT32  PointerToLinenumbers;
+  UINT16  NumberOfRelocations;
+  UINT16  NumberOfLinenumbers;
+  UINT32  Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+///
+/// Size of EFI_IMAGE_SECTION_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER       40
+
+//
+// Section Flags Values
+//
+#define EFI_IMAGE_SCN_TYPE_NO_PAD                  BIT3   ///< 0x00000008  ///< Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE                     BIT5   ///< 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA         BIT6   ///< 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA       BIT7   ///< 0x00000080
+
+#define EFI_IMAGE_SCN_LNK_OTHER                    BIT8   ///< 0x00000100  ///< Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO                     BIT9   ///< 0x00000200  ///< Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE                   BIT11  ///< 0x00000800  ///< Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT                   BIT12  ///< 0x00001000
+
+#define EFI_IMAGE_SCN_ALIGN_1BYTES                 BIT20  ///< 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES                 BIT21  ///< 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES          (BIT20|BIT21) ///< 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES                 BIT22  ///< 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES         (BIT20|BIT22) ///< 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES         (BIT21|BIT22) ///< 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES   (BIT20|BIT21|BIT22) ///< 0x00700000
+
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE              BIT25  ///< 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED               BIT26  ///< 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED                BIT27  ///< 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED                   BIT28  ///< 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE                  BIT29  ///< 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ                     BIT30  ///< 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE                    BIT31  ///< 0x80000000
+
+///
+/// Size of a Symbol Table Record.
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0  ///< Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE  (UINT16) -1 ///< Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG     (UINT16) -2 ///< Symbol is a special debug item.
+
+//
+// Symbol Type (fundamental) values.
+//
+#define EFI_IMAGE_SYM_TYPE_NULL   0   ///< no type.
+#define EFI_IMAGE_SYM_TYPE_VOID   1   ///< no valid type.
+#define EFI_IMAGE_SYM_TYPE_CHAR   2   ///< type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT  3   ///< type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT    4
+#define EFI_IMAGE_SYM_TYPE_LONG   5
+#define EFI_IMAGE_SYM_TYPE_FLOAT  6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION  9
+#define EFI_IMAGE_SYM_TYPE_ENUM   10  ///< enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE    11  ///< member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE   12
+#define EFI_IMAGE_SYM_TYPE_WORD   13
+#define EFI_IMAGE_SYM_TYPE_UINT   14
+#define EFI_IMAGE_SYM_TYPE_DWORD  15
+
+//
+// Symbol Type (derived) values.
+//
+#define EFI_IMAGE_SYM_DTYPE_NULL      0 ///< no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER   1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION  2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY     3
+
+//
+// Storage classes.
+//
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION   ((UINT8) -1)
+#define EFI_IMAGE_SYM_CLASS_NULL              0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC         1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL          2
+#define EFI_IMAGE_SYM_CLASS_STATIC            3
+#define EFI_IMAGE_SYM_CLASS_REGISTER          4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF      5
+#define EFI_IMAGE_SYM_CLASS_LABEL             6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL   7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT  8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT          9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG        10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION   11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG         12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION   13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC  14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG          15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM    16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM    17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD         18
+#define EFI_IMAGE_SYM_CLASS_BLOCK             100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION          101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT     102
+#define EFI_IMAGE_SYM_CLASS_FILE              103
+#define EFI_IMAGE_SYM_CLASS_SECTION           104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL     105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK  017
+#define EFI_IMAGE_N_TMASK   060
+#define EFI_IMAGE_N_TMASK1  0300
+#define EFI_IMAGE_N_TMASK2  0360
+#define EFI_IMAGE_N_BTSHFT  4
+#define EFI_IMAGE_N_TSHIFT  2
+
+//
+// Communal selection types.
+//
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES    1
+#define EFI_IMAGE_COMDAT_SELECT_ANY             2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE       3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH     4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE     5
+
+//
+// the following values only be referred in PeCoff, not defined in PECOFF.
+//
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY  1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY    2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS      3
+
+///
+/// Relocation format.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  SymbolTableIndex;
+  UINT16  Type;
+} EFI_IMAGE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_RELOCATION
+///
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000  ///< Reference is absolute, no relocation is necessary.
+#define EFI_IMAGE_REL_I386_DIR16    0x0001  ///< Direct 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_REL16    0x0002  ///< PC-relative 16-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32    0x0006  ///< Direct 32-bit reference to the symbols virtual address.
+#define EFI_IMAGE_REL_I386_DIR32NB  0x0007  ///< Direct 32-bit reference to the symbols virtual address, base not included.
+#define EFI_IMAGE_REL_I386_SEG12    0x0009  ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address.
+#define EFI_IMAGE_REL_I386_SECTION  0x000A
+#define EFI_IMAGE_REL_I386_SECREL   0x000B
+#define EFI_IMAGE_REL_I386_REL32    0x0014  ///< PC-relative 32-bit reference to the symbols virtual address.
+
+//
+// x64 processor relocation types.
+//
+#define IMAGE_REL_AMD64_ABSOLUTE  0x0000
+#define IMAGE_REL_AMD64_ADDR64    0x0001
+#define IMAGE_REL_AMD64_ADDR32    0x0002
+#define IMAGE_REL_AMD64_ADDR32NB  0x0003
+#define IMAGE_REL_AMD64_REL32     0x0004
+#define IMAGE_REL_AMD64_REL32_1   0x0005
+#define IMAGE_REL_AMD64_REL32_2   0x0006
+#define IMAGE_REL_AMD64_REL32_3   0x0007
+#define IMAGE_REL_AMD64_REL32_4   0x0008
+#define IMAGE_REL_AMD64_REL32_5   0x0009
+#define IMAGE_REL_AMD64_SECTION   0x000A
+#define IMAGE_REL_AMD64_SECREL    0x000B
+#define IMAGE_REL_AMD64_SECREL7   0x000C
+#define IMAGE_REL_AMD64_TOKEN     0x000D
+#define IMAGE_REL_AMD64_SREL32    0x000E
+#define IMAGE_REL_AMD64_PAIR      0x000F
+#define IMAGE_REL_AMD64_SSPAN32   0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+  UINT32  VirtualAddress;
+  UINT32  SizeOfBlock;
+} EFI_IMAGE_BASE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_BASE_RELOCATION.
+///
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION  8
+
+//
+// Based relocation types.
+//
+#define EFI_IMAGE_REL_BASED_ABSOLUTE        0
+#define EFI_IMAGE_REL_BASED_HIGH            1
+#define EFI_IMAGE_REL_BASED_LOW             2
+#define EFI_IMAGE_REL_BASED_HIGHLOW         3
+#define EFI_IMAGE_REL_BASED_HIGHADJ         4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR    5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32A      5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32T      7
+#define EFI_IMAGE_REL_BASED_IA64_IMM64      9
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16  9
+#define EFI_IMAGE_REL_BASED_DIR64           10
+
+///
+/// Line number format.
+///
+typedef struct {
+  union {
+    UINT32  SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0.
+    UINT32  VirtualAddress;   ///< Virtual address of line number.
+  } Type;
+  UINT16  Linenumber;         ///< Line number.
+} EFI_IMAGE_LINENUMBER;
+
+///
+/// Size of EFI_IMAGE_LINENUMBER.
+///
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+//
+// Archive format.
+//
+#define EFI_IMAGE_ARCHIVE_START_SIZE        8
+#define EFI_IMAGE_ARCHIVE_START             "!<arch>\n"
+#define EFI_IMAGE_ARCHIVE_END               "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD               "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER     "/               "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER  "//              "
+
+///
+/// Archive Member Headers
+///
+typedef struct {
+  UINT8 Name[16];     ///< File member name - `/' terminated.
+  UINT8 Date[12];     ///< File member date - decimal.
+  UINT8 UserID[6];    ///< File member user id - decimal.
+  UINT8 GroupID[6];   ///< File member group id - decimal.
+  UINT8 Mode[8];      ///< File member mode - octal.
+  UINT8 Size[10];     ///< File member size - decimal.
+  UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A).
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+///
+/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER.
+///
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+
+//
+// DLL Support
+//
+
+///
+/// Export Directory Table.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT32  Name;
+  UINT32  Base;
+  UINT32  NumberOfFunctions;
+  UINT32  NumberOfNames;
+  UINT32  AddressOfFunctions;
+  UINT32  AddressOfNames;
+  UINT32  AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// Hint/Name Table.
+///
+typedef struct {
+  UINT16  Hint;
+  UINT8   Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+///
+/// Import Address Table RVA (Thunk Table).
+///
+typedef struct {
+  union {
+    UINT32                    Function;
+    UINT32                    Ordinal;
+    EFI_IMAGE_IMPORT_BY_NAME  *AddressOfData;
+  } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG              BIT31    ///< Flag for PE32.
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal)  ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal)          (Ordinal & 0xffff)
+
+///
+/// Import Directory Table
+///
+typedef struct {
+  UINT32                Characteristics;
+  UINT32                TimeDateStamp;
+  UINT32                ForwarderChain;
+  UINT32                Name;
+  EFI_IMAGE_THUNK_DATA  *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+
+///
+/// Debug Directory Format.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT32  Type;
+  UINT32  SizeOfData;
+  UINT32  RVA;           ///< The address of the debug data when loaded, relative to the image base.
+  UINT32  FileOffset;    ///< The file pointer to the debug data.
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2     ///< The Visual C++ debug information.
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_NB10  SIGNATURE_32('N', 'B', '1', '0')
+typedef struct {
+  UINT32  Signature;                        ///< "NB10"
+  UINT32  Unknown;
+  UINT32  Unknown2;
+  UINT32  Unknown3;
+  //
+  // Filename of .PDB goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+///
+/// Debug Data Structure defined in Microsoft C++.
+///
+#define CODEVIEW_SIGNATURE_RSDS  SIGNATURE_32('R', 'S', 'D', 'S')
+typedef struct {
+  UINT32  Signature;                        ///< "RSDS".
+  UINT32  Unknown;
+  UINT32  Unknown2;
+  UINT32  Unknown3;
+  UINT32  Unknown4;
+  UINT32  Unknown5;
+  //
+  // Filename of .PDB goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+
+///
+/// Debug Data Structure defined by Apple Mach-O to Coff utility.
+///
+#define CODEVIEW_SIGNATURE_MTOC  SIGNATURE_32('M', 'T', 'O', 'C')
+typedef struct {
+  UINT32    Signature;                       ///< "MTOC".
+  GUID      MachOUuid;
+  //
+  //  Filename of .DLL (Mach-O with debug info) goes here
+  //
+} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
+
+///
+/// Resource format.
+///
+typedef struct {
+  UINT32  Characteristics;
+  UINT32  TimeDateStamp;
+  UINT16  MajorVersion;
+  UINT16  MinorVersion;
+  UINT16  NumberOfNamedEntries;
+  UINT16  NumberOfIdEntries;
+  //
+  // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here.
+  //
+} EFI_IMAGE_RESOURCE_DIRECTORY;
+
+///
+/// Resource directory entry format.
+///
+typedef struct {
+  union {
+    struct {
+      UINT32  NameOffset:31;
+      UINT32  NameIsString:1;
+    } s;
+    UINT32  Id;
+  } u1;
+  union {
+    UINT32  OffsetToData;
+    struct {
+      UINT32  OffsetToDirectory:31;
+      UINT32  DataIsDirectory:1;
+    } s;
+  } u2;
+} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY;
+
+///
+/// Resource directory entry for string.
+///
+typedef struct {
+  UINT16  Length;
+  CHAR16  String[1];
+} EFI_IMAGE_RESOURCE_DIRECTORY_STRING;
+
+///
+/// Resource directory entry for data array.
+///
+typedef struct {
+  UINT32  OffsetToData;
+  UINT32  Size;
+  UINT32  CodePage;
+  UINT32  Reserved;
+} EFI_IMAGE_RESOURCE_DATA_ENTRY;
+
+///
+/// Header format for TE images, defined in the PI Specification, 1.0.
+///
+typedef struct {
+  UINT16                    Signature;            ///< The signature for TE format = "VZ".
+  UINT16                    Machine;              ///< From the original file header.
+  UINT8                     NumberOfSections;     ///< From the original file header.
+  UINT8                     Subsystem;            ///< From original optional header.
+  UINT16                    StrippedSize;         ///< Number of bytes we removed from the header.
+  UINT32                    AddressOfEntryPoint;  ///< Offset to entry point -- from original optional header.
+  UINT32                    BaseOfCode;           ///< From original image -- required for ITP debug.
+  UINT64                    ImageBase;            ///< From original file header.
+  EFI_IMAGE_DATA_DIRECTORY  DataDirectory[2];     ///< Only base relocation and debug directory.
+} EFI_TE_IMAGE_HEADER;
+
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE  SIGNATURE_16('V', 'Z')
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC  0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG      1
+
+
+///
+/// Union of PE32, PE32+, and TE headers.
+///
+typedef union {
+  EFI_IMAGE_NT_HEADERS32   Pe32;
+  EFI_IMAGE_NT_HEADERS64   Pe32Plus;
+  EFI_TE_IMAGE_HEADER      Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+typedef union {
+  EFI_IMAGE_NT_HEADERS32            *Pe32;
+  EFI_IMAGE_NT_HEADERS64            *Pe32Plus;
+  EFI_TE_IMAGE_HEADER               *Te;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION   *Union;
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/LICENCE b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/LICENCE
new file mode 100644
index 0000000..6c28e6f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/LICENCE
@@ -0,0 +1,40 @@
+The EFI headers contained herein are copied from the EFI Development
+Kit, available from http://www.tianocore.org and published under the
+following licence:
+
+  BSD License from Intel
+  Copyright (c) 2004, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+  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.
+
+  Neither the name of the Intel Corporation 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 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 THE
+  COPYRIGHT OWNER 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.
+
+
+This licence applies only to files that are part of the EFI
+Development Kit.  Other files may contain their own licence terms, or
+may fall under the standard iPXE GPL licence.
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h
new file mode 100644
index 0000000..30fd443
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h
@@ -0,0 +1,43 @@
+/** @file
+  Present the boot mode values in PI.
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.0
+
+**/
+
+#ifndef __PI_BOOT_MODE_H__
+#define __PI_BOOT_MODE_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// EFI boot mode
+///
+typedef UINT32  EFI_BOOT_MODE;
+
+//
+// 0x21 - 0xf..f are reserved.
+//
+#define BOOT_WITH_FULL_CONFIGURATION                  0x00
+#define BOOT_WITH_MINIMAL_CONFIGURATION               0x01
+#define BOOT_ASSUMING_NO_CONFIGURATION_CHANGES        0x02
+#define BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03
+#define BOOT_WITH_DEFAULT_SETTINGS                    0x04
+#define BOOT_ON_S4_RESUME                             0x05
+#define BOOT_ON_S5_RESUME                             0x06
+#define BOOT_ON_S2_RESUME                             0x10
+#define BOOT_ON_S3_RESUME                             0x11
+#define BOOT_ON_FLASH_UPDATE                          0x12
+#define BOOT_IN_RECOVERY_MODE                         0x20
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDependency.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDependency.h
new file mode 100644
index 0000000..b1fa399
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDependency.h
@@ -0,0 +1,49 @@
+/** @file
+  Present the dependency expression values in PI.
+
+  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.0
+
+**/
+#ifndef __PI_DEPENDENCY_H__
+#define __PI_DEPENDENCY_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE may be used by DXE and SMM drivers.
+///
+#define EFI_DEP_BEFORE        0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER may be used by DXE and SMM drivers.
+///
+#define EFI_DEP_AFTER         0x01
+
+#define EFI_DEP_PUSH          0x02
+#define EFI_DEP_AND           0x03
+#define EFI_DEP_OR            0x04
+#define EFI_DEP_NOT           0x05
+#define EFI_DEP_TRUE          0x06
+#define EFI_DEP_FALSE         0x07
+#define EFI_DEP_END           0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR           0x09
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h
new file mode 100644
index 0000000..6c4f44b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h
@@ -0,0 +1,715 @@
+/** @file
+  Include file matches things in PI.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.0
+
+**/
+
+#ifndef __PI_DXECIS_H__
+#define __PI_DXECIS_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Uefi/UefiMultiPhase.h>
+#include <ipxe/efi/Pi/PiMultiPhase.h>
+
+///
+/// Global Coherencey Domain types - Memory type.
+///
+typedef enum {
+  ///
+  /// A memory region that is visible to the boot processor. However, there are no system
+  /// components that are currently decoding this memory region.
+  ///
+  EfiGcdMemoryTypeNonExistent,
+  ///
+  /// A memory region that is visible to the boot processor. This memory region is being
+  /// decoded by a system component, but the memory region is not considered to be either
+  /// system memory or memory-mapped I/O.
+  ///
+  EfiGcdMemoryTypeReserved,
+  ///
+  /// A memory region that is visible to the boot processor. A memory controller is
+  /// currently decoding this memory region and the memory controller is producing a
+  /// tested system memory region that is available to the memory services.
+  ///
+  EfiGcdMemoryTypeSystemMemory,
+  ///
+  /// A memory region that is visible to the boot processor. This memory region is
+  /// currently being decoded by a component as memory-mapped I/O that can be used to
+  /// access I/O devices in the platform.
+  ///
+  EfiGcdMemoryTypeMemoryMappedIo,
+  EfiGcdMemoryTypeMaximum
+} EFI_GCD_MEMORY_TYPE;
+
+///
+/// Global Coherencey Domain types - IO type.
+///
+typedef enum {
+  ///
+  /// An I/O region that is visible to the boot processor. However, there are no system
+  /// components that are currently decoding this I/O region.
+  ///
+  EfiGcdIoTypeNonExistent,
+  ///
+  /// An I/O region that is visible to the boot processor. This I/O region is currently being
+  /// decoded by a system component, but the I/O region cannot be used to access I/O devices.
+  ///
+  EfiGcdIoTypeReserved,
+  ///
+  /// An I/O region that is visible to the boot processor. This I/O region is currently being
+  /// decoded by a system component that is producing I/O ports that can be used to access I/O devices.
+  ///
+  EfiGcdIoTypeIo,
+  EfiGcdIoTypeMaximum
+} EFI_GCD_IO_TYPE;
+
+///
+/// The type of allocation to perform.
+///
+typedef enum {
+  ///
+  /// The GCD memory space map is searched from the lowest address up to the highest address
+  /// looking for unallocated memory ranges.
+  ///
+  EfiGcdAllocateAnySearchBottomUp,
+  ///
+  /// The GCD memory space map is searched from the lowest address up
+  /// to the specified MaxAddress looking for unallocated memory ranges.
+  ///
+  EfiGcdAllocateMaxAddressSearchBottomUp,
+  ///
+  /// The GCD memory space map is checked to see if the memory range starting
+  /// at the specified Address is available.
+  ///
+  EfiGcdAllocateAddress,
+  ///
+  /// The GCD memory space map is searched from the highest address down to the lowest address
+  /// looking for unallocated memory ranges.
+  ///
+  EfiGcdAllocateAnySearchTopDown,
+  ///
+  /// The GCD memory space map is searched from the specified MaxAddress
+  /// down to the lowest address looking for unallocated memory ranges.
+  ///
+  EfiGcdAllocateMaxAddressSearchTopDown,
+  EfiGcdMaxAllocateType
+} EFI_GCD_ALLOCATE_TYPE;
+
+///
+/// EFI_GCD_MEMORY_SPACE_DESCRIPTOR.
+///
+typedef struct {
+  ///
+  /// The physical address of the first byte in the memory region. Type
+  /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+  /// description in the UEFI 2.0 specification.
+  ///
+  EFI_PHYSICAL_ADDRESS  BaseAddress;
+
+  ///
+  /// The number of bytes in the memory region.
+  ///
+  UINT64                Length;
+
+  ///
+  /// The bit mask of attributes that the memory region is capable of supporting. The bit
+  /// mask of available attributes is defined in the GetMemoryMap() function description
+  /// in the UEFI 2.0 specification.
+  ///
+  UINT64                Capabilities;
+  ///
+  /// The bit mask of attributes that the memory region is currently using. The bit mask of
+  /// available attributes is defined in GetMemoryMap().
+  ///
+  UINT64                Attributes;
+  ///
+  /// Type of the memory region. Type EFI_GCD_MEMORY_TYPE is defined in the
+  /// AddMemorySpace() function description.
+  ///
+  EFI_GCD_MEMORY_TYPE   GcdMemoryType;
+
+  ///
+  /// The image handle of the agent that allocated the memory resource described by
+  /// PhysicalStart and NumberOfBytes. If this field is NULL, then the memory
+  /// resource is not currently allocated. Type EFI_HANDLE is defined in
+  /// InstallProtocolInterface() in the UEFI 2.0 specification.
+  ///
+  EFI_HANDLE            ImageHandle;
+
+  ///
+  /// The device handle for which the memory resource has been allocated. If
+  /// ImageHandle is NULL, then the memory resource is not currently allocated. If this
+  /// field is NULL, then the memory resource is not associated with a device that is
+  /// described by a device handle. Type EFI_HANDLE is defined in
+  /// InstallProtocolInterface() in the UEFI 2.0 specification.
+  ///
+  EFI_HANDLE            DeviceHandle;
+} EFI_GCD_MEMORY_SPACE_DESCRIPTOR;
+
+///
+/// EFI_GCD_IO_SPACE_DESCRIPTOR.
+///
+typedef struct {
+  ///
+  /// Physical address of the first byte in the I/O region. Type
+  /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+  /// description in the UEFI 2.0 specification.
+  ///
+  EFI_PHYSICAL_ADDRESS  BaseAddress;
+
+  ///
+  /// Number of bytes in the I/O region.
+  ///
+  UINT64                Length;
+
+  ///
+  /// Type of the I/O region. Type EFI_GCD_IO_TYPE is defined in the
+  /// AddIoSpace() function description.
+  ///
+  EFI_GCD_IO_TYPE       GcdIoType;
+
+  ///
+  /// The image handle of the agent that allocated the I/O resource described by
+  /// PhysicalStart and NumberOfBytes. If this field is NULL, then the I/O
+  /// resource is not currently allocated. Type EFI_HANDLE is defined in
+  /// InstallProtocolInterface() in the UEFI 2.0 specification.
+  ///
+  EFI_HANDLE            ImageHandle;
+
+  ///
+  /// The device handle for which the I/O resource has been allocated. If ImageHandle
+  /// is NULL, then the I/O resource is not currently allocated. If this field is NULL, then
+  /// the I/O resource is not associated with a device that is described by a device handle.
+  /// Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI
+  /// 2.0 specification.
+  ///
+  EFI_HANDLE            DeviceHandle;
+} EFI_GCD_IO_SPACE_DESCRIPTOR;
+
+
+/**
+  Adds reserved memory, system memory, or memory-mapped I/O resources to the
+  global coherency domain of the processor.
+
+  @param  GcdMemoryType    The type of memory resource being added.
+  @param  BaseAddress      The physical address that is the start address
+                           of the memory resource being added.
+  @param  Length           The size, in bytes, of the memory resource that
+                           is being added.
+  @param  Capabilities     The bit mask of attributes that the memory
+                           resource region supports.
+
+  @retval EFI_SUCCESS            The memory resource was added to the global
+                                 coherency domain of the processor.
+  @retval EFI_INVALID_PARAMETER  GcdMemoryType is invalid.
+  @retval EFI_INVALID_PARAMETER  Length is zero.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough system resources to add
+                                 the memory resource to the global coherency
+                                 domain of the processor.
+  @retval EFI_UNSUPPORTED        The processor does not support one or more bytes
+                                 of the memory resource range specified by
+                                 BaseAddress and Length.
+  @retval EFI_ACCESS_DENIED      One or more bytes of the memory resource range
+                                 specified by BaseAddress and Length conflicts
+                                 with a memory resource range that was previously
+                                 added to the global coherency domain of the processor.
+  @retval EFI_ACCESS_DENIED      One or more bytes of the memory resource range
+                                 specified by BaseAddress and Length was allocated
+                                 in a prior call to AllocateMemorySpace().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_MEMORY_SPACE)(
+  IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                Capabilities
+  );
+
+/**
+  Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+  I/O resources from the global coherency domain of the processor.
+
+  @param  GcdAllocateType  The type of allocation to perform.
+  @param  GcdMemoryType    The type of memory resource being allocated.
+  @param  Alignment        The log base 2 of the boundary that BaseAddress must
+                           be aligned on output. Align with 2^Alignment.
+  @param  Length           The size in bytes of the memory resource range that
+                           is being allocated.
+  @param  BaseAddress      A pointer to a physical address to allocate.
+  @param  Imagehandle      The image handle of the agent that is allocating
+                           the memory resource.
+  @param  DeviceHandle     The device handle for which the memory resource
+                           is being allocated.
+
+  @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+  @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+  @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+  @retval EFI_NOT_FOUND         The memory resource request could not be satisfied.
+                                No descriptor contains the desired space.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to allocate the memory
+                                resource from the global coherency domain of the processor.
+  @retval EFI_SUCCESS           The memory resource was allocated from the global coherency
+                                domain of the processor.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_MEMORY_SPACE)(
+  IN     EFI_GCD_ALLOCATE_TYPE               GcdAllocateType,
+  IN     EFI_GCD_MEMORY_TYPE                 GcdMemoryType,
+  IN     UINTN                               Alignment,
+  IN     UINT64                              Length,
+  IN OUT EFI_PHYSICAL_ADDRESS                *BaseAddress,
+  IN     EFI_HANDLE                          ImageHandle,
+  IN     EFI_HANDLE                          DeviceHandle OPTIONAL
+  );
+
+/**
+  Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+  I/O resources from the global coherency domain of the processor.
+
+  @param  BaseAddress      The physical address that is the start address of the memory resource being freed.
+  @param  Length           The size in bytes of the memory resource range that is being freed.
+
+  @retval EFI_SUCCESS           The memory resource was freed from the global coherency domain of
+                                the processor.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_NOT_FOUND         The memory resource range specified by BaseAddress and
+                                Length was not allocated with previous calls to AllocateMemorySpace().
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to free the memory resource
+                                from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_MEMORY_SPACE)(
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length
+  );
+
+/**
+  Removes reserved memory, system memory, or memory-mapped I/O resources from
+  the global coherency domain of the processor.
+
+  @param  BaseAddress      The physical address that is the start address of the memory resource being removed.
+  @param  Length           The size in bytes of the memory resource that is being removed.
+
+  @retval EFI_SUCCESS           The memory resource was removed from the global coherency
+                                domain of the processor.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_NOT_FOUND         One or more bytes of the memory resource range specified by
+                                BaseAddress and Length was not added with previous calls to
+                                AddMemorySpace().
+  @retval EFI_ACCESS_DEFINED    One or more bytes of the memory resource range specified by
+                                BaseAddress and Length has been allocated with AllocateMemorySpace().
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to remove the memory
+                                resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_MEMORY_SPACE)(
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length
+  );
+
+/**
+  Retrieves the descriptor for a memory region containing a specified address.
+
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Descriptor       A pointer to a caller allocated descriptor.
+
+  @retval EFI_SUCCESS           The descriptor for the memory resource region containing
+                                BaseAddress was returned in Descriptor.
+  @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+  @retval EFI_NOT_FOUND         A memory resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_DESCRIPTOR)(
+  IN  EFI_PHYSICAL_ADDRESS             BaseAddress,
+  OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor
+  );
+
+/**
+  Modifies the attributes for a memory region in the global coherency domain of the
+  processor.
+
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  Attributes       The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_UNSUPPORTED       The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+  @retval EFI_ACCESS_DEFINED    The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_MEMORY_SPACE_ATTRIBUTES)(
+  IN EFI_PHYSICAL_ADDRESS         BaseAddress,
+  IN UINT64                       Length,
+  IN UINT64                       Attributes
+  );
+
+/**
+  Returns a map of the memory resources in the global coherency domain of the
+  processor.
+
+  @param  NumberOfDescriptors A pointer to number of descriptors returned in the MemorySpaceMap buffer.
+  @param  MemorySpaceMap      A pointer to the array of EFI_GCD_MEMORY_SPACE_DESCRIPTORs.
+
+  @retval EFI_SUCCESS           The memory space map was returned in the MemorySpaceMap
+                                buffer, and the number of descriptors in MemorySpaceMap was
+                                returned in NumberOfDescriptors.
+  @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+  @retval EFI_INVALID_PARAMETER MemorySpaceMap is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate MemorySpaceMap.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_MAP)(
+  OUT UINTN                            *NumberOfDescriptors,
+  OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  **MemorySpaceMap
+  );
+
+/**
+  Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+  @param  GcdIoType        The type of I/O resource being added.
+  @param  BaseAddress      The physical address that is the start address of the I/O resource being added.
+  @param  Length           The size in bytes of the I/O resource that is being added.
+
+  @retval EFI_SUCCESS           The I/O resource was added to the global coherency domain of
+                                the processor.
+  @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to add the I/O resource to
+                                the global coherency domain of the processor.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the I/O
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_ACCESS_DENIED     One or more bytes of the I/O resource range specified by
+                                BaseAddress and Length conflicts with an I/O resource
+                                range that was previously added to the global coherency domain
+                                of the processor.
+  @retval EFI_ACCESS_DENIED     One or more bytes of the I/O resource range specified by
+                                BaseAddress and Length was allocated in a prior call to
+                                AllocateIoSpace().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_IO_SPACE)(
+  IN EFI_GCD_IO_TYPE       GcdIoType,
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length
+  );
+
+/**
+  Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+  domain of the processor.
+
+  @param  GcdAllocateType  The type of allocation to perform.
+  @param  GcdIoType        The type of I/O resource being allocated.
+  @param  Alignment        The log base 2 of the boundary that BaseAddress must be aligned on output.
+  @param  Length           The size in bytes of the I/O resource range that is being allocated.
+  @param  BaseAddress      A pointer to a physical address.
+  @param  Imagehandle      The image handle of the agent that is allocating the I/O resource.
+  @param  DeviceHandle     The device handle for which the I/O resource is being allocated.
+
+  @retval EFI_SUCCESS           The I/O resource was allocated from the global coherency domain
+                                of the processor.
+  @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+  @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+  @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to allocate the I/O
+                                resource from the global coherency domain of the processor.
+  @retval EFI_NOT_FOUND         The I/O resource request could not be satisfied.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_IO_SPACE)(
+  IN     EFI_GCD_ALLOCATE_TYPE               GcdAllocateType,
+  IN     EFI_GCD_IO_TYPE                     GcdIoType,
+  IN     UINTN                               Alignment,
+  IN     UINT64                              Length,
+  IN OUT EFI_PHYSICAL_ADDRESS                *BaseAddress,
+  IN     EFI_HANDLE                          ImageHandle,
+  IN     EFI_HANDLE                          DeviceHandle OPTIONAL
+  );
+
+/**
+  Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+  domain of the processor.
+
+  @param  BaseAddress      The physical address that is the start address of the I/O resource being freed.
+  @param  Length           The size in bytes of the I/O resource range that is being freed.
+
+  @retval EFI_SUCCESS           The I/O resource was freed from the global coherency domain of the
+                                processor.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the I/O resource
+                                range specified by BaseAddress and Length.
+  @retval EFI_NOT_FOUND         The I/O resource range specified by BaseAddress and Length
+                                was not allocated with previous calls to AllocateIoSpace().
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to free the I/O resource from
+                                the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_IO_SPACE)(
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length
+  );
+
+/**
+  Removes reserved I/O or I/O resources from the global coherency domain of the
+  processor.
+
+  @param  BaseAddress      A pointer to a physical address that is the start address of the I/O resource being
+                           removed.
+  @param Length            The size in bytes of the I/O resource that is being removed.
+
+  @retval EFI_SUCCESS           The I/O resource was removed from the global coherency domain
+                                of the processor.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the I/O
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_NOT_FOUND         One or more bytes of the I/O resource range specified by
+                                BaseAddress and Length was not added with previous
+                                calls to AddIoSpace().
+  @retval EFI_ACCESS_DENIED     One or more bytes of the I/O resource range specified by
+                                BaseAddress and Length has been allocated with
+                                AllocateIoSpace().
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to remove the I/O
+                                resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_IO_SPACE)(
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length
+  );
+
+/**
+  Retrieves the descriptor for an I/O region containing a specified address.
+
+  @param  BaseAddress      The physical address that is the start address of an I/O region.
+  @param  Descriptor       A pointer to a caller allocated descriptor.
+
+  @retval EFI_SUCCESS           The descriptor for the I/O resource region containing
+                                BaseAddress was returned in Descriptor.
+  @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+  @retval EFI_NOT_FOUND         An I/O resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_DESCRIPTOR)(
+  IN  EFI_PHYSICAL_ADDRESS         BaseAddress,
+  OUT EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor
+  );
+
+/**
+  Returns a map of the I/O resources in the global coherency domain of the processor.
+
+  @param  NumberOfDescriptors A pointer to number of descriptors returned in the IoSpaceMap buffer.
+  @param  MemorySpaceMap      A pointer to the array of EFI_GCD_IO_SPACE_DESCRIPTORs.
+
+  @retval EFI_SUCCESS           The I/O space map was returned in the IoSpaceMap buffer, and
+                                the number of descriptors in IoSpaceMap was returned in
+                                NumberOfDescriptors.
+  @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+  @retval EFI_INVALID_PARAMETER IoSpaceMap is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate IoSpaceMap.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_MAP)(
+  OUT UINTN                        *NumberOfDescriptors,
+  OUT EFI_GCD_IO_SPACE_DESCRIPTOR  **IoSpaceMap
+  );
+
+
+
+/**
+  Loads and executed DXE drivers from firmware volumes.
+
+  The Dispatch() function searches for DXE drivers in firmware volumes that have been
+  installed since the last time the Dispatch() service was called. It then evaluates
+  the dependency expressions of all the DXE drivers and loads and executes those DXE
+  drivers whose dependency expression evaluate to TRUE. This service must interact with
+  the Security Architectural Protocol to authenticate DXE drivers before they are executed.
+  This process is continued until no more DXE drivers can be executed.
+
+  @retval EFI_SUCCESS         One or more DXE driver were dispatched.
+  @retval EFI_NOT_FOUND       No DXE drivers were dispatched.
+  @retval EFI_ALREADY_STARTED An attempt is being made to start the DXE Dispatcher recursively.
+                              Thus, no action was taken.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISPATCH)(
+  VOID
+  );
+
+/**
+  Clears the Schedule on Request (SOR) flag for a component that is stored in a firmware volume.
+
+  @param  FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+  @param  FileName             A pointer to the name of the file in a firmware volume.
+
+  @retval EFI_SUCCESS         The DXE driver was found and its SOR bit was cleared.
+  @retval EFI_NOT_FOUND       The DXE driver does not exist, or the DXE driver exists and its SOR
+                              bit is not set.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SCHEDULE)(
+  IN EFI_HANDLE  FirmwareVolumeHandle,
+  IN CONST EFI_GUID    *FileName
+  );
+
+/**
+  Promotes a file stored in a firmware volume from the untrusted to the trusted state.
+
+  @param  FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+  @param  DriverName           A pointer to the name of the file in a firmware volume.
+
+  @return Status of promoting FFS from untrusted to trusted
+          state.
+  @retval EFI_NOT_FOUND       The file was not found in the untrusted state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TRUST)(
+  IN EFI_HANDLE  FirmwareVolumeHandle,
+  IN CONST EFI_GUID    *FileName
+  );
+
+/**
+  Creates a firmware volume handle for a firmware volume that is present in system memory.
+
+  @param  FirmwareVolumeHeader A pointer to the header of the firmware volume.
+  @param  Size                 The size, in bytes, of the firmware volume.
+  @param  FirmwareVolumeHandle On output, a pointer to the created handle.
+
+  @retval EFI_SUCCESS          The EFI_FIRMWARE_VOLUME_PROTOCOL and
+                               EFI_DEVICE_PATH_PROTOCOL were installed onto
+                               FirmwareVolumeHandle for the firmware volume described
+                               by FirmwareVolumeHeader and Size.
+  @retval EFI_VOLUME_CORRUPTED The firmware volume described by FirmwareVolumeHeader
+                               and Size is corrupted.
+  @retval EFI_OUT_OF_RESOURCES There are not enough system resources available to produce the
+                               EFI_FIRMWARE_VOLUME_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL
+                               for the firmware volume described by FirmwareVolumeHeader and Size.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROCESS_FIRMWARE_VOLUME)(
+  IN CONST VOID                       *FirmwareVolumeHeader,
+  IN UINTN                            Size,
+  OUT EFI_HANDLE                      *FirmwareVolumeHandle
+  );
+
+//
+// DXE Services Table
+//
+#define DXE_SERVICES_SIGNATURE  0x565245535f455844ULL
+#define DXE_SERVICES_REVISION   ((1<<16) | (00))
+
+typedef struct {
+  ///
+  /// The table header for the DXE Services Table.
+  /// This header contains the DXE_SERVICES_SIGNATURE and DXE_SERVICES_REVISION values.
+  ///
+  EFI_TABLE_HEADER                Hdr;
+
+  //
+  // Global Coherency Domain Services
+  //
+  EFI_ADD_MEMORY_SPACE            AddMemorySpace;
+  EFI_ALLOCATE_MEMORY_SPACE       AllocateMemorySpace;
+  EFI_FREE_MEMORY_SPACE           FreeMemorySpace;
+  EFI_REMOVE_MEMORY_SPACE         RemoveMemorySpace;
+  EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor;
+  EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes;
+  EFI_GET_MEMORY_SPACE_MAP        GetMemorySpaceMap;
+  EFI_ADD_IO_SPACE                AddIoSpace;
+  EFI_ALLOCATE_IO_SPACE           AllocateIoSpace;
+  EFI_FREE_IO_SPACE               FreeIoSpace;
+  EFI_REMOVE_IO_SPACE             RemoveIoSpace;
+  EFI_GET_IO_SPACE_DESCRIPTOR     GetIoSpaceDescriptor;
+  EFI_GET_IO_SPACE_MAP            GetIoSpaceMap;
+
+  //
+  // Dispatcher Services
+  //
+  EFI_DISPATCH                    Dispatch;
+  EFI_SCHEDULE                    Schedule;
+  EFI_TRUST                       Trust;
+  //
+  // Service to process a single firmware volume found in a capsule
+  //
+  EFI_PROCESS_FIRMWARE_VOLUME     ProcessFirmwareVolume;
+} DXE_SERVICES;
+
+typedef DXE_SERVICES EFI_DXE_SERVICES;
+
+
+/**
+  The function prototype for invoking a function on an Application Processor.
+
+  This definition is used by the UEFI MP Serices Protocol, and the
+  PI SMM System Table.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+typedef
+VOID
+(EFIAPI *EFI_AP_PROCEDURE)(
+  IN OUT VOID  *Buffer
+  );
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h
new file mode 100644
index 0000000..6909018
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h
@@ -0,0 +1,482 @@
+/** @file
+  The firmware file related definitions in PI.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.2.
+
+**/
+
+
+#ifndef __PI_FIRMWARE_FILE_H__
+#define __PI_FIRMWARE_FILE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#pragma pack(1)
+///
+/// Used to verify the integrity of the file.
+///
+typedef union {
+  struct {
+    ///
+    /// The IntegrityCheck.Checksum.Header field is an 8-bit checksum of the file
+    /// header. The State and IntegrityCheck.Checksum.File fields are assumed
+    /// to be zero and the checksum is calculated such that the entire header sums to zero.
+    ///
+    UINT8   Header;
+    ///
+    /// If the FFS_ATTRIB_CHECKSUM (see definition below) bit of the Attributes
+    /// field is set to one, the IntegrityCheck.Checksum.File field is an 8-bit
+    /// checksum of the entire file The State field and the file tail are assumed to be zero
+    /// and the checksum is calculated such that the entire file sums to zero.
+    /// If the FFS_ATTRIB_CHECKSUM bit of the Attributes field is cleared to zero,
+    /// the IntegrityCheck.Checksum.File field must be initialized with a value of
+    /// 0xAA. The IntegrityCheck.Checksum.File field is valid any time the
+    /// EFI_FILE_DATA_VALID bit is set in the State field.
+    ///
+    UINT8   File;
+  } Checksum;
+  ///
+  /// This is the full 16 bits of the IntegrityCheck field.
+  ///
+  UINT16    Checksum16;
+} EFI_FFS_INTEGRITY_CHECK;
+
+///
+/// FFS_FIXED_CHECKSUM is the checksum value used when the
+/// FFS_ATTRIB_CHECKSUM attribute bit is clear.
+///
+#define FFS_FIXED_CHECKSUM  0xAA
+
+typedef UINT8 EFI_FV_FILETYPE;
+typedef UINT8 EFI_FFS_FILE_ATTRIBUTES;
+typedef UINT8 EFI_FFS_FILE_STATE;
+
+///
+/// File Types Definitions
+///
+#define EFI_FV_FILETYPE_ALL                   0x00
+#define EFI_FV_FILETYPE_RAW                   0x01
+#define EFI_FV_FILETYPE_FREEFORM              0x02
+#define EFI_FV_FILETYPE_SECURITY_CORE         0x03
+#define EFI_FV_FILETYPE_PEI_CORE              0x04
+#define EFI_FV_FILETYPE_DXE_CORE              0x05
+#define EFI_FV_FILETYPE_PEIM                  0x06
+#define EFI_FV_FILETYPE_DRIVER                0x07
+#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER  0x08
+#define EFI_FV_FILETYPE_APPLICATION           0x09
+#define EFI_FV_FILETYPE_SMM                   0x0A
+#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B
+#define EFI_FV_FILETYPE_COMBINED_SMM_DXE      0x0C
+#define EFI_FV_FILETYPE_SMM_CORE              0x0D
+#define EFI_FV_FILETYPE_OEM_MIN               0xc0
+#define EFI_FV_FILETYPE_OEM_MAX               0xdf
+#define EFI_FV_FILETYPE_DEBUG_MIN             0xe0
+#define EFI_FV_FILETYPE_DEBUG_MAX             0xef
+#define EFI_FV_FILETYPE_FFS_MIN               0xf0
+#define EFI_FV_FILETYPE_FFS_MAX               0xff
+#define EFI_FV_FILETYPE_FFS_PAD               0xf0
+///
+/// FFS File Attributes.
+///
+#define FFS_ATTRIB_LARGE_FILE         0x01
+#define FFS_ATTRIB_FIXED              0x04
+#define FFS_ATTRIB_DATA_ALIGNMENT     0x38
+#define FFS_ATTRIB_CHECKSUM           0x40
+
+///
+/// FFS File State Bits.
+///
+#define EFI_FILE_HEADER_CONSTRUCTION  0x01
+#define EFI_FILE_HEADER_VALID         0x02
+#define EFI_FILE_DATA_VALID           0x04
+#define EFI_FILE_MARKED_FOR_UPDATE    0x08
+#define EFI_FILE_DELETED              0x10
+#define EFI_FILE_HEADER_INVALID       0x20
+
+
+///
+/// Each file begins with the header that describe the
+/// contents and state of the files.
+///
+typedef struct {
+  ///
+  /// This GUID is the file name. It is used to uniquely identify the file.
+  ///
+  EFI_GUID                Name;
+  ///
+  /// Used to verify the integrity of the file.
+  ///
+  EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
+  ///
+  /// Identifies the type of file.
+  ///
+  EFI_FV_FILETYPE         Type;
+  ///
+  /// Declares various file attribute bits.
+  ///
+  EFI_FFS_FILE_ATTRIBUTES Attributes;
+  ///
+  /// The length of the file in bytes, including the FFS header.
+  ///
+  UINT8                   Size[3];
+  ///
+  /// Used to track the state of the file throughout the life of the file from creation to deletion.
+  ///
+  EFI_FFS_FILE_STATE      State;
+} EFI_FFS_FILE_HEADER;
+
+typedef struct {
+  ///
+  /// This GUID is the file name. It is used to uniquely identify the file. There may be only
+  /// one instance of a file with the file name GUID of Name in any given firmware
+  /// volume, except if the file type is EFI_FV_FILETYPE_FFS_PAD.
+  ///
+  EFI_GUID                  Name;
+
+  ///
+  /// Used to verify the integrity of the file.
+  ///
+  EFI_FFS_INTEGRITY_CHECK   IntegrityCheck;
+
+  ///
+  /// Identifies the type of file.
+  ///
+  EFI_FV_FILETYPE           Type;
+
+  ///
+  /// Declares various file attribute bits.
+  ///
+  EFI_FFS_FILE_ATTRIBUTES   Attributes;
+
+  ///
+  /// The length of the file in bytes, including the FFS header.
+  /// The length of the file data is either (Size - sizeof(EFI_FFS_FILE_HEADER)). This calculation means a
+  /// zero-length file has a Size of 24 bytes, which is sizeof(EFI_FFS_FILE_HEADER).
+  /// Size is not required to be a multiple of 8 bytes. Given a file F, the next file header is
+  /// located at the next 8-byte aligned firmware volume offset following the last byte of the file F.
+  ///
+  UINT8                     Size[3];
+
+  ///
+  /// Used to track the state of the file throughout the life of the file from creation to deletion.
+  ///
+  EFI_FFS_FILE_STATE        State;
+
+  ///
+  /// If FFS_ATTRIB_LARGE_FILE is set in Attributes, then ExtendedSize exists and Size must be set to zero.
+  /// If FFS_ATTRIB_LARGE_FILE is not set then EFI_FFS_FILE_HEADER is used.
+  ///
+  EFI_FFS_FILE_STATE        ExtendedSize;
+} EFI_FFS_FILE_HEADER2;
+
+typedef UINT8 EFI_SECTION_TYPE;
+
+///
+/// Pseudo type. It is used as a wild card when retrieving sections.
+///  The section type EFI_SECTION_ALL matches all section types.
+///
+#define EFI_SECTION_ALL                   0x00
+
+///
+/// Encapsulation section Type values.
+///
+#define EFI_SECTION_COMPRESSION           0x01
+
+#define EFI_SECTION_GUID_DEFINED          0x02
+
+#define EFI_SECTION_DISPOSABLE            0x03
+
+///
+/// Leaf section Type values.
+///
+#define EFI_SECTION_PE32                  0x10
+#define EFI_SECTION_PIC                   0x11
+#define EFI_SECTION_TE                    0x12
+#define EFI_SECTION_DXE_DEPEX             0x13
+#define EFI_SECTION_VERSION               0x14
+#define EFI_SECTION_USER_INTERFACE        0x15
+#define EFI_SECTION_COMPATIBILITY16       0x16
+#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
+#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
+#define EFI_SECTION_RAW                   0x19
+#define EFI_SECTION_PEI_DEPEX             0x1B
+#define EFI_SECTION_SMM_DEPEX             0x1C
+
+///
+/// Common section header.
+///
+typedef struct {
+  ///
+  /// A 24-bit unsigned integer that contains the total size of the section in bytes,
+  /// including the EFI_COMMON_SECTION_HEADER.
+  ///
+  UINT8             Size[3];
+  EFI_SECTION_TYPE  Type;
+  ///
+  /// Declares the section type.
+  ///
+} EFI_COMMON_SECTION_HEADER;
+
+typedef struct {
+  ///
+  /// A 24-bit unsigned integer that contains the total size of the section in bytes,
+  /// including the EFI_COMMON_SECTION_HEADER.
+  ///
+  UINT8             Size[3];
+
+  EFI_SECTION_TYPE  Type;
+
+  ///
+  /// If Size is 0xFFFFFF, then ExtendedSize contains the size of the section. If
+  /// Size is not equal to 0xFFFFFF, then this field does not exist.
+  ///
+  UINT32            ExtendedSize;
+} EFI_COMMON_SECTION_HEADER2;
+
+///
+/// Leaf section type that contains an
+/// IA-32 16-bit executable image.
+///
+typedef EFI_COMMON_SECTION_HEADER  EFI_COMPATIBILITY16_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2 EFI_COMPATIBILITY16_SECTION2;
+
+///
+/// CompressionType of EFI_COMPRESSION_SECTION.
+///
+#define EFI_NOT_COMPRESSED        0x00
+#define EFI_STANDARD_COMPRESSION  0x01
+///
+/// An encapsulation section type in which the
+/// section data is compressed.
+///
+typedef struct {
+  ///
+  /// Usual common section header. CommonHeader.Type = EFI_SECTION_COMPRESSION.
+  ///
+  EFI_COMMON_SECTION_HEADER   CommonHeader;
+  ///
+  /// The UINT32 that indicates the size of the section data after decompression.
+  ///
+  UINT32                      UncompressedLength;
+  ///
+  /// Indicates which compression algorithm is used.
+  ///
+  UINT8                       CompressionType;
+} EFI_COMPRESSION_SECTION;
+
+typedef struct {
+  ///
+  /// Usual common section header. CommonHeader.Type = EFI_SECTION_COMPRESSION.
+  ///
+  EFI_COMMON_SECTION_HEADER2    CommonHeader;
+  ///
+  /// UINT32 that indicates the size of the section data after decompression.
+  ///
+  UINT32                        UncompressedLength;
+  ///
+  /// Indicates which compression algorithm is used.
+  ///
+  UINT8                         CompressionType;
+} EFI_COMPRESSION_SECTION2;
+
+///
+/// An encapsulation section type in which the section data is disposable.
+/// A disposable section is an encapsulation section in which the section data may be disposed of during
+/// the process of creating or updating a firmware image without significant impact on the usefulness of
+/// the file. The Type field in the section header is set to EFI_SECTION_DISPOSABLE. This
+/// allows optional or descriptive data to be included with the firmware file which can be removed in
+/// order to conserve space. The contents of this section are implementation specific, but might contain
+/// debug data or detailed integration instructions.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_DISPOSABLE_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_DISPOSABLE_SECTION2;
+
+///
+/// The leaf section which could be used to determine the dispatch order of DXEs.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_DXE_DEPEX_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_DXE_DEPEX_SECTION2;
+
+///
+/// The leaf section which contains a PI FV.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_FIRMWARE_VOLUME_IMAGE_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_FIRMWARE_VOLUME_IMAGE_SECTION2;
+
+///
+/// The leaf section which contains a single GUID.
+///
+typedef struct {
+  ///
+  /// Common section header. CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID.
+  ///
+  EFI_COMMON_SECTION_HEADER   CommonHeader;
+  ///
+  /// This GUID is defined by the creator of the file. It is a vendor-defined file type.
+  ///
+  EFI_GUID                    SubTypeGuid;
+} EFI_FREEFORM_SUBTYPE_GUID_SECTION;
+
+typedef struct {
+  ///
+  /// The common section header. CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID.
+  ///
+  EFI_COMMON_SECTION_HEADER2    CommonHeader;
+  ///
+  /// This GUID is defined by the creator of the file. It is a vendor-defined file type.
+  ///
+  EFI_GUID                      SubTypeGuid;
+} EFI_FREEFORM_SUBTYPE_GUID_SECTION2;
+
+///
+/// Attributes of EFI_GUID_DEFINED_SECTION.
+///
+#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED  0x01
+#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID    0x02
+///
+/// The leaf section which is encapsulation defined by specific GUID.
+///
+typedef struct {
+  ///
+  /// The common section header. CommonHeader.Type = EFI_SECTION_GUID_DEFINED.
+  ///
+  EFI_COMMON_SECTION_HEADER   CommonHeader;
+  ///
+  /// The GUID that defines the format of the data that follows. It is a vendor-defined section type.
+  ///
+  EFI_GUID                    SectionDefinitionGuid;
+  ///
+  /// Contains the offset in bytes from the beginning of the common header to the first byte of the data.
+  ///
+  UINT16                      DataOffset;
+  ///
+  /// The bit field that declares some specific characteristics of the section contents.
+  ///
+  UINT16                      Attributes;
+} EFI_GUID_DEFINED_SECTION;
+
+typedef struct {
+  ///
+  /// The common section header. CommonHeader.Type = EFI_SECTION_GUID_DEFINED.
+  ///
+  EFI_COMMON_SECTION_HEADER2    CommonHeader;
+  ///
+  /// The GUID that defines the format of the data that follows. It is a vendor-defined section type.
+  ///
+  EFI_GUID                      SectionDefinitionGuid;
+  ///
+  /// Contains the offset in bytes from the beginning of the common header to the first byte of the data.
+  ///
+  UINT16                        DataOffset;
+  ///
+  /// The bit field that declares some specific characteristics of the section contents.
+  ///
+  UINT16                        Attributes;
+} EFI_GUID_DEFINED_SECTION2;
+
+///
+/// The leaf section which contains PE32+ image.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_PE32_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_PE32_SECTION2;
+
+///
+/// The leaf section used to determine the dispatch order of PEIMs.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_PEI_DEPEX_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_PEI_DEPEX_SECTION2;
+
+///
+/// A leaf section type that contains a position-independent-code (PIC) image.
+/// A PIC image section is a leaf section that contains a position-independent-code (PIC) image.
+/// In addition to normal PE32+ images that contain relocation information, PEIM executables may be
+/// PIC and are referred to as PIC images. A PIC image is the same as a PE32+ image except that all
+/// relocation information has been stripped from the image and the image can be moved and will
+/// execute correctly without performing any relocation or other fix-ups. EFI_PIC_SECTION2 must
+/// be used if the section is 16MB or larger.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_PIC_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_PIC_SECTION2;
+
+///
+/// The leaf section which constains the position-independent-code image.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_TE_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_TE_SECTION2;
+
+///
+/// The leaf section which contains an array of zero or more bytes.
+///
+typedef EFI_COMMON_SECTION_HEADER   EFI_RAW_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2  EFI_RAW_SECTION2;
+
+///
+/// The SMM dependency expression section is a leaf section that contains a dependency expression that
+/// is used to determine the dispatch order for SMM drivers. Before the SMRAM invocation of the
+/// SMM driver's entry point, this dependency expression must evaluate to TRUE. See the Platform
+/// Initialization Specification, Volume 2, for details regarding the format of the dependency expression.
+/// The dependency expression may refer to protocols installed in either the UEFI or the SMM protocol
+/// database. EFI_SMM_DEPEX_SECTION2 must be used if the section is 16MB or larger.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_SMM_DEPEX_SECTION;
+typedef EFI_COMMON_SECTION_HEADER2 EFI_SMM_DEPEX_SECTION2;
+
+///
+/// The leaf section which contains a unicode string that
+/// is human readable file name.
+///
+typedef struct {
+  EFI_COMMON_SECTION_HEADER   CommonHeader;
+
+  ///
+  /// Array of unicode string.
+  ///
+  CHAR16                      FileNameString[1];
+} EFI_USER_INTERFACE_SECTION;
+
+typedef struct {
+  EFI_COMMON_SECTION_HEADER2    CommonHeader;
+  CHAR16                        FileNameString[1];
+} EFI_USER_INTERFACE_SECTION2;
+
+///
+/// The leaf section which contains a numeric build number and
+/// an optional unicode string that represents the file revision.
+///
+typedef struct {
+  EFI_COMMON_SECTION_HEADER   CommonHeader;
+  UINT16                      BuildNumber;
+
+  ///
+  /// Array of unicode string.
+  ///
+  CHAR16                      VersionString[1];
+} EFI_VERSION_SECTION;
+
+typedef struct {
+  EFI_COMMON_SECTION_HEADER2    CommonHeader;
+  ///
+  /// A UINT16 that represents a particular build. Subsequent builds have monotonically
+  /// increasing build numbers relative to earlier builds.
+  ///
+  UINT16                        BuildNumber;
+  CHAR16                        VersionString[1];
+} EFI_VERSION_SECTION2;
+
+#define SECTION_SIZE(SectionHeaderPtr) \
+    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff))
+
+#pragma pack()
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h
new file mode 100644
index 0000000..813fab2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h
@@ -0,0 +1,233 @@
+/** @file
+  The firmware volume related definitions in PI.
+
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.2B
+
+**/
+
+#ifndef __PI_FIRMWAREVOLUME_H__
+#define __PI_FIRMWAREVOLUME_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// EFI_FV_FILE_ATTRIBUTES
+///
+typedef UINT32  EFI_FV_FILE_ATTRIBUTES;
+
+//
+// Value of EFI_FV_FILE_ATTRIBUTES.
+//
+#define EFI_FV_FILE_ATTRIB_ALIGNMENT      0x0000001F
+#define EFI_FV_FILE_ATTRIB_FIXED          0x00000100
+#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED  0x00000200
+
+///
+/// type of EFI FVB attribute
+///
+typedef UINT32  EFI_FVB_ATTRIBUTES_2;
+
+//
+// Attributes bit definitions
+//
+#define EFI_FVB2_READ_DISABLED_CAP  0x00000001
+#define EFI_FVB2_READ_ENABLED_CAP   0x00000002
+#define EFI_FVB2_READ_STATUS        0x00000004
+#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008
+#define EFI_FVB2_WRITE_ENABLED_CAP  0x00000010
+#define EFI_FVB2_WRITE_STATUS       0x00000020
+#define EFI_FVB2_LOCK_CAP           0x00000040
+#define EFI_FVB2_LOCK_STATUS        0x00000080
+#define EFI_FVB2_STICKY_WRITE       0x00000200
+#define EFI_FVB2_MEMORY_MAPPED      0x00000400
+#define EFI_FVB2_ERASE_POLARITY     0x00000800
+#define EFI_FVB2_READ_LOCK_CAP      0x00001000
+#define EFI_FVB2_READ_LOCK_STATUS   0x00002000
+#define EFI_FVB2_WRITE_LOCK_CAP     0x00004000
+#define EFI_FVB2_WRITE_LOCK_STATUS  0x00008000
+#define EFI_FVB2_ALIGNMENT          0x001F0000
+#define EFI_FVB2_ALIGNMENT_1        0x00000000
+#define EFI_FVB2_ALIGNMENT_2        0x00010000
+#define EFI_FVB2_ALIGNMENT_4        0x00020000
+#define EFI_FVB2_ALIGNMENT_8        0x00030000
+#define EFI_FVB2_ALIGNMENT_16       0x00040000
+#define EFI_FVB2_ALIGNMENT_32       0x00050000
+#define EFI_FVB2_ALIGNMENT_64       0x00060000
+#define EFI_FVB2_ALIGNMENT_128      0x00070000
+#define EFI_FVB2_ALIGNMENT_256      0x00080000
+#define EFI_FVB2_ALIGNMENT_512      0x00090000
+#define EFI_FVB2_ALIGNMENT_1K       0x000A0000
+#define EFI_FVB2_ALIGNMENT_2K       0x000B0000
+#define EFI_FVB2_ALIGNMENT_4K       0x000C0000
+#define EFI_FVB2_ALIGNMENT_8K       0x000D0000
+#define EFI_FVB2_ALIGNMENT_16K      0x000E0000
+#define EFI_FVB2_ALIGNMENT_32K      0x000F0000
+#define EFI_FVB2_ALIGNMENT_64K      0x00100000
+#define EFI_FVB2_ALIGNMENT_128K     0x00110000
+#define EFI_FVB2_ALIGNMENT_256K     0x00120000
+#define EFI_FVB2_ALIGNMNET_512K     0x00130000
+#define EFI_FVB2_ALIGNMENT_1M       0x00140000
+#define EFI_FVB2_ALIGNMENT_2M       0x00150000
+#define EFI_FVB2_ALIGNMENT_4M       0x00160000
+#define EFI_FVB2_ALIGNMENT_8M       0x00170000
+#define EFI_FVB2_ALIGNMENT_16M      0x00180000
+#define EFI_FVB2_ALIGNMENT_32M      0x00190000
+#define EFI_FVB2_ALIGNMENT_64M      0x001A0000
+#define EFI_FVB2_ALIGNMENT_128M     0x001B0000
+#define EFI_FVB2_ALIGNMENT_256M     0x001C0000
+#define EFI_FVB2_ALIGNMENT_512M     0x001D0000
+#define EFI_FVB2_ALIGNMENT_1G       0x001E0000
+#define EFI_FVB2_ALIGNMENT_2G       0x001F0000
+
+
+typedef struct {
+  ///
+  /// The number of sequential blocks which are of the same size.
+  ///
+  UINT32 NumBlocks;
+  ///
+  /// The size of the blocks.
+  ///
+  UINT32 Length;
+} EFI_FV_BLOCK_MAP_ENTRY;
+
+///
+/// Describes the features and layout of the firmware volume.
+///
+typedef struct {
+  ///
+  /// The first 16 bytes are reserved to allow for the reset vector of
+  /// processors whose reset vector is at address 0.
+  ///
+  UINT8                     ZeroVector[16];
+  ///
+  /// Declares the file system with which the firmware volume is formatted.
+  ///
+  EFI_GUID                  FileSystemGuid;
+  ///
+  /// Length in bytes of the complete firmware volume, including the header.
+  ///
+  UINT64                    FvLength;
+  ///
+  /// Set to EFI_FVH_SIGNATURE
+  ///
+  UINT32                    Signature;
+  ///
+  /// Declares capabilities and power-on defaults for the firmware volume.
+  ///
+  EFI_FVB_ATTRIBUTES_2      Attributes;
+  ///
+  /// Length in bytes of the complete firmware volume header.
+  ///
+  UINT16                    HeaderLength;
+  ///
+  /// A 16-bit checksum of the firmware volume header. A valid header sums to zero.
+  ///
+  UINT16                    Checksum;
+  ///
+  /// Offset, relative to the start of the header, of the extended header
+  /// (EFI_FIRMWARE_VOLUME_EXT_HEADER) or zero if there is no extended header.
+  ///
+  UINT16                    ExtHeaderOffset;
+  ///
+  /// This field must always be set to zero.
+  ///
+  UINT8                     Reserved[1];
+  ///
+  /// Set to 2. Future versions of this specification may define new header fields and will
+  /// increment the Revision field accordingly.
+  ///
+  UINT8                     Revision;
+  ///
+  /// An array of run-length encoded FvBlockMapEntry structures. The array is
+  /// terminated with an entry of {0,0}.
+  ///
+  EFI_FV_BLOCK_MAP_ENTRY    BlockMap[1];
+} EFI_FIRMWARE_VOLUME_HEADER;
+
+#define EFI_FVH_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', 'H')
+
+///
+/// Firmware Volume Header Revision definition
+///
+#define EFI_FVH_REVISION  0x02
+
+///
+/// Extension header pointed by ExtHeaderOffset of volume header.
+///
+typedef struct {
+  ///
+  /// Firmware volume name.
+  ///
+  EFI_GUID  FvName;
+  ///
+  /// Size of the rest of the extension header, including this structure.
+  ///
+  UINT32    ExtHeaderSize;
+} EFI_FIRMWARE_VOLUME_EXT_HEADER;
+
+///
+/// Entry struture for describing FV extension header
+///
+typedef struct {
+  ///
+  /// Size of this header extension.
+  ///
+  UINT16    ExtEntrySize;
+  ///
+  /// Type of the header.
+  ///
+  UINT16    ExtEntryType;
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY;
+
+#define EFI_FV_EXT_TYPE_OEM_TYPE  0x01
+///
+/// This extension header provides a mapping between a GUID and an OEM file type.
+///
+typedef struct {
+  ///
+  /// Standard extension entry, with the type EFI_FV_EXT_TYPE_OEM_TYPE.
+  ///
+  EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
+  ///
+  /// A bit mask, one bit for each file type between 0xC0 (bit 0) and 0xDF (bit 31). If a bit
+  /// is '1', then the GUID entry exists in Types. If a bit is '0' then no GUID entry exists in Types.
+  ///
+  UINT32    TypeMask;
+  ///
+  /// An array of GUIDs, each GUID representing an OEM file type.
+  ///
+  EFI_GUID  Types[1];
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE;
+
+#define EFI_FV_EXT_TYPE_GUID_TYPE 0x0002
+
+///
+/// This extension header provides a mapping between a GUID and an OEM file type.
+///
+typedef struct {
+  ///
+  /// Standard extension entry, with the type EFI_FV_EXT_TYPE_OEM_TYPE.
+  ///
+  EFI_FIRMWARE_VOLUME_EXT_ENTRY     Hdr;
+  ///
+  /// Vendor-specific GUID.
+  ///
+  EFI_GUID                          FormatType;
+  ///
+  /// An arry of bytes of length Length.
+  ///
+  UINT8                             Data[1];
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h
new file mode 100644
index 0000000..cd196cb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h
@@ -0,0 +1,451 @@
+/** @file
+  HOB related definitions in PI.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  PI Version 1.0
+
+**/
+
+#ifndef __PI_HOB_H__
+#define __PI_HOB_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// HobType of EFI_HOB_GENERIC_HEADER.
+//
+#define EFI_HOB_TYPE_HANDOFF              0x0001
+#define EFI_HOB_TYPE_MEMORY_ALLOCATION    0x0002
+#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR  0x0003
+#define EFI_HOB_TYPE_GUID_EXTENSION       0x0004
+#define EFI_HOB_TYPE_FV                   0x0005
+#define EFI_HOB_TYPE_CPU                  0x0006
+#define EFI_HOB_TYPE_MEMORY_POOL          0x0007
+#define EFI_HOB_TYPE_FV2                  0x0009
+#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED     0x000A
+#define EFI_HOB_TYPE_UEFI_CAPSULE         0x000B
+#define EFI_HOB_TYPE_UNUSED               0xFFFE
+#define EFI_HOB_TYPE_END_OF_HOB_LIST      0xFFFF
+
+///
+/// Describes the format and size of the data inside the HOB.
+/// All HOBs must contain this generic HOB header.
+///
+typedef struct {
+  ///
+  /// Identifies the HOB data structure type.
+  ///
+  UINT16    HobType;
+  ///
+  /// The length in bytes of the HOB.
+  ///
+  UINT16    HobLength;
+  ///
+  /// This field must always be set to zero.
+  ///
+  UINT32    Reserved;
+} EFI_HOB_GENERIC_HEADER;
+
+
+///
+/// Value of version  in EFI_HOB_HANDOFF_INFO_TABLE.
+///
+#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009
+
+///
+/// Contains general state information used by the HOB producer phase.
+/// This HOB must be the first one in the HOB list.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_HANDOFF.
+  ///
+  EFI_HOB_GENERIC_HEADER  Header;
+  ///
+  /// The version number pertaining to the PHIT HOB definition.
+  /// This value is four bytes in length to provide an 8-byte aligned entry
+  /// when it is combined with the 4-byte BootMode.
+  ///
+  UINT32                  Version;
+  ///
+  /// The system boot mode as determined during the HOB producer phase.
+  ///
+  EFI_BOOT_MODE           BootMode;
+  ///
+  /// The highest address location of memory that is allocated for use by the HOB producer
+  /// phase. This address must be 4-KB aligned to meet page restrictions of UEFI.
+  ///
+  EFI_PHYSICAL_ADDRESS    EfiMemoryTop;
+  ///
+  /// The lowest address location of memory that is allocated for use by the HOB producer phase.
+  ///
+  EFI_PHYSICAL_ADDRESS    EfiMemoryBottom;
+  ///
+  /// The highest address location of free memory that is currently available
+  /// for use by the HOB producer phase.
+  ///
+  EFI_PHYSICAL_ADDRESS    EfiFreeMemoryTop;
+  ///
+  /// The lowest address location of free memory that is available for use by the HOB producer phase.
+  ///
+  EFI_PHYSICAL_ADDRESS    EfiFreeMemoryBottom;
+  ///
+  /// The end of the HOB list.
+  ///
+  EFI_PHYSICAL_ADDRESS    EfiEndOfHobList;
+} EFI_HOB_HANDOFF_INFO_TABLE;
+
+///
+/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the
+/// various attributes of the logical memory allocation. The type field will be used for
+/// subsequent inclusion in the UEFI memory map.
+///
+typedef struct {
+  ///
+  /// A GUID that defines the memory allocation region's type and purpose, as well as
+  /// other fields within the memory allocation HOB. This GUID is used to define the
+  /// additional data within the HOB that may be present for the memory allocation HOB.
+  /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0
+  /// specification.
+  ///
+  EFI_GUID              Name;
+
+  ///
+  /// The base address of memory allocated by this HOB. Type
+  /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0
+  /// specification.
+  ///
+  EFI_PHYSICAL_ADDRESS  MemoryBaseAddress;
+
+  ///
+  /// The length in bytes of memory allocated by this HOB.
+  ///
+  UINT64                MemoryLength;
+
+  ///
+  /// Defines the type of memory allocated by this HOB. The memory type definition
+  /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined
+  /// in AllocatePages() in the UEFI 2.0 specification.
+  ///
+  EFI_MEMORY_TYPE       MemoryType;
+
+  ///
+  /// Padding for Itanium processor family
+  ///
+  UINT8                 Reserved[4];
+} EFI_HOB_MEMORY_ALLOCATION_HEADER;
+
+///
+/// Describes all memory ranges used during the HOB producer
+/// phase that exist outside the HOB list. This HOB type
+/// describes how memory is used, not the physical attributes of memory.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
+  ///
+  EFI_HOB_GENERIC_HEADER            Header;
+  ///
+  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
+  /// various attributes of the logical memory allocation.
+  ///
+  EFI_HOB_MEMORY_ALLOCATION_HEADER  AllocDescriptor;
+  //
+  // Additional data pertaining to the "Name" Guid memory
+  // may go here.
+  //
+} EFI_HOB_MEMORY_ALLOCATION;
+
+
+///
+/// Describes the memory stack that is produced by the HOB producer
+/// phase and upon which all post-memory-installed executable
+/// content in the HOB producer phase is executing.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
+  ///
+  EFI_HOB_GENERIC_HEADER            Header;
+  ///
+  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
+  /// various attributes of the logical memory allocation.
+  ///
+  EFI_HOB_MEMORY_ALLOCATION_HEADER  AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_STACK;
+
+///
+/// Defines the location of the boot-strap
+/// processor (BSP) BSPStore ("Backing Store Pointer Store").
+/// This HOB is valid for the Itanium processor family only
+/// register overflow store.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
+  ///
+  EFI_HOB_GENERIC_HEADER            Header;
+  ///
+  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
+  /// various attributes of the logical memory allocation.
+  ///
+  EFI_HOB_MEMORY_ALLOCATION_HEADER  AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE;
+
+///
+/// Defines the location and entry point of the HOB consumer phase.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
+  ///
+  EFI_HOB_GENERIC_HEADER            Header;
+  ///
+  /// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
+  /// various attributes of the logical memory allocation.
+  ///
+  EFI_HOB_MEMORY_ALLOCATION_HEADER  MemoryAllocationHeader;
+  ///
+  /// The GUID specifying the values of the firmware file system name
+  /// that contains the HOB consumer phase component.
+  ///
+  EFI_GUID                          ModuleName;
+  ///
+  /// The address of the memory-mapped firmware volume
+  /// that contains the HOB consumer phase firmware file.
+  ///
+  EFI_PHYSICAL_ADDRESS              EntryPoint;
+} EFI_HOB_MEMORY_ALLOCATION_MODULE;
+
+///
+/// The resource type.
+///
+typedef UINT32 EFI_RESOURCE_TYPE;
+
+//
+// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR.
+//
+#define EFI_RESOURCE_SYSTEM_MEMORY          0x00000000
+#define EFI_RESOURCE_MEMORY_MAPPED_IO       0x00000001
+#define EFI_RESOURCE_IO                     0x00000002
+#define EFI_RESOURCE_FIRMWARE_DEVICE        0x00000003
+#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT  0x00000004
+#define EFI_RESOURCE_MEMORY_RESERVED        0x00000005
+#define EFI_RESOURCE_IO_RESERVED            0x00000006
+#define EFI_RESOURCE_MAX_MEMORY_TYPE        0x00000007
+
+///
+/// A type of recount attribute type.
+///
+typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
+
+//
+// These types can be ORed together as needed.
+//
+// The first three enumerations describe settings
+//
+#define EFI_RESOURCE_ATTRIBUTE_PRESENT              0x00000001
+#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED          0x00000002
+#define EFI_RESOURCE_ATTRIBUTE_TESTED               0x00000004
+//
+// The rest of the settings describe capabilities
+//
+#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC           0x00000008
+#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC         0x00000010
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1           0x00000020
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2           0x00000040
+#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED           0x00000080
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED          0x00000100
+#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED      0x00000200
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE              0x00000400
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE        0x00000800
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE  0x00001000
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE     0x00002000
+#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO                0x00004000
+#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO                0x00008000
+#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO                0x00010000
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED        0x00020000
+
+///
+/// Describes the resource properties of all fixed,
+/// nonrelocatable resource ranges found on the processor
+/// host bus during the HOB producer phase.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR.
+  ///
+  EFI_HOB_GENERIC_HEADER      Header;
+  ///
+  /// A GUID representing the owner of the resource. This GUID is used by HOB
+  /// consumer phase components to correlate device ownership of a resource.
+  ///
+  EFI_GUID                    Owner;
+  ///
+  /// The resource type enumeration as defined by EFI_RESOURCE_TYPE.
+  ///
+  EFI_RESOURCE_TYPE           ResourceType;
+  ///
+  /// Resource attributes as defined by EFI_RESOURCE_ATTRIBUTE_TYPE.
+  ///
+  EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
+  ///
+  /// The physical start address of the resource region.
+  ///
+  EFI_PHYSICAL_ADDRESS        PhysicalStart;
+  ///
+  /// The number of bytes of the resource region.
+  ///
+  UINT64                      ResourceLength;
+} EFI_HOB_RESOURCE_DESCRIPTOR;
+
+///
+/// Allows writers of executable content in the HOB producer phase to
+/// maintain and manage HOBs with specific GUID.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION.
+  ///
+  EFI_HOB_GENERIC_HEADER      Header;
+  ///
+  /// A GUID that defines the contents of this HOB.
+  ///
+  EFI_GUID                    Name;
+  //
+  // Guid specific data goes here
+  //
+} EFI_HOB_GUID_TYPE;
+
+///
+/// Details the location of firmware volumes that contain firmware files.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_FV.
+  ///
+  EFI_HOB_GENERIC_HEADER Header;
+  ///
+  /// The physical memory-mapped base address of the firmware volume.
+  ///
+  EFI_PHYSICAL_ADDRESS   BaseAddress;
+  ///
+  /// The length in bytes of the firmware volume.
+  ///
+  UINT64                 Length;
+} EFI_HOB_FIRMWARE_VOLUME;
+
+///
+/// Details the location of a firmware volume that was extracted
+/// from a file within another firmware volume.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_FV2.
+  ///
+  EFI_HOB_GENERIC_HEADER  Header;
+  ///
+  /// The physical memory-mapped base address of the firmware volume.
+  ///
+  EFI_PHYSICAL_ADDRESS    BaseAddress;
+  ///
+  /// The length in bytes of the firmware volume.
+  ///
+  UINT64                  Length;
+  ///
+  /// The name of the firmware volume.
+  ///
+  EFI_GUID                FvName;
+  ///
+  /// The name of the firmware file that contained this firmware volume.
+  ///
+  EFI_GUID                FileName;
+} EFI_HOB_FIRMWARE_VOLUME2;
+
+
+///
+/// Describes processor information, such as address space and I/O space capabilities.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_CPU.
+  ///
+  EFI_HOB_GENERIC_HEADER  Header;
+  ///
+  /// Identifies the maximum physical memory addressability of the processor.
+  ///
+  UINT8                   SizeOfMemorySpace;
+  ///
+  /// Identifies the maximum physical I/O addressability of the processor.
+  ///
+  UINT8                   SizeOfIoSpace;
+  ///
+  /// This field will always be set to zero.
+  ///
+  UINT8                   Reserved[6];
+} EFI_HOB_CPU;
+
+
+///
+/// Describes pool memory allocations.
+///
+typedef struct {
+  ///
+  /// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_POOL.
+  ///
+  EFI_HOB_GENERIC_HEADER  Header;
+} EFI_HOB_MEMORY_POOL;
+
+///
+/// Each UEFI capsule HOB details the location of a UEFI capsule. It includes a base address and length
+/// which is based upon memory blocks with a EFI_CAPSULE_HEADER and the associated
+/// CapsuleImageSize-based payloads. These HOB's shall be created by the PEI PI firmware
+/// sometime after the UEFI UpdateCapsule service invocation with the
+/// CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag set in the EFI_CAPSULE_HEADER.
+///
+typedef struct {
+  ///
+  /// The HOB generic header where Header.HobType = EFI_HOB_TYPE_UEFI_CAPSULE.
+  ///
+  EFI_HOB_GENERIC_HEADER Header;
+
+  ///
+  /// The physical memory-mapped base address of an UEFI capsule. This value is set to
+  /// point to the base of the contiguous memory of the UEFI capsule.
+  /// The length of the contiguous memory in bytes.
+  ///
+  EFI_PHYSICAL_ADDRESS   BaseAddress;
+  UINT64                 Length;
+} EFI_HOB_UEFI_CAPSULE;
+
+///
+/// Union of all the possible HOB Types.
+///
+typedef union {
+  EFI_HOB_GENERIC_HEADER              *Header;
+  EFI_HOB_HANDOFF_INFO_TABLE          *HandoffInformationTable;
+  EFI_HOB_MEMORY_ALLOCATION           *MemoryAllocation;
+  EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore;
+  EFI_HOB_MEMORY_ALLOCATION_STACK     *MemoryAllocationStack;
+  EFI_HOB_MEMORY_ALLOCATION_MODULE    *MemoryAllocationModule;
+  EFI_HOB_RESOURCE_DESCRIPTOR         *ResourceDescriptor;
+  EFI_HOB_GUID_TYPE                   *Guid;
+  EFI_HOB_FIRMWARE_VOLUME             *FirmwareVolume;
+  EFI_HOB_FIRMWARE_VOLUME2            *FirmwareVolume2;
+  EFI_HOB_CPU                         *Cpu;
+  EFI_HOB_MEMORY_POOL                 *Pool;
+  EFI_HOB_UEFI_CAPSULE                *Capsule;
+  UINT8                               *Raw;
+} EFI_PEI_HOB_POINTERS;
+
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h
new file mode 100644
index 0000000..d5d7aaa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h
@@ -0,0 +1,138 @@
+/** @file
+  Include file matches things in PI for multiple module types.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  These elements are defined in UEFI Platform Initialization Specification 1.2.
+
+**/
+
+#ifndef __PI_MULTIPHASE_H__
+#define __PI_MULTIPHASE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Pi/PiFirmwareVolume.h>
+#include <ipxe/efi/Pi/PiFirmwareFile.h>
+#include <ipxe/efi/Pi/PiBootMode.h>
+#include <ipxe/efi/Pi/PiHob.h>
+#include <ipxe/efi/Pi/PiDependency.h>
+#include <ipxe/efi/Pi/PiStatusCode.h>
+#include <ipxe/efi/Pi/PiS3BootScript.h>
+
+/**
+  Produces an error code in the range reserved for use by the Platform Initialization
+  Architecture Specification.
+
+  The supported 32-bit range is 0xA0000000-0xBFFFFFFF
+  The supported 64-bit range is 0xA000000000000000-0xBFFFFFFFFFFFFFFF
+
+  @param  StatusCode    The status code value to convert into a warning code.
+                        StatusCode must be in the range 0x00000000..0x1FFFFFFF.
+
+  @return The value specified by StatusCode in the PI reserved range.
+
+**/
+#define DXE_ERROR(StatusCode)  (MAX_BIT | (MAX_BIT >> 2) | StatusCode)
+
+///
+/// If this value is returned by an EFI image, then the image should be unloaded.
+///
+#define EFI_REQUEST_UNLOAD_IMAGE  DXE_ERROR (1)
+
+///
+/// If this value is returned by an API, it means the capability is not yet
+/// installed/available/ready to use.
+///
+#define EFI_NOT_AVAILABLE_YET     DXE_ERROR (2)
+
+///
+/// Success and warning codes reserved for use by PI.
+/// Supported 32-bit range is 0x20000000-0x3fffffff.
+/// Supported 64-bit range is 0x2000000000000000-0x3fffffffffffffff.
+///
+#define PI_ENCODE_WARNING(a)                ((MAX_BIT >> 2) | (a))
+
+///
+/// Error codes reserved for use by PI.
+/// Supported 32-bit range is 0xa0000000-0xbfffffff.
+/// Supported 64-bit range is 0xa000000000000000-0xbfffffffffffffff.
+///
+#define PI_ENCODE_ERROR(a)                  (MAX_BIT | (MAX_BIT >> 2) | (a))
+
+///
+/// Return status codes defined in SMM CIS.
+///
+#define EFI_INTERRUPT_PENDING               PI_ENCODE_ERROR (0)
+
+#define EFI_WARN_INTERRUPT_SOURCE_PENDING   PI_ENCODE_WARNING (0)
+#define EFI_WARN_INTERRUPT_SOURCE_QUIESCED  PI_ENCODE_WARNING (1)
+
+///
+/// Bitmask of values for Authentication Status.
+/// Authentication Status is returned from EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
+/// and the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+///
+/// xx00 Image was not signed.
+/// xxx1 Platform security policy override. Assumes the same meaning as 0010 (the image was signed, the
+///      signature was tested, and the signature passed authentication test).
+/// 0010 Image was signed, the signature was tested, and the signature passed authentication test.
+/// 0110 Image was signed and the signature was not tested.
+/// 1010 Image was signed, the signature was tested, and the signature failed the authentication test.
+///
+///@{
+#define EFI_AUTH_STATUS_PLATFORM_OVERRIDE   0x01
+#define EFI_AUTH_STATUS_IMAGE_SIGNED        0x02
+#define EFI_AUTH_STATUS_NOT_TESTED          0x04
+#define EFI_AUTH_STATUS_TEST_FAILED         0x08
+#define EFI_AUTH_STATUS_ALL                 0x0f
+///@}
+
+///
+/// SMRAM states and capabilities
+///
+#define EFI_SMRAM_OPEN                  0x00000001
+#define EFI_SMRAM_CLOSED                0x00000002
+#define EFI_SMRAM_LOCKED                0x00000004
+#define EFI_CACHEABLE                   0x00000008
+#define EFI_ALLOCATED                   0x00000010
+#define EFI_NEEDS_TESTING               0x00000020
+#define EFI_NEEDS_ECC_INITIALIZATION    0x00000040
+
+///
+/// Structure describing a SMRAM region and its accessibility attributes.
+///
+typedef struct {
+  ///
+  /// Designates the physical address of the SMRAM in memory. This view of memory is
+  /// the same as seen by I/O-based agents, for example, but it may not be the address seen
+  /// by the processors.
+  ///
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;
+  ///
+  /// Designates the address of the SMRAM, as seen by software executing on the
+  /// processors. This address may or may not match PhysicalStart.
+  ///
+  EFI_PHYSICAL_ADDRESS  CpuStart;
+  ///
+  /// Describes the number of bytes in the SMRAM region.
+  ///
+  UINT64                PhysicalSize;
+  ///
+  /// Describes the accessibility attributes of the SMRAM.  These attributes include the
+  /// hardware state (e.g., Open/Closed/Locked), capability (e.g., cacheable), logical
+  /// allocation (e.g., allocated), and pre-use initialization (e.g., needs testing/ECC
+  /// initialization).
+  ///
+  UINT64                RegionState;
+} EFI_SMRAM_DESCRIPTOR;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiS3BootScript.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiS3BootScript.h
new file mode 100644
index 0000000..01cae15
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiS3BootScript.h
@@ -0,0 +1,61 @@
+/** @file
+  This file contains the boot script defintions that are shared between the
+  Boot Script Executor PPI and the Boot Script Save Protocol.
+
+  Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PI_S3_BOOT_SCRIPT_H_
+#define _PI_S3_BOOT_SCRIPT_H_
+
+FILE_LICENCE ( BSD3 );
+
+//*******************************************
+// EFI Boot Script Opcode definitions
+//*******************************************
+#define EFI_BOOT_SCRIPT_IO_WRITE_OPCODE                 0x00
+#define EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE            0x01
+#define EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE                0x02
+#define EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE           0x03
+#define EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE         0x04
+#define EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE    0x05
+#define EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE            0x06
+#define EFI_BOOT_SCRIPT_STALL_OPCODE                    0x07
+#define EFI_BOOT_SCRIPT_DISPATCH_OPCODE                 0x08
+#define EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE               0x09
+#define EFI_BOOT_SCRIPT_INFORMATION_OPCODE              0x0A
+#define EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE        0x0B
+#define EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE   0x0C
+#define EFI_BOOT_SCRIPT_IO_POLL_OPCODE                  0x0D
+#define EFI_BOOT_SCRIPT_MEM_POLL_OPCODE                 0x0E
+#define EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE          0x0F
+#define EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE         0x10
+
+//*******************************************
+// EFI_BOOT_SCRIPT_WIDTH
+//*******************************************
+typedef enum {
+  EfiBootScriptWidthUint8,
+  EfiBootScriptWidthUint16,
+  EfiBootScriptWidthUint32,
+  EfiBootScriptWidthUint64,
+  EfiBootScriptWidthFifoUint8,
+  EfiBootScriptWidthFifoUint16,
+  EfiBootScriptWidthFifoUint32,
+  EfiBootScriptWidthFifoUint64,
+  EfiBootScriptWidthFillUint8,
+  EfiBootScriptWidthFillUint16,
+  EfiBootScriptWidthFillUint32,
+  EfiBootScriptWidthFillUint64,
+  EfiBootScriptWidthMaximum
+} EFI_BOOT_SCRIPT_WIDTH;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h
new file mode 100644
index 0000000..6133f00
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h
@@ -0,0 +1,1130 @@
+/** @file
+  StatusCode related definitions in PI.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  These status codes are defined in UEFI Platform Initialization Specification 1.2,
+  Volume 3: Shared Architectural Elements.
+
+**/
+
+#ifndef __PI_STATUS_CODE_H__
+#define __PI_STATUS_CODE_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// Required for IA32 and IPF defines for CPU exception types
+//
+#include <ipxe/efi/Protocol/DebugSupport.h>
+
+///
+/// Status Code Type Definition.
+///
+typedef UINT32  EFI_STATUS_CODE_TYPE;
+
+///
+/// A Status Code Type is made up of the code type and severity.
+/// All values masked by EFI_STATUS_CODE_RESERVED_MASK are
+/// reserved for use by this specification.
+///
+///@{
+#define EFI_STATUS_CODE_TYPE_MASK     0x000000FF
+#define EFI_STATUS_CODE_SEVERITY_MASK 0xFF000000
+#define EFI_STATUS_CODE_RESERVED_MASK 0x00FFFF00
+///@}
+
+///
+/// Definition of code types. All other values masked by
+/// EFI_STATUS_CODE_TYPE_MASK are reserved for use by
+/// this specification.
+///
+///@{
+#define EFI_PROGRESS_CODE             0x00000001
+#define EFI_ERROR_CODE                0x00000002
+#define EFI_DEBUG_CODE                0x00000003
+///@}
+
+///
+/// Definitions of severities, all other values masked by
+/// EFI_STATUS_CODE_SEVERITY_MASK are reserved for use by
+/// this specification.
+/// Uncontained errors are major errors that could not contained
+/// to the specific component that is reporting the error.
+/// For example, if a memory error was not detected early enough,
+/// the bad data could be consumed by other drivers.
+///
+///@{
+#define EFI_ERROR_MINOR               0x40000000
+#define EFI_ERROR_MAJOR               0x80000000
+#define EFI_ERROR_UNRECOVERED         0x90000000
+#define EFI_ERROR_UNCONTAINED         0xa0000000
+///@}
+
+///
+/// Status Code Value Definition.
+///
+typedef UINT32 EFI_STATUS_CODE_VALUE;
+
+///
+/// A Status Code Value is made up of the class, subclass, and
+/// an operation.
+///
+///@{
+#define EFI_STATUS_CODE_CLASS_MASK      0xFF000000
+#define EFI_STATUS_CODE_SUBCLASS_MASK   0x00FF0000
+#define EFI_STATUS_CODE_OPERATION_MASK  0x0000FFFF
+///@}
+
+///
+/// Definition of Status Code extended data header.
+/// The data will follow HeaderSize bytes from the beginning of
+/// the structure and is Size bytes long.
+///
+typedef struct {
+  ///
+  /// The size of the structure. This is specified to enable future expansion.
+  ///
+  UINT16    HeaderSize;
+  ///
+  /// The size of the data in bytes. This does not include the size of the header structure.
+  ///
+  UINT16    Size;
+  ///
+  /// The GUID defining the type of the data.
+  ///
+  EFI_GUID  Type;
+} EFI_STATUS_CODE_DATA;
+
+///
+/// General partitioning scheme for Progress and Error Codes are:
+///   - 0x0000-0x0FFF    Shared by all sub-classes in a given class.
+///   - 0x1000-0x7FFF    Subclass Specific.
+///   - 0x8000-0xFFFF    OEM specific.
+///@{
+#define EFI_SUBCLASS_SPECIFIC 0x1000
+#define EFI_OEM_SPECIFIC      0x8000
+///@}
+
+///
+/// Debug Code definitions for all classes and subclass.
+/// Only one debug code is defined at this point and should
+/// be used for anything that is sent to the debug stream.
+///
+///@{
+#define EFI_DC_UNSPECIFIED  0x0
+///@}
+
+///
+/// Class definitions.
+/// Values of 4-127 are reserved for future use by this specification.
+/// Values in the range 127-255 are reserved for OEM use.
+///
+///@{
+#define EFI_COMPUTING_UNIT  0x00000000
+#define EFI_PERIPHERAL      0x01000000
+#define EFI_IO_BUS          0x02000000
+#define EFI_SOFTWARE        0x03000000
+///@}
+
+///
+/// Computing Unit Subclass definitions.
+/// Values of 8-127 are reserved for future use by this specification.
+/// Values of 128-255 are reserved for OEM use.
+///
+///@{
+#define EFI_COMPUTING_UNIT_UNSPECIFIED        (EFI_COMPUTING_UNIT | 0x00000000)
+#define EFI_COMPUTING_UNIT_HOST_PROCESSOR     (EFI_COMPUTING_UNIT | 0x00010000)
+#define EFI_COMPUTING_UNIT_FIRMWARE_PROCESSOR (EFI_COMPUTING_UNIT | 0x00020000)
+#define EFI_COMPUTING_UNIT_IO_PROCESSOR       (EFI_COMPUTING_UNIT | 0x00030000)
+#define EFI_COMPUTING_UNIT_CACHE              (EFI_COMPUTING_UNIT | 0x00040000)
+#define EFI_COMPUTING_UNIT_MEMORY             (EFI_COMPUTING_UNIT | 0x00050000)
+#define EFI_COMPUTING_UNIT_CHIPSET            (EFI_COMPUTING_UNIT | 0x00060000)
+///@}
+
+///
+/// Computing Unit Class Progress Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_CU_PC_INIT_BEGIN  0x00000000
+#define EFI_CU_PC_INIT_END    0x00000001
+///@}
+
+//
+// Computing Unit Unspecified Subclass Progress Code definitions.
+//
+
+///
+/// Computing Unit Host Processor Subclass Progress Code definitions.
+///@{
+#define EFI_CU_HP_PC_POWER_ON_INIT          (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_HP_PC_CACHE_INIT             (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_HP_PC_RAM_INIT               (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_CU_HP_PC_MEMORY_CONTROLLER_INIT (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_CU_HP_PC_IO_INIT                (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_CU_HP_PC_BSP_SELECT             (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_CU_HP_PC_BSP_RESELECT           (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_CU_HP_PC_AP_INIT                (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_CU_HP_PC_SMM_INIT               (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+///@}
+
+//
+// Computing Unit Firmware Processor Subclass Progress Code definitions.
+//
+
+//
+// Computing Unit IO Processor Subclass Progress Code definitions.
+//
+
+///
+/// Computing Unit Cache Subclass Progress Code definitions.
+///
+///@{
+#define EFI_CU_CACHE_PC_PRESENCE_DETECT (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_CACHE_PC_CONFIGURATION   (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+///
+/// Computing Unit Memory Subclass Progress Code definitions.
+///
+///@{
+#define EFI_CU_MEMORY_PC_SPD_READ         (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_MEMORY_PC_PRESENCE_DETECT  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_MEMORY_PC_TIMING           (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_CU_MEMORY_PC_CONFIGURING      (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_CU_MEMORY_PC_OPTIMIZING       (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_CU_MEMORY_PC_INIT             (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_CU_MEMORY_PC_TEST             (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+///@}
+
+//
+// Computing Unit Chipset Subclass Progress Code definitions.
+//
+
+///
+/// South Bridge initialization prior to memory detection.
+///
+#define EFI_CHIPSET_PC_PEI_CAR_SB_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000000)
+
+///
+/// North Bridge initialization prior to memory detection.
+///
+#define EFI_CHIPSET_PC_PEI_CAR_NB_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000001)
+
+///
+/// South Bridge initialization after memory detection.
+///
+#define EFI_CHIPSET_PC_PEI_MEM_SB_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000002)
+
+///
+/// North Bridge initialization after memory detection.
+///
+#define EFI_CHIPSET_PC_PEI_MEM_NB_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000003)
+
+///
+/// PCI Host Bridge DXE initialization.
+///
+#define EFI_CHIPSET_PC_DXE_HB_INIT          (EFI_SUBCLASS_SPECIFIC|0x00000004)
+
+///
+/// North Bridge DXE initialization.
+///
+#define EFI_CHIPSET_PC_DXE_NB_INIT          (EFI_SUBCLASS_SPECIFIC|0x00000005)
+
+///
+/// North Bridge specific SMM initialization in DXE.
+///
+#define EFI_CHIPSET_PC_DXE_NB_SMM_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000006)
+
+///
+/// Initialization of the South Bridge specific UEFI Runtime Services.
+///
+#define EFI_CHIPSET_PC_DXE_SB_RT_INIT       (EFI_SUBCLASS_SPECIFIC|0x00000007)
+
+///
+/// South Bridge DXE initialization
+///
+#define EFI_CHIPSET_PC_DXE_SB_INIT          (EFI_SUBCLASS_SPECIFIC|0x00000008)
+
+///
+/// South Bridge specific SMM initialization in DXE.
+///
+#define EFI_CHIPSET_PC_DXE_SB_SMM_INIT      (EFI_SUBCLASS_SPECIFIC|0x00000009)
+
+///
+/// Initialization of the South Bridge devices.
+///
+#define EFI_CHIPSET_PC_DXE_SB_DEVICES_INIT  (EFI_SUBCLASS_SPECIFIC|0x0000000a)
+
+///
+/// Computing Unit Class Error Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_CU_EC_NON_SPECIFIC    0x00000000
+#define EFI_CU_EC_DISABLED        0x00000001
+#define EFI_CU_EC_NOT_SUPPORTED   0x00000002
+#define EFI_CU_EC_NOT_DETECTED    0x00000003
+#define EFI_CU_EC_NOT_CONFIGURED  0x00000004
+///@}
+
+//
+// Computing Unit Unspecified Subclass Error Code definitions.
+//
+
+///
+/// Computing Unit Host Processor Subclass Error Code definitions.
+///
+///@{
+#define EFI_CU_HP_EC_INVALID_TYPE         (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_HP_EC_INVALID_SPEED        (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_HP_EC_MISMATCH             (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_CU_HP_EC_TIMER_EXPIRED        (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_CU_HP_EC_SELF_TEST            (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_CU_HP_EC_INTERNAL             (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_CU_HP_EC_THERMAL              (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_CU_HP_EC_LOW_VOLTAGE          (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_CU_HP_EC_HIGH_VOLTAGE         (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_CU_HP_EC_CACHE                (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_CU_HP_EC_MICROCODE_UPDATE     (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+#define EFI_CU_HP_EC_CORRECTABLE          (EFI_SUBCLASS_SPECIFIC | 0x0000000B)
+#define EFI_CU_HP_EC_UNCORRECTABLE        (EFI_SUBCLASS_SPECIFIC | 0x0000000C)
+#define EFI_CU_HP_EC_NO_MICROCODE_UPDATE  (EFI_SUBCLASS_SPECIFIC | 0x0000000D)
+///@}
+
+///
+/// Computing Unit Firmware Processor Subclass Error Code definitions.
+///
+///@{
+#define EFI_CU_FP_EC_HARD_FAIL  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_FP_EC_SOFT_FAIL  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_FP_EC_COMM_ERROR (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+//
+// Computing Unit IO Processor Subclass Error Code definitions.
+//
+
+///
+/// Computing Unit Cache Subclass Error Code definitions.
+///
+///@{
+#define EFI_CU_CACHE_EC_INVALID_TYPE  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_CACHE_EC_INVALID_SPEED (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_CACHE_EC_INVALID_SIZE  (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_CU_CACHE_EC_MISMATCH      (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+///@}
+
+///
+/// Computing Unit Memory Subclass Error Code definitions.
+///
+///@{
+#define EFI_CU_MEMORY_EC_INVALID_TYPE   (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CU_MEMORY_EC_INVALID_SPEED  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CU_MEMORY_EC_CORRECTABLE    (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_CU_MEMORY_EC_UNCORRECTABLE  (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_CU_MEMORY_EC_SPD_FAIL       (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_CU_MEMORY_EC_INVALID_SIZE   (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_CU_MEMORY_EC_MISMATCH       (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_CU_MEMORY_EC_S3_RESUME_FAIL (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_CU_MEMORY_EC_UPDATE_FAIL    (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_CU_MEMORY_EC_NONE_DETECTED  (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_CU_MEMORY_EC_NONE_USEFUL    (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+///@}
+
+///
+/// Computing Unit Chipset Subclass Error Code definitions.
+///
+///@{
+#define EFI_CHIPSET_EC_BAD_BATTERY      (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_CHIPSET_EC_DXE_NB_ERROR     (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_CHIPSET_EC_DXE_SB_ERROR     (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+///
+/// Peripheral Subclass definitions.
+/// Values of 12-127 are reserved for future use by this specification.
+/// Values of 128-255 are reserved for OEM use.
+///
+///@{
+#define EFI_PERIPHERAL_UNSPECIFIED      (EFI_PERIPHERAL | 0x00000000)
+#define EFI_PERIPHERAL_KEYBOARD         (EFI_PERIPHERAL | 0x00010000)
+#define EFI_PERIPHERAL_MOUSE            (EFI_PERIPHERAL | 0x00020000)
+#define EFI_PERIPHERAL_LOCAL_CONSOLE    (EFI_PERIPHERAL | 0x00030000)
+#define EFI_PERIPHERAL_REMOTE_CONSOLE   (EFI_PERIPHERAL | 0x00040000)
+#define EFI_PERIPHERAL_SERIAL_PORT      (EFI_PERIPHERAL | 0x00050000)
+#define EFI_PERIPHERAL_PARALLEL_PORT    (EFI_PERIPHERAL | 0x00060000)
+#define EFI_PERIPHERAL_FIXED_MEDIA      (EFI_PERIPHERAL | 0x00070000)
+#define EFI_PERIPHERAL_REMOVABLE_MEDIA  (EFI_PERIPHERAL | 0x00080000)
+#define EFI_PERIPHERAL_AUDIO_INPUT      (EFI_PERIPHERAL | 0x00090000)
+#define EFI_PERIPHERAL_AUDIO_OUTPUT     (EFI_PERIPHERAL | 0x000A0000)
+#define EFI_PERIPHERAL_LCD_DEVICE       (EFI_PERIPHERAL | 0x000B0000)
+#define EFI_PERIPHERAL_NETWORK          (EFI_PERIPHERAL | 0x000C0000)
+///@}
+
+///
+/// Peripheral Class Progress Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_P_PC_INIT             0x00000000
+#define EFI_P_PC_RESET            0x00000001
+#define EFI_P_PC_DISABLE          0x00000002
+#define EFI_P_PC_PRESENCE_DETECT  0x00000003
+#define EFI_P_PC_ENABLE           0x00000004
+#define EFI_P_PC_RECONFIG         0x00000005
+#define EFI_P_PC_DETECTED         0x00000006
+///@}
+
+//
+// Peripheral Class Unspecified Subclass Progress Code definitions.
+//
+
+///
+/// Peripheral Class Keyboard Subclass Progress Code definitions.
+///
+///@{
+#define EFI_P_KEYBOARD_PC_CLEAR_BUFFER  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_P_KEYBOARD_PC_SELF_TEST     (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+///
+/// Peripheral Class Mouse Subclass Progress Code definitions.
+///
+///@{
+#define EFI_P_MOUSE_PC_SELF_TEST  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+///@}
+
+//
+// Peripheral Class Local Console Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Remote Console Subclass Progress Code definitions.
+//
+
+///
+/// Peripheral Class Serial Port Subclass Progress Code definitions.
+///
+///@{
+#define EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+///@}
+
+//
+// Peripheral Class Parallel Port Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Fixed Media Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Removable Media Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Audio Input Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Audio Output Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class LCD Device Subclass Progress Code definitions.
+//
+
+//
+// Peripheral Class Network Subclass Progress Code definitions.
+//
+
+///
+/// Peripheral Class Error Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_P_EC_NON_SPECIFIC       0x00000000
+#define EFI_P_EC_DISABLED           0x00000001
+#define EFI_P_EC_NOT_SUPPORTED      0x00000002
+#define EFI_P_EC_NOT_DETECTED       0x00000003
+#define EFI_P_EC_NOT_CONFIGURED     0x00000004
+#define EFI_P_EC_INTERFACE_ERROR    0x00000005
+#define EFI_P_EC_CONTROLLER_ERROR   0x00000006
+#define EFI_P_EC_INPUT_ERROR        0x00000007
+#define EFI_P_EC_OUTPUT_ERROR       0x00000008
+#define EFI_P_EC_RESOURCE_CONFLICT  0x00000009
+///@}
+
+//
+// Peripheral Class Unspecified Subclass Error Code definitions.
+//
+
+///
+/// Peripheral Class Keyboard Subclass Error Code definitions.
+///
+///@{
+#define EFI_P_KEYBOARD_EC_LOCKED    (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_P_KEYBOARD_EC_STUCK_KEY (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+///
+/// Peripheral Class Mouse Subclass Error Code definitions.
+///
+///@{
+#define EFI_P_MOUSE_EC_LOCKED (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+///@}
+
+//
+// Peripheral Class Local Console Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Remote Console Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Serial Port Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Parallel Port Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Fixed Media Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Removable Media Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Audio Input Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Audio Output Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class LCD Device Subclass Error Code definitions.
+//
+
+//
+// Peripheral Class Network Subclass Error Code definitions.
+//
+
+///
+/// IO Bus Subclass definitions.
+/// Values of 14-127 are reserved for future use by this specification.
+/// Values of 128-255 are reserved for OEM use.
+///
+///@{
+#define EFI_IO_BUS_UNSPECIFIED  (EFI_IO_BUS | 0x00000000)
+#define EFI_IO_BUS_PCI          (EFI_IO_BUS | 0x00010000)
+#define EFI_IO_BUS_USB          (EFI_IO_BUS | 0x00020000)
+#define EFI_IO_BUS_IBA          (EFI_IO_BUS | 0x00030000)
+#define EFI_IO_BUS_AGP          (EFI_IO_BUS | 0x00040000)
+#define EFI_IO_BUS_PC_CARD      (EFI_IO_BUS | 0x00050000)
+#define EFI_IO_BUS_LPC          (EFI_IO_BUS | 0x00060000)
+#define EFI_IO_BUS_SCSI         (EFI_IO_BUS | 0x00070000)
+#define EFI_IO_BUS_ATA_ATAPI    (EFI_IO_BUS | 0x00080000)
+#define EFI_IO_BUS_FC           (EFI_IO_BUS | 0x00090000)
+#define EFI_IO_BUS_IP_NETWORK   (EFI_IO_BUS | 0x000A0000)
+#define EFI_IO_BUS_SMBUS        (EFI_IO_BUS | 0x000B0000)
+#define EFI_IO_BUS_I2C          (EFI_IO_BUS | 0x000C0000)
+///@}
+
+///
+/// IO Bus Class Progress Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_IOB_PC_INIT     0x00000000
+#define EFI_IOB_PC_RESET    0x00000001
+#define EFI_IOB_PC_DISABLE  0x00000002
+#define EFI_IOB_PC_DETECT   0x00000003
+#define EFI_IOB_PC_ENABLE   0x00000004
+#define EFI_IOB_PC_RECONFIG 0x00000005
+#define EFI_IOB_PC_HOTPLUG  0x00000006
+///@}
+
+//
+// IO Bus Class Unspecified Subclass Progress Code definitions.
+//
+
+///
+/// IO Bus Class PCI Subclass Progress Code definitions.
+///
+///@{
+#define EFI_IOB_PCI_BUS_ENUM   (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_IOB_PCI_RES_ALLOC  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_IOB_PCI_HPC_INIT   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+//
+// IO Bus Class USB Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class IBA Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class AGP Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class PC Card Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class LPC Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class SCSI Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class ATA/ATAPI Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class FC Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class IP Network Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class SMBUS Subclass Progress Code definitions.
+//
+
+//
+// IO Bus Class I2C Subclass Progress Code definitions.
+//
+
+///
+/// IO Bus Class Error Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_IOB_EC_NON_SPECIFIC       0x00000000
+#define EFI_IOB_EC_DISABLED           0x00000001
+#define EFI_IOB_EC_NOT_SUPPORTED      0x00000002
+#define EFI_IOB_EC_NOT_DETECTED       0x00000003
+#define EFI_IOB_EC_NOT_CONFIGURED     0x00000004
+#define EFI_IOB_EC_INTERFACE_ERROR    0x00000005
+#define EFI_IOB_EC_CONTROLLER_ERROR   0x00000006
+#define EFI_IOB_EC_READ_ERROR         0x00000007
+#define EFI_IOB_EC_WRITE_ERROR        0x00000008
+#define EFI_IOB_EC_RESOURCE_CONFLICT  0x00000009
+///@}
+
+//
+// IO Bus Class Unspecified Subclass Error Code definitions.
+//
+
+///
+/// IO Bus Class PCI Subclass Error Code definitions.
+///
+///@{
+#define EFI_IOB_PCI_EC_PERR (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_IOB_PCI_EC_SERR (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+//
+// IO Bus Class USB Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class IBA Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class AGP Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class PC Card Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class LPC Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class SCSI Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class ATA/ATAPI Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class FC Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class IP Network Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class SMBUS Subclass Error Code definitions.
+//
+
+//
+// IO Bus Class I2C Subclass Error Code definitions.
+//
+
+///
+/// Software Subclass definitions.
+/// Values of 14-127 are reserved for future use by this specification.
+/// Values of 128-255 are reserved for OEM use.
+///
+///@{
+#define EFI_SOFTWARE_UNSPECIFIED          (EFI_SOFTWARE | 0x00000000)
+#define EFI_SOFTWARE_SEC                  (EFI_SOFTWARE | 0x00010000)
+#define EFI_SOFTWARE_PEI_CORE             (EFI_SOFTWARE | 0x00020000)
+#define EFI_SOFTWARE_PEI_MODULE           (EFI_SOFTWARE | 0x00030000)
+#define EFI_SOFTWARE_DXE_CORE             (EFI_SOFTWARE | 0x00040000)
+#define EFI_SOFTWARE_DXE_BS_DRIVER        (EFI_SOFTWARE | 0x00050000)
+#define EFI_SOFTWARE_DXE_RT_DRIVER        (EFI_SOFTWARE | 0x00060000)
+#define EFI_SOFTWARE_SMM_DRIVER           (EFI_SOFTWARE | 0x00070000)
+#define EFI_SOFTWARE_EFI_APPLICATION      (EFI_SOFTWARE | 0x00080000)
+#define EFI_SOFTWARE_EFI_OS_LOADER        (EFI_SOFTWARE | 0x00090000)
+#define EFI_SOFTWARE_RT                   (EFI_SOFTWARE | 0x000A0000)
+#define EFI_SOFTWARE_AL                   (EFI_SOFTWARE | 0x000B0000)
+#define EFI_SOFTWARE_EBC_EXCEPTION        (EFI_SOFTWARE | 0x000C0000)
+#define EFI_SOFTWARE_IA32_EXCEPTION       (EFI_SOFTWARE | 0x000D0000)
+#define EFI_SOFTWARE_IPF_EXCEPTION        (EFI_SOFTWARE | 0x000E0000)
+#define EFI_SOFTWARE_PEI_SERVICE          (EFI_SOFTWARE | 0x000F0000)
+#define EFI_SOFTWARE_EFI_BOOT_SERVICE     (EFI_SOFTWARE | 0x00100000)
+#define EFI_SOFTWARE_EFI_RUNTIME_SERVICE  (EFI_SOFTWARE | 0x00110000)
+#define EFI_SOFTWARE_EFI_DXE_SERVICE      (EFI_SOFTWARE | 0x00120000)
+///@}
+
+///
+/// Software Class Progress Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_SW_PC_INIT                0x00000000
+#define EFI_SW_PC_LOAD                0x00000001
+#define EFI_SW_PC_INIT_BEGIN          0x00000002
+#define EFI_SW_PC_INIT_END            0x00000003
+#define EFI_SW_PC_AUTHENTICATE_BEGIN  0x00000004
+#define EFI_SW_PC_AUTHENTICATE_END    0x00000005
+#define EFI_SW_PC_INPUT_WAIT          0x00000006
+#define EFI_SW_PC_USER_SETUP          0x00000007
+///@}
+
+//
+// Software Class Unspecified Subclass Progress Code definitions.
+//
+
+///
+/// Software Class SEC Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_SEC_PC_ENTRY_POINT     (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_SEC_PC_HANDOFF_TO_NEXT (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+///
+/// Software Class PEI Core Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_PEI_CORE_PC_ENTRY_POINT      (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_PEI_CORE_PC_RETURN_TO_LAST   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+///
+/// Software Class PEI Module Subclass Progress Code definitions.
+/// Note: EFI_SW_PEI_PC_RECOVERY_BEGIN is different from PI 1.2 Specification.
+///
+///@{
+#define EFI_SW_PEI_PC_RECOVERY_BEGIN  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PEI_PC_CAPSULE_LOAD    (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_PEI_PC_CAPSULE_START   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_PEI_PC_RECOVERY_USER   (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_PEI_PC_RECOVERY_AUTO   (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_PEI_PC_S3_BOOT_SCRIPT  (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_PEI_PC_OS_WAKE         (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+///@}
+
+///
+/// Software Class DXE Core Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_DXE_CORE_PC_ENTRY_POINT      (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_DXE_CORE_PC_RETURN_TO_LAST   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_DXE_CORE_PC_START_DRIVER     (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_DXE_CORE_PC_ARCH_READY       (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+///@}
+
+///
+/// Software Class DXE BS Driver Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_DXE_BS_PC_LEGACY_OPROM_INIT            (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT          (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT            (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_DXE_BS_PC_EXIT_BOOT_SERVICES_EVENT     (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_DXE_BS_PC_VIRTUAL_ADDRESS_CHANGE_EVENT (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+///@}
+
+//
+// Software Class SMM Driver Subclass Progress Code definitions.
+//
+
+//
+// Software Class EFI Application Subclass Progress Code definitions.
+//
+
+//
+// Software Class EFI OS Loader Subclass Progress Code definitions.
+//
+
+///
+/// Software Class EFI RT Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_RT_PC_ENTRY_POINT      (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_RT_PC_HANDOFF_TO_NEXT  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_RT_PC_RETURN_TO_LAST   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+//
+// Software Class EBC Exception Subclass Progress Code definitions.
+//
+
+//
+// Software Class IA32 Exception Subclass Progress Code definitions.
+//
+
+//
+// Software Class X64 Exception Subclass Progress Code definitions.
+//
+
+//
+// Software Class IPF Exception Subclass Progress Code definitions.
+//
+
+///
+/// Software Class PEI Services Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_PS_PC_INSTALL_PPI              (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PS_PC_REINSTALL_PPI            (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_PS_PC_LOCATE_PPI               (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_PS_PC_NOTIFY_PPI               (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_PS_PC_GET_BOOT_MODE            (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_PS_PC_SET_BOOT_MODE            (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_PS_PC_GET_HOB_LIST             (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_SW_PS_PC_CREATE_HOB               (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_SW_PS_PC_FFS_FIND_NEXT_VOLUME     (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_SW_PS_PC_FFS_FIND_NEXT_FILE       (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_SW_PS_PC_FFS_FIND_SECTION_DATA    (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+#define EFI_SW_PS_PC_INSTALL_PEI_MEMORY       (EFI_SUBCLASS_SPECIFIC | 0x0000000B)
+#define EFI_SW_PS_PC_ALLOCATE_PAGES           (EFI_SUBCLASS_SPECIFIC | 0x0000000C)
+#define EFI_SW_PS_PC_ALLOCATE_POOL            (EFI_SUBCLASS_SPECIFIC | 0x0000000D)
+#define EFI_SW_PS_PC_COPY_MEM                 (EFI_SUBCLASS_SPECIFIC | 0x0000000E)
+#define EFI_SW_PS_PC_SET_MEM                  (EFI_SUBCLASS_SPECIFIC | 0x0000000F)
+#define EFI_SW_PS_PC_RESET_SYSTEM             (EFI_SUBCLASS_SPECIFIC | 0x00000010)
+#define EFI_SW_PS_PC_FFS_FIND_FILE_BY_NAME    (EFI_SUBCLASS_SPECIFIC | 0x00000013)
+#define EFI_SW_PS_PC_FFS_GET_FILE_INFO        (EFI_SUBCLASS_SPECIFIC | 0x00000014)
+#define EFI_SW_PS_PC_FFS_GET_VOLUME_INFO      (EFI_SUBCLASS_SPECIFIC | 0x00000015)
+#define EFI_SW_PS_PC_FFS_REGISTER_FOR_SHADOW  (EFI_SUBCLASS_SPECIFIC | 0x00000016)
+///@}
+
+///
+/// Software Class EFI Boot Services Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_BS_PC_RAISE_TPL                      (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_BS_PC_RESTORE_TPL                    (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_BS_PC_ALLOCATE_PAGES                 (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_BS_PC_FREE_PAGES                     (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_BS_PC_GET_MEMORY_MAP                 (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_BS_PC_ALLOCATE_POOL                  (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_BS_PC_FREE_POOL                      (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_SW_BS_PC_CREATE_EVENT                   (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_SW_BS_PC_SET_TIMER                      (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_SW_BS_PC_WAIT_FOR_EVENT                 (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_SW_BS_PC_SIGNAL_EVENT                   (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+#define EFI_SW_BS_PC_CLOSE_EVENT                    (EFI_SUBCLASS_SPECIFIC | 0x0000000B)
+#define EFI_SW_BS_PC_CHECK_EVENT                    (EFI_SUBCLASS_SPECIFIC | 0x0000000C)
+#define EFI_SW_BS_PC_INSTALL_PROTOCOL_INTERFACE     (EFI_SUBCLASS_SPECIFIC | 0x0000000D)
+#define EFI_SW_BS_PC_REINSTALL_PROTOCOL_INTERFACE   (EFI_SUBCLASS_SPECIFIC | 0x0000000E)
+#define EFI_SW_BS_PC_UNINSTALL_PROTOCOL_INTERFACE   (EFI_SUBCLASS_SPECIFIC | 0x0000000F)
+#define EFI_SW_BS_PC_HANDLE_PROTOCOL                (EFI_SUBCLASS_SPECIFIC | 0x00000010)
+#define EFI_SW_BS_PC_PC_HANDLE_PROTOCOL             (EFI_SUBCLASS_SPECIFIC | 0x00000011)
+#define EFI_SW_BS_PC_REGISTER_PROTOCOL_NOTIFY       (EFI_SUBCLASS_SPECIFIC | 0x00000012)
+#define EFI_SW_BS_PC_LOCATE_HANDLE                  (EFI_SUBCLASS_SPECIFIC | 0x00000013)
+#define EFI_SW_BS_PC_INSTALL_CONFIGURATION_TABLE    (EFI_SUBCLASS_SPECIFIC | 0x00000014)
+#define EFI_SW_BS_PC_LOAD_IMAGE                     (EFI_SUBCLASS_SPECIFIC | 0x00000015)
+#define EFI_SW_BS_PC_START_IMAGE                    (EFI_SUBCLASS_SPECIFIC | 0x00000016)
+#define EFI_SW_BS_PC_EXIT                           (EFI_SUBCLASS_SPECIFIC | 0x00000017)
+#define EFI_SW_BS_PC_UNLOAD_IMAGE                   (EFI_SUBCLASS_SPECIFIC | 0x00000018)
+#define EFI_SW_BS_PC_EXIT_BOOT_SERVICES             (EFI_SUBCLASS_SPECIFIC | 0x00000019)
+#define EFI_SW_BS_PC_GET_NEXT_MONOTONIC_COUNT       (EFI_SUBCLASS_SPECIFIC | 0x0000001A)
+#define EFI_SW_BS_PC_STALL                          (EFI_SUBCLASS_SPECIFIC | 0x0000001B)
+#define EFI_SW_BS_PC_SET_WATCHDOG_TIMER             (EFI_SUBCLASS_SPECIFIC | 0x0000001C)
+#define EFI_SW_BS_PC_CONNECT_CONTROLLER             (EFI_SUBCLASS_SPECIFIC | 0x0000001D)
+#define EFI_SW_BS_PC_DISCONNECT_CONTROLLER          (EFI_SUBCLASS_SPECIFIC | 0x0000001E)
+#define EFI_SW_BS_PC_OPEN_PROTOCOL                  (EFI_SUBCLASS_SPECIFIC | 0x0000001F)
+#define EFI_SW_BS_PC_CLOSE_PROTOCOL                 (EFI_SUBCLASS_SPECIFIC | 0x00000020)
+#define EFI_SW_BS_PC_OPEN_PROTOCOL_INFORMATION      (EFI_SUBCLASS_SPECIFIC | 0x00000021)
+#define EFI_SW_BS_PC_PROTOCOLS_PER_HANDLE           (EFI_SUBCLASS_SPECIFIC | 0x00000022)
+#define EFI_SW_BS_PC_LOCATE_HANDLE_BUFFER           (EFI_SUBCLASS_SPECIFIC | 0x00000023)
+#define EFI_SW_BS_PC_LOCATE_PROTOCOL                (EFI_SUBCLASS_SPECIFIC | 0x00000024)
+#define EFI_SW_BS_PC_INSTALL_MULTIPLE_INTERFACES    (EFI_SUBCLASS_SPECIFIC | 0x00000025)
+#define EFI_SW_BS_PC_UNINSTALL_MULTIPLE_INTERFACES  (EFI_SUBCLASS_SPECIFIC | 0x00000026)
+#define EFI_SW_BS_PC_CALCULATE_CRC_32               (EFI_SUBCLASS_SPECIFIC | 0x00000027)
+#define EFI_SW_BS_PC_COPY_MEM                       (EFI_SUBCLASS_SPECIFIC | 0x00000028)
+#define EFI_SW_BS_PC_SET_MEM                        (EFI_SUBCLASS_SPECIFIC | 0x00000029)
+#define EFI_SW_BS_PC_CREATE_EVENT_EX                (EFI_SUBCLASS_SPECIFIC | 0x0000002A)
+///@}
+
+///
+/// Software Class EFI Runtime Services Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_RS_PC_GET_TIME                       (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_RS_PC_SET_TIME                       (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_RS_PC_GET_WAKEUP_TIME                (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_RS_PC_SET_WAKEUP_TIME                (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP        (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_RS_PC_CONVERT_POINTER                (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_RS_PC_GET_VARIABLE                   (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_SW_RS_PC_GET_NEXT_VARIABLE_NAME         (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_SW_RS_PC_SET_VARIABLE                   (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_SW_RS_PC_GET_NEXT_HIGH_MONOTONIC_COUNT  (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_SW_RS_PC_RESET_SYSTEM                   (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+#define EFI_SW_RS_PC_UPDATE_CAPSULE                 (EFI_SUBCLASS_SPECIFIC | 0x0000000B)
+#define EFI_SW_RS_PC_QUERY_CAPSULE_CAPABILITIES     (EFI_SUBCLASS_SPECIFIC | 0x0000000C)
+#define EFI_SW_RS_PC_QUERY_VARIABLE_INFO            (EFI_SUBCLASS_SPECIFIC | 0x0000000D)
+///@}
+
+///
+/// Software Class EFI DXE Services Subclass Progress Code definitions
+///
+///@{
+#define EFI_SW_DS_PC_ADD_MEMORY_SPACE             (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_DS_PC_ALLOCATE_MEMORY_SPACE        (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_DS_PC_FREE_MEMORY_SPACE            (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_DS_PC_REMOVE_MEMORY_SPACE          (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_DS_PC_GET_MEMORY_SPACE_DESCRIPTOR  (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_DS_PC_SET_MEMORY_SPACE_ATTRIBUTES  (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_DS_PC_GET_MEMORY_SPACE_MAP         (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_SW_DS_PC_ADD_IO_SPACE                 (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+#define EFI_SW_DS_PC_ALLOCATE_IO_SPACE            (EFI_SUBCLASS_SPECIFIC | 0x00000008)
+#define EFI_SW_DS_PC_FREE_IO_SPACE                (EFI_SUBCLASS_SPECIFIC | 0x00000009)
+#define EFI_SW_DS_PC_REMOVE_IO_SPACE              (EFI_SUBCLASS_SPECIFIC | 0x0000000A)
+#define EFI_SW_DS_PC_GET_IO_SPACE_DESCRIPTOR      (EFI_SUBCLASS_SPECIFIC | 0x0000000B)
+#define EFI_SW_DS_PC_GET_IO_SPACE_MAP             (EFI_SUBCLASS_SPECIFIC | 0x0000000C)
+#define EFI_SW_DS_PC_DISPATCH                     (EFI_SUBCLASS_SPECIFIC | 0x0000000D)
+#define EFI_SW_DS_PC_SCHEDULE                     (EFI_SUBCLASS_SPECIFIC | 0x0000000E)
+#define EFI_SW_DS_PC_TRUST                        (EFI_SUBCLASS_SPECIFIC | 0x0000000F)
+#define EFI_SW_DS_PC_PROCESS_FIRMWARE_VOLUME      (EFI_SUBCLASS_SPECIFIC | 0x00000010)
+///@}
+
+///
+/// Software Class Error Code definitions.
+/// These are shared by all subclasses.
+///
+///@{
+#define EFI_SW_EC_NON_SPECIFIC            0x00000000
+#define EFI_SW_EC_LOAD_ERROR              0x00000001
+#define EFI_SW_EC_INVALID_PARAMETER       0x00000002
+#define EFI_SW_EC_UNSUPPORTED             0x00000003
+#define EFI_SW_EC_INVALID_BUFFER          0x00000004
+#define EFI_SW_EC_OUT_OF_RESOURCES        0x00000005
+#define EFI_SW_EC_ABORTED                 0x00000006
+#define EFI_SW_EC_ILLEGAL_SOFTWARE_STATE  0x00000007
+#define EFI_SW_EC_ILLEGAL_HARDWARE_STATE  0x00000008
+#define EFI_SW_EC_START_ERROR             0x00000009
+#define EFI_SW_EC_BAD_DATE_TIME           0x0000000A
+#define EFI_SW_EC_CFG_INVALID             0x0000000B
+#define EFI_SW_EC_CFG_CLR_REQUEST         0x0000000C
+#define EFI_SW_EC_CFG_DEFAULT             0x0000000D
+#define EFI_SW_EC_PWD_INVALID             0x0000000E
+#define EFI_SW_EC_PWD_CLR_REQUEST         0x0000000F
+#define EFI_SW_EC_PWD_CLEARED             0x00000010
+#define EFI_SW_EC_EVENT_LOG_FULL          0x00000011
+///@}
+
+//
+// Software Class Unspecified Subclass Error Code definitions.
+//
+
+//
+// Software Class SEC Subclass Error Code definitions.
+//
+
+///
+/// Software Class PEI Core Subclass Error Code definitions.
+///
+///@{
+#define EFI_SW_PEI_CORE_EC_DXE_CORRUPT           (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND      (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_PEI_CORE_EC_MEMORY_NOT_INSTALLED  (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+///@}
+
+///
+/// Software Class PEI Module Subclass Error Code definitions.
+/// Note: EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR is different from PI 1.2 Specification.
+///
+///@{
+#define EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE          (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR   (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND      (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR         (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_PEI_EC_S3_OS_WAKE_ERROR             (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_PEI_EC_S3_RESUME_FAILED             (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND       (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+#define EFI_SW_PEI_EC_RECOVERY_FAILED              (EFI_SUBCLASS_SPECIFIC | 0x00000007)
+///@}
+
+///
+/// Software Class DXE Foundation Subclass Error Code definitions.
+///
+///@{
+#define EFI_SW_DXE_CORE_EC_NO_ARCH                (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+///@}
+
+
+///
+/// Software Class DXE Boot Service Driver Subclass Error Code definitions.
+///
+///@{
+#define EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE   (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_DXE_BS_EC_INVALID_PASSWORD        (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR  (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED      (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_DXE_BS_EC_INVALID_IDE_PASSWORD    (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+///@}
+
+//
+// Software Class DXE Runtime Service Driver Subclass Error Code definitions.
+//
+
+//
+// Software Class SMM Driver Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI Application Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI OS Loader Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI RT Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI AL Subclass Error Code definitions.
+//
+
+///
+/// Software Class EBC Exception Subclass Error Code definitions.
+/// These exceptions are derived from the debug protocol definitions in the EFI
+/// specification.
+///
+///@{
+#define EFI_SW_EC_EBC_UNDEFINED             0x00000000
+#define EFI_SW_EC_EBC_DIVIDE_ERROR          EXCEPT_EBC_DIVIDE_ERROR
+#define EFI_SW_EC_EBC_DEBUG                 EXCEPT_EBC_DEBUG
+#define EFI_SW_EC_EBC_BREAKPOINT            EXCEPT_EBC_BREAKPOINT
+#define EFI_SW_EC_EBC_OVERFLOW              EXCEPT_EBC_OVERFLOW
+#define EFI_SW_EC_EBC_INVALID_OPCODE        EXCEPT_EBC_INVALID_OPCODE
+#define EFI_SW_EC_EBC_STACK_FAULT           EXCEPT_EBC_STACK_FAULT
+#define EFI_SW_EC_EBC_ALIGNMENT_CHECK       EXCEPT_EBC_ALIGNMENT_CHECK
+#define EFI_SW_EC_EBC_INSTRUCTION_ENCODING  EXCEPT_EBC_INSTRUCTION_ENCODING
+#define EFI_SW_EC_EBC_BAD_BREAK             EXCEPT_EBC_BAD_BREAK
+#define EFI_SW_EC_EBC_STEP                  EXCEPT_EBC_STEP
+///@}
+
+///
+/// Software Class IA32 Exception Subclass Error Code definitions.
+/// These exceptions are derived from the debug protocol definitions in the EFI
+/// specification.
+///
+///@{
+#define EFI_SW_EC_IA32_DIVIDE_ERROR     EXCEPT_IA32_DIVIDE_ERROR
+#define EFI_SW_EC_IA32_DEBUG            EXCEPT_IA32_DEBUG
+#define EFI_SW_EC_IA32_NMI              EXCEPT_IA32_NMI
+#define EFI_SW_EC_IA32_BREAKPOINT       EXCEPT_IA32_BREAKPOINT
+#define EFI_SW_EC_IA32_OVERFLOW         EXCEPT_IA32_OVERFLOW
+#define EFI_SW_EC_IA32_BOUND            EXCEPT_IA32_BOUND
+#define EFI_SW_EC_IA32_INVALID_OPCODE   EXCEPT_IA32_INVALID_OPCODE
+#define EFI_SW_EC_IA32_DOUBLE_FAULT     EXCEPT_IA32_DOUBLE_FAULT
+#define EFI_SW_EC_IA32_INVALID_TSS      EXCEPT_IA32_INVALID_TSS
+#define EFI_SW_EC_IA32_SEG_NOT_PRESENT  EXCEPT_IA32_SEG_NOT_PRESENT
+#define EFI_SW_EC_IA32_STACK_FAULT      EXCEPT_IA32_STACK_FAULT
+#define EFI_SW_EC_IA32_GP_FAULT         EXCEPT_IA32_GP_FAULT
+#define EFI_SW_EC_IA32_PAGE_FAULT       EXCEPT_IA32_PAGE_FAULT
+#define EFI_SW_EC_IA32_FP_ERROR         EXCEPT_IA32_FP_ERROR
+#define EFI_SW_EC_IA32_ALIGNMENT_CHECK  EXCEPT_IA32_ALIGNMENT_CHECK
+#define EFI_SW_EC_IA32_MACHINE_CHECK    EXCEPT_IA32_MACHINE_CHECK
+#define EFI_SW_EC_IA32_SIMD             EXCEPT_IA32_SIMD
+///@}
+
+///
+/// Software Class IPF Exception Subclass Error Code definitions.
+/// These exceptions are derived from the debug protocol definitions in the EFI
+/// specification.
+///
+///@{
+#define EFI_SW_EC_IPF_ALT_DTLB            EXCEPT_IPF_ALT_DTLB
+#define EFI_SW_EC_IPF_DNESTED_TLB         EXCEPT_IPF_DNESTED_TLB
+#define EFI_SW_EC_IPF_BREAKPOINT          EXCEPT_IPF_BREAKPOINT
+#define EFI_SW_EC_IPF_EXTERNAL_INTERRUPT  EXCEPT_IPF_EXTERNAL_INTERRUPT
+#define EFI_SW_EC_IPF_GEN_EXCEPT          EXCEPT_IPF_GEN_EXCEPT
+#define EFI_SW_EC_IPF_NAT_CONSUMPTION     EXCEPT_IPF_NAT_CONSUMPTION
+#define EFI_SW_EC_IPF_DEBUG_EXCEPT        EXCEPT_IPF_DEBUG_EXCEPT
+#define EFI_SW_EC_IPF_UNALIGNED_ACCESS    EXCEPT_IPF_UNALIGNED_ACCESS
+#define EFI_SW_EC_IPF_FP_FAULT            EXCEPT_IPF_FP_FAULT
+#define EFI_SW_EC_IPF_FP_TRAP             EXCEPT_IPF_FP_TRAP
+#define EFI_SW_EC_IPF_TAKEN_BRANCH        EXCEPT_IPF_TAKEN_BRANCH
+#define EFI_SW_EC_IPF_SINGLE_STEP         EXCEPT_IPF_SINGLE_STEP
+///@}
+
+///
+/// Software Class PEI Service Subclass Error Code definitions.
+///
+///@{
+#define EFI_SW_PS_EC_RESET_NOT_AVAILABLE     (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_PS_EC_MEMORY_INSTALLED_TWICE  (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+///@}
+
+//
+// Software Class EFI Boot Service Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI Runtime Service Subclass Error Code definitions.
+//
+
+//
+// Software Class EFI DXE Service Subclass Error Code definitions.
+//
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/PiDxe.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/PiDxe.h
new file mode 100644
index 0000000..9443368
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/PiDxe.h
@@ -0,0 +1,27 @@
+/** @file
+
+  Root include file for Mde Package DXE_CORE, DXE, RUNTIME, SMM, SAL type modules.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_DXE_H__
+#define __PI_DXE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Uefi/UefiBaseType.h>
+#include <ipxe/efi/Uefi/UefiSpec.h>
+
+#include <ipxe/efi/Pi/PiDxeCis.h>
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
new file mode 100644
index 0000000..535cd4c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
@@ -0,0 +1,19 @@
+#ifndef _IPXE_EFI_PROCESSOR_BIND_H
+#define _IPXE_EFI_PROCESSOR_BIND_H
+
+/*
+ * EFI header files rely on having the CPU architecture directory
+ * present in the search path in order to pick up ProcessorBind.h.  We
+ * use this header file as a quick indirection layer.
+ *  - mcb30
+ */
+
+#if __i386__
+#include <ipxe/efi/Ia32/ProcessorBind.h>
+#endif
+
+#if __x86_64__
+#include <ipxe/efi/X64/ProcessorBind.h>
+#endif
+
+#endif /* _IPXE_EFI_PROCESSOR_BIND_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h
new file mode 100644
index 0000000..978ede5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h
@@ -0,0 +1,175 @@
+/** @file
+  UEFI Component Name 2 Protocol as defined in the UEFI 2.1 specification.
+  This protocol is used to retrieve user readable names of drivers
+  and controllers managed by UEFI Drivers.
+
+  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_COMPONENT_NAME2_H__
+#define __EFI_COMPONENT_NAME2_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Global ID for the Component Name Protocol
+///
+#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \
+  {0x6a7a5cff, 0xe8d9, 0x4f70, { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } }
+
+typedef struct _EFI_COMPONENT_NAME2_PROTOCOL  EFI_COMPONENT_NAME2_PROTOCOL;
+
+
+/**
+  Retrieves a string that is the user readable name of
+  the EFI Driver.
+
+  @param  This       A pointer to the
+                     EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+  @param  Language   A pointer to a Null-terminated ASCII string
+                     array indicating the language. This is the
+                     language of the driver name that the caller
+                     is requesting, and it must match one of the
+                     languages specified in SupportedLanguages.
+                     The number of languages supported by a
+                     driver is up to the driver writer. Language
+                     is specified in RFC 4646 language code
+                     format.
+
+  @param  DriverName A pointer to the string to return.
+                     This string is the name of the
+                     driver specified by This in the language
+                     specified by Language.
+
+  @retval EFI_SUCCESS           The string for the
+                                Driver specified by This and the
+                                language specified by Language
+                                was returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This
+                                does not support the language
+                                specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(
+  IN EFI_COMPONENT_NAME2_PROTOCOL          *This,
+  IN  CHAR8                                *Language,
+  OUT CHAR16                               **DriverName
+  );
+
+
+/**
+  Retrieves a string that is the user readable name of
+  the controller that is being managed by an EFI Driver.
+
+  @param  This             A pointer to the
+                           EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+  @param  ControllerHandle The handle of a controller that the
+                           driver specified by This is managing.
+                           This handle specifies the controller
+                           whose name is to be returned.
+
+  @param  ChildHandle      The handle of the child controller to
+                           retrieve the name of.  This is an
+                           optional parameter that may be NULL.
+                           It will be NULL for device drivers.
+                           It will also be NULL for bus
+                           drivers that wish to retrieve the
+                           name of the bus controller.  It will
+                           not be NULL for a bus driver that
+                           wishes to retrieve the name of a
+                           child controller.
+
+  @param  Language         A pointer to a Null-terminated ASCII
+                           string array indicating the language.
+                           This is the language of the driver
+                           name that the caller is requesting,
+                           and it must match one of the
+                           languages specified in
+                           SupportedLanguages. The number of
+                           languages supported by a driver is up
+                           to the driver writer. Language is
+                           specified in RFC 4646 language code
+                           format.
+
+  @param  ControllerName   A pointer to the string to return.
+                           This string is the name of the controller
+                           specified by ControllerHandle and ChildHandle
+                           in the language specified by Language
+                           from the point of view of the driver
+                           specified by This.
+
+  @retval EFI_SUCCESS           The string for the user
+                                readable name in the language
+                                specified by Language for the
+                                driver specified by This was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it
+                                is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is
+                                not currently managing the
+                                controller specified by
+                                ControllerHandle and
+                                ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This
+                                does not support the language
+                                specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(
+  IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  EFI_HANDLE                  ChildHandle        OPTIONAL,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  );
+
+///
+/// This protocol is used to retrieve user readable names of drivers
+/// and controllers managed by UEFI Drivers.
+///
+struct _EFI_COMPONENT_NAME2_PROTOCOL {
+  EFI_COMPONENT_NAME2_GET_DRIVER_NAME      GetDriverName;
+  EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME  GetControllerName;
+
+  ///
+  /// A Null-terminated ASCII string array that contains one or more
+  /// supported language codes. This is the list of language codes that
+  /// this protocol supports. The number of languages supported by a
+  /// driver is up to the driver writer. SupportedLanguages is
+  /// specified in RFC 4646 format.
+  ///
+  CHAR8                                    *SupportedLanguages;
+};
+
+extern EFI_GUID gEfiComponentName2ProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h
new file mode 100644
index 0000000..ebcaf5f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h
@@ -0,0 +1,300 @@
+/** @file
+  CPU Architectural Protocol as defined in PI spec Volume 2 DXE
+
+  This code abstracts the DXE core from processor implementation details.
+
+  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __ARCH_PROTOCOL_CPU_H__
+#define __ARCH_PROTOCOL_CPU_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Protocol/DebugSupport.h>
+
+#define EFI_CPU_ARCH_PROTOCOL_GUID \
+  { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }
+
+typedef struct _EFI_CPU_ARCH_PROTOCOL   EFI_CPU_ARCH_PROTOCOL;
+
+///
+/// The type of flush operation
+///
+typedef enum {
+  EfiCpuFlushTypeWriteBackInvalidate,
+  EfiCpuFlushTypeWriteBack,
+  EfiCpuFlushTypeInvalidate,
+  EfiCpuMaxFlushType
+} EFI_CPU_FLUSH_TYPE;
+
+///
+/// The type of processor INIT.
+///
+typedef enum {
+  EfiCpuInit,
+  EfiCpuMaxInitType
+} EFI_CPU_INIT_TYPE;
+
+/**
+  EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+  @param  InterruptType    Defines the type of interrupt or exception that
+                           occurred on the processor.This parameter is processor architecture specific.
+  @param  SystemContext    A pointer to the processor context when
+                           the interrupt occurred on the processor.
+
+  @return None
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)(
+  IN CONST  EFI_EXCEPTION_TYPE  InterruptType,
+  IN CONST  EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+/**
+  This function flushes the range of addresses from Start to Start+Length
+  from the processor's data cache. If Start is not aligned to a cache line
+  boundary, then the bytes before Start to the preceding cache line boundary
+  are also flushed. If Start+Length is not aligned to a cache line boundary,
+  then the bytes past Start+Length to the end of the next cache line boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+  supported. If the data cache is fully coherent with all DMA operations, then
+  this function can just return EFI_SUCCESS. If the processor does not support
+  flushing a range of the data cache, then the entire data cache can be flushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from the processor's data
+                           cache.
+  @param  Length           The number of bytes to flush from the processor's data cache. This
+                           function may flush more bytes than Length specifies depending upon
+                           the granularity of the flush operation that the processor supports.
+  @param  FlushType        Specifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
+                                the processor's data cache.
+  @retval EFI_UNSUPPORTEDT      The processor does not support the cache flush type specified
+                                by FlushType.
+  @retval EFI_DEVICE_ERROR      The address range from Start to Start+Length could not be flushed
+                                from the processor's data cache.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  IN EFI_PHYSICAL_ADDRESS               Start,
+  IN UINT64                             Length,
+  IN EFI_CPU_FLUSH_TYPE                 FlushType
+  );
+
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This
+  );
+
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This
+  );
+
+
+/**
+  This function retrieves the processor's current interrupt state a returns it in
+  State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
+                           interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  OUT BOOLEAN                           *State
+  );
+
+
+/**
+  This function generates an INIT on the processor. If this function succeeds, then the
+  processor will be reset, and control will not be returned to the caller. If InitType is
+  not supported by this processor, or the processor cannot programmatically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType         The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
+  @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
+                                by this processor.
+  @retval EFI_DEVICE_ERROR      The processor INIT failed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_INIT)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  IN EFI_CPU_INIT_TYPE                  InitType
+  );
+
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  IN EFI_EXCEPTION_TYPE                 InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler
+  );
+
+
+/**
+  This function reads the processor timer specified by TimerIndex and returns it in TimerValue.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  TimerIndex       Specifies which processor timer is to be returned in TimerValue. This parameter
+                           must be between 0 and NumberOfTimers-1.
+  @param  TimerValue       Pointer to the returned timer value.
+  @param  TimerPeriod      A pointer to the amount of time that passes in femtoseconds for each increment
+                           of TimerValue. If TimerValue does not increment at a predictable rate, then 0 is
+                           returned. This parameter is optional and may be NULL.
+
+  @retval EFI_SUCCESS           The processor timer value specified by TimerIndex was returned in TimerValue.
+  @retval EFI_DEVICE_ERROR      An error occurred attempting to read one of the processor's timers.
+  @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid.
+  @retval EFI_UNSUPPORTED       The processor does not have any readable timers.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_TIMER_VALUE)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  IN UINT32                             TimerIndex,
+  OUT UINT64                            *TimerValue,
+  OUT UINT64                            *TimerPeriod OPTIONAL
+  );
+
+
+/**
+  This function modifies the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  Attributes       The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This,
+  IN  EFI_PHYSICAL_ADDRESS              BaseAddress,
+  IN  UINT64                            Length,
+  IN  UINT64                            Attributes
+  );
+
+
+///
+/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
+/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
+/// vectors and exception vectors, reading internal processor timers, resetting the processor, and
+/// determining the processor frequency.
+///
+struct _EFI_CPU_ARCH_PROTOCOL {
+  EFI_CPU_FLUSH_DATA_CACHE            FlushDataCache;
+  EFI_CPU_ENABLE_INTERRUPT            EnableInterrupt;
+  EFI_CPU_DISABLE_INTERRUPT           DisableInterrupt;
+  EFI_CPU_GET_INTERRUPT_STATE         GetInterruptState;
+  EFI_CPU_INIT                        Init;
+  EFI_CPU_REGISTER_INTERRUPT_HANDLER  RegisterInterruptHandler;
+  EFI_CPU_GET_TIMER_VALUE             GetTimerValue;
+  EFI_CPU_SET_MEMORY_ATTRIBUTES       SetMemoryAttributes;
+  ///
+  /// The number of timers that are available in a processor. The value in this
+  /// field is a constant that must not be modified after the CPU Architectural
+  /// Protocol is installed. All consumers must treat this as a read-only field.
+  ///
+  UINT32                              NumberOfTimers;
+  ///
+  /// The size, in bytes, of the alignment required for DMA buffer allocations.
+  /// This is typically the size of the largest data cache line in the platform.
+  /// The value in this field is a constant that must not be modified after the
+  /// CPU Architectural Protocol is installed. All consumers must treat this as
+  /// a read-only field.
+  ///
+  UINT32                              DmaBufferAlignment;
+};
+
+extern EFI_GUID gEfiCpuArchProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h
new file mode 100644
index 0000000..39b82b3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h
@@ -0,0 +1,48 @@
+/** @file
+  This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific
+  PEIM that abstracts the processor-visible I/O operations.
+
+  Note: This is a runtime protocol and can be used by runtime drivers after ExitBootServices().
+  It is different from the PI 1.2 CPU I/O 2 Protocol, which is a boot services only protocol
+  and may not be used by runtime drivers after ExitBootServices().
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec
+  Version 0.9.
+
+**/
+
+#ifndef _CPUIO_H_
+#define _CPUIO_H_
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Protocol/CpuIo2.h>
+
+#define EFI_CPU_IO_PROTOCOL_GUID \
+  { \
+    0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \
+  }
+
+//
+// Framework CPU IO protocol structure is the same as CPU IO 2 protocol defined in PI 1.2 spec.
+// However, there is a significant different between the Framework CPU I/O
+// Protocol and the PI 1.2 CPU I/O 2 Protocol.  The Framework one is a runtime
+// protocol, which means it can be used by runtime drivers after ExitBootServices().
+// The PI one is not runtime safe, so it is a boot services only protocol and may
+// not be used by runtime drivers after ExitBootServices().
+//
+typedef EFI_CPU_IO2_PROTOCOL EFI_CPU_IO_PROTOCOL;
+
+extern EFI_GUID gEfiCpuIoProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h
new file mode 100644
index 0000000..aef8157
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h
@@ -0,0 +1,144 @@
+/** @file
+  This files describes the CPU I/O 2 Protocol.
+
+  This protocol provides an I/O abstraction for a system processor. This protocol
+  is used by a PCI root bridge I/O driver to perform memory-mapped I/O and I/O transactions.
+  The I/O or memory primitives can be used by the consumer of the protocol to materialize
+  bus-specific configuration cycles, such as the transitional configuration address and data
+  ports for PCI. Only drivers that require direct access to the entire system should use this
+  protocol.
+
+  Note: This is a boot-services only protocol and it may not be used by runtime drivers after
+  ExitBootServices(). It is different from the Framework CPU I/O Protocol, which is a runtime
+  protocol and can be used by runtime drivers after ExitBootServices().
+
+  Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  This Protocol is defined in UEFI Platform Initialization Specification 1.2
+  Volume 5: Standards
+
+**/
+
+#ifndef __CPU_IO2_H__
+#define __CPU_IO2_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_CPU_IO2_PROTOCOL_GUID \
+  { \
+    0xad61f191, 0xae5f, 0x4c0e, {0xb9, 0xfa, 0xe8, 0x69, 0xd2, 0x88, 0xc6, 0x4f} \
+  }
+
+typedef struct _EFI_CPU_IO2_PROTOCOL EFI_CPU_IO2_PROTOCOL;
+
+///
+/// Enumeration that defines the width of the I/O operation.
+///
+typedef enum {
+  EfiCpuIoWidthUint8,
+  EfiCpuIoWidthUint16,
+  EfiCpuIoWidthUint32,
+  EfiCpuIoWidthUint64,
+  EfiCpuIoWidthFifoUint8,
+  EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32,
+  EfiCpuIoWidthFifoUint64,
+  EfiCpuIoWidthFillUint8,
+  EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32,
+  EfiCpuIoWidthFillUint64,
+  EfiCpuIoWidthMaximum
+} EFI_CPU_IO_PROTOCOL_WIDTH;
+
+/**
+  Enables a driver to access registers in the PI CPU I/O space.
+
+  The Io.Read() and Io.Write() functions enable a driver to access PCI controller
+  registers in the PI CPU I/O space.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]       This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]       Width    Signifies the width of the I/O or Memory operation.
+  @param[in]       Address  The base address of the I/O operation.
+  @param[in]       Count    The number of I/O operations to perform. The number
+                            of bytes moved is Width size * Count, starting at Address.
+  @param[in, out]  Buffer   For read operations, the destination buffer to store the results.
+                            For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)(
+  IN     EFI_CPU_IO2_PROTOCOL              *This,
+  IN     EFI_CPU_IO_PROTOCOL_WIDTH         Width,
+  IN     UINT64                            Address,
+  IN     UINTN                             Count,
+  IN OUT VOID                              *Buffer
+  );
+
+///
+/// Service for read and write accesses.
+///
+typedef struct {
+  ///
+  /// This service provides the various modalities of memory and I/O read.
+  ///
+  EFI_CPU_IO_PROTOCOL_IO_MEM  Read;
+  ///
+  /// This service provides the various modalities of memory and I/O write.
+  ///
+  EFI_CPU_IO_PROTOCOL_IO_MEM  Write;
+} EFI_CPU_IO_PROTOCOL_ACCESS;
+
+///
+/// Provides the basic memory and I/O interfaces that are used to abstract
+/// accesses to devices in a system.
+///
+struct _EFI_CPU_IO2_PROTOCOL {
+  ///
+  /// Enables a driver to access memory-mapped registers in the EFI system memory space.
+  ///
+  EFI_CPU_IO_PROTOCOL_ACCESS  Mem;
+  ///
+  /// Enables a driver to access registers in the EFI CPU I/O space.
+  ///
+  EFI_CPU_IO_PROTOCOL_ACCESS  Io;
+};
+
+extern EFI_GUID gEfiCpuIo2ProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h
new file mode 100644
index 0000000..ea5cec5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h
@@ -0,0 +1,685 @@
+/** @file
+  DebugSupport protocol and supporting definitions as defined in the UEFI2.0
+  specification.
+
+  The DebugSupport protocol is used by source level debuggers to abstract the
+  processor and handle context save and restore operations.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEBUG_SUPPORT_H__
+#define __DEBUG_SUPPORT_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/IndustryStandard/PeImage.h>
+
+typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL;
+
+///
+/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25}.
+///
+#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \
+  { \
+    0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \
+  }
+
+///
+/// Processor exception to be hooked.
+/// All exception types for IA32, X64, Itanium and EBC processors are defined.
+///
+typedef INTN  EFI_EXCEPTION_TYPE;
+
+///
+///  IA-32 processor exception types.
+///
+#define EXCEPT_IA32_DIVIDE_ERROR    0
+#define EXCEPT_IA32_DEBUG           1
+#define EXCEPT_IA32_NMI             2
+#define EXCEPT_IA32_BREAKPOINT      3
+#define EXCEPT_IA32_OVERFLOW        4
+#define EXCEPT_IA32_BOUND           5
+#define EXCEPT_IA32_INVALID_OPCODE  6
+#define EXCEPT_IA32_DOUBLE_FAULT    8
+#define EXCEPT_IA32_INVALID_TSS     10
+#define EXCEPT_IA32_SEG_NOT_PRESENT 11
+#define EXCEPT_IA32_STACK_FAULT     12
+#define EXCEPT_IA32_GP_FAULT        13
+#define EXCEPT_IA32_PAGE_FAULT      14
+#define EXCEPT_IA32_FP_ERROR        16
+#define EXCEPT_IA32_ALIGNMENT_CHECK 17
+#define EXCEPT_IA32_MACHINE_CHECK   18
+#define EXCEPT_IA32_SIMD            19
+
+///
+/// FXSAVE_STATE.
+/// FP / MMX / XMM registers (see fxrstor instruction definition).
+///
+typedef struct {
+  UINT16  Fcw;
+  UINT16  Fsw;
+  UINT16  Ftw;
+  UINT16  Opcode;
+  UINT32  Eip;
+  UINT16  Cs;
+  UINT16  Reserved1;
+  UINT32  DataOffset;
+  UINT16  Ds;
+  UINT8   Reserved2[10];
+  UINT8   St0Mm0[10], Reserved3[6];
+  UINT8   St1Mm1[10], Reserved4[6];
+  UINT8   St2Mm2[10], Reserved5[6];
+  UINT8   St3Mm3[10], Reserved6[6];
+  UINT8   St4Mm4[10], Reserved7[6];
+  UINT8   St5Mm5[10], Reserved8[6];
+  UINT8   St6Mm6[10], Reserved9[6];
+  UINT8   St7Mm7[10], Reserved10[6];
+  UINT8   Xmm0[16];
+  UINT8   Xmm1[16];
+  UINT8   Xmm2[16];
+  UINT8   Xmm3[16];
+  UINT8   Xmm4[16];
+  UINT8   Xmm5[16];
+  UINT8   Xmm6[16];
+  UINT8   Xmm7[16];
+  UINT8   Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_IA32;
+
+///
+///  IA-32 processor context definition.
+///
+typedef struct {
+  UINT32                 ExceptionData;
+  EFI_FX_SAVE_STATE_IA32 FxSaveState;
+  UINT32                 Dr0;
+  UINT32                 Dr1;
+  UINT32                 Dr2;
+  UINT32                 Dr3;
+  UINT32                 Dr6;
+  UINT32                 Dr7;
+  UINT32                 Cr0;
+  UINT32                 Cr1;  /* Reserved */
+  UINT32                 Cr2;
+  UINT32                 Cr3;
+  UINT32                 Cr4;
+  UINT32                 Eflags;
+  UINT32                 Ldtr;
+  UINT32                 Tr;
+  UINT32                 Gdtr[2];
+  UINT32                 Idtr[2];
+  UINT32                 Eip;
+  UINT32                 Gs;
+  UINT32                 Fs;
+  UINT32                 Es;
+  UINT32                 Ds;
+  UINT32                 Cs;
+  UINT32                 Ss;
+  UINT32                 Edi;
+  UINT32                 Esi;
+  UINT32                 Ebp;
+  UINT32                 Esp;
+  UINT32                 Ebx;
+  UINT32                 Edx;
+  UINT32                 Ecx;
+  UINT32                 Eax;
+} EFI_SYSTEM_CONTEXT_IA32;
+
+///
+///  x64 processor exception types.
+///
+#define EXCEPT_X64_DIVIDE_ERROR    0
+#define EXCEPT_X64_DEBUG           1
+#define EXCEPT_X64_NMI             2
+#define EXCEPT_X64_BREAKPOINT      3
+#define EXCEPT_X64_OVERFLOW        4
+#define EXCEPT_X64_BOUND           5
+#define EXCEPT_X64_INVALID_OPCODE  6
+#define EXCEPT_X64_DOUBLE_FAULT    8
+#define EXCEPT_X64_INVALID_TSS     10
+#define EXCEPT_X64_SEG_NOT_PRESENT 11
+#define EXCEPT_X64_STACK_FAULT     12
+#define EXCEPT_X64_GP_FAULT        13
+#define EXCEPT_X64_PAGE_FAULT      14
+#define EXCEPT_X64_FP_ERROR        16
+#define EXCEPT_X64_ALIGNMENT_CHECK 17
+#define EXCEPT_X64_MACHINE_CHECK   18
+#define EXCEPT_X64_SIMD            19
+
+///
+/// FXSAVE_STATE.
+/// FP / MMX / XMM registers (see fxrstor instruction definition).
+///
+typedef struct {
+  UINT16  Fcw;
+  UINT16  Fsw;
+  UINT16  Ftw;
+  UINT16  Opcode;
+  UINT64  Rip;
+  UINT64  DataOffset;
+  UINT8   Reserved1[8];
+  UINT8   St0Mm0[10], Reserved2[6];
+  UINT8   St1Mm1[10], Reserved3[6];
+  UINT8   St2Mm2[10], Reserved4[6];
+  UINT8   St3Mm3[10], Reserved5[6];
+  UINT8   St4Mm4[10], Reserved6[6];
+  UINT8   St5Mm5[10], Reserved7[6];
+  UINT8   St6Mm6[10], Reserved8[6];
+  UINT8   St7Mm7[10], Reserved9[6];
+  UINT8   Xmm0[16];
+  UINT8   Xmm1[16];
+  UINT8   Xmm2[16];
+  UINT8   Xmm3[16];
+  UINT8   Xmm4[16];
+  UINT8   Xmm5[16];
+  UINT8   Xmm6[16];
+  UINT8   Xmm7[16];
+  //
+  // NOTE: UEFI 2.0 spec definition as follows.
+  //
+  UINT8   Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_X64;
+
+///
+///  x64 processor context definition.
+///
+typedef struct {
+  UINT64                ExceptionData;
+  EFI_FX_SAVE_STATE_X64 FxSaveState;
+  UINT64                Dr0;
+  UINT64                Dr1;
+  UINT64                Dr2;
+  UINT64                Dr3;
+  UINT64                Dr6;
+  UINT64                Dr7;
+  UINT64                Cr0;
+  UINT64                Cr1;  /* Reserved */
+  UINT64                Cr2;
+  UINT64                Cr3;
+  UINT64                Cr4;
+  UINT64                Cr8;
+  UINT64                Rflags;
+  UINT64                Ldtr;
+  UINT64                Tr;
+  UINT64                Gdtr[2];
+  UINT64                Idtr[2];
+  UINT64                Rip;
+  UINT64                Gs;
+  UINT64                Fs;
+  UINT64                Es;
+  UINT64                Ds;
+  UINT64                Cs;
+  UINT64                Ss;
+  UINT64                Rdi;
+  UINT64                Rsi;
+  UINT64                Rbp;
+  UINT64                Rsp;
+  UINT64                Rbx;
+  UINT64                Rdx;
+  UINT64                Rcx;
+  UINT64                Rax;
+  UINT64                R8;
+  UINT64                R9;
+  UINT64                R10;
+  UINT64                R11;
+  UINT64                R12;
+  UINT64                R13;
+  UINT64                R14;
+  UINT64                R15;
+} EFI_SYSTEM_CONTEXT_X64;
+
+///
+///  Itanium Processor Family Exception types.
+///
+#define EXCEPT_IPF_VHTP_TRANSLATION       0
+#define EXCEPT_IPF_INSTRUCTION_TLB        1
+#define EXCEPT_IPF_DATA_TLB               2
+#define EXCEPT_IPF_ALT_INSTRUCTION_TLB    3
+#define EXCEPT_IPF_ALT_DATA_TLB           4
+#define EXCEPT_IPF_DATA_NESTED_TLB        5
+#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6
+#define EXCEPT_IPF_DATA_KEY_MISSED        7
+#define EXCEPT_IPF_DIRTY_BIT              8
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9
+#define EXCEPT_IPF_DATA_ACCESS_BIT        10
+#define EXCEPT_IPF_BREAKPOINT             11
+#define EXCEPT_IPF_EXTERNAL_INTERRUPT     12
+//
+// 13 - 19 reserved
+//
+#define EXCEPT_IPF_PAGE_NOT_PRESENT           20
+#define EXCEPT_IPF_KEY_PERMISSION             21
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS  22
+#define EXCEPT_IPF_DATA_ACCESS_RIGHTS         23
+#define EXCEPT_IPF_GENERAL_EXCEPTION          24
+#define EXCEPT_IPF_DISABLED_FP_REGISTER       25
+#define EXCEPT_IPF_NAT_CONSUMPTION            26
+#define EXCEPT_IPF_SPECULATION                27
+//
+// 28 reserved
+//
+#define EXCEPT_IPF_DEBUG                          29
+#define EXCEPT_IPF_UNALIGNED_REFERENCE            30
+#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE     31
+#define EXCEPT_IPF_FP_FAULT                       32
+#define EXCEPT_IPF_FP_TRAP                        33
+#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP  34
+#define EXCEPT_IPF_TAKEN_BRANCH                   35
+#define EXCEPT_IPF_SINGLE_STEP                    36
+//
+// 37 - 44 reserved
+//
+#define EXCEPT_IPF_IA32_EXCEPTION 45
+#define EXCEPT_IPF_IA32_INTERCEPT 46
+#define EXCEPT_IPF_IA32_INTERRUPT 47
+
+///
+///  IPF processor context definition.
+///
+typedef struct {
+  //
+  // The first reserved field is necessary to preserve alignment for the correct
+  // bits in UNAT and to insure F2 is 16 byte aligned.
+  //
+  UINT64  Reserved;
+  UINT64  R1;
+  UINT64  R2;
+  UINT64  R3;
+  UINT64  R4;
+  UINT64  R5;
+  UINT64  R6;
+  UINT64  R7;
+  UINT64  R8;
+  UINT64  R9;
+  UINT64  R10;
+  UINT64  R11;
+  UINT64  R12;
+  UINT64  R13;
+  UINT64  R14;
+  UINT64  R15;
+  UINT64  R16;
+  UINT64  R17;
+  UINT64  R18;
+  UINT64  R19;
+  UINT64  R20;
+  UINT64  R21;
+  UINT64  R22;
+  UINT64  R23;
+  UINT64  R24;
+  UINT64  R25;
+  UINT64  R26;
+  UINT64  R27;
+  UINT64  R28;
+  UINT64  R29;
+  UINT64  R30;
+  UINT64  R31;
+
+  UINT64  F2[2];
+  UINT64  F3[2];
+  UINT64  F4[2];
+  UINT64  F5[2];
+  UINT64  F6[2];
+  UINT64  F7[2];
+  UINT64  F8[2];
+  UINT64  F9[2];
+  UINT64  F10[2];
+  UINT64  F11[2];
+  UINT64  F12[2];
+  UINT64  F13[2];
+  UINT64  F14[2];
+  UINT64  F15[2];
+  UINT64  F16[2];
+  UINT64  F17[2];
+  UINT64  F18[2];
+  UINT64  F19[2];
+  UINT64  F20[2];
+  UINT64  F21[2];
+  UINT64  F22[2];
+  UINT64  F23[2];
+  UINT64  F24[2];
+  UINT64  F25[2];
+  UINT64  F26[2];
+  UINT64  F27[2];
+  UINT64  F28[2];
+  UINT64  F29[2];
+  UINT64  F30[2];
+  UINT64  F31[2];
+
+  UINT64  Pr;
+
+  UINT64  B0;
+  UINT64  B1;
+  UINT64  B2;
+  UINT64  B3;
+  UINT64  B4;
+  UINT64  B5;
+  UINT64  B6;
+  UINT64  B7;
+
+  //
+  // application registers
+  //
+  UINT64  ArRsc;
+  UINT64  ArBsp;
+  UINT64  ArBspstore;
+  UINT64  ArRnat;
+
+  UINT64  ArFcr;
+
+  UINT64  ArEflag;
+  UINT64  ArCsd;
+  UINT64  ArSsd;
+  UINT64  ArCflg;
+  UINT64  ArFsr;
+  UINT64  ArFir;
+  UINT64  ArFdr;
+
+  UINT64  ArCcv;
+
+  UINT64  ArUnat;
+
+  UINT64  ArFpsr;
+
+  UINT64  ArPfs;
+  UINT64  ArLc;
+  UINT64  ArEc;
+
+  //
+  // control registers
+  //
+  UINT64  CrDcr;
+  UINT64  CrItm;
+  UINT64  CrIva;
+  UINT64  CrPta;
+  UINT64  CrIpsr;
+  UINT64  CrIsr;
+  UINT64  CrIip;
+  UINT64  CrIfa;
+  UINT64  CrItir;
+  UINT64  CrIipa;
+  UINT64  CrIfs;
+  UINT64  CrIim;
+  UINT64  CrIha;
+
+  //
+  // debug registers
+  //
+  UINT64  Dbr0;
+  UINT64  Dbr1;
+  UINT64  Dbr2;
+  UINT64  Dbr3;
+  UINT64  Dbr4;
+  UINT64  Dbr5;
+  UINT64  Dbr6;
+  UINT64  Dbr7;
+
+  UINT64  Ibr0;
+  UINT64  Ibr1;
+  UINT64  Ibr2;
+  UINT64  Ibr3;
+  UINT64  Ibr4;
+  UINT64  Ibr5;
+  UINT64  Ibr6;
+  UINT64  Ibr7;
+
+  //
+  // virtual registers - nat bits for R1-R31
+  //
+  UINT64  IntNat;
+
+} EFI_SYSTEM_CONTEXT_IPF;
+
+///
+///  EBC processor exception types.
+///
+#define EXCEPT_EBC_UNDEFINED            0
+#define EXCEPT_EBC_DIVIDE_ERROR         1
+#define EXCEPT_EBC_DEBUG                2
+#define EXCEPT_EBC_BREAKPOINT           3
+#define EXCEPT_EBC_OVERFLOW             4
+#define EXCEPT_EBC_INVALID_OPCODE       5   ///< Opcode out of range.
+#define EXCEPT_EBC_STACK_FAULT          6
+#define EXCEPT_EBC_ALIGNMENT_CHECK      7
+#define EXCEPT_EBC_INSTRUCTION_ENCODING 8   ///< Malformed instruction.
+#define EXCEPT_EBC_BAD_BREAK            9   ///< BREAK 0 or undefined BREAK.
+#define EXCEPT_EBC_STEP                 10  ///< To support debug stepping.
+///
+/// For coding convenience, define the maximum valid EBC exception.
+///
+#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP
+
+///
+///  EBC processor context definition.
+///
+typedef struct {
+  UINT64  R0;
+  UINT64  R1;
+  UINT64  R2;
+  UINT64  R3;
+  UINT64  R4;
+  UINT64  R5;
+  UINT64  R6;
+  UINT64  R7;
+  UINT64  Flags;
+  UINT64  ControlFlags;
+  UINT64  Ip;
+} EFI_SYSTEM_CONTEXT_EBC;
+
+
+
+///
+///  ARM processor exception types.
+///
+#define EXCEPT_ARM_RESET                    0
+#define EXCEPT_ARM_UNDEFINED_INSTRUCTION    1
+#define EXCEPT_ARM_SOFTWARE_INTERRUPT       2
+#define EXCEPT_ARM_PREFETCH_ABORT           3
+#define EXCEPT_ARM_DATA_ABORT               4
+#define EXCEPT_ARM_RESERVED                 5
+#define EXCEPT_ARM_IRQ                      6
+#define EXCEPT_ARM_FIQ                      7
+
+///
+/// For coding convenience, define the maximum valid ARM exception.
+///
+#define MAX_ARM_EXCEPTION EXCEPT_ARM_FIQ
+
+///
+///  ARM processor context definition.
+///
+typedef struct {
+  UINT32  R0;
+  UINT32  R1;
+  UINT32  R2;
+  UINT32  R3;
+  UINT32  R4;
+  UINT32  R5;
+  UINT32  R6;
+  UINT32  R7;
+  UINT32  R8;
+  UINT32  R9;
+  UINT32  R10;
+  UINT32  R11;
+  UINT32  R12;
+  UINT32  SP;
+  UINT32  LR;
+  UINT32  PC;
+  UINT32  CPSR;
+  UINT32  DFSR;
+  UINT32  DFAR;
+  UINT32  IFSR;
+  UINT32  IFAR;
+} EFI_SYSTEM_CONTEXT_ARM;
+
+///
+/// Universal EFI_SYSTEM_CONTEXT definition.
+///
+typedef union {
+  EFI_SYSTEM_CONTEXT_EBC  *SystemContextEbc;
+  EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32;
+  EFI_SYSTEM_CONTEXT_X64  *SystemContextX64;
+  EFI_SYSTEM_CONTEXT_IPF  *SystemContextIpf;
+  EFI_SYSTEM_CONTEXT_ARM  *SystemContextArm;
+} EFI_SYSTEM_CONTEXT;
+
+//
+// DebugSupport callback function prototypes
+//
+
+/**
+  Registers and enables an exception callback function for the specified exception.
+
+  @param  ExceptionType         Exception types in EBC, IA-32, x64, or IPF.
+  @param  SystemContext         Exception content.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_EXCEPTION_CALLBACK)(
+  IN     EFI_EXCEPTION_TYPE               ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT               SystemContext
+  );
+
+/**
+  Registers and enables the on-target debug agent's periodic entry point.
+
+  @param  SystemContext         Exception content.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_PERIODIC_CALLBACK)(
+  IN OUT EFI_SYSTEM_CONTEXT               SystemContext
+  );
+
+///
+/// Machine type definition
+///
+typedef enum {
+  IsaIa32 = IMAGE_FILE_MACHINE_I386,           ///< 0x014C
+  IsaX64  = IMAGE_FILE_MACHINE_X64,            ///< 0x8664
+  IsaIpf  = IMAGE_FILE_MACHINE_IA64,           ///< 0x0200
+  IsaEbc  = IMAGE_FILE_MACHINE_EBC,            ///< 0x0EBC
+  IsaArm  = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED  ///< 0x01c2
+} EFI_INSTRUCTION_SET_ARCHITECTURE;
+
+
+//
+// DebugSupport member function definitions
+//
+
+/**
+  Returns the maximum value that may be used for the ProcessorIndex parameter in
+  RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+  @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+  @param  MaxProcessorIndex     Pointer to a caller-allocated UINTN in which the maximum supported
+                                processor index is returned.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)(
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
+  OUT UINTN                              *MaxProcessorIndex
+  );
+
+/**
+  Registers a function to be called back periodically in interrupt context.
+
+  @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+  @param  ProcessorIndex        Specifies which processor the callback function applies to.
+  @param  PeriodicCallback      A pointer to a function of type PERIODIC_CALLBACK that is the main
+                                periodic entry point of the debug agent.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+  @retval EFI_ALREADY_STARTED   Non-NULL PeriodicCallback parameter when a callback
+                                function was previously registered.
+  @retval EFI_OUT_OF_RESOURCES  System has insufficient memory resources to register new callback
+                                function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)(
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
+  IN UINTN                               ProcessorIndex,
+  IN EFI_PERIODIC_CALLBACK               PeriodicCallback
+  );
+
+/**
+  Registers a function to be called when a given processor exception occurs.
+
+  @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+  @param  ProcessorIndex        Specifies which processor the callback function applies to.
+  @param  ExceptionCallback     A pointer to a function of type EXCEPTION_CALLBACK that is called
+                                when the processor exception specified by ExceptionType occurs.
+  @param  ExceptionType         Specifies which processor exception to hook.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+  @retval EFI_ALREADY_STARTED   Non-NULL PeriodicCallback parameter when a callback
+                                function was previously registered.
+  @retval EFI_OUT_OF_RESOURCES  System has insufficient memory resources to register new callback
+                                function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)(
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
+  IN UINTN                               ProcessorIndex,
+  IN EFI_EXCEPTION_CALLBACK              ExceptionCallback,
+  IN EFI_EXCEPTION_TYPE                  ExceptionType
+  );
+
+/**
+  Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+  causes a fresh memory fetch to retrieve code to be executed.
+
+  @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+  @param  ProcessorIndex        Specifies which processor's instruction cache is to be invalidated.
+  @param  Start                 Specifies the physical base of the memory range to be invalidated.
+  @param  Length                Specifies the minimum number of bytes in the processor's instruction
+                                cache to invalidate.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)(
+  IN EFI_DEBUG_SUPPORT_PROTOCOL          *This,
+  IN UINTN                               ProcessorIndex,
+  IN VOID                                *Start,
+  IN UINT64                              Length
+  );
+
+///
+/// This protocol provides the services to allow the debug agent to register
+/// callback functions that are called either periodically or when specific
+/// processor exceptions occur.
+///
+struct _EFI_DEBUG_SUPPORT_PROTOCOL {
+  ///
+  /// Declares the processor architecture for this instance of the EFI Debug Support protocol.
+  ///
+  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa;
+  EFI_GET_MAXIMUM_PROCESSOR_INDEX   GetMaximumProcessorIndex;
+  EFI_REGISTER_PERIODIC_CALLBACK    RegisterPeriodicCallback;
+  EFI_REGISTER_EXCEPTION_CALLBACK   RegisterExceptionCallback;
+  EFI_INVALIDATE_INSTRUCTION_CACHE  InvalidateInstructionCache;
+};
+
+extern EFI_GUID gEfiDebugSupportProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h
new file mode 100644
index 0000000..5c67870
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h
@@ -0,0 +1,1074 @@
+/** @file
+  The device path protocol as defined in UEFI 2.0.
+
+  The device path represents a programmatic path to a device,
+  from a software point of view. The path must persist from boot to boot, so
+  it can not contain things like PCI bus numbers that change from boot to boot.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DEVICE_PATH_PROTOCOL_H__
+#define __EFI_DEVICE_PATH_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Guid/PcAnsi.h>
+
+///
+/// Device Path protocol.
+///
+#define EFI_DEVICE_PATH_PROTOCOL_GUID \
+  { \
+    0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+///
+/// Device Path guid definition for backward-compatible with EFI1.1.
+///
+#define DEVICE_PATH_PROTOCOL  EFI_DEVICE_PATH_PROTOCOL_GUID
+
+#pragma pack(1)
+
+/**
+  This protocol can be used on any device handle to obtain generic path/location
+  information concerning the physical device or logical device. If the handle does
+  not logically map to a physical device, the handle may not necessarily support
+  the device path protocol. The device path describes the location of the device
+  the handle is for. The size of the Device Path can be determined from the structures
+  that make up the Device Path.
+**/
+typedef struct {
+  UINT8 Type;       ///< 0x01 Hardware Device Path.
+                    ///< 0x02 ACPI Device Path.
+                    ///< 0x03 Messaging Device Path.
+                    ///< 0x04 Media Device Path.
+                    ///< 0x05 BIOS Boot Specification Device Path.
+                    ///< 0x7F End of Hardware Device Path.
+
+  UINT8 SubType;    ///< Varies by Type
+                    ///< 0xFF End Entire Device Path, or
+                    ///< 0x01 End This Instance of a Device Path and start a new
+                    ///< Device Path.
+
+  UINT8 Length[2];  ///< Specific Device Path data. Type and Sub-Type define
+                    ///< type of data. Size of data is included in Length.
+
+} EFI_DEVICE_PATH_PROTOCOL;
+
+///
+/// Device Path protocol definition for backward-compatible with EFI1.1.
+///
+typedef EFI_DEVICE_PATH_PROTOCOL  EFI_DEVICE_PATH;
+
+///
+/// Hardware Device Paths.
+///
+#define HARDWARE_DEVICE_PATH      0x01
+
+///
+/// PCI Device Path SubType.
+///
+#define HW_PCI_DP                 0x01
+
+///
+/// PCI Device Path.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// PCI Function Number.
+  ///
+  UINT8                           Function;
+  ///
+  /// PCI Device Number.
+  ///
+  UINT8                           Device;
+} PCI_DEVICE_PATH;
+
+///
+/// PCCARD Device Path SubType.
+///
+#define HW_PCCARD_DP              0x02
+
+///
+/// PCCARD Device Path.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Function Number (0 = First Function).
+  ///
+  UINT8                           FunctionNumber;
+} PCCARD_DEVICE_PATH;
+
+///
+/// Memory Mapped Device Path SubType.
+///
+#define HW_MEMMAP_DP              0x03
+
+///
+/// Memory Mapped Device Path.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// EFI_MEMORY_TYPE
+  ///
+  UINT32                          MemoryType;
+  ///
+  /// Starting Memory Address.
+  ///
+  EFI_PHYSICAL_ADDRESS            StartingAddress;
+  ///
+  /// Ending Memory Address.
+  ///
+  EFI_PHYSICAL_ADDRESS            EndingAddress;
+} MEMMAP_DEVICE_PATH;
+
+///
+/// Hardware Vendor Device Path SubType.
+///
+#define HW_VENDOR_DP              0x04
+
+///
+/// The Vendor Device Path allows the creation of vendor-defined Device Paths. A vendor must
+/// allocate a Vendor GUID for a Device Path. The Vendor GUID can then be used to define the
+/// contents on the n bytes that follow in the Vendor Device Path node.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Vendor-assigned GUID that defines the data that follows.
+  ///
+  EFI_GUID                        Guid;
+  ///
+  /// Vendor-defined variable size data.
+  ///
+} VENDOR_DEVICE_PATH;
+
+///
+/// Controller Device Path SubType.
+///
+#define HW_CONTROLLER_DP          0x05
+
+///
+/// Controller Device Path.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Controller number.
+  ///
+  UINT32                          ControllerNumber;
+} CONTROLLER_DEVICE_PATH;
+
+///
+/// ACPI Device Paths.
+///
+#define ACPI_DEVICE_PATH          0x02
+
+///
+/// ACPI Device Path SubType.
+///
+#define ACPI_DP                   0x01
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Device's PnP hardware ID stored in a numeric 32-bit
+  /// compressed EISA-type ID. This value must match the
+  /// corresponding _HID in the ACPI name space.
+  ///
+  UINT32                          HID;
+  ///
+  /// Unique ID that is required by ACPI if two devices have the
+  /// same _HID. This value must also match the corresponding
+  /// _UID/_HID pair in the ACPI name space. Only the 32-bit
+  /// numeric value type of _UID is supported. Thus, strings must
+  /// not be used for the _UID in the ACPI name space.
+  ///
+  UINT32                          UID;
+} ACPI_HID_DEVICE_PATH;
+
+///
+/// Expanded ACPI Device Path SubType.
+///
+#define ACPI_EXTENDED_DP          0x02
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Device's PnP hardware ID stored in a numeric 32-bit
+  /// compressed EISA-type ID. This value must match the
+  /// corresponding _HID in the ACPI name space.
+  ///
+  UINT32                          HID;
+  ///
+  /// Unique ID that is required by ACPI if two devices have the
+  /// same _HID. This value must also match the corresponding
+  /// _UID/_HID pair in the ACPI name space.
+  ///
+  UINT32                          UID;
+  ///
+  /// Device's compatible PnP hardware ID stored in a numeric
+  /// 32-bit compressed EISA-type ID. This value must match at
+  /// least one of the compatible device IDs returned by the
+  /// corresponding _CID in the ACPI name space.
+  ///
+  UINT32                          CID;
+  ///
+  /// Optional variable length _HIDSTR.
+  /// Optional variable length _UIDSTR.
+  /// Optional variable length _CIDSTR.
+  ///
+} ACPI_EXTENDED_HID_DEVICE_PATH;
+
+//
+//  EISA ID Macro
+//  EISA ID Definition 32-bits
+//   bits[15:0] - three character compressed ASCII EISA ID.
+//   bits[31:16] - binary number
+//    Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z'
+//
+#define PNP_EISA_ID_CONST         0x41d0
+#define EISA_ID(_Name, _Num)      ((UINT32)((_Name) | (_Num) << 16))
+#define EISA_PNP_ID(_PNPId)       (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+#define EFI_PNP_ID(_PNPId)        (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+
+#define PNP_EISA_ID_MASK          0xffff
+#define EISA_ID_TO_NUM(_Id)       ((_Id) >> 16)
+
+///
+/// ACPI _ADR Device Path SubType.
+///
+#define ACPI_ADR_DP               0x03
+
+///
+/// The _ADR device path is used to contain video output device attributes to support the Graphics
+/// Output Protocol. The device path can contain multiple _ADR entries if multiple video output
+/// devices are displaying the same output.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// _ADR value. For video output devices the value of this
+  /// field comes from Table B-2 of the ACPI 3.0 specification. At
+  /// least one _ADR value is required.
+  ///
+  UINT32                          ADR;
+  //
+  // This device path may optionally contain more than one _ADR entry.
+  //
+} ACPI_ADR_DEVICE_PATH;
+
+#define ACPI_ADR_DISPLAY_TYPE_OTHER             0
+#define ACPI_ADR_DISPLAY_TYPE_VGA               1
+#define ACPI_ADR_DISPLAY_TYPE_TV                2
+#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL  3
+#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL  4
+
+#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \
+          ((UINT32)( (((_DeviceIdScheme) & 0x1) << 31) |  \
+                      (((_HeadId)         & 0x7) << 18) |  \
+                      (((_NonVgaOutput)   & 0x1) << 17) |  \
+                      (((_BiosCanDetect)  & 0x1) << 16) |  \
+                      (((_VendorInfo)     & 0xf) << 12) |  \
+                      (((_Type)           & 0xf) << 8)  |  \
+                      (((_Port)           & 0xf) << 4)  |  \
+                       ((_Index)          & 0xf) ))
+
+///
+/// Messaging Device Paths.
+/// This Device Path is used to describe the connection of devices outside the resource domain of the
+/// system. This Device Path can describe physical messaging information like SCSI ID, or abstract
+/// information like networking protocol IP addresses.
+///
+#define MESSAGING_DEVICE_PATH     0x03
+
+///
+/// ATAPI Device Path SubType
+///
+#define MSG_ATAPI_DP              0x01
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Set to zero for primary, or one for secondary.
+  ///
+  UINT8                           PrimarySecondary;
+  ///
+  /// Set to zero for master, or one for slave mode.
+  ///
+  UINT8                           SlaveMaster;
+  ///
+  /// Logical Unit Number.
+  ///
+  UINT16                          Lun;
+} ATAPI_DEVICE_PATH;
+
+///
+/// SCSI Device Path SubType.
+///
+#define MSG_SCSI_DP               0x02
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Target ID on the SCSI bus (PUN).
+  ///
+  UINT16                          Pun;
+  ///
+  /// Logical Unit Number (LUN).
+  ///
+  UINT16                          Lun;
+} SCSI_DEVICE_PATH;
+
+///
+/// Fibre Channel SubType.
+///
+#define MSG_FIBRECHANNEL_DP       0x03
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Reserved for the future.
+  ///
+  UINT32                          Reserved;
+  ///
+  /// Fibre Channel World Wide Number.
+  ///
+  UINT64                          WWN;
+  ///
+  /// Fibre Channel Logical Unit Number.
+  ///
+  UINT64                          Lun;
+} FIBRECHANNEL_DEVICE_PATH;
+
+///
+/// 1394 Device Path SubType
+///
+#define MSG_1394_DP               0x04
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Reserved for the future.
+  ///
+  UINT32                          Reserved;
+  ///
+  /// 1394 Global Unique ID (GUID).
+  ///
+  UINT64                          Guid;
+} F1394_DEVICE_PATH;
+
+///
+/// USB Device Path SubType.
+///
+#define MSG_USB_DP                0x05
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL      Header;
+  ///
+  /// USB Parent Port Number.
+  ///
+  UINT8                         ParentPortNumber;
+  ///
+  /// USB Interface Number.
+  ///
+  UINT8                         InterfaceNumber;
+} USB_DEVICE_PATH;
+
+///
+/// USB Class Device Path SubType.
+///
+#define MSG_USB_CLASS_DP          0x0f
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL      Header;
+  ///
+  /// Vendor ID assigned by USB-IF. A value of 0xFFFF will
+  /// match any Vendor ID.
+  ///
+  UINT16                        VendorId;
+  ///
+  /// Product ID assigned by USB-IF. A value of 0xFFFF will
+  /// match any Product ID.
+  ///
+  UINT16                        ProductId;
+  ///
+  /// The class code assigned by the USB-IF. A value of 0xFF
+  /// will match any class code.
+  ///
+  UINT8                         DeviceClass;
+  ///
+  /// The subclass code assigned by the USB-IF. A value of
+  /// 0xFF will match any subclass code.
+  ///
+  UINT8                         DeviceSubClass;
+  ///
+  /// The protocol code assigned by the USB-IF. A value of
+  /// 0xFF will match any protocol code.
+  ///
+  UINT8                         DeviceProtocol;
+} USB_CLASS_DEVICE_PATH;
+
+///
+/// USB WWID Device Path SubType.
+///
+#define MSG_USB_WWID_DP           0x10
+
+///
+/// This device path describes a USB device using its serial number.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL      Header;
+  ///
+  /// USB interface number.
+  ///
+  UINT16                        InterfaceNumber;
+  ///
+  /// USB vendor id of the device.
+  ///
+  UINT16                        VendorId;
+  ///
+  /// USB product id of the device.
+  ///
+  UINT16                        ProductId;
+  ///
+  /// Last 64-or-fewer UTF-16 characters of the USB
+  /// serial number. The length of the string is
+  /// determined by the Length field less the offset of the
+  /// Serial Number field (10)
+  ///
+  /// CHAR16                     SerialNumber[...];
+} USB_WWID_DEVICE_PATH;
+
+///
+/// Device Logical Unit SubType.
+///
+#define MSG_DEVICE_LOGICAL_UNIT_DP  0x11
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL      Header;
+  ///
+  /// Logical Unit Number for the interface.
+  ///
+  UINT8                         Lun;
+} DEVICE_LOGICAL_UNIT_DEVICE_PATH;
+
+///
+/// SATA Device Path SubType.
+///
+#define MSG_SATA_DP               0x12
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// The HBA port number that facilitates the connection to the
+  /// device or a port multiplier. The value 0xFFFF is reserved.
+  ///
+  UINT16                          HBAPortNumber;
+  ///
+  /// The Port multiplier port number that facilitates the connection
+  /// to the device. Bit 15 should be set if the device is directly
+  /// connected to the HBA.
+  ///
+  UINT16                          PortMultiplierPortNumber;
+  ///
+  /// Logical Unit Number.
+  ///
+  UINT16                          Lun;
+} SATA_DEVICE_PATH;
+
+///
+/// Flag for if the device is directly connected to the HBA.
+///
+#define SATA_HBA_DIRECT_CONNECT_FLAG 0x8000
+
+///
+/// I2O Device Path SubType.
+///
+#define MSG_I2O_DP                0x06
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Target ID (TID) for a device.
+  ///
+  UINT32                          Tid;
+} I2O_DEVICE_PATH;
+
+///
+/// MAC Address Device Path SubType.
+///
+#define MSG_MAC_ADDR_DP           0x0b
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// The MAC address for a network interface padded with 0s.
+  ///
+  EFI_MAC_ADDRESS                 MacAddress;
+  ///
+  /// Network interface type(i.e. 802.3, FDDI).
+  ///
+  UINT8                           IfType;
+} MAC_ADDR_DEVICE_PATH;
+
+///
+/// IPv4 Device Path SubType
+///
+#define MSG_IPv4_DP               0x0c
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// The local IPv4 address.
+  ///
+  EFI_IPv4_ADDRESS                LocalIpAddress;
+  ///
+  /// The remote IPv4 address.
+  ///
+  EFI_IPv4_ADDRESS                RemoteIpAddress;
+  ///
+  /// The local port number.
+  ///
+  UINT16                          LocalPort;
+  ///
+  /// The remote port number.
+  ///
+  UINT16                          RemotePort;
+  ///
+  /// The network protocol(i.e. UDP, TCP).
+  ///
+  UINT16                          Protocol;
+  ///
+  /// 0x00 - The Source IP Address was assigned though DHCP.
+  /// 0x01 - The Source IP Address is statically bound.
+  ///
+  BOOLEAN                         StaticIpAddress;
+} IPv4_DEVICE_PATH;
+
+///
+/// IPv6 Device Path SubType.
+///
+#define MSG_IPv6_DP               0x0d
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// The local IPv6 address.
+  ///
+  EFI_IPv6_ADDRESS                LocalIpAddress;
+  ///
+  /// The remote IPv6 address.
+  ///
+  EFI_IPv6_ADDRESS                RemoteIpAddress;
+  ///
+  /// The local port number.
+  ///
+  UINT16                          LocalPort;
+  ///
+  /// The remote port number.
+  ///
+  UINT16                          RemotePort;
+  ///
+  /// The network protocol(i.e. UDP, TCP).
+  ///
+  UINT16                          Protocol;
+  ///
+  /// 0x00 - The Source IP Address was assigned though DHCP.
+  /// 0x01 - The Source IP Address is statically bound.
+  ///
+  BOOLEAN                         StaticIpAddress;
+} IPv6_DEVICE_PATH;
+
+///
+/// InfiniBand Device Path SubType.
+///
+#define MSG_INFINIBAND_DP         0x09
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Flags to help identify/manage InfiniBand device path elements:
+  /// Bit 0 - IOC/Service (0b = IOC, 1b = Service).
+  /// Bit 1 - Extend Boot Environment.
+  /// Bit 2 - Console Protocol.
+  /// Bit 3 - Storage Protocol.
+  /// Bit 4 - Network Protocol.
+  /// All other bits are reserved.
+  ///
+  UINT32                          ResourceFlags;
+  ///
+  /// 128-bit Global Identifier for remote fabric port.
+  ///
+  UINT8                           PortGid[16];
+  ///
+  /// 64-bit unique identifier to remote IOC or server process.
+  /// Interpretation of field specified by Resource Flags (bit 0).
+  ///
+  UINT64                          ServiceId;
+  ///
+  /// 64-bit persistent ID of remote IOC port.
+  ///
+  UINT64                          TargetPortId;
+  ///
+  /// 64-bit persistent ID of remote device.
+  ///
+  UINT64                          DeviceId;
+} INFINIBAND_DEVICE_PATH;
+
+#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE                0x01
+#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT  0x02
+#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL           0x04
+#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL           0x08
+#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL           0x10
+
+///
+/// UART Device Path SubType.
+///
+#define MSG_UART_DP               0x0e
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Reserved.
+  ///
+  UINT32                          Reserved;
+  ///
+  /// The baud rate setting for the UART style device. A value of 0
+  /// means that the device's default baud rate will be used.
+  ///
+  UINT64                          BaudRate;
+  ///
+  /// The number of data bits for the UART style device. A value
+  /// of 0 means that the device's default number of data bits will be used.
+  ///
+  UINT8                           DataBits;
+  ///
+  /// The parity setting for the UART style device.
+  /// Parity 0x00 - Default Parity.
+  /// Parity 0x01 - No Parity.
+  /// Parity 0x02 - Even Parity.
+  /// Parity 0x03 - Odd Parity.
+  /// Parity 0x04 - Mark Parity.
+  /// Parity 0x05 - Space Parity.
+  ///
+  UINT8                           Parity;
+  ///
+  /// The number of stop bits for the UART style device.
+  /// Stop Bits 0x00 - Default Stop Bits.
+  /// Stop Bits 0x01 - 1 Stop Bit.
+  /// Stop Bits 0x02 - 1.5 Stop Bits.
+  /// Stop Bits 0x03 - 2 Stop Bits.
+  ///
+  UINT8                           StopBits;
+} UART_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MSG_VENDOR_DP             0x0a
+typedef VENDOR_DEVICE_PATH        VENDOR_DEFINED_DEVICE_PATH;
+
+#define DEVICE_PATH_MESSAGING_PC_ANSI     EFI_PC_ANSI_GUID
+#define DEVICE_PATH_MESSAGING_VT_100      EFI_VT_100_GUID
+#define DEVICE_PATH_MESSAGING_VT_100_PLUS EFI_VT_100_PLUS_GUID
+#define DEVICE_PATH_MESSAGING_VT_UTF8     EFI_VT_UTF8_GUID
+
+///
+/// A new device path node is defined to declare flow control characteristics.
+/// UART Flow Control Messaging Device Path
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL GUID.
+  ///
+  EFI_GUID                        Guid;
+  ///
+  /// Bitmap of supported flow control types.
+  /// Bit 0 set indicates hardware flow control.
+  /// Bit 1 set indicates Xon/Xoff flow control.
+  /// All other bits are reserved and are clear.
+  ///
+  UINT32                          FlowControlMap;
+} UART_FLOW_CONTROL_DEVICE_PATH;
+
+#define UART_FLOW_CONTROL_HARDWARE         0x00000001
+#define UART_FLOW_CONTROL_XON_XOFF         0x00000010
+
+#define DEVICE_PATH_MESSAGING_SAS                 EFI_SAS_DEVICE_PATH_GUID
+///
+/// Serial Attached SCSI (SAS) devices.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// DEVICE_PATH_MESSAGING_SAS GUID.
+  ///
+  EFI_GUID                        Guid;
+  ///
+  /// Reserved for future use.
+  ///
+  UINT32                          Reserved;
+  ///
+  /// SAS Address for Serial Attached SCSI Target.
+  ///
+  UINT64                          SasAddress;
+  ///
+  /// SAS Logical Unit Number.
+  ///
+  UINT64                          Lun;
+  ///
+  /// More Information about the device and its interconnect.
+  ///
+  UINT16                          DeviceTopology;
+  ///
+  /// Relative Target Port (RTP).
+  ///
+  UINT16                          RelativeTargetPort;
+} SAS_DEVICE_PATH;
+
+///
+/// iSCSI Device Path SubType
+///
+#define MSG_ISCSI_DP              0x13
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Network Protocol (0 = TCP, 1+ = reserved).
+  ///
+  UINT16                          NetworkProtocol;
+  ///
+  /// iSCSI Login Options.
+  ///
+  UINT16                          LoginOption;
+  ///
+  /// iSCSI Logical Unit Number.
+  ///
+  UINT64                          Lun;
+  ///
+  /// iSCSI Target Portal group tag the initiator intends
+  /// to establish a session with.
+  ///
+  UINT16                          TargetPortalGroupTag;
+  ///
+  /// iSCSI NodeTarget Name. The length of the name
+  /// is determined by subtracting the offset of this field from Length.
+  ///
+  /// CHAR8                        iSCSI Target Name.
+} ISCSI_DEVICE_PATH;
+
+#define ISCSI_LOGIN_OPTION_NO_HEADER_DIGEST             0x0000
+#define ISCSI_LOGIN_OPTION_HEADER_DIGEST_USING_CRC32C   0x0002
+#define ISCSI_LOGIN_OPTION_NO_DATA_DIGEST               0x0000
+#define ISCSI_LOGIN_OPTION_DATA_DIGEST_USING_CRC32C     0x0008
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_CHAP              0x0000
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_NON               0x1000
+#define ISCSI_LOGIN_OPTION_CHAP_BI                      0x0000
+#define ISCSI_LOGIN_OPTION_CHAP_UNI                     0x2000
+
+///
+/// VLAN Device Path SubType.
+///
+#define MSG_VLAN_DP               0x14
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// VLAN identifier (0-4094).
+  ///
+  UINT16                          VlanId;
+} VLAN_DEVICE_PATH;
+
+//
+// Media Device Path
+//
+#define MEDIA_DEVICE_PATH         0x04
+
+///
+/// Hard Drive Media Device Path SubType.
+///
+#define MEDIA_HARDDRIVE_DP        0x01
+
+///
+/// The Hard Drive Media Device Path is used to represent a partition on a hard drive.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Describes the entry in a partition table, starting with entry 1.
+  /// Partition number zero represents the entire device. Valid
+  /// partition numbers for a MBR partition are [1, 4]. Valid
+  /// partition numbers for a GPT partition are [1, NumberOfPartitionEntries].
+  ///
+  UINT32                          PartitionNumber;
+  ///
+  /// Starting LBA of the partition on the hard drive.
+  ///
+  UINT64                          PartitionStart;
+  ///
+  /// Size of the partition in units of Logical Blocks.
+  ///
+  UINT64                          PartitionSize;
+  ///
+  /// Signature unique to this partition:
+  /// If SignatureType is 0, this field has to be initialized with 16 zeros.
+  /// If SignatureType is 1, the MBR signature is stored in the first 4 bytes of this field.
+  /// The other 12 bytes are initialized with zeros.
+  /// If SignatureType is 2, this field contains a 16 byte signature.
+  ///
+  UINT8                           Signature[16];
+  ///
+  /// Partition Format: (Unused values reserved).
+  /// 0x01 - PC-AT compatible legacy MBR.
+  /// 0x02 - GUID Partition Table.
+  ///
+  UINT8                           MBRType;
+  ///
+  /// Type of Disk Signature: (Unused values reserved).
+  /// 0x00 - No Disk Signature.
+  /// 0x01 - 32-bit signature from address 0x1b8 of the type 0x01 MBR.
+  /// 0x02 - GUID signature.
+  ///
+  UINT8                           SignatureType;
+} HARDDRIVE_DEVICE_PATH;
+
+#define MBR_TYPE_PCAT             0x01
+#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
+
+#define NO_DISK_SIGNATURE         0x00
+#define SIGNATURE_TYPE_MBR        0x01
+#define SIGNATURE_TYPE_GUID       0x02
+
+///
+/// CD-ROM Media Device Path SubType.
+///
+#define MEDIA_CDROM_DP            0x02
+
+///
+/// The CD-ROM Media Device Path is used to define a system partition that exists on a CD-ROM.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Boot Entry number from the Boot Catalog. The Initial/Default entry is defined as zero.
+  ///
+  UINT32                          BootEntry;
+  ///
+  /// Starting RBA of the partition on the medium. CD-ROMs use Relative logical Block Addressing.
+  ///
+  UINT64                          PartitionStart;
+  ///
+  /// Size of the partition in units of Blocks, also called Sectors.
+  ///
+  UINT64                          PartitionSize;
+} CDROM_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MEDIA_VENDOR_DP           0x03  ///< Media vendor device path subtype.
+
+///
+/// File Path Media Device Path SubType
+///
+#define MEDIA_FILEPATH_DP         0x04
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// A NULL-terminated Path string including directory and file names.
+  ///
+  CHAR16                          PathName[1];
+} FILEPATH_DEVICE_PATH;
+
+#define SIZE_OF_FILEPATH_DEVICE_PATH  OFFSET_OF(FILEPATH_DEVICE_PATH,PathName)
+
+///
+/// Media Protocol Device Path SubType.
+///
+#define MEDIA_PROTOCOL_DP         0x05
+
+///
+/// The Media Protocol Device Path is used to denote the protocol that is being
+/// used in a device path at the location of the path specified.
+/// Many protocols are inherent to the style of device path.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// The ID of the protocol.
+  ///
+  EFI_GUID                        Protocol;
+} MEDIA_PROTOCOL_DEVICE_PATH;
+
+///
+/// PIWG Firmware Volume Device Path SubType.
+///
+#define MEDIA_PIWG_FW_FILE_DP     0x06
+
+///
+/// This device path is used by systems implementing the UEFI PI Specification 1.0 to describe a firmware file.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Firmware file name
+  ///
+  EFI_GUID                        FvFileName;
+} MEDIA_FW_VOL_FILEPATH_DEVICE_PATH;
+
+///
+/// PIWG Firmware Volume Device Path SubType.
+///
+#define MEDIA_PIWG_FW_VOL_DP      0x07
+
+///
+/// This device path is used by systems implementing the UEFI PI Specification 1.0 to describe a firmware volume.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Firmware volume name.
+  ///
+  EFI_GUID                        FvName;
+} MEDIA_FW_VOL_DEVICE_PATH;
+
+///
+/// Media relative offset range device path.
+///
+#define MEDIA_RELATIVE_OFFSET_RANGE_DP 0x08
+
+///
+/// Used to describe the offset range of media relative.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  Header;
+  UINT32                    Reserved;
+  UINT64                    StartingOffset;
+  UINT64                    EndingOffset;
+} MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH;
+
+///
+/// BIOS Boot Specification Device Path.
+///
+#define BBS_DEVICE_PATH           0x05
+
+///
+/// BIOS Boot Specification Device Path SubType.
+///
+#define BBS_BBS_DP                0x01
+
+///
+/// This Device Path is used to describe the booting of non-EFI-aware operating systems.
+///
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Device Type as defined by the BIOS Boot Specification.
+  ///
+  UINT16                          DeviceType;
+  ///
+  /// Status Flags as defined by the BIOS Boot Specification.
+  ///
+  UINT16                          StatusFlag;
+  ///
+  /// ASCIIZ string that describes the boot device to a user.
+  ///
+  CHAR8                           String[1];
+} BBS_BBS_DEVICE_PATH;
+
+//
+// DeviceType definitions - from BBS specification
+//
+#define BBS_TYPE_FLOPPY           0x01
+#define BBS_TYPE_HARDDRIVE        0x02
+#define BBS_TYPE_CDROM            0x03
+#define BBS_TYPE_PCMCIA           0x04
+#define BBS_TYPE_USB              0x05
+#define BBS_TYPE_EMBEDDED_NETWORK 0x06
+#define BBS_TYPE_BEV              0x80
+#define BBS_TYPE_UNKNOWN          0xFF
+
+
+///
+/// Union of all possible Device Paths and pointers to Device Paths.
+///
+typedef union {
+  EFI_DEVICE_PATH_PROTOCOL             DevPath;
+  PCI_DEVICE_PATH                      Pci;
+  PCCARD_DEVICE_PATH                   PcCard;
+  MEMMAP_DEVICE_PATH                   MemMap;
+  VENDOR_DEVICE_PATH                   Vendor;
+
+  CONTROLLER_DEVICE_PATH               Controller;
+  ACPI_HID_DEVICE_PATH                 Acpi;
+
+  ATAPI_DEVICE_PATH                    Atapi;
+  SCSI_DEVICE_PATH                     Scsi;
+  ISCSI_DEVICE_PATH                    Iscsi;
+  FIBRECHANNEL_DEVICE_PATH             FibreChannel;
+
+  F1394_DEVICE_PATH                    F1394;
+  USB_DEVICE_PATH                      Usb;
+  SATA_DEVICE_PATH                     Sata;
+  USB_CLASS_DEVICE_PATH                UsbClass;
+  I2O_DEVICE_PATH                      I2O;
+  MAC_ADDR_DEVICE_PATH                 MacAddr;
+  IPv4_DEVICE_PATH                     Ipv4;
+  IPv6_DEVICE_PATH                     Ipv6;
+  INFINIBAND_DEVICE_PATH               InfiniBand;
+  UART_DEVICE_PATH                     Uart;
+
+  HARDDRIVE_DEVICE_PATH                HardDrive;
+  CDROM_DEVICE_PATH                    CD;
+
+  FILEPATH_DEVICE_PATH                 FilePath;
+  MEDIA_PROTOCOL_DEVICE_PATH           MediaProtocol;
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH Offset;
+
+  BBS_BBS_DEVICE_PATH                  Bbs;
+} EFI_DEV_PATH;
+
+
+
+typedef union {
+  EFI_DEVICE_PATH_PROTOCOL             *DevPath;
+  PCI_DEVICE_PATH                      *Pci;
+  PCCARD_DEVICE_PATH                   *PcCard;
+  MEMMAP_DEVICE_PATH                   *MemMap;
+  VENDOR_DEVICE_PATH                   *Vendor;
+
+  CONTROLLER_DEVICE_PATH               *Controller;
+  ACPI_HID_DEVICE_PATH                 *Acpi;
+  ACPI_EXTENDED_HID_DEVICE_PATH        *ExtendedAcpi;
+
+  ATAPI_DEVICE_PATH                    *Atapi;
+  SCSI_DEVICE_PATH                     *Scsi;
+  FIBRECHANNEL_DEVICE_PATH             *FibreChannel;
+
+  F1394_DEVICE_PATH                    *F1394;
+  USB_DEVICE_PATH                      *Usb;
+  SATA_DEVICE_PATH                     *Sata;
+  USB_CLASS_DEVICE_PATH                *UsbClass;
+  I2O_DEVICE_PATH                      *I2O;
+  MAC_ADDR_DEVICE_PATH                 *MacAddr;
+  IPv4_DEVICE_PATH                     *Ipv4;
+  IPv6_DEVICE_PATH                     *Ipv6;
+  INFINIBAND_DEVICE_PATH               *InfiniBand;
+  UART_DEVICE_PATH                     *Uart;
+
+  HARDDRIVE_DEVICE_PATH                *HardDrive;
+  CDROM_DEVICE_PATH                    *CD;
+
+  FILEPATH_DEVICE_PATH                 *FilePath;
+  MEDIA_PROTOCOL_DEVICE_PATH           *MediaProtocol;
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset;
+
+  BBS_BBS_DEVICE_PATH                  *Bbs;
+  UINT8                                *Raw;
+} EFI_DEV_PATH_PTR;
+
+#pragma pack()
+
+#define END_DEVICE_PATH_TYPE                 0x7f
+#define END_ENTIRE_DEVICE_PATH_SUBTYPE       0xFF
+#define END_INSTANCE_DEVICE_PATH_SUBTYPE     0x01
+
+extern EFI_GUID gEfiDevicePathProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DriverBinding.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DriverBinding.h
new file mode 100644
index 0000000..1f464a7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/DriverBinding.h
@@ -0,0 +1,203 @@
+/** @file
+  UEFI DriverBinding Protocol is defined in UEFI specification.
+
+  This protocol is produced by every driver that follows the UEFI Driver Model,
+  and it is the central component that allows drivers and controllers to be managed.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DRIVER_BINDING_H__
+#define __EFI_DRIVER_BINDING_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// The global ID for the ControllerHandle Driver Protocol.
+///
+#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
+  { \
+    0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \
+  }
+
+typedef struct _EFI_DRIVER_BINDING_PROTOCOL  EFI_DRIVER_BINDING_PROTOCOL;
+
+/**
+  Tests to see if this driver supports a given controller. If a child device is provided,
+  it further tests to see if this driver supports creating a handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the device specified by
+  ControllerHandle. Drivers will typically use the device path attached to
+  ControllerHandle and/or the services from the bus I/O abstraction attached to
+  ControllerHandle to determine if the driver supports ControllerHandle. This function
+  may be called many times during platform initialization. In order to reduce boot times, the tests
+  performed by this function must be very small, and take as little time as possible to execute. This
+  function must not change the state of any hardware devices, and this function must be aware that the
+  device specified by ControllerHandle may already be managed by the same driver or a
+  different driver. This function must match its calls to AllocatePages() with FreePages(),
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required
+  to guarantee the state of ControllerHandle is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter is not NULL, then
+                                   the bus driver must determine if the bus controller specified
+                                   by ControllerHandle and the child controller specified
+                                   by RemainingDevicePath are both supported by this
+                                   bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by the driver
+                                   specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by a different
+                                   driver or an application that requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the driver specified by This.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)(
+  IN EFI_DRIVER_BINDING_PROTOCOL            *This,
+  IN EFI_HANDLE                             ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL               *RemainingDevicePath OPTIONAL
+  );
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+     EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For a bus driver, if this parameter is NULL, then handles
+                                   for all the children of Controller are created by this driver.
+                                   If this parameter is not NULL and the first Device Path Node is
+                                   not the End of Device Path Node, then only the handle for the
+                                   child device specified by the first Device Path Node of
+                                   RemainingDevicePath is created by this driver.
+                                   If the first Device Path Node of RemainingDevicePath is
+                                   the End of Device Path Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
+  @retval Others                   The driver failded to start the device.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_START)(
+  IN EFI_DRIVER_BINDING_PROTOCOL            *This,
+  IN EFI_HANDLE                             ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL               *RemainingDevicePath OPTIONAL
+  );
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been moved
+  into this common boot service. It is legal to call Stop() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+     same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+     Start() function, and the Start() function must have called OpenProtocol() on
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
+                                support a bus specific I/O protocol for the driver
+                                to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
+                                if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_STOP)(
+  IN EFI_DRIVER_BINDING_PROTOCOL            *This,
+  IN  EFI_HANDLE                            ControllerHandle,
+  IN  UINTN                                 NumberOfChildren,
+  IN  EFI_HANDLE                            *ChildHandleBuffer OPTIONAL
+  );
+
+///
+/// This protocol provides the services required to determine if a driver supports a given controller.
+/// If a controller is supported, then it also provides routines to start and stop the controller.
+///
+struct _EFI_DRIVER_BINDING_PROTOCOL {
+  EFI_DRIVER_BINDING_SUPPORTED  Supported;
+  EFI_DRIVER_BINDING_START      Start;
+  EFI_DRIVER_BINDING_STOP       Stop;
+
+  ///
+  /// The version number of the UEFI driver that produced the
+  /// EFI_DRIVER_BINDING_PROTOCOL. This field is used by
+  /// the EFI boot service ConnectController() to determine
+  /// the order that driver's Supported() service will be used when
+  /// a controller needs to be started. EFI Driver Binding Protocol
+  /// instances with higher Version values will be used before ones
+  /// with lower Version values. The Version values of 0x0-
+  /// 0x0f and 0xfffffff0-0xffffffff are reserved for
+  /// platform/OEM specific drivers. The Version values of 0x10-
+  /// 0xffffffef are reserved for IHV-developed drivers.
+  ///
+  UINT32                        Version;
+
+  ///
+  /// The image handle of the UEFI driver that produced this instance
+  /// of the EFI_DRIVER_BINDING_PROTOCOL.
+  ///
+  EFI_HANDLE                    ImageHandle;
+
+  ///
+  /// The handle on which this instance of the
+  /// EFI_DRIVER_BINDING_PROTOCOL is installed. In most
+  /// cases, this is the same handle as ImageHandle. However, for
+  /// UEFI drivers that produce more than one instance of the
+  /// EFI_DRIVER_BINDING_PROTOCOL, this value may not be
+  /// the same as ImageHandle.
+  ///
+  EFI_HANDLE                    DriverBindingHandle;
+};
+
+extern EFI_GUID gEfiDriverBindingProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h
new file mode 100644
index 0000000..6befec6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h
@@ -0,0 +1,177 @@
+/** @file
+  This protocol is defined in UEFI spec.
+
+  The EFI_FORM_BROWSER2_PROTOCOL is the interface to call for drivers to
+  leverage the EFI configuration driver interface.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_FORM_BROWSER2_H__
+#define __EFI_FORM_BROWSER2_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Guid/HiiPlatformSetupFormset.h>
+
+#define EFI_FORM_BROWSER2_PROTOCOL_GUID \
+  {0xb9d4c360, 0xbcfb, 0x4f9b, {0x92, 0x98, 0x53, 0xc1, 0x36, 0x98, 0x22, 0x58 }}
+
+
+typedef struct _EFI_FORM_BROWSER2_PROTOCOL   EFI_FORM_BROWSER2_PROTOCOL;
+
+
+
+/**
+
+  @param LeftColumn   The value that designates the text column
+                      where the browser window will begin from
+                      the left-hand side of the screen
+
+  @param RightColumn  The value that designates the text
+                      column where the browser window will end
+                      on the right-hand side of the screen.
+
+  @param TopRow       The value that designates the text row from the
+                      top of the screen where the browser window
+                      will start.
+
+  @param BottomRow    The value that designates the text row from the
+                      bottom of the screen where the browser
+                      window will end.
+**/
+typedef struct {
+  UINTN   LeftColumn;
+  UINTN   RightColumn;
+  UINTN   TopRow;
+  UINTN   BottomRow;
+} EFI_SCREEN_DESCRIPTOR;
+
+typedef UINTN EFI_BROWSER_ACTION_REQUEST;
+
+#define EFI_BROWSER_ACTION_REQUEST_NONE   0
+#define EFI_BROWSER_ACTION_REQUEST_RESET  1
+#define EFI_BROWSER_ACTION_REQUEST_SUBMIT 2
+#define EFI_BROWSER_ACTION_REQUEST_EXIT   3
+
+
+/**
+  Initialize the browser to display the specified configuration forms.
+
+  This function is the primary interface to the internal forms-based browser.
+  The forms browser will display forms associated with the specified Handles.
+  The browser will select all forms in packages which have the specified Type
+  and (for EFI_HII_PACKAGE_TYPE_GUID) the specified PackageGuid.
+
+  @param This            A pointer to the EFI_FORM_BROWSER2_PROTOCOL instance
+
+  @param Handles         A pointer to an array of Handles. This value should correspond
+                         to the value of the HII form package that is required to be displayed.
+
+  @param HandleCount     The number of Handles specified in Handle.
+
+  @param FormSetGuid     This field points to the EFI_GUID which must match the Guid field or one of the
+                         elements of the ClassId field  in the EFI_IFR_FORM_SET op-code.  If
+                         FormsetGuid is NULL, then this function will display the the form set class
+                         EFI_HII_PLATFORM_SETUP_FORMSET_GUID.
+
+  @param FormId          This field specifies the identifier of the form within the form set to render as the first
+                         displayable page. If this field has a value of 0x0000, then the Forms Browser will
+                         render the first enabled form in the form set.
+
+  @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
+                          characters.
+
+  @param ActionRequest   Points to the action recommended by the form.
+
+  @retval EFI_SUCCESS           The function completed successfully
+
+  @retval EFI_NOT_FOUND         The variable was not found.
+
+  @retval EFI_INVALID_PARAMETER One of the parameters has an
+                                invalid value.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SEND_FORM2)(
+  IN CONST  EFI_FORM_BROWSER2_PROTOCOL  *This,
+  IN        EFI_HII_HANDLE              *Handle,
+  IN        UINTN                      HandleCount,
+  IN        EFI_GUID                   *FormSetGuid, OPTIONAL
+  IN        EFI_FORM_ID                FormId, OPTIONAL
+  IN CONST  EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL
+  OUT       EFI_BROWSER_ACTION_REQUEST *ActionRequest  OPTIONAL
+);
+
+
+/**
+  This function is called by a callback handler to retrieve uncommitted state data from the browser.
+
+  This routine is called by a routine which was called by the
+  browser. This routine called this service in the browser to
+  retrieve or set certain uncommitted state information.
+
+  @param This           A pointer to the EFI_FORM_BROWSER2_PROTOCOL instance.
+
+  @param ResultsDataSize  A pointer to the size of the buffer
+                          associated with ResultsData. On input, the size in
+                          bytes of ResultsData. On output, the size of data
+                          returned in ResultsData.
+
+  @param ResultsData    A string returned from an IFR browser or
+                        equivalent. The results string will have
+                        no routing information in them.
+
+  @param RetrieveData   A BOOLEAN field which allows an agent to
+                        retrieve (if RetrieveData = TRUE) data
+                        from the uncommitted browser state
+                        information or set (if RetrieveData =
+                        FALSE) data in the uncommitted browser
+                        state information.
+
+  @param VariableGuid   An optional field to indicate the target
+                        variable GUID name to use.
+
+  @param VariableName   An optional field to indicate the target
+                        human-readable variable name.
+
+  @retval EFI_SUCCESS           The results have been distributed or are
+                                awaiting distribution.
+
+  @retval EFI_OUT_OF_RESOURCES  The ResultsDataSize specified
+                                was too small to contain the
+                                results data.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BROWSER_CALLBACK2)(
+  IN CONST  EFI_FORM_BROWSER2_PROTOCOL *This,
+  IN OUT    UINTN                     *ResultsDataSize,
+  IN OUT    EFI_STRING                ResultsData,
+  IN CONST  BOOLEAN                   RetrieveData,
+  IN CONST  EFI_GUID                  *VariableGuid, OPTIONAL
+  IN CONST  CHAR16                    *VariableName OPTIONAL
+);
+
+///
+/// This interface will allow the caller to direct the configuration
+/// driver to use either the HII database or use the passed-in packet of data.
+///
+struct _EFI_FORM_BROWSER2_PROTOCOL {
+  EFI_SEND_FORM2         SendForm;
+  EFI_BROWSER_CALLBACK2  BrowserCallback;
+} ;
+
+extern EFI_GUID gEfiFormBrowser2ProtocolGuid;
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
new file mode 100644
index 0000000..2bef5cb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
@@ -0,0 +1,221 @@
+/** @file
+
+  The EFI HII results processing protocol invokes this type of protocol
+  when it needs to forward results to a driver's configuration handler.
+  This protocol is published by drivers providing and requesting
+  configuration data from HII. It may only be invoked by HII.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __EFI_HII_CONFIG_ACCESS_H__
+#define __EFI_HII_CONFIG_ACCESS_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Protocol/FormBrowser2.h>
+
+#define EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID  \
+  { 0x330d4706, 0xf2a0, 0x4e4f, { 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85 } }
+
+typedef struct _EFI_HII_CONFIG_ACCESS_PROTOCOL  EFI_HII_CONFIG_ACCESS_PROTOCOL;
+
+typedef UINTN EFI_BROWSER_ACTION;
+
+#define EFI_BROWSER_ACTION_CHANGING   0
+#define EFI_BROWSER_ACTION_CHANGED    1
+#define EFI_BROWSER_ACTION_RETRIEVE   2
+#define EFI_BROWSER_ACTION_FORM_OPEN  3
+#define EFI_BROWSER_ACTION_FORM_CLOSE 4
+
+/**
+
+  This function allows the caller to request the current
+  configuration for one or more named elements. The resulting
+  string is in <ConfigAltResp> format. Any and all alternative
+  configuration strings shall also be appended to the end of the
+  current configuration string. If they are, they must appear
+  after the current configuration. They must contain the same
+  routing (GUID, NAME, PATH) as the current configuration string.
+  They must have an additional description indicating the type of
+  alternative configuration the string represents,
+  "ALTCFG=<StringToken>". That <StringToken> (when
+  converted from Hex UNICODE to binary) is a reference to a
+  string in the associated string pack.
+
+  @param This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+  @param Request    A null-terminated Unicode string in
+                    <ConfigRequest> format. Note that this
+                    includes the routing information as well as
+                    the configurable name / value pairs. It is
+                    invalid for this string to be in
+                    <MultiConfigRequest> format.
+                    If a NULL is passed in for the Request field,
+                    all of the settings being abstracted by this function
+                    will be returned in the Results field.  In addition,
+                    if a ConfigHdr is passed in with no request elements,
+                    all of the settings being abstracted for that particular
+                    ConfigHdr reference will be returned in the Results Field.
+
+  @param Progress   On return, points to a character in the
+                    Request string. Points to the string's null
+                    terminator if request was successful. Points
+                    to the most recent "&" before the first
+                    failing name / value pair (or the beginning
+                    of the string if the failure is in the first
+                    name / value pair) if the request was not
+                    successful.
+
+  @param Results    A null-terminated Unicode string in
+                    <MultiConfigAltResp> format which has all values
+                    filled in for the names in the Request string.
+                    String to be allocated by the called function.
+
+  @retval EFI_SUCCESS             The Results string is filled with the
+                                  values corresponding to all requested
+                                  names.
+
+  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
+                                  parts of the results that must be
+                                  stored awaiting possible future
+                                  protocols.
+
+  @retval EFI_NOT_FOUND           Routing data doesn't match any
+                                  known driver. Progress set to the
+                                  first character in the routing header.
+                                  Note: There is no requirement that the
+                                  driver validate the routing data. It
+                                  must skip the <ConfigHdr> in order to
+                                  process the names.
+
+  @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
+                                  to most recent "&" before the
+                                  error or the beginning of the
+                                  string.
+
+  @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
+                                  to the & before the name in
+                                  question.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_HII_ACCESS_EXTRACT_CONFIG)(
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Request,
+  OUT       EFI_STRING                      *Progress,
+  OUT       EFI_STRING                      *Results
+);
+
+
+/**
+
+  This function applies changes in a driver's configuration.
+  Input is a Configuration, which has the routing data for this
+  driver followed by name / value configuration pairs. The driver
+  must apply those pairs to its configurable storage. If the
+  driver's configuration is stored in a linear block of data
+  and the driver's name / value pairs are in <BlockConfig>
+  format, it may use the ConfigToBlock helper function (above) to
+  simplify the job.
+
+  @param This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+  @param Configuration  A null-terminated Unicode string in
+                        <ConfigString> format.
+
+  @param Progress       A pointer to a string filled in with the
+                        offset of the most recent '&' before the
+                        first failing name / value pair (or the
+                        beginn ing of the string if the failure
+                        is in the first name / value pair) or
+                        the terminating NULL if all was
+                        successful.
+
+  @retval EFI_SUCCESS             The results have been distributed or are
+                                  awaiting distribution.
+
+  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
+                                  parts of the results that must be
+                                  stored awaiting possible future
+                                  protocols.
+
+  @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
+                                  Results parameter would result
+                                  in this type of error.
+
+  @retval EFI_NOT_FOUND           Target for the specified routing data
+                                  was not found
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_HII_ACCESS_ROUTE_CONFIG)(
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Configuration,
+  OUT       EFI_STRING                      *Progress
+);
+
+/**
+
+  This function is called to provide results data to the driver.
+  This data consists of a unique key that is used to identify
+  which data is either being passed back or being asked for.
+
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+  @param  Action                 Specifies the type of action taken by the browser.
+  @param  QuestionId             A unique value which is sent to the original
+                                 exporting driver so that it can identify the type
+                                 of data to expect. The format of the data tends to
+                                 vary based on the opcode that generated the callback.
+  @param  Type                   The type of value for the question.
+  @param  Value                  A pointer to the data being sent to the original
+                                 exporting driver.
+  @param  ActionRequest          On return, points to the action requested by the
+                                 callback function.
+
+  @retval EFI_SUCCESS            The callback successfully handled the action.
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
+                                 variable and its data.
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
+                                 callback.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_ACCESS_FORM_CALLBACK)(
+  IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN     EFI_BROWSER_ACTION                     Action,
+  IN     EFI_QUESTION_ID                        QuestionId,
+  IN     UINT8                                  Type,
+  IN OUT EFI_IFR_TYPE_VALUE                     *Value,
+  OUT    EFI_BROWSER_ACTION_REQUEST             *ActionRequest
+  )
+  ;
+
+///
+/// This protocol provides a callable interface between the HII and
+/// drivers. Only drivers which provide IFR data to HII are required
+/// to publish this protocol.
+///
+struct _EFI_HII_CONFIG_ACCESS_PROTOCOL {
+  EFI_HII_ACCESS_EXTRACT_CONFIG     ExtractConfig;
+  EFI_HII_ACCESS_ROUTE_CONFIG       RouteConfig;
+  EFI_HII_ACCESS_FORM_CALLBACK      Callback;
+} ;
+
+extern EFI_GUID gEfiHiiConfigAccessProtocolGuid;
+
+#endif
+
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h
new file mode 100644
index 0000000..411ca2c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h
@@ -0,0 +1,519 @@
+/** @file
+  The file provides Database manager for HII-related data
+  structures.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __HII_DATABASE_H__
+#define __HII_DATABASE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_HII_DATABASE_PROTOCOL_GUID \
+  { 0xef9fc172, 0xa1b2, 0x4693, { 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42 } }
+
+
+typedef struct _EFI_HII_DATABASE_PROTOCOL EFI_HII_DATABASE_PROTOCOL;
+
+
+///
+/// EFI_HII_DATABASE_NOTIFY_TYPE.
+///
+typedef UINTN   EFI_HII_DATABASE_NOTIFY_TYPE;
+
+#define EFI_HII_DATABASE_NOTIFY_NEW_PACK    0x00000001
+#define EFI_HII_DATABASE_NOTIFY_REMOVE_PACK 0x00000002
+#define EFI_HII_DATABASE_NOTIFY_EXPORT_PACK 0x00000004
+#define EFI_HII_DATABASE_NOTIFY_ADD_PACK    0x00000008
+/**
+
+  Functions which are registered to receive notification of
+  database events have this prototype. The actual event is encoded
+  in NotifyType. The following table describes how PackageType,
+  PackageGuid, Handle, and Package are used for each of the
+  notification types.
+
+  @param PackageType  Package type of the notification.
+
+  @param PackageGuid  If PackageType is
+                      EFI_HII_PACKAGE_TYPE_GUID, then this is
+                      the pointer to the GUID from the Guid
+                      field of EFI_HII_PACKAGE_GUID_HEADER.
+                      Otherwise, it must be NULL.
+
+  @param Package      Points to the package referred to by the notification.
+
+  @param Handle       The handle of the package
+                      list which contains the specified package.
+
+  @param NotifyType   The type of change concerning the
+                      database. See
+                      EFI_HII_DATABASE_NOTIFY_TYPE.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_NOTIFY)(
+  IN        UINT8                         PackageType,
+  IN CONST  EFI_GUID                      *PackageGuid,
+  IN CONST  EFI_HII_PACKAGE_HEADER        *Package,
+  IN        EFI_HII_HANDLE                 Handle,
+  IN        EFI_HII_DATABASE_NOTIFY_TYPE  NotifyType
+);
+
+/**
+
+  This function adds the packages in the package list to the
+  database and returns a handle. If there is a
+  EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then
+  this function will create a package of type
+  EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list. For
+  each package in the package list, registered functions with the
+  notification type NEW_PACK and having the same package type will
+  be called. For each call to NewPackageList(), there should be a
+  corresponding call to
+  EFI_HII_DATABASE_PROTOCOL.RemovePackageList().
+
+  @param This           A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageList    A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure.
+
+  @param DriverHandle   Associate the package list with this EFI handle.
+                        If a NULL is specified, this data will not be associate
+                        with any drivers and cannot have a callback induced.
+
+  @param Handle         A pointer to the EFI_HII_HANDLE instance.
+
+  @retval EFI_SUCCESS           The package list associated with the
+                                Handle was added to the HII database.
+
+  @retval EFI_OUT_OF_RESOURCES  Unable to allocate necessary
+                                resources for the new database
+                                contents.
+
+  @retval EFI_INVALID_PARAMETER PackageList is NULL, or Handle is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_NEW_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL   *This,
+  IN CONST  EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+  IN        EFI_HANDLE                  DriverHandle, OPTIONAL
+  OUT       EFI_HII_HANDLE               *Handle
+);
+
+
+/**
+
+  This function removes the package list that is associated with a
+  handle Handle from the HII database. Before removing the
+  package, any registered functions with the notification type
+  REMOVE_PACK and the same package type will be called. For each
+  call to EFI_HII_DATABASE_PROTOCOL.NewPackageList(), there should
+  be a corresponding call to RemovePackageList.
+
+  @param This             A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param Handle           The handle that was registered to the data
+                          that is requested for removal.
+
+  @retval EFI_SUCCESS     The data associated with the Handle was
+                          removed from the HII database.
+  @retval EFI_NOT_FOUND   The specified Handle is not in database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_REMOVE_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HII_HANDLE             Handle
+);
+
+
+/**
+
+  This function updates the existing package list (which has the
+  specified Handle) in the HII databases, using the new package
+  list specified by PackageList. The update process has the
+  following steps: Collect all the package types in the package
+  list specified by PackageList. A package type consists of the
+  Type field of EFI_HII_PACKAGE_HEADER and, if the Type is
+  EFI_HII_PACKAGE_TYPE_GUID, the Guid field, as defined in
+  EFI_HII_PACKAGE_GUID_HEADER. Iterate through the packages within
+  the existing package list in the HII database specified by
+  Handle. If a package's type matches one of the collected types collected
+  in step 1, then perform the following steps:
+  - Call any functions registered with the notification type
+  REMOVE_PACK.
+  - Remove the package from the package list and the HII
+  database.
+  Add all of the packages within the new package list specified
+  by PackageList, using the following steps:
+  - Add the package to the package list and the HII database.
+  - Call any functions registered with the notification type
+  ADD_PACK.
+
+  @param This         A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param Handle       The handle that was registered to the data
+                      that is requested for removal.
+
+  @param PackageList  A pointer to an EFI_HII_PACKAGE_LIST
+                      package.
+
+  @retval EFI_SUCCESS            The HII database was successfully updated.
+
+  @retval EFI_OUT_OF_RESOURCES   Unable to allocate enough memory
+                                 for the updated database.
+
+  @retval EFI_INVALID_PARAMETER  PackageList was NULL.
+  @retval EFI_NOT_FOUND          The specified Handle is not in database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_UPDATE_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL   *This,
+  IN        EFI_HII_HANDLE               Handle,
+  IN CONST  EFI_HII_PACKAGE_LIST_HEADER *PackageList
+);
+
+
+/**
+
+  This function returns a list of the package handles of the
+  specified type that are currently active in the database. The
+  pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package
+  handles to be listed.
+
+  @param This                 A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageType          Specifies the package type of the packages
+                              to list or EFI_HII_PACKAGE_TYPE_ALL for
+                              all packages to be listed.
+
+  @param PackageGuid          If PackageType is
+                              EFI_HII_PACKAGE_TYPE_GUID, then this is
+                              the pointer to the GUID which must match
+                              the Guid field of
+                              EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
+                              must be NULL.
+
+  @param HandleBufferLength   On input, a pointer to the length
+                              of the handle buffer. On output,
+                              the length of the handle buffer
+                              that is required for the handles found.
+
+  @param Handle               An array of EFI_HII_HANDLE instances returned.
+
+  @retval EFI_SUCCESS           The matching handles are outputed successfully.
+                                HandleBufferLength is updated with the actual length.
+  @retval EFI_BUFFER_TOO_SMALL  The HandleBufferLength parameter
+                                indicates that Handle is too
+                                small to support the number of
+                                handles. HandleBufferLength is
+                                updated with a value that will
+                                enable the data to fit.
+  @retval EFI_NOT_FOUND         No matching handle could be found in database.
+  @retval EFI_INVALID_PARAMETER Handle or HandleBufferLength was NULL.
+  @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but
+                                PackageGuid is not NULL, PackageType is a EFI_HII_
+                                PACKAGE_TYPE_GUID but PackageGuid is NULL.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_LIST_PACKS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        UINT8                     PackageType,
+  IN CONST  EFI_GUID                  *PackageGuid,
+  IN OUT    UINTN                     *HandleBufferLength,
+  OUT       EFI_HII_HANDLE            *Handle
+);
+
+/**
+
+  This function will export one or all package lists in the
+  database to a buffer. For each package list exported, this
+  function will call functions registered with EXPORT_PACK and
+  then copy the package list to the buffer. The registered
+  functions may call EFI_HII_DATABASE_PROTOCOL.UpdatePackageList()
+  to modify the package list before it is copied to the buffer. If
+  the specified BufferSize is too small, then the status
+  EFI_OUT_OF_RESOURCES will be returned and the actual package
+  size will be returned in BufferSize.
+
+  @param This         A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+
+  @param Handle       An EFI_HII_HANDLE  that corresponds to the
+                      desired package list in the HII database to
+                      export or NULL to indicate all package lists
+                      should be exported.
+
+  @param BufferSize   On input, a pointer to the length of the
+                      buffer. On output, the length of the
+                      buffer that is required for the exported
+                      data.
+
+  @param Buffer       A pointer to a buffer that will contain the
+                      results of the export function.
+
+
+  @retval EFI_SUCCESS           Package exported.
+
+  @retval EFI_OUT_OF_RESOURCES  BufferSize is too small to hold the package.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_EXPORT_PACKS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL      *This,
+  IN        EFI_HII_HANDLE                 Handle,
+  IN OUT    UINTN                          *BufferSize,
+  OUT       EFI_HII_PACKAGE_LIST_HEADER    *Buffer
+);
+
+
+/**
+
+
+  This function registers a function which will be called when
+  specified actions related to packages of the specified type
+  occur in the HII database. By registering a function, other
+  HII-related drivers are notified when specific package types
+  are added, removed or updated in the HII database. Each driver
+  or application which registers a notification should use
+  EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before
+  exiting.
+
+
+  @param This             A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageType      The package type. See
+                          EFI_HII_PACKAGE_TYPE_x in EFI_HII_PACKAGE_HEADER.
+
+  @param PackageGuid      If PackageType is
+                          EFI_HII_PACKAGE_TYPE_GUID, then this is
+                          the pointer to the GUID which must match
+                          the Guid field of
+                          EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
+                          must be NULL.
+
+  @param PackageNotifyFn  Points to the function to be called
+                          when the event specified by
+                          NotificationType occurs. See
+                          EFI_HII_DATABASE_NOTIFY.
+
+  @param NotifyType       Describes the types of notification which
+                          this function will be receiving. See
+                          EFI_HII_DATABASE_NOTIFY_TYPE for a
+                          list of types.
+
+  @param NotifyHandle     Points to the unique handle assigned to
+                          the registered notification. Can be used
+                          in EFI_HII_DATABASE_PROTOCOL.UnregisterPack
+                          to stop notifications.
+
+
+  @retval EFI_SUCCESS           Notification registered successfully.
+
+  @retval EFI_OUT_OF_RESOURCES  Unable to allocate necessary
+                                data structures.
+
+  @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when
+                                PackageType is not
+                                EFI_HII_PACKAGE_TYPE_GUID.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_REGISTER_NOTIFY)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL     *This,
+  IN        UINT8                         PackageType,
+  IN CONST  EFI_GUID                      *PackageGuid,
+  IN        EFI_HII_DATABASE_NOTIFY       PackageNotifyFn,
+  IN        EFI_HII_DATABASE_NOTIFY_TYPE  NotifyType,
+  OUT       EFI_HANDLE                    *NotifyHandle
+);
+
+
+/**
+
+  Removes the specified HII database package-related notification.
+
+  @param This                 A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param NotificationHandle   The handle of the notification
+                              function being unregistered.
+
+  @retval EFI_SUCCESS   Successsfully unregistered the notification.
+
+  @retval EFI_NOT_FOUND The incoming notification handle does not exist
+                        in the current hii database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_UNREGISTER_NOTIFY)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HANDLE                NotificationHandle
+);
+
+
+/**
+
+  This routine retrieves an array of GUID values for each keyboard
+  layout that was previously registered in the system.
+
+  @param This                 A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuidBufferLength  On input, a pointer to the length
+                              of the keyboard GUID buffer. On
+                              output, the length of the handle
+                              buffer that is required for the
+                              handles found.
+
+  @param KeyGuidBuffer        An array of keyboard layout GUID
+                              instances returned.
+
+  @retval EFI_SUCCESS           KeyGuidBuffer was updated successfully.
+
+  @retval EFI_BUFFER_TOO_SMALL  The KeyGuidBufferLength
+                                parameter indicates that
+                                KeyGuidBuffer is too small to
+                                support the number of GUIDs.
+                                KeyGuidBufferLength is updated
+                                with a value that will enable
+                                the data to fit.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_FIND_KEYBOARD_LAYOUTS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN OUT    UINT16                    *KeyGuidBufferLength,
+  OUT       EFI_GUID                  *KeyGuidBuffer
+);
+
+
+/**
+
+  This routine retrieves the requested keyboard layout. The layout
+  is a physical description of the keys on a keyboard, and the
+  character(s) that are associated with a particular set of key
+  strokes.
+
+  @param This                   A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuid                A pointer to the unique ID associated with a
+                                given keyboard layout. If KeyGuid is NULL then
+                                the current layout will be retrieved.
+
+  @param KeyboardLayoutLength   On input, a pointer to the length of the
+                                KeyboardLayout buffer.  On output, the length of
+                                the data placed into KeyboardLayout.
+
+  @param KeyboardLayout         A pointer to a buffer containing the
+                                retrieved keyboard layout.
+
+  @retval EFI_SUCCESS   The keyboard layout was retrieved
+                        successfully.
+
+  @retval EFI_NOT_FOUND The requested keyboard layout was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_GET_KEYBOARD_LAYOUT)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN CONST  EFI_GUID                  *KeyGuid,
+  IN OUT UINT16                       *KeyboardLayoutLength,
+  OUT       EFI_HII_KEYBOARD_LAYOUT   *KeyboardLayout
+);
+
+/**
+
+  This routine sets the default keyboard layout to the one
+  referenced by KeyGuid. When this routine is called, an event
+  will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+  group type. This is so that agents which are sensitive to the
+  current keyboard layout being changed can be notified of this
+  change.
+
+  @param This      A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuid   A pointer to the unique ID associated with a
+                   given keyboard layout.
+
+  @retval EFI_SUCCESS    The current keyboard layout was successfully set.
+
+  @retval EFI_NOT_FOUND  The referenced keyboard layout was not
+                         found, so action was taken.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_SET_KEYBOARD_LAYOUT)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN CONST  EFI_GUID                  *KeyGuid
+);
+
+/**
+
+  Return the EFI handle associated with a package list.
+
+  @param This               A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param PackageListHandle  An EFI_HII_HANDLE  that corresponds
+                            to the desired package list in the
+                            HIIdatabase.
+
+  @param DriverHandle       On return, contains the EFI_HANDLE which
+                            was registered with the package list in
+                            NewPackageList().
+
+  @retval EFI_SUCCESS            The DriverHandle was returned successfully.
+
+  @retval EFI_INVALID_PARAMETER  The PackageListHandle was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_GET_PACK_HANDLE)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HII_HANDLE             PackageListHandle,
+  OUT       EFI_HANDLE                *DriverHandle
+);
+
+///
+/// Database manager for HII-related data structures.
+///
+struct _EFI_HII_DATABASE_PROTOCOL {
+  EFI_HII_DATABASE_NEW_PACK           NewPackageList;
+  EFI_HII_DATABASE_REMOVE_PACK        RemovePackageList;
+  EFI_HII_DATABASE_UPDATE_PACK        UpdatePackageList;
+  EFI_HII_DATABASE_LIST_PACKS         ListPackageLists;
+  EFI_HII_DATABASE_EXPORT_PACKS       ExportPackageLists;
+  EFI_HII_DATABASE_REGISTER_NOTIFY    RegisterPackageNotify;
+  EFI_HII_DATABASE_UNREGISTER_NOTIFY  UnregisterPackageNotify;
+  EFI_HII_FIND_KEYBOARD_LAYOUTS       FindKeyboardLayouts;
+  EFI_HII_GET_KEYBOARD_LAYOUT         GetKeyboardLayout;
+  EFI_HII_SET_KEYBOARD_LAYOUT         SetKeyboardLayout;
+  EFI_HII_DATABASE_GET_PACK_HANDLE    GetPackageListHandle;
+};
+
+extern EFI_GUID gEfiHiiDatabaseProtocolGuid;
+
+#endif
+
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/LoadedImage.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/LoadedImage.h
new file mode 100755
index 0000000..cbe4103
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/LoadedImage.h
@@ -0,0 +1,90 @@
+/** @file
+  UEFI 2.0 Loaded image protocol definition.
+
+  Every EFI driver and application is passed an image handle when it is loaded.
+  This image handle will contain a Loaded Image Protocol.
+
+  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __LOADED_IMAGE_PROTOCOL_H__
+#define __LOADED_IMAGE_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_LOADED_IMAGE_PROTOCOL_GUID \
+  { \
+    0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } \
+  }
+
+#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \
+  { \
+    0xbc62157e, 0x3e33, 0x4fec, {0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } \
+  }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define LOADED_IMAGE_PROTOCOL   EFI_LOADED_IMAGE_PROTOCOL_GUID
+
+///
+/// EFI_SYSTEM_TABLE & EFI_IMAGE_UNLOAD are defined in EfiApi.h
+///
+#define EFI_LOADED_IMAGE_PROTOCOL_REVISION  0x1000
+
+///
+/// Revision defined in EFI1.1.
+///
+#define EFI_LOADED_IMAGE_INFORMATION_REVISION    EFI_LOADED_IMAGE_PROTOCOL_REVISION
+
+///
+/// Can be used on any image handle to obtain information about the loaded image.
+///
+typedef struct {
+  UINT32            Revision;       ///< Defines the revision of the EFI_LOADED_IMAGE_PROTOCOL structure.
+                                    ///< All future revisions will be backward compatible to the current revision.
+  EFI_HANDLE        ParentHandle;   ///< Parent image's image handle. NULL if the image is loaded directly from
+                                    ///< the firmware's boot manager.
+  EFI_SYSTEM_TABLE  *SystemTable;   ///< the image's EFI system table pointer.
+
+  //
+  // Source location of image
+  //
+  EFI_HANDLE        DeviceHandle;   ///< The device handle that the EFI Image was loaded from.
+  EFI_DEVICE_PATH_PROTOCOL  *FilePath;  ///< A pointer to the file path portion specific to DeviceHandle
+                                        ///< that the EFI Image was loaded from.
+  VOID              *Reserved;      ///< Reserved. DO NOT USE.
+
+  //
+  // Images load options
+  //
+  UINT32            LoadOptionsSize;///< The size in bytes of LoadOptions.
+  VOID              *LoadOptions;   ///< A pointer to the image's binary load options.
+
+  //
+  // Location of where image was loaded
+  //
+  VOID              *ImageBase;     ///< The base address at which the image was loaded.
+  UINT64            ImageSize;      ///< The size in bytes of the loaded image.
+  EFI_MEMORY_TYPE   ImageCodeType;  ///< The memory type that the code sections were loaded as.
+  EFI_MEMORY_TYPE   ImageDataType;  ///< The memory type that the data sections were loaded as.
+  EFI_IMAGE_UNLOAD  Unload;
+} EFI_LOADED_IMAGE_PROTOCOL;
+
+//
+// For backward-compatible with EFI1.1.
+//
+typedef EFI_LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE;
+
+extern EFI_GUID gEfiLoadedImageProtocolGuid;
+extern EFI_GUID gEfiLoadedImageDevicePathProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h
new file mode 100644
index 0000000..ac86e97
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h
@@ -0,0 +1,93 @@
+/** @file
+  EFI Network Interface Identifier Protocol.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  This Protocol is introduced in EFI Specification 1.10.
+
+**/
+
+#ifndef __EFI_NETWORK_INTERFACE_IDENTIFER_H__
+#define __EFI_NETWORK_INTERFACE_IDENTIFER_H__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// GUID retired from UEFI Specification 2.1b
+//
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID \
+  { \
+    0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29 } \
+  }
+
+//
+// GUID intruduced in UEFI Specification 2.1b
+//
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID_31 \
+  { \
+    0x1ACED566, 0x76ED, 0x4218, {0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } \
+  }
+
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION    0x00010000
+
+///
+/// Revision defined in EFI1.1.
+///
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION
+
+///
+/// Forward reference for pure ANSI compatability.
+///
+typedef struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL   EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE;
+
+///
+/// An optional protocol that is used to describe details about the software
+/// layer that is used to produce the Simple Network Protocol.
+///
+struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL {
+  UINT64    Revision;   ///< The revision of the EFI_NETWORK_INTERFACE_IDENTIFIER protocol.
+  UINT64    Id;         ///< The address of the first byte of the identifying structure for this network
+                        ///< interface. This is only valid when the network interface is started
+                        ///< (see Start()). When the network interface is not started, this field is set to zero.
+  UINT64    ImageAddr;  ///< The address of the first byte of the identifying structure for this
+                        ///< network interface.  This is set to zero if there is no structure.
+  UINT32    ImageSize;  ///< The size of unrelocated network interface image.
+  CHAR8     StringId[4];///< A four-character ASCII string that is sent in the class identifier field of
+                        ///< option 60 in DHCP. For a Type of EfiNetworkInterfaceUndi, this field is UNDI.
+  UINT8     Type;       ///< Network interface type. This will be set to one of the values
+                        ///< in EFI_NETWORK_INTERFACE_TYPE.
+  UINT8     MajorVer;   ///< Major version number.
+  UINT8     MinorVer;   ///< Minor version number.
+  BOOLEAN   Ipv6Supported; ///< TRUE if the network interface supports IPv6; otherwise FALSE.
+  UINT8     IfNum;      ///< The network interface number that is being identified by this Network
+                        ///< Interface Identifier Protocol. This field must be less than or equal
+                        ///< to the IFcnt field in the !PXE structure.
+
+};
+
+///
+///*******************************************************
+/// EFI_NETWORK_INTERFACE_TYPE
+///*******************************************************
+///
+typedef enum {
+  EfiNetworkInterfaceUndi = 1
+} EFI_NETWORK_INTERFACE_TYPE;
+
+extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid;
+extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciIo.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciIo.h
new file mode 100644
index 0000000..97f65e1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciIo.h
@@ -0,0 +1,560 @@
+/** @file
+  EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration,
+  and DMA interfaces that a driver uses to access its PCI controller.
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_IO_H__
+#define __PCI_IO_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Global ID for the PCI I/O Protocol
+///
+#define EFI_PCI_IO_PROTOCOL_GUID \
+  { \
+    0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a } \
+  }
+
+typedef struct _EFI_PCI_IO_PROTOCOL  EFI_PCI_IO_PROTOCOL;
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_WIDTH
+/// *******************************************************
+///
+typedef enum {
+  EfiPciIoWidthUint8      = 0,
+  EfiPciIoWidthUint16,
+  EfiPciIoWidthUint32,
+  EfiPciIoWidthUint64,
+  EfiPciIoWidthFifoUint8,
+  EfiPciIoWidthFifoUint16,
+  EfiPciIoWidthFifoUint32,
+  EfiPciIoWidthFifoUint64,
+  EfiPciIoWidthFillUint8,
+  EfiPciIoWidthFillUint16,
+  EfiPciIoWidthFillUint32,
+  EfiPciIoWidthFillUint64,
+  EfiPciIoWidthMaximum
+} EFI_PCI_IO_PROTOCOL_WIDTH;
+
+//
+// Complete PCI address generater
+//
+#define EFI_PCI_IO_PASS_THROUGH_BAR               0xff    ///< Special BAR that passes a memory or I/O cycle through unchanged
+#define EFI_PCI_IO_ATTRIBUTE_MASK                 0x077f  ///< All the following I/O and Memory cycles
+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO   0x0001  ///< I/O cycles 0x0000-0x00FF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO               0x0002  ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO       0x0004  ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY           0x0008  ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO               0x0010  ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO       0x0020  ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO     0x0040  ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080  ///< Map a memory range so writes are combined
+#define EFI_PCI_IO_ATTRIBUTE_IO                   0x0100  ///< Enable the I/O decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY               0x0200  ///< Enable the Memory decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER           0x0400  ///< Enable the DMA bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED        0x0800  ///< Map a memory range so all r/w accesses are cached
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE       0x1000  ///< Disable a memory range
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE      0x2000  ///< Clear for an add-in PCI Device
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM         0x4000  ///< Clear for a physical PCI Option ROM accessed through ROM BAR
+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE   0x8000  ///< Clear for PCI controllers that can not genrate a DAC
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16            0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16    0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16            0x40000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode)
+
+#define EFI_PCI_DEVICE_ENABLE                     (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)
+#define EFI_VGA_DEVICE_ENABLE                     (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO)
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_OPERATION
+/// *******************************************************
+///
+typedef enum {
+  ///
+  /// A read operation from system memory by a bus master.
+  ///
+  EfiPciIoOperationBusMasterRead,
+  ///
+  /// A write operation from system memory by a bus master.
+  ///
+  EfiPciIoOperationBusMasterWrite,
+  ///
+  /// Provides both read and write access to system memory by both the processor and a
+  /// bus master. The buffer is coherent from both the processor's and the bus master's point of view.
+  ///
+  EfiPciIoOperationBusMasterCommonBuffer,
+  EfiPciIoOperationMaximum
+} EFI_PCI_IO_PROTOCOL_OPERATION;
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION
+/// *******************************************************
+///
+typedef enum {
+  ///
+  /// Retrieve the PCI controller's current attributes, and return them in Result.
+  ///
+  EfiPciIoAttributeOperationGet,
+  ///
+  /// Set the PCI controller's current attributes to Attributes.
+  ///
+  EfiPciIoAttributeOperationSet,
+  ///
+  /// Enable the attributes specified by the bits that are set in Attributes for this PCI controller.
+  ///
+  EfiPciIoAttributeOperationEnable,
+  ///
+  /// Disable the attributes specified by the bits that are set in Attributes for this PCI controller.
+  ///
+  EfiPciIoAttributeOperationDisable,
+  ///
+  /// Retrieve the PCI controller's supported attributes, and return them in Result.
+  ///
+  EfiPciIoAttributeOperationSupported,
+  EfiPciIoAttributeOperationMaximum
+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+
+/**
+  Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+  satisfied or after a defined duration.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Width                 Signifies the width of the memory or I/O operations.
+  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
+                                base address for the memory operation to perform.
+  @param  Offset                The offset within the selected BAR to start the memory operation.
+  @param  Mask                  Mask used for the polling criteria.
+  @param  Value                 The comparison value used for the polling exit criteria.
+  @param  Delay                 The number of 100 ns units to poll.
+  @param  Result                Pointer to the last value read from the memory location.
+
+  @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.
+  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
+  @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this PCI controller.
+  @retval EFI_TIMEOUT           Delay expired before a match occurred.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)(
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN  UINT8                        BarIndex,
+  IN  UINT64                       Offset,
+  IN  UINT64                       Mask,
+  IN  UINT64                       Value,
+  IN  UINT64                       Delay,
+  OUT UINT64                       *Result
+  );
+
+/**
+  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Width                 Signifies the width of the memory or I/O operations.
+  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
+                                base address for the memory or I/O operation to perform.
+  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
+  @param  Count                 The number of memory or I/O operations to perform.
+  @param  Buffer                For read operations, the destination buffer to store the results. For write
+                                operations, the source buffer to write data from.
+
+  @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
+  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
+  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
+                                valid for the PCI BAR specified by BarIndex.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)(
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        BarIndex,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  );
+
+typedef struct {
+  ///
+  /// Read PCI controller registers in the PCI memory or I/O space.
+  ///
+  EFI_PCI_IO_PROTOCOL_IO_MEM  Read;
+  ///
+  /// Write PCI controller registers in the PCI memory or I/O space.
+  ///
+  EFI_PCI_IO_PROTOCOL_IO_MEM  Write;
+} EFI_PCI_IO_PROTOCOL_ACCESS;
+
+/**
+  Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Width                 Signifies the width of the memory operations.
+  @param  Offset                The offset within the PCI configuration space for the PCI controller.
+  @param  Count                 The number of PCI configuration operations to perform.
+  @param  Buffer                For read operations, the destination buffer to store the results. For write
+                                operations, the source buffer to write data from.
+
+
+  @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
+  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
+                                valid for the PCI configuration header of the PCI controller.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)(
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT32                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  );
+
+typedef struct {
+  ///
+  /// Read PCI controller registers in PCI configuration space.
+  ///
+  EFI_PCI_IO_PROTOCOL_CONFIG  Read;
+  ///
+  /// Write PCI controller registers in PCI configuration space.
+  ///
+  EFI_PCI_IO_PROTOCOL_CONFIG  Write;
+} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS;
+
+/**
+  Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+  memory space.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Width                 Signifies the width of the memory operations.
+  @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the
+                                base address for the memory operation to perform.
+  @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to
+                                start the memory writes for the copy operation.
+  @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the
+                                base address for the memory operation to perform.
+  @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start
+                                the memory reads for the copy operation.
+  @param  Count                 The number of memory operations to perform. Bytes moved is Width
+                                size * Count, starting at DestOffset and SrcOffset.
+
+  @retval EFI_SUCCESS           The data was copied from one memory region to another memory region.
+  @retval EFI_UNSUPPORTED       DestBarIndex not valid for this PCI controller.
+  @retval EFI_UNSUPPORTED       SrcBarIndex not valid for this PCI controller.
+  @retval EFI_UNSUPPORTED       The address range specified by DestOffset, Width, and Count
+                                is not valid for the PCI BAR specified by DestBarIndex.
+  @retval EFI_UNSUPPORTED       The address range specified by SrcOffset, Width, and Count is
+                                not valid for the PCI BAR specified by SrcBarIndex.
+  @retval EFI_INVALID_PARAMETER Width is invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)(
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        DestBarIndex,
+  IN     UINT64                       DestOffset,
+  IN     UINT8                        SrcBarIndex,
+  IN     UINT64                       SrcOffset,
+  IN     UINTN                        Count
+  );
+
+/**
+  Provides the PCI controller-specific addresses needed to access system memory.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)(
+  IN EFI_PCI_IO_PROTOCOL                *This,
+  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
+  IN     VOID                           *HostAddress,
+  IN OUT UINTN                          *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
+  OUT    VOID                           **Mapping
+  );
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)(
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  VOID                         *Mapping
+  );
+
+/**
+  Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+  mapping.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)(
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  EFI_ALLOCATE_TYPE            Type,
+  IN  EFI_MEMORY_TYPE              MemoryType,
+  IN  UINTN                        Pages,
+  OUT VOID                         **HostAddress,
+  IN  UINT64                       Attributes
+  );
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)(
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  UINTN                        Pages,
+  IN  VOID                         *HostAddress
+  );
+
+/**
+  Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           The PCI posted write transactions were flushed from the PCI host
+                                bridge to system memory.
+  @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not flushed from the PCI
+                                host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)(
+  IN EFI_PCI_IO_PROTOCOL  *This
+  );
+
+/**
+  Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  SegmentNumber         The PCI controller's current PCI segment number.
+  @param  BusNumber             The PCI controller's current PCI bus number.
+  @param  DeviceNumber          The PCI controller's current PCI device number.
+  @param  FunctionNumber        The PCI controller's current PCI function number.
+
+  @retval EFI_SUCCESS           The PCI controller location was returned.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)(
+  IN EFI_PCI_IO_PROTOCOL          *This,
+  OUT UINTN                       *SegmentNumber,
+  OUT UINTN                       *BusNumber,
+  OUT UINTN                       *DeviceNumber,
+  OUT UINTN                       *FunctionNumber
+  );
+
+/**
+  Performs an operation on the attributes that this PCI controller supports. The operations include
+  getting the set of supported attributes, retrieving the current attributes, setting the current
+  attributes, enabling attributes, and disabling attributes.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Operation             The operation to perform on the attributes for this PCI controller.
+  @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable
+                                operations.
+  @param  Result                A pointer to the result mask of attributes that are returned for the Get
+                                and Supported operations.
+
+  @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_UNSUPPORTED       one or more of the bits set in
+                                Attributes are not supported by this PCI controller or one of
+                                its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)(
+  IN EFI_PCI_IO_PROTOCOL                       *This,
+  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
+  IN  UINT64                                   Attributes,
+  OUT UINT64                                   *Result OPTIONAL
+  );
+
+/**
+  Gets the attributes that this PCI controller supports setting on a BAR using
+  SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
+                                base address for resource range. The legal range for this field is 0..5.
+  @param  Supports              A pointer to the mask of attributes that this PCI controller supports
+                                setting for this BAR with SetBarAttributes().
+  @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
+                                configuration of this BAR of the PCI controller.
+
+  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI
+                                controller supports are returned in Supports. If Resources
+                                is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+                                controller is currently using are returned in Resources.
+  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate
+                                Resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)(
+  IN EFI_PCI_IO_PROTOCOL             *This,
+  IN  UINT8                          BarIndex,
+  OUT UINT64                         *Supports, OPTIONAL
+  OUT VOID                           **Resources OPTIONAL
+  );
+
+/**
+  Sets the attributes for a range of a BAR on a PCI controller.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Attributes            The mask of attributes to set for the resource range specified by
+                                BarIndex, Offset, and Length.
+  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
+                                base address for resource range. The legal range for this field is 0..5.
+  @param  Offset                A pointer to the BAR relative base address of the resource range to be
+                                modified by the attributes specified by Attributes.
+  @param  Length                A pointer to the length of the resource range to be modified by the
+                                attributes specified by Attributes.
+
+  @retval EFI_SUCCESS           The set of attributes specified by Attributes for the resource
+                                range specified by BarIndex, Offset, and Length were
+                                set on the PCI controller, and the actual resource range is returned
+                                in Offset and Length.
+  @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the attributes on the
+                                resource range specified by BarIndex, Offset, and
+                                Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)(
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     UINT64                       Attributes,
+  IN     UINT8                        BarIndex,
+  IN OUT UINT64                       *Offset,
+  IN OUT UINT64                       *Length
+  );
+
+///
+/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration,
+/// and DMA interfaces used to abstract accesses to PCI controllers.
+/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus.
+/// A device driver that wishes to manage a PCI controller in a system will have to
+/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller.
+///
+struct _EFI_PCI_IO_PROTOCOL {
+  EFI_PCI_IO_PROTOCOL_POLL_IO_MEM         PollMem;
+  EFI_PCI_IO_PROTOCOL_POLL_IO_MEM         PollIo;
+  EFI_PCI_IO_PROTOCOL_ACCESS              Mem;
+  EFI_PCI_IO_PROTOCOL_ACCESS              Io;
+  EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS       Pci;
+  EFI_PCI_IO_PROTOCOL_COPY_MEM            CopyMem;
+  EFI_PCI_IO_PROTOCOL_MAP                 Map;
+  EFI_PCI_IO_PROTOCOL_UNMAP               Unmap;
+  EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER     AllocateBuffer;
+  EFI_PCI_IO_PROTOCOL_FREE_BUFFER         FreeBuffer;
+  EFI_PCI_IO_PROTOCOL_FLUSH               Flush;
+  EFI_PCI_IO_PROTOCOL_GET_LOCATION        GetLocation;
+  EFI_PCI_IO_PROTOCOL_ATTRIBUTES          Attributes;
+  EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES  GetBarAttributes;
+  EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES  SetBarAttributes;
+
+  ///
+  /// The size, in bytes, of the ROM image.
+  ///
+  UINT64                                  RomSize;
+
+  ///
+  /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible
+  /// for allocating memory for the ROM image, and copying the contents of the ROM to memory.
+  /// The contents of this buffer are either from the PCI option ROM that can be accessed
+  /// through the ROM BAR of the PCI controller, or it is from a platform-specific location.
+  /// The Attributes() function can be used to determine from which of these two sources
+  /// the RomImage buffer was initialized.
+  ///
+  VOID                                    *RomImage;
+};
+
+extern EFI_GUID gEfiPciIoProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h
new file mode 100644
index 0000000..e8feea0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h
@@ -0,0 +1,438 @@
+/** @file
+  PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification.
+
+  PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O,
+  and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform
+  defferent types of bus mastering DMA.
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_ROOT_BRIDGE_IO_H__
+#define __PCI_ROOT_BRIDGE_IO_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
+  { \
+    0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+  }
+
+typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+
+///
+/// *******************************************************
+/// EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
+/// *******************************************************
+///
+typedef enum {
+  EfiPciWidthUint8,
+  EfiPciWidthUint16,
+  EfiPciWidthUint32,
+  EfiPciWidthUint64,
+  EfiPciWidthFifoUint8,
+  EfiPciWidthFifoUint16,
+  EfiPciWidthFifoUint32,
+  EfiPciWidthFifoUint64,
+  EfiPciWidthFillUint8,
+  EfiPciWidthFillUint16,
+  EfiPciWidthFillUint32,
+  EfiPciWidthFillUint64,
+  EfiPciWidthMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
+
+///
+/// *******************************************************
+/// EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION
+/// *******************************************************
+///
+typedef enum {
+  ///
+  /// A read operation from system memory by a bus master that is not capable of producing
+  /// PCI dual address cycles.
+  ///
+  EfiPciOperationBusMasterRead,
+  ///
+  /// A write operation from system memory by a bus master that is not capable of producing
+  /// PCI dual address cycles.
+  ///
+  EfiPciOperationBusMasterWrite,
+  ///
+  /// Provides both read and write access to system memory by both the processor and a bus
+  /// master that is not capable of producing PCI dual address cycles.
+  ///
+  EfiPciOperationBusMasterCommonBuffer,
+  ///
+  /// A read operation from system memory by a bus master that is capable of producing PCI
+  /// dual address cycles.
+  ///
+  EfiPciOperationBusMasterRead64,
+  ///
+  /// A write operation to system memory by a bus master that is capable of producing PCI
+  /// dual address cycles.
+  ///
+  EfiPciOperationBusMasterWrite64,
+  ///
+  /// Provides both read and write access to system memory by both the processor and a bus
+  /// master that is capable of producing PCI dual address cycles.
+  ///
+  EfiPciOperationBusMasterCommonBuffer64,
+  EfiPciOperationMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION;
+
+#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO          0x0001
+#define EFI_PCI_ATTRIBUTE_ISA_IO                      0x0002
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO              0x0004
+#define EFI_PCI_ATTRIBUTE_VGA_MEMORY                  0x0008
+#define EFI_PCI_ATTRIBUTE_VGA_IO                      0x0010
+#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO              0x0020
+#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO            0x0040
+#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE        0x0080
+#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED               0x0800
+#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE              0x1000
+#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE          0x8000
+#define EFI_PCI_ATTRIBUTE_ISA_IO_16                   0x10000
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16           0x20000
+#define EFI_PCI_ATTRIBUTE_VGA_IO_16                   0x40000
+
+#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER   (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER)
+
+#define EFI_PCI_ADDRESS(bus, dev, func, reg) \
+    ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg)))
+
+typedef struct {
+  UINT8   Register;
+  UINT8   Function;
+  UINT8   Device;
+  UINT8   Bus;
+  UINT32  ExtendedRegister;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS;
+
+/**
+  Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is
+  satisfied or after a defined duration.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Width                 Signifies the width of the memory or I/O operations.
+  @param  Address               The base address of the memory or I/O operations.
+  @param  Mask                  Mask used for the polling criteria.
+  @param  Value                 The comparison value used for the polling exit criteria.
+  @param  Delay                 The number of 100 ns units to poll.
+  @param  Result                Pointer to the last value read from the memory location.
+
+  @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.
+  @retval EFI_TIMEOUT           Delay expired before a match occurred.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
+  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
+  IN  UINT64                                   Address,
+  IN  UINT64                                   Mask,
+  IN  UINT64                                   Value,
+  IN  UINT64                                   Delay,
+  OUT UINT64                                   *Result
+  );
+
+/**
+  Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Width                 Signifies the width of the memory operations.
+  @param  Address               The base address of the memory operations.
+  @param  Count                 The number of memory operations to perform.
+  @param  Buffer                For read operations, the destination buffer to store the results. For write
+                                operations, the source buffer to write data from.
+
+  @retval EFI_SUCCESS           The data was read from or written to the PCI root bridge.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
+  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT64                                   Address,
+  IN     UINTN                                    Count,
+  IN OUT VOID                                     *Buffer
+  );
+
+typedef struct {
+  ///
+  /// Read PCI controller registers in the PCI root bridge memory space.
+  ///
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM  Read;
+  ///
+  /// Write PCI controller registers in the PCI root bridge memory space.
+  ///
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM  Write;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
+
+/**
+  Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI
+  root bridge memory space.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+  @param  Width                 Signifies the width of the memory operations.
+  @param  DestAddress           The destination address of the memory operation.
+  @param  SrcAddress            The source address of the memory operation.
+  @param  Count                 The number of memory operations to perform.
+
+  @retval EFI_SUCCESS           The data was copied from one memory region to another memory region.
+  @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
+  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT64                                   DestAddress,
+  IN     UINT64                                   SrcAddress,
+  IN     UINTN                                    Count
+  );
+
+/**
+  Provides the PCI controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL                *This,
+  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION  Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  );
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
+  IN  VOID                                     *Mapping
+  );
+
+/**
+  Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or
+  EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
+  IN     EFI_ALLOCATE_TYPE                        Type,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  );
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  );
+
+/**
+  Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+  @retval EFI_SUCCESS           The PCI posted write transactions were flushed from the PCI host
+                                bridge to system memory.
+  @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not flushed from the PCI
+                                host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This
+  );
+
+/**
+  Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the
+  attributes that a PCI root bridge is currently using.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Supports              A pointer to the mask of attributes that this PCI root bridge supports
+                                setting with SetAttributes().
+  @param  Attributes            A pointer to the mask of attributes that this PCI root bridge is currently
+                                using.
+
+  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI root
+                                bridge supports is returned in Supports. If Attributes is
+                                not NULL, then the attributes that the PCI root bridge is currently
+                                using is returned in Attributes.
+  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
+  OUT UINT64                                   *Supports,
+  OUT UINT64                                   *Attributes
+  );
+
+/**
+  Sets attributes for a resource range on a PCI root bridge.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Attributes            The mask of attributes to set.
+  @param  ResourceBase          A pointer to the base address of the resource range to be modified by the
+                                attributes specified by Attributes.
+  @param  ResourceLength        A pointer to the length of the resource range to be modified by the
+                                attributes specified by Attributes.
+
+  @retval EFI_SUCCESS           The set of attributes specified by Attributes for the resource
+                                range specified by ResourceBase and ResourceLength
+                                were set on the PCI root bridge, and the actual resource range is
+                                returned in ResuourceBase and ResourceLength.
+  @retval EFI_UNSUPPORTED       A bit is set in Attributes that is not supported by the PCI Root
+                                Bridge.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the attributes on the
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)(
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
+  IN     UINT64                                   Attributes,
+  IN OUT UINT64                                   *ResourceBase,
+  IN OUT UINT64                                   *ResourceLength
+  );
+
+/**
+  Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0
+  resource descriptors.
+
+  @param  This                  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+  @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
+                                configuration of this PCI root bridge.
+
+  @retval EFI_SUCCESS           The current configuration of this PCI root bridge was returned in
+                                Resources.
+  @retval EFI_UNSUPPORTED       The current configuration of this PCI root bridge could not be
+                                retrieved.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)(
+  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL          *This,
+  OUT VOID                                     **Resources
+  );
+
+///
+/// Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are
+/// used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller.
+///
+struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+  ///
+  /// The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member.
+  ///
+  EFI_HANDLE                                      ParentHandle;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM     PollMem;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM     PollIo;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Mem;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Io;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS          Pci;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM        CopyMem;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP             Map;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP           Unmap;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER     FreeBuffer;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH           Flush;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES  GetAttributes;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES  SetAttributes;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION   Configuration;
+
+  ///
+  /// The segment number that this PCI root bridge resides.
+  ///
+  UINT32                                          SegmentNumber;
+};
+
+extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleNetwork.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleNetwork.h
new file mode 100644
index 0000000..2b521a9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleNetwork.h
@@ -0,0 +1,664 @@
+/** @file
+  The EFI_SIMPLE_NETWORK_PROTOCOL provides services to initialize a network interface,
+  transmit packets, receive packets, and close a network interface.
+
+  Basic network device abstraction.
+
+  Rx    - Received
+  Tx    - Transmit
+  MCast - MultiCast
+  ...
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  This Protocol is introduced in EFI Specification 1.10.
+
+**/
+
+#ifndef __SIMPLE_NETWORK_H__
+#define __SIMPLE_NETWORK_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \
+  { \
+    0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } \
+  }
+
+typedef struct _EFI_SIMPLE_NETWORK_PROTOCOL  EFI_SIMPLE_NETWORK_PROTOCOL;
+
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_SIMPLE_NETWORK_PROTOCOL   EFI_SIMPLE_NETWORK;
+
+///
+/// Simple Network Protocol data structures.
+///
+typedef struct {
+  ///
+  /// Total number of frames received.  Includes frames with errors and
+  /// dropped frames.
+  ///
+  UINT64  RxTotalFrames;
+
+  ///
+  /// Number of valid frames received and copied into receive buffers.
+  ///
+  UINT64  RxGoodFrames;
+
+  ///
+  /// Number of frames below the minimum length for the media.
+  /// This would be <64 for ethernet.
+  ///
+  UINT64  RxUndersizeFrames;
+
+  ///
+  /// Number of frames longer than the maxminum length for the
+  /// media.  This would be >1500 for ethernet.
+  ///
+  UINT64  RxOversizeFrames;
+
+  ///
+  /// Valid frames that were dropped because receive buffers were full.
+  ///
+  UINT64  RxDroppedFrames;
+
+  ///
+  /// Number of valid unicast frames received and not dropped.
+  ///
+  UINT64  RxUnicastFrames;
+
+  ///
+  /// Number of valid broadcast frames received and not dropped.
+  ///
+  UINT64  RxBroadcastFrames;
+
+  ///
+  /// Number of valid mutlicast frames received and not dropped.
+  ///
+  UINT64  RxMulticastFrames;
+
+  ///
+  /// Number of frames w/ CRC or alignment errors.
+  ///
+  UINT64  RxCrcErrorFrames;
+
+  ///
+  /// Total number of bytes received.  Includes frames with errors
+  /// and dropped frames.
+  //
+  UINT64  RxTotalBytes;
+
+  ///
+  /// Transmit statistics.
+  ///
+  UINT64  TxTotalFrames;
+  UINT64  TxGoodFrames;
+  UINT64  TxUndersizeFrames;
+  UINT64  TxOversizeFrames;
+  UINT64  TxDroppedFrames;
+  UINT64  TxUnicastFrames;
+  UINT64  TxBroadcastFrames;
+  UINT64  TxMulticastFrames;
+  UINT64  TxCrcErrorFrames;
+  UINT64  TxTotalBytes;
+
+  ///
+  /// Number of collisions detection on this subnet.
+  ///
+  UINT64  Collisions;
+
+  ///
+  /// Number of frames destined for unsupported protocol.
+  ///
+  UINT64  UnsupportedProtocol;
+
+} EFI_NETWORK_STATISTICS;
+
+///
+/// The state of the network interface.
+/// When an EFI_SIMPLE_NETWORK_PROTOCOL driver initializes a
+/// network interface, the network interface is left in the EfiSimpleNetworkStopped state.
+///
+typedef enum {
+  EfiSimpleNetworkStopped,
+  EfiSimpleNetworkStarted,
+  EfiSimpleNetworkInitialized,
+  EfiSimpleNetworkMaxState
+} EFI_SIMPLE_NETWORK_STATE;
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST                0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST              0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST              0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS            0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST  0x10
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT              0x01
+#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT             0x02
+#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT              0x04
+#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT             0x08
+
+#define MAX_MCAST_FILTER_CNT                              16
+typedef struct {
+  ///
+  /// Reports the current state of the network interface.
+  ///
+  UINT32          State;
+  ///
+  /// The size, in bytes, of the network interface's HW address.
+  ///
+  UINT32          HwAddressSize;
+  ///
+  /// The size, in bytes, of the network interface's media header.
+  ///
+  UINT32          MediaHeaderSize;
+  ///
+  /// The maximum size, in bytes, of the packets supported by the network interface.
+  ///
+  UINT32          MaxPacketSize;
+  ///
+  /// The size, in bytes, of the NVRAM device attached to the network interface.
+  ///
+  UINT32          NvRamSize;
+  ///
+  /// The size that must be used for all NVRAM reads and writes. The
+  /// start address for NVRAM read and write operations and the total
+  /// length of those operations, must be a multiple of this value. The
+  /// legal values for this field are 0, 1, 2, 4, and 8.
+  ///
+  UINT32          NvRamAccessSize;
+  ///
+  /// The multicast receive filter settings supported by the network interface.
+  ///
+  UINT32          ReceiveFilterMask;
+  ///
+  /// The current multicast receive filter settings.
+  ///
+  UINT32          ReceiveFilterSetting;
+  ///
+  /// The maximum number of multicast address receive filters supported by the driver.
+  ///
+  UINT32          MaxMCastFilterCount;
+  ///
+  /// The current number of multicast address receive filters.
+  ///
+  UINT32          MCastFilterCount;
+  ///
+  /// Array containing the addresses of the current multicast address receive filters.
+  ///
+  EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT];
+  ///
+  /// The current HW MAC address for the network interface.
+  ///
+  EFI_MAC_ADDRESS CurrentAddress;
+  ///
+  /// The current HW MAC address for broadcast packets.
+  ///
+  EFI_MAC_ADDRESS BroadcastAddress;
+  ///
+  /// The permanent HW MAC address for the network interface.
+  ///
+  EFI_MAC_ADDRESS PermanentAddress;
+  ///
+  /// The interface type of the network interface.
+  ///
+  UINT8           IfType;
+  ///
+  /// TRUE if the HW MAC address can be changed.
+  ///
+  BOOLEAN         MacAddressChangeable;
+  ///
+  /// TRUE if the network interface can transmit more than one packet at a time.
+  ///
+  BOOLEAN         MultipleTxSupported;
+  ///
+  /// TRUE if the presence of media can be determined; otherwise FALSE.
+  ///
+  BOOLEAN         MediaPresentSupported;
+  ///
+  /// TRUE if media are connected to the network interface; otherwise FALSE.
+  ///
+  BOOLEAN         MediaPresent;
+} EFI_SIMPLE_NETWORK_MODE;
+
+//
+// Protocol Member Functions
+//
+/**
+  Changes the state of a network interface from "stopped" to "started".
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was started.
+  @retval EFI_ALREADY_STARTED   The network interface is already in the started state.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_START)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This
+  );
+
+/**
+  Changes the state of a network interface from "started" to "stopped".
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was stopped.
+  @retval EFI_ALREADY_STARTED   The network interface is already in the stopped state.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STOP)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This
+  );
+
+/**
+  Resets a network adapter and allocates the transmit and receive buffers
+  required by the network interface; optionally, also requests allocation
+  of additional transmit and receive buffers.
+
+  @param  This              The protocol instance pointer.
+  @param  ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+                            that the driver should allocate for the network interface.
+                            Some network interfaces will not be able to use the extra
+                            buffer, and the caller will not know if it is actually
+                            being used.
+  @param  ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+                            that the driver should allocate for the network interface.
+                            Some network interfaces will not be able to use the extra
+                            buffer, and the caller will not know if it is actually
+                            being used.
+
+  @retval EFI_SUCCESS           The network interface was initialized.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_OUT_OF_RESOURCES  There was not enough memory for the transmit and
+                                receive buffers.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL                    *This,
+  IN UINTN                                          ExtraRxBufferSize  OPTIONAL,
+  IN UINTN                                          ExtraTxBufferSize  OPTIONAL
+  );
+
+/**
+  Resets a network adapter and re-initializes it with the parameters that were
+  provided in the previous call to Initialize().
+
+  @param  This                 The protocol instance pointer.
+  @param  ExtendedVerification Indicates that the driver may perform a more
+                               exhaustive verification operation of the device
+                               during reset.
+
+  @retval EFI_SUCCESS           The network interface was reset.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RESET)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL   *This,
+  IN BOOLEAN                       ExtendedVerification
+  );
+
+/**
+  Resets a network adapter and leaves it in a state that is safe for
+  another driver to initialize.
+
+  @param  This Protocol instance pointer.
+
+  @retval EFI_SUCCESS           The network interface was shutdown.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *This
+  );
+
+/**
+  Manages the multicast receive filters of a network interface.
+
+  @param  This             The protocol instance pointer.
+  @param  Enable           A bit mask of receive filters to enable on the network interface.
+  @param  Disable          A bit mask of receive filters to disable on the network interface.
+  @param  ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+                           filters on the network interface to their default values.
+  @param  McastFilterCnt   Number of multicast HW MAC addresses in the new
+                           MCastFilter list. This value must be less than or equal to
+                           the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This
+                           field is optional if ResetMCastFilter is TRUE.
+  @param  MCastFilter      A pointer to a list of new multicast receive filter HW MAC
+                           addresses. This list will replace any existing multicast
+                           HW MAC address list. This field is optional if
+                           ResetMCastFilter is TRUE.
+
+  @retval EFI_SUCCESS           The multicast receive filter list was updated.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL                             *This,
+  IN UINT32                                                  Enable,
+  IN UINT32                                                  Disable,
+  IN BOOLEAN                                                 ResetMCastFilter,
+  IN UINTN                                                   MCastFilterCnt     OPTIONAL,
+  IN EFI_MAC_ADDRESS                                         *MCastFilter OPTIONAL
+  );
+
+/**
+  Modifies or resets the current station address, if supported.
+
+  @param  This  The protocol instance pointer.
+  @param  Reset Flag used to reset the station address to the network interfaces
+                permanent address.
+  @param  New   The new station address to be used for the network interface.
+
+  @retval EFI_SUCCESS           The network interfaces station address was updated.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL            *This,
+  IN BOOLEAN                                Reset,
+  IN EFI_MAC_ADDRESS                        *New OPTIONAL
+  );
+
+/**
+  Resets or collects the statistics on a network interface.
+
+  @param  This            Protocol instance pointer.
+  @param  Reset           Set to TRUE to reset the statistics for the network interface.
+  @param  StatisticsSize  On input the size, in bytes, of StatisticsTable. On
+                          output the size, in bytes, of the resulting table of
+                          statistics.
+  @param  StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+                          contains the statistics.
+
+  @retval EFI_SUCCESS           The statistics were collected from the network interface.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer
+                                size needed to hold the statistics is returned in
+                                StatisticsSize.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  IN BOOLEAN                              Reset,
+  IN OUT UINTN                            *StatisticsSize   OPTIONAL,
+  OUT EFI_NETWORK_STATISTICS              *StatisticsTable  OPTIONAL
+  );
+
+/**
+  Converts a multicast IP address to a multicast HW MAC address.
+
+  @param  This The protocol instance pointer.
+  @param  IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+               to FALSE if the multicast IP address is IPv4 [RFC 791].
+  @param  IP   The multicast IP address that is to be converted to a multicast
+               HW MAC address.
+  @param  MAC  The multicast HW MAC address that is to be generated from IP.
+
+  @retval EFI_SUCCESS           The multicast IP address was mapped to the multicast
+                                HW MAC address.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer
+                                size needed to hold the statistics is returned in
+                                StatisticsSize.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  IN BOOLEAN                              IPv6,
+  IN EFI_IP_ADDRESS                       *IP,
+  OUT EFI_MAC_ADDRESS                     *MAC
+  );
+
+/**
+  Performs read and write operations on the NVRAM device attached to a
+  network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  ReadWrite  TRUE for read operations, FALSE for write operations.
+  @param  Offset     Byte offset in the NVRAM device at which to start the read or
+                     write operation. This must be a multiple of NvRamAccessSize and
+                     less than NvRamSize.
+  @param  BufferSize The number of bytes to read or write from the NVRAM device.
+                     This must also be a multiple of NvramAccessSize.
+  @param  Buffer     A pointer to the data buffer.
+
+  @retval EFI_SUCCESS           The NVRAM access was performed.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  IN BOOLEAN                              ReadWrite,
+  IN UINTN                                Offset,
+  IN UINTN                                BufferSize,
+  IN OUT VOID                             *Buffer
+  );
+
+/**
+  Reads the current interrupt status and recycled transmit buffer status from
+  a network interface.
+
+  @param  This            The protocol instance pointer.
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts
+                          If this is NULL, the interrupt status will not be read from
+                          the device. If this is not NULL, the interrupt status will
+                          be read from the device. When the  interrupt status is read,
+                          it will also be cleared. Clearing the transmit  interrupt
+                          does not empty the recycled transmit buffer array.
+  @param  TxBuf           Recycled transmit buffer address. The network interface will
+                          not transmit if its internal recycled transmit buffer array
+                          is full. Reading the transmit buffer does not clear the
+                          transmit interrupt. If this is NULL, then the transmit buffer
+                          status will not be read. If there are no transmit buffers to
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+  @retval EFI_SUCCESS           The status of the network interface was retrieved.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  OUT UINT32                              *InterruptStatus OPTIONAL,
+  OUT VOID                                **TxBuf OPTIONAL
+  );
+
+/**
+  Places a packet in the transmit queue of a network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by
+                     the Transmit() function. If HeaderSize is non-zero, then it
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr
+                     and Protocol parameters must not be NULL.
+  @param  BufferSize The size, in bytes, of the entire packet (media header and
+                     data) to be transmitted through the network interface.
+  @param  Buffer     A pointer to the packet (media header followed by data) to be
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+                     then the media header in Buffer must already be filled in by the
+                     caller. If HeaderSize is non-zero, then the media header will be
+                     filled in by the Transmit() function.
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+                     This->Mode->CurrentAddress is used for the source HW MAC address.
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this
+                     parameter is ignored.
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this
+                     parameter is ignored. See RFC 1700, section "Ether Types", for
+                     examples.
+
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.
+  @retval EFI_NOT_STARTED       The network interface has not been started.
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  IN UINTN                                HeaderSize,
+  IN UINTN                                BufferSize,
+  IN VOID                                 *Buffer,
+  IN EFI_MAC_ADDRESS                      *SrcAddr  OPTIONAL,
+  IN EFI_MAC_ADDRESS                      *DestAddr OPTIONAL,
+  IN UINT16                               *Protocol OPTIONAL
+  );
+
+/**
+  Receives a packet from a network interface.
+
+  @param  This       The protocol instance pointer.
+  @param  HeaderSize The size, in bytes, of the media header received on the network
+                     interface. If this parameter is NULL, then the media header size
+                     will not be returned.
+  @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+                     bytes, of the packet that was received on the network interface.
+  @param  Buffer     A pointer to the data buffer to receive both the media header and
+                     the data.
+  @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the
+                     HW MAC source address will not be extracted from the media
+                     header.
+  @param  DestAddr   The destination HW MAC address. If this parameter is NULL,
+                     the HW MAC destination address will not be extracted from the
+                     media header.
+  @param  Protocol   The media header type. If this parameter is NULL, then the
+                     protocol will not be extracted from the media header. See
+                     RFC 1700 section "Ether Types" for examples.
+
+  @retval  EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has
+                                 been updated to the number of bytes received.
+  @retval  EFI_NOT_STARTED       The network interface has not been started.
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit
+                                 request.
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE)(
+  IN EFI_SIMPLE_NETWORK_PROTOCOL          *This,
+  OUT UINTN                               *HeaderSize OPTIONAL,
+  IN OUT UINTN                            *BufferSize,
+  OUT VOID                                *Buffer,
+  OUT EFI_MAC_ADDRESS                     *SrcAddr    OPTIONAL,
+  OUT EFI_MAC_ADDRESS                     *DestAddr   OPTIONAL,
+  OUT UINT16                              *Protocol   OPTIONAL
+  );
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION  0x00010000
+
+//
+// Revision defined in EFI1.1
+//
+#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION   EFI_SIMPLE_NETWORK_PROTOCOL_REVISION
+
+///
+/// The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access
+/// to a network adapter. Once the network adapter initializes,
+/// the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that
+/// allow packets to be transmitted and received.
+///
+struct _EFI_SIMPLE_NETWORK_PROTOCOL {
+  ///
+  /// Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must
+  /// be backwards compatible. If a future version is not backwards compatible
+  /// it is not the same GUID.
+  ///
+  UINT64                              Revision;
+  EFI_SIMPLE_NETWORK_START            Start;
+  EFI_SIMPLE_NETWORK_STOP             Stop;
+  EFI_SIMPLE_NETWORK_INITIALIZE       Initialize;
+  EFI_SIMPLE_NETWORK_RESET            Reset;
+  EFI_SIMPLE_NETWORK_SHUTDOWN         Shutdown;
+  EFI_SIMPLE_NETWORK_RECEIVE_FILTERS  ReceiveFilters;
+  EFI_SIMPLE_NETWORK_STATION_ADDRESS  StationAddress;
+  EFI_SIMPLE_NETWORK_STATISTICS       Statistics;
+  EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC  MCastIpToMac;
+  EFI_SIMPLE_NETWORK_NVDATA           NvData;
+  EFI_SIMPLE_NETWORK_GET_STATUS       GetStatus;
+  EFI_SIMPLE_NETWORK_TRANSMIT         Transmit;
+  EFI_SIMPLE_NETWORK_RECEIVE          Receive;
+  ///
+  /// Event used with WaitForEvent() to wait for a packet to be received.
+  ///
+  EFI_EVENT                           WaitForPacket;
+  ///
+  /// Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.
+  ///
+  EFI_SIMPLE_NETWORK_MODE             *Mode;
+};
+
+extern EFI_GUID gEfiSimpleNetworkProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h
new file mode 100644
index 0000000..a89a9b4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h
@@ -0,0 +1,138 @@
+/** @file
+  Simple Text Input protocol from the UEFI 2.0 specification.
+
+  Abstraction of a very simple input device like a keyboard or serial
+  terminal.
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_IN_PROTOCOL_H__
+#define __SIMPLE_TEXT_IN_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
+  { \
+    0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL  EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+
+///
+/// Protocol GUID name defined in EFI1.1.
+///
+#define SIMPLE_INPUT_PROTOCOL   EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID
+
+///
+/// Protocol name in EFI1.1 for backward-compatible.
+///
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL  SIMPLE_INPUT_INTERFACE;
+
+///
+/// The keystroke information for the key that was pressed.
+///
+typedef struct {
+  UINT16  ScanCode;
+  CHAR16  UnicodeChar;
+} EFI_INPUT_KEY;
+
+//
+// Required unicode control chars
+//
+#define CHAR_NULL             0x0000
+#define CHAR_BACKSPACE        0x0008
+#define CHAR_TAB              0x0009
+#define CHAR_LINEFEED         0x000A
+#define CHAR_CARRIAGE_RETURN  0x000D
+
+//
+// EFI Scan codes
+//
+#define SCAN_NULL       0x0000
+#define SCAN_UP         0x0001
+#define SCAN_DOWN       0x0002
+#define SCAN_RIGHT      0x0003
+#define SCAN_LEFT       0x0004
+#define SCAN_HOME       0x0005
+#define SCAN_END        0x0006
+#define SCAN_INSERT     0x0007
+#define SCAN_DELETE     0x0008
+#define SCAN_PAGE_UP    0x0009
+#define SCAN_PAGE_DOWN  0x000A
+#define SCAN_F1         0x000B
+#define SCAN_F2         0x000C
+#define SCAN_F3         0x000D
+#define SCAN_F4         0x000E
+#define SCAN_F5         0x000F
+#define SCAN_F6         0x0010
+#define SCAN_F7         0x0011
+#define SCAN_F8         0x0012
+#define SCAN_F9         0x0013
+#define SCAN_F10        0x0014
+#define SCAN_F11        0x0015
+#define SCAN_F12        0x0016
+#define SCAN_ESC        0x0017
+
+/**
+  Reset the input device and optionally run diagnostics
+
+  @param  This                 Protocol instance pointer.
+  @param  ExtendedVerification Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS          The device was reset.
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET)(
+  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL       *This,
+  IN BOOLEAN                              ExtendedVerification
+  );
+
+/**
+  Reads the next keystroke from the input device. The WaitForKey Event can
+  be used to test for existence of a keystroke via WaitForEvent () call.
+
+  @param  This  Protocol instance pointer.
+  @param  Key   A pointer to a buffer that is filled in with the keystroke
+                information for the key that was pressed.
+
+  @retval EFI_SUCCESS      The keystroke information was returned.
+  @retval EFI_NOT_READY    There was no keystroke data available.
+  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+                           hardware errors.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY)(
+  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL       *This,
+  OUT EFI_INPUT_KEY                       *Key
+  );
+
+///
+/// The EFI_SIMPLE_TEXT_INPUT_PROTOCOL is used on the ConsoleIn device.
+/// It is the minimum required protocol for ConsoleIn.
+///
+struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+  EFI_INPUT_RESET     Reset;
+  EFI_INPUT_READ_KEY  ReadKeyStroke;
+  ///
+  /// Event to use with WaitForEvent() to wait for a key to be available
+  ///
+  EFI_EVENT           WaitForKey;
+};
+
+extern EFI_GUID gEfiSimpleTextInProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextOut.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextOut.h
new file mode 100644
index 0000000..a79cf43
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextOut.h
@@ -0,0 +1,406 @@
+/** @file
+  Simple Text Out protocol from the UEFI 2.0 specification.
+
+  Abstraction of a very simple text based output device like VGA text mode or
+  a serial terminal. The Simple Text Out protocol instance can represent
+  a single hardware device or a virtual device that is an aggregation
+  of multiple physical devices.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_OUT_H__
+#define __SIMPLE_TEXT_OUT_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
+  { \
+    0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define SIMPLE_TEXT_OUTPUT_PROTOCOL   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID
+
+typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1.
+///
+typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   SIMPLE_TEXT_OUTPUT_INTERFACE;
+
+//
+// Define's for required EFI Unicode Box Draw characters
+//
+#define BOXDRAW_HORIZONTAL                  0x2500
+#define BOXDRAW_VERTICAL                    0x2502
+#define BOXDRAW_DOWN_RIGHT                  0x250c
+#define BOXDRAW_DOWN_LEFT                   0x2510
+#define BOXDRAW_UP_RIGHT                    0x2514
+#define BOXDRAW_UP_LEFT                     0x2518
+#define BOXDRAW_VERTICAL_RIGHT              0x251c
+#define BOXDRAW_VERTICAL_LEFT               0x2524
+#define BOXDRAW_DOWN_HORIZONTAL             0x252c
+#define BOXDRAW_UP_HORIZONTAL               0x2534
+#define BOXDRAW_VERTICAL_HORIZONTAL         0x253c
+#define BOXDRAW_DOUBLE_HORIZONTAL           0x2550
+#define BOXDRAW_DOUBLE_VERTICAL             0x2551
+#define BOXDRAW_DOWN_RIGHT_DOUBLE           0x2552
+#define BOXDRAW_DOWN_DOUBLE_RIGHT           0x2553
+#define BOXDRAW_DOUBLE_DOWN_RIGHT           0x2554
+#define BOXDRAW_DOWN_LEFT_DOUBLE            0x2555
+#define BOXDRAW_DOWN_DOUBLE_LEFT            0x2556
+#define BOXDRAW_DOUBLE_DOWN_LEFT            0x2557
+#define BOXDRAW_UP_RIGHT_DOUBLE             0x2558
+#define BOXDRAW_UP_DOUBLE_RIGHT             0x2559
+#define BOXDRAW_DOUBLE_UP_RIGHT             0x255a
+#define BOXDRAW_UP_LEFT_DOUBLE              0x255b
+#define BOXDRAW_UP_DOUBLE_LEFT              0x255c
+#define BOXDRAW_DOUBLE_UP_LEFT              0x255d
+#define BOXDRAW_VERTICAL_RIGHT_DOUBLE       0x255e
+#define BOXDRAW_VERTICAL_DOUBLE_RIGHT       0x255f
+#define BOXDRAW_DOUBLE_VERTICAL_RIGHT       0x2560
+#define BOXDRAW_VERTICAL_LEFT_DOUBLE        0x2561
+#define BOXDRAW_VERTICAL_DOUBLE_LEFT        0x2562
+#define BOXDRAW_DOUBLE_VERTICAL_LEFT        0x2563
+#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE      0x2564
+#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL      0x2565
+#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL      0x2566
+#define BOXDRAW_UP_HORIZONTAL_DOUBLE        0x2567
+#define BOXDRAW_UP_DOUBLE_HORIZONTAL        0x2568
+#define BOXDRAW_DOUBLE_UP_HORIZONTAL        0x2569
+#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE  0x256a
+#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL  0x256b
+#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL  0x256c
+
+//
+// EFI Required Block Elements Code Chart
+//
+#define BLOCKELEMENT_FULL_BLOCK   0x2588
+#define BLOCKELEMENT_LIGHT_SHADE  0x2591
+
+//
+// EFI Required Geometric Shapes Code Chart
+//
+#define GEOMETRICSHAPE_UP_TRIANGLE    0x25b2
+#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba
+#define GEOMETRICSHAPE_DOWN_TRIANGLE  0x25bc
+#define GEOMETRICSHAPE_LEFT_TRIANGLE  0x25c4
+
+//
+// EFI Required Arrow shapes
+//
+#define ARROW_LEFT  0x2190
+#define ARROW_UP    0x2191
+#define ARROW_RIGHT 0x2192
+#define ARROW_DOWN  0x2193
+
+//
+// EFI Console Colours
+//
+#define EFI_BLACK                 0x00
+#define EFI_BLUE                  0x01
+#define EFI_GREEN                 0x02
+#define EFI_CYAN                  (EFI_BLUE | EFI_GREEN)
+#define EFI_RED                   0x04
+#define EFI_MAGENTA               (EFI_BLUE | EFI_RED)
+#define EFI_BROWN                 (EFI_GREEN | EFI_RED)
+#define EFI_LIGHTGRAY             (EFI_BLUE | EFI_GREEN | EFI_RED)
+#define EFI_BRIGHT                0x08
+#define EFI_DARKGRAY              (EFI_BRIGHT)
+#define EFI_LIGHTBLUE             (EFI_BLUE | EFI_BRIGHT)
+#define EFI_LIGHTGREEN            (EFI_GREEN | EFI_BRIGHT)
+#define EFI_LIGHTCYAN             (EFI_CYAN | EFI_BRIGHT)
+#define EFI_LIGHTRED              (EFI_RED | EFI_BRIGHT)
+#define EFI_LIGHTMAGENTA          (EFI_MAGENTA | EFI_BRIGHT)
+#define EFI_YELLOW                (EFI_BROWN | EFI_BRIGHT)
+#define EFI_WHITE                 (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT)
+
+#define EFI_TEXT_ATTR(f, b)       ((f) | ((b) << 4))
+
+#define EFI_BACKGROUND_BLACK      0x00
+#define EFI_BACKGROUND_BLUE       0x10
+#define EFI_BACKGROUND_GREEN      0x20
+#define EFI_BACKGROUND_CYAN       (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN)
+#define EFI_BACKGROUND_RED        0x40
+#define EFI_BACKGROUND_MAGENTA    (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_BROWN      (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_LIGHTGRAY  (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+
+//
+// We currently define attributes from 0 - 7F for color manipulations
+// To internally handle the local display characteristics for a particular character,
+// Bit 7 signifies the local glyph representation for a character.  If turned on, glyphs will be
+// pulled from the wide glyph database and will display locally as a wide character (16 X 19 versus 8 X 19)
+// If bit 7 is off, the narrow glyph database will be used.  This does NOT affect information that is sent to
+// non-local displays, such as serial or LAN consoles.
+//
+#define EFI_WIDE_ATTRIBUTE  0x80
+
+/**
+  Reset the text output device hardware and optionaly run diagnostics
+
+  @param  This                 The protocol instance pointer.
+  @param  ExtendedVerification Driver may perform more exhaustive verfication
+                               operation of the device during reset.
+
+  @retval EFI_SUCCESS          The text output device was reset.
+  @retval EFI_DEVICE_ERROR     The text output device is not functioning correctly and
+                               could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_RESET)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN BOOLEAN                                ExtendedVerification
+  );
+
+/**
+  Write a string to the output device.
+
+  @param  This   The protocol instance pointer.
+  @param  String The NULL-terminated string to be displayed on the output
+                 device(s). All output devices must also support the Unicode
+                 drawing character codes defined in this file.
+
+  @retval EFI_SUCCESS             The string was output to the device.
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting to output
+                                  the text.
+  @retval EFI_UNSUPPORTED         The output device's mode is not currently in a
+                                  defined text mode.
+  @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the
+                                  characters in the string could not be
+                                  rendered and were skipped.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_STRING)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN CHAR16                                 *String
+  );
+
+/**
+  Verifies that all characters in a string can be output to the
+  target device.
+
+  @param  This   The protocol instance pointer.
+  @param  String The NULL-terminated string to be examined for the output
+                 device(s).
+
+  @retval EFI_SUCCESS      The device(s) are capable of rendering the output string.
+  @retval EFI_UNSUPPORTED  Some of the characters in the string cannot be
+                           rendered by one or more of the output devices mapped
+                           by the EFI handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_TEST_STRING)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN CHAR16                                 *String
+  );
+
+/**
+  Returns information for an available text mode that the output device(s)
+  supports.
+
+  @param  This       The protocol instance pointer.
+  @param  ModeNumber The mode number to return information on.
+  @param  Columns    Returns the geometry of the text output device for the
+                     requested ModeNumber.
+  @param  Rows       Returns the geometry of the text output device for the
+                     requested ModeNumber.
+
+  @retval EFI_SUCCESS      The requested mode information was returned.
+  @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+  @retval EFI_UNSUPPORTED  The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_QUERY_MODE)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN UINTN                                  ModeNumber,
+  OUT UINTN                                 *Columns,
+  OUT UINTN                                 *Rows
+  );
+
+/**
+  Sets the output device(s) to a specified mode.
+
+  @param  This       The protocol instance pointer.
+  @param  ModeNumber The mode number to set.
+
+  @retval EFI_SUCCESS      The requested text mode was set.
+  @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+  @retval EFI_UNSUPPORTED  The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_MODE)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN UINTN                                  ModeNumber
+  );
+
+/**
+  Sets the background and foreground colors for the OutputString () and
+  ClearScreen () functions.
+
+  @param  This      The protocol instance pointer.
+  @param  Attribute The attribute to set. Bits 0..3 are the foreground color, and
+                    bits 4..6 are the background color. All other bits are undefined
+                    and must be zero. The valid Attributes are defined in this file.
+
+  @retval EFI_SUCCESS       The attribute was set.
+  @retval EFI_DEVICE_ERROR  The device had an error and could not complete the request.
+  @retval EFI_UNSUPPORTED   The attribute requested is not defined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN UINTN                                  Attribute
+  );
+
+/**
+  Clears the output device(s) display to the currently selected background
+  color.
+
+  @param  This              The protocol instance pointer.
+
+  @retval  EFI_SUCCESS      The operation completed successfully.
+  @retval  EFI_DEVICE_ERROR The device had an error and could not complete the request.
+  @retval  EFI_UNSUPPORTED  The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_CLEAR_SCREEN)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This
+  );
+
+/**
+  Sets the current coordinates of the cursor position
+
+  @param  This        The protocol instance pointer.
+  @param  Column      The position to set the cursor to. Must be greater than or
+                      equal to zero and less than the number of columns and rows
+                      by QueryMode ().
+  @param  Row         The position to set the cursor to. Must be greater than or
+                      equal to zero and less than the number of columns and rows
+                      by QueryMode ().
+
+  @retval EFI_SUCCESS      The operation completed successfully.
+  @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+  @retval EFI_UNSUPPORTED  The output device is not in a valid text mode, or the
+                           cursor position is invalid for the current mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN UINTN                                  Column,
+  IN UINTN                                  Row
+  );
+
+/**
+  Makes the cursor visible or invisible
+
+  @param  This    The protocol instance pointer.
+  @param  Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
+                  set to be invisible.
+
+  @retval EFI_SUCCESS      The operation completed successfully.
+  @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+                           request, or the device does not support changing
+                           the cursor mode.
+  @retval EFI_UNSUPPORTED  The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_ENABLE_CURSOR)(
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL        *This,
+  IN BOOLEAN                                Visible
+  );
+
+/**
+  @par Data Structure Description:
+  Mode Structure pointed to by Simple Text Out protocol.
+**/
+typedef struct {
+  ///
+  /// The number of modes supported by QueryMode () and SetMode ().
+  ///
+  INT32   MaxMode;
+
+  //
+  // current settings
+  //
+
+  ///
+  /// The text mode of the output device(s).
+  ///
+  INT32   Mode;
+  ///
+  /// The current character output attribute.
+  ///
+  INT32   Attribute;
+  ///
+  /// The cursor's column.
+  ///
+  INT32   CursorColumn;
+  ///
+  /// The cursor's row.
+  ///
+  INT32   CursorRow;
+  ///
+  /// The cursor is currently visbile or not.
+  ///
+  BOOLEAN CursorVisible;
+} EFI_SIMPLE_TEXT_OUTPUT_MODE;
+
+///
+/// The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices.
+/// It is the minimum required protocol for any handle supplied as the ConsoleOut
+/// or StandardError device. In addition, the minimum supported text mode of such
+/// devices is at least 80 x 25 characters.
+///
+struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
+  EFI_TEXT_RESET                Reset;
+
+  EFI_TEXT_STRING               OutputString;
+  EFI_TEXT_TEST_STRING          TestString;
+
+  EFI_TEXT_QUERY_MODE           QueryMode;
+  EFI_TEXT_SET_MODE             SetMode;
+  EFI_TEXT_SET_ATTRIBUTE        SetAttribute;
+
+  EFI_TEXT_CLEAR_SCREEN         ClearScreen;
+  EFI_TEXT_SET_CURSOR_POSITION  SetCursorPosition;
+  EFI_TEXT_ENABLE_CURSOR        EnableCursor;
+
+  ///
+  /// Pointer to SIMPLE_TEXT_OUTPUT_MODE data.
+  ///
+  EFI_SIMPLE_TEXT_OUTPUT_MODE   *Mode;
+};
+
+extern EFI_GUID gEfiSimpleTextOutProtocolGuid;
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi.h
new file mode 100644
index 0000000..a5a25a9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi.h
@@ -0,0 +1,29 @@
+/** @file
+
+  Root include file for Mde Package UEFI, UEFI_APPLICATION type modules.
+
+  This is the include file for any module of type UEFI and UEFI_APPLICATION. Uefi modules only use
+  types defined via this include file and can be ported easily to any
+  environment.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_UEFI_H__
+#define __PI_UEFI_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Uefi/UefiBaseType.h>
+#include <ipxe/efi/Uefi/UefiSpec.h>
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h
new file mode 100644
index 0000000..2c63aa6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h
@@ -0,0 +1,287 @@
+/** @file
+  Defines data types and constants introduced in UEFI.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_BASETYPE_H__
+#define __UEFI_BASETYPE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Base.h>
+
+//
+// Basic data type definitions introduced in UEFI.
+//
+
+///
+/// 128-bit buffer containing a unique identifier value.
+///
+typedef GUID                      EFI_GUID;
+///
+/// Function return status for EFI API.
+///
+typedef RETURN_STATUS             EFI_STATUS;
+///
+/// A collection of related interfaces.
+///
+typedef VOID                      *EFI_HANDLE;
+///
+/// Handle to an event structure.
+///
+typedef VOID                      *EFI_EVENT;
+///
+/// Task priority level.
+///
+typedef UINTN                     EFI_TPL;
+///
+/// Logical block address.
+///
+typedef UINT64                    EFI_LBA;
+
+///
+/// 64-bit physical memory address.
+///
+typedef UINT64                    EFI_PHYSICAL_ADDRESS;
+
+///
+/// 64-bit virtual memory address.
+///
+typedef UINT64                    EFI_VIRTUAL_ADDRESS;
+
+///
+/// EFI Time Abstraction:
+///  Year:       1900 - 9999
+///  Month:      1 - 12
+///  Day:        1 - 31
+///  Hour:       0 - 23
+///  Minute:     0 - 59
+///  Second:     0 - 59
+///  Nanosecond: 0 - 999,999,999
+///  TimeZone:   -1440 to 1440 or 2047
+///
+typedef struct {
+  UINT16  Year;
+  UINT8   Month;
+  UINT8   Day;
+  UINT8   Hour;
+  UINT8   Minute;
+  UINT8   Second;
+  UINT8   Pad1;
+  UINT32  Nanosecond;
+  INT16   TimeZone;
+  UINT8   Daylight;
+  UINT8   Pad2;
+} EFI_TIME;
+
+
+///
+/// 4-byte buffer. An IPv4 internet protocol address.
+///
+typedef struct {
+  UINT8 Addr[4];
+} EFI_IPv4_ADDRESS;
+
+///
+/// 16-byte buffer. An IPv6 internet protocol address.
+///
+typedef struct {
+  UINT8 Addr[16];
+} EFI_IPv6_ADDRESS;
+
+///
+/// 32-byte buffer containing a network Media Access Control address.
+///
+typedef struct {
+  UINT8 Addr[32];
+} EFI_MAC_ADDRESS;
+
+///
+/// 16-byte buffer aligned on a 4-byte boundary.
+/// An IPv4 or IPv6 internet protocol address.
+///
+typedef union {
+  UINT32            Addr[4];
+  EFI_IPv4_ADDRESS  v4;
+  EFI_IPv6_ADDRESS  v6;
+} EFI_IP_ADDRESS;
+
+
+///
+/// Enumeration of EFI_STATUS.
+///@{
+#define EFI_SUCCESS               RETURN_SUCCESS
+#define EFI_LOAD_ERROR            RETURN_LOAD_ERROR
+#define EFI_INVALID_PARAMETER     RETURN_INVALID_PARAMETER
+#define EFI_UNSUPPORTED           RETURN_UNSUPPORTED
+#define EFI_BAD_BUFFER_SIZE       RETURN_BAD_BUFFER_SIZE
+#define EFI_BUFFER_TOO_SMALL      RETURN_BUFFER_TOO_SMALL
+#define EFI_NOT_READY             RETURN_NOT_READY
+#define EFI_DEVICE_ERROR          RETURN_DEVICE_ERROR
+#define EFI_WRITE_PROTECTED       RETURN_WRITE_PROTECTED
+#define EFI_OUT_OF_RESOURCES      RETURN_OUT_OF_RESOURCES
+#define EFI_VOLUME_CORRUPTED      RETURN_VOLUME_CORRUPTED
+#define EFI_VOLUME_FULL           RETURN_VOLUME_FULL
+#define EFI_NO_MEDIA              RETURN_NO_MEDIA
+#define EFI_MEDIA_CHANGED         RETURN_MEDIA_CHANGED
+#define EFI_NOT_FOUND             RETURN_NOT_FOUND
+#define EFI_ACCESS_DENIED         RETURN_ACCESS_DENIED
+#define EFI_NO_RESPONSE           RETURN_NO_RESPONSE
+#define EFI_NO_MAPPING            RETURN_NO_MAPPING
+#define EFI_TIMEOUT               RETURN_TIMEOUT
+#define EFI_NOT_STARTED           RETURN_NOT_STARTED
+#define EFI_ALREADY_STARTED       RETURN_ALREADY_STARTED
+#define EFI_ABORTED               RETURN_ABORTED
+#define EFI_ICMP_ERROR            RETURN_ICMP_ERROR
+#define EFI_TFTP_ERROR            RETURN_TFTP_ERROR
+#define EFI_PROTOCOL_ERROR        RETURN_PROTOCOL_ERROR
+#define EFI_INCOMPATIBLE_VERSION  RETURN_INCOMPATIBLE_VERSION
+#define EFI_SECURITY_VIOLATION    RETURN_SECURITY_VIOLATION
+#define EFI_CRC_ERROR             RETURN_CRC_ERROR
+#define EFI_END_OF_MEDIA          RETURN_END_OF_MEDIA
+#define EFI_END_OF_FILE           RETURN_END_OF_FILE
+#define EFI_INVALID_LANGUAGE      RETURN_INVALID_LANGUAGE
+
+#define EFI_WARN_UNKNOWN_GLYPH    RETURN_WARN_UNKNOWN_GLYPH
+#define EFI_WARN_DELETE_FAILURE   RETURN_WARN_DELETE_FAILURE
+#define EFI_WARN_WRITE_FAILURE    RETURN_WARN_WRITE_FAILURE
+#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
+///@}
+
+///
+/// Define macro to encode the status code.
+///
+#define EFIERR(_a)                ENCODE_ERROR(_a)
+
+#define EFI_ERROR(A)              RETURN_ERROR(A)
+
+///
+/// ICMP error definitions
+///@{
+#define EFI_NETWORK_UNREACHABLE   EFIERR(100)
+#define EFI_HOST_UNREACHABLE      EFIERR(101)
+#define EFI_PROTOCOL_UNREACHABLE  EFIERR(102)
+#define EFI_PORT_UNREACHABLE      EFIERR(103)
+///@}
+
+///
+/// Tcp connection status definitions
+///@{
+#define EFI_CONNECTION_FIN        EFIERR(104)
+#define EFI_CONNECTION_RESET      EFIERR(105)
+#define EFI_CONNECTION_REFUSED    EFIERR(106)
+///@}
+
+//
+// The EFI memory allocation functions work in units of EFI_PAGEs that are
+// 4KB. This should in no way be confused with the page size of the processor.
+// An EFI_PAGE is just the quanta of memory in EFI.
+//
+#define EFI_PAGE_SIZE             SIZE_4KB
+#define EFI_PAGE_MASK             0xFFF
+#define EFI_PAGE_SHIFT            12
+
+/**
+  Macro that converts a size, in bytes, to a number of EFI_PAGESs.
+
+  @param  Size      A size in bytes.  This parameter is assumed to be type UINTN.
+                    Passing in a parameter that is larger than UINTN may produce
+                    unexpected results.
+
+  @return  The number of EFI_PAGESs associated with the number of bytes specified
+           by Size.
+
+**/
+#define EFI_SIZE_TO_PAGES(Size)  (((Size) >> EFI_PAGE_SHIFT) + (((Size) & EFI_PAGE_MASK) ? 1 : 0))
+
+/**
+  Macro that converts a number of EFI_PAGEs to a size in bytes.
+
+  @param  Pages     The number of EFI_PAGES.  This parameter is assumed to be
+                    type UINTN.  Passing in a parameter that is larger than
+                    UINTN may produce unexpected results.
+
+  @return  The number of bytes associated with the number of EFI_PAGEs specified
+           by Pages.
+
+**/
+#define EFI_PAGES_TO_SIZE(Pages)  ((Pages) << EFI_PAGE_SHIFT)
+
+///
+/// PE32+ Machine type for IA32 UEFI images.
+///
+#define EFI_IMAGE_MACHINE_IA32            0x014C
+
+///
+/// PE32+ Machine type for IA64 UEFI images.
+///
+#define EFI_IMAGE_MACHINE_IA64            0x0200
+
+///
+/// PE32+ Machine type for EBC UEFI images.
+///
+#define EFI_IMAGE_MACHINE_EBC             0x0EBC
+
+///
+/// PE32+ Machine type for X64 UEFI images.
+///
+#define EFI_IMAGE_MACHINE_X64             0x8664
+
+///
+/// PE32+ Machine type for ARM mixed ARM and Thumb/Thumb2 images.
+///
+#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED  0x01C2
+
+
+#if   defined (MDE_CPU_IA32)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+  (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64)
+
+#elif defined (MDE_CPU_IPF)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+  (((Machine) == EFI_IMAGE_MACHINE_IA64) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+#elif defined (MDE_CPU_X64)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+  (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32)
+
+#elif defined (MDE_CPU_ARM)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+  (((Machine) == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)
+
+#elif defined (MDE_CPU_EBC)
+
+///
+/// This is just to make sure you can cross compile with the EBC compiler.
+/// It does not make sense to have a PE loader coded in EBC.
+///
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC)
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+#else
+#error Unknown Processor Type
+#endif
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h
new file mode 100644
index 0000000..26af39f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h
@@ -0,0 +1,142 @@
+/** @file
+  EFI Guid Partition Table Format Definition.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_GPT_H__
+#define __UEFI_GPT_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// The primary GUID Partition Table Header must be
+/// located in LBA 1 (i.e., the second logical block).
+///
+#define PRIMARY_PART_HEADER_LBA 1
+///
+/// EFI Partition Table Signature: "EFI PART".
+///
+#define EFI_PTAB_HEADER_ID      SIGNATURE_64 ('E','F','I',' ','P','A','R','T')
+
+#pragma pack(1)
+
+///
+/// GPT Partition Table Header.
+///
+typedef struct {
+  ///
+  /// The table header for the GPT partition Table.
+  /// This header contains EFI_PTAB_HEADER_ID.
+  ///
+  EFI_TABLE_HEADER  Header;
+  ///
+  /// The LBA that contains this data structure.
+  ///
+  EFI_LBA           MyLBA;
+  ///
+  /// LBA address of the alternate GUID Partition Table Header.
+  ///
+  EFI_LBA           AlternateLBA;
+  ///
+  /// The first usable logical block that may be used
+  /// by a partition described by a GUID Partition Entry.
+  ///
+  EFI_LBA           FirstUsableLBA;
+  ///
+  /// The last usable logical block that may be used
+  /// by a partition described by a GUID Partition Entry.
+  ///
+  EFI_LBA           LastUsableLBA;
+  ///
+  /// GUID that can be used to uniquely identify the disk.
+  ///
+  EFI_GUID          DiskGUID;
+  ///
+  /// The starting LBA of the GUID Partition Entry array.
+  ///
+  EFI_LBA           PartitionEntryLBA;
+  ///
+  /// The number of Partition Entries in the GUID Partition Entry array.
+  ///
+  UINT32            NumberOfPartitionEntries;
+  ///
+  /// The size, in bytes, of each the GUID Partition
+  /// Entry structures in the GUID Partition Entry
+  /// array. Must be a multiple of 8.
+  ///
+  UINT32            SizeOfPartitionEntry;
+  ///
+  /// The CRC32 of the GUID Partition Entry array.
+  /// Starts at PartitionEntryLBA and is
+  /// computed over a byte length of
+  /// NumberOfPartitionEntries * SizeOfPartitionEntry.
+  ///
+  UINT32            PartitionEntryArrayCRC32;
+} EFI_PARTITION_TABLE_HEADER;
+
+///
+/// GPT Partition Entry.
+///
+typedef struct {
+  ///
+  /// Unique ID that defines the purpose and type of this Partition. A value of
+  /// zero defines that this partition entry is not being used.
+  ///
+  EFI_GUID  PartitionTypeGUID;
+  ///
+  /// GUID that is unique for every partition entry. Every partition ever
+  /// created will have a unique GUID.
+  /// This GUID must be assigned when the GUID Partition Entry is created.
+  ///
+  EFI_GUID  UniquePartitionGUID;
+  ///
+  /// Starting LBA of the partition defined by this entry
+  ///
+  EFI_LBA   StartingLBA;
+  ///
+  /// Ending LBA of the partition defined by this entry.
+  ///
+  EFI_LBA   EndingLBA;
+  ///
+  /// Attribute bits, all bits reserved by UEFI
+  /// Bit 0:      If this bit is set, the partition is required for the platform to function. The owner/creator of the
+  ///             partition indicates that deletion or modification of the contents can result in loss of platform
+  ///             features or failure for the platform to boot or operate. The system cannot function normally if
+  ///             this partition is removed, and it should be considered part of the hardware of the system.
+  ///             Actions such as running diagnostics, system recovery, or even OS install or boot, could
+  ///             potentially stop working if this partition is removed. Unless OS software or firmware
+  ///             recognizes this partition, it should never be removed or modified as the UEFI firmware or
+  ///             platform hardware may become non-functional.
+  /// Bit 1:      If this bit is set, then firmware must not produce an EFI_BLOCK_IO_PROTOCOL device for
+  ///             this partition. By not producing an EFI_BLOCK_IO_PROTOCOL partition, file system
+  ///             mappings will not be created for this partition in UEFI.
+  /// Bit 2:      This bit is set aside to let systems with traditional PC-AT BIOS firmware implementations
+  ///             inform certain limited, special-purpose software running on these systems that a GPT
+  ///             partition may be bootable. The UEFI boot manager must ignore this bit when selecting
+  ///             a UEFI-compliant application, e.g., an OS loader.
+  /// Bits 3-47:  Undefined and must be zero. Reserved for expansion by future versions of the UEFI
+  ///             specification.
+  /// Bits 48-63: Reserved for GUID specific use. The use of these bits will vary depending on the
+  ///             PartitionTypeGUID. Only the owner of the PartitionTypeGUID is allowed
+  ///             to modify these bits. They must be preserved if Bits 0-47 are modified..
+  ///
+  UINT64    Attributes;
+  ///
+  /// Null-terminated name of the partition.
+  ///
+  CHAR16    PartitionName[36];
+} EFI_PARTITION_ENTRY;
+
+#pragma pack()
+#endif
+
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h
new file mode 100644
index 0000000..6b6d1e0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h
@@ -0,0 +1,2068 @@
+/** @file
+  This file defines the encoding for the VFR (Visual Form Representation) language.
+  IFR is primarily consumed by the EFI presentation engine, and produced by EFI
+  internal application and drivers as well as all add-in card option-ROM drivers
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  These definitions are from UEFI 2.1 and 2.2.
+
+**/
+
+#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__
+#define __UEFI_INTERNAL_FORMREPRESENTATION_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Guid/HiiFormMapMethodGuid.h>
+
+///
+/// The following types are currently defined:
+///
+typedef VOID*   EFI_HII_HANDLE;
+typedef CHAR16* EFI_STRING;
+typedef UINT16  EFI_IMAGE_ID;
+typedef UINT16  EFI_QUESTION_ID;
+typedef UINT16  EFI_STRING_ID;
+typedef UINT16  EFI_FORM_ID;
+typedef UINT16  EFI_VARSTORE_ID;
+typedef UINT16  EFI_ANIMATION_ID;
+
+typedef UINT16  EFI_DEFAULT_ID;
+
+typedef UINT32  EFI_HII_FONT_STYLE;
+
+
+
+#pragma pack(1)
+
+//
+// Definitions for Package Lists and Package Headers
+// Section 27.3.1
+//
+
+///
+/// The header found at the start of each package list.
+///
+typedef struct {
+  EFI_GUID               PackageListGuid;
+  UINT32                 PackageLength;
+} EFI_HII_PACKAGE_LIST_HEADER;
+
+///
+/// The header found at the start of each package.
+///
+typedef struct {
+  UINT32  Length:24;
+  UINT32  Type:8;
+  // UINT8  Data[...];
+} EFI_HII_PACKAGE_HEADER;
+
+//
+// Value of HII package type
+//
+#define EFI_HII_PACKAGE_TYPE_ALL             0x00
+#define EFI_HII_PACKAGE_TYPE_GUID            0x01
+#define EFI_HII_PACKAGE_FORMS                0x02
+#define EFI_HII_PACKAGE_STRINGS              0x04
+#define EFI_HII_PACKAGE_FONTS                0x05
+#define EFI_HII_PACKAGE_IMAGES               0x06
+#define EFI_HII_PACKAGE_SIMPLE_FONTS         0x07
+#define EFI_HII_PACKAGE_DEVICE_PATH          0x08
+#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT      0x09
+#define EFI_HII_PACKAGE_ANIMATIONS           0x0A
+#define EFI_HII_PACKAGE_END                  0xDF
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN    0xE0
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_END      0xFF
+
+//
+// Definitions for Simplified Font Package
+//
+
+///
+/// Contents of EFI_NARROW_GLYPH.Attributes.
+///@{
+#define EFI_GLYPH_NON_SPACING                0x01
+#define EFI_GLYPH_WIDE                       0x02
+#define EFI_GLYPH_HEIGHT                     19
+#define EFI_GLYPH_WIDTH                      8
+///@}
+
+///
+/// The EFI_NARROW_GLYPH has a preferred dimension (w x h) of 8 x 19 pixels.
+///
+typedef struct {
+  ///
+  /// The Unicode representation of the glyph. The term weight is the
+  /// technical term for a character code.
+  ///
+  CHAR16                 UnicodeWeight;
+  ///
+  /// The data element containing the glyph definitions.
+  ///
+  UINT8                  Attributes;
+  ///
+  /// The column major glyph representation of the character. Bits
+  /// with values of one indicate that the corresponding pixel is to be
+  /// on when normally displayed; those with zero are off.
+  ///
+  UINT8                  GlyphCol1[EFI_GLYPH_HEIGHT];
+} EFI_NARROW_GLYPH;
+
+///
+/// The EFI_WIDE_GLYPH has a preferred dimension (w x h) of 16 x 19 pixels, which is large enough
+/// to accommodate logographic characters.
+///
+typedef struct {
+  ///
+  /// The Unicode representation of the glyph. The term weight is the
+  /// technical term for a character code.
+  ///
+  CHAR16                 UnicodeWeight;
+  ///
+  /// The data element containing the glyph definitions.
+  ///
+  UINT8                  Attributes;
+  ///
+  /// The column major glyph representation of the character. Bits
+  /// with values of one indicate that the corresponding pixel is to be
+  /// on when normally displayed; those with zero are off.
+  ///
+  UINT8                  GlyphCol1[EFI_GLYPH_HEIGHT];
+  ///
+  /// The column major glyph representation of the character. Bits
+  /// with values of one indicate that the corresponding pixel is to be
+  /// on when normally displayed; those with zero are off.
+  ///
+  UINT8                  GlyphCol2[EFI_GLYPH_HEIGHT];
+  ///
+  /// Ensures that sizeof (EFI_WIDE_GLYPH) is twice the
+  /// sizeof (EFI_NARROW_GLYPH). The contents of Pad must
+  /// be zero.
+  ///
+  UINT8                  Pad[3];
+} EFI_WIDE_GLYPH;
+
+///
+/// A simplified font package consists of a font header
+/// followed by a series of glyph structures.
+///
+typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER Header;
+  UINT16                 NumberOfNarrowGlyphs;
+  UINT16                 NumberOfWideGlyphs;
+  // EFI_NARROW_GLYPH       NarrowGlyphs[];
+  // EFI_WIDE_GLYPH         WideGlyphs[];
+} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;
+
+//
+// Definitions for Font Package
+// Section 27.3.3
+//
+
+//
+// Value for font style
+//
+#define EFI_HII_FONT_STYLE_NORMAL            0x00000000
+#define EFI_HII_FONT_STYLE_BOLD              0x00000001
+#define EFI_HII_FONT_STYLE_ITALIC            0x00000002
+#define EFI_HII_FONT_STYLE_EMBOSS            0x00010000
+#define EFI_HII_FONT_STYLE_OUTLINE           0x00020000
+#define EFI_HII_FONT_STYLE_SHADOW            0x00040000
+#define EFI_HII_FONT_STYLE_UNDERLINE         0x00080000
+#define EFI_HII_FONT_STYLE_DBL_UNDER         0x00100000
+
+typedef struct _EFI_HII_GLYPH_INFO {
+  UINT16                 Width;
+  UINT16                 Height;
+  INT16                  OffsetX;
+  INT16                  OffsetY;
+  INT16                  AdvanceX;
+} EFI_HII_GLYPH_INFO;
+
+///
+/// The fixed header consists of a standard record header,
+/// then the character values in this section, the flags
+/// (including the encoding method) and the offsets of the glyph
+/// information, the glyph bitmaps and the character map.
+///
+typedef struct _EFI_HII_FONT_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER Header;
+  UINT32                 HdrSize;
+  UINT32                 GlyphBlockOffset;
+  EFI_HII_GLYPH_INFO     Cell;
+  EFI_HII_FONT_STYLE     FontStyle;
+  CHAR16                 FontFamily[1];
+} EFI_HII_FONT_PACKAGE_HDR;
+
+//
+// Value of different glyph info block types
+//
+#define EFI_HII_GIBT_END                  0x00
+#define EFI_HII_GIBT_GLYPH                0x10
+#define EFI_HII_GIBT_GLYPHS               0x11
+#define EFI_HII_GIBT_GLYPH_DEFAULT        0x12
+#define EFI_HII_GIBT_GLYPHS_DEFAULT       0x13
+#define EFI_HII_GIBT_DUPLICATE            0x20
+#define EFI_HII_GIBT_SKIP2                0x21
+#define EFI_HII_GIBT_SKIP1                0x22
+#define EFI_HII_GIBT_DEFAULTS             0x23
+#define EFI_HII_GIBT_EXT1                 0x30
+#define EFI_HII_GIBT_EXT2                 0x31
+#define EFI_HII_GIBT_EXT4                 0x32
+
+typedef struct _EFI_HII_GLYPH_BLOCK {
+  UINT8                  BlockType;
+} EFI_HII_GLYPH_BLOCK;
+
+//
+// Definition of different glyph info block types
+//
+
+typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  EFI_HII_GLYPH_INFO     Cell;
+} EFI_HII_GIBT_DEFAULTS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  CHAR16                 CharValue;
+} EFI_HII_GIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_GLYPH_GIBT_END_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+} EFI_GLYPH_GIBT_END_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT1_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT8                  BlockType2;
+  UINT8                  Length;
+} EFI_HII_GIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT2_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT8                  BlockType2;
+  UINT16                 Length;
+} EFI_HII_GIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT4_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT8                  BlockType2;
+  UINT32                 Length;
+} EFI_HII_GIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  EFI_HII_GLYPH_INFO     Cell;
+  UINT8                  BitmapData[1];
+} EFI_HII_GIBT_GLYPH_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  EFI_HII_GLYPH_INFO     Cell;
+  UINT16                 Count;
+  UINT8                  BitmapData[1];
+} EFI_HII_GIBT_GLYPHS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT8                  BitmapData[1];
+} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT16                 Count;
+  UINT8                  BitmapData[1];
+} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP1_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT8                  SkipCount;
+} EFI_HII_GIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP2_BLOCK {
+  EFI_HII_GLYPH_BLOCK    Header;
+  UINT16                 SkipCount;
+} EFI_HII_GIBT_SKIP2_BLOCK;
+
+//
+// Definitions for Device Path Package
+// Section 27.3.4
+//
+
+///
+/// The device path package is used to carry a device path
+/// associated with the package list.
+///
+typedef struct _EFI_HII_DEVICE_PATH_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER   Header;
+  // EFI_DEVICE_PATH_PROTOCOL DevicePath[];
+} EFI_HII_DEVICE_PATH_PACKAGE_HDR;
+
+//
+// Definitions for GUID Package
+// Section 27.3.5
+//
+
+///
+/// The GUID package is used to carry data where the format is defined by a GUID.
+///
+typedef struct _EFI_HII_GUID_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER  Header;
+  EFI_GUID                Guid;
+  // Data per GUID definition may follow
+} EFI_HII_GUID_PACKAGE_HDR;
+
+//
+// Definitions for String Package
+// Section 27.3.6
+//
+
+#define UEFI_CONFIG_LANG   "x-UEFI"
+#define UEFI_CONFIG_LANG_2 "x-i-UEFI"
+
+///
+/// The fixed header consists of a standard record header and then the string identifiers
+/// contained in this section and the offsets of the string and language information.
+///
+typedef struct _EFI_HII_STRING_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER  Header;
+  UINT32                  HdrSize;
+  UINT32                  StringInfoOffset;
+  CHAR16                  LanguageWindow[16];
+  EFI_STRING_ID           LanguageName;
+  CHAR8                   Language[1];
+} EFI_HII_STRING_PACKAGE_HDR;
+
+typedef struct {
+  UINT8                   BlockType;
+} EFI_HII_STRING_BLOCK;
+
+//
+// Value of different string information block types
+//
+#define EFI_HII_SIBT_END                     0x00
+#define EFI_HII_SIBT_STRING_SCSU             0x10
+#define EFI_HII_SIBT_STRING_SCSU_FONT        0x11
+#define EFI_HII_SIBT_STRINGS_SCSU            0x12
+#define EFI_HII_SIBT_STRINGS_SCSU_FONT       0x13
+#define EFI_HII_SIBT_STRING_UCS2             0x14
+#define EFI_HII_SIBT_STRING_UCS2_FONT        0x15
+#define EFI_HII_SIBT_STRINGS_UCS2            0x16
+#define EFI_HII_SIBT_STRINGS_UCS2_FONT       0x17
+#define EFI_HII_SIBT_DUPLICATE               0x20
+#define EFI_HII_SIBT_SKIP2                   0x21
+#define EFI_HII_SIBT_SKIP1                   0x22
+#define EFI_HII_SIBT_EXT1                    0x30
+#define EFI_HII_SIBT_EXT2                    0x31
+#define EFI_HII_SIBT_EXT4                    0x32
+#define EFI_HII_SIBT_FONT                    0x40
+
+//
+// Definition of different string information block types
+//
+
+typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  EFI_STRING_ID           StringId;
+} EFI_HII_SIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_SIBT_END_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+} EFI_HII_SIBT_END_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT1_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   BlockType2;
+  UINT8                   Length;
+} EFI_HII_SIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT2_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   BlockType2;
+  UINT16                  Length;
+} EFI_HII_SIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT4_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   BlockType2;
+  UINT32                  Length;
+} EFI_HII_SIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_SIBT_FONT_BLOCK {
+  EFI_HII_SIBT_EXT2_BLOCK Header;
+  UINT8                   FontId;
+  UINT16                  FontSize;
+  EFI_HII_FONT_STYLE      FontStyle;
+  CHAR16                  FontName[1];
+} EFI_HII_SIBT_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP1_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   SkipCount;
+} EFI_HII_SIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP2_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT16                  SkipCount;
+} EFI_HII_SIBT_SKIP2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   FontIdentifier;
+  UINT8                   StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT16                  StringCount;
+  UINT8                   StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   FontIdentifier;
+  UINT16                  StringCount;
+  UINT8                   StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  CHAR16                  StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   FontIdentifier;
+  CHAR16                  StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT16                  StringCount;
+  CHAR16                  StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK {
+  EFI_HII_STRING_BLOCK    Header;
+  UINT8                   FontIdentifier;
+  UINT16                  StringCount;
+  CHAR16                  StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK;
+
+//
+// Definitions for Image Package
+// Section 27.3.7
+//
+
+typedef struct _EFI_HII_IMAGE_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER  Header;
+  UINT32                  ImageInfoOffset;
+  UINT32                  PaletteInfoOffset;
+} EFI_HII_IMAGE_PACKAGE_HDR;
+
+typedef struct _EFI_HII_IMAGE_BLOCK {
+  UINT8                   BlockType;
+} EFI_HII_IMAGE_BLOCK;
+
+//
+// Value of different image information block types
+//
+#define EFI_HII_IIBT_END               0x00
+#define EFI_HII_IIBT_IMAGE_1BIT        0x10
+#define EFI_HII_IIBT_IMAGE_1BIT_TRANS  0x11
+#define EFI_HII_IIBT_IMAGE_4BIT        0x12
+#define EFI_HII_IIBT_IMAGE_4BIT_TRANS  0x13
+#define EFI_HII_IIBT_IMAGE_8BIT        0x14
+#define EFI_HII_IIBT_IMAGE_8BIT_TRANS  0x15
+#define EFI_HII_IIBT_IMAGE_24BIT       0x16
+#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17
+#define EFI_HII_IIBT_IMAGE_JPEG        0x18
+#define EFI_HII_IIBT_DUPLICATE         0x20
+#define EFI_HII_IIBT_SKIP2             0x21
+#define EFI_HII_IIBT_SKIP1             0x22
+#define EFI_HII_IIBT_EXT1              0x30
+#define EFI_HII_IIBT_EXT2              0x31
+#define EFI_HII_IIBT_EXT4              0x32
+
+//
+// Definition of different image information block types
+//
+
+typedef struct _EFI_HII_IIBT_END_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+} EFI_HII_IIBT_END_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT1_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        BlockType2;
+  UINT8                        Length;
+} EFI_HII_IIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT2_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        BlockType2;
+  UINT16                       Length;
+} EFI_HII_IIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT4_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        BlockType2;
+  UINT32                       Length;
+} EFI_HII_IIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE {
+  UINT16                       Width;
+  UINT16                       Height;
+  UINT8                        Data[1];
+} EFI_HII_IIBT_IMAGE_1BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_RGB_PIXEL {
+  UINT8                        b;
+  UINT8                        g;
+  UINT8                        r;
+} EFI_HII_RGB_PIXEL;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE {
+  UINT16                       Width;
+  UINT16                       Height;
+  EFI_HII_RGB_PIXEL            Bitmap[1];
+} EFI_HII_IIBT_IMAGE_24BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK {
+  EFI_HII_IMAGE_BLOCK           Header;
+  EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK {
+  EFI_HII_IMAGE_BLOCK           Header;
+  EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE {
+  UINT16                       Width;
+  UINT16                       Height;
+  UINT8                        Data[1];
+} EFI_HII_IIBT_IMAGE_4BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE {
+  UINT16                       Width;
+  UINT16                       Height;
+  UINT8                        Data[1];
+} EFI_HII_IIBT_IMAGE_8BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        PaletteIndex;
+  EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK;
+
+typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  EFI_IMAGE_ID                 ImageId;
+} EFI_HII_IIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_IIBT_JPEG_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT32                       Size;
+  UINT8                        Data[1];
+} EFI_HII_IIBT_JPEG_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP1_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT8                        SkipCount;
+} EFI_HII_IIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP2_BLOCK {
+  EFI_HII_IMAGE_BLOCK          Header;
+  UINT16                       SkipCount;
+} EFI_HII_IIBT_SKIP2_BLOCK;
+
+//
+// Definitions for Palette Information
+//
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER {
+  UINT16                       PaletteCount;
+} EFI_HII_IMAGE_PALETTE_INFO_HEADER;
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO {
+  UINT16                       PaletteSize;
+  EFI_HII_RGB_PIXEL            PaletteValue[1];
+} EFI_HII_IMAGE_PALETTE_INFO;
+
+//
+// Definitions for Forms Package
+// Section 27.3.8
+//
+
+///
+/// The Form package is used to carry form-based encoding data.
+///
+typedef struct _EFI_HII_FORM_PACKAGE_HDR {
+  EFI_HII_PACKAGE_HEADER       Header;
+  // EFI_IFR_OP_HEADER         OpCodeHeader;
+  // More op-codes follow
+} EFI_HII_FORM_PACKAGE_HDR;
+
+typedef struct {
+  UINT8 Hour;
+  UINT8 Minute;
+  UINT8 Second;
+} EFI_HII_TIME;
+
+typedef struct {
+  UINT16 Year;
+  UINT8  Month;
+  UINT8  Day;
+} EFI_HII_DATE;
+
+typedef union {
+  UINT8           u8;
+  UINT16          u16;
+  UINT32          u32;
+  UINT64          u64;
+  BOOLEAN         b;
+  EFI_HII_TIME    time;
+  EFI_HII_DATE    date;
+  EFI_STRING_ID   string; ///< EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION
+  // UINT8 buffer[];      ///< EFI_IFR_TYPE_ORDERED_LIST
+} EFI_IFR_TYPE_VALUE;
+
+//
+// IFR Opcodes
+//
+#define EFI_IFR_FORM_OP                0x01
+#define EFI_IFR_SUBTITLE_OP            0x02
+#define EFI_IFR_TEXT_OP                0x03
+#define EFI_IFR_IMAGE_OP               0x04
+#define EFI_IFR_ONE_OF_OP              0x05
+#define EFI_IFR_CHECKBOX_OP            0x06
+#define EFI_IFR_NUMERIC_OP             0x07
+#define EFI_IFR_PASSWORD_OP            0x08
+#define EFI_IFR_ONE_OF_OPTION_OP       0x09
+#define EFI_IFR_SUPPRESS_IF_OP         0x0A
+#define EFI_IFR_LOCKED_OP              0x0B
+#define EFI_IFR_ACTION_OP              0x0C
+#define EFI_IFR_RESET_BUTTON_OP        0x0D
+#define EFI_IFR_FORM_SET_OP            0x0E
+#define EFI_IFR_REF_OP                 0x0F
+#define EFI_IFR_NO_SUBMIT_IF_OP        0x10
+#define EFI_IFR_INCONSISTENT_IF_OP     0x11
+#define EFI_IFR_EQ_ID_VAL_OP           0x12
+#define EFI_IFR_EQ_ID_ID_OP            0x13
+#define EFI_IFR_EQ_ID_LIST_OP          0x14
+#define EFI_IFR_AND_OP                 0x15
+#define EFI_IFR_OR_OP                  0x16
+#define EFI_IFR_NOT_OP                 0x17
+#define EFI_IFR_RULE_OP                0x18
+#define EFI_IFR_GRAY_OUT_IF_OP         0x19
+#define EFI_IFR_DATE_OP                0x1A
+#define EFI_IFR_TIME_OP                0x1B
+#define EFI_IFR_STRING_OP              0x1C
+#define EFI_IFR_REFRESH_OP             0x1D
+#define EFI_IFR_DISABLE_IF_OP          0x1E
+#define EFI_IFR_ANIMATION_OP           0x1F
+#define EFI_IFR_TO_LOWER_OP            0x20
+#define EFI_IFR_TO_UPPER_OP            0x21
+#define EFI_IFR_MAP_OP                 0x22
+#define EFI_IFR_ORDERED_LIST_OP        0x23
+#define EFI_IFR_VARSTORE_OP            0x24
+#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25
+#define EFI_IFR_VARSTORE_EFI_OP        0x26
+#define EFI_IFR_VARSTORE_DEVICE_OP     0x27
+#define EFI_IFR_VERSION_OP             0x28
+#define EFI_IFR_END_OP                 0x29
+#define EFI_IFR_MATCH_OP               0x2A
+#define EFI_IFR_GET_OP                 0x2B
+#define EFI_IFR_SET_OP                 0x2C
+#define EFI_IFR_READ_OP                0x2D
+#define EFI_IFR_WRITE_OP               0x2E
+#define EFI_IFR_EQUAL_OP               0x2F
+#define EFI_IFR_NOT_EQUAL_OP           0x30
+#define EFI_IFR_GREATER_THAN_OP        0x31
+#define EFI_IFR_GREATER_EQUAL_OP       0x32
+#define EFI_IFR_LESS_THAN_OP           0x33
+#define EFI_IFR_LESS_EQUAL_OP          0x34
+#define EFI_IFR_BITWISE_AND_OP         0x35
+#define EFI_IFR_BITWISE_OR_OP          0x36
+#define EFI_IFR_BITWISE_NOT_OP         0x37
+#define EFI_IFR_SHIFT_LEFT_OP          0x38
+#define EFI_IFR_SHIFT_RIGHT_OP         0x39
+#define EFI_IFR_ADD_OP                 0x3A
+#define EFI_IFR_SUBTRACT_OP            0x3B
+#define EFI_IFR_MULTIPLY_OP            0x3C
+#define EFI_IFR_DIVIDE_OP              0x3D
+#define EFI_IFR_MODULO_OP              0x3E
+#define EFI_IFR_RULE_REF_OP            0x3F
+#define EFI_IFR_QUESTION_REF1_OP       0x40
+#define EFI_IFR_QUESTION_REF2_OP       0x41
+#define EFI_IFR_UINT8_OP               0x42
+#define EFI_IFR_UINT16_OP              0x43
+#define EFI_IFR_UINT32_OP              0x44
+#define EFI_IFR_UINT64_OP              0x45
+#define EFI_IFR_TRUE_OP                0x46
+#define EFI_IFR_FALSE_OP               0x47
+#define EFI_IFR_TO_UINT_OP             0x48
+#define EFI_IFR_TO_STRING_OP           0x49
+#define EFI_IFR_TO_BOOLEAN_OP          0x4A
+#define EFI_IFR_MID_OP                 0x4B
+#define EFI_IFR_FIND_OP                0x4C
+#define EFI_IFR_TOKEN_OP               0x4D
+#define EFI_IFR_STRING_REF1_OP         0x4E
+#define EFI_IFR_STRING_REF2_OP         0x4F
+#define EFI_IFR_CONDITIONAL_OP         0x50
+#define EFI_IFR_QUESTION_REF3_OP       0x51
+#define EFI_IFR_ZERO_OP                0x52
+#define EFI_IFR_ONE_OP                 0x53
+#define EFI_IFR_ONES_OP                0x54
+#define EFI_IFR_UNDEFINED_OP           0x55
+#define EFI_IFR_LENGTH_OP              0x56
+#define EFI_IFR_DUP_OP                 0x57
+#define EFI_IFR_THIS_OP                0x58
+#define EFI_IFR_SPAN_OP                0x59
+#define EFI_IFR_VALUE_OP               0x5A
+#define EFI_IFR_DEFAULT_OP             0x5B
+#define EFI_IFR_DEFAULTSTORE_OP        0x5C
+#define EFI_IFR_FORM_MAP_OP            0x5D
+#define EFI_IFR_CATENATE_OP            0x5E
+#define EFI_IFR_GUID_OP                0x5F
+#define EFI_IFR_SECURITY_OP            0x60
+
+//
+// Definitions of IFR Standard Headers
+// Section 27.3.8.2
+//
+
+typedef struct _EFI_IFR_OP_HEADER {
+  UINT8                    OpCode;
+  UINT8                    Length:7;
+  UINT8                    Scope:1;
+} EFI_IFR_OP_HEADER;
+
+typedef struct _EFI_IFR_STATEMENT_HEADER {
+  EFI_STRING_ID            Prompt;
+  EFI_STRING_ID            Help;
+} EFI_IFR_STATEMENT_HEADER;
+
+typedef struct _EFI_IFR_QUESTION_HEADER {
+  EFI_IFR_STATEMENT_HEADER Header;
+  EFI_QUESTION_ID          QuestionId;
+  EFI_VARSTORE_ID          VarStoreId;
+  union {
+    EFI_STRING_ID          VarName;
+    UINT16                 VarOffset;
+  }                        VarStoreInfo;
+  UINT8                    Flags;
+} EFI_IFR_QUESTION_HEADER;
+
+//
+// Flag values of EFI_IFR_QUESTION_HEADER
+//
+#define EFI_IFR_FLAG_READ_ONLY         0x01
+#define EFI_IFR_FLAG_CALLBACK          0x04
+#define EFI_IFR_FLAG_RESET_REQUIRED    0x10
+#define EFI_IFR_FLAG_OPTIONS_ONLY      0x80
+
+//
+// Definition for Opcode Reference
+// Section 27.3.8.3
+//
+typedef struct _EFI_IFR_DEFAULTSTORE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            DefaultName;
+  UINT16                   DefaultId;
+} EFI_IFR_DEFAULTSTORE;
+
+//
+// Default Identifier of default store
+//
+#define EFI_HII_DEFAULT_CLASS_STANDARD       0x0000
+#define EFI_HII_DEFAULT_CLASS_MANUFACTURING  0x0001
+#define EFI_HII_DEFAULT_CLASS_SAFE           0x0002
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_END   0x7fff
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_END   0xbfff
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END   0xffff
+
+typedef struct _EFI_IFR_VARSTORE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_GUID                 Guid;
+  EFI_VARSTORE_ID          VarStoreId;
+  UINT16                   Size;
+  UINT8                    Name[1];
+} EFI_IFR_VARSTORE;
+
+typedef struct _EFI_IFR_VARSTORE_EFI {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_VARSTORE_ID          VarStoreId;
+  EFI_GUID                 Guid;
+  UINT32                   Attributes;
+} EFI_IFR_VARSTORE_EFI;
+
+typedef struct _EFI_IFR_VARSTORE_NAME_VALUE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_VARSTORE_ID          VarStoreId;
+  EFI_GUID                 Guid;
+} EFI_IFR_VARSTORE_NAME_VALUE;
+
+typedef struct _EFI_IFR_FORM_SET {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_GUID                 Guid;
+  EFI_STRING_ID            FormSetTitle;
+  EFI_STRING_ID            Help;
+  UINT8                    Flags;
+  // EFI_GUID              ClassGuid[];
+} EFI_IFR_FORM_SET;
+
+typedef struct _EFI_IFR_END {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_END;
+
+typedef struct _EFI_IFR_FORM {
+  EFI_IFR_OP_HEADER        Header;
+  UINT16                   FormId;
+  EFI_STRING_ID            FormTitle;
+} EFI_IFR_FORM;
+
+typedef struct _EFI_IFR_IMAGE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IMAGE_ID             Id;
+} EFI_IFR_IMAGE;
+
+typedef struct _EFI_IFR_LOCKED {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_LOCKED;
+
+typedef struct _EFI_IFR_RULE {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    RuleId;
+} EFI_IFR_RULE;
+
+typedef struct _EFI_IFR_DEFAULT {
+  EFI_IFR_OP_HEADER        Header;
+  UINT16                   DefaultId;
+  UINT8                    Type;
+  EFI_IFR_TYPE_VALUE       Value;
+} EFI_IFR_DEFAULT;
+
+typedef struct _EFI_IFR_VALUE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_VALUE;
+
+typedef struct _EFI_IFR_SUBTITLE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_STATEMENT_HEADER Statement;
+  UINT8                    Flags;
+} EFI_IFR_SUBTITLE;
+
+#define EFI_IFR_FLAGS_HORIZONTAL       0x01
+
+typedef struct _EFI_IFR_CHECKBOX {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    Flags;
+} EFI_IFR_CHECKBOX;
+
+#define EFI_IFR_CHECKBOX_DEFAULT       0x01
+#define EFI_IFR_CHECKBOX_DEFAULT_MFG   0x02
+
+typedef struct _EFI_IFR_TEXT {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_STATEMENT_HEADER Statement;
+  EFI_STRING_ID            TextTwo;
+} EFI_IFR_TEXT;
+
+typedef struct _EFI_IFR_REF {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  EFI_FORM_ID              FormId;
+} EFI_IFR_REF;
+
+typedef struct _EFI_IFR_REF2 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  EFI_FORM_ID              FormId;
+  EFI_QUESTION_ID          QuestionId;
+} EFI_IFR_REF2;
+
+typedef struct _EFI_IFR_REF3 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  EFI_FORM_ID              FormId;
+  EFI_QUESTION_ID          QuestionId;
+  EFI_GUID                 FormSetId;
+} EFI_IFR_REF3;
+
+typedef struct _EFI_IFR_REF4 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  EFI_FORM_ID              FormId;
+  EFI_QUESTION_ID          QuestionId;
+  EFI_GUID                 FormSetId;
+  EFI_STRING_ID            DevicePath;
+} EFI_IFR_REF4;
+
+typedef struct _EFI_IFR_RESET_BUTTON {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_STATEMENT_HEADER Statement;
+  EFI_DEFAULT_ID           DefaultId;
+} EFI_IFR_RESET_BUTTON;
+
+typedef struct _EFI_IFR_ACTION {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  EFI_STRING_ID            QuestionConfig;
+} EFI_IFR_ACTION;
+
+typedef struct _EFI_IFR_ACTION_1 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+} EFI_IFR_ACTION_1;
+
+typedef struct _EFI_IFR_DATE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    Flags;
+} EFI_IFR_DATE;
+
+//
+// Flags that describe the behavior of the question.
+//
+#define EFI_QF_DATE_YEAR_SUPPRESS      0x01
+#define EFI_QF_DATE_MONTH_SUPPRESS     0x02
+#define EFI_QF_DATE_DAY_SUPPRESS       0x04
+
+#define EFI_QF_DATE_STORAGE            0x30
+#define     QF_DATE_STORAGE_NORMAL     0x00
+#define     QF_DATE_STORAGE_TIME       0x10
+#define     QF_DATE_STORAGE_WAKEUP     0x20
+
+typedef union {
+  struct {
+    UINT8 MinValue;
+    UINT8 MaxValue;
+    UINT8 Step;
+  } u8;
+  struct {
+    UINT16 MinValue;
+    UINT16 MaxValue;
+    UINT16 Step;
+  } u16;
+  struct {
+    UINT32 MinValue;
+    UINT32 MaxValue;
+    UINT32 Step;
+  } u32;
+  struct {
+    UINT64 MinValue;
+    UINT64 MaxValue;
+    UINT64 Step;
+  } u64;
+} MINMAXSTEP_DATA;
+
+typedef struct _EFI_IFR_NUMERIC {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    Flags;
+  MINMAXSTEP_DATA          data;
+} EFI_IFR_NUMERIC;
+
+//
+// Flags related to the numeric question
+//
+#define EFI_IFR_NUMERIC_SIZE           0x03
+#define   EFI_IFR_NUMERIC_SIZE_1       0x00
+#define   EFI_IFR_NUMERIC_SIZE_2       0x01
+#define   EFI_IFR_NUMERIC_SIZE_4       0x02
+#define   EFI_IFR_NUMERIC_SIZE_8       0x03
+
+#define EFI_IFR_DISPLAY                0x30
+#define   EFI_IFR_DISPLAY_INT_DEC      0x00
+#define   EFI_IFR_DISPLAY_UINT_DEC     0x10
+#define   EFI_IFR_DISPLAY_UINT_HEX     0x20
+
+typedef struct _EFI_IFR_ONE_OF {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    Flags;
+  MINMAXSTEP_DATA          data;
+} EFI_IFR_ONE_OF;
+
+typedef struct _EFI_IFR_STRING {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    MinSize;
+  UINT8                    MaxSize;
+  UINT8                    Flags;
+} EFI_IFR_STRING;
+
+#define EFI_IFR_STRING_MULTI_LINE      0x01
+
+typedef struct _EFI_IFR_PASSWORD {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT16                   MinSize;
+  UINT16                   MaxSize;
+} EFI_IFR_PASSWORD;
+
+typedef struct _EFI_IFR_ORDERED_LIST {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    MaxContainers;
+  UINT8                    Flags;
+} EFI_IFR_ORDERED_LIST;
+
+#define EFI_IFR_UNIQUE_SET             0x01
+#define EFI_IFR_NO_EMPTY_SET           0x02
+
+typedef struct _EFI_IFR_TIME {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_IFR_QUESTION_HEADER  Question;
+  UINT8                    Flags;
+} EFI_IFR_TIME;
+
+//
+// A bit-mask that determines which unique settings are active for this opcode.
+//
+#define QF_TIME_HOUR_SUPPRESS          0x01
+#define QF_TIME_MINUTE_SUPPRESS        0x02
+#define QF_TIME_SECOND_SUPPRESS        0x04
+
+#define QF_TIME_STORAGE                0x30
+#define   QF_TIME_STORAGE_NORMAL       0x00
+#define   QF_TIME_STORAGE_TIME         0x10
+#define   QF_TIME_STORAGE_WAKEUP       0x20
+
+typedef struct _EFI_IFR_DISABLE_IF {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_DISABLE_IF;
+
+typedef struct _EFI_IFR_SUPPRESS_IF {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_SUPPRESS_IF;
+
+typedef struct _EFI_IFR_GRAY_OUT_IF {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_GRAY_OUT_IF;
+
+typedef struct _EFI_IFR_INCONSISTENT_IF {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            Error;
+} EFI_IFR_INCONSISTENT_IF;
+
+typedef struct _EFI_IFR_NO_SUBMIT_IF {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            Error;
+} EFI_IFR_NO_SUBMIT_IF;
+
+typedef struct _EFI_IFR_REFRESH {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    RefreshInterval;
+} EFI_IFR_REFRESH;
+
+typedef struct _EFI_IFR_VARSTORE_DEVICE {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            DevicePath;
+} EFI_IFR_VARSTORE_DEVICE;
+
+typedef struct _EFI_IFR_ONE_OF_OPTION {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            Option;
+  UINT8                    Flags;
+  UINT8                    Type;
+  EFI_IFR_TYPE_VALUE       Value;
+} EFI_IFR_ONE_OF_OPTION;
+
+//
+// Types of the option's value.
+//
+#define EFI_IFR_TYPE_NUM_SIZE_8        0x00
+#define EFI_IFR_TYPE_NUM_SIZE_16       0x01
+#define EFI_IFR_TYPE_NUM_SIZE_32       0x02
+#define EFI_IFR_TYPE_NUM_SIZE_64       0x03
+#define EFI_IFR_TYPE_BOOLEAN           0x04
+#define EFI_IFR_TYPE_TIME              0x05
+#define EFI_IFR_TYPE_DATE              0x06
+#define EFI_IFR_TYPE_STRING            0x07
+#define EFI_IFR_TYPE_OTHER             0x08
+#define EFI_IFR_TYPE_UNDEFINED         0x09
+#define EFI_IFR_TYPE_ACTION            0x0A
+#define EFI_IFR_TYPE_BUFFER            0x0B
+
+#define EFI_IFR_OPTION_DEFAULT         0x10
+#define EFI_IFR_OPTION_DEFAULT_MFG     0x20
+
+typedef struct _EFI_IFR_GUID {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_GUID                 Guid;
+  //Optional Data Follows
+} EFI_IFR_GUID;
+
+typedef struct _EFI_IFR_DUP {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_DUP;
+
+typedef struct _EFI_IFR_EQ_ID_ID {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_QUESTION_ID          QuestionId1;
+  EFI_QUESTION_ID          QuestionId2;
+} EFI_IFR_EQ_ID_ID;
+
+typedef struct _EFI_IFR_EQ_ID_VAL {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_QUESTION_ID          QuestionId;
+  UINT16                   Value;
+} EFI_IFR_EQ_ID_VAL;
+
+typedef struct _EFI_IFR_EQ_ID_VAL_LIST {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_QUESTION_ID          QuestionId;
+  UINT16                   ListLength;
+  UINT16                   ValueList[1];
+} EFI_IFR_EQ_ID_VAL_LIST;
+
+typedef struct _EFI_IFR_UINT8 {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8 Value;
+} EFI_IFR_UINT8;
+
+typedef struct _EFI_IFR_UINT16 {
+  EFI_IFR_OP_HEADER        Header;
+  UINT16                   Value;
+} EFI_IFR_UINT16;
+
+typedef struct _EFI_IFR_UINT32 {
+  EFI_IFR_OP_HEADER        Header;
+  UINT32                   Value;
+} EFI_IFR_UINT32;
+
+typedef struct _EFI_IFR_UINT64 {
+  EFI_IFR_OP_HEADER        Header;
+  UINT64 Value;
+} EFI_IFR_UINT64;
+
+typedef struct _EFI_IFR_QUESTION_REF1 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_QUESTION_ID          QuestionId;
+} EFI_IFR_QUESTION_REF1;
+
+typedef struct _EFI_IFR_QUESTION_REF2 {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_QUESTION_REF2;
+
+typedef struct _EFI_IFR_QUESTION_REF3 {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_QUESTION_REF3;
+
+typedef struct _EFI_IFR_QUESTION_REF3_2 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            DevicePath;
+} EFI_IFR_QUESTION_REF3_2;
+
+typedef struct _EFI_IFR_QUESTION_REF3_3 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            DevicePath;
+  EFI_GUID                 Guid;
+} EFI_IFR_QUESTION_REF3_3;
+
+typedef struct _EFI_IFR_RULE_REF {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    RuleId;
+} EFI_IFR_RULE_REF;
+
+typedef struct _EFI_IFR_STRING_REF1 {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_STRING_ID            StringId;
+} EFI_IFR_STRING_REF1;
+
+typedef struct _EFI_IFR_STRING_REF2 {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_STRING_REF2;
+
+typedef struct _EFI_IFR_THIS {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_THIS;
+
+typedef struct _EFI_IFR_TRUE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TRUE;
+
+typedef struct _EFI_IFR_FALSE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_FALSE;
+
+typedef struct _EFI_IFR_ONE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_ONE;
+
+typedef struct _EFI_IFR_ONES {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_ONES;
+
+typedef struct _EFI_IFR_ZERO {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_ZERO;
+
+typedef struct _EFI_IFR_UNDEFINED {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_UNDEFINED;
+
+typedef struct _EFI_IFR_VERSION {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_VERSION;
+
+typedef struct _EFI_IFR_LENGTH {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_LENGTH;
+
+typedef struct _EFI_IFR_NOT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_NOT;
+
+typedef struct _EFI_IFR_BITWISE_NOT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_BITWISE_NOT;
+
+typedef struct _EFI_IFR_TO_BOOLEAN {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TO_BOOLEAN;
+
+///
+/// For EFI_IFR_TO_STRING, when converting from
+/// unsigned integers, these flags control the format:
+/// 0 = unsigned decimal.
+/// 1 = signed decimal.
+/// 2 = hexadecimal (lower-case alpha).
+/// 3 = hexadecimal (upper-case alpha).
+///@{
+#define EFI_IFR_STRING_UNSIGNED_DEC      0
+#define EFI_IFR_STRING_SIGNED_DEC        1
+#define EFI_IFR_STRING_LOWERCASE_HEX     2
+#define EFI_IFR_STRING_UPPERCASE_HEX     3
+///@}
+
+///
+/// When converting from a buffer, these flags control the format:
+/// 0 = ASCII.
+/// 8 = Unicode.
+///@{
+#define EFI_IFR_STRING_ASCII             0
+#define EFI_IFR_STRING_UNICODE           8
+///@}
+
+typedef struct _EFI_IFR_TO_STRING {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    Format;
+} EFI_IFR_TO_STRING;
+
+typedef struct _EFI_IFR_TO_UINT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TO_UINT;
+
+typedef struct _EFI_IFR_TO_UPPER {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TO_UPPER;
+
+typedef struct _EFI_IFR_TO_LOWER {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TO_LOWER;
+
+typedef struct _EFI_IFR_ADD {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_ADD;
+
+typedef struct _EFI_IFR_AND {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_AND;
+
+typedef struct _EFI_IFR_BITWISE_AND {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_BITWISE_AND;
+
+typedef struct _EFI_IFR_BITWISE_OR {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_BITWISE_OR;
+
+typedef struct _EFI_IFR_CATENATE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_CATENATE;
+
+typedef struct _EFI_IFR_DIVIDE {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_DIVIDE;
+
+typedef struct _EFI_IFR_EQUAL {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_EQUAL {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_GREATER_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_THAN {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_GREATER_THAN;
+
+typedef struct _EFI_IFR_LESS_EQUAL {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_LESS_EQUAL;
+
+typedef struct _EFI_IFR_LESS_THAN {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_LESS_THAN;
+
+typedef struct _EFI_IFR_MATCH {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_MATCH;
+
+typedef struct _EFI_IFR_MULTIPLY {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_MULTIPLY;
+
+typedef struct _EFI_IFR_MODULO {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_MODULO;
+
+typedef struct _EFI_IFR_NOT_EQUAL {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_NOT_EQUAL;
+
+typedef struct _EFI_IFR_OR {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_OR;
+
+typedef struct _EFI_IFR_SHIFT_LEFT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_SHIFT_LEFT;
+
+typedef struct _EFI_IFR_SHIFT_RIGHT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_SHIFT_RIGHT;
+
+typedef struct _EFI_IFR_SUBTRACT {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_SUBTRACT;
+
+typedef struct _EFI_IFR_CONDITIONAL {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_CONDITIONAL;
+
+//
+// Flags governing the matching criteria of EFI_IFR_FIND
+//
+#define EFI_IFR_FF_CASE_SENSITIVE    0x00
+#define EFI_IFR_FF_CASE_INSENSITIVE  0x01
+
+typedef struct _EFI_IFR_FIND {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    Format;
+} EFI_IFR_FIND;
+
+typedef struct _EFI_IFR_MID {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_MID;
+
+typedef struct _EFI_IFR_TOKEN {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_TOKEN;
+
+//
+// Flags specifying whether to find the first matching string
+// or the first non-matching string.
+//
+#define EFI_IFR_FLAGS_FIRST_MATCHING     0x00
+#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01
+
+typedef struct _EFI_IFR_SPAN {
+  EFI_IFR_OP_HEADER        Header;
+  UINT8                    Flags;
+} EFI_IFR_SPAN;
+
+typedef struct _EFI_IFR_SECURITY {
+  ///
+  /// Standard opcode header, where Header.Op = EFI_IFR_SECURITY_OP.
+  ///
+  EFI_IFR_OP_HEADER        Header;
+  ///
+  /// Security permission level.
+  ///
+  EFI_GUID                 Permissions;
+} EFI_IFR_SECURITY;
+
+typedef struct _EFI_IFR_FORM_MAP_METHOD {
+  ///
+  /// The string identifier which provides the human-readable name of
+  /// the configuration method for this standards map form.
+  ///
+  EFI_STRING_ID            MethodTitle;
+  ///
+  /// Identifier which uniquely specifies the configuration methods
+  /// associated with this standards map form.
+  ///
+  EFI_GUID                 MethodIdentifier;
+} EFI_IFR_FORM_MAP_METHOD;
+
+typedef struct _EFI_IFR_FORM_MAP {
+  ///
+  /// The sequence that defines the type of opcode as well as the length
+  /// of the opcode being defined. Header.OpCode = EFI_IFR_FORM_MAP_OP.
+  ///
+  EFI_IFR_OP_HEADER        Header;
+  ///
+  /// The unique identifier for this particular form.
+  ///
+  EFI_FORM_ID              FormId;
+  ///
+  /// One or more configuration method's name and unique identifier.
+  ///
+  // EFI_IFR_FORM_MAP_METHOD  Methods[];
+} EFI_IFR_FORM_MAP;
+
+typedef struct _EFI_IFR_SET {
+  ///
+  /// The sequence that defines the type of opcode as well as the length
+  /// of the opcode being defined. Header.OpCode = EFI_IFR_SET_OP.
+  ///
+  EFI_IFR_OP_HEADER  Header;
+  ///
+  /// Specifies the identifier of a previously declared variable store to
+  /// use when storing the question's value.
+  ///
+  EFI_VARSTORE_ID    VarStoreId;
+  union {
+    ///
+    /// A 16-bit Buffer Storage offset.
+    ///
+    EFI_STRING_ID    VarName;
+    ///
+    /// A Name Value or EFI Variable name (VarName).
+    ///
+    UINT16           VarOffset;
+  }                  VarStoreInfo;
+  ///
+  /// Specifies the type used for storage.
+  ///
+  UINT8              VarStoreType;
+} EFI_IFR_SET;
+
+typedef struct _EFI_IFR_GET {
+  ///
+  /// The sequence that defines the type of opcode as well as the length
+  /// of the opcode being defined. Header.OpCode = EFI_IFR_GET_OP.
+  ///
+  EFI_IFR_OP_HEADER  Header;
+  ///
+  /// Specifies the identifier of a previously declared variable store to
+  /// use when retrieving the value.
+  ///
+  EFI_VARSTORE_ID    VarStoreId;
+  union {
+    ///
+    /// A 16-bit Buffer Storage offset.
+    ///
+    EFI_STRING_ID    VarName;
+    ///
+    /// A Name Value or EFI Variable name (VarName).
+    ///
+    UINT16           VarOffset;
+  }                  VarStoreInfo;
+  ///
+  /// Specifies the type used for storage.
+  ///
+  UINT8              VarStoreType;
+} EFI_IFR_GET;
+
+typedef struct _EFI_IFR_READ {
+  EFI_IFR_OP_HEADER       Header;
+} EFI_IFR_READ;
+
+typedef struct _EFI_IFR_WRITE {
+  EFI_IFR_OP_HEADER      Header;
+} EFI_IFR_WRITE;
+
+typedef struct _EFI_IFR_MAP {
+  EFI_IFR_OP_HEADER      Header;
+} EFI_IFR_MAP;
+//
+// Definitions for Keyboard Package
+// Releated definitions are in Section of EFI_HII_DATABASE_PROTOCOL
+//
+
+///
+/// Each enumeration values maps a physical key on a keyboard.
+///
+typedef enum {
+  EfiKeyLCtrl,
+  EfiKeyA0,
+  EfiKeyLAlt,
+  EfiKeySpaceBar,
+  EfiKeyA2,
+  EfiKeyA3,
+  EfiKeyA4,
+  EfiKeyRCtrl,
+  EfiKeyLeftArrow,
+  EfiKeyDownArrow,
+  EfiKeyRightArrow,
+  EfiKeyZero,
+  EfiKeyPeriod,
+  EfiKeyEnter,
+  EfiKeyLShift,
+  EfiKeyB0,
+  EfiKeyB1,
+  EfiKeyB2,
+  EfiKeyB3,
+  EfiKeyB4,
+  EfiKeyB5,
+  EfiKeyB6,
+  EfiKeyB7,
+  EfiKeyB8,
+  EfiKeyB9,
+  EfiKeyB10,
+  EfiKeyRShift,
+  EfiKeyUpArrow,
+  EfiKeyOne,
+  EfiKeyTwo,
+  EfiKeyThree,
+  EfiKeyCapsLock,
+  EfiKeyC1,
+  EfiKeyC2,
+  EfiKeyC3,
+  EfiKeyC4,
+  EfiKeyC5,
+  EfiKeyC6,
+  EfiKeyC7,
+  EfiKeyC8,
+  EfiKeyC9,
+  EfiKeyC10,
+  EfiKeyC11,
+  EfiKeyC12,
+  EfiKeyFour,
+  EfiKeyFive,
+  EfiKeySix,
+  EfiKeyPlus,
+  EfiKeyTab,
+  EfiKeyD1,
+  EfiKeyD2,
+  EfiKeyD3,
+  EfiKeyD4,
+  EfiKeyD5,
+  EfiKeyD6,
+  EfiKeyD7,
+  EfiKeyD8,
+  EfiKeyD9,
+  EfiKeyD10,
+  EfiKeyD11,
+  EfiKeyD12,
+  EfiKeyD13,
+  EfiKeyDel,
+  EfiKeyEnd,
+  EfiKeyPgDn,
+  EfiKeySeven,
+  EfiKeyEight,
+  EfiKeyNine,
+  EfiKeyE0,
+  EfiKeyE1,
+  EfiKeyE2,
+  EfiKeyE3,
+  EfiKeyE4,
+  EfiKeyE5,
+  EfiKeyE6,
+  EfiKeyE7,
+  EfiKeyE8,
+  EfiKeyE9,
+  EfiKeyE10,
+  EfiKeyE11,
+  EfiKeyE12,
+  EfiKeyBackSpace,
+  EfiKeyIns,
+  EfiKeyHome,
+  EfiKeyPgUp,
+  EfiKeyNLck,
+  EfiKeySlash,
+  EfiKeyAsterisk,
+  EfiKeyMinus,
+  EfiKeyEsc,
+  EfiKeyF1,
+  EfiKeyF2,
+  EfiKeyF3,
+  EfiKeyF4,
+  EfiKeyF5,
+  EfiKeyF6,
+  EfiKeyF7,
+  EfiKeyF8,
+  EfiKeyF9,
+  EfiKeyF10,
+  EfiKeyF11,
+  EfiKeyF12,
+  EfiKeyPrint,
+  EfiKeySLck,
+  EfiKeyPause
+} EFI_KEY;
+
+typedef struct {
+  ///
+  /// Used to describe a physical key on a keyboard.
+  ///
+  EFI_KEY                 Key;
+  ///
+  /// Unicode character code for the Key.
+  ///
+  CHAR16                  Unicode;
+  ///
+  /// Unicode character code for the key with the shift key being held down.
+  ///
+  CHAR16                  ShiftedUnicode;
+  ///
+  /// Unicode character code for the key with the Alt-GR being held down.
+  ///
+  CHAR16                  AltGrUnicode;
+  ///
+  /// Unicode character code for the key with the Alt-GR and shift keys being held down.
+  ///
+  CHAR16                  ShiftedAltGrUnicode;
+  ///
+  /// Modifier keys are defined to allow for special functionality that is not necessarily
+  /// accomplished by a printable character. Many of these modifier keys are flags to toggle
+  /// certain state bits on and off inside of a keyboard driver.
+  ///
+  UINT16                  Modifier;
+  UINT16                  AffectedAttribute;
+} EFI_KEY_DESCRIPTOR;
+
+///
+/// A key which is affected by all the standard shift modifiers.
+/// Most keys would be expected to have this bit active.
+///
+#define EFI_AFFECTED_BY_STANDARD_SHIFT       0x0001
+
+///
+/// This key is affected by the caps lock so that if a keyboard driver
+/// would need to disambiguate between a key which had a "1" defined
+/// versus an "a" character.  Having this bit turned on would tell
+/// the keyboard driver to use the appropriate shifted state or not.
+///
+#define EFI_AFFECTED_BY_CAPS_LOCK            0x0002
+
+///
+/// Similar to the case of CAPS lock, if this bit is active, the key
+/// is affected by the num lock being turned on.
+///
+#define EFI_AFFECTED_BY_NUM_LOCK             0x0004
+
+typedef struct {
+  UINT16                  LayoutLength;
+  EFI_GUID                Guid;
+  UINT32                  LayoutDescriptorStringOffset;
+  UINT8                   DescriptorCount;
+  // EFI_KEY_DESCRIPTOR    Descriptors[];
+} EFI_HII_KEYBOARD_LAYOUT;
+
+typedef struct {
+  EFI_HII_PACKAGE_HEADER  Header;
+  UINT16                  LayoutCount;
+  // EFI_HII_KEYBOARD_LAYOUT Layout[];
+} EFI_HII_KEYBOARD_PACKAGE_HDR;
+
+//
+// Modifier values
+//
+#define EFI_NULL_MODIFIER                0x0000
+#define EFI_LEFT_CONTROL_MODIFIER        0x0001
+#define EFI_RIGHT_CONTROL_MODIFIER       0x0002
+#define EFI_LEFT_ALT_MODIFIER            0x0003
+#define EFI_RIGHT_ALT_MODIFIER           0x0004
+#define EFI_ALT_GR_MODIFIER              0x0005
+#define EFI_INSERT_MODIFIER              0x0006
+#define EFI_DELETE_MODIFIER              0x0007
+#define EFI_PAGE_DOWN_MODIFIER           0x0008
+#define EFI_PAGE_UP_MODIFIER             0x0009
+#define EFI_HOME_MODIFIER                0x000A
+#define EFI_END_MODIFIER                 0x000B
+#define EFI_LEFT_SHIFT_MODIFIER          0x000C
+#define EFI_RIGHT_SHIFT_MODIFIER         0x000D
+#define EFI_CAPS_LOCK_MODIFIER           0x000E
+#define EFI_NUM_LOCK_MODIFIER            0x000F
+#define EFI_LEFT_ARROW_MODIFIER          0x0010
+#define EFI_RIGHT_ARROW_MODIFIER         0x0011
+#define EFI_DOWN_ARROW_MODIFIER          0x0012
+#define EFI_UP_ARROW_MODIFIER            0x0013
+#define EFI_NS_KEY_MODIFIER              0x0014
+#define EFI_NS_KEY_DEPENDENCY_MODIFIER   0x0015
+#define EFI_FUNCTION_KEY_ONE_MODIFIER    0x0016
+#define EFI_FUNCTION_KEY_TWO_MODIFIER    0x0017
+#define EFI_FUNCTION_KEY_THREE_MODIFIER  0x0018
+#define EFI_FUNCTION_KEY_FOUR_MODIFIER   0x0019
+#define EFI_FUNCTION_KEY_FIVE_MODIFIER   0x001A
+#define EFI_FUNCTION_KEY_SIX_MODIFIER    0x001B
+#define EFI_FUNCTION_KEY_SEVEN_MODIFIER  0x001C
+#define EFI_FUNCTION_KEY_EIGHT_MODIFIER  0x001D
+#define EFI_FUNCTION_KEY_NINE_MODIFIER   0x001E
+#define EFI_FUNCTION_KEY_TEN_MODIFIER    0x001F
+#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020
+#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021
+
+//
+// Keys that have multiple control functions based on modifier
+// settings are handled in the keyboard driver implementation.
+// For instance, PRINT_KEY might have a modifier held down and
+// is still a nonprinting character, but might have an alternate
+// control function like SYSREQUEST
+//
+#define EFI_PRINT_MODIFIER               0x0022
+#define EFI_SYS_REQUEST_MODIFIER         0x0023
+#define EFI_SCROLL_LOCK_MODIFIER         0x0024
+#define EFI_PAUSE_MODIFIER               0x0025
+#define EFI_BREAK_MODIFIER               0x0026
+
+#define EFI_LEFT_LOGO_MODIFIER           0x0027
+#define EFI_RIGHT_LOGO_MODIFIER          0x0028
+#define EFI_MENU_MODIFIER                0x0029
+
+///
+/// Animation IFR opcode
+///
+typedef struct _EFI_IFR_ANIMATION {
+  ///
+  /// Standard opcode header, where Header.OpCode is
+  /// EFI_IFR_ANIMATION_OP.
+  ///
+  EFI_IFR_OP_HEADER        Header;
+  ///
+  /// Animation identifier in the HII database.
+  ///
+  EFI_ANIMATION_ID         Id;
+} EFI_IFR_ANIMATION;
+
+///
+/// HII animation package header.
+///
+typedef struct _EFI_HII_ANIMATION_PACKAGE_HDR {
+  ///
+  /// Standard package header, where Header.Type = EFI_HII_PACKAGE_ANIMATIONS.
+  ///
+  EFI_HII_PACKAGE_HEADER  Header;
+  ///
+  /// Offset, relative to this header, of the animation information. If
+  /// this is zero, then there are no animation sequences in the package.
+  ///
+  UINT32                  AnimationInfoOffset;
+} EFI_HII_ANIMATION_PACKAGE_HDR;
+
+///
+/// Animation information is encoded as a series of blocks,
+/// with each block prefixed by a single byte header EFI_HII_ANIMATION_BLOCK.
+///
+typedef struct _EFI_HII_ANIMATION_BLOCK {
+  UINT8  BlockType;
+  //UINT8  BlockBody[];
+} EFI_HII_ANIMATION_BLOCK;
+
+///
+/// Animation block types.
+///
+#define EFI_HII_AIBT_END                 0x00
+#define EFI_HII_AIBT_OVERLAY_IMAGES      0x10
+#define EFI_HII_AIBT_CLEAR_IMAGES        0x11
+#define EFI_HII_AIBT_RESTORE_SCRN        0x12
+#define EFI_HII_AIBT_OVERLAY_IMAGES_LOOP 0x18
+#define EFI_HII_AIBT_CLEAR_IMAGES_LOOP   0x19
+#define EFI_HII_AIBT_RESTORE_SCRN_LOOP   0x1A
+#define EFI_HII_AIBT_DUPLICATE           0x20
+#define EFI_HII_AIBT_SKIP2               0x21
+#define EFI_HII_AIBT_SKIP1               0x22
+#define EFI_HII_AIBT_EXT1                0x30
+#define EFI_HII_AIBT_EXT2                0x31
+#define EFI_HII_AIBT_EXT4                0x32
+
+///
+/// Extended block headers used for variable sized animation records
+/// which need an explicit length.
+///
+
+typedef struct _EFI_HII_AIBT_EXT1_BLOCK  {
+  ///
+  /// Standard animation header, where Header.BlockType = EFI_HII_AIBT_EXT1.
+  ///
+  EFI_HII_ANIMATION_BLOCK  Header;
+  ///
+  /// The block type.
+  ///
+  UINT8                    BlockType2;
+  ///
+  /// Size of the animation block, in bytes, including the animation block header.
+  ///
+  UINT8                    Length;
+} EFI_HII_AIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_AIBT_EXT2_BLOCK {
+  ///
+  /// Standard animation header, where Header.BlockType = EFI_HII_AIBT_EXT2.
+  ///
+  EFI_HII_ANIMATION_BLOCK  Header;
+  ///
+  /// The block type
+  ///
+  UINT8                    BlockType2;
+  ///
+  /// Size of the animation block, in bytes, including the animation block header.
+  ///
+  UINT16                   Length;
+} EFI_HII_AIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_AIBT_EXT4_BLOCK {
+  ///
+  /// Standard animation header, where Header.BlockType = EFI_HII_AIBT_EXT4.
+  ///
+  EFI_HII_ANIMATION_BLOCK  Header;
+  ///
+  /// The block type
+  ///
+  UINT8                    BlockType2;
+  ///
+  /// Size of the animation block, in bytes, including the animation block header.
+  ///
+  UINT32                   Length;
+} EFI_HII_AIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_ANIMATION_CELL {
+  ///
+  /// The X offset from the upper left hand corner of the logical
+  /// window to position the indexed image.
+  ///
+  UINT16                    OffsetX;
+  ///
+  /// The Y offset from the upper left hand corner of the logical
+  /// window to position the indexed image.
+  ///
+  UINT16                    OffsetY;
+  ///
+  /// The image to display at the specified offset from the upper left
+  /// hand corner of the logical window.
+  ///
+  EFI_IMAGE_ID              ImageId;
+  ///
+  /// The number of milliseconds to delay after displaying the indexed
+  /// image and before continuing on to the next linked image.  If value
+  /// is zero, no delay.
+  ///
+  UINT16                    Delay;
+} EFI_HII_ANIMATION_CELL;
+
+///
+/// An animation block to describe an animation sequence that does not cycle, and
+/// where one image is simply displayed over the previous image.
+///
+typedef struct _EFI_HII_AIBT_OVERLAY_IMAGES_BLOCK {
+  ///
+  /// This is image that is to be reference by the image protocols, if the
+  /// animation function is not supported or disabled. This image can
+  /// be one particular image from the animation sequence (if any one
+  /// of the animation frames has a complete image) or an alternate
+  /// image that can be displayed alone. If the value is zero, no image
+  /// is displayed.
+  ///
+  EFI_IMAGE_ID            DftImageId;
+  ///
+  /// The overall width of the set of images (logical window width).
+  ///
+  UINT16                  Width;
+  ///
+  /// The overall height of the set of images (logical window height).
+  ///
+  UINT16                  Height;
+  ///
+  /// The number of EFI_HII_ANIMATION_CELL contained in the
+  /// animation sequence.
+  ///
+  UINT16                  CellCount;
+  ///
+  /// An array of CellCount animation cells.
+  ///
+  EFI_HII_ANIMATION_CELL  AnimationCell[1];
+} EFI_HII_AIBT_OVERLAY_IMAGES_BLOCK;
+
+///
+/// An animation block to describe an animation sequence that does not cycle,
+/// and where the logical window is cleared to the specified color before
+/// the next image is displayed.
+///
+typedef struct _EFI_HII_AIBT_CLEAR_IMAGES_BLOCK {
+  ///
+  /// This is image that is to be reference by the image protocols, if the
+  /// animation function is not supported or disabled. This image can
+  /// be one particular image from the animation sequence (if any one
+  /// of the animation frames has a complete image) or an alternate
+  /// image that can be displayed alone. If the value is zero, no image
+  /// is displayed.
+  ///
+  EFI_IMAGE_ID       DftImageId;
+  ///
+  /// The overall width of the set of images (logical window width).
+  ///
+  UINT16             Width;
+  ///
+  /// The overall height of the set of images (logical window height).
+  ///
+  UINT16             Height;
+  ///
+  /// The number of EFI_HII_ANIMATION_CELL contained in the
+  /// animation sequence.
+  ///
+  UINT16             CellCount;
+  ///
+  /// The color to clear the logical window to before displaying the
+  /// indexed image.
+  ///
+  EFI_HII_RGB_PIXEL  BackgndColor;
+  ///
+  /// An array of CellCount animation cells.
+  ///
+  EFI_HII_ANIMATION_CELL AnimationCell[1];
+} EFI_HII_AIBT_CLEAR_IMAGES_BLOCK;
+
+///
+/// An animation block to describe an animation sequence that does not cycle,
+/// and where the screen is restored to the original state before the next
+/// image is displayed.
+///
+typedef struct _EFI_HII_AIBT_RESTORE_SCRN_BLOCK {
+  ///
+  /// This is image that is to be reference by the image protocols, if the
+  /// animation function is not supported or disabled. This image can
+  /// be one particular image from the animation sequence (if any one
+  /// of the animation frames has a complete image) or an alternate
+  /// image that can be displayed alone. If the value is zero, no image
+  /// is displayed.
+  ///
+  EFI_IMAGE_ID            DftImageId;
+  ///
+  /// The overall width of the set of images (logical window width).
+  ///
+  UINT16                  Width;
+  ///
+  /// The overall height of the set of images (logical window height).
+  ///
+  UINT16                  Height;
+  ///
+  /// The number of EFI_HII_ANIMATION_CELL contained in the
+  /// animation sequence.
+  ///
+  UINT16                  CellCount;
+  ///
+  /// An array of CellCount animation cells.
+  ///
+  EFI_HII_ANIMATION_CELL  AnimationCell[1];
+} EFI_HII_AIBT_RESTORE_SCRN_BLOCK;
+
+///
+/// An animation block to describe an animation sequence that continuously cycles,
+/// and where one image is simply displayed over the previous image.
+///
+typedef EFI_HII_AIBT_OVERLAY_IMAGES_BLOCK  EFI_HII_AIBT_OVERLAY_IMAGES_LOOP_BLOCK;
+
+///
+/// An animation block to describe an animation sequence that continuously cycles,
+/// and where the logical window is cleared to the specified color before
+/// the next image is displayed.
+///
+typedef EFI_HII_AIBT_CLEAR_IMAGES_BLOCK    EFI_HII_AIBT_CLEAR_IMAGES_LOOP_BLOCK;
+
+///
+/// An animation block to describe an animation sequence that continuously cycles,
+/// and where the screen is restored to the original state before
+/// the next image is displayed.
+///
+typedef EFI_HII_AIBT_RESTORE_SCRN_BLOCK    EFI_HII_AIBT_RESTORE_SCRN_LOOP_BLOCK;
+
+///
+/// Assigns a new character value to a previously defined animation sequence.
+///
+typedef struct _EFI_HII_AIBT_DUPLICATE_BLOCK {
+  ///
+  /// The previously defined animation ID with the exact same
+  /// animation information.
+  ///
+  EFI_ANIMATION_ID  AnimationId;
+} EFI_HII_AIBT_DUPLICATE_BLOCK;
+
+///
+/// Skips animation IDs.
+///
+typedef struct _EFI_HII_AIBT_SKIP1_BLOCK {
+  ///
+  /// The unsigned 8-bit value to add to AnimationIdCurrent.
+  ///
+  UINT8  SkipCount;
+} EFI_HII_AIBT_SKIP1_BLOCK;
+
+///
+/// Skips animation IDs.
+///
+typedef struct _EFI_HII_AIBT_SKIP2_BLOCK {
+  ///
+  /// The unsigned 16-bit value to add to AnimationIdCurrent.
+  ///
+  UINT16  SkipCount;
+} EFI_HII_AIBT_SKIP2_BLOCK;
+
+#pragma pack()
+
+
+
+///
+/// References to string tokens must use this macro to enable scanning for
+/// token usages.
+///
+///
+/// STRING_TOKEN is not defined in UEFI specification. But it is placed
+/// here for the easy access by C files and VFR source files.
+///
+#define STRING_TOKEN(t) t
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h
new file mode 100644
index 0000000..6ecbcf1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h
@@ -0,0 +1,171 @@
+/** @file
+  This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_MULTIPHASE_H__
+#define __UEFI_MULTIPHASE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Guid/WinCertificate.h>
+///
+/// Enumeration of memory types introduced in UEFI.
+///
+typedef enum {
+  ///
+  /// Not used.
+  ///
+  EfiReservedMemoryType,
+  ///
+  /// The code portions of a loaded application.
+  /// (Note that UEFI OS loaders are UEFI applications.)
+  ///
+  EfiLoaderCode,
+  ///
+  /// The data portions of a loaded application and the default data allocation
+  /// type used by an application to allocate pool memory.
+  ///
+  EfiLoaderData,
+  ///
+  /// The code portions of a loaded Boot Services Driver.
+  ///
+  EfiBootServicesCode,
+  ///
+  /// The data portions of a loaded Boot Serves Driver, and the default data
+  /// allocation type used by a Boot Services Driver to allocate pool memory.
+  ///
+  EfiBootServicesData,
+  ///
+  /// The code portions of a loaded Runtime Services Driver.
+  ///
+  EfiRuntimeServicesCode,
+  ///
+  /// The data portions of a loaded Runtime Services Driver and the default
+  /// data allocation type used by a Runtime Services Driver to allocate pool memory.
+  ///
+  EfiRuntimeServicesData,
+  ///
+  /// Free (unallocated) memory.
+  ///
+  EfiConventionalMemory,
+  ///
+  /// Memory in which errors have been detected.
+  ///
+  EfiUnusableMemory,
+  ///
+  /// Memory that holds the ACPI tables.
+  ///
+  EfiACPIReclaimMemory,
+  ///
+  /// Address space reserved for use by the firmware.
+  ///
+  EfiACPIMemoryNVS,
+  ///
+  /// Used by system firmware to request that a memory-mapped IO region
+  /// be mapped by the OS to a virtual address so it can be accessed by EFI runtime services.
+  ///
+  EfiMemoryMappedIO,
+  ///
+  /// System memory-mapped IO region that is used to translate memory
+  /// cycles to IO cycles by the processor.
+  ///
+  EfiMemoryMappedIOPortSpace,
+  ///
+  /// Address space reserved by the firmware for code that is part of the processor.
+  ///
+  EfiPalCode,
+  EfiMaxMemoryType
+} EFI_MEMORY_TYPE;
+
+///
+/// Data structure that precedes all of the standard EFI table types.
+///
+typedef struct {
+  ///
+  /// A 64-bit signature that identifies the type of table that follows.
+  /// Unique signatures have been generated for the EFI System Table,
+  /// the EFI Boot Services Table, and the EFI Runtime Services Table.
+  ///
+  UINT64  Signature;
+  ///
+  /// The revision of the EFI Specification to which this table
+  /// conforms. The upper 16 bits of this field contain the major
+  /// revision value, and the lower 16 bits contain the minor revision
+  /// value. The minor revision values are limited to the range of 00..99.
+  ///
+  UINT32  Revision;
+  ///
+  /// The size, in bytes, of the entire table including the EFI_TABLE_HEADER.
+  ///
+  UINT32  HeaderSize;
+  ///
+  /// The 32-bit CRC for the entire table. This value is computed by
+  /// setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes.
+  ///
+  UINT32  CRC32;
+  ///
+  /// Reserved field that must be set to 0.
+  ///
+  UINT32  Reserved;
+} EFI_TABLE_HEADER;
+
+///
+/// Attributes of variable.
+///
+#define EFI_VARIABLE_NON_VOLATILE                 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS           0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS               0x00000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD        0x00000008
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS   0x00000010
+
+///
+/// AuthInfo is a WIN_CERTIFICATE using the wCertificateType
+/// WIN_CERTIFICATE_UEFI_GUID and the CertType
+/// EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies
+/// authenticated access, then the Data buffer should begin with an
+/// authentication descriptor prior to the data payload and DataSize
+/// should reflect the the data.and descriptor size. The caller
+/// shall digest the Monotonic Count value and the associated data
+/// for the variable update using the SHA-256 1-way hash algorithm.
+/// The ensuing the 32-byte digest will be signed using the private
+/// key associated w/ the public/private 2048-bit RSA key-pair. The
+/// WIN_CERTIFICATE shall be used to describe the signature of the
+/// Variable data *Data. In addition, the signature will also
+/// include the MonotonicCount value to guard against replay attacks.
+///
+typedef struct {
+  ///
+  /// Included in the signature of
+  /// AuthInfo.Used to ensure freshness/no
+  /// replay. Incremented during each
+  /// "Write" access.
+  ///
+  UINT64                      MonotonicCount;
+  ///
+  /// Provides the authorization for the variable
+  /// access. It is a signature across the
+  /// variable data and the  Monotonic Count
+  /// value. Caller uses Private key that is
+  /// associated with a public key that has been
+  /// provisioned via the key exchange.
+  ///
+  WIN_CERTIFICATE_UEFI_GUID   AuthInfo;
+} EFI_VARIABLE_AUTHENTICATION;
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h
new file mode 100644
index 0000000..0b8da5f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h
@@ -0,0 +1,1772 @@
+/** @file
+  This header file contains all of the PXE type definitions,
+  structure prototypes, global variables and constants that
+  are needed for porting PXE to EFI.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  32/64-bit PXE specification:
+  alpha-4, 99-Dec-17.
+
+**/
+
+#ifndef __EFI_PXE_H__
+#define __EFI_PXE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#pragma pack(1)
+
+#define PXE_BUSTYPE(a, b, c, d) \
+    ( \
+      (((PXE_UINT32) (d) & 0xFF) << 24) | (((PXE_UINT32) (c) & 0xFF) << 16) | (((PXE_UINT32) (b) & 0xFF) << 8) | \
+        ((PXE_UINT32) (a) & 0xFF) \
+    )
+
+///
+/// UNDI ROM ID and devive ID signature.
+///
+#define PXE_BUSTYPE_PXE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+///
+/// BUS ROM ID signatures.
+///
+#define PXE_BUSTYPE_PCI     PXE_BUSTYPE ('P', 'C', 'I', 'R')
+#define PXE_BUSTYPE_PC_CARD PXE_BUSTYPE ('P', 'C', 'C', 'R')
+#define PXE_BUSTYPE_USB     PXE_BUSTYPE ('U', 'S', 'B', 'R')
+#define PXE_BUSTYPE_1394    PXE_BUSTYPE ('1', '3', '9', '4')
+
+#define PXE_SWAP_UINT16(n)  ((((PXE_UINT16) (n) & 0x00FF) << 8) | (((PXE_UINT16) (n) & 0xFF00) >> 8))
+
+#define PXE_SWAP_UINT32(n) \
+  ((((PXE_UINT32)(n) & 0x000000FF) << 24) | \
+   (((PXE_UINT32)(n) & 0x0000FF00) << 8)  | \
+   (((PXE_UINT32)(n) & 0x00FF0000) >> 8)  | \
+   (((PXE_UINT32)(n) & 0xFF000000) >> 24))
+
+#define PXE_SWAP_UINT64(n) \
+  ((((PXE_UINT64)(n) & 0x00000000000000FFULL) << 56) | \
+   (((PXE_UINT64)(n) & 0x000000000000FF00ULL) << 40) | \
+   (((PXE_UINT64)(n) & 0x0000000000FF0000ULL) << 24) | \
+   (((PXE_UINT64)(n) & 0x00000000FF000000ULL) << 8)  | \
+   (((PXE_UINT64)(n) & 0x000000FF00000000ULL) >> 8)  | \
+   (((PXE_UINT64)(n) & 0x0000FF0000000000ULL) >> 24) | \
+   (((PXE_UINT64)(n) & 0x00FF000000000000ULL) >> 40) | \
+   (((PXE_UINT64)(n) & 0xFF00000000000000ULL) >> 56))
+
+
+#define PXE_CPBSIZE_NOT_USED  0               ///< zero
+#define PXE_DBSIZE_NOT_USED   0               ///< zero
+#define PXE_CPBADDR_NOT_USED  (PXE_UINT64) 0  ///< zero
+#define PXE_DBADDR_NOT_USED   (PXE_UINT64) 0  ///< zero
+#define PXE_CONST             CONST
+
+#define PXE_VOLATILE          volatile
+
+typedef VOID           PXE_VOID;
+typedef UINT8          PXE_UINT8;
+typedef UINT16         PXE_UINT16;
+typedef UINT32         PXE_UINT32;
+typedef UINTN          PXE_UINTN;
+
+///
+/// Typedef unsigned long PXE_UINT64.
+///
+typedef UINT64      PXE_UINT64;
+
+typedef PXE_UINT8 PXE_BOOL;
+#define PXE_FALSE 0            ///< zero
+#define PXE_TRUE  (!PXE_FALSE)
+
+typedef PXE_UINT16      PXE_OPCODE;
+
+///
+/// Return UNDI operational state.
+///
+#define PXE_OPCODE_GET_STATE  0x0000
+
+///
+/// Change UNDI operational state from Stopped to Started.
+///
+#define PXE_OPCODE_START  0x0001
+
+///
+/// Change UNDI operational state from Started to Stopped.
+///
+#define PXE_OPCODE_STOP 0x0002
+
+///
+/// Get UNDI initialization information.
+///
+#define PXE_OPCODE_GET_INIT_INFO  0x0003
+
+///
+/// Get NIC configuration information.
+///
+#define PXE_OPCODE_GET_CONFIG_INFO  0x0004
+
+///
+/// Changed UNDI operational state from Started to Initialized.
+///
+#define PXE_OPCODE_INITIALIZE 0x0005
+
+///
+/// Re-initialize the NIC H/W.
+///
+#define PXE_OPCODE_RESET  0x0006
+
+///
+/// Change the UNDI operational state from Initialized to Started.
+///
+#define PXE_OPCODE_SHUTDOWN 0x0007
+
+///
+/// Read & change state of external interrupt enables.
+///
+#define PXE_OPCODE_INTERRUPT_ENABLES  0x0008
+
+///
+/// Read & change state of packet receive filters.
+///
+#define PXE_OPCODE_RECEIVE_FILTERS  0x0009
+
+///
+/// Read & change station MAC address.
+///
+#define PXE_OPCODE_STATION_ADDRESS  0x000A
+
+///
+/// Read traffic statistics.
+///
+#define PXE_OPCODE_STATISTICS 0x000B
+
+///
+/// Convert multicast IP address to multicast MAC address.
+///
+#define PXE_OPCODE_MCAST_IP_TO_MAC  0x000C
+
+///
+/// Read or change non-volatile storage on the NIC.
+///
+#define PXE_OPCODE_NVDATA 0x000D
+
+///
+/// Get & clear interrupt status.
+///
+#define PXE_OPCODE_GET_STATUS 0x000E
+
+///
+/// Fill media header in packet for transmit.
+///
+#define PXE_OPCODE_FILL_HEADER  0x000F
+
+///
+/// Transmit packet(s).
+///
+#define PXE_OPCODE_TRANSMIT 0x0010
+
+///
+/// Receive packet.
+///
+#define PXE_OPCODE_RECEIVE  0x0011
+
+///
+/// Last valid PXE UNDI OpCode number.
+///
+#define PXE_OPCODE_LAST_VALID 0x0011
+
+typedef PXE_UINT16  PXE_OPFLAGS;
+
+#define PXE_OPFLAGS_NOT_USED  0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Get State
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Start
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Stop
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Get Init Info
+//
+// No Opflags
+
+////////////////////////////////////////
+// UNDI Get Config Info
+//
+// No Opflags
+
+///
+/// UNDI Initialize
+///
+#define PXE_OPFLAGS_INITIALIZE_CABLE_DETECT_MASK    0x0001
+#define PXE_OPFLAGS_INITIALIZE_DETECT_CABLE         0x0000
+#define PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE  0x0001
+
+///
+///
+/// UNDI Reset
+///
+#define PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS  0x0001
+#define PXE_OPFLAGS_RESET_DISABLE_FILTERS     0x0002
+
+///
+/// UNDI Shutdown.
+///
+/// No OpFlags.
+
+///
+/// UNDI Interrupt Enables.
+///
+///
+/// Select whether to enable or disable external interrupt signals.
+/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPFLAGS.
+///
+#define PXE_OPFLAGS_INTERRUPT_OPMASK  0xC000
+#define PXE_OPFLAGS_INTERRUPT_ENABLE  0x8000
+#define PXE_OPFLAGS_INTERRUPT_DISABLE 0x4000
+#define PXE_OPFLAGS_INTERRUPT_READ    0x0000
+
+///
+/// Enable receive interrupts.  An external interrupt will be generated
+/// after a complete non-error packet has been received.
+///
+#define PXE_OPFLAGS_INTERRUPT_RECEIVE 0x0001
+
+///
+/// Enable transmit interrupts.  An external interrupt will be generated
+/// after a complete non-error packet has been transmitted.
+///
+#define PXE_OPFLAGS_INTERRUPT_TRANSMIT  0x0002
+
+///
+/// Enable command interrupts.  An external interrupt will be generated
+/// when command execution stops.
+///
+#define PXE_OPFLAGS_INTERRUPT_COMMAND 0x0004
+
+///
+/// Generate software interrupt.  Setting this bit generates an external
+/// interrupt, if it is supported by the hardware.
+///
+#define PXE_OPFLAGS_INTERRUPT_SOFTWARE  0x0008
+
+///
+/// UNDI Receive Filters.
+///
+///
+/// Select whether to enable or disable receive filters.
+/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPCODE.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_OPMASK   0xC000
+#define PXE_OPFLAGS_RECEIVE_FILTER_ENABLE   0x8000
+#define PXE_OPFLAGS_RECEIVE_FILTER_DISABLE  0x4000
+#define PXE_OPFLAGS_RECEIVE_FILTER_READ     0x0000
+
+///
+/// To reset the contents of the multicast MAC address filter list,
+/// set this OpFlag:
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000
+
+///
+/// Enable unicast packet receiving.  Packets sent to the current station
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_UNICAST  0x0001
+
+///
+/// Enable broadcast packet receiving.  Packets sent to the broadcast
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST  0x0002
+
+///
+/// Enable filtered multicast packet receiving.  Packets sent to any
+/// of the multicast MAC addresses in the multicast MAC address filter
+/// list will be received.  If the filter list is empty, no multicast
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+///
+/// Enable promiscuous packet receiving.  All packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS  0x0008
+
+///
+/// Enable promiscuous multicast packet receiving.  All multicast
+/// packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST  0x0010
+
+///
+/// UNDI Station Address.
+///
+#define PXE_OPFLAGS_STATION_ADDRESS_READ   0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_WRITE  0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_RESET  0x0001
+
+///
+/// UNDI Statistics.
+///
+#define PXE_OPFLAGS_STATISTICS_READ   0x0000
+#define PXE_OPFLAGS_STATISTICS_RESET  0x0001
+
+///
+/// UNDI MCast IP to MAC.
+///
+///
+/// Identify the type of IP address in the CPB.
+///
+#define PXE_OPFLAGS_MCAST_IP_TO_MAC_OPMASK  0x0003
+#define PXE_OPFLAGS_MCAST_IPV4_TO_MAC       0x0000
+#define PXE_OPFLAGS_MCAST_IPV6_TO_MAC       0x0001
+
+///
+/// UNDI NvData.
+///
+///
+/// Select the type of non-volatile data operation.
+///
+#define PXE_OPFLAGS_NVDATA_OPMASK 0x0001
+#define PXE_OPFLAGS_NVDATA_READ   0x0000
+#define PXE_OPFLAGS_NVDATA_WRITE  0x0001
+
+///
+/// UNDI Get Status.
+///
+///
+/// Return current interrupt status.  This will also clear any interrupts
+/// that are currently set.  This can be used in a polling routine.  The
+/// interrupt flags are still set and cleared even when the interrupts
+/// are disabled.
+///
+#define PXE_OPFLAGS_GET_INTERRUPT_STATUS  0x0001
+
+///
+/// Return list of transmitted buffers for recycling.  Transmit buffers
+/// must not be changed or unallocated until they have recycled.  After
+/// issuing a transmit command, wait for a transmit complete interrupt.
+/// When a transmit complete interrupt is received, read the transmitted
+/// buffers.  Do not plan on getting one buffer per interrupt.  Some
+/// NICs and UNDIs may transmit multiple buffers per interrupt.
+///
+#define PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002
+
+///
+/// Return current media status.
+///
+#define PXE_OPFLAGS_GET_MEDIA_STATUS    0x0004
+
+///
+/// UNDI Fill Header.
+///
+#define PXE_OPFLAGS_FILL_HEADER_OPMASK      0x0001
+#define PXE_OPFLAGS_FILL_HEADER_FRAGMENTED  0x0001
+#define PXE_OPFLAGS_FILL_HEADER_WHOLE       0x0000
+
+///
+/// UNDI Transmit.
+///
+///
+/// S/W UNDI only.  Return after the packet has been transmitted.  A
+/// transmit complete interrupt will still be generated and the transmit
+/// buffer will have to be recycled.
+///
+#define PXE_OPFLAGS_SWUNDI_TRANSMIT_OPMASK  0x0001
+#define PXE_OPFLAGS_TRANSMIT_BLOCK          0x0001
+#define PXE_OPFLAGS_TRANSMIT_DONT_BLOCK     0x0000
+
+#define PXE_OPFLAGS_TRANSMIT_OPMASK     0x0002
+#define PXE_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002
+#define PXE_OPFLAGS_TRANSMIT_WHOLE      0x0000
+
+///
+/// UNDI Receive.
+///
+/// No OpFlags.
+///
+
+///
+/// PXE STATFLAGS.
+///
+typedef PXE_UINT16  PXE_STATFLAGS;
+
+#define PXE_STATFLAGS_INITIALIZE  0x0000
+
+///
+/// Common StatFlags that can be returned by all commands.
+///
+///
+/// The COMMAND_COMPLETE and COMMAND_FAILED status flags must be
+/// implemented by all UNDIs.  COMMAND_QUEUED is only needed by UNDIs
+/// that support command queuing.
+///
+#define PXE_STATFLAGS_STATUS_MASK       0xC000
+#define PXE_STATFLAGS_COMMAND_COMPLETE  0xC000
+#define PXE_STATFLAGS_COMMAND_FAILED    0x8000
+#define PXE_STATFLAGS_COMMAND_QUEUED    0x4000
+
+///
+/// UNDI Get State.
+///
+#define PXE_STATFLAGS_GET_STATE_MASK        0x0003
+#define PXE_STATFLAGS_GET_STATE_INITIALIZED 0x0002
+#define PXE_STATFLAGS_GET_STATE_STARTED     0x0001
+#define PXE_STATFLAGS_GET_STATE_STOPPED     0x0000
+
+///
+/// UNDI Start.
+///
+/// No additional StatFlags.
+///
+
+///
+/// UNDI Get Init Info.
+///
+#define PXE_STATFLAGS_CABLE_DETECT_MASK           0x0001
+#define PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED  0x0000
+#define PXE_STATFLAGS_CABLE_DETECT_SUPPORTED      0x0001
+
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK           0x0002
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED  0x0000
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED      0x0002
+
+///
+/// UNDI Initialize.
+///
+#define PXE_STATFLAGS_INITIALIZED_NO_MEDIA  0x0001
+
+///
+/// UNDI Reset.
+///
+#define PXE_STATFLAGS_RESET_NO_MEDIA  0x0001
+
+///
+/// UNDI Shutdown.
+///
+/// No additional StatFlags.
+
+///
+/// UNDI Interrupt Enables.
+///
+///
+/// If set, receive interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_RECEIVE 0x0001
+
+///
+/// If set, transmit interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_TRANSMIT  0x0002
+
+///
+/// If set, command interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_COMMAND 0x0004
+
+///
+/// UNDI Receive Filters.
+///
+
+///
+/// If set, unicast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_UNICAST  0x0001
+
+///
+/// If set, broadcast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST  0x0002
+
+///
+/// If set, multicast packets that match up with the multicast address
+/// filter list will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+///
+/// If set, all packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS  0x0008
+
+///
+/// If set, all multicast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST  0x0010
+
+///
+/// UNDI Station Address.
+///
+/// No additional StatFlags.
+///
+
+///
+/// UNDI Statistics.
+///
+/// No additional StatFlags.
+///
+
+///
+//// UNDI MCast IP to MAC.
+////
+//// No additional StatFlags.
+
+///
+/// UNDI NvData.
+///
+/// No additional StatFlags.
+///
+
+///
+/// UNDI Get Status.
+///
+
+///
+/// Use to determine if an interrupt has occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F
+#define PXE_STATFLAGS_GET_STATUS_NO_INTERRUPTS  0x0000
+
+///
+/// If set, at least one receive interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_RECEIVE  0x0001
+
+///
+/// If set, at least one transmit interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_TRANSMIT 0x0002
+
+///
+/// If set, at least one command interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_COMMAND  0x0004
+
+///
+/// If set, at least one software interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_SOFTWARE 0x0008
+
+///
+/// This flag is set if the transmitted buffer queue is empty.  This flag
+/// will be set if all transmitted buffer addresses get written into the DB.
+///
+#define PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY  0x0010
+
+///
+/// This flag is set if no transmitted buffer addresses were written
+/// into the DB.  (This could be because DBsize was too small.)
+///
+#define PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN  0x0020
+
+///
+/// This flag is set if there is no media detected.
+///
+#define PXE_STATFLAGS_GET_STATUS_NO_MEDIA  0x0040
+
+///
+/// UNDI Fill Header.
+///
+/// No additional StatFlags.
+///
+
+///
+/// UNDI Transmit.
+///
+/// No additional StatFlags.
+
+///
+/// UNDI Receive
+///.
+
+///
+/// No additional StatFlags.
+///
+typedef PXE_UINT16  PXE_STATCODE;
+
+#define PXE_STATCODE_INITIALIZE 0x0000
+
+///
+/// Common StatCodes returned by all UNDI commands, UNDI protocol functions
+/// and BC protocol functions.
+///
+#define PXE_STATCODE_SUCCESS              0x0000
+
+#define PXE_STATCODE_INVALID_CDB          0x0001
+#define PXE_STATCODE_INVALID_CPB          0x0002
+#define PXE_STATCODE_BUSY                 0x0003
+#define PXE_STATCODE_QUEUE_FULL           0x0004
+#define PXE_STATCODE_ALREADY_STARTED      0x0005
+#define PXE_STATCODE_NOT_STARTED          0x0006
+#define PXE_STATCODE_NOT_SHUTDOWN         0x0007
+#define PXE_STATCODE_ALREADY_INITIALIZED  0x0008
+#define PXE_STATCODE_NOT_INITIALIZED      0x0009
+#define PXE_STATCODE_DEVICE_FAILURE       0x000A
+#define PXE_STATCODE_NVDATA_FAILURE       0x000B
+#define PXE_STATCODE_UNSUPPORTED          0x000C
+#define PXE_STATCODE_BUFFER_FULL          0x000D
+#define PXE_STATCODE_INVALID_PARAMETER    0x000E
+#define PXE_STATCODE_INVALID_UNDI         0x000F
+#define PXE_STATCODE_IPV4_NOT_SUPPORTED   0x0010
+#define PXE_STATCODE_IPV6_NOT_SUPPORTED   0x0011
+#define PXE_STATCODE_NOT_ENOUGH_MEMORY    0x0012
+#define PXE_STATCODE_NO_DATA              0x0013
+
+typedef PXE_UINT16  PXE_IFNUM;
+
+///
+/// This interface number must be passed to the S/W UNDI Start command.
+///
+#define PXE_IFNUM_START 0x0000
+
+///
+/// This interface number is returned by the S/W UNDI Get State and
+/// Start commands if information in the CDB, CPB or DB is invalid.
+///
+#define PXE_IFNUM_INVALID 0x0000
+
+typedef PXE_UINT16  PXE_CONTROL;
+
+///
+/// Setting this flag directs the UNDI to queue this command for later
+/// execution if the UNDI is busy and it supports command queuing.
+/// If queuing is not supported, a PXE_STATCODE_INVALID_CONTROL error
+/// is returned.  If the queue is full, a PXE_STATCODE_CDB_QUEUE_FULL
+/// error is returned.
+///
+#define PXE_CONTROL_QUEUE_IF_BUSY 0x0002
+
+///
+/// These two bit values are used to determine if there are more UNDI
+/// CDB structures following this one.  If the link bit is set, there
+/// must be a CDB structure following this one.  Execution will start
+/// on the next CDB structure as soon as this one completes successfully.
+/// If an error is generated by this command, execution will stop.
+///
+#define PXE_CONTROL_LINK              0x0001
+#define PXE_CONTROL_LAST_CDB_IN_LIST  0x0000
+
+typedef PXE_UINT8   PXE_FRAME_TYPE;
+
+#define PXE_FRAME_TYPE_NONE                     0x00
+#define PXE_FRAME_TYPE_UNICAST                  0x01
+#define PXE_FRAME_TYPE_BROADCAST                0x02
+#define PXE_FRAME_TYPE_FILTERED_MULTICAST       0x03
+#define PXE_FRAME_TYPE_PROMISCUOUS              0x04
+#define PXE_FRAME_TYPE_PROMISCUOUS_MULTICAST    0x05
+
+#define PXE_FRAME_TYPE_MULTICAST                PXE_FRAME_TYPE_FILTERED_MULTICAST
+
+typedef PXE_UINT32  PXE_IPV4;
+
+typedef PXE_UINT32  PXE_IPV6[4];
+#define PXE_MAC_LENGTH  32
+
+typedef PXE_UINT8   PXE_MAC_ADDR[PXE_MAC_LENGTH];
+
+typedef PXE_UINT8   PXE_IFTYPE;
+typedef UINT16      PXE_MEDIA_PROTOCOL;
+
+///
+/// This information is from the ARP section of RFC 1700.
+///
+///     1 Ethernet (10Mb)                                    [JBP]
+///     2 Experimental Ethernet (3Mb)                        [JBP]
+///     3 Amateur Radio AX.25                                [PXK]
+///     4 Proteon ProNET Token Ring                          [JBP]
+///     5 Chaos                                              [GXP]
+///     6 IEEE 802 Networks                                  [JBP]
+///     7 ARCNET                                             [JBP]
+///     8 Hyperchannel                                       [JBP]
+///     9 Lanstar                                             [TU]
+///    10 Autonet Short Address                             [MXB1]
+///    11 LocalTalk                                         [JKR1]
+///    12 LocalNet (IBM* PCNet or SYTEK* LocalNET)           [JXM]
+///    13 Ultra link                                        [RXD2]
+///    14 SMDS                                              [GXC1]
+///    15 Frame Relay                                        [AGM]
+///    16 Asynchronous Transmission Mode (ATM)              [JXB2]
+///    17 HDLC                                               [JBP]
+///    18 Fibre Channel                            [Yakov Rekhter]
+///    19 Asynchronous Transmission Mode (ATM)      [Mark Laubach]
+///    20 Serial Line                                        [JBP]
+///    21 Asynchronous Transmission Mode (ATM)              [MXB1]
+///
+/// * Other names and brands may be claimed as the property of others.
+///
+#define PXE_IFTYPE_ETHERNET       0x01
+#define PXE_IFTYPE_TOKENRING      0x04
+#define PXE_IFTYPE_FIBRE_CHANNEL  0x12
+
+typedef struct s_pxe_hw_undi {
+  PXE_UINT32  Signature;      ///< PXE_ROMID_SIGNATURE.
+  PXE_UINT8   Len;            ///< sizeof(PXE_HW_UNDI).
+  PXE_UINT8   Fudge;          ///< makes 8-bit cksum equal zero.
+  PXE_UINT8   Rev;            ///< PXE_ROMID_REV.
+  PXE_UINT8   IFcnt;          ///< physical connector count.
+  PXE_UINT8   MajorVer;       ///< PXE_ROMID_MAJORVER.
+  PXE_UINT8   MinorVer;       ///< PXE_ROMID_MINORVER.
+  PXE_UINT16  reserved;       ///< zero, not used.
+  PXE_UINT32  Implementation; ///< implementation flags.
+  ///< reserved             ///< vendor use.
+  ///< UINT32 Status;       ///< status port.
+  ///< UINT32 Command;      ///< command port.
+  ///< UINT64 CDBaddr;      ///< CDB address port.
+  ///<
+} PXE_HW_UNDI;
+
+///
+/// Status port bit definitions.
+///
+
+///
+/// UNDI operation state.
+///
+#define PXE_HWSTAT_STATE_MASK   0xC0000000
+#define PXE_HWSTAT_BUSY         0xC0000000
+#define PXE_HWSTAT_INITIALIZED  0x80000000
+#define PXE_HWSTAT_STARTED      0x40000000
+#define PXE_HWSTAT_STOPPED      0x00000000
+
+///
+/// If set, last command failed.
+///
+#define PXE_HWSTAT_COMMAND_FAILED 0x20000000
+
+///
+/// If set, identifies enabled receive filters.
+///
+#define PXE_HWSTAT_PROMISCUOUS_MULTICAST_RX_ENABLED 0x00001000
+#define PXE_HWSTAT_PROMISCUOUS_RX_ENABLED           0x00000800
+#define PXE_HWSTAT_BROADCAST_RX_ENABLED             0x00000400
+#define PXE_HWSTAT_MULTICAST_RX_ENABLED             0x00000200
+#define PXE_HWSTAT_UNICAST_RX_ENABLED               0x00000100
+
+///
+/// If set, identifies enabled external interrupts.
+///
+#define PXE_HWSTAT_SOFTWARE_INT_ENABLED     0x00000080
+#define PXE_HWSTAT_TX_COMPLETE_INT_ENABLED  0x00000040
+#define PXE_HWSTAT_PACKET_RX_INT_ENABLED    0x00000020
+#define PXE_HWSTAT_CMD_COMPLETE_INT_ENABLED 0x00000010
+
+///
+/// If set, identifies pending interrupts.
+///
+#define PXE_HWSTAT_SOFTWARE_INT_PENDING     0x00000008
+#define PXE_HWSTAT_TX_COMPLETE_INT_PENDING  0x00000004
+#define PXE_HWSTAT_PACKET_RX_INT_PENDING    0x00000002
+#define PXE_HWSTAT_CMD_COMPLETE_INT_PENDING 0x00000001
+
+///
+/// Command port definitions.
+///
+
+///
+/// If set, CDB identified in CDBaddr port is given to UNDI.
+/// If not set, other bits in this word will be processed.
+///
+#define PXE_HWCMD_ISSUE_COMMAND   0x80000000
+#define PXE_HWCMD_INTS_AND_FILTS  0x00000000
+
+///
+/// Use these to enable/disable receive filters.
+///
+#define PXE_HWCMD_PROMISCUOUS_MULTICAST_RX_ENABLE 0x00001000
+#define PXE_HWCMD_PROMISCUOUS_RX_ENABLE           0x00000800
+#define PXE_HWCMD_BROADCAST_RX_ENABLE             0x00000400
+#define PXE_HWCMD_MULTICAST_RX_ENABLE             0x00000200
+#define PXE_HWCMD_UNICAST_RX_ENABLE               0x00000100
+
+///
+/// Use these to enable/disable external interrupts.
+///
+#define PXE_HWCMD_SOFTWARE_INT_ENABLE     0x00000080
+#define PXE_HWCMD_TX_COMPLETE_INT_ENABLE  0x00000040
+#define PXE_HWCMD_PACKET_RX_INT_ENABLE    0x00000020
+#define PXE_HWCMD_CMD_COMPLETE_INT_ENABLE 0x00000010
+
+///
+/// Use these to clear pending external interrupts.
+///
+#define PXE_HWCMD_CLEAR_SOFTWARE_INT      0x00000008
+#define PXE_HWCMD_CLEAR_TX_COMPLETE_INT   0x00000004
+#define PXE_HWCMD_CLEAR_PACKET_RX_INT     0x00000002
+#define PXE_HWCMD_CLEAR_CMD_COMPLETE_INT  0x00000001
+
+typedef struct s_pxe_sw_undi {
+  PXE_UINT32  Signature;      ///< PXE_ROMID_SIGNATURE.
+  PXE_UINT8   Len;            ///< sizeof(PXE_SW_UNDI).
+  PXE_UINT8   Fudge;          ///< makes 8-bit cksum zero.
+  PXE_UINT8   Rev;            ///< PXE_ROMID_REV.
+  PXE_UINT8   IFcnt;          ///< physical connector count.
+  PXE_UINT8   MajorVer;       ///< PXE_ROMID_MAJORVER.
+  PXE_UINT8   MinorVer;       ///< PXE_ROMID_MINORVER.
+  PXE_UINT16  reserved1;      ///< zero, not used.
+  PXE_UINT32  Implementation; ///< Implementation flags.
+  PXE_UINT64  EntryPoint;     ///< API entry point.
+  PXE_UINT8   reserved2[3];   ///< zero, not used.
+  PXE_UINT8   BusCnt;         ///< number of bustypes supported.
+  PXE_UINT32  BusType[1];     ///< list of supported bustypes.
+} PXE_SW_UNDI;
+
+typedef union u_pxe_undi {
+  PXE_HW_UNDI hw;
+  PXE_SW_UNDI sw;
+} PXE_UNDI;
+
+///
+/// Signature of !PXE structure.
+///
+#define PXE_ROMID_SIGNATURE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+///
+/// !PXE structure format revision
+///.
+#define PXE_ROMID_REV 0x02
+
+///
+/// UNDI command interface revision.  These are the values that get sent
+/// in option 94 (Client Network Interface Identifier) in the DHCP Discover
+/// and PXE Boot Server Request packets.
+///
+#define PXE_ROMID_MAJORVER    0x03
+#define PXE_ROMID_MINORVER    0x01
+
+///
+/// Implementation flags.
+///
+#define PXE_ROMID_IMP_HW_UNDI                             0x80000000
+#define PXE_ROMID_IMP_SW_VIRT_ADDR                        0x40000000
+#define PXE_ROMID_IMP_64BIT_DEVICE                        0x00010000
+#define PXE_ROMID_IMP_FRAG_SUPPORTED                      0x00008000
+#define PXE_ROMID_IMP_CMD_LINK_SUPPORTED                  0x00004000
+#define PXE_ROMID_IMP_CMD_QUEUE_SUPPORTED                 0x00002000
+#define PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED               0x00001000
+#define PXE_ROMID_IMP_NVDATA_SUPPORT_MASK                 0x00000C00
+#define PXE_ROMID_IMP_NVDATA_BULK_WRITABLE                0x00000C00
+#define PXE_ROMID_IMP_NVDATA_SPARSE_WRITABLE              0x00000800
+#define PXE_ROMID_IMP_NVDATA_READ_ONLY                    0x00000400
+#define PXE_ROMID_IMP_NVDATA_NOT_AVAILABLE                0x00000000
+#define PXE_ROMID_IMP_STATISTICS_SUPPORTED                0x00000200
+#define PXE_ROMID_IMP_STATION_ADDR_SETTABLE               0x00000100
+#define PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED  0x00000080
+#define PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED            0x00000040
+#define PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED              0x00000020
+#define PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED     0x00000010
+#define PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED              0x00000008
+#define PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED           0x00000004
+#define PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED             0x00000002
+#define PXE_ROMID_IMP_CMD_COMPLETE_INT_SUPPORTED          0x00000001
+
+typedef struct s_pxe_cdb {
+  PXE_OPCODE    OpCode;
+  PXE_OPFLAGS   OpFlags;
+  PXE_UINT16    CPBsize;
+  PXE_UINT16    DBsize;
+  PXE_UINT64    CPBaddr;
+  PXE_UINT64    DBaddr;
+  PXE_STATCODE  StatCode;
+  PXE_STATFLAGS StatFlags;
+  PXE_UINT16    IFnum;
+  PXE_CONTROL   Control;
+} PXE_CDB;
+
+typedef union u_pxe_ip_addr {
+  PXE_IPV6  IPv6;
+  PXE_IPV4  IPv4;
+} PXE_IP_ADDR;
+
+typedef union pxe_device {
+  ///
+  /// PCI and PC Card NICs are both identified using bus, device
+  /// and function numbers.  For PC Card, this may require PC
+  /// Card services to be loaded in the BIOS or preboot
+  /// environment.
+  ///
+  struct {
+    ///
+    /// See S/W UNDI ROMID structure definition for PCI and
+    /// PCC BusType definitions.
+    ///
+    PXE_UINT32  BusType;
+
+    ///
+    /// Bus, device & function numbers that locate this device.
+    ///
+    PXE_UINT16  Bus;
+    PXE_UINT8   Device;
+    PXE_UINT8   Function;
+  }
+  PCI, PCC;
+
+} PXE_DEVICE;
+
+///
+/// cpb and db definitions
+///
+#define MAX_PCI_CONFIG_LEN    64  ///< # of dwords.
+#define MAX_EEPROM_LEN        128 ///< # of dwords.
+#define MAX_XMIT_BUFFERS      32  ///< recycling Q length for xmit_done.
+#define MAX_MCAST_ADDRESS_CNT 8
+
+typedef struct s_pxe_cpb_start_30 {
+  ///
+  /// PXE_VOID Delay(UINTN microseconds);
+  ///
+  /// UNDI will never request a delay smaller than 10 microseconds
+  /// and will always request delays in increments of 10 microseconds.
+  /// The Delay() CallBack routine must delay between n and n + 10
+  /// microseconds before returning control to the UNDI.
+  ///
+  /// This field cannot be set to zero.
+  ///
+  UINT64  Delay;
+
+  ///
+  /// PXE_VOID Block(UINT32 enable);
+  ///
+  /// UNDI may need to block multi-threaded/multi-processor access to
+  /// critical code sections when programming or accessing the network
+  /// device.  To this end, a blocking service is needed by the UNDI.
+  /// When UNDI needs a block, it will call Block() passing a non-zero
+  /// value.  When UNDI no longer needs a block, it will call Block()
+  /// with a zero value.  When called, if the Block() is already enabled,
+  /// do not return control to the UNDI until the previous Block() is
+  /// disabled.
+  ///
+  /// This field cannot be set to zero.
+  ///
+  UINT64  Block;
+
+  ///
+  /// PXE_VOID Virt2Phys(UINT64 virtual, UINT64 physical_ptr);
+  ///
+  /// UNDI will pass the virtual address of a buffer and the virtual
+  /// address of a 64-bit physical buffer.  Convert the virtual address
+  /// to a physical address and write the result to the physical address
+  /// buffer.  If virtual and physical addresses are the same, just
+  /// copy the virtual address to the physical address buffer.
+  ///
+  /// This field can be set to zero if virtual and physical addresses
+  /// are equal.
+  ///
+  UINT64  Virt2Phys;
+  ///
+  /// PXE_VOID Mem_IO(UINT8 read_write, UINT8 len, UINT64 port,
+  ///              UINT64 buf_addr);
+  ///
+  /// UNDI will read or write the device io space using this call back
+  /// function. It passes the number of bytes as the len parameter and it
+  /// will be either 1,2,4 or 8.
+  ///
+  /// This field can not be set to zero.
+  ///
+  UINT64  Mem_IO;
+} PXE_CPB_START_30;
+
+typedef struct s_pxe_cpb_start_31 {
+  ///
+  /// PXE_VOID Delay(UINT64 UnqId, UINTN microseconds);
+  ///
+  /// UNDI will never request a delay smaller than 10 microseconds
+  /// and will always request delays in increments of 10 microseconds.
+  /// The Delay() CallBack routine must delay between n and n + 10
+  /// microseconds before returning control to the UNDI.
+  ///
+  /// This field cannot be set to zero.
+  ///
+  UINT64  Delay;
+
+  ///
+  /// PXE_VOID Block(UINT64 unq_id, UINT32 enable);
+  ///
+  /// UNDI may need to block multi-threaded/multi-processor access to
+  /// critical code sections when programming or accessing the network
+  /// device.  To this end, a blocking service is needed by the UNDI.
+  /// When UNDI needs a block, it will call Block() passing a non-zero
+  /// value.  When UNDI no longer needs a block, it will call Block()
+  /// with a zero value.  When called, if the Block() is already enabled,
+  /// do not return control to the UNDI until the previous Block() is
+  /// disabled.
+  ///
+  /// This field cannot be set to zero.
+  ///
+  UINT64  Block;
+
+  ///
+  /// PXE_VOID Virt2Phys(UINT64 UnqId, UINT64 virtual, UINT64 physical_ptr);
+  ///
+  /// UNDI will pass the virtual address of a buffer and the virtual
+  /// address of a 64-bit physical buffer.  Convert the virtual address
+  /// to a physical address and write the result to the physical address
+  /// buffer.  If virtual and physical addresses are the same, just
+  /// copy the virtual address to the physical address buffer.
+  ///
+  /// This field can be set to zero if virtual and physical addresses
+  /// are equal.
+  ///
+  UINT64  Virt2Phys;
+  ///
+  /// PXE_VOID Mem_IO(UINT64 UnqId, UINT8 read_write, UINT8 len, UINT64 port,
+  ///              UINT64 buf_addr);
+  ///
+  /// UNDI will read or write the device io space using this call back
+  /// function. It passes the number of bytes as the len parameter and it
+  /// will be either 1,2,4 or 8.
+  ///
+  /// This field can not be set to zero.
+  ///
+  UINT64  Mem_IO;
+  ///
+  /// PXE_VOID Map_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+  ///                 UINT32 Direction, UINT64 mapped_addr);
+  ///
+  /// UNDI will pass the virtual address of a buffer, direction of the data
+  /// flow from/to the mapped buffer (the constants are defined below)
+  /// and a place holder (pointer) for the mapped address.
+  /// This call will Map the given address to a physical DMA address and write
+  /// the result to the mapped_addr pointer.  If there is no need to
+  /// map the given address to a lower address (i.e. the given address is
+  /// associated with a physical address that is already compatible to be
+  /// used with the DMA, it converts the given virtual address to it's
+  /// physical address and write that in the mapped address pointer.
+  ///
+  /// This field can be set to zero if there is no mapping service available.
+  ///
+  UINT64  Map_Mem;
+
+  ///
+  /// PXE_VOID UnMap_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+  ///            UINT32 Direction, UINT64 mapped_addr);
+  ///
+  /// UNDI will pass the virtual and mapped addresses of a buffer.
+  /// This call will un map the given address.
+  ///
+  /// This field can be set to zero if there is no unmapping service available.
+  ///
+  UINT64  UnMap_Mem;
+
+  ///
+  /// PXE_VOID Sync_Mem(UINT64 unq_id, UINT64 virtual,
+  ///            UINT32 size, UINT32 Direction, UINT64 mapped_addr);
+  ///
+  /// UNDI will pass the virtual and mapped addresses of a buffer.
+  /// This call will synchronize the contents of both the virtual and mapped.
+  /// buffers for the given Direction.
+  ///
+  /// This field can be set to zero if there is no service available.
+  ///
+  UINT64  Sync_Mem;
+
+  ///
+  /// protocol driver can provide anything for this Unique_ID, UNDI remembers
+  /// that as just a 64bit value assocaited to the interface specified by
+  /// the ifnum and gives it back as a parameter to all the call-back routines
+  /// when calling for that interface!
+  ///
+  UINT64  Unique_ID;
+} PXE_CPB_START_31;
+
+#define TO_AND_FROM_DEVICE    0
+#define FROM_DEVICE           1
+#define TO_DEVICE             2
+
+#define PXE_DELAY_MILLISECOND 1000
+#define PXE_DELAY_SECOND      1000000
+#define PXE_IO_READ           0
+#define PXE_IO_WRITE          1
+#define PXE_MEM_READ          2
+#define PXE_MEM_WRITE         4
+
+typedef struct s_pxe_db_get_init_info {
+  ///
+  /// Minimum length of locked memory buffer that must be given to
+  /// the Initialize command. Giving UNDI more memory will generally
+  /// give better performance.
+  ///
+  /// If MemoryRequired is zero, the UNDI does not need and will not
+  /// use system memory to receive and transmit packets.
+  ///
+  PXE_UINT32  MemoryRequired;
+
+  ///
+  /// Maximum frame data length for Tx/Rx excluding the media header.
+  ///
+  PXE_UINT32  FrameDataLen;
+
+  ///
+  /// Supported link speeds are in units of mega bits.  Common ethernet
+  /// values are 10, 100 and 1000.  Unused LinkSpeeds[] entries are zero
+  /// filled.
+  ///
+  PXE_UINT32  LinkSpeeds[4];
+
+  ///
+  /// Number of non-volatile storage items.
+  ///
+  PXE_UINT32  NvCount;
+
+  ///
+  /// Width of non-volatile storage item in bytes.  0, 1, 2 or 4
+  ///
+  PXE_UINT16  NvWidth;
+
+  ///
+  /// Media header length.  This is the typical media header length for
+  /// this UNDI.  This information is needed when allocating receive
+  /// and transmit buffers.
+  ///
+  PXE_UINT16  MediaHeaderLen;
+
+  ///
+  /// Number of bytes in the NIC hardware (MAC) address.
+  ///
+  PXE_UINT16  HWaddrLen;
+
+  ///
+  /// Maximum number of multicast MAC addresses in the multicast
+  /// MAC address filter list.
+  ///
+  PXE_UINT16  MCastFilterCnt;
+
+  ///
+  /// Default number and size of transmit and receive buffers that will
+  /// be allocated by the UNDI.  If MemoryRequired is non-zero, this
+  /// allocation will come out of the memory buffer given to the Initialize
+  /// command.  If MemoryRequired is zero, this allocation will come out of
+  /// memory on the NIC.
+  ///
+  PXE_UINT16  TxBufCnt;
+  PXE_UINT16  TxBufSize;
+  PXE_UINT16  RxBufCnt;
+  PXE_UINT16  RxBufSize;
+
+  ///
+  /// Hardware interface types defined in the Assigned Numbers RFC
+  /// and used in DHCP and ARP packets.
+  /// See the PXE_IFTYPE typedef and PXE_IFTYPE_xxx macros.
+  ///
+  PXE_UINT8   IFtype;
+
+  ///
+  /// Supported duplex.  See PXE_DUPLEX_xxxxx #defines below.
+  ///
+  PXE_UINT8   SupportedDuplexModes;
+
+  ///
+  /// Supported loopback options.  See PXE_LOOPBACK_xxxxx #defines below.
+  ///
+  PXE_UINT8   SupportedLoopBackModes;
+} PXE_DB_GET_INIT_INFO;
+
+#define PXE_MAX_TXRX_UNIT_ETHER           1500
+
+#define PXE_HWADDR_LEN_ETHER              0x0006
+#define PXE_MAC_HEADER_LEN_ETHER          0x000E
+
+#define PXE_DUPLEX_ENABLE_FULL_SUPPORTED  1
+#define PXE_DUPLEX_FORCE_FULL_SUPPORTED   2
+
+#define PXE_LOOPBACK_INTERNAL_SUPPORTED   1
+#define PXE_LOOPBACK_EXTERNAL_SUPPORTED   2
+
+typedef struct s_pxe_pci_config_info {
+  ///
+  /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+  /// For PCI bus devices, this field is set to PXE_BUSTYPE_PCI.
+  ///
+  UINT32  BusType;
+
+  ///
+  /// This identifies the PCI network device that this UNDI interface.
+  /// is bound to.
+  ///
+  UINT16  Bus;
+  UINT8   Device;
+  UINT8   Function;
+
+  ///
+  /// This is a copy of the PCI configuration space for this
+  /// network device.
+  ///
+  union {
+    UINT8   Byte[256];
+    UINT16  Word[128];
+    UINT32  Dword[64];
+  } Config;
+} PXE_PCI_CONFIG_INFO;
+
+typedef struct s_pxe_pcc_config_info {
+  ///
+  /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+  /// For PCC bus devices, this field is set to PXE_BUSTYPE_PCC.
+  ///
+  PXE_UINT32  BusType;
+
+  ///
+  /// This identifies the PCC network device that this UNDI interface
+  /// is bound to.
+  ///
+  PXE_UINT16  Bus;
+  PXE_UINT8   Device;
+  PXE_UINT8   Function;
+
+  ///
+  /// This is a copy of the PCC configuration space for this
+  /// network device.
+  ///
+  union {
+    PXE_UINT8   Byte[256];
+    PXE_UINT16  Word[128];
+    PXE_UINT32  Dword[64];
+  } Config;
+} PXE_PCC_CONFIG_INFO;
+
+typedef union u_pxe_db_get_config_info {
+  PXE_PCI_CONFIG_INFO   pci;
+  PXE_PCC_CONFIG_INFO   pcc;
+} PXE_DB_GET_CONFIG_INFO;
+
+typedef struct s_pxe_cpb_initialize {
+  ///
+  /// Address of first (lowest) byte of the memory buffer.  This buffer must
+  /// be in contiguous physical memory and cannot be swapped out.  The UNDI
+  /// will be using this for transmit and receive buffering.
+  ///
+  PXE_UINT64  MemoryAddr;
+
+  ///
+  /// MemoryLength must be greater than or equal to MemoryRequired
+  /// returned by the Get Init Info command.
+  ///
+  PXE_UINT32  MemoryLength;
+
+  ///
+  /// Desired link speed in Mbit/sec.  Common ethernet values are 10, 100
+  /// and 1000.  Setting a value of zero will auto-detect and/or use the
+  /// default link speed (operation depends on UNDI/NIC functionality).
+  ///
+  PXE_UINT32  LinkSpeed;
+
+  ///
+  /// Suggested number and size of receive and transmit buffers to
+  /// allocate.  If MemoryAddr and MemoryLength are non-zero, this
+  /// allocation comes out of the supplied memory buffer.  If MemoryAddr
+  /// and MemoryLength are zero, this allocation comes out of memory
+  /// on the NIC.
+  ///
+  /// If these fields are set to zero, the UNDI will allocate buffer
+  /// counts and sizes as it sees fit.
+  ///
+  PXE_UINT16  TxBufCnt;
+  PXE_UINT16  TxBufSize;
+  PXE_UINT16  RxBufCnt;
+  PXE_UINT16  RxBufSize;
+
+  ///
+  /// The following configuration parameters are optional and must be zero
+  /// to use the default values.
+  ///
+  PXE_UINT8   DuplexMode;
+
+  PXE_UINT8   LoopBackMode;
+} PXE_CPB_INITIALIZE;
+
+#define PXE_DUPLEX_DEFAULT      0x00
+#define PXE_FORCE_FULL_DUPLEX   0x01
+#define PXE_ENABLE_FULL_DUPLEX  0x02
+#define PXE_FORCE_HALF_DUPLEX   0x04
+#define PXE_DISABLE_FULL_DUPLEX 0x08
+
+#define LOOPBACK_NORMAL         0
+#define LOOPBACK_INTERNAL       1
+#define LOOPBACK_EXTERNAL       2
+
+typedef struct s_pxe_db_initialize {
+  ///
+  /// Actual amount of memory used from the supplied memory buffer.  This
+  /// may be less that the amount of memory suppllied and may be zero if
+  /// the UNDI and network device do not use external memory buffers.
+  ///
+  /// Memory used by the UNDI and network device is allocated from the
+  /// lowest memory buffer address.
+  ///
+  PXE_UINT32  MemoryUsed;
+
+  ///
+  /// Actual number and size of receive and transmit buffers that were
+  /// allocated.
+  ///
+  PXE_UINT16  TxBufCnt;
+  PXE_UINT16  TxBufSize;
+  PXE_UINT16  RxBufCnt;
+  PXE_UINT16  RxBufSize;
+} PXE_DB_INITIALIZE;
+
+typedef struct s_pxe_cpb_receive_filters {
+  ///
+  /// List of multicast MAC addresses.  This list, if present, will
+  /// replace the existing multicast MAC address filter list.
+  ///
+  PXE_MAC_ADDR  MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_CPB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_db_receive_filters {
+  ///
+  /// Filtered multicast MAC address list.
+  ///
+  PXE_MAC_ADDR  MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_DB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_cpb_station_address {
+  ///
+  /// If supplied and supported, the current station MAC address
+  /// will be changed.
+  ///
+  PXE_MAC_ADDR  StationAddr;
+} PXE_CPB_STATION_ADDRESS;
+
+typedef struct s_pxe_dpb_station_address {
+  ///
+  /// Current station MAC address.
+  ///
+  PXE_MAC_ADDR  StationAddr;
+
+  ///
+  /// Station broadcast MAC address.
+  ///
+  PXE_MAC_ADDR  BroadcastAddr;
+
+  ///
+  /// Permanent station MAC address.
+  ///
+  PXE_MAC_ADDR  PermanentAddr;
+} PXE_DB_STATION_ADDRESS;
+
+typedef struct s_pxe_db_statistics {
+  ///
+  /// Bit field identifying what statistic data is collected by the
+  /// UNDI/NIC.
+  /// If bit 0x00 is set, Data[0x00] is collected.
+  /// If bit 0x01 is set, Data[0x01] is collected.
+  /// If bit 0x20 is set, Data[0x20] is collected.
+  /// If bit 0x21 is set, Data[0x21] is collected.
+  /// Etc.
+  ///
+  PXE_UINT64  Supported;
+
+  ///
+  /// Statistic data.
+  ///
+  PXE_UINT64  Data[64];
+} PXE_DB_STATISTICS;
+
+///
+/// Total number of frames received.  Includes frames with errors and
+/// dropped frames.
+///
+#define PXE_STATISTICS_RX_TOTAL_FRAMES  0x00
+
+///
+/// Number of valid frames received and copied into receive buffers.
+///
+#define PXE_STATISTICS_RX_GOOD_FRAMES 0x01
+
+///
+/// Number of frames below the minimum length for the media.
+/// This would be <64 for ethernet.
+///
+#define PXE_STATISTICS_RX_UNDERSIZE_FRAMES  0x02
+
+///
+/// Number of frames longer than the maxminum length for the
+/// media.  This would be >1500 for ethernet.
+///
+#define PXE_STATISTICS_RX_OVERSIZE_FRAMES 0x03
+
+///
+/// Valid frames that were dropped because receive buffers were full.
+///
+#define PXE_STATISTICS_RX_DROPPED_FRAMES  0x04
+
+///
+/// Number of valid unicast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_UNICAST_FRAMES  0x05
+
+///
+/// Number of valid broadcast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_BROADCAST_FRAMES  0x06
+
+///
+/// Number of valid mutlicast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_MULTICAST_FRAMES  0x07
+
+///
+/// Number of frames w/ CRC or alignment errors.
+///
+#define PXE_STATISTICS_RX_CRC_ERROR_FRAMES  0x08
+
+///
+/// Total number of bytes received.  Includes frames with errors
+/// and dropped frames.
+///
+#define PXE_STATISTICS_RX_TOTAL_BYTES 0x09
+
+///
+/// Transmit statistics.
+///
+#define PXE_STATISTICS_TX_TOTAL_FRAMES      0x0A
+#define PXE_STATISTICS_TX_GOOD_FRAMES       0x0B
+#define PXE_STATISTICS_TX_UNDERSIZE_FRAMES  0x0C
+#define PXE_STATISTICS_TX_OVERSIZE_FRAMES   0x0D
+#define PXE_STATISTICS_TX_DROPPED_FRAMES    0x0E
+#define PXE_STATISTICS_TX_UNICAST_FRAMES    0x0F
+#define PXE_STATISTICS_TX_BROADCAST_FRAMES  0x10
+#define PXE_STATISTICS_TX_MULTICAST_FRAMES  0x11
+#define PXE_STATISTICS_TX_CRC_ERROR_FRAMES  0x12
+#define PXE_STATISTICS_TX_TOTAL_BYTES       0x13
+
+///
+/// Number of collisions detection on this subnet.
+///
+#define PXE_STATISTICS_COLLISIONS 0x14
+
+///
+/// Number of frames destined for unsupported protocol.
+///
+#define PXE_STATISTICS_UNSUPPORTED_PROTOCOL 0x15
+
+typedef struct s_pxe_cpb_mcast_ip_to_mac {
+  ///
+  /// Multicast IP address to be converted to multicast MAC address.
+  ///
+  PXE_IP_ADDR IP;
+} PXE_CPB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_db_mcast_ip_to_mac {
+  ///
+  /// Multicast MAC address.
+  ///
+  PXE_MAC_ADDR  MAC;
+} PXE_DB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_cpb_nvdata_sparse {
+  ///
+  /// NvData item list.  Only items in this list will be updated.
+  ///
+  struct {
+    ///
+    ///  Non-volatile storage address to be changed.
+    ///
+    PXE_UINT32  Addr;
+
+    ///
+    /// Data item to write into above storage address.
+    ///
+    union {
+      PXE_UINT8   Byte;
+      PXE_UINT16  Word;
+      PXE_UINT32  Dword;
+    } Data;
+  } Item[MAX_EEPROM_LEN];
+} PXE_CPB_NVDATA_SPARSE;
+
+///
+/// When using bulk update, the size of the CPB structure must be
+/// the same size as the non-volatile NIC storage.
+///
+typedef union u_pxe_cpb_nvdata_bulk {
+  ///
+  /// Array of byte-wide data items.
+  ///
+  PXE_UINT8   Byte[MAX_EEPROM_LEN << 2];
+
+  ///
+  /// Array of word-wide data items.
+  ///
+  PXE_UINT16  Word[MAX_EEPROM_LEN << 1];
+
+  ///
+  /// Array of dword-wide data items.
+  ///
+  PXE_UINT32  Dword[MAX_EEPROM_LEN];
+} PXE_CPB_NVDATA_BULK;
+
+typedef struct s_pxe_db_nvdata {
+  ///
+  /// Arrays of data items from non-volatile storage.
+  ///
+  union {
+    ///
+    /// Array of byte-wide data items.
+    ///
+    PXE_UINT8   Byte[MAX_EEPROM_LEN << 2];
+
+    ///
+    /// Array of word-wide data items.
+    ///
+    PXE_UINT16  Word[MAX_EEPROM_LEN << 1];
+
+    ///
+    /// Array of dword-wide data items.
+    ///
+    PXE_UINT32  Dword[MAX_EEPROM_LEN];
+  } Data;
+} PXE_DB_NVDATA;
+
+typedef struct s_pxe_db_get_status {
+  ///
+  /// Length of next receive frame (header + data).  If this is zero,
+  /// there is no next receive frame available.
+  ///
+  PXE_UINT32  RxFrameLen;
+
+  ///
+  /// Reserved, set to zero.
+  ///
+  PXE_UINT32  reserved;
+
+  ///
+  ///  Addresses of transmitted buffers that need to be recycled.
+  ///
+  PXE_UINT64  TxBuffer[MAX_XMIT_BUFFERS];
+} PXE_DB_GET_STATUS;
+
+typedef struct s_pxe_cpb_fill_header {
+  ///
+  /// Source and destination MAC addresses.  These will be copied into
+  /// the media header without doing byte swapping.
+  ///
+  PXE_MAC_ADDR  SrcAddr;
+  PXE_MAC_ADDR  DestAddr;
+
+  ///
+  /// Address of first byte of media header.  The first byte of packet data
+  /// follows the last byte of the media header.
+  ///
+  PXE_UINT64        MediaHeader;
+
+  ///
+  /// Length of packet data in bytes (not including the media header).
+  ///
+  PXE_UINT32        PacketLen;
+
+  ///
+  /// Protocol type.  This will be copied into the media header without
+  /// doing byte swapping.  Protocol type numbers can be obtained from
+  /// the Assigned Numbers RFC 1700.
+  ///
+  PXE_UINT16        Protocol;
+
+  ///
+  /// Length of the media header in bytes.
+  ///
+  PXE_UINT16        MediaHeaderLen;
+} PXE_CPB_FILL_HEADER;
+
+#define PXE_PROTOCOL_ETHERNET_IP  0x0800
+#define PXE_PROTOCOL_ETHERNET_ARP 0x0806
+#define MAX_XMIT_FRAGMENTS        16
+
+typedef struct s_pxe_cpb_fill_header_fragmented {
+  ///
+  /// Source and destination MAC addresses.  These will be copied into
+  /// the media header without doing byte swapping.
+  ///
+  PXE_MAC_ADDR        SrcAddr;
+  PXE_MAC_ADDR        DestAddr;
+
+  ///
+  /// Length of packet data in bytes (not including the media header).
+  ///
+  PXE_UINT32          PacketLen;
+
+  ///
+  /// Protocol type.  This will be copied into the media header without
+  /// doing byte swapping.  Protocol type numbers can be obtained from
+  /// the Assigned Numbers RFC 1700.
+  ///
+  PXE_MEDIA_PROTOCOL  Protocol;
+
+  ///
+  /// Length of the media header in bytes.
+  ///
+  PXE_UINT16          MediaHeaderLen;
+
+  ///
+  /// Number of packet fragment descriptors.
+  ///
+  PXE_UINT16          FragCnt;
+
+  ///
+  /// Reserved, must be set to zero.
+  ///
+  PXE_UINT16          reserved;
+
+  ///
+  /// Array of packet fragment descriptors.  The first byte of the media
+  /// header is the first byte of the first fragment.
+  ///
+  struct {
+    ///
+    /// Address of this packet fragment.
+    ///
+    PXE_UINT64  FragAddr;
+
+    ///
+    /// Length of this packet fragment.
+    ///
+    PXE_UINT32  FragLen;
+
+    ///
+    /// Reserved, must be set to zero.
+    ///
+    PXE_UINT32  reserved;
+  } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_FILL_HEADER_FRAGMENTED;
+
+typedef struct s_pxe_cpb_transmit {
+  ///
+  /// Address of first byte of frame buffer.  This is also the first byte
+  /// of the media header.
+  ///
+  PXE_UINT64  FrameAddr;
+
+  ///
+  /// Length of the data portion of the frame buffer in bytes.  Do not
+  /// include the length of the media header.
+  ///
+  PXE_UINT32  DataLen;
+
+  ///
+  /// Length of the media header in bytes.
+  ///
+  PXE_UINT16  MediaheaderLen;
+
+  ///
+  /// Reserved, must be zero.
+  ///
+  PXE_UINT16  reserved;
+} PXE_CPB_TRANSMIT;
+
+typedef struct s_pxe_cpb_transmit_fragments {
+  ///
+  /// Length of packet data in bytes (not including the media header).
+  ///
+  PXE_UINT32  FrameLen;
+
+  ///
+  /// Length of the media header in bytes.
+  ///
+  PXE_UINT16  MediaheaderLen;
+
+  ///
+  /// Number of packet fragment descriptors.
+  ///
+  PXE_UINT16  FragCnt;
+
+  ///
+  /// Array of frame fragment descriptors.  The first byte of the first
+  /// fragment is also the first byte of the media header.
+  ///
+  struct {
+    ///
+    /// Address of this frame fragment.
+    ///
+    PXE_UINT64  FragAddr;
+
+    ///
+    /// Length of this frame fragment.
+    ///
+    PXE_UINT32  FragLen;
+
+    ///
+    /// Reserved, must be set to zero.
+    ///
+    PXE_UINT32  reserved;
+  } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_TRANSMIT_FRAGMENTS;
+
+typedef struct s_pxe_cpb_receive {
+  ///
+  /// Address of first byte of receive buffer.  This is also the first byte
+  /// of the frame header.
+  ///
+  PXE_UINT64  BufferAddr;
+
+  ///
+  /// Length of receive buffer.  This must be large enough to hold the
+  /// received frame (media header + data).  If the length of smaller than
+  /// the received frame, data will be lost.
+  ///
+  PXE_UINT32  BufferLen;
+
+  ///
+  /// Reserved, must be set to zero.
+  ///
+  PXE_UINT32  reserved;
+} PXE_CPB_RECEIVE;
+
+typedef struct s_pxe_db_receive {
+  ///
+  /// Source and destination MAC addresses from media header.
+  ///
+  PXE_MAC_ADDR        SrcAddr;
+  PXE_MAC_ADDR        DestAddr;
+
+  ///
+  /// Length of received frame.  May be larger than receive buffer size.
+  /// The receive buffer will not be overwritten.  This is how to tell
+  /// if data was lost because the receive buffer was too small.
+  ///
+  PXE_UINT32          FrameLen;
+
+  ///
+  /// Protocol type from media header.
+  ///
+  PXE_MEDIA_PROTOCOL  Protocol;
+
+  ///
+  /// Length of media header in received frame.
+  ///
+  PXE_UINT16          MediaHeaderLen;
+
+  ///
+  /// Type of receive frame.
+  ///
+  PXE_FRAME_TYPE      Type;
+
+  ///
+  /// Reserved, must be zero.
+  ///
+  PXE_UINT8           reserved[7];
+
+} PXE_DB_RECEIVE;
+
+#pragma pack()
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h
new file mode 100644
index 0000000..1f125d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h
@@ -0,0 +1,2099 @@
+/** @file
+  Include file that supports UEFI.
+
+  This include file must contain things defined in the UEFI 2.3 specification.
+  If a code construct is defined in the UEFI 2.3 specification it must be included
+  by this include file.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_SPEC_H__
+#define __UEFI_SPEC_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Uefi/UefiMultiPhase.h>
+
+#include <ipxe/efi/Protocol/DevicePath.h>
+#include <ipxe/efi/Protocol/SimpleTextIn.h>
+#include <ipxe/efi/Protocol/SimpleTextOut.h>
+
+///
+/// Enumeration of EFI memory allocation types.
+///
+typedef enum {
+  ///
+  /// Allocate any available range of pages that satisfies the request.
+  ///
+  AllocateAnyPages,
+  ///
+  /// Allocate any available range of pages whose uppermost address is less than
+  /// or equal to a specified maximum address.
+  ///
+  AllocateMaxAddress,
+  ///
+  /// Allocate pages at a specified address.
+  ///
+  AllocateAddress,
+  ///
+  /// Maximum enumeration value that may be used for bounds checking.
+  ///
+  MaxAllocateType
+} EFI_ALLOCATE_TYPE;
+
+//
+// Bit definitions for EFI_TIME.Daylight
+//
+#define EFI_TIME_ADJUST_DAYLIGHT  0x01
+#define EFI_TIME_IN_DAYLIGHT      0x02
+
+///
+/// Value definition for EFI_TIME.TimeZone.
+///
+#define EFI_UNSPECIFIED_TIMEZONE  0x07FF
+
+//
+// Memory cacheability attributes
+//
+#define EFI_MEMORY_UC   0x0000000000000001ULL
+#define EFI_MEMORY_WC   0x0000000000000002ULL
+#define EFI_MEMORY_WT   0x0000000000000004ULL
+#define EFI_MEMORY_WB   0x0000000000000008ULL
+#define EFI_MEMORY_UCE  0x0000000000000010ULL
+//
+// Physical memory protection attributes
+//
+#define EFI_MEMORY_WP   0x0000000000001000ULL
+#define EFI_MEMORY_RP   0x0000000000002000ULL
+#define EFI_MEMORY_XP   0x0000000000004000ULL
+//
+// Runtime memory attribute
+//
+#define EFI_MEMORY_RUNTIME  0x8000000000000000ULL
+
+///
+/// Memory descriptor version number.
+///
+#define EFI_MEMORY_DESCRIPTOR_VERSION 1
+
+///
+/// Definition of an EFI memory descriptor.
+///
+typedef struct {
+  ///
+  /// Type of the memory region.  See EFI_MEMORY_TYPE.
+  ///
+  UINT32                Type;
+  ///
+  /// Physical address of the first byte of the memory region.  Must aligned
+  /// on a 4 KB boundary.
+  ///
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;
+  ///
+  /// Virtual address of the first byte of the memory region.  Must aligned
+  /// on a 4 KB boundary.
+  ///
+  EFI_VIRTUAL_ADDRESS   VirtualStart;
+  ///
+  /// Number of 4KB pages in the memory region.
+  ///
+  UINT64                NumberOfPages;
+  ///
+  /// Attributes of the memory region that describe the bit mask of capabilities
+  /// for that memory region, and not necessarily the current settings for that
+  /// memory region.
+  ///
+  UINT64                Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+/**
+  Allocates memory pages from the system.
+
+  @param  Type        The type of allocation to perform.
+  @param  MemoryType  The type of memory to allocate.
+  @param  Pages       The number of contiguous 4 KB pages to allocate.
+  @param  Memory      The pointer to a physical address. On input, the way in which the address is
+                      used depends on the value of Type.
+
+  @retval EFI_SUCCESS           The requested pages were allocated.
+  @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or
+                                AllocateMaxAddress or AllocateAddress.
+                                2) MemoryType is in the range
+                                EfiMaxMemoryType..0x7FFFFFFF.
+  @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
+  @retval EFI_NOT_FOUND         The requested pages could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_PAGES)(
+  IN     EFI_ALLOCATE_TYPE            Type,
+  IN     EFI_MEMORY_TYPE              MemoryType,
+  IN     UINTN                        Pages,
+  IN OUT EFI_PHYSICAL_ADDRESS         *Memory
+  );
+
+/**
+  Frees memory pages.
+
+  @param  Memory      The base physical address of the pages to be freed.
+  @param  Pages       The number of contiguous 4 KB pages to free.
+
+  @retval EFI_SUCCESS           The requested pages were freed.
+  @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+  @retval EFI_NOT_FOUND         The requested memory pages were not allocated with
+                                AllocatePages().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_PAGES)(
+  IN  EFI_PHYSICAL_ADDRESS         Memory,
+  IN  UINTN                        Pages
+  );
+
+/**
+  Returns the current memory map.
+
+  @param  MemoryMapSize         A pointer to the size, in bytes, of the MemoryMap buffer.
+                                On input, this is the size of the buffer allocated by the caller.
+                                On output, it is the size of the buffer returned by the firmware if
+                                the buffer was large enough, or the size of the buffer needed to contain
+                                the map if the buffer was too small.
+  @param  MemoryMap             A pointer to the buffer in which firmware places the current memory
+                                map.
+  @param  MapKey                A pointer to the location in which firmware returns the key for the
+                                current memory map.
+  @param  DescriptorSize        A pointer to the location in which firmware returns the size, in bytes, of
+                                an individual EFI_MEMORY_DESCRIPTOR.
+  @param  DescriptorVersion     A pointer to the location in which firmware returns the version number
+                                associated with the EFI_MEMORY_DESCRIPTOR.
+
+  @retval EFI_SUCCESS           The memory map was returned in the MemoryMap buffer.
+  @retval EFI_BUFFER_TOO_SMALL  The MemoryMap buffer was too small. The current buffer size
+                                needed to hold the memory map is returned in MemoryMapSize.
+  @retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL.
+                                2) The MemoryMap buffer is not too small and MemoryMap is
+                                   NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_MAP)(
+  IN OUT UINTN                       *MemoryMapSize,
+  IN OUT EFI_MEMORY_DESCRIPTOR       *MemoryMap,
+  OUT    UINTN                       *MapKey,
+  OUT    UINTN                       *DescriptorSize,
+  OUT    UINT32                      *DescriptorVersion
+  );
+
+/**
+  Allocates pool memory.
+
+  @param  PoolType              The type of pool to allocate.
+  @param  Size                  The number of bytes to allocate from the pool.
+  @param  Buffer                A pointer to a pointer to the allocated buffer if the call succeeds;
+                                undefined otherwise.
+
+  @retval EFI_SUCCESS           The requested number of bytes was allocated.
+  @retval EFI_OUT_OF_RESOURCES  The pool requested could not be allocated.
+  @retval EFI_INVALID_PARAMETER PoolType was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_POOL)(
+  IN  EFI_MEMORY_TYPE              PoolType,
+  IN  UINTN                        Size,
+  OUT VOID                         **Buffer
+  );
+
+/**
+  Returns pool memory to the system.
+
+  @param  Buffer                The pointer to the buffer to free.
+
+  @retval EFI_SUCCESS           The memory was returned to the system.
+  @retval EFI_INVALID_PARAMETER Buffer was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_POOL)(
+  IN  VOID                         *Buffer
+  );
+
+/**
+  Changes the runtime addressing mode of EFI firmware from physical to virtual.
+
+  @param  MemoryMapSize         The size in bytes of VirtualMap.
+  @param  DescriptorSize        The size in bytes of an entry in the VirtualMap.
+  @param  DescriptorVersion     The version of the structure entries in VirtualMap.
+  @param  VirtualMap            An array of memory descriptors which contain new virtual
+                                address mapping information for all runtime ranges.
+
+  @retval EFI_SUCCESS           The virtual address map has been applied.
+  @retval EFI_UNSUPPORTED       EFI firmware is not at runtime, or the EFI firmware is already in
+                                virtual address mapped mode.
+  @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid.
+  @retval EFI_NO_MAPPING        A virtual address was not supplied for a range in the memory
+                                map that requires a mapping.
+  @retval EFI_NOT_FOUND         A virtual address was supplied for an address that is not found
+                                in the memory map.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)(
+  IN  UINTN                        MemoryMapSize,
+  IN  UINTN                        DescriptorSize,
+  IN  UINT32                       DescriptorVersion,
+  IN  EFI_MEMORY_DESCRIPTOR        *VirtualMap
+  );
+
+/**
+  Connects one or more drivers to a controller.
+
+  @param  ControllerHandle      The handle of the controller to which driver(s) are to be connected.
+  @param  DriverImageHandle     A pointer to an ordered list handles that support the
+                                EFI_DRIVER_BINDING_PROTOCOL.
+  @param  RemainingDevicePath   A pointer to the device path that specifies a child of the
+                                controller specified by ControllerHandle.
+  @param  Recursive             If TRUE, then ConnectController() is called recursively
+                                until the entire tree of controllers below the controller specified
+                                by ControllerHandle have been created. If FALSE, then
+                                the tree of controllers is only expanded one level.
+
+  @retval EFI_SUCCESS           1) One or more drivers were connected to ControllerHandle.
+                                2) No drivers were connected to ControllerHandle, but
+                                RemainingDevicePath is not NULL, and it is an End Device
+                                Path Node.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+  @retval EFI_NOT_FOUND         1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+                                present in the system.
+                                2) No drivers were connected to ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONNECT_CONTROLLER)(
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  EFI_HANDLE                    *DriverImageHandle,   OPTIONAL
+  IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath, OPTIONAL
+  IN  BOOLEAN                       Recursive
+  );
+
+/**
+  Disconnects one or more drivers from a controller.
+
+  @param  ControllerHandle      The handle of the controller from which driver(s) are to be disconnected.
+  @param  DriverImageHandle     The driver to disconnect from ControllerHandle.
+                                If DriverImageHandle is NULL, then all the drivers currently managing
+                                ControllerHandle are disconnected from ControllerHandle.
+  @param  ChildHandle           The handle of the child to destroy.
+                                If ChildHandle is NULL, then all the children of ControllerHandle are
+                                destroyed before the drivers are disconnected from ControllerHandle.
+
+  @retval EFI_SUCCESS           1) One or more drivers were disconnected from the controller.
+                                2) On entry, no drivers are managing ControllerHandle.
+                                3) DriverImageHandle is not NULL, and on entry
+                                   DriverImageHandle is not managing ControllerHandle.
+  @retval EFI_INVALID_PARAMETER 1) ControllerHandle is not a valid EFI_HANDLE.
+                                2) DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE.
+                                3) ChildHandle is not NULL, and it is not a valid EFI_HANDLE.
+                                4) DriverImageHandle does not support the EFI_DRIVER_BINDING_PROTOCOL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to disconnect any drivers from
+                                ControllerHandle.
+  @retval EFI_DEVICE_ERROR      The controller could not be disconnected because of a device error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISCONNECT_CONTROLLER)(
+  IN  EFI_HANDLE                     ControllerHandle,
+  IN  EFI_HANDLE                     DriverImageHandle, OPTIONAL
+  IN  EFI_HANDLE                     ChildHandle        OPTIONAL
+  );
+
+
+
+//
+// ConvertPointer DebugDisposition type.
+//
+#define EFI_OPTIONAL_PTR     0x00000001
+
+/**
+  Determines the new virtual address that is to be used on subsequent memory accesses.
+
+  @param  DebugDisposition      Supplies type information for the pointer being converted.
+  @param  Address               A pointer to a pointer that is to be fixed to be the value needed
+                                for the new virtual address mappings being applied.
+
+  @retval EFI_SUCCESS           The pointer pointed to by Address was modified.
+  @retval EFI_INVALID_PARAMETER 1) Address is NULL.
+                                2) *Address is NULL and DebugDisposition does
+                                not have the EFI_OPTIONAL_PTR bit set.
+  @retval EFI_NOT_FOUND         The pointer pointed to by Address was not found to be part
+                                of the current memory map. This is normally fatal.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONVERT_POINTER)(
+  IN     UINTN                      DebugDisposition,
+  IN OUT VOID                       **Address
+  );
+
+
+//
+// These types can be ORed together as needed - for example,
+// EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or
+// EVT_NOTIFY_SIGNAL.
+//
+#define EVT_TIMER                         0x80000000
+#define EVT_RUNTIME                       0x40000000
+#define EVT_NOTIFY_WAIT                   0x00000100
+#define EVT_NOTIFY_SIGNAL                 0x00000200
+
+#define EVT_SIGNAL_EXIT_BOOT_SERVICES     0x00000201
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+//
+// The event's NotifyContext pointer points to a runtime memory
+// address.
+// The event is deprecated in UEFI2.0 and later specifications.
+//
+#define EVT_RUNTIME_CONTEXT               0x20000000
+
+
+/**
+  Invoke a notification event
+
+  @param  Event                 Event whose notification function is being invoked.
+  @param  Context               The pointer to the notification function's context,
+                                which is implementation-dependent.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_EVENT_NOTIFY)(
+  IN  EFI_EVENT                Event,
+  IN  VOID                     *Context
+  );
+
+/**
+  Creates an event.
+
+  @param  Type                  The type of event to create and its mode and attributes.
+  @param  NotifyTpl             The task priority level of event notifications, if needed.
+  @param  NotifyFunction        The pointer to the event's notification function, if any.
+  @param  NotifyContext         The pointer to the notification function's context; corresponds to parameter
+                                Context in the notification function.
+  @param  Event                 The pointer to the newly created event if the call succeeds; undefined
+                                otherwise.
+
+  @retval EFI_SUCCESS           The event structure was created.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT)(
+  IN  UINT32                       Type,
+  IN  EFI_TPL                      NotifyTpl,
+  IN  EFI_EVENT_NOTIFY             NotifyFunction,
+  IN  VOID                         *NotifyContext,
+  OUT EFI_EVENT                    *Event
+  );
+
+/**
+  Creates an event in a group.
+
+  @param  Type                  The type of event to create and its mode and attributes.
+  @param  NotifyTpl             The task priority level of event notifications,if needed.
+  @param  NotifyFunction        The pointer to the event's notification function, if any.
+  @param  NotifyContext         The pointer to the notification function's context; corresponds to parameter
+                                Context in the notification function.
+  @param  EventGroup            The pointer to the unique identifier of the group to which this event belongs.
+                                If this is NULL, then the function behaves as if the parameters were passed
+                                to CreateEvent.
+  @param  Event                 The pointer to the newly created event if the call succeeds; undefined
+                                otherwise.
+
+  @retval EFI_SUCCESS           The event structure was created.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT_EX)(
+  IN       UINT32                 Type,
+  IN       EFI_TPL                NotifyTpl,
+  IN       EFI_EVENT_NOTIFY       NotifyFunction OPTIONAL,
+  IN CONST VOID                   *NotifyContext OPTIONAL,
+  IN CONST EFI_GUID               *EventGroup    OPTIONAL,
+  OUT      EFI_EVENT              *Event
+  );
+
+///
+/// Timer delay types
+///
+typedef enum {
+  ///
+  /// An event's timer settings is to be cancelled and not trigger time is to be set/
+  ///
+  TimerCancel,
+  ///
+  /// An event is to be signalled periodically at a specified interval from the current time.
+  ///
+  TimerPeriodic,
+  ///
+  /// An event is to be signalled once at a specified interval from the current time.
+  ///
+  TimerRelative
+} EFI_TIMER_DELAY;
+
+/**
+  Sets the type of timer and the trigger time for a timer event.
+
+  @param  Event                 The timer event that is to be signaled at the specified time.
+  @param  Type                  The type of time that is specified in TriggerTime.
+  @param  TriggerTime           The number of 100ns units until the timer expires.
+                                A TriggerTime of 0 is legal.
+                                If Type is TimerRelative and TriggerTime is 0, then the timer
+                                event will be signaled on the next timer tick.
+                                If Type is TimerPeriodic and TriggerTime is 0, then the timer
+                                event will be signaled on every timer tick.
+
+  @retval EFI_SUCCESS           The event has been set to be signaled at the requested time.
+  @retval EFI_INVALID_PARAMETER Event or Type is not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIMER)(
+  IN  EFI_EVENT                Event,
+  IN  EFI_TIMER_DELAY          Type,
+  IN  UINT64                   TriggerTime
+  );
+
+/**
+  Signals an event.
+
+  @param  Event                 The event to signal.
+
+  @retval EFI_SUCCESS           The event has been signaled.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIGNAL_EVENT)(
+  IN  EFI_EVENT                Event
+  );
+
+/**
+  Stops execution until an event is signaled.
+
+  @param  NumberOfEvents        The number of events in the Event array.
+  @param  Event                 An array of EFI_EVENT.
+  @param  Index                 The pointer to the index of the event which satisfied the wait condition.
+
+  @retval EFI_SUCCESS           The event indicated by Index was signaled.
+  @retval EFI_INVALID_PARAMETER 1) NumberOfEvents is 0.
+                                2) The event indicated by Index is of type
+                                   EVT_NOTIFY_SIGNAL.
+  @retval EFI_UNSUPPORTED       The current TPL is not TPL_APPLICATION.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_WAIT_FOR_EVENT)(
+  IN  UINTN                    NumberOfEvents,
+  IN  EFI_EVENT                *Event,
+  OUT UINTN                    *Index
+  );
+
+/**
+  Closes an event.
+
+  @param  Event                 The event to close.
+
+  @retval EFI_SUCCESS           The event has been closed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_EVENT)(
+  IN EFI_EVENT                Event
+  );
+
+/**
+  Checks whether an event is in the signaled state.
+
+  @param  Event                 The event to check.
+
+  @retval EFI_SUCCESS           The event is in the signaled state.
+  @retval EFI_NOT_READY         The event is not in the signaled state.
+  @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CHECK_EVENT)(
+  IN EFI_EVENT                Event
+  );
+
+
+//
+// Task priority level
+//
+#define TPL_APPLICATION       4
+#define TPL_CALLBACK          8
+#define TPL_NOTIFY            16
+#define TPL_HIGH_LEVEL        31
+
+
+/**
+  Raises a task's priority level and returns its previous level.
+
+  @param  NewTpl                The new task priority level.
+
+  @return Previous task priority level
+
+**/
+typedef
+EFI_TPL
+(EFIAPI *EFI_RAISE_TPL)(
+  IN EFI_TPL      NewTpl
+  );
+
+/**
+  Restores a task's priority level to its previous value.
+
+  @param  OldTpl                The previous task priority level to restore.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESTORE_TPL)(
+  IN EFI_TPL      OldTpl
+  );
+
+/**
+  Returns the value of a variable.
+
+  @param  VariableName          A Null-terminated string that is the name of the vendor's
+                                variable.
+  @param  VendorGuid            A unique identifier for the vendor.
+  @param  Attributes            If not NULL, a pointer to the memory location to return the
+                                attributes bitmask for the variable.
+  @param  DataSize              On input, the size in bytes of the return Data buffer.
+                                On output the size of data returned in Data.
+  @param  Data                  The buffer to return the contents of the variable.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_VARIABLE)(
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  OUT    UINT32                      *Attributes,    OPTIONAL
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data
+  );
+
+/**
+  Enumerates the current variable names.
+
+  @param  VariableNameSize      The size of the VariableName buffer.
+  @param  VariableName          On input, supplies the last VariableName that was returned
+                                by GetNextVariableName(). On output, returns the Nullterminated
+                                string of the current variable.
+  @param  VendorGuid            On input, supplies the last VendorGuid that was returned by
+                                GetNextVariableName(). On output, returns the
+                                VendorGuid of the current variable.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+  @retval EFI_NOT_FOUND         The next variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+  @retval EFI_INVALID_PARAMETER VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)(
+  IN OUT UINTN                    *VariableNameSize,
+  IN OUT CHAR16                   *VariableName,
+  IN OUT EFI_GUID                 *VendorGuid
+  );
+
+/**
+  Sets the value of a variable.
+
+  @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param  VendorGuid             A unique identifier for the vendor.
+  @param  Attributes             Attributes bitmask to set for the variable.
+  @param  DataSize               The size in bytes of the Data buffer. A size of zero causes the
+                                 variable to be deleted.
+  @param  Data                   The contents for the variable.
+
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
+                                 defined by the Attributes.
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
+  @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+                                 set but the AuthInfo does NOT pass the validation check carried out
+                                 by the firmware.
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VARIABLE)(
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  );
+
+
+///
+/// This provides the capabilities of the
+/// real time clock device as exposed through the EFI interfaces.
+///
+typedef struct {
+  ///
+  /// Provides the reporting resolution of the real-time clock device in
+  /// counts per second. For a normal PC-AT CMOS RTC device, this
+  /// value would be 1 Hz, or 1, to indicate that the device only reports
+  /// the time to the resolution of 1 second.
+  ///
+  UINT32    Resolution;
+  ///
+  /// Provides the timekeeping accuracy of the real-time clock in an
+  /// error rate of 1E-6 parts per million. For a clock with an accuracy
+  /// of 50 parts per million, the value in this field would be
+  /// 50,000,000.
+  ///
+  UINT32    Accuracy;
+  ///
+  /// A TRUE indicates that a time set operation clears the device's
+  /// time below the Resolution reporting level. A FALSE
+  /// indicates that the state below the Resolution level of the
+  /// device is not cleared when the time is set. Normal PC-AT CMOS
+  /// RTC devices set this value to FALSE.
+  ///
+  BOOLEAN   SetsToZero;
+} EFI_TIME_CAPABILITIES;
+
+/**
+  Returns the current time and date information, and the time-keeping capabilities
+  of the hardware platform.
+
+  @param  Time                  A pointer to storage to receive a snapshot of the current time.
+  @param  Capabilities          An optional pointer to a buffer to receive the real time clock
+                                device's capabilities.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER Time is NULL.
+  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_TIME)(
+  OUT  EFI_TIME                    *Time,
+  OUT  EFI_TIME_CAPABILITIES       *Capabilities OPTIONAL
+  );
+
+/**
+  Sets the current local time and date information.
+
+  @param  Time                  A pointer to the current time.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIME)(
+  IN  EFI_TIME                     *Time
+  );
+
+/**
+  Returns the current wakeup alarm clock setting.
+
+  @param  Enabled               Indicates if the alarm is currently enabled or disabled.
+  @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
+  @param  Time                  The current alarm setting.
+
+  @retval EFI_SUCCESS           The alarm settings were returned.
+  @retval EFI_INVALID_PARAMETER Enabled is NULL.
+  @retval EFI_INVALID_PARAMETER Pending is NULL.
+  @retval EFI_INVALID_PARAMETER Time is NULL.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_WAKEUP_TIME)(
+  OUT BOOLEAN                     *Enabled,
+  OUT BOOLEAN                     *Pending,
+  OUT EFI_TIME                    *Time
+  );
+
+/**
+  Sets the system wakeup alarm clock time.
+
+  @param  Enabled               Enable or disable the wakeup alarm.
+  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
+                                If Enable is FALSE, then this parameter is optional, and may be NULL.
+
+  @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
+                                Enable is FALSE, then the wakeup alarm was disabled.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WAKEUP_TIME)(
+  IN  BOOLEAN                      Enable,
+  IN  EFI_TIME                     *Time   OPTIONAL
+  );
+
+/**
+  Loads an EFI image into memory.
+
+  @param  BootPolicy            If TRUE, indicates that the request originates from the boot
+                                manager, and that the boot manager is attempting to load
+                                FilePath as a boot selection. Ignored if SourceBuffer is
+                                not NULL.
+  @param  ParentImageHandle     The caller's image handle.
+  @param  DevicePath            The DeviceHandle specific file path from which the image is
+                                loaded.
+  @param  SourceBuffer          If not NULL, a pointer to the memory location containing a copy
+                                of the image to be loaded.
+  @param  SourceSize            The size in bytes of SourceBuffer. Ignored if SourceBuffer is NULL.
+  @param  ImageHandle           The pointer to the returned image handle that is created when the
+                                image is successfully loaded.
+
+  @retval EFI_SUCCESS           Image was loaded into memory correctly.
+  @retval EFI_NOT_FOUND         Both SourceBuffer and DevicePath are NULL.
+  @retval EFI_INVALID_PARAMETER One or more parametes are invalid.
+  @retval EFI_UNSUPPORTED       The image type is not supported.
+  @retval EFI_OUT_OF_RESOURCES  Image was not loaded due to insufficient resources.
+  @retval EFI_LOAD_ERROR        Image was not loaded because the image format was corrupt or not
+                                understood.
+  @retval EFI_DEVICE_ERROR      Image was not loaded because the device returned a read error.
+  @retval EFI_ACCESS_DENIED     Image was not loaded because the platform policy prohibits the
+                                image from being loaded. NULL is returned in *ImageHandle.
+  @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+                                valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+                                platform policy specifies that the image should not be started.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_LOAD)(
+  IN  BOOLEAN                      BootPolicy,
+  IN  EFI_HANDLE                   ParentImageHandle,
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath,
+  IN  VOID                         *SourceBuffer OPTIONAL,
+  IN  UINTN                        SourceSize,
+  OUT EFI_HANDLE                   *ImageHandle
+  );
+
+/**
+  Transfers control to a loaded image's entry point.
+
+  @param  ImageHandle           Handle of image to be started.
+  @param  ExitDataSize          The pointer to the size, in bytes, of ExitData.
+  @param  ExitData              The pointer to a pointer to a data buffer that includes a Null-terminated
+                                string, optionally followed by additional binary data.
+
+  @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image
+                                has already been initialized with StartImage.
+  @return Exit code from image
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_START)(
+  IN  EFI_HANDLE                  ImageHandle,
+  OUT UINTN                       *ExitDataSize,
+  OUT CHAR16                      **ExitData    OPTIONAL
+  );
+
+/**
+  Terminates a loaded EFI image and returns control to boot services.
+
+  @param  ImageHandle           Handle that identifies the image. This parameter is passed to the
+                                image on entry.
+  @param  ExitStatus            The image's exit code.
+  @param  ExitDataSize          The size, in bytes, of ExitData. Ignored if ExitStatus is EFI_SUCCESS.
+  @param  ExitData              The pointer to a data buffer that includes a Null-terminated string,
+                                optionally followed by additional binary data. The string is a
+                                description that the caller may use to further indicate the reason
+                                for the image's exit. ExitData is only valid if ExitStatus
+                                is something other than EFI_SUCCESS. The ExitData buffer
+                                must be allocated by calling AllocatePool().
+
+  @retval EFI_SUCCESS           The image specified by ImageHandle was unloaded.
+  @retval EFI_INVALID_PARAMETER The image specified by ImageHandle has been loaded and
+                                started with LoadImage() and StartImage(), but the
+                                image is not the currently executing image.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT)(
+  IN  EFI_HANDLE                   ImageHandle,
+  IN  EFI_STATUS                   ExitStatus,
+  IN  UINTN                        ExitDataSize,
+  IN  CHAR16                       *ExitData     OPTIONAL
+  );
+
+/**
+  Unloads an image.
+
+  @param  ImageHandle           Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS           The image has been unloaded.
+  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_UNLOAD)(
+  IN  EFI_HANDLE                   ImageHandle
+  );
+
+/**
+  Terminates all boot services.
+
+  @param  ImageHandle           Handle that identifies the exiting image.
+  @param  MapKey                Key to the latest memory map.
+
+  @retval EFI_SUCCESS           Boot services have been terminated.
+  @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT_BOOT_SERVICES)(
+  IN  EFI_HANDLE                   ImageHandle,
+  IN  UINTN                        MapKey
+  );
+
+/**
+  Induces a fine-grained stall.
+
+  @param  Microseconds          The number of microseconds to stall execution.
+
+  @retval EFI_SUCCESS           Execution was stalled at least the requested number of
+                                Microseconds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_STALL)(
+  IN  UINTN                    Microseconds
+  );
+
+/**
+  Sets the system's watchdog timer.
+
+  @param  Timeout               The number of seconds to set the watchdog timer to.
+  @param  WatchdogCode          The numeric code to log on a watchdog timer timeout event.
+  @param  DataSize              The size, in bytes, of WatchdogData.
+  @param  WatchdogData          A data buffer that includes a Null-terminated string, optionally
+                                followed by additional binary data.
+
+  @retval EFI_SUCCESS           The timeout has been set.
+  @retval EFI_INVALID_PARAMETER The supplied WatchdogCode is invalid.
+  @retval EFI_UNSUPPORTED       The system does not have a watchdog timer.
+  @retval EFI_DEVICE_ERROR      The watchdog timer could not be programmed due to a hardware
+                                error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WATCHDOG_TIMER)(
+  IN UINTN                    Timeout,
+  IN UINT64                   WatchdogCode,
+  IN UINTN                    DataSize,
+  IN CHAR16                   *WatchdogData OPTIONAL
+  );
+
+///
+/// Enumeration of reset types.
+///
+typedef enum {
+  ///
+  /// Used to induce a system-wide reset. This sets all circuitry within the
+  /// system to its initial state.  This type of reset is asynchronous to system
+  /// operation and operates withgout regard to cycle boundaries.  EfiColdReset
+  /// is tantamount to a system power cycle.
+  ///
+  EfiResetCold,
+  ///
+  /// Used to induce a system-wide initialization. The processors are set to their
+  /// initial state, and pending cycles are not corrupted.  If the system does
+  /// not support this reset type, then an EfiResetCold must be performed.
+  ///
+  EfiResetWarm,
+  ///
+  /// Used to induce an entry into a power state equivalent to the ACPI G2/S5 or G3
+  /// state.  If the system does not support this reset type, then when the system
+  /// is rebooted, it should exhibit the EfiResetCold attributes.
+  ///
+  EfiResetShutdown
+} EFI_RESET_TYPE;
+
+/**
+  Resets the entire platform.
+
+  @param  ResetType             The type of reset to perform.
+  @param  ResetStatus           The status code for the reset.
+  @param  DataSize              The size, in bytes, of WatchdogData.
+  @param  ResetData             For a ResetType of EfiResetCold, EfiResetWarm, or
+                                EfiResetShutdown the data buffer starts with a Null-terminated
+                                string, optionally followed by additional binary data.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESET_SYSTEM)(
+  IN EFI_RESET_TYPE           ResetType,
+  IN EFI_STATUS               ResetStatus,
+  IN UINTN                    DataSize,
+  IN VOID                     *ResetData OPTIONAL
+  );
+
+/**
+  Returns a monotonically increasing count for the platform.
+
+  @param  Count                 The pointer to returned value.
+
+  @retval EFI_SUCCESS           The next monotonic count was returned.
+  @retval EFI_INVALID_PARAMETER Count is NULL.
+  @retval EFI_DEVICE_ERROR      The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)(
+  OUT UINT64                  *Count
+  );
+
+/**
+  Returns the next high 32 bits of the platform's monotonic counter.
+
+  @param  HighCount             The pointer to returned value.
+
+  @retval EFI_SUCCESS           The next high monotonic count was returned.
+  @retval EFI_INVALID_PARAMETER HighCount is NULL.
+  @retval EFI_DEVICE_ERROR      The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)(
+  OUT UINT32                  *HighCount
+  );
+
+/**
+  Computes and returns a 32-bit CRC for a data buffer.
+
+  @param  Data                  A pointer to the buffer on which the 32-bit CRC is to be computed.
+  @param  DataSize              The number of bytes in the buffer Data.
+  @param  Crc32                 The 32-bit CRC that was computed for the data buffer specified by Data
+                                and DataSize.
+
+  @retval EFI_SUCCESS           The 32-bit CRC was computed for the data buffer and returned in
+                                Crc32.
+  @retval EFI_INVALID_PARAMETER Data is NULL.
+  @retval EFI_INVALID_PARAMETER Crc32 is NULL.
+  @retval EFI_INVALID_PARAMETER DataSize is 0.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CALCULATE_CRC32)(
+  IN  VOID                              *Data,
+  IN  UINTN                             DataSize,
+  OUT UINT32                            *Crc32
+  );
+
+/**
+  Copies the contents of one buffer to another buffer.
+
+  @param  Destination           The pointer to the destination buffer of the memory copy.
+  @param  Source                The pointer to the source buffer of the memory copy.
+  @param  Length                Number of bytes to copy from Source to Destination.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_COPY_MEM)(
+  IN VOID     *Destination,
+  IN VOID     *Source,
+  IN UINTN    Length
+  );
+
+/**
+  The SetMem() function fills a buffer with a specified value.
+
+  @param  Buffer                The pointer to the buffer to fill.
+  @param  Size                  Number of bytes in Buffer to fill.
+  @param  Value                 Value to fill Buffer with.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_SET_MEM)(
+  IN VOID     *Buffer,
+  IN UINTN    Size,
+  IN UINT8    Value
+  );
+
+///
+/// Enumeration of EFI Interface Types
+///
+typedef enum {
+  ///
+  /// Indicates that the supplied protocol interface is supplied in native form.
+  ///
+  EFI_NATIVE_INTERFACE
+} EFI_INTERFACE_TYPE;
+
+/**
+  Installs a protocol interface on a device handle. If the handle does not exist, it is created and added
+  to the list of handles in the system. InstallMultipleProtocolInterfaces() performs
+  more error checking than InstallProtocolInterface(), so it is recommended that
+  InstallMultipleProtocolInterfaces() be used in place of
+  InstallProtocolInterface()
+
+  @param  Handle                A pointer to the EFI_HANDLE on which the interface is to be installed.
+  @param  Protocol              The numeric ID of the protocol interface.
+  @param  InterfaceType         Indicates whether Interface is supplied in native form.
+  @param  Interface             A pointer to the protocol interface.
+
+  @retval EFI_SUCCESS           The protocol interface was installed.
+  @retval EFI_OUT_OF_RESOURCES  Space for a new handle could not be allocated.
+  @retval EFI_INVALID_PARAMETER Handle is NULL.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+  @retval EFI_INVALID_PARAMETER InterfaceType is not EFI_NATIVE_INTERFACE.
+  @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)(
+  IN OUT EFI_HANDLE               *Handle,
+  IN     EFI_GUID                 *Protocol,
+  IN     EFI_INTERFACE_TYPE       InterfaceType,
+  IN     VOID                     *Interface
+  );
+
+/**
+  Installs one or more protocol interfaces into the boot services environment.
+
+  @param  Handle                The handle to install the new protocol interfaces on, or NULL if a new
+                                handle is to be allocated.
+  @param  ...                   A variable argument list containing pairs of protocol GUIDs and protocol
+                                interfaces.
+
+  @retval EFI_SUCCESS           All the protocol interface was installed.
+  @retval EFI_OUT_OF_RESOURCES  There was not enough memory in pool to install all the protocols.
+  @retval EFI_ALREADY_STARTED   A Device Path Protocol instance was passed in that is already present in
+                                the handle database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+  IN OUT EFI_HANDLE           *Handle,
+  ...
+  );
+
+/**
+  Reinstalls a protocol interface on a device handle.
+
+  @param  Handle                Handle on which the interface is to be reinstalled.
+  @param  Protocol              The numeric ID of the interface.
+  @param  OldInterface          A pointer to the old interface. NULL can be used if a structure is not
+                                associated with Protocol.
+  @param  NewInterface          A pointer to the new interface.
+
+  @retval EFI_SUCCESS           The protocol interface was reinstalled.
+  @retval EFI_NOT_FOUND         The OldInterface on the handle was not found.
+  @retval EFI_ACCESS_DENIED     The protocol interface could not be reinstalled,
+                                because OldInterface is still being used by a
+                                driver that will not release it.
+  @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE)(
+  IN EFI_HANDLE               Handle,
+  IN EFI_GUID                 *Protocol,
+  IN VOID                     *OldInterface,
+  IN VOID                     *NewInterface
+  );
+
+/**
+  Removes a protocol interface from a device handle. It is recommended that
+  UninstallMultipleProtocolInterfaces() be used in place of
+  UninstallProtocolInterface().
+
+  @param  Handle                The handle on which the interface was installed.
+  @param  Protocol              The numeric ID of the interface.
+  @param  Interface             A pointer to the interface.
+
+  @retval EFI_SUCCESS           The interface was removed.
+  @retval EFI_NOT_FOUND         The interface was not found.
+  @retval EFI_ACCESS_DENIED     The interface was not removed because the interface
+                                is still being used by a driver.
+  @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE)(
+  IN EFI_HANDLE               Handle,
+  IN EFI_GUID                 *Protocol,
+  IN VOID                     *Interface
+  );
+
+/**
+  Removes one or more protocol interfaces into the boot services environment.
+
+  @param  Handle                The handle to remove the protocol interfaces from.
+  @param  ...                   A variable argument list containing pairs of protocol GUIDs and
+                                protocol interfaces.
+
+  @retval EFI_SUCCESS           All the protocol interfaces were removed.
+  @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+  IN EFI_HANDLE           Handle,
+  ...
+  );
+
+/**
+  Queries a handle to determine if it supports a specified protocol.
+
+  @param  Handle                The handle being queried.
+  @param  Protocol              The published unique identifier of the protocol.
+  @param  Interface             Supplies the address where a pointer to the corresponding Protocol
+                                Interface is returned.
+
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
+  @retval EFI_UNSUPPORTED       The device does not support the specified protocol.
+  @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+  @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HANDLE_PROTOCOL)(
+  IN  EFI_HANDLE               Handle,
+  IN  EFI_GUID                 *Protocol,
+  OUT VOID                     **Interface
+  );
+
+#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL  0x00000001
+#define EFI_OPEN_PROTOCOL_GET_PROTOCOL        0x00000002
+#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL       0x00000004
+#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
+#define EFI_OPEN_PROTOCOL_BY_DRIVER           0x00000010
+#define EFI_OPEN_PROTOCOL_EXCLUSIVE           0x00000020
+
+/**
+  Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
+  handle, it opens the protocol on behalf of the calling agent.
+
+  @param  Handle                The handle for the protocol interface that is being opened.
+  @param  Protocol              The published unique identifier of the protocol.
+  @param  Interface             Supplies the address where a pointer to the corresponding Protocol
+                                Interface is returned.
+  @param  AgentHandle           The handle of the agent that is opening the protocol interface
+                                specified by Protocol and Interface.
+  @param  ControllerHandle      If the agent that is opening a protocol is a driver that follows the
+                                UEFI Driver Model, then this parameter is the controller handle
+                                that requires the protocol interface. If the agent does not follow
+                                the UEFI Driver Model, then this parameter is optional and may
+                                be NULL.
+  @param  Attributes            The open mode of the protocol interface specified by Handle
+                                and Protocol.
+
+  @retval EFI_SUCCESS           An item was added to the open list for the protocol interface, and the
+                                protocol interface was returned in Interface.
+  @retval EFI_UNSUPPORTED       Handle does not support Protocol.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_ACCESS_DENIED     Required attributes can't be supported in current environment.
+  @retval EFI_ALREADY_STARTED   Item on the open list already has requierd attributes whose agent
+                                handle is the same as AgentHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL)(
+  IN  EFI_HANDLE                Handle,
+  IN  EFI_GUID                  *Protocol,
+  OUT VOID                      **Interface, OPTIONAL
+  IN  EFI_HANDLE                AgentHandle,
+  IN  EFI_HANDLE                ControllerHandle,
+  IN  UINT32                    Attributes
+  );
+
+
+/**
+  Closes a protocol on a handle that was opened using OpenProtocol().
+
+  @param  Handle                The handle for the protocol interface that was previously opened
+                                with OpenProtocol(), and is now being closed.
+  @param  Protocol              The published unique identifier of the protocol.
+  @param  AgentHandle           The handle of the agent that is closing the protocol interface.
+  @param  ControllerHandle      If the agent that opened a protocol is a driver that follows the
+                                UEFI Driver Model, then this parameter is the controller handle
+                                that required the protocol interface.
+
+  @retval EFI_SUCCESS           The protocol instance was closed.
+  @retval EFI_INVALID_PARAMETER 1) Handle is not a valid EFI_HANDLE.
+                                2) AgentHandle is not a valid EFI_HANDLE.
+                                3) ControllerHandle is not NULL and ControllerHandle is not a valid EFI_HANDLE.
+                                4) Protocol is NULL.
+  @retval EFI_NOT_FOUND         1) Handle does not support the protocol specified by Protocol.
+                                2) The protocol interface specified by Handle and Protocol is not
+                                   currently open by AgentHandle and ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_PROTOCOL)(
+  IN EFI_HANDLE               Handle,
+  IN EFI_GUID                 *Protocol,
+  IN EFI_HANDLE               AgentHandle,
+  IN EFI_HANDLE               ControllerHandle
+  );
+
+///
+/// EFI Oprn Protocol Information Entry
+///
+typedef struct {
+  EFI_HANDLE  AgentHandle;
+  EFI_HANDLE  ControllerHandle;
+  UINT32      Attributes;
+  UINT32      OpenCount;
+} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY;
+
+/**
+  Retrieves the list of agents that currently have a protocol interface opened.
+
+  @param  Handle                The handle for the protocol interface that is being queried.
+  @param  Protocol              The published unique identifier of the protocol.
+  @param  EntryBuffer           A pointer to a buffer of open protocol information in the form of
+                                EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+  @param  EntryCount            A pointer to the number of entries in EntryBuffer.
+
+  @retval EFI_SUCCESS           The open protocol information was returned in EntryBuffer, and the
+                                number of entries was returned EntryCount.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate EntryBuffer.
+  @retval EFI_NOT_FOUND         Handle does not support the protocol specified by Protocol.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION)(
+  IN  EFI_HANDLE                          Handle,
+  IN  EFI_GUID                            *Protocol,
+  OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+  OUT UINTN                               *EntryCount
+  );
+
+/**
+  Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+  from pool.
+
+  @param  Handle                The handle from which to retrieve the list of protocol interface
+                                GUIDs.
+  @param  ProtocolBuffer        A pointer to the list of protocol interface GUID pointers that are
+                                installed on Handle.
+  @param  ProtocolBufferCount   A pointer to the number of GUID pointers present in
+                                ProtocolBuffer.
+
+  @retval EFI_SUCCESS           The list of protocol interface GUIDs installed on Handle was returned in
+                                ProtocolBuffer. The number of protocol interface GUIDs was
+                                returned in ProtocolBufferCount.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the results.
+  @retval EFI_INVALID_PARAMETER Handle is NULL.
+  @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+  @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROTOCOLS_PER_HANDLE)(
+  IN  EFI_HANDLE      Handle,
+  OUT EFI_GUID        ***ProtocolBuffer,
+  OUT UINTN           *ProtocolBufferCount
+  );
+
+/**
+  Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
+
+  @param  Protocol              The numeric ID of the protocol for which the event is to be registered.
+  @param  Event                 Event that is to be signaled whenever a protocol interface is registered
+                                for Protocol.
+  @param  Registration          A pointer to a memory location to receive the registration value.
+
+  @retval EFI_SUCCESS           The notification event has been registered.
+  @retval EFI_OUT_OF_RESOURCES  Space for the notification event could not be allocated.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+  @retval EFI_INVALID_PARAMETER Event is NULL.
+  @retval EFI_INVALID_PARAMETER Registration is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY)(
+  IN  EFI_GUID                 *Protocol,
+  IN  EFI_EVENT                Event,
+  OUT VOID                     **Registration
+  );
+
+///
+/// Enumeration of EFI Locate Search Types
+///
+typedef enum {
+  ///
+  /// Retrieve all the handles in the handle database.
+  ///
+  AllHandles,
+  ///
+  /// Retrieve the next handle fron a RegisterProtocolNotify() event.
+  ///
+  ByRegisterNotify,
+  ///
+  /// Retrieve the set of handles from the handle database that support a
+  /// specified protocol.
+  ///
+  ByProtocol
+} EFI_LOCATE_SEARCH_TYPE;
+
+/**
+  Returns an array of handles that support a specified protocol.
+
+  @param  SearchType            Specifies which handle(s) are to be returned.
+  @param  Protocol              Specifies the protocol to search by.
+  @param  SearchKey             Specifies the search key.
+  @param  BufferSize            On input, the size in bytes of Buffer. On output, the size in bytes of
+                                the array returned in Buffer (if the buffer was large enough) or the
+                                size, in bytes, of the buffer needed to obtain the array (if the buffer was
+                                not large enough).
+  @param  Buffer                The buffer in which the array is returned.
+
+  @retval EFI_SUCCESS           The array of handles was returned.
+  @retval EFI_NOT_FOUND         No handles match the search.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER SearchType is not a member of EFI_LOCATE_SEARCH_TYPE.
+  @retval EFI_INVALID_PARAMETER SearchType is ByRegisterNotify and SearchKey is NULL.
+  @retval EFI_INVALID_PARAMETER SearchType is ByProtocol and Protocol is NULL.
+  @retval EFI_INVALID_PARAMETER One or more matches are found and BufferSize is NULL.
+  @retval EFI_INVALID_PARAMETER BufferSize is large enough for the result and Buffer is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE)(
+  IN     EFI_LOCATE_SEARCH_TYPE   SearchType,
+  IN     EFI_GUID                 *Protocol,    OPTIONAL
+  IN     VOID                     *SearchKey,   OPTIONAL
+  IN OUT UINTN                    *BufferSize,
+  OUT    EFI_HANDLE               *Buffer
+  );
+
+/**
+  Locates the handle to a device on the device path that supports the specified protocol.
+
+  @param  Protocol              Specifies the protocol to search for.
+  @param  DevicePath            On input, a pointer to a pointer to the device path. On output, the device
+                                path pointer is modified to point to the remaining part of the device
+                                path.
+  @param  Device                A pointer to the returned device handle.
+
+  @retval EFI_SUCCESS           The resulting handle was returned.
+  @retval EFI_NOT_FOUND         No handles match the search.
+  @retval EFI_INVALID_PARAMETER Protocol is NULL.
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+  @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_DEVICE_PATH)(
+  IN     EFI_GUID                         *Protocol,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL         **DevicePath,
+  OUT    EFI_HANDLE                       *Device
+  );
+
+/**
+  Adds, updates, or removes a configuration table entry from the EFI System Table.
+
+  @param  Guid                  A pointer to the GUID for the entry to add, update, or remove.
+  @param  Table                 A pointer to the configuration table for the entry to add, update, or
+                                remove. May be NULL.
+
+  @retval EFI_SUCCESS           The (Guid, Table) pair was added, updated, or removed.
+  @retval EFI_NOT_FOUND         An attempt was made to delete a nonexistent entry.
+  @retval EFI_INVALID_PARAMETER Guid is not valid.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough memory available to complete the operation.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)(
+  IN EFI_GUID                 *Guid,
+  IN VOID                     *Table
+  );
+
+/**
+  Returns an array of handles that support the requested protocol in a buffer allocated from pool.
+
+  @param  SearchType            Specifies which handle(s) are to be returned.
+  @param  Protocol              Provides the protocol to search by.
+                                This parameter is only valid for a SearchType of ByProtocol.
+  @param  SearchKey             Supplies the search key depending on the SearchType.
+  @param  NoHandles             The number of handles returned in Buffer.
+  @param  Buffer                A pointer to the buffer to return the requested array of handles that
+                                support Protocol.
+
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of
+                                handles in Buffer was returned in NoHandles.
+  @retval EFI_NOT_FOUND         No handles match the search.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.
+  @retval EFI_INVALID_PARAMETER NoHandles is NULL.
+  @retval EFI_INVALID_PARAMETER Buffer is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE_BUFFER)(
+  IN     EFI_LOCATE_SEARCH_TYPE       SearchType,
+  IN     EFI_GUID                     *Protocol,      OPTIONAL
+  IN     VOID                         *SearchKey,     OPTIONAL
+  IN OUT UINTN                        *NoHandles,
+  OUT    EFI_HANDLE                   **Buffer
+  );
+
+/**
+  Returns the first protocol instance that matches the given protocol.
+
+  @param  Protocol              Provides the protocol to search for.
+  @param  Registration          Optional registration key returned from
+                                RegisterProtocolNotify().
+  @param  Interface             On return, a pointer to the first interface that matches Protocol and
+                                Registration.
+
+  @retval EFI_SUCCESS           A protocol instance matching Protocol was found and returned in
+                                Interface.
+  @retval EFI_NOT_FOUND         No protocol instances were found that match Protocol and
+                                Registration.
+  @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_PROTOCOL)(
+  IN  EFI_GUID  *Protocol,
+  IN  VOID      *Registration, OPTIONAL
+  OUT VOID      **Interface
+  );
+
+///
+/// EFI Capsule Block Descriptor
+///
+typedef struct {
+  ///
+  /// Length in bytes of the data pointed to by DataBlock/ContinuationPointer.
+  ///
+  UINT64                  Length;
+  union {
+    ///
+    /// Physical address of the data block. This member of the union is
+    /// used if Length is not equal to zero.
+    ///
+    EFI_PHYSICAL_ADDRESS  DataBlock;
+    ///
+    /// Physical address of another block of
+    /// EFI_CAPSULE_BLOCK_DESCRIPTOR structures. This
+    /// member of the union is used if Length is equal to zero. If
+    /// ContinuationPointer is zero this entry represents the end of the list.
+    ///
+    EFI_PHYSICAL_ADDRESS  ContinuationPointer;
+  } Union;
+} EFI_CAPSULE_BLOCK_DESCRIPTOR;
+
+///
+/// EFI Capsule Header.
+///
+typedef struct {
+  ///
+  /// A GUID that defines the contents of a capsule.
+  ///
+  EFI_GUID          CapsuleGuid;
+  ///
+  /// The size of the capsule header. This may be larger than the size of
+  /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply
+  /// extended header entries
+  ///
+  UINT32            HeaderSize;
+  ///
+  /// Bit-mapped list describing the capsule attributes. The Flag values
+  /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values
+  /// of 0x10000 - 0xFFFFFFFF are defined by this specification
+  ///
+  UINT32            Flags;
+  ///
+  /// Size in bytes of the capsule.
+  ///
+  UINT32            CapsuleImageSize;
+} EFI_CAPSULE_HEADER;
+
+///
+/// The EFI System Table entry must point to an array of capsules
+/// that contain the same CapsuleGuid value. The array must be
+/// prefixed by a UINT32 that represents the size of the array of capsules.
+///
+typedef struct {
+  ///
+  /// the size of the array of capsules.
+  ///
+  UINT32   CapsuleArrayNumber;
+  ///
+  /// Point to an array of capsules that contain the same CapsuleGuid value.
+  ///
+  VOID*    CapsulePtr[1];
+} EFI_CAPSULE_TABLE;
+
+#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET          0x00010000
+#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE         0x00020000
+#define CAPSULE_FLAGS_INITIATE_RESET                0x00040000
+
+/**
+  Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
+  consumption, the firmware may process the capsule immediately. If the payload should persist
+  across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
+  be passed into ResetSystem() and will cause the capsule to be processed by the firmware as
+  part of the reset process.
+
+  @param  CapsuleHeaderArray    Virtual pointer to an array of virtual pointers to the capsules
+                                being passed into update capsule.
+  @param  CapsuleCount          Number of pointers to EFI_CAPSULE_HEADER in
+                                CaspuleHeaderArray.
+  @param  ScatterGatherList     Physical pointer to a set of
+                                EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the
+                                location in physical memory of a set of capsules.
+
+  @retval EFI_SUCCESS           Valid capsule was passed. If
+                                CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the
+                                capsule has been successfully processed by the firmware.
+  @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were
+                                set in the capsule header.
+  @retval EFI_INVALID_PARAMETER CapsuleCount is 0.
+  @retval EFI_DEVICE_ERROR      The capsule update was started, but failed due to a device error.
+  @retval EFI_UNSUPPORTED       The capsule type is not supported on this platform.
+  @retval EFI_OUT_OF_RESOURCES  There were insufficient resources to process the capsule.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UPDATE_CAPSULE)(
+  IN EFI_CAPSULE_HEADER     **CapsuleHeaderArray,
+  IN UINTN                  CapsuleCount,
+  IN EFI_PHYSICAL_ADDRESS   ScatterGatherList   OPTIONAL
+  );
+
+/**
+  Returns if the capsule can be supported via UpdateCapsule().
+
+  @param  CapsuleHeaderArray    Virtual pointer to an array of virtual pointers to the capsules
+                                being passed into update capsule.
+  @param  CapsuleCount          Number of pointers to EFI_CAPSULE_HEADER in
+                                CaspuleHeaderArray.
+  @param  MaxiumCapsuleSize     On output the maximum size that UpdateCapsule() can
+                                support as an argument to UpdateCapsule() via
+                                CapsuleHeaderArray and ScatterGatherList.
+  @param  ResetType             Returns the type of reset required for the capsule update.
+
+  @retval EFI_SUCCESS           Valid answer returned.
+  @retval EFI_UNSUPPORTED       The capsule type is not supported on this platform, and
+                                MaximumCapsuleSize and ResetType are undefined.
+  @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There were insufficient resources to process the query request.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)(
+  IN  EFI_CAPSULE_HEADER     **CapsuleHeaderArray,
+  IN  UINTN                  CapsuleCount,
+  OUT UINT64                 *MaximumCapsuleSize,
+  OUT EFI_RESET_TYPE         *ResetType
+  );
+
+/**
+  Returns information about the EFI variables.
+
+  @param  Attributes                   Attributes bitmask to specify the type of variables on
+                                       which to return information.
+  @param  MaximumVariableStorageSize   On output the maximum size of the storage space
+                                       available for the EFI variables associated with the
+                                       attributes specified.
+  @param  RemainingVariableStorageSize Returns the remaining size of the storage space
+                                       available for the EFI variables associated with the
+                                       attributes specified.
+  @param  MaximumVariableSize          Returns the maximum size of the individual EFI
+                                       variables associated with the attributes specified.
+
+  @retval EFI_SUCCESS                  Valid answer returned.
+  @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied
+  @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the
+                                       MaximumVariableStorageSize,
+                                       RemainingVariableStorageSize, MaximumVariableSize
+                                       are undefined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_VARIABLE_INFO)(
+  IN  UINT32            Attributes,
+  OUT UINT64            *MaximumVariableStorageSize,
+  OUT UINT64            *RemainingVariableStorageSize,
+  OUT UINT64            *MaximumVariableSize
+  );
+
+
+//
+// EFI Runtime Services Table
+//
+#define EFI_SYSTEM_TABLE_SIGNATURE      SIGNATURE_64 ('I','B','I',' ','S','Y','S','T')
+#define EFI_2_30_SYSTEM_TABLE_REVISION  ((2 << 16) | (30))
+#define EFI_2_20_SYSTEM_TABLE_REVISION  ((2 << 16) | (20))
+#define EFI_2_10_SYSTEM_TABLE_REVISION  ((2 << 16) | (10))
+#define EFI_2_00_SYSTEM_TABLE_REVISION  ((2 << 16) | (00))
+#define EFI_1_10_SYSTEM_TABLE_REVISION  ((1 << 16) | (10))
+#define EFI_1_02_SYSTEM_TABLE_REVISION  ((1 << 16) | (02))
+#define EFI_SYSTEM_TABLE_REVISION       EFI_2_30_SYSTEM_TABLE_REVISION
+
+#define EFI_RUNTIME_SERVICES_SIGNATURE  SIGNATURE_64 ('R','U','N','T','S','E','R','V')
+#define EFI_RUNTIME_SERVICES_REVISION   EFI_2_30_SYSTEM_TABLE_REVISION
+
+///
+/// EFI Runtime Services Table.
+///
+typedef struct {
+  ///
+  /// The table header for the EFI Runtime Services Table.
+  ///
+  EFI_TABLE_HEADER                Hdr;
+
+  //
+  // Time Services
+  //
+  EFI_GET_TIME                    GetTime;
+  EFI_SET_TIME                    SetTime;
+  EFI_GET_WAKEUP_TIME             GetWakeupTime;
+  EFI_SET_WAKEUP_TIME             SetWakeupTime;
+
+  //
+  // Virtual Memory Services
+  //
+  EFI_SET_VIRTUAL_ADDRESS_MAP     SetVirtualAddressMap;
+  EFI_CONVERT_POINTER             ConvertPointer;
+
+  //
+  // Variable Services
+  //
+  EFI_GET_VARIABLE                GetVariable;
+  EFI_GET_NEXT_VARIABLE_NAME      GetNextVariableName;
+  EFI_SET_VARIABLE                SetVariable;
+
+  //
+  // Miscellaneous Services
+  //
+  EFI_GET_NEXT_HIGH_MONO_COUNT    GetNextHighMonotonicCount;
+  EFI_RESET_SYSTEM                ResetSystem;
+
+  //
+  // UEFI 2.0 Capsule Services
+  //
+  EFI_UPDATE_CAPSULE              UpdateCapsule;
+  EFI_QUERY_CAPSULE_CAPABILITIES  QueryCapsuleCapabilities;
+
+  //
+  // Miscellaneous UEFI 2.0 Service
+  //
+  EFI_QUERY_VARIABLE_INFO         QueryVariableInfo;
+} EFI_RUNTIME_SERVICES;
+
+
+#define EFI_BOOT_SERVICES_SIGNATURE   SIGNATURE_64 ('B','O','O','T','S','E','R','V')
+#define EFI_BOOT_SERVICES_REVISION    EFI_2_30_SYSTEM_TABLE_REVISION
+
+///
+/// EFI Boot Services Table.
+///
+typedef struct {
+  ///
+  /// The table header for the EFI Boot Services Table.
+  ///
+  EFI_TABLE_HEADER                Hdr;
+
+  //
+  // Task Priority Services
+  //
+  EFI_RAISE_TPL                   RaiseTPL;
+  EFI_RESTORE_TPL                 RestoreTPL;
+
+  //
+  // Memory Services
+  //
+  EFI_ALLOCATE_PAGES              AllocatePages;
+  EFI_FREE_PAGES                  FreePages;
+  EFI_GET_MEMORY_MAP              GetMemoryMap;
+  EFI_ALLOCATE_POOL               AllocatePool;
+  EFI_FREE_POOL                   FreePool;
+
+  //
+  // Event & Timer Services
+  //
+  EFI_CREATE_EVENT                  CreateEvent;
+  EFI_SET_TIMER                     SetTimer;
+  EFI_WAIT_FOR_EVENT                WaitForEvent;
+  EFI_SIGNAL_EVENT                  SignalEvent;
+  EFI_CLOSE_EVENT                   CloseEvent;
+  EFI_CHECK_EVENT                   CheckEvent;
+
+  //
+  // Protocol Handler Services
+  //
+  EFI_INSTALL_PROTOCOL_INTERFACE    InstallProtocolInterface;
+  EFI_REINSTALL_PROTOCOL_INTERFACE  ReinstallProtocolInterface;
+  EFI_UNINSTALL_PROTOCOL_INTERFACE  UninstallProtocolInterface;
+  EFI_HANDLE_PROTOCOL               HandleProtocol;
+  VOID                              *Reserved;
+  EFI_REGISTER_PROTOCOL_NOTIFY      RegisterProtocolNotify;
+  EFI_LOCATE_HANDLE                 LocateHandle;
+  EFI_LOCATE_DEVICE_PATH            LocateDevicePath;
+  EFI_INSTALL_CONFIGURATION_TABLE   InstallConfigurationTable;
+
+  //
+  // Image Services
+  //
+  EFI_IMAGE_LOAD                    LoadImage;
+  EFI_IMAGE_START                   StartImage;
+  EFI_EXIT                          Exit;
+  EFI_IMAGE_UNLOAD                  UnloadImage;
+  EFI_EXIT_BOOT_SERVICES            ExitBootServices;
+
+  //
+  // Miscellaneous Services
+  //
+  EFI_GET_NEXT_MONOTONIC_COUNT      GetNextMonotonicCount;
+  EFI_STALL                         Stall;
+  EFI_SET_WATCHDOG_TIMER            SetWatchdogTimer;
+
+  //
+  // DriverSupport Services
+  //
+  EFI_CONNECT_CONTROLLER            ConnectController;
+  EFI_DISCONNECT_CONTROLLER         DisconnectController;
+
+  //
+  // Open and Close Protocol Services
+  //
+  EFI_OPEN_PROTOCOL                 OpenProtocol;
+  EFI_CLOSE_PROTOCOL                CloseProtocol;
+  EFI_OPEN_PROTOCOL_INFORMATION     OpenProtocolInformation;
+
+  //
+  // Library Services
+  //
+  EFI_PROTOCOLS_PER_HANDLE          ProtocolsPerHandle;
+  EFI_LOCATE_HANDLE_BUFFER          LocateHandleBuffer;
+  EFI_LOCATE_PROTOCOL               LocateProtocol;
+  EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES    InstallMultipleProtocolInterfaces;
+  EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES  UninstallMultipleProtocolInterfaces;
+
+  //
+  // 32-bit CRC Services
+  //
+  EFI_CALCULATE_CRC32               CalculateCrc32;
+
+  //
+  // Miscellaneous Services
+  //
+  EFI_COPY_MEM                      CopyMem;
+  EFI_SET_MEM                       SetMem;
+  EFI_CREATE_EVENT_EX               CreateEventEx;
+} EFI_BOOT_SERVICES;
+
+///
+/// Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the
+/// EFI System Table.
+///
+typedef struct {
+  ///
+  /// The 128-bit GUID value that uniquely identifies the system configuration table.
+  ///
+  EFI_GUID                          VendorGuid;
+  ///
+  /// A pointer to the table associated with VendorGuid.
+  ///
+  VOID                              *VendorTable;
+} EFI_CONFIGURATION_TABLE;
+
+///
+/// EFI System Table
+///
+typedef struct {
+  ///
+  /// The table header for the EFI System Table.
+  ///
+  EFI_TABLE_HEADER                  Hdr;
+  ///
+  /// A pointer to a null terminated string that identifies the vendor
+  /// that produces the system firmware for the platform.
+  ///
+  CHAR16                            *FirmwareVendor;
+  ///
+  /// A firmware vendor specific value that identifies the revision
+  /// of the system firmware for the platform.
+  ///
+  UINT32                            FirmwareRevision;
+  ///
+  /// The handle for the active console input device. This handle must support
+  /// EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+  ///
+  EFI_HANDLE                        ConsoleInHandle;
+  ///
+  /// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is
+  /// associated with ConsoleInHandle.
+  ///
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *ConIn;
+  ///
+  /// The handle for the active console output device.
+  ///
+  EFI_HANDLE                        ConsoleOutHandle;
+  ///
+  /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
+  /// that is associated with ConsoleOutHandle.
+  ///
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut;
+  ///
+  /// The handle for the active standard error console device.
+  /// This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+  ///
+  EFI_HANDLE                        StandardErrorHandle;
+  ///
+  /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
+  /// that is associated with StandardErrorHandle.
+  ///
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *StdErr;
+  ///
+  /// A pointer to the EFI Runtime Services Table.
+  ///
+  EFI_RUNTIME_SERVICES              *RuntimeServices;
+  ///
+  /// A pointer to the EFI Boot Services Table.
+  ///
+  EFI_BOOT_SERVICES                 *BootServices;
+  ///
+  /// The number of system configuration tables in the buffer ConfigurationTable.
+  ///
+  UINTN                             NumberOfTableEntries;
+  ///
+  /// A pointer to the system configuration tables.
+  /// The number of entries in the table is NumberOfTableEntries.
+  ///
+  EFI_CONFIGURATION_TABLE           *ConfigurationTable;
+} EFI_SYSTEM_TABLE;
+
+/**
+  This is the declaration of an EFI image entry point. This entry point is
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+  both device drivers and bus drivers.
+
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param  SystemTable           A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_ENTRY_POINT)(
+  IN  EFI_HANDLE                   ImageHandle,
+  IN  EFI_SYSTEM_TABLE             *SystemTable
+  );
+
+//
+// EFI Load Options Attributes
+//
+#define LOAD_OPTION_ACTIVE            0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT   0x00000002
+#define LOAD_OPTION_HIDDEN            0x00000008
+#define LOAD_OPTION_CATEGORY          0x00001F00
+
+#define LOAD_OPTION_CATEGORY_BOOT     0x00000000
+#define LOAD_OPTION_CATEGORY_APP      0x00000100
+
+#define EFI_BOOT_OPTION_SUPPORT_KEY   0x00000001
+#define EFI_BOOT_OPTION_SUPPORT_APP   0x00000002
+#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300
+
+///
+/// EFI Boot Key Data
+///
+typedef union {
+  struct {
+    ///
+    /// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0.
+    ///
+    UINT32  Revision        : 8;
+    ///
+    /// Either the left or right Shift keys must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  ShiftPressed    : 1;
+    ///
+    /// Either the left or right Control keys must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  ControlPressed  : 1;
+    ///
+    /// Either the left or right Alt keys must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  AltPressed      : 1;
+    ///
+    /// Either the left or right Logo keys must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  LogoPressed     : 1;
+    ///
+    /// The Menu key must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  MenuPressed     : 1;
+    ///
+    /// The SysReq key must be pressed (1) or must not be pressed (0).
+    ///
+    UINT32  SysReqPressed    : 1;
+    UINT32  Reserved        : 16;
+    ///
+    /// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If
+    /// zero, then only the shift state is considered. If more than one, then the boot option will
+    /// only be launched if all of the specified keys are pressed with the same shift state.
+    ///
+    UINT32  InputKeyCount   : 2;
+  } Options;
+  UINT32  PackedValue;
+} EFI_BOOT_KEY_DATA;
+
+///
+/// EFI Key Option.
+///
+typedef struct {
+  ///
+  /// Specifies options about how the key will be processed.
+  ///
+  EFI_BOOT_KEY_DATA  KeyData;
+  ///
+  /// The CRC-32 which should match the CRC-32 of the entire EFI_LOAD_OPTION to
+  /// which BootOption refers. If the CRC-32s do not match this value, then this key
+  /// option is ignored.
+  ///
+  UINT32             BootOptionCrc;
+  ///
+  /// The Boot#### option which will be invoked if this key is pressed and the boot option
+  /// is active (LOAD_OPTION_ACTIVE is set).
+  ///
+  UINT16             BootOption;
+  ///
+  /// The key codes to compare against those returned by the
+  /// EFI_SIMPLE_TEXT_INPUT and EFI_SIMPLE_TEXT_INPUT_EX protocols.
+  /// The number of key codes (0-3) is specified by the EFI_KEY_CODE_COUNT field in KeyOptions.
+  ///
+  //EFI_INPUT_KEY      Keys[];
+} EFI_KEY_OPTION;
+
+//
+// EFI File location to boot from on removable media devices
+//
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA32    L"\\EFI\\BOOT\\BOOTIA32.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64    L"\\EFI\\BOOT\\BOOTIA64.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_X64     L"\\EFI\\BOOT\\BOOTX64.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_ARM     L"\\EFI\\BOOT\\BOOTARM.EFI"
+
+#if   defined (MDE_CPU_IA32)
+  #define EFI_REMOVABLE_MEDIA_FILE_NAME   EFI_REMOVABLE_MEDIA_FILE_NAME_IA32
+#elif defined (MDE_CPU_IPF)
+  #define EFI_REMOVABLE_MEDIA_FILE_NAME   EFI_REMOVABLE_MEDIA_FILE_NAME_IA64
+#elif defined (MDE_CPU_X64)
+  #define EFI_REMOVABLE_MEDIA_FILE_NAME   EFI_REMOVABLE_MEDIA_FILE_NAME_X64
+#elif defined (MDE_CPU_EBC)
+#elif defined (MDE_CPU_ARM)
+  #define EFI_REMOVABLE_MEDIA_FILE_NAME   EFI_REMOVABLE_MEDIA_FILE_NAME_ARM
+#else
+  #error Unknown Processor Type
+#endif
+
+#include <ipxe/efi/Uefi/UefiPxe.h>
+#include <ipxe/efi/Uefi/UefiGpt.h>
+#include <ipxe/efi/Uefi/UefiInternalFormRepresentation.h>
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h
new file mode 100644
index 0000000..0b1a3e1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h
@@ -0,0 +1,290 @@
+/** @file
+  Processor or Compiler specific defines and types x64 (Intel 64, AMD64).
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PROCESSOR_BIND_H__
+#define __PROCESSOR_BIND_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Define the processor type so other code can make processor based choices
+///
+#define MDE_CPU_X64
+
+//
+// Make sure we are using the correct packing rules per EFI specification
+//
+#if !defined(__GNUC__)
+#pragma pack()
+#endif
+
+
+#if defined(__INTEL_COMPILER)
+//
+// Disable ICC's remark #869: "Parameter" was never referenced warning.
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 869 )
+
+//
+// Disable ICC's remark #1418: external function definition with no prior declaration.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1418 )
+
+//
+// Disable ICC's remark #1419: external declaration in primary source file
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1419 )
+
+//
+// Disable ICC's remark #593: "Variable" was set but never used.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 593 )
+
+#endif
+
+
+#if defined(_MSC_EXTENSIONS)
+
+//
+// Disable warning that make it impossible to compile at /W4
+// This only works for Microsoft* tools
+//
+
+//
+// Disabling bitfield type checking warnings.
+//
+#pragma warning ( disable : 4214 )
+
+//
+// Disabling the unreferenced formal parameter warnings.
+//
+#pragma warning ( disable : 4100 )
+
+//
+// Disable slightly different base types warning as CHAR8 * can not be set
+// to a constant string.
+//
+#pragma warning ( disable : 4057 )
+
+//
+// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
+//
+#pragma warning ( disable : 4127 )
+
+//
+// This warning is caused by functions defined but not used. For precompiled header only.
+//
+#pragma warning ( disable : 4505 )
+
+//
+// This warning is caused by empty (after preprocessing) source file. For precompiled header only.
+//
+#pragma warning ( disable : 4206 )
+
+#endif
+
+
+#if defined(_MSC_EXTENSIONS)
+  //
+  // use Microsoft C complier dependent integer width types
+  //
+
+  ///
+  /// 8-byte unsigned value
+  ///
+  typedef unsigned __int64    UINT64;
+  ///
+  /// 8-byte signed value
+  ///
+  typedef __int64             INT64;
+  ///
+  /// 4-byte unsigned value
+  ///
+  typedef unsigned __int32    UINT32;
+  ///
+  /// 4-byte signed value
+  ///
+  typedef __int32             INT32;
+  ///
+  /// 2-byte unsigned value
+  ///
+  typedef unsigned short      UINT16;
+  ///
+  /// 2-byte Character.  Unless otherwise specified all strings are stored in the
+  /// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
+  ///
+  typedef unsigned short      CHAR16;
+  ///
+  /// 2-byte signed value
+  ///
+  typedef short               INT16;
+  ///
+  /// Logical Boolean.  1-byte value containing 0 for FALSE or a 1 for TRUE.  Other
+  /// values are undefined.
+  ///
+  typedef unsigned char       BOOLEAN;
+  ///
+  /// 1-byte unsigned value
+  ///
+  typedef unsigned char       UINT8;
+  ///
+  /// 1-byte Character
+  ///
+  typedef char                CHAR8;
+  ///
+  /// 1-byte signed value
+  ///
+  typedef char                INT8;
+#else
+  ///
+  /// 8-byte unsigned value
+  ///
+  typedef unsigned long long  UINT64;
+  ///
+  /// 8-byte signed value
+  ///
+  typedef long long           INT64;
+  ///
+  /// 4-byte unsigned value
+  ///
+  typedef unsigned int        UINT32;
+  ///
+  /// 4-byte signed value
+  ///
+  typedef int                 INT32;
+  ///
+  /// 2-byte unsigned value
+  ///
+  typedef unsigned short      UINT16;
+  ///
+  /// 2-byte Character.  Unless otherwise specified all strings are stored in the
+  /// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
+  ///
+  typedef unsigned short      CHAR16;
+  ///
+  /// 2-byte signed value
+  ///
+  typedef short               INT16;
+  ///
+  /// Logical Boolean.  1-byte value containing 0 for FALSE or a 1 for TRUE.  Other
+  /// values are undefined.
+  ///
+  typedef unsigned char       BOOLEAN;
+  ///
+  /// 1-byte unsigned value
+  ///
+  typedef unsigned char       UINT8;
+  ///
+  /// 1-byte Character
+  ///
+  typedef char                CHAR8;
+  ///
+  /// 1-byte signed value
+  ///
+  typedef char                INT8;
+#endif
+
+///
+/// Unsigned value of native width.  (4 bytes on supported 32-bit processor instructions,
+/// 8 bytes on supported 64-bit processor instructions)
+///
+typedef UINT64  UINTN;
+///
+/// Signed value of native width.  (4 bytes on supported 32-bit processor instructions,
+/// 8 bytes on supported 64-bit processor instructions)
+///
+typedef INT64   INTN;
+
+
+//
+// Processor specific defines
+//
+
+///
+/// A value of native width with the highest bit set.
+///
+#define MAX_BIT     0x8000000000000000ULL
+///
+/// A value of native width with the two highest bits set.
+///
+#define MAX_2_BITS  0xC000000000000000ULL
+
+///
+/// Maximum legal x64 address
+///
+#define MAX_ADDRESS   0xFFFFFFFFFFFFFFFFULL
+
+///
+/// The stack alignment required for x64
+///
+#define CPU_STACK_ALIGNMENT   16
+
+//
+// Modifier to ensure that all protocol member functions and EFI intrinsics
+// use the correct C calling convention. All protocol member functions and
+// EFI intrinsics are required to modify their member functions with EFIAPI.
+//
+#ifdef EFIAPI
+  ///
+  /// If EFIAPI is already defined, then we use that definition.
+  ///
+#elif defined(_MSC_EXTENSIONS)
+  ///
+  /// Microsoft* compiler specific method for EFIAPI calling convension
+  ///
+  #define EFIAPI __cdecl
+#elif defined(__GNUC__)
+  ///
+  /// Define the standard calling convention reguardless of optimization level.
+  /// The GCC support assumes a GCC compiler that supports the EFI ABI. The EFI
+  /// ABI is much closer to the x64 Microsoft* ABI than standard x64 (x86-64)
+  /// GCC ABI. Thus a standard x64 (x86-64) GCC compiler can not be used for
+  /// x64. Warning the assembly code in the MDE x64 does not follow the correct
+  /// ABI for the standard x64 (x86-64) GCC.
+  ///
+  #define EFIAPI
+#else
+  ///
+  /// The default for a non Microsoft* or GCC compiler is to assume the EFI ABI
+  /// is the standard.
+  ///
+  #define EFIAPI
+#endif
+
+#if defined(__GNUC__)
+  ///
+  /// For GNU assembly code, .global or .globl can declare global symbols.
+  /// Define this macro to unify the usage.
+  ///
+  #define ASM_GLOBAL .globl
+#endif
+
+/**
+  Return the pointer to the first instruction of a function given a function pointer.
+  On x64 CPU architectures, these two pointer values are the same,
+  so the implementation of this macro is very simple.
+
+  @param  FunctionPointer   A pointer to a function.
+
+  @return The pointer to the first instruction of a function given a function pointer.
+
+**/
+#define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer)
+
+#endif
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi.h
new file mode 100644
index 0000000..8a216b5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi.h
@@ -0,0 +1,146 @@
+#ifndef _IPXE_EFI_H
+#define _IPXE_EFI_H
+
+/** @file
+ *
+ * EFI API
+ *
+ * The intention is to include near-verbatim copies of the EFI headers
+ * required by iPXE.  This is achieved using the import.pl script in
+ * this directory.  Run the import script to update the local copies
+ * of the headers:
+ *
+ *     ./import.pl /path/to/edk2/edk2
+ *
+ * where /path/to/edk2/edk2 is the path to your local checkout of the
+ * EFI Development Kit.
+ *
+ * Note that import.pl will modify any #include lines in each imported
+ * header to reflect its new location within the iPXE tree.  It will
+ * also tidy up the file by removing carriage return characters and
+ * trailing whitespace.
+ */
+
+/* EFI headers rudely redefine NULL */
+#undef NULL
+
+/* EFI headers expect ICC to define __GNUC__ */
+#if defined ( __ICC ) && ! defined ( __GNUC__ )
+#define __GNUC__ 1
+#endif
+
+/* EFI headers think your compiler uses the MS ABI by default on X64 */
+#if __x86_64__
+#define EFIAPI __attribute__((ms_abi))
+#endif
+
+/* EFI headers assume regparm(0) on i386, but that is not the case for iPXE */
+#if __i386__
+#define EFIAPI __attribute__((cdecl,regparm(0)))
+#endif
+
+/* Include the top-level EFI header files */
+#include <ipxe/efi/Uefi.h>
+#include <ipxe/efi/PiDxe.h>
+#include <ipxe/efi/Protocol/LoadedImage.h>
+
+/* Reset any trailing #pragma pack directives */
+#pragma pack(1)
+#pragma pack()
+
+#include <ipxe/tables.h>
+#include <ipxe/uuid.h>
+
+/** An EFI protocol used by iPXE */
+struct efi_protocol {
+	/** GUID */
+	union {
+		/** EFI protocol GUID */
+		EFI_GUID guid;
+		/** UUID structure understood by iPXE */
+		union uuid uuid;
+	} u;
+	/** Variable containing pointer to protocol structure */
+	void **protocol;
+};
+
+/** EFI protocol table */
+#define EFI_PROTOCOLS __table ( struct efi_protocol, "efi_protocols" )
+
+/** Declare an EFI protocol used by iPXE */
+#define __efi_protocol __table_entry ( EFI_PROTOCOLS, 01 )
+
+/** Declare an EFI protocol to be required by iPXE
+ *
+ * @v _protocol		EFI protocol name
+ * @v _ptr		Pointer to protocol instance
+ */
+#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr )				     \
+	struct efi_protocol __ ## _protocol __efi_protocol = {		     \
+		.u.guid = _protocol ## _GUID,				     \
+		.protocol = ( ( void ** ) ( void * )			     \
+			      ( ( (_ptr) == ( ( _protocol ** ) (_ptr) ) ) ?  \
+				(_ptr) : (_ptr) ) ),			     \
+	}
+
+/** An EFI configuration table used by iPXE */
+struct efi_config_table {
+	/** GUID */
+	union {
+		/** EFI configuration table GUID */
+		EFI_GUID guid;
+		/** UUID structure understood by iPXE */
+		union uuid uuid;
+	} u;
+	/** Variable containing pointer to configuration table */
+	void **table;
+	/** Table is required for operation */
+	int required;
+};
+
+/** EFI configuration table table */
+#define EFI_CONFIG_TABLES \
+	__table ( struct efi_config_table, "efi_config_tables" )
+
+/** Declare an EFI configuration table used by iPXE */
+#define __efi_config_table __table_entry ( EFI_CONFIG_TABLES, 01 )
+
+/** Declare an EFI configuration table to be used by iPXE
+ *
+ * @v _table		EFI configuration table name
+ * @v _ptr		Pointer to configuration table
+ * @v _required		Table is required for operation
+ */
+#define EFI_USE_TABLE( _table, _ptr, _required )			     \
+	struct efi_config_table __ ## _table __efi_config_table = {	     \
+		.u.guid = _table ## _GUID,				     \
+		.table = ( ( void ** ) ( void * ) (_ptr) ),		     \
+		.required = (_required),				     \
+	}
+
+/** Convert a iPXE status code to an EFI status code
+ *
+ * FIXME: actually perform some kind of conversion.  iPXE error codes
+ * will be detected as EFI error codes; both have the top bit set, and
+ * the success return code is zero for both.  Anything that just
+ * reports a numerical error will be OK, anything attempting to
+ * interpret the value or to display a text equivalent will be
+ * screwed.
+ */
+#define RC_TO_EFIRC( rc ) (rc)
+
+/** Convert an EFI status code to a iPXE status code
+ *
+ * FIXME: as above
+ */
+#define EFIRC_TO_RC( efirc ) (efirc)
+
+extern EFI_HANDLE efi_image_handle;
+extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
+extern EFI_SYSTEM_TABLE *efi_systab;
+
+extern const char * efi_strerror ( EFI_STATUS efirc );
+extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+			     EFI_SYSTEM_TABLE *systab );
+
+#endif /* _IPXE_EFI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_driver.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_driver.h
new file mode 100644
index 0000000..e5872ce
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_driver.h
@@ -0,0 +1,49 @@
+#ifndef _IPXE_EFI_DRIVER_H
+#define _IPXE_EFI_DRIVER_H
+
+/** @file
+ *
+ * EFI driver interface
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/DriverBinding.h>
+#include <ipxe/efi/Protocol/ComponentName2.h>
+#include <ipxe/efi/Protocol/DevicePath.h>
+
+/** An EFI driver */
+struct efi_driver {
+	/** Name */
+	const char *name;
+	/** EFI name */
+	CHAR16 wname[32];
+	/** EFI driver binding protocol */
+	EFI_DRIVER_BINDING_PROTOCOL driver;
+	/** EFI component name protocol */
+	EFI_COMPONENT_NAME2_PROTOCOL wtf;
+};
+
+/** Initialise an EFI driver
+ *
+ * @v name		Driver name
+ * @v supported		Device supported method
+ * @v start		Device start method
+ * @v stop		Device stop method
+ */
+#define EFI_DRIVER_INIT( _name, _supported, _start, _stop ) {	\
+	.name = _name,						\
+	.driver = {						\
+		.Supported = _supported,			\
+		.Start = _start,				\
+		.Stop = _stop,					\
+		.Version = 0x10,				\
+	} }
+
+extern EFI_DEVICE_PATH_PROTOCOL *
+efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path );
+
+extern EFI_STATUS efi_driver_install ( struct efi_driver *efidrv );
+
+#endif /* _IPXE_EFI_DRIVER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_hii.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_hii.h
new file mode 100644
index 0000000..1a98750
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_hii.h
@@ -0,0 +1,140 @@
+#ifndef _IPXE_EFI_HII_H
+#define _IPXE_EFI_HII_H
+
+/** @file
+ *
+ * EFI human interface infrastructure
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/efi/Uefi/UefiInternalFormRepresentation.h>
+#include <ipxe/efi/Guid/MdeModuleHii.h>
+
+/**
+ * Define an EFI IFR form set type
+ *
+ * @v num_class_guids	Number of class GUIDs
+ * @ret type		Form set type
+ */
+#define EFI_IFR_FORM_SET_TYPE( num_class_guids )			   \
+	struct {							   \
+		EFI_IFR_FORM_SET FormSet;				   \
+		EFI_GUID ClassGuid[num_class_guids];			   \
+	} __attribute__ (( packed ))
+
+/**
+ * Define an EFI IFR form set
+ *
+ * @v guid		GUID
+ * @v title		Title string
+ * @v help		Help string
+ * @v type		Form set type (as returned by EFI_IFR_FORM_SET_TYPE())
+ * @ret ifr		Form set
+ *
+ * This definition opens a new scope, which must be closed by an
+ * EFI_IFR_END().
+ */
+#define EFI_IFR_FORM_SET( guid, title, help, type, ... ) {		   \
+	.FormSet = {							   \
+		.Header = {						   \
+			.OpCode = EFI_IFR_FORM_SET_OP,			   \
+			.Length = sizeof ( type ),			   \
+			.Scope = 1,					   \
+		},							   \
+		.Guid = guid,						   \
+		.FormSetTitle = title,					   \
+		.Help = help,						   \
+		.Flags = ( sizeof ( ( ( type * ) NULL )->ClassGuid ) /	   \
+			   sizeof ( ( ( type * ) NULL )->ClassGuid[0] ) ), \
+	},								   \
+	.ClassGuid = {							   \
+		__VA_ARGS__						   \
+	},								   \
+	}
+
+/**
+ * Define an EFI IFR GUID class
+ *
+ * @v class		Class
+ * @ret ifr		GUID class
+ */
+#define EFI_IFR_GUID_CLASS( class ) {					   \
+	.Header = {							   \
+		.OpCode = EFI_IFR_GUID_OP,				   \
+		.Length = sizeof ( EFI_IFR_GUID_CLASS ),		   \
+	},								   \
+	.Guid = EFI_IFR_TIANO_GUID,					   \
+	.ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS,			   \
+	.Class = class,							   \
+	}
+
+/**
+ * Define an EFI IFR GUID subclass
+ *
+ * @v subclass		Subclass
+ * @ret ifr		GUID subclass
+ */
+#define EFI_IFR_GUID_SUBCLASS( subclass ) {				   \
+	.Header = {							   \
+		.OpCode = EFI_IFR_GUID_OP,				   \
+		.Length = sizeof ( EFI_IFR_GUID_SUBCLASS ),		   \
+	},								   \
+	.Guid = EFI_IFR_TIANO_GUID,					   \
+	.ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS,			   \
+	.SubClass = subclass,						   \
+	}
+
+/**
+ * Define an EFI IFR form
+ *
+ * @v formid		Form ID
+ * @v title		Title string
+ * @ret ifr		Form
+ *
+ * This definition opens a new scope, which must be closed by an
+ * EFI_IFR_END().
+ */
+#define EFI_IFR_FORM( formid, title ) {					   \
+	.Header = {							   \
+		.OpCode = EFI_IFR_FORM_OP,				   \
+		.Length = sizeof ( EFI_IFR_FORM ),			   \
+		.Scope = 1,						   \
+	},								   \
+	.FormId = formid,						   \
+	.FormTitle = title,						   \
+	}
+
+/**
+ * Define an EFI IFR text widget
+ *
+ * @v prompt		Prompt string
+ * @v help		Help string
+ * @v text		Text string
+ * @ret ifr		Text widget
+ */
+#define EFI_IFR_TEXT( prompt, help, text ) {				   \
+	.Header = {							   \
+		.OpCode = EFI_IFR_TEXT_OP,				   \
+		.Length = sizeof ( EFI_IFR_TEXT ),			   \
+	},								   \
+	.Statement = {							   \
+		.Prompt = prompt,					   \
+		.Help = help,						   \
+	},								   \
+	.TextTwo = text,						   \
+	}
+
+/**
+ * Define an EFI IFR end marker
+ *
+ * @ret ifr		End marker
+ */
+#define EFI_IFR_END() {							   \
+	.Header = {							   \
+		.OpCode = EFI_IFR_END_OP,				   \
+		.Length = sizeof ( EFI_IFR_END ),			   \
+	},								   \
+	}
+
+#endif /* _IPXE_EFI_HII_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_io.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_io.h
new file mode 100644
index 0000000..2ed96e1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_io.h
@@ -0,0 +1,180 @@
+#ifndef _IPXE_EFI_IO_H
+#define _IPXE_EFI_IO_H
+
+/** @file
+ *
+ * iPXE I/O API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops.  I/O is handled using the EFI_CPU_IO_PROTOCOL.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef IOAPI_EFI
+#define IOAPI_PREFIX_efi
+#else
+#define IOAPI_PREFIX_efi __efi_
+#endif
+
+extern unsigned long long efi_ioread ( volatile void *io_addr,
+				       size_t size );
+extern void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+			  size_t size );
+extern void efi_ioreads ( volatile void *io_addr, void *data,
+			  size_t size, unsigned int count );
+extern void efi_iowrites ( volatile void *io_addr, const void *data,
+			  size_t size, unsigned int count );
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ * EFI runs with flat physical addressing, so these are all no-ops.
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) {
+	return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) {
+	return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+	return ( ( void * ) bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) {
+	/* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) {
+	return ( ( unsigned long ) io_addr );
+}
+
+/*
+ * I/O functions
+ *
+ */
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint64_t
+IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) {
+	return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) {
+	efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data,
+			     unsigned int count ) {
+	efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data,
+			     unsigned int count ) {
+	efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data,
+			     unsigned int count ) {
+	efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data,
+			      unsigned int count ) {
+	efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data,
+			      unsigned int count ) {
+	efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data,
+			      unsigned int count ) {
+	efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, mb ) ( void ) {
+	/* Do nothing; EFI readl()/writel() calls already act as
+	 * memory barriers.
+	 */
+}
+
+#endif /* _IPXE_EFI_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci.h
new file mode 100644
index 0000000..24890eb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci.h
@@ -0,0 +1,46 @@
+#ifndef _IPXE_EFI_PCI_H
+#define _IPXE_EFI_PCI_H
+
+/** @file
+ *
+ * EFI driver interface
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/PciIo.h>
+#include <ipxe/efi/Protocol/DevicePath.h>
+
+struct efi_driver;
+struct device;
+
+/** An EFI PCI device */
+struct efi_pci_device {
+	/** List of EFI PCI devices */
+	struct list_head list;
+	/** iPXE PCI device */
+	struct pci_device pci;
+	/** Underlying EFI device */
+	EFI_HANDLE device;
+	/** PCI I/O protocol */
+	EFI_PCI_IO_PROTOCOL *pci_io;
+	/** Device path */
+	EFI_DEVICE_PATH_PROTOCOL *path;
+	/** EFI driver */
+	struct efi_driver *efidrv;
+};
+
+extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
+					       EFI_HANDLE device );
+extern EFI_STATUS efipci_enable ( struct efi_pci_device *efipci );
+extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device );
+extern struct efi_pci_device * efipci_find ( struct device *dev );
+extern EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
+				     EFI_HANDLE device );
+extern void efipci_child_del ( struct efi_pci_device *efipci,
+			       EFI_HANDLE device );
+extern void efipci_destroy ( struct efi_driver *efidrv,
+			     struct efi_pci_device *efipci );
+
+#endif /* _IPXE_EFI_PCI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
new file mode 100644
index 0000000..1bc43e3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
@@ -0,0 +1,148 @@
+#ifndef _IPXE_EFI_PCI_API_H
+#define _IPXE_EFI_PCI_API_H
+
+/** @file
+ *
+ * iPXE PCI I/O API for EFI
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef PCIAPI_EFI
+#define PCIAPI_PREFIX_efi
+#else
+#define PCIAPI_PREFIX_efi __efi_
+#endif
+
+/* EFI PCI width codes defined by EFI spec */
+#define EFIPCI_WIDTH_BYTE 0
+#define EFIPCI_WIDTH_WORD 1
+#define EFIPCI_WIDTH_DWORD 2
+
+#define EFIPCI_LOCATION( _offset, _width ) \
+	( (_offset) | ( (_width) << 16 ) )
+#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff )
+#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 )
+
+struct pci_device;
+
+extern int efipci_read ( struct pci_device *pci, unsigned long location,
+			 void *value );
+extern int efipci_write ( struct pci_device *pci, unsigned long location,
+			  unsigned long value );
+
+/**
+ * Determine number of PCI buses within system
+ *
+ * @ret num_bus		Number of buses
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_num_bus ) ( void ) {
+	/* EFI does not want us to scan the PCI bus ourselves */
+	return 0;
+}
+
+/**
+ * Read byte from PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci,
+					      unsigned int where,
+					      uint8_t *value ) {
+	return efipci_read ( pci,
+			     EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+			     value );
+}
+
+/**
+ * Read word from PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci,
+					      unsigned int where,
+					      uint16_t *value ) {
+	return efipci_read ( pci,
+			     EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+			     value );
+}
+
+/**
+ * Read dword from PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci,
+					       unsigned int where,
+					       uint32_t *value ) {
+	return efipci_read ( pci,
+			     EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+			     value );
+}
+
+/**
+ * Write byte to PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_byte ) ( struct pci_device *pci,
+					       unsigned int where,
+					       uint8_t value ) {
+	return efipci_write ( pci,
+			      EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+			      value );
+}
+
+/**
+ * Write word to PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_word ) ( struct pci_device *pci,
+					       unsigned int where,
+					       uint16_t value ) {
+	return efipci_write ( pci,
+			      EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+			      value );
+}
+
+/**
+ * Write dword to PCI configuration space via EFI
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci,
+						unsigned int where,
+						uint32_t value ) {
+	return efipci_write ( pci,
+			      EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+			      value );
+}
+
+#endif /* _IPXE_EFI_PCI_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_smbios.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
new file mode 100644
index 0000000..7642e5b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_EFI_SMBIOS_H
+#define _IPXE_EFI_SMBIOS_H
+
+/** @file
+ *
+ * iPXE SMBIOS API for EFI
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef SMBIOS_EFI
+#define SMBIOS_PREFIX_efi
+#else
+#define SMBIOS_PREFIX_efi __efi_
+#endif
+
+#endif /* _IPXE_EFI_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_strings.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_strings.h
new file mode 100644
index 0000000..023ccda
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_strings.h
@@ -0,0 +1,23 @@
+#ifndef _IPXE_EFI_STRINGS_H
+#define _IPXE_EFI_STRINGS_H
+
+/** @file
+ *
+ * EFI strings
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+extern int efi_vsnprintf ( wchar_t *wbuf, size_t wsize, const char *fmt,
+			   va_list args );
+extern int efi_snprintf ( wchar_t *wbuf, size_t wsize, const char *fmt, ... );
+extern int efi_vssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt,
+			    va_list args );
+extern int efi_ssnprintf ( wchar_t *wbuf, ssize_t swsize,
+			   const char *fmt, ... );
+
+#endif /* _IPXE_EFI_STRINGS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_timer.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_timer.h
new file mode 100644
index 0000000..b10543d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_timer.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_EFI_TIMER_H
+#define _IPXE_EFI_TIMER_H
+
+/** @file
+ *
+ * iPXE timer API for EFI
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIMER_EFI
+#define TIMER_PREFIX_efi
+#else
+#define TIMER_PREFIX_efi __efi_
+#endif
+
+#endif /* _IPXE_EFI_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
new file mode 100644
index 0000000..dc226a3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
@@ -0,0 +1,90 @@
+#ifndef _IPXE_EFI_UACCESS_H
+#define _IPXE_EFI_UACCESS_H
+
+/** @file
+ *
+ * iPXE user access API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef UACCESS_EFI
+#define UACCESS_PREFIX_efi
+#else
+#define UACCESS_PREFIX_efi __efi_
+#endif
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr		Physical address
+ * @ret userptr		User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) {
+	return phys_addr;
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset from user pointer
+ * @ret phys_addr	Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+	return ( userptr + offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) {
+	return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+	return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) {
+	return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off,
+					userptr_t src, off_t src_off,
+					size_t len ) {
+	trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off,
+					 userptr_t src, off_t src_off,
+					 size_t len ) {
+	trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset,
+					int c, size_t len ) {
+	trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) {
+	return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset,
+					int c, size_t len ) {
+	return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+#endif /* _IPXE_EFI_UACCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
new file mode 100644
index 0000000..911e69a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_EFI_UMALLOC_H
+#define _IPXE_EFI_UMALLOC_H
+
+/** @file
+ *
+ * iPXE user memory allocation API for EFI
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef UMALLOC_EFI
+#define UMALLOC_PREFIX_efi
+#else
+#define UMALLOC_PREFIX_efi __efi_
+#endif
+
+#endif /* _IPXE_EFI_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/import.pl b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/import.pl
new file mode 100755
index 0000000..2b5d3e9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/efi/import.pl
@@ -0,0 +1,135 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+import.pl
+
+=head1 SYNOPSIS
+
+import.pl [options] /path/to/edk2/edk2
+
+Options:
+
+    -h,--help		Display brief help message
+    -v,--verbose	Increase verbosity
+    -q,--quiet		Decrease verbosity
+
+=cut
+
+use File::Spec::Functions qw ( :ALL );
+use File::Find;
+use File::Path;
+use Getopt::Long;
+use Pod::Usage;
+use FindBin;
+use strict;
+use warnings;
+
+my $verbosity = 0;
+
+sub try_import_file {
+  my $ipxedir = shift;
+  my $edktop = shift;
+  my $edkdirs = shift;
+  my $filename = shift;
+
+  # Skip everything except headers
+  return unless $filename =~ /\.h$/;
+
+  # Skip files that are iPXE native headers
+  my $outfile = catfile ( $ipxedir, $filename );
+  if ( -s $outfile ) {
+    open my $outfh, "<$outfile" or die "Could not open $outfile: $!\n";
+    my $line = <$outfh>;
+    close $outfh;
+    chomp $line;
+    return if $line =~ /^\#ifndef\s+_IPXE_\S+_H$/;
+  }
+
+  # Search for importable header
+  foreach my $edkdir ( @$edkdirs ) {
+    my $infile = catfile ( $edktop, $edkdir, $filename );
+    if ( -e $infile ) {
+      # We have found a matching source file - import it
+      print "$filename <- ".catfile ( $edkdir, $filename )."\n"
+	  if $verbosity >= 1;
+      open my $infh, "<$infile" or die "Could not open $infile: $!\n";
+      ( undef, my $outdir, undef ) = splitpath ( $outfile );
+      mkpath ( $outdir );
+      open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n";
+      my @dependencies = ();
+      my $licence;
+      my $guard;
+      while ( <$infh> ) {
+	# Strip CR and trailing whitespace
+	s/\r//g;
+	s/\s*$//g;
+	chomp;
+	# Update include lines, and record included files
+	if ( s/^\#include\s+[<\"](\S+)[>\"]/\#include <ipxe\/efi\/$1>/ ) {
+	  push @dependencies, $1;
+	}
+	# Check for BSD licence statement
+	if ( /^\s*THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE/ ) {
+	  die "Licence detected after header guard\n" if $guard;
+	  $licence = "BSD3";
+	}
+	# Write out line
+	print $outfh "$_\n";
+	# Apply FILE_LICENCE() immediately after include guard
+	if ( /^\#define\s+_?_\S+_H_?_$/ ) {
+	  die "Duplicate header guard detected in $infile\n" if $guard;
+	  $guard = 1;
+	  print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence;
+	}
+      }
+      close $outfh;
+      close $infh;
+      # Warn if no licence was detected
+      warn "Cannot detect licence in $infile\n" unless $licence;
+      warn "Cannot detect header guard in $infile\n" unless $guard;
+      # Recurse to handle any included files that we don't already have
+      foreach my $dependency ( @dependencies ) {
+	if ( ! -e catfile ( $ipxedir, $dependency ) ) {
+	  print "...following dependency on $dependency\n" if $verbosity >= 1;
+	  try_import_file ( $ipxedir, $edktop, $edkdirs, $dependency );
+	}
+      }
+      return;
+    }
+  }
+  die "$filename has no equivalent in $edktop\n";
+}
+
+# Parse command-line options
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+  'verbose|v+' => sub { $verbosity++; },
+  'quiet|q+' => sub { $verbosity--; },
+  'help|h' => sub { pod2usage ( 1 ); },
+) or die "Could not parse command-line options\n";
+pod2usage ( 1 ) unless @ARGV == 1;
+my $edktop = shift;
+
+# Identify edk import directories
+my $edkdirs = [ "MdePkg/Include", "IntelFrameworkPkg/Include",
+		"MdeModulePkg/Include" ];
+foreach my $edkdir ( @$edkdirs ) {
+  die "Directory \"$edktop\" does not appear to contain the EFI EDK2 "
+      ."(missing \"$edkdir\")\n" unless -d catdir ( $edktop, $edkdir );
+}
+
+# Identify iPXE EFI includes directory
+my $ipxedir = $FindBin::Bin;
+die "Directory \"$ipxedir\" does not appear to contain the iPXE EFI includes\n"
+    unless -e catfile ( $ipxedir, "../../../include/ipxe/efi" );
+
+if ( $verbosity >= 1 ) {
+  print "Importing EFI headers into $ipxedir\nfrom ";
+  print join ( "\n and ", map { catdir ( $edktop, $_ ) } @$edkdirs )."\n";
+}
+
+# Import headers
+find ( { wanted => sub {
+  try_import_file ( $ipxedir, $edktop, $edkdirs, abs2rel ( $_, $ipxedir ) );
+}, no_chdir => 1 }, $ipxedir );
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/eisa.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eisa.h
new file mode 100644
index 0000000..22a1ed9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eisa.h
@@ -0,0 +1,128 @@
+#ifndef EISA_H
+#define EISA_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/isa_ids.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+
+/*
+ * EISA constants
+ *
+ */
+
+#define EISA_MIN_SLOT (0x1)
+#define EISA_MAX_SLOT (0xf)	/* Must be 2^n - 1 */
+#define EISA_SLOT_BASE( n ) ( 0x1000 * (n) )
+
+#define EISA_VENDOR_ID ( 0xc80 )
+#define EISA_PROD_ID ( 0xc82 )
+#define EISA_GLOBAL_CONFIG ( 0xc84 )
+
+#define EISA_CMD_RESET ( 1 << 2 )
+#define EISA_CMD_ENABLE ( 1 << 0 )
+
+/** An EISA device ID list entry */
+struct eisa_device_id {
+	/** Name */
+        const char *name;
+	/** Manufacturer ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+};
+
+/** An EISA device */
+struct eisa_device {
+	/** Generic device */
+	struct device dev;
+	/** Slot number */
+	unsigned int slot;
+	/** I/O address */
+	uint16_t ioaddr;
+	/** Manufacturer ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+	/** Driver for this device */
+	struct eisa_driver *driver;
+	/** Driver-private data
+	 *
+	 * Use eisa_set_drvdata() and eisa_get_drvdata() to access
+	 * this field.
+	 */
+	void *priv;
+};
+
+/** An EISA driver */
+struct eisa_driver {
+	/** EISA ID table */
+	struct eisa_device_id *ids;
+	/** Number of entries in EISA ID table */
+	unsigned int id_count;
+	/**
+	 * Probe device
+	 *
+	 * @v eisa	EISA device
+	 * @v id	Matching entry in ID table
+	 * @ret rc	Return status code
+	 */
+	int ( * probe ) ( struct eisa_device *eisa,
+			  const struct eisa_device_id *id );
+	/**
+	 * Remove device
+	 *
+	 * @v eisa	EISA device
+	 */
+	void ( * remove ) ( struct eisa_device *eisa );
+};
+
+/** EISA driver table */
+#define EISA_DRIVERS __table ( struct eisa_driver, "eisa_drivers" )
+
+/** Declare an EISA driver */
+#define __eisa_driver __table_entry ( EISA_DRIVERS, 01 )
+
+extern void eisa_device_enabled ( struct eisa_device *eisa, int enabled );
+
+/**
+ * Enable EISA device
+ *
+ * @v eisa		EISA device
+ */
+static inline void enable_eisa_device ( struct eisa_device *eisa ) {
+	eisa_device_enabled ( eisa, 1 );
+}
+
+/**
+ * Disable EISA device
+ *
+ * @v eisa		EISA device
+ */
+static inline void disable_eisa_device ( struct eisa_device *eisa ) {
+	eisa_device_enabled ( eisa, 0 );
+}
+
+/**
+ * Set EISA driver-private data
+ *
+ * @v eisa		EISA device
+ * @v priv		Private data
+ */
+static inline void eisa_set_drvdata ( struct eisa_device *eisa, void *priv ) {
+	eisa->priv = priv;
+}
+
+/**
+ * Get EISA driver-private data
+ *
+ * @v eisa		EISA device
+ * @ret priv		Private data
+ */
+static inline void * eisa_get_drvdata ( struct eisa_device *eisa ) {
+	return eisa->priv;
+}
+
+#endif /* EISA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/elf.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/elf.h
new file mode 100644
index 0000000..e5fed2f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/elf.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_ELF_H
+#define _IPXE_ELF_H
+
+/**
+ * @file
+ *
+ * ELF image format
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <elf.h>
+
+extern int elf_load ( struct image *image, physaddr_t *entry );
+
+#endif /* _IPXE_ELF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/errfile.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/errfile.h
new file mode 100644
index 0000000..3073383
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/errfile.h
@@ -0,0 +1,245 @@
+#ifndef _IPXE_ERRFILE_H
+#define _IPXE_ERRFILE_H
+
+/** @file
+ *
+ * Error file identifiers
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <bits/errfile.h>
+
+/**
+ * @defgroup errfilecat Error file identifier categories
+ *
+ * @{
+ */
+
+#define ERRFILE_CORE		0x00002000	/**< Core code */
+#define ERRFILE_DRIVER		0x00004000	/**< Driver code */
+#define ERRFILE_NET		0x00006000	/**< Networking code */
+#define ERRFILE_IMAGE		0x00008000	/**< Image code */
+#define ERRFILE_OTHER		0x0000e000	/**< Any other code */
+
+/** @} */
+
+/** Flag for architecture-dependent error files */
+#define ERRFILE_ARCH		0x00800000
+
+/**
+ * @defgroup errfile Error file identifiers
+ *
+ * These values are automatically incorporated into the definitions
+ * for error numbers such as EINVAL.
+ *
+ * @{
+ */
+
+#define ERRFILE_asprintf	       ( ERRFILE_CORE | 0x00000000 )
+#define ERRFILE_downloader	       ( ERRFILE_CORE | 0x00010000 )
+#define ERRFILE_exec		       ( ERRFILE_CORE | 0x00020000 )
+#define ERRFILE_hw		       ( ERRFILE_CORE | 0x00030000 )
+#define ERRFILE_iobuf		       ( ERRFILE_CORE | 0x00040000 )
+#define ERRFILE_job		       ( ERRFILE_CORE | 0x00050000 )
+#define ERRFILE_linebuf		       ( ERRFILE_CORE | 0x00060000 )
+#define ERRFILE_monojob		       ( ERRFILE_CORE | 0x00070000 )
+#define ERRFILE_nvo		       ( ERRFILE_CORE | 0x00080000 )
+#define ERRFILE_open		       ( ERRFILE_CORE | 0x00090000 )
+#define ERRFILE_posix_io	       ( ERRFILE_CORE | 0x000a0000 )
+#define ERRFILE_resolv		       ( ERRFILE_CORE | 0x000b0000 )
+#define ERRFILE_settings	       ( ERRFILE_CORE | 0x000c0000 )
+#define ERRFILE_vsprintf	       ( ERRFILE_CORE | 0x000d0000 )
+#define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
+#define ERRFILE_bitmap		       ( ERRFILE_CORE | 0x000f0000 )
+#define ERRFILE_base64		       ( ERRFILE_CORE | 0x00100000 )
+#define ERRFILE_base16		       ( ERRFILE_CORE | 0x00110000 )
+#define ERRFILE_blockdev	       ( ERRFILE_CORE | 0x00120000 )
+#define ERRFILE_acpi		       ( ERRFILE_CORE | 0x00130000 )
+#define ERRFILE_null_sanboot	       ( ERRFILE_CORE | 0x00140000 )
+#define ERRFILE_edd		       ( ERRFILE_CORE | 0x00150000 )
+#define ERRFILE_parseopt	       ( ERRFILE_CORE | 0x00160000 )
+
+#define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
+#define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )
+#define ERRFILE_isapnp		     ( ERRFILE_DRIVER | 0x00020000 )
+#define ERRFILE_mca		     ( ERRFILE_DRIVER | 0x00030000 )
+#define ERRFILE_pci		     ( ERRFILE_DRIVER | 0x00040000 )
+#define ERRFILE_linux		     ( ERRFILE_DRIVER | 0x00050000 )
+#define ERRFILE_pcivpd		     ( ERRFILE_DRIVER | 0x00060000 )
+
+#define ERRFILE_nvs		     ( ERRFILE_DRIVER | 0x00100000 )
+#define ERRFILE_spi		     ( ERRFILE_DRIVER | 0x00110000 )
+#define ERRFILE_i2c_bit		     ( ERRFILE_DRIVER | 0x00120000 )
+#define ERRFILE_spi_bit		     ( ERRFILE_DRIVER | 0x00130000 )
+#define ERRFILE_nvsvpd		     ( ERRFILE_DRIVER | 0x00140000 )
+
+#define ERRFILE_3c509		     ( ERRFILE_DRIVER | 0x00200000 )
+#define ERRFILE_bnx2		     ( ERRFILE_DRIVER | 0x00210000 )
+#define ERRFILE_cs89x0		     ( ERRFILE_DRIVER | 0x00220000 )
+#define ERRFILE_eepro		     ( ERRFILE_DRIVER | 0x00230000 )
+#define ERRFILE_etherfabric	     ( ERRFILE_DRIVER | 0x00240000 )
+#define ERRFILE_legacy		     ( ERRFILE_DRIVER | 0x00250000 )
+#define ERRFILE_natsemi		     ( ERRFILE_DRIVER | 0x00260000 )
+#define ERRFILE_pnic		     ( ERRFILE_DRIVER | 0x00270000 )
+#define ERRFILE_prism2_pci	     ( ERRFILE_DRIVER | 0x00280000 )
+#define ERRFILE_prism2_plx	     ( ERRFILE_DRIVER | 0x00290000 )
+#define ERRFILE_rtl8139		     ( ERRFILE_DRIVER | 0x002a0000 )
+#define ERRFILE_smc9000		     ( ERRFILE_DRIVER | 0x002b0000 )
+#define ERRFILE_tg3		     ( ERRFILE_DRIVER | 0x002c0000 )
+#define ERRFILE_3c509_eisa	     ( ERRFILE_DRIVER | 0x002d0000 )
+#define ERRFILE_3c515		     ( ERRFILE_DRIVER | 0x002e0000 )
+#define ERRFILE_3c529		     ( ERRFILE_DRIVER | 0x002f0000 )
+#define ERRFILE_3c595		     ( ERRFILE_DRIVER | 0x00300000 )
+#define ERRFILE_3c5x9		     ( ERRFILE_DRIVER | 0x00310000 )
+#define ERRFILE_3c90x		     ( ERRFILE_DRIVER | 0x00320000 )
+#define ERRFILE_amd8111e	     ( ERRFILE_DRIVER | 0x00330000 )
+#define ERRFILE_davicom		     ( ERRFILE_DRIVER | 0x00340000 )
+#define ERRFILE_depca		     ( ERRFILE_DRIVER | 0x00350000 )
+#define ERRFILE_dmfe		     ( ERRFILE_DRIVER | 0x00360000 )
+#define ERRFILE_eepro100	     ( ERRFILE_DRIVER | 0x00380000 )
+#define ERRFILE_epic100		     ( ERRFILE_DRIVER | 0x00390000 )
+#define ERRFILE_forcedeth	     ( ERRFILE_DRIVER | 0x003a0000 )
+#define ERRFILE_mtd80x		     ( ERRFILE_DRIVER | 0x003b0000 )
+#define ERRFILE_ns83820		     ( ERRFILE_DRIVER | 0x003c0000 )
+#define ERRFILE_ns8390		     ( ERRFILE_DRIVER | 0x003d0000 )
+#define ERRFILE_pcnet32		     ( ERRFILE_DRIVER | 0x003e0000 )
+#define ERRFILE_r8169		     ( ERRFILE_DRIVER | 0x003f0000 )
+#define ERRFILE_sis900		     ( ERRFILE_DRIVER | 0x00400000 )
+#define ERRFILE_sundance	     ( ERRFILE_DRIVER | 0x00410000 )
+#define ERRFILE_tlan		     ( ERRFILE_DRIVER | 0x00420000 )
+#define ERRFILE_tulip		     ( ERRFILE_DRIVER | 0x00430000 )
+#define ERRFILE_via_rhine	     ( ERRFILE_DRIVER | 0x00440000 )
+#define ERRFILE_via_velocity	     ( ERRFILE_DRIVER | 0x00450000 )
+#define ERRFILE_w89c840		     ( ERRFILE_DRIVER | 0x00460000 )
+#define ERRFILE_ipoib		     ( ERRFILE_DRIVER | 0x00470000 )
+#define ERRFILE_e1000_main	     ( ERRFILE_DRIVER | 0x00480000 )
+#define ERRFILE_e1000e_main	     ( ERRFILE_DRIVER | 0x00490000 )
+#define ERRFILE_mtnic		     ( ERRFILE_DRIVER | 0x004a0000 )
+#define ERRFILE_phantom		     ( ERRFILE_DRIVER | 0x004b0000 )
+#define ERRFILE_ne2k_isa	     ( ERRFILE_DRIVER | 0x004c0000 )
+#define ERRFILE_b44		     ( ERRFILE_DRIVER | 0x004d0000 )
+#define ERRFILE_rtl818x		     ( ERRFILE_DRIVER | 0x004e0000 )
+#define ERRFILE_sky2                 ( ERRFILE_DRIVER | 0x004f0000 )
+#define ERRFILE_ath5k		     ( ERRFILE_DRIVER | 0x00500000 )
+#define ERRFILE_atl1e		     ( ERRFILE_DRIVER | 0x00510000 )
+#define ERRFILE_sis190		     ( ERRFILE_DRIVER | 0x00520000 )
+#define ERRFILE_myri10ge	     ( ERRFILE_DRIVER | 0x00530000 )
+#define ERRFILE_skge		     ( ERRFILE_DRIVER | 0x00540000 )
+#define ERRFILE_vxge_main	     ( ERRFILE_DRIVER | 0x00550000 )
+#define ERRFILE_vxge_config	     ( ERRFILE_DRIVER | 0x00560000 )
+#define ERRFILE_vxge_traffic	     ( ERRFILE_DRIVER | 0x00570000 )
+#define ERRFILE_igb_main	     ( ERRFILE_DRIVER | 0x00580000 )
+#define ERRFILE_snpnet		     ( ERRFILE_DRIVER | 0x00590000 )
+#define ERRFILE_snponly		     ( ERRFILE_DRIVER | 0x005a0000 )
+#define ERRFILE_jme		     ( ERRFILE_DRIVER | 0x005b0000 )
+#define ERRFILE_virtio_net	     ( ERRFILE_DRIVER | 0x005c0000 )
+#define ERRFILE_tap		     ( ERRFILE_DRIVER | 0x005d0000 )
+#define ERRFILE_igbvf_main	     ( ERRFILE_DRIVER | 0x005e0000 )
+
+#define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
+#define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )
+#define ERRFILE_hermon		     ( ERRFILE_DRIVER | 0x00720000 )
+#define ERRFILE_linda		     ( ERRFILE_DRIVER | 0x00730000 )
+#define ERRFILE_ata		     ( ERRFILE_DRIVER | 0x00740000 )
+#define ERRFILE_srp		     ( ERRFILE_DRIVER | 0x00750000 )
+#define ERRFILE_qib7322		     ( ERRFILE_DRIVER | 0x00760000 )
+
+#define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
+#define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )
+#define ERRFILE_dhcpopts		( ERRFILE_NET | 0x00020000 )
+#define ERRFILE_ethernet		( ERRFILE_NET | 0x00030000 )
+#define ERRFILE_icmpv6			( ERRFILE_NET | 0x00040000 )
+#define ERRFILE_ipv4			( ERRFILE_NET | 0x00050000 )
+#define ERRFILE_ipv6			( ERRFILE_NET | 0x00060000 )
+#define ERRFILE_ndp			( ERRFILE_NET | 0x00070000 )
+#define ERRFILE_netdevice		( ERRFILE_NET | 0x00080000 )
+#define ERRFILE_nullnet			( ERRFILE_NET | 0x00090000 )
+#define ERRFILE_tcp			( ERRFILE_NET | 0x000a0000 )
+#define ERRFILE_ftp			( ERRFILE_NET | 0x000b0000 )
+#define ERRFILE_http			( ERRFILE_NET | 0x000c0000 )
+#define ERRFILE_iscsi			( ERRFILE_NET | 0x000d0000 )
+#define ERRFILE_tcpip			( ERRFILE_NET | 0x000e0000 )
+#define ERRFILE_udp			( ERRFILE_NET | 0x000f0000 )
+#define ERRFILE_dhcp			( ERRFILE_NET | 0x00100000 )
+#define ERRFILE_dns			( ERRFILE_NET | 0x00110000 )
+#define ERRFILE_tftp			( ERRFILE_NET | 0x00120000 )
+#define ERRFILE_infiniband		( ERRFILE_NET | 0x00130000 )
+#define ERRFILE_netdev_settings		( ERRFILE_NET | 0x00140000 )
+#define ERRFILE_dhcppkt			( ERRFILE_NET | 0x00150000 )
+#define ERRFILE_slam			( ERRFILE_NET | 0x00160000 )
+#define ERRFILE_ib_sma			( ERRFILE_NET | 0x00170000 )
+#define ERRFILE_ib_packet		( ERRFILE_NET | 0x00180000 )
+#define ERRFILE_icmp			( ERRFILE_NET | 0x00190000 )
+#define ERRFILE_ib_qset			( ERRFILE_NET | 0x001a0000 )
+#define ERRFILE_ib_gma			( ERRFILE_NET | 0x001b0000 )
+#define ERRFILE_ib_pathrec		( ERRFILE_NET | 0x001c0000 )
+#define ERRFILE_ib_mcast		( ERRFILE_NET | 0x001d0000 )
+#define ERRFILE_ib_cm			( ERRFILE_NET | 0x001e0000 )
+#define ERRFILE_net80211		( ERRFILE_NET | 0x001f0000 )
+#define ERRFILE_ib_mi			( ERRFILE_NET | 0x00200000 )
+#define ERRFILE_ib_cmrc			( ERRFILE_NET | 0x00210000 )
+#define ERRFILE_ib_srp			( ERRFILE_NET | 0x00220000 )
+#define ERRFILE_sec80211		( ERRFILE_NET | 0x00230000 )
+#define ERRFILE_wep			( ERRFILE_NET | 0x00240000 )
+#define ERRFILE_eapol			( ERRFILE_NET | 0x00250000 )
+#define ERRFILE_wpa			( ERRFILE_NET | 0x00260000 )
+#define ERRFILE_wpa_psk			( ERRFILE_NET | 0x00270000 )
+#define ERRFILE_wpa_tkip		( ERRFILE_NET | 0x00280000 )
+#define ERRFILE_wpa_ccmp		( ERRFILE_NET | 0x00290000 )
+#define ERRFILE_eth_slow		( ERRFILE_NET | 0x002a0000 )
+#define ERRFILE_fc			( ERRFILE_NET | 0x002b0000 )
+#define ERRFILE_fcels			( ERRFILE_NET | 0x002c0000 )
+#define ERRFILE_fcp			( ERRFILE_NET | 0x002d0000 )
+#define ERRFILE_fcoe			( ERRFILE_NET | 0x002e0000 )
+#define ERRFILE_fcns			( ERRFILE_NET | 0x002f0000 )
+#define ERRFILE_vlan			( ERRFILE_NET | 0x00300000 )
+
+#define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
+#define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )
+#define ERRFILE_script		      ( ERRFILE_IMAGE | 0x00020000 )
+#define ERRFILE_segment		      ( ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_efi_image	      ( ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_embedded	      ( ERRFILE_IMAGE | 0x00050000 )
+
+#define ERRFILE_asn1		      ( ERRFILE_OTHER | 0x00000000 )
+#define ERRFILE_chap		      ( ERRFILE_OTHER | 0x00010000 )
+#define ERRFILE_aoeboot		      ( ERRFILE_OTHER | 0x00020000 )
+#define ERRFILE_autoboot	      ( ERRFILE_OTHER | 0x00030000 )
+#define ERRFILE_dhcpmgmt	      ( ERRFILE_OTHER | 0x00040000 )
+#define ERRFILE_imgmgmt		      ( ERRFILE_OTHER | 0x00050000 )
+#define ERRFILE_pxe_tftp	      ( ERRFILE_OTHER | 0x00060000 )
+#define ERRFILE_pxe_udp		      ( ERRFILE_OTHER | 0x00070000 )
+#define ERRFILE_axtls_aes	      ( ERRFILE_OTHER | 0x00080000 )
+#define ERRFILE_cipher		      ( ERRFILE_OTHER | 0x00090000 )
+#define ERRFILE_image_cmd	      ( ERRFILE_OTHER | 0x000a0000 )
+#define ERRFILE_uri_test	      ( ERRFILE_OTHER | 0x000b0000 )
+#define ERRFILE_ibft		      ( ERRFILE_OTHER | 0x000c0000 )
+#define ERRFILE_tls		      ( ERRFILE_OTHER | 0x000d0000 )
+#define ERRFILE_ifmgmt		      ( ERRFILE_OTHER | 0x000e0000 )
+#define ERRFILE_iscsiboot	      ( ERRFILE_OTHER | 0x000f0000 )
+#define ERRFILE_efi_pci		      ( ERRFILE_OTHER | 0x00100000 )
+#define ERRFILE_efi_snp		      ( ERRFILE_OTHER | 0x00110000 )
+#define ERRFILE_smbios		      ( ERRFILE_OTHER | 0x00120000 )
+#define ERRFILE_smbios_settings	      ( ERRFILE_OTHER | 0x00130000 )
+#define ERRFILE_efi_smbios	      ( ERRFILE_OTHER | 0x00140000 )
+#define ERRFILE_pxemenu		      ( ERRFILE_OTHER | 0x00150000 )
+#define ERRFILE_x509		      ( ERRFILE_OTHER | 0x00160000 )
+#define ERRFILE_login_ui	      ( ERRFILE_OTHER | 0x00170000 )
+#define ERRFILE_ib_srpboot	      ( ERRFILE_OTHER | 0x00180000 )
+#define ERRFILE_iwmgmt		      ( ERRFILE_OTHER | 0x00190000 )
+#define ERRFILE_linux_smbios	      ( ERRFILE_OTHER | 0x001a0000 )
+#define ERRFILE_lotest		      ( ERRFILE_OTHER | 0x001b0000 )
+#define ERRFILE_config_cmd	      ( ERRFILE_OTHER | 0x001c0000 )
+#define ERRFILE_ifmgmt_cmd	      ( ERRFILE_OTHER | 0x001d0000 )
+#define ERRFILE_fcmgmt_cmd	      ( ERRFILE_OTHER | 0x001e0000 )
+#define ERRFILE_gdbstub_cmd	      ( ERRFILE_OTHER | 0x001f0000 )
+#define ERRFILE_sanboot_cmd	      ( ERRFILE_OTHER | 0x00200000 )
+#define ERRFILE_bofm		      ( ERRFILE_OTHER | 0x00210000 )
+#define ERRFILE_prompt		      ( ERRFILE_OTHER | 0x00220000 )
+#define ERRFILE_nvo_cmd		      ( ERRFILE_OTHER | 0x00230000 )
+
+/** @} */
+
+#endif /* _IPXE_ERRFILE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/errortab.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/errortab.h
new file mode 100644
index 0000000..a2f6a70
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/errortab.h
@@ -0,0 +1,28 @@
+#ifndef _IPXE_ERRORTAB_H
+#define _IPXE_ERRORTAB_H
+
+/** @file
+ *
+ * Error message tables
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+
+struct errortab {
+	int errno;
+	const char *text;
+};
+
+#define ERRORTAB __table ( struct errortab, "errortab" )
+
+#define __errortab __table_entry ( ERRORTAB, 01 )
+
+#define __einfo_errortab( einfo ) {			\
+	.errno = __einfo_errno ( einfo ),		\
+	.text = __einfo_desc ( einfo ),			\
+	}
+
+#endif /* _IPXE_ERRORTAB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/eth_slow.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eth_slow.h
new file mode 100644
index 0000000..0050919
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/eth_slow.h
@@ -0,0 +1,255 @@
+#ifndef _IPXE_ETH_SLOW_H
+#define _IPXE_ETH_SLOW_H
+
+/** @file
+ *
+ * Ethernet slow protocols
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Slow protocols header */
+struct eth_slow_header {
+	/** Slow protocols subtype */
+	uint8_t subtype;
+	/** Subtype version number */
+	uint8_t version;
+} __attribute__ (( packed ));
+
+/** LACP subtype */
+#define ETH_SLOW_SUBTYPE_LACP 1
+
+/** LACP version number */
+#define ETH_SLOW_LACP_VERSION 1
+
+/** Marker subtype */
+#define ETH_SLOW_SUBTYPE_MARKER 2
+
+/** Marker version number */
+#define ETH_SLOW_MARKER_VERSION 1
+
+/** TLV (type, length, value) header */
+struct eth_slow_tlv_header {
+	/** Type
+	 *
+	 * This is an ETH_SLOW_TLV_XXX constant.
+	 */
+	uint8_t type;
+	/** Length
+	 *
+	 * The length includes the TLV header (except for a TLV
+	 * terminator, which has a length of zero).
+	 */
+	uint8_t length;
+} __attribute__ (( packed ));
+
+/** Terminator type */
+#define ETH_SLOW_TLV_TERMINATOR 0
+
+/** Terminator length */
+#define ETH_SLOW_TLV_TERMINATOR_LEN 0
+
+/** LACP actor type */
+#define ETH_SLOW_TLV_LACP_ACTOR 1
+
+/** LACP actor length */
+#define ETH_SLOW_TLV_LACP_ACTOR_LEN \
+	( sizeof ( struct eth_slow_lacp_entity_tlv ) )
+
+/** LACP partner type */
+#define ETH_SLOW_TLV_LACP_PARTNER 2
+
+/** LACP partner length */
+#define ETH_SLOW_TLV_LACP_PARTNER_LEN \
+	( sizeof ( struct eth_slow_lacp_entity_tlv ) )
+
+/** LACP collector type */
+#define ETH_SLOW_TLV_LACP_COLLECTOR 3
+
+/** LACP collector length */
+#define ETH_SLOW_TLV_LACP_COLLECTOR_LEN \
+	( sizeof ( struct eth_slow_lacp_collector_tlv ) )
+
+/** Marker request type */
+#define ETH_SLOW_TLV_MARKER_REQUEST 1
+
+/** Marker request length */
+#define ETH_SLOW_TLV_MARKER_REQUEST_LEN \
+	( sizeof ( struct eth_slow_marker_tlv ) )
+
+/** Marker response type */
+#define ETH_SLOW_TLV_MARKER_RESPONSE 2
+
+/** Marker response length */
+#define ETH_SLOW_TLV_MARKER_RESPONSE_LEN \
+	( sizeof ( struct eth_slow_marker_tlv ) )
+
+/** Terminator TLV */
+struct eth_slow_terminator_tlv {
+	/** TLV header */
+	struct eth_slow_tlv_header tlv;
+} __attribute__ (( packed ));
+
+/** LACP entity (actor or partner) TLV */
+struct eth_slow_lacp_entity_tlv {
+	/** TLV header */
+	struct eth_slow_tlv_header tlv;
+	/** System priority
+	 *
+	 * Used to determine the order in which ports are selected for
+	 * aggregation.
+	 */
+	uint16_t system_priority;
+	/** System identifier
+	 *
+	 * Used to uniquely identify the system (i.e. the entity with
+	 * potentially multiple ports).
+	 */
+	uint8_t system[ETH_ALEN];
+	/** Key
+	 *
+	 * Used to uniquely identify a group of aggregatable ports
+	 * within a system.
+	 */
+	uint16_t key;
+	/** Port priority
+	 *
+	 * Used to determine the order in which ports are selected for
+	 * aggregation.
+	 */
+	uint16_t port_priority;
+	/** Port identifier
+	 *
+	 * Used to uniquely identify a port within a system.
+	 */
+	uint16_t port;
+	/** State
+	 *
+	 * This is the bitwise OR of zero or more LACP_STATE_XXX
+	 * constants.
+	 */
+	uint8_t state;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Maximum system priority */
+#define LACP_SYSTEM_PRIORITY_MAX 0xffff
+
+/** Maximum port priority */
+#define LACP_PORT_PRIORITY_MAX 0xff
+
+/** LACP entity is active
+ *
+ * Represented by the state character "A"/"a"
+ */
+#define LACP_STATE_ACTIVE 0x01
+
+/** LACP timeout is short
+ *
+ * Short timeout is one second, long timeout is 30s
+ *
+ * Represented by the state character "F"/"f"
+ */
+#define LACP_STATE_FAST 0x02
+
+/** LACP link is aggregateable
+ *
+ * Represented by the state characters "G"/"g"
+ */
+#define LACP_STATE_AGGREGATABLE 0x04
+
+/** LACP link is in synchronisation
+ *
+ * Represented by the state characters "S"/"s"
+ */
+#define LACP_STATE_IN_SYNC 0x08
+
+/** LACP link is collecting (receiving)
+ *
+ * Represented by the state characters "C"/"c"
+ */
+#define LACP_STATE_COLLECTING 0x10
+
+/** LACP link is distributing (transmitting)
+ *
+ * Represented by the state characters "D"/"d"
+ */
+#define LACP_STATE_DISTRIBUTING 0x20
+
+/** LACP entity is using defaulted partner information
+ *
+ * Represented by the state characters "L"/"l"
+ */
+#define LACP_STATE_DEFAULTED 0x40
+
+/** LACP entity receive state machine is in EXPIRED
+ *
+ * Represented by the state characters "X"/"x"
+ */
+#define LACP_STATE_EXPIRED 0x80
+
+/** LACP collector TLV */
+struct eth_slow_lacp_collector_tlv {
+	/** TLV header */
+	struct eth_slow_tlv_header tlv;
+	/** Maximum delay (in 10us increments) */
+	uint16_t max_delay;
+	/** Reserved */
+	uint8_t reserved[12];
+} __attribute__ (( packed ));
+
+/** Marker TLV */
+struct eth_slow_marker_tlv {
+	/** TLV header */
+	struct eth_slow_tlv_header tlv;
+	/** Requester port */
+	uint16_t port;
+	/** Requester system */
+	uint8_t system[ETH_ALEN];
+	/** Requester transaction ID */
+	uint32_t xact;
+	/** Padding */
+	uint16_t pad;
+} __attribute__ (( packed ));
+
+/** LACP packet */
+struct eth_slow_lacp {
+	/** Slow protocols header */
+	struct eth_slow_header header;
+	/** Actor information */
+	struct eth_slow_lacp_entity_tlv actor;
+	/** Partner information */
+	struct eth_slow_lacp_entity_tlv partner;
+	/** Collector information */
+	struct eth_slow_lacp_collector_tlv collector;
+	/** Terminator */
+	struct eth_slow_terminator_tlv terminator;
+	/** Reserved */
+	uint8_t reserved[50];
+} __attribute__ (( packed ));
+
+/** Marker packet */
+struct eth_slow_marker {
+	/** Slow protocols header */
+	struct eth_slow_header header;
+	/** Marker information */
+	struct eth_slow_marker_tlv marker;
+	/** Terminator */
+	struct eth_slow_terminator_tlv terminator;
+	/** Reserved */
+	uint8_t reserved[90];
+} __attribute__ (( packed ));
+
+/** Slow protocols packet */
+union eth_slow_packet {
+	/** Slow protocols header */
+	struct eth_slow_header header;
+	/** LACP packet */
+	struct eth_slow_lacp lacp;
+	/** Marker packet */
+	struct eth_slow_marker marker;
+} __attribute__ (( packed ));
+
+#endif /* _IPXE_ETH_SLOW_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ethernet.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ethernet.h
new file mode 100644
index 0000000..7e49655
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ethernet.h
@@ -0,0 +1,87 @@
+#ifndef _IPXE_ETHERNET_H
+#define _IPXE_ETHERNET_H
+
+/** @file
+ *
+ * Ethernet protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/**
+ * Check if Ethernet address is all zeroes
+ *
+ * @v addr		Ethernet address
+ * @ret is_zero		Address is all zeroes
+ */
+static inline int is_zero_ether_addr ( const void *addr ) {
+	const uint8_t *addr_bytes = addr;
+
+	return ( ! ( addr_bytes[0] | addr_bytes[1] | addr_bytes[2] |
+		     addr_bytes[3] | addr_bytes[4] | addr_bytes[5] ) );
+}
+
+/**
+ * Check if Ethernet address is a multicast address
+ *
+ * @v addr		Ethernet address
+ * @ret is_mcast	Address is a multicast address
+ *
+ * Note that the broadcast address is also a multicast address.
+ */
+static inline int is_multicast_ether_addr ( const void *addr ) {
+	const uint8_t *addr_bytes = addr;
+
+	return ( addr_bytes[0] & 0x01 );
+}
+
+/**
+ * Check if Ethernet address is locally assigned
+ *
+ * @v addr		Ethernet address
+ * @ret is_local	Address is locally assigned
+ */
+static inline int is_local_ether_addr ( const void *addr ) {
+	const uint8_t *addr_bytes = addr;
+
+	return ( addr_bytes[0] & 0x02 );
+}
+
+/**
+ * Check if Ethernet address is the broadcast address
+ *
+ * @v addr		Ethernet address
+ * @ret is_bcast	Address is the broadcast address
+ */
+static inline int is_broadcast_ether_addr ( const void *addr ) {
+	const uint8_t *addr_bytes = addr;
+
+	return ( ( addr_bytes[0] & addr_bytes[1] & addr_bytes[2] &
+		   addr_bytes[3] & addr_bytes[4] & addr_bytes[5] ) == 0xff );
+}
+
+/**
+ * Check if Ethernet address is valid
+ *
+ * @v addr		Ethernet address
+ * @ret is_valid	Address is valid
+ *
+ * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is
+ * not a multicast address, and is not ff:ff:ff:ff:ff:ff.
+ */
+static inline int is_valid_ether_addr ( const void *addr ) {
+	return ( ( ! is_multicast_ether_addr ( addr ) ) &&
+		 ( ! is_zero_ether_addr ( addr ) ) );
+}
+
+extern void eth_init_addr ( const void *hw_addr, void *ll_addr );
+extern const char * eth_ntoa ( const void *ll_addr );
+extern int eth_mc_hash ( unsigned int af, const void *net_addr,
+			 void *ll_addr );
+extern int eth_eth_addr ( const void *ll_addr, void *eth_addr );
+extern struct net_device * alloc_etherdev ( size_t priv_size );
+
+#endif /* _IPXE_ETHERNET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fakedhcp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fakedhcp.h
new file mode 100644
index 0000000..ea06b06
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fakedhcp.h
@@ -0,0 +1,23 @@
+#ifndef _IPXE_FAKEDHCP_H
+#define _IPXE_FAKEDHCP_H
+
+/** @file
+ *
+ * Fake DHCP packets
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+struct net_device;
+
+extern int create_fakedhcpdiscover ( struct net_device *netdev,
+				     void *data, size_t max_len );
+extern int create_fakedhcpack ( struct net_device *netdev,
+				void *data, size_t max_len );
+extern int create_fakepxebsack ( struct net_device *netdev,
+				 void *data, size_t max_len );
+
+#endif /* _IPXE_FAKEDHCP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fc.h
new file mode 100644
index 0000000..ab6b5ba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fc.h
@@ -0,0 +1,471 @@
+#ifndef _IPXE_FC_H
+#define _IPXE_FC_H
+
+/**
+ * @file
+ *
+ * Fibre Channel
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/interface.h>
+#include <ipxe/retry.h>
+#include <ipxe/socket.h>
+
+/******************************************************************************
+ *
+ * Fibre Channel Names and identifiers
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel name */
+struct fc_name {
+	uint8_t bytes[8];
+} __attribute__ (( packed ));
+
+/** Length of Fibre Channel name text */
+#define FC_NAME_STRLEN 23 /* "xx:xx:xx:xx:xx:xx:xx:xx" */
+
+/** A Fibre Channel port identifier */
+struct fc_port_id {
+	uint8_t bytes[3];
+} __attribute__ (( packed ));
+
+/** Length of Fibre Channel port identifier next */
+#define FC_PORT_ID_STRLEN 9 /* "xx.xx.xx" */
+
+/**
+ * Fibre Channel socket address
+ */
+struct sockaddr_fc {
+	/** Socket address family (part of struct @c sockaddr)
+	 *
+	 * Always set to @c AF_FC for Fibre Channel addresses
+	 */
+	sa_family_t sfc_family;
+	/** Port ID */
+	struct fc_port_id sfc_port_id;
+	/** Padding
+	 *
+	 * This ensures that a struct @c sockaddr_tcpip is large
+	 * enough to hold a socket address for any TCP/IP address
+	 * family.
+	 */
+	char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
+					     - sizeof ( struct fc_port_id ) ];
+} __attribute__ (( may_alias ));
+
+extern struct fc_port_id fc_empty_port_id;
+extern struct fc_port_id fc_f_port_id;
+extern struct fc_port_id fc_gs_port_id;
+extern struct fc_port_id fc_ptp_low_port_id;
+extern struct fc_port_id fc_ptp_high_port_id;
+
+extern const char * fc_id_ntoa ( const struct fc_port_id *id );
+extern int fc_id_aton ( const char *id_text, struct fc_port_id *id );
+extern const char * fc_ntoa ( const struct fc_name *wwn );
+extern int fc_aton ( const char *wwn_text, struct fc_name *wwn );
+extern struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
+					    struct fc_port_id *id );
+
+/******************************************************************************
+ *
+ * Fibre Channel link state
+ *
+ ******************************************************************************
+ */
+
+/** Delay between failed link-up attempts */
+#define FC_LINK_RETRY_DELAY ( 2 * TICKS_PER_SEC )
+
+/** A Fibre Channel link state nonitor */
+struct fc_link_state {
+	/** Retry timer */
+	struct retry_timer timer;
+	/** Link state */
+	int rc;
+	/** Examine link state
+	 *
+	 * @v link		Fibre Channel link state monitor
+	 */
+	void ( * examine ) ( struct fc_link_state *link );
+};
+
+/**
+ * Check Fibre Channel link state
+ *
+ * @v link		Fibre Channel link state monitor
+ * @ret link_up		Link is up
+ */
+static inline __attribute__ (( always_inline )) int
+fc_link_ok ( struct fc_link_state *link ) {
+	return ( link->rc == 0 );
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel packet formats and exchanges
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel Frame Header */
+struct fc_frame_header {
+	/** Routing control
+	 *
+	 * This is the bitwise OR of one @c fc_r_ctl_routing value and
+	 * one @c fc_r_ctl_info value.
+	 */
+	uint8_t r_ctl;
+	/** Destination ID */
+	struct fc_port_id d_id;
+	/** Class-specific control / Priority */
+	uint8_t cs_ctl_prio;
+	/** Source ID */
+	struct fc_port_id s_id;
+	/** Data structure type */
+	uint8_t type;
+	/** Frame control - exchange and sequence */
+	uint8_t f_ctl_es;
+	/** Frame control - acknowledgements  */
+	uint8_t f_ctl_ack;
+	/** Frame control - miscellaneous */
+	uint8_t f_ctl_misc;
+	/** Sequence ID */
+	uint8_t seq_id;
+	/** Data field control */
+	uint8_t df_ctl;
+	/** Sequence count */
+	uint16_t seq_cnt;
+	/** Originator exchange ID */
+	uint16_t ox_id;
+	/** Responder exchange ID */
+	uint16_t rx_id;
+	/** Parameter
+	 *
+	 * Contains the relative offset when @c FC_F_CTL_MISC_REL_OFF
+	 * is set.
+	 */
+	uint32_t parameter;
+} __attribute__ (( packed ));
+
+/** Fibre Channel Routing Control Routing */
+enum fc_r_ctl_routing {
+	FC_R_CTL_DATA = 0x00,		/**< Device Data */
+	FC_R_CTL_ELS = 0x20,		/**< Extended Link Services */
+	FC_R_CTL_FC4_LINK = 0x30,	/**< FC-4 Link Data */
+	FC_R_CTL_VIDEO = 0x40,		/**< Video Data */
+	FC_R_CTL_EH = 0x50,		/**< Extended Headers */
+	FC_R_CTL_BLS = 0x80,		/**< Basic Link Services */
+	FC_R_CTL_LINK_CTRL = 0xc0,	/**< Link Control */
+	FC_R_CTL_EXT_ROUTE = 0xf0,	/**< Extended Routing */
+};
+
+/** Fibre Channel Routing Control Routing mask */
+#define FC_R_CTL_ROUTING_MASK 0xf0
+
+/** Fibre Channel Routing Control Information */
+enum fc_r_ctl_info {
+	FC_R_CTL_UNCAT = 0x00,		/**< Uncategorized */
+	FC_R_CTL_SOL_DATA = 0x01,	/**< Solicited Data */
+	FC_R_CTL_UNSOL_CTRL = 0x02,	/**< Unsolicited Control */
+	FC_R_CTL_SOL_CTRL = 0x03,	/**< Solicited Control */
+	FC_R_CTL_UNSOL_DATA = 0x04,	/**< Unsolicited Data */
+	FC_R_CTL_DATA_DESC = 0x05,	/**< Data Descriptor */
+	FC_R_CTL_UNSOL_CMD = 0x06,	/**< Unsolicited Command */
+	FC_R_CTL_CMD_STAT = 0x07,	/**< Command Status */
+};
+
+/** Fibre Channel Routing Control Information mask */
+#define FC_R_CTL_INFO_MASK 0x07
+
+/** Fibre Channel Data Structure Type */
+enum fc_type {
+	FC_TYPE_BLS = 0x00,		/**< Basic Link Service */
+	FC_TYPE_ELS = 0x01,		/**< Extended Link Service */
+	FC_TYPE_FCP = 0x08,		/**< Fibre Channel Protocol */
+	FC_TYPE_CT  = 0x20,		/**< Common Transport */
+};
+
+/** Fibre Channel Frame Control - Exchange and Sequence */
+enum fc_f_ctl_es {
+	FC_F_CTL_ES_RESPONDER = 0x80,	/**< Responder of Exchange */
+	FC_F_CTL_ES_RECIPIENT = 0x40,	/**< Sequence Recipient */
+	FC_F_CTL_ES_FIRST = 0x20,	/**< First Sequence of Exchange */
+	FC_F_CTL_ES_LAST = 0x10,	/**< Last Sequence of Exchange */
+	FC_F_CTL_ES_END = 0x08,		/**< Last Data Frame of Sequence */
+	FC_F_CTL_ES_TRANSFER = 0x01,	/**< Transfer Sequence Initiative */
+};
+
+/** Fibre Channel Frame Control - Miscellaneous */
+enum fc_f_ctl_misc {
+	FC_F_CTL_MISC_REL_OFF = 0x08,	/**< Relative Offset Present */
+};
+
+/** Responder exchange identifier used before first response */
+#define FC_RX_ID_UNKNOWN 0xffff
+
+struct fc_port;
+
+extern int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
+			       struct fc_port_id *peer_port_id,
+			       unsigned int type );
+
+/** A Fibre Channel responder */
+struct fc_responder {
+	/** Type */
+	unsigned int type;
+	/** Respond to exchange
+	 *
+	 * @v xchg		Exchange interface
+	 * @v port		Fibre Channel port
+	 * @v port_id		Local port ID
+	 * @v peer_port_id	Peer port ID
+	 * @ret rc		Return status code
+	 */
+	int ( * respond ) ( struct interface *xchg, struct fc_port *port,
+			    struct fc_port_id *port_id,
+			    struct fc_port_id *peer_port_id );
+};
+
+/** Fibre Channel responder table */
+#define FC_RESPONDERS __table ( struct fc_responder, "fc_responders" )
+
+/** Declare a Fibre Channel responder */
+#define __fc_responder __table_entry ( FC_RESPONDERS, 01 )
+
+/******************************************************************************
+ *
+ * Fibre Channel ports
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel port */
+struct fc_port {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of all ports */
+	struct list_head list;
+	/** Name of this port */
+	char name[8];
+
+	/** Transport interface */
+	struct interface transport;
+	/** Node name */
+	struct fc_name node_wwn;
+	/** Port name */
+	struct fc_name port_wwn;
+	/** Local port ID */
+	struct fc_port_id port_id;
+	/** Flags */
+	unsigned int flags;
+
+	/** Link state monitor */
+	struct fc_link_state link;
+	/** FLOGI interface */
+	struct interface flogi;
+	/** Link node name */
+	struct fc_name link_node_wwn;
+	/** Link port name */
+	struct fc_name link_port_wwn;
+	/** Link port ID (for point-to-point links only) */
+	struct fc_port_id ptp_link_port_id;
+
+	/** Name server PLOGI interface */
+	struct interface ns_plogi;
+
+	/** List of active exchanges */
+	struct list_head xchgs;
+};
+
+/** Fibre Channel port flags */
+enum fc_port_flags {
+	/** Port is attached to a fabric */
+	FC_PORT_HAS_FABRIC = 0x0001,
+	/** Port is logged in to a name server */
+	FC_PORT_HAS_NS = 0x0002,
+};
+
+/**
+ * Get reference to Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ * @ret port		Fibre Channel port
+ */
+static inline __attribute__ (( always_inline )) struct fc_port *
+fc_port_get ( struct fc_port *port ) {
+	ref_get ( &port->refcnt );
+	return port;
+}
+
+/**
+ * Drop reference to Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ */
+static inline __attribute__ (( always_inline )) void
+fc_port_put ( struct fc_port *port ) {
+	ref_put ( &port->refcnt );
+}
+
+extern struct list_head fc_ports;
+
+extern int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
+			   const struct fc_name *link_node_wwn,
+			   const struct fc_name *link_port_wwn,
+			   int has_fabric );
+extern void fc_port_logout ( struct fc_port *port, int rc );
+extern int fc_port_open ( struct interface *transport,
+			  const struct fc_name *node_wwn,
+			  const struct fc_name *port_wwn,
+			  const char *name );
+extern struct fc_port * fc_port_find ( const char *name );
+
+/******************************************************************************
+ *
+ * Fibre Channel peers
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel peer */
+struct fc_peer {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of all peers */
+	struct list_head list;
+
+	/** Port name */
+	struct fc_name port_wwn;
+
+	/** Link state monitor */
+	struct fc_link_state link;
+	/** PLOGI interface */
+	struct interface plogi;
+	/** Fibre Channel port, if known */
+	struct fc_port *port;
+	/** Peer port ID, if known */
+	struct fc_port_id port_id;
+
+	/** List of upper-layer protocols */
+	struct list_head ulps;
+	/** Active usage count */
+	unsigned int usage;
+};
+
+/**
+ * Get reference to Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ * @ret peer		Fibre Channel peer
+ */
+static inline __attribute__ (( always_inline )) struct fc_peer *
+fc_peer_get ( struct fc_peer *peer ) {
+	ref_get ( &peer->refcnt );
+	return peer;
+}
+
+/**
+ * Drop reference to Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ */
+static inline __attribute__ (( always_inline )) void
+fc_peer_put ( struct fc_peer *peer ) {
+	ref_put ( &peer->refcnt );
+}
+
+extern struct list_head fc_peers;
+
+extern struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn );
+extern struct fc_peer *
+fc_peer_get_port_id ( struct fc_port *port,
+		      const struct fc_port_id *peer_port_id );
+extern int fc_peer_login ( struct fc_peer *peer,
+			   struct fc_port *port,
+			   struct fc_port_id *port_id );
+extern void fc_peer_logout ( struct fc_peer *peer, int rc );
+
+/******************************************************************************
+ *
+ * Fibre Channel upper-layer protocols
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel upper-layer protocol */
+struct fc_ulp {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Fibre Channel peer */
+	struct fc_peer *peer;
+	/** List of upper-layer protocols */
+	struct list_head list;
+
+	/** Type */
+	unsigned int type;
+	/** Flags */
+	unsigned int flags;
+
+	/** Link state monitor */
+	struct fc_link_state link;
+	/** PRLI interface */
+	struct interface prli;
+	/** Service parameters, if any */
+	void *param;
+	/** Service parameter length */
+	size_t param_len;
+
+	/** Active usage count */
+	unsigned int usage;
+};
+
+/** Fibre Channel upper-layer protocol flags */
+enum fc_ulp_flags {
+	/** A login originated by us has succeeded */
+	FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
+};
+
+/**
+ * Get reference to Fibre Channel upper-layer protocol
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @ret ulp		Fibre Channel upper-layer protocol
+ */
+static inline __attribute__ (( always_inline )) struct fc_ulp *
+fc_ulp_get ( struct fc_ulp *ulp ) {
+	ref_get ( &ulp->refcnt );
+	return ulp;
+}
+
+/**
+ * Drop reference to Fibre Channel upper-layer protocol
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_put ( struct fc_ulp *ulp ) {
+	ref_put ( &ulp->refcnt );
+}
+
+extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
+					     unsigned int type );
+extern struct fc_ulp *
+fc_ulp_get_port_id_type ( struct fc_port *port,
+			  const struct fc_port_id *peer_port_id,
+			  unsigned int type );
+extern void fc_ulp_increment ( struct fc_ulp *ulp );
+extern void fc_ulp_decrement ( struct fc_ulp *ulp );
+extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param,
+			  size_t param_len, int originated );
+extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc );
+
+#endif /* _IPXE_FC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcels.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcels.h
new file mode 100644
index 0000000..45fa69a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcels.h
@@ -0,0 +1,445 @@
+#ifndef _IPXE_FCELS_H
+#define _IPXE_FCELS_H
+
+/**
+ * @file
+ *
+ * Fibre Channel Extended Link Services
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+#include <ipxe/tables.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+#include <ipxe/interface.h>
+
+/** Fibre Channel ELS frame common parameters */
+struct fc_els_frame_common {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Fibre Channel ELS command codes */
+enum fc_els_command_code {
+	FC_ELS_LS_RJT = 0x01,		/**< Link Service Reject */
+	FC_ELS_LS_ACC = 0x02,		/**< Link Service Accept */
+	FC_ELS_PLOGI = 0x03,		/**< Port Login */
+	FC_ELS_FLOGI = 0x04,		/**< Fabric Login */
+	FC_ELS_LOGO = 0x05,		/**< Logout */
+	FC_ELS_RTV = 0x0e,		/**< Read Timeout Value */
+	FC_ELS_ECHO = 0x10,		/**< Echo */
+	FC_ELS_PRLI = 0x20,		/**< Process Login */
+	FC_ELS_PRLO = 0x21,		/**< Process Logout */
+};
+
+/** A Fibre Channel LS_RJT frame */
+struct fc_ls_rjt_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[4];
+	/** Reason code */
+	uint8_t reason;
+	/** Reason code explanation */
+	uint8_t explanation;
+	/** Vendor unique */
+	uint8_t vendor;
+} __attribute__ (( packed ));
+
+/** Fibre Channel ELS rejection reason codes */
+enum fc_els_reject_reason {
+	/** Invalid ELS command code */
+	FC_ELS_RJT_INVALID_COMMAND = 0x01,
+	/** Logical error */
+	FC_ELS_RJT_ILLOGICAL = 0x03,
+	/** Logical busy */
+	FC_ELS_RJT_BUSY = 0x05,
+	/** Protocol error */
+	FC_ELS_RJT_PROTOCOL = 0x07,
+	/** Unable to perform command request */
+	FC_ELS_RJT_UNABLE = 0x09,
+	/** Command not supported */
+	FC_ELS_RJT_UNSUPPORTED = 0x0b,
+	/** Command already in progress */
+	FC_ELS_RJT_IN_PROGRESS = 0x0e,
+};
+
+/** Fibre Channel "common" service parameters */
+struct fc_login_common {
+	/** Login version */
+	uint16_t version;
+	/** Buffer-to-buffer credit */
+	uint16_t credit;
+	/** Flags */
+	uint16_t flags;
+	/** Receive size */
+	uint16_t mtu;
+	/** "Common"?! */
+	union {
+		struct {
+			/** Maximum number of concurrent sequences */
+			uint16_t max_seq;
+			/** Relative offset by info category */
+			uint16_t rel_offs;
+		} plogi;
+		struct {
+			/** Resource allocation timeout value */
+			uint32_t r_a_tov;
+		} flogi;
+	} u;
+	/** Error detection timeout value */
+	uint32_t e_d_tov;
+} __attribute__ (( packed ));
+
+/** Fibre Channel default login version */
+#define FC_LOGIN_VERSION 0x2020
+
+/** Fibre Channel default buffer-to-buffer credit */
+#define FC_LOGIN_DEFAULT_B2B 10
+
+/** Continuously increasing relative offset */
+#define FC_LOGIN_CONTINUOUS_OFFSET 0x8000
+
+/** Clean address */
+#define FC_LOGIN_CLEAN 0x8000
+
+/** Multiple N_Port_ID support */
+#define FC_LOGIN_MULTI_N 0x8000
+
+/** Random relative offset */
+#define FC_LOGIN_RANDOM_OFFSET 0x4000
+
+/** Virtual fabrics */
+#define FC_LOGIN_VIRTUAL 0x4000
+
+/** Vendor version level */
+#define FC_LOGIN_VENDOR 0x2000
+
+/** Multiple N_Port_ID support */
+#define FC_LOGIN_MULTI_F 0x2000
+
+/** Forwarder port */
+#define FC_LOGIN_F_PORT 0x1000
+
+/** Alternative credit management */
+#define FC_LOGIN_ALT_CREDIT 0x0800
+
+/** Name server session started */
+#define FC_LOGIN_NSS_STARTED 0x0800
+
+/** Begin name server session */
+#define FC_LOGIN_NSS_BEGIN 0x0400
+
+/** 1ns error detection timer resolution */
+#define FC_LOGIN_HIRES_E_D_TOV 0x0400
+
+/** Broadcast supported */
+#define FC_LOGIN_BROADCAST 0x0100
+
+/** Query buffer conditions */
+#define FC_LOGIN_QUERY_BUF 0x0040
+
+/** Security */
+#define FC_LOGIN_SECURITY 0x0020
+
+/** Clock sync primitive capable */
+#define FC_LOGIN_CLOCK_SYNC 0x0010
+
+/** Short R_T timeout */
+#define FC_LOGIN_SHORT_R_T_TOV 0x0008
+
+/** Dynamic half duplex */
+#define FC_LOGIN_DHD 0x0004
+
+/** Continuously increasing sequence count */
+#define FC_LOGIN_CONTINUOUS_SEQ 0x0002
+
+/** Payload */
+#define FC_LOGIN_PAYLOAD 0x0001
+
+/** Fibre Channel default MTU */
+#define FC_LOGIN_DEFAULT_MTU 1452
+
+/** Default maximum number of concurrent sequences */
+#define FC_LOGIN_DEFAULT_MAX_SEQ 255
+
+/** Default relative offset by info category */
+#define FC_LOGIN_DEFAULT_REL_OFFS 0x1f
+
+/** Default E_D timeout value */
+#define FC_LOGIN_DEFAULT_E_D_TOV 2000
+
+/** Fibre Channel class-specific login parameters */
+struct fc_login_class {
+	/** Flags */
+	uint16_t flags;
+	/** Initiator flags */
+	uint16_t init_flags;
+	/** Recipient flags */
+	uint16_t recip_flags;
+	/** Receive data field size */
+	uint16_t mtu;
+	/** Maximum number of concurrent sequences */
+	uint16_t max_seq;
+	/** End-to-end credit */
+	uint16_t credit;
+	/** Reserved */
+	uint8_t reserved0;
+	/** Maximum number of open sequences per exchange */
+	uint8_t max_seq_per_xchg;
+	/** Reserved */
+	uint8_t reserved1[2];
+} __attribute__ (( packed ));
+
+/** Class valid */
+#define FC_LOGIN_CLASS_VALID 0x8000
+
+/** Sequential delivery requested */
+#define FC_LOGIN_CLASS_SEQUENTIAL 0x0800
+
+/** A Fibre Channel FLOGI/PLOGI frame */
+struct fc_login_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[3];
+	/** Common service parameters */
+	struct fc_login_common common;
+	/** Port name */
+	struct fc_name port_wwn;
+	/** Node name */
+	struct fc_name node_wwn;
+	/** Class 1 service parameters */
+	struct fc_login_class class1;
+	/** Class 2 service parameters */
+	struct fc_login_class class2;
+	/** Class 3 service parameters */
+	struct fc_login_class class3;
+	/** Class 4 service parameters */
+	struct fc_login_class class4;
+	/** Vendor version level */
+	uint8_t vendor_version[16];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel LOGO request frame */
+struct fc_logout_request_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[4];
+	/** Port ID */
+	struct fc_port_id port_id;
+	/** Port name */
+	struct fc_name port_wwn;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel LOGO response frame */
+struct fc_logout_response_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel PRLI service parameter page */
+struct fc_prli_page {
+	/** Type code */
+	uint8_t type;
+	/** Type code extension */
+	uint8_t type_ext;
+	/** Flags and response code */
+	uint16_t flags;
+	/** Reserved */
+	uint32_t reserved[2];
+} __attribute__ (( packed ));
+
+/** Establish image pair */
+#define FC_PRLI_ESTABLISH 0x2000
+
+/** Response code mask */
+#define FC_PRLI_RESPONSE_MASK 0x0f00
+
+/** Request was executed successfully */
+#define FC_PRLI_RESPONSE_SUCCESS 0x0100
+
+/** A Fibre Channel PRLI frame */
+struct fc_prli_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Page length */
+	uint8_t page_len;
+	/** Payload length */
+	uint16_t len;
+	/** Service parameter page */
+	struct fc_prli_page page;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel RTV request frame */
+struct fc_rtv_request_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel RTV response frame */
+struct fc_rtv_response_frame {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved0[3];
+	/** Resource allocation timeout value */
+	uint32_t r_a_tov;
+	/** Error detection timeout value */
+	uint32_t e_d_tov;
+	/** Timeout qualifier */
+	uint16_t flags;
+	/** Reserved */
+	uint16_t reserved1;
+} __attribute__ (( packed ));
+
+/** 1ns error detection timer resolution */
+#define FC_RTV_HIRES_E_D_TOV 0x0400
+
+/** Short R_T timeout */
+#define FC_RTV_SHORT_R_T_TOV 0x0008
+
+/** A Fibre Channel ECHO frame */
+struct fc_echo_frame_header {
+	/** ELS command code */
+	uint8_t command;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** A Fibre Channel extended link services transaction */
+struct fc_els {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Job control interface */
+	struct interface job;
+	/** Fibre Channel exchange */
+	struct interface xchg;
+	/** Request sending process */
+	struct process process;
+
+	/** Fibre Channel port */
+	struct fc_port *port;
+	/** Local port ID */
+	struct fc_port_id port_id;
+	/** Peer port ID */
+	struct fc_port_id peer_port_id;
+	/** ELS handler, if known */
+	struct fc_els_handler *handler;
+	/** Flags */
+	unsigned int flags;
+};
+
+/** Fibre Channel extended link services transaction flags */
+enum fc_els_flags {
+	/** ELS transaction is a request */
+	FC_ELS_REQUEST = 0x0001,
+};
+
+/** A Fibre Channel extended link services handler */
+struct fc_els_handler {
+	/** Name */
+	const char *name;
+	/** Transmit ELS frame
+	 *
+	 * @v els		Fibre Channel ELS transaction
+	 * @ret rc		Return status code
+	 */
+	int ( * tx ) ( struct fc_els *els );
+	/** Receive ELS frame
+	 *
+	 * @v els		Fibre Channel ELS transaction
+	 * @v data		ELS frame
+	 * @v len		Length of ELS frame
+	 * @ret rc		Return status code
+	 */
+	int ( * rx ) ( struct fc_els *els, void *data, size_t len );
+	/** Detect ELS frame
+	 *
+	 * @v els		Fibre Channel ELS transaction
+	 * @v data		ELS frame
+	 * @v len		Length of ELS frame
+	 * @ret rc		Return status code
+	 */
+	int ( * detect ) ( struct fc_els *els, const void *data, size_t len );
+};
+
+/** Fibre Channel ELS handler table */
+#define FC_ELS_HANDLERS __table ( struct fc_els_handler, "fc_els_handlers" )
+
+/** Declare a Fibre Channel ELS handler */
+#define __fc_els_handler __table_entry ( FC_ELS_HANDLERS, 01 )
+
+/** A Fibre Channel ELS PRLI descriptor */
+struct fc_els_prli_descriptor {
+	/** Upper-layer protocol type */
+	unsigned int type;
+	/** Service parameter length */
+	size_t param_len;
+	/** Fibre Channel ELS handler */
+	struct fc_els_handler *handler;
+};
+
+/** Fibre Channel ELS PRLI descriptor table */
+#define FC_ELS_PRLI_DESCRIPTORS \
+	__table ( struct fc_els_prli_descriptor, "fc_els_prli_descriptors" )
+
+/** Declare a Fibre Channel ELS PRLI descriptor */
+#define __fc_els_prli_descriptor __table_entry ( FC_ELS_PRLI_DESCRIPTORS, 01 )
+
+/**
+ * Check if Fibre Channel ELS transaction is a request
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret is_request	ELS transaction is a request
+ */
+static inline int fc_els_is_request ( struct fc_els *els ) {
+	return ( els->flags & FC_ELS_REQUEST );
+}
+
+/**
+ * Calculate ELS command to transmit
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v request_command	Command for requests
+ * @v command		Command to transmit
+ */
+static inline unsigned int fc_els_tx_command ( struct fc_els *els,
+					       unsigned int request_command ) {
+	return ( fc_els_is_request ( els ) ? request_command : FC_ELS_LS_ACC );
+}
+
+extern int fc_els_tx ( struct fc_els *els, const void *data, size_t len );
+extern int fc_els_request ( struct interface *job, struct fc_port *port,
+			    struct fc_port_id *peer_port_id,
+			    struct fc_els_handler *handler );
+extern int fc_els_flogi ( struct interface *parent, struct fc_port *port );
+extern int fc_els_plogi ( struct interface *parent, struct fc_port *port,
+			  struct fc_port_id *peer_port_id );
+extern int fc_els_logo ( struct interface *parent, struct fc_port *port,
+			 struct fc_port_id *peer_port_id );
+extern int fc_els_prli ( struct interface *parent, struct fc_port *port,
+			 struct fc_port_id *peer_port_id, unsigned int type );
+extern int fc_els_prli_tx ( struct fc_els *els,
+			    struct fc_els_prli_descriptor *descriptor,
+			    void *param );
+extern int fc_els_prli_rx ( struct fc_els *els,
+			    struct fc_els_prli_descriptor *descriptor,
+			    void *data, size_t len );
+extern int fc_els_prli_detect ( struct fc_els *els __unused,
+				struct fc_els_prli_descriptor *descriptor,
+				const void *data, size_t len );
+
+#endif /* _IPXE_FCELS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcns.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcns.h
new file mode 100644
index 0000000..e25d9b9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcns.h
@@ -0,0 +1,217 @@
+#ifndef _IPXE_FCNS_H
+#define _IPXE_FCNS_H
+
+/**
+ * @file
+ *
+ * Fibre Channel name server lookups
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+
+/** A Fibre Channel Common Transport header */
+struct fc_ct_header {
+	/** Revision */
+	uint8_t revision;
+	/** Original requestor ID */
+	struct fc_port_id in_id;
+	/** Generic service type */
+	uint8_t type;
+	/** Generic service subtype */
+	uint8_t subtype;
+	/** Options */
+	uint8_t options;
+	/** Reserved */
+	uint8_t reserved;
+	/** Command/response code */
+	uint16_t code;
+	/** Maximum/residual size */
+	uint16_t size;
+	/** Fragment ID */
+	uint8_t fragment;
+	/** Reason code */
+	uint8_t reason;
+	/** Reason code explanation */
+	uint8_t explanation;
+	/** Vendor specific */
+	uint8_t vendor;
+} __attribute__ (( packed ));
+
+/** Fibre Channel Common Transport revision */
+#define FC_CT_REVISION 1
+
+/** Fibre Channel generic service type */
+enum fc_gs_type {
+	/** Directory service */
+	FC_GS_TYPE_DS = 0xfc,
+};
+
+/** Fibre Channel generic service response codes */
+enum fc_gs_response_code {
+	/** Accepted */
+	FC_GS_ACCEPT = 0x8002,
+	/** Rejected */
+	FC_GS_REJECT = 0x8001,
+};
+
+/** Fibre Channel generic service rejection reason codes */
+enum fc_gs_reason_code {
+	/** Invalid command code */
+	FC_GS_BAD_COMMAND = 0x01,
+	/** Invalid version level */
+	FC_GS_BAD_VERSION = 0x02,
+	/** Logical error */
+	FC_GS_ERROR = 0x03,
+	/** Invalid CT_IU size */
+	FC_GS_BAD_SIZE = 0x04,
+	/** Logical busy */
+	FC_GS_BUSY = 0x05,
+	/** Protocol error */
+	FC_GS_EPROTO = 0x07,
+	/** Unable to perform command request */
+	FC_GS_UNABLE = 0x09,
+	/** Command not supported */
+	FC_GS_ENOTSUP = 0x0b,
+	/** Server not available */
+	FC_GS_UNAVAILABLE = 0x0d,
+	/** Session could not be established */
+	FC_GS_SESSION = 0x0e,
+};
+
+/** Fibre Channel directory service subtype */
+enum fc_ds_subtype {
+	/** Name server */
+	FC_DS_SUBTYPE_NAME = 0x02,
+};
+
+/** Fibre Channel name server commands */
+enum fc_ns_command_nibble {
+	/** Get */
+	FC_NS_GET = 0x1,
+	/** Register */
+	FC_NS_REGISTER = 0x2,
+	/** De-register */
+	FC_NS_DEREGISTER = 0x3,
+};
+
+/** Fibre Channel name server objects */
+enum fc_ns_object_nibble {
+	/** Port ID */
+	FC_NS_PORT_ID = 0x1,
+	/** Port name */
+	FC_NS_PORT_NAME = 0x2,
+	/** Node name */
+	FC_NS_NODE_NAME = 0x3,
+	/** FC-4 types */
+	FC_NS_FC4_TYPES = 0x7,
+	/** Symbolic port name */
+	FC_NS_SYM_PORT_NAME = 0x8,
+	/** Symbolic node name */
+	FC_NS_SYM_NODE_NAME = 0x9,
+	/** FC-4 features */
+	FC_NS_FC4_FEATURES = 0xf,
+};
+
+/** Construct Fibre Channel name server command code
+ *
+ * @v command		Name server command
+ * @v key		Name server key
+ * @v value		Name server value
+ * @ret code		Name server command code
+ */
+#define FC_NS_CODE( command, key, value )				\
+	( ( (command) << 8 ) | ( (key) << 4 ) | ( (value) << 0 ) )
+
+/** Construct Fibre Channel name server "get" command code
+ *
+ * @v key		Name server key
+ * @v value		Name server value to get
+ * @ret code		Name server command code
+ */
+#define FC_NS_GET( key, value ) FC_NS_CODE ( FC_NS_GET, key, value )
+
+/** Construct Fibre Channel name server "register" command code
+ *
+ * @v key		Name server key
+ * @v value		Name server value to register
+ * @ret code		Name server command code
+ */
+#define FC_NS_REGISTER( key, value ) FC_NS_CODE ( FC_NS_REGISTER, key, value )
+
+/** Extract Fibre Channel name server command
+ *
+ * @v code		Name server command code
+ * @ret command		Name server command
+ */
+#define FC_NS_COMMAND( code ) ( ( (code) >> 8 ) & 0xf )
+
+/** Extract Fibre Channel name server key
+ *
+ * @v code		Name server command code
+ * @ret key		Name server key
+ */
+#define FC_NS_KEY( code ) ( ( (code) >> 4 ) & 0xf )
+
+/** Extract Fibre Channel name server value
+ *
+ * @v code		Name server command code
+ * @ret value		NAme server value
+ */
+#define FC_NS_VALUE( code ) ( ( (code) >> 0 ) & 0xf )
+
+/** A Fibre Channel name server port ID */
+struct fc_ns_port_id {
+	/** Reserved */
+	uint8_t reserved;
+	/** Port ID */
+	struct fc_port_id port_id;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel name server GID_PN request */
+struct fc_ns_gid_pn_request {
+	/** Common Transport header */
+	struct fc_ct_header ct;
+	/** Port name */
+	struct fc_name port_wwn;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel name server request */
+union fc_ns_request {
+	/** Get ID by port name */
+	struct fc_ns_gid_pn_request gid_pn;
+};
+
+/** A Fibre Channel name server rejection response */
+struct fc_ns_reject_response {
+	/** Common Transport header */
+	struct fc_ct_header ct;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel name server GID_PN response */
+struct fc_ns_gid_pn_response {
+	/** Common Transport header */
+	struct fc_ct_header ct;
+	/** Port ID */
+	struct fc_ns_port_id port_id;
+} __attribute__ (( packed ));
+
+/** A Fibre Channel name server response */
+union fc_ns_response {
+	/** Common Transport header */
+	struct fc_ct_header ct;
+	/** Rejection */
+	struct fc_ns_reject_response reject;
+	/** Get ID by port name */
+	struct fc_ns_gid_pn_response gid_pn;
+};
+
+extern int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
+			 int ( * done ) ( struct fc_peer *peer,
+					  struct fc_port *port,
+					  struct fc_port_id *peer_port_id ) );
+
+#endif /* _IPXE_FCNS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcoe.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcoe.h
new file mode 100644
index 0000000..6ba5b40
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcoe.h
@@ -0,0 +1,92 @@
+#ifndef _IPXE_FCOE_H
+#define _IPXE_FCOE_H
+
+/**
+ * @file
+ *
+ * Fibre Channel over Ethernet
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+#include <ipxe/if_ether.h>
+
+/** An FCoE name */
+union fcoe_name {
+	/** Fibre Channel name */
+	struct fc_name fc;
+	/** FCoE name */
+	struct {
+		/** Naming authority */
+		uint16_t authority;
+		/** MAC address */
+		uint8_t mac[ETH_ALEN];
+	} __attribute__ (( packed )) fcoe;
+};
+
+/** IEEE 48-bit address */
+#define FCOE_AUTHORITY_IEEE 0x1000
+
+/** IEEE extended */
+#define FCOE_AUTHORITY_IEEE_EXTENDED 0x2000
+
+/** An FCoE MAC address prefix (FC-MAP) */
+struct fcoe_map {
+	uint8_t bytes[3];
+} __attribute__ (( packed ));
+
+/** An FCoE (fabric-assigned) MAC address */
+struct fcoe_mac {
+	/** MAC address prefix */
+	struct fcoe_map map;
+	/** Port ID */
+	struct fc_port_id port_id;
+} __attribute__ (( packed ));
+
+/** An FCoE header */
+struct fcoe_header {
+	/** FCoE frame version */
+	uint8_t version;
+	/** Reserved */
+	uint8_t reserved[12];
+	/** Start of Frame marker */
+	uint8_t sof;
+} __attribute__ (( packed ));
+
+/** FCoE frame version */
+#define FCOE_FRAME_VER 0x00
+
+/** Start of Frame marker values */
+enum fcoe_sof {
+	FCOE_SOF_F = 0x28,	/**< Start of Frame Class F */
+	FCOE_SOF_I2 = 0x2d,	/**< Start of Frame Initiate Class 2 */
+	FCOE_SOF_N2 = 0x35,	/**< Start of Frame Normal Class 2 */
+	FCOE_SOF_I3 = 0x2e,	/**< Start of Frame Initiate Class 3 */
+	FCOE_SOF_N3 = 0x36,	/**< Start of Frame Normal Class 3 */
+};
+
+/** An FCoE footer */
+struct fcoe_footer {
+	/** CRC */
+	uint32_t crc;
+	/** End of frame marker */
+	uint8_t eof;
+	/** Reserved */
+	uint8_t reserved[3];
+} __attribute__ (( packed ));
+
+/** End of Frame marker value */
+enum fcoe_eof {
+	FCOE_EOF_N = 0x41,	/**< End of Frame Normal */
+	FCOE_EOF_T = 0x42,	/**< End of Frame Terminate */
+	FCOE_EOF_NI = 0x49,	/**< End of Frame Invalid */
+	FCOE_EOF_A = 0x50,	/**< End of Frame Abort */
+};
+
+/** FCoE VLAN priority */
+#define FCOE_VLAN_PRIORITY 3
+
+#endif /* _IPXE_FCOE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcp.h
new file mode 100644
index 0000000..f6922bc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fcp.h
@@ -0,0 +1,166 @@
+#ifndef _IPXE_FCP_H
+#define _IPXE_FCP_H
+
+/**
+ * @file
+ *
+ * Fibre Channel Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/scsi.h>
+
+/** An FCP command IU */
+struct fcp_cmnd {
+	/** SCSI LUN */
+	struct scsi_lun lun;
+	/** Command reference number */
+	uint8_t ref;
+	/** Priority and task attributes */
+	uint8_t priority;
+	/** Task management flags */
+	uint8_t flags;
+	/** Direction */
+	uint8_t dirn;
+	/** SCSI CDB */
+	union scsi_cdb cdb;
+	/** Data length */
+	uint32_t len;
+} __attribute__ (( packed ));
+
+/** Command includes data-out */
+#define FCP_CMND_WRDATA 0x01
+
+/** Command includes data-in */
+#define FCP_CMND_RDDATA 0x02
+
+/** FCP tag magic marker */
+#define FCP_TAG_MAGIC 0x18ae0000
+
+/** An FCP transfer ready IU */
+struct fcp_xfer_rdy {
+	/** Relative offset of data */
+	uint32_t offset;
+	/** Burst length */
+	uint32_t len;
+	/** Reserved */
+	uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** An FCP response IU */
+struct fcp_rsp {
+	/** Reserved */
+	uint8_t reserved[8];
+	/** Retry delay timer */
+	uint16_t retry_delay;
+	/** Flags */
+	uint8_t flags;
+	/** SCSI status code */
+	uint8_t status;
+	/** Residual data count */
+	uint32_t residual;
+	/** Sense data length */
+	uint32_t sense_len;
+	/** Response data length */
+	uint32_t response_len;
+} __attribute__ (( packed ));
+
+/** Response length field is valid */
+#define FCP_RSP_RESPONSE_LEN_VALID 0x01
+
+/** Sense length field is valid */
+#define FCP_RSP_SENSE_LEN_VALID 0x02
+
+/** Residual represents overrun */
+#define FCP_RSP_RESIDUAL_OVERRUN 0x04
+
+/** Residual represents underrun */
+#define FCP_RSP_RESIDUAL_UNDERRUN 0x08
+
+/**
+ * Get response data portion of FCP response
+ *
+ * @v rsp			FCP response
+ * @ret response_data		Response data, or NULL if not present
+ */
+static inline void * fcp_rsp_response_data ( struct fcp_rsp *rsp ) {
+	return ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ?
+		 ( ( ( void * ) rsp ) + sizeof ( *rsp ) ) : NULL );
+}
+
+/**
+ * Get length of response data portion of FCP response
+ *
+ * @v rsp			FCP response
+ * @ret response_data_len	Response data length
+ */
+static inline size_t fcp_rsp_response_data_len ( struct fcp_rsp *rsp ) {
+	return ( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ?
+		 ntohl ( rsp->response_len ) : 0 );
+}
+
+/**
+ * Get sense data portion of FCP response
+ *
+ * @v rsp			FCP response
+ * @ret sense_data		Sense data, or NULL if not present
+ */
+static inline void * fcp_rsp_sense_data ( struct fcp_rsp *rsp ) {
+	return ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ?
+		 ( ( ( void * ) rsp ) + sizeof ( *rsp ) +
+		   fcp_rsp_response_data_len ( rsp ) ) : NULL );
+}
+
+/**
+ * Get length of sense data portion of FCP response
+ *
+ * @v rsp			FCP response
+ * @ret sense_data_len		Sense data length
+ */
+static inline size_t fcp_rsp_sense_data_len ( struct fcp_rsp *rsp ) {
+	return ( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ?
+		 ntohl ( rsp->sense_len ) : 0 );
+}
+
+/** An FCP PRLI service parameter page */
+struct fcp_prli_service_parameters {
+	/** Flags */
+	uint32_t flags;
+} __attribute__ (( packed ));
+
+/** Write FCP_XFER_RDY disabled */
+#define FCP_PRLI_NO_WRITE_RDY 0x0001
+
+/** Read FCP_XFER_RDY disabled */
+#define FCP_PRLI_NO_READ_RDY 0x0002
+
+/** Has target functionality */
+#define FCP_PRLI_TARGET 0x0010
+
+/** Has initiator functionality */
+#define FCP_PRLI_INITIATOR 0x0020
+
+/** Data overlay allowed */
+#define FCP_PRLI_OVERLAY 0x0040
+
+/** Confirm completion allowed */
+#define FCP_PRLI_CONF 0x0080
+
+/** Retransmission supported */
+#define FCP_PRLI_RETRY 0x0100
+
+/** Task retry identification */
+#define FCP_PRLI_TASK_RETRY 0x0200
+
+/** REC ELS supported */
+#define FCP_PRLI_REC 0x0400
+
+/** Enhanced discovery supported */
+#define FCP_PRLI_ENH_DISC 0x0800
+
+#endif /* _IPXE_FCP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/features.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/features.h
new file mode 100644
index 0000000..660015c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/features.h
@@ -0,0 +1,105 @@
+#ifndef _IPXE_FEATURES_H
+#define _IPXE_FEATURES_H
+
+#include <stdint.h>
+#include <ipxe/tables.h>
+#include <ipxe/dhcp.h>
+
+/** @file
+ *
+ * Feature list
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @defgroup featurecat Feature categories
+ * @{
+ */
+
+#define FEATURE_PROTOCOL		01 /**< Network protocols */
+#define FEATURE_IMAGE			02 /**< Image formats */
+#define FEATURE_MISC			03 /**< Miscellaneous */
+
+/** @} */
+
+/**
+ * @defgroup dhcpfeatures DHCP feature option tags
+ *
+ * DHCP feature option tags are Etherboot encapsulated options in the
+ * range 0x10-0x7f.
+ *
+ * @{
+ */
+
+#define DHCP_EB_FEATURE_PXE_EXT		0x10 /**< PXE API extensions */
+#define DHCP_EB_FEATURE_ISCSI		0x11 /**< iSCSI protocol */
+#define DHCP_EB_FEATURE_AOE		0x12 /**< AoE protocol */
+#define DHCP_EB_FEATURE_HTTP		0x13 /**< HTTP protocol */
+#define DHCP_EB_FEATURE_HTTPS		0x14 /**< HTTPS protocol */
+#define DHCP_EB_FEATURE_TFTP		0x15 /**< TFTP protocol */
+#define DHCP_EB_FEATURE_FTP		0x16 /**< FTP protocol */
+#define DHCP_EB_FEATURE_DNS		0x17 /**< DNS protocol */
+#define DHCP_EB_FEATURE_BZIMAGE		0x18 /**< bzImage format */
+#define DHCP_EB_FEATURE_MULTIBOOT	0x19 /**< Multiboot format */
+#define DHCP_EB_FEATURE_SLAM		0x1a /**< SLAM protocol */
+#define DHCP_EB_FEATURE_SRP		0x1b /**< SRP protocol */
+#define DHCP_EB_FEATURE_NBI		0x20 /**< NBI format */
+#define DHCP_EB_FEATURE_PXE		0x21 /**< PXE format */
+#define DHCP_EB_FEATURE_ELF		0x22 /**< ELF format */
+#define DHCP_EB_FEATURE_COMBOOT		0x23 /**< COMBOOT format */
+#define DHCP_EB_FEATURE_EFI		0x24 /**< EFI format */
+#define DHCP_EB_FEATURE_FCOE		0x25 /**< FCoE protocol */
+#define DHCP_EB_FEATURE_VLAN		0x26 /**< VLAN support */
+
+/** @} */
+
+/** DHCP feature table */
+#define DHCP_FEATURES __table ( uint8_t, "dhcp_features" )
+
+/** Declare a feature code for DHCP */
+#define __dhcp_feature __table_entry ( DHCP_FEATURES, 01 )
+
+/** Construct a DHCP feature table entry */
+#define DHCP_FEATURE( feature_opt, ... )				    \
+	_DHCP_FEATURE ( OBJECT, feature_opt, __VA_ARGS__ )
+#define _DHCP_FEATURE( _name, feature_opt, ... )			    \
+	__DHCP_FEATURE ( _name, feature_opt, __VA_ARGS__ )
+#define __DHCP_FEATURE( _name, feature_opt, ... )			    \
+	uint8_t __dhcp_feature_ ## _name [] __dhcp_feature = {		    \
+		feature_opt, DHCP_OPTION ( __VA_ARGS__ )		    \
+	};
+
+/** A named feature */
+struct feature {
+	/** Feature name */
+	char *name;
+};
+
+/** Named feature table */
+#define FEATURES __table ( struct feature, "features" )
+
+/** Declare a named feature */
+#define __feature_name( category ) __table_entry ( FEATURES, category )
+
+/** Construct a named feature */
+#define FEATURE_NAME( category, text )					    \
+	_FEATURE_NAME ( category, OBJECT, text )
+#define _FEATURE_NAME( category, _name, text )				    \
+	__FEATURE_NAME ( category, _name, text )
+#define __FEATURE_NAME( category, _name, text )				    \
+	struct feature __feature_ ## _name __feature_name ( category ) = {  \
+		.name = text,						    \
+	};
+
+/** Declare a feature */
+#define FEATURE( category, text, feature_opt, version )			    \
+	FEATURE_NAME ( category, text );				    \
+	DHCP_FEATURE ( feature_opt, version );
+
+/** Declare the version number feature */
+#define FEATURE_VERSION( ... )						    \
+	DHCP_FEATURE ( DHCP_ENCAPSULATED ( DHCP_EB_VERSION ), __VA_ARGS__ )
+
+#endif /* _IPXE_FEATURES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/fip.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fip.h
new file mode 100644
index 0000000..b81e860
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/fip.h
@@ -0,0 +1,450 @@
+#ifndef _IPXE_FIP_H
+#define _IPXE_FIP_H
+
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/fcoe.h>
+
+/** A FIP frame header */
+struct fip_header {
+	/** Frame version */
+	uint8_t version;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** Protocol code */
+	uint16_t code;
+	/** Reserved */
+	uint8_t reserved_b;
+	/** Subcode */
+	uint8_t subcode;
+	/** Descriptor list length in 32-bit words */
+	uint16_t len;
+	/** Flags */
+	uint16_t flags;
+} __attribute__ (( packed ));
+
+/** FIP frame version */
+#define FIP_VERSION 0x10
+
+/** FIP protocol code */
+enum fip_code {
+	FIP_CODE_DISCOVERY = 0x0001,	/**< Discovery */
+	FIP_CODE_ELS = 0x0002,		/**< Extended link services */
+	FIP_CODE_MAINTAIN = 0x0003,	/**< Maintain virtual links */
+	FIP_CODE_VLAN = 0x0004,		/**< VLAN */
+};
+
+/** FIP protocol subcode for discovery */
+enum fip_discovery_subcode {
+	FIP_DISCOVERY_SOLICIT = 0x01,	/**< Discovery solicitation */
+	FIP_DISCOVERY_ADVERTISE = 0x02,	/**< Discovery advertisement */
+};
+
+/** FIP protocol subcode for extended link services */
+enum fip_els_subcode {
+	FIP_ELS_REQUEST = 0x01,		/**< ELS request */
+	FIP_ELS_RESPONSE = 0x02,	/**< ELS response */
+};
+
+/** FIP protocol subcode for keep alive / clear links */
+enum fip_vitality_subcode {
+	FIP_MAINTAIN_KEEP_ALIVE = 0x01,	/**< Keep alive */
+	FIP_MAINTAIN_CLEAR_LINKS = 0x02,/**< Clear virtual links */
+};
+
+/** FIP protocol subcode for VLAN */
+enum fip_vlan_subcode {
+	FIP_VLAN_REQUEST = 0x01,	/**< VLAN request */
+	FIP_VLAN_NOTIFY = 0x02,		/**< VLAN notification */
+};
+
+/** FIP flags */
+enum fip_flags {
+	FIP_FP	= 0x8000,		/**< Fabric-provided MAC address */
+	FIP_SP	= 0x4000,		/**< Server-provided MAC address */
+	FIP_A	= 0x0004,		/**< Available for login */
+	FIP_S	= 0x0002,		/**< Solicited */
+	FIP_F	= 0x0001,		/**< Forwarder */
+};
+
+/** FIP descriptor common fields */
+struct fip_common {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+} __attribute__ (( packed ));
+
+/** FIP descriptor types */
+enum fip_type {
+	FIP_RESERVED = 0x00,		/**< Reserved */
+	FIP_PRIORITY = 0x01,		/**< Priority */
+	FIP_MAC_ADDRESS = 0x02,		/**< MAC address */
+	FIP_FC_MAP = 0x03,		/**< FC-MAP */
+	FIP_NAME_ID = 0x04,		/**< Name identifier */
+	FIP_FABRIC = 0x05,		/**< Fabric */
+	FIP_MAX_FCOE_SIZE = 0x06,	/**< Max FCoE size */
+	FIP_FLOGI = 0x07,		/**< FLOGI */
+	FIP_NPIV_FDISC = 0x08,		/**< NPIV FDISC */
+	FIP_LOGO = 0x09,		/**< LOGO */
+	FIP_ELP = 0x0a,			/**< ELP */
+	FIP_VX_PORT_ID = 0x0b,		/**< Vx port identification */
+	FIP_FKA_ADV_P = 0x0c,		/**< FKA ADV period */
+	FIP_VENDOR_ID = 0x0d,		/**< Vendor ID */
+	FIP_VLAN = 0x0e,		/**< VLAN */
+	FIP_NUM_DESCRIPTOR_TYPES
+};
+
+/** FIP descriptor type is critical */
+#define FIP_IS_CRITICAL( type ) ( (type) <= 0x7f )
+
+/** A FIP priority descriptor */
+struct fip_priority {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved;
+	/** Priority
+	 *
+	 * A higher value indicates a lower priority.
+	 */
+	uint8_t priority;
+} __attribute__ (( packed ));
+
+/** Default FIP priority */
+#define FIP_DEFAULT_PRIORITY 128
+
+/** Lowest FIP priority */
+#define FIP_LOWEST_PRIORITY 255
+
+/** A FIP MAC address descriptor */
+struct fip_mac_address {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** MAC address */
+	uint8_t mac[ETH_ALEN];
+} __attribute__ (( packed ));
+
+/** A FIP FC-MAP descriptor */
+struct fip_fc_map {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[3];
+	/** FC-MAP */
+	struct fcoe_map map;
+} __attribute__ (( packed ));
+
+/** A FIP name identifier descriptor */
+struct fip_name_id {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Name identifier */
+	struct fc_name name;
+} __attribute__ (( packed ));
+
+/** A FIP fabric descriptor */
+struct fip_fabric {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Virtual Fabric ID, if any */
+	uint16_t vf_id;
+	/** Reserved */
+	uint8_t reserved;
+	/** FC-MAP */
+	struct fcoe_map map;
+	/** Fabric name */
+	struct fc_name name;
+} __attribute__ (( packed ));
+
+/** A FIP max FCoE size descriptor */
+struct fip_max_fcoe_size {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Maximum FCoE size */
+	uint16_t mtu;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated ELS frame */
+struct fip_els {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_els_frame_common els;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated login frame */
+struct fip_login {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_login_frame els;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated LOGO request frame */
+struct fip_logo_request {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_logout_request_frame els;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated LOGO response frame */
+struct fip_logo_response {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_logout_response_frame els;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated ELP frame */
+struct fip_elp {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_els_frame_common els;
+	/** Uninteresting content */
+	uint32_t dull[25];
+} __attribute__ (( packed ));
+
+/** A FIP descriptor containing an encapsulated LS_RJT frame */
+struct fip_ls_rjt {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Fibre Channel frame header */
+	struct fc_frame_header fc;
+	/** ELS frame */
+	struct fc_ls_rjt_frame els;
+} __attribute__ (( packed ));
+
+/** A FIP Vx port identification descriptor */
+struct fip_vx_port_id {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** MAC address */
+	uint8_t mac[ETH_ALEN];
+	/** Reserved */
+	uint8_t reserved;
+	/** Address identifier */
+	struct fc_port_id id;
+	/** Port name */
+	struct fc_name name;
+} __attribute__ (( packed ));
+
+/** A FIP FKA ADV period descriptor */
+struct fip_fka_adv_p {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved;
+	/** Flags */
+	uint8_t flags;
+	/** Keep alive advertisement period in milliseconds */
+	uint32_t period;
+} __attribute__ (( packed ));
+
+/** FIP FKA ADV period flags */
+enum fip_fka_adv_p_flags {
+	FIP_NO_KEEPALIVE = 0x01,	/**< Do not send keepalives */
+};
+
+/** A FIP vendor ID descriptor */
+struct fip_vendor_id {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** Reserved */
+	uint8_t reserved[2];
+	/** Vendor ID */
+	uint8_t vendor[8];
+} __attribute__ (( packed ));
+
+/** A FIP VLAN descriptor */
+struct fip_vlan {
+	/** Type */
+	uint8_t type;
+	/** Length in 32-bit words */
+	uint8_t len;
+	/** VLAN ID */
+	uint16_t vlan;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor */
+union fip_descriptor {
+	/** Common fields */
+	struct fip_common common;
+	/** Priority descriptor */
+	struct fip_priority priority;
+	/** MAC address descriptor */
+	struct fip_mac_address mac_address;
+	/** FC-MAP descriptor */
+	struct fip_fc_map fc_map;
+	/** Name identifier descriptor */
+	struct fip_name_id name_id;
+	/** Fabric descriptor */
+	struct fip_fabric fabric;
+	/** Max FCoE size descriptor */
+	struct fip_max_fcoe_size max_fcoe_size;
+	/** FLOGI descriptor */
+	struct fip_els flogi;
+	/** FLOGI request descriptor */
+	struct fip_login flogi_request;
+	/** FLOGI LS_ACC descriptor */
+	struct fip_login flogi_ls_acc;
+	/** FLOGI LS_RJT descriptor */
+	struct fip_ls_rjt flogi_ls_rjt;
+	/** NPIV FDISC descriptor */
+	struct fip_els npiv_fdisc;
+	/** NPIV FDISC request descriptor */
+	struct fip_login npiv_fdisc_request;
+	/** NPIV FDISC LS_ACC descriptor */
+	struct fip_login npiv_fdisc_ls_acc;
+	/** NPIV FDISC LS_RJT descriptor */
+	struct fip_ls_rjt npiv_fdisc_ls_rjt;
+	/** LOGO descriptor */
+	struct fip_els logo;
+	/** LOGO request descriptor */
+	struct fip_logo_request logo_request;
+	/** LOGO LS_ACC descriptor */
+	struct fip_logo_response logo_ls_acc;
+	/** LOGO LS_RJT descriptor */
+	struct fip_ls_rjt logo_ls_rjt;
+	/** ELS descriptor */
+	struct fip_els elp;
+	/** ELP request descriptor */
+	struct fip_elp elp_request;
+	/** ELP LS_ACC descriptor */
+	struct fip_elp elp_ls_acc;
+	/** ELP LS_RJT descriptor */
+	struct fip_ls_rjt elp_ls_rjt;
+	/** Vx port identification descriptor */
+	struct fip_vx_port_id vx_port_id;
+	/** FKA ADV period descriptor */
+	struct fip_fka_adv_p fka_adv_p;
+	/** Vendor ID descriptor */
+	struct fip_vendor_id vendor_id;
+	/** VLAN descriptor */
+	struct fip_vlan vlan;
+} __attribute__ (( packed ));
+
+/** A FIP descriptor set */
+struct fip_descriptors {
+	/** Descriptors, indexed by type */
+	union fip_descriptor *desc[FIP_NUM_DESCRIPTOR_TYPES];
+};
+
+/**
+ * Define a function to extract a specific FIP descriptor type from a list
+ *
+ * @v type		Descriptor type
+ * @v name		Descriptor name
+ * @v finder		Descriptor finder
+ */
+#define FIP_DESCRIPTOR( type, name )					\
+	static inline __attribute__ (( always_inline ))			\
+	typeof ( ( ( union fip_descriptor * ) NULL )->name ) *		\
+	fip_ ## name ( struct fip_descriptors *descs ) {		\
+		return &(descs->desc[type]->name);			\
+	}
+FIP_DESCRIPTOR ( FIP_PRIORITY, priority );
+FIP_DESCRIPTOR ( FIP_MAC_ADDRESS, mac_address );
+FIP_DESCRIPTOR ( FIP_FC_MAP, fc_map );
+FIP_DESCRIPTOR ( FIP_NAME_ID, name_id );
+FIP_DESCRIPTOR ( FIP_FABRIC, fabric );
+FIP_DESCRIPTOR ( FIP_MAX_FCOE_SIZE, max_fcoe_size );
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi );
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_request );
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_acc );
+FIP_DESCRIPTOR ( FIP_FLOGI, flogi_ls_rjt );
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc );
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_request );
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_acc );
+FIP_DESCRIPTOR ( FIP_NPIV_FDISC, npiv_fdisc_ls_rjt );
+FIP_DESCRIPTOR ( FIP_LOGO, logo );
+FIP_DESCRIPTOR ( FIP_LOGO, logo_request );
+FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_acc );
+FIP_DESCRIPTOR ( FIP_LOGO, logo_ls_rjt );
+FIP_DESCRIPTOR ( FIP_ELP, elp );
+FIP_DESCRIPTOR ( FIP_ELP, elp_request );
+FIP_DESCRIPTOR ( FIP_ELP, elp_ls_acc );
+FIP_DESCRIPTOR ( FIP_ELP, elp_ls_rjt );
+FIP_DESCRIPTOR ( FIP_VX_PORT_ID, vx_port_id );
+FIP_DESCRIPTOR ( FIP_FKA_ADV_P, fka_adv_p );
+FIP_DESCRIPTOR ( FIP_VENDOR_ID, vendor_id );
+FIP_DESCRIPTOR ( FIP_VLAN, vlan );
+
+#endif /* _IPXE_FIP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ftp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ftp.h
new file mode 100644
index 0000000..cbab12d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ftp.h
@@ -0,0 +1,15 @@
+#ifndef _IPXE_FTP_H
+#define _IPXE_FTP_H
+
+/** @file
+ *
+ * File transfer protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** FTP default port */
+#define FTP_PORT 21
+
+#endif /* _IPXE_FTP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbserial.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbserial.h
new file mode 100644
index 0000000..a3b5617
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbserial.h
@@ -0,0 +1,21 @@
+#ifndef _IPXE_GDBSERIAL_H
+#define _IPXE_GDBSERIAL_H
+
+/** @file
+ *
+ * GDB remote debugging over serial
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct gdb_transport;
+
+/**
+ * Set up the serial transport
+ *
+ * @ret transport suitable for starting the GDB stub or NULL on error
+ */
+struct gdb_transport *gdbserial_configure ( void );
+
+#endif /* _IPXE_GDBSERIAL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbstub.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbstub.h
new file mode 100644
index 0000000..3196067
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbstub.h
@@ -0,0 +1,77 @@
+#ifndef _IPXE_GDBSTUB_H
+#define _IPXE_GDBSTUB_H
+
+/** @file
+ *
+ * GDB remote debugging
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/tables.h>
+#include <gdbmach.h>
+
+/**
+ * A transport mechanism for the GDB protocol
+ *
+ */
+struct gdb_transport {
+	/** Transport name */
+	const char *name;
+	/**
+	 * Set up the transport given a list of arguments
+	 *
+	 * @v argc Number of arguments
+	 * @v argv Argument list
+	 * @ret Return status code
+	 *
+	 * Note that arguments start at argv[0].
+	 */
+	int ( * init ) ( int argc, char **argv );
+	/**
+	 * Perform a blocking read
+	 *
+	 * @v buf Buffer
+	 * @v len Size of buffer
+	 * @ret Number of bytes read into buffer
+	 */
+	size_t ( * recv ) ( char *buf, size_t len );
+	/**
+	 * Write, may block
+	 *
+	 * @v buf Buffer
+	 * @v len Size of buffer
+	 */
+	void ( * send ) ( const char *buf, size_t len );
+};
+
+#define GDB_TRANSPORTS __table ( struct gdb_transport, "gdb_transports" )
+
+#define __gdb_transport __table_entry ( GDB_TRANSPORTS, 01 )
+
+/**
+ * Look up GDB transport by name
+ *
+ * @v name Name of transport
+ * @ret GDB transport or NULL
+ */
+extern struct gdb_transport *find_gdb_transport ( const char *name );
+
+/**
+ * Break into the debugger using the given transport
+ *
+ * @v trans GDB transport
+ */
+extern void gdbstub_start ( struct gdb_transport *trans );
+
+/**
+ * Interrupt handler
+ *
+ * @signo POSIX signal number
+ * @regs CPU register snapshot
+ **/
+extern void gdbstub_handler ( int signo, gdbreg_t *regs );
+
+#endif /* _IPXE_GDBSTUB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbudp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbudp.h
new file mode 100644
index 0000000..db7a451
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/gdbudp.h
@@ -0,0 +1,24 @@
+#ifndef _IPXE_GDBUDP_H
+#define _IPXE_GDBUDP_H
+
+/** @file
+ *
+ * GDB remote debugging over UDP
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct sockaddr_in;
+struct gdb_transport;
+
+/**
+ * Set up the UDP transport with network address
+ *
+ * @name network device name
+ * @addr IP address and UDP listen port, may be NULL and fields may be zero
+ * @ret transport suitable for starting the GDB stub or NULL on error
+ */
+struct gdb_transport *gdbudp_configure ( const char *name, struct sockaddr_in *addr );
+
+#endif /* _IPXE_GDBUDP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/hidemem.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/hidemem.h
new file mode 100644
index 0000000..ddc9cd8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/hidemem.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_HIDEMEM_H
+#define _IPXE_HIDEMEM_H
+
+/**
+ * @file
+ *
+ * Hidden memory regions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+extern void hide_umalloc ( physaddr_t start, physaddr_t end );
+
+#endif /* _IPXE_HIDEMEM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/hmac.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/hmac.h
new file mode 100644
index 0000000..d5ec086
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/hmac.h
@@ -0,0 +1,32 @@
+#ifndef _IPXE_HMAC_H
+#define _IPXE_HMAC_H
+
+/** @file
+ *
+ * Keyed-Hashing for Message Authentication
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crypto.h>
+
+/**
+ * Update HMAC
+ *
+ * @v digest		Digest algorithm to use
+ * @v digest_ctx	Digest context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static inline void hmac_update ( struct digest_algorithm *digest,
+				 void *digest_ctx, const void *data,
+				 size_t len ) {
+	digest_update ( digest, digest_ctx, data, len );
+}
+
+extern void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
+			void *key, size_t *key_len );
+extern void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
+			 void *key, size_t *key_len, void *hmac );
+
+#endif /* _IPXE_HMAC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/http.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/http.h
new file mode 100644
index 0000000..d8f4ca5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/http.h
@@ -0,0 +1,23 @@
+#ifndef _IPXE_HTTP_H
+#define _IPXE_HTTP_H
+
+/** @file
+ *
+ * Hyper Text Transport Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** HTTP default port */
+#define HTTP_PORT 80
+
+/** HTTPS default port */
+#define HTTPS_PORT 443
+
+extern int http_open_filter ( struct interface *xfer, struct uri *uri,
+			      unsigned int default_port,
+			      int ( * filter ) ( struct interface *,
+						 struct interface ** ) );
+
+#endif /* _IPXE_HTTP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/i2c.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/i2c.h
new file mode 100644
index 0000000..c1f5a9b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/i2c.h
@@ -0,0 +1,171 @@
+#ifndef _IPXE_I2C_H
+#define _IPXE_I2C_H
+
+/** @file
+ *
+ * I2C interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/bitbash.h>
+
+/** An I2C device
+ *
+ * An I2C device represents a specific slave device on an I2C bus.  It
+ * is accessed via an I2C interface.
+ */
+struct i2c_device {
+	/** Address of this device
+	 *
+	 * The actual address sent on the bus will look like
+	 *
+	 *    <start> <device address> <word address overflow> <r/w>
+	 *
+	 * The "word address overflow" is any excess bits from the
+	 * word address, i.e. any portion that does not fit within the
+	 * defined word address length.
+	 */
+	unsigned int dev_addr;
+	/** Device address length, in bytes
+	 *
+	 * This is the number of bytes that comprise the device
+	 * address, defined to be the portion that terminates with the
+	 * read/write bit.
+	 */
+	unsigned int dev_addr_len;
+	/** Word adddress length, in bytes
+	 *
+	 * This is the number of bytes that comprise the word address,
+	 * defined to be the portion that starts after the read/write
+	 * bit and ends before the first data byte.
+	 *
+	 * For some devices, this length will be zero (i.e. the word
+	 * address is contained entirely within the "word address
+	 * overflow").
+	 */
+	unsigned int word_addr_len;
+};
+
+/** An I2C interface
+ *
+ * An I2C interface provides access to an I2C bus, via which I2C
+ * devices may be reached.
+ */
+struct i2c_interface {
+	/**
+	 * Read data from I2C device
+	 *
+	 * @v i2c		I2C interface
+	 * @v i2cdev		I2C device
+	 * @v offset		Starting offset within the device
+	 * @v data		Data buffer
+	 * @v len		Length of data buffer
+	 * @ret rc		Return status code
+	 */
+	int ( * read ) ( struct i2c_interface *i2c, struct i2c_device *i2cdev,
+			 unsigned int offset, uint8_t *data,
+			 unsigned int len );
+	/**
+	 * Write data to I2C device
+	 *
+	 * @v i2c		I2C interface
+	 * @v i2cdev		I2C device
+	 * @v offset		Starting offset within the device
+	 * @v data		Data buffer
+	 * @v len		Length of data buffer
+	 * @ret rc		Return status code
+	 */
+	int ( * write ) ( struct i2c_interface *i2c, struct i2c_device *i2cdev,
+			  unsigned int offset, const uint8_t *data,
+			  unsigned int len );
+};
+
+/** A bit-bashing I2C interface
+ *
+ * This provides a standardised way to construct I2C buses via a
+ * bit-bashing interface.
+ */
+struct i2c_bit_basher {
+	/** I2C interface */
+	struct i2c_interface i2c;
+	/** Bit-bashing interface */
+	struct bit_basher basher;
+};
+
+/** Ten-bit address marker
+ *
+ * This value is ORed with the I2C device address to indicate a
+ * ten-bit address format on the bus.
+ */
+#define I2C_TENBIT_ADDRESS 0x7800
+
+/** An I2C write command */
+#define I2C_WRITE 0
+
+/** An I2C read command */
+#define I2C_READ 1
+
+/** Bit indices used for I2C bit-bashing interface */
+enum {
+	/** Serial clock */
+	I2C_BIT_SCL = 0,
+	/** Serial data */
+	I2C_BIT_SDA,
+};
+
+/** Delay required for bit-bashing operation */
+#define I2C_UDELAY 5
+
+/** Maximum number of cycles to use when attempting a bus reset */
+#define I2C_RESET_MAX_CYCLES 32
+
+/**
+ * Check presence of I2C device
+ *
+ * @v i2c		I2C interface
+ * @v i2cdev		I2C device
+ * @ret rc		Return status code
+ *
+ * Checks for the presence of the device on the I2C bus by attempting
+ * a zero-length write.
+ */
+static inline int i2c_check_presence ( struct i2c_interface *i2c,
+				       struct i2c_device *i2cdev ) {
+	return i2c->write ( i2c, i2cdev, 0, NULL, 0 );
+}
+
+extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+				 struct bit_basher_operations *bash_op );
+
+/**
+ * Initialise generic I2C EEPROM device
+ *
+ * @v i2cdev		I2C device
+ */
+static inline __always_inline void
+init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) {
+	i2cdev->dev_addr = dev_addr;
+	i2cdev->dev_addr_len = 1;
+	i2cdev->word_addr_len = 1;
+}
+
+/**
+ * Initialise Atmel AT24C11
+ *
+ * @v i2cdev		I2C device
+ */
+static inline __always_inline void
+init_at24c11 ( struct i2c_device *i2cdev ) {
+	/* This chip has no device address; it must be the only chip
+	 * on the bus.  The word address is contained entirely within
+	 * the device address field.
+	 */
+	i2cdev->dev_addr = 0;
+	i2cdev->dev_addr_len = 1;
+	i2cdev->word_addr_len = 0;
+}
+
+#endif /* _IPXE_I2C_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cm.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cm.h
new file mode 100644
index 0000000..7d08cd9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cm.h
@@ -0,0 +1,72 @@
+#ifndef _IPXE_IB_CM_H
+#define _IPXE_IB_CM_H
+
+/** @file
+ *
+ * Infiniband communication management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/infiniband.h>
+#include <ipxe/retry.h>
+
+struct ib_mad_transaction;
+struct ib_connection;
+
+/** Infiniband connection operations */
+struct ib_connection_operations {
+	/** Handle change of connection status
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v conn		Connection
+	 * @v rc		Connection status code
+	 * @v private_data	Private data, if available
+	 * @v private_data_len	Length of private data
+	 */
+	void ( * changed ) ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			     struct ib_connection *conn, int rc,
+			     void *private_data, size_t private_data_len );
+};
+
+/** An Infiniband connection */
+struct ib_connection {
+	/** Infiniband device */
+	struct ib_device *ibdev;
+	/** Queue pair */
+	struct ib_queue_pair *qp;
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Target service ID */
+	union ib_guid service_id;
+	/** Connection operations */
+	struct ib_connection_operations *op;
+
+	/** List of connections */
+	struct list_head list;
+
+	/** Path to target */
+	struct ib_path *path;
+	/** Connection request management transaction */
+	struct ib_mad_transaction *madx;
+
+	/** Length of connection request private data */
+	size_t private_data_len;
+	/** Connection request private data */
+	uint8_t private_data[0];
+};
+
+extern struct ib_connection *
+ib_create_conn ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		 union ib_gid *dgid, union ib_guid *service_id,
+		 void *req_private_data, size_t req_private_data_len,
+		 struct ib_connection_operations *op );
+extern void ib_destroy_conn ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct ib_connection *conn );
+
+#endif /* _IPXE_IB_CM_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cmrc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cmrc.h
new file mode 100644
index 0000000..47ad27f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_cmrc.h
@@ -0,0 +1,20 @@
+#ifndef _IPXE_IB_CMRC_H
+#define _IPXE_IB_CMRC_H
+
+/** @file
+ *
+ * Infiniband Communication-managed Reliable Connections
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <ipxe/infiniband.h>
+#include <ipxe/xfer.h>
+
+extern int ib_cmrc_open ( struct interface *xfer,
+			  struct ib_device *ibdev,
+			  union ib_gid *dgid,
+			  union ib_guid *service_id );
+
+#endif /* _IPXE_IB_CMRC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mad.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mad.h
new file mode 100644
index 0000000..b869483
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mad.h
@@ -0,0 +1,591 @@
+#ifndef _IPXE_IB_MAD_H
+#define _IPXE_IB_MAD_H
+
+/** @file
+ *
+ * Infiniband management datagrams
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/ib_packet.h>
+
+/*****************************************************************************
+ *
+ * Subnet management MADs
+ *
+ *****************************************************************************
+ */
+
+/** A subnet management header
+ *
+ * Defined in sections 14.2.1.1 and 14.2.1.2 of the IBA.
+ */
+struct ib_smp_hdr {
+	uint64_t mkey;
+	uint16_t slid;
+	uint16_t dlid;
+	uint8_t reserved[28];
+} __attribute__ (( packed ));
+
+/** Subnet management class version */
+#define IB_SMP_CLASS_VERSION			1
+
+/** Subnet management direction bit
+ *
+ * This bit resides in the "status" field in the MAD header.
+ */
+#define IB_SMP_STATUS_D_INBOUND			0x8000
+
+/* Subnet management attributes */
+#define IB_SMP_ATTR_NOTICE			0x0002
+#define IB_SMP_ATTR_NODE_DESC			0x0010
+#define IB_SMP_ATTR_NODE_INFO			0x0011
+#define IB_SMP_ATTR_SWITCH_INFO			0x0012
+#define IB_SMP_ATTR_GUID_INFO			0x0014
+#define IB_SMP_ATTR_PORT_INFO			0x0015
+#define IB_SMP_ATTR_PKEY_TABLE			0x0016
+#define IB_SMP_ATTR_SL_TO_VL_TABLE		0x0017
+#define IB_SMP_ATTR_VL_ARB_TABLE		0x0018
+#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE	0x0019
+#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE	0x001A
+#define IB_SMP_ATTR_MCAST_FORWARD_TABLE		0x001B
+#define IB_SMP_ATTR_SM_INFO			0x0020
+#define IB_SMP_ATTR_VENDOR_DIAG			0x0030
+#define IB_SMP_ATTR_LED_INFO			0x0031
+#define IB_SMP_ATTR_VENDOR_MASK			0xFF00
+
+/**
+ * A Node Description attribute
+ *
+ * Defined in section 14.2.5.2 of the IBA
+ */
+struct ib_node_desc {
+	char node_string[64];
+} __attribute__ (( packed ));
+
+/** A Node Information attribute
+ *
+ * Defined in section 14.2.5.3 of the IBA.
+ */
+struct ib_node_info {
+	uint8_t base_version;
+	uint8_t class_version;
+	uint8_t node_type;
+	uint8_t num_ports;
+	union ib_guid sys_guid;
+	union ib_guid node_guid;
+	union ib_guid port_guid;
+	uint16_t partition_cap;
+	uint16_t device_id;
+	uint32_t revision;
+	uint8_t local_port_num;
+	uint8_t vendor_id[3];
+} __attribute__ ((packed));
+
+#define IB_NODE_TYPE_HCA		0x01
+#define IB_NODE_TYPE_SWITCH		0x02
+#define IB_NODE_TYPE_ROUTER		0x03
+
+/** A GUID Information attribute
+ *
+ * Defined in section 14.2.5.5 of the IBA.
+ */
+struct ib_guid_info {
+	uint8_t guid[8][8];
+} __attribute__ (( packed ));
+
+/** A Port Information attribute
+ *
+ * Defined in section 14.2.5.6 of the IBA.
+ */
+struct ib_port_info {
+	uint64_t mkey;
+	uint8_t gid_prefix[8];
+	uint16_t lid;
+	uint16_t mastersm_lid;
+	uint32_t cap_mask;
+	uint16_t diag_code;
+	uint16_t mkey_lease_period;
+	uint8_t local_port_num;
+	uint8_t link_width_enabled;
+	uint8_t link_width_supported;
+	uint8_t link_width_active;
+	uint8_t link_speed_supported__port_state;
+	uint8_t port_phys_state__link_down_def_state;
+	uint8_t mkey_prot_bits__lmc;
+	uint8_t link_speed_active__link_speed_enabled;
+	uint8_t neighbour_mtu__mastersm_sl;
+	uint8_t vl_cap__init_type;
+	uint8_t vl_high_limit;
+	uint8_t vl_arbitration_high_cap;
+	uint8_t vl_arbitration_low_cap;
+	uint8_t init_type_reply__mtu_cap;
+	uint8_t vl_stall_count__hoq_life;
+	uint8_t operational_vls__enforcement;
+	uint16_t mkey_violations;
+	uint16_t pkey_violations;
+	uint16_t qkey_violations;
+	uint8_t guid_cap;
+	uint8_t client_reregister__subnet_timeout;
+	uint8_t resp_time_value;
+	uint8_t local_phy_errors__overrun_errors;
+	uint16_t max_credit_hint;
+	uint32_t link_round_trip_latency;
+} __attribute__ (( packed ));
+
+#define IB_LINK_WIDTH_1X		0x01
+#define IB_LINK_WIDTH_4X		0x02
+#define IB_LINK_WIDTH_8X		0x04
+#define IB_LINK_WIDTH_12X		0x08
+
+#define IB_LINK_SPEED_SDR		0x01
+#define IB_LINK_SPEED_DDR		0x02
+#define IB_LINK_SPEED_QDR		0x04
+
+#define IB_PORT_STATE_DOWN		0x01
+#define IB_PORT_STATE_INIT		0x02
+#define IB_PORT_STATE_ARMED		0x03
+#define IB_PORT_STATE_ACTIVE		0x04
+
+#define IB_PORT_PHYS_STATE_SLEEP	0x01
+#define IB_PORT_PHYS_STATE_POLLING	0x02
+
+#define IB_MTU_256			0x01
+#define IB_MTU_512			0x02
+#define IB_MTU_1024			0x03
+#define IB_MTU_2048			0x04
+#define IB_MTU_4096			0x05
+
+#define IB_VL_0				0x01
+#define IB_VL_0_1			0x02
+#define IB_VL_0_3			0x03
+#define IB_VL_0_7			0x04
+#define IB_VL_0_14			0x05
+
+/** A Partition Key Table attribute
+ *
+ * Defined in section 14.2.5.7 of the IBA.
+ */
+struct ib_pkey_table {
+	uint16_t pkey[32];
+} __attribute__ (( packed ));
+
+/** A subnet management attribute */
+union ib_smp_data {
+	struct ib_node_desc node_desc;
+	struct ib_node_info node_info;
+	struct ib_guid_info guid_info;
+	struct ib_port_info port_info;
+	struct ib_pkey_table pkey_table;
+	uint8_t bytes[64];
+} __attribute__ (( packed ));
+
+/** A subnet management directed route path */
+struct ib_smp_dr_path {
+	uint8_t hops[64];
+} __attribute__ (( packed ));
+
+/** Subnet management MAD class-specific data */
+struct ib_smp_class_specific {
+	uint8_t hop_pointer;
+	uint8_t hop_count;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * Subnet administration MADs
+ *
+ *****************************************************************************
+ */
+
+#define IB_SA_CLASS_VERSION			2
+
+#define IB_SA_METHOD_DELETE_RESP		0x95
+
+struct ib_rmpp_hdr {
+	uint32_t raw[3];
+} __attribute__ (( packed ));
+
+struct ib_sa_hdr {
+	uint32_t sm_key[2];
+	uint16_t reserved;
+	uint16_t attrib_offset;
+	uint32_t comp_mask[2];
+} __attribute__ (( packed ));
+
+#define IB_SA_ATTR_MC_MEMBER_REC		0x38
+#define IB_SA_ATTR_PATH_REC			0x35
+
+struct ib_path_record {
+	uint32_t reserved0[2];
+	union ib_gid dgid;
+	union ib_gid sgid;
+	uint16_t dlid;
+	uint16_t slid;
+	uint32_t hop_limit__flow_label__raw_traffic;
+	uint32_t pkey__numb_path__reversible__tclass;
+	uint8_t reserved1;
+	uint8_t reserved__sl;
+	uint8_t mtu_selector__mtu;
+	uint8_t rate_selector__rate;
+	uint32_t preference__packet_lifetime__packet_lifetime_selector;
+	uint32_t reserved2[35];
+} __attribute__ (( packed ));
+
+#define IB_SA_PATH_REC_DGID			(1<<2)
+#define IB_SA_PATH_REC_SGID			(1<<3)
+
+struct ib_mc_member_record {
+	union ib_gid mgid;
+	union ib_gid port_gid;
+	uint32_t qkey;
+	uint16_t mlid;
+	uint8_t mtu_selector__mtu;
+	uint8_t tclass;
+	uint16_t pkey;
+	uint8_t rate_selector__rate;
+	uint8_t packet_lifetime_selector__packet_lifetime;
+	uint32_t sl__flow_label__hop_limit;
+	uint8_t scope__join_state;
+	uint8_t proxy_join__reserved;
+	uint16_t reserved0;
+	uint32_t reserved1[37];
+} __attribute__ (( packed ));
+
+#define IB_SA_MCMEMBER_REC_MGID			(1<<0)
+#define IB_SA_MCMEMBER_REC_PORT_GID		(1<<1)
+#define IB_SA_MCMEMBER_REC_QKEY			(1<<2)
+#define IB_SA_MCMEMBER_REC_MLID			(1<<3)
+#define IB_SA_MCMEMBER_REC_MTU_SELECTOR		(1<<4)
+#define IB_SA_MCMEMBER_REC_MTU			(1<<5)
+#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS	(1<<6)
+#define IB_SA_MCMEMBER_REC_PKEY			(1<<7)
+#define IB_SA_MCMEMBER_REC_RATE_SELECTOR	(1<<8)
+#define IB_SA_MCMEMBER_REC_RATE			(1<<9)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR	(1<<10)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME	(1<<11)
+#define IB_SA_MCMEMBER_REC_SL			(1<<12)
+#define IB_SA_MCMEMBER_REC_FLOW_LABEL		(1<<13)
+#define IB_SA_MCMEMBER_REC_HOP_LIMIT		(1<<14)
+#define IB_SA_MCMEMBER_REC_SCOPE		(1<<15)
+#define IB_SA_MCMEMBER_REC_JOIN_STATE		(1<<16)
+#define IB_SA_MCMEMBER_REC_PROXY_JOIN		(1<<17)
+
+union ib_sa_data {
+	struct ib_path_record path_record;
+	struct ib_mc_member_record mc_member_record;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * Communication management MADs
+ *
+ *****************************************************************************
+ */
+
+/** Communication management class version */
+#define IB_CM_CLASS_VERSION			2
+
+/* Communication management attributes */
+#define IB_CM_ATTR_CLASS_PORT_INFO		0x0001
+#define IB_CM_ATTR_CONNECT_REQUEST		0x0010
+#define IB_CM_ATTR_MSG_RCPT_ACK			0x0011
+#define IB_CM_ATTR_CONNECT_REJECT		0x0012
+#define IB_CM_ATTR_CONNECT_REPLY		0x0013
+#define IB_CM_ATTR_READY_TO_USE			0x0014
+#define IB_CM_ATTR_DISCONNECT_REQUEST		0x0015
+#define IB_CM_ATTR_DISCONNECT_REPLY		0x0016
+#define IB_CM_ATTR_SERVICE_ID_RES_REQ		0x0016
+#define IB_CM_ATTR_SERVICE_ID_RES_REQ_RESP	0x0018
+#define IB_CM_ATTR_LOAD_ALTERNATE_PATH		0x0019
+#define IB_CM_ATTR_ALTERNATE_PATH_RESPONSE	0x001a
+
+/** Communication management common fields */
+struct ib_cm_common {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Reserved */
+	uint8_t reserved[224];
+} __attribute__ (( packed ));
+
+/** A communication management path */
+struct ib_cm_path {
+	/** Local port LID */
+	uint16_t local_lid;
+	/** Remote port LID */
+	uint16_t remote_lid;
+	/** Local port GID */
+	union ib_gid local_gid;
+	/** Remote port GID */
+	union ib_gid remote_gid;
+	/** Flow label and rate */
+	uint32_t flow_label__rate;
+	/** Traffic class */
+	uint8_t tc;
+	/** Hop limit */
+	uint8_t hop_limit;
+	/** SL and subnet local*/
+	uint8_t sl__subnet_local;
+	/** Local ACK timeout */
+	uint8_t local_ack_timeout;
+} __attribute__ (( packed ));
+
+/** A communication management connection request
+ *
+ * Defined in section 12.6.5 of the IBA.
+ */
+struct ib_cm_connect_request {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Reserved */
+	uint32_t reserved0[1];
+	/** Service ID */
+	union ib_guid service_id;
+	/** Local CA GUID */
+	union ib_guid local_ca;
+	/** Reserved */
+	uint32_t reserved1[1];
+	/** Local queue key */
+	uint32_t local_qkey;
+	/** Local QPN and responder resources*/
+	uint32_t local_qpn__responder_resources;
+	/** Local EECN and initiator depth */
+	uint32_t local_eecn__initiator_depth;
+	/** Remote EECN, remote CM response timeout, transport service
+	 * type, EE flow control
+	 */
+	uint32_t remote_eecn__remote_timeout__service_type__ee_flow_ctrl;
+	/** Starting PSN, local CM response timeout and retry count */
+	uint32_t starting_psn__local_timeout__retry_count;
+	/** Partition key */
+	uint16_t pkey;
+	/** Path packet payload MTU, RDC exists, RNR retry count */
+	uint8_t payload_mtu__rdc_exists__rnr_retry;
+	/** Max CM retries and SRQ */
+	uint8_t max_cm_retries__srq;
+	/** Primary path */
+	struct ib_cm_path primary;
+	/** Alternate path */
+	struct ib_cm_path alternate;
+	/** Private data */
+	uint8_t private_data[92];
+} __attribute__ (( packed ));
+
+/** CM transport types */
+#define IB_CM_TRANSPORT_RC		0
+#define IB_CM_TRANSPORT_UC		1
+#define IB_CM_TRANSPORT_RD		2
+
+/** A communication management connection rejection
+ *
+ * Defined in section 12.6.7 of the IBA.
+ */
+struct ib_cm_connect_reject {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Message rejected */
+	uint8_t message;
+	/** Reject information length */
+	uint8_t info_len;
+	/** Rejection reason */
+	uint16_t reason;
+	/** Additional rejection information */
+	uint8_t info[72];
+	/** Private data */
+	uint8_t private_data[148];
+} __attribute__ (( packed ));
+
+/** CM rejection reasons */
+#define IB_CM_REJECT_BAD_SERVICE_ID	8
+#define IB_CM_REJECT_STALE_CONN		10
+#define IB_CM_REJECT_CONSUMER		28
+
+/** A communication management connection reply
+ *
+ * Defined in section 12.6.8 of the IBA.
+ */
+struct ib_cm_connect_reply {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Local queue key */
+	uint32_t local_qkey;
+	/** Local QPN */
+	uint32_t local_qpn;
+	/** Local EECN */
+	uint32_t local_eecn;
+	/** Starting PSN */
+	uint32_t starting_psn;
+	/** Responder resources */
+	uint8_t responder_resources;
+	/** Initiator depth */
+	uint8_t initiator_depth;
+	/** Target ACK delay, failover accepted, and end-to-end flow control */
+	uint8_t target_ack_delay__failover_accepted__ee_flow_ctrl;
+	/** RNR retry count, SRQ */
+	uint8_t rnr_retry__srq;
+	/** Local CA GUID */
+	union ib_guid local_ca;
+	/** Private data */
+	uint8_t private_data[196];
+} __attribute__ (( packed ));
+
+/** A communication management ready to use reply
+ *
+ * Defined in section 12.6.9 of the IBA.
+ */
+struct ib_cm_ready_to_use {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Private data */
+	uint8_t private_data[224];
+} __attribute__ (( packed ));
+
+/** A communication management disconnection request
+ *
+ * Defined in section 12.6.10 of the IBA.
+ */
+struct ib_cm_disconnect_request {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Remote QPN/EECN */
+	uint32_t remote_qpn_eecn;
+	/** Private data */
+	uint8_t private_data[220];
+} __attribute__ (( packed ));
+
+/** A communication management disconnection reply
+ *
+ * Defined in section 12.6.11 of the IBA.
+ */
+struct ib_cm_disconnect_reply {
+	/** Local communication ID */
+	uint32_t local_id;
+	/** Remote communication ID */
+	uint32_t remote_id;
+	/** Private data */
+	uint8_t private_data[224];
+} __attribute__ (( packed ));
+
+/** A communication management attribute */
+union ib_cm_data {
+	struct ib_cm_common common;
+	struct ib_cm_connect_request connect_request;
+	struct ib_cm_connect_reject connect_reject;
+	struct ib_cm_connect_reply connect_reply;
+	struct ib_cm_ready_to_use ready_to_use;
+	struct ib_cm_disconnect_request disconnect_request;
+	struct ib_cm_disconnect_reply disconnect_reply;
+	uint8_t bytes[232];
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * MADs
+ *
+ *****************************************************************************
+ */
+
+/** Management datagram class_specific data */
+union ib_mad_class_specific {
+	uint16_t raw;
+	struct ib_smp_class_specific smp;
+} __attribute__ (( packed ));
+
+/** A management datagram common header
+ *
+ * Defined in section 13.4.2 of the IBA.
+ */
+struct ib_mad_hdr {
+	uint8_t base_version;
+	uint8_t mgmt_class;
+	uint8_t class_version;
+	uint8_t method;
+	uint16_t status;
+	union ib_mad_class_specific class_specific;
+	uint32_t tid[2];
+	uint16_t attr_id;
+	uint8_t reserved[2];
+	uint32_t attr_mod;
+} __attribute__ (( packed ));
+
+/* Management base version */
+#define IB_MGMT_BASE_VERSION			1
+
+/* Management classes */
+#define IB_MGMT_CLASS_SUBN_LID_ROUTED		0x01
+#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE	0x81
+#define IB_MGMT_CLASS_SUBN_ADM			0x03
+#define IB_MGMT_CLASS_PERF_MGMT			0x04
+#define IB_MGMT_CLASS_BM			0x05
+#define IB_MGMT_CLASS_DEVICE_MGMT		0x06
+#define IB_MGMT_CLASS_CM			0x07
+#define IB_MGMT_CLASS_SNMP			0x08
+#define IB_MGMT_CLASS_VENDOR_RANGE2_START	0x30
+#define IB_MGMT_CLASS_VENDOR_RANGE2_END		0x4f
+
+#define IB_MGMT_CLASS_MASK			0x7f
+
+/* Management methods */
+#define IB_MGMT_METHOD_GET			0x01
+#define IB_MGMT_METHOD_SET			0x02
+#define IB_MGMT_METHOD_GET_RESP			0x81
+#define IB_MGMT_METHOD_SEND			0x03
+#define IB_MGMT_METHOD_TRAP			0x05
+#define IB_MGMT_METHOD_REPORT			0x06
+#define IB_MGMT_METHOD_REPORT_RESP		0x86
+#define IB_MGMT_METHOD_TRAP_REPRESS		0x07
+#define IB_MGMT_METHOD_DELETE			0x15
+
+/* Status codes */
+#define IB_MGMT_STATUS_OK			0x0000
+#define IB_MGMT_STATUS_BAD_VERSION		0x0001
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD	0x0002
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR	0x0003
+#define IB_MGMT_STATUS_INVALID_VALUE		0x0004
+
+/** A subnet management MAD */
+struct ib_mad_smp {
+	struct ib_mad_hdr mad_hdr;
+	struct ib_smp_hdr smp_hdr;
+	union ib_smp_data smp_data;
+	struct ib_smp_dr_path initial_path;
+	struct ib_smp_dr_path return_path;
+} __attribute__ (( packed ));
+
+/** A subnet administration MAD */
+struct ib_mad_sa {
+	struct ib_mad_hdr mad_hdr;
+	struct ib_rmpp_hdr rmpp_hdr;
+	struct ib_sa_hdr sa_hdr;
+	union ib_sa_data sa_data;
+} __attribute__ (( packed ));
+
+/** A communication management MAD */
+struct ib_mad_cm {
+	struct ib_mad_hdr mad_hdr;
+	union ib_cm_data cm_data;
+} __attribute__ (( packed ));
+
+/** A management datagram */
+union ib_mad {
+	struct ib_mad_hdr hdr;
+	struct ib_mad_smp smp;
+	struct ib_mad_sa sa;
+	struct ib_mad_cm cm;
+	uint8_t bytes[256];
+} __attribute__ (( packed ));
+
+#endif /* _IPXE_IB_MAD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mcast.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mcast.h
new file mode 100644
index 0000000..a5c22a0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mcast.h
@@ -0,0 +1,48 @@
+#ifndef _IPXE_IB_MCAST_H
+#define _IPXE_IB_MCAST_H
+
+/** @file
+ *
+ * Infiniband multicast groups
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/infiniband.h>
+
+struct ib_mad_transaction;
+
+/** An Infiniband multicast group membership */
+struct ib_mc_membership {
+	/** Queue pair */
+	struct ib_queue_pair *qp;
+	/** Multicast GID */
+	union ib_gid gid;
+	/** Multicast group join transaction */
+	struct ib_mad_transaction *madx;
+	/** Handle join success/failure
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v membership	Multicast group membership
+	 * @v rc		Status code
+	 * @v mad		Response MAD (or NULL on error)
+	 */
+	void ( * complete ) ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			      struct ib_mc_membership *membership, int rc,
+			      union ib_mad *mad );
+};
+
+extern int ib_mcast_join ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			   struct ib_mc_membership *membership,
+			   union ib_gid *gid,
+			   void ( * joined ) ( struct ib_device *ibdev,
+					       struct ib_queue_pair *qp,
+					       struct ib_mc_membership *memb,
+					       int rc, union ib_mad *mad ) );
+
+extern void ib_mcast_leave ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			     struct ib_mc_membership *membership );
+
+#endif /* _IPXE_IB_MCAST_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mi.h
new file mode 100644
index 0000000..5c5415b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_mi.h
@@ -0,0 +1,135 @@
+#ifndef _IPXE_IB_MI_H
+#define _IPXE_IB_MI_H
+
+/** @file
+ *
+ * Infiniband management interfaces
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+#include <ipxe/retry.h>
+#include <ipxe/tables.h>
+#include <ipxe/infiniband.h>
+
+struct ib_mad_interface;
+struct ib_mad_transaction;
+
+/** An Infiniband management agent */
+struct ib_mad_agent {
+	/** Management class */
+	uint8_t mgmt_class;
+	/** Class version */
+	uint8_t class_version;
+	/** Attribute (in network byte order) */
+	uint16_t attr_id;
+	/** Handle MAD
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v mi		Management interface
+	 * @v mad		Received MAD
+	 * @v av		Source address vector
+	 * @ret rc		Return status code
+	 */
+	void ( * handle ) ( struct ib_device *ibdev,
+			    struct ib_mad_interface *mi,
+			    union ib_mad *mad,
+			    struct ib_address_vector *av );
+};
+
+/** Infiniband management agents */
+#define IB_MAD_AGENTS __table ( struct ib_mad_agent, "ib_mad_agents" )
+
+/** Declare an Infiniband management agent */
+#define __ib_mad_agent __table_entry ( IB_MAD_AGENTS, 01 )
+
+/** Infiniband management transaction operations */
+struct ib_mad_transaction_operations {
+	/** Handle transaction completion
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v mi		Management interface
+	 * @v madx		Management transaction
+	 * @v rc		Status code
+	 * @v mad		Received MAD (or NULL on error)
+	 * @v av		Source address vector (or NULL on error)
+	 *
+	 * The completion handler should in most cases call
+	 * ib_destroy_madx() to free up the completed transaction.
+	 */
+	void ( * complete ) ( struct ib_device *ibdev,
+			      struct ib_mad_interface *mi,
+			      struct ib_mad_transaction *madx,
+			      int rc, union ib_mad *mad,
+			      struct ib_address_vector *av );
+};
+
+/** An Infiniband management transaction */
+struct ib_mad_transaction {
+	/** Associated management interface */
+	struct ib_mad_interface *mi;
+	/** List of transactions */
+	struct list_head list;
+	/** Retry timer */
+	struct retry_timer timer;
+	/** Destination address vector */
+	struct ib_address_vector av;
+	/** MAD being sent */
+	union ib_mad mad;
+	/** Transaction operations */
+	struct ib_mad_transaction_operations *op;
+	/** Owner private data */
+	void *owner_priv;
+};
+
+/** An Infiniband management interface */
+struct ib_mad_interface {
+	/** Infiniband device */
+	struct ib_device *ibdev;
+	/** Completion queue */
+	struct ib_completion_queue *cq;
+	/** Queue pair */
+	struct ib_queue_pair *qp;
+	/** List of management transactions */
+	struct list_head madx;
+};
+
+/**
+ * Set Infiniband management transaction owner-private data
+ *
+ * @v madx		Management transaction
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_madx_set_ownerdata ( struct ib_mad_transaction *madx, void *priv ) {
+	madx->owner_priv = priv;
+}
+
+/**
+ * Get Infiniband management transaction owner-private data
+ *
+ * @v madx		Management transaction
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_madx_get_ownerdata ( struct ib_mad_transaction *madx ) {
+	return madx->owner_priv;
+}
+
+extern int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
+			union ib_mad *mad, struct ib_address_vector *av );
+extern struct ib_mad_transaction *
+ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
+		 union ib_mad *mad, struct ib_address_vector *av,
+		 struct ib_mad_transaction_operations *op );
+extern void ib_destroy_madx ( struct ib_device *ibdev,
+			      struct ib_mad_interface *mi,
+			      struct ib_mad_transaction *madx );
+extern struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
+						enum ib_queue_pair_type type );
+extern void ib_destroy_mi ( struct ib_device *ibdev,
+			    struct ib_mad_interface *mi );
+
+#endif /* _IPXE_IB_MI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_packet.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_packet.h
new file mode 100644
index 0000000..4bd3357
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_packet.h
@@ -0,0 +1,160 @@
+#ifndef _IPXE_IB_PACKET_H
+#define _IPXE_IB_PACKET_H
+
+/** @file
+ *
+ * Infiniband packet format
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct ib_device;
+struct ib_queue_pair;
+struct ib_address_vector;
+struct io_buffer;
+
+/** An Infiniband Globally Unique Identifier */
+union ib_guid {
+	uint8_t bytes[8];
+	uint16_t words[4];
+	uint32_t dwords[2];
+};
+
+/** Infiniband Globally Unique Identifier debug message format */
+#define IB_GUID_FMT "%08x:%08x"
+
+/** Infiniband Globally Unique Identifier debug message arguments */
+#define IB_GUID_ARGS( guid ) \
+	ntohl ( (guid)->dwords[0] ), ntohl ( (guid)->dwords[1] )
+
+/** An Infiniband Global Identifier */
+union ib_gid {
+	uint8_t bytes[16];
+	uint16_t words[8];
+	uint32_t dwords[4];
+	struct {
+		union ib_guid prefix;
+		union ib_guid guid;
+	} s;
+};
+
+/** Infiniband Global Identifier debug message format */
+#define IB_GID_FMT IB_GUID_FMT ":" IB_GUID_FMT
+
+/** Infiniband Global Identifier debug message arguments */
+#define IB_GID_ARGS( gid ) \
+	IB_GUID_ARGS ( &(gid)->s.prefix ), IB_GUID_ARGS ( &(gid)->s.guid )
+
+/** An Infiniband Local Route Header */
+struct ib_local_route_header {
+	/** Virtual lane and link version */
+	uint8_t vl__lver;
+	/** Service level and next link header */
+	uint8_t sl__lnh;
+	/** Destination LID */
+	uint16_t dlid;
+	/** Packet length */
+	uint16_t length;
+	/** Source LID */
+	uint16_t slid;
+} __attribute__ (( packed ));
+
+/** Infiniband virtual lanes */
+enum ib_vl {
+	IB_VL_DEFAULT = 0,
+	IB_VL_SMP = 15,
+};
+
+/** An Infiniband Link Next Header value */
+enum ib_lnh {
+	IB_LNH_RAW = 0,
+	IB_LNH_IPv6 = 1,
+	IB_LNH_BTH = 2,
+	IB_LNH_GRH = 3
+};
+
+/** Default Infiniband LID */
+#define IB_LID_NONE 0xffff
+
+/** Test for multicast LID */
+#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) )
+
+/** An Infiniband Global Route Header */
+struct ib_global_route_header {
+	/** IP version, traffic class, and flow label
+	 *
+	 *  4 bits : Version of the GRH
+	 *  8 bits : Traffic class
+	 * 20 bits : Flow label
+	 */
+	uint32_t ipver__tclass__flowlabel;
+	/** Payload length */
+	uint16_t paylen;
+	/** Next header */
+	uint8_t nxthdr;
+	/** Hop limit */
+	uint8_t hoplmt;
+	/** Source GID */
+	union ib_gid sgid;
+	/** Destiniation GID */
+	union ib_gid dgid;
+} __attribute__ (( packed ));
+
+#define IB_GRH_IPVER_IPv6 0x06
+#define IB_GRH_NXTHDR_IBA 0x1b
+
+/** An Infiniband Base Transport Header */
+struct ib_base_transport_header {
+	/** Opcode */
+	uint8_t opcode;
+	/** Transport header version, pad count, migration and solicitation */
+	uint8_t se__m__padcnt__tver;
+	/** Partition key */
+	uint16_t pkey;
+	/** Destination queue pair */
+	uint32_t dest_qp;
+	/** Packet sequence number and acknowledge request */
+	uint32_t ack__psn;
+} __attribute__ (( packed ));
+
+/** An Infiniband BTH opcode */
+enum ib_bth_opcode {
+	BTH_OPCODE_UD_SEND = 0x64,
+};
+
+/** An Infiniband Datagram Extended Transport Header */
+struct ib_datagram_extended_transport_header {
+	/** Queue key */
+	uint32_t qkey;
+	/** Source queue pair */
+	uint32_t src_qp;
+} __attribute__ (( packed ));
+
+/** All known IB header formats */
+union ib_headers {
+	struct ib_local_route_header lrh;
+	struct {
+		struct ib_local_route_header lrh;
+		struct ib_global_route_header grh;
+		struct ib_base_transport_header bth;
+		struct ib_datagram_extended_transport_header deth;
+	} __attribute__ (( packed )) lrh__grh__bth__deth;
+	struct {
+		struct ib_local_route_header lrh;
+		struct ib_base_transport_header bth;
+		struct ib_datagram_extended_transport_header deth;
+	} __attribute__ (( packed )) lrh__bth__deth;
+} __attribute__ (( packed ));
+
+/** Maximum size required for IB headers */
+#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers )
+
+extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+		     struct ib_queue_pair *qp, size_t payload_len,
+		     const struct ib_address_vector *av );
+extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+		     struct ib_queue_pair **qp, size_t *payload_len,
+		     struct ib_address_vector *av );
+
+#endif /* _IPXE_IB_PACKET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_pathrec.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_pathrec.h
new file mode 100644
index 0000000..1fe67f8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_pathrec.h
@@ -0,0 +1,76 @@
+#ifndef _IPXE_IB_PATHREC_H
+#define _IPXE_IB_PATHREC_H
+
+/** @file
+ *
+ * Infiniband path records
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/infiniband.h>
+
+struct ib_mad_transaction;
+struct ib_path;
+
+/** Infiniband path operations */
+struct ib_path_operations {
+	/** Handle path transaction completion
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v path		Path
+	 * @v rc		Status code
+	 * @v av		Address vector, or NULL on error
+	 */
+	void ( * complete ) ( struct ib_device *ibdev,
+			      struct ib_path *path, int rc,
+			      struct ib_address_vector *av );
+};
+
+/** An Infiniband path */
+struct ib_path {
+	/** Infiniband device */
+	struct ib_device *ibdev;
+	/** Address vector */
+	struct ib_address_vector av;
+	/** Management transaction */
+	struct ib_mad_transaction *madx;
+	/** Path operations */
+	struct ib_path_operations *op;
+	/** Owner private data */
+	void *owner_priv;
+};
+
+/**
+ * Set Infiniband path owner-private data
+ *
+ * @v path		Path
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_path_set_ownerdata ( struct ib_path *path, void *priv ) {
+	path->owner_priv = priv;
+}
+
+/**
+ * Get Infiniband path owner-private data
+ *
+ * @v path		Path
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_path_get_ownerdata ( struct ib_path *path ) {
+	return path->owner_priv;
+}
+
+extern struct ib_path *
+ib_create_path ( struct ib_device *ibdev, struct ib_address_vector *av,
+		 struct ib_path_operations *op );
+extern void ib_destroy_path ( struct ib_device *ibdev,
+			      struct ib_path *path );
+
+extern int ib_resolve_path ( struct ib_device *ibdev,
+			     struct ib_address_vector *av );
+
+#endif /* _IPXE_IB_PATHREC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_sma.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_sma.h
new file mode 100644
index 0000000..fa355c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_sma.h
@@ -0,0 +1,20 @@
+#ifndef _IPXE_IB_SMA_H
+#define _IPXE_IB_SMA_H
+
+/** @file
+ *
+ * Infiniband subnet management agent
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct ib_device;
+struct ib_mad_interface;
+
+extern int ib_create_sma ( struct ib_device *ibdev,
+			   struct ib_mad_interface *mi );
+extern void ib_destroy_sma ( struct ib_device *ibdev,
+			     struct ib_mad_interface *mi );
+
+#endif /* _IPXE_IB_SMA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_smc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_smc.h
new file mode 100644
index 0000000..259d2cd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_smc.h
@@ -0,0 +1,20 @@
+#ifndef _IPXE_IB_SMC_H
+#define _IPXE_IB_SMC_H
+
+/** @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/infiniband.h>
+
+typedef int ( * ib_local_mad_t ) ( struct ib_device *ibdev,
+				   union ib_mad *mad );
+
+extern int ib_smc_init ( struct ib_device *ibdev, ib_local_mad_t local_mad );
+extern int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad );
+
+#endif /* _IPXE_IB_SMC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_srp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_srp.h
new file mode 100644
index 0000000..ad407b0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ib_srp.h
@@ -0,0 +1,58 @@
+#ifndef _IPXE_IB_SRP_H
+#define _IPXE_IB_SRP_H
+
+/** @file
+ *
+ * SCSI RDMA Protocol over Infiniband
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/srp.h>
+
+/** SRP initiator port identifier for Infiniband */
+union ib_srp_initiator_port_id {
+	/** SRP version of port identifier */
+	union srp_port_id srp;
+	/** Infiniband version of port identifier */
+	struct {
+		/** Identifier extension */
+		union ib_guid id_ext;
+		/** IB channel adapter GUID */
+		union ib_guid hca_guid;
+	} __attribute__ (( packed )) ib;
+};
+
+/** SRP target port identifier for Infiniband */
+union ib_srp_target_port_id {
+	/** SRP version of port identifier */
+	union srp_port_id srp;
+	/** Infiniband version of port identifier */
+	struct {
+		/** Identifier extension */
+		union ib_guid id_ext;
+		/** I/O controller GUID */
+		union ib_guid ioc_guid;
+	} __attribute__ (( packed )) ib;
+};
+
+/**
+ * sBFT Infiniband subtable
+ */
+struct sbft_ib_subtable {
+	/** Source GID */
+	union ib_gid sgid;
+	/** Destination GID */
+	union ib_gid dgid;
+	/** Service ID */
+	union ib_guid service_id;
+	/** Partition key */
+	uint16_t pkey;
+	/** Reserved */
+	uint8_t reserved[6];
+} __attribute__ (( packed ));
+
+#endif /* _IPXE_IB_SRP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ibft.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ibft.h
new file mode 100644
index 0000000..7337212
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ibft.h
@@ -0,0 +1,271 @@
+#ifndef _IPXE_IBFT_H
+#define _IPXE_IBFT_H
+
+/*
+ * Copyright Fen Systems Ltd. 2007.  Portions of this code are derived
+ * from IBM Corporation Sample Programs.  Copyright IBM Corporation
+ * 2004, 2007.  All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+/** @file
+ *
+ * iSCSI boot firmware table
+ *
+ * The information in this file is derived from the document "iSCSI
+ * Boot Firmware Table (iBFT)" as published by IBM at
+ *
+ * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/acpi.h>
+#include <ipxe/scsi.h>
+#include <ipxe/in.h>
+
+/** iSCSI Boot Firmware Table signature */
+#define IBFT_SIG ACPI_SIGNATURE ( 'i', 'B', 'F', 'T' )
+
+/** An offset from the start of the iBFT */
+typedef uint16_t ibft_off_t;
+
+/** Length of a string within the iBFT (excluding terminating NUL) */
+typedef uint16_t ibft_size_t;
+
+/** A string within the iBFT */
+struct ibft_string {
+	/** Length of string */
+	ibft_size_t len;
+	/** Offset to string */
+	ibft_off_t offset;
+} __attribute__ (( packed ));
+
+/** An IP address within the iBFT */
+struct ibft_ipaddr {
+	/** Reserved; must be zero */
+	uint16_t zeroes[5];
+	/** Must be 0xffff if IPv4 address is present, otherwise zero */
+	uint16_t ones;
+	/** The IPv4 address, or zero if not present */
+	struct in_addr in;
+} __attribute__ (( packed ));
+
+/**
+ * iBFT structure header
+ *
+ * This structure is common to several sections within the iBFT.
+ */
+struct ibft_header {
+	/** Structure ID
+	 *
+	 * This is an IBFT_STRUCTURE_ID_XXX constant
+	 */
+	uint8_t structure_id;
+	/** Version (always 1) */
+	uint8_t version;
+	/** Length, including this header */
+	uint16_t length;
+	/** Index 
+	 *
+	 * This is the number of the NIC or Target, when applicable.
+	 */
+	uint8_t index;
+	/** Flags */
+	uint8_t flags;
+} __attribute__ (( packed ));
+
+/**
+ * iBFT Control structure
+ *
+ */
+struct ibft_control {
+	/** Common header */
+	struct ibft_header header;
+	/** Extensions */
+	uint16_t extensions;
+	/** Offset to Initiator structure */
+	ibft_off_t initiator;
+	/** Offset to NIC structure for NIC 0 */
+	ibft_off_t nic_0;
+	/** Offset to Target structure for target 0 */
+	ibft_off_t target_0;
+	/** Offset to NIC structure for NIC 1 */
+	ibft_off_t nic_1;
+	/** Offset to Target structure for target 1 */
+	ibft_off_t target_1;
+} __attribute__ (( packed ));
+
+/** Structure ID for Control section */
+#define IBFT_STRUCTURE_ID_CONTROL 0x01
+
+/** Attempt login only to specified target
+ *
+ * If this flag is not set, all targets will be logged in to.
+ */
+#define IBFT_FL_CONTROL_SINGLE_LOGIN_ONLY 0x01
+
+/**
+ * iBFT Initiator structure
+ *
+ */
+struct ibft_initiator {
+	/** Common header */
+	struct ibft_header header;
+	/** iSNS server */
+	struct ibft_ipaddr isns_server;
+	/** SLP server */
+	struct ibft_ipaddr slp_server;
+	/** Primary and secondary Radius servers */
+	struct ibft_ipaddr radius[2];
+	/** Initiator name */
+	struct ibft_string initiator_name;
+} __attribute__ (( packed ));
+
+/** Structure ID for Initiator section */
+#define IBFT_STRUCTURE_ID_INITIATOR 0x02
+
+/** Initiator block valid */
+#define IBFT_FL_INITIATOR_BLOCK_VALID 0x01
+
+/** Initiator firmware boot selected */
+#define IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED 0x02
+
+/**
+ * iBFT NIC structure
+ *
+ */
+struct ibft_nic {
+	/** Common header */
+	struct ibft_header header;
+	/** IP address */
+	struct ibft_ipaddr ip_address;
+	/** Subnet mask
+	 *
+	 * This is the length of the subnet mask in bits (e.g. /24).
+	 */
+	uint8_t subnet_mask_prefix;
+	/** Origin */
+	uint8_t origin;
+	/** Default gateway */
+	struct ibft_ipaddr gateway;
+	/** Primary and secondary DNS servers */
+	struct ibft_ipaddr dns[2];
+	/** DHCP server */
+	struct ibft_ipaddr dhcp;
+	/** VLAN tag */
+	uint16_t vlan;
+	/** MAC address */
+	uint8_t mac_address[6];
+	/** PCI bus:dev:fn */
+	uint16_t pci_bus_dev_func;
+	/** Hostname */
+	struct ibft_string hostname;
+} __attribute__ (( packed ));
+
+/** Structure ID for NIC section */
+#define IBFT_STRUCTURE_ID_NIC 0x03
+
+/** NIC block valid */
+#define IBFT_FL_NIC_BLOCK_VALID 0x01
+
+/** NIC firmware boot selected */
+#define IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED 0x02
+
+/** NIC global / link local */
+#define IBFT_FL_NIC_GLOBAL 0x04
+
+/**
+ * iBFT Target structure
+ *
+ */
+struct ibft_target {
+	/** Common header */
+	struct ibft_header header;
+	/** IP address */
+	struct ibft_ipaddr ip_address;
+	/** TCP port */
+	uint16_t socket;
+	/** Boot LUN */
+	struct scsi_lun boot_lun;
+	/** CHAP type
+	 *
+	 * This is an IBFT_CHAP_XXX constant.
+	 */
+	uint8_t chap_type;
+	/** NIC association */
+	uint8_t nic_association;
+	/** Target name */
+	struct ibft_string target_name;
+	/** CHAP name */
+	struct ibft_string chap_name;
+	/** CHAP secret */
+	struct ibft_string chap_secret;
+	/** Reverse CHAP name */
+	struct ibft_string reverse_chap_name;
+	/** Reverse CHAP secret */
+	struct ibft_string reverse_chap_secret;
+} __attribute__ (( packed ));
+
+/** Structure ID for Target section */
+#define IBFT_STRUCTURE_ID_TARGET 0x04
+
+/** Target block valid */
+#define IBFT_FL_TARGET_BLOCK_VALID 0x01
+
+/** Target firmware boot selected */
+#define IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED 0x02
+
+/** Target use Radius CHAP */
+#define IBFT_FL_TARGET_USE_CHAP 0x04
+
+/** Target use Radius rCHAP */
+#define IBFT_FL_TARGET_USE_RCHAP 0x08
+
+/* Values for chap_type */
+#define IBFT_CHAP_NONE		0	/**< No CHAP authentication */
+#define IBFT_CHAP_ONE_WAY	1	/**< One-way CHAP */
+#define IBFT_CHAP_MUTUAL	2	/**< Mutual CHAP */
+
+/**
+ * iSCSI Boot Firmware Table (iBFT)
+ */
+struct ibft_table {
+	/** ACPI header */
+	struct acpi_description_header acpi;
+	/** Reserved */
+	uint8_t reserved[12];
+	/** Control structure */
+	struct ibft_control control;
+} __attribute__ (( packed ));
+
+struct iscsi_session;
+struct net_device;
+
+extern int ibft_describe ( struct iscsi_session *iscsi,
+			   struct acpi_description_header *acpi,
+			   size_t len );
+
+#endif /* _IPXE_IBFT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp.h
new file mode 100644
index 0000000..e402ce4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp.h
@@ -0,0 +1,25 @@
+#ifndef _IPXE_ICMP_H
+#define _IPXE_ICMP_H
+
+/** @file
+ *
+ * ICMP protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** An ICMP header */
+struct icmp_header {
+	/** Type */
+	uint8_t type;
+	/** Code */
+	uint8_t code;
+	/** Checksum */
+	uint16_t chksum;
+} __attribute__ (( packed ));
+
+#define ICMP_ECHO_RESPONSE 0
+#define ICMP_ECHO_REQUEST 8
+
+#endif /* _IPXE_ICMP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp6.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp6.h
new file mode 100644
index 0000000..1d43340
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/icmp6.h
@@ -0,0 +1,59 @@
+#ifndef _IPXE_ICMP6_H
+#define _IPXE_ICMP6_H
+
+/** @file
+ *
+ * ICMP6 protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/ip6.h>
+#include <ipxe/ndp.h>
+
+#define ICMP6_NSOLICIT 135
+#define ICMP6_NADVERT 136
+
+extern struct tcpip_protocol icmp6_protocol __tcpip_protocol;
+
+struct icmp6_header {
+	uint8_t type;
+	uint8_t code;
+	uint16_t csum;
+	/* Message body */
+};
+
+struct neighbour_solicit {
+	uint8_t type;
+	uint8_t code;
+	uint16_t csum;
+	uint32_t reserved;
+	struct in6_addr target;
+	/* "Compulsory" options */
+	uint8_t opt_type;
+	uint8_t opt_len;
+  /* FIXME:  hack alert */
+	uint8_t opt_ll_addr[6];
+};
+
+struct neighbour_advert {
+	uint8_t type;
+	uint8_t code;
+	uint16_t csum;
+	uint8_t flags;
+	uint8_t reserved;
+	struct in6_addr target;
+	uint8_t opt_type;
+	uint8_t opt_len;
+  /* FIXME:  hack alert */
+	uint8_t opt_ll_addr[6];
+};
+
+#define ICMP6_FLAGS_ROUTER 0x80
+#define ICMP6_FLAGS_SOLICITED 0x40
+#define ICMP6_FLAGS_OVERRIDE 0x20
+
+int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src, struct in6_addr *dest );
+
+#endif /* _IPXE_ICMP6_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ieee80211.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ieee80211.h
new file mode 100644
index 0000000..4e44f43
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ieee80211.h
@@ -0,0 +1,1161 @@
+#ifndef _IPXE_IEEE80211_H
+#define _IPXE_IEEE80211_H
+
+#include <stddef.h>
+#include <ipxe/if_ether.h>	/* for ETH_ALEN */
+#include <endian.h>
+
+/** @file
+ * Constants and data structures defined in IEEE 802.11, subsetted
+ * according to what iPXE knows how to use.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/* ---------- Maximum lengths of things ---------- */
+
+/**
+ * @defgroup ieee80211_maxlen Maximum lengths in the 802.11 protocol
+ * @{
+ */
+
+/** Maximum length of frame payload
+ *
+ * This does not include cryptographic overhead, which can be up to 20
+ * bytes, but it DOES include the 802.2 LLC/SNAP headers that are used
+ * on data frames (but not management frames).
+ */
+#define IEEE80211_MAX_DATA_LEN          2304
+
+/** Length of LLC/SNAP headers on data frames */
+#define IEEE80211_LLC_HEADER_LEN	8
+
+/** Maximum cryptographic overhead before encrypted data */
+#define IEEE80211_MAX_CRYPTO_HEADER	8
+
+/** Maximum cryptographic overhead after encrypted data
+ *
+ * This does not count the MIC in TKIP frames, since that is
+ * considered to be part of the MSDU and thus contributes to the size
+ * of the data field.
+ *
+ * It @e does count the MIC in CCMP frames, which is considered part
+ * of the MPDU (outside the data field).
+ */
+#define IEEE80211_MAX_CRYPTO_TRAILER    8
+
+/** Total maximum cryptographic overhead */
+#define IEEE80211_MAX_CRYPTO_OVERHEAD	16
+
+/** Bytes of network-layer data that can go into a regular data frame */
+#define IEEE80211_MAX_FRAME_DATA	2296
+
+/** Frame header length for frames we might work with
+ *
+ * QoS adds a two-byte field on top of this, and APs communicating
+ * with each other in Wireless Distribution System (WDS) mode add an
+ * extra 6-byte MAC address field, but we do not work with such
+ * frames.
+ */
+#define IEEE80211_TYP_FRAME_HEADER_LEN	24
+
+/** Theoretical maximum frame header length
+ *
+ * This includes the QoS and WDS Addr4 fields that we should never
+ * see.
+ */
+#define IEEE80211_MAX_FRAME_HEADER_LEN	32
+
+/** Maximum combined frame length
+ *
+ * The biggest frame will include 32 frame header bytes, 16 bytes of
+ * crypto overhead, and 2304 data bytes.
+ */
+#define IEEE80211_MAX_FRAME_LEN         2352
+
+/** Maximum length of an ESSID */
+#define IEEE80211_MAX_SSID_LEN          32
+
+/** @} */
+
+
+/* ---------- Frame Control defines ---------- */
+
+/**
+ * @defgroup ieee80211_fc 802.11 Frame Control field bits
+ * @{
+ */
+
+/** 802.11 Frame Control field, Version bitmask */
+#define IEEE80211_FC_VERSION	0x0003
+
+/** Expected value of Version bits in Frame Control */
+#define  IEEE80211_THIS_VERSION  0x0000
+
+
+/** 802.11 Frame Control field, Frame Type bitmask */
+#define IEEE80211_FC_TYPE	0x000C
+
+/** Type value for management (layer-2) frames */
+#define  IEEE80211_TYPE_MGMT     0x0000
+
+/** Type value for control (layer-1, hardware-managed) frames */
+#define  IEEE80211_TYPE_CTRL     0x0004
+
+/** Type value for data frames */
+#define  IEEE80211_TYPE_DATA     0x0008
+
+
+/** 802.11 Frame Control field, Frame Subtype bitmask */
+#define IEEE80211_FC_SUBTYPE	0x00F0
+
+/** Subtype value for association-request management frames
+ *
+ * Association request frames are sent after authentication from the
+ * client to the Access Point to establish the client as part of the
+ * Access Point's network.
+ */
+#define  IEEE80211_STYPE_ASSOC_REQ    0x0000
+
+/** Subtype value for association-response management frames
+ *
+ * Association response frames are sent by the Access Point to confirm
+ * or deny the association requested in an association request frame.
+ */
+#define  IEEE80211_STYPE_ASSOC_RESP   0x0010
+
+/** Subtype value for reassociation-request management frames
+ *
+ * Reassociation request frames are sent by clients wishing to change
+ * from one Access Point to another while roaming within the same
+ * extended network (same ESSID).
+ */
+#define  IEEE80211_STYPE_REASSOC_REQ  0x0020
+
+/** Subtype value for reassociation-response management frames
+ *
+ * Reassociation response frames are sent by the Access Point to
+ * confirm or deny the swap requested in a reassociation request
+ * frame.
+ */
+#define  IEEE80211_STYPE_REASSOC_RESP 0x0030
+
+/** Subtype value for probe-request management frames
+ *
+ * Probe request frames are sent by clients to request that all Access
+ * Points on the sending channel, or all belonging to a particular
+ * ESSID, identify themselves by BSSID, supported transfer rates, RF
+ * configuration, and other capabilities.
+ */
+#define  IEEE80211_STYPE_PROBE_REQ    0x0040
+
+/** Subtype value for probe-response management frames
+ *
+ * Probe response frames are sent by Access Points in response to
+ * probe request frames, providing the requested information.
+ */
+#define  IEEE80211_STYPE_PROBE_RESP   0x0050
+
+/** Subtype value for beacon management frames
+ *
+ * Beacon frames are sent by Access Points at regular intervals,
+ * usually ten per second, on the channel on which they communicate.
+ * They can be used to probe passively for access points on a channel
+ * where local regulatory restrictions prohibit active scanning, or
+ * due to their regularity as a mechanism to determine the fraction of
+ * packets that are being dropped.
+ */
+#define  IEEE80211_STYPE_BEACON       0x0080
+
+/** Subtype value for disassociation management frames
+ *
+ * Disassociation frames are sent by either a client or an Access
+ * Point to unequivocally terminate the association between the two.
+ * They may be sent by clients upon leaving the network, or by an
+ * Access Point upon reconfiguration, among other reasons; they are
+ * usually more "polite" than deauthentication frames.
+ */
+#define  IEEE80211_STYPE_DISASSOC     0x00A0
+
+/** Subtype value for authentication management frames
+ *
+ * Authentication frames are exchanged between a client and an Access
+ * Point before association may be performed. Confusingly, in the most
+ * common authentication method (Open System) no security tokens are
+ * exchanged at all. Modern 802.11 security handshaking takes place
+ * after association.
+ */
+#define  IEEE80211_STYPE_AUTH         0x00B0
+
+/** Subtype value for deauthentication management frames
+ *
+ * Deauthentication frames are sent by either a client or an Access
+ * Point to terminate the authentication (and therefore also the
+ * association) between the two. They are generally more forceful than
+ * disassociation frames, sent for such reasons as a failure to
+ * set up security properly after associating.
+ */
+#define  IEEE80211_STYPE_DEAUTH       0x00C0
+
+/** Subtype value for action management frames
+ *
+ * Action frames are used to implement spectrum management and QoS
+ * features that iPXE currently does not support.
+ */
+#define  IEEE80211_STYPE_ACTION	      0x00D0
+
+
+/** Subtype value for RTS (request to send) control frames */
+#define  IEEE80211_STYPE_RTS          0x00B0
+
+/** Subtype value for CTS (clear to send) control frames */
+#define  IEEE80211_STYPE_CTS          0x00C0
+
+/** Subtype value for ACK (acknowledgement) control frames */
+#define  IEEE80211_STYPE_ACK          0x00D0
+
+
+/** Subtype value for ordinary data frames, with no QoS or CF add-ons */
+#define  IEEE80211_STYPE_DATA         0x0000
+
+/** Subtype value for data frames containing no data */
+#define  IEEE80211_STYPE_NODATA       0x0040
+
+
+/** 802.11 Frame Control field: To Data System flag
+ *
+ * This is set on data frames sent to an Access Point.
+ */
+#define IEEE80211_FC_TODS       0x0100
+
+/** 802.11 Frame Control field: From Data System flag
+ *
+ * This is set on data frames sent from an Access Point. If both TODS
+ * and FROMDS are set, the frame header is a 4-address format used for
+ * inter-Access Point communication.
+ */
+#define IEEE80211_FC_FROMDS     0x0200
+
+/** 802.11 Frame Control field: More Fragments flag */
+#define IEEE80211_FC_MORE_FRAG  0x0400
+
+/** 802.11 Frame Control field: Retransmission flag */
+#define IEEE80211_FC_RETRY      0x0800
+
+/** 802.11 Frame Control field: Power Managed flag
+ *
+ * This is set on any frame sent by a low-power station that will go
+ * into a power-saving mode immediately after this frame. Access
+ * Points are not allowed to act as low-power stations.
+ */
+#define IEEE80211_FC_PWR_MGMT   0x1000
+
+/** 802.11 Frame Control field: More Data flag
+ *
+ * This is set on any frame sent by a station that has more data
+ * queued to be sent than is in the frame.
+ */
+#define IEEE80211_FC_MORE_DATA  0x2000
+
+/** 802.11 Frame Control field: Protected flag
+ *
+ * This is set on frames in which data is encrypted (by any method).
+ */
+#define IEEE80211_FC_PROTECTED  0x4000
+
+/** 802.11 Frame Control field: Ordered flag [?] */
+#define IEEE80211_FC_ORDER      0x8000
+
+/** @} */
+
+
+/* ---------- Sequence Control defines ---------- */
+
+/**
+ * @defgroup ieee80211_seq 802.11 Sequence Control field handling
+ * @{
+ */
+
+/** Extract sequence number from 802.11 Sequence Control field */
+#define IEEE80211_SEQNR( seq )		( ( seq ) >> 4 )
+
+/** Extract fragment number from 802.11 Sequence Control field */
+#define IEEE80211_FRAG( seq )		( ( seq ) & 0x000F )
+
+/** Make 802.11 Sequence Control field from sequence and fragment numbers */
+#define IEEE80211_MAKESEQ( seqnr, frag )	\
+	( ( ( ( seqnr ) & 0xFFF ) << 4 ) | ( ( frag ) & 0xF ) )
+
+/** @} */
+
+
+/* ---------- Frame header formats ---------- */
+
+/**
+ * @defgroup ieee80211_hdr 802.11 frame header formats
+ * @{
+ */
+
+/** An 802.11 data or management frame without QoS or WDS header fields */
+struct ieee80211_frame
+{
+	u16 fc;			/**< 802.11 Frame Control field */
+	u16 duration;		/**< Microseconds to reserve link */
+	u8 addr1[ETH_ALEN];	/**< Address 1 (immediate receiver) */
+	u8 addr2[ETH_ALEN];	/**< Address 2 (immediate sender) */
+	u8 addr3[ETH_ALEN];	/**< Address 3 (often "forward to") */
+	u16 seq;		/**< 802.11 Sequence Control field */
+	u8 data[0];		/**< Beginning of frame data */
+} __attribute__((packed));
+
+/** The 802.2 LLC/SNAP header sent before actual data in a data frame
+ *
+ * This header is not acknowledged in the 802.11 standard at all; it
+ * is treated just like data for MAC-layer purposes, including
+ * fragmentation and encryption. It is actually two headers
+ * concatenated: a three-byte 802.2 LLC header indicating Subnetwork
+ * Accesss Protocol (SNAP) in both source and destination Service
+ * Access Point (SAP) fields, and a five-byte SNAP header indicating a
+ * zero OUI and two-byte Ethernet protocol type field.
+ *
+ * Thus, an eight-byte header in which six of the bytes are redundant.
+ * Lovely, isn't it?
+ */
+struct ieee80211_llc_snap_header
+{
+	/* LLC part: */
+	u8 dsap;		/**< Destination SAP ID */
+	u8 ssap;		/**< Source SAP ID */
+	u8 ctrl;		/**< Control information */
+
+	/* SNAP part: */
+	u8 oui[3];		/**< Organization code, usually 0 */
+	u16 ethertype;		/**< Ethernet Type field */
+} __attribute__((packed));
+
+/** Value for DSAP field in 802.2 LLC header for 802.11 frames: SNAP */
+#define IEEE80211_LLC_DSAP	0xAA
+
+/** Value for SSAP field in 802.2 LLC header for 802.11 frames: SNAP */
+#define IEEE80211_LLC_SSAP	0xAA
+
+/** Value for control field in 802.2 LLC header for 802.11 frames
+ *
+ * "Unnumbered Information".
+ */
+#define IEEE80211_LLC_CTRL	0x03
+
+
+/** 16-byte RTS frame format, with abbreviated header */
+struct ieee80211_rts
+{
+	u16 fc;			/**< 802.11 Frame Control field */
+	u16 duration;		/**< Microseconds to reserve link */
+	u8 addr1[ETH_ALEN];	/**< Address 1 (immediate receiver) */
+	u8 addr2[ETH_ALEN];	/**< Address 2 (immediate sender) */
+} __attribute__((packed));
+
+/** Length of 802.11 RTS control frame */
+#define IEEE80211_RTS_LEN	16
+
+/** 10-byte CTS or ACK frame format, with abbreviated header */
+struct ieee80211_cts_or_ack
+{
+	u16 fc;			/**< 802.11 Frame Control field */
+	u16 duration;		/**< Microseconds to reserve link */
+	u8 addr1[ETH_ALEN];	/**< Address 1 (immediate receiver) */
+} __attribute__((packed));
+
+#define ieee80211_cts ieee80211_cts_or_ack
+#define ieee80211_ack ieee80211_cts_or_ack
+
+/** Length of 802.11 CTS control frame */
+#define IEEE80211_CTS_LEN	10
+
+/** Length of 802.11 ACK control frame */
+#define IEEE80211_ACK_LEN	10
+
+/** @} */
+
+
+/* ---------- Capability bits, status and reason codes ---------- */
+
+/**
+ * @defgroup ieee80211_capab 802.11 management frame capability field bits
+ * @{
+ */
+
+/** Set if using an Access Point (managed mode) */
+#define IEEE80211_CAPAB_MANAGED       0x0001
+
+/** Set if operating in IBSS (no-AP, "Ad-Hoc") mode */
+#define IEEE80211_CAPAB_ADHOC         0x0002
+
+/** Set if we support Contention-Free Period operation */
+#define IEEE80211_CAPAB_CFPOLL        0x0004
+
+/** Set if we wish to be polled for Contention-Free operation */
+#define IEEE80211_CAPAB_CFPR          0x0008
+
+/** Set if the network is encrypted (by any method) */
+#define IEEE80211_CAPAB_PRIVACY       0x0010
+
+/** Set if PHY supports short preambles on 802.11b */
+#define IEEE80211_CAPAB_SHORT_PMBL    0x0020
+
+/** Set if PHY supports PBCC modulation */
+#define IEEE80211_CAPAB_PBCC          0x0040
+
+/** Set if we support Channel Agility */
+#define IEEE80211_CAPAB_CHAN_AGILITY  0x0080
+
+/** Set if we support spectrum management (DFS and TPC) on the 5GHz band */
+#define IEEE80211_CAPAB_SPECTRUM_MGMT 0x0100
+
+/** Set if we support Quality of Service enhancements */
+#define IEEE80211_CAPAB_QOS           0x0200
+
+/** Set if PHY supports short slot time on 802.11g */
+#define IEEE80211_CAPAB_SHORT_SLOT    0x0400
+
+/** Set if PHY supports APSD option */
+#define IEEE80211_CAPAB_APSD          0x0800
+
+/** Set if PHY supports DSSS/OFDM modulation (one way of 802.11 b/g mixing) */
+#define IEEE80211_CAPAB_DSSS_OFDM     0x2000
+
+/** Set if we support delayed block ACK */
+#define IEEE80211_CAPAB_DELAYED_BACK  0x4000
+
+/** Set if we support immediate block ACK */
+#define IEEE80211_CAPAB_IMMED_BACK    0x8000
+
+/** @} */
+
+
+/**
+ * @defgroup ieee80211_status 802.11 status codes
+ *
+ * These are returned to indicate an immediate denial of
+ * authentication or association. In iPXE, the lower 5 bits of the
+ * status code are encoded into the file-unique portion of an error
+ * code, the ERRFILE portion is always @c ERRFILE_net80211, and the
+ * POSIX error code is @c ECONNREFUSED for status 0-31 or @c
+ * EHOSTUNREACH for status 32-63.
+ *
+ * For a complete table with non-abbreviated error messages, see IEEE
+ * Std 802.11-2007, Table 7-23, p.94.
+ *
+ * @{
+ */
+
+#define IEEE80211_STATUS_SUCCESS		0
+#define IEEE80211_STATUS_FAILURE		1
+#define IEEE80211_STATUS_CAPAB_UNSUPP		10
+#define IEEE80211_STATUS_REASSOC_INVALID	11
+#define IEEE80211_STATUS_ASSOC_DENIED		12
+#define IEEE80211_STATUS_AUTH_ALGO_UNSUPP	13
+#define IEEE80211_STATUS_AUTH_SEQ_INVALID	14
+#define IEEE80211_STATUS_AUTH_CHALL_INVALID	15
+#define IEEE80211_STATUS_AUTH_TIMEOUT		16
+#define IEEE80211_STATUS_ASSOC_NO_ROOM		17
+#define IEEE80211_STATUS_ASSOC_NEED_RATE	18
+#define IEEE80211_STATUS_ASSOC_NEED_SHORT_PMBL	19
+#define IEEE80211_STATUS_ASSOC_NEED_PBCC	20
+#define IEEE80211_STATUS_ASSOC_NEED_CHAN_AGILITY 21
+#define IEEE80211_STATUS_ASSOC_NEED_SPECTRUM_MGMT 22
+#define IEEE80211_STATUS_ASSOC_BAD_POWER	23
+#define IEEE80211_STATUS_ASSOC_BAD_CHANNELS	24
+#define IEEE80211_STATUS_ASSOC_NEED_SHORT_SLOT	25
+#define IEEE80211_STATUS_ASSOC_NEED_DSSS_OFDM	26
+#define IEEE80211_STATUS_QOS_FAILURE		32
+#define IEEE80211_STATUS_QOS_NO_ROOM		33
+#define IEEE80211_STATUS_LINK_IS_HORRIBLE	34
+#define IEEE80211_STATUS_ASSOC_NEED_QOS		35
+#define IEEE80211_STATUS_REQUEST_DECLINED	37
+#define IEEE80211_STATUS_REQUEST_INVALID	38
+#define IEEE80211_STATUS_TS_NOT_CREATED_AGAIN	39
+#define IEEE80211_STATUS_INVALID_IE		40
+#define IEEE80211_STATUS_GROUP_CIPHER_INVALID	41
+#define IEEE80211_STATUS_PAIR_CIPHER_INVALID	42
+#define IEEE80211_STATUS_AKMP_INVALID		43
+#define IEEE80211_STATUS_RSN_VERSION_UNSUPP	44
+#define IEEE80211_STATUS_RSN_CAPAB_INVALID	45
+#define IEEE80211_STATUS_CIPHER_REJECTED	46
+#define IEEE80211_STATUS_TS_NOT_CREATED_WAIT	47
+#define IEEE80211_STATUS_DIRECT_LINK_FORBIDDEN	48
+#define IEEE80211_STATUS_DEST_NOT_PRESENT	49
+#define IEEE80211_STATUS_DEST_NOT_QOS		50
+#define IEEE80211_STATUS_ASSOC_LISTEN_TOO_HIGH	51
+
+/** @} */
+
+
+
+/**
+ * @defgroup ieee80211_reason 802.11 reason codes
+ *
+ * These are returned to indicate the reason for a deauthentication or
+ * disassociation sent (usually) after authentication or association
+ * had succeeded.  In iPXE, the lower 5 bits of the reason code are
+ * encoded into the file-unique portion of an error code, the ERRFILE
+ * portion is always @c ERRFILE_net80211, and the POSIX error code is
+ * @c ECONNRESET for reason 0-31 or @c ENETRESET for reason 32-63.
+ *
+ * For a complete table with non-abbreviated error messages, see IEEE
+ * Std 802.11-2007, Table 7-22, p.92.
+ *
+ * @{
+ */
+
+#define IEEE80211_REASON_NONE			0
+#define IEEE80211_REASON_UNSPECIFIED		1
+#define IEEE80211_REASON_AUTH_NO_LONGER_VALID	2
+#define IEEE80211_REASON_LEAVING		3
+#define IEEE80211_REASON_INACTIVITY		4
+#define IEEE80211_REASON_OUT_OF_RESOURCES	5
+#define IEEE80211_REASON_NEED_AUTH		6
+#define IEEE80211_REASON_NEED_ASSOC		7
+#define IEEE80211_REASON_LEAVING_TO_ROAM	8
+#define IEEE80211_REASON_REASSOC_INVALID	9
+#define IEEE80211_REASON_BAD_POWER		10
+#define IEEE80211_REASON_BAD_CHANNELS		11
+#define IEEE80211_REASON_INVALID_IE		13
+#define IEEE80211_REASON_MIC_FAILURE		14
+#define IEEE80211_REASON_4WAY_TIMEOUT		15
+#define IEEE80211_REASON_GROUPKEY_TIMEOUT	16
+#define IEEE80211_REASON_4WAY_INVALID		17
+#define IEEE80211_REASON_GROUP_CIPHER_INVALID	18
+#define IEEE80211_REASON_PAIR_CIPHER_INVALID	19
+#define IEEE80211_REASON_AKMP_INVALID		20
+#define IEEE80211_REASON_RSN_VERSION_INVALID	21
+#define IEEE80211_REASON_RSN_CAPAB_INVALID	22
+#define IEEE80211_REASON_8021X_FAILURE		23
+#define IEEE80211_REASON_CIPHER_REJECTED	24
+#define IEEE80211_REASON_QOS_UNSPECIFIED	32
+#define IEEE80211_REASON_QOS_OUT_OF_RESOURCES	33
+#define IEEE80211_REASON_LINK_IS_HORRIBLE	34
+#define IEEE80211_REASON_INVALID_TXOP		35
+#define IEEE80211_REASON_REQUESTED_LEAVING	36
+#define IEEE80211_REASON_REQUESTED_NO_USE	37
+#define IEEE80211_REASON_REQUESTED_NEED_SETUP	38
+#define IEEE80211_REASON_REQUESTED_TIMEOUT	39
+#define IEEE80211_REASON_CIPHER_UNSUPPORTED	45
+
+/** @} */
+
+/* ---------- Information element declarations ---------- */
+
+/**
+ * @defgroup ieee80211_ie 802.11 information elements
+ *
+ * Many management frames include a section that amounts to a
+ * concatenation of these information elements, so that the sender can
+ * choose which information to send and the receiver can ignore the
+ * parts it doesn't understand. Each IE contains a two-byte header,
+ * one byte ID and one byte length, followed by IE-specific data. The
+ * length does not include the two-byte header. Information elements
+ * are required to be sorted by ID, but iPXE does not require that in
+ * those it receives.
+ *
+ * This group also includes a few inline functions to simplify common
+ * tasks in IE processing.
+ *
+ * @{
+ */
+
+/** Generic 802.11 information element header */
+struct ieee80211_ie_header {
+	u8 id;			/**< Information element ID */
+	u8 len;			/**< Information element length */
+} __attribute__ ((packed));
+
+
+/** 802.11 SSID information element */
+struct ieee80211_ie_ssid {
+	u8 id;			/**< SSID ID: 0 */
+	u8 len;			/**< SSID length */
+	char ssid[0];		/**< SSID data, not NUL-terminated */
+} __attribute__ ((packed));
+
+/** Information element ID for SSID information element */
+#define IEEE80211_IE_SSID	0
+
+
+/** 802.11 rates information element
+ *
+ * The first 8 rates go in an IE of type RATES (1), and any more rates
+ * go in one of type EXT_RATES (50). Each rate is a byte with the low
+ * 7 bits equal to the rate in units of 500 kbps, and the high bit set
+ * if and only if the rate is "basic" (must be supported by all
+ * connected stations).
+ */
+struct ieee80211_ie_rates {
+	u8 id;			/**< Rates ID: 1 or 50 */
+	u8 len;			/**< Number of rates */
+	u8 rates[0];		/**< Rates data, one rate per byte */
+} __attribute__ ((packed));
+
+/** Information element ID for rates information element */
+#define IEEE80211_IE_RATES	1
+
+/** Information element ID for extended rates information element */
+#define IEEE80211_IE_EXT_RATES	50
+
+
+/** 802.11 Direct Spectrum parameter information element
+ *
+ * This just contains the channel number. It has the fancy name
+ * because IEEE 802.11 also defines a frequency-hopping PHY that
+ * changes channels at regular intervals following a predetermined
+ * pattern; in practice nobody uses the FH PHY.
+ */
+struct ieee80211_ie_ds_param {
+	u8 id;			/**< DS parameter ID: 3 */
+	u8 len;			/**< DS parameter length: 1 */
+	u8 current_channel;	/**< Current channel number, 1-14 */
+} __attribute__ ((packed));
+
+/** Information element ID for Direct Spectrum parameter information element */
+#define IEEE80211_IE_DS_PARAM	3
+
+
+/** 802.11 Country information element regulatory extension triplet */
+struct ieee80211_ie_country_ext_triplet {
+	u8 reg_ext_id;		/**< Regulatory extension ID */
+	u8 reg_class_id;	/**< Regulatory class ID */
+	u8 coverage_class;	/**< Coverage class */
+} __attribute__ ((packed));
+
+/** 802.11 Country information element regulatory band triplet */
+struct ieee80211_ie_country_band_triplet {
+	u8 first_channel;	/**< Channel number for first channel in band */
+	u8 nr_channels;		/**< Number of contiguous channels in band */
+	u8 max_txpower;		/**< Maximum TX power in dBm */
+} __attribute__ ((packed));
+
+/** 802.11 Country information element regulatory triplet
+ *
+ * It is a band triplet if the first byte is 200 or less, and a
+ * regulatory extension triplet otherwise.
+ */
+union ieee80211_ie_country_triplet {
+	/** Differentiator between band and ext triplets */
+	u8 first;
+
+	/** Information about a band of channels */
+	struct ieee80211_ie_country_band_triplet band;
+
+	/** Regulatory extension information */
+	struct ieee80211_ie_country_ext_triplet ext;
+};
+
+/** 802.11 Country information element
+ *
+ * This contains some data about RF regulations.
+ */
+struct ieee80211_ie_country {
+	u8 id;			/**< Country information ID: 7 */
+	u8 len;			/**< Country information length: varies */
+	char name[2];		/**< ISO Alpha2 country code */
+	char in_out;		/**< 'I' for indoor, 'O' for outdoor */
+
+	/** List of regulatory triplets */
+	union ieee80211_ie_country_triplet triplet[0];
+} __attribute__ ((packed));
+
+/** Information element ID for Country information element */
+#define IEEE80211_IE_COUNTRY	7
+
+
+/** 802.11 Request information element
+ *
+ * This contains a list of information element types we would like to
+ * be included in probe response frames.
+ */
+struct ieee80211_ie_request {
+	u8 id;			/**< Request ID: 10 */
+	u8 len;			/**< Number of IEs requested */
+	u8 request[0];		/**< List of IEs requested */
+} __attribute__ ((packed));
+
+/** Information element ID for Request information element */
+#define IEEE80211_IE_REQUEST	10
+
+
+/** 802.11 Challenge Text information element
+ *
+ * This is used in authentication frames under Shared Key
+ * authentication.
+ */
+struct ieee80211_ie_challenge_text {
+	u8 id;			/**< Challenge Text ID: 16 */
+	u8 len;			/**< Challenge Text length: usually 128 */
+	u8 challenge_text[0];	/**< Challenge Text data */
+} __attribute__ ((packed));
+
+/** Information element ID for Challenge Text information element */
+#define IEEE80211_IE_CHALLENGE_TEXT	16
+
+
+/** 802.11 Power Constraint information element
+ *
+ * This is used to specify an additional power limitation on top of
+ * the Country requirements.
+ */
+struct ieee80211_ie_power_constraint {
+	u8 id;			/**< Power Constraint ID: 52 */
+	u8 len;			/**< Power Constraint length: 1 */
+	u8 power_constraint;	/**< Decrease in allowed TX power, dBm */
+} __attribute__ ((packed));
+
+/** Information element ID for Power Constraint information element */
+#define IEEE80211_IE_POWER_CONSTRAINT	52
+
+
+/** 802.11 Power Capability information element
+ *
+ * This is used in association request frames to indicate the extremes
+ * of our TX power abilities. It is required only if we indicate
+ * support for spectrum management.
+ */
+struct ieee80211_ie_power_capab {
+	u8 id;			/**< Power Capability ID: 33 */
+	u8 len;			/**< Power Capability length: 2 */
+	u8 min_txpower;		/**< Minimum possible TX power, dBm */
+	u8 max_txpower;		/**< Maximum possible TX power, dBm */
+} __attribute__ ((packed));
+
+/** Information element ID for Power Capability information element */
+#define IEEE80211_IE_POWER_CAPAB	33
+
+
+/** 802.11 Channels information element channel band tuple */
+struct ieee80211_ie_channels_channel_band {
+	u8 first_channel;	/**< Channel number of first channel in band */
+	u8 nr_channels;		/**< Number of channels in band */
+} __attribute__ ((packed));
+
+/** 802.11 Channels information element
+ *
+ * This is used in association frames to indicate the channels we can
+ * use. It is required only if we indicate support for spectrum
+ * management.
+ */
+struct ieee80211_ie_channels {
+	u8 id;			/**< Channels ID: 36 */
+	u8 len;			/**< Channels length: 2 */
+
+	/** List of (start, length) channel bands we can use */
+	struct ieee80211_ie_channels_channel_band channels[0];
+} __attribute__ ((packed));
+
+/** Information element ID for Channels information element */
+#define IEEE80211_IE_CHANNELS	36
+
+
+/** 802.11 ERP Information information element
+ *
+ * This is used to communicate some PHY-level flags.
+ */
+struct ieee80211_ie_erp_info {
+	u8 id;			/**< ERP Information ID: 42 */
+	u8 len;			/**< ERP Information length: 1 */
+	u8 erp_info;		/**< ERP flags */
+} __attribute__ ((packed));
+
+/** Information element ID for ERP Information information element */
+#define IEEE80211_IE_ERP_INFO	42
+
+/** ERP information element: Flag set if 802.11b stations are present */
+#define  IEEE80211_ERP_NONERP_PRESENT	0x01
+
+/** ERP information element: Flag set if CTS protection must be used */
+#define  IEEE80211_ERP_USE_PROTECTION	0x02
+
+/** ERP information element: Flag set if long preambles must be used */
+#define  IEEE80211_ERP_BARKER_LONG	0x04
+
+
+/** 802.11 Robust Security Network ("WPA") information element
+ *
+ * Showing once again a striking clarity of design, the IEEE folks put
+ * dynamically-sized data in the middle of this structure. As such,
+ * the below structure definition only works for IEs we create
+ * ourselves, which always have one pairwise cipher and one AKM;
+ * received IEs should be parsed piecemeal.
+ *
+ * Also inspired was IEEE's choice of 16-bit fields to count the
+ * number of 4-byte elements in a structure with a maximum length of
+ * 255 bytes.
+ *
+ * Many fields reference a cipher or authentication-type ID; this is a
+ * three-byte OUI followed by one byte identifying the cipher with
+ * respect to that OUI. For all standard ciphers the OUI is 00:0F:AC,
+ * except in old-style WPA IEs encapsulated in vendor-specific IEs,
+ * where it's 00:50:F2.
+ */
+struct ieee80211_ie_rsn {
+	/** Information element ID */
+	u8 id;
+
+	/** Information element length */
+	u8 len;
+
+	/** RSN information element version */
+	u16 version;
+
+	/** Cipher ID for the cipher used in multicast/broadcast frames */
+	u32 group_cipher;
+
+	/** Number of unicast ciphers supported */
+	u16 pairwise_count;
+
+	/** List of cipher IDs for supported unicast frame ciphers */
+	u32 pairwise_cipher[1];
+
+	/** Number of authentication types supported */
+	u16 akm_count;
+
+	/** List of authentication type IDs for supported types */
+	u32 akm_list[1];
+
+	/** Security capabilities field (RSN only) */
+	u16 rsn_capab;
+
+	/** Number of PMKIDs included (present only in association frames) */
+	u16 pmkid_count;
+
+	/** List of PMKIDs included, each a 16-byte SHA1 hash */
+	u8 pmkid_list[0];
+} __attribute__((packed));
+
+/** Information element ID for Robust Security Network information element */
+#define IEEE80211_IE_RSN	48
+
+/** Calculate necessary size of RSN information element
+ *
+ * @v npair	Number of pairwise ciphers supported
+ * @v nauth	Number of authentication types supported
+ * @v npmkid	Number of PMKIDs to include
+ * @v is_rsn	If TRUE, calculate RSN IE size; if FALSE, calculate WPA IE size
+ * @ret size	Necessary size of IE, including header bytes
+ */
+static inline size_t ieee80211_rsn_size ( int npair, int nauth, int npmkid,
+					  int rsn_ie ) {
+	return 16 + 4 * ( npair + nauth ) + 16 * npmkid - 4 * ! rsn_ie;
+}
+
+/** Make OUI plus type byte into 32-bit integer for easy comparison */
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define _MKOUI( a, b, c, t )	\
+		( ( ( a ) << 24 ) | ( ( b ) << 16 ) | ( ( c ) << 8 ) | ( d ) )
+#define  OUI_ORG_MASK		0xFFFFFF00
+#define  OUI_TYPE_MASK		0x000000FF
+#else
+#define _MKOUI( a, b, c, t )	\
+		( ( ( t ) << 24 ) | ( ( c ) << 16 ) | ( ( b ) << 8 ) | ( a ) )
+#define  OUI_ORG_MASK		0x00FFFFFF
+#define  OUI_TYPE_MASK		0xFF000000
+#endif
+
+/** Organization part for OUIs in standard RSN IE */
+#define  IEEE80211_RSN_OUI	_MKOUI ( 0x00, 0x0F, 0xAC, 0 )
+
+/** Organization part for OUIs in old WPA IE */
+#define  IEEE80211_WPA_OUI	_MKOUI ( 0x00, 0x50, 0xF2, 0 )
+
+/** Old vendor-type WPA IE OUI type + subtype */
+#define  IEEE80211_WPA_OUI_VEN	_MKOUI ( 0x00, 0x50, 0xF2, 0x01 )
+
+
+/** 802.11 RSN IE: expected version number */
+#define  IEEE80211_RSN_VERSION		1
+
+/** 802.11 RSN IE: cipher type for 40-bit WEP */
+#define  IEEE80211_RSN_CTYPE_WEP40	_MKOUI ( 0, 0, 0, 0x01 )
+
+/** 802.11 RSN IE: cipher type for 104-bit WEP */
+#define  IEEE80211_RSN_CTYPE_WEP104	_MKOUI ( 0, 0, 0, 0x05 )
+
+/** 802.11 RSN IE: cipher type for TKIP ("WPA") */
+#define  IEEE80211_RSN_CTYPE_TKIP	_MKOUI ( 0, 0, 0, 0x02 )
+
+/** 802.11 RSN IE: cipher type for CCMP ("WPA2") */
+#define  IEEE80211_RSN_CTYPE_CCMP	_MKOUI ( 0, 0, 0, 0x04 )
+
+/** 802.11 RSN IE: cipher type for "use group"
+ *
+ * This can only appear as a pairwise cipher, and means unicast frames
+ * should be encrypted in the same way as broadcast/multicast frames.
+ */
+#define  IEEE80211_RSN_CTYPE_USEGROUP	_MKOUI ( 0, 0, 0, 0x00 )
+
+/** 802.11 RSN IE: auth method type for using an 802.1X server */
+#define  IEEE80211_RSN_ATYPE_8021X	_MKOUI ( 0, 0, 0, 0x01 )
+
+/** 802.11 RSN IE: auth method type for using a pre-shared key */
+#define  IEEE80211_RSN_ATYPE_PSK	_MKOUI ( 0, 0, 0, 0x02 )
+
+/** 802.11 RSN IE capabilities: AP supports pre-authentication */
+#define  IEEE80211_RSN_CAPAB_PREAUTH	0x001
+
+/** 802.11 RSN IE capabilities: Node has conflict between TKIP and WEP
+ *
+ * This is a legacy issue; APs always set it to 0, and iPXE sets it to
+ * 0.
+ */
+#define  IEEE80211_RSN_CAPAB_NO_PAIRWISE 0x002
+
+/** 802.11 RSN IE capabilities: Number of PTKSA replay counters
+ *
+ * A value of 0 means one replay counter, 1 means two, 2 means four,
+ * and 3 means sixteen.
+ */
+#define  IEEE80211_RSN_CAPAB_PTKSA_REPLAY 0x00C
+
+/** 802.11 RSN IE capabilities: Number of GTKSA replay counters
+ *
+ * A value of 0 means one replay counter, 1 means two, 2 means four,
+ * and 3 means sixteen.
+ */
+#define  IEEE80211_RSN_CAPAB_GTKSA_REPLAY 0x030
+
+/** 802.11 RSN IE capabilities: PeerKey Handshaking is suported */
+#define  IEEE80211_RSN_CAPAB_PEERKEY	0x200
+
+
+/** 802.11 RSN IE capabilities: One replay counter
+ *
+ * This should be AND'ed with @c IEEE80211_RSN_CAPAB_PTKSA_REPLAY or
+ * @c IEEE80211_RSN_CAPAB_GTKSA_REPLAY (or both) to produce a value
+ * which can be OR'ed into the capabilities field.
+ */
+#define IEEE80211_RSN_1_CTR		0x000
+
+/** 802.11 RSN IE capabilities: Two replay counters */
+#define IEEE80211_RSN_2_CTR		0x014
+
+/** 802.11 RSN IE capabilities: Four replay counters */
+#define IEEE80211_RSN_4_CTR		0x028
+
+/** 802.11 RSN IE capabilities: 16 replay counters */
+#define IEEE80211_RSN_16_CTR		0x03C
+
+
+/** 802.11 Vendor Specific information element
+ *
+ * One often sees the RSN IE masquerading as vendor-specific on
+ * devices that were produced prior to 802.11i (the WPA amendment)
+ * being finalized.
+ */
+struct ieee80211_ie_vendor {
+	u8 id;			/**< Vendor-specific ID: 221 */
+	u8 len;			/**< Vendor-specific length: variable */
+	u32 oui;		/**< OUI and vendor-specific type byte */
+	u8 data[0];		/**< Vendor-specific data */
+} __attribute__ ((packed));
+
+/** Information element ID for Vendor Specific information element */
+#define IEEE80211_IE_VENDOR	221
+
+
+
+
+/** Any 802.11 information element
+ *
+ * This is formatted for ease of use, so IEs with complex structures
+ * get referenced in full, while those with only one byte of data or a
+ * simple array are pulled in to avoid a layer of indirection like
+ * ie->channels.channels[0].
+ */
+union ieee80211_ie
+{
+	/** Generic and simple information element info */
+	struct {
+		u8 id;		/**< Information element ID */
+		u8 len;		/**< Information element data length */
+		union {
+			char ssid[0];	/**< SSID text */
+			u8 rates[0];	/**< Rates data */
+			u8 request[0];	/**< Request list */
+			u8 challenge_text[0]; /**< Challenge text data */
+			u8 power_constraint; /**< Power constraint, dBm */
+			u8 erp_info;	/**< ERP information flags */
+			/** List of channels */
+			struct ieee80211_ie_channels_channel_band channels[0];
+		};
+	};
+
+	/** DS parameter set */
+	struct ieee80211_ie_ds_param ds_param;
+
+	/** Country information */
+	struct ieee80211_ie_country country;
+
+	/** Power capability */
+	struct ieee80211_ie_power_capab power_capab;
+
+	/** Security information */
+	struct ieee80211_ie_rsn rsn;
+
+	/** Vendor-specific */
+	struct ieee80211_ie_vendor vendor;
+};
+
+/** Check that 802.11 information element is bounded by buffer
+ *
+ * @v ie	Information element
+ * @v end	End of buffer in which information element is stored
+ * @ret ok	TRUE if the IE is completely contained within the buffer
+ */
+static inline int ieee80211_ie_bound ( union ieee80211_ie *ie, void *end )
+{
+	void *iep = ie;
+	return ( iep + 2 <= end && iep + 2 + ie->len <= end );
+}
+
+/** Advance to next 802.11 information element
+ *
+ * @v ie	Current information element pointer
+ * @v end	Pointer to first byte not in information element space
+ * @ret next	Pointer to next information element, or NULL if no more
+ *
+ * When processing received IEs, @a end should be set to the I/O
+ * buffer tail pointer; when marshalling IEs for sending, @a end
+ * should be NULL.
+ */
+static inline union ieee80211_ie * ieee80211_next_ie ( union ieee80211_ie *ie,
+						       void *end )
+{
+	void *next_ie_byte = ( void * ) ie + ie->len + 2;
+	union ieee80211_ie *next_ie = next_ie_byte;
+
+	if ( ! end )
+		return next_ie;
+
+	if ( ieee80211_ie_bound ( next_ie, end ) )
+		return next_ie;
+
+	return NULL;
+}
+
+/** @} */
+
+
+/* ---------- Management frame data formats ---------- */
+
+/**
+ * @defgroup ieee80211_mgmt_data Management frame data payloads
+ * @{
+ */
+
+/** Beacon or probe response frame data */
+struct ieee80211_beacon_or_probe_resp
+{
+	/** 802.11 TSFT value at frame send */
+	u64 timestamp;
+
+	/** Interval at which beacons are sent, in units of 1024 us */
+	u16 beacon_interval;
+
+	/** Capability flags */
+	u16 capability;
+
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+#define ieee80211_beacon	ieee80211_beacon_or_probe_resp
+#define ieee80211_probe_resp	ieee80211_beacon_or_probe_resp
+
+/** Disassociation or deauthentication frame data */
+struct ieee80211_disassoc_or_deauth
+{
+	/** Reason code */
+	u16 reason;
+} __attribute__((packed));
+
+#define ieee80211_disassoc	ieee80211_disassoc_or_deauth
+#define ieee80211_deauth	ieee80211_disassoc_or_deauth
+
+/** Association request frame data */
+struct ieee80211_assoc_req
+{
+	/** Capability flags */
+	u16 capability;
+
+	/** Interval at which we wake up, in units of the beacon interval */
+	u16 listen_interval;
+
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+/** Association or reassociation response frame data */
+struct ieee80211_assoc_or_reassoc_resp
+{
+	/** Capability flags */
+	u16 capability;
+
+	/** Status code */
+	u16 status;
+
+	/** Association ID */
+	u16 aid;
+
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+#define ieee80211_assoc_resp	ieee80211_assoc_or_reassoc_resp
+#define ieee80211_reassoc_resp	ieee80211_assoc_or_reassoc_resp
+
+/** Reassociation request frame data */
+struct ieee80211_reassoc_req
+{
+	/** Capability flags */
+	u16 capability;
+
+	/** Interval at which we wake up, in units of the beacon interval */
+	u16 listen_interval;
+
+	/** MAC address of current Access Point */
+	u8 current_addr[ETH_ALEN];
+
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+/** Probe request frame data */
+struct ieee80211_probe_req
+{
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+/** Authentication frame data */
+struct ieee80211_auth
+{
+	/** Authentication algorithm (Open System or Shared Key) */
+	u16 algorithm;
+
+	/** Sequence number of this frame; first from client to AP is 1 */
+	u16 tx_seq;
+
+	/** Status code */
+	u16 status;
+
+	/** List of information elements */
+	union ieee80211_ie info_element[0];
+} __attribute__((packed));
+
+/** Open System authentication algorithm */
+#define IEEE80211_AUTH_OPEN_SYSTEM  0
+
+/** Shared Key authentication algorithm */
+#define IEEE80211_AUTH_SHARED_KEY   1
+
+/** @} */
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_arp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_arp.h
new file mode 100644
index 0000000..fd36e9c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_arp.h
@@ -0,0 +1,102 @@
+#ifndef	_IPXE_IF_ARP_H
+#define	_IPXE_IF_ARP_H
+
+/** @file
+ *
+ * Address Resolution Protocol constants and types
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM	0		/**< from KA9Q: NET/ROM pseudo	*/
+#define ARPHRD_ETHER 	1		/**< Ethernet 10Mbps		*/
+#define	ARPHRD_EETHER	2		/**< Experimental Ethernet	*/
+#define	ARPHRD_AX25	3		/**< AX.25 Level 2		*/
+#define	ARPHRD_PRONET	4		/**< PROnet token ring		*/
+#define	ARPHRD_CHAOS	5		/**< Chaosnet			*/
+#define	ARPHRD_IEEE802	6		/**< IEEE 802.2 Ethernet/TR/TB	*/
+#define	ARPHRD_ARCNET	7		/**< ARCnet			*/
+#define	ARPHRD_APPLETLK	8		/**< APPLEtalk			*/
+#define ARPHRD_DLCI	15		/**< Frame Relay DLCI		*/
+#define ARPHRD_ATM	19		/**< ATM 			*/
+#define ARPHRD_METRICOM	23		/**< Metricom STRIP (new IANA id) */
+#define	ARPHRD_IEEE1394	24		/**< IEEE 1394 IPv4 - RFC 2734	*/
+#define ARPHRD_EUI64	27		/**< EUI-64			*/
+#define ARPHRD_INFINIBAND 32		/**< InfiniBand			*/
+
+/* ARP protocol opcodes. */
+#define	ARPOP_REQUEST	1		/**< ARP request		*/
+#define	ARPOP_REPLY	2		/**< ARP reply			*/
+#define	ARPOP_RREQUEST	3		/**< RARP request		*/
+#define	ARPOP_RREPLY	4		/**< RARP reply			*/
+#define	ARPOP_InREQUEST	8		/**< InARP request		*/
+#define	ARPOP_InREPLY	9		/**< InARP reply		*/
+#define	ARPOP_NAK	10		/**< (ATM)ARP NAK		*/
+
+/**
+ * An ARP header
+ *
+ * This contains only the fixed-size portions of an ARP header; for
+ * other fields use the arp_{sender,target}_{ha,pa} family of
+ * functions.
+ */
+struct arphdr {
+	/** Link-layer protocol
+	 *
+	 * This is an ARPHRD_XXX constant
+	 */
+	uint16_t ar_hrd;
+	/** Network-layer protocol
+	 *
+	 * This is, for Ethernet, an ETH_P_XXX constant.
+	 */
+	uint16_t ar_pro;
+	/** Link-layer address length */
+	uint8_t ar_hln;
+	/** Network-layer address length */
+	uint8_t ar_pln;
+	/** ARP opcode */
+	uint16_t ar_op;
+} __attribute__ (( packed ));
+
+/** ARP packet sender hardware address
+ *
+ * @v arphdr	ARP header
+ * @ret ar_sha	Sender hardware address
+ */
+static inline void * arp_sender_ha ( struct arphdr *arphdr ) {
+	return ( ( ( void * ) arphdr ) + sizeof ( *arphdr ) );
+}
+
+/** ARP packet sender protocol address
+ *
+ * @v arphdr	ARP header
+ * @ret ar_spa	Sender protocol address
+ */
+static inline void * arp_sender_pa ( struct arphdr *arphdr ) {
+	return ( arp_sender_ha ( arphdr ) + arphdr->ar_hln );
+}
+
+/** ARP packet target hardware address
+ *
+ * @v arphdr	ARP header
+ * @ret ar_tha	Target hardware address
+ */
+static inline void * arp_target_ha ( struct arphdr *arphdr ) {
+	return ( arp_sender_pa ( arphdr ) + arphdr->ar_pln );
+}
+
+/** ARP packet target protocol address
+ *
+ * @v arphdr	ARP header
+ * @ret ar_tpa	Target protocol address
+ */
+static inline void * arp_target_pa ( struct arphdr *arphdr ) {
+	return ( arp_target_ha ( arphdr ) + arphdr->ar_hln );
+}
+
+#endif	/* _IPXE_IF_ARP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_ether.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_ether.h
new file mode 100644
index 0000000..a7e2373
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/if_ether.h
@@ -0,0 +1,39 @@
+#ifndef	_IPXE_IF_ETHER_H
+#define	_IPXE_IF_ETHER_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+#define ETH_ALEN		6	/* Size of Ethernet address */
+#define ETH_HLEN		14	/* Size of ethernet header */
+#define	ETH_ZLEN		60	/* Minimum packet */
+#define	ETH_FRAME_LEN		1514	/* Maximum packet */
+#define ETH_DATA_ALIGN		2	/* Amount needed to align the data after an ethernet header */
+#ifndef	ETH_MAX_MTU
+#define	ETH_MAX_MTU		(ETH_FRAME_LEN-ETH_HLEN)
+#endif
+
+#define ETH_P_RAW	0x0000	/* Raw packet */
+#define ETH_P_IP	0x0800	/* Internet Protocl Packet */
+#define ETH_P_ARP	0x0806	/* Address Resolution Protocol */
+#define ETH_P_RARP	0x8035	/* Reverse Address resolution Protocol */
+#define ETH_P_8021Q	0x8100	/* 802.1Q VLAN Extended Header */
+#define ETH_P_IPV6	0x86DD	/* IPv6 over blueblook */
+#define ETH_P_SLOW	0x8809	/* Ethernet slow protocols */
+#define ETH_P_EAPOL	0x888E	/* 802.1X EAP over LANs */
+#define ETH_P_AOE	0x88A2	/* ATA over Ethernet */
+#define ETH_P_FCOE	0x8906	/* Fibre Channel over Ethernet */
+#define ETH_P_FIP	0x8914	/* FCoE Initialization Protocol */
+
+/** An Ethernet link-layer header */
+struct ethhdr {
+	/** Destination MAC address */
+        uint8_t h_dest[ETH_ALEN];
+	/** Source MAC address */
+        uint8_t h_source[ETH_ALEN];
+	/** Protocol ID */
+        uint16_t h_protocol;
+} __attribute__ ((packed));
+
+#endif	/* _IPXE_IF_ETHER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/image.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/image.h
new file mode 100644
index 0000000..dbcd6d6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/image.h
@@ -0,0 +1,184 @@
+#ifndef _IPXE_IMAGE_H
+#define _IPXE_IMAGE_H
+
+/**
+ * @file
+ *
+ * Executable images
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+#include <ipxe/list.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/refcnt.h>
+
+struct uri;
+struct image_type;
+
+/** An executable image */
+struct image {
+	/** Reference count */
+	struct refcnt refcnt;
+
+	/** List of registered images */
+	struct list_head list;
+
+	/** URI of image */
+	struct uri *uri;
+	/** Name */
+	char name[16];
+	/** Flags */
+	unsigned int flags;
+
+	/** Command line to pass to image */
+	char *cmdline;
+	/** Raw file image */
+	userptr_t data;
+	/** Length of raw file image */
+	size_t len;
+
+	/** Image type, if known */
+	struct image_type *type;
+
+	/** Replacement image
+	 *
+	 * An image wishing to replace itself with another image (in a
+	 * style similar to a Unix exec() call) should return from its
+	 * exec() method with the replacement image set to point to
+	 * the new image.
+	 *
+	 * If an image unregisters itself as a result of being
+	 * executed, it must make sure that its replacement image (if
+	 * any) is registered, otherwise the replacement is likely to
+	 * be freed before it can be executed.
+	 */
+	struct image *replacement;
+};
+
+/** Image is registered */
+#define IMAGE_REGISTERED 0x00001
+
+/** Image is selected for execution */
+#define IMAGE_SELECTED 0x0002
+
+/** An executable image type */
+struct image_type {
+	/** Name of this image type */
+	char *name;
+	/** Probe image
+	 *
+	 * @v image		Executable image
+	 * @ret rc		Return status code
+	 *
+	 * Return success if the image is of this image type.
+	 */
+	int ( * probe ) ( struct image *image );
+	/**
+	 * Execute image
+	 *
+	 * @v image		Executable image
+	 * @ret rc		Return status code
+	 */
+	int ( * exec ) ( struct image *image );
+};
+
+/**
+ * Multiboot image probe priority
+ *
+ * Multiboot images are also valid executables in another format
+ * (e.g. ELF), so we must perform the multiboot probe first.
+ */
+#define PROBE_MULTIBOOT	01
+
+/**
+ * Normal image probe priority
+ */
+#define PROBE_NORMAL 02
+
+/**
+ * PXE image probe priority
+ *
+ * PXE images have no signature checks, so will claim all image files.
+ * They must therefore be tried last in the probe order list.
+ */
+#define PROBE_PXE 03
+
+/** Executable image type table */
+#define IMAGE_TYPES __table ( struct image_type, "image_types" )
+
+/** An executable image type */
+#define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order )
+
+extern struct list_head images;
+extern struct image *current_image;
+
+/** Iterate over all registered images */
+#define for_each_image( image ) \
+	list_for_each_entry ( (image), &images, list )
+
+/**
+ * Test for existence of images
+ *
+ * @ret existence	Some images exist
+ */
+static inline int have_images ( void ) {
+	return ( ! list_empty ( &images ) );
+}
+
+/**
+ * Retrieve first image
+ *
+ * @ret image		Image, or NULL
+ */
+static inline struct image * first_image ( void ) {
+	return list_first_entry ( &images, struct image, list );
+}
+
+extern struct image * alloc_image ( void );
+extern void image_set_uri ( struct image *image, struct uri *uri );
+extern int image_set_cmdline ( struct image *image, const char *cmdline );
+extern int register_image ( struct image *image );
+extern void unregister_image ( struct image *image );
+struct image * find_image ( const char *name );
+extern int image_probe ( struct image *image );
+extern int image_exec ( struct image *image );
+extern int image_replace ( struct image *replacement );
+extern int image_select ( struct image *image );
+extern struct image * image_find_selected ( void );
+
+/**
+ * Increment reference count on an image
+ *
+ * @v image		Image
+ * @ret image		Image
+ */
+static inline struct image * image_get ( struct image *image ) {
+	ref_get ( &image->refcnt );
+	return image;
+}
+
+/**
+ * Decrement reference count on an image
+ *
+ * @v image		Image
+ */
+static inline void image_put ( struct image *image ) {
+	ref_put ( &image->refcnt );
+}
+
+/**
+ * Set image name
+ *
+ * @v image		Image
+ * @v name		New image name
+ * @ret rc		Return status code
+ */
+static inline int image_set_name ( struct image *image, const char *name ) {
+	strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) );
+	return 0;
+}
+
+#endif /* _IPXE_IMAGE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/in.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/in.h
new file mode 100644
index 0000000..20f1ce2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/in.h
@@ -0,0 +1,104 @@
+#ifndef	_IPXE_IN_H
+#define	_IPXE_IN_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/socket.h>
+
+/* Protocol numbers */
+
+#define IP_ICMP		1
+#define IP_TCP		6
+#define IP_UDP		17
+#define IP_ICMP6	58
+
+/* IP address constants */
+
+#define INADDR_NONE 0xffffffff
+
+#define INADDR_BROADCAST 0xffffffff
+
+#define	IN_CLASSA(addr)		( ( (addr) & 0x80000000 ) == 0x00000000 )
+#define	IN_CLASSA_NET		0xff000000
+#define	IN_CLASSB(addr)		( ( (addr) & 0xc0000000 ) == 0x80000000 )
+#define	IN_CLASSB_NET		0xffff0000
+#define	IN_CLASSC(addr)		( ( (addr) & 0xe0000000 ) == 0xc0000000 )
+#define	IN_CLASSC_NET		0xffffff00
+#define IN_MULTICAST(addr)	( ( (addr) & 0xf0000000 ) == 0xe0000000 )
+
+/**
+ * IP address structure
+ */
+struct in_addr {
+	uint32_t	s_addr;
+};
+
+typedef struct in_addr in_addr;
+
+/**
+ * IP6 address structure
+ */
+struct in6_addr {
+        union {
+                uint8_t u6_addr8[16];
+                uint16_t u6_addr16[8];
+                uint32_t u6_addr32[4];
+        } in6_u;
+#define s6_addr         in6_u.u6_addr8
+#define s6_addr16       in6_u.u6_addr16
+#define s6_addr32       in6_u.u6_addr32
+};
+
+/**
+ * IPv4 socket address
+ */
+struct sockaddr_in {
+	/** Socket address family (part of struct @c sockaddr)
+	 *
+	 * Always set to @c AF_INET for IPv4 addresses
+	 */
+	sa_family_t sin_family;
+	/** TCP/IP port (part of struct @c sockaddr_tcpip) */
+	uint16_t sin_port;
+	/** IPv4 address */
+	struct in_addr sin_addr;
+	/** Padding
+	 *
+	 * This ensures that a struct @c sockaddr_tcpip is large
+	 * enough to hold a socket address for any TCP/IP address
+	 * family.
+	 */
+	char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
+					     - sizeof ( uint16_t )
+					     - sizeof ( struct in_addr ) ];
+} __attribute__ (( may_alias ));
+
+/**
+ * IPv6 socket address
+ */
+struct sockaddr_in6 {
+	/** Socket address family (part of struct @c sockaddr)
+	 *
+	 * Always set to @c AF_INET6 for IPv6 addresses
+	 */
+	sa_family_t sin_family;
+	/** TCP/IP port (part of struct @c sockaddr_tcpip) */
+	uint16_t 	sin_port;
+        uint32_t        sin6_flowinfo;  /* Flow number */
+        struct in6_addr sin6_addr;      /* 128-bit destination address */
+        uint32_t        sin6_scope_id;  /* Scope ID */
+} __attribute__ (( may_alias ));
+
+extern int inet_aton ( const char *cp, struct in_addr *inp );
+extern char * inet_ntoa ( struct in_addr in );
+
+/* Adding the following for IP6 support
+ *
+
+extern int inet6_aton ( const char *cp, struct in6_addr *inp );
+extern char * inet6_ntoa ( struct in_addr in );
+
+ */
+
+#endif	/* _IPXE_IN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/infiniband.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/infiniband.h
new file mode 100644
index 0000000..f97a5d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/infiniband.h
@@ -0,0 +1,705 @@
+#ifndef _IPXE_INFINIBAND_H
+#define _IPXE_INFINIBAND_H
+
+/** @file
+ *
+ * Infiniband protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+#include <ipxe/ib_packet.h>
+#include <ipxe/ib_mad.h>
+
+/** Subnet management interface QPN */
+#define IB_QPN_SMI 0
+
+/** Subnet management interface queue key */
+#define IB_QKEY_SMI 0
+
+/** General service interface QPN */
+#define IB_QPN_GSI 1
+
+/** General service interface queue key */
+#define IB_QKEY_GSI 0x80010000UL
+
+/** Broadcast QPN */
+#define IB_QPN_BROADCAST 0xffffffUL
+
+/** QPN mask */
+#define IB_QPN_MASK 0xffffffUL
+
+/** Default Infiniband partition key */
+#define IB_PKEY_DEFAULT 0xffff
+
+/** Infiniband partition key full membership flag */
+#define IB_PKEY_FULL 0x8000
+
+/**
+ * Maximum payload size
+ *
+ * This is currently hard-coded in various places (drivers, subnet
+ * management agent, etc.) to 2048.
+ */
+#define IB_MAX_PAYLOAD_SIZE 2048
+
+struct ib_device;
+struct ib_queue_pair;
+struct ib_address_vector;
+struct ib_completion_queue;
+struct ib_mad_interface;
+
+/** Infiniband transmission rates */
+enum ib_rate {
+	IB_RATE_2_5 = 2,
+	IB_RATE_10 = 3,
+	IB_RATE_30 = 4,
+	IB_RATE_5 = 5,
+	IB_RATE_20 = 6,
+	IB_RATE_40 = 7,
+	IB_RATE_60 = 8,
+	IB_RATE_80 = 9,
+	IB_RATE_120 = 10,
+};
+
+/** An Infiniband Address Vector */
+struct ib_address_vector {
+	/** Queue Pair Number */
+	unsigned long qpn;
+	/** Queue key
+	 *
+	 * Not specified for received packets.
+	 */
+	unsigned long qkey;
+	/** Local ID */
+	unsigned int lid;
+	/** Rate
+	 *
+	 * Not specified for received packets.
+	 */
+	enum ib_rate rate;
+	/** Service level */
+	unsigned int sl;
+	/** GID is present */
+	unsigned int gid_present;
+	/** GID, if present */
+	union ib_gid gid;
+	/** VLAN is present */
+	unsigned int vlan_present;
+	/** VLAN, if present */
+	unsigned int vlan;
+};
+
+/** An Infiniband Work Queue */
+struct ib_work_queue {
+	/** Containing queue pair */
+	struct ib_queue_pair *qp;
+	/** "Is a send queue" flag */
+	int is_send;
+	/** Associated completion queue */
+	struct ib_completion_queue *cq;
+	/** List of work queues on this completion queue */
+	struct list_head list;
+	/** Packet sequence number */
+	uint32_t psn;
+	/** Number of work queue entries */
+	unsigned int num_wqes;
+	/** Number of occupied work queue entries */
+	unsigned int fill;
+	/** Next work queue entry index
+	 *
+	 * This is the index of the next entry to be filled (i.e. the
+	 * first empty entry).  This value is not bounded by num_wqes;
+	 * users must logical-AND with (num_wqes-1) to generate an
+	 * array index.
+	 */
+	unsigned long next_idx;
+	/** I/O buffers assigned to work queue */
+	struct io_buffer **iobufs;
+	/** Driver private data */
+	void *drv_priv;
+};
+
+/** An Infiniband multicast GID */
+struct ib_multicast_gid {
+	/** List of multicast GIDs on this QP */
+	struct list_head list;
+	/** Multicast GID */
+	union ib_gid gid;
+};
+
+/** An Infiniband queue pair type */
+enum ib_queue_pair_type {
+	IB_QPT_SMI,
+	IB_QPT_GSI,
+	IB_QPT_UD,
+	IB_QPT_RC,
+	IB_QPT_ETH,
+};
+
+/** An Infiniband Queue Pair */
+struct ib_queue_pair {
+	/** Containing Infiniband device */
+	struct ib_device *ibdev;
+	/** List of queue pairs on this Infiniband device */
+	struct list_head list;
+	/** Queue pair number */
+	unsigned long qpn;
+	/** Externally-visible queue pair number
+	 *
+	 * This may differ from the real queue pair number (e.g. when
+	 * the HCA cannot use the management QPNs 0 and 1 as hardware
+	 * QPNs and needs to remap them).
+	 */
+	unsigned long ext_qpn;
+	/** Queue pair type */
+	enum ib_queue_pair_type type;
+	/** Queue key */
+	unsigned long qkey;
+	/** Send queue */
+	struct ib_work_queue send;
+	/** Receive queue */
+	struct ib_work_queue recv;
+	/** List of multicast GIDs */
+	struct list_head mgids;
+	/** Address vector */
+	struct ib_address_vector av;
+	/** Driver private data */
+	void *drv_priv;
+	/** Queue owner private data */
+	void *owner_priv;
+};
+
+/** Infiniband completion queue operations */
+struct ib_completion_queue_operations {
+	/**
+	 * Complete Send WQE
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v iobuf		I/O buffer
+	 * @v rc		Completion status code
+	 */
+	void ( * complete_send ) ( struct ib_device *ibdev,
+				   struct ib_queue_pair *qp,
+				   struct io_buffer *iobuf, int rc );
+	/**
+	 * Complete Receive WQE
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v av		Address vector, or NULL
+	 * @v iobuf		I/O buffer
+	 * @v rc		Completion status code
+	 */
+	void ( * complete_recv ) ( struct ib_device *ibdev,
+				   struct ib_queue_pair *qp,
+				   struct ib_address_vector *av,
+				   struct io_buffer *iobuf, int rc );
+};
+
+/** An Infiniband Completion Queue */
+struct ib_completion_queue {
+	/** Containing Infiniband device */
+	struct ib_device *ibdev;
+	/** List of completion queues on this Infiniband device */
+	struct list_head list;
+	/** Completion queue number */
+	unsigned long cqn;
+	/** Number of completion queue entries */
+	unsigned int num_cqes;
+	/** Next completion queue entry index
+	 *
+	 * This is the index of the next entry to be filled (i.e. the
+	 * first empty entry).  This value is not bounded by num_wqes;
+	 * users must logical-AND with (num_wqes-1) to generate an
+	 * array index.
+	 */
+	unsigned long next_idx;
+	/** List of work queues completing to this queue */
+	struct list_head work_queues;
+	/** Completion queue operations */
+	struct ib_completion_queue_operations *op;
+	/** Driver private data */
+	void *drv_priv;
+};
+
+/**
+ * Infiniband device operations
+ *
+ * These represent a subset of the Infiniband Verbs.
+ */
+struct ib_device_operations {
+	/** Create completion queue
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v cq		Completion queue
+	 * @ret rc		Return status code
+	 */
+	int ( * create_cq ) ( struct ib_device *ibdev,
+			      struct ib_completion_queue *cq );
+	/** Destroy completion queue
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v cq		Completion queue
+	 */
+	void ( * destroy_cq ) ( struct ib_device *ibdev,
+				struct ib_completion_queue *cq );
+	/** Create queue pair
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @ret rc		Return status code
+	 */
+	int ( * create_qp ) ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp );
+	/** Modify queue pair
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @ret rc		Return status code
+	 */
+	int ( * modify_qp ) ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp );
+	/** Destroy queue pair
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 */
+	void ( * destroy_qp ) ( struct ib_device *ibdev,
+				struct ib_queue_pair *qp );
+	/** Post send work queue entry
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v av		Address vector
+	 * @v iobuf		I/O buffer
+	 * @ret rc		Return status code
+	 *
+	 * If this method returns success, the I/O buffer remains
+	 * owned by the queue pair.  If this method returns failure,
+	 * the I/O buffer is immediately released; the failure is
+	 * interpreted as "failure to enqueue buffer".
+	 */
+	int ( * post_send ) ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct ib_address_vector *av,
+			      struct io_buffer *iobuf );
+	/** Post receive work queue entry
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v iobuf		I/O buffer
+	 * @ret rc		Return status code
+	 *
+	 * If this method returns success, the I/O buffer remains
+	 * owned by the queue pair.  If this method returns failure,
+	 * the I/O buffer is immediately released; the failure is
+	 * interpreted as "failure to enqueue buffer".
+	 */
+	int ( * post_recv ) ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp,
+			      struct io_buffer *iobuf );
+	/** Poll completion queue
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v cq		Completion queue
+	 *
+	 * The relevant completion handler (specified at completion
+	 * queue creation time) takes ownership of the I/O buffer.
+	 */
+	void ( * poll_cq ) ( struct ib_device *ibdev,
+			     struct ib_completion_queue *cq );
+	/**
+	 * Poll event queue
+	 *
+	 * @v ibdev		Infiniband device
+	 */
+	void ( * poll_eq ) ( struct ib_device *ibdev );
+	/**
+	 * Open port
+	 *
+	 * @v ibdev		Infiniband device
+	 * @ret rc		Return status code
+	 */
+	int ( * open ) ( struct ib_device *ibdev );
+	/**
+	 * Close port
+	 *
+	 * @v ibdev		Infiniband device
+	 */
+	void ( * close ) ( struct ib_device *ibdev );
+	/** Attach to multicast group
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v gid		Multicast GID
+	 * @ret rc		Return status code
+	 */
+	int ( * mcast_attach ) ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp,
+				 union ib_gid *gid );
+	/** Detach from multicast group
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v qp		Queue pair
+	 * @v gid		Multicast GID
+	 */
+	void ( * mcast_detach ) ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp,
+				  union ib_gid *gid );
+	/** Set port information
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v mad		Set port information MAD
+	 *
+	 * This method is required only by adapters that do not have
+	 * an embedded SMA.
+	 */
+	int ( * set_port_info ) ( struct ib_device *ibdev, union ib_mad *mad );
+	/** Set partition key table
+	 *
+	 * @v ibdev		Infiniband device
+	 * @v mad		Set partition key table MAD
+	 *
+	 * This method is required only by adapters that do not have
+	 * an embedded SMA.
+	 */
+	int ( * set_pkey_table ) ( struct ib_device *ibdev,
+				   union ib_mad *mad );
+};
+
+/** An Infiniband device */
+struct ib_device {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** List of Infiniband devices */
+	struct list_head list;
+	/** List of open Infiniband devices */
+	struct list_head open_list;
+	/** Underlying device */
+	struct device *dev;
+	/** List of completion queues */
+	struct list_head cqs;
+	/** List of queue pairs */
+	struct list_head qps;
+	/** Infiniband operations */
+	struct ib_device_operations *op;
+	/** Port number */
+	unsigned int port;
+	/** Port open request counter */
+	unsigned int open_count;
+
+	/** Port state */
+	uint8_t port_state;
+	/** Link width supported */
+	uint8_t link_width_supported;
+	/** Link width enabled */
+	uint8_t link_width_enabled;
+	/** Link width active */
+	uint8_t link_width_active;
+	/** Link speed supported */
+	uint8_t link_speed_supported;
+	/** Link speed enabled */
+	uint8_t link_speed_enabled;
+	/** Link speed active */
+	uint8_t link_speed_active;
+	/** Node GUID */
+	union ib_guid node_guid;
+	/** Port GID (comprising GID prefix and port GUID) */
+	union ib_gid gid;
+	/** Port LID */
+	uint16_t lid;
+	/** Subnet manager LID */
+	uint16_t sm_lid;
+	/** Subnet manager SL */
+	uint8_t sm_sl;
+	/** Partition key */
+	uint16_t pkey;
+
+	/** RDMA key
+	 *
+	 * This is a single key allowing unrestricted access to
+	 * memory.
+	 */
+	uint32_t rdma_key;
+
+	/** Subnet management interface */
+	struct ib_mad_interface *smi;
+	/** General services interface */
+	struct ib_mad_interface *gsi;
+
+	/** Driver private data */
+	void *drv_priv;
+	/** Owner private data */
+	void *owner_priv;
+};
+
+/** An Infiniband upper-layer driver */
+struct ib_driver {
+	/** Name */
+	const char *name;
+	/** Probe device
+	 *
+	 * @v ibdev		Infiniband device
+	 * @ret rc		Return status code
+	 */
+	int ( * probe ) ( struct ib_device *ibdev );
+	/** Notify of device or link state change
+	 *
+	 * @v ibdev		Infiniband device
+	 */
+	void ( * notify ) ( struct ib_device *ibdev );
+	/** Remove device
+	 *
+	 * @v ibdev		Infiniband device
+	 */
+	void ( * remove ) ( struct ib_device *ibdev );
+};
+
+/** Infiniband driver table */
+#define IB_DRIVERS __table ( struct ib_driver, "ib_drivers" )
+
+/** Declare an Infiniband driver */
+#define __ib_driver __table_entry ( IB_DRIVERS, 01 )
+
+extern struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+	       struct ib_completion_queue_operations *op );
+extern void ib_destroy_cq ( struct ib_device *ibdev,
+			    struct ib_completion_queue *cq );
+extern void ib_poll_cq ( struct ib_device *ibdev,
+			 struct ib_completion_queue *cq );
+extern struct ib_queue_pair *
+ib_create_qp ( struct ib_device *ibdev, enum ib_queue_pair_type type,
+	       unsigned int num_send_wqes, struct ib_completion_queue *send_cq,
+	       unsigned int num_recv_wqes,
+	       struct ib_completion_queue *recv_cq );
+extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp );
+extern void ib_destroy_qp ( struct ib_device *ibdev,
+			    struct ib_queue_pair *qp );
+extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+					       unsigned long qpn );
+extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+						union ib_gid *gid );
+extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
+					   unsigned long qpn, int is_send );
+extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			  struct ib_address_vector *av,
+			  struct io_buffer *iobuf );
+extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			  struct io_buffer *iobuf );
+extern void ib_complete_send ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp,
+			       struct io_buffer *iobuf, int rc );
+extern void ib_complete_recv ( struct ib_device *ibdev,
+			       struct ib_queue_pair *qp,
+			       struct ib_address_vector *av,
+			       struct io_buffer *iobuf, int rc );
+extern void ib_refill_recv ( struct ib_device *ibdev,
+			     struct ib_queue_pair *qp );
+extern int ib_open ( struct ib_device *ibdev );
+extern void ib_close ( struct ib_device *ibdev );
+extern int ib_link_rc ( struct ib_device *ibdev );
+extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			     union ib_gid *gid );
+extern void ib_mcast_detach ( struct ib_device *ibdev,
+			      struct ib_queue_pair *qp, union ib_gid *gid );
+extern int ib_count_ports ( struct ib_device *ibdev );
+extern int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad );
+extern int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad );
+extern struct ib_device * alloc_ibdev ( size_t priv_size );
+extern int register_ibdev ( struct ib_device *ibdev );
+extern void unregister_ibdev ( struct ib_device *ibdev );
+extern struct ib_device * find_ibdev ( union ib_gid *gid );
+extern struct ib_device * last_opened_ibdev ( void );
+extern void ib_link_state_changed ( struct ib_device *ibdev );
+extern void ib_poll_eq ( struct ib_device *ibdev );
+extern struct list_head ib_devices;
+
+/** Iterate over all network devices */
+#define for_each_ibdev( ibdev ) \
+	list_for_each_entry ( (ibdev), &ib_devices, list )
+
+/**
+ * Check link state of Infiniband device
+ *
+ * @v ibdev		Infiniband device
+ * @ret link_up		Link is up
+ */
+static inline __always_inline int
+ib_link_ok ( struct ib_device *ibdev ) {
+	return ( ibdev->port_state == IB_PORT_STATE_ACTIVE );
+}
+
+/**
+ * Check whether or not Infiniband device is open
+ *
+ * @v ibdev		Infiniband device
+ * @v is_open		Infiniband device is open
+ */
+static inline __attribute__ (( always_inline )) int
+ib_is_open ( struct ib_device *ibdev ) {
+	return ( ibdev->open_count > 0 );
+}
+
+/**
+ * Get reference to Infiniband device
+ *
+ * @v ibdev		Infiniband device
+ * @ret ibdev		Infiniband device
+ */
+static inline __always_inline struct ib_device *
+ibdev_get ( struct ib_device *ibdev ) {
+	ref_get ( &ibdev->refcnt );
+	return ibdev;
+}
+
+/**
+ * Drop reference to Infiniband device
+ *
+ * @v ibdev		Infiniband device
+ */
+static inline __always_inline void
+ibdev_put ( struct ib_device *ibdev ) {
+	ref_put ( &ibdev->refcnt );
+}
+
+/**
+ * Set Infiniband work queue driver-private data
+ *
+ * @v wq		Work queue
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) {
+	wq->drv_priv = priv;
+}
+
+/**
+ * Get Infiniband work queue driver-private data
+ *
+ * @v wq		Work queue
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_wq_get_drvdata ( struct ib_work_queue *wq ) {
+	return wq->drv_priv;
+}
+
+/**
+ * Set Infiniband queue pair driver-private data
+ *
+ * @v qp		Queue pair
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) {
+	qp->drv_priv = priv;
+}
+
+/**
+ * Get Infiniband queue pair driver-private data
+ *
+ * @v qp		Queue pair
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_qp_get_drvdata ( struct ib_queue_pair *qp ) {
+	return qp->drv_priv;
+}
+
+/**
+ * Set Infiniband queue pair owner-private data
+ *
+ * @v qp		Queue pair
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) {
+	qp->owner_priv = priv;
+}
+
+/**
+ * Get Infiniband queue pair owner-private data
+ *
+ * @v qp		Queue pair
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) {
+	return qp->owner_priv;
+}
+
+/**
+ * Set Infiniband completion queue driver-private data
+ *
+ * @v cq		Completion queue
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) {
+	cq->drv_priv = priv;
+}
+
+/**
+ * Get Infiniband completion queue driver-private data
+ *
+ * @v cq		Completion queue
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_cq_get_drvdata ( struct ib_completion_queue *cq ) {
+	return cq->drv_priv;
+}
+
+/**
+ * Set Infiniband device driver-private data
+ *
+ * @v ibdev		Infiniband device
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_set_drvdata ( struct ib_device *ibdev, void *priv ) {
+	ibdev->drv_priv = priv;
+}
+
+/**
+ * Get Infiniband device driver-private data
+ *
+ * @v ibdev		Infiniband device
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_get_drvdata ( struct ib_device *ibdev ) {
+	return ibdev->drv_priv;
+}
+
+/**
+ * Set Infiniband device owner-private data
+ *
+ * @v ibdev		Infiniband device
+ * @v priv		Private data
+ */
+static inline __always_inline void
+ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) {
+	ibdev->owner_priv = priv;
+}
+
+/**
+ * Get Infiniband device owner-private data
+ *
+ * @v ibdev		Infiniband device
+ * @ret priv		Private data
+ */
+static inline __always_inline void *
+ib_get_ownerdata ( struct ib_device *ibdev ) {
+	return ibdev->owner_priv;
+}
+
+#endif /* _IPXE_INFINIBAND_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/init.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/init.h
new file mode 100644
index 0000000..19c5925
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/init.h
@@ -0,0 +1,88 @@
+#ifndef _IPXE_INIT_H
+#define _IPXE_INIT_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+
+/**
+ * An initialisation function
+ *
+ * Initialisation functions are called exactly once, as part of the
+ * call to initialise().
+ */
+struct init_fn {
+	void ( * initialise ) ( void );
+};
+
+/** Initialisation function table */
+#define INIT_FNS __table ( struct init_fn, "init_fns" )
+
+/** Declare an initialisation functon */
+#define __init_fn( init_order ) __table_entry ( INIT_FNS, init_order )
+
+/** @defgroup initfn_order Initialisation function ordering
+ * @{
+ */
+
+#define INIT_EARLY	01	/**< Early initialisation */
+#define INIT_SERIAL	02	/**< Serial driver initialisation */
+#define	INIT_CONSOLE	03	/**< Console initialisation */
+#define INIT_NORMAL	04	/**< Normal initialisation */
+#define INIT_LATE	05	/**< Late initialisation */
+
+/** @} */
+
+/**
+ * A startup/shutdown function
+ *
+ * Startup and shutdown functions may be called multiple times, as
+ * part of the calls to startup() and shutdown().
+ */
+struct startup_fn {
+	void ( * startup ) ( void );
+	void ( * shutdown ) ( int booting );
+};
+
+/** Startup/shutdown function table */
+#define STARTUP_FNS __table ( struct startup_fn, "startup_fns" )
+
+/** Declare a startup/shutdown function */
+#define __startup_fn( startup_order ) \
+	__table_entry ( STARTUP_FNS, startup_order )
+
+/** @defgroup startfn_order Startup/shutdown function ordering
+ *
+ * Shutdown functions are called in the reverse order to startup
+ * functions.
+ *
+ * @{
+ */
+
+#define STARTUP_EARLY	01	/**< Early startup */
+#define STARTUP_NORMAL	02	/**< Normal startup */
+#define STARTUP_LATE	03	/**< Late startup */
+
+/** @} */
+
+extern void initialise ( void );
+extern void startup ( void );
+extern void shutdown ( int booting );
+
+/**
+ * Shut down system for OS boot
+ *
+ */
+static inline void shutdown_boot ( void ) {
+	shutdown ( 1 );
+}
+
+/**
+ * Shut down system for exit back to firmware
+ *
+ */
+static inline void shutdown_exit ( void ) {
+	shutdown ( 0 );
+}
+
+#endif /* _IPXE_INIT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/interface.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/interface.h
new file mode 100644
index 0000000..a474aaa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/interface.h
@@ -0,0 +1,234 @@
+#ifndef _IPXE_INTERFACE_H
+#define _IPXE_INTERFACE_H
+
+/** @file
+ *
+ * Object interfaces
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <ipxe/refcnt.h>
+
+/** An object interface operation */
+struct interface_operation {
+	/** Operation type */
+	void *type;
+	/** Implementing method */
+	void *func;
+};
+
+/**
+ * Define an object interface operation
+ *
+ * @v op_type		Operation type
+ * @v object_type	Implementing method's expected object type
+ * @v op_func		Implementing method
+ * @ret op		Object interface operation
+ */
+#define INTF_OP( op_type, object_type, op_func ) {			      \
+		.type = op_type,					      \
+		.func = ( ( ( ( typeof ( op_func ) * ) NULL ) ==	      \
+			    ( ( op_type ## _TYPE ( object_type ) * ) NULL ) ) \
+			  ? op_func : op_func ),			      \
+	}
+
+/** An object interface descriptor */
+struct interface_descriptor {
+	/** Offset of interface within containing object */
+	size_t offset;
+	/** Number of interface operations */
+	unsigned int num_op;
+	/** Object interface operations */
+	struct interface_operation *op;
+	/** Offset to pass-through interface, if present */
+	ssize_t passthru_offset;
+};
+
+#define intf_offset( object_type, intf )				      \
+	( ( ( ( typeof ( ( ( object_type * ) NULL )->intf ) * ) NULL )	      \
+	    == ( ( struct interface * ) NULL ) )			      \
+	  ? offsetof ( object_type, intf )				      \
+	  : offsetof ( object_type, intf ) )
+
+/**
+ * Define an object interface descriptor
+ *
+ * @v object_type	Containing object data type
+ * @v intf		Interface name (i.e. field within object data type)
+ * @v operations	Object interface operations array
+ * @ret desc		Object interface descriptor
+ */
+#define INTF_DESC( object_type, intf, operations ) {			      \
+		.offset = intf_offset ( object_type, intf ),		      \
+		.op = operations,					      \
+		.num_op = ( sizeof ( operations ) /			      \
+			    sizeof ( operations[0] ) ),			      \
+		.passthru_offset = 0,					      \
+	}
+
+/**
+ * Define an object interface descriptor with pass-through interface
+ *
+ * @v object_type	Containing object data type
+ * @v intf		Interface name (i.e. field within object data type)
+ * @v operations	Object interface operations array
+ * @v passthru		Pass-through interface name
+ * @ret desc		Object interface descriptor
+ */
+#define INTF_DESC_PASSTHRU( object_type, intf, operations, passthru ) {	      \
+		.offset = offsetof ( object_type, intf ),		      \
+		.op = operations,					      \
+		.num_op = ( sizeof ( operations ) /			      \
+			    sizeof ( operations[0] ) ),			      \
+		.passthru_offset = ( intf_offset ( object_type, passthru ) -  \
+				     intf_offset ( object_type, intf ) ),     \
+	}
+
+/**
+ * Define an object interface descriptor for a pure-interface object
+ *
+ * @v operations	Object interface operations array
+ * @ret desc		Object interface descriptor
+ *
+ * A pure-interface object is an object that consists solely of a
+ * single interface.
+ */
+#define INTF_DESC_PURE( operations ) {					      \
+		.offset = 0,						      \
+		.op = operations,					      \
+		.num_op = ( sizeof ( operations ) /			      \
+			    sizeof ( operations[0] ) ),			      \
+		.passthru_offset = 0,					      \
+	}
+
+/** An object interface */
+struct interface {
+	/** Destination object interface
+	 *
+	 * When the containing object invokes an operation on this
+	 * interface, it will be executed by the destination object.
+	 *
+	 * This pointer may never be NULL.  When the interface is
+	 * unplugged, it should point to the null interface.
+	 */
+	struct interface *dest;
+	/** Reference counter
+	 *
+	 * If this interface is not part of a reference-counted
+	 * object, this field may be NULL.
+	 */
+	struct refcnt *refcnt;
+	/** Interface descriptor */
+	struct interface_descriptor *desc;
+};
+
+extern void intf_plug ( struct interface *intf, struct interface *dest );
+extern void intf_plug_plug ( struct interface *a, struct interface *b );
+extern void intf_unplug ( struct interface *intf );
+extern void intf_nullify ( struct interface *intf );
+extern struct interface * intf_get ( struct interface *intf );
+extern void intf_put ( struct interface *intf );
+extern void * __attribute__ (( pure )) intf_object ( struct interface *intf );
+extern void * intf_get_dest_op_no_passthru_untyped ( struct interface *intf,
+						     void *type,
+						     struct interface **dest );
+extern void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
+					 struct interface **dest );
+
+extern void intf_close ( struct interface *intf, int rc );
+#define intf_close_TYPE( object_type ) \
+	typeof ( void ( object_type, int rc ) )
+
+extern void intf_shutdown ( struct interface *intf, int rc );
+extern void intf_restart ( struct interface *intf, int rc );
+
+extern struct interface_descriptor null_intf_desc;
+extern struct interface null_intf;
+
+/**
+ * Initialise an object interface
+ *
+ * @v intf		Object interface
+ * @v desc		Object interface descriptor
+ * @v refcnt		Containing object reference counter, or NULL
+ */
+static inline void intf_init ( struct interface *intf,
+			       struct interface_descriptor *desc,
+			       struct refcnt *refcnt ) {
+	intf->dest = &null_intf;
+	intf->refcnt = refcnt;
+	intf->desc = desc;
+}
+
+/**
+ * Initialise a static object interface
+ *
+ * @v descriptor	Object interface descriptor
+ */
+#define INTF_INIT( descriptor ) {		\
+		.dest = &null_intf,		\
+		.refcnt = NULL,			\
+		.desc = &(descriptor),		\
+	}
+
+/**
+ * Get object interface destination and operation method (without pass-through)
+ *
+ * @v intf		Object interface
+ * @v type		Operation type
+ * @ret dest		Destination interface
+ * @ret func		Implementing method, or NULL
+ */
+#define intf_get_dest_op_no_passthru( intf, type, dest )		\
+	( ( type ## _TYPE ( void * ) * )				\
+	  intf_get_dest_op_no_passthru_untyped ( intf, type, dest ) )
+
+/**
+ * Get object interface destination and operation method
+ *
+ * @v intf		Object interface
+ * @v type		Operation type
+ * @ret dest		Destination interface
+ * @ret func		Implementing method, or NULL
+ */
+#define intf_get_dest_op( intf, type, dest )				\
+	( ( type ## _TYPE ( void * ) * )				\
+	  intf_get_dest_op_untyped ( intf, type, dest ) )
+
+/**
+ * Find debugging colourisation for an object interface
+ *
+ * @v intf		Object interface
+ * @ret col		Debugging colourisation
+ *
+ * Use as the first argument to DBGC() or equivalent macro.
+ */
+#define INTF_COL( intf ) intf_object ( intf )
+
+/** printf() format string for INTF_DBG() */
+#define INTF_FMT "%p+%zx"
+
+/**
+ * printf() arguments for representing an object interface
+ *
+ * @v intf		Object interface
+ * @ret args		printf() argument list corresponding to INTF_FMT
+ */
+#define INTF_DBG( intf ) intf_object ( intf ), (intf)->desc->offset
+
+/** printf() format string for INTF_INTF_DBG() */
+#define INTF_INTF_FMT INTF_FMT "->" INTF_FMT
+
+/**
+ * printf() arguments for representing an object interface pair
+ *
+ * @v intf		Object interface
+ * @v dest		Destination object interface
+ * @ret args		printf() argument list corresponding to INTF_INTF_FMT
+ */
+#define INTF_INTF_DBG( intf, dest ) INTF_DBG ( intf ), INTF_DBG ( dest )
+
+#endif /* _IPXE_INTERFACE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/io.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/io.h
new file mode 100644
index 0000000..b4d88fe
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/io.h
@@ -0,0 +1,532 @@
+#ifndef _IPXE_IO_H
+#define _IPXE_IO_H
+
+/** @file
+ *
+ * iPXE I/O API
+ *
+ * The I/O API provides methods for reading from and writing to
+ * memory-mapped and I/O-mapped devices.
+ *
+ * The standard methods (readl()/writel() etc.) do not strictly check
+ * the type of the address parameter; this is because traditional
+ * usage does not necessarily provide the correct pointer type.  For
+ * example, code written for ISA devices at fixed I/O addresses (such
+ * as the keyboard controller) tend to use plain integer constants for
+ * the address parameter.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/api.h>
+#include <config/ioapi.h>
+#include <ipxe/uaccess.h>
+
+/**
+ * Calculate static inline I/O API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define IOAPI_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an I/O API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline I/O API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <ipxe/efi/efi_io.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/io.h>
+
+/**
+ * Wrap an I/O read
+ *
+ * @v _func		I/O API function
+ * @v _type		Data type
+ * @v io_addr		I/O address
+ * @v _prefix		Prefix for address in debug message
+ * @v _ndigits		Number of hex digits for this data type
+ */
+#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( {	      \
+	volatile _type *_io_addr =					      \
+		( ( volatile _type * ) ( intptr_t ) (io_addr) );	      \
+	_type _data = _func ( _io_addr );				      \
+	DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n",		      \
+		io_to_bus ( _io_addr ), ( unsigned long long ) _data );	      \
+	_data; } )
+
+/**
+ * Wrap an I/O write
+ *
+ * @v _func		I/O API function
+ * @v _type		Data type
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ * @v _prefix		Prefix for address in debug message
+ * @v _ndigits		Number of hex digits for this data type
+ */
+#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do {    \
+	volatile _type *_io_addr =					      \
+		( ( volatile _type * ) ( intptr_t ) (io_addr) );	      \
+	_type _data = (data);						      \
+	DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n",		      \
+		io_to_bus ( _io_addr ), ( unsigned long long ) _data );	      \
+	_func ( _data, _io_addr );					      \
+	} while ( 0 )
+
+/**
+ * Wrap an I/O string read
+ *
+ * @v _func		I/O API function
+ * @v _type		Data type
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of elements to read
+ * @v _prefix		Prefix for address in debug message
+ * @v _ndigits		Number of hex digits for this data type
+ */
+#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits )  \
+	do {								      \
+	volatile _type *_io_addr =					      \
+		( ( volatile _type * ) ( intptr_t ) (io_addr) );	      \
+	void *_data_void = (data); /* Check data is a pointer */	      \
+	_type * _data = ( ( _type * ) _data_void );			      \
+	const _type * _dbg_data = _data;				      \
+	unsigned int _count = (count);					      \
+	unsigned int _dbg_count = _count;				      \
+	_func ( _io_addr, _data, _count );				      \
+	DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) );	      \
+	while ( _dbg_count-- ) {					      \
+		DBGIO ( " %0" #_ndigits "llx",				      \
+			( ( unsigned long long ) *(_dbg_data++) ) );	      \
+	}								      \
+	DBGIO ( "\n" );							      \
+	} while ( 0 )
+
+/**
+ * Wrap an I/O string write
+ *
+ * @v _func		I/O API function
+ * @v _type		Data type
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of elements to write
+ * @v _prefix		Prefix for address in debug message
+ * @v _ndigits		Number of hex digits for this data type
+ */
+#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
+	do {								      \
+	volatile _type *_io_addr =					      \
+		( ( volatile _type * ) ( intptr_t ) (io_addr) );	      \
+	const void *_data_void = (data); /* Check data is a pointer */	      \
+	const _type * _data = ( ( const _type * ) _data_void );		      \
+	const _type * _dbg_data = _data;				      \
+	unsigned int _count = (count);					      \
+	unsigned int _dbg_count = _count;				      \
+	DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) );	      \
+	while ( _dbg_count-- ) {					      \
+		DBGIO ( " %0" #_ndigits "llx",				      \
+			( ( unsigned long long ) *(_dbg_data++) ) );	      \
+	}								      \
+	DBGIO ( "\n" );							      \
+	_func ( _io_addr, _data, _count );				      \
+	} while ( 0 )
+
+/**
+ * Convert physical address to a bus address
+ *
+ * @v phys_addr		Physical address
+ * @ret bus_addr	Bus address
+ */
+unsigned long phys_to_bus ( unsigned long phys_addr );
+
+/**
+ * Convert bus address to a physical address
+ *
+ * @v bus_addr		Bus address
+ * @ret phys_addr	Physical address
+ */
+unsigned long bus_to_phys ( unsigned long bus_addr );
+
+/**
+ * Convert virtual address to a bus address
+ *
+ * @v addr		Virtual address
+ * @ret bus_addr	Bus address
+ */
+static inline __always_inline unsigned long
+virt_to_bus ( volatile const void *addr ) {
+	return phys_to_bus ( virt_to_phys ( addr ) );
+}
+
+/**
+ * Convert bus address to a virtual address
+ *
+ * @v bus_addr		Bus address
+ * @ret addr		Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) {
+	return phys_to_virt ( bus_to_phys ( bus_addr ) );
+}
+
+/**
+ * Map bus address as an I/O address
+ *
+ * @v bus_addr		Bus address
+ * @v len		Length of region
+ * @ret io_addr		I/O address
+ */
+void * ioremap ( unsigned long bus_addr, size_t len );
+
+/**
+ * Unmap I/O address
+ *
+ * @v io_addr		I/O address
+ */
+void iounmap ( volatile const void *io_addr );
+
+/**
+ * Convert I/O address to bus address (for debug only)
+ *
+ * @v io_addr		I/O address
+ * @ret bus_addr	Bus address
+ */
+unsigned long io_to_bus ( volatile const void *io_addr );
+
+/**
+ * Read byte from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint8_t readb ( volatile uint8_t *io_addr );
+#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 )
+
+/**
+ * Read 16-bit word from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint16_t readw ( volatile uint16_t *io_addr );
+#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 )
+
+/**
+ * Read 32-bit dword from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint32_t readl ( volatile uint32_t *io_addr );
+#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 )
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint64_t readq ( volatile uint64_t *io_addr );
+#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 )
+
+/**
+ * Write byte to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void writeb ( uint8_t data, volatile uint8_t *io_addr );
+#define writeb( data, io_addr ) \
+	IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 )
+
+/**
+ * Write 16-bit word to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void writew ( uint16_t data, volatile uint16_t *io_addr );
+#define writew( data, io_addr ) \
+	IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 )
+
+/**
+ * Write 32-bit dword to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void writel ( uint32_t data, volatile uint32_t *io_addr );
+#define writel( data, io_addr ) \
+	IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 )
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void writeq ( uint64_t data, volatile uint64_t *io_addr );
+#define writeq( data, io_addr ) \
+	IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint8_t inb ( volatile uint8_t *io_addr );
+#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint16_t inw ( volatile uint16_t *io_addr );
+#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+uint32_t inl ( volatile uint32_t *io_addr );
+#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 )
+
+/**
+ * Write byte to I/O-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void outb ( uint8_t data, volatile uint8_t *io_addr );
+#define outb( data, io_addr ) \
+	IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 )
+
+/**
+ * Write 16-bit word to I/O-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void outw ( uint16_t data, volatile uint16_t *io_addr );
+#define outw( data, io_addr ) \
+	IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 )
+
+/**
+ * Write 32-bit dword to I/O-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+void outl ( uint32_t data, volatile uint32_t *io_addr );
+#define outl( data, io_addr ) \
+	IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 )
+
+/**
+ * Read bytes from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of bytes to read
+ */
+void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count );
+#define insb( io_addr, data, count ) \
+	IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Read 16-bit words from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of words to read
+ */
+void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count );
+#define insw( io_addr, data, count ) \
+	IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Read 32-bit words from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of words to read
+ */
+void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count );
+#define insl( io_addr, data, count ) \
+	IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Write bytes to I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of bytes to write
+ */
+void outsb ( volatile uint8_t *io_addr, const uint8_t *data,
+	     unsigned int count );
+#define outsb( io_addr, data, count ) \
+	IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Write 16-bit words to I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of words to write
+ */
+void outsw ( volatile uint16_t *io_addr, const uint16_t *data,
+	     unsigned int count );
+#define outsw( io_addr, data, count ) \
+	IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Write 32-bit words to I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v count		Number of words to write
+ */
+void outsl ( volatile uint32_t *io_addr, const uint32_t *data,
+	     unsigned int count );
+#define outsl( io_addr, data, count ) \
+	IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Slow down I/O
+ *
+ */
+void iodelay ( void );
+
+/**
+ * Read value from I/O-mapped device, slowly
+ *
+ * @v _func		Function to use to read value
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+#define INX_P( _func, _type, io_addr ) ( {				      \
+	_type _data = _func ( (io_addr) );				      \
+	iodelay();							      \
+	_data; } )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr )
+
+/**
+ * Write value to I/O-mapped device, slowly
+ *
+ * @v _func		Function to use to write value
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+#define OUTX_P( _func, data, io_addr ) do {				      \
+	_func ( (data), (io_addr) );					      \
+	iodelay();							      \
+	} while ( 0 )
+
+/**
+ * Write byte to I/O-mapped device, slowly
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr )
+
+/**
+ * Write 16-bit word to I/O-mapped device, slowly
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr )
+
+/**
+ * Write 32-bit dword to I/O-mapped device, slowly
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr )
+
+/**
+ * Memory barrier
+ *
+ */
+void mb ( void );
+#define rmb()	mb()
+#define wmb()	mb()
+
+/** A usable memory region */
+struct memory_region {
+	/** Physical start address */
+	uint64_t start;
+	/** Physical end address */
+	uint64_t end;
+};
+
+/** Maximum number of memory regions we expect to encounter */
+#define MAX_MEMORY_REGIONS 8
+
+/** A memory map */
+struct memory_map {
+	/** Memory regions */
+	struct memory_region regions[MAX_MEMORY_REGIONS];
+	/** Number of used regions */
+	unsigned int count;
+};
+
+/**
+ * Get memory map
+ *
+ * @v memmap		Memory map to fill in
+ */
+void get_memmap ( struct memory_map *memmap );
+
+#endif /* _IPXE_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/iobuf.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/iobuf.h
new file mode 100644
index 0000000..82c8b88
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/iobuf.h
@@ -0,0 +1,229 @@
+#ifndef _IPXE_IOBUF_H
+#define _IPXE_IOBUF_H
+
+/** @file
+ *
+ * I/O buffers
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <assert.h>
+#include <ipxe/list.h>
+
+/**
+ * I/O buffer alignment
+ *
+ * I/O buffers allocated via alloc_iob() are guaranteed to be
+ * physically aligned to this boundary.  Some cards cannot DMA across
+ * a 4kB boundary.  With a standard Ethernet MTU, aligning to a 2kB
+ * boundary is sufficient to guarantee no 4kB boundary crossings.  For
+ * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
+ */
+#define IOB_ALIGN 2048
+
+/**
+ * Minimum I/O buffer length
+ *
+ * alloc_iob() will round up the allocated length to this size if
+ * necessary.  This is used on behalf of hardware that is not capable
+ * of auto-padding.
+ */
+#define IOB_ZLEN 64
+
+/**
+ * A persistent I/O buffer
+ *
+ * This data structure encapsulates a long-lived I/O buffer.  The
+ * buffer may be passed between multiple owners, queued for possible
+ * retransmission, etc.
+ */
+struct io_buffer {
+	/** List of which this buffer is a member
+	 *
+	 * The list must belong to the current owner of the buffer.
+	 * Different owners may maintain different lists (e.g. a
+	 * retransmission list for TCP).
+	 */
+	struct list_head list;
+
+	/** Start of the buffer */
+	void *head;
+	/** Start of data */
+	void *data;
+	/** End of data */
+	void *tail;
+	/** End of the buffer */
+        void *end;
+};
+
+/**
+ * Reserve space at start of I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Length to reserve
+ * @ret data	Pointer to new start of buffer
+ */
+static inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
+	iobuf->data += len;
+	iobuf->tail += len;
+	return iobuf->data;
+}
+#define iob_reserve( iobuf, len ) ( {			\
+	void *__result;					\
+	__result = iob_reserve ( (iobuf), (len) );	\
+	assert ( (iobuf)->tail <= (iobuf)->end );	\
+	__result; } )
+
+/**
+ * Add data to start of I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Length to add
+ * @ret data	Pointer to new start of buffer
+ */
+static inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
+	iobuf->data -= len;
+	return iobuf->data;
+}
+#define iob_push( iobuf, len ) ( {			\
+	void *__result;					\
+	__result = iob_push ( (iobuf), (len) );		\
+	assert ( (iobuf)->data >= (iobuf)->head );	\
+	__result; } )
+
+/**
+ * Remove data from start of I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Length to remove
+ * @ret data	Pointer to new start of buffer
+ */
+static inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
+	iobuf->data += len;
+	assert ( iobuf->data <= iobuf->tail );
+	return iobuf->data;
+}
+#define iob_pull( iobuf, len ) ( {			\
+	void *__result;					\
+	__result = iob_pull ( (iobuf), (len) );		\
+	assert ( (iobuf)->data <= (iobuf)->tail );	\
+	__result; } )
+
+/**
+ * Add data to end of I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Length to add
+ * @ret data	Pointer to newly added space
+ */
+static inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
+	void *old_tail = iobuf->tail;
+	iobuf->tail += len;
+	return old_tail;
+}
+#define iob_put( iobuf, len ) ( {			\
+	void *__result;					\
+	__result = iob_put ( (iobuf), (len) );		\
+	assert ( (iobuf)->tail <= (iobuf)->end );	\
+	__result; } )
+
+/**
+ * Remove data from end of I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v len	Length to remove
+ */
+static inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
+	iobuf->tail -= len;
+}
+#define iob_unput( iobuf, len ) do {			\
+	iob_unput ( (iobuf), (len) );			\
+	assert ( (iobuf)->tail >= (iobuf)->data );	\
+	} while ( 0 )
+
+/**
+ * Empty an I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ */
+static inline void iob_empty ( struct io_buffer *iobuf ) {
+	iobuf->tail = iobuf->data;
+}
+
+/**
+ * Calculate length of data in an I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @ret len	Length of data in buffer
+ */
+static inline size_t iob_len ( struct io_buffer *iobuf ) {
+	return ( iobuf->tail - iobuf->data );
+}
+
+/**
+ * Calculate available space at start of an I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @ret len	Length of data available at start of buffer
+ */
+static inline size_t iob_headroom ( struct io_buffer *iobuf ) {
+	return ( iobuf->data - iobuf->head );
+}
+
+/**
+ * Calculate available space at end of an I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @ret len	Length of data available at end of buffer
+ */
+static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
+	return ( iobuf->end - iobuf->tail );
+}
+
+/**
+ * Create a temporary I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ * @v data	Data buffer
+ * @v len	Length of data
+ * @v max_len	Length of buffer
+ *
+ * It is sometimes useful to use the iob_xxx() methods on temporary
+ * data buffers.
+ */
+static inline void iob_populate ( struct io_buffer *iobuf,
+				  void *data, size_t len, size_t max_len ) {
+	iobuf->head = iobuf->data = data;
+	iobuf->tail = ( data + len );
+	iobuf->end = ( data + max_len );
+}
+
+/**
+ * Disown an I/O buffer
+ *
+ * @v iobuf	I/O buffer
+ *
+ * There are many functions that take ownership of the I/O buffer they
+ * are passed as a parameter.  The caller should not retain a pointer
+ * to the I/O buffer.  Use iob_disown() to automatically nullify the
+ * caller's pointer, e.g.:
+ *
+ *     xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
+ *
+ * This will ensure that iobuf is set to NULL for any code after the
+ * call to xfer_deliver_iob().
+ */
+#define iob_disown( iobuf ) ( {				\
+	struct io_buffer *__iobuf = (iobuf);		\
+	(iobuf) = NULL;					\
+	__iobuf; } )
+
+extern struct io_buffer * __malloc alloc_iob ( size_t len );
+extern void free_iob ( struct io_buffer *iobuf );
+extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
+extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
+
+#endif /* _IPXE_IOBUF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip.h
new file mode 100644
index 0000000..3f3dc1f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip.h
@@ -0,0 +1,96 @@
+#ifndef _IPXE_IP_H
+#define _IPXE_IP_H
+
+/** @file
+ *
+ * IP protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/in.h>
+#include <ipxe/list.h>
+#include <ipxe/retry.h>
+#include <ipxe/netdevice.h>
+
+struct io_buffer;
+
+/* IP constants */
+
+#define IP_VER			0x40U
+#define IP_MASK_VER		0xf0U
+#define IP_MASK_HLEN 		0x0fU
+#define IP_MASK_OFFSET		0x1fffU
+#define IP_MASK_DONOTFRAG	0x4000U
+#define IP_MASK_MOREFRAGS	0x2000U
+#define IP_PSHLEN 	12
+
+/* IP header defaults */
+#define IP_TOS		0
+#define IP_TTL		64
+
+#define IP_FRAG_IOB_SIZE	1500
+#define IP_FRAG_TIMEOUT		50
+
+/** An IPv4 packet header */
+struct iphdr {
+	uint8_t  verhdrlen;
+	uint8_t  service;
+	uint16_t len;
+	uint16_t ident;
+	uint16_t frags;
+	uint8_t  ttl;
+	uint8_t  protocol;
+	uint16_t chksum;
+	struct in_addr src;
+	struct in_addr dest;
+} __attribute__ (( packed ));
+
+/** An IPv4 pseudo header */
+struct ipv4_pseudo_header {
+	struct in_addr src;
+	struct in_addr dest;
+	uint8_t zero_padding;
+	uint8_t protocol;
+	uint16_t len;
+};
+
+/** An IPv4 address/routing table entry */
+struct ipv4_miniroute {
+	/** List of miniroutes */
+	struct list_head list;
+
+	/** Network device */
+	struct net_device *netdev;
+
+	/** IPv4 address */
+	struct in_addr address;
+	/** Subnet mask */
+	struct in_addr netmask;
+	/** Gateway address */
+	struct in_addr gateway;
+};
+
+/* Fragment reassembly buffer */
+struct frag_buffer {
+	/* Identification number */
+	uint16_t ident;
+	/* Source network address */
+	struct in_addr src;
+	/* Destination network address */
+	struct in_addr dest;
+	/* Reassembled I/O buffer */
+	struct io_buffer *frag_iob;
+	/* Reassembly timer */
+	struct retry_timer frag_timer;
+	/* List of fragment reassembly buffers */
+	struct list_head list;
+};
+
+extern struct list_head ipv4_miniroutes;
+
+extern struct net_protocol ipv4_protocol __net_protocol;
+
+#endif /* _IPXE_IP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip6.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip6.h
new file mode 100644
index 0000000..e9584bd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ip6.h
@@ -0,0 +1,80 @@
+#ifndef _IPXE_IP6_H
+#define _IPXE_IP6_H
+
+/** @file
+ *
+ * IP6 protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/in.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/tcpip.h>
+
+/* IP6 constants */
+
+#define IP6_VERSION	0x6
+#define IP6_HOP_LIMIT	255
+
+/**
+ * I/O buffer contents
+ * This is duplicated in tcp.h and here. Ideally it should go into iobuf.h
+ */
+#define MAX_HDR_LEN	100
+#define MAX_IOB_LEN	1500
+#define MIN_IOB_LEN	MAX_HDR_LEN + 100 /* To account for padding by LL */
+
+#define IP6_EQUAL( in6_addr1, in6_addr2 ) \
+        ( memcmp ( ( char* ) &( in6_addr1 ), ( char* ) &( in6_addr2 ),\
+	sizeof ( struct in6_addr ) ) == 0 )
+
+#define IS_UNSPECIFIED( addr ) \
+	( ( (addr).in6_u.u6_addr32[0] == 0x00000000 ) && \
+	( (addr).in6_u.u6_addr32[1] == 0x00000000 ) && \
+	( (addr).in6_u.u6_addr32[2] == 0x00000000 ) && \
+	( (addr).in6_u.u6_addr32[3] == 0x00000000 ) )
+/* IP6 header */
+struct ip6_header {
+	uint32_t 	ver_traffic_class_flow_label;
+	uint16_t 	payload_len;
+	uint8_t 	nxt_hdr;
+	uint8_t 	hop_limit;
+	struct in6_addr src;
+	struct in6_addr dest;
+};
+
+/* IP6 pseudo header */
+struct ipv6_pseudo_header {
+	struct in6_addr src;
+	struct in6_addr dest;
+	uint8_t zero_padding;
+	uint8_t nxt_hdr;
+	uint16_t len;
+};
+
+/* Next header numbers */
+#define IP6_HOPBYHOP 		0x00
+#define IP6_ROUTING 		0x43
+#define IP6_FRAGMENT		0x44
+#define IP6_AUTHENTICATION	0x51
+#define IP6_DEST_OPTS		0x60
+#define IP6_ESP			0x50
+#define IP6_ICMP6		0x58
+#define IP6_NO_HEADER		0x59
+
+struct io_buffer;
+
+extern struct net_protocol ipv6_protocol __net_protocol;
+extern struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol;
+extern char * inet6_ntoa ( struct in6_addr in6 );
+
+extern int add_ipv6_address ( struct net_device *netdev,
+			      struct in6_addr prefix, int prefix_len,
+			      struct in6_addr address,
+			      struct in6_addr gateway );
+extern void del_ipv6_address ( struct net_device *netdev );
+
+#endif /* _IPXE_IP6_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ipoib.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ipoib.h
new file mode 100644
index 0000000..e8f12dc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ipoib.h
@@ -0,0 +1,58 @@
+#ifndef _IPXE_IPOIB_H
+#define _IPXE_IPOIB_H
+
+/** @file
+ *
+ * IP over Infiniband
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/infiniband.h>
+
+/** IPoIB MAC address length */
+#define IPOIB_ALEN 20
+
+/** An IPoIB MAC address */
+struct ipoib_mac {
+	/** Queue pair number
+	 *
+	 * MSB indicates support for IPoIB "connected mode".  Lower 24
+	 * bits are the QPN.
+	 */
+	uint32_t flags__qpn;
+	/** Port GID */
+	union ib_gid gid;
+} __attribute__ (( packed ));
+
+/** IPoIB link-layer header length */
+#define IPOIB_HLEN 4
+
+/** IPoIB link-layer header */
+struct ipoib_hdr {
+	/** Network-layer protocol */
+	uint16_t proto;
+	/** Reserved, must be zero */
+	union {
+		/** Reserved, must be zero */
+		uint16_t reserved;
+		/** Peer addresses
+		 *
+		 * We use these fields internally to represent the
+		 * peer addresses using a lookup key.  There simply
+		 * isn't enough room in the IPoIB header to store
+		 * literal source or destination MAC addresses.
+		 */
+		struct {
+			/** Destination address key */
+			uint8_t dest;
+			/** Source address key */
+			uint8_t src;
+		} __attribute__ (( packed )) peer;
+	} __attribute__ (( packed )) u;
+} __attribute__ (( packed ));
+
+extern const char * ipoib_ntoa ( const void *ll_addr );
+extern struct net_device * alloc_ipoibdev ( size_t priv_size );
+
+#endif /* _IPXE_IPOIB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa.h
new file mode 100644
index 0000000..4e69fc6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa.h
@@ -0,0 +1,95 @@
+#ifndef	ISA_H
+#define ISA_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/isa_ids.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+
+/** An ISA device */
+struct isa_device {
+	/** Generic device */
+	struct device dev;
+	/** I/O address */
+	uint16_t ioaddr;
+	/** Driver for this device */
+	struct isa_driver *driver;
+	/** Driver-private data
+	 *
+	 * Use isa_set_drvdata() and isa_get_drvdata() to access
+	 * this field.
+	 */
+	void *priv;
+};
+
+/*
+ * An individual ISA device, identified by probe address
+ *
+ */
+typedef uint16_t isa_probe_addr_t;
+
+/** An ISA driver */
+struct isa_driver {
+	/** Name */
+	const char *name;
+	/** Probe address list */
+	isa_probe_addr_t *probe_addrs;
+	/** Number of entries in probe address list */
+	unsigned int addr_count;
+	/** Manufacturer ID to be assumed for this device */
+	uint16_t vendor_id;
+	/** Product ID to be assumed for this device */
+	uint16_t prod_id;
+	/**
+	 * Probe device
+	 *
+	 * @v isa	ISA device
+	 * @v id	Matching entry in ID table
+	 * @ret rc	Return status code
+	 */
+	int ( * probe ) ( struct isa_device *isa );
+	/**
+	 * Remove device
+	 *
+	 * @v isa	ISA device
+	 */
+	void ( * remove ) ( struct isa_device *isa );
+};
+
+/** ISA driver table */
+#define ISA_DRIVERS __table ( struct isa_driver, "isa_drivers" )
+
+/** Declare an ISA driver */
+#define __isa_driver __table_entry ( ISA_DRIVERS, 01 )
+
+/**
+ * Set ISA driver-private data
+ *
+ * @v isa		ISA device
+ * @v priv		Private data
+ */
+static inline void isa_set_drvdata ( struct isa_device *isa, void *priv ) {
+	isa->priv = priv;
+}
+
+/**
+ * Get ISA driver-private data
+ *
+ * @v isa		ISA device
+ * @ret priv		Private data
+ */
+static inline void * isa_get_drvdata ( struct isa_device *isa ) {
+	return isa->priv;
+}
+
+/*
+ * ISA_ROM is parsed by parserom.pl to generate Makefile rules and
+ * files for rom-o-matic.
+ *
+ */
+#define ISA_ROM( IMAGE, DESCRIPTION )
+
+#endif /* ISA_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa_ids.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa_ids.h
new file mode 100644
index 0000000..1faf114
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isa_ids.h
@@ -0,0 +1,51 @@
+#ifndef ISA_IDS_H
+#define ISA_IDS_H
+
+/* 
+ * This file defines IDs as used by ISAPnP and EISA devices.  These
+ * IDs have the format:
+ *
+ * vendor  byte 0 bit  7    must be zero
+ *		  bits 6-2  first vendor char in compressed ASCII
+ *		  bits 1-0  second vendor char in compressed ASCII (bits 4-3)
+ *	   byte 1 bits 7-5  second vendor char in compressed ASCII (bits 2-0)
+ *                bits 4-0  third vendor char in compressed ASCII
+ * product byte 0 bits 7-4  first hex digit of product number
+ *		  bits 3-0  second hex digit of product number
+ *	   byte 1 bits 7-4  third hex digit of product number
+ *		  bits 3-0  hex digit of revision level
+ *
+ * ISA IDs are always expressed in little-endian order, even though
+ * the underlying "meaning" is big-endian.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <byteswap.h>
+
+/*
+ * Construct a vendor ID from three ASCII characters
+ *
+ */
+#define ISA_VENDOR( a, b, c )					\
+	bswap_16 ( ( ( ( (a) - 'A' + 1 ) & 0x1f ) << 10 ) |	\
+		   ( ( ( (b) - 'A' + 1 ) & 0x1f ) << 5 ) |	\
+		   ( ( ( (c) - 'A' + 1 ) & 0x1f ) << 0 ) )
+
+#define ISAPNP_VENDOR( a, b, c )	ISA_VENDOR ( a, b, c )
+#define EISA_VENDOR( a, b, c )		ISA_VENDOR ( a, b, c )
+
+#define	GENERIC_ISAPNP_VENDOR		ISAPNP_VENDOR ( 'P','N','P' )
+
+/*
+ * Extract product ID and revision from combined product field
+ *
+ */
+#define ISA_PROD_ID_MASK	( 0xf0ff )
+#define ISA_PROD_ID(product)	( (product) & ISA_PROD_ID_MASK )
+#define ISA_PROD_REV(product)	( ( (product) & ~ISA_PROD_ID_MASK ) >> 8 )
+
+/* Functions in isa_ids.c */
+extern char * isa_id_string ( unsigned int vendor, unsigned int product );
+
+#endif /* ISA_IDS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/isapnp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isapnp.h
new file mode 100644
index 0000000..47a4702
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/isapnp.h
@@ -0,0 +1,276 @@
+/**************************************************************************
+*
+*    isapnp.h -- Etherboot isapnp support for the 3Com 3c515
+*    Written 2002-2003 by Timothy Legge <tlegge at rogers.com>
+*
+*    This program is free software; you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation; either version 2 of the License, or
+*    (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software
+*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*    Portions of this code:
+*		Copyright (C) 2001  P.J.H.Fox (fox at roestock.demon.co.uk)
+*
+*
+*
+*    REVISION HISTORY:
+*    ================
+*        Version 0.1 April 26, 2002 	TJL
+*	 Version 0.2 01/08/2003			TJL Renamed from 3c515_isapnp.h
+*
+*
+*    Generalised into an ISAPnP bus that can be used by more than just
+*    the 3c515 by Michael Brown <mbrown at fensystems.co.uk>
+*
+***************************************************************************/
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef ISAPNP_H
+#define ISAPNP_H
+
+#include <stdint.h>
+#include <ipxe/isa_ids.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+
+/*
+ * ISAPnP constants
+ *
+ */
+
+/* Port addresses */
+#define ISAPNP_ADDRESS		0x279
+#define ISAPNP_WRITE_DATA	0xa79
+#define ISAPNP_READ_PORT_MIN	0x203
+#define ISAPNP_READ_PORT_START	0x213	/* ISAPnP spec says 0x203, but
+					 * Linux ISAPnP starts at
+					 * 0x213 with no explanatory
+					 * comment.  0x203 probably
+					 * clashes with something. */
+#define ISAPNP_READ_PORT_MAX	0x3ff
+#define ISAPNP_READ_PORT_STEP	0x10	/* Can be any multiple of 4
+					 * according to the spec, but
+					 * since ISA I/O addresses are
+					 * allocated in blocks of 16,
+					 * it makes no sense to use
+					 * any value less than 16.
+					 */
+
+/* Card select numbers */
+#define ISAPNP_CSN_MIN		0x01
+#define ISAPNP_CSN_MAX		0x0f
+
+/* Registers */
+#define ISAPNP_READPORT			0x00
+#define ISAPNP_SERIALISOLATION 		0x01
+#define ISAPNP_CONFIGCONTROL		0x02
+#define ISAPNP_WAKE			0x03
+#define ISAPNP_RESOURCEDATA		0x04
+#define ISAPNP_STATUS          		0x05
+#define ISAPNP_CARDSELECTNUMBER		0x06
+#define ISAPNP_LOGICALDEVICENUMBER	0x07
+#define ISAPNP_ACTIVATE			0x30
+#define ISAPNP_IORANGECHECK		0x31
+#define ISAPNP_IOBASE(n)		( 0x60 + ( (n) * 2 ) )
+#define ISAPNP_IRQNO(n)			( 0x70 + ( (n) * 2 ) )
+#define ISAPNP_IRQTYPE(n)		( 0x71 + ( (n) * 2 ) )
+
+/* Bits in the CONFIGCONTROL register */
+#define ISAPNP_CONFIG_RESET		( 1 << 0 )
+#define ISAPNP_CONFIG_WAIT_FOR_KEY	( 1 << 1 )
+#define ISAPNP_CONFIG_RESET_CSN		( 1 << 2 )
+#define ISAPNP_CONFIG_RESET_DRV		( ISAPNP_CONFIG_RESET | 	\
+					  ISAPNP_CONFIG_WAIT_FOR_KEY |	\
+					  ISAPNP_CONFIG_RESET_CSN )
+
+/* The LFSR used for the initiation key and for checksumming */
+#define ISAPNP_LFSR_SEED		0x6a
+
+/* Small tags */
+#define ISAPNP_IS_SMALL_TAG(tag)	( ! ( (tag) & 0x80 ) )
+#define ISAPNP_SMALL_TAG_NAME(tag)	( ( (tag) >> 3 ) & 0xf )
+#define ISAPNP_SMALL_TAG_LEN(tag)	( ( (tag) & 0x7 ) )
+#define ISAPNP_TAG_PNPVERNO		0x01
+#define ISAPNP_TAG_LOGDEVID		0x02
+#define ISAPNP_TAG_COMPATDEVID		0x03
+#define ISAPNP_TAG_IRQ			0x04
+#define ISAPNP_TAG_DMA			0x05
+#define ISAPNP_TAG_STARTDEP		0x06
+#define ISAPNP_TAG_ENDDEP		0x07
+#define ISAPNP_TAG_IOPORT		0x08
+#define ISAPNP_TAG_FIXEDIO		0x09
+#define ISAPNP_TAG_RSVDSHORTA		0x0A
+#define ISAPNP_TAG_RSVDSHORTB		0x0B
+#define ISAPNP_TAG_RSVDSHORTC		0x0C
+#define ISAPNP_TAG_RSVDSHORTD		0x0D
+#define ISAPNP_TAG_VENDORSHORT		0x0E
+#define ISAPNP_TAG_END			0x0F
+/* Large tags */
+#define ISAPNP_IS_LARGE_TAG(tag)	( ( (tag) & 0x80 ) )
+#define ISAPNP_LARGE_TAG_NAME(tag)	(tag)
+#define ISAPNP_TAG_MEMRANGE		0x81
+#define ISAPNP_TAG_ANSISTR		0x82
+#define ISAPNP_TAG_UNICODESTR		0x83
+#define ISAPNP_TAG_VENDORLONG		0x84
+#define ISAPNP_TAG_MEM32RANGE		0x85
+#define ISAPNP_TAG_FIXEDMEM32RANGE	0x86
+#define ISAPNP_TAG_RSVDLONG0		0xF0
+#define ISAPNP_TAG_RSVDLONG1		0xF1
+#define ISAPNP_TAG_RSVDLONG2		0xF2
+#define ISAPNP_TAG_RSVDLONG3		0xF3
+#define ISAPNP_TAG_RSVDLONG4		0xF4
+#define ISAPNP_TAG_RSVDLONG5		0xF5
+#define ISAPNP_TAG_RSVDLONG6		0xF6
+#define ISAPNP_TAG_RSVDLONG7		0xF7
+#define ISAPNP_TAG_RSVDLONG8		0xF8
+#define ISAPNP_TAG_RSVDLONG9		0xF9
+#define ISAPNP_TAG_RSVDLONGA		0xFA
+#define ISAPNP_TAG_RSVDLONGB		0xFB
+#define ISAPNP_TAG_RSVDLONGC		0xFC
+#define ISAPNP_TAG_RSVDLONGD		0xFD
+#define ISAPNP_TAG_RSVDLONGE		0xFE
+#define ISAPNP_TAG_RSVDLONGF		0xFF
+#define ISAPNP_TAG_PSEUDO_NEWBOARD	0x100
+
+/** An ISAPnP serial identifier */
+struct isapnp_identifier {
+	/** Vendor ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+	/** Serial number */
+	uint32_t serial;
+	/** Checksum */
+	uint8_t checksum;
+} __attribute__ (( packed ));
+
+/** An ISAPnP logical device ID structure */
+struct isapnp_logdevid {
+	/** Vendor ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+	/** Flags */
+	uint16_t flags;
+} __attribute__ (( packed ));
+
+/** An ISAPnP device ID list entry */
+struct isapnp_device_id {
+	/** Name */
+        const char *name;
+	/** Vendor ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+};
+
+/** An ISAPnP device */
+struct isapnp_device {
+	/** Generic device */
+	struct device dev;
+	/** Vendor ID */
+	uint16_t vendor_id;
+	/** Product ID */
+	uint16_t prod_id;
+	/** I/O address */
+	uint16_t ioaddr;
+	/** Interrupt number */
+	uint8_t irqno;
+	/** Card Select Number */
+	uint8_t csn;
+	/** Logical Device ID */
+	uint8_t logdev;
+	/** Driver for this device */
+	struct isapnp_driver *driver;
+	/** Driver-private data
+	 *
+	 * Use isapnp_set_drvdata() and isapnp_get_drvdata() to access
+	 * this field.
+	 */
+	void *priv;
+};
+
+/** An ISAPnP driver */
+struct isapnp_driver {
+	/** ISAPnP ID table */
+	struct isapnp_device_id *ids;
+	/** Number of entries in ISAPnP ID table */
+	unsigned int id_count;
+	/**
+	 * Probe device
+	 *
+	 * @v isapnp	ISAPnP device
+	 * @v id	Matching entry in ID table
+	 * @ret rc	Return status code
+	 */
+	int ( * probe ) ( struct isapnp_device *isapnp,
+			  const struct isapnp_device_id *id );
+	/**
+	 * Remove device
+	 *
+	 * @v isapnp	ISAPnP device
+	 */
+	void ( * remove ) ( struct isapnp_device *isapnp );
+};
+
+/** ISAPnP driver table */
+#define ISAPNP_DRIVERS __table ( struct isapnp_driver, "isapnp_drivers" )
+
+/** Declare an ISAPnP driver */
+#define __isapnp_driver __table_entry ( ISAPNP_DRIVERS, 01 )
+
+extern uint16_t isapnp_read_port;
+
+extern void isapnp_device_activation ( struct isapnp_device *isapnp,
+				       int activation );
+
+/**
+ * Activate ISAPnP device
+ *
+ * @v isapnp		ISAPnP device
+ */
+static inline void activate_isapnp_device ( struct isapnp_device *isapnp ) {
+	isapnp_device_activation ( isapnp, 1 );
+}
+
+/**
+ * Deactivate ISAPnP device
+ *
+ * @v isapnp		ISAPnP device
+ */
+static inline void deactivate_isapnp_device ( struct isapnp_device *isapnp ) {
+	isapnp_device_activation ( isapnp, 0 );
+}
+
+/**
+ * Set ISAPnP driver-private data
+ *
+ * @v isapnp		ISAPnP device
+ * @v priv		Private data
+ */
+static inline void isapnp_set_drvdata ( struct isapnp_device *isapnp,
+					void *priv ) {
+	isapnp->priv = priv;
+}
+
+/**
+ * Get ISAPnP driver-private data
+ *
+ * @v isapnp		ISAPnP device
+ * @ret priv		Private data
+ */
+static inline void * isapnp_get_drvdata ( struct isapnp_device *isapnp ) {
+	return isapnp->priv;
+}
+
+#endif /* ISAPNP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/iscsi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/iscsi.h
new file mode 100644
index 0000000..5d3d73b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/iscsi.h
@@ -0,0 +1,702 @@
+#ifndef _IPXE_ISCSI_H
+#define _IPXE_ISCSI_H
+
+/** @file
+ *
+ * iSCSI protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/socket.h>
+#include <ipxe/scsi.h>
+#include <ipxe/chap.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/xfer.h>
+#include <ipxe/process.h>
+
+/** Default iSCSI port */
+#define ISCSI_PORT 3260
+
+/**
+ * iSCSI segment lengths
+ *
+ * iSCSI uses an icky structure with one one-byte field (a dword
+ * count) and one three-byte field (a byte count).  This structure,
+ * and the accompanying macros, relieve some of the pain.
+ */
+union iscsi_segment_lengths {
+	struct {
+		/** The AHS length (measured in dwords) */
+		uint8_t ahs_len;
+		/** The data length (measured in bytes), in network
+		 * byte order
+		 */
+		uint8_t data_len[3];
+	} bytes;
+	/** Ths data length (measured in bytes), in network byte
+	 * order, with ahs_len as the first byte.
+	 */
+	uint32_t ahs_and_data_len;
+};
+
+/** The length of the additional header segment, in dwords */
+#define ISCSI_AHS_LEN( segment_lengths ) \
+	( (segment_lengths).bytes.ahs_len )
+
+/** The length of the data segment, in bytes, excluding any padding */
+#define ISCSI_DATA_LEN( segment_lengths ) \
+	( ntohl ( (segment_lengths).ahs_and_data_len ) & 0xffffff )
+
+/** The padding of the data segment, in bytes */
+#define ISCSI_DATA_PAD_LEN( segment_lengths ) \
+	( ( 0 - (segment_lengths).bytes.data_len[2] ) & 0x03 )
+
+/** Set additional header and data segment lengths */
+#define ISCSI_SET_LENGTHS( segment_lengths, ahs_len, data_len ) do {	\
+	(segment_lengths).ahs_and_data_len =				\
+		htonl ( data_len | ( ahs_len << 24 ) );			\
+	} while ( 0 )
+
+/**
+ * iSCSI basic header segment common fields
+ *
+ */
+struct iscsi_bhs_common {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Fields specific to the PDU type */
+	uint8_t other_a[2];
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Fields specific to the PDU type */
+	uint8_t other_b[8];
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Fields specific to the PDU type */
+	uint8_t other_c[28];
+};
+
+/** Opcode mask */
+#define ISCSI_OPCODE_MASK 0x3f
+
+/** Immediate delivery */
+#define ISCSI_FLAG_IMMEDIATE 0x40
+
+/** Final PDU of a sequence */
+#define ISCSI_FLAG_FINAL 0x80
+
+/** iSCSI tag magic marker */
+#define ISCSI_TAG_MAGIC 0x18ae0000
+
+/** iSCSI reserved tag value */
+#define ISCSI_TAG_RESERVED 0xffffffff
+
+/**
+ * iSCSI basic header segment common request fields
+ *
+ */
+struct iscsi_bhs_common_response {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Fields specific to the PDU type */
+	uint8_t other_a[2];
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Fields specific to the PDU type */
+	uint8_t other_b[8];
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Fields specific to the PDU type */
+	uint8_t other_c[4];
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Fields specific to the PDU type */
+	uint8_t other_d[16];
+};
+
+/**
+ * iSCSI login request basic header segment
+ *
+ */
+struct iscsi_bhs_login_request {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Maximum supported version number */
+	uint8_t version_max;
+	/** Minimum supported version number */
+	uint8_t version_min;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Initiator session ID (IANA format) enterprise number and flags */
+	uint32_t isid_iana_en;
+	/** Initiator session ID (IANA format) qualifier */
+	uint16_t isid_iana_qual;
+	/** Target session identifying handle */
+	uint16_t tsih;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Connection ID */
+	uint16_t cid;
+	/** Reserved */
+	uint16_t reserved_a;
+	/** Command sequence number */
+	uint32_t cmdsn;
+	/** Expected status sequence number */
+	uint32_t expstatsn;
+	/** Reserved */
+	uint8_t reserved_b[16];
+};
+
+/** Login request opcode */
+#define ISCSI_OPCODE_LOGIN_REQUEST 0x03
+
+/** Willingness to transition to next stage */
+#define ISCSI_LOGIN_FLAG_TRANSITION 0x80
+
+/** Key=value pairs continued in subsequent request */
+#define ISCSI_LOGIN_FLAG_CONTINUE 0x40
+
+/* Current stage values and mask */
+#define ISCSI_LOGIN_CSG_MASK 0x0c
+#define ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION 0x00
+#define ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION 0x04
+#define ISCSI_LOGIN_CSG_FULL_FEATURE_PHASE 0x0c
+
+/* Next stage values and mask */
+#define ISCSI_LOGIN_NSG_MASK 0x03
+#define ISCSI_LOGIN_NSG_SECURITY_NEGOTIATION 0x00
+#define ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION 0x01
+#define ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE 0x03
+
+/** ISID IANA format marker */
+#define ISCSI_ISID_IANA 0x40000000
+
+/** Fen Systems Ltd. IANA enterprise number
+ *
+ * Permission is hereby granted to use Fen Systems Ltd.'s IANA
+ * enterprise number with this iSCSI implementation.
+ */
+#define IANA_EN_FEN_SYSTEMS 10019
+
+/**
+ * iSCSI login response basic header segment
+ *
+ */
+struct iscsi_bhs_login_response {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Maximum supported version number */
+	uint8_t version_max;
+	/** Minimum supported version number */
+	uint8_t version_min;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Initiator session ID (IANA format) enterprise number and flags */
+	uint32_t isid_iana_en;
+	/** Initiator session ID (IANA format) qualifier */
+	uint16_t isid_iana_qual;
+	/** Target session identifying handle */
+	uint16_t tsih;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Reserved */
+	uint32_t reserved_a;
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Maximum command sequence number */
+	uint32_t maxcmdsn;
+	/** Status class */
+	uint8_t status_class;
+	/** Status detail */
+	uint8_t status_detail;
+	/** Reserved */
+	uint8_t reserved_b[10];
+};
+
+/** Login response opcode */
+#define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
+
+/* Login response status codes */
+#define ISCSI_STATUS_SUCCESS			0x00
+#define ISCSI_STATUS_REDIRECT			0x01
+#define ISCSI_STATUS_INITIATOR_ERROR		0x02
+#define ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION	0x01
+#define ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION	0x02
+#define ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND		0x03
+#define ISCSI_STATUS_INITIATOR_ERROR_REMOVED		0x04
+#define ISCSI_STATUS_TARGET_ERROR		0x03
+#define ISCSI_STATUS_TARGET_ERROR_UNAVAILABLE		0x01
+#define ISCSI_STATUS_TARGET_ERROR_NO_RESOURCES		0x02
+
+/**
+ * iSCSI SCSI command basic header segment
+ *
+ */
+struct iscsi_bhs_scsi_command {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Reserved */
+	uint16_t reserved_a;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** SCSI Logical Unit Number */
+	struct scsi_lun lun;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Expected data transfer length */
+	uint32_t exp_len;
+	/** Command sequence number */
+	uint32_t cmdsn;
+	/** Expected status sequence number */
+	uint32_t expstatsn;
+	/** SCSI Command Descriptor Block (CDB) */
+	union scsi_cdb cdb;
+};
+
+/** SCSI command opcode */
+#define ISCSI_OPCODE_SCSI_COMMAND 0x01
+
+/** Command will read data */
+#define ISCSI_COMMAND_FLAG_READ 0x40
+
+/** Command will write data */
+#define ISCSI_COMMAND_FLAG_WRITE 0x20
+
+/* Task attributes */
+#define ISCSI_COMMAND_ATTR_UNTAGGED 0x00
+#define ISCSI_COMMAND_ATTR_SIMPLE 0x01
+#define ISCSI_COMMAND_ATTR_ORDERED 0x02
+#define ISCSI_COMMAND_ATTR_HEAD_OF_QUEUE 0x03
+#define ISCSI_COMMAND_ATTR_ACA 0x04
+
+/**
+ * iSCSI SCSI response basic header segment
+ *
+ */
+struct iscsi_bhs_scsi_response {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Response code */
+	uint8_t response;
+	/** SCSI status code */
+	uint8_t status;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Reserved */
+	uint8_t reserved_a[8];
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** SNACK tag */
+	uint32_t snack;
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Maximum command sequence number */
+	uint32_t maxcmdsn;
+	/** Expected data sequence number */
+	uint32_t expdatasn;
+	/** Bidirectional read residual count */
+	uint32_t bidi_residual_count;
+	/** Residual count */
+	uint32_t residual_count;
+};
+
+/** SCSI response opcode */
+#define ISCSI_OPCODE_SCSI_RESPONSE 0x21
+
+/** SCSI command completed at target */
+#define ISCSI_RESPONSE_COMMAND_COMPLETE 0x00
+
+/** SCSI target failure */
+#define ISCSI_RESPONSE_TARGET_FAILURE 0x01
+
+/** Data overflow occurred */
+#define ISCSI_RESPONSE_FLAG_OVERFLOW 0x20
+
+/** Data underflow occurred */
+#define ISCSI_RESPONSE_FLAG_UNDERFLOW 0x40
+
+/**
+ * iSCSI data-in basic header segment
+ *
+ */
+struct iscsi_bhs_data_in {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** SCSI status code */
+	uint8_t status;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Logical Unit Number */
+	struct scsi_lun lun;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Target Transfer Tag */
+	uint32_t ttt;
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Maximum command sequence number */
+	uint32_t maxcmdsn;
+	/** Data sequence number */
+	uint32_t datasn;
+	/** Buffer offset */
+	uint32_t offset;
+	/** Residual count */
+	uint32_t residual_count;
+};
+
+/** Data-in opcode */
+#define ISCSI_OPCODE_DATA_IN 0x25
+
+/** Data requires acknowledgement */
+#define ISCSI_DATA_FLAG_ACKNOWLEDGE 0x40
+
+/** Data overflow occurred */
+#define ISCSI_DATA_FLAG_OVERFLOW 0x04
+
+/** Data underflow occurred */
+#define ISCSI_DATA_FLAG_UNDERFLOW 0x02
+
+/** SCSI status code and overflow/underflow flags are valid */
+#define ISCSI_DATA_FLAG_STATUS 0x01
+
+/**
+ * iSCSI data-out basic header segment
+ *
+ */
+struct iscsi_bhs_data_out {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Reserved */
+	uint16_t reserved_a;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Logical Unit Number */
+	struct scsi_lun lun;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Target Transfer Tag */
+	uint32_t ttt;
+	/** Reserved */
+	uint32_t reserved_b;
+	/** Expected status sequence number */
+	uint32_t expstatsn;
+	/** Reserved */
+	uint32_t reserved_c;
+	/** Data sequence number */
+	uint32_t datasn;
+	/** Buffer offset */
+	uint32_t offset;
+	/** Reserved */
+	uint32_t reserved_d;
+};
+
+/** Data-out opcode */
+#define ISCSI_OPCODE_DATA_OUT 0x05
+
+/**
+ * iSCSI request to transfer basic header segment
+ *
+ */
+struct iscsi_bhs_r2t {
+	/** Opcode */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Reserved */
+	uint16_t reserved_a;
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Logical Unit Number */
+	struct scsi_lun lun;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Target Transfer Tag */
+	uint32_t ttt;
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Maximum command sequence number */
+	uint32_t maxcmdsn;
+	/** R2T sequence number */
+	uint32_t r2tsn;
+	/** Buffer offset */
+	uint32_t offset;
+	/** Desired data transfer length */
+	uint32_t len;
+};
+
+/** R2T opcode */
+#define ISCSI_OPCODE_R2T 0x31
+
+/**
+ * iSCSI NOP-In basic header segment
+ *
+ */
+struct iscsi_nop_in {
+	/** Opcode */
+	uint8_t opcode;
+	/** Reserved */
+	uint8_t reserved_a[3];
+	/** Segment lengths */
+	union iscsi_segment_lengths lengths;
+	/** Logical Unit Number */
+	struct scsi_lun lun;
+	/** Initiator Task Tag */
+	uint32_t itt;
+	/** Target Transfer Tag */
+	uint32_t ttt;
+	/** Status sequence number */
+	uint32_t statsn;
+	/** Expected command sequence number */
+	uint32_t expcmdsn;
+	/** Maximum command sequence number */
+	uint32_t maxcmdsn;
+	/** Reserved */
+	uint8_t reserved_b[12];
+};
+
+/** NOP-In opcode */
+#define ISCSI_OPCODE_NOP_IN 0x20
+
+/**
+ * An iSCSI basic header segment
+ */
+union iscsi_bhs {
+	struct iscsi_bhs_common common;
+	struct iscsi_bhs_common_response common_response;
+	struct iscsi_bhs_login_request login_request;
+	struct iscsi_bhs_login_response login_response;
+	struct iscsi_bhs_scsi_command scsi_command;
+	struct iscsi_bhs_scsi_response scsi_response;
+	struct iscsi_bhs_data_in data_in;
+	struct iscsi_bhs_data_out data_out;
+	struct iscsi_bhs_r2t r2t;
+	struct iscsi_nop_in nop_in;
+	unsigned char bytes[ sizeof ( struct iscsi_bhs_common ) ];
+};
+
+/** State of an iSCSI TX engine */
+enum iscsi_tx_state {
+	/** Nothing to send */
+	ISCSI_TX_IDLE = 0,
+	/** Sending the basic header segment */
+	ISCSI_TX_BHS,
+	/** Sending the additional header segment */
+	ISCSI_TX_AHS,
+	/** Sending the data segment */
+	ISCSI_TX_DATA,
+	/** Sending the data segment padding */
+	ISCSI_TX_DATA_PADDING,
+};
+
+/** State of an iSCSI RX engine */
+enum iscsi_rx_state {
+	/** Receiving the basic header segment */
+	ISCSI_RX_BHS = 0,
+	/** Receiving the additional header segment */
+	ISCSI_RX_AHS,
+	/** Receiving the data segment */
+	ISCSI_RX_DATA,
+	/** Receiving the data segment padding */
+	ISCSI_RX_DATA_PADDING,
+};
+
+/** An iSCSI session */
+struct iscsi_session {
+	/** Reference counter */
+	struct refcnt refcnt;
+
+	/** SCSI command-issuing interface */
+	struct interface control;
+	/** SCSI command interface */
+	struct interface data;
+	/** Transport-layer socket */
+	struct interface socket;
+
+	/** Initiator IQN */
+	char *initiator_iqn;
+	/** Target address */
+	char *target_address;
+	/** Target port */
+	unsigned int target_port;
+	/** Target IQN */
+	char *target_iqn;
+
+	/** Session status
+	 *
+	 * This is the bitwise-OR of zero or more ISCSI_STATUS_XXX
+	 * constants.
+	 */
+	int status;
+
+	/** Initiator username (if any) */
+	char *initiator_username;
+	/** Initiator password (if any) */
+	char *initiator_password;
+	/** Target username (if any) */
+	char *target_username;
+	/** Target password (if any) */
+	char *target_password;
+	/** CHAP challenge (for target auth only)
+	 *
+	 * This is a block of random data; the first byte is used as
+	 * the CHAP identifier (CHAP_I) and the remainder as the CHAP
+	 * challenge (CHAP_C).
+	 */
+	unsigned char chap_challenge[17];
+	/** CHAP response (used for both initiator and target auth) */
+	struct chap_response chap;
+
+	/** Initiator session ID (IANA format) qualifier
+	 *
+	 * This is part of the ISID.  It is generated randomly
+	 * whenever a new connection is opened.
+	 */
+	uint16_t isid_iana_qual;
+	/** Initiator task tag
+	 *
+	 * This is the tag of the current command.  It is incremented
+	 * whenever a new command is started.
+	 */
+	uint32_t itt;
+	/** Target transfer tag
+	 *
+	 * This is the tag attached to a sequence of data-out PDUs in
+	 * response to an R2T.
+	 */
+	uint32_t ttt;
+	/** Transfer offset
+	 *
+	 * This is the offset for an in-progress sequence of data-out
+	 * PDUs in response to an R2T.
+	 */
+	uint32_t transfer_offset;
+	/** Transfer length
+	 *
+	 * This is the length for an in-progress sequence of data-out
+	 * PDUs in response to an R2T.
+	 */
+	uint32_t transfer_len;
+	/** Command sequence number
+	 *
+	 * This is the sequence number of the current command, used to
+	 * fill out the CmdSN field in iSCSI request PDUs.  It is
+	 * updated with the value of the ExpCmdSN field whenever we
+	 * receive an iSCSI response PDU containing such a field.
+	 */
+	uint32_t cmdsn;
+	/** Status sequence number
+	 *
+	 * This is the most recent status sequence number present in
+	 * the StatSN field of an iSCSI response PDU containing such a
+	 * field.  Whenever we send an iSCSI request PDU, we fill out
+	 * the ExpStatSN field with this value plus one.
+	 */
+	uint32_t statsn;
+	
+	/** Basic header segment for current TX PDU */
+	union iscsi_bhs tx_bhs;
+	/** State of the TX engine */
+	enum iscsi_tx_state tx_state;
+	/** TX process */
+	struct process process;
+
+	/** Basic header segment for current RX PDU */
+	union iscsi_bhs rx_bhs;
+	/** State of the RX engine */
+	enum iscsi_rx_state rx_state;
+	/** Byte offset within the current RX state */
+	size_t rx_offset;
+	/** Length of the current RX state */
+	size_t rx_len;
+	/** Buffer for received data (not always used) */
+	void *rx_buffer;
+
+	/** Current SCSI command, if any */
+	struct scsi_cmd *command;
+
+	/** Target socket address (for boot firmware table) */
+	struct sockaddr target_sockaddr;
+	/** SCSI LUN (for boot firmware table) */
+	struct scsi_lun lun;
+};
+
+/** iSCSI session is currently in the security negotiation phase */
+#define ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE		\
+	( ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION |	\
+	  ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION )
+
+/** iSCSI session is currently in the operational parameter
+ * negotiation phase
+ */
+#define ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE	\
+	( ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION |	\
+	  ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE )
+
+/** iSCSI session is currently in the full feature phase */
+#define ISCSI_STATUS_FULL_FEATURE_PHASE	ISCSI_LOGIN_CSG_FULL_FEATURE_PHASE
+
+/** Mask for all iSCSI session phases */
+#define ISCSI_STATUS_PHASE_MASK ( ISCSI_LOGIN_CSG_MASK | ISCSI_LOGIN_NSG_MASK )
+
+/** iSCSI session needs to send the initial security negotiation strings */
+#define ISCSI_STATUS_STRINGS_SECURITY 0x0100
+
+/** iSCSI session needs to send the CHAP_A string */
+#define ISCSI_STATUS_STRINGS_CHAP_ALGORITHM 0x0200
+
+/** iSCSI session needs to send the CHAP response */
+#define ISCSI_STATUS_STRINGS_CHAP_RESPONSE 0x0400
+
+/** iSCSI session needs to send the mutual CHAP challenge */
+#define ISCSI_STATUS_STRINGS_CHAP_CHALLENGE 0x0800
+
+/** iSCSI session needs to send the operational negotiation strings */
+#define ISCSI_STATUS_STRINGS_OPERATIONAL 0x1000
+
+/** Mask for all iSCSI "needs to send" flags */
+#define ISCSI_STATUS_STRINGS_MASK 0xff00
+
+/** Target has requested forward (initiator) authentication */
+#define ISCSI_STATUS_AUTH_FORWARD_REQUIRED 0x00010000
+
+/** Initiator requires target (reverse) authentication */
+#define ISCSI_STATUS_AUTH_REVERSE_REQUIRED 0x00020000
+
+/** Target authenticated itself correctly */
+#define ISCSI_STATUS_AUTH_REVERSE_OK 0x00040000
+
+/** Default initiator IQN prefix */
+#define ISCSI_DEFAULT_IQN_PREFIX "iqn.2010-04.org.ipxe"
+
+#endif /* _IPXE_ISCSI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/job.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/job.h
new file mode 100644
index 0000000..c2232fc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/job.h
@@ -0,0 +1,38 @@
+#ifndef _IPXE_JOB_H
+#define _IPXE_JOB_H
+
+/** @file
+ *
+ * Job control interfaces
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/interface.h>
+
+/** Job progress */
+struct job_progress {
+	/** Amount of operation completed so far
+	 *
+	 * The units for this quantity are arbitrary.  @c completed
+	 * divded by @total should give something which approximately
+	 * represents the progress through the operation.  For a
+	 * download operation, using byte counts would make sense.
+	 */
+	unsigned long completed;
+	/** Total operation size
+	 *
+	 * See @c completed.  A zero value means "total size unknown"
+	 * and is explcitly permitted; users should take this into
+	 * account before calculating @c completed/total.
+	 */
+	unsigned long total;
+};
+
+extern void job_progress ( struct interface *intf,
+			   struct job_progress *progress );
+#define job_progress_TYPE( object_type ) \
+	typeof ( void ( object_type, struct job_progress *progress ) )
+
+#endif /* _IPXE_JOB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/keymap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/keymap.h
new file mode 100644
index 0000000..9ac42a6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/keymap.h
@@ -0,0 +1,30 @@
+#ifndef _IPXE_KEYMAP_H
+#define _IPXE_KEYMAP_H
+
+/**
+ * @file
+ *
+ * Keyboard mappings
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/tables.h>
+
+/** A keyboard mapping */
+struct key_mapping {
+	/** Character read from keyboard */
+	uint8_t from;
+	/** Character to be used instead */
+	uint8_t to;
+} __attribute__ (( packed ));
+
+/** Keyboard mapping table */
+#define KEYMAP __table ( struct key_mapping, "keymap" )
+
+/** Define a keyboard mapping */
+#define __keymap __table_entry ( KEYMAP, 01 )
+
+#endif /* _IPXE_KEYMAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/keys.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/keys.h
new file mode 100644
index 0000000..8b13550
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/keys.h
@@ -0,0 +1,88 @@
+#ifndef _IPXE_KEYS_H
+#define _IPXE_KEYS_H
+
+/** @file
+ *
+ * Key definitions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * Symbolic names for some standard ASCII characters
+ *
+ */
+
+#define NUL		0x00
+#define CTRL_A		0x01
+#define CTRL_B		0x02
+#define CTRL_C		0x03
+#define CTRL_D		0x04
+#define CTRL_E		0x05
+#define CTRL_F		0x06
+#define CTRL_G		0x07
+#define CTRL_H		0x08
+#define CTRL_I		0x09
+#define CTRL_J		0x0a
+#define CTRL_K		0x0b
+#define CTRL_L		0x0c
+#define CTRL_M		0x0d
+#define CTRL_N		0x0e
+#define CTRL_O		0x0f
+#define CTRL_P		0x10
+#define CTRL_Q		0x11
+#define CTRL_R		0x12
+#define CTRL_S		0x13
+#define CTRL_T		0x14
+#define CTRL_U		0x15
+#define CTRL_V		0x16
+#define CTRL_W		0x17
+#define CTRL_X		0x18
+#define CTRL_Y		0x19
+#define CTRL_Z		0x1a
+
+#define BACKSPACE	CTRL_H
+#define TAB		CTRL_I
+#define LF		CTRL_J
+#define CR		CTRL_M
+#define ESC		0x1b
+
+/*
+ * Special keys outside the normal ASCII range 
+ *
+ *
+ * The names are chosen to match those used by curses.  The values are
+ * chosen to facilitate easy conversion from a received ANSI escape
+ * sequence to a KEY_XXX constant.
+ */
+
+#define KEY_ANSI( n, terminator ) ( 0x100 * ( (n) + 1 ) + (terminator) )
+
+#define KEY_MIN		0x101
+#define KEY_UP		KEY_ANSI ( 0, 'A' )	/**< Up arrow */
+#define KEY_DOWN	KEY_ANSI ( 0, 'B' )	/**< Down arrow */
+#define KEY_RIGHT	KEY_ANSI ( 0, 'C' )	/**< Right arrow */
+#define KEY_LEFT	KEY_ANSI ( 0, 'D' )	/**< Left arrow */
+#define KEY_END		KEY_ANSI ( 0, 'F' )	/**< End */
+#define KEY_HOME	KEY_ANSI ( 0, 'H' )	/**< Home */
+#define KEY_IC		KEY_ANSI ( 2, '~' )	/**< Insert */
+#define KEY_DC		KEY_ANSI ( 3, '~' )	/**< Delete */
+#define KEY_PPAGE	KEY_ANSI ( 5, '~' )	/**< Page up */
+#define KEY_NPAGE	KEY_ANSI ( 6, '~' )	/**< Page down */
+#define KEY_F5		KEY_ANSI ( 15, '~' )	/**< F5 */
+#define KEY_F6		KEY_ANSI ( 17, '~' )	/**< F6 */
+#define KEY_F7		KEY_ANSI ( 18, '~' )	/**< F7 */
+#define KEY_F8		KEY_ANSI ( 19, '~' )	/**< F8 (for PXE) */
+#define KEY_F9		KEY_ANSI ( 20, '~' )	/**< F9 */
+#define KEY_F10		KEY_ANSI ( 21, '~' )	/**< F10 */
+#define KEY_F11		KEY_ANSI ( 23, '~' )	/**< F11 */
+#define KEY_F12		KEY_ANSI ( 24, '~' )	/**< F12 */
+
+/* Not in the [KEY_MIN,KEY_MAX] range; terminals seem to send these as
+ * normal ASCII values.
+ */
+#define KEY_BACKSPACE	BACKSPACE
+#define KEY_ENTER	LF
+
+#endif /* _IPXE_KEYS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linebuf.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linebuf.h
new file mode 100644
index 0000000..706ef25
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linebuf.h
@@ -0,0 +1,30 @@
+#ifndef _IPXE_LINEBUF_H
+#define _IPXE_LINEBUF_H
+
+/** @file
+ *
+ * Line buffering
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+
+/** A line buffer */
+struct line_buffer {
+	/** Current string in the buffer */
+	char *data;
+	/** Length of current string, excluding the terminating NUL */
+	size_t len;
+	/** String is ready to read */
+	int ready;
+};
+
+extern char * buffered_line ( struct line_buffer *linebuf );
+extern ssize_t line_buffer ( struct line_buffer *linebuf,
+			     const char *data, size_t len );
+extern void empty_line_buffer ( struct line_buffer *linebuf );
+
+#endif /* _IPXE_LINEBUF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux.h
new file mode 100644
index 0000000..dac508e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _IPXE_LINUX_H
+#define _IPXE_LINUX_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * Linux devices, drivers and device requests.
+ */
+
+#include <ipxe/list.h>
+#include <ipxe/device.h>
+#include <ipxe/settings.h>
+
+/** A linux device */
+struct linux_device {
+	/** Generic device */
+	struct device dev;
+	/** Driver that's handling the device */
+	struct linux_driver *driver;
+	/** Private data used by drivers */
+	void *priv;
+};
+
+struct linux_device_request;
+
+/** A linux driver */
+struct linux_driver {
+	/** Name */
+	char *name;
+	/** Probe function */
+	int (*probe)(struct linux_device *device, struct linux_device_request *request);
+	/** Remove function */
+	void (*remove)(struct linux_device *device);
+	/** Can the driver probe any more devices? */
+	int can_probe;
+};
+
+/** Linux driver table */
+#define LINUX_DRIVERS __table(struct linux_driver, "linux_drivers")
+
+/** Declare a Linux driver */
+#define __linux_driver __table_entry(LINUX_DRIVERS, 01)
+
+/**
+ * Set linux device driver-private data
+ *
+ * @v device	Linux device
+ * @v priv		Private data
+ */
+static inline void linux_set_drvdata(struct linux_device * device, void *priv)
+{
+	device->priv = priv;
+}
+
+/**
+ * Get linux device driver-private data
+ *
+ * @v device	Linux device
+ * @ret priv	Private data
+ */
+static inline void *linux_get_drvdata(struct linux_device *device)
+{
+	return device->priv;
+}
+
+/**
+ * A device request.
+ *
+ * To be created and filled by the UI code.
+ */
+struct linux_device_request {
+	/** Driver name. Compared to the linux drivers' names */
+	char *driver;
+	/** List node */
+	struct list_head list;
+	/** List of settings */
+	struct list_head settings;
+};
+
+/** A device request setting */
+struct linux_setting {
+	/** Name */
+	char *name;
+	/** Value */
+	char *value;
+	/** Was the setting already applied? */
+	int applied;
+	/** List node */
+	struct list_head list;
+};
+
+/**
+ * List of requested devices.
+ *
+ * Filled by the UI code. Linux root_driver walks over this list looking for an
+ * appropriate driver to handle each request by matching the driver's name.
+ */
+extern struct list_head linux_device_requests;
+
+/**
+ * List of global settings to apply.
+ *
+ * Filled by the UI code. Linux root_driver applies these settings.
+ */
+extern struct list_head linux_global_settings;
+
+/**
+ * Look for the last occurrence of a setting with the specified name
+ *
+ * @v name     Name of the setting to look for
+ * @v settings List of the settings to look through
+ */
+struct linux_setting *linux_find_setting(char *name, struct list_head *settings);
+
+/**
+ * Apply a list of linux settings to a settings block
+ *
+ * @v new_settings     List of linux_setting's to apply
+ * @v settings_block   Settings block to apply the settings to
+ * @ret rc             0 on success
+ */
+extern void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block);
+
+
+#endif /* _IPXE_LINUX_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_nap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_nap.h
new file mode 100644
index 0000000..5bac724
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_nap.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_LINUX_NAP_H
+#define _IPXE_LINUX_NAP_H
+
+/** @file
+ *
+ * Linux CPU sleeping
+ *
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#ifdef NAP_LINUX
+#define NAP_PREFIX_linux
+#else
+#define NAP_PREFIX_linux __linux_
+#endif
+
+#endif /* _IPXE_LINUX_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_smbios.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
new file mode 100644
index 0000000..6d51e13
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_LINUX_SMBIOS_H
+#define _IPXE_LINUX_SMBIOS_H
+
+/** @file
+ *
+ * iPXE SMBIOS API for linux
+ *
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#ifdef SMBIOS_LINUX
+#define SMBIOS_PREFIX_linux
+#else
+#define SMBIOS_PREFIX_linux __linux_
+#endif
+
+#endif /* _IPXE_LINUX_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_timer.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_timer.h
new file mode 100644
index 0000000..3795074
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_timer.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_LINUX_TIMER_H
+#define _IPXE_LINUX_TIMER_H
+
+/** @file
+ *
+ * iPXE timer API for Linux
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIMER_LINUX
+#define TIMER_PREFIX_linux
+#else
+#define TIMER_PREFIX_linux __linux_
+#endif
+
+#endif /* _IPXE_LINUX_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
new file mode 100644
index 0000000..1b49611
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _IPXE_LINUX_UACCESS_H
+#define _IPXE_LINUX_UACCESS_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * iPXE user access API for linux
+ *
+ * In linux userspace virtual == user == phys addresses.
+ * Physical addresses also being the same is wrong, but there is no general way
+ * of converting userspace addresses to physical as what appears to be
+ * contiguous in userspace is physically fragmented.
+ * Currently only the DMA memory is special-cased, but its conversion to bus
+ * addresses is done in phys_to_bus.
+ * This is known to break virtio as it is passing phys addresses to the virtual
+ * device.
+ */
+
+#ifdef UACCESS_LINUX
+#define UACCESS_PREFIX_linux
+#else
+#define UACCESS_PREFIX_linux __linux_
+#endif
+
+static inline __always_inline userptr_t
+UACCESS_INLINE(linux, phys_to_user)(unsigned long phys_addr)
+{
+	return phys_addr;
+}
+
+static inline __always_inline unsigned long
+UACCESS_INLINE(linux, user_to_phys)(userptr_t userptr, off_t offset)
+{
+	return userptr + offset;
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE(linux, virt_to_user)(volatile const void *addr)
+{
+	return trivial_virt_to_user(addr);
+}
+
+static inline __always_inline void *
+UACCESS_INLINE(linux, user_to_virt)(userptr_t userptr, off_t offset)
+{
+	return trivial_user_to_virt(userptr, offset);
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE(linux, userptr_add)(userptr_t userptr, off_t offset)
+{
+	return trivial_userptr_add(userptr, offset);
+}
+
+static inline __always_inline void
+UACCESS_INLINE(linux, memcpy_user)(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
+{
+	trivial_memcpy_user(dest, dest_off, src, src_off, len);
+}
+
+static inline __always_inline void
+UACCESS_INLINE(linux, memmove_user)(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
+{
+	trivial_memmove_user(dest, dest_off, src, src_off, len);
+}
+
+static inline __always_inline void
+UACCESS_INLINE(linux, memset_user)(userptr_t buffer, off_t offset, int c, size_t len)
+{
+	trivial_memset_user(buffer, offset, c, len);
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE(linux, strlen_user)(userptr_t buffer, off_t offset)
+{
+	return trivial_strlen_user(buffer, offset);
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE(linux, memchr_user)(userptr_t buffer, off_t offset, int c, size_t len)
+{
+	return trivial_memchr_user(buffer, offset, c, len);
+}
+
+#endif /* _IPXE_LINUX_UACCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
new file mode 100644
index 0000000..4de55ec
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_LINUX_UMALLOC_H
+#define _IPXE_LINUX_UMALLOC_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * iPXE user memory allocation API for linux
+ *
+ */
+
+#ifdef UMALLOC_LINUX
+#define UMALLOC_PREFIX_linux
+#else
+#define UMALLOC_PREFIX_linux __linux_
+#endif
+
+#endif /* _IPXE_LINUX_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux_compat.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux_compat.h
new file mode 100644
index 0000000..6f6ed97
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/linux_compat.h
@@ -0,0 +1,27 @@
+#ifndef _IPXE_LINUX_COMPAT_H
+#define _IPXE_LINUX_COMPAT_H
+
+/** @file
+ *
+ * Linux code compatibility
+ *
+ * This file exists to ease the building of Linux source code within
+ * iPXE.  This is intended to facilitate quick testing; it is not
+ * intended to be a substitute for proper porting.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <ipxe/bitops.h>
+
+#define __init
+#define __exit
+#define __initdata
+#define __exitdata
+#define printk printf
+
+#endif /* _IPXE_LINUX_COMPAT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/list.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/list.h
new file mode 100644
index 0000000..ab4c119
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/list.h
@@ -0,0 +1,215 @@
+#ifndef _IPXE_LIST_H
+#define _IPXE_LIST_H
+
+/** @file
+ *
+ * Linked lists
+ *
+ * This linked list handling code is based on the Linux kernel's
+ * list.h.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stddef.h>
+#include <assert.h>
+
+/** A doubly-linked list entry (or list head) */
+struct list_head {
+	/** Next list entry */
+	struct list_head *next;
+	/** Previous list entry */
+	struct list_head *prev;
+};
+
+/**
+ * Initialise a static list head
+ *
+ * @v list		List head
+ */
+#define LIST_HEAD_INIT( list ) { &(list), &(list) }
+
+/**
+ * Declare a static list head
+ *
+ * @v list		List head
+ */
+#define LIST_HEAD( list ) \
+	struct list_head list = LIST_HEAD_INIT ( list )
+
+/**
+ * Initialise a list head
+ *
+ * @v list		List head
+ */
+#define INIT_LIST_HEAD( list ) do {			\
+	(list)->next = (list);				\
+	(list)->prev = (list);				\
+	} while ( 0 )
+
+/**
+ * Check a list entry or list head is valid
+ *
+ * @v list		List entry or head
+ */
+#define list_check( list ) ( {				\
+	assert ( (list) != NULL );			\
+	assert ( (list)->prev != NULL );		\
+	assert ( (list)->next != NULL );		\
+	assert ( (list)->next->prev == (list) );	\
+	assert ( (list)->prev->next == (list) );	\
+	} )
+
+/**
+ * Insert a list entry between two known consecutive entries
+ *
+ * @v new		New list entry
+ * @v prev		Previous list entry
+ * @v next		Next list entry
+ */
+static inline void __list_add ( struct list_head *new,
+				struct list_head *prev,
+				struct list_head *next ) {
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * Add a new entry to the head of a list
+ *
+ * @v new		New entry to be added
+ * @v head		List head, or entry after which to add the new entry
+ */
+static inline void list_add ( struct list_head *new, struct list_head *head ) {
+	__list_add ( new, head, head->next );
+}
+#define list_add( new, head ) do {			\
+	list_check ( (head) );				\
+	list_add ( (new), (head) );			\
+	} while ( 0 )
+
+/**
+ * Add a new entry to the tail of a list
+ *
+ * @v new		New entry to be added
+ * @v head		List head, or entry before which to add the new entry
+ */
+static inline void list_add_tail ( struct list_head *new,
+				   struct list_head *head ) {
+	__list_add ( new, head->prev, head );
+}
+#define list_add_tail( new, head ) do {			\
+	list_check ( (head) );				\
+	list_add_tail ( (new), (head) );		\
+	} while ( 0 )
+
+/**
+ * Delete a list entry between two known consecutive entries
+ *
+ * @v prev		Previous list entry
+ * @v next		Next list entry
+ */
+static inline void __list_del ( struct list_head *prev,
+				struct list_head *next ) {
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * Delete an entry from a list
+ *
+ * @v list		List entry
+ *
+ * Note that list_empty() on entry does not return true after this;
+ * the entry is in an undefined state.
+ */
+static inline void list_del ( struct list_head *list ) {
+	__list_del ( list->prev, list->next );
+}
+#define list_del( list ) do {				\
+	list_check ( (list) );				\
+	list_del ( (list) );				\
+	} while ( 0 )
+
+/**
+ * Test whether a list is empty
+ *
+ * @v list		List head
+ */
+static inline int list_empty ( const struct list_head *list ) {
+	return ( list->next == list );
+}
+#define list_empty( list ) ( {				\
+	list_check ( (list) );				\
+	list_empty ( (list) ); } )
+
+/**
+ * Get the container of a list entry
+ *
+ * @v list		List entry
+ * @v type		Containing type
+ * @v member		Name of list field within containing type
+ * @ret container	Containing object
+ */
+#define list_entry( list, type, member ) ( {		\
+	list_check ( (list) );				\
+	container_of ( list, type, member ); } )
+
+/**
+ * Get the container of the first entry in a list
+ *
+ * @v list		List head
+ * @v type		Containing type
+ * @v member		Name of list field within containing type
+ * @ret first		First list entry, or NULL
+ */
+#define list_first_entry( list, type, member )		\
+	( list_empty ( (list) ) ?			\
+	  ( type * ) NULL :				\
+	  list_entry ( (list)->next, type, member ) )
+
+/**
+ * Iterate over entries in a list
+ *
+ * @v pos		Iterator
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_for_each_entry( pos, head, member )			      \
+	for ( list_check ( (head) ),					      \
+	      pos = list_entry ( (head)->next, typeof ( *pos ), member );     \
+	      &pos->member != (head);					      \
+	      pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
+
+/**
+ * Iterate over entries in a list in reverse order
+ *
+ * @v pos		Iterator
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_for_each_entry_reverse( pos, head, member )		      \
+	for ( list_check ( (head) ),					      \
+	      pos = list_entry ( (head)->prev, typeof ( *pos ), member );     \
+	      &pos->member != (head);					      \
+	      pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) )
+
+/**
+ * Iterate over entries in a list, safe against deletion of the current entry
+ *
+ * @v pos		Iterator
+ * @v tmp		Temporary value (of same type as iterator)
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_for_each_entry_safe( pos, tmp, head, member )		      \
+	for ( list_check ( (head) ),					      \
+	      pos = list_entry ( (head)->next, typeof ( *pos ), member ),     \
+	      tmp = list_entry ( pos->member.next, typeof ( *tmp ), member ); \
+	      &pos->member != (head);					      \
+	      pos = tmp,						      \
+	      tmp = list_entry ( tmp->member.next, typeof ( *tmp ), member ) )
+
+#endif /* _IPXE_LIST_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/login_ui.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/login_ui.h
new file mode 100644
index 0000000..01e5479
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/login_ui.h
@@ -0,0 +1,14 @@
+#ifndef _IPXE_LOGIN_UI_H
+#define _IPXE_LOGIN_UI_H
+
+/** @file
+ *
+ * Login UI
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern int login_ui ( void );
+
+#endif /* _IPXE_LOGIN_UI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/malloc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/malloc.h
new file mode 100644
index 0000000..c435a7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/malloc.h
@@ -0,0 +1,81 @@
+#ifndef _IPXE_MALLOC_H
+#define _IPXE_MALLOC_H
+
+#include <stdint.h>
+
+/** @file
+ *
+ * Dynamic memory allocation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * Prototypes for the standard functions (malloc() et al) are in
+ * stdlib.h.  Include <ipxe/malloc.h> only if you need the
+ * non-standard functions, such as malloc_dma().
+ *
+ */
+#include <stdlib.h>
+#include <ipxe/tables.h>
+#include <valgrind/memcheck.h>
+
+extern size_t freemem;
+
+extern void * __malloc alloc_memblock ( size_t size, size_t align );
+extern void free_memblock ( void *ptr, size_t size );
+extern void mpopulate ( void *start, size_t len );
+extern void mdumpfree ( void );
+
+/**
+ * Allocate memory for DMA
+ *
+ * @v size		Requested size
+ * @v align		Physical alignment
+ * @ret ptr		Memory, or NULL
+ *
+ * Allocates physically-aligned memory for DMA.
+ *
+ * @c align must be a power of two.  @c size may not be zero.
+ */
+static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) {
+	void * ptr = alloc_memblock ( size, phys_align );
+	if ( ptr && size )
+		VALGRIND_MALLOCLIKE_BLOCK ( ptr, size, 0, 0 );
+	return ptr;
+}
+
+/**
+ * Free memory allocated with malloc_dma()
+ *
+ * @v ptr		Memory allocated by malloc_dma(), or NULL
+ * @v size		Size of memory, as passed to malloc_dma()
+ *
+ * Memory allocated with malloc_dma() can only be freed with
+ * free_dma(); it cannot be freed with the standard free().
+ *
+ * If @c ptr is NULL, no action is taken.
+ */
+static inline void free_dma ( void *ptr, size_t size ) {
+	free_memblock ( ptr, size );
+	VALGRIND_FREELIKE_BLOCK ( ptr, 0 );
+}
+
+/** A cache discarder */
+struct cache_discarder {
+	/**
+	 * Discard some cached data
+	 *
+	 * @ret discarded	Number of cached items discarded
+	 */
+	unsigned int ( * discard ) ( void );
+};
+
+/** Cache discarder table */
+#define CACHE_DISCARDERS __table ( struct cache_discarder, "cache_discarders" )
+
+/** Declare a cache discarder */
+#define __cache_discarder __table_entry ( CACHE_DISCARDERS, 01 )
+
+#endif /* _IPXE_MALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/mca.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/mca.h
new file mode 100644
index 0000000..d86dab1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/mca.h
@@ -0,0 +1,106 @@
+/*
+ * MCA bus driver code
+ *
+ * Abstracted from 3c509.c.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef MCA_H
+#define MCA_H
+
+#include <ipxe/isa_ids.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+
+/*
+ * MCA constants
+ *
+ */
+#define MCA_MOTHERBOARD_SETUP_REG	0x94
+#define MCA_ADAPTER_SETUP_REG		0x96
+#define MCA_MAX_SLOT_NR			0x07	/* Must be 2^n - 1 */
+#define MCA_POS_REG(n)			(0x100+(n))
+
+/* Is there a standard that would define this? */
+#define GENERIC_MCA_VENDOR ISA_VENDOR ( 'M', 'C', 'A' )
+
+/** An MCA device ID list entry */
+struct mca_device_id {
+	/** Name */
+        const char *name;
+	/** Device ID */
+	uint16_t id;
+};
+
+/** An MCA device */
+struct mca_device {
+	/** Generic device */
+	struct device dev;
+	/** Slot number */
+	unsigned int slot;
+	/** POS register values */
+	unsigned char pos[8];
+	/** Driver for this device */
+	struct mca_driver *driver;
+	/** Driver-private data
+	 *
+	 * Use mca_set_drvdata() and mca_get_drvdata() to access
+	 * this field.
+	 */
+	void *priv;
+};
+
+#define MCA_ID(mca) ( ( (mca)->pos[1] << 8 ) + (mca)->pos[0] )
+
+/** An MCA driver */
+struct mca_driver {
+	/** MCA ID table */
+	struct mca_device_id *ids;
+	/** Number of entries in MCA ID table */
+	unsigned int id_count;
+	/**
+	 * Probe device
+	 *
+	 * @v mca	MCA device
+	 * @v id	Matching entry in ID table
+	 * @ret rc	Return status code
+	 */
+	int ( * probe ) ( struct mca_device *mca,
+			  const struct mca_device_id *id );
+	/**
+	 * Remove device
+	 *
+	 * @v mca	MCA device
+	 */
+	void ( * remove ) ( struct mca_device *mca );
+};
+
+/** MCA driver table */
+#define MCA_DRIVERS __table ( struct mca_driver, "mca_drivers" )
+
+/** Declare an MCA driver */
+#define __mca_driver __table_entry ( MCA_DRIVERS, 01 )
+
+/**
+ * Set MCA driver-private data
+ *
+ * @v mca		MCA device
+ * @v priv		Private data
+ */
+static inline void mca_set_drvdata ( struct mca_device *mca, void *priv ) {
+	mca->priv = priv;
+}
+
+/**
+ * Get MCA driver-private data
+ *
+ * @v mca		MCA device
+ * @ret priv		Private data
+ */
+static inline void * mca_get_drvdata ( struct mca_device *mca ) {
+	return mca->priv;
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/md5.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/md5.h
new file mode 100644
index 0000000..c3dfeb7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/md5.h
@@ -0,0 +1,24 @@
+#ifndef _IPXE_MD5_H
+#define _IPXE_MD5_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct digest_algorithm;
+
+#include <stdint.h>
+
+#define MD5_DIGEST_SIZE		16
+#define MD5_BLOCK_WORDS		16
+#define MD5_HASH_WORDS		4
+
+struct md5_ctx {
+	u32 hash[MD5_HASH_WORDS];
+	u32 block[MD5_BLOCK_WORDS];
+	u64 byte_count;
+};
+
+#define MD5_CTX_SIZE sizeof ( struct md5_ctx )
+
+extern struct digest_algorithm md5_algorithm;
+
+#endif /* _IPXE_MD5_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/monojob.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/monojob.h
new file mode 100644
index 0000000..3d8b31c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/monojob.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_MONOJOB_H
+#define _IPXE_MONOJOB_H
+
+/** @file
+ *
+ * Single foreground job
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct interface;
+
+extern struct interface monojob;
+
+extern int monojob_wait ( const char *string );
+
+#endif /* _IPXE_MONOJOB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/nap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nap.h
new file mode 100644
index 0000000..afc8879
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nap.h
@@ -0,0 +1,57 @@
+#ifndef _IPXE_NAP_H
+#define _IPXE_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/api.h>
+#include <config/nap.h>
+
+/**
+ * Calculate static inline CPU sleeping API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define NAP_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an CPU sleeping API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_NAP( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( NAP_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline CPU sleeping API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_NAP_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <ipxe/null_nap.h>
+#include <ipxe/linux/linux_nap.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/nap.h>
+
+/**
+ * Sleep until next CPU interrupt
+ *
+ */
+void cpu_nap ( void );
+
+#endif /* _IPXE_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/ndp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ndp.h
new file mode 100644
index 0000000..42bb2fe
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/ndp.h
@@ -0,0 +1,21 @@
+#include <stdint.h>
+#include <byteswap.h>
+#include <string.h>
+#include <ipxe/icmp6.h>
+#include <ipxe/ip6.h>
+#include <ipxe/in.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tcpip.h>
+
+#define NDP_STATE_INVALID 0
+#define NDP_STATE_INCOMPLETE 1
+#define NDP_STATE_REACHABLE 2
+#define NDP_STATE_DELAY 3
+#define NDP_STATE_PROBE 4
+#define NDP_STATE_STALE 5
+
+int ndp_resolve ( struct net_device *netdev, struct in6_addr *src,
+		  struct in6_addr *dest, void *dest_ll_addr );
+int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+			 struct sockaddr_tcpip *st_dest );
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211.h
new file mode 100644
index 0000000..3c30f06
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211.h
@@ -0,0 +1,1207 @@
+#ifndef _IPXE_NET80211_H
+#define _IPXE_NET80211_H
+
+#include <ipxe/process.h>
+#include <ipxe/ieee80211.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/rc80211.h>
+
+/** @file
+ *
+ * The iPXE 802.11 MAC layer.
+ */
+
+/*
+ * Major things NOT YET supported:
+ * - any type of security
+ * - 802.11n
+ *
+ * Major things that probably will NEVER be supported, barring a
+ * compelling use case and/or corporate sponsorship:
+ * - QoS
+ * - 802.1X authentication ("WPA Enterprise")
+ * - Contention-free periods
+ * - "ad-hoc" networks (IBSS), monitor mode, host AP mode
+ * - hidden networks on the 5GHz band due to regulatory issues
+ * - spectrum management on the 5GHz band (TPC and DFS), as required
+ *   in some non-US regulatory domains
+ * - Clause 14 PHYs (Frequency-Hopping Spread Spectrum on 2.4GHz)
+ *   and Clause 16 PHYs (infrared) - I'm not aware of any real-world
+ *   use of these.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* All 802.11 devices are handled using a generic "802.11 device"
+   net_device, with a link in its `priv' field to a net80211_device
+   which we use to handle 802.11-specific details. */
+
+
+/** @defgroup net80211_band RF bands on which an 802.11 device can transmit */
+/** @{ */
+
+/** The 2.4 GHz ISM band, unlicensed in most countries */
+#define NET80211_BAND_2GHZ	0
+/** The band from 4.9 GHz to 5.7 GHz, which tends to be more restricted */
+#define NET80211_BAND_5GHZ	1
+/** Number of RF bands */
+#define NET80211_NR_BANDS	2
+
+/** Bitmask for the 2GHz band */
+#define NET80211_BAND_BIT_2GHZ	(1 << 0)
+/** Bitmask for the 5GHz band */
+#define NET80211_BAND_BIT_5GHZ	(1 << 1)
+
+/** @} */
+
+
+/** @defgroup net80211_mode 802.11 operation modes supported by hardware */
+/** @{ */
+
+/** 802.11a: 54 Mbps operation using OFDM signaling on the 5GHz band */
+#define NET80211_MODE_A		(1 << 0)
+
+/** 802.11b: 1-11 Mbps operation using DSSS/CCK signaling on the 2.4GHz band */
+#define NET80211_MODE_B		(1 << 1)
+
+/** 802.11g: 54 Mbps operation using ERP/OFDM signaling on the 2.4GHz band */
+#define NET80211_MODE_G		(1 << 2)
+
+/** 802.11n: High-rate operation using MIMO technology on 2.4GHz or 5GHz */
+#define NET80211_MODE_N		(1 << 3)
+
+/** @} */
+
+
+/** @defgroup net80211_cfg Constants for the net80211 config callback */
+/** @{ */
+
+/** Channel choice (@c dev->channel) or regulatory parameters have changed */
+#define NET80211_CFG_CHANNEL	(1 << 0)
+
+/** Requested transmission rate (@c dev->rate) has changed */
+#define NET80211_CFG_RATE	(1 << 1)
+
+/** Association has been established with a new BSS (@c dev->bssid) */
+#define NET80211_CFG_ASSOC	(1 << 2)
+
+/** Low-level link parameters (short preamble, protection, etc) have changed */
+#define NET80211_CFG_PHY_PARAMS	(1 << 3)
+
+/** @} */
+
+
+/** An 802.11 security handshaking protocol */
+enum net80211_security_proto {
+	/** No security handshaking
+	 *
+	 * This might be used with an open network or with WEP, as
+	 * WEP does not have a cryptographic handshaking phase.
+	 */
+	NET80211_SECPROT_NONE = 0,
+
+	/** Pre-shared key handshaking
+	 *
+	 * This implements the "WPA Personal" handshake. 802.1X
+	 * authentication is not performed -- the user supplies a
+	 * pre-shared key directly -- but there is a 4-way handshake
+	 * between client and AP to verify that both have the same key
+	 * without revealing the contents of that key.
+	 */
+	NET80211_SECPROT_PSK = 1,
+
+	/** Full EAP 802.1X handshaking
+	 *
+	 * This implements the "WPA Enterprise" handshake, connecting
+	 * to an 802.1X authentication server to provide credentials
+	 * and receive a pairwise master key (PMK), which is then used
+	 * in the same 4-way handshake as the PSK method.
+	 */
+	NET80211_SECPROT_EAP = 2,
+
+	/** Dummy value used when the handshaking type can't be detected */
+	NET80211_SECPROT_UNKNOWN = 3,
+};
+
+
+/** An 802.11 data encryption algorithm */
+enum net80211_crypto_alg {
+	/** No security, an "Open" network */
+	NET80211_CRYPT_NONE = 0,
+
+	/** Network protected with WEP (awful RC4-based system)
+	 *
+	 * WEP uses a naive application of RC4, with a monotonically
+	 * increasing initialization vector that is prepended to the
+	 * key to initialize the RC4 keystream. It is highly insecure
+	 * and can be completely cracked or subverted using automated,
+	 * robust, freely available tools (aircrack-ng) in minutes.
+	 *
+	 * 40-bit and 104-bit WEP are differentiated only by the size
+	 * of the key. They may be advertised as 64-bit and 128-bit,
+	 * counting the non-random IV as part of the key bits.
+	 */
+	NET80211_CRYPT_WEP = 1,
+
+	/** Network protected with TKIP (better RC4-based system)
+	 *
+	 * Usually known by its trade name of WPA (Wi-Fi Protected
+	 * Access), TKIP implements a message integrity code (MIC)
+	 * called Michael, a timestamp counter for replay prevention,
+	 * and a key mixing function that together remove almost all
+	 * the security problems with WEP. Countermeasures are
+	 * implemented to prevent high data-rate attacks.
+	 *
+	 * There exists one known attack on TKIP, that allows one to
+	 * send between 7 and 15 arbitrary short data packets on a
+	 * QoS-enabled network given about an hour of data
+	 * gathering. Since iPXE does not support QoS for 802.11
+	 * networks, this is not a threat to us. The only other method
+	 * is a brute-force passphrase attack.
+	 */
+	NET80211_CRYPT_TKIP = 2,
+
+	/** Network protected with CCMP (AES-based system)
+	 *
+	 * Often called WPA2 in commerce, or RSNA (Robust Security
+	 * Network Architecture) in the 802.11 standard, CCMP is
+	 * highly secure and does not have any known attack vectors.
+	 * Since it is based on a block cipher, the statistical
+	 * correlation and "chopchop" attacks used with great success
+	 * against WEP and minor success against TKIP fail.
+	 */
+	NET80211_CRYPT_CCMP = 3,
+
+	/** Dummy value used when the cryptosystem can't be detected */
+	NET80211_CRYPT_UNKNOWN = 4,
+};
+
+
+/** @defgroup net80211_state Bits for the 802.11 association state field */
+/** @{ */
+
+/** An error code indicating the failure mode, or 0 if successful */
+#define NET80211_STATUS_MASK    0x7F
+
+/** Whether the error code provided is a "reason" code, not a "status" code */
+#define NET80211_IS_REASON	0x80
+
+/** Whether we have found the network we will be associating with */
+#define NET80211_PROBED		(1 << 8)
+
+/** Whether we have successfully authenticated with the network
+ *
+ * This usually has nothing to do with actual security; it is a
+ * holdover from older 802.11 implementation ideas.
+ */
+#define NET80211_AUTHENTICATED  (1 << 9)
+
+/** Whether we have successfully associated with the network */
+#define NET80211_ASSOCIATED     (1 << 10)
+
+/** Whether we have completed security handshaking with the network
+ *
+ * Once this is set, we can send data packets. For that reason this
+ * bit is set even in cases where no security handshaking is
+ * required.
+ */
+#define NET80211_CRYPTO_SYNCED  (1 << 11)
+
+/** Whether the auto-association task is running */
+#define NET80211_WORKING        (1 << 12)
+
+/** Whether the auto-association task is waiting for a reply from the AP */
+#define NET80211_WAITING        (1 << 13)
+
+/** Whether the auto-association task should be suppressed
+ *
+ * This is set by the `iwlist' command so that it can open the device
+ * without starting another probe process that will interfere with its
+ * own.
+ */
+#define NET80211_NO_ASSOC	(1 << 14)
+
+/** Whether this association was performed using a broadcast SSID
+ *
+ * If the user opened this device without netX/ssid set, the device's
+ * SSID will be set to that of the network it chooses to associate
+ * with, but the netX/ssid setting will remain blank. If we don't
+ * remember that we started from no specified SSID, it will appear
+ * every time settings are updated (e.g. after DHCP) that we need to
+ * reassociate due to the difference between the set SSID and our own.
+ */
+#define NET80211_AUTO_SSID	(1 << 15)
+
+
+/** @} */
+
+
+/** @defgroup net80211_phy 802.11 physical layer flags */
+/** @{ */
+
+/** Whether to use RTS/CTS or CTS-to-self protection for transmissions
+ *
+ * Since the RTS or CTS is transmitted using 802.11b signaling, and
+ * includes a field indicating the amount of time that will be used by
+ * transmission of the following packet, this serves as an effective
+ * protection mechanism to avoid 802.11b clients interfering with
+ * 802.11g clients on mixed networks.
+ */
+#define NET80211_PHY_USE_PROTECTION      (1 << 1)
+
+/** Whether to use 802.11b short preamble operation
+ *
+ * Short-preamble operation can moderately increase throughput on
+ * 802.11b networks operating between 2Mbps and 11Mbps. It is
+ * irrelevant for 802.11g data rates, since they use a different
+ * modulation scheme.
+ */
+#define NET80211_PHY_USE_SHORT_PREAMBLE  (1 << 2)
+
+/** Whether to use 802.11g short slot operation
+ *
+ * This affects a low-level timing parameter of 802.11g transmissions.
+ */
+#define NET80211_PHY_USE_SHORT_SLOT      (1 << 3)
+
+/** @} */
+
+
+/** The maximum number of TX rates we allow to be configured simultaneously */
+#define NET80211_MAX_RATES	16
+
+/** The maximum number of channels we allow to be configured simultaneously */
+#define NET80211_MAX_CHANNELS	32
+
+/** Seconds we'll wait to get all fragments of a packet */
+#define NET80211_FRAG_TIMEOUT	2
+
+/** The number of fragments we can receive at once
+ *
+ * The 802.11 standard requires that this be at least 3.
+ */
+#define NET80211_NR_CONCURRENT_FRAGS 3
+
+/** Maximum TX power to allow (dBm), if we don't get a regulatory hint */
+#define NET80211_REG_TXPOWER	20
+
+
+struct net80211_device;
+
+/** Operations that must be implemented by an 802.11 driver */
+struct net80211_device_operations {
+	/** Open 802.11 device
+	 *
+	 * @v dev	802.11 device
+	 * @ret rc	Return status code
+	 *
+	 * This method should allocate RX I/O buffers and enable the
+	 * hardware to start transmitting and receiving packets on the
+	 * channels its net80211_register() call indicated it could
+	 * handle. It does not need to tune the antenna to receive
+	 * packets on any particular channel.
+	 */
+	int ( * open ) ( struct net80211_device *dev );
+
+	/** Close 802.11 network device
+	 *
+	 * @v dev	802.11 device
+	 *
+	 * This method should stop the flow of packets, and call
+	 * net80211_tx_complete() for any packets remaining in the
+	 * device's TX queue.
+	 */
+	void ( * close ) ( struct net80211_device *dev );
+
+	/** Transmit packet on 802.11 network device
+	 *
+	 * @v dev	802.11 device
+	 * @v iobuf	I/O buffer
+	 * @ret rc	Return status code
+	 *
+	 * This method should cause the hardware to initiate
+	 * transmission of the I/O buffer, using the channel and rate
+	 * most recently indicated by an appropriate call to the
+	 * @c config callback. The 802.11 layer guarantees that said
+	 * channel and rate will be the same as those currently
+	 * reflected in the fields of @a dev.
+	 *
+	 * If this method returns success, the I/O buffer remains
+	 * owned by the network layer's TX queue, and the driver must
+	 * eventually call net80211_tx_complete() to free the buffer
+	 * whether transmission succeeded or not. If this method
+	 * returns failure, it will be interpreted as "failure to
+	 * enqueue buffer" and the I/O buffer will be immediately
+	 * released.
+	 *
+	 * This method is guaranteed to be called only when the device
+	 * is open.
+	 */
+	int ( * transmit ) ( struct net80211_device *dev,
+			     struct io_buffer *iobuf );
+
+	/** Poll for completed and received packets
+	 *
+	 * @v dev	802.11 device
+	 *
+	 * This method should cause the hardware to check for
+	 * completed transmissions and received packets. Any received
+	 * packets should be delivered via net80211_rx(), and
+	 * completed transmissions should be indicated using
+	 * net80211_tx_complete().
+	 *
+	 * This method is guaranteed to be called only when the device
+	 * is open.
+	 */
+	void ( * poll ) ( struct net80211_device *dev );
+
+	/** Enable or disable interrupts
+	 *
+	 * @v dev	802.11 device
+	 * @v enable	If TRUE, interrupts should be enabled
+	 */
+	void ( * irq ) ( struct net80211_device *dev, int enable );
+
+	/** Update hardware state to match 802.11 layer state
+	 *
+	 * @v dev	802.11 device
+	 * @v changed	Set of flags indicating what may have changed
+	 * @ret rc	Return status code
+	 *
+	 * This method should cause the hardware state to be
+	 * reinitialized from the state indicated in fields of
+	 * net80211_device, in the areas indicated by bits set in
+	 * @a changed. If the hardware is unable to do so, this method
+	 * may return an appropriate error indication.
+	 *
+	 * This method is guaranteed to be called only when the device
+	 * is open.
+	 */
+	int ( * config ) ( struct net80211_device *dev, int changed );
+};
+
+/** An 802.11 RF channel. */
+struct net80211_channel
+{
+	/** The band with which this channel is associated */
+	u8 band;
+
+	/** A channel number interpreted according to the band
+	 *
+	 * The 2.4GHz band uses channel numbers from 1-13 at 5MHz
+	 * intervals such that channel 1 is 2407 MHz; channel 14,
+	 * legal for use only in Japan, is defined separately as 2484
+	 * MHz. Adjacent channels will overlap, since 802.11
+	 * transmissions use a 20 MHz (4-channel) bandwidth. Most
+	 * commonly, channels 1, 6, and 11 are used.
+	 *
+	 * The 5GHz band uses channel numbers derived directly from
+	 * the frequency; channel 0 is 5000 MHz, and channels are
+	 * always spaced 5 MHz apart. Channel numbers over 180 are
+	 * relative to 4GHz instead of 5GHz, but these are rarely
+	 * seen. Most channels are not legal for use.
+	 */
+	u8 channel_nr;
+
+	/** The center frequency for this channel
+	 *
+	 * Currently a bandwidth of 20 MHz is assumed.
+	 */
+	u16 center_freq;
+
+	/** Hardware channel value */
+	u16 hw_value;
+
+	/** Maximum allowable transmit power, in dBm
+	 *
+	 * This should be interpreted as EIRP, the power supplied to
+	 * an ideal isotropic antenna in order to achieve the same
+	 * average signal intensity as the real hardware at a
+	 * particular distance.
+	 *
+	 * Currently no provision is made for directional antennas.
+	 */
+	u8 maxpower;
+};
+
+/** Information on the capabilities of an 802.11 hardware device
+ *
+ * In its probe callback, an 802.11 driver must read hardware
+ * registers to determine the appropriate contents of this structure,
+ * fill it, and pass it to net80211_register() so that the 802.11
+ * layer knows how to treat the hardware and what to advertise as
+ * supported to access points.
+ */
+struct net80211_hw_info
+{
+	/** Default hardware MAC address.
+	 *
+	 * The user may change this by setting the @c netX/mac setting
+	 * before the driver's open function is called; in that case
+	 * the driver must set the hardware MAC address to the address
+	 * contained in the wrapping net_device's ll_addr field, or if
+	 * that is impossible, set that ll_addr field back to the
+	 * unchangeable hardware MAC address.
+	 */
+	u8 hwaddr[ETH_ALEN];
+
+	/** A bitwise OR of the 802.11x modes supported by this device */
+	int modes;
+
+	/** A bitwise OR of the bands on which this device can communicate */
+	int bands;
+
+	/** A set of flags indicating peculiarities of this device. */
+	enum {
+		/** Received frames include a frame check sequence. */
+		NET80211_HW_RX_HAS_FCS = (1 << 1),
+
+		/** Hardware doesn't support 2.4GHz short preambles
+		 *
+		 * This is only relevant for 802.11b operation above
+		 * 2Mbps. All 802.11g devices support short preambles.
+		 */
+		NET80211_HW_NO_SHORT_PREAMBLE = (1 << 2),
+
+		/** Hardware doesn't support 802.11g short slot operation */
+		NET80211_HW_NO_SHORT_SLOT = (1 << 3),
+	} flags;
+
+	/** Signal strength information that can be provided by the device
+	 *
+	 * Signal strength is passed to net80211_rx(), primarily to
+	 * allow determination of the closest access point for a
+	 * multi-AP network. The units are provided for completeness
+	 * of status displays.
+	 */
+	enum {
+		/** No signal strength information supported */
+		NET80211_SIGNAL_NONE = 0,
+		/** Signal strength in arbitrary units */
+		NET80211_SIGNAL_ARBITRARY,
+		/** Signal strength in decibels relative to arbitrary base */
+		NET80211_SIGNAL_DB,
+		/** Signal strength in decibels relative to 1mW */
+		NET80211_SIGNAL_DBM,
+	} signal_type;
+
+	/** Maximum signal in arbitrary cases
+	 *
+	 * If signal_type is NET80211_SIGNAL_ARBITRARY or
+	 * NET80211_SIGNAL_DB, the driver should report it on a scale
+	 * from 0 to signal_max.
+	 */
+	unsigned signal_max;
+
+	/** List of RF channels supported by the card */
+	struct net80211_channel channels[NET80211_MAX_CHANNELS];
+
+	/** Number of supported channels */
+	int nr_channels;
+
+	/** List of transmission rates supported by the card, indexed by band
+	 *
+	 * Rates should be in 100kbps increments (e.g. 11 Mbps would
+	 * be represented as the number 110).
+	 */
+	u16 rates[NET80211_NR_BANDS][NET80211_MAX_RATES];
+
+	/** Number of supported rates, indexed by band */
+	int nr_rates[NET80211_NR_BANDS];
+
+	/** Estimate of the time required to change channels, in microseconds
+	 *
+	 * If this is not known, a guess on the order of a few
+	 * milliseconds (value of 1000-5000) is reasonable.
+	 */
+	unsigned channel_change_time;
+};
+
+/** Structure tracking received fragments for a packet
+ *
+ * We set up a fragment cache entry when we receive a packet marked as
+ * fragment 0 with the "more fragments" bit set in its frame control
+ * header. We are required by the 802.11 standard to track 3
+ * fragmented packets arriving simultaneously; if we receive more we
+ * may drop some. Upon receipt of a new fragment-0 packet, if no entry
+ * is available or expired, we take over the most @e recent entry for
+ * the new packet, since we don't want to starve old entries from ever
+ * finishing at all. If we get a fragment after the zeroth with no
+ * cache entry for its packet, we drop it.
+ */
+struct net80211_frag_cache
+{
+	/** Whether this cache entry is in use */
+	u8 in_use;
+
+	/** Sequence number of this MSDU (packet) */
+	u16 seqnr;
+
+	/** Timestamp from point at which first fragment was collected */
+	u32 start_ticks;
+
+	/** Buffers for each fragment */
+	struct io_buffer *iob[16];
+};
+
+
+/** Interface to an 802.11 security handshaking protocol
+ *
+ * Security handshaking protocols handle parsing a user-specified key
+ * into a suitable input to the encryption algorithm, and for WPA and
+ * better systems, manage performing whatever authentication with the
+ * network is necessary.
+ *
+ * At all times when any method in this structure is called with a
+ * net80211_device argument @a dev, a dynamically allocated copy of
+ * the handshaker structure itself with space for the requested amount
+ * of private data may be accessed as @c dev->handshaker. The
+ * structure will not be modified, and will only be freed during
+ * reassociation and device closing after the @a stop method has been
+ * called.
+ */
+struct net80211_handshaker
+{
+	/** The security handshaking protocol implemented */
+	enum net80211_security_proto protocol;
+
+	/** Initialize security handshaking protocol
+	 *
+	 * @v dev	802.11 device
+	 * @ret rc	Return status code
+	 *
+	 * This method is expected to access @c netX/key or other
+	 * applicable settings to determine the parameters for
+	 * handshaking. If no handshaking is required, it should call
+	 * sec80211_install() with the cryptosystem and key that are
+	 * to be used, and @c start and @c step should be set to @c
+	 * NULL.
+	 *
+	 * This is always called just before association is performed,
+	 * but after its parameters have been set; in particular, you
+	 * may rely on the contents of the @a essid field in @a dev.
+	 */
+	int ( * init ) ( struct net80211_device *dev );
+
+	/** Start handshaking
+	 *
+	 * @v dev	802.11 device
+	 * @ret rc	Return status code
+	 *
+	 * This method is expected to set up internal state so that
+	 * packets sent immediately after association, before @a step
+	 * can be called, will be handled appropriately.
+	 *
+	 * This is always called just before association is attempted.
+	 */
+	int ( * start ) ( struct net80211_device *dev );
+
+	/** Process handshaking state
+	 *
+	 * @v dev	802.11 device
+	 * @ret rc	Return status code, or positive if done
+	 *
+	 * This method is expected to perform as much progress on the
+	 * protocol it implements as is possible without blocking. It
+	 * should return 0 if it wishes to be called again, a negative
+	 * return status code on error, or a positive value if
+	 * handshaking is complete. In the case of a positive return,
+	 * net80211_crypto_install() must have been called.
+	 *
+	 * If handshaking may require further action (e.g. an AP that
+	 * might decide to rekey), handlers must be installed by this
+	 * function that will act without further calls to @a step.
+	 */
+	int ( * step ) ( struct net80211_device *dev );
+
+	/** Change cryptographic key based on setting
+	 *
+	 * @v dev	802.11 device
+	 * @ret rc	Return status code
+	 *
+	 * This method is called whenever the @c netX/key setting
+	 * @e may have been changed. It is expected to determine
+	 * whether it did in fact change, and if so, to install the
+	 * new key using net80211_crypto_install(). If it is not
+	 * possible to do this immediately, this method should return
+	 * an error; in that case the 802.11 stack will reassociate,
+	 * following the usual init/start/step sequence.
+	 *
+	 * This method is only relevant when it is possible to
+	 * associate successfully with an incorrect key. When it is
+	 * not, a failed association will be retried until the user
+	 * changes the key setting, and a successful association will
+	 * not be dropped due to such a change. When association with
+	 * an incorrect key is impossible, this function should return
+	 * 0 after performing no action.
+	 */
+	int ( * change_key ) ( struct net80211_device *dev );
+
+	/** Stop security handshaking handlers
+	 *
+	 * @v dev	802.11 device
+	 *
+	 * This method is called just before freeing a security
+	 * handshaker; it could, for example, delete a process that @a
+	 * start had created to manage the security of the connection.
+	 * If not needed it may be set to NULL.
+	 */
+	void ( * stop ) ( struct net80211_device *dev );
+
+	/** Amount of private data requested
+	 *
+	 * Before @c init is called for the first time, this structure's
+	 * @c priv pointer will point to this many bytes of allocated
+	 * data, where the allocation will be performed separately for
+	 * each net80211_device.
+	 */
+	int priv_len;
+
+	/** Whether @a start has been called
+	 *
+	 * Reset to 0 after @a stop is called.
+	 */
+	int started;
+
+	/** Pointer to private data
+	 *
+	 * In initializing this structure statically for a linker
+	 * table, set this to NULL.
+	 */
+	void *priv;
+};
+
+#define NET80211_HANDSHAKERS __table ( struct net80211_handshaker, \
+				       "net80211_handshakers" )
+#define __net80211_handshaker __table_entry ( NET80211_HANDSHAKERS, 01 )
+
+
+/** Interface to an 802.11 cryptosystem
+ *
+ * Cryptosystems define a net80211_crypto structure statically, using
+ * a iPXE linker table to make it available to the 802.11 layer. When
+ * the cryptosystem needs to be used, the 802.11 code will allocate a
+ * copy of the static definition plus whatever space the algorithm has
+ * requested for private state, and point net80211_device::crypto or
+ * net80211_device::gcrypto at it.
+ */
+struct net80211_crypto
+{
+	/** The cryptographic algorithm implemented */
+	enum net80211_crypto_alg algorithm;
+
+	/** Initialize cryptosystem using a given key
+	 *
+	 * @v crypto	802.11 cryptosystem
+	 * @v key	Pointer to key bytes
+	 * @v keylen	Number of key bytes
+	 * @v rsc	Initial receive sequence counter, if applicable
+	 * @ret rc	Return status code
+	 *
+	 * This method is passed the communication key provided by the
+	 * security handshake handler, which will already be in the
+	 * low-level form required. It may not store a pointer to the
+	 * key after returning; it must copy it to its private storage.
+	 */
+	int ( * init ) ( struct net80211_crypto *crypto, const void *key,
+			 int keylen, const void *rsc );
+
+	/** Encrypt a frame using the cryptosystem
+	 *
+	 * @v crypto	802.11 cryptosystem
+	 * @v iob	I/O buffer
+	 * @ret eiob	Newly allocated I/O buffer with encrypted packet
+	 *
+	 * This method is called to encrypt a single frame. It is
+	 * guaranteed that initialize() will have completed
+	 * successfully before this method is called.
+	 *
+	 * The frame passed already has an 802.11 header prepended,
+	 * but the PROTECTED bit in the frame control field will not
+	 * be set; this method is responsible for setting it. The
+	 * returned I/O buffer should contain a complete copy of @a
+	 * iob, including the 802.11 header, but with the PROTECTED
+	 * bit set, the data encrypted, and whatever encryption
+	 * headers/trailers are necessary added.
+	 *
+	 * This method should never free the passed I/O buffer.
+	 *
+	 * Return NULL if the packet could not be encrypted, due to
+	 * memory limitations or otherwise.
+	 */
+	struct io_buffer * ( * encrypt ) ( struct net80211_crypto *crypto,
+					   struct io_buffer *iob );
+
+	/** Decrypt a frame using the cryptosystem
+	 *
+	 * @v crypto	802.11 cryptosystem
+	 * @v eiob	Encrypted I/O buffer
+	 * @ret iob	Newly allocated I/O buffer with decrypted packet
+	 *
+	 * This method is called to decrypt a single frame. It is
+	 * guaranteed that initialize() will have completed
+	 * successfully before this method is called.
+	 *
+	 * Decryption follows the reverse of the pattern used for
+	 * encryption: this method must copy the 802.11 header into
+	 * the returned packet, decrypt the data stream, remove any
+	 * encryption header or trailer, and clear the PROTECTED bit
+	 * in the frame control header.
+	 *
+	 * This method should never free the passed I/O buffer.
+	 *
+	 * Return NULL if memory was not available for decryption, if
+	 * a consistency or integrity check on the decrypted frame
+	 * failed, or if the decrypted frame should not be processed
+	 * by the network stack for any other reason.
+	 */
+	struct io_buffer * ( * decrypt ) ( struct net80211_crypto *crypto,
+					   struct io_buffer *iob );
+
+	/** Length of private data requested to be allocated */
+	int priv_len;
+
+	/** Private data for the algorithm to store key and state info */
+	void *priv;
+};
+
+#define NET80211_CRYPTOS __table ( struct net80211_crypto, "net80211_cryptos" )
+#define __net80211_crypto __table_entry ( NET80211_CRYPTOS, 01 )
+
+
+struct net80211_probe_ctx;
+struct net80211_assoc_ctx;
+
+
+/** Structure encapsulating the complete state of an 802.11 device
+ *
+ * An 802.11 device is always wrapped by a network device, and this
+ * network device is always pointed to by the @a netdev field. In
+ * general, operations should never be performed by 802.11 code using
+ * netdev functions directly. It is usually the case that the 802.11
+ * layer might need to do some processing or bookkeeping on top of
+ * what the netdevice code will do.
+ */
+struct net80211_device
+{
+	/** The net_device that wraps us. */
+	struct net_device *netdev;
+
+	/** List of 802.11 devices. */
+	struct list_head list;
+
+	/** 802.11 device operations */
+	struct net80211_device_operations *op;
+
+	/** Driver private data */
+	void *priv;
+
+	/** Information about the hardware, provided to net80211_register() */
+	struct net80211_hw_info *hw;
+
+	/* ---------- Channel and rate fields ---------- */
+
+	/** A list of all possible channels we might use */
+	struct net80211_channel channels[NET80211_MAX_CHANNELS];
+
+	/** The number of channels in the channels array */
+	u8 nr_channels;
+
+	/** The channel currently in use, as an index into the channels array */
+	u8 channel;
+
+	/** A list of all possible TX rates we might use
+	 *
+	 * Rates are in units of 100 kbps.
+	 */
+	u16 rates[NET80211_MAX_RATES];
+
+	/** The number of transmission rates in the rates array */
+	u8 nr_rates;
+
+	/** The rate currently in use, as an index into the rates array */
+	u8 rate;
+
+	/** The rate to use for RTS/CTS transmissions
+	 *
+	 * This is always the fastest basic rate that is not faster
+	 * than the data rate in use. Also an index into the rates array.
+	 */
+	u8 rtscts_rate;
+
+	/** Bitmask of basic rates
+	 *
+	 * If bit N is set in this value, with the LSB considered to
+	 * be bit 0, then rate N in the rates array is a "basic" rate.
+	 *
+	 * We don't decide which rates are "basic"; our AP does, and
+	 * we respect its wishes. We need to be able to identify basic
+	 * rates in order to calculate the duration of a CTS packet
+	 * used for 802.11 g/b interoperability.
+	 */
+	u32 basic_rates;
+
+	/* ---------- Association fields ---------- */
+
+	/** The asynchronous association process.
+	 *
+	 * When an 802.11 netdev is opened, or when the user changes
+	 * the SSID setting on an open 802.11 device, an
+	 * autoassociation task is started by net80211_autoassocate()
+	 * to associate with the new best network. The association is
+	 * asynchronous, but no packets can be transmitted until it is
+	 * complete. If it is successful, the wrapping net_device is
+	 * set as "link up". If it fails, @c assoc_rc will be set with
+	 * an error indication.
+	 */
+	struct process proc_assoc;
+
+	/** Network with which we are associating
+	 *
+	 * This will be NULL when we are not actively in the process
+	 * of associating with a network we have already successfully
+	 * probed for.
+	 */
+	struct net80211_wlan *associating;
+
+	/** Context for the association process
+	 *
+	 * This is a probe_ctx if the @c PROBED flag is not set in @c
+	 * state, and an assoc_ctx otherwise.
+	 */
+	union {
+		struct net80211_probe_ctx *probe;
+		struct net80211_assoc_ctx *assoc;
+	} ctx;
+
+	/** Security handshaker being used */
+	struct net80211_handshaker *handshaker;
+
+	/** State of our association to the network
+	 *
+	 * Since the association process happens asynchronously, it's
+	 * necessary to have some channel of communication so the
+	 * driver can say "I got an association reply and we're OK" or
+	 * similar. This variable provides that link. It is a bitmask
+	 * of any of NET80211_PROBED, NET80211_AUTHENTICATED,
+	 * NET80211_ASSOCIATED, NET80211_CRYPTO_SYNCED to indicate how
+	 * far along in associating we are; NET80211_WORKING if the
+	 * association task is running; and NET80211_WAITING if a
+	 * packet has been sent that we're waiting for a reply to. We
+	 * can only be crypto-synced if we're associated, we can
+	 * only be associated if we're authenticated, we can only be
+	 * authenticated if we've probed.
+	 *
+	 * If an association process fails (that is, we receive a
+	 * packet with an error indication), the error code is copied
+	 * into bits 6-0 of this variable and bit 7 is set to specify
+	 * what type of error code it is. An AP can provide either a
+	 * "status code" (0-51 are defined) explaining why it refused
+	 * an association immediately, or a "reason code" (0-45 are
+	 * defined) explaining why it canceled an association after it
+	 * had originally OK'ed it. Status and reason codes serve
+	 * similar functions, but they use separate error message
+	 * tables. A iPXE-formatted return status code (negative) is
+	 * placed in @c assoc_rc.
+	 *
+	 * If the failure to associate is indicated by a status code,
+	 * the NET80211_IS_REASON bit will be clear; if it is
+	 * indicated by a reason code, the bit will be set. If we were
+	 * successful, both zero status and zero reason mean success,
+	 * so there is no ambiguity.
+	 *
+	 * To prevent association when opening the device, user code
+	 * can set the NET80211_NO_ASSOC bit. The final bit in this
+	 * variable, NET80211_AUTO_SSID, is used to remember whether
+	 * we picked our SSID through automated probing as opposed to
+	 * user specification; the distinction becomes relevant in the
+	 * settings applicator.
+	 */
+	u16 state;
+
+	/** Return status code associated with @c state */
+	int assoc_rc;
+
+	/** RSN or WPA information element to include with association
+	 *
+	 * If set to @c NULL, none will be included. It is expected
+	 * that this will be set by the @a init function of a security
+	 * handshaker if it is needed.
+	 */
+	union ieee80211_ie *rsn_ie;
+
+	/* ---------- Parameters of currently associated network ---------- */
+
+	/** 802.11 cryptosystem for our current network
+	 *
+	 * For an open network, this will be set to NULL.
+	 */
+	struct net80211_crypto *crypto;
+
+	/** 802.11 cryptosystem for multicast and broadcast frames
+	 *
+	 * If this is NULL, the cryptosystem used for receiving
+	 * unicast frames will also be used for receiving multicast
+	 * and broadcast frames. Transmitted multicast and broadcast
+	 * frames are always sent unicast to the AP, who multicasts
+	 * them on our behalf; thus they always use the unicast
+	 * cryptosystem.
+	 */
+	struct net80211_crypto *gcrypto;
+
+	/** MAC address of the access point most recently associated */
+	u8 bssid[ETH_ALEN];
+
+	/** SSID of the access point we are or will be associated with
+	 *
+	 * Although the SSID field in 802.11 packets is generally not
+	 * NUL-terminated, here and in net80211_wlan we add a NUL for
+	 * convenience.
+	 */
+	char essid[IEEE80211_MAX_SSID_LEN+1];
+
+	/** Association ID given to us by the AP */
+	u16 aid;
+
+	/** TSFT value for last beacon received, microseconds */
+	u64 last_beacon_timestamp;
+
+	/** Time between AP sending beacons, microseconds */
+	u32 tx_beacon_interval;
+
+	/** Smoothed average time between beacons, microseconds */
+	u32 rx_beacon_interval;
+
+	/* ---------- Physical layer information ---------- */
+
+	/** Physical layer options
+	 *
+	 * These control the use of CTS protection, short preambles,
+	 * and short-slot operation.
+	 */
+	int phy_flags;
+
+	/** Signal strength of last received packet */
+	int last_signal;
+
+	/** Rate control state */
+	struct rc80211_ctx *rctl;
+
+	/* ---------- Packet handling state ---------- */
+
+	/** Fragment reassembly state */
+	struct net80211_frag_cache frags[NET80211_NR_CONCURRENT_FRAGS];
+
+	/** The sequence number of the last packet we sent */
+	u16 last_tx_seqnr;
+
+	/** Packet duplication elimination state
+	 *
+	 * We are only required to handle immediate duplicates for
+	 * each direct sender, and since we can only have one direct
+	 * sender (the AP), we need only keep the sequence control
+	 * field from the most recent packet we've received. Thus,
+	 * this field stores the last sequence control field we've
+	 * received for a packet from the AP.
+	 */
+	u16 last_rx_seq;
+
+	/** RX management packet queue
+	 *
+	 * Sometimes we want to keep probe, beacon, and action packets
+	 * that we receive, such as when we're scanning for networks.
+	 * Ordinarily we drop them because they are sent at a large
+	 * volume (ten beacons per second per AP, broadcast) and we
+	 * have no need of them except when we're scanning.
+	 *
+	 * When keep_mgmt is TRUE, received probe, beacon, and action
+	 * management packets will be stored in this queue.
+	 */
+	struct list_head mgmt_queue;
+
+	/** RX management packet info queue
+	 *
+	 * We need to keep track of the signal strength for management
+	 * packets we're keeping, because that provides the only way
+	 * to distinguish between multiple APs for the same network.
+	 * Since we can't extend io_buffer to store signal, this field
+	 * heads a linked list of "RX packet info" structures that
+	 * contain that signal strength field. Its entries always
+	 * parallel the entries in mgmt_queue, because the two queues
+	 * are always added to or removed from in parallel.
+	 */
+	struct list_head mgmt_info_queue;
+
+	/** Whether to store management packets
+	 *
+	 * Received beacon, probe, and action packets will be added to
+	 * mgmt_queue (and their signal strengths added to
+	 * mgmt_info_queue) only when this variable is TRUE. It should
+	 * be set by net80211_keep_mgmt() (which returns the old
+	 * value) only when calling code is prepared to poll the
+	 * management queue frequently, because packets will otherwise
+	 * pile up and exhaust memory.
+	 */
+	int keep_mgmt;
+};
+
+/** Structure representing a probed network.
+ *
+ * This is returned from the net80211_probe_finish functions and
+ * passed to the low-level association functions. At least essid,
+ * bssid, channel, beacon, and security must be filled in if you want
+ * to build this structure manually.
+ */
+struct net80211_wlan
+{
+	/** The human-readable ESSID (network name)
+	 *
+	 * Although the 802.11 SSID field is generally not
+	 * NUL-terminated, the iPXE code adds an extra NUL (and
+	 * expects one in this structure) for convenience.
+	 */
+	char essid[IEEE80211_MAX_SSID_LEN+1];
+
+	/** MAC address of the strongest-signal access point for this ESSID */
+	u8 bssid[ETH_ALEN];
+
+	/** Signal strength of beacon frame from that access point */
+	int signal;
+
+	/** The channel on which that access point communicates
+	 *
+	 * This is a raw channel number (net80211_channel::channel_nr),
+	 * so that it will not be affected by reconfiguration of the
+	 * device channels array.
+	 */
+	int channel;
+
+	/** The complete beacon or probe-response frame received */
+	struct io_buffer *beacon;
+
+	/** Security handshaking method used on the network */
+	enum net80211_security_proto handshaking;
+
+	/** Cryptographic algorithm used on the network */
+	enum net80211_crypto_alg crypto;
+
+	/** Link to allow chaining multiple structures into a list to
+	    be returned from net80211_probe_finish_all(). */
+	struct list_head list;
+};
+
+
+/** 802.11 encryption key setting */
+extern struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA );
+
+
+/**
+ * @defgroup net80211_probe 802.11 network location API
+ * @{
+ */
+int net80211_prepare_probe ( struct net80211_device *dev, int band,
+			     int active );
+struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
+						   const char *essid,
+						   int active );
+int net80211_probe_step ( struct net80211_probe_ctx *ctx );
+struct net80211_wlan *
+net80211_probe_finish_best ( struct net80211_probe_ctx *ctx );
+struct list_head *net80211_probe_finish_all ( struct net80211_probe_ctx *ctx );
+
+void net80211_free_wlan ( struct net80211_wlan *wlan );
+void net80211_free_wlanlist ( struct list_head *list );
+/** @} */
+
+
+/**
+ * @defgroup net80211_mgmt 802.11 network management API
+ * @{
+ */
+struct net80211_device * net80211_get ( struct net_device *netdev );
+void net80211_autoassociate ( struct net80211_device *dev );
+
+int net80211_change_channel ( struct net80211_device *dev, int channel );
+void net80211_set_rate_idx ( struct net80211_device *dev, int rate );
+
+int net80211_keep_mgmt ( struct net80211_device *dev, int enable );
+struct io_buffer * net80211_mgmt_dequeue ( struct net80211_device *dev,
+					   int *signal );
+int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc,
+		       u8 bssid[ETH_ALEN], struct io_buffer *iob );
+/** @} */
+
+
+/**
+ * @defgroup net80211_assoc 802.11 network association API
+ * @{
+ */
+int net80211_prepare_assoc ( struct net80211_device *dev,
+			     struct net80211_wlan *wlan );
+int net80211_send_auth ( struct net80211_device *dev,
+			 struct net80211_wlan *wlan, int method );
+int net80211_send_assoc ( struct net80211_device *dev,
+			  struct net80211_wlan *wlan );
+void net80211_deauthenticate ( struct net80211_device *dev, int rc );
+/** @} */
+
+
+/**
+ * @defgroup net80211_driver 802.11 driver interface API
+ * @{
+ */
+struct net80211_device *net80211_alloc ( size_t priv_size );
+int net80211_register ( struct net80211_device *dev,
+			struct net80211_device_operations *ops,
+			struct net80211_hw_info *hw );
+u16 net80211_duration ( struct net80211_device *dev, int bytes, u16 rate );
+void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
+		   int signal, u16 rate );
+void net80211_rx_err ( struct net80211_device *dev,
+		       struct io_buffer *iob, int rc );
+void net80211_tx_complete ( struct net80211_device *dev,
+			    struct io_buffer *iob, int retries, int rc );
+void net80211_unregister ( struct net80211_device *dev );
+void net80211_free ( struct net80211_device *dev );
+/** @} */
+
+/**
+ * Calculate duration field for a CTS control frame
+ *
+ * @v dev	802.11 device
+ * @v size	Size of the packet being cleared to send
+ *
+ * A CTS control frame's duration field captures the frame being
+ * protected and its 10-byte ACK.
+ */
+static inline u16 net80211_cts_duration ( struct net80211_device *dev,
+					  int size )
+{
+	return ( net80211_duration ( dev, 10,
+				     dev->rates[dev->rtscts_rate] ) +
+		 net80211_duration ( dev, size, dev->rates[dev->rate] ) );
+}
+
+/** 802.11 device setting tag magic */
+#define NET80211_SETTING_TAG_MAGIC 0x8211
+
+/**
+ * Construct 802.11 setting tag
+ *
+ * @v id		Unique identifier
+ * @ret tag		Setting tag
+ */
+#define NET80211_SETTING_TAG( id ) \
+	NETDEV_SETTING_TAG ( ( NET80211_SETTING_TAG_MAGIC << 8 ) | (id) )
+
+/** SSID setting tag */
+#define NET80211_SETTING_TAG_SSID NET80211_SETTING_TAG ( 0x01 )
+
+/** Active scanning setting tag */
+#define NET80211_SETTING_TAG_ACTIVE_SCAN NET80211_SETTING_TAG ( 0x02 )
+
+/** Wireless key setting tag */
+#define NET80211_SETTING_TAG_KEY NET80211_SETTING_TAG ( 0x03 )
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211_err.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211_err.h
new file mode 100644
index 0000000..2175b14
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/net80211_err.h
@@ -0,0 +1,633 @@
+#ifndef _IPXE_NET80211_ERR_H
+#define _IPXE_NET80211_ERR_H
+
+#include <errno.h>
+#include <ipxe/ieee80211.h>
+
+/*
+ * The iPXE 802.11 MAC layer.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * The iPXE 802.11 MAC layer errors.
+ */
+
+/* Disambiguate the EINVAL's a bit */
+#define EINVAL_PKT_TOO_SHORT __einfo_error ( EINFO_EINVAL_PKT_TOO_SHORT )
+#define EINFO_EINVAL_PKT_TOO_SHORT __einfo_uniqify \
+	( EINFO_EINVAL, 0x01, "Packet too short" )
+#define EINVAL_PKT_VERSION __einfo_error ( EINFO_EINVAL_PKT_VERSION )
+#define EINFO_EINVAL_PKT_VERSION __einfo_uniqify \
+	( EINFO_EINVAL, 0x02, "Packet 802.11 version not supported" )
+#define EINVAL_PKT_NOT_DATA __einfo_error ( EINFO_EINVAL_PKT_NOT_DATA )
+#define EINFO_EINVAL_PKT_NOT_DATA __einfo_uniqify \
+	( EINFO_EINVAL, 0x03, "Packet not a data packet" )
+#define EINVAL_PKT_NOT_FROMDS __einfo_error ( EINFO_EINVAL_PKT_NOT_FROMDS )
+#define EINFO_EINVAL_PKT_NOT_FROMDS __einfo_uniqify \
+	( EINFO_EINVAL, 0x04, "Packet not from an Access Point" )
+#define EINVAL_PKT_LLC_HEADER __einfo_error ( EINFO_EINVAL_PKT_LLC_HEADER )
+#define EINFO_EINVAL_PKT_LLC_HEADER __einfo_uniqify \
+	( EINFO_EINVAL, 0x05, "Packet has invalid LLC header" )
+#define EINVAL_CRYPTO_REQUEST __einfo_error ( EINFO_EINVAL_CRYPTO_REQUEST )
+#define EINFO_EINVAL_CRYPTO_REQUEST __einfo_uniqify \
+	( EINFO_EINVAL, 0x06, "Packet decryption error" )
+#define EINVAL_ACTIVE_SCAN __einfo_error ( EINFO_EINVAL_ACTIVE_SCAN )
+#define EINFO_EINVAL_ACTIVE_SCAN __einfo_uniqify \
+	( EINFO_EINVAL, 0x07, "Invalid active scan requested" )
+
+/*
+ * 802.11 error codes: The AP can give us a status code explaining why
+ * authentication failed, or a reason code explaining why we were
+ * deauthenticated/disassociated. These codes range from 0-63 (the
+ * field is 16 bits wide, but only up to 45 or so are defined yet; we
+ * allow up to 63 for extensibility). This is encoded into an error
+ * code as such:
+ *
+ *                                      status & 0x1f goes here --vv--
+ *   Status code 0-31:  ECONNREFUSED | EUNIQ_(status & 0x1f) (0e1a6038)
+ *   Status code 32-63: EHOSTUNREACH | EUNIQ_(status & 0x1f) (171a6011)
+ *   Reason code 0-31:  ECONNRESET | EUNIQ_(reason & 0x1f)   (0f1a6039)
+ *   Reason code 32-63: ENETRESET | EUNIQ_(reason & 0x1f)    (271a6001)
+ *
+ * The POSIX error codes more or less convey the appropriate message
+ * (status codes occur when we can't associate at all, reason codes
+ * when we lose association unexpectedly) and let us extract the
+ * complete 802.11 error code from the rc value.
+ *
+ * The error messages follow the 802.11 standard as much as is
+ * feasible, but most have been abbreviated to fit the 50-character
+ * limit imposed by strerror().
+ */
+
+/* 802.11 status codes (IEEE Std 802.11-2007, Table 7-23) */
+
+#define ECONNREFUSED_FAILURE __einfo_error				\
+	( EINFO_ECONNREFUSED_FAILURE )
+#define EINFO_ECONNREFUSED_FAILURE __einfo_uniqify			\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_FAILURE & 0x1f ),				\
+	  "Unspecified failure" )
+
+#define ECONNREFUSED_CAPAB_UNSUPP __einfo_error				\
+	( EINFO_ECONNREFUSED_CAPAB_UNSUPP )
+#define EINFO_ECONNREFUSED_CAPAB_UNSUPP __einfo_uniqify			\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_CAPAB_UNSUPP & 0x1f ),			\
+	  "Cannot support all requested capabilities" )
+
+#define ECONNREFUSED_REASSOC_INVALID __einfo_error			\
+	( EINFO_ECONNREFUSED_REASSOC_INVALID )
+#define EINFO_ECONNREFUSED_REASSOC_INVALID __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_REASSOC_INVALID & 0x1f ),			\
+	  "Reassociation denied due to lack of association" )
+
+#define ECONNREFUSED_ASSOC_DENIED __einfo_error				\
+	( EINFO_ECONNREFUSED_ASSOC_DENIED )
+#define EINFO_ECONNREFUSED_ASSOC_DENIED __einfo_uniqify			\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_DENIED & 0x1f ),			\
+	  "Association denied for another reason" )
+
+#define ECONNREFUSED_AUTH_ALGO_UNSUPP __einfo_error			\
+	( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP )
+#define EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_AUTH_ALGO_UNSUPP & 0x1f ),			\
+	  "Authentication algorithm unsupported" )
+
+#define ECONNREFUSED_AUTH_SEQ_INVALID __einfo_error			\
+	( EINFO_ECONNREFUSED_AUTH_SEQ_INVALID )
+#define EINFO_ECONNREFUSED_AUTH_SEQ_INVALID __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_AUTH_SEQ_INVALID & 0x1f ),			\
+	  "Authentication sequence number unexpected" )
+
+#define ECONNREFUSED_AUTH_CHALL_INVALID __einfo_error			\
+	( EINFO_ECONNREFUSED_AUTH_CHALL_INVALID )
+#define EINFO_ECONNREFUSED_AUTH_CHALL_INVALID __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,					\
+	  ( IEEE80211_STATUS_AUTH_CHALL_INVALID & 0x1f ),		\
+	  "Authentication rejected due to challenge failure" )
+
+#define ECONNREFUSED_AUTH_TIMEOUT __einfo_error				\
+	( EINFO_ECONNREFUSED_AUTH_TIMEOUT )
+#define EINFO_ECONNREFUSED_AUTH_TIMEOUT __einfo_uniqify			\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_AUTH_TIMEOUT & 0x1f ),			\
+	  "Authentication rejected due to timeout" )
+
+#define ECONNREFUSED_ASSOC_NO_ROOM __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_NO_ROOM )
+#define EINFO_ECONNREFUSED_ASSOC_NO_ROOM __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NO_ROOM & 0x1f ),			\
+	  "Association denied because AP is out of resources" )
+
+#define ECONNREFUSED_ASSOC_NEED_RATE __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_RATE )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_RATE __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_RATE & 0x1f ),			\
+	  "Association denied; basic rate support required" )
+
+#define ECONNREFUSED_ASSOC_NEED_SHORT_PMBL __einfo_error		\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_PMBL )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_PMBL __einfo_uniqify	\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_SHORT_PMBL & 0x1f ),		\
+	  "Association denied; short preamble support req'd" )
+
+#define ECONNREFUSED_ASSOC_NEED_PBCC __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_PBCC )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_PBCC __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_PBCC & 0x1f ),			\
+	  "Association denied; PBCC modulation support req'd" )
+
+#define ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY __einfo_error		\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY __einfo_uniqify	\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_CHAN_AGILITY & 0x1f ),		\
+	  "Association denied; Channel Agility support req'd" )
+
+#define ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT __einfo_error		\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT __einfo_uniqify	\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_SPECTRUM_MGMT & 0x1f ),		\
+	  "Association denied; Spectrum Management required" )
+
+#define ECONNREFUSED_ASSOC_BAD_POWER __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_BAD_POWER )
+#define EINFO_ECONNREFUSED_ASSOC_BAD_POWER __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_BAD_POWER & 0x1f ),			\
+	  "Association denied; Power Capability unacceptable" )
+
+#define ECONNREFUSED_ASSOC_BAD_CHANNELS __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_BAD_CHANNELS )
+#define EINFO_ECONNREFUSED_ASSOC_BAD_CHANNELS __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_BAD_CHANNELS & 0x1f ),		\
+	  "Association denied; Supported Channels unacceptable" )
+
+#define ECONNREFUSED_ASSOC_NEED_SHORT_SLOT __einfo_error		\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_SLOT )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_SHORT_SLOT __einfo_uniqify	\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_SHORT_SLOT & 0x1f ),		\
+	  "Association denied; Short Slot Tume support req'd" )
+
+#define ECONNREFUSED_ASSOC_NEED_DSSS_OFDM __einfo_error			\
+	( EINFO_ECONNREFUSED_ASSOC_NEED_DSSS_OFDM )
+#define EINFO_ECONNREFUSED_ASSOC_NEED_DSSS_OFDM __einfo_uniqify		\
+	( EINFO_ECONNREFUSED,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_DSSS_OFDM & 0x1f ),		\
+	  "Association denied; DSSS-OFDM support required" )
+
+#define EHOSTUNREACH_QOS_FAILURE __einfo_error				\
+	( EINFO_EHOSTUNREACH_QOS_FAILURE )
+#define EINFO_EHOSTUNREACH_QOS_FAILURE __einfo_uniqify			\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_QOS_FAILURE & 0x1f ),			\
+	  "Unspecified, QoS-related failure" )
+
+#define EHOSTUNREACH_QOS_NO_ROOM __einfo_error				\
+	( EINFO_EHOSTUNREACH_QOS_NO_ROOM )
+#define EINFO_EHOSTUNREACH_QOS_NO_ROOM __einfo_uniqify			\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_QOS_NO_ROOM & 0x1f ),			\
+	  "Association denied; QoS AP out of QoS resources" )
+
+#define EHOSTUNREACH_LINK_IS_HORRIBLE __einfo_error			\
+	( EINFO_EHOSTUNREACH_LINK_IS_HORRIBLE )
+#define EINFO_EHOSTUNREACH_LINK_IS_HORRIBLE __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_LINK_IS_HORRIBLE & 0x1f ),			\
+	  "Association denied due to excessively poor link" )
+
+#define EHOSTUNREACH_ASSOC_NEED_QOS __einfo_error			\
+	( EINFO_EHOSTUNREACH_ASSOC_NEED_QOS )
+#define EINFO_EHOSTUNREACH_ASSOC_NEED_QOS __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_ASSOC_NEED_QOS & 0x1f ),			\
+	  "Association denied; QoS support required" )
+
+#define EHOSTUNREACH_REQUEST_DECLINED __einfo_error			\
+	( EINFO_EHOSTUNREACH_REQUEST_DECLINED )
+#define EINFO_EHOSTUNREACH_REQUEST_DECLINED __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_REQUEST_DECLINED & 0x1f ),			\
+	  "The request has been declined" )
+
+#define EHOSTUNREACH_REQUEST_INVALID __einfo_error			\
+	( EINFO_EHOSTUNREACH_REQUEST_INVALID )
+#define EINFO_EHOSTUNREACH_REQUEST_INVALID __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_REQUEST_INVALID & 0x1f ),			\
+	  "Request unsuccessful due to invalid parameters" )
+
+#define EHOSTUNREACH_TS_NOT_CREATED_AGAIN __einfo_error			\
+	( EINFO_EHOSTUNREACH_TS_NOT_CREATED_AGAIN )
+#define EINFO_EHOSTUNREACH_TS_NOT_CREATED_AGAIN __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_TS_NOT_CREATED_AGAIN & 0x1f ),		\
+	  "TS not created due to bad specification" )
+
+#define EHOSTUNREACH_INVALID_IE __einfo_error				\
+	( EINFO_EHOSTUNREACH_INVALID_IE )
+#define EINFO_EHOSTUNREACH_INVALID_IE __einfo_uniqify			\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_INVALID_IE & 0x1f ),			\
+	  "Invalid information element" )
+
+#define EHOSTUNREACH_GROUP_CIPHER_INVALID __einfo_error			\
+	( EINFO_EHOSTUNREACH_GROUP_CIPHER_INVALID )
+#define EINFO_EHOSTUNREACH_GROUP_CIPHER_INVALID __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_GROUP_CIPHER_INVALID & 0x1f ),		\
+	  "Invalid group cipher" )
+
+#define EHOSTUNREACH_PAIR_CIPHER_INVALID __einfo_error			\
+	( EINFO_EHOSTUNREACH_PAIR_CIPHER_INVALID )
+#define EINFO_EHOSTUNREACH_PAIR_CIPHER_INVALID __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_PAIR_CIPHER_INVALID & 0x1f ),		\
+	  "Invalid pairwise cipher" )
+
+#define EHOSTUNREACH_AKMP_INVALID __einfo_error				\
+	( EINFO_EHOSTUNREACH_AKMP_INVALID )
+#define EINFO_EHOSTUNREACH_AKMP_INVALID __einfo_uniqify			\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_AKMP_INVALID & 0x1f ),			\
+	  "Invalid AKMP" )
+
+#define EHOSTUNREACH_RSN_VERSION_UNSUPP __einfo_error			\
+	( EINFO_EHOSTUNREACH_RSN_VERSION_UNSUPP )
+#define EINFO_EHOSTUNREACH_RSN_VERSION_UNSUPP __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_RSN_VERSION_UNSUPP & 0x1f ),		\
+	  "Unsupported RSN information element version" )
+
+#define EHOSTUNREACH_RSN_CAPAB_INVALID __einfo_error			\
+	( EINFO_EHOSTUNREACH_RSN_CAPAB_INVALID )
+#define EINFO_EHOSTUNREACH_RSN_CAPAB_INVALID __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_RSN_CAPAB_INVALID & 0x1f ),		\
+	  "Invalid RSN information element capabilities" )
+
+#define EHOSTUNREACH_CIPHER_REJECTED __einfo_error			\
+	( EINFO_EHOSTUNREACH_CIPHER_REJECTED )
+#define EINFO_EHOSTUNREACH_CIPHER_REJECTED __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_CIPHER_REJECTED & 0x1f ),			\
+	  "Cipher suite rejected because of security policy" )
+
+#define EHOSTUNREACH_TS_NOT_CREATED_WAIT __einfo_error			\
+	( EINFO_EHOSTUNREACH_TS_NOT_CREATED_WAIT )
+#define EINFO_EHOSTUNREACH_TS_NOT_CREATED_WAIT __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_TS_NOT_CREATED_WAIT & 0x1f ),		\
+	  "TS not created due to insufficient delay" )
+
+#define EHOSTUNREACH_DIRECT_LINK_FORBIDDEN __einfo_error		\
+	( EINFO_EHOSTUNREACH_DIRECT_LINK_FORBIDDEN )
+#define EINFO_EHOSTUNREACH_DIRECT_LINK_FORBIDDEN __einfo_uniqify	\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_DIRECT_LINK_FORBIDDEN & 0x1f ),		\
+	  "Direct link is not allowed in the BSS by policy" )
+
+#define EHOSTUNREACH_DEST_NOT_PRESENT __einfo_error			\
+	( EINFO_EHOSTUNREACH_DEST_NOT_PRESENT )
+#define EINFO_EHOSTUNREACH_DEST_NOT_PRESENT __einfo_uniqify		\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_DEST_NOT_PRESENT & 0x1f ),			\
+	  "The Destination STA is not present within the BSS" )
+
+#define EHOSTUNREACH_DEST_NOT_QOS __einfo_error				\
+	( EINFO_EHOSTUNREACH_DEST_NOT_QOS )
+#define EINFO_EHOSTUNREACH_DEST_NOT_QOS __einfo_uniqify			\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_DEST_NOT_QOS & 0x1f ),			\
+	  "The Destination STA is not a QoS STA" )
+
+#define EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH __einfo_error		\
+	( EINFO_EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH )
+#define EINFO_EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH __einfo_uniqify	\
+	( EINFO_EHOSTUNREACH,						\
+	  ( IEEE80211_STATUS_ASSOC_LISTEN_TOO_HIGH & 0x1f ),		\
+	  "Association denied; Listen Interval is too large" )
+
+/* 802.11 reason codes (IEEE Std 802.11-2007, Table 7-22) */
+
+#define ECONNRESET_UNSPECIFIED __einfo_error				\
+	( EINFO_ECONNRESET_UNSPECIFIED )
+#define EINFO_ECONNRESET_UNSPECIFIED __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_UNSPECIFIED & 0x1f ),			\
+	  "Unspecified reason" )
+
+#define ECONNRESET_AUTH_NO_LONGER_VALID __einfo_error			\
+	( EINFO_ECONNRESET_AUTH_NO_LONGER_VALID )
+#define EINFO_ECONNRESET_AUTH_NO_LONGER_VALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_AUTH_NO_LONGER_VALID & 0x1f ),		\
+	  "Previous authentication no longer valid" )
+
+#define ECONNRESET_LEAVING __einfo_error				\
+	( EINFO_ECONNRESET_LEAVING )
+#define EINFO_ECONNRESET_LEAVING __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_LEAVING & 0x1f ),				\
+	  "Deauthenticated due to leaving network" )
+
+#define ECONNRESET_INACTIVITY __einfo_error				\
+	( EINFO_ECONNRESET_INACTIVITY )
+#define EINFO_ECONNRESET_INACTIVITY __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_INACTIVITY & 0x1f ),			\
+	  "Disassociated due to inactivity" )
+
+#define ECONNRESET_OUT_OF_RESOURCES __einfo_error			\
+	( EINFO_ECONNRESET_OUT_OF_RESOURCES )
+#define EINFO_ECONNRESET_OUT_OF_RESOURCES __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_OUT_OF_RESOURCES & 0x1f ),			\
+	  "Disassociated because AP is out of resources" )
+
+#define ECONNRESET_NEED_AUTH __einfo_error				\
+	( EINFO_ECONNRESET_NEED_AUTH )
+#define EINFO_ECONNRESET_NEED_AUTH __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_NEED_AUTH & 0x1f ),			\
+	  "Class 2 frame received from nonauthenticated STA" )
+
+#define ECONNRESET_NEED_ASSOC __einfo_error				\
+	( EINFO_ECONNRESET_NEED_ASSOC )
+#define EINFO_ECONNRESET_NEED_ASSOC __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_NEED_ASSOC & 0x1f ),			\
+	  "Class 3 frame received from nonassociated STA" )
+
+#define ECONNRESET_LEAVING_TO_ROAM __einfo_error			\
+	( EINFO_ECONNRESET_LEAVING_TO_ROAM )
+#define EINFO_ECONNRESET_LEAVING_TO_ROAM __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_LEAVING_TO_ROAM & 0x1f ),			\
+	  "Disassociated due to roaming" )
+
+#define ECONNRESET_REASSOC_INVALID __einfo_error			\
+	( EINFO_ECONNRESET_REASSOC_INVALID )
+#define EINFO_ECONNRESET_REASSOC_INVALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_REASSOC_INVALID & 0x1f ),			\
+	  "STA requesting (re)association not authenticated" )
+
+#define ECONNRESET_BAD_POWER __einfo_error				\
+	( EINFO_ECONNRESET_BAD_POWER )
+#define EINFO_ECONNRESET_BAD_POWER __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_BAD_POWER & 0x1f ),			\
+	  "Disassociated; Power Capability unacceptable" )
+
+#define ECONNRESET_BAD_CHANNELS __einfo_error				\
+	( EINFO_ECONNRESET_BAD_CHANNELS )
+#define EINFO_ECONNRESET_BAD_CHANNELS __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_BAD_CHANNELS & 0x1f ),			\
+	  "Disassociated; Supported Channels unacceptable" )
+
+#define ECONNRESET_INVALID_IE __einfo_error				\
+	( EINFO_ECONNRESET_INVALID_IE )
+#define EINFO_ECONNRESET_INVALID_IE __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_INVALID_IE & 0x1f ),			\
+	  "Invalid information element" )
+
+#define ECONNRESET_MIC_FAILURE __einfo_error				\
+	( EINFO_ECONNRESET_MIC_FAILURE )
+#define EINFO_ECONNRESET_MIC_FAILURE __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_MIC_FAILURE & 0x1f ),			\
+	  "Message integrity code (MIC) failure" )
+
+#define ECONNRESET_4WAY_TIMEOUT __einfo_error				\
+	( EINFO_ECONNRESET_4WAY_TIMEOUT )
+#define EINFO_ECONNRESET_4WAY_TIMEOUT __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_4WAY_TIMEOUT & 0x1f ),			\
+	  "4-Way Handshake timeout" )
+
+#define ECONNRESET_GROUPKEY_TIMEOUT __einfo_error			\
+	( EINFO_ECONNRESET_GROUPKEY_TIMEOUT )
+#define EINFO_ECONNRESET_GROUPKEY_TIMEOUT __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_GROUPKEY_TIMEOUT & 0x1f ),			\
+	  "Group Key Handshake timeout" )
+
+#define ECONNRESET_4WAY_INVALID __einfo_error				\
+	( EINFO_ECONNRESET_4WAY_INVALID )
+#define EINFO_ECONNRESET_4WAY_INVALID __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_4WAY_INVALID & 0x1f ),			\
+	  "4-Way Handshake information element changed unduly" )
+
+#define ECONNRESET_GROUP_CIPHER_INVALID __einfo_error			\
+	( EINFO_ECONNRESET_GROUP_CIPHER_INVALID )
+#define EINFO_ECONNRESET_GROUP_CIPHER_INVALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_GROUP_CIPHER_INVALID & 0x1f ),		\
+	  "Invalid group cipher" )
+
+#define ECONNRESET_PAIR_CIPHER_INVALID __einfo_error			\
+	( EINFO_ECONNRESET_PAIR_CIPHER_INVALID )
+#define EINFO_ECONNRESET_PAIR_CIPHER_INVALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_PAIR_CIPHER_INVALID & 0x1f ),		\
+	  "Invalid pairwise cipher" )
+
+#define ECONNRESET_AKMP_INVALID __einfo_error				\
+	( EINFO_ECONNRESET_AKMP_INVALID )
+#define EINFO_ECONNRESET_AKMP_INVALID __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_AKMP_INVALID & 0x1f ),			\
+	  "Invalid AKMP" )
+
+#define ECONNRESET_RSN_VERSION_INVALID __einfo_error			\
+	( EINFO_ECONNRESET_RSN_VERSION_INVALID )
+#define EINFO_ECONNRESET_RSN_VERSION_INVALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_RSN_VERSION_INVALID & 0x1f ),		\
+	  "Unsupported RSN information element version" )
+
+#define ECONNRESET_RSN_CAPAB_INVALID __einfo_error			\
+	( EINFO_ECONNRESET_RSN_CAPAB_INVALID )
+#define EINFO_ECONNRESET_RSN_CAPAB_INVALID __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_RSN_CAPAB_INVALID & 0x1f ),		\
+	  "Invalid RSN information element capabilities" )
+
+#define ECONNRESET_8021X_FAILURE __einfo_error				\
+	( EINFO_ECONNRESET_8021X_FAILURE )
+#define EINFO_ECONNRESET_8021X_FAILURE __einfo_uniqify			\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_8021X_FAILURE & 0x1f ),			\
+	  "IEEE 802.1X authentication failed" )
+
+#define ECONNRESET_CIPHER_REJECTED __einfo_error			\
+	( EINFO_ECONNRESET_CIPHER_REJECTED )
+#define EINFO_ECONNRESET_CIPHER_REJECTED __einfo_uniqify		\
+	( EINFO_ECONNRESET,						\
+	  ( IEEE80211_REASON_CIPHER_REJECTED & 0x1f ),			\
+	  "Cipher suite rejected because of security policy" )
+
+#define ENETRESET_QOS_UNSPECIFIED __einfo_error				\
+	( EINFO_ENETRESET_QOS_UNSPECIFIED )
+#define EINFO_ENETRESET_QOS_UNSPECIFIED __einfo_uniqify			\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_QOS_UNSPECIFIED & 0x1f ),			\
+	  "Disassociated for unspecified, QoS-related reason" )
+
+#define ENETRESET_QOS_OUT_OF_RESOURCES __einfo_error			\
+	( EINFO_ENETRESET_QOS_OUT_OF_RESOURCES )
+#define EINFO_ENETRESET_QOS_OUT_OF_RESOURCES __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_QOS_OUT_OF_RESOURCES & 0x1f ),		\
+	  "Disassociated; QoS AP is out of QoS resources" )
+
+#define ENETRESET_LINK_IS_HORRIBLE __einfo_error			\
+	( EINFO_ENETRESET_LINK_IS_HORRIBLE )
+#define EINFO_ENETRESET_LINK_IS_HORRIBLE __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_LINK_IS_HORRIBLE & 0x1f ),			\
+	  "Disassociated due to excessively poor link" )
+
+#define ENETRESET_INVALID_TXOP __einfo_error				\
+	( EINFO_ENETRESET_INVALID_TXOP )
+#define EINFO_ENETRESET_INVALID_TXOP __einfo_uniqify			\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_INVALID_TXOP & 0x1f ),			\
+	  "Disassociated due to TXOP limit violation" )
+
+#define ENETRESET_REQUESTED_LEAVING __einfo_error			\
+	( EINFO_ENETRESET_REQUESTED_LEAVING )
+#define EINFO_ENETRESET_REQUESTED_LEAVING __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_REQUESTED_LEAVING & 0x1f ),		\
+	  "Requested; STA is leaving the BSS (or resetting)" )
+
+#define ENETRESET_REQUESTED_NO_USE __einfo_error			\
+	( EINFO_ENETRESET_REQUESTED_NO_USE )
+#define EINFO_ENETRESET_REQUESTED_NO_USE __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_REQUESTED_NO_USE & 0x1f ),			\
+	  "Requested; does not want to use the mechanism" )
+
+#define ENETRESET_REQUESTED_NEED_SETUP __einfo_error			\
+	( EINFO_ENETRESET_REQUESTED_NEED_SETUP )
+#define EINFO_ENETRESET_REQUESTED_NEED_SETUP __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_REQUESTED_NEED_SETUP & 0x1f ),		\
+	  "Requested; setup is required" )
+
+#define ENETRESET_REQUESTED_TIMEOUT __einfo_error			\
+	( EINFO_ENETRESET_REQUESTED_TIMEOUT )
+#define EINFO_ENETRESET_REQUESTED_TIMEOUT __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_REQUESTED_TIMEOUT & 0x1f ),		\
+	  "Requested from peer STA due to timeout" )
+
+#define ENETRESET_CIPHER_UNSUPPORTED __einfo_error			\
+	( EINFO_ENETRESET_CIPHER_UNSUPPORTED )
+#define EINFO_ENETRESET_CIPHER_UNSUPPORTED __einfo_uniqify		\
+	( EINFO_ENETRESET,						\
+	  ( IEEE80211_REASON_CIPHER_UNSUPPORTED & 0x1f ),		\
+	  "Peer STA does not support requested cipher suite" )
+
+/** Make return status code from 802.11 status code */
+#define E80211_STATUS( stat )						\
+	EUNIQ ( ( ( stat & 0x20 ) ? EHOSTUNREACH : ECONNREFUSED ),	\
+		( stat &0x1f ),						\
+		ECONNREFUSED_FAILURE,					\
+		ECONNREFUSED_CAPAB_UNSUPP,				\
+		ECONNREFUSED_REASSOC_INVALID,				\
+		ECONNREFUSED_ASSOC_DENIED,				\
+		ECONNREFUSED_AUTH_ALGO_UNSUPP,				\
+		ECONNREFUSED_AUTH_SEQ_INVALID,				\
+		ECONNREFUSED_AUTH_CHALL_INVALID,			\
+		ECONNREFUSED_AUTH_TIMEOUT,				\
+		ECONNREFUSED_ASSOC_NO_ROOM,				\
+		ECONNREFUSED_ASSOC_NEED_RATE,				\
+		ECONNREFUSED_ASSOC_NEED_SHORT_PMBL,			\
+		ECONNREFUSED_ASSOC_NEED_PBCC,				\
+		ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY,			\
+		ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT,			\
+		ECONNREFUSED_ASSOC_BAD_POWER,				\
+		ECONNREFUSED_ASSOC_BAD_CHANNELS,			\
+		ECONNREFUSED_ASSOC_NEED_SHORT_SLOT,			\
+		ECONNREFUSED_ASSOC_NEED_DSSS_OFDM,			\
+		EHOSTUNREACH_QOS_FAILURE,				\
+		EHOSTUNREACH_QOS_NO_ROOM,				\
+		EHOSTUNREACH_LINK_IS_HORRIBLE,				\
+		EHOSTUNREACH_ASSOC_NEED_QOS,				\
+		EHOSTUNREACH_REQUEST_DECLINED,				\
+		EHOSTUNREACH_REQUEST_INVALID,				\
+		EHOSTUNREACH_TS_NOT_CREATED_AGAIN,			\
+		EHOSTUNREACH_INVALID_IE,				\
+		EHOSTUNREACH_GROUP_CIPHER_INVALID,			\
+		EHOSTUNREACH_PAIR_CIPHER_INVALID,			\
+		EHOSTUNREACH_AKMP_INVALID,				\
+		EHOSTUNREACH_RSN_VERSION_UNSUPP,			\
+		EHOSTUNREACH_RSN_CAPAB_INVALID,				\
+		EHOSTUNREACH_CIPHER_REJECTED,				\
+		EHOSTUNREACH_TS_NOT_CREATED_WAIT,			\
+		EHOSTUNREACH_DIRECT_LINK_FORBIDDEN,			\
+		EHOSTUNREACH_DEST_NOT_PRESENT,				\
+		EHOSTUNREACH_DEST_NOT_QOS,				\
+		EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH )
+
+/** Make return status code from 802.11 reason code */
+#define E80211_REASON( reas )						\
+	EUNIQ ( ( ( reas & 0x20 ) ? ENETRESET : ECONNRESET ),		\
+		( reas & 0x1f ),					\
+		ECONNRESET_UNSPECIFIED,					\
+		ECONNRESET_AUTH_NO_LONGER_VALID,			\
+		ECONNRESET_LEAVING,					\
+		ECONNRESET_INACTIVITY,					\
+		ECONNRESET_OUT_OF_RESOURCES,				\
+		ECONNRESET_NEED_AUTH,					\
+		ECONNRESET_NEED_ASSOC,					\
+		ECONNRESET_LEAVING_TO_ROAM,				\
+		ECONNRESET_REASSOC_INVALID,				\
+		ECONNRESET_BAD_POWER,					\
+		ECONNRESET_BAD_CHANNELS,				\
+		ECONNRESET_INVALID_IE,					\
+		ECONNRESET_MIC_FAILURE,					\
+		ECONNRESET_4WAY_TIMEOUT,				\
+		ECONNRESET_GROUPKEY_TIMEOUT,				\
+		ECONNRESET_4WAY_INVALID,				\
+		ECONNRESET_GROUP_CIPHER_INVALID,			\
+		ECONNRESET_PAIR_CIPHER_INVALID,				\
+		ECONNRESET_AKMP_INVALID,				\
+		ECONNRESET_RSN_VERSION_INVALID,				\
+		ECONNRESET_RSN_CAPAB_INVALID,				\
+		ECONNRESET_8021X_FAILURE,				\
+		ECONNRESET_CIPHER_REJECTED,				\
+		ENETRESET_QOS_UNSPECIFIED,				\
+		ENETRESET_QOS_OUT_OF_RESOURCES,				\
+		ENETRESET_LINK_IS_HORRIBLE,				\
+		ENETRESET_INVALID_TXOP,					\
+		ENETRESET_REQUESTED_LEAVING,				\
+		ENETRESET_REQUESTED_NO_USE,				\
+		ENETRESET_REQUESTED_NEED_SETUP,				\
+		ENETRESET_REQUESTED_TIMEOUT,				\
+		ENETRESET_CIPHER_UNSUPPORTED )
+
+#endif /* _IPXE_NET80211_ERR_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/netdevice.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/netdevice.h
new file mode 100644
index 0000000..e49191f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/netdevice.h
@@ -0,0 +1,669 @@
+#ifndef _IPXE_NETDEVICE_H
+#define _IPXE_NETDEVICE_H
+
+/** @file
+ *
+ * Network device management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/settings.h>
+
+struct io_buffer;
+struct net_device;
+struct net_protocol;
+struct ll_protocol;
+struct device;
+
+/** Maximum length of a hardware address
+ *
+ * The longest currently-supported link-layer address is for IPoIB.
+ */
+#define MAX_HW_ADDR_LEN 8
+
+/** Maximum length of a link-layer address
+ *
+ * The longest currently-supported link-layer address is for IPoIB.
+ */
+#define MAX_LL_ADDR_LEN 20
+
+/** Maximum length of a link-layer header
+ *
+ * The longest currently-supported link-layer header is for 802.11: a
+ * 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header, plus a
+ * possible 4-byte VLAN header.  (The IPoIB link-layer pseudo-header
+ * doesn't actually include link-layer addresses; see ipoib.c for
+ * details.)
+ */
+#define MAX_LL_HEADER_LEN 36
+
+/** Maximum length of a network-layer address */
+#define MAX_NET_ADDR_LEN 4
+
+/** Maximum length of a network-layer header
+ *
+ * The longest currently-supported network-layer header is for IPv6 at
+ * 40 bytes.
+ */
+#define MAX_NET_HEADER_LEN 40
+
+/** Maximum combined length of a link-layer and network-layer header */
+#define MAX_LL_NET_HEADER_LEN ( MAX_LL_HEADER_LEN + MAX_NET_HEADER_LEN )
+
+/**
+ * A network-layer protocol
+ *
+ */
+struct net_protocol {
+	/** Protocol name */
+	const char *name;
+	/**
+	 * Process received packet
+	 *
+	 * @v iobuf	I/O buffer
+	 * @v netdev	Network device
+	 * @v ll_dest	Link-layer destination address
+	 * @v ll_source	Link-layer source address
+	 *
+	 * This method takes ownership of the I/O buffer.
+	 */
+	int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev,
+		       const void *ll_dest, const void *ll_source );
+	/**
+	 * Transcribe network-layer address
+	 *
+	 * @v net_addr	Network-layer address
+	 * @ret string	Human-readable transcription of address
+	 *
+	 * This method should convert the network-layer address into a
+	 * human-readable format (e.g. dotted quad notation for IPv4).
+	 *
+	 * The buffer used to hold the transcription is statically
+	 * allocated.
+	 */
+	const char * ( *ntoa ) ( const void * net_addr );
+	/** Network-layer protocol
+	 *
+	 * This is an ETH_P_XXX constant, in network-byte order
+	 */
+	uint16_t net_proto;
+	/** Network-layer address length */
+	uint8_t net_addr_len;
+};
+
+/**
+ * A link-layer protocol
+ *
+ */
+struct ll_protocol {
+	/** Protocol name */
+	const char *name;
+	/**
+	 * Add link-layer header
+	 *
+	 * @v netdev		Network device
+	 * @v iobuf		I/O buffer
+	 * @v ll_dest		Link-layer destination address
+	 * @v ll_source		Source link-layer address
+	 * @v net_proto		Network-layer protocol, in network-byte order
+	 * @ret rc		Return status code
+	 */
+	int ( * push ) ( struct net_device *netdev, struct io_buffer *iobuf,
+			 const void *ll_dest, const void *ll_source,
+			 uint16_t net_proto );
+	/**
+	 * Remove link-layer header
+	 *
+	 * @v netdev		Network device
+	 * @v iobuf		I/O buffer
+	 * @ret ll_dest		Link-layer destination address
+	 * @ret ll_source	Source link-layer address
+	 * @ret net_proto	Network-layer protocol, in network-byte order
+	 * @ret rc		Return status code
+	 */
+	int ( * pull ) ( struct net_device *netdev, struct io_buffer *iobuf,
+			 const void **ll_dest, const void **ll_source,
+			 uint16_t *net_proto );
+	/**
+	 * Initialise link-layer address
+	 *
+	 * @v hw_addr		Hardware address
+	 * @v ll_addr		Link-layer address to fill in
+	 */
+	void ( * init_addr ) ( const void *hw_addr, void *ll_addr );
+	/**
+	 * Transcribe link-layer address
+	 *
+	 * @v ll_addr		Link-layer address
+	 * @ret string		Human-readable transcription of address
+	 *
+	 * This method should convert the link-layer address into a
+	 * human-readable format.
+	 *
+	 * The buffer used to hold the transcription is statically
+	 * allocated.
+	 */
+	const char * ( * ntoa ) ( const void *ll_addr );
+	/**
+	 * Hash multicast address
+	 *
+	 * @v af		Address family
+	 * @v net_addr		Network-layer address
+	 * @v ll_addr		Link-layer address to fill in
+	 * @ret rc		Return status code
+	 */
+	int ( * mc_hash ) ( unsigned int af, const void *net_addr,
+			    void *ll_addr );
+	/**
+	 * Generate Ethernet-compatible compressed link-layer address
+	 *
+	 * @v ll_addr		Link-layer address
+	 * @v eth_addr		Ethernet-compatible address to fill in
+	 */
+	int ( * eth_addr ) ( const void *ll_addr, void *eth_addr );
+	/** Link-layer protocol
+	 *
+	 * This is an ARPHRD_XXX constant, in network byte order.
+	 */
+	uint16_t ll_proto;
+	/** Hardware address length */
+	uint8_t hw_addr_len;
+	/** Link-layer address length */
+	uint8_t ll_addr_len;
+	/** Link-layer header length */
+	uint8_t ll_header_len;
+};
+
+/** Network device operations */
+struct net_device_operations {
+	/** Open network device
+	 *
+	 * @v netdev	Network device
+	 * @ret rc	Return status code
+	 *
+	 * This method should allocate RX I/O buffers and enable
+	 * the hardware to start transmitting and receiving packets.
+	 */
+	int ( * open ) ( struct net_device *netdev );
+	/** Close network device
+	 *
+	 * @v netdev	Network device
+	 *
+	 * This method should stop the flow of packets, and free up
+	 * any packets that are currently in the device's TX queue.
+	 */
+	void ( * close ) ( struct net_device *netdev );
+	/** Transmit packet
+	 *
+	 * @v netdev	Network device
+	 * @v iobuf	I/O buffer
+	 * @ret rc	Return status code
+	 *
+	 * This method should cause the hardware to initiate
+	 * transmission of the I/O buffer.
+	 *
+	 * If this method returns success, the I/O buffer remains
+	 * owned by the net device's TX queue, and the net device must
+	 * eventually call netdev_tx_complete() to free the buffer.
+	 * If this method returns failure, the I/O buffer is
+	 * immediately released; the failure is interpreted as
+	 * "failure to enqueue buffer".
+	 *
+	 * This method is guaranteed to be called only when the device
+	 * is open.
+	 */
+	int ( * transmit ) ( struct net_device *netdev,
+			     struct io_buffer *iobuf );
+	/** Poll for completed and received packets
+	 *
+	 * @v netdev	Network device
+	 *
+	 * This method should cause the hardware to check for
+	 * completed transmissions and received packets.  Any received
+	 * packets should be delivered via netdev_rx().
+	 *
+	 * This method is guaranteed to be called only when the device
+	 * is open.
+	 */
+	void ( * poll ) ( struct net_device *netdev );
+	/** Enable or disable interrupts
+	 *
+	 * @v netdev	Network device
+	 * @v enable	Interrupts should be enabled
+	 *
+	 * This method may be NULL to indicate that interrupts are not
+	 * supported.
+	 */
+	void ( * irq ) ( struct net_device *netdev, int enable );
+};
+
+/** Network device error */
+struct net_device_error {
+	/** Error status code */
+	int rc;
+	/** Error count */
+	unsigned int count;
+};
+
+/** Maximum number of unique errors that we will keep track of */
+#define NETDEV_MAX_UNIQUE_ERRORS 4
+
+/** Network device statistics */
+struct net_device_stats {
+	/** Count of successful completions */
+	unsigned int good;
+	/** Count of error completions */
+	unsigned int bad;
+	/** Error breakdowns */
+	struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
+};
+
+/**
+ * A network device
+ *
+ * This structure represents a piece of networking hardware.  It has
+ * properties such as a link-layer address and methods for
+ * transmitting and receiving raw packets.
+ *
+ * Note that this structure must represent a generic network device,
+ * not just an Ethernet device.
+ */
+struct net_device {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** List of network devices */
+	struct list_head list;
+	/** List of open network devices */
+	struct list_head open_list;
+	/** Name of this network device */
+	char name[12];
+	/** Underlying hardware device */
+	struct device *dev;
+
+	/** Network device operations */
+	struct net_device_operations *op;
+
+	/** Link-layer protocol */
+	struct ll_protocol *ll_protocol;
+	/** Hardware address
+	 *
+	 * This is an address which is an intrinsic property of the
+	 * hardware, e.g. an address held in EEPROM.
+	 *
+	 * Note that the hardware address may not be the same length
+	 * as the link-layer address.
+	 */
+	uint8_t hw_addr[MAX_HW_ADDR_LEN];
+	/** Link-layer address
+	 *
+	 * This is the current link-layer address assigned to the
+	 * device.  It can be changed at runtime.
+	 */
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
+	/** Link-layer broadcast address */
+	const uint8_t *ll_broadcast;
+
+	/** Current device state
+	 *
+	 * This is the bitwise-OR of zero or more NETDEV_XXX constants.
+	 */
+	unsigned int state;
+	/** Link status code
+	 *
+	 * Zero indicates that the link is up; any other value
+	 * indicates the error preventing link-up.
+	 */
+	int link_rc;
+	/** Maximum packet length
+	 *
+	 * This length includes any link-layer headers.
+	 */
+	size_t max_pkt_len;
+	/** TX packet queue */
+	struct list_head tx_queue;
+	/** RX packet queue */
+	struct list_head rx_queue;
+	/** TX statistics */
+	struct net_device_stats tx_stats;
+	/** RX statistics */
+	struct net_device_stats rx_stats;
+
+	/** Configuration settings applicable to this device */
+	struct generic_settings settings;
+
+	/** Driver private data */
+	void *priv;
+};
+
+/** Network device is open */
+#define NETDEV_OPEN 0x0001
+
+/** Network device interrupts are enabled */
+#define NETDEV_IRQ_ENABLED 0x0002
+
+/** Network device receive queue processing is frozen */
+#define NETDEV_RX_FROZEN 0x0004
+
+/** Link-layer protocol table */
+#define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" )
+
+/** Declare a link-layer protocol */
+#define __ll_protocol  __table_entry ( LL_PROTOCOLS, 01 )
+
+/** Network-layer protocol table */
+#define NET_PROTOCOLS __table ( struct net_protocol, "net_protocols" )
+
+/** Declare a network-layer protocol */
+#define __net_protocol __table_entry ( NET_PROTOCOLS, 01 )
+
+/** A network upper-layer driver */
+struct net_driver {
+	/** Name */
+	const char *name;
+	/** Probe device
+	 *
+	 * @v netdev		Network device
+	 * @ret rc		Return status code
+	 */
+	int ( * probe ) ( struct net_device *netdev );
+	/** Notify of device or link state change
+	 *
+	 * @v netdev		Network device
+	 */
+	void ( * notify ) ( struct net_device *netdev );
+	/** Remove device
+	 *
+	 * @v netdev		Network device
+	 */
+	void ( * remove ) ( struct net_device *netdev );
+};
+
+/** Network driver table */
+#define NET_DRIVERS __table ( struct net_driver, "net_drivers" )
+
+/** Declare a network driver */
+#define __net_driver __table_entry ( NET_DRIVERS, 01 )
+
+/** Network device setting tag magic
+ *
+ * All DHCP option settings are deemed to be valid as network device
+ * settings.  There are also some extra non-DHCP settings (such as
+ * "mac"), which are marked as being valid network device settings by
+ * using a magic tag value.
+ */
+#define NETDEV_SETTING_TAG_MAGIC 0xeb
+
+/**
+ * Construct network device setting tag
+ *
+ * @v id		Unique identifier
+ * @ret tag		Setting tag
+ */
+#define NETDEV_SETTING_TAG( id ) ( ( NETDEV_SETTING_TAG_MAGIC << 24 ) | (id) )
+
+/**
+ * Check if tag is a network device setting tag
+ *
+ * @v tag		Setting tag
+ * @ret is_ours		Tag is a network device setting tag
+ */
+#define IS_NETDEV_SETTING_TAG( tag ) \
+	( ( (tag) >> 24 ) == NETDEV_SETTING_TAG_MAGIC )
+
+/** MAC address setting tag */
+#define NETDEV_SETTING_TAG_MAC NETDEV_SETTING_TAG ( 0x01 )
+
+/** Bus ID setting tag */
+#define NETDEV_SETTING_TAG_BUS_ID NETDEV_SETTING_TAG ( 0x02 )
+
+extern struct list_head net_devices;
+extern struct net_device_operations null_netdev_operations;
+extern struct settings_operations netdev_settings_operations;
+
+/**
+ * Initialise a network device
+ *
+ * @v netdev		Network device
+ * @v op		Network device operations
+ */
+static inline void netdev_init ( struct net_device *netdev,
+				 struct net_device_operations *op ) {
+	netdev->op = op;
+}
+
+/**
+ * Stop using a network device
+ *
+ * @v netdev		Network device
+ *
+ * Drivers should call this method immediately before the final call
+ * to netdev_put().
+ */
+static inline void netdev_nullify ( struct net_device *netdev ) {
+	netdev->op = &null_netdev_operations;
+}
+
+/**
+ * Get printable network device link-layer address
+ *
+ * @v netdev		Network device
+ * @ret name		Link-layer address
+ */
+static inline const char * netdev_addr ( struct net_device *netdev ) {
+	return netdev->ll_protocol->ntoa ( netdev->ll_addr );
+}
+
+/** Iterate over all network devices */
+#define for_each_netdev( netdev ) \
+	list_for_each_entry ( (netdev), &net_devices, list )
+
+/** There exist some network devices
+ *
+ * @ret existence	Existence of network devices
+ */
+static inline int have_netdevs ( void ) {
+	return ( ! list_empty ( &net_devices ) );
+}
+
+/**
+ * Get reference to network device
+ *
+ * @v netdev		Network device
+ * @ret netdev		Network device
+ */
+static inline __attribute__ (( always_inline )) struct net_device *
+netdev_get ( struct net_device *netdev ) {
+	ref_get ( &netdev->refcnt );
+	return netdev;
+}
+
+/**
+ * Drop reference to network device
+ *
+ * @v netdev		Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_put ( struct net_device *netdev ) {
+	ref_put ( &netdev->refcnt );
+}
+
+/**
+ * Get driver private area for this network device
+ *
+ * @v netdev		Network device
+ * @ret priv		Driver private area for this network device
+ */
+static inline __attribute__ (( always_inline )) void *
+netdev_priv ( struct net_device *netdev ) {
+        return netdev->priv;
+}
+
+/**
+ * Get per-netdevice configuration settings block
+ *
+ * @v netdev		Network device
+ * @ret settings	Settings block
+ */
+static inline __attribute__ (( always_inline )) struct settings *
+netdev_settings ( struct net_device *netdev ) {
+	return &netdev->settings.settings;
+}
+
+/**
+ * Initialise a per-netdevice configuration settings block
+ *
+ * @v generics		Generic settings block
+ * @v refcnt		Containing object reference counter, or NULL
+ * @v name		Settings block name
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_settings_init ( struct net_device *netdev ) {
+	generic_settings_init ( &netdev->settings, &netdev->refcnt );
+	netdev->settings.settings.op = &netdev_settings_operations;
+}
+
+/**
+ * Check link state of network device
+ *
+ * @v netdev		Network device
+ * @ret link_up		Link is up
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_link_ok ( struct net_device *netdev ) {
+	return ( netdev->link_rc == 0 );
+}
+
+/**
+ * Check whether or not network device is open
+ *
+ * @v netdev		Network device
+ * @ret is_open		Network device is open
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_is_open ( struct net_device *netdev ) {
+	return ( netdev->state & NETDEV_OPEN );
+}
+
+/**
+ * Check whether or not network device supports interrupts
+ *
+ * @v netdev		Network device
+ * @ret irq_supported	Network device supports interrupts
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_irq_supported ( struct net_device *netdev ) {
+	return ( netdev->op->irq != NULL );
+}
+
+/**
+ * Check whether or not network device interrupts are currently enabled
+ *
+ * @v netdev		Network device
+ * @ret irq_enabled	Network device interrupts are enabled
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_irq_enabled ( struct net_device *netdev ) {
+	return ( netdev->state & NETDEV_IRQ_ENABLED );
+}
+
+/**
+ * Check whether or not network device receive queue processing is frozen
+ *
+ * @v netdev		Network device
+ * @ret rx_frozen	Network device receive queue processing is frozen
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_rx_frozen ( struct net_device *netdev ) {
+	return ( netdev->state & NETDEV_RX_FROZEN );
+}
+
+extern void netdev_link_err ( struct net_device *netdev, int rc );
+extern void netdev_link_down ( struct net_device *netdev );
+extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
+extern void netdev_tx_complete_err ( struct net_device *netdev,
+				 struct io_buffer *iobuf, int rc );
+extern void netdev_tx_complete_next_err ( struct net_device *netdev, int rc );
+extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf );
+extern void netdev_rx_err ( struct net_device *netdev,
+			    struct io_buffer *iobuf, int rc );
+extern void netdev_poll ( struct net_device *netdev );
+extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
+extern struct net_device * alloc_netdev ( size_t priv_size );
+extern int register_netdev ( struct net_device *netdev );
+extern int netdev_open ( struct net_device *netdev );
+extern void netdev_close ( struct net_device *netdev );
+extern void unregister_netdev ( struct net_device *netdev );
+extern void netdev_irq ( struct net_device *netdev, int enable );
+extern struct net_device * find_netdev ( const char *name );
+extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
+						     unsigned int location );
+extern struct net_device * last_opened_netdev ( void );
+extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
+		    struct net_protocol *net_protocol, const void *ll_dest,
+		    const void *ll_source );
+extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
+		    uint16_t net_proto, const void *ll_dest,
+		    const void *ll_source );
+extern void net_poll ( void );
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ *
+ * The packet must currently be in the network device's TX queue.
+ */
+static inline void netdev_tx_complete ( struct net_device *netdev,
+					struct io_buffer *iobuf ) {
+	netdev_tx_complete_err ( netdev, iobuf, 0 );
+}
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev		Network device
+ *
+ * Completes the oldest outstanding packet in the TX queue.
+ */
+static inline void netdev_tx_complete_next ( struct net_device *netdev ) {
+	netdev_tx_complete_next_err ( netdev, 0 );
+}
+
+/**
+ * Mark network device as having link up
+ *
+ * @v netdev		Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_link_up ( struct net_device *netdev ) {
+	netdev_link_err ( netdev, 0 );
+}
+
+/**
+ * Freeze network device receive queue processing
+ *
+ * @v netdev		Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_rx_freeze ( struct net_device *netdev ) {
+	netdev->state |= NETDEV_RX_FROZEN;
+}
+
+/**
+ * Unfreeze network device receive queue processing
+ *
+ * @v netdev		Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_rx_unfreeze ( struct net_device *netdev ) {
+	netdev->state &= ~NETDEV_RX_FROZEN;
+}
+
+#endif /* _IPXE_NETDEVICE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_nap.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_nap.h
new file mode 100644
index 0000000..0c0704b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_nap.h
@@ -0,0 +1,23 @@
+#ifndef _IPXE_NULL_NAP_H
+#define _IPXE_NULL_NAP_H
+
+/** @file
+ *
+ * Null CPU sleeping
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef NAP_NULL
+#define NAP_PREFIX_null
+#else
+#define NAP_PREFIX_null __null_
+#endif
+
+static inline __always_inline void
+NAP_INLINE ( null, cpu_nap ) ( void ) {
+	/* Do nothing */
+}
+
+#endif /* _IPXE_NULL_NAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_sanboot.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_sanboot.h
new file mode 100644
index 0000000..341a9a1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/null_sanboot.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_NULL_SANBOOT_H
+#define _IPXE_NULL_SANBOOT_H
+
+/** @file
+ *
+ * Standard do-nothing sanboot interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef SANBOOT_NULL
+#define SANBOOT_PREFIX_null
+#else
+#define SANBOOT_PREFIX_null __null_
+#endif
+
+#endif /* _IPXE_NULL_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvo.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvo.h
new file mode 100644
index 0000000..995afd7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvo.h
@@ -0,0 +1,52 @@
+#ifndef _IPXE_NVO_H
+#define _IPXE_NVO_H
+
+/** @file
+ *
+ * Non-volatile stored options
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/dhcpopts.h>
+#include <ipxe/settings.h>
+
+struct nvs_device;
+struct refcnt;
+
+/**
+ * A block of non-volatile stored options
+ */
+struct nvo_block {
+	/** Settings block */
+	struct settings settings;
+	/** Underlying non-volatile storage device */
+	struct nvs_device *nvs;
+	/** Address within NVS device */
+	unsigned int address;
+	/** Length of options data */
+	size_t len;
+	/** Option-containing data */
+	void *data;
+	/**
+	 * Resize non-volatile stored option block
+	 *
+	 * @v nvo		Non-volatile options block
+	 * @v len		New size
+	 * @ret rc		Return status code
+	 */
+	int ( * resize ) ( struct nvo_block *nvo, size_t len );
+	/** DHCP options block */
+	struct dhcp_options dhcpopts;
+};
+
+extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
+		       size_t address, size_t len,
+		       int ( * resize ) ( struct nvo_block *nvo, size_t len ),
+		       struct refcnt *refcnt );
+extern int register_nvo ( struct nvo_block *nvo, struct settings *parent );
+extern void unregister_nvo ( struct nvo_block *nvo );
+
+#endif /* _IPXE_NVO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvs.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvs.h
new file mode 100644
index 0000000..4733123
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvs.h
@@ -0,0 +1,68 @@
+#ifndef _IPXE_NVS_H
+#define _IPXE_NVS_H
+
+/** @file
+ *
+ * Non-volatile storage
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** A non-volatile storage device */
+struct nvs_device {
+	/** Word length
+	 *
+	 * This is expressed as the base-2 logarithm of the word
+	 * length in bytes.  A value of 0 therefore translates as
+	 * 8-bit words, and a value of 1 translates as 16-bit words.
+	 */
+	unsigned int word_len_log2;
+	/** Device size (in words) */
+	unsigned int size;
+	/** Data block size (in words)
+	 *
+	 * This is the block size used by the device.  It must be a
+	 * power of two.  Data reads and writes must not cross a block
+	 * boundary.
+	 *
+	 * Many devices allow reads to cross a block boundary, and
+	 * restrict only writes.  For the sake of simplicity, we
+	 * assume that the same restriction applies to both reads and
+	 * writes.
+	 */
+	unsigned int block_size;
+	/** Read data from device
+	 *
+	 * @v nvs		NVS device
+	 * @v address		Address from which to read
+	 * @v data		Data buffer
+	 * @v len		Length of data buffer
+	 * @ret rc		Return status code
+	 *
+	 * Reads may not cross a block boundary.
+	 */
+	int ( * read ) ( struct nvs_device *nvs, unsigned int address,
+			 void *data, size_t len );
+	/** Write data to device
+	 *
+	 * @v nvs		NVS device
+	 * @v address		Address to which to write
+	 * @v data		Data buffer
+	 * @v len		Length of data buffer
+	 * @ret rc		Return status code
+	 *
+	 * Writes may not cross a block boundary.
+	 */
+	int ( * write ) ( struct nvs_device *nvs, unsigned int address,
+			  const void *data, size_t len );
+};
+
+extern int nvs_read ( struct nvs_device *nvs, unsigned int address,
+		      void *data, size_t len );
+extern int nvs_write ( struct nvs_device *nvs, unsigned int address,
+		       const void *data, size_t len );
+
+#endif /* _IPXE_NVS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvsvpd.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvsvpd.h
new file mode 100644
index 0000000..3450e5c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/nvsvpd.h
@@ -0,0 +1,33 @@
+#ifndef _IPXE_NVSVPD_H
+#define _IPXE_NVSVPD_H
+
+/**
+ * @file
+ *
+ * Non-Volatile Storage using Vital Product Data
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/nvs.h>
+#include <ipxe/pcivpd.h>
+
+struct nvo_block;
+struct refcnt;
+
+/** An NVS VPD device */
+struct nvs_vpd_device {
+	/** NVS device */
+	struct nvs_device nvs;
+	/** PCI VPD device */
+	struct pci_vpd vpd;
+};
+
+extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd,
+			  struct pci_device *pci );
+extern void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd,
+			       unsigned int field, struct nvo_block *nvo,
+			       struct refcnt *refcnt );
+
+#endif /* IPXE_NVSVPD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/open.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/open.h
new file mode 100644
index 0000000..a522f0c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/open.h
@@ -0,0 +1,106 @@
+#ifndef _IPXE_OPEN_H
+#define _IPXE_OPEN_H
+
+/** @file
+ *
+ * Data transfer interface opening
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdarg.h>
+#include <ipxe/tables.h>
+#include <ipxe/socket.h>
+
+struct uri;
+struct interface;
+
+/** Location types */
+enum {
+	/** Location is a URI
+	 *
+	 * Parameter list for open() is:
+	 *
+	 * struct uri *uri;
+	 */
+	LOCATION_URI = 1,
+	/** Location is a URI string
+	 *
+	 * Parameter list for open() is:
+	 *
+	 * const char *uri_string;
+	 */
+	LOCATION_URI_STRING,
+	/** Location is a socket
+	 *
+	 * Parameter list for open() is:
+	 *
+	 * int semantics;
+	 * struct sockaddr *peer;
+	 * struct sockaddr *local;
+	 */
+	LOCATION_SOCKET,
+};
+
+/** A URI opener */
+struct uri_opener {
+	/** URI protocol name
+	 *
+	 * This is the "scheme" portion of the URI, e.g. "http" or
+	 * "file".
+	 */
+	const char *scheme;
+	/** Open URI
+	 *
+	 * @v intf		Object interface
+	 * @v uri		URI
+	 * @ret rc		Return status code
+	 */
+	int ( * open ) ( struct interface *intf, struct uri *uri );
+};
+
+/** URI opener table */
+#define URI_OPENERS __table ( struct uri_opener, "uri_openers" )
+
+/** Register a URI opener */
+#define __uri_opener __table_entry ( URI_OPENERS, 01 )
+
+/** A socket opener */
+struct socket_opener {
+	/** Communication semantics (e.g. SOCK_STREAM) */
+	int semantics;
+	/** Address family (e.g. AF_INET) */
+	int family;
+	/** Open socket
+	 *
+	 * @v intf		Object interface
+	 * @v peer		Peer socket address
+	 * @v local		Local socket address, or NULL
+	 * @ret rc		Return status code
+	 */
+	int ( * open ) ( struct interface *intf, struct sockaddr *peer,
+			 struct sockaddr *local );
+};
+
+/** Socket opener table */
+#define SOCKET_OPENERS __table ( struct socket_opener, "socket_openers" )
+
+/** Register a socket opener */
+#define __socket_opener __table_entry ( SOCKET_OPENERS, 01 )
+
+extern struct uri_opener * xfer_uri_opener ( const char *scheme );
+extern int xfer_open_uri ( struct interface *intf, struct uri *uri );
+extern int xfer_open_uri_string ( struct interface *intf,
+				  const char *uri_string );
+extern int xfer_open_named_socket ( struct interface *intf, int semantics,
+				    struct sockaddr *peer, const char *name,
+				    struct sockaddr *local );
+extern int xfer_open_socket ( struct interface *intf, int semantics,
+			      struct sockaddr *peer, struct sockaddr *local );
+extern int xfer_vopen ( struct interface *intf, int type, va_list args );
+extern int xfer_open ( struct interface *intf, int type, ... );
+extern int xfer_vreopen ( struct interface *intf, int type,
+			  va_list args );
+
+#endif /* _IPXE_OPEN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/parseopt.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/parseopt.h
new file mode 100644
index 0000000..eed40b7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/parseopt.h
@@ -0,0 +1,126 @@
+#ifndef _IPXE_PARSEOPT_H
+#define _IPXE_PARSEOPT_H
+
+/** @file
+ *
+ * Command line option parsing
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+
+struct net_device;
+struct image;
+
+/** A command-line option descriptor */
+struct option_descriptor {
+	/** Long option name, if any */
+	const char *longopt;
+	/** Short option name */
+	char shortopt;
+	/** Argument requirement (as for @c struct @c option) */
+	uint8_t has_arg;
+	/** Offset of field within options structure */
+	uint16_t offset;
+	/** Parse option
+	 *
+	 * @v text		Option text
+	 * @v value		Option value to fill in
+	 * @ret rc		Return status code
+	 */
+	int ( * parse ) ( const char *text, void *value );
+};
+
+/**
+ * Construct option parser
+ *
+ * @v _struct		Options structure type
+ * @v _field		Field within options structure
+ * @v _parse		Field type-specific option parser
+ * @ret _parse		Generic option parser
+ */
+#define OPTION_PARSER( _struct, _field, _parse )			      \
+	( ( int ( * ) ( const char *text, void *value ) )		      \
+	  ( ( ( ( typeof ( _parse ) * ) NULL ) ==			      \
+	      ( ( int ( * ) ( const char *text,				      \
+			      typeof ( ( ( _struct * ) NULL )->_field ) * ) ) \
+		NULL ) ) ? _parse : _parse ) )
+
+/**
+ * Construct option descriptor
+ *
+ * @v _longopt		Long option name, if any
+ * @v _shortopt		Short option name, if any
+ * @v _has_arg		Argument requirement
+ * @v _struct		Options structure type
+ * @v _field		Field within options structure
+ * @v _parse		Field type-specific option parser
+ * @ret _option		Option descriptor
+ */
+#define OPTION_DESC( _longopt, _shortopt, _has_arg, _struct, _field, _parse ) \
+	{								      \
+		.longopt = _longopt,					      \
+		.shortopt = _shortopt,					      \
+		.has_arg = _has_arg,					      \
+		.offset = offsetof ( _struct, _field ),			      \
+		.parse = OPTION_PARSER ( _struct, _field, _parse ),	      \
+	}
+
+/** A command descriptor */
+struct command_descriptor {
+	/** Option descriptors */
+	struct option_descriptor *options;
+	/** Number of option descriptors */
+	uint8_t num_options;
+	/** Length of option structure */
+	uint8_t len;
+	/** Minimum number of non-option arguments */
+	uint8_t min_args;
+	/** Maximum number of non-option arguments */
+	uint8_t max_args;
+	/** Command usage
+	 *
+	 * This excludes the literal "Usage:" and the command name,
+	 * which will be prepended automatically.
+	 */
+	const char *usage;
+};
+
+/** No maximum number of arguments */
+#define MAX_ARGUMENTS 0xff
+
+/**
+ * Construct command descriptor
+ *
+ * @v _struct		Options structure type
+ * @v _options		Option descriptor array
+ * @v _check_args	Remaining argument checker
+ * @v _usage		Command usage
+ * @ret _command	Command descriptor
+ */
+#define COMMAND_DESC( _struct, _options, _min_args, _max_args, _usage )	      \
+	{								      \
+		.options = ( ( ( ( typeof ( _options[0] ) * ) NULL ) ==	      \
+			       ( ( struct option_descriptor * ) NULL ) ) ?    \
+			     _options : _options ),			      \
+		.num_options = ( sizeof ( _options ) /			      \
+				 sizeof ( _options[0] ) ),		      \
+		.len = sizeof ( _struct ),				      \
+		.min_args = _min_args,					      \
+		.max_args = _max_args,					      \
+		.usage = _usage,					      \
+	 }
+
+extern int parse_string ( const char *text, const char **value );
+extern int parse_integer ( const char *text, unsigned int *value );
+extern int parse_netdev ( const char *text, struct net_device **netdev );
+extern int parse_image ( const char *text, struct image **image );
+extern int parse_flag ( const char *text __unused, int *flag );
+extern void print_usage ( struct command_descriptor *cmd, char **argv );
+extern int parse_options ( int argc, char **argv,
+			   struct command_descriptor *cmd, void *opts );
+
+#endif /* _IPXE_PARSEOPT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci.h
new file mode 100644
index 0000000..960454d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci.h
@@ -0,0 +1,436 @@
+#ifndef	_IPXE_PCI_H
+#define _IPXE_PCI_H
+
+/*
+ * Support for NE2000 PCI clones added David Monro June 1997
+ * Generalised for other PCI NICs by Ken Yap July 1997
+ * PCI support rewritten by Michael Brown 2006
+ *
+ * Most of this is taken from /usr/src/linux/include/linux/pci.h.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stdint.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+#include <ipxe/pci_io.h>
+#include "pci_ids.h"
+
+/*
+ * PCI constants
+ *
+ */
+
+#define PCI_COMMAND_IO			0x1	/* Enable response in I/O space */
+#define PCI_COMMAND_MEM			0x2	/* Enable response in mem space */
+#define PCI_COMMAND_MASTER		0x4	/* Enable bus mastering */
+
+#define PCI_CACHE_LINE_SIZE		0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER		0x0d	/* 8 bits */
+
+#define PCI_COMMAND_SPECIAL		0x8	/* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE		0x10	/* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20	/* Enable palette snooping */
+#define  PCI_COMMAND_PARITY	0x40	/* Enable parity checking */
+#define  PCI_COMMAND_WAIT 	0x80	/* Enable address/data stepping */
+#define  PCI_COMMAND_SERR	0x100	/* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK	0x200	/* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+
+#define PCI_VENDOR_ID           0x00    /* 16 bits */
+#define PCI_DEVICE_ID           0x02    /* 16 bits */
+#define PCI_COMMAND             0x04    /* 16 bits */
+
+#define PCI_STATUS		0x06	/* 16 bits */
+#define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */
+#define  PCI_STATUS_66MHZ	0x20	/* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK	0x80	/* Accept fast-back to back */
+#define  PCI_STATUS_PARITY	0x100	/* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK	0x600	/* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST	0x000	
+#define  PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define  PCI_STATUS_DEVSEL_SLOW 0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_REVISION            0x08    /* 8 bits  */
+#define PCI_REVISION_ID         0x08    /* 8 bits  */
+#define PCI_CLASS_REVISION      0x08    /* 32 bits  */
+#define PCI_CLASS_CODE          0x0b    /* 8 bits */
+#define PCI_SUBCLASS_CODE       0x0a    /* 8 bits */
+#define PCI_HEADER_TYPE         0x0e    /* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL	0
+#define  PCI_HEADER_TYPE_BRIDGE 1
+#define  PCI_HEADER_TYPE_CARDBUS 2
+
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS		0x28
+#define PCI_SUBSYSTEM_VENDOR_ID	0x2c
+#define PCI_SUBSYSTEM_ID	0x2e  
+
+#define PCI_BASE_ADDRESS_0      0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1      0x14    /* 32 bits */
+#define PCI_BASE_ADDRESS_2      0x18    /* 32 bits */
+#define PCI_BASE_ADDRESS_3      0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4      0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5      0x24    /* 32 bits */
+
+#define PCI_BASE_ADDRESS_SPACE		0x01    /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO	0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY	0x00
+
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK	0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
+#define	PCI_BASE_ADDRESS_MEM_MASK	(~0x0f)
+#define	PCI_BASE_ADDRESS_IO_MASK	(~0x03)
+#define	PCI_ROM_ADDRESS		0x30	/* 32 bits */
+#define	PCI_ROM_ADDRESS_ENABLE	0x01	/* Write 1 to enable ROM,
+					   bits 31..11 are address,
+					   10..2 are reserved */
+
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
+
+#define PCI_INTERRUPT_LINE	0x3c	/* IRQ number (0-15) */
+#define PCI_INTERRUPT_PIN	0x3d	/* IRQ pin on PCI bus (A-D) */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS		0x18	/* Primary bus number */
+#define PCI_SECONDARY_BUS	0x19	/* Secondary bus number */
+#define PCI_SUBORDINATE_BUS	0x1a	/* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER	0x1b	/* Latency timer for secondary interface */
+#define PCI_IO_BASE		0x1c	/* I/O range behind the bridge */
+#define PCI_IO_LIMIT		0x1d
+#define  PCI_IO_RANGE_TYPE_MASK	0x0f	/* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16	0x00
+#define  PCI_IO_RANGE_TYPE_32	0x01
+#define  PCI_IO_RANGE_MASK	~0x0f
+#define PCI_SEC_STATUS		0x1e	/* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE		0x20	/* Memory range behind */
+#define PCI_MEMORY_LIMIT	0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0f
+#define  PCI_MEMORY_RANGE_MASK	~0x0f
+#define PCI_PREF_MEMORY_BASE	0x24	/* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT	0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0f
+#define  PCI_PREF_RANGE_TYPE_32	0x00
+#define  PCI_PREF_RANGE_TYPE_64	0x01
+#define  PCI_PREF_RANGE_MASK	~0x0f
+#define PCI_PREF_BASE_UPPER32	0x28	/* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32	0x2c
+#define PCI_IO_BASE_UPPER16	0x30	/* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16	0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1	0x38	/* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL	0x3e
+#define  PCI_BRIDGE_CTL_PARITY	0x01	/* Enable parity detection on secondary interface */
+#define  PCI_BRIDGE_CTL_SERR	0x02	/* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_NO_ISA	0x04	/* Disable bridging of ISA ports */
+#define  PCI_BRIDGE_CTL_VGA	0x08	/* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT 0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET 0x40	/* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK 0x80	/* Fast Back2Back enabled on secondary interface */
+
+#define PCI_CB_CAPABILITY_LIST	0x14
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID		0	/* Capability ID */
+#define  PCI_CAP_ID_PM		0x01	/* Power Management */
+#define  PCI_CAP_ID_AGP		0x02	/* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD		0x03	/* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
+#define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
+#define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_VNDR	0x09	/* Vendor specific */
+#define  PCI_CAP_ID_EXP		0x10	/* PCI Express */
+#define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
+#define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF		4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC              2       /* PM Capabilities Register */
+#define  PCI_PM_CAP_VER_MASK	0x0007	/* Version */
+#define  PCI_PM_CAP_PME_CLOCK	0x0008	/* PME clock required */
+#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
+#define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization */
+#define  PCI_PM_CAP_AUX_POWER	0x01C0	/* Auxilliary power support mask */
+#define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
+#define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
+#define  PCI_PM_CAP_PME		0x0800	/* PME pin supported */
+#define  PCI_PM_CAP_PME_MASK    0xF800  /* PME Mask of all supported states */
+#define  PCI_PM_CAP_PME_D0      0x0800  /* PME# from D0 */
+#define  PCI_PM_CAP_PME_D1      0x1000  /* PME# from D1 */
+#define  PCI_PM_CAP_PME_D2      0x2000  /* PME# from D2 */
+#define  PCI_PM_CAP_PME_D3      0x4000  /* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3cold  0x8000  /* PME# from D3 (cold) */
+#define PCI_PM_CTRL		4	/* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS	0x8000	/* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS	6	/* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3	0x40	/* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE	0x80	/* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER	7	/* (??) */
+#define PCI_PM_SIZEOF		8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION		2	/* BCD version number */
+#define PCI_AGP_RFU		3	/* Rest of capability flags */
+#define PCI_AGP_STATUS		4	/* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK	0xff000000	/* Maximum number of requests - 1 */
+#define  PCI_AGP_STATUS_SBA	0x0200	/* Sideband addressing supported */
+#define  PCI_AGP_STATUS_64BIT	0x0020	/* 64-bit addressing supported */
+#define  PCI_AGP_STATUS_FW	0x0010	/* FW transfers supported */
+#define  PCI_AGP_STATUS_RATE4	0x0004	/* 4x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE2	0x0002	/* 2x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE1	0x0001	/* 1x transfer rate supported */
+#define PCI_AGP_COMMAND		8	/* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
+#define  PCI_AGP_COMMAND_SBA	0x0200	/* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP	0x0100	/* Allow processing of AGP transactions */
+#define  PCI_AGP_COMMAND_64BIT	0x0020 	/* Allow processing of 64-bit addresses */
+#define  PCI_AGP_COMMAND_FW	0x0010 	/* Force FW transfers */
+#define  PCI_AGP_COMMAND_RATE4	0x0004	/* Use 4x rate */
+#define  PCI_AGP_COMMAND_RATE2	0x0002	/* Use 2x rate */
+#define  PCI_AGP_COMMAND_RATE1	0x0001	/* Use 1x rate */
+#define PCI_AGP_SIZEOF		12
+
+/* Slot Identification */
+
+#define PCI_SID_ESR		2	/* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS	0x1f	/* Number of expansion slots available */
+#define  PCI_SID_ESR_FIC	0x20	/* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR	3	/* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS		2	/* Various flags */
+#define  PCI_MSI_FLAGS_64BIT	0x80	/* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE	0x70	/* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK	0x0e	/* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE	0x01	/* MSI feature enabled */
+#define PCI_MSI_RFU		3	/* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO	4	/* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI	8	/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
+#define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
+
+/* Advanced Error Reporting */
+
+#define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
+#define  PCI_ERR_UNC_TRAIN	0x00000001	/* Training */
+#define  PCI_ERR_UNC_DLP	0x00000010	/* Data Link Protocol */
+#define  PCI_ERR_UNC_POISON_TLP	0x00001000	/* Poisoned TLP */
+#define  PCI_ERR_UNC_FCP	0x00002000	/* Flow Control Protocol */
+#define  PCI_ERR_UNC_COMP_TIME	0x00004000	/* Completion Timeout */
+#define  PCI_ERR_UNC_COMP_ABORT	0x00008000	/* Completer Abort */
+#define  PCI_ERR_UNC_UNX_COMP	0x00010000	/* Unexpected Completion */
+#define  PCI_ERR_UNC_RX_OVER	0x00020000	/* Receiver Overflow */
+#define  PCI_ERR_UNC_MALF_TLP	0x00040000	/* Malformed TLP */
+#define  PCI_ERR_UNC_ECRC	0x00080000	/* ECRC Error Status */
+#define  PCI_ERR_UNC_UNSUP	0x00100000	/* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK	8	/* Uncorrectable Error Mask */
+	/* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER	12	/* Uncorrectable Error Severity */
+	/* Same bits as above */
+#define PCI_ERR_COR_STATUS	16	/* Correctable Error Status */
+#define  PCI_ERR_COR_RCVR	0x00000001	/* Receiver Error Status */
+#define  PCI_ERR_COR_BAD_TLP	0x00000040	/* Bad TLP Status */
+#define  PCI_ERR_COR_BAD_DLLP	0x00000080	/* Bad DLLP Status */
+#define  PCI_ERR_COR_REP_ROLL	0x00000100	/* REPLAY_NUM Rollover */
+#define  PCI_ERR_COR_REP_TIMER	0x00001000	/* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK	20	/* Correctable Error Mask */
+	/* Same bits as above */
+
+/** A PCI device ID list entry */
+struct pci_device_id {
+	/** Name */
+	const char *name;
+	/** PCI vendor ID */
+	uint16_t vendor;
+	/** PCI device ID */
+	uint16_t device;
+	/** Arbitrary driver data */
+	unsigned long driver_data;
+};
+
+/** Match-anything ID */
+#define PCI_ANY_ID 0xffff
+
+/** A PCI device */
+struct pci_device {
+	/** Generic device */
+	struct device dev;
+	/** Memory base
+	 *
+	 * This is the physical address of the first valid memory BAR.
+	 */
+	unsigned long membase;
+	/**
+	 * I/O address
+	 *
+	 * This is the physical address of the first valid I/O BAR.
+	 */
+	unsigned long ioaddr;
+	/** Vendor ID */
+	uint16_t vendor;
+	/** Device ID */
+	uint16_t device;
+	/** Device class */
+	uint32_t class;
+	/** Interrupt number */
+	uint8_t irq;
+	/** Bus, device, and function (bus:dev.fn) number */
+	uint16_t busdevfn;
+	/** Driver for this device */
+	struct pci_driver *driver;
+	/** Driver-private data
+	 *
+	 * Use pci_set_drvdata() and pci_get_drvdata() to access this
+	 * field.
+	 */
+	void *priv;
+	/** Driver device ID */
+	struct pci_device_id *id;
+};
+
+/** A PCI driver */
+struct pci_driver {
+	/** PCI ID table */
+	struct pci_device_id *ids;
+	/** Number of entries in PCI ID table */
+	unsigned int id_count;
+	/**
+	 * Probe device
+	 *
+	 * @v pci	PCI device
+	 * @ret rc	Return status code
+	 */
+	int ( * probe ) ( struct pci_device *pci );
+	/**
+	 * Remove device
+	 *
+	 * @v pci	PCI device
+	 */
+	void ( * remove ) ( struct pci_device *pci );
+};
+
+/** PCI driver table */
+#define PCI_DRIVERS __table ( struct pci_driver, "pci_drivers" )
+
+/** Declare a PCI driver */
+#define __pci_driver __table_entry ( PCI_DRIVERS, 01 )
+
+#define PCI_BUS( busdevfn )		( ( (busdevfn) >> 8 ) & 0xff )
+#define PCI_SLOT( busdevfn )		( ( (busdevfn) >> 3 ) & 0x1f )
+#define PCI_FUNC( busdevfn )		( ( (busdevfn) >> 0 ) & 0x07 )
+#define PCI_BUSDEVFN( bus, slot, func )	\
+	( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) )
+
+#define PCI_BASE_CLASS( class )		( (class) >> 16 )
+#define PCI_SUB_CLASS( class )		( ( (class) >> 8 ) & 0xff )
+#define PCI_PROG_INTF( class )		( (class) & 0xff )
+
+/*
+ * PCI_ROM is used to build up entries in a struct pci_id array.  It
+ * is also parsed by parserom.pl to generate Makefile rules and files
+ * for rom-o-matic.
+ *
+ * PCI_ID can be used to generate entries without creating a
+ * corresponding ROM in the build process.
+ */
+#define PCI_ID( _vendor, _device, _name, _description, _data ) {	\
+	.vendor = _vendor,						\
+	.device = _device,						\
+	.name = _name,							\
+	.driver_data = _data						\
+}
+#define PCI_ROM( _vendor, _device, _name, _description, _data ) \
+	PCI_ID( _vendor, _device, _name, _description, _data )
+
+/** PCI device debug message format */
+#define PCI_FMT "PCI %02x:%02x.%x"
+
+/** PCI device debug message arguments */
+#define PCI_ARGS( pci )							\
+	PCI_BUS ( (pci)->busdevfn ), PCI_SLOT ( (pci)->busdevfn ),	\
+	PCI_FUNC ( (pci)->busdevfn )
+
+extern void adjust_pci_device ( struct pci_device *pci );
+extern unsigned long pci_bar_start ( struct pci_device *pci,
+				     unsigned int reg );
+extern int pci_read_config ( struct pci_device *pci );
+extern int pci_find_driver ( struct pci_device *pci );
+extern int pci_probe ( struct pci_device *pci );
+extern void pci_remove ( struct pci_device *pci );
+extern int pci_find_capability ( struct pci_device *pci, int capability );
+extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
+
+/**
+ * Initialise PCI device
+ *
+ * @v pci		PCI device
+ * @v busdevfn		PCI bus:dev.fn address
+ */
+static inline void pci_init ( struct pci_device *pci, unsigned int busdevfn ) {
+	pci->busdevfn = busdevfn;
+}
+
+/**
+ * Set PCI driver
+ *
+ * @v pci		PCI device
+ * @v driver		PCI driver
+ * @v id		PCI device ID
+ */
+static inline void pci_set_driver ( struct pci_device *pci,
+				    struct pci_driver *driver,
+				    struct pci_device_id *id ) {
+	pci->driver = driver;
+	pci->id = id;
+	pci->dev.driver_name = id->name;
+}
+
+/**
+ * Set PCI driver-private data
+ *
+ * @v pci		PCI device
+ * @v priv		Private data
+ */
+static inline void pci_set_drvdata ( struct pci_device *pci, void *priv ) {
+	pci->priv = priv;
+}
+
+/**
+ * Get PCI driver-private data
+ *
+ * @v pci		PCI device
+ * @ret priv		Private data
+ */
+static inline void * pci_get_drvdata ( struct pci_device *pci ) {
+	return pci->priv;
+}
+
+#endif	/* _IPXE_PCI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_ids.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_ids.h
new file mode 100644
index 0000000..25c7782
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_ids.h
@@ -0,0 +1,351 @@
+#ifndef _IPXE_PCI_IDS_H
+#define _IPXE_PCI_IDS_H
+
+/*
+ *	PCI Class, Vendor and Device IDs
+ *
+ *	Please keep sorted.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED		0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
+
+#define PCI_BASE_CLASS_STORAGE		0x01
+#define PCI_CLASS_STORAGE_SCSI		0x0100
+#define PCI_CLASS_STORAGE_IDE		0x0101
+#define PCI_CLASS_STORAGE_FLOPPY	0x0102
+#define PCI_CLASS_STORAGE_IPI		0x0103
+#define PCI_CLASS_STORAGE_RAID		0x0104
+#define PCI_CLASS_STORAGE_OTHER		0x0180
+
+#define PCI_BASE_CLASS_NETWORK		0x02
+#define PCI_CLASS_NETWORK_ETHERNET	0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
+#define PCI_CLASS_NETWORK_FDDI		0x0202
+#define PCI_CLASS_NETWORK_ATM		0x0203
+#define PCI_CLASS_NETWORK_OTHER		0x0280
+
+#define PCI_BASE_CLASS_DISPLAY		0x03
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_CLASS_DISPLAY_XGA		0x0301
+#define PCI_CLASS_DISPLAY_3D		0x0302
+#define PCI_CLASS_DISPLAY_OTHER		0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA	0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
+#define PCI_CLASS_MULTIMEDIA_PHONE	0x0402
+#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
+
+#define PCI_BASE_CLASS_MEMORY		0x05
+#define PCI_CLASS_MEMORY_RAM		0x0500
+#define PCI_CLASS_MEMORY_FLASH		0x0501
+#define PCI_CLASS_MEMORY_OTHER		0x0580
+
+#define PCI_BASE_CLASS_BRIDGE		0x06
+#define PCI_CLASS_BRIDGE_HOST		0x0600
+#define PCI_CLASS_BRIDGE_ISA		0x0601
+#define PCI_CLASS_BRIDGE_EISA		0x0602
+#define PCI_CLASS_BRIDGE_MC		0x0603
+#define PCI_CLASS_BRIDGE_PCI		0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA		0x0605
+#define PCI_CLASS_BRIDGE_NUBUS		0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS	0x0607
+#define PCI_CLASS_BRIDGE_RACEWAY	0x0608
+#define PCI_CLASS_BRIDGE_OTHER		0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION	0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM	0x0703
+#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
+
+#define PCI_BASE_CLASS_SYSTEM		0x08
+#define PCI_CLASS_SYSTEM_PIC		0x0800
+#define PCI_CLASS_SYSTEM_DMA		0x0801
+#define PCI_CLASS_SYSTEM_TIMER		0x0802
+#define PCI_CLASS_SYSTEM_RTC		0x0803
+#define PCI_CLASS_SYSTEM_PCI_HOTPLUG	0x0804
+#define PCI_CLASS_SYSTEM_OTHER		0x0880
+
+#define PCI_BASE_CLASS_INPUT		0x09
+#define PCI_CLASS_INPUT_KEYBOARD	0x0900
+#define PCI_CLASS_INPUT_PEN		0x0901
+#define PCI_CLASS_INPUT_MOUSE		0x0902
+#define PCI_CLASS_INPUT_SCANNER		0x0903
+#define PCI_CLASS_INPUT_GAMEPORT	0x0904
+#define PCI_CLASS_INPUT_OTHER		0x0980
+
+#define PCI_BASE_CLASS_DOCKING		0x0a
+#define PCI_CLASS_DOCKING_GENERIC	0x0a00
+#define PCI_CLASS_DOCKING_OTHER		0x0a80
+
+#define PCI_BASE_CLASS_PROCESSOR	0x0b
+#define PCI_CLASS_PROCESSOR_386		0x0b00
+#define PCI_CLASS_PROCESSOR_486		0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
+#define PCI_CLASS_PROCESSOR_MIPS	0x0b30
+#define PCI_CLASS_PROCESSOR_CO		0x0b40
+
+#define PCI_BASE_CLASS_SERIAL		0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_ACCESS		0x0c01
+#define PCI_CLASS_SERIAL_SSA		0x0c02
+#define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_FIBER		0x0c04
+#define PCI_CLASS_SERIAL_SMBUS		0x0c05
+
+#define PCI_BASE_CLASS_INTELLIGENT	0x0e
+#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
+
+#define PCI_BASE_CLASS_SATELLITE	0x0f
+#define PCI_CLASS_SATELLITE_TV		0x0f00
+#define PCI_CLASS_SATELLITE_AUDIO	0x0f01
+#define PCI_CLASS_SATELLITE_VOICE	0x0f03
+#define PCI_CLASS_SATELLITE_DATA	0x0f04
+
+#define PCI_BASE_CLASS_CRYPT		0x10
+#define PCI_CLASS_CRYPT_NETWORK		0x1000
+#define PCI_CLASS_CRYPT_ENTERTAINMENT	0x1001
+#define PCI_CLASS_CRYPT_OTHER		0x1080
+
+#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11
+#define PCI_CLASS_SP_DPIO		0x1100
+#define PCI_CLASS_SP_OTHER		0x1180
+
+#define PCI_CLASS_OTHERS		0xff
+
+/* Vendors */
+
+#define PCI_VENDOR_ID_DYNALINK		0x0675
+#define PCI_VENDOR_ID_BERKOM			0x0871
+#define PCI_VENDOR_ID_COMPAQ		0x0e11
+#define PCI_VENDOR_ID_NCR		0x1000
+#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
+#define PCI_VENDOR_ID_ATI		0x1002
+#define PCI_VENDOR_ID_VLSI		0x1004
+#define PCI_VENDOR_ID_ADL		0x1005
+#define PCI_VENDOR_ID_NS		0x100b
+#define PCI_VENDOR_ID_TSENG		0x100c
+#define PCI_VENDOR_ID_WEITEK		0x100e
+#define PCI_VENDOR_ID_DEC		0x1011
+#define PCI_VENDOR_ID_CIRRUS		0x1013
+#define PCI_VENDOR_ID_IBM		0x1014
+#define PCI_VENDOR_ID_COMPEX2		0x101a
+/* pci.ids says "AT&T GIS (NCR)" */
+#define PCI_VENDOR_ID_WD		0x101c
+#define PCI_VENDOR_ID_AMI		0x101e
+#define PCI_VENDOR_ID_AMD		0x1022
+#define PCI_VENDOR_ID_TRIDENT		0x1023
+#define PCI_VENDOR_ID_AI		0x1025
+#define PCI_VENDOR_ID_DELL              0x1028
+#define PCI_VENDOR_ID_MATROX		0x102B
+#define PCI_VENDOR_ID_CT		0x102c
+#define PCI_VENDOR_ID_MIRO		0x1031
+#define PCI_VENDOR_ID_NEC		0x1033
+#define PCI_VENDOR_ID_FD		0x1036
+#define PCI_VENDOR_ID_SIS         	0x1039
+#define PCI_VENDOR_ID_SI		0x1039
+#define PCI_VENDOR_ID_HP		0x103c
+#define PCI_VENDOR_ID_PCTECH		0x1042
+#define PCI_VENDOR_ID_ASUSTEK		0x1043
+#define PCI_VENDOR_ID_DPT		0x1044
+#define PCI_VENDOR_ID_OPTI		0x1045
+#define PCI_VENDOR_ID_ELSA		0x1048
+#define PCI_VENDOR_ID_ELSA		0x1048
+#define PCI_VENDOR_ID_SGS		0x104a
+#define PCI_VENDOR_ID_BUSLOGIC		      0x104B
+#define PCI_VENDOR_ID_TI		0x104c
+#define PCI_VENDOR_ID_SONY		0x104d
+#define PCI_VENDOR_ID_OAK		0x104e
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2		0x1050
+#define PCI_VENDOR_ID_ANIGMA		0x1051
+#define PCI_VENDOR_ID_EFAR		0x1055
+#define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
+#define PCI_VENDOR_ID_PROMISE		0x105a
+#define PCI_VENDOR_ID_N9		0x105d
+#define PCI_VENDOR_ID_UMC		0x1060
+#define PCI_VENDOR_ID_X			0x1061
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_VENDOR_ID_PICOP		0x1066
+#define PCI_VENDOR_ID_APPLE		0x106b
+#define PCI_VENDOR_ID_YAMAHA		0x1073
+#define PCI_VENDOR_ID_NEXGEN		0x1074
+#define PCI_VENDOR_ID_QLOGIC		0x1077
+#define PCI_VENDOR_ID_CYRIX		0x1078
+#define PCI_VENDOR_ID_LEADTEK		0x107d
+#define PCI_VENDOR_ID_INTERPHASE	0x107e
+#define PCI_VENDOR_ID_CONTAQ		0x1080
+#define PCI_VENDOR_ID_FOREX		0x1083
+#define PCI_VENDOR_ID_OLICOM		0x108d
+#define PCI_VENDOR_ID_SUN		0x108e
+#define PCI_VENDOR_ID_CMD		0x1095
+#define PCI_VENDOR_ID_VISION		0x1098
+#define PCI_VENDOR_ID_BROOKTREE		0x109e
+#define PCI_VENDOR_ID_SIERRA		0x10a8
+#define PCI_VENDOR_ID_SGI		0x10a9
+#define PCI_VENDOR_ID_ACC		0x10aa
+#define PCI_VENDOR_ID_WINBOND		0x10ad
+#define PCI_VENDOR_ID_DATABOOK		0x10b3
+#define PCI_VENDOR_ID_PLX		0x10b5
+#define PCI_VENDOR_ID_MADGE		0x10b6
+#define PCI_VENDOR_ID_3COM		0x10b7
+#define PCI_VENDOR_ID_SMC		0x10b8
+#define PCI_VENDOR_ID_SUNDANCE		0x13F0
+#define PCI_VENDOR_ID_AL		0x10b9
+#define PCI_VENDOR_ID_MITSUBISHI	0x10ba
+#define PCI_VENDOR_ID_SURECOM		0x10bd
+#define PCI_VENDOR_ID_NEOMAGIC		0x10c8
+#define PCI_VENDOR_ID_ASP		0x10cd
+#define PCI_VENDOR_ID_MACRONIX		0x10d9
+#define PCI_VENDOR_ID_TCONRAD		0x10da
+#define PCI_VENDOR_ID_CERN		0x10dc
+#define PCI_VENDOR_ID_NVIDIA			0x10de
+#define PCI_VENDOR_ID_IMS		0x10e0
+#define PCI_VENDOR_ID_TEKRAM2		0x10e1
+#define PCI_VENDOR_ID_TUNDRA		0x10e3
+#define PCI_VENDOR_ID_AMCC		0x10e8
+#define PCI_VENDOR_ID_INTERG		0x10ea
+#define PCI_VENDOR_ID_REALTEK		0x10ec
+#define PCI_VENDOR_ID_XILINX		0x10ee
+#define PCI_VENDOR_ID_TRUEVISION	0x10fa
+#define PCI_VENDOR_ID_INIT		0x1101
+#define PCI_VENDOR_ID_CREATIVE		0x1102
+/* duplicate: ECTIVA */
+#define PCI_VENDOR_ID_ECTIVA		0x1102
+/* duplicate: CREATIVE */
+#define PCI_VENDOR_ID_TTI		0x1103
+#define PCI_VENDOR_ID_VIA		0x1106
+#define PCI_VENDOR_ID_VIATEC		0x1106
+#define PCI_VENDOR_ID_SIEMENS           0x110A
+#define PCI_VENDOR_ID_SMC2		0x1113
+#define PCI_VENDOR_ID_VORTEX		0x1119
+#define PCI_VENDOR_ID_EF		0x111a
+#define PCI_VENDOR_ID_IDT		0x111d
+#define PCI_VENDOR_ID_FORE		0x1127
+#define PCI_VENDOR_ID_IMAGINGTECH	0x112f
+#define PCI_VENDOR_ID_PHILIPS		0x1131
+#define PCI_VENDOR_ID_EICON		0x1133
+#define PCI_VENDOR_ID_CYCLONE		0x113c
+#define PCI_VENDOR_ID_ALLIANCE		0x1142
+#define PCI_VENDOR_ID_SYSKONNECT	0x1148
+#define PCI_VENDOR_ID_VMIC		0x114a
+#define PCI_VENDOR_ID_DIGI		0x114f
+#define PCI_VENDOR_ID_MUTECH		0x1159
+#define PCI_VENDOR_ID_XIRCOM		0x115d
+#define PCI_VENDOR_ID_RENDITION		0x1163
+#define PCI_VENDOR_ID_SERVERWORKS	  0x1166
+#define PCI_VENDOR_ID_SBE		0x1176
+#define PCI_VENDOR_ID_TOSHIBA		0x1179
+#define PCI_VENDOR_ID_RICOH		0x1180
+#define	PCI_VENDOR_ID_DLINK		0x1186
+#define PCI_VENDOR_ID_ARTOP		0x1191
+#define PCI_VENDOR_ID_ZEITNET		0x1193
+#define PCI_VENDOR_ID_OMEGA		0x119b
+#define PCI_VENDOR_ID_FUJITSU_ME	0x119e
+#define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
+#define PCI_VENDOR_ID_GALILEO		0x11ab
+#define PCI_VENDOR_ID_LINKSYS		0x11ad
+#define PCI_VENDOR_ID_LITEON		0x11ad
+#define PCI_VENDOR_ID_V3		0x11b0
+#define PCI_VENDOR_ID_NP		0x11bc
+#define PCI_VENDOR_ID_ATT		0x11c1
+#define PCI_VENDOR_ID_SPECIALIX		0x11cb
+#define PCI_VENDOR_ID_AURAVISION	0x11d1
+#define PCI_VENDOR_ID_ANALOG_DEVICES	0x11d4
+#define PCI_VENDOR_ID_IKON		0x11d5
+#define PCI_VENDOR_ID_ZORAN		0x11de
+#define PCI_VENDOR_ID_KINETIC		0x11f4
+#define PCI_VENDOR_ID_COMPEX		0x11f6
+#define PCI_VENDOR_ID_RP		0x11fe
+#define PCI_VENDOR_ID_CYCLADES		0x120e
+#define PCI_VENDOR_ID_ESSENTIAL		0x120f
+#define PCI_VENDOR_ID_O2		0x1217
+#define PCI_VENDOR_ID_3DFX		0x121a
+#define PCI_VENDOR_ID_SIGMADES		0x1236
+#define PCI_VENDOR_ID_CCUBE		0x123f
+#define PCI_VENDOR_ID_AVM		0x1244
+#define PCI_VENDOR_ID_DIPIX		0x1246
+#define PCI_VENDOR_ID_STALLION		0x124d
+#define PCI_VENDOR_ID_OPTIBASE		0x1255
+#define PCI_VENDOR_ID_ESS		0x125d
+#define PCI_VENDOR_ID_HARRIS        	0x1260
+#define PCI_VENDOR_ID_SATSAGEM		0x1267
+#define PCI_VENDOR_ID_HUGHES		0x1273
+#define PCI_VENDOR_ID_ENSONIQ		0x1274
+#define PCI_VENDOR_ID_ROCKWELL		0x127A
+#define PCI_VENDOR_ID_DAVICOM		0x1282
+#define PCI_VENDOR_ID_ITE		0x1283
+/* formerly Platform Tech */
+#define PCI_VENDOR_ID_ESS_OLD		0x1285
+#define PCI_VENDOR_ID_ALTEON		0x12ae
+#define PCI_VENDOR_ID_USR		0x12B9
+#define	PCI_VENDOR_ID_HOLTEK		0x12c3
+#define PCI_SUBVENDOR_ID_CONNECT_TECH			0x12c4
+#define PCI_VENDOR_ID_PICTUREL		0x12c5
+#define PCI_VENDOR_ID_NVIDIA_SGS	0x12d2
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST		0x12E0
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS		0x124D
+#define PCI_VENDOR_ID_AUREAL		0x12eb
+#define PCI_VENDOR_ID_CBOARDS		0x1307
+#define PCI_VENDOR_ID_SIIG		0x131f
+#define PCI_VENDOR_ID_ADMTEK            0x1317
+#define PCI_VENDOR_ID_DOMEX		0x134a
+#define PCI_VENDOR_ID_QUATECH		0x135C
+#define PCI_VENDOR_ID_SEALEVEL		0x135e
+#define PCI_VENDOR_ID_HYPERCOPE		0x1365
+#define PCI_VENDOR_ID_KAWASAKI		0x136b
+#define PCI_VENDOR_ID_LMC		0x1376
+#define PCI_VENDOR_ID_NETGEAR		0x1385
+#define PCI_VENDOR_ID_APPLICOM		0x1389
+#define PCI_VENDOR_ID_MOXA		0x1393
+#define PCI_VENDOR_ID_CCD		0x1397
+#define PCI_VENDOR_ID_MICROGATE		0x13c0
+#define PCI_VENDOR_ID_3WARE		0x13C1
+#define PCI_VENDOR_ID_ABOCOM		0x13D1
+#define PCI_VENDOR_ID_CMEDIA		0x13f6
+#define PCI_VENDOR_ID_LAVA		0x1407
+#define PCI_VENDOR_ID_TIMEDIA		0x1409
+#define PCI_VENDOR_ID_OXSEMI		0x1415
+#define PCI_VENDOR_ID_AIRONET		0x14b9
+#define PCI_VENDOR_ID_MYRICOM		0x14c1
+#define PCI_VENDOR_ID_TITAN		0x14D2
+#define PCI_VENDOR_ID_PANACOM		0x14d4
+#define PCI_VENDOR_ID_BROADCOM		0x14e4
+#define PCI_VENDOR_ID_SYBA		0x1592
+#define PCI_VENDOR_ID_MORETON		0x15aa
+#define PCI_VENDOR_ID_ZOLTRIX		0x15b0
+#define PCI_VENDOR_ID_PDC		0x15e9
+#define PCI_VENDOR_ID_FSC		0x1734
+#define PCI_VENDOR_ID_SYMPHONY		0x1c1c
+#define PCI_VENDOR_ID_TEKRAM		0x1de1
+#define PCI_VENDOR_ID_3DLABS		0x3d3d
+#define PCI_VENDOR_ID_AVANCE		0x4005
+#define PCI_VENDOR_ID_AKS		0x416c
+#define PCI_VENDOR_ID_NETVIN		0x4a14
+#define PCI_VENDOR_ID_S3		0x5333
+#define PCI_VENDOR_ID_DCI		0x6666
+#define PCI_VENDOR_ID_GENROCO		0x5555
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_SUBVENDOR_ID_COMPUTONE	0x8e0e
+#define PCI_VENDOR_ID_KTI		0x8e2e
+#define PCI_VENDOR_ID_ADAPTEC		0x9004
+#define PCI_VENDOR_ID_ADAPTEC2		0x9005
+#define PCI_VENDOR_ID_ATRONICS		0x907f
+#define PCI_VENDOR_ID_HOLTEK2		0x9412
+#define PCI_VENDOR_ID_NETMOS		0x9710
+#define PCI_SUBVENDOR_ID_EXSYS		0xd84d
+#define PCI_VENDOR_ID_TIGERJET		0xe159
+#define PCI_VENDOR_ID_ARK		0xedd8
+
+#endif /* _IPXE_PCI_IDS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_io.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_io.h
new file mode 100644
index 0000000..7368cf4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pci_io.h
@@ -0,0 +1,124 @@
+#ifndef _IPXE_PCI_IO_H
+#define _IPXE_PCI_IO_H
+
+/** @file
+ *
+ * PCI I/O API
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * Calculate static inline PCI I/O API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define PCIAPI_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a PCI I/O API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_PCIAPI( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( PCIAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline PCI I/O API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_PCIAPI_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <ipxe/efi/efi_pci_api.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/pci_io.h>
+
+/**
+ * Determine number of PCI buses within system
+ *
+ * @ret num_bus		Number of buses
+ */
+int pci_num_bus ( void );
+
+/**
+ * Read byte from PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+int pci_read_config_byte ( struct pci_device *pci, unsigned int where,
+			   uint8_t *value );
+
+/**
+ * Read 16-bit word from PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+int pci_read_config_word ( struct pci_device *pci, unsigned int where,
+			   uint16_t *value );
+
+/**
+ * Read 32-bit dword from PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
+			    uint32_t *value );
+
+/**
+ * Write byte to PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
+			    uint8_t value );
+
+/**
+ * Write 16-bit word to PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+int pci_write_config_word ( struct pci_device *pci, unsigned int where,
+			    uint16_t value );
+
+/**
+ * Write 32-bit dword to PCI configuration space
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
+			     uint32_t value );
+
+#endif /* _IPXE_PCI_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcibackup.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcibackup.h
new file mode 100644
index 0000000..b9f55cf
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcibackup.h
@@ -0,0 +1,33 @@
+#ifndef _IPXE_PCIBACKUP_H
+#define _IPXE_PCIBACKUP_H
+
+/** @file
+ *
+ * PCI configuration space backup and restoration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** A PCI configuration space backup */
+struct pci_config_backup {
+	uint32_t dwords[64];
+};
+
+/** PCI configuration space backup exclusion list end marker */
+#define PCI_CONFIG_BACKUP_EXCLUDE_END 0xff
+
+/** Define a PCI configuration space backup exclusion list */
+#define PCI_CONFIG_BACKUP_EXCLUDE(...) \
+	{ __VA_ARGS__, PCI_CONFIG_BACKUP_EXCLUDE_END }
+
+extern void pci_backup ( struct pci_device *pci,
+			 struct pci_config_backup *backup,
+			 const uint8_t *exclude );
+extern void pci_restore ( struct pci_device *pci,
+			  struct pci_config_backup *backup,
+			  const uint8_t *exclude );
+
+#endif /* _IPXE_PCIBACKUP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcivpd.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcivpd.h
new file mode 100644
index 0000000..0abf8a9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/pcivpd.h
@@ -0,0 +1,181 @@
+#ifndef _IPXE_PCIVPD_H
+#define _IPXE_PCIVPD_H
+
+/**
+ * @file
+ *
+ * PCI Vital Product Data
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/isapnp.h>
+#include <ipxe/pci.h>
+
+/** PCI VPD address register */
+#define PCI_VPD_ADDRESS 0x02
+
+/** PCI VPD write flag */
+#define PCI_VPD_FLAG 0x8000
+
+/** PCI VPD data register */
+#define PCI_VPD_DATA 0x04
+
+/** A PCI VPD field */
+struct pci_vpd_field {
+	/** Keyword */
+	uint16_t keyword;
+	/** Length */
+	uint8_t len;
+} __attribute__ (( packed ));
+
+/** Maximum PCI VPD field length */
+#define PCI_VPD_MAX_LEN 0xff
+
+/** Construct PCI VPD field descriptor
+ *
+ * @v tag		ISAPnP tag
+ * @v keyword1		First character of keyword
+ * @v keyword2		Second character of keyword
+ * @ret field		VPD field descriptor
+ */
+#define PCI_VPD_FIELD( tag, keyword1, keyword2 ) \
+	( ( (tag) << 16 ) | ( (keyword2) << 8 ) | ( (keyword1) << 0 ) )
+
+/** Construct PCI VPD whole-tag field descriptor
+ *
+ * @v tag		ISAPnP tag
+ * @ret field		VPD field descriptor
+ */
+#define PCI_VPD_WHOLE_TAG_FIELD( tag ) PCI_VPD_FIELD ( (tag), '\0', '\0' )
+
+/** Extract PCI VPD ISAPnP tag
+ *
+ * @v field		VPD field descriptor
+ * @ret tag		ISAPnP tag
+ */
+#define PCI_VPD_TAG( field ) ( (field) >> 16 )
+
+/** Extract PCI VPD keyword
+ *
+ * @v field		VPD field descriptor
+ * @ret keyword		Keyword
+ */
+#define PCI_VPD_KEYWORD( field ) ( cpu_to_le16 ( (field) & 0xffff ) )
+
+/** PCI VPD field debug message format */
+#define PCI_VPD_FIELD_FMT "%c%c"
+
+/** PCI VPD field debug message arguments */
+#define PCI_VPD_FIELD_ARGS( field ) \
+	( (field) >> 0 ), ( (field) >> 8 )
+
+/** PCI VPD Read-Only field tag */
+#define PCI_VPD_TAG_RO 0x90
+
+/** PCI VPD Read-Write field tag */
+#define PCI_VPD_TAG_RW 0x91
+
+/** PCI VPD Card Name field descriptor */
+#define PCI_VPD_FIELD_NAME PCI_VPD_WHOLE_TAG_FIELD ( ISAPNP_TAG_ANSISTR )
+
+/** PCI VPD Part Number field descriptor */
+#define PCI_VPD_FIELD_PN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'N' )
+
+/** PCI VPD Engineering Change Level field descriptor */
+#define PCI_VPD_FIELD_EC PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'E', 'C' )
+
+/** PCI VPD Fabric Geography field descriptor */
+#define PCI_VPD_FIELD_FG PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'F', 'G' )
+
+/** PCI VPD Location field descriptor */
+#define PCI_VPD_FIELD_LC PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'L', 'C' )
+
+/** PCI VPD Manufacturer ID field descriptor */
+#define PCI_VPD_FIELD_MN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'M', 'N' )
+
+/** PCI VPD PCI Geography field descriptor */
+#define PCI_VPD_FIELD_PG PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'G' )
+
+/** PCI VPD Serial Number field descriptor */
+#define PCI_VPD_FIELD_SN PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'S', 'N' )
+
+/** PCI VPD Extended Capability field descriptor */
+#define PCI_VPD_FIELD_CP PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'C', 'P' )
+
+/** PCI VPD Checksum and Reserved field descriptor */
+#define PCI_VPD_FIELD_RV PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'R', 'V' )
+
+/** PCI VPD Asset Tag field descriptor */
+#define PCI_VPD_FIELD_YA PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'Y', 'A' )
+
+/** PCI VPD Remaining Read/Write Area field descriptor */
+#define PCI_VPD_FIELD_RW PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'R', 'W' )
+
+/** Maximum wait for PCI VPD (in ms) */
+#define PCI_VPD_MAX_WAIT_MS 100
+
+/** PCI VPD cache */
+struct pci_vpd_cache {
+	/** Address */
+	int address;
+	/** Data */
+	uint32_t data;
+};
+
+/** PCI VPD */
+struct pci_vpd {
+	/** PCI device */
+	struct pci_device *pci;
+	/** VPD capability offset */
+	int cap;
+	/** Read cache */
+	struct pci_vpd_cache cache;
+};
+
+/**
+ * Check for presence of PCI VPD
+ *
+ * @v vpd		PCI VPD
+ * @ret is_present	VPD is present
+ */
+static inline __attribute__ (( always_inline )) int
+pci_vpd_is_present ( struct pci_vpd *vpd ) {
+	return ( vpd->cap != 0 );
+}
+
+/**
+ * Check if PCI VPD read cache is valid
+ *
+ * @v vpd		PCI VPD
+ * @ret is_valid	Read cache is valid
+ */
+static inline __attribute__ (( always_inline )) int
+pci_vpd_cache_is_valid ( struct pci_vpd *vpd ) {
+	return ( vpd->cache.address >= 0 );
+}
+
+/**
+ * Invalidate PCI VPD read cache
+ *
+ * @v vpd		PCI VPD
+ */
+static inline __attribute__ (( always_inline )) void
+pci_vpd_invalidate_cache ( struct pci_vpd *vpd ) {
+	vpd->cache.address = -1;
+}
+
+extern int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci );
+extern int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address,
+			  void *buf, size_t len );
+extern int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address,
+			   const void *buf, size_t len );
+extern int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
+			  unsigned int *address, size_t *len );
+extern int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field,
+			    size_t len, unsigned int *address );
+
+#endif /* _IPXE_PCIVPD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/posix_io.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/posix_io.h
new file mode 100644
index 0000000..11f3bb5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/posix_io.h
@@ -0,0 +1,87 @@
+#ifndef _IPXE_POSIX_IO_H
+#define _IPXE_POSIX_IO_H
+
+/** @file
+ *
+ * POSIX-like I/O
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+
+/** Minimum file descriptor that will ever be allocated */
+#define POSIX_FD_MIN ( 1 )
+
+/** Maximum file descriptor that will ever be allocated */
+#define POSIX_FD_MAX ( 31 )
+
+/** File descriptor set as used for select() */
+typedef uint32_t fd_set;
+
+extern int open ( const char *uri_string );
+extern ssize_t read_user ( int fd, userptr_t buffer,
+			   off_t offset, size_t len );
+extern int select ( fd_set *readfds, int wait );
+extern ssize_t fsize ( int fd );
+extern int close ( int fd );
+
+/**
+ * Zero a file descriptor set
+ *
+ * @v set		File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_ZERO ( fd_set *set ) {
+	*set = 0;
+}
+
+/**
+ * Set a bit within a file descriptor set
+ *
+ * @v fd		File descriptor
+ * @v set		File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_SET ( int fd, fd_set *set ) {
+	*set |= ( 1 << fd );
+}
+
+/**
+ * Clear a bit within a file descriptor set
+ *
+ * @v fd		File descriptor
+ * @v set		File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_CLR ( int fd, fd_set *set ) {
+	*set &= ~( 1 << fd );
+}
+
+/**
+ * Test a bit within a file descriptor set
+ *
+ * @v fd		File descriptor
+ * @v set		File descriptor set
+ * @ret is_set		Corresponding bit is set
+ */
+static inline __attribute__ (( always_inline )) int
+FD_ISSET ( int fd, fd_set *set ) {
+	return ( *set & ( 1 << fd ) );
+}
+
+/**
+ * Read data from file
+ *
+ * @v fd		File descriptor
+ * @v buf		Data buffer
+ * @v len		Maximum length to read
+ * @ret len		Actual length read, or negative error number
+ */
+static inline ssize_t read ( int fd, void *buf, size_t len ) {
+	return read_user ( fd, virt_to_user ( buf ), 0, len );
+}
+
+#endif /* _IPXE_POSIX_IO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/process.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/process.h
new file mode 100644
index 0000000..45c2af6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/process.h
@@ -0,0 +1,91 @@
+#ifndef _IPXE_PROCESS_H
+#define _IPXE_PROCESS_H
+
+/** @file
+ *
+ * Processes
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/tables.h>
+
+/** A process */
+struct process {
+	/** List of processes */
+	struct list_head list;
+	/**
+	 * Single-step the process
+	 *
+	 * This method should execute a single step of the process.
+	 * Returning from this method is isomorphic to yielding the
+	 * CPU to another process.
+	 */
+	void ( * step ) ( struct process *process );
+	/** Reference counter
+	 *
+	 * If this interface is not part of a reference-counted
+	 * object, this field may be NULL.
+	 */
+	struct refcnt *refcnt;
+};
+
+extern void process_add ( struct process *process );
+extern void process_del ( struct process *process );
+extern void step ( void );
+
+/**
+ * Initialise process without adding to process list
+ *
+ * @v process		Process
+ * @v step		Process' step() method
+ */
+static inline __attribute__ (( always_inline )) void
+process_init_stopped ( struct process *process,
+		       void ( * step ) ( struct process *process ),
+		       struct refcnt *refcnt ) {
+	INIT_LIST_HEAD ( &process->list );
+	process->step = step;
+	process->refcnt = refcnt;
+}
+
+/**
+ * Initialise process and add to process list
+ *
+ * @v process		Process
+ * @v step		Process' step() method
+ */
+static inline __attribute__ (( always_inline )) void
+process_init ( struct process *process,
+	       void ( * step ) ( struct process *process ),
+	       struct refcnt *refcnt ) {
+	process_init_stopped ( process, step, refcnt );
+	process_add ( process );
+}
+
+/**
+ * Check if process is running
+ *
+ * @v process		Process
+ * @ret running		Process is running
+ */
+static inline __attribute__ (( always_inline )) int
+process_running ( struct process *process ) {
+	return ( ! list_empty ( &process->list ) );
+}
+
+/** Permanent process table */
+#define PERMANENT_PROCESSES __table ( struct process, "processes" )
+
+/**
+ * Declare a permanent process
+ *
+ * Permanent processes will be automatically added to the process list
+ * at initialisation time.
+ */
+#define __permanent_process __table_entry ( PERMANENT_PROCESSES, 01 )
+
+#endif /* _IPXE_PROCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/profile.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/profile.h
new file mode 100644
index 0000000..60dd53a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/profile.h
@@ -0,0 +1,80 @@
+#ifndef _IPXE_PROFILE_H
+#define _IPXE_PROFILE_H
+
+/** @file
+ *
+ * Profiling
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/**
+ * A data structure for storing profiling information
+ */
+union profiler {
+	/** Timestamp (in CPU-specific "ticks") */
+	uint64_t timestamp;
+	/** Registers returned by rdtsc.
+	 *
+	 * This part should really be architecture-specific code.
+	 */
+	struct {
+		uint32_t eax;
+		uint32_t edx;
+	} rdtsc;
+};
+
+/**
+ * Static per-object profiler, for use with simple_profile()
+ */
+static union profiler simple_profiler;
+
+/**
+ * Perform profiling
+ *
+ * @v profiler		Profiler data structure
+ * @ret delta		Elapsed ticks since last call to profile().
+ *
+ * Call profile() both before and after the code you wish to measure.
+ * The "after" call will return the measurement.  For example:
+ *
+ * @code
+ *
+ *     profile ( &profiler );
+ *     ... do something here ...
+ *     printf ( "It took %ld ticks to execute\n", profile ( &profiler ) );
+ *
+ * @endcode
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+profile ( union profiler *profiler ) {
+	uint64_t last_timestamp = profiler->timestamp;
+
+	__asm__ __volatile__ ( "rdtsc" :
+			       "=a" ( profiler->rdtsc.eax ),
+			       "=d" ( profiler->rdtsc.edx ) );
+	return ( profiler->timestamp - last_timestamp );
+}
+
+/**
+ * Perform profiling
+ *
+ * @ret delta		Elapsed ticks since last call to profile().
+ *
+ * When you only need one profiler, you can avoid the hassle of
+ * creating your own @c profiler data structure by using
+ * simple_profile() instead.
+ *
+ * simple_profile() is equivalent to profile(&simple_profiler), where
+ * @c simple_profiler is a @c profiler data structure that is static
+ * to each object which includes @c profile.h.
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+simple_profile ( void ) {
+	return profile ( &simple_profiler );
+}
+
+#endif /* _IPXE_PROFILE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/rarp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rarp.h
new file mode 100644
index 0000000..f84301a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rarp.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_RARP_H
+#define _IPXE_RARP_H
+
+/** @file
+ *
+ * Reverse Address Resolution Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/netdevice.h>
+
+extern struct net_protocol rarp_protocol __net_protocol;
+
+#endif /* _IPXE_RARP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/rc80211.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rc80211.h
new file mode 100644
index 0000000..eac6bc9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rc80211.h
@@ -0,0 +1,19 @@
+#ifndef _IPXE_RC80211_H
+#define _IPXE_RC80211_H
+
+/** @file
+ *
+ * Rate-control algorithm prototype for 802.11.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net80211_device;
+struct rc80211_ctx;
+
+struct rc80211_ctx * rc80211_init ( struct net80211_device *dev );
+void rc80211_update_tx ( struct net80211_device *dev, int retries, int rc );
+void rc80211_update_rx ( struct net80211_device *dev, int retry, u16 rate );
+void rc80211_free ( struct rc80211_ctx *ctx );
+
+#endif /* _IPXE_RC80211_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/refcnt.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/refcnt.h
new file mode 100644
index 0000000..0e8b865
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/refcnt.h
@@ -0,0 +1,114 @@
+#ifndef _IPXE_REFCNT_H
+#define _IPXE_REFCNT_H
+
+/** @file
+ *
+ * Reference counting
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <assert.h>
+
+/**
+ * A reference counter
+ *
+ * This data structure is designed to be embedded within a
+ * reference-counted object.
+ *
+ * Reference-counted objects are freed when their reference count
+ * drops below zero.  This means that a freshly allocated-and-zeroed
+ * reference-counted object will be freed on the first call to
+ * ref_put().
+ */
+struct refcnt {
+	/** Current reference count
+	 *
+	 * When this count is decremented below zero, the free()
+	 * method will be called.
+	 */
+	int count;
+	/** Free containing object
+	 *
+	 * This method is called when the reference count is
+	 * decremented below zero.
+	 *
+	 * If this method is left NULL, the standard library free()
+	 * function will be called.  The upshot of this is that you
+	 * may omit the free() method if the @c refcnt object is the
+	 * first element of your reference-counted struct.
+	 */
+	void ( * free ) ( struct refcnt *refcnt );
+};
+
+/**
+ * Initialise a reference counter
+ *
+ * @v refcnt		Reference counter
+ * @v free		Freeing function
+ */
+static inline __attribute__ (( always_inline )) void
+ref_init ( struct refcnt *refcnt,
+	   void ( * free ) ( struct refcnt *refcnt ) ) {
+	refcnt->free = free;
+}
+
+/**
+ * Initialise a reference counter
+ *
+ * @v refcnt		Reference counter
+ * @v free		Free containing object
+ */
+#define ref_init( refcnt, free ) do {					\
+	if ( __builtin_constant_p ( (free) ) && ( (free) == NULL ) ) {	\
+		/* Skip common case of no initialisation required */	\
+	} else {							\
+		ref_init ( (refcnt), (free) );				\
+	}								\
+	} while ( 0 )
+
+/**
+ * Initialise a static reference counter
+ *
+ * @v free_fn		Free containing object
+ */
+#define REF_INIT( free_fn ) {						\
+		.free = free_fn,					\
+	}
+
+extern void ref_increment ( struct refcnt *refcnt );
+extern void ref_decrement ( struct refcnt *refcnt );
+
+/**
+ * Get additional reference to object
+ *
+ * @v refcnt		Reference counter, or NULL
+ * @ret refcnt		Reference counter
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+#define ref_get( refcnt ) ( {						\
+	if ( refcnt )							\
+		assert ( (refcnt)->count >= 0 );			\
+	ref_increment ( refcnt );					\
+	(refcnt); } )
+
+/**
+ * Drop reference to object
+ *
+ * @v refcnt		Reference counter, or NULL
+ * @ret refcnt		Reference counter
+ *
+ * If @c refcnt is NULL, no action is taken.
+ */
+#define ref_put( refcnt ) do {						\
+	if ( refcnt )							\
+		assert ( (refcnt)->count >= 0 );			\
+	ref_decrement ( refcnt );					\
+	} while ( 0 )
+
+extern void ref_no_free ( struct refcnt *refcnt );
+
+#endif /* _IPXE_REFCNT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/resolv.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/resolv.h
new file mode 100644
index 0000000..d9868a5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/resolv.h
@@ -0,0 +1,51 @@
+#ifndef _IPXE_RESOLV_H
+#define _IPXE_RESOLV_H
+
+/** @file
+ *
+ * Name resolution
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/interface.h>
+#include <ipxe/tables.h>
+
+struct sockaddr;
+
+/** A name resolver */
+struct resolver {
+	/** Name of this resolver (e.g. "DNS") */
+	const char *name;
+	/** Start name resolution
+	 *
+	 * @v resolv		Name resolution interface
+	 * @v name		Name to resolve
+	 * @v sa		Socket address to complete
+	 * @ret rc		Return status code
+	 */
+	int ( * resolv ) ( struct interface *resolv, const char *name,
+			   struct sockaddr *sa );
+};
+
+/** Numeric resolver priority */
+#define RESOLV_NUMERIC 01
+
+/** Normal resolver priority */
+#define RESOLV_NORMAL 02
+
+/** Resolvers table */
+#define RESOLVERS __table ( struct resolver, "resolvers" )
+
+/** Register as a name resolver */
+#define __resolver( resolv_order ) __table_entry ( RESOLVERS, resolv_order )
+
+extern void resolv_done ( struct interface *intf, struct sockaddr *sa );
+#define resolv_done_TYPE( object_type ) \
+	typeof ( void ( object_type, struct sockaddr *sa ) )
+
+extern int resolv ( struct interface *resolv, const char *name,
+		    struct sockaddr *sa );
+
+#endif /* _IPXE_RESOLV_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/retry.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/retry.h
new file mode 100644
index 0000000..87f69a5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/retry.h
@@ -0,0 +1,111 @@
+#ifndef _IPXE_RETRY_H
+#define _IPXE_RETRY_H
+
+/** @file
+ *
+ * Retry timers
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+
+/** Default timeout value */
+#define DEFAULT_MIN_TIMEOUT ( TICKS_PER_SEC / 4 )
+
+/** Limit after which the timeout will be deemed permanent */
+#define DEFAULT_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
+
+/** A retry timer */
+struct retry_timer {
+	/** List of active timers */
+	struct list_head list;
+	/** Timer is currently running */
+	unsigned int running;
+	/** Timeout value (in ticks) */
+	unsigned long timeout;
+	/** Minimum timeout value (in ticks)
+	 *
+	 * A value of zero means "use default timeout."
+	 */
+	unsigned long min_timeout;
+	/** Maximum timeout value before failure (in ticks)
+	 *
+	 * A value of zero means "use default timeout."
+	 */
+	unsigned long max_timeout;
+	/** Start time (in ticks) */
+	unsigned long start;
+	/** Retry count */
+	unsigned int count;
+	/** Timer expired callback
+	 *
+	 * @v timer	Retry timer
+	 * @v fail	Failure indicator
+	 *
+	 * The timer will already be stopped when this method is
+	 * called.  The failure indicator will be True if the retry
+	 * timeout has already exceeded @c MAX_TIMEOUT.
+	 */
+	void ( * expired ) ( struct retry_timer *timer, int over );
+	/** Reference counter
+	 *
+	 * If this interface is not part of a reference-counted
+	 * object, this field may be NULL.
+	 */
+	struct refcnt *refcnt;
+};
+
+/**
+ * Initialise a timer
+ *
+ * @v timer		Retry timer
+ * @v expired		Timer expired callback
+ * @v refcnt		Reference counter, or NULL
+ */
+static inline __attribute__ (( always_inline )) void
+timer_init ( struct retry_timer *timer,
+	     void ( * expired ) ( struct retry_timer *timer, int over ),
+	     struct refcnt *refcnt ) {
+	timer->expired = expired;
+	timer->refcnt = refcnt;
+}
+
+/**
+ * Initialise a static timer
+ *
+ * @v expired_fn	Timer expired callback
+ */
+#define TIMER_INIT( expired_fn ) {			\
+		.expired = (expired_fn),		\
+	}
+
+extern void start_timer ( struct retry_timer *timer );
+extern void start_timer_fixed ( struct retry_timer *timer,
+				unsigned long timeout );
+extern void stop_timer ( struct retry_timer *timer );
+
+/**
+ * Start timer with no delay
+ *
+ * @v timer		Retry timer
+ *
+ * This starts the timer running with a zero timeout value.
+ */
+static inline void start_timer_nodelay ( struct retry_timer *timer ) {
+	start_timer_fixed ( timer, 0 );
+}
+
+/**
+ * Test to see if timer is currently running
+ *
+ * @v timer		Retry timer
+ * @ret running		Non-zero if timer is running
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+timer_running ( struct retry_timer *timer ) {
+	return ( timer->running );
+}
+
+#endif /* _IPXE_RETRY_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/rotate.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rotate.h
new file mode 100644
index 0000000..745d84e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rotate.h
@@ -0,0 +1,29 @@
+#ifndef _IPXE_ROTATE_H
+#define _IPXE_ROTATE_H
+
+/** @file
+ *
+ * Bit operations
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
+        return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
+}
+
+static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) {
+        return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) );
+}
+
+static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) {
+        return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) );
+}
+
+static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) {
+        return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
+}
+
+#endif /* _IPXE_ROTATE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/rsa.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rsa.h
new file mode 100644
index 0000000..a080f9f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/rsa.h
@@ -0,0 +1,12 @@
+#ifndef _IPXE_RSA_H
+#define _IPXE_RSA_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct pubkey_algorithm;
+
+extern struct pubkey_algorithm rsa_algorithm;
+
+#include "crypto/axtls/crypto.h"
+
+#endif /* _IPXE_RSA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/sanboot.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sanboot.h
new file mode 100644
index 0000000..913282e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sanboot.h
@@ -0,0 +1,93 @@
+#ifndef _IPXE_SANBOOT_H
+#define _IPXE_SANBOOT_H
+
+/** @file
+ *
+ * iPXE sanboot API
+ *
+ * The sanboot API provides methods for hooking, unhooking,
+ * describing, and booting from SAN devices.
+ *
+ * The standard methods (readl()/writel() etc.) do not strictly check
+ * the type of the address parameter; this is because traditional
+ * usage does not necessarily provide the correct pointer type.  For
+ * example, code written for ISA devices at fixed I/O addresses (such
+ * as the keyboard controller) tend to use plain integer constants for
+ * the address parameter.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/api.h>
+#include <config/sanboot.h>
+
+struct uri;
+
+/**
+ * Calculate static inline sanboot API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define SANBOOT_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( SANBOOT_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a sanboot API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_SANBOOT( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( SANBOOT_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline sanboot API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_SANBOOT_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( SANBOOT_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent sanboot API headers */
+#include <ipxe/null_sanboot.h>
+
+/* Include all architecture-dependent sanboot API headers */
+#include <bits/sanboot.h>
+
+/**
+ * Hook SAN device
+ *
+ * @v uri		URI
+ * @v drive		Requested drive number
+ * @ret drive		Assigned drive number, or negative error
+ */
+int san_hook ( struct uri *uri, unsigned int drive );
+
+/**
+ * Unhook SAN device
+ *
+ * @v drive		Drive number
+ */
+void san_unhook ( unsigned int drive );
+
+/**
+ * Attempt to boot from a SAN device
+ *
+ * @v drive		Drive number
+ * @ret rc		Return status code
+ */
+int san_boot ( unsigned int drive );
+
+/**
+ * Describe SAN device for SAN-booted operating system
+ *
+ * @v drive		Drive number
+ * @ret rc		Return status code
+ */
+int san_describe ( unsigned int drive );
+
+#endif /* _IPXE_SANBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/script.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/script.h
new file mode 100644
index 0000000..33420da
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/script.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_SCRIPT_H
+#define _IPXE_SCRIPT_H
+
+/** @file
+ *
+ * iPXE scripts
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/image.h>
+
+extern struct image_type script_image_type __image_type ( PROBE_NORMAL );
+
+#endif /* _IPXE_SCRIPT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/scsi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/scsi.h
new file mode 100644
index 0000000..6dfb7f1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/scsi.h
@@ -0,0 +1,310 @@
+#ifndef _IPXE_SCSI_H
+#define _IPXE_SCSI_H
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/interface.h>
+
+/** @file
+ *
+ * SCSI devices
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Maximum block for READ/WRITE (10) commands */
+#define SCSI_MAX_BLOCK_10 0xffffffffULL
+
+/**
+ * @defgroup scsiops SCSI operation codes
+ * @{
+ */
+
+#define SCSI_OPCODE_READ_10		0x28	/**< READ (10) */
+#define SCSI_OPCODE_READ_16		0x88	/**< READ (16) */
+#define SCSI_OPCODE_WRITE_10		0x2a	/**< WRITE (10) */
+#define SCSI_OPCODE_WRITE_16		0x8a	/**< WRITE (16) */
+#define SCSI_OPCODE_READ_CAPACITY_10	0x25	/**< READ CAPACITY (10) */
+#define SCSI_OPCODE_SERVICE_ACTION_IN	0x9e	/**< SERVICE ACTION IN */
+#define SCSI_SERVICE_ACTION_READ_CAPACITY_16 0x10 /**< READ CAPACITY (16) */
+#define SCSI_OPCODE_TEST_UNIT_READY	0x00	/**< TEST UNIT READY */
+
+/** @} */
+
+/**
+ * @defgroup scsiflags SCSI flags
+ * @{
+ */
+
+#define SCSI_FL_FUA_NV		0x02	/**< Force unit access to NVS */
+#define SCSI_FL_FUA		0x08	/**< Force unit access */
+#define SCSI_FL_DPO		0x10	/**< Disable cache page out */
+
+/** @} */
+
+/**
+ * @defgroup scsicdbs SCSI command data blocks
+ * @{
+ */
+
+/** A SCSI "READ (10)" CDB */
+struct scsi_cdb_read_10 {
+	/** Opcode (0x28) */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Start address
+	 *
+	 * This is a logical block number, in big-endian order.
+	 */
+	uint32_t lba;
+	/** Group number */
+	uint8_t group;
+	/** Transfer length
+	 *
+	 * This is a logical block count, in big-endian order.
+	 */
+	uint16_t len;
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** A SCSI "READ (16)" CDB */
+struct scsi_cdb_read_16 {
+	/** Opcode (0x88) */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Start address
+	 *
+	 * This is a logical block number, in big-endian order.
+	 */
+	uint64_t lba;
+	/** Transfer length
+	 *
+	 * This is a logical block count, in big-endian order.
+	 */
+	uint32_t len;
+	/** Group number */
+	uint8_t group;
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** A SCSI "WRITE (10)" CDB */
+struct scsi_cdb_write_10 {
+	/** Opcode (0x2a) */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Start address
+	 *
+	 * This is a logical block number, in big-endian order.
+	 */
+	uint32_t lba;
+	/** Group number */
+	uint8_t group;
+	/** Transfer length
+	 *
+	 * This is a logical block count, in big-endian order.
+	 */
+	uint16_t len;
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** A SCSI "WRITE (16)" CDB */
+struct scsi_cdb_write_16 {
+	/** Opcode (0x8a) */
+	uint8_t opcode;
+	/** Flags */
+	uint8_t flags;
+	/** Start address
+	 *
+	 * This is a logical block number, in big-endian order.
+	 */
+	uint64_t lba;
+	/** Transfer length
+	 *
+	 * This is a logical block count, in big-endian order.
+	 */
+	uint32_t len;
+	/** Group number */
+	uint8_t group;
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** A SCSI "READ CAPACITY (10)" CDB */
+struct scsi_cdb_read_capacity_10 {
+	/** Opcode (0x25) */
+	uint8_t opcode;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** Logical block address
+	 *
+	 * Applicable only if the PMI bit is set.
+	 */
+	uint32_t lba;
+	/** Reserved */
+	uint8_t reserved_b[3];
+	/** Control byte */
+	uint8_t control;	
+} __attribute__ (( packed ));
+
+/** SCSI "READ CAPACITY (10)" parameter data */
+struct scsi_capacity_10 {
+	/** Maximum logical block number */
+	uint32_t lba;
+	/** Block length in bytes */
+	uint32_t blksize;
+} __attribute__ (( packed ));
+
+/** A SCSI "READ CAPACITY (16)" CDB */
+struct scsi_cdb_read_capacity_16 {
+	/** Opcode (0x9e) */
+	uint8_t opcode;
+	/** Service action */
+	uint8_t service_action;
+	/** Logical block address
+	 *
+	 * Applicable only if the PMI bit is set.
+	 */
+	uint64_t lba;
+	/** Transfer length
+	 *
+	 * This is the size of the data-in buffer, in bytes.
+	 */
+	uint32_t len;
+	/** Reserved */
+	uint8_t reserved;
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** SCSI "READ CAPACITY (16)" parameter data */
+struct scsi_capacity_16 {
+	/** Maximum logical block number */
+	uint64_t lba;
+	/** Block length in bytes */
+	uint32_t blksize;
+	/** Reserved */
+	uint8_t reserved[20];
+} __attribute__ (( packed ));
+
+/** A SCSI "TEST UNIT READY" CDB */
+struct scsi_cdb_test_unit_ready {
+	/** Opcode (0x00) */
+	uint8_t opcode;
+	/** Reserved */
+	uint8_t reserved[4];
+	/** Control byte */
+	uint8_t control;
+} __attribute__ (( packed ));
+
+/** A SCSI Command Data Block */
+union scsi_cdb {
+	struct scsi_cdb_read_10 read10;
+	struct scsi_cdb_read_16 read16;
+	struct scsi_cdb_write_10 write10;
+	struct scsi_cdb_write_16 write16;
+	struct scsi_cdb_read_capacity_10 readcap10;
+	struct scsi_cdb_read_capacity_16 readcap16;
+	struct scsi_cdb_test_unit_ready testready;
+	unsigned char bytes[16];
+};
+
+/** printf() format for dumping a scsi_cdb */
+#define SCSI_CDB_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
+			"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+
+/** printf() parameters for dumping a scsi_cdb */
+#define SCSI_CDB_DATA(cdb)						  \
+	(cdb).bytes[0], (cdb).bytes[1], (cdb).bytes[2], (cdb).bytes[3],	  \
+	(cdb).bytes[4], (cdb).bytes[5], (cdb).bytes[6], (cdb).bytes[7],	  \
+	(cdb).bytes[8], (cdb).bytes[9], (cdb).bytes[10], (cdb).bytes[11], \
+	(cdb).bytes[12], (cdb).bytes[13], (cdb).bytes[14], (cdb).bytes[15]
+
+/** @} */
+
+/** A SCSI LUN
+ *
+ * This is a four-level LUN as specified by SAM-2, in big-endian
+ * order.
+ */
+struct scsi_lun {
+	uint16_t u16[4];
+}  __attribute__ (( packed ));
+
+/** printf() format for dumping a scsi_lun */
+#define SCSI_LUN_FORMAT "%04x-%04x-%04x-%04x"
+
+/** printf() parameters for dumping a scsi_lun */
+#define SCSI_LUN_DATA(lun)						  \
+	ntohs ( (lun).u16[0] ), ntohs ( (lun).u16[1] ),			  \
+	ntohs ( (lun).u16[2] ), ntohs ( (lun).u16[3] )
+
+/** A SCSI command information unit */
+struct scsi_cmd {
+	/** LUN */
+	struct scsi_lun lun;
+	/** CDB for this command */
+	union scsi_cdb cdb;
+	/** Data-out buffer (may be NULL) */
+	userptr_t data_out;
+	/** Data-out buffer length
+	 *
+	 * Must be zero if @c data_out is NULL
+	 */
+	size_t data_out_len;
+	/** Data-in buffer (may be NULL) */
+	userptr_t data_in;
+	/** Data-in buffer length
+	 *
+	 * Must be zero if @c data_in is NULL
+	 */
+	size_t data_in_len;
+};
+
+/** SCSI sense data */
+struct scsi_sns {
+	/** Response code */
+	uint8_t code;
+	/** Reserved */
+	uint8_t reserved;
+	/** Sense key */
+	uint8_t key;
+	/** Information */
+	uint32_t info;
+};
+
+/** SCSI sense key mask */
+#define SCSI_SENSE_KEY_MASK 0x0f
+
+/** A SCSI response information unit */
+struct scsi_rsp {
+	/** SCSI status code */
+	uint8_t status;
+	/** Data overrun (or negative underrun) */
+	ssize_t overrun;
+	/** Autosense data (if any) */
+	struct scsi_sns sense;
+};
+
+extern int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun );
+
+extern int scsi_command ( struct interface *control, struct interface *data,
+			  struct scsi_cmd *command );
+#define scsi_command_TYPE( object_type )				\
+	typeof ( int ( object_type, struct interface *data,		\
+		       struct scsi_cmd *command ) )
+
+extern void scsi_response ( struct interface *intf, struct scsi_rsp *response );
+#define scsi_response_TYPE( object_type ) \
+	typeof ( void ( object_type, struct scsi_rsp *response ) )
+
+extern int scsi_open ( struct interface *block, struct interface *scsi,
+		       struct scsi_lun *lun );
+
+#endif /* _IPXE_SCSI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/sec80211.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sec80211.h
new file mode 100644
index 0000000..59ca3eb
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sec80211.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _IPXE_SEC80211_H
+#define _IPXE_SEC80211_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <errno.h>
+
+/** @file
+ *
+ * Definitions for general secured-network routines.
+ */
+
+int sec80211_detect ( struct io_buffer *iob,
+		      enum net80211_security_proto *secprot,
+		      enum net80211_crypto_alg *crypt );
+
+int sec80211_detect_ie ( int is_rsn, u8 *start, u8 *end,
+			 enum net80211_security_proto *secprot,
+			 enum net80211_crypto_alg *crypt );
+u8 * sec80211_find_rsn ( union ieee80211_ie *ie, void *ie_end,
+			 int *is_rsn, u8 **end );
+
+int sec80211_install ( struct net80211_crypto **which,
+		       enum net80211_crypto_alg crypt,
+		       const void *key, int len, const void *rsc );
+
+u32 sec80211_rsn_get_crypto_desc ( enum net80211_crypto_alg crypt, int rsnie );
+u32 sec80211_rsn_get_akm_desc ( enum net80211_security_proto secprot,
+				int rsnie );
+enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt ( u32 desc );
+
+#endif /* _IPXE_SEC80211_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/segment.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/segment.h
new file mode 100644
index 0000000..37bed0e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/segment.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_SEGMENT_H
+#define _IPXE_SEGMENT_H
+
+/**
+ * @file
+ *
+ * Executable image segments
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/uaccess.h>
+
+extern int prep_segment ( userptr_t segment, size_t filesz, size_t memsz );
+
+#endif /* _IPXE_SEGMENT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/serial.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/serial.h
new file mode 100644
index 0000000..c16e56a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/serial.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_SERIAL_H
+#define _IPXE_SERIAL_H
+
+/** @file
+ *
+ * Serial driver functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern void serial_putc ( int ch );
+extern int serial_getc ( void );
+extern int serial_ischar ( void );
+
+#endif /* _IPXE_SERIAL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings.h
new file mode 100644
index 0000000..0f1ec5b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings.h
@@ -0,0 +1,393 @@
+#ifndef _IPXE_SETTINGS_H
+#define _IPXE_SETTINGS_H
+
+/** @file
+ *
+ * Configuration settings
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/tables.h>
+#include <ipxe/list.h>
+#include <ipxe/refcnt.h>
+
+struct settings;
+struct in_addr;
+union uuid;
+
+/** A setting */
+struct setting {
+	/** Name
+	 *
+	 * This is the human-readable name for the setting.
+	 */
+	const char *name;
+	/** Description */
+	const char *description;
+	/** Setting type
+	 *
+	 * This identifies the type of setting (e.g. string, IPv4
+	 * address, etc.).
+	 */
+	struct setting_type *type;
+	/** Setting tag, if applicable
+	 *
+	 * The setting tag is a numerical description of the setting
+	 * (such as a DHCP option number, or an SMBIOS structure and
+	 * field number).
+	 *
+	 * Users can construct tags for settings that are not
+	 * explicitly known to iPXE using the generic syntax for
+	 * numerical settings.  For example, the setting name "60"
+	 * will be interpreted as referring to DHCP option 60 (the
+	 * vendor class identifier).
+	 *
+	 * This creates a potential for namespace collisions, since
+	 * the interpretation of the numerical description will vary
+	 * according to the settings block.  When a user attempts to
+	 * fetch a generic numerical setting, we need to ensure that
+	 * only the intended settings block interprets the numerical
+	 * description.  (For example, we do not want to attempt to
+	 * retrieve the subnet mask from SMBIOS, or the system UUID
+	 * from DHCP.)
+	 *
+	 * This potential problem is resolved by allowing the setting
+	 * tag to include a "magic" value indicating the
+	 * interpretation to be placed upon the numerical description.
+	 */
+	unsigned int tag;
+};
+
+/** Configuration setting table */
+#define SETTINGS __table ( struct setting, "settings" )
+
+/** Declare a configuration setting */
+#define __setting( setting_order ) __table_entry ( SETTINGS, setting_order )
+
+/** @defgroup setting_order Setting ordering
+ * @{
+ */
+
+#define SETTING_NETDEV		01 /**< Network device settings */
+#define SETTING_NETDEV_EXTRA	02 /**< Network device additional settings */
+#define SETTING_IPv4		03 /**< IPv4 settings */
+#define SETTING_IPv4_EXTRA	04 /**< IPv4 additional settings */
+#define SETTING_BOOT		05 /**< Generic boot settings */
+#define SETTING_BOOT_EXTRA	06 /**< Generic boot additional settings */
+#define SETTING_SANBOOT		07 /**< SAN boot settings */
+#define SETTING_SANBOOT_EXTRA	08 /**< SAN boot additional settings */
+#define SETTING_HOST		09 /**< Host identity settings */
+#define SETTING_HOST_EXTRA	10 /**< Host identity additional settings */
+#define SETTING_AUTH		11 /**< Authentication settings */
+#define SETTING_AUTH_EXTRA	12 /**< Authentication additional settings */
+#define SETTING_MISC		13 /**< Miscellaneous settings */
+
+/** @} */
+
+/** Settings block operations */
+struct settings_operations {
+	/** Check applicability of setting
+	 *
+	 * @v settings		Settings block
+	 * @v setting		Setting
+	 * @ret applies		Setting applies within this settings block
+	 */
+	int ( * applies ) ( struct settings *settings,
+			    struct setting *setting );
+	/** Store value of setting
+	 *
+	 * @v settings		Settings block
+	 * @v setting		Setting to store
+	 * @v data		Setting data, or NULL to clear setting
+	 * @v len		Length of setting data
+	 * @ret rc		Return status code
+	 */
+	int ( * store ) ( struct settings *settings, struct setting *setting,
+			  const void *data, size_t len );
+	/** Fetch value of setting
+	 *
+	 * @v settings		Settings block
+	 * @v setting		Setting to fetch
+	 * @v data		Buffer to fill with setting data
+	 * @v len		Length of buffer
+	 * @ret len		Length of setting data, or negative error
+	 *
+	 * The actual length of the setting will be returned even if
+	 * the buffer was too small.
+	 */
+	int ( * fetch ) ( struct settings *settings, struct setting *setting,
+			  void *data, size_t len );
+	/** Clear settings block
+	 *
+	 * @v settings		Settings block
+	 */
+	void ( * clear ) ( struct settings *settings );
+};
+
+/** A settings block */
+struct settings {
+	/** Reference counter */
+	struct refcnt *refcnt;
+	/** Name */
+	const char *name;
+	/** Tag magic
+	 *
+	 * This value will be ORed in to any numerical tags
+	 * constructed by parse_setting_name().
+	 */
+	unsigned int tag_magic;
+	/** Parent settings block */
+	struct settings *parent;
+	/** Sibling settings blocks */
+	struct list_head siblings;
+	/** Child settings blocks */
+	struct list_head children;
+	/** Settings block operations */
+	struct settings_operations *op;
+};
+
+/**
+ * A setting type
+ *
+ * This represents a type of setting (e.g. string, IPv4 address,
+ * etc.).
+ */
+struct setting_type {
+	/** Name
+	 *
+	 * This is the name exposed to the user (e.g. "string").
+	 */
+	const char *name;
+	/** Parse and set value of setting
+	 *
+	 * @v settings		Settings block
+	 * @v setting		Setting to store
+	 * @v value		Formatted setting data
+	 * @ret rc		Return status code
+	 */
+	int ( * storef ) ( struct settings *settings, struct setting *setting,
+			   const char *value );
+	/** Fetch and format value of setting
+	 *
+	 * @v settings		Settings block
+	 * @v setting		Setting to fetch
+	 * @v buf		Buffer to contain formatted value
+	 * @v len		Length of buffer
+	 * @ret len		Length of formatted value, or negative error
+	 */
+	int ( * fetchf ) ( struct settings *settings, struct setting *setting,
+			   char *buf, size_t len );
+};
+
+/** Configuration setting type table */
+#define SETTING_TYPES __table ( struct setting_type, "setting_types" )
+
+/** Declare a configuration setting type */
+#define __setting_type __table_entry ( SETTING_TYPES, 01 )
+
+/**
+ * A settings applicator
+ *
+ */
+struct settings_applicator {
+	/** Apply updated settings
+	 *
+	 * @ret rc		Return status code
+	 */
+	int ( * apply ) ( void );
+};
+
+/** Settings applicator table */
+#define SETTINGS_APPLICATORS \
+	__table ( struct settings_applicator, "settings_applicators" )
+
+/** Declare a settings applicator */
+#define __settings_applicator __table_entry ( SETTINGS_APPLICATORS, 01 )
+
+/**
+ * A generic settings block
+ *
+ */
+struct generic_settings {
+	/** Settings block */
+	struct settings settings;
+	/** List of generic settings */
+	struct list_head list;
+};
+
+extern struct settings_operations generic_settings_operations;
+extern int generic_settings_store ( struct settings *settings,
+				    struct setting *setting,
+				    const void *data, size_t len );
+extern int generic_settings_fetch ( struct settings *settings,
+				    struct setting *setting,
+				    void *data, size_t len );
+extern void generic_settings_clear ( struct settings *settings );
+
+extern int register_settings ( struct settings *settings,
+			       struct settings *parent, const char *name );
+extern void unregister_settings ( struct settings *settings );
+
+extern int setting_applies ( struct settings *settings,
+			     struct setting *setting );
+extern int store_setting ( struct settings *settings, struct setting *setting,
+			   const void *data, size_t len );
+extern int fetch_setting ( struct settings *settings, struct setting *setting,
+			   void *data, size_t len );
+extern struct settings * fetch_setting_origin ( struct settings *settings,
+						struct setting *setting );
+extern int fetch_setting_len ( struct settings *settings,
+			       struct setting *setting );
+extern int fetch_string_setting ( struct settings *settings,
+				  struct setting *setting,
+				  char *data, size_t len );
+extern int fetch_string_setting_copy ( struct settings *settings,
+				       struct setting *setting,
+				       char **data );
+extern int fetch_ipv4_array_setting ( struct settings *settings,
+				      struct setting *setting,
+				      struct in_addr *inp,
+				      unsigned int count );
+extern int fetch_ipv4_setting ( struct settings *settings,
+				struct setting *setting, struct in_addr *inp );
+extern int fetch_int_setting ( struct settings *settings,
+			       struct setting *setting, long *value );
+extern int fetch_uint_setting ( struct settings *settings,
+				struct setting *setting,
+				unsigned long *value );
+extern long fetch_intz_setting ( struct settings *settings,
+				 struct setting *setting );
+extern unsigned long fetch_uintz_setting ( struct settings *settings,
+					   struct setting *setting );
+extern int fetch_uuid_setting ( struct settings *settings,
+				struct setting *setting, union uuid *uuid );
+extern void clear_settings ( struct settings *settings );
+extern int setting_cmp ( struct setting *a, struct setting *b );
+
+extern const char * settings_name ( struct settings *settings );
+extern struct settings * find_settings ( const char *name );
+extern struct setting * find_setting ( const char *name );
+
+extern int setting_name ( struct settings *settings, struct setting *setting,
+			  char *buf, size_t len );
+extern int storef_setting ( struct settings *settings,
+			    struct setting *setting,
+			    const char *value );
+extern int storef_named_setting ( const char *name, const char *value );
+extern int fetchf_named_setting ( const char *name, char *name_buf,
+				  size_t name_len, char *value_buf,
+				  size_t value_len );
+extern char * expand_settings ( const char *string );
+
+extern struct setting_type setting_type_string __setting_type;
+extern struct setting_type setting_type_ipv4 __setting_type;
+extern struct setting_type setting_type_int8 __setting_type;
+extern struct setting_type setting_type_int16 __setting_type;
+extern struct setting_type setting_type_int32 __setting_type;
+extern struct setting_type setting_type_uint8 __setting_type;
+extern struct setting_type setting_type_uint16 __setting_type;
+extern struct setting_type setting_type_uint32 __setting_type;
+extern struct setting_type setting_type_hex __setting_type;
+extern struct setting_type setting_type_uuid __setting_type;
+
+extern struct setting ip_setting __setting ( SETTING_IPv4 );
+extern struct setting netmask_setting __setting ( SETTING_IPv4 );
+extern struct setting gateway_setting __setting ( SETTING_IPv4 );
+extern struct setting dns_setting __setting ( SETTING_IPv4_EXTRA );
+extern struct setting hostname_setting __setting ( SETTING_HOST );
+extern struct setting filename_setting __setting ( SETTING_BOOT );
+extern struct setting root_path_setting __setting ( SETTING_SANBOOT );
+extern struct setting username_setting __setting ( SETTING_AUTH );
+extern struct setting password_setting __setting ( SETTING_AUTH );
+extern struct setting priority_setting __setting ( SETTING_MISC );
+extern struct setting uuid_setting __setting ( SETTING_HOST );
+extern struct setting next_server_setting __setting ( SETTING_BOOT );
+extern struct setting mac_setting __setting ( SETTING_NETDEV );
+extern struct setting busid_setting __setting ( SETTING_NETDEV );
+
+/**
+ * Initialise a settings block
+ *
+ * @v settings		Settings block
+ * @v op		Settings block operations
+ * @v refcnt		Containing object reference counter, or NULL
+ * @v tag_magic		Tag magic
+ */
+static inline void settings_init ( struct settings *settings,
+				   struct settings_operations *op,
+				   struct refcnt *refcnt,
+				   unsigned int tag_magic ) {
+	INIT_LIST_HEAD ( &settings->siblings );
+	INIT_LIST_HEAD ( &settings->children );
+	settings->op = op;
+	settings->refcnt = refcnt;
+	settings->tag_magic = tag_magic;
+}
+
+/**
+ * Initialise a settings block
+ *
+ * @v generics		Generic settings block
+ * @v refcnt		Containing object reference counter, or NULL
+ */
+static inline void generic_settings_init ( struct generic_settings *generics,
+					   struct refcnt *refcnt ) {
+	settings_init ( &generics->settings, &generic_settings_operations,
+			refcnt, 0 );
+	INIT_LIST_HEAD ( &generics->list );
+}
+
+/**
+ * Delete setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to delete
+ * @ret rc		Return status code
+ */
+static inline int delete_setting ( struct settings *settings,
+				   struct setting *setting ) {
+	return store_setting ( settings, setting, NULL, 0 );
+}
+
+/**
+ * Fetch and format value of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v type		Settings type
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+static inline int fetchf_setting ( struct settings *settings,
+				   struct setting *setting,
+				   char *buf, size_t len ) {
+	return setting->type->fetchf ( settings, setting, buf, len );
+}
+
+/**
+ * Delete named setting
+ *
+ * @v name		Name of setting
+ * @ret rc		Return status code
+ */
+static inline int delete_named_setting ( const char *name ) {
+	return storef_named_setting ( name, NULL );
+}
+
+/**
+ * Check existence of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @ret exists		Setting exists
+ */
+static inline int setting_exists ( struct settings *settings,
+				   struct setting *setting ) {
+	return ( fetch_setting_len ( settings, setting ) >= 0 );
+}
+
+#endif /* _IPXE_SETTINGS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings_ui.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings_ui.h
new file mode 100644
index 0000000..5f7be30
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/settings_ui.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_SETTINGS_UI_H
+#define _IPXE_SETTINGS_UI_H
+
+/** @file
+ *
+ * Option configuration console
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct settings;
+
+extern int settings_ui ( struct settings *settings ) __nonnull;
+
+#endif /* _IPXE_SETTINGS_UI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/sha1.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sha1.h
new file mode 100644
index 0000000..9b6f551
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/sha1.h
@@ -0,0 +1,24 @@
+#ifndef _IPXE_SHA1_H
+#define _IPXE_SHA1_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include "crypto/axtls/crypto.h"
+
+struct digest_algorithm;
+
+#define SHA1_CTX_SIZE sizeof ( SHA1_CTX )
+#define SHA1_DIGEST_SIZE SHA1_SIZE
+
+extern struct digest_algorithm sha1_algorithm;
+
+/* SHA1-wrapping functions defined in sha1extra.c: */
+
+void prf_sha1 ( const void *key, size_t key_len, const char *label,
+		const void *data, size_t data_len, void *prf, size_t prf_len );
+
+void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
+		   const void *salt, size_t salt_len,
+		   int iterations, void *key, size_t key_len );
+
+#endif /* _IPXE_SHA1_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/shell.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/shell.h
new file mode 100644
index 0000000..faa32f4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/shell.h
@@ -0,0 +1,36 @@
+#ifndef _IPXE_SHELL_H
+#define _IPXE_SHELL_H
+
+/** @file
+ *
+ * Minimal command shell
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Shell stop states */
+enum shell_stop_state {
+	/** Continue processing */
+	SHELL_CONTINUE = 0,
+	/**
+	 * Stop processing current command line
+	 *
+	 * This is the stop state entered by commands that change the flow
+	 * of execution, such as "goto".
+	 */
+	SHELL_STOP_COMMAND = 1,
+	/**
+	 * Stop processing commands
+	 *
+	 * This is the stop state entered by commands that terminate
+	 * the flow of execution, such as "exit".
+	 */
+	SHELL_STOP_COMMAND_SEQUENCE = 2,
+};
+
+extern void shell_stop ( int stop );
+extern int shell_stopped ( int stop );
+extern int shell ( void );
+
+#endif /* _IPXE_SHELL_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/smbios.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/smbios.h
new file mode 100644
index 0000000..fcf149e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/smbios.h
@@ -0,0 +1,162 @@
+#ifndef _IPXE_SMBIOS_H
+#define _IPXE_SMBIOS_H
+
+/** @file
+ *
+ * System Management BIOS
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/api.h>
+#include <config/general.h>
+#include <ipxe/uaccess.h>
+
+/**
+ * Provide an SMBIOS API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_SMBIOS( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( SMBIOS_PREFIX_ ## _subsys, _api_func, _func )
+
+/* Include all architecture-independent SMBIOS API headers */
+#include <ipxe/efi/efi_smbios.h>
+#include <ipxe/linux/linux_smbios.h>
+
+/* Include all architecture-dependent SMBIOS API headers */
+#include <bits/smbios.h>
+
+/** Signature for SMBIOS entry point */
+#define SMBIOS_SIGNATURE \
+        ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) )
+
+/**
+ * SMBIOS entry point
+ *
+ * This is the single table which describes the list of SMBIOS
+ * structures.  It is located by scanning through the BIOS segment.
+ */
+struct smbios_entry {
+	/** Signature
+	 *
+	 * Must be equal to SMBIOS_SIGNATURE
+	 */
+	uint32_t signature;
+	/** Checksum */
+	uint8_t checksum;
+	/** Length */
+	uint8_t len;
+	/** Major version */
+	uint8_t major;
+	/** Minor version */
+	uint8_t minor;
+	/** Maximum structure size */
+	uint16_t max;
+	/** Entry point revision */
+	uint8_t revision;
+	/** Formatted area */
+	uint8_t formatted[5];
+	/** DMI Signature */
+	uint8_t dmi_signature[5];
+	/** DMI checksum */
+	uint8_t dmi_checksum;
+	/** Structure table length */
+	uint16_t smbios_len;
+	/** Structure table address */
+	uint32_t smbios_address;
+	/** Number of SMBIOS structures */
+	uint16_t smbios_count;
+	/** BCD revision */
+	uint8_t bcd_revision;
+} __attribute__ (( packed ));
+
+/** An SMBIOS structure header */
+struct smbios_header {
+	/** Type */
+	uint8_t type;
+	/** Length */
+	uint8_t len;
+	/** Handle */
+	uint16_t handle;
+} __attribute__ (( packed ));
+
+/** SMBIOS structure descriptor */
+struct smbios_structure {
+	/** Copy of SMBIOS structure header */
+	struct smbios_header header;
+	/** Offset of structure within SMBIOS */
+	size_t offset;
+	/** Length of strings section */
+	size_t strings_len;
+};
+
+/** SMBIOS system information structure */
+struct smbios_system_information {
+	/** SMBIOS structure header */
+	struct smbios_header header;
+	/** Manufacturer string */
+	uint8_t manufacturer;
+	/** Product string */
+	uint8_t product;
+	/** Version string */
+	uint8_t version;
+	/** Serial number string */
+	uint8_t serial;
+	/** UUID */
+	uint8_t uuid[16];
+	/** Wake-up type */
+	uint8_t wakeup;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure type */
+#define SMBIOS_TYPE_SYSTEM_INFORMATION 1
+
+/** SMBIOS enclosure information structure */
+struct smbios_enclosure_information {
+	/** SMBIOS structure header */
+	struct smbios_header header;
+	/** Manufacturer string */
+	uint8_t manufacturer;
+	/** Type string */
+	uint8_t type;
+	/** Version string */
+	uint8_t version;
+	/** Serial number string */
+	uint8_t serial;
+	/** Asset tag */
+	uint8_t asset_tag;
+} __attribute__ (( packed ));
+
+/** SMBIOS enclosure information structure type */
+#define SMBIOS_TYPE_ENCLOSURE_INFORMATION 3
+
+/**
+ * SMBIOS entry point descriptor
+ *
+ * This contains the information from the SMBIOS entry point that we
+ * care about.
+ */
+struct smbios {
+	/** Start of SMBIOS structures */
+	userptr_t address;
+	/** Length of SMBIOS structures */
+	size_t len;
+	/** Number of SMBIOS structures */
+	unsigned int count;
+};
+
+extern int find_smbios ( struct smbios *smbios );
+extern int find_smbios_structure ( unsigned int type,
+				   struct smbios_structure *structure );
+extern int read_smbios_structure ( struct smbios_structure *structure,
+				   void *data, size_t len );
+extern int read_smbios_string ( struct smbios_structure *structure,
+				unsigned int index,
+				void *data, size_t len );
+
+#endif /* _IPXE_SMBIOS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/socket.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/socket.h
new file mode 100644
index 0000000..320dae4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/socket.h
@@ -0,0 +1,102 @@
+#ifndef _IPXE_SOCKET_H
+#define _IPXE_SOCKET_H
+
+/** @file
+ *
+ * Socket addresses
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/**
+ * @defgroup commtypes Communication semantics
+ *
+ * @{
+ */
+
+/** Connection-based, reliable streams */
+extern int tcp_sock_stream;
+#define TCP_SOCK_STREAM 0x1
+#define SOCK_STREAM tcp_sock_stream
+
+/** Connectionless, unreliable streams */
+extern int udp_sock_dgram;
+#define UDP_SOCK_DGRAM 0x2
+#define SOCK_DGRAM udp_sock_dgram
+
+/** @} */
+
+/**
+ * Name communication semantics
+ *
+ * @v semantics		Communication semantics (e.g. SOCK_STREAM)
+ * @ret name		Name of communication semantics
+ */
+static inline __attribute__ (( always_inline )) const char *
+socket_semantics_name ( int semantics ) {
+	/* Cannot use a switch() because of the {TCP_UDP}_SOCK_XXX hack */
+	if ( semantics == SOCK_STREAM ) {
+		return "SOCK_STREAM";
+	} else if ( semantics == SOCK_DGRAM ) {
+		return "SOCK_DGRAM";
+	} else {
+		return "SOCK_UNKNOWN";
+	}
+}
+
+/**
+ * @defgroup addrfam Address families
+ *
+ * @{
+ */
+#define AF_INET		1	/**< IPv4 Internet addresses */
+#define AF_INET6	2	/**< IPv6 Internet addresses */
+#define AF_FC		3	/**< Fibre Channel addresses */
+/** @} */
+
+/**
+ * Name address family
+ *
+ * @v family		Address family (e.g. AF_INET)
+ * @ret name		Name of address family
+ */
+static inline __attribute__ (( always_inline )) const char *
+socket_family_name ( int family ) {
+	switch ( family ) {
+	case AF_INET:		return "AF_INET";
+	case AF_INET6:		return "AF_INET6";
+	default:		return "AF_UNKNOWN";
+	}
+}
+
+/** A socket address family */
+typedef uint16_t sa_family_t;
+
+/** Length of a @c struct @c sockaddr */
+#define SA_LEN 32
+
+/**
+ * Generalized socket address structure
+ *
+ * This contains the fields common to socket addresses for all address
+ * families.
+ */
+struct sockaddr {
+	/** Socket address family
+	 *
+	 * This is an AF_XXX constant.
+	 */
+        sa_family_t sa_family;
+	/** Padding
+	 *
+	 * This ensures that a struct @c sockaddr_tcpip is large
+	 * enough to hold a socket address for any TCP/IP address
+	 * family.
+	 */
+	char pad[ SA_LEN - sizeof ( sa_family_t ) ];
+} __attribute__ (( may_alias ));
+
+#endif /* _IPXE_SOCKET_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi.h
new file mode 100644
index 0000000..d92d1ae
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi.h
@@ -0,0 +1,258 @@
+#ifndef _IPXE_SPI_H
+#define _IPXE_SPI_H
+
+/** @file
+ *
+ * SPI interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/nvs.h>
+
+/**
+ * @defgroup spicmds SPI commands
+ * @{
+ */
+
+/** Write status register */
+#define SPI_WRSR 0x01
+
+/** Write data to memory array */
+#define SPI_WRITE 0x02
+
+/** Read data from memory array */
+#define SPI_READ 0x03
+
+/** Reset write enable latch */
+#define SPI_WRDI 0x04
+
+/** Read status register */
+#define SPI_RDSR 0x05
+
+/** Set write enable latch */
+#define SPI_WREN 0x06
+
+/**
+ * @defgroup atmelcmds Atmel-specific SPI commands
+ * @{
+ */
+
+/** Erase one sector in memory array (Not supported on all devices) */
+#define ATMEL_SECTOR_ERASE 0x52
+
+/** Erase all sections in memory array (Not supported on all devices) */
+#define ATMEL_CHIP_ERASE 0x62
+
+/** Read manufacturer and product ID (Not supported on all devices) */
+#define ATMEL_RDID 0x15
+
+/** @} */
+
+/** @} */
+
+/**
+ * @defgroup spistatus SPI status register bits (not present on all devices)
+ * @{
+ */
+
+/** Write-protect pin enabled */
+#define SPI_STATUS_WPEN 0x80
+
+/** Block protection bit 2 */
+#define SPI_STATUS_BP2 0x10
+
+/** Block protection bit 1 */
+#define SPI_STATUS_BP1 0x08
+
+/** Block protection bit 0 */
+#define SPI_STATUS_BP0 0x04
+
+/** State of the write enable latch */
+#define SPI_STATUS_WEN 0x02
+
+/** Device busy flag */
+#define SPI_STATUS_NRDY 0x01
+
+/** @} */
+
+/**
+ * An SPI device
+ *
+ * This data structure represents a physical SPI device attached to an
+ * SPI bus.
+ */
+struct spi_device {
+	/** NVS device */
+	struct nvs_device nvs;
+	/** SPI bus to which device is attached */
+	struct spi_bus *bus;
+	/** Slave number */
+	unsigned int slave;
+	/** Command length, in bits */
+	unsigned int command_len;
+	/** Address length, in bits */
+	unsigned int address_len;
+	/** Address is munged
+	 *
+	 * Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
+	 * use bit 3 of the command byte as address bit A8, rather
+	 * than having a two-byte address.  If this flag is set, then
+	 * commands should be munged in this way.
+	 */
+	unsigned int munge_address : 1;
+};
+
+/**
+ * SPI magic autodetection address length
+ *
+ * Set @c spi_device::address_len to @c SPI_AUTODETECT_ADDRESS_LEN if
+ * the address length should be autodetected.
+ */
+#define SPI_AUTODETECT_ADDRESS_LEN 0
+
+static inline __attribute__ (( always_inline )) struct spi_device *
+nvs_to_spi ( struct nvs_device *nvs ) {
+	return container_of ( nvs, struct spi_device, nvs );
+}
+
+/**
+ * An SPI bus
+ *
+ * This data structure represents an SPI bus controller capable of
+ * issuing commands to attached SPI devices.
+ */
+struct spi_bus {
+	/** SPI interface mode
+	 *
+	 * This is the bitwise OR of zero or more of @c SPI_MODE_CPHA
+	 * and @c SPI_MODE_CPOL.  It is also the number conventionally
+	 * used to describe the SPI interface mode.  For example, SPI
+	 * mode 1 is the mode in which CPOL=0 and CPHA=1, which
+	 * therefore corresponds to a mode value of (0|SPI_MODE_CPHA)
+	 * which, happily, equals 1.
+	 */
+	unsigned int mode;
+	/**
+	 * Read/write data via SPI bus
+	 *
+	 * @v bus		SPI bus
+	 * @v device		SPI device
+	 * @v command		Command
+	 * @v address		Address to read/write (<0 for no address)
+	 * @v data_out		TX data buffer (or NULL)
+	 * @v data_in		RX data buffer (or NULL)
+	 * @v len		Length of data buffer(s)
+	 *
+	 * This issues the specified command and optional address to
+	 * the SPI device, then reads and/or writes data to/from the
+	 * data buffers.
+	 */
+	int ( * rw ) ( struct spi_bus *bus, struct spi_device *device,
+		       unsigned int command, int address,
+		       const void *data_out, void *data_in, size_t len );
+};
+
+/** Clock phase (CPHA) mode bit
+ *
+ * Phase 0 is sample on rising edge, shift data on falling edge.
+ *
+ * Phase 1 is shift data on rising edge, sample data on falling edge.
+ */
+#define SPI_MODE_CPHA 0x01
+
+/** Clock polarity (CPOL) mode bit
+ *
+ * This bit reflects the idle state of the clock line (SCLK).
+ */
+#define SPI_MODE_CPOL 0x02
+
+/** Slave select polarity mode bit
+ *
+ * This bit reflects that active state of the slave select lines.  It
+ * is not part of the normal SPI mode number (which covers only @c
+ * SPI_MODE_CPOL and @c SPI_MODE_CPHA), but is included here for
+ * convenience.
+ */
+#define SPI_MODE_SSPOL 0x10
+
+/** Microwire-compatible mode
+ *
+ * This is SPI mode 1 (i.e. CPOL=0, CPHA=1), and is compatible with
+ * the original Microwire protocol.
+ */
+#define SPI_MODE_MICROWIRE 1
+
+/** Microwire/Plus-compatible mode
+ *
+ * This is SPI mode 0 (i.e. CPOL=0, CPHA=0), and is compatible with
+ * the Microwire/Plus protocol
+ */
+#define SPI_MODE_MICROWIRE_PLUS 0
+
+/** Threewire-compatible mode
+ *
+ * This mode is compatible with Atmel's series of "three-wire"
+ * interfaces.
+ */
+#define SPI_MODE_THREEWIRE ( SPI_MODE_MICROWIRE_PLUS | SPI_MODE_SSPOL )
+
+extern int spi_read ( struct nvs_device *nvs, unsigned int address,
+		      void *data, size_t len );
+extern int spi_write ( struct nvs_device *nvs, unsigned int address,
+		       const void *data, size_t len );
+
+/**
+ * @defgroup spidevs SPI device types
+ * @{
+ */
+
+static inline __attribute__ (( always_inline )) void
+init_spi ( struct spi_device *device ) {
+	device->nvs.word_len_log2 = 0;
+	device->command_len = 8,
+	device->nvs.read = spi_read;
+	device->nvs.write = spi_write;	
+}
+
+/** Atmel AT25F1024 serial flash */
+static inline __attribute__ (( always_inline )) void
+init_at25f1024 ( struct spi_device *device ) {
+	device->address_len = 24;
+	device->nvs.size = ( 128 * 1024 );
+	device->nvs.block_size = 256;
+	init_spi ( device );
+}
+
+/** Atmel 25040 serial EEPROM */
+static inline __attribute__ (( always_inline )) void
+init_at25040 ( struct spi_device *device ) {
+	device->address_len = 8;
+	device->munge_address = 1;
+	device->nvs.size = 512;
+	device->nvs.block_size = 8;
+	init_spi ( device );
+}
+
+/** ST M25P32 serial flash */
+static inline __attribute__ (( always_inline )) void
+init_m25p32 ( struct spi_device *device ) {
+	device->address_len = 24;
+	device->nvs.size = ( 4 * 1024 * 1024 );
+	device->nvs.block_size = 256;
+	init_spi ( device );
+}
+
+/** Microchip 25XX640 serial EEPROM */
+static inline __attribute__ (( always_inline )) void
+init_mc25xx640 ( struct spi_device *device ) {
+	device->address_len = 16;
+	device->nvs.size = ( 8 * 1024 );
+	device->nvs.block_size = 32;
+	init_spi ( device );
+}
+
+/** @} */
+
+#endif /* _IPXE_SPI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi_bit.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi_bit.h
new file mode 100644
index 0000000..9cfa7b8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/spi_bit.h
@@ -0,0 +1,63 @@
+#ifndef _IPXE_SPI_BIT_H
+#define _IPXE_SPI_BIT_H
+
+/** @file
+ *
+ * SPI bit-bashing interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/spi.h>
+#include <ipxe/bitbash.h>
+
+/** A bit-bashing SPI bus */
+struct spi_bit_basher {
+	/** SPI bus */
+	struct spi_bus bus;
+	/** Bit-bashing interface */
+	struct bit_basher basher;
+	/** Endianness of data
+	 *
+	 * SPI commands and addresses are always big-endian (i.e. MSB
+	 * transmitted first on the wire), but some cards
+	 * (e.g. natsemi) choose to regard the data stored in the
+	 * EEPROM as little-endian (i.e. LSB transmitted first on the
+	 * wire).
+	 */
+	int endianness;
+};
+
+/** Bit indices used for SPI bit-bashing interface */
+enum {
+	/** Serial clock */
+	SPI_BIT_SCLK = 0,
+	/** Master Out Slave In */
+	SPI_BIT_MOSI,
+	/** Master In Slave Out */
+	SPI_BIT_MISO,
+	/** Slave 0 select */
+	SPI_BIT_SS0,
+};
+
+/**
+ * Determine bit index for a particular slave
+ *
+ * @v slave		Slave number
+ * @ret index		Bit index (i.e. SPI_BIT_SSN, where N=slave) 
+ */
+#define SPI_BIT_SS( slave ) ( SPI_BIT_SS0 + (slave) )
+
+/** Delay between SCLK transitions */
+#define SPI_BIT_UDELAY 1
+
+/** SPI bit basher treats data as big-endian */
+#define SPI_BIT_BIG_ENDIAN 0
+
+/** SPI bit basher treats data as little-endian */
+#define SPI_BIT_LITTLE_ENDIAN 1
+
+extern void init_spi_bit_basher ( struct spi_bit_basher *spibit );
+
+#endif /* _IPXE_SPI_BIT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/srp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/srp.h
new file mode 100644
index 0000000..8d7f799
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/srp.h
@@ -0,0 +1,833 @@
+#ifndef _IPXE_SRP_H
+#define _IPXE_SRP_H
+
+/** @file
+ *
+ * SCSI RDMA Protocol
+ *
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/scsi.h>
+#include <ipxe/acpi.h>
+
+/*****************************************************************************
+ *
+ * Common fields
+ *
+ *****************************************************************************
+ */
+
+/** An SRP information unit tag */
+union srp_tag {
+	uint8_t bytes[8];
+	uint32_t dwords[2];
+} __attribute__ (( packed ));
+
+/** SRP tag magic marker */
+#define SRP_TAG_MAGIC 0x69505845
+
+/** An SRP port ID */
+union srp_port_id {
+	uint8_t bytes[16];
+	uint32_t dwords[4];
+} __attribute__ (( packed ));
+
+/** SRP information unit common fields */
+struct srp_common {
+	/** Information unit type */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[7];
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * Login request
+ *
+ *****************************************************************************
+ */
+
+/** An SRP login request information unit */
+struct srp_login_req {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_LOGIN_REQ
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[7];
+	/** Tag */
+	union srp_tag tag;
+	/** Requested maximum initiator to target IU length */
+	uint32_t max_i_t_iu_len;
+	/** Reserved */
+	uint8_t reserved1[4];
+	/** Required buffer formats
+	 *
+	 * This is the bitwise OR of one or more @c
+	 * SRP_LOGIN_REQ_FMT_XXX constants.
+	 */
+	uint16_t required_buffer_formats;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c
+	 * SRP_LOGIN_REQ_FLAG_XXX and @c SRP_LOGIN_REQ_MCA_XXX
+	 * constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved2[5];
+	/** Initiator port identifier */
+	union srp_port_id initiator;
+	/** Target port identifier */
+	union srp_port_id target;
+} __attribute__ (( packed ));
+
+/** Type of an SRP login request */
+#define SRP_LOGIN_REQ 0x00
+
+/** Require indirect data buffer descriptor format */
+#define SRP_LOGIN_REQ_FMT_IDBD 0x04
+
+/** Require direct data buffer descriptor format */
+#define SRP_LOGIN_REQ_FMT_DDBD 0x02
+
+/** Use solicited notification for asynchronous events */
+#define SRP_LOGIN_REQ_FLAG_AESOLNT 0x40
+
+/** Use solicited notification for credit request */
+#define SRP_LOGIN_REQ_FLAG_CRSOLNT 0x20
+
+/** Use solicited notification for logouts */
+#define SRP_LOGIN_REQ_FLAG_LOSOLNT 0x10
+
+/** Multi-channel action mask */
+#define SRP_LOGIN_REQ_MCA_MASK 0x03
+
+/** Single RDMA channel operation */
+#define SRP_LOGIN_REQ_MCA_SINGLE_CHANNEL 0x00
+
+/** Multiple independent RDMA channel operation */
+#define SRP_LOGIN_REQ_MCA_MULTIPLE_CHANNELS 0x01
+
+/*****************************************************************************
+ *
+ * Login response
+ *
+ *****************************************************************************
+ */
+
+/** An SRP login response */
+struct srp_login_rsp {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_LOGIN_RSP
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[3];
+	/** Request limit delta */
+	uint32_t request_limit_delta;
+	/** Tag */
+	union srp_tag tag;
+	/** Maximum initiator to target IU length */
+	uint32_t max_i_t_iu_len;
+	/** Maximum target to initiator IU length */
+	uint32_t max_t_i_iu_len;
+	/** Supported buffer formats
+	 *
+	 * This is the bitwise OR of one or more @c
+	 * SRP_LOGIN_RSP_FMT_XXX constants.
+	 */
+	uint16_t supported_buffer_formats;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c
+	 * SRP_LOGIN_RSP_FLAG_XXX and @c SRP_LOGIN_RSP_MCR_XXX
+	 * constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved1[25];
+} __attribute__ (( packed ));
+
+/** Type of an SRP login response */
+#define SRP_LOGIN_RSP 0xc0
+
+/** Indirect data buffer descriptor format supported */
+#define SRP_LOGIN_RSP_FMT_IDBD 0x04
+
+/** Direct data buffer descriptor format supported */
+#define SRP_LOGIN_RSP_FMT_DDBD 0x02
+
+/** Solicited notification is supported */
+#define SRP_LOGIN_RSP_FLAG_SOLNTSUP 0x10
+
+/** Multi-channel result mask */
+#define SRP_LOGIN_RSP_MCR_MASK 0x03
+
+/** No existing RDMA channels were associated with the same I_T nexus */
+#define SRP_LOGIN_RSP_MCR_NO_EXISTING_CHANNELS 0x00
+
+/** One or more existing RDMA channels were terminated */
+#define SRP_LOGIN_RSP_MCR_EXISTING_CHANNELS_TERMINATED 0x01
+
+/** One or more existing RDMA channels continue to operate independently */
+#define SRP_LOGIN_RSP_MCR_EXISTING_CHANNELS_CONTINUE 0x02
+
+/*****************************************************************************
+ *
+ * Login rejection
+ *
+ *****************************************************************************
+ */
+
+/** An SRP login rejection */
+struct srp_login_rej {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_LOGIN_REJ
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[3];
+	/** Reason
+	 *
+	 * This is a @c SRP_LOGIN_REJ_REASON_XXX constant.
+	 */
+	uint32_t reason;
+	/** Tag */
+	union srp_tag tag;
+	/** Reserved */
+	uint8_t reserved1[8];
+	/** Supported buffer formats
+	 *
+	 * This is the bitwise OR of one or more @c
+	 * SRP_LOGIN_REJ_FMT_XXX constants.
+	 */
+	uint16_t supported_buffer_formats;
+	/** Reserved */
+	uint8_t reserved2[6];
+} __attribute__ (( packed ));
+
+/** Type of an SRP login rejection */
+#define SRP_LOGIN_REJ 0xc2
+
+/** Unable to establish RDMA channel, no reason specified */
+#define SRP_LOGIN_REJ_REASON_UNKNOWN 0x00010000UL
+
+/** Insufficient RDMA channel resources */
+#define SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES 0x00010001UL
+
+/** Requested maximum initiator to target IU length value too large */
+#define SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN 0x00010002UL
+
+/** Unable to associate RDMA channel with specified I_T nexus */
+#define SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE 0x00010003UL
+
+/** One or more requested data buffer descriptor formats are not supported */
+#define SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT 0x00010004UL
+
+/** SRP target port does not support multiple RDMA channels per I_T nexus */
+#define SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS 0x00010005UL
+
+/** RDMA channel limit reached for this initiator */
+#define SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS 0x00010006UL
+
+/** SRP login rejection reason is defined */
+#define SRP_LOGIN_REJ_REASON_DEFINED( reason ) \
+	( ( (reason) & 0xfffffff0UL ) == 0x00010000UL )
+
+/** Indirect data buffer descriptor format supported */
+#define SRP_LOGIN_REJ_FMT_IDBD 0x04
+
+/** Direct data buffer descriptor format supported */
+#define SRP_LOGIN_REJ_FMT_DDBD 0x02
+
+/*****************************************************************************
+ *
+ * Initiator logout
+ *
+ *****************************************************************************
+ */
+
+/** An SRP initiator logout request */
+struct srp_i_logout {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_I_LOGOUT
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[7];
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/** Type of an SRP initiator logout request */
+#define SRP_I_LOGOUT 0x03
+
+/*****************************************************************************
+ *
+ * Target logout
+ *
+ *****************************************************************************
+ */
+
+/** An SRP target logout request */
+struct srp_t_logout {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_T_LOGOUT
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c
+	 * SRP_T_LOGOUT_FLAG_XXX constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[2];
+	/** Reason
+	 *
+	 * This is a @c SRP_T_LOGOUT_REASON_XXX constant.
+	 */
+	uint32_t reason;
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/** Type of an SRP target logout request */
+#define SRP_T_LOGOUT 0x80
+
+/** The initiator specified solicited notification of logouts */
+#define SRP_T_LOGOUT_FLAG_SOLNT 0x01
+
+/** No reason specified */
+#define SRP_T_LOGOUT_REASON_UNKNOWN 0x00000000UL
+
+/** Inactive RDMA channel (reclaiming resources) */
+#define SRP_T_LOGOUT_REASON_INACTIVE 0x00000001UL
+
+/** Invalid information unit type code received by SRP target port */
+#define SRP_T_LOGOUT_REASON_INVALID_TYPE 0x00000002UL
+
+/** SRP initiator port sent response with no corresponding request */
+#define SRP_T_LOGOUT_REASON_SPURIOUS_RESPONSE 0x00000003UL
+
+/** RDMA channel disconnected due to multi-channel action code in new login */
+#define SRP_T_LOGOUT_REASON_MCA 0x00000004UL
+
+/** Unsuppported format code value specified in data-out buffer descriptor */
+#define SRP_T_LOGOUT_UNSUPPORTED_DATA_OUT_FORMAT 0x00000005UL
+
+/** Unsuppported format code value specified in data-in buffer descriptor */
+#define SRP_T_LOGOUT_UNSUPPORTED_DATA_IN_FORMAT 0x00000006UL
+
+/** Invalid length for IU type */
+#define SRP_T_LOGOUT_INVALID_IU_LEN 0x00000008UL
+
+/*****************************************************************************
+ *
+ * Task management
+ *
+ *****************************************************************************
+ */
+
+/** An SRP task management request */
+struct srp_tsk_mgmt {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_TSK_MGMT
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more
+	 * @c SRP_TSK_MGMT_FLAG_XXX constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[6];
+	/** Tag */
+	union srp_tag tag;
+	/** Reserved */
+	uint8_t reserved1[4];
+	/** Logical unit number */
+	struct scsi_lun lun;
+	/** Reserved */
+	uint8_t reserved2[2];
+	/** Task management function
+	 *
+	 * This is a @c SRP_TASK_MGMT_FUNC_XXX constant
+	 */
+	uint8_t function;
+	/** Reserved */
+	uint8_t reserved3[1];
+	/** Tag of task to be managed */
+	union srp_tag managed_tag;
+	/** Reserved */
+	uint8_t reserved4[8];
+} __attribute__ (( packed ));
+
+/** Type of an SRP task management request */
+#define SRP_TSK_MGMT 0x01
+
+/** Use solicited notification for unsuccessful completions */
+#define SRP_TSK_MGMT_FLAG_UCSOLNT 0x04
+
+/** Use solicited notification for successful completions */
+#define SRP_TSK_MGMT_FLAG_SCSOLNT 0x02
+
+/** The task manager shall perform an ABORT TASK function */
+#define SRP_TSK_MGMT_FUNC_ABORT_TASK 0x01
+
+/** The task manager shall perform an ABORT TASK SET function */
+#define SRP_TSK_MGMT_FUNC_ABORT_TASK_SET 0x02
+
+/** The task manager shall perform a CLEAR TASK SET function */
+#define SRP_TSK_MGMT_FUNC_CLEAR_TASK_SET 0x04
+
+/** The task manager shall perform a LOGICAL UNIT RESET function */
+#define SRP_TSK_MGMT_FUNC_LOGICAL_UNIT_RESET 0x08
+
+/** The task manager shall perform a CLEAR ACA function */
+#define SRP_TSK_MGMT_FUNC_CLEAR_ACA 0x40
+
+/*****************************************************************************
+ *
+ * SCSI command
+ *
+ *****************************************************************************
+ */
+
+/** An SRP SCSI command */
+struct srp_cmd {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_CMD
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c SRP_CMD_FLAG_XXX
+	 * constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[3];
+	/** Data buffer descriptor formats
+	 *
+	 * This is the bitwise OR of one @c SRP_CMD_DO_FMT_XXX and one @c
+	 * SRP_CMD_DI_FMT_XXX constant.
+	 */
+	uint8_t data_buffer_formats;
+	/** Data-out buffer descriptor count */
+	uint8_t data_out_buffer_count;
+	/** Data-in buffer descriptor count */
+	uint8_t data_in_buffer_count;
+	/** Tag */
+	union srp_tag tag;
+	/** Reserved */
+	uint8_t reserved1[4];
+	/** Logical unit number */
+	struct scsi_lun lun;
+	/** Reserved */
+	uint8_t reserved2[1];
+	/** Task attribute
+	 *
+	 * This is a @c SRP_CMD_TASK_ATTR_XXX constant.
+	 */
+	uint8_t task_attr;
+	/** Reserved */
+	uint8_t reserved3[1];
+	/** Additional CDB length */
+	uint8_t additional_cdb_len;
+	/** Command data block */
+	union scsi_cdb cdb;
+} __attribute__ (( packed ));
+
+/** Type of an SRP SCSI command */
+#define SRP_CMD 0x02
+
+/** Use solicited notification for unsuccessful completions */
+#define SRP_CMD_FLAG_UCSOLNT 0x04
+
+/** Use solicited notification for successful completions */
+#define SRP_CMD_FLAG_SCSOLNT 0x02
+
+/** Data-out buffer format mask */
+#define SRP_CMD_DO_FMT_MASK 0xf0
+
+/** Direct data-out buffer format */
+#define SRP_CMD_DO_FMT_DIRECT 0x10
+
+/** Indirect data-out buffer format */
+#define SRP_CMD_DO_FMT_INDIRECT 0x20
+
+/** Data-in buffer format mask */
+#define SRP_CMD_DI_FMT_MASK 0x0f
+
+/** Direct data-in buffer format */
+#define SRP_CMD_DI_FMT_DIRECT 0x01
+
+/** Indirect data-in buffer format */
+#define SRP_CMD_DI_FMT_INDIRECT 0x02
+
+/** Use the rules for a simple task attribute */
+#define SRP_CMD_TASK_ATTR_SIMPLE 0x00
+
+/** Use the rules for a head of queue task attribute */
+#define SRP_CMD_TASK_ATTR_QUEUE_HEAD 0x01
+
+/** Use the rules for an ordered task attribute */
+#define SRP_CMD_TASK_ATTR_ORDERED 0x02
+
+/** Use the rules for an automatic contingent allegiance task attribute */
+#define SRP_CMD_TASK_ATTR_AUTOMATIC_CONTINGENT_ALLEGIANCE 0x08
+
+/** An SRP memory descriptor */
+struct srp_memory_descriptor {
+	/** Virtual address */
+	uint64_t address;
+	/** Memory handle */
+	uint32_t handle;
+	/** Data length */
+	uint32_t len;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * SCSI response
+ *
+ *****************************************************************************
+ */
+
+/** An SRP SCSI response */
+struct srp_rsp {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_RSP
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c SRP_RSP_FLAG_XXX
+	 * constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[2];
+	/** Request limit delta */
+	uint32_t request_limit_delta;
+	/** Tag */
+	union srp_tag tag;
+	/** Reserved */
+	uint8_t reserved1[2];
+	/** Valid fields
+	 *
+	 * This is the bitwise OR of zero or more @c SRP_RSP_VALID_XXX
+	 * constants.
+	 */
+	uint8_t valid;
+	/** Status
+	 *
+	 * This is the SCSI status code.
+	 */
+	uint8_t status;
+	/** Data-out residual count */
+	uint32_t data_out_residual_count;
+	/** Data-in residual count */
+	uint32_t data_in_residual_count;
+	/** Sense data list length */
+	uint32_t sense_data_len;
+	/** Response data list length */
+	uint32_t response_data_len;
+} __attribute__ (( packed ));
+
+/** Type of an SRP SCSI response */
+#define SRP_RSP 0xc1
+
+/** The initiator specified solicited notification of this response */
+#define SRP_RSP_FLAG_SOLNT 0x01
+
+/** Data-in residual count field is valid and represents an underflow */
+#define SRP_RSP_VALID_DIUNDER 0x20
+
+/** Data-in residual count field is valid and represents an overflow */
+#define SRP_RSP_VALID_DIOVER 0x10
+
+/** Data-out residual count field is valid and represents an underflow */
+#define SRP_RSP_VALID_DOUNDER 0x08
+
+/** Data-out residual count field is valid and represents an overflow */
+#define SRP_RSP_VALID_DOOVER 0x04
+
+/** Sense data list length field is valid */
+#define SRP_RSP_VALID_SNSVALID 0x02
+
+/** Response data list length field is valid */
+#define SRP_RSP_VALID_RSPVALID 0x01
+
+/**
+ * Get response data portion of SCSI response
+ *
+ * @v rsp			SCSI response
+ * @ret response_data		Response data, or NULL if not present
+ */
+static inline const void * srp_rsp_response_data ( const struct srp_rsp *rsp ) {
+	return ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ?
+		 ( ( ( const void * ) rsp ) + sizeof ( *rsp ) ) : NULL );
+}
+
+/**
+ * Get length of response data portion of SCSI response
+ *
+ * @v rsp			SCSI response
+ * @ret response_data_len	Response data length
+ */
+static inline size_t srp_rsp_response_data_len ( const struct srp_rsp *rsp ) {
+	return ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ?
+		 ntohl ( rsp->response_data_len ) : 0 );
+}
+
+/**
+ * Get sense data portion of SCSI response
+ *
+ * @v rsp			SCSI response
+ * @ret sense_data		Sense data, or NULL if not present
+ */
+static inline const void * srp_rsp_sense_data ( const struct srp_rsp *rsp ) {
+	return ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ?
+		 ( ( ( const void * ) rsp ) + sizeof ( *rsp ) +
+		   srp_rsp_response_data_len ( rsp ) ) : NULL );
+}
+
+/**
+ * Get length of sense data portion of SCSI response
+ *
+ * @v rsp			SCSI response
+ * @ret sense_data_len		Sense data length
+ */
+static inline size_t srp_rsp_sense_data_len ( const struct srp_rsp *rsp ) {
+	return ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ?
+		 ntohl ( rsp->sense_data_len ) : 0 );
+}
+
+/*****************************************************************************
+ *
+ * Credit request
+ *
+ *****************************************************************************
+ */
+
+/** An SRP credit request */
+struct srp_cred_req {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_CRED_REQ
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more
+	 * @c SRP_CRED_REQ_FLAG_XXX constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[2];
+	/** Request limit delta */
+	uint32_t request_limit_delta;
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/** Type of an SRP credit request */
+#define SRP_CRED_REQ 0x81
+
+/** The initiator specified solicited notification of credit requests */
+#define SRP_CRED_REQ_FLAG_SOLNT 0x01
+
+/*****************************************************************************
+ *
+ * Credit response
+ *
+ *****************************************************************************
+ */
+
+/** An SRP credit response */
+struct srp_cred_rsp {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_CRED_RSP
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[7];
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/** Type of an SRP credit response */
+#define SRP_CRED_RSP 0x41
+
+/*****************************************************************************
+ *
+ * Asynchronous event request
+ *
+ *****************************************************************************
+ */
+
+/** An SRP asynchronous event request */
+struct srp_aer_req {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_AER_REQ
+	 */
+	uint8_t type;
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c
+	 * SRP_AER_REQ_FLAG_XXX constants.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved0[2];
+	/** Request limit delta */
+	uint32_t request_limit_delta;
+	/** Tag */
+	union srp_tag tag;
+	/** Reserved */
+	uint8_t reserved1[4];
+	/** Logical unit number */
+	struct scsi_lun lun;
+	/** Sense data list length */
+	uint32_t sense_data_len;
+	/** Reserved */
+	uint8_t reserved2[4];
+} __attribute__ (( packed ));
+
+/** Type of an SRP asynchronous event request */
+#define SRP_AER_REQ 0x82
+
+/** The initiator specified solicited notification of asynchronous events */
+#define SRP_AER_REQ_FLAG_SOLNT 0x01
+
+/**
+ * Get sense data portion of asynchronous event request
+ *
+ * @v aer_req			SRP asynchronous event request
+ * @ret sense_data		Sense data
+ */
+static inline __always_inline void *
+srp_aer_req_sense_data ( struct srp_aer_req *aer_req ) {
+	return ( ( ( void * ) aer_req ) + sizeof ( *aer_req ) );
+}
+
+/**
+ * Get length of sense data portion of asynchronous event request
+ *
+ * @v aer_req			SRP asynchronous event request
+ * @ret sense_data_len		Sense data length
+ */
+static inline __always_inline size_t
+srp_aer_req_sense_data_len ( struct srp_aer_req *aer_req ) {
+	return ( ntohl ( aer_req->sense_data_len ) );
+}
+
+/*****************************************************************************
+ *
+ * Asynchronous event response
+ *
+ *****************************************************************************
+ */
+
+/** An SRP asynchronous event response */
+struct srp_aer_rsp {
+	/** Information unit type
+	 *
+	 * This must be @c SRP_AER_RSP
+	 */
+	uint8_t type;
+	/** Reserved */
+	uint8_t reserved0[7];
+	/** Tag */
+	union srp_tag tag;
+} __attribute__ (( packed ));
+
+/** Type of an SRP asynchronous event response */
+#define SRP_AER_RSP 0x42
+
+/*****************************************************************************
+ *
+ * SRP boot firmware table
+ *
+ * The working draft specification for the SRP boot firmware table can
+ * be found at
+ *
+ *   http://ipxe.org/wiki/srp/sbft
+ *
+ *****************************************************************************
+ */
+
+/** SRP Boot Firmware Table signature */
+#define SBFT_SIG ACPI_SIGNATURE ( 's', 'B', 'F', 'T' )
+
+/** An offset from the start of the sBFT */
+typedef uint16_t sbft_off_t;
+
+/**
+ * SRP Boot Firmware Table
+ */
+struct sbft_table {
+	/** ACPI header */
+	struct acpi_description_header acpi;
+	/** Offset to SCSI subtable */
+	sbft_off_t scsi_offset;
+	/** Offset to SRP subtable */
+	sbft_off_t srp_offset;
+	/** Offset to IB subtable, if present */
+	sbft_off_t ib_offset;
+	/** Reserved */
+	uint8_t reserved[6];
+} __attribute__ (( packed ));
+
+/**
+ * sBFT SCSI subtable
+ */
+struct sbft_scsi_subtable {
+	/** LUN */
+	struct scsi_lun lun;
+} __attribute__ (( packed ));
+
+/**
+ * sBFT SRP subtable
+ */
+struct sbft_srp_subtable {
+	/** Initiator port identifier */
+	union srp_port_id initiator;
+	/** Target port identifier */
+	union srp_port_id target;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * SRP devices
+ *
+ *****************************************************************************
+ */
+
+extern int srp_open ( struct interface *block, struct interface *socket,
+		      union srp_port_id *initiator, union srp_port_id *target,
+		      uint32_t memory_handle, struct scsi_lun *lun );
+
+#endif /* _IPXE_SRP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/syslog.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/syslog.h
new file mode 100644
index 0000000..25edc6b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/syslog.h
@@ -0,0 +1,36 @@
+#ifndef _IPXE_SYSLOG_H
+#define _IPXE_SYSLOG_H
+
+/** @file
+ *
+ * Syslog protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Syslog server port */
+#define SYSLOG_PORT 514
+
+/** Syslog line buffer size
+ *
+ * This is a policy decision
+ */
+#define SYSLOG_BUFSIZE 128
+
+/** Syslog facility
+ *
+ * This is a policy decision
+ */
+#define SYSLOG_FACILITY 0 /* kernel */
+
+/** Syslog severity
+ *
+ * This is a policy decision
+ */
+#define SYSLOG_SEVERITY 6 /* informational */
+
+/** Syslog priority */
+#define SYSLOG_PRIORITY( facility, severity ) ( 8 * (facility) + (severity) )
+
+#endif /* _IPXE_SYSLOG_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/tables.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tables.h
new file mode 100644
index 0000000..e35ce82
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tables.h
@@ -0,0 +1,518 @@
+#ifndef _IPXE_TABLES_H
+#define _IPXE_TABLES_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @page ifdef_harmful #ifdef considered harmful
+ *
+ * Overuse of @c #ifdef has long been a problem in Etherboot.
+ * Etherboot provides a rich array of features, but all these features
+ * take up valuable space in a ROM image.  The traditional solution to
+ * this problem has been for each feature to have its own @c #ifdef
+ * option, allowing the feature to be compiled in only if desired.
+ *
+ * The problem with this is that it becomes impossible to compile, let
+ * alone test, all possible versions of Etherboot.  Code that is not
+ * typically used tends to suffer from bit-rot over time.  It becomes
+ * extremely difficult to predict which combinations of compile-time
+ * options will result in code that can even compile and link
+ * correctly.
+ *
+ * To solve this problem, we have adopted a new approach from
+ * Etherboot 5.5 onwards.  @c #ifdef is now "considered harmful", and
+ * its use should be minimised.  Separate features should be
+ * implemented in separate @c .c files, and should \b always be
+ * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
+ * MY_PET_FEATURE statement).  By making (almost) all code always
+ * compile, we avoid the problem of bit-rot in rarely-used code.
+ *
+ * The file config.h, in combination with the @c make command line,
+ * specifies the objects that will be included in any particular build
+ * of Etherboot.  For example, suppose that config.h includes the line
+ *
+ * @code
+ *
+ *   #define CONSOLE_SERIAL
+ *   #define DOWNLOAD_PROTO_TFTP
+ *
+ * @endcode
+ *
+ * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
+ * built, the options specified in config.h are used to drag in the
+ * relevant objects at link-time.  For the above example, serial.o and
+ * tftp.o would be linked in.
+ *
+ * There remains one problem to solve: how do these objects get used?
+ * Traditionally, we had code such as
+ *
+ * @code
+ *
+ *    #ifdef CONSOLE_SERIAL
+ *      serial_init();
+ *    #endif
+ *
+ * @endcode
+ *
+ * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
+ * We cannot simply remove the @c #ifdef and make it
+ *
+ * @code
+ *
+ *   serial_init();
+ *
+ * @endcode
+ *
+ * because then serial.o would end up always being linked in.
+ *
+ * The solution is to use @link tables.h linker tables @endlink.
+ *
+ */
+
+/** @file
+ *
+ * Linker tables
+ *
+ * Read @ref ifdef_harmful first for some background on the motivation
+ * for using linker tables.
+ *
+ * This file provides macros for dealing with linker-generated tables
+ * of fixed-size symbols.  We make fairly extensive use of these in
+ * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
+ * For example, instead of having code such as
+ *
+ * @code
+ *
+ *    #ifdef CONSOLE_SERIAL
+ *      serial_init();
+ *    #endif
+ *
+ * @endcode
+ *
+ * we make serial.c generate an entry in the initialisation function
+ * table, and then have a function call_init_fns() that simply calls
+ * all functions present in this table.  If and only if serial.o gets
+ * linked in, then its initialisation function will be called.  We
+ * avoid linker symbol pollution (i.e. always dragging in serial.o
+ * just because of a call to serial_init()) and we also avoid @c
+ * #ifdef spaghetti (having to conditionalise every reference to
+ * functions in serial.c).
+ *
+ * The linker script takes care of assembling the tables for us.  All
+ * our table sections have names of the format @c .tbl.NAME.NN where
+ * @c NAME designates the data structure stored in the table (e.g. @c
+ * init_fns) and @c NN is a two-digit decimal number used to impose an
+ * ordering upon the tables if required.  @c NN=00 is reserved for the
+ * symbol indicating "table start", and @c NN=99 is reserved for the
+ * symbol indicating "table end".
+ *
+ * As an example, suppose that we want to create a "frobnicator"
+ * feature framework, and allow for several independent modules to
+ * provide frobnicating services.  Then we would create a frob.h
+ * header file containing e.g.
+ *
+ * @code
+ *
+ *   struct frobnicator {
+ *      const char *name;		// Name of the frobnicator
+ *	void ( *frob ) ( void ); 	// The frobnicating function itself
+ *   };
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ * @endcode
+ *
+ * Any module providing frobnicating services would look something
+ * like
+ *
+ * @code
+ *
+ *   #include "frob.h"
+ *
+ *   static void my_frob ( void ) {
+ *	// Do my frobnicating
+ *	...
+ *   }
+ *
+ *   struct frob my_frobnicator __frobnicator = {
+ *	.name = "my_frob",
+ *	.frob = my_frob,
+ *   };
+ *
+ * @endcode
+ *
+ * The central frobnicator code (frob.c) would use the frobnicating
+ * modules as follows
+ *
+ * @code
+ *
+ *   #include "frob.h"
+ *
+ *   // Call all linked-in frobnicators
+ *   void frob_all ( void ) {
+ *	struct frob *frob;
+ *
+ *	for_each_table ( frob, FROBNICATORS ) {
+ *         printf ( "Calling frobnicator \"%s\"\n", frob->name );
+ *	   frob->frob ();
+ *	}
+ *   }
+ *
+ * @endcode
+ *
+ * See init.h and init.c for a real-life example.
+ *
+ */
+
+#ifdef DOXYGEN
+#define __attribute__( x )
+#endif
+
+/**
+ * Declare a linker table
+ *
+ * @v type		Data type
+ * @v name		Table name
+ * @ret table		Linker table
+ */
+#define __table( type, name ) ( type, name )
+
+/**
+ * Get linker table data type
+ *
+ * @v table		Linker table
+ * @ret type		Data type
+ */
+#define __table_type( table ) __table_extract_type table
+#define __table_extract_type( type, name ) type
+
+/**
+ * Get linker table name
+ *
+ * @v table		Linker table
+ * @ret name		Table name
+ */
+#define __table_name( table ) __table_extract_name table
+#define __table_extract_name( type, name ) name
+
+/**
+ * Get linker table section name
+ *
+ * @v table		Linker table
+ * @v idx		Sub-table index
+ * @ret section		Section name
+ */
+#define __table_section( table, idx ) \
+	".tbl." __table_name ( table ) "." __table_str ( idx )
+#define __table_str( x ) #x
+
+/**
+ * Get linker table alignment
+ *
+ * @v table		Linker table
+ * @ret align		Alignment
+ */
+#define __table_alignment( table ) __alignof__ ( __table_type ( table ) )
+
+/**
+ * Declare a linker table entry
+ *
+ * @v table		Linker table
+ * @v idx		Sub-table index
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ *   struct frobnicator my_frob __frobnicator = {
+ *      ...
+ *   };
+ *
+ * @endcode
+ */
+#define __table_entry( table, idx )					\
+	__attribute__ (( __section__ ( __table_section ( table, idx ) ),\
+			 __aligned__ ( __table_alignment ( table ) ) ))
+
+/**
+ * Get start of linker table entries
+ *
+ * @v table		Linker table
+ * @v idx		Sub-table index
+ * @ret entries		Start of entries
+ */
+#define __table_entries( table, idx ) ( {				\
+	static __table_type ( table ) __table_entries[0]		\
+		__table_entry ( table, idx ) 				\
+		__attribute__ (( unused ));				\
+	__table_entries; } )
+
+/**
+ * Get start of linker table
+ *
+ * @v table		Linker table
+ * @ret start		Start of linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   struct frobnicator *frobs = table_start ( FROBNICATORS );
+ *
+ * @endcode
+ */
+#define table_start( table ) __table_entries ( table, 00 )
+
+/**
+ * Get end of linker table
+ *
+ * @v table		Linker table
+ * @ret end		End of linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   struct frobnicator *frobs_end = table_end ( FROBNICATORS );
+ *
+ * @endcode
+ */
+#define table_end( table ) __table_entries ( table, 99 )
+
+/**
+ * Get number of entries in linker table
+ *
+ * @v table		Linker table
+ * @ret num_entries	Number of entries in linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   unsigned int num_frobs = table_num_entries ( FROBNICATORS );
+ *
+ * @endcode
+ *
+ */
+#define table_num_entries( table )					\
+	( ( unsigned int ) ( table_end ( table ) -			\
+			     table_start ( table ) ) )
+
+/**
+ * Get index of entry within linker table
+ *
+ * @v table		Linker table
+ * @v entry		Table entry
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ *   struct frobnicator my_frob __frobnicator = {
+ *      ...
+ *   };
+ *
+ *   unsigned int my_frob_idx = table_index ( FROBNICATORS, &my_frob );
+ *
+ * @endcode
+ */
+#define table_index( table, entry )					\
+	( ( unsigned int ) ( (entry) - table_start ( table ) ) )
+
+/**
+ * Iterate through all entries within a linker table
+ *
+ * @v pointer		Entry pointer
+ * @v table		Linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   struct frobnicator *frob;
+ *
+ *   for_each_table_entry ( frob, FROBNICATORS ) {
+ *     ...
+ *   }
+ *
+ * @endcode
+ *
+ */
+#define for_each_table_entry( pointer, table )				\
+	for ( pointer = table_start ( table ) ;				\
+	      pointer < table_end ( table ) ;				\
+	      pointer++ )
+
+/**
+ * Iterate through all remaining entries within a linker table
+ *
+ * @v pointer		Entry pointer, preset to most recent entry
+ * @v table		Linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *   #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ *   struct frob my_frobnicator __frobnicator;
+ *   struct frobnicator *frob;
+ *
+ *   frob = &my_frobnicator;
+ *   for_each_table_entry_continue ( frob, FROBNICATORS ) {
+ *     ...
+ *   }
+ *
+ * @endcode
+ *
+ */
+#define for_each_table_entry_continue( pointer, table )			\
+	for ( pointer++ ;						\
+	      pointer < table_end ( table ) ;				\
+	      pointer++ )
+
+/**
+ * Iterate through all entries within a linker table in reverse order
+ *
+ * @v pointer		Entry pointer
+ * @v table		Linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ *   struct frobnicator *frob;
+ *
+ *   for_each_table_entry_reverse ( frob, FROBNICATORS ) {
+ *     ...
+ *   }
+ *
+ * @endcode
+ *
+ */
+#define for_each_table_entry_reverse( pointer, table )			\
+	for ( pointer = ( table_end ( table ) - 1 ) ;			\
+	      pointer >= table_start ( table ) ;			\
+	      pointer-- )
+
+/**
+ * Iterate through all remaining entries within a linker table in reverse order
+ *
+ * @v pointer		Entry pointer, preset to most recent entry
+ * @v table		Linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ *   #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *   #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ *   struct frob my_frobnicator __frobnicator;
+ *   struct frobnicator *frob;
+ *
+ *   frob = &my_frobnicator;
+ *   for_each_table_entry_continue_reverse ( frob, FROBNICATORS ) {
+ *     ...
+ *   }
+ *
+ * @endcode
+ *
+ */
+#define for_each_table_entry_continue_reverse( pointer, table )		\
+	for ( pointer-- ;						\
+	      pointer >= table_start ( table ) ;			\
+	      pointer-- )
+
+/******************************************************************************
+ *
+ * Intel's C compiler chokes on several of the constructs used in this
+ * file.  The workarounds are ugly, so we use them only for an icc
+ * build.
+ *
+ */
+#define ICC_ALIGN_HACK_FACTOR 128
+#ifdef __ICC
+
+/*
+ * icc miscompiles zero-length arrays by inserting padding to a length
+ * of two array elements.  We therefore have to generate the
+ * __table_entries() symbols by hand in asm.
+ *
+ */
+#undef __table_entries
+#define __table_entries( table, idx ) ( {				\
+	extern __table_type ( table )					\
+		__table_temp_sym ( idx, __LINE__ ) []			\
+		__table_entry ( table, idx ) 				\
+		asm ( __table_entries_sym ( table, idx ) );		\
+	__asm__ ( ".ifndef %c0\n\t"					\
+		  ".section " __table_section ( table, idx ) "\n\t"	\
+		  ".align %c1\n\t"					\
+	          "\n%c0:\n\t"						\
+		  ".previous\n\t" 					\
+		  ".endif\n\t"						\
+		  : : "i" ( __table_temp_sym ( idx, __LINE__ ) ),	\
+		      "i" ( __table_alignment ( table ) ) );		\
+	__table_temp_sym ( idx, __LINE__ ); } )
+#define __table_entries_sym( table, idx )				\
+	"__tbl_" __table_name ( table ) "_" #idx
+#define __table_temp_sym( a, b )					\
+	___table_temp_sym( __table_, a, _, b )
+#define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d
+
+/*
+ * icc ignores __attribute__ (( aligned (x) )) when it is used to
+ * decrease the compiler's default choice of alignment (which may be
+ * higher than the alignment actually required by the structure).  We
+ * work around this by forcing the alignment to a large multiple of
+ * the required value (so that we are never attempting to decrease the
+ * default alignment) and then postprocessing the object file to
+ * reduce the alignment back down to the "real" value.
+ *
+ */
+#undef __table_alignment
+#define __table_alignment( table ) \
+	( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) )
+
+/*
+ * Because of the alignment hack, we must ensure that the compiler
+ * never tries to place multiple objects within the same section,
+ * otherwise the assembler will insert padding to the (incorrect)
+ * alignment boundary.  Do this by appending the line number to table
+ * section names.
+ *
+ * Note that we don't need to worry about padding between array
+ * elements, since the alignment is declared on the variable (i.e. the
+ * whole array) rather than on the type (i.e. on all individual array
+ * elements).
+ */
+#undef __table_section
+#define __table_section( table, idx ) \
+	".tbl." __table_name ( table ) "." __table_str ( idx ) \
+	"." __table_xstr ( __LINE__ )
+#define __table_xstr( x ) __table_str ( x )
+
+#endif /* __ICC */
+
+#endif /* _IPXE_TABLES_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcp.h
new file mode 100644
index 0000000..197712b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcp.h
@@ -0,0 +1,342 @@
+#ifndef _IPXE_TCP_H
+#define _IPXE_TCP_H
+
+/** @file
+ *
+ * TCP protocol
+ *
+ * This file defines the iPXE TCP API.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tcpip.h>
+
+/**
+ * A TCP header
+ */
+struct tcp_header {
+	uint16_t src;		/* Source port */
+	uint16_t dest;		/* Destination port */
+	uint32_t seq;		/* Sequence number */
+	uint32_t ack;		/* Acknowledgement number */
+	uint8_t hlen;		/* Header length (4), Reserved (4) */
+	uint8_t flags;		/* Reserved (2), Flags (6) */
+	uint16_t win;		/* Advertised window */
+	uint16_t csum;		/* Checksum */
+	uint16_t urg;		/* Urgent pointer */
+};
+
+/** @defgroup tcpopts TCP options
+ * @{
+ */
+
+/** End of TCP options list */
+#define TCP_OPTION_END 0
+
+/** TCP option pad */
+#define TCP_OPTION_NOP 1
+
+/** Generic TCP option */
+struct tcp_option {
+	uint8_t kind;
+	uint8_t length;
+} __attribute__ (( packed ));
+
+/** TCP MSS option */
+struct tcp_mss_option {
+	uint8_t kind;
+	uint8_t length;
+	uint16_t mss;
+} __attribute__ (( packed ));
+
+/** Code for the TCP MSS option */
+#define TCP_OPTION_MSS 2
+
+/** TCP timestamp option */
+struct tcp_timestamp_option {
+	uint8_t kind;
+	uint8_t length;
+	uint32_t tsval;
+	uint32_t tsecr;
+} __attribute__ (( packed ));
+
+/** Padded TCP timestamp option (used for sending) */
+struct tcp_timestamp_padded_option {
+	uint8_t nop[2];
+	struct tcp_timestamp_option tsopt;
+} __attribute__ (( packed ));
+
+/** Code for the TCP timestamp option */
+#define TCP_OPTION_TS 8
+
+/** Parsed TCP options */
+struct tcp_options {
+	/** MSS option, if present */
+	const struct tcp_mss_option *mssopt;
+	/** Timestampe option, if present */
+	const struct tcp_timestamp_option *tsopt;
+};
+
+/** @} */
+
+/*
+ * TCP flags
+ */
+#define TCP_CWR		0x80
+#define TCP_ECE		0x40
+#define TCP_URG		0x20
+#define TCP_ACK		0x10
+#define TCP_PSH		0x08
+#define TCP_RST		0x04
+#define TCP_SYN		0x02
+#define TCP_FIN		0x01
+
+/**
+* @defgroup tcpstates TCP states
+*
+* The TCP state is defined by a combination of the flags that have
+* been sent to the peer, the flags that have been acknowledged by the
+* peer, and the flags that have been received from the peer.
+*
+* @{
+*/
+
+/** TCP flags that have been sent in outgoing packets */
+#define TCP_STATE_SENT(flags) ( (flags) << 0 )
+#define TCP_FLAGS_SENT(state) ( ( (state) >> 0 ) & 0xff )
+
+/** TCP flags that have been acknowledged by the peer
+ *
+ * Note that this applies only to SYN and FIN.
+ */
+#define TCP_STATE_ACKED(flags) ( (flags) << 8 )
+#define TCP_FLAGS_ACKED(state) ( ( (state) >> 8 ) & 0xff )
+
+/** TCP flags that have been received from the peer
+ *
+ * Note that this applies only to SYN and FIN, and that once SYN has
+ * been received, we should always be sending ACK.
+ */
+#define TCP_STATE_RCVD(flags) ( (flags) << 16 )
+#define TCP_FLAGS_RCVD(state) ( ( (state) >> 16 ) & 0xff )
+
+/** TCP flags that are currently being sent in outgoing packets */
+#define TCP_FLAGS_SENDING(state) \
+	( TCP_FLAGS_SENT ( state ) & ~TCP_FLAGS_ACKED ( state ) )
+
+/** CLOSED
+ *
+ * The connection has not yet been used for anything.
+ */
+#define TCP_CLOSED TCP_RST
+
+/** LISTEN
+ *
+ * Not currently used as a state; we have no support for listening
+ * connections.  Given a unique value to avoid compiler warnings.
+ */
+#define TCP_LISTEN 0
+
+/** SYN_SENT
+ *
+ * SYN has been sent, nothing has yet been received or acknowledged.
+ */
+#define TCP_SYN_SENT	( TCP_STATE_SENT ( TCP_SYN ) )
+
+/** SYN_RCVD
+ *
+ * SYN has been sent but not acknowledged, SYN has been received.
+ */
+#define TCP_SYN_RCVD	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) |	    \
+			  TCP_STATE_RCVD ( TCP_SYN ) )
+
+/** ESTABLISHED
+ *
+ * SYN has been sent and acknowledged, SYN has been received.
+ */
+#define TCP_ESTABLISHED	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) |	    \
+			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			  TCP_STATE_RCVD ( TCP_SYN ) )
+
+/** FIN_WAIT_1
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent but not acknowledged, FIN has not been received.
+ *
+ * RFC 793 shows that we can enter FIN_WAIT_1 without have had SYN
+ * acknowledged, i.e. if the application closes the connection after
+ * sending and receiving SYN, but before having had SYN acknowledged.
+ * However, we have to *pretend* that SYN has been acknowledged
+ * anyway, otherwise we end up sending SYN and FIN in the same
+ * sequence number slot.  Therefore, when we transition from SYN_RCVD
+ * to FIN_WAIT_1, we have to remember to set TCP_STATE_ACKED(TCP_SYN)
+ * and increment our sequence number.
+ */
+#define TCP_FIN_WAIT_1	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			  TCP_STATE_RCVD ( TCP_SYN ) )
+
+/** FIN_WAIT_2
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent and acknowledged, FIN ha not been received.
+ */
+#define TCP_FIN_WAIT_2	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_STATE_RCVD ( TCP_SYN ) )
+
+/** CLOSING / LAST_ACK
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent but not acknowledged, FIN has been received.
+ *
+ * This state actually encompasses both CLOSING and LAST_ACK; they are
+ * identical with the definition of state that we use.  I don't
+ * *believe* that they need to be distinguished.
+ */
+#define TCP_CLOSING_OR_LAST_ACK						    \
+			( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
+
+/** TIME_WAIT
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent and acknowledged, FIN has been received.
+ */
+#define TCP_TIME_WAIT	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
+
+/** CLOSE_WAIT
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been received.
+ */
+#define TCP_CLOSE_WAIT	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) |	    \
+			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
+
+/** Can send data in current state
+ *
+ * We can send data if and only if we have had our SYN acked and we
+ * have not yet sent our FIN.
+ */
+#define TCP_CAN_SEND_DATA(state)					    \
+	( ( (state) & ( TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			TCP_STATE_SENT ( TCP_FIN ) ) )			    \
+	  == TCP_STATE_ACKED ( TCP_SYN ) )
+
+/** Have ever been fully established
+ *
+ * We have been fully established if we have both received a SYN and
+ * had our own SYN acked.
+ */
+#define TCP_HAS_BEEN_ESTABLISHED(state)					    \
+	( ( (state) & ( TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			TCP_STATE_RCVD ( TCP_SYN ) ) )			    \
+	  == ( TCP_STATE_ACKED ( TCP_SYN ) | TCP_STATE_RCVD ( TCP_SYN ) ) )
+
+/** Have closed gracefully
+ *
+ * We have closed gracefully if we have both received a FIN and had
+ * our own FIN acked.
+ */
+#define TCP_CLOSED_GRACEFULLY(state)					    \
+	( ( (state) & ( TCP_STATE_ACKED ( TCP_FIN ) |			    \
+			TCP_STATE_RCVD ( TCP_FIN ) ) )			    \
+	  == ( TCP_STATE_ACKED ( TCP_FIN ) | TCP_STATE_RCVD ( TCP_FIN ) ) )
+
+/** @} */
+
+/** Mask for TCP header length field */
+#define TCP_MASK_HLEN	0xf0
+
+/** Smallest port number on which a TCP connection can listen */
+#define TCP_MIN_PORT 1
+
+/**
+ * Maxmimum advertised TCP window size
+ *
+ * We estimate the TCP window size as the amount of free memory we
+ * have.  This is not strictly accurate (since it ignores any space
+ * already allocated as RX buffers), but it will do for now.
+ *
+ * Since we don't store out-of-order received packets, the
+ * retransmission penalty is that the whole window contents must be
+ * resent.  This suggests keeping the window size small, but bear in
+ * mind that the maximum bandwidth on any link is limited to
+ *
+ *    max_bandwidth = ( tcp_window / round_trip_time )
+ *
+ * With a 48kB window, which probably accurately reflects our amount
+ * of free memory, and a WAN RTT of say 200ms, this gives a maximum
+ * bandwidth of 240kB/s.  This is sufficiently close to realistic that
+ * we will need to be careful that our advertised window doesn't end
+ * up limiting WAN download speeds.
+ *
+ * Finally, since the window goes into a 16-bit field and we cannot
+ * actually use 65536, we use a window size of (65536-4) to ensure
+ * that payloads remain dword-aligned.
+ */
+//#define TCP_MAX_WINDOW_SIZE	( 65536 - 4 )
+#define TCP_MAX_WINDOW_SIZE	8192
+
+/**
+ * Path MTU
+ *
+ * We really ought to implement Path MTU discovery.  Until we do,
+ * anything with a path MTU greater than this may fail.
+ */
+#define TCP_PATH_MTU 1460
+
+/**
+ * Advertised TCP MSS
+ *
+ * We currently hardcode this to a reasonable value and hope that the
+ * sender uses path MTU discovery.  The alternative is breaking the
+ * abstraction layer so that we can find out the MTU from the IP layer
+ * (which would have to find out from the net device layer).
+ */
+#define TCP_MSS 1460
+
+/** TCP maximum segment lifetime
+ *
+ * Currently set to 2 minutes, as per RFC 793.
+ */
+#define TCP_MSL ( 2 * 60 * TICKS_PER_SEC )
+
+/**
+ * Compare TCP sequence numbers
+ *
+ * @v seq1		Sequence number 1
+ * @v seq2		Sequence number 2
+ * @ret diff		Sequence difference
+ *
+ * Analogous to memcmp(), returns an integer less than, equal to, or
+ * greater than zero if @c seq1 is found, respectively, to be before,
+ * equal to, or after @c seq2.
+ */
+static inline __attribute__ (( always_inline )) int32_t
+tcp_cmp ( uint32_t seq1, uint32_t seq2 ) {
+	return ( ( int32_t ) ( seq1 - seq2 ) );
+}
+
+/**
+ * Check if TCP sequence number lies within window
+ *
+ * @v seq		Sequence number
+ * @v start		Start of window
+ * @v len		Length of window
+ * @ret in_window	Sequence number is within window
+ */
+static inline int tcp_in_window ( uint32_t seq, uint32_t start,
+				  uint32_t len ) {
+	return ( ( seq - start ) < len );
+}
+
+extern struct tcpip_protocol tcp_protocol __tcpip_protocol;
+
+#endif /* _IPXE_TCP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcpip.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcpip.h
new file mode 100644
index 0000000..cdf554e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tcpip.h
@@ -0,0 +1,128 @@
+#ifndef _IPXE_TCPIP_H
+#define _IPXE_TCPIP_H
+
+/** @file
+ *
+ * Transport-network layer interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/socket.h>
+#include <ipxe/in.h>
+#include <ipxe/tables.h>
+
+struct io_buffer;
+struct net_device;
+
+/** Empty checksum value
+ *
+ * This is the TCP/IP checksum over a zero-length block of data.
+ */
+#define TCPIP_EMPTY_CSUM 0xffff
+
+/**
+ * TCP/IP socket address
+ *
+ * This contains the fields common to socket addresses for all TCP/IP
+ * address families.
+ */
+struct sockaddr_tcpip {
+	/** Socket address family (part of struct @c sockaddr) */
+	sa_family_t st_family;
+	/** TCP/IP port */
+	uint16_t st_port;
+	/** Padding
+	 *
+	 * This ensures that a struct @c sockaddr_tcpip is large
+	 * enough to hold a socket address for any TCP/IP address
+	 * family.
+	 */
+	char pad[ sizeof ( struct sockaddr ) -
+		  ( sizeof ( sa_family_t ) + sizeof ( uint16_t ) ) ];
+} __attribute__ (( may_alias ));
+
+/** 
+ * A transport-layer protocol of the TCP/IP stack (eg. UDP, TCP, etc)
+ */
+struct tcpip_protocol {
+	/** Protocol name */
+	const char *name;
+       	/**
+         * Process received packet
+         *
+         * @v iobuf		I/O buffer
+	 * @v st_src		Partially-filled source address
+	 * @v st_dest		Partially-filled destination address
+	 * @v pshdr_csum	Pseudo-header checksum
+	 * @ret rc		Return status code
+         *
+         * This method takes ownership of the I/O buffer.
+         */
+        int ( * rx ) ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+		       struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
+        /** 
+	 * Transport-layer protocol number
+	 *
+	 * This is a constant of the type IP_XXX
+         */
+        uint8_t tcpip_proto;
+};
+
+/**
+ * A network-layer protocol of the TCP/IP stack (eg. IPV4, IPv6, etc)
+ */
+struct tcpip_net_protocol {
+	/** Protocol name */
+	const char *name;
+	/** Network address family */
+	sa_family_t sa_family;
+	/**
+	 * Transmit packet
+	 *
+	 * @v iobuf		I/O buffer
+	 * @v tcpip_protocol	Transport-layer protocol
+	 * @v st_src		Source address, or NULL to use default
+	 * @v st_dest		Destination address
+	 * @v netdev		Network device (or NULL to route automatically)
+	 * @v trans_csum	Transport-layer checksum to complete, or NULL
+	 * @ret rc		Return status code
+	 *
+	 * This function takes ownership of the I/O buffer.
+	 */
+	int ( * tx ) ( struct io_buffer *iobuf,
+		       struct tcpip_protocol *tcpip_protocol,
+		       struct sockaddr_tcpip *st_src,
+		       struct sockaddr_tcpip *st_dest,
+		       struct net_device *netdev,
+		       uint16_t *trans_csum );
+};
+
+/** TCP/IP transport-layer protocol table */
+#define TCPIP_PROTOCOLS __table ( struct tcpip_protocol, "tcpip_protocols" )
+
+/** Declare a TCP/IP transport-layer protocol */
+#define __tcpip_protocol __table_entry ( TCPIP_PROTOCOLS, 01 )
+
+/** TCP/IP network-layer protocol table */
+#define TCPIP_NET_PROTOCOLS \
+	__table ( struct tcpip_net_protocol, "tcpip_net_protocols" )
+
+/** Declare a TCP/IP network-layer protocol */
+#define __tcpip_net_protocol __table_entry ( TCPIP_NET_PROTOCOLS, 01 )
+
+extern int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
+		      struct sockaddr_tcpip *st_src,
+		      struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
+extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+		      struct sockaddr_tcpip *st_src,
+		      struct sockaddr_tcpip *st_dest,
+		      struct net_device *netdev,
+		      uint16_t *trans_csum );
+extern uint16_t tcpip_continue_chksum ( uint16_t partial,
+					const void *data, size_t len );
+extern uint16_t tcpip_chksum ( const void *data, size_t len );
+
+#endif /* _IPXE_TCPIP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/tftp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tftp.h
new file mode 100644
index 0000000..38be0d4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tftp.h
@@ -0,0 +1,85 @@
+#ifndef	_IPXE_TFTP_H
+#define	_IPXE_TFTP_H
+
+/** @file
+ *
+ * TFTP protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+#define TFTP_PORT	       69 /**< Default TFTP server port */
+#define	TFTP_DEFAULT_BLKSIZE  512 /**< Default TFTP data block size */
+#define	TFTP_MAX_BLKSIZE     1432
+
+#define TFTP_RRQ		1 /**< Read request opcode */
+#define TFTP_WRQ		2 /**< Write request opcode */
+#define TFTP_DATA		3 /**< Data block opcode */
+#define TFTP_ACK		4 /**< Data block acknowledgement opcode */
+#define TFTP_ERROR		5 /**< Error opcode */
+#define TFTP_OACK		6 /**< Options acknowledgement opcode */
+
+#define TFTP_ERR_FILE_NOT_FOUND	1 /**< File not found */
+#define TFTP_ERR_ACCESS_DENIED	2 /**< Access violation */
+#define TFTP_ERR_DISK_FULL	3 /**< Disk full or allocation exceeded */
+#define TFTP_ERR_ILLEGAL_OP	4 /**< Illegal TFTP operation */
+#define TFTP_ERR_UNKNOWN_TID	5 /**< Unknown transfer ID */
+#define TFTP_ERR_FILE_EXISTS	6 /**< File already exists */
+#define TFTP_ERR_UNKNOWN_USER	7 /**< No such user */
+#define TFTP_ERR_BAD_OPTS	8 /**< Option negotiation failed */
+
+#define MTFTP_PORT	     1759 /**< Default MTFTP server port */
+
+/** A TFTP read request (RRQ) packet */
+struct tftp_rrq {
+	uint16_t opcode;
+	char data[0];
+} __attribute__ (( packed ));
+
+/** A TFTP data (DATA) packet */
+struct tftp_data {
+	uint16_t opcode;
+	uint16_t block;
+	uint8_t data[0];
+} __attribute__ (( packed ));
+ 
+/** A TFTP acknowledgement (ACK) packet */
+struct tftp_ack {
+	uint16_t opcode;
+	uint16_t block;
+} __attribute__ (( packed ));
+
+/** A TFTP error (ERROR) packet */
+struct tftp_error {
+	uint16_t opcode;
+	uint16_t errcode;
+	char errmsg[0];
+} __attribute__ (( packed ));
+
+/** A TFTP options acknowledgement (OACK) packet */
+struct tftp_oack {
+	uint16_t opcode;
+	char data[0];
+} __attribute__ (( packed ));
+
+/** The common header of all TFTP packets */
+struct tftp_common {
+	uint16_t opcode;
+} __attribute__ (( packed ));
+
+/** A union encapsulating all TFTP packet types */
+union tftp_any {
+	struct tftp_common	common;
+	struct tftp_rrq		rrq;
+	struct tftp_data	data;
+	struct tftp_ack		ack;
+	struct tftp_error	error;
+	struct tftp_oack	oack;
+};
+
+extern void tftp_set_request_blksize ( unsigned int blksize );
+
+#endif /* _IPXE_TFTP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/threewire.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/threewire.h
new file mode 100644
index 0000000..135ef56
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/threewire.h
@@ -0,0 +1,105 @@
+#ifndef _IPXE_THREEWIRE_H
+#define _IPXE_THREEWIRE_H
+
+/** @file
+ *
+ * Three-wire serial interface
+ *
+ * The Atmel three-wire interface is a subset of the (newer) SPI
+ * interface, and is implemented here as a layer on top of the SPI
+ * support.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/spi.h>
+#include <limits.h>
+
+/**
+ * @defgroup tcmds Three-wire commands
+ * @{
+ */
+
+/** Read data from memory array */
+#define THREEWIRE_READ 0x6
+
+/** Write data to memory array */
+#define THREEWIRE_WRITE 0x5
+
+/** Write enable */
+#define THREEWIRE_EWEN 0x4
+
+/** Address to be used for write enable command */
+#define THREEWIRE_EWEN_ADDRESS INT_MAX
+
+/** Time to wait for write cycles to complete
+ *
+ * This is sufficient for AT93C46/AT93C56 devices, but may need to be
+ * increased in future when other devices are added.
+ */
+#define THREEWIRE_WRITE_MDELAY 10
+
+/** @} */
+
+extern int threewire_read ( struct nvs_device *nvs, unsigned int address,
+			    void *data, size_t len );
+extern int threewire_write ( struct nvs_device *nvs, unsigned int address,
+			     const void *data, size_t len );
+extern int threewire_detect_address_len ( struct spi_device *device );
+
+/**
+ * @defgroup tdevs Three-wire device types
+ * @{
+ */
+
+static inline __attribute__ (( always_inline )) void
+init_at93cx6 ( struct spi_device *device, unsigned int organisation ) {
+	device->nvs.word_len_log2 = ( ( organisation == 8 ) ? 0 : 1 );
+	device->nvs.block_size = 1;
+	device->command_len = 3,
+	device->nvs.read = threewire_read;
+	device->nvs.write = threewire_write;
+}
+
+/**
+ * Initialise Atmel AT93C46 serial EEPROM
+ *
+ * @v device		SPI device
+ * @v organisation	Word organisation (8 or 16)
+ */
+static inline __attribute__ (( always_inline )) void
+init_at93c46 ( struct spi_device *device, unsigned int organisation ) {
+	device->nvs.size = ( 1024 / organisation );
+	device->address_len = ( ( organisation == 8 ) ? 7 : 6 );
+	init_at93cx6 ( device, organisation );
+}
+
+/**
+ * Initialise Atmel AT93C56 serial EEPROM
+ *
+ * @v device		SPI device
+ * @v organisation	Word organisation (8 or 16)
+ */
+static inline __attribute__ (( always_inline )) void
+init_at93c56 ( struct spi_device *device, unsigned int organisation ) {
+	device->nvs.size = ( 2048 / organisation );
+	device->address_len = ( ( organisation == 8 ) ? 9 : 8 );
+	init_at93cx6 ( device, organisation );
+}
+
+/**
+ * Initialise Atmel AT93C66 serial EEPROM
+ *
+ * @v device		SPI device
+ * @v organisation	Word organisation (8 or 16)
+ */
+static inline __attribute__ (( always_inline )) void
+init_at93c66 ( struct spi_device *device, unsigned int organisation ) {
+	device->nvs.size = ( 4096 / organisation );
+	device->address_len = ( ( organisation == 8 ) ? 9 : 8 );
+	init_at93cx6 ( device, organisation );
+}
+
+/** @} */
+
+#endif /* _IPXE_THREEWIRE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/timer.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/timer.h
new file mode 100644
index 0000000..d030965
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/timer.h
@@ -0,0 +1,77 @@
+#ifndef	_IPXE_TIMER_H
+#define _IPXE_TIMER_H
+
+/** @file
+ *
+ * iPXE timer API
+ *
+ * The timer API provides udelay() for fixed delays, and currticks()
+ * for a monotonically increasing tick counter.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/api.h>
+#include <config/timer.h>
+
+/**
+ * Calculate static inline timer API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define TIMER_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a timer API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline timer API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <ipxe/efi/efi_timer.h>
+#include <ipxe/linux/linux_timer.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/timer.h>
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs		Number of microseconds for which to delay
+ */
+void udelay ( unsigned long usecs );
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks		Current time, in ticks
+ */
+unsigned long currticks ( void );
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec	Number of ticks per second
+ */
+unsigned long ticks_per_sec ( void );
+
+/** Number of ticks per second */
+#define TICKS_PER_SEC ( ticks_per_sec() )
+
+#endif /* _IPXE_TIMER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/tls.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tls.h
new file mode 100644
index 0000000..94cd322
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/tls.h
@@ -0,0 +1,187 @@
+#ifndef _IPXE_TLS_H
+#define _IPXE_TLS_H
+
+/**
+ * @file
+ *
+ * Transport Layer Security Protocol
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/interface.h>
+#include <ipxe/process.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/x509.h>
+
+/** A TLS header */
+struct tls_header {
+	/** Content type
+	 *
+	 * This is a TLS_TYPE_XXX constant
+	 */
+	uint8_t type;
+	/** Protocol version
+	 *
+	 * This is a TLS_VERSION_XXX constant
+	 */
+	uint16_t version;
+	/** Length of payload */
+	uint16_t length;
+} __attribute__ (( packed ));
+
+/** TLS version 1.0 */
+#define TLS_VERSION_TLS_1_0 0x0301
+
+/** TLS version 1.1 */
+#define TLS_VERSION_TLS_1_1 0x0302
+
+/** Change cipher content type */
+#define TLS_TYPE_CHANGE_CIPHER 20
+
+/** Alert content type */
+#define TLS_TYPE_ALERT 21
+
+/** Handshake content type */
+#define TLS_TYPE_HANDSHAKE 22
+
+/** Application data content type */
+#define TLS_TYPE_DATA 23
+
+/* Handshake message types */
+#define TLS_HELLO_REQUEST 0
+#define TLS_CLIENT_HELLO 1
+#define TLS_SERVER_HELLO 2
+#define TLS_CERTIFICATE 11
+#define TLS_SERVER_KEY_EXCHANGE 12
+#define TLS_CERTIFICATE_REQUEST 13
+#define TLS_SERVER_HELLO_DONE 14
+#define TLS_CERTIFICATE_VERIFY 15
+#define TLS_CLIENT_KEY_EXCHANGE 16
+#define TLS_FINISHED 20
+
+/* TLS alert levels */
+#define TLS_ALERT_WARNING 1
+#define TLS_ALERT_FATAL 2
+
+/* TLS cipher specifications */
+#define TLS_RSA_WITH_NULL_MD5 0x0001
+#define TLS_RSA_WITH_NULL_SHA 0x0002
+#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f
+#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
+
+/** TLS RX state machine state */
+enum tls_rx_state {
+	TLS_RX_HEADER = 0,
+	TLS_RX_DATA,
+};
+
+/** TLS TX state machine state */
+enum tls_tx_state {
+	TLS_TX_NONE = 0,
+	TLS_TX_CLIENT_HELLO,
+	TLS_TX_CLIENT_KEY_EXCHANGE,
+	TLS_TX_CHANGE_CIPHER,
+	TLS_TX_FINISHED,
+	TLS_TX_DATA
+};
+
+/** A TLS cipher specification */
+struct tls_cipherspec {
+	/** Public-key encryption algorithm */
+	struct pubkey_algorithm *pubkey;
+	/** Bulk encryption cipher algorithm */
+	struct cipher_algorithm *cipher;
+	/** MAC digest algorithm */
+	struct digest_algorithm *digest;
+	/** Key length */
+	size_t key_len;
+	/** Dynamically-allocated storage */
+	void *dynamic;
+	/** Public key encryption context */
+	void *pubkey_ctx;
+	/** Bulk encryption cipher context */
+	void *cipher_ctx;
+	/** Next bulk encryption cipher context (TX only) */
+	void *cipher_next_ctx;
+	/** MAC secret */
+	void *mac_secret;
+};
+
+/** TLS pre-master secret */
+struct tls_pre_master_secret {
+	/** TLS version */
+	uint16_t version;
+	/** Random data */
+	uint8_t random[46];
+} __attribute__ (( packed ));
+
+/** TLS client random data */
+struct tls_client_random {
+	/** GMT Unix time */
+	uint32_t gmt_unix_time;
+	/** Random data */
+	uint8_t random[28];
+} __attribute__ (( packed ));
+
+/** A TLS session */
+struct tls_session {
+	/** Reference counter */
+	struct refcnt refcnt;
+
+	/** Plaintext stream */
+	struct interface plainstream;
+	/** Ciphertext stream */
+	struct interface cipherstream;
+
+	/** Current TX cipher specification */
+	struct tls_cipherspec tx_cipherspec;
+	/** Next TX cipher specification */
+	struct tls_cipherspec tx_cipherspec_pending;
+	/** Current RX cipher specification */
+	struct tls_cipherspec rx_cipherspec;
+	/** Next RX cipher specification */
+	struct tls_cipherspec rx_cipherspec_pending;
+	/** Premaster secret */
+	struct tls_pre_master_secret pre_master_secret;
+	/** Master secret */
+	uint8_t master_secret[48];
+	/** Server random bytes */
+	uint8_t server_random[32];
+	/** Client random bytes */
+	struct tls_client_random client_random;
+	/** MD5 context for handshake verification */
+	uint8_t handshake_md5_ctx[MD5_CTX_SIZE];
+	/** SHA1 context for handshake verification */
+	uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE];
+
+	/** Hack: server RSA public key */
+	struct x509_rsa_public_key rsa;
+
+	/** TX sequence number */
+	uint64_t tx_seq;
+	/** TX state */
+	enum tls_tx_state tx_state;
+	/** TX process */
+	struct process process;
+
+	/** RX sequence number */
+	uint64_t rx_seq;
+	/** RX state */
+	enum tls_rx_state rx_state;
+	/** Offset within current RX state */
+	size_t rx_rcvd;
+	/** Current received record header */
+	struct tls_header rx_header;
+	/** Current received raw data buffer */
+	void *rx_data;
+};
+
+extern int add_tls ( struct interface *xfer,
+		     struct interface **next );
+
+#endif /* _IPXE_TLS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/uaccess.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uaccess.h
new file mode 100644
index 0000000..b574c31
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uaccess.h
@@ -0,0 +1,345 @@
+#ifndef _IPXE_UACCESS_H
+#define _IPXE_UACCESS_H
+
+/**
+ * @file
+ *
+ * Access to external ("user") memory
+ *
+ * iPXE often needs to transfer data between internal and external
+ * buffers.  On i386, the external buffers may require access via a
+ * different segment, and the buffer address cannot be encoded into a
+ * simple void * pointer.  The @c userptr_t type encapsulates the
+ * information needed to identify an external buffer, and the
+ * copy_to_user() and copy_from_user() functions provide methods for
+ * transferring data between internal and external buffers.
+ *
+ * Note that userptr_t is an opaque type; in particular, performing
+ * arithmetic upon a userptr_t is not allowed.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * A pointer to a user buffer
+ *
+ */
+typedef unsigned long userptr_t;
+
+/** Equivalent of NULL for user pointers */
+#define UNULL ( ( userptr_t ) 0 )
+
+/**
+ * @defgroup uaccess_trivial Trivial user access API implementations
+ *
+ * User access API implementations that can be used by environments in
+ * which virtual addresses allow access to all of memory.
+ *
+ * @{
+ *
+ */
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr		Virtual address
+ * @ret userptr		User pointer
+ */
+static inline __always_inline userptr_t
+trivial_virt_to_user ( volatile const void *addr ) {
+	return ( ( userptr_t ) addr );
+}
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset from user pointer
+ * @ret addr		Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void *
+trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
+	return ( ( void * ) userptr + offset );
+}
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset
+ * @ret userptr		New pointer value
+ */
+static inline __always_inline userptr_t
+trivial_userptr_add ( userptr_t userptr, off_t offset ) {
+	return ( userptr + offset );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest		Destination
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+static inline __always_inline void
+trivial_memcpy_user ( userptr_t dest, off_t dest_off,
+		      userptr_t src, off_t src_off, size_t len ) {
+	memcpy ( ( ( void * ) dest + dest_off ),
+		 ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest		Destination
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+static inline __always_inline void
+trivial_memmove_user ( userptr_t dest, off_t dest_off,
+		       userptr_t src, off_t src_off, size_t len ) {
+	memmove ( ( ( void * ) dest + dest_off ),
+		  ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v buffer		User buffer
+ * @v offset		Offset within buffer
+ * @v c			Constant byte with which to fill
+ * @v len		Length
+ */
+static inline __always_inline void
+trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+	memset ( ( ( void * ) buffer + offset ), c, len );
+}
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v buffer		User buffer
+ * @v offset		Offset within buffer
+ * @ret len		Length of string (excluding NUL)
+ */
+static inline __always_inline size_t
+trivial_strlen_user ( userptr_t buffer, off_t offset ) {
+	return strlen ( ( void * ) buffer + offset );
+}
+
+/**
+ * Find character in user buffer
+ *
+ * @v buffer		User buffer
+ * @v offset		Starting offset within buffer
+ * @v c			Character to search for
+ * @v len		Length of user buffer
+ * @ret offset		Offset of character, or <0 if not found
+ */
+static inline __always_inline off_t
+trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+	void *found;
+
+	found = memchr ( ( ( void * ) buffer + offset ), c, len );
+	return ( found ? ( found - ( void * ) buffer ) : -1 );
+}
+
+/** @} */
+
+/**
+ * Calculate static inline user access API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define UACCESS_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an user access API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline user access API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent user access API headers */
+#include <ipxe/efi/efi_uaccess.h>
+#include <ipxe/linux/linux_uaccess.h>
+
+/* Include all architecture-dependent user access API headers */
+#include <bits/uaccess.h>
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr		Physical address
+ * @ret userptr		User pointer
+ */
+userptr_t phys_to_user ( unsigned long phys_addr );
+
+/**
+ * Convert user pointer to physical address
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset from user pointer
+ * @ret phys_addr	Physical address
+ */
+unsigned long user_to_phys ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr		Virtual address
+ * @ret userptr		User pointer
+ */
+userptr_t virt_to_user ( volatile const void *addr );
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset from user pointer
+ * @ret addr		Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+void * user_to_virt ( userptr_t userptr, off_t offset );
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr		User pointer
+ * @v offset		Offset
+ * @ret userptr		New pointer value
+ */
+userptr_t userptr_add ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to a physical address
+ *
+ * @v addr		Virtual address
+ * @ret phys_addr	Physical address
+ */
+static inline __always_inline unsigned long
+virt_to_phys ( volatile const void *addr ) {
+	return user_to_phys ( virt_to_user ( addr ), 0 );
+}
+
+/**
+ * Convert physical address to a virtual address
+ *
+ * @v addr		Virtual address
+ * @ret phys_addr	Physical address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
+	return user_to_virt ( phys_to_user ( phys_addr ), 0 );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest		Destination
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+void memcpy_user ( userptr_t dest, off_t dest_off,
+		   userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Copy data to user buffer
+ *
+ * @v dest		Destination
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v len		Length
+ */
+static inline __always_inline void
+copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
+	memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest		Destination
+ * @v src		Source
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+static inline __always_inline void
+copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
+	memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest		Destination
+ * @v dest_off		Destination offset
+ * @v src		Source
+ * @v src_off		Source offset
+ * @v len		Length
+ */
+void memmove_user ( userptr_t dest, off_t dest_off,
+		    userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v userptr		User buffer
+ * @v offset		Offset within buffer
+ * @v c			Constant byte with which to fill
+ * @v len		Length
+ */
+void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v userptr		User buffer
+ * @v offset		Offset within buffer
+ * @ret len		Length of string (excluding NUL)
+ */
+size_t strlen_user ( userptr_t userptr, off_t offset );
+
+/**
+ * Find character in user buffer
+ *
+ * @v userptr		User buffer
+ * @v offset		Starting offset within buffer
+ * @v c			Character to search for
+ * @v len		Length of user buffer
+ * @ret offset		Offset of character, or <0 if not found
+ */
+off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
+#endif /* _IPXE_UACCESS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/udp.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/udp.h
new file mode 100644
index 0000000..5717ef2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/udp.h
@@ -0,0 +1,45 @@
+#ifndef _IPXE_UDP_H
+#define _IPXE_UDP_H
+
+/** @file
+ *
+ * UDP protocol
+ *
+ * This file defines the iPXE UDP API.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/if_ether.h>
+
+struct interface;
+struct sockaddr;
+
+/**
+ * UDP constants
+ */
+
+/**
+ * A UDP header
+ */
+struct udp_header {
+	/** Source port */
+	uint16_t src;
+	/** Destination port */
+	uint16_t dest;
+	/** Length */
+	uint16_t len;
+	/** Checksum */
+	uint16_t chksum;
+};
+
+extern int udp_open_promisc ( struct interface *xfer );
+extern int udp_open ( struct interface *xfer, struct sockaddr *peer,
+		      struct sockaddr *local );
+
+#endif /* _IPXE_UDP_H */
+
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/umalloc.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/umalloc.h
new file mode 100644
index 0000000..4b25e18
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/umalloc.h
@@ -0,0 +1,69 @@
+#ifndef _IPXE_UMALLOC_H
+#define _IPXE_UMALLOC_H
+
+/**
+ * @file
+ *
+ * User memory allocation
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/api.h>
+#include <config/umalloc.h>
+#include <ipxe/uaccess.h>
+
+/**
+ * Provide a user memory allocation API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_UMALLOC( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func )
+
+/* Include all architecture-independent I/O API headers */
+#include <ipxe/efi/efi_umalloc.h>
+#include <ipxe/linux/linux_umalloc.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/umalloc.h>
+
+/**
+ * Reallocate external memory
+ *
+ * @v userptr		Memory previously allocated by umalloc(), or UNULL
+ * @v new_size		Requested size
+ * @ret userptr		Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+userptr_t urealloc ( userptr_t userptr, size_t new_size );
+
+/**
+ * Allocate external memory
+ *
+ * @v size		Requested size
+ * @ret userptr		Memory, or UNULL
+ *
+ * Memory is guaranteed to be aligned to a page boundary.
+ */
+static inline __always_inline userptr_t umalloc ( size_t size ) {
+	return urealloc ( UNULL, size );
+}
+
+/**
+ * Free external memory
+ *
+ * @v userptr		Memory allocated by umalloc(), or UNULL
+ *
+ * If @c ptr is UNULL, no action is taken.
+ */
+static inline __always_inline void ufree ( userptr_t userptr ) {
+	urealloc ( userptr, 0 );
+}
+
+#endif /* _IPXE_UMALLOC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/uri.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uri.h
new file mode 100644
index 0000000..b7b8b44
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uri.h
@@ -0,0 +1,192 @@
+#ifndef _IPXE_URI_H
+#define _IPXE_URI_H
+
+/** @file
+ *
+ * Uniform Resource Identifiers
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <ipxe/refcnt.h>
+
+/** A Uniform Resource Identifier
+ *
+ * Terminology for this data structure is as per uri(7), except that
+ * "path" is defined to include the leading '/' for an absolute path.
+ *
+ * Note that all fields within a URI are optional and may be NULL.
+ *
+ * The pointers to the various fields are packed together so they can
+ * be accessed in array fashion in some places in uri.c where doing so
+ * saves significant code size.
+ *
+ * Some examples are probably helpful:
+ *
+ *   http://www.ipxe.org/wiki :
+ *
+ *   scheme = "http", host = "www.ipxe.org", path = "/wiki"
+ *
+ *   /var/lib/tftpboot :
+ *
+ *   path = "/var/lib/tftpboot"
+ *
+ *   mailto:bob at nowhere.com :
+ *
+ *   scheme = "mailto", opaque = "bob at nowhere.com"
+ *
+ *   ftp://joe:secret@insecure.org:8081/hidden/path/to?what=is#this
+ *
+ *   scheme = "ftp", user = "joe", password = "secret",
+ *   host = "insecure.org", port = "8081", path = "/hidden/path/to",
+ *   query = "what=is", fragment = "this"
+ */
+struct uri {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Scheme */
+	const char *scheme;
+	/** Opaque part */
+	const char *opaque;
+	/** User name */
+	const char *user;
+	/** Password */
+	const char *password;
+	/** Host name */
+	const char *host;
+	/** Port number */
+	const char *port;
+	/** Path */
+	const char *path;
+	/** Query */
+	const char *query;
+	/** Fragment */
+	const char *fragment;
+} __attribute__ (( packed ));
+
+/** A field in a URI
+ *
+ * The order of the indices in this enumeration must match the order
+ * of the fields in the URI structure.
+ */
+enum {
+	URI_SCHEME = 0,		URI_SCHEME_BIT = ( 1 << URI_SCHEME ),
+	URI_OPAQUE = 1,		URI_OPAQUE_BIT = ( 1 << URI_OPAQUE ),
+	URI_USER = 2,		URI_USER_BIT = ( 1 << URI_USER ),
+	URI_PASSWORD = 3,	URI_PASSWORD_BIT = ( 1 << URI_PASSWORD ),
+	URI_HOST = 4,		URI_HOST_BIT = ( 1 << URI_HOST ),
+	URI_PORT = 5,		URI_PORT_BIT = ( 1 << URI_PORT ),
+	URI_PATH = 6,		URI_PATH_BIT = ( 1 << URI_PATH ),
+	URI_QUERY = 7,		URI_QUERY_BIT = ( 1 << URI_QUERY ),
+	URI_FRAGMENT = 8,	URI_FRAGMENT_BIT = ( 1 << URI_FRAGMENT ),
+
+	URI_FIRST_FIELD = URI_SCHEME,
+	URI_LAST_FIELD = URI_FRAGMENT,
+};
+
+/** Extract field from URI */
+#define uri_get_field( uri, field )	(&uri->scheme)[field]
+
+/** All URI fields */
+#define URI_ALL		( URI_SCHEME_BIT | URI_OPAQUE_BIT | URI_USER_BIT | \
+			  URI_PASSWORD_BIT | URI_HOST_BIT | URI_PORT_BIT | \
+			  URI_PATH_BIT | URI_QUERY_BIT | URI_FRAGMENT_BIT )
+
+/** URI fields that should be decoded on storage */
+#define URI_ENCODED	( URI_USER_BIT | URI_PASSWORD_BIT | URI_HOST_BIT | \
+			  URI_PATH_BIT | URI_QUERY_BIT | URI_FRAGMENT_BIT )
+
+/**
+ * URI is an absolute URI
+ *
+ * @v uri			URI
+ * @ret is_absolute		URI is absolute
+ *
+ * An absolute URI begins with a scheme, e.g. "http:" or "mailto:".
+ * Note that this is a separate concept from a URI with an absolute
+ * path.
+ */
+static inline int uri_is_absolute ( struct uri *uri ) {
+	return ( uri->scheme != NULL );
+}
+
+/**
+ * URI has a path
+ *
+ * @v uri			URI
+ * @ret has_path		URI has a path
+ */
+static inline int uri_has_path ( struct uri *uri ) {
+	return ( uri->path && ( uri->path[0] != '\0' ) );
+}
+
+/**
+ * URI has an absolute path
+ *
+ * @v uri			URI
+ * @ret has_absolute_path	URI has an absolute path
+ *
+ * An absolute path begins with a '/'.  Note that this is a separate
+ * concept from an absolute URI.  Note also that a URI may not have a
+ * path at all.
+ */
+static inline int uri_has_absolute_path ( struct uri *uri ) {
+	return ( uri->path && ( uri->path[0] == '/' ) );
+}
+
+/**
+ * URI has a relative path
+ *
+ * @v uri			URI
+ * @ret has_relative_path	URI has a relative path
+ *
+ * A relative path begins with something other than a '/'.  Note that
+ * this is a separate concept from a relative URI.  Note also that a
+ * URI may not have a path at all.
+ */
+static inline int uri_has_relative_path ( struct uri *uri ) {
+	return ( uri->path && ( uri->path[0] != '/' ) );
+}
+
+/**
+ * Increment URI reference count
+ *
+ * @v uri		URI, or NULL
+ * @ret uri		URI as passed in
+ */
+static inline __attribute__ (( always_inline )) struct uri *
+uri_get ( struct uri *uri ) {
+	ref_get ( &uri->refcnt );
+	return uri;
+}
+
+/**
+ * Decrement URI reference count
+ *
+ * @v uri		URI, or NULL
+ */
+static inline __attribute__ (( always_inline )) void
+uri_put ( struct uri *uri ) {
+	ref_put ( &uri->refcnt );
+}
+
+extern struct uri *cwuri;
+
+extern struct uri * parse_uri ( const char *uri_string );
+extern unsigned int uri_port ( struct uri *uri, unsigned int default_port );
+extern int unparse_uri ( char *buf, size_t size, struct uri *uri,
+			 unsigned int fields );
+extern struct uri * uri_dup ( struct uri *uri );
+extern char * resolve_path ( const char *base_path,
+			     const char *relative_path );
+extern struct uri * resolve_uri ( struct uri *base_uri,
+				  struct uri *relative_uri );
+extern void churi ( struct uri *uri );
+extern size_t uri_encode ( const char *raw_string, char *buf, ssize_t len,
+			   int field );
+extern size_t uri_decode ( const char *encoded_string, char *buf, ssize_t len );
+
+#endif /* _IPXE_URI_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/uuid.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uuid.h
new file mode 100644
index 0000000..2f3c224
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/uuid.h
@@ -0,0 +1,33 @@
+#ifndef _IPXE_UUID_H
+#define _IPXE_UUID_H
+
+/** @file
+ *
+ * Universally unique IDs
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** A universally unique ID */
+union uuid {
+	/** Canonical form (00000000-0000-0000-0000-000000000000) */
+	struct {
+		/** 8 hex digits, big-endian */
+		uint32_t a;
+		/** 2 hex digits, big-endian */
+		uint16_t b;
+		/** 2 hex digits, big-endian */
+		uint16_t c;
+		/** 2 hex digits, big-endian */
+		uint16_t d;
+		/** 12 hex digits, big-endian */
+		uint8_t e[6];
+	} canonical;
+	uint8_t raw[16];
+};
+
+extern char * uuid_ntoa ( union uuid *uuid );
+
+#endif /* _IPXE_UUID_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-pci.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-pci.h
new file mode 100644
index 0000000..a09c463
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-pci.h
@@ -0,0 +1,101 @@
+#ifndef _VIRTIO_PCI_H_
+# define _VIRTIO_PCI_H_
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES        0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES       4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN            8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM            12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL            14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY         16
+
+/* An 8-bit device status register.  */
+#define VIRTIO_PCI_STATUS               18
+
+/* An 8-bit r/o interrupt status register.  Reading the value will return the
+ * current contents of the ISR and will also clear it.  This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR                  19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG           0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG               20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION          0
+
+static inline u32 vp_get_features(unsigned int ioaddr)
+{
+   return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+static inline void vp_set_features(unsigned int ioaddr, u32 features)
+{
+        outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+}
+
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
+                     void *buf, unsigned len)
+{
+   u8 *ptr = buf;
+   unsigned i;
+
+   for (i = 0; i < len; i++)
+           ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+}
+
+static inline u8 vp_get_status(unsigned int ioaddr)
+{
+   return inb(ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline void vp_set_status(unsigned int ioaddr, u8 status)
+{
+   if (status == 0)        /* reset */
+           return;
+   outb(status, ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline u8 vp_get_isr(unsigned int ioaddr)
+{
+   return inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_reset(unsigned int ioaddr)
+{
+   outb(0, ioaddr + VIRTIO_PCI_STATUS);
+   (void)inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_notify(unsigned int ioaddr, int queue_index)
+{
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
+{
+   /* select the queue */
+
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+   /* deactivate the queue */
+
+   outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
+}
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq);
+#endif /* _VIRTIO_PCI_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-ring.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-ring.h
new file mode 100644
index 0000000..0afe8ba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/virtio-ring.h
@@ -0,0 +1,142 @@
+#ifndef _VIRTIO_RING_H_
+# define _VIRTIO_RING_H_
+#define PAGE_SHIFT (12)
+#define PAGE_SIZE  (1<<PAGE_SHIFT)
+#define PAGE_MASK  (PAGE_SIZE-1)
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER          2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK       4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED          0x80
+
+#define MAX_QUEUE_NUM      (256)
+
+#define VRING_DESC_F_NEXT  1
+#define VRING_DESC_F_WRITE 2
+
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+#define VRING_USED_F_NO_NOTIFY     1
+
+struct vring_desc
+{
+   u64 addr;
+   u32 len;
+   u16 flags;
+   u16 next;
+};
+
+struct vring_avail
+{
+   u16 flags;
+   u16 idx;
+   u16 ring[0];
+};
+
+struct vring_used_elem
+{
+   u32 id;
+   u32 len;
+};
+
+struct vring_used
+{
+   u16 flags;
+   u16 idx;
+   struct vring_used_elem ring[];
+};
+
+struct vring {
+   unsigned int num;
+   struct vring_desc *desc;
+   struct vring_avail *avail;
+   struct vring_used *used;
+};
+
+#define vring_size(num) \
+   (((((sizeof(struct vring_desc) * num) + \
+      (sizeof(struct vring_avail) + sizeof(u16) * num)) \
+         + PAGE_MASK) & ~PAGE_MASK) + \
+         (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+
+typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
+
+struct vring_virtqueue {
+   virtio_queue_t queue;
+   struct vring vring;
+   u16 free_head;
+   u16 last_used_idx;
+   void *vdata[MAX_QUEUE_NUM];
+   /* PCI */
+   int queue_index;
+};
+
+struct vring_list {
+  char *addr;
+  unsigned int length;
+};
+
+static inline void vring_init(struct vring *vr,
+                         unsigned int num, unsigned char *queue)
+{
+   unsigned int i;
+   unsigned long pa;
+
+        vr->num = num;
+
+   /* physical address of desc must be page aligned */
+
+   pa = virt_to_phys(queue);
+   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+   vr->desc = phys_to_virt(pa);
+
+        vr->avail = (struct vring_avail *)&vr->desc[num];
+
+   /* physical address of used must be page aligned */
+
+   pa = virt_to_phys(&vr->avail->ring[num]);
+   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+        vr->used = phys_to_virt(pa);
+
+   for (i = 0; i < num - 1; i++)
+           vr->desc[i].next = i + 1;
+   vr->desc[i].next = 0;
+}
+
+static inline void vring_enable_cb(struct vring_virtqueue *vq)
+{
+   vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+}
+
+static inline void vring_disable_cb(struct vring_virtqueue *vq)
+{
+   vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+}
+
+
+/*
+ * vring_more_used
+ *
+ * is there some used buffers ?
+ *
+ */
+
+static inline int vring_more_used(struct vring_virtqueue *vq)
+{
+   wmb();
+   return vq->last_used_idx != vq->vring.used->idx;
+}
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head);
+void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
+void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
+                   unsigned int out, unsigned int in,
+                   void *index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+
+#endif /* _VIRTIO_RING_H_ */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/vlan.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/vlan.h
new file mode 100644
index 0000000..d9f4484
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/vlan.h
@@ -0,0 +1,69 @@
+#ifndef _IPXE_VLAN_H
+#define _IPXE_VLAN_H
+
+/**
+ * @file
+ *
+ * Virtual LANs
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A VLAN header */
+struct vlan_header {
+	/** Tag control information */
+	uint16_t tci;
+	/** Encapsulated protocol */
+	uint16_t net_proto;
+} __attribute__ (( packed ));
+
+/**
+ * Extract VLAN tag from tag control information
+ *
+ * @v tci		Tag control information
+ * @ret tag		VLAN tag
+ */
+#define VLAN_TAG( tci ) ( (tci) & 0x0fff )
+
+/**
+ * Extract VLAN priority from tag control information
+ *
+ * @v tci		Tag control information
+ * @ret priority	Priority
+ */
+#define VLAN_PRIORITY( tci ) ( (tci) >> 13 )
+
+/**
+ * Construct VLAN tag control information
+ *
+ * @v tag		VLAN tag
+ * @v priority		Priority
+ * @ret tci		Tag control information
+ */
+#define VLAN_TCI( tag, priority ) ( ( (priority) << 13 ) | (tag) )
+
+/**
+ * Check VLAN tag is valid
+ *
+ * @v tag		VLAN tag
+ * @ret is_valid	VLAN tag is valid
+ */
+#define VLAN_TAG_IS_VALID( tag ) ( (tag) < 0xfff )
+
+/**
+ * Check VLAN priority is valid
+ *
+ * @v priority		VLAN priority
+ * @ret is_valid	VLAN priority is valid
+ */
+#define VLAN_PRIORITY_IS_VALID( priority ) ( (priority) <= 7 )
+
+extern struct net_device * vlan_find ( struct net_device *trunk,
+				       unsigned int tag );
+extern int vlan_can_be_trunk ( struct net_device *trunk );
+extern int vlan_create ( struct net_device *trunk, unsigned int tag,
+			 unsigned int priority );
+extern int vlan_destroy ( struct net_device *netdev );
+
+#endif /* _IPXE_VLAN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/vsprintf.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/vsprintf.h
new file mode 100644
index 0000000..c48c97a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/vsprintf.h
@@ -0,0 +1,74 @@
+#ifndef _IPXE_VSPRINTF_H
+#define _IPXE_VSPRINTF_H
+
+/** @file
+ *
+ * printf() and friends
+ *
+ * Etherboot's printf() functions understand the following subset of
+ * the standard C printf()'s format specifiers:
+ *
+ *	- Flag characters
+ *		- '#'		- Alternate form (i.e. "0x" prefix)
+ *		- '0'		- Zero-pad
+ *	- Field widths
+ *	- Length modifiers
+ *		- 'hh'		- Signed / unsigned char
+ *		- 'h'		- Signed / unsigned short
+ *		- 'l'		- Signed / unsigned long
+ *		- 'll'		- Signed / unsigned long long
+ *		- 'z'		- Signed / unsigned size_t
+ *	- Conversion specifiers
+ *		- 'd'		- Signed decimal
+ *		- 'x','X'	- Unsigned hexadecimal
+ *		- 'c'		- Character
+ *		- 's'		- String
+ *		- 'p'		- Pointer
+ *
+ * Hexadecimal numbers are always zero-padded to the specified field
+ * width (if any); decimal numbers are always space-padded.  Decimal
+ * long longs are not supported.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/**
+ * A printf context
+ *
+ * Contexts are used in order to be able to share code between
+ * vprintf() and vsnprintf(), without requiring the allocation of a
+ * buffer for vprintf().
+ */
+struct printf_context {
+	/**
+	 * Character handler
+	 *
+	 * @v ctx	Context
+	 * @v c		Character
+	 *
+	 * This method is called for each character written to the
+	 * formatted string.
+	 */
+	void ( * handler ) ( struct printf_context *ctx, unsigned int c );
+	/** Length of formatted string
+	 *
+	 * When handler() is called, @len will be set to the number of
+	 * characters written so far (i.e. zero for the first call to
+	 * handler()).
+	 */
+	size_t len;
+};
+
+extern size_t vcprintf ( struct printf_context *ctx, const char *fmt,
+			 va_list args );
+extern int vssnprintf ( char *buf, ssize_t ssize, const char *fmt,
+			va_list args );
+extern int __attribute__ (( format ( printf, 3, 4 ) ))
+ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... );
+
+#endif /* _IPXE_VSPRINTF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/wpa.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/wpa.h
new file mode 100644
index 0000000..2934228
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/wpa.h
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _IPXE_WPA_H
+#define _IPXE_WPA_H
+
+#include <ipxe/ieee80211.h>
+#include <ipxe/list.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Common definitions for all types of WPA-protected networks.
+ */
+
+
+/** EAPOL-Key type field for modern 802.11i/RSN WPA packets */
+#define EAPOL_KEY_TYPE_RSN	2
+
+/** Old EAPOL-Key type field used by WPA1 hardware before 802.11i ratified */
+#define EAPOL_KEY_TYPE_WPA	254
+
+
+/**
+ * @defgroup eapol_key_info EAPOL-Key Info field bits
+ * @{
+ */
+
+/** Key descriptor version, indicating WPA or WPA2 */
+#define EAPOL_KEY_INFO_VERSION	0x0007
+
+/** Key type bit, indicating pairwise or group */
+#define EAPOL_KEY_INFO_TYPE	0x0008
+
+/** Key install bit; set on message 3 except when legacy hacks are used */
+#define EAPOL_KEY_INFO_INSTALL	0x0040
+
+/** Key ACK bit; set when a response is required, on all messages except #4 */
+#define EAPOL_KEY_INFO_KEY_ACK	0x0080
+
+/** Key MIC bit; set when the MIC field is valid, on messages 3 and 4 */
+#define EAPOL_KEY_INFO_KEY_MIC	0x0100
+
+/** Secure bit; set when both sides have both keys, on messages 3 and 4 */
+#define EAPOL_KEY_INFO_SECURE	0x0200
+
+/** Error bit; set on a MIC failure for TKIP */
+#define EAPOL_KEY_INFO_ERROR	0x0400
+
+/** Request bit; set when authentication is initiated by the Peer (unusual) */
+#define EAPOL_KEY_INFO_REQUEST	0x0800
+
+/** Key Encrypted bit; set when the Key Data field is encrypted */
+#define EAPOL_KEY_INFO_KEY_ENC	0x1000
+
+/** SMC Message bit; set when this frame is part of an IBSS SMK handshake */
+#define EAPOL_KEY_INFO_SMC_MESS	0x2000
+
+
+/** Key descriptor version field value for WPA (TKIP) */
+#define EAPOL_KEY_VERSION_WPA	1
+
+/** Key descriptor version field value for WPA2 (CCMP) */
+#define EAPOL_KEY_VERSION_WPA2	2
+
+/** Key type field value for a PTK (pairwise) key handshake */
+#define EAPOL_KEY_TYPE_PTK	0x0008
+
+/** Key type field value for a GTK (group) key handshake */
+#define EAPOL_KEY_TYPE_GTK	0x0000
+
+/** @} */
+
+
+
+/** An EAPOL-Key packet.
+ *
+ * These are used for the WPA 4-Way Handshake, whether or not prior
+ * authentication has been performed using EAP.
+ *
+ * On LANs, an eapol_key_pkt is always encapsulated in the data field
+ * of an eapol_frame, with the frame's type code set to EAPOL_TYPE_KEY.
+ *
+ * Unlike 802.11 frame headers, the fields in this structure are
+ * stored in big-endian!
+ */
+struct eapol_key_pkt
+{
+	/** One of the EAPOL_KEY_TYPE_* defines. */
+	u8 type;
+
+	/** Bitfield of key characteristics, network byte order */
+	u16 info;
+
+	/** Length of encryption key to be used, network byte order
+	 *
+	 * This is 16 for CCMP, 32 for TKIP, and 5 or 13 for WEP.
+	 */
+	u16 keysize;
+
+	/** Monotonically increasing value for EAPOL-Key conversations
+	 *
+	 * In another classic demonstration of overengineering, this
+	 * 8-byte value will rarely be anything above 1. It's stored
+	 * in network byte order.
+	 */
+	u64 replay;
+
+	/** Nonce value
+	 *
+	 * This is the authenticator's ANonce in frame 1, the peer's
+	 * SNonce in frame 2, and 0 in frames 3 and 4.
+	 */
+	u8 nonce[32];
+
+	/** Initialization vector
+	 *
+	 * This contains the IV used with the Key Encryption Key, or 0
+	 * if the key is unencrypted or encrypted using an algorithm
+	 * that does not require an IV.
+	 */
+	u8 iv[16];
+
+	/** Receive sequence counter for GTK
+	 *
+	 * This is used to synchronize the client's replay counter for
+	 * ordinary data packets. The first six bytes contain PN0
+	 * through PN5 for CCMP mode, or TSC0 through TSC5 for TKIP
+	 * mode. The last two bytes are zero.
+	 */
+	u8 rsc[8];
+
+	/** Reserved bytes */
+	u8 _reserved[8];
+
+	/** Message integrity code over the entire EAPOL frame
+	 *
+	 * This is calculated using HMAC-MD5 when the key descriptor
+	 * version field in @a info is 1, and HMAC-SHA1 ignoring the
+	 * last 4 bytes of the hash when the version field in @a info
+	 * is 2.
+	 */
+	u8 mic[16];
+
+	/** Length of the @a data field in bytes, network byte order */
+	u16 datalen;
+
+	/** Key data
+	 *
+	 * This is formatted as a series of 802.11 information
+	 * elements, with cryptographic data encapsulated using a
+	 * "vendor-specific IE" code and an IEEE-specified OUI.
+	 */
+	u8 data[0];
+} __attribute__ (( packed ));
+
+
+/** WPA handshaking state */
+enum wpa_state {
+	/** Waiting for PMK to be set */
+	WPA_WAITING = 0,
+
+	/** Ready for 4-Way Handshake */
+	WPA_READY,
+
+	/** Performing 4-Way Handshake */
+	WPA_WORKING,
+
+	/** 4-Way Handshake succeeded */
+	WPA_SUCCESS,
+
+	/** 4-Way Handshake failed */
+	WPA_FAILURE,
+};
+
+/** Bitfield indicating a selection of WPA transient keys */
+enum wpa_keymask {
+	/** Pairwise transient key */
+	WPA_PTK = 1,
+
+	/** Group transient key */
+	WPA_GTK = 2,
+};
+
+
+/** Length of a nonce */
+#define WPA_NONCE_LEN		32
+
+/** Length of a TKIP main key */
+#define WPA_TKIP_KEY_LEN	16
+
+/** Length of a TKIP MIC key */
+#define WPA_TKIP_MIC_KEY_LEN	8
+
+/** Length of a CCMP key */
+#define WPA_CCMP_KEY_LEN	16
+
+/** Length of an EAPOL Key Confirmation Key */
+#define WPA_KCK_LEN		16
+
+/** Length of an EAPOL Key Encryption Key */
+#define WPA_KEK_LEN		16
+
+/** Usual length of a Pairwise Master Key */
+#define WPA_PMK_LEN		32
+
+/** Length of a PMKID */
+#define WPA_PMKID_LEN		16
+
+
+/** Structure of the Temporal Key for TKIP encryption */
+struct tkip_tk
+{
+	/** Main key: input to TKIP Phase 1 and Phase 2 key mixing functions */
+	u8 key[WPA_TKIP_KEY_LEN];
+
+	/** Michael MIC keys */
+	struct {
+		/** MIC key for packets from the AP */
+		u8 rx[WPA_TKIP_MIC_KEY_LEN];
+
+		/** MIC key for packets to the AP */
+		u8 tx[WPA_TKIP_MIC_KEY_LEN];
+	} __attribute__ (( packed )) mic;
+} __attribute__ (( packed ));
+
+/** Structure of a generic Temporal Key */
+union wpa_tk
+{
+	/** CCMP key */
+	u8 ccmp[WPA_CCMP_KEY_LEN];
+
+	/** TKIP keys */
+	struct tkip_tk tkip;
+};
+
+/** Structure of the Pairwise Transient Key */
+struct wpa_ptk
+{
+	/** EAPOL-Key Key Confirmation Key (KCK) */
+	u8 kck[WPA_KCK_LEN];
+
+	/** EAPOL-Key Key Encryption Key (KEK) */
+	u8 kek[WPA_KEK_LEN];
+
+	/** Temporal key */
+	union wpa_tk tk;
+} __attribute__ (( packed ));
+
+/** Structure of the Group Transient Key */
+struct wpa_gtk
+{
+	/** Temporal key */
+	union wpa_tk tk;
+} __attribute__ (( packed ));
+
+
+/** Common context for WPA security handshaking
+ *
+ * Any implementor of a particular handshaking type (e.g. PSK or EAP)
+ * must include this structure at the very beginning of their private
+ * data context structure, to allow the EAPOL-Key handling code to
+ * work. When the preliminary authentication is done, it is necessary
+ * to call wpa_start(), passing the PMK (derived from PSK or EAP MSK)
+ * as an argument. The handshaker can use its @a step function to
+ * monitor @a state in this wpa_ctx structure for success or
+ * failure. On success, the keys will be available in @a ptk and @a
+ * gtk according to the state of the @a valid bitmask.
+ *
+ * After an initial success, the parent handshaker does not need to
+ * concern itself with rekeying; the WPA common code takes care of
+ * that.
+ */
+struct wpa_common_ctx
+{
+	/** 802.11 device we are authenticating for */
+	struct net80211_device *dev;
+
+	/** The Pairwise Master Key to use in handshaking
+	 *
+	 * This is set either by running the PBKDF2 algorithm on a
+	 * passphrase with the SSID as salt to generate a pre-shared
+	 * key, or by copying the first 32 bytes of the EAP Master
+	 * Session Key in 802.1X-served authentication.
+	 */
+	u8 pmk[WPA_PMK_LEN];
+
+	/** Length of the Pairwise Master Key
+	 *
+	 * This is always 32 except with one EAP method which only
+	 * gives 16 bytes.
+	 */
+	int pmk_len;
+
+	/** State of EAPOL-Key handshaking */
+	enum wpa_state state;
+
+	/** Replay counter for this association
+	 *
+	 * This stores the replay counter value for the most recent
+	 * packet we've accepted. It is initially initialised to ~0 to
+	 * show we'll accept anything.
+	 */
+	u64 replay;
+
+	/** Mask of valid keys after authentication success
+	 *
+	 * If the PTK is not valid, the GTK should be used for both
+	 * unicast and multicast decryption; if the GTK is not valid,
+	 * multicast packets cannot be decrypted.
+	 */
+	enum wpa_keymask valid;
+
+	/** The cipher to use for unicast RX and all TX */
+	enum net80211_crypto_alg crypt;
+
+	/** The cipher to use for broadcast and multicast RX */
+	enum net80211_crypto_alg gcrypt;
+
+	/** The Pairwise Transient Key derived from the handshake */
+	struct wpa_ptk ptk;
+
+	/** The Group Transient Key derived from the handshake */
+	struct wpa_gtk gtk;
+
+	/** Authenticator-provided nonce */
+	u8 Anonce[WPA_NONCE_LEN];
+
+	/** Supplicant-generated nonce (that's us) */
+	u8 Snonce[WPA_NONCE_LEN];
+
+	/** Whether we should refrain from generating another SNonce */
+	int have_Snonce;
+
+	/** Data in WPA or RSN IE from AP's beacon frame */
+	void *ap_rsn_ie;
+
+	/** Length of @a ap_rsn_ie */
+	int ap_rsn_ie_len;
+
+	/** Whether @a ap_rsn_ie is an RSN IE (as opposed to old WPA) */
+	int ap_rsn_is_rsn;
+
+	/** List entry */
+	struct list_head list;
+};
+
+
+/** WPA handshake key integrity and encryption handler
+ *
+ * Note that due to the structure of the 4-Way Handshake we never
+ * actually need to encrypt key data, only decrypt it.
+ */
+struct wpa_kie {
+	/** Value of version bits in EAPOL-Key info field for which to use
+	 *
+	 * This should be one of the @c EAPOL_KEY_VERSION_* constants.
+	 */
+	int version;
+
+	/** Calculate MIC over message
+	 *
+	 * @v kck	Key Confirmation Key, 16 bytes
+	 * @v msg	Message to calculate MIC over
+	 * @v len	Number of bytes to calculate MIC over
+	 * @ret mic	Calculated MIC, 16 bytes long
+	 *
+	 * The @a mic return may point within @a msg, so it must not
+	 * be filled until the calculation has been performed.
+	 */
+	void ( * mic ) ( const void *kck, const void *msg, size_t len,
+			 void *mic );
+
+	/** Decrypt key data
+	 *
+	 * @v kek	Key Encryption Key, 16 bytes
+	 * @v iv	Initialisation vector for encryption, 16 bytes
+	 * @v msg	Message to decrypt (Key Data field)
+	 * @v len	Length of message
+	 * @ret msg	Decrypted message in place of original
+	 * @ret len	Updated to reflect encrypted length
+	 * @ret rc	Return status code
+	 *
+	 * The decrypted message is written over the encrypted one.
+	 */
+	int ( * decrypt ) ( const void *kek, const void *iv, void *msg,
+			    u16 *len );
+};
+
+#define WPA_KIES	__table ( struct wpa_kie, "wpa_kies" )
+#define __wpa_kie	__table_entry ( WPA_KIES, 01 )
+
+
+
+/**
+ * @defgroup wpa_kde Key descriptor element types
+ * @{
+ */
+
+/** Payload structure of the GTK-encapsulating KDE
+ *
+ * This does not include the IE type, length, or OUI bytes, which are
+ * generic to all KDEs.
+ */
+struct wpa_kde_gtk_encap
+{
+	/** Key ID and TX bit */
+	u8 id;
+
+	/** Reserved byte */
+	u8 _rsvd;
+
+	/** Encapsulated group transient key */
+	struct wpa_gtk gtk;
+} __attribute__ (( packed ));
+
+/** Mask for Key ID in wpa_kde_gtk::id field */
+#define WPA_GTK_KID	0x03
+
+/** Mask for Tx bit in wpa_kde_gtk::id field */
+#define WPA_GTK_TXBIT	0x04
+
+
+/** KDE type for an encapsulated Group Transient Key (requires encryption) */
+#define WPA_KDE_GTK	_MKOUI ( 0x00, 0x0F, 0xAC, 0x01 )
+
+/** KDE type for a MAC address */
+#define WPA_KDE_MAC	_MKOUI ( 0x00, 0x0F, 0xAC, 0x03 )
+
+/** KDE type for a PMKID */
+#define WPA_KDE_PMKID	_MKOUI ( 0x00, 0x0F, 0xAC, 0x04 )
+
+/** KDE type for a nonce */
+#define WPA_KDE_NONCE	_MKOUI ( 0x00, 0x0F, 0xAC, 0x06 )
+
+/** KDE type for a lifetime value */
+#define WPA_KDE_LIFETIME _MKOUI ( 0x00, 0x0F, 0xAC, 0x07 )
+
+
+/** Any key descriptor element type
+ *
+ * KDEs follow the 802.11 information element format of a type byte
+ * (in this case "vendor-specific", with the requisite OUI+subtype
+ * after length) and a length byte whose value does not include the
+ * length of the type and length bytes.
+ */
+struct wpa_kde
+{
+	/** Information element type: always 0xDD (IEEE80211_IE_VENDOR) */
+	u8 ie_type;
+
+	/** Length, not including ie_type and length fields */
+	u8 len;
+
+	/** OUI + type byte */
+	u32 oui_type;
+
+	/** Payload data */
+	union {
+		/** For GTK-type KDEs, encapsulated GTK */
+		struct wpa_kde_gtk_encap gtk_encap;
+
+		/** For MAC-type KDEs, the MAC address */
+		u8 mac[ETH_ALEN];
+
+		/** For PMKID-type KDEs, the PMKID */
+		u8 pmkid[WPA_PMKID_LEN];
+
+		/** For Nonce-type KDEs, the nonce */
+		u8 nonce[WPA_NONCE_LEN];
+
+		/** For Lifetime-type KDEs, the lifetime in seconds
+		 *
+		 * This is in network byte order!
+		 */
+		u32 lifetime;
+	};
+} __attribute__ (( packed ));
+
+/** @} */
+
+int wpa_make_rsn_ie ( struct net80211_device *dev, union ieee80211_ie **ie );
+int wpa_start ( struct net80211_device *dev, struct wpa_common_ctx *ctx,
+		const void *pmk, size_t pmk_len );
+void wpa_stop ( struct net80211_device *dev );
+
+#endif /* _IPXE_WPA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/x509.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/x509.h
new file mode 100644
index 0000000..37c5a4e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/x509.h
@@ -0,0 +1,41 @@
+#ifndef _IPXE_X509_H
+#define _IPXE_X509_H
+
+/** @file
+ *
+ * X.509 certificates
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+struct asn1_cursor;
+
+/** An X.509 RSA public key */
+struct x509_rsa_public_key {
+	/** Modulus */
+	uint8_t *modulus;
+	/** Modulus length */
+	size_t modulus_len;
+	/** Exponent */
+	uint8_t *exponent;
+	/** Exponent length */
+	size_t exponent_len;
+};
+
+/**
+ * Free X.509 RSA public key
+ *
+ * @v rsa_pubkey	RSA public key
+ */
+static inline void
+x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) {
+	free ( rsa_pubkey->modulus );
+}
+
+extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
+				 struct x509_rsa_public_key *rsa_pubkey );
+
+#endif /* _IPXE_X509_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/ipxe/xfer.h b/qemu-0.15.x/roms/ipxe/src/include/ipxe/xfer.h
new file mode 100644
index 0000000..1167e5c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/ipxe/xfer.h
@@ -0,0 +1,107 @@
+#ifndef _IPXE_XFER_H
+#define _IPXE_XFER_H
+
+/** @file
+ *
+ * Data transfer interfaces
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <ipxe/interface.h>
+
+struct xfer_metadata;
+struct io_buffer;
+struct sockaddr;
+struct net_device;
+
+/** Data transfer metadata */
+struct xfer_metadata {
+	/** Flags
+	 *
+	 * This is the bitwise OR of zero or more @c XFER_FL_XXX
+	 * constants.
+	 */
+	unsigned int flags;
+	/** Offset of data within stream
+	 *
+	 * This is an absolute offset if the @c XFER_FL_ABS_OFFSET
+	 * flag is set, otherwise a relative offset.  (A freshly
+	 * zeroed @c xfer_metadata structure therefore represents a
+	 * relative offset of zero, i.e. no offset from the current
+	 * position.)
+	 */
+	off_t offset;
+	/** Source socket address, or NULL */
+	struct sockaddr *src;
+	/** Destination socket address, or NULL */
+	struct sockaddr *dest;
+	/** Network device, or NULL */
+	struct net_device *netdev;
+};
+
+/** Offset is absolute */
+#define XFER_FL_ABS_OFFSET 0x0001
+
+/** Sender is relinquishing use of half-duplex channel */
+#define XFER_FL_OVER 0x0002
+
+/** This is the final data transfer */
+#define XFER_FL_OUT 0x0004
+
+/** Data content represents a command or status message
+ *
+ * The flag @c XFER_FL_RESPONSE is used to distinguish between a
+ * command message and a status message.
+ */
+#define XFER_FL_CMD_STAT 0x0008
+
+/** Data content is a response */
+#define XFER_FL_RESPONSE 0x0010
+
+/* Data transfer interface operations */
+
+extern int xfer_vredirect ( struct interface *intf, int type,
+			    va_list args );
+#define xfer_vredirect_TYPE( object_type ) \
+	typeof ( int ( object_type, int type, va_list args ) )
+
+extern size_t xfer_window ( struct interface *intf );
+#define xfer_window_TYPE( object_type ) \
+	typeof ( size_t ( object_type ) )
+
+extern void xfer_window_changed ( struct interface *intf );
+#define xfer_window_changed_TYPE( object_type ) \
+	typeof ( void ( object_type ) )
+
+extern struct io_buffer * xfer_alloc_iob ( struct interface *intf,
+					   size_t len );
+#define xfer_alloc_iob_TYPE( object_type ) \
+	typeof ( struct io_buffer * ( object_type, size_t len ) )
+
+extern int xfer_deliver ( struct interface *intf,
+			  struct io_buffer *iobuf,
+			  struct xfer_metadata *meta );
+#define xfer_deliver_TYPE( object_type )			\
+	typeof ( int ( object_type, struct io_buffer *iobuf,	\
+		       struct xfer_metadata *meta ) )
+
+/* Data transfer interface helper functions */
+
+extern int xfer_redirect ( struct interface *xfer, int type, ... );
+extern int xfer_deliver_iob ( struct interface *intf,
+			      struct io_buffer *iobuf );
+extern int xfer_deliver_raw_meta ( struct interface *intf, const void *data,
+				   size_t len, struct xfer_metadata *meta );
+extern int xfer_deliver_raw ( struct interface *intf,
+			      const void *data, size_t len );
+extern int xfer_vprintf ( struct interface *intf,
+			  const char *format, va_list args );
+extern int __attribute__ (( format ( printf, 2, 3 ) ))
+xfer_printf ( struct interface *intf, const char *format, ... );
+extern int xfer_seek ( struct interface *intf, off_t offset );
+
+#endif /* _IPXE_XFER_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/libgen.h b/qemu-0.15.x/roms/ipxe/src/include/libgen.h
new file mode 100644
index 0000000..7e94881
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/libgen.h
@@ -0,0 +1,9 @@
+#ifndef _LIBGEN_H
+#define _LIBGEN_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern char * basename ( char *path );
+extern char * dirname ( char *path );
+
+#endif /* _LIBGEN_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/linux_api.h b/qemu-0.15.x/roms/ipxe/src/include/linux_api.h
new file mode 100644
index 0000000..066cdd3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/linux_api.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LINUX_API_H
+#define _LINUX_API_H
+
+/** * @file
+ *
+ * Linux API prototypes.
+ * Most of the functions map directly to linux syscalls and are the equivalent
+ * of POSIX functions with the linux_ prefix removed.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <bits/linux_api.h>
+#include <bits/linux_api_platform.h>
+
+#include <stdint.h>
+
+#define __KERNEL_STRICT_NAMES
+#include <linux/types.h>
+#include <linux/posix_types.h>
+typedef __kernel_pid_t pid_t;
+typedef __kernel_time_t time_t;
+typedef __kernel_suseconds_t suseconds_t;
+typedef __kernel_loff_t loff_t;
+#include <linux/time.h>
+#include <linux/mman.h>
+#include <linux/fcntl.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+typedef unsigned long nfds_t;
+typedef uint32_t useconds_t;
+#define MAP_FAILED ( ( void * ) -1 )
+
+extern long linux_syscall ( int number, ... );
+
+extern int linux_open ( const char *pathname, int flags );
+extern int linux_close ( int fd );
+extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count );
+extern __kernel_ssize_t linux_write ( int fd, const void *buf,
+				      __kernel_size_t count );
+extern int linux_fcntl ( int fd, int cmd, ... );
+extern int linux_ioctl ( int fd, int request, ... );
+extern int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout );
+extern int linux_nanosleep ( const struct timespec *req, struct timespec *rem );
+extern int linux_usleep ( useconds_t usec );
+extern int linux_gettimeofday ( struct timeval *tv, struct timezone *tz );
+extern void * linux_mmap ( void *addr, __kernel_size_t length, int prot,
+			   int flags, int fd, off_t offset );
+extern void * linux_mremap ( void *old_address, __kernel_size_t old_size,
+			     __kernel_size_t new_size, int flags );
+extern int linux_munmap ( void *addr, __kernel_size_t length );
+
+extern const char * linux_strerror ( int errnum );
+
+#endif /* _LINUX_API_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/little_bswap.h b/qemu-0.15.x/roms/ipxe/src/include/little_bswap.h
new file mode 100644
index 0000000..a5dc9c8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/little_bswap.h
@@ -0,0 +1,35 @@
+#ifndef ETHERBOOT_LITTLE_BSWAP_H
+#define ETHERBOOT_LITTLE_BSWAP_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define ntohl(x)	__bswap_32(x)
+#define htonl(x) 	__bswap_32(x)
+#define ntohs(x) 	__bswap_16(x)
+#define htons(x) 	__bswap_16(x)
+#define cpu_to_le64(x)	(x)
+#define cpu_to_le32(x)	(x)
+#define cpu_to_le16(x)	(x)
+#define cpu_to_be64(x)	__bswap_64(x)
+#define cpu_to_be32(x)	__bswap_32(x)
+#define cpu_to_be16(x)	__bswap_16(x)
+#define le64_to_cpu(x)	(x)
+#define le32_to_cpu(x)	(x)
+#define le16_to_cpu(x)	(x)
+#define be64_to_cpu(x)	__bswap_64(x)
+#define be32_to_cpu(x)	__bswap_32(x)
+#define be16_to_cpu(x)	__bswap_16(x)
+#define cpu_to_le64s(x) do {} while (0)
+#define cpu_to_le32s(x) do {} while (0)
+#define cpu_to_le16s(x) do {} while (0)
+#define cpu_to_be64s(x) __bswap_64s(x)
+#define cpu_to_be32s(x) __bswap_32s(x)
+#define cpu_to_be16s(x) __bswap_16s(x)
+#define le64_to_cpus(x) do {} while (0)
+#define le32_to_cpus(x) do {} while (0)
+#define le16_to_cpus(x) do {} while (0)
+#define be64_to_cpus(x) __bswap_64s(x)
+#define be32_to_cpus(x) __bswap_32s(x)
+#define be16_to_cpus(x) __bswap_16s(x)
+
+#endif /* ETHERBOOT_LITTLE_BSWAP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/mii.h b/qemu-0.15.x/roms/ipxe/src/include/mii.h
new file mode 100644
index 0000000..2baff2f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/mii.h
@@ -0,0 +1,219 @@
+/*
+ * linux/mii.h: definitions for MII-compatible transceivers
+ * Originally drivers/net/sunhme.h.
+ *
+ * Copyright (C) 1996, 1999, 2001 David S. Miller (davem at redhat.com)
+ *
+ * Copied Form Linux 2.4.25 an unneeded items removed by:
+ * Timothy Legge (timlegge at etherboot dot org)
+ *
+ * 03/26/2004
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef _MII_H_
+#define _MII_H_
+
+/* Generic MII registers. */
+
+#define MII_BMCR            0x00	/* Basic mode control register */
+#define MII_BMSR            0x01	/* Basic mode status register  */
+#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
+#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
+#define MII_ADVERTISE       0x04	/* Advertisement control reg   */
+#define MII_LPA             0x05	/* Link partner ability reg    */
+#define MII_EXPANSION       0x06        /* Expansion register          */
+#define MII_CTRL1000        0x09        /* 1000BASE-T control          */
+#define MII_STAT1000        0x0a        /* 1000BASE-T status           */
+#define MII_ESTATUS         0x0f        /* Extended Status */
+#define MII_DCOUNTER        0x12        /* Disconnect counter          */
+#define MII_FCSCOUNTER      0x13        /* False carrier counter       */
+#define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
+#define MII_RERRCOUNTER     0x15        /* Receive error counter       */
+#define MII_SREVISION       0x16        /* Silicon revision            */
+#define MII_RESV1           0x17        /* Reserved...                 */
+#define MII_LBRERROR        0x18        /* Lpback, rx, bypass error    */
+#define MII_PHYADDR         0x19        /* PHY address                 */
+#define MII_RESV2           0x1a        /* Reserved...                 */
+#define MII_TPISTATUS       0x1b        /* TPI status for 10mbps       */
+#define MII_NCONFIG         0x1c        /* Network interface config    */
+
+/* Basic mode control register. */
+#define BMCR_RESV               0x003f  /* Unused...                   */
+#define BMCR_SPEED1000          0x0040  /* MSB of Speed (1000)         */
+#define BMCR_CTST               0x0080  /* Collision test              */
+#define BMCR_FULLDPLX           0x0100	/* Full duplex                 */
+#define BMCR_ANRESTART          0x0200	/* Auto negotiation restart    */
+#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
+#define BMCR_ANENABLE           0x1000	/* Enable auto negotiation     */
+#define BMCR_SPEED100           0x2000	/* Select 100Mbps              */
+#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
+#define BMCR_RESET              0x8000	/* Reset the DP83840           */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_JCD                0x0002  /* Jabber detected             */
+#define BMSR_LSTATUS            0x0004  /* Link status                 */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+#define BMSR_RESV               0x00c0  /* Unused...                   */
+#define BMSR_ESTATEN            0x0100  /* Extended Status in R15 */
+#define BMSR_100HALF2           0x0200  /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2           0x0400  /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020	/* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL        0x0040	/* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF       0x0080	/* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
+#define ADVERTISE_100FULL       0x0100	/* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */
+#define ADVERTISE_RESV          0x1000  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+			ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                      ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* Link partner ability register. */
+#define LPA_SLCT                0x001f  /* Same as advertise selector  */
+#define LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
+#define LPA_1000XFULL           0x0020  /* Can do 1000BASE-X full-duplex */
+#define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
+#define LPA_1000XHALF           0x0040  /* Can do 1000BASE-X half-duplex */
+#define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
+#define LPA_1000XPAUSE          0x0080  /* Can do 1000BASE-X pause     */
+#define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
+#define LPA_1000XPAUSE_ASYM     0x0100  /* Can do 1000BASE-X pause asym*/
+#define LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
+#define LPA_PAUSE_CAP           0x0400  /* Can pause                   */
+#define LPA_PAUSE_ASYM          0x0800  /* Can pause asymetrically     */
+#define LPA_RESV                0x1000  /* Unused...                   */
+#define LPA_RFAULT              0x2000  /* Link partner faulted        */
+#define LPA_LPACK               0x4000  /* Link partner acked us       */
+#define LPA_NPAGE               0x8000  /* Next page bit               */
+
+#define LPA_DUPLEX            (LPA_10FULL | LPA_100FULL)
+#define LPA_100                       (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
+
+/* Expansion register for auto-negotiation. */
+#define EXPANSION_NWAY          0x0001  /* Can do N-way auto-nego      */
+#define EXPANSION_LCWP          0x0002  /* Got new RX page code word   */
+#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
+#define EXPANSION_NPCAPABLE     0x0008  /* Link partner supports npage */
+#define EXPANSION_MFAULTS       0x0010  /* Multiple faults detected    */
+#define EXPANSION_RESV          0xffe0  /* Unused...                   */
+
+#define ESTATUS_1000_TFULL      0x2000  /* Can do 1000BT Full */
+#define ESTATUS_1000_THALF      0x1000  /* Can do 1000BT Half */
+
+/* N-way test register. */
+#define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
+#define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
+#define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
+
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF      0x0100  /* Advertise 1000BASE-T half duplex */
+
+/* 1000BASE-T Status register */
+#define LPA_1000LOCALRXOK       0x2000  /* Link partner local receiver status */
+#define LPA_1000REMRXOK         0x1000  /* Link partner remote receiver status */
+#define LPA_1000FULL            0x0800  /* Link partner 1000BASE-T full duplex */
+#define LPA_1000HALF            0x0400  /* Link partner 1000BASE-T half duplex */
+
+#include <ipxe/netdevice.h>
+
+struct mii_if_info {
+        int phy_id;
+        int advertising;
+        int phy_id_mask;
+        int reg_num_mask;
+
+        unsigned int full_duplex : 1;   /* is full duplex? */
+        unsigned int force_media : 1;   /* is autoneg. disabled? */
+        unsigned int supports_gmii : 1; /* are GMII registers supported? */
+
+        struct net_device *dev;
+        int (*mdio_read) (struct net_device *dev, int phy_id, int location);
+        void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
+};
+
+
+extern int mii_link_ok (struct mii_if_info *mii);
+extern void mii_check_link (struct mii_if_info *mii);
+extern unsigned int mii_check_media (struct mii_if_info *mii,
+                                       unsigned int ok_to_print,
+                                       unsigned int init_media);
+
+
+/**
+ * mii_nway_result
+ * @negotiated: value of MII ANAR and'd with ANLPAR
+ *
+ * Given a set of MII abilities, check each bit and returns the
+ * currently supported media, in the priority order defined by
+ * IEEE 802.3u.  We use LPA_xxx constants but note this is not the
+ * value of LPA solely, as described above.
+ *
+ * The one exception to IEEE 802.3u is that 100baseT4 is placed
+ * between 100T-full and 100T-half.  If your phy does not support
+ * 100T4 this is fine.  If your phy places 100T4 elsewhere in the
+ * priority order, you will need to roll your own function.
+ */
+static inline unsigned int mii_nway_result (unsigned int negotiated)
+{
+        unsigned int ret;
+
+        if (negotiated & LPA_100FULL)
+                ret = LPA_100FULL;
+        else if (negotiated & LPA_100BASE4)
+                ret = LPA_100BASE4;
+        else if (negotiated & LPA_100HALF)
+                ret = LPA_100HALF;
+        else if (negotiated & LPA_10FULL)
+                ret = LPA_10FULL;
+        else
+                ret = LPA_10HALF;
+
+        return ret;
+}
+
+/**
+ * mii_duplex
+ * @duplex_lock: Non-zero if duplex is locked at full
+ * @negotiated: value of MII ANAR and'd with ANLPAR
+ *
+ * A small helper function for a common case.  Returns one
+ * if the media is operating or locked at full duplex, and
+ * returns zero otherwise.
+ */
+static inline unsigned int mii_duplex (unsigned int duplex_lock,
+                                       unsigned int negotiated)
+{
+        if (duplex_lock)
+                return 1;
+        if (mii_nway_result(negotiated) & LPA_DUPLEX)
+                return 1;
+        return 0;
+}
+
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/nic.h b/qemu-0.15.x/roms/ipxe/src/include/nic.h
new file mode 100644
index 0000000..9aaede8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/nic.h
@@ -0,0 +1,271 @@
+ /*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifndef	NIC_H
+#define NIC_H
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/isapnp.h>
+#include <ipxe/isa.h>
+#include <ipxe/eisa.h>
+#include <ipxe/mca.h>
+#include <ipxe/io.h>
+
+typedef enum {
+	DISABLE = 0,
+	ENABLE,
+	FORCE
+} irq_action_t;
+
+typedef enum duplex {
+	HALF_DUPLEX = 1,
+	FULL_DUPLEX
+} duplex_t;
+
+/*
+ *	Structure returned from eth_probe and passed to other driver
+ *	functions.
+ */
+struct nic {
+	struct nic_operations	*nic_op;
+	int			flags;	/* driver specific flags */
+	unsigned char		*node_addr;
+	unsigned char		*packet;
+	unsigned int		packetlen;
+	unsigned int		ioaddr;
+	unsigned char		irqno;
+	unsigned int		mbps;
+	duplex_t		duplex;
+	void			*priv_data;	/* driver private data */
+};
+
+struct nic_operations {
+	int ( *connect ) ( struct nic * );
+	int ( *poll ) ( struct nic *, int retrieve );
+	void ( *transmit ) ( struct nic *, const char *,
+			     unsigned int, unsigned int, const char * );
+	void ( *irq ) ( struct nic *, irq_action_t );
+};
+
+extern struct nic nic;
+
+static inline int eth_poll ( int retrieve ) {
+	return nic.nic_op->poll ( &nic, retrieve );
+}
+
+static inline void eth_transmit ( const char *dest, unsigned int type,
+				  unsigned int size, const void *packet ) {
+	nic.nic_op->transmit ( &nic, dest, type, size, packet );
+}
+
+/*
+ * Function prototypes
+ *
+ */
+extern int dummy_connect ( struct nic *nic );
+extern void dummy_irq ( struct nic *nic, irq_action_t irq_action );
+extern int legacy_probe ( void *hwdev,
+			  void ( * set_drvdata ) ( void *hwdev, void *priv ),
+			  struct device *dev,
+			  int ( * probe ) ( struct nic *nic, void *hwdev ),
+			  void ( * disable ) ( struct nic *nic, void *hwdev ));
+void legacy_remove ( void *hwdev,
+		     void * ( * get_drvdata ) ( void *hwdev ),
+		     void ( * disable ) ( struct nic *nic, void *hwdev ) );
+
+#define PCI_DRIVER(_name,_ids,_class) 					  \
+	static inline int						  \
+	_name ## _pci_legacy_probe ( struct pci_device *pci );		  \
+	static inline void						  \
+	_name ## _pci_legacy_remove ( struct pci_device *pci );		  \
+	struct pci_driver _name __pci_driver = {			  \
+		.ids = _ids,						  \
+		.id_count = sizeof ( _ids ) / sizeof ( _ids[0] ),	  \
+		.probe = _name ## _pci_legacy_probe,			  \
+		.remove = _name ## _pci_legacy_remove,			  \
+	};								  \
+	REQUIRE_OBJECT ( pci );
+
+static inline void legacy_pci_set_drvdata ( void *hwdev, void *priv ) {
+	pci_set_drvdata ( hwdev, priv );
+}
+static inline void * legacy_pci_get_drvdata ( void *hwdev ) {
+	return pci_get_drvdata ( hwdev );
+}
+
+#define ISAPNP_DRIVER(_name,_ids)					  \
+	static inline int						  \
+	_name ## _isapnp_legacy_probe ( struct isapnp_device *isapnp,	  \
+					const struct isapnp_device_id *id ); \
+	static inline void						  \
+	_name ## _isapnp_legacy_remove ( struct isapnp_device *isapnp );  \
+	struct isapnp_driver _name __isapnp_driver = {			  \
+		.ids = _ids,						  \
+		.id_count = sizeof ( _ids ) / sizeof ( _ids[0] ),	  \
+		.probe = _name ## _isapnp_legacy_probe,			  \
+		.remove = _name ## _isapnp_legacy_remove,		  \
+	};								  \
+	REQUIRE_OBJECT ( isapnp );
+
+static inline void legacy_isapnp_set_drvdata ( void *hwdev, void *priv ) {
+	isapnp_set_drvdata ( hwdev, priv );
+}
+static inline void * legacy_isapnp_get_drvdata ( void *hwdev ) {
+	return isapnp_get_drvdata ( hwdev );
+}
+
+#define EISA_DRIVER(_name,_ids)						  \
+	static inline int						  \
+	_name ## _eisa_legacy_probe ( struct eisa_device *eisa,		  \
+				      const struct eisa_device_id *id );  \
+	static inline void						  \
+	_name ## _eisa_legacy_remove ( struct eisa_device *eisa );	  \
+	struct eisa_driver _name __eisa_driver = {			  \
+		.ids = _ids,						  \
+		.id_count = sizeof ( _ids ) / sizeof ( _ids[0] ),	  \
+		.probe = _name ## _eisa_legacy_probe,			  \
+		.remove = _name ## _eisa_legacy_remove,			  \
+	};								  \
+	REQUIRE_OBJECT ( eisa );
+
+static inline void legacy_eisa_set_drvdata ( void *hwdev, void *priv ) {
+	eisa_set_drvdata ( hwdev, priv );
+}
+static inline void * legacy_eisa_get_drvdata ( void *hwdev ) {
+	return eisa_get_drvdata ( hwdev );
+}
+
+#define MCA_DRIVER(_name,_ids)						  \
+	static inline int						  \
+	_name ## _mca_legacy_probe ( struct mca_device *mca,		  \
+				     const struct mca_device_id *id );	  \
+	static inline void						  \
+	_name ## _mca_legacy_remove ( struct mca_device *mca );		  \
+	struct mca_driver _name __mca_driver = {			  \
+		.ids = _ids,						  \
+		.id_count = sizeof ( _ids ) / sizeof ( _ids[0] ),	  \
+		.probe = _name ## _mca_legacy_probe,			  \
+		.remove = _name ## _mca_legacy_remove,			  \
+	};								  \
+	REQUIRE_OBJECT ( mca );
+
+static inline void legacy_mca_set_drvdata ( void *hwdev, void *priv ) {
+	mca_set_drvdata ( hwdev, priv );
+}
+static inline void * legacy_mca_get_drvdata ( void *hwdev ) {
+	return mca_get_drvdata ( hwdev );
+}
+
+#define ISA_DRIVER(_name,_probe_addrs,_probe_addr,_vendor_id,_prod_id)	  \
+	static inline int						  \
+	_name ## _isa_legacy_probe ( struct isa_device *isa );		  \
+	static inline int						  \
+	_name ## _isa_legacy_probe_at_addr ( struct isa_device *isa ) {	  \
+		if ( ! _probe_addr ( isa->ioaddr ) )			  \
+			return -ENODEV; 				  \
+		return _name ## _isa_legacy_probe ( isa );		  \
+	}								  \
+	static inline void						  \
+	_name ## _isa_legacy_remove ( struct isa_device *isa );		  \
+	static const char _name ## _text[];				  \
+	struct isa_driver _name __isa_driver = {			  \
+		.name = _name ## _text,					  \
+		.probe_addrs = _probe_addrs,				  \
+		.addr_count = ( sizeof ( _probe_addrs ) /		  \
+				sizeof ( _probe_addrs[0] ) ),		  \
+		.vendor_id = _vendor_id,				  \
+		.prod_id = _prod_id,					  \
+		.probe = _name ## _isa_legacy_probe_at_addr,		  \
+		.remove = _name ## _isa_legacy_remove,			  \
+	};								  \
+	REQUIRE_OBJECT ( isa );
+
+static inline void legacy_isa_set_drvdata ( void *hwdev, void *priv ) {
+	isa_set_drvdata ( hwdev, priv );
+}
+static inline void * legacy_isa_get_drvdata ( void *hwdev ) {
+	return isa_get_drvdata ( hwdev );
+}
+
+#undef DRIVER
+#define DRIVER(_name_text,_unused2,_unused3,_name,_probe,_disable)	  \
+	static const char _name ## _text[] = _name_text;		  \
+	static inline int						  \
+	_name ## _probe ( struct nic *nic, void *hwdev ) {		  \
+		return _probe ( nic, hwdev );				  \
+	}								  \
+	static inline void						  \
+	_name ## _disable ( struct nic *nic, void *hwdev ) {		  \
+		void ( * _unsafe_disable ) () = _disable;		  \
+		_unsafe_disable ( nic, hwdev );				  \
+	}								  \
+	static inline int						  \
+	_name ## _pci_legacy_probe ( struct pci_device *pci ) {		  \
+		return legacy_probe ( pci, legacy_pci_set_drvdata,	  \
+				      &pci->dev, _name ## _probe,	  \
+				      _name ## _disable );		  \
+	}								  \
+	static inline void						  \
+	_name ## _pci_legacy_remove ( struct pci_device *pci ) {	  \
+		return legacy_remove ( pci, legacy_pci_get_drvdata,	  \
+				       _name ## _disable );		  \
+	}								  \
+	static inline int						  \
+	_name ## _isapnp_legacy_probe ( struct isapnp_device *isapnp,	  \
+			 const struct isapnp_device_id *id __unused ) {	  \
+		return legacy_probe ( isapnp, legacy_isapnp_set_drvdata,  \
+				      &isapnp->dev, _name ## _probe,	  \
+				      _name ## _disable );		  \
+	}								  \
+	static inline void						  \
+	_name ## _isapnp_legacy_remove ( struct isapnp_device *isapnp ) { \
+		return legacy_remove ( isapnp, legacy_isapnp_get_drvdata, \
+				       _name ## _disable );		  \
+	}								  \
+	static inline int						  \
+	_name ## _eisa_legacy_probe ( struct eisa_device *eisa,		  \
+			     const struct eisa_device_id *id __unused ) { \
+		return legacy_probe ( eisa, legacy_eisa_set_drvdata,	  \
+				      &eisa->dev, _name ## _probe,	  \
+				      _name ## _disable );		  \
+	}								  \
+	static inline void						  \
+	_name ## _eisa_legacy_remove ( struct eisa_device *eisa ) {	  \
+		return legacy_remove ( eisa, legacy_eisa_get_drvdata,	  \
+				       _name ## _disable );		  \
+	}								  \
+	static inline int						  \
+	_name ## _mca_legacy_probe ( struct mca_device *mca,		  \
+			      const struct mca_device_id *id __unused ) { \
+		return legacy_probe ( mca, legacy_mca_set_drvdata,	  \
+				      &mca->dev, _name ## _probe,	  \
+				      _name ## _disable );		  \
+	}								  \
+	static inline void						  \
+	_name ## _mca_legacy_remove ( struct mca_device *mca ) {	  \
+		return legacy_remove ( mca, legacy_mca_get_drvdata,	  \
+				       _name ## _disable );		  \
+	}								  \
+	static inline int						  \
+	_name ## _isa_legacy_probe ( struct isa_device *isa ) {		  \
+		return legacy_probe ( isa, legacy_isa_set_drvdata,	  \
+				      &isa->dev, _name ## _probe,	  \
+				      _name ## _disable );		  \
+	}								  \
+	static inline void						  \
+	_name ## _isa_legacy_remove ( struct isa_device *isa ) {	  \
+		return legacy_remove ( isa, legacy_isa_get_drvdata,	  \
+				       _name ## _disable );		  \
+	}
+
+#endif	/* NIC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/old_tcp.h b/qemu-0.15.x/roms/ipxe/src/include/old_tcp.h
new file mode 100644
index 0000000..93e1485
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/old_tcp.h
@@ -0,0 +1,37 @@
+#ifndef	_TCP_H
+#define	_TCP_H
+
+#define TCP_INITIAL_TIMEOUT     (3*TICKS_PER_SEC)
+#define TCP_MAX_TIMEOUT         (60*TICKS_PER_SEC)
+#define TCP_MIN_TIMEOUT         (TICKS_PER_SEC)
+#define TCP_MAX_RETRY           10
+#define TCP_MAX_HEADER          ((int)sizeof(struct iphdr)+64)
+#define TCP_MIN_WINDOW          (1500-TCP_MAX_HEADER)
+#define TCP_MAX_WINDOW          (65535-TCP_MAX_HEADER)
+
+#define FIN             1
+#define SYN             2
+#define RST             4
+#define PSH             8
+#define ACK             16
+#define URG             32
+
+
+struct tcphdr {
+       uint16_t src;
+       uint16_t dst;
+       int32_t  seq;
+       int32_t  ack;
+       uint16_t ctrl;
+       uint16_t window;
+       uint16_t chksum;
+       uint16_t urgent;
+};
+
+extern int tcp_transaction ( unsigned long destip, unsigned int destsock,
+			     void *ptr,
+			     int (*send)(int len, void *buf, void *ptr),
+			     int (*recv)(int len, const void *buf, void *ptr));
+
+
+#endif	/* _TCP_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/pc_kbd.h b/qemu-0.15.x/roms/ipxe/src/include/pc_kbd.h
new file mode 100644
index 0000000..c125efa
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/pc_kbd.h
@@ -0,0 +1,7 @@
+#ifndef _PC_KBD_H
+#define _PC_KBD_H
+
+int kbd_ischar(void);
+
+int kbd_getc(void);
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/pcmcia-opts.h b/qemu-0.15.x/roms/ipxe/src/include/pcmcia-opts.h
new file mode 100644
index 0000000..70dc092
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/pcmcia-opts.h
@@ -0,0 +1,23 @@
+// pcmcia-opts.h
+// special options file for development time. Later this could end in Config(?)
+#ifndef __pcmciaopts
+#define __pcmciaopts
+
+	#define	_yes_ 1
+	#define	_no_  0
+
+	#define	SUPPORT_I82365		(_yes_)
+//	#define	SUPPORT_YENTA		(_no_)
+//	#define	SUPPORT_SOME_DRIVER	(_no_)
+
+	#define PCMCIA_SHUTDOWN		(_yes_)
+	#define	MAP_ATTRMEM_TO		0xd0000
+	#define	MAP_ATTRMEM_LEN		0x02000
+
+	#define	PDEBUG			3
+	// The higher the more output you get, 0..3
+	// Not fully implemented though, but for the future...
+
+	#undef _yes_
+	#undef _no_
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/include/pcmcia.h b/qemu-0.15.x/roms/ipxe/src/include/pcmcia.h
new file mode 100644
index 0000000..d528bea
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/pcmcia.h
@@ -0,0 +1,156 @@
+//	pcmcia.h - Header file for PCMCIA support
+
+#ifndef PCMCIA_H
+#define	PCMCIA_H
+
+typedef unsigned char	u_char;
+typedef unsigned short	u_short;
+typedef unsigned int	u_int;
+typedef unsigned long	u_long;
+
+typedef u_short		ioaddr_t;
+extern int sockets;
+
+#define	MAXPCCSOCKS	8
+#define	MAXPCCCONFIGS	8
+
+typedef	enum ebpdriver_t	{ I82365, SOMEDRIVER						} ebpdriver_t;
+typedef enum interface_func_t	{ INIT, SHUTDOWN, MAPATTRMEM, UNMAPATTRMEM, SELECTCONFIG	} interface_func_t;
+typedef enum ebpstatus_t	{ EMPTY, HASCARD, INITIALIZED, SUSPENDED, OTHERDEVICE, UNKNOWN	} ebpstatus_t;
+
+struct	driver_interact_t {
+	ebpdriver_t	id;
+	int		(*f)(interface_func_t,int,int,int,int);
+	char		*name;
+};
+struct	pccsock_t {
+	ebpdriver_t	device;
+	int		drivernum;
+	ebpstatus_t	status;
+		// Internal usage of the drivers:
+	int		internalid;
+	int		flags;
+	int		ioaddr;
+	int		type;
+	int		configoffset;
+	int		possibleconfignum;
+	int		stringoffset;
+	u_int		stringlength;
+	int		rmask0;
+};
+
+extern struct	pccsock_t	pccsock[MAXPCCSOCKS];
+extern u_int	pccsocks;
+
+struct	pcc_config_t {
+	u_char	index;
+	u_char	irq;
+	int	iowin;
+	int	iolen;
+};
+
+
+int	i82365_interfacer(interface_func_t,int,int,int,void *);
+void	sleepticks(int);
+
+#define	EINVAL	22
+
+
+//*********************************************************** cc.h:
+/* Definitions for card status flags for GetStatus */
+#define SS_WRPROT       0x0001
+#define SS_CARDLOCK     0x0002
+#define SS_EJECTION     0x0004
+#define SS_INSERTION    0x0008
+#define SS_BATDEAD      0x0010
+#define SS_BATWARN      0x0020
+#define SS_READY        0x0040
+#define SS_DETECT       0x0080
+#define SS_POWERON      0x0100
+#define SS_GPI          0x0200
+#define SS_STSCHG       0x0400
+#define SS_CARDBUS      0x0800
+#define SS_3VCARD       0x1000
+#define SS_XVCARD       0x2000
+#define SS_PENDING      0x4000
+
+/* cc.h: for InquireSocket */
+typedef struct socket_cap_t {
+    u_int       features;
+    u_int       irq_mask;
+    u_int       map_size;
+    ioaddr_t    io_offset;
+    u_char      pci_irq;
+    //struct pci_dev *cb_dev;
+    //struct bus_operations *bus;
+    void *cb_dev;
+    void *bus;
+} socket_cap_t;
+/* InquireSocket capabilities */
+#define SS_CAP_PAGE_REGS        0x0001
+#define SS_CAP_VIRTUAL_BUS      0x0002
+#define SS_CAP_MEM_ALIGN        0x0004
+#define SS_CAP_STATIC_MAP       0x0008
+#define SS_CAP_PCCARD           0x4000
+#define SS_CAP_CARDBUS          0x8000
+
+/* for GetSocket, SetSocket */
+typedef struct socket_state_t {
+    u_int       flags;
+    u_int       csc_mask;
+    u_char      Vcc, Vpp;
+    u_char      io_irq;
+} socket_state_t;
+
+extern socket_state_t dead_socket;
+
+/* Socket configuration flags */
+#define SS_PWR_AUTO     0x0010
+#define SS_IOCARD       0x0020
+#define SS_RESET        0x0040
+#define SS_DMA_MODE     0x0080
+#define SS_SPKR_ENA     0x0100
+#define SS_OUTPUT_ENA   0x0200
+#define SS_DEBOUNCED    0x0400  /* Tell driver that the debounce delay has ended */
+#define SS_ZVCARD       0x0800
+
+/* Flags for I/O port and memory windows */
+#define MAP_ACTIVE      0x01
+#define MAP_16BIT       0x02
+#define MAP_AUTOSZ      0x04
+#define MAP_0WS         0x08
+#define MAP_WRPROT      0x10
+#define MAP_ATTRIB      0x20
+#define MAP_USE_WAIT    0x40
+#define MAP_PREFETCH    0x80
+
+/* Use this just for bridge windows */
+#define MAP_IOSPACE     0x20
+
+typedef struct pccard_io_map {
+    u_char      map;
+    u_char      flags;
+    u_short     speed;
+    ioaddr_t    start, stop;
+} pccard_io_map;
+
+
+typedef struct pccard_mem_map {
+    u_char      map;
+    u_char      flags;
+    u_short     speed;
+    u_long      sys_start, sys_stop;
+    u_int       card_start;
+} pccard_mem_map;
+
+typedef struct cb_bridge_map {
+    u_char      map;
+    u_char      flags;
+    u_int       start, stop;
+} cb_bridge_map;
+// need the global function pointer struct? *TODO*
+//************************************* end cc.h
+
+
+
+#endif /* PCMCIA_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/readline/readline.h b/qemu-0.15.x/roms/ipxe/src/include/readline/readline.h
new file mode 100644
index 0000000..42dfd8c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/readline/readline.h
@@ -0,0 +1,57 @@
+#ifndef _READLINE_H
+#define _READLINE_H
+
+/** @file
+ *
+ * Minmal readline
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A readline history entry */
+struct readline_history_entry {
+	/** Persistent copy of string */
+	char *string;
+	/** Temporary copy of string
+	 *
+	 * The temporary copy exists only during the call to
+	 * readline().
+	 */
+	char *temp;
+};
+
+/** Maximum depth of a readline history buffer
+ *
+ * Must be one less than a power of two.
+ */
+#define READLINE_HISTORY_MAX_DEPTH ( ( 1 << 3 ) - 1 )
+
+/** A readline history buffer */
+struct readline_history {
+	/** History entries
+	 *
+	 * This is a circular buffer, with entries in chronological
+	 * order.  The "next" entry is always empty except during a
+	 * call to readline().
+	 */
+	struct readline_history_entry entries[READLINE_HISTORY_MAX_DEPTH + 1];
+	/** Position of next entry within buffer
+	 *
+	 * This is incremented monotonically each time an entry is
+	 * added to the buffer.
+	 */
+	unsigned int next;
+	/** Current depth within history buffer
+	 *
+	 * This is valid only during the call to readline()
+	 */
+	unsigned int depth;
+};
+
+extern void history_free ( struct readline_history *history );
+extern char * __malloc readline_history ( const char *prompt,
+					  struct readline_history *history );
+extern char * __malloc readline ( const char *prompt );
+
+#endif /* _READLINE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/stdarg.h b/qemu-0.15.x/roms/ipxe/src/include/stdarg.h
new file mode 100644
index 0000000..78b261a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/stdarg.h
@@ -0,0 +1,12 @@
+#ifndef _STDARG_H
+#define _STDARG_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+typedef __builtin_va_list va_list;
+#define va_start( ap, last ) __builtin_va_start ( ap, last )
+#define va_arg( ap, type ) __builtin_va_arg ( ap, type )
+#define va_end( ap ) __builtin_va_end ( ap )
+#define va_copy( dest, src ) __builtin_va_copy ( dest, src )
+
+#endif /* _STDARG_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/stddef.h b/qemu-0.15.x/roms/ipxe/src/include/stddef.h
new file mode 100644
index 0000000..c91a103
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/stddef.h
@@ -0,0 +1,30 @@
+#ifndef STDDEF_H
+#define STDDEF_H
+
+FILE_LICENCE ( GPL2_ONLY );
+
+/* for size_t */
+#include <stdint.h>
+
+#undef NULL
+#define NULL ((void *)0)
+
+#undef offsetof
+#if ( defined ( __GNUC__ ) && ( __GNUC__ > 3 ) )
+#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#undef container_of
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */
+#ifndef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ long int
+#endif
+typedef __WCHAR_TYPE__ wchar_t;
+
+#endif /* STDDEF_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/stdint.h b/qemu-0.15.x/roms/ipxe/src/include/stdint.h
new file mode 100644
index 0000000..8cc9b84
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/stdint.h
@@ -0,0 +1,36 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/*
+ * This is a standard predefined macro on all gcc's I've seen. It's
+ * important that we define size_t in the same way as the compiler,
+ * because that's what it's expecting when it checks %zd/%zx printf
+ * format specifiers.
+ */
+#ifndef __SIZE_TYPE__
+#define __SIZE_TYPE__ unsigned long /* safe choice on most systems */
+#endif
+
+#include <bits/stdint.h>
+
+typedef int8_t s8;
+typedef uint8_t u8;
+typedef int16_t s16;
+typedef uint16_t u16;
+typedef int32_t s32;
+typedef uint32_t u32;
+typedef int64_t s64;
+typedef uint64_t u64;
+
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+#endif /* _STDINT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/stdio.h b/qemu-0.15.x/roms/ipxe/src/include/stdio.h
new file mode 100644
index 0000000..84181f0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/stdio.h
@@ -0,0 +1,47 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdarg.h>
+
+extern int __attribute__ (( format ( printf, 1, 2 ) ))
+printf ( const char *fmt, ... );
+
+extern int __attribute__ (( format ( printf, 3, 4 ) ))
+snprintf ( char *buf, size_t size, const char *fmt, ... );
+
+extern int __attribute__ (( format ( printf, 2, 3 ) ))
+asprintf ( char **strp, const char *fmt, ... );
+
+extern int vprintf ( const char *fmt, va_list args );
+
+extern int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args );
+
+extern int vasprintf ( char **strp, const char *fmt, va_list args );
+
+/**
+ * Write a formatted string to a buffer
+ *
+ * @v buf		Buffer into which to write the string
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+#define sprintf( buf, fmt, ... ) \
+	snprintf ( (buf), ~( ( size_t ) 0 ), (fmt), ## __VA_ARGS__ )
+
+/**
+ * Write a formatted string to a buffer
+ *
+ * @v buf		Buffer into which to write the string
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret len		Length of formatted string
+ */
+static inline int vsprintf ( char *buf, const char *fmt, va_list args ) {
+	return vsnprintf ( buf, ~( ( size_t ) 0 ), fmt, args );
+}
+
+#endif /* _STDIO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/stdlib.h b/qemu-0.15.x/roms/ipxe/src/include/stdlib.h
new file mode 100644
index 0000000..19a7c8e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/stdlib.h
@@ -0,0 +1,115 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <assert.h>
+#include <ctype.h>
+
+/*****************************************************************************
+ *
+ * Numeric parsing
+ *
+ ****************************************************************************
+ */
+
+static inline int strtoul_base ( const char **pp, int base )
+{
+	const char *p = *pp;
+
+	while ( isspace ( *p ) )
+		p++;
+
+	if ( base == 0 ) {
+		base = 10;
+		if ( *p == '0' ) {
+			p++;
+			base = 8;
+			if ( ( *p | 0x20 ) == 'x' ) {
+				p++;
+				base = 16;
+			}
+		}
+	}
+
+	*pp = p;
+
+	return base;
+}
+
+static inline unsigned int strtoul_charval ( unsigned int charval )
+{
+	if ( charval >= 'a' ) {
+		charval = ( charval - 'a' + 10 );
+	} else if ( charval >= 'A' ) {
+		charval = ( charval - 'A' + 10 );
+	} else if ( charval <= '9' ) {
+		charval = ( charval - '0' );
+	}
+
+	return charval;
+}
+
+extern unsigned long strtoul ( const char *p, char **endp, int base );
+extern unsigned long long strtoull ( const char *p, char **endp, int base );
+
+
+/*****************************************************************************
+ *
+ * Memory allocation
+ *
+ ****************************************************************************
+ */
+
+extern void * __malloc malloc ( size_t size );
+extern void * realloc ( void *old_ptr, size_t new_size );
+extern void free ( void *ptr );
+extern void * __malloc zalloc ( size_t len );
+
+/**
+ * Allocate cleared memory
+ *
+ * @v nmemb		Number of members
+ * @v size		Size of each member
+ * @ret ptr		Allocated memory
+ *
+ * Allocate memory as per malloc(), and zero it.
+ *
+ * This is implemented as a static inline, with the body of the
+ * function in zalloc(), since in most cases @c nmemb will be 1 and
+ * doing the multiply is just wasteful.
+ */
+static inline void * __malloc calloc ( size_t nmemb, size_t size ) {
+	return zalloc ( nmemb * size );
+}
+
+/*****************************************************************************
+ *
+ * Random number generation
+ *
+ ****************************************************************************
+ */
+
+extern long int random ( void );
+extern void srandom ( unsigned int seed );
+
+static inline int rand ( void ) {
+	return random();
+}
+
+static inline void srand ( unsigned int seed ) {
+	srandom ( seed );
+}
+
+/*****************************************************************************
+ *
+ * Miscellaneous
+ *
+ ****************************************************************************
+ */
+
+extern int system ( const char *command );
+extern __asmcall int main ( void );
+
+#endif /* STDLIB_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/string.h b/qemu-0.15.x/roms/ipxe/src/include/string.h
new file mode 100644
index 0000000..2fd6acf
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/string.h
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2004 Tobias Lorenz
+ *
+ *  string handling functions
+ *  based on linux/include/linux/ctype.h
+ *       and linux/include/linux/string.h
+ *
+ * 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.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#ifndef ETHERBOOT_STRING_H
+#define ETHERBOOT_STRING_H
+
+#include <stddef.h>
+#include <bits/string.h>
+
+int __pure strnicmp(const char *s1, const char *s2, size_t len) __nonnull;
+char * strcpy(char * dest,const char *src) __nonnull;
+char * strncpy(char * dest,const char *src,size_t count) __nonnull;
+char * strcat(char * dest, const char * src) __nonnull;
+char * strncat(char *dest, const char *src, size_t count) __nonnull;
+int __pure strcmp(const char * cs,const char * ct) __nonnull;
+int __pure strncmp(const char * cs,const char * ct,
+				     size_t count) __nonnull;
+char * __pure strchr(const char * s, int c) __nonnull;
+char * __pure strrchr(const char * s, int c) __nonnull;
+size_t __pure strlen(const char * s) __nonnull;
+size_t __pure strnlen(const char * s, size_t count) __nonnull;
+size_t __pure strspn(const char *s, const char *accept) __nonnull;
+size_t __pure strcspn(const char *s, const char *reject) __nonnull;
+char * __pure strpbrk(const char * cs,const char * ct) __nonnull;
+char * strtok(char * s,const char * ct) __nonnull;
+char * strsep(char **s, const char *ct) __nonnull;
+void * memset(void * s,int c,size_t count) __nonnull;
+void * memmove(void * dest,const void *src,size_t count) __nonnull;
+int __pure memcmp(const void * cs,const void * ct,
+				    size_t count) __nonnull;
+void * __pure memscan(const void * addr, int c, size_t size) __nonnull;
+char * __pure strstr(const char * s1,const char * s2) __nonnull;
+void * __pure memchr(const void *s, int c, size_t n) __nonnull;
+char * __malloc strdup(const char *s) __nonnull;
+char * __malloc strndup(const char *s, size_t n) __nonnull;
+
+extern const char * __pure strerror ( int errno );
+
+#endif /* ETHERBOOT_STRING */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/strings.h b/qemu-0.15.x/roms/ipxe/src/include/strings.h
new file mode 100644
index 0000000..c7063d6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/strings.h
@@ -0,0 +1,65 @@
+#ifndef _STRINGS_H
+#define _STRINGS_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <limits.h>
+#include <string.h>
+
+static inline __attribute__ (( always_inline )) int
+__constant_flsl ( unsigned long x ) {
+	int r = 0;
+
+#if ULONG_MAX > 0xffffffff
+	if ( x & 0xffffffff00000000UL ) {
+		x >>= 32;
+		r += 32;
+	}
+#endif
+	if ( x & 0xffff0000UL ) {
+		x >>= 16;
+		r += 16;
+	}
+	if ( x & 0xff00 ) {
+		x >>= 8;
+		r += 8;
+	}
+	if ( x & 0xf0 ) {
+		x >>= 4;
+		r += 4;
+	}
+	if ( x & 0xc ) {
+		x >>= 2;
+		r += 2;
+	}
+	if ( x & 0x2 ) {
+		x >>= 1;
+		r += 1;
+	}
+	if ( x & 0x1 ) {
+		r += 1;
+	}
+	return r;
+}
+
+/* We don't actually have these functions yet */
+extern int __flsl ( long x );
+
+#define flsl( x ) \
+	( __builtin_constant_p ( x ) ? __constant_flsl ( x ) : __flsl ( x ) )
+
+#define fls( x ) flsl ( x )
+
+extern int strcasecmp ( const char *s1, const char *s2 );
+
+static inline __attribute__ (( always_inline )) void
+bcopy ( const void *src, void *dest, size_t n ) {
+	memmove ( dest, src, n );
+}
+
+static inline __attribute__ (( always_inline )) void
+bzero ( void *s, size_t n ) {
+	memset ( s, 0, n );
+}
+
+#endif /* _STRINGS_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/sys/time.h b/qemu-0.15.x/roms/ipxe/src/include/sys/time.h
new file mode 100644
index 0000000..21fb7e9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/sys/time.h
@@ -0,0 +1,20 @@
+#ifndef _SYS_TIME_H
+#define _SYS_TIME_H
+
+#include <time.h>
+
+typedef unsigned long suseconds_t;
+
+struct timeval {
+	time_t tv_sec;		/* seconds */
+	suseconds_t tv_usec;	/* microseconds */
+};
+
+struct timezone {
+	int tz_minuteswest;	/* minutes W of Greenwich */
+	int tz_dsttime;		/* type of dst correction */
+};
+
+extern int gettimeofday ( struct timeval *tv, struct timezone *tz );
+
+#endif /* _SYS_TIME_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/sys_info.h b/qemu-0.15.x/roms/ipxe/src/include/sys_info.h
new file mode 100644
index 0000000..7127c64
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/sys_info.h
@@ -0,0 +1,33 @@
+#ifndef SYS_INFO_H
+#define SYS_INFO_H
+
+/* Information collected from firmware/bootloader */
+
+struct sys_info {
+    /* Values passed by bootloader */
+    unsigned long boot_type;
+    unsigned long boot_data;
+    unsigned long boot_arg;
+
+    char *firmware; /* "PCBIOS", "LinuxBIOS", etc. */
+    char *command_line; /* command line given to us */
+#if 0
+//By LYH
+//Will use meminfo in Etherboot 
+    /* memory map */
+    int n_memranges;
+    struct memrange {
+	unsigned long long base;
+	unsigned long long size;
+    } *memrange;
+#endif
+};
+
+void collect_sys_info(struct sys_info *info);
+void collect_elfboot_info(struct sys_info *info);
+void collect_linuxbios_info(struct sys_info *info);
+
+/* Our name and version. I want to see single instance of these in the image */
+extern const char *program_name, *program_version;
+
+#endif /* SYS_INFO_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/time.h b/qemu-0.15.x/roms/ipxe/src/include/time.h
new file mode 100644
index 0000000..6ea927c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/time.h
@@ -0,0 +1,22 @@
+#ifndef _TIME_H
+#define _TIME_H
+
+typedef unsigned long time_t;
+
+struct tm {
+	int tm_sec;	/* seconds */
+	int tm_min;	/* minutes */
+	int tm_hour;	/* hours */
+	int tm_mday;	/* day of the month */
+	int tm_mon;	/* month */
+	int tm_year;	/* year */
+	int tm_wday;	/* day of the week */
+	int tm_yday;	/* day in the year */
+	int tm_isdst;	/* daylight saving time */
+};
+
+extern time_t time ( time_t *t );
+
+extern time_t mktime ( struct tm *tm );
+
+#endif /* _TIME_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/unistd.h b/qemu-0.15.x/roms/ipxe/src/include/unistd.h
new file mode 100644
index 0000000..3a50a25
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/unistd.h
@@ -0,0 +1,43 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdarg.h>
+
+extern int execv ( const char *command, char * const argv[] );
+
+/**
+ * Execute command
+ *
+ * @v command		Command name
+ * @v arg ...		Argument list (starting with argv[0])
+ * @ret rc		Command exit status
+ *
+ * This is a front end to execv().
+ */
+#define execl( command, arg, ... ) ( {					\
+		char * const argv[] = { (arg), ## __VA_ARGS__ };	\
+		int rc = execv ( (command), argv );			\
+		rc;							\
+	} )
+
+/* Pick up udelay() */
+#include <ipxe/timer.h>
+
+/*
+ * sleep() prototype is defined by POSIX.1.  usleep() prototype is
+ * defined by 4.3BSD.  udelay() and mdelay() prototypes are chosen to
+ * be reasonably sensible.
+ *
+ */
+
+extern unsigned int sleep ( unsigned int seconds );
+extern void mdelay ( unsigned long msecs );
+
+static inline __always_inline void usleep ( unsigned long usecs ) {
+	udelay ( usecs );
+}
+
+#endif /* _UNISTD_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/autoboot.h b/qemu-0.15.x/roms/ipxe/src/include/usr/autoboot.h
new file mode 100644
index 0000000..a608b3d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/autoboot.h
@@ -0,0 +1,25 @@
+#ifndef _USR_AUTOBOOT_H
+#define _USR_AUTOBOOT_H
+
+/** @file
+ *
+ * Automatic booting
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/in.h>
+struct net_device;
+struct uri;
+struct settings;
+
+extern int uriboot ( struct uri *filename, struct uri *root_path );
+extern struct uri *
+fetch_next_server_and_filename ( struct settings *settings );
+extern int netboot ( struct net_device *netdev );
+extern int autoboot ( void );
+
+extern int pxe_menu_boot ( struct net_device *netdev );
+
+#endif /* _USR_AUTOBOOT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/dhcpmgmt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/dhcpmgmt.h
new file mode 100644
index 0000000..2394dac
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/dhcpmgmt.h
@@ -0,0 +1,17 @@
+#ifndef _USR_DHCPMGMT_H
+#define _USR_DHCPMGMT_H
+
+/** @file
+ *
+ * DHCP management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net_device;
+
+extern int dhcp ( struct net_device *netdev );
+extern int pxebs ( struct net_device *netdev, unsigned int pxe_type );
+
+#endif /* _USR_DHCPMGMT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/fcmgmt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/fcmgmt.h
new file mode 100644
index 0000000..9441cef
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/fcmgmt.h
@@ -0,0 +1,21 @@
+#ifndef _USR_FCMGMT_H
+#define _USR_FCMGMT_H
+
+/** @file
+ *
+ * Fibre Channel management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct fc_port;
+struct fc_peer;
+struct fc_els_handler;
+
+extern void fcportstat ( struct fc_port *port );
+extern void fcpeerstat ( struct fc_peer *peer );
+extern int fcels ( struct fc_port *port, struct fc_port_id *peer_port_id,
+		   struct fc_els_handler *handler );
+
+#endif /* _USR_FCMGMT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/ifmgmt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/ifmgmt.h
new file mode 100644
index 0000000..f762c7b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/ifmgmt.h
@@ -0,0 +1,19 @@
+#ifndef _USR_IFMGMT_H
+#define _USR_IFMGMT_H
+
+/** @file
+ *
+ * Network interface management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net_device;
+
+extern int ifopen ( struct net_device *netdev );
+extern void ifclose ( struct net_device *netdev );
+extern void ifstat ( struct net_device *netdev );
+extern int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms );
+
+#endif /* _USR_IFMGMT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/imgmgmt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/imgmgmt.h
new file mode 100644
index 0000000..1c0a212
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/imgmgmt.h
@@ -0,0 +1,56 @@
+#ifndef _USR_IMGMGMT_H
+#define _USR_IMGMGMT_H
+
+/** @file
+ *
+ * Image management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/image.h>
+
+extern int register_and_put_image ( struct image *image );
+extern int register_and_probe_image ( struct image *image );
+extern int register_and_select_image ( struct image *image );
+extern int register_and_boot_image ( struct image *image );
+extern int register_and_replace_image ( struct image *image );
+extern int imgdownload ( struct uri *uri, const char *name, const char *cmdline,
+			 int ( * action ) ( struct image *image ) );
+extern int imgdownload_string ( const char *uri_string, const char *name,
+				const char *cmdline,
+				int ( * action ) ( struct image *image ) );
+extern void imgstat ( struct image *image );
+extern void imgfree ( struct image *image );
+
+/**
+ * Select an image for execution
+ *
+ * @v image		Image
+ * @ret rc		Return status code
+ */
+static inline int imgselect ( struct image *image ) {
+	return image_select ( image );
+}
+
+/**
+ * Find the previously-selected image
+ *
+ * @ret image		Image, or NULL
+ */
+static inline struct image * imgautoselect ( void ) {
+	return image_find_selected();
+}
+
+/**
+ * Execute an image
+ *
+ * @v image		Image
+ * @ret rc		Return status code
+ */
+static inline int imgexec ( struct image *image ) {
+	return image_exec ( image );
+}
+
+#endif /* _USR_IMGMGMT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/iwmgmt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/iwmgmt.h
new file mode 100644
index 0000000..c1bdc37
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/iwmgmt.h
@@ -0,0 +1,17 @@
+#ifndef _USR_IWMGMT_H
+#define _USR_IWMGMT_H
+
+/** @file
+ *
+ * Wireless network interface management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net80211_device;
+
+extern void iwstat ( struct net80211_device *dev );
+extern int iwlist ( struct net80211_device *dev );
+
+#endif /* _USR_IWMGMT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/lotest.h b/qemu-0.15.x/roms/ipxe/src/include/usr/lotest.h
new file mode 100644
index 0000000..aa4bbac
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/lotest.h
@@ -0,0 +1,15 @@
+#ifndef _USR_LOTEST_H
+#define _USR_LOTEST_H
+
+/** @file
+ *
+ * Loopback testing
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern int loopback_test ( struct net_device *sender,
+			   struct net_device *receiver, size_t mtu );
+
+#endif /* _USR_LOTEST_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/prompt.h b/qemu-0.15.x/roms/ipxe/src/include/usr/prompt.h
new file mode 100644
index 0000000..fc1946c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/prompt.h
@@ -0,0 +1,14 @@
+#ifndef _USR_PROMPT_H
+#define _USR_PROMPT_H
+
+/** @file
+ *
+ * Prompt for keypress
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern int prompt ( const char *text, unsigned int wait_ms, int key );
+
+#endif /* _USR_PROMPT_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/include/usr/route.h b/qemu-0.15.x/roms/ipxe/src/include/usr/route.h
new file mode 100644
index 0000000..855fa7b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/include/usr/route.h
@@ -0,0 +1,14 @@
+#ifndef _USR_ROUTE_H
+#define _USR_ROUTE_H
+
+/** @file
+ *
+ * Routing table management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern void route ( void );
+
+#endif /* _USR_ROUTE_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/bofm/bofm.c b/qemu-0.15.x/roms/ipxe/src/interface/bofm/bofm.c
new file mode 100644
index 0000000..dfa76d3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/bofm/bofm.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/list.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/bofm.h>
+
+/** @file
+ *
+ * IBM BladeCenter Open Fabric Manager (BOFM)
+ *
+ */
+
+/** List of BOFM devices */
+static LIST_HEAD ( bofmdevs );
+
+/**
+ * Register BOFM device
+ *
+ * @v bofm		BOFM device
+ * @ret rc		Return status code
+ */
+int bofm_register ( struct bofm_device *bofm ) {
+
+	list_add ( &bofm->list, &bofmdevs );
+	DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n",
+	      PCI_ARGS ( bofm->pci ), bofm->pci->id->name );
+	return 0;
+}
+
+/**
+ * Unregister BOFM device
+ *
+ * @v bofm		BOFM device
+ */
+void bofm_unregister ( struct bofm_device *bofm ) {
+
+	list_del ( &bofm->list );
+	DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
+}
+
+/**
+ * Find BOFM device matching PCI bus:dev.fn address
+ *
+ * @v busdevfn		PCI bus:dev.fn address
+ * @ret bofm		BOFM device, or NULL
+ */
+static struct bofm_device * bofm_find_busdevfn ( unsigned int busdevfn ) {
+	struct bofm_device *bofm;
+
+	list_for_each_entry ( bofm, &bofmdevs, list ) {
+		if ( bofm->pci->busdevfn == busdevfn )
+			return bofm;
+	}
+	return NULL;
+}
+
+/**
+ * Find BOFM driver for PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+int bofm_find_driver ( struct pci_device *pci ) {
+	struct pci_driver *driver;
+	struct pci_device_id *id;
+	unsigned int i;
+
+	for_each_table_entry ( driver, BOFM_DRIVERS ) {
+		for ( i = 0 ; i < driver->id_count ; i++ ) {
+			id = &driver->ids[i];
+			if ( ( id->vendor == pci->vendor ) &&
+			     ( id->device == pci->device ) ) {
+				pci_set_driver ( pci, driver, id );
+				return 0;
+			}
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * Probe PCI device for BOFM driver
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int bofm_probe ( struct pci_device *pci ) {
+	int rc;
+
+	/* Probe device */
+	if ( ( rc = pci_probe ( pci ) ) != 0 ) {
+		DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n",
+		      PCI_ARGS ( pci ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void bofm_remove ( struct pci_device *pci ) {
+
+	/* Note that the IBM BIOS may re-read the expansion ROM after
+	 * the BOFM initialisation call.  The BOFM driver must ensure
+	 * that the card is left in a state in which expansion ROM
+	 * reads will succeed.  (For example, if a card contains an
+	 * embedded CPU that may issue reads to the same underlying
+	 * flash device, and these reads are not locked against reads
+	 * via the expansion ROM BAR, then the CPU must be stopped.)
+	 *
+	 * If this is not done, then occasional corrupted reads from
+	 * the expansion ROM will be seen, and the BIOS may complain
+	 * about a ROM checksum error.
+	 */
+	pci_remove ( pci );
+	DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
+}
+
+/**
+ * Locate BOFM table section
+ *
+ * @v bofmtab		BOFM table
+ * @v len		Length of BOFM table
+ * @v magic		Section magic
+ * @v bofmsec		BOFM section header to fill in
+ * @ret offset		Offset to section, or 0 if not found
+ */
+static size_t bofm_locate_section ( userptr_t bofmtab, size_t len,
+				    uint32_t magic,
+				    struct bofm_section_header *bofmsec ) {
+	size_t offset = sizeof ( struct bofm_global_header );
+
+	while ( offset < len ) {
+		copy_from_user ( bofmsec, bofmtab, offset,
+				 sizeof ( *bofmsec ) );
+		if ( bofmsec->magic == magic )
+			return offset;
+		if ( bofmsec->magic == BOFM_DONE_MAGIC )
+			break;
+		offset += ( sizeof ( *bofmsec ) + bofmsec->length );
+	}
+	return 0;
+}
+
+/**
+ * Process BOFM Ethernet parameter entry
+ *
+ * @v bofm		BOFM device
+ * @v en		EN parameter entry
+ * @ret rc		Return status code
+ */
+static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
+	uint8_t mac[6];
+	int rc;
+
+	/* Retrieve current MAC address */
+	if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
+		DBG ( "BOFM: " PCI_FMT " port %d could not harvest: %s\n",
+		      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Harvest MAC address if necessary */
+	if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
+		DBG ( "BOFM: " PCI_FMT " port %d harvested MAC %s\n",
+		      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
+		memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
+		en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
+	}
+
+	/* Mark as changed if necessary */
+	if ( ( en->options & BOFM_EN_EN_A ) &&
+	     ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
+		DBG ( "BOFM: " PCI_FMT " port %d MAC %s",
+		      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
+		DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
+		en->options |= BOFM_EN_CHG_CHANGED;
+	}
+
+	/* Apply MAC address if necessary */
+	if ( ( en->options & BOFM_EN_EN_A ) &&
+	     ( en->options & BOFM_EN_USAGE_ENTRY ) &&
+	     ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
+		DBG ( "BOFM: " PCI_FMT " port %d applied MAC %s\n",
+		      PCI_ARGS ( bofm->pci ), en->mport,
+		      eth_ntoa ( en->mac_a ) );
+		memcpy ( mac, en->mac_a, sizeof ( mac ) );
+	}
+
+	/* Store MAC address */
+	if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
+		DBG ( "BOFM: " PCI_FMT " port %d could not update: %s\n",
+		      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Process BOFM table
+ *
+ * @v bofmtab		BOFM table
+ * @v pci		PCI device
+ * @ret bofmrc		BOFM return status
+ */
+int bofm ( userptr_t bofmtab, struct pci_device *pci ) {
+	struct bofm_global_header bofmhdr;
+	struct bofm_section_header bofmsec;
+	struct bofm_en en;
+	struct bofm_device *bofm;
+	size_t en_region_offset;
+	size_t en_offset;
+	int skip;
+	int rc;
+	int bofmrc;
+
+	/* Read BOFM structure */
+	copy_from_user ( &bofmhdr, bofmtab, 0, sizeof ( bofmhdr ) );
+	if ( bofmhdr.magic != BOFM_IOAA_MAGIC ) {
+		DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n",
+		      BOFM_MAGIC_ARGS ( bofmhdr.magic ) );
+		bofmrc = BOFM_ERR_INVALID_ACTION;
+		goto err_bad_signature;
+	}
+	DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n",
+	      BOFM_MAGIC_ARGS ( bofmhdr.action ), bofmhdr.profile );
+
+	/* Determine whether or not we should skip normal POST
+	 * initialisation.
+	 */
+	switch ( bofmhdr.action ) {
+	case BOFM_ACTION_UPDT:
+	case BOFM_ACTION_DFLT:
+	case BOFM_ACTION_HVST:
+		skip = BOFM_SKIP_INIT;
+		break;
+	case BOFM_ACTION_PARM:
+	case BOFM_ACTION_NONE:
+		skip = 0;
+		break;
+	default:
+		DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n",
+		      BOFM_MAGIC_ARGS ( bofmhdr.action ) );
+		bofmrc = BOFM_ERR_INVALID_ACTION;
+		goto err_bad_action;
+	}
+
+	/* Find BOFM driver */
+	if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) {
+		DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) );
+		bofmrc = BOFM_ERR_DEVICE_ERROR;
+		goto err_find_driver;
+	}
+
+	/* Probe driver for PCI device */
+	if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
+		bofmrc = BOFM_ERR_DEVICE_ERROR;
+		goto err_probe;
+	}
+
+	/* Locate EN section, if present */
+	en_region_offset = bofm_locate_section ( bofmtab, bofmhdr.length,
+						 BOFM_EN_MAGIC, &bofmsec );
+	if ( ! en_region_offset ) {
+		DBG ( "BOFM: No EN section found\n" );
+		bofmrc = ( BOFM_SUCCESS | skip );
+		goto err_no_en_section;
+	}
+
+	/* Iterate through EN entries */
+	for ( en_offset = ( en_region_offset + sizeof ( bofmsec ) ) ;
+	      en_offset < ( en_region_offset + sizeof ( bofmsec ) +
+			    bofmsec.length ) ; en_offset += sizeof ( en ) ) {
+		copy_from_user ( &en, bofmtab, en_offset, sizeof ( en ) );
+		DBG2 ( "BOFM: EN entry found:\n" );
+		DBG2_HDA ( en_offset, &en, sizeof ( en ) );
+		if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
+			DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
+			      en.slot, en.port );
+			continue;
+		}
+		bofm = bofm_find_busdevfn ( en.busdevfn );
+		if ( ! bofm ) {
+			DBG ( "BOFM: " PCI_FMT " ignored\n",
+			      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
+			      PCI_FUNC ( en.busdevfn ) );
+			continue;
+		}
+		if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) {
+			en.options |= BOFM_EN_CSM_SUCCESS;
+		} else {
+			en.options |= BOFM_EN_CSM_FAILED;
+		}
+		DBG2 ( "BOFM: EN entry after processing:\n" );
+		DBG2_HDA ( en_offset, &en, sizeof ( en ) );
+		copy_to_user ( bofmtab, en_offset, &en, sizeof ( en ) );
+	}
+
+	bofmrc = ( BOFM_SUCCESS | skip );
+
+ err_no_en_section:
+	bofm_remove ( pci );
+ err_probe:
+ err_find_driver:
+ err_bad_action:
+ err_bad_signature:
+	return bofmrc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_bofm.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_bofm.c
new file mode 100644
index 0000000..1d647db
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_bofm.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/bofm.h>
+#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_pci.h>
+#include <ipxe/efi/efi_driver.h>
+
+/** @file
+ *
+ * IBM BladeCenter Open Fabric Manager (BOFM) EFI interface
+ *
+ */
+
+/***************************************************************************
+ *
+ * EFI BOFM definitions
+ *
+ ***************************************************************************
+ *
+ * Taken from the BOFM UEFI Vendor Specification document
+ *
+ */
+
+#define IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL_GUID			\
+	{ 0x03207ce2, 0xd9c7, 0x11dc,					\
+	  { 0xa9, 0x4d, 0x00, 0x19, 0x7d, 0x89, 0x02, 0x38 } }
+
+#define IBM_BOFM_DRIVER_CONFIGURATION2_PROTOCOL_GUID			\
+	{ 0xe82a9763, 0x0584, 0x4e41,					\
+	  { 0xbb, 0x39, 0xe0, 0xcd, 0xb8, 0xc1, 0xf0, 0xfc } }
+
+typedef struct {
+	UINT8 Id;
+	UINT8 ResultByte;
+} __attribute__ (( packed )) BOFM_EPID_Results_t;
+
+typedef struct {
+	UINT8 Version;
+	UINT8 Level;
+	UINT16 Length;
+	UINT8 Checksum;
+	UINT8 Profile[32];
+	UINT8 GlobalOption0;
+	UINT8 GlobalOption1;
+	UINT8 GlobalOption2;
+	UINT8 GlobalOption3;
+	UINT32 SequenceStamp;
+	UINT8 Regions[911]; // For use by BOFM Driver
+	UINT32 Reserved1;
+} __attribute__ (( packed )) BOFM_Parameters_t;
+
+typedef struct {
+	UINT32 Reserved1;
+	UINT8 Version;
+	UINT8 Level;
+	UINT8 Checksum;
+	UINT32 SequenceStamp;
+	UINT8 SUIDResults;
+	UINT8 EntryResults[32];
+	UINT8 Reserved2;
+	UINT8 Reserved3;
+	UINT8 FCTgtResults[2];
+	UINT8 SASTgtResults[2];
+	BOFM_EPID_Results_t EPIDResults[2];
+	UINT8 Results4[10];
+} __attribute__ (( packed )) BOFM_Results_t;
+
+typedef struct {
+	UINT32 Signature;
+	UINT32 SubSignature;
+	BOFM_Parameters_t Parameters;
+	BOFM_Results_t Results;
+} __attribute__ (( packed )) BOFM_DataStructure_t;
+
+#define IBM_BOFM_TABLE BOFM_DataStructure_t
+
+typedef struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL
+	IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL;
+
+typedef EFI_STATUS ( EFIAPI *IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT ) (
+	IN IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *This,
+	EFI_HANDLE ControllerHandle,
+	UINT8 SupporttedOptions,
+	UINT8 iSCSI_Parameter_Version,
+	UINT8 BOFM_Parameter_Version
+);
+
+typedef EFI_STATUS ( EFIAPI *IBM_BOFM_DRIVER_CONFIGURATION_STATUS ) (
+	IN IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *This,
+	EFI_HANDLE ControllerHandle,
+	BOOLEAN ResetRequired,
+	UINT8 BOFMReturnCode
+);
+
+struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL {
+	IBM_BOFM_TABLE BofmTable;
+	IBM_BOFM_DRIVER_CONFIGURATION_STATUS SetStatus;
+	IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT RegisterSupport;
+};
+
+typedef struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 {
+	UINT32 Signature;
+	UINT32 Reserved1;
+	UINT64 Reserved2;
+	IBM_BOFM_DRIVER_CONFIGURATION_STATUS SetStatus;
+	IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT RegisterSupport;
+	IBM_BOFM_TABLE BofmTable;
+} IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2;
+
+/***************************************************************************
+ *
+ * EFI BOFM interface
+ *
+ ***************************************************************************
+ */
+
+/** BOFM1 protocol GUID */
+static EFI_GUID bofm1_protocol_guid =
+	IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL_GUID;
+
+/** BOFM2 protocol GUID */
+static EFI_GUID bofm2_protocol_guid =
+	IBM_BOFM_DRIVER_CONFIGURATION2_PROTOCOL_GUID;
+
+/**
+ * Check if device is supported
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v child		Path to child device, if any
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+		     EFI_HANDLE device,
+		     EFI_DEVICE_PATH_PROTOCOL *child ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	union {
+		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
+		void *interface;
+	} bofm1;
+	struct efi_pci_device *efipci;
+	EFI_STATUS efirc;
+	int rc;
+
+	DBGCP ( efidrv, "BOFM DRIVER_SUPPORTED %p (%p)\n", device, child );
+
+	/* Create corresponding PCI device, if any */
+	efipci = efipci_create ( efidrv, device );
+	if ( ! efipci ) {
+		efirc = EFI_UNSUPPORTED;
+		goto err_not_pci;
+	}
+
+	/* Look for a BOFM driver */
+	if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) {
+		DBGC2 ( efidrv, "BOFM " PCI_FMT " has no driver\n",
+			PCI_ARGS ( &efipci->pci ) );
+		efirc = EFI_UNSUPPORTED;
+		goto err_no_driver;
+	}
+
+	/* Locate BOFM protocol */
+	if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
+					    &bofm1.interface ) ) != 0 ) {
+		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM protocol\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		efirc = EFI_UNSUPPORTED;
+		goto err_not_bofm;
+	}
+
+	/* Register support for this device */
+	if ( ( efirc = bofm1.bofm1->RegisterSupport ( bofm1.bofm1, device,
+						      0x04 /* Can change MAC */,
+						      0x00 /* No iSCSI */,
+						      0x02 /* Version */ ))!=0){
+		DBGC ( efidrv, "BOFM " PCI_FMT " could not register support: "
+		       "%s\n", PCI_ARGS ( &efipci->pci ),
+		       efi_strerror ( efirc ) );
+		goto err_cannot_register;
+	}
+
+	DBGC ( efidrv, "BOFM " PCI_FMT " is supported by driver \"%s\"\n",
+	       PCI_ARGS ( &efipci->pci ), efipci->pci.id->name );
+
+	/* Destroy temporary PCI device */
+	efipci_destroy ( efidrv, efipci );
+
+	return 0;
+
+ err_cannot_register:
+ err_not_bofm:
+ err_no_driver:
+	efipci_destroy ( efidrv, efipci );
+ err_not_pci:
+	return efirc;
+}
+
+/**
+ * Attach driver to device
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v child		Path to child device, if any
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+				   EFI_HANDLE device,
+				   EFI_DEVICE_PATH_PROTOCOL *child ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	union {
+		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
+		void *interface;
+	} bofm1;
+	union {
+		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 *bofm2;
+		void *interface;
+	} bofm2;
+	struct efi_pci_device *efipci;
+	userptr_t bofmtab;
+	EFI_STATUS efirc;
+	int bofmrc;
+
+	DBGCP ( efidrv, "BOFM DRIVER_START %p (%p)\n", device, child );
+
+	/* Create corresponding PCI device */
+	efipci = efipci_create ( efidrv, device );
+	if ( ! efipci ) {
+		efirc = EFI_OUT_OF_RESOURCES;
+		goto err_create;
+	}
+
+	/* Enable PCI device */
+	if ( ( efirc = efipci_enable ( efipci ) ) != 0 )
+		goto err_enable;
+
+	/* Locate BOFM protocol */
+	if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
+					    &bofm1.interface ) ) != 0 ) {
+		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM protocol\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		goto err_locate_bofm;
+	}
+
+	/* Locate BOFM2 protocol, if available */
+	if ( ( efirc = bs->LocateProtocol ( &bofm2_protocol_guid, NULL,
+					    &bofm2.interface ) ) != 0 ) {
+		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM2 protocol\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		/* Not a fatal error; may be a BOFM1-only system */
+		bofm2.bofm2 = NULL;
+	}
+
+	/* Select appropriate BOFM table (v1 or v2) to use */
+	if ( bofm2.bofm2 ) {
+		DBGC ( efidrv, "BOFM " PCI_FMT " using version 2 BOFM table\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		assert ( bofm2.bofm2->RegisterSupport ==
+			 bofm1.bofm1->RegisterSupport );
+		assert ( bofm2.bofm2->SetStatus == bofm1.bofm1->SetStatus );
+		bofmtab = virt_to_user ( &bofm2.bofm2->BofmTable );
+	} else {
+		DBGC ( efidrv, "BOFM " PCI_FMT " using version 1 BOFM table\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		bofmtab = virt_to_user ( &bofm1.bofm1->BofmTable );
+	}
+
+	/* Process BOFM table */
+	bofmrc = bofm ( bofmtab, &efipci->pci );
+	DBGC ( efidrv, "BOFM " PCI_FMT " status %08x\n",
+	       PCI_ARGS ( &efipci->pci ), bofmrc );
+
+	/* Return BOFM status */
+	if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device, FALSE,
+						bofmrc ) ) != 0 ) {
+		DBGC ( efidrv, "BOFM " PCI_FMT " could not set BOFM status: "
+		       "%s\n", PCI_ARGS ( &efipci->pci ),
+		       efi_strerror ( efirc ) );
+		goto err_set_status;
+	}
+
+	/* Destroy the PCI device anyway; we have no further use for it */
+	efipci_destroy ( efidrv, efipci );
+
+	/* BOFM (ab)uses the "start" method to mean "process and exit" */
+	return EFI_NOT_READY;
+
+ err_set_status:
+ err_locate_bofm:
+ err_enable:
+	efipci_destroy ( efidrv, efipci );
+ err_create:
+	return efirc;
+}
+
+/**
+ * Detach driver from device
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v num_children	Number of child devices
+ * @v children		List of child devices
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_bofm_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+					 EFI_HANDLE device, UINTN num_children,
+					 EFI_HANDLE *children ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+
+	DBGCP ( efidrv, "BOFM DRIVER_STOP %p (%ld %p)\n",
+		device, ( ( unsigned long ) num_children ), children );
+
+	return 0;
+}
+
+/** EFI BOFM driver */
+static struct efi_driver efi_bofm_driver =
+	EFI_DRIVER_INIT ( "BOFM",
+			  efi_bofm_supported, efi_bofm_start, efi_bofm_stop );
+
+/**
+ * Install EFI BOFM driver
+ *
+ */
+static void efi_bofm_driver_init ( void ) {
+	struct efi_driver *efidrv = &efi_bofm_driver;
+	EFI_STATUS efirc;
+
+	/* Install driver */
+	if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) {
+		DBGC ( efidrv, "BOFM could not install driver: %s\n",
+		       efi_strerror ( efirc ) );
+		return;
+	}
+
+	DBGC ( efidrv, "BOFM driver installed\n" );
+}
+
+/** EFI BOFM startup function */
+struct startup_fn startup_bofm __startup_fn ( STARTUP_EARLY ) = {
+	.startup = efi_bofm_driver_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_console.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_console.c
new file mode 100644
index 0000000..1303a42
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_console.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <assert.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/ansiesc.h>
+#include <ipxe/console.h>
+
+#define ATTR_BOLD		0x08
+
+#define ATTR_FCOL_MASK		0x07
+#define ATTR_FCOL_BLACK		0x00
+#define ATTR_FCOL_BLUE		0x01
+#define ATTR_FCOL_GREEN		0x02
+#define ATTR_FCOL_CYAN		0x03
+#define ATTR_FCOL_RED		0x04
+#define ATTR_FCOL_MAGENTA	0x05
+#define ATTR_FCOL_YELLOW	0x06
+#define ATTR_FCOL_WHITE		0x07
+
+#define ATTR_BCOL_MASK		0x70
+#define ATTR_BCOL_BLACK		0x00
+#define ATTR_BCOL_BLUE		0x10
+#define ATTR_BCOL_GREEN		0x20
+#define ATTR_BCOL_CYAN		0x30
+#define ATTR_BCOL_RED		0x40
+#define ATTR_BCOL_MAGENTA	0x50
+#define ATTR_BCOL_YELLOW	0x60
+#define ATTR_BCOL_WHITE		0x70
+
+#define ATTR_DEFAULT		ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int efi_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count		Parameter count
+ * @v params[0]		Row (1 is top)
+ * @v params[1]		Column (1 is left)
+ */
+static void efi_handle_cup ( unsigned int count __unused, int params[] ) {
+	EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+	int cx = ( params[1] - 1 );
+	int cy = ( params[0] - 1 );
+
+	if ( cx < 0 )
+		cx = 0;
+	if ( cy < 0 )
+		cy = 0;
+
+	conout->SetCursorPosition ( conout, cx, cy );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count		Parameter count
+ * @v params[0]		Region to erase
+ */
+static void efi_handle_ed ( unsigned int count __unused,
+			     int params[] __unused ) {
+	EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+
+	/* We assume that we always clear the whole screen */
+	assert ( params[0] == ANSIESC_ED_ALL );
+
+	conout->ClearScreen ( conout );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count		Parameter count
+ * @v params		List of graphic rendition aspects
+ */
+static void efi_handle_sgr ( unsigned int count, int params[] ) {
+	EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+	static const uint8_t efi_attr_fcols[10] = {
+		ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+		ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+		ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+		ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+	};
+	static const uint8_t efi_attr_bcols[10] = {
+		ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+		ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+		ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+		ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+	};
+	unsigned int i;
+	int aspect;
+
+	for ( i = 0 ; i < count ; i++ ) {
+		aspect = params[i];
+		if ( aspect == 0 ) {
+			efi_attr = ATTR_DEFAULT;
+		} else if ( aspect == 1 ) {
+			efi_attr |= ATTR_BOLD;
+		} else if ( aspect == 22 ) {
+			efi_attr &= ~ATTR_BOLD;
+		} else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+			efi_attr &= ~ATTR_FCOL_MASK;
+			efi_attr |= efi_attr_fcols[ aspect - 30 ];
+		} else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+			efi_attr &= ~ATTR_BCOL_MASK;
+			efi_attr |= efi_attr_bcols[ aspect - 40 ];
+		}
+	}
+
+	conout->SetAttribute ( conout, efi_attr );
+}
+
+/** EFI console ANSI escape sequence handlers */
+static struct ansiesc_handler efi_ansiesc_handlers[] = {
+	{ ANSIESC_CUP, efi_handle_cup },
+	{ ANSIESC_ED, efi_handle_ed },
+	{ ANSIESC_SGR, efi_handle_sgr },
+	{ 0, NULL }
+};
+
+/** EFI console ANSI escape sequence context */
+static struct ansiesc_context efi_ansiesc_ctx = {
+	.handlers = efi_ansiesc_handlers,
+};
+
+/**
+ * Print a character to EFI console
+ *
+ * @v character		Character to be printed
+ */
+static void efi_putchar ( int character ) {
+	EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+	wchar_t wstr[] = { character, 0 };
+
+	/* Intercept ANSI escape sequences */
+	character = ansiesc_process ( &efi_ansiesc_ctx, character );
+	if ( character < 0 )
+		return;
+
+	conout->OutputString ( conout, wstr );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return.  When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/** Mapping from EFI scan codes to ANSI escape sequences */
+static const char *ansi_sequences[] = {
+	[SCAN_UP] = "[A",
+	[SCAN_DOWN] = "[B",
+	[SCAN_RIGHT] = "[C",
+	[SCAN_LEFT] = "[D",
+	[SCAN_HOME] = "[H",
+	[SCAN_END] = "[F",
+	[SCAN_INSERT] = "[2~",
+	/* EFI translates an incoming backspace via the serial console
+	 * into a SCAN_DELETE.  There's not much we can do about this.
+	 */
+	[SCAN_DELETE] = "[3~",
+	[SCAN_PAGE_UP] = "[5~",
+	[SCAN_PAGE_DOWN] = "[6~",
+	/* EFI translates some (but not all) incoming escape sequences
+	 * via the serial console into equivalent scancodes.  When it
+	 * doesn't recognise a sequence, it helpfully(!) translates
+	 * the initial ESC and passes the remainder through verbatim.
+	 * Treating SCAN_ESC as equivalent to an empty escape sequence
+	 * works around this bug.
+	 */
+	[SCAN_ESC] = "",
+};
+
+/**
+ * Get ANSI escape sequence corresponding to EFI scancode
+ *
+ * @v scancode		EFI scancode
+ * @ret ansi_seq	ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+	if ( scancode < ( sizeof ( ansi_sequences ) /
+			  sizeof ( ansi_sequences[0] ) ) ) {
+		return ansi_sequences[scancode];
+	}
+	return NULL;
+}
+
+/**
+ * Get character from EFI console
+ *
+ * @ret character	Character read from console
+ */
+static int efi_getchar ( void ) {
+	EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+	const char *ansi_seq;
+	EFI_INPUT_KEY key;
+	EFI_STATUS efirc;
+
+	/* If we are mid-sequence, pass out the next byte */
+	if ( *ansi_input )
+		return *(ansi_input++);
+
+	/* Read key from real EFI console */
+	if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) {
+		DBG ( "EFI could not read keystroke: %s\n",
+		      efi_strerror ( efirc ) );
+		return 0;
+	}
+	DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n",
+	       key.UnicodeChar, key.ScanCode );
+
+	/* If key has a Unicode representation, return it */
+	if ( key.UnicodeChar )
+		return key.UnicodeChar;
+
+	/* Otherwise, check for a special key that we know about */
+	if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) {
+		/* Start of escape sequence: return ESC (0x1b) */
+		ansi_input = ansi_seq;
+		return 0x1b;
+	}
+
+	return 0;
+}
+
+/**
+ * Check for character ready to read from EFI console
+ *
+ * @ret True		Character available to read
+ * @ret False		No character available to read
+ */
+static int efi_iskey ( void ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+	EFI_STATUS efirc;
+
+	/* If we are mid-sequence, we are always ready */
+	if ( *ansi_input )
+		return 1;
+
+	/* Check to see if the WaitForKey event has fired */
+	if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 )
+		return 1;
+
+	return 0;
+}
+
+struct console_driver efi_console __console_driver = {
+	.putchar = efi_putchar,
+	.getchar = efi_getchar,
+	.iskey = efi_iskey,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_driver.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_driver.c
new file mode 100644
index 0000000..4aa976f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_driver.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdio.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/DriverBinding.h>
+#include <ipxe/efi/Protocol/ComponentName2.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_driver.h>
+#include <config/general.h>
+
+/** @file
+ *
+ * EFI driver interface
+ *
+ */
+
+/** EFI driver binding protocol GUID */
+static EFI_GUID efi_driver_binding_protocol_guid
+	= EFI_DRIVER_BINDING_PROTOCOL_GUID;
+
+/** EFI component name protocol GUID */
+static EFI_GUID efi_component_name2_protocol_guid
+	= EFI_COMPONENT_NAME2_PROTOCOL_GUID;
+
+/**
+ * Find end of device path
+ *
+ * @v path		Path to device
+ * @ret path_end	End of device path
+ */
+EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
+
+	while ( path->Type != END_DEVICE_PATH_TYPE ) {
+		path = ( ( ( void * ) path ) +
+			 /* There's this amazing new-fangled thing known as
+			  * a UINT16, but who wants to use one of those? */
+			 ( ( path->Length[1] << 8 ) | path->Length[0] ) );
+	}
+
+	return path;
+}
+
+/**
+ * Look up driver name
+ *
+ * @v wtf		Component name protocol
+ * @v language		Language to use
+ * @v driver_name	Driver name to fill in
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf,
+			     CHAR8 *language __unused, CHAR16 **driver_name ) {
+	struct efi_driver *efidrv =
+		container_of ( wtf, struct efi_driver, wtf );
+
+	*driver_name = efidrv->wname;
+	return 0;
+}
+
+/**
+ * Look up controller name
+ *
+ * @v wtf		Component name protocol
+ * @v device		Device
+ * @v child		Child device, or NULL
+ * @v language		Language to use
+ * @v driver_name	Device name to fill in
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+				 EFI_HANDLE device __unused,
+				 EFI_HANDLE child __unused,
+				 CHAR8 *language __unused,
+				 CHAR16 **controller_name __unused ) {
+
+	/* Just let EFI use the default Device Path Name */
+	return EFI_UNSUPPORTED;
+}
+
+/**
+ * Install EFI driver
+ *
+ * @v efidrv		EFI driver
+ * @ret efirc		EFI status code
+ */
+EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver;
+	EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf;
+	EFI_STATUS efirc;
+
+	/* Configure driver binding protocol */
+	driver->ImageHandle = efi_image_handle;
+
+	/* Configure component name protocol */
+	wtf->GetDriverName = efi_driver_get_driver_name;
+	wtf->GetControllerName = efi_driver_get_controller_name;
+	wtf->SupportedLanguages = "en";
+
+	/* Fill in driver name */
+	efi_snprintf ( efidrv->wname,
+		       ( sizeof ( efidrv->wname ) /
+			 sizeof ( efidrv->wname[0] ) ),
+		       PRODUCT_SHORT_NAME " - %s", efidrv->name );
+
+	/* Install driver */
+	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+			&driver->DriverBindingHandle,
+			&efi_driver_binding_protocol_guid, driver,
+			&efi_component_name2_protocol_guid, wtf,
+			NULL ) ) != 0 ) {
+		DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n",
+		       efidrv->name, efi_strerror ( efirc ) );
+		return efirc;
+	}
+
+	DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_init.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_init.c
new file mode 100644
index 0000000..6c7b495
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_init.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/LoadedImage.h>
+#include <ipxe/uuid.h>
+#include <ipxe/init.h>
+
+/** Image handle passed to entry point */
+EFI_HANDLE efi_image_handle;
+
+/** Loaded image protocol for this image */
+EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
+
+/** System table passed to entry point */
+EFI_SYSTEM_TABLE *efi_systab;
+
+/** EFI loaded image protocol GUID */
+static EFI_GUID efi_loaded_image_protocol_guid
+	= EFI_LOADED_IMAGE_PROTOCOL_GUID;
+
+/** Event used to signal shutdown */
+static EFI_EVENT efi_shutdown_event;
+
+/**
+ * Shut down in preparation for booting an OS.
+ *
+ * This hook gets called at ExitBootServices time in order to make
+ * sure that everything is properly shut down before the OS takes
+ * over.
+ */
+static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
+				       void *context __unused ) {
+	shutdown_boot();
+}
+
+/**
+ * Look up EFI configuration table
+ *
+ * @v guid		Configuration table GUID
+ * @ret table		Configuration table, or NULL
+ */
+static void * efi_find_table ( EFI_GUID *guid ) {
+	unsigned int i;
+
+	for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
+		if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid,
+			      guid, sizeof ( *guid ) ) == 0 )
+			return efi_systab->ConfigurationTable[i].VendorTable;
+	}
+
+	return NULL;
+}
+
+/**
+ * Initialise EFI environment
+ *
+ * @v image_handle	Image handle
+ * @v systab		System table
+ * @ret efirc		EFI return status code
+ */
+EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+		      EFI_SYSTEM_TABLE *systab ) {
+	EFI_BOOT_SERVICES *bs;
+	struct efi_protocol *prot;
+	struct efi_config_table *tab;
+	EFI_STATUS efirc;
+	void *loaded_image;
+
+	/* Store image handle and system table pointer for future use */
+	efi_image_handle = image_handle;
+	efi_systab = systab;
+
+	/* Sanity checks */
+	if ( ! systab )
+		return EFI_NOT_AVAILABLE_YET;
+	if ( ! systab->ConOut )
+		return EFI_NOT_AVAILABLE_YET;
+	if ( ! systab->BootServices ) {
+		DBGC ( systab, "EFI provided no BootServices entry point\n" );
+		return EFI_NOT_AVAILABLE_YET;
+	}
+	if ( ! systab->RuntimeServices ) {
+		DBGC ( systab, "EFI provided no RuntimeServices entry "
+		       "point\n" );
+		return EFI_NOT_AVAILABLE_YET;
+	}
+	DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
+
+	bs = systab->BootServices;
+	efirc = bs->OpenProtocol ( image_handle,
+				   &efi_loaded_image_protocol_guid,
+				   &loaded_image, image_handle, NULL,
+				   EFI_OPEN_PROTOCOL_GET_PROTOCOL );
+	if ( efirc ) {
+	   DBGC ( systab, "Could not get loaded image protocol" );
+	   return efirc;
+	}
+
+	efi_loaded_image = loaded_image;
+	DBG ( "Image base address = %p\n", efi_loaded_image->ImageBase );
+
+	/* Look up used protocols */
+	for_each_table_entry ( prot, EFI_PROTOCOLS ) {
+		if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL,
+						    prot->protocol ) ) == 0 ) {
+			DBGC ( systab, "EFI protocol %s is at %p\n",
+			       uuid_ntoa ( &prot->u.uuid ), *(prot->protocol));
+		} else {
+			DBGC ( systab, "EFI does not provide protocol %s\n",
+			       uuid_ntoa ( &prot->u.uuid ) );
+			/* All protocols are required */
+			return efirc;
+		}
+	}
+
+	/* Look up used configuration tables */
+	for_each_table_entry ( tab, EFI_CONFIG_TABLES ) {
+		if ( ( *(tab->table) = efi_find_table ( &tab->u.guid ) ) ) {
+			DBGC ( systab, "EFI configuration table %s is at %p\n",
+			       uuid_ntoa ( &tab->u.uuid ), *(tab->table) );
+		} else {
+			DBGC ( systab, "EFI does not provide configuration "
+			       "table %s\n", uuid_ntoa ( &tab->u.uuid ) );
+			if ( tab->required )
+				return EFI_NOT_AVAILABLE_YET;
+		}
+	}
+
+	/* EFI is perfectly capable of gracefully shutting down any
+	 * loaded devices if it decides to fall back to a legacy boot.
+	 * For no particularly comprehensible reason, it doesn't
+	 * bother doing so when ExitBootServices() is called.
+	 */
+	if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
+					 TPL_CALLBACK, efi_shutdown_hook,
+					 NULL, &efi_shutdown_event ) ) != 0 ) {
+		DBGC ( systab, "EFI could not create ExitBootServices event: "
+		       "%s\n", efi_strerror ( efirc ) );
+		return efirc;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_io.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_io.c
new file mode 100644
index 0000000..9a9aad3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_io.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <ipxe/io.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/CpuIo.h>
+#include <ipxe/efi/efi_io.h>
+
+/** @file
+ *
+ * iPXE I/O API for EFI
+ *
+ */
+
+/** CPU I/O protocol */
+static EFI_CPU_IO_PROTOCOL *cpu_io;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
+
+/** Maximum address that can be used for port I/O */
+#define MAX_PORT_ADDRESS 0xffff
+
+/**
+ * Determine whether or not address is a port I/O address
+ *
+ * @v io_addr		I/O address
+ * @v is_port		I/O address is a port I/O address
+ */
+#define IS_PORT_ADDRESS(io_addr) \
+	( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
+
+/**
+ * Determine EFI CPU I/O width code
+ *
+ * @v size		Size of value
+ * @ret width		EFI width code
+ *
+ * Someone at Intel clearly gets paid by the number of lines of code
+ * they write.  No-one should ever be able to make I/O this
+ * convoluted.  The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
+ * idiocy.
+ */
+static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
+	switch ( size ) {
+	case 1 :	return EfiCpuIoWidthFifoUint8;
+	case 2 :	return EfiCpuIoWidthFifoUint16;
+	case 4 :	return EfiCpuIoWidthFifoUint32;
+	case 8 :	return EfiCpuIoWidthFifoUint64;
+	default :
+		assert ( 0 );
+		/* I wonder what this will actually do... */
+		return EfiCpuIoWidthMaximum;
+	}
+}
+
+/**
+ * Read from device
+ *
+ * @v io_addr		I/O address
+ * @v size		Size of value
+ * @ret data		Value read
+ */
+unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
+	EFI_CPU_IO_PROTOCOL_IO_MEM read;
+	unsigned long long data = 0;
+	EFI_STATUS efirc;
+
+	read = ( IS_PORT_ADDRESS ( io_addr ) ?
+		 cpu_io->Io.Read : cpu_io->Mem.Read );
+
+	if ( ( efirc = read ( cpu_io, efi_width ( size ),
+			      ( intptr_t ) io_addr, 1,
+			      ( void * ) &data ) ) != 0 ) {
+		DBG ( "EFI I/O read at %p failed: %s\n",
+		      io_addr, efi_strerror ( efirc ) );
+		return -1ULL;
+	}
+
+	return data;
+}
+
+/**
+ * Write to device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ * @v size		Size of value
+ */
+void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+		   size_t size ) {
+	EFI_CPU_IO_PROTOCOL_IO_MEM write;
+	EFI_STATUS efirc;
+
+	write = ( IS_PORT_ADDRESS ( io_addr ) ?
+		  cpu_io->Io.Write : cpu_io->Mem.Write );
+
+	if ( ( efirc = write ( cpu_io, efi_width ( size ),
+			       ( intptr_t ) io_addr, 1,
+			       ( void * ) &data ) ) != 0 ) {
+		DBG ( "EFI I/O write at %p failed: %s\n",
+		      io_addr, efi_strerror ( efirc ) );
+	}
+}
+
+/**
+ * String read from device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v size		Size of values
+ * @v count		Number of values to read
+ */
+void efi_ioreads ( volatile void *io_addr, void *data,
+		   size_t size, unsigned int count ) {
+	EFI_CPU_IO_PROTOCOL_IO_MEM read;
+	EFI_STATUS efirc;
+
+	read = ( IS_PORT_ADDRESS ( io_addr ) ?
+		 cpu_io->Io.Read : cpu_io->Mem.Read );
+
+	if ( ( efirc = read ( cpu_io, efi_width ( size ),
+			      ( intptr_t ) io_addr, count,
+			      ( void * ) data ) ) != 0 ) {
+		DBG ( "EFI I/O string read at %p failed: %s\n",
+		      io_addr, efi_strerror ( efirc ) );
+	}
+}
+
+/**
+ * String write to device
+ *
+ * @v io_addr		I/O address
+ * @v data		Data buffer
+ * @v size		Size of values
+ * @v count		Number of values to write
+ */
+void efi_iowrites ( volatile void *io_addr, const void *data,
+		    size_t size, unsigned int count ) {
+	EFI_CPU_IO_PROTOCOL_IO_MEM write;
+	EFI_STATUS efirc;
+
+	write = ( IS_PORT_ADDRESS ( io_addr ) ?
+		 cpu_io->Io.Write : cpu_io->Mem.Write );
+
+	if ( ( efirc = write ( cpu_io, efi_width ( size ),
+			       ( intptr_t ) io_addr, count,
+			       ( void * ) data ) ) != 0 ) {
+		DBG ( "EFI I/O write at %p failed: %s\n",
+		      io_addr, efi_strerror ( efirc ) );
+	}
+}
+
+/**
+ * Wait for I/O-mapped operation to complete
+ *
+ */
+static void efi_iodelay ( void ) {
+	/* Write to non-existent port.  Probably x86-only. */
+	outb ( 0, 0x80 );
+}
+
+/**
+ * Get memory map
+ *
+ * Can't be done on EFI so return an empty map
+ *
+ * @v memmap		Memory map to fill in
+ */
+static void efi_get_memmap ( struct memory_map *memmap ) {
+	memmap->count = 0;
+}
+
+PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( efi, ioremap );
+PROVIDE_IOAPI_INLINE ( efi, iounmap );
+PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, readb );
+PROVIDE_IOAPI_INLINE ( efi, readw );
+PROVIDE_IOAPI_INLINE ( efi, readl );
+PROVIDE_IOAPI_INLINE ( efi, readq );
+PROVIDE_IOAPI_INLINE ( efi, writeb );
+PROVIDE_IOAPI_INLINE ( efi, writew );
+PROVIDE_IOAPI_INLINE ( efi, writel );
+PROVIDE_IOAPI_INLINE ( efi, writeq );
+PROVIDE_IOAPI_INLINE ( efi, inb );
+PROVIDE_IOAPI_INLINE ( efi, inw );
+PROVIDE_IOAPI_INLINE ( efi, inl );
+PROVIDE_IOAPI_INLINE ( efi, outb );
+PROVIDE_IOAPI_INLINE ( efi, outw );
+PROVIDE_IOAPI_INLINE ( efi, outl );
+PROVIDE_IOAPI_INLINE ( efi, insb );
+PROVIDE_IOAPI_INLINE ( efi, insw );
+PROVIDE_IOAPI_INLINE ( efi, insl );
+PROVIDE_IOAPI_INLINE ( efi, outsb );
+PROVIDE_IOAPI_INLINE ( efi, outsw );
+PROVIDE_IOAPI_INLINE ( efi, outsl );
+PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
+PROVIDE_IOAPI_INLINE ( efi, mb );
+PROVIDE_IOAPI ( efi, get_memmap, efi_get_memmap );
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_pci.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_pci.c
new file mode 100644
index 0000000..fa71e7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_pci.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/pci.h>
+#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_pci.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/Protocol/PciIo.h>
+#include <ipxe/efi/Protocol/PciRootBridgeIo.h>
+
+/** @file
+ *
+ * iPXE PCI I/O API for EFI
+ *
+ */
+
+/******************************************************************************
+ *
+ * iPXE PCI API
+ *
+ ******************************************************************************
+ */
+
+/** PCI root bridge I/O protocol */
+static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
+EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
+
+static unsigned long efipci_address ( struct pci_device *pci,
+				      unsigned long location ) {
+	return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ),
+				 PCI_SLOT ( pci->busdevfn ),
+				 PCI_FUNC ( pci->busdevfn ),
+				 EFIPCI_OFFSET ( location ) );
+}
+
+int efipci_read ( struct pci_device *pci, unsigned long location,
+		  void *value ) {
+	EFI_STATUS efirc;
+
+	if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
+					  efipci_address ( pci, location ), 1,
+					  value ) ) != 0 ) {
+		DBG ( "EFIPCI config read from " PCI_FMT " offset %02lx "
+		      "failed: %s\n", PCI_ARGS ( pci ),
+		      EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) );
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int efipci_write ( struct pci_device *pci, unsigned long location,
+		   unsigned long value ) {
+	EFI_STATUS efirc;
+
+	if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
+					   efipci_address ( pci, location ), 1,
+					   &value ) ) != 0 ) {
+		DBG ( "EFIPCI config write to " PCI_FMT " offset %02lx "
+		      "failed: %s\n", PCI_ARGS ( pci ),
+		      EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) );
+		return -EIO;
+	}
+
+	return 0;
+}
+
+PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
+
+/******************************************************************************
+ *
+ * EFI PCI device instantiation
+ *
+ ******************************************************************************
+ */
+
+/** EFI PCI I/O protocol GUID */
+static EFI_GUID efi_pci_io_protocol_guid
+	= EFI_PCI_IO_PROTOCOL_GUID;
+
+/** EFI device path protocol GUID */
+static EFI_GUID efi_device_path_protocol_guid
+	= EFI_DEVICE_PATH_PROTOCOL_GUID;
+
+/** EFI PCI devices */
+static LIST_HEAD ( efi_pci_devices );
+
+/**
+ * Create EFI PCI device
+ *
+ * @v efidrv		EFI driver
+ * @v device		EFI device
+ * @ret efipci		EFI PCI device, or NULL
+ */
+struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
+					EFI_HANDLE device ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_pci_device *efipci;
+	union {
+		EFI_PCI_IO_PROTOCOL *pci_io;
+		void *interface;
+	} pci_io;
+	union {
+		EFI_DEVICE_PATH_PROTOCOL *path;
+		void *interface;
+	} path;
+	UINTN pci_segment, pci_bus, pci_dev, pci_fn;
+	EFI_STATUS efirc;
+	int rc;
+
+	/* Allocate PCI device */
+	efipci = zalloc ( sizeof ( *efipci ) );
+	if ( ! efipci )
+		goto err_zalloc;
+	efipci->device = device;
+	efipci->efidrv = efidrv;
+
+	/* See if device is a PCI device */
+	if ( ( efirc = bs->OpenProtocol ( device,
+					  &efi_pci_io_protocol_guid,
+					  &pci_io.interface,
+					  efidrv->driver.DriverBindingHandle,
+					  device,
+					  EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+		DBGCP ( efipci, "EFIPCI device %p is not a PCI device\n",
+			device );
+		goto err_open_protocol;
+	}
+	efipci->pci_io = pci_io.pci_io;
+
+	/* Get PCI bus:dev.fn address */
+	if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io,
+						    &pci_segment,
+						    &pci_bus, &pci_dev,
+						    &pci_fn ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI device %p could not get PCI "
+		       "location: %s\n", device, efi_strerror ( efirc ) );
+		goto err_get_location;
+	}
+	DBGC2 ( efipci, "EFIPCI device %p is PCI %04lx:%02lx:%02lx.%lx\n",
+		device, ( ( unsigned long ) pci_segment ),
+		( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
+		( ( unsigned long ) pci_fn ) );
+
+	/* Populate PCI device */
+	pci_init ( &efipci->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
+	if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " cannot read PCI "
+		       "configuration: %s\n",
+		       PCI_ARGS ( &efipci->pci ), strerror ( rc ) );
+		goto err_pci_read_config;
+	}
+
+	/* Retrieve device path */
+	if ( ( efirc = bs->OpenProtocol ( device,
+					  &efi_device_path_protocol_guid,
+					  &path.interface,
+					  efidrv->driver.DriverBindingHandle,
+					  device,
+					  EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+		DBGC ( efipci, "EFIPCI " PCI_FMT " has no device path\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		goto err_no_device_path;
+	}
+	efipci->path = path.path;
+
+	/* Add to list of PCI devices */
+	list_add ( &efipci->list, &efi_pci_devices );
+
+	return efipci;
+
+	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
+			    efidrv->driver.DriverBindingHandle, device );
+ err_no_device_path:
+ err_pci_read_config:
+ err_get_location:
+	bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
+			    efidrv->driver.DriverBindingHandle, device );
+ err_open_protocol:
+	free ( efipci );
+ err_zalloc:
+	return NULL;
+}
+
+/**
+ * Enable EFI PCI device
+ *
+ * @v efipci		EFI PCI device
+ * @ret efirc		EFI status code
+ */
+EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ) {
+	EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io;
+	EFI_STATUS efirc;
+
+	/* Enable device */
+	if ( ( efirc = pci_io->Attributes ( pci_io,
+					    EfiPciIoAttributeOperationSet,
+					    EFI_PCI_DEVICE_ENABLE,
+					    NULL ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " could not be enabled: %s\n",
+		       PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) );
+		return efirc;
+	}
+
+	return 0;
+}
+
+/**
+ * Find EFI PCI device by EFI device
+ *
+ * @v device		EFI device
+ * @ret efipci		EFI PCI device, or NULL
+ */
+struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ) {
+	struct efi_pci_device *efipci;
+
+	list_for_each_entry ( efipci, &efi_pci_devices, list ) {
+		if ( efipci->device == device )
+			return efipci;
+	}
+	return NULL;
+}
+
+/**
+ * Find EFI PCI device by iPXE device
+ *
+ * @v dev		Device
+ * @ret efipci		EFI PCI device, or NULL
+ */
+struct efi_pci_device * efipci_find ( struct device *dev ) {
+	struct efi_pci_device *efipci;
+
+	list_for_each_entry ( efipci, &efi_pci_devices, list ) {
+		if ( &efipci->pci.dev == dev )
+			return efipci;
+	}
+	return NULL;
+}
+
+/**
+ * Add EFI device as child of EFI PCI device
+ *
+ * @v efipci		EFI PCI device
+ * @v device		EFI child device
+ * @ret efirc		EFI status code
+ */
+EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
+			      EFI_HANDLE device ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_driver *efidrv = efipci->efidrv;
+	union {
+		EFI_PCI_IO_PROTOCOL *pci_io;
+		void *interface;
+	} pci_io;
+	EFI_STATUS efirc;
+
+	/* Re-open the PCI_IO_PROTOCOL */
+	if ( ( efirc = bs->OpenProtocol ( efipci->device,
+					  &efi_pci_io_protocol_guid,
+					  &pci_io.interface,
+					  efidrv->driver.DriverBindingHandle,
+					  device,
+					  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+					  ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n",
+		       PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) );
+		return efirc;
+	}
+
+	return 0;
+}
+
+/**
+ * Remove EFI device as child of PCI device
+ *
+ * @v efipci		EFI PCI device
+ * @v device		EFI child device
+ * @ret efirc		EFI status code
+ */
+void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_driver *efidrv = efipci->efidrv;
+
+	bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
+			    efidrv->driver.DriverBindingHandle, device );
+}
+
+/**
+ * Destroy EFI PCI device
+ *
+ * @v efidrv		EFI driver
+ * @v efipci		EFI PCI device
+ */
+void efipci_destroy ( struct efi_driver *efidrv,
+		      struct efi_pci_device *efipci ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+	list_del ( &efipci->list );
+	bs->CloseProtocol ( efipci->device, &efi_device_path_protocol_guid,
+			    efidrv->driver.DriverBindingHandle,
+			    efipci->device );
+	bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
+			    efidrv->driver.DriverBindingHandle,
+			    efipci->device );
+	free ( efipci );
+}
+
+/******************************************************************************
+ *
+ * EFI PCI driver
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check to see if driver supports a device
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v child		Path to child device, if any
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
+		   EFI_DEVICE_PATH_PROTOCOL *child ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+	struct efi_pci_device *efipci;
+	EFI_STATUS efirc;
+	int rc;
+
+	DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child );
+
+	/* Create temporary corresponding PCI device, if any */
+	efipci = efipci_create ( efidrv, device );
+	if ( ! efipci ) {
+		/* Non-PCI devices are simply unsupported */
+		efirc = EFI_UNSUPPORTED;
+		goto err_not_pci;
+	}
+
+	/* Look for a driver */
+	if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
+		DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
+			PCI_ARGS ( &efipci->pci ) );
+		efirc = EFI_UNSUPPORTED;
+		goto err_no_driver;
+	}
+
+	DBGC ( efipci, "EFIPCI " PCI_FMT " is supported by driver \"%s\"\n",
+	       PCI_ARGS ( &efipci->pci ), efipci->pci.id->name );
+
+	/* Destroy temporary PCI device */
+	efipci_destroy ( efidrv, efipci );
+
+	return 0;
+
+ err_no_driver:
+	efipci_destroy ( efidrv, efipci );
+ err_not_pci:
+	return efirc;
+}
+
+/**
+ * Attach driver to device
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v child		Path to child device, if any
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
+	       EFI_DEVICE_PATH_PROTOCOL *child ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+	struct efi_pci_device *efipci;
+	EFI_STATUS efirc;
+	int rc;
+
+	DBGC ( efidrv, "EFIPCI DRIVER_START %p (%p)\n", device, child );
+
+	/* Create corresponding PCI device */
+	efipci = efipci_create ( efidrv, device );
+	if ( ! efipci ) {
+		efirc = EFI_OUT_OF_RESOURCES;
+		goto err_create;
+	}
+
+	/* Find driver */
+	if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
+		       PCI_ARGS ( &efipci->pci ) );
+		efirc = RC_TO_EFIRC ( rc );
+		goto err_find_driver;
+	}
+
+	/* Enable PCI device */
+	if ( ( efirc = efipci_enable ( efipci ) ) != 0 )
+		goto err_enable;
+
+	/* Probe driver */
+	if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " could not probe driver "
+		       "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ),
+		       efipci->pci.id->name, strerror ( rc ) );
+		efirc = RC_TO_EFIRC ( rc );
+		goto err_probe;
+	}
+
+	return 0;
+
+	pci_remove ( &efipci->pci );
+ err_probe:
+ err_enable:
+ err_find_driver:
+	efipci_destroy ( efidrv, efipci );
+ err_create:
+	return efirc;
+}
+
+/**
+ * Detach driver from device
+ *
+ * @v driver		EFI driver
+ * @v device		EFI device
+ * @v pci		PCI device
+ * @v num_children	Number of child devices
+ * @v children		List of child devices
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efipci_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
+	      UINTN num_children, EFI_HANDLE *children ) {
+	struct efi_driver *efidrv =
+		container_of ( driver, struct efi_driver, driver );
+	struct efi_pci_device *efipci;
+
+	DBGC ( efidrv, "EFIPCI DRIVER_STOP %p (%ld %p)\n",
+	       device, ( ( unsigned long ) num_children ), children );
+
+	/* Find PCI device */
+	efipci = efipci_find_efi ( device );
+	if ( ! efipci ) {
+		DBGC ( efidrv, "EFIPCI device %p not started!\n", device );
+		return EFI_INVALID_PARAMETER;
+	}
+
+	/* Remove device */
+	pci_remove ( &efipci->pci );
+
+	/* Delete EFI PCI device */
+	efipci_destroy ( efidrv, efipci );
+
+	return 0;
+}
+
+/** EFI PCI driver */
+static struct efi_driver efipci_driver =
+	EFI_DRIVER_INIT ( "PCI", efipci_supported, efipci_start, efipci_stop );
+
+/**
+ * Install EFI PCI driver
+ *
+ */
+static void efipci_driver_startup ( void ) {
+	struct efi_driver *efidrv = &efipci_driver;
+	EFI_STATUS efirc;
+
+	/* Install driver */
+	if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) {
+		DBGC ( efidrv, "EFIPCI could not install driver: %s\n",
+		       efi_strerror ( efirc ) );
+		return;
+	}
+
+	DBGC ( efidrv, "EFIPCI driver installed\n" );
+}
+
+/**
+ * Shut down EFI PCI driver
+ *
+ * @v booting		System is shutting down for OS boot
+ */
+static void efipci_driver_shutdown ( int booting __unused ) {
+	struct efi_driver *efidrv = &efipci_driver;
+	struct efi_pci_device *efipci;
+	struct efi_pci_device *tmp;
+
+	/* Shut down any remaining devices */
+	list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) {
+		DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; "
+		       "forcing close\n", PCI_ARGS ( &efipci->pci ) );
+		pci_remove ( &efipci->pci );
+		efipci_destroy ( efidrv, efipci );
+	}
+}
+
+/** EFI PCI startup function */
+struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = {
+	.startup = efipci_driver_startup,
+	.shutdown = efipci_driver_shutdown,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_smbios.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_smbios.c
new file mode 100644
index 0000000..4b58d84
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_smbios.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/smbios.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Guid/SmBios.h>
+
+/** @file
+ *
+ * iPXE SMBIOS API for EFI
+ *
+ */
+
+/** SMBIOS configuration table */
+static struct smbios_entry *smbios_entry;
+EFI_USE_TABLE ( SMBIOS_TABLE, &smbios_entry, 0 );
+
+/**
+ * Find SMBIOS
+ *
+ * @v smbios		SMBIOS entry point descriptor structure to fill in
+ * @ret rc		Return status code
+ */
+static int efi_find_smbios ( struct smbios *smbios ) {
+
+	if ( ! smbios_entry ) {
+		DBG ( "No SMBIOS table provided\n" );
+		return -ENODEV;
+	}
+
+	if ( smbios_entry->signature != SMBIOS_SIGNATURE ) {
+		DBG ( "Invalid SMBIOS signature\n" );
+		return -ENODEV;
+	}
+
+	smbios->address = phys_to_user ( smbios_entry->smbios_address );
+	smbios->len = smbios_entry->smbios_len;
+	smbios->count = smbios_entry->smbios_count;
+	DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n",
+	      smbios_entry->major, smbios_entry->minor, smbios_entry,
+	      smbios_entry->smbios_address, smbios->len );
+
+	return 0;
+}
+
+PROVIDE_SMBIOS ( efi, find_smbios, efi_find_smbios );
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_snp.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_snp.c
new file mode 100644
index 0000000..f40bfff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_snp.c
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/in.h>
+#include <ipxe/pci.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_pci.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_hii.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
+#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
+#include <ipxe/efi/Protocol/DevicePath.h>
+#include <ipxe/efi/Protocol/HiiConfigAccess.h>
+#include <ipxe/efi/Protocol/HiiDatabase.h>
+#include <config/general.h>
+
+/** @file
+ *
+ * iPXE EFI SNP interface
+ *
+ */
+
+/** An SNP device */
+struct efi_snp_device {
+	/** List of SNP devices */
+	struct list_head list;
+	/** The underlying iPXE network device */
+	struct net_device *netdev;
+	/** The underlying EFI PCI device */
+	struct efi_pci_device *efipci;
+	/** EFI device handle */
+	EFI_HANDLE handle;
+	/** The SNP structure itself */
+	EFI_SIMPLE_NETWORK_PROTOCOL snp;
+	/** The SNP "mode" (parameters) */
+	EFI_SIMPLE_NETWORK_MODE mode;
+	/** Outstanding TX packet count (via "interrupt status")
+	 *
+	 * Used in order to generate TX completions.
+	 */
+	unsigned int tx_count_interrupts;
+	/** Outstanding TX packet count (via "recycled tx buffers")
+	 *
+	 * Used in order to generate TX completions.
+	 */
+	unsigned int tx_count_txbufs;
+	/** Outstanding RX packet count (via "interrupt status") */
+	unsigned int rx_count_interrupts;
+	/** Outstanding RX packet count (via WaitForPacket event) */
+	unsigned int rx_count_events;
+	/** The network interface identifier */
+	EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
+	/** HII configuration access protocol */
+	EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
+	/** HII package list */
+	EFI_HII_PACKAGE_LIST_HEADER *package_list;
+	/** HII handle */
+	EFI_HII_HANDLE hii_handle;
+	/** Device name */
+	wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
+	/** The device path
+	 *
+	 * This field is variable in size and must appear at the end
+	 * of the structure.
+	 */
+	EFI_DEVICE_PATH_PROTOCOL path;
+};
+
+/** EFI simple network protocol GUID */
+static EFI_GUID efi_simple_network_protocol_guid
+	= EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
+
+/** EFI device path protocol GUID */
+static EFI_GUID efi_device_path_protocol_guid
+	= EFI_DEVICE_PATH_PROTOCOL_GUID;
+
+/** EFI network interface identifier GUID */
+static EFI_GUID efi_nii_protocol_guid
+	= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
+
+/** EFI network interface identifier GUID (extra special version) */
+static EFI_GUID efi_nii31_protocol_guid = {
+	/* At some point, it seems that someone decided to change the
+	 * GUID.  Current EFI builds ignore the older GUID, older EFI
+	 * builds ignore the newer GUID, so we have to expose both.
+	 */
+	0x1ACED566, 0x76ED, 0x4218,
+	{ 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
+};
+
+/** List of SNP devices */
+static LIST_HEAD ( efi_snp_devices );
+
+/**
+ * Set EFI SNP mode based on iPXE net device parameters
+ *
+ * @v snp		SNP interface
+ */
+static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
+	struct net_device *netdev = snpdev->netdev;
+	EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	unsigned int ll_addr_len = ll_protocol->ll_addr_len;
+
+	mode->HwAddressSize = ll_addr_len;
+	mode->MediaHeaderSize = ll_protocol->ll_header_len;
+	mode->MaxPacketSize = netdev->max_pkt_len;
+	mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+				    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+				    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
+	assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
+	memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
+	memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
+	ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
+	mode->IfType = ntohs ( ll_protocol->ll_proto );
+	mode->MacAddressChangeable = TRUE;
+	mode->MediaPresentSupported = TRUE;
+	mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
+}
+
+/**
+ * Poll net device and count received packets
+ *
+ * @v snpdev		SNP device
+ */
+static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
+	struct io_buffer *iobuf;
+	unsigned int before = 0;
+	unsigned int after = 0;
+	unsigned int arrived;
+
+	/* We have to report packet arrivals, and this is the easiest
+	 * way to fake it.
+	 */
+	list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+		before++;
+	netdev_poll ( snpdev->netdev );
+	list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+		after++;
+	arrived = ( after - before );
+
+	snpdev->rx_count_interrupts += arrived;
+	snpdev->rx_count_events += arrived;
+}
+
+/**
+ * Change SNP state from "stopped" to "started"
+ *
+ * @v snp		SNP interface
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+
+	DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
+
+	snpdev->mode.State = EfiSimpleNetworkStarted;
+	return 0;
+}
+
+/**
+ * Change SNP state from "started" to "stopped"
+ *
+ * @v snp		SNP interface
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+
+	DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
+
+	snpdev->mode.State = EfiSimpleNetworkStopped;
+	return 0;
+}
+
+/**
+ * Open the network device
+ *
+ * @v snp		SNP interface
+ * @v extra_rx_bufsize	Extra RX buffer size, in bytes
+ * @v extra_tx_bufsize	Extra TX buffer size, in bytes
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+		     UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	int rc;
+
+	DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
+		snpdev, ( ( unsigned long ) extra_rx_bufsize ),
+		( ( unsigned long ) extra_tx_bufsize ) );
+
+	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
+		       snpdev, snpdev->netdev->name, strerror ( rc ) );
+		return RC_TO_EFIRC ( rc );
+	}
+
+	snpdev->mode.State = EfiSimpleNetworkInitialized;
+	return 0;
+}
+
+/**
+ * Reset the network device
+ *
+ * @v snp		SNP interface
+ * @v ext_verify	Extended verification required
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	int rc;
+
+	DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
+		snpdev, ( ext_verify ? "with" : "without" ) );
+
+	netdev_close ( snpdev->netdev );
+	snpdev->mode.State = EfiSimpleNetworkStarted;
+
+	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
+		       snpdev, snpdev->netdev->name, strerror ( rc ) );
+		return RC_TO_EFIRC ( rc );
+	}
+
+	snpdev->mode.State = EfiSimpleNetworkInitialized;
+	return 0;
+}
+
+/**
+ * Shut down the network device
+ *
+ * @v snp		SNP interface
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+
+	DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
+
+	netdev_close ( snpdev->netdev );
+	snpdev->mode.State = EfiSimpleNetworkStarted;
+	return 0;
+}
+
+/**
+ * Manage receive filters
+ *
+ * @v snp		SNP interface
+ * @v enable		Receive filters to enable
+ * @v disable		Receive filters to disable
+ * @v mcast_reset	Reset multicast filters
+ * @v mcast_count	Number of multicast filters
+ * @v mcast		Multicast filters
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
+			  UINT32 disable, BOOLEAN mcast_reset,
+			  UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	unsigned int i;
+
+	DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
+		snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
+		( ( unsigned long ) mcast_count ) );
+	for ( i = 0 ; i < mcast_count ; i++ ) {
+		DBGC2_HDA ( snpdev, i, &mcast[i],
+			    snpdev->netdev->ll_protocol->ll_addr_len );
+	}
+
+	/* Lie through our teeth, otherwise MNP refuses to accept us */
+	return 0;
+}
+
+/**
+ * Set station address
+ *
+ * @v snp		SNP interface
+ * @v reset		Reset to permanent address
+ * @v new		New station address
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+			  EFI_MAC_ADDRESS *new ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+
+	DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
+		( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
+
+	/* Set the MAC address */
+	if ( reset )
+		new = &snpdev->mode.PermanentAddress;
+	memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
+
+	/* MAC address changes take effect only on netdev_open() */
+	if ( netdev_is_open ( snpdev->netdev ) ) {
+		DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
+		       "devive open\n", snpdev );
+	}
+
+	return 0;
+}
+
+/**
+ * Get (or reset) statistics
+ *
+ * @v snp		SNP interface
+ * @v reset		Reset statistics
+ * @v stats_len		Size of statistics table
+ * @v stats		Statistics table
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+		     UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	EFI_NETWORK_STATISTICS stats_buf;
+
+	DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
+		( reset ? " reset" : "" ) );
+
+	/* Gather statistics */
+	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
+	stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
+	stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
+	stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
+				    snpdev->netdev->tx_stats.bad );
+	stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
+	stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
+	stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
+				    snpdev->netdev->rx_stats.bad );
+	if ( *stats_len > sizeof ( stats_buf ) )
+		*stats_len = sizeof ( stats_buf );
+	if ( stats )
+		memcpy ( stats, &stats_buf, *stats_len );
+
+	/* Reset statistics if requested to do so */
+	if ( reset ) {
+		memset ( &snpdev->netdev->tx_stats, 0,
+			 sizeof ( snpdev->netdev->tx_stats ) );
+		memset ( &snpdev->netdev->rx_stats, 0,
+			 sizeof ( snpdev->netdev->rx_stats ) );
+	}
+
+	return 0;
+}
+
+/**
+ * Convert multicast IP address to MAC address
+ *
+ * @v snp		SNP interface
+ * @v ipv6		Address is IPv6
+ * @v ip		IP address
+ * @v mac		MAC address
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
+			  EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+	const char *ip_str;
+	int rc;
+
+	ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
+		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
+	DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
+
+	/* Try to hash the address */
+	if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
+					   ip, mac ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
+		       snpdev, ip_str, strerror ( rc ) );
+		return RC_TO_EFIRC ( rc );
+	}
+
+	return 0;
+}
+
+/**
+ * Read or write non-volatile storage
+ *
+ * @v snp		SNP interface
+ * @v read		Operation is a read
+ * @v offset		Starting offset within NVRAM
+ * @v len		Length of data buffer
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
+		 UINTN offset, UINTN len, VOID *data ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+
+	DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
+		( read ? "read" : "write" ), ( ( unsigned long ) offset ),
+		( ( unsigned long ) len ) );
+	if ( ! read )
+		DBGC2_HDA ( snpdev, offset, data, len );
+
+	return EFI_UNSUPPORTED;
+}
+
+/**
+ * Read interrupt status and TX recycled buffer status
+ *
+ * @v snp		SNP interface
+ * @v interrupts	Interrupt status, or NULL
+ * @v txbufs		Recycled transmit buffer address, or NULL
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+		     UINT32 *interrupts, VOID **txbufs ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+
+	DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
+
+	/* Poll the network device */
+	efi_snp_poll ( snpdev );
+
+	/* Interrupt status.  In practice, this seems to be used only
+	 * to detect TX completions.
+	 */
+	if ( interrupts ) {
+		*interrupts = 0;
+		/* Report TX completions once queue is empty; this
+		 * avoids having to add hooks in the net device layer.
+		 */
+		if ( snpdev->tx_count_interrupts &&
+		     list_empty ( &snpdev->netdev->tx_queue ) ) {
+			*interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+			snpdev->tx_count_interrupts--;
+		}
+		/* Report RX */
+		if ( snpdev->rx_count_interrupts ) {
+			*interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+			snpdev->rx_count_interrupts--;
+		}
+		DBGC2 ( snpdev, " INTS:%02x", *interrupts );
+	}
+
+	/* TX completions.  It would be possible to design a more
+	 * idiotic scheme for this, but it would be a challenge.
+	 * According to the UEFI header file, txbufs will be filled in
+	 * with a list of "recycled transmit buffers" (i.e. completed
+	 * TX buffers).  Observant readers may care to note that
+	 * *txbufs is a void pointer.  Precisely how a list of
+	 * completed transmit buffers is meant to be represented as an
+	 * array of voids is left as an exercise for the reader.
+	 *
+	 * The only users of this interface (MnpDxe/MnpIo.c and
+	 * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
+	 * seeing a non-NULL result return in txbufs.  This is valid
+	 * provided that they do not ever attempt to transmit more
+	 * than one packet concurrently (and that TX never times out).
+	 */
+	if ( txbufs ) {
+		if ( snpdev->tx_count_txbufs &&
+		     list_empty ( &snpdev->netdev->tx_queue ) ) {
+			*txbufs = "Which idiot designed this API?";
+			snpdev->tx_count_txbufs--;
+		} else {
+			*txbufs = NULL;
+		}
+		DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
+	}
+
+	DBGC2 ( snpdev, "\n" );
+	return 0;
+}
+
+/**
+ * Start packet transmission
+ *
+ * @v snp		SNP interface
+ * @v ll_header_len	Link-layer header length, if to be filled in
+ * @v len		Length of data buffer
+ * @v data		Data buffer
+ * @v ll_src		Link-layer source address, if specified
+ * @v ll_dest		Link-layer destination address, if specified
+ * @v net_proto		Network-layer protocol (in host order)
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+		   UINTN ll_header_len, UINTN len, VOID *data,
+		   EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+		   UINT16 *net_proto ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+	struct io_buffer *iobuf;
+	size_t ll_headroom;
+	int rc;
+	EFI_STATUS efirc;
+
+	DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
+		( ( unsigned long ) len ) );
+	if ( ll_header_len ) {
+		if ( ll_src ) {
+			DBGC2 ( snpdev, " src %s",
+				ll_protocol->ntoa ( ll_src ) );
+		}
+		if ( ll_dest ) {
+			DBGC2 ( snpdev, " dest %s",
+				ll_protocol->ntoa ( ll_dest ) );
+		}
+		if ( net_proto ) {
+			DBGC2 ( snpdev, " proto %04x", *net_proto );
+		}
+	}
+	DBGC2 ( snpdev, "\n" );
+
+	/* Sanity checks */
+	if ( ll_header_len ) {
+		if ( ll_header_len != ll_protocol->ll_header_len ) {
+			DBGC ( snpdev, "SNPDEV %p TX invalid header length "
+			       "%ld\n", snpdev,
+			       ( ( unsigned long ) ll_header_len ) );
+			efirc = EFI_INVALID_PARAMETER;
+			goto err_sanity;
+		}
+		if ( len < ll_header_len ) {
+			DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
+			       snpdev, ( ( unsigned long ) len ) );
+			efirc = EFI_BUFFER_TOO_SMALL;
+			goto err_sanity;
+		}
+		if ( ! ll_dest ) {
+			DBGC ( snpdev, "SNPDEV %p TX missing destination "
+			       "address\n", snpdev );
+			efirc = EFI_INVALID_PARAMETER;
+			goto err_sanity;
+		}
+		if ( ! net_proto ) {
+			DBGC ( snpdev, "SNPDEV %p TX missing network "
+			       "protocol\n", snpdev );
+			efirc = EFI_INVALID_PARAMETER;
+			goto err_sanity;
+		}
+		if ( ! ll_src )
+			ll_src = &snpdev->mode.CurrentAddress;
+	}
+
+	/* Allocate buffer */
+	ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len );
+	iobuf = alloc_iob ( ll_headroom + len );
+	if ( ! iobuf ) {
+		DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
+		       "buffer\n", snpdev, ( ( unsigned long ) len ) );
+		efirc = EFI_DEVICE_ERROR;
+		goto err_alloc_iob;
+	}
+	iob_reserve ( iobuf, ll_headroom );
+	memcpy ( iob_put ( iobuf, len ), data, len );
+
+	/* Create link-layer header, if specified */
+	if ( ll_header_len ) {
+		iob_pull ( iobuf, ll_header_len );
+		if ( ( rc = ll_protocol->push ( snpdev->netdev,
+						iobuf, ll_dest, ll_src,
+						htons ( *net_proto ) )) != 0 ){
+			DBGC ( snpdev, "SNPDEV %p TX could not construct "
+			       "header: %s\n", snpdev, strerror ( rc ) );
+			efirc = RC_TO_EFIRC ( rc );
+			goto err_ll_push;
+		}
+	}
+
+	/* Transmit packet */
+	if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
+		DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
+		       snpdev, strerror ( rc ) );
+		efirc = RC_TO_EFIRC ( rc );
+		goto err_tx;
+	}
+
+	/* Record transmission as outstanding */
+	snpdev->tx_count_interrupts++;
+	snpdev->tx_count_txbufs++;
+
+	return 0;
+
+ err_tx:
+ err_ll_push:
+	free_iob ( iobuf );
+ err_alloc_iob:
+ err_sanity:
+	return efirc;
+}
+
+/**
+ * Receive packet
+ *
+ * @v snp		SNP interface
+ * @v ll_header_len	Link-layer header length, if to be filled in
+ * @v len		Length of data buffer
+ * @v data		Data buffer
+ * @v ll_src		Link-layer source address, if specified
+ * @v ll_dest		Link-layer destination address, if specified
+ * @v net_proto		Network-layer protocol (in host order)
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+		  UINTN *ll_header_len, UINTN *len, VOID *data,
+		  EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+		  UINT16 *net_proto ) {
+	struct efi_snp_device *snpdev =
+		container_of ( snp, struct efi_snp_device, snp );
+	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+	struct io_buffer *iobuf;
+	const void *iob_ll_dest;
+	const void *iob_ll_src;
+	uint16_t iob_net_proto;
+	int rc;
+	EFI_STATUS efirc;
+
+	DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
+		( ( unsigned long ) *len ) );
+
+	/* Poll the network device */
+	efi_snp_poll ( snpdev );
+
+	/* Dequeue a packet, if one is available */
+	iobuf = netdev_rx_dequeue ( snpdev->netdev );
+	if ( ! iobuf ) {
+		DBGC2 ( snpdev, "\n" );
+		efirc = EFI_NOT_READY;
+		goto out_no_packet;
+	}
+	DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
+
+	/* Return packet to caller */
+	memcpy ( data, iobuf->data, iob_len ( iobuf ) );
+	*len = iob_len ( iobuf );
+
+	/* Attempt to decode link-layer header */
+	if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
+					&iob_ll_src, &iob_net_proto ) ) != 0 ){
+		DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
+		       snpdev, strerror ( rc ) );
+		efirc = RC_TO_EFIRC ( rc );
+		goto out_bad_ll_header;
+	}
+
+	/* Return link-layer header parameters to caller, if required */
+	if ( ll_header_len )
+		*ll_header_len = ll_protocol->ll_header_len;
+	if ( ll_src )
+		memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
+	if ( ll_dest )
+		memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
+	if ( net_proto )
+		*net_proto = ntohs ( iob_net_proto );
+
+	efirc = 0;
+
+ out_bad_ll_header:
+	free_iob ( iobuf );
+out_no_packet:
+	return efirc;
+}
+
+/**
+ * Poll event
+ *
+ * @v event		Event
+ * @v context		Event context
+ */
+static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
+					     VOID *context ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_snp_device *snpdev = context;
+
+	DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
+
+	/* Do nothing unless the net device is open */
+	if ( ! netdev_is_open ( snpdev->netdev ) )
+		return;
+
+	/* Poll the network device */
+	efi_snp_poll ( snpdev );
+
+	/* Fire event if packets have been received */
+	if ( snpdev->rx_count_events != 0 ) {
+		DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
+			snpdev );
+		bs->SignalEvent ( event );
+		snpdev->rx_count_events--;
+	}
+}
+
+/** SNP interface */
+static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
+	.Revision	= EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
+	.Start		= efi_snp_start,
+	.Stop		= efi_snp_stop,
+	.Initialize	= efi_snp_initialize,
+	.Reset		= efi_snp_reset,
+	.Shutdown	= efi_snp_shutdown,
+	.ReceiveFilters	= efi_snp_receive_filters,
+	.StationAddress	= efi_snp_station_address,
+	.Statistics	= efi_snp_statistics,
+	.MCastIpToMac	= efi_snp_mcast_ip_to_mac,
+	.NvData		= efi_snp_nvdata,
+	.GetStatus	= efi_snp_get_status,
+	.Transmit	= efi_snp_transmit,
+	.Receive	= efi_snp_receive,
+};
+
+/******************************************************************************
+ *
+ * Human Interface Infrastructure
+ *
+ ******************************************************************************
+ */
+
+/** EFI configuration access protocol GUID */
+static EFI_GUID efi_hii_config_access_protocol_guid
+	= EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
+
+/** EFI HII database protocol */
+static EFI_HII_DATABASE_PROTOCOL *efihii;
+EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
+
+/** Local GUID used for our EFI SNP formset */
+#define EFI_SNP_FORMSET_GUID						\
+	{ 0xc4f84019, 0x6dfd, 0x4a27,					\
+	  { 0x9b, 0x94, 0xb7, 0x2e, 0x1f, 0xbc, 0xad, 0xca } }
+
+/** Form identifiers used for our EFI SNP HII */
+enum efi_snp_hii_form_id {
+	EFI_SNP_FORM = 0x0001,		/**< The only form */
+};
+
+/** String identifiers used for our EFI SNP HII */
+enum efi_snp_hii_string_id {
+	/* Language name */
+	EFI_SNP_LANGUAGE_NAME = 0x0001,
+	/* Formset */
+	EFI_SNP_FORMSET_TITLE, EFI_SNP_FORMSET_HELP,
+	/* Product name */
+	EFI_SNP_PRODUCT_PROMPT, EFI_SNP_PRODUCT_HELP, EFI_SNP_PRODUCT_TEXT,
+	/* Version */
+	EFI_SNP_VERSION_PROMPT, EFI_SNP_VERSION_HELP, EFI_SNP_VERSION_TEXT,
+	/* Driver */
+	EFI_SNP_DRIVER_PROMPT, EFI_SNP_DRIVER_HELP, EFI_SNP_DRIVER_TEXT,
+	/* Device */
+	EFI_SNP_DEVICE_PROMPT, EFI_SNP_DEVICE_HELP, EFI_SNP_DEVICE_TEXT,
+	/* End of list */
+	EFI_SNP_MAX_STRING_ID
+};
+
+/** EFI SNP formset */
+struct efi_snp_formset {
+	EFI_HII_PACKAGE_HEADER Header;
+	EFI_IFR_FORM_SET_TYPE(1) FormSet;
+	EFI_IFR_GUID_CLASS Class;
+	EFI_IFR_GUID_SUBCLASS SubClass;
+	EFI_IFR_FORM Form;
+	EFI_IFR_TEXT ProductText;
+	EFI_IFR_TEXT VersionText;
+	EFI_IFR_TEXT DriverText;
+	EFI_IFR_TEXT DeviceText;
+	EFI_IFR_END EndForm;
+	EFI_IFR_END EndFormSet;
+} __attribute__ (( packed )) efi_snp_formset = {
+	.Header = {
+		.Length = sizeof ( efi_snp_formset ),
+		.Type = EFI_HII_PACKAGE_FORMS,
+	},
+	.FormSet = EFI_IFR_FORM_SET ( EFI_SNP_FORMSET_GUID,
+				      EFI_SNP_FORMSET_TITLE,
+				      EFI_SNP_FORMSET_HELP,
+				      typeof ( efi_snp_formset.FormSet ),
+				      EFI_HII_PLATFORM_SETUP_FORMSET_GUID ),
+	.Class = EFI_IFR_GUID_CLASS ( EFI_NETWORK_DEVICE_CLASS ),
+	.SubClass = EFI_IFR_GUID_SUBCLASS ( 0x03 ),
+	.Form = EFI_IFR_FORM ( EFI_SNP_FORM, EFI_SNP_FORMSET_TITLE ),
+	.ProductText = EFI_IFR_TEXT ( EFI_SNP_PRODUCT_PROMPT,
+				      EFI_SNP_PRODUCT_HELP,
+				      EFI_SNP_PRODUCT_TEXT ),
+	.VersionText = EFI_IFR_TEXT ( EFI_SNP_VERSION_PROMPT,
+				      EFI_SNP_VERSION_HELP,
+				      EFI_SNP_VERSION_TEXT ),
+	.DriverText = EFI_IFR_TEXT ( EFI_SNP_DRIVER_PROMPT,
+				     EFI_SNP_DRIVER_HELP,
+				     EFI_SNP_DRIVER_TEXT ),
+	.DeviceText = EFI_IFR_TEXT ( EFI_SNP_DEVICE_PROMPT,
+				     EFI_SNP_DEVICE_HELP,
+				     EFI_SNP_DEVICE_TEXT ),
+	.EndForm = EFI_IFR_END(),
+	.EndFormSet = EFI_IFR_END(),
+};
+
+/**
+ * Generate EFI SNP string
+ *
+ * @v wbuf		Buffer
+ * @v swlen		Size of buffer (in wide characters)
+ * @v snpdev		SNP device
+ * @ret wlen		Length of string (in wide characters)
+ */
+static int efi_snp_string ( wchar_t *wbuf, ssize_t swlen,
+			    enum efi_snp_hii_string_id id,
+			    struct efi_snp_device *snpdev ) {
+	struct net_device *netdev = snpdev->netdev;
+	struct device *dev = netdev->dev;
+
+	switch ( id ) {
+	case EFI_SNP_LANGUAGE_NAME:
+		return efi_ssnprintf ( wbuf, swlen, "English" );
+	case EFI_SNP_FORMSET_TITLE:
+		return efi_ssnprintf ( wbuf, swlen, "%s (%s)",
+				       ( PRODUCT_NAME[0] ?
+					 PRODUCT_NAME : PRODUCT_SHORT_NAME ),
+				       netdev_addr ( netdev ) );
+	case EFI_SNP_FORMSET_HELP:
+		return efi_ssnprintf ( wbuf, swlen,
+				       "Configure " PRODUCT_SHORT_NAME );
+	case EFI_SNP_PRODUCT_PROMPT:
+		return efi_ssnprintf ( wbuf, swlen, "Name" );
+	case EFI_SNP_PRODUCT_HELP:
+		return efi_ssnprintf ( wbuf, swlen, "Firmware product name" );
+	case EFI_SNP_PRODUCT_TEXT:
+		return efi_ssnprintf ( wbuf, swlen, "%s",
+				       ( PRODUCT_NAME[0] ?
+					 PRODUCT_NAME : PRODUCT_SHORT_NAME ) );
+	case EFI_SNP_VERSION_PROMPT:
+		return efi_ssnprintf ( wbuf, swlen, "Version" );
+	case EFI_SNP_VERSION_HELP:
+		return efi_ssnprintf ( wbuf, swlen, "Firmware version" );
+	case EFI_SNP_VERSION_TEXT:
+		return efi_ssnprintf ( wbuf, swlen, VERSION );
+	case EFI_SNP_DRIVER_PROMPT:
+		return efi_ssnprintf ( wbuf, swlen, "Driver" );
+	case EFI_SNP_DRIVER_HELP:
+		return efi_ssnprintf ( wbuf, swlen, "Firmware driver" );
+	case EFI_SNP_DRIVER_TEXT:
+		return efi_ssnprintf ( wbuf, swlen, "%s", dev->driver_name );
+	case EFI_SNP_DEVICE_PROMPT:
+		return efi_ssnprintf ( wbuf, swlen, "Device" );
+	case EFI_SNP_DEVICE_HELP:
+		return efi_ssnprintf ( wbuf, swlen, "Hardware device" );
+	case EFI_SNP_DEVICE_TEXT:
+		return efi_ssnprintf ( wbuf, swlen, "%s", dev->name );
+	default:
+		assert ( 0 );
+		return 0;
+	}
+}
+
+/**
+ * Generate EFI SNP string package
+ *
+ * @v strings		String package header buffer
+ * @v max_len		Buffer length
+ * @v snpdev		SNP device
+ * @ret len		Length of string package
+ */
+static int efi_snp_strings ( EFI_HII_STRING_PACKAGE_HDR *strings,
+			     size_t max_len, struct efi_snp_device *snpdev ) {
+	static const char language[] = "en-us";
+	void *buf = strings;
+	ssize_t remaining = max_len;
+	size_t hdrsize;
+	EFI_HII_SIBT_STRING_UCS2_BLOCK *string;
+	ssize_t wremaining;
+	size_t string_wlen;
+	unsigned int id;
+	EFI_HII_STRING_BLOCK *end;
+	size_t len;
+
+	/* Calculate header size */
+	hdrsize = ( offsetof ( typeof ( *strings ), Language ) +
+		    sizeof ( language ) );
+	buf += hdrsize;
+	remaining -= hdrsize;
+
+	/* Fill in strings */
+	for ( id = 1 ; id < EFI_SNP_MAX_STRING_ID ; id++ ) {
+		string = buf;
+		if ( remaining >= ( ( ssize_t ) sizeof ( string->Header ) ) )
+			string->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
+		buf += offsetof ( typeof ( *string ), StringText );
+		remaining -= offsetof ( typeof ( *string ), StringText );
+		wremaining = ( remaining /
+			       ( ( ssize_t ) sizeof ( string->StringText[0] )));
+		assert ( ! ( ( remaining <= 0 ) && ( wremaining > 0 ) ) );
+		string_wlen = efi_snp_string ( string->StringText, wremaining,
+					       id, snpdev );
+		buf += ( ( string_wlen + 1 /* wNUL */ ) *
+			 sizeof ( string->StringText[0] ) );
+		remaining -= ( ( string_wlen + 1 /* wNUL */ ) *
+			       sizeof ( string->StringText[0] ) );
+	}
+
+	/* Fill in end marker */
+	end = buf;
+	if ( remaining >= ( ( ssize_t ) sizeof ( *end ) ) )
+		end->BlockType = EFI_HII_SIBT_END;
+	buf += sizeof ( *end );
+	remaining -= sizeof ( *end );
+
+	/* Calculate overall length */
+	len = ( max_len - remaining );
+
+	/* Fill in string package header */
+	if ( strings ) {
+		memset ( strings, 0, sizeof ( *strings ) );
+		strings->Header.Length = len;
+		strings->Header.Type = EFI_HII_PACKAGE_STRINGS;
+		strings->HdrSize = hdrsize;
+		strings->StringInfoOffset = hdrsize;
+		strings->LanguageName = EFI_SNP_LANGUAGE_NAME;
+		memcpy ( strings->Language, language, sizeof ( language ) );
+	}
+
+	return len;
+}
+
+/**
+ * Generate EFI SNP package list
+ *
+ * @v snpdev		SNP device
+ * @ret package_list	Package list, or NULL on error
+ *
+ * The package list is allocated using malloc(), and must eventually
+ * be freed by the caller.
+ */
+static EFI_HII_PACKAGE_LIST_HEADER *
+efi_snp_package_list ( struct efi_snp_device *snpdev ) {
+	size_t strings_len = efi_snp_strings ( NULL, 0, snpdev );
+	struct {
+		EFI_HII_PACKAGE_LIST_HEADER header;
+		struct efi_snp_formset formset;
+		union {
+			EFI_HII_STRING_PACKAGE_HDR strings;
+			uint8_t pad[strings_len];
+		} __attribute__ (( packed )) strings;
+		EFI_HII_PACKAGE_HEADER end;
+	} __attribute__ (( packed )) *package_list;
+
+	/* Allocate package list */
+	package_list = zalloc ( sizeof ( *package_list ) );
+	if ( ! package_list )
+		return NULL;
+
+	/* Populate package list */
+	memcpy ( &package_list->header.PackageListGuid,
+		 &efi_snp_formset.FormSet.FormSet.Guid,
+		 sizeof ( package_list->header.PackageListGuid ) );
+	package_list->header.PackageLength = sizeof ( *package_list );
+	memcpy ( &package_list->formset, &efi_snp_formset,
+		 sizeof ( package_list->formset ) );
+	efi_snp_strings ( &package_list->strings.strings,
+			  sizeof ( package_list->strings ), snpdev );
+	package_list->end.Length = sizeof ( package_list->end );
+	package_list->end.Type = EFI_HII_PACKAGE_END;
+
+	return &package_list->header;
+}
+
+/**
+ * Fetch configuration
+ *
+ * @v hii		HII configuration access protocol
+ * @v request		Configuration to fetch
+ * @ret progress	Progress made through configuration to fetch
+ * @ret results		Query results
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+			     EFI_STRING request, EFI_STRING *progress,
+			     EFI_STRING *results __unused ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+
+	DBGC ( snpdev, "SNPDEV %p ExtractConfig\n", snpdev );
+
+	*progress = request;
+	return EFI_INVALID_PARAMETER;
+}
+
+/**
+ * Store configuration
+ *
+ * @v hii		HII configuration access protocol
+ * @v config		Configuration to store
+ * @ret progress	Progress made through configuration to store
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+			   EFI_STRING config, EFI_STRING *progress ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+
+	DBGC ( snpdev, "SNPDEV %p RouteConfig\n", snpdev );
+
+	*progress = config;
+	return EFI_INVALID_PARAMETER;
+}
+
+/**
+ * Handle form actions
+ *
+ * @v hii		HII configuration access protocol
+ * @v action		Form browser action
+ * @v question_id	Question ID
+ * @v type		Type of value
+ * @v value		Value
+ * @ret action_request	Action requested by driver
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+		       EFI_BROWSER_ACTION action __unused,
+		       EFI_QUESTION_ID question_id __unused,
+		       UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
+		       EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+
+	DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
+	return EFI_UNSUPPORTED;
+}
+
+/** HII configuration access protocol */
+static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
+	.ExtractConfig	= efi_snp_hii_extract_config,
+	.RouteConfig	= efi_snp_hii_route_config,
+	.Callback	= efi_snp_hii_callback,
+};
+
+/******************************************************************************
+ *
+ * iPXE network driver
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Locate SNP device corresponding to network device
+ *
+ * @v netdev		Network device
+ * @ret snp		SNP device, or NULL if not found
+ */
+static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
+	struct efi_snp_device *snpdev;
+
+	list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
+		if ( snpdev->netdev == netdev )
+			return snpdev;
+	}
+	return NULL;
+}
+
+/**
+ * Create SNP device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int efi_snp_probe ( struct net_device *netdev ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_pci_device *efipci;
+	struct efi_snp_device *snpdev;
+	EFI_DEVICE_PATH_PROTOCOL *path_end;
+	MAC_ADDR_DEVICE_PATH *macpath;
+	size_t path_prefix_len = 0;
+	EFI_STATUS efirc;
+	int rc;
+
+	/* Find EFI PCI device */
+	efipci = efipci_find ( netdev->dev );
+	if ( ! efipci ) {
+		DBG ( "SNP skipping non-PCI device %s\n", netdev->name );
+		rc = 0;
+		goto err_no_pci;
+	}
+
+	/* Calculate device path prefix length */
+	path_end = efi_devpath_end ( efipci->path );
+	path_prefix_len = ( ( ( void * ) path_end ) -
+			    ( ( void * ) efipci->path ) );
+
+	/* Allocate the SNP device */
+	snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
+			  sizeof ( *macpath ) );
+	if ( ! snpdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_snp;
+	}
+	snpdev->netdev = netdev_get ( netdev );
+	snpdev->efipci = efipci;
+
+	/* Sanity check */
+	if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
+		DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
+		       "length %d for %s\n", snpdev,
+		       netdev->ll_protocol->ll_addr_len, netdev->name );
+		rc = -ENOTSUP;
+		goto err_ll_addr_len;
+	}
+
+	/* Populate the SNP structure */
+	memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
+	snpdev->snp.Mode = &snpdev->mode;
+	if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
+					 efi_snp_wait_for_packet, snpdev,
+					 &snpdev->snp.WaitForPacket ) ) != 0 ){
+		DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
+		       snpdev, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_create_event;
+	}
+
+	/* Populate the SNP mode structure */
+	snpdev->mode.State = EfiSimpleNetworkStopped;
+	efi_snp_set_mode ( snpdev );
+
+	/* Populate the NII structure */
+	snpdev->nii.Revision =
+		EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+	strncpy ( snpdev->nii.StringId, "iPXE",
+		  sizeof ( snpdev->nii.StringId ) );
+
+	/* Populate the HII configuration access structure */
+	memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
+
+	/* Populate the device name */
+	efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
+				       sizeof ( snpdev->name[0] ) ),
+		       "%s", netdev->name );
+
+	/* Populate the device path */
+	memcpy ( &snpdev->path, efipci->path, path_prefix_len );
+	macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
+	path_end = ( ( void * ) ( macpath + 1 ) );
+	memset ( macpath, 0, sizeof ( *macpath ) );
+	macpath->Header.Type = MESSAGING_DEVICE_PATH;
+	macpath->Header.SubType = MSG_MAC_ADDR_DP;
+	macpath->Header.Length[0] = sizeof ( *macpath );
+	memcpy ( &macpath->MacAddress, netdev->ll_addr,
+		 sizeof ( macpath->MacAddress ) );
+	macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+	memset ( path_end, 0, sizeof ( *path_end ) );
+	path_end->Type = END_DEVICE_PATH_TYPE;
+	path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	path_end->Length[0] = sizeof ( *path_end );
+
+	/* Install the SNP */
+	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+			&snpdev->handle,
+			&efi_simple_network_protocol_guid, &snpdev->snp,
+			&efi_device_path_protocol_guid, &snpdev->path,
+			&efi_nii_protocol_guid, &snpdev->nii,
+			&efi_nii31_protocol_guid, &snpdev->nii,
+			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			NULL ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not install protocols: "
+		       "%s\n", snpdev, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_install_protocol_interface;
+	}
+
+	/* Add as child of PCI device */
+	if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT
+		       ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ),
+		       efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_efipci_child_add;
+	}
+
+	/* Create HII package list */
+	snpdev->package_list = efi_snp_package_list ( snpdev );
+	if ( ! snpdev->package_list ) {
+		DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
+		       snpdev );
+		rc = -ENOMEM;
+		goto err_create_hii;
+	}
+
+	/* Add HII packages */
+	if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
+						snpdev->handle,
+						&snpdev->hii_handle ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
+		       snpdev, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_register_hii;
+	}
+
+	/* Add to list of SNP devices */
+	list_add ( &snpdev->list, &efi_snp_devices );
+
+	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
+	       snpdev, netdev->name, snpdev->handle );
+	return 0;
+
+	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+ err_register_hii:
+	free ( snpdev->package_list );
+ err_create_hii:
+	efipci_child_del ( efipci, snpdev->handle );
+ err_efipci_child_add:
+	bs->UninstallMultipleProtocolInterfaces (
+			snpdev->handle,
+			&efi_simple_network_protocol_guid, &snpdev->snp,
+			&efi_device_path_protocol_guid, &snpdev->path,
+			&efi_nii_protocol_guid, &snpdev->nii,
+			&efi_nii31_protocol_guid, &snpdev->nii,
+			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			NULL );
+ err_install_protocol_interface:
+	bs->CloseEvent ( snpdev->snp.WaitForPacket );
+ err_create_event:
+ err_ll_addr_len:
+	netdev_put ( netdev );
+	free ( snpdev );
+ err_alloc_snp:
+ err_no_pci:
+	return rc;
+}
+
+/**
+ * Handle SNP device or link state change
+ *
+ * @v netdev		Network device
+ */
+static void efi_snp_notify ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+}
+
+/**
+ * Destroy SNP device
+ *
+ * @v netdev		Network device
+ */
+static void efi_snp_remove ( struct net_device *netdev ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_snp_device *snpdev;
+
+	/* Locate SNP device */
+	snpdev = efi_snp_demux ( netdev );
+	if ( ! snpdev ) {
+		DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
+		return;
+	}
+
+	/* Uninstall the SNP */
+	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+	free ( snpdev->package_list );
+	efipci_child_del ( snpdev->efipci, snpdev->handle );
+	list_del ( &snpdev->list );
+	bs->UninstallMultipleProtocolInterfaces (
+			snpdev->handle,
+			&efi_simple_network_protocol_guid, &snpdev->snp,
+			&efi_device_path_protocol_guid, &snpdev->path,
+			&efi_nii_protocol_guid, &snpdev->nii,
+			&efi_nii31_protocol_guid, &snpdev->nii,
+			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			NULL );
+	bs->CloseEvent ( snpdev->snp.WaitForPacket );
+	netdev_put ( snpdev->netdev );
+	free ( snpdev );
+}
+
+/** SNP driver */
+struct net_driver efi_snp_driver __net_driver = {
+	.name = "SNP",
+	.probe = efi_snp_probe,
+	.notify = efi_snp_notify,
+	.remove = efi_snp_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strerror.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strerror.c
new file mode 100644
index 0000000..430758f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strerror.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <ipxe/efi/efi.h>
+
+/** @file
+ *
+ * iPXE error message formatting for EFI
+ *
+ */
+
+/**
+ * Format EFI status code
+ *
+ * @v efirc		EFI status code
+ * @v efi_strerror	EFI status code string
+ */
+const char * efi_strerror ( EFI_STATUS efirc ) {
+	static char errbuf[32];
+
+	if ( ! efirc )
+		return "No error";
+
+	snprintf ( errbuf, sizeof ( errbuf ), "Error %lld",
+		   ( unsigned long long ) ( efirc ^ MAX_BIT ) );
+	return errbuf;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strings.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strings.c
new file mode 100644
index 0000000..0fbc453
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_strings.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <ipxe/vsprintf.h>
+#include <ipxe/efi/efi_strings.h>
+
+/** Context used by efi_vsnprintf() and friends */
+struct efi_sputc_context {
+	/** printf context */
+	struct printf_context ctx;
+	/** Buffer for formatted string (used by efi_printf_sputc()) */
+	wchar_t *buf;
+	/** Buffer length (used by efi_printf_sputc())
+	 *
+	 * Note that this is a number of wide characters, not a number
+	 * of bytes.
+	 */
+	size_t max_wlen;
+};
+
+/**
+ * Write wide character to buffer
+ *
+ * @v ctx		Context
+ * @v c			Character
+ */
+static void efi_printf_sputc ( struct printf_context *ctx, unsigned int c ) {
+	struct efi_sputc_context * sctx =
+		container_of ( ctx, struct efi_sputc_context, ctx );
+
+	if ( ctx->len < sctx->max_wlen )
+		sctx->buf[ctx->len] = c;
+}
+
+/**
+ * Write a formatted string to a wide-character buffer
+ *
+ * @v wbuf		Buffer into which to write the string
+ * @v wsize		Size of buffer (in wide characters)
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret wlen		Length of formatted string (in wide characters)
+ *
+ * If the buffer is too small to contain the string, the returned
+ * length is the length that would have been written had enough space
+ * been available.
+ */
+int efi_vsnprintf ( wchar_t *wbuf, size_t wsize, const char *fmt,
+		    va_list args ) {
+	struct efi_sputc_context sctx;
+	size_t wlen;
+	size_t wend;
+
+	/* Hand off to vcprintf */
+	sctx.ctx.handler = efi_printf_sputc;
+	sctx.buf = wbuf;
+	sctx.max_wlen = wsize;
+	wlen = vcprintf ( &sctx.ctx, fmt, args );
+
+	/* Add trailing NUL */
+	if ( wsize ) {
+		wend = wsize - 1;
+		if ( wlen < wend )
+			wend = wlen;
+		wbuf[wend] = '\0';
+	}
+
+	return wlen;
+}
+
+/**
+ * Write a formatted string to a buffer
+ *
+ * @v wbuf		Buffer into which to write the string
+ * @v wsize		Size of buffer (in wide characters)
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret wlen		Length of formatted string (in wide characters)
+ */
+int efi_snprintf ( wchar_t *wbuf, size_t wsize, const char *fmt, ... ) {
+	va_list args;
+	int i;
+
+	va_start ( args, fmt );
+	i = efi_vsnprintf ( wbuf, wsize, fmt, args );
+	va_end ( args );
+	return i;
+}
+
+/**
+ * Version of efi_vsnprintf() that accepts a signed buffer size
+ *
+ * @v wbuf		Buffer into which to write the string
+ * @v swsize		Size of buffer (in wide characters)
+ * @v fmt		Format string
+ * @v args		Arguments corresponding to the format string
+ * @ret wlen		Length of formatted string (in wide characters)
+ */
+int efi_vssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt,
+		     va_list args ) {
+
+	/* Treat negative buffer size as zero buffer size */
+	if ( swsize < 0 )
+		swsize = 0;
+
+	/* Hand off to vsnprintf */
+	return efi_vsnprintf ( wbuf, swsize, fmt, args );
+}
+
+/**
+ * Version of efi_vsnprintf() that accepts a signed buffer size
+ *
+ * @v wbuf		Buffer into which to write the string
+ * @v swsize		Size of buffer (in wide characters)
+ * @v fmt		Format string
+ * @v ...		Arguments corresponding to the format string
+ * @ret wlen		Length of formatted string (in wide characters)
+ */
+int efi_ssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt, ... ) {
+	va_list args;
+	int len;
+
+	/* Hand off to vssnprintf */
+	va_start ( args, fmt );
+	len = efi_vssnprintf ( wbuf, swsize, fmt, args );
+	va_end ( args );
+	return len;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_timer.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_timer.c
new file mode 100644
index 0000000..1f8ad15
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_timer.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ipxe/timer.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/Cpu.h>
+
+/** @file
+ *
+ * iPXE timer API for EFI
+ *
+ */
+
+/** Scale factor to apply to CPU timer 0
+ *
+ * The timer is scaled down in order to ensure that reasonable values
+ * for "number of ticks" don't exceed the size of an unsigned long.
+ */
+#define EFI_TIMER0_SHIFT 12
+
+/** Calibration time */
+#define EFI_CALIBRATE_DELAY_MS 1
+
+/** CPU protocol */
+static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs		Number of microseconds for which to delay
+ */
+static void efi_udelay ( unsigned long usecs ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_STATUS efirc;
+
+	if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
+		DBG ( "EFI could not delay for %ldus: %s\n",
+		      usecs, efi_strerror ( efirc ) );
+		/* Probably screwed */
+	}
+}
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks		Current time, in ticks
+ */
+static unsigned long efi_currticks ( void ) {
+	UINT64 time;
+	EFI_STATUS efirc;
+
+	/* Read CPU timer 0 (TSC) */
+	if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
+						 NULL ) ) != 0 ) {
+		DBG ( "EFI could not read CPU timer: %s\n",
+		      efi_strerror ( efirc ) );
+		/* Probably screwed */
+		return -1UL;
+	}
+
+	return ( time >> EFI_TIMER0_SHIFT );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec	Number of ticks per second
+ */
+static unsigned long efi_ticks_per_sec ( void ) {
+	static unsigned long ticks_per_sec = 0;
+
+	/* Calibrate timer, if necessary.  EFI does nominally provide
+	 * the timer speed via the (optional) TimerPeriod parameter to
+	 * the GetTimerValue() call, but it gets the speed slightly
+	 * wrong.  By up to three orders of magnitude.  Not helpful.
+	 */
+	if ( ! ticks_per_sec ) {
+		unsigned long start;
+		unsigned long elapsed;
+
+		DBG ( "Calibrating EFI timer with a %d ms delay\n",
+		      EFI_CALIBRATE_DELAY_MS );
+		start = currticks();
+		mdelay ( EFI_CALIBRATE_DELAY_MS );
+		elapsed = ( currticks() - start );
+		ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
+		DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
+		      "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
+		      ticks_per_sec );
+	}
+
+	return ticks_per_sec;
+}
+
+PROVIDE_TIMER ( efi, udelay, efi_udelay );
+PROVIDE_TIMER ( efi, currticks, efi_currticks );
+PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_uaccess.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_uaccess.c
new file mode 100644
index 0000000..d80ca7a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_uaccess.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/uaccess.h>
+#include <ipxe/efi/efi.h>
+
+/** @file
+ *
+ * iPXE user access API for EFI
+ *
+ */
+
+PROVIDE_UACCESS_INLINE ( efi, phys_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_phys );
+PROVIDE_UACCESS_INLINE ( efi, virt_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_virt );
+PROVIDE_UACCESS_INLINE ( efi, userptr_add );
+PROVIDE_UACCESS_INLINE ( efi, memcpy_user );
+PROVIDE_UACCESS_INLINE ( efi, memmove_user );
+PROVIDE_UACCESS_INLINE ( efi, memset_user );
+PROVIDE_UACCESS_INLINE ( efi, strlen_user );
+PROVIDE_UACCESS_INLINE ( efi, memchr_user );
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_umalloc.c b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_umalloc.c
new file mode 100644
index 0000000..d1d689e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/efi/efi_umalloc.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/efi/efi.h>
+
+/** @file
+ *
+ * iPXE user memory allocation API for EFI
+ *
+ */
+
+/** Equivalent of NOWHERE for user pointers */
+#define UNOWHERE ( ~UNULL )
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr		Memory previously allocated by umalloc(), or UNULL
+ * @v new_size		Requested size
+ * @ret new_ptr		Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_PHYSICAL_ADDRESS phys_addr;
+	unsigned int new_pages, old_pages;
+	userptr_t new_ptr = UNOWHERE;
+	size_t old_size;
+	EFI_STATUS efirc;
+
+	/* Allocate new memory if necessary.  If allocation fails,
+	 * return without touching the old block.
+	 */
+	if ( new_size ) {
+		new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 );
+		if ( ( efirc = bs->AllocatePages ( AllocateAnyPages,
+						   EfiBootServicesData,
+						   new_pages,
+						   &phys_addr ) ) != 0 ) {
+			DBG ( "EFI could not allocate %d pages: %s\n",
+			      new_pages, efi_strerror ( efirc ) );
+			return UNULL;
+		}
+		assert ( phys_addr != 0 );
+		new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
+		copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
+			       &new_size, sizeof ( new_size ) );
+		DBG ( "EFI allocated %d pages at %llx\n",
+		      new_pages, phys_addr );
+	}
+
+	/* Copy across relevant part of the old data region (if any),
+	 * then free it.  Note that at this point either (a) new_ptr
+	 * is valid, or (b) new_size is 0; either way, the memcpy() is
+	 * valid.
+	 */
+	if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
+		copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
+				 sizeof ( old_size ) );
+		memcpy_user ( new_ptr, 0, old_ptr, 0,
+			      ( (old_size < new_size) ? old_size : new_size ));
+		old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
+		phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
+		if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
+			DBG ( "EFI could not free %d pages at %llx: %s\n",
+			      old_pages, phys_addr, efi_strerror ( efirc ) );
+			/* Not fatal; we have leaked memory but successfully
+			 * allocated (if asked to do so).
+			 */
+		}
+		DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr );
+	}
+
+	return new_ptr;
+}
+
+PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc );
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_console.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_console.c
new file mode 100644
index 0000000..aeb7c66
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_console.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * Linux console implementation.
+ *
+ */
+
+#include <ipxe/console.h>
+
+#include <ipxe/init.h>
+#include <ipxe/keys.h>
+#include <linux_api.h>
+
+#include <linux/termios.h>
+#include <asm/errno.h>
+
+static void linux_console_putchar(int c)
+{
+	/* write to stdout */
+	if (linux_write(1, &c, 1) != 1)
+		DBG("linux_console write failed (%s)\n", linux_strerror(linux_errno));
+}
+
+static int linux_console_getchar()
+{
+	char c;
+
+	/* read from stdin */
+	if (linux_read(0, &c, 1) < 0) {
+		DBG("linux_console read failed (%s)\n", linux_strerror(linux_errno));
+		return 0;
+	}
+	/* backspace seems to be returned as ascii del, map it here */
+	if (c == 0x7f)
+		return KEY_BACKSPACE;
+	else
+		return c;
+}
+
+static int linux_console_iskey()
+{
+	struct pollfd pfd;
+	pfd.fd = 0;
+	pfd.events = POLLIN;
+
+	/* poll for data to be read on stdin */
+	if (linux_poll(&pfd, 1, 0) == -1) {
+		DBG("linux_console poll failed (%s)\n", linux_strerror(linux_errno));
+		return 0;
+	}
+
+	if (pfd.revents & POLLIN)
+		return 1;
+	else
+		return 0;
+}
+
+struct console_driver linux_console __console_driver = {
+	.disabled = 0,
+	.putchar = linux_console_putchar,
+	.getchar = linux_console_getchar,
+	.iskey = linux_console_iskey,
+};
+
+static int linux_tcgetattr(int fd, struct termios *termios_p)
+{
+	return linux_ioctl(fd, TCGETS, termios_p);
+}
+
+static int linux_tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
+{
+	unsigned long int cmd;
+
+	switch (optional_actions)
+	{
+		case TCSANOW:
+			cmd = TCSETS;
+			break;
+		case TCSADRAIN:
+			cmd = TCSETSW;
+			break;
+		case TCSAFLUSH:
+			cmd = TCSETSF;
+			break;
+		default:
+			linux_errno = EINVAL;
+			return -1;
+	}
+
+	return linux_ioctl(fd, cmd, termios_p);
+}
+
+/** Saved termios attributes */
+static struct termios saved_termios;
+
+/** Setup the terminal for our use */
+static void linux_console_startup(void)
+{
+	struct termios t;
+
+	if (linux_tcgetattr(0, &t)) {
+		DBG("linux_console tcgetattr failed (%s)", linux_strerror(linux_errno));
+		return;
+	}
+
+	saved_termios = t;
+
+	/* Disable canonical mode and echo. Let readline handle that */
+	t.c_lflag &= ~(ECHO | ICANON);
+	/* stop ^C from sending a signal */
+	t.c_cc[VINTR] = 0;
+
+	if (linux_tcsetattr(0, TCSAFLUSH, &t))
+		DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno));
+}
+
+/** Restores original terminal attributes on shutdown */
+static void linux_console_shutdown(int flags __unused)
+{
+	if (linux_tcsetattr(0, TCSAFLUSH, &saved_termios))
+		DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno));
+}
+
+struct startup_fn linux_console_startup_fn __startup_fn(STARTUP_EARLY) = {
+	.startup = linux_console_startup,
+	.shutdown = linux_console_shutdown,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_nap.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_nap.c
new file mode 100644
index 0000000..98642ba
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_nap.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/nap.h>
+
+#include <linux_api.h>
+
+/** @file
+ *
+ * iPXE CPU sleeping API for linux
+ *
+ */
+
+/**
+ * Sleep until next CPU interrupt
+ *
+ */
+static void linux_cpu_nap(void)
+{
+	linux_usleep(0);
+}
+
+PROVIDE_NAP(linux, cpu_nap, linux_cpu_nap);
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_smbios.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_smbios.c
new file mode 100644
index 0000000..f99120b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_smbios.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <errno.h>
+#include <ipxe/smbios.h>
+
+/**
+ * Find SMBIOS
+ *
+ * Not implemented currently.
+ *
+ * @v smbios		SMBIOS entry point descriptor structure to fill in
+ * @ret rc		Return status code
+ */
+static int linux_find_smbios(struct smbios *smbios __unused)
+{
+	return -ENODEV;
+}
+
+PROVIDE_SMBIOS(linux, find_smbios, linux_find_smbios);
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_timer.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_timer.c
new file mode 100644
index 0000000..6b4643a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_timer.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/timer.h>
+
+#include <linux_api.h>
+
+/** @file
+ *
+ * iPXE timer API for linux
+ *
+ */
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs		Number of microseconds for which to delay
+ */
+static void linux_udelay(unsigned long usecs)
+{
+	linux_usleep(usecs);
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec	Number of ticks per second
+ */
+static unsigned long linux_ticks_per_sec(void)
+{
+	return 1000;
+}
+
+/**
+ * Get current system time in ticks
+ *
+ * linux doesn't provide an easy access to jiffies so implement it by measuring
+ * the time since the first call to this function.
+ *
+ * @ret ticks		Current time, in ticks
+ */
+static unsigned long linux_currticks(void)
+{
+	static struct timeval start;
+	static int initialized = 0;
+
+	if (! initialized) {
+		linux_gettimeofday(&start, NULL);
+		initialized = 1;
+	}
+
+	struct timeval now;
+	linux_gettimeofday(&now, NULL);
+
+	unsigned long ticks = (now.tv_sec - start.tv_sec) * linux_ticks_per_sec();
+	ticks += (now.tv_usec - start.tv_usec) / (long)(1000000 / linux_ticks_per_sec());
+
+	return ticks;
+}
+
+PROVIDE_TIMER(linux, udelay, linux_udelay);
+PROVIDE_TIMER(linux, currticks, linux_currticks);
+PROVIDE_TIMER(linux, ticks_per_sec, linux_ticks_per_sec);
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_uaccess.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_uaccess.c
new file mode 100644
index 0000000..d4e52d0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_uaccess.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <ipxe/uaccess.h>
+
+/** @file
+ *
+ * iPXE user access API for linux
+ *
+ */
+
+PROVIDE_UACCESS_INLINE(linux, phys_to_user);
+PROVIDE_UACCESS_INLINE(linux, user_to_phys);
+PROVIDE_UACCESS_INLINE(linux, virt_to_user);
+PROVIDE_UACCESS_INLINE(linux, user_to_virt);
+PROVIDE_UACCESS_INLINE(linux, userptr_add);
+PROVIDE_UACCESS_INLINE(linux, memcpy_user);
+PROVIDE_UACCESS_INLINE(linux, memmove_user);
+PROVIDE_UACCESS_INLINE(linux, memset_user);
+PROVIDE_UACCESS_INLINE(linux, strlen_user);
+PROVIDE_UACCESS_INLINE(linux, memchr_user);
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_umalloc.c b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_umalloc.c
new file mode 100644
index 0000000..aa0052c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/linux/linux_umalloc.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <valgrind/memcheck.h>
+
+/** @file
+ *
+ * iPXE user memory allocation API for linux
+ *
+ */
+
+#include <assert.h>
+#include <ipxe/umalloc.h>
+
+#include <linux_api.h>
+
+/** Special address returned for empty allocations */
+#define NOWHERE ((void *)-1)
+
+/** Poison to make the metadata more unique */
+#define POISON 0xa5a5a5a5
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/** Metadata stored at the beginning of all allocations */
+struct metadata
+{
+	unsigned poison;
+	size_t size;
+};
+
+#define SIZE_MD (sizeof(struct metadata))
+
+/** Simple realloc which passes most of the work to mmap(), mremap() and munmap() */
+static void * linux_realloc(void *ptr, size_t size)
+{
+	struct metadata md = {0, 0};
+	struct metadata * mdptr = NULL;
+
+	DBG2("linux_realloc(%p, %zd)\n", ptr, size);
+
+	/* Check whether we have a valid pointer */
+	if (ptr != NULL && ptr != NOWHERE) {
+		mdptr = ptr - SIZE_MD;
+		VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD);
+		md = *mdptr;
+		VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD);
+
+		/* Check for poison in the metadata */
+		if (md.poison != POISON) {
+			DBG("linux_realloc bad poison: 0x%x (expected 0x%x)\n", md.poison, POISON);
+			return NULL;
+		}
+	} else {
+		/* Handle NOWHERE as NULL */
+		ptr = NULL;
+	}
+
+	/*
+	 * At this point, ptr is either NULL or pointing to a region allocated by us.
+	 * In the latter case mdptr is pointing to a valid metadata, otherwise it is NULL.
+	 */
+
+	/* Handle deallocation or allocation of size 0 */
+	if (size == 0) {
+		if (mdptr) {
+			if (linux_munmap(mdptr, md.size))
+				DBG("linux_realloc munmap failed: %s\n", linux_strerror(linux_errno));
+			VALGRIND_FREELIKE_BLOCK(ptr, sizeof(*mdptr));
+		}
+		return NOWHERE;
+	}
+
+	if (ptr) {
+		char *vbits = NULL;
+
+		if (RUNNING_ON_VALGRIND > 0)
+			vbits = linux_realloc(NULL, min(size, md.size));
+
+/* prevent an unused variable warning when building w/o valgrind support */
+#ifndef NVALGRIND
+		VALGRIND_GET_VBITS(ptr, vbits, min(size, md.size));
+#endif
+
+		VALGRIND_FREELIKE_BLOCK(ptr, SIZE_MD);
+
+		mdptr = linux_mremap(mdptr, md.size + SIZE_MD, size + SIZE_MD, MREMAP_MAYMOVE);
+		if (mdptr == MAP_FAILED) {
+			DBG("linux_realloc mremap failed: %s\n", linux_strerror(linux_errno));
+			return NULL;
+		}
+		ptr = ((void *)mdptr) + SIZE_MD;
+
+		VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0);
+/* prevent an unused variable warning when building w/o valgrind support */
+#ifndef NVALGRIND
+		VALGRIND_SET_VBITS(ptr, vbits, min(size, md.size));
+#endif
+
+		if (RUNNING_ON_VALGRIND > 0)
+			linux_realloc(vbits, 0);
+	} else {
+		mdptr = linux_mmap(NULL, size + SIZE_MD, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (mdptr == MAP_FAILED) {
+			DBG("linux_realloc mmap failed: %s\n", linux_strerror(linux_errno));
+			return NULL;
+		}
+		ptr = ((void *)mdptr) + SIZE_MD;
+		VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0);
+	}
+
+	/* Update the metadata */
+	VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD);
+	mdptr->poison = POISON;
+	mdptr->size = size;
+	VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD);
+	// VALGRIND_MALLOCLIKE_BLOCK ignores redzones currently, make our own
+	VALGRIND_MAKE_MEM_NOACCESS(ptr + size, SIZE_MD);
+
+	return ptr;
+}
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr		Memory previously allocated by umalloc(), or UNULL
+ * @v new_size		Requested size
+ * @ret new_ptr		Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t linux_urealloc(userptr_t old_ptr, size_t new_size)
+{
+	return (userptr_t)linux_realloc((void *)old_ptr, new_size);
+}
+
+PROVIDE_UMALLOC(linux, urealloc, linux_urealloc);
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios.c b/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios.c
new file mode 100644
index 0000000..b60e10f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/smbios.h>
+
+/** @file
+ *
+ * System Management BIOS
+ *
+ */
+
+/** SMBIOS entry point descriptor */
+static struct smbios smbios = {
+	.address = UNULL,
+};
+
+/**
+ * Find SMBIOS strings terminator
+ *
+ * @v offset		Offset to start of strings
+ * @ret offset		Offset to strings terminator, or 0 if not found
+ */
+static size_t find_strings_terminator ( size_t offset ) {
+	size_t max_offset = ( smbios.len - 2 );
+	uint16_t nulnul;
+
+	for ( ; offset <= max_offset ; offset++ ) {
+		copy_from_user ( &nulnul, smbios.address, offset, 2 );
+		if ( nulnul == 0 )
+			return ( offset + 1 );
+	}
+	return 0;
+}
+
+/**
+ * Find specific structure type within SMBIOS
+ *
+ * @v type		Structure type to search for
+ * @v structure		SMBIOS structure descriptor to fill in
+ * @ret rc		Return status code
+ */
+int find_smbios_structure ( unsigned int type,
+			    struct smbios_structure *structure ) {
+	unsigned int count = 0;
+	size_t offset = 0;
+	size_t strings_offset;
+	size_t terminator_offset;
+	int rc;
+
+	/* Find SMBIOS */
+	if ( ( smbios.address == UNULL ) &&
+	     ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
+		return rc;
+	assert ( smbios.address != UNULL );
+
+	/* Scan through list of structures */
+	while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len )
+		&& ( count < smbios.count ) ) {
+
+		/* Read next SMBIOS structure header */
+		copy_from_user ( &structure->header, smbios.address, offset,
+				 sizeof ( structure->header ) );
+
+		/* Determine start and extent of strings block */
+		strings_offset = ( offset + structure->header.len );
+		if ( strings_offset > smbios.len ) {
+			DBG ( "SMBIOS structure at offset %zx with length "
+			      "%x extends beyond SMBIOS\n", offset,
+			      structure->header.len );
+			return -ENOENT;
+		}
+		terminator_offset = find_strings_terminator ( strings_offset );
+		if ( ! terminator_offset ) {
+			DBG ( "SMBIOS structure at offset %zx has "
+			      "unterminated strings section\n", offset );
+			return -ENOENT;
+		}
+		structure->strings_len = ( terminator_offset - strings_offset);
+
+		DBG ( "SMBIOS structure at offset %zx has type %d, length %x, "
+		      "strings length %zx\n", offset, structure->header.type,
+		      structure->header.len, structure->strings_len );
+
+		/* If this is the structure we want, return */
+		if ( structure->header.type == type ) {
+			structure->offset = offset;
+			return 0;
+		}
+
+		/* Move to next SMBIOS structure */
+		offset = ( terminator_offset + 1 );
+		count++;
+	}
+
+	DBG ( "SMBIOS structure type %d not found\n", type );
+	return -ENOENT;
+}
+
+/**
+ * Copy SMBIOS structure
+ *
+ * @v structure		SMBIOS structure descriptor
+ * @v data		Buffer to hold SMBIOS structure
+ * @v len		Length of buffer
+ * @ret rc		Return status code
+ */
+int read_smbios_structure ( struct smbios_structure *structure,
+			    void *data, size_t len ) {
+
+	assert ( smbios.address != UNULL );
+
+	if ( len > structure->header.len )
+		len = structure->header.len;
+	copy_from_user ( data, smbios.address, structure->offset, len );
+	return 0;
+}
+
+/**
+ * Find indexed string within SMBIOS structure
+ *
+ * @v structure		SMBIOS structure descriptor
+ * @v index		String index
+ * @v data		Buffer for string
+ * @v len		Length of string buffer
+ * @ret rc		Length of string, or negative error
+ */
+int read_smbios_string ( struct smbios_structure *structure,
+			 unsigned int index, void *data, size_t len ) {
+	size_t strings_start = ( structure->offset + structure->header.len );
+	size_t strings_end = ( strings_start + structure->strings_len );
+	size_t offset;
+	size_t string_len;
+
+	assert ( smbios.address != UNULL );
+
+	/* String numbers start at 1 (0 is used to indicate "no string") */
+	if ( ! index )
+		return -ENOENT;
+
+	for ( offset = strings_start ; offset < strings_end ;
+	      offset += ( string_len + 1 ) ) {
+		/* Get string length.  This is known safe, since the
+		 * smbios_strings struct is constructed so as to
+		 * always end on a string boundary.
+		 */
+		string_len = strlen_user ( smbios.address, offset );
+		if ( --index == 0 ) {
+			/* Copy string, truncating as necessary. */
+			if ( len > string_len )
+				len = string_len;
+			copy_from_user ( data, smbios.address, offset, len );
+			return string_len;
+		}
+	}
+
+	DBG ( "SMBIOS string index %d not found\n", index );
+	return -ENOENT;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios_settings.c b/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios_settings.c
new file mode 100644
index 0000000..92dc412
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/interface/smbios/smbios_settings.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/settings.h>
+#include <ipxe/init.h>
+#include <ipxe/uuid.h>
+#include <ipxe/smbios.h>
+
+/** SMBIOS settings tag magic number */
+#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */
+
+/**
+ * Construct SMBIOS empty tag
+ *
+ * @ret tag		SMBIOS setting tag
+ */
+#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 )
+
+/**
+ * Construct SMBIOS raw-data tag
+ *
+ * @v _type		SMBIOS structure type number
+ * @v _structure	SMBIOS structure data type
+ * @v _field		Field within SMBIOS structure data type
+ * @ret tag		SMBIOS setting tag
+ */
+#define SMBIOS_RAW_TAG( _type, _structure, _field )		\
+	( ( SMBIOS_TAG_MAGIC << 24 ) |				\
+	  ( (_type) << 16 ) |					\
+	  ( offsetof ( _structure, _field ) << 8 ) |		\
+	  ( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
+
+/**
+ * Construct SMBIOS string tag
+ *
+ * @v _type		SMBIOS structure type number
+ * @v _structure	SMBIOS structure data type
+ * @v _field		Field within SMBIOS structure data type
+ * @ret tag		SMBIOS setting tag
+ */
+#define SMBIOS_STRING_TAG( _type, _structure, _field )		\
+	( ( SMBIOS_TAG_MAGIC << 24 ) |				\
+	  ( (_type) << 16 ) |					\
+	  ( offsetof ( _structure, _field ) << 8 ) )
+
+/**
+ * Check applicability of SMBIOS setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int smbios_applies ( struct settings *settings __unused,
+			    struct setting *setting ) {
+	unsigned int tag_magic;
+
+	/* Check tag magic */
+	tag_magic = ( setting->tag >> 24 );
+	return ( tag_magic == SMBIOS_TAG_MAGIC );
+}
+
+/**
+ * Fetch value of SMBIOS setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+static int smbios_fetch ( struct settings *settings __unused,
+			  struct setting *setting,
+			  void *data, size_t len ) {
+	struct smbios_structure structure;
+	unsigned int tag_magic;
+	unsigned int tag_type;
+	unsigned int tag_offset;
+	unsigned int tag_len;
+	int rc;
+
+	/* Split tag into type, offset and length */
+	tag_magic = ( setting->tag >> 24 );
+	tag_type = ( ( setting->tag >> 16 ) & 0xff );
+	tag_offset = ( ( setting->tag >> 8 ) & 0xff );
+	tag_len = ( setting->tag & 0xff );
+	assert ( tag_magic == SMBIOS_TAG_MAGIC );
+
+	/* Find SMBIOS structure */
+	if ( ( rc = find_smbios_structure ( tag_type, &structure ) ) != 0 )
+		return rc;
+
+	{
+		uint8_t buf[structure.header.len];
+
+		/* Read SMBIOS structure */
+		if ( ( rc = read_smbios_structure ( &structure, buf,
+						    sizeof ( buf ) ) ) != 0 )
+			return rc;
+
+		if ( tag_len == 0 ) {
+			/* String */
+			return read_smbios_string ( &structure,
+						    buf[tag_offset],
+						    data, len );
+		} else {
+			/* Raw data */
+			if ( len > tag_len )
+				len = tag_len;
+			memcpy ( data, &buf[tag_offset], len );
+			return tag_len;
+		}
+	}
+}
+
+/** SMBIOS settings operations */
+static struct settings_operations smbios_settings_operations = {
+	.applies = smbios_applies,
+	.fetch = smbios_fetch,
+};
+
+/** SMBIOS settings */
+static struct settings smbios_settings = {
+	.refcnt = NULL,
+	.tag_magic = SMBIOS_EMPTY_TAG,
+	.siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
+	.children = LIST_HEAD_INIT ( smbios_settings.children ),
+	.op = &smbios_settings_operations,
+};
+
+/** Initialise SMBIOS settings */
+static void smbios_init ( void ) {
+	int rc;
+
+	if ( ( rc = register_settings ( &smbios_settings, NULL,
+					"smbios" ) ) != 0 ) {
+		DBG ( "SMBIOS could not register settings: %s\n",
+		      strerror ( rc ) );
+		return;
+	}
+}
+
+/** SMBIOS settings initialiser */
+struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = smbios_init,
+};
+
+/** UUID setting obtained via SMBIOS */
+struct setting uuid_setting __setting ( SETTING_HOST ) = {
+	.name = "uuid",
+	.description = "UUID",
+	.tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
+				struct smbios_system_information, uuid ),
+	.type = &setting_type_uuid,
+};
+
+/** Other SMBIOS named settings */
+struct setting smbios_named_settings[] __setting ( SETTING_HOST_EXTRA ) = {
+	{
+		.name = "manufacturer",
+		.description = "Manufacturer",
+		.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
+					   struct smbios_system_information,
+					   manufacturer ),
+		.type = &setting_type_string,
+	},
+	{
+		.name = "product",
+		.description = "Product name",
+		.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
+					   struct smbios_system_information,
+					   product ),
+		.type = &setting_type_string,
+	},
+	{
+		.name = "serial",
+		.description = "Serial number",
+		.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
+					   struct smbios_system_information,
+					   serial ),
+		.type = &setting_type_string,
+	},
+	{
+		.name = "asset",
+		.description = "Asset tag",
+		.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION,
+					   struct smbios_enclosure_information,
+					   asset_tag ),
+		.type = &setting_type_string,
+	},
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/__divdi3.c b/qemu-0.15.x/roms/ipxe/src/libgcc/__divdi3.c
new file mode 100644
index 0000000..7097b11
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/__divdi3.c
@@ -0,0 +1,26 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include "libgcc.h"
+
+__libgcc int64_t __divdi3(int64_t num, int64_t den)
+{
+  int minus = 0;
+  int64_t v;
+
+  if ( num < 0 ) {
+    num = -num;
+    minus = 1;
+  }
+  if ( den < 0 ) {
+    den = -den;
+    minus ^= 1;
+  }
+
+  v = __udivmoddi4(num, den, NULL);
+  if ( minus )
+    v = -v;
+
+  return v;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/__moddi3.c b/qemu-0.15.x/roms/ipxe/src/libgcc/__moddi3.c
new file mode 100644
index 0000000..d671bbc
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/__moddi3.c
@@ -0,0 +1,26 @@
+/*
+ * arch/i386/libgcc/__moddi3.c
+ */
+
+#include "libgcc.h"
+
+__libgcc int64_t __moddi3(int64_t num, int64_t den)
+{
+  int minus = 0;
+  int64_t v;
+
+  if ( num < 0 ) {
+    num = -num;
+    minus = 1;
+  }
+  if ( den < 0 ) {
+    den = -den;
+    minus ^= 1;
+  }
+
+  (void) __udivmoddi4(num, den, (uint64_t *)&v);
+  if ( minus )
+    v = -v;
+
+  return v;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/__udivdi3.c b/qemu-0.15.x/roms/ipxe/src/libgcc/__udivdi3.c
new file mode 100644
index 0000000..f5a14de
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/__udivdi3.c
@@ -0,0 +1,10 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include "libgcc.h"
+
+__libgcc uint64_t __udivdi3(uint64_t num, uint64_t den)
+{
+  return __udivmoddi4(num, den, NULL);
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/__udivmoddi4.c b/qemu-0.15.x/roms/ipxe/src/libgcc/__udivmoddi4.c
new file mode 100644
index 0000000..21e0d51
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/__udivmoddi4.c
@@ -0,0 +1,32 @@
+#include "libgcc.h"
+
+__libgcc uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p)
+{
+  uint64_t quot = 0, qbit = 1;
+
+  if ( den == 0 ) {
+    return 1/((unsigned)den); /* Intentional divide by zero, without
+				 triggering a compiler warning which
+				 would abort the build */
+  }
+
+  /* Left-justify denominator and count shift */
+  while ( (int64_t)den >= 0 ) {
+    den <<= 1;
+    qbit <<= 1;
+  }
+
+  while ( qbit ) {
+    if ( den <= num ) {
+      num -= den;
+      quot += qbit;
+    }
+    den >>= 1;
+    qbit >>= 1;
+  }
+
+  if ( rem_p )
+    *rem_p = num;
+
+  return quot;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/__umoddi3.c b/qemu-0.15.x/roms/ipxe/src/libgcc/__umoddi3.c
new file mode 100644
index 0000000..fb4da99
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/__umoddi3.c
@@ -0,0 +1,13 @@
+/*
+ * arch/i386/libgcc/__umoddi3.c
+ */
+
+#include "libgcc.h"
+
+__libgcc uint64_t __umoddi3(uint64_t num, uint64_t den)
+{
+  uint64_t v;
+
+  (void) __udivmoddi4(num, den, &v);
+  return v;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/icc.c b/qemu-0.15.x/roms/ipxe/src/libgcc/icc.c
new file mode 100644
index 0000000..2f7f605
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/icc.c
@@ -0,0 +1,8 @@
+/*
+ * Intel's compiler creates an implicit call to this function at the
+ * start of main().
+ *
+ */
+void __libgcc __intel_new_proc_init ( void ) {
+	/* Do nothing */
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/libgcc.h b/qemu-0.15.x/roms/ipxe/src/libgcc/libgcc.h
new file mode 100644
index 0000000..d3e9bdd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/libgcc.h
@@ -0,0 +1,14 @@
+#ifndef _LIBGCC_H
+#define _LIBGCC_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern __libgcc uint64_t __udivmoddi4 ( uint64_t num, uint64_t den,
+					uint64_t *rem );
+extern __libgcc uint64_t __udivdi3  (uint64_t num, uint64_t den );
+extern __libgcc uint64_t __umoddi3 ( uint64_t num, uint64_t den );
+extern __libgcc int64_t __divdi3 ( int64_t num, int64_t den );
+extern __libgcc int64_t __moddi3 ( int64_t num, int64_t den );
+
+#endif /* _LIBGCC_H */
diff --git a/qemu-0.15.x/roms/ipxe/src/libgcc/memcpy.c b/qemu-0.15.x/roms/ipxe/src/libgcc/memcpy.c
new file mode 100644
index 0000000..e98b783
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/libgcc/memcpy.c
@@ -0,0 +1,18 @@
+/** @file
+ *
+ * gcc sometimes likes to insert implicit calls to memcpy().
+ * Unfortunately, there doesn't seem to be any way to prevent it from
+ * doing this, or to force it to use the optimised memcpy() as seen by
+ * C code; it insists on inserting a symbol reference to "memcpy".  We
+ * therefore include wrapper functions just to keep gcc happy.
+ *
+ */
+
+#include <string.h>
+
+void * gcc_implicit_memcpy ( void *dest, const void *src,
+			     size_t len ) asm ( "memcpy" );
+
+void * gcc_implicit_memcpy ( void *dest, const void *src, size_t len ) {
+	return memcpy ( dest, src, len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/net80211.c b/qemu-0.15.x/roms/ipxe/src/net/80211/net80211.c
new file mode 100644
index 0000000..f5ab65f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/net80211.c
@@ -0,0 +1,2820 @@
+/*
+ * The iPXE 802.11 MAC layer.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <byteswap.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/settings.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/ieee80211.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/net80211.h>
+#include <ipxe/sec80211.h>
+#include <ipxe/timer.h>
+#include <ipxe/nap.h>
+#include <ipxe/errortab.h>
+#include <ipxe/net80211_err.h>
+
+/** @file
+ *
+ * 802.11 device management
+ */
+
+/** List of 802.11 devices */
+static struct list_head net80211_devices = LIST_HEAD_INIT ( net80211_devices );
+
+/** Set of device operations that does nothing */
+static struct net80211_device_operations net80211_null_ops;
+
+/** Information associated with a received management packet
+ *
+ * This is used to keep beacon signal strengths in a parallel queue to
+ * the beacons themselves.
+ */
+struct net80211_rx_info {
+	int signal;
+	struct list_head list;
+};
+
+/** Context for a probe operation */
+struct net80211_probe_ctx {
+	/** 802.11 device to probe on */
+	struct net80211_device *dev;
+
+	/** Value of keep_mgmt before probe was started */
+	int old_keep_mgmt;
+
+	/** If scanning actively, pointer to probe packet to send */
+	struct io_buffer *probe;
+
+	/** If non-"", the ESSID to limit ourselves to */
+	const char *essid;
+
+	/** Time probe was started */
+	u32 ticks_start;
+
+	/** Time last useful beacon was received */
+	u32 ticks_beacon;
+
+	/** Time channel was last changed */
+	u32 ticks_channel;
+
+	/** Time to stay on each channel */
+	u32 hop_time;
+
+	/** Channels to hop by when changing channel */
+	int hop_step;
+
+	/** List of best beacons for each network found so far */
+	struct list_head *beacons;
+};
+
+/** Context for the association task */
+struct net80211_assoc_ctx {
+	/** Next authentication method to try using */
+	int method;
+
+	/** Time (in ticks) of the last sent association-related packet */
+	int last_packet;
+
+	/** Number of times we have tried sending it */
+	int times_tried;
+};
+
+/**
+ * Detect secure 802.11 network when security support is not available
+ *
+ * @return -ENOTSUP, always.
+ */
+__weak int sec80211_detect ( struct io_buffer *iob __unused,
+			     enum net80211_security_proto *secprot __unused,
+			     enum net80211_crypto_alg *crypt __unused ) {
+	return -ENOTSUP;
+}
+
+/**
+ * @defgroup net80211_netdev Network device interface functions
+ * @{
+ */
+static int net80211_netdev_open ( struct net_device *netdev );
+static void net80211_netdev_close ( struct net_device *netdev );
+static int net80211_netdev_transmit ( struct net_device *netdev,
+				      struct io_buffer *iobuf );
+static void net80211_netdev_poll ( struct net_device *netdev );
+static void net80211_netdev_irq ( struct net_device *netdev, int enable );
+/** @} */
+
+/**
+ * @defgroup net80211_linklayer 802.11 link-layer protocol functions
+ * @{
+ */
+static int net80211_ll_push ( struct net_device *netdev,
+			      struct io_buffer *iobuf, const void *ll_dest,
+			      const void *ll_source, uint16_t net_proto );
+static int net80211_ll_pull ( struct net_device *netdev,
+			      struct io_buffer *iobuf, const void **ll_dest,
+			      const void **ll_source, uint16_t * net_proto );
+/** @} */
+
+/**
+ * @defgroup net80211_help 802.11 helper functions
+ * @{
+ */
+static void net80211_add_channels ( struct net80211_device *dev, int start,
+				    int len, int txpower );
+static void net80211_filter_hw_channels ( struct net80211_device *dev );
+static void net80211_set_rtscts_rate ( struct net80211_device *dev );
+static int net80211_process_capab ( struct net80211_device *dev,
+				    u16 capab );
+static int net80211_process_ie ( struct net80211_device *dev,
+				 union ieee80211_ie *ie, void *ie_end );
+static union ieee80211_ie *
+net80211_marshal_request_info ( struct net80211_device *dev,
+				union ieee80211_ie *ie );
+/** @} */
+
+/**
+ * @defgroup net80211_assoc_ll 802.11 association handling functions
+ * @{
+ */
+static void net80211_step_associate ( struct process *proc );
+static void net80211_handle_auth ( struct net80211_device *dev,
+				   struct io_buffer *iob );
+static void net80211_handle_assoc_reply ( struct net80211_device *dev,
+					  struct io_buffer *iob );
+static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
+				    int deauth );
+static void net80211_handle_mgmt ( struct net80211_device *dev,
+				   struct io_buffer *iob, int signal );
+/** @} */
+
+/**
+ * @defgroup net80211_frag 802.11 fragment handling functions
+ * @{
+ */
+static void net80211_free_frags ( struct net80211_device *dev, int fcid );
+static struct io_buffer *net80211_accum_frags ( struct net80211_device *dev,
+						int fcid, int nfrags, int size );
+static void net80211_rx_frag ( struct net80211_device *dev,
+			       struct io_buffer *iob, int signal );
+/** @} */
+
+/**
+ * @defgroup net80211_settings 802.11 settings handlers
+ * @{
+ */
+static int net80211_check_settings_update ( void );
+
+/** 802.11 settings applicator
+ *
+ * When the SSID is changed, this will cause any open devices to
+ * re-associate; when the encryption key is changed, we similarly
+ * update their state.
+ */
+struct settings_applicator net80211_applicator __settings_applicator = {
+	.apply = net80211_check_settings_update,
+};
+
+/** The network name to associate with
+ *
+ * If this is blank, we scan for all networks and use the one with the
+ * greatest signal strength.
+ */
+struct setting net80211_ssid_setting __setting ( SETTING_NETDEV_EXTRA ) = {
+	.name = "ssid",
+	.description = "Wireless SSID",
+	.type = &setting_type_string,
+	.tag = NET80211_SETTING_TAG_SSID,
+};
+
+/** Whether to use active scanning
+ *
+ * In order to associate with a hidden SSID, it's necessary to use an
+ * active scan (send probe packets). If this setting is nonzero, an
+ * active scan on the 2.4GHz band will be used to associate.
+ */
+struct setting net80211_active_setting __setting ( SETTING_NETDEV_EXTRA ) = {
+	.name = "active-scan",
+	.description = "Actively scan for wireless networks",
+	.type = &setting_type_int8,
+	.tag = NET80211_SETTING_TAG_ACTIVE_SCAN,
+};
+
+/** The cryptographic key to use
+ *
+ * For hex WEP keys, as is common, this must be entered using the
+ * normal iPXE method for entering hex settings; an ASCII string of
+ * hex characters will not behave as expected.
+ */
+struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA ) = {
+	.name = "key",
+	.description = "Wireless encryption key",
+	.type = &setting_type_string,
+	.tag = NET80211_SETTING_TAG_KEY,
+};
+
+/** @} */
+
+
+/* ---------- net_device wrapper ---------- */
+
+/**
+ * Open 802.11 device and start association
+ *
+ * @v netdev	Wrapping network device
+ * @ret rc	Return status code
+ *
+ * This sets up a default conservative set of channels for probing,
+ * and starts the auto-association task unless the @c
+ * NET80211_NO_ASSOC flag is set in the wrapped 802.11 device's @c
+ * state field.
+ */
+static int net80211_netdev_open ( struct net_device *netdev )
+{
+	struct net80211_device *dev = netdev->priv;
+	int rc = 0;
+
+	if ( dev->op == &net80211_null_ops )
+		return -EFAULT;
+
+	if ( dev->op->open )
+		rc = dev->op->open ( dev );
+
+	if ( rc < 0 )
+		return rc;
+
+	if ( ! ( dev->state & NET80211_NO_ASSOC ) )
+		net80211_autoassociate ( dev );
+
+	return 0;
+}
+
+/**
+ * Close 802.11 device
+ *
+ * @v netdev	Wrapping network device.
+ *
+ * If the association task is running, this will stop it.
+ */
+static void net80211_netdev_close ( struct net_device *netdev )
+{
+	struct net80211_device *dev = netdev->priv;
+
+	if ( dev->state & NET80211_WORKING )
+		process_del ( &dev->proc_assoc );
+
+	/* Send disassociation frame to AP, to be polite */
+	if ( dev->state & NET80211_ASSOCIATED )
+		net80211_send_disassoc ( dev, IEEE80211_REASON_LEAVING, 0 );
+
+	if ( dev->handshaker && dev->handshaker->stop &&
+	     dev->handshaker->started )
+		dev->handshaker->stop ( dev );
+
+	free ( dev->crypto );
+	free ( dev->handshaker );
+	dev->crypto = NULL;
+	dev->handshaker = NULL;
+
+	netdev_link_down ( netdev );
+	dev->state = 0;
+
+	if ( dev->op->close )
+		dev->op->close ( dev );
+}
+
+/**
+ * Transmit packet on 802.11 device
+ *
+ * @v netdev	Wrapping network device
+ * @v iobuf	I/O buffer
+ * @ret rc	Return status code
+ *
+ * If encryption is enabled for the currently associated network, the
+ * packet will be encrypted prior to transmission.
+ */
+static int net80211_netdev_transmit ( struct net_device *netdev,
+				      struct io_buffer *iobuf )
+{
+	struct net80211_device *dev = netdev->priv;
+	struct ieee80211_frame *hdr = iobuf->data;
+	int rc = -ENOSYS;
+
+	if ( dev->crypto && ! ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
+	     ( ( hdr->fc & IEEE80211_FC_TYPE ) == IEEE80211_TYPE_DATA ) ) {
+		struct io_buffer *niob = dev->crypto->encrypt ( dev->crypto,
+								iobuf );
+		if ( ! niob )
+			return -ENOMEM;	/* only reason encryption could fail */
+
+		/* Free the non-encrypted iob */
+		netdev_tx_complete ( netdev, iobuf );
+
+		/* Transmit the encrypted iob; the Protected flag is
+		   set, so we won't recurse into here again */
+		netdev_tx ( netdev, niob );
+
+		/* Don't transmit the freed packet */
+		return 0;
+	}
+
+	if ( dev->op->transmit )
+		rc = dev->op->transmit ( dev, iobuf );
+
+	return rc;
+}
+
+/**
+ * Poll 802.11 device for received packets and completed transmissions
+ *
+ * @v netdev	Wrapping network device
+ */
+static void net80211_netdev_poll ( struct net_device *netdev )
+{
+	struct net80211_device *dev = netdev->priv;
+
+	if ( dev->op->poll )
+		dev->op->poll ( dev );
+}
+
+/**
+ * Enable or disable interrupts for 802.11 device
+ *
+ * @v netdev	Wrapping network device
+ * @v enable	Whether to enable interrupts
+ */
+static void net80211_netdev_irq ( struct net_device *netdev, int enable )
+{
+	struct net80211_device *dev = netdev->priv;
+
+	if ( dev->op->irq )
+		dev->op->irq ( dev, enable );
+}
+
+/** Network device operations for a wrapped 802.11 device */
+static struct net_device_operations net80211_netdev_ops = {
+	.open = net80211_netdev_open,
+	.close = net80211_netdev_close,
+	.transmit = net80211_netdev_transmit,
+	.poll = net80211_netdev_poll,
+	.irq = net80211_netdev_irq,
+};
+
+
+/* ---------- 802.11 link-layer protocol ---------- */
+
+/** 802.11 broadcast MAC address */
+static u8 net80211_ll_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/**
+ * Determine whether a transmission rate uses ERP/OFDM
+ *
+ * @v rate	Rate in 100 kbps units
+ * @ret is_erp	TRUE if the rate is an ERP/OFDM rate
+ *
+ * 802.11b supports rates of 1.0, 2.0, 5.5, and 11.0 Mbps; any other
+ * rate than these on the 2.4GHz spectrum is an ERP (802.11g) rate.
+ */
+static inline int net80211_rate_is_erp ( u16 rate )
+{
+	if ( rate == 10 || rate == 20 || rate == 55 || rate == 110 )
+		return 0;
+	return 1;
+}
+
+
+/**
+ * Calculate one frame's contribution to 802.11 duration field
+ *
+ * @v dev	802.11 device
+ * @v bytes	Amount of data to calculate duration for
+ * @ret dur	Duration field in microseconds
+ *
+ * To avoid multiple stations attempting to transmit at once, 802.11
+ * provides that every packet shall include a duration field
+ * specifying a length of time for which the wireless medium will be
+ * reserved after it is transmitted. The duration is measured in
+ * microseconds and is calculated with respect to the current
+ * physical-layer parameters of the 802.11 device.
+ *
+ * For an unfragmented data or management frame, or the last fragment
+ * of a fragmented frame, the duration captures only the 10 data bytes
+ * of one ACK; call once with bytes = 10.
+ *
+ * For a fragment of a data or management rame that will be followed
+ * by more fragments, the duration captures an ACK, the following
+ * fragment, and its ACK; add the results of three calls, two with
+ * bytes = 10 and one with bytes set to the next fragment's size.
+ *
+ * For an RTS control frame, the duration captures the responding CTS,
+ * the frame being sent, and its ACK; add the results of three calls,
+ * two with bytes = 10 and one with bytes set to the next frame's size
+ * (assuming unfragmented).
+ *
+ * For a CTS-to-self control frame, the duration captures the frame
+ * being protected and its ACK; add the results of two calls, one with
+ * bytes = 10 and one with bytes set to the next frame's size.
+ *
+ * No other frame types are currently supported by iPXE.
+ */
+u16 net80211_duration ( struct net80211_device *dev, int bytes, u16 rate )
+{
+	struct net80211_channel *chan = &dev->channels[dev->channel];
+	u32 kbps = rate * 100;
+
+	if ( chan->band == NET80211_BAND_5GHZ || net80211_rate_is_erp ( rate ) ) {
+		/* OFDM encoding (802.11a/g) */
+		int bits_per_symbol = ( kbps * 4 ) / 1000;	/* 4us/symbol */
+		int bits = 22 + ( bytes << 3 );	/* 22-bit PLCP */
+		int symbols = ( bits + bits_per_symbol - 1 ) / bits_per_symbol;
+
+		return 16 + 20 + ( symbols * 4 ); /* 16us SIFS, 20us preamble */
+	} else {
+		/* CCK encoding (802.11b) */
+		int phy_time = 144 + 48;	/* preamble + PLCP */
+		int bits = bytes << 3;
+		int data_time = ( bits * 1000 + kbps - 1 ) / kbps;
+
+		if ( dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE )
+			phy_time >>= 1;
+
+		return 10 + phy_time + data_time; /* 10us SIFS */
+	}
+}
+
+/**
+ * Add 802.11 link-layer header
+ *
+ * @v netdev		Wrapping network device
+ * @v iobuf		I/O buffer
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @v net_proto		Network-layer protocol, in network byte order
+ * @ret rc		Return status code
+ *
+ * This adds both the 802.11 frame header and the 802.2 LLC/SNAP
+ * header used on data packets.
+ *
+ * We also check here for state of the link that would make it invalid
+ * to send a data packet; every data packet must pass through here,
+ * and no non-data packet (e.g. management frame) should.
+ */
+static int net80211_ll_push ( struct net_device *netdev,
+			      struct io_buffer *iobuf, const void *ll_dest,
+			      const void *ll_source, uint16_t net_proto )
+{
+	struct net80211_device *dev = netdev->priv;
+	struct ieee80211_frame *hdr = iob_push ( iobuf,
+						 IEEE80211_LLC_HEADER_LEN +
+						 IEEE80211_TYP_FRAME_HEADER_LEN );
+	struct ieee80211_llc_snap_header *lhdr =
+		( void * ) hdr + IEEE80211_TYP_FRAME_HEADER_LEN;
+
+	/* We can't send data packets if we're not associated. */
+	if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
+		if ( dev->assoc_rc )
+			return dev->assoc_rc;
+		return -ENETUNREACH;
+	}
+
+	hdr->fc = IEEE80211_THIS_VERSION | IEEE80211_TYPE_DATA |
+	    IEEE80211_STYPE_DATA | IEEE80211_FC_TODS;
+
+	/* We don't send fragmented frames, so duration is the time
+	   for an SIFS + 10-byte ACK. */
+	hdr->duration = net80211_duration ( dev, 10, dev->rates[dev->rate] );
+
+	memcpy ( hdr->addr1, dev->bssid, ETH_ALEN );
+	memcpy ( hdr->addr2, ll_source, ETH_ALEN );
+	memcpy ( hdr->addr3, ll_dest, ETH_ALEN );
+
+	hdr->seq = IEEE80211_MAKESEQ ( ++dev->last_tx_seqnr, 0 );
+
+	lhdr->dsap = IEEE80211_LLC_DSAP;
+	lhdr->ssap = IEEE80211_LLC_SSAP;
+	lhdr->ctrl = IEEE80211_LLC_CTRL;
+	memset ( lhdr->oui, 0x00, 3 );
+	lhdr->ethertype = net_proto;
+
+	return 0;
+}
+
+/**
+ * Remove 802.11 link-layer header
+ *
+ * @v netdev		Wrapping network device
+ * @v iobuf		I/O buffer
+ * @ret ll_dest		Link-layer destination address
+ * @ret ll_source	Link-layer source
+ * @ret net_proto	Network-layer protocol, in network byte order
+ * @ret rc		Return status code
+ *
+ * This expects and removes both the 802.11 frame header and the 802.2
+ * LLC/SNAP header that are used on data packets.
+ */
+static int net80211_ll_pull ( struct net_device *netdev __unused,
+			      struct io_buffer *iobuf,
+			      const void **ll_dest, const void **ll_source,
+			      uint16_t * net_proto )
+{
+	struct ieee80211_frame *hdr = iobuf->data;
+	struct ieee80211_llc_snap_header *lhdr =
+		( void * ) hdr + IEEE80211_TYP_FRAME_HEADER_LEN;
+
+	/* Bunch of sanity checks */
+	if ( iob_len ( iobuf ) < IEEE80211_TYP_FRAME_HEADER_LEN +
+	     IEEE80211_LLC_HEADER_LEN ) {
+		DBGC ( netdev->priv, "802.11 %p packet too short (%zd bytes)\n",
+		       netdev->priv, iob_len ( iobuf ) );
+		return -EINVAL_PKT_TOO_SHORT;
+	}
+
+	if ( ( hdr->fc & IEEE80211_FC_VERSION ) != IEEE80211_THIS_VERSION ) {
+		DBGC ( netdev->priv, "802.11 %p packet invalid version %04x\n",
+		       netdev->priv, hdr->fc & IEEE80211_FC_VERSION );
+		return -EINVAL_PKT_VERSION;
+	}
+
+	if ( ( hdr->fc & IEEE80211_FC_TYPE ) != IEEE80211_TYPE_DATA ||
+	     ( hdr->fc & IEEE80211_FC_SUBTYPE ) != IEEE80211_STYPE_DATA ) {
+		DBGC ( netdev->priv, "802.11 %p packet not data/data (fc=%04x)\n",
+		       netdev->priv, hdr->fc );
+		return -EINVAL_PKT_NOT_DATA;
+	}
+
+	if ( ( hdr->fc & ( IEEE80211_FC_TODS | IEEE80211_FC_FROMDS ) ) !=
+	     IEEE80211_FC_FROMDS ) {
+		DBGC ( netdev->priv, "802.11 %p packet not from DS (fc=%04x)\n",
+		       netdev->priv, hdr->fc );
+		return -EINVAL_PKT_NOT_FROMDS;
+	}
+
+	if ( lhdr->dsap != IEEE80211_LLC_DSAP || lhdr->ssap != IEEE80211_LLC_SSAP ||
+	     lhdr->ctrl != IEEE80211_LLC_CTRL || lhdr->oui[0] || lhdr->oui[1] ||
+	     lhdr->oui[2] ) {
+		DBGC ( netdev->priv, "802.11 %p LLC header is not plain EtherType "
+		       "encapsulator: %02x->%02x [%02x] %02x:%02x:%02x %04x\n",
+		       netdev->priv, lhdr->dsap, lhdr->ssap, lhdr->ctrl,
+		       lhdr->oui[0], lhdr->oui[1], lhdr->oui[2], lhdr->ethertype );
+		return -EINVAL_PKT_LLC_HEADER;
+	}
+
+	iob_pull ( iobuf, sizeof ( *hdr ) + sizeof ( *lhdr ) );
+
+	*ll_dest = hdr->addr1;
+	*ll_source = hdr->addr3;
+	*net_proto = lhdr->ethertype;
+	return 0;
+}
+
+/** 802.11 link-layer protocol */
+static struct ll_protocol net80211_ll_protocol __ll_protocol = {
+	.name = "802.11",
+	.push = net80211_ll_push,
+	.pull = net80211_ll_pull,
+	.init_addr = eth_init_addr,
+	.ntoa = eth_ntoa,
+	.mc_hash = eth_mc_hash,
+	.eth_addr = eth_eth_addr,
+	.ll_proto = htons ( ARPHRD_ETHER ),	/* "encapsulated Ethernet" */
+	.hw_addr_len = ETH_ALEN,
+	.ll_addr_len = ETH_ALEN,
+	.ll_header_len = IEEE80211_TYP_FRAME_HEADER_LEN +
+				IEEE80211_LLC_HEADER_LEN,
+};
+
+
+/* ---------- 802.11 network management API ---------- */
+
+/**
+ * Get 802.11 device from wrapping network device
+ *
+ * @v netdev	Wrapping network device
+ * @ret dev	802.11 device wrapped by network device, or NULL
+ *
+ * Returns NULL if the network device does not wrap an 802.11 device.
+ */
+struct net80211_device * net80211_get ( struct net_device *netdev )
+{
+	struct net80211_device *dev;
+
+	list_for_each_entry ( dev, &net80211_devices, list ) {
+		if ( netdev->priv == dev )
+			return netdev->priv;
+	}
+
+	return NULL;
+}
+
+/**
+ * Set state of 802.11 device keeping management frames
+ *
+ * @v dev	802.11 device
+ * @v enable	Whether to keep management frames
+ * @ret oldenab	Whether management frames were enabled before this call
+ *
+ * If enable is TRUE, beacon, probe, and action frames will be kept
+ * and may be retrieved by calling net80211_mgmt_dequeue().
+ */
+int net80211_keep_mgmt ( struct net80211_device *dev, int enable )
+{
+	int oldenab = dev->keep_mgmt;
+
+	dev->keep_mgmt = enable;
+	return oldenab;
+}
+
+/**
+ * Get 802.11 management frame
+ *
+ * @v dev	802.11 device
+ * @ret signal	Signal strength of returned management frame
+ * @ret iob	I/O buffer, or NULL if no management frame is queued
+ *
+ * Frames will only be returned by this function if
+ * net80211_keep_mgmt() has been previously called with enable set to
+ * TRUE.
+ *
+ * The calling function takes ownership of the returned I/O buffer.
+ */
+struct io_buffer * net80211_mgmt_dequeue ( struct net80211_device *dev,
+					   int *signal )
+{
+	struct io_buffer *iobuf;
+	struct net80211_rx_info *rxi;
+
+	list_for_each_entry ( rxi, &dev->mgmt_info_queue, list ) {
+		list_del ( &rxi->list );
+		if ( signal )
+			*signal = rxi->signal;
+		free ( rxi );
+
+		assert ( ! list_empty ( &dev->mgmt_queue ) );
+		iobuf = list_first_entry ( &dev->mgmt_queue, struct io_buffer,
+					   list );
+		list_del ( &iobuf->list );
+		return iobuf;
+	}
+
+	return NULL;
+}
+
+/**
+ * Transmit 802.11 management frame
+ *
+ * @v dev	802.11 device
+ * @v fc	Frame Control flags for management frame
+ * @v dest	Destination access point
+ * @v iob	I/O buffer
+ * @ret rc	Return status code
+ *
+ * The @a fc argument must contain at least an IEEE 802.11 management
+ * subtype number (e.g. IEEE80211_STYPE_PROBE_REQ). If it contains
+ * IEEE80211_FC_PROTECTED, the frame will be encrypted prior to
+ * transmission.
+ *
+ * It is required that @a iob have at least 24 bytes of headroom
+ * reserved before its data start.
+ */
+int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc, u8 dest[6],
+		       struct io_buffer *iob )
+{
+	struct ieee80211_frame *hdr = iob_push ( iob,
+						 IEEE80211_TYP_FRAME_HEADER_LEN );
+
+	hdr->fc = IEEE80211_THIS_VERSION | IEEE80211_TYPE_MGMT |
+	    ( fc & ~IEEE80211_FC_PROTECTED );
+	hdr->duration = net80211_duration ( dev, 10, dev->rates[dev->rate] );
+	hdr->seq = IEEE80211_MAKESEQ ( ++dev->last_tx_seqnr, 0 );
+
+	memcpy ( hdr->addr1, dest, ETH_ALEN );	/* DA = RA */
+	memcpy ( hdr->addr2, dev->netdev->ll_addr, ETH_ALEN );	/* SA = TA */
+	memcpy ( hdr->addr3, dest, ETH_ALEN );	/* BSSID */
+
+	if ( fc & IEEE80211_FC_PROTECTED ) {
+		if ( ! dev->crypto )
+			return -EINVAL_CRYPTO_REQUEST;
+
+		struct io_buffer *eiob = dev->crypto->encrypt ( dev->crypto,
+								iob );
+		free_iob ( iob );
+		iob = eiob;
+	}
+
+	return netdev_tx ( dev->netdev, iob );
+}
+
+
+/* ---------- Driver API ---------- */
+
+/**
+ * Allocate 802.11 device
+ *
+ * @v priv_size		Size of driver-private allocation area
+ * @ret dev		Newly allocated 802.11 device
+ *
+ * This function allocates a net_device with space in its private area
+ * for both the net80211_device it will wrap and the driver-private
+ * data space requested. It initializes the link-layer-specific parts
+ * of the net_device, and links the net80211_device to the net_device
+ * appropriately.
+ */
+struct net80211_device * net80211_alloc ( size_t priv_size )
+{
+	struct net80211_device *dev;
+	struct net_device *netdev =
+		alloc_netdev ( sizeof ( *dev ) + priv_size );
+
+	if ( ! netdev )
+		return NULL;
+
+	netdev->ll_protocol = &net80211_ll_protocol;
+	netdev->ll_broadcast = net80211_ll_broadcast;
+	netdev->max_pkt_len = IEEE80211_MAX_DATA_LEN;
+	netdev_init ( netdev, &net80211_netdev_ops );
+
+	dev = netdev->priv;
+	dev->netdev = netdev;
+	dev->priv = ( u8 * ) dev + sizeof ( *dev );
+	dev->op = &net80211_null_ops;
+
+	process_init_stopped ( &dev->proc_assoc, net80211_step_associate,
+			       &netdev->refcnt );
+	INIT_LIST_HEAD ( &dev->mgmt_queue );
+	INIT_LIST_HEAD ( &dev->mgmt_info_queue );
+
+	return dev;
+}
+
+/**
+ * Register 802.11 device with network stack
+ *
+ * @v dev	802.11 device
+ * @v ops	802.11 device operations
+ * @v hw	802.11 hardware information
+ *
+ * This also registers the wrapping net_device with the higher network
+ * layers.
+ */
+int net80211_register ( struct net80211_device *dev,
+			struct net80211_device_operations *ops,
+			struct net80211_hw_info *hw )
+{
+	dev->op = ops;
+	dev->hw = malloc ( sizeof ( *hw ) );
+	if ( ! dev->hw )
+		return -ENOMEM;
+
+	memcpy ( dev->hw, hw, sizeof ( *hw ) );
+	memcpy ( dev->netdev->hw_addr, hw->hwaddr, ETH_ALEN );
+
+	/* Set some sensible channel defaults for driver's open() function */
+	memcpy ( dev->channels, dev->hw->channels,
+		 NET80211_MAX_CHANNELS * sizeof ( dev->channels[0] ) );
+	dev->channel = 0;
+
+	list_add_tail ( &dev->list, &net80211_devices );
+	return register_netdev ( dev->netdev );
+}
+
+/**
+ * Unregister 802.11 device from network stack
+ *
+ * @v dev	802.11 device
+ *
+ * After this call, the device operations are cleared so that they
+ * will not be called.
+ */
+void net80211_unregister ( struct net80211_device *dev )
+{
+	unregister_netdev ( dev->netdev );
+	list_del ( &dev->list );
+	dev->op = &net80211_null_ops;
+}
+
+/**
+ * Free 802.11 device
+ *
+ * @v dev	802.11 device
+ *
+ * The device should be unregistered before this function is called.
+ */
+void net80211_free ( struct net80211_device *dev )
+{
+	free ( dev->hw );
+	rc80211_free ( dev->rctl );
+	netdev_nullify ( dev->netdev );
+	netdev_put ( dev->netdev );
+}
+
+
+/* ---------- 802.11 network management workhorse code ---------- */
+
+/**
+ * Set state of 802.11 device
+ *
+ * @v dev	802.11 device
+ * @v clear	Bitmask of flags to clear
+ * @v set	Bitmask of flags to set
+ * @v status	Status or reason code for most recent operation
+ *
+ * If @a status represents a reason code, it should be OR'ed with
+ * NET80211_IS_REASON.
+ *
+ * Clearing authentication also clears association; clearing
+ * association also clears security handshaking state. Clearing
+ * association removes the link-up flag from the wrapping net_device,
+ * but setting it does not automatically set the flag; that is left to
+ * the judgment of higher-level code.
+ */
+static inline void net80211_set_state ( struct net80211_device *dev,
+					short clear, short set,
+					u16 status )
+{
+	/* The conditions in this function are deliberately formulated
+	   to be decidable at compile-time in most cases. Since clear
+	   and set are generally passed as constants, the body of this
+	   function can be reduced down to a few statements by the
+	   compiler. */
+
+	const int statmsk = NET80211_STATUS_MASK | NET80211_IS_REASON;
+
+	if ( clear & NET80211_PROBED )
+		clear |= NET80211_AUTHENTICATED;
+
+	if ( clear & NET80211_AUTHENTICATED )
+		clear |= NET80211_ASSOCIATED;
+
+	if ( clear & NET80211_ASSOCIATED )
+		clear |= NET80211_CRYPTO_SYNCED;
+
+	dev->state = ( dev->state & ~clear ) | set;
+	dev->state = ( dev->state & ~statmsk ) | ( status & statmsk );
+
+	if ( clear & NET80211_ASSOCIATED )
+		netdev_link_down ( dev->netdev );
+
+	if ( ( clear | set ) & NET80211_ASSOCIATED )
+		dev->op->config ( dev, NET80211_CFG_ASSOC );
+
+	if ( status != 0 ) {
+		if ( status & NET80211_IS_REASON )
+			dev->assoc_rc = -E80211_REASON ( status );
+		else
+			dev->assoc_rc = -E80211_STATUS ( status );
+		netdev_link_err ( dev->netdev, dev->assoc_rc );
+	}
+}
+
+/**
+ * Add channels to 802.11 device
+ *
+ * @v dev	802.11 device
+ * @v start	First channel number to add
+ * @v len	Number of channels to add
+ * @v txpower	TX power (dBm) to allow on added channels
+ *
+ * To replace the current list of channels instead of adding to it,
+ * set the nr_channels field of the 802.11 device to 0 before calling
+ * this function.
+ */
+static void net80211_add_channels ( struct net80211_device *dev, int start,
+				    int len, int txpower )
+{
+	int i, chan = start;
+
+	for ( i = dev->nr_channels; len-- && i < NET80211_MAX_CHANNELS; i++ ) {
+		dev->channels[i].channel_nr = chan;
+		dev->channels[i].maxpower = txpower;
+		dev->channels[i].hw_value = 0;
+
+		if ( chan >= 1 && chan <= 14 ) {
+			dev->channels[i].band = NET80211_BAND_2GHZ;
+			if ( chan == 14 )
+				dev->channels[i].center_freq = 2484;
+			else
+				dev->channels[i].center_freq = 2407 + 5 * chan;
+			chan++;
+		} else {
+			dev->channels[i].band = NET80211_BAND_5GHZ;
+			dev->channels[i].center_freq = 5000 + 5 * chan;
+			chan += 4;
+		}
+	}
+
+	dev->nr_channels = i;
+}
+
+/**
+ * Filter 802.11 device channels for hardware capabilities
+ *
+ * @v dev	802.11 device
+ *
+ * Hardware may support fewer channels than regulatory restrictions
+ * allow; this function filters out channels in dev->channels that are
+ * not supported by the hardware list in dev->hwinfo. It also copies
+ * over the net80211_channel::hw_value and limits maximum TX power
+ * appropriately.
+ *
+ * Channels are matched based on center frequency, ignoring band and
+ * channel number.
+ *
+ * If the driver specifies no supported channels, the effect will be
+ * as though all were supported.
+ */
+static void net80211_filter_hw_channels ( struct net80211_device *dev )
+{
+	int delta = 0, i = 0;
+	int old_freq = dev->channels[dev->channel].center_freq;
+	struct net80211_channel *chan, *hwchan;
+
+	if ( ! dev->hw->nr_channels )
+		return;
+
+	dev->channel = 0;
+	for ( chan = dev->channels; chan < dev->channels + dev->nr_channels;
+	      chan++, i++ ) {
+		int ok = 0;
+		for ( hwchan = dev->hw->channels;
+		      hwchan < dev->hw->channels + dev->hw->nr_channels;
+		      hwchan++ ) {
+			if ( hwchan->center_freq == chan->center_freq ) {
+				ok = 1;
+				break;
+			}
+		}
+
+		if ( ! ok )
+			delta++;
+		else {
+			chan->hw_value = hwchan->hw_value;
+			if ( hwchan->maxpower != 0 &&
+			     chan->maxpower > hwchan->maxpower )
+				chan->maxpower = hwchan->maxpower;
+			if ( old_freq == chan->center_freq )
+				dev->channel = i - delta;
+			if ( delta )
+				chan[-delta] = *chan;
+		}
+	}
+
+	dev->nr_channels -= delta;
+
+	if ( dev->channels[dev->channel].center_freq != old_freq )
+		dev->op->config ( dev, NET80211_CFG_CHANNEL );
+}
+
+/**
+ * Update 802.11 device state to reflect received capabilities field
+ *
+ * @v dev	802.11 device
+ * @v capab	Capabilities field in beacon, probe, or association frame
+ * @ret rc	Return status code
+ */
+static int net80211_process_capab ( struct net80211_device *dev,
+				    u16 capab )
+{
+	u16 old_phy = dev->phy_flags;
+
+	if ( ( capab & ( IEEE80211_CAPAB_MANAGED | IEEE80211_CAPAB_ADHOC ) ) !=
+	     IEEE80211_CAPAB_MANAGED ) {
+		DBGC ( dev, "802.11 %p cannot handle IBSS network\n", dev );
+		return -ENOSYS;
+	}
+
+	dev->phy_flags &= ~( NET80211_PHY_USE_SHORT_PREAMBLE |
+			     NET80211_PHY_USE_SHORT_SLOT );
+
+	if ( capab & IEEE80211_CAPAB_SHORT_PMBL )
+		dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
+
+	if ( capab & IEEE80211_CAPAB_SHORT_SLOT )
+		dev->phy_flags |= NET80211_PHY_USE_SHORT_SLOT;
+
+	if ( old_phy != dev->phy_flags )
+		dev->op->config ( dev, NET80211_CFG_PHY_PARAMS );
+
+	return 0;
+}
+
+/**
+ * Update 802.11 device state to reflect received information elements
+ *
+ * @v dev	802.11 device
+ * @v ie	Pointer to first information element
+ * @v ie_end	Pointer to tail of packet I/O buffer
+ * @ret rc	Return status code
+ */
+static int net80211_process_ie ( struct net80211_device *dev,
+				 union ieee80211_ie *ie, void *ie_end )
+{
+	u16 old_rate = dev->rates[dev->rate];
+	u16 old_phy = dev->phy_flags;
+	int have_rates = 0, i;
+	int ds_channel = 0;
+	int changed = 0;
+	int band = dev->channels[dev->channel].band;
+
+	if ( ! ieee80211_ie_bound ( ie, ie_end ) )
+		return 0;
+
+	for ( ; ie; ie = ieee80211_next_ie ( ie, ie_end ) ) {
+		switch ( ie->id ) {
+		case IEEE80211_IE_SSID:
+			if ( ie->len <= 32 ) {
+				memcpy ( dev->essid, ie->ssid, ie->len );
+				dev->essid[ie->len] = 0;
+			}
+			break;
+
+		case IEEE80211_IE_RATES:
+		case IEEE80211_IE_EXT_RATES:
+			if ( ! have_rates ) {
+				dev->nr_rates = 0;
+				dev->basic_rates = 0;
+				have_rates = 1;
+			}
+			for ( i = 0; i < ie->len &&
+			      dev->nr_rates < NET80211_MAX_RATES; i++ ) {
+				u8 rid = ie->rates[i];
+				u16 rate = ( rid & 0x7f ) * 5;
+
+				if ( rid & 0x80 )
+					dev->basic_rates |=
+						( 1 << dev->nr_rates );
+
+				dev->rates[dev->nr_rates++] = rate;
+			}
+
+			break;
+
+		case IEEE80211_IE_DS_PARAM:
+			if ( dev->channel < dev->nr_channels && ds_channel ==
+			     dev->channels[dev->channel].channel_nr )
+				break;
+			ds_channel = ie->ds_param.current_channel;
+			net80211_change_channel ( dev, ds_channel );
+			break;
+
+		case IEEE80211_IE_COUNTRY:
+			dev->nr_channels = 0;
+
+			DBGC ( dev, "802.11 %p setting country regulations "
+			       "for %c%c\n", dev, ie->country.name[0],
+			       ie->country.name[1] );
+			for ( i = 0; i < ( ie->len - 3 ) / 3; i++ ) {
+				union ieee80211_ie_country_triplet *t =
+					&ie->country.triplet[i];
+				if ( t->first > 200 ) {
+					DBGC ( dev, "802.11 %p ignoring regulatory "
+					       "extension information\n", dev );
+				} else {
+					net80211_add_channels ( dev,
+							t->band.first_channel,
+							t->band.nr_channels,
+							t->band.max_txpower );
+				}
+			}
+			net80211_filter_hw_channels ( dev );
+			break;
+
+		case IEEE80211_IE_ERP_INFO:
+			dev->phy_flags &= ~( NET80211_PHY_USE_PROTECTION |
+					     NET80211_PHY_USE_SHORT_PREAMBLE );
+			if ( ie->erp_info & IEEE80211_ERP_USE_PROTECTION )
+				dev->phy_flags |= NET80211_PHY_USE_PROTECTION;
+			if ( ! ( ie->erp_info & IEEE80211_ERP_BARKER_LONG ) )
+				dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
+			break;
+		}
+	}
+
+	if ( have_rates ) {
+		/* Allow only those rates that are also supported by
+		   the hardware. */
+		int delta = 0, j;
+
+		dev->rate = 0;
+		for ( i = 0; i < dev->nr_rates; i++ ) {
+			int ok = 0;
+			for ( j = 0; j < dev->hw->nr_rates[band]; j++ ) {
+				if ( dev->hw->rates[band][j] == dev->rates[i] ){
+					ok = 1;
+					break;
+				}
+			}
+
+			if ( ! ok )
+				delta++;
+			else {
+				dev->rates[i - delta] = dev->rates[i];
+				if ( old_rate == dev->rates[i] )
+					dev->rate = i - delta;
+			}
+		}
+
+		dev->nr_rates -= delta;
+
+		/* Sort available rates - sorted subclumps tend to already
+		   exist, so insertion sort works well. */
+		for ( i = 1; i < dev->nr_rates; i++ ) {
+			u16 rate = dev->rates[i];
+			u32 tmp, br, mask;
+
+			for ( j = i - 1; j >= 0 && dev->rates[j] >= rate; j-- )
+				dev->rates[j + 1] = dev->rates[j];
+			dev->rates[j + 1] = rate;
+
+			/* Adjust basic_rates to match by rotating the
+			   bits from bit j+1 to bit i left one position. */
+			mask = ( ( 1 << i ) - 1 ) & ~( ( 1 << ( j + 1 ) ) - 1 );
+			br = dev->basic_rates;
+			tmp = br & ( 1 << i );
+			br = ( br & ~( mask | tmp ) ) | ( ( br & mask ) << 1 );
+			br |= ( tmp >> ( i - j - 1 ) );
+			dev->basic_rates = br;
+		}
+
+		net80211_set_rtscts_rate ( dev );
+
+		if ( dev->rates[dev->rate] != old_rate )
+			changed |= NET80211_CFG_RATE;
+	}
+
+	if ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE )
+		dev->phy_flags &= ~NET80211_PHY_USE_SHORT_PREAMBLE;
+	if ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT )
+		dev->phy_flags &= ~NET80211_PHY_USE_SHORT_SLOT;
+
+	if ( old_phy != dev->phy_flags )
+		changed |= NET80211_CFG_PHY_PARAMS;
+
+	if ( changed )
+		dev->op->config ( dev, changed );
+
+	return 0;
+}
+
+/**
+ * Create information elements for outgoing probe or association packet
+ *
+ * @v dev		802.11 device
+ * @v ie		Pointer to start of information element area
+ * @ret next_ie		Pointer to first byte after added information elements
+ */
+static union ieee80211_ie *
+net80211_marshal_request_info ( struct net80211_device *dev,
+				union ieee80211_ie *ie )
+{
+	int i;
+
+	ie->id = IEEE80211_IE_SSID;
+	ie->len = strlen ( dev->essid );
+	memcpy ( ie->ssid, dev->essid, ie->len );
+
+	ie = ieee80211_next_ie ( ie, NULL );
+
+	ie->id = IEEE80211_IE_RATES;
+	ie->len = dev->nr_rates;
+	if ( ie->len > 8 )
+		ie->len = 8;
+
+	for ( i = 0; i < ie->len; i++ ) {
+		ie->rates[i] = dev->rates[i] / 5;
+		if ( dev->basic_rates & ( 1 << i ) )
+			ie->rates[i] |= 0x80;
+	}
+
+	ie = ieee80211_next_ie ( ie, NULL );
+
+	if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_RSN ) {
+		memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
+		ie = ieee80211_next_ie ( ie, NULL );
+	}
+
+	if ( dev->nr_rates > 8 ) {
+		/* 802.11 requires we use an Extended Basic Rates IE
+		   for the rates beyond the eighth. */
+
+		ie->id = IEEE80211_IE_EXT_RATES;
+		ie->len = dev->nr_rates - 8;
+
+		for ( ; i < dev->nr_rates; i++ ) {
+			ie->rates[i - 8] = dev->rates[i] / 5;
+			if ( dev->basic_rates & ( 1 << i ) )
+				ie->rates[i - 8] |= 0x80;
+		}
+
+		ie = ieee80211_next_ie ( ie, NULL );
+	}
+
+	if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_VENDOR ) {
+		memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
+		ie = ieee80211_next_ie ( ie, NULL );
+	}
+
+	return ie;
+}
+
+/** Seconds to wait after finding a network, to possibly find better APs for it
+ *
+ * This is used when a specific SSID to scan for is specified.
+ */
+#define NET80211_PROBE_GATHER    1
+
+/** Seconds to wait after finding a network, to possibly find other networks
+ *
+ * This is used when an empty SSID is specified, to scan for all
+ * networks.
+ */
+#define NET80211_PROBE_GATHER_ALL 2
+
+/** Seconds to allow a probe to take if no network has been found */
+#define NET80211_PROBE_TIMEOUT   6
+
+/**
+ * Begin probe of 802.11 networks
+ *
+ * @v dev	802.11 device
+ * @v essid	SSID to probe for, or "" to accept any (may not be NULL)
+ * @v active	Whether to use active scanning
+ * @ret ctx	Probe context
+ *
+ * Active scanning may only be used on channels 1-11 in the 2.4GHz
+ * band, due to iPXE's lack of a complete regulatory database. If
+ * active scanning is used, probe packets will be sent on each
+ * channel; this can allow association with hidden-SSID networks if
+ * the SSID is properly specified.
+ *
+ * A @c NULL return indicates an out-of-memory condition.
+ *
+ * The returned context must be periodically passed to
+ * net80211_probe_step() until that function returns zero.
+ */
+struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
+						   const char *essid,
+						   int active )
+{
+	struct net80211_probe_ctx *ctx = zalloc ( sizeof ( *ctx ) );
+
+	if ( ! ctx )
+		return NULL;
+
+	assert ( netdev_is_open ( dev->netdev ) );
+
+	ctx->dev = dev;
+	ctx->old_keep_mgmt = net80211_keep_mgmt ( dev, 1 );
+	ctx->essid = essid;
+	if ( dev->essid != ctx->essid )
+		strcpy ( dev->essid, ctx->essid );
+
+	if ( active ) {
+		struct ieee80211_probe_req *probe_req;
+		union ieee80211_ie *ie;
+
+		ctx->probe = alloc_iob ( 128 );
+		iob_reserve ( ctx->probe, IEEE80211_TYP_FRAME_HEADER_LEN );
+		probe_req = ctx->probe->data;
+
+		ie = net80211_marshal_request_info ( dev,
+						     probe_req->info_element );
+
+		iob_put ( ctx->probe, ( void * ) ie - ctx->probe->data );
+	}
+
+	ctx->ticks_start = currticks();
+	ctx->ticks_beacon = 0;
+	ctx->ticks_channel = currticks();
+	ctx->hop_time = ticks_per_sec() / ( active ? 2 : 6 );
+
+	/*
+	 * Channels on 2.4GHz overlap, and the most commonly used
+	 * are 1, 6, and 11. We'll get a result faster if we check
+	 * every 5 channels, but in order to hit all of them the
+	 * number of channels must be relatively prime to 5. If it's
+	 * not, tweak the hop.
+	 */
+	ctx->hop_step = 5;
+	while ( dev->nr_channels % ctx->hop_step == 0 && ctx->hop_step > 1 )
+		ctx->hop_step--;
+
+	ctx->beacons = malloc ( sizeof ( *ctx->beacons ) );
+	INIT_LIST_HEAD ( ctx->beacons );
+
+	dev->channel = 0;
+	dev->op->config ( dev, NET80211_CFG_CHANNEL );
+
+	return ctx;
+}
+
+/**
+ * Continue probe of 802.11 networks
+ *
+ * @v ctx	Probe context returned by net80211_probe_start()
+ * @ret rc	Probe status
+ *
+ * The return code will be 0 if the probe is still going on (and this
+ * function should be called again), a positive number if the probe
+ * completed successfully, or a negative error code if the probe
+ * failed for that reason.
+ *
+ * Whether the probe succeeded or failed, you must call
+ * net80211_probe_finish_all() or net80211_probe_finish_best()
+ * (depending on whether you want information on all networks or just
+ * the best-signal one) in order to release the probe context. A
+ * failed probe may still have acquired some valid data.
+ */
+int net80211_probe_step ( struct net80211_probe_ctx *ctx )
+{
+	struct net80211_device *dev = ctx->dev;
+	u32 start_timeout = NET80211_PROBE_TIMEOUT * ticks_per_sec();
+	u32 gather_timeout = ticks_per_sec();
+	u32 now = currticks();
+	struct io_buffer *iob;
+	int signal;
+	int rc;
+	char ssid[IEEE80211_MAX_SSID_LEN + 1];
+
+	gather_timeout *= ( ctx->essid[0] ? NET80211_PROBE_GATHER :
+			    NET80211_PROBE_GATHER_ALL );
+
+	/* Time out if necessary */
+	if ( now >= ctx->ticks_start + start_timeout )
+		return list_empty ( ctx->beacons ) ? -ETIMEDOUT : +1;
+
+	if ( ctx->ticks_beacon > 0 && now >= ctx->ticks_start + gather_timeout )
+		return +1;
+
+	/* Change channels if necessary */
+	if ( now >= ctx->ticks_channel + ctx->hop_time ) {
+		dev->channel = ( dev->channel + ctx->hop_step )
+			% dev->nr_channels;
+		dev->op->config ( dev, NET80211_CFG_CHANNEL );
+		udelay ( dev->hw->channel_change_time );
+
+		ctx->ticks_channel = now;
+
+		if ( ctx->probe ) {
+			struct io_buffer *siob = ctx->probe; /* to send */
+
+			/* make a copy for future use */
+			iob = alloc_iob ( siob->tail - siob->head );
+			iob_reserve ( iob, iob_headroom ( siob ) );
+			memcpy ( iob_put ( iob, iob_len ( siob ) ),
+				 siob->data, iob_len ( siob ) );
+
+			ctx->probe = iob;
+			rc = net80211_tx_mgmt ( dev, IEEE80211_STYPE_PROBE_REQ,
+						net80211_ll_broadcast,
+						iob_disown ( siob ) );
+			if ( rc ) {
+				DBGC ( dev, "802.11 %p send probe failed: "
+				       "%s\n", dev, strerror ( rc ) );
+				return rc;
+			}
+		}
+	}
+
+	/* Check for new management packets */
+	while ( ( iob = net80211_mgmt_dequeue ( dev, &signal ) ) != NULL ) {
+		struct ieee80211_frame *hdr;
+		struct ieee80211_beacon *beacon;
+		union ieee80211_ie *ie;
+		struct net80211_wlan *wlan;
+		u16 type;
+
+		hdr = iob->data;
+		type = hdr->fc & IEEE80211_FC_SUBTYPE;
+		beacon = ( struct ieee80211_beacon * ) hdr->data;
+
+		if ( type != IEEE80211_STYPE_BEACON &&
+		     type != IEEE80211_STYPE_PROBE_RESP ) {
+			DBGC2 ( dev, "802.11 %p probe: non-beacon\n", dev );
+			goto drop;
+		}
+
+		if ( ( void * ) beacon->info_element >= iob->tail ) {
+			DBGC ( dev, "802.11 %p probe: beacon with no IEs\n",
+			       dev );
+			goto drop;
+		}
+
+		ie = beacon->info_element;
+
+		if ( ! ieee80211_ie_bound ( ie, iob->tail ) )
+			ie = NULL;
+
+		while ( ie && ie->id != IEEE80211_IE_SSID )
+			ie = ieee80211_next_ie ( ie, iob->tail );
+
+		if ( ! ie ) {
+			DBGC ( dev, "802.11 %p probe: beacon with no SSID\n",
+			       dev );
+			goto drop;
+		}
+
+		memcpy ( ssid, ie->ssid, ie->len );
+		ssid[ie->len] = 0;
+
+		if ( ctx->essid[0] && strcmp ( ctx->essid, ssid ) != 0 ) {
+			DBGC2 ( dev, "802.11 %p probe: beacon with wrong SSID "
+				"(%s)\n", dev, ssid );
+			goto drop;
+		}
+
+		/* See if we've got an entry for this network */
+		list_for_each_entry ( wlan, ctx->beacons, list ) {
+			if ( strcmp ( wlan->essid, ssid ) != 0 )
+				continue;
+
+			if ( signal < wlan->signal ) {
+				DBGC2 ( dev, "802.11 %p probe: beacon for %s "
+					"(%s) with weaker signal %d\n", dev,
+					ssid, eth_ntoa ( hdr->addr3 ), signal );
+				goto drop;
+			}
+
+			goto fill;
+		}
+
+		/* No entry yet - make one */
+		wlan = zalloc ( sizeof ( *wlan ) );
+		strcpy ( wlan->essid, ssid );
+		list_add_tail ( &wlan->list, ctx->beacons );
+
+		/* Whether we're using an old entry or a new one, fill
+		   it with new data. */
+	fill:
+		memcpy ( wlan->bssid, hdr->addr3, ETH_ALEN );
+		wlan->signal = signal;
+		wlan->channel = dev->channels[dev->channel].channel_nr;
+
+		/* Copy this I/O buffer into a new wlan->beacon; the
+		 * iob we've got probably came from the device driver
+		 * and may have the full 2.4k allocation, which we
+		 * don't want to keep around wasting memory.
+		 */
+		free_iob ( wlan->beacon );
+		wlan->beacon = alloc_iob ( iob_len ( iob ) );
+		memcpy ( iob_put ( wlan->beacon, iob_len ( iob ) ),
+			 iob->data, iob_len ( iob ) );
+
+		if ( ( rc = sec80211_detect ( wlan->beacon, &wlan->handshaking,
+					      &wlan->crypto ) ) == -ENOTSUP ) {
+			struct ieee80211_beacon *beacon =
+				( struct ieee80211_beacon * ) hdr->data;
+
+			if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) {
+				DBG ( "802.11 %p probe: secured network %s but "
+				      "encryption support not compiled in\n",
+				      dev, wlan->essid );
+				wlan->handshaking = NET80211_SECPROT_UNKNOWN;
+				wlan->crypto = NET80211_CRYPT_UNKNOWN;
+			} else {
+				wlan->handshaking = NET80211_SECPROT_NONE;
+				wlan->crypto = NET80211_CRYPT_NONE;
+			}
+		} else if ( rc != 0 ) {
+			DBGC ( dev, "802.11 %p probe warning: network "
+			       "%s with unidentifiable security "
+			       "settings: %s\n", dev, wlan->essid,
+			       strerror ( rc ) );
+		}
+
+		ctx->ticks_beacon = now;
+
+		DBGC2 ( dev, "802.11 %p probe: good beacon for %s (%s)\n",
+			dev, wlan->essid, eth_ntoa ( wlan->bssid ) );
+
+	drop:
+		free_iob ( iob );
+	}
+
+	return 0;
+}
+
+
+/**
+ * Finish probe of 802.11 networks, returning best-signal network found
+ *
+ * @v ctx	Probe context
+ * @ret wlan	Best-signal network found, or @c NULL if none were found
+ *
+ * If net80211_probe_start() was called with a particular SSID
+ * parameter as filter, only a network with that SSID (matching
+ * case-sensitively) can be returned from this function.
+ */
+struct net80211_wlan *
+net80211_probe_finish_best ( struct net80211_probe_ctx *ctx )
+{
+	struct net80211_wlan *best = NULL, *wlan;
+
+	if ( ! ctx )
+		return NULL;
+
+	list_for_each_entry ( wlan, ctx->beacons, list ) {
+		if ( ! best || best->signal < wlan->signal )
+			best = wlan;
+	}
+
+	if ( best )
+		list_del ( &best->list );
+	else
+		DBGC ( ctx->dev, "802.11 %p probe: found nothing for '%s'\n",
+		       ctx->dev, ctx->essid );
+
+	net80211_free_wlanlist ( ctx->beacons );
+
+	net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );
+
+	if ( ctx->probe )
+		free_iob ( ctx->probe );
+
+	free ( ctx );
+
+	return best;
+}
+
+
+/**
+ * Finish probe of 802.11 networks, returning all networks found
+ *
+ * @v ctx	Probe context
+ * @ret list	List of net80211_wlan detailing networks found
+ *
+ * If net80211_probe_start() was called with a particular SSID
+ * parameter as filter, this will always return either an empty or a
+ * one-element list.
+ */
+struct list_head *net80211_probe_finish_all ( struct net80211_probe_ctx *ctx )
+{
+	struct list_head *beacons = ctx->beacons;
+
+	if ( ! ctx )
+		return NULL;
+
+	net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );
+
+	if ( ctx->probe )
+		free_iob ( ctx->probe );
+
+	free ( ctx );
+
+	return beacons;
+}
+
+
+/**
+ * Free WLAN structure
+ *
+ * @v wlan	WLAN structure to free
+ */
+void net80211_free_wlan ( struct net80211_wlan *wlan )
+{
+	if ( wlan ) {
+		free_iob ( wlan->beacon );
+		free ( wlan );
+	}
+}
+
+
+/**
+ * Free list of WLAN structures
+ *
+ * @v list	List of WLAN structures to free
+ */
+void net80211_free_wlanlist ( struct list_head *list )
+{
+	struct net80211_wlan *wlan, *tmp;
+
+	if ( ! list )
+		return;
+
+	list_for_each_entry_safe ( wlan, tmp, list, list ) {
+		list_del ( &wlan->list );
+		net80211_free_wlan ( wlan );
+	}
+
+	free ( list );
+}
+
+
+/** Number of ticks to wait for replies to association management frames */
+#define ASSOC_TIMEOUT	TICKS_PER_SEC
+
+/** Number of times to try sending a particular association management frame */
+#define ASSOC_RETRIES	2
+
+/**
+ * Step 802.11 association process
+ *
+ * @v proc	Association process
+ */
+static void net80211_step_associate ( struct process *proc )
+{
+	struct net80211_device *dev =
+	    container_of ( proc, struct net80211_device, proc_assoc );
+	int rc = 0;
+	int status = dev->state & NET80211_STATUS_MASK;
+
+	/*
+	 * We use a sort of state machine implemented using bits in
+	 * the dev->state variable. At each call, we take the
+	 * logically first step that has not yet succeeded; either it
+	 * has not been tried yet, it's being retried, or it failed.
+	 * If it failed, we return an error indication; otherwise we
+	 * perform the step. If it succeeds, RX handling code will set
+	 * the appropriate status bit for us.
+	 *
+	 * Probe works a bit differently, since we have to step it
+	 * on every call instead of waiting for a packet to arrive
+	 * that will set the completion bit for us.
+	 */
+
+	/* If we're waiting for a reply, check for timeout condition */
+	if ( dev->state & NET80211_WAITING ) {
+		/* Sanity check */
+		if ( ! dev->associating )
+			return;
+
+		if ( currticks() - dev->ctx.assoc->last_packet > ASSOC_TIMEOUT ) {
+			/* Timed out - fail if too many retries, or retry */
+			dev->ctx.assoc->times_tried++;
+			if ( ++dev->ctx.assoc->times_tried > ASSOC_RETRIES ) {
+				rc = -ETIMEDOUT;
+				goto fail;
+			}
+		} else {
+			/* Didn't time out - let it keep going */
+			return;
+		}
+	} else {
+		if ( dev->state & NET80211_PROBED )
+			dev->ctx.assoc->times_tried = 0;
+	}
+
+	if ( ! ( dev->state & NET80211_PROBED ) ) {
+		/* state: probe */
+
+		if ( ! dev->ctx.probe ) {
+			/* start probe */
+			int active = fetch_intz_setting ( NULL,
+						&net80211_active_setting );
+			int band = dev->hw->bands;
+
+			if ( active )
+				band &= ~NET80211_BAND_BIT_5GHZ;
+
+			rc = net80211_prepare_probe ( dev, band, active );
+			if ( rc )
+				goto fail;
+
+			dev->ctx.probe = net80211_probe_start ( dev, dev->essid,
+								active );
+			if ( ! dev->ctx.probe ) {
+				dev->assoc_rc = -ENOMEM;
+				goto fail;
+			}
+		}
+
+		rc = net80211_probe_step ( dev->ctx.probe );
+		if ( ! rc ) {
+			return;	/* still going */
+		}
+
+		dev->associating = net80211_probe_finish_best ( dev->ctx.probe );
+		dev->ctx.probe = NULL;
+		if ( ! dev->associating ) {
+			if ( rc > 0 ) /* "successful" probe found nothing */
+				rc = -ETIMEDOUT;
+			goto fail;
+		}
+
+		/* If we probed using a broadcast SSID, record that
+		   fact for the settings applicator before we clobber
+		   it with the specific SSID we've chosen. */
+		if ( ! dev->essid[0] )
+			dev->state |= NET80211_AUTO_SSID;
+
+		DBGC ( dev, "802.11 %p found network %s (%s)\n", dev,
+		       dev->associating->essid,
+		       eth_ntoa ( dev->associating->bssid ) );
+
+		dev->ctx.assoc = zalloc ( sizeof ( *dev->ctx.assoc ) );
+		if ( ! dev->ctx.assoc ) {
+			rc = -ENOMEM;
+			goto fail;
+		}
+
+		dev->state |= NET80211_PROBED;
+		dev->ctx.assoc->method = IEEE80211_AUTH_OPEN_SYSTEM;
+
+		return;
+	}
+
+	/* Record time of sending the packet we're about to send, for timeout */
+	dev->ctx.assoc->last_packet = currticks();
+
+	if ( ! ( dev->state & NET80211_AUTHENTICATED ) ) {
+		/* state: prepare and authenticate */
+
+		if ( status != IEEE80211_STATUS_SUCCESS ) {
+			/* we tried authenticating already, but failed */
+			int method = dev->ctx.assoc->method;
+
+			if ( method == IEEE80211_AUTH_OPEN_SYSTEM &&
+			     ( status == IEEE80211_STATUS_AUTH_CHALL_INVALID ||
+			       status == IEEE80211_STATUS_AUTH_ALGO_UNSUPP ) ) {
+				/* Maybe this network uses Shared Key? */
+				dev->ctx.assoc->method =
+					IEEE80211_AUTH_SHARED_KEY;
+			} else {
+				goto fail;
+			}
+		}
+
+		DBGC ( dev, "802.11 %p authenticating with method %d\n", dev,
+		       dev->ctx.assoc->method );
+
+		rc = net80211_prepare_assoc ( dev, dev->associating );
+		if ( rc )
+			goto fail;
+
+		rc = net80211_send_auth ( dev, dev->associating,
+					  dev->ctx.assoc->method );
+		if ( rc )
+			goto fail;
+
+		return;
+	}
+
+	if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
+		/* state: associate */
+
+		if ( status != IEEE80211_STATUS_SUCCESS )
+			goto fail;
+
+		DBGC ( dev, "802.11 %p associating\n", dev );
+
+		if ( dev->handshaker && dev->handshaker->start &&
+		     ! dev->handshaker->started ) {
+			rc = dev->handshaker->start ( dev );
+			if ( rc < 0 )
+				goto fail;
+			dev->handshaker->started = 1;
+		}
+
+		rc = net80211_send_assoc ( dev, dev->associating );
+		if ( rc )
+			goto fail;
+
+		return;
+	}
+
+	if ( ! ( dev->state & NET80211_CRYPTO_SYNCED ) ) {
+		/* state: crypto sync */
+		DBGC ( dev, "802.11 %p security handshaking\n", dev );
+
+		if ( ! dev->handshaker || ! dev->handshaker->step ) {
+			dev->state |= NET80211_CRYPTO_SYNCED;
+			return;
+		}
+
+		rc = dev->handshaker->step ( dev );
+
+		if ( rc < 0 ) {
+			/* Only record the returned error if we're
+			   still marked as associated, because an
+			   asynchronous error will have already been
+			   reported to net80211_deauthenticate() and
+			   assoc_rc thereby set. */
+			if ( dev->state & NET80211_ASSOCIATED )
+				dev->assoc_rc = rc;
+			rc = 0;
+			goto fail;
+		}
+
+		if ( rc > 0 ) {
+			dev->assoc_rc = 0;
+			dev->state |= NET80211_CRYPTO_SYNCED;
+		}
+		return;
+	}
+
+	/* state: done! */
+	netdev_link_up ( dev->netdev );
+	dev->assoc_rc = 0;
+	dev->state &= ~NET80211_WORKING;
+
+	free ( dev->ctx.assoc );
+	dev->ctx.assoc = NULL;
+
+	net80211_free_wlan ( dev->associating );
+	dev->associating = NULL;
+
+	dev->rctl = rc80211_init ( dev );
+
+	process_del ( proc );
+
+	DBGC ( dev, "802.11 %p associated with %s (%s)\n", dev,
+	       dev->essid, eth_ntoa ( dev->bssid ) );
+
+	return;
+
+ fail:
+	dev->state &= ~( NET80211_WORKING | NET80211_WAITING );
+	if ( rc )
+		dev->assoc_rc = rc;
+
+	netdev_link_err ( dev->netdev, dev->assoc_rc );
+
+	/* We never reach here from the middle of a probe, so we don't
+	   need to worry about freeing dev->ctx.probe. */
+
+	if ( dev->state & NET80211_PROBED ) {
+		free ( dev->ctx.assoc );
+		dev->ctx.assoc = NULL;
+	}
+
+	net80211_free_wlan ( dev->associating );
+	dev->associating = NULL;
+
+	process_del ( proc );
+
+	DBGC ( dev, "802.11 %p association failed (state=%04x): "
+	       "%s\n", dev, dev->state, strerror ( dev->assoc_rc ) );
+
+	/* Try it again: */
+	net80211_autoassociate ( dev );
+}
+
+/**
+ * Check for 802.11 SSID or key updates
+ *
+ * This acts as a settings applicator; if the user changes netX/ssid,
+ * and netX is currently open, the association task will be invoked
+ * again. If the user changes the encryption key, the current security
+ * handshaker will be asked to update its state to match; if that is
+ * impossible without reassociation, we reassociate.
+ */
+static int net80211_check_settings_update ( void )
+{
+	struct net80211_device *dev;
+	char ssid[IEEE80211_MAX_SSID_LEN + 1];
+	int key_reassoc;
+
+	list_for_each_entry ( dev, &net80211_devices, list ) {
+		if ( ! netdev_is_open ( dev->netdev ) )
+			continue;
+
+		key_reassoc = 0;
+		if ( dev->handshaker && dev->handshaker->change_key &&
+		     dev->handshaker->change_key ( dev ) < 0 )
+			key_reassoc = 1;
+
+		fetch_string_setting ( netdev_settings ( dev->netdev ),
+				       &net80211_ssid_setting, ssid,
+				       IEEE80211_MAX_SSID_LEN + 1 );
+
+		if ( key_reassoc ||
+		     ( ! ( ! ssid[0] && ( dev->state & NET80211_AUTO_SSID ) ) &&
+		       strcmp ( ssid, dev->essid ) != 0 ) ) {
+			DBGC ( dev, "802.11 %p updating association: "
+			       "%s -> %s\n", dev, dev->essid, ssid );
+			net80211_autoassociate ( dev );
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Start 802.11 association process
+ *
+ * @v dev	802.11 device
+ *
+ * If the association process is running, it will be restarted.
+ */
+void net80211_autoassociate ( struct net80211_device *dev )
+{
+	if ( ! ( dev->state & NET80211_WORKING ) ) {
+		DBGC2 ( dev, "802.11 %p spawning association process\n", dev );
+		process_add ( &dev->proc_assoc );
+	} else {
+		DBGC2 ( dev, "802.11 %p restarting association\n", dev );
+	}
+
+	/* Clean up everything an earlier association process might
+	   have been in the middle of using */
+	if ( dev->associating )
+		net80211_free_wlan ( dev->associating );
+
+	if ( ! ( dev->state & NET80211_PROBED ) )
+		net80211_free_wlan (
+			net80211_probe_finish_best ( dev->ctx.probe ) );
+	else
+		free ( dev->ctx.assoc );
+
+	/* Reset to a clean state */
+	fetch_string_setting ( netdev_settings ( dev->netdev ),
+			       &net80211_ssid_setting, dev->essid,
+			       IEEE80211_MAX_SSID_LEN + 1 );
+	dev->ctx.probe = NULL;
+	dev->associating = NULL;
+	dev->assoc_rc = 0;
+	net80211_set_state ( dev, NET80211_PROBED, NET80211_WORKING, 0 );
+}
+
+/**
+ * Pick TX rate for RTS/CTS packets based on data rate
+ *
+ * @v dev	802.11 device
+ *
+ * The RTS/CTS rate is the fastest TX rate marked as "basic" that is
+ * not faster than the data rate.
+ */
+static void net80211_set_rtscts_rate ( struct net80211_device *dev )
+{
+	u16 datarate = dev->rates[dev->rate];
+	u16 rtsrate = 0;
+	int rts_idx = -1;
+	int i;
+
+	for ( i = 0; i < dev->nr_rates; i++ ) {
+		u16 rate = dev->rates[i];
+
+		if ( ! ( dev->basic_rates & ( 1 << i ) ) || rate > datarate )
+			continue;
+
+		if ( rate > rtsrate ) {
+			rtsrate = rate;
+			rts_idx = i;
+		}
+	}
+
+	/* If this is in initialization, we might not have any basic
+	   rates; just use the first data rate in that case. */
+	if ( rts_idx < 0 )
+		rts_idx = 0;
+
+	dev->rtscts_rate = rts_idx;
+}
+
+/**
+ * Set data transmission rate for 802.11 device
+ *
+ * @v dev	802.11 device
+ * @v rate	Rate to set, as index into @c dev->rates array
+ */
+void net80211_set_rate_idx ( struct net80211_device *dev, int rate )
+{
+	assert ( netdev_is_open ( dev->netdev ) );
+
+	if ( rate >= 0 && rate < dev->nr_rates && rate != dev->rate ) {
+		DBGC2 ( dev, "802.11 %p changing rate from %d->%d Mbps\n",
+			dev, dev->rates[dev->rate] / 10,
+			dev->rates[rate] / 10 );
+
+		dev->rate = rate;
+		net80211_set_rtscts_rate ( dev );
+		dev->op->config ( dev, NET80211_CFG_RATE );
+	}
+}
+
+/**
+ * Configure 802.11 device to transmit on a certain channel
+ *
+ * @v dev	802.11 device
+ * @v channel	Channel number (1-11 for 2.4GHz) to transmit on
+ */
+int net80211_change_channel ( struct net80211_device *dev, int channel )
+{
+	int i, oldchan = dev->channel;
+
+	assert ( netdev_is_open ( dev->netdev ) );
+
+	for ( i = 0; i < dev->nr_channels; i++ ) {
+		if ( dev->channels[i].channel_nr == channel ) {
+			dev->channel = i;
+			break;
+		}
+	}
+
+	if ( i == dev->nr_channels )
+		return -ENOENT;
+
+	if ( i != oldchan )
+		return dev->op->config ( dev, NET80211_CFG_CHANNEL );
+
+	return 0;
+}
+
+/**
+ * Prepare 802.11 device channel and rate set for scanning
+ *
+ * @v dev	802.11 device
+ * @v band	RF band(s) on which to prepare for scanning
+ * @v active	Whether the scanning will be active
+ * @ret rc	Return status code
+ */
+int net80211_prepare_probe ( struct net80211_device *dev, int band,
+			     int active )
+{
+	assert ( netdev_is_open ( dev->netdev ) );
+
+	if ( active && ( band & NET80211_BAND_BIT_5GHZ ) ) {
+		DBGC ( dev, "802.11 %p cannot perform active scanning on "
+		       "5GHz band\n", dev );
+		return -EINVAL_ACTIVE_SCAN;
+	}
+
+	if ( band == 0 ) {
+		/* This can happen for a 5GHz-only card with 5GHz
+		   scanning masked out by an active request. */
+		DBGC ( dev, "802.11 %p asked to prepare for scanning nothing\n",
+		       dev );
+		return -EINVAL_ACTIVE_SCAN;
+	}
+
+	dev->nr_channels = 0;
+
+	if ( active )
+		net80211_add_channels ( dev, 1, 11, NET80211_REG_TXPOWER );
+	else {
+		if ( band & NET80211_BAND_BIT_2GHZ )
+			net80211_add_channels ( dev, 1, 14,
+						NET80211_REG_TXPOWER );
+		if ( band & NET80211_BAND_BIT_5GHZ )
+			net80211_add_channels ( dev, 36, 8,
+						NET80211_REG_TXPOWER );
+	}
+
+	net80211_filter_hw_channels ( dev );
+
+	/* Use channel 1 for now */
+	dev->channel = 0;
+	dev->op->config ( dev, NET80211_CFG_CHANNEL );
+
+	/* Always do active probes at lowest (presumably first) speed */
+	dev->rate = 0;
+	dev->nr_rates = 1;
+	dev->rates[0] = dev->hw->rates[dev->channels[0].band][0];
+	dev->op->config ( dev, NET80211_CFG_RATE );
+
+	return 0;
+}
+
+/**
+ * Prepare 802.11 device channel and rate set for communication
+ *
+ * @v dev	802.11 device
+ * @v wlan	WLAN to prepare for communication with
+ * @ret rc	Return status code
+ */
+int net80211_prepare_assoc ( struct net80211_device *dev,
+			     struct net80211_wlan *wlan )
+{
+	struct ieee80211_frame *hdr = wlan->beacon->data;
+	struct ieee80211_beacon *beacon =
+		( struct ieee80211_beacon * ) hdr->data;
+	struct net80211_handshaker *handshaker;
+	int rc;
+
+	assert ( netdev_is_open ( dev->netdev ) );
+
+	net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
+	memcpy ( dev->bssid, wlan->bssid, ETH_ALEN );
+	strcpy ( dev->essid, wlan->essid );
+
+	free ( dev->rsn_ie );
+	dev->rsn_ie = NULL;
+
+	dev->last_beacon_timestamp = beacon->timestamp;
+	dev->tx_beacon_interval = 1024 * beacon->beacon_interval;
+
+	/* Barring an IE that tells us the channel outright, assume
+	   the channel we heard this AP best on is the channel it's
+	   communicating on. */
+	net80211_change_channel ( dev, wlan->channel );
+
+	rc = net80211_process_capab ( dev, beacon->capability );
+	if ( rc )
+		return rc;
+
+	rc = net80211_process_ie ( dev, beacon->info_element,
+				   wlan->beacon->tail );
+	if ( rc )
+		return rc;
+
+	/* Associate at the lowest rate so we know it'll get through */
+	dev->rate = 0;
+	dev->op->config ( dev, NET80211_CFG_RATE );
+
+	/* Free old handshaker and crypto, if they exist */
+	if ( dev->handshaker && dev->handshaker->stop &&
+	     dev->handshaker->started )
+		dev->handshaker->stop ( dev );
+	free ( dev->handshaker );
+	dev->handshaker = NULL;
+	free ( dev->crypto );
+	free ( dev->gcrypto );
+	dev->crypto = dev->gcrypto = NULL;
+
+	/* Find new security handshaker to use */
+	for_each_table_entry ( handshaker, NET80211_HANDSHAKERS ) {
+		if ( handshaker->protocol == wlan->handshaking ) {
+			dev->handshaker = zalloc ( sizeof ( *handshaker ) +
+						   handshaker->priv_len );
+			if ( ! dev->handshaker )
+				return -ENOMEM;
+
+			memcpy ( dev->handshaker, handshaker,
+				 sizeof ( *handshaker ) );
+			dev->handshaker->priv = ( ( void * ) dev->handshaker +
+						  sizeof ( *handshaker ) );
+			break;
+		}
+	}
+
+	if ( ( wlan->handshaking != NET80211_SECPROT_NONE ) &&
+	     ! dev->handshaker ) {
+		DBGC ( dev, "802.11 %p no support for handshaking scheme %d\n",
+		       dev, wlan->handshaking );
+		return -( ENOTSUP | ( wlan->handshaking << 8 ) );
+	}
+
+	/* Initialize security handshaker */
+	if ( dev->handshaker ) {
+		rc = dev->handshaker->init ( dev );
+		if ( rc < 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Send 802.11 initial authentication frame
+ *
+ * @v dev	802.11 device
+ * @v wlan	WLAN to authenticate with
+ * @v method	Authentication method
+ * @ret rc	Return status code
+ *
+ * @a method may be 0 for Open System authentication or 1 for Shared
+ * Key authentication. Open System provides no security in association
+ * whatsoever, relying on encryption for confidentiality, but Shared
+ * Key actively introduces security problems and is very rarely used.
+ */
+int net80211_send_auth ( struct net80211_device *dev,
+			 struct net80211_wlan *wlan, int method )
+{
+	struct io_buffer *iob = alloc_iob ( 64 );
+	struct ieee80211_auth *auth;
+
+	net80211_set_state ( dev, 0, NET80211_WAITING, 0 );
+	iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
+	auth = iob_put ( iob, sizeof ( *auth ) );
+	auth->algorithm = method;
+	auth->tx_seq = 1;
+	auth->status = 0;
+
+	return net80211_tx_mgmt ( dev, IEEE80211_STYPE_AUTH, wlan->bssid, iob );
+}
+
+/**
+ * Handle receipt of 802.11 authentication frame
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer
+ *
+ * If the authentication method being used is Shared Key, and the
+ * frame that was received included challenge text, the frame is
+ * encrypted using the cryptosystem currently in effect and sent back
+ * to the AP to complete the authentication.
+ */
+static void net80211_handle_auth ( struct net80211_device *dev,
+				   struct io_buffer *iob )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	struct ieee80211_auth *auth =
+	    ( struct ieee80211_auth * ) hdr->data;
+
+	if ( auth->tx_seq & 1 ) {
+		DBGC ( dev, "802.11 %p authentication received improperly "
+		       "directed frame (seq. %d)\n", dev, auth->tx_seq );
+		net80211_set_state ( dev, NET80211_WAITING, 0,
+				     IEEE80211_STATUS_FAILURE );
+		return;
+	}
+
+	if ( auth->status != IEEE80211_STATUS_SUCCESS ) {
+		DBGC ( dev, "802.11 %p authentication failed: status %d\n",
+		       dev, auth->status );
+		net80211_set_state ( dev, NET80211_WAITING, 0,
+				     auth->status );
+		return;
+	}
+
+	if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY && ! dev->crypto ) {
+		DBGC ( dev, "802.11 %p can't perform shared-key authentication "
+		       "without a cryptosystem\n", dev );
+		net80211_set_state ( dev, NET80211_WAITING, 0,
+				     IEEE80211_STATUS_FAILURE );
+		return;
+	}
+
+	if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY &&
+	     auth->tx_seq == 2 ) {
+		/* Since the iob we got is going to be freed as soon
+		   as we return, we can do some in-place
+		   modification. */
+		auth->tx_seq = 3;
+		auth->status = 0;
+
+		memcpy ( hdr->addr2, hdr->addr1, ETH_ALEN );
+		memcpy ( hdr->addr1, hdr->addr3, ETH_ALEN );
+
+		netdev_tx ( dev->netdev,
+			    dev->crypto->encrypt ( dev->crypto, iob ) );
+		return;
+	}
+
+	net80211_set_state ( dev, NET80211_WAITING, NET80211_AUTHENTICATED,
+			     IEEE80211_STATUS_SUCCESS );
+
+	return;
+}
+
+/**
+ * Send 802.11 association frame
+ *
+ * @v dev	802.11 device
+ * @v wlan	WLAN to associate with
+ * @ret rc	Return status code
+ */
+int net80211_send_assoc ( struct net80211_device *dev,
+			  struct net80211_wlan *wlan )
+{
+	struct io_buffer *iob = alloc_iob ( 128 );
+	struct ieee80211_assoc_req *assoc;
+	union ieee80211_ie *ie;
+
+	net80211_set_state ( dev, 0, NET80211_WAITING, 0 );
+
+	iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
+	assoc = iob->data;
+
+	assoc->capability = IEEE80211_CAPAB_MANAGED;
+	if ( ! ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE ) )
+		assoc->capability |= IEEE80211_CAPAB_SHORT_PMBL;
+	if ( ! ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT ) )
+		assoc->capability |= IEEE80211_CAPAB_SHORT_SLOT;
+	if ( wlan->crypto )
+		assoc->capability |= IEEE80211_CAPAB_PRIVACY;
+
+	assoc->listen_interval = 1;
+
+	ie = net80211_marshal_request_info ( dev, assoc->info_element );
+
+	DBGP ( "802.11 %p about to send association request:\n", dev );
+	DBGP_HD ( iob->data, ( void * ) ie - iob->data );
+
+	iob_put ( iob, ( void * ) ie - iob->data );
+
+	return net80211_tx_mgmt ( dev, IEEE80211_STYPE_ASSOC_REQ,
+				  wlan->bssid, iob );
+}
+
+/**
+ * Handle receipt of 802.11 association reply frame
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer
+ */
+static void net80211_handle_assoc_reply ( struct net80211_device *dev,
+					  struct io_buffer *iob )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	struct ieee80211_assoc_resp *assoc =
+		( struct ieee80211_assoc_resp * ) hdr->data;
+
+	net80211_process_capab ( dev, assoc->capability );
+	net80211_process_ie ( dev, assoc->info_element, iob->tail );
+
+	if ( assoc->status != IEEE80211_STATUS_SUCCESS ) {
+		DBGC ( dev, "802.11 %p association failed: status %d\n",
+		       dev, assoc->status );
+		net80211_set_state ( dev, NET80211_WAITING, 0,
+				     assoc->status );
+		return;
+	}
+
+	/* ESSID was filled before the association request was sent */
+	memcpy ( dev->bssid, hdr->addr3, ETH_ALEN );
+	dev->aid = assoc->aid;
+
+	net80211_set_state ( dev, NET80211_WAITING, NET80211_ASSOCIATED,
+			     IEEE80211_STATUS_SUCCESS );
+}
+
+
+/**
+ * Send 802.11 disassociation frame
+ *
+ * @v dev	802.11 device
+ * @v reason	Reason for disassociation
+ * @v deauth	If TRUE, send deauthentication instead of disassociation
+ * @ret rc	Return status code
+ */
+static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
+				    int deauth )
+{
+	struct io_buffer *iob = alloc_iob ( 64 );
+	struct ieee80211_disassoc *disassoc;
+
+	if ( ! ( dev->state & NET80211_ASSOCIATED ) )
+		return -EINVAL;
+
+	net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
+	iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
+	disassoc = iob_put ( iob, sizeof ( *disassoc ) );
+	disassoc->reason = reason;
+
+	return net80211_tx_mgmt ( dev, deauth ? IEEE80211_STYPE_DEAUTH :
+				  IEEE80211_STYPE_DISASSOC, dev->bssid, iob );
+}
+
+
+/**
+ * Deauthenticate from current network and try again
+ *
+ * @v dev	802.11 device
+ * @v rc	Return status code indicating reason
+ *
+ * The deauthentication will be sent using an 802.11 "unspecified
+ * reason", as is common, but @a rc will be set as a link-up
+ * error to aid the user in debugging.
+ */
+void net80211_deauthenticate ( struct net80211_device *dev, int rc )
+{
+	net80211_send_disassoc ( dev, IEEE80211_REASON_UNSPECIFIED, 1 );
+	dev->assoc_rc = rc;
+	netdev_link_err ( dev->netdev, rc );
+
+	net80211_autoassociate ( dev );
+}
+
+
+/** Smoothing factor (1-7) for link quality calculation */
+#define LQ_SMOOTH	7
+
+/**
+ * Update link quality information based on received beacon
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer containing beacon
+ * @ret rc	Return status code
+ */
+static void net80211_update_link_quality ( struct net80211_device *dev,
+					   struct io_buffer *iob )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	struct ieee80211_beacon *beacon;
+	u32 dt, rxi;
+
+	if ( ! ( dev->state & NET80211_ASSOCIATED ) )
+		return;
+
+	beacon = ( struct ieee80211_beacon * ) hdr->data;
+	dt = ( u32 ) ( beacon->timestamp - dev->last_beacon_timestamp );
+	rxi = dev->rx_beacon_interval;
+
+	rxi = ( LQ_SMOOTH * rxi ) + ( ( 8 - LQ_SMOOTH ) * dt );
+	dev->rx_beacon_interval = rxi >> 3;
+
+	dev->last_beacon_timestamp = beacon->timestamp;
+}
+
+
+/**
+ * Handle receipt of 802.11 management frame
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer
+ * @v signal	Signal strength of received frame
+ */
+static void net80211_handle_mgmt ( struct net80211_device *dev,
+				   struct io_buffer *iob, int signal )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	struct ieee80211_disassoc *disassoc;
+	u16 stype = hdr->fc & IEEE80211_FC_SUBTYPE;
+	int keep = 0;
+	int is_deauth = ( stype == IEEE80211_STYPE_DEAUTH );
+
+	if ( ( hdr->fc & IEEE80211_FC_TYPE ) != IEEE80211_TYPE_MGMT ) {
+		free_iob ( iob );
+		return;		/* only handle management frames */
+	}
+
+	switch ( stype ) {
+		/* We reconnect on deauthentication and disassociation. */
+	case IEEE80211_STYPE_DEAUTH:
+	case IEEE80211_STYPE_DISASSOC:
+		disassoc = ( struct ieee80211_disassoc * ) hdr->data;
+		net80211_set_state ( dev, is_deauth ? NET80211_AUTHENTICATED :
+				     NET80211_ASSOCIATED, 0,
+				     NET80211_IS_REASON | disassoc->reason );
+		DBGC ( dev, "802.11 %p %s: reason %d\n",
+		       dev, is_deauth ? "deauthenticated" : "disassociated",
+		       disassoc->reason );
+
+		/* Try to reassociate, in case it's transient. */
+		net80211_autoassociate ( dev );
+
+		break;
+
+		/* We handle authentication and association. */
+	case IEEE80211_STYPE_AUTH:
+		if ( ! ( dev->state & NET80211_AUTHENTICATED ) )
+			net80211_handle_auth ( dev, iob );
+		break;
+
+	case IEEE80211_STYPE_ASSOC_RESP:
+	case IEEE80211_STYPE_REASSOC_RESP:
+		if ( ! ( dev->state & NET80211_ASSOCIATED ) )
+			net80211_handle_assoc_reply ( dev, iob );
+		break;
+
+		/* We pass probes and beacons onto network scanning
+		   code. Pass actions for future extensibility. */
+	case IEEE80211_STYPE_BEACON:
+		net80211_update_link_quality ( dev, iob );
+		/* fall through */
+	case IEEE80211_STYPE_PROBE_RESP:
+	case IEEE80211_STYPE_ACTION:
+		if ( dev->keep_mgmt ) {
+			struct net80211_rx_info *rxinf;
+			rxinf = zalloc ( sizeof ( *rxinf ) );
+			if ( ! rxinf ) {
+				DBGC ( dev, "802.11 %p out of memory\n", dev );
+				break;
+			}
+			rxinf->signal = signal;
+			list_add_tail ( &iob->list, &dev->mgmt_queue );
+			list_add_tail ( &rxinf->list, &dev->mgmt_info_queue );
+			keep = 1;
+		}
+		break;
+
+	case IEEE80211_STYPE_PROBE_REQ:
+		/* Some nodes send these broadcast. Ignore them. */
+		break;
+
+	case IEEE80211_STYPE_ASSOC_REQ:
+	case IEEE80211_STYPE_REASSOC_REQ:
+		/* We should never receive these, only send them. */
+		DBGC ( dev, "802.11 %p received strange management request "
+		       "(%04x)\n", dev, stype );
+		break;
+
+	default:
+		DBGC ( dev, "802.11 %p received unimplemented management "
+		       "packet (%04x)\n", dev, stype );
+		break;
+	}
+
+	if ( ! keep )
+		free_iob ( iob );
+}
+
+/* ---------- Packet handling functions ---------- */
+
+/**
+ * Free buffers used by 802.11 fragment cache entry
+ *
+ * @v dev	802.11 device
+ * @v fcid	Fragment cache entry index
+ *
+ * After this function, the referenced entry will be marked unused.
+ */
+static void net80211_free_frags ( struct net80211_device *dev, int fcid )
+{
+	int j;
+	struct net80211_frag_cache *frag = &dev->frags[fcid];
+
+	for ( j = 0; j < 16; j++ ) {
+		if ( frag->iob[j] ) {
+			free_iob ( frag->iob[j] );
+			frag->iob[j] = NULL;
+		}
+	}
+
+	frag->seqnr = 0;
+	frag->start_ticks = 0;
+	frag->in_use = 0;
+}
+
+/**
+ * Accumulate 802.11 fragments into one I/O buffer
+ *
+ * @v dev	802.11 device
+ * @v fcid	Fragment cache entry index
+ * @v nfrags	Number of fragments received
+ * @v size	Sum of sizes of all fragments, including headers
+ * @ret iob	I/O buffer containing reassembled packet
+ *
+ * This function does not free the fragment buffers.
+ */
+static struct io_buffer *net80211_accum_frags ( struct net80211_device *dev,
+						int fcid, int nfrags, int size )
+{
+	struct net80211_frag_cache *frag = &dev->frags[fcid];
+	int hdrsize = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int nsize = size - hdrsize * ( nfrags - 1 );
+	int i;
+
+	struct io_buffer *niob = alloc_iob ( nsize );
+	struct ieee80211_frame *hdr;
+
+	/* Add the header from the first one... */
+	memcpy ( iob_put ( niob, hdrsize ), frag->iob[0]->data, hdrsize );
+
+	/* ... and all the data from all of them. */
+	for ( i = 0; i < nfrags; i++ ) {
+		int len = iob_len ( frag->iob[i] ) - hdrsize;
+		memcpy ( iob_put ( niob, len ),
+			 frag->iob[i]->data + hdrsize, len );
+	}
+
+	/* Turn off the fragment bit. */
+	hdr = niob->data;
+	hdr->fc &= ~IEEE80211_FC_MORE_FRAG;
+
+	return niob;
+}
+
+/**
+ * Handle receipt of 802.11 fragment
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer containing fragment
+ * @v signal	Signal strength with which fragment was received
+ */
+static void net80211_rx_frag ( struct net80211_device *dev,
+			       struct io_buffer *iob, int signal )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	int fragnr = IEEE80211_FRAG ( hdr->seq );
+
+	if ( fragnr == 0 && ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
+		/* start a frag cache entry */
+		int i, newest = -1;
+		u32 curr_ticks = currticks(), newest_ticks = 0;
+		u32 timeout = ticks_per_sec() * NET80211_FRAG_TIMEOUT;
+
+		for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
+			if ( dev->frags[i].in_use == 0 )
+				break;
+
+			if ( dev->frags[i].start_ticks + timeout >=
+			     curr_ticks ) {
+				net80211_free_frags ( dev, i );
+				break;
+			}
+
+			if ( dev->frags[i].start_ticks > newest_ticks ) {
+				newest = i;
+				newest_ticks = dev->frags[i].start_ticks;
+			}
+		}
+
+		/* If we're being sent more concurrent fragmented
+		   packets than we can handle, drop the newest so the
+		   older ones have time to complete. */
+		if ( i == NET80211_NR_CONCURRENT_FRAGS ) {
+			i = newest;
+			net80211_free_frags ( dev, i );
+		}
+
+		dev->frags[i].in_use = 1;
+		dev->frags[i].seqnr = IEEE80211_SEQNR ( hdr->seq );
+		dev->frags[i].start_ticks = currticks();
+		dev->frags[i].iob[0] = iob;
+		return;
+	} else {
+		int i;
+		for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
+			if ( dev->frags[i].in_use && dev->frags[i].seqnr ==
+			     IEEE80211_SEQNR ( hdr->seq ) )
+				break;
+		}
+		if ( i == NET80211_NR_CONCURRENT_FRAGS ) {
+			/* Drop non-first not-in-cache fragments */
+			DBGC ( dev, "802.11 %p dropped fragment fc=%04x "
+			       "seq=%04x\n", dev, hdr->fc, hdr->seq );
+			free_iob ( iob );
+			return;
+		}
+
+		dev->frags[i].iob[fragnr] = iob;
+
+		if ( ! ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
+			int j, size = 0;
+			for ( j = 0; j < fragnr; j++ ) {
+				size += iob_len ( dev->frags[i].iob[j] );
+				if ( dev->frags[i].iob[j] == NULL )
+					break;
+			}
+			if ( j == fragnr ) {
+				/* We've got everything */
+				struct io_buffer *niob =
+				    net80211_accum_frags ( dev, i, fragnr,
+							   size );
+				net80211_free_frags ( dev, i );
+				net80211_rx ( dev, niob, signal, 0 );
+			} else {
+				DBGC ( dev, "802.11 %p dropping fragmented "
+				       "packet due to out-of-order arrival, "
+				       "fc=%04x seq=%04x\n", dev, hdr->fc,
+				       hdr->seq );
+				net80211_free_frags ( dev, i );
+			}
+		}
+	}
+}
+
+/**
+ * Handle receipt of 802.11 frame
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer
+ * @v signal	Received signal strength
+ * @v rate	Bitrate at which frame was received, in 100 kbps units
+ *
+ * If the rate or signal is unknown, 0 should be passed.
+ */
+void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
+		   int signal, u16 rate )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	u16 type = hdr->fc & IEEE80211_FC_TYPE;
+	if ( ( hdr->fc & IEEE80211_FC_VERSION ) != IEEE80211_THIS_VERSION )
+		goto drop;	/* drop invalid-version packets */
+
+	if ( type == IEEE80211_TYPE_CTRL )
+		goto drop;	/* we don't handle control packets,
+				   the hardware does */
+
+	if ( dev->last_rx_seq == hdr->seq )
+		goto drop;	/* avoid duplicate packet */
+	dev->last_rx_seq = hdr->seq;
+
+	if ( dev->hw->flags & NET80211_HW_RX_HAS_FCS ) {
+		/* discard the FCS */
+		iob_unput ( iob, 4 );
+	}
+
+	/* Only decrypt packets from our BSSID, to avoid spurious errors */
+	if ( ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
+	     ! memcmp ( hdr->addr2, dev->bssid, ETH_ALEN ) ) {
+		/* Decrypt packet; record and drop if it fails */
+		struct io_buffer *niob;
+		struct net80211_crypto *crypto = dev->crypto;
+
+		if ( ! dev->crypto ) {
+			DBGC ( dev, "802.11 %p cannot decrypt packet "
+			       "without a cryptosystem\n", dev );
+			goto drop_crypt;
+		}
+
+		if ( ( hdr->addr1[0] & 1 ) && dev->gcrypto ) {
+			/* Use group decryption if needed */
+			crypto = dev->gcrypto;
+		}
+
+		niob = crypto->decrypt ( crypto, iob );
+		if ( ! niob ) {
+			DBGC ( dev, "802.11 %p decryption error\n", dev );
+			goto drop_crypt;
+		}
+		free_iob ( iob );
+		iob = niob;
+		hdr = iob->data;
+	}
+
+	dev->last_signal = signal;
+
+	/* Fragments go into the frag cache or get dropped. */
+	if ( IEEE80211_FRAG ( hdr->seq ) != 0
+	     || ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
+		net80211_rx_frag ( dev, iob, signal );
+		return;
+	}
+
+	/* Management frames get handled, enqueued, or dropped. */
+	if ( type == IEEE80211_TYPE_MGMT ) {
+		net80211_handle_mgmt ( dev, iob, signal );
+		return;
+	}
+
+	/* Data frames get dropped or sent to the net_device. */
+	if ( ( hdr->fc & IEEE80211_FC_SUBTYPE ) != IEEE80211_STYPE_DATA )
+		goto drop;	/* drop QoS, CFP, or null data packets */
+
+	/* Update rate-control algorithm */
+	if ( dev->rctl )
+		rc80211_update_rx ( dev, hdr->fc & IEEE80211_FC_RETRY, rate );
+
+	/* Pass packet onward */
+	if ( dev->state & NET80211_ASSOCIATED ) {
+		netdev_rx ( dev->netdev, iob );
+		return;
+	}
+
+	/* No association? Drop it. */
+	goto drop;
+
+ drop_crypt:
+	netdev_rx_err ( dev->netdev, NULL, EINVAL_CRYPTO_REQUEST );
+ drop:
+	DBGC2 ( dev, "802.11 %p dropped packet fc=%04x seq=%04x\n", dev,
+		hdr->fc, hdr->seq );
+	free_iob ( iob );
+	return;
+}
+
+/** Indicate an error in receiving a packet
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer with received packet, or NULL
+ * @v rc	Error code
+ *
+ * This logs the error with the wrapping net_device, and frees iob if
+ * it is passed.
+ */
+void net80211_rx_err ( struct net80211_device *dev,
+		       struct io_buffer *iob, int rc )
+{
+	netdev_rx_err ( dev->netdev, iob, rc );
+}
+
+/** Indicate the completed transmission of a packet
+ *
+ * @v dev	802.11 device
+ * @v iob	I/O buffer of transmitted packet
+ * @v retries	Number of times this packet was retransmitted
+ * @v rc	Error code, or 0 for success
+ *
+ * This logs an error with the wrapping net_device if one occurred,
+ * and removes and frees the I/O buffer from its TX queue. The
+ * provided retry information is used to tune our transmission rate.
+ *
+ * If the packet did not need to be retransmitted because it was
+ * properly ACKed the first time, @a retries should be 0.
+ */
+void net80211_tx_complete ( struct net80211_device *dev,
+			    struct io_buffer *iob, int retries, int rc )
+{
+	/* Update rate-control algorithm */
+	if ( dev->rctl )
+		rc80211_update_tx ( dev, retries, rc );
+
+	/* Pass completion onward */
+	netdev_tx_complete_err ( dev->netdev, iob, rc );
+}
+
+/** Common 802.11 errors */
+struct errortab common_wireless_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EINVAL_CRYPTO_REQUEST ),
+	__einfo_errortab ( EINFO_ECONNRESET_UNSPECIFIED ),
+	__einfo_errortab ( EINFO_ECONNRESET_INACTIVITY ),
+	__einfo_errortab ( EINFO_ECONNRESET_4WAY_TIMEOUT ),
+	__einfo_errortab ( EINFO_ECONNRESET_8021X_FAILURE ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_FAILURE ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_DENIED ),
+	__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/rc80211.c b/qemu-0.15.x/roms/ipxe/src/net/80211/rc80211.c
new file mode 100644
index 0000000..56bbc8a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/rc80211.c
@@ -0,0 +1,371 @@
+/*
+ * Simple 802.11 rate-control algorithm for iPXE.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/net80211.h>
+
+/**
+ * @file
+ *
+ * Simple 802.11 rate-control algorithm
+ */
+
+/** @page rc80211 Rate control philosophy
+ *
+ * We want to maximize our transmission speed, to the extent that we
+ * can do that without dropping undue numbers of packets. We also
+ * don't want to take up very much code space, so our algorithm has to
+ * be pretty simple
+ *
+ * When we receive a packet, we know what rate it was transmitted at,
+ * and whether it had to be retransmitted to get to us.
+ *
+ * When we send a packet, we hear back how many times it had to be
+ * retried to get through, and whether it got through at all.
+ *
+ * Indications of TX success are more reliable than RX success, but RX
+ * information helps us know where to start.
+ *
+ * To handle all of this, we keep for each rate and each direction (TX
+ * and RX separately) some state information for the most recent
+ * packets on that rate and the number of packets for which we have
+ * information. The state is a 32-bit unsigned integer in which two
+ * bits represent a packet: 11 if it went through well, 10 if it went
+ * through with one retry, 01 if it went through with more than one
+ * retry, or 00 if it didn't go through at all. We define the
+ * "goodness" for a particular (rate, direction) combination as the
+ * sum of all the 2-bit fields, times 33, divided by the number of
+ * 2-bit fields containing valid information (16 except when we're
+ * starting out). The number produced is between 0 and 99; we use -1
+ * for rates with less than 4 RX packets or 1 TX, as an indicator that
+ * we do not have enough information to rely on them.
+ *
+ * In deciding which rates are best, we find the weighted average of
+ * TX and RX goodness, where the weighting is by number of packets
+ * with data and TX packets are worth 4 times as much as RX packets.
+ * The weighted average is called "net goodness" and is also a number
+ * between 0 and 99.  If 3 consecutive packets fail transmission
+ * outright, we automatically ratchet down the rate; otherwise, we
+ * switch to the best rate whenever the current rate's goodness falls
+ * below some threshold, and try increasing our rate when the goodness
+ * is very high.
+ *
+ * This system is optimized for iPXE's style of usage. Because normal
+ * operation always involves receiving something, we'll make our way
+ * to the best rate pretty quickly. We tend to follow the lead of the
+ * sending AP in choosing rates, but we won't use rates for long that
+ * don't work well for us in transmission. We assume iPXE won't be
+ * running for long enough that rate patterns will change much, so we
+ * don't have to keep time counters or the like.  And if this doesn't
+ * work well in practice there are many ways it could be tweaked.
+ *
+ * To avoid staying at 1Mbps for a long time, we don't track any
+ * transmitted packets until we've set our rate based on received
+ * packets.
+ */
+
+/** Two-bit packet status indicator for a packet with no retries */
+#define RC_PKT_OK		0x3
+
+/** Two-bit packet status indicator for a packet with one retry */
+#define RC_PKT_RETRIED_ONCE	0x2
+
+/** Two-bit packet status indicator for a TX packet with multiple retries
+ *
+ * It is not possible to tell whether an RX packet had one or multiple
+ * retries; we rely instead on the fact that failed RX packets won't
+ * get to us at all, so if we receive a lot of RX packets on a certain
+ * rate it must be pretty good.
+ */
+#define RC_PKT_RETRIED_MULTI	0x1
+
+/** Two-bit packet status indicator for a TX packet that was never ACKed
+ *
+ * It is not possible to tell whether an RX packet was setn if it
+ * didn't get through to us, but if we don't see one we won't increase
+ * the goodness for its rate. This asymmetry is part of why TX packets
+ * are weighted much more heavily than RX.
+ */
+#define RC_PKT_FAILED		0x0
+
+/** Number of times to weight TX packets more heavily than RX packets */
+#define RC_TX_FACTOR		4
+
+/** Number of consecutive failed TX packets that cause an automatic rate drop */
+#define RC_TX_EMERG_FAIL	3
+
+/** Minimum net goodness below which we will search for a better rate */
+#define RC_GOODNESS_MIN		85
+
+/** Maximum net goodness above which we will try to increase our rate */
+#define RC_GOODNESS_MAX		95
+
+/** Minimum (num RX + @c RC_TX_FACTOR * num TX) to use a certain rate */
+#define RC_UNCERTAINTY_THRESH	4
+
+/** TX direction */
+#define TX	0
+
+/** RX direction */
+#define RX	1
+
+/** A rate control context */
+struct rc80211_ctx
+{
+	/** Goodness state for each rate, TX and RX */
+	u32 goodness[2][NET80211_MAX_RATES];
+
+	/** Number of packets recorded for each rate */
+	u8 count[2][NET80211_MAX_RATES];
+
+	/** Indication of whether we've set the device rate yet */
+	int started;
+
+	/** Counter of all packets sent and received */
+	int packets;
+};
+
+/**
+ * Initialize rate-control algorithm
+ *
+ * @v dev	802.11 device
+ * @ret ctx	Rate-control context, to be stored in @c dev->rctl
+ */
+struct rc80211_ctx * rc80211_init ( struct net80211_device *dev __unused )
+{
+	struct rc80211_ctx *ret = zalloc ( sizeof ( *ret ) );
+	return ret;
+}
+
+/**
+ * Calculate net goodness for a certain rate
+ *
+ * @v ctx	Rate-control context
+ * @v rate_idx	Index of rate to calculate net goodness for
+ */
+static int rc80211_calc_net_goodness ( struct rc80211_ctx *ctx,
+				       int rate_idx )
+{
+	int sum[2], num[2], dir, pkt;
+
+	for ( dir = 0; dir < 2; dir++ ) {
+		u32 good = ctx->goodness[dir][rate_idx];
+
+		num[dir] = ctx->count[dir][rate_idx];
+		sum[dir] = 0;
+
+		for ( pkt = 0; pkt < num[dir]; pkt++ )
+			sum[dir] += ( good >> ( 2 * pkt ) ) & 0x3;
+	}
+
+	if ( ( num[TX] * RC_TX_FACTOR + num[RX] ) < RC_UNCERTAINTY_THRESH )
+		return -1;
+
+	return ( 33 * ( sum[TX] * RC_TX_FACTOR + sum[RX] ) /
+		      ( num[TX] * RC_TX_FACTOR + num[RX] ) );
+}
+
+/**
+ * Determine the best rate to switch to and return it
+ *
+ * @v dev		802.11 device
+ * @ret rate_idx	Index of the best rate to switch to
+ */
+static int rc80211_pick_best ( struct net80211_device *dev )
+{
+	struct rc80211_ctx *ctx = dev->rctl;
+	int best_net_good = 0, best_rate = -1, i;
+
+	for ( i = 0; i < dev->nr_rates; i++ ) {
+		int net_good = rc80211_calc_net_goodness ( ctx, i );
+
+		if ( net_good > best_net_good ||
+		     ( best_net_good > RC_GOODNESS_MIN &&
+		       net_good > RC_GOODNESS_MIN ) ) {
+			best_net_good = net_good;
+			best_rate = i;
+		}
+	}
+
+	if ( best_rate >= 0 ) {
+		int old_good = rc80211_calc_net_goodness ( ctx, dev->rate );
+		if ( old_good != best_net_good )
+			DBGC ( ctx, "802.11 RC %p switching from goodness "
+			       "%d to %d\n", ctx, old_good, best_net_good );
+
+		ctx->started = 1;
+		return best_rate;
+	}
+
+	return dev->rate;
+}
+
+/**
+ * Set 802.11 device rate
+ *
+ * @v dev	802.11 device
+ * @v rate_idx	Index of rate to switch to
+ *
+ * This is a thin wrapper around net80211_set_rate_idx to insert a
+ * debugging message where appropriate.
+ */
+static inline void rc80211_set_rate ( struct net80211_device *dev,
+				      int rate_idx )
+{
+	DBGC ( dev->rctl, "802.11 RC %p changing rate %d->%d Mbps\n", dev->rctl,
+	       dev->rates[dev->rate] / 10, dev->rates[rate_idx] / 10 );
+
+	net80211_set_rate_idx ( dev, rate_idx );
+}
+
+/**
+ * Check rate-control state and change rate if necessary
+ *
+ * @v dev	802.11 device
+ */
+static void rc80211_maybe_set_new ( struct net80211_device *dev )
+{
+	struct rc80211_ctx *ctx = dev->rctl;
+	int net_good;
+
+	net_good = rc80211_calc_net_goodness ( ctx, dev->rate );
+
+	if ( ! ctx->started ) {
+		rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
+		return;
+	}
+
+	if ( net_good < 0 )	/* insufficient data */
+		return;
+
+	if ( net_good > RC_GOODNESS_MAX && dev->rate + 1 < dev->nr_rates ) {
+		int higher = rc80211_calc_net_goodness ( ctx, dev->rate + 1 );
+		if ( higher > net_good || higher < 0 )
+			rc80211_set_rate ( dev, dev->rate + 1 );
+		else
+			rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
+	}
+
+	if ( net_good < RC_GOODNESS_MIN ) {
+		rc80211_set_rate ( dev, rc80211_pick_best ( dev ) );
+	}
+}
+
+/**
+ * Update rate-control state
+ *
+ * @v dev		802.11 device
+ * @v direction		One of the direction constants TX or RX
+ * @v rate_idx		Index of rate at which packet was sent or received
+ * @v retries		Number of times packet was retried before success
+ * @v failed		If nonzero, the packet failed to get through
+ */
+static void rc80211_update ( struct net80211_device *dev, int direction,
+			     int rate_idx, int retries, int failed )
+{
+	struct rc80211_ctx *ctx = dev->rctl;
+	u32 goodness = ctx->goodness[direction][rate_idx];
+
+	if ( ctx->count[direction][rate_idx] < 16 )
+		ctx->count[direction][rate_idx]++;
+
+	goodness <<= 2;
+	if ( failed )
+		goodness |= RC_PKT_FAILED;
+	else if ( retries > 1 )
+		goodness |= RC_PKT_RETRIED_MULTI;
+	else if ( retries )
+		goodness |= RC_PKT_RETRIED_ONCE;
+	else
+		goodness |= RC_PKT_OK;
+
+	ctx->goodness[direction][rate_idx] = goodness;
+
+	ctx->packets++;
+
+	rc80211_maybe_set_new ( dev );
+}
+
+/**
+ * Update rate-control state for transmitted packet
+ *
+ * @v dev	802.11 device
+ * @v retries	Number of times packet was transmitted before success
+ * @v rc	Return status code for transmission
+ */
+void rc80211_update_tx ( struct net80211_device *dev, int retries, int rc )
+{
+	struct rc80211_ctx *ctx = dev->rctl;
+
+	if ( ! ctx->started )
+		return;
+
+	rc80211_update ( dev, TX, dev->rate, retries, rc );
+
+	/* Check if the last RC_TX_EMERG_FAIL packets have all failed */
+	if ( ! ( ctx->goodness[TX][dev->rate] &
+		 ( ( 1 << ( 2 * RC_TX_EMERG_FAIL ) ) - 1 ) ) ) {
+		if ( dev->rate == 0 )
+			DBGC ( dev->rctl, "802.11 RC %p saw %d consecutive "
+			       "failed TX, but cannot lower rate any further\n",
+			       dev->rctl, RC_TX_EMERG_FAIL );
+		else {
+			DBGC ( dev->rctl, "802.11 RC %p lowering rate (%d->%d "
+			       "Mbps) due to %d consecutive TX failures\n",
+			       dev->rctl, dev->rates[dev->rate] / 10,
+			       dev->rates[dev->rate - 1] / 10,
+			       RC_TX_EMERG_FAIL );
+
+			rc80211_set_rate ( dev, dev->rate - 1 );
+		}
+	}
+}
+
+/**
+ * Update rate-control state for received packet
+ *
+ * @v dev	802.11 device
+ * @v retry	Whether the received packet had been retransmitted
+ * @v rate	Rate at which packet was received, in 100 kbps units
+ */
+void rc80211_update_rx ( struct net80211_device *dev, int retry, u16 rate )
+{
+	int ridx;
+
+	for ( ridx = 0; ridx < dev->nr_rates && dev->rates[ridx] != rate;
+	      ridx++ )
+		;
+	if ( ridx >= dev->nr_rates )
+		return;		/* couldn't find the rate */
+
+	rc80211_update ( dev, RX, ridx, retry, 0 );
+}
+
+/**
+ * Free rate-control context
+ *
+ * @v ctx	Rate-control context
+ */
+void rc80211_free ( struct rc80211_ctx *ctx )
+{
+	free ( ctx );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/sec80211.c b/qemu-0.15.x/roms/ipxe/src/net/80211/sec80211.c
new file mode 100644
index 0000000..82b1ce9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/sec80211.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/ieee80211.h>
+#include <ipxe/net80211.h>
+#include <ipxe/sec80211.h>
+
+/** @file
+ *
+ * General secured-network routines required whenever any secure
+ * network support at all is compiled in. This involves things like
+ * installing keys, determining the type of security used by a probed
+ * network, and some small helper functions that take advantage of
+ * static data in this file.
+ */
+
+/* Unsupported cryptosystem error numbers */
+#define ENOTSUP_WEP __einfo_error ( EINFO_ENOTSUP_WEP )
+#define EINFO_ENOTSUP_WEP __einfo_uniqify ( EINFO_ENOTSUP, \
+	( 0x10 | NET80211_CRYPT_WEP ), "WEP not supported" )
+#define ENOTSUP_TKIP __einfo_error ( EINFO_ENOTSUP_TKIP )
+#define EINFO_ENOTSUP_TKIP __einfo_uniqify ( EINFO_ENOTSUP, \
+	( 0x10 | NET80211_CRYPT_TKIP ), "TKIP not supported" )
+#define ENOTSUP_CCMP __einfo_error ( EINFO_ENOTSUP_CCMP )
+#define EINFO_ENOTSUP_CCMP __einfo_uniqify ( EINFO_ENOTSUP, \
+	( 0x10 | NET80211_CRYPT_CCMP ), "CCMP not supported" )
+#define ENOTSUP_CRYPT( crypt )		     \
+	EUNIQ ( ENOTSUP, ( 0x10 | (crypt) ), \
+		ENOTSUP_WEP, ENOTSUP_TKIP, ENOTSUP_CCMP )
+
+/** Mapping from net80211 crypto/secprot types to RSN OUI descriptors */
+struct descriptor_map {
+	/** Value of net80211_crypto_alg or net80211_security_proto */
+	u32 net80211_type;
+
+	/** OUI+type in appropriate byte order, masked to exclude vendor */
+	u32 oui_type;
+};
+
+/** Magic number in @a oui_type showing end of list */
+#define END_MAGIC	0xFFFFFFFF
+
+/** Mapping between net80211 cryptosystems and 802.11i cipher IDs */
+static struct descriptor_map rsn_cipher_map[] = {
+	{ .net80211_type = NET80211_CRYPT_WEP,
+	  .oui_type = IEEE80211_RSN_CTYPE_WEP40 },
+
+	{ .net80211_type = NET80211_CRYPT_WEP,
+	  .oui_type = IEEE80211_RSN_CTYPE_WEP104 },
+
+	{ .net80211_type = NET80211_CRYPT_TKIP,
+	  .oui_type = IEEE80211_RSN_CTYPE_TKIP },
+
+	{ .net80211_type = NET80211_CRYPT_CCMP,
+	  .oui_type = IEEE80211_RSN_CTYPE_CCMP },
+
+	{ .net80211_type = NET80211_CRYPT_UNKNOWN,
+	  .oui_type = END_MAGIC },
+};
+
+/** Mapping between net80211 handshakers and 802.11i AKM IDs */
+static struct descriptor_map rsn_akm_map[] = {
+	{ .net80211_type = NET80211_SECPROT_EAP,
+	  .oui_type = IEEE80211_RSN_ATYPE_8021X },
+
+	{ .net80211_type = NET80211_SECPROT_PSK,
+	  .oui_type = IEEE80211_RSN_ATYPE_PSK },
+
+	{ .net80211_type = NET80211_SECPROT_UNKNOWN,
+	  .oui_type = END_MAGIC },
+};
+
+
+/**
+ * Install 802.11 cryptosystem
+ *
+ * @v which	Pointer to the cryptosystem structure to install in
+ * @v crypt	Cryptosystem ID number
+ * @v key	Encryption key to use
+ * @v len	Length of encryption key
+ * @v rsc	Initial receive sequence counter, if applicable
+ * @ret rc	Return status code
+ *
+ * The encryption key will not be accessed via the provided pointer
+ * after this function returns, so you may keep it on the stack.
+ *
+ * @a which must point to either @c dev->crypto (for the normal case
+ * of installing a unicast cryptosystem) or @c dev->gcrypto (to
+ * install a cryptosystem that will be used only for decrypting
+ * group-source frames).
+ */
+int sec80211_install ( struct net80211_crypto **which,
+		       enum net80211_crypto_alg crypt,
+		       const void *key, int len, const void *rsc )
+{
+	struct net80211_crypto *crypto = *which;
+	struct net80211_crypto *tbl_crypto;
+
+	/* Remove old crypto if it exists */
+	free ( *which );
+	*which = NULL;
+
+	if ( crypt == NET80211_CRYPT_NONE ) {
+		DBG ( "802.11-Sec not installing null cryptography\n" );
+		return 0;
+	}
+
+	/* Find cryptosystem to use */
+	for_each_table_entry ( tbl_crypto, NET80211_CRYPTOS ) {
+		if ( tbl_crypto->algorithm == crypt ) {
+			crypto = zalloc ( sizeof ( *crypto ) +
+					  tbl_crypto->priv_len );
+			if ( ! crypto ) {
+				DBG ( "802.11-Sec out of memory\n" );
+				return -ENOMEM;
+			}
+
+			memcpy ( crypto, tbl_crypto, sizeof ( *crypto ) );
+			crypto->priv = ( ( void * ) crypto +
+					 sizeof ( *crypto ) );
+			break;
+		}
+	}
+
+	if ( ! crypto ) {
+		DBG ( "802.11-Sec no support for cryptosystem %d\n", crypt );
+		return -ENOTSUP_CRYPT ( crypt );
+	}
+
+	*which = crypto;
+
+	DBG ( "802.11-Sec installing cryptosystem %d as %p with key of "
+	      "length %d\n", crypt, crypto, len );
+
+	return crypto->init ( crypto, key, len, rsc );
+}
+
+
+/**
+ * Determine net80211 crypto or handshaking type value to return for RSN info
+ *
+ * @v rsnp		Pointer to next descriptor count field in RSN IE
+ * @v rsn_end		Pointer to end of RSN IE
+ * @v map		Descriptor map to use
+ * @v tbl_start		Start of linker table to examine for iPXE support
+ * @v tbl_end		End of linker table to examine for iPXE support
+ * @ret rsnp		Updated to point to first byte after descriptors
+ * @ret map_ent		Descriptor map entry of translation to use
+ *
+ * The entries in the linker table must be either net80211_crypto or
+ * net80211_handshaker structures, and @a tbl_stride must be set to
+ * sizeof() the appropriate one.
+ *
+ * This function expects @a rsnp to point at a two-byte descriptor
+ * count followed by a list of four-byte cipher or AKM descriptors; it
+ * will return @c NULL if the input packet is malformed, and otherwise
+ * set @a rsnp to the first byte it has not looked at. It will return
+ * the first cipher in the list that is supported by the current build
+ * of iPXE, or the first of all if none are supported.
+ *
+ * We play rather fast and loose with type checking, because this
+ * function is only called from two well-defined places in the
+ * RSN-checking code. Don't try to use it for anything else.
+ */
+static struct descriptor_map * rsn_pick_desc ( u8 **rsnp, u8 *rsn_end,
+					       struct descriptor_map *map,
+					       void *tbl_start, void *tbl_end )
+{
+	int ndesc;
+	int ok = 0;
+	struct descriptor_map *map_ent, *map_ret = NULL;
+	u8 *rsn = *rsnp;
+	void *tblp;
+	size_t tbl_stride = ( map == rsn_cipher_map ?
+			      sizeof ( struct net80211_crypto ) :
+			      sizeof ( struct net80211_handshaker ) );
+
+	if ( map != rsn_cipher_map && map != rsn_akm_map )
+		return NULL;
+
+	/* Determine which types we support */
+	for ( tblp = tbl_start; tblp < tbl_end; tblp += tbl_stride ) {
+		struct net80211_crypto *crypto = tblp;
+		struct net80211_handshaker *hs = tblp;
+
+		if ( map == rsn_cipher_map )
+			ok |= ( 1 << crypto->algorithm );
+		else
+			ok |= ( 1 << hs->protocol );
+	}
+
+	/* RSN sanity checks */
+	if ( rsn + 2 > rsn_end ) {
+		DBG ( "RSN detect: malformed descriptor count\n" );
+		return NULL;
+	}
+
+	ndesc = *( u16 * ) rsn;
+	rsn += 2;
+
+	if ( ! ndesc ) {
+		DBG ( "RSN detect: no descriptors\n" );
+		return NULL;
+	}
+
+	/* Determine which net80211 crypto types are listed */
+	while ( ndesc-- ) {
+		u32 desc;
+
+		if ( rsn + 4 > rsn_end ) {
+			DBG ( "RSN detect: malformed descriptor (%d left)\n",
+			      ndesc );
+			return NULL;
+		}
+
+		desc = *( u32 * ) rsn;
+		rsn += 4;
+
+		for ( map_ent = map; map_ent->oui_type != END_MAGIC; map_ent++ )
+			if ( map_ent->oui_type == ( desc & OUI_TYPE_MASK ) )
+				break;
+
+		/* Use first cipher as a fallback */
+		if ( ! map_ret )
+			map_ret = map_ent;
+
+		/* Once we find one we support, use it */
+		if ( ok & ( 1 << map_ent->net80211_type ) ) {
+			map_ret = map_ent;
+			break;
+		}
+	}
+
+	if ( ndesc > 0 )
+		rsn += 4 * ndesc;
+
+	*rsnp = rsn;
+	return map_ret;
+}
+
+
+/**
+ * Find the RSN or WPA information element in the provided beacon frame
+ *
+ * @v ie	Pointer to first information element to check
+ * @v ie_end	Pointer to end of information element space
+ * @ret is_rsn	TRUE if returned IE is RSN, FALSE if it's WPA
+ * @ret end	Pointer to byte immediately after last byte of data
+ * @ret data	Pointer to first byte of data (the `version' field)
+ *
+ * If both an RSN and a WPA information element are found, this
+ * function will return the first one seen, which by ordering rules
+ * should always prefer the newer RSN IE.
+ *
+ * If no RSN or WPA infomration element is found, returns @c NULL and
+ * leaves @a is_rsn and @a end in an undefined state.
+ *
+ * This function will not return a pointer to an information element
+ * that states it extends past the tail of the io_buffer, or whose @a
+ * version field is incorrect.
+ */
+u8 * sec80211_find_rsn ( union ieee80211_ie *ie, void *ie_end,
+			 int *is_rsn, u8 **end )
+{
+	u8 *rsn = NULL;
+
+	if ( ! ieee80211_ie_bound ( ie, ie_end ) )
+		return NULL;
+
+	while ( ie ) {
+		if ( ie->id == IEEE80211_IE_VENDOR &&
+		     ie->vendor.oui == IEEE80211_WPA_OUI_VEN ) {
+			DBG ( "RSN detect: old-style WPA IE found\n" );
+			rsn = &ie->vendor.data[0];
+			*end = rsn + ie->len - 4;
+			*is_rsn = 0;
+		} else if ( ie->id == IEEE80211_IE_RSN ) {
+			DBG ( "RSN detect: 802.11i RSN IE found\n" );
+			rsn = ( u8 * ) &ie->rsn.version;
+			*end = rsn + ie->len;
+			*is_rsn = 1;
+		}
+
+		if ( rsn && ( *end > ( u8 * ) ie_end || rsn >= *end ||
+			      *( u16 * ) rsn != IEEE80211_RSN_VERSION ) ) {
+			DBG ( "RSN detect: malformed RSN IE or unknown "
+			      "version, keep trying\n" );
+			rsn = NULL;
+		}
+
+		if ( rsn )
+			break;
+
+		ie = ieee80211_next_ie ( ie, ie_end );
+	}
+
+	if ( ! ie ) {
+		DBG ( "RSN detect: no RSN IE found\n" );
+		return NULL;
+	}
+
+	return rsn;
+}
+
+
+/**
+ * Detect crypto and AKM types from RSN information element
+ *
+ * @v is_rsn	If TRUE, IE is a new-style RSN information element
+ * @v start	Pointer to first byte of @a version field
+ * @v end	Pointer to first byte not in the RSN IE
+ * @ret secprot	Security handshaking protocol used by network
+ * @ret crypt	Cryptosystem used by network
+ * @ret rc	Return status code
+ *
+ * If the IE cannot be parsed, returns an error indication and leaves
+ * @a secprot and @a crypt unchanged.
+ */
+int sec80211_detect_ie ( int is_rsn, u8 *start, u8 *end,
+			 enum net80211_security_proto *secprot,
+			 enum net80211_crypto_alg *crypt )
+{
+	enum net80211_security_proto sp;
+	enum net80211_crypto_alg cr;
+	struct descriptor_map *map;
+	u8 *rsn = start;
+
+	/* Set some defaults */
+	cr = ( is_rsn ? NET80211_CRYPT_CCMP : NET80211_CRYPT_TKIP );
+	sp = NET80211_SECPROT_EAP;
+
+	rsn += 2;		/* version - already checked */
+	rsn += 4;		/* group cipher - we don't use it here */
+
+	if ( rsn >= end )
+		goto done;
+
+	/* Pick crypto algorithm */
+	map = rsn_pick_desc ( &rsn, end, rsn_cipher_map,
+			      table_start ( NET80211_CRYPTOS ),
+			      table_end ( NET80211_CRYPTOS ) );
+	if ( ! map )
+		goto invalid_rsn;
+
+	cr = map->net80211_type;
+
+	if ( rsn >= end )
+		goto done;
+
+	/* Pick handshaking algorithm */
+	map = rsn_pick_desc ( &rsn, end, rsn_akm_map,
+			      table_start ( NET80211_HANDSHAKERS ),
+			      table_end ( NET80211_HANDSHAKERS ) );
+	if ( ! map )
+		goto invalid_rsn;
+
+	sp = map->net80211_type;
+
+ done:
+	DBG ( "RSN detect: OK, crypto type %d, secprot type %d\n", cr, sp );
+	*secprot = sp;
+	*crypt = cr;
+	return 0;
+
+ invalid_rsn:
+	DBG ( "RSN detect: invalid RSN IE\n" );
+	return -EINVAL;
+}
+
+
+/**
+ * Detect the cryptosystem and handshaking protocol used by an 802.11 network
+ *
+ * @v iob	I/O buffer containing beacon frame
+ * @ret secprot	Security handshaking protocol used by network
+ * @ret crypt	Cryptosystem used by network
+ * @ret rc	Return status code
+ *
+ * This function uses weak linkage, as it must be called from generic
+ * contexts but should only be linked in if some encryption is
+ * supported; you must test its address against @c NULL before calling
+ * it. If it does not exist, any network with the PRIVACY bit set in
+ * beacon->capab should be considered unknown.
+ */
+int sec80211_detect ( struct io_buffer *iob,
+		      enum net80211_security_proto *secprot,
+		      enum net80211_crypto_alg *crypt )
+{
+	struct ieee80211_frame *hdr = iob->data;
+	struct ieee80211_beacon *beacon =
+		( struct ieee80211_beacon * ) hdr->data;
+	u8 *rsn, *rsn_end;
+	int is_rsn, rc;
+
+	*crypt = NET80211_CRYPT_UNKNOWN;
+	*secprot = NET80211_SECPROT_UNKNOWN;
+
+	/* Find RSN or WPA IE */
+	if ( ! ( rsn = sec80211_find_rsn ( beacon->info_element, iob->tail,
+					   &is_rsn, &rsn_end ) ) ) {
+		/* No security IE at all; either WEP or no security. */
+		*secprot = NET80211_SECPROT_NONE;
+
+		if ( beacon->capability & IEEE80211_CAPAB_PRIVACY )
+			*crypt = NET80211_CRYPT_WEP;
+		else
+			*crypt = NET80211_CRYPT_NONE;
+
+		return 0;
+	}
+
+	/* Determine type of security */
+	if ( ( rc = sec80211_detect_ie ( is_rsn, rsn, rsn_end, secprot,
+					 crypt ) ) == 0 )
+		return 0;
+
+	/* If we get here, the RSN IE was invalid */
+
+	*crypt = NET80211_CRYPT_UNKNOWN;
+	*secprot = NET80211_SECPROT_UNKNOWN;
+	DBG ( "Failed to handle RSN IE:\n" );
+	DBG_HD ( rsn, rsn_end - rsn );
+	return rc;
+}
+
+
+/**
+ * Determine RSN descriptor for specified net80211 ID
+ *
+ * @v id	net80211 ID value
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
+ * @v map	Map to use in translation
+ * @ret desc	RSN descriptor, or 0 on error
+ *
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
+ * descriptor.
+ */
+static u32 rsn_get_desc ( unsigned id, int rsnie, struct descriptor_map *map )
+{
+	u32 vendor = ( rsnie ? IEEE80211_RSN_OUI : IEEE80211_WPA_OUI );
+
+	for ( ; map->oui_type != END_MAGIC; map++ ) {
+		if ( map->net80211_type == id )
+			return map->oui_type | vendor;
+	}
+
+	return 0;
+}
+
+/**
+ * Determine RSN descriptor for specified net80211 cryptosystem number
+ *
+ * @v crypt	Cryptosystem number
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
+ * @ret desc	RSN descriptor
+ *
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
+ * descriptor.
+ */
+u32 sec80211_rsn_get_crypto_desc ( enum net80211_crypto_alg crypt, int rsnie )
+{
+	return rsn_get_desc ( crypt, rsnie, rsn_cipher_map );
+}
+
+/**
+ * Determine RSN descriptor for specified net80211 handshaker number
+ *
+ * @v secprot	Handshaker number
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
+ * @ret desc	RSN descriptor
+ *
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
+ * descriptor.
+ */
+u32 sec80211_rsn_get_akm_desc ( enum net80211_security_proto secprot,
+				int rsnie )
+{
+	return rsn_get_desc ( secprot, rsnie, rsn_akm_map );
+}
+
+/**
+ * Determine net80211 cryptosystem number from RSN descriptor
+ *
+ * @v desc	RSN descriptor
+ * @ret crypt	net80211 cryptosystem enumeration value
+ */
+enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt ( u32 desc )
+{
+	struct descriptor_map *map = rsn_cipher_map;
+
+	for ( ; map->oui_type != END_MAGIC; map++ ) {
+		if ( map->oui_type == ( desc & OUI_TYPE_MASK ) )
+			break;
+	}
+
+	return map->net80211_type;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/wep.c b/qemu-0.15.x/roms/ipxe/src/net/80211/wep.c
new file mode 100644
index 0000000..3b10455
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/wep.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <ipxe/sec80211.h>
+#include <ipxe/crypto.h>
+#include <ipxe/arc4.h>
+#include <ipxe/crc32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/** @file
+ *
+ * The WEP wireless encryption method (insecure!)
+ *
+ * The data field in a WEP-encrypted packet contains a 3-byte
+ * initialisation vector, one-byte Key ID field (only the bottom two
+ * bits are ever used), encrypted data, and a 4-byte encrypted CRC of
+ * the plaintext data, called the ICV. To decrypt it, the IV is
+ * prepended to the shared key and the data stream (including ICV) is
+ * run through the ARC4 stream cipher; if the ICV matches a CRC32
+ * calculated on the plaintext, the packet is valid.
+ *
+ * For efficiency and code-size reasons, this file assumes it is
+ * running on a little-endian machine.
+ */
+
+/** Length of WEP initialisation vector */
+#define WEP_IV_LEN	3
+
+/** Length of WEP key ID byte */
+#define WEP_KID_LEN	1
+
+/** Length of WEP ICV checksum */
+#define WEP_ICV_LEN	4
+
+/** Maximum length of WEP key */
+#define WEP_MAX_KEY	16
+
+/** Amount of data placed before the encrypted bytes */
+#define WEP_HEADER_LEN	4
+
+/** Amount of data placed after the encrypted bytes */
+#define WEP_TRAILER_LEN	4
+
+/** Total WEP overhead bytes */
+#define WEP_OVERHEAD	8
+
+/** Context for WEP encryption and decryption */
+struct wep_ctx
+{
+	/** Encoded WEP key
+	 *
+	 * The actual key bytes are stored beginning at offset 3, to
+	 * leave room for easily inserting the IV before a particular
+	 * operation.
+	 */
+	u8 key[WEP_IV_LEN + WEP_MAX_KEY];
+
+	/** Length of WEP key (not including IV bytes) */
+	int keylen;
+
+	/** ARC4 context */
+	struct arc4_ctx arc4;
+};
+
+/**
+ * Initialize WEP algorithm
+ *
+ * @v crypto	802.11 cryptographic algorithm
+ * @v key	WEP key to use
+ * @v keylen	Length of WEP key
+ * @v rsc	Initial receive sequence counter (unused)
+ * @ret rc	Return status code
+ *
+ * Standard key lengths are 5 and 13 bytes; 16-byte keys are
+ * occasionally supported as an extension to the standard.
+ */
+static int wep_init ( struct net80211_crypto *crypto, const void *key,
+		      int keylen, const void *rsc __unused )
+{
+	struct wep_ctx *ctx = crypto->priv;
+
+	ctx->keylen = ( keylen > WEP_MAX_KEY ? WEP_MAX_KEY : keylen );
+	memcpy ( ctx->key + WEP_IV_LEN, key, ctx->keylen );
+
+	return 0;
+}
+
+/**
+ * Encrypt packet using WEP
+ *
+ * @v crypto	802.11 cryptographic algorithm
+ * @v iob	I/O buffer of plaintext packet
+ * @ret eiob	Newly allocated I/O buffer for encrypted packet, or NULL
+ *
+ * If memory allocation fails, @c NULL is returned.
+ */
+static struct io_buffer * wep_encrypt ( struct net80211_crypto *crypto,
+					struct io_buffer *iob )
+{
+	struct wep_ctx *ctx = crypto->priv;
+	struct io_buffer *eiob;
+	struct ieee80211_frame *hdr;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( iob ) - hdrlen;
+	int newlen = hdrlen + datalen + WEP_OVERHEAD;
+	u32 iv, icv;
+
+	eiob = alloc_iob ( newlen );
+	if ( ! eiob )
+		return NULL;
+
+	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
+	hdr = eiob->data;
+	hdr->fc |= IEEE80211_FC_PROTECTED;
+
+	/* Calculate IV, put it in the header (with key ID byte = 0), and
+	   set it up at the start of the encryption key. */
+	iv = random() & 0xffffff; /* IV in bottom 3 bytes, top byte = KID = 0 */
+	memcpy ( iob_put ( eiob, WEP_HEADER_LEN ), &iv, WEP_HEADER_LEN );
+	memcpy ( ctx->key, &iv, WEP_IV_LEN );
+
+	/* Encrypt the data using RC4 */
+	cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
+			ctx->keylen + WEP_IV_LEN );
+	cipher_encrypt ( &arc4_algorithm, &ctx->arc4, iob->data + hdrlen,
+			 iob_put ( eiob, datalen ), datalen );
+
+	/* Add ICV */
+	icv = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
+	cipher_encrypt ( &arc4_algorithm, &ctx->arc4, &icv,
+			 iob_put ( eiob, WEP_ICV_LEN ), WEP_ICV_LEN );
+
+	return eiob;
+}
+
+/**
+ * Decrypt packet using WEP
+ *
+ * @v crypto	802.11 cryptographic algorithm
+ * @v eiob	I/O buffer of encrypted packet
+ * @ret iob	Newly allocated I/O buffer for plaintext packet, or NULL
+ *
+ * If a consistency check for the decryption fails (usually indicating
+ * an invalid key), @c NULL is returned.
+ */
+static struct io_buffer * wep_decrypt ( struct net80211_crypto *crypto,
+					struct io_buffer *eiob )
+{
+	struct wep_ctx *ctx = crypto->priv;
+	struct io_buffer *iob;
+	struct ieee80211_frame *hdr;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( eiob ) - hdrlen - WEP_OVERHEAD;
+	int newlen = hdrlen + datalen;
+	u32 iv, icv, crc;
+
+	iob = alloc_iob ( newlen );
+	if ( ! iob )
+		return NULL;
+
+	memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
+	hdr = iob->data;
+	hdr->fc &= ~IEEE80211_FC_PROTECTED;
+
+	/* Strip off IV and use it to initialize cryptosystem */
+	memcpy ( &iv, eiob->data + hdrlen, 4 );
+	iv &= 0xffffff;		/* ignore key ID byte */
+	memcpy ( ctx->key, &iv, WEP_IV_LEN );
+
+	/* Decrypt the data using RC4 */
+	cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
+			ctx->keylen + WEP_IV_LEN );
+	cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
+			 WEP_HEADER_LEN, iob_put ( iob, datalen ), datalen );
+
+	/* Strip off ICV and verify it */
+	cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
+			 WEP_HEADER_LEN + datalen, &icv, WEP_ICV_LEN );
+	crc = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
+	if ( crc != icv ) {
+		DBGC ( crypto, "WEP %p CRC mismatch: expect %08x, get %08x\n",
+		       crypto, icv, crc );
+		free_iob ( iob );
+		return NULL;
+	}
+	return iob;
+}
+
+/** WEP cryptosystem for 802.11 */
+struct net80211_crypto wep_crypto __net80211_crypto = {
+	.algorithm = NET80211_CRYPT_WEP,
+	.init = wep_init,
+	.encrypt = wep_encrypt,
+	.decrypt = wep_decrypt,
+	.priv_len = sizeof ( struct wep_ctx ),
+};
+
+/**
+ * Initialize trivial 802.11 security handshaker
+ *
+ * @v dev	802.11 device
+ * @v ctx	Security handshaker
+ *
+ * This simply fetches a WEP key from netX/key, and if it exists,
+ * installs WEP cryptography on the 802.11 device. No real handshaking
+ * is performed.
+ */
+static int trivial_init ( struct net80211_device *dev )
+{
+	u8 key[WEP_MAX_KEY];	/* support up to 128-bit keys */
+	int len;
+	int rc;
+
+	if ( dev->associating &&
+	     dev->associating->crypto == NET80211_CRYPT_NONE )
+		return 0;	/* no crypto? OK. */
+
+	len = fetch_setting ( netdev_settings ( dev->netdev ),
+			      &net80211_key_setting, key, WEP_MAX_KEY );
+
+	if ( len <= 0 ) {
+		DBGC ( dev, "802.11 %p cannot do WEP without a key\n", dev );
+		return -EACCES;
+	}
+
+	/* Full 128-bit keys are a nonstandard extension, but they're
+	   utterly trivial to support, so we do. */
+	if ( len != 5 && len != 13 && len != 16 ) {
+		DBGC ( dev, "802.11 %p invalid WEP key length %d\n",
+		       dev, len );
+		return -EINVAL;
+	}
+
+	DBGC ( dev, "802.11 %p installing %d-bit WEP\n", dev, len * 8 );
+
+	rc = sec80211_install ( &dev->crypto, NET80211_CRYPT_WEP, key, len,
+				NULL );
+	if ( rc < 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Check for key change on trivial 802.11 security handshaker
+ *
+ * @v dev	802.11 device
+ * @v ctx	Security handshaker
+ */
+static int trivial_change_key ( struct net80211_device *dev )
+{
+	u8 key[WEP_MAX_KEY];
+	int len;
+	int change = 0;
+
+	/* If going from WEP to clear, or something else to WEP, reassociate. */
+	if ( ! dev->crypto || ( dev->crypto->init != wep_init ) )
+		change ^= 1;
+
+	len = fetch_setting ( netdev_settings ( dev->netdev ),
+			      &net80211_key_setting, key, WEP_MAX_KEY );
+	if ( len <= 0 )
+		change ^= 1;
+
+	/* Changing crypto type => return nonzero to reassociate. */
+	if ( change )
+		return -EINVAL;
+
+	/* Going from no crypto to still no crypto => nothing to do. */
+	if ( len <= 0 )
+		return 0;
+
+	/* Otherwise, reinitialise WEP with new key. */
+	return wep_init ( dev->crypto, key, len, NULL );
+}
+
+/** Trivial 802.11 security handshaker */
+struct net80211_handshaker trivial_handshaker __net80211_handshaker = {
+	.protocol = NET80211_SECPROT_NONE,
+	.init = trivial_init,
+	.change_key = trivial_change_key,
+	.priv_len = 0,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/wpa.c b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa.c
new file mode 100644
index 0000000..38ddb91
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <ipxe/sec80211.h>
+#include <ipxe/wpa.h>
+#include <ipxe/eapol.h>
+#include <ipxe/crypto.h>
+#include <ipxe/arc4.h>
+#include <ipxe/crc32.h>
+#include <ipxe/sha1.h>
+#include <ipxe/hmac.h>
+#include <ipxe/list.h>
+#include <ipxe/ethernet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/** @file
+ *
+ * Handler for the aspects of WPA handshaking that are independent of
+ * 802.1X/PSK or TKIP/CCMP; this mostly involves the 4-Way Handshake.
+ */
+
+/** List of WPA contexts in active use. */
+struct list_head wpa_contexts = LIST_HEAD_INIT ( wpa_contexts );
+
+
+/**
+ * Return an error code and deauthenticate
+ *
+ * @v ctx	WPA common context
+ * @v rc	Return status code
+ * @ret rc	The passed return status code
+ */
+static int wpa_fail ( struct wpa_common_ctx *ctx, int rc )
+{
+	net80211_deauthenticate ( ctx->dev, rc );
+	return rc;
+}
+
+
+/**
+ * Find a cryptosystem handler structure from a crypto ID
+ *
+ * @v crypt	Cryptosystem ID
+ * @ret crypto	Cryptosystem handler structure
+ *
+ * If support for @a crypt is not compiled in to iPXE, or if @a crypt
+ * is NET80211_CRYPT_UNKNOWN, returns @c NULL.
+ */
+static struct net80211_crypto *
+wpa_find_cryptosystem ( enum net80211_crypto_alg crypt )
+{
+	struct net80211_crypto *crypto;
+
+	for_each_table_entry ( crypto, NET80211_CRYPTOS ) {
+		if ( crypto->algorithm == crypt )
+			return crypto;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * Find WPA key integrity and encryption handler from key version field
+ *
+ * @v ver	Version bits of EAPOL-Key info field
+ * @ret kie	Key integrity and encryption handler
+ */
+struct wpa_kie * wpa_find_kie ( int version )
+{
+	struct wpa_kie *kie;
+
+	for_each_table_entry ( kie, WPA_KIES ) {
+		if ( kie->version == version )
+			return kie;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * Construct RSN or WPA information element
+ *
+ * @v dev	802.11 device
+ * @ret ie_ret	RSN or WPA information element
+ * @ret rc	Return status code
+ *
+ * This function allocates, fills, and returns a RSN or WPA
+ * information element suitable for including in an association
+ * request frame to the network identified by @c dev->associating.
+ * If it is impossible to construct an information element consistent
+ * with iPXE's capabilities that is compatible with that network, or
+ * if none should be sent because that network's beacon included no
+ * security information, returns an error indication and leaves
+ * @a ie_ret unchanged.
+ *
+ * The returned IE will be of the same type (RSN or WPA) as was
+ * included in the beacon for the network it is destined for.
+ */
+int wpa_make_rsn_ie ( struct net80211_device *dev, union ieee80211_ie **ie_ret )
+{
+	u8 *rsn, *rsn_end;
+	int is_rsn;
+	u32 group_cipher;
+	enum net80211_crypto_alg gcrypt;
+	int ie_len;
+	u8 *iep;
+	struct ieee80211_ie_rsn *ie;
+	struct ieee80211_frame *hdr;
+	struct ieee80211_beacon *beacon;
+
+	if ( ! dev->associating ) {
+		DBG ( "WPA: Can't make RSN IE for a non-associating device\n" );
+		return -EINVAL;
+	}
+
+	hdr = dev->associating->beacon->data;
+	beacon = ( struct ieee80211_beacon * ) hdr->data;
+	rsn = sec80211_find_rsn ( beacon->info_element,
+				  dev->associating->beacon->tail, &is_rsn,
+				  &rsn_end );
+	if ( ! rsn ) {
+		DBG ( "WPA: Can't make RSN IE when we didn't get one\n" );
+		return -EINVAL;
+	}
+
+	rsn += 2;		/* skip version */
+	group_cipher = *( u32 * ) rsn;
+	gcrypt = sec80211_rsn_get_net80211_crypt ( group_cipher );
+
+	if ( ! wpa_find_cryptosystem ( gcrypt ) ||
+	     ! wpa_find_cryptosystem ( dev->associating->crypto ) ) {
+		DBG ( "WPA: No support for (GC:%d, PC:%d)\n",
+		      gcrypt, dev->associating->crypto );
+		return -ENOTSUP;
+	}
+
+	/* Everything looks good - make our IE. */
+
+	/* WPA IEs need 4 more bytes for the OUI+type */
+	ie_len = ieee80211_rsn_size ( 1, 1, 0, is_rsn ) + ( 4 * ! is_rsn );
+	iep = malloc ( ie_len );
+	if ( ! iep )
+		return -ENOMEM;
+
+	*ie_ret = ( union ieee80211_ie * ) iep;
+
+	/* Store ID and length bytes. */
+	*iep++ = ( is_rsn ? IEEE80211_IE_RSN : IEEE80211_IE_VENDOR );
+	*iep++ = ie_len - 2;
+
+	/* Store OUI+type for WPA IEs. */
+	if ( ! is_rsn ) {
+		*( u32 * ) iep = IEEE80211_WPA_OUI_VEN;
+		iep += 4;
+	}
+
+	/* If this is a WPA IE, the id and len bytes in the
+	   ieee80211_ie_rsn structure will not be valid, but by doing
+	   the cast we can fill all the other fields much more
+	   readily. */
+
+	ie = ( struct ieee80211_ie_rsn * ) ( iep - 2 );
+	ie->version = IEEE80211_RSN_VERSION;
+	ie->group_cipher = group_cipher;
+	ie->pairwise_count = 1;
+	ie->pairwise_cipher[0] =
+		sec80211_rsn_get_crypto_desc ( dev->associating->crypto,
+					       is_rsn );
+	ie->akm_count = 1;
+	ie->akm_list[0] =
+		sec80211_rsn_get_akm_desc ( dev->associating->handshaking,
+					    is_rsn );
+	if ( is_rsn ) {
+		ie->rsn_capab = 0;
+		ie->pmkid_count = 0;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Set up generic WPA support to handle 4-Way Handshake
+ *
+ * @v dev	802.11 device
+ * @v ctx	WPA common context
+ * @v pmk	Pairwise Master Key to use for session
+ * @v pmk_len	Length of PMK, almost always 32
+ * @ret rc	Return status code
+ */
+int wpa_start ( struct net80211_device *dev, struct wpa_common_ctx *ctx,
+		const void *pmk, size_t pmk_len )
+{
+	struct io_buffer *iob;
+	struct ieee80211_frame *hdr;
+	struct ieee80211_beacon *beacon;
+	u8 *ap_rsn_ie = NULL, *ap_rsn_ie_end;
+
+	if ( ! dev->rsn_ie || ! dev->associating )
+		return -EINVAL;
+
+	ctx->dev = dev;
+	memcpy ( ctx->pmk, pmk, ctx->pmk_len = pmk_len );
+	ctx->state = WPA_READY;
+	ctx->replay = ~0ULL;
+
+	iob = dev->associating->beacon;
+	hdr = iob->data;
+	beacon = ( struct ieee80211_beacon * ) hdr->data;
+	ap_rsn_ie = sec80211_find_rsn ( beacon->info_element, iob->tail,
+					&ctx->ap_rsn_is_rsn, &ap_rsn_ie_end );
+	if ( ap_rsn_ie ) {
+		ctx->ap_rsn_ie = malloc ( ap_rsn_ie_end - ap_rsn_ie );
+		if ( ! ctx->ap_rsn_ie )
+			return -ENOMEM;
+		memcpy ( ctx->ap_rsn_ie, ap_rsn_ie, ap_rsn_ie_end - ap_rsn_ie );
+		ctx->ap_rsn_ie_len = ap_rsn_ie_end - ap_rsn_ie;
+	} else {
+		return -ENOENT;
+	}
+
+	ctx->crypt = dev->associating->crypto;
+	ctx->gcrypt = NET80211_CRYPT_UNKNOWN;
+
+	list_add_tail ( &ctx->list, &wpa_contexts );
+	return 0;
+}
+
+
+/**
+ * Disable handling of received WPA handshake frames
+ *
+ * @v dev	802.11 device
+ */
+void wpa_stop ( struct net80211_device *dev )
+{
+	struct wpa_common_ctx *ctx, *tmp;
+
+	list_for_each_entry_safe ( ctx, tmp, &wpa_contexts, list ) {
+		if ( ctx->dev == dev ) {
+			free ( ctx->ap_rsn_ie );
+			ctx->ap_rsn_ie = NULL;
+			list_del ( &ctx->list );
+		}
+	}
+}
+
+
+/**
+ * Derive pairwise transient key
+ *
+ * @v ctx	WPA common context
+ */
+static void wpa_derive_ptk ( struct wpa_common_ctx *ctx )
+{
+	struct {
+		u8 mac1[ETH_ALEN];
+		u8 mac2[ETH_ALEN];
+		u8 nonce1[WPA_NONCE_LEN];
+		u8 nonce2[WPA_NONCE_LEN];
+	} __attribute__ (( packed )) ptk_data;
+
+	/* The addresses and nonces are stored in numerical order (!) */
+
+	if ( memcmp ( ctx->dev->netdev->ll_addr, ctx->dev->bssid,
+		      ETH_ALEN ) < 0 ) {
+		memcpy ( ptk_data.mac1, ctx->dev->netdev->ll_addr, ETH_ALEN );
+		memcpy ( ptk_data.mac2, ctx->dev->bssid, ETH_ALEN );
+	} else {
+		memcpy ( ptk_data.mac1, ctx->dev->bssid, ETH_ALEN );
+		memcpy ( ptk_data.mac2, ctx->dev->netdev->ll_addr, ETH_ALEN );
+	}
+
+	if ( memcmp ( ctx->Anonce, ctx->Snonce, WPA_NONCE_LEN ) < 0 ) {
+		memcpy ( ptk_data.nonce1, ctx->Anonce, WPA_NONCE_LEN );
+		memcpy ( ptk_data.nonce2, ctx->Snonce, WPA_NONCE_LEN );
+	} else {
+		memcpy ( ptk_data.nonce1, ctx->Snonce, WPA_NONCE_LEN );
+		memcpy ( ptk_data.nonce2, ctx->Anonce, WPA_NONCE_LEN );
+	}
+
+	DBGC2 ( ctx, "WPA %p A1 %s, A2 %s\n", ctx, eth_ntoa ( ptk_data.mac1 ),
+	       eth_ntoa ( ptk_data.mac2 ) );
+	DBGC2 ( ctx, "WPA %p Nonce1, Nonce2:\n", ctx );
+	DBGC2_HD ( ctx, ptk_data.nonce1, WPA_NONCE_LEN );
+	DBGC2_HD ( ctx, ptk_data.nonce2, WPA_NONCE_LEN );
+
+	prf_sha1 ( ctx->pmk, ctx->pmk_len,
+		   "Pairwise key expansion",
+		   &ptk_data, sizeof ( ptk_data ),
+		   &ctx->ptk, sizeof ( ctx->ptk ) );
+
+	DBGC2 ( ctx, "WPA %p PTK:\n", ctx );
+	DBGC2_HD ( ctx, &ctx->ptk, sizeof ( ctx->ptk ) );
+}
+
+
+/**
+ * Install pairwise transient key
+ *
+ * @v ctx	WPA common context
+ * @v len	Key length (16 for CCMP, 32 for TKIP)
+ * @ret rc	Return status code
+ */
+static inline int wpa_install_ptk ( struct wpa_common_ctx *ctx, int len )
+{
+	DBGC ( ctx, "WPA %p: installing %d-byte pairwise transient key\n",
+	       ctx, len );
+	DBGC2_HD ( ctx, &ctx->ptk.tk, len );
+
+	return sec80211_install ( &ctx->dev->crypto, ctx->crypt,
+				  &ctx->ptk.tk, len, NULL );
+}
+
+/**
+ * Install group transient key
+ *
+ * @v ctx	WPA common context
+ * @v len	Key length (16 for CCMP, 32 for TKIP)
+ * @v rsc	Receive sequence counter field in EAPOL-Key packet
+ * @ret rc	Return status code
+ */
+static inline int wpa_install_gtk ( struct wpa_common_ctx *ctx, int len,
+				    const void *rsc )
+{
+	DBGC ( ctx, "WPA %p: installing %d-byte group transient key\n",
+	       ctx, len );
+	DBGC2_HD ( ctx, &ctx->gtk.tk, len );
+
+	return sec80211_install ( &ctx->dev->gcrypto, ctx->gcrypt,
+				  &ctx->gtk.tk, len, rsc );
+}
+
+/**
+ * Search for group transient key, and install it if found
+ *
+ * @v ctx	WPA common context
+ * @v ie	Pointer to first IE in key data field
+ * @v ie_end	Pointer to first byte not in key data field
+ * @v rsc	Receive sequence counter field in EAPOL-Key packet
+ * @ret rc	Return status code
+ */
+static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx,
+				   union ieee80211_ie *ie, void *ie_end,
+				   const void *rsc )
+{
+	struct wpa_kde *kde;
+
+	if ( ! ieee80211_ie_bound ( ie, ie_end ) )
+		return -ENOENT;
+
+	while ( ie ) {
+		if ( ie->id == IEEE80211_IE_VENDOR &&
+		     ie->vendor.oui == WPA_KDE_GTK )
+			break;
+
+		ie = ieee80211_next_ie ( ie, ie_end );
+	}
+
+	if ( ! ie )
+		return -ENOENT;
+
+	if ( ie->len - 6u > sizeof ( ctx->gtk.tk ) ) {
+		DBGC ( ctx, "WPA %p: GTK KDE is too long (%d bytes, max %zd)\n",
+		       ctx, ie->len - 4, sizeof ( ctx->gtk.tk ) );
+		return -EINVAL;
+	}
+
+	/* XXX We ignore key ID for now. */
+	kde = ( struct wpa_kde * ) ie;
+	memcpy ( &ctx->gtk.tk, &kde->gtk_encap.gtk, kde->len - 6 );
+
+	return wpa_install_gtk ( ctx, kde->len - 6, rsc );
+}
+
+
+/**
+ * Allocate I/O buffer for construction of outgoing EAPOL-Key frame
+ *
+ * @v kdlen	Maximum number of bytes in the Key Data field
+ * @ret iob	Newly allocated I/O buffer
+ *
+ * The returned buffer will have space reserved for the link-layer and
+ * EAPOL headers, and will have @c iob->tail pointing to the start of
+ * the Key Data field. Thus, it is necessary to use iob_put() in
+ * filling the Key Data.
+ */
+static struct io_buffer * wpa_alloc_frame ( int kdlen )
+{
+	struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) +
+					    kdlen + EAPOL_HDR_LEN +
+					    MAX_LL_HEADER_LEN );
+	if ( ! ret )
+		return NULL;
+
+	iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN );
+	memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0,
+		 sizeof ( struct eapol_key_pkt ) );
+
+	return ret;
+}
+
+
+/**
+ * Send EAPOL-Key packet
+ *
+ * @v iob	I/O buffer, with sufficient headroom for headers
+ * @v dev	802.11 device
+ * @v kie	Key integrity and encryption handler
+ * @v is_rsn	If TRUE, handshake uses new RSN format
+ * @ret rc	Return status code
+ *
+ * If a KIE is specified, the MIC will be filled in before transmission.
+ */
+static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx,
+			    struct wpa_kie *kie )
+{
+	struct eapol_key_pkt *pkt = iob->data;
+	struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN );
+
+	pkt->info = htons ( pkt->info );
+	pkt->keysize = htons ( pkt->keysize );
+	pkt->datalen = htons ( pkt->datalen );
+	pkt->replay = cpu_to_be64 ( pkt->replay );
+	eapol->version = EAPOL_THIS_VERSION;
+	eapol->type = EAPOL_TYPE_KEY;
+	eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) );
+
+	memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
+	if ( kie )
+		kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN +
+			   sizeof ( *pkt ) + ntohs ( pkt->datalen ),
+			   pkt->mic );
+
+	return net_tx ( iob, ctx->dev->netdev, &eapol_protocol,
+			ctx->dev->bssid, ctx->dev->netdev->ll_addr );
+}
+
+
+/**
+ * Send second frame in 4-Way Handshake
+ *
+ * @v ctx	WPA common context
+ * @v pkt	First frame, to which this is a reply
+ * @v is_rsn	If TRUE, handshake uses new RSN format
+ * @v kie	Key integrity and encryption handler
+ * @ret rc	Return status code
+ */
+static int wpa_send_2_of_4 ( struct wpa_common_ctx *ctx,
+			     struct eapol_key_pkt *pkt, int is_rsn,
+			     struct wpa_kie *kie )
+{
+	struct io_buffer *iob = wpa_alloc_frame ( ctx->dev->rsn_ie->len + 2 );
+	struct eapol_key_pkt *npkt;
+
+	if ( ! iob )
+		return -ENOMEM;
+
+	npkt = iob->data;
+	memcpy ( npkt, pkt, sizeof ( *pkt ) );
+	npkt->info &= ~EAPOL_KEY_INFO_KEY_ACK;
+	npkt->info |= EAPOL_KEY_INFO_KEY_MIC;
+	if ( is_rsn )
+		npkt->keysize = 0;
+	memcpy ( npkt->nonce, ctx->Snonce, sizeof ( npkt->nonce ) );
+	npkt->datalen = ctx->dev->rsn_ie->len + 2;
+	memcpy ( iob_put ( iob, npkt->datalen ), ctx->dev->rsn_ie,
+		 npkt->datalen );
+
+	DBGC ( ctx, "WPA %p: sending 2/4\n", ctx );
+
+	return wpa_send_eapol ( iob, ctx, kie );
+}
+
+
+/**
+ * Handle receipt of first frame in 4-Way Handshake
+ *
+ * @v ctx	WPA common context
+ * @v pkt	EAPOL-Key packet
+ * @v is_rsn	If TRUE, frame uses new RSN format
+ * @v kie	Key integrity and encryption handler
+ * @ret rc	Return status code
+ */
+static int wpa_handle_1_of_4 ( struct wpa_common_ctx *ctx,
+			       struct eapol_key_pkt *pkt, int is_rsn,
+			       struct wpa_kie *kie )
+{
+	if ( ctx->state == WPA_WAITING )
+		return -EINVAL;
+
+	ctx->state = WPA_WORKING;
+	memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) );
+	if ( ! ctx->have_Snonce ) {
+		get_random_bytes ( ctx->Snonce, sizeof ( ctx->Snonce ) );
+		ctx->have_Snonce = 1;
+	}
+
+	DBGC ( ctx, "WPA %p: received 1/4, looks OK\n", ctx );
+
+	wpa_derive_ptk ( ctx );
+
+	return wpa_send_2_of_4 ( ctx, pkt, is_rsn, kie );
+}
+
+
+/**
+ * Send fourth frame in 4-Way Handshake, or second in Group Key Handshake
+ *
+ * @v ctx	WPA common context
+ * @v pkt	EAPOL-Key packet for frame to which we're replying
+ * @v is_rsn	If TRUE, frame uses new RSN format
+ * @v kie	Key integrity and encryption handler
+ * @ret rc	Return status code
+ */
+static int wpa_send_final ( struct wpa_common_ctx *ctx,
+			    struct eapol_key_pkt *pkt, int is_rsn,
+			    struct wpa_kie *kie )
+{
+	struct io_buffer *iob = wpa_alloc_frame ( 0 );
+	struct eapol_key_pkt *npkt;
+
+	if ( ! iob )
+		return -ENOMEM;
+
+	npkt = iob->data;
+	memcpy ( npkt, pkt, sizeof ( *pkt ) );
+	npkt->info &= ~( EAPOL_KEY_INFO_KEY_ACK | EAPOL_KEY_INFO_INSTALL |
+			 EAPOL_KEY_INFO_KEY_ENC );
+	if ( is_rsn )
+		npkt->keysize = 0;
+	memset ( npkt->nonce, 0, sizeof ( npkt->nonce ) );
+	memset ( npkt->iv, 0, sizeof ( npkt->iv ) );
+	npkt->datalen = 0;
+
+	if ( npkt->info & EAPOL_KEY_INFO_TYPE )
+		DBGC ( ctx, "WPA %p: sending 4/4\n", ctx );
+	else
+		DBGC ( ctx, "WPA %p: sending 2/2\n", ctx );
+
+	return wpa_send_eapol ( iob, ctx, kie );
+
+}
+
+
+/**
+ * Handle receipt of third frame in 4-Way Handshake
+ *
+ * @v ctx	WPA common context
+ * @v pkt	EAPOL-Key packet
+ * @v is_rsn	If TRUE, frame uses new RSN format
+ * @v kie	Key integrity and encryption handler
+ * @ret rc	Return status code
+ */
+static int wpa_handle_3_of_4 ( struct wpa_common_ctx *ctx,
+			       struct eapol_key_pkt *pkt, int is_rsn,
+			       struct wpa_kie *kie )
+{
+	int rc;
+	u8 *this_rsn, *this_rsn_end;
+	u8 *new_rsn, *new_rsn_end;
+	int this_is_rsn, new_is_rsn;
+
+	if ( ctx->state == WPA_WAITING )
+		return -EINVAL;
+
+	ctx->state = WPA_WORKING;
+
+	/* Check nonce */
+	if ( memcmp ( ctx->Anonce, pkt->nonce, WPA_NONCE_LEN ) != 0 ) {
+		DBGC ( ctx, "WPA %p ALERT: nonce mismatch in 3/4\n", ctx );
+		return wpa_fail ( ctx, -EACCES );
+	}
+
+	/* Check RSN IE */
+	this_rsn = sec80211_find_rsn ( ( union ieee80211_ie * ) pkt->data,
+				       pkt->data + pkt->datalen,
+				       &this_is_rsn, &this_rsn_end );
+	if ( this_rsn )
+		new_rsn = sec80211_find_rsn ( ( union ieee80211_ie * )
+					              this_rsn_end,
+					      pkt->data + pkt->datalen,
+					      &new_is_rsn, &new_rsn_end );
+	else
+		new_rsn = NULL;
+
+	if ( ! ctx->ap_rsn_ie || ! this_rsn ||
+	     ctx->ap_rsn_ie_len != ( this_rsn_end - this_rsn ) ||
+	     ctx->ap_rsn_is_rsn != this_is_rsn ||
+	     memcmp ( ctx->ap_rsn_ie, this_rsn, ctx->ap_rsn_ie_len ) != 0 ) {
+		DBGC ( ctx, "WPA %p ALERT: RSN mismatch in 3/4\n", ctx );
+		DBGC2 ( ctx, "WPA %p RSNs (in 3/4, in beacon):\n", ctx );
+		DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
+		DBGC2_HD ( ctx, ctx->ap_rsn_ie, ctx->ap_rsn_ie_len );
+		return wpa_fail ( ctx, -EACCES );
+	}
+
+	/* Don't switch if they just supplied both styles of IE
+	   simultaneously; we need two RSN IEs or two WPA IEs to
+	   switch ciphers. They'll be immediately consecutive because
+	   of ordering guarantees. */
+	if ( new_rsn && this_is_rsn == new_is_rsn ) {
+		struct net80211_wlan *assoc = ctx->dev->associating;
+		DBGC ( ctx, "WPA %p: accommodating bait-and-switch tactics\n",
+		       ctx );
+		DBGC2 ( ctx, "WPA %p RSNs (in 3/4+beacon, new in 3/4):\n",
+			ctx );
+		DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
+		DBGC2_HD ( ctx, new_rsn, new_rsn_end - new_rsn );
+
+		if ( ( rc = sec80211_detect_ie ( new_is_rsn, new_rsn,
+						 new_rsn_end,
+						 &assoc->handshaking,
+						 &assoc->crypto ) ) != 0 )
+			DBGC ( ctx, "WPA %p: bait-and-switch invalid, staying "
+			       "with original request\n", ctx );
+	} else {
+		new_rsn = this_rsn;
+		new_is_rsn = this_is_rsn;
+		new_rsn_end = this_rsn_end;
+	}
+
+	/* Grab group cryptosystem ID */
+	ctx->gcrypt = sec80211_rsn_get_net80211_crypt ( *( u32 * )
+							( new_rsn + 2 ) );
+
+	/* Check for a GTK, if info field is encrypted */
+	if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
+		rc = wpa_maybe_install_gtk ( ctx,
+					     ( union ieee80211_ie * ) pkt->data,
+					     pkt->data + pkt->datalen,
+					     pkt->rsc );
+		if ( rc < 0 ) {
+			DBGC ( ctx, "WPA %p did not install GTK in 3/4: %s\n",
+			       ctx, strerror ( rc ) );
+			if ( rc != -ENOENT )
+				return wpa_fail ( ctx, rc );
+		}
+	}
+
+	DBGC ( ctx, "WPA %p: received 3/4, looks OK\n", ctx );
+
+	/* Send final message */
+	rc = wpa_send_final ( ctx, pkt, is_rsn, kie );
+	if ( rc < 0 )
+		return wpa_fail ( ctx, rc );
+
+	/* Install PTK */
+	rc = wpa_install_ptk ( ctx, pkt->keysize );
+	if ( rc < 0 ) {
+		DBGC ( ctx, "WPA %p failed to install PTK: %s\n", ctx,
+		       strerror ( rc ) );
+		return wpa_fail ( ctx, rc );
+	}
+
+	/* Mark us as needing a new Snonce if we rekey */
+	ctx->have_Snonce = 0;
+
+	/* Done! */
+	ctx->state = WPA_SUCCESS;
+	return 0;
+}
+
+
+/**
+ * Handle receipt of first frame in Group Key Handshake
+ *
+ * @v ctx	WPA common context
+ * @v pkt	EAPOL-Key packet
+ * @v is_rsn	If TRUE, frame uses new RSN format
+ * @v kie	Key integrity and encryption handler
+ * @ret rc	Return status code
+ */
+static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx,
+			       struct eapol_key_pkt *pkt, int is_rsn,
+			       struct wpa_kie *kie )
+{
+	int rc;
+
+	/*
+	 * WPA and RSN do this completely differently.
+	 *
+	 * The idea of encoding the GTK (or PMKID, or various other
+	 * things) into a KDE that looks like an information element
+	 * is an RSN innovation; old WPA code never encapsulates
+	 * things like that. If it looks like an info element, it
+	 * really is (for the WPA IE check in frames 2/4 and 3/4). The
+	 * "key data encrypted" bit in the info field is also specific
+	 * to RSN.
+	 *
+	 * So from an old WPA host, 3/4 does not contain an
+	 * encapsulated GTK. The first frame of the GK handshake
+	 * contains it, encrypted, but without a KDE wrapper, and with
+	 * the key ID field (which iPXE doesn't use) shoved away in
+	 * the reserved bits in the info field, and the TxRx bit
+	 * stealing the Install bit's spot.
+	 */
+
+	if ( is_rsn && ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) ) {
+		rc = wpa_maybe_install_gtk ( ctx,
+					     ( union ieee80211_ie * ) pkt->data,
+					     pkt->data + pkt->datalen,
+					     pkt->rsc );
+		if ( rc < 0 ) {
+			DBGC ( ctx, "WPA %p: failed to install GTK in 1/2: "
+			       "%s\n", ctx, strerror ( rc ) );
+			return wpa_fail ( ctx, rc );
+		}
+	} else {
+		rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
+				    &pkt->datalen );
+		if ( rc < 0 ) {
+			DBGC ( ctx, "WPA %p: failed to decrypt GTK: %s\n",
+			       ctx, strerror ( rc ) );
+			return rc; /* non-fatal */
+		}
+		if ( pkt->datalen > sizeof ( ctx->gtk.tk ) ) {
+			DBGC ( ctx, "WPA %p: too much GTK data (%d > %zd)\n",
+			       ctx, pkt->datalen, sizeof ( ctx->gtk.tk ) );
+			return wpa_fail ( ctx, -EINVAL );
+		}
+
+		memcpy ( &ctx->gtk.tk, pkt->data, pkt->datalen );
+		wpa_install_gtk ( ctx, pkt->datalen, pkt->rsc );
+	}
+
+	DBGC ( ctx, "WPA %p: received 1/2, looks OK\n", ctx );
+
+	return wpa_send_final ( ctx, pkt, is_rsn, kie );
+}
+
+
+/**
+ * Handle receipt of EAPOL-Key frame for WPA
+ *
+ * @v iob	I/O buffer
+ * @v netdev	Network device
+ * @v ll_dest	Link-layer destination address
+ * @v ll_source	Source link-layer address
+ */
+static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev,
+			  const void *ll_dest __unused,
+			  const void *ll_source )
+{
+	struct net80211_device *dev = net80211_get ( netdev );
+	struct eapol_key_pkt *pkt = iob->data;
+	int is_rsn, found_ctx;
+	struct wpa_common_ctx *ctx;
+	int rc = 0;
+	struct wpa_kie *kie;
+	u8 their_mic[16], our_mic[16];
+
+	if ( pkt->type != EAPOL_KEY_TYPE_WPA &&
+	     pkt->type != EAPOL_KEY_TYPE_RSN ) {
+		DBG ( "EAPOL-Key: packet not of 802.11 type\n" );
+		rc = -EINVAL;
+		goto drop;
+	}
+
+	is_rsn = ( pkt->type == EAPOL_KEY_TYPE_RSN );
+
+	if ( ! dev ) {
+		DBG ( "EAPOL-Key: packet not from 802.11\n" );
+		rc = -EINVAL;
+		goto drop;
+	}
+
+	if ( memcmp ( dev->bssid, ll_source, ETH_ALEN ) != 0 ) {
+		DBG ( "EAPOL-Key: packet not from associated AP\n" );
+		rc = -EINVAL;
+		goto drop;
+	}
+
+	if ( ! ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_ACK ) ) {
+		DBG ( "EAPOL-Key: packet sent in wrong direction\n" );
+		rc = -EINVAL;
+		goto drop;
+	}
+
+	found_ctx = 0;
+	list_for_each_entry ( ctx, &wpa_contexts, list ) {
+		if ( ctx->dev == dev ) {
+			found_ctx = 1;
+			break;
+		}
+	}
+
+	if ( ! found_ctx ) {
+		DBG ( "EAPOL-Key: no WPA context to handle packet for %p\n",
+		      dev );
+		rc = -ENOENT;
+		goto drop;
+	}
+
+	if ( ( void * ) ( pkt + 1 ) + ntohs ( pkt->datalen ) > iob->tail ) {
+		DBGC ( ctx, "WPA %p: packet truncated (has %zd extra bytes, "
+		       "states %d)\n", ctx, iob->tail - ( void * ) ( pkt + 1 ),
+		       ntohs ( pkt->datalen ) );
+		rc = -EINVAL;
+		goto drop;
+	}
+
+	/* Get a handle on key integrity/encryption handler */
+	kie = wpa_find_kie ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
+	if ( ! kie ) {
+		DBGC ( ctx, "WPA %p: no support for packet version %d\n", ctx,
+		       ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
+		rc = wpa_fail ( ctx, -ENOTSUP );
+		goto drop;
+	}
+
+	/* Check MIC */
+	if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) {
+		memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) );
+		memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
+		kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN,
+			   EAPOL_HDR_LEN + sizeof ( *pkt ) +
+			   ntohs ( pkt->datalen ), our_mic );
+		DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx );
+		DBGC2_HD ( ctx, their_mic, 16 );
+		DBGC2_HD ( ctx, our_mic, 16 );
+		if ( memcmp ( their_mic, our_mic, sizeof ( pkt->mic ) ) != 0 ) {
+			DBGC ( ctx, "WPA %p: EAPOL MIC failure\n", ctx );
+			goto drop;
+		}
+	}
+
+	/* Fix byte order to local */
+	pkt->info = ntohs ( pkt->info );
+	pkt->keysize = ntohs ( pkt->keysize );
+	pkt->datalen = ntohs ( pkt->datalen );
+	pkt->replay = be64_to_cpu ( pkt->replay );
+
+	/* Check replay counter */
+	if ( ctx->replay != ~0ULL && ctx->replay >= pkt->replay ) {
+		DBGC ( ctx, "WPA %p ALERT: Replay detected! "
+		       "(%08x:%08x >= %08x:%08x)\n", ctx,
+		       ( u32 ) ( ctx->replay >> 32 ), ( u32 ) ctx->replay,
+		       ( u32 ) ( pkt->replay >> 32 ), ( u32 ) pkt->replay );
+		rc = 0;		/* ignore without error */
+		goto drop;
+	}
+	ctx->replay = pkt->replay;
+
+	/* Decrypt key data */
+	if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
+		rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
+				    &pkt->datalen );
+		if ( rc < 0 ) {
+			DBGC ( ctx, "WPA %p: failed to decrypt packet: %s\n",
+			       ctx, strerror ( rc ) );
+			goto drop;
+		}
+	}
+
+	/* Hand it off to appropriate handler */
+	switch ( pkt->info & ( EAPOL_KEY_INFO_TYPE |
+			       EAPOL_KEY_INFO_KEY_MIC ) ) {
+	case EAPOL_KEY_TYPE_PTK:
+		rc = wpa_handle_1_of_4 ( ctx, pkt, is_rsn, kie );
+		break;
+
+	case EAPOL_KEY_TYPE_PTK | EAPOL_KEY_INFO_KEY_MIC:
+		rc = wpa_handle_3_of_4 ( ctx, pkt, is_rsn, kie );
+		break;
+
+	case EAPOL_KEY_TYPE_GTK | EAPOL_KEY_INFO_KEY_MIC:
+		rc = wpa_handle_1_of_2 ( ctx, pkt, is_rsn, kie );
+		break;
+
+	default:
+		DBGC ( ctx, "WPA %p: Invalid combination of key flags %04x\n",
+		       ctx, pkt->info );
+		rc = -EINVAL;
+		break;
+	}
+
+ drop:
+	free_iob ( iob );
+	return rc;
+}
+
+struct eapol_handler eapol_key_handler __eapol_handler = {
+	.type = EAPOL_TYPE_KEY,
+	.rx = eapol_key_rx,
+};
+
+/* WPA always needs EAPOL in order to be useful */
+REQUIRE_OBJECT ( eapol );
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_ccmp.c b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_ccmp.c
new file mode 100644
index 0000000..89bb36f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_ccmp.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+#include <ipxe/sha1.h>
+#include <ipxe/aes.h>
+#include <ipxe/wpa.h>
+#include <byteswap.h>
+#include <errno.h>
+
+/** @file
+ *
+ * Backend for WPA using the CCMP encryption method
+ */
+
+/** Context for CCMP encryption and decryption */
+struct ccmp_ctx
+{
+	/** AES context - only ever used for encryption */
+	u8 aes_ctx[AES_CTX_SIZE];
+
+	/** Most recently sent packet number */
+	u64 tx_seq;
+
+	/** Most recently received packet number */
+	u64 rx_seq;
+};
+
+/** Header structure at the beginning of CCMP frame data */
+struct ccmp_head
+{
+	u8 pn_lo[2];		/**< Bytes 0 and 1 of packet number */
+	u8 _rsvd;		/**< Reserved byte */
+	u8 kid;			/**< Key ID and ExtIV byte */
+	u8 pn_hi[4];		/**< Bytes 2-5 (2 first) of packet number */
+} __attribute__ (( packed ));
+
+
+/** CCMP header overhead */
+#define CCMP_HEAD_LEN	8
+
+/** CCMP MIC trailer overhead */
+#define CCMP_MIC_LEN	8
+
+/** CCMP nonce length */
+#define CCMP_NONCE_LEN	13
+
+/** CCMP nonce structure */
+struct ccmp_nonce
+{
+	u8 prio;		/**< Packet priority, 0 for non-QoS */
+	u8 a2[ETH_ALEN];	/**< Address 2 from packet header (sender) */
+	u8 pn[6];		/**< Packet number */
+} __attribute__ (( packed ));
+
+/** CCMP additional authentication data length (for non-QoS, non-WDS frames) */
+#define CCMP_AAD_LEN	22
+
+/** CCMP additional authentication data structure */
+struct ccmp_aad
+{
+	u16 fc;			/**< Frame Control field */
+	u8 a1[6];		/**< Address 1 */
+	u8 a2[6];		/**< Address 2 */
+	u8 a3[6];		/**< Address 3 */
+	u16 seq;		/**< Sequence Control field */
+	/* Address 4 and QoS Control are included if present */
+} __attribute__ (( packed ));
+
+/** Mask for Frame Control field in AAD */
+#define CCMP_AAD_FC_MASK	0xC38F
+
+/** Mask for Sequence Control field in AAD */
+#define CCMP_AAD_SEQ_MASK	0x000F
+
+
+/**
+ * Convert 6-byte LSB packet number to 64-bit integer
+ *
+ * @v pn	Pointer to 6-byte packet number
+ * @ret v	64-bit integer value of @a pn
+ */
+static u64 pn_to_u64 ( const u8 *pn )
+{
+	int i;
+	u64 ret = 0;
+
+	for ( i = 5; i >= 0; i-- ) {
+		ret <<= 8;
+		ret |= pn[i];
+	}
+
+	return ret;
+}
+
+/**
+ * Convert 64-bit integer to 6-byte packet number
+ *
+ * @v v		64-bit integer
+ * @v msb	If TRUE, reverse the output PN to be in MSB order
+ * @ret pn	6-byte packet number
+ *
+ * The PN is stored in LSB order in the packet header and in MSB order
+ * in the nonce. WHYYYYY?
+ */
+static void u64_to_pn ( u64 v, u8 *pn, int msb )
+{
+	int i;
+	u8 *pnp = pn + ( msb ? 5 : 0 );
+	int delta = ( msb ? -1 : +1 );
+
+	for ( i = 0; i < 6; i++ ) {
+		*pnp = v & 0xFF;
+		pnp += delta;
+		v >>= 8;
+	}
+}
+
+/** Value for @a msb argument of u64_to_pn() for MSB output */
+#define PN_MSB	1
+
+/** Value for @a msb argument of u64_to_pn() for LSB output */
+#define PN_LSB	0
+
+
+
+/**
+ * Initialise CCMP state and install key
+ *
+ * @v crypto	CCMP cryptosystem structure
+ * @v key	Pointer to 16-byte temporal key to install
+ * @v keylen	Length of key (16 bytes)
+ * @v rsc	Initial receive sequence counter
+ */
+static int ccmp_init ( struct net80211_crypto *crypto, const void *key,
+		       int keylen, const void *rsc )
+{
+	struct ccmp_ctx *ctx = crypto->priv;
+
+	if ( keylen != 16 )
+		return -EINVAL;
+
+	if ( rsc )
+		ctx->rx_seq = pn_to_u64 ( rsc );
+
+	cipher_setkey ( &aes_algorithm, ctx->aes_ctx, key, keylen );
+
+	return 0;
+}
+
+
+/**
+ * Encrypt or decrypt data stream using AES in Counter mode
+ *
+ * @v ctx	CCMP cryptosystem context
+ * @v nonce	Nonce value, 13 bytes
+ * @v srcv	Data to encrypt or decrypt
+ * @v len	Number of bytes pointed to by @a src
+ * @v msrcv	MIC value to encrypt or decrypt (may be NULL)
+ * @ret destv	Encrypted or decrypted data
+ * @ret mdestv	Encrypted or decrypted MIC value
+ *
+ * This assumes CCMP parameters of L=2 and M=8. The algorithm is
+ * defined in RFC 3610.
+ */
+static void ccmp_ctr_xor ( struct ccmp_ctx *ctx, const void *nonce,
+			   const void *srcv, void *destv, int len,
+			   const void *msrcv, void *mdestv )
+{
+	u8 A[16], S[16];
+	u16 ctr;
+	int i;
+	const u8 *src = srcv, *msrc = msrcv;
+	u8 *dest = destv, *mdest = mdestv;
+
+	A[0] = 0x01;		/* flags, L' = L - 1 = 1, other bits rsvd */
+	memcpy ( A + 1, nonce, CCMP_NONCE_LEN );
+
+	if ( msrcv ) {
+		A[14] = A[15] = 0;
+
+		cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 );
+
+		for ( i = 0; i < 8; i++ ) {
+			*mdest++ = *msrc++ ^ S[i];
+		}
+	}
+
+	for ( ctr = 1 ;; ctr++ ) {
+		A[14] = ctr >> 8;
+		A[15] = ctr & 0xFF;
+
+		cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 );
+
+		for ( i = 0; i < len && i < 16; i++ )
+			*dest++ = *src++ ^ S[i];
+
+		if ( len <= 16 )
+			break;	/* we're done */
+
+		len -= 16;
+	}
+}
+
+
+/**
+ * Advance one block in CBC-MAC calculation
+ *
+ * @v aes_ctx	AES encryption context with key set
+ * @v B		Cleartext block to incorporate (16 bytes)
+ * @v X		Previous ciphertext block (16 bytes)
+ * @ret B	Clobbered
+ * @ret X	New ciphertext block (16 bytes)
+ *
+ * This function does X := E[key] ( X ^ B ).
+ */
+static void ccmp_feed_cbc_mac ( void *aes_ctx, u8 *B, u8 *X )
+{
+	int i;
+	for ( i = 0; i < 16; i++ )
+		B[i] ^= X[i];
+	cipher_encrypt ( &aes_algorithm, aes_ctx, B, X, 16 );
+}
+
+
+/**
+ * Calculate MIC on plaintext data using CBC-MAC
+ *
+ * @v ctx	CCMP cryptosystem context
+ * @v nonce	Nonce value, 13 bytes
+ * @v data	Data to calculate MIC over
+ * @v datalen	Length of @a data
+ * @v aad	Additional authentication data, for MIC but not encryption
+ * @ret mic	MIC value (unencrypted), 8 bytes
+ *
+ * @a aadlen is assumed to be 22 bytes long, as it always is for
+ * 802.11 use when transmitting non-QoS, not-between-APs frames (the
+ * only type we deal with).
+ */
+static void ccmp_cbc_mac ( struct ccmp_ctx *ctx, const void *nonce,
+			   const void *data, u16 datalen,
+			   const void *aad, void *mic )
+{
+	u8 X[16], B[16];
+
+	/* Zeroth block: flags, nonce, length */
+
+	/* Rsv AAD - M'-  - L'-
+	 *  0   1  0 1 1  0 0 1   for an 8-byte MAC and 2-byte message length
+	 */
+	B[0] = 0x59;
+	memcpy ( B + 1, nonce, CCMP_NONCE_LEN );
+	B[14] = datalen >> 8;
+	B[15] = datalen & 0xFF;
+
+	cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, B, X, 16 );
+
+	/* First block: AAD length field and 14 bytes of AAD */
+	B[0] = 0;
+	B[1] = CCMP_AAD_LEN;
+	memcpy ( B + 2, aad, 14 );
+
+	ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
+
+	/* Second block: Remaining 8 bytes of AAD, 8 bytes zero pad */
+	memcpy ( B, aad + 14, 8 );
+	memset ( B + 8, 0, 8 );
+
+	ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
+
+	/* Message blocks */
+	while ( datalen ) {
+		if ( datalen >= 16 ) {
+			memcpy ( B, data, 16 );
+			datalen -= 16;
+		} else {
+			memcpy ( B, data, datalen );
+			memset ( B + datalen, 0, 16 - datalen );
+			datalen = 0;
+		}
+
+		ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
+
+		data += 16;
+	}
+
+	/* Get MIC from final value of X */
+	memcpy ( mic, X, 8 );
+}
+
+
+/**
+ * Encapsulate and encrypt a packet using CCMP
+ *
+ * @v crypto	CCMP cryptosystem
+ * @v iob	I/O buffer containing cleartext packet
+ * @ret eiob	I/O buffer containing encrypted packet
+ */
+struct io_buffer * ccmp_encrypt ( struct net80211_crypto *crypto,
+				  struct io_buffer *iob )
+{
+	struct ccmp_ctx *ctx = crypto->priv;
+	struct ieee80211_frame *hdr = iob->data;
+	struct io_buffer *eiob;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( iob ) - hdrlen;
+	struct ccmp_head head;
+	struct ccmp_nonce nonce;
+	struct ccmp_aad aad;
+	u8 mic[8], tx_pn[6];
+	void *edata, *emic;
+
+	ctx->tx_seq++;
+	u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB );
+
+	/* Allocate memory */
+	eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN );
+	if ( ! eiob )
+		return NULL;
+
+	/* Copy frame header */
+	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
+	hdr = eiob->data;
+	hdr->fc |= IEEE80211_FC_PROTECTED;
+
+	/* Fill in packet number and extended IV */
+	memcpy ( head.pn_lo, tx_pn, 2 );
+	memcpy ( head.pn_hi, tx_pn + 2, 4 );
+	head.kid = 0x20;	/* have Extended IV, key ID 0 */
+	head._rsvd = 0;
+	memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) );
+
+	/* Form nonce */
+	nonce.prio = 0;
+	memcpy ( nonce.a2, hdr->addr2, ETH_ALEN );
+	u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB );
+
+	/* Form additional authentication data */
+	aad.fc = hdr->fc & CCMP_AAD_FC_MASK;
+	memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */
+	aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK;
+
+	/* Calculate MIC over the data */
+	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic );
+
+	/* Copy and encrypt data and MIC */
+	edata = iob_put ( eiob, datalen );
+	emic = iob_put ( eiob, CCMP_MIC_LEN );
+	ccmp_ctr_xor ( ctx, &nonce,
+		       iob->data + hdrlen, edata, datalen,
+		       mic, emic );
+
+	/* Done! */
+	DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx,
+		iob, eiob );
+
+	return eiob;
+}
+
+/**
+ * Decrypt a packet using CCMP
+ *
+ * @v crypto	CCMP cryptosystem
+ * @v eiob	I/O buffer containing encrypted packet
+ * @ret iob	I/O buffer containing cleartext packet
+ */
+static struct io_buffer * ccmp_decrypt ( struct net80211_crypto *crypto,
+					 struct io_buffer *eiob )
+{
+	struct ccmp_ctx *ctx = crypto->priv;
+	struct ieee80211_frame *hdr;
+	struct io_buffer *iob;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN;
+	struct ccmp_head *head;
+	struct ccmp_nonce nonce;
+	struct ccmp_aad aad;
+	u8 rx_pn[6], their_mic[8], our_mic[8];
+
+	iob = alloc_iob ( hdrlen + datalen );
+	if ( ! iob )
+		return NULL;
+
+	/* Copy frame header */
+	memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
+	hdr = iob->data;
+	hdr->fc &= ~IEEE80211_FC_PROTECTED;
+
+	/* Check and update RX packet number */
+	head = eiob->data + hdrlen;
+	memcpy ( rx_pn, head->pn_lo, 2 );
+	memcpy ( rx_pn + 2, head->pn_hi, 4 );
+
+	if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) {
+		DBGC ( ctx, "WPA-CCMP %p: packet received out of order "
+		       "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ),
+		       ctx->rx_seq );
+		free_iob ( iob );
+		return NULL;
+	}
+
+	ctx->rx_seq = pn_to_u64 ( rx_pn );
+	DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq );
+
+	/* Form nonce */
+	nonce.prio = 0;
+	memcpy ( nonce.a2, hdr->addr2, ETH_ALEN );
+	u64_to_pn ( ctx->rx_seq, nonce.pn, PN_MSB );
+
+	/* Form additional authentication data */
+	aad.fc = ( hdr->fc & CCMP_AAD_FC_MASK ) | IEEE80211_FC_PROTECTED;
+	memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */
+	aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK;
+
+	/* Copy-decrypt data and MIC */
+	ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ),
+		       iob_put ( iob, datalen ), datalen,
+		       eiob->tail - CCMP_MIC_LEN, their_mic );
+
+	/* Check MIC */
+	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad,
+		       our_mic );
+
+	if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) {
+		DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx );
+		free_iob ( iob );
+		return NULL;
+	}
+
+	DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx,
+		eiob, iob );
+
+	return iob;
+}
+
+
+/** CCMP cryptosystem */
+struct net80211_crypto ccmp_crypto __net80211_crypto = {
+	.algorithm = NET80211_CRYPT_CCMP,
+	.init = ccmp_init,
+	.encrypt = ccmp_encrypt,
+	.decrypt = ccmp_decrypt,
+	.priv_len = sizeof ( struct ccmp_ctx ),
+};
+
+
+
+
+/**
+ * Calculate HMAC-SHA1 MIC for EAPOL-Key frame
+ *
+ * @v kck	Key Confirmation Key, 16 bytes
+ * @v msg	Message to calculate MIC over
+ * @v len	Number of bytes to calculate MIC over
+ * @ret mic	Calculated MIC, 16 bytes long
+ */
+static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len,
+			   void *mic )
+{
+	u8 sha1_ctx[SHA1_CTX_SIZE];
+	u8 kckb[16];
+	u8 hash[SHA1_SIZE];
+	size_t kck_len = 16;
+
+	memcpy ( kckb, kck, kck_len );
+
+	hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len );
+	hmac_update ( &sha1_algorithm, sha1_ctx, msg, len );
+	hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash );
+
+	memcpy ( mic, hash, 16 );
+}
+
+/**
+ * Decrypt key data in EAPOL-Key frame
+ *
+ * @v kek	Key Encryption Key, 16 bytes
+ * @v iv	Initialisation vector, 16 bytes (unused)
+ * @v msg	Message to decrypt
+ * @v len	Length of message
+ * @ret msg	Decrypted message in place of original
+ * @ret len	Adjusted downward for 8 bytes of overhead
+ * @ret rc	Return status code
+ *
+ * The returned message may still contain padding of 0xDD followed by
+ * zero or more 0x00 octets. It is impossible to remove the padding
+ * without parsing the IEs in the packet (another design decision that
+ * tends to make one question the 802.11i committee's intelligence...)
+ */
+static int ccmp_kie_decrypt ( const void *kek, const void *iv __unused,
+			      void *msg, u16 *len )
+{
+	if ( *len % 8 != 0 )
+		return -EINVAL;
+
+	if ( aes_unwrap ( kek, msg, msg, *len / 8 - 1 ) != 0 )
+		return -EINVAL;
+
+	*len -= 8;
+
+	return 0;
+}
+
+/** CCMP-style key integrity and encryption handler */
+struct wpa_kie ccmp_kie __wpa_kie = {
+	.version = EAPOL_KEY_VERSION_WPA2,
+	.mic = ccmp_kie_mic,
+	.decrypt = ccmp_kie_decrypt,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_psk.c b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_psk.c
new file mode 100644
index 0000000..780738e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_psk.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <ipxe/sha1.h>
+#include <ipxe/wpa.h>
+#include <errno.h>
+
+/** @file
+ *
+ * Frontend for WPA using a pre-shared key.
+ */
+
+/**
+ * Initialise WPA-PSK state
+ *
+ * @v dev	802.11 device
+ * @ret rc	Return status code
+ */
+static int wpa_psk_init ( struct net80211_device *dev )
+{
+	return wpa_make_rsn_ie ( dev, &dev->rsn_ie );
+}
+
+/**
+ * Start WPA-PSK authentication
+ *
+ * @v dev	802.11 device
+ * @ret rc	Return status code
+ */
+static int wpa_psk_start ( struct net80211_device *dev )
+{
+	char passphrase[64+1];
+	u8 pmk[WPA_PMK_LEN];
+	int len;
+	struct wpa_common_ctx *ctx = dev->handshaker->priv;
+
+	len = fetch_string_setting ( netdev_settings ( dev->netdev ),
+				     &net80211_key_setting, passphrase,
+				     64 + 1 );
+
+	if ( len <= 0 ) {
+		DBGC ( ctx, "WPA-PSK %p: no passphrase provided!\n", ctx );
+		net80211_deauthenticate ( dev, -EACCES );
+		return -EACCES;
+	}
+
+	pbkdf2_sha1 ( passphrase, len, dev->essid, strlen ( dev->essid ),
+		      4096, pmk, WPA_PMK_LEN );
+
+	DBGC ( ctx, "WPA-PSK %p: derived PMK from passphrase `%s':\n", ctx,
+	       passphrase );
+	DBGC_HD ( ctx, pmk, WPA_PMK_LEN );
+
+	return wpa_start ( dev, ctx, pmk, WPA_PMK_LEN );
+}
+
+/**
+ * Step WPA-PSK authentication
+ *
+ * @v dev	802.11 device
+ * @ret rc	Return status code
+ */
+static int wpa_psk_step ( struct net80211_device *dev )
+{
+	struct wpa_common_ctx *ctx = dev->handshaker->priv;
+
+	switch ( ctx->state ) {
+	case WPA_SUCCESS:
+		return 1;
+	case WPA_FAILURE:
+		return -EACCES;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Do-nothing function; you can't change a WPA key post-authentication
+ *
+ * @v dev	802.11 device
+ * @ret rc	Return status code
+ */
+static int wpa_psk_no_change_key ( struct net80211_device *dev __unused )
+{
+	return 0;
+}
+
+/**
+ * Disable handling of received WPA authentication frames
+ *
+ * @v dev	802.11 device
+ */
+static void wpa_psk_stop ( struct net80211_device *dev )
+{
+	wpa_stop ( dev );
+}
+
+/** WPA-PSK security handshaker */
+struct net80211_handshaker wpa_psk_handshaker __net80211_handshaker = {
+	.protocol = NET80211_SECPROT_PSK,
+	.init = wpa_psk_init,
+	.start = wpa_psk_start,
+	.step = wpa_psk_step,
+	.change_key = wpa_psk_no_change_key,
+	.stop = wpa_psk_stop,
+	.priv_len = sizeof ( struct wpa_common_ctx ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_tkip.c b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_tkip.c
new file mode 100644
index 0000000..0a94df0
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/80211/wpa_tkip.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/net80211.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+#include <ipxe/sha1.h>
+#include <ipxe/md5.h>
+#include <ipxe/crc32.h>
+#include <ipxe/arc4.h>
+#include <ipxe/wpa.h>
+#include <byteswap.h>
+#include <errno.h>
+
+/** @file
+ *
+ * Backend for WPA using the TKIP encryption standard.
+ */
+
+/** Context for one direction of TKIP, either encryption or decryption */
+struct tkip_dir_ctx
+{
+	/** High 32 bits of last sequence counter value used */
+	u32 tsc_hi;
+
+	/** Low 32 bits of last sequence counter value used */
+	u16 tsc_lo;
+
+	/** MAC address used to derive TTAK */
+	u8 mac[ETH_ALEN];
+
+	/** If TRUE, TTAK is valid */
+	u16 ttak_ok;
+
+	/** TKIP-mixed transmit address and key, depends on tsc_hi and MAC */
+	u16 ttak[5];
+};
+
+/** Context for TKIP encryption and decryption */
+struct tkip_ctx
+{
+	/** Temporal key to use */
+	struct tkip_tk tk;
+
+	/** State for encryption */
+	struct tkip_dir_ctx enc;
+
+	/** State for decryption */
+	struct tkip_dir_ctx dec;
+};
+
+/** Header structure at the beginning of TKIP frame data */
+struct tkip_head
+{
+	u8 tsc1;		/**< High byte of low 16 bits of TSC */
+	u8 seed1;		/**< Second byte of WEP seed */
+	u8 tsc0;		/**< Low byte of TSC */
+	u8 kid;			/**< Key ID and ExtIV byte */
+	u32 tsc_hi;		/**< High 32 bits of TSC, as an ExtIV */
+} __attribute__ (( packed ));
+
+
+/** TKIP header overhead (IV + KID + ExtIV) */
+#define TKIP_HEAD_LEN	8
+
+/** TKIP trailer overhead (MIC + ICV) [assumes unfragmented] */
+#define TKIP_FOOT_LEN	12
+
+/** TKIP MIC length */
+#define TKIP_MIC_LEN	8
+
+/** TKIP ICV length */
+#define TKIP_ICV_LEN	4
+
+
+/** TKIP S-box */
+static const u16 Sbox[256] = {
+	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+/**
+ * Perform S-box mapping on a 16-bit value
+ *
+ * @v v		Value to perform S-box mapping on
+ * @ret Sv	S-box mapped value
+ */
+static inline u16 S ( u16 v )
+{
+	return Sbox[v & 0xFF] ^ swap16 ( Sbox[v >> 8] );
+}
+
+/**
+ * Rotate 16-bit value right
+ *
+ * @v v		Value to rotate
+ * @v bits	Number of bits to rotate by
+ * @ret rotv	Rotated value
+ */
+static inline u16 ror16 ( u16 v, int bits )
+{
+	return ( v >> bits ) | ( v << ( 16 - bits ) );
+}
+
+/**
+ * Rotate 32-bit value right
+ *
+ * @v v		Value to rotate
+ * @v bits	Number of bits to rotate by
+ * @ret rotv	Rotated value
+ */
+static inline u32 ror32 ( u32 v, int bits )
+{
+	return ( v >> bits ) | ( v << ( 32 - bits ) );
+}
+
+/**
+ * Rotate 32-bit value left
+ *
+ * @v v		Value to rotate
+ * @v bits	Number of bits to rotate by
+ * @ret rotv	Rotated value
+ */
+static inline u32 rol32 ( u32 v, int bits )
+{
+	return ( v << bits ) | ( v >> ( 32 - bits ) );
+}
+
+
+/**
+ * Initialise TKIP state and install key
+ *
+ * @v crypto	TKIP cryptosystem structure
+ * @v key	Pointer to tkip_tk to install
+ * @v keylen	Length of key (32 bytes)
+ * @v rsc	Initial receive sequence counter
+ */
+static int tkip_init ( struct net80211_crypto *crypto, const void *key,
+		       int keylen, const void *rsc )
+{
+	struct tkip_ctx *ctx = crypto->priv;
+	const u8 *rscb = rsc;
+
+	if ( keylen != sizeof ( ctx->tk ) )
+		return -EINVAL;
+
+	if ( rscb ) {
+		ctx->dec.tsc_lo =   ( rscb[1] <<  8 ) |   rscb[0];
+		ctx->dec.tsc_hi = ( ( rscb[5] << 24 ) | ( rscb[4] << 16 ) |
+				    ( rscb[3] <<  8 ) |   rscb[2] );
+	}
+
+	memcpy ( &ctx->tk, key, sizeof ( ctx->tk ) );
+
+	return 0;
+}
+
+/**
+ * Perform TKIP key mixing, phase 1
+ *
+ * @v dctx	TKIP directional context
+ * @v tk	TKIP temporal key
+ * @v mac	MAC address of transmitter
+ *
+ * This recomputes the TTAK in @a dctx if necessary, and sets
+ * @c dctx->ttak_ok.
+ */
+static void tkip_mix_1 ( struct tkip_dir_ctx *dctx, struct tkip_tk *tk, u8 *mac )
+{
+	int i, j;
+
+	if ( dctx->ttak_ok && ! memcmp ( mac, dctx->mac, ETH_ALEN ) )
+		return;
+
+	memcpy ( dctx->mac, mac, ETH_ALEN );
+
+	dctx->ttak[0] = dctx->tsc_hi & 0xFFFF;
+	dctx->ttak[1] = dctx->tsc_hi >> 16;
+	dctx->ttak[2] = ( mac[1] << 8 ) | mac[0];
+	dctx->ttak[3] = ( mac[3] << 8 ) | mac[2];
+	dctx->ttak[4] = ( mac[5] << 8 ) | mac[4];
+
+	for ( i = 0; i < 8; i++ ) {
+		j = 2 * ( i & 1 );
+
+		dctx->ttak[0] += S ( dctx->ttak[4] ^ ( ( tk->key[1 + j] << 8 ) |
+						         tk->key[0 + j] ) );
+		dctx->ttak[1] += S ( dctx->ttak[0] ^ ( ( tk->key[5 + j] << 8 ) |
+						         tk->key[4 + j] ) );
+		dctx->ttak[2] += S ( dctx->ttak[1] ^ ( ( tk->key[9 + j] << 8 ) |
+						         tk->key[8 + j] ) );
+		dctx->ttak[3] += S ( dctx->ttak[2] ^ ( ( tk->key[13+ j] << 8 ) |
+						         tk->key[12+ j] ) );
+		dctx->ttak[4] += S ( dctx->ttak[3] ^ ( ( tk->key[1 + j] << 8 ) |
+						         tk->key[0 + j] ) ) + i;
+	}
+
+	dctx->ttak_ok = 1;
+}
+
+/**
+ * Perform TKIP key mixing, phase 2
+ *
+ * @v dctx	TKIP directional context
+ * @v tk	TKIP temporal key
+ * @ret key	ARC4 key, 16 bytes long
+ */
+static void tkip_mix_2 ( struct tkip_dir_ctx *dctx, struct tkip_tk *tk,
+			 void *key )
+{
+	u8 *kb = key;
+	u16 ppk[6];
+	int i;
+
+	memcpy ( ppk, dctx->ttak, sizeof ( dctx->ttak ) );
+	ppk[5] = dctx->ttak[4] + dctx->tsc_lo;
+
+	ppk[0] += S ( ppk[5] ^ ( ( tk->key[1] << 8 ) | tk->key[0] ) );
+	ppk[1] += S ( ppk[0] ^ ( ( tk->key[3] << 8 ) | tk->key[2] ) );
+	ppk[2] += S ( ppk[1] ^ ( ( tk->key[5] << 8 ) | tk->key[4] ) );
+	ppk[3] += S ( ppk[2] ^ ( ( tk->key[7] << 8 ) | tk->key[6] ) );
+	ppk[4] += S ( ppk[3] ^ ( ( tk->key[9] << 8 ) | tk->key[8] ) );
+	ppk[5] += S ( ppk[4] ^ ( ( tk->key[11] << 8 ) | tk->key[10] ) );
+
+	ppk[0] += ror16 ( ppk[5] ^ ( ( tk->key[13] << 8 ) | tk->key[12] ), 1 );
+	ppk[1] += ror16 ( ppk[0] ^ ( ( tk->key[15] << 8 ) | tk->key[14] ), 1 );
+	ppk[2] += ror16 ( ppk[1], 1 );
+	ppk[3] += ror16 ( ppk[2], 1 );
+	ppk[4] += ror16 ( ppk[3], 1 );
+	ppk[5] += ror16 ( ppk[4], 1 );
+
+	kb[0] = dctx->tsc_lo >> 8;
+	kb[1] = ( ( dctx->tsc_lo >> 8 ) | 0x20 ) & 0x7F;
+	kb[2] = dctx->tsc_lo & 0xFF;
+	kb[3] = ( ( ppk[5] ^ ( ( tk->key[1] << 8 ) | tk->key[0] ) ) >> 1 )
+		& 0xFF;
+
+	for ( i = 0; i < 6; i++ ) {
+		kb[4 + 2*i] = ppk[i] & 0xFF;
+		kb[5 + 2*i] = ppk[i] >> 8;
+	}
+}
+
+/**
+ * Update Michael message integrity code based on next 32-bit word of data
+ *
+ * @v V		Michael code state (two 32-bit words)
+ * @v word	Next 32-bit word of data
+ */
+static void tkip_feed_michael ( u32 *V, u32 word )
+{
+	V[0] ^= word;
+	V[1] ^= rol32 ( V[0], 17 );
+	V[0] += V[1];
+	V[1] ^= ( ( V[0] & 0xFF00FF00 ) >> 8 ) | ( ( V[0] & 0x00FF00FF ) << 8 );
+	V[0] += V[1];
+	V[1] ^= rol32 ( V[0], 3 );
+	V[0] += V[1];
+	V[1] ^= ror32 ( V[0], 2 );
+	V[0] += V[1];
+}
+
+/**
+ * Calculate Michael message integrity code
+ *
+ * @v key	MIC key to use (8 bytes)
+ * @v da	Destination link-layer address
+ * @v sa	Source link-layer address
+ * @v data	Start of data to calculate over
+ * @v len	Length of header + data
+ * @ret mic	Calculated Michael MIC (8 bytes)
+ */
+static void tkip_michael ( const void *key, const void *da, const void *sa,
+			   const void *data, size_t len, void *mic )
+{
+	u32 V[2];		/* V[0] = "l", V[1] = "r" in 802.11 */
+	union {
+		u8 byte[12];
+		u32 word[3];
+	} cap;
+	const u8 *ptr = data;
+	const u8 *end = ptr + len;
+	int i;
+
+	memcpy ( V, key, sizeof ( V ) );
+	V[0] = le32_to_cpu ( V[0] );
+	V[1] = le32_to_cpu ( V[1] );
+
+	/* Feed in header (we assume non-QoS, so Priority = 0) */
+	memcpy ( &cap.byte[0], da, ETH_ALEN );
+	memcpy ( &cap.byte[6], sa, ETH_ALEN );
+	tkip_feed_michael ( V, le32_to_cpu ( cap.word[0] ) );
+	tkip_feed_michael ( V, le32_to_cpu ( cap.word[1] ) );
+	tkip_feed_michael ( V, le32_to_cpu ( cap.word[2] ) );
+	tkip_feed_michael ( V, 0 );
+
+	/* Feed in data */
+	while ( ptr + 4 <= end ) {
+		tkip_feed_michael ( V, le32_to_cpu ( *( u32 * ) ptr ) );
+		ptr += 4;
+	}
+
+	/* Add unaligned part and padding */
+	for ( i = 0; ptr < end; i++ )
+		cap.byte[i] = *ptr++;
+	cap.byte[i++] = 0x5a;
+	for ( ; i < 8; i++ )
+		cap.byte[i] = 0;
+
+	/* Feed in padding */
+	tkip_feed_michael ( V, le32_to_cpu ( cap.word[0] ) );
+	tkip_feed_michael ( V, le32_to_cpu ( cap.word[1] ) );
+
+	/* Output MIC */
+	V[0] = cpu_to_le32 ( V[0] );
+	V[1] = cpu_to_le32 ( V[1] );
+	memcpy ( mic, V, sizeof ( V ) );
+}
+
+/**
+ * Encrypt a packet using TKIP
+ *
+ * @v crypto	TKIP cryptosystem
+ * @v iob	I/O buffer containing cleartext packet
+ * @ret eiob	I/O buffer containing encrypted packet
+ */
+static struct io_buffer * tkip_encrypt ( struct net80211_crypto *crypto,
+					 struct io_buffer *iob )
+{
+	struct tkip_ctx *ctx = crypto->priv;
+	struct ieee80211_frame *hdr = iob->data;
+	struct io_buffer *eiob;
+	struct arc4_ctx arc4;
+	u8 key[16];
+	struct tkip_head head;
+	u8 mic[8];
+	u32 icv;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( iob ) - hdrlen;
+
+	ctx->enc.tsc_lo++;
+	if ( ctx->enc.tsc_lo == 0 ) {
+		ctx->enc.tsc_hi++;
+		ctx->enc.ttak_ok = 0;
+	}
+
+	tkip_mix_1 ( &ctx->enc, &ctx->tk, hdr->addr2 );
+	tkip_mix_2 ( &ctx->enc, &ctx->tk, key );
+
+	eiob = alloc_iob ( iob_len ( iob ) + TKIP_HEAD_LEN + TKIP_FOOT_LEN );
+	if ( ! eiob )
+		return NULL;
+
+	/* Copy frame header */
+	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
+	hdr = eiob->data;
+	hdr->fc |= IEEE80211_FC_PROTECTED;
+
+	/* Fill in IV and key ID byte, and extended IV */
+	memcpy ( &head, key, 3 );
+	head.kid = 0x20;		/* have Extended IV, key ID 0 */
+	head.tsc_hi = cpu_to_le32 ( ctx->enc.tsc_hi );
+	memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) );
+
+	/* Copy and encrypt the data */
+	cipher_setkey ( &arc4_algorithm, &arc4, key, 16 );
+	cipher_encrypt ( &arc4_algorithm, &arc4, iob->data + hdrlen,
+			 iob_put ( eiob, datalen ), datalen );
+
+	/* Add MIC */
+	hdr = iob->data;
+	tkip_michael ( &ctx->tk.mic.tx, hdr->addr3, hdr->addr2,
+		       iob->data + hdrlen, datalen, mic );
+	cipher_encrypt ( &arc4_algorithm, &arc4, mic,
+			 iob_put ( eiob, sizeof ( mic ) ), sizeof ( mic ) );
+
+	/* Add ICV */
+	icv = crc32_le ( ~0, iob->data + hdrlen, datalen );
+	icv = crc32_le ( icv, mic, sizeof ( mic ) );
+	icv = cpu_to_le32 ( ~icv );
+	cipher_encrypt ( &arc4_algorithm, &arc4, &icv,
+			 iob_put ( eiob, TKIP_ICV_LEN ), TKIP_ICV_LEN );
+
+	DBGC2 ( ctx, "WPA-TKIP %p: encrypted packet %p -> %p\n", ctx,
+		iob, eiob );
+
+	return eiob;
+}
+
+/**
+ * Decrypt a packet using TKIP
+ *
+ * @v crypto	TKIP cryptosystem
+ * @v eiob	I/O buffer containing encrypted packet
+ * @ret iob	I/O buffer containing cleartext packet
+ */
+static struct io_buffer * tkip_decrypt ( struct net80211_crypto *crypto,
+					 struct io_buffer *eiob )
+{
+	struct tkip_ctx *ctx = crypto->priv;
+	struct ieee80211_frame *hdr;
+	struct io_buffer *iob;
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
+	int datalen = iob_len ( eiob ) - hdrlen - TKIP_HEAD_LEN - TKIP_FOOT_LEN;
+	struct tkip_head *head;
+	struct arc4_ctx arc4;
+	u16 rx_tsc_lo;
+	u8 key[16];
+	u8 mic[8];
+	u32 icv, crc;
+
+	iob = alloc_iob ( hdrlen + datalen + TKIP_FOOT_LEN );
+	if ( ! iob )
+		return NULL;
+
+	/* Copy frame header */
+	memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
+	hdr = iob->data;
+	hdr->fc &= ~IEEE80211_FC_PROTECTED;
+
+	/* Check and update TSC */
+	head = eiob->data + hdrlen;
+	rx_tsc_lo = ( head->tsc1 << 8 ) | head->tsc0;
+
+	if ( head->tsc_hi < ctx->dec.tsc_hi ||
+	     ( head->tsc_hi == ctx->dec.tsc_hi &&
+	       rx_tsc_lo <= ctx->dec.tsc_lo ) ) {
+		DBGC ( ctx, "WPA-TKIP %p: packet received out of order "
+		       "(%08x:%04x <= %08x:%04x)\n", ctx, head->tsc_hi,
+		       rx_tsc_lo, ctx->dec.tsc_hi, ctx->dec.tsc_lo );
+		free_iob ( iob );
+		return NULL;
+	}
+	ctx->dec.tsc_lo = rx_tsc_lo;
+	if ( ctx->dec.tsc_hi != head->tsc_hi ) {
+		ctx->dec.ttak_ok = 0;
+		ctx->dec.tsc_hi = head->tsc_hi;
+	}
+
+	/* Calculate key */
+	tkip_mix_1 ( &ctx->dec, &ctx->tk, hdr->addr2 );
+	tkip_mix_2 ( &ctx->dec, &ctx->tk, key );
+
+	/* Copy-decrypt data, MIC, ICV */
+	cipher_setkey ( &arc4_algorithm, &arc4, key, 16 );
+	cipher_decrypt ( &arc4_algorithm, &arc4,
+			 eiob->data + hdrlen + TKIP_HEAD_LEN,
+			 iob_put ( iob, datalen ), datalen + TKIP_FOOT_LEN );
+
+	/* Check ICV */
+	icv = le32_to_cpu ( *( u32 * ) ( iob->tail + TKIP_MIC_LEN ) );
+	crc = ~crc32_le ( ~0, iob->data + hdrlen, datalen + TKIP_MIC_LEN );
+	if ( crc != icv ) {
+		DBGC ( ctx, "WPA-TKIP %p CRC mismatch: expect %08x, get %08x\n",
+		       ctx, icv, crc );
+		free_iob ( iob );
+		return NULL;
+	}
+
+	/* Check MIC */
+	tkip_michael ( &ctx->tk.mic.rx, hdr->addr1, hdr->addr3,
+		       iob->data + hdrlen, datalen, mic );
+	if ( memcmp ( mic, iob->tail, TKIP_MIC_LEN ) != 0 ) {
+		DBGC ( ctx, "WPA-TKIP %p ALERT! MIC failure\n", ctx );
+		/* XXX we should do the countermeasures here */
+		free_iob ( iob );
+		return NULL;
+	}
+
+	DBGC2 ( ctx, "WPA-TKIP %p: decrypted packet %p -> %p\n", ctx,
+		eiob, iob );
+
+	return iob;
+}
+
+/** TKIP cryptosystem */
+struct net80211_crypto tkip_crypto __net80211_crypto = {
+	.algorithm = NET80211_CRYPT_TKIP,
+	.init = tkip_init,
+	.encrypt = tkip_encrypt,
+	.decrypt = tkip_decrypt,
+	.priv_len = sizeof ( struct tkip_ctx ),
+};
+
+
+
+
+/**
+ * Calculate HMAC-MD5 MIC for EAPOL-Key frame
+ *
+ * @v kck	Key Confirmation Key, 16 bytes
+ * @v msg	Message to calculate MIC over
+ * @v len	Number of bytes to calculate MIC over
+ * @ret mic	Calculated MIC, 16 bytes long
+ */
+static void tkip_kie_mic ( const void *kck, const void *msg, size_t len,
+			   void *mic )
+{
+	struct md5_ctx md5;
+	u8 kckb[16];
+	size_t kck_len = 16;
+
+	memcpy ( kckb, kck, kck_len );
+
+	hmac_init ( &md5_algorithm, &md5, kckb, &kck_len );
+	hmac_update ( &md5_algorithm, &md5, msg, len );
+	hmac_final ( &md5_algorithm, &md5, kckb, &kck_len, mic );
+}
+
+/**
+ * Decrypt key data in EAPOL-Key frame
+ *
+ * @v kek	Key Encryption Key, 16 bytes
+ * @v iv	Initialisation vector, 16 bytes
+ * @v msg	Message to decrypt
+ * @v len	Length of message
+ * @ret msg	Decrypted message in place of original
+ * @ret len	Unchanged
+ * @ret rc	Always 0 for success
+ */
+static int tkip_kie_decrypt ( const void *kek, const void *iv,
+			      void *msg, u16 *len )
+{
+	u8 key[32];
+	memcpy ( key, iv, 16 );
+	memcpy ( key + 16, kek, 16 );
+
+	arc4_skip ( key, 32, 256, msg, msg, *len );
+
+	return 0;
+}
+
+
+/** TKIP-style key integrity and encryption handler */
+struct wpa_kie tkip_kie __wpa_kie = {
+	.version = EAPOL_KEY_VERSION_WPA,
+	.mic = tkip_kie_mic,
+	.decrypt = tkip_kie_decrypt,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/aoe.c b/qemu-0.15.x/roms/ipxe/src/net/aoe.c
new file mode 100644
index 0000000..3b1953a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/aoe.c
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/list.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/features.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/uri.h>
+#include <ipxe/open.h>
+#include <ipxe/ata.h>
+#include <ipxe/device.h>
+#include <ipxe/aoe.h>
+
+/** @file
+ *
+ * AoE protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
+
+struct net_protocol aoe_protocol __net_protocol;
+
+/******************************************************************************
+ *
+ * AoE devices and commands
+ *
+ ******************************************************************************
+ */
+
+/** List of all AoE devices */
+static LIST_HEAD ( aoe_devices );
+
+/** List of active AoE commands */
+static LIST_HEAD ( aoe_commands );
+
+/** An AoE device */
+struct aoe_device {
+	/** Reference counter */
+	struct refcnt refcnt;
+
+	/** Network device */
+	struct net_device *netdev;
+	/** ATA command issuing interface */
+	struct interface ata;
+
+	/** Major number */
+	uint16_t major;
+	/** Minor number */
+	uint8_t minor;
+	/** Target MAC address */
+	uint8_t target[MAX_LL_ADDR_LEN];
+
+	/** Saved timeout value */
+	unsigned long timeout;
+
+	/** Configuration command interface */
+	struct interface config;
+	/** Device is configued */
+	int configured;
+};
+
+/** An AoE command */
+struct aoe_command {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** AOE device */
+	struct aoe_device *aoedev;
+	/** List of active commands */
+	struct list_head list;
+
+	/** ATA command interface */
+	struct interface ata;
+
+	/** ATA command */
+	struct ata_cmd command;
+	/** Command type */
+	struct aoe_command_type *type;
+	/** Command tag */
+	uint32_t tag;
+
+	/** Retransmission timer */
+	struct retry_timer timer;
+};
+
+/** An AoE command type */
+struct aoe_command_type {
+	/**
+	 * Calculate length of AoE command IU
+	 *
+	 * @v aoecmd		AoE command
+	 * @ret len		Length of command IU
+	 */
+	size_t ( * cmd_len ) ( struct aoe_command *aoecmd );
+	/**
+	 * Build AoE command IU
+	 *
+	 * @v aoecmd		AoE command
+	 * @v data		Command IU
+	 * @v len		Length of command IU
+	 */
+	void ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
+	/**
+	 * Handle AoE response IU
+	 *
+	 * @v aoecmd		AoE command
+	 * @v data		Response IU
+	 * @v len		Length of response IU
+	 * @v ll_source		Link-layer source address
+	 * @ret rc		Return status code
+	 */
+	int ( * rsp ) ( struct aoe_command *aoecmd, const void *data,
+			size_t len, const void *ll_source );
+};
+
+/**
+ * Get reference to AoE device
+ *
+ * @v aoedev		AoE device
+ * @ret aoedev		AoE device
+ */
+static inline __attribute__ (( always_inline )) struct aoe_device *
+aoedev_get ( struct aoe_device *aoedev ) {
+	ref_get ( &aoedev->refcnt );
+	return aoedev;
+}
+
+/**
+ * Drop reference to AoE device
+ *
+ * @v aoedev		AoE device
+ */
+static inline __attribute__ (( always_inline )) void
+aoedev_put ( struct aoe_device *aoedev ) {
+	ref_put ( &aoedev->refcnt );
+}
+
+/**
+ * Get reference to AoE command
+ *
+ * @v aoecmd		AoE command
+ * @ret aoecmd		AoE command
+ */
+static inline __attribute__ (( always_inline )) struct aoe_command *
+aoecmd_get ( struct aoe_command *aoecmd ) {
+	ref_get ( &aoecmd->refcnt );
+	return aoecmd;
+}
+
+/**
+ * Drop reference to AoE command
+ *
+ * @v aoecmd		AoE command
+ */
+static inline __attribute__ (( always_inline )) void
+aoecmd_put ( struct aoe_command *aoecmd ) {
+	ref_put ( &aoecmd->refcnt );
+}
+
+/**
+ * Name AoE device
+ *
+ * @v aoedev		AoE device
+ * @ret name		AoE device name
+ */
+static const char * aoedev_name ( struct aoe_device *aoedev ) {
+	static char buf[16];
+
+	snprintf ( buf, sizeof ( buf ), "%s/e%d.%d", aoedev->netdev->name,
+		   aoedev->major, aoedev->minor );
+	return buf;
+}
+
+/**
+ * Free AoE command
+ *
+ * @v refcnt		Reference counter
+ */
+static void aoecmd_free ( struct refcnt *refcnt ) {
+	struct aoe_command *aoecmd =
+		container_of ( refcnt, struct aoe_command, refcnt );
+
+	assert ( ! timer_running ( &aoecmd->timer ) );
+	assert ( list_empty ( &aoecmd->list ) );
+
+	aoedev_put ( aoecmd->aoedev );
+	free ( aoecmd );
+}
+
+/**
+ * Close AoE command
+ *
+ * @v aoecmd		AoE command
+ * @v rc		Reason for close
+ */
+static void aoecmd_close ( struct aoe_command *aoecmd, int rc ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+
+	/* Stop timer */
+	stop_timer ( &aoecmd->timer );
+
+	/* Preserve the timeout value for subsequent commands */
+	aoedev->timeout = aoecmd->timer.timeout;
+
+	/* Remove from list of commands */
+	if ( ! list_empty ( &aoecmd->list ) ) {
+		list_del ( &aoecmd->list );
+		INIT_LIST_HEAD ( &aoecmd->list );
+		aoecmd_put ( aoecmd );
+	}
+
+	/* Shut down interfaces */
+	intf_shutdown ( &aoecmd->ata, rc );
+}
+
+/**
+ * Transmit AoE command request
+ *
+ * @v aoecmd		AoE command
+ * @ret rc		Return status code
+ */
+static int aoecmd_tx ( struct aoe_command *aoecmd ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct net_device *netdev = aoedev->netdev;
+	struct io_buffer *iobuf;
+	struct aoehdr *aoehdr;
+	size_t cmd_len;
+	int rc;
+
+	/* Sanity check */
+	assert ( netdev != NULL );
+
+	/* If we are transmitting anything that requires a response,
+         * start the retransmission timer.  Do this before attempting
+         * to allocate the I/O buffer, in case allocation itself
+         * fails.
+         */
+	start_timer ( &aoecmd->timer );
+
+	/* Create outgoing I/O buffer */
+	cmd_len = aoecmd->type->cmd_len ( aoecmd );
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + cmd_len );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+	aoehdr = iob_put ( iobuf, cmd_len );
+
+	/* Fill AoE header */
+	memset ( aoehdr, 0, sizeof ( *aoehdr ) );
+	aoehdr->ver_flags = AOE_VERSION;
+	aoehdr->major = htons ( aoedev->major );
+	aoehdr->minor = aoedev->minor;
+	aoehdr->tag = htonl ( aoecmd->tag );
+	aoecmd->type->cmd ( aoecmd, iobuf->data, iob_len ( iobuf ) );
+
+	/* Send packet */
+	if ( ( rc = net_tx ( iobuf, netdev, &aoe_protocol, aoedev->target,
+			     netdev->ll_addr ) ) != 0 ) {
+		DBGC ( aoedev, "AoE %s/%08x could not transmit: %s\n",
+		       aoedev_name ( aoedev ), aoecmd->tag,
+		       strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive AoE command response
+ *
+ * @v aoecmd		AoE command
+ * @v iobuf		I/O buffer
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int aoecmd_rx ( struct aoe_command *aoecmd, struct io_buffer *iobuf,
+		       const void *ll_source ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct aoehdr *aoehdr = iobuf->data;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
+		DBGC ( aoedev, "AoE %s/%08x received underlength response "
+		       "(%zd bytes)\n", aoedev_name ( aoedev ),
+		       aoecmd->tag, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto done;
+	}
+	if ( ( ntohs ( aoehdr->major ) != aoedev->major ) ||
+	     ( aoehdr->minor != aoedev->minor ) ) {
+		DBGC ( aoedev, "AoE %s/%08x received response for incorrect "
+		       "device e%d.%d\n", aoedev_name ( aoedev ), aoecmd->tag,
+		       ntohs ( aoehdr->major ), aoehdr->minor );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Catch command failures */
+	if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
+		DBGC ( aoedev, "AoE %s/%08x terminated in error\n",
+		       aoedev_name ( aoedev ), aoecmd->tag );
+		aoecmd_close ( aoecmd, -EIO );
+		rc = -EIO;
+		goto done;
+	}
+
+	/* Hand off to command completion handler */
+	if ( ( rc = aoecmd->type->rsp ( aoecmd, iobuf->data, iob_len ( iobuf ),
+					ll_source ) ) != 0 )
+		goto done;
+
+ done:
+	/* Free I/O buffer */
+	free_iob ( iobuf );
+
+	/* Terminate command */
+	aoecmd_close ( aoecmd, rc );
+
+	return rc;
+}
+
+/**
+ * Handle AoE retry timer expiry
+ *
+ * @v timer		AoE retry timer
+ * @v fail		Failure indicator
+ */
+static void aoecmd_expired ( struct retry_timer *timer, int fail ) {
+	struct aoe_command *aoecmd =
+		container_of ( timer, struct aoe_command, timer );
+
+	if ( fail ) {
+		aoecmd_close ( aoecmd, -ETIMEDOUT );
+	} else {
+		aoecmd_tx ( aoecmd );
+	}
+}
+
+/**
+ * Calculate length of AoE ATA command IU
+ *
+ * @v aoecmd		AoE command
+ * @ret len		Length of command IU
+ */
+static size_t aoecmd_ata_cmd_len ( struct aoe_command *aoecmd ) {
+	struct ata_cmd *command = &aoecmd->command;
+
+	return ( sizeof ( struct aoehdr ) + sizeof ( struct aoeata ) +
+		 command->data_out_len );
+}
+
+/**
+ * Build AoE ATA command IU
+ *
+ * @v aoecmd		AoE command
+ * @v data		Command IU
+ * @v len		Length of command IU
+ */
+static void aoecmd_ata_cmd ( struct aoe_command *aoecmd,
+			     void *data, size_t len ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct ata_cmd *command = &aoecmd->command;
+	struct aoehdr *aoehdr = data;
+	struct aoeata *aoeata = &aoehdr->payload[0].ata;
+
+	/* Sanity check */
+	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
+	assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) +
+			  command->data_out_len ) );
+
+	/* Build IU */
+	aoehdr->command = AOE_CMD_ATA;
+	memset ( aoeata, 0, sizeof ( *aoeata ) );
+	aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
+			   ( command->cb.device & ATA_DEV_SLAVE ) |
+			   ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
+	aoeata->err_feat = command->cb.err_feat.bytes.cur;
+	aoeata->count = command->cb.count.native;
+	aoeata->cmd_stat = command->cb.cmd_stat;
+	aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
+	if ( ! command->cb.lba48 )
+		aoeata->lba.bytes[3] |=
+			( command->cb.device & ATA_DEV_MASK );
+	copy_from_user ( aoeata->data, command->data_out, 0,
+			 command->data_out_len );
+
+	DBGC2 ( aoedev, "AoE %s/%08x ATA cmd %02x:%02x:%02x:%02x:%08llx",
+		aoedev_name ( aoedev ), aoecmd->tag, aoeata->aflags,
+		aoeata->err_feat, aoeata->count, aoeata->cmd_stat,
+		aoeata->lba.u64 );
+	if ( command->data_out_len )
+		DBGC2 ( aoedev, " out %04zx", command->data_out_len );
+	if ( command->data_in_len )
+		DBGC2 ( aoedev, " in %04zx", command->data_in_len );
+	DBGC2 ( aoedev, "\n" );
+}
+
+/**
+ * Handle AoE ATA response IU
+ *
+ * @v aoecmd		AoE command
+ * @v data		Response IU
+ * @v len		Length of response IU
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int aoecmd_ata_rsp ( struct aoe_command *aoecmd, const void *data,
+			    size_t len, const void *ll_source __unused ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct ata_cmd *command = &aoecmd->command;
+	const struct aoehdr *aoehdr = data;
+	const struct aoeata *aoeata = &aoehdr->payload[0].ata;
+	size_t data_len;
+
+	/* Sanity check */
+	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) ) {
+		DBGC ( aoedev, "AoE %s/%08x received underlength ATA response "
+		       "(%zd bytes)\n", aoedev_name ( aoedev ),
+		       aoecmd->tag, len );
+		return -EINVAL;
+	}
+	data_len = ( len - ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) );
+	DBGC2 ( aoedev, "AoE %s/%08x ATA rsp %02x in %04zx\n",
+		aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat,
+		data_len );
+
+	/* Check for command failure */
+	if ( aoeata->cmd_stat & ATA_STAT_ERR ) {
+		DBGC ( aoedev, "AoE %s/%08x status %02x\n",
+		       aoedev_name ( aoedev ), aoecmd->tag, aoeata->cmd_stat );
+		return -EIO;
+	}
+
+	/* Check data-in length is sufficient.  (There may be trailing
+	 * garbage due to Ethernet minimum-frame-size padding.)
+	 */
+	if ( data_len < command->data_in_len ) {
+		DBGC ( aoedev, "AoE %s/%08x data-in underrun (received %zd, "
+		       "expected %zd)\n", aoedev_name ( aoedev ), aoecmd->tag,
+		       data_len, command->data_in_len );
+		return -ERANGE;
+	}
+
+	/* Copy out data payload */
+	copy_to_user ( command->data_in, 0, aoeata->data,
+		       command->data_in_len );
+
+	return 0;
+}
+
+/** AoE ATA command */
+static struct aoe_command_type aoecmd_ata = {
+	.cmd_len = aoecmd_ata_cmd_len,
+	.cmd = aoecmd_ata_cmd,
+	.rsp = aoecmd_ata_rsp,
+};
+
+/**
+ * Calculate length of AoE configuration command IU
+ *
+ * @v aoecmd		AoE command
+ * @ret len		Length of command IU
+ */
+static size_t aoecmd_cfg_cmd_len ( struct aoe_command *aoecmd __unused ) {
+	return ( sizeof ( struct aoehdr ) + sizeof ( struct aoecfg ) );
+}
+
+/**
+ * Build AoE configuration command IU
+ *
+ * @v aoecmd		AoE command
+ * @v data		Command IU
+ * @v len		Length of command IU
+ */
+static void aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
+			     void *data, size_t len ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct aoehdr *aoehdr = data;
+	struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
+
+	/* Sanity check */
+	assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) );
+
+	/* Build IU */
+	aoehdr->command = AOE_CMD_CONFIG;
+	memset ( aoecfg, 0, sizeof ( *aoecfg ) );
+
+	DBGC ( aoedev, "AoE %s/%08x CONFIG cmd\n",
+	       aoedev_name ( aoedev ), aoecmd->tag );
+}
+
+/**
+ * Handle AoE configuration response IU
+ *
+ * @v aoecmd		AoE command
+ * @v data		Response IU
+ * @v len		Length of response IU
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int aoecmd_cfg_rsp ( struct aoe_command *aoecmd, const void *data,
+			    size_t len, const void *ll_source ) {
+	struct aoe_device *aoedev = aoecmd->aoedev;
+	struct ll_protocol *ll_protocol = aoedev->netdev->ll_protocol;
+	const struct aoehdr *aoehdr = data;
+	const struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
+
+	/* Sanity check */
+	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecfg ) ) ) {
+		DBGC ( aoedev, "AoE %s/%08x received underlength "
+		       "configuration response (%zd bytes)\n",
+		       aoedev_name ( aoedev ), aoecmd->tag, len );
+		return -EINVAL;
+	}
+	DBGC ( aoedev, "AoE %s/%08x CONFIG rsp buf %04x fw %04x scnt %02x\n",
+	       aoedev_name ( aoedev ), aoecmd->tag, ntohs ( aoecfg->bufcnt ),
+	       aoecfg->fwver, aoecfg->scnt );
+
+	/* Record target MAC address */
+	memcpy ( aoedev->target, ll_source, ll_protocol->ll_addr_len );
+	DBGC ( aoedev, "AoE %s has MAC address %s\n",
+	       aoedev_name ( aoedev ), ll_protocol->ntoa ( aoedev->target ) );
+
+	return 0;
+}
+
+/** AoE configuration command */
+static struct aoe_command_type aoecmd_cfg = {
+	.cmd_len = aoecmd_cfg_cmd_len,
+	.cmd = aoecmd_cfg_cmd,
+	.rsp = aoecmd_cfg_rsp,
+};
+
+/** AoE command ATA interface operations */
+static struct interface_operation aoecmd_ata_op[] = {
+	INTF_OP ( intf_close, struct aoe_command *, aoecmd_close ),
+};
+
+/** AoE command ATA interface descriptor */
+static struct interface_descriptor aoecmd_ata_desc =
+	INTF_DESC ( struct aoe_command, ata, aoecmd_ata_op );
+
+/**
+ * Identify AoE command by tag
+ *
+ * @v tag		Command tag
+ * @ret aoecmd		AoE command, or NULL
+ */
+static struct aoe_command * aoecmd_find_tag ( uint32_t tag ) {
+	struct aoe_command *aoecmd;
+
+	list_for_each_entry ( aoecmd, &aoe_commands, list ) {
+		if ( aoecmd->tag == tag )
+			return aoecmd;
+	}
+	return NULL;
+}
+
+/**
+ * Choose an AoE command tag
+ *
+ * @ret tag		New tag, or negative error
+ */
+static int aoecmd_new_tag ( void ) {
+	static uint16_t tag_idx;
+	unsigned int i;
+
+	for ( i = 0 ; i < 65536 ; i++ ) {
+		tag_idx++;
+		if ( aoecmd_find_tag ( tag_idx ) == NULL )
+			return ( AOE_TAG_MAGIC | tag_idx );
+	}
+	return -EADDRINUSE;
+}
+
+/**
+ * Create AoE command
+ *
+ * @v aoedev		AoE device
+ * @v type		AoE command type
+ * @ret aoecmd		AoE command
+ */
+static struct aoe_command * aoecmd_create ( struct aoe_device *aoedev,
+					    struct aoe_command_type *type ) {
+	struct aoe_command *aoecmd;
+	int tag;
+
+	/* Allocate command tag */
+	tag = aoecmd_new_tag();
+	if ( tag < 0 )
+		return NULL;
+
+	/* Allocate and initialise structure */
+	aoecmd = zalloc ( sizeof ( *aoecmd ) );
+	if ( ! aoecmd )
+		return NULL;
+	ref_init ( &aoecmd->refcnt, aoecmd_free );
+	list_add ( &aoecmd->list, &aoe_commands );
+	intf_init ( &aoecmd->ata, &aoecmd_ata_desc, &aoecmd->refcnt );
+	timer_init ( &aoecmd->timer, aoecmd_expired, &aoecmd->refcnt );
+	aoecmd->aoedev = aoedev_get ( aoedev );
+	aoecmd->type = type;
+	aoecmd->tag = tag;
+
+	/* Preserve timeout from last completed command */
+	aoecmd->timer.timeout = aoedev->timeout;
+
+	/* Return already mortalised.  (Reference is held by command list.) */
+	return aoecmd;
+}
+
+/**
+ * Issue AoE ATA command
+ *
+ * @v aoedev		AoE device
+ * @v parent		Parent interface
+ * @v command		ATA command
+ * @ret tag		Command tag, or negative error
+ */
+static int aoedev_ata_command ( struct aoe_device *aoedev,
+				struct interface *parent,
+				struct ata_cmd *command ) {
+	struct net_device *netdev = aoedev->netdev;
+	struct aoe_command *aoecmd;
+
+	/* Fail immediately if net device is closed */
+	if ( ! netdev_is_open ( netdev ) ) {
+		DBGC ( aoedev, "AoE %s cannot issue command while net device "
+		       "is closed\n", aoedev_name ( aoedev ) );
+		return -EWOULDBLOCK;
+	}
+
+	/* Create command */
+	aoecmd = aoecmd_create ( aoedev, &aoecmd_ata );
+	if ( ! aoecmd )
+		return -ENOMEM;
+	memcpy ( &aoecmd->command, command, sizeof ( aoecmd->command ) );
+
+	/* Attempt to send command.  Allow failures to be handled by
+	 * the retry timer.
+	 */
+	aoecmd_tx ( aoecmd );
+
+	/* Attach to parent interface, leave reference with command
+	 * list, and return.
+	 */
+	intf_plug_plug ( &aoecmd->ata, parent );
+	return aoecmd->tag;
+}
+
+/**
+ * Issue AoE configuration command
+ *
+ * @v aoedev		AoE device
+ * @v parent		Parent interface
+ * @ret tag		Command tag, or negative error
+ */
+static int aoedev_cfg_command ( struct aoe_device *aoedev,
+				struct interface *parent ) {
+	struct aoe_command *aoecmd;
+
+	/* Create command */
+	aoecmd = aoecmd_create ( aoedev, &aoecmd_cfg );
+	if ( ! aoecmd )
+		return -ENOMEM;
+
+	/* Attempt to send command.  Allow failures to be handled by
+	 * the retry timer.
+	 */
+	aoecmd_tx ( aoecmd );
+
+	/* Attach to parent interface, leave reference with command
+	 * list, and return.
+	 */
+	intf_plug_plug ( &aoecmd->ata, parent );
+	return aoecmd->tag;
+}
+
+/**
+ * Free AoE device
+ *
+ * @v refcnt		Reference count
+ */
+static void aoedev_free ( struct refcnt *refcnt ) {
+	struct aoe_device *aoedev =
+		container_of ( refcnt, struct aoe_device, refcnt );
+
+	netdev_put ( aoedev->netdev );
+	free ( aoedev );
+}
+
+/**
+ * Close AoE device
+ *
+ * @v aoedev		AoE device
+ * @v rc		Reason for close
+ */
+static void aoedev_close ( struct aoe_device *aoedev, int rc ) {
+	struct aoe_command *aoecmd;
+	struct aoe_command *tmp;
+
+	/* Shut down interfaces */
+	intf_shutdown ( &aoedev->ata, rc );
+	intf_shutdown ( &aoedev->config, rc );
+
+	/* Shut down any active commands */
+	list_for_each_entry_safe ( aoecmd, tmp, &aoe_commands, list ) {
+		if ( aoecmd->aoedev != aoedev )
+			continue;
+		aoecmd_get ( aoecmd );
+		aoecmd_close ( aoecmd, rc );
+		aoecmd_put ( aoecmd );
+	}
+}
+
+/**
+ * Check AoE device flow-control window
+ *
+ * @v aoedev		AoE device
+ * @ret len		Length of window
+ */
+static size_t aoedev_window ( struct aoe_device *aoedev ) {
+	return ( aoedev->configured ? ~( ( size_t ) 0 ) : 0 );
+}
+
+/**
+ * Handle AoE device configuration completion
+ *
+ * @v aoedev		AoE device
+ * @v rc		Reason for completion
+ */
+static void aoedev_config_done ( struct aoe_device *aoedev, int rc ) {
+
+	/* Shut down interface */
+	intf_shutdown ( &aoedev->config, rc );
+
+	/* Close device on failure */
+	if ( rc != 0 ) {
+		aoedev_close ( aoedev, rc );
+		return;
+	}
+
+	/* Mark device as configured */
+	aoedev->configured = 1;
+	xfer_window_changed ( &aoedev->ata );
+}
+
+/**
+ * Identify device underlying AoE device
+ *
+ * @v aoedev		AoE device
+ * @ret device		Underlying device
+ */
+static struct device * aoedev_identify_device ( struct aoe_device *aoedev ) {
+	return aoedev->netdev->dev;
+}
+
+/**
+ * Describe AoE device in an ACPI table
+ *
+ * @v aoedev		AoE device
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+static int aoedev_describe ( struct aoe_device *aoedev,
+			     struct acpi_description_header *acpi,
+			     size_t len ) {
+	struct abft_table *abft =
+		container_of ( acpi, struct abft_table, acpi );
+
+	/* Sanity check */
+	if ( len < sizeof ( *abft ) )
+		return -ENOBUFS;
+
+	/* Populate table */
+	abft->acpi.signature = cpu_to_le32 ( ABFT_SIG );
+	abft->acpi.length = cpu_to_le32 ( sizeof ( *abft ) );
+	abft->acpi.revision = 1;
+	abft->shelf = cpu_to_le16 ( aoedev->major );
+	abft->slot = aoedev->minor;
+	memcpy ( abft->mac, aoedev->netdev->ll_addr, sizeof ( abft->mac ) );
+
+	return 0;
+}
+
+/** AoE device ATA interface operations */
+static struct interface_operation aoedev_ata_op[] = {
+	INTF_OP ( ata_command, struct aoe_device *, aoedev_ata_command ),
+	INTF_OP ( xfer_window, struct aoe_device *, aoedev_window ),
+	INTF_OP ( intf_close, struct aoe_device *, aoedev_close ),
+	INTF_OP ( acpi_describe, struct aoe_device *, aoedev_describe ),
+	INTF_OP ( identify_device, struct aoe_device *,
+		  aoedev_identify_device ),
+};
+
+/** AoE device ATA interface descriptor */
+static struct interface_descriptor aoedev_ata_desc =
+	INTF_DESC ( struct aoe_device, ata, aoedev_ata_op );
+
+/** AoE device configuration interface operations */
+static struct interface_operation aoedev_config_op[] = {
+	INTF_OP ( intf_close, struct aoe_device *, aoedev_config_done ),
+};
+
+/** AoE device configuration interface descriptor */
+static struct interface_descriptor aoedev_config_desc =
+	INTF_DESC ( struct aoe_device, config, aoedev_config_op );
+
+/**
+ * Open AoE device
+ *
+ * @v parent		Parent interface
+ * @v netdev		Network device
+ * @v major		Device major number
+ * @v minor		Device minor number
+ * @ret rc		Return status code
+ */
+static int aoedev_open ( struct interface *parent, struct net_device *netdev,
+			 unsigned int major, unsigned int minor ) {
+	struct aoe_device *aoedev;
+	int rc;
+
+	/* Allocate and initialise structure */
+	aoedev = zalloc ( sizeof ( *aoedev ) );
+	if ( ! aoedev ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &aoedev->refcnt, aoedev_free );
+	intf_init ( &aoedev->ata, &aoedev_ata_desc, &aoedev->refcnt );
+	intf_init ( &aoedev->config, &aoedev_config_desc, &aoedev->refcnt );
+	aoedev->netdev = netdev_get ( netdev );
+	aoedev->major = major;
+	aoedev->minor = minor;
+	memcpy ( aoedev->target, netdev->ll_broadcast,
+		 netdev->ll_protocol->ll_addr_len );
+
+	/* Initiate configuration */
+	if ( ( rc = aoedev_cfg_command ( aoedev, &aoedev->config ) ) < 0 ) {
+		DBGC ( aoedev, "AoE %s could not initiate configuration: %s\n",
+		       aoedev_name ( aoedev ), strerror ( rc ) );
+		goto err_config;
+	}
+
+	/* Attach ATA device to parent interface */
+	if ( ( rc = ata_open ( parent, &aoedev->ata, ATA_DEV_MASTER,
+			       AOE_MAX_COUNT ) ) != 0 ) {
+		DBGC ( aoedev, "AoE %s could not create ATA device: %s\n",
+		       aoedev_name ( aoedev ), strerror ( rc ) );
+		goto err_ata_open;
+	}
+
+	/* Mortalise self and return */
+	ref_put ( &aoedev->refcnt );
+	return 0;
+
+ err_ata_open:
+ err_config:
+	aoedev_close ( aoedev, rc );
+	ref_put ( &aoedev->refcnt );
+ err_zalloc:
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * AoE network protocol
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Process incoming AoE packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ *
+ */
+static int aoe_rx ( struct io_buffer *iobuf,
+		    struct net_device *netdev __unused,
+		    const void *ll_dest __unused,
+		    const void *ll_source ) {
+	struct aoehdr *aoehdr = iobuf->data;
+	struct aoe_command *aoecmd;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
+		DBG ( "AoE received underlength packet (%zd bytes)\n",
+		      iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+	if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
+		DBG ( "AoE received packet for unsupported protocol version "
+		      "%02x\n", ( aoehdr->ver_flags & AOE_VERSION_MASK ) );
+		rc = -EPROTONOSUPPORT;
+		goto err_sanity;
+	}
+	if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
+		DBG ( "AoE received request packet\n" );
+		rc = -EOPNOTSUPP;
+		goto err_sanity;
+	}
+
+	/* Demultiplex amongst active AoE commands */
+	aoecmd = aoecmd_find_tag ( ntohl ( aoehdr->tag ) );
+	if ( ! aoecmd ) {
+		DBG ( "AoE received packet for unused tag %08x\n",
+		      ntohl ( aoehdr->tag ) );
+		rc = -ENOENT;
+		goto err_demux;
+	}
+
+	/* Pass received frame to command */
+	aoecmd_get ( aoecmd );
+	if ( ( rc = aoecmd_rx ( aoecmd, iob_disown ( iobuf ),
+				ll_source ) ) != 0 )
+		goto err_rx;
+
+ err_rx:
+	aoecmd_put ( aoecmd );
+ err_demux:
+ err_sanity:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** AoE protocol */
+struct net_protocol aoe_protocol __net_protocol = {
+	.name = "AoE",
+	.net_proto = htons ( ETH_P_AOE ),
+	.rx = aoe_rx,
+};
+
+/******************************************************************************
+ *
+ * AoE URIs
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Parse AoE URI
+ *
+ * @v uri		URI
+ * @ret major		Major device number
+ * @ret minor		Minor device number
+ * @ret rc		Return status code
+ *
+ * An AoE URI has the form "aoe:e<major>.<minor>".
+ */
+static int aoe_parse_uri ( struct uri *uri, unsigned int *major,
+			   unsigned int *minor ) {
+	const char *ptr;
+	char *end;
+
+	/* Check for URI with opaque portion */
+	if ( ! uri->opaque )
+		return -EINVAL;
+	ptr = uri->opaque;
+
+	/* Check for initial 'e' */
+	if ( *ptr != 'e' )
+		return -EINVAL;
+	ptr++;
+
+	/* Parse major device number */
+	*major = strtoul ( ptr, &end, 10 );
+	if ( *end != '.' )
+		return -EINVAL;
+	ptr = ( end + 1 );
+
+	/* Parse minor device number */
+	*minor = strtoul ( ptr, &end, 10 );
+	if ( *end )
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * Open AoE URI
+ *
+ * @v parent		Parent interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int aoe_open ( struct interface *parent, struct uri *uri ) {
+	struct net_device *netdev;
+	unsigned int major;
+	unsigned int minor;
+	int rc;
+
+	/* Identify network device.  This is something of a hack, but
+	 * the AoE URI scheme that has been in use for some time now
+	 * provides no way to specify a particular device.
+	 */
+	netdev = last_opened_netdev();
+	if ( ! netdev ) {
+		DBG ( "AoE cannot identify network device\n" );
+		return -ENODEV;
+	}
+
+	/* Parse URI */
+	if ( ( rc = aoe_parse_uri ( uri, &major, &minor ) ) != 0 ) {
+		DBG ( "AoE cannot parse URI\n" );
+		return rc;
+	}
+
+	/* Open AoE device */
+	if ( ( rc = aoedev_open ( parent, netdev, major, minor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** AoE URI opener */
+struct uri_opener aoe_uri_opener __uri_opener = {
+	.scheme = "aoe",
+	.open = aoe_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/arp.c b/qemu-0.15.x/roms/ipxe/src/net/arp.c
new file mode 100644
index 0000000..9b5fd22
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/arp.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/arp.h>
+
+/** @file
+ *
+ * Address Resolution Protocol
+ *
+ * This file implements the address resolution protocol as defined in
+ * RFC826.  The implementation is media-independent and
+ * protocol-independent; it is not limited to Ethernet or to IPv4.
+ *
+ */
+
+/** An ARP cache entry */
+struct arp_entry {
+	/** Network-layer protocol */
+	struct net_protocol *net_protocol;
+	/** Link-layer protocol */
+	struct ll_protocol *ll_protocol;
+	/** Network-layer address */
+	uint8_t net_addr[MAX_NET_ADDR_LEN];
+	/** Link-layer address */
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
+};
+
+/** Number of entries in the ARP cache
+ *
+ * This is a global cache, covering all network interfaces,
+ * network-layer protocols and link-layer protocols.
+ */
+#define NUM_ARP_ENTRIES 4
+
+/** The ARP cache */
+static struct arp_entry arp_table[NUM_ARP_ENTRIES];
+#define arp_table_end &arp_table[NUM_ARP_ENTRIES]
+
+static unsigned int next_new_arp_entry = 0;
+
+struct net_protocol arp_protocol __net_protocol;
+
+/**
+ * Find entry in the ARP cache
+ *
+ * @v ll_protocol	Link-layer protocol
+ * @v net_protocol	Network-layer protocol
+ * @v net_addr		Network-layer address
+ * @ret arp		ARP cache entry, or NULL if not found
+ *
+ */
+static struct arp_entry *
+arp_find_entry ( struct ll_protocol *ll_protocol,
+		 struct net_protocol *net_protocol,
+		 const void *net_addr ) {
+	struct arp_entry *arp;
+
+	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
+		if ( ( arp->ll_protocol == ll_protocol ) &&
+		     ( arp->net_protocol == net_protocol ) &&
+		     ( memcmp ( arp->net_addr, net_addr,
+				net_protocol->net_addr_len ) == 0 ) )
+			return arp;
+	}
+	return NULL;
+}
+
+/**
+ * Look up media-specific link-layer address in the ARP cache
+ *
+ * @v netdev		Network device
+ * @v net_protocol	Network-layer protocol
+ * @v dest_net_addr	Destination network-layer address
+ * @v source_net_addr	Source network-layer address
+ * @ret dest_ll_addr	Destination link layer address
+ * @ret rc		Return status code
+ *
+ * This function will use the ARP cache to look up the link-layer
+ * address for the link-layer protocol associated with the network
+ * device and the given network-layer protocol and addresses.  If
+ * found, the destination link-layer address will be filled in in @c
+ * dest_ll_addr.
+ *
+ * If no address is found in the ARP cache, an ARP request will be
+ * transmitted on the specified network device and -ENOENT will be
+ * returned.
+ */
+int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
+		  const void *dest_net_addr, const void *source_net_addr,
+		  void *dest_ll_addr ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	const struct arp_entry *arp;
+	struct io_buffer *iobuf;
+	struct arphdr *arphdr;
+	int rc;
+
+	/* Look for existing entry in ARP table */
+	arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
+	if ( arp ) {
+		DBG ( "ARP cache hit: %s %s => %s %s\n",
+		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
+		memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
+		return 0;
+	}
+	DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
+	      net_protocol->ntoa ( dest_net_addr ) );
+
+	/* Allocate ARP packet */
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
+			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+
+	/* Build up ARP request */
+	arphdr = iob_put ( iobuf, sizeof ( *arphdr ) );
+	arphdr->ar_hrd = ll_protocol->ll_proto;
+	arphdr->ar_hln = ll_protocol->ll_addr_len;
+	arphdr->ar_pro = net_protocol->net_proto;
+	arphdr->ar_pln = net_protocol->net_addr_len;
+	arphdr->ar_op = htons ( ARPOP_REQUEST );
+	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
+		 netdev->ll_addr, ll_protocol->ll_addr_len );
+	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
+		 source_net_addr, net_protocol->net_addr_len );
+	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
+		 0, ll_protocol->ll_addr_len );
+	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
+		 dest_net_addr, net_protocol->net_addr_len );
+
+	/* Transmit ARP request */
+	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
+			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 )
+		return rc;
+
+	return -ENOENT;
+}
+
+/**
+ * Identify ARP protocol
+ *
+ * @v net_proto			Network-layer protocol, in network-endian order
+ * @ret arp_net_protocol	ARP protocol, or NULL
+ *
+ */
+static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
+	struct arp_net_protocol *arp_net_protocol;
+
+	for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) {
+		if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
+			return arp_net_protocol;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Process incoming ARP packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ *
+ * This handles ARP requests and responses as detailed in RFC826.  The
+ * method detailed within the RFC is pretty optimised, handling
+ * requests and responses with basically a single code path and
+ * avoiding the need for extraneous ARP requests; read the RFC for
+ * details.
+ */
+static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
+		    const void *ll_dest __unused,
+		    const void *ll_source __unused ) {
+	struct arphdr *arphdr = iobuf->data;
+	struct arp_net_protocol *arp_net_protocol;
+	struct net_protocol *net_protocol;
+	struct ll_protocol *ll_protocol;
+	struct arp_entry *arp;
+	int merge = 0;
+
+	/* Identify network-layer and link-layer protocols */
+	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
+	if ( ! arp_net_protocol )
+		goto done;
+	net_protocol = arp_net_protocol->net_protocol;
+	ll_protocol = netdev->ll_protocol;
+
+	/* Sanity checks */
+	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
+	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
+	     ( arphdr->ar_pln != net_protocol->net_addr_len ) )
+		goto done;
+
+	/* See if we have an entry for this sender, and update it if so */
+	arp = arp_find_entry ( ll_protocol, net_protocol,
+			       arp_sender_pa ( arphdr ) );
+	if ( arp ) {
+		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
+			 arphdr->ar_hln );
+		merge = 1;
+		DBG ( "ARP cache update: %s %s => %s %s\n",
+		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
+	}
+
+	/* See if we own the target protocol address */
+	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
+		goto done;
+	
+	/* Create new ARP table entry if necessary */
+	if ( ! merge ) {
+		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
+		arp->ll_protocol = ll_protocol;
+		arp->net_protocol = net_protocol;
+		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
+			 arphdr->ar_hln );
+		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
+			 arphdr->ar_pln);
+		DBG ( "ARP cache add: %s %s => %s %s\n",
+		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
+	}
+
+	/* If it's not a request, there's nothing more to do */
+	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
+		goto done;
+
+	/* Change request to a reply */
+	DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
+	      net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
+	      ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
+	arphdr->ar_op = htons ( ARPOP_REPLY );
+	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
+		 arphdr->ar_hln + arphdr->ar_pln );
+	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
+
+	/* Send reply */
+	net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
+		 arp_target_ha ( arphdr ), netdev->ll_addr );
+
+ done:
+	free_iob ( iobuf );
+	return 0;
+}
+
+/**
+ * Transcribe ARP address
+ *
+ * @v net_addr	ARP address
+ * @ret string	"<ARP>"
+ *
+ * This operation is meaningless for the ARP protocol.
+ */
+static const char * arp_ntoa ( const void *net_addr __unused ) {
+	return "<ARP>";
+}
+
+/** ARP protocol */
+struct net_protocol arp_protocol __net_protocol = {
+	.name = "ARP",
+	.net_proto = htons ( ETH_P_ARP ),
+	.rx = arp_rx,
+	.ntoa = arp_ntoa,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/cachedhcp.c b/qemu-0.15.x/roms/ipxe/src/net/cachedhcp.c
new file mode 100644
index 0000000..36f480a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/cachedhcp.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcppkt.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/uaccess.h>
+
+/** @file
+ *
+ * Cached DHCP packet handling
+ *
+ */
+
+/**
+ * Store cached DHCPACK packet
+ *
+ * @v data		User pointer to cached DHCP packet data
+ * @v len		Length of cached DHCP packet data
+ * @ret rc		Return status code
+ *
+ * This function should be called by the architecture-specific
+ * get_cached_dhcpack() handler.
+ */
+void store_cached_dhcpack ( userptr_t data, size_t len ) {
+	struct dhcp_packet *dhcppkt;
+	struct dhcphdr *dhcphdr;
+	struct settings *parent;
+	int rc;
+
+	/* Create DHCP packet */
+	dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len );
+	if ( ! dhcppkt )
+		return;
+
+	/* Fill in data for DHCP packet */
+	dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( * dhcppkt ) );
+	copy_from_user ( dhcphdr, data, 0, len );
+	dhcppkt_init ( dhcppkt, dhcphdr, len );
+	DBG_HD ( dhcppkt->options.data, dhcppkt->options.used_len );
+
+	/* Register settings on the last opened network device.
+	 * This will have the effect of registering cached settings
+	 * with a network device when "dhcp netX" is performed for that
+	 * device, which is usually what we want.
+	 */
+	parent = netdev_settings ( last_opened_netdev() );
+	if ( ( rc = register_settings ( &dhcppkt->settings, parent,
+					DHCP_SETTINGS_NAME ) ) != 0 )
+		DBG ( "DHCP could not register cached settings: %s\n",
+		      strerror ( rc ) );
+
+	dhcppkt_put ( dhcppkt );
+
+	DBG ( "DHCP registered cached settings\n" );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/dhcpopts.c b/qemu-0.15.x/roms/ipxe/src/net/dhcpopts.c
new file mode 100644
index 0000000..249fde1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/dhcpopts.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
+
+/** @file
+ *
+ * DHCP options
+ *
+ */
+
+/**
+ * Obtain printable version of a DHCP option tag
+ *
+ * @v tag		DHCP option tag
+ * @ret name		String representation of the tag
+ *
+ */
+static inline char * dhcp_tag_name ( unsigned int tag ) {
+	static char name[8];
+
+	if ( DHCP_IS_ENCAP_OPT ( tag ) ) {
+		snprintf ( name, sizeof ( name ), "%d.%d",
+			   DHCP_ENCAPSULATOR ( tag ),
+			   DHCP_ENCAPSULATED ( tag ) );
+	} else {
+		snprintf ( name, sizeof ( name ), "%d", tag );
+	}
+	return name;
+}
+
+/**
+ * Get pointer to DHCP option
+ *
+ * @v options		DHCP options block
+ * @v offset		Offset within options block
+ * @ret option		DHCP option
+ */
+static inline __attribute__ (( always_inline )) struct dhcp_option *
+dhcp_option ( struct dhcp_options *options, unsigned int offset ) {
+	return ( ( struct dhcp_option * ) ( options->data + offset ) );
+}
+
+/**
+ * Get offset of a DHCP option
+ *
+ * @v options		DHCP options block
+ * @v option		DHCP option
+ * @ret offset		Offset within options block
+ */
+static inline __attribute__ (( always_inline )) int
+dhcp_option_offset ( struct dhcp_options *options,
+		     struct dhcp_option *option ) {
+	return ( ( ( void * ) option ) - options->data );
+}
+
+/**
+ * Calculate length of any DHCP option
+ *
+ * @v option		DHCP option
+ * @ret len		Length (including tag and length field)
+ */
+static unsigned int dhcp_option_len ( struct dhcp_option *option ) {
+	if ( ( option->tag == DHCP_END ) || ( option->tag == DHCP_PAD ) ) {
+		return 1;
+	} else {
+		return ( option->len + DHCP_OPTION_HEADER_LEN );
+	}
+}
+
+/**
+ * Find DHCP option within DHCP options block, and its encapsulator (if any)
+ *
+ * @v options		DHCP options block
+ * @v tag		DHCP option tag to search for
+ * @ret encap_offset	Offset of encapsulating DHCP option
+ * @ret offset		Offset of DHCP option, or negative error
+ *
+ * Searches for the DHCP option matching the specified tag within the
+ * DHCP option block.  Encapsulated options may be searched for by
+ * using DHCP_ENCAP_OPT() to construct the tag value.
+ *
+ * If the option is encapsulated, and @c encap_offset is non-NULL, it
+ * will be filled in with the offset of the encapsulating option.
+ *
+ * This routine is designed to be paranoid.  It does not assume that
+ * the option data is well-formatted, and so must guard against flaws
+ * such as options missing a @c DHCP_END terminator, or options whose
+ * length would take them beyond the end of the data block.
+ */
+static int find_dhcp_option_with_encap ( struct dhcp_options *options,
+					 unsigned int tag,
+					 int *encap_offset ) {
+	unsigned int original_tag __attribute__ (( unused )) = tag;
+	struct dhcp_option *option;
+	int offset = 0;
+	ssize_t remaining = options->used_len;
+	unsigned int option_len;
+
+	/* Sanity check */
+	if ( tag == DHCP_PAD )
+		return -ENOENT;
+
+	/* Search for option */
+	while ( remaining ) {
+		/* Calculate length of this option.  Abort processing
+		 * if the length is malformed (i.e. takes us beyond
+		 * the end of the data block).
+		 */
+		option = dhcp_option ( options, offset );
+		option_len = dhcp_option_len ( option );
+		remaining -= option_len;
+		if ( remaining < 0 )
+			break;
+		/* Check for explicit end marker */
+		if ( option->tag == DHCP_END ) {
+			if ( tag == DHCP_END )
+				/* Special case where the caller is interested
+				 * in whether we have this marker or not.
+				 */
+				return offset;
+			else
+				break;
+		}
+		/* Check for matching tag */
+		if ( option->tag == tag ) {
+			DBGC ( options, "DHCPOPT %p found %s (length %d)\n",
+			       options, dhcp_tag_name ( original_tag ),
+			       option_len );
+			return offset;
+		}
+		/* Check for start of matching encapsulation block */
+		if ( DHCP_IS_ENCAP_OPT ( tag ) &&
+		     ( option->tag == DHCP_ENCAPSULATOR ( tag ) ) ) {
+			if ( encap_offset )
+				*encap_offset = offset;
+			/* Continue search within encapsulated option block */
+			tag = DHCP_ENCAPSULATED ( tag );
+			remaining = option_len;
+			offset += DHCP_OPTION_HEADER_LEN;
+			continue;
+		}
+		offset += option_len;
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * Refuse to reallocate DHCP option block
+ *
+ * @v options		DHCP option block
+ * @v len		New length
+ * @ret rc		Return status code
+ */
+int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len ) {
+	return ( ( len <= options->alloc_len ) ? 0 : -ENOSPC );
+}
+
+/**
+ * Resize a DHCP option
+ *
+ * @v options		DHCP option block
+ * @v offset		Offset of option to resize
+ * @v encap_offset	Offset of encapsulating offset (or -ve for none)
+ * @v old_len		Old length (including header)
+ * @v new_len		New length (including header)
+ * @ret rc		Return status code
+ */
+static int resize_dhcp_option ( struct dhcp_options *options,
+				int offset, int encap_offset,
+				size_t old_len, size_t new_len ) {
+	struct dhcp_option *encapsulator;
+	struct dhcp_option *option;
+	ssize_t delta = ( new_len - old_len );
+	size_t old_alloc_len;
+	size_t new_used_len;
+	size_t new_encapsulator_len;
+	void *source;
+	void *dest;
+	void *end;
+	int rc;
+
+	/* Check for sufficient space */
+	if ( new_len > DHCP_MAX_LEN ) {
+		DBGC ( options, "DHCPOPT %p overlength option\n", options );
+		return -ENOSPC;
+	}
+	new_used_len = ( options->used_len + delta );
+
+	/* Expand options block, if necessary */
+	if ( new_used_len > options->alloc_len ) {
+		/* Reallocate options block */
+		old_alloc_len = options->alloc_len;
+		if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
+			DBGC ( options, "DHCPOPT %p could not reallocate to "
+			       "%zd bytes\n", options, new_used_len );
+			return rc;
+		}
+		/* Clear newly allocated space */
+		memset ( ( options->data + old_alloc_len ), 0,
+			 ( options->alloc_len - old_alloc_len ) );
+	}
+
+	/* Update encapsulator, if applicable */
+	if ( encap_offset >= 0 ) {
+		encapsulator = dhcp_option ( options, encap_offset );
+		new_encapsulator_len = ( encapsulator->len + delta );
+		if ( new_encapsulator_len > DHCP_MAX_LEN ) {
+			DBGC ( options, "DHCPOPT %p overlength encapsulator\n",
+			       options );
+			return -ENOSPC;
+		}
+		encapsulator->len = new_encapsulator_len;
+	}
+
+	/* Update used length */
+	options->used_len = new_used_len;
+
+	/* Move remainder of option data */
+	option = dhcp_option ( options, offset );
+	source = ( ( ( void * ) option ) + old_len );
+	dest = ( ( ( void * ) option ) + new_len );
+	end = ( options->data + options->alloc_len );
+	memmove ( dest, source, ( end - dest ) );
+
+	/* Shrink options block, if applicable */
+	if ( new_used_len < options->alloc_len ) {
+		if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
+			DBGC ( options, "DHCPOPT %p could not reallocate to "
+			       "%zd bytes\n", options, new_used_len );
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Set value of DHCP option
+ *
+ * @v options		DHCP option block
+ * @v tag		DHCP option tag
+ * @v data		New value for DHCP option
+ * @v len		Length of value, in bytes
+ * @ret offset		Offset of DHCP option, or negative error
+ *
+ * Sets the value of a DHCP option within the options block.  The
+ * option may or may not already exist.  Encapsulators will be created
+ * (and deleted) as necessary.
+ *
+ * This call may fail due to insufficient space in the options block.
+ * If it does fail, and the option existed previously, the option will
+ * be left with its original value.
+ */
+static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
+			     const void *data, size_t len ) {
+	static const uint8_t empty_encap[] = { DHCP_END };
+	int offset;
+	int encap_offset = -1;
+	int creation_offset;
+	struct dhcp_option *option;
+	unsigned int encap_tag = DHCP_ENCAPSULATOR ( tag );
+	size_t old_len = 0;
+	size_t new_len = ( len ? ( len + DHCP_OPTION_HEADER_LEN ) : 0 );
+	int rc;
+
+	/* Sanity check */
+	if ( tag == DHCP_PAD )
+		return -ENOTTY;
+
+	creation_offset = find_dhcp_option_with_encap ( options, DHCP_END,
+							NULL );
+	if ( creation_offset < 0 )
+		creation_offset = options->used_len;
+	/* Find old instance of this option, if any */
+	offset = find_dhcp_option_with_encap ( options, tag, &encap_offset );
+	if ( offset >= 0 ) {
+		old_len = dhcp_option_len ( dhcp_option ( options, offset ) );
+		DBGC ( options, "DHCPOPT %p resizing %s from %zd to %zd\n",
+		       options, dhcp_tag_name ( tag ), old_len, new_len );
+	} else {
+		DBGC ( options, "DHCPOPT %p creating %s (length %zd)\n",
+		       options, dhcp_tag_name ( tag ), new_len );
+	}
+
+	/* Ensure that encapsulator exists, if required */
+	if ( encap_tag ) {
+		if ( encap_offset < 0 ) {
+			encap_offset =
+				set_dhcp_option ( options, encap_tag,
+						  empty_encap,
+						  sizeof ( empty_encap ) );
+		}
+		if ( encap_offset < 0 )
+			return encap_offset;
+		creation_offset = ( encap_offset + DHCP_OPTION_HEADER_LEN );
+	}
+
+	/* Create new option if necessary */
+	if ( offset < 0 )
+		offset = creation_offset;
+
+	/* Resize option to fit new data */
+	if ( ( rc = resize_dhcp_option ( options, offset, encap_offset,
+					 old_len, new_len ) ) != 0 )
+		return rc;
+
+	/* Copy new data into option, if applicable */
+	if ( len ) {
+		option = dhcp_option ( options, offset );
+		option->tag = tag;
+		option->len = len;
+		memcpy ( &option->data, data, len );
+	}
+
+	/* Delete encapsulator if there's nothing else left in it */
+	if ( encap_offset >= 0 ) {
+		option = dhcp_option ( options, encap_offset );
+		if ( option->len <= 1 )
+			set_dhcp_option ( options, encap_tag, NULL, 0 );
+	}
+
+	return offset;
+}
+
+/**
+ * Check applicability of DHCP option setting
+ *
+ * @v tag		Setting tag number
+ * @ret applies		Setting applies to this option block
+ */
+int dhcpopt_applies ( unsigned int tag ) {
+
+	return ( tag && ( tag <= DHCP_ENCAP_OPT ( DHCP_MAX_OPTION,
+						  DHCP_MAX_OPTION ) ) );
+}
+
+/**
+ * Store value of DHCP option setting
+ *
+ * @v options		DHCP option block
+ * @v tag		Setting tag number
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
+		    const void *data, size_t len ) {
+	int offset;
+
+	offset = set_dhcp_option ( options, tag, data, len );
+	if ( offset < 0 )
+		return offset;
+	return 0;
+}
+
+/**
+ * Fetch value of DHCP option setting
+ *
+ * @v options		DHCP option block
+ * @v tag		Setting tag number
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
+		    void *data, size_t len ) {
+	int offset;
+	struct dhcp_option *option;
+	size_t option_len;
+
+	offset = find_dhcp_option_with_encap ( options, tag, NULL );
+	if ( offset < 0 )
+		return offset;
+
+	option = dhcp_option ( options, offset );
+	option_len = option->len;
+	if ( len > option_len )
+		len = option_len;
+	memcpy ( data, option->data, len );
+
+	return option_len;
+}
+
+/**
+ * Recalculate length of DHCP options block
+ *
+ * @v options		Uninitialised DHCP option block
+ *
+ * The "used length" field will be updated based on scanning through
+ * the block to find the end of the options.
+ */
+void dhcpopt_update_used_len ( struct dhcp_options *options ) {
+	struct dhcp_option *option;
+	int offset = 0;
+	ssize_t remaining = options->alloc_len;
+	unsigned int option_len;
+
+	/* Find last non-pad option */
+	options->used_len = 0;
+	while ( remaining ) {
+		option = dhcp_option ( options, offset );
+		option_len = dhcp_option_len ( option );
+		remaining -= option_len;
+		if ( remaining < 0 )
+			break;
+		offset += option_len;
+		if ( option->tag != DHCP_PAD )
+			options->used_len = offset;
+	}
+}
+
+/**
+ * Initialise prepopulated block of DHCP options
+ *
+ * @v options		Uninitialised DHCP option block
+ * @v data		Memory for DHCP option data
+ * @v alloc_len		Length of memory for DHCP option data
+ * @v realloc		DHCP option block reallocator
+ *
+ * The memory content must already be filled with valid DHCP options.
+ * A zeroed block counts as a block of valid DHCP options.
+ */
+void dhcpopt_init ( struct dhcp_options *options, void *data, size_t alloc_len,
+		    int ( * realloc ) ( struct dhcp_options *options,
+					size_t len ) ) {
+
+	/* Fill in fields */
+	options->data = data;
+	options->alloc_len = alloc_len;
+	options->realloc = realloc;
+
+	/* Update length */
+	dhcpopt_update_used_len ( options );
+
+	DBGC ( options, "DHCPOPT %p created (data %p lengths %#zx,%#zx)\n",
+	       options, options->data, options->used_len, options->alloc_len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/dhcppkt.c b/qemu-0.15.x/roms/ipxe/src/net/dhcppkt.c
new file mode 100644
index 0000000..0a0e458
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/dhcppkt.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
+#include <ipxe/dhcppkt.h>
+
+/** @file
+ *
+ * DHCP packets
+ *
+ */
+
+/****************************************************************************
+ *
+ * DHCP packet raw interface
+ *
+ */
+
+/**
+ * Calculate used length of an IPv4 field within a DHCP packet
+ *
+ * @v data		Field data
+ * @v len		Length of field
+ * @ret used		Used length of field
+ */
+static size_t used_len_ipv4 ( const void *data, size_t len __unused ) {
+	const struct in_addr *in = data;
+
+	return ( in->s_addr ? sizeof ( *in ) : 0 );
+}
+
+/**
+ * Calculate used length of a string field within a DHCP packet
+ *
+ * @v data		Field data
+ * @v len		Length of field
+ * @ret used		Used length of field
+ */
+static size_t used_len_string ( const void *data, size_t len ) {
+	return strnlen ( data, len );
+}
+
+/** A dedicated field within a DHCP packet */
+struct dhcp_packet_field {
+	/** Settings tag number */
+	unsigned int tag;
+	/** Offset within DHCP packet */
+	uint16_t offset;
+	/** Length of field */
+	uint16_t len;
+	/** Calculate used length of field
+	 *
+	 * @v data	Field data
+	 * @v len	Length of field
+	 * @ret used	Used length of field
+	 */
+	size_t ( * used_len ) ( const void *data, size_t len );
+};
+
+/** Declare a dedicated field within a DHCP packet
+ *
+ * @v _tag		Settings tag number
+ * @v _field		Field name
+ * @v _used_len		Function to calculate used length of field
+ */
+#define DHCP_PACKET_FIELD( _tag, _field, _used_len ) {			\
+		.tag = (_tag),						\
+		.offset = offsetof ( struct dhcphdr, _field ),		\
+		.len = sizeof ( ( ( struct dhcphdr * ) 0 )->_field ),	\
+		.used_len = _used_len,					\
+	}
+
+/** Dedicated fields within a DHCP packet */
+static struct dhcp_packet_field dhcp_packet_fields[] = {
+	DHCP_PACKET_FIELD ( DHCP_EB_YIADDR, yiaddr, used_len_ipv4 ),
+	DHCP_PACKET_FIELD ( DHCP_EB_SIADDR, siaddr, used_len_ipv4 ),
+	DHCP_PACKET_FIELD ( DHCP_TFTP_SERVER_NAME, sname, used_len_string ),
+	DHCP_PACKET_FIELD ( DHCP_BOOTFILE_NAME, file, used_len_string ),
+};
+
+/**
+ * Get address of a DHCP packet field
+ *
+ * @v dhcphdr		DHCP packet header
+ * @v field		DHCP packet field
+ * @ret data		Packet field data
+ */
+static inline void * dhcp_packet_field ( struct dhcphdr *dhcphdr,
+					 struct dhcp_packet_field *field ) {
+	return ( ( ( void * ) dhcphdr ) + field->offset );
+}
+
+/**
+ * Find DHCP packet field corresponding to settings tag number
+ *
+ * @v tag		Settings tag number
+ * @ret field		DHCP packet field, or NULL
+ */
+static struct dhcp_packet_field *
+find_dhcp_packet_field ( unsigned int tag ) {
+	struct dhcp_packet_field *field;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( dhcp_packet_fields ) /
+			    sizeof ( dhcp_packet_fields[0] ) ) ; i++ ) {
+		field = &dhcp_packet_fields[i];
+		if ( field->tag == tag )
+			return field;
+	}
+	return NULL;
+}
+
+/**
+ * Check applicability of DHCP setting
+ *
+ * @v dhcppkt		DHCP packet
+ * @v tag		Setting tag number
+ * @ret applies		Setting applies within this settings block
+ */
+static int dhcppkt_applies ( struct dhcp_packet *dhcppkt __unused,
+			     unsigned int tag ) {
+
+	return dhcpopt_applies ( tag );
+}
+
+/**
+ * Store value of DHCP packet setting
+ *
+ * @v dhcppkt		DHCP packet
+ * @v tag		Setting tag number
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
+		    const void *data, size_t len ) {
+	struct dhcp_packet_field *field;
+	void *field_data;
+
+	/* If this is a special field, fill it in */
+	if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
+		if ( len > field->len )
+			return -ENOSPC;
+		field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
+		memset ( field_data, 0, field->len );
+		memcpy ( dhcp_packet_field ( dhcppkt->dhcphdr, field ),
+			 data, len );
+		/* Erase any equivalent option from the options block */
+		dhcpopt_store ( &dhcppkt->options, tag, NULL, 0 );
+		return 0;
+	}
+
+	/* Otherwise, use the generic options block */
+	return dhcpopt_store ( &dhcppkt->options, tag, data, len );
+}
+
+/**
+ * Fetch value of DHCP packet setting
+ *
+ * @v dhcppkt		DHCP packet
+ * @v tag		Setting tag number
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
+		    void *data, size_t len ) {
+	struct dhcp_packet_field *field;
+	void *field_data;
+	size_t field_len = 0;
+	
+	/* Identify special field, if any */
+	if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
+		field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
+		field_len = field->used_len ( field_data, field->len );
+	}
+
+	/* Return special field, if it exists and is populated */
+	if ( field_len ) {
+		if ( len > field_len )
+			len = field_len;
+		memcpy ( data, field_data, len );
+		return field_len;
+	}
+
+	/* Otherwise, use the generic options block */
+	return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
+}
+
+/****************************************************************************
+ *
+ * DHCP packet settings interface
+ *
+ */
+
+/**
+ * Check applicability of DHCP setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int dhcppkt_settings_applies ( struct settings *settings,
+				      struct setting *setting ) {
+	struct dhcp_packet *dhcppkt =
+		container_of ( settings, struct dhcp_packet, settings );
+
+	return dhcppkt_applies ( dhcppkt, setting->tag );
+}
+
+/**
+ * Store value of DHCP setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int dhcppkt_settings_store ( struct settings *settings,
+				    struct setting *setting,
+				    const void *data, size_t len ) {
+	struct dhcp_packet *dhcppkt =
+		container_of ( settings, struct dhcp_packet, settings );
+
+	return dhcppkt_store ( dhcppkt, setting->tag, data, len );
+}
+
+/**
+ * Fetch value of DHCP setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret len		Length of setting data, or negative error
+ */
+static int dhcppkt_settings_fetch ( struct settings *settings,
+				    struct setting *setting,
+				    void *data, size_t len ) {
+	struct dhcp_packet *dhcppkt =
+		container_of ( settings, struct dhcp_packet, settings );
+
+	return dhcppkt_fetch ( dhcppkt, setting->tag, data, len );
+}
+
+/** DHCP settings operations */
+static struct settings_operations dhcppkt_settings_operations = {
+	.applies = dhcppkt_settings_applies,
+	.store = dhcppkt_settings_store,
+	.fetch = dhcppkt_settings_fetch,
+};
+
+/****************************************************************************
+ *
+ * Constructor
+ *
+ */
+
+/**
+ * Initialise DHCP packet
+ *
+ * @v dhcppkt		DHCP packet structure to fill in
+ * @v data		DHCP packet raw data
+ * @v max_len		Length of raw data buffer
+ *
+ * Initialise a DHCP packet structure from a data buffer containing a
+ * DHCP packet.
+ */
+void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
+		    size_t len ) {
+	ref_init ( &dhcppkt->refcnt, NULL );
+	dhcppkt->dhcphdr = data;
+	dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
+		       ( len - offsetof ( struct dhcphdr, options ) ),
+		       dhcpopt_no_realloc );
+	settings_init ( &dhcppkt->settings,
+			&dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/eapol.c b/qemu-0.15.x/roms/ipxe/src/net/eapol.c
new file mode 100644
index 0000000..9e5f264
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/eapol.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * 802.1X Extensible Authentication Protocol over LANs demultiplexer
+ *
+ */
+
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/eapol.h>
+#include <errno.h>
+#include <byteswap.h>
+
+/**
+ * Receive EAPOL network-layer packet
+ *
+ * @v iob	I/O buffer
+ * @v netdev	Network device
+ * @v ll_dest	Link-layer destination address
+ * @v ll_source	Link-layer source address
+ *
+ * This function takes ownership of the I/O buffer passed to it.
+ */
+static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev,
+		      const void *ll_dest, const void *ll_source ) {
+	struct eapol_frame *eapol = iob->data;
+	struct eapol_handler *handler;
+
+	if ( iob_len ( iob ) < EAPOL_HDR_LEN ) {
+		free_iob ( iob );
+		return -EINVAL;
+	}
+
+	for_each_table_entry ( handler, EAPOL_HANDLERS ) {
+		if ( handler->type == eapol->type ) {
+			iob_pull ( iob, EAPOL_HDR_LEN );
+			return handler->rx ( iob, netdev, ll_dest, ll_source );
+		}
+	}
+
+	free_iob ( iob );
+	return -( ENOTSUP | ( ( eapol->type & 0x1f ) << 8 ) );
+}
+
+/**
+ * Transcribe EAPOL network-layer address
+ *
+ * @v net_addr	Network-layer address
+ * @ret str	String representation of network-layer address
+ *
+ * EAPOL doesn't have network-layer addresses, so we just return the
+ * string @c "<EAPOL>".
+ */
+static const char * eapol_ntoa ( const void *net_addr __unused )
+{
+	return "<EAPOL>";
+}
+
+/** EAPOL network protocol */
+struct net_protocol eapol_protocol __net_protocol = {
+	.name = "EAPOL",
+	.rx = eapol_rx,
+	.ntoa = eapol_ntoa,
+	.net_proto = htons ( ETH_P_EAPOL ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/eth_slow.c b/qemu-0.15.x/roms/ipxe/src/net/eth_slow.c
new file mode 100644
index 0000000..9e68939
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/eth_slow.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/eth_slow.h>
+
+/** @file
+ *
+ * Ethernet slow protocols
+ *
+ * We implement a very simple passive LACP entity, that pretends that
+ * each port is the only port on an individual system.  We avoid the
+ * need for timeout logic (and retaining local state about our
+ * partner) by requesting the same timeout period (1s or 30s) as our
+ * partner requests, and then simply responding to every packet the
+ * partner sends us.
+ */
+
+struct net_protocol eth_slow_protocol __net_protocol;
+
+/** Slow protocols multicast address */
+static const uint8_t eth_slow_address[ETH_ALEN] =
+	{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
+
+/**
+ * Name LACP TLV type
+ *
+ * @v type		LACP TLV type
+ * @ret name		Name of LACP TLV type
+ */
+static inline __attribute__ (( always_inline )) const char *
+eth_slow_lacp_tlv_name ( uint8_t type ) {
+	switch ( type ) {
+	case ETH_SLOW_TLV_TERMINATOR:		return "terminator";
+	case ETH_SLOW_TLV_LACP_ACTOR:		return "actor";
+	case ETH_SLOW_TLV_LACP_PARTNER:		return "partner";
+	case ETH_SLOW_TLV_LACP_COLLECTOR:	return "collector";
+	default:				return "<invalid>";
+	}
+}
+
+/**
+ * Name marker TLV type
+ *
+ * @v type		Marker TLV type
+ * @ret name		Name of marker TLV type
+ */
+static inline __attribute__ (( always_inline )) const char *
+eth_slow_marker_tlv_name ( uint8_t type ) {
+	switch ( type ) {
+	case ETH_SLOW_TLV_TERMINATOR:		return "terminator";
+	case ETH_SLOW_TLV_MARKER_REQUEST:	return "request";
+	case ETH_SLOW_TLV_MARKER_RESPONSE:	return "response";
+	default:				return "<invalid>";
+	}
+}
+
+/**
+ * Name LACP state
+ *
+ * @v state		LACP state
+ * @ret name		LACP state name
+ */
+static const char * eth_slow_lacp_state_name ( uint8_t state ) {
+	static char state_chars[] = "AFGSRTLX";
+	unsigned int i;
+
+	for ( i = 0 ; i < 8 ; i++ ) {
+		state_chars[i] |= 0x20;
+		if ( state & ( 1 << i ) )
+			state_chars[i] &= ~0x20;
+	}
+	return state_chars;
+}
+
+/**
+ * Dump LACP packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v label		"RX" or "TX"
+ */
+static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
+				 struct net_device *netdev,
+				 const char *label ) {
+	union eth_slow_packet *eth_slow = iobuf->data;
+	struct eth_slow_lacp *lacp = &eth_slow->lacp;
+
+	DBGC ( netdev,
+	       "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
+	       netdev->name, label, ntohs ( lacp->actor.system_priority ),
+	       eth_ntoa ( lacp->actor.system ),
+	       ntohs ( lacp->actor.key ),
+	       ntohs ( lacp->actor.port_priority ),
+	       ntohs ( lacp->actor.port ),
+	       eth_slow_lacp_state_name ( lacp->actor.state ) );
+	DBGC ( netdev,
+	       "SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
+	       netdev->name, label, ntohs ( lacp->partner.system_priority ),
+	       eth_ntoa ( lacp->partner.system ),
+	       ntohs ( lacp->partner.key ),
+	       ntohs ( lacp->partner.port_priority ),
+	       ntohs ( lacp->partner.port ),
+	       eth_slow_lacp_state_name ( lacp->partner.state ) );
+	DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n",
+	       netdev->name, label, ntohs ( lacp->collector.max_delay ),
+	       ( ntohs ( lacp->collector.max_delay ) * 10 ) );
+	DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
+}
+
+/**
+ * Process incoming LACP packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int eth_slow_lacp_rx ( struct io_buffer *iobuf,
+			      struct net_device *netdev ) {
+	union eth_slow_packet *eth_slow = iobuf->data;
+	struct eth_slow_lacp *lacp = &eth_slow->lacp;
+
+	eth_slow_lacp_dump ( iobuf, netdev, "RX" );
+
+	/* Build response */
+	memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
+	memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );
+	memset ( &lacp->collector, 0, sizeof ( lacp->collector ) );
+	lacp->collector.tlv.type = ETH_SLOW_TLV_LACP_COLLECTOR;
+	lacp->collector.tlv.length = ETH_SLOW_TLV_LACP_COLLECTOR_LEN;
+	memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) );
+	lacp->partner.tlv.type = ETH_SLOW_TLV_LACP_PARTNER;
+	lacp->partner.tlv.length = ETH_SLOW_TLV_LACP_PARTNER_LEN;
+	memset ( &lacp->partner.reserved, 0,
+		 sizeof ( lacp->partner.reserved ) );
+	memset ( &lacp->actor, 0, sizeof ( lacp->actor ) );
+	lacp->actor.tlv.type = ETH_SLOW_TLV_LACP_ACTOR;
+	lacp->actor.tlv.length = ETH_SLOW_TLV_LACP_ACTOR_LEN;
+	lacp->actor.system_priority = htons ( LACP_SYSTEM_PRIORITY_MAX );
+	memcpy ( lacp->actor.system, netdev->ll_addr,
+		 sizeof ( lacp->actor.system ) );
+	lacp->actor.key = htons ( 1 );
+	lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX );
+	lacp->actor.port = htons ( 1 );
+	lacp->actor.state = ( LACP_STATE_IN_SYNC |
+			      LACP_STATE_COLLECTING |
+			      LACP_STATE_DISTRIBUTING |
+			      ( lacp->partner.state & LACP_STATE_FAST ) );
+	lacp->header.version = ETH_SLOW_LACP_VERSION;
+
+	/* Send response */
+	eth_slow_lacp_dump ( iobuf, netdev, "TX" );
+	return net_tx ( iobuf, netdev, &eth_slow_protocol, eth_slow_address,
+			netdev->ll_addr );
+}
+
+/**
+ * Dump marker packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v label		"RX" or "TX"
+ */
+static void eth_slow_marker_dump ( struct io_buffer *iobuf,
+				   struct net_device *netdev,
+				   const char *label ) {
+	union eth_slow_packet *eth_slow = iobuf->data;
+	struct eth_slow_marker *marker = &eth_slow->marker;
+
+	DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
+	       netdev->name, label,
+	       eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
+	       ntohs ( marker->marker.port ),
+	       eth_ntoa ( marker->marker.system ),
+	       ntohl ( marker->marker.xact ) );
+	DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
+}
+
+/**
+ * Process incoming marker packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int eth_slow_marker_rx ( struct io_buffer *iobuf,
+				struct net_device *netdev ) {
+	union eth_slow_packet *eth_slow = iobuf->data;
+	struct eth_slow_marker *marker = &eth_slow->marker;
+
+	eth_slow_marker_dump ( iobuf, netdev, "RX" );
+
+	if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
+		/* Send marker response */
+		marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE;
+		eth_slow_marker_dump ( iobuf, netdev, "TX" );
+		return net_tx ( iobuf, netdev, &eth_slow_protocol,
+				eth_slow_address, netdev->ll_addr );
+	} else {
+		/* Discard all other marker packets */
+		free_iob ( iobuf );
+		return -EINVAL;
+	}
+}
+
+/**
+ * Process incoming slow packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int eth_slow_rx ( struct io_buffer *iobuf,
+			 struct net_device *netdev,
+			 const void *ll_dest __unused,
+			 const void *ll_source __unused ) {
+	union eth_slow_packet *eth_slow = iobuf->data;
+
+	/* Sanity checks */
+	if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
+		free_iob ( iobuf );
+		return -EINVAL;
+	}
+
+	/* Handle according to subtype */
+	switch ( eth_slow->header.subtype ) {
+	case ETH_SLOW_SUBTYPE_LACP:
+		return eth_slow_lacp_rx ( iobuf, netdev );
+	case ETH_SLOW_SUBTYPE_MARKER:
+		return eth_slow_marker_rx ( iobuf, netdev );
+	default:
+		DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n",
+		       netdev->name, eth_slow->header.subtype );
+		free_iob ( iobuf );
+		return -EINVAL;
+	}
+}
+
+/** Slow protocol */
+struct net_protocol eth_slow_protocol __net_protocol = {
+	.name = "Slow",
+	.net_proto = htons ( ETH_P_SLOW ),
+	.rx = eth_slow_rx,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/ethernet.c b/qemu-0.15.x/roms/ipxe/src/net/ethernet.c
new file mode 100644
index 0000000..d14cfef
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/ethernet.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/in.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ethernet.h>
+
+/** @file
+ *
+ * Ethernet protocol
+ *
+ */
+
+/** Ethernet broadcast MAC address */
+static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/**
+ * Add Ethernet link-layer header
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Source link-layer address
+ * @v net_proto		Network-layer protocol, in network-byte order
+ * @ret rc		Return status code
+ */
+static int eth_push ( struct net_device *netdev __unused,
+		      struct io_buffer *iobuf, const void *ll_dest,
+		      const void *ll_source, uint16_t net_proto ) {
+	struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
+
+	/* Build Ethernet header */
+	memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
+	memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
+	ethhdr->h_protocol = net_proto;
+
+	return 0;
+}
+
+/**
+ * Remove Ethernet link-layer header
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret ll_dest		Link-layer destination address
+ * @ret ll_source	Source link-layer address
+ * @ret net_proto	Network-layer protocol, in network-byte order
+ * @ret rc		Return status code
+ */
+static int eth_pull ( struct net_device *netdev __unused, 
+		      struct io_buffer *iobuf, const void **ll_dest,
+		      const void **ll_source, uint16_t *net_proto ) {
+	struct ethhdr *ethhdr = iobuf->data;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
+		DBG ( "Ethernet packet too short (%zd bytes)\n",
+		      iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+
+	/* Strip off Ethernet header */
+	iob_pull ( iobuf, sizeof ( *ethhdr ) );
+
+	/* Fill in required fields */
+	*ll_dest = ethhdr->h_dest;
+	*ll_source = ethhdr->h_source;
+	*net_proto = ethhdr->h_protocol;
+
+	return 0;
+}
+
+/**
+ * Initialise Ethernet address
+ *
+ * @v hw_addr		Hardware address
+ * @v ll_addr		Link-layer address
+ */
+void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
+	memcpy ( ll_addr, hw_addr, ETH_ALEN );
+}
+
+/**
+ * Transcribe Ethernet address
+ *
+ * @v ll_addr		Link-layer address
+ * @ret string		Link-layer address in human-readable format
+ */
+const char * eth_ntoa ( const void *ll_addr ) {
+	static char buf[18]; /* "00:00:00:00:00:00" */
+	const uint8_t *eth_addr = ll_addr;
+
+	sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+		  eth_addr[0], eth_addr[1], eth_addr[2],
+		  eth_addr[3], eth_addr[4], eth_addr[5] );
+	return buf;
+}
+
+/**
+ * Hash multicast address
+ *
+ * @v af		Address family
+ * @v net_addr		Network-layer address
+ * @v ll_addr		Link-layer address to fill in
+ * @ret rc		Return status code
+ */
+int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
+	const uint8_t *net_addr_bytes = net_addr;
+	uint8_t *ll_addr_bytes = ll_addr;
+
+	switch ( af ) {
+	case AF_INET:
+		ll_addr_bytes[0] = 0x01;
+		ll_addr_bytes[1] = 0x00;
+		ll_addr_bytes[2] = 0x5e;
+		ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
+		ll_addr_bytes[4] = net_addr_bytes[2];
+		ll_addr_bytes[5] = net_addr_bytes[3];
+		return 0;
+	default:
+		return -ENOTSUP;
+	}
+}
+
+/**
+ * Generate Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr		Link-layer address
+ * @v eth_addr		Ethernet-compatible address to fill in
+ */
+int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
+	memcpy ( eth_addr, ll_addr, ETH_ALEN );
+	return 0;
+}
+
+/** Ethernet protocol */
+struct ll_protocol ethernet_protocol __ll_protocol = {
+	.name		= "Ethernet",
+	.ll_proto	= htons ( ARPHRD_ETHER ),
+	.hw_addr_len	= ETH_ALEN,
+	.ll_addr_len	= ETH_ALEN,
+	.ll_header_len	= ETH_HLEN,
+	.push		= eth_push,
+	.pull		= eth_pull,
+	.init_addr	= eth_init_addr,
+	.ntoa		= eth_ntoa,
+	.mc_hash	= eth_mc_hash,
+	.eth_addr	= eth_eth_addr,
+};
+
+/**
+ * Allocate Ethernet device
+ *
+ * @v priv_size		Size of driver private data
+ * @ret netdev		Network device, or NULL
+ */
+struct net_device * alloc_etherdev ( size_t priv_size ) {
+	struct net_device *netdev;
+
+	netdev = alloc_netdev ( priv_size );
+	if ( netdev ) {
+		netdev->ll_protocol = &ethernet_protocol;
+		netdev->ll_broadcast = eth_broadcast;
+		netdev->max_pkt_len = ETH_FRAME_LEN;
+	}
+	return netdev;
+}
+
+/* Drag in Ethernet slow protocols */
+REQUIRE_OBJECT ( eth_slow );
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fakedhcp.c b/qemu-0.15.x/roms/ipxe/src/net/fakedhcp.c
new file mode 100644
index 0000000..b43e9b1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fakedhcp.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ipxe/settings.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/dhcppkt.h>
+#include <ipxe/fakedhcp.h>
+
+/** @file
+ *
+ * Fake DHCP packets
+ *
+ */
+
+/**
+ * Copy settings to DHCP packet
+ *
+ * @v dest		Destination DHCP packet
+ * @v source		Source settings block
+ * @v encapsulator	Encapsulating setting tag number, or zero
+ * @ret rc		Return status code
+ */
+static int copy_encap_settings ( struct dhcp_packet *dest,
+				 struct settings *source,
+				 unsigned int encapsulator ) {
+	struct setting setting = { .name = "" };
+	unsigned int subtag;
+	unsigned int tag;
+	int len;
+	int check_len;
+	int rc;
+
+	for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) {
+		tag = DHCP_ENCAP_OPT ( encapsulator, subtag );
+		switch ( tag ) {
+		case DHCP_EB_ENCAP:
+		case DHCP_VENDOR_ENCAP:
+			/* Process encapsulated settings */
+			if ( ( rc = copy_encap_settings ( dest, source,
+							  tag ) ) != 0 )
+				return rc;
+			break;
+		default:
+			/* Copy setting, if present */
+			setting.tag = tag;
+			len = fetch_setting_len ( source, &setting );
+			if ( len < 0 )
+				break;
+			{
+				char buf[len];
+
+				check_len = fetch_setting ( source, &setting,
+							    buf, sizeof (buf));
+				assert ( check_len == len );
+				if ( ( rc = dhcppkt_store ( dest, tag, buf,
+							    sizeof(buf) )) !=0)
+					return rc;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Copy settings to DHCP packet
+ *
+ * @v dest		Destination DHCP packet
+ * @v source		Source settings block
+ * @ret rc		Return status code
+ */
+static int copy_settings ( struct dhcp_packet *dest,
+			   struct settings *source ) {
+	return copy_encap_settings ( dest, source, 0 );
+}
+
+/**
+ * Create fake DHCPDISCOVER packet
+ *
+ * @v netdev		Network device
+ * @v data		Buffer for DHCP packet
+ * @v max_len		Size of DHCP packet buffer
+ * @ret rc		Return status code
+ *
+ * Used by external code.
+ */
+int create_fakedhcpdiscover ( struct net_device *netdev,
+			      void *data, size_t max_len ) {
+	struct dhcp_packet dhcppkt;
+	struct in_addr ciaddr = { 0 };
+	int rc;
+
+	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
+					  ciaddr, data, max_len ) ) != 0 ) {
+		DBG ( "Could not create DHCPDISCOVER: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Create fake DHCPACK packet
+ *
+ * @v netdev		Network device
+ * @v data		Buffer for DHCP packet
+ * @v max_len		Size of DHCP packet buffer
+ * @ret rc		Return status code
+ *
+ * Used by external code.
+ */
+int create_fakedhcpack ( struct net_device *netdev,
+			 void *data, size_t max_len ) {
+	struct dhcp_packet dhcppkt;
+	int rc;
+
+	/* Create base DHCPACK packet */
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
+					 data, max_len ) ) != 0 ) {
+		DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	/* Merge in globally-scoped settings, then netdev-specific
+	 * settings.  Do it in this order so that netdev-specific
+	 * settings take precedence regardless of stated priorities.
+	 */
+	if ( ( rc = copy_settings ( &dhcppkt, NULL ) ) != 0 ) {
+		DBG ( "Could not set DHCPACK global settings: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+	if ( ( rc = copy_settings ( &dhcppkt,
+				    netdev_settings ( netdev ) ) ) != 0 ) {
+		DBG ( "Could not set DHCPACK netdev settings: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Create fake PXE Boot Server ACK packet
+ *
+ * @v netdev		Network device
+ * @v data		Buffer for DHCP packet
+ * @v max_len		Size of DHCP packet buffer
+ * @ret rc		Return status code
+ *
+ * Used by external code.
+ */
+int create_fakepxebsack ( struct net_device *netdev,
+			  void *data, size_t max_len ) {
+	struct dhcp_packet dhcppkt;
+	struct settings *proxy_settings;
+	struct settings *pxebs_settings;
+	int rc;
+
+	/* Identify available settings */
+	proxy_settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
+	pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
+	if ( ( ! proxy_settings ) && ( ! pxebs_settings ) ) {
+		/* No PXE boot server; return the regular DHCPACK */
+		return create_fakedhcpack ( netdev, data, max_len );
+	}
+
+	/* Create base DHCPACK packet */
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
+					 data, max_len ) ) != 0 ) {
+		DBG ( "Could not create PXE BS ACK: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Merge in ProxyDHCP options */
+	if ( proxy_settings &&
+	     ( ( rc = copy_settings ( &dhcppkt, proxy_settings ) ) != 0 ) ) {
+		DBG ( "Could not copy ProxyDHCP settings: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Merge in BootServerDHCP options, if present */
+	if ( pxebs_settings &&
+	     ( ( rc = copy_settings ( &dhcppkt, pxebs_settings ) ) != 0 ) ) {
+		DBG ( "Could not copy PXE BS settings: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fc.c b/qemu-0.15.x/roms/ipxe/src/net/fc.c
new file mode 100644
index 0000000..1934fab
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fc.c
@@ -0,0 +1,1900 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/timer.h>
+#include <ipxe/retry.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/fcns.h>
+
+/** @file
+ *
+ * Fibre Channel
+ *
+ */
+
+/** List of Fibre Channel ports */
+LIST_HEAD ( fc_ports );
+
+/** List of Fibre Channel peers */
+LIST_HEAD ( fc_peers );
+
+/******************************************************************************
+ *
+ * Well-known addresses
+ *
+ ******************************************************************************
+ */
+
+/** Unassigned port ID */
+struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
+
+/** F_Port contoller port ID */
+struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
+
+/** Generic services port ID */
+struct fc_port_id fc_gs_port_id = { .bytes = { 0xff, 0xff, 0xfc } };
+
+/** Point-to-point low port ID */
+struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
+
+/** Point-to-point high port ID */
+struct fc_port_id fc_ptp_high_port_id = { .bytes = { 0x01, 0x01, 0x02 } };
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Format Fibre Channel port ID
+ *
+ * @v id		Fibre Channel port ID
+ * @ret id_text		Port ID text
+ */
+const char * fc_id_ntoa ( const struct fc_port_id *id ) {
+	static char id_text[ FC_PORT_ID_STRLEN + 1 /* NUL */ ];
+
+	snprintf ( id_text, sizeof ( id_text ), "%02x.%02x.%02x",
+		   id->bytes[0], id->bytes[1], id->bytes[2] );
+	return id_text;
+}
+
+/**
+ * Parse Fibre Channel port ID
+ *
+ * @v id_text		Port ID text
+ * @ret id		Fibre Channel port ID
+ * @ret rc		Return status code
+ */
+int fc_id_aton ( const char *id_text, struct fc_port_id *id ) {
+	char *ptr = ( ( char * ) id_text );
+	unsigned int i = 0;
+
+	while ( 1 ) {
+		id->bytes[i++] = strtoul ( ptr, &ptr, 16 );
+		if ( i == sizeof ( id->bytes ) )
+			return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
+		if ( *ptr != '.' )
+			return -EINVAL;
+		ptr++;
+	}
+}
+
+/**
+ * Format Fibre Channel WWN
+ *
+ * @v wwn		Fibre Channel WWN
+ * @ret wwn_text	WWN text
+ */
+const char * fc_ntoa ( const struct fc_name *wwn ) {
+	static char wwn_text[ FC_NAME_STRLEN + 1 /* NUL */ ];
+
+	snprintf ( wwn_text, sizeof ( wwn_text ),
+		   "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+		   wwn->bytes[0], wwn->bytes[1], wwn->bytes[2], wwn->bytes[3],
+		   wwn->bytes[4], wwn->bytes[5], wwn->bytes[6], wwn->bytes[7] );
+	return wwn_text;
+}
+
+/**
+ * Parse Fibre Channel WWN
+ *
+ * @v wwn_text		WWN text
+ * @ret wwn		Fibre Channel WWN
+ * @ret rc		Return status code
+ */
+int fc_aton ( const char *wwn_text, struct fc_name *wwn ) {
+	char *ptr = ( ( char * ) wwn_text );
+	unsigned int i = 0;
+
+	while ( 1 ) {
+		wwn->bytes[i++] = strtoul ( ptr, &ptr, 16 );
+		if ( i == sizeof ( wwn->bytes ) )
+			return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
+		if ( *ptr != ':' )
+			return -EINVAL;
+		ptr++;
+	}
+}
+
+/**
+ * Fill Fibre Channel socket address
+ *
+ * @v sa_fc		Fibre Channel socket address to fill in
+ * @v id		Fibre Channel port ID
+ * @ret sa		Socket address
+ */
+struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
+				     struct fc_port_id *id ) {
+	union {
+		struct sockaddr sa;
+		struct sockaddr_fc fc;
+	} *u = container_of ( sa_fc, typeof ( *u ), fc );
+
+	memset ( sa_fc, 0, sizeof ( *sa_fc ) );
+	sa_fc->sfc_family = AF_FC;
+	memcpy ( &sa_fc->sfc_port_id, id, sizeof ( sa_fc->sfc_port_id ) );
+	return &u->sa;
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel link state
+ *
+ ******************************************************************************
+ */
+
+/** Default link status code */
+#define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
+#define EINFO_EUNKNOWN_LINK_STATUS \
+	__einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
+
+/**
+ * Mark Fibre Channel link as up
+ *
+ * @v link		Fibre Channel link state monitor
+ */
+static void fc_link_up ( struct fc_link_state *link ) {
+
+	/* Stop retry timer */
+	stop_timer ( &link->timer );
+
+	/* Record link state */
+	link->rc = 0;
+}
+
+/**
+ * Mark Fibre Channel link as down
+ *
+ * @v link		Fibre Channel link state monitor
+ * @v rc		Link state
+ */
+static void fc_link_err ( struct fc_link_state *link, int rc ) {
+
+	/* Record link state */
+	if ( rc == 0 )
+		rc = -EUNKNOWN_LINK_STATUS;
+	link->rc = rc;
+
+	/* Schedule another link examination */
+	start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
+}
+
+/**
+ * Examine Fibre Channel link state
+ *
+ * @v link		Fibre Channel link state monitor
+ */
+static void fc_link_examine ( struct fc_link_state *link ) {
+
+	link->examine ( link );
+}
+
+/**
+ * Handle Fibre Channel link retry timer expiry
+ */
+static void fc_link_expired ( struct retry_timer *timer, int over __unused ) {
+	struct fc_link_state *link =
+		container_of ( timer, struct fc_link_state, timer );
+
+	/* Schedule another link examination */
+	start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
+
+	/* Examine link */
+	fc_link_examine ( link );
+}
+
+/**
+ * Initialise Fibre Channel link state monitor
+ *
+ * @v link		Fibre Channel link state monitor
+ * @v examine		Examine link state method
+ * @v refcnt		Reference counter
+ */
+static void fc_link_init ( struct fc_link_state *link,
+			   void ( * examine ) ( struct fc_link_state *link ),
+			   struct refcnt *refcnt ) {
+
+	link->rc = -EUNKNOWN_LINK_STATUS;
+	timer_init ( &link->timer, fc_link_expired, refcnt );
+	link->examine = examine;
+}
+
+/**
+ * Start monitoring Fibre Channel link state
+ *
+ * @v link		Fibre Channel link state monitor
+ */
+static void fc_link_start ( struct fc_link_state *link ) {
+	start_timer_nodelay ( &link->timer );
+}
+
+/**
+ * Stop monitoring Fibre Channel link state
+ *
+ * @v link		Fibre Channel link state monitor
+ */
+static void fc_link_stop ( struct fc_link_state *link ) {
+	stop_timer ( &link->timer );
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel exchanges
+ *
+ ******************************************************************************
+ */
+
+/** A Fibre Channel exchange */
+struct fc_exchange {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Fibre Channel port */
+	struct fc_port *port;
+	/** List of active exchanges within this port */
+	struct list_head list;
+
+	/** Peer port ID */
+	struct fc_port_id peer_port_id;
+	/** Data structure type */
+	unsigned int type;
+	/** Flags */
+	unsigned int flags;
+	/** Local exchange ID */
+	uint16_t xchg_id;
+	/** Peer exchange ID */
+	uint16_t peer_xchg_id;
+	/** Active sequence ID */
+	uint8_t seq_id;
+	/** Active sequence count */
+	uint16_t seq_cnt;
+
+	/** Timeout timer */
+	struct retry_timer timer;
+
+	/** Upper-layer protocol interface */
+	struct interface ulp;
+};
+
+/** Fibre Channel exchange flags */
+enum fc_exchange_flags {
+	/** We are the exchange originator */
+	FC_XCHG_ORIGINATOR = 0x0001,
+	/** We have the sequence initiative */
+	FC_XCHG_SEQ_INITIATIVE = 0x0002,
+	/** This is the first sequence of the exchange */
+	FC_XCHG_SEQ_FIRST = 0x0004,
+};
+
+/** Fibre Channel timeout */
+#define FC_TIMEOUT ( 1 * TICKS_PER_SEC )
+
+/**
+ * Create local Fibre Channel exchange identifier
+ *
+ * @ret xchg_id		Local exchange ID
+ */
+static unsigned int fc_new_xchg_id ( void ) {
+	static uint16_t next_id = 0x0000;
+
+	/* We must avoid using FC_RX_ID_UNKNOWN (0xffff) */
+	next_id += 2;
+	return next_id;
+}
+
+/**
+ * Create local Fibre Channel sequence identifier
+ *
+ * @ret seq_id		Local sequence identifier
+ */
+static unsigned int fc_new_seq_id ( void ) {
+	static uint8_t seq_id = 0x00;
+
+	return (++seq_id);
+}
+
+/**
+ * Free Fibre Channel exchange
+ *
+ * @v refcnt		Reference count
+ */
+static void fc_xchg_free ( struct refcnt *refcnt ) {
+	struct fc_exchange *xchg =
+		container_of ( refcnt, struct fc_exchange, refcnt );
+
+	assert ( ! timer_running ( &xchg->timer ) );
+	assert ( list_empty ( &xchg->list ) );
+
+	fc_port_put ( xchg->port );
+	free ( xchg );
+}
+
+/**
+ * Close Fibre Channel exchange
+ *
+ * @v xchg		Fibre Channel exchange
+ * @v rc		Reason for close
+ */
+static void fc_xchg_close ( struct fc_exchange *xchg, int rc ) {
+	struct fc_port *port = xchg->port;
+
+	if ( rc != 0 ) {
+		DBGC2 ( port, "FCXCHG %s/%04x closed: %s\n",
+			port->name, xchg->xchg_id, strerror ( rc ) );
+	}
+
+	/* Stop timer */
+	stop_timer ( &xchg->timer );
+
+	/* If list still holds a reference, remove from list of open
+	 * exchanges and drop list's reference.
+	 */
+	if ( ! list_empty ( &xchg->list ) ) {
+		list_del ( &xchg->list );
+		INIT_LIST_HEAD ( &xchg->list );
+		ref_put ( &xchg->refcnt );
+	}
+
+	/* Shutdown interfaces */
+	intf_shutdown ( &xchg->ulp, rc );
+}
+
+/**
+ * Handle exchange timeout
+ *
+ * @v timer		Timeout timer
+ * @v over		Failure indicator
+ */
+static void fc_xchg_expired ( struct retry_timer *timer, int over __unused ) {
+	struct fc_exchange *xchg =
+		container_of ( timer, struct fc_exchange, timer );
+	struct fc_port *port = xchg->port;
+
+	DBGC ( port, "FCXCHG %s/%04x timed out\n", port->name, xchg->xchg_id );
+
+	/* Terminate the exchange */
+	fc_xchg_close ( xchg, -ETIMEDOUT );
+}
+
+/**
+ * Check Fibre Channel exchange window
+ *
+ * @v xchg		Fibre Channel exchange
+ * @ret len		Length opf window
+ */
+static size_t fc_xchg_window ( struct fc_exchange *xchg __unused ) {
+
+	/* We don't currently store the path MTU */
+	return FC_LOGIN_DEFAULT_MTU;
+}
+
+/**
+ * Allocate Fibre Channel I/O buffer
+ *
+ * @v xchg		Fibre Channel exchange
+ * @v len		Payload length
+ * @ret iobuf		I/O buffer, or NULL
+ */
+static struct io_buffer * fc_xchg_alloc_iob ( struct fc_exchange *xchg,
+					      size_t len ) {
+	struct fc_port *port = xchg->port;
+	struct io_buffer *iobuf;
+
+	iobuf = xfer_alloc_iob ( &port->transport,
+				 ( sizeof ( struct fc_frame_header ) + len ) );
+	if ( iobuf ) {
+		iob_reserve ( iobuf, sizeof ( struct fc_frame_header ) );
+	}
+	return iobuf;
+}
+
+/**
+ * Transmit data as part of a Fibre Channel exchange
+ *
+ * @v xchg		Fibre Channel exchange
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
+			struct xfer_metadata *meta ) {
+	struct fc_port *port = xchg->port;
+	struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
+	struct fc_frame_header *fchdr;
+	unsigned int r_ctl;
+	unsigned int f_ctl_es;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) ) {
+		DBGC ( port, "FCXCHG %s/%04x cannot transmit while not "
+		       "holding sequence initiative\n",
+		       port->name, xchg->xchg_id );
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* Calculate routing control */
+	switch ( xchg->type ) {
+	case FC_TYPE_ELS:
+		r_ctl = FC_R_CTL_ELS;
+		if ( meta->flags & XFER_FL_RESPONSE ) {
+			r_ctl |= FC_R_CTL_SOL_CTRL;
+		} else {
+			r_ctl |= FC_R_CTL_UNSOL_CTRL;
+		}
+		break;
+	case FC_TYPE_CT:
+		r_ctl = FC_R_CTL_DATA;
+		if ( meta->flags & XFER_FL_RESPONSE ) {
+			r_ctl |= FC_R_CTL_SOL_CTRL;
+		} else {
+			r_ctl |= FC_R_CTL_UNSOL_CTRL;
+		}
+		break;
+	default:
+		r_ctl = FC_R_CTL_DATA;
+		switch ( meta->flags &
+			 ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
+		case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ):
+			r_ctl |= FC_R_CTL_CMD_STAT;
+			break;
+		case ( XFER_FL_CMD_STAT ):
+			r_ctl |= FC_R_CTL_UNSOL_CMD;
+			break;
+		case ( XFER_FL_RESPONSE ):
+			r_ctl |= FC_R_CTL_SOL_DATA;
+			break;
+		default:
+			r_ctl |= FC_R_CTL_UNSOL_DATA;
+			break;
+		}
+		break;
+	}
+
+	/* Calculate exchange and sequence control */
+	f_ctl_es = 0;
+	if ( ! ( xchg->flags & FC_XCHG_ORIGINATOR ) )
+		f_ctl_es |= FC_F_CTL_ES_RESPONDER;
+	if ( xchg->flags & FC_XCHG_SEQ_FIRST )
+		f_ctl_es |= FC_F_CTL_ES_FIRST;
+	if ( meta->flags & XFER_FL_OUT )
+		f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_LAST );
+	if ( meta->flags & XFER_FL_OVER )
+		f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_TRANSFER );
+
+	/* Create frame header */
+	fchdr = iob_push ( iobuf, sizeof ( *fchdr ) );
+	memset ( fchdr, 0, sizeof ( *fchdr ) );
+	fchdr->r_ctl = r_ctl;
+	memcpy ( &fchdr->d_id,
+		 ( dest ? &dest->sfc_port_id : &xchg->peer_port_id ),
+		 sizeof ( fchdr->d_id ) );
+	memcpy ( &fchdr->s_id, &port->port_id, sizeof ( fchdr->s_id ) );
+	fchdr->type = xchg->type;
+	fchdr->f_ctl_es = f_ctl_es;
+	fchdr->seq_id = xchg->seq_id;
+	fchdr->seq_cnt = htons ( xchg->seq_cnt++ );
+	fchdr->ox_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
+			       xchg->xchg_id : xchg->peer_xchg_id );
+	fchdr->rx_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
+			       xchg->peer_xchg_id : xchg->xchg_id );
+	if ( meta->flags & XFER_FL_ABS_OFFSET ) {
+		fchdr->f_ctl_misc |= FC_F_CTL_MISC_REL_OFF;
+		fchdr->parameter = htonl ( meta->offset );
+	}
+
+	/* Relinquish sequence initiative if applicable */
+	if ( meta->flags & XFER_FL_OVER ) {
+		xchg->flags &= ~( FC_XCHG_SEQ_INITIATIVE | FC_XCHG_SEQ_FIRST );
+		xchg->seq_cnt = 0;
+	}
+
+	/* Reset timeout */
+	start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
+
+	/* Deliver frame */
+	if ( ( rc = xfer_deliver_iob ( &port->transport,
+				       iob_disown ( iobuf ) ) ) != 0 ) {
+		DBGC ( port, "FCXCHG %s/%04x cannot transmit: %s\n",
+		       port->name, xchg->xchg_id, strerror ( rc ) );
+		goto done;
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** Mapping from Fibre Channel routing control information to xfer metadata */
+static const uint8_t fc_r_ctl_info_meta_flags[ FC_R_CTL_INFO_MASK + 1 ] = {
+	[FC_R_CTL_UNCAT]	= ( 0 ),
+	[FC_R_CTL_SOL_DATA]	= ( XFER_FL_RESPONSE ),
+	[FC_R_CTL_UNSOL_CTRL]	= ( XFER_FL_CMD_STAT ),
+	[FC_R_CTL_SOL_CTRL]	= ( XFER_FL_CMD_STAT ),
+	[FC_R_CTL_UNSOL_DATA]	= ( 0 ),
+	[FC_R_CTL_DATA_DESC]	= ( XFER_FL_CMD_STAT ),
+	[FC_R_CTL_UNSOL_CMD]	= ( XFER_FL_CMD_STAT ),
+	[FC_R_CTL_CMD_STAT]	= ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ),
+};
+
+/**
+ * Receive data as part of a Fibre Channel exchange
+ *
+ * @v xchg		Fibre Channel exchange
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fc_xchg_rx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
+			struct xfer_metadata *meta __unused ) {
+	struct fc_port *port = xchg->port;
+	struct fc_frame_header *fchdr = iobuf->data;
+	struct xfer_metadata fc_meta;
+	struct sockaddr_fc src;
+	struct sockaddr_fc dest;
+	int rc;
+
+	/* Record peer exchange ID */
+	xchg->peer_xchg_id =
+		ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
+			fchdr->rx_id : fchdr->ox_id );
+
+	/* Sequence checks */
+	if ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) {
+		DBGC ( port, "FCXCHG %s/%04x received frame while holding "
+		       "sequence initiative\n", port->name, xchg->xchg_id );
+		rc = -EBUSY;
+		goto done;
+	}
+	if ( ntohs ( fchdr->seq_cnt ) != xchg->seq_cnt ) {
+		DBGC ( port, "FCXCHG %s/%04x received out-of-order frame %d "
+		       "(expected %d)\n", port->name, xchg->xchg_id,
+		       ntohs ( fchdr->seq_cnt ), xchg->seq_cnt );
+		rc = -EPIPE;
+		goto done;
+	}
+	if ( xchg->seq_cnt == 0 )
+		xchg->seq_id = fchdr->seq_id;
+	xchg->seq_cnt++;
+	if ( fchdr->seq_id != xchg->seq_id ) {
+		DBGC ( port, "FCXCHG %s/%04x received frame for incorrect "
+		       "sequence %02x (expected %02x)\n", port->name,
+		       xchg->xchg_id, fchdr->seq_id, xchg->seq_id );
+		rc = -EPIPE;
+		goto done;
+	}
+
+	/* Check for end of sequence and transfer of sequence initiative */
+	if ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) {
+		xchg->seq_cnt = 0;
+		if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
+			xchg->flags |= FC_XCHG_SEQ_INITIATIVE;
+			xchg->seq_id = fc_new_seq_id();
+		}
+	}
+
+	/* Construct metadata */
+	memset ( &fc_meta, 0, sizeof ( fc_meta ) );
+	fc_meta.flags =
+		fc_r_ctl_info_meta_flags[ fchdr->r_ctl & FC_R_CTL_INFO_MASK ];
+	if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
+		fc_meta.flags |= XFER_FL_OVER;
+	}
+	if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
+	     ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
+		fc_meta.flags |= XFER_FL_OUT;
+	}
+	if ( fchdr->f_ctl_misc & FC_F_CTL_MISC_REL_OFF ) {
+		fc_meta.flags |= XFER_FL_ABS_OFFSET;
+		fc_meta.offset = ntohl ( fchdr->parameter );
+	}
+	fc_meta.src = fc_fill_sockaddr ( &src, &fchdr->s_id );
+	fc_meta.dest = fc_fill_sockaddr ( &dest, &fchdr->d_id );
+
+	/* Reset timeout */
+	start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
+
+	/* Deliver via exchange's ULP interface */
+	iob_pull ( iobuf, sizeof ( *fchdr ) );
+	if ( ( rc = xfer_deliver ( &xchg->ulp, iob_disown ( iobuf ),
+				   &fc_meta ) ) != 0 ) {
+		DBGC ( port, "FCXCHG %s/%04x cannot deliver frame: %s\n",
+		       port->name, xchg->xchg_id, strerror ( rc ) );
+		goto done;
+	}
+
+	/* Close exchange if applicable */
+	if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
+	     ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
+		fc_xchg_close ( xchg, 0 );
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** Fibre Channel exchange ULP interface operations */
+static struct interface_operation fc_xchg_ulp_op[] = {
+	INTF_OP ( xfer_deliver, struct fc_exchange *, fc_xchg_tx ),
+	INTF_OP ( xfer_alloc_iob, struct fc_exchange *, fc_xchg_alloc_iob ),
+	INTF_OP ( xfer_window, struct fc_exchange *, fc_xchg_window ),
+	INTF_OP ( intf_close, struct fc_exchange *, fc_xchg_close ),
+};
+
+/** Fibre Channel exchange ULP interface descriptor */
+static struct interface_descriptor fc_xchg_ulp_desc =
+	INTF_DESC ( struct fc_exchange, ulp, fc_xchg_ulp_op );
+
+/**
+ * Create new Fibre Channel exchange
+ *
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret xchg		Exchange, or NULL
+ */
+static struct fc_exchange * fc_xchg_create ( struct fc_port *port,
+					     struct fc_port_id *peer_port_id,
+					     unsigned int type ) {
+	struct fc_exchange *xchg;
+
+	/* Allocate and initialise structure */
+	xchg = zalloc ( sizeof ( *xchg ) );
+	if ( ! xchg )
+		return NULL;
+	ref_init ( &xchg->refcnt, fc_xchg_free );
+	intf_init ( &xchg->ulp, &fc_xchg_ulp_desc, &xchg->refcnt );
+	timer_init ( &xchg->timer, fc_xchg_expired, &xchg->refcnt );
+	xchg->port = fc_port_get ( port );
+	memcpy ( &xchg->peer_port_id, peer_port_id,
+		 sizeof ( xchg->peer_port_id ) );
+	xchg->type = type;
+	xchg->xchg_id = fc_new_xchg_id();
+	xchg->peer_xchg_id = FC_RX_ID_UNKNOWN;
+	xchg->seq_id = fc_new_seq_id();
+
+	/* Transfer reference to list of exchanges and return */
+	list_add ( &xchg->list, &port->xchgs );
+	return xchg;
+}
+
+/**
+ * Originate a new Fibre Channel exchange
+ *
+ * @v parent		Interface to which to attach
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret xchg_id		Exchange ID, or negative error
+ */
+int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
+			struct fc_port_id *peer_port_id, unsigned int type ) {
+	struct fc_exchange *xchg;
+
+	/* Allocate and initialise structure */
+	xchg = fc_xchg_create ( port, peer_port_id, type );
+	if ( ! xchg )
+		return -ENOMEM;
+	xchg->flags = ( FC_XCHG_ORIGINATOR | FC_XCHG_SEQ_INITIATIVE |
+			FC_XCHG_SEQ_FIRST );
+
+	DBGC2 ( port, "FCXCHG %s/%04x originating to %s (type %02x)\n",
+		port->name, xchg->xchg_id, fc_id_ntoa ( &xchg->peer_port_id ),
+		xchg->type );
+
+	/* Attach to parent interface and return */
+	intf_plug_plug ( &xchg->ulp, parent );
+	return xchg->xchg_id;
+}
+
+/**
+ * Open a new responder Fibre Channel exchange
+ *
+ * @v port		Fibre Channel port
+ * @v fchdr		Fibre Channel frame header
+ * @ret xchg		Fibre Channel exchange, or NULL
+ */
+static struct fc_exchange * fc_xchg_respond ( struct fc_port *port,
+					      struct fc_frame_header *fchdr ) {
+	struct fc_exchange *xchg;
+	struct fc_responder *responder;
+	unsigned int type = fchdr->type;
+	int rc;
+
+	/* Allocate and initialise structure */
+	xchg = fc_xchg_create ( port, &fchdr->s_id, type );
+	if ( ! xchg )
+		return NULL;
+	xchg->seq_id = fchdr->seq_id;
+
+	DBGC2 ( port, "FCXCHG %s/%04x responding to %s xchg %04x (type "
+		"%02x)\n", port->name, xchg->xchg_id,
+		fc_id_ntoa ( &xchg->peer_port_id ),
+		ntohs ( fchdr->ox_id ), xchg->type );
+
+	/* Find a responder, if any */
+	for_each_table_entry ( responder, FC_RESPONDERS ) {
+		if ( responder->type == type ) {
+			if ( ( rc = responder->respond ( &xchg->ulp, port,
+							 &fchdr->d_id,
+							 &fchdr->s_id ) ) !=0 ){
+				DBGC ( port, "FCXCHG %s/%04x could not "
+				       "respond: %s\n", port->name,
+				       xchg->xchg_id, strerror ( rc ) );
+			}
+		}
+		break;
+	}
+
+	/* We may or may not have a ULP attached at this point, but
+	 * the exchange does exist.
+	 */
+	return xchg;
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel ports
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Close Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ * @v rc		Reason for close
+ */
+static void fc_port_close ( struct fc_port *port, int rc ) {
+	struct fc_exchange *xchg;
+	struct fc_exchange *tmp;
+
+	DBGC ( port, "FCPORT %s closed\n", port->name );
+
+	/* Log out port, if necessary */
+	if ( fc_link_ok ( &port->link ) )
+		fc_port_logout ( port, rc );
+
+	/* Stop link monitor */
+	fc_link_stop ( &port->link );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &port->transport, rc );
+	intf_shutdown ( &port->flogi, rc );
+	intf_shutdown ( &port->ns_plogi, rc );
+
+	/* Shut down any remaining exchanges */
+	list_for_each_entry_safe ( xchg, tmp, &port->xchgs, list )
+		fc_xchg_close ( xchg, rc );
+
+	/* Remove from list of ports */
+	list_del ( &port->list );
+	INIT_LIST_HEAD ( &port->list );
+}
+
+/**
+ * Identify Fibre Channel exchange by local exchange ID
+ *
+ * @v port		Fibre Channel port
+ * @v xchg_id		Local exchange ID
+ * @ret xchg		Fibre Channel exchange, or NULL
+ */
+static struct fc_exchange * fc_port_demux ( struct fc_port *port,
+					    unsigned int xchg_id ) {
+	struct fc_exchange *xchg;
+
+	list_for_each_entry ( xchg, &port->xchgs, list ) {
+		if ( xchg->xchg_id == xchg_id )
+			return xchg;
+	}
+	return NULL;
+}
+
+/**
+ * Handle received frame from Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
+			     struct xfer_metadata *meta ) {
+	struct fc_frame_header *fchdr = iobuf->data;
+	unsigned int xchg_id;
+	struct fc_exchange *xchg;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *fchdr ) ) {
+		DBGC ( port, "FCPORT %s received underlength frame (%zd "
+		       "bytes)\n", port->name, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	/* Verify local port ID */
+	if ( ( memcmp ( &fchdr->d_id, &port->port_id,
+			sizeof ( fchdr->d_id ) ) != 0 ) &&
+	     ( memcmp ( &fchdr->d_id, &fc_f_port_id,
+			sizeof ( fchdr->d_id ) ) != 0 ) &&
+	     ( memcmp ( &port->port_id, &fc_empty_port_id,
+			sizeof ( port->port_id ) ) != 0 ) ) {
+		DBGC ( port, "FCPORT %s received frame for incorrect port ID "
+		       "%s\n", port->name, fc_id_ntoa ( &fchdr->d_id ) );
+		rc = -ENOTCONN;
+		goto err_port_id;
+	}
+
+	/* Demultiplex amongst active exchanges */
+	xchg_id = ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
+			  fchdr->ox_id : fchdr->rx_id );
+	xchg = fc_port_demux ( port, xchg_id );
+
+	/* If we have no active exchange and this frame starts a new
+	 * exchange, try to create a new responder exchange
+	 */
+	if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_FIRST ) &&
+	     ( fchdr->seq_cnt == 0 ) ) {
+
+		/* Create new exchange */
+		xchg = fc_xchg_respond ( port, fchdr );
+		if ( ! xchg ) {
+			DBGC ( port, "FCPORT %s cannot create new exchange\n",
+			       port->name );
+			rc = -ENOMEM;
+			goto err_respond;
+		}
+	}
+
+	/* Fail if no exchange exists */
+	if ( ! xchg ) {
+		DBGC ( port, "FCPORT %s xchg %04x unknown\n",
+		       port->name, xchg_id );
+		rc = -ENOTCONN;
+		goto err_no_xchg;
+	}
+
+	/* Pass received frame to exchange */
+	ref_get ( &xchg->refcnt );
+	if ( ( rc = fc_xchg_rx ( xchg, iob_disown ( iobuf ), meta ) ) != 0 )
+		goto err_xchg_rx;
+
+ err_xchg_rx:
+	ref_put ( &xchg->refcnt );
+ err_no_xchg:
+ err_respond:
+ err_port_id:
+ err_sanity:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Log in Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ * @v port_id		Local port ID
+ * @v link_node_wwn	Link node name
+ * @v link_port_wwn	Link port name
+ * @v has_fabric	Link is to a fabric
+ * @ret rc		Return status code
+ */
+int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
+		    const struct fc_name *link_node_wwn,
+		    const struct fc_name *link_port_wwn, int has_fabric ) {
+	struct fc_peer *peer;
+	struct fc_peer *tmp;
+	int rc;
+
+	/* Perform implicit logout if logged in and details differ */
+	if ( fc_link_ok ( &port->link ) &&
+	     ( ( ( !! ( port->flags & FC_PORT_HAS_FABRIC ) ) !=
+		 ( !! has_fabric ) ) ||
+	       ( memcmp ( &port->link_node_wwn, link_node_wwn,
+			  sizeof ( port->link_node_wwn ) ) != 0 ) ||
+	       ( memcmp ( &port->link_port_wwn, link_port_wwn,
+			  sizeof ( port->link_port_wwn ) ) != 0 ) ||
+	       ( has_fabric &&
+		 ( memcmp ( &port->port_id, port_id,
+			    sizeof ( port->port_id ) ) != 0 ) ) ) ) {
+		fc_port_logout ( port, 0 );
+	}
+
+	/* Log in, if applicable */
+	if ( ! fc_link_ok ( &port->link ) ) {
+
+		/* Record link port name */
+		memcpy ( &port->link_node_wwn, link_node_wwn,
+			 sizeof ( port->link_node_wwn ) );
+		memcpy ( &port->link_port_wwn, link_port_wwn,
+			 sizeof ( port->link_port_wwn ) );
+		DBGC ( port, "FCPORT %s logged in to %s",
+		       port->name, fc_ntoa ( &port->link_node_wwn ) );
+		DBGC ( port, " port %s\n", fc_ntoa ( &port->link_port_wwn ) );
+
+		/* Calculate local (and possibly remote) port IDs */
+		if ( has_fabric ) {
+			port->flags |= FC_PORT_HAS_FABRIC;
+			memcpy ( &port->port_id, port_id,
+				 sizeof ( port->port_id ) );
+		} else {
+			port->flags &= ~FC_PORT_HAS_FABRIC;
+			if ( memcmp ( &port->port_wwn, link_port_wwn,
+				      sizeof ( port->port_wwn ) ) > 0 ) {
+				memcpy ( &port->port_id, &fc_ptp_high_port_id,
+					 sizeof ( port->port_id ) );
+				memcpy ( &port->ptp_link_port_id,
+					 &fc_ptp_low_port_id,
+					 sizeof ( port->ptp_link_port_id ) );
+			} else {
+				memcpy ( &port->port_id, &fc_ptp_low_port_id,
+					 sizeof ( port->port_id ) );
+				memcpy ( &port->ptp_link_port_id,
+					 &fc_ptp_high_port_id,
+					 sizeof ( port->ptp_link_port_id ) );
+			}
+		}
+		DBGC ( port, "FCPORT %s logged in via a %s, with local ID "
+		       "%s\n", port->name,
+		       ( ( port->flags & FC_PORT_HAS_FABRIC ) ?
+			 "fabric" : "point-to-point link" ),
+		       fc_id_ntoa ( &port->port_id ) );
+	}
+
+	/* Log in to name server, if attached to a fabric */
+	if ( has_fabric && ! ( port->flags & FC_PORT_HAS_NS ) ) {
+
+		DBGC ( port, "FCPORT %s attempting login to name server\n",
+		       port->name );
+
+		intf_restart ( &port->ns_plogi, -ECANCELED );
+		if ( ( rc = fc_els_plogi ( &port->ns_plogi, port,
+					   &fc_gs_port_id ) ) != 0 ) {
+			DBGC ( port, "FCPORT %s could not initiate name "
+			       "server PLOGI: %s\n",
+			       port->name, strerror ( rc ) );
+			fc_port_logout ( port, rc );
+			return rc;
+		}
+	}
+
+	/* Record login */
+	fc_link_up ( &port->link );
+
+	/* Notify peers of link state change */
+	list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
+		fc_peer_get ( peer );
+		fc_link_examine ( &peer->link );
+		fc_peer_put ( peer );
+	}
+
+	return 0;
+}
+
+/**
+ * Log out Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ * @v rc		Reason for logout
+ */
+void fc_port_logout ( struct fc_port *port, int rc ) {
+	struct fc_peer *peer;
+	struct fc_peer *tmp;
+
+	DBGC ( port, "FCPORT %s logged out: %s\n",
+	       port->name, strerror ( rc ) );
+
+	/* Erase port details */
+	memset ( &port->port_id, 0, sizeof ( port->port_id ) );
+	port->flags = 0;
+
+	/* Record logout */
+	fc_link_err ( &port->link, rc );
+
+	/* Notify peers of link state change */
+	list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
+		fc_peer_get ( peer );
+		fc_link_examine ( &peer->link );
+		fc_peer_put ( peer );
+	}
+}
+
+/**
+ * Handle FLOGI completion
+ *
+ * @v port		Fibre Channel port
+ * @v rc		Reason for completion
+ */
+static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
+
+	intf_restart ( &port->flogi, rc );
+
+	if ( rc != 0 )
+		fc_port_logout ( port, rc );
+}
+
+/**
+ * Handle name server PLOGI completion
+ *
+ * @v port		Fibre Channel port
+ * @v rc		Reason for completion
+ */
+static void fc_port_ns_plogi_done ( struct fc_port *port, int rc ) {
+
+	intf_restart ( &port->ns_plogi, rc );
+
+	if ( rc == 0 ) {
+		port->flags |= FC_PORT_HAS_NS;
+		DBGC ( port, "FCPORT %s logged in to name server\n",
+		       port->name );
+	} else {
+		DBGC ( port, "FCPORT %s could not log in to name server: %s\n",
+		       port->name, strerror ( rc ) );
+		/* Absence of a name server is not a fatal error */
+	}
+}
+
+/**
+ * Examine Fibre Channel port link state
+ *
+ * @ link		Fibre Channel link state monitor
+ */
+static void fc_port_examine ( struct fc_link_state *link ) {
+	struct fc_port *port = container_of ( link, struct fc_port, link );
+	int rc;
+
+	/* Do nothing if already logged in */
+	if ( fc_link_ok ( &port->link ) )
+		return;
+
+	DBGC ( port, "FCPORT %s attempting login\n", port->name );
+
+	/* Try to create FLOGI ELS */
+	intf_restart ( &port->flogi, -ECANCELED );
+	if ( ( rc = fc_els_flogi ( &port->flogi, port ) ) != 0 ) {
+		DBGC ( port, "FCPORT %s could not initiate FLOGI: %s\n",
+		       port->name, strerror ( rc ) );
+		fc_port_logout ( port, rc );
+		return;
+	}
+}
+
+/**
+ * Handle change of flow control window
+ *
+ * @v port		Fibre Channel port
+ */
+static void fc_port_window_changed ( struct fc_port *port ) {
+	size_t window;
+
+	/* Check if transport layer is ready */
+	window = xfer_window ( &port->transport );
+	if ( window > 0 ) {
+
+		/* Transport layer is ready.  Start login if the link
+		 * is not already up.
+		 */
+		if ( ! fc_link_ok ( &port->link ) )
+			fc_link_start ( &port->link );
+
+	} else {
+
+		/* Transport layer is not ready.  Log out port and
+		 * wait for transport layer before attempting log in
+		 * again.
+		 */
+		fc_port_logout ( port, -ENOTCONN );
+		fc_link_stop ( &port->link );
+	}
+}
+
+/** Fibre Channel port transport interface operations */
+static struct interface_operation fc_port_transport_op[] = {
+	INTF_OP ( xfer_deliver, struct fc_port *, fc_port_deliver ),
+	INTF_OP ( xfer_window_changed, struct fc_port *,
+		  fc_port_window_changed ),
+	INTF_OP ( intf_close, struct fc_port *, fc_port_close ),
+};
+
+/** Fibre Channel port transport interface descriptor */
+static struct interface_descriptor fc_port_transport_desc =
+	INTF_DESC ( struct fc_port, transport, fc_port_transport_op );
+
+/** Fibre Channel port FLOGI interface operations */
+static struct interface_operation fc_port_flogi_op[] = {
+	INTF_OP ( intf_close, struct fc_port *, fc_port_flogi_done ),
+};
+
+/** Fibre Channel port FLOGI interface descriptor */
+static struct interface_descriptor fc_port_flogi_desc =
+	INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
+
+/** Fibre Channel port name server PLOGI interface operations */
+static struct interface_operation fc_port_ns_plogi_op[] = {
+	INTF_OP ( intf_close, struct fc_port *, fc_port_ns_plogi_done ),
+};
+
+/** Fibre Channel port name server PLOGI interface descriptor */
+static struct interface_descriptor fc_port_ns_plogi_desc =
+	INTF_DESC ( struct fc_port, ns_plogi, fc_port_ns_plogi_op );
+
+/**
+ * Create Fibre Channel port
+ *
+ * @v transport		Transport interface
+ * @v node		Fibre Channel node name
+ * @v port		Fibre Channel port name
+ * @v name		Symbolic port name
+ * @ret rc		Return status code
+ */
+int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
+		   const struct fc_name *port_wwn, const char *name ) {
+	struct fc_port *port;
+
+	/* Allocate and initialise structure */
+	port = zalloc ( sizeof ( *port ) );
+	if ( ! port )
+		return -ENOMEM;
+	ref_init ( &port->refcnt, NULL );
+	intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
+	fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
+	intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
+	intf_init ( &port->ns_plogi, &fc_port_ns_plogi_desc, &port->refcnt );
+	list_add_tail ( &port->list, &fc_ports );
+	INIT_LIST_HEAD ( &port->xchgs );
+	memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
+	memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
+	snprintf ( port->name, sizeof ( port->name ), "%s", name );
+
+	DBGC ( port, "FCPORT %s opened as %s",
+	       port->name, fc_ntoa ( &port->node_wwn ) );
+	DBGC ( port, " port %s\n", fc_ntoa ( &port->port_wwn ) );
+
+	/* Attach to transport layer, mortalise self, and return */
+	intf_plug_plug ( &port->transport, transport );
+	ref_put ( &port->refcnt );
+	return 0;
+}
+
+/**
+ * Find Fibre Channel port by name
+ *
+ * @v name		Fibre Channel port name
+ * @ret port		Fibre Channel port, or NULL
+ */
+struct fc_port * fc_port_find ( const char *name ) {
+	struct fc_port *port;
+
+	list_for_each_entry ( port, &fc_ports, list ) {
+		if ( strcmp ( name, port->name ) == 0 )
+			return port;
+	}
+	return NULL;
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel peers
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Close Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ * @v rc		Reason for close
+ */
+static void fc_peer_close ( struct fc_peer *peer, int rc ) {
+
+	DBGC ( peer, "FCPEER %s closed: %s\n",
+	       fc_ntoa ( &peer->port_wwn ) , strerror ( rc ) );
+
+	/* Sanity check */
+	assert ( list_empty ( &peer->ulps ) );
+
+	/* Stop link timer */
+	fc_link_stop ( &peer->link );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &peer->plogi, rc );
+
+	/* Remove from list of peers */
+	list_del ( &peer->list );
+	INIT_LIST_HEAD ( &peer->list );
+}
+
+/**
+ * Increment Fibre Channel peer active usage count
+ *
+ * @v peer		Fibre Channel peer
+ */
+static void fc_peer_increment ( struct fc_peer *peer ) {
+
+	/* Increment our usage count */
+	peer->usage++;
+}
+
+/**
+ * Decrement Fibre Channel peer active usage count
+ *
+ * @v peer		Fibre Channel peer
+ */
+static void fc_peer_decrement ( struct fc_peer *peer ) {
+
+	/* Sanity check */
+	assert ( peer->usage > 0 );
+
+	/* Decrement our usage count and log out if we reach zero */
+	if ( --(peer->usage) == 0 )
+		fc_peer_logout ( peer, 0 );
+}
+
+/**
+ * Log in Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ * @v port		Fibre Channel port
+ * @v port_id		Port ID
+ * @ret rc		Return status code
+ */
+int fc_peer_login ( struct fc_peer *peer, struct fc_port *port,
+		    struct fc_port_id *port_id ) {
+	struct fc_ulp *ulp;
+	struct fc_ulp *tmp;
+
+	/* Perform implicit logout if logged in and details differ */
+	if ( fc_link_ok ( &peer->link ) &&
+	     ( ( peer->port != port ) ||
+	       ( memcmp ( &peer->port_id, port_id,
+			  sizeof ( peer->port_id ) ) !=0 ) ) ) {
+		fc_peer_logout ( peer, 0 );
+	}
+
+	/* Log in, if applicable */
+	if ( ! fc_link_ok ( &peer->link ) ) {
+
+		/* Record peer details */
+		assert ( peer->port == NULL );
+		peer->port = fc_port_get ( port );
+		memcpy ( &peer->port_id, port_id, sizeof ( peer->port_id ) );
+		DBGC ( peer, "FCPEER %s logged in via %s as %s\n",
+		       fc_ntoa ( &peer->port_wwn ), peer->port->name,
+		       fc_id_ntoa ( &peer->port_id ) );
+
+		/* Add login reference */
+		fc_peer_get ( peer );
+	}
+
+	/* Record login */
+	fc_link_up ( &peer->link );
+
+	/* Notify ULPs of link state change */
+	list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
+		fc_ulp_get ( ulp );
+		fc_link_examine ( &ulp->link );
+		fc_ulp_put ( ulp );
+	}
+
+	return 0;
+}
+
+/**
+ * Log out Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ * @v rc		Reason for logout
+ */
+void fc_peer_logout ( struct fc_peer *peer, int rc ) {
+	struct fc_ulp *ulp;
+	struct fc_ulp *tmp;
+
+	DBGC ( peer, "FCPEER %s logged out: %s\n",
+	       fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
+
+	/* Drop login reference, if applicable */
+	if ( fc_link_ok ( &peer->link ) )
+		fc_peer_put ( peer );
+
+	/* Erase peer details */
+	fc_port_put ( peer->port );
+	peer->port = NULL;
+
+	/* Record logout */
+	fc_link_err ( &peer->link, rc );
+
+	/* Notify ULPs of link state change */
+	list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
+		fc_ulp_get ( ulp );
+		fc_link_examine ( &ulp->link );
+		fc_ulp_put ( ulp );
+	}
+
+	/* Close peer if there are no active users */
+	if ( peer->usage == 0 )
+		fc_peer_close ( peer, rc );
+}
+
+/**
+ * Handle PLOGI completion
+ *
+ * @v peer		Fibre Channel peer
+ * @v rc		Reason for completion
+ */
+static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
+
+	intf_restart ( &peer->plogi, rc );
+
+	if ( rc != 0 )
+		fc_peer_logout ( peer, rc );
+}
+
+/**
+ * Initiate PLOGI
+ *
+ * @v peer		Fibre Channel peer
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret rc		Return status code
+ */
+static int fc_peer_plogi ( struct fc_peer *peer, struct fc_port *port,
+			   struct fc_port_id *peer_port_id ) {
+	int rc;
+
+	/* Try to create PLOGI ELS */
+	intf_restart ( &peer->plogi, -ECANCELED );
+	if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
+		DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
+		       fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
+		fc_peer_logout ( peer, rc );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Examine Fibre Channel peer link state
+ *
+ * @ link		Fibre Channel link state monitor
+ */
+static void fc_peer_examine ( struct fc_link_state *link ) {
+	struct fc_peer *peer = container_of ( link, struct fc_peer, link );
+	struct fc_port *port;
+	int rc;
+
+	/* Check to see if underlying port link has gone down */
+	if ( peer->port && ( ! fc_link_ok ( &peer->port->link ) ) ) {
+		fc_peer_logout ( peer, -ENOTCONN );
+		return;
+	}
+
+	/* Do nothing if already logged in */
+	if ( fc_link_ok ( &peer->link ) )
+		return;
+
+	DBGC ( peer, "FCPEER %s attempting login\n",
+	       fc_ntoa ( &peer->port_wwn ) );
+
+	/* Sanity check */
+	assert ( peer->port == NULL );
+
+	/* First, look for a port with the peer attached via a
+	 * point-to-point link.
+	 */
+	list_for_each_entry ( port, &fc_ports, list ) {
+		if ( fc_link_ok ( &port->link ) &&
+		     ( ! ( port->flags & FC_PORT_HAS_FABRIC ) ) &&
+		     ( memcmp ( &peer->port_wwn, &port->link_port_wwn,
+				sizeof ( peer->port_wwn ) ) == 0 ) ) {
+			/* Use this peer port ID, and stop looking */
+			fc_peer_plogi ( peer, port, &port->ptp_link_port_id );
+			return;
+		}
+	}
+
+	/* If the peer is not directly attached, try initiating a name
+	 * server lookup on any suitable ports.
+	 */
+	list_for_each_entry ( port, &fc_ports, list ) {
+		if ( fc_link_ok ( &port->link ) &&
+		     ( port->flags & FC_PORT_HAS_FABRIC ) &&
+		     ( port->flags & FC_PORT_HAS_NS ) ) {
+			if ( ( rc = fc_ns_query ( peer, port,
+						  fc_peer_plogi ) ) != 0 ) {
+				DBGC ( peer, "FCPEER %s could not attempt "
+				       "name server lookup on %s: %s\n",
+				       fc_ntoa ( &peer->port_wwn ), port->name,
+				       strerror ( rc ) );
+				/* Non-fatal */
+			}
+		}
+	}
+}
+
+/** Fibre Channel peer PLOGI interface operations */
+static struct interface_operation fc_peer_plogi_op[] = {
+	INTF_OP ( intf_close, struct fc_peer *, fc_peer_plogi_done ),
+};
+
+/** Fibre Channel peer PLOGI interface descriptor */
+static struct interface_descriptor fc_peer_plogi_desc =
+	INTF_DESC ( struct fc_peer, plogi, fc_peer_plogi_op );
+
+/**
+ * Create Fibre Channel peer
+ *
+ * @v port_wwn		Node name
+ * @ret peer		Fibre Channel peer, or NULL
+ */
+static struct fc_peer * fc_peer_create ( const struct fc_name *port_wwn ) {
+	struct fc_peer *peer;
+
+	/* Allocate and initialise structure */
+	peer = zalloc ( sizeof ( *peer ) );
+	if ( ! peer )
+		return NULL;
+	ref_init ( &peer->refcnt, NULL );
+	fc_link_init ( &peer->link, fc_peer_examine, &peer->refcnt );
+	intf_init ( &peer->plogi, &fc_peer_plogi_desc, &peer->refcnt );
+	list_add_tail ( &peer->list, &fc_peers );
+	memcpy ( &peer->port_wwn, port_wwn, sizeof ( peer->port_wwn ) );
+	INIT_LIST_HEAD ( &peer->ulps );
+
+	/* Start link monitor */
+	fc_link_start ( &peer->link );
+
+	DBGC ( peer, "FCPEER %s created\n", fc_ntoa ( &peer->port_wwn ) );
+	return peer;
+}
+
+/**
+ * Get Fibre Channel peer by node name
+ *
+ * @v port_wwn		Node name
+ * @ret peer		Fibre Channel peer, or NULL
+ */
+struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn ) {
+	struct fc_peer *peer;
+
+	/* Look for an existing peer */
+	list_for_each_entry ( peer, &fc_peers, list ) {
+		if ( memcmp ( &peer->port_wwn, port_wwn,
+			      sizeof ( peer->port_wwn ) ) == 0 )
+			return fc_peer_get ( peer );
+	}
+
+	/* Create a new peer */
+	peer = fc_peer_create ( port_wwn );
+	if ( ! peer )
+		return NULL;
+
+	return peer;
+}
+
+/**
+ * Get Fibre Channel peer by port ID
+ *
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret peer		Fibre Channel peer, or NULL
+ */
+struct fc_peer * fc_peer_get_port_id ( struct fc_port *port,
+				       const struct fc_port_id *peer_port_id ){
+	struct fc_peer *peer;
+
+	/* Look for an existing peer */
+	list_for_each_entry ( peer, &fc_peers, list ) {
+		if ( ( peer->port == port ) &&
+		     ( memcmp ( &peer->port_id, peer_port_id,
+				sizeof ( peer->port_id ) ) == 0 ) )
+			return fc_peer_get ( peer );
+	}
+
+	/* Cannot create a new peer, since we have no port name to use */
+	return NULL;
+}
+
+/******************************************************************************
+ *
+ * Fibre Channel upper-layer protocols
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Free Fibre Channel upper-layer protocol
+ *
+ * @v refcnt		Reference count
+ */
+static void fc_ulp_free ( struct refcnt *refcnt ) {
+	struct fc_ulp *ulp = container_of ( refcnt, struct fc_ulp, refcnt );
+
+	fc_peer_put ( ulp->peer );
+	free ( ulp );
+}
+
+/**
+ * Close Fibre Channel upper-layer protocol
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @v rc		Reason for close
+ */
+static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
+
+	DBGC ( ulp, "FCULP %s/%02x closed: %s\n",
+	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
+
+	/* Sanity check */
+	assert ( ulp->usage == 0 );
+
+	/* Stop link monitor */
+	fc_link_stop ( &ulp->link );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &ulp->prli, rc );
+
+	/* Remove from list of ULPs */
+	list_del ( &ulp->list );
+	INIT_LIST_HEAD ( &ulp->list );
+}
+
+/**
+ * Increment Fibre Channel upper-layer protocol active usage count
+ *
+ * @v ulp		Fibre Channel ulp
+ */
+void fc_ulp_increment ( struct fc_ulp *ulp ) {
+
+	/* Increment peer's usage count */
+	fc_peer_increment ( ulp->peer );
+
+	/* Increment our usage count */
+	ulp->usage++;
+}
+
+/**
+ * Decrement Fibre Channel upper-layer protocol active usage count
+ *
+ * @v ulp		Fibre Channel ulp
+ */
+void fc_ulp_decrement ( struct fc_ulp *ulp ) {
+
+	/* Sanity check */
+	assert ( ulp->usage > 0 );
+
+	/* Decrement our usage count and log out if we reach zero */
+	if ( --(ulp->usage) == 0 )
+		fc_ulp_logout ( ulp, 0 );
+
+	/* Decrement our peer's usage count */
+	fc_peer_decrement ( ulp->peer );
+}
+
+/**
+ * Log in Fibre Channel upper-layer protocol
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @v param		Service parameters
+ * @v param_len		Length of service parameters
+ * @v originated	Login was originated by us
+ * @ret rc		Return status code
+ */
+int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
+		   int originated ) {
+
+	/* Perform implicit logout if logged in and service parameters differ */
+	if ( fc_link_ok ( &ulp->link ) &&
+	     ( ( ulp->param_len != param_len ) ||
+	       ( memcmp ( ulp->param, param, ulp->param_len ) != 0 ) ) ) {
+		fc_ulp_logout ( ulp, 0 );
+	}
+
+	/* Log in, if applicable */
+	if ( ! fc_link_ok ( &ulp->link ) ) {
+
+		/* Record service parameters */
+		assert ( ulp->param == NULL );
+		assert ( ulp->param_len == 0 );
+		ulp->param = malloc ( param_len );
+		if ( ! ulp->param ) {
+			DBGC ( ulp, "FCULP %s/%02x could not record "
+			       "parameters\n",
+			       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+			return -ENOMEM;
+		}
+		memcpy ( ulp->param, param, param_len );
+		ulp->param_len = param_len;
+		DBGC ( ulp, "FCULP %s/%02x logged in with parameters:\n",
+		       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+		DBGC_HDA ( ulp, 0, ulp->param, ulp->param_len );
+
+		/* Add login reference */
+		fc_ulp_get ( ulp );
+	}
+
+	/* Record login */
+	fc_link_up ( &ulp->link );
+
+	/* Work around a bug in some versions of the Linux Fibre
+	 * Channel stack, which fail to fully initialise image pairs
+	 * established via a PRLI originated by the Linux stack
+	 * itself.
+	 */
+	if ( originated )
+		ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
+	if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
+		DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
+		       "Linux bug\n",
+		       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+		fc_link_start ( &ulp->link );
+	}
+
+	return 0;
+}
+
+/**
+ * Log out Fibre Channel upper-layer protocol
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @v rc		Reason for logout
+ */
+void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
+
+	DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
+	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
+
+	/* Drop login reference, if applicable */
+	if ( fc_link_ok ( &ulp->link ) )
+		fc_ulp_put ( ulp );
+
+	/* Discard service parameters */
+	free ( ulp->param );
+	ulp->param = NULL;
+	ulp->param_len = 0;
+	ulp->flags = 0;
+
+	/* Record logout */
+	fc_link_err ( &ulp->link, rc );
+
+	/* Close ULP if there are no clients attached */
+	if ( ulp->usage == 0 )
+		fc_ulp_close ( ulp, rc );
+}
+
+/**
+ * Handle PRLI completion
+ *
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @v rc		Reason for completion
+ */
+static void fc_ulp_prli_done ( struct fc_ulp *ulp, int rc ) {
+
+	intf_restart ( &ulp->prli, rc );
+
+	if ( rc != 0 )
+		fc_ulp_logout ( ulp, rc );
+}
+
+/**
+ * Examine Fibre Channel upper-layer protocol link state
+ *
+ * @ link		Fibre Channel link state monitor
+ */
+static void fc_ulp_examine ( struct fc_link_state *link ) {
+	struct fc_ulp *ulp = container_of ( link, struct fc_ulp, link );
+	int rc;
+
+	/* Check to see if underlying peer link has gone down */
+	if ( ! fc_link_ok ( &ulp->peer->link ) ) {
+		fc_ulp_logout ( ulp, -ENOTCONN );
+		return;
+	}
+
+	/* Do nothing if already logged in */
+	if ( fc_link_ok ( &ulp->link ) &&
+	     ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) )
+		return;
+
+	DBGC ( ulp, "FCULP %s/%02x attempting login\n",
+	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+
+	/* Try to create PRLI ELS */
+	intf_restart ( &ulp->prli, -ECANCELED );
+	if ( ( rc = fc_els_prli ( &ulp->prli, ulp->peer->port,
+				  &ulp->peer->port_id, ulp->type ) ) != 0 ) {
+		DBGC ( ulp, "FCULP %s/%02x could not initiate PRLI: %s\n",
+		       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type,
+		       strerror ( rc ) );
+		fc_ulp_logout ( ulp, rc );
+		return;
+	}
+}
+
+/** Fibre Channel upper-layer protocol PRLI interface operations */
+static struct interface_operation fc_ulp_prli_op[] = {
+	INTF_OP ( intf_close, struct fc_ulp *, fc_ulp_prli_done ),
+};
+
+/** Fibre Channel upper-layer protocol PRLI interface descriptor */
+static struct interface_descriptor fc_ulp_prli_desc =
+	INTF_DESC ( struct fc_ulp, prli, fc_ulp_prli_op );
+
+/**
+ * Create Fibre Channel upper-layer protocl
+ *
+ * @v peer		Fibre Channel peer
+ * @v type		Type
+ * @ret ulp		Fibre Channel upper-layer protocol, or NULL
+ */
+static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
+				       unsigned int type ) {
+	struct fc_ulp *ulp;
+
+	/* Allocate and initialise structure */
+	ulp = zalloc ( sizeof ( *ulp ) );
+	if ( ! ulp )
+		return NULL;
+	ref_init ( &ulp->refcnt, fc_ulp_free );
+	fc_link_init ( &ulp->link, fc_ulp_examine, &ulp->refcnt );
+	intf_init ( &ulp->prli, &fc_ulp_prli_desc, &ulp->refcnt );
+	ulp->peer = fc_peer_get ( peer );
+	list_add_tail ( &ulp->list, &peer->ulps );
+	ulp->type = type;
+
+	/* Start link state monitor */
+	fc_link_start ( &ulp->link );
+
+	DBGC ( ulp, "FCULP %s/%02x created\n",
+	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+	return ulp;
+}
+
+/**
+ * Get Fibre Channel upper-layer protocol by peer and type
+ *
+ * @v peer		Fibre Channel peer
+ * @v type		Type
+ * @ret ulp		Fibre Channel upper-layer protocol, or NULL
+ */
+static struct fc_ulp * fc_ulp_get_type ( struct fc_peer *peer,
+					 unsigned int type ) {
+	struct fc_ulp *ulp;
+
+	/* Look for an existing ULP */
+	list_for_each_entry ( ulp, &peer->ulps, list ) {
+		if ( ulp->type == type )
+			return fc_ulp_get ( ulp );
+	}
+
+	/* Create a new ULP */
+	ulp = fc_ulp_create ( peer, type );
+	if ( ! ulp )
+		return NULL;
+
+	return ulp;
+}
+
+/**
+ * Get Fibre Channel upper-layer protocol by port name and type
+ *
+ * @v port_wwn		Port name
+ * @v type		Type
+ * @ret ulp		Fibre Channel upper-layer protocol, or NULL
+ */
+struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
+				      unsigned int type ) {
+	struct fc_ulp *ulp;
+	struct fc_peer *peer;
+
+	/* Get peer */
+	peer = fc_peer_get_wwn ( port_wwn );
+	if ( ! peer )
+		goto err_peer_get_wwn;
+
+	/* Get ULP */
+	ulp = fc_ulp_get_type ( peer, type );
+	if ( ! ulp )
+		goto err_ulp_get_type;
+
+	/* Drop temporary reference to peer */
+	fc_peer_put ( peer );
+
+	return ulp;
+
+	fc_ulp_put ( ulp );
+ err_ulp_get_type:
+	fc_peer_put ( peer );
+ err_peer_get_wwn:
+	return NULL;
+}
+
+/**
+ * Get Fibre Channel upper-layer protocol by port ID and type
+ *
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @v type		Type
+ * @ret ulp		Fibre Channel upper-layer protocol, or NULL
+ */
+struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port,
+					  const struct fc_port_id *peer_port_id,
+					  unsigned int type ) {
+	struct fc_ulp *ulp;
+	struct fc_peer *peer;
+
+	/* Get peer */
+	peer = fc_peer_get_port_id ( port, peer_port_id );
+	if ( ! peer )
+		goto err_peer_get_wwn;
+
+	/* Get ULP */
+	ulp = fc_ulp_get_type ( peer, type );
+	if ( ! ulp )
+		goto err_ulp_get_type;
+
+	/* Drop temporary reference to peer */
+	fc_peer_put ( peer );
+
+	return ulp;
+
+	fc_ulp_put ( ulp );
+ err_ulp_get_type:
+	fc_peer_put ( peer );
+ err_peer_get_wwn:
+	return NULL;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fcels.c b/qemu-0.15.x/roms/ipxe/src/net/fcels.c
new file mode 100644
index 0000000..f8bcb86
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fcels.c
@@ -0,0 +1,1338 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/process.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+
+/** @file
+ *
+ * Fibre Channel Extended Link Services
+ *
+ */
+
+/** Fibre Channel ELS transaction debug message format */
+#define FCELS_FMT "FCELS %s %s %s %s"
+
+/** Fibre Channel ELS transaction debug message arguments */
+#define FCELS_ARGS( els )						\
+	(els)->port->name,						\
+	( (els)->handler ? (els)->handler->name : "unknown ELS" ),	\
+	( fc_els_is_request ( els ) ? "to" : "from" ),			\
+	fc_id_ntoa ( &(els)->peer_port_id )
+
+struct fc_els_handler fc_els_unknown_handler __fc_els_handler;
+
+/**
+ * Free Fibre Channel ELS transaction
+ *
+ * @v refcnt		Reference count
+ */
+static void fc_els_free ( struct refcnt *refcnt ) {
+	struct fc_els *els = container_of ( refcnt, struct fc_els, refcnt );
+
+	assert ( ! process_running ( &els->process ) );
+	fc_port_put ( els->port );
+	free ( els );
+}
+
+/**
+ * Close Fibre Channel ELS transaction
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v rc		Reason for close
+ */
+static void fc_els_close ( struct fc_els *els, int rc ) {
+
+	if ( rc != 0 ) {
+		DBGC ( els, FCELS_FMT " complete (%s)\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+	}
+
+	/* Stop process */
+	process_del ( &els->process );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &els->xchg, rc );
+	intf_shutdown ( &els->job, rc );
+}
+
+/**
+ * Detect Fibre Channel ELS frame handler
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v command		ELS command code
+ * @ret handler		ELS handler, or NULL
+ */
+static struct fc_els_handler * fc_els_detect ( struct fc_els *els,
+					       const void *data,
+					       size_t len ) {
+	const struct fc_els_frame_common *frame = data;
+	struct fc_els_handler *handler;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *frame ) )
+		return NULL;
+
+	/* Try each handler in turn */
+	for_each_table_entry ( handler, FC_ELS_HANDLERS ) {
+		if ( ( rc = handler->detect ( els, data, len ) ) == 0 )
+			return handler;
+	}
+
+	return NULL;
+}
+
+/**
+ * Transmit Fibre Channel ELS frame
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		Data to transmit
+ * @v len		Length of data
+ * @ret rc		Return status code
+ */
+int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
+	struct xfer_metadata meta;
+	struct sockaddr_fc dest;
+	int rc;
+
+	DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
+	DBGC2_HDA ( els, 0, data, len );
+
+	/* Construct metadata */
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = ( fc_els_is_request ( els ) ?
+		       XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) );
+	meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id );
+
+	/* Transmit frame */
+	if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
+					    &meta ) ) != 0 ) {
+		DBGC ( els, FCELS_FMT " could not deliver frame: %s\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive Fibre Channel ELS frame
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fc_els_rx ( struct fc_els *els,
+		       struct io_buffer *iobuf,
+		       struct xfer_metadata *meta ) {
+	struct fc_els_frame_common *frame = iobuf->data;
+	struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
+	struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
+	size_t len = iob_len ( iobuf );
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *frame ) ) {
+		DBGC ( els, FCELS_FMT " received underlength frame:\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, frame, len );
+		rc = -EINVAL;
+		goto done;
+	}
+	if ( ! src ) {
+		DBGC ( els, FCELS_FMT " received frame missing source "
+		       "address:\n", FCELS_ARGS ( els ) );
+		rc = -EINVAL;
+		goto done;
+	}
+	if ( ! dest ) {
+		DBGC ( els, FCELS_FMT " received frame missing destination "
+		       "address:\n", FCELS_ARGS ( els ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Check for rejection responses */
+	if ( fc_els_is_request ( els ) &&
+	     ( frame->command != FC_ELS_LS_ACC ) ) {
+		DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, frame, len );
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Update port IDs */
+	memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) );
+	memcpy ( &els->peer_port_id, &src->sfc_port_id,
+		 sizeof ( els->peer_port_id ) );
+
+	/* Determine handler, if necessary */
+	if ( ! els->handler )
+		els->handler = fc_els_detect ( els, frame, len );
+	if ( ! els->handler )
+		els->handler = &fc_els_unknown_handler;
+
+	DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) );
+	DBGC2_HDA ( els, 0, frame, len );
+
+	/* Handle received frame */
+	if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
+		DBGC ( els, FCELS_FMT " could not handle received frame: "
+		       "%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
+		DBGC_HDA ( els, 0, frame, len );
+		goto done;
+	}
+
+ done:
+	/* Free I/O buffer */
+	free_iob ( iobuf );
+
+	/* Close transaction */
+	fc_els_close ( els, rc );
+
+	return rc;
+}
+
+/** Fibre Channel ELS exchange interface operations */
+static struct interface_operation fc_els_xchg_op[] = {
+	INTF_OP ( xfer_deliver, struct fc_els *, fc_els_rx ),
+	INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
+};
+
+/** Fibre Channel ELS exchange interface descriptor */
+static struct interface_descriptor fc_els_xchg_desc =
+	INTF_DESC ( struct fc_els, xchg, fc_els_xchg_op );
+
+/** Fibre Channel ELS job control interface operations */
+static struct interface_operation fc_els_job_op[] = {
+	INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
+};
+
+/** Fibre Channel ELS job control interface descriptor */
+static struct interface_descriptor fc_els_job_desc =
+	INTF_DESC ( struct fc_els, job, fc_els_job_op );
+
+/**
+ * Fibre Channel ELS process
+ *
+ * @v process		Process
+ */
+static void fc_els_step ( struct process *process ) {
+	struct fc_els *els =
+		container_of ( process, struct fc_els, process );
+	int xchg_id;
+	int rc;
+
+	/* Sanity check */
+	assert ( fc_els_is_request ( els ) );
+
+	/* Stop process */
+	process_del ( &els->process );
+
+	/* Create exchange */
+	if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
+					     &els->peer_port_id,
+					     FC_TYPE_ELS ) ) < 0 ) {
+		rc = xchg_id;
+		DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+		fc_els_close ( els, rc );
+		return;
+	}
+
+	/* Transmit request */
+	if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
+		DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+		fc_els_close ( els, rc );
+		return;
+	}
+}
+
+/**
+ * Create ELS transaction
+ *
+ * @v port		Fibre Channel port
+ * @v port_id		Local port ID
+ * @v peer_port_id	Peer port ID
+ * @ret els		Fibre Channel ELS transaction, or NULL
+ */
+static struct fc_els * fc_els_create ( struct fc_port *port,
+				       struct fc_port_id *port_id,
+				       struct fc_port_id *peer_port_id ) {
+	struct fc_els *els;
+
+	/* Allocate and initialise structure */
+	els = zalloc ( sizeof ( *els ) );
+	if ( ! els )
+		return NULL;
+	ref_init ( &els->refcnt, fc_els_free );
+	intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
+	intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
+	process_init_stopped ( &els->process, fc_els_step, &els->refcnt );
+	els->port = fc_port_get ( port );
+	memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
+	memcpy ( &els->peer_port_id, peer_port_id,
+		 sizeof ( els->peer_port_id ) );
+	return els;
+}
+
+/**
+ * Create ELS request
+ *
+ * @v job		Parent job-control interface
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @v handler		ELS handler
+ * @ret rc		Return status code
+ */
+int fc_els_request ( struct interface *job, struct fc_port *port,
+		     struct fc_port_id *peer_port_id,
+		     struct fc_els_handler *handler ) {
+	struct fc_els *els;
+
+	/* Allocate and initialise structure */
+	els = fc_els_create ( port, &port->port_id, peer_port_id );
+	if ( ! els )
+		return -ENOMEM;
+	els->handler = handler;
+	els->flags = FC_ELS_REQUEST;
+	process_add ( &els->process );
+
+	/* Attach to parent job interface, mortalise self, and return */
+	intf_plug_plug ( &els->job, job );
+	ref_put ( &els->refcnt );
+	return 0;
+}
+
+/**
+ * Create ELS response
+ *
+ * @v xchg		Exchange interface
+ * @v port		Fibre Channel port
+ * @v port_id		Local port ID
+ * @v peer_port_id	Peer port ID
+ * @ret rc		Return status code
+ */
+static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
+			    struct fc_port_id *port_id,
+			    struct fc_port_id *peer_port_id ) {
+	struct fc_els *els;
+
+	/* Allocate and initialise structure */
+	els = fc_els_create ( port, port_id, peer_port_id );
+	if ( ! els )
+		return -ENOMEM;
+
+	/* Attach to exchange interface, mortalise self, and return */
+	intf_plug_plug ( &els->xchg, xchg );
+	ref_put ( &els->refcnt );
+	return 0;
+}
+
+/** Fibre Channel ELS responder */
+struct fc_responder fc_els_responder __fc_responder = {
+	.type = FC_TYPE_ELS,
+	.respond = fc_els_respond,
+};
+
+/******************************************************************************
+ *
+ * Unknown ELS handler
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit unknown ELS request
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
+	return -ENOTSUP;
+}
+
+/**
+ * Transmit unknown ELS response
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_unknown_tx_response ( struct fc_els *els ) {
+	struct fc_ls_rjt_frame ls_rjt;
+
+	/* Construct LS_RJT */
+	memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
+	ls_rjt.command = FC_ELS_LS_RJT;
+	ls_rjt.reason = FC_ELS_RJT_UNSUPPORTED;
+
+	/* Transmit LS_RJT */
+	return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
+}
+
+/**
+ * Receive unknown ELS
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
+	int rc;
+
+	DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
+	DBGC_HDA ( els, 0, data, len );
+
+	/* Transmit response, if applicable */
+	if ( ! fc_els_is_request ( els ) ) {
+		if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detect unknown ELS
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_unknown_detect ( struct fc_els *els __unused,
+				   const void *data __unused,
+				   size_t len __unused ) {
+	return -ENOTSUP;
+}
+
+/** Unknown ELS handler */
+struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
+	.name		= "UNKNOWN",
+	.tx		= fc_els_unknown_tx,
+	.rx		= fc_els_unknown_rx,
+	.detect		= fc_els_unknown_detect,
+};
+
+/******************************************************************************
+ *
+ * FLOGI
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit FLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_flogi_tx ( struct fc_els *els ) {
+	struct fc_login_frame flogi;
+
+	/* Construct FLOGI */
+	memset ( &flogi, 0, sizeof ( flogi ) );
+	flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
+	flogi.common.version = htons ( FC_LOGIN_VERSION );
+	flogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
+	flogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
+	flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
+	memcpy ( &flogi.port_wwn, &els->port->port_wwn,
+		 sizeof ( flogi.port_wwn ) );
+	memcpy ( &flogi.node_wwn, &els->port->node_wwn,
+		 sizeof ( flogi.node_wwn ) );
+	flogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
+				     FC_LOGIN_CLASS_SEQUENTIAL );
+
+	/* Transmit FLOGI */
+	return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
+}
+
+/**
+ * Receive FLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
+	struct fc_login_frame *flogi = data;
+	int has_fabric;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *flogi ) ) {
+		DBGC ( els, FCELS_FMT " received underlength frame:\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		return -EINVAL;
+	}
+
+	/* Extract parameters */
+	has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
+	DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
+	       fc_ntoa ( &flogi->node_wwn ) );
+	DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
+	       fc_ntoa ( &flogi->port_wwn ) );
+	if ( has_fabric ) {
+		DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
+		DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
+	} else {
+		DBGC ( els, FCELS_FMT " has point-to-point link\n",
+		       FCELS_ARGS ( els ) );
+	}
+
+	/* Log in port */
+	if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
+				    &flogi->port_wwn, has_fabric ) ) != 0 ) {
+		DBGC ( els, FCELS_FMT " could not log in port: %s\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+		return rc;
+	}
+
+	/* Send any responses to the newly-assigned peer port ID, if
+	 * applicable.
+	 */
+	if ( ! has_fabric ) {
+		memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
+			 sizeof ( els->peer_port_id ) );
+	}
+
+	/* Transmit response, if applicable */
+	if ( ! fc_els_is_request ( els ) ) {
+		if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detect FLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
+				 size_t len __unused ) {
+	const struct fc_login_frame *flogi = data;
+
+	/* Check for FLOGI */
+	if ( flogi->command != FC_ELS_FLOGI )
+		return -EINVAL;
+
+	return 0;
+}
+
+/** FLOGI ELS handler */
+struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
+	.name		= "FLOGI",
+	.tx		= fc_els_flogi_tx,
+	.rx		= fc_els_flogi_rx,
+	.detect		= fc_els_flogi_detect,
+};
+
+/**
+ * Create FLOGI request
+ *
+ * @v parent		Parent interface
+ * @v port		Fibre Channel port
+ * @ret rc		Return status code
+ */
+int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
+
+	return fc_els_request ( parent, port, &fc_f_port_id,
+				&fc_els_flogi_handler );
+}
+
+/******************************************************************************
+ *
+ * PLOGI
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit PLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_plogi_tx ( struct fc_els *els ) {
+	struct fc_login_frame plogi;
+
+	/* Construct PLOGI */
+	memset ( &plogi, 0, sizeof ( plogi ) );
+	plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
+	plogi.common.version = htons ( FC_LOGIN_VERSION );
+	plogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
+	plogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
+	plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
+	plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
+	plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
+	plogi.common.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
+	memcpy ( &plogi.port_wwn, &els->port->port_wwn,
+		 sizeof ( plogi.port_wwn ) );
+	memcpy ( &plogi.node_wwn, &els->port->node_wwn,
+		 sizeof ( plogi.node_wwn ) );
+	plogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
+				     FC_LOGIN_CLASS_SEQUENTIAL );
+	plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
+	plogi.class3.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
+	plogi.class3.max_seq_per_xchg = 1;
+
+	/* Transmit PLOGI */
+	return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
+}
+
+/**
+ * Receive PLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
+	struct fc_login_frame *plogi = data;
+	struct fc_peer *peer;
+	int rc;
+
+	/* Sanity checks */
+	if ( len < sizeof ( *plogi ) ) {
+		DBGC ( els, FCELS_FMT " received underlength frame:\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+	if ( ! fc_link_ok ( &els->port->link ) ) {
+		DBGC ( els, FCELS_FMT " received while port link is down\n",
+		       FCELS_ARGS ( els ) );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	/* Extract parameters */
+	DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
+	       fc_ntoa ( &plogi->node_wwn ) );
+	DBGC ( els, FCELS_FMT " has port %s as %s\n",
+	       FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
+	       fc_id_ntoa ( &els->peer_port_id ) );
+
+	/* Get peer */
+	peer = fc_peer_get_wwn ( &plogi->port_wwn );
+	if ( ! peer ) {
+		DBGC ( els, FCELS_FMT " could not create peer\n",
+		       FCELS_ARGS ( els ) );
+		rc = -ENOMEM;
+		goto err_peer_get_wwn;
+	}
+
+	/* Record login */
+	if ( ( rc = fc_peer_login ( peer, els->port,
+				    &els->peer_port_id ) ) != 0 ) {
+		DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
+		       FCELS_ARGS ( els ), strerror ( rc ) );
+		goto err_login;
+	}
+
+	/* Transmit response, if applicable */
+	if ( ! fc_els_is_request ( els ) ) {
+		if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
+			goto err_plogi_tx;
+	}
+
+	/* Drop temporary reference to peer */
+	fc_peer_put ( peer );
+
+	return 0;
+
+ err_plogi_tx:
+ err_login:
+	fc_peer_put ( peer );
+ err_peer_get_wwn:
+ err_sanity:
+	return rc;
+}
+
+/**
+ * Detect PLOGI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
+				 size_t len __unused ) {
+	const struct fc_login_frame *plogi = data;
+
+	/* Check for PLOGI */
+	if ( plogi->command != FC_ELS_PLOGI )
+		return -EINVAL;
+
+	return 0;
+}
+
+/** PLOGI ELS handler */
+struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
+	.name		= "PLOGI",
+	.tx		= fc_els_plogi_tx,
+	.rx		= fc_els_plogi_rx,
+	.detect		= fc_els_plogi_detect,
+};
+
+/**
+ * Create PLOGI request
+ *
+ * @v parent		Parent interface
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret rc		Return status code
+ */
+int fc_els_plogi ( struct interface *parent, struct fc_port *port,
+		   struct fc_port_id *peer_port_id ) {
+
+	return fc_els_request ( parent, port, peer_port_id,
+				&fc_els_plogi_handler );
+}
+
+/******************************************************************************
+ *
+ * LOGO
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit LOGO request
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_tx ( struct fc_els *els ) {
+	struct fc_logout_request_frame logo;
+
+	/* Construct LOGO */
+	memset ( &logo, 0, sizeof ( logo ) );
+	logo.command = FC_ELS_LOGO;
+	memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
+	memcpy ( &logo.port_wwn, &els->port->port_wwn,
+		 sizeof ( logo.port_wwn ) );
+
+	/* Transmit LOGO */
+	return fc_els_tx ( els, &logo, sizeof ( logo ) );
+}
+
+/**
+ * Transmit LOGO response
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_tx_response ( struct fc_els *els ) {
+	struct fc_logout_response_frame logo;
+
+	/* Construct LOGO */
+	memset ( &logo, 0, sizeof ( logo ) );
+	logo.command = FC_ELS_LS_ACC;
+
+	/* Transmit LOGO */
+	return fc_els_tx ( els, &logo, sizeof ( logo ) );
+}
+
+/**
+ * Log out individual peer or whole port as applicable
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v port_id		Peer port ID
+ */
+static void fc_els_logo_logout ( struct fc_els *els,
+				 struct fc_port_id *peer_port_id ) {
+	struct fc_peer *peer;
+
+	if ( ( memcmp ( peer_port_id, &fc_f_port_id,
+			sizeof ( *peer_port_id ) ) == 0 ) ||
+	     ( memcmp ( peer_port_id, &els->port->port_id,
+			sizeof ( *peer_port_id ) ) == 0 ) ) {
+		fc_port_logout ( els->port, 0 );
+	} else {
+		peer = fc_peer_get_port_id ( els->port, peer_port_id );
+		if ( peer ) {
+			fc_peer_logout ( peer, 0 );
+			fc_peer_put ( peer );
+		}
+	}
+}
+
+/**
+ * Receive LOGO request
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
+				    size_t len ) {
+	struct fc_logout_request_frame *logo = data;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *logo ) ) {
+		DBGC ( els, FCELS_FMT " received underlength frame:\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		return -EINVAL;
+	}
+
+	DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
+	       fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
+
+	/* Log out individual peer or whole port as applicable */
+	fc_els_logo_logout ( els, &logo->port_id );
+
+	/* Transmit repsonse */
+	if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Receive LOGO response
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
+				     size_t len __unused ) {
+
+	/* Log out individual peer or whole port as applicable */
+	fc_els_logo_logout ( els, &els->peer_port_id );
+
+	return 0;
+}
+
+/**
+ * Receive LOGO
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
+
+	if ( fc_els_is_request ( els ) ) {
+		return fc_els_logo_rx_response ( els, data, len );
+	} else {
+		return fc_els_logo_rx_request ( els, data, len );
+	}
+}
+
+/**
+ * Detect LOGO
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
+				size_t len __unused ) {
+	const struct fc_logout_request_frame *logo = data;
+
+	/* Check for LOGO */
+	if ( logo->command != FC_ELS_LOGO )
+		return -EINVAL;
+
+	return 0;
+}
+
+/** LOGO ELS handler */
+struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
+	.name		= "LOGO",
+	.tx		= fc_els_logo_tx,
+	.rx		= fc_els_logo_rx,
+	.detect		= fc_els_logo_detect,
+};
+
+/**
+ * Create LOGO request
+ *
+ * @v parent		Parent interface
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @ret rc		Return status code
+ */
+int fc_els_logo ( struct interface *parent, struct fc_port *port,
+		  struct fc_port_id *peer_port_id ) {
+
+	return fc_els_request ( parent, port, peer_port_id,
+				&fc_els_logo_handler );
+}
+
+/******************************************************************************
+ *
+ * PRLI
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Find PRLI descriptor
+ *
+ * @v type		Upper-layer protocol type
+ * @ret descriptor	PRLI descriptor, or NULL
+ */
+static struct fc_els_prli_descriptor *
+fc_els_prli_descriptor ( unsigned int type ) {
+	struct fc_els_prli_descriptor *descriptor;
+
+	for_each_table_entry ( descriptor, FC_ELS_PRLI_DESCRIPTORS ) {
+		if ( descriptor->type == type )
+			return descriptor;
+	}
+	return NULL;
+}
+
+/**
+ * Transmit PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v descriptor	ELS PRLI descriptor
+ * @v param		Service parameters
+ * @ret rc		Return status code
+ */
+int fc_els_prli_tx ( struct fc_els *els,
+		     struct fc_els_prli_descriptor *descriptor, void *param ) {
+	struct {
+		struct fc_prli_frame frame;
+		uint8_t param[descriptor->param_len];
+	} __attribute__ (( packed )) prli;
+	struct fc_ulp *ulp;
+	int rc;
+
+	/* Get ULP */
+	ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
+					descriptor->type );
+	if ( ! ulp ) {
+		rc = -ENOMEM;
+		goto err_get_port_id_type;
+	}
+
+	/* Build frame for transmission */
+	memset ( &prli, 0, sizeof ( prli ) );
+	prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
+	prli.frame.page_len =
+		( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
+	prli.frame.len = htons ( sizeof ( prli ) );
+	prli.frame.page.type = descriptor->type;
+	if ( fc_els_is_request ( els ) ) {
+		prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
+	} else if ( fc_link_ok ( &ulp->link ) ) {
+		prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
+						    FC_PRLI_RESPONSE_SUCCESS );
+	}
+	memcpy ( &prli.param, param, sizeof ( prli.param ) );
+
+	/* Transmit frame */
+	if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
+		goto err_tx;
+
+	/* Drop temporary reference to ULP */
+	fc_ulp_put ( ulp );
+
+	return 0;
+
+ err_tx:
+	fc_ulp_put ( ulp );
+ err_get_port_id_type:
+	return rc;
+}
+
+/**
+ * Receive PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v descriptor	ELS PRLI descriptor
+ * @v frame		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+int fc_els_prli_rx ( struct fc_els *els,
+		     struct fc_els_prli_descriptor *descriptor,
+		     void *data, size_t len ) {
+	struct {
+		struct fc_prli_frame frame;
+		uint8_t param[descriptor->param_len];
+	} __attribute__ (( packed )) *prli = data;
+	struct fc_ulp *ulp;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *prli ) ) {
+		DBGC ( els, FCELS_FMT " received underlength frame:\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
+	DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
+
+	/* Get ULP */
+	ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
+					descriptor->type );
+	if ( ! ulp ) {
+		rc = -ENOMEM;
+		goto err_get_port_id_type;
+	}
+
+	/* Sanity check */
+	if ( ! fc_link_ok ( &ulp->peer->link ) ) {
+		DBGC ( els, FCELS_FMT " received while peer link is down\n",
+		       FCELS_ARGS ( els ) );
+		rc = -EINVAL;
+		goto err_link;
+	}
+
+	/* Log in ULP, if applicable */
+	if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
+		if ( ( rc = fc_ulp_login ( ulp, prli->param,
+					   sizeof ( prli->param ),
+					   fc_els_is_request ( els ) ) ) != 0 ){
+			DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
+			       FCELS_ARGS ( els ), strerror ( rc ) );
+			goto err_login;
+		}
+	} else {
+		if ( fc_els_is_request ( els ) ) {
+			fc_ulp_logout ( ulp, -EACCES );
+		} else {
+			/* This is just an information-gathering PRLI; do not
+			 * log in or out
+			 */
+		}
+	}
+
+	/* Transmit response, if applicable */
+	if ( ! fc_els_is_request ( els ) ) {
+		if ( ( rc = els->handler->tx ( els ) ) != 0 )
+			goto err_tx;
+	}
+
+	/* Drop temporary reference to ULP */
+	fc_ulp_put ( ulp );
+
+	return 0;
+
+ err_tx:
+ err_login:
+ err_link:
+	fc_ulp_put ( ulp );
+ err_get_port_id_type:
+ err_sanity:
+	return rc;
+}
+
+/**
+ * Detect PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v descriptor	ELS PRLI descriptor
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+int fc_els_prli_detect ( struct fc_els *els __unused,
+			 struct fc_els_prli_descriptor *descriptor,
+			 const void *data, size_t len ) {
+	const struct {
+		struct fc_prli_frame frame;
+		uint8_t param[descriptor->param_len];
+	} __attribute__ (( packed )) *prli = data;
+
+	/* Check for PRLI */
+	if ( prli->frame.command != FC_ELS_PRLI )
+		return -EINVAL;
+
+	/* Check for sufficient length to contain service parameter page */
+	if ( len < sizeof ( *prli ) )
+		return -EINVAL;
+
+	/* Check for upper-layer protocol type */
+	if ( prli->frame.page.type != descriptor->type )
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * Create PRLI request
+ *
+ * @v parent		Parent interface
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @v type		Upper-layer protocol type
+ * @ret rc		Return status code
+ */
+int fc_els_prli ( struct interface *parent, struct fc_port *port,
+		  struct fc_port_id *peer_port_id, unsigned int type ) {
+	struct fc_els_prli_descriptor *descriptor;
+
+	/* Find a PRLI descriptor */
+	descriptor = fc_els_prli_descriptor ( type );
+	if ( ! descriptor )
+		return -ENOTSUP;
+
+	return fc_els_request ( parent, port, peer_port_id,
+				descriptor->handler );
+}
+
+/******************************************************************************
+ *
+ * RTV
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit RTV response
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_rtv_tx_response ( struct fc_els *els ) {
+	struct fc_rtv_response_frame rtv;
+
+	/* Construct RTV */
+	memset ( &rtv, 0, sizeof ( rtv ) );
+	rtv.command = FC_ELS_LS_ACC;
+	rtv.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
+
+	/* Transmit RTV */
+	return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
+}
+
+/**
+ * Receive RTV
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
+			   size_t len __unused ) {
+	int rc;
+
+	DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
+
+	/* Transmit response */
+	if ( ! fc_els_is_request ( els ) ) {
+		if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detect RTV
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
+			       size_t len __unused ) {
+	const struct fc_rtv_request_frame *rtv = data;
+
+	/* Check for RTV */
+	if ( rtv->command != FC_ELS_RTV )
+		return -EINVAL;
+
+	return 0;
+}
+
+/** RTV ELS handler */
+struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
+	.name		= "RTV",
+	.tx		= fc_els_unknown_tx,
+	.rx		= fc_els_rtv_rx,
+	.detect		= fc_els_rtv_detect,
+};
+
+/******************************************************************************
+ *
+ * ECHO
+ *
+ ******************************************************************************
+ */
+
+/** ECHO request data */
+struct fc_echo_request_frame {
+	/** ECHO frame header */
+	struct fc_echo_frame_header echo;
+	/** Magic marker */
+	uint32_t magic;
+} __attribute__ (( packed ));
+
+/** ECHO magic marker */
+#define FC_ECHO_MAGIC 0x69505845
+
+/**
+ * Transmit ECHO
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fc_els_echo_tx ( struct fc_els *els ) {
+	struct fc_echo_request_frame echo;
+
+	/* Construct ECHO */
+	memset ( &echo, 0, sizeof ( echo ) );
+	echo.echo.command = FC_ELS_ECHO;
+	echo.magic = htonl ( FC_ECHO_MAGIC );
+
+	/* Transmit ECHO */
+	return fc_els_tx ( els, &echo, sizeof ( echo ) );
+}
+
+/**
+ * Receive ECHO request
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
+				    size_t len ) {
+	struct {
+		struct fc_echo_frame_header echo;
+		char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
+	} *echo = data;
+	int rc;
+
+	DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
+
+	/* Transmit response */
+	echo->echo.command = FC_ELS_LS_ACC;
+	if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
+		return rc;
+
+	/* Nothing to do */
+	return 0;
+}
+
+/**
+ * Receive ECHO response
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
+				     size_t len ) {
+	struct fc_echo_request_frame *echo = data;
+
+	DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
+
+	/* Check response is correct */
+	if ( ( len != sizeof ( *echo ) ) ||
+	     ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
+		DBGC ( els, FCELS_FMT " received bad echo response\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive ECHO
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
+
+	if ( fc_els_is_request ( els ) ) {
+		return fc_els_echo_rx_response ( els, data, len );
+	} else {
+		return fc_els_echo_rx_request ( els, data, len );
+	}
+}
+
+/**
+ * Detect ECHO
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
+				size_t len __unused ) {
+	const struct fc_echo_frame_header *echo = data;
+
+	/* Check for ECHO */
+	if ( echo->command != FC_ELS_ECHO )
+		return -EINVAL;
+
+	return 0;
+}
+
+/** ECHO ELS handler */
+struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
+	.name		= "ECHO",
+	.tx		= fc_els_echo_tx,
+	.rx		= fc_els_echo_rx,
+	.detect		= fc_els_echo_detect,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fcns.c b/qemu-0.15.x/roms/ipxe/src/net/fcns.c
new file mode 100644
index 0000000..7769e25
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fcns.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/interface.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/process.h>
+#include <ipxe/xfer.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcns.h>
+
+/** @file
+ *
+ * Fibre Channel name server lookups
+ *
+ */
+
+/** A Fibre Channel name server query */
+struct fc_ns_query {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Fibre Channel exchange */
+	struct interface xchg;
+
+	/** Fibre Channel peer */
+	struct fc_peer *peer;
+	/** Fibre Channel port */
+	struct fc_port *port;
+
+	/** Process */
+	struct process process;
+	/** Success handler
+	 *
+	 * @v peer		Fibre Channel peer
+	 * @v port		Fibre Channel port
+	 * @v peer_port_id	Peer port ID
+	 * @ret rc		Return status code
+	 */
+	int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
+			 struct fc_port_id *peer_port_id );
+};
+
+/**
+ * Free name server query
+ *
+ * @v refcnt		Reference count
+ */
+static void fc_ns_query_free ( struct refcnt *refcnt ) {
+	struct fc_ns_query *query =
+		container_of ( refcnt, struct fc_ns_query, refcnt );
+
+	fc_peer_put ( query->peer );
+	fc_port_put ( query->port );
+	free ( query );
+}
+
+/**
+ * Close name server query
+ *
+ * @v query		Name server query
+ * @v rc		Reason for close
+ */
+static void fc_ns_query_close ( struct fc_ns_query *query, int rc ) {
+
+	/* Stop process */
+	process_del ( &query->process );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &query->xchg, rc );
+}
+
+/**
+ * Receive name server query response
+ *
+ * @v query		Name server query
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fc_ns_query_deliver ( struct fc_ns_query *query,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta __unused ) {
+	union fc_ns_response *resp = iobuf->data;
+	struct fc_port_id *peer_port_id;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( resp->ct ) ) {
+		DBGC ( query, "FCNS %p received underlength response (%zd "
+		       "bytes)\n", query, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Handle response */
+	switch ( ntohs ( resp->ct.code ) ) {
+	case FC_GS_ACCEPT:
+		if ( iob_len ( iobuf ) < sizeof ( resp->gid_pn ) ) {
+			DBGC ( query, "FCNS %p received underlength accept "
+			       "response (%zd bytes)\n",
+			       query, iob_len ( iobuf ) );
+			rc = -EINVAL;
+			goto done;
+		}
+		peer_port_id = &resp->gid_pn.port_id.port_id;
+		DBGC ( query, "FCNS %p resolved %s to %s via %s\n",
+		       query, fc_ntoa ( &query->peer->port_wwn ),
+		       fc_id_ntoa ( peer_port_id ), query->port->name );
+		if ( ( rc = query->done ( query->peer, query->port,
+					  peer_port_id ) ) != 0 )
+			goto done;
+		break;
+	case FC_GS_REJECT:
+		DBGC ( query, "FCNS %p rejected (reason %02x explanation "
+		       "%02x)\n", query, resp->reject.ct.reason,
+		       resp->reject.ct.explanation );
+		break;
+	default:
+		DBGC ( query, "FCNS %p received invalid response code %04x\n",
+		       query, ntohs ( resp->ct.code ) );
+		rc = -ENOTSUP;
+		goto done;
+	}
+
+	rc = 0;
+ done:
+	free_iob ( iobuf );
+	fc_ns_query_close ( query, rc );
+	return rc;
+}
+
+/**
+ * Name server query process
+ *
+ * @v process		Process
+ */
+static void fc_ns_query_step ( struct process *process ) {
+	struct fc_ns_query *query =
+		container_of ( process, struct fc_ns_query, process );
+	struct xfer_metadata meta;
+	struct fc_ns_gid_pn_request gid_pn;
+	int xchg_id;
+	int rc;
+
+	/* Stop process */
+	process_del ( &query->process );
+
+	/* Create exchange */
+	if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
+					     &fc_gs_port_id,
+					     FC_TYPE_CT ) ) < 0 ) {
+		rc = xchg_id;
+		DBGC ( query, "FCNS %p could not create exchange: %s\n",
+		       query, strerror ( rc ) );
+		fc_ns_query_close ( query, rc );
+		return;
+	}
+
+	/* Construct query request */
+	memset ( &gid_pn, 0, sizeof ( gid_pn ) );
+	gid_pn.ct.revision = FC_CT_REVISION;
+	gid_pn.ct.type = FC_GS_TYPE_DS;
+	gid_pn.ct.subtype = FC_DS_SUBTYPE_NAME;
+	gid_pn.ct.code = htons ( FC_NS_GET ( FC_NS_PORT_NAME, FC_NS_PORT_ID ));
+	memcpy ( &gid_pn.port_wwn, &query->peer->port_wwn,
+		 sizeof ( gid_pn.port_wwn ) );
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = XFER_FL_OVER;
+
+	/* Send query */
+	if ( ( rc = xfer_deliver_raw_meta ( &query->xchg, &gid_pn,
+					    sizeof ( gid_pn ), &meta ) ) != 0){
+		DBGC ( query, "FCNS %p could not deliver query: %s\n",
+		       query, strerror ( rc ) );
+		fc_ns_query_close ( query, rc );
+		return;
+	}
+}
+
+/** Name server exchange interface operations */
+static struct interface_operation fc_ns_query_xchg_op[] = {
+	INTF_OP ( xfer_deliver, struct fc_ns_query *, fc_ns_query_deliver ),
+	INTF_OP ( intf_close, struct fc_ns_query *, fc_ns_query_close ),
+};
+
+/** Name server exchange interface descriptor */
+static struct interface_descriptor fc_ns_query_xchg_desc =
+	INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
+
+/**
+ * Issue Fibre Channel name server query
+ *
+ * @v peer		Fibre Channel peer
+ * @v port		Fibre Channel port
+ * @ret rc		Return status code
+ */
+int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
+		  int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
+				   struct fc_port_id *peer_port_id ) ) {
+	struct fc_ns_query *query;
+
+	/* Allocate and initialise structure */
+	query = zalloc ( sizeof ( *query ) );
+	if ( ! query )
+		return -ENOMEM;
+	ref_init ( &query->refcnt, fc_ns_query_free );
+	intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
+	process_init ( &query->process, fc_ns_query_step, &query->refcnt );
+	query->peer = fc_peer_get ( peer );
+	query->port = fc_port_get ( port );
+	query->done = done;
+
+	DBGC ( query, "FCNS %p querying %s via %s\n",
+	       query, fc_ntoa ( &query->peer->port_wwn ), port->name );
+
+	/* Mortalise self and return */
+	ref_put ( &query->refcnt );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fcoe.c b/qemu-0.15.x/roms/ipxe/src/net/fcoe.c
new file mode 100644
index 0000000..db2fc98
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fcoe.c
@@ -0,0 +1,1224 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/vlan.h>
+#include <ipxe/features.h>
+#include <ipxe/errortab.h>
+#include <ipxe/device.h>
+#include <ipxe/crc32.h>
+#include <ipxe/retry.h>
+#include <ipxe/timer.h>
+#include <ipxe/fc.h>
+#include <ipxe/fip.h>
+#include <ipxe/fcoe.h>
+
+/** @file
+ *
+ * FCoE protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 );
+
+/* Disambiguate the various error causes */
+#define EINVAL_UNDERLENGTH __einfo_error ( EINFO_EINVAL_UNDERLENGTH )
+#define EINFO_EINVAL_UNDERLENGTH \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Underlength packet" )
+#define EINVAL_SOF __einfo_error ( EINFO_EINVAL_SOF )
+#define EINFO_EINVAL_SOF \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid SoF delimiter" )
+#define EINVAL_CRC __einfo_error ( EINFO_EINVAL_CRC )
+#define EINFO_EINVAL_CRC \
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid CRC (not stripped?)" )
+#define EINVAL_EOF __einfo_error ( EINFO_EINVAL_EOF )
+#define EINFO_EINVAL_EOF \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid EoF delimiter" )
+
+/** An FCoE port */
+struct fcoe_port {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of FCoE ports */
+	struct list_head list;
+	/** Transport interface */
+	struct interface transport;
+	/** Network device */
+	struct net_device *netdev;
+
+	/** Node WWN */
+	union fcoe_name node_wwn;
+	/** Port WWN */
+	union fcoe_name port_wwn;
+
+	/** FIP retransmission timer */
+	struct retry_timer timer;
+	/** FIP timeout counter */
+	unsigned int timeouts;
+	/** Flags */
+	unsigned int flags;
+	/** FCoE forwarder priority */
+	unsigned int priority;
+	/** Keepalive delay (in ms) */
+	unsigned int keepalive;
+	/** FCoE forwarder MAC address */
+	uint8_t fcf_mac[ETH_ALEN];
+	/** Local MAC address */
+	uint8_t local_mac[ETH_ALEN];
+};
+
+/** FCoE flags */
+enum fcoe_flags {
+	/** Underlying network device is available */
+	FCOE_HAVE_NETWORK = 0x0001,
+	/** We have selected an FCoE forwarder to use */
+	FCOE_HAVE_FCF = 0x0002,
+	/** We have a FIP-capable FCoE forwarder available to be used */
+	FCOE_HAVE_FIP_FCF = 0x0004,
+	/** FCoE forwarder supports server-provided MAC addresses */
+	FCOE_FCF_ALLOWS_SPMA = 0x0008,
+	/** An alternative VLAN has been found */
+	FCOE_VLAN_FOUND = 0x0010,
+	/** VLAN discovery has timed out */
+	FCOE_VLAN_TIMED_OUT = 0x0020,
+};
+
+struct net_protocol fcoe_protocol __net_protocol;
+struct net_protocol fip_protocol __net_protocol;
+
+/** FCoE All-FCoE-MACs address */
+static uint8_t all_fcoe_macs[ETH_ALEN] =
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
+
+/** FCoE All-ENode-MACs address */
+static uint8_t all_enode_macs[ETH_ALEN] =
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
+
+/** FCoE All-FCF-MACs address */
+static uint8_t all_fcf_macs[ETH_ALEN] =
+	{ 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
+
+/** Default FCoE forwarded MAC address */
+static uint8_t default_fcf_mac[ETH_ALEN] =
+	{ 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
+
+/** Maximum number of VLAN requests before giving up on VLAN discovery */
+#define FCOE_MAX_VLAN_REQUESTS 2
+
+/** Delay between retrying VLAN requests */
+#define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
+
+/** Delay between retrying polling VLAN requests */
+#define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
+
+/** Maximum number of FIP solicitations before giving up on FIP */
+#define FCOE_MAX_FIP_SOLICITATIONS 2
+
+/** Delay between retrying FIP solicitations */
+#define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
+
+/** Maximum number of missing discovery advertisements */
+#define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
+
+/** List of FCoE ports */
+static LIST_HEAD ( fcoe_ports );
+
+/******************************************************************************
+ *
+ * FCoE protocol
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Identify FCoE port by network device
+ *
+ * @v netdev		Network device
+ * @ret fcoe		FCoE port, or NULL
+ */
+static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
+	struct fcoe_port *fcoe;
+
+	list_for_each_entry ( fcoe, &fcoe_ports, list ) {
+		if ( fcoe->netdev == netdev )
+			return fcoe;
+	}
+	return NULL;
+}
+
+/**
+ * Reset FCoE port
+ *
+ * @v fcoe		FCoE port
+ */
+static void fcoe_reset ( struct fcoe_port *fcoe ) {
+
+	/* Detach FC port, if any */
+	intf_restart ( &fcoe->transport, -ECANCELED );
+
+	/* Reset any FIP state */
+	stop_timer ( &fcoe->timer );
+	fcoe->timeouts = 0;
+	fcoe->flags = 0;
+	fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
+	fcoe->keepalive = 0;
+	memcpy ( fcoe->fcf_mac, default_fcf_mac,
+		 sizeof ( fcoe->fcf_mac ) );
+	memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr,
+		 sizeof ( fcoe->local_mac ) );
+
+	/* Start FIP solicitation if network is available */
+	if ( netdev_is_open ( fcoe->netdev ) &&
+	     netdev_link_ok ( fcoe->netdev ) ) {
+		fcoe->flags |= FCOE_HAVE_NETWORK;
+		start_timer_nodelay ( &fcoe->timer );
+		DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
+		       ( vlan_can_be_trunk ( fcoe->netdev ) ?
+			 "VLAN discovery" : "FIP solicitation" ) );
+	}
+
+	/* Send notification of window change */
+	xfer_window_changed ( &fcoe->transport );
+}
+
+/**
+ * Transmit FCoE packet
+ *
+ * @v fcoe		FCoE port
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcoe_deliver ( struct fcoe_port *fcoe,
+			  struct io_buffer *iobuf,
+			  struct xfer_metadata *meta __unused ) {
+	struct fc_frame_header *fchdr = iobuf->data;
+	struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) );
+	struct fcoe_header *fcoehdr;
+	struct fcoe_footer *fcoeftr;
+	struct fip_header *fiphdr;
+	struct fip_login *fipflogi;
+	struct fip_mac_address *fipmac;
+	uint32_t crc;
+	struct net_protocol *net_protocol;
+	void *ll_source;
+	int rc;
+
+	/* Send as FIP or FCoE as appropriate */
+	if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) &&
+	     ( els->command == FC_ELS_FLOGI ) &&
+	     ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) {
+
+		/* Create FIP FLOGI descriptor */
+		fipflogi = iob_push ( iobuf,
+				      offsetof ( typeof ( *fipflogi ), fc ) );
+		memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) );
+		fipflogi->type = FIP_FLOGI;
+		fipflogi->len = ( iob_len ( iobuf ) / 4 );
+
+		/* Create FIP MAC address descriptor */
+		fipmac = iob_put ( iobuf, sizeof ( *fipmac ) );
+		memset ( fipmac, 0, sizeof ( *fipmac ) );
+		fipmac->type = FIP_MAC_ADDRESS;
+		fipmac->len = ( sizeof ( *fipmac ) / 4 );
+		if ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) {
+			memcpy ( fipmac->mac, fcoe->netdev->ll_addr,
+				 sizeof ( fipmac->mac ) );
+		}
+
+		/* Create FIP header */
+		fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) );
+		memset ( fiphdr, 0, sizeof ( *fiphdr ) );
+		fiphdr->version = FIP_VERSION;
+		fiphdr->code = htons ( FIP_CODE_ELS );
+		fiphdr->subcode = FIP_ELS_REQUEST;
+		fiphdr->len =
+			htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
+		fiphdr->flags = ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
+				  htons ( FIP_SP ) : htons ( FIP_FP ) );
+
+		/* Send as FIP packet from netdev's own MAC address */
+		net_protocol = &fip_protocol;
+		ll_source = fcoe->netdev->ll_addr;
+
+	} else {
+
+		/* Calculate CRC */
+		crc = crc32_le ( ~((uint32_t)0), iobuf->data,
+				 iob_len ( iobuf ) );
+
+		/* Create FCoE header */
+		fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
+		memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
+		fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
+				 FCOE_SOF_I3 : FCOE_SOF_N3 );
+
+		/* Create FCoE footer */
+		fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
+		memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
+		fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
+		fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
+				 FCOE_EOF_T : FCOE_EOF_N );
+
+		/* Send as FCoE packet from FCoE MAC address */
+		net_protocol = &fcoe_protocol;
+		ll_source = fcoe->local_mac;
+	}
+
+	/* Transmit packet */
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol,
+			     fcoe->fcf_mac, ll_source ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not transmit: %s\n",
+		       fcoe->netdev->name, strerror ( rc ) );
+		goto done;
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Allocate FCoE I/O buffer
+ *
+ * @v len		Payload length
+ * @ret iobuf		I/O buffer, or NULL
+ */
+static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
+					   size_t len ) {
+	struct io_buffer *iobuf;
+
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( struct fcoe_header ) +
+			    len + sizeof ( struct fcoe_footer ) );
+	if ( iobuf ) {
+		iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN +
+				       sizeof ( struct fcoe_header ) ) );
+	}
+	return iobuf;
+}
+
+/**
+ * Process incoming FCoE packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
+		     const void *ll_dest, const void *ll_source ) {
+	struct fcoe_header *fcoehdr;
+	struct fcoe_footer *fcoeftr;
+	struct fcoe_port *fcoe;
+	int rc;
+
+	/* Identify FCoE port */
+	if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
+		DBG ( "FCoE received frame for net device %s missing FCoE "
+		      "port\n", netdev->name );
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	/* Discard packets not destined for us */
+	if ( ( memcmp ( fcoe->local_mac, ll_dest,
+			sizeof ( fcoe->local_mac ) ) != 0 ) &&
+	     ( memcmp ( default_fcf_mac, ll_dest,
+			sizeof ( default_fcf_mac ) ) != 0 ) ) {
+		DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n",
+			fcoe->netdev->name, eth_ntoa ( ll_dest ) );
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){
+		DBGC ( fcoe, "FCoE %s received under-length frame (%zd "
+		       "bytes)\n", fcoe->netdev->name, iob_len ( iobuf ) );
+		rc = -EINVAL_UNDERLENGTH;
+		goto done;
+	}
+
+	/* Strip header and footer */
+	fcoehdr = iobuf->data;
+	iob_pull ( iobuf, sizeof ( *fcoehdr ) );
+	fcoeftr = ( iobuf->data + iob_len ( iobuf ) - sizeof ( *fcoeftr ) );
+	iob_unput ( iobuf, sizeof ( *fcoeftr ) );
+
+	/* Validity checks */
+	if ( fcoehdr->version != FCOE_FRAME_VER ) {
+		DBGC ( fcoe, "FCoE %s received unsupported frame version "
+		       "%02x\n", fcoe->netdev->name, fcoehdr->version );
+		rc = -EPROTONOSUPPORT;
+		goto done;
+	}
+	if ( ! ( ( fcoehdr->sof == FCOE_SOF_I3 ) ||
+		 ( fcoehdr->sof == FCOE_SOF_N3 ) ) ) {
+		DBGC ( fcoe, "FCoE %s received unsupported start-of-frame "
+		       "delimiter %02x\n", fcoe->netdev->name, fcoehdr->sof );
+		rc = -EINVAL_SOF;
+		goto done;
+	}
+	if ( ( le32_to_cpu ( fcoeftr->crc ) ^ ~((uint32_t)0) ) !=
+	     crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) ) ) {
+		DBGC ( fcoe, "FCoE %s received invalid CRC\n",
+		       fcoe->netdev->name );
+		rc = -EINVAL_CRC;
+		goto done;
+	}
+	if ( ! ( ( fcoeftr->eof == FCOE_EOF_N ) ||
+		 ( fcoeftr->eof == FCOE_EOF_T ) ) ) {
+		DBGC ( fcoe, "FCoE %s received unsupported end-of-frame "
+		       "delimiter %02x\n", fcoe->netdev->name, fcoeftr->eof );
+		rc = -EINVAL_EOF;
+		goto done;
+	}
+
+	/* Record FCF address if applicable */
+	if ( ( fcoe->flags & FCOE_HAVE_FCF ) &&
+	     ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) {
+		memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) );
+	}
+
+	/* Hand off via transport interface */
+	if ( ( rc = xfer_deliver_iob ( &fcoe->transport,
+				       iob_disown ( iobuf ) ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not deliver frame: %s\n",
+		       fcoe->netdev->name, strerror ( rc ) );
+		goto done;
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Check FCoE flow control window
+ *
+ * @v fcoe		FCoE port
+ * @ret len		Length of window
+ */
+static size_t fcoe_window ( struct fcoe_port *fcoe ) {
+	return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
+}
+
+/**
+ * Close FCoE port
+ *
+ * @v fcoe		FCoE port
+ * @v rc		Reason for close
+ */
+static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
+
+	stop_timer ( &fcoe->timer );
+	intf_shutdown ( &fcoe->transport, rc );
+	netdev_put ( fcoe->netdev );
+	list_del ( &fcoe->list );
+	ref_put ( &fcoe->refcnt );
+}
+
+/**
+ * Identify device underlying FCoE port
+ *
+ * @v fcoe		FCoE port
+ * @ret device		Underlying device
+ */
+static struct device * fcoe_identify_device ( struct fcoe_port *fcoe ) {
+	return fcoe->netdev->dev;
+}
+
+/** FCoE transport interface operations */
+static struct interface_operation fcoe_transport_op[] = {
+	INTF_OP ( xfer_deliver, struct fcoe_port *, fcoe_deliver ),
+	INTF_OP ( xfer_alloc_iob, struct fcoe_port *, fcoe_alloc_iob ),
+	INTF_OP ( xfer_window, struct fcoe_port *, fcoe_window ),
+	INTF_OP ( intf_close, struct fcoe_port *, fcoe_close ),
+	INTF_OP ( identify_device, struct fcoe_port *,
+		  fcoe_identify_device ),
+};
+
+/** FCoE transport interface descriptor */
+static struct interface_descriptor fcoe_transport_desc =
+	INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
+
+/******************************************************************************
+ *
+ * FIP protocol
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Parse FIP packet into descriptor set
+ *
+ * @v fcoe		FCoE port
+ * @v fiphdr		FIP header
+ * @v len		Length of FIP packet
+ * @v descs		Descriptor set to fill in
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
+			    size_t len, struct fip_descriptors *descs ) {
+	union fip_descriptor *desc;
+	size_t descs_len;
+	size_t desc_len;
+	size_t desc_offset;
+	unsigned int desc_type;
+
+	/* Check FIP version */
+	if ( fiphdr->version != FIP_VERSION ) {
+		DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n",
+		       fcoe->netdev->name, fiphdr->version );
+		return -EINVAL;
+	}
+
+	/* Check length */
+	descs_len = ( ntohs ( fiphdr->len ) * 4 );
+	if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) {
+		DBGC ( fcoe, "FCoE %s received bad descriptor list length\n",
+		       fcoe->netdev->name );
+		return -EINVAL;
+	}
+
+	/* Parse descriptor list */
+	memset ( descs, 0, sizeof ( *descs ) );
+	for ( desc_offset = 0 ;
+	      desc_offset <= ( descs_len - sizeof ( desc->common ) ) ;
+	      desc_offset += desc_len ) {
+
+		/* Find descriptor and validate length */
+		desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset );
+		desc_type = desc->common.type;
+		desc_len = ( desc->common.len * 4 );
+		if ( desc_len == 0 ) {
+			DBGC ( fcoe, "FCoE %s received zero-length "
+			       "descriptor\n", fcoe->netdev->name );
+			return -EINVAL;
+		}
+		if ( ( desc_offset + desc_len ) > descs_len ) {
+			DBGC ( fcoe, "FCoE %s descriptor overrun\n",
+			       fcoe->netdev->name );
+			return -EINVAL;
+		}
+
+		/* Handle descriptors that we understand */
+		if ( ( desc_type > FIP_RESERVED ) &&
+		     ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
+			/* Use only the first instance of a descriptor */
+			if ( descs->desc[desc_type] == NULL )
+				descs->desc[desc_type] = desc;
+			continue;
+		}
+
+		/* Abort if we cannot understand a critical descriptor */
+		if ( FIP_IS_CRITICAL ( desc_type ) ) {
+			DBGC ( fcoe, "FCoE %s cannot understand critical "
+			       "descriptor type %02x\n",
+			       fcoe->netdev->name, desc_type );
+			return -ENOTSUP;
+		}
+
+		/* Ignore non-critical descriptors that we cannot understand */
+	}
+
+	return 0;
+}
+
+/**
+ * Send FIP VLAN request
+ *
+ * @v fcoe		FCoE port
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
+	struct io_buffer *iobuf;
+	struct {
+		struct fip_header hdr;
+		struct fip_mac_address mac_address;
+	} __attribute__ (( packed )) *request;
+	int rc;
+
+	/* Allocate I/O buffer */
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+
+	/* Construct VLAN request */
+	request = iob_put ( iobuf, sizeof ( *request ) );
+	memset ( request, 0, sizeof ( *request ) );
+	request->hdr.version = FIP_VERSION;
+	request->hdr.code = htons ( FIP_CODE_VLAN );
+	request->hdr.subcode = FIP_VLAN_REQUEST;
+	request->hdr.len = htons ( ( sizeof ( *request ) -
+				     sizeof ( request->hdr ) ) / 4 );
+	request->mac_address.type = FIP_MAC_ADDRESS;
+	request->mac_address.len =
+		( sizeof ( request->mac_address ) / 4 );
+	memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
+		 sizeof ( request->mac_address.mac ) );
+
+	/* Send VLAN request */
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
+			     &fip_protocol, all_fcf_macs,
+			     fcoe->netdev->ll_addr ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not send VLAN request: "
+		       "%s\n", fcoe->netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle received FIP VLAN notification
+ *
+ * @v fcoe		FCoE port
+ * @v descs		Descriptor list
+ * @v flags		Flags
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
+			      struct fip_descriptors *descs,
+			      unsigned int flags __unused ) {
+	struct fip_mac_address *mac_address = fip_mac_address ( descs );
+	struct fip_vlan *vlan = fip_vlan ( descs );
+	unsigned int tag;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! mac_address ) {
+		DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
+		       "address\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+	if ( ! vlan ) {
+		DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
+		       "tag\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+
+	/* Create VLAN */
+	tag = ntohs ( vlan->vlan );
+	DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
+	       fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
+	if ( ( rc = vlan_create ( fcoe->netdev, tag,
+				  FCOE_VLAN_PRIORITY ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
+		       fcoe->netdev->name, tag, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Record that a VLAN was found.  This FCoE port will play no
+	 * further active role; the real FCoE traffic will use the
+	 * port automatically created for the new VLAN device.
+	 */
+	fcoe->flags |= FCOE_VLAN_FOUND;
+
+	return 0;
+}
+
+/**
+ * Send FIP discovery solicitation
+ *
+ * @v fcoe		FCoE port
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
+	struct io_buffer *iobuf;
+	struct {
+		struct fip_header hdr;
+		struct fip_mac_address mac_address;
+		struct fip_name_id name_id;
+		struct fip_max_fcoe_size max_fcoe_size;
+	} __attribute__ (( packed )) *solicitation;
+	int rc;
+
+	/* Allocate I/O buffer */
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+
+	/* Construct discovery solicitation */
+	solicitation = iob_put ( iobuf, sizeof ( *solicitation ) );
+	memset ( solicitation, 0, sizeof ( *solicitation ) );
+	solicitation->hdr.version = FIP_VERSION;
+	solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY );
+	solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT;
+	solicitation->hdr.len =	htons ( ( sizeof ( *solicitation ) -
+					  sizeof ( solicitation->hdr ) ) / 4 );
+	solicitation->hdr.flags = htons ( FIP_FP | FIP_SP );
+	solicitation->mac_address.type = FIP_MAC_ADDRESS;
+	solicitation->mac_address.len =
+		( sizeof ( solicitation->mac_address ) / 4 );
+	memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr,
+		 sizeof ( solicitation->mac_address.mac ) );
+	solicitation->name_id.type = FIP_NAME_ID;
+	solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 );
+	memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc,
+		 sizeof ( solicitation->name_id.name ) );
+	solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE;
+	solicitation->max_fcoe_size.len =
+		( sizeof ( solicitation->max_fcoe_size ) / 4 );
+	solicitation->max_fcoe_size.mtu =
+		htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) -
+			sizeof ( struct fcoe_footer ) );
+
+	/* Send discovery solicitation */
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
+			     &fip_protocol, all_fcf_macs,
+			     fcoe->netdev->ll_addr ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not send discovery solicitation: "
+		       "%s\n", fcoe->netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle received FIP discovery advertisement
+ *
+ * @v fcoe		FCoE port
+ * @v descs		Descriptor list
+ * @v flags		Flags
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
+				       struct fip_descriptors *descs,
+				       unsigned int flags ) {
+	struct fip_priority *priority = fip_priority ( descs );
+	struct fip_mac_address *mac_address = fip_mac_address ( descs );
+	struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs );
+
+	/* Sanity checks */
+	if ( ! priority ) {
+		DBGC ( fcoe, "FCoE %s received advertisement missing "
+		       "priority\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+	if ( ! mac_address ) {
+		DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
+		       "address\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+	if ( ! fka_adv_p ) {
+		DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
+		       "period\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+
+	if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
+
+		/* We are soliciting for an FCF.  Store the highest
+		 * (i.e. lowest-valued) priority solicited
+		 * advertisement that we receive.
+		 */
+		if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
+		       ( FIP_A | FIP_S | FIP_F ) ) &&
+		     ( priority->priority < fcoe->priority ) ) {
+
+			fcoe->flags |= FCOE_HAVE_FIP_FCF;
+			fcoe->priority = priority->priority;
+			if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
+				fcoe->keepalive = 0;
+			} else {
+				fcoe->keepalive = ntohl ( fka_adv_p->period );
+			}
+			fcoe->flags &= ~FCOE_FCF_ALLOWS_SPMA;
+			if ( flags & FIP_SP )
+				fcoe->flags |= FCOE_FCF_ALLOWS_SPMA;
+			memcpy ( fcoe->fcf_mac, mac_address->mac,
+				 sizeof ( fcoe->fcf_mac ) );
+			DBGC ( fcoe, "FCoE %s selected FCF %s (pri %d",
+			       fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
+			       fcoe->priority );
+			if ( fcoe->keepalive ) {
+				DBGC ( fcoe, ", FKA ADV %dms",
+				       fcoe->keepalive );
+			}
+			DBGC ( fcoe, ", %cPMA)\n",
+			       ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
+				 'S' : 'F' ) );
+		}
+
+	} else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
+
+		/* We are checking that the FCF remains alive.  Reset
+		 * the timeout counter if this is an advertisement
+		 * from our forwarder.
+		 */
+		if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
+			      sizeof ( fcoe->fcf_mac ) ) == 0 ) {
+			fcoe->timeouts = 0;
+		}
+
+	} else {
+
+		/* We are operating in non-FIP mode and have received
+		 * a FIP advertisement.  Reset the link in order to
+		 * attempt FIP.
+		 */
+		fcoe_reset ( fcoe );
+
+	}
+
+	return 0;
+}
+
+/**
+ * Handle received FIP ELS response
+ *
+ * @v fcoe		FCoE port
+ * @v descs		Descriptor list
+ * @v flags		Flags
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe,
+				      struct fip_descriptors *descs,
+				      unsigned int flags __unused ) {
+	struct fip_els *flogi = fip_flogi ( descs );
+	struct fip_mac_address *mac_address = fip_mac_address ( descs );
+	void *frame;
+	size_t frame_len;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! flogi ) {
+		DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
+		       fcoe->netdev->name );
+		return -EINVAL;
+	}
+	if ( ! mac_address ) {
+		DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
+		       "address\n", fcoe->netdev->name );
+		return -EINVAL;
+	}
+
+	/* Record local MAC address */
+	memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac ));
+	DBGC ( fcoe, "FCoE %s using local MAC %s\n",
+	       fcoe->netdev->name, eth_ntoa ( fcoe->local_mac ) );
+
+	/* Hand off via transport interface */
+	frame = &flogi->fc;
+	frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) );
+	if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame,
+				       frame_len ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n",
+		       fcoe->netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Send FIP keepalive
+ *
+ * @v fcoe		FCoE port
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
+	struct io_buffer *iobuf;
+	struct {
+		struct fip_header hdr;
+		struct fip_mac_address mac_address;
+	} __attribute__ (( packed )) *keepalive;
+	int rc;
+
+	/* Allocate I/O buffer */
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+
+	/* Construct keepalive */
+	keepalive = iob_put ( iobuf, sizeof ( *keepalive ) );
+	memset ( keepalive, 0, sizeof ( *keepalive ) );
+	keepalive->hdr.version = FIP_VERSION;
+	keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN );
+	keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE;
+	keepalive->hdr.len =	htons ( ( sizeof ( *keepalive ) -
+					  sizeof ( keepalive->hdr ) ) / 4 );
+	keepalive->mac_address.type = FIP_MAC_ADDRESS;
+	keepalive->mac_address.len =
+		( sizeof ( keepalive->mac_address ) / 4 );
+	memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr,
+		 sizeof ( keepalive->mac_address.mac ) );
+
+	/* Send keepalive */
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
+			     &fip_protocol, fcoe->fcf_mac,
+			     fcoe->netdev->ll_addr ) ) != 0 ) {
+		DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n",
+		       fcoe->netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** A FIP handler */
+struct fip_handler {
+	/** Protocol code */
+	uint16_t code;
+	/** Protocol subcode */
+	uint8_t subcode;
+	/**
+	 * Receive FIP packet
+	 *
+	 * @v fcoe		FCoE port
+	 * @v descs		Descriptor list
+	 * @v flags		Flags
+	 * @ret rc		Return status code
+	 */
+	int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
+		       unsigned int flags );
+};
+
+/** FIP handlers */
+static struct fip_handler fip_handlers[] = {
+	{ FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
+	  fcoe_fip_rx_vlan },
+	{ FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
+	  fcoe_fip_rx_advertisement },
+	{ FIP_CODE_ELS, FIP_ELS_RESPONSE,
+	  fcoe_fip_rx_els_response },
+};
+
+/**
+ * Process incoming FIP packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int fcoe_fip_rx ( struct io_buffer *iobuf,
+			 struct net_device *netdev,
+			 const void *ll_dest,
+			 const void *ll_source __unused ) {
+	struct fip_header *fiphdr = iobuf->data;
+	struct fip_descriptors descs;
+	struct fip_handler *handler;
+	struct fcoe_port *fcoe;
+	unsigned int i;
+	int rc;
+
+	/* Identify FCoE port */
+	if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
+		DBG ( "FCoE received FIP frame for net device %s missing FCoE "
+		      "port\n", netdev->name );
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	/* Discard packets not destined for us */
+	if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) &&
+	     ( memcmp ( all_fcoe_macs, ll_dest,
+			sizeof ( all_fcoe_macs ) ) != 0 ) &&
+	     ( memcmp ( all_enode_macs, ll_dest,
+			sizeof ( all_enode_macs ) ) != 0 ) ) {
+		DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n",
+			fcoe->netdev->name, eth_ntoa ( ll_dest ) );
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	/* Parse FIP packet */
+	if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
+				     &descs ) ) != 0 )
+		goto done;
+
+	/* Find a suitable handler */
+	for ( i = 0 ; i < ( sizeof ( fip_handlers ) /
+			    sizeof ( fip_handlers[0] ) ) ; i++ ) {
+		handler = &fip_handlers[i];
+		if ( ( handler->code == ntohs ( fiphdr->code ) ) &&
+		     ( handler->subcode == fiphdr->subcode ) ) {
+			rc = handler->rx ( fcoe, &descs,
+					   ntohs ( fiphdr->flags ) );
+			goto done;
+		}
+	}
+	DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
+	       fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
+	rc = -ENOTSUP;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * FCoE ports
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Handle FCoE timer expiry
+ *
+ * @v timer		FIP timer
+ * @v over		Timer expired
+ */
+static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
+	struct fcoe_port *fcoe =
+		container_of ( timer, struct fcoe_port, timer );
+	int rc;
+
+	/* Sanity check */
+	assert ( fcoe->flags & FCOE_HAVE_NETWORK );
+
+	/* Increment the timeout counter */
+	fcoe->timeouts++;
+
+	if ( vlan_can_be_trunk ( fcoe->netdev ) &
+	     ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
+
+		/* If we have already found a VLAN, send infrequent
+		 * VLAN requests, in case VLAN information changes.
+		 */
+		if ( fcoe->flags & FCOE_VLAN_FOUND ) {
+			fcoe->flags &= ~FCOE_VLAN_FOUND;
+			fcoe->timeouts = 0;
+			start_timer_fixed ( &fcoe->timer,
+					    FCOE_VLAN_POLL_DELAY );
+			fcoe_fip_tx_vlan ( fcoe );
+			return;
+		}
+
+		/* If we have not yet found a VLAN, and we have not
+		 * yet timed out and given up on finding one, then
+		 * send a VLAN request and wait.
+		 */
+		if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
+			start_timer_fixed ( &fcoe->timer,
+					    FCOE_VLAN_RETRY_DELAY );
+			fcoe_fip_tx_vlan ( fcoe );
+			return;
+		}
+
+		/* We have timed out waiting for a VLAN; proceed to
+		 * FIP discovery.
+		 */
+		fcoe->flags |= FCOE_VLAN_TIMED_OUT;
+		fcoe->timeouts = 0;
+		DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
+		       fcoe->netdev->name );
+		start_timer_nodelay ( &fcoe->timer );
+
+	} else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
+
+		/* If we have not yet found a FIP-capable forwarder,
+		 * and we have not yet timed out and given up on
+		 * finding one, then send a FIP solicitation and wait.
+		 */
+		start_timer_fixed ( &fcoe->timer, FCOE_FIP_RETRY_DELAY );
+		if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
+		     ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
+			fcoe_fip_tx_solicitation ( fcoe );
+			return;
+		}
+
+		/* Attach Fibre Channel port */
+		if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
+					   &fcoe->port_wwn.fc,
+					   fcoe->netdev->name ) ) != 0 ) {
+			DBGC ( fcoe, "FCoE %s could not create FC port: %s\n",
+			       fcoe->netdev->name, strerror ( rc ) );
+			/* We will try again on the next timer expiry */
+			return;
+		}
+		stop_timer ( &fcoe->timer );
+
+		/* Either we have found a FIP-capable forwarder, or we
+		 * have timed out and will fall back to pre-FIP mode.
+		 */
+		fcoe->flags |= FCOE_HAVE_FCF;
+		fcoe->timeouts = 0;
+		DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name,
+		       ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ),
+		       eth_ntoa ( fcoe->fcf_mac ) );
+
+		/* Start sending keepalives if applicable */
+		if ( fcoe->keepalive )
+			start_timer_nodelay ( &fcoe->timer );
+
+		/* Send notification of window change */
+		xfer_window_changed ( &fcoe->transport );
+
+	} else {
+
+		/* Send keepalive */
+		start_timer_fixed ( &fcoe->timer,
+			      ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
+		fcoe_fip_tx_keepalive ( fcoe );
+
+		/* Abandon FCF if we have not seen its advertisements */
+		if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) {
+			DBGC ( fcoe, "FCoE %s abandoning FCF %s\n",
+			       fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ));
+			fcoe_reset ( fcoe );
+		}
+	}
+}
+
+/**
+ * Create FCoE port
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int fcoe_probe ( struct net_device *netdev ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct fcoe_port *fcoe;
+	int rc;
+
+	/* Sanity check */
+	if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) {
+		/* Not an error; simply skip this net device */
+		DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name );
+		rc = 0;
+		goto err_non_ethernet;
+	}
+
+	/* Allocate and initialise structure */
+	fcoe = zalloc ( sizeof ( *fcoe ) );
+	if ( ! fcoe ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &fcoe->refcnt, NULL );
+	intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt );
+	timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt );
+	fcoe->netdev = netdev_get ( netdev );
+
+	/* Construct node and port names */
+	fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
+	memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr,
+		 sizeof ( fcoe->node_wwn.fcoe.mac ) );
+	fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
+	memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr,
+		 sizeof ( fcoe->port_wwn.fcoe.mac ) );
+
+	DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name,
+	       fc_ntoa ( &fcoe->node_wwn.fc ) );
+	DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
+
+	/* Transfer reference to port list */
+	list_add ( &fcoe->list, &fcoe_ports );
+	return 0;
+
+	netdev_put ( fcoe->netdev );
+ err_zalloc:
+ err_non_ethernet:
+	return rc;
+}
+
+/**
+ * Handle FCoE port device or link state change
+ *
+ * @v netdev		Network device
+ */
+static void fcoe_notify ( struct net_device *netdev ) {
+	struct fcoe_port *fcoe;
+
+	/* Sanity check */
+	if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
+		DBG ( "FCoE notification for net device %s missing FCoE "
+		      "port\n", netdev->name );
+		return;
+	}
+
+	/* Reset the FCoE link if necessary */
+	if ( ! ( netdev_is_open ( netdev ) &&
+		 netdev_link_ok ( netdev ) &&
+		 ( fcoe->flags & FCOE_HAVE_NETWORK ) ) ) {
+		fcoe_reset ( fcoe );
+	}
+}
+
+/**
+ * Destroy FCoE port
+ *
+ * @v netdev		Network device
+ */
+static void fcoe_remove ( struct net_device *netdev ) {
+	struct fcoe_port *fcoe;
+
+	/* Sanity check */
+	if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
+		DBG ( "FCoE removal of net device %s missing FCoE port\n",
+		      netdev->name );
+		return;
+	}
+
+	/* Close FCoE device */
+	fcoe_close ( fcoe, 0 );
+}
+
+/** FCoE driver */
+struct net_driver fcoe_driver __net_driver = {
+	.name = "FCoE",
+	.probe = fcoe_probe,
+	.notify = fcoe_notify,
+	.remove = fcoe_remove,
+};
+
+/** FCoE protocol */
+struct net_protocol fcoe_protocol __net_protocol = {
+	.name = "FCoE",
+	.net_proto = htons ( ETH_P_FCOE ),
+	.rx = fcoe_rx,
+};
+
+/** FIP protocol */
+struct net_protocol fip_protocol __net_protocol = {
+	.name = "FIP",
+	.net_proto = htons ( ETH_P_FIP ),
+	.rx = fcoe_fip_rx,
+};
+
+/** Human-readable message for CRC errors
+ *
+ * It seems as though several drivers neglect to strip the Ethernet
+ * CRC, which will cause the FCoE footer to be misplaced and result
+ * (coincidentally) in an "invalid CRC" error from FCoE.
+ */
+struct errortab fcoe_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EINVAL_CRC ),
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/fcp.c b/qemu-0.15.x/roms/ipxe/src/net/fcp.c
new file mode 100644
index 0000000..40cd057
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/fcp.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/open.h>
+#include <ipxe/process.h>
+#include <ipxe/uri.h>
+#include <ipxe/acpi.h>
+#include <ipxe/scsi.h>
+#include <ipxe/device.h>
+#include <ipxe/edd.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/fcp.h>
+
+/** @file
+ *
+ * Fibre Channel Protocol
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define ERANGE_READ_DATA_ORDERING \
+	__einfo_error ( EINFO_ERANGE_READ_DATA_ORDERING )
+#define EINFO_ERANGE_READ_DATA_ORDERING \
+	__einfo_uniqify ( EINFO_ERANGE, 0x01, "Read data out of order" )
+#define ERANGE_READ_DATA_OVERRUN \
+	__einfo_error ( EINFO_ERANGE_READ_DATA_OVERRUN )
+#define EINFO_ERANGE_READ_DATA_OVERRUN \
+	__einfo_uniqify ( EINFO_ERANGE, 0x02, "Read data overrun" )
+#define ERANGE_WRITE_DATA_STUCK \
+	__einfo_error ( EINFO_ERANGE_WRITE_DATA_STUCK )
+#define EINFO_ERANGE_WRITE_DATA_STUCK \
+	__einfo_uniqify ( EINFO_ERANGE, 0x03, "Write data stuck" )
+#define ERANGE_WRITE_DATA_OVERRUN \
+	__einfo_error ( EINFO_ERANGE_WRITE_DATA_OVERRUN )
+#define EINFO_ERANGE_WRITE_DATA_OVERRUN \
+	__einfo_uniqify ( EINFO_ERANGE, 0x04, "Write data overrun" )
+#define ERANGE_DATA_UNDERRUN \
+	__einfo_error ( EINFO_ERANGE_DATA_UNDERRUN )
+#define EINFO_ERANGE_DATA_UNDERRUN \
+	__einfo_uniqify ( EINFO_ERANGE, 0x05, "Data underrun" )
+
+/******************************************************************************
+ *
+ * PRLI
+ *
+ ******************************************************************************
+ */
+
+struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor;
+
+/**
+ * Transmit FCP PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @ret rc		Return status code
+ */
+static int fcp_prli_tx ( struct fc_els *els ) {
+	struct fcp_prli_service_parameters param;
+
+	/* Build service parameter page */
+	memset ( &param, 0, sizeof ( param ) );
+	param.flags = htonl ( FCP_PRLI_NO_READ_RDY | FCP_PRLI_INITIATOR );
+
+	return fc_els_prli_tx ( els, &fcp_prli_descriptor, &param );
+}
+
+/**
+ * Receive FCP PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v frame		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fcp_prli_rx ( struct fc_els *els, void *data, size_t len ) {
+	return fc_els_prli_rx ( els, &fcp_prli_descriptor, data, len );
+}
+
+/**
+ * Detect FCP PRLI
+ *
+ * @v els		Fibre Channel ELS transaction
+ * @v data		ELS frame
+ * @v len		Length of ELS frame
+ * @ret rc		Return status code
+ */
+static int fcp_prli_detect ( struct fc_els *els, const void *data,
+			     size_t len ) {
+	return fc_els_prli_detect ( els, &fcp_prli_descriptor, data, len );
+}
+
+/** FCP PRLI ELS handler */
+struct fc_els_handler fcp_prli_handler __fc_els_handler = {
+	.name		= "PRLI-FCP",
+	.tx		= fcp_prli_tx,
+	.rx		= fcp_prli_rx,
+	.detect		= fcp_prli_detect,
+};
+
+/** FCP PRLI descriptor */
+struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = {
+	.type		= FC_TYPE_FCP,
+	.param_len	= sizeof ( struct fcp_prli_service_parameters ),
+	.handler	= &fcp_prli_handler,
+};
+
+/******************************************************************************
+ *
+ * FCP devices and commands
+ *
+ ******************************************************************************
+ */
+
+/** An FCP device */
+struct fcp_device {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Fibre Channel upper-layer protocol */
+	struct fc_ulp *ulp;
+	/** SCSI command issuing interface */
+	struct interface scsi;
+	/** List of active commands */
+	struct list_head fcpcmds;
+
+	/** Fibre Channel WWN (for boot firmware table) */
+	struct fc_name wwn;
+	/** SCSI LUN (for boot firmware table) */
+	struct scsi_lun lun;
+};
+
+/** An FCP command */
+struct fcp_command {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** FCP SCSI device */
+	struct fcp_device *fcpdev;
+	/** List of active commands */
+	struct list_head list;
+	/** SCSI command interface */
+	struct interface scsi;
+	/** Fibre Channel exchange interface */
+	struct interface xchg;
+	/** Send process */
+	struct process process;
+	/** Send current IU
+	 *
+	 * @v fcpcmd	FCP command
+	 * @ret rc	Return status code
+	 */
+	int ( * send ) ( struct fcp_command *fcpcmd );
+	/** SCSI command */
+	struct scsi_cmd command;
+	/** Data offset within command */
+	size_t offset;
+	/** Length of data remaining to be sent within this IU */
+	size_t remaining;
+	/** Exchange ID */
+	uint16_t xchg_id;
+};
+
+/**
+ * Get reference to FCP device
+ *
+ * @v fcpdev		FCP device
+ * @ret fcpdev		FCP device
+ */
+static inline __attribute__ (( always_inline )) struct fcp_device *
+fcpdev_get ( struct fcp_device *fcpdev ) {
+	ref_get ( &fcpdev->refcnt );
+	return fcpdev;
+}
+
+/**
+ * Drop reference to FCP device
+ *
+ * @v fcpdev		FCP device
+ */
+static inline __attribute__ (( always_inline )) void
+fcpdev_put ( struct fcp_device *fcpdev ) {
+	ref_put ( &fcpdev->refcnt );
+}
+
+/**
+ * Get reference to FCP command
+ *
+ * @v fcpcmd		FCP command
+ * @ret fcpcmd		FCP command
+ */
+static inline __attribute__ (( always_inline )) struct fcp_command *
+fcpcmd_get ( struct fcp_command *fcpcmd ) {
+	ref_get ( &fcpcmd->refcnt );
+	return fcpcmd;
+}
+
+/**
+ * Drop reference to FCP command
+ *
+ * @v fcpcmd		FCP command
+ */
+static inline __attribute__ (( always_inline )) void
+fcpcmd_put ( struct fcp_command *fcpcmd ) {
+	ref_put ( &fcpcmd->refcnt );
+}
+
+/**
+ * Start FCP command sending
+ *
+ * @v fcpcmd		FCP command
+ * @v send		Send method
+ */
+static inline __attribute__ (( always_inline )) void
+fcpcmd_start_send ( struct fcp_command *fcpcmd,
+		    int ( * send ) ( struct fcp_command *fcpcmd ) ) {
+	fcpcmd->send = send;
+	process_add ( &fcpcmd->process );
+}
+
+/**
+ * Stop FCP command sending
+ *
+ * @v fcpcmd		FCP command
+ */
+static inline __attribute__ (( always_inline )) void
+fcpcmd_stop_send ( struct fcp_command *fcpcmd ) {
+	process_del ( &fcpcmd->process );
+}
+
+/**
+ * Free FCP command
+ *
+ * @v refcnt		Reference count
+ */
+static void fcpcmd_free ( struct refcnt *refcnt ) {
+	struct fcp_command *fcpcmd =
+		container_of ( refcnt, struct fcp_command, refcnt );
+
+	/* Remove from list of commands */
+	list_del ( &fcpcmd->list );
+	fcpdev_put ( fcpcmd->fcpdev );
+
+	/* Free command */
+	free ( fcpcmd );
+}
+
+/**
+ * Close FCP command
+ *
+ * @v fcpcmd		FCP command
+ * @v rc		Reason for close
+ */
+static void fcpcmd_close ( struct fcp_command *fcpcmd, int rc ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+
+	if ( rc != 0 ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x closed: %s\n",
+		       fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
+	}
+
+	/* Stop sending */
+	fcpcmd_stop_send ( fcpcmd );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &fcpcmd->scsi, rc );
+	intf_shutdown ( &fcpcmd->xchg, rc );
+}
+
+/**
+ * Close FCP command in error
+ *
+ * @v fcpcmd		FCP command
+ * @v rc		Reason for close
+ */
+static void fcpcmd_close_err ( struct fcp_command *fcpcmd, int rc ) {
+	if ( rc == 0 )
+		rc = -EPIPE;
+	fcpcmd_close ( fcpcmd, rc );
+}
+
+/**
+ * Send FCP command IU
+ *
+ * @v fcpcmd		FCP command
+ * @ret rc		Return status code
+ */
+static int fcpcmd_send_cmnd ( struct fcp_command *fcpcmd ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+	struct scsi_cmd *command = &fcpcmd->command;
+	struct io_buffer *iobuf;
+	struct fcp_cmnd *cmnd;
+	struct xfer_metadata meta;
+	int rc;
+
+	/* Sanity check */
+	if ( command->data_in_len && command->data_out_len ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot handle bidirectional "
+		       "command\n", fcpdev, fcpcmd->xchg_id );
+		return -ENOTSUP;
+	}
+
+	/* Allocate I/O buffer */
+	iobuf = xfer_alloc_iob ( &fcpcmd->xchg, sizeof ( *cmnd ) );
+	if ( ! iobuf ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate command IU\n",
+		       fcpdev, fcpcmd->xchg_id );
+		return -ENOMEM;
+	}
+
+	/* Construct command IU frame */
+	cmnd = iob_put ( iobuf, sizeof ( *cmnd ) );
+	memset ( cmnd, 0, sizeof ( *cmnd ) );
+	memcpy ( &cmnd->lun, &command->lun, sizeof ( cmnd->lun ) );
+	assert ( ! ( command->data_in_len && command->data_out_len ) );
+	if ( command->data_in_len )
+		cmnd->dirn |= FCP_CMND_RDDATA;
+	if ( command->data_out_len )
+		cmnd->dirn |= FCP_CMND_WRDATA;
+	memcpy ( &cmnd->cdb, &fcpcmd->command.cdb, sizeof ( cmnd->cdb ) );
+	cmnd->len = htonl ( command->data_in_len + command->data_out_len );
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = ( XFER_FL_CMD_STAT | XFER_FL_OVER );
+	DBGC2 ( fcpdev, "FCP %p xchg %04x CMND " SCSI_CDB_FORMAT " %04x\n",
+		fcpdev, fcpcmd->xchg_id, SCSI_CDB_DATA ( cmnd->cdb ),
+		ntohl ( cmnd->len ) );
+
+	/* No further data to send within this IU */
+	fcpcmd_stop_send ( fcpcmd );
+
+	/* Send command IU frame */
+	if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
+				   &meta ) ) != 0 ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver command IU: "
+		       "%s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle FCP read data IU
+ *
+ * @v fcpcmd		FCP command
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcpcmd_recv_rddata ( struct fcp_command *fcpcmd,
+				struct io_buffer *iobuf,
+				struct xfer_metadata *meta ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+	struct scsi_cmd *command = &fcpcmd->command;
+	size_t offset = meta->offset;
+	size_t len = iob_len ( iobuf );
+	int rc;
+
+	/* Sanity checks */
+	if ( ! ( meta->flags & XFER_FL_ABS_OFFSET ) ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x read data missing offset\n",
+		       fcpdev, fcpcmd->xchg_id );
+		rc = -ERANGE_READ_DATA_ORDERING;
+		goto done;
+	}
+	if ( offset != fcpcmd->offset ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x read data out of order "
+		       "(expected %zd, received %zd)\n",
+		       fcpdev, fcpcmd->xchg_id, fcpcmd->offset, offset );
+		rc = -ERANGE_READ_DATA_ORDERING;
+		goto done;
+	}
+	if ( ( offset + len ) > command->data_in_len ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x read data overrun (max %zd, "
+		       "received %zd)\n", fcpdev, fcpcmd->xchg_id,
+		       command->data_in_len, ( offset + len ) );
+		rc = -ERANGE_READ_DATA_OVERRUN;
+		goto done;
+	}
+	DBGC2 ( fcpdev, "FCP %p xchg %04x RDDATA [%08zx,%08zx)\n",
+		fcpdev, fcpcmd->xchg_id, offset, ( offset + len ) );
+
+	/* Copy to user buffer */
+	copy_to_user ( command->data_in, offset, iobuf->data, len );
+	fcpcmd->offset += len;
+	assert ( fcpcmd->offset <= command->data_in_len );
+
+	rc = 0;
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Send FCP write data IU
+ *
+ * @v fcpcmd		FCP command
+ * @ret rc		Return status code
+ */
+static int fcpcmd_send_wrdata ( struct fcp_command *fcpcmd ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+	struct scsi_cmd *command = &fcpcmd->command;
+	struct io_buffer *iobuf;
+	struct xfer_metadata meta;
+	size_t len;
+	int rc;
+
+	/* Calculate length to be sent */
+	len = xfer_window ( &fcpcmd->xchg );
+	if ( len > fcpcmd->remaining )
+		len = fcpcmd->remaining;
+
+	/* Sanity checks */
+	if ( len == 0 ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x write data stuck\n",
+		       fcpdev, fcpcmd->xchg_id );
+		return -ERANGE_WRITE_DATA_STUCK;
+	}
+	if ( ( fcpcmd->offset + len ) > command->data_out_len ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x write data overrun (max %zd, "
+		       "requested %zd)\n", fcpdev, fcpcmd->xchg_id,
+		       command->data_out_len, ( fcpcmd->offset + len ) );
+		return -ERANGE_WRITE_DATA_OVERRUN;
+	}
+
+	/* Allocate I/O buffer */
+	iobuf = xfer_alloc_iob ( &fcpcmd->xchg, len );
+	if ( ! iobuf ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot allocate write data "
+		       "IU for %zd bytes\n", fcpdev, fcpcmd->xchg_id, len );
+		return -ENOMEM;
+	}
+
+	/* Construct data IU frame */
+	copy_from_user ( iob_put ( iobuf, len ), command->data_out,
+			 fcpcmd->offset, len );
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = ( XFER_FL_RESPONSE | XFER_FL_ABS_OFFSET );
+	meta.offset = fcpcmd->offset;
+	DBGC2 ( fcpdev, "FCP %p xchg %04x WRDATA [%08zx,%04zx)\n",
+		fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
+		( fcpcmd->offset + iob_len ( iobuf ) ) );
+
+	/* Calculate amount of data remaining to be sent within this IU */
+	assert ( len <= fcpcmd->remaining );
+	fcpcmd->offset += len;
+	fcpcmd->remaining -= len;
+	assert ( fcpcmd->offset <= command->data_out_len );
+	if ( fcpcmd->remaining == 0 ) {
+		fcpcmd_stop_send ( fcpcmd );
+		meta.flags |= XFER_FL_OVER;
+	}
+
+	/* Send data IU frame */
+	if ( ( rc = xfer_deliver ( &fcpcmd->xchg, iob_disown ( iobuf ),
+				   &meta ) ) != 0 ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot deliver write data "
+		       "IU: %s\n", fcpdev, fcpcmd->xchg_id, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle FCP transfer ready IU
+ *
+ * @v fcpcmd		FCP command
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcpcmd_recv_xfer_rdy ( struct fcp_command *fcpcmd,
+				  struct io_buffer *iobuf,
+				  struct xfer_metadata *meta __unused ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+	struct fcp_xfer_rdy *xfer_rdy = iobuf->data;
+	int rc;
+
+	/* Sanity checks */
+	if ( iob_len ( iobuf ) != sizeof ( *xfer_rdy ) ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x received invalid transfer "
+		       "ready IU:\n", fcpdev, fcpcmd->xchg_id );
+		DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
+		rc = -EPROTO;
+		goto done;
+	}
+	if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) {
+		/* We do not advertise out-of-order delivery */
+		DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order "
+		       "delivery (expected %zd, requested %d)\n",
+		       fcpdev, fcpcmd->xchg_id, fcpcmd->offset,
+		       ntohl ( xfer_rdy->offset ) );
+		rc = -EPROTO;
+		goto done;
+	}
+	DBGC2 ( fcpdev, "FCP %p xchg %04x XFER_RDY [%08x,%08x)\n",
+		fcpdev, fcpcmd->xchg_id, ntohl ( xfer_rdy->offset ),
+		( ntohl ( xfer_rdy->offset ) + ntohl ( xfer_rdy->len ) ) );
+
+	/* Start sending requested data */
+	fcpcmd->remaining = ntohl ( xfer_rdy->len );
+	fcpcmd_start_send ( fcpcmd, fcpcmd_send_wrdata );
+
+	rc = 0;
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Handle FCP response IU
+ *
+ * @v fcpcmd		FCP command
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
+			     struct io_buffer *iobuf,
+			     struct xfer_metadata *meta __unused ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+	struct scsi_cmd *command = &fcpcmd->command;
+	struct fcp_rsp *rsp = iobuf->data;
+	struct scsi_sense *sense;
+	struct scsi_rsp response;
+	int rc;
+
+	/* Sanity check */
+	if ( ( iob_len ( iobuf ) < sizeof ( *rsp ) ) ||
+	     ( iob_len ( iobuf ) < ( sizeof ( *rsp ) +
+				     fcp_rsp_response_data_len ( rsp ) +
+				     fcp_rsp_sense_data_len ( rsp ) ) ) ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x received invalid response "
+		       "IU:\n", fcpdev, fcpcmd->xchg_id );
+		DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
+		rc = -EPROTO;
+		goto done;
+	}
+	DBGC2 ( fcpdev, "FCP %p xchg %04x RSP stat %02x resid %08x flags %02x"
+		"%s%s%s%s\n", fcpdev, fcpcmd->xchg_id, rsp->status,
+		ntohl ( rsp->residual ), rsp->flags,
+		( ( rsp->flags & FCP_RSP_RESPONSE_LEN_VALID ) ? " resp" : "" ),
+		( ( rsp->flags & FCP_RSP_SENSE_LEN_VALID ) ? " sense" : "" ),
+		( ( rsp->flags & FCP_RSP_RESIDUAL_OVERRUN ) ? " over" : "" ),
+		( ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) ? " under" : "" ));
+	if ( fcp_rsp_response_data ( rsp ) ) {
+		DBGC2 ( fcpdev, "FCP %p xchg %04x response data:\n",
+			fcpdev, fcpcmd->xchg_id );
+		DBGC2_HDA ( fcpdev, 0, fcp_rsp_response_data ( rsp ),
+			    fcp_rsp_response_data_len ( rsp ) );
+	}
+	if ( fcp_rsp_sense_data ( rsp ) ) {
+		DBGC2 ( fcpdev, "FCP %p xchg %04x sense data:\n",
+			fcpdev, fcpcmd->xchg_id );
+		DBGC2_HDA ( fcpdev, 0, fcp_rsp_sense_data ( rsp ),
+			    fcp_rsp_sense_data_len ( rsp ) );
+	}
+
+	/* Check for locally-detected command underrun */
+	if ( ( rsp->status == 0 ) &&
+	     ( fcpcmd->offset != ( command->data_in_len +
+				   command->data_out_len ) ) ) {
+		DBGC ( fcpdev, "FCP %p xchg %04x data underrun (expected %zd, "
+		       "got %zd)\n", fcpdev, fcpcmd->xchg_id,
+		       ( command->data_in_len + command->data_out_len ),
+		       fcpcmd->offset );
+		rc = -ERANGE_DATA_UNDERRUN;
+		goto done;
+	}
+
+	/* Build SCSI response */
+	memset ( &response, 0, sizeof ( response ) );
+	response.status = rsp->status;
+	if ( rsp->flags & ( FCP_RSP_RESIDUAL_OVERRUN |
+			    FCP_RSP_RESIDUAL_UNDERRUN ) ) {
+		response.overrun = ntohl ( rsp->residual );
+		if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN )
+			response.overrun = -response.overrun;
+	}
+	if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL )
+		memcpy ( &response.sense, sense, sizeof ( response.sense ) );
+
+	/* Free buffer before sending response, to minimise
+	 * out-of-memory errors.
+	 */
+	free_iob ( iob_disown ( iobuf ) );
+
+	/* Send SCSI response */
+	scsi_response ( &fcpcmd->scsi, &response );
+
+	/* Terminate command */
+	fcpcmd_close ( fcpcmd, 0 );
+
+	rc = 0;
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Handle unknown FCP IU
+ *
+ * @v fcpcmd		FCP command
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta __unused ) {
+	struct fcp_device *fcpdev = fcpcmd->fcpdev;
+
+	DBGC ( fcpdev, "FCP %p xchg %04x received unknown IU:\n",
+	       fcpdev, fcpcmd->xchg_id );
+	DBGC_HDA ( fcpdev, 0, iobuf->data, iob_len ( iobuf ) );
+	free_iob ( iobuf );
+	return -EPROTO;
+}
+
+/**
+ * Transmit FCP frame
+ *
+ * @v process		FCP command process
+ */
+static void fcpcmd_step ( struct process *process ) {
+	struct fcp_command *fcpcmd =
+		container_of ( process, struct fcp_command, process );
+	int rc;
+
+	/* Send the current IU */
+	if ( ( rc = fcpcmd->send ( fcpcmd ) ) != 0 ) {
+		/* Treat failure as a fatal error */
+		fcpcmd_close ( fcpcmd, rc );
+	}
+}
+
+/**
+ * Receive FCP frame
+ *
+ * @v fcpcmd		FCP command
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int fcpcmd_deliver ( struct fcp_command *fcpcmd,
+			    struct io_buffer *iobuf,
+			    struct xfer_metadata *meta ) {
+	int ( * fcpcmd_recv ) ( struct fcp_command *fcpcmd,
+				struct io_buffer *iobuf,
+				struct xfer_metadata *meta );
+	int rc;
+
+	/* Determine handler */
+	switch ( meta->flags & ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
+	case ( XFER_FL_RESPONSE ) :
+		fcpcmd_recv = fcpcmd_recv_rddata;
+		break;
+	case ( XFER_FL_CMD_STAT ) :
+		fcpcmd_recv = fcpcmd_recv_xfer_rdy;
+		break;
+	case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) :
+		fcpcmd_recv = fcpcmd_recv_rsp;
+		break;
+	default:
+		fcpcmd_recv = fcpcmd_recv_unknown;
+		break;
+	}
+
+	/* Handle IU */
+	if ( ( rc = fcpcmd_recv ( fcpcmd, iob_disown ( iobuf ), meta ) ) != 0 ){
+		/* Treat any error as fatal to the command */
+		fcpcmd_close ( fcpcmd, rc );
+	}
+
+	return rc;
+}
+
+/** FCP command SCSI interface operations */
+static struct interface_operation fcpcmd_scsi_op[] = {
+	INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close ),
+};
+
+/** FCP command SCSI interface descriptor */
+static struct interface_descriptor fcpcmd_scsi_desc =
+	INTF_DESC_PASSTHRU ( struct fcp_command, scsi, fcpcmd_scsi_op, xchg );
+
+/** FCP command Fibre Channel exchange interface operations */
+static struct interface_operation fcpcmd_xchg_op[] = {
+	INTF_OP ( xfer_deliver, struct fcp_command *, fcpcmd_deliver ),
+	INTF_OP ( intf_close, struct fcp_command *, fcpcmd_close_err ),
+};
+
+/** FCP command Fibre Channel exchange interface descriptor */
+static struct interface_descriptor fcpcmd_xchg_desc =
+	INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi );
+
+/**
+ * Issue FCP SCSI command
+ *
+ * @v fcpdev		FCP device
+ * @v parent		Parent interface
+ * @v command		SCSI command
+ * @ret tag		Command tag, or negative error
+ */
+static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
+				 struct interface *parent,
+				 struct scsi_cmd *command ) {
+	struct fcp_prli_service_parameters *param = fcpdev->ulp->param;
+	struct fcp_command *fcpcmd;
+	int xchg_id;
+	int rc;
+
+	/* Check link */
+	if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) {
+		DBGC ( fcpdev, "FCP %p could not issue command while link is "
+		       "down: %s\n", fcpdev, strerror ( rc ) );
+		goto err_link;
+	}
+
+	/* Check target capability */
+	assert ( param != NULL );
+	assert ( fcpdev->ulp->param_len >= sizeof ( *param ) );
+	if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) {
+		DBGC ( fcpdev, "FCP %p could not issue command: not a target\n",
+		       fcpdev );
+		rc = -ENOTTY;
+		goto err_target;
+	}
+
+	/* Allocate and initialise structure */
+	fcpcmd = zalloc ( sizeof ( *fcpcmd ) );
+	if ( ! fcpcmd ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &fcpcmd->refcnt, fcpcmd_free );
+	intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt );
+	intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt );
+	process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt );
+	fcpcmd->fcpdev = fcpdev_get ( fcpdev );
+	list_add ( &fcpcmd->list, &fcpdev->fcpcmds );
+	memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) );
+
+	/* Create new exchange */
+	if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg,
+					     fcpdev->ulp->peer->port,
+					     &fcpdev->ulp->peer->port_id,
+					     FC_TYPE_FCP ) ) < 0 ) {
+		rc = xchg_id;
+		DBGC ( fcpdev, "FCP %p could not create exchange: %s\n",
+		       fcpdev, strerror ( rc ) );
+		goto err_xchg_originate;
+	}
+	fcpcmd->xchg_id = xchg_id;
+
+	/* Start sending command IU */
+	fcpcmd_start_send ( fcpcmd, fcpcmd_send_cmnd );
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &fcpcmd->scsi, parent );
+	ref_put ( &fcpcmd->refcnt );
+	return ( FCP_TAG_MAGIC | fcpcmd->xchg_id );
+
+ err_xchg_originate:
+	fcpcmd_close ( fcpcmd, rc );
+	ref_put ( &fcpcmd->refcnt );
+ err_zalloc:
+ err_target:
+ err_link:
+	return rc;
+}
+
+/**
+ * Close FCP device
+ *
+ * @v fcpdev		FCP device
+ * @v rc		Reason for close
+ */
+static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
+	struct fcp_command *fcpcmd;
+	struct fcp_command *tmp;
+
+	DBGC ( fcpdev, "FCP %p closed: %s\n", fcpdev, strerror ( rc ) );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &fcpdev->scsi, rc );
+
+	/* Shut down any active commands */
+	list_for_each_entry_safe ( fcpcmd, tmp, &fcpdev->fcpcmds, list ) {
+		fcpcmd_get ( fcpcmd );
+		fcpcmd_close ( fcpcmd, rc );
+		fcpcmd_put ( fcpcmd );
+	}
+
+	/* Drop reference to ULP */
+	if ( fcpdev->ulp ) {
+		fc_ulp_decrement ( fcpdev->ulp );
+		fc_ulp_put ( fcpdev->ulp );
+		fcpdev->ulp = NULL;
+	}
+}
+
+/**
+ * Check FCP device flow-control window
+ *
+ * @v fcpdev		FCP device
+ * @ret len		Length of window
+ */
+static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
+	return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 );
+}
+
+/**
+ * Describe FCP device in an ACPI table
+ *
+ * @v fcpdev		FCP device
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+static int fcpdev_acpi_describe ( struct fcp_device *fcpdev,
+				  struct acpi_description_header *acpi,
+				  size_t len ) {
+
+	DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n",
+	       fcpdev );
+	( void ) acpi;
+	( void ) len;
+	return 0;
+}
+
+/**
+ * Describe FCP device using EDD
+ *
+ * @v fcpdev		FCP device
+ * @v type		EDD interface type
+ * @v path		EDD device path
+ * @ret rc		Return status code
+ */
+static int fcpdev_edd_describe ( struct fcp_device *fcpdev,
+				 struct edd_interface_type *type,
+				 union edd_device_path *path ) {
+	union {
+		struct fc_name fc;
+		uint64_t u64;
+	} wwn;
+	union {
+		struct scsi_lun scsi;
+		uint64_t u64;
+	} lun;
+
+	type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE );
+	memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) );
+	path->fibre.wwn = be64_to_cpu ( wwn.u64 );
+	memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) );
+	path->fibre.lun = be64_to_cpu ( lun.u64 );
+	return 0;
+}
+
+/**
+ * Identify device underlying FCP device
+ *
+ * @v fcpdev		FCP device
+ * @ret device		Underlying device
+ */
+static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) {
+
+	/* We know the underlying device only if the link is up;
+	 * otherwise we don't have a port to examine.
+	 */
+	if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) {
+		DBGC ( fcpdev, "FCP %p doesn't know underlying device "
+		       "until link is up\n", fcpdev );
+		return NULL;
+	}
+
+	/* Hand off to port's transport interface */
+	assert ( fcpdev->ulp->peer->port != NULL );
+	return identify_device ( &fcpdev->ulp->peer->port->transport );
+}
+
+/** FCP device SCSI interface operations */
+static struct interface_operation fcpdev_scsi_op[] = {
+	INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ),
+	INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ),
+	INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ),
+	INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ),
+	INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ),
+	INTF_OP ( identify_device, struct fcp_device *,
+		  fcpdev_identify_device ),
+};
+
+/** FCP device SCSI interface descriptor */
+static struct interface_descriptor fcpdev_scsi_desc =
+	INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
+
+/**
+ * Open FCP device
+ *
+ * @v parent		Parent interface
+ * @v wwn		Fibre Channel WWN
+ * @v lun		SCSI LUN
+ * @ret rc		Return status code
+ */
+static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
+			 struct scsi_lun *lun ) {
+	struct fc_ulp *ulp;
+	struct fcp_device *fcpdev;
+	int rc;
+
+	/* Get Fibre Channel ULP interface */
+	ulp = fc_ulp_get_wwn_type ( wwn, FC_TYPE_FCP );
+	if ( ! ulp ) {
+		rc = -ENOMEM;
+		goto err_ulp_get;
+	}
+
+	/* Allocate and initialise structure */
+	fcpdev = zalloc ( sizeof ( *fcpdev ) );
+	if ( ! fcpdev ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &fcpdev->refcnt, NULL );
+	intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
+	INIT_LIST_HEAD ( &fcpdev->fcpcmds );
+	fcpdev->ulp = fc_ulp_get ( ulp );
+	fc_ulp_increment ( fcpdev->ulp );
+
+	DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
+
+	/* Preserve parameters required for boot firmware table */
+	memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
+	memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
+
+	/* Attach SCSI device to parent interface */
+	if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) {
+		DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n",
+		       fcpdev, strerror ( rc ) );
+		goto err_scsi_open;
+	}
+
+	/* Drop temporary reference to ULP */
+	fc_ulp_put ( ulp );
+
+	/* Mortalise self and return */
+	ref_put ( &fcpdev->refcnt );
+	return 0;
+
+ err_scsi_open:
+	fcpdev_close ( fcpdev, rc );
+	ref_put ( &fcpdev->refcnt );
+ err_zalloc:
+	fc_ulp_put ( ulp );
+ err_ulp_get:
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * FCP URIs
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Parse FCP URI
+ *
+ * @v uri		URI
+ * @ret wwn		Fibre Channel WWN
+ * @ret lun		SCSI LUN
+ * @ret rc		Return status code
+ *
+ * An FCP URI has the form "fcp:<wwn>:<lun>" or "fcp://<wwn>/<lun>"
+ */
+static int fcp_parse_uri ( struct uri *uri, struct fc_name *wwn,
+			   struct scsi_lun *lun ) {
+	char wwn_buf[ FC_NAME_STRLEN + 1 /* NUL */ ];
+	const char *wwn_text;
+	const char *lun_text;
+	int rc;
+
+	/* Extract WWN and LUN texts from URI */
+	if ( uri->opaque ) {
+		/* "fcp:<wwn>:<lun>" */
+		if ( snprintf ( wwn_buf, sizeof ( wwn_buf ), "%s",
+				uri->opaque ) < ( FC_NAME_STRLEN + 1 /* : */ ) )
+			return -EINVAL;
+		if ( uri->opaque[FC_NAME_STRLEN] != ':' )
+			return -EINVAL;
+		wwn_text = wwn_buf;
+		lun_text = &uri->opaque[FC_NAME_STRLEN + 1];
+	} else {
+		/* If host exists, path must also exist */
+		if ( ! ( uri->host && uri->path ) )
+			return -EINVAL;
+		if ( uri->path[0] != '/' )
+			return -EINVAL;
+		wwn_text = uri->host;
+		lun_text = ( uri->path + 1 );
+	}
+
+	/* Parse WWN */
+	if ( ( rc = fc_aton ( wwn_text, wwn ) ) != 0 )
+		return rc;
+
+	/* Parse LUN */
+	if ( ( rc = scsi_parse_lun ( lun_text, lun ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Open FCP URI
+ *
+ * @v parent		Parent interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int fcp_open ( struct interface *parent, struct uri *uri ) {
+	struct fc_name wwn;
+	struct scsi_lun lun;
+	int rc;
+
+	/* Parse URI */
+	if ( ( rc = fcp_parse_uri ( uri, &wwn, &lun ) ) != 0 )
+		return rc;
+
+	/* Open FCP device */
+	if ( ( rc = fcpdev_open ( parent, &wwn, &lun ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** FCP URI opener */
+struct uri_opener fcp_uri_opener __uri_opener = {
+	.scheme = "fcp",
+	.open = fcp_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/icmp.c b/qemu-0.15.x/roms/ipxe/src/net/icmp.c
new file mode 100644
index 0000000..84dad42
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/icmp.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/in.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/icmp.h>
+
+/** @file
+ *
+ * ICMP protocol
+ *
+ */
+
+struct tcpip_protocol icmp_protocol __tcpip_protocol;
+
+/**
+ * Process a received packet
+ *
+ * @v iobuf		I/O buffer
+ * @v st_src		Partially-filled source address
+ * @v st_dest		Partially-filled destination address
+ * @v pshdr_csum	Pseudo-header checksum
+ * @ret rc		Return status code
+ */
+static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+		     struct sockaddr_tcpip *st_dest,
+		     uint16_t pshdr_csum __unused ) {
+	struct icmp_header *icmp = iobuf->data;
+	size_t len = iob_len ( iobuf );
+	unsigned int csum;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *icmp ) ) {
+		DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n",
+		      len, sizeof ( *icmp ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Verify checksum */
+	csum = tcpip_chksum ( icmp, len );
+	if ( csum != 0 ) {
+		DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n",
+		      csum );
+		DBG_HD ( icmp, len );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* We respond only to pings */
+	if ( icmp->type != ICMP_ECHO_REQUEST ) {
+		DBG ( "ICMP ignoring type %d\n", icmp->type );
+		rc = 0;
+		goto done;
+	}
+
+	DBG ( "ICMP responding to ping\n" );
+
+	/* Change type to response and recalculate checksum */
+	icmp->type = ICMP_ECHO_RESPONSE;
+	icmp->chksum = 0;
+	icmp->chksum = tcpip_chksum ( icmp, len );
+
+	/* Transmit the response */
+	if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest,
+			       st_src, NULL, NULL ) ) != 0 ) {
+		DBG ( "ICMP could not transmit ping response: %s\n",
+		      strerror ( rc ) );
+		goto done;
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** ICMP TCP/IP protocol */
+struct tcpip_protocol icmp_protocol __tcpip_protocol = {
+	.name = "ICMP",
+	.rx = icmp_rx,
+	.tcpip_proto = IP_ICMP,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/icmpv6.c b/qemu-0.15.x/roms/ipxe/src/net/icmpv6.c
new file mode 100644
index 0000000..1a5aad3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/icmpv6.c
@@ -0,0 +1,126 @@
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/in.h>
+#include <ipxe/ip6.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ndp.h>
+#include <ipxe/icmp6.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/netdevice.h>
+
+/**
+ * Send neighbour solicitation packet
+ *
+ * @v netdev	Network device
+ * @v src	Source address
+ * @v dest	Destination address
+ *
+ * This function prepares a neighbour solicitation packet and sends it to the
+ * network layer.
+ */
+int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unused,
+			 struct in6_addr *dest ) {
+	union {
+		struct sockaddr_in6 sin6;
+		struct sockaddr_tcpip st;
+	} st_dest;
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct neighbour_solicit *nsolicit;
+	struct io_buffer *iobuf = alloc_iob ( sizeof ( *nsolicit ) + MIN_IOB_LEN );
+	iob_reserve ( iobuf, MAX_HDR_LEN );
+	nsolicit = iob_put ( iobuf, sizeof ( *nsolicit ) );
+
+	/* Fill up the headers */
+	memset ( nsolicit, 0, sizeof ( *nsolicit ) );
+	nsolicit->type = ICMP6_NSOLICIT;
+	nsolicit->code = 0;
+	nsolicit->target = *dest;
+	nsolicit->opt_type = 1;
+	nsolicit->opt_len = ( 2 + ll_protocol->ll_addr_len ) / 8;
+	memcpy ( nsolicit->opt_ll_addr, netdev->ll_addr,
+				netdev->ll_protocol->ll_addr_len );
+	/* Partial checksum */
+	nsolicit->csum = 0;
+	nsolicit->csum = tcpip_chksum ( nsolicit, sizeof ( *nsolicit ) );
+
+	/* Solicited multicast address */
+	st_dest.sin6.sin_family = AF_INET6;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[0] = 0xff;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[2] = 0x02;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[1] = 0x0000;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr32[1] = 0x00000000;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[4] = 0x0000;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[5] = 0x0001;
+	st_dest.sin6.sin6_addr.in6_u.u6_addr32[3] = dest->in6_u.u6_addr32[3];
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
+	
+	/* Send packet over IP6 */
+	return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st,
+			  NULL, &nsolicit->csum );
+}
+
+/**
+ * Process ICMP6 headers
+ *
+ * @v iobuf	I/O buffer
+ * @v st_src	Source address
+ * @v st_dest	Destination address
+ */
+static int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+		      struct sockaddr_tcpip *st_dest, __unused uint16_t pshdr_csum ) {
+	struct icmp6_header *icmp6hdr = iobuf->data;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *icmp6hdr ) ) {
+		DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
+		free_iob ( iobuf );
+		return -EINVAL;
+	}
+
+	/* TODO: Verify checksum */
+
+	/* Process the ICMP header */
+	switch ( icmp6hdr->type ) {
+	case ICMP6_NADVERT:
+		return ndp_process_advert ( iobuf, st_src, st_dest );
+	}
+	return -ENOSYS;
+}
+
+#if 0
+void icmp6_test_nadvert (struct net_device *netdev, struct sockaddr_in6 *server_p, char *ll_addr) {
+
+		struct sockaddr_in6 server;
+		memcpy ( &server, server_p, sizeof ( server ) );
+                struct io_buffer *rxiobuf = alloc_iob ( 500 );
+                iob_reserve ( rxiobuf, MAX_HDR_LEN );
+                struct neighbour_advert *nadvert = iob_put ( rxiobuf, sizeof ( *nadvert ) );
+                nadvert->type = 136;
+                nadvert->code = 0;
+                nadvert->flags = ICMP6_FLAGS_SOLICITED;
+		nadvert->csum = 0xffff;
+		nadvert->target = server.sin6_addr;
+                nadvert->opt_type = 2;
+                nadvert->opt_len = 1;
+                memcpy ( nadvert->opt_ll_addr, ll_addr, 6 );
+                struct ip6_header *ip6hdr = iob_push ( rxiobuf, sizeof ( *ip6hdr ) );
+                ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 );
+		ip6hdr->hop_limit = 255;
+		ip6hdr->nxt_hdr = 58;
+		ip6hdr->payload_len = htons ( sizeof ( *nadvert ) );
+                ip6hdr->src = server.sin6_addr;
+                ip6hdr->dest = server.sin6_addr;
+		hex_dump ( rxiobuf->data, iob_len ( rxiobuf ) );
+                net_rx ( rxiobuf, netdev, htons ( ETH_P_IPV6 ), ll_addr );
+}
+#endif
+
+/** ICMP6 protocol */
+struct tcpip_protocol icmp6_protocol __tcpip_protocol = {
+	.name = "ICMP6",
+	.rx = icmp6_rx,
+	.tcpip_proto = IP_ICMP6, // 58
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband.c
new file mode 100644
index 0000000..c2cb834
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband.c
@@ -0,0 +1,995 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/list.h>
+#include <ipxe/errortab.h>
+#include <ipxe/if_arp.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/process.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_mi.h>
+#include <ipxe/ib_sma.h>
+
+/** @file
+ *
+ * Infiniband protocol
+ *
+ */
+
+/** List of Infiniband devices */
+struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
+
+/** List of open Infiniband devices, in reverse order of opening */
+static struct list_head open_ib_devices = LIST_HEAD_INIT ( open_ib_devices );
+
+/* Disambiguate the various possible EINPROGRESSes */
+#define EINPROGRESS_INIT __einfo_error ( EINFO_EINPROGRESS_INIT )
+#define EINFO_EINPROGRESS_INIT __einfo_uniqify \
+	( EINFO_EINPROGRESS, 0x01, "Initialising" )
+#define EINPROGRESS_ARMED __einfo_error ( EINFO_EINPROGRESS_ARMED )
+#define EINFO_EINPROGRESS_ARMED __einfo_uniqify \
+	( EINFO_EINPROGRESS, 0x02, "Armed" )
+
+/** Human-readable message for the link statuses */
+struct errortab infiniband_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EINPROGRESS_INIT ),
+	__einfo_errortab ( EINFO_EINPROGRESS_ARMED ),
+};
+
+/***************************************************************************
+ *
+ * Completion queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v num_cqes		Number of completion queue entries
+ * @v op		Completion queue operations
+ * @ret cq		New completion queue
+ */
+struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+	       struct ib_completion_queue_operations *op ) {
+	struct ib_completion_queue *cq;
+	int rc;
+
+	DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
+
+	/* Allocate and initialise data structure */
+	cq = zalloc ( sizeof ( *cq ) );
+	if ( ! cq )
+		goto err_alloc_cq;
+	cq->ibdev = ibdev;
+	list_add ( &cq->list, &ibdev->cqs );
+	cq->num_cqes = num_cqes;
+	INIT_LIST_HEAD ( &cq->work_queues );
+	cq->op = op;
+
+	/* Perform device-specific initialisation and get CQN */
+	if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not initialise completion "
+		       "queue: %s\n", ibdev, strerror ( rc ) );
+		goto err_dev_create_cq;
+	}
+
+	DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
+	       "with CQN %#lx\n", ibdev, num_cqes, cq,
+	       ib_cq_get_drvdata ( cq ), cq->cqn );
+	return cq;
+
+	ibdev->op->destroy_cq ( ibdev, cq );
+ err_dev_create_cq:
+	list_del ( &cq->list );
+	free ( cq );
+ err_alloc_cq:
+	return NULL;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+void ib_destroy_cq ( struct ib_device *ibdev,
+		     struct ib_completion_queue *cq ) {
+	DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
+	       ibdev, cq->cqn );
+	assert ( list_empty ( &cq->work_queues ) );
+	ibdev->op->destroy_cq ( ibdev, cq );
+	list_del ( &cq->list );
+	free ( cq );
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev		Infiniband device
+ * @v cq		Completion queue
+ */
+void ib_poll_cq ( struct ib_device *ibdev,
+		  struct ib_completion_queue *cq ) {
+	struct ib_work_queue *wq;
+
+	/* Poll completion queue */
+	ibdev->op->poll_cq ( ibdev, cq );
+
+	/* Refill receive work queues */
+	list_for_each_entry ( wq, &cq->work_queues, list ) {
+		if ( ! wq->is_send )
+			ib_refill_recv ( ibdev, wq->qp );
+	}
+}
+
+/***************************************************************************
+ *
+ * Work queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v type		Queue pair type
+ * @v num_send_wqes	Number of send work queue entries
+ * @v send_cq		Send completion queue
+ * @v num_recv_wqes	Number of receive work queue entries
+ * @v recv_cq		Receive completion queue
+ * @ret qp		Queue pair
+ *
+ * The queue pair will be left in the INIT state; you must call
+ * ib_modify_qp() before it is ready to use for sending and receiving.
+ */
+struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
+				      enum ib_queue_pair_type type,
+				      unsigned int num_send_wqes,
+				      struct ib_completion_queue *send_cq,
+				      unsigned int num_recv_wqes,
+				      struct ib_completion_queue *recv_cq ) {
+	struct ib_queue_pair *qp;
+	size_t total_size;
+	int rc;
+
+	DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
+
+	/* Allocate and initialise data structure */
+	total_size = ( sizeof ( *qp ) +
+		       ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
+		       ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
+	qp = zalloc ( total_size );
+	if ( ! qp )
+		goto err_alloc_qp;
+	qp->ibdev = ibdev;
+	list_add ( &qp->list, &ibdev->qps );
+	qp->type = type;
+	qp->send.qp = qp;
+	qp->send.is_send = 1;
+	qp->send.cq = send_cq;
+	list_add ( &qp->send.list, &send_cq->work_queues );
+	qp->send.psn = ( random() & 0xffffffUL );
+	qp->send.num_wqes = num_send_wqes;
+	qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
+	qp->recv.qp = qp;
+	qp->recv.cq = recv_cq;
+	list_add ( &qp->recv.list, &recv_cq->work_queues );
+	qp->recv.psn = ( random() & 0xffffffUL );
+	qp->recv.num_wqes = num_recv_wqes;
+	qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
+			    ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
+	INIT_LIST_HEAD ( &qp->mgids );
+
+	/* Perform device-specific initialisation and get QPN */
+	if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
+		       "%s\n", ibdev, strerror ( rc ) );
+		goto err_dev_create_qp;
+	}
+	DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
+	       ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
+	DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
+	       ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
+	       qp->recv.iobufs );
+	DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
+	       ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
+	       ( ( ( void * ) qp ) + total_size ) );
+
+	/* Calculate externally-visible QPN */
+	switch ( type ) {
+	case IB_QPT_SMI:
+		qp->ext_qpn = IB_QPN_SMI;
+		break;
+	case IB_QPT_GSI:
+		qp->ext_qpn = IB_QPN_GSI;
+		break;
+	default:
+		qp->ext_qpn = qp->qpn;
+		break;
+	}
+	if ( qp->ext_qpn != qp->qpn ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx has external QPN %#lx\n",
+		       ibdev, qp->qpn, qp->ext_qpn );
+	}
+
+	return qp;
+
+	ibdev->op->destroy_qp ( ibdev, qp );
+ err_dev_create_qp:
+	list_del ( &qp->send.list );
+	list_del ( &qp->recv.list );
+	list_del ( &qp->list );
+	free ( qp );
+ err_alloc_qp:
+	return NULL;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		New address vector, if applicable
+ * @ret rc		Return status code
+ */
+int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+	int rc;
+
+	DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
+
+	if ( ( rc = ibdev->op->modify_qp ( ibdev, qp ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
+		       ibdev, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+	struct io_buffer *iobuf;
+	unsigned int i;
+
+	DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
+	       ibdev, qp->qpn );
+
+	assert ( list_empty ( &qp->mgids ) );
+
+	/* Perform device-specific destruction */
+	ibdev->op->destroy_qp ( ibdev, qp );
+
+	/* Complete any remaining I/O buffers with errors */
+	for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
+		if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
+			ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
+	}
+	for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
+		if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
+			ib_complete_recv ( ibdev, qp, NULL, iobuf,
+					   -ECANCELED );
+		}
+	}
+
+	/* Remove work queues from completion queue */
+	list_del ( &qp->send.list );
+	list_del ( &qp->recv.list );
+
+	/* Free QP */
+	list_del ( &qp->list );
+	free ( qp );
+}
+
+/**
+ * Find queue pair by QPN
+ *
+ * @v ibdev		Infiniband device
+ * @v qpn		Queue pair number
+ * @ret qp		Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+					unsigned long qpn ) {
+	struct ib_queue_pair *qp;
+
+	list_for_each_entry ( qp, &ibdev->qps, list ) {
+		if ( ( qpn == qp->qpn ) || ( qpn == qp->ext_qpn ) )
+			return qp;
+	}
+	return NULL;
+}
+
+/**
+ * Find queue pair by multicast GID
+ *
+ * @v ibdev		Infiniband device
+ * @v gid		Multicast GID
+ * @ret qp		Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+					 union ib_gid *gid ) {
+	struct ib_queue_pair *qp;
+	struct ib_multicast_gid *mgid;
+
+	list_for_each_entry ( qp, &ibdev->qps, list ) {
+		list_for_each_entry ( mgid, &qp->mgids, list ) {
+			if ( memcmp ( &mgid->gid, gid,
+				      sizeof ( mgid->gid ) ) == 0 ) {
+				return qp;
+			}
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Find work queue belonging to completion queue
+ *
+ * @v cq		Completion queue
+ * @v qpn		Queue pair number
+ * @v is_send		Find send work queue (rather than receive)
+ * @ret wq		Work queue, or NULL if not found
+ */
+struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
+				    unsigned long qpn, int is_send ) {
+	struct ib_work_queue *wq;
+
+	list_for_each_entry ( wq, &cq->work_queues, list ) {
+		if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
+			return wq;
+	}
+	return NULL;
+}
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		   struct ib_address_vector *av,
+		   struct io_buffer *iobuf ) {
+	struct ib_address_vector av_copy;
+	int rc;
+
+	/* Check queue fill level */
+	if ( qp->send.fill >= qp->send.num_wqes ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
+		       ibdev, qp->qpn );
+		return -ENOBUFS;
+	}
+
+	/* Use default address vector if none specified */
+	if ( ! av )
+		av = &qp->av;
+
+	/* Make modifiable copy of address vector */
+	memcpy ( &av_copy, av, sizeof ( av_copy ) );
+	av = &av_copy;
+
+	/* Fill in optional parameters in address vector */
+	if ( ! av->qkey )
+		av->qkey = qp->qkey;
+	if ( ! av->rate )
+		av->rate = IB_RATE_2_5;
+
+	/* Post to hardware */
+	if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
+		       "%s\n", ibdev, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+
+	qp->send.fill++;
+	return 0;
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		   struct io_buffer *iobuf ) {
+	int rc;
+
+	/* Check packet length */
+	if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
+		       ibdev, qp->qpn, iob_tailroom ( iobuf ) );
+		return -EINVAL;
+	}
+
+	/* Check queue fill level */
+	if ( qp->recv.fill >= qp->recv.num_wqes ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
+		       ibdev, qp->qpn );
+		return -ENOBUFS;
+	}
+
+	/* Post to hardware */
+	if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
+		       "%s\n", ibdev, qp->qpn, strerror ( rc ) );
+		return rc;
+	}
+
+	qp->recv.fill++;
+	return 0;
+}
+
+/**
+ * Complete send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			struct io_buffer *iobuf, int rc ) {
+
+	if ( qp->send.cq->op->complete_send ) {
+		qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
+	} else {
+		free_iob ( iobuf );
+	}
+	qp->send.fill--;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector, or NULL
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+			struct ib_address_vector *av,
+			struct io_buffer *iobuf, int rc ) {
+
+	if ( qp->recv.cq->op->complete_recv ) {
+		qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
+	} else {
+		free_iob ( iobuf );
+	}
+	qp->recv.fill--;
+}
+
+/**
+ * Refill receive work queue
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ */
+void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+	struct io_buffer *iobuf;
+	int rc;
+
+	/* Keep filling while unfilled entries remain */
+	while ( qp->recv.fill < qp->recv.num_wqes ) {
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
+		if ( ! iobuf ) {
+			/* Non-fatal; we will refill on next attempt */
+			return;
+		}
+
+		/* Post I/O buffer */
+		if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+			DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
+			       ibdev, strerror ( rc ) );
+			free_iob ( iobuf );
+			/* Give up */
+			return;
+		}
+	}
+}
+
+/***************************************************************************
+ *
+ * Link control
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Get link state
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Link status code
+ */
+int ib_link_rc ( struct ib_device *ibdev ) {
+	switch ( ibdev->port_state ) {
+	case IB_PORT_STATE_DOWN:	return -ENOTCONN;
+	case IB_PORT_STATE_INIT:	return -EINPROGRESS_INIT;
+	case IB_PORT_STATE_ARMED:	return -EINPROGRESS_ARMED;
+	case IB_PORT_STATE_ACTIVE:	return 0;
+	default:			return -EINVAL;
+	}
+}
+
+/**
+ * Textual representation of Infiniband link state
+ *
+ * @v ibdev		Infiniband device
+ * @ret link_text	Link state text
+ */
+static const char * ib_link_state_text ( struct ib_device *ibdev ) {
+	switch ( ibdev->port_state ) {
+	case IB_PORT_STATE_DOWN:	return "DOWN";
+	case IB_PORT_STATE_INIT:	return "INIT";
+	case IB_PORT_STATE_ARMED:	return "ARMED";
+	case IB_PORT_STATE_ACTIVE:	return "ACTIVE";
+	default:			return "UNKNOWN";
+	}
+}
+
+/**
+ * Notify drivers of Infiniband device or link state change
+ *
+ * @v ibdev		Infiniband device
+ */
+static void ib_notify ( struct ib_device *ibdev ) {
+	struct ib_driver *driver;
+
+	for_each_table_entry ( driver, IB_DRIVERS )
+		driver->notify ( ibdev );
+}
+
+/**
+ * Notify of Infiniband link state change
+ *
+ * @v ibdev		Infiniband device
+ */
+void ib_link_state_changed ( struct ib_device *ibdev ) {
+
+	DBGC ( ibdev, "IBDEV %p link state is %s\n",
+	       ibdev, ib_link_state_text ( ibdev ) );
+
+	/* Notify drivers of link state change */
+	ib_notify ( ibdev );
+}
+
+/**
+ * Open port
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+int ib_open ( struct ib_device *ibdev ) {
+	int rc;
+
+	/* Increment device open request counter */
+	if ( ibdev->open_count++ > 0 ) {
+		/* Device was already open; do nothing */
+		return 0;
+	}
+
+	/* Create subnet management interface */
+	ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI );
+	if ( ! ibdev->smi ) {
+		DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev );
+		rc = -ENOMEM;
+		goto err_create_smi;
+	}
+
+	/* Create subnet management agent */
+	if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n",
+		       ibdev, strerror ( rc ) );
+		goto err_create_sma;
+	}
+
+	/* Create general services interface */
+	ibdev->gsi = ib_create_mi ( ibdev, IB_QPT_GSI );
+	if ( ! ibdev->gsi ) {
+		DBGC ( ibdev, "IBDEV %p could not create GSI\n", ibdev );
+		rc = -ENOMEM;
+		goto err_create_gsi;
+	}
+
+	/* Open device */
+	if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not open: %s\n",
+		       ibdev, strerror ( rc ) );
+		goto err_open;
+	}
+
+	/* Add to head of open devices list */
+	list_add ( &ibdev->open_list, &open_ib_devices );
+
+	/* Notify drivers of device state change */
+	ib_notify ( ibdev );
+
+	assert ( ibdev->open_count == 1 );
+	return 0;
+
+	ibdev->op->close ( ibdev );
+ err_open:
+	ib_destroy_mi ( ibdev, ibdev->gsi );
+ err_create_gsi:
+	ib_destroy_sma ( ibdev, ibdev->smi );
+ err_create_sma:
+	ib_destroy_mi ( ibdev, ibdev->smi );
+ err_create_smi:
+	assert ( ibdev->open_count == 1 );
+	ibdev->open_count = 0;
+	return rc;
+}
+
+/**
+ * Close port
+ *
+ * @v ibdev		Infiniband device
+ */
+void ib_close ( struct ib_device *ibdev ) {
+
+	/* Decrement device open request counter */
+	ibdev->open_count--;
+
+	/* Close device if this was the last remaining requested opening */
+	if ( ibdev->open_count == 0 ) {
+		ib_notify ( ibdev );
+		list_del ( &ibdev->open_list );
+		ib_destroy_mi ( ibdev, ibdev->gsi );
+		ib_destroy_sma ( ibdev, ibdev->smi );
+		ib_destroy_mi ( ibdev, ibdev->smi );
+		ibdev->op->close ( ibdev );
+	}
+}
+
+/***************************************************************************
+ *
+ * Multicast
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ * @ret rc		Return status code
+ *
+ * Note that this function handles only the local device's attachment
+ * to the multicast GID; it does not issue the relevant MADs to join
+ * the multicast group on the subnet.
+ */
+int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		      union ib_gid *gid ) {
+	struct ib_multicast_gid *mgid;
+	int rc;
+
+	/* Add to software multicast GID list */
+	mgid = zalloc ( sizeof ( *mgid ) );
+	if ( ! mgid ) {
+		rc = -ENOMEM;
+		goto err_alloc_mgid;
+	}
+	memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
+	list_add ( &mgid->list, &qp->mgids );
+
+	/* Add to hardware multicast GID list */
+	if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
+		goto err_dev_mcast_attach;
+
+	return 0;
+
+ err_dev_mcast_attach:
+	list_del ( &mgid->list );
+	free ( mgid );
+ err_alloc_mgid:
+	return rc;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		       union ib_gid *gid ) {
+	struct ib_multicast_gid *mgid;
+
+	/* Remove from hardware multicast GID list */
+	ibdev->op->mcast_detach ( ibdev, qp, gid );
+
+	/* Remove from software multicast GID list */
+	list_for_each_entry ( mgid, &qp->mgids, list ) {
+		if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
+			list_del ( &mgid->list );
+			free ( mgid );
+			break;
+		}
+	}
+}
+
+/***************************************************************************
+ *
+ * Miscellaneous
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Count Infiniband HCA ports
+ *
+ * @v ibdev		Infiniband device
+ * @ret num_ports	Number of ports
+ */
+int ib_count_ports ( struct ib_device *ibdev ) {
+	struct ib_device *tmp;
+	int num_ports = 0;
+
+	/* Search for IB devices with the same physical device to
+	 * identify port count.
+	 */
+	for_each_ibdev ( tmp ) {
+		if ( tmp->dev == ibdev->dev )
+			num_ports++;
+	}
+	return num_ports;
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set port information MAD
+ */
+int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) {
+	int rc;
+
+	/* Adapters with embedded SMAs do not need to support this method */
+	if ( ! ibdev->op->set_port_info ) {
+		DBGC ( ibdev, "IBDEV %p does not support setting port "
+		       "information\n", ibdev );
+		return -ENOTSUP;
+	}
+
+	if ( ( rc = ibdev->op->set_port_info ( ibdev, mad ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
+		       ibdev, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+};
+
+/**
+ * Set partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		Set partition key table MAD
+ */
+int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ) {
+	int rc;
+
+	/* Adapters with embedded SMAs do not need to support this method */
+	if ( ! ibdev->op->set_pkey_table ) {
+		DBGC ( ibdev, "IBDEV %p does not support setting partition "
+		       "key table\n", ibdev );
+		return -ENOTSUP;
+	}
+
+	if ( ( rc = ibdev->op->set_pkey_table ( ibdev, mad ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not set partition key table: "
+		       "%s\n", ibdev, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+};
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev		Infiniband device
+ */
+void ib_poll_eq ( struct ib_device *ibdev ) {
+	struct ib_completion_queue *cq;
+
+	/* Poll device's event queue */
+	ibdev->op->poll_eq ( ibdev );
+
+	/* Poll all completion queues */
+	list_for_each_entry ( cq, &ibdev->cqs, list )
+		ib_poll_cq ( ibdev, cq );
+}
+
+/**
+ * Single-step the Infiniband event queue
+ *
+ * @v process		Infiniband event queue process
+ */
+static void ib_step ( struct process *process __unused ) {
+	struct ib_device *ibdev;
+
+	for_each_ibdev ( ibdev )
+		ib_poll_eq ( ibdev );
+}
+
+/** Infiniband event queue process */
+struct process ib_process __permanent_process = {
+	.list = LIST_HEAD_INIT ( ib_process.list ),
+	.step = ib_step,
+};
+
+/***************************************************************************
+ *
+ * Infiniband device creation/destruction
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate Infiniband device
+ *
+ * @v priv_size		Size of driver private data area
+ * @ret ibdev		Infiniband device, or NULL
+ */
+struct ib_device * alloc_ibdev ( size_t priv_size ) {
+	struct ib_device *ibdev;
+	void *drv_priv;
+	size_t total_len;
+
+	total_len = ( sizeof ( *ibdev ) + priv_size );
+	ibdev = zalloc ( total_len );
+	if ( ibdev ) {
+		drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
+		ib_set_drvdata ( ibdev, drv_priv );
+		INIT_LIST_HEAD ( &ibdev->list );
+		INIT_LIST_HEAD ( &ibdev->open_list );
+		INIT_LIST_HEAD ( &ibdev->cqs );
+		INIT_LIST_HEAD ( &ibdev->qps );
+		ibdev->port_state = IB_PORT_STATE_DOWN;
+		ibdev->lid = IB_LID_NONE;
+		ibdev->pkey = IB_PKEY_DEFAULT;
+	}
+	return ibdev;
+}
+
+/**
+ * Register Infiniband device
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+int register_ibdev ( struct ib_device *ibdev ) {
+	struct ib_driver *driver;
+	int rc;
+
+	/* Add to device list */
+	ibdev_get ( ibdev );
+	list_add_tail ( &ibdev->list, &ib_devices );
+	DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
+	       ibdev->dev->name );
+
+	/* Probe device */
+	for_each_table_entry ( driver, IB_DRIVERS ) {
+		if ( ( rc = driver->probe ( ibdev ) ) != 0 ) {
+			DBGC ( ibdev, "IBDEV %p could not add %s device: %s\n",
+			       ibdev, driver->name, strerror ( rc ) );
+			goto err_probe;
+		}
+	}
+
+	return 0;
+
+ err_probe:
+	for_each_table_entry_continue_reverse ( driver, IB_DRIVERS )
+		driver->remove ( ibdev );
+	list_del ( &ibdev->list );
+	ibdev_put ( ibdev );
+	return rc;
+}
+
+/**
+ * Unregister Infiniband device
+ *
+ * @v ibdev		Infiniband device
+ */
+void unregister_ibdev ( struct ib_device *ibdev ) {
+	struct ib_driver *driver;
+
+	/* Remove device */
+	for_each_table_entry_reverse ( driver, IB_DRIVERS )
+		driver->remove ( ibdev );
+
+	/* Remove from device list */
+	list_del ( &ibdev->list );
+	ibdev_put ( ibdev );
+	DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
+}
+
+/**
+ * Find Infiniband device by GID
+ *
+ * @v gid		GID
+ * @ret ibdev		Infiniband device, or NULL
+ */
+struct ib_device * find_ibdev ( union ib_gid *gid ) {
+	struct ib_device *ibdev;
+
+	for_each_ibdev ( ibdev ) {
+		if ( memcmp ( gid, &ibdev->gid, sizeof ( *gid ) ) == 0 )
+			return ibdev;
+	}
+	return NULL;
+}
+
+/**
+ * Get most recently opened Infiniband device
+ *
+ * @ret ibdev		Most recently opened Infiniband device, or NULL
+ */
+struct ib_device * last_opened_ibdev ( void ) {
+	struct ib_device *ibdev;
+
+	ibdev = list_first_entry ( &open_ib_devices, struct ib_device,
+				   open_list );
+	if ( ! ibdev )
+		return NULL;
+
+	assert ( ibdev->open_count != 0 );
+	return ibdev;
+}
+
+/* Drag in IPoIB */
+REQUIRE_OBJECT ( ipoib );
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cm.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cm.c
new file mode 100644
index 0000000..1a0646b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cm.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_mi.h>
+#include <ipxe/ib_pathrec.h>
+#include <ipxe/ib_cm.h>
+
+/**
+ * @file
+ *
+ * Infiniband communication management
+ *
+ */
+
+/** List of connections */
+static LIST_HEAD ( ib_cm_conns );
+
+/**
+ * Find connection by local communication ID
+ *
+ * @v local_id		Local communication ID
+ * @ret conn		Connection, or NULL
+ */
+static struct ib_connection * ib_cm_find ( uint32_t local_id ) {
+	struct ib_connection *conn;
+
+	list_for_each_entry ( conn, &ib_cm_conns, list ) {
+		if ( conn->local_id == local_id )
+			return conn;
+	}
+	return NULL;
+}
+
+/**
+ * Send "ready to use" response
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v av		Address vector
+ * @v local_id		Local communication ID
+ * @v remote_id		Remote communication ID
+ * @ret rc		Return status code
+ */
+static int ib_cm_send_rtu ( struct ib_device *ibdev,
+			    struct ib_mad_interface *mi,
+			    struct ib_address_vector *av,
+			    uint32_t local_id, uint32_t remote_id ) {
+	union ib_mad mad;
+	struct ib_cm_ready_to_use *rtu = &mad.cm.cm_data.ready_to_use;
+	int rc;
+
+	/* Construct "ready to use" response */
+	memset ( &mad, 0, sizeof ( mad ) );
+	mad.hdr.mgmt_class = IB_MGMT_CLASS_CM;
+	mad.hdr.class_version = IB_CM_CLASS_VERSION;
+	mad.hdr.method = IB_MGMT_METHOD_SEND;
+	mad.hdr.attr_id = htons ( IB_CM_ATTR_READY_TO_USE );
+	rtu->local_id = htonl ( local_id );
+	rtu->remote_id = htonl ( remote_id );
+	if ( ( rc = ib_mi_send ( ibdev, mi, &mad, av ) ) != 0 ){
+		DBG ( "CM could not send RTU: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle duplicate connection replies
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ * @ret rc		Return status code
+ *
+ * If a "ready to use" MAD is lost, the peer may resend the connection
+ * reply.  We have to respond to these with duplicate "ready to use"
+ * MADs, otherwise the peer may time out and drop the connection.
+ */
+static void ib_cm_recv_rep ( struct ib_device *ibdev,
+			     struct ib_mad_interface *mi,
+			     union ib_mad *mad,
+			     struct ib_address_vector *av ) {
+	struct ib_cm_connect_reply *rep = &mad->cm.cm_data.connect_reply;
+	struct ib_connection *conn;
+	uint32_t local_id = ntohl ( rep->remote_id );
+	int rc;
+
+	/* Identify connection */
+	conn = ib_cm_find ( local_id );
+	if ( conn ) {
+		/* Try to send "ready to use" reply */
+		if ( ( rc = ib_cm_send_rtu ( ibdev, mi, av, conn->local_id,
+					     conn->remote_id ) ) != 0 ) {
+			/* Ignore errors; the remote end will retry */
+		}
+	} else {
+		DBG ( "CM unidentified connection %08x\n", local_id );
+	}
+}
+
+/**
+ * Send reply to disconnection request
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v av		Address vector
+ * @v local_id		Local communication ID
+ * @v remote_id		Remote communication ID
+ * @ret rc		Return status code
+ */
+static int ib_cm_send_drep ( struct ib_device *ibdev,
+			     struct ib_mad_interface *mi,
+			     struct ib_address_vector *av,
+			     uint32_t local_id, uint32_t remote_id ) {
+	union ib_mad mad;
+	struct ib_cm_disconnect_reply *drep = &mad.cm.cm_data.disconnect_reply;
+	int rc;
+
+	/* Construct reply to disconnection request */
+	memset ( &mad, 0, sizeof ( mad ) );
+	mad.hdr.mgmt_class = IB_MGMT_CLASS_CM;
+	mad.hdr.class_version = IB_CM_CLASS_VERSION;
+	mad.hdr.method = IB_MGMT_METHOD_SEND;
+	mad.hdr.attr_id = htons ( IB_CM_ATTR_DISCONNECT_REPLY );
+	drep->local_id = htonl ( local_id );
+	drep->remote_id = htonl ( remote_id );
+	if ( ( rc = ib_mi_send ( ibdev, mi, &mad, av ) ) != 0 ){
+		DBG ( "CM could not send DREP: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle disconnection requests
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ * @ret rc		Return status code
+ */
+static void ib_cm_recv_dreq ( struct ib_device *ibdev,
+			      struct ib_mad_interface *mi,
+			      union ib_mad *mad,
+			      struct ib_address_vector *av ) {
+	struct ib_cm_disconnect_request *dreq =
+		&mad->cm.cm_data.disconnect_request;
+	struct ib_connection *conn;
+	uint32_t local_id = ntohl ( dreq->remote_id );
+	uint32_t remote_id = ntohl ( dreq->local_id );
+	int rc;
+
+	/* Identify connection */
+	conn = ib_cm_find ( local_id );
+	if ( conn ) {
+		/* Notify upper layer */
+		conn->op->changed ( ibdev, conn->qp, conn, -ENOTCONN,
+				    &dreq->private_data,
+				    sizeof ( dreq->private_data ) );
+	} else {
+		DBG ( "CM unidentified connection %08x\n", local_id );
+	}
+
+	/* Send reply */
+	if ( ( rc = ib_cm_send_drep ( ibdev, mi, av, local_id,
+				      remote_id ) ) != 0 ) {
+		/* Ignore errors; the remote end will retry */
+	}
+};
+
+/** Communication management agents */
+struct ib_mad_agent ib_cm_agent[] __ib_mad_agent = {
+	{
+		.mgmt_class = IB_MGMT_CLASS_CM,
+		.class_version = IB_CM_CLASS_VERSION,
+		.attr_id = htons ( IB_CM_ATTR_CONNECT_REPLY ),
+		.handle = ib_cm_recv_rep,
+	},
+	{
+		.mgmt_class = IB_MGMT_CLASS_CM,
+		.class_version = IB_CM_CLASS_VERSION,
+		.attr_id = htons ( IB_CM_ATTR_DISCONNECT_REQUEST ),
+		.handle = ib_cm_recv_dreq,
+	},
+};
+
+/**
+ * Convert connection rejection reason to return status code
+ *
+ * @v reason		Rejection reason (in network byte order)
+ * @ret rc		Return status code
+ */
+static int ib_cm_rejection_reason_to_rc ( uint16_t reason ) {
+	switch ( reason ) {
+	case htons ( IB_CM_REJECT_BAD_SERVICE_ID ) :
+		return -ENODEV;
+	case htons ( IB_CM_REJECT_STALE_CONN ) :
+		return -EALREADY;
+	case htons ( IB_CM_REJECT_CONSUMER ) :
+		return -ENOTTY;
+	default:
+		return -EPERM;
+	}
+}
+
+/**
+ * Handle connection request transaction completion
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v madx		Management transaction
+ * @v rc		Status code
+ * @v mad		Received MAD (or NULL on error)
+ * @v av		Source address vector (or NULL on error)
+ */
+static void ib_cm_req_complete ( struct ib_device *ibdev,
+				 struct ib_mad_interface *mi,
+				 struct ib_mad_transaction *madx,
+				 int rc, union ib_mad *mad,
+				 struct ib_address_vector *av ) {
+	struct ib_connection *conn = ib_madx_get_ownerdata ( madx );
+	struct ib_queue_pair *qp = conn->qp;
+	struct ib_cm_common *common = &mad->cm.cm_data.common;
+	struct ib_cm_connect_reply *rep = &mad->cm.cm_data.connect_reply;
+	struct ib_cm_connect_reject *rej = &mad->cm.cm_data.connect_reject;
+	void *private_data = NULL;
+	size_t private_data_len = 0;
+
+	/* Report failures */
+	if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
+		rc = -EIO;
+	if ( rc != 0 ) {
+		DBGC ( conn, "CM %p connection request failed: %s\n",
+		       conn, strerror ( rc ) );
+		goto out;
+	}
+
+	/* Record remote communication ID */
+	conn->remote_id = ntohl ( common->local_id );
+
+	/* Handle response */
+	switch ( mad->hdr.attr_id ) {
+
+	case htons ( IB_CM_ATTR_CONNECT_REPLY ) :
+		/* Extract fields */
+		qp->av.qpn = ( ntohl ( rep->local_qpn ) >> 8 );
+		qp->send.psn = ( ntohl ( rep->starting_psn ) >> 8 );
+		private_data = &rep->private_data;
+		private_data_len = sizeof ( rep->private_data );
+		DBGC ( conn, "CM %p connected to QPN %lx PSN %x\n",
+		       conn, qp->av.qpn, qp->send.psn );
+
+		/* Modify queue pair */
+		if ( ( rc = ib_modify_qp ( ibdev, qp ) ) != 0 ) {
+			DBGC ( conn, "CM %p could not modify queue pair: %s\n",
+			       conn, strerror ( rc ) );
+			goto out;
+		}
+
+		/* Send "ready to use" reply */
+		if ( ( rc = ib_cm_send_rtu ( ibdev, mi, av, conn->local_id,
+					     conn->remote_id ) ) != 0 ) {
+			/* Treat as non-fatal */
+			rc = 0;
+		}
+		break;
+
+	case htons ( IB_CM_ATTR_CONNECT_REJECT ) :
+		/* Extract fields */
+		DBGC ( conn, "CM %p connection rejected (reason %d)\n",
+		       conn, ntohs ( rej->reason ) );
+		/* Private data is valid only for a Consumer Reject */
+		if ( rej->reason == htons ( IB_CM_REJECT_CONSUMER ) ) {
+			private_data = &rej->private_data;
+			private_data_len = sizeof ( rej->private_data );
+		}
+		rc = ib_cm_rejection_reason_to_rc ( rej->reason );
+		break;
+
+	default:
+		DBGC ( conn, "CM %p unexpected response (attribute %04x)\n",
+		       conn, ntohs ( mad->hdr.attr_id ) );
+		rc = -ENOTSUP;
+		break;
+	}
+
+ out:
+	/* Destroy the completed transaction */
+	ib_destroy_madx ( ibdev, ibdev->gsi, madx );
+	conn->madx = NULL;
+
+	/* Hand off to the upper completion handler */
+	conn->op->changed ( ibdev, qp, conn, rc, private_data,
+			    private_data_len );
+}
+
+/** Connection request operations */
+static struct ib_mad_transaction_operations ib_cm_req_op = {
+	.complete = ib_cm_req_complete,
+};
+
+/**
+ * Handle connection path transaction completion
+ *
+ * @v ibdev		Infiniband device
+ * @v path		Path
+ * @v rc		Status code
+ * @v av		Address vector, or NULL on error
+ */
+static void ib_cm_path_complete ( struct ib_device *ibdev,
+				  struct ib_path *path, int rc,
+				  struct ib_address_vector *av ) {
+	struct ib_connection *conn = ib_path_get_ownerdata ( path );
+	struct ib_queue_pair *qp = conn->qp;
+	union ib_mad mad;
+	struct ib_cm_connect_request *req = &mad.cm.cm_data.connect_request;
+	size_t private_data_len;
+
+	/* Report failures */
+	if ( rc != 0 ) {
+		DBGC ( conn, "CM %p path lookup failed: %s\n",
+		       conn, strerror ( rc ) );
+		conn->op->changed ( ibdev, qp, conn, rc, NULL, 0 );
+		goto out;
+	}
+
+	/* Update queue pair peer path */
+	memcpy ( &qp->av, av, sizeof ( qp->av ) );
+
+	/* Construct connection request */
+	memset ( &mad, 0, sizeof ( mad ) );
+	mad.hdr.mgmt_class = IB_MGMT_CLASS_CM;
+	mad.hdr.class_version = IB_CM_CLASS_VERSION;
+	mad.hdr.method = IB_MGMT_METHOD_SEND;
+	mad.hdr.attr_id = htons ( IB_CM_ATTR_CONNECT_REQUEST );
+	req->local_id = htonl ( conn->local_id );
+	memcpy ( &req->service_id, &conn->service_id,
+		 sizeof ( req->service_id ) );
+	memcpy ( &req->local_ca, &ibdev->node_guid, sizeof ( req->local_ca ) );
+	req->local_qpn__responder_resources = htonl ( ( qp->qpn << 8 ) | 1 );
+	req->local_eecn__initiator_depth = htonl ( ( 0 << 8 ) | 1 );
+	req->remote_eecn__remote_timeout__service_type__ee_flow_ctrl =
+		htonl ( ( 0x14 << 3 ) | ( IB_CM_TRANSPORT_RC << 1 ) |
+			( 0 << 0 ) );
+	req->starting_psn__local_timeout__retry_count =
+		htonl ( ( qp->recv.psn << 8 ) | ( 0x14 << 3 ) |
+			( 0x07 << 0 ) );
+	req->pkey = htons ( ibdev->pkey );
+	req->payload_mtu__rdc_exists__rnr_retry =
+		( ( IB_MTU_2048 << 4 ) | ( 1 << 3 ) | ( 0x07 << 0 ) );
+	req->max_cm_retries__srq = ( ( 0x0f << 4 ) | ( 0 << 3 ) );
+	req->primary.local_lid = htons ( ibdev->lid );
+	req->primary.remote_lid = htons ( conn->qp->av.lid );
+	memcpy ( &req->primary.local_gid, &ibdev->gid,
+		 sizeof ( req->primary.local_gid ) );
+	memcpy ( &req->primary.remote_gid, &conn->qp->av.gid,
+		 sizeof ( req->primary.remote_gid ) );
+	req->primary.flow_label__rate =
+		htonl ( ( 0 << 12 ) | ( conn->qp->av.rate << 0 ) );
+	req->primary.hop_limit = 0;
+	req->primary.sl__subnet_local =
+		( ( conn->qp->av.sl << 4 ) | ( 1 << 3 ) );
+	req->primary.local_ack_timeout = ( 0x13 << 3 );
+	private_data_len = conn->private_data_len;
+	if ( private_data_len > sizeof ( req->private_data ) )
+		private_data_len = sizeof ( req->private_data );
+	memcpy ( &req->private_data, &conn->private_data, private_data_len );
+
+	/* Create connection request */
+	av->qpn = IB_QPN_GSI;
+	av->qkey = IB_QKEY_GSI;
+	conn->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, av,
+				      &ib_cm_req_op );
+	if ( ! conn->madx ) {
+		DBGC ( conn, "CM %p could not create connection request\n",
+		       conn );
+		conn->op->changed ( ibdev, qp, conn, rc, NULL, 0 );
+		goto out;
+	}
+	ib_madx_set_ownerdata ( conn->madx, conn );
+
+ out:
+	/* Destroy the completed transaction */
+	ib_destroy_path ( ibdev, path );
+	conn->path = NULL;
+}
+
+/** Connection path operations */
+static struct ib_path_operations ib_cm_path_op = {
+	.complete = ib_cm_path_complete,
+};
+
+/**
+ * Create connection to remote QP
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v dgid		Target GID
+ * @v service_id	Target service ID
+ * @v private_data	Connection request private data
+ * @v private_data_len	Length of connection request private data
+ * @v op		Connection operations
+ * @ret conn		Connection
+ */
+struct ib_connection *
+ib_create_conn ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		 union ib_gid *dgid, union ib_guid *service_id,
+		 void *private_data, size_t private_data_len,
+		 struct ib_connection_operations *op ) {
+	struct ib_connection *conn;
+
+	/* Allocate and initialise request */
+	conn = zalloc ( sizeof ( *conn ) + private_data_len );
+	if ( ! conn )
+		goto err_alloc_conn;
+	conn->ibdev = ibdev;
+	conn->qp = qp;
+	memset ( &qp->av, 0, sizeof ( qp->av ) );
+	qp->av.gid_present = 1;
+	memcpy ( &qp->av.gid, dgid, sizeof ( qp->av.gid ) );
+	conn->local_id = random();
+	memcpy ( &conn->service_id, service_id, sizeof ( conn->service_id ) );
+	conn->op = op;
+	conn->private_data_len = private_data_len;
+	memcpy ( &conn->private_data, private_data, private_data_len );
+
+	/* Create path */
+	conn->path = ib_create_path ( ibdev, &qp->av, &ib_cm_path_op );
+	if ( ! conn->path )
+		goto err_create_path;
+	ib_path_set_ownerdata ( conn->path, conn );
+
+	/* Add to list of connections */
+	list_add ( &conn->list, &ib_cm_conns );
+
+	DBGC ( conn, "CM %p created for IBDEV %p QPN %lx\n",
+	       conn, ibdev, qp->qpn );
+	DBGC ( conn, "CM %p connecting to " IB_GID_FMT " " IB_GUID_FMT "\n",
+	       conn, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
+
+	return conn;
+
+	ib_destroy_path ( ibdev, conn->path );
+ err_create_path:
+	free ( conn );
+ err_alloc_conn:
+	return NULL;
+}
+
+/**
+ * Destroy connection to remote QP
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v conn		Connection
+ */
+void ib_destroy_conn ( struct ib_device *ibdev,
+		       struct ib_queue_pair *qp __unused,
+		       struct ib_connection *conn ) {
+
+	list_del ( &conn->list );
+	if ( conn->madx )
+		ib_destroy_madx ( ibdev, ibdev->gsi, conn->madx );
+	if ( conn->path )
+		ib_destroy_path ( ibdev, conn->path );
+	free ( conn );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cmrc.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cmrc.c
new file mode 100644
index 0000000..ed388b2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_cmrc.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2009 Fen Systems Ltd <mbrown at fensystems.co.uk>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   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 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 THE
+ * COPYRIGHT HOLDER 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.
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/process.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_cm.h>
+#include <ipxe/ib_cmrc.h>
+
+/**
+ * @file
+ *
+ * Infiniband Communication-managed Reliable Connections
+ *
+ */
+
+/** CMRC number of send WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_CMRC_NUM_SEND_WQES 4
+
+/** CMRC number of receive WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_CMRC_NUM_RECV_WQES 2
+
+/** CMRC number of completion queue entries
+ *
+ * This is a policy decision
+ */
+#define IB_CMRC_NUM_CQES 8
+
+/** An Infiniband Communication-Managed Reliable Connection */
+struct ib_cmrc_connection {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Infiniband device */
+	struct ib_device *ibdev;
+	/** Completion queue */
+	struct ib_completion_queue *cq;
+	/** Queue pair */
+	struct ib_queue_pair *qp;
+	/** Connection */
+	struct ib_connection *conn;
+	/** Destination GID */
+	union ib_gid dgid;
+	/** Service ID */
+	union ib_guid service_id;
+	/** QP is connected */
+	int connected;
+	/** Shutdown process */
+	struct process shutdown;
+};
+
+/**
+ * Shut down CMRC connection gracefully
+ *
+ * @v process		Process
+ *
+ * The Infiniband data structures are not reference-counted or
+ * guarded.  It is therefore unsafe to shut them down while we may be
+ * in the middle of a callback from the Infiniband stack (e.g. in a
+ * receive completion handler).
+ *
+ * This shutdown process will run some time after the call to
+ * ib_cmrc_close(), after control has returned out of the Infiniband
+ * core, and will shut down the Infiniband interfaces cleanly.
+ *
+ * The shutdown process holds an implicit reference on the CMRC
+ * connection, ensuring that the structure is not freed before the
+ * shutdown process has run.
+ */
+static void ib_cmrc_shutdown ( struct process *process ) {
+	struct ib_cmrc_connection *cmrc =
+		container_of ( process, struct ib_cmrc_connection, shutdown );
+
+	DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
+
+	/* Shut down Infiniband interface */
+	ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn );
+	ib_destroy_qp ( cmrc->ibdev, cmrc->qp );
+	ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
+	ib_close ( cmrc->ibdev );
+
+	/* Remove process from run queue */
+	process_del ( &cmrc->shutdown );
+
+	/* Drop the remaining reference */
+	ref_put ( &cmrc->refcnt );
+}
+
+/**
+ * Close CMRC connection
+ *
+ * @v cmrc		Communication-Managed Reliable Connection
+ * @v rc		Reason for close
+ */
+static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
+
+	/* Close data transfer interface */
+	intf_shutdown ( &cmrc->xfer, rc );
+
+	/* Schedule shutdown process */
+	process_add ( &cmrc->shutdown );
+}
+
+/**
+ * Handle change of CMRC connection status
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v conn		Connection
+ * @v rc_cm		Connection status code
+ * @v private_data	Private data, if available
+ * @v private_data_len	Length of private data
+ */
+static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
+			      struct ib_queue_pair *qp,
+			      struct ib_connection *conn __unused, int rc_cm,
+			      void *private_data, size_t private_data_len ) {
+	struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
+	int rc_xfer;
+
+	/* Record connection status */
+	if ( rc_cm == 0 ) {
+		DBGC ( cmrc, "CMRC %p connected\n", cmrc );
+		cmrc->connected = 1;
+	} else {
+		DBGC ( cmrc, "CMRC %p disconnected: %s\n",
+		       cmrc, strerror ( rc_cm ) );
+		cmrc->connected = 0;
+	}
+
+	/* Pass up any private data */
+	DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
+	DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
+	if ( private_data &&
+	     ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
+					    private_data_len ) ) != 0 ) {
+		DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
+		       cmrc, strerror ( rc_xfer ) );
+		ib_cmrc_close ( cmrc, rc_xfer );
+		return;
+	}
+
+	/* If we are disconnected, close the upper connection */
+	if ( rc_cm != 0 ) {
+		ib_cmrc_close ( cmrc, rc_cm );
+		return;
+	}
+}
+
+/** CMRC connection operations */
+static struct ib_connection_operations ib_cmrc_conn_op = {
+	.changed = ib_cmrc_changed,
+};
+
+/**
+ * Handle CMRC send completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
+				    struct ib_queue_pair *qp,
+				    struct io_buffer *iobuf, int rc ) {
+	struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
+
+	/* Free the completed I/O buffer */
+	free_iob ( iobuf );
+
+	/* Close the connection on any send errors */
+	if ( rc != 0 ) {
+		DBGC ( cmrc, "CMRC %p send error: %s\n",
+		       cmrc, strerror ( rc ) );
+		ib_cmrc_close ( cmrc, rc );
+		return;
+	}
+}
+
+/**
+ * Handle CMRC receive completion
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector, or NULL
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
+				    struct ib_queue_pair *qp,
+				    struct ib_address_vector *av __unused,
+				    struct io_buffer *iobuf, int rc ) {
+	struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
+
+	/* Close the connection on any receive errors */
+	if ( rc != 0 ) {
+		DBGC ( cmrc, "CMRC %p receive error: %s\n",
+		       cmrc, strerror ( rc ) );
+		free_iob ( iobuf );
+		ib_cmrc_close ( cmrc, rc );
+		return;
+	}
+
+	DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
+	DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
+
+	/* Pass up data */
+	if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
+		DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
+		       cmrc, strerror ( rc ) );
+		ib_cmrc_close ( cmrc, rc );
+		return;
+	}
+}
+
+/** Infiniband CMRC completion operations */
+static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
+	.complete_send = ib_cmrc_complete_send,
+	.complete_recv = ib_cmrc_complete_recv,
+};
+
+/**
+ * Send data via CMRC
+ *
+ * @v cmrc		CMRC connection
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int ib_cmrc_xfer_deliver ( struct ib_cmrc_connection *cmrc,
+				  struct io_buffer *iobuf,
+				  struct xfer_metadata *meta __unused ) {
+	int rc;
+
+	/* If no connection has yet been attempted, send this datagram
+	 * as the CM REQ private data.  Otherwise, send it via the QP.
+	 */
+	if ( ! cmrc->connected ) {
+
+		/* Abort if we have already sent a CM connection request */
+		if ( cmrc->conn ) {
+			DBGC ( cmrc, "CMRC %p attempt to send before "
+			       "connection is complete\n", cmrc );
+			rc = -EIO;
+			goto out;
+		}
+
+		/* Send via CM connection request */
+		cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
+					      &cmrc->dgid, &cmrc->service_id,
+					      iobuf->data, iob_len ( iobuf ),
+					      &ib_cmrc_conn_op );
+		if ( ! cmrc->conn ) {
+			DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
+			rc = -ENOMEM;
+			goto out;
+		}
+
+	} else {
+
+		/* Send via QP */
+		if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
+					   iob_disown ( iobuf ) ) ) != 0 ) {
+			DBGC ( cmrc, "CMRC %p could not send: %s\n",
+			       cmrc, strerror ( rc ) );
+			goto out;
+		}
+
+	}
+	return 0;
+
+ out:
+	/* Free the I/O buffer if necessary */
+	free_iob ( iobuf );
+
+	/* Close the connection on any errors */
+	if ( rc != 0 )
+		ib_cmrc_close ( cmrc, rc );
+
+	return rc;
+}
+
+/**
+ * Check CMRC flow control window
+ *
+ * @v cmrc		CMRC connection
+ * @ret len		Length of window
+ */
+static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) {
+
+	/* We indicate a window only when we are successfully
+	 * connected.
+	 */
+	return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
+}
+
+/**
+ * Identify device underlying CMRC connection
+ *
+ * @v cmrc		CMRC connection
+ * @ret device		Underlying device
+ */
+static struct device *
+ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) {
+	return cmrc->ibdev->dev;
+}
+
+/** CMRC data transfer interface operations */
+static struct interface_operation ib_cmrc_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct ib_cmrc_connection *,
+		  ib_cmrc_xfer_deliver ),
+	INTF_OP ( xfer_window, struct ib_cmrc_connection *,
+		  ib_cmrc_xfer_window ),
+	INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ),
+	INTF_OP ( identify_device, struct ib_cmrc_connection *,
+		  ib_cmrc_identify_device ),
+};
+
+/** CMRC data transfer interface descriptor */
+static struct interface_descriptor ib_cmrc_xfer_desc =
+	INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
+
+/**
+ * Open CMRC connection
+ *
+ * @v xfer		Data transfer interface
+ * @v ibdev		Infiniband device
+ * @v dgid		Destination GID
+ * @v service_id	Service ID
+ * @ret rc		Returns status code
+ */
+int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
+		   union ib_gid *dgid, union ib_guid *service_id ) {
+	struct ib_cmrc_connection *cmrc;
+	int rc;
+
+	/* Allocate and initialise structure */
+	cmrc = zalloc ( sizeof ( *cmrc ) );
+	if ( ! cmrc ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	ref_init ( &cmrc->refcnt, NULL );
+	intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt );
+	cmrc->ibdev = ibdev;
+	memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
+	memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
+	process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
+			       &cmrc->refcnt );
+
+	/* Open Infiniband device */
+	if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
+		DBGC ( cmrc, "CMRC %p could not open device: %s\n",
+		       cmrc, strerror ( rc ) );
+		goto err_open;
+	}
+
+	/* Create completion queue */
+	cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
+				  &ib_cmrc_completion_ops );
+	if ( ! cmrc->cq ) {
+		DBGC ( cmrc, "CMRC %p could not create completion queue\n",
+		       cmrc );
+		rc = -ENOMEM;
+		goto err_create_cq;
+	}
+
+	/* Create queue pair */
+	cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
+				  cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
+	if ( ! cmrc->qp ) {
+		DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
+		rc = -ENOMEM;
+		goto err_create_qp;
+	}
+	ib_qp_set_ownerdata ( cmrc->qp, cmrc );
+	DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
+
+	/* Attach to parent interface, transfer reference (implicitly)
+	 * to our shutdown process, and return.
+	 */
+	intf_plug_plug ( &cmrc->xfer, xfer );
+	return 0;
+
+	ib_destroy_qp ( ibdev, cmrc->qp );
+ err_create_qp:
+	ib_destroy_cq ( ibdev, cmrc->cq );
+ err_create_cq:
+	ib_close ( ibdev );
+ err_open:
+	ref_put ( &cmrc->refcnt );
+ err_alloc:
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mcast.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mcast.c
new file mode 100644
index 0000000..0f03b54
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mcast.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/list.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_mi.h>
+#include <ipxe/ib_mcast.h>
+
+/** @file
+ *
+ * Infiniband multicast groups
+ *
+ */
+
+/**
+ * Generate multicast membership MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v gid		Multicast GID
+ * @v join		Join (rather than leave) group
+ * @v mad		MAD to fill in
+ */
+static void ib_mcast_mad ( struct ib_device *ibdev, union ib_gid *gid,
+			   int join, union ib_mad *mad ) {
+	struct ib_mad_sa *sa = &mad->sa;
+
+	/* Construct multicast membership record request */
+	memset ( sa, 0, sizeof ( *sa ) );
+	sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+	sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
+	sa->mad_hdr.method =
+		( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
+	sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
+	sa->sa_hdr.comp_mask[1] =
+		htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
+			IB_SA_MCMEMBER_REC_JOIN_STATE );
+	sa->sa_data.mc_member_record.scope__join_state = 1;
+	memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
+		 sizeof ( sa->sa_data.mc_member_record.mgid ) );
+	memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
+		 sizeof ( sa->sa_data.mc_member_record.port_gid ) );
+}
+
+/**
+ * Handle multicast membership record join response
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v madx		Management transaction
+ * @v rc		Status code
+ * @v mad		Received MAD (or NULL on error)
+ * @v av		Source address vector (or NULL on error)
+ */
+static void ib_mcast_complete ( struct ib_device *ibdev,
+				struct ib_mad_interface *mi __unused,
+				struct ib_mad_transaction *madx,
+				int rc, union ib_mad *mad,
+				struct ib_address_vector *av __unused ) {
+	struct ib_mc_membership *membership = ib_madx_get_ownerdata ( madx );
+	struct ib_queue_pair *qp = membership->qp;
+	union ib_gid *gid = &membership->gid;
+	struct ib_mc_member_record *mc_member_record =
+		&mad->sa.sa_data.mc_member_record;
+	int joined;
+	unsigned long qkey;
+
+	/* Report failures */
+	if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
+		rc = -ENOTCONN;
+	if ( rc != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %lx join failed: %s\n",
+		       ibdev, qp->qpn, strerror ( rc ) );
+		goto out;
+	}
+
+	/* Extract values from MAD */
+	joined = ( mad->hdr.method == IB_MGMT_METHOD_GET_RESP );
+	qkey = ntohl ( mc_member_record->qkey );
+	DBGC ( ibdev, "IBDEV %p QPN %lx %s " IB_GID_FMT " qkey %lx\n",
+	       ibdev, qp->qpn, ( joined ? "joined" : "left" ),
+	       IB_GID_ARGS ( gid ), qkey );
+
+	/* Set queue key */
+	qp->qkey = qkey;
+	if ( ( rc = ib_modify_qp ( ibdev, qp ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %lx could not modify qkey: %s\n",
+		       ibdev, qp->qpn, strerror ( rc ) );
+		goto out;
+	}
+
+ out:
+	/* Destroy the completed transaction */
+	ib_destroy_madx ( ibdev, mi, madx );
+	membership->madx = NULL;
+
+	/* Hand off to upper completion handler */
+	membership->complete ( ibdev, qp, membership, rc, mad );
+}
+
+/** Multicast membership management transaction completion operations */
+static struct ib_mad_transaction_operations ib_mcast_op = {
+	.complete = ib_mcast_complete,
+};
+
+/**
+ * Join multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v membership	Multicast group membership
+ * @v gid		Multicast GID to join
+ * @v joined		Join completion handler
+ * @ret rc		Return status code
+ */
+int ib_mcast_join ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		    struct ib_mc_membership *membership, union ib_gid *gid,
+		    void ( * complete ) ( struct ib_device *ibdev,
+					  struct ib_queue_pair *qp,
+					  struct ib_mc_membership *membership,
+					  int rc, union ib_mad *mad ) ) {
+	union ib_mad mad;
+	int rc;
+
+	DBGC ( ibdev, "IBDEV %p QPN %lx joining " IB_GID_FMT "\n",
+	       ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
+
+	/* Initialise structure */
+	membership->qp = qp;
+	memcpy ( &membership->gid, gid, sizeof ( membership->gid ) );
+	membership->complete = complete;
+
+	/* Attach queue pair to multicast GID */
+	if ( ( rc = ib_mcast_attach ( ibdev, qp, gid ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %lx could not attach: %s\n",
+		       ibdev, qp->qpn, strerror ( rc ) );
+		goto err_mcast_attach;
+	}
+
+	/* Initiate multicast membership join */
+	ib_mcast_mad ( ibdev, gid, 1, &mad );
+	membership->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL,
+					    &ib_mcast_op );
+	if ( ! membership->madx ) {
+		DBGC ( ibdev, "IBDEV %p QPN %lx could not create join "
+		       "transaction\n", ibdev, qp->qpn );
+		rc = -ENOMEM;
+		goto err_create_madx;
+	}
+	ib_madx_set_ownerdata ( membership->madx, membership );
+
+	return 0;
+
+	ib_destroy_madx ( ibdev, ibdev->gsi, membership->madx );
+ err_create_madx:
+	ib_mcast_detach ( ibdev, qp, gid );
+ err_mcast_attach:
+	return rc;
+}
+
+/**
+ * Leave multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v membership	Multicast group membership
+ */
+void ib_mcast_leave ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+		      struct ib_mc_membership *membership ) {
+	union ib_gid *gid = &membership->gid;
+	union ib_mad mad;
+	int rc;
+
+	DBGC ( ibdev, "IBDEV %p QPN %lx leaving " IB_GID_FMT "\n",
+	       ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
+
+	/* Detach from multicast GID */
+	ib_mcast_detach ( ibdev, qp, &membership->gid );
+
+	/* Cancel multicast membership join, if applicable */
+	if ( membership->madx ) {
+		ib_destroy_madx ( ibdev, ibdev->gsi, membership->madx );
+		membership->madx = NULL;
+	}
+
+	/* Send a single group leave MAD */
+	ib_mcast_mad ( ibdev, &membership->gid, 0, &mad );
+	if ( ( rc = ib_mi_send ( ibdev, ibdev->gsi, &mad, NULL ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p QPN %lx could not send leave request: "
+		       "%s\n", ibdev, qp->qpn, strerror ( rc ) );
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mi.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mi.c
new file mode 100644
index 0000000..d4cf58a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_mi.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ib_mi.h>
+
+/**
+ * @file
+ *
+ * Infiniband management interfaces
+ *
+ */
+
+/** Management interface number of send WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_MI_NUM_SEND_WQES 4
+
+/** Management interface number of receive WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_MI_NUM_RECV_WQES 2
+
+/** Management interface number of completion queue entries
+ *
+ * This is a policy decision
+ */
+#define IB_MI_NUM_CQES 8
+
+/** TID magic signature */
+#define IB_MI_TID_MAGIC ( ( 'i' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
+
+/** TID to use for next MAD */
+static unsigned int next_tid;
+
+/**
+ * Handle received MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ * @ret rc		Return status code
+ */
+static int ib_mi_handle ( struct ib_device *ibdev,
+			  struct ib_mad_interface *mi,
+			  union ib_mad *mad,
+			  struct ib_address_vector *av ) {
+	struct ib_mad_hdr *hdr = &mad->hdr;
+	struct ib_mad_transaction *madx;
+	struct ib_mad_agent *agent;
+
+	/* Look for a matching transaction by TID */
+	list_for_each_entry ( madx, &mi->madx, list ) {
+		if ( memcmp ( &hdr->tid, &madx->mad.hdr.tid,
+			      sizeof ( hdr->tid ) ) != 0 )
+			continue;
+		/* Found a matching transaction */
+		madx->op->complete ( ibdev, mi, madx, 0, mad, av );
+		return 0;
+	}
+
+	/* If there is no matching transaction, look for a listening agent */
+	for_each_table_entry ( agent, IB_MAD_AGENTS ) {
+		if ( ( ( agent->mgmt_class & IB_MGMT_CLASS_MASK ) !=
+		       ( hdr->mgmt_class & IB_MGMT_CLASS_MASK ) ) ||
+		     ( agent->class_version != hdr->class_version ) ||
+		     ( agent->attr_id != hdr->attr_id ) )
+			continue;
+		/* Found a matching agent */
+		agent->handle ( ibdev, mi, mad, av );
+		return 0;
+	}
+
+	/* Otherwise, ignore it */
+	DBGC ( mi, "MI %p RX TID %08x%08x ignored\n",
+	       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
+	return -ENOTSUP;
+}
+
+/**
+ * Complete receive via management interface
+ *
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v av		Address vector
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
+ */
+static void ib_mi_complete_recv ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp,
+				  struct ib_address_vector *av,
+				  struct io_buffer *iobuf, int rc ) {
+	struct ib_mad_interface *mi = ib_qp_get_ownerdata ( qp );
+	union ib_mad *mad;
+	struct ib_mad_hdr *hdr;
+
+	/* Ignore errors */
+	if ( rc != 0 ) {
+		DBGC ( mi, "MI %p RX error: %s\n", mi, strerror ( rc ) );
+		goto out;
+	}
+
+	/* Sanity checks */
+	if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
+		DBGC ( mi, "MI %p RX bad size (%zd bytes)\n",
+		       mi, iob_len ( iobuf ) );
+		DBGC_HDA ( mi, 0, iobuf->data, iob_len ( iobuf ) );
+		goto out;
+	}
+	mad = iobuf->data;
+	hdr = &mad->hdr;
+	if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
+		DBGC ( mi, "MI %p RX unsupported base version %x\n",
+		       mi, hdr->base_version );
+		DBGC_HDA ( mi, 0, mad, sizeof ( *mad ) );
+		goto out;
+	}
+	DBGC ( mi, "MI %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
+	       "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
+	       hdr->mgmt_class, hdr->class_version, hdr->method,
+	       ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
+	DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
+
+	/* Handle MAD */
+	if ( ( rc = ib_mi_handle ( ibdev, mi, mad, av ) ) != 0 )
+		goto out;
+
+ out:
+	free_iob ( iobuf );
+}
+
+/** Management interface completion operations */
+static struct ib_completion_queue_operations ib_mi_completion_ops = {
+	.complete_recv = ib_mi_complete_recv,
+};
+
+/**
+ * Transmit MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		MAD
+ * @v av		Destination address vector
+ * @ret rc		Return status code
+ */
+int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
+		 union ib_mad *mad, struct ib_address_vector *av ) {
+	struct ib_mad_hdr *hdr = &mad->hdr;
+	struct io_buffer *iobuf;
+	int rc;
+
+	/* Set common fields */
+	hdr->base_version = IB_MGMT_BASE_VERSION;
+	if ( ( hdr->tid[0] == 0 ) && ( hdr->tid[1] == 0 ) ) {
+		hdr->tid[0] = htonl ( IB_MI_TID_MAGIC );
+		hdr->tid[1] = htonl ( ++next_tid );
+	}
+	DBGC ( mi, "MI %p TX TID %08x%08x (%02x,%02x,%02x,%04x) status "
+	       "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
+	       hdr->mgmt_class, hdr->class_version, hdr->method,
+	       ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
+	DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
+
+	/* Construct directed route portion of response, if necessary */
+	if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
+		struct ib_mad_smp *smp = &mad->smp;
+		unsigned int hop_pointer;
+		unsigned int hop_count;
+
+		smp->mad_hdr.status |= htons ( IB_SMP_STATUS_D_INBOUND );
+		hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
+		hop_count = smp->mad_hdr.class_specific.smp.hop_count;
+		assert ( hop_count == hop_pointer );
+		if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
+				     sizeof ( smp->return_path.hops[0] ) ) ) {
+			smp->return_path.hops[hop_pointer] = ibdev->port;
+		} else {
+			DBGC ( mi, "MI %p TX TID %08x%08x invalid hop pointer "
+			       "%d\n", mi, ntohl ( hdr->tid[0] ),
+			       ntohl ( hdr->tid[1] ), hop_pointer );
+			return -EINVAL;
+		}
+	}
+
+	/* Construct I/O buffer */
+	iobuf = alloc_iob ( sizeof ( *mad ) );
+	if ( ! iobuf ) {
+		DBGC ( mi, "MI %p could not allocate buffer for TID "
+		       "%08x%08x\n",
+		       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
+		return -ENOMEM;
+	}
+	memcpy ( iob_put ( iobuf, sizeof ( *mad ) ), mad, sizeof ( *mad ) );
+
+	/* Send I/O buffer */
+	if ( ( rc = ib_post_send ( ibdev, mi->qp, av, iobuf ) ) != 0 ) {
+		DBGC ( mi, "MI %p TX TID %08x%08x failed: %s\n",
+		       mi,  ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
+		       strerror ( rc ) );
+		free_iob ( iobuf );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle management transaction timer expiry
+ *
+ * @v timer		Retry timer
+ * @v expired		Failure indicator
+ */
+static void ib_mi_timer_expired ( struct retry_timer *timer, int expired ) {
+	struct ib_mad_transaction *madx =
+		container_of ( timer, struct ib_mad_transaction, timer );
+	struct ib_mad_interface *mi = madx->mi;
+	struct ib_device *ibdev = mi->ibdev;
+	struct ib_mad_hdr *hdr = &madx->mad.hdr;
+
+	/* Abandon transaction if we have tried too many times */
+	if ( expired ) {
+		DBGC ( mi, "MI %p abandoning TID %08x%08x\n",
+		       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
+		madx->op->complete ( ibdev, mi, madx, -ETIMEDOUT, NULL, NULL );
+		return;
+	}
+
+	/* Restart retransmission timer */
+	start_timer ( timer );
+
+	/* Resend MAD */
+	ib_mi_send ( ibdev, mi, &madx->mad, &madx->av );
+}
+
+/**
+ * Create management transaction
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		MAD to send
+ * @v av		Destination address, or NULL to use SM's GSI
+ * @v op		Management transaction operations
+ * @ret madx		Management transaction, or NULL
+ */
+struct ib_mad_transaction *
+ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
+		 union ib_mad *mad, struct ib_address_vector *av,
+		 struct ib_mad_transaction_operations *op ) {
+	struct ib_mad_transaction *madx;
+
+	/* Allocate and initialise structure */
+	madx = zalloc ( sizeof ( *madx ) );
+	if ( ! madx )
+		return NULL;
+	timer_init ( &madx->timer, ib_mi_timer_expired, NULL );
+	madx->mi = mi;
+	madx->op = op;
+
+	/* Determine address vector */
+	if ( av ) {
+		memcpy ( &madx->av, av, sizeof ( madx->av ) );
+	} else {
+		madx->av.lid = ibdev->sm_lid;
+		madx->av.sl = ibdev->sm_sl;
+		madx->av.qpn = IB_QPN_GSI;
+		madx->av.qkey = IB_QKEY_GSI;
+	}
+
+	/* Copy MAD */
+	memcpy ( &madx->mad, mad, sizeof ( madx->mad ) );
+
+	/* Add to list and start timer to send initial MAD */
+	list_add ( &madx->list, &mi->madx );
+	start_timer_nodelay ( &madx->timer );
+
+	return madx;
+}
+
+/**
+ * Destroy management transaction
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v madx		Management transaction
+ */
+void ib_destroy_madx ( struct ib_device *ibdev __unused,
+		       struct ib_mad_interface *mi __unused,
+		       struct ib_mad_transaction *madx ) {
+
+	/* Stop timer and remove from list */
+	stop_timer ( &madx->timer );
+	list_del ( &madx->list );
+
+	/* Free transaction */
+	free ( madx );
+}
+
+/**
+ * Create management interface
+ *
+ * @v ibdev		Infiniband device
+ * @v type		Queue pair type
+ * @ret mi		Management agent, or NULL
+ */
+struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
+					 enum ib_queue_pair_type type ) {
+	struct ib_mad_interface *mi;
+	int rc;
+
+	/* Allocate and initialise fields */
+	mi = zalloc ( sizeof ( *mi ) );
+	if ( ! mi )
+		goto err_alloc;
+	mi->ibdev = ibdev;
+	INIT_LIST_HEAD ( &mi->madx );
+
+	/* Create completion queue */
+	mi->cq = ib_create_cq ( ibdev, IB_MI_NUM_CQES, &ib_mi_completion_ops );
+	if ( ! mi->cq ) {
+		DBGC ( mi, "MI %p could not allocate completion queue\n", mi );
+		goto err_create_cq;
+	}
+
+	/* Create queue pair */
+	mi->qp = ib_create_qp ( ibdev, type, IB_MI_NUM_SEND_WQES, mi->cq,
+				IB_MI_NUM_RECV_WQES, mi->cq );
+	if ( ! mi->qp ) {
+		DBGC ( mi, "MI %p could not allocate queue pair\n", mi );
+		goto err_create_qp;
+	}
+	ib_qp_set_ownerdata ( mi->qp, mi );
+	DBGC ( mi, "MI %p (%s) running on QPN %#lx\n",
+	       mi, ( ( type == IB_QPT_SMI ) ? "SMI" : "GSI" ), mi->qp->qpn );
+
+	/* Set queue key */
+	mi->qp->qkey = ( ( type == IB_QPT_SMI ) ? IB_QKEY_SMI : IB_QKEY_GSI );
+	if ( ( rc = ib_modify_qp ( ibdev, mi->qp ) ) != 0 ) {
+		DBGC ( mi, "MI %p could not set queue key: %s\n",
+		       mi, strerror ( rc ) );
+		goto err_modify_qp;
+	}
+
+	/* Fill receive ring */
+	ib_refill_recv ( ibdev, mi->qp );
+	return mi;
+
+ err_modify_qp:
+	ib_destroy_qp ( ibdev, mi->qp );
+ err_create_qp:
+	ib_destroy_cq ( ibdev, mi->cq );
+ err_create_cq:
+	free ( mi );
+ err_alloc:
+	return NULL;
+}
+
+/**
+ * Destroy management interface
+ *
+ * @v mi		Management interface
+ */
+void ib_destroy_mi ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
+	struct ib_mad_transaction *madx;
+	struct ib_mad_transaction *tmp;
+
+	/* Flush any outstanding requests */
+	list_for_each_entry_safe ( madx, tmp, &mi->madx, list ) {
+		DBGC ( mi, "MI %p destroyed while TID %08x%08x in progress\n",
+		       mi, ntohl ( madx->mad.hdr.tid[0] ),
+		       ntohl ( madx->mad.hdr.tid[1] ) );
+		madx->op->complete ( ibdev, mi, madx, -ECANCELED, NULL, NULL );
+	}
+
+	ib_destroy_qp ( ibdev, mi->qp );
+	ib_destroy_cq ( ibdev, mi->cq );
+	free ( mi );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_packet.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_packet.c
new file mode 100644
index 0000000..d58e0ad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_packet.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_packet.h>
+
+/**
+ * @file
+ *
+ * Infiniband Packet Formats
+ *
+ */
+
+/**
+ * Add IB headers
+ *
+ * @v ibdev		Infiniband device
+ * @v iobuf		I/O buffer to contain headers
+ * @v qp		Queue pair
+ * @v payload_len	Payload length
+ * @v av		Address vector
+ */
+int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+	      struct ib_queue_pair *qp, size_t payload_len,
+	      const struct ib_address_vector *av ) {
+	struct ib_local_route_header *lrh;
+	struct ib_global_route_header *grh;
+	struct ib_base_transport_header *bth;
+	struct ib_datagram_extended_transport_header *deth;
+	size_t orig_iob_len = iob_len ( iobuf );
+	size_t pad_len;
+	size_t lrh_len;
+	size_t grh_len;
+	unsigned int vl;
+	unsigned int lnh;
+
+	DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
+		ibdev, ibdev->lid, qp->ext_qpn, av->lid, av->qpn, av->qkey );
+
+	/* Calculate packet length */
+	pad_len = ( (-payload_len) & 0x3 );
+	payload_len += pad_len;
+	payload_len += 4; /* ICRC */
+
+	/* Reserve space for headers */
+	orig_iob_len = iob_len ( iobuf );
+	deth = iob_push ( iobuf, sizeof ( *deth ) );
+	bth = iob_push ( iobuf, sizeof ( *bth ) );
+	grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+	grh = ( av->gid_present ?
+		iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
+	lrh = iob_push ( iobuf, sizeof ( *lrh ) );
+	lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+
+	/* Construct LRH */
+	vl = ( ( qp->ext_qpn == IB_QPN_SMI ) ? IB_VL_SMP : IB_VL_DEFAULT );
+	lrh->vl__lver = ( vl << 4 );
+	lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
+	lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
+	lrh->dlid = htons ( av->lid );
+	lrh->length = htons ( lrh_len >> 2 );
+	lrh->slid = htons ( ibdev->lid );
+
+	/* Construct GRH, if required */
+	if ( grh ) {
+		grh->ipver__tclass__flowlabel =
+			htonl ( IB_GRH_IPVER_IPv6 << 28 );
+		grh->paylen = htons ( grh_len );
+		grh->nxthdr = IB_GRH_NXTHDR_IBA;
+		grh->hoplmt = 0;
+		memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
+		memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
+	}
+
+	/* Construct BTH */
+	bth->opcode = BTH_OPCODE_UD_SEND;
+	bth->se__m__padcnt__tver = ( pad_len << 4 );
+	bth->pkey = htons ( ibdev->pkey );
+	bth->dest_qp = htonl ( av->qpn );
+	bth->ack__psn = htonl ( ( qp->send.psn++ ) & 0xffffffUL );
+
+	/* Construct DETH */
+	deth->qkey = htonl ( av->qkey );
+	deth->src_qp = htonl ( qp->ext_qpn );
+
+	DBGCP_HDA ( ibdev, 0, iobuf->data,
+		    ( iob_len ( iobuf ) - orig_iob_len ) );
+
+	return 0;
+}
+
+/**
+ * Remove IB headers
+ *
+ * @v ibdev		Infiniband device
+ * @v iobuf		I/O buffer containing headers
+ * @v qp		Queue pair to fill in, or NULL
+ * @v payload_len	Payload length to fill in, or NULL
+ * @v av		Address vector to fill in
+ */
+int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+	      struct ib_queue_pair **qp, size_t *payload_len,
+	      struct ib_address_vector *av ) {
+	struct ib_local_route_header *lrh;
+	struct ib_global_route_header *grh;
+	struct ib_base_transport_header *bth;
+	struct ib_datagram_extended_transport_header *deth;
+	size_t orig_iob_len = iob_len ( iobuf );
+	unsigned int lnh;
+	size_t pad_len;
+	unsigned long qpn;
+	unsigned int lid;
+
+	/* Clear return values */
+	if ( qp )
+		*qp = NULL;
+	if ( payload_len )
+		*payload_len = 0;
+	memset ( av, 0, sizeof ( *av ) );
+
+	/* Extract LRH */
+	if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
+		       ibdev, iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+	lrh = iobuf->data;
+	iob_pull ( iobuf, sizeof ( *lrh ) );
+	av->lid = ntohs ( lrh->slid );
+	av->sl = ( lrh->sl__lnh >> 4 );
+	lnh = ( lrh->sl__lnh & 0x3 );
+	lid = ntohs ( lrh->dlid );
+
+	/* Reject unsupported packets */
+	if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
+		DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
+		       ibdev, lnh );
+		return -ENOTSUP;
+	}
+
+	/* Extract GRH, if present */
+	if ( lnh == IB_LNH_GRH ) {
+		if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
+			DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
+			       "for GRH\n", ibdev, iob_len ( iobuf ) );
+			return -EINVAL;
+		}
+		grh = iobuf->data;
+		iob_pull ( iobuf, sizeof ( *grh ) );
+		av->gid_present = 1;
+		memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+	} else {
+		grh = NULL;
+	}
+
+	/* Extract BTH */
+	if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
+		       ibdev, iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+	bth = iobuf->data;
+	iob_pull ( iobuf, sizeof ( *bth ) );
+	if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
+		DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
+		       ibdev, bth->opcode );
+		return -ENOTSUP;
+	}
+	qpn = ntohl ( bth->dest_qp );
+
+	/* Extract DETH */
+	if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
+		       ibdev, iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+	deth = iobuf->data;
+	iob_pull ( iobuf, sizeof ( *deth ) );
+	av->qpn = ntohl ( deth->src_qp );
+	av->qkey = ntohl ( deth->qkey );
+
+	/* Calculate payload length, if applicable */
+	if ( payload_len ) {
+		pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
+		*payload_len = ( ( ntohs ( lrh->length ) << 2 )
+				 - ( orig_iob_len - iob_len ( iobuf ) )
+				 - pad_len - 4 /* ICRC */ );
+	}
+
+	/* Determine destination QP, if applicable */
+	if ( qp ) {
+		if ( IB_LID_MULTICAST ( lid ) && grh ) {
+			if ( ! ( *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ))){
+				DBGC ( ibdev, "IBDEV %p RX for unknown MGID "
+				       IB_GID_FMT "\n",
+				       ibdev, IB_GID_ARGS ( &grh->dgid ) );
+				return -ENODEV;
+			}
+		} else {
+			if ( ! ( *qp = ib_find_qp_qpn ( ibdev, qpn ) ) ) {
+				DBGC ( ibdev, "IBDEV %p RX for nonexistent "
+				       "QPN %lx\n", ibdev, qpn );
+				return -ENODEV;
+			}
+		}
+		assert ( *qp );
+	}
+
+	DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
+		ibdev, lid, ( IB_LID_MULTICAST( lid ) ?
+			      ( qp ? (*qp)->ext_qpn : -1UL ) : qpn ),
+		av->lid, av->qpn, ntohl ( deth->qkey ) );
+	DBGCP_HDA ( ibdev, 0,
+		    ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
+		    ( orig_iob_len - iob_len ( iobuf ) ) );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_pathrec.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_pathrec.c
new file mode 100644
index 0000000..7b91465
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_pathrec.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_mi.h>
+#include <ipxe/ib_pathrec.h>
+
+/** @file
+ *
+ * Infiniband path lookups
+ *
+ */
+
+/**
+ * Handle path transaction completion
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v madx		Management transaction
+ * @v rc		Status code
+ * @v mad		Received MAD (or NULL on error)
+ * @v av		Source address vector (or NULL on error)
+ */
+static void ib_path_complete ( struct ib_device *ibdev,
+			       struct ib_mad_interface *mi,
+			       struct ib_mad_transaction *madx,
+			       int rc, union ib_mad *mad,
+			       struct ib_address_vector *av __unused ) {
+	struct ib_path *path = ib_madx_get_ownerdata ( madx );
+	union ib_gid *dgid = &path->av.gid;
+	struct ib_path_record *pathrec = &mad->sa.sa_data.path_record;
+
+	/* Report failures */
+	if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
+		rc = -ENETUNREACH;
+	if ( rc != 0 ) {
+		DBGC ( ibdev, "IBDEV %p path lookup for " IB_GID_FMT
+		       " failed: %s\n",
+		       ibdev, IB_GID_ARGS ( dgid ), strerror ( rc ) );
+		goto out;
+	}
+
+	/* Extract values from MAD */
+	path->av.lid = ntohs ( pathrec->dlid );
+	path->av.sl = ( pathrec->reserved__sl & 0x0f );
+	path->av.rate = ( pathrec->rate_selector__rate & 0x3f );
+	DBGC ( ibdev, "IBDEV %p path to " IB_GID_FMT " is %04x sl %d rate "
+	       "%d\n", ibdev, IB_GID_ARGS ( dgid ), path->av.lid, path->av.sl,
+	       path->av.rate );
+
+ out:
+	/* Destroy the completed transaction */
+	ib_destroy_madx ( ibdev, mi, madx );
+	path->madx = NULL;
+
+	/* Hand off to upper completion handler */
+	path->op->complete ( ibdev, path, rc, &path->av );
+}
+
+/** Path transaction completion operations */
+static struct ib_mad_transaction_operations ib_path_op = {
+	.complete = ib_path_complete,
+};
+
+/**
+ * Create path
+ *
+ * @v ibdev		Infiniband device
+ * @v av		Address vector to complete
+ * @v op		Path operations
+ * @ret path		Path
+ */
+struct ib_path *
+ib_create_path ( struct ib_device *ibdev, struct ib_address_vector *av,
+		 struct ib_path_operations *op ) {
+	struct ib_path *path;
+	union ib_mad mad;
+	struct ib_mad_sa *sa = &mad.sa;
+
+	/* Allocate and initialise structure */
+	path = zalloc ( sizeof ( *path ) );
+	if ( ! path )
+		goto err_alloc_path;
+	path->ibdev = ibdev;
+	memcpy ( &path->av, av, sizeof ( path->av ) );
+	path->op = op;
+
+	/* Construct path request */
+	memset ( sa, 0, sizeof ( *sa ) );
+	sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+	sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
+	sa->mad_hdr.method = IB_MGMT_METHOD_GET;
+	sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
+	sa->sa_hdr.comp_mask[1] =
+		htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
+	memcpy ( &sa->sa_data.path_record.dgid, &path->av.gid,
+		 sizeof ( sa->sa_data.path_record.dgid ) );
+	memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
+		 sizeof ( sa->sa_data.path_record.sgid ) );
+
+	/* Create management transaction */
+	path->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL,
+				      &ib_path_op );
+	if ( ! path->madx )
+		goto err_create_madx;
+	ib_madx_set_ownerdata ( path->madx, path );
+
+	return path;
+
+	ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
+ err_create_madx:
+	free ( path );
+ err_alloc_path:
+	return NULL;
+}
+
+/**
+ * Destroy path
+ *
+ * @v ibdev		Infiniband device
+ * @v path		Path
+ */
+void ib_destroy_path ( struct ib_device *ibdev, struct ib_path *path ) {
+
+	if ( path->madx )
+		ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
+	free ( path );
+}
+
+/** Number of path cache entries
+ *
+ * Must be a power of two.
+ */
+#define IB_NUM_CACHED_PATHS 4
+
+/** A cached path */
+struct ib_cached_path {
+	/** Path */
+	struct ib_path *path;
+};
+
+/** Path cache */
+static struct ib_cached_path ib_path_cache[IB_NUM_CACHED_PATHS];
+
+/** Oldest path cache entry index */
+static unsigned int ib_path_cache_idx;
+
+/**
+ * Find path cache entry
+ *
+ * @v ibdev		Infiniband device
+ * @v dgid		Destination GID
+ * @ret path		Path cache entry, or NULL
+ */
+static struct ib_cached_path *
+ib_find_path_cache_entry ( struct ib_device *ibdev, union ib_gid *dgid ) {
+	struct ib_cached_path *cached;
+	unsigned int i;
+
+	for ( i = 0 ; i < IB_NUM_CACHED_PATHS ; i++ ) {
+		cached = &ib_path_cache[i];
+		if ( ! cached->path )
+			continue;
+		if ( cached->path->ibdev != ibdev )
+			continue;
+		if ( memcmp ( &cached->path->av.gid, dgid,
+			      sizeof ( cached->path->av.gid ) ) != 0 )
+			continue;
+		return cached;
+	}
+
+	return NULL;
+}
+
+/**
+ * Handle cached path transaction completion
+ *
+ * @v ibdev		Infiniband device
+ * @v path		Path
+ * @v rc		Status code
+ * @v av		Address vector, or NULL on error
+ */
+static void ib_cached_path_complete ( struct ib_device *ibdev,
+				      struct ib_path *path, int rc,
+				      struct ib_address_vector *av __unused ) {
+	struct ib_cached_path *cached = ib_path_get_ownerdata ( path );
+
+	/* If the transaction failed, erase the cache entry */
+	if ( rc != 0 ) {
+		/* Destroy the old cache entry */
+		ib_destroy_path ( ibdev, path );
+		memset ( cached, 0, sizeof ( *cached ) );
+		return;
+	}
+
+	/* Do not destroy the completed transaction; we still need to
+	 * refer to the resolved path.
+	 */
+}
+
+/** Cached path transaction completion operations */
+static struct ib_path_operations ib_cached_path_op = {
+	.complete = ib_cached_path_complete,
+};
+
+/**
+ * Resolve path
+ *
+ * @v ibdev		Infiniband device
+ * @v av		Address vector to complete
+ * @ret rc		Return status code
+ *
+ * This provides a non-transactional way to resolve a path, via a
+ * cache similar to ARP.
+ */
+int ib_resolve_path ( struct ib_device *ibdev, struct ib_address_vector *av ) {
+	union ib_gid *gid = &av->gid;
+	struct ib_cached_path *cached;
+	unsigned int cache_idx;
+
+	/* Sanity check */
+	if ( ! av->gid_present ) {
+		DBGC ( ibdev, "IBDEV %p attempt to look up path without GID\n",
+		       ibdev );
+		return -EINVAL;
+	}
+
+	/* Look in cache for a matching entry */
+	cached = ib_find_path_cache_entry ( ibdev, gid );
+	if ( cached && cached->path->av.lid ) {
+		/* Populated entry found */
+		av->lid = cached->path->av.lid;
+		av->rate = cached->path->av.rate;
+		av->sl = cached->path->av.sl;
+		DBGC2 ( ibdev, "IBDEV %p cache hit for " IB_GID_FMT "\n",
+			ibdev, IB_GID_ARGS ( gid ) );
+		return 0;
+	}
+	DBGC ( ibdev, "IBDEV %p cache miss for " IB_GID_FMT "%s\n", ibdev,
+	       IB_GID_ARGS ( gid ), ( cached ? " (in progress)" : "" ) );
+
+	/* If lookup is already in progress, do nothing */
+	if ( cached )
+		return -ENOENT;
+
+	/* Locate a new cache entry to use */
+	cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS );
+	cached = &ib_path_cache[cache_idx];
+
+	/* Destroy the old cache entry */
+	if ( cached->path )
+		ib_destroy_path ( ibdev, cached->path );
+	memset ( cached, 0, sizeof ( *cached ) );
+
+	/* Create new path */
+	cached->path = ib_create_path ( ibdev, av, &ib_cached_path_op );
+	if ( ! cached->path ) {
+		DBGC ( ibdev, "IBDEV %p could not create path\n",
+		       ibdev );
+		return -ENOMEM;
+	}
+	ib_path_set_ownerdata ( cached->path, cached );
+
+	/* Not found yet */
+	return -ENOENT;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_sma.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_sma.c
new file mode 100644
index 0000000..1f3c6d8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_sma.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/settings.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ib_mi.h>
+#include <ipxe/ib_sma.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+/**
+ * Node information
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ */
+static void ib_sma_node_info ( struct ib_device *ibdev,
+			       struct ib_mad_interface *mi,
+			       union ib_mad *mad,
+			       struct ib_address_vector *av ) {
+	struct ib_node_info *node_info = &mad->smp.smp_data.node_info;
+	int rc;
+
+	/* Fill in information */
+	memset ( node_info, 0, sizeof ( *node_info ) );
+	node_info->base_version = IB_MGMT_BASE_VERSION;
+	node_info->class_version = IB_SMP_CLASS_VERSION;
+	node_info->node_type = IB_NODE_TYPE_HCA;
+	node_info->num_ports = ib_count_ports ( ibdev );
+	memcpy ( &node_info->sys_guid, &ibdev->node_guid,
+		 sizeof ( node_info->sys_guid ) );
+	memcpy ( &node_info->node_guid, &ibdev->node_guid,
+		 sizeof ( node_info->node_guid ) );
+	memcpy ( &node_info->port_guid, &ibdev->gid.s.guid,
+		 sizeof ( node_info->port_guid ) );
+	node_info->partition_cap = htons ( 1 );
+	node_info->local_port_num = ibdev->port;
+
+	/* Send GetResponse */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not send NodeInfo GetResponse: %s\n",
+		       mi, strerror ( rc ) );
+		return;
+	}
+}
+
+/**
+ * Node description
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ */
+static void ib_sma_node_desc ( struct ib_device *ibdev,
+			       struct ib_mad_interface *mi,
+			       union ib_mad *mad,
+			       struct ib_address_vector *av ) {
+	struct ib_node_desc *node_desc = &mad->smp.smp_data.node_desc;
+	union ib_guid *guid = &ibdev->node_guid;
+	char hostname[ sizeof ( node_desc->node_string ) ];
+	int hostname_len;
+	int rc;
+
+	/* Fill in information */
+	memset ( node_desc, 0, sizeof ( *node_desc ) );
+	hostname_len = fetch_string_setting ( NULL, &hostname_setting,
+					      hostname, sizeof ( hostname ) );
+	snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
+		   "iPXE %s%s%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
+		   hostname, ( ( hostname_len >= 0 ) ? " " : "" ),
+		   guid->bytes[0], guid->bytes[1], guid->bytes[2],
+		   guid->bytes[3], guid->bytes[4], guid->bytes[5],
+		   guid->bytes[6], guid->bytes[7], ibdev->dev->name );
+
+	/* Send GetResponse */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not send NodeDesc GetResponse: %s\n",
+		       mi, strerror ( rc ) );
+		return;
+	}
+}
+
+/**
+ * GUID information
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ */
+static void ib_sma_guid_info ( struct ib_device *ibdev,
+			       struct ib_mad_interface *mi,
+			       union ib_mad *mad,
+			       struct ib_address_vector *av ) {
+	struct ib_guid_info *guid_info = &mad->smp.smp_data.guid_info;
+	int rc;
+
+	/* Fill in information */
+	memset ( guid_info, 0, sizeof ( *guid_info ) );
+	memcpy ( guid_info->guid[0], &ibdev->gid.s.guid,
+		 sizeof ( guid_info->guid[0] ) );
+
+	/* Send GetResponse */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not send GuidInfo GetResponse: %s\n",
+		       mi, strerror ( rc ) );
+		return;
+	}
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @ret rc		Return status code
+ */
+static int ib_sma_set_port_info ( struct ib_device *ibdev,
+				  struct ib_mad_interface *mi,
+				  union ib_mad *mad ) {
+	const struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+	unsigned int link_width_enabled;
+	unsigned int link_speed_enabled;
+	int rc;
+
+	/* Set parameters */
+	memcpy ( &ibdev->gid.s.prefix, port_info->gid_prefix,
+		 sizeof ( ibdev->gid.s.prefix ) );
+	ibdev->lid = ntohs ( port_info->lid );
+	ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
+	if ( ( link_width_enabled = port_info->link_width_enabled ) )
+		ibdev->link_width_enabled = link_width_enabled;
+	if ( ( link_speed_enabled =
+	       ( port_info->link_speed_active__link_speed_enabled & 0xf ) ) )
+		ibdev->link_speed_enabled = link_speed_enabled;
+	ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
+	DBGC ( mi, "SMA %p set LID %04x SMLID %04x link width %02x speed "
+	       "%02x\n", mi, ibdev->lid, ibdev->sm_lid,
+	       ibdev->link_width_enabled, ibdev->link_speed_enabled );
+
+	/* Update parameters on device */
+	if ( ( rc = ib_set_port_info ( ibdev, mad ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not set port information: %s\n",
+		       mi, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Port information
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ */
+static void ib_sma_port_info ( struct ib_device *ibdev,
+			       struct ib_mad_interface *mi,
+			       union ib_mad *mad,
+			       struct ib_address_vector *av ) {
+	struct ib_port_info *port_info = &mad->smp.smp_data.port_info;
+	int rc;
+
+	/* Set parameters if applicable */
+	if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
+		if ( ( rc = ib_sma_set_port_info ( ibdev, mi, mad ) ) != 0 ) {
+			mad->hdr.status =
+			      htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+			/* Fall through to generate GetResponse */
+		}
+	}
+
+	/* Fill in information */
+	memset ( port_info, 0, sizeof ( *port_info ) );
+	memcpy ( port_info->gid_prefix, &ibdev->gid.s.prefix,
+		 sizeof ( port_info->gid_prefix ) );
+	port_info->lid = ntohs ( ibdev->lid );
+	port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
+	port_info->local_port_num = ibdev->port;
+	port_info->link_width_enabled = ibdev->link_width_enabled;
+	port_info->link_width_supported = ibdev->link_width_supported;
+	port_info->link_width_active = ibdev->link_width_active;
+	port_info->link_speed_supported__port_state =
+		( ( ibdev->link_speed_supported << 4 ) | ibdev->port_state );
+	port_info->port_phys_state__link_down_def_state =
+		( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
+		  IB_PORT_PHYS_STATE_POLLING );
+	port_info->link_speed_active__link_speed_enabled =
+		( ( ibdev->link_speed_active << 4 ) |
+		  ibdev->link_speed_enabled );
+	port_info->neighbour_mtu__mastersm_sl =
+		( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
+	port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
+	port_info->init_type_reply__mtu_cap = IB_MTU_2048;
+	port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
+	port_info->guid_cap = 1;
+
+	/* Send GetResponse */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not send PortInfo GetResponse: %s\n",
+		       mi, strerror ( rc ) );
+		return;
+	}
+}
+
+/**
+ * Set partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @ret rc		Return status code
+ */
+static int ib_sma_set_pkey_table ( struct ib_device *ibdev,
+				   struct ib_mad_interface *mi,
+				   union ib_mad *mad ) {
+	struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
+	int rc;
+
+	/* Set parameters */
+	ibdev->pkey = ntohs ( pkey_table->pkey[0] );
+	DBGC ( mi, "SMA %p set pkey %04x\n", mi, ibdev->pkey );
+
+	/* Update parameters on device */
+	if ( ( rc = ib_set_pkey_table ( ibdev, mad ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not set pkey table: %s\n",
+		       mi, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @v mad		Received MAD
+ * @v av		Source address vector
+ */
+static void ib_sma_pkey_table ( struct ib_device *ibdev,
+				struct ib_mad_interface *mi,
+				union ib_mad *mad,
+				struct ib_address_vector *av ) {
+	struct ib_pkey_table *pkey_table = &mad->smp.smp_data.pkey_table;
+	int rc;
+
+	/* Set parameters, if applicable */
+	if ( mad->hdr.method == IB_MGMT_METHOD_SET ) {
+		if ( ( rc = ib_sma_set_pkey_table ( ibdev, mi, mad ) ) != 0 ) {
+			mad->hdr.status =
+			      htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+			/* Fall through to generate GetResponse */
+		}
+	}
+
+	/* Fill in information */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	memset ( pkey_table, 0, sizeof ( *pkey_table ) );
+	pkey_table->pkey[0] = htons ( ibdev->pkey );
+
+	/* Send GetResponse */
+	mad->hdr.method = IB_MGMT_METHOD_GET_RESP;
+	if ( ( rc = ib_mi_send ( ibdev, mi, mad, av ) ) != 0 ) {
+		DBGC ( mi, "SMA %p could not send PKeyTable GetResponse: %s\n",
+		       mi, strerror ( rc ) );
+		return;
+	}
+}
+
+/** Subnet management agent */
+struct ib_mad_agent ib_sma_agent[] __ib_mad_agent = {
+	{
+		.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+		.class_version = IB_SMP_CLASS_VERSION,
+		.attr_id = htons ( IB_SMP_ATTR_NODE_INFO ),
+		.handle = ib_sma_node_info,
+	},
+	{
+		.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+		.class_version = IB_SMP_CLASS_VERSION,
+		.attr_id = htons ( IB_SMP_ATTR_NODE_DESC ),
+		.handle = ib_sma_node_desc,
+	},
+	{
+		.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+		.class_version = IB_SMP_CLASS_VERSION,
+		.attr_id = htons ( IB_SMP_ATTR_GUID_INFO ),
+		.handle = ib_sma_guid_info,
+	},
+	{
+		.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+		.class_version = IB_SMP_CLASS_VERSION,
+		.attr_id = htons ( IB_SMP_ATTR_PORT_INFO ),
+		.handle = ib_sma_port_info,
+	},
+	{
+		.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED,
+		.class_version = IB_SMP_CLASS_VERSION,
+		.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ),
+		.handle = ib_sma_pkey_table,
+	},
+};
+
+/**
+ * Create subnet management agent and interface
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ * @ret rc		Return status code
+ */
+int ib_create_sma ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
+
+	/* Nothing to do */
+	DBGC ( ibdev, "IBDEV %p SMA using SMI %p\n", ibdev, mi );
+
+	return 0;
+}
+
+/**
+ * Destroy subnet management agent and interface
+ *
+ * @v ibdev		Infiniband device
+ * @v mi		Management interface
+ */
+void ib_destroy_sma ( struct ib_device *ibdev __unused,
+		      struct ib_mad_interface *mi __unused ) {
+	/* Nothing to do */
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_smc.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_smc.c
new file mode 100644
index 0000000..8196cb7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_smc.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_smc.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+/**
+ * Issue local MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v attr_id		Attribute ID, in network byte order
+ * @v attr_mod		Attribute modifier, in network byte order
+ * @v local_mad		Method for issuing local MADs
+ * @v mad		Management datagram to fill in
+ * @ret rc		Return status code
+ */
+static int ib_smc_mad ( struct ib_device *ibdev, uint16_t attr_id,
+			uint32_t attr_mod, ib_local_mad_t local_mad,
+			union ib_mad *mad ) {
+	int rc;
+
+	/* Construct MAD */
+	memset ( mad, 0, sizeof ( *mad ) );
+	mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+	mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+	mad->hdr.class_version = 1;
+	mad->hdr.method = IB_MGMT_METHOD_GET;
+	mad->hdr.attr_id = attr_id;
+	mad->hdr.attr_mod = attr_mod;
+
+	/* Issue MAD */
+	if ( ( rc = local_mad ( ibdev, mad ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Get node information
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @v mad		Management datagram to fill in
+ * @ret rc		Return status code
+ */
+static int ib_smc_get_node_info ( struct ib_device *ibdev,
+				  ib_local_mad_t local_mad,
+				  union ib_mad *mad ) {
+	int rc;
+
+	/* Issue MAD */
+	if ( ( rc = ib_smc_mad ( ibdev, htons ( IB_SMP_ATTR_NODE_INFO ), 0,
+				 local_mad, mad ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not get node info: %s\n",
+		       ibdev, strerror ( rc ) );
+		return rc;
+	}
+	return 0;
+}
+
+/**
+ * Get port information
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @v mad		Management datagram to fill in
+ * @ret rc		Return status code
+ */
+static int ib_smc_get_port_info ( struct ib_device *ibdev,
+				  ib_local_mad_t local_mad,
+				  union ib_mad *mad ) {
+	int rc;
+
+	/* Issue MAD */
+	if ( ( rc = ib_smc_mad ( ibdev, htons ( IB_SMP_ATTR_PORT_INFO ),
+				 htonl ( ibdev->port ), local_mad, mad )) !=0){
+		DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
+		       ibdev, strerror ( rc ) );
+		return rc;
+	}
+	return 0;
+}
+
+/**
+ * Get GUID information
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @v mad		Management datagram to fill in
+ * @ret rc		Return status code
+ */
+static int ib_smc_get_guid_info ( struct ib_device *ibdev,
+				  ib_local_mad_t local_mad,
+				  union ib_mad *mad ) {
+	int rc;
+
+	/* Issue MAD */
+	if ( ( rc = ib_smc_mad ( ibdev, htons ( IB_SMP_ATTR_GUID_INFO ), 0,
+				 local_mad, mad ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
+		       ibdev, strerror ( rc ) );
+		return rc;
+	}
+	return 0;
+}
+
+/**
+ * Get partition key table
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @v mad		Management datagram to fill in
+ * @ret rc		Return status code
+ */
+static int ib_smc_get_pkey_table ( struct ib_device *ibdev,
+				   ib_local_mad_t local_mad,
+				   union ib_mad *mad ) {
+	int rc;
+
+	/* Issue MAD */
+	if ( ( rc = ib_smc_mad ( ibdev, htons ( IB_SMP_ATTR_PKEY_TABLE ), 0,
+				 local_mad, mad ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
+		       ibdev, strerror ( rc ) );
+		return rc;
+	}
+	return 0;
+}
+
+/**
+ * Get Infiniband parameters using SMC
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @ret rc		Return status code
+ */
+static int ib_smc_get ( struct ib_device *ibdev, ib_local_mad_t local_mad ) {
+	union ib_mad mad;
+	struct ib_node_info *node_info = &mad.smp.smp_data.node_info;
+	struct ib_port_info *port_info = &mad.smp.smp_data.port_info;
+	struct ib_guid_info *guid_info = &mad.smp.smp_data.guid_info;
+	struct ib_pkey_table *pkey_table = &mad.smp.smp_data.pkey_table;
+	int rc;
+
+	/* Node info gives us the node GUID */
+	if ( ( rc = ib_smc_get_node_info ( ibdev, local_mad, &mad ) ) != 0 )
+		return rc;
+	memcpy ( &ibdev->node_guid, &node_info->node_guid,
+		 sizeof ( ibdev->node_guid ) );
+
+	/* Port info gives us the link state, the first half of the
+	 * port GID and the SM LID.
+	 */
+	if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 )
+		return rc;
+	memcpy ( &ibdev->gid.s.prefix, port_info->gid_prefix,
+		 sizeof ( ibdev->gid.s.prefix ) );
+	ibdev->lid = ntohs ( port_info->lid );
+	ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
+	ibdev->link_width_enabled = port_info->link_width_enabled;
+	ibdev->link_width_supported = port_info->link_width_supported;
+	ibdev->link_width_active = port_info->link_width_active;
+	ibdev->link_speed_supported =
+		( port_info->link_speed_supported__port_state >> 4 );
+	ibdev->port_state =
+		( port_info->link_speed_supported__port_state & 0xf );
+	ibdev->link_speed_active =
+		( port_info->link_speed_active__link_speed_enabled >> 4 );
+	ibdev->link_speed_enabled =
+		( port_info->link_speed_active__link_speed_enabled & 0xf );
+	ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
+
+	/* GUID info gives us the second half of the port GID */
+	if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 )
+		return rc;
+	memcpy ( &ibdev->gid.s.guid, guid_info->guid[0],
+		 sizeof ( ibdev->gid.s.guid ) );
+
+	/* Get partition key */
+	if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 )
+		return rc;
+	ibdev->pkey = ntohs ( pkey_table->pkey[0] );
+
+	DBGC ( ibdev, "IBDEV %p port GID is " IB_GID_FMT "\n",
+	       ibdev, IB_GID_ARGS ( &ibdev->gid ) );
+
+	return 0;
+}
+
+/**
+ * Initialise Infiniband parameters using SMC
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @ret rc		Return status code
+ */
+int ib_smc_init ( struct ib_device *ibdev, ib_local_mad_t local_mad ) {
+	int rc;
+
+	/* Get MAD parameters */
+	if ( ( rc = ib_smc_get ( ibdev, local_mad ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Update Infiniband parameters using SMC
+ *
+ * @v ibdev		Infiniband device
+ * @v local_mad		Method for issuing local MADs
+ * @ret rc		Return status code
+ */
+int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) {
+	int rc;
+
+	/* Get MAD parameters */
+	if ( ( rc = ib_smc_get ( ibdev, local_mad ) ) != 0 )
+		return rc;
+
+	/* Notify Infiniband core of potential link state change */
+	ib_link_state_changed ( ibdev );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_srp.c b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_srp.c
new file mode 100644
index 0000000..7b2b2b4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/infiniband/ib_srp.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2009 Fen Systems Ltd <mbrown at fensystems.co.uk>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   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 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 THE
+ * COPYRIGHT HOLDER 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.
+ */
+
+FILE_LICENCE ( BSD2 );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/interface.h>
+#include <ipxe/uri.h>
+#include <ipxe/open.h>
+#include <ipxe/base16.h>
+#include <ipxe/acpi.h>
+#include <ipxe/srp.h>
+#include <ipxe/infiniband.h>
+#include <ipxe/ib_cmrc.h>
+#include <ipxe/ib_srp.h>
+
+/**
+ * @file
+ *
+ * SCSI RDMA Protocol over Infiniband
+ *
+ */
+
+/* Disambiguate the various possible EINVALs */
+#define EINVAL_BYTE_STRING_LEN __einfo_error ( EINFO_EINVAL_BYTE_STRING_LEN )
+#define EINFO_EINVAL_BYTE_STRING_LEN __einfo_uniqify \
+	( EINFO_EINVAL, 0x01, "Invalid byte string length" )
+#define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
+#define EINFO_EINVAL_INTEGER __einfo_uniqify \
+	( EINFO_EINVAL, 0x03, "Invalid integer" )
+#define EINVAL_RP_TOO_SHORT __einfo_error ( EINFO_EINVAL_RP_TOO_SHORT )
+#define EINFO_EINVAL_RP_TOO_SHORT __einfo_uniqify \
+	( EINFO_EINVAL, 0x04, "Root path too short" )
+
+/******************************************************************************
+ *
+ * IB SRP devices
+ *
+ ******************************************************************************
+ */
+
+/** An Infiniband SRP device */
+struct ib_srp_device {
+	/** Reference count */
+	struct refcnt refcnt;
+
+	/** SRP transport interface */
+	struct interface srp;
+	/** CMRC interface */
+	struct interface cmrc;
+
+	/** Infiniband device */
+	struct ib_device *ibdev;
+
+	/** Destination GID (for boot firmware table) */
+	union ib_gid dgid;
+	/** Service ID (for boot firmware table) */
+	union ib_guid service_id;
+};
+
+/**
+ * Free IB SRP device
+ *
+ * @v refcnt		Reference count
+ */
+static void ib_srp_free ( struct refcnt *refcnt ) {
+	struct ib_srp_device *ib_srp =
+		container_of ( refcnt, struct ib_srp_device, refcnt );
+
+	ibdev_put ( ib_srp->ibdev );
+	free ( ib_srp );
+}
+
+/**
+ * Close IB SRP device
+ *
+ * @v ib_srp		IB SRP device
+ * @v rc		Reason for close
+ */
+static void ib_srp_close ( struct ib_srp_device *ib_srp, int rc ) {
+
+	/* Shut down interfaces */
+	intf_shutdown ( &ib_srp->cmrc, rc );
+	intf_shutdown ( &ib_srp->srp, rc );
+}
+
+/**
+ * Describe IB SRP device in an ACPI table
+ *
+ * @v srpdev		SRP device
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+static int ib_srp_describe ( struct ib_srp_device *ib_srp,
+			     struct acpi_description_header *acpi,
+			     size_t len ) {
+	struct ib_device *ibdev = ib_srp->ibdev;
+	struct sbft_table *sbft =
+		container_of ( acpi, struct sbft_table, acpi );
+	struct sbft_ib_subtable *ib_sbft;
+	size_t used;
+
+	/* Sanity check */
+	if ( acpi->signature != SBFT_SIG )
+		return -EINVAL;
+
+	/* Append IB subtable to existing table */
+	used = le32_to_cpu ( sbft->acpi.length );
+	sbft->ib_offset = cpu_to_le16 ( used );
+	ib_sbft = ( ( ( void * ) sbft ) + used );
+	used += sizeof ( *ib_sbft );
+	if ( used > len )
+		return -ENOBUFS;
+	sbft->acpi.length = cpu_to_le32 ( used );
+
+	/* Populate subtable */
+	memcpy ( &ib_sbft->sgid, &ibdev->gid, sizeof ( ib_sbft->sgid ) );
+	memcpy ( &ib_sbft->dgid, &ib_srp->dgid, sizeof ( ib_sbft->dgid ) );
+	memcpy ( &ib_sbft->service_id, &ib_srp->service_id,
+		 sizeof ( ib_sbft->service_id ) );
+	ib_sbft->pkey = cpu_to_le16 ( ibdev->pkey );
+
+	return 0;
+}
+
+/** IB SRP CMRC interface operations */
+static struct interface_operation ib_srp_cmrc_op[] = {
+	INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
+};
+
+/** IB SRP CMRC interface descriptor */
+static struct interface_descriptor ib_srp_cmrc_desc =
+	INTF_DESC_PASSTHRU ( struct ib_srp_device, cmrc, ib_srp_cmrc_op, srp );
+
+/** IB SRP SRP interface operations */
+static struct interface_operation ib_srp_srp_op[] = {
+	INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ),
+	INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ),
+};
+
+/** IB SRP SRP interface descriptor */
+static struct interface_descriptor ib_srp_srp_desc =
+	INTF_DESC_PASSTHRU ( struct ib_srp_device, srp, ib_srp_srp_op, cmrc );
+
+/**
+ * Open IB SRP device
+ *
+ * @v block		Block control interface
+ * @v ibdev		Infiniband device
+ * @v dgid		Destination GID
+ * @v service_id	Service ID
+ * @v initiator		Initiator port ID
+ * @v target		Target port ID
+ * @v lun		SCSI LUN
+ * @ret rc		Return status code
+ */
+static int ib_srp_open ( struct interface *block, struct ib_device *ibdev,
+			 union ib_gid *dgid, union ib_guid *service_id,
+			 union srp_port_id *initiator,
+			 union srp_port_id *target, struct scsi_lun *lun ) {
+	struct ib_srp_device *ib_srp;
+	int rc;
+
+	/* Allocate and initialise structure */
+	ib_srp = zalloc ( sizeof ( *ib_srp ) );
+	if ( ! ib_srp ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &ib_srp->refcnt, ib_srp_free );
+	intf_init ( &ib_srp->srp, &ib_srp_srp_desc, &ib_srp->refcnt );
+	intf_init ( &ib_srp->cmrc, &ib_srp_cmrc_desc, &ib_srp->refcnt );
+	ib_srp->ibdev = ibdev_get ( ibdev );
+	DBGC ( ib_srp, "IBSRP %p for " IB_GID_FMT " " IB_GUID_FMT "\n",
+	       ib_srp, IB_GID_ARGS ( dgid ), IB_GUID_ARGS ( service_id ) );
+
+	/* Preserve parameters required for boot firmware table */
+	memcpy ( &ib_srp->dgid, dgid, sizeof ( ib_srp->dgid ) );
+	memcpy ( &ib_srp->service_id, service_id,
+		 sizeof ( ib_srp->service_id ) );
+
+	/* Open CMRC socket */
+	if ( ( rc = ib_cmrc_open ( &ib_srp->cmrc, ibdev, dgid,
+				   service_id ) ) != 0 ) {
+		DBGC ( ib_srp, "IBSRP %p could not open CMRC socket: %s\n",
+		       ib_srp, strerror ( rc ) );
+		goto err_cmrc_open;
+	}
+
+	/* Attach SRP device to parent interface */
+	if ( ( rc = srp_open ( block, &ib_srp->srp, initiator, target,
+			       ibdev->rdma_key, lun ) ) != 0 ) {
+		DBGC ( ib_srp, "IBSRP %p could not create SRP device: %s\n",
+		       ib_srp, strerror ( rc ) );
+		goto err_srp_open;
+	}
+
+	/* Mortalise self and return */
+	ref_put ( &ib_srp->refcnt );
+	return 0;
+
+ err_srp_open:
+ err_cmrc_open:
+	ib_srp_close ( ib_srp, rc );
+	ref_put ( &ib_srp->refcnt );
+ err_zalloc:
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * IB SRP URIs
+ *
+ ******************************************************************************
+ */
+
+/** IB SRP parse flags */
+enum ib_srp_parse_flags {
+	IB_SRP_PARSE_REQUIRED = 0x0000,
+	IB_SRP_PARSE_OPTIONAL = 0x8000,
+	IB_SRP_PARSE_FLAG_MASK = 0xf000,
+};
+
+/** IB SRP root path parameters */
+struct ib_srp_root_path {
+	/** Source GID */
+	union ib_gid sgid;
+	/** Initiator port ID */
+	union ib_srp_initiator_port_id initiator;
+	/** Destination GID */
+	union ib_gid dgid;
+	/** Partition key */
+	uint16_t pkey;
+	/** Service ID */
+	union ib_guid service_id;
+	/** SCSI LUN */
+	struct scsi_lun lun;
+	/** Target port ID */
+	union ib_srp_target_port_id target;
+};
+
+/**
+ * Parse IB SRP root path byte-string value
+ *
+ * @v rp_comp		Root path component string
+ * @v default_value	Default value to use if component string is empty
+ * @ret value		Value
+ */
+static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
+				      unsigned int size_flags ) {
+	size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
+	size_t rp_comp_len = strlen ( rp_comp );
+	int decoded_size;
+
+	/* Allow optional components to be empty */
+	if ( ( rp_comp_len == 0 ) &&
+	     ( size_flags & IB_SRP_PARSE_OPTIONAL ) )
+		return 0;
+
+	/* Check string length */
+	if ( rp_comp_len != ( 2 * size ) )
+		return -EINVAL_BYTE_STRING_LEN;
+
+	/* Parse byte string */
+	decoded_size = base16_decode ( rp_comp, bytes );
+	if ( decoded_size < 0 )
+		return decoded_size;
+
+	return 0;
+}
+
+/**
+ * Parse IB SRP root path integer value
+ *
+ * @v rp_comp		Root path component string
+ * @v default_value	Default value to use if component string is empty
+ * @ret value		Value
+ */
+static int ib_srp_parse_integer ( const char *rp_comp, int default_value ) {
+	int value;
+	char *end;
+
+	value = strtoul ( rp_comp, &end, 16 );
+	if ( *end )
+		return -EINVAL_INTEGER;
+
+	if ( end == rp_comp )
+		return default_value;
+
+	return value;
+}
+
+/**
+ * Parse IB SRP root path source GID
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_sgid ( const char *rp_comp,
+			       struct ib_srp_root_path *rp ) {
+	struct ib_device *ibdev;
+
+	/* Default to the GID of the last opened Infiniband device */
+	if ( ( ibdev = last_opened_ibdev() ) != NULL )
+		memcpy ( &rp->sgid, &ibdev->gid, sizeof ( rp->sgid ) );
+
+	return ib_srp_parse_byte_string ( rp_comp, rp->sgid.bytes,
+					  ( sizeof ( rp->sgid ) |
+					    IB_SRP_PARSE_OPTIONAL ) );
+}
+
+/**
+ * Parse IB SRP root path initiator identifier extension
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_initiator_id_ext ( const char *rp_comp,
+					   struct ib_srp_root_path *rp ) {
+	union ib_srp_initiator_port_id *port_id = &rp->initiator;
+
+	return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
+					  ( sizeof ( port_id->ib.id_ext ) |
+					    IB_SRP_PARSE_OPTIONAL ) );
+}
+
+/**
+ * Parse IB SRP root path initiator HCA GUID
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_initiator_hca_guid ( const char *rp_comp,
+					     struct ib_srp_root_path *rp ) {
+	union ib_srp_initiator_port_id *port_id = &rp->initiator;
+
+	/* Default to the GUID portion of the source GID */
+	memcpy ( &port_id->ib.hca_guid, &rp->sgid.s.guid,
+		 sizeof ( port_id->ib.hca_guid ) );
+
+	return ib_srp_parse_byte_string ( rp_comp, port_id->ib.hca_guid.bytes,
+					  ( sizeof ( port_id->ib.hca_guid ) |
+					    IB_SRP_PARSE_OPTIONAL ) );
+}
+
+/**
+ * Parse IB SRP root path destination GID
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_dgid ( const char *rp_comp,
+			       struct ib_srp_root_path *rp ) {
+	return ib_srp_parse_byte_string ( rp_comp, rp->dgid.bytes,
+					  ( sizeof ( rp->dgid ) |
+					    IB_SRP_PARSE_REQUIRED ) );
+}
+
+/**
+ * Parse IB SRP root path partition key
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_pkey ( const char *rp_comp,
+			       struct ib_srp_root_path *rp ) {
+	int pkey;
+
+	if ( ( pkey = ib_srp_parse_integer ( rp_comp, IB_PKEY_DEFAULT ) ) < 0 )
+		return pkey;
+	rp->pkey = pkey;
+	return 0;
+}
+
+/**
+ * Parse IB SRP root path service ID
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_service_id ( const char *rp_comp,
+				     struct ib_srp_root_path *rp ) {
+	return ib_srp_parse_byte_string ( rp_comp, rp->service_id.bytes,
+					  ( sizeof ( rp->service_id ) |
+					    IB_SRP_PARSE_REQUIRED ) );
+}
+
+/**
+ * Parse IB SRP root path LUN
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_lun ( const char *rp_comp,
+			      struct ib_srp_root_path *rp ) {
+	return scsi_parse_lun ( rp_comp, &rp->lun );
+}
+
+/**
+ * Parse IB SRP root path target identifier extension
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_target_id_ext ( const char *rp_comp,
+					struct ib_srp_root_path *rp ) {
+	union ib_srp_target_port_id *port_id = &rp->target;
+
+	return ib_srp_parse_byte_string ( rp_comp, port_id->ib.id_ext.bytes,
+					  ( sizeof ( port_id->ib.id_ext ) |
+					    IB_SRP_PARSE_REQUIRED ) );
+}
+
+/**
+ * Parse IB SRP root path target I/O controller GUID
+ *
+ * @v rp_comp		Root path component string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_target_ioc_guid ( const char *rp_comp,
+					  struct ib_srp_root_path *rp ) {
+	union ib_srp_target_port_id *port_id = &rp->target;
+
+	return ib_srp_parse_byte_string ( rp_comp, port_id->ib.ioc_guid.bytes,
+					  ( sizeof ( port_id->ib.ioc_guid ) |
+					    IB_SRP_PARSE_REQUIRED ) );
+}
+
+/** IB SRP root path component parser */
+struct ib_srp_root_path_parser {
+	/**
+	 * Parse IB SRP root path component
+	 *
+	 * @v rp_comp		Root path component string
+	 * @v rp		IB SRP root path
+	 * @ret rc		Return status code
+	 */
+	int ( * parse ) ( const char *rp_comp, struct ib_srp_root_path *rp );
+};
+
+/** IB SRP root path components */
+static struct ib_srp_root_path_parser ib_srp_rp_parser[] = {
+	{ ib_srp_parse_sgid },
+	{ ib_srp_parse_initiator_id_ext },
+	{ ib_srp_parse_initiator_hca_guid },
+	{ ib_srp_parse_dgid },
+	{ ib_srp_parse_pkey },
+	{ ib_srp_parse_service_id },
+	{ ib_srp_parse_lun },
+	{ ib_srp_parse_target_id_ext },
+	{ ib_srp_parse_target_ioc_guid },
+};
+
+/** Number of IB SRP root path components */
+#define IB_SRP_NUM_RP_COMPONENTS \
+	( sizeof ( ib_srp_rp_parser ) / sizeof ( ib_srp_rp_parser[0] ) )
+
+/**
+ * Parse IB SRP root path
+ *
+ * @v rp_string		Root path string
+ * @v rp		IB SRP root path
+ * @ret rc		Return status code
+ */
+static int ib_srp_parse_root_path ( const char *rp_string,
+				    struct ib_srp_root_path *rp ) {
+	struct ib_srp_root_path_parser *parser;
+	char rp_string_copy[ strlen ( rp_string ) + 1 ];
+	char *rp_comp[IB_SRP_NUM_RP_COMPONENTS];
+	char *rp_string_tmp = rp_string_copy;
+	unsigned int i = 0;
+	int rc;
+
+	/* Split root path into component parts */
+	strcpy ( rp_string_copy, rp_string );
+	while ( 1 ) {
+		rp_comp[i++] = rp_string_tmp;
+		if ( i == IB_SRP_NUM_RP_COMPONENTS )
+			break;
+		for ( ; *rp_string_tmp != ':' ; rp_string_tmp++ ) {
+			if ( ! *rp_string_tmp ) {
+				DBG ( "IBSRP root path \"%s\" too short\n",
+				      rp_string );
+				return -EINVAL_RP_TOO_SHORT;
+			}
+		}
+		*(rp_string_tmp++) = '\0';
+	}
+
+	/* Parse root path components */
+	for ( i = 0 ; i < IB_SRP_NUM_RP_COMPONENTS ; i++ ) {
+		parser = &ib_srp_rp_parser[i];
+		if ( ( rc = parser->parse ( rp_comp[i], rp ) ) != 0 ) {
+			DBG ( "IBSRP could not parse \"%s\" in root path "
+			      "\"%s\": %s\n", rp_comp[i], rp_string,
+			      strerror ( rc ) );
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Open IB SRP URI
+ *
+ * @v parent		Parent interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int ib_srp_open_uri ( struct interface *parent, struct uri *uri ) {
+	struct ib_srp_root_path rp;
+	struct ib_device *ibdev;
+	int rc;
+
+	/* Parse URI */
+	if ( ! uri->opaque )
+		return -EINVAL;
+	memset ( &rp, 0, sizeof ( rp ) );
+	if ( ( rc = ib_srp_parse_root_path ( uri->opaque, &rp ) ) != 0 )
+		return rc;
+
+	/* Identify Infiniband device */
+	ibdev = find_ibdev ( &rp.sgid );
+	if ( ! ibdev ) {
+		DBG ( "IBSRP could not identify Infiniband device\n" );
+		return -ENODEV;
+	}
+
+	/* Open IB SRP device */
+	if ( ( rc = ib_srp_open ( parent, ibdev, &rp.dgid, &rp.service_id,
+				  &rp.initiator.srp, &rp.target.srp,
+				  &rp.lun ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** IB SRP URI opener */
+struct uri_opener ib_srp_uri_opener __uri_opener = {
+	.scheme = "ib_srp",
+	.open = ib_srp_open_uri,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/iobpad.c b/qemu-0.15.x/roms/ipxe/src/net/iobpad.c
new file mode 100644
index 0000000..f83c76d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/iobpad.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * I/O buffer padding
+ *
+ */
+
+#include <string.h>
+#include <ipxe/iobuf.h>
+
+/**
+ * Pad I/O buffer
+ *
+ * @v iobuf		I/O buffer
+ * @v min_len		Minimum length
+ *
+ * This function pads and aligns I/O buffers, for devices that
+ * aren't capable of padding in hardware, or that require specific
+ * alignment in TX buffers.  The packet data will end up aligned to a
+ * multiple of @c IOB_ALIGN.
+ *
+ * @c min_len must not exceed @v IOB_ZLEN.
+ */
+void iob_pad ( struct io_buffer *iobuf, size_t min_len ) {
+	void *data;
+	size_t len;
+	size_t headroom;
+	signed int pad_len;
+
+	assert ( min_len <= IOB_ZLEN );
+
+	/* Move packet data to start of I/O buffer.  This will both
+	 * align the data (since I/O buffers are aligned to
+	 * IOB_ALIGN) and give us sufficient space for the
+	 * zero-padding
+	 */
+	data = iobuf->data;
+	len = iob_len ( iobuf );
+	headroom = iob_headroom ( iobuf );
+	iob_push ( iobuf, headroom );
+	memmove ( iobuf->data, data, len );
+	iob_unput ( iobuf, headroom );
+
+	/* Pad to minimum packet length */
+	pad_len = ( min_len - iob_len ( iobuf ) );
+	if ( pad_len > 0 )
+		memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/ipv4.c b/qemu-0.15.x/roms/ipxe/src/net/ipv4.c
new file mode 100644
index 0000000..b2d51ad
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/ipv4.c
@@ -0,0 +1,636 @@
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/list.h>
+#include <ipxe/in.h>
+#include <ipxe/arp.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ip.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+
+/** @file
+ *
+ * IPv4 protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/* Unique IP datagram identification number */
+static uint16_t next_ident = 0;
+
+/** List of IPv4 miniroutes */
+struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
+
+/** List of fragment reassembly buffers */
+static LIST_HEAD ( frag_buffers );
+
+/**
+ * Add IPv4 minirouting table entry
+ *
+ * @v netdev		Network device
+ * @v address		IPv4 address
+ * @v netmask		Subnet mask
+ * @v gateway		Gateway address (if any)
+ * @ret miniroute	Routing table entry, or NULL
+ */
+static struct ipv4_miniroute * __malloc
+add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
+		     struct in_addr netmask, struct in_addr gateway ) {
+	struct ipv4_miniroute *miniroute;
+
+	DBG ( "IPv4 add %s", inet_ntoa ( address ) );
+	DBG ( "/%s ", inet_ntoa ( netmask ) );
+	if ( gateway.s_addr )
+		DBG ( "gw %s ", inet_ntoa ( gateway ) );
+	DBG ( "via %s\n", netdev->name );
+
+	/* Allocate and populate miniroute structure */
+	miniroute = malloc ( sizeof ( *miniroute ) );
+	if ( ! miniroute ) {
+		DBG ( "IPv4 could not add miniroute\n" );
+		return NULL;
+	}
+
+	/* Record routing information */
+	miniroute->netdev = netdev_get ( netdev );
+	miniroute->address = address;
+	miniroute->netmask = netmask;
+	miniroute->gateway = gateway;
+		
+	/* Add to end of list if we have a gateway, otherwise
+	 * to start of list.
+	 */
+	if ( gateway.s_addr ) {
+		list_add_tail ( &miniroute->list, &ipv4_miniroutes );
+	} else {
+		list_add ( &miniroute->list, &ipv4_miniroutes );
+	}
+
+	return miniroute;
+}
+
+/**
+ * Delete IPv4 minirouting table entry
+ *
+ * @v miniroute		Routing table entry
+ */
+static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
+
+	DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
+	DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
+	if ( miniroute->gateway.s_addr )
+		DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
+	DBG ( "via %s\n", miniroute->netdev->name );
+
+	netdev_put ( miniroute->netdev );
+	list_del ( &miniroute->list );
+	free ( miniroute );
+}
+
+/**
+ * Perform IPv4 routing
+ *
+ * @v dest		Final destination address
+ * @ret dest		Next hop destination address
+ * @ret miniroute	Routing table entry to use, or NULL if no route
+ *
+ * If the route requires use of a gateway, the next hop destination
+ * address will be overwritten with the gateway address.
+ */
+static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
+	struct ipv4_miniroute *miniroute;
+	int local;
+	int has_gw;
+
+	/* Never attempt to route the broadcast address */
+	if ( dest->s_addr == INADDR_BROADCAST )
+		return NULL;
+
+	/* Find first usable route in routing table */
+	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+		if ( ! netdev_is_open ( miniroute->netdev ) )
+			continue;
+		local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
+			    & miniroute->netmask.s_addr ) == 0 );
+		has_gw = ( miniroute->gateway.s_addr );
+		if ( local || has_gw ) {
+			if ( ! local )
+				*dest = miniroute->gateway;
+			return miniroute;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Fragment reassembly counter timeout
+ *
+ * @v timer	Retry timer
+ * @v over	If asserted, the timer is greater than @c MAX_TIMEOUT 
+ */
+static void ipv4_frag_expired ( struct retry_timer *timer __unused,
+				int over ) {
+	if ( over ) {
+		DBG ( "Fragment reassembly timeout" );
+		/* Free the fragment buffer */
+	}
+}
+
+/**
+ * Free fragment buffer
+ *
+ * @v fragbug	Fragment buffer
+ */
+static void free_fragbuf ( struct frag_buffer *fragbuf ) {
+	free ( fragbuf );
+}
+
+/**
+ * Fragment reassembler
+ *
+ * @v iobuf		I/O buffer, fragment of the datagram
+ * @ret frag_iob	Reassembled packet, or NULL
+ */
+static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
+	struct iphdr *iphdr = iobuf->data;
+	struct frag_buffer *fragbuf;
+	
+	/**
+	 * Check if the fragment belongs to any fragment series
+	 */
+	list_for_each_entry ( fragbuf, &frag_buffers, list ) {
+		if ( fragbuf->ident == iphdr->ident &&
+		     fragbuf->src.s_addr == iphdr->src.s_addr ) {
+			/**
+			 * Check if the packet is the expected fragment
+			 * 
+			 * The offset of the new packet must be equal to the
+			 * length of the data accumulated so far (the length of
+			 * the reassembled I/O buffer
+			 */
+			if ( iob_len ( fragbuf->frag_iob ) == 
+			      ( iphdr->frags & IP_MASK_OFFSET ) ) {
+				/**
+				 * Append the contents of the fragment to the
+				 * reassembled I/O buffer
+				 */
+				iob_pull ( iobuf, sizeof ( *iphdr ) );
+				memcpy ( iob_put ( fragbuf->frag_iob,
+							iob_len ( iobuf ) ),
+					 iobuf->data, iob_len ( iobuf ) );
+				free_iob ( iobuf );
+
+				/** Check if the fragment series is over */
+				if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
+					iobuf = fragbuf->frag_iob;
+					free_fragbuf ( fragbuf );
+					return iobuf;
+				}
+
+			} else {
+				/* Discard the fragment series */
+				free_fragbuf ( fragbuf );
+				free_iob ( iobuf );
+			}
+			return NULL;
+		}
+	}
+	
+	/** Check if the fragment is the first in the fragment series */
+	if ( iphdr->frags & IP_MASK_MOREFRAGS &&
+			( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
+	
+		/** Create a new fragment buffer */
+		fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
+		fragbuf->ident = iphdr->ident;
+		fragbuf->src = iphdr->src;
+
+		/* Set up the reassembly I/O buffer */
+		fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
+		iob_pull ( iobuf, sizeof ( *iphdr ) );
+		memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
+			 iobuf->data, iob_len ( iobuf ) );
+		free_iob ( iobuf );
+
+		/* Set the reassembly timer */
+		timer_init ( &fragbuf->frag_timer, ipv4_frag_expired, NULL );
+		start_timer_fixed ( &fragbuf->frag_timer, IP_FRAG_TIMEOUT );
+
+		/* Add the fragment buffer to the list of fragment buffers */
+		list_add ( &fragbuf->list, &frag_buffers );
+	}
+	
+	return NULL;
+}
+
+/**
+ * Add IPv4 pseudo-header checksum to existing checksum
+ *
+ * @v iobuf		I/O buffer
+ * @v csum		Existing checksum
+ * @ret csum		Updated checksum
+ */
+static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
+	struct ipv4_pseudo_header pshdr;
+	struct iphdr *iphdr = iobuf->data;
+	size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
+
+	/* Build pseudo-header */
+	pshdr.src = iphdr->src;
+	pshdr.dest = iphdr->dest;
+	pshdr.zero_padding = 0x00;
+	pshdr.protocol = iphdr->protocol;
+	pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
+
+	/* Update the checksum value */
+	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
+}
+
+/**
+ * Determine link-layer address
+ *
+ * @v dest		IPv4 destination address
+ * @v src		IPv4 source address
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address buffer
+ * @ret rc		Return status code
+ */
+static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
+			  struct net_device *netdev, uint8_t *ll_dest ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+
+	if ( dest.s_addr == INADDR_BROADCAST ) {
+		/* Broadcast address */
+		memcpy ( ll_dest, netdev->ll_broadcast,
+			 ll_protocol->ll_addr_len );
+		return 0;
+	} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
+		return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
+	} else {
+		/* Unicast address: resolve via ARP */
+		return arp_resolve ( netdev, &ipv4_protocol, &dest,
+				     &src, ll_dest );
+	}
+}
+
+/**
+ * Transmit IP packet
+ *
+ * @v iobuf		I/O buffer
+ * @v tcpip		Transport-layer protocol
+ * @v st_src		Source network-layer address
+ * @v st_dest		Destination network-layer address
+ * @v netdev		Network device to use if no route found, or NULL
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
+ * @ret rc		Status
+ *
+ * This function expects a transport-layer segment and prepends the IP header
+ */
+static int ipv4_tx ( struct io_buffer *iobuf,
+		     struct tcpip_protocol *tcpip_protocol,
+		     struct sockaddr_tcpip *st_src,
+		     struct sockaddr_tcpip *st_dest,
+		     struct net_device *netdev,
+		     uint16_t *trans_csum ) {
+	struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
+	struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
+	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
+	struct ipv4_miniroute *miniroute;
+	struct in_addr next_hop;
+	uint8_t ll_dest[MAX_LL_ADDR_LEN];
+	int rc;
+
+	/* Fill up the IP header, except source address */
+	memset ( iphdr, 0, sizeof ( *iphdr ) );
+	iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
+	iphdr->service = IP_TOS;
+	iphdr->len = htons ( iob_len ( iobuf ) );	
+	iphdr->ident = htons ( ++next_ident );
+	iphdr->ttl = IP_TTL;
+	iphdr->protocol = tcpip_protocol->tcpip_proto;
+	iphdr->dest = sin_dest->sin_addr;
+
+	/* Use routing table to identify next hop and transmitting netdev */
+	next_hop = iphdr->dest;
+	if ( sin_src )
+		iphdr->src = sin_src->sin_addr;
+	if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
+	     ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
+	     ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
+		iphdr->src = miniroute->address;
+		netdev = miniroute->netdev;
+	}
+	if ( ! netdev ) {
+		DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
+		rc = -ENETUNREACH;
+		goto err;
+	}
+
+	/* Determine link-layer destination address */
+	if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
+				   ll_dest ) ) != 0 ) {
+		DBG ( "IPv4 has no link-layer address for %s: %s\n",
+		      inet_ntoa ( next_hop ), strerror ( rc ) );
+		goto err;
+	}
+
+	/* Fix up checksums */
+	if ( trans_csum )
+		*trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
+	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
+
+	/* Print IP4 header for debugging */
+	DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
+	DBG ( "%s len %d proto %d id %04x csum %04x\n",
+	      inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
+	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
+
+	/* Hand off to link layer */
+	if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
+			     netdev->ll_addr ) ) != 0 ) {
+		DBG ( "IPv4 could not transmit packet via %s: %s\n",
+		      netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+
+ err:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Process incoming packets
+ *
+ * @v iobuf	I/O buffer
+ * @v netdev	Network device
+ * @v ll_dest	Link-layer destination address
+ * @v ll_source	Link-layer destination source
+ *
+ * This function expects an IP4 network datagram. It processes the headers 
+ * and sends it to the transport layer.
+ */
+static int ipv4_rx ( struct io_buffer *iobuf,
+		     struct net_device *netdev __unused,
+		     const void *ll_dest __unused,
+		     const void *ll_source __unused ) {
+	struct iphdr *iphdr = iobuf->data;
+	size_t hdrlen;
+	size_t len;
+	union {
+		struct sockaddr_in sin;
+		struct sockaddr_tcpip st;
+	} src, dest;
+	uint16_t csum;
+	uint16_t pshdr_csum;
+	int rc;
+
+	/* Sanity check the IPv4 header */
+	if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
+		DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
+		      iob_len ( iobuf ), sizeof ( *iphdr ) );
+		goto err;
+	}
+	if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
+		DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
+		goto err;
+	}
+	hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
+	if ( hdrlen < sizeof ( *iphdr ) ) {
+		DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
+		      hdrlen, sizeof ( *iphdr ) );
+		goto err;
+	}
+	if ( hdrlen > iob_len ( iobuf ) ) {
+		DBG ( "IPv4 header too long at %zd bytes "
+		      "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
+		goto err;
+	}
+	if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
+		DBG ( "IPv4 checksum incorrect (is %04x including checksum "
+		      "field, should be 0000)\n", csum );
+		goto err;
+	}
+	len = ntohs ( iphdr->len );
+	if ( len < hdrlen ) {
+		DBG ( "IPv4 length too short at %zd bytes "
+		      "(header is %zd bytes)\n", len, hdrlen );
+		goto err;
+	}
+	if ( len > iob_len ( iobuf ) ) {
+		DBG ( "IPv4 length too long at %zd bytes "
+		      "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
+		goto err;
+	}
+
+	/* Print IPv4 header for debugging */
+	DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
+	DBG ( "%s len %d proto %d id %04x csum %04x\n",
+	      inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
+	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
+
+	/* Truncate packet to correct length, calculate pseudo-header
+	 * checksum and then strip off the IPv4 header.
+	 */
+	iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
+	pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
+	iob_pull ( iobuf, hdrlen );
+
+	/* Fragment reassembly */
+	if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
+	     ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
+		/* Pass the fragment to ipv4_reassemble() which either
+		 * returns a fully reassembled I/O buffer or NULL.
+		 */
+		iobuf = ipv4_reassemble ( iobuf );
+		if ( ! iobuf )
+			return 0;
+	}
+
+	/* Construct socket addresses and hand off to transport layer */
+	memset ( &src, 0, sizeof ( src ) );
+	src.sin.sin_family = AF_INET;
+	src.sin.sin_addr = iphdr->src;
+	memset ( &dest, 0, sizeof ( dest ) );
+	dest.sin.sin_family = AF_INET;
+	dest.sin.sin_addr = iphdr->dest;
+	if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
+			       &dest.st, pshdr_csum ) ) != 0 ) {
+		DBG ( "IPv4 received packet rejected by stack: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+
+ err:
+	free_iob ( iobuf );
+	return -EINVAL;
+}
+
+/** 
+ * Check existence of IPv4 address for ARP
+ *
+ * @v netdev		Network device
+ * @v net_addr		Network-layer address
+ * @ret rc		Return status code
+ */
+static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
+	const struct in_addr *address = net_addr;
+	struct ipv4_miniroute *miniroute;
+
+	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+		if ( ( miniroute->netdev == netdev ) &&
+		     ( miniroute->address.s_addr == address->s_addr ) ) {
+			/* Found matching address */
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * Convert IPv4 address to dotted-quad notation
+ *
+ * @v in	IP address
+ * @ret string	IP address in dotted-quad notation
+ */
+char * inet_ntoa ( struct in_addr in ) {
+	static char buf[16]; /* "xxx.xxx.xxx.xxx" */
+	uint8_t *bytes = ( uint8_t * ) ∈
+	
+	sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
+	return buf;
+}
+
+/**
+ * Transcribe IP address
+ *
+ * @v net_addr	IP address
+ * @ret string	IP address in dotted-quad notation
+ *
+ */
+static const char * ipv4_ntoa ( const void *net_addr ) {
+	return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
+}
+
+/** IPv4 protocol */
+struct net_protocol ipv4_protocol __net_protocol = {
+	.name = "IP",
+	.net_proto = htons ( ETH_P_IP ),
+	.net_addr_len = sizeof ( struct in_addr ),
+	.rx = ipv4_rx,
+	.ntoa = ipv4_ntoa,
+};
+
+/** IPv4 TCPIP net protocol */
+struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
+	.name = "IPv4",
+	.sa_family = AF_INET,
+	.tx = ipv4_tx,
+};
+
+/** IPv4 ARP protocol */
+struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
+	.net_protocol = &ipv4_protocol,
+	.check = ipv4_arp_check,
+};
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** IPv4 address setting */
+struct setting ip_setting __setting ( SETTING_IPv4 ) = {
+	.name = "ip",
+	.description = "IP address",
+	.tag = DHCP_EB_YIADDR,
+	.type = &setting_type_ipv4,
+};
+
+/** IPv4 subnet mask setting */
+struct setting netmask_setting __setting ( SETTING_IPv4 ) = {
+	.name = "netmask",
+	.description = "Subnet mask",
+	.tag = DHCP_SUBNET_MASK,
+	.type = &setting_type_ipv4,
+};
+
+/** Default gateway setting */
+struct setting gateway_setting __setting ( SETTING_IPv4 ) = {
+	.name = "gateway",
+	.description = "Default gateway",
+	.tag = DHCP_ROUTERS,
+	.type = &setting_type_ipv4,
+};
+
+/**
+ * Create IPv4 routing table based on configured settings
+ *
+ * @ret rc		Return status code
+ */
+static int ipv4_create_routes ( void ) {
+	struct ipv4_miniroute *miniroute;
+	struct ipv4_miniroute *tmp;
+	struct net_device *netdev;
+	struct settings *settings;
+	struct in_addr address = { 0 };
+	struct in_addr netmask = { 0 };
+	struct in_addr gateway = { 0 };
+
+	/* Delete all existing routes */
+	list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
+		del_ipv4_miniroute ( miniroute );
+
+	/* Create a route for each configured network device */
+	for_each_netdev ( netdev ) {
+		settings = netdev_settings ( netdev );
+		/* Get IPv4 address */
+		address.s_addr = 0;
+		fetch_ipv4_setting ( settings, &ip_setting, &address );
+		if ( ! address.s_addr )
+			continue;
+		/* Get subnet mask */
+		fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
+		/* Calculate default netmask, if necessary */
+		if ( ! netmask.s_addr ) {
+			if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
+				netmask.s_addr = htonl ( IN_CLASSA_NET );
+			} else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
+				netmask.s_addr = htonl ( IN_CLASSB_NET );
+			} else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
+				netmask.s_addr = htonl ( IN_CLASSC_NET );
+			}
+		}
+		/* Get default gateway, if present */
+		fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
+		/* Configure route */
+		miniroute = add_ipv4_miniroute ( netdev, address,
+						 netmask, gateway );
+		if ( ! miniroute )
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/** IPv4 settings applicator */
+struct settings_applicator ipv4_settings_applicator __settings_applicator = {
+	.apply = ipv4_create_routes,
+};
+
+/* Drag in ICMP */
+REQUIRE_OBJECT ( icmp );
diff --git a/qemu-0.15.x/roms/ipxe/src/net/ipv6.c b/qemu-0.15.x/roms/ipxe/src/net/ipv6.c
new file mode 100644
index 0000000..712aa49
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/ipv6.c
@@ -0,0 +1,382 @@
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <ipxe/in.h>
+#include <ipxe/ip6.h>
+#include <ipxe/ndp.h>
+#include <ipxe/list.h>
+#include <ipxe/icmp6.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/socket.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+
+/* Unspecified IP6 address */
+static struct in6_addr ip6_none = {
+        .in6_u.u6_addr32 = { 0,0,0,0 }
+};
+
+/** An IPv6 routing table entry */
+struct ipv6_miniroute {
+	/* List of miniroutes */
+	struct list_head list;
+
+	/* Network device */
+	struct net_device *netdev;
+
+	/* Destination prefix */
+	struct in6_addr prefix;
+	/* Prefix length */
+	int prefix_len;
+	/* IPv6 address of interface */
+	struct in6_addr address;
+	/* Gateway address */
+	struct in6_addr gateway;
+};
+
+/** List of IPv6 miniroutes */
+static LIST_HEAD ( miniroutes );
+
+/**
+ * Add IPv6 minirouting table entry
+ *
+ * @v netdev		Network device
+ * @v prefix		Destination prefix
+ * @v address		Address of the interface
+ * @v gateway		Gateway address (or ::0 for no gateway)
+ * @ret miniroute	Routing table entry, or NULL
+ */
+static struct ipv6_miniroute * __malloc 
+add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr prefix,
+		     int prefix_len, struct in6_addr address,
+		     struct in6_addr gateway ) {
+	struct ipv6_miniroute *miniroute;
+	
+	miniroute = malloc ( sizeof ( *miniroute ) );
+	if ( miniroute ) {
+		/* Record routing information */
+		miniroute->netdev = netdev_get ( netdev );
+		miniroute->prefix = prefix;
+		miniroute->prefix_len = prefix_len;
+		miniroute->address = address;
+		miniroute->gateway = gateway;
+		
+		/* Add miniroute to list of miniroutes */
+		if ( !IP6_EQUAL ( gateway, ip6_none ) ) {
+			list_add_tail ( &miniroute->list, &miniroutes );
+		} else {
+			list_add ( &miniroute->list, &miniroutes );
+		}
+	}
+
+	return miniroute;
+}
+
+/**
+ * Delete IPv6 minirouting table entry
+ *
+ * @v miniroute		Routing table entry
+ */
+static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
+	netdev_put ( miniroute->netdev );
+	list_del ( &miniroute->list );
+	free ( miniroute );
+}
+
+/**
+ * Add IPv6 interface
+ *
+ * @v netdev	Network device
+ * @v prefix	Destination prefix
+ * @v address	Address of the interface
+ * @v gateway	Gateway address (or ::0 for no gateway)
+ */
+int add_ipv6_address ( struct net_device *netdev, struct in6_addr prefix,
+		       int prefix_len, struct in6_addr address,
+		       struct in6_addr gateway ) {
+	struct ipv6_miniroute *miniroute;
+
+	/* Clear any existing address for this net device */
+	del_ipv6_address ( netdev );
+
+	/* Add new miniroute */
+	miniroute = add_ipv6_miniroute ( netdev, prefix, prefix_len, address,
+					 gateway );
+	if ( ! miniroute )
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * Remove IPv6 interface
+ *
+ * @v netdev	Network device
+ */
+void del_ipv6_address ( struct net_device *netdev ) {
+	struct ipv6_miniroute *miniroute;
+
+	list_for_each_entry ( miniroute, &miniroutes, list ) {
+		if ( miniroute->netdev == netdev ) {
+			del_ipv6_miniroute ( miniroute );
+			break;
+		}
+	}
+}
+
+/**
+ * Calculate TCPIP checksum
+ *
+ * @v iobuf	I/O buffer
+ * @v tcpip	TCP/IP protocol
+ *
+ * This function constructs the pseudo header and completes the checksum in the
+ * upper layer header.
+ */
+static uint16_t ipv6_tx_csum ( struct io_buffer *iobuf, uint16_t csum ) {
+	struct ip6_header *ip6hdr = iobuf->data;
+	struct ipv6_pseudo_header pshdr;
+
+	/* Calculate pseudo header */
+	memset ( &pshdr, 0, sizeof ( pshdr ) );
+	pshdr.src = ip6hdr->src;
+	pshdr.dest = ip6hdr->dest;
+	pshdr.len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) );
+	pshdr.nxt_hdr = ip6hdr->nxt_hdr;
+
+	/* Update checksum value */
+	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
+}
+
+/**
+ * Dump IP6 header for debugging
+ *
+ * ip6hdr	IPv6 header
+ */
+void ipv6_dump ( struct ip6_header *ip6hdr ) {
+	DBG ( "IP6 %p src %s dest %s nxt_hdr %d len %d\n", ip6hdr,
+	      inet6_ntoa ( ip6hdr->src ), inet6_ntoa ( ip6hdr->dest ),
+	      ip6hdr->nxt_hdr, ntohs ( ip6hdr->payload_len ) );
+}
+
+/**
+ * Transmit IP6 packet
+ *
+ * iobuf		I/O buffer
+ * tcpip	TCP/IP protocol
+ * st_dest	Destination socket address
+ *
+ * This function prepends the IPv6 headers to the payload an transmits it.
+ */
+static int ipv6_tx ( struct io_buffer *iobuf,
+		     struct tcpip_protocol *tcpip,
+		     struct sockaddr_tcpip *st_src __unused,
+		     struct sockaddr_tcpip *st_dest,
+		     struct net_device *netdev,
+		     uint16_t *trans_csum ) {
+	struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
+	struct in6_addr next_hop;
+	struct ipv6_miniroute *miniroute;
+	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
+	const uint8_t *ll_dest = ll_dest_buf;
+	int rc;
+
+	/* Construct the IPv6 packet */
+	struct ip6_header *ip6hdr = iob_push ( iobuf, sizeof ( *ip6hdr ) );
+	memset ( ip6hdr, 0, sizeof ( *ip6hdr) );
+	ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 );//IP6_VERSION;
+	ip6hdr->payload_len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) );
+	ip6hdr->nxt_hdr = tcpip->tcpip_proto;
+	ip6hdr->hop_limit = IP6_HOP_LIMIT; // 255
+
+	/* Determine the next hop address and interface
+	 *
+	 * TODO: Implement the routing table.
+	 */
+	next_hop = dest->sin6_addr;
+	list_for_each_entry ( miniroute, &miniroutes, list ) {
+		if ( ( memcmp ( &ip6hdr->dest, &miniroute->prefix,
+					miniroute->prefix_len ) == 0 ) ||
+		     ( IP6_EQUAL ( miniroute->gateway, ip6_none ) ) ) {
+			netdev = miniroute->netdev;
+			ip6hdr->src = miniroute->address;
+			if ( ! ( IS_UNSPECIFIED ( miniroute->gateway ) ) ) {
+				next_hop = miniroute->gateway;
+			}
+			break;
+		}
+	}
+	/* No network interface identified */
+	if ( !netdev ) {
+		DBG ( "No route to host %s\n", inet6_ntoa ( ip6hdr->dest ) );
+		rc = -ENETUNREACH;
+		goto err;
+	}
+
+	/* Complete the transport layer checksum */
+	if ( trans_csum )
+		*trans_csum = ipv6_tx_csum ( iobuf, *trans_csum );
+
+	/* Print IPv6 header */
+	ipv6_dump ( ip6hdr );
+	
+	/* Resolve link layer address */
+	if ( next_hop.in6_u.u6_addr8[0] == 0xff ) {
+		ll_dest_buf[0] = 0x33;
+		ll_dest_buf[1] = 0x33;
+		ll_dest_buf[2] = next_hop.in6_u.u6_addr8[12];
+		ll_dest_buf[3] = next_hop.in6_u.u6_addr8[13];
+		ll_dest_buf[4] = next_hop.in6_u.u6_addr8[14];
+		ll_dest_buf[5] = next_hop.in6_u.u6_addr8[15];
+	} else {
+		/* Unicast address needs to be resolved by NDP */
+		if ( ( rc = ndp_resolve ( netdev, &next_hop, &ip6hdr->src,
+					  ll_dest_buf ) ) != 0 ) {
+			DBG ( "No entry for %s\n", inet6_ntoa ( next_hop ) );
+			goto err;
+		}
+	}
+
+	/* Transmit packet */
+	return net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest,
+			netdev->ll_addr );
+
+  err:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Process next IP6 header
+ *
+ * @v iobuf	I/O buffer
+ * @v nxt_hdr	Next header number
+ * @v src	Source socket address
+ * @v dest	Destination socket address
+ *
+ * Refer http://www.iana.org/assignments/ipv6-parameters for the numbers
+ */
+static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr,
+		struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest ) {
+	switch ( nxt_hdr ) {
+	case IP6_HOPBYHOP: 
+	case IP6_ROUTING: 
+	case IP6_FRAGMENT: 
+	case IP6_AUTHENTICATION: 
+	case IP6_DEST_OPTS: 
+	case IP6_ESP: 
+		DBG ( "Function not implemented for header %d\n", nxt_hdr );
+		return -ENOSYS;
+	case IP6_ICMP6: 
+		break;
+	case IP6_NO_HEADER: 
+		DBG ( "No next header\n" );
+		return 0;
+	}
+	/* Next header is not a IPv6 extension header */
+	return tcpip_rx ( iobuf, nxt_hdr, src, dest, 0 /* fixme */ );
+}
+
+/**
+ * Process incoming IP6 packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ *
+ * This function processes a IPv6 packet
+ */
+static int ipv6_rx ( struct io_buffer *iobuf,
+		     __unused struct net_device *netdev,
+		     __unused const void *ll_dest,
+		     __unused const void *ll_source ) {
+
+	struct ip6_header *ip6hdr = iobuf->data;
+	union {
+		struct sockaddr_in6 sin6;
+		struct sockaddr_tcpip st;
+	} src, dest;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *ip6hdr ) ) {
+		DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
+		goto drop;
+	}
+
+	/* TODO: Verify checksum */
+
+	/* Print IP6 header for debugging */
+	ipv6_dump ( ip6hdr );
+
+	/* Check header version */
+	if ( ( ip6hdr->ver_traffic_class_flow_label & 0xf0000000 ) != 0x60000000 ) {
+		DBG ( "Invalid protocol version\n" );
+		goto drop;
+	}
+
+	/* Check the payload length */
+	if ( ntohs ( ip6hdr->payload_len ) > iob_len ( iobuf ) ) {
+		DBG ( "Inconsistent packet length (%d bytes)\n",
+			ip6hdr->payload_len );
+		goto drop;
+	}
+
+	/* Ignore the traffic class and flow control values */
+
+	/* Construct socket address */
+	memset ( &src, 0, sizeof ( src ) );
+	src.sin6.sin_family = AF_INET6;
+	src.sin6.sin6_addr = ip6hdr->src;
+	memset ( &dest, 0, sizeof ( dest ) );
+	dest.sin6.sin_family = AF_INET6;
+	dest.sin6.sin6_addr = ip6hdr->dest;
+
+	/* Strip header */
+	iob_unput ( iobuf, iob_len ( iobuf ) - ntohs ( ip6hdr->payload_len ) -
+							sizeof ( *ip6hdr ) );
+	iob_pull ( iobuf, sizeof ( *ip6hdr ) );
+
+	/* Send it to the transport layer */
+	return ipv6_process_nxt_hdr ( iobuf, ip6hdr->nxt_hdr, &src.st, &dest.st );
+
+  drop:
+	DBG ( "Packet dropped\n" );
+	free_iob ( iobuf );
+	return -1;
+}
+
+/**
+ * Print a IP6 address as xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
+ */
+char * inet6_ntoa ( struct in6_addr in6 ) {
+	static char buf[40];
+	uint16_t *bytes = ( uint16_t* ) &in6;
+	sprintf ( buf, "%x:%x:%x:%x:%x:%x:%x:%x", bytes[0], bytes[1], bytes[2],
+			bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] );
+	return buf;
+}
+
+static const char * ipv6_ntoa ( const void *net_addr ) {
+	return inet6_ntoa ( * ( ( struct in6_addr * ) net_addr ) );
+}
+
+/** IPv6 protocol */
+struct net_protocol ipv6_protocol __net_protocol = {
+	.name = "IPv6",
+	.net_proto = htons ( ETH_P_IPV6 ),
+	.net_addr_len = sizeof ( struct in6_addr ),
+	.rx = ipv6_rx,
+	.ntoa = ipv6_ntoa,
+};
+
+/** IPv6 TCPIP net protocol */
+struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = {
+	.name = "IPv6",
+	.sa_family = AF_INET6,
+	.tx = ipv6_tx,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/mii.c b/qemu-0.15.x/roms/ipxe/src/net/mii.c
new file mode 100644
index 0000000..dbaecf1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/mii.c
@@ -0,0 +1,147 @@
+/*
+
+	mii.c: MII interface library
+
+	Ported to iPXE by Daniel Verkamp <daniel at drv.nu>
+	from Linux drivers/net/mii.c
+
+	Maintained by Jeff Garzik <jgarzik at pobox.com>
+	Copyright 2001,2002 Jeff Garzik
+
+	Various code came from myson803.c and other files by
+	Donald Becker.  Copyright:
+
+		Written 1998-2002 by Donald Becker.
+
+		This software may be used and distributed according
+		to the terms of the GNU General Public License (GPL),
+		incorporated herein by reference.  Drivers based on
+		or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.
+		This file is not a complete program and may only be
+		used when the entire operating system is licensed
+		under the GPL.
+
+		The author may be reached as becker at scyld.com, or C/O
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
+*/
+
+#include <mii.h>
+
+/**
+ * mii_link_ok - is link status up/ok
+ * @mii: the MII interface
+ *
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
+ */
+int
+mii_link_ok ( struct mii_if_info *mii )
+{
+	/* first, a dummy read, needed to latch some MII phys */
+	mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR );
+	if ( mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ) & BMSR_LSTATUS )
+		return 1;
+	return 0;
+}
+
+/**
+ * mii_check_link - check MII link status
+ * @mii: MII interface
+ *
+ * If the link status changed (previous != current), call
+ * netif_carrier_on() if current link status is Up or call
+ * netif_carrier_off() if current link status is Down.
+ */
+void
+mii_check_link ( struct mii_if_info *mii )
+{
+	int cur_link = mii_link_ok ( mii );
+	int prev_link = netdev_link_ok ( mii->dev );
+
+	if ( cur_link && !prev_link )
+		netdev_link_up ( mii->dev );
+	else if (prev_link && !cur_link)
+		netdev_link_down ( mii->dev );
+}
+
+
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
+unsigned int
+mii_check_media ( struct mii_if_info *mii,
+                  unsigned int ok_to_print,
+                  unsigned int init_media )
+{
+	unsigned int old_carrier, new_carrier;
+	int advertise, lpa, media, duplex;
+	int lpa2 = 0;
+
+	/* if forced media, go no further */
+	if (mii->force_media)
+		return 0; /* duplex did not change */
+
+	/* check current and old link status */
+	old_carrier = netdev_link_ok ( mii->dev ) ? 1 : 0;
+	new_carrier = (unsigned int) mii_link_ok ( mii );
+
+	/* if carrier state did not change, this is a "bounce",
+	 * just exit as everything is already set correctly
+	 */
+	if ( ( ! init_media ) && ( old_carrier == new_carrier ) )
+		return 0; /* duplex did not change */
+
+	/* no carrier, nothing much to do */
+	if ( ! new_carrier ) {
+		netdev_link_down ( mii->dev );
+		if ( ok_to_print )
+			DBG ( "%s: link down\n", mii->dev->name);
+		return 0; /* duplex did not change */
+	}
+
+	/*
+	 * we have carrier, see who's on the other end
+	 */
+	netdev_link_up ( mii->dev );
+
+	/* get MII advertise and LPA values */
+	if ( ( ! init_media ) && ( mii->advertising ) ) {
+		advertise = mii->advertising;
+	} else {
+		advertise = mii->mdio_read ( mii->dev, mii->phy_id, MII_ADVERTISE );
+		mii->advertising = advertise;
+	}
+	lpa = mii->mdio_read ( mii->dev, mii->phy_id, MII_LPA );
+	if ( mii->supports_gmii )
+		lpa2 = mii->mdio_read ( mii->dev, mii->phy_id, MII_STAT1000 );
+
+	/* figure out media and duplex from advertise and LPA values */
+	media = mii_nway_result ( lpa & advertise );
+	duplex = ( media & ADVERTISE_FULL ) ? 1 : 0;
+	if ( lpa2 & LPA_1000FULL )
+		duplex = 1;
+
+	if ( ok_to_print )
+		DBG ( "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
+		       mii->dev->name,
+		       lpa2 & ( LPA_1000FULL | LPA_1000HALF ) ? "1000" :
+		       media & ( ADVERTISE_100FULL | ADVERTISE_100HALF ) ? "100" : "10",
+		       duplex ? "full" : "half",
+		       lpa);
+
+	if ( ( init_media ) || ( mii->full_duplex != duplex ) ) {
+		mii->full_duplex = duplex;
+		return 1; /* duplex changed */
+	}
+
+	return 0; /* duplex did not change */
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/ndp.c b/qemu-0.15.x/roms/ipxe/src/net/ndp.c
new file mode 100644
index 0000000..4d37133
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/ndp.c
@@ -0,0 +1,180 @@
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/ndp.h>
+#include <ipxe/icmp6.h>
+#include <ipxe/ip6.h>
+#include <ipxe/netdevice.h>
+
+/** @file
+ *
+ * Neighbour Discovery Protocol
+ *
+ * This file implements address resolution as specified by the neighbour
+ * discovery protocol in RFC2461. This protocol is part of the IPv6 protocol
+ * family.
+ */
+
+/* A neighbour entry */
+struct ndp_entry {
+	/** Target IP6 address */
+	struct in6_addr in6;
+	/** Link layer protocol */
+	struct ll_protocol *ll_protocol;
+	/** Link-layer address */
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
+	/** State of the neighbour entry */
+	int state;
+};
+
+/** Number of entries in the neighbour cache table */
+#define NUM_NDP_ENTRIES 4
+
+/** The neighbour cache table */
+static struct ndp_entry ndp_table[NUM_NDP_ENTRIES];
+#define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
+
+static unsigned int next_new_ndp_entry = 0;
+
+/**
+ * Find entry in the neighbour cache
+ *
+ * @v in6	IP6 address
+ */
+static struct ndp_entry *
+ndp_find_entry ( struct in6_addr *in6 ) {
+	struct ndp_entry *ndp;
+
+	for ( ndp = ndp_table ; ndp < ndp_table_end ; ndp++ ) {
+		if ( IP6_EQUAL ( ( *in6 ), ndp->in6 ) && 
+		     ( ndp->state != NDP_STATE_INVALID ) ) {
+			return ndp;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Add NDP entry
+ * 
+ * @v netdev	Network device
+ * @v in6	IP6 address
+ * @v ll_addr	Link-layer address
+ * @v state	State of the entry - one of the NDP_STATE_XXX values
+ */
+static void 
+add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
+		void *ll_addr, int state ) {
+	struct ndp_entry *ndp;
+	ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES];
+
+	/* Fill up entry */
+	ndp->ll_protocol = netdev->ll_protocol;
+	memcpy ( &ndp->in6, &( *in6 ), sizeof ( *in6 ) );
+	if ( ll_addr ) {
+		memcpy ( ndp->ll_addr, ll_addr, netdev->ll_protocol->ll_addr_len );
+	} else {
+		memset ( ndp->ll_addr, 0, netdev->ll_protocol->ll_addr_len );
+	}
+	ndp->state = state;
+	DBG ( "New neighbour cache entry: IP6 %s => %s %s\n",
+	      inet6_ntoa ( ndp->in6 ), netdev->ll_protocol->name,
+	      netdev->ll_protocol->ntoa ( ndp->ll_addr ) );
+}
+
+/**
+ * Resolve the link-layer address
+ *
+ * @v netdev		Network device
+ * @v dest		Destination address
+ * @v src		Source address
+ * @ret dest_ll_addr	Destination link-layer address or NULL
+ * @ret rc		Status
+ *
+ * This function looks up the neighbour cache for an entry corresponding to the
+ * destination address. If it finds a valid entry, it fills up dest_ll_addr and
+ * returns 0. Otherwise it sends a neighbour solicitation to the solicited
+ * multicast address.
+ */
+int ndp_resolve ( struct net_device *netdev, struct in6_addr *dest,
+		  struct in6_addr *src, void *dest_ll_addr ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct ndp_entry *ndp;
+	int rc;
+
+	ndp = ndp_find_entry ( dest );
+	/* Check if the entry is valid */
+	if ( ndp && ndp->state == NDP_STATE_REACHABLE ) {
+		DBG ( "Neighbour cache hit: IP6 %s => %s %s\n",
+		      inet6_ntoa ( *dest ), ll_protocol->name,
+		      ll_protocol->ntoa ( ndp->ll_addr ) );
+		memcpy ( dest_ll_addr, ndp->ll_addr, ll_protocol->ll_addr_len );
+		return 0;
+	}
+
+	/* Check if the entry was already created */
+	if ( ndp ) {
+		DBG ( "Awaiting neighbour advertisement\n" );
+		/* For test */
+//		ndp->state = NDP_STATE_REACHABLE;
+//		memcpy ( ndp->ll_addr, netdev->ll_addr, 6 );
+//		assert ( ndp->ll_protocol->ll_addr_len == 6 );
+//		icmp6_test_nadvert ( netdev, dest, ndp->ll_addr );
+//		assert ( ndp->state == NDP_STATE_REACHABLE );
+		/* Take it out till here */
+		return -ENOENT;
+	}
+	DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest ) );
+
+	/* Add entry in the neighbour cache */
+	add_ndp_entry ( netdev, dest, NULL, NDP_STATE_INCOMPLETE );
+
+	/* Send neighbour solicitation */
+	if ( ( rc = icmp6_send_solicit ( netdev, src, dest ) ) != 0 ) {
+		return rc;
+	}
+	return -ENOENT;
+}
+
+/**
+ * Process neighbour advertisement
+ *
+ * @v iobuf	I/O buffer
+ * @v st_src	Source address
+ * @v st_dest	Destination address 
+ */
+int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src __unused,
+			   struct sockaddr_tcpip *st_dest __unused ) {
+	struct neighbour_advert *nadvert = iobuf->data;
+	struct ndp_entry *ndp;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *nadvert ) ) {
+		DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
+		return -EINVAL;
+	}
+
+	assert ( nadvert->code == 0 );
+	assert ( nadvert->flags & ICMP6_FLAGS_SOLICITED );
+	assert ( nadvert->opt_type == 2 );
+
+	/* Update the neighbour cache, if entry is present */
+	ndp = ndp_find_entry ( &nadvert->target );
+	if ( ndp ) {
+
+	assert ( nadvert->opt_len ==
+			( ( 2 + ndp->ll_protocol->ll_addr_len ) / 8 ) );
+
+		if ( IP6_EQUAL ( ndp->in6, nadvert->target ) ) {
+			memcpy ( ndp->ll_addr, nadvert->opt_ll_addr,
+				 ndp->ll_protocol->ll_addr_len );
+			ndp->state = NDP_STATE_REACHABLE;
+			return 0;
+		}
+	}
+	DBG ( "Unsolicited advertisement (dropping packet)\n" );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/netdev_settings.c b/qemu-0.15.x/roms/ipxe/src/net/netdev_settings.c
new file mode 100644
index 0000000..2ef3984
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/netdev_settings.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
+#include <ipxe/settings.h>
+#include <ipxe/device.h>
+#include <ipxe/netdevice.h>
+
+/** @file
+ *
+ * Network device configuration settings
+ *
+ */
+
+/** Network device named settings */
+struct setting mac_setting __setting ( SETTING_NETDEV ) = {
+	.name = "mac",
+	.description = "MAC address",
+	.type = &setting_type_hex,
+	.tag = NETDEV_SETTING_TAG_MAC,
+};
+struct setting busid_setting __setting ( SETTING_NETDEV ) = {
+	.name = "busid",
+	.description = "Bus ID",
+	.type = &setting_type_hex,
+	.tag = NETDEV_SETTING_TAG_BUS_ID,
+};
+
+/**
+ * Check applicability of network device setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int netdev_applies ( struct settings *settings __unused,
+			    struct setting *setting ) {
+
+	return ( IS_NETDEV_SETTING_TAG ( setting->tag ) ||
+		 dhcpopt_applies ( setting->tag ) );
+}
+
+/**
+ * Store value of network device setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to store
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int netdev_store ( struct settings *settings, struct setting *setting,
+			  const void *data, size_t len ) {
+	struct net_device *netdev = container_of ( settings, struct net_device,
+						   settings.settings );
+
+	if ( setting_cmp ( setting, &mac_setting ) == 0 ) {
+		if ( len != netdev->ll_protocol->ll_addr_len )
+			return -EINVAL;
+		memcpy ( netdev->ll_addr, data, len );
+		return 0;
+	}
+	if ( setting_cmp ( setting, &busid_setting ) == 0 )
+		return -ENOTSUP;
+
+	return generic_settings_store ( settings, setting, data, len );
+}
+
+/**
+ * Fetch value of network device setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int netdev_fetch ( struct settings *settings, struct setting *setting,
+			  void *data, size_t len ) {
+	struct net_device *netdev = container_of ( settings, struct net_device,
+						   settings.settings );
+	struct device_description *desc = &netdev->dev->desc;
+	struct dhcp_netdev_desc dhcp_desc;
+
+	if ( setting_cmp ( setting, &mac_setting ) == 0 ) {
+		if ( len > netdev->ll_protocol->ll_addr_len )
+			len = netdev->ll_protocol->ll_addr_len;
+		memcpy ( data, netdev->ll_addr, len );
+		return netdev->ll_protocol->ll_addr_len;
+	}
+	if ( setting_cmp ( setting, &busid_setting ) == 0 ) {
+		dhcp_desc.type = desc->bus_type;
+		dhcp_desc.vendor = htons ( desc->vendor );
+		dhcp_desc.device = htons ( desc->device );
+		if ( len > sizeof ( dhcp_desc ) )
+			len = sizeof ( dhcp_desc );
+		memcpy ( data, &dhcp_desc, len );
+		return sizeof ( dhcp_desc );
+	}
+
+	return generic_settings_fetch ( settings, setting, data, len );
+}
+
+/**
+ * Clear network device settings
+ *
+ * @v settings		Settings block
+ */
+static void netdev_clear ( struct settings *settings ) {
+	generic_settings_clear ( settings );
+}
+
+/** Network device configuration settings operations */
+struct settings_operations netdev_settings_operations = {
+	.applies = netdev_applies,
+	.store = netdev_store,
+	.fetch = netdev_fetch,
+	.clear = netdev_clear,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/netdevice.c b/qemu-0.15.x/roms/ipxe/src/net/netdevice.c
new file mode 100644
index 0000000..9b0ea19
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/netdevice.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <string.h>
+#include <errno.h>
+#include <config/general.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tables.h>
+#include <ipxe/process.h>
+#include <ipxe/init.h>
+#include <ipxe/device.h>
+#include <ipxe/errortab.h>
+#include <ipxe/netdevice.h>
+
+/** @file
+ *
+ * Network device management
+ *
+ */
+
+/** List of network devices */
+struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
+
+/** List of open network devices, in reverse order of opening */
+static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
+
+/** Default unknown link status code */
+#define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
+#define EINFO_EUNKNOWN_LINK_STATUS \
+	__einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
+
+/** Default link-down status code */
+#define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN )
+#define EINFO_ENOTCONN_LINK_DOWN \
+	__einfo_uniqify ( EINFO_ENOTCONN, 0x01, "Down" )
+
+/** Human-readable message for the default link statuses */
+struct errortab netdev_errors[] __errortab = {
+	__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
+	__einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ),
+};
+
+/**
+ * Notify drivers of network device or link state change
+ *
+ * @v netdev		Network device
+ */
+static void netdev_notify ( struct net_device *netdev ) {
+	struct net_driver *driver;
+
+	for_each_table_entry ( driver, NET_DRIVERS )
+		driver->notify ( netdev );
+}
+
+/**
+ * Mark network device as having a specific link state
+ *
+ * @v netdev		Network device
+ * @v rc		Link status code
+ */
+void netdev_link_err ( struct net_device *netdev, int rc ) {
+
+	/* Record link state */
+	netdev->link_rc = rc;
+	if ( netdev->link_rc == 0 ) {
+		DBGC ( netdev, "NETDEV %s link is up\n", netdev->name );
+	} else {
+		DBGC ( netdev, "NETDEV %s link is down: %s\n",
+		       netdev->name, strerror ( netdev->link_rc ) );
+	}
+
+	/* Notify drivers of link state change */
+	netdev_notify ( netdev );
+}
+
+/**
+ * Mark network device as having link down
+ *
+ * @v netdev		Network device
+ */
+void netdev_link_down ( struct net_device *netdev ) {
+
+	/* Avoid clobbering a more detailed link status code, if one
+	 * is already set.
+	 */
+	if ( ( netdev->link_rc == 0 ) ||
+	     ( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) {
+		netdev_link_err ( netdev, -ENOTCONN_LINK_DOWN );
+	}
+}
+
+/**
+ * Record network device statistic
+ *
+ * @v stats		Network device statistics
+ * @v rc		Status code
+ */
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
+	struct net_device_error *error;
+	struct net_device_error *least_common_error;
+	unsigned int i;
+
+	/* If this is not an error, just update the good counter */
+	if ( rc == 0 ) {
+		stats->good++;
+		return;
+	}
+
+	/* Update the bad counter */
+	stats->bad++;
+
+	/* Locate the appropriate error record */
+	least_common_error = &stats->errors[0];
+	for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+			    sizeof ( stats->errors[0] ) ) ; i++ ) {
+		error = &stats->errors[i];
+		/* Update matching record, if found */
+		if ( error->rc == rc ) {
+			error->count++;
+			return;
+		}
+		if ( error->count < least_common_error->count )
+			least_common_error = error;
+	}
+
+	/* Overwrite the least common error record */
+	least_common_error->rc = rc;
+	least_common_error->count = 1;
+}
+
+/**
+ * Transmit raw packet via network device
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ *
+ * Transmits the packet via the specified network device.  This
+ * function takes ownership of the I/O buffer.
+ */
+int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
+	int rc;
+
+	DBGC ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n",
+	       netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
+
+	/* Enqueue packet */
+	list_add_tail ( &iobuf->list, &netdev->tx_queue );
+
+	/* Avoid calling transmit() on unopened network devices */
+	if ( ! netdev_is_open ( netdev ) ) {
+		rc = -ENETUNREACH;
+		goto err;
+	}
+
+	/* Discard packet (for test purposes) if applicable */
+	if ( ( NETDEV_DISCARD_RATE > 0 ) &&
+	     ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) {
+		rc = -EAGAIN;
+		goto err;
+	}
+
+	/* Transmit packet */
+	if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
+		goto err;
+
+	return 0;
+
+ err:
+	netdev_tx_complete_err ( netdev, iobuf, rc );
+	return rc;
+}
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @v rc		Packet status code
+ *
+ * The packet must currently be in the network device's TX queue.
+ */
+void netdev_tx_complete_err ( struct net_device *netdev,
+			      struct io_buffer *iobuf, int rc ) {
+
+	/* Update statistics counter */
+	netdev_record_stat ( &netdev->tx_stats, rc );
+	if ( rc == 0 ) {
+		DBGC ( netdev, "NETDEV %s transmission %p complete\n",
+		       netdev->name, iobuf );
+	} else {
+		DBGC ( netdev, "NETDEV %s transmission %p failed: %s\n",
+		       netdev->name, iobuf, strerror ( rc ) );
+	}
+
+	/* Catch data corruption as early as possible */
+	assert ( iobuf->list.next != NULL );
+	assert ( iobuf->list.prev != NULL );
+
+	/* Dequeue and free I/O buffer */
+	list_del ( &iobuf->list );
+	free_iob ( iobuf );
+}
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev		Network device
+ * @v rc		Packet status code
+ *
+ * Completes the oldest outstanding packet in the TX queue.
+ */
+void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
+	struct io_buffer *iobuf;
+
+	list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
+		netdev_tx_complete_err ( netdev, iobuf, rc );
+		return;
+	}
+}
+
+/**
+ * Flush device's transmit queue
+ *
+ * @v netdev		Network device
+ */
+static void netdev_tx_flush ( struct net_device *netdev ) {
+
+	/* Discard any packets in the TX queue */
+	while ( ! list_empty ( &netdev->tx_queue ) ) {
+		netdev_tx_complete_next_err ( netdev, -ECANCELED );
+	}
+}
+
+/**
+ * Add packet to receive queue
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer, or NULL
+ *
+ * The packet is added to the network device's RX queue.  This
+ * function takes ownership of the I/O buffer.
+ */
+void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
+
+	DBGC ( netdev, "NETDEV %s received %p (%p+%zx)\n",
+	       netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
+
+	/* Discard packet (for test purposes) if applicable */
+	if ( ( NETDEV_DISCARD_RATE > 0 ) &&
+	     ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) {
+		netdev_rx_err ( netdev, iobuf, -EAGAIN );
+		return;
+	}
+
+	/* Enqueue packet */
+	list_add_tail ( &iobuf->list, &netdev->rx_queue );
+
+	/* Update statistics counter */
+	netdev_record_stat ( &netdev->rx_stats, 0 );
+}
+
+/**
+ * Discard received packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer, or NULL
+ * @v rc		Packet status code
+ *
+ * The packet is discarded and an RX error is recorded.  This function
+ * takes ownership of the I/O buffer.  @c iobuf may be NULL if, for
+ * example, the net device wishes to report an error due to being
+ * unable to allocate an I/O buffer.
+ */
+void netdev_rx_err ( struct net_device *netdev,
+		     struct io_buffer *iobuf, int rc ) {
+
+	DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n",
+	       netdev->name, iobuf, strerror ( rc ) );
+
+	/* Discard packet */
+	free_iob ( iobuf );
+
+	/* Update statistics counter */
+	netdev_record_stat ( &netdev->rx_stats, rc );
+}
+
+/**
+ * Poll for completed and received packets on network device
+ *
+ * @v netdev		Network device
+ *
+ * Polls the network device for completed transmissions and received
+ * packets.  Any received packets will be added to the RX packet queue
+ * via netdev_rx().
+ */
+void netdev_poll ( struct net_device *netdev ) {
+
+	if ( netdev_is_open ( netdev ) )
+		netdev->op->poll ( netdev );
+}
+
+/**
+ * Remove packet from device's receive queue
+ *
+ * @v netdev		Network device
+ * @ret iobuf		I/O buffer, or NULL
+ *
+ * Removes the first packet from the device's RX queue and returns it.
+ * Ownership of the packet is transferred to the caller.
+ */
+struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) {
+	struct io_buffer *iobuf;
+
+	iobuf = list_first_entry ( &netdev->rx_queue, struct io_buffer, list );
+	if ( ! iobuf )
+		return NULL;
+
+	list_del ( &iobuf->list );
+	return iobuf;
+}
+
+/**
+ * Flush device's receive queue
+ *
+ * @v netdev		Network device
+ */
+static void netdev_rx_flush ( struct net_device *netdev ) {
+	struct io_buffer *iobuf;
+
+	/* Discard any packets in the RX queue */
+	while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
+		netdev_rx_err ( netdev, iobuf, -ECANCELED );
+	}
+}
+
+/**
+ * Free network device
+ *
+ * @v refcnt		Network device reference counter
+ */
+static void free_netdev ( struct refcnt *refcnt ) {
+	struct net_device *netdev =
+		container_of ( refcnt, struct net_device, refcnt );
+	
+	netdev_tx_flush ( netdev );
+	netdev_rx_flush ( netdev );
+	clear_settings ( netdev_settings ( netdev ) );
+	free ( netdev );
+}
+
+/**
+ * Allocate network device
+ *
+ * @v priv_size		Size of private data area (net_device::priv)
+ * @ret netdev		Network device, or NULL
+ *
+ * Allocates space for a network device and its private data area.
+ */
+struct net_device * alloc_netdev ( size_t priv_size ) {
+	struct net_device *netdev;
+	size_t total_len;
+
+	total_len = ( sizeof ( *netdev ) + priv_size );
+	netdev = zalloc ( total_len );
+	if ( netdev ) {
+		ref_init ( &netdev->refcnt, free_netdev );
+		netdev->link_rc = -EUNKNOWN_LINK_STATUS;
+		INIT_LIST_HEAD ( &netdev->tx_queue );
+		INIT_LIST_HEAD ( &netdev->rx_queue );
+		netdev_settings_init ( netdev );
+		netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
+	}
+	return netdev;
+}
+
+/**
+ * Register network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ *
+ * Gives the network device a name and adds it to the list of network
+ * devices.
+ */
+int register_netdev ( struct net_device *netdev ) {
+	static unsigned int ifindex = 0;
+	struct net_driver *driver;
+	int rc;
+
+	/* Create device name */
+	if ( netdev->name[0] == '\0' ) {
+		snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
+			   ifindex++ );
+	}
+
+	/* Set initial link-layer address */
+	netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
+
+	/* Add to device list */
+	netdev_get ( netdev );
+	list_add_tail ( &netdev->list, &net_devices );
+	DBGC ( netdev, "NETDEV %s registered (phys %s hwaddr %s)\n",
+	       netdev->name, netdev->dev->name,
+	       netdev_addr ( netdev ) );
+
+	/* Register per-netdev configuration settings */
+	if ( ( rc = register_settings ( netdev_settings ( netdev ),
+					NULL, netdev->name ) ) != 0 ) {
+		DBGC ( netdev, "NETDEV %s could not register settings: %s\n",
+		       netdev->name, strerror ( rc ) );
+		goto err_register_settings;
+	}
+
+	/* Probe device */
+	for_each_table_entry ( driver, NET_DRIVERS ) {
+		if ( ( rc = driver->probe ( netdev ) ) != 0 ) {
+			DBGC ( netdev, "NETDEV %s could not add %s device: "
+			       "%s\n", netdev->name, driver->name,
+			       strerror ( rc ) );
+			goto err_probe;
+		}
+	}
+
+	return 0;
+
+ err_probe:
+	for_each_table_entry_continue_reverse ( driver, NET_DRIVERS )
+		driver->remove ( netdev );
+	unregister_settings ( netdev_settings ( netdev ) );
+ err_register_settings:
+	return rc;
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+int netdev_open ( struct net_device *netdev ) {
+	int rc;
+
+	/* Do nothing if device is already open */
+	if ( netdev->state & NETDEV_OPEN )
+		return 0;
+
+	DBGC ( netdev, "NETDEV %s opening\n", netdev->name );
+
+	/* Open the device */
+	if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
+		return rc;
+
+	/* Mark as opened */
+	netdev->state |= NETDEV_OPEN;
+
+	/* Add to head of open devices list */
+	list_add ( &netdev->open_list, &open_net_devices );
+
+	/* Notify drivers of device state change */
+	netdev_notify ( netdev );
+
+	return 0;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+void netdev_close ( struct net_device *netdev ) {
+
+	/* Do nothing if device is already closed */
+	if ( ! ( netdev->state & NETDEV_OPEN ) )
+		return;
+
+	DBGC ( netdev, "NETDEV %s closing\n", netdev->name );
+
+	/* Remove from open devices list */
+	list_del ( &netdev->open_list );
+
+	/* Mark as closed */
+	netdev->state &= ~NETDEV_OPEN;
+
+	/* Notify drivers of device state change */
+	netdev_notify ( netdev );
+
+	/* Close the device */
+	netdev->op->close ( netdev );
+
+	/* Flush TX and RX queues */
+	netdev_tx_flush ( netdev );
+	netdev_rx_flush ( netdev );
+}
+
+/**
+ * Unregister network device
+ *
+ * @v netdev		Network device
+ *
+ * Removes the network device from the list of network devices.
+ */
+void unregister_netdev ( struct net_device *netdev ) {
+	struct net_driver *driver;
+
+	/* Ensure device is closed */
+	netdev_close ( netdev );
+
+	/* Remove device */
+	for_each_table_entry_reverse ( driver, NET_DRIVERS )
+		driver->remove ( netdev );
+
+	/* Unregister per-netdev configuration settings */
+	unregister_settings ( netdev_settings ( netdev ) );
+
+	/* Remove from device list */
+	list_del ( &netdev->list );
+	netdev_put ( netdev );
+	DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
+}
+
+/** Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+void netdev_irq ( struct net_device *netdev, int enable ) {
+
+	/* Do nothing if device does not support interrupts */
+	if ( ! netdev_irq_supported ( netdev ) )
+		return;
+
+	/* Enable or disable device interrupts */
+	netdev->op->irq ( netdev, enable );
+
+	/* Record interrupt enabled state */
+	netdev->state &= ~NETDEV_IRQ_ENABLED;
+	if ( enable )
+		netdev->state |= NETDEV_IRQ_ENABLED;
+}
+
+/**
+ * Get network device by name
+ *
+ * @v name		Network device name
+ * @ret netdev		Network device, or NULL
+ */
+struct net_device * find_netdev ( const char *name ) {
+	struct net_device *netdev;
+
+	list_for_each_entry ( netdev, &net_devices, list ) {
+		if ( strcmp ( netdev->name, name ) == 0 )
+			return netdev;
+	}
+
+	return NULL;
+}
+
+/**
+ * Get network device by PCI bus:dev.fn address
+ *
+ * @v bus_type		Bus type
+ * @v location		Bus location
+ * @ret netdev		Network device, or NULL
+ */
+struct net_device * find_netdev_by_location ( unsigned int bus_type,
+					      unsigned int location ) {
+	struct net_device *netdev;
+
+	list_for_each_entry ( netdev, &net_devices, list ) {
+		if ( ( netdev->dev->desc.bus_type == bus_type ) &&
+		     ( netdev->dev->desc.location == location ) )
+			return netdev;
+	}
+
+	return NULL;	
+}
+
+/**
+ * Get most recently opened network device
+ *
+ * @ret netdev		Most recently opened network device, or NULL
+ */
+struct net_device * last_opened_netdev ( void ) {
+	struct net_device *netdev;
+
+	netdev = list_first_entry ( &open_net_devices, struct net_device,
+				    open_list );
+	if ( ! netdev )
+		return NULL;
+
+	assert ( netdev_is_open ( netdev ) );
+	return netdev;
+}
+
+/**
+ * Transmit network-layer packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v net_protocol	Network-layer protocol
+ * @v ll_dest		Destination link-layer address
+ * @v ll_source		Source link-layer address
+ * @ret rc		Return status code
+ *
+ * Prepends link-layer headers to the I/O buffer and transmits the
+ * packet via the specified network device.  This function takes
+ * ownership of the I/O buffer.
+ */
+int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
+	     struct net_protocol *net_protocol, const void *ll_dest,
+	     const void *ll_source ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	int rc;
+
+	/* Force a poll on the netdevice to (potentially) clear any
+	 * backed-up TX completions.  This is needed on some network
+	 * devices to avoid excessive losses due to small TX ring
+	 * sizes.
+	 */
+	netdev_poll ( netdev );
+
+	/* Add link-layer header */
+	if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, ll_source,
+					net_protocol->net_proto ) ) != 0 ) {
+		free_iob ( iobuf );
+		return rc;
+	}
+
+	/* Transmit packet */
+	return netdev_tx ( netdev, iobuf );
+}
+
+/**
+ * Process received network-layer packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v net_proto		Network-layer protocol, in network-byte order
+ * @v ll_dest		Destination link-layer address
+ * @v ll_source		Source link-layer address
+ * @ret rc		Return status code
+ */
+int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
+	     uint16_t net_proto, const void *ll_dest, const void *ll_source ) {
+	struct net_protocol *net_protocol;
+
+	/* Hand off to network-layer protocol, if any */
+	for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
+		if ( net_protocol->net_proto == net_proto )
+			return net_protocol->rx ( iobuf, netdev, ll_dest,
+						  ll_source );
+	}
+
+	DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n",
+	       netdev->name, ntohs ( net_proto ) );
+	free_iob ( iobuf );
+	return -ENOTSUP;
+}
+
+/**
+ * Poll the network stack
+ *
+ * This polls all interfaces for received packets, and processes
+ * packets from the RX queue.
+ */
+void net_poll ( void ) {
+	struct net_device *netdev;
+	struct io_buffer *iobuf;
+	struct ll_protocol *ll_protocol;
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	int rc;
+
+	/* Poll and process each network device */
+	list_for_each_entry ( netdev, &net_devices, list ) {
+
+		/* Poll for new packets */
+		netdev_poll ( netdev );
+
+		/* Leave received packets on the queue if receive
+		 * queue processing is currently frozen.  This will
+		 * happen when the raw packets are to be manually
+		 * dequeued using netdev_rx_dequeue(), rather than
+		 * processed via the usual networking stack.
+		 */
+		if ( netdev_rx_frozen ( netdev ) )
+			continue;
+
+		/* Process at most one received packet.  Give priority
+		 * to getting packets out of the NIC over processing
+		 * the received packets, because we advertise a window
+		 * that assumes that we can receive packets from the
+		 * NIC faster than they arrive.
+		 */
+		if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
+
+			DBGC ( netdev, "NETDEV %s processing %p (%p+%zx)\n",
+			       netdev->name, iobuf, iobuf->data,
+			       iob_len ( iobuf ) );
+
+			/* Remove link-layer header */
+			ll_protocol = netdev->ll_protocol;
+			if ( ( rc = ll_protocol->pull ( netdev, iobuf,
+							&ll_dest, &ll_source,
+							&net_proto ) ) != 0 ) {
+				free_iob ( iobuf );
+				continue;
+			}
+
+			/* Hand packet to network layer */
+			if ( ( rc = net_rx ( iob_disown ( iobuf ), netdev,
+					     net_proto, ll_dest,
+					     ll_source ) ) != 0 ) {
+				/* Record error for diagnosis */
+				netdev_rx_err ( netdev, NULL, rc );
+			}
+		}
+	}
+}
+
+/**
+ * Single-step the network stack
+ *
+ * @v process		Network stack process
+ */
+static void net_step ( struct process *process __unused ) {
+	net_poll();
+}
+
+/** Networking stack process */
+struct process net_process __permanent_process = {
+	.list = LIST_HEAD_INIT ( net_process.list ),
+	.step = net_step,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/nullnet.c b/qemu-0.15.x/roms/ipxe/src/net/nullnet.c
new file mode 100644
index 0000000..48849df
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/nullnet.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+
+/** @file
+ *
+ * Null network device
+ *
+ */
+
+static int null_open ( struct net_device *netdev __unused ) {
+	return -ENODEV;
+};
+
+static void null_close ( struct net_device *netdev __unused ) {
+	/* Do nothing */
+};
+
+static int null_transmit ( struct net_device *netdev __unused,
+			   struct io_buffer *iobuf __unused ) {
+	return -ENODEV;
+};
+
+static void null_poll ( struct net_device *netdev __unused ) {
+	/* Do nothing */
+}
+
+static void null_irq ( struct net_device *netdev __unused,
+		       int enable __unused ) {
+	/* Do nothing */
+}
+
+struct net_device_operations null_netdev_operations = {
+	.open		= null_open,
+	.close		= null_close,
+	.transmit	= null_transmit,
+	.poll		= null_poll,
+	.irq   		= null_irq,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/rarp.c b/qemu-0.15.x/roms/ipxe/src/net/rarp.c
new file mode 100644
index 0000000..da67c45
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/rarp.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/rarp.h>
+
+/** @file
+ *
+ * Reverse Address Resolution Protocol
+ *
+ */
+
+/**
+ * Process incoming ARP packets
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ *
+ * This is a dummy method which simply discards RARP packets.
+ */
+static int rarp_rx ( struct io_buffer *iobuf,
+		     struct net_device *netdev __unused,
+		     const void *ll_dest __unused,
+		     const void *ll_source __unused ) {
+	free_iob ( iobuf );
+	return 0;
+}
+
+
+/**
+ * Transcribe RARP address
+ *
+ * @v net_addr	RARP address
+ * @ret string	"<RARP>"
+ *
+ * This operation is meaningless for the RARP protocol.
+ */
+static const char * rarp_ntoa ( const void *net_addr __unused ) {
+	return "<RARP>";
+}
+
+/** RARP protocol */
+struct net_protocol rarp_protocol __net_protocol = {
+	.name = "RARP",
+	.net_proto = htons ( ETH_P_RARP ),
+	.rx = rarp_rx,
+	.ntoa = rarp_ntoa,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/retry.c b/qemu-0.15.x/roms/ipxe/src/net/retry.c
new file mode 100644
index 0000000..082be39
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/retry.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <ipxe/timer.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+#include <ipxe/init.h>
+#include <ipxe/retry.h>
+
+/** @file
+ *
+ * Retry timers
+ *
+ * A retry timer is a binary exponential backoff timer.  It can be
+ * used to build automatic retransmission into network protocols.
+ *
+ * This implementation of the timer is designed to satisfy RFC 2988
+ * and therefore be usable as a TCP retransmission timer.
+ *
+ * 
+ */
+
+/* The theoretical minimum that the algorithm in stop_timer() can
+ * adjust the timeout back down to is seven ticks, so set the minimum
+ * timeout to at least that value for the sake of consistency.
+ */
+#define MIN_TIMEOUT 7
+
+/** List of running timers */
+static LIST_HEAD ( timers );
+
+/**
+ * Start timer
+ *
+ * @v timer		Retry timer
+ *
+ * This starts the timer running with the current timeout value.  If
+ * stop_timer() is not called before the timer expires, the timer will
+ * be stopped and the timer's callback function will be called.
+ */
+void start_timer ( struct retry_timer *timer ) {
+	if ( ! timer->running ) {
+		list_add ( &timer->list, &timers );
+		ref_get ( timer->refcnt );
+	}
+	timer->start = currticks();
+	timer->running = 1;
+
+	/* 0 means "use default timeout" */
+	if ( timer->min_timeout == 0 )
+		timer->min_timeout = DEFAULT_MIN_TIMEOUT;
+	/* We must never be less than MIN_TIMEOUT under any circumstances */
+	if ( timer->min_timeout < MIN_TIMEOUT )
+		timer->min_timeout = MIN_TIMEOUT;
+	/* Honor user-specified minimum timeout */
+	if ( timer->timeout < timer->min_timeout )
+		timer->timeout = timer->min_timeout;
+
+	DBG2 ( "Timer %p started at time %ld (expires at %ld)\n",
+	       timer, timer->start, ( timer->start + timer->timeout ) );
+}
+
+/**
+ * Start timer with a specified fixed timeout
+ *
+ * @v timer		Retry timer
+ * @v timeout		Timeout, in ticks
+ */
+void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
+	start_timer ( timer );
+	timer->timeout = timeout;
+	DBG2 ( "Timer %p expiry time changed to %ld\n",
+	       timer, ( timer->start + timer->timeout ) );
+}
+
+/**
+ * Stop timer
+ *
+ * @v timer		Retry timer
+ *
+ * This stops the timer and updates the timer's timeout value.
+ */
+void stop_timer ( struct retry_timer *timer ) {
+	unsigned long old_timeout = timer->timeout;
+	unsigned long now = currticks();
+	unsigned long runtime;
+
+	/* If timer was already stopped, do nothing */
+	if ( ! timer->running )
+		return;
+
+	list_del ( &timer->list );
+	runtime = ( now - timer->start );
+	timer->running = 0;
+	DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n",
+	       timer, now, runtime );
+
+	/* Update timer.  Variables are:
+	 *
+	 *   r = round-trip time estimate (i.e. runtime)
+	 *   t = timeout value (i.e. timer->timeout)
+	 *   s = smoothed round-trip time
+	 *
+	 * By choice, we set t = 4s, i.e. allow for four times the
+	 * normal round-trip time to pass before retransmitting.
+	 *
+	 * We want to smooth according to s := ( 7 s + r ) / 8
+	 *
+	 * Since we don't actually store s, this reduces to
+	 * t := ( 7 t / 8 ) + ( r / 2 )
+	 *
+	 */
+	if ( timer->count ) {
+		timer->count--;
+	} else {
+		timer->timeout -= ( timer->timeout >> 3 );
+		timer->timeout += ( runtime >> 1 );
+		if ( timer->timeout != old_timeout ) {
+			DBG ( "Timer %p timeout updated to %ld\n",
+			      timer, timer->timeout );
+		}
+	}
+
+	ref_put ( timer->refcnt );
+}
+
+/**
+ * Handle expired timer
+ *
+ * @v timer		Retry timer
+ */
+static void timer_expired ( struct retry_timer *timer ) {
+	int fail;
+
+	/* Stop timer without performing RTT calculations */
+	DBG2 ( "Timer %p stopped at time %ld on expiry\n",
+	       timer, currticks() );
+	assert ( timer->running );
+	list_del ( &timer->list );
+	timer->running = 0;
+	timer->count++;
+
+	/* Back off the timeout value */
+	timer->timeout <<= 1;
+	if ( timer->max_timeout == 0 ) /* 0 means "use default timeout" */
+		timer->max_timeout = DEFAULT_MAX_TIMEOUT;
+	if ( ( fail = ( timer->timeout > timer->max_timeout ) ) )
+		timer->timeout = timer->max_timeout;
+	DBG ( "Timer %p timeout backed off to %ld\n",
+	      timer, timer->timeout );
+
+	/* Call expiry callback */
+	timer->expired ( timer, fail );
+
+	ref_put ( timer->refcnt );
+}
+
+/**
+ * Single-step the retry timer list
+ *
+ * @v process		Retry timer process
+ */
+static void retry_step ( struct process *process __unused ) {
+	struct retry_timer *timer;
+	unsigned long now = currticks();
+	unsigned long used;
+
+	/* Process at most one timer expiry.  We cannot process
+	 * multiple expiries in one pass, because one timer expiring
+	 * may end up triggering another timer's deletion from the
+	 * list.
+	 */
+	list_for_each_entry ( timer, &timers, list ) {
+		used = ( now - timer->start );
+		if ( used >= timer->timeout ) {
+			timer_expired ( timer );
+			break;
+		}
+	}
+}
+
+/** Retry timer process */
+struct process retry_process __permanent_process = {
+	.list = LIST_HEAD_INIT ( retry_process.list ),
+	.step = retry_step,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcp.c b/qemu-0.15.x/roms/ipxe/src/net/tcp.c
new file mode 100644
index 0000000..fbcf279
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcp.c
@@ -0,0 +1,1353 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/timer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/retry.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/tcp.h>
+
+/** @file
+ *
+ * TCP protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** A TCP connection */
+struct tcp_connection {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** List of TCP connections */
+	struct list_head list;
+
+	/** Flags */
+	unsigned int flags;
+
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** Remote socket address */
+	struct sockaddr_tcpip peer;
+	/** Local port */
+	unsigned int local_port;
+
+	/** Current TCP state */
+	unsigned int tcp_state;
+	/** Previous TCP state
+	 *
+	 * Maintained only for debug messages
+	 */
+	unsigned int prev_tcp_state;
+	/** Current sequence number
+	 *
+	 * Equivalent to SND.UNA in RFC 793 terminology.
+	 */
+	uint32_t snd_seq;
+	/** Unacknowledged sequence count
+	 *
+	 * Equivalent to (SND.NXT-SND.UNA) in RFC 793 terminology.
+	 */
+	uint32_t snd_sent;
+	/** Send window
+	 *
+	 * Equivalent to SND.WND in RFC 793 terminology
+	 */
+	uint32_t snd_win;
+	/** Current acknowledgement number
+	 *
+	 * Equivalent to RCV.NXT in RFC 793 terminology.
+	 */
+	uint32_t rcv_ack;
+	/** Receive window
+	 *
+	 * Equivalent to RCV.WND in RFC 793 terminology.
+	 */
+	uint32_t rcv_win;
+	/** Received timestamp value
+	 *
+	 * Updated when a packet is received; copied to ts_recent when
+	 * the window is advanced.
+	 */
+	uint32_t ts_val;
+	/** Most recent received timestamp that advanced the window
+	 *
+	 * Equivalent to TS.Recent in RFC 1323 terminology.
+	 */
+	uint32_t ts_recent;
+
+	/** Transmit queue */
+	struct list_head tx_queue;
+	/** Receive queue */
+	struct list_head rx_queue;
+	/** Retransmission timer */
+	struct retry_timer timer;
+	/** Shutdown (TIME_WAIT) timer */
+	struct retry_timer wait;
+};
+
+/** TCP flags */
+enum tcp_flags {
+	/** TCP data transfer interface has been closed */
+	TCP_XFER_CLOSED = 0x0001,
+	/** TCP timestamps are enabled */
+	TCP_TS_ENABLED = 0x0002,
+	/** TCP acknowledgement is pending */
+	TCP_ACK_PENDING = 0x0004,
+};
+
+/** TCP internal header
+ *
+ * This is the header that replaces the TCP header for packets
+ * enqueued on the receive queue.
+ */
+struct tcp_rx_queued_header {
+	/** SEQ value, in host-endian order
+	 *
+	 * This represents the SEQ value at the time the packet is
+	 * enqueued, and so excludes the SYN, if present.
+	 */
+	uint32_t seq;
+	/** Flags
+	 *
+	 * Only FIN is valid within this flags byte; all other flags
+	 * have already been processed by the time the packet is
+	 * enqueued.
+	 */
+	uint8_t flags;
+	/** Reserved */
+	uint8_t reserved[3];
+};
+
+/**
+ * List of registered TCP connections
+ */
+static LIST_HEAD ( tcp_conns );
+
+/* Forward declarations */
+static struct interface_descriptor tcp_xfer_desc;
+static void tcp_expired ( struct retry_timer *timer, int over );
+static void tcp_wait_expired ( struct retry_timer *timer, int over );
+static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
+			uint32_t win );
+
+/**
+ * Name TCP state
+ *
+ * @v state		TCP state
+ * @ret name		Name of TCP state
+ */
+static inline __attribute__ (( always_inline )) const char *
+tcp_state ( int state ) {
+	switch ( state ) {
+	case TCP_CLOSED:		return "CLOSED";
+	case TCP_LISTEN:		return "LISTEN";
+	case TCP_SYN_SENT:		return "SYN_SENT";
+	case TCP_SYN_RCVD:		return "SYN_RCVD";
+	case TCP_ESTABLISHED:		return "ESTABLISHED";
+	case TCP_FIN_WAIT_1:		return "FIN_WAIT_1";
+	case TCP_FIN_WAIT_2:		return "FIN_WAIT_2";
+	case TCP_CLOSING_OR_LAST_ACK:	return "CLOSING/LAST_ACK";
+	case TCP_TIME_WAIT:		return "TIME_WAIT";
+	case TCP_CLOSE_WAIT:		return "CLOSE_WAIT";
+	default:			return "INVALID";
+	}
+}
+
+/**
+ * Dump TCP state transition
+ *
+ * @v tcp		TCP connection
+ */
+static inline __attribute__ (( always_inline )) void
+tcp_dump_state ( struct tcp_connection *tcp ) {
+
+	if ( tcp->tcp_state != tcp->prev_tcp_state ) {
+		DBGC ( tcp, "TCP %p transitioned from %s to %s\n", tcp,
+		       tcp_state ( tcp->prev_tcp_state ),
+		       tcp_state ( tcp->tcp_state ) );
+	}
+	tcp->prev_tcp_state = tcp->tcp_state;
+}
+
+/**
+ * Dump TCP flags
+ *
+ * @v flags		TCP flags
+ */
+static inline __attribute__ (( always_inline )) void
+tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) {
+	if ( flags & TCP_RST )
+		DBGC2 ( tcp, " RST" );
+	if ( flags & TCP_SYN )
+		DBGC2 ( tcp, " SYN" );
+	if ( flags & TCP_PSH )
+		DBGC2 ( tcp, " PSH" );
+	if ( flags & TCP_FIN )
+		DBGC2 ( tcp, " FIN" );
+	if ( flags & TCP_ACK )
+		DBGC2 ( tcp, " ACK" );
+}
+
+/***************************************************************************
+ *
+ * Open and close
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Bind TCP connection to local port
+ *
+ * @v tcp		TCP connection
+ * @v port		Local port number
+ * @ret rc		Return status code
+ *
+ * If the port is 0, the connection is assigned an available port
+ * between 1024 and 65535.
+ */
+static int tcp_bind ( struct tcp_connection *tcp, unsigned int port ) {
+	struct tcp_connection *existing;
+	uint16_t try_port;
+	unsigned int i;
+
+	/* If no port is specified, find an available port */
+	if ( ! port ) {
+		try_port = random();
+		for ( i = 0 ; i < 65536 ; i++ ) {
+			try_port++;
+			if ( try_port < 1024 )
+				continue;
+			if ( tcp_bind ( tcp, try_port ) == 0 )
+				return 0;
+		}
+		DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp );
+		return -EADDRINUSE;
+	}
+
+	/* Attempt bind to local port */
+	list_for_each_entry ( existing, &tcp_conns, list ) {
+		if ( existing->local_port == port ) {
+			DBGC ( tcp, "TCP %p could not bind: port %d in use\n",
+			       tcp, port );
+			return -EADDRINUSE;
+		}
+	}
+	tcp->local_port = port;
+
+	DBGC ( tcp, "TCP %p bound to port %d\n", tcp, port );
+	return 0;
+}
+
+/**
+ * Open a TCP connection
+ *
+ * @v xfer		Data transfer interface
+ * @v peer		Peer socket address
+ * @v local		Local socket address, or NULL
+ * @ret rc		Return status code
+ */
+static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
+		      struct sockaddr *local ) {
+	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
+	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
+	struct tcp_connection *tcp;
+	unsigned int bind_port;
+	int rc;
+
+	/* Allocate and initialise structure */
+	tcp = zalloc ( sizeof ( *tcp ) );
+	if ( ! tcp )
+		return -ENOMEM;
+	DBGC ( tcp, "TCP %p allocated\n", tcp );
+	ref_init ( &tcp->refcnt, NULL );
+	intf_init ( &tcp->xfer, &tcp_xfer_desc, &tcp->refcnt );
+	timer_init ( &tcp->timer, tcp_expired, &tcp->refcnt );
+	timer_init ( &tcp->wait, tcp_wait_expired, &tcp->refcnt );
+	tcp->prev_tcp_state = TCP_CLOSED;
+	tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
+	tcp_dump_state ( tcp );
+	tcp->snd_seq = random();
+	INIT_LIST_HEAD ( &tcp->tx_queue );
+	INIT_LIST_HEAD ( &tcp->rx_queue );
+	memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
+
+	/* Bind to local port */
+	bind_port = ( st_local ? ntohs ( st_local->st_port ) : 0 );
+	if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 )
+		goto err;
+
+	/* Start timer to initiate SYN */
+	start_timer_nodelay ( &tcp->timer );
+
+	/* Attach parent interface, transfer reference to connection
+	 * list and return
+	 */
+	intf_plug_plug ( &tcp->xfer, xfer );
+	list_add ( &tcp->list, &tcp_conns );
+	return 0;
+
+ err:
+	ref_put ( &tcp->refcnt );
+	return rc;
+}
+
+/**
+ * Close TCP connection
+ *
+ * @v tcp		TCP connection
+ * @v rc		Reason for close
+ *
+ * Closes the data transfer interface.  If the TCP state machine is in
+ * a suitable state, the connection will be deleted.
+ */
+static void tcp_close ( struct tcp_connection *tcp, int rc ) {
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
+
+	/* Close data transfer interface */
+	intf_shutdown ( &tcp->xfer, rc );
+	tcp->flags |= TCP_XFER_CLOSED;
+
+	/* If we are in CLOSED, or have otherwise not yet received a
+	 * SYN (i.e. we are in LISTEN or SYN_SENT), just delete the
+	 * connection.
+	 */
+	if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
+
+		/* Transition to CLOSED for the sake of debugging messages */
+		tcp->tcp_state = TCP_CLOSED;
+		tcp_dump_state ( tcp );
+
+		/* Free any unprocessed I/O buffers */
+		list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) {
+			list_del ( &iobuf->list );
+			free_iob ( iobuf );
+		}
+
+		/* Free any unsent I/O buffers */
+		list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
+			list_del ( &iobuf->list );
+			free_iob ( iobuf );
+		}
+
+		/* Remove from list and drop reference */
+		stop_timer ( &tcp->timer );
+		list_del ( &tcp->list );
+		ref_put ( &tcp->refcnt );
+		DBGC ( tcp, "TCP %p connection deleted\n", tcp );
+		return;
+	}
+
+	/* If we have not had our SYN acknowledged (i.e. we are in
+	 * SYN_RCVD), pretend that it has been acknowledged so that we
+	 * can send a FIN without breaking things.
+	 */
+	if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
+		tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
+
+	/* If we have no data remaining to send, start sending FIN */
+	if ( list_empty ( &tcp->tx_queue ) ) {
+		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
+		tcp_dump_state ( tcp );
+	}
+}
+
+/***************************************************************************
+ *
+ * Transmit data path
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Calculate transmission window
+ *
+ * @v tcp		TCP connection
+ * @ret len		Maximum length that can be sent in a single packet
+ */
+static size_t tcp_xmit_win ( struct tcp_connection *tcp ) {
+	size_t len;
+
+	/* Not ready if we're not in a suitable connection state */
+	if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) )
+		return 0;
+
+	/* Length is the minimum of the receiver's window and the path MTU */
+	len = tcp->snd_win;
+	if ( len > TCP_PATH_MTU )
+		len = TCP_PATH_MTU;
+
+	return len;
+}
+
+/**
+ * Process TCP transmit queue
+ *
+ * @v tcp		TCP connection
+ * @v max_len		Maximum length to process
+ * @v dest		I/O buffer to fill with data, or NULL
+ * @v remove		Remove data from queue
+ * @ret len		Length of data processed
+ *
+ * This processes at most @c max_len bytes from the TCP connection's
+ * transmit queue.  Data will be copied into the @c dest I/O buffer
+ * (if provided) and, if @c remove is true, removed from the transmit
+ * queue.
+ */
+static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
+				     struct io_buffer *dest, int remove ) {
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
+	size_t frag_len;
+	size_t len = 0;
+
+	list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
+		frag_len = iob_len ( iobuf );
+		if ( frag_len > max_len )
+			frag_len = max_len;
+		if ( dest ) {
+			memcpy ( iob_put ( dest, frag_len ), iobuf->data,
+				 frag_len );
+		}
+		if ( remove ) {
+			iob_pull ( iobuf, frag_len );
+			if ( ! iob_len ( iobuf ) ) {
+				list_del ( &iobuf->list );
+				free_iob ( iobuf );
+			}
+		}
+		len += frag_len;
+		max_len -= frag_len;
+	}
+	return len;
+}
+
+/**
+ * Transmit any outstanding data
+ *
+ * @v tcp		TCP connection
+ * 
+ * Transmits any outstanding data on the connection.
+ *
+ * Note that even if an error is returned, the retransmission timer
+ * will have been started if necessary, and so the stack will
+ * eventually attempt to retransmit the failed packet.
+ */
+static int tcp_xmit ( struct tcp_connection *tcp ) {
+	struct io_buffer *iobuf;
+	struct tcp_header *tcphdr;
+	struct tcp_mss_option *mssopt;
+	struct tcp_timestamp_padded_option *tsopt;
+	void *payload;
+	unsigned int flags;
+	size_t len = 0;
+	uint32_t seq_len;
+	uint32_t app_win;
+	uint32_t max_rcv_win;
+	int rc;
+
+	/* If retransmission timer is already running, do nothing */
+	if ( timer_running ( &tcp->timer ) )
+		return 0;
+
+	/* Calculate both the actual (payload) and sequence space
+	 * lengths that we wish to transmit.
+	 */
+	if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) {
+		len = tcp_process_tx_queue ( tcp, tcp_xmit_win ( tcp ),
+					     NULL, 0 );
+	}
+	seq_len = len;
+	flags = TCP_FLAGS_SENDING ( tcp->tcp_state );
+	if ( flags & ( TCP_SYN | TCP_FIN ) ) {
+		/* SYN or FIN consume one byte, and we can never send both */
+		assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) );
+		seq_len++;
+	}
+	tcp->snd_sent = seq_len;
+
+	/* If we have nothing to transmit, stop now */
+	if ( ( seq_len == 0 ) && ! ( tcp->flags & TCP_ACK_PENDING ) )
+		return 0;
+
+	/* If we are transmitting anything that requires
+	 * acknowledgement (i.e. consumes sequence space), start the
+	 * retransmission timer.  Do this before attempting to
+	 * allocate the I/O buffer, in case allocation itself fails.
+	 */
+	if ( seq_len )
+		start_timer ( &tcp->timer );
+
+	/* Allocate I/O buffer */
+	iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN );
+	if ( ! iobuf ) {
+		DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
+		       "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
+		       tcp->rcv_ack );
+		return -ENOMEM;
+	}
+	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
+
+	/* Fill data payload from transmit queue */
+	tcp_process_tx_queue ( tcp, len, iobuf, 0 );
+
+	/* Expand receive window if possible */
+	max_rcv_win = ( ( freemem * 3 ) / 4 );
+	if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
+		max_rcv_win = TCP_MAX_WINDOW_SIZE;
+	app_win = xfer_window ( &tcp->xfer );
+	if ( max_rcv_win > app_win )
+		max_rcv_win = app_win;
+	max_rcv_win &= ~0x03; /* Keep everything dword-aligned */
+	if ( tcp->rcv_win < max_rcv_win )
+		tcp->rcv_win = max_rcv_win;
+
+	/* Fill up the TCP header */
+	payload = iobuf->data;
+	if ( flags & TCP_SYN ) {
+		mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
+		mssopt->kind = TCP_OPTION_MSS;
+		mssopt->length = sizeof ( *mssopt );
+		mssopt->mss = htons ( TCP_MSS );
+	}
+	if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) {
+		tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
+		memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) );
+		tsopt->tsopt.kind = TCP_OPTION_TS;
+		tsopt->tsopt.length = sizeof ( tsopt->tsopt );
+		tsopt->tsopt.tsval = htonl ( currticks() );
+		tsopt->tsopt.tsecr = htonl ( tcp->ts_recent );
+	}
+	if ( len != 0 )
+		flags |= TCP_PSH;
+	tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
+	memset ( tcphdr, 0, sizeof ( *tcphdr ) );
+	tcphdr->src = htons ( tcp->local_port );
+	tcphdr->dest = tcp->peer.st_port;
+	tcphdr->seq = htonl ( tcp->snd_seq );
+	tcphdr->ack = htonl ( tcp->rcv_ack );
+	tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
+	tcphdr->flags = flags;
+	tcphdr->win = htons ( tcp->rcv_win );
+	tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
+
+	/* Dump header */
+	DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x           %08x %4zd",
+		tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
+		ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ),
+		ntohl ( tcphdr->ack ), len );
+	tcp_dump_flags ( tcp, tcphdr->flags );
+	DBGC2 ( tcp, "\n" );
+
+	/* Transmit packet */
+	if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
+			       &tcphdr->csum ) ) != 0 ) {
+		DBGC ( tcp, "TCP %p could not transmit %08x..%08x %08x: %s\n",
+		       tcp, tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ),
+		       tcp->rcv_ack, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Clear ACK-pending flag */
+	tcp->flags &= ~TCP_ACK_PENDING;
+
+	return 0;
+}
+
+/**
+ * Retransmission timer expired
+ *
+ * @v timer		Retransmission timer
+ * @v over		Failure indicator
+ */
+static void tcp_expired ( struct retry_timer *timer, int over ) {
+	struct tcp_connection *tcp =
+		container_of ( timer, struct tcp_connection, timer );
+
+	DBGC ( tcp, "TCP %p timer %s in %s for %08x..%08x %08x\n", tcp,
+	       ( over ? "expired" : "fired" ), tcp_state ( tcp->tcp_state ),
+	       tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack );
+
+	assert ( ( tcp->tcp_state == TCP_SYN_SENT ) ||
+		 ( tcp->tcp_state == TCP_SYN_RCVD ) ||
+		 ( tcp->tcp_state == TCP_ESTABLISHED ) ||
+		 ( tcp->tcp_state == TCP_FIN_WAIT_1 ) ||
+		 ( tcp->tcp_state == TCP_CLOSE_WAIT ) ||
+		 ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
+
+	if ( over ) {
+		/* If we have finally timed out and given up,
+		 * terminate the connection
+		 */
+		tcp->tcp_state = TCP_CLOSED;
+		tcp_dump_state ( tcp );
+		tcp_close ( tcp, -ETIMEDOUT );
+	} else {
+		/* Otherwise, retransmit the packet */
+		tcp_xmit ( tcp );
+	}
+}
+
+/**
+ * Shutdown timer expired
+ *
+ * @v timer		Shutdown timer
+ * @v over		Failure indicator
+ */
+static void tcp_wait_expired ( struct retry_timer *timer, int over __unused ) {
+	struct tcp_connection *tcp =
+		container_of ( timer, struct tcp_connection, wait );
+
+	assert ( tcp->tcp_state == TCP_TIME_WAIT );
+
+	DBGC ( tcp, "TCP %p wait complete in %s for %08x..%08x %08x\n", tcp,
+	       tcp_state ( tcp->tcp_state ), tcp->snd_seq,
+	       ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack );
+
+	tcp->tcp_state = TCP_CLOSED;
+	tcp_dump_state ( tcp );
+	tcp_close ( tcp, 0 );
+}
+
+/**
+ * Send RST response to incoming packet
+ *
+ * @v in_tcphdr		TCP header of incoming packet
+ * @ret rc		Return status code
+ */
+static int tcp_xmit_reset ( struct tcp_connection *tcp,
+			    struct sockaddr_tcpip *st_dest,
+			    struct tcp_header *in_tcphdr ) {
+	struct io_buffer *iobuf;
+	struct tcp_header *tcphdr;
+	int rc;
+
+	/* Allocate space for dataless TX buffer */
+	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN );
+	if ( ! iobuf ) {
+		DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
+		       "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
+		       ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
+		return -ENOMEM;
+	}
+	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
+
+	/* Construct RST response */
+	tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
+	memset ( tcphdr, 0, sizeof ( *tcphdr ) );
+	tcphdr->src = in_tcphdr->dest;
+	tcphdr->dest = in_tcphdr->src;
+	tcphdr->seq = in_tcphdr->ack;
+	tcphdr->ack = in_tcphdr->seq;
+	tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
+	tcphdr->flags = ( TCP_RST | TCP_ACK );
+	tcphdr->win = htons ( TCP_MAX_WINDOW_SIZE );
+	tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
+
+	/* Dump header */
+	DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x           %08x %4d",
+		tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
+		ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ),
+		ntohl ( tcphdr->ack ), 0 );
+	tcp_dump_flags ( tcp, tcphdr->flags );
+	DBGC2 ( tcp, "\n" );
+
+	/* Transmit packet */
+	if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
+			       NULL, &tcphdr->csum ) ) != 0 ) {
+		DBGC ( tcp, "TCP %p could not transmit RST %08x..%08x %08x: "
+		       "%s\n", tcp, ntohl ( in_tcphdr->ack ),
+		       ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ),
+		       strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * Receive data path
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Identify TCP connection by local port number
+ *
+ * @v local_port	Local port
+ * @ret tcp		TCP connection, or NULL
+ */
+static struct tcp_connection * tcp_demux ( unsigned int local_port ) {
+	struct tcp_connection *tcp;
+
+	list_for_each_entry ( tcp, &tcp_conns, list ) {
+		if ( tcp->local_port == local_port )
+			return tcp;
+	}
+	return NULL;
+}
+
+/**
+ * Parse TCP received options
+ *
+ * @v tcp		TCP connection
+ * @v data		Raw options data
+ * @v len		Raw options length
+ * @v options		Options structure to fill in
+ */
+static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
+			  size_t len, struct tcp_options *options ) {
+	const void *end = ( data + len );
+	const struct tcp_option *option;
+	unsigned int kind;
+
+	memset ( options, 0, sizeof ( *options ) );
+	while ( data < end ) {
+		option = data;
+		kind = option->kind;
+		if ( kind == TCP_OPTION_END )
+			return;
+		if ( kind == TCP_OPTION_NOP ) {
+			data++;
+			continue;
+		}
+		switch ( kind ) {
+		case TCP_OPTION_MSS:
+			options->mssopt = data;
+			break;
+		case TCP_OPTION_TS:
+			options->tsopt = data;
+			break;
+		default:
+			DBGC ( tcp, "TCP %p received unknown option %d\n",
+			       tcp, kind );
+			break;
+		}
+		data += option->length;
+	}
+}
+
+/**
+ * Consume received sequence space
+ *
+ * @v tcp		TCP connection
+ * @v seq_len		Sequence space length to consume
+ */
+static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) {
+
+	/* Sanity check */
+	assert ( seq_len > 0 );
+
+	/* Update acknowledgement number */
+	tcp->rcv_ack += seq_len;
+
+	/* Update window */
+	if ( tcp->rcv_win > seq_len ) {
+		tcp->rcv_win -= seq_len;
+	} else {
+		tcp->rcv_win = 0;
+	}
+
+	/* Update timestamp */
+	tcp->ts_recent = tcp->ts_val;
+
+	/* Mark ACK as pending */
+	tcp->flags |= TCP_ACK_PENDING;
+}
+
+/**
+ * Handle TCP received SYN
+ *
+ * @v tcp		TCP connection
+ * @v seq		SEQ value (in host-endian order)
+ * @v options		TCP options
+ * @ret rc		Return status code
+ */
+static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
+			struct tcp_options *options ) {
+
+	/* Synchronise sequence numbers on first SYN */
+	if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
+		tcp->rcv_ack = seq;
+		if ( options->tsopt )
+			tcp->flags |= TCP_TS_ENABLED;
+	}
+
+	/* Ignore duplicate SYN */
+	if ( seq != tcp->rcv_ack )
+		return 0;
+
+	/* Acknowledge SYN */
+	tcp_rx_seq ( tcp, 1 );
+
+	/* Mark SYN as received and start sending ACKs with each packet */
+	tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) |
+			    TCP_STATE_RCVD ( TCP_SYN ) );
+
+	return 0;
+}
+
+/**
+ * Handle TCP received ACK
+ *
+ * @v tcp		TCP connection
+ * @v ack		ACK value (in host-endian order)
+ * @v win		WIN value (in host-endian order)
+ * @ret rc		Return status code
+ */
+static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
+			uint32_t win ) {
+	uint32_t ack_len = ( ack - tcp->snd_seq );
+	size_t len;
+	unsigned int acked_flags;
+
+	/* Check for out-of-range or old duplicate ACKs */
+	if ( ack_len > tcp->snd_sent ) {
+		DBGC ( tcp, "TCP %p received ACK for %08x..%08x, "
+		       "sent only %08x..%08x\n", tcp, tcp->snd_seq,
+		       ( tcp->snd_seq + ack_len ), tcp->snd_seq,
+		       ( tcp->snd_seq + tcp->snd_sent ) );
+
+		if ( TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) {
+			/* Just ignore what might be old duplicate ACKs */
+			return 0;
+		} else {
+			/* Send RST if an out-of-range ACK is received
+			 * on a not-yet-established connection, as per
+			 * RFC 793.
+			 */
+			return -EINVAL;
+		}
+	}
+
+	/* Ignore ACKs that don't actually acknowledge any new data.
+	 * (In particular, do not stop the retransmission timer; this
+	 * avoids creating a sorceror's apprentice syndrome when a
+	 * duplicate ACK is received and we still have data in our
+	 * transmit queue.)
+	 */
+	if ( ack_len == 0 )
+		return 0;
+
+	/* Stop the retransmission timer */
+	stop_timer ( &tcp->timer );
+
+	/* Determine acknowledged flags and data length */
+	len = ack_len;
+	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
+			( TCP_SYN | TCP_FIN ) );
+	if ( acked_flags )
+		len--;
+
+	/* Update SEQ and sent counters, and window size */
+	tcp->snd_seq = ack;
+	tcp->snd_sent = 0;
+	tcp->snd_win = win;
+
+	/* Remove any acknowledged data from transmit queue */
+	tcp_process_tx_queue ( tcp, len, NULL, 1 );
+		
+	/* Mark SYN/FIN as acknowledged if applicable. */
+	if ( acked_flags )
+		tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
+
+	/* Start sending FIN if we've had all possible data ACKed */
+	if ( list_empty ( &tcp->tx_queue ) && ( tcp->flags & TCP_XFER_CLOSED ) )
+		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
+
+	return 0;
+}
+
+/**
+ * Handle TCP received data
+ *
+ * @v tcp		TCP connection
+ * @v seq		SEQ value (in host-endian order)
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ *
+ * This function takes ownership of the I/O buffer.
+ */
+static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq,
+			 struct io_buffer *iobuf ) {
+	uint32_t already_rcvd;
+	uint32_t len;
+	int rc;
+
+	/* Ignore duplicate or out-of-order data */
+	already_rcvd = ( tcp->rcv_ack - seq );
+	len = iob_len ( iobuf );
+	if ( already_rcvd >= len ) {
+		free_iob ( iobuf );
+		return 0;
+	}
+	iob_pull ( iobuf, already_rcvd );
+	len -= already_rcvd;
+
+	/* Acknowledge new data */
+	tcp_rx_seq ( tcp, len );
+
+	/* Deliver data to application */
+	if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
+		DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n",
+		       tcp, seq, ( seq + len ), strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle TCP received FIN
+ *
+ * @v tcp		TCP connection
+ * @v seq		SEQ value (in host-endian order)
+ * @ret rc		Return status code
+ */
+static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) {
+
+	/* Ignore duplicate or out-of-order FIN */
+	if ( seq != tcp->rcv_ack )
+		return 0;
+
+	/* Acknowledge FIN */
+	tcp_rx_seq ( tcp, 1 );
+
+	/* Mark FIN as received */
+	tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
+
+	/* Close connection */
+	tcp_close ( tcp, 0 );
+
+	return 0;
+}
+
+/**
+ * Handle TCP received RST
+ *
+ * @v tcp		TCP connection
+ * @v seq		SEQ value (in host-endian order)
+ * @ret rc		Return status code
+ */
+static int tcp_rx_rst ( struct tcp_connection *tcp, uint32_t seq ) {
+
+	/* Accept RST only if it falls within the window.  If we have
+	 * not yet received a SYN, then we have no window to test
+	 * against, so fall back to checking that our SYN has been
+	 * ACKed.
+	 */
+	if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) {
+		if ( ! tcp_in_window ( seq, tcp->rcv_ack, tcp->rcv_win ) )
+			return 0;
+	} else {
+		if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
+			return 0;
+	}
+
+	/* Abort connection */
+	tcp->tcp_state = TCP_CLOSED;
+	tcp_dump_state ( tcp );
+	tcp_close ( tcp, -ECONNRESET );
+
+	DBGC ( tcp, "TCP %p connection reset by peer\n", tcp );
+	return -ECONNRESET;
+}
+
+/**
+ * Enqueue received TCP packet
+ *
+ * @v tcp		TCP connection
+ * @v seq		SEQ value (in host-endian order)
+ * @v flags		TCP flags
+ * @v iobuf		I/O buffer
+ */
+static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
+			     uint8_t flags, struct io_buffer *iobuf ) {
+	struct tcp_rx_queued_header *tcpqhdr;
+	struct io_buffer *queued;
+	size_t len;
+	uint32_t seq_len;
+
+	/* Calculate remaining flags and sequence length.  Note that
+	 * SYN, if present, has already been processed by this point.
+	 */
+	flags &= TCP_FIN;
+	len = iob_len ( iobuf );
+	seq_len = ( len + ( flags ? 1 : 0 ) );
+
+	/* Discard immediately (to save memory) if:
+	 *
+	 * a) we have not yet received a SYN (and so have no defined
+	 *    receive window), or
+	 * b) the packet lies entirely outside the receive window, or
+	 * c) there is no further content to process.
+	 */
+	if ( ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) ||
+	     ( tcp_cmp ( seq, tcp->rcv_ack + tcp->rcv_win ) >= 0 ) ||
+	     ( tcp_cmp ( seq + seq_len, tcp->rcv_ack ) < 0 ) ||
+	     ( seq_len == 0 ) ) {
+		free_iob ( iobuf );
+		return;
+	}
+
+	/* Add internal header */
+	tcpqhdr = iob_push ( iobuf, sizeof ( *tcpqhdr ) );
+	tcpqhdr->seq = seq;
+	tcpqhdr->flags = flags;
+
+	/* Add to RX queue */
+	list_for_each_entry ( queued, &tcp->rx_queue, list ) {
+		tcpqhdr = queued->data;
+		if ( tcp_cmp ( seq, tcpqhdr->seq ) < 0 )
+			break;
+	}
+	list_add_tail ( &iobuf->list, &queued->list );
+}
+
+/**
+ * Process receive queue
+ *
+ * @v tcp		TCP connection
+ */
+static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
+	struct io_buffer *iobuf;
+	struct tcp_rx_queued_header *tcpqhdr;
+	uint32_t seq;
+	unsigned int flags;
+	size_t len;
+
+	/* Process all applicable received buffers.  Note that we
+	 * cannot use list_for_each_entry() to iterate over the RX
+	 * queue, since tcp_discard() may remove packets from the RX
+	 * queue while we are processing.
+	 */
+	while ( ( iobuf = list_first_entry ( &tcp->rx_queue, struct io_buffer,
+					     list ) ) ) {
+
+		/* Stop processing when we hit the first gap */
+		tcpqhdr = iobuf->data;
+		if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
+			break;
+
+		/* Strip internal header and remove from RX queue */
+		list_del ( &iobuf->list );
+		seq = tcpqhdr->seq;
+		flags = tcpqhdr->flags;
+		iob_pull ( iobuf, sizeof ( *tcpqhdr ) );
+		len = iob_len ( iobuf );
+
+		/* Handle new data, if any */
+		tcp_rx_data ( tcp, seq, iob_disown ( iobuf ) );
+		seq += len;
+
+		/* Handle FIN, if present */
+		if ( flags & TCP_FIN ) {
+			tcp_rx_fin ( tcp, seq );
+			seq++;
+		}
+	}
+}
+
+/**
+ * Process received packet
+ *
+ * @v iobuf		I/O buffer
+ * @v st_src		Partially-filled source address
+ * @v st_dest		Partially-filled destination address
+ * @v pshdr_csum	Pseudo-header checksum
+ * @ret rc		Return status code
+  */
+static int tcp_rx ( struct io_buffer *iobuf,
+		    struct sockaddr_tcpip *st_src,
+		    struct sockaddr_tcpip *st_dest __unused,
+		    uint16_t pshdr_csum ) {
+	struct tcp_header *tcphdr = iobuf->data;
+	struct tcp_connection *tcp;
+	struct tcp_options options;
+	size_t hlen;
+	uint16_t csum;
+	uint32_t seq;
+	uint32_t ack;
+	uint32_t win;
+	unsigned int flags;
+	size_t len;
+	uint32_t seq_len;
+	int rc;
+
+	/* Sanity check packet */
+	if ( iob_len ( iobuf ) < sizeof ( *tcphdr ) ) {
+		DBG ( "TCP packet too short at %zd bytes (min %zd bytes)\n",
+		      iob_len ( iobuf ), sizeof ( *tcphdr ) );
+		rc = -EINVAL;
+		goto discard;
+	}
+	hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
+	if ( hlen < sizeof ( *tcphdr ) ) {
+		DBG ( "TCP header too short at %zd bytes (min %zd bytes)\n",
+		      hlen, sizeof ( *tcphdr ) );
+		rc = -EINVAL;
+		goto discard;
+	}
+	if ( hlen > iob_len ( iobuf ) ) {
+		DBG ( "TCP header too long at %zd bytes (max %zd bytes)\n",
+		      hlen, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto discard;
+	}
+	csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
+				       iob_len ( iobuf ) );
+	if ( csum != 0 ) {
+		DBG ( "TCP checksum incorrect (is %04x including checksum "
+		      "field, should be 0000)\n", csum );
+		rc = -EINVAL;
+		goto discard;
+	}
+	
+	/* Parse parameters from header and strip header */
+	tcp = tcp_demux ( ntohs ( tcphdr->dest ) );
+	seq = ntohl ( tcphdr->seq );
+	ack = ntohl ( tcphdr->ack );
+	win = ntohs ( tcphdr->win );
+	flags = tcphdr->flags;
+	tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
+		      ( hlen - sizeof ( *tcphdr ) ), &options );
+	if ( options.tsopt )
+		tcp->ts_val = ntohl ( options.tsopt->tsval );
+	iob_pull ( iobuf, hlen );
+	len = iob_len ( iobuf );
+	seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) +
+		    ( ( flags & TCP_FIN ) ? 1 : 0 ) );
+
+	/* Dump header */
+	DBGC2 ( tcp, "TCP %p RX %d<-%d           %08x %08x..%08x %4zd",
+		tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
+		ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ),
+		( ntohl ( tcphdr->seq ) + seq_len ), len );
+	tcp_dump_flags ( tcp, tcphdr->flags );
+	DBGC2 ( tcp, "\n" );
+
+	/* If no connection was found, send RST */
+	if ( ! tcp ) {
+		tcp_xmit_reset ( tcp, st_src, tcphdr );
+		rc = -ENOTCONN;
+		goto discard;
+	}
+
+	/* Handle ACK, if present */
+	if ( flags & TCP_ACK ) {
+		if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) {
+			tcp_xmit_reset ( tcp, st_src, tcphdr );
+			goto discard;
+		}
+	}
+
+	/* Force an ACK if this packet is out of order */
+	if ( ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) &&
+	     ( seq != tcp->rcv_ack ) ) {
+		tcp->flags |= TCP_ACK_PENDING;
+	}
+
+	/* Handle SYN, if present */
+	if ( flags & TCP_SYN ) {
+		tcp_rx_syn ( tcp, seq, &options );
+		seq++;
+	}
+
+	/* Handle RST, if present */
+	if ( flags & TCP_RST ) {
+		if ( ( rc = tcp_rx_rst ( tcp, seq ) ) != 0 )
+			goto discard;
+	}
+
+	/* Enqueue received data */
+	tcp_rx_enqueue ( tcp, seq, flags, iob_disown ( iobuf ) );
+
+	/* Process receive queue */
+	tcp_process_rx_queue ( tcp );
+
+	/* Dump out any state change as a result of the received packet */
+	tcp_dump_state ( tcp );
+
+	/* Send out any pending data */
+	tcp_xmit ( tcp );
+
+	/* If this packet was the last we expect to receive, set up
+	 * timer to expire and cause the connection to be freed.
+	 */
+	if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) {
+		stop_timer ( &tcp->wait );
+		start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) );
+	}
+
+	return 0;
+
+ discard:
+	/* Free received packet */
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** TCP protocol */
+struct tcpip_protocol tcp_protocol __tcpip_protocol = {
+	.name = "TCP",
+	.rx = tcp_rx,
+	.tcpip_proto = IP_TCP,
+};
+
+/**
+ * Discard some cached TCP data
+ *
+ * @ret discarded	Number of cached items discarded
+ */
+static unsigned int tcp_discard ( void ) {
+	struct tcp_connection *tcp;
+	struct io_buffer *iobuf;
+	unsigned int discarded = 0;
+
+	/* Try to drop one queued RX packet from each connection */
+	list_for_each_entry ( tcp, &tcp_conns, list ) {
+		list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
+			list_del ( &iobuf->list );
+			free_iob ( iobuf );
+			discarded++;
+			break;
+		}
+	}
+
+	return discarded;
+}
+
+/** TCP cache discarder */
+struct cache_discarder tcp_cache_discarder __cache_discarder = {
+	.discard = tcp_discard,
+};
+
+/***************************************************************************
+ *
+ * Data transfer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Close interface
+ *
+ * @v tcp		TCP connection
+ * @v rc		Reason for close
+ */
+static void tcp_xfer_close ( struct tcp_connection *tcp, int rc ) {
+
+	/* Close data transfer interface */
+	tcp_close ( tcp, rc );
+
+	/* Transmit FIN, if possible */
+	tcp_xmit ( tcp );
+}
+
+/**
+ * Check flow control window
+ *
+ * @v tcp		TCP connection
+ * @ret len		Length of window
+ */
+static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
+
+	/* Not ready if data queue is non-empty.  This imposes a limit
+	 * of only one unACKed packet in the TX queue at any time; we
+	 * do this to conserve memory usage.
+	 */
+	if ( ! list_empty ( &tcp->tx_queue ) )
+		return 0;
+
+	/* Return TCP window length */
+	return tcp_xmit_win ( tcp );
+}
+
+/**
+ * Deliver datagram as I/O buffer
+ *
+ * @v tcp		TCP connection
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int tcp_xfer_deliver ( struct tcp_connection *tcp,
+			      struct io_buffer *iobuf,
+			      struct xfer_metadata *meta __unused ) {
+
+	/* Enqueue packet */
+	list_add_tail ( &iobuf->list, &tcp->tx_queue );
+
+	/* Transmit data, if possible */
+	tcp_xmit ( tcp );
+
+	return 0;
+}
+
+/** TCP data transfer interface operations */
+static struct interface_operation tcp_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct tcp_connection *, tcp_xfer_deliver ),
+	INTF_OP ( xfer_window, struct tcp_connection *, tcp_xfer_window ),
+	INTF_OP ( intf_close, struct tcp_connection *, tcp_xfer_close ),
+};
+
+/** TCP data transfer interface descriptor */
+static struct interface_descriptor tcp_xfer_desc =
+	INTF_DESC ( struct tcp_connection, xfer, tcp_xfer_operations );
+
+/***************************************************************************
+ *
+ * Openers
+ *
+ ***************************************************************************
+ */
+
+/** TCP socket opener */
+struct socket_opener tcp_socket_opener __socket_opener = {
+	.semantics	= TCP_SOCK_STREAM,
+	.family		= AF_INET,
+	.open		= tcp_open,
+};
+
+/** Linkage hack */
+int tcp_sock_stream = TCP_SOCK_STREAM;
+
+/**
+ * Open TCP URI
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int tcp_open_uri ( struct interface *xfer, struct uri *uri ) {
+	struct sockaddr_tcpip peer;
+
+	/* Sanity check */
+	if ( ! uri->host )
+		return -EINVAL;
+
+	memset ( &peer, 0, sizeof ( peer ) );
+	peer.st_port = htons ( uri_port ( uri, 0 ) );
+	return xfer_open_named_socket ( xfer, SOCK_STREAM,
+					( struct sockaddr * ) &peer,
+					uri->host, NULL );
+}
+
+/** TCP URI opener */
+struct uri_opener tcp_uri_opener __uri_opener = {
+	.scheme		= "tcp",
+	.open		= tcp_open_uri,
+};
+
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcp/ftp.c b/qemu-0.15.x/roms/ipxe/src/net/tcp/ftp.c
new file mode 100644
index 0000000..957f05c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcp/ftp.c
@@ -0,0 +1,491 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/socket.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/in.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/features.h>
+#include <ipxe/ftp.h>
+
+/** @file
+ *
+ * File transfer protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "FTP", DHCP_EB_FEATURE_FTP, 1 );
+
+/**
+ * FTP states
+ *
+ * These @b must be sequential, i.e. a successful FTP session must
+ * pass through each of these states in order.
+ */
+enum ftp_state {
+	FTP_CONNECT = 0,
+	FTP_USER,
+	FTP_PASS,
+	FTP_TYPE,
+	FTP_PASV,
+	FTP_RETR,
+	FTP_WAIT,
+	FTP_QUIT,
+	FTP_DONE,
+};
+
+/**
+ * An FTP request
+ *
+ */
+struct ftp_request {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** URI being fetched */
+	struct uri *uri;
+	/** FTP control channel interface */
+	struct interface control;
+	/** FTP data channel interface */
+	struct interface data;
+
+	/** Current state */
+	enum ftp_state state;
+	/** Buffer to be filled with data received via the control channel */
+	char *recvbuf;
+	/** Remaining size of recvbuf */
+	size_t recvsize;
+	/** FTP status code, as text */
+	char status_text[5];
+	/** Passive-mode parameters, as text */
+	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
+};
+
+/**
+ * Free FTP request
+ *
+ * @v refcnt		Reference counter
+ */
+static void ftp_free ( struct refcnt *refcnt ) {
+	struct ftp_request *ftp =
+		container_of ( refcnt, struct ftp_request, refcnt );
+
+	DBGC ( ftp, "FTP %p freed\n", ftp );
+
+	uri_put ( ftp->uri );
+	free ( ftp );
+}
+
+/**
+ * Mark FTP operation as complete
+ *
+ * @v ftp		FTP request
+ * @v rc		Return status code
+ */
+static void ftp_done ( struct ftp_request *ftp, int rc ) {
+
+	DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) );
+
+	/* Close all data transfer interfaces */
+	intf_shutdown ( &ftp->data, rc );
+	intf_shutdown ( &ftp->control, rc );
+	intf_shutdown ( &ftp->xfer, rc );
+}
+
+/*****************************************************************************
+ *
+ * FTP control channel
+ *
+ */
+
+/** An FTP control channel string */
+struct ftp_control_string {
+	/** Literal portion */
+	const char *literal;
+	/** Variable portion
+	 *
+	 * @v ftp	FTP request
+	 * @ret string	Variable portion of string
+	 */
+	const char * ( *variable ) ( struct ftp_request *ftp );
+};
+
+/**
+ * Retrieve FTP pathname
+ *
+ * @v ftp		FTP request
+ * @ret path		FTP pathname
+ */
+static const char * ftp_uri_path ( struct ftp_request *ftp ) {
+	return ftp->uri->path;
+}
+
+/**
+ * Retrieve FTP user
+ *
+ * @v ftp		FTP request
+ * @ret user		FTP user
+ */
+static const char * ftp_user ( struct ftp_request *ftp ) {
+	static char *ftp_default_user = "anonymous";
+	return ftp->uri->user ? ftp->uri->user : ftp_default_user;
+}
+
+/**
+ * Retrieve FTP password
+ *
+ * @v ftp		FTP request
+ * @ret password	FTP password
+ */
+static const char * ftp_password ( struct ftp_request *ftp ) {
+	static char *ftp_default_password = "ipxe at ipxe.org";
+	return ftp->uri->password ? ftp->uri->password : ftp_default_password;
+}
+
+/** FTP control channel strings */
+static struct ftp_control_string ftp_strings[] = {
+	[FTP_CONNECT]	= { NULL, NULL },
+	[FTP_USER]	= { "USER ", ftp_user },
+	[FTP_PASS]	= { "PASS ", ftp_password },
+	[FTP_TYPE]	= { "TYPE I", NULL },
+	[FTP_PASV]	= { "PASV", NULL },
+	[FTP_RETR]	= { "RETR ", ftp_uri_path },
+	[FTP_WAIT]	= { NULL, NULL },
+	[FTP_QUIT]	= { "QUIT", NULL },
+	[FTP_DONE]	= { NULL, NULL },
+};
+
+/**
+ * Parse FTP byte sequence value
+ *
+ * @v text		Text string
+ * @v value		Value buffer
+ * @v len		Length of value buffer
+ *
+ * This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd"
+ * form for IP addresses in PORT commands) into a byte sequence.  @c
+ * *text will be updated to point beyond the end of the parsed byte
+ * sequence.
+ *
+ * This function is safe in the presence of malformed data, though the
+ * output is undefined.
+ */
+static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
+	do {
+		*(value++) = strtoul ( *text, text, 10 );
+		if ( **text )
+			(*text)++;
+	} while ( --len );
+}
+
+/**
+ * Move to next state and send the appropriate FTP control string
+ *
+ * @v ftp		FTP request
+ *
+ */
+static void ftp_next_state ( struct ftp_request *ftp ) {
+	struct ftp_control_string *ftp_string;
+	const char *literal;
+	const char *variable;
+
+	/* Move to next state */
+	if ( ftp->state < FTP_DONE )
+		ftp->state++;
+
+	/* Send control string if needed */
+	ftp_string = &ftp_strings[ftp->state];
+	literal = ftp_string->literal;
+	variable = ( ftp_string->variable ?
+		     ftp_string->variable ( ftp ) : "" );
+	if ( literal ) {
+		DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
+		xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
+	}
+}
+
+/**
+ * Handle an FTP control channel response
+ *
+ * @v ftp		FTP request
+ *
+ * This is called once we have received a complete response line.
+ */
+static void ftp_reply ( struct ftp_request *ftp ) {
+	char status_major = ftp->status_text[0];
+	char separator = ftp->status_text[3];
+
+	DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text );
+
+	/* Ignore malformed lines */
+	if ( separator != ' ' )
+		return;
+
+	/* Ignore "intermediate" responses (1xx codes) */
+	if ( status_major == '1' )
+		return;
+
+	/* Anything other than success (2xx) or, in the case of a
+	 * repsonse to a "USER" command, a password prompt (3xx), is a
+	 * fatal error.
+	 */
+	if ( ! ( ( status_major == '2' ) ||
+		 ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){
+		/* Flag protocol error and close connections */
+		ftp_done ( ftp, -EPROTO );
+		return;
+	}
+
+	/* Open passive connection when we get "PASV" response */
+	if ( ftp->state == FTP_PASV ) {
+		char *ptr = ftp->passive_text;
+		union {
+			struct sockaddr_in sin;
+			struct sockaddr sa;
+		} sa;
+		int rc;
+
+		sa.sin.sin_family = AF_INET;
+		ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr,
+				  sizeof ( sa.sin.sin_addr ) );
+		ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port,
+				  sizeof ( sa.sin.sin_port ) );
+		if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM,
+					       &sa.sa, NULL ) ) != 0 ) {
+			DBGC ( ftp, "FTP %p could not open data connection\n",
+			       ftp );
+			ftp_done ( ftp, rc );
+			return;
+		}
+	}
+
+	/* Move to next state and send control string */
+	ftp_next_state ( ftp );
+	
+}
+
+/**
+ * Handle new data arriving on FTP control channel
+ *
+ * @v ftp		FTP request
+ * @v iob		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ *
+ * Data is collected until a complete line is received, at which point
+ * its information is passed to ftp_reply().
+ */
+static int ftp_control_deliver ( struct ftp_request *ftp,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta __unused ) {
+	char *data = iobuf->data;
+	size_t len = iob_len ( iobuf );
+	char *recvbuf = ftp->recvbuf;
+	size_t recvsize = ftp->recvsize;
+	char c;
+	
+	while ( len-- ) {
+		c = *(data++);
+		switch ( c ) {
+		case '\r' :
+		case '\n' :
+			/* End of line: call ftp_reply() to handle
+			 * completed reply.  Avoid calling ftp_reply()
+			 * twice if we receive both \r and \n.
+			 */
+			if ( recvsize == 0 )
+				ftp_reply ( ftp );
+			/* Start filling up the status code buffer */
+			recvbuf = ftp->status_text;
+			recvsize = sizeof ( ftp->status_text ) - 1;
+			break;
+		case '(' :
+			/* Start filling up the passive parameter buffer */
+			recvbuf = ftp->passive_text;
+			recvsize = sizeof ( ftp->passive_text ) - 1;
+			break;
+		case ')' :
+			/* Stop filling the passive parameter buffer */
+			recvsize = 0;
+			break;
+		default :
+			/* Fill up buffer if applicable */
+			if ( recvsize > 0 ) {
+				*(recvbuf++) = c;
+				recvsize--;
+			}
+			break;
+		}
+	}
+
+	/* Store for next invocation */
+	ftp->recvbuf = recvbuf;
+	ftp->recvsize = recvsize;
+
+	/* Free I/O buffer */
+	free_iob ( iobuf );
+
+	return 0;
+}
+
+/** FTP control channel interface operations */
+static struct interface_operation ftp_control_operations[] = {
+	INTF_OP ( xfer_deliver, struct ftp_request *, ftp_control_deliver ),
+	INTF_OP ( intf_close, struct ftp_request *, ftp_done ),
+};
+
+/** FTP control channel interface descriptor */
+static struct interface_descriptor ftp_control_desc =
+	INTF_DESC ( struct ftp_request, control, ftp_control_operations );
+
+/*****************************************************************************
+ *
+ * FTP data channel
+ *
+ */
+
+/**
+ * Handle FTP data channel being closed
+ *
+ * @v ftp		FTP request
+ * @v rc		Reason for closure
+ *
+ * When the data channel is closed, the control channel should be left
+ * alone; the server will send a completion message via the control
+ * channel which we'll pick up.
+ *
+ * If the data channel is closed due to an error, we abort the request.
+ */
+static void ftp_data_closed ( struct ftp_request *ftp, int rc ) {
+
+	DBGC ( ftp, "FTP %p data connection closed: %s\n",
+	       ftp, strerror ( rc ) );
+	
+	/* If there was an error, close control channel and record status */
+	if ( rc ) {
+		ftp_done ( ftp, rc );
+	} else {
+		ftp_next_state ( ftp );
+	}
+}
+
+/**
+ * Handle data delivery via FTP data channel
+ *
+ * @v ftp		FTP request
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int ftp_data_deliver ( struct ftp_request *ftp,
+			      struct io_buffer *iobuf,
+			      struct xfer_metadata *meta __unused ) {
+	int rc;
+
+	if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
+		DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
+		       ftp, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** FTP data channel interface operations */
+static struct interface_operation ftp_data_operations[] = {
+	INTF_OP ( xfer_deliver, struct ftp_request *, ftp_data_deliver ),
+	INTF_OP ( intf_close, struct ftp_request *, ftp_data_closed ),
+};
+
+/** FTP data channel interface descriptor */
+static struct interface_descriptor ftp_data_desc =
+	INTF_DESC ( struct ftp_request, data, ftp_data_operations );
+
+/*****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
+/** FTP data transfer interface operations */
+static struct interface_operation ftp_xfer_operations[] = {
+	INTF_OP ( intf_close, struct ftp_request *, ftp_done ),
+};
+
+/** FTP data transfer interface descriptor */
+static struct interface_descriptor ftp_xfer_desc =
+	INTF_DESC ( struct ftp_request, xfer, ftp_xfer_operations );
+
+/*****************************************************************************
+ *
+ * URI opener
+ *
+ */
+
+/**
+ * Initiate an FTP connection
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int ftp_open ( struct interface *xfer, struct uri *uri ) {
+	struct ftp_request *ftp;
+	struct sockaddr_tcpip server;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! uri->path )
+		return -EINVAL;
+	if ( ! uri->host )
+		return -EINVAL;
+
+	/* Allocate and populate structure */
+	ftp = zalloc ( sizeof ( *ftp ) );
+	if ( ! ftp )
+		return -ENOMEM;
+	ref_init ( &ftp->refcnt, ftp_free );
+	intf_init ( &ftp->xfer, &ftp_xfer_desc, &ftp->refcnt );
+	intf_init ( &ftp->control, &ftp_control_desc, &ftp->refcnt );
+	intf_init ( &ftp->data, &ftp_data_desc, &ftp->refcnt );
+	ftp->uri = uri_get ( uri );
+	ftp->recvbuf = ftp->status_text;
+	ftp->recvsize = sizeof ( ftp->status_text ) - 1;
+
+	DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
+
+	/* Open control connection */
+	memset ( &server, 0, sizeof ( server ) );
+	server.st_port = htons ( uri_port ( uri, FTP_PORT ) );
+	if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM,
+					     ( struct sockaddr * ) &server,
+					     uri->host, NULL ) ) != 0 )
+		goto err;
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &ftp->xfer, xfer );
+	ref_put ( &ftp->refcnt );
+	return 0;
+
+ err:
+	DBGC ( ftp, "FTP %p could not create request: %s\n", 
+	       ftp, strerror ( rc ) );
+	ftp_done ( ftp, rc );
+	ref_put ( &ftp->refcnt );
+	return rc;
+}
+
+/** FTP URI opener */
+struct uri_opener ftp_uri_opener __uri_opener = {
+	.scheme	= "ftp",
+	.open	= ftp_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcp/http.c b/qemu-0.15.x/roms/ipxe/src/net/tcp/http.c
new file mode 100644
index 0000000..20f14e6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcp/http.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP)
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/uri.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/socket.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/process.h>
+#include <ipxe/linebuf.h>
+#include <ipxe/features.h>
+#include <ipxe/base64.h>
+#include <ipxe/http.h>
+
+FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
+
+/** HTTP receive state */
+enum http_rx_state {
+	HTTP_RX_RESPONSE = 0,
+	HTTP_RX_HEADER,
+	HTTP_RX_DATA,
+	HTTP_RX_DEAD,
+};
+
+/**
+ * An HTTP request
+ *
+ */
+struct http_request {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** URI being fetched */
+	struct uri *uri;
+	/** Transport layer interface */
+	struct interface socket;
+
+	/** TX process */
+	struct process process;
+
+	/** HTTP response code */
+	unsigned int response;
+	/** HTTP Content-Length */
+	size_t content_length;
+	/** Received length */
+	size_t rx_len;
+	/** RX state */
+	enum http_rx_state rx_state;
+	/** Line buffer for received header lines */
+	struct line_buffer linebuf;
+};
+
+/**
+ * Free HTTP request
+ *
+ * @v refcnt		Reference counter
+ */
+static void http_free ( struct refcnt *refcnt ) {
+	struct http_request *http =
+		container_of ( refcnt, struct http_request, refcnt );
+
+	uri_put ( http->uri );
+	empty_line_buffer ( &http->linebuf );
+	free ( http );
+};
+
+/**
+ * Mark HTTP request as complete
+ *
+ * @v http		HTTP request
+ * @v rc		Return status code
+ */
+static void http_done ( struct http_request *http, int rc ) {
+
+	/* Prevent further processing of any current packet */
+	http->rx_state = HTTP_RX_DEAD;
+
+	/* If we had a Content-Length, and the received content length
+	 * isn't correct, flag an error
+	 */
+	if ( http->content_length &&
+	     ( http->content_length != http->rx_len ) ) {
+		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
+		       http, http->rx_len, http->content_length );
+		rc = -EIO;
+	}
+
+	/* Remove process */
+	process_del ( &http->process );
+
+	/* Close all data transfer interfaces */
+	intf_shutdown ( &http->socket, rc );
+	intf_shutdown ( &http->xfer, rc );
+}
+
+/**
+ * Convert HTTP response code to return status code
+ *
+ * @v response		HTTP response code
+ * @ret rc		Return status code
+ */
+static int http_response_to_rc ( unsigned int response ) {
+	switch ( response ) {
+	case 200:
+	case 301:
+	case 302:
+		return 0;
+	case 404:
+		return -ENOENT;
+	case 403:
+		return -EPERM;
+	case 401:
+		return -EACCES;
+	default:
+		return -EIO;
+	}
+}
+
+/**
+ * Handle HTTP response
+ *
+ * @v http		HTTP request
+ * @v response		HTTP response
+ * @ret rc		Return status code
+ */
+static int http_rx_response ( struct http_request *http, char *response ) {
+	char *spc;
+	int rc;
+
+	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
+
+	/* Check response starts with "HTTP/" */
+	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
+		return -EIO;
+
+	/* Locate and check response code */
+	spc = strchr ( response, ' ' );
+	if ( ! spc )
+		return -EIO;
+	http->response = strtoul ( spc, NULL, 10 );
+	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
+		return rc;
+
+	/* Move to received headers */
+	http->rx_state = HTTP_RX_HEADER;
+	return 0;
+}
+
+/**
+ * Handle HTTP Location header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_location ( struct http_request *http, const char *value ) {
+	int rc;
+
+	/* Redirect to new location */
+	DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
+	if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
+				    value ) ) != 0 ) {
+		DBGC ( http, "HTTP %p could not redirect: %s\n",
+		       http, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle HTTP Content-Length header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_content_length ( struct http_request *http,
+				    const char *value ) {
+	char *endp;
+
+	http->content_length = strtoul ( value, &endp, 10 );
+	if ( *endp != '\0' ) {
+		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
+		       http, value );
+		return -EIO;
+	}
+
+	/* Use seek() to notify recipient of filesize */
+	xfer_seek ( &http->xfer, http->content_length );
+	xfer_seek ( &http->xfer, 0 );
+
+	return 0;
+}
+
+/** An HTTP header handler */
+struct http_header_handler {
+	/** Name (e.g. "Content-Length") */
+	const char *header;
+	/** Handle received header
+	 *
+	 * @v http	HTTP request
+	 * @v value	HTTP header value
+	 * @ret rc	Return status code
+	 *
+	 * If an error is returned, the download will be aborted.
+	 */
+	int ( * rx ) ( struct http_request *http, const char *value );
+};
+
+/** List of HTTP header handlers */
+static struct http_header_handler http_header_handlers[] = {
+	{
+		.header = "Location",
+		.rx = http_rx_location,
+	},
+	{
+		.header = "Content-Length",
+		.rx = http_rx_content_length,
+	},
+	{ NULL, NULL }
+};
+
+/**
+ * Handle HTTP header
+ *
+ * @v http		HTTP request
+ * @v header		HTTP header
+ * @ret rc		Return status code
+ */
+static int http_rx_header ( struct http_request *http, char *header ) {
+	struct http_header_handler *handler;
+	char *separator;
+	char *value;
+	int rc;
+
+	/* An empty header line marks the transition to the data phase */
+	if ( ! header[0] ) {
+		DBGC ( http, "HTTP %p start of data\n", http );
+		empty_line_buffer ( &http->linebuf );
+		http->rx_state = HTTP_RX_DATA;
+		return 0;
+	}
+
+	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
+
+	/* Split header at the ": " */
+	separator = strstr ( header, ": " );
+	if ( ! separator ) {
+		DBGC ( http, "HTTP %p malformed header\n", http );
+		return -EIO;
+	}
+	*separator = '\0';
+	value = ( separator + 2 );
+
+	/* Hand off to header handler, if one exists */
+	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
+		if ( strcasecmp ( header, handler->header ) == 0 ) {
+			if ( ( rc = handler->rx ( http, value ) ) != 0 )
+				return rc;
+			break;
+		}
+	}
+	return 0;
+}
+
+/** An HTTP line-based data handler */
+struct http_line_handler {
+	/** Handle line
+	 *
+	 * @v http	HTTP request
+	 * @v line	Line to handle
+	 * @ret rc	Return status code
+	 */
+	int ( * rx ) ( struct http_request *http, char *line );
+};
+
+/** List of HTTP line-based data handlers */
+static struct http_line_handler http_line_handlers[] = {
+	[HTTP_RX_RESPONSE]	= { .rx = http_rx_response },
+	[HTTP_RX_HEADER]	= { .rx = http_rx_header },
+};
+
+/**
+ * Handle new data arriving via HTTP connection in the data phase
+ *
+ * @v http		HTTP request
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int http_rx_data ( struct http_request *http,
+			  struct io_buffer *iobuf ) {
+	int rc;
+
+	/* Update received length */
+	http->rx_len += iob_len ( iobuf );
+
+	/* Hand off data buffer */
+	if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
+		return rc;
+
+	/* If we have reached the content-length, stop now */
+	if ( http->content_length &&
+	     ( http->rx_len >= http->content_length ) ) {
+		http_done ( http, 0 );
+	}
+
+	return 0;
+}
+
+/**
+ * Handle new data arriving via HTTP connection
+ *
+ * @v http		HTTP request
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int http_socket_deliver ( struct http_request *http,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta __unused ) {
+	struct http_line_handler *lh;
+	char *line;
+	ssize_t len;
+	int rc = 0;
+
+	while ( iob_len ( iobuf ) ) {
+		switch ( http->rx_state ) {
+		case HTTP_RX_DEAD:
+			/* Do no further processing */
+			goto done;
+		case HTTP_RX_DATA:
+			/* Once we're into the data phase, just fill
+			 * the data buffer
+			 */
+			rc = http_rx_data ( http, iob_disown ( iobuf ) );
+			goto done;
+		case HTTP_RX_RESPONSE:
+		case HTTP_RX_HEADER:
+			/* In the other phases, buffer and process a
+			 * line at a time
+			 */
+			len = line_buffer ( &http->linebuf, iobuf->data,
+					    iob_len ( iobuf ) );
+			if ( len < 0 ) {
+				rc = len;
+				DBGC ( http, "HTTP %p could not buffer line: "
+				       "%s\n", http, strerror ( rc ) );
+				goto done;
+			}
+			iob_pull ( iobuf, len );
+			line = buffered_line ( &http->linebuf );
+			if ( line ) {
+				lh = &http_line_handlers[http->rx_state];
+				if ( ( rc = lh->rx ( http, line ) ) != 0 )
+					goto done;
+			}
+			break;
+		default:
+			assert ( 0 );
+			break;
+		}
+	}
+
+ done:
+	if ( rc )
+		http_done ( http, rc );
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * HTTP process
+ *
+ * @v process		Process
+ */
+static void http_step ( struct process *process ) {
+	struct http_request *http =
+		container_of ( process, struct http_request, process );
+	const char *host = http->uri->host;
+	const char *user = http->uri->user;
+	const char *password =
+		( http->uri->password ? http->uri->password : "" );
+	size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
+					strlen ( password ) ) : 0 );
+	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
+	uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
+	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
+	int rc;
+	int request_len = unparse_uri ( NULL, 0, http->uri,
+					URI_PATH_BIT | URI_QUERY_BIT );
+
+	if ( xfer_window ( &http->socket ) ) {
+		char request[request_len + 1];
+
+		/* Construct path?query request */
+		unparse_uri ( request, sizeof ( request ), http->uri,
+			      URI_PATH_BIT | URI_QUERY_BIT );
+
+		/* We want to execute only once */
+		process_del ( &http->process );
+
+		/* Construct authorisation, if applicable */
+		if ( user ) {
+			/* Make "user:password" string from decoded fields */
+			snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
+				   "%s:%s", user, password );
+
+			/* Base64-encode the "user:password" string */
+			base64_encode ( user_pw, user_pw_len, user_pw_base64 );
+		}
+
+		/* Send GET request */
+		if ( ( rc = xfer_printf ( &http->socket,
+					  "GET %s%s HTTP/1.0\r\n"
+					  "User-Agent: iPXE/" VERSION "\r\n"
+					  "%s%s%s"
+					  "Host: %s\r\n"
+					  "\r\n",
+					  http->uri->path ? "" : "/",
+					  request,
+					  ( user ?
+					    "Authorization: Basic " : "" ),
+					  ( user ? user_pw_base64 : "" ),
+					  ( user ? "\r\n" : "" ),
+					  host ) ) != 0 ) {
+			http_done ( http, rc );
+		}
+	}
+}
+
+/** HTTP socket interface operations */
+static struct interface_operation http_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
+	INTF_OP ( intf_close, struct http_request *, http_done ),
+};
+
+/** HTTP socket interface descriptor */
+static struct interface_descriptor http_socket_desc =
+	INTF_DESC_PASSTHRU ( struct http_request, socket,
+			     http_socket_operations, xfer );
+
+/** HTTP data transfer interface operations */
+static struct interface_operation http_xfer_operations[] = {
+	INTF_OP ( intf_close, struct http_request *, http_done ),
+};
+
+/** HTTP data transfer interface descriptor */
+static struct interface_descriptor http_xfer_desc =
+	INTF_DESC_PASSTHRU ( struct http_request, xfer,
+			     http_xfer_operations, socket );
+
+/**
+ * Initiate an HTTP connection, with optional filter
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @v default_port	Default port number
+ * @v filter		Filter to apply to socket, or NULL
+ * @ret rc		Return status code
+ */
+int http_open_filter ( struct interface *xfer, struct uri *uri,
+		       unsigned int default_port,
+		       int ( * filter ) ( struct interface *xfer,
+					  struct interface **next ) ) {
+	struct http_request *http;
+	struct sockaddr_tcpip server;
+	struct interface *socket;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! uri->host )
+		return -EINVAL;
+
+	/* Allocate and populate HTTP structure */
+	http = zalloc ( sizeof ( *http ) );
+	if ( ! http )
+		return -ENOMEM;
+	ref_init ( &http->refcnt, http_free );
+	intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
+       	http->uri = uri_get ( uri );
+	intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
+	process_init ( &http->process, http_step, &http->refcnt );
+
+	/* Open socket */
+	memset ( &server, 0, sizeof ( server ) );
+	server.st_port = htons ( uri_port ( http->uri, default_port ) );
+	socket = &http->socket;
+	if ( filter ) {
+		if ( ( rc = filter ( socket, &socket ) ) != 0 )
+			goto err;
+	}
+	if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
+					     ( struct sockaddr * ) &server,
+					     uri->host, NULL ) ) != 0 )
+		goto err;
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &http->xfer, xfer );
+	ref_put ( &http->refcnt );
+	return 0;
+
+ err:
+	DBGC ( http, "HTTP %p could not create request: %s\n", 
+	       http, strerror ( rc ) );
+	http_done ( http, rc );
+	ref_put ( &http->refcnt );
+	return rc;
+}
+
+/**
+ * Initiate an HTTP connection
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int http_open ( struct interface *xfer, struct uri *uri ) {
+	return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
+}
+
+/** HTTP URI opener */
+struct uri_opener http_uri_opener __uri_opener = {
+	.scheme	= "http",
+	.open	= http_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcp/https.c b/qemu-0.15.x/roms/ipxe/src/net/tcp/https.c
new file mode 100644
index 0000000..805d108
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcp/https.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Secure Hyper Text Transfer Protocol (HTTPS)
+ *
+ */
+
+#include <stddef.h>
+#include <ipxe/open.h>
+#include <ipxe/tls.h>
+#include <ipxe/http.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 );
+
+/**
+ * Initiate an HTTPS connection
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int https_open ( struct interface *xfer, struct uri *uri ) {
+	return http_open_filter ( xfer, uri, HTTPS_PORT, add_tls );
+}
+
+/** HTTPS URI opener */
+struct uri_opener https_uri_opener __uri_opener = {
+	.scheme	= "https",
+	.open	= https_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcp/iscsi.c b/qemu-0.15.x/roms/ipxe/src/net/tcp/iscsi.c
new file mode 100644
index 0000000..cde3ed6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcp/iscsi.c
@@ -0,0 +1,2101 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/vsprintf.h>
+#include <ipxe/socket.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/uri.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/scsi.h>
+#include <ipxe/process.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/settings.h>
+#include <ipxe/features.h>
+#include <ipxe/base16.h>
+#include <ipxe/base64.h>
+#include <ipxe/ibft.h>
+#include <ipxe/iscsi.h>
+
+/** @file
+ *
+ * iSCSI protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
+
+/* Disambiguate the various error causes */
+#define EACCES_INCORRECT_TARGET_USERNAME \
+	__einfo_error ( EINFO_EACCES_INCORRECT_TARGET_USERNAME )
+#define EINFO_EACCES_INCORRECT_TARGET_USERNAME \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Incorrect target username" )
+#define EACCES_INCORRECT_TARGET_PASSWORD \
+	__einfo_error ( EINFO_EACCES_INCORRECT_TARGET_PASSWORD )
+#define EINFO_EACCES_INCORRECT_TARGET_PASSWORD \
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect target password" )
+#define EINVAL_ROOT_PATH_TOO_SHORT \
+	__einfo_error ( EINFO_EINVAL_ROOT_PATH_TOO_SHORT )
+#define EINFO_EINVAL_ROOT_PATH_TOO_SHORT \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Root path too short" )
+#define EINVAL_BAD_CREDENTIAL_MIX \
+	__einfo_error ( EINFO_EINVAL_BAD_CREDENTIAL_MIX )
+#define EINFO_EINVAL_BAD_CREDENTIAL_MIX \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Bad credential mix" )
+#define EINVAL_NO_ROOT_PATH \
+	__einfo_error ( EINFO_EINVAL_NO_ROOT_PATH )
+#define EINFO_EINVAL_NO_ROOT_PATH \
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "No root path" )
+#define EINVAL_NO_TARGET_IQN \
+	__einfo_error ( EINFO_EINVAL_NO_TARGET_IQN )
+#define EINFO_EINVAL_NO_TARGET_IQN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "No target IQN" )
+#define EINVAL_NO_INITIATOR_IQN \
+	__einfo_error ( EINFO_EINVAL_NO_INITIATOR_IQN )
+#define EINFO_EINVAL_NO_INITIATOR_IQN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x05, "No initiator IQN" )
+#define EIO_TARGET_UNAVAILABLE \
+	__einfo_error ( EINFO_EIO_TARGET_UNAVAILABLE )
+#define EINFO_EIO_TARGET_UNAVAILABLE \
+	__einfo_uniqify ( EINFO_EIO, 0x01, "Target not currently operational" )
+#define EIO_TARGET_NO_RESOURCES \
+	__einfo_error ( EINFO_EIO_TARGET_NO_RESOURCES )
+#define EINFO_EIO_TARGET_NO_RESOURCES \
+	__einfo_uniqify ( EINFO_EIO, 0x02, "Target out of resources" )
+#define ENOTSUP_INITIATOR_STATUS \
+	__einfo_error ( EINFO_ENOTSUP_INITIATOR_STATUS )
+#define EINFO_ENOTSUP_INITIATOR_STATUS \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported initiator status" )
+#define ENOTSUP_OPCODE \
+	__einfo_error ( EINFO_ENOTSUP_OPCODE )
+#define EINFO_ENOTSUP_OPCODE \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported opcode" )
+#define ENOTSUP_DISCOVERY \
+	__einfo_error ( EINFO_ENOTSUP_DISCOVERY )
+#define EINFO_ENOTSUP_DISCOVERY \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x03, "Discovery not supported" )
+#define ENOTSUP_TARGET_STATUS \
+	__einfo_error ( EINFO_ENOTSUP_TARGET_STATUS )
+#define EINFO_ENOTSUP_TARGET_STATUS \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x04, "Unsupported target status" )
+#define ENOTSUP_NOP_IN \
+	__einfo_error ( EINFO_ENOTSUP_NOP_IN )
+#define EINFO_ENOTSUP_NOP_IN \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x05, "Unsupported NOP-In received" )
+#define EPERM_INITIATOR_AUTHENTICATION \
+	__einfo_error ( EINFO_EPERM_INITIATOR_AUTHENTICATION )
+#define EINFO_EPERM_INITIATOR_AUTHENTICATION \
+	__einfo_uniqify ( EINFO_EPERM, 0x01, "Initiator authentication failed" )
+#define EPERM_INITIATOR_AUTHORISATION \
+	__einfo_error ( EINFO_EPERM_INITIATOR_AUTHORISATION )
+#define EINFO_EPERM_INITIATOR_AUTHORISATION \
+	__einfo_uniqify ( EINFO_EPERM, 0x02, "Initiator not authorised" )
+#define EPROTO_INVALID_CHAP_ALGORITHM \
+	__einfo_error ( EINFO_EPROTO_INVALID_CHAP_ALGORITHM )
+#define EINFO_EPROTO_INVALID_CHAP_ALGORITHM \
+	__einfo_uniqify ( EINFO_EPROTO, 0x01, "Invalid CHAP algorithm" )
+#define EPROTO_INVALID_CHAP_IDENTIFIER \
+	__einfo_error ( EINFO_EPROTO_INVALID_CHAP_IDENTIFIER )
+#define EINFO_EPROTO_INVALID_CHAP_IDENTIFIER \
+	__einfo_uniqify ( EINFO_EPROTO, 0x02, "Invalid CHAP identifier" )
+#define EPROTO_INVALID_LARGE_BINARY \
+	__einfo_error ( EINFO_EPROTO_INVALID_LARGE_BINARY )
+#define EINFO_EPROTO_INVALID_LARGE_BINARY \
+	__einfo_uniqify ( EINFO_EPROTO, 0x03, "Invalid large binary" )
+#define EPROTO_INVALID_CHAP_RESPONSE \
+	__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
+#define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
+	__einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
+
+static void iscsi_start_tx ( struct iscsi_session *iscsi );
+static void iscsi_start_login ( struct iscsi_session *iscsi );
+static void iscsi_start_data_out ( struct iscsi_session *iscsi,
+				   unsigned int datasn );
+
+/**
+ * Finish receiving PDU data into buffer
+ *
+ * @v iscsi		iSCSI session
+ */
+static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
+	free ( iscsi->rx_buffer );
+	iscsi->rx_buffer = NULL;
+}
+
+/**
+ * Receive PDU data into buffer
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Data to receive
+ * @v len		Length of data
+ * @ret rc		Return status code
+ *
+ * This can be used when the RX PDU type handler wishes to buffer up
+ * all received data and process the PDU as a single unit.  The caller
+ * is repsonsible for calling iscsi_rx_buffered_data_done() after
+ * processing the data.
+ */
+static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
+				    const void *data, size_t len ) {
+
+	/* Allocate buffer on first call */
+	if ( ! iscsi->rx_buffer ) {
+		iscsi->rx_buffer = malloc ( iscsi->rx_len );
+		if ( ! iscsi->rx_buffer )
+			return -ENOMEM;
+	}
+
+	/* Copy data to buffer */
+	assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
+	memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
+
+	return 0;
+}
+
+/**
+ * Free iSCSI session
+ *
+ * @v refcnt		Reference counter
+ */
+static void iscsi_free ( struct refcnt *refcnt ) {
+	struct iscsi_session *iscsi =
+		container_of ( refcnt, struct iscsi_session, refcnt );
+
+	free ( iscsi->initiator_iqn );
+	free ( iscsi->target_address );
+	free ( iscsi->target_iqn );
+	free ( iscsi->initiator_username );
+	free ( iscsi->initiator_password );
+	free ( iscsi->target_username );
+	free ( iscsi->target_password );
+	chap_finish ( &iscsi->chap );
+	iscsi_rx_buffered_data_done ( iscsi );
+	free ( iscsi->command );
+	free ( iscsi );
+}
+
+/**
+ * Shut down iSCSI interface
+ *
+ * @v iscsi		iSCSI session
+ * @v rc		Reason for close
+ */
+static void iscsi_close ( struct iscsi_session *iscsi, int rc ) {
+
+	/* A TCP graceful close is still an error from our point of view */
+	if ( rc == 0 )
+		rc = -ECONNRESET;
+
+	DBGC ( iscsi, "iSCSI %p closed: %s\n", iscsi, strerror ( rc ) );
+
+	/* Stop transmission process */
+	process_del ( &iscsi->process );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &iscsi->socket, rc );
+	intf_shutdown ( &iscsi->control, rc );
+	intf_shutdown ( &iscsi->data, rc );
+}
+
+/**
+ * Assign new iSCSI initiator task tag
+ *
+ * @v iscsi		iSCSI session
+ */
+static void iscsi_new_itt ( struct iscsi_session *iscsi ) {
+	static uint16_t itt_idx;
+
+	iscsi->itt = ( ISCSI_TAG_MAGIC | (++itt_idx) );
+}
+
+/**
+ * Open iSCSI transport-layer connection
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
+	struct sockaddr_tcpip target;
+	int rc;
+
+	assert ( iscsi->tx_state == ISCSI_TX_IDLE );
+	assert ( iscsi->rx_state == ISCSI_RX_BHS );
+	assert ( iscsi->rx_offset == 0 );
+
+	/* Open socket */
+	memset ( &target, 0, sizeof ( target ) );
+	target.st_port = htons ( iscsi->target_port );
+	if ( ( rc = xfer_open_named_socket ( &iscsi->socket, SOCK_STREAM,
+					     ( struct sockaddr * ) &target,
+					     iscsi->target_address,
+					     NULL ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not open socket: %s\n",
+		       iscsi, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Enter security negotiation phase */
+	iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
+			  ISCSI_STATUS_STRINGS_SECURITY );
+	if ( iscsi->target_username )
+		iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_REQUIRED;
+
+	/* Assign new ISID */
+	iscsi->isid_iana_qual = ( random() & 0xffff );
+
+	/* Assign fresh initiator task tag */
+	iscsi_new_itt ( iscsi );
+
+	/* Initiate login */
+	iscsi_start_login ( iscsi );
+
+	return 0;
+}
+
+/**
+ * Close iSCSI transport-layer connection
+ *
+ * @v iscsi		iSCSI session
+ * @v rc		Reason for close
+ *
+ * Closes the transport-layer connection and resets the session state
+ * ready to attempt a fresh login.
+ */
+static void iscsi_close_connection ( struct iscsi_session *iscsi, int rc ) {
+
+	/* Close all data transfer interfaces */
+	intf_restart ( &iscsi->socket, rc );
+
+	/* Clear connection status */
+	iscsi->status = 0;
+
+	/* Reset TX and RX state machines */
+	iscsi->tx_state = ISCSI_TX_IDLE;
+	iscsi->rx_state = ISCSI_RX_BHS;
+	iscsi->rx_offset = 0;
+
+	/* Free any temporary dynamically allocated memory */
+	chap_finish ( &iscsi->chap );
+	iscsi_rx_buffered_data_done ( iscsi );
+}
+
+/**
+ * Mark iSCSI SCSI operation as complete
+ *
+ * @v iscsi		iSCSI session
+ * @v rc		Return status code
+ * @v rsp		SCSI response, if any
+ *
+ * Note that iscsi_scsi_done() will not close the connection, and must
+ * therefore be called only when the internal state machines are in an
+ * appropriate state, otherwise bad things may happen on the next call
+ * to iscsi_scsi_command().  The general rule is to call
+ * iscsi_scsi_done() only at the end of receiving a PDU; at this point
+ * the TX and RX engines should both be idle.
+ */
+static void iscsi_scsi_done ( struct iscsi_session *iscsi, int rc,
+			      struct scsi_rsp *rsp ) {
+	uint32_t itt = iscsi->itt;
+
+	assert ( iscsi->tx_state == ISCSI_TX_IDLE );
+
+	/* Clear command */
+	free ( iscsi->command );
+	iscsi->command = NULL;
+
+	/* Send SCSI response, if any */
+	scsi_response ( &iscsi->data, rsp );
+
+	/* Close SCSI command, if this is still the same command.  (It
+	 * is possible that the command interface has already been
+	 * closed as a result of the SCSI response we sent.)
+	 */
+	if ( iscsi->itt == itt )
+		intf_restart ( &iscsi->data, rc );
+}
+
+/****************************************************************************
+ *
+ * iSCSI SCSI command issuing
+ *
+ */
+
+/**
+ * Build iSCSI SCSI command BHS
+ *
+ * @v iscsi		iSCSI session
+ *
+ * We don't currently support bidirectional commands (i.e. with both
+ * Data-In and Data-Out segments); these would require providing code
+ * to generate an AHS, and there doesn't seem to be any need for it at
+ * the moment.
+ */
+static void iscsi_start_command ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
+
+	assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
+
+	/* Construct BHS and initiate transmission */
+	iscsi_start_tx ( iscsi );
+	command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
+	command->flags = ( ISCSI_FLAG_FINAL |
+			   ISCSI_COMMAND_ATTR_SIMPLE );
+	if ( iscsi->command->data_in )
+		command->flags |= ISCSI_COMMAND_FLAG_READ;
+	if ( iscsi->command->data_out )
+		command->flags |= ISCSI_COMMAND_FLAG_WRITE;
+	/* lengths left as zero */
+	memcpy ( &command->lun, &iscsi->command->lun,
+		 sizeof ( command->lun ) );
+	command->itt = htonl ( iscsi->itt );
+	command->exp_len = htonl ( iscsi->command->data_in_len |
+				   iscsi->command->data_out_len );
+	command->cmdsn = htonl ( iscsi->cmdsn );
+	command->expstatsn = htonl ( iscsi->statsn + 1 );
+	memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
+	DBGC2 ( iscsi, "iSCSI %p start " SCSI_CDB_FORMAT " %s %#zx\n",
+		iscsi, SCSI_CDB_DATA ( command->cdb ),
+		( iscsi->command->data_in ? "in" : "out" ),
+		( iscsi->command->data_in ?
+		  iscsi->command->data_in_len :
+		  iscsi->command->data_out_len ) );
+}
+
+/**
+ * Receive data segment of an iSCSI SCSI response PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ */
+static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi,
+				    const void *data, size_t len,
+				    size_t remaining ) {
+	struct iscsi_bhs_scsi_response *response
+		= &iscsi->rx_bhs.scsi_response;
+	struct scsi_rsp rsp;
+	uint32_t residual_count;
+	int rc;
+
+	/* Buffer up the PDU data */
+	if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
+		       iscsi, strerror ( rc ) );
+		return rc;
+	}
+	if ( remaining )
+		return 0;
+
+	/* Parse SCSI response and discard buffer */
+	memset ( &rsp, 0, sizeof ( rsp ) );
+	rsp.status = response->status;
+	residual_count = ntohl ( response->residual_count );
+	if ( response->flags & ISCSI_DATA_FLAG_OVERFLOW ) {
+		rsp.overrun = residual_count;
+	} else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) {
+		rsp.overrun = -(residual_count);
+	}
+	if ( ISCSI_DATA_LEN ( response->lengths ) )
+		memcpy ( &rsp.sense, ( iscsi->rx_buffer + 2 ),
+			 sizeof ( rsp.sense ) );
+	iscsi_rx_buffered_data_done ( iscsi );
+
+	/* Check for errors */
+	if ( response->response != ISCSI_RESPONSE_COMMAND_COMPLETE )
+		return -EIO;
+
+	/* Mark as completed */
+	iscsi_scsi_done ( iscsi, 0, &rsp );
+	return 0;
+}
+
+/**
+ * Receive data segment of an iSCSI data-in PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ */
+static int iscsi_rx_data_in ( struct iscsi_session *iscsi,
+			      const void *data, size_t len,
+			      size_t remaining ) {
+	struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
+	unsigned long offset;
+
+	/* Copy data to data-in buffer */
+	offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
+	assert ( iscsi->command != NULL );
+	assert ( iscsi->command->data_in );
+	assert ( ( offset + len ) <= iscsi->command->data_in_len );
+	copy_to_user ( iscsi->command->data_in, offset, data, len );
+
+	/* Wait for whole SCSI response to arrive */
+	if ( remaining )
+		return 0;
+
+	/* Mark as completed if status is present */
+	if ( data_in->flags & ISCSI_DATA_FLAG_STATUS ) {
+		assert ( ( offset + len ) == iscsi->command->data_in_len );
+		assert ( data_in->flags & ISCSI_FLAG_FINAL );
+		/* iSCSI cannot return an error status via a data-in */
+		iscsi_scsi_done ( iscsi, 0, NULL );
+	}
+
+	return 0;
+}
+
+/**
+ * Receive data segment of an iSCSI R2T PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ */
+static int iscsi_rx_r2t ( struct iscsi_session *iscsi,
+			  const void *data __unused, size_t len __unused,
+			  size_t remaining __unused ) {
+	struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
+
+	/* Record transfer parameters and trigger first data-out */
+	iscsi->ttt = ntohl ( r2t->ttt );
+	iscsi->transfer_offset = ntohl ( r2t->offset );
+	iscsi->transfer_len = ntohl ( r2t->len );
+	iscsi_start_data_out ( iscsi, 0 );
+
+	return 0;
+}
+
+/**
+ * Build iSCSI data-out BHS
+ *
+ * @v iscsi		iSCSI session
+ * @v datasn		Data sequence number within the transfer
+ *
+ */
+static void iscsi_start_data_out ( struct iscsi_session *iscsi,
+				   unsigned int datasn ) {
+	struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
+	unsigned long offset;
+	unsigned long remaining;
+	unsigned long len;
+
+	/* We always send 512-byte Data-Out PDUs; this removes the
+	 * need to worry about the target's MaxRecvDataSegmentLength.
+	 */
+	offset = datasn * 512;
+	remaining = iscsi->transfer_len - offset;
+	len = remaining;
+	if ( len > 512 )
+		len = 512;
+
+	/* Construct BHS and initiate transmission */
+	iscsi_start_tx ( iscsi );
+	data_out->opcode = ISCSI_OPCODE_DATA_OUT;
+	if ( len == remaining )
+		data_out->flags = ( ISCSI_FLAG_FINAL );
+	ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
+	data_out->lun = iscsi->command->lun;
+	data_out->itt = htonl ( iscsi->itt );
+	data_out->ttt = htonl ( iscsi->ttt );
+	data_out->expstatsn = htonl ( iscsi->statsn + 1 );
+	data_out->datasn = htonl ( datasn );
+	data_out->offset = htonl ( iscsi->transfer_offset + offset );
+	DBGC ( iscsi, "iSCSI %p start data out DataSN %#x len %#lx\n",
+	       iscsi, datasn, len );
+}
+
+/**
+ * Complete iSCSI data-out PDU transmission
+ *
+ * @v iscsi		iSCSI session
+ *
+ */
+static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
+
+	/* If we haven't reached the end of the sequence, start
+	 * sending the next data-out PDU.
+	 */
+	if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
+		iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
+}
+
+/**
+ * Send iSCSI data-out data segment
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
+	struct io_buffer *iobuf;
+	unsigned long offset;
+	size_t len;
+
+	offset = ntohl ( data_out->offset );
+	len = ISCSI_DATA_LEN ( data_out->lengths );
+
+	assert ( iscsi->command != NULL );
+	assert ( iscsi->command->data_out );
+	assert ( ( offset + len ) <= iscsi->command->data_out_len );
+
+	iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+	if ( ! iobuf )
+		return -ENOMEM;
+	
+	copy_from_user ( iob_put ( iobuf, len ),
+			 iscsi->command->data_out, offset, len );
+
+	return xfer_deliver_iob ( &iscsi->socket, iobuf );
+}
+
+/**
+ * Receive data segment of an iSCSI NOP-In
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ */
+static int iscsi_rx_nop_in ( struct iscsi_session *iscsi,
+			     const void *data __unused, size_t len __unused,
+			     size_t remaining __unused ) {
+	struct iscsi_nop_in *nop_in = &iscsi->rx_bhs.nop_in;
+
+	DBGC2 ( iscsi, "iSCSI %p received NOP-In\n", iscsi );
+
+	/* We don't currently have the ability to respond to NOP-Ins
+	 * sent as ping requests, but we can happily accept NOP-Ins
+	 * sent merely to update CmdSN.
+	 */
+	if ( nop_in->ttt != htonl ( ISCSI_TAG_RESERVED ) ) {
+		DBGC ( iscsi, "iSCSI %p received unsupported NOP-In with TTT "
+		       "%08x\n", iscsi, ntohl ( nop_in->ttt ) );
+		return -ENOTSUP_NOP_IN;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * iSCSI login
+ *
+ */
+
+/**
+ * Build iSCSI login request strings
+ *
+ * @v iscsi		iSCSI session
+ *
+ * These are the initial set of strings sent in the first login
+ * request PDU.  We want the following settings:
+ *
+ *     HeaderDigest=None
+ *     DataDigest=None
+ *     MaxConnections is irrelevant; we make only one connection anyway [4]
+ *     InitialR2T=Yes [1]
+ *     ImmediateData is irrelevant; we never send immediate data [4]
+ *     MaxRecvDataSegmentLength=8192 (default; we don't care) [3]
+ *     MaxBurstLength=262144 (default; we don't care) [3]
+ *     FirstBurstLength=262144 (default; we don't care)
+ *     DefaultTime2Wait=0 [2]
+ *     DefaultTime2Retain=0 [2]
+ *     MaxOutstandingR2T=1
+ *     DataPDUInOrder=Yes
+ *     DataSequenceInOrder=Yes
+ *     ErrorRecoveryLevel=0
+ *
+ * [1] InitialR2T has an OR resolution function, so the target may
+ * force us to use it.  We therefore simplify our logic by always
+ * using it.
+ *
+ * [2] These ensure that we can safely start a new task once we have
+ * reconnected after a failure, without having to manually tidy up
+ * after the old one.
+ *
+ * [3] We are quite happy to use the RFC-defined default values for
+ * these parameters, but some targets (notably OpenSolaris)
+ * incorrectly assume a default value of zero, so we explicitly
+ * specify the default values.
+ *
+ * [4] We are quite happy to use the RFC-defined default values for
+ * these parameters, but some targets (notably a QNAP TS-639Pro) fail
+ * unless they are supplied, so we explicitly specify the default
+ * values.
+ */
+static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
+					       void *data, size_t len ) {
+	unsigned int used = 0;
+	const char *auth_method;
+
+	if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
+		/* Default to allowing no authentication */
+		auth_method = "None";
+		/* If we have a credential to supply, permit CHAP */
+		if ( iscsi->initiator_username )
+			auth_method = "CHAP,None";
+		/* If we have a credential to check, force CHAP */
+		if ( iscsi->target_username )
+			auth_method = "CHAP";
+		used += ssnprintf ( data + used, len - used,
+				    "InitiatorName=%s%c"
+				    "TargetName=%s%c"
+				    "SessionType=Normal%c"
+				    "AuthMethod=%s%c",
+				    iscsi->initiator_iqn, 0,
+				    iscsi->target_iqn, 0, 0,
+				    auth_method, 0 );
+	}
+
+	if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) {
+		used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 );
+	}
+	
+	if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) ) {
+		char buf[ base16_encoded_len ( iscsi->chap.response_len ) + 1 ];
+		assert ( iscsi->initiator_username != NULL );
+		base16_encode ( iscsi->chap.response, iscsi->chap.response_len,
+				buf );
+		used += ssnprintf ( data + used, len - used,
+				    "CHAP_N=%s%cCHAP_R=0x%s%c",
+				    iscsi->initiator_username, 0, buf, 0 );
+	}
+
+	if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_CHALLENGE ) ) {
+		size_t challenge_len = ( sizeof ( iscsi->chap_challenge ) - 1 );
+		char buf[ base16_encoded_len ( challenge_len ) + 1 ];
+		base16_encode ( ( iscsi->chap_challenge + 1 ), challenge_len,
+				buf );
+		used += ssnprintf ( data + used, len - used,
+				    "CHAP_I=%d%cCHAP_C=0x%s%c",
+				    iscsi->chap_challenge[0], 0, buf, 0 );
+	}
+
+	if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
+		used += ssnprintf ( data + used, len - used,
+				    "HeaderDigest=None%c"
+				    "DataDigest=None%c"
+				    "MaxConnections=1%c"
+				    "InitialR2T=Yes%c"
+				    "ImmediateData=No%c"
+				    "MaxRecvDataSegmentLength=8192%c"
+				    "MaxBurstLength=262144%c"
+				    "DefaultTime2Wait=0%c"
+				    "DefaultTime2Retain=0%c"
+				    "MaxOutstandingR2T=1%c"
+				    "DataPDUInOrder=Yes%c"
+				    "DataSequenceInOrder=Yes%c"
+				    "ErrorRecoveryLevel=0%c",
+				    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+	}
+
+	return used;
+}
+
+/**
+ * Build iSCSI login request BHS
+ *
+ * @v iscsi		iSCSI session
+ */
+static void iscsi_start_login ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
+	int len;
+
+	switch ( iscsi->status & ISCSI_LOGIN_CSG_MASK ) {
+	case ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION:
+		DBGC ( iscsi, "iSCSI %p entering security negotiation\n",
+		       iscsi );
+		break;
+	case ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION:
+		DBGC ( iscsi, "iSCSI %p entering operational negotiation\n",
+		       iscsi );
+		break;
+	default:
+		assert ( 0 );
+	}
+
+	/* Construct BHS and initiate transmission */
+	iscsi_start_tx ( iscsi );
+	request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
+			    ISCSI_FLAG_IMMEDIATE );
+	request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) |
+			   ISCSI_LOGIN_FLAG_TRANSITION );
+	/* version_max and version_min left as zero */
+	len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
+	ISCSI_SET_LENGTHS ( request->lengths, 0, len );
+	request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
+					IANA_EN_FEN_SYSTEMS );
+	request->isid_iana_qual = htons ( iscsi->isid_iana_qual );
+	/* tsih left as zero */
+	request->itt = htonl ( iscsi->itt );
+	/* cid left as zero */
+	request->cmdsn = htonl ( iscsi->cmdsn );
+	request->expstatsn = htonl ( iscsi->statsn + 1 );
+}
+
+/**
+ * Complete iSCSI login request PDU transmission
+ *
+ * @v iscsi		iSCSI session
+ *
+ */
+static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
+
+	/* Clear any "strings to send" flags */
+	iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
+
+	/* Free any dynamically allocated storage used for login */
+	chap_finish ( &iscsi->chap );
+}
+
+/**
+ * Transmit data segment of an iSCSI login request PDU
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ *
+ * For login requests, the data segment consists of the login strings.
+ */
+static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
+	struct io_buffer *iobuf;
+	size_t len;
+
+	len = ISCSI_DATA_LEN ( request->lengths );
+	iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+	if ( ! iobuf )
+		return -ENOMEM;
+	iob_put ( iobuf, len );
+	iscsi_build_login_request_strings ( iscsi, iobuf->data, len );
+	return xfer_deliver_iob ( &iscsi->socket, iobuf );
+}
+
+/**
+ * Calculate maximum length of decoded large binary value
+ *
+ * @v encoded		Encoded large binary value
+ * @v max_raw_len	Maximum length of raw data
+ */
+static inline size_t
+iscsi_large_binary_decoded_max_len ( const char *encoded ) {
+	return ( strlen ( encoded ) ); /* Decoding never expands data */
+}
+
+/**
+ * Decode large binary value
+ *
+ * @v encoded		Encoded large binary value
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ */
+static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
+
+	if ( encoded[0] != '0' )
+		return -EPROTO_INVALID_LARGE_BINARY;
+
+	switch ( encoded[1] ) {
+	case 'x' :
+	case 'X' :
+		return base16_decode ( ( encoded + 2 ), raw );
+	case 'b' :
+	case 'B' :
+		return base64_decode ( ( encoded + 2 ), raw );
+	default:
+		return -EPROTO_INVALID_LARGE_BINARY;
+	}
+}
+
+/**
+ * Handle iSCSI TargetAddress text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		TargetAddress value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
+					      const char *value ) {
+	char *separator;
+
+	DBGC ( iscsi, "iSCSI %p will redirect to %s\n", iscsi, value );
+
+	/* Replace target address */
+	free ( iscsi->target_address );
+	iscsi->target_address = strdup ( value );
+	if ( ! iscsi->target_address )
+		return -ENOMEM;
+
+	/* Replace target port */
+	iscsi->target_port = htons ( ISCSI_PORT );
+	separator = strchr ( iscsi->target_address, ':' );
+	if ( separator ) {
+		*separator = '\0';
+		iscsi->target_port = strtoul ( ( separator + 1 ), NULL, 0 );
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI AuthMethod text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		AuthMethod value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
+					   const char *value ) {
+
+	/* If server requests CHAP, send the CHAP_A string */
+	if ( strcmp ( value, "CHAP" ) == 0 ) {
+		DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n",
+		       iscsi );
+		iscsi->status |= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM |
+				   ISCSI_STATUS_AUTH_FORWARD_REQUIRED );
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI CHAP_A text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		CHAP_A value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
+				       const char *value ) {
+
+	/* We only ever offer "5" (i.e. MD5) as an algorithm, so if
+	 * the server responds with anything else it is a protocol
+	 * violation.
+	 */
+	if ( strcmp ( value, "5" ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
+		       iscsi, value );
+		return -EPROTO_INVALID_CHAP_ALGORITHM;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI CHAP_I text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		CHAP_I value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
+				       const char *value ) {
+	unsigned int identifier;
+	char *endp;
+	int rc;
+
+	/* The CHAP identifier is an integer value */
+	identifier = strtoul ( value, &endp, 0 );
+	if ( *endp != '\0' ) {
+		DBGC ( iscsi, "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
+		       iscsi, value );
+		return -EPROTO_INVALID_CHAP_IDENTIFIER;
+	}
+
+	/* Prepare for CHAP with MD5 */
+	chap_finish ( &iscsi->chap );
+	if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
+		       iscsi, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Identifier and secret are the first two components of the
+	 * challenge.
+	 */
+	chap_set_identifier ( &iscsi->chap, identifier );
+	if ( iscsi->initiator_password ) {
+		chap_update ( &iscsi->chap, iscsi->initiator_password,
+			      strlen ( iscsi->initiator_password ) );
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI CHAP_C text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		CHAP_C value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
+				       const char *value ) {
+	uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
+	unsigned int i;
+	size_t len;
+	int rc;
+
+	/* Process challenge */
+	rc = iscsi_large_binary_decode ( value, buf );
+	if ( rc < 0 ) {
+		DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
+		       iscsi, value, strerror ( rc ) );
+		return rc;
+	}
+	len = rc;
+	chap_update ( &iscsi->chap, buf, len );
+
+	/* Build CHAP response */
+	DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
+	chap_respond ( &iscsi->chap );
+	iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
+
+	/* Send CHAP challenge, if applicable */
+	if ( iscsi->target_username ) {
+		iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_CHALLENGE;
+		/* Generate CHAP challenge data */
+		for ( i = 0 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) {
+			iscsi->chap_challenge[i] = random();
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI CHAP_N text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		CHAP_N value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi,
+				       const char *value ) {
+
+	/* The target username isn't actually involved at any point in
+	 * the authentication process; it merely serves to identify
+	 * which password the target is using to generate the CHAP
+	 * response.  We unnecessarily verify that the username is as
+	 * expected, in order to provide mildly helpful diagnostics if
+	 * the target is supplying the wrong username/password
+	 * combination.
+	 */
+	if ( iscsi->target_username &&
+	     ( strcmp ( iscsi->target_username, value ) != 0 ) ) {
+		DBGC ( iscsi, "iSCSI %p target username \"%s\" incorrect "
+		       "(wanted \"%s\")\n",
+		       iscsi, value, iscsi->target_username );
+		return -EACCES_INCORRECT_TARGET_USERNAME;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle iSCSI CHAP_R text value
+ *
+ * @v iscsi		iSCSI session
+ * @v value		CHAP_R value
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
+				       const char *value ) {
+	uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
+	size_t len;
+	int rc;
+
+	/* Generate CHAP response for verification */
+	chap_finish ( &iscsi->chap );
+	if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
+		       iscsi, strerror ( rc ) );
+		return rc;
+	}
+	chap_set_identifier ( &iscsi->chap, iscsi->chap_challenge[0] );
+	if ( iscsi->target_password ) {
+		chap_update ( &iscsi->chap, iscsi->target_password,
+			      strlen ( iscsi->target_password ) );
+	}
+	chap_update ( &iscsi->chap, &iscsi->chap_challenge[1],
+		      ( sizeof ( iscsi->chap_challenge ) - 1 ) );
+	chap_respond ( &iscsi->chap );
+
+	/* Process response */
+	rc = iscsi_large_binary_decode ( value, buf );
+	if ( rc < 0 ) {
+		DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
+		       iscsi, value, strerror ( rc ) );
+		return rc;
+	}
+	len = rc;
+
+	/* Check CHAP response */
+	if ( len != iscsi->chap.response_len ) {
+		DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n",
+		       iscsi );
+		return -EPROTO_INVALID_CHAP_RESPONSE;
+	}
+	if ( memcmp ( buf, iscsi->chap.response, len ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p incorrect CHAP response \"%s\"\n",
+		       iscsi, value );
+		return -EACCES_INCORRECT_TARGET_PASSWORD;
+	}
+
+	/* Mark session as authenticated */
+	iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;
+
+	return 0;
+}
+
+/** An iSCSI text string that we want to handle */
+struct iscsi_string_type {
+	/** String key
+	 *
+	 * This is the portion up to and including the "=" sign,
+	 * e.g. "InitiatorName=", "CHAP_A=", etc.
+	 */
+	const char *key;
+	/** Handle iSCSI string value
+	 *
+	 * @v iscsi		iSCSI session
+	 * @v value		iSCSI string value
+	 * @ret rc		Return status code
+	 */
+	int ( * handle ) ( struct iscsi_session *iscsi, const char *value );
+};
+
+/** iSCSI text strings that we want to handle */
+static struct iscsi_string_type iscsi_string_types[] = {
+	{ "TargetAddress=", iscsi_handle_targetaddress_value },
+	{ "AuthMethod=", iscsi_handle_authmethod_value },
+	{ "CHAP_A=", iscsi_handle_chap_a_value },
+	{ "CHAP_I=", iscsi_handle_chap_i_value },
+	{ "CHAP_C=", iscsi_handle_chap_c_value },
+	{ "CHAP_N=", iscsi_handle_chap_n_value },
+	{ "CHAP_R=", iscsi_handle_chap_r_value },
+	{ NULL, NULL }
+};
+
+/**
+ * Handle iSCSI string
+ *
+ * @v iscsi		iSCSI session
+ * @v string		iSCSI string (in "key=value" format)
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_string ( struct iscsi_session *iscsi,
+				 const char *string ) {
+	struct iscsi_string_type *type;
+	size_t key_len;
+	int rc;
+
+	for ( type = iscsi_string_types ; type->key ; type++ ) {
+		key_len = strlen ( type->key );
+		if ( strncmp ( string, type->key, key_len ) != 0 )
+			continue;
+		DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string );
+		if ( ( rc = type->handle ( iscsi,
+					   ( string + key_len ) ) ) != 0 ) {
+			DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n",
+			       iscsi, string, strerror ( rc ) );
+			return rc;
+		}
+		return 0;
+	}
+	DBGC ( iscsi, "iSCSI %p ignoring %s\n", iscsi, string );
+	return 0;
+}
+
+/**
+ * Handle iSCSI strings
+ *
+ * @v iscsi		iSCSI session
+ * @v string		iSCSI string buffer
+ * @v len		Length of string buffer
+ * @ret rc		Return status code
+ */
+static int iscsi_handle_strings ( struct iscsi_session *iscsi,
+				  const char *strings, size_t len ) {
+	size_t string_len;
+	int rc;
+
+	/* Handle each string in turn, taking care not to overrun the
+	 * data buffer in case of badly-terminated data.
+	 */
+	while ( 1 ) {
+		string_len = ( strnlen ( strings, len ) + 1 );
+		if ( string_len > len )
+			break;
+		if ( ( rc = iscsi_handle_string ( iscsi, strings ) ) != 0 )
+			return rc;
+		strings += string_len;
+		len -= string_len;
+	}
+	return 0;
+}
+
+/**
+ * Convert iSCSI response status to return status code
+ *
+ * @v status_class	iSCSI status class
+ * @v status_detail	iSCSI status detail
+ * @ret rc		Return status code
+ */
+static int iscsi_status_to_rc ( unsigned int status_class,
+				unsigned int status_detail ) {
+	switch ( status_class ) {
+	case ISCSI_STATUS_INITIATOR_ERROR :
+		switch ( status_detail ) {
+		case ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION :
+			return -EPERM_INITIATOR_AUTHENTICATION;
+		case ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION :
+			return -EPERM_INITIATOR_AUTHORISATION;
+		case ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND :
+		case ISCSI_STATUS_INITIATOR_ERROR_REMOVED :
+			return -ENODEV;
+		default :
+			return -ENOTSUP_INITIATOR_STATUS;
+		}
+	case ISCSI_STATUS_TARGET_ERROR :
+		switch ( status_detail ) {
+		case ISCSI_STATUS_TARGET_ERROR_UNAVAILABLE:
+			return -EIO_TARGET_UNAVAILABLE;
+		case ISCSI_STATUS_TARGET_ERROR_NO_RESOURCES:
+			return -EIO_TARGET_NO_RESOURCES;
+		default:
+			return -ENOTSUP_TARGET_STATUS;
+		}
+	default :
+		return -EINVAL;
+	}
+}
+
+/**
+ * Receive data segment of an iSCSI login response PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ */
+static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
+				     const void *data, size_t len,
+				     size_t remaining ) {
+	struct iscsi_bhs_login_response *response
+		= &iscsi->rx_bhs.login_response;
+	int rc;
+
+	/* Buffer up the PDU data */
+	if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
+		       iscsi, strerror ( rc ) );
+		return rc;
+	}
+	if ( remaining )
+		return 0;
+
+	/* Process string data and discard string buffer */
+	if ( ( rc = iscsi_handle_strings ( iscsi, iscsi->rx_buffer,
+					   iscsi->rx_len ) ) != 0 )
+		return rc;
+	iscsi_rx_buffered_data_done ( iscsi );
+
+	/* Check for login redirection */
+	if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
+		DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi );
+		iscsi_close_connection ( iscsi, 0 );
+		if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) {
+			DBGC ( iscsi, "iSCSI %p could not redirect: %s\n ",
+			       iscsi, strerror ( rc ) );
+			return rc;
+		}
+		return 0;
+	}
+
+	/* Check for fatal errors */
+	if ( response->status_class != 0 ) {
+		DBGC ( iscsi, "iSCSI login failure: class %02x detail %02x\n",
+		       response->status_class, response->status_detail );
+		rc = iscsi_status_to_rc ( response->status_class,
+					  response->status_detail );
+		return rc;
+	}
+
+	/* Handle login transitions */
+	if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
+		iscsi->status &= ~( ISCSI_STATUS_PHASE_MASK |
+				    ISCSI_STATUS_STRINGS_MASK );
+		switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
+		case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
+			iscsi->status |=
+				( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
+				  ISCSI_STATUS_STRINGS_OPERATIONAL );
+			break;
+		case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
+			iscsi->status |= ISCSI_STATUS_FULL_FEATURE_PHASE;
+			break;
+		default:
+			DBGC ( iscsi, "iSCSI %p got invalid response flags "
+			       "%02x\n", iscsi, response->flags );
+			return -EIO;
+		}
+	}
+
+	/* Send next login request PDU if we haven't reached the full
+	 * feature phase yet.
+	 */
+	if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
+	     ISCSI_STATUS_FULL_FEATURE_PHASE ) {
+		iscsi_start_login ( iscsi );
+		return 0;
+	}
+
+	/* Check that target authentication was successful (if required) */
+	if ( ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) &&
+	     ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_OK ) ) {
+		DBGC ( iscsi, "iSCSI %p nefarious target tried to bypass "
+		       "authentication\n", iscsi );
+		return -EPROTO;
+	}
+
+	/* Notify SCSI layer of window change */
+	DBGC ( iscsi, "iSCSI %p entering full feature phase\n", iscsi );
+	xfer_window_changed ( &iscsi->control );
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * iSCSI to socket interface
+ *
+ */
+
+/**
+ * Start up a new TX PDU
+ *
+ * @v iscsi		iSCSI session
+ *
+ * This initiates the process of sending a new PDU.  Only one PDU may
+ * be in transit at any one time.
+ */
+static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
+
+	assert ( iscsi->tx_state == ISCSI_TX_IDLE );
+	assert ( ! process_running ( &iscsi->process ) );
+	
+	/* Initialise TX BHS */
+	memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
+
+	/* Flag TX engine to start transmitting */
+	iscsi->tx_state = ISCSI_TX_BHS;
+
+	/* Start transmission process */
+	process_add ( &iscsi->process );
+}
+
+/**
+ * Transmit nothing
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_tx_nothing ( struct iscsi_session *iscsi __unused ) {
+	return 0;
+}
+
+/**
+ * Transmit basic header segment of an iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_tx_bhs ( struct iscsi_session *iscsi ) {
+	return xfer_deliver_raw ( &iscsi->socket,  &iscsi->tx_bhs,
+				  sizeof ( iscsi->tx_bhs ) );
+}
+
+/**
+ * Transmit data segment of an iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ * 
+ * Handle transmission of part of a PDU data segment.  iscsi::tx_bhs
+ * will be valid when this is called.
+ */
+static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
+
+	switch ( common->opcode & ISCSI_OPCODE_MASK ) {
+	case ISCSI_OPCODE_DATA_OUT:
+		return iscsi_tx_data_out ( iscsi );
+	case ISCSI_OPCODE_LOGIN_REQUEST:
+		return iscsi_tx_login_request ( iscsi );
+	default:
+		/* Nothing to send in other states */
+		return 0;
+	}
+}
+
+/**
+ * Transmit data padding of an iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ * 
+ * Handle transmission of any data padding in a PDU data segment.
+ * iscsi::tx_bhs will be valid when this is called.
+ */
+static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) {
+	static const char pad[] = { '\0', '\0', '\0' };
+	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
+	size_t pad_len;
+	
+	pad_len = ISCSI_DATA_PAD_LEN ( common->lengths );
+	if ( ! pad_len )
+		return 0;
+
+	return xfer_deliver_raw ( &iscsi->socket, pad, pad_len );
+}
+
+/**
+ * Complete iSCSI PDU transmission
+ *
+ * @v iscsi		iSCSI session
+ *
+ * Called when a PDU has been completely transmitted and the TX state
+ * machine is about to enter the idle state.  iscsi::tx_bhs will be
+ * valid for the just-completed PDU when this is called.
+ */
+static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
+	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
+
+	/* Stop transmission process */
+	process_del ( &iscsi->process );
+
+	switch ( common->opcode & ISCSI_OPCODE_MASK ) {
+	case ISCSI_OPCODE_DATA_OUT:
+		iscsi_data_out_done ( iscsi );
+	case ISCSI_OPCODE_LOGIN_REQUEST:
+		iscsi_login_request_done ( iscsi );
+	default:
+		/* No action */
+		break;
+	}
+}
+
+/**
+ * Transmit iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v buf		Temporary data buffer
+ * @v len		Length of temporary data buffer
+ * 
+ * Constructs data to be sent for the current TX state
+ */
+static void iscsi_tx_step ( struct process *process ) {
+	struct iscsi_session *iscsi =
+		container_of ( process, struct iscsi_session, process );
+	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
+	int ( * tx ) ( struct iscsi_session *iscsi );
+	enum iscsi_tx_state next_state;
+	size_t tx_len;
+	int rc;
+
+	/* Select fragment to transmit */
+	while ( 1 ) {
+		switch ( iscsi->tx_state ) {
+		case ISCSI_TX_BHS:
+			tx = iscsi_tx_bhs;
+			tx_len = sizeof ( iscsi->tx_bhs );
+			next_state = ISCSI_TX_AHS;
+			break;
+		case ISCSI_TX_AHS:
+			tx = iscsi_tx_nothing;
+			tx_len = 0;
+			next_state = ISCSI_TX_DATA;
+			break;
+		case ISCSI_TX_DATA:
+			tx = iscsi_tx_data;
+			tx_len = ISCSI_DATA_LEN ( common->lengths );
+			next_state = ISCSI_TX_DATA_PADDING;
+			break;
+		case ISCSI_TX_DATA_PADDING:
+			tx = iscsi_tx_data_padding;
+			tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
+			next_state = ISCSI_TX_IDLE;
+			break;
+		case ISCSI_TX_IDLE:
+			/* Stop processing */
+			iscsi_tx_done ( iscsi );
+			return;
+		default:
+			assert ( 0 );
+			return;
+		}
+
+		/* Check for window availability, if needed */
+		if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
+			/* Cannot transmit at this point; stop processing */
+			return;
+		}
+
+		/* Transmit data */
+		if ( ( rc = tx ( iscsi ) ) != 0 ) {
+			DBGC ( iscsi, "iSCSI %p could not transmit: %s\n",
+			       iscsi, strerror ( rc ) );
+			/* Transmission errors are fatal */
+			iscsi_close ( iscsi, rc );
+			return;
+		}
+
+		/* Move to next state */
+		iscsi->tx_state = next_state;
+	}
+}
+
+/**
+ * Receive basic header segment of an iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ *
+ * This fills in iscsi::rx_bhs with the data from the BHS portion of
+ * the received PDU.
+ */
+static int iscsi_rx_bhs ( struct iscsi_session *iscsi, const void *data,
+			  size_t len, size_t remaining __unused ) {
+	memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
+	if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
+		DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n",
+			iscsi, iscsi->rx_bhs.common.opcode,
+			ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
+	}
+	return 0;
+}
+
+/**
+ * Discard portion of an iSCSI PDU.
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ *
+ * This discards data from a portion of a received PDU.
+ */
+static int iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
+			      const void *data __unused, size_t len __unused,
+			      size_t remaining __unused ) {
+	/* Do nothing */
+	return 0;
+}
+
+/**
+ * Receive data segment of an iSCSI PDU
+ *
+ * @v iscsi		iSCSI session
+ * @v data		Received data
+ * @v len		Length of received data
+ * @v remaining		Data remaining after this data
+ * @ret rc		Return status code
+ *
+ * Handle processing of part of a PDU data segment.  iscsi::rx_bhs
+ * will be valid when this is called.
+ */
+static int iscsi_rx_data ( struct iscsi_session *iscsi, const void *data,
+			   size_t len, size_t remaining ) {
+	struct iscsi_bhs_common_response *response
+		= &iscsi->rx_bhs.common_response;
+
+	/* Update cmdsn and statsn */
+	iscsi->cmdsn = ntohl ( response->expcmdsn );
+	iscsi->statsn = ntohl ( response->statsn );
+
+	switch ( response->opcode & ISCSI_OPCODE_MASK ) {
+	case ISCSI_OPCODE_LOGIN_RESPONSE:
+		return iscsi_rx_login_response ( iscsi, data, len, remaining );
+	case ISCSI_OPCODE_SCSI_RESPONSE:
+		return iscsi_rx_scsi_response ( iscsi, data, len, remaining );
+	case ISCSI_OPCODE_DATA_IN:
+		return iscsi_rx_data_in ( iscsi, data, len, remaining );
+	case ISCSI_OPCODE_R2T:
+		return iscsi_rx_r2t ( iscsi, data, len, remaining );
+	case ISCSI_OPCODE_NOP_IN:
+		return iscsi_rx_nop_in ( iscsi, data, len, remaining );
+	default:
+		if ( remaining )
+			return 0;
+		DBGC ( iscsi, "iSCSI %p unknown opcode %02x\n", iscsi,
+		       response->opcode );
+		return -ENOTSUP_OPCODE;
+	}
+}
+
+/**
+ * Receive new data
+ *
+ * @v iscsi		iSCSI session
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ *
+ * This handles received PDUs.  The receive strategy is to fill in
+ * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
+ * throw away any AHS portion, and then process each part of the data
+ * portion as it arrives.  The data processing routine therefore
+ * always has a full copy of the BHS available, even for portions of
+ * the data in different packets to the BHS.
+ */
+static int iscsi_socket_deliver ( struct iscsi_session *iscsi,
+				  struct io_buffer *iobuf,
+				  struct xfer_metadata *meta __unused ) {
+	struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
+	int ( * rx ) ( struct iscsi_session *iscsi, const void *data,
+		       size_t len, size_t remaining );
+	enum iscsi_rx_state next_state;
+	size_t frag_len;
+	size_t remaining;
+	int rc;
+
+	while ( 1 ) {
+		switch ( iscsi->rx_state ) {
+		case ISCSI_RX_BHS:
+			rx = iscsi_rx_bhs;
+			iscsi->rx_len = sizeof ( iscsi->rx_bhs );
+			next_state = ISCSI_RX_AHS;			
+			break;
+		case ISCSI_RX_AHS:
+			rx = iscsi_rx_discard;
+			iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
+			next_state = ISCSI_RX_DATA;
+			break;
+		case ISCSI_RX_DATA:
+			rx = iscsi_rx_data;
+			iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
+			next_state = ISCSI_RX_DATA_PADDING;
+			break;
+		case ISCSI_RX_DATA_PADDING:
+			rx = iscsi_rx_discard;
+			iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
+			next_state = ISCSI_RX_BHS;
+			break;
+		default:
+			assert ( 0 );
+			rc = -EINVAL;
+			goto done;
+		}
+
+		frag_len = iscsi->rx_len - iscsi->rx_offset;
+		if ( frag_len > iob_len ( iobuf ) )
+			frag_len = iob_len ( iobuf );
+		remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
+		if ( ( rc = rx ( iscsi, iobuf->data, frag_len,
+				 remaining ) ) != 0 ) {
+			DBGC ( iscsi, "iSCSI %p could not process received "
+			       "data: %s\n", iscsi, strerror ( rc ) );
+			goto done;
+		}
+
+		iscsi->rx_offset += frag_len;
+		iob_pull ( iobuf, frag_len );
+
+		/* If all the data for this state has not yet been
+		 * received, stay in this state for now.
+		 */
+		if ( iscsi->rx_offset != iscsi->rx_len ) {
+			rc = 0;
+			goto done;
+		}
+
+		iscsi->rx_state = next_state;
+		iscsi->rx_offset = 0;
+	}
+
+ done:
+	/* Free I/O buffer */
+	free_iob ( iobuf );
+
+	/* Destroy session on error */
+	if ( rc != 0 )
+		iscsi_close ( iscsi, rc );
+
+	return rc;
+}
+
+/**
+ * Handle redirection event
+ *
+ * @v iscsi		iSCSI session
+ * @v type		Location type
+ * @v args		Remaining arguments depend upon location type
+ * @ret rc		Return status code
+ */
+static int iscsi_vredirect ( struct iscsi_session *iscsi, int type,
+			     va_list args ) {
+	va_list tmp;
+	struct sockaddr *peer;
+
+	/* Intercept redirects to a LOCATION_SOCKET and record the IP
+	 * address for the iBFT.  This is a bit of a hack, but avoids
+	 * inventing an ioctl()-style call to retrieve the socket
+	 * address from a data-xfer interface.
+	 */
+	if ( type == LOCATION_SOCKET ) {
+		va_copy ( tmp, args );
+		( void ) va_arg ( tmp, int ); /* Discard "semantics" */
+		peer = va_arg ( tmp, struct sockaddr * );
+		memcpy ( &iscsi->target_sockaddr, peer,
+			 sizeof ( iscsi->target_sockaddr ) );
+		va_end ( tmp );
+	}
+
+	return xfer_vreopen ( &iscsi->socket, type, args );
+}
+
+/** iSCSI socket interface operations */
+static struct interface_operation iscsi_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct iscsi_session *, iscsi_socket_deliver ),
+	INTF_OP ( xfer_vredirect, struct iscsi_session *, iscsi_vredirect ),
+	INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
+};
+
+/** iSCSI socket interface descriptor */
+static struct interface_descriptor iscsi_socket_desc =
+	INTF_DESC ( struct iscsi_session, socket, iscsi_socket_operations );
+
+/****************************************************************************
+ *
+ * iSCSI command issuing
+ *
+ */
+
+/**
+ * Check iSCSI flow-control window
+ *
+ * @v iscsi		iSCSI session
+ * @ret len		Length of window
+ */
+static size_t iscsi_scsi_window ( struct iscsi_session *iscsi ) {
+
+	if ( ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) ==
+	       ISCSI_STATUS_FULL_FEATURE_PHASE ) &&
+	     ( iscsi->command == NULL ) ) {
+		/* We cannot handle concurrent commands */
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * Issue iSCSI SCSI command
+ *
+ * @v iscsi		iSCSI session
+ * @v parent		Parent interface
+ * @v command		SCSI command
+ * @ret tag		Command tag, or negative error
+ */
+static int iscsi_scsi_command ( struct iscsi_session *iscsi,
+				struct interface *parent,
+				struct scsi_cmd *command ) {
+
+	/* This iSCSI implementation cannot handle multiple concurrent
+	 * commands or commands arriving before login is complete.
+	 */
+	if ( iscsi_scsi_window ( iscsi ) == 0 ) {
+		DBGC ( iscsi, "iSCSI %p cannot handle concurrent commands\n",
+		       iscsi );
+		return -EOPNOTSUPP;
+	}
+
+	/* Store command */
+	iscsi->command = malloc ( sizeof ( *command ) );
+	if ( ! iscsi->command )
+		return -ENOMEM;
+	memcpy ( iscsi->command, command, sizeof ( *command ) );
+
+	/* Assign new ITT */
+	iscsi_new_itt ( iscsi );
+
+	/* Start sending command */
+	iscsi_start_command ( iscsi );
+
+	/* Attach to parent interface and return */
+	intf_plug_plug ( &iscsi->data, parent );
+	return iscsi->itt;
+}
+
+/** iSCSI SCSI command-issuing interface operations */
+static struct interface_operation iscsi_control_op[] = {
+	INTF_OP ( scsi_command, struct iscsi_session *, iscsi_scsi_command ),
+	INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ),
+	INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
+	INTF_OP ( acpi_describe, struct iscsi_session *, ibft_describe ),
+};
+
+/** iSCSI SCSI command-issuing interface descriptor */
+static struct interface_descriptor iscsi_control_desc =
+	INTF_DESC ( struct iscsi_session, control, iscsi_control_op );
+
+/**
+ * Close iSCSI command
+ *
+ * @v iscsi		iSCSI session
+ * @v rc		Reason for close
+ */
+static void iscsi_command_close ( struct iscsi_session *iscsi, int rc ) {
+
+	/* Restart interface */
+	intf_restart ( &iscsi->data, rc );
+
+	/* Treat unsolicited command closures mid-command as fatal,
+	 * because we have no code to handle partially-completed PDUs.
+	 */
+	if ( iscsi->command != NULL )
+		iscsi_close ( iscsi, ( ( rc == 0 ) ? -ECANCELED : rc ) );
+}
+
+/** iSCSI SCSI command interface operations */
+static struct interface_operation iscsi_data_op[] = {
+	INTF_OP ( intf_close, struct iscsi_session *, iscsi_command_close ),
+};
+
+/** iSCSI SCSI command interface descriptor */
+static struct interface_descriptor iscsi_data_desc =
+	INTF_DESC ( struct iscsi_session, data, iscsi_data_op );
+
+/****************************************************************************
+ *
+ * Instantiator
+ *
+ */
+
+/** iSCSI root path components (as per RFC4173) */
+enum iscsi_root_path_component {
+	RP_SERVERNAME = 0,
+	RP_PROTOCOL,
+	RP_PORT,
+	RP_LUN,
+	RP_TARGETNAME,
+	NUM_RP_COMPONENTS
+};
+
+/** iSCSI initiator IQN setting */
+struct setting initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA ) = {
+	.name = "initiator-iqn",
+	.description = "iSCSI initiator name",
+	.tag = DHCP_ISCSI_INITIATOR_IQN,
+	.type = &setting_type_string,
+};
+
+/** iSCSI reverse username setting */
+struct setting reverse_username_setting __setting ( SETTING_AUTH_EXTRA ) = {
+	.name = "reverse-username",
+	.description = "Reverse user name",
+	.tag = DHCP_EB_REVERSE_USERNAME,
+	.type = &setting_type_string,
+};
+
+/** iSCSI reverse password setting */
+struct setting reverse_password_setting __setting ( SETTING_AUTH_EXTRA ) = {
+	.name = "reverse-password",
+	.description = "Reverse password",
+	.tag = DHCP_EB_REVERSE_PASSWORD,
+	.type = &setting_type_string,
+};
+
+/**
+ * Parse iSCSI root path
+ *
+ * @v iscsi		iSCSI session
+ * @v root_path		iSCSI root path (as per RFC4173)
+ * @ret rc		Return status code
+ */
+static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
+				   const char *root_path ) {
+	char rp_copy[ strlen ( root_path ) + 1 ];
+	char *rp_comp[NUM_RP_COMPONENTS];
+	char *rp = rp_copy;
+	int i = 0;
+	int rc;
+
+	/* Split root path into component parts */
+	strcpy ( rp_copy, root_path );
+	while ( 1 ) {
+		rp_comp[i++] = rp;
+		if ( i == NUM_RP_COMPONENTS )
+			break;
+		for ( ; *rp != ':' ; rp++ ) {
+			if ( ! *rp ) {
+				DBGC ( iscsi, "iSCSI %p root path \"%s\" "
+				       "too short\n", iscsi, root_path );
+				return -EINVAL_ROOT_PATH_TOO_SHORT;
+			}
+		}
+		*(rp++) = '\0';
+	}
+
+	/* Use root path components to configure iSCSI session */
+	iscsi->target_address = strdup ( rp_comp[RP_SERVERNAME] );
+	if ( ! iscsi->target_address )
+		return -ENOMEM;
+	iscsi->target_port = strtoul ( rp_comp[RP_PORT], NULL, 10 );
+	if ( ! iscsi->target_port )
+		iscsi->target_port = ISCSI_PORT;
+	if ( ( rc = scsi_parse_lun ( rp_comp[RP_LUN], &iscsi->lun ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p invalid LUN \"%s\"\n",
+		       iscsi, rp_comp[RP_LUN] );
+		return rc;
+	}
+	iscsi->target_iqn = strdup ( rp_comp[RP_TARGETNAME] );
+	if ( ! iscsi->target_iqn )
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * Fetch iSCSI settings
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_fetch_settings ( struct iscsi_session *iscsi ) {
+	char *hostname;
+	union uuid uuid;
+	int len;
+
+	/* Fetch relevant settings.  Don't worry about freeing on
+	 * error, since iscsi_free() will take care of that anyway.
+	 */
+	if ( ( len = fetch_string_setting_copy ( NULL, &username_setting,
+					  &iscsi->initiator_username ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch username: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+	if ( ( len = fetch_string_setting_copy ( NULL, &password_setting,
+					  &iscsi->initiator_password ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch password: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+	if ( ( len = fetch_string_setting_copy( NULL, &reverse_username_setting,
+					     &iscsi->target_username ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch reverse username: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+	if ( ( len = fetch_string_setting_copy( NULL, &reverse_password_setting,
+					     &iscsi->target_password ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch reverse password: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+
+	/* Find a suitable initiator name */
+	if ( ( len = fetch_string_setting_copy ( NULL, &initiator_iqn_setting,
+					       &iscsi->initiator_iqn ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch initiator IQN: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+	if ( iscsi->initiator_iqn )
+		return 0;
+	if ( ( len = fetch_string_setting_copy ( NULL, &hostname_setting,
+						&hostname ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not fetch hostname: %s\n",
+		       iscsi, strerror ( len ) );
+		return len;
+	}
+	if ( hostname ) {
+		len = asprintf ( &iscsi->initiator_iqn,
+				 ISCSI_DEFAULT_IQN_PREFIX ":%s", hostname );
+		free ( hostname );
+		if ( len < 0 ) {
+			DBGC ( iscsi, "iSCSI %p could not allocate initiator "
+			       "IQN\n", iscsi );
+			return -ENOMEM;
+		}
+		assert ( iscsi->initiator_iqn );
+		return 0;
+	}
+	if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p has no suitable initiator IQN\n",
+		       iscsi );
+		return -EINVAL_NO_INITIATOR_IQN;
+	}
+	if ( ( len = asprintf ( &iscsi->initiator_iqn,
+				ISCSI_DEFAULT_IQN_PREFIX ":%s",
+				uuid_ntoa ( &uuid ) ) ) < 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not allocate initiator IQN\n",
+		       iscsi );
+		return -ENOMEM;
+	}
+	assert ( iscsi->initiator_iqn );
+
+	return 0;
+}
+
+
+/**
+ * Check iSCSI authentication details
+ *
+ * @v iscsi		iSCSI session
+ * @ret rc		Return status code
+ */
+static int iscsi_check_auth ( struct iscsi_session *iscsi ) {
+
+	/* Check for invalid authentication combinations */
+	if ( ( /* Initiator username without password (or vice-versa) */
+		( !! iscsi->initiator_username ) ^
+		( !! iscsi->initiator_password ) ) ||
+	     ( /* Target username without password (or vice-versa) */
+		( !! iscsi->target_username ) ^
+		( !! iscsi->target_password ) ) ||
+	     ( /* Target (reverse) without initiator (forward) */
+		( iscsi->target_username &&
+		  ( ! iscsi->initiator_username ) ) ) ) {
+		DBGC ( iscsi, "iSCSI %p invalid credentials: initiator "
+		       "%sname,%spw, target %sname,%spw\n", iscsi,
+		       ( iscsi->initiator_username ? "" : "no " ),
+		       ( iscsi->initiator_password ? "" : "no " ),
+		       ( iscsi->target_username ? "" : "no " ),
+		       ( iscsi->target_password ? "" : "no " ) );
+		return -EINVAL_BAD_CREDENTIAL_MIX;
+	}
+
+	return 0;
+}
+
+/**
+ * Open iSCSI URI
+ *
+ * @v parent		Parent interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int iscsi_open ( struct interface *parent, struct uri *uri ) {
+	struct iscsi_session *iscsi;
+	int rc;
+
+	/* Sanity check */
+	if ( ! uri->opaque ) {
+		rc = -EINVAL_NO_ROOT_PATH;
+		goto err_sanity_uri;
+	}
+
+	/* Allocate and initialise structure */
+	iscsi = zalloc ( sizeof ( *iscsi ) );
+	if ( ! iscsi ) {
+		rc = -ENOMEM;
+		goto err_zalloc;
+	}
+	ref_init ( &iscsi->refcnt, iscsi_free );
+	intf_init ( &iscsi->control, &iscsi_control_desc, &iscsi->refcnt );
+	intf_init ( &iscsi->data, &iscsi_data_desc, &iscsi->refcnt );
+	intf_init ( &iscsi->socket, &iscsi_socket_desc, &iscsi->refcnt );
+	process_init_stopped ( &iscsi->process, iscsi_tx_step,
+			       &iscsi->refcnt );
+
+	/* Parse root path */
+	if ( ( rc = iscsi_parse_root_path ( iscsi, uri->opaque ) ) != 0 )
+		goto err_parse_root_path;
+	/* Set fields not specified by root path */
+	if ( ( rc = iscsi_fetch_settings ( iscsi ) ) != 0 )
+		goto err_fetch_settings;
+	/* Validate authentication */
+	if ( ( rc = iscsi_check_auth ( iscsi ) ) != 0 )
+		goto err_check_auth;
+
+	/* Sanity checks */
+	if ( ! iscsi->target_address ) {
+		DBGC ( iscsi, "iSCSI %p does not yet support discovery\n",
+		       iscsi );
+		rc = -ENOTSUP_DISCOVERY;
+		goto err_sanity_address;
+	}
+	if ( ! iscsi->target_iqn ) {
+		DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n",
+		       iscsi, uri->opaque );
+		rc = -EINVAL_NO_TARGET_IQN;
+		goto err_sanity_iqn;
+	}
+	DBGC ( iscsi, "iSCSI %p initiator %s\n",iscsi, iscsi->initiator_iqn );
+	DBGC ( iscsi, "iSCSI %p target %s %s\n",
+	       iscsi, iscsi->target_address, iscsi->target_iqn );
+
+	/* Open socket */
+	if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 )
+		goto err_open_connection;
+
+	/* Attach SCSI device to parent interface */
+	if ( ( rc = scsi_open ( parent, &iscsi->control,
+				&iscsi->lun ) ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p could not create SCSI device: %s\n",
+		       iscsi, strerror ( rc ) );
+		goto err_scsi_open;
+	}
+
+	/* Mortalise self, and return */
+	ref_put ( &iscsi->refcnt );
+	return 0;
+	
+ err_scsi_open:
+ err_open_connection:
+ err_sanity_iqn:
+ err_sanity_address:
+ err_check_auth:
+ err_fetch_settings:
+ err_parse_root_path:
+	iscsi_close ( iscsi, rc );
+	ref_put ( &iscsi->refcnt );
+ err_zalloc:
+ err_sanity_uri:
+	return rc;
+}
+
+/** iSCSI URI opener */
+struct uri_opener iscsi_uri_opener __uri_opener = {
+	.scheme = "iscsi",
+	.open = iscsi_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tcpip.c b/qemu-0.15.x/roms/ipxe/src/net/tcpip.c
new file mode 100644
index 0000000..4451bf1
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tcpip.c
@@ -0,0 +1,135 @@
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tables.h>
+#include <ipxe/tcpip.h>
+
+/** @file
+ *
+ * Transport-network layer interface
+ *
+ * This file contains functions and utilities for the
+ * TCP/IP transport-network layer interface
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Process a received TCP/IP packet
+ *
+ * @v iobuf		I/O buffer
+ * @v tcpip_proto	Transport-layer protocol number
+ * @v st_src		Partially-filled source address
+ * @v st_dest		Partially-filled destination address
+ * @v pshdr_csum	Pseudo-header checksum
+ * @ret rc		Return status code
+ *
+ * This function expects a transport-layer segment from the network
+ * layer.  The network layer should fill in as much as it can of the
+ * source and destination addresses (i.e. it should fill in the
+ * address family and the network-layer addresses, but leave the ports
+ * and the rest of the structures as zero).
+ */
+int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto, 
+	       struct sockaddr_tcpip *st_src,
+	       struct sockaddr_tcpip *st_dest,
+	       uint16_t pshdr_csum ) {
+	struct tcpip_protocol *tcpip;
+
+	/* Hand off packet to the appropriate transport-layer protocol */
+	for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) {
+		if ( tcpip->tcpip_proto == tcpip_proto ) {
+			DBG ( "TCP/IP received %s packet\n", tcpip->name );
+			return tcpip->rx ( iobuf, st_src, st_dest, pshdr_csum );
+		}
+	}
+
+	DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
+	free_iob ( iobuf );
+	return -EPROTONOSUPPORT;
+}
+
+/** Transmit a TCP/IP packet
+ *
+ * @v iobuf		I/O buffer
+ * @v tcpip_protocol	Transport-layer protocol
+ * @v st_src		Source address, or NULL to use route default
+ * @v st_dest		Destination address
+ * @v netdev		Network device to use if no route found, or NULL
+ * @v trans_csum	Transport-layer checksum to complete, or NULL
+ * @ret rc		Return status code
+ */
+int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
+	       struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest,
+	       struct net_device *netdev, uint16_t *trans_csum ) {
+	struct tcpip_net_protocol *tcpip_net;
+
+	/* Hand off packet to the appropriate network-layer protocol */
+	for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) {
+		if ( tcpip_net->sa_family == st_dest->st_family ) {
+			DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
+			return tcpip_net->tx ( iobuf, tcpip_protocol, st_src,
+					       st_dest, netdev, trans_csum );
+		}
+	}
+	
+	DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family );
+	free_iob ( iobuf );
+	return -EAFNOSUPPORT;
+}
+
+/**
+ * Calculate continued TCP/IP checkum
+ *
+ * @v partial		Checksum of already-summed data, in network byte order
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret cksum		Updated checksum, in network byte order
+ *
+ * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
+ * checksum is returned in network byte order.
+ *
+ * This function may be used to add new data to an existing checksum.
+ * The function assumes that both the old data and the new data start
+ * on even byte offsets; if this is not the case then you will need to
+ * byte-swap either the input partial checksum, the output checksum,
+ * or both.  Deciding which to swap is left as an exercise for the
+ * interested reader.
+ */
+uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
+				 size_t len ) {
+	unsigned int cksum = ( ( ~partial ) & 0xffff );
+	unsigned int value;
+	unsigned int i;
+	
+	for ( i = 0 ; i < len ; i++ ) {
+		value = * ( ( uint8_t * ) data + i );
+		if ( i & 1 ) {
+			/* Odd bytes: swap on little-endian systems */
+			value = be16_to_cpu ( value );
+		} else {
+			/* Even bytes: swap on big-endian systems */
+			value = le16_to_cpu ( value );
+		}
+		cksum += value;
+		if ( cksum > 0xffff )
+			cksum -= 0xffff;
+	}
+	
+	return ( ~cksum );
+}
+
+/**
+ * Calculate TCP/IP checkum
+ *
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret cksum		Checksum, in network byte order
+ *
+ * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
+ * checksum is returned in network byte order.
+ */
+uint16_t tcpip_chksum ( const void *data, size_t len ) {
+	return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/tls.c b/qemu-0.15.x/roms/ipxe/src/net/tls.c
new file mode 100644
index 0000000..5e22221
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/tls.c
@@ -0,0 +1,1754 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Transport Layer Security Protocol
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/hmac.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/aes.h>
+#include <ipxe/rsa.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/tls.h>
+
+static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
+				const void *data, size_t len );
+static void tls_clear_cipher ( struct tls_session *tls,
+			       struct tls_cipherspec *cipherspec );
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Extract 24-bit field value
+ *
+ * @v field24		24-bit field
+ * @ret value		Field value
+ *
+ * TLS uses 24-bit integers in several places, which are awkward to
+ * parse in C.
+ */
+static unsigned long tls_uint24 ( uint8_t field24[3] ) {
+	return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
+}
+
+/******************************************************************************
+ *
+ * Cleanup functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Free TLS session
+ *
+ * @v refcnt		Reference counter
+ */
+static void free_tls ( struct refcnt *refcnt ) {
+	struct tls_session *tls =
+		container_of ( refcnt, struct tls_session, refcnt );
+
+	/* Free dynamically-allocated resources */
+	tls_clear_cipher ( tls, &tls->tx_cipherspec );
+	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
+	tls_clear_cipher ( tls, &tls->rx_cipherspec );
+	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
+	x509_free_rsa_public_key ( &tls->rsa );
+	free ( tls->rx_data );
+
+	/* Free TLS structure itself */
+	free ( tls );	
+}
+
+/**
+ * Finish with TLS session
+ *
+ * @v tls		TLS session
+ * @v rc		Status code
+ */
+static void tls_close ( struct tls_session *tls, int rc ) {
+
+	/* Remove process */
+	process_del ( &tls->process );
+	
+	/* Close ciphertext and plaintext streams */
+	intf_shutdown ( &tls->cipherstream, rc );
+	intf_shutdown ( &tls->plainstream, rc );
+}
+
+/******************************************************************************
+ *
+ * Random number generation
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Generate random data
+ *
+ * @v data		Buffer to fill
+ * @v len		Length of buffer
+ */
+static void tls_generate_random ( void *data, size_t len ) {
+	/* FIXME: Some real random data source would be nice... */
+	memset ( data, 0x01, len );
+}
+
+/**
+ * Update HMAC with a list of ( data, len ) pairs
+ *
+ * @v digest		Hash function to use
+ * @v digest_ctx	Digest context
+ * @v args		( data, len ) pairs of data, terminated by NULL
+ */
+static void tls_hmac_update_va ( struct digest_algorithm *digest,
+				 void *digest_ctx, va_list args ) {
+	void *data;
+	size_t len;
+
+	while ( ( data = va_arg ( args, void * ) ) ) {
+		len = va_arg ( args, size_t );
+		hmac_update ( digest, digest_ctx, data, len );
+	}
+}
+
+/**
+ * Generate secure pseudo-random data using a single hash function
+ *
+ * @v tls		TLS session
+ * @v digest		Hash function to use
+ * @v secret		Secret
+ * @v secret_len	Length of secret
+ * @v out		Output buffer
+ * @v out_len		Length of output buffer
+ * @v seeds		( data, len ) pairs of seed data, terminated by NULL
+ */
+static void tls_p_hash_va ( struct tls_session *tls,
+			    struct digest_algorithm *digest,
+			    void *secret, size_t secret_len,
+			    void *out, size_t out_len,
+			    va_list seeds ) {
+	uint8_t secret_copy[secret_len];
+	uint8_t digest_ctx[digest->ctxsize];
+	uint8_t digest_ctx_partial[digest->ctxsize];
+	uint8_t a[digest->digestsize];
+	uint8_t out_tmp[digest->digestsize];
+	size_t frag_len = digest->digestsize;
+	va_list tmp;
+
+	/* Copy the secret, in case HMAC modifies it */
+	memcpy ( secret_copy, secret, secret_len );
+	secret = secret_copy;
+	DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name );
+	DBGC2_HD ( tls, secret, secret_len );
+
+	/* Calculate A(1) */
+	hmac_init ( digest, digest_ctx, secret, &secret_len );
+	va_copy ( tmp, seeds );
+	tls_hmac_update_va ( digest, digest_ctx, tmp );
+	va_end ( tmp );
+	hmac_final ( digest, digest_ctx, secret, &secret_len, a );
+	DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name );
+	DBGC2_HD ( tls, &a, sizeof ( a ) );
+
+	/* Generate as much data as required */
+	while ( out_len ) {
+		/* Calculate output portion */
+		hmac_init ( digest, digest_ctx, secret, &secret_len );
+		hmac_update ( digest, digest_ctx, a, sizeof ( a ) );
+		memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize );
+		va_copy ( tmp, seeds );
+		tls_hmac_update_va ( digest, digest_ctx, tmp );
+		va_end ( tmp );
+		hmac_final ( digest, digest_ctx,
+			     secret, &secret_len, out_tmp );
+
+		/* Copy output */
+		if ( frag_len > out_len )
+			frag_len = out_len;
+		memcpy ( out, out_tmp, frag_len );
+		DBGC2 ( tls, "TLS %p %s output:\n", tls, digest->name );
+		DBGC2_HD ( tls, out, frag_len );
+
+		/* Calculate A(i) */
+		hmac_final ( digest, digest_ctx_partial,
+			     secret, &secret_len, a );
+		DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name );
+		DBGC2_HD ( tls, &a, sizeof ( a ) );
+
+		out += frag_len;
+		out_len -= frag_len;
+	}
+}
+
+/**
+ * Generate secure pseudo-random data
+ *
+ * @v tls		TLS session
+ * @v secret		Secret
+ * @v secret_len	Length of secret
+ * @v out		Output buffer
+ * @v out_len		Length of output buffer
+ * @v ...		( data, len ) pairs of seed data, terminated by NULL
+ */
+static void tls_prf ( struct tls_session *tls, void *secret, size_t secret_len,
+		      void *out, size_t out_len, ... ) {
+	va_list seeds;
+	va_list tmp;
+	size_t subsecret_len;
+	void *md5_secret;
+	void *sha1_secret;
+	uint8_t out_md5[out_len];
+	uint8_t out_sha1[out_len];
+	unsigned int i;
+
+	va_start ( seeds, out_len );
+
+	/* Split secret into two, with an overlap of up to one byte */
+	subsecret_len = ( ( secret_len + 1 ) / 2 );
+	md5_secret = secret;
+	sha1_secret = ( secret + secret_len - subsecret_len );
+
+	/* Calculate MD5 portion */
+	va_copy ( tmp, seeds );
+	tls_p_hash_va ( tls, &md5_algorithm, md5_secret, subsecret_len,
+			out_md5, out_len, seeds );
+	va_end ( tmp );
+
+	/* Calculate SHA1 portion */
+	va_copy ( tmp, seeds );
+	tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, subsecret_len,
+			out_sha1, out_len, seeds );
+	va_end ( tmp );
+
+	/* XOR the two portions together into the final output buffer */
+	for ( i = 0 ; i < out_len ; i++ ) {
+		*( ( uint8_t * ) out + i ) = ( out_md5[i] ^ out_sha1[i] );
+	}
+
+	va_end ( seeds );
+}
+
+/**
+ * Generate secure pseudo-random data
+ *
+ * @v secret		Secret
+ * @v secret_len	Length of secret
+ * @v out		Output buffer
+ * @v out_len		Length of output buffer
+ * @v label		String literal label
+ * @v ...		( data, len ) pairs of seed data
+ */
+#define tls_prf_label( tls, secret, secret_len, out, out_len, label, ... ) \
+	tls_prf ( (tls), (secret), (secret_len), (out), (out_len),	   \
+		  label, ( sizeof ( label ) - 1 ), __VA_ARGS__, NULL )
+
+/******************************************************************************
+ *
+ * Secret management
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Generate master secret
+ *
+ * @v tls		TLS session
+ *
+ * The pre-master secret and the client and server random values must
+ * already be known.
+ */
+static void tls_generate_master_secret ( struct tls_session *tls ) {
+	DBGC ( tls, "TLS %p pre-master-secret:\n", tls );
+	DBGC_HD ( tls, &tls->pre_master_secret,
+		  sizeof ( tls->pre_master_secret ) );
+	DBGC ( tls, "TLS %p client random bytes:\n", tls );
+	DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
+	DBGC ( tls, "TLS %p server random bytes:\n", tls );
+	DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
+
+	tls_prf_label ( tls, &tls->pre_master_secret,
+			sizeof ( tls->pre_master_secret ),
+			&tls->master_secret, sizeof ( tls->master_secret ),
+			"master secret",
+			&tls->client_random, sizeof ( tls->client_random ),
+			&tls->server_random, sizeof ( tls->server_random ) );
+
+	DBGC ( tls, "TLS %p generated master secret:\n", tls );
+	DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
+}
+
+/**
+ * Generate key material
+ *
+ * @v tls		TLS session
+ *
+ * The master secret must already be known.
+ */
+static int tls_generate_keys ( struct tls_session *tls ) {
+	struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending;
+	struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending;
+	size_t hash_size = tx_cipherspec->digest->digestsize;
+	size_t key_size = tx_cipherspec->key_len;
+	size_t iv_size = tx_cipherspec->cipher->blocksize;
+	size_t total = ( 2 * ( hash_size + key_size + iv_size ) );
+	uint8_t key_block[total];
+	uint8_t *key;
+	int rc;
+
+	/* Generate key block */
+	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
+			key_block, sizeof ( key_block ), "key expansion",
+			&tls->server_random, sizeof ( tls->server_random ),
+			&tls->client_random, sizeof ( tls->client_random ) );
+
+	/* Split key block into portions */
+	key = key_block;
+
+	/* TX MAC secret */
+	memcpy ( tx_cipherspec->mac_secret, key, hash_size );
+	DBGC ( tls, "TLS %p TX MAC secret:\n", tls );
+	DBGC_HD ( tls, key, hash_size );
+	key += hash_size;
+
+	/* RX MAC secret */
+	memcpy ( rx_cipherspec->mac_secret, key, hash_size );
+	DBGC ( tls, "TLS %p RX MAC secret:\n", tls );
+	DBGC_HD ( tls, key, hash_size );
+	key += hash_size;
+
+	/* TX key */
+	if ( ( rc = cipher_setkey ( tx_cipherspec->cipher,
+				    tx_cipherspec->cipher_ctx,
+				    key, key_size ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not set TX key: %s\n",
+		       tls, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( tls, "TLS %p TX key:\n", tls );
+	DBGC_HD ( tls, key, key_size );
+	key += key_size;
+
+	/* RX key */
+	if ( ( rc = cipher_setkey ( rx_cipherspec->cipher,
+				    rx_cipherspec->cipher_ctx,
+				    key, key_size ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not set TX key: %s\n",
+		       tls, strerror ( rc ) );
+		return rc;
+	}
+	DBGC ( tls, "TLS %p RX key:\n", tls );
+	DBGC_HD ( tls, key, key_size );
+	key += key_size;
+
+	/* TX initialisation vector */
+	cipher_setiv ( tx_cipherspec->cipher, tx_cipherspec->cipher_ctx, key );
+	DBGC ( tls, "TLS %p TX IV:\n", tls );
+	DBGC_HD ( tls, key, iv_size );
+	key += iv_size;
+
+	/* RX initialisation vector */
+	cipher_setiv ( rx_cipherspec->cipher, rx_cipherspec->cipher_ctx, key );
+	DBGC ( tls, "TLS %p RX IV:\n", tls );
+	DBGC_HD ( tls, key, iv_size );
+	key += iv_size;
+
+	assert ( ( key_block + total ) == key );
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Cipher suite management
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Clear cipher suite
+ *
+ * @v cipherspec	TLS cipher specification
+ */
+static void tls_clear_cipher ( struct tls_session *tls __unused,
+			       struct tls_cipherspec *cipherspec ) {
+	free ( cipherspec->dynamic );
+	memset ( cipherspec, 0, sizeof ( cipherspec ) );
+	cipherspec->pubkey = &pubkey_null;
+	cipherspec->cipher = &cipher_null;
+	cipherspec->digest = &digest_null;
+}
+
+/**
+ * Set cipher suite
+ *
+ * @v tls		TLS session
+ * @v cipherspec	TLS cipher specification
+ * @v pubkey		Public-key encryption elgorithm
+ * @v cipher		Bulk encryption cipher algorithm
+ * @v digest		MAC digest algorithm
+ * @v key_len		Key length
+ * @ret rc		Return status code
+ */
+static int tls_set_cipher ( struct tls_session *tls,
+			    struct tls_cipherspec *cipherspec,
+			    struct pubkey_algorithm *pubkey,
+			    struct cipher_algorithm *cipher,
+			    struct digest_algorithm *digest,
+			    size_t key_len ) {
+	size_t total;
+	void *dynamic;
+
+	/* Clear out old cipher contents, if any */
+	tls_clear_cipher ( tls, cipherspec );
+	
+	/* Allocate dynamic storage */
+	total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
+	dynamic = malloc ( total );
+	if ( ! dynamic ) {
+		DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
+		       "context\n", tls, total );
+		return -ENOMEM;
+	}
+	memset ( dynamic, 0, total );
+
+	/* Assign storage */
+	cipherspec->dynamic = dynamic;
+	cipherspec->pubkey_ctx = dynamic;	dynamic += pubkey->ctxsize;
+	cipherspec->cipher_ctx = dynamic;	dynamic += cipher->ctxsize;
+	cipherspec->cipher_next_ctx = dynamic;	dynamic += cipher->ctxsize;
+	cipherspec->mac_secret = dynamic;	dynamic += digest->digestsize;
+	assert ( ( cipherspec->dynamic + total ) == dynamic );
+
+	/* Store parameters */
+	cipherspec->pubkey = pubkey;
+	cipherspec->cipher = cipher;
+	cipherspec->digest = digest;
+	cipherspec->key_len = key_len;
+
+	return 0;
+}
+
+/**
+ * Select next cipher suite
+ *
+ * @v tls		TLS session
+ * @v cipher_suite	Cipher suite specification
+ * @ret rc		Return status code
+ */
+static int tls_select_cipher ( struct tls_session *tls,
+			       unsigned int cipher_suite ) {
+	struct pubkey_algorithm *pubkey = &pubkey_null;
+	struct cipher_algorithm *cipher = &cipher_null;
+	struct digest_algorithm *digest = &digest_null;
+	unsigned int key_len = 0;
+	int rc;
+
+	switch ( cipher_suite ) {
+	case htons ( TLS_RSA_WITH_AES_128_CBC_SHA ):
+		key_len = ( 128 / 8 );
+		cipher = &aes_cbc_algorithm;
+		digest = &sha1_algorithm;
+		break;
+	case htons ( TLS_RSA_WITH_AES_256_CBC_SHA ):
+		key_len = ( 256 / 8 );
+		cipher = &aes_cbc_algorithm;
+		digest = &sha1_algorithm;
+		break;
+	default:
+		DBGC ( tls, "TLS %p does not support cipher %04x\n",
+		       tls, ntohs ( cipher_suite ) );
+		return -ENOTSUP;
+	}
+
+	/* Set ciphers */
+	if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, pubkey,
+				     cipher, digest, key_len ) ) != 0 )
+		return rc;
+	if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, pubkey,
+				     cipher, digest, key_len ) ) != 0 )
+		return rc;
+
+	DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls,
+	       pubkey->name, cipher->name, ( key_len * 8 ), digest->name );
+
+	return 0;
+}
+
+/**
+ * Activate next cipher suite
+ *
+ * @v tls		TLS session
+ * @v pending		Pending cipher specification
+ * @v active		Active cipher specification to replace
+ * @ret rc		Return status code
+ */
+static int tls_change_cipher ( struct tls_session *tls,
+			       struct tls_cipherspec *pending,
+			       struct tls_cipherspec *active ) {
+
+	/* Sanity check */
+	if ( /* FIXME (when pubkey is not hard-coded to RSA):
+	      * ( pending->pubkey == &pubkey_null ) || */
+	     ( pending->cipher == &cipher_null ) ||
+	     ( pending->digest == &digest_null ) ) {
+		DBGC ( tls, "TLS %p refusing to use null cipher\n", tls );
+		return -ENOTSUP;
+	}
+
+	tls_clear_cipher ( tls, active );
+	memswap ( active, pending, sizeof ( *active ) );
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Handshake verification
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Add handshake record to verification hash
+ *
+ * @v tls		TLS session
+ * @v data		Handshake record
+ * @v len		Length of handshake record
+ */
+static void tls_add_handshake ( struct tls_session *tls,
+				const void *data, size_t len ) {
+
+	digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len );
+	digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len );
+}
+
+/**
+ * Calculate handshake verification hash
+ *
+ * @v tls		TLS session
+ * @v out		Output buffer
+ *
+ * Calculates the MD5+SHA1 digest over all handshake messages seen so
+ * far.
+ */
+static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
+	struct digest_algorithm *md5 = &md5_algorithm;
+	struct digest_algorithm *sha1 = &sha1_algorithm;
+	uint8_t md5_ctx[md5->ctxsize];
+	uint8_t sha1_ctx[sha1->ctxsize];
+	void *md5_digest = out;
+	void *sha1_digest = ( out + md5->digestsize );
+
+	memcpy ( md5_ctx, tls->handshake_md5_ctx, sizeof ( md5_ctx ) );
+	memcpy ( sha1_ctx, tls->handshake_sha1_ctx, sizeof ( sha1_ctx ) );
+	digest_final ( md5, md5_ctx, md5_digest );
+	digest_final ( sha1, sha1_ctx, sha1_digest );
+}
+
+/******************************************************************************
+ *
+ * Record handling
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transmit Handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_send_handshake ( struct tls_session *tls,
+				void *data, size_t len ) {
+
+	/* Add to handshake digest */
+	tls_add_handshake ( tls, data, len );
+
+	/* Send record */
+	return tls_send_plaintext ( tls, TLS_TYPE_HANDSHAKE, data, len );
+}
+
+/**
+ * Transmit Client Hello record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_client_hello ( struct tls_session *tls ) {
+	struct {
+		uint32_t type_length;
+		uint16_t version;
+		uint8_t random[32];
+		uint8_t session_id_len;
+		uint16_t cipher_suite_len;
+		uint16_t cipher_suites[2];
+		uint8_t compression_methods_len;
+		uint8_t compression_methods[1];
+	} __attribute__ (( packed )) hello;
+
+	memset ( &hello, 0, sizeof ( hello ) );
+	hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
+			      htonl ( sizeof ( hello ) -
+				      sizeof ( hello.type_length ) ) );
+	hello.version = htons ( TLS_VERSION_TLS_1_0 );
+	memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
+	hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
+	hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
+	hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
+	hello.compression_methods_len = sizeof ( hello.compression_methods );
+
+	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
+}
+
+/**
+ * Transmit Client Key Exchange record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_client_key_exchange ( struct tls_session *tls ) {
+	/* FIXME: Hack alert */
+	RSA_CTX *rsa_ctx;
+	RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
+			  tls->rsa.exponent, tls->rsa.exponent_len );
+	struct {
+		uint32_t type_length;
+		uint16_t encrypted_pre_master_secret_len;
+		uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
+	} __attribute__ (( packed )) key_xchg;
+
+	memset ( &key_xchg, 0, sizeof ( key_xchg ) );
+	key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
+				 htonl ( sizeof ( key_xchg ) -
+					 sizeof ( key_xchg.type_length ) ) );
+	key_xchg.encrypted_pre_master_secret_len
+		= htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
+
+	/* FIXME: Hack alert */
+	DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
+	DBGC_HD ( tls, &tls->pre_master_secret,
+		  sizeof ( tls->pre_master_secret ) );
+	DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
+	DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
+	RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
+		      sizeof ( tls->pre_master_secret ),
+		      key_xchg.encrypted_pre_master_secret, 0 );
+	DBGC ( tls, "RSA encrypt done.  Ciphertext:\n" );
+	DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
+		  sizeof ( key_xchg.encrypted_pre_master_secret ) );
+	RSA_free ( rsa_ctx );
+
+
+	return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
+}
+
+/**
+ * Transmit Change Cipher record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_change_cipher ( struct tls_session *tls ) {
+	static const uint8_t change_cipher[1] = { 1 };
+	return tls_send_plaintext ( tls, TLS_TYPE_CHANGE_CIPHER,
+				    change_cipher, sizeof ( change_cipher ) );
+}
+
+/**
+ * Transmit Finished record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_finished ( struct tls_session *tls ) {
+	struct {
+		uint32_t type_length;
+		uint8_t verify_data[12];
+	} __attribute__ (( packed )) finished;
+	uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
+
+	memset ( &finished, 0, sizeof ( finished ) );
+	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
+				 htonl ( sizeof ( finished ) -
+					 sizeof ( finished.type_length ) ) );
+	tls_verify_handshake ( tls, digest );
+	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
+			finished.verify_data, sizeof ( finished.verify_data ),
+			"client finished", digest, sizeof ( digest ) );
+
+	return tls_send_handshake ( tls, &finished, sizeof ( finished ) );
+}
+
+/**
+ * Receive new Change Cipher record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_new_change_cipher ( struct tls_session *tls,
+				   void *data, size_t len ) {
+	int rc;
+
+	if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
+		DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL;
+	}
+
+	if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
+					&tls->rx_cipherspec ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not activate RX cipher: %s\n",
+		       tls, strerror ( rc ) );
+		return rc;
+	}
+	tls->rx_seq = ~( ( uint64_t ) 0 );
+
+	return 0;
+}
+
+/**
+ * Receive new Alert record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
+	struct {
+		uint8_t level;
+		uint8_t description;
+		char next[0];
+	} __attribute__ (( packed )) *alert = data;
+	void *end = alert->next;
+
+	/* Sanity check */
+	if ( end != ( data + len ) ) {
+		DBGC ( tls, "TLS %p received overlength Alert\n", tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL;
+	}
+
+	switch ( alert->level ) {
+	case TLS_ALERT_WARNING:
+		DBGC ( tls, "TLS %p received warning alert %d\n",
+		       tls, alert->description );
+		return 0;
+	case TLS_ALERT_FATAL:
+		DBGC ( tls, "TLS %p received fatal alert %d\n",
+		       tls, alert->description );
+		return -EPERM;
+	default:
+		DBGC ( tls, "TLS %p received unknown alert level %d"
+		       "(alert %d)\n", tls, alert->level, alert->description );
+		return -EIO;
+	}
+}
+
+/**
+ * Receive new Server Hello handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext handshake record
+ * @v len		Length of plaintext handshake record
+ * @ret rc		Return status code
+ */
+static int tls_new_server_hello ( struct tls_session *tls,
+				  void *data, size_t len ) {
+	struct {
+		uint16_t version;
+		uint8_t random[32];
+		uint8_t session_id_len;
+		char next[0];
+	} __attribute__ (( packed )) *hello_a = data;
+	struct {
+		uint8_t session_id[hello_a->session_id_len];
+		uint16_t cipher_suite;
+		uint8_t compression_method;
+		char next[0];
+	} __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next;
+	void *end = hello_b->next;
+	int rc;
+
+	/* Sanity check */
+	if ( end != ( data + len ) ) {
+		DBGC ( tls, "TLS %p received overlength Server Hello\n", tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL;
+	}
+
+	/* Check protocol version */
+	if ( ntohs ( hello_a->version ) < TLS_VERSION_TLS_1_0 ) {
+		DBGC ( tls, "TLS %p does not support protocol version %d.%d\n",
+		       tls, ( ntohs ( hello_a->version ) >> 8 ),
+		       ( ntohs ( hello_a->version ) & 0xff ) );
+		return -ENOTSUP;
+	}
+
+	/* Copy out server random bytes */
+	memcpy ( &tls->server_random, &hello_a->random,
+		 sizeof ( tls->server_random ) );
+
+	/* Select cipher suite */
+	if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
+		return rc;
+
+	/* Generate secrets */
+	tls_generate_master_secret ( tls );
+	if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Receive new Certificate handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext handshake record
+ * @v len		Length of plaintext handshake record
+ * @ret rc		Return status code
+ */
+static int tls_new_certificate ( struct tls_session *tls,
+				 void *data, size_t len ) {
+	struct {
+		uint8_t length[3];
+		uint8_t certificates[0];
+	} __attribute__ (( packed )) *certificate = data;
+	struct {
+		uint8_t length[3];
+		uint8_t certificate[0];
+	} __attribute__ (( packed )) *element =
+		  ( ( void * ) certificate->certificates );
+	size_t elements_len = tls_uint24 ( certificate->length );
+	void *end = ( certificate->certificates + elements_len );
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Sanity check */
+	if ( end != ( data + len ) ) {
+		DBGC ( tls, "TLS %p received overlength Server Certificate\n",
+		       tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL;
+	}
+
+	/* Traverse certificate chain */
+	do {
+		cursor.data = element->certificate;
+		cursor.len = tls_uint24 ( element->length );
+		if ( ( cursor.data + cursor.len ) > end ) {
+			DBGC ( tls, "TLS %p received corrupt Server "
+			       "Certificate\n", tls );
+			DBGC_HD ( tls, data, len );
+			return -EINVAL;
+		}
+
+		// HACK
+		if ( ( rc = x509_rsa_public_key ( &cursor,
+						  &tls->rsa ) ) != 0 ) {
+			DBGC ( tls, "TLS %p cannot determine RSA public key: "
+			       "%s\n", tls, strerror ( rc ) );
+			return rc;
+		}
+		return 0;
+
+		element = ( cursor.data + cursor.len );
+	} while ( element != end );
+
+	return -EINVAL;
+}
+
+/**
+ * Receive new Server Hello Done handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext handshake record
+ * @v len		Length of plaintext handshake record
+ * @ret rc		Return status code
+ */
+static int tls_new_server_hello_done ( struct tls_session *tls,
+				       void *data, size_t len ) {
+	struct {
+		char next[0];
+	} __attribute__ (( packed )) *hello_done = data;
+	void *end = hello_done->next;
+
+	/* Sanity check */
+	if ( end != ( data + len ) ) {
+		DBGC ( tls, "TLS %p received overlength Server Hello Done\n",
+		       tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL;
+	}
+
+	/* Check that we are ready to send the Client Key Exchange */
+	if ( tls->tx_state != TLS_TX_NONE ) {
+		DBGC ( tls, "TLS %p received Server Hello Done while in "
+		       "TX state %d\n", tls, tls->tx_state );
+		return -EIO;
+	}
+
+	/* Start sending the Client Key Exchange */
+	tls->tx_state = TLS_TX_CLIENT_KEY_EXCHANGE;
+
+	return 0;
+}
+
+/**
+ * Receive new Finished handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext handshake record
+ * @v len		Length of plaintext handshake record
+ * @ret rc		Return status code
+ */
+static int tls_new_finished ( struct tls_session *tls,
+			      void *data, size_t len ) {
+
+	/* FIXME: Handle this properly */
+	tls->tx_state = TLS_TX_DATA;
+	( void ) data;
+	( void ) len;
+	return 0;
+}
+
+/**
+ * Receive new Handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_new_handshake ( struct tls_session *tls,
+			       void *data, size_t len ) {
+	void *end = ( data + len );
+	int rc;
+
+	while ( data != end ) {
+		struct {
+			uint8_t type;
+			uint8_t length[3];
+			uint8_t payload[0];
+		} __attribute__ (( packed )) *handshake = data;
+		void *payload = &handshake->payload;
+		size_t payload_len = tls_uint24 ( handshake->length );
+		void *next = ( payload + payload_len );
+
+		/* Sanity check */
+		if ( next > end ) {
+			DBGC ( tls, "TLS %p received overlength Handshake\n",
+			       tls );
+			DBGC_HD ( tls, data, len );
+			return -EINVAL;
+		}
+
+		switch ( handshake->type ) {
+		case TLS_SERVER_HELLO:
+			rc = tls_new_server_hello ( tls, payload, payload_len );
+			break;
+		case TLS_CERTIFICATE:
+			rc = tls_new_certificate ( tls, payload, payload_len );
+			break;
+		case TLS_SERVER_HELLO_DONE:
+			rc = tls_new_server_hello_done ( tls, payload,
+							 payload_len );
+			break;
+		case TLS_FINISHED:
+			rc = tls_new_finished ( tls, payload, payload_len );
+			break;
+		default:
+			DBGC ( tls, "TLS %p ignoring handshake type %d\n",
+			       tls, handshake->type );
+			rc = 0;
+			break;
+		}
+
+		/* Add to handshake digest (except for Hello Requests,
+		 * which are explicitly excluded).
+		 */
+		if ( handshake->type != TLS_HELLO_REQUEST )
+			tls_add_handshake ( tls, data,
+					    sizeof ( *handshake ) +
+					    payload_len );
+
+		/* Abort on failure */
+		if ( rc != 0 )
+			return rc;
+
+		/* Move to next handshake record */
+		data = next;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive new record
+ *
+ * @v tls		TLS session
+ * @v type		Record type
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_new_record ( struct tls_session *tls,
+			    unsigned int type, void *data, size_t len ) {
+
+	switch ( type ) {
+	case TLS_TYPE_CHANGE_CIPHER:
+		return tls_new_change_cipher ( tls, data, len );
+	case TLS_TYPE_ALERT:
+		return tls_new_alert ( tls, data, len );
+	case TLS_TYPE_HANDSHAKE:
+		return tls_new_handshake ( tls, data, len );
+	case TLS_TYPE_DATA:
+		return xfer_deliver_raw ( &tls->plainstream, data, len );
+	default:
+		/* RFC4346 says that we should just ignore unknown
+		 * record types.
+		 */
+		DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
+		return 0;
+	}
+}
+
+/******************************************************************************
+ *
+ * Record encryption/decryption
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Calculate HMAC
+ *
+ * @v tls		TLS session
+ * @v cipherspec	Cipher specification
+ * @v seq		Sequence number
+ * @v tlshdr		TLS header
+ * @v data		Data
+ * @v len		Length of data
+ * @v mac		HMAC to fill in
+ */
+static void tls_hmac ( struct tls_session *tls __unused,
+		       struct tls_cipherspec *cipherspec,
+		       uint64_t seq, struct tls_header *tlshdr,
+		       const void *data, size_t len, void *hmac ) {
+	struct digest_algorithm *digest = cipherspec->digest;
+	uint8_t digest_ctx[digest->ctxsize];
+
+	hmac_init ( digest, digest_ctx, cipherspec->mac_secret,
+		    &digest->digestsize );
+	seq = cpu_to_be64 ( seq );
+	hmac_update ( digest, digest_ctx, &seq, sizeof ( seq ) );
+	hmac_update ( digest, digest_ctx, tlshdr, sizeof ( *tlshdr ) );
+	hmac_update ( digest, digest_ctx, data, len );
+	hmac_final ( digest, digest_ctx, cipherspec->mac_secret,
+		     &digest->digestsize, hmac );
+}
+
+/**
+ * Allocate and assemble stream-ciphered record from data and MAC portions
+ *
+ * @v tls		TLS session
+ * @ret data		Data
+ * @ret len		Length of data
+ * @ret digest		MAC digest
+ * @ret plaintext_len	Length of plaintext record
+ * @ret plaintext	Allocated plaintext record
+ */
+static void * __malloc tls_assemble_stream ( struct tls_session *tls,
+				    const void *data, size_t len,
+				    void *digest, size_t *plaintext_len ) {
+	size_t mac_len = tls->tx_cipherspec.digest->digestsize;
+	void *plaintext;
+	void *content;
+	void *mac;
+
+	/* Calculate stream-ciphered struct length */
+	*plaintext_len = ( len + mac_len );
+
+	/* Allocate stream-ciphered struct */
+	plaintext = malloc ( *plaintext_len );
+	if ( ! plaintext )
+		return NULL;
+	content = plaintext;
+	mac = ( content + len );
+
+	/* Fill in stream-ciphered struct */
+	memcpy ( content, data, len );
+	memcpy ( mac, digest, mac_len );
+
+	return plaintext;
+}
+
+/**
+ * Allocate and assemble block-ciphered record from data and MAC portions
+ *
+ * @v tls		TLS session
+ * @ret data		Data
+ * @ret len		Length of data
+ * @ret digest		MAC digest
+ * @ret plaintext_len	Length of plaintext record
+ * @ret plaintext	Allocated plaintext record
+ */
+static void * tls_assemble_block ( struct tls_session *tls,
+				   const void *data, size_t len,
+				   void *digest, size_t *plaintext_len ) {
+	size_t blocksize = tls->tx_cipherspec.cipher->blocksize;
+	size_t iv_len = blocksize;
+	size_t mac_len = tls->tx_cipherspec.digest->digestsize;
+	size_t padding_len;
+	void *plaintext;
+	void *iv;
+	void *content;
+	void *mac;
+	void *padding;
+
+	/* FIXME: TLSv1.1 has an explicit IV */
+	iv_len = 0;
+
+	/* Calculate block-ciphered struct length */
+	padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) );
+	*plaintext_len = ( iv_len + len + mac_len + padding_len + 1 );
+
+	/* Allocate block-ciphered struct */
+	plaintext = malloc ( *plaintext_len );
+	if ( ! plaintext )
+		return NULL;
+	iv = plaintext;
+	content = ( iv + iv_len );
+	mac = ( content + len );
+	padding = ( mac + mac_len );
+
+	/* Fill in block-ciphered struct */
+	memset ( iv, 0, iv_len );
+	memcpy ( content, data, len );
+	memcpy ( mac, digest, mac_len );
+	memset ( padding, padding_len, ( padding_len + 1 ) );
+
+	return plaintext;
+}
+
+/**
+ * Send plaintext record
+ *
+ * @v tls		TLS session
+ * @v type		Record type
+ * @v data		Plaintext record
+ * @v len		Length of plaintext record
+ * @ret rc		Return status code
+ */
+static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
+				const void *data, size_t len ) {
+	struct tls_header plaintext_tlshdr;
+	struct tls_header *tlshdr;
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
+	void *plaintext = NULL;
+	size_t plaintext_len;
+	struct io_buffer *ciphertext = NULL;
+	size_t ciphertext_len;
+	size_t mac_len = cipherspec->digest->digestsize;
+	uint8_t mac[mac_len];
+	int rc;
+
+	/* Construct header */
+	plaintext_tlshdr.type = type;
+	plaintext_tlshdr.version = htons ( TLS_VERSION_TLS_1_0 );
+	plaintext_tlshdr.length = htons ( len );
+
+	/* Calculate MAC */
+	tls_hmac ( tls, cipherspec, tls->tx_seq, &plaintext_tlshdr,
+		   data, len, mac );
+
+	/* Allocate and assemble plaintext struct */
+	if ( is_stream_cipher ( cipherspec->cipher ) ) {
+		plaintext = tls_assemble_stream ( tls, data, len, mac,
+						  &plaintext_len );
+	} else {
+		plaintext = tls_assemble_block ( tls, data, len, mac,
+						 &plaintext_len );
+	}
+	if ( ! plaintext ) {
+		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
+		       "plaintext\n", tls, plaintext_len );
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	DBGC2 ( tls, "Sending plaintext data:\n" );
+	DBGC2_HD ( tls, plaintext, plaintext_len );
+
+	/* Allocate ciphertext */
+	ciphertext_len = ( sizeof ( *tlshdr ) + plaintext_len );
+	ciphertext = xfer_alloc_iob ( &tls->cipherstream, ciphertext_len );
+	if ( ! ciphertext ) {
+		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
+		       "ciphertext\n", tls, ciphertext_len );
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	/* Assemble ciphertext */
+	tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) );
+	tlshdr->type = type;
+	tlshdr->version = htons ( TLS_VERSION_TLS_1_0 );
+	tlshdr->length = htons ( plaintext_len );
+	memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx,
+		 cipherspec->cipher->ctxsize );
+	cipher_encrypt ( cipherspec->cipher, cipherspec->cipher_next_ctx,
+			 plaintext, iob_put ( ciphertext, plaintext_len ),
+			 plaintext_len );
+
+	/* Free plaintext as soon as possible to conserve memory */
+	free ( plaintext );
+	plaintext = NULL;
+
+	/* Send ciphertext */
+	if ( ( rc = xfer_deliver_iob ( &tls->cipherstream,
+				       iob_disown ( ciphertext ) ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n",
+		       tls, strerror ( rc ) );
+		goto done;
+	}
+
+	/* Update TX state machine to next record */
+	tls->tx_seq += 1;
+	memcpy ( tls->tx_cipherspec.cipher_ctx,
+		 tls->tx_cipherspec.cipher_next_ctx,
+		 tls->tx_cipherspec.cipher->ctxsize );
+
+ done:
+	free ( plaintext );
+	free_iob ( ciphertext );
+	return rc;
+}
+
+/**
+ * Split stream-ciphered record into data and MAC portions
+ *
+ * @v tls		TLS session
+ * @v plaintext		Plaintext record
+ * @v plaintext_len	Length of record
+ * @ret data		Data
+ * @ret len		Length of data
+ * @ret digest		MAC digest
+ * @ret rc		Return status code
+ */
+static int tls_split_stream ( struct tls_session *tls,
+			      void *plaintext, size_t plaintext_len,
+			      void **data, size_t *len, void **digest ) {
+	void *content;
+	size_t content_len;
+	void *mac;
+	size_t mac_len;
+
+	/* Decompose stream-ciphered data */
+	mac_len = tls->rx_cipherspec.digest->digestsize;
+	if ( plaintext_len < mac_len ) {
+		DBGC ( tls, "TLS %p received underlength record\n", tls );
+		DBGC_HD ( tls, plaintext, plaintext_len );
+		return -EINVAL;
+	}
+	content_len = ( plaintext_len - mac_len );
+	content = plaintext;
+	mac = ( content + content_len );
+
+	/* Fill in return values */
+	*data = content;
+	*len = content_len;
+	*digest = mac;
+
+	return 0;
+}
+
+/**
+ * Split block-ciphered record into data and MAC portions
+ *
+ * @v tls		TLS session
+ * @v plaintext		Plaintext record
+ * @v plaintext_len	Length of record
+ * @ret data		Data
+ * @ret len		Length of data
+ * @ret digest		MAC digest
+ * @ret rc		Return status code
+ */
+static int tls_split_block ( struct tls_session *tls,
+			     void *plaintext, size_t plaintext_len,
+			     void **data, size_t *len,
+			     void **digest ) {
+	void *iv;
+	size_t iv_len;
+	void *content;
+	size_t content_len;
+	void *mac;
+	size_t mac_len;
+	void *padding;
+	size_t padding_len;
+	unsigned int i;
+
+	/* Decompose block-ciphered data */
+	if ( plaintext_len < 1 ) {
+		DBGC ( tls, "TLS %p received underlength record\n", tls );
+		DBGC_HD ( tls, plaintext, plaintext_len );
+		return -EINVAL;
+	}
+	iv_len = tls->rx_cipherspec.cipher->blocksize;
+
+	/* FIXME: TLSv1.1 uses an explicit IV */
+	iv_len = 0;
+
+	mac_len = tls->rx_cipherspec.digest->digestsize;
+	padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) );
+	if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) {
+		DBGC ( tls, "TLS %p received underlength record\n", tls );
+		DBGC_HD ( tls, plaintext, plaintext_len );
+		return -EINVAL;
+	}
+	content_len = ( plaintext_len - iv_len - mac_len - padding_len - 1 );
+	iv = plaintext;
+	content = ( iv + iv_len );
+	mac = ( content + content_len );
+	padding = ( mac + mac_len );
+
+	/* Verify padding bytes */
+	for ( i = 0 ; i < padding_len ; i++ ) {
+		if ( *( ( uint8_t * ) ( padding + i ) ) != padding_len ) {
+			DBGC ( tls, "TLS %p received bad padding\n", tls );
+			DBGC_HD ( tls, plaintext, plaintext_len );
+			return -EINVAL;
+		}
+	}
+
+	/* Fill in return values */
+	*data = content;
+	*len = content_len;
+	*digest = mac;
+
+	return 0;
+}
+
+/**
+ * Receive new ciphertext record
+ *
+ * @v tls		TLS session
+ * @v tlshdr		Record header
+ * @v ciphertext	Ciphertext record
+ * @ret rc		Return status code
+ */
+static int tls_new_ciphertext ( struct tls_session *tls,
+				struct tls_header *tlshdr, void *ciphertext ) {
+	struct tls_header plaintext_tlshdr;
+	struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
+	size_t record_len = ntohs ( tlshdr->length );
+	void *plaintext = NULL;
+	void *data;
+	size_t len;
+	void *mac;
+	size_t mac_len = cipherspec->digest->digestsize;
+	uint8_t verify_mac[mac_len];
+	int rc;
+
+	/* Allocate buffer for plaintext */
+	plaintext = malloc ( record_len );
+	if ( ! plaintext ) {
+		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
+		       "decryption buffer\n", tls, record_len );
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	/* Decrypt the record */
+	cipher_decrypt ( cipherspec->cipher, cipherspec->cipher_ctx,
+			 ciphertext, plaintext, record_len );
+
+	/* Split record into content and MAC */
+	if ( is_stream_cipher ( cipherspec->cipher ) ) {
+		if ( ( rc = tls_split_stream ( tls, plaintext, record_len,
+					       &data, &len, &mac ) ) != 0 )
+			goto done;
+	} else {
+		if ( ( rc = tls_split_block ( tls, plaintext, record_len,
+					      &data, &len, &mac ) ) != 0 )
+			goto done;
+	}
+
+	/* Verify MAC */
+	plaintext_tlshdr.type = tlshdr->type;
+	plaintext_tlshdr.version = tlshdr->version;
+	plaintext_tlshdr.length = htons ( len );
+	tls_hmac ( tls, cipherspec, tls->rx_seq, &plaintext_tlshdr,
+		   data, len, verify_mac);
+	if ( memcmp ( mac, verify_mac, mac_len ) != 0 ) {
+		DBGC ( tls, "TLS %p failed MAC verification\n", tls );
+		DBGC_HD ( tls, plaintext, record_len );
+		goto done;
+	}
+
+	DBGC2 ( tls, "Received plaintext data:\n" );
+	DBGC2_HD ( tls, data, len );
+
+	/* Process plaintext record */
+	if ( ( rc = tls_new_record ( tls, tlshdr->type, data, len ) ) != 0 )
+		goto done;
+
+	rc = 0;
+ done:
+	free ( plaintext );
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * Plaintext stream operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check flow control window
+ *
+ * @v tls		TLS session
+ * @ret len		Length of window
+ */
+static size_t tls_plainstream_window ( struct tls_session *tls ) {
+
+	/* Block window unless we are ready to accept data */
+	if ( tls->tx_state != TLS_TX_DATA )
+		return 0;
+
+	return xfer_window ( &tls->cipherstream );
+}
+
+/**
+ * Deliver datagram as raw data
+ *
+ * @v tls		TLS session
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int tls_plainstream_deliver ( struct tls_session *tls,
+				     struct io_buffer *iobuf,
+				     struct xfer_metadata *meta __unused ) {
+	int rc;
+	
+	/* Refuse unless we are ready to accept data */
+	if ( tls->tx_state != TLS_TX_DATA ) {
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	if ( ( rc = tls_send_plaintext ( tls, TLS_TYPE_DATA, iobuf->data,
+					 iob_len ( iobuf ) ) ) != 0 )
+		goto done;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** TLS plaintext stream interface operations */
+static struct interface_operation tls_plainstream_ops[] = {
+	INTF_OP ( xfer_deliver, struct tls_session *, tls_plainstream_deliver ),
+	INTF_OP ( xfer_window, struct tls_session *, tls_plainstream_window ),
+	INTF_OP ( intf_close, struct tls_session *, tls_close ),
+};
+
+/** TLS plaintext stream interface descriptor */
+static struct interface_descriptor tls_plainstream_desc =
+	INTF_DESC_PASSTHRU ( struct tls_session, plainstream,
+			     tls_plainstream_ops, cipherstream );
+
+/******************************************************************************
+ *
+ * Ciphertext stream operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Handle received TLS header
+ *
+ * @v tls		TLS session
+ * @ret rc		Returned status code
+ */
+static int tls_newdata_process_header ( struct tls_session *tls ) {
+	size_t data_len = ntohs ( tls->rx_header.length );
+
+	/* Allocate data buffer now that we know the length */
+	assert ( tls->rx_data == NULL );
+	tls->rx_data = malloc ( data_len );
+	if ( ! tls->rx_data ) {
+		DBGC ( tls, "TLS %p could not allocate %zd bytes "
+		       "for receive buffer\n", tls, data_len );
+		return -ENOMEM;
+	}
+
+	/* Move to data state */
+	tls->rx_state = TLS_RX_DATA;
+
+	return 0;
+}
+
+/**
+ * Handle received TLS data payload
+ *
+ * @v tls		TLS session
+ * @ret rc		Returned status code
+ */
+static int tls_newdata_process_data ( struct tls_session *tls ) {
+	int rc;
+
+	/* Process record */
+	if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
+					 tls->rx_data ) ) != 0 )
+		return rc;
+
+	/* Increment RX sequence number */
+	tls->rx_seq += 1;
+
+	/* Free data buffer */
+	free ( tls->rx_data );
+	tls->rx_data = NULL;
+
+	/* Return to header state */
+	tls->rx_state = TLS_RX_HEADER;
+
+	return 0;
+}
+
+/**
+ * Receive new ciphertext
+ *
+ * @v tls		TLS session
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadat
+ * @ret rc		Return status code
+ */
+static int tls_cipherstream_deliver ( struct tls_session *tls,
+				      struct io_buffer *iobuf,
+				      struct xfer_metadata *xfer __unused ) {
+	size_t frag_len;
+	void *buf;
+	size_t buf_len;
+	int ( * process ) ( struct tls_session *tls );
+	int rc;
+
+	while ( iob_len ( iobuf ) ) {
+		/* Select buffer according to current state */
+		switch ( tls->rx_state ) {
+		case TLS_RX_HEADER:
+			buf = &tls->rx_header;
+			buf_len = sizeof ( tls->rx_header );
+			process = tls_newdata_process_header;
+			break;
+		case TLS_RX_DATA:
+			buf = tls->rx_data;
+			buf_len = ntohs ( tls->rx_header.length );
+			process = tls_newdata_process_data;
+			break;
+		default:
+			assert ( 0 );
+			rc = -EINVAL;
+			goto done;
+		}
+
+		/* Copy data portion to buffer */
+		frag_len = ( buf_len - tls->rx_rcvd );
+		if ( frag_len > iob_len  ( iobuf ) )
+			frag_len = iob_len ( iobuf );
+		memcpy ( ( buf + tls->rx_rcvd ), iobuf->data, frag_len );
+		tls->rx_rcvd += frag_len;
+		iob_pull ( iobuf, frag_len );
+
+		/* Process data if buffer is now full */
+		if ( tls->rx_rcvd == buf_len ) {
+			if ( ( rc = process ( tls ) ) != 0 ) {
+				tls_close ( tls, rc );
+				goto done;
+			}
+			tls->rx_rcvd = 0;
+		}
+	}
+	rc = 0;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** TLS ciphertext stream interface operations */
+static struct interface_operation tls_cipherstream_ops[] = {
+	INTF_OP ( xfer_deliver, struct tls_session *,
+		  tls_cipherstream_deliver ),
+	INTF_OP ( intf_close, struct tls_session *, tls_close ),
+};
+
+/** TLS ciphertext stream interface descriptor */
+static struct interface_descriptor tls_cipherstream_desc =
+	INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
+			     tls_cipherstream_ops, plainstream );
+
+/******************************************************************************
+ *
+ * Controlling process
+ *
+ ******************************************************************************
+ */
+
+/**
+ * TLS TX state machine
+ *
+ * @v process		TLS process
+ */
+static void tls_step ( struct process *process ) {
+	struct tls_session *tls =
+		container_of ( process, struct tls_session, process );
+	int rc;
+
+	/* Wait for cipherstream to become ready */
+	if ( ! xfer_window ( &tls->cipherstream ) )
+		return;
+
+	switch ( tls->tx_state ) {
+	case TLS_TX_NONE:
+		/* Nothing to do */
+		break;
+	case TLS_TX_CLIENT_HELLO:
+		/* Send Client Hello */
+		if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
+			       tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_state = TLS_TX_NONE;
+		break;
+	case TLS_TX_CLIENT_KEY_EXCHANGE:
+		/* Send Client Key Exchange */
+		if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could send Client Key Exchange: "
+			       "%s\n", tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_state = TLS_TX_CHANGE_CIPHER;
+		break;
+	case TLS_TX_CHANGE_CIPHER:
+		/* Send Change Cipher, and then change the cipher in use */
+		if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not send Change Cipher: "
+			       "%s\n", tls, strerror ( rc ) );
+			goto err;
+		}
+		if ( ( rc = tls_change_cipher ( tls,
+						&tls->tx_cipherspec_pending,
+						&tls->tx_cipherspec )) != 0 ){
+			DBGC ( tls, "TLS %p could not activate TX cipher: "
+			       "%s\n", tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_seq = 0;
+		tls->tx_state = TLS_TX_FINISHED;
+		break;
+	case TLS_TX_FINISHED:
+		/* Send Finished */
+		if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not send Finished: %s\n",
+			       tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_state = TLS_TX_NONE;
+		break;
+	case TLS_TX_DATA:
+		/* Nothing to do */
+		break;
+	default:
+		assert ( 0 );
+	}
+
+	return;
+
+ err:
+	tls_close ( tls, rc );
+}
+
+/******************************************************************************
+ *
+ * Instantiator
+ *
+ ******************************************************************************
+ */
+
+int add_tls ( struct interface *xfer, struct interface **next ) {
+	struct tls_session *tls;
+
+	/* Allocate and initialise TLS structure */
+	tls = malloc ( sizeof ( *tls ) );
+	if ( ! tls )
+		return -ENOMEM;
+	memset ( tls, 0, sizeof ( *tls ) );
+	ref_init ( &tls->refcnt, free_tls );
+	intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
+	intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
+	tls_clear_cipher ( tls, &tls->tx_cipherspec );
+	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
+	tls_clear_cipher ( tls, &tls->rx_cipherspec );
+	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
+	tls->client_random.gmt_unix_time = 0;
+	tls_generate_random ( &tls->client_random.random,
+			      ( sizeof ( tls->client_random.random ) ) );
+	tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
+	tls_generate_random ( &tls->pre_master_secret.random,
+			      ( sizeof ( tls->pre_master_secret.random ) ) );
+	digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
+	digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
+	tls->tx_state = TLS_TX_CLIENT_HELLO;
+	process_init ( &tls->process, tls_step, &tls->refcnt );
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &tls->plainstream, xfer );
+	*next = &tls->cipherstream;
+	ref_put ( &tls->refcnt );
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp.c b/qemu-0.15.x/roms/ipxe/src/net/udp.c
new file mode 100644
index 0000000..5f45253
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp.c
@@ -0,0 +1,448 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/udp.h>
+
+/** @file
+ *
+ * UDP protocol
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * A UDP connection
+ *
+ */
+struct udp_connection {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** List of UDP connections */
+	struct list_head list;
+
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** Local socket address */
+	struct sockaddr_tcpip local;
+	/** Remote socket address */
+	struct sockaddr_tcpip peer;
+};
+
+/**
+ * List of registered UDP connections
+ */
+static LIST_HEAD ( udp_conns );
+
+/* Forward declatations */
+static struct interface_descriptor udp_xfer_desc;
+struct tcpip_protocol udp_protocol __tcpip_protocol;
+
+/**
+ * Bind UDP connection to local port
+ *
+ * @v udp		UDP connection
+ * @ret rc		Return status code
+ *
+ * Opens the UDP connection and binds to the specified local port.  If
+ * no local port is specified, the first available port will be used.
+ */
+static int udp_bind ( struct udp_connection *udp ) {
+	struct udp_connection *existing;
+	static uint16_t try_port = 1023;
+
+	/* If no port specified, find the first available port */
+	if ( ! udp->local.st_port ) {
+		while ( try_port ) {
+			try_port++;
+			if ( try_port < 1024 )
+				continue;
+			udp->local.st_port = htons ( try_port );
+			if ( udp_bind ( udp ) == 0 )
+				return 0;
+		}
+		return -EADDRINUSE;
+	}
+
+	/* Attempt bind to local port */
+	list_for_each_entry ( existing, &udp_conns, list ) {
+		if ( existing->local.st_port == udp->local.st_port ) {
+			DBGC ( udp, "UDP %p could not bind: port %d in use\n",
+			       udp, ntohs ( udp->local.st_port ) );
+			return -EADDRINUSE;
+		}
+	}
+
+	/* Add to UDP connection list */
+	DBGC ( udp, "UDP %p bound to port %d\n",
+	       udp, ntohs ( udp->local.st_port ) );
+
+	return 0;
+}
+
+/**
+ * Open a UDP connection
+ *
+ * @v xfer		Data transfer interface
+ * @v peer		Peer socket address, or NULL
+ * @v local		Local socket address, or NULL
+ * @v promisc		Socket is promiscuous
+ * @ret rc		Return status code
+ */
+static int udp_open_common ( struct interface *xfer,
+			     struct sockaddr *peer, struct sockaddr *local,
+			     int promisc ) {
+	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
+	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
+	struct udp_connection *udp;
+	int rc;
+
+	/* Allocate and initialise structure */
+	udp = zalloc ( sizeof ( *udp ) );
+	if ( ! udp )
+		return -ENOMEM;
+	DBGC ( udp, "UDP %p allocated\n", udp );
+	ref_init ( &udp->refcnt, NULL );
+	intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
+	if ( st_peer )
+		memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
+	if ( st_local )
+		memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
+
+	/* Bind to local port */
+	if ( ! promisc ) {
+		if ( ( rc = udp_bind ( udp ) ) != 0 )
+			goto err;
+	}
+
+	/* Attach parent interface, transfer reference to connection
+	 * list and return
+	 */
+	intf_plug_plug ( &udp->xfer, xfer );
+	list_add ( &udp->list, &udp_conns );
+	return 0;
+
+ err:
+	ref_put ( &udp->refcnt );
+	return rc;
+}
+
+/**
+ * Open a UDP connection
+ *
+ * @v xfer		Data transfer interface
+ * @v peer		Peer socket address
+ * @v local		Local socket address, or NULL
+ * @ret rc		Return status code
+ */
+int udp_open ( struct interface *xfer, struct sockaddr *peer,
+	       struct sockaddr *local ) {
+	return udp_open_common ( xfer, peer, local, 0 );
+}
+
+/**
+ * Open a promiscuous UDP connection
+ *
+ * @v xfer		Data transfer interface
+ * @ret rc		Return status code
+ *
+ * Promiscuous UDP connections are required in order to support the
+ * PXE API.
+ */
+int udp_open_promisc ( struct interface *xfer ) {
+	return udp_open_common ( xfer, NULL, NULL, 1 );
+}
+
+/**
+ * Close a UDP connection
+ *
+ * @v udp		UDP connection
+ * @v rc		Reason for close
+ */
+static void udp_close ( struct udp_connection *udp, int rc ) {
+
+	/* Close data transfer interface */
+	intf_shutdown ( &udp->xfer, rc );
+
+	/* Remove from list of connections and drop list's reference */
+	list_del ( &udp->list );
+	ref_put ( &udp->refcnt );
+
+	DBGC ( udp, "UDP %p closed\n", udp );
+}
+
+/**
+ * Transmit data via a UDP connection to a specified address
+ *
+ * @v udp		UDP connection
+ * @v iobuf		I/O buffer
+ * @v src		Source address, or NULL to use default
+ * @v dest		Destination address, or NULL to use default
+ * @v netdev		Network device, or NULL to use default
+ * @ret rc		Return status code
+ */
+static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
+		    struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
+		    struct net_device *netdev ) {
+       	struct udp_header *udphdr;
+	size_t len;
+	int rc;
+
+	/* Check we can accommodate the header */
+	if ( ( rc = iob_ensure_headroom ( iobuf,
+					  MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
+		free_iob ( iobuf );
+		return rc;
+	}
+
+	/* Fill in default values if not explicitly provided */
+	if ( ! src )
+		src = &udp->local;
+	if ( ! dest )
+		dest = &udp->peer;
+
+	/* Add the UDP header */
+	udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
+	len = iob_len ( iobuf );
+	udphdr->dest = dest->st_port;
+	udphdr->src = src->st_port;
+	udphdr->len = htons ( len );
+	udphdr->chksum = 0;
+	udphdr->chksum = tcpip_chksum ( udphdr, len );
+
+	/* Dump debugging information */
+	DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp,
+	       ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
+	       ntohs ( udphdr->len ) );
+
+	/* Send it to the next layer for processing */
+	if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
+			       &udphdr->chksum ) ) != 0 ) {
+		DBGC ( udp, "UDP %p could not transmit packet: %s\n",
+		       udp, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Identify UDP connection by local address
+ *
+ * @v local		Local address
+ * @ret udp		UDP connection, or NULL
+ */
+static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
+	static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
+	struct udp_connection *udp;
+
+	list_for_each_entry ( udp, &udp_conns, list ) {
+		if ( ( ( udp->local.st_family == local->st_family ) ||
+		       ( udp->local.st_family == 0 ) ) &&
+		     ( ( udp->local.st_port == local->st_port ) ||
+		       ( udp->local.st_port == 0 ) ) &&
+		     ( ( memcmp ( udp->local.pad, local->pad,
+				  sizeof ( udp->local.pad ) ) == 0 ) ||
+		       ( memcmp ( udp->local.pad, empty_sockaddr.pad,
+				  sizeof ( udp->local.pad ) ) == 0 ) ) ) {
+			return udp;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Process a received packet
+ *
+ * @v iobuf		I/O buffer
+ * @v st_src		Partially-filled source address
+ * @v st_dest		Partially-filled destination address
+ * @v pshdr_csum	Pseudo-header checksum
+ * @ret rc		Return status code
+ */
+static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+		    struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
+	struct udp_header *udphdr = iobuf->data;
+	struct udp_connection *udp;
+	struct xfer_metadata meta;
+	size_t ulen;
+	unsigned int csum;
+	int rc = 0;
+
+	/* Sanity check packet */
+	if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
+		DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
+		      iob_len ( iobuf ), sizeof ( *udphdr ) );
+		
+		rc = -EINVAL;
+		goto done;
+	}
+	ulen = ntohs ( udphdr->len );
+	if ( ulen < sizeof ( *udphdr ) ) {
+		DBG ( "UDP length too short at %zd bytes "
+		      "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
+		rc = -EINVAL;
+		goto done;
+	}
+	if ( ulen > iob_len ( iobuf ) ) {
+		DBG ( "UDP length too long at %zd bytes (packet is %zd "
+		      "bytes)\n", ulen, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto done;
+	}
+	if ( udphdr->chksum ) {
+		csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
+		if ( csum != 0 ) {
+			DBG ( "UDP checksum incorrect (is %04x including "
+			      "checksum field, should be 0000)\n", csum );
+			rc = -EINVAL;
+			goto done;
+		}
+	}
+
+	/* Parse parameters from header and strip header */
+	st_src->st_port = udphdr->src;
+	st_dest->st_port = udphdr->dest;
+	udp = udp_demux ( st_dest );
+	iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
+	iob_pull ( iobuf, sizeof ( *udphdr ) );
+
+	/* Dump debugging information */
+	DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
+	       ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
+
+	/* Ignore if no matching connection found */
+	if ( ! udp ) {
+		DBG ( "No UDP connection listening on port %d\n",
+		      ntohs ( udphdr->dest ) );
+		rc = -ENOTCONN;
+		goto done;
+	}
+
+	/* Pass data to application */
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.src = ( struct sockaddr * ) st_src;
+	meta.dest = ( struct sockaddr * ) st_dest;
+	rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+struct tcpip_protocol udp_protocol __tcpip_protocol = {
+	.name = "UDP",
+	.rx = udp_rx,
+	.tcpip_proto = IP_UDP,
+};
+
+/***************************************************************************
+ *
+ * Data transfer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate I/O buffer for UDP
+ *
+ * @v udp		UDP connection
+ * @v len		Payload size
+ * @ret iobuf		I/O buffer, or NULL
+ */
+static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
+					       size_t len ) {
+	struct io_buffer *iobuf;
+
+	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
+	if ( ! iobuf ) {
+		DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
+		       udp, len );
+		return NULL;
+	}
+	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
+	return iobuf;
+}
+
+/**
+ * Deliver datagram as I/O buffer
+ *
+ * @v udp		UDP connection
+ * @v iobuf		Datagram I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int udp_xfer_deliver ( struct udp_connection *udp,
+			      struct io_buffer *iobuf,
+			      struct xfer_metadata *meta ) {
+
+	/* Transmit data, if possible */
+	udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
+		 ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev );
+
+	return 0;
+}
+
+/** UDP data transfer interface operations */
+static struct interface_operation udp_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
+	INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
+	INTF_OP ( intf_close, struct udp_connection *, udp_close ),
+};
+
+/** UDP data transfer interface descriptor */
+static struct interface_descriptor udp_xfer_desc =
+	INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
+
+/***************************************************************************
+ *
+ * Openers
+ *
+ ***************************************************************************
+ */
+
+/** UDP socket opener */
+struct socket_opener udp_socket_opener __socket_opener = {
+	.semantics	= UDP_SOCK_DGRAM,
+	.family		= AF_INET,
+	.open		= udp_open,
+};
+
+/** Linkage hack */
+int udp_sock_dgram = UDP_SOCK_DGRAM;
+
+/**
+ * Open UDP URI
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		URI
+ * @ret rc		Return status code
+ */
+static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
+	struct sockaddr_tcpip peer;
+
+	/* Sanity check */
+	if ( ! uri->host )
+		return -EINVAL;
+
+	memset ( &peer, 0, sizeof ( peer ) );
+	peer.st_port = htons ( uri_port ( uri, 0 ) );
+	return xfer_open_named_socket ( xfer, SOCK_DGRAM,
+					( struct sockaddr * ) &peer,
+					uri->host, NULL );
+}
+
+/** UDP URI opener */
+struct uri_opener udp_uri_opener __uri_opener = {
+	.scheme		= "udp",
+	.open		= udp_open_uri,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp/dhcp.c b/qemu-0.15.x/roms/ipxe/src/net/udp/dhcp.c
new file mode 100644
index 0000000..a0b74df
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp/dhcp.c
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/device.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/job.h>
+#include <ipxe/retry.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/ip.h>
+#include <ipxe/uuid.h>
+#include <ipxe/timer.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/dhcpopts.h>
+#include <ipxe/dhcppkt.h>
+#include <ipxe/dhcp_arch.h>
+#include <ipxe/features.h>
+
+/** @file
+ *
+ * Dynamic Host Configuration Protocol
+ *
+ */
+
+struct dhcp_session;
+static int dhcp_tx ( struct dhcp_session *dhcp );
+
+/**
+ * DHCP operation types
+ *
+ * This table maps from DHCP message types (i.e. values of the @c
+ * DHCP_MESSAGE_TYPE option) to values of the "op" field within a DHCP
+ * packet.
+ */
+static const uint8_t dhcp_op[] = {
+	[DHCPDISCOVER]	= BOOTP_REQUEST,
+	[DHCPOFFER]	= BOOTP_REPLY,
+	[DHCPREQUEST]	= BOOTP_REQUEST,
+	[DHCPDECLINE]	= BOOTP_REQUEST,
+	[DHCPACK]	= BOOTP_REPLY,
+	[DHCPNAK]	= BOOTP_REPLY,
+	[DHCPRELEASE]	= BOOTP_REQUEST,
+	[DHCPINFORM]	= BOOTP_REQUEST,
+};
+
+/** Raw option data for options common to all DHCP requests */
+static uint8_t dhcp_request_options_data[] = {
+	DHCP_MESSAGE_TYPE, DHCP_BYTE ( 0 ),
+	DHCP_MAX_MESSAGE_SIZE,
+	DHCP_WORD ( ETH_MAX_MTU - 20 /* IP header */ - 8 /* UDP header */ ),
+	DHCP_CLIENT_ARCHITECTURE, DHCP_ARCH_CLIENT_ARCHITECTURE,
+	DHCP_CLIENT_NDI, DHCP_ARCH_CLIENT_NDI,
+	DHCP_VENDOR_CLASS_ID, DHCP_ARCH_VENDOR_CLASS_ID,
+	DHCP_USER_CLASS_ID, DHCP_STRING ( 'i', 'P', 'X', 'E' ),
+	DHCP_PARAMETER_REQUEST_LIST,
+	DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
+		      DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
+		      DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
+		      DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
+		      DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
+	DHCP_END
+};
+
+/** Version number feature */
+FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
+
+/** DHCP server address setting */
+struct setting dhcp_server_setting __setting ( SETTING_MISC ) = {
+	.name = "dhcp-server",
+	.description = "DHCP server",
+	.tag = DHCP_SERVER_IDENTIFIER,
+	.type = &setting_type_ipv4,
+};
+
+/** DHCP user class setting */
+struct setting user_class_setting __setting ( SETTING_HOST_EXTRA ) = {
+	.name = "user-class",
+	.description = "DHCP user class",
+	.tag = DHCP_USER_CLASS_ID,
+	.type = &setting_type_string,
+};
+
+/** Use cached network settings */
+struct setting use_cached_setting __setting ( SETTING_MISC ) = {
+	.name = "use-cached",
+	.description = "Use cached settings",
+	.tag = DHCP_EB_USE_CACHED,
+	.type = &setting_type_uint8,
+};
+
+/**
+ * Name a DHCP packet type
+ *
+ * @v msgtype		DHCP message type
+ * @ret string		DHCP mesasge type name
+ */
+static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
+	switch ( msgtype ) {
+	case DHCPNONE:		return "BOOTP"; /* Non-DHCP packet */
+	case DHCPDISCOVER:	return "DHCPDISCOVER";
+	case DHCPOFFER:		return "DHCPOFFER";
+	case DHCPREQUEST:	return "DHCPREQUEST";
+	case DHCPDECLINE:	return "DHCPDECLINE";
+	case DHCPACK:		return "DHCPACK";
+	case DHCPNAK:		return "DHCPNAK";
+	case DHCPRELEASE:	return "DHCPRELEASE";
+	case DHCPINFORM:	return "DHCPINFORM";
+	default:		return "DHCP<invalid>";
+	}
+}
+
+/**
+ * Calculate DHCP transaction ID for a network device
+ *
+ * @v netdev		Network device
+ * @ret xid		DHCP XID
+ *
+ * Extract the least significant bits of the hardware address for use
+ * as the transaction ID.
+ */
+static uint32_t dhcp_xid ( struct net_device *netdev ) {
+	uint32_t xid;
+
+	memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
+			 - sizeof ( xid ) ), sizeof ( xid ) );
+	return xid;
+}
+
+/****************************************************************************
+ *
+ * DHCP session
+ *
+ */
+
+struct dhcp_session;
+
+/** DHCP session state operations */
+struct dhcp_session_state {
+	/** State name */
+	const char *name;
+	/**
+	 * Construct transmitted packet
+	 *
+	 * @v dhcp		DHCP session
+	 * @v dhcppkt		DHCP packet
+	 * @v peer		Destination address
+	 */
+	int ( * tx ) ( struct dhcp_session *dhcp,
+		       struct dhcp_packet *dhcppkt,
+		       struct sockaddr_in *peer );
+	/** Handle received packet
+	 *
+	 * @v dhcp		DHCP session
+	 * @v dhcppkt		DHCP packet
+	 * @v peer		DHCP server address
+	 * @v msgtype		DHCP message type
+	 * @v server_id		DHCP server ID
+	 */
+	void ( * rx ) ( struct dhcp_session *dhcp,
+			struct dhcp_packet *dhcppkt,
+			struct sockaddr_in *peer,
+			uint8_t msgtype, struct in_addr server_id );
+	/** Handle timer expiry
+	 *
+	 * @v dhcp		DHCP session
+	 */
+	void ( * expired ) ( struct dhcp_session *dhcp );
+	/** Transmitted message type */
+	uint8_t tx_msgtype;
+	/** Apply minimum timeout */
+	uint8_t apply_min_timeout;
+};
+
+static struct dhcp_session_state dhcp_state_discover;
+static struct dhcp_session_state dhcp_state_request;
+static struct dhcp_session_state dhcp_state_proxy;
+static struct dhcp_session_state dhcp_state_pxebs;
+
+/** A DHCP session */
+struct dhcp_session {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Job control interface */
+	struct interface job;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** Network device being configured */
+	struct net_device *netdev;
+	/** Local socket address */
+	struct sockaddr_in local;
+	/** State of the session */
+	struct dhcp_session_state *state;
+
+	/** Offered IP address */
+	struct in_addr offer;
+	/** DHCP server */
+	struct in_addr server;
+	/** DHCP offer priority */
+	int priority;
+
+	/** ProxyDHCP protocol extensions should be ignored */
+	int no_pxedhcp;
+	/** ProxyDHCP server */
+	struct in_addr proxy_server;
+	/** ProxyDHCP offer */
+	struct dhcp_packet *proxy_offer;
+	/** ProxyDHCP offer priority */
+	int proxy_priority;
+
+	/** PXE Boot Server type */
+	uint16_t pxe_type;
+	/** List of PXE Boot Servers to attempt */
+	struct in_addr *pxe_attempt;
+	/** List of PXE Boot Servers to accept */
+	struct in_addr *pxe_accept;
+
+	/** Retransmission timer */
+	struct retry_timer timer;
+	/** Transmission counter */
+	unsigned int count;
+	/** Start time of the current state (in ticks) */
+	unsigned long start;
+};
+
+/**
+ * Free DHCP session
+ *
+ * @v refcnt		Reference counter
+ */
+static void dhcp_free ( struct refcnt *refcnt ) {
+	struct dhcp_session *dhcp =
+		container_of ( refcnt, struct dhcp_session, refcnt );
+
+	netdev_put ( dhcp->netdev );
+	dhcppkt_put ( dhcp->proxy_offer );
+	free ( dhcp );
+}
+
+/**
+ * Mark DHCP session as complete
+ *
+ * @v dhcp		DHCP session
+ * @v rc		Return status code
+ */
+static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
+
+	/* Stop retry timer */
+	stop_timer ( &dhcp->timer );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &dhcp->xfer, rc );
+	intf_shutdown ( &dhcp->job, rc );
+}
+
+/**
+ * Transition to new DHCP session state
+ *
+ * @v dhcp		DHCP session
+ * @v state		New session state
+ */
+static void dhcp_set_state ( struct dhcp_session *dhcp,
+			     struct dhcp_session_state *state ) {
+
+	DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
+	dhcp->state = state;
+	dhcp->start = currticks();
+	stop_timer ( &dhcp->timer );
+	dhcp->timer.min_timeout =
+		( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 );
+	dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
+	start_timer_nodelay ( &dhcp->timer );
+}
+
+/**
+ * Check if DHCP packet contains PXE options
+ *
+ * @v dhcppkt		DHCP packet
+ * @ret has_pxeopts	DHCP packet contains PXE options
+ *
+ * It is assumed that the packet is already known to contain option 60
+ * set to "PXEClient".
+ */
+static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
+
+	/* Check for a boot filename */
+	if ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 )
+		return 1;
+
+	/* Check for a PXE boot menu */
+	if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
+		return 1;
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * DHCP state machine
+ *
+ */
+
+/**
+ * Construct transmitted packet for DHCP discovery
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		Destination address
+ */
+static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
+			       struct dhcp_packet *dhcppkt __unused,
+			       struct sockaddr_in *peer ) {
+
+	DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
+
+	/* Set server address */
+	peer->sin_addr.s_addr = INADDR_BROADCAST;
+	peer->sin_port = htons ( BOOTPS_PORT );
+
+	return 0;
+}
+
+/**
+ * Handle received packet during DHCP discovery
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		DHCP server address
+ * @v msgtype		DHCP message type
+ * @v server_id		DHCP server ID
+ */
+static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
+				struct dhcp_packet *dhcppkt,
+				struct sockaddr_in *peer, uint8_t msgtype,
+				struct in_addr server_id ) {
+	struct in_addr ip;
+	char vci[9]; /* "PXEClient" */
+	int vci_len;
+	int has_pxeclient;
+	int8_t priority = 0;
+	uint8_t no_pxedhcp = 0;
+	unsigned long elapsed;
+
+	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+	       ntohs ( peer->sin_port ) );
+	if ( server_id.s_addr != peer->sin_addr.s_addr )
+		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+	/* Identify offered IP address */
+	ip = dhcppkt->dhcphdr->yiaddr;
+	if ( ip.s_addr )
+		DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
+
+	/* Identify "PXEClient" vendor class */
+	vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
+				  vci, sizeof ( vci ) );
+	has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
+			  ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
+	if ( has_pxeclient ) {
+		DBGC ( dhcp, "%s",
+		       ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
+	}
+
+	/* Identify priority */
+	dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
+			sizeof ( priority ) );
+	if ( priority )
+		DBGC ( dhcp, " pri %d", priority );
+
+	/* Identify ignore-PXE flag */
+	dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp,
+			sizeof ( no_pxedhcp ) );
+	if ( no_pxedhcp )
+		DBGC ( dhcp, " nopxe" );
+	DBGC ( dhcp, "\n" );
+
+	/* Select as DHCP offer, if applicable */
+	if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
+	     ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) &&
+	     ( priority >= dhcp->priority ) ) {
+		dhcp->offer = ip;
+		dhcp->server = server_id;
+		dhcp->priority = priority;
+		dhcp->no_pxedhcp = no_pxedhcp;
+	}
+
+	/* Select as ProxyDHCP offer, if applicable */
+	if ( server_id.s_addr && has_pxeclient &&
+	     ( priority >= dhcp->proxy_priority ) ) {
+		dhcppkt_put ( dhcp->proxy_offer );
+		dhcp->proxy_server = server_id;
+		dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
+		dhcp->proxy_priority = priority;
+	}
+
+	/* We can exit the discovery state when we have a valid
+	 * DHCPOFFER, and either:
+	 *
+	 *  o  The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or
+	 *  o  We have a valid ProxyDHCPOFFER, or
+	 *  o  We have allowed sufficient time for ProxyDHCPOFFERs.
+	 */
+
+	/* If we don't yet have a DHCPOFFER, do nothing */
+	if ( ! dhcp->offer.s_addr )
+		return;
+
+	/* If we can't yet transition to DHCPREQUEST, do nothing */
+	elapsed = ( currticks() - dhcp->start );
+	if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
+		 ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
+		return;
+
+	/* Transition to DHCPREQUEST */
+	dhcp_set_state ( dhcp, &dhcp_state_request );
+}
+
+/**
+ * Handle timer expiry during DHCP discovery
+ *
+ * @v dhcp		DHCP session
+ */
+static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
+	unsigned long elapsed = ( currticks() - dhcp->start );
+
+	/* Give up waiting for ProxyDHCP before we reach the failure point */
+	if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
+		dhcp_set_state ( dhcp, &dhcp_state_request );
+		return;
+	}
+
+	/* Otherwise, retransmit current packet */
+	dhcp_tx ( dhcp );
+}
+
+/** DHCP discovery state operations */
+static struct dhcp_session_state dhcp_state_discover = {
+	.name			= "discovery",
+	.tx			= dhcp_discovery_tx,
+	.rx			= dhcp_discovery_rx,
+	.expired		= dhcp_discovery_expired,
+	.tx_msgtype		= DHCPDISCOVER,
+	.apply_min_timeout	= 1,
+};
+
+/**
+ * Construct transmitted packet for DHCP request
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		Destination address
+ */
+static int dhcp_request_tx ( struct dhcp_session *dhcp,
+			     struct dhcp_packet *dhcppkt,
+			     struct sockaddr_in *peer ) {
+	int rc;
+
+	DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
+	       dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT );
+	DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) );
+
+	/* Set server ID */
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+				    &dhcp->server,
+				    sizeof ( dhcp->server ) ) ) != 0 )
+		return rc;
+
+	/* Set requested IP address */
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
+				    &dhcp->offer,
+				    sizeof ( dhcp->offer ) ) ) != 0 )
+		return rc;
+
+	/* Set server address */
+	peer->sin_addr.s_addr = INADDR_BROADCAST;
+	peer->sin_port = htons ( BOOTPS_PORT );
+
+	return 0;
+}
+
+/**
+ * Handle received packet during DHCP request
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		DHCP server address
+ * @v msgtype		DHCP message type
+ * @v server_id		DHCP server ID
+ */
+static void dhcp_request_rx ( struct dhcp_session *dhcp,
+			      struct dhcp_packet *dhcppkt,
+			      struct sockaddr_in *peer, uint8_t msgtype,
+			      struct in_addr server_id ) {
+	struct in_addr ip;
+	struct settings *parent;
+	struct settings *settings;
+	int rc;
+
+	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+	       ntohs ( peer->sin_port ) );
+	if ( server_id.s_addr != peer->sin_addr.s_addr )
+		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+	/* Identify leased IP address */
+	ip = dhcppkt->dhcphdr->yiaddr;
+	if ( ip.s_addr )
+		DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
+	DBGC ( dhcp, "\n" );
+
+	/* Filter out unacceptable responses */
+	if ( peer->sin_port != htons ( BOOTPS_PORT ) )
+		return;
+	if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
+		return;
+	if ( server_id.s_addr != dhcp->server.s_addr )
+		return;
+	if ( ip.s_addr != dhcp->offer.s_addr )
+		return;
+
+	/* Record assigned address */
+	dhcp->local.sin_addr = ip;
+
+	/* Register settings */
+	parent = netdev_settings ( dhcp->netdev );
+	settings = &dhcppkt->settings;
+	if ( ( rc = register_settings ( settings, parent,
+					DHCP_SETTINGS_NAME ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+		       dhcp, strerror ( rc ) );
+		dhcp_finished ( dhcp, rc );
+		return;
+	}
+
+	/* Perform ProxyDHCP if applicable */
+	if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
+	     ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
+		if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
+			/* PXE options already present; register settings
+			 * without performing a ProxyDHCPREQUEST
+			 */
+			settings = &dhcp->proxy_offer->settings;
+			if ( ( rc = register_settings ( settings, NULL,
+					   PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
+				DBGC ( dhcp, "DHCP %p could not register "
+				       "proxy settings: %s\n",
+				       dhcp, strerror ( rc ) );
+				dhcp_finished ( dhcp, rc );
+				return;
+			}
+		} else {
+			/* PXE options not present; use a ProxyDHCPREQUEST */
+			dhcp_set_state ( dhcp, &dhcp_state_proxy );
+			return;
+		}
+	}
+
+	/* Terminate DHCP */
+	dhcp_finished ( dhcp, 0 );
+}
+
+/**
+ * Handle timer expiry during DHCP discovery
+ *
+ * @v dhcp		DHCP session
+ */
+static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
+
+	/* Retransmit current packet */
+	dhcp_tx ( dhcp );
+}
+
+/** DHCP request state operations */
+static struct dhcp_session_state dhcp_state_request = {
+	.name			= "request",
+	.tx			= dhcp_request_tx,
+	.rx			= dhcp_request_rx,
+	.expired		= dhcp_request_expired,
+	.tx_msgtype		= DHCPREQUEST,
+	.apply_min_timeout	= 0,
+};
+
+/**
+ * Construct transmitted packet for ProxyDHCP request
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		Destination address
+ */
+static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
+			   struct dhcp_packet *dhcppkt,
+			   struct sockaddr_in *peer ) {
+	int rc;
+
+	DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
+	       inet_ntoa ( dhcp->proxy_server ) );
+
+	/* Set server ID */
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+				    &dhcp->proxy_server,
+				    sizeof ( dhcp->proxy_server ) ) ) != 0 )
+		return rc;
+
+	/* Set server address */
+	peer->sin_addr = dhcp->proxy_server;
+	peer->sin_port = htons ( PXE_PORT );
+
+	return 0;
+}
+
+/**
+ * Handle received packet during ProxyDHCP request
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		DHCP server address
+ * @v msgtype		DHCP message type
+ * @v server_id		DHCP server ID
+ */
+static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
+			    struct dhcp_packet *dhcppkt,
+			    struct sockaddr_in *peer, uint8_t msgtype,
+			    struct in_addr server_id ) {
+	struct settings *settings = &dhcppkt->settings;
+	int rc;
+
+	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+	       ntohs ( peer->sin_port ) );
+	if ( server_id.s_addr != peer->sin_addr.s_addr )
+		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+	DBGC ( dhcp, "\n" );
+
+	/* Filter out unacceptable responses */
+	if ( peer->sin_port != ntohs ( PXE_PORT ) )
+		return;
+	if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
+		return;
+	if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
+	     ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
+		return;
+
+	/* Register settings */
+	if ( ( rc = register_settings ( settings, NULL,
+					PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
+		       dhcp, strerror ( rc ) );
+		dhcp_finished ( dhcp, rc );
+		return;
+	}
+
+	/* Terminate DHCP */
+	dhcp_finished ( dhcp, 0 );
+}
+
+/**
+ * Handle timer expiry during ProxyDHCP request
+ *
+ * @v dhcp		DHCP session
+ */
+static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
+	unsigned long elapsed = ( currticks() - dhcp->start );
+
+	/* Give up waiting for ProxyDHCP before we reach the failure point */
+	if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
+		dhcp_finished ( dhcp, 0 );
+		return;
+	}
+
+	/* Retransmit current packet */
+	dhcp_tx ( dhcp );
+}
+
+/** ProxyDHCP request state operations */
+static struct dhcp_session_state dhcp_state_proxy = {
+	.name			= "ProxyDHCP",
+	.tx			= dhcp_proxy_tx,
+	.rx			= dhcp_proxy_rx,
+	.expired		= dhcp_proxy_expired,
+	.tx_msgtype		= DHCPREQUEST,
+	.apply_min_timeout	= 0,
+};
+
+/**
+ * Construct transmitted packet for PXE Boot Server Discovery
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		Destination address
+ */
+static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
+			   struct dhcp_packet *dhcppkt,
+			   struct sockaddr_in *peer ) {
+	struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
+	int rc;
+
+	/* Set server address */
+	peer->sin_addr = *(dhcp->pxe_attempt);
+	peer->sin_port = ( ( peer->sin_addr.s_addr == INADDR_BROADCAST ) ?
+			   htons ( BOOTPS_PORT ) : htons ( PXE_PORT ) );
+
+	DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
+	       dhcp, inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
+	       le16_to_cpu ( dhcp->pxe_type ) );
+
+	/* Set boot menu item */
+	menu_item.type = dhcp->pxe_type;
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
+				    &menu_item, sizeof ( menu_item ) ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Check to see if PXE Boot Server address is acceptable
+ *
+ * @v dhcp		DHCP session
+ * @v bs		Boot Server address
+ * @ret accept		Boot Server is acceptable
+ */
+static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
+			       struct in_addr bs ) {
+	struct in_addr *accept;
+
+	/* Accept if we have no acceptance filter */
+	if ( ! dhcp->pxe_accept )
+		return 1;
+
+	/* Scan through acceptance list */
+	for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
+		if ( accept->s_addr == bs.s_addr )
+			return 1;
+	}
+
+	DBGC ( dhcp, "DHCP %p rejecting server %s\n",
+	       dhcp, inet_ntoa ( bs ) );
+	return 0;
+}
+
+/**
+ * Handle received packet during PXE Boot Server Discovery
+ *
+ * @v dhcp		DHCP session
+ * @v dhcppkt		DHCP packet
+ * @v peer		DHCP server address
+ * @v msgtype		DHCP message type
+ * @v server_id		DHCP server ID
+ */
+static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
+			    struct dhcp_packet *dhcppkt,
+			    struct sockaddr_in *peer, uint8_t msgtype,
+			    struct in_addr server_id ) {
+	struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
+	int rc;
+
+	DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+	       dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+	       ntohs ( peer->sin_port ) );
+	if ( server_id.s_addr != peer->sin_addr.s_addr )
+		DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+	/* Identify boot menu item */
+	dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
+			&menu_item, sizeof ( menu_item ) );
+	if ( menu_item.type )
+		DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
+	DBGC ( dhcp, "\n" );
+
+	/* Filter out unacceptable responses */
+	if ( ( peer->sin_port != htons ( BOOTPS_PORT ) ) &&
+	     ( peer->sin_port != htons ( PXE_PORT ) ) )
+		return;
+	if ( msgtype != DHCPACK )
+		return;
+	if ( menu_item.type != dhcp->pxe_type )
+		return;
+	if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
+					   server_id : peer->sin_addr ) ) )
+		return;
+
+	/* Register settings */
+	if ( ( rc = register_settings ( &dhcppkt->settings, NULL,
+					PXEBS_SETTINGS_NAME ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+		       dhcp, strerror ( rc ) );
+		dhcp_finished ( dhcp, rc );
+		return;
+	}
+
+	/* Terminate DHCP */
+	dhcp_finished ( dhcp, 0 );
+}
+
+/**
+ * Handle timer expiry during PXE Boot Server Discovery
+ *
+ * @v dhcp		DHCP session
+ */
+static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
+	unsigned long elapsed = ( currticks() - dhcp->start );
+
+	/* Give up waiting before we reach the failure point, and fail
+	 * over to the next server in the attempt list
+	 */
+	if ( elapsed > PXEBS_MAX_TIMEOUT ) {
+		dhcp->pxe_attempt++;
+		if ( dhcp->pxe_attempt->s_addr ) {
+			dhcp_set_state ( dhcp, &dhcp_state_pxebs );
+			return;
+		} else {
+			dhcp_finished ( dhcp, -ETIMEDOUT );
+			return;
+		}
+	}
+
+	/* Retransmit current packet */
+	dhcp_tx ( dhcp );
+}
+
+/** PXE Boot Server Discovery state operations */
+static struct dhcp_session_state dhcp_state_pxebs = {
+	.name			= "PXEBS",
+	.tx			= dhcp_pxebs_tx,
+	.rx			= dhcp_pxebs_rx,
+	.expired		= dhcp_pxebs_expired,
+	.tx_msgtype		= DHCPREQUEST,
+	.apply_min_timeout	= 1,
+};
+
+/****************************************************************************
+ *
+ * Packet construction
+ *
+ */
+
+/**
+ * Construct DHCP client hardware address field and broadcast flag
+ *
+ * @v netdev		Network device
+ * @v chaddr		Hardware address buffer
+ * @v flags		Flags to set (or NULL)
+ * @ret hlen		Hardware address length
+ */
+unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
+			   uint16_t *flags ) {
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct dhcphdr *dhcphdr;
+	int rc;
+
+	/* If the link-layer address cannot fit into the chaddr field
+	 * (as is the case for IPoIB) then try using the Ethernet-
+	 * compatible link-layer address.  If we do this, set the
+	 * broadcast flag, since chaddr then does not represent a
+	 * valid link-layer address for the return path.
+	 *
+	 * If we cannot produce an Ethernet-compatible link-layer
+	 * address, try using the hardware address.
+	 *
+	 * If even the hardware address is too large, use an empty
+	 * chaddr field and set the broadcast flag.
+	 *
+	 * This goes against RFC4390, but RFC4390 mandates that we use
+	 * a DHCP client identifier that conforms with RFC4361, which
+	 * we cannot do without either persistent (NIC-independent)
+	 * storage, or by eliminating the hardware address completely
+	 * from the DHCP packet, which seems unfriendly to users.
+	 */
+	if ( ll_protocol->ll_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
+		memcpy ( chaddr, netdev->ll_addr, ll_protocol->ll_addr_len );
+		return ll_protocol->ll_addr_len;
+	}
+	if ( flags )
+		*flags |= htons ( BOOTP_FL_BROADCAST );
+	if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, chaddr ) ) == 0 )
+		return ETH_ALEN;
+	if ( ll_protocol->hw_addr_len <= sizeof ( dhcphdr->chaddr ) ) {
+		memcpy ( chaddr, netdev->hw_addr, ll_protocol->hw_addr_len );
+		return ll_protocol->hw_addr_len;
+	}
+	return 0;
+}
+
+/**
+ * Create a DHCP packet
+ *
+ * @v dhcppkt		DHCP packet structure to fill in
+ * @v netdev		Network device
+ * @v msgtype		DHCP message type
+ * @v options		Initial options to include (or NULL)
+ * @v options_len	Length of initial options
+ * @v data		Buffer for DHCP packet
+ * @v max_len		Size of DHCP packet buffer
+ * @ret rc		Return status code
+ *
+ * Creates a DHCP packet in the specified buffer, and initialise a
+ * DHCP packet structure.
+ */
+int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
+			 struct net_device *netdev, uint8_t msgtype,
+			 const void *options, size_t options_len,
+			 void *data, size_t max_len ) {
+	struct dhcphdr *dhcphdr = data;
+	int rc;
+
+	/* Sanity check */
+	if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
+		return -ENOSPC;
+
+	/* Initialise DHCP packet content */
+	memset ( dhcphdr, 0, max_len );
+	dhcphdr->xid = dhcp_xid ( netdev );
+	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
+	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
+	dhcphdr->op = dhcp_op[msgtype];
+	dhcphdr->hlen = dhcp_chaddr ( netdev, dhcphdr->chaddr,
+				      &dhcphdr->flags );
+	memcpy ( dhcphdr->options, options, options_len );
+
+	/* Initialise DHCP packet structure */
+	memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
+	dhcppkt_init ( dhcppkt, data, max_len );
+	
+	/* Set DHCP_MESSAGE_TYPE option */
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
+				    &msgtype, sizeof ( msgtype ) ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Create DHCP request packet
+ *
+ * @v dhcppkt		DHCP packet structure to fill in
+ * @v netdev		Network device
+ * @v msgtype		DHCP message type
+ * @v ciaddr		Client IP address
+ * @v data		Buffer for DHCP packet
+ * @v max_len		Size of DHCP packet buffer
+ * @ret rc		Return status code
+ *
+ * Creates a DHCP request packet in the specified buffer, and
+ * initialise a DHCP packet structure.
+ */
+int dhcp_create_request ( struct dhcp_packet *dhcppkt,
+			  struct net_device *netdev, unsigned int msgtype,
+			  struct in_addr ciaddr, void *data, size_t max_len ) {
+	struct dhcp_netdev_desc dhcp_desc;
+	struct dhcp_client_id client_id;
+	struct dhcp_client_uuid client_uuid;
+	uint8_t *dhcp_features;
+	size_t dhcp_features_len;
+	size_t ll_addr_len;
+	ssize_t len;
+	int rc;
+
+	/* Create DHCP packet */
+	if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
+					 dhcp_request_options_data,
+					 sizeof ( dhcp_request_options_data ),
+					 data, max_len ) ) != 0 ) {
+		DBG ( "DHCP could not create DHCP packet: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Set client IP address */
+	dhcppkt->dhcphdr->ciaddr = ciaddr;
+
+	/* Add options to identify the feature list */
+	dhcp_features = table_start ( DHCP_FEATURES );
+	dhcp_features_len = table_num_entries ( DHCP_FEATURES );
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
+				    dhcp_features_len ) ) != 0 ) {
+		DBG ( "DHCP could not set features list option: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Add options to identify the network device */
+	fetch_setting ( &netdev->settings.settings, &busid_setting, &dhcp_desc,
+		sizeof ( dhcp_desc ) );
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
+				    sizeof ( dhcp_desc ) ) ) != 0 ) {
+		DBG ( "DHCP could not set bus ID option: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Add DHCP client identifier.  Required for Infiniband, and
+	 * doesn't hurt other link layers.
+	 */
+	client_id.ll_proto = ntohs ( netdev->ll_protocol->ll_proto );
+	ll_addr_len = netdev->ll_protocol->ll_addr_len;
+	assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
+	memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
+	if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
+				    ( ll_addr_len + 1 ) ) ) != 0 ) {
+		DBG ( "DHCP could not set client ID: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
+	/* Add client UUID, if we have one.  Required for PXE. */
+	client_uuid.type = DHCP_CLIENT_UUID_TYPE;
+	if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
+					  &client_uuid.uuid ) ) >= 0 ) {
+		if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
+					    &client_uuid,
+					    sizeof ( client_uuid ) ) ) != 0 ) {
+			DBG ( "DHCP could not set client UUID: %s\n",
+			      strerror ( rc ) );
+			return rc;
+		}
+	}
+
+	/* Add user class, if we have one. */
+	if ( ( len = fetch_setting_len ( NULL, &user_class_setting ) ) >= 0 ) {
+		char user_class[len];
+		fetch_setting ( NULL, &user_class_setting, user_class,
+				sizeof ( user_class ) );
+		if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID,
+					    &user_class,
+					    sizeof ( user_class ) ) ) != 0 ) {
+			DBG ( "DHCP could not set user class: %s\n",
+			      strerror ( rc ) );
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
+/**
+ * Transmit DHCP request
+ *
+ * @v dhcp		DHCP session
+ * @ret rc		Return status code
+ */
+static int dhcp_tx ( struct dhcp_session *dhcp ) {
+	static struct sockaddr_in peer = {
+		.sin_family = AF_INET,
+	};
+	struct xfer_metadata meta = {
+		.netdev = dhcp->netdev,
+		.src = ( struct sockaddr * ) &dhcp->local,
+		.dest = ( struct sockaddr * ) &peer,
+	};
+	struct io_buffer *iobuf;
+	uint8_t msgtype = dhcp->state->tx_msgtype;
+	struct dhcp_packet dhcppkt;
+	int rc;
+
+	/* Start retry timer.  Do this first so that failures to
+	 * transmit will be retried.
+	 */
+	start_timer ( &dhcp->timer );
+
+	/* Allocate buffer for packet */
+	iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Create basic DHCP packet in temporary buffer */
+	if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
+					  dhcp->local.sin_addr, iobuf->data,
+					  iob_tailroom ( iobuf ) ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
+		       dhcp, strerror ( rc ) );
+		goto done;
+	}
+
+	/* (Ab)use the "secs" field to convey metadata about the DHCP
+	 * session state into packet traces.  Useful for extracting
+	 * debug information from non-debug builds.
+	 */
+	dhcppkt.dhcphdr->secs = htons ( ( ++(dhcp->count) << 2 ) |
+					( dhcp->offer.s_addr ? 0x02 : 0 ) |
+					( dhcp->proxy_offer ? 0x01 : 0 ) );
+
+	/* Fill in packet based on current state */
+	if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
+		       dhcp, strerror ( rc ) );
+		goto done;
+	}
+
+	/* Transmit the packet */
+	iob_put ( iobuf, dhcppkt_len ( &dhcppkt ) );
+	if ( ( rc = xfer_deliver ( &dhcp->xfer, iob_disown ( iobuf ),
+				   &meta ) ) != 0 ) {
+		DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
+		       dhcp, strerror ( rc ) );
+		goto done;
+	}
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Receive new data
+ *
+ * @v dhcp		DHCP session
+ * @v iobuf		I/O buffer
+ * @v meta		Transfer metadata
+ * @ret rc		Return status code
+ */
+static int dhcp_deliver ( struct dhcp_session *dhcp,
+			  struct io_buffer *iobuf,
+			  struct xfer_metadata *meta ) {
+	struct sockaddr_in *peer;
+	size_t data_len;
+	struct dhcp_packet *dhcppkt;
+	struct dhcphdr *dhcphdr;
+	uint8_t msgtype = 0;
+	struct in_addr server_id = { 0 };
+	int rc = 0;
+
+	/* Sanity checks */
+	if ( ! meta->src ) {
+		DBGC ( dhcp, "DHCP %p received packet without source port\n",
+		       dhcp );
+		rc = -EINVAL;
+		goto err_no_src;
+	}
+	peer = ( struct sockaddr_in * ) meta->src;
+
+	/* Create a DHCP packet containing the I/O buffer contents.
+	 * Whilst we could just use the original buffer in situ, that
+	 * would waste the unused space in the packet buffer, and also
+	 * waste a relatively scarce fully-aligned I/O buffer.
+	 */
+	data_len = iob_len ( iobuf );
+	dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
+	if ( ! dhcppkt ) {
+		rc = -ENOMEM;
+		goto err_alloc_dhcppkt;
+	}
+	dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
+	memcpy ( dhcphdr, iobuf->data, data_len );
+	dhcppkt_init ( dhcppkt, dhcphdr, data_len );
+
+	/* Identify message type */
+	dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
+			sizeof ( msgtype ) );
+
+	/* Identify server ID */
+	dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+			&server_id, sizeof ( server_id ) );
+
+	/* Check for matching transaction ID */
+	if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
+		DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
+		       "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
+		       inet_ntoa ( peer->sin_addr ),
+		       ntohs ( peer->sin_port ) );
+		rc = -EINVAL;
+		goto err_xid;
+	};
+
+	/* Handle packet based on current state */
+	dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
+
+ err_xid:
+	dhcppkt_put ( dhcppkt );
+ err_alloc_dhcppkt:
+ err_no_src:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** DHCP data transfer interface operations */
+static struct interface_operation dhcp_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct dhcp_session *, dhcp_deliver ),
+};
+
+/** DHCP data transfer interface descriptor */
+static struct interface_descriptor dhcp_xfer_desc =
+	INTF_DESC ( struct dhcp_session, xfer, dhcp_xfer_operations );
+
+/**
+ * Handle DHCP retry timer expiry
+ *
+ * @v timer		DHCP retry timer
+ * @v fail		Failure indicator
+ */
+static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
+	struct dhcp_session *dhcp =
+		container_of ( timer, struct dhcp_session, timer );
+
+	/* If we have failed, terminate DHCP */
+	if ( fail ) {
+		dhcp_finished ( dhcp, -ETIMEDOUT );
+		return;
+	}
+
+	/* Handle timer expiry based on current state */
+	dhcp->state->expired ( dhcp );
+}
+
+/****************************************************************************
+ *
+ * Job control interface
+ *
+ */
+
+/** DHCP job control interface operations */
+static struct interface_operation dhcp_job_op[] = {
+	INTF_OP ( intf_close, struct dhcp_session *, dhcp_finished ),
+};
+
+/** DHCP job control interface descriptor */
+static struct interface_descriptor dhcp_job_desc =
+	INTF_DESC ( struct dhcp_session, job, dhcp_job_op );
+
+/****************************************************************************
+ *
+ * Instantiators
+ *
+ */
+
+/**
+ * DHCP peer address for socket opening
+ *
+ * This is a dummy address; the only useful portion is the socket
+ * family (so that we get a UDP connection).  The DHCP client will set
+ * the IP address and source port explicitly on each transmission.
+ */
+static struct sockaddr dhcp_peer = {
+	.sa_family = AF_INET,
+};
+
+/**
+ * Get cached DHCPACK where none exists
+ */
+__weak void get_cached_dhcpack ( void ) { __keepme }
+
+/**
+ * Start DHCP state machine on a network device
+ *
+ * @v job		Job control interface
+ * @v netdev		Network device
+ * @ret rc		Return status code, or positive if cached
+ *
+ * Starts DHCP on the specified network device.  If successful, the
+ * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as
+ * option sources.
+ *
+ * On a return of 0, a background job has been started to perform the
+ * DHCP request. Any nonzero return means the job has not been
+ * started; a positive return value indicates the success condition of
+ * having fetched the appropriate data from cached information.
+ */
+int start_dhcp ( struct interface *job, struct net_device *netdev ) {
+	struct dhcp_session *dhcp;
+	int rc;
+
+	/* Check for cached DHCP information */
+	get_cached_dhcpack();
+	if ( fetch_uintz_setting ( NULL, &use_cached_setting ) ) {
+		DBG ( "DHCP using cached network settings\n" );
+		return 1;
+	}
+
+	/* Allocate and initialise structure */
+	dhcp = zalloc ( sizeof ( *dhcp ) );
+	if ( ! dhcp )
+		return -ENOMEM;
+	ref_init ( &dhcp->refcnt, dhcp_free );
+	intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
+	intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
+	timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
+	dhcp->netdev = netdev_get ( netdev );
+	dhcp->local.sin_family = AF_INET;
+	dhcp->local.sin_port = htons ( BOOTPC_PORT );
+
+	/* Instantiate child objects and attach to our interfaces */
+	if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
+				  ( struct sockaddr * ) &dhcp->local ) ) != 0 )
+		goto err;
+
+	/* Enter DHCPDISCOVER state */
+	dhcp_set_state ( dhcp, &dhcp_state_discover );
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &dhcp->job, job );
+	ref_put ( &dhcp->refcnt );
+	return 0;
+
+ err:
+	dhcp_finished ( dhcp, rc );
+	ref_put ( &dhcp->refcnt );
+	return rc;
+}
+
+/**
+ * Retrieve list of PXE boot servers for a given server type
+ *
+ * @v dhcp		DHCP session
+ * @v raw		DHCP PXE boot server list
+ * @v raw_len		Length of DHCP PXE boot server list
+ * @v ip		IP address list to fill in
+ *
+ * The caller must ensure that the IP address list has sufficient
+ * space.
+ */
+static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
+			 size_t raw_len, struct in_addr *ip ) {
+	struct dhcp_pxe_boot_server *server = raw;
+	size_t server_len;
+	unsigned int i;
+
+	while ( raw_len ) {
+		if ( raw_len < sizeof ( *server ) ) {
+			DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
+			       dhcp );
+			break;
+		}
+		server_len = offsetof ( typeof ( *server ),
+					ip[ server->num_ip ] );
+		if ( raw_len < server_len ) {
+			DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
+			       dhcp );
+			break;
+		}
+		if ( server->type == dhcp->pxe_type ) {
+			for ( i = 0 ; i < server->num_ip ; i++ )
+				*(ip++) = server->ip[i];
+		}
+		server = ( ( ( void * ) server ) + server_len );
+		raw_len -= server_len;
+	}
+}
+
+/**
+ * Start PXE Boot Server Discovery on a network device
+ *
+ * @v job		Job control interface
+ * @v netdev		Network device
+ * @v pxe_type		PXE server type
+ * @ret rc		Return status code
+ *
+ * Starts PXE Boot Server Discovery on the specified network device.
+ * If successful, the Boot Server ACK will be registered as an option
+ * source.
+ */
+int start_pxebs ( struct interface *job, struct net_device *netdev,
+		  unsigned int pxe_type ) {
+	struct setting pxe_discovery_control_setting =
+		{ .tag = DHCP_PXE_DISCOVERY_CONTROL };
+	struct setting pxe_boot_servers_setting =
+		{ .tag = DHCP_PXE_BOOT_SERVERS };
+	struct setting pxe_boot_server_mcast_setting =
+		{ .tag = DHCP_PXE_BOOT_SERVER_MCAST };
+	ssize_t pxebs_list_len;
+	struct dhcp_session *dhcp;
+	struct in_addr *ip;
+	unsigned int pxe_discovery_control;
+	int rc;
+
+	/* Get upper bound for PXE boot server IP address list */
+	pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
+	if ( pxebs_list_len < 0 )
+		pxebs_list_len = 0;
+
+	/* Allocate and initialise structure */
+	dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
+			sizeof ( *ip ) /* bcast */ + pxebs_list_len +
+			sizeof ( *ip ) /* terminator */ );
+	if ( ! dhcp )
+		return -ENOMEM;
+	ref_init ( &dhcp->refcnt, dhcp_free );
+	intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
+	intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
+	timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
+	dhcp->netdev = netdev_get ( netdev );
+	dhcp->local.sin_family = AF_INET;
+	fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
+			     &dhcp->local.sin_addr );
+	dhcp->local.sin_port = htons ( BOOTPC_PORT );
+	dhcp->pxe_type = cpu_to_le16 ( pxe_type );
+
+	/* Construct PXE boot server IP address lists */
+	pxe_discovery_control =
+		fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
+	ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
+	dhcp->pxe_attempt = ip;
+	if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
+		fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
+		if ( ip->s_addr )
+			ip++;
+	}
+	if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
+		(ip++)->s_addr = INADDR_BROADCAST;
+	if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
+		dhcp->pxe_accept = ip;
+	if ( pxebs_list_len ) {
+		uint8_t buf[pxebs_list_len];
+
+		fetch_setting ( NULL, &pxe_boot_servers_setting,
+				buf, sizeof ( buf ) );
+		pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
+	}
+	if ( ! dhcp->pxe_attempt->s_addr ) {
+		DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
+		       dhcp, pxe_type );
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Dump out PXE server lists */
+	DBGC ( dhcp, "DHCP %p attempting", dhcp );
+	for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
+		DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
+	DBGC ( dhcp, "\n" );
+	if ( dhcp->pxe_accept ) {
+		DBGC ( dhcp, "DHCP %p accepting", dhcp );
+		for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
+			DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
+		DBGC ( dhcp, "\n" );
+	}
+
+	/* Instantiate child objects and attach to our interfaces */
+	if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
+				  ( struct sockaddr * ) &dhcp->local ) ) != 0 )
+		goto err;
+
+	/* Enter PXEBS state */
+	dhcp_set_state ( dhcp, &dhcp_state_pxebs );
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &dhcp->job, job );
+	ref_put ( &dhcp->refcnt );
+	return 0;
+
+ err:
+	dhcp_finished ( dhcp, rc );
+	ref_put ( &dhcp->refcnt );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp/dns.c b/qemu-0.15.x/roms/ipxe/src/net/udp/dns.c
new file mode 100644
index 0000000..d1435e7
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp/dns.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * Portions copyright (C) 2004 Anselm M. Hoffmeister
+ * <stockholm at users.sourceforge.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/resolv.h>
+#include <ipxe/retry.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/settings.h>
+#include <ipxe/features.h>
+#include <ipxe/dns.h>
+
+/** @file
+ *
+ * DNS protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
+
+/* Disambiguate the various error causes */
+#define ENXIO_NO_RECORD __einfo_error ( EINFO_ENXIO_NO_RECORD )
+#define EINFO_ENXIO_NO_RECORD \
+	__einfo_uniqify ( EINFO_ENXIO, 0x01, "DNS name does not exist" )
+#define ENXIO_NO_NAMESERVER __einfo_error ( EINFO_ENXIO_NO_NAMESERVER )
+#define EINFO_ENXIO_NO_NAMESERVER \
+	__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
+
+/** The DNS server */
+static struct sockaddr_tcpip nameserver = {
+	.st_port = htons ( DNS_PORT ),
+};
+
+/** The local domain */
+static char *localdomain;
+
+/** A DNS request */
+struct dns_request {
+	/** Reference counter */
+	struct refcnt refcnt;
+	/** Name resolution interface */
+	struct interface resolv;
+	/** Data transfer interface */
+	struct interface socket;
+	/** Retry timer */
+	struct retry_timer timer;
+
+	/** Socket address to fill in with resolved address */
+	struct sockaddr sa;
+	/** Current query packet */
+	struct dns_query query;
+	/** Location of query info structure within current packet
+	 *
+	 * The query info structure is located immediately after the
+	 * compressed name.
+	 */
+	struct dns_query_info *qinfo;
+	/** Recursion counter */
+	unsigned int recursion;
+};
+
+/**
+ * Mark DNS request as complete
+ *
+ * @v dns		DNS request
+ * @v rc		Return status code
+ */
+static void dns_done ( struct dns_request *dns, int rc ) {
+
+	/* Stop the retry timer */
+	stop_timer ( &dns->timer );
+
+	/* Shut down interfaces */
+	intf_shutdown ( &dns->socket, rc );
+	intf_shutdown ( &dns->resolv, rc );
+}
+
+/**
+ * Compare DNS reply name against the query name from the original request
+ *
+ * @v dns		DNS request
+ * @v reply		DNS reply
+ * @v rname		Reply name
+ * @ret	zero		Names match
+ * @ret non-zero	Names do not match
+ */
+static int dns_name_cmp ( struct dns_request *dns,
+			  const struct dns_header *reply, 
+			  const char *rname ) {
+	const char *qname = dns->query.payload;
+	int i;
+
+	while ( 1 ) {
+		/* Obtain next section of rname */
+		while ( ( *rname ) & 0xc0 ) {
+			rname = ( ( ( char * ) reply ) +
+				  ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
+		}
+		/* Check that lengths match */
+		if ( *rname != *qname )
+			return -1;
+		/* If length is zero, we have reached the end */
+		if ( ! *qname )
+			return 0;
+		/* Check that data matches */
+		for ( i = *qname + 1; i > 0 ; i-- ) {
+			if ( *(rname++) != *(qname++) )
+				return -1;
+		}
+	}
+}
+
+/**
+ * Skip over a (possibly compressed) DNS name
+ *
+ * @v name		DNS name
+ * @ret name		Next DNS name
+ */
+static const char * dns_skip_name ( const char *name ) {
+	while ( 1 ) {
+		if ( ! *name ) {
+			/* End of name */
+			return ( name + 1);
+		}
+		if ( *name & 0xc0 ) {
+			/* Start of a compressed name */
+			return ( name + 2 );
+		}
+		/* Uncompressed name portion */
+		name += *name + 1;
+	}
+}
+
+/**
+ * Find an RR in a reply packet corresponding to our query
+ *
+ * @v dns		DNS request
+ * @v reply		DNS reply
+ * @ret rr		DNS RR, or NULL if not found
+ */
+static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
+					 const struct dns_header *reply ) {
+	int i, cmp;
+	const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
+	union dns_rr_info *rr_info;
+
+	/* Skip over the questions section */
+	for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
+		p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
+	}
+
+	/* Process the answers section */
+	for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
+		cmp = dns_name_cmp ( dns, reply, p );
+		p = dns_skip_name ( p );
+		rr_info = ( ( union dns_rr_info * ) p );
+		if ( cmp == 0 )
+			return rr_info;
+		p += ( sizeof ( rr_info->common ) +
+		       ntohs ( rr_info->common.rdlength ) );
+	}
+
+	return NULL;
+}
+
+/**
+ * Append DHCP domain name if available and name is not fully qualified
+ *
+ * @v string		Name as a NUL-terminated string
+ * @ret fqdn		Fully-qualified domain name, malloc'd copy
+ *
+ * The caller must free fqdn which is allocated even if the name is already
+ * fully qualified.
+ */
+static char * dns_qualify_name ( const char *string ) {
+	char *fqdn;
+
+	/* Leave unchanged if already fully-qualified or no local domain */
+	if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
+		return strdup ( string );
+
+	/* Append local domain to name */
+	asprintf ( &fqdn, "%s.%s", string, localdomain );
+	return fqdn;
+}
+
+/**
+ * Convert a standard NUL-terminated string to a DNS name
+ *
+ * @v string		Name as a NUL-terminated string
+ * @v buf		Buffer in which to place DNS name
+ * @ret next		Byte following constructed DNS name
+ *
+ * DNS names consist of "<length>element" pairs.
+ */
+static char * dns_make_name ( const char *string, char *buf ) {
+	char *length_byte = buf++;
+	char c;
+
+	while ( ( c = *(string++) ) ) {
+		if ( c == '.' ) {
+			*length_byte = buf - length_byte - 1;
+			length_byte = buf;
+		}
+		*(buf++) = c;
+	}
+	*length_byte = buf - length_byte - 1;
+	*(buf++) = '\0';
+	return buf;
+}
+
+/**
+ * Convert an uncompressed DNS name to a NUL-terminated string
+ *
+ * @v name		DNS name
+ * @ret string		NUL-terminated string
+ *
+ * Produce a printable version of a DNS name.  Used only for debugging.
+ */
+static inline char * dns_unmake_name ( char *name ) {
+	char *p;
+	unsigned int len;
+
+	p = name;
+	while ( ( len = *p ) ) {
+		*(p++) = '.';
+		p += len;
+	}
+
+	return name + 1;
+}
+
+/**
+ * Decompress a DNS name
+ *
+ * @v reply		DNS replay
+ * @v name		DNS name
+ * @v buf		Buffer into which to decompress DNS name
+ * @ret next		Byte following decompressed DNS name
+ */
+static char * dns_decompress_name ( const struct dns_header *reply,
+				    const char *name, char *buf ) {
+	int i, len;
+
+	do {
+		/* Obtain next section of name */
+		while ( ( *name ) & 0xc0 ) {
+			name = ( ( char * ) reply +
+				 ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
+		}
+		/* Copy data */
+		len = *name;
+		for ( i = len + 1 ; i > 0 ; i-- ) {
+			*(buf++) = *(name++);
+		}
+	} while ( len );
+	return buf;
+}
+
+/**
+ * Send next packet in DNS request
+ *
+ * @v dns		DNS request
+ */
+static int dns_send_packet ( struct dns_request *dns ) {
+	static unsigned int qid = 0;
+	size_t qlen;
+
+	/* Increment query ID */
+	dns->query.dns.id = htons ( ++qid );
+
+	DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
+
+	/* Start retransmission timer */
+	start_timer ( &dns->timer );
+
+	/* Send the data */
+	qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
+		 + sizeof ( dns->qinfo ) );
+	return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
+}
+
+/**
+ * Handle DNS retransmission timer expiry
+ *
+ * @v timer		Retry timer
+ * @v fail		Failure indicator
+ */
+static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
+	struct dns_request *dns =
+		container_of ( timer, struct dns_request, timer );
+
+	if ( fail ) {
+		dns_done ( dns, -ETIMEDOUT );
+	} else {
+		dns_send_packet ( dns );
+	}
+}
+
+/**
+ * Receive new data
+ *
+ * @v dns		DNS request
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int dns_xfer_deliver ( struct dns_request *dns,
+			      struct io_buffer *iobuf,
+			      struct xfer_metadata *meta __unused ) {
+	const struct dns_header *reply = iobuf->data;
+	union dns_rr_info *rr_info;
+	struct sockaddr_in *sin;
+	unsigned int qtype = dns->qinfo->qtype;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *reply ) ) {
+		DBGC ( dns, "DNS %p received underlength packet length %zd\n",
+		       dns, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Check reply ID matches query ID */
+	if ( reply->id != dns->query.dns.id ) {
+		DBGC ( dns, "DNS %p received unexpected reply ID %d "
+		       "(wanted %d)\n", dns, ntohs ( reply->id ),
+		       ntohs ( dns->query.dns.id ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
+
+	/* Stop the retry timer.  After this point, each code path
+	 * must either restart the timer by calling dns_send_packet(),
+	 * or mark the DNS operation as complete by calling
+	 * dns_done()
+	 */
+	stop_timer ( &dns->timer );
+
+	/* Search through response for useful answers.  Do this
+	 * multiple times, to take advantage of useful nameservers
+	 * which send us e.g. the CNAME *and* the A record for the
+	 * pointed-to name.
+	 */
+	while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
+		switch ( rr_info->common.type ) {
+
+		case htons ( DNS_TYPE_A ):
+
+			/* Found the target A record */
+			DBGC ( dns, "DNS %p found address %s\n",
+			       dns, inet_ntoa ( rr_info->a.in_addr ) );
+			sin = ( struct sockaddr_in * ) &dns->sa;
+			sin->sin_family = AF_INET;
+			sin->sin_addr = rr_info->a.in_addr;
+
+			/* Return resolved address */
+			resolv_done ( &dns->resolv, &dns->sa );
+
+			/* Mark operation as complete */
+			dns_done ( dns, 0 );
+			rc = 0;
+			goto done;
+
+		case htons ( DNS_TYPE_CNAME ):
+
+			/* Found a CNAME record; update query and recurse */
+			DBGC ( dns, "DNS %p found CNAME\n", dns );
+			dns->qinfo = ( void * ) dns_decompress_name ( reply,
+							 rr_info->cname.cname,
+							 dns->query.payload );
+			dns->qinfo->qtype = htons ( DNS_TYPE_A );
+			dns->qinfo->qclass = htons ( DNS_CLASS_IN );
+			
+			/* Terminate the operation if we recurse too far */
+			if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
+				DBGC ( dns, "DNS %p recursion exceeded\n",
+				       dns );
+				dns_done ( dns, -ELOOP );
+				rc = 0;
+				goto done;
+			}
+			break;
+
+		default:
+			DBGC ( dns, "DNS %p got unknown record type %d\n",
+			       dns, ntohs ( rr_info->common.type ) );
+			break;
+		}
+	}
+	
+	/* Determine what to do next based on the type of query we
+	 * issued and the reponse we received
+	 */
+	switch ( qtype ) {
+
+	case htons ( DNS_TYPE_A ):
+		/* We asked for an A record and got nothing;
+		 * try the CNAME.
+		 */
+		DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
+		dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
+		dns_send_packet ( dns );
+		rc = 0;
+		goto done;
+
+	case htons ( DNS_TYPE_CNAME ):
+		/* We asked for a CNAME record.  If we got a response
+		 * (i.e. if the next A query is already set up), then
+		 * issue it, otherwise abort.
+		 */
+		if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
+			dns_send_packet ( dns );
+			rc = 0;
+			goto done;
+		} else {
+			DBGC ( dns, "DNS %p found no CNAME record\n", dns );
+			dns_done ( dns, -ENXIO_NO_RECORD );
+			rc = 0;
+			goto done;
+		}
+
+	default:
+		assert ( 0 );
+		dns_done ( dns, -EINVAL );
+		rc = -EINVAL;
+		goto done;
+	}
+
+ done:
+	/* Free I/O buffer */
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Receive new data
+ *
+ * @v dns		DNS request
+ * @v rc		Reason for close
+ */
+static void dns_xfer_close ( struct dns_request *dns, int rc ) {
+
+	if ( ! rc )
+		rc = -ECONNABORTED;
+
+	dns_done ( dns, rc );
+}
+
+/** DNS socket interface operations */
+static struct interface_operation dns_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct dns_request *, dns_xfer_deliver ),
+	INTF_OP ( intf_close, struct dns_request *, dns_xfer_close ),
+};
+
+/** DNS socket interface descriptor */
+static struct interface_descriptor dns_socket_desc =
+	INTF_DESC ( struct dns_request, socket, dns_socket_operations );
+
+/** DNS resolver interface operations */
+static struct interface_operation dns_resolv_op[] = {
+	INTF_OP ( intf_close, struct dns_request *, dns_done ),
+};
+
+/** DNS resolver interface descriptor */
+static struct interface_descriptor dns_resolv_desc =
+	INTF_DESC ( struct dns_request, resolv, dns_resolv_op );
+
+/**
+ * Resolve name using DNS
+ *
+ * @v resolv		Name resolution interface
+ * @v name		Name to resolve
+ * @v sa		Socket address to fill in
+ * @ret rc		Return status code
+ */
+static int dns_resolv ( struct interface *resolv,
+			const char *name, struct sockaddr *sa ) {
+	struct dns_request *dns;
+	char *fqdn;
+	int rc;
+
+	/* Fail immediately if no DNS servers */
+	if ( ! nameserver.st_family ) {
+		DBG ( "DNS not attempting to resolve \"%s\": "
+		      "no DNS servers\n", name );
+		rc = -ENXIO_NO_NAMESERVER;
+		goto err_no_nameserver;
+	}
+
+	/* Ensure fully-qualified domain name if DHCP option was given */
+	fqdn = dns_qualify_name ( name );
+	if ( ! fqdn ) {
+		rc = -ENOMEM;
+		goto err_qualify_name;
+	}
+
+	/* Allocate DNS structure */
+	dns = zalloc ( sizeof ( *dns ) );
+	if ( ! dns ) {
+		rc = -ENOMEM;
+		goto err_alloc_dns;
+	}
+	ref_init ( &dns->refcnt, NULL );
+	intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
+	intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
+	timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt );
+	memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
+
+	/* Create query */
+	dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
+				       DNS_FLAG_RD );
+	dns->query.dns.qdcount = htons ( 1 );
+	dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
+	dns->qinfo->qtype = htons ( DNS_TYPE_A );
+	dns->qinfo->qclass = htons ( DNS_CLASS_IN );
+
+	/* Open UDP connection */
+	if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
+				       ( struct sockaddr * ) &nameserver,
+				       NULL ) ) != 0 ) {
+		DBGC ( dns, "DNS %p could not open socket: %s\n",
+		       dns, strerror ( rc ) );
+		goto err_open_socket;
+	}
+
+	/* Send first DNS packet */
+	dns_send_packet ( dns );
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &dns->resolv, resolv );
+	ref_put ( &dns->refcnt );
+	free ( fqdn );
+	return 0;	
+
+ err_open_socket:
+ err_alloc_dns:
+	ref_put ( &dns->refcnt );
+ err_qualify_name:
+	free ( fqdn );
+ err_no_nameserver:
+	return rc;
+}
+
+/** DNS name resolver */
+struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
+	.name = "DNS",
+	.resolv = dns_resolv,
+};
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** DNS server setting */
+struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
+	.name = "dns",
+	.description = "DNS server",
+	.tag = DHCP_DNS_SERVERS,
+	.type = &setting_type_ipv4,
+};
+
+/** Domain name setting */
+struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = {
+	.name = "domain",
+	.description = "DNS domain",
+	.tag = DHCP_DOMAIN_NAME,
+	.type = &setting_type_string,
+};
+
+/**
+ * Apply DNS settings
+ *
+ * @ret rc		Return status code
+ */
+static int apply_dns_settings ( void ) {
+	struct sockaddr_in *sin_nameserver =
+		( struct sockaddr_in * ) &nameserver;
+	int len;
+
+	/* Fetch DNS server address */
+	nameserver.st_family = 0;
+	if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
+					  &sin_nameserver->sin_addr ) ) >= 0 ){
+		nameserver.st_family = AF_INET;
+		DBG ( "DNS using nameserver %s\n",
+		      inet_ntoa ( sin_nameserver->sin_addr ) );
+	}
+
+	/* Get local domain DHCP option */
+	free ( localdomain );
+	if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
+						 &localdomain ) ) < 0 ) {
+		DBG ( "DNS could not fetch local domain: %s\n",
+		      strerror ( len ) );
+	}
+	if ( localdomain )
+		DBG ( "DNS local domain %s\n", localdomain );
+
+	return 0;
+}
+
+/** DNS settings applicator */
+struct settings_applicator dns_applicator __settings_applicator = {
+	.apply = apply_dns_settings,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp/slam.c b/qemu-0.15.x/roms/ipxe/src/net/udp/slam.c
new file mode 100644
index 0000000..0de138c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp/slam.c
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/features.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/bitmap.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/timer.h>
+#include <ipxe/retry.h>
+
+/** @file
+ *
+ * Scalable Local Area Multicast protocol
+ *
+ * The SLAM protocol is supported only by Etherboot; it was designed
+ * and implemented by Eric Biederman.  A server implementation is
+ * available in contrib/mini-slamd.  There does not appear to be any
+ * documentation beyond a few sparse comments in Etherboot's
+ * proto_slam.c.
+ *
+ * SLAM packets use three types of data field:
+ *
+ *  Nul : A single NUL (0) byte, used as a list terminator
+ *
+ *  Raw : A block of raw data
+ *
+ *  Int : A variable-length integer, in big-endian order.  The length
+ *        of the integer is encoded in the most significant three bits.
+ *
+ * Packets received by the client have the following layout:
+ *
+ *  Int : Transaction identifier.  This is an opaque value.
+ *
+ *  Int : Total number of bytes in the transfer.
+ *
+ *  Int : Block size, in bytes.
+ *
+ *  Int : Packet sequence number within the transfer (if this packet
+ *        contains data).
+ *
+ *  Raw : Packet data (if this packet contains data).
+ *
+ * Packets transmitted by the client consist of a run-length-encoded
+ * representation of the received-blocks bitmap, looking something
+ * like:
+ *
+ *  Int : Number of consecutive successfully-received packets
+ *  Int : Number of consecutive missing packets
+ *  Int : Number of consecutive successfully-received packets
+ *  Int : Number of consecutive missing packets
+ *  ....
+ *  Nul
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "SLAM", DHCP_EB_FEATURE_SLAM, 1 );
+
+/** Default SLAM server port */
+#define SLAM_DEFAULT_PORT 10000
+
+/** Default SLAM multicast IP address */
+#define SLAM_DEFAULT_MULTICAST_IP \
+	( ( 239 << 24 ) | ( 255 << 16 ) | ( 1 << 8 ) | ( 1 << 0 ) )
+
+/** Default SLAM multicast port */
+#define SLAM_DEFAULT_MULTICAST_PORT 10000
+
+/** Maximum SLAM header length */
+#define SLAM_MAX_HEADER_LEN ( 7 /* transaction id */ + 7 /* total_bytes */ + \
+			      7 /* block_size */ )
+
+/** Maximum number of blocks to request per NACK
+ *
+ * This is a policy decision equivalent to selecting a TCP window
+ * size.
+ */
+#define SLAM_MAX_BLOCKS_PER_NACK 4
+
+/** Maximum SLAM NACK length
+ *
+ * We only ever send a NACK for a single range of up to @c
+ * SLAM_MAX_BLOCKS_PER_NACK blocks.
+ */
+#define SLAM_MAX_NACK_LEN ( 7 /* block */ + 7 /* #blocks */ + 1 /* NUL */ )
+
+/** SLAM slave timeout */
+#define SLAM_SLAVE_TIMEOUT ( 1 * TICKS_PER_SEC )
+
+/** A SLAM request */
+struct slam_request {
+	/** Reference counter */
+	struct refcnt refcnt;
+
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Unicast socket */
+	struct interface socket;
+	/** Multicast socket */
+	struct interface mc_socket;
+
+	/** Master client retry timer */
+	struct retry_timer master_timer;
+	/** Slave client retry timer */
+	struct retry_timer slave_timer;
+
+	/** Cached header */
+	uint8_t header[SLAM_MAX_HEADER_LEN];
+	/** Size of cached header */
+	size_t header_len;
+	/** Total number of bytes in transfer */
+	unsigned long total_bytes;
+	/** Transfer block size */
+	unsigned long block_size;
+	/** Number of blocks in transfer */
+	unsigned long num_blocks;
+	/** Block bitmap */
+	struct bitmap bitmap;
+	/** NACK sent flag */
+	int nack_sent;
+};
+
+/**
+ * Free a SLAM request
+ *
+ * @v refcnt		Reference counter
+ */
+static void slam_free ( struct refcnt *refcnt ) {
+	struct slam_request *slam =
+		container_of ( refcnt, struct slam_request, refcnt );
+
+	bitmap_free ( &slam->bitmap );
+	free ( slam );
+}
+
+/**
+ * Mark SLAM request as complete
+ *
+ * @v slam		SLAM request
+ * @v rc		Return status code
+ */
+static void slam_finished ( struct slam_request *slam, int rc ) {
+	static const uint8_t slam_disconnect[] = { 0 };
+
+	DBGC ( slam, "SLAM %p finished with status code %d (%s)\n",
+	       slam, rc, strerror ( rc ) );
+
+	/* Send a disconnect message if we ever sent anything to the
+	 * server.
+	 */
+	if ( slam->nack_sent ) {
+		xfer_deliver_raw ( &slam->socket, slam_disconnect,
+				   sizeof ( slam_disconnect ) );
+	}
+
+	/* Stop the retry timers */
+	stop_timer ( &slam->master_timer );
+	stop_timer ( &slam->slave_timer );
+
+	/* Close all data transfer interfaces */
+	intf_shutdown ( &slam->socket, rc );
+	intf_shutdown ( &slam->mc_socket, rc );
+	intf_shutdown ( &slam->xfer, rc );
+}
+
+/****************************************************************************
+ *
+ * TX datapath
+ *
+ */
+
+/**
+ * Add a variable-length value to a SLAM packet
+ *
+ * @v slam		SLAM request
+ * @v iobuf		I/O buffer
+ * @v value		Value to add
+ * @ret rc		Return status code
+ *
+ * Adds a variable-length value to the end of an I/O buffer.  Will
+ * always leave at least one byte of tailroom in the I/O buffer (to
+ * allow space for the terminating NUL).
+ */
+static int slam_put_value ( struct slam_request *slam,
+			    struct io_buffer *iobuf, unsigned long value ) {
+	uint8_t *data;
+	size_t len;
+	unsigned int i;
+
+	/* Calculate variable length required to store value.  Always
+	 * leave at least one byte in the I/O buffer.
+	 */
+	len = ( ( flsl ( value ) + 10 ) / 8 );
+	if ( len >= iob_tailroom ( iobuf ) ) {
+		DBGC2 ( slam, "SLAM %p cannot add %zd-byte value\n",
+			slam, len );
+		return -ENOBUFS;
+	}
+	/* There is no valid way within the protocol that we can end
+	 * up trying to push a full-sized long (i.e. without space for
+	 * the length encoding).
+	 */
+	assert ( len <= sizeof ( value ) );
+
+	/* Add value */
+	data = iob_put ( iobuf, len );
+	for ( i = len ; i-- ; ) {
+		data[i] = value;
+		value >>= 8;
+	}
+	*data |= ( len << 5 );
+	assert ( value == 0 );
+
+	return 0;
+}
+
+/**
+ * Send SLAM NACK packet
+ *
+ * @v slam		SLAM request
+ * @ret rc		Return status code
+ */
+static int slam_tx_nack ( struct slam_request *slam ) {
+	struct io_buffer *iobuf;
+	unsigned long first_block;
+	unsigned long num_blocks;
+	uint8_t *nul;
+	int rc;
+
+	/* Mark NACK as sent, so that we know we have to disconnect later */
+	slam->nack_sent = 1;
+
+	/* Allocate I/O buffer */
+	iobuf = xfer_alloc_iob ( &slam->socket,	SLAM_MAX_NACK_LEN );
+	if ( ! iobuf ) {
+		DBGC ( slam, "SLAM %p could not allocate I/O buffer\n",
+		       slam );
+		return -ENOMEM;
+	}
+
+	/* Construct NACK.  We always request only a single packet;
+	 * this allows us to force multicast-TFTP-style flow control
+	 * on the SLAM server, which will otherwise just blast the
+	 * data out as fast as it can.  On a gigabit network, without
+	 * RX checksumming, this would inevitably cause packet drops.
+	 */
+	first_block = bitmap_first_gap ( &slam->bitmap );
+	for ( num_blocks = 1 ; ; num_blocks++ ) {
+		if ( num_blocks >= SLAM_MAX_BLOCKS_PER_NACK )
+			break;
+		if ( ( first_block + num_blocks ) >= slam->num_blocks )
+			break;
+		if ( bitmap_test ( &slam->bitmap,
+				   ( first_block + num_blocks ) ) )
+			break;
+	}
+	if ( first_block ) {
+		DBGCP ( slam, "SLAM %p transmitting NACK for blocks "
+			"%ld-%ld\n", slam, first_block,
+			( first_block + num_blocks - 1 ) );
+	} else {
+		DBGC ( slam, "SLAM %p transmitting initial NACK for blocks "
+		       "0-%ld\n", slam, ( num_blocks - 1 ) );
+	}
+	if ( ( rc = slam_put_value ( slam, iobuf, first_block ) ) != 0 )
+		return rc;
+	if ( ( rc = slam_put_value ( slam, iobuf, num_blocks ) ) != 0 )
+		return rc;
+	nul = iob_put ( iobuf, 1 );
+	*nul = 0;
+
+	/* Transmit packet */
+	return xfer_deliver_iob ( &slam->socket, iobuf );
+}
+
+/**
+ * Handle SLAM master client retry timer expiry
+ *
+ * @v timer		Master retry timer
+ * @v fail		Failure indicator
+ */
+static void slam_master_timer_expired ( struct retry_timer *timer,
+					int fail ) {
+	struct slam_request *slam =
+		container_of ( timer, struct slam_request, master_timer );
+
+	if ( fail ) {
+		/* Allow timer to stop running.  We will terminate the
+		 * connection only if the slave timer times out.
+		 */
+		DBGC ( slam, "SLAM %p giving up acting as master client\n",
+		       slam );
+	} else {
+		/* Retransmit NACK */
+		start_timer ( timer );
+		slam_tx_nack ( slam );
+	}
+}
+
+/**
+ * Handle SLAM slave client retry timer expiry
+ *
+ * @v timer		Master retry timer
+ * @v fail		Failure indicator
+ */
+static void slam_slave_timer_expired ( struct retry_timer *timer,
+					int fail ) {
+	struct slam_request *slam =
+		container_of ( timer, struct slam_request, slave_timer );
+
+	if ( fail ) {
+		/* Terminate connection */
+		slam_finished ( slam, -ETIMEDOUT );
+	} else {
+		/* Try sending a NACK */
+		DBGC ( slam, "SLAM %p trying to become master client\n",
+		       slam );
+		start_timer ( timer );
+		slam_tx_nack ( slam );
+	}
+}
+
+/****************************************************************************
+ *
+ * RX datapath
+ *
+ */
+
+/**
+ * Read and strip a variable-length value from a SLAM packet
+ *
+ * @v slam		SLAM request
+ * @v iobuf		I/O buffer
+ * @v value		Value to fill in, or NULL to ignore value
+ * @ret rc		Return status code
+ *
+ * Reads a variable-length value from the start of the I/O buffer.  
+ */
+static int slam_pull_value ( struct slam_request *slam,
+			     struct io_buffer *iobuf,
+			     unsigned long *value ) {
+	uint8_t *data;
+	size_t len;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) == 0 ) {
+		DBGC ( slam, "SLAM %p empty value\n", slam );
+		return -EINVAL;
+	}
+
+	/* Read and verify length of value */
+	data = iobuf->data;
+	len = ( *data >> 5 );
+	if ( ( len == 0 ) ||
+	     ( value && ( len > sizeof ( *value ) ) ) ) {
+		DBGC ( slam, "SLAM %p invalid value length %zd bytes\n",
+		       slam, len );
+		return -EINVAL;
+	}
+	if ( len > iob_len ( iobuf ) ) {
+		DBGC ( slam, "SLAM %p value extends beyond I/O buffer\n",
+		       slam );
+		return -EINVAL;
+	}
+
+	/* Read value */
+	iob_pull ( iobuf, len );
+	*value = ( *data & 0x1f );
+	while ( --len ) {
+		*value <<= 8;
+		*value |= *(++data);
+	}
+
+	return 0;
+}
+
+/**
+ * Read and strip SLAM header
+ *
+ * @v slam		SLAM request
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int slam_pull_header ( struct slam_request *slam,
+			      struct io_buffer *iobuf ) {
+	void *header = iobuf->data;
+	int rc;
+
+	/* If header matches cached header, just pull it and return */
+	if ( ( slam->header_len <= iob_len ( iobuf ) ) &&
+	     ( memcmp ( slam->header, iobuf->data, slam->header_len ) == 0 )){
+		iob_pull ( iobuf, slam->header_len );
+		return 0;
+	}
+
+	DBGC ( slam, "SLAM %p detected changed header; resetting\n", slam );
+
+	/* Read and strip transaction ID, total number of bytes, and
+	 * block size.
+	 */
+	if ( ( rc = slam_pull_value ( slam, iobuf, NULL ) ) != 0 )
+		return rc;
+	if ( ( rc = slam_pull_value ( slam, iobuf,
+				      &slam->total_bytes ) ) != 0 )
+		return rc;
+	if ( ( rc = slam_pull_value ( slam, iobuf,
+				      &slam->block_size ) ) != 0 )
+		return rc;
+
+	/* Update the cached header */
+	slam->header_len = ( iobuf->data - header );
+	assert ( slam->header_len <= sizeof ( slam->header ) );
+	memcpy ( slam->header, header, slam->header_len );
+
+	/* Calculate number of blocks */
+	slam->num_blocks = ( ( slam->total_bytes + slam->block_size - 1 ) /
+			     slam->block_size );
+
+	DBGC ( slam, "SLAM %p has total bytes %ld, block size %ld, num "
+	       "blocks %ld\n", slam, slam->total_bytes, slam->block_size,
+	       slam->num_blocks );
+
+	/* Discard and reset the bitmap */
+	bitmap_free ( &slam->bitmap );
+	memset ( &slam->bitmap, 0, sizeof ( slam->bitmap ) );
+
+	/* Allocate a new bitmap */
+	if ( ( rc = bitmap_resize ( &slam->bitmap,
+				    slam->num_blocks ) ) != 0 ) {
+		/* Failure to allocate a bitmap is fatal */
+		DBGC ( slam, "SLAM %p could not allocate bitmap for %ld "
+		       "blocks: %s\n", slam, slam->num_blocks,
+		       strerror ( rc ) );
+		slam_finished ( slam, rc );
+		return rc;
+	}
+
+	/* Notify recipient of file size */
+	xfer_seek ( &slam->xfer, slam->total_bytes );
+
+	return 0;
+}
+
+/**
+ * Receive SLAM data packet
+ *
+ * @v slam		SLAM request
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int slam_mc_socket_deliver ( struct slam_request *slam,
+				    struct io_buffer *iobuf,
+				    struct xfer_metadata *rx_meta __unused ) {
+	struct xfer_metadata meta;
+	unsigned long packet;
+	size_t len;
+	int rc;
+
+	/* Stop the master client timer.  Restart the slave client timer. */
+	stop_timer ( &slam->master_timer );
+	stop_timer ( &slam->slave_timer );
+	start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT );
+
+	/* Read and strip packet header */
+	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
+		goto err_discard;
+
+	/* Read and strip packet number */
+	if ( ( rc = slam_pull_value ( slam, iobuf, &packet ) ) != 0 )
+		goto err_discard;
+
+	/* Sanity check packet number */
+	if ( packet >= slam->num_blocks ) {
+		DBGC ( slam, "SLAM %p received out-of-range packet %ld "
+		       "(num_blocks=%ld)\n", slam, packet, slam->num_blocks );
+		rc = -EINVAL;
+		goto err_discard;
+	}
+
+	/* Sanity check length */
+	len = iob_len ( iobuf );
+	if ( len > slam->block_size ) {
+		DBGC ( slam, "SLAM %p received oversize packet of %zd bytes "
+		       "(block_size=%ld)\n", slam, len, slam->block_size );
+		rc = -EINVAL;
+		goto err_discard;
+	}
+	if ( ( packet != ( slam->num_blocks - 1 ) ) &&
+	     ( len < slam->block_size ) ) {
+		DBGC ( slam, "SLAM %p received short packet of %zd bytes "
+		       "(block_size=%ld)\n", slam, len, slam->block_size );
+		rc = -EINVAL;
+		goto err_discard;
+	}
+
+	/* If we have already seen this packet, discard it */
+	if ( bitmap_test ( &slam->bitmap, packet ) ) {
+		goto discard;
+	}
+
+	/* Pass to recipient */
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = XFER_FL_ABS_OFFSET;
+	meta.offset = ( packet * slam->block_size );
+	if ( ( rc = xfer_deliver ( &slam->xfer, iobuf, &meta ) ) != 0 )
+		goto err;
+
+	/* Mark block as received */
+	bitmap_set ( &slam->bitmap, packet );
+
+	/* If we have received all blocks, terminate */
+	if ( bitmap_full ( &slam->bitmap ) )
+		slam_finished ( slam, 0 );
+
+	return 0;
+
+ err_discard:
+ discard:
+	free_iob ( iobuf );
+ err:
+	return rc;
+}
+
+/**
+ * Receive SLAM non-data packet
+ *
+ * @v slam		SLAM request
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int slam_socket_deliver ( struct slam_request *slam,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *rx_meta __unused ) {
+	int rc;
+
+	/* Restart the master client timer */
+	stop_timer ( &slam->master_timer );
+	start_timer ( &slam->master_timer );
+
+	/* Read and strip packet header */
+	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
+		goto discard;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) != 0 ) {
+		DBGC ( slam, "SLAM %p received trailing garbage:\n", slam );
+		DBGC_HD ( slam, iobuf->data, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto discard;
+	}
+
+	/* Discard packet */
+	free_iob ( iobuf );
+
+	/* Send NACK in reply */
+	slam_tx_nack ( slam );
+
+	return 0;
+
+ discard:
+	free_iob ( iobuf );
+	return rc;
+
+}
+
+/** SLAM unicast socket interface operations */
+static struct interface_operation slam_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct slam_request *, slam_socket_deliver ),
+	INTF_OP ( intf_close, struct slam_request *, slam_finished ),
+};
+
+/** SLAM unicast socket interface descriptor */
+static struct interface_descriptor slam_socket_desc =
+	INTF_DESC ( struct slam_request, socket, slam_socket_operations );
+
+/** SLAM multicast socket interface operations */
+static struct interface_operation slam_mc_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct slam_request *, slam_mc_socket_deliver ),
+	INTF_OP ( intf_close, struct slam_request *, slam_finished ),
+};
+
+/** SLAM multicast socket interface descriptor */
+static struct interface_descriptor slam_mc_socket_desc =
+	INTF_DESC ( struct slam_request, mc_socket, slam_mc_socket_operations );
+
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
+/** SLAM data transfer interface operations */
+static struct interface_operation slam_xfer_operations[] = {
+	INTF_OP ( intf_close, struct slam_request *, slam_finished ),
+};
+
+/** SLAM data transfer interface descriptor */
+static struct interface_descriptor slam_xfer_desc =
+	INTF_DESC ( struct slam_request, xfer, slam_xfer_operations );
+
+/**
+ * Parse SLAM URI multicast address
+ *
+ * @v slam		SLAM request
+ * @v path		Path portion of x-slam:// URI
+ * @v address		Socket address to fill in
+ * @ret rc		Return status code
+ */
+static int slam_parse_multicast_address ( struct slam_request *slam,
+					  const char *path,
+					  struct sockaddr_in *address ) {
+	char path_dup[ strlen ( path ) /* no +1 */ ];
+	char *sep;
+	char *end;
+
+	/* Create temporary copy of path, minus the leading '/' */
+	assert ( *path == '/' );
+	memcpy ( path_dup, ( path + 1 ) , sizeof ( path_dup ) );
+
+	/* Parse port, if present */
+	sep = strchr ( path_dup, ':' );
+	if ( sep ) {
+		*(sep++) = '\0';
+		address->sin_port = htons ( strtoul ( sep, &end, 0 ) );
+		if ( *end != '\0' ) {
+			DBGC ( slam, "SLAM %p invalid multicast port "
+			       "\"%s\"\n", slam, sep );
+			return -EINVAL;
+		}
+	}
+
+	/* Parse address */
+	if ( inet_aton ( path_dup, &address->sin_addr ) == 0 ) {
+		DBGC ( slam, "SLAM %p invalid multicast address \"%s\"\n",
+		       slam, path_dup );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Initiate a SLAM request
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int slam_open ( struct interface *xfer, struct uri *uri ) {
+	static const struct sockaddr_in default_multicast = {
+		.sin_family = AF_INET,
+		.sin_port = htons ( SLAM_DEFAULT_MULTICAST_PORT ),
+		.sin_addr = { htonl ( SLAM_DEFAULT_MULTICAST_IP ) },
+	};
+	struct slam_request *slam;
+	struct sockaddr_tcpip server;
+	struct sockaddr_in multicast;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! uri->host )
+		return -EINVAL;
+
+	/* Allocate and populate structure */
+	slam = zalloc ( sizeof ( *slam ) );
+	if ( ! slam )
+		return -ENOMEM;
+	ref_init ( &slam->refcnt, slam_free );
+	intf_init ( &slam->xfer, &slam_xfer_desc, &slam->refcnt );
+	intf_init ( &slam->socket, &slam_socket_desc, &slam->refcnt );
+	intf_init ( &slam->mc_socket, &slam_mc_socket_desc, &slam->refcnt );
+	timer_init ( &slam->master_timer, slam_master_timer_expired,
+		     &slam->refcnt );
+	timer_init ( &slam->slave_timer, slam_slave_timer_expired,
+		     &slam->refcnt );
+	/* Fake an invalid cached header of { 0x00, ... } */
+	slam->header_len = 1;
+	/* Fake parameters for initial NACK */
+	slam->num_blocks = 1;
+	if ( ( rc = bitmap_resize ( &slam->bitmap, 1 ) ) != 0 ) {
+		DBGC ( slam, "SLAM %p could not allocate initial bitmap: "
+		       "%s\n", slam, strerror ( rc ) );
+		goto err;
+	}
+
+	/* Open unicast socket */
+	memset ( &server, 0, sizeof ( server ) );
+	server.st_port = htons ( uri_port ( uri, SLAM_DEFAULT_PORT ) );
+	if ( ( rc = xfer_open_named_socket ( &slam->socket, SOCK_DGRAM,
+					     ( struct sockaddr * ) &server,
+					     uri->host, NULL ) ) != 0 ) {
+		DBGC ( slam, "SLAM %p could not open unicast socket: %s\n",
+		       slam, strerror ( rc ) );
+		goto err;
+	}
+
+	/* Open multicast socket */
+	memcpy ( &multicast, &default_multicast, sizeof ( multicast ) );
+	if ( uri->path && 
+	     ( ( rc = slam_parse_multicast_address ( slam, uri->path,
+						     &multicast ) ) != 0 ) ) {
+		goto err;
+	}
+	if ( ( rc = xfer_open_socket ( &slam->mc_socket, SOCK_DGRAM,
+				 ( struct sockaddr * ) &multicast,
+				 ( struct sockaddr * ) &multicast ) ) != 0 ) {
+		DBGC ( slam, "SLAM %p could not open multicast socket: %s\n",
+		       slam, strerror ( rc ) );
+		goto err;
+	}
+
+	/* Start slave retry timer */
+	start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT );
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &slam->xfer, xfer );
+	ref_put ( &slam->refcnt );
+	return 0;
+
+ err:
+	slam_finished ( slam, rc );
+	ref_put ( &slam->refcnt );
+	return rc;
+}
+
+/** SLAM URI opener */
+struct uri_opener slam_uri_opener __uri_opener = {
+	.scheme	= "x-slam",
+	.open	= slam_open,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp/syslog.c b/qemu-0.15.x/roms/ipxe/src/net/udp/syslog.c
new file mode 100644
index 0000000..6d9fc21
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp/syslog.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Syslog protocol
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/console.h>
+#include <ipxe/ansiesc.h>
+#include <ipxe/syslog.h>
+
+/** The syslog server */
+static struct sockaddr_tcpip logserver = {
+	.st_port = htons ( SYSLOG_PORT ),
+};
+
+/** Syslog UDP interface operations */
+static struct interface_operation syslogger_operations[] = {};
+
+/** Syslog UDP interface descriptor */
+static struct interface_descriptor syslogger_desc =
+	INTF_DESC_PURE ( syslogger_operations );
+
+/** The syslog UDP interface */
+static struct interface syslogger = INTF_INIT ( syslogger_desc );
+
+/******************************************************************************
+ *
+ * Console driver
+ *
+ ******************************************************************************
+ */
+
+/** Syslog line buffer */
+static char syslog_buffer[SYSLOG_BUFSIZE];
+
+/** Index into syslog line buffer */
+static unsigned int syslog_idx;
+
+/** Syslog recursion marker */
+static int syslog_entered;
+
+/** Syslog ANSI escape sequence handlers */
+static struct ansiesc_handler syslog_ansiesc_handlers[] = {
+	{ 0, NULL }
+};
+
+/** Syslog ANSI escape sequence context */
+static struct ansiesc_context syslog_ansiesc_ctx = {
+	.handlers = syslog_ansiesc_handlers,
+};
+
+/**
+ * Print a character to syslog console
+ *
+ * @v character		Character to be printed
+ */
+static void syslog_putchar ( int character ) {
+	int rc;
+
+	/* Do nothing if we have no log server */
+	if ( ! logserver.st_family )
+		return;
+
+	/* Ignore if we are already mid-logging */
+	if ( syslog_entered )
+		return;
+
+	/* Strip ANSI escape sequences */
+	character = ansiesc_process ( &syslog_ansiesc_ctx, character );
+	if ( character < 0 )
+		return;
+
+	/* Ignore carriage return */
+	if ( character == '\r' )
+		return;
+
+	/* Treat newline as a terminator */
+	if ( character == '\n' )
+		character = 0;
+
+	/* Add character to buffer */
+	syslog_buffer[syslog_idx++] = character;
+
+	/* Do nothing more unless we reach end-of-line (or end-of-buffer) */
+	if ( ( character != 0 ) &&
+	     ( syslog_idx < ( sizeof ( syslog_buffer ) - 1 /* NUL */ ) ) ) {
+		return;
+	}
+
+	/* Reset to start of buffer */
+	syslog_idx = 0;
+
+	/* Guard against re-entry */
+	syslog_entered = 1;
+
+	/* Send log message */
+	if ( ( rc = xfer_printf ( &syslogger, "<%d>ipxe: %s",
+				  SYSLOG_PRIORITY ( SYSLOG_FACILITY,
+						    SYSLOG_SEVERITY ),
+				  syslog_buffer ) ) != 0 ) {
+		DBG ( "SYSLOG could not send log message: %s\n",
+		      strerror ( rc ) );
+	}
+
+	/* Clear re-entry flag */
+	syslog_entered = 0;
+}
+
+/** Syslog console driver */
+struct console_driver syslog_console __console_driver = {
+	.putchar = syslog_putchar,
+};
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** Syslog server setting */
+struct setting syslog_setting __setting ( SETTING_MISC ) = {
+	.name = "syslog",
+	.description = "Syslog server",
+	.tag = DHCP_LOG_SERVERS,
+	.type = &setting_type_ipv4,
+};
+
+/**
+ * Apply syslog settings
+ *
+ * @ret rc		Return status code
+ */
+static int apply_syslog_settings ( void ) {
+	struct sockaddr_in *sin_logserver =
+		( struct sockaddr_in * ) &logserver;
+	struct in_addr old_addr;
+	int len;
+	int rc;
+
+	/* Fetch log server */
+	old_addr.s_addr = sin_logserver->sin_addr.s_addr;
+	logserver.st_family = 0;
+	if ( ( len = fetch_ipv4_setting ( NULL, &syslog_setting,
+					  &sin_logserver->sin_addr ) ) >= 0 ) {
+		sin_logserver->sin_family = AF_INET;
+	}
+
+	/* Do nothing unless log server has changed */
+	if ( sin_logserver->sin_addr.s_addr == old_addr.s_addr )
+		return 0;
+
+	/* Reset syslog connection */
+	intf_restart ( &syslogger, 0 );
+
+	/* Do nothing unless we have a log server */
+	if ( ! logserver.st_family ) {
+		DBG ( "SYSLOG has no log server\n" );
+		return 0;
+	}
+
+	/* Connect to log server */
+	if ( ( rc = xfer_open_socket ( &syslogger, SOCK_DGRAM,
+				       ( ( struct sockaddr * ) &logserver ),
+				       NULL ) ) != 0 ) {
+		DBG ( "SYSLOG cannot connect to log server: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+	DBG ( "SYSLOG using log server %s\n",
+	      inet_ntoa ( sin_logserver->sin_addr ) );
+
+	return 0;
+}
+
+/** Syslog settings applicator */
+struct settings_applicator syslog_applicator __settings_applicator = {
+	.apply = apply_syslog_settings,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/udp/tftp.c b/qemu-0.15.x/roms/ipxe/src/net/udp/tftp.c
new file mode 100644
index 0000000..7cd211e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/udp/tftp.c
@@ -0,0 +1,1267 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/retry.h>
+#include <ipxe/features.h>
+#include <ipxe/bitmap.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/uri.h>
+#include <ipxe/tftp.h>
+
+/** @file
+ *
+ * TFTP protocol
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
+
+/* TFTP-specific error codes */
+#define EINVAL_BLKSIZE 	__einfo_error ( EINFO_EINVAL_BLKSIZE )
+#define EINFO_EINVAL_BLKSIZE __einfo_uniqify \
+	( EINFO_EINVAL, 0x01, "Invalid blksize" )
+#define EINVAL_TSIZE __einfo_error ( EINFO_EINVAL_TSIZE )
+#define EINFO_EINVAL_TSIZE __einfo_uniqify \
+	( EINFO_EINVAL, 0x02, "Invalid tsize" )
+#define EINVAL_MC_NO_PORT __einfo_error ( EINFO_EINVAL_MC_NO_PORT )
+#define EINFO_EINVAL_MC_NO_PORT __einfo_uniqify \
+	( EINFO_EINVAL, 0x03, "Missing multicast port" )
+#define EINVAL_MC_NO_MC __einfo_error ( EINFO_EINVAL_MC_NO_MC )
+#define EINFO_EINVAL_MC_NO_MC __einfo_uniqify \
+	( EINFO_EINVAL, 0x04, "Missing multicast mc" )
+#define EINVAL_MC_INVALID_MC __einfo_error ( EINFO_EINVAL_MC_INVALID_MC )
+#define EINFO_EINVAL_MC_INVALID_MC __einfo_uniqify \
+	( EINFO_EINVAL, 0x05, "Missing multicast IP" )
+#define EINVAL_MC_INVALID_IP __einfo_error ( EINFO_EINVAL_MC_INVALID_IP )
+#define EINFO_EINVAL_MC_INVALID_IP __einfo_uniqify \
+	( EINFO_EINVAL, 0x06, "Invalid multicast IP" )
+#define EINVAL_MC_INVALID_PORT __einfo_error ( EINFO_EINVAL_MC_INVALID_PORT )
+#define EINFO_EINVAL_MC_INVALID_PORT __einfo_uniqify \
+	( EINFO_EINVAL, 0x07, "Invalid multicast port" )
+
+/**
+ * A TFTP request
+ *
+ * This data structure holds the state for an ongoing TFTP transfer.
+ */
+struct tftp_request {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** URI being fetched */
+	struct uri *uri;
+	/** Transport layer interface */
+	struct interface socket;
+	/** Multicast transport layer interface */
+	struct interface mc_socket;
+
+	/** Data block size
+	 *
+	 * This is the "blksize" option negotiated with the TFTP
+	 * server.  (If the TFTP server does not support TFTP options,
+	 * this will default to 512).
+	 */
+	unsigned int blksize;
+	/** File size
+	 *
+	 * This is the value returned in the "tsize" option from the
+	 * TFTP server.  If the TFTP server does not support the
+	 * "tsize" option, this value will be zero.
+	 */
+	unsigned long tsize;
+	
+	/** Server port
+	 *
+	 * This is the port to which RRQ packets are sent.
+	 */
+	unsigned int port;
+	/** Peer address
+	 *
+	 * The peer address is determined by the first response
+	 * received to the TFTP RRQ.
+	 */
+	struct sockaddr_tcpip peer;
+	/** Request flags */
+	unsigned int flags;
+	/** MTFTP timeout count */
+	unsigned int mtftp_timeouts;
+
+	/** Block bitmap */
+	struct bitmap bitmap;
+	/** Maximum known length
+	 *
+	 * We don't always know the file length in advance.  In
+	 * particular, if the TFTP server doesn't support the tsize
+	 * option, or we are using MTFTP, then we don't know the file
+	 * length until we see the end-of-file block (which, in the
+	 * case of MTFTP, may not be the last block we see).
+	 *
+	 * This value is updated whenever we obtain information about
+	 * the file length.
+	 */
+	size_t filesize;
+	/** Retransmission timer */
+	struct retry_timer timer;
+};
+
+/** TFTP request flags */
+enum {
+	/** Send ACK packets */
+	TFTP_FL_SEND_ACK = 0x0001,
+	/** Request blksize and tsize options */
+	TFTP_FL_RRQ_SIZES = 0x0002,
+	/** Request multicast option */
+	TFTP_FL_RRQ_MULTICAST = 0x0004,
+	/** Perform MTFTP recovery on timeout */
+	TFTP_FL_MTFTP_RECOVERY = 0x0008,
+	/** Only get filesize and then abort the transfer */
+	TFTP_FL_SIZEONLY = 0x0010,
+};
+
+/** Maximum number of MTFTP open requests before falling back to TFTP */
+#define MTFTP_MAX_TIMEOUTS 3
+
+/**
+ * Free TFTP request
+ *
+ * @v refcnt		Reference counter
+ */
+static void tftp_free ( struct refcnt *refcnt ) {
+	struct tftp_request *tftp =
+		container_of ( refcnt, struct tftp_request, refcnt );
+
+	uri_put ( tftp->uri );
+	bitmap_free ( &tftp->bitmap );
+	free ( tftp );
+}
+
+/**
+ * Mark TFTP request as complete
+ *
+ * @v tftp		TFTP connection
+ * @v rc		Return status code
+ */
+static void tftp_done ( struct tftp_request *tftp, int rc ) {
+
+	DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
+	       tftp, rc, strerror ( rc ) );
+
+	/* Stop the retry timer */
+	stop_timer ( &tftp->timer );
+
+	/* Close all data transfer interfaces */
+	intf_shutdown ( &tftp->socket, rc );
+	intf_shutdown ( &tftp->mc_socket, rc );
+	intf_shutdown ( &tftp->xfer, rc );
+}
+
+/**
+ * Reopen TFTP socket
+ *
+ * @v tftp		TFTP connection
+ * @ret rc		Return status code
+ */
+static int tftp_reopen ( struct tftp_request *tftp ) {
+	struct sockaddr_tcpip server;
+	int rc;
+
+	/* Close socket */
+	intf_restart ( &tftp->socket, 0 );
+
+	/* Disable ACK sending. */
+	tftp->flags &= ~TFTP_FL_SEND_ACK;
+
+	/* Reset peer address */
+	memset ( &tftp->peer, 0, sizeof ( tftp->peer ) );
+
+	/* Open socket */
+	memset ( &server, 0, sizeof ( server ) );
+	server.st_port = htons ( tftp->port );
+	if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
+					     ( struct sockaddr * ) &server,
+					     tftp->uri->host, NULL ) ) != 0 ) {
+		DBGC ( tftp, "TFTP %p could not open socket: %s\n",
+		       tftp, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Reopen TFTP multicast socket
+ *
+ * @v tftp		TFTP connection
+ * @v local		Local socket address
+ * @ret rc		Return status code
+ */
+static int tftp_reopen_mc ( struct tftp_request *tftp,
+			    struct sockaddr *local ) {
+	int rc;
+
+	/* Close multicast socket */
+	intf_restart ( &tftp->mc_socket, 0 );
+
+	/* Open multicast socket.  We never send via this socket, so
+	 * use the local address as the peer address (since the peer
+	 * address cannot be NULL).
+	 */
+	if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
+				       local, local ) ) != 0 ) {
+		DBGC ( tftp, "TFTP %p could not open multicast "
+		       "socket: %s\n", tftp, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Presize TFTP receive buffers and block bitmap
+ *
+ * @v tftp		TFTP connection
+ * @v filesize		Known minimum file size
+ * @ret rc		Return status code
+ */
+static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
+	unsigned int num_blocks;
+	int rc;
+
+	/* Do nothing if we are already large enough */
+	if ( filesize <= tftp->filesize )
+		return 0;
+
+	/* Record filesize */
+	tftp->filesize = filesize;
+
+	/* Notify recipient of file size */
+	xfer_seek ( &tftp->xfer, filesize );
+	xfer_seek ( &tftp->xfer, 0 );
+
+	/* Calculate expected number of blocks.  Note that files whose
+	 * length is an exact multiple of the blocksize will have a
+	 * trailing zero-length block, which must be included.
+	 */
+	num_blocks = ( ( filesize / tftp->blksize ) + 1 );
+	if ( ( rc = bitmap_resize ( &tftp->bitmap, num_blocks ) ) != 0 ) {
+		DBGC ( tftp, "TFTP %p could not resize bitmap to %d blocks: "
+		       "%s\n", tftp, num_blocks, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * TFTP requested blocksize
+ *
+ * This is treated as a global configuration parameter.
+ */
+static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
+
+/**
+ * Set TFTP request blocksize
+ *
+ * @v blksize		Requested block size
+ */
+void tftp_set_request_blksize ( unsigned int blksize ) {
+	if ( blksize < TFTP_DEFAULT_BLKSIZE )
+		blksize = TFTP_DEFAULT_BLKSIZE;
+	tftp_request_blksize = blksize;
+}
+
+/**
+ * MTFTP multicast receive address
+ *
+ * This is treated as a global configuration parameter.
+ */
+static struct sockaddr_in tftp_mtftp_socket = {
+	.sin_family = AF_INET,
+	.sin_addr.s_addr = htonl ( 0xefff0101 ),
+	.sin_port = htons ( 3001 ),
+};
+
+/**
+ * Set MTFTP multicast address
+ *
+ * @v address		Multicast IPv4 address
+ */
+void tftp_set_mtftp_address ( struct in_addr address ) {
+	tftp_mtftp_socket.sin_addr = address;
+}
+
+/**
+ * Set MTFTP multicast port
+ *
+ * @v port		Multicast port
+ */
+void tftp_set_mtftp_port ( unsigned int port ) {
+	tftp_mtftp_socket.sin_port = htons ( port );
+}
+
+/**
+ * Transmit RRQ
+ *
+ * @v tftp		TFTP connection
+ * @ret rc		Return status code
+ */
+static int tftp_send_rrq ( struct tftp_request *tftp ) {
+	struct tftp_rrq *rrq;
+	const char *path;
+	size_t len;
+	struct io_buffer *iobuf;
+
+	/* Strip initial '/' if present.  If we were opened via the
+	 * URI interface, then there will be an initial '/', since a
+	 * full tftp:// URI provides no way to specify a non-absolute
+	 * path.  However, many TFTP servers (particularly Windows
+	 * TFTP servers) complain about having an initial '/', and it
+	 * violates user expectations to have a '/' silently added to
+	 * the DHCP-specified filename.
+	 */
+	path = tftp->uri->path;
+	if ( *path == '/' )
+		path++;
+
+	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
+
+	/* Allocate buffer */
+	len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
+		+ 5 + 1 /* "octet" + NUL */
+		+ 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
+		+ 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ 
+		+ 9 + 1 + 1 /* "multicast" + NUL + NUL */ );
+	iobuf = xfer_alloc_iob ( &tftp->socket, len );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Build request */
+	rrq = iob_put ( iobuf, sizeof ( *rrq ) );
+	rrq->opcode = htons ( TFTP_RRQ );
+	iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ),
+				    "%s%coctet", path, 0 ) + 1 );
+	if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
+		iob_put ( iobuf, snprintf ( iobuf->tail,
+					    iob_tailroom ( iobuf ),
+					    "blksize%c%d%ctsize%c0", 0,
+					    tftp_request_blksize, 0, 0 ) + 1 );
+	}
+	if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
+		iob_put ( iobuf, snprintf ( iobuf->tail,
+					    iob_tailroom ( iobuf ),
+					    "multicast%c", 0 ) + 1 );
+	}
+
+	/* RRQ always goes to the address specified in the initial
+	 * xfer_open() call
+	 */
+	return xfer_deliver_iob ( &tftp->socket, iobuf );
+}
+
+/**
+ * Transmit ACK
+ *
+ * @v tftp		TFTP connection
+ * @ret rc		Return status code
+ */
+static int tftp_send_ack ( struct tftp_request *tftp ) {
+	struct tftp_ack *ack;
+	struct io_buffer *iobuf;
+	struct xfer_metadata meta = {
+		.dest = ( struct sockaddr * ) &tftp->peer,
+	};
+	unsigned int block;
+
+	/* Determine next required block number */
+	block = bitmap_first_gap ( &tftp->bitmap );
+	DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n", tftp, block );
+
+	/* Allocate buffer */
+	iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Build ACK */
+	ack = iob_put ( iobuf, sizeof ( *ack ) );
+	ack->opcode = htons ( TFTP_ACK );
+	ack->block = htons ( block );
+
+	/* ACK always goes to the peer recorded from the RRQ response */
+	return xfer_deliver ( &tftp->socket, iobuf, &meta );
+}
+
+/**
+ * Transmit ERROR (Abort)
+ *
+ * @v tftp		TFTP connection
+ * @v errcode		TFTP error code
+ * @v errmsg		Error message string
+ * @ret rc		Return status code
+ */
+static int tftp_send_error ( struct tftp_request *tftp, int errcode,
+			     const char *errmsg ) {
+	struct tftp_error *err;
+	struct io_buffer *iobuf;
+	struct xfer_metadata meta = {
+		.dest = ( struct sockaddr * ) &tftp->peer,
+	};
+	size_t msglen;
+
+	DBGC2 ( tftp, "TFTP %p sending ERROR %d: %s\n", tftp, errcode,
+		errmsg );
+
+	/* Allocate buffer */
+	msglen = sizeof ( *err ) + strlen ( errmsg ) + 1 /* NUL */;
+	iobuf = xfer_alloc_iob ( &tftp->socket, msglen );
+	if ( ! iobuf )
+		return -ENOMEM;
+
+	/* Build ERROR */
+	err = iob_put ( iobuf, msglen );
+	err->opcode = htons ( TFTP_ERROR );
+	err->errcode = htons ( errcode );
+	strcpy ( err->errmsg, errmsg );
+
+	/* ERR always goes to the peer recorded from the RRQ response */
+	return xfer_deliver ( &tftp->socket, iobuf, &meta );
+}
+
+/**
+ * Transmit next relevant packet
+ *
+ * @v tftp		TFTP connection
+ * @ret rc		Return status code
+ */
+static int tftp_send_packet ( struct tftp_request *tftp ) {
+
+	/* Update retransmission timer.  While name resolution takes place the
+	 * window is zero.  Avoid unnecessary delay after name resolution
+	 * completes by retrying immediately.
+	 */
+	stop_timer ( &tftp->timer );
+	if ( xfer_window ( &tftp->socket ) ) {
+		start_timer ( &tftp->timer );
+	} else {
+		start_timer_nodelay ( &tftp->timer );
+	}
+
+	/* Send RRQ or ACK as appropriate */
+	if ( ! tftp->peer.st_family ) {
+		return tftp_send_rrq ( tftp );
+	} else {
+		if ( tftp->flags & TFTP_FL_SEND_ACK ) {
+			return tftp_send_ack ( tftp );
+		} else {
+			return 0;
+		}
+	}
+}
+
+/**
+ * Handle TFTP retransmission timer expiry
+ *
+ * @v timer		Retry timer
+ * @v fail		Failure indicator
+ */
+static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
+	struct tftp_request *tftp =
+		container_of ( timer, struct tftp_request, timer );
+	int rc;
+
+	/* If we are doing MTFTP, attempt the various recovery strategies */
+	if ( tftp->flags & TFTP_FL_MTFTP_RECOVERY ) {
+		if ( tftp->peer.st_family ) {
+			/* If we have received any response from the server,
+			 * try resending the RRQ to restart the download.
+			 */
+			DBGC ( tftp, "TFTP %p attempting reopen\n", tftp );
+			if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
+				goto err;
+		} else {
+			/* Fall back to plain TFTP after several attempts */
+			tftp->mtftp_timeouts++;
+			DBGC ( tftp, "TFTP %p timeout %d waiting for MTFTP "
+			       "open\n", tftp, tftp->mtftp_timeouts );
+
+			if ( tftp->mtftp_timeouts > MTFTP_MAX_TIMEOUTS ) {
+				DBGC ( tftp, "TFTP %p falling back to plain "
+				       "TFTP\n", tftp );
+				tftp->flags = TFTP_FL_RRQ_SIZES;
+
+				/* Close multicast socket */
+				intf_restart ( &tftp->mc_socket, 0 );
+
+				/* Reset retry timer */
+				start_timer_nodelay ( &tftp->timer );
+
+				/* The blocksize may change: discard
+				 * the block bitmap
+				 */
+				bitmap_free ( &tftp->bitmap );
+				memset ( &tftp->bitmap, 0,
+					 sizeof ( tftp->bitmap ) );
+
+				/* Reopen on standard TFTP port */
+				tftp->port = TFTP_PORT;
+				if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
+					goto err;
+			}
+		}
+	} else {
+		/* Not doing MTFTP (or have fallen back to plain
+		 * TFTP); fail as per normal.
+		 */
+		if ( fail ) {
+			rc = -ETIMEDOUT;
+			goto err;
+		}
+	}
+	tftp_send_packet ( tftp );
+	return;
+
+ err:
+	tftp_done ( tftp, rc );
+}
+
+/**
+ * Process TFTP "blksize" option
+ *
+ * @v tftp		TFTP connection
+ * @v value		Option value
+ * @ret rc		Return status code
+ */
+static int tftp_process_blksize ( struct tftp_request *tftp,
+				  const char *value ) {
+	char *end;
+
+	tftp->blksize = strtoul ( value, &end, 10 );
+	if ( *end ) {
+		DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
+		       tftp, value );
+		return -EINVAL_BLKSIZE;
+	}
+	DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
+
+	return 0;
+}
+
+/**
+ * Process TFTP "tsize" option
+ *
+ * @v tftp		TFTP connection
+ * @v value		Option value
+ * @ret rc		Return status code
+ */
+static int tftp_process_tsize ( struct tftp_request *tftp,
+				const char *value ) {
+	char *end;
+
+	tftp->tsize = strtoul ( value, &end, 10 );
+	if ( *end ) {
+		DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
+		       tftp, value );
+		return -EINVAL_TSIZE;
+	}
+	DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
+
+	return 0;
+}
+
+/**
+ * Process TFTP "multicast" option
+ *
+ * @v tftp		TFTP connection
+ * @v value		Option value
+ * @ret rc		Return status code
+ */
+static int tftp_process_multicast ( struct tftp_request *tftp,
+				    const char *value ) {
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+	} socket;
+	char buf[ strlen ( value ) + 1 ];
+	char *addr;
+	char *port;
+	char *port_end;
+	char *mc;
+	char *mc_end;
+	int rc;
+
+	/* Split value into "addr,port,mc" fields */
+	memcpy ( buf, value, sizeof ( buf ) );
+	addr = buf;
+	port = strchr ( addr, ',' );
+	if ( ! port ) {
+		DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
+		return -EINVAL_MC_NO_PORT;
+	}
+	*(port++) = '\0';
+	mc = strchr ( port, ',' );
+	if ( ! mc ) {
+		DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
+		return -EINVAL_MC_NO_MC;
+	}
+	*(mc++) = '\0';
+
+	/* Parse parameters */
+	if ( strtoul ( mc, &mc_end, 0 ) == 0 )
+		tftp->flags &= ~TFTP_FL_SEND_ACK;
+	if ( *mc_end ) {
+		DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
+		return -EINVAL_MC_INVALID_MC;
+	}
+	DBGC ( tftp, "TFTP %p is%s the master client\n",
+	       tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
+	if ( *addr && *port ) {
+		socket.sin.sin_family = AF_INET;
+		if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
+			DBGC ( tftp, "TFTP %p multicast invalid IP address "
+			       "%s\n", tftp, addr );
+			return -EINVAL_MC_INVALID_IP;
+		}
+		DBGC ( tftp, "TFTP %p multicast IP address %s\n",
+		       tftp, inet_ntoa ( socket.sin.sin_addr ) );
+		socket.sin.sin_port = htons ( strtoul ( port, &port_end, 0 ) );
+		if ( *port_end ) {
+			DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
+			       tftp, port );
+			return -EINVAL_MC_INVALID_PORT;
+		}
+		DBGC ( tftp, "TFTP %p multicast port %d\n",
+		       tftp, ntohs ( socket.sin.sin_port ) );
+		if ( ( rc = tftp_reopen_mc ( tftp, &socket.sa ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/** A TFTP option */
+struct tftp_option {
+	/** Option name */
+	const char *name;
+	/** Option processor
+	 *
+	 * @v tftp	TFTP connection
+	 * @v value	Option value
+	 * @ret rc	Return status code
+	 */
+	int ( * process ) ( struct tftp_request *tftp, const char *value );
+};
+
+/** Recognised TFTP options */
+static struct tftp_option tftp_options[] = {
+	{ "blksize", tftp_process_blksize },
+	{ "tsize", tftp_process_tsize },
+	{ "multicast", tftp_process_multicast },
+	{ NULL, NULL }
+};
+
+/**
+ * Process TFTP option
+ *
+ * @v tftp		TFTP connection
+ * @v name		Option name
+ * @v value		Option value
+ * @ret rc		Return status code
+ */
+static int tftp_process_option ( struct tftp_request *tftp,
+				 const char *name, const char *value ) {
+	struct tftp_option *option;
+
+	for ( option = tftp_options ; option->name ; option++ ) {
+		if ( strcasecmp ( name, option->name ) == 0 )
+			return option->process ( tftp, value );
+	}
+
+	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
+	       tftp, name, value );
+
+	/* Unknown options should be silently ignored */
+	return 0;
+}
+
+/**
+ * Receive OACK
+ *
+ * @v tftp		TFTP connection
+ * @v buf		Temporary data buffer
+ * @v len		Length of temporary data buffer
+ * @ret rc		Return status code
+ */
+static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
+	struct tftp_oack *oack = buf;
+	char *end = buf + len;
+	char *name;
+	char *value;
+	char *next;
+	int rc = 0;
+
+	/* Sanity check */
+	if ( len < sizeof ( *oack ) ) {
+		DBGC ( tftp, "TFTP %p received underlength OACK packet "
+		       "length %zd\n", tftp, len );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Process each option in turn */
+	for ( name = oack->data ; name < end ; name = next ) {
+
+		/* Parse option name and value
+		 *
+		 * We treat parsing errors as non-fatal, because there
+		 * exists at least one TFTP server (IBM Tivoli PXE
+		 * Server 5.1.0.3) that has been observed to send
+		 * malformed OACKs containing trailing garbage bytes.
+		 */
+		value = ( name + strnlen ( name, ( end - name ) ) + 1 );
+		if ( value > end ) {
+			DBGC ( tftp, "TFTP %p received OACK with malformed "
+			       "option name:\n", tftp );
+			DBGC_HD ( tftp, oack, len );
+			break;
+		}
+		if ( value == end ) {
+			DBGC ( tftp, "TFTP %p received OACK missing value "
+			       "for option \"%s\"\n", tftp, name );
+			DBGC_HD ( tftp, oack, len );
+			break;
+		}
+		next = ( value + strnlen ( value, ( end - value ) ) + 1 );
+		if ( next > end ) {
+			DBGC ( tftp, "TFTP %p received OACK with malformed "
+			       "value for option \"%s\":\n", tftp, name );
+			DBGC_HD ( tftp, oack, len );
+			break;
+		}
+
+		/* Process option */
+		if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
+			goto done;
+	}
+
+	/* Process tsize information, if available */
+	if ( tftp->tsize ) {
+		if ( ( rc = tftp_presize ( tftp, tftp->tsize ) ) != 0 )
+			goto done;
+	}
+
+	/* Abort request if only trying to determine file size */
+	if ( tftp->flags & TFTP_FL_SIZEONLY ) {
+		rc = 0;
+		tftp_send_error ( tftp, 0, "TFTP Aborted" );
+		tftp_done ( tftp, rc );
+		return rc;
+	}
+
+	/* Request next data block */
+	tftp_send_packet ( tftp );
+
+ done:
+	if ( rc )
+		tftp_done ( tftp, rc );
+	return rc;
+}
+
+/**
+ * Receive DATA
+ *
+ * @v tftp		TFTP connection
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ *
+ * Takes ownership of I/O buffer.
+ */
+static int tftp_rx_data ( struct tftp_request *tftp,
+			  struct io_buffer *iobuf ) {
+	struct tftp_data *data = iobuf->data;
+	struct xfer_metadata meta;
+	unsigned int block;
+	off_t offset;
+	size_t data_len;
+	int rc;
+
+	if ( tftp->flags & TFTP_FL_SIZEONLY ) {
+		/* If we get here then server doesn't support SIZE option */
+		rc = -ENOTSUP;
+		tftp_send_error ( tftp, 0, "TFTP Aborted" );
+		goto done;
+	}
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
+		DBGC ( tftp, "TFTP %p received underlength DATA packet "
+		       "length %zd\n", tftp, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Calculate block number */
+	block = ( ( bitmap_first_gap ( &tftp->bitmap ) + 1 ) & ~0xffff );
+	if ( data->block == 0 && block == 0 ) {
+		DBGC ( tftp, "TFTP %p received data block 0\n", tftp );
+		rc = -EINVAL;
+		goto done;
+	}
+	block += ( ntohs ( data->block ) - 1 );
+
+	/* Extract data */
+	offset = ( block * tftp->blksize );
+	iob_pull ( iobuf, sizeof ( *data ) );
+	data_len = iob_len ( iobuf );
+	if ( data_len > tftp->blksize ) {
+		DBGC ( tftp, "TFTP %p received overlength DATA packet "
+		       "length %zd\n", tftp, data_len );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Deliver data */
+	memset ( &meta, 0, sizeof ( meta ) );
+	meta.flags = XFER_FL_ABS_OFFSET;
+	meta.offset = offset;
+	if ( ( rc = xfer_deliver ( &tftp->xfer, iob_disown ( iobuf ),
+				   &meta ) ) != 0 ) {
+		DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
+		       tftp, strerror ( rc ) );
+		goto done;
+	}
+
+	/* Ensure block bitmap is ready */
+	if ( ( rc = tftp_presize ( tftp, ( offset + data_len ) ) ) != 0 )
+		goto done;
+
+	/* Mark block as received */
+	bitmap_set ( &tftp->bitmap, block );
+
+	/* Acknowledge block */
+	tftp_send_packet ( tftp );
+
+	/* If all blocks have been received, finish. */
+	if ( bitmap_full ( &tftp->bitmap ) )
+		tftp_done ( tftp, 0 );
+
+ done:
+	free_iob ( iobuf );
+	if ( rc )
+		tftp_done ( tftp, rc );
+	return rc;
+}
+
+/**
+ * Convert TFTP error code to return status code
+ *
+ * @v errcode		TFTP error code
+ * @ret rc		Return status code
+ */
+static int tftp_errcode_to_rc ( unsigned int errcode ) {
+	switch ( errcode ) {
+	case TFTP_ERR_FILE_NOT_FOUND:	return -ENOENT;
+	case TFTP_ERR_ACCESS_DENIED:	return -EACCES;
+	case TFTP_ERR_ILLEGAL_OP:	return -ENOTTY;
+	default:			return -ENOTSUP;
+	}
+}
+
+/**
+ * Receive ERROR
+ *
+ * @v tftp		TFTP connection
+ * @v buf		Temporary data buffer
+ * @v len		Length of temporary data buffer
+ * @ret rc		Return status code
+ */
+static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
+	struct tftp_error *error = buf;
+	int rc;
+
+	/* Sanity check */
+	if ( len < sizeof ( *error ) ) {
+		DBGC ( tftp, "TFTP %p received underlength ERROR packet "
+		       "length %zd\n", tftp, len );
+		return -EINVAL;
+	}
+
+	DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
+	       "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
+	
+	/* Determine final operation result */
+	rc = tftp_errcode_to_rc ( ntohs ( error->errcode ) );
+
+	/* Close TFTP request */
+	tftp_done ( tftp, rc );
+
+	return 0;
+}
+
+/**
+ * Receive new data
+ *
+ * @v tftp		TFTP connection
+ * @v iobuf		I/O buffer
+ * @v meta		Transfer metadata
+ * @ret rc		Return status code
+ */
+static int tftp_rx ( struct tftp_request *tftp,
+		     struct io_buffer *iobuf,
+		     struct xfer_metadata *meta ) {
+	struct sockaddr_tcpip *st_src;
+	struct tftp_common *common = iobuf->data;
+	size_t len = iob_len ( iobuf );
+	int rc = -EINVAL;
+	
+	/* Sanity checks */
+	if ( len < sizeof ( *common ) ) {
+		DBGC ( tftp, "TFTP %p received underlength packet length "
+		       "%zd\n", tftp, len );
+		goto done;
+	}
+	if ( ! meta->src ) {
+		DBGC ( tftp, "TFTP %p received packet without source port\n",
+		       tftp );
+		goto done;
+	}
+
+	/* Filter by TID.  Set TID on first response received */
+	st_src = ( struct sockaddr_tcpip * ) meta->src;
+	if ( ! tftp->peer.st_family ) {
+		memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
+		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
+		       ntohs ( tftp->peer.st_port ) );
+	} else if ( memcmp ( &tftp->peer, st_src,
+			     sizeof ( tftp->peer ) ) != 0 ) {
+		DBGC ( tftp, "TFTP %p received packet from wrong source (got "
+		       "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
+		       ntohs ( tftp->peer.st_port ) );
+		goto done;
+	}
+
+	switch ( common->opcode ) {
+	case htons ( TFTP_OACK ):
+		rc = tftp_rx_oack ( tftp, iobuf->data, len );
+		break;
+	case htons ( TFTP_DATA ):
+		rc = tftp_rx_data ( tftp, iob_disown ( iobuf ) );
+		break;
+	case htons ( TFTP_ERROR ):
+		rc = tftp_rx_error ( tftp, iobuf->data, len );
+		break;
+	default:
+		DBGC ( tftp, "TFTP %p received strange packet type %d\n",
+		       tftp, ntohs ( common->opcode ) );
+		break;
+	};
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Receive new data via socket
+ *
+ * @v tftp		TFTP connection
+ * @v iobuf		I/O buffer
+ * @v meta		Transfer metadata
+ * @ret rc		Return status code
+ */
+static int tftp_socket_deliver ( struct tftp_request *tftp,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta ) {
+
+	/* Enable sending ACKs when we receive a unicast packet.  This
+	 * covers three cases:
+	 *
+	 * 1. Standard TFTP; we should always send ACKs, and will
+	 *    always receive a unicast packet before we need to send the
+	 *    first ACK.
+	 *
+	 * 2. RFC2090 multicast TFTP; the only unicast packets we will
+         *    receive are the OACKs; enable sending ACKs here (before
+         *    processing the OACK) and disable it when processing the
+         *    multicast option if we are not the master client.
+	 *
+	 * 3. MTFTP; receiving a unicast datagram indicates that we
+	 *    are the "master client" and should send ACKs.
+	 */
+	tftp->flags |= TFTP_FL_SEND_ACK;
+
+	return tftp_rx ( tftp, iobuf, meta );
+}
+
+/** TFTP socket operations */
+static struct interface_operation tftp_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct tftp_request *, tftp_socket_deliver ),
+};
+
+/** TFTP socket interface descriptor */
+static struct interface_descriptor tftp_socket_desc =
+	INTF_DESC ( struct tftp_request, socket, tftp_socket_operations );
+
+/** TFTP multicast socket operations */
+static struct interface_operation tftp_mc_socket_operations[] = {
+	INTF_OP ( xfer_deliver, struct tftp_request *, tftp_rx ),
+};
+
+/** TFTP multicast socket interface descriptor */
+static struct interface_descriptor tftp_mc_socket_desc =
+	INTF_DESC ( struct tftp_request, mc_socket, tftp_mc_socket_operations );
+
+/**
+ * Check flow control window
+ *
+ * @v tftp		TFTP connection
+ * @ret len		Length of window
+ */
+static size_t tftp_xfer_window ( struct tftp_request *tftp ) {
+
+	/* We abuse this data-xfer method to convey the blocksize to
+	 * the caller.  This really should be done using some kind of
+	 * stat() method, but we don't yet have the facility to do
+	 * that.
+	 */
+	return tftp->blksize;
+}
+
+/** TFTP data transfer interface operations */
+static struct interface_operation tftp_xfer_operations[] = {
+	INTF_OP ( xfer_window, struct tftp_request *, tftp_xfer_window ),
+	INTF_OP ( intf_close, struct tftp_request *, tftp_done ),
+};
+
+/** TFTP data transfer interface descriptor */
+static struct interface_descriptor tftp_xfer_desc =
+	INTF_DESC ( struct tftp_request, xfer, tftp_xfer_operations );
+
+/**
+ * Initiate TFTP/TFTM/MTFTP download
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int tftp_core_open ( struct interface *xfer, struct uri *uri,
+			    unsigned int default_port,
+			    struct sockaddr *multicast,
+			    unsigned int flags ) {
+	struct tftp_request *tftp;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! uri->host )
+		return -EINVAL;
+	if ( ! uri->path )
+		return -EINVAL;
+
+	/* Allocate and populate TFTP structure */
+	tftp = zalloc ( sizeof ( *tftp ) );
+	if ( ! tftp )
+		return -ENOMEM;
+	ref_init ( &tftp->refcnt, tftp_free );
+	intf_init ( &tftp->xfer, &tftp_xfer_desc, &tftp->refcnt );
+	intf_init ( &tftp->socket, &tftp_socket_desc, &tftp->refcnt );
+	intf_init ( &tftp->mc_socket, &tftp_mc_socket_desc, &tftp->refcnt );
+	timer_init ( &tftp->timer, tftp_timer_expired, &tftp->refcnt );
+	tftp->uri = uri_get ( uri );
+	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
+	tftp->flags = flags;
+
+	/* Open socket */
+	tftp->port = uri_port ( tftp->uri, default_port );
+	if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
+		goto err;
+
+	/* Open multicast socket */
+	if ( multicast ) {
+		if ( ( rc = tftp_reopen_mc ( tftp, multicast ) ) != 0 )
+			goto err;
+	}
+
+	/* Start timer to initiate RRQ */
+	start_timer_nodelay ( &tftp->timer );
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &tftp->xfer, xfer );
+	ref_put ( &tftp->refcnt );
+	return 0;
+
+ err:
+	DBGC ( tftp, "TFTP %p could not create request: %s\n",
+	       tftp, strerror ( rc ) );
+	tftp_done ( tftp, rc );
+	ref_put ( &tftp->refcnt );
+	return rc;
+}
+
+/**
+ * Initiate TFTP download
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int tftp_open ( struct interface *xfer, struct uri *uri ) {
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
+				TFTP_FL_RRQ_SIZES );
+
+}
+
+/** TFTP URI opener */
+struct uri_opener tftp_uri_opener __uri_opener = {
+	.scheme	= "tftp",
+	.open	= tftp_open,
+};
+
+/**
+ * Initiate TFTP-size request
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int tftpsize_open ( struct interface *xfer, struct uri *uri ) {
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
+				( TFTP_FL_RRQ_SIZES |
+				  TFTP_FL_SIZEONLY ) );
+
+}
+
+/** TFTP URI opener */
+struct uri_opener tftpsize_uri_opener __uri_opener = {
+	.scheme	= "tftpsize",
+	.open	= tftpsize_open,
+};
+
+/**
+ * Initiate TFTM download
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int tftm_open ( struct interface *xfer, struct uri *uri ) {
+	return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
+				( TFTP_FL_RRQ_SIZES |
+				  TFTP_FL_RRQ_MULTICAST ) );
+
+}
+
+/** TFTM URI opener */
+struct uri_opener tftm_uri_opener __uri_opener = {
+	.scheme	= "tftm",
+	.open	= tftm_open,
+};
+
+/**
+ * Initiate MTFTP download
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @ret rc		Return status code
+ */
+static int mtftp_open ( struct interface *xfer, struct uri *uri ) {
+	return tftp_core_open ( xfer, uri, MTFTP_PORT,
+				( struct sockaddr * ) &tftp_mtftp_socket,
+				TFTP_FL_MTFTP_RECOVERY );
+}
+
+/** MTFTP URI opener */
+struct uri_opener mtftp_uri_opener __uri_opener = {
+	.scheme	= "mtftp",
+	.open	= mtftp_open,
+};
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** TFTP server setting */
+struct setting next_server_setting __setting ( SETTING_BOOT ) = {
+	.name = "next-server",
+	.description = "TFTP server",
+	.tag = DHCP_EB_SIADDR,
+	.type = &setting_type_ipv4,
+};
+
+/**
+ * Apply TFTP configuration settings
+ *
+ * @ret rc		Return status code
+ */
+static int tftp_apply_settings ( void ) {
+	static struct in_addr tftp_server = { 0 };
+	struct in_addr last_tftp_server;
+	char uri_string[32];
+	struct uri *uri;
+
+	/* Retrieve TFTP server setting */
+	last_tftp_server = tftp_server;
+	fetch_ipv4_setting ( NULL, &next_server_setting, &tftp_server );
+
+	/* If TFTP server setting has changed, set the current working
+	 * URI to match.  Do it only when the TFTP server has changed
+	 * to try to minimise surprises to the user, who probably
+	 * won't expect the CWURI to change just because they updated
+	 * an unrelated setting and triggered all the settings
+	 * applicators.
+	 */
+	if ( tftp_server.s_addr != last_tftp_server.s_addr ) {
+		if ( tftp_server.s_addr ) {
+			snprintf ( uri_string, sizeof ( uri_string ),
+				   "tftp://%s/", inet_ntoa ( tftp_server ) );
+			uri = parse_uri ( uri_string );
+			if ( ! uri )
+				return -ENOMEM;
+		} else {
+			uri = NULL;
+		}
+		churi ( uri );
+		uri_put ( uri );
+	}
+
+	return 0;
+}
+
+/** TFTP settings applicator */
+struct settings_applicator tftp_settings_applicator __settings_applicator = {
+	.apply = tftp_apply_settings,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/net/vlan.c b/qemu-0.15.x/roms/ipxe/src/net/vlan.c
new file mode 100644
index 0000000..9ac560f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/net/vlan.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/features.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/vlan.h>
+
+/** @file
+ *
+ * Virtual LANs
+ *
+ */
+
+FEATURE ( FEATURE_PROTOCOL, "VLAN", DHCP_EB_FEATURE_VLAN, 1 );
+
+struct net_protocol vlan_protocol __net_protocol;
+
+/** VLAN device private data */
+struct vlan_device {
+	/** Trunk network device */
+	struct net_device *trunk;
+	/** VLAN tag */
+	unsigned int tag;
+	/** Default priority */
+	unsigned int priority;
+};
+
+/**
+ * Open VLAN device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int vlan_open ( struct net_device *netdev ) {
+	struct vlan_device *vlan = netdev->priv;
+
+	return netdev_open ( vlan->trunk );
+}
+
+/**
+ * Close VLAN device
+ *
+ * @v netdev		Network device
+ */
+static void vlan_close ( struct net_device *netdev ) {
+	struct vlan_device *vlan = netdev->priv;
+
+	netdev_close ( vlan->trunk );
+}
+
+/**
+ * Transmit packet on VLAN device
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int vlan_transmit ( struct net_device *netdev,
+			   struct io_buffer *iobuf ) {
+	struct vlan_device *vlan = netdev->priv;
+	struct net_device *trunk = vlan->trunk;
+	struct ll_protocol *ll_protocol;
+	struct vlan_header *vlanhdr;
+	uint8_t ll_dest_copy[ETH_ALEN];
+	uint8_t ll_source_copy[ETH_ALEN];
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	int rc;
+
+	/* Strip link-layer header and preserve link-layer header fields */
+	ll_protocol = netdev->ll_protocol;
+	if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
+					&net_proto ) ) != 0 ) {
+		DBGC ( netdev, "VLAN %s could not parse link-layer header: "
+		       "%s\n", netdev->name, strerror ( rc ) );
+		return rc;
+	}
+	memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
+	memcpy ( ll_source_copy, ll_source, ETH_ALEN );
+
+	/* Construct VLAN header */
+	vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) );
+	vlanhdr->tci = htons ( VLAN_TCI ( vlan->tag, vlan->priority ) );
+	vlanhdr->net_proto = net_proto;
+
+	/* Reclaim I/O buffer from VLAN device's TX queue */
+	list_del ( &iobuf->list );
+
+	/* Transmit packet on trunk device */
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), trunk, &vlan_protocol,
+			     ll_dest_copy, ll_source_copy ) ) != 0 ) {
+		DBGC ( netdev, "VLAN %s could not transmit: %s\n",
+		       netdev->name, strerror ( rc ) );
+		/* Cannot return an error status, since that would
+		 * cause the I/O buffer to be double-freed.
+		 */
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Poll VLAN device
+ *
+ * @v netdev		Network device
+ */
+static void vlan_poll ( struct net_device *netdev ) {
+	struct vlan_device *vlan = netdev->priv;
+
+	/* Poll trunk device */
+	netdev_poll ( vlan->trunk );
+}
+
+/**
+ * Enable/disable interrupts on VLAN device
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void vlan_irq ( struct net_device *netdev, int enable ) {
+	struct vlan_device *vlan = netdev->priv;
+
+	/* Enable/disable interrupts on trunk device.  This is not at
+	 * all robust, but there is no sensible course of action
+	 * available.
+	 */
+	netdev_irq ( vlan->trunk, enable );
+}
+
+/** VLAN device operations */
+static struct net_device_operations vlan_operations = {
+	.open		= vlan_open,
+	.close		= vlan_close,
+	.transmit	= vlan_transmit,
+	.poll		= vlan_poll,
+	.irq		= vlan_irq,
+};
+
+/**
+ * Synchronise VLAN device
+ *
+ * @v netdev		Network device
+ */
+static void vlan_sync ( struct net_device *netdev ) {
+	struct vlan_device *vlan = netdev->priv;
+	struct net_device *trunk = vlan->trunk;
+
+	/* Synchronise link status */
+	if ( netdev->link_rc != trunk->link_rc )
+		netdev_link_err ( netdev, trunk->link_rc );
+
+	/* Synchronise open/closed status */
+	if ( netdev_is_open ( trunk ) ) {
+		if ( ! netdev_is_open ( netdev ) )
+			netdev_open ( netdev );
+	} else {
+		if ( netdev_is_open ( netdev ) )
+			netdev_close ( netdev );
+	}
+}
+
+/**
+ * Identify VLAN device
+ *
+ * @v trunk		Trunk network device
+ * @v tag		VLAN tag
+ * @ret netdev		VLAN device, if any
+ */
+struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
+	struct net_device *netdev;
+	struct vlan_device *vlan;
+
+	for_each_netdev ( netdev ) {
+		if ( netdev->op != &vlan_operations )
+			continue;
+		vlan = netdev->priv;
+		if ( ( vlan->trunk == trunk ) && ( vlan->tag == tag ) )
+			return netdev;
+	}
+	return NULL;
+}
+
+/**
+ * Process incoming VLAN packet
+ *
+ * @v iobuf		I/O buffer
+ * @v trunk		Trunk network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
+		     const void *ll_dest, const void *ll_source ) {
+	struct vlan_header *vlanhdr = iobuf->data;
+	struct net_device *netdev;
+	struct ll_protocol *ll_protocol;
+	uint8_t ll_dest_copy[ETH_ALEN];
+	uint8_t ll_source_copy[ETH_ALEN];
+	uint16_t tag;
+	int rc;
+
+	/* Sanity check */
+	if ( iob_len ( iobuf ) < sizeof ( *vlanhdr ) ) {
+		DBGC ( trunk, "VLAN %s received underlength packet (%zd "
+		       "bytes)\n", trunk->name, iob_len ( iobuf ) );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	/* Identify VLAN device */
+	tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) );
+	netdev = vlan_find ( trunk, tag );
+	if ( ! netdev ) {
+		DBGC2 ( trunk, "VLAN %s received packet for unknown VLAN "
+			"%d\n", trunk->name, tag );
+		rc = -EPIPE;
+		goto err_no_vlan;
+	}
+
+	/* Strip VLAN header and preserve original link-layer header fields */
+	iob_pull ( iobuf, sizeof ( *vlanhdr ) );
+	ll_protocol = trunk->ll_protocol;
+	memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
+	memcpy ( ll_source_copy, ll_source, ETH_ALEN );
+
+	/* Reconstruct link-layer header for VLAN device */
+	ll_protocol = netdev->ll_protocol;
+	if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest_copy,
+					ll_source_copy,
+					vlanhdr->net_proto ) ) != 0 ) {
+		DBGC ( netdev, "VLAN %s could not reconstruct link-layer "
+		       "header: %s\n", netdev->name, strerror ( rc ) );
+		goto err_ll_push;
+	}
+
+	/* Enqueue packet on VLAN device */
+	netdev_rx ( netdev, iob_disown ( iobuf ) );
+	return 0;
+
+ err_ll_push:
+ err_no_vlan:
+ err_sanity:
+	free_iob ( iobuf );
+	return rc;
+}
+
+/** VLAN protocol */
+struct net_protocol vlan_protocol __net_protocol = {
+	.name = "VLAN",
+	.net_proto = htons ( ETH_P_8021Q ),
+	.rx = vlan_rx,
+};
+
+/**
+ * Check if network device can be used as a VLAN trunk device
+ *
+ * @v trunk		Trunk network device
+ * @ret is_ok		Trunk network device is usable
+ *
+ * VLAN devices will be created as Ethernet devices.  (We cannot
+ * simply clone the link layer of the trunk network device, because
+ * this link layer may expect the network device structure to contain
+ * some link-layer-private data.)  The trunk network device must
+ * therefore have a link layer that is in some sense 'compatible' with
+ * Ethernet; specifically, it must have link-layer addresses that are
+ * the same length as Ethernet link-layer addresses.
+ *
+ * As an additional check, and primarily to assist with the sanity of
+ * the FCoE code, we refuse to allow nested VLANs.
+ */
+int vlan_can_be_trunk ( struct net_device *trunk ) {
+
+	return ( ( trunk->ll_protocol->ll_addr_len == ETH_ALEN ) &&
+		 ( trunk->op != &vlan_operations ) );
+}
+
+/**
+ * Create VLAN device
+ *
+ * @v trunk		Trunk network device
+ * @v tag		VLAN tag
+ * @v priority		Default VLAN priority
+ * @ret rc		Return status code
+ */
+int vlan_create ( struct net_device *trunk, unsigned int tag,
+		  unsigned int priority ) {
+	struct net_device *netdev;
+	struct vlan_device *vlan;
+	int rc;
+
+	/* If VLAN already exists, just update the priority */
+	if ( ( netdev = vlan_find ( trunk, tag ) ) != NULL ) {
+		vlan = netdev->priv;
+		if ( priority != vlan->priority ) {
+			DBGC ( netdev, "VLAN %s priority changed from %d to "
+			       "%d\n", netdev->name, vlan->priority, priority );
+		}
+		vlan->priority = priority;
+		return 0;
+	}
+
+	/* Sanity checks */
+	if ( ! vlan_can_be_trunk ( trunk ) ) {
+		DBGC ( trunk, "VLAN %s cannot create VLAN on non-trunk "
+		       "device\n", trunk->name );
+		rc = -ENOTTY;
+		goto err_sanity;
+	}
+	if ( ! VLAN_TAG_IS_VALID ( tag ) ) {
+		DBGC ( trunk, "VLAN %s cannot create VLAN with invalid tag "
+		       "%d\n", trunk->name, tag );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+	if ( ! VLAN_PRIORITY_IS_VALID ( priority ) ) {
+		DBGC ( trunk, "VLAN %s cannot create VLAN with invalid "
+		       "priority %d\n", trunk->name, priority );
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	/* Allocate and initialise structure */
+	netdev = alloc_etherdev ( sizeof ( *vlan ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+	netdev_init ( netdev, &vlan_operations );
+	netdev->dev = trunk->dev;
+	memcpy ( netdev->hw_addr, trunk->ll_addr, ETH_ALEN );
+	vlan = netdev->priv;
+	vlan->trunk = netdev_get ( trunk );
+	vlan->tag = tag;
+	vlan->priority = priority;
+
+	/* Construct VLAN device name */
+	snprintf ( netdev->name, sizeof ( netdev->name ), "%s-%d",
+		   trunk->name, vlan->tag );
+
+	/* Register VLAN device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBGC ( netdev, "VLAN %s could not register: %s\n",
+		       netdev->name, strerror ( rc ) );
+		goto err_register;
+	}
+
+	/* Synchronise with trunk device */
+	vlan_sync ( netdev );
+
+	DBGC ( netdev, "VLAN %s created with tag %d and priority %d\n",
+	       netdev->name, vlan->tag, vlan->priority );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register:
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	netdev_put ( trunk );
+ err_alloc_etherdev:
+ err_sanity:
+	return rc;
+}
+
+/**
+ * Destroy VLAN device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+int vlan_destroy ( struct net_device *netdev ) {
+	struct vlan_device *vlan = netdev->priv;
+	struct net_device *trunk;
+
+	/* Sanity check */
+	if ( netdev->op != &vlan_operations ) {
+		DBGC ( netdev, "VLAN %s cannot destroy non-VLAN device\n",
+		       netdev->name );
+		return -ENOTTY;
+	}
+
+	DBGC ( netdev, "VLAN %s destroyed\n", netdev->name );
+
+	/* Remove VLAN device */
+	unregister_netdev ( netdev );
+	trunk = vlan->trunk;
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+	netdev_put ( trunk );
+
+	return 0;
+}
+
+/**
+ * Do nothing
+ *
+ * @v trunk		Trunk network device
+ * @ret rc		Return status code
+ */
+static int vlan_probe ( struct net_device *trunk __unused ) {
+	return 0;
+}
+
+/**
+ * Handle trunk network device link state change
+ *
+ * @v trunk		Trunk network device
+ */
+static void vlan_notify ( struct net_device *trunk ) {
+	struct net_device *netdev;
+	struct vlan_device *vlan;
+
+	for_each_netdev ( netdev ) {
+		if ( netdev->op != &vlan_operations )
+			continue;
+		vlan = netdev->priv;
+		if ( vlan->trunk == trunk )
+			vlan_sync ( netdev );
+	}
+}
+
+/**
+ * Destroy first VLAN device for a given trunk
+ *
+ * @v trunk		Trunk network device
+ * @ret found		A VLAN device was found
+ */
+static int vlan_remove_first ( struct net_device *trunk ) {
+	struct net_device *netdev;
+	struct vlan_device *vlan;
+
+	for_each_netdev ( netdev ) {
+		if ( netdev->op != &vlan_operations )
+			continue;
+		vlan = netdev->priv;
+		if ( vlan->trunk == trunk ) {
+			vlan_destroy ( netdev );
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Destroy all VLAN devices for a given trunk
+ *
+ * @v trunk		Trunk network device
+ */
+static void vlan_remove ( struct net_device *trunk ) {
+
+	/* Remove all VLAN devices attached to this trunk, safe
+	 * against arbitrary net device removal.
+	 */
+	while ( vlan_remove_first ( trunk ) ) {}
+}
+
+/** VLAN driver */
+struct net_driver vlan_driver __net_driver = {
+	.name = "VLAN",
+	.probe = vlan_probe,
+	.notify = vlan_notify,
+	.remove = vlan_remove,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/bofm_test.c b/qemu-0.15.x/roms/ipxe/src/tests/bofm_test.c
new file mode 100644
index 0000000..6f2e6c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/bofm_test.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/init.h>
+#include <ipxe/pci.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/bofm.h>
+
+/** @file
+ *
+ * IBM BladeCenter Open Fabric Manager (BOFM) tests
+ *
+ */
+
+/** Harvest test table */
+static struct {
+	struct bofm_global_header header;
+	struct bofm_section_header en_header;
+	struct bofm_en en;
+	struct bofm_section_header done;
+} __attribute__ (( packed )) bofmtab_harvest = {
+	.header = {
+		.magic = BOFM_IOAA_MAGIC,
+		.action = BOFM_ACTION_HVST,
+		.version = 0x01,
+		.level = 0x01,
+		.length = sizeof ( bofmtab_harvest ),
+		.profile = "Harvest test profile",
+	},
+	.en_header = {
+		.magic = BOFM_EN_MAGIC,
+		.length = sizeof ( bofmtab_harvest.en ),
+	},
+	.en = {
+		.options = ( BOFM_EN_MAP_PFA | BOFM_EN_USAGE_HARVEST |
+			     BOFM_EN_RQ_HVST_ACTIVE ),
+		.mport = 1,
+	},
+	.done = {
+		.magic = BOFM_DONE_MAGIC,
+	},
+};
+
+/** Update test table */
+static struct {
+	struct bofm_global_header header;
+	struct bofm_section_header en_header;
+	struct bofm_en en;
+	struct bofm_section_header done;
+} __attribute__ (( packed )) bofmtab_update = {
+	.header = {
+		.magic = BOFM_IOAA_MAGIC,
+		.action = BOFM_ACTION_UPDT,
+		.version = 0x01,
+		.level = 0x01,
+		.length = sizeof ( bofmtab_update ),
+		.profile = "Update test profile",
+	},
+	.en_header = {
+		.magic = BOFM_EN_MAGIC,
+		.length = sizeof ( bofmtab_update.en ),
+	},
+	.en = {
+		.options = ( BOFM_EN_MAP_PFA | BOFM_EN_EN_A |
+			     BOFM_EN_USAGE_ENTRY ),
+		.mport = 1,
+		.mac_a = { 0x02, 0x00, 0x69, 0x50, 0x58, 0x45 },
+	},
+	.done = {
+		.magic = BOFM_DONE_MAGIC,
+	},
+};
+
+/**
+ * Perform BOFM test
+ *
+ * @v pci		PCI device
+ */
+void bofm_test ( struct pci_device *pci ) {
+	int bofmrc;
+
+	printf ( "BOFMTEST using " PCI_FMT "\n", PCI_ARGS ( pci ) );
+
+	/* Perform harvest test */
+	printf ( "BOFMTEST performing harvest\n" );
+	bofmtab_harvest.en.busdevfn = pci->busdevfn;
+	DBG_HDA ( 0, &bofmtab_harvest, sizeof ( bofmtab_harvest ) );
+	bofmrc = bofm ( virt_to_user ( &bofmtab_harvest ), pci );
+	printf ( "BOFMTEST harvest result %08x\n", bofmrc );
+	if ( bofmtab_harvest.en.options & BOFM_EN_HVST ) {
+		printf ( "BOFMTEST harvested MAC address %s\n",
+			 eth_ntoa ( &bofmtab_harvest.en.mac_a ) );
+	} else {
+		printf ( "BOFMTEST failed to harvest a MAC address\n" );
+	}
+	DBG_HDA ( 0, &bofmtab_harvest, sizeof ( bofmtab_harvest ) );
+
+	/* Perform update test */
+	printf ( "BOFMTEST performing update\n" );
+	bofmtab_update.en.busdevfn = pci->busdevfn;
+	DBG_HDA ( 0, &bofmtab_update, sizeof ( bofmtab_update ) );
+	bofmrc = bofm ( virt_to_user ( &bofmtab_update ), pci );
+	printf ( "BOFMTEST update result %08x\n", bofmrc );
+	if ( bofmtab_update.en.options & BOFM_EN_CSM_SUCCESS ) {
+		printf ( "BOFMTEST updated MAC address to %s\n",
+			 eth_ntoa ( &bofmtab_update.en.mac_a ) );
+	} else {
+		printf ( "BOFMTEST failed to update MAC address\n" );
+	}
+	DBG_HDA ( 0, &bofmtab_update, sizeof ( bofmtab_update ) );
+}
+
+/**
+ * Perform BOFM test at initialisation time
+ *
+ */
+static void bofm_test_init ( void ) {
+	struct pci_device pci;
+	int busdevfn = -1;
+	int rc;
+
+	/* Uncomment the following line and specify the correct PCI
+	 * bus:dev.fn address in order to perform a BOFM test at
+	 * initialisation time.
+	 */
+	// busdevfn = PCI_BUSDEVFN ( <bus>, <dev>, <fn> );
+
+	/* Skip test if no PCI bus:dev.fn is defined */
+	if ( busdevfn < 0 )
+		return;
+
+	/* Initialise PCI device */
+	memset ( &pci, 0, sizeof ( pci ) );
+	pci_init ( &pci, busdevfn );
+	if ( ( rc = pci_read_config ( &pci ) ) != 0 ) {
+		printf ( "BOFMTEST could not create " PCI_FMT " device: %s\n",
+			 PCI_ARGS ( &pci ), strerror ( rc ) );
+		return;
+	}
+
+	/* Perform test */
+	bofm_test ( &pci );
+}
+
+/** BOFM test initialisation function */
+struct init_fn bofm_test_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = bofm_test_init,
+};
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/comboot/shuffle-simple.asm b/qemu-0.15.x/roms/ipxe/src/tests/comboot/shuffle-simple.asm
new file mode 100644
index 0000000..efc7d9b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/comboot/shuffle-simple.asm
@@ -0,0 +1,40 @@
+	bits 16
+	org 100h
+
+	jmp start
+	
+shuffle_start:
+	push 0xB800
+	pop es
+	mov cx, 80*24*2
+	mov ax, 'AA'
+	xor di, di
+	rep stosw
+.lbl:	jmp .lbl
+shuffle_end:
+	nop
+shuffle_len equ (shuffle_end - shuffle_start + 1)
+
+start:
+	; calculate physical address of shuffled part
+	xor eax, eax
+	push ds
+	pop ax
+	shl eax, 4
+	add ax, shuffle_start
+	mov dword [source], eax
+
+	mov ax, 0012h
+	mov di, shuffle_descriptors
+	mov cx, num_shuffle_descriptors
+	mov ebp, 0x7c00
+	int 22h
+	int3
+
+shuffle_descriptors:
+	dd 0x7C00
+source:	dd 0
+	dd shuffle_len
+
+num_shuffle_descriptors equ 1
+
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/comboot/version.asm b/qemu-0.15.x/roms/ipxe/src/tests/comboot/version.asm
new file mode 100644
index 0000000..0114042
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/comboot/version.asm
@@ -0,0 +1,136 @@
+	bits 16
+	org 100h
+
+_start:
+	; first check for SYSLINUX
+	mov ah, 30h
+	int 21h
+
+	cmp eax, 59530000h
+	jne .not_syslinux
+	cmp ebx, 4c530000h
+	jne .not_syslinux
+	cmp ecx, 4e490000h
+	jne .not_syslinux
+	cmp edx, 58550000h
+	jne .not_syslinux
+
+	; now get syslinux version
+	mov ax, 0001h
+	int 22h
+
+	push cx
+	push dx
+	push di
+	push si
+	push es
+
+	; print version string
+	mov dx, str_version
+	mov ah, 09h
+	int 21h
+
+	pop es
+	pop bx
+	push es
+	mov ax, 0002h
+	int 22h
+
+	; print copyright string
+	mov dx, str_copyright
+	mov ah, 09h
+	int 21h
+
+	pop es
+	pop bx
+	mov ax, 0002h
+	int 22h
+
+	; print syslinux derivative id
+	mov dx, str_derivative
+	mov ah, 09h
+	int 21h
+
+	pop ax
+	call print_hex_byte
+
+	; print version number
+	mov dx, str_version_num
+	mov ah, 09h
+	int 21h
+
+	pop cx
+	push cx
+	mov ax, cx
+	and ax, 0FFh
+	call print_dec_word
+
+	mov dl, '.'
+	mov ah, 02h
+	int 21h
+
+	pop cx
+	mov ax, cx
+	shr ax, 8
+	call print_dec_word
+
+	ret
+
+
+.not_syslinux:
+	mov dx, str_not_syslinux
+	mov ah, 09h
+	int 21h
+	ret
+
+; input: al = byte to print in hex
+print_hex_byte:
+	push ax
+	shr al, 4
+	call print_hex_nybble
+	pop ax
+	call print_hex_nybble
+	ret
+
+; input: bottom half of al = nybble to print in hex
+print_hex_nybble:
+	push ax
+	mov bl, al
+	and bx, 1111b
+	mov dl, [str_hex + bx]
+	mov ah, 02h
+	int 21h
+	pop ax
+	ret
+
+str_hex: db "01234567890abcdef"
+
+; input: ax = word to print
+print_dec_word:
+	mov cx, 10
+	mov word [.count], 0
+.loop:
+	xor dx, dx
+	div cx
+	inc word [.count]
+	push dx
+	test ax, ax
+	jnz .loop
+
+.print:
+	pop dx
+	add dx, '0'
+	mov ah, 02h
+	int 21h
+	dec word [.count]
+	jnz .print
+
+	ret
+
+.count:	dw 0
+
+str_not_syslinux: db "Not SYSLINUX or derivative (running on DOS?)$"
+str_version: db "Version: $"
+str_copyright: db 10, "Copyright: $"
+str_derivative: db 10, "Derivative ID: 0x$"
+str_version_num: db 10, "Version number: $"
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.S b/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.S
new file mode 100644
index 0000000..739b052
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.S
@@ -0,0 +1,54 @@
+	.arch i386
+
+	.section ".data", "aw", @progbits
+watch_me:
+	.long 0xfeedbeef
+
+	.section ".text", "ax", @progbits
+	.code32
+gdbstub_test:
+	/* 1. Read registers test */
+	movl    $0xea010203, %eax
+	movl    $0xeb040506, %ebx
+	movl    $0xec070809, %ecx
+	movl    $0xed0a0b0c, %edx
+	movl    $0x510d0e0f, %esi
+	movl    $0xd1102030, %edi
+	int	$3
+
+	/* 2. Write registers test */
+	int	$3
+
+	/* 3. Read memory test */
+	subl	$8, %esp
+	movl	$0x11223344, 4(%esp)
+	movw	$0x5566, 2(%esp)
+	movb	$0x77, (%esp)
+	int	$3
+
+	/* 4. Write memory test */
+	int	$3
+	addl	$8, %esp
+
+	/* 5. Step test */
+	int	$3
+	nop
+
+	/* 6. Access watch test */
+	movl	$0x600d0000, %ecx
+	movl	watch_me, %eax
+	movl	$0xbad00000, %ecx
+	int	$3
+	movl	$0x600d0001, %ecx
+	movl	%eax, watch_me
+	movl	$0xbad00001, %ecx
+	int	$3
+
+	/* 7. Write watch test */
+	movl	$0x600d0002, %ecx
+	movl	%eax, watch_me
+	movl	$0xbad00002, %ecx
+	int	$3
+
+1:
+	jmp	1b
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.gdb b/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.gdb
new file mode 100755
index 0000000..bcfa07d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/gdbstub_test.gdb
@@ -0,0 +1,116 @@
+#!/usr/bin/gdb -x
+# Test suite for GDB remote debugging
+# Run:
+#   make bin/ipxe.hd.tmp
+#   make
+#   gdb
+#   (gdb) target remote :TCPPORT
+#   OR
+#   (gdb) target remote udp:IP:UDPPORT
+#   (gdb) source tests/gdbstub_test.gdb
+
+define ipxe_load_symbols
+	file bin/ipxe.hd.tmp
+end
+
+define ipxe_assert
+	if $arg0 != $arg1
+		echo FAIL $arg2\n
+	else
+		echo PASS $arg2\n
+	end
+end
+
+define ipxe_start_tests
+	jump gdbstub_test
+end
+
+define ipxe_test_regs_read
+	ipxe_assert $eax 0xea010203 "ipxe_test_regs_read eax"
+	ipxe_assert $ebx 0xeb040506 "ipxe_test_regs_read ebx"
+	ipxe_assert $ecx 0xec070809 "ipxe_test_regs_read ecx"
+	ipxe_assert $edx 0xed0a0b0c "ipxe_test_regs_read edx"
+	ipxe_assert $esi 0x510d0e0f "ipxe_test_regs_read esi"
+	ipxe_assert $edi 0xd1102030 "ipxe_test_regs_read edi"
+end
+
+define ipxe_test_regs_write
+	set $eax = 0xea112233
+	set $ebx = 0xeb445566
+	set $ecx = 0xec778899
+	set $edx = 0xedaabbcc
+	set $esi = 0x51ddeeff
+	set $edi = 0xd1010203
+	c
+	ipxe_assert $eax 0xea112233 "ipxe_test_regs_write eax"
+	ipxe_assert $ebx 0xeb445566 "ipxe_test_regs_write ebx"
+	ipxe_assert $ecx 0xec778899 "ipxe_test_regs_write ecx"
+	ipxe_assert $edx 0xedaabbcc "ipxe_test_regs_write edx"
+	ipxe_assert $esi 0x51ddeeff "ipxe_test_regs_write esi"
+	ipxe_assert $edi 0xd1010203 "ipxe_test_regs_write edi"
+
+	# This assumes segment selectors are always 0x10 or 0x8 (for code).
+	ipxe_assert $cs 0x08 "ipxe_test_regs_write cs"
+	ipxe_assert $ds 0x10 "ipxe_test_regs_write ds"
+end
+
+define ipxe_test_mem_read
+	c
+	ipxe_assert ({int}($esp+4)) 0x11223344 "ipxe_test_mem_read int"
+	ipxe_assert ({short}($esp+2)) 0x5566 "ipxe_test_mem_read short"
+	ipxe_assert ({char}($esp)) 0x77 "ipxe_test_mem_read char"
+end
+
+define ipxe_test_mem_write
+	set ({int}($esp+4)) = 0xaabbccdd
+	set ({short}($esp+2)) = 0xeeff
+	set ({char}($esp)) = 0x99
+	c
+	ipxe_assert ({int}($esp+4)) 0xaabbccdd "ipxe_test_mem_write int"
+	ipxe_assert ({short}($esp+2)) (short)0xeeff "ipxe_test_mem_write short"
+	ipxe_assert ({char}($esp)) (char)0x99 "ipxe_test_mem_write char"
+end
+
+define ipxe_test_step
+	c
+	si
+	ipxe_assert ({char}($eip-1)) (char)0x90 "ipxe_test_step" # nop = 0x90
+end
+
+define ipxe_test_awatch
+	awatch watch_me
+
+	c
+	ipxe_assert $ecx 0x600d0000 "ipxe_test_awatch read"
+	if $ecx == 0x600d0000
+		c
+	end
+
+	c
+	ipxe_assert $ecx 0x600d0001 "ipxe_test_awatch write"
+	if $ecx == 0x600d0001
+		c
+	end
+
+	delete
+end
+
+define ipxe_test_watch
+	watch watch_me
+	c
+	ipxe_assert $ecx 0x600d0002 "ipxe_test_watch"
+	if $ecx == 0x600d0002
+		c
+	end
+	delete
+end
+
+ipxe_load_symbols
+ipxe_start_tests
+ipxe_test_regs_read
+ipxe_test_regs_write
+ipxe_test_mem_read
+ipxe_test_mem_write
+ipxe_test_step
+ipxe_test_awatch
+ipxe_test_watch
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/linebuf_test.c b/qemu-0.15.x/roms/ipxe/src/tests/linebuf_test.c
new file mode 100644
index 0000000..e06ac7d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/linebuf_test.c
@@ -0,0 +1,35 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/linebuf.h>
+
+static const char data1[] = 
+"Hello world\r\n"
+"This is a reasonably nice set of lines\n"
+"with not many different terminators\r\n\r\n"
+"There should be exactly one blank line above\n"
+"and this line should never appear at all since it has no terminator";
+
+void linebuf_test ( void ) {
+	struct line_buffer linebuf;
+	const char *data = data1;
+	size_t len = ( sizeof ( data1 ) - 1 /* be mean; strip the NUL */ );
+	ssize_t frag_len;
+	char *line;
+
+	memset ( &linebuf, 0, sizeof ( linebuf ) );
+	while ( len ) {
+		frag_len = line_buffer ( &linebuf, data, len );
+		if ( frag_len < 0 ) {
+			printf ( "line_buffer() failed: %s\n",
+				 strerror ( frag_len ) );
+			return;
+		}
+		data += frag_len;
+		len -= frag_len;
+		if ( ( line = buffered_line ( &linebuf ) ) )
+			printf ( "\"%s\"\n", line );
+	}
+
+	empty_line_buffer ( &linebuf );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/memcpy_test.c b/qemu-0.15.x/roms/ipxe/src/tests/memcpy_test.c
new file mode 100644
index 0000000..7626e63
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/memcpy_test.c
@@ -0,0 +1,39 @@
+#include <string.h>
+
+/*
+ * This file exists for testing the compilation of memcpy() with the
+ * various constant-length optimisations.
+ *
+ */
+
+#define __regparm __attribute__ (( regparm(3) ))
+
+void __regparm memcpy_0 ( void *dest, void *src ) { memcpy ( dest, src, 0 ); }
+void __regparm memcpy_1 ( void *dest, void *src ) { memcpy ( dest, src, 1 ); }
+void __regparm memcpy_2 ( void *dest, void *src ) { memcpy ( dest, src, 2 ); }
+void __regparm memcpy_3 ( void *dest, void *src ) { memcpy ( dest, src, 3 ); }
+void __regparm memcpy_4 ( void *dest, void *src ) { memcpy ( dest, src, 4 ); }
+void __regparm memcpy_5 ( void *dest, void *src ) { memcpy ( dest, src, 5 ); }
+void __regparm memcpy_6 ( void *dest, void *src ) { memcpy ( dest, src, 6 ); }
+void __regparm memcpy_7 ( void *dest, void *src ) { memcpy ( dest, src, 7 ); }
+void __regparm memcpy_8 ( void *dest, void *src ) { memcpy ( dest, src, 8 ); }
+void __regparm memcpy_9 ( void *dest, void *src ) { memcpy ( dest, src, 9 ); }
+void __regparm memcpy_10 ( void *dest, void *src ) { memcpy ( dest, src, 10 ); }
+void __regparm memcpy_11 ( void *dest, void *src ) { memcpy ( dest, src, 11 ); }
+void __regparm memcpy_12 ( void *dest, void *src ) { memcpy ( dest, src, 12 ); }
+void __regparm memcpy_13 ( void *dest, void *src ) { memcpy ( dest, src, 13 ); }
+void __regparm memcpy_14 ( void *dest, void *src ) { memcpy ( dest, src, 14 ); }
+void __regparm memcpy_15 ( void *dest, void *src ) { memcpy ( dest, src, 15 ); }
+void __regparm memcpy_16 ( void *dest, void *src ) { memcpy ( dest, src, 16 ); }
+void __regparm memcpy_17 ( void *dest, void *src ) { memcpy ( dest, src, 17 ); }
+void __regparm memcpy_18 ( void *dest, void *src ) { memcpy ( dest, src, 18 ); }
+void __regparm memcpy_19 ( void *dest, void *src ) { memcpy ( dest, src, 19 ); }
+void __regparm memcpy_20 ( void *dest, void *src ) { memcpy ( dest, src, 20 ); }
+void __regparm memcpy_21 ( void *dest, void *src ) { memcpy ( dest, src, 21 ); }
+void __regparm memcpy_22 ( void *dest, void *src ) { memcpy ( dest, src, 22 ); }
+void __regparm memcpy_23 ( void *dest, void *src ) { memcpy ( dest, src, 23 ); }
+void __regparm memcpy_24 ( void *dest, void *src ) { memcpy ( dest, src, 24 ); }
+void __regparm memcpy_25 ( void *dest, void *src ) { memcpy ( dest, src, 25 ); }
+void __regparm memcpy_26 ( void *dest, void *src ) { memcpy ( dest, src, 26 ); }
+void __regparm memcpy_27 ( void *dest, void *src ) { memcpy ( dest, src, 27 ); }
+void __regparm memcpy_28 ( void *dest, void *src ) { memcpy ( dest, src, 28 ); }
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/umalloc_test.c b/qemu-0.15.x/roms/ipxe/src/tests/umalloc_test.c
new file mode 100644
index 0000000..5381083
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/umalloc_test.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/io.h>
+
+void umalloc_test ( void ) {
+	struct memory_map memmap;
+	userptr_t bob;
+	userptr_t fred;
+
+	printf ( "Before allocation:\n" );
+	get_memmap ( &memmap );
+
+	bob = umalloc ( 1234 );
+	bob = urealloc ( bob, 12345 );
+	fred = umalloc ( 999 );
+
+	printf ( "After allocation:\n" );
+	get_memmap ( &memmap );
+
+	ufree ( bob );
+	ufree ( fred );
+
+	printf ( "After freeing:\n" );
+	get_memmap ( &memmap );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/tests/uri_test.c b/qemu-0.15.x/roms/ipxe/src/tests/uri_test.c
new file mode 100644
index 0000000..c39c7ff
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/tests/uri_test.c
@@ -0,0 +1,146 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/uri.h>
+
+#define URI_MAX_LEN 1024
+
+struct uri_test {
+	const char *base_uri_string;
+	const char *relative_uri_string;
+	const char *resolved_uri_string;
+};
+
+static struct uri_test uri_tests[] = {
+	{ "http://www.fensystems.co.uk", "",
+	  "http://www.fensystems.co.uk/" },
+	{ "http://ipxe.org/wiki/page1", "page2",
+	  "http://ipxe.org/wiki/page2" },
+	{ "http://ipxe.org/wiki/page1", "../page3",
+	  "http://ipxe.org/page3" },
+	{ "tftp://192.168.0.1/", "/tftpboot/vmlinuz",
+	  "tftp://192.168.0.1/tftpboot/vmlinuz" },
+	{ "ftp://the%41nswer%3d:%34ty%32wo@ether%62oot.org:8080/p%41th/foo",
+	  "to?%41=b#%43d",
+	  "ftp://theAnswer%3d:4ty2wo@ipxe.org:8080/path/to?a=b#cd" },
+#if 0
+	"http://www.ipxe.org/wiki",
+	"mailto:bob at nowhere.com",
+	"ftp://joe:secret@insecure.org:8081/hidden/path/to?what=is#this",
+#endif
+};
+
+static int test_parse_unparse ( const char *uri_string ) {
+	char buf[URI_MAX_LEN];
+	struct uri *uri = NULL;
+	int rc;
+
+	/* Parse and unparse URI */
+	uri = parse_uri ( uri_string );
+	if ( ! uri ) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	unparse_uri ( buf, sizeof ( buf ), uri, URI_ALL );
+
+	/* Compare result */
+	if ( strcmp ( buf, uri_string ) != 0 ) {
+		printf ( "Unparse of \"%s\" produced \"%s\"\n",
+			 uri_string, buf );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	rc = 0;
+
+ done:
+	uri_put ( uri );
+	if ( rc ) {
+		printf ( "URI parse-unparse of \"%s\" failed: %s\n",
+			 uri_string, strerror ( rc ) );
+	}
+	return rc;
+}
+
+static int test_resolve ( const char *base_uri_string,
+			  const char *relative_uri_string,
+			  const char *resolved_uri_string ) {
+	struct uri *base_uri = NULL;
+	struct uri *relative_uri = NULL;
+	struct uri *resolved_uri = NULL;
+	char buf[URI_MAX_LEN];
+	int rc;
+
+	/* Parse URIs */
+	base_uri = parse_uri ( base_uri_string );
+	if ( ! base_uri ) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	relative_uri = parse_uri ( relative_uri_string );
+	if ( ! relative_uri ) {
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	/* Resolve URI */
+	resolved_uri = resolve_uri ( base_uri, relative_uri );
+	if ( ! resolved_uri ) {
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	/* Compare result */
+	unparse_uri ( buf, sizeof ( buf ), resolved_uri, URI_ALL );
+	if ( strcmp ( buf, resolved_uri_string ) != 0 ) {
+		printf ( "Resolution of \"%s\"+\"%s\" produced \"%s\"\n",
+			 base_uri_string, relative_uri_string, buf );
+		rc = -EINVAL;
+		goto done;
+	}
+
+	rc = 0;
+
+ done:
+	uri_put ( base_uri );
+	uri_put ( relative_uri );
+	uri_put ( resolved_uri );
+	if ( rc ) {
+		printf ( "URI resolution of \"%s\"+\"%s\" failed: %s\n",
+			 base_uri_string, relative_uri_string,
+			 strerror ( rc ) );
+	}
+	return rc;
+}
+
+int uri_test ( void ) {
+	unsigned int i;
+	struct uri_test *uri_test;
+	int rc;
+	int overall_rc = 0;
+
+	for ( i = 0 ; i < ( sizeof ( uri_tests ) /
+			    sizeof ( uri_tests[0] ) ) ; i++ ) {
+		uri_test = &uri_tests[i];
+		rc = test_parse_unparse ( uri_test->base_uri_string );
+		if ( rc != 0 )
+			overall_rc = rc;
+		rc = test_parse_unparse ( uri_test->relative_uri_string );
+		if ( rc != 0 )
+			overall_rc = rc;
+		rc = test_parse_unparse ( uri_test->resolved_uri_string );
+		if ( rc != 0 )
+			overall_rc = rc;
+		rc = test_resolve ( uri_test->base_uri_string,
+				    uri_test->relative_uri_string,
+				    uri_test->resolved_uri_string );
+		if ( rc != 0 )
+			overall_rc = rc;
+	}
+
+	if ( overall_rc )
+		printf ( "URI tests failed: %s\n", strerror ( overall_rc ) );
+	return overall_rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/autoboot.c b/qemu-0.15.x/roms/ipxe/src/usr/autoboot.c
new file mode 100644
index 0000000..c5c5f3e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/autoboot.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/image.h>
+#include <ipxe/sanboot.h>
+#include <ipxe/uri.h>
+#include <ipxe/open.h>
+#include <ipxe/init.h>
+#include <usr/ifmgmt.h>
+#include <usr/route.h>
+#include <usr/dhcpmgmt.h>
+#include <usr/imgmgmt.h>
+#include <usr/autoboot.h>
+
+/** @file
+ *
+ * Automatic booting
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define ENOENT_BOOT __einfo_error ( EINFO_ENOENT_BOOT )
+#define EINFO_ENOENT_BOOT \
+	__einfo_uniqify ( EINFO_ENOENT, 0x01, "Nothing to boot" )
+
+/**
+ * Perform PXE menu boot when PXE stack is not available
+ */
+__weak int pxe_menu_boot ( struct net_device *netdev __unused ) {
+	return -ENOTSUP;
+}
+
+/**
+ * Identify the boot network device
+ *
+ * @ret netdev		Boot network device
+ */
+static struct net_device * find_boot_netdev ( void ) {
+	return NULL;
+}
+
+/**
+ * Parse next-server and filename into a URI
+ *
+ * @v next_server	Next-server address
+ * @v filename		Filename
+ * @ret uri		URI, or NULL on failure
+ */
+static struct uri * parse_next_server_and_filename ( struct in_addr next_server,
+						     const char *filename ) {
+	char buf[ 23 /* "tftp://xxx.xxx.xxx.xxx/" */ + strlen ( filename )
+		  + 1 /* NUL */ ];
+	struct uri *uri;
+
+	/* Parse filename */
+	uri = parse_uri ( filename );
+	if ( ! uri )
+		return NULL;
+
+	/* Construct a tftp:// URI for the filename, if applicable.
+	 * We can't just rely on the current working URI, because the
+	 * relative URI resolution will remove the distinction between
+	 * filenames with and without initial slashes, which is
+	 * significant for TFTP.
+	 */
+	if ( next_server.s_addr && filename[0] && ! uri_is_absolute ( uri ) ) {
+		uri_put ( uri );
+		snprintf ( buf, sizeof ( buf ), "tftp://%s/%s",
+			   inet_ntoa ( next_server ), filename );
+		uri = parse_uri ( buf );
+		if ( ! uri )
+			return NULL;
+	}
+
+	return uri;
+}
+
+/** The "keep-san" setting */
+struct setting keep_san_setting __setting ( SETTING_SANBOOT_EXTRA ) = {
+	.name = "keep-san",
+	.description = "Preserve SAN connection",
+	.tag = DHCP_EB_KEEP_SAN,
+	.type = &setting_type_int8,
+};
+
+/** The "skip-san-boot" setting */
+struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA ) = {
+	.name = "skip-san-boot",
+	.description = "Do not boot from SAN device",
+	.tag = DHCP_EB_SKIP_SAN_BOOT,
+	.type = &setting_type_int8,
+};
+
+/**
+ * Boot from filename and root-path URIs
+ *
+ * @v filename		Filename
+ * @v root_path		Root path
+ * @ret rc		Return status code
+ */
+int uriboot ( struct uri *filename, struct uri *root_path ) {
+	int drive;
+	int rc;
+
+	/* Treat empty URIs as absent */
+	if ( filename && ( ! uri_has_path ( filename ) ) )
+		filename = NULL;
+	if ( root_path && ( ! uri_is_absolute ( root_path ) ) )
+		root_path = NULL;
+
+	/* If we have both a filename and a root path, ignore an
+	 * unsupported URI scheme in the root path, since it may
+	 * represent an NFS root.
+	 */
+	if ( filename && root_path &&
+	     ( xfer_uri_opener ( root_path->scheme ) == NULL ) ) {
+		printf ( "Ignoring unsupported root path\n" );
+		root_path = NULL;
+	}
+
+	/* Check that we have something to boot */
+	if ( ! ( filename || root_path ) ) {
+		rc = -ENOENT_BOOT;
+		printf ( "Nothing to boot: %s\n", strerror ( rc ) );
+		goto err_no_boot;
+	}
+
+	/* Hook SAN device, if applicable */
+	if ( root_path ) {
+		drive = san_hook ( root_path, 0 );
+		if ( drive < 0 ) {
+			rc = drive;
+			printf ( "Could not open SAN device: %s\n",
+				 strerror ( rc ) );
+			goto err_san_hook;
+		}
+		printf ( "Registered as SAN device %#02x\n", drive );
+	} else {
+		drive = -ENODEV;
+	}
+
+	/* Describe SAN device, if applicable */
+	if ( ( drive >= 0 ) && ( ( rc = san_describe ( drive ) ) != 0 ) ) {
+		printf ( "Could not describe SAN device %#02x: %s\n",
+			 drive, strerror ( rc ) );
+		goto err_san_describe;
+	}
+
+	/* Allow a root-path-only boot with skip-san enabled to succeed */
+	rc = 0;
+
+	/* Attempt filename boot if applicable */
+	if ( filename ) {
+		if ( ( rc = imgdownload ( filename, NULL, NULL,
+					  register_and_boot_image ) ) != 0 ) {
+			printf ( "\nCould not chain image: %s\n",
+				 strerror ( rc ) );
+			/* Fall through to (possibly) attempt a SAN boot
+			 * as a fallback.  If no SAN boot is attempted,
+			 * our status will become the return status.
+			 */
+		} else {
+			/* Always print an extra newline, because we
+			 * don't know where the NBP may have left the
+			 * cursor.
+			 */
+			printf ( "\n" );
+		}
+	}
+
+	/* Attempt SAN boot if applicable */
+	if ( root_path ) {
+		if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) {
+			printf ( "Booting from SAN device %#02x\n", drive );
+			rc = san_boot ( drive );
+			printf ( "Boot from SAN device %#02x failed: %s\n",
+				 drive, strerror ( rc ) );
+		} else {
+			printf ( "Skipping boot from SAN device %#02x\n",
+				 drive );
+			/* Avoid overwriting a possible failure status
+			 * from a filename boot.
+			 */
+		}
+	}
+
+ err_san_describe:
+	/* Unhook SAN device, if applicable */
+	if ( drive >= 0 ) {
+		if ( fetch_intz_setting ( NULL, &keep_san_setting ) == 0 ) {
+			printf ( "Unregistering SAN device %#02x\n", drive );
+			san_unhook ( drive );
+		} else {
+			printf ( "Preserving connection to SAN device %#02x\n",
+				 drive );
+		}
+	}
+ err_san_hook:
+ err_no_boot:
+	return rc;
+}
+
+/**
+ * Close all open net devices
+ *
+ * Called before a fresh boot attempt in order to free up memory.  We
+ * don't just close the device immediately after the boot fails,
+ * because there may still be TCP connections in the process of
+ * closing.
+ */
+static void close_all_netdevs ( void ) {
+	struct net_device *netdev;
+
+	for_each_netdev ( netdev ) {
+		ifclose ( netdev );
+	}
+}
+
+/**
+ * Fetch next-server and filename settings into a URI
+ *
+ * @v settings		Settings block
+ * @ret uri		URI, or NULL on failure
+ */
+struct uri * fetch_next_server_and_filename ( struct settings *settings ) {
+	struct in_addr next_server;
+	char buf[256];
+	char *filename;
+	struct uri *uri;
+
+	/* Fetch next-server setting */
+	fetch_ipv4_setting ( settings, &next_server_setting, &next_server );
+	if ( next_server.s_addr )
+		printf ( "Next server: %s\n", inet_ntoa ( next_server ) );
+
+	/* Fetch filename setting */
+	fetch_string_setting ( settings, &filename_setting,
+			       buf, sizeof ( buf ) );
+	if ( buf[0] )
+		printf ( "Filename: %s\n", buf );
+
+	/* Expand filename setting */
+	filename = expand_settings ( buf );
+	if ( ! filename )
+		return NULL;
+
+	/* Parse next server and filename */
+	uri = parse_next_server_and_filename ( next_server, filename );
+
+	free ( filename );
+	return uri;
+}
+
+/**
+ * Fetch root-path setting into a URI
+ *
+ * @v settings		Settings block
+ * @ret uri		URI, or NULL on failure
+ */
+static struct uri * fetch_root_path ( struct settings *settings ) {
+	char buf[256];
+	char *root_path;
+	struct uri *uri;
+
+	/* Fetch root-path setting */
+	fetch_string_setting ( settings, &root_path_setting,
+			       buf, sizeof ( buf ) );
+	if ( buf[0] )
+		printf ( "Root path: %s\n", buf );
+
+	/* Expand filename setting */
+	root_path = expand_settings ( buf );
+	if ( ! root_path )
+		return NULL;
+
+	/* Parse root path */
+	uri = parse_uri ( root_path );
+
+	free ( root_path );
+	return uri;
+}
+
+/**
+ * Check whether or not we have a usable PXE menu
+ *
+ * @ret have_menu	A usable PXE menu is present
+ */
+static int have_pxe_menu ( void ) {
+	struct setting vendor_class_id_setting
+		= { .tag = DHCP_VENDOR_CLASS_ID };
+	struct setting pxe_discovery_control_setting
+		= { .tag = DHCP_PXE_DISCOVERY_CONTROL };
+	struct setting pxe_boot_menu_setting
+		= { .tag = DHCP_PXE_BOOT_MENU };
+	char buf[256];
+	unsigned int pxe_discovery_control;
+
+	fetch_string_setting ( NULL, &vendor_class_id_setting,
+			       buf, sizeof ( buf ) );
+	pxe_discovery_control =
+		fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
+
+	return ( ( strcmp ( buf, "PXEClient" ) == 0 ) &&
+		 setting_exists ( NULL, &pxe_boot_menu_setting ) &&
+		 ( ! ( ( pxe_discovery_control & PXEBS_SKIP ) &&
+		       setting_exists ( NULL, &filename_setting ) ) ) );
+}
+
+/**
+ * Boot from a network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+int netboot ( struct net_device *netdev ) {
+	struct uri *filename;
+	struct uri *root_path;
+	int rc;
+
+	/* Close all other network devices */
+	close_all_netdevs();
+
+	/* Open device and display device status */
+	if ( ( rc = ifopen ( netdev ) ) != 0 )
+		goto err_ifopen;
+	ifstat ( netdev );
+
+	/* Configure device via DHCP */
+	if ( ( rc = dhcp ( netdev ) ) != 0 )
+		goto err_dhcp;
+	route();
+
+	/* Try PXE menu boot, if applicable */
+	if ( have_pxe_menu() ) {
+		printf ( "Booting from PXE menu\n" );
+		rc = pxe_menu_boot ( netdev );
+		goto err_pxe_menu_boot;
+	}
+
+	/* Fetch next server, filename and root path */
+	filename = fetch_next_server_and_filename ( NULL );
+	if ( ! filename )
+		goto err_filename;
+	root_path = fetch_root_path ( NULL );
+	if ( ! root_path )
+		goto err_root_path;
+
+	/* Boot using next server, filename and root path */
+	if ( ( rc = uriboot ( filename, root_path ) ) != 0 )
+		goto err_uriboot;
+
+ err_uriboot:
+	uri_put ( root_path );
+ err_root_path:
+	uri_put ( filename );
+ err_filename:
+ err_pxe_menu_boot:
+ err_dhcp:
+ err_ifopen:
+	return rc;
+}
+
+/**
+ * Boot the system
+ */
+int autoboot ( void ) {
+	struct net_device *boot_netdev;
+	struct net_device *netdev;
+	int rc = -ENODEV;
+
+	/* If we have an identifable boot device, try that first */
+	if ( ( boot_netdev = find_boot_netdev() ) )
+		rc = netboot ( boot_netdev );
+
+	/* If that fails, try booting from any of the other devices */
+	for_each_netdev ( netdev ) {
+		if ( netdev == boot_netdev )
+			continue;
+		rc = netboot ( netdev );
+	}
+
+	printf ( "No more network devices\n" );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/dhcpmgmt.c b/qemu-0.15.x/roms/ipxe/src/usr/dhcpmgmt.c
new file mode 100644
index 0000000..e651dfd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/dhcpmgmt.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/monojob.h>
+#include <ipxe/process.h>
+#include <usr/ifmgmt.h>
+#include <usr/dhcpmgmt.h>
+
+#define LINK_WAIT_MS	15000
+
+/** @file
+ *
+ * DHCP management
+ *
+ */
+
+int dhcp ( struct net_device *netdev ) {
+	struct dhcphdr *dhcphdr;
+	typeof ( dhcphdr->chaddr ) chaddr;
+	unsigned int hlen;
+	unsigned int i;
+	int rc;
+
+	/* Check we can open the interface first */
+	if ( ( rc = ifopen ( netdev ) ) != 0 )
+		return rc;
+
+	/* Wait for link-up */
+	if ( ( rc = iflinkwait ( netdev, LINK_WAIT_MS ) ) != 0 )
+		return rc;
+
+	/* Perform DHCP */
+	printf ( "DHCP (%s", netdev->name );
+	hlen = dhcp_chaddr ( netdev, chaddr, NULL );
+	for ( i = 0 ; i < hlen ; i++ )
+		printf ( "%c%02x", ( i ? ':' : ' ' ), chaddr[i] );
+	printf ( ")" );
+
+	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) {
+		rc = monojob_wait ( "" );
+	} else if ( rc > 0 ) {
+		printf ( " using cached\n" );
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int pxebs ( struct net_device *netdev, unsigned int pxe_type ) {
+	int rc;
+
+	/* Perform PXE Boot Server Discovery */
+	printf ( "PXEBS (%s type %d)", netdev->name, pxe_type );
+	if ( ( rc = start_pxebs ( &monojob, netdev, pxe_type ) ) == 0 )
+		rc = monojob_wait ( "" );
+
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/fcmgmt.c b/qemu-0.15.x/roms/ipxe/src/usr/fcmgmt.c
new file mode 100644
index 0000000..1af723d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/fcmgmt.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/fc.h>
+#include <ipxe/fcels.h>
+#include <ipxe/monojob.h>
+#include <usr/fcmgmt.h>
+
+/** @file
+ *
+ * Fibre Channel management
+ *
+ */
+
+/**
+ * Print status of Fibre Channel port
+ *
+ * @v port		Fibre Channel port
+ */
+void fcportstat ( struct fc_port *port ) {
+	printf ( "%s: %s id %s", port->name, fc_ntoa ( &port->port_wwn ),
+		 fc_id_ntoa ( &port->port_id ) );
+	printf ( " node %s\n  [Link:", fc_ntoa ( &port->node_wwn ) );
+	if ( fc_link_ok ( &port->link ) ) {
+		printf ( " up, %s", fc_ntoa ( &port->link_port_wwn ) );
+		if ( ( port->flags & FC_PORT_HAS_FABRIC ) ) {
+			printf ( " fabric" );
+		} else {
+			printf ( " id %s",
+				 fc_id_ntoa ( &port->ptp_link_port_id ) );
+		}
+		printf ( " node %s]\n", fc_ntoa ( &port->link_node_wwn ) );
+	} else {
+		printf ( " down: %s]\n", strerror ( port->link.rc ) );
+	}
+}
+
+/**
+ * Print status of Fibre Channel peer
+ *
+ * @v peer		Fibre Channel peer
+ */
+void fcpeerstat ( struct fc_peer *peer ) {
+	struct fc_ulp *ulp;
+	uint8_t *param;
+	unsigned int i;
+
+	printf ( "%s:\n  [Link:", fc_ntoa ( &peer->port_wwn ) );
+	if ( fc_link_ok ( &peer->link ) ) {
+		printf ( " up, port %s id %s]\n", peer->port->name,
+			 fc_id_ntoa ( &peer->port_id ) );
+	} else {
+		printf ( " down: %s]\n", strerror ( peer->link.rc ) );
+	}
+
+	list_for_each_entry ( ulp, &peer->ulps, list ) {
+		printf ( "  [Type %02x usage %d link:",
+			 ulp->type, ulp->usage );
+		if ( fc_link_ok ( &ulp->link ) ) {
+			printf ( " up, params" );
+			param = ulp->param;
+			for ( i = 0 ; i < ulp->param_len ; i++ ) {
+				printf ( "%c%02x", ( ( i == 0 ) ? ' ' : ':' ),
+					 param[i] );
+			}
+		} else {
+			printf ( " down: %s", strerror ( ulp->link.rc ) );
+		}
+		printf ( "]\n" );
+	}
+}
+
+/**
+ * Issue Fibre Channel ELS
+ *
+ * @v port		Fibre Channel port
+ * @v peer_port_id	Peer port ID
+ * @v handler		ELS handler
+ * @ret rc		Return status code
+ */
+int fcels ( struct fc_port *port, struct fc_port_id *peer_port_id,
+	    struct fc_els_handler *handler ) {
+	int rc;
+
+	/* Initiate ELS */
+	printf ( "%s %s to %s...",
+		 port->name, handler->name, fc_id_ntoa ( peer_port_id ) );
+	if ( ( rc = fc_els_request ( &monojob, port, peer_port_id,
+				     handler ) ) != 0 ) {
+		printf ( "%s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	/* Wait for ELS to complete */
+	return monojob_wait ( "" );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/ifmgmt.c b/qemu-0.15.x/roms/ipxe/src/usr/ifmgmt.c
new file mode 100644
index 0000000..0498515
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/ifmgmt.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/console.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/device.h>
+#include <ipxe/process.h>
+#include <ipxe/keys.h>
+#include <usr/ifmgmt.h>
+
+/** @file
+ *
+ * Network interface management
+ *
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+int ifopen ( struct net_device *netdev ) {
+	int rc;
+
+	if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
+		printf ( "Could not open %s: %s\n",
+			 netdev->name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+void ifclose ( struct net_device *netdev ) {
+	netdev_close ( netdev );
+}
+
+/**
+ * Print network device error breakdown
+ *
+ * @v stats		Network device statistics
+ * @v prefix		Message prefix
+ */
+static void ifstat_errors ( struct net_device_stats *stats,
+			    const char *prefix ) {
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+			    sizeof ( stats->errors[0] ) ) ; i++ ) {
+		if ( stats->errors[i].count )
+			printf ( "  [%s: %d x \"%s\"]\n", prefix,
+				 stats->errors[i].count,
+				 strerror ( stats->errors[i].rc ) );
+	}
+}
+
+/**
+ * Print status of network device
+ *
+ * @v netdev		Network device
+ */
+void ifstat ( struct net_device *netdev ) {
+	printf ( "%s: %s using %s on %s (%s)\n"
+		 "  [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
+		 netdev->name, netdev_addr ( netdev ),
+		 netdev->dev->driver_name, netdev->dev->name,
+		 ( netdev_is_open ( netdev ) ? "open" : "closed" ),
+		 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
+		 netdev->tx_stats.good, netdev->tx_stats.bad,
+		 netdev->rx_stats.good, netdev->rx_stats.bad );
+	if ( ! netdev_link_ok ( netdev ) ) {
+		printf ( "  [Link status: %s]\n",
+			 strerror ( netdev->link_rc ) );
+	}
+	ifstat_errors ( &netdev->tx_stats, "TXE" );
+	ifstat_errors ( &netdev->rx_stats, "RXE" );
+}
+
+/**
+ * Wait for link-up, with status indication
+ *
+ * @v netdev		Network device
+ * @v max_wait_ms	Maximum time to wait, in ms
+ */
+int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) {
+	int key;
+	int rc;
+
+	if ( netdev_link_ok ( netdev ) )
+		return 0;
+
+	printf ( "Waiting for link-up on %s...", netdev->name );
+
+	while ( 1 ) {
+		if ( netdev_link_ok ( netdev ) ) {
+			rc = 0;
+			break;
+		}
+		if ( max_wait_ms-- == 0 ) {
+			rc = netdev->link_rc;
+			break;
+		}
+		step();
+		if ( iskey() ) {
+			key = getchar();
+			if ( key == CTRL_C ) {
+				rc = -ECANCELED;
+				break;
+			}
+		}
+		mdelay ( 1 );
+	}
+
+	if ( rc == 0 ) {
+		printf ( " ok\n" );
+	} else {
+		printf ( " failed: %s\n", strerror ( rc ) );
+	}
+
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/imgmgmt.c b/qemu-0.15.x/roms/ipxe/src/usr/imgmgmt.c
new file mode 100644
index 0000000..dbf792b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/imgmgmt.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/image.h>
+#include <ipxe/downloader.h>
+#include <ipxe/monojob.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <usr/imgmgmt.h>
+
+/** @file
+ *
+ * Image management
+ *
+ */
+
+/**
+ * Register an image and leave it registered
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ *
+ * This function assumes an ownership of the passed image.
+ */
+int register_and_put_image ( struct image *image ) {
+	int rc;
+
+	rc = register_image ( image );
+	image_put ( image );
+	return rc;
+}
+
+/**
+ * Register and probe an image
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ *
+ * This function assumes an ownership of the passed image.
+ */
+int register_and_probe_image ( struct image *image ) {
+	int rc;
+
+	if ( ( rc = register_and_put_image ( image ) ) != 0 )
+		return rc;
+
+	if ( ( rc = image_probe ( image ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Register and select an image
+ *
+ * @v image		Executable image
+ * @ret rc		Return status code
+ *
+ * This function assumes an ownership of the passed image.
+ */
+int register_and_select_image ( struct image *image ) {
+	int rc;
+
+	if ( ( rc = register_and_probe_image ( image ) ) != 0 )
+		return rc;
+
+	if ( ( rc = image_select ( image ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Register and boot an image
+ *
+ * @v image		Image
+ * @ret rc		Return status code
+ *
+ * This function assumes an ownership of the passed image.
+ */
+int register_and_boot_image ( struct image *image ) {
+	int rc;
+
+	if ( ( rc = register_and_select_image ( image ) ) != 0 )
+		return rc;
+
+	if ( ( rc = image_exec ( image ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Register and replace image
+ *
+ * @v image		Image
+ * @ret rc		Return status code
+ *
+ * This function assumes an ownership of the passed image.
+ */
+int register_and_replace_image ( struct image *image ) {
+	int rc;
+
+	if ( ( rc = register_and_probe_image ( image ) ) != 0 )
+		return rc;
+
+	if ( ( rc = image_replace ( image ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Download an image
+ *
+ * @v uri		URI
+ * @v name		Image name, or NULL to use default
+ * @v cmdline		Command line, or NULL for no command line
+ * @v action		Action to take upon a successful download
+ * @ret rc		Return status code
+ */
+int imgdownload ( struct uri *uri, const char *name, const char *cmdline,
+		  int ( * action ) ( struct image *image ) ) {
+	struct image *image;
+	size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 );
+	char uri_string_redacted[len];
+	const char *password;
+	int rc;
+
+	/* Allocate image */
+	image = alloc_image();
+	if ( ! image )
+		return -ENOMEM;
+
+	/* Set image name */
+	if ( name )
+		image_set_name ( image, name );
+
+	/* Set image URI */
+	image_set_uri ( image, uri );
+
+	/* Set image command line */
+	image_set_cmdline ( image, cmdline );
+
+	/* Redact password portion of URI, if necessary */
+	password = uri->password;
+	if ( password )
+		uri->password = "***";
+	unparse_uri ( uri_string_redacted, sizeof ( uri_string_redacted ),
+		      uri, URI_ALL );
+	uri->password = password;
+
+	/* Create downloader */
+	if ( ( rc = create_downloader ( &monojob, image, LOCATION_URI,
+					uri ) ) != 0 ) {
+		image_put ( image );
+		return rc;
+	}
+
+	/* Wait for download to complete */
+	if ( ( rc = monojob_wait ( uri_string_redacted ) ) != 0 ) {
+		image_put ( image );
+		return rc;
+	}
+
+	/* Act upon downloaded image.  This action assumes our
+	 * ownership of the image.
+	 */
+	if ( ( rc = action ( image ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Download an image
+ *
+ * @v uri_string	URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
+ * @v name		Image name, or NULL to use default
+ * @v cmdline		Command line, or NULL for no command line
+ * @v action		Action to take upon a successful download
+ * @ret rc		Return status code
+ */
+int imgdownload_string ( const char *uri_string, const char *name,
+			 const char *cmdline,
+			 int ( * action ) ( struct image *image ) ) {
+	struct uri *uri;
+	int rc;
+
+	if ( ! ( uri = parse_uri ( uri_string ) ) )
+		return -ENOMEM;
+
+	rc = imgdownload ( uri, name, cmdline, action );
+
+	uri_put ( uri );
+	return rc;
+}
+
+/**
+ * Display status of an image
+ *
+ * @v image		Executable/loadable image
+ */
+void imgstat ( struct image *image ) {
+	printf ( "%s : %zd bytes", image->name, image->len );
+	if ( image->type )
+		printf ( " [%s]", image->type->name );
+	if ( image->flags & IMAGE_SELECTED )
+		printf ( " [SELECTED]" );
+	if ( image->cmdline )
+		printf ( " \"%s\"", image->cmdline );
+	printf ( "\n" );
+}
+
+/**
+ * Free an image
+ *
+ * @v image		Executable/loadable image
+ */
+void imgfree ( struct image *image ) {
+	unregister_image ( image );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/iwmgmt.c b/qemu-0.15.x/roms/ipxe/src/usr/iwmgmt.c
new file mode 100644
index 0000000..29f623c
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/iwmgmt.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2009 Joshua Oreman <oremanj at rwcr.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <ipxe/console.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/net80211.h>
+#include <ipxe/ethernet.h>
+#include <usr/ifmgmt.h>
+#include <usr/iwmgmt.h>
+
+/** @file
+ *
+ * Wireless network interface management
+ *
+ */
+
+/**
+ * Print status of 802.11 device
+ *
+ * @v dev	802.11 device
+ */
+void iwstat ( struct net80211_device *dev ) {
+
+	ifstat ( dev->netdev );
+
+	printf ( "  [802.11 ");
+	if ( dev->state & NET80211_ASSOCIATED ) {
+		printf ( "SSID '%s', ", dev->essid );
+	} else {
+		printf ( "not associated, " );
+	}
+	if ( dev->channel < dev->nr_channels && dev->rate < dev->nr_rates ) {
+		printf ( "Ch:%d Sig:%d", dev->channels[dev->channel].channel_nr,
+			 dev->last_signal );
+		switch ( dev->hw->signal_type ) {
+		case NET80211_SIGNAL_NONE:
+			printf ( "?" );
+			break;
+		case NET80211_SIGNAL_ARBITRARY:
+			printf ( "/%d", dev->hw->signal_max );
+			break;
+		case NET80211_SIGNAL_DB:
+			printf ( "/%d dB", dev->hw->signal_max );
+			break;
+		case NET80211_SIGNAL_DBM:
+			printf ( " dBm" );
+			break;
+		}
+		printf ( ", Qual:%d%% Rate:%d Mbps]\n",
+			 ( dev->rx_beacon_interval == 0 ? 0 :
+			   100 * dev->tx_beacon_interval /
+			   dev->rx_beacon_interval ),
+			 dev->rates[dev->rate] / 10 );
+	} else {
+		printf ( "antenna off]\n" );
+	}
+
+	if ( dev->state & NET80211_WORKING ) {
+		printf ( "  [associating" );
+		if ( dev->associating )
+			printf ( " to '%s'", dev->associating->essid );
+		printf ( "...]\n" );
+	}
+}
+
+/** Identifiers for 802.11 cryptography types, indexed by type number */
+static const char *crypto_types[] = {
+	[NET80211_CRYPT_NONE] = "Open",
+	[NET80211_CRYPT_WEP] = "WEP ",
+	[NET80211_CRYPT_TKIP] = "WPA ",
+	[NET80211_CRYPT_CCMP] = "WPA2",
+	[NET80211_CRYPT_UNKNOWN] = "UNK ",
+};
+
+/** Number of 802.11 cryptography types defined */
+#define NR_CRYPTO_TYPES ( sizeof ( crypto_types ) / sizeof ( crypto_types[0] ) )
+
+/** Identifiers for 802.11 authentication types, indexed by type number */
+static const char *auth_types[] = {
+	[NET80211_SECPROT_NONE] = "",
+	[NET80211_SECPROT_PSK] = "PSK",
+	[NET80211_SECPROT_EAP] = "802.1X",
+	[NET80211_SECPROT_UNKNOWN] = "UNK",
+};
+
+/** Number of 802.11 authentication types defined */
+#define NR_AUTH_TYPES ( sizeof ( auth_types ) / sizeof ( auth_types[0] ) )
+
+/**
+ * Scan for wireless networks using 802.11 device
+ *
+ * @v dev	802.11 device
+ * @v active	Whether to use active scanning
+ *
+ * The list of networks found will be printed in tabular format.
+ *
+ * This function is safe to call at all times, whether the 802.11
+ * device is open or not, but if called while the auto-association
+ * task is running it will return an error indication.
+ */
+int iwlist ( struct net80211_device *dev ) {
+	struct net80211_probe_ctx *ctx;
+	struct list_head *networks;
+	struct net80211_wlan *wlan;
+	char ssid_buf[22];
+	int rc;
+	unsigned i;
+	int was_opened = netdev_is_open ( dev->netdev );
+	int was_channel = dev->channels[dev->channel].channel_nr;
+
+	if ( ! was_opened ) {
+		dev->state |= NET80211_NO_ASSOC;
+		rc = netdev_open ( dev->netdev );
+		if ( rc < 0 )
+			goto err;
+	}
+
+	if ( dev->state & NET80211_WORKING ) {
+		rc = -EINVAL;
+		goto err_close_netdev;
+	}
+
+	if ( ! was_opened ) {
+		rc = net80211_prepare_probe ( dev, dev->hw->bands, 0 );
+		if ( rc < 0 )
+			goto err_close_netdev;
+	}
+
+	ctx = net80211_probe_start ( dev, "", 0 );
+	if ( ! ctx ) {
+		rc = -ENOMEM;
+		goto err_close_netdev;
+	}
+
+	while ( ! ( rc = net80211_probe_step ( ctx ) ) ) {
+		step();
+	}
+
+	networks = net80211_probe_finish_all ( ctx );
+
+	if ( list_empty ( networks ) ) {
+		goto err_free_networks;
+	}
+
+	rc = 0;
+
+	printf ( "Networks on %s:\n\n", dev->netdev->name );
+
+	/* Output format:
+	 * 0         1         2         3         4         5         6
+	 * 0123456789012345678901234567890123456789012345678901234567890
+	 * [Sig] SSID                  BSSID              Ch  Crypt/Auth
+	 * -------------------------------------------------------------
+	 * [ 15] abcdefghijklmnopqrst> 00:00:00:00:00:00  11  Open
+	 *                                             ... or WPA   PSK etc.
+	 */
+
+	/* Quoting the dashes and spaces verbatim uses less code space
+	   than generating them programmatically. */
+	printf ( "[Sig] SSID                  BSSID              Ch  Crypt/Auth\n"
+		 "-------------------------------------------------------------\n" );
+
+	list_for_each_entry ( wlan, networks, list ) {
+
+		/* Format SSID into 22-character string, space-padded,
+		   with '>' indicating truncation */
+
+		snprintf ( ssid_buf, sizeof ( ssid_buf ), "%s", wlan->essid );
+		for ( i = strlen ( ssid_buf ); i < sizeof ( ssid_buf ) - 1;
+		      i++ )
+			ssid_buf[i] = ' ';
+		if ( ssid_buf[sizeof ( ssid_buf ) - 2] != ' ' )
+			ssid_buf[sizeof ( ssid_buf ) - 2] = '>';
+		ssid_buf[sizeof ( ssid_buf ) - 1] = 0;
+
+		/* Sanity check */
+		if ( wlan->crypto >= NR_CRYPTO_TYPES ||
+		     wlan->handshaking >= NR_AUTH_TYPES )
+			continue;
+
+		printf ( "[%3d] %s %s  %2d  %s  %s\n",
+			 wlan->signal < 0 ? 100 + wlan->signal : wlan->signal,
+			 ssid_buf, eth_ntoa ( wlan->bssid ), wlan->channel,
+			 crypto_types[wlan->crypto],
+			 auth_types[wlan->handshaking] );
+	}
+	printf ( "\n" );
+
+ err_free_networks:
+	net80211_free_wlanlist ( networks );
+
+ err_close_netdev:
+	if ( ! was_opened ) {
+		dev->state &= ~NET80211_NO_ASSOC;
+		netdev_close ( dev->netdev );
+	} else {
+		net80211_change_channel ( dev, was_channel );
+	}
+
+	if ( ! rc )
+		return 0;
+
+ err:
+	printf ( "Scanning for networks on %s: %s\n",
+		 dev->netdev->name, strerror ( rc ) );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/lotest.c b/qemu-0.15.x/roms/ipxe/src/usr/lotest.c
new file mode 100644
index 0000000..7f9f2fd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/lotest.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/keys.h>
+#include <ipxe/console.h>
+#include <usr/ifmgmt.h>
+#include <usr/lotest.h>
+
+/** @file
+ *
+ * Loopback testing
+ *
+ */
+
+#define LINK_WAIT_MS 15000
+
+/**
+ * Process received packet
+ *
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer source address
+ * @ret rc		Return status code
+ */
+static int lotest_rx ( struct io_buffer *iobuf,
+		       struct net_device *netdev __unused,
+		       const void *ll_dest __unused,
+		       const void *ll_source __unused ) {
+	free_iob ( iobuf );
+	return -ENOTSUP;
+}
+
+/**
+ * Transcribe network-layer address
+ *
+ * @v net_addr		Network-layer address
+ * @ret string		Human-readable transcription of address
+ */
+static const char * lotest_ntoa ( const void *net_addr __unused ) {
+	return "<INVALID>";
+}
+
+/**
+ * Loopback test network-layer protocol
+ *
+ * Using a dedicated network-layer protocol avoids problems caused by
+ * cards supporting features such as IPv4 checksum offload trying to
+ * interpret the (randomly generated) network-layer content.
+ */
+static struct net_protocol lotest_protocol __net_protocol = {
+	.name = "LOTEST",
+	.rx = lotest_rx,
+	.ntoa = lotest_ntoa,
+	.net_proto = htons ( 0x6950 ), /* Not a genuine protocol number */
+	.net_addr_len = 0,
+};
+
+/**
+ * Perform loopback test between two network devices
+ *
+ * @v sender		Sending network device
+ * @v receiver		Received network device
+ * @v mtu		Packet size (excluding link-layer headers)
+ * @ret rc		Return status code
+ */
+int loopback_test ( struct net_device *sender, struct net_device *receiver,
+		    size_t mtu ) {
+	uint8_t buf[mtu];
+	struct io_buffer *iobuf;
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	unsigned int i;
+	unsigned int successes;
+	int rc;
+
+	/* Open network devices */
+	if ( ( rc = ifopen ( sender ) ) != 0 )
+		return rc;
+	if ( ( rc = ifopen ( receiver ) ) != 0 )
+		return rc;
+
+	/* Wait for link-up */
+	if ( ( rc = iflinkwait ( sender, LINK_WAIT_MS ) ) != 0 )
+		return rc;
+	if ( ( rc = iflinkwait ( receiver, LINK_WAIT_MS ) ) != 0 )
+		return rc;
+
+	/* Print initial statistics */
+	printf ( "Performing loopback test from %s to %s with %zd byte MTU\n",
+		 sender->name, receiver->name, mtu );
+	ifstat ( sender );
+	ifstat ( receiver );
+
+	/* Freeze receive queue processing on the receiver, so that we
+	 * can extract all received packets.
+	 */
+	netdev_rx_freeze ( receiver );
+
+	/* Perform loopback test */
+	for ( successes = 0 ; ; successes++ ) {
+
+		/* Print running total */
+		printf ( "\r%d", successes );
+
+		/* Generate random packet */
+		for ( i = 0 ; i < sizeof ( buf ) ; i++ )
+			buf[i] = random();
+		iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( buf ) );
+		if ( ! iobuf ) {
+			printf ( "\nFailed to allocate I/O buffer" );
+			rc = -ENOMEM;
+			goto done;
+		}
+		iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
+		memcpy ( iob_put ( iobuf, sizeof ( buf ) ),
+			 buf, sizeof ( buf ) );
+
+		/* Transmit packet */
+		if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
+				     &lotest_protocol, receiver->ll_addr,
+				     sender->ll_addr ) ) != 0 ) {
+			printf ( "\nFailed to transmit packet: %s",
+				 strerror ( rc ) );
+			goto done;
+		}
+
+		/* Poll until packet arrives */
+		do {
+			/* Check for cancellation */
+			if ( iskey() && ( getchar() == CTRL_C ) ) {
+				rc = -ECANCELED;
+				goto done;
+			}
+			/* Poll network devices */
+			net_poll();
+		} while ( ( iobuf = netdev_rx_dequeue ( receiver ) ) == NULL );
+
+		/* Check received packet */
+		if ( ( rc = receiver->ll_protocol->pull ( receiver, iobuf,
+							  &ll_dest, &ll_source,
+							  &net_proto ) ) != 0 ){
+			printf ( "\nFailed to strip link-layer header: %s",
+				 strerror ( rc ) );
+			goto done;
+		}
+		if ( net_proto == lotest_protocol.net_proto ) {
+			if ( iob_len ( iobuf ) != sizeof ( buf ) ) {
+				printf ( "\nLength mismatch: sent %zd, "
+					 "received %zd",
+					 sizeof ( buf ), iob_len ( iobuf ) );
+				DBG ( "\nSent:\n" );
+				DBG_HDA ( 0, buf, sizeof ( buf ) );
+				DBG ( "Received:\n" );
+				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
+				rc = -EINVAL;
+				goto done;
+			}
+			if ( memcmp ( iobuf->data, buf, sizeof ( buf ) ) != 0){
+				printf ( "\nContent mismatch" );
+				DBG ( "\nSent:\n" );
+				DBG_HDA ( 0, buf, sizeof ( buf ) );
+				DBG ( "Received:\n" );
+				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
+				rc = -EINVAL;
+				goto done;
+			}
+		} else {
+			printf ( "\nReceived spurious packet type %04x\n",
+				 ntohs ( net_proto ) );
+			/* Continue; this allows for the fact that
+			 * there may have been packets outstanding on
+			 * the wire when we started the test.
+			 */
+		}
+
+		free_iob ( iob_disown ( iobuf ) );
+	}
+
+ done:
+	printf ( "\n");
+	free_iob ( iobuf );
+	netdev_rx_unfreeze ( receiver );
+
+	/* Dump final statistics */
+	ifstat ( sender );
+	ifstat ( receiver );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/prompt.c b/qemu-0.15.x/roms/ipxe/src/usr/prompt.c
new file mode 100644
index 0000000..3c353a6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/prompt.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Prompt for keypress
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <ipxe/console.h>
+#include <ipxe/timer.h>
+#include <usr/prompt.h>
+
+/**
+ * Prompt for keypress
+ *
+ * @v text		Prompt string
+ * @v wait_ms		Time to wait, in milliseconds (0=indefinite)
+ * @v key		Key to wait for (0=any key)
+ * @ret rc		Return status code
+ *
+ * Returns success if the specified key was pressed within the
+ * specified timeout period.
+ */
+int prompt ( const char *text, unsigned int wait_ms, int key ) {
+	int key_pressed;
+
+	/* Display prompt */
+	printf ( "%s", text );
+
+	/* Wait for key */
+	key_pressed = getkey ( ( wait_ms * TICKS_PER_SEC ) / 1000 );
+
+	/* Clear the prompt line */
+	while ( *(text++) )
+		printf ( "\b \b" );
+
+	/* Check for timeout */
+	if ( key_pressed < 0 )
+		return -ETIMEDOUT;
+
+	/* Check for correct key pressed */
+	if ( key && ( key_pressed != key ) )
+		return -ECANCELED;
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/pxemenu.c b/qemu-0.15.x/roms/ipxe/src/usr/pxemenu.c
new file mode 100644
index 0000000..75789e2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/pxemenu.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <byteswap.h>
+#include <curses.h>
+#include <ipxe/console.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/keys.h>
+#include <ipxe/timer.h>
+#include <ipxe/uri.h>
+#include <usr/dhcpmgmt.h>
+#include <usr/autoboot.h>
+
+/** @file
+ *
+ * PXE Boot Menus
+ *
+ */
+
+/* Colour pairs */
+#define CPAIR_NORMAL	1
+#define CPAIR_SELECT	2
+
+/** A PXE boot menu item */
+struct pxe_menu_item {
+	/** Boot Server type */
+	unsigned int type;
+	/** Description */
+	char *desc;
+};
+
+/**
+ * A PXE boot menu
+ *
+ * This structure encapsulates the menu information provided via DHCP
+ * options.
+ */
+struct pxe_menu {
+	/** Prompt string (optional) */
+	const char *prompt;
+	/** Timeout (in seconds)
+	 *
+	 * Negative indicates no timeout (i.e. wait indefinitely)
+	 */
+	int timeout;
+	/** Number of menu items */
+	unsigned int num_items;
+	/** Selected menu item */
+	unsigned int selection;
+	/** Menu items */
+	struct pxe_menu_item items[0];
+};
+
+/**
+ * Parse and allocate PXE boot menu
+ *
+ * @v menu		PXE boot menu to fill in
+ * @ret rc		Return status code
+ *
+ * It is the callers responsibility to eventually free the allocated
+ * boot menu.
+ */
+static int pxe_menu_parse ( struct pxe_menu **menu ) {
+	struct setting pxe_boot_menu_prompt_setting =
+		{ .tag = DHCP_PXE_BOOT_MENU_PROMPT };
+	struct setting pxe_boot_menu_setting =
+		{ .tag = DHCP_PXE_BOOT_MENU };
+	uint8_t raw_menu[256];
+	int raw_prompt_len;
+	int raw_menu_len;
+	struct dhcp_pxe_boot_menu *raw_menu_item;
+	struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt;
+	void *raw_menu_end;
+	unsigned int num_menu_items;
+	unsigned int i;
+	int rc;
+
+	/* Fetch raw menu */
+	memset ( raw_menu, 0, sizeof ( raw_menu ) );
+	if ( ( raw_menu_len = fetch_setting ( NULL, &pxe_boot_menu_setting,
+					      raw_menu,
+					      sizeof ( raw_menu ) ) ) < 0 ) {
+		rc = raw_menu_len;
+		DBG ( "Could not retrieve raw PXE boot menu: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+	if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) {
+		DBG ( "Raw PXE boot menu too large for buffer\n" );
+		return -ENOSPC;
+	}
+	raw_menu_end = ( raw_menu + raw_menu_len );
+
+	/* Fetch raw prompt length */
+	raw_prompt_len = fetch_setting_len ( NULL,
+					     &pxe_boot_menu_prompt_setting );
+	if ( raw_prompt_len < 0 )
+		raw_prompt_len = 0;
+
+	/* Count menu items */
+	num_menu_items = 0;
+	raw_menu_item = ( ( void * ) raw_menu );
+	while ( 1 ) {
+		if ( ( ( ( void * ) raw_menu_item ) +
+		       sizeof ( *raw_menu_item ) ) > raw_menu_end )
+			break;
+		if ( ( ( ( void * ) raw_menu_item ) +
+		       sizeof ( *raw_menu_item ) +
+		       raw_menu_item->desc_len ) > raw_menu_end )
+			break;
+		num_menu_items++;
+		raw_menu_item = ( ( ( void * ) raw_menu_item ) +
+				  sizeof ( *raw_menu_item ) +
+				  raw_menu_item->desc_len );
+	}
+
+	/* Allocate space for parsed menu */
+	*menu = zalloc ( sizeof ( **menu ) +
+			 ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
+			 raw_menu_len + 1 /* NUL */ +
+			 raw_prompt_len + 1 /* NUL */ );
+	if ( ! *menu ) {
+		DBG ( "Could not allocate PXE boot menu\n" );
+		return -ENOMEM;
+	}
+
+	/* Fill in parsed menu */
+	(*menu)->num_items = num_menu_items;
+	raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
+			  ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
+	memcpy ( raw_menu_item, raw_menu, raw_menu_len );
+	for ( i = 0 ; i < num_menu_items ; i++ ) {
+		(*menu)->items[i].type = le16_to_cpu ( raw_menu_item->type );
+		(*menu)->items[i].desc = raw_menu_item->desc;
+		/* Set type to 0; this ensures that the description
+		 * for the previous menu item is NUL-terminated.
+		 * (Final item is NUL-terminated anyway.)
+		 */
+		raw_menu_item->type = 0;
+		raw_menu_item = ( ( ( void * ) raw_menu_item ) +
+				  sizeof ( *raw_menu_item ) +
+				  raw_menu_item->desc_len );
+	}
+	if ( raw_prompt_len ) {
+		raw_menu_prompt = ( ( ( void * ) raw_menu_item ) +
+				    1 /* NUL */ );
+		fetch_setting ( NULL, &pxe_boot_menu_prompt_setting,
+				raw_menu_prompt, raw_prompt_len );
+		(*menu)->timeout =
+			( ( raw_menu_prompt->timeout == 0xff ) ?
+			  -1 : raw_menu_prompt->timeout );
+		(*menu)->prompt = raw_menu_prompt->prompt;
+	} else {
+		(*menu)->timeout = -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Draw PXE boot menu item
+ *
+ * @v menu		PXE boot menu
+ * @v index		Index of item to draw
+ * @v selected		Item is selected
+ */
+static void pxe_menu_draw_item ( struct pxe_menu *menu,
+				 unsigned int index, int selected ) {
+	char buf[COLS+1];
+	size_t len;
+	unsigned int row;
+
+	/* Prepare space-padded row content */
+	len = snprintf ( buf, sizeof ( buf ), " %c. %s",
+			 ( 'A' + index ), menu->items[index].desc );
+	while ( len < ( sizeof ( buf ) - 1 ) )
+		buf[len++] = ' ';
+	buf[ sizeof ( buf ) - 1 ] = '\0';
+
+	/* Draw row */
+	row = ( LINES - menu->num_items + index );
+	color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL );
+	mvprintw ( row, 0, "%s", buf );
+	move ( row, 1 );
+}
+
+/**
+ * Make selection from PXE boot menu
+ *
+ * @v menu		PXE boot menu
+ * @ret rc		Return status code
+ */
+static int pxe_menu_select ( struct pxe_menu *menu ) {
+	int key;
+	unsigned int key_selection;
+	unsigned int i;
+	int rc = 0;
+
+	/* Initialise UI */
+	initscr();
+	start_color();
+	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
+	init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE );
+	color_set ( CPAIR_NORMAL, NULL );
+
+	/* Draw initial menu */
+	for ( i = 0 ; i < menu->num_items ; i++ )
+		printf ( "\n" );
+	for ( i = 0 ; i < menu->num_items ; i++ )
+		pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 );
+
+	while ( 1 ) {
+
+		/* Highlight currently selected item */
+		pxe_menu_draw_item ( menu, menu->selection, 1 );
+
+		/* Wait for keyboard input */
+		key = getkey ( 0 );
+
+		/* Unhighlight currently selected item */
+		pxe_menu_draw_item ( menu, menu->selection, 0 );
+
+		/* Act upon key */
+		if ( ( key == CR ) || ( key == LF ) ) {
+			pxe_menu_draw_item ( menu, menu->selection, 1 );
+			break;
+		} else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
+			rc = -ECANCELED;
+			break;
+		} else if ( key == KEY_UP ) {
+			if ( menu->selection > 0 )
+				menu->selection--;
+		} else if ( key == KEY_DOWN ) {
+			if ( menu->selection < ( menu->num_items - 1 ) )
+				menu->selection++;
+		} else if ( ( key < KEY_MIN ) &&
+			    ( ( key_selection = ( toupper ( key ) - 'A' ) )
+			      < menu->num_items ) ) {
+			menu->selection = key_selection;
+			pxe_menu_draw_item ( menu, menu->selection, 1 );
+			break;
+		}
+	}
+
+	/* Shut down UI */
+	endwin();
+
+	return rc;
+}
+
+/**
+ * Prompt for (and make selection from) PXE boot menu
+ *
+ * @v menu		PXE boot menu
+ * @ret rc		Return status code
+ */
+static int pxe_menu_prompt_and_select ( struct pxe_menu *menu ) {
+	unsigned long start = currticks();
+	unsigned long now;
+	unsigned long elapsed;
+	size_t len = 0;
+	int key;
+	int rc = 0;
+
+	/* Display menu immediately, if specified to do so */
+	if ( menu->timeout < 0 ) {
+		if ( menu->prompt )
+			printf ( "%s\n", menu->prompt );
+		return pxe_menu_select ( menu );
+	}
+
+	/* Display prompt, if specified */
+	if ( menu->prompt )
+		printf ( "%s", menu->prompt );
+
+	/* Wait for timeout, if specified */
+	while ( menu->timeout > 0 ) {
+		if ( ! len )
+			len = printf ( " (%d)", menu->timeout );
+		if ( iskey() ) {
+			key = getkey ( 0 );
+			if ( key == KEY_F8 ) {
+				/* Display menu */
+				printf ( "\n" );
+				return pxe_menu_select ( menu );
+			} else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
+				/* Abort */
+				rc = -ECANCELED;
+				break;
+			} else {
+				/* Stop waiting */
+				break;
+			}
+		}
+		now = currticks();
+		elapsed = ( now - start );
+		if ( elapsed >= TICKS_PER_SEC ) {
+			menu->timeout -= 1;
+			do {
+				printf ( "\b \b" );
+			} while ( --len );
+			start = now;
+		}
+	}
+
+	/* Return with default option selected */
+	printf ( "\n" );
+	return rc;
+}
+
+/**
+ * Boot using PXE boot menu
+ *
+ * @ret rc		Return status code
+ *
+ * Note that a success return status indicates that a PXE boot menu
+ * item has been selected, and that the DHCP session should perform a
+ * boot server request/ack.
+ */
+int pxe_menu_boot ( struct net_device *netdev ) {
+	struct pxe_menu *menu;
+	unsigned int pxe_type;
+	struct settings *pxebs_settings;
+	struct uri *uri;
+	int rc;
+
+	/* Parse and allocate boot menu */
+	if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 )
+		return rc;
+
+	/* Make selection from boot menu */
+	if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) {
+		free ( menu );
+		return rc;
+	}
+	pxe_type = menu->items[menu->selection].type;
+
+	/* Free boot menu */
+	free ( menu );
+
+	/* Return immediately if local boot selected */
+	if ( ! pxe_type )
+		return 0;
+
+	/* Attempt PXE Boot Server Discovery */
+	if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
+		return rc;
+
+	/* Fetch next server and filename */
+	pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
+	assert ( pxebs_settings );
+	uri = fetch_next_server_and_filename ( pxebs_settings );
+	if ( ! uri )
+		return -ENOMEM;
+
+	/* Attempt boot */
+	rc = uriboot ( uri, NULL );
+	uri_put ( uri );
+	return rc;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/usr/route.c b/qemu-0.15.x/roms/ipxe/src/usr/route.c
new file mode 100644
index 0000000..1da7135
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/usr/route.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ip.h>
+#include <usr/route.h>
+
+/** @file
+ *
+ * Routing table management
+ *
+ */
+
+void route ( void ) {
+	struct ipv4_miniroute *miniroute;
+
+	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+		printf ( "%s: %s/", miniroute->netdev->name,
+			 inet_ntoa ( miniroute->address ) );
+		printf ( "%s", inet_ntoa ( miniroute->netmask ) );
+		if ( miniroute->gateway.s_addr )
+			printf ( " gw %s", inet_ntoa ( miniroute->gateway ) );
+		if ( ! netdev_is_open ( miniroute->netdev ) )
+			printf ( " (inaccessible)" );
+		printf ( "\n" );
+	}
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/.gitignore b/qemu-0.15.x/roms/ipxe/src/util/.gitignore
new file mode 100644
index 0000000..633ca32
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/.gitignore
@@ -0,0 +1,9 @@
+nrv2b
+zbin
+hijack
+prototester
+elf2efi32
+elf2efi64
+efirom
+iccfix
+einfo
diff --git a/qemu-0.15.x/roms/ipxe/src/util/Makefile b/qemu-0.15.x/roms/ipxe/src/util/Makefile
new file mode 100644
index 0000000..d72661e
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/Makefile
@@ -0,0 +1,22 @@
+BLIB = ../bin/blib.a
+CFLAGS = -Os
+
+all : hijack prototester mucurses_test
+
+hijack : hijack.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -lpcap -o $@ $<
+
+prototester.o : prototester.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $< -idirafter ../include
+
+prototester : prototester.o $(BLIB)
+	$(CC) -o $@ $< -lc $(BLIB)
+
+mucurses_test.o : mucurses_test.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $<
+
+mucurses_test : mucurses_test.o $(BLIB)
+	$(CC) -o $@ $< -lc $(BLIB)
+
+clean :
+	rm -f hijack prototester mucurses_test *.o
diff --git a/qemu-0.15.x/roms/ipxe/src/util/Option/ROM.pm b/qemu-0.15.x/roms/ipxe/src/util/Option/ROM.pm
new file mode 100644
index 0000000..9fea4d3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/Option/ROM.pm
@@ -0,0 +1,502 @@
+package Option::ROM;
+
+# Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=head1 NAME
+
+Option::ROM - Option ROM manipulation
+
+=head1 SYNOPSIS
+
+    use Option::ROM;
+
+    # Load a ROM image
+    my $rom = new Option::ROM;
+    $rom->load ( "rtl8139.rom" );
+
+    # Modify the PCI device ID
+    $rom->pci_header->{device_id} = 0x1234;
+    $rom->fix_checksum();
+
+    # Write ROM image out to a new file
+    $rom->save ( "rtl8139-modified.rom" );
+
+=head1 DESCRIPTION
+
+C<Option::ROM> provides a mechanism for manipulating Option ROM
+images.
+
+=head1 METHODS
+
+=cut
+
+##############################################################################
+#
+# Option::ROM::Fields
+#
+##############################################################################
+
+package Option::ROM::Fields;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub TIEHASH {
+  my $class = shift;
+  my $self = shift;
+
+  bless $self, $class;
+  return $self;
+}
+
+sub FETCH {
+  my $self = shift;
+  my $key = shift;
+
+  return undef unless $self->EXISTS ( $key );
+  my $raw = substr ( ${$self->{data}},
+		     ( $self->{offset} + $self->{fields}->{$key}->{offset} ),
+		     $self->{fields}->{$key}->{length} );
+  my $unpack = ( ref $self->{fields}->{$key}->{unpack} ?
+		 $self->{fields}->{$key}->{unpack} :
+		 sub { unpack ( $self->{fields}->{$key}->{pack}, shift ); } );
+  return &$unpack ( $raw );
+}
+
+sub STORE {
+  my $self = shift;
+  my $key = shift;
+  my $value = shift;
+
+  croak "Nonexistent field \"$key\"" unless $self->EXISTS ( $key );
+  my $pack = ( ref $self->{fields}->{$key}->{pack} ?
+	       $self->{fields}->{$key}->{pack} :
+	       sub { pack ( $self->{fields}->{$key}->{pack}, shift ); } );
+  my $raw = &$pack ( $value );
+  substr ( ${$self->{data}},
+	   ( $self->{offset} + $self->{fields}->{$key}->{offset} ),
+	   $self->{fields}->{$key}->{length} ) = $raw;
+}
+
+sub DELETE {
+  my $self = shift;
+  my $key = shift;
+
+  $self->STORE ( $key, 0 );
+}
+
+sub CLEAR {
+  my $self = shift;
+
+  foreach my $key ( keys %{$self->{fields}} ) {
+    $self->DELETE ( $key );
+  }
+}
+
+sub EXISTS {
+  my $self = shift;
+  my $key = shift;
+
+  return ( exists $self->{fields}->{$key} &&
+	   ( ( $self->{fields}->{$key}->{offset} +
+	       $self->{fields}->{$key}->{length} ) <= $self->{length} ) );
+}
+
+sub FIRSTKEY {
+  my $self = shift;
+
+  keys %{$self->{fields}};
+  return each %{$self->{fields}};
+}
+
+sub NEXTKEY {
+  my $self = shift;
+  my $lastkey = shift;
+
+  return each %{$self->{fields}};
+}
+
+sub SCALAR {
+  my $self = shift;
+
+  return 1;
+}
+
+sub UNTIE {
+  my $self = shift;
+}
+
+sub DESTROY {
+  my $self = shift;
+}
+
+sub checksum {
+  my $self = shift;
+
+  my $raw = substr ( ${$self->{data}}, $self->{offset}, $self->{length} );
+  return unpack ( "%8C*", $raw );
+}
+
+##############################################################################
+#
+# Option::ROM
+#
+##############################################################################
+
+package Option::ROM;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+use Exporter 'import';
+
+use constant ROM_SIGNATURE => 0xaa55;
+use constant PCI_SIGNATURE => 'PCIR';
+use constant PNP_SIGNATURE => '$PnP';
+
+our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PNP_SIGNATURE );
+our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
+
+use constant JMP_SHORT => 0xeb;
+use constant JMP_NEAR => 0xe9;
+
+sub pack_init {
+  my $dest = shift;
+
+  # Always create a near jump; it's simpler
+  if ( $dest ) {
+    return pack ( "CS", JMP_NEAR, ( $dest - 6 ) );
+  } else {
+    return pack ( "CS", 0, 0 );
+  }
+}
+
+sub unpack_init {
+  my $instr = shift;
+
+  # Accept both short and near jumps
+  my $jump = unpack ( "C", $instr );
+  if ( $jump == JMP_SHORT ) {
+    my $offset = unpack ( "xC", $instr );
+    return ( $offset + 5 );
+  } elsif ( $jump == JMP_NEAR ) {
+    my $offset = unpack ( "xS", $instr );
+    return ( $offset + 6 );
+  } elsif ( $jump == 0 ) {
+    return 0;
+  } else {
+    croak "Unrecognised jump instruction in init vector\n";
+  }
+}
+
+=pod
+
+=item C<< new () >>
+
+Construct a new C<Option::ROM> object.
+
+=cut
+
+sub new {
+  my $class = shift;
+
+  my $hash = {};
+  tie %$hash, "Option::ROM::Fields", {
+    data => undef,
+    offset => 0x00,
+    length => 0x20,
+    fields => {
+      signature =>	{ offset => 0x00, length => 0x02, pack => "S" },
+      length =>		{ offset => 0x02, length => 0x01, pack => "C" },
+      # "init" is part of a jump instruction
+      init =>		{ offset => 0x03, length => 0x03,
+			  pack => \&pack_init, unpack => \&unpack_init },
+      checksum =>	{ offset => 0x06, length => 0x01, pack => "C" },
+      bofm_header =>	{ offset => 0x14, length => 0x02, pack => "S" },
+      undi_header =>	{ offset => 0x16, length => 0x02, pack => "S" },
+      pci_header =>	{ offset => 0x18, length => 0x02, pack => "S" },
+      pnp_header =>	{ offset => 0x1a, length => 0x02, pack => "S" },
+    },
+  };
+  bless $hash, $class;
+  return $hash;
+}
+
+=pod
+
+=item C<< load ( $filename ) >>
+
+Load option ROM contents from the file C<$filename>.
+
+=cut
+
+sub load {
+  my $hash = shift;
+  my $self = tied(%$hash);
+  my $filename = shift;
+
+  $self->{filename} = $filename;
+
+  open my $fh, "<$filename"
+      or croak "Cannot open $filename for reading: $!";
+  read $fh, my $data, ( 128 * 1024 ); # 128kB is theoretical max size
+  $self->{data} = \$data;
+  close $fh;
+}
+
+=pod
+
+=item C<< save ( [ $filename ] ) >>
+
+Write the ROM data back out to the file C<$filename>.  If C<$filename>
+is omitted, the file used in the call to C<load()> will be used.
+
+=cut
+
+sub save {
+  my $hash = shift;
+  my $self = tied(%$hash);
+  my $filename = shift;
+
+  $filename ||= $self->{filename};
+
+  open my $fh, ">$filename"
+      or croak "Cannot open $filename for writing: $!";
+  print $fh ${$self->{data}};
+  close $fh;
+}
+
+=pod
+
+=item C<< length () >>
+
+Length of option ROM data.  This is the length of the file, not the
+length from the ROM header length field.
+
+=cut
+
+sub length {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  return length ${$self->{data}};
+}
+
+=pod
+
+=item C<< pci_header () >>
+
+Return a C<Option::ROM::PCI> object representing the ROM's PCI header,
+if present.
+
+=cut
+
+sub pci_header {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $offset = $hash->{pci_header};
+  return undef unless $offset != 0;
+
+  return Option::ROM::PCI->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< pnp_header () >>
+
+Return a C<Option::ROM::PnP> object representing the ROM's PnP header,
+if present.
+
+=cut
+
+sub pnp_header {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $offset = $hash->{pnp_header};
+  return undef unless $offset != 0;
+
+  return Option::ROM::PnP->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< checksum () >>
+
+Calculate the byte checksum of the ROM.
+
+=cut
+
+sub checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $raw = substr ( ${$self->{data}}, 0, ( $hash->{length} * 512 ) );
+  return unpack ( "%8C*", $raw );
+}
+
+=pod
+
+=item C<< fix_checksum () >>
+
+Fix the byte checksum of the ROM.
+
+=cut
+
+sub fix_checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
+##############################################################################
+#
+# Option::ROM::PCI
+#
+##############################################################################
+
+package Option::ROM::PCI;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+  my $class = shift;
+  my $data = shift;
+  my $offset = shift;
+
+  my $hash = {};
+  tie %$hash, "Option::ROM::Fields", {
+    data => $data,
+    offset => $offset,
+    length => 0x0c,
+    fields => {
+      signature =>	{ offset => 0x00, length => 0x04, pack => "a4" },
+      vendor_id =>	{ offset => 0x04, length => 0x02, pack => "S" },
+      device_id =>	{ offset => 0x06, length => 0x02, pack => "S" },
+      device_list =>	{ offset => 0x08, length => 0x02, pack => "S" },
+      struct_length =>	{ offset => 0x0a, length => 0x02, pack => "S" },
+      struct_revision =>{ offset => 0x0c, length => 0x01, pack => "C" },
+      base_class => 	{ offset => 0x0d, length => 0x01, pack => "C" },
+      sub_class => 	{ offset => 0x0e, length => 0x01, pack => "C" },
+      prog_intf => 	{ offset => 0x0f, length => 0x01, pack => "C" },
+      image_length =>	{ offset => 0x10, length => 0x02, pack => "S" },
+      revision =>	{ offset => 0x12, length => 0x02, pack => "S" },
+      code_type => 	{ offset => 0x14, length => 0x01, pack => "C" },
+      last_image => 	{ offset => 0x15, length => 0x01, pack => "C" },
+      runtime_length =>	{ offset => 0x16, length => 0x02, pack => "S" },
+      conf_header =>	{ offset => 0x18, length => 0x02, pack => "S" },
+      clp_entry =>	{ offset => 0x1a, length => 0x02, pack => "S" },
+    },
+  };
+  bless $hash, $class;
+
+  # Retrieve true length of structure
+  my $self = tied ( %$hash );
+  $self->{length} = $hash->{struct_length};
+
+  return $hash;  
+}
+
+##############################################################################
+#
+# Option::ROM::PnP
+#
+##############################################################################
+
+package Option::ROM::PnP;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+  my $class = shift;
+  my $data = shift;
+  my $offset = shift;
+
+  my $hash = {};
+  tie %$hash, "Option::ROM::Fields", {
+    data => $data,
+    offset => $offset,
+    length => 0x06,
+    fields => {
+      signature =>	{ offset => 0x00, length => 0x04, pack => "a4" },
+      struct_revision =>{ offset => 0x04, length => 0x01, pack => "C" },
+      struct_length =>	{ offset => 0x05, length => 0x01, pack => "C" },
+      checksum =>	{ offset => 0x09, length => 0x01, pack => "C" },
+      manufacturer =>	{ offset => 0x0e, length => 0x02, pack => "S" },
+      product =>	{ offset => 0x10, length => 0x02, pack => "S" },
+      bcv =>		{ offset => 0x16, length => 0x02, pack => "S" },
+      bdv =>		{ offset => 0x18, length => 0x02, pack => "S" },
+      bev =>		{ offset => 0x1a, length => 0x02, pack => "S" },
+    },
+  };
+  bless $hash, $class;
+
+  # Retrieve true length of structure
+  my $self = tied ( %$hash );
+  $self->{length} = ( $hash->{struct_length} * 16 );
+
+  return $hash;  
+}
+
+sub checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  return $self->checksum();
+}
+
+sub fix_checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
+sub manufacturer {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $manufacturer = $hash->{manufacturer};
+  return undef unless $manufacturer;
+
+  my $raw = substr ( ${$self->{data}}, $manufacturer );
+  return unpack ( "Z*", $raw );
+}
+
+sub product {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $product = $hash->{product};
+  return undef unless $product;
+
+  my $raw = substr ( ${$self->{data}}, $product );
+  return unpack ( "Z*", $raw );
+}
+
+1;
diff --git a/qemu-0.15.x/roms/ipxe/src/util/catrom.pl b/qemu-0.15.x/roms/ipxe/src/util/catrom.pl
new file mode 100755
index 0000000..fe37e6b
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/catrom.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+
+use bytes;
+
+use constant MAX_ROM_LEN => 1024*1024;
+use constant PCI_OFF => 0x18;
+use constant INDICATOR_OFF => 0x15;
+
+my $total_len = 0;
+my @romfiles = @ARGV
+    or die "Usage: $0 rom-file-1 rom-file-2 ... > multi-rom-file\n";
+
+while ( my $romfile = shift @romfiles ) {
+  my $last = @romfiles ? 0 : 1;
+
+  open ROM, "<$romfile" or die "Could not open $romfile: $!\n";
+  my $len = read ( ROM, my $romdata, MAX_ROM_LEN )
+      or die "Could not read $romfile: $!\n";
+  close ROM;
+
+  die "$romfile is not a ROM file\n"
+      unless substr ( $romdata, 0, 2 ) eq "\x55\xAA";
+
+  ( my $checklen ) = unpack ( 'C', substr ( $romdata, 2, 1 ) );
+  $checklen *= 512;
+  die "$romfile has incorrect length field $checklen (should be $len)\n"
+      unless $len == $checklen;
+
+  ( my $pci ) = unpack ( 'v', substr ( $romdata, PCI_OFF, 2 ) );
+  die "Invalid PCI offset field in $romfile\n"
+      if $pci >= $len;
+  die "No PCIR signature in $romfile\n"
+      unless substr ( $romdata, $pci, 4 ) eq "PCIR";
+  
+  ( my $indicator ) =
+      unpack ( 'C', substr ( $romdata, $pci + INDICATOR_OFF, 1 ) );
+  my $msg = sprintf ( "$romfile: indicator was %02x, ", $indicator );
+  $indicator &= ! ( 1 << 7 );
+  $indicator |= ( $last << 7 );
+  $msg .= sprintf ( "now %02x\n", $indicator );
+  substr ( $romdata, $pci + INDICATOR_OFF, 1 ) = pack ( 'C', $indicator );
+  warn $msg;
+
+  print $romdata;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/diffsize.pl b/qemu-0.15.x/roms/ipxe/src/util/diffsize.pl
new file mode 100755
index 0000000..ced0786
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/diffsize.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+# usage:
+# [somebody at somewhere ~/ipxe/src]$ ./util/diffsize.pl [<old rev> [<new rev>]]
+# by default <old rev> is HEAD and <new rev> is the working tree
+
+use strict;
+
+-d "bin" or die "Please run me in the iPXE src directory\n";
+mkdir ".sizes";
+
+my($oldrev, $newrev);
+my($oldname, $newname);
+
+if (@ARGV) {
+  $oldname = shift;
+} else {
+  $oldname = "HEAD";
+}
+
+if (@ARGV) {
+  $newname = shift;
+} else {
+  $newrev = "tree" . time();
+}
+
+$oldrev = `git rev-parse $oldname`;
+chomp $oldrev;
+
+unless (defined $newrev) {
+  $newrev = `git rev-parse $newname`;
+  chomp $newrev;
+}
+
+sub calc_sizes($$) {
+  my($name, $rev) = @_;
+  my $output;
+  my $lastrev;
+  my $stashed = 0;
+  my $res = 0;
+
+  return if -e ".sizes/$rev.sizes";
+
+  if (defined $name) {
+    $output = `git stash`;
+    $stashed = 1 unless $output =~ /No local changes to save/;
+    $lastrev = `git name-rev --name-only HEAD`;
+    system("git checkout $name >/dev/null"); $res ||= $?;
+  }
+
+  system("make -j4 bin/ipxe.lkrn >/dev/null"); $res ||= $?;
+  system("make bin/ipxe.lkrn.sizes > .sizes/$rev.sizes"); $res ||= $?;
+
+  if (defined $name) {
+    system("git checkout $lastrev >/dev/null"); $res ||= $?;
+    system("git stash pop >/dev/null") if $stashed; $res ||= $?;
+  }
+
+  if ($res) {
+    unlink(".sizes/$rev.sizes");
+    die "Error making sizes file\n";
+  }
+}
+
+our %Sizes;
+
+sub save_sizes($$) {
+  my($id, $rev) = @_;
+  my $file = ".sizes/$rev.sizes";
+
+  open SIZES, $file or die "opening $file: $!\n";
+  while (<SIZES>) {
+    my($text, $data, $bss, $total, $hex, $name) = split;
+    $name =~ s|bin/||; $name =~ s|\.o$||;
+
+    # Skip the header and totals lines
+    next if $total =~ /[a-z]/ or $name =~ /TOTALS/;
+
+    # Skip files named with dash, due to old Makefile bug
+    next if $name =~ /-/;
+
+    $Sizes{$name} = {old => 0, new => 0} unless exists $Sizes{$name};
+    $Sizes{$name}{$id} = $total;
+  }
+}
+
+calc_sizes($oldname, $oldrev);
+calc_sizes($newname, $newrev);
+
+save_sizes('old', $oldrev);
+save_sizes('new', $newrev);
+
+my $total = 0;
+
+for (sort keys %Sizes) {
+  my $diff = $Sizes{$_}{new} - $Sizes{$_}{old};
+  if (abs($diff) >= 16) {
+    printf "%12s %+d\n", substr($_, 0, 12), $Sizes{$_}{new} - $Sizes{$_}{old};
+  }
+  $total += $diff;
+}
+printf "      TOTAL: %+d\n", $total;
diff --git a/qemu-0.15.x/roms/ipxe/src/util/disrom.pl b/qemu-0.15.x/roms/ipxe/src/util/disrom.pl
new file mode 100755
index 0000000..1fb4cc3
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/disrom.pl
@@ -0,0 +1,81 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
+
+my $romfile = shift || "-";
+my $rom = new Option::ROM;
+$rom->load ( $romfile );
+
+die "Not an option ROM image\n"
+    unless $rom->{signature} == ROM_SIGNATURE;
+
+my $romlength = ( $rom->{length} * 512 );
+my $filelength = $rom->length;
+die "ROM image truncated (is $filelength, should be $romlength)\n"
+    if $filelength < $romlength;
+
+printf "ROM header:\n\n";
+printf "  %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 );
+printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum},
+       ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum;
+printf "  %-16s 0x%04x\n", "Init:", $rom->{init};
+printf "  %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header};
+printf "  %-16s 0x%04x\n", "PCI header:", $rom->{pci_header};
+printf "  %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header};
+printf "\n";
+
+my $pci = $rom->pci_header();
+if ( $pci ) {
+  printf "PCI header:\n\n";
+  printf "  %-16s %s\n", "Signature:", $pci->{signature};
+  printf "  %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id};
+  printf "  %-16s 0x%04x\n", "Device ID:", $pci->{device_id};
+  printf "  %-16s 0x%02x%02x%02x\n", "Device class:",
+	 $pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
+  printf "  %-16s 0x%04x (%d)\n", "Image length:",
+	 $pci->{image_length}, ( $pci->{image_length} * 512 );
+  printf "  %-16s 0x%04x (%d)\n", "Runtime length:",
+	 $pci->{runtime_length}, ( $pci->{runtime_length} * 512 );
+  if ( exists $pci->{conf_header} ) {
+    printf "  %-16s 0x%04x\n", "Config header:", $pci->{conf_header};
+    printf "  %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry};
+  }
+  printf "\n";
+}
+
+my $pnp = $rom->pnp_header();
+if ( $pnp ) {
+  printf "PnP header:\n\n";
+  printf "  %-16s %s\n", "Signature:", $pnp->{signature};
+  printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum},
+	 ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum;
+  printf "  %-16s 0x%04x \"%s\"\n", "Manufacturer:",
+	 $pnp->{manufacturer}, $pnp->manufacturer;
+  printf "  %-16s 0x%04x \"%s\"\n", "Product:",
+	 $pnp->{product}, $pnp->product;
+  printf "  %-16s 0x%04x\n", "BCV:", $pnp->{bcv};
+  printf "  %-16s 0x%04x\n", "BDV:", $pnp->{bdv};
+  printf "  %-16s 0x%04x\n", "BEV:", $pnp->{bev};
+  printf "\n";
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/efirom.c b/qemu-0.15.x/roms/ipxe/src/util/efirom.c
new file mode 100644
index 0000000..d0bdace
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/efirom.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/IndustryStandard/PeImage.h>
+#include <ipxe/efi/IndustryStandard/Pci22.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+/** Command-line options */
+struct options {
+	uint16_t vendor;
+	uint16_t device;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len		Length of memory to allocate
+ * @ret ptr		Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+	void *ptr;
+
+	ptr = malloc ( len );
+	if ( ! ptr ) {
+		eprintf ( "Could not allocate %zd bytes\n", len );
+		exit ( 1 );
+	}
+
+	return ptr;
+}
+
+/**
+ * Get file size
+ *
+ * @v file		File
+ * @v len		File size
+ */
+static size_t file_size ( FILE *file ) {
+	ssize_t len;
+
+	return len;
+}
+
+/**
+ * Read information from PE headers
+ *
+ * @v pe		PE file
+ * @ret machine		Machine type
+ * @ret subsystem	EFI subsystem
+ */
+static void read_pe_info ( void *pe, uint16_t *machine,
+			   uint16_t *subsystem ) {
+	EFI_IMAGE_DOS_HEADER *dos;
+	union {
+		EFI_IMAGE_NT_HEADERS32 nt32;
+		EFI_IMAGE_NT_HEADERS64 nt64;
+	} *nt;
+
+	/* Locate NT header */
+	dos = pe;
+	nt = ( pe + dos->e_lfanew );
+
+	/* Parse out PE information */
+	*machine = nt->nt32.FileHeader.Machine;
+	switch ( *machine ) {
+	case EFI_IMAGE_MACHINE_IA32:
+		*subsystem = nt->nt32.OptionalHeader.Subsystem;
+		break;
+	case EFI_IMAGE_MACHINE_X64:
+		*subsystem = nt->nt64.OptionalHeader.Subsystem;
+		break;
+	default:
+		eprintf ( "Unrecognised machine type %04x\n", *machine );
+		exit ( 1 );
+	}
+}
+
+/**
+ * Convert EFI image to ROM image
+ *
+ * @v pe		EFI file
+ * @v rom		ROM file
+ */
+static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
+	struct {
+		EFI_PCI_EXPANSION_ROM_HEADER rom;
+		PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
+		uint8_t checksum;
+	} *headers;
+	struct stat pe_stat;
+	size_t pe_size;
+	size_t rom_size;
+	void *buf;
+	void *payload;
+	unsigned int i;
+	uint8_t checksum;
+
+	/* Determine PE file size */
+	if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
+		eprintf ( "Could not stat PE file: %s\n",
+			  strerror ( errno ) );
+		exit ( 1 );
+	}
+	pe_size = pe_stat.st_size;
+
+	/* Determine ROM file size */
+	rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
+
+	/* Allocate ROM buffer and read in PE file */
+	buf = xmalloc ( rom_size );
+	memset ( buf, 0, rom_size );
+	headers = buf;
+	payload = ( buf + sizeof ( *headers ) );
+	if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
+		eprintf ( "Could not read PE file: %s\n",
+			  strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Construct ROM header */
+	headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
+	headers->rom.InitializationSize = ( rom_size / 512 );
+	headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
+	read_pe_info ( payload, &headers->rom.EfiMachineType,
+		       &headers->rom.EfiSubsystem );
+	headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
+	headers->rom.PcirOffset =
+		offsetof ( typeof ( *headers ), pci );
+	headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
+	headers->pci.VendorId = opts->vendor;
+	headers->pci.DeviceId = opts->device;
+	headers->pci.Length = sizeof ( headers->pci );
+	headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
+	headers->pci.ImageLength = ( rom_size / 512 );
+	headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
+	headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
+
+	/* Fix image checksum */
+	for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
+		checksum += *( ( uint8_t * ) buf + i );
+	headers->checksum -= checksum;
+
+	/* Write out ROM */
+	if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
+		eprintf ( "Could not write ROM file: %s\n",
+			  strerror ( errno ) );
+		exit ( 1 );
+	}
+}
+
+/**
+ * Print help
+ *
+ * @v program_name	Program name
+ */
+static void print_help ( const char *program_name ) {
+	eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] "
+		  "infile outfile\n", program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opts		Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+			   struct options *opts ) {
+	char *end;
+	int c;
+
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "vendor", required_argument, NULL, 'v' },
+			{ "device", required_argument, NULL, 'd' },
+			{ "help", 0, NULL, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		if ( ( c = getopt_long ( argc, argv, "v:d:h",
+					 long_options,
+					 &option_index ) ) == -1 ) {
+			break;
+		}
+
+		switch ( c ) {
+		case 'v':
+			opts->vendor = strtoul ( optarg, &end, 16 );
+			if ( *end ) {
+				eprintf ( "Invalid vendor \"%s\"\n", optarg );
+				exit ( 2 );
+			}
+			break;
+		case 'd':
+			opts->device = strtoul ( optarg, &end, 16 );
+			if ( *end ) {
+				eprintf ( "Invalid device \"%s\"\n", optarg );
+				exit ( 2 );
+			}
+			break;
+		case 'h':
+			print_help ( argv[0] );
+			exit ( 0 );
+		case '?':
+		default:
+			exit ( 2 );
+		}
+	}
+	return optind;
+}
+
+int main ( int argc, char **argv ) {
+	struct options opts = {
+	};
+	unsigned int infile_index;
+	const char *infile_name;
+	const char *outfile_name;
+	FILE *infile;
+	FILE *outfile;
+
+	/* Parse command-line arguments */
+	infile_index = parse_options ( argc, argv, &opts );
+	if ( argc != ( infile_index + 2 ) ) {
+		print_help ( argv[0] );
+		exit ( 2 );
+	}
+	infile_name = argv[infile_index];
+	outfile_name = argv[infile_index + 1];
+
+	/* Open input and output files */
+	infile = fopen ( infile_name, "r" );
+	if ( ! infile ) {
+		eprintf ( "Could not open %s for reading: %s\n",
+			  infile_name, strerror ( errno ) );
+		exit ( 1 );
+	}
+	outfile = fopen ( outfile_name, "w" );
+	if ( ! outfile ) {
+		eprintf ( "Could not open %s for writing: %s\n",
+			  outfile_name, strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Convert file */
+	make_efi_rom ( infile, outfile, &opts );
+
+	fclose ( outfile );
+	fclose ( infile );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/einfo.c b/qemu-0.15.x/roms/ipxe/src/util/einfo.c
new file mode 100644
index 0000000..06736f2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/einfo.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+/** Command-line options */
+struct options {
+};
+
+/** Error usage information */
+struct einfo {
+	uint32_t size;
+	uint32_t error;
+	uint32_t desc;
+	uint32_t file;
+	uint32_t line;
+} __attribute__ (( packed ));
+
+/**
+ * Process einfo file
+ *
+ * @v infile		Filename
+ * @v opts		Command-line options
+ */
+static void einfo ( const char *infile, struct options *opts ) {
+	int fd;
+	struct stat stat;
+	size_t len;
+	void *start;
+	struct einfo *einfo;
+
+	/* Open einfo file */
+	if ( ( fd = open ( infile, O_RDONLY ) ) < 0 ) {
+		eprintf ( "Cannot open \"%s\": %s\n",
+			  infile, strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Get file size */
+	if ( fstat ( fd, &stat ) < 0 ) {
+		eprintf ( "Cannot stat \"%s\": %s\n",
+			  infile, strerror ( errno ) );
+		exit ( 1 );
+	}
+	len = stat.st_size;
+
+	if ( len ) {
+
+		/* Map file */
+		if ( ( start = mmap ( NULL, len, PROT_READ, MAP_SHARED,
+				      fd, 0 ) ) == MAP_FAILED ) {
+			eprintf ( "Cannot mmap \"%s\": %s\n",
+				  infile, strerror ( errno ) );
+			exit ( 1 );
+		}
+
+		/* Iterate over einfo records */
+		for ( einfo = start ; ( ( void * ) einfo ) < ( start + len ) ;
+		      einfo = ( ( ( void * ) einfo ) + einfo->size ) ) {
+			printf ( "%08x\t%s\t%d\t%s\n", einfo->error,
+				 ( ( ( void * ) einfo ) + einfo->file ),
+				 einfo->line,
+				 ( ( ( void * ) einfo ) + einfo->desc ) );
+		}
+
+	}
+
+	/* Unmap and close file */
+	munmap ( start, len );
+	close ( fd );
+}
+
+/**
+ * Print help
+ *
+ * @v program_name	Program name
+ */
+static void print_help ( const char *program_name ) {
+	eprintf ( "Syntax: %s file1.einfo [file2.einfo...]\n",
+		  program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opts		Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+			   struct options *opts ) {
+	char *end;
+	int c;
+
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "help", 0, NULL, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		if ( ( c = getopt_long ( argc, argv, "s:h",
+					 long_options,
+					 &option_index ) ) == -1 ) {
+			break;
+		}
+
+		switch ( c ) {
+		case 'h':
+			print_help ( argv[0] );
+			exit ( 0 );
+		case '?':
+		default:
+			exit ( 2 );
+		}
+	}
+	return optind;
+}
+
+int main ( int argc, char **argv ) {
+	struct options opts = {
+	};
+	unsigned int infile_index;
+	const char *infile;
+
+	/* Parse command-line arguments */
+	infile_index = parse_options ( argc, argv, &opts );
+	if ( argc <= infile_index ) {
+		print_help ( argv[0] );
+		exit ( 2 );
+	}
+
+	/* Process each einfo file */
+	for ( ; infile_index < argc ; infile_index++ ) {
+		infile = argv[infile_index];
+		einfo ( infile, &opts );
+	}
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/elf2efi.c b/qemu-0.15.x/roms/ipxe/src/util/elf2efi.c
new file mode 100644
index 0000000..e662929
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/elf2efi.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <bfd.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/IndustryStandard/PeImage.h>
+#include <libgen.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define EFI_FILE_ALIGN 0x20
+
+struct pe_section {
+	struct pe_section *next;
+	EFI_IMAGE_SECTION_HEADER hdr;
+	uint8_t contents[0];
+};
+
+struct pe_relocs {
+	struct pe_relocs *next;
+	unsigned long start_rva;
+	unsigned int used_relocs;
+	unsigned int total_relocs;
+	uint16_t *relocs;
+};
+
+struct pe_header {
+	EFI_IMAGE_DOS_HEADER dos;
+	uint8_t padding[128];
+#if defined(EFI_TARGET_IA32)
+	EFI_IMAGE_NT_HEADERS32 nt;
+#elif defined(EFI_TARGET_X64)
+	EFI_IMAGE_NT_HEADERS64 nt;
+#endif
+};
+
+static struct pe_header efi_pe_header = {
+	.dos = {
+		.e_magic = EFI_IMAGE_DOS_SIGNATURE,
+		.e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
+	},
+	.nt = {
+		.Signature = EFI_IMAGE_NT_SIGNATURE,
+		.FileHeader = {
+#if defined(EFI_TARGET_IA32)
+			.Machine = EFI_IMAGE_MACHINE_IA32,
+#elif defined(EFI_TARGET_X64)
+			.Machine = EFI_IMAGE_MACHINE_X64,
+#endif
+			.TimeDateStamp = 0x10d1a884,
+			.SizeOfOptionalHeader =
+				sizeof ( efi_pe_header.nt.OptionalHeader ),
+			.Characteristics = ( EFI_IMAGE_FILE_DLL |
+#if defined(EFI_TARGET_IA32)
+					     EFI_IMAGE_FILE_32BIT_MACHINE |
+#endif
+					     EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
+		},
+		.OptionalHeader = {
+#if defined(EFI_TARGET_IA32)
+			.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
+#elif defined(EFI_TARGET_X64)
+			.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
+#endif
+			.SectionAlignment = EFI_FILE_ALIGN,
+			.FileAlignment = EFI_FILE_ALIGN,
+			.SizeOfImage = sizeof ( efi_pe_header ),
+			.SizeOfHeaders = sizeof ( efi_pe_header ),
+			.NumberOfRvaAndSizes =
+				EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+		},
+	},
+};
+
+/** Command-line options */
+struct options {
+	unsigned int subsystem;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len		Length of memory to allocate
+ * @ret ptr		Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+	void *ptr;
+
+	ptr = malloc ( len );
+	if ( ! ptr ) {
+		eprintf ( "Could not allocate %zd bytes\n", len );
+		exit ( 1 );
+	}
+
+	return ptr;
+}
+
+/**
+ * Align section within PE file
+ *
+ * @v offset		Unaligned offset
+ * @ret aligned_offset	Aligned offset
+ */
+static unsigned long efi_file_align ( unsigned long offset ) {
+	return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab		PE relocation table
+ * @v rva		RVA
+ * @v size		Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+				unsigned long rva, size_t size ) {
+	unsigned long start_rva;
+	uint16_t reloc;
+	struct pe_relocs *pe_rel;
+	uint16_t *relocs;
+
+	/* Construct */
+	start_rva = ( rva & ~0xfff );
+	reloc = ( rva & 0xfff );
+	switch ( size ) {
+	case 8:
+		reloc |= 0xa000;
+		break;
+	case 4:
+		reloc |= 0x3000;
+		break;
+	case 2:
+		reloc |= 0x2000;
+		break;
+	default:
+		eprintf ( "Unsupported relocation size %zd\n", size );
+		exit ( 1 );
+	}
+
+	/* Locate or create PE relocation table */
+	for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+		if ( pe_rel->start_rva == start_rva )
+			break;
+	}
+	if ( ! pe_rel ) {
+		pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+		memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+		pe_rel->next = *pe_reltab;
+		*pe_reltab = pe_rel;
+		pe_rel->start_rva = start_rva;
+	}
+
+	/* Expand relocation list if necessary */
+	if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+		relocs = pe_rel->relocs;
+	} else {
+		pe_rel->total_relocs = ( pe_rel->total_relocs ?
+					 ( pe_rel->total_relocs * 2 ) : 256 );
+		relocs = xmalloc ( pe_rel->total_relocs *
+				   sizeof ( pe_rel->relocs[0] ) );
+		memset ( relocs, 0,
+			 pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+		memcpy ( relocs, pe_rel->relocs,
+			 pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+		free ( pe_rel->relocs );
+		pe_rel->relocs = relocs;
+	}
+
+	/* Store relocation */
+	pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab		PE relocation table
+ * @v buffer		Buffer to contain binary table, or NULL
+ * @ret size		Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+				 void *buffer ) {
+	struct pe_relocs *pe_rel;
+	unsigned int num_relocs;
+	size_t size;
+	size_t total_size = 0;
+
+	for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+		num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+		size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+			 sizeof ( uint32_t ) /* SizeOfBlock */ +
+			 ( num_relocs * sizeof ( uint16_t ) ) );
+		if ( buffer ) {
+			*( (uint32_t *) ( buffer + total_size + 0 ) )
+				= pe_rel->start_rva;
+			*( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+			memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+				 ( num_relocs * sizeof ( uint16_t ) ) );
+		}
+		total_size += size;
+	}
+
+	return total_size;
+}
+
+/**
+ * Open input BFD file
+ *
+ * @v filename		File name
+ * @ret ibfd		BFD file
+ */
+static bfd * open_input_bfd ( const char *filename ) {
+	bfd *bfd;
+
+	/* Open the file */
+	bfd = bfd_openr ( filename, NULL );
+	if ( ! bfd ) {
+		eprintf ( "Cannot open %s: ", filename );
+		bfd_perror ( NULL );
+		exit ( 1 );
+	}
+
+	/* The call to bfd_check_format() must be present, otherwise
+	 * we get a segfault from later BFD calls.
+	 */
+	if ( ! bfd_check_format ( bfd, bfd_object ) ) {
+		eprintf ( "%s is not an object file: ", filename );
+		bfd_perror ( NULL );
+		exit ( 1 );
+	}
+
+	return bfd;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd		BFD file
+ */
+static asymbol ** read_symtab ( bfd *bfd ) {
+	long symtab_size;
+	asymbol **symtab;
+	long symcount;
+
+	/* Get symbol table size */
+	symtab_size = bfd_get_symtab_upper_bound ( bfd );
+	if ( symtab_size < 0 ) {
+		bfd_perror ( "Could not get symbol table upper bound" );
+		exit ( 1 );
+	}
+
+	/* Allocate and read symbol table */
+	symtab = xmalloc ( symtab_size );
+	symcount = bfd_canonicalize_symtab ( bfd, symtab );
+	if ( symcount < 0 ) {
+		bfd_perror ( "Cannot read symbol table" );
+		exit ( 1 );
+	}
+
+	return symtab;
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd		BFD file
+ * @v symtab		Symbol table
+ * @v section		Section
+ * @v symtab		Symbol table
+ * @ret reltab		Relocation table
+ */
+static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
+				asection *section ) {
+	long reltab_size;
+	arelent **reltab;
+	long numrels;
+
+	/* Get relocation table size */
+	reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
+	if ( reltab_size < 0 ) {
+		bfd_perror ( "Could not get relocation table upper bound" );
+		exit ( 1 );
+	}
+
+	/* Allocate and read relocation table */
+	reltab = xmalloc ( reltab_size );
+	numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
+	if ( numrels < 0 ) {
+		bfd_perror ( "Cannot read relocation table" );
+		exit ( 1 );
+	}
+
+	return reltab;
+}
+
+/**
+ * Process section
+ *
+ * @v bfd		BFD file
+ * @v pe_header		PE file header
+ * @v section		Section
+ * @ret new		New PE section
+ */
+static struct pe_section * process_section ( bfd *bfd,
+					     struct pe_header *pe_header,
+					     asection *section ) {
+	struct pe_section *new;
+	size_t section_memsz;
+	size_t section_filesz;
+	unsigned long flags = bfd_get_section_flags ( bfd, section );
+	unsigned long code_start;
+	unsigned long code_end;
+	unsigned long data_start;
+	unsigned long data_mid;
+	unsigned long data_end;
+	unsigned long start;
+	unsigned long end;
+	unsigned long *applicable_start;
+	unsigned long *applicable_end;
+
+	/* Extract current RVA limits from file header */
+	code_start = pe_header->nt.OptionalHeader.BaseOfCode;
+	code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+#if defined(EFI_TARGET_IA32)
+	data_start = pe_header->nt.OptionalHeader.BaseOfData;
+#elif defined(EFI_TARGET_X64)
+	data_start = code_end;
+#endif
+	data_mid = ( data_start +
+		     pe_header->nt.OptionalHeader.SizeOfInitializedData );
+	data_end = ( data_mid +
+		     pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+
+	/* Allocate PE section */
+	section_memsz = bfd_section_size ( bfd, section );
+	section_filesz = ( ( flags & SEC_LOAD ) ?
+			   efi_file_align ( section_memsz ) : 0 );
+	new = xmalloc ( sizeof ( *new ) + section_filesz );
+	memset ( new, 0, sizeof ( *new ) + section_filesz );
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) new->hdr.Name, section->name,
+		  sizeof ( new->hdr.Name ) );
+	new->hdr.Misc.VirtualSize = section_memsz;
+	new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
+	new->hdr.SizeOfRawData = section_filesz;
+
+	/* Fill in section characteristics and update RVA limits */
+	if ( flags & SEC_CODE ) {
+		/* .text-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_CODE |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_EXECUTE |
+			  EFI_IMAGE_SCN_MEM_READ );
+		applicable_start = &code_start;
+		applicable_end = &code_end;
+	} else if ( flags & SEC_DATA ) {
+		/* .data-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ |
+			  EFI_IMAGE_SCN_MEM_WRITE );
+		applicable_start = &data_start;
+		applicable_end = &data_mid;
+	} else if ( flags & SEC_READONLY ) {
+		/* .rodata-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ );
+		applicable_start = &data_start;
+		applicable_end = &data_mid;
+	} else if ( ! ( flags & SEC_LOAD ) ) {
+		/* .bss-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ |
+			  EFI_IMAGE_SCN_MEM_WRITE );
+		applicable_start = &data_mid;
+		applicable_end = &data_end;
+	}
+
+	/* Copy in section contents */
+	if ( flags & SEC_LOAD ) {
+		if ( ! bfd_get_section_contents ( bfd, section, new->contents,
+						  0, section_memsz ) ) {
+			eprintf ( "Cannot read section %s: ", section->name );
+			bfd_perror ( NULL );
+			exit ( 1 );
+		}
+	}
+
+	/* Update RVA limits */
+	start = new->hdr.VirtualAddress;
+	end = ( start + new->hdr.Misc.VirtualSize );
+	if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
+		*applicable_start = start;
+	if ( *applicable_end < end )
+		*applicable_end = end;
+	if ( data_start < code_end )
+		data_start = code_end;
+	if ( data_mid < data_start )
+		data_mid = data_start;
+	if ( data_end < data_mid )
+		data_end = data_mid;
+
+	/* Write RVA limits back to file header */
+	pe_header->nt.OptionalHeader.BaseOfCode = code_start;
+	pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
+#if defined(EFI_TARGET_IA32)
+	pe_header->nt.OptionalHeader.BaseOfData = data_start;
+#endif
+	pe_header->nt.OptionalHeader.SizeOfInitializedData =
+		( data_mid - data_start );
+	pe_header->nt.OptionalHeader.SizeOfUninitializedData =
+		( data_end - data_mid );
+
+	/* Update remaining file header fields */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage =
+		efi_file_align ( data_end );
+
+	return new;
+}
+
+/**
+ * Process relocation record
+ *
+ * @v bfd		BFD file
+ * @v section		Section
+ * @v rel		Relocation entry
+ * @v pe_reltab		PE relocation table to fill in
+ */
+static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
+			    struct pe_relocs **pe_reltab ) {
+	reloc_howto_type *howto = rel->howto;
+	asymbol *sym = *(rel->sym_ptr_ptr);
+	unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
+				 rel->address );
+
+	if ( bfd_is_abs_section ( sym->section ) ) {
+		/* Skip absolute symbols; the symbol value won't
+		 * change when the object is loaded.
+		 */
+	} else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
+		/* Generate an 8-byte PE relocation */
+		generate_pe_reloc ( pe_reltab, offset, 8 );
+	} else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
+		    ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
+		/* Generate a 4-byte PE relocation */
+		generate_pe_reloc ( pe_reltab, offset, 4 );
+	} else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+		/* Generate a 2-byte PE relocation */
+		generate_pe_reloc ( pe_reltab, offset, 2 );
+	} else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
+		    ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
+		/* Skip PC-relative relocations; all relative offsets
+		 * remain unaltered when the object is loaded.
+		 */
+	} else {
+		eprintf ( "Unrecognised relocation type %s\n", howto->name );
+		exit ( 1 );
+	}
+}
+
+/**
+ * Create relocations section
+ *
+ * @v pe_header		PE file header
+ * @v pe_reltab		PE relocation table
+ * @ret section		Relocation section
+ */
+static struct pe_section *
+create_reloc_section ( struct pe_header *pe_header,
+		       struct pe_relocs *pe_reltab ) {
+	struct pe_section *reloc;
+	size_t section_memsz;
+	size_t section_filesz;
+	EFI_IMAGE_DATA_DIRECTORY *relocdir;
+
+	/* Allocate PE section */
+	section_memsz = output_pe_reltab ( pe_reltab, NULL );
+	section_filesz = efi_file_align ( section_memsz );
+	reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
+	memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
+		  sizeof ( reloc->hdr.Name ) );
+	reloc->hdr.Misc.VirtualSize = section_memsz;
+	reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+	reloc->hdr.SizeOfRawData = section_filesz;
+	reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
+				       EFI_IMAGE_SCN_MEM_READ );
+
+	/* Copy in section contents */
+	output_pe_reltab ( pe_reltab, reloc->contents );
+
+	/* Update file header details */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+	relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
+		     [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+	relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
+	relocdir->Size = reloc->hdr.Misc.VirtualSize;
+
+	return reloc;
+}
+
+/**
+ * Create debug section
+ *
+ * @v pe_header		PE file header
+ * @ret section		Debug section
+ */
+static struct pe_section *
+create_debug_section ( struct pe_header *pe_header, const char *filename ) {
+	struct pe_section *debug;
+	size_t section_memsz;
+	size_t section_filesz;
+	EFI_IMAGE_DATA_DIRECTORY *debugdir;
+	struct {
+		EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
+		EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
+		char name[ strlen ( filename ) + 1 ];
+	} *contents;
+
+	/* Allocate PE section */
+	section_memsz = sizeof ( *contents );
+	section_filesz = efi_file_align ( section_memsz );
+	debug = xmalloc ( sizeof ( *debug ) + section_filesz );
+	memset ( debug, 0, sizeof ( *debug ) + section_filesz );
+	contents = ( void * ) debug->contents;
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) debug->hdr.Name, ".debug",
+		  sizeof ( debug->hdr.Name ) );
+	debug->hdr.Misc.VirtualSize = section_memsz;
+	debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+	debug->hdr.SizeOfRawData = section_filesz;
+	debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
+				       EFI_IMAGE_SCN_MEM_READ );
+
+	/* Create section contents */
+	contents->debug.TimeDateStamp = 0x10d1a884;
+	contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
+	contents->debug.SizeOfData =
+		( sizeof ( *contents ) - sizeof ( contents->debug ) );
+	contents->debug.RVA = ( debug->hdr.VirtualAddress +
+				offsetof ( typeof ( *contents ), rsds ) );
+	contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
+	snprintf ( contents->name, sizeof ( contents->name ), "%s",
+		   filename );
+
+	/* Update file header details */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+	debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
+		     [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+	debugdir->VirtualAddress = debug->hdr.VirtualAddress;
+	debugdir->Size = debug->hdr.Misc.VirtualSize;
+
+	return debug;
+}
+
+/**
+ * Write out PE file
+ *
+ * @v pe_header		PE file header
+ * @v pe_sections	List of PE sections
+ * @v pe		Output file
+ */
+static void write_pe_file ( struct pe_header *pe_header,
+			    struct pe_section *pe_sections,
+			    FILE *pe ) {
+	struct pe_section *section;
+	unsigned long fpos = 0;
+
+	/* Assign raw data pointers */
+	fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( section->hdr.SizeOfRawData ) {
+			section->hdr.PointerToRawData = fpos;
+			fpos += section->hdr.SizeOfRawData;
+			fpos = efi_file_align ( fpos );
+		}
+	}
+
+	/* Write file header */
+	if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
+		perror ( "Could not write PE header" );
+		exit ( 1 );
+	}
+
+	/* Write section headers */
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
+			      1, pe ) != 1 ) {
+			perror ( "Could not write section header" );
+			exit ( 1 );
+		}
+	}
+
+	/* Write sections */
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( fseek ( pe, section->hdr.PointerToRawData,
+			     SEEK_SET ) != 0 ) {
+			eprintf ( "Could not seek to %lx: %s\n",
+				  section->hdr.PointerToRawData,
+				  strerror ( errno ) );
+			exit ( 1 );
+		}
+		if ( section->hdr.SizeOfRawData &&
+		     ( fwrite ( section->contents, section->hdr.SizeOfRawData,
+				1, pe ) != 1 ) ) {
+			eprintf ( "Could not write section %.8s: %s\n",
+				  section->hdr.Name, strerror ( errno ) );
+			exit ( 1 );
+		}
+	}
+}
+
+/**
+ * Convert ELF to PE
+ *
+ * @v elf_name		ELF file name
+ * @v pe_name		PE file name
+ */
+static void elf2pe ( const char *elf_name, const char *pe_name,
+		     struct options *opts ) {
+	char pe_name_tmp[ strlen ( pe_name ) + 1 ];
+	bfd *bfd;
+	asymbol **symtab;
+	asection *section;
+	arelent **reltab;
+	arelent **rel;
+	struct pe_relocs *pe_reltab = NULL;
+	struct pe_section *pe_sections = NULL;
+	struct pe_section **next_pe_section = &pe_sections;
+	struct pe_header pe_header;
+	FILE *pe;
+
+	/* Create a modifiable copy of the PE name */
+	memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
+
+	/* Open the file */
+	bfd = open_input_bfd ( elf_name );
+	symtab = read_symtab ( bfd );
+
+	/* Initialise the PE header */
+	memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
+	pe_header.nt.OptionalHeader.AddressOfEntryPoint =
+		bfd_get_start_address ( bfd );
+	pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
+
+	/* For each input section, build an output section and create
+	 * the appropriate relocation records
+	 */
+	for ( section = bfd->sections ; section ; section = section->next ) {
+		/* Discard non-allocatable sections */
+		if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
+			continue;
+		/* Create output section */
+		*(next_pe_section) = process_section ( bfd, &pe_header,
+						       section );
+		next_pe_section = &(*next_pe_section)->next;
+		/* Add relocations from this section */
+		reltab = read_reltab ( bfd, symtab, section );
+		for ( rel = reltab ; *rel ; rel++ )
+			process_reloc ( bfd, section, *rel, &pe_reltab );
+		free ( reltab );
+	}
+
+	/* Create the .reloc section */
+	*(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
+	next_pe_section = &(*next_pe_section)->next;
+
+	/* Create the .reloc section */
+	*(next_pe_section) = create_debug_section ( &pe_header,
+						    basename ( pe_name_tmp ) );
+	next_pe_section = &(*next_pe_section)->next;
+
+	/* Write out PE file */
+	pe = fopen ( pe_name, "w" );
+	if ( ! pe ) {
+		eprintf ( "Could not open %s for writing: %s\n",
+			  pe_name, strerror ( errno ) );
+		exit ( 1 );
+	}
+	write_pe_file ( &pe_header, pe_sections, pe );
+	fclose ( pe );
+
+	/* Close BFD file */
+	bfd_close ( bfd );
+}
+
+/**
+ * Print help
+ *
+ * @v program_name	Program name
+ */
+static void print_help ( const char *program_name ) {
+	eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
+		  program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opts		Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+			   struct options *opts ) {
+	char *end;
+	int c;
+
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "subsystem", required_argument, NULL, 's' },
+			{ "help", 0, NULL, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		if ( ( c = getopt_long ( argc, argv, "s:h",
+					 long_options,
+					 &option_index ) ) == -1 ) {
+			break;
+		}
+
+		switch ( c ) {
+		case 's':
+			opts->subsystem = strtoul ( optarg, &end, 0 );
+			if ( *end ) {
+				eprintf ( "Invalid subsytem \"%s\"\n",
+					  optarg );
+				exit ( 2 );
+			}
+			break;
+		case 'h':
+			print_help ( argv[0] );
+			exit ( 0 );
+		case '?':
+		default:
+			exit ( 2 );
+		}
+	}
+	return optind;
+}
+
+int main ( int argc, char **argv ) {
+	struct options opts = {
+		.subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
+	};
+	unsigned int infile_index;
+	const char *infile;
+	const char *outfile;
+
+	/* Initialise libbfd */
+	bfd_init();
+
+	/* Parse command-line arguments */
+	infile_index = parse_options ( argc, argv, &opts );
+	if ( argc != ( infile_index + 2 ) ) {
+		print_help ( argv[0] );
+		exit ( 2 );
+	}
+	infile = argv[infile_index];
+	outfile = argv[infile_index + 1];
+
+	/* Convert file */
+	elf2pe ( infile, outfile, &opts );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/fixrom.pl b/qemu-0.15.x/roms/ipxe/src/util/fixrom.pl
new file mode 100755
index 0000000..c3a31f4
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/fixrom.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
+
+my @romfiles = @ARGV;
+
+foreach my $romfile ( @romfiles ) {
+  my $rom = new Option::ROM;
+  $rom->load ( $romfile );
+  $rom->pnp_header->fix_checksum() if $rom->pnp_header;
+  $rom->fix_checksum();
+  $rom->save ( $romfile );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/fnrec.pl b/qemu-0.15.x/roms/ipxe/src/util/fnrec.pl
new file mode 100755
index 0000000..9a2b3d8
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/fnrec.pl
@@ -0,0 +1,145 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=head1 NAME
+
+fnrec.pl
+
+=head1 SYNOPSIS
+
+fnrec.pl [options] bin/image.xxx < logfile
+
+Decode a function trace produced by building with FNREC=1
+
+Options:
+
+	-m,--max-depth=N	Set maximum displayed function depth
+
+=cut
+
+use IPC::Open2;
+use Getopt::Long;
+use Pod::Usage;
+use strict;
+use warnings;
+
+use constant MAX_OPEN_BRACE => 10;
+use constant MAX_COMMON_BRACE => 3;
+use constant MAX_CLOSE_BRACE => 10;
+
+# Parse command-line options
+my $max_depth = 16;
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+  'help|h' => sub { pod2usage ( 1 ); },
+  'max-depth|m=i' => sub { shift; $max_depth = shift; },
+) or die "Could not parse command-line options\n";
+pod2usage ( 1 ) unless @ARGV == 1;
+my $image = shift;
+my $elf = $image.".tmp";
+die "ELF file ".$elf." not found\n" unless -e $elf;
+
+# Start up addr2line
+my $addr2line_pid = open2 ( my $addr2line_out, my $addr2line_in,
+			    "addr2line", "-f", "-e", $elf )
+    or die "Could not start addr2line: $!\n";
+
+# Translate address using addr2line
+sub addr2line {
+  my $address = shift;
+
+  print $addr2line_in $address."\n";
+  chomp ( my $name = <$addr2line_out> );
+  chomp ( my $file_line = <$addr2line_out> );
+  ( my $file, my $line ) = ( $file_line =~ /^(.*):(\d+)$/ );
+  $file =~ s/^.*\/src\///;
+  my $location = ( $line ? $file.":".$line." = ".$address : $address );
+  return ( $name, $location );
+}
+
+# Parse logfile
+my $depth = 0;
+my $depths = [];
+while ( my $line = <> ) {
+  chomp $line;
+  $line =~ s/\r//g;
+  ( my $called_fn, my $call_site, my $entry_count, my $exit_count ) =
+      ( $line =~ /^(0x[0-9a-f]+)\s+(0x[0-9a-f]+)\s+([0-9]+)\s+([0-9]+)$/ )
+      or print $line."\n" and next;
+
+  ( my $called_fn_name, undef ) = addr2line ( $called_fn );
+  ( undef, my $call_site_location ) = addr2line ( $call_site );
+  $entry_count = ( $entry_count + 0 );
+  $exit_count = ( $exit_count + 0 );
+
+  if ( $entry_count >= $exit_count ) {
+    #
+    # Function entry
+    #
+    my $text = "";
+    $text .= $called_fn_name." (from ".$call_site_location.")";
+    if ( $exit_count <= MAX_COMMON_BRACE ) {
+      $text .= " { }" x $exit_count;
+    } else {
+      $text .= " { } x ".$exit_count;
+    }
+    $entry_count -= $exit_count;
+    if ( $entry_count <= MAX_OPEN_BRACE ) {
+      $text .= " {" x $entry_count;
+    } else {
+      $text .= " { x ".$entry_count;
+    }
+    my $indent = "  " x $depth;
+    print $indent.$text."\n";
+    $depth += $entry_count;
+    $depth = $max_depth if ( $depth > $max_depth );
+    push @$depths, ( { called_fn => $called_fn, call_site => $call_site } ) x
+	( $depth - @$depths );
+  } else {
+    #
+    # Function exit
+    #
+    my $text = "";
+    if ( $entry_count <= MAX_COMMON_BRACE ) {
+      $text .= " { }" x $entry_count;
+    } else {
+      $text .= " { } x ".$entry_count;
+    }
+    $exit_count -= $entry_count;
+    if ( $exit_count <= MAX_CLOSE_BRACE ) {
+      $text .= " }" x $exit_count;
+    } else {
+      $text .= " } x ".$exit_count;
+    }
+    $depth -= $exit_count;
+    $depth = 0 if ( $depth < 0 );
+    if ( ( @$depths == 0 ) ||
+	 ( $depths->[$depth]->{called_fn} ne $called_fn ) ||
+	 ( $depths->[$depth]->{call_site} ne $call_site ) ) {
+      $text .= " (from ".$called_fn_name." to ".$call_site_location.")";
+    }
+    splice ( @$depths, $depth );
+    my $indent = "  " x $depth;
+    print substr ( $indent.$text, 1 )."\n";
+  }
+}
+
+# Clean up addr2line
+close $addr2line_in;
+close $addr2line_out;
+waitpid ( $addr2line_pid, 0 );
diff --git a/qemu-0.15.x/roms/ipxe/src/util/geniso b/qemu-0.15.x/roms/ipxe/src/util/geniso
new file mode 100755
index 0000000..790e717
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/geniso
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# Generate a isolinux ISO boot image
+#
+# geniso foo.iso foo.lkrn
+#
+# the ISO image is the first argument so that a list of .lkrn images
+# to include can be specified
+#
+case $# in
+0|1)
+	echo Usage: $0 foo.iso foo.lkrn ...
+	exit 1
+	;;
+esac
+
+# This should be the default location of the isolinux.bin file
+isolinux_bin=${ISOLINUX_BIN:-util/isolinux.bin}
+if [ ! -r $isolinux_bin ]
+then
+	echo $0: $isolinux_bin not found, please install, or set ISOLINUX_BIN in arch/i386/Makefile correctly
+	exit 1
+fi
+
+# There should either be mkisofs or the compatible genisoimage program
+mkisofs=`which mkisofs genisoimage 2>/dev/null | head -n1`
+if [ -z $mkisofs ]
+then
+	echo $0: mkisofs or genisoimage not found, please install or set PATH
+	exit 1
+fi
+
+# isohybrid will be used if available
+isohybrid=`which isohybrid 2>/dev/null`
+
+out=$1
+shift
+dir=`mktemp -d bin/iso.dir.XXXXXX`
+cfg=$dir/isolinux.cfg
+cp -p $isolinux_bin $dir
+cat > $cfg <<EOF
+# These default options can be changed in the geniso script
+SAY iPXE ISO boot image
+TIMEOUT 30
+EOF
+first=
+for f
+do
+	if [ ! -r $f ]
+	then
+		echo $f does not exist, skipping 1>&2
+		continue
+	fi
+	b=$(basename $f)
+	g=${b%.lkrn}
+	g=${g//[^a-z0-9]}.krn
+	case "$first" in
+	"")
+		echo DEFAULT $g
+		;;
+	esac
+	first=$g
+	echo LABEL $b
+	echo "" KERNEL $g
+	cp -p $f $dir/$g
+done >> $cfg
+$mkisofs -quiet -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
+rm -fr $dir
+if [ -n "$isohybrid" ]
+then
+    $isohybrid $out >/dev/null
+fi
diff --git a/qemu-0.15.x/roms/ipxe/src/util/genkeymap.pl b/qemu-0.15.x/roms/ipxe/src/util/genkeymap.pl
new file mode 100755
index 0000000..d556df2
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/genkeymap.pl
@@ -0,0 +1,235 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2011 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=head1 NAME
+
+genkeymap.pl
+
+=head1 SYNOPSIS
+
+genkeymap.pl [options] <keymap name>
+
+Options:
+
+    -f,--from=<name>	Set BIOS keymap name (default "us")
+    -h,--help		Display brief help message
+    -v,--verbose	Increase verbosity
+    -q,--quiet		Decrease verbosity
+
+=cut
+
+# With reference to:
+#
+# http://gunnarwrobel.de/wiki/Linux-and-the-keyboard.html
+
+use Getopt::Long;
+use Pod::Usage;
+use strict;
+use warnings;
+
+use constant BIOS_KEYMAP => "us";
+use constant BKEYMAP_MAGIC => "bkeymap";
+use constant MAX_NR_KEYMAPS => 256;
+use constant NR_KEYS => 128;
+use constant KG_SHIFT => 0;
+use constant KG_ALTGR => 1;
+use constant KG_CTRL => 2;
+use constant KG_ALT => 3;
+use constant KG_SHIFTL => 4;
+use constant KG_KANASHIFT => 4;
+use constant KG_SHIFTR => 5;
+use constant KG_CTRLL => 6;
+use constant KG_CTRLR => 7;
+use constant KG_CAPSSHIFT => 8;
+use constant KT_LATIN => 0;
+use constant KT_FN => 1;
+use constant KT_SPEC => 2;
+use constant KT_PAD => 3;
+use constant KT_DEAD => 4;
+use constant KT_CONS => 5;
+use constant KT_CUR => 6;
+use constant KT_SHIFT => 7;
+use constant KT_META => 8;
+use constant KT_ASCII => 9;
+use constant KT_LOCK => 10;
+use constant KT_LETTER => 11;
+use constant KT_SLOCK => 12;
+use constant KT_SPKUP => 14;
+
+my $verbosity = 1;
+my $from_name = BIOS_KEYMAP;
+
+# Read named keymaps using "loadkeys -b"
+#
+sub read_keymaps {
+  my $name = shift;
+  my $keymaps = [];
+
+  # Generate binary keymap
+  open my $pipe, "-|", "loadkeys", "-b", $name
+      or die "Could not load keymap \"".$name."\": $!\n";
+
+  # Check magic
+  read $pipe, my $magic, length BKEYMAP_MAGIC
+      or die "Could not read from \"".$name."\": $!\n";
+  die "Bad magic value from \"".$name."\"\n"
+      unless $magic eq BKEYMAP_MAGIC;
+
+  # Read list of included keymaps
+  read $pipe, my $included, MAX_NR_KEYMAPS
+      or die "Could not read from \"".$name."\": $!\n";
+  my @included = unpack ( "C*", $included );
+  die "Missing or truncated keymap list from \"".$name."\"\n"
+      unless @included == MAX_NR_KEYMAPS;
+
+  # Read each keymap in turn
+  for ( my $keymap = 0 ; $keymap < MAX_NR_KEYMAPS ; $keymap++ ) {
+    if ( $included[$keymap] ) {
+      read $pipe, my $keysyms, ( NR_KEYS * 2 )
+	  or die "Could not read from \"".$name."\": $!\n";
+      my @keysyms = unpack ( "S*", $keysyms );
+      die "Missing or truncated keymap ".$keymap." from \"".$name."\"\n"
+	  unless @keysyms == NR_KEYS;
+      push @$keymaps, \@keysyms;
+    } else {
+      push @$keymaps, undef;
+    }
+  }
+
+  close $pipe;
+  return $keymaps;
+}
+
+# Translate keysym value to ASCII
+#
+sub keysym_to_ascii {
+  my $keysym = shift;
+
+  # Non-existent keysyms have no ASCII equivalent
+  return unless $keysym;
+
+  # Sanity check
+  die "Unexpected keysym ".sprintf ( "0x%04x\n", $keysym )."\n"
+      if $keysym & 0xf000;
+
+  # Extract type and value
+  my $type = ( $keysym >> 8 );
+  my $value = ( $keysym & 0xff );
+
+  # Non-simple types have no ASCII equivalent
+  return unless ( ( $type == KT_LATIN ) || ( $type == KT_ASCII ) ||
+		  ( $type == KT_LETTER ) );
+
+  # High-bit-set characters cannot be generated on a US keyboard
+  return if $value & 0x80;
+
+  return $value;
+}
+
+# Translate ASCII to descriptive name
+#
+sub ascii_to_name {
+  my $ascii = shift;
+
+  if ( $ascii == 0x5c ) {
+    return "'\\\\'";
+  } elsif ( $ascii == 0x27 ) {
+    return "'\\\''";
+  } elsif ( ( $ascii >= 0x20 ) && ( $ascii <= 0x7e ) ) {
+    return sprintf ( "'%c'", $ascii );
+  } elsif ( $ascii <= 0x1a ) {
+    return sprintf ( "Ctrl-%c", ( 0x40 + $ascii ) );
+  } else {
+    return sprintf ( "0x%02x", $ascii );
+  }
+}
+
+# Produce translation table between two keymaps
+#
+sub translate_keymaps {
+  my $from = shift;
+  my $to = shift;
+  my $map = {};
+
+  foreach my $keymap ( 0, 1 << KG_SHIFT, 1 << KG_CTRL ) {
+    for ( my $keycode = 0 ; $keycode < NR_KEYS ; $keycode++ ) {
+      my $from_ascii = keysym_to_ascii ( $from->[$keymap]->[$keycode] )
+	  or next;
+      my $to_ascii = keysym_to_ascii ( $to->[$keymap]->[$keycode] )
+	  or next;
+      my $new_map = ( ! exists $map->{$from_ascii} );
+      my $update_map =
+	  ( $new_map || ( $keycode < $map->{$from_ascii}->{keycode} ) );
+      if ( ( $verbosity > 1 ) &&
+	   ( ( $from_ascii != $to_ascii ) ||
+	     ( $update_map && ! $new_map ) ) ) {
+	printf STDERR "In keymap %d: %s => %s%s\n", $keymap,
+	       ascii_to_name ( $from_ascii ), ascii_to_name ( $to_ascii ),
+	       ( $update_map ? ( $new_map ? "" : " (override)" )
+			     : " (ignored)" );
+      }
+      if ( $update_map ) {
+	$map->{$from_ascii} = {
+	  to_ascii => $to_ascii,
+	  keycode => $keycode,
+	};
+      }
+    }
+  }
+  return { map { $_ => $map->{$_}->{to_ascii} } keys %$map };
+}
+
+# Parse command-line options
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+  'verbose|v+' => sub { $verbosity++; },
+  'quiet|q+' => sub { $verbosity--; },
+  'from|f=s' => sub { shift; $from_name = shift; },
+  'help|h' => sub { pod2usage ( 1 ); },
+) or die "Could not parse command-line options\n";
+pod2usage ( 1 ) unless @ARGV == 1;
+my $to_name = shift;
+
+# Read and translate keymaps
+my $from = read_keymaps ( $from_name );
+my $to = read_keymaps ( $to_name );
+my $map = translate_keymaps ( $from, $to );
+
+# Generate output
+( my $to_name_c = $to_name ) =~ s/\W/_/g;
+printf "/** \@file\n";
+printf " *\n";
+printf " * \"".$to_name."\" keyboard mapping\n";
+printf " *\n";
+printf " * This file is automatically generated; do not edit\n";
+printf " *\n";
+printf " */\n";
+printf "\n";
+printf "FILE_LICENCE ( PUBLIC_DOMAIN );\n";
+printf "\n";
+printf "#include <ipxe/keymap.h>\n";
+printf "\n";
+printf "/** \"".$to_name."\" keyboard mapping */\n";
+printf "struct key_mapping ".$to_name_c."_mapping[] __keymap = {\n";
+foreach my $from_sym ( sort { $a <=> $b } keys %$map ) {
+  my $to_sym = $map->{$from_sym};
+  next if $from_sym == $to_sym;
+  printf "\t{ 0x%02x, 0x%02x },\t/* %s => %s */\n", $from_sym, $to_sym,
+	 ascii_to_name ( $from_sym ), ascii_to_name ( $to_sym );
+}
+printf "};\n";
diff --git a/qemu-0.15.x/roms/ipxe/src/util/genliso b/qemu-0.15.x/roms/ipxe/src/util/genliso
new file mode 100755
index 0000000..184408a
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/genliso
@@ -0,0 +1,74 @@
+#!/bin/bash
+#
+# Generate a legacy floppy emulation ISO boot image
+#
+# genliso foo.liso foo.lkrn bar.lkrn ...
+#
+# The .liso image filename is the first argument followed by
+#   a list of .lkrn images  include in .liso image
+
+case $# in
+0|1)
+	echo Usage: $0 foo.liso foo.lkrn ...
+	exit 1
+	;;
+esac
+
+case "`mtools -V`" in
+Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*)
+	;;
+*)
+	echo Mtools version 3.9.9 or later is required
+	exit 1
+	;;
+esac
+
+out=$1
+shift
+
+dir=`mktemp -d bin/liso.dir.XXXXXX`
+
+img=$dir/boot.img
+mformat -f 1440 -C -i $img ::
+
+cfg=$dir/syslinux.cfg
+cat > $cfg <<EOF
+# These default options can be changed in the genliso script
+SAY iPXE ISO boot image generated by genliso
+TIMEOUT 30
+EOF
+
+first=
+for f
+do
+	if [ ! -r $f ]
+	then
+		echo $f does not exist, skipping 1>&2
+		continue
+	fi
+	# shorten name for 8.3 filesystem
+	b=$(basename $f)
+	g=${b%.lkrn}
+	g=${g//[^a-z0-9]}
+	g=${g:0:8}.krn
+	case "$first" in
+	"")
+		echo DEFAULT $g
+		;;
+	esac
+	first=$g
+	echo LABEL $b
+	echo "" KERNEL $g
+	mcopy -m -i $img $f ::$g
+done >> $cfg
+
+mcopy -i $img $cfg ::syslinux.cfg
+
+if ! syslinux $img
+then
+	exit 1
+fi
+
+mkisofs -q -o $out -c boot.cat -b boot.img $dir
+
+rm -fr $dir
diff --git a/qemu-0.15.x/roms/ipxe/src/util/gensdsk b/qemu-0.15.x/roms/ipxe/src/util/gensdsk
new file mode 100755
index 0000000..9e8361d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/gensdsk
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Generate a syslinux floppy that loads a iPXE image
+#
+# gensdsk foo.sdsk foo.lkrn
+#
+# the floppy image is the first argument
+#   followed by list of .lkrn images
+#
+
+case $# in
+0|1)
+	echo Usage: $0 foo.sdsk foo.lkrn ...
+	exit 1
+	;;
+esac
+case "`mtools -V`" in
+Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*)
+	;;
+*)
+	echo Mtools version 3.9.9 or later is required
+	exit 1
+	;;
+esac
+img=$1
+shift
+dir=`mktemp -d bin/sdsk.dir.XXXXXX`
+
+mformat -f 1440 -C -i $img ::
+cfg=$dir/syslinux.cfg
+cat > $cfg <<EOF
+
+# These default options can be changed in the gensdsk script
+TIMEOUT 30
+EOF
+first=
+for f
+do
+	if [ ! -r $f ]
+	then
+		echo $f does not exist, skipping 1>&2
+		continue
+	fi
+	# shorten name for 8.3 filesystem
+	b=$(basename $f)
+	g=${b%.lkrn}
+	g=${g//[^a-z0-9]}
+	g=${g:0:8}.krn
+	case "$first" in
+	"")
+		echo DEFAULT $g
+		;;
+	esac
+	first=$g
+	echo LABEL $b
+	echo "" KERNEL $g
+	mcopy -m -i $img $f ::$g
+done >> $cfg
+mcopy -i $img $cfg ::syslinux.cfg
+if ! syslinux $img
+then
+	exit 1
+fi
+
+rm -fr $dir
diff --git a/qemu-0.15.x/roms/ipxe/src/util/get-pci-ids b/qemu-0.15.x/roms/ipxe/src/util/get-pci-ids
new file mode 100755
index 0000000..6501a7f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/get-pci-ids
@@ -0,0 +1,135 @@
+#! /usr/bin/perl -w
+
+# get-pci-ids: extract pci vendor/device ids from linux net drivers
+
+# Copyright (C) 2003 Georg Baum <gbaum at users.sf.net>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+# Known bugs/limitations:
+# - Does not recognize all drivers because some require special cflags.
+#   Fails also on some drivers that do belong to other architectures
+#   than the one of the machine this script is running on.
+#   This is currently not so important because all drivers that have an
+#   Etherboot counterpart are recognized.
+
+
+use strict;
+use File::Basename "dirname";
+use POSIX "uname";
+
+# Where to find the kernel sources
+my $kernel_src = "/usr/src/linux";
+
+if($#ARGV >= 0) {
+	$kernel_src = shift;
+}
+
+# Sanity checks
+if($#ARGV >= 0) {
+	print STDERR "Too many arguments.\n";
+	print STDERR "Usage: get-pci-ids [path to kernel sources]\n";
+	print STDERR "       /usr/src/linux is assumed if no path is given.\n";
+	exit 1;
+}
+
+unless(-f "$kernel_src/include/linux/version.h") {
+	print STDERR "Could not find $kernel_src/include/linux/version.h.\n";
+	print STDERR "$kernel_src is probably no Linux kernel source tree.\n";
+	exit 1;
+}
+
+# Flags that are needed to preprocess the drivers.
+# Some drivers need optimization
+my $cflags="-D__KERNEL__ -I$kernel_src/include -I$kernel_src/net/inet -O2";
+
+# The C preprocessor. It needs to spit out the preprocessed source on stdout.
+my $cpp="gcc -E";
+
+# List of drivers. We parse every .c file. It does not harm if it does not contain a driver.
+my @drivers = split /\s+/, `find $kernel_src/drivers/net -name '*.c' | sort`;
+
+# Kernel version
+my $version = `grep UTS_RELEASE $kernel_src/include/linux/version.h`;
+chomp $version;
+$version =~ s/\s*#define\s+UTS_RELEASE\s+"(\S+)".*$/$1/g;
+
+# Architecture
+my @uname = uname();
+
+
+# Print header
+print "# PCI vendor/device ids extracted from Linux $version on $uname[4] at " . gmtime() . "\n";
+
+my $driver;
+
+# Process the drivers
+foreach $driver (@drivers) {
+
+	# Preprocess to expand macros
+	my $command = "$cpp $cflags -I" . dirname($driver) . " $driver";
+	open  DRIVER, "$command |" or die "Could not execute\n\"$command\".\n";
+
+	# Extract the pci_device_id structure
+	my $found = 0;
+	my $line = "";
+	my @lines;
+	while(<DRIVER>) {
+		if(/^\s*static\s+struct\s+pci_device_id/) {
+			# This file contains a driver. Print the name.
+			$driver =~ s!$kernel_src/drivers/net/!!g;
+			print "\n$driver\n";
+			$found = 1;
+			next;
+		}
+		if($found == 1){
+			if(/\};/ or /{\s*0\s*,?\s*}/) {
+				# End of struct
+				$found = 0;
+			} else {
+				chomp;
+				if(/\}\s*,?\s*\n?$/) {
+					# This line contains a full entry or the last part of it.
+					$_ = $line . $_;
+					$line = "";
+					s/[,\{\};\(\)]//g;	# Strip punctuation
+					s/^\s+//g;		# Eat whitespace at beginning of line
+					tr[A-Z][a-z];		# Convert to lowercase
+					# Push the vendor and device id to @lines if this line is not empty.
+					# We ignore everything else that might be there
+					my ($vendor_id, $device_id, $remainder) = split /\W+/, $_, 3;
+					push @lines, "$vendor_id $device_id\n" if($vendor_id && $device_id);
+				} else {
+					# This line does contain a partial entry. Remember it.
+					$line .= "$_ ";
+				}
+			}
+		}
+	}
+	close DRIVER;		# No "or die", because $cpp fails on some files
+
+	# Now print out the sorted values
+	@lines = sort @lines;
+	my $lastline = "";
+	foreach(@lines) {
+		# Print each vendor/device id combination only once.
+		# Some drivers (e.g. e100) do contain subfamilies
+		print if($_ ne $lastline);
+		$lastline = $_;
+	}
+}
+
+
diff --git a/qemu-0.15.x/roms/ipxe/src/util/hijack.c b/qemu-0.15.x/roms/ipxe/src/util/hijack.c
new file mode 100644
index 0000000..ed89592
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/hijack.c
@@ -0,0 +1,628 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <pcap.h>
+
+#define SNAPLEN 1600
+
+/*
+ * FIXME: is there a way to detect the version of the libpcap library?
+ * Version 0.9 has pcap_inject; version 0.8 doesn't, but both report
+ * their version number as 2.4.
+ */
+#define HAVE_PCAP_INJECT 0
+
+struct hijack {
+	pcap_t *pcap;
+	int fd;
+	int datalink;
+	int filtered;
+	unsigned long rx_count;
+	unsigned long tx_count;
+};
+
+struct hijack_listener {
+	struct sockaddr_un sun;
+	int fd;
+};
+
+struct hijack_options {
+	char interface[IF_NAMESIZE];
+	int daemonise;
+};
+
+static int daemonised = 0;
+
+static int signalled = 0;
+
+static void flag_signalled ( int signal __attribute__ (( unused )) ) {
+	signalled = 1;
+}
+
+#if ! HAVE_PCAP_INJECT
+/**
+ * Substitute for pcap_inject(), if this version of libpcap doesn't
+ * have it.  Will almost certainly only work under Linux.
+ *
+ */
+int pcap_inject ( pcap_t *pcap, const void *data, size_t len ) {
+	int fd;
+	char *errbuf = pcap_geterr ( pcap );
+
+	fd = pcap_get_selectable_fd ( pcap );
+	if ( fd < 0 ) {
+		snprintf ( errbuf, PCAP_ERRBUF_SIZE,
+			   "could not get file descriptor" );
+		return -1;
+	}
+	if ( write ( fd, data, len ) != len ) {
+		snprintf ( errbuf, PCAP_ERRBUF_SIZE,
+			   "could not write data: %s", strerror ( errno ) );
+		return -1;
+	}
+	return len;
+}
+#endif /* ! HAVE_PCAP_INJECT */
+
+/**
+ * Log error message
+ *
+ */
+static __attribute__ (( format ( printf, 2, 3 ) )) void
+logmsg ( int level, const char *format, ... ) {
+	va_list ap;
+
+	va_start ( ap, format );
+	if ( daemonised ) {
+		vsyslog ( ( LOG_DAEMON | level ), format, ap );
+	} else {
+		vfprintf ( stderr, format, ap );
+	}
+	va_end ( ap );
+}
+
+/**
+ * Open pcap device
+ *
+ */
+static int hijack_open ( const char *interface, struct hijack *hijack ) {
+	char errbuf[PCAP_ERRBUF_SIZE];
+
+	/* Open interface via pcap */
+	errbuf[0] = '\0';
+	hijack->pcap = pcap_open_live ( interface, SNAPLEN, 1, 0, errbuf );
+	if ( ! hijack->pcap ) {
+		logmsg ( LOG_ERR, "Failed to open %s: %s\n",
+			 interface, errbuf );
+		goto err;
+	}
+	if ( errbuf[0] )
+		logmsg ( LOG_WARNING, "Warning: %s\n", errbuf );
+
+	/* Set capture interface to non-blocking mode */
+	if ( pcap_setnonblock ( hijack->pcap, 1, errbuf ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not make %s non-blocking: %s\n",
+			 interface, errbuf );
+		goto err;
+	}
+
+	/* Get file descriptor for select() */
+	hijack->fd = pcap_get_selectable_fd ( hijack->pcap );
+	if ( hijack->fd < 0 ) {
+		logmsg ( LOG_ERR, "Cannot get selectable file descriptor "
+			 "for %s\n", interface );
+		goto err;
+	}
+
+	/* Get link layer type */
+	hijack->datalink = pcap_datalink ( hijack->pcap );
+
+	return 0;
+
+ err:
+	if ( hijack->pcap )
+		pcap_close ( hijack->pcap );
+	return -1;
+}
+
+/**
+ * Close pcap device
+ *
+ */
+static void hijack_close ( struct hijack *hijack ) {
+	pcap_close ( hijack->pcap );
+}
+
+/**
+ * Install filter for hijacked connection
+ *
+ */
+static int hijack_install_filter ( struct hijack *hijack,
+				   char *filter ) {
+	struct bpf_program program;
+
+	/* Compile filter */
+	if ( pcap_compile ( hijack->pcap, &program, filter, 1, 0 ) < 0 ) {
+		logmsg ( LOG_ERR, "could not compile filter \"%s\": %s\n",
+			 filter, pcap_geterr ( hijack->pcap ) );
+		goto err_nofree;
+	}
+
+	/* Install filter */
+	if ( pcap_setfilter ( hijack->pcap, &program ) < 0 ) {
+		logmsg ( LOG_ERR, "could not install filter \"%s\": %s\n",
+			 filter, pcap_geterr ( hijack->pcap ) );
+		goto err;
+	}
+	
+	logmsg ( LOG_INFO, "using filter \"%s\"\n", filter );
+
+	pcap_freecode ( &program );
+	return 0;
+
+ err:	
+	pcap_freecode ( &program );
+ err_nofree:
+	return -1;
+}
+
+/**
+ * Set up filter for hijacked ethernet connection
+ *
+ */
+static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf,
+				    size_t len ) {
+	char filter[55]; /* see format string */
+	struct ether_header *ether_header = ( struct ether_header * ) buf;
+	unsigned char *hwaddr = ether_header->ether_shost;
+
+	if ( len < sizeof ( *ether_header ) )
+		return -1;
+
+	snprintf ( filter, sizeof ( filter ), "broadcast or multicast or "
+		   "ether host %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0],
+		   hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] );
+
+	return hijack_install_filter ( hijack, filter );
+}
+
+/**
+ * Set up filter for hijacked connection
+ *
+ */
+static int hijack_filter ( struct hijack *hijack, const char *buf,
+			   size_t len ) {
+	switch ( hijack->datalink ) {
+	case DLT_EN10MB:
+		return hijack_filter_ethernet ( hijack, buf, len );
+	default:
+		logmsg ( LOG_ERR, "unsupported protocol %s: cannot filter\n",
+			 ( pcap_datalink_val_to_name ( hijack->datalink ) ?
+			   pcap_datalink_val_to_name ( hijack->datalink ) :
+			   "UNKNOWN" ) );
+		/* Return success so we don't get called again */
+		return 0;
+	}
+}
+
+/**
+ * Forward data from hijacker
+ *
+ */
+static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
+	char buf[SNAPLEN];
+	ssize_t len;
+
+	/* Read packet from hijacker */
+	len = read ( fd, buf, sizeof ( buf ) );
+	if ( len < 0 ) {
+		logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
+			 strerror ( errno ) );
+		return -1;
+	}
+	if ( len == 0 )
+		return 0;
+
+	/* Set up filter if not already in place */
+	if ( ! hijack->filtered ) {
+		if ( hijack_filter ( hijack, buf, len ) == 0 )
+			hijack->filtered = 1;
+	}
+
+	/* Transmit packet to network */
+	if ( pcap_inject ( hijack->pcap, buf, len ) != len ) {
+		logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
+			 pcap_geterr ( hijack->pcap ) );
+		return -1;
+	}
+
+	hijack->tx_count++;
+	return len;
+};
+
+/**
+ * Forward data to hijacker
+ *
+ */
+static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
+	struct pcap_pkthdr *pkt_header;
+	const unsigned char *pkt_data;
+	ssize_t len;
+
+	/* Receive packet from network */
+	if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) {
+		logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
+			 pcap_geterr ( hijack->pcap ) );
+		return -1;
+	}
+	if ( pkt_header->caplen != pkt_header->len ) {
+		logmsg ( LOG_ERR, "read partial packet (%d of %d bytes)\n",
+			 pkt_header->caplen, pkt_header->len );
+		return -1;
+	}
+	if ( pkt_header->caplen == 0 )
+		return 0;
+	len = pkt_header->caplen;
+
+	/* Write packet to hijacker */
+	if ( write ( fd, pkt_data, len ) != len ) {
+		logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
+			 strerror ( errno ) );
+		return -1;
+	}
+
+	hijack->rx_count++;
+	return len;
+};
+
+
+/**
+ * Run hijacker
+ *
+ */
+static int run_hijacker ( const char *interface, int fd ) {
+	struct hijack hijack;
+	fd_set fdset;
+	int max_fd;
+	ssize_t len;
+
+	logmsg ( LOG_INFO, "new connection for %s\n", interface );
+
+	/* Open connection to network */
+	memset ( &hijack, 0, sizeof ( hijack ) );
+	if ( hijack_open ( interface, &hijack ) < 0 )
+		goto err;
+	
+	/* Do the forwarding */
+	max_fd = ( ( fd > hijack.fd ) ? fd : hijack.fd );
+	while ( 1 ) {
+		/* Wait for available data */
+		FD_ZERO ( &fdset );
+		FD_SET ( fd, &fdset );
+		FD_SET ( hijack.fd, &fdset );
+		if ( select ( ( max_fd + 1 ), &fdset, NULL, NULL, 0 ) < 0 ) {
+			logmsg ( LOG_ERR, "select failed: %s\n",
+				 strerror ( errno ) );
+			goto err;
+		}
+		if ( FD_ISSET ( fd, &fdset ) ) {
+			len = forward_from_hijacker ( &hijack, fd );
+			if ( len < 0 )
+				goto err;
+			if ( len == 0 )
+				break;
+		}
+		if ( FD_ISSET ( hijack.fd, &fdset ) ) {
+			len = forward_to_hijacker ( fd, &hijack );
+			if ( len < 0 )
+				goto err;
+			if ( len == 0 )
+				break;
+		}
+	}
+
+	hijack_close ( &hijack );
+	logmsg ( LOG_INFO, "closed connection for %s\n", interface );
+	logmsg ( LOG_INFO, "received %ld packets, sent %ld packets\n",
+		 hijack.rx_count, hijack.tx_count );
+
+	return 0;
+
+ err:
+	if ( hijack.pcap )
+		hijack_close ( &hijack );
+	return -1;
+}
+
+/**
+ * Open listener socket
+ *
+ */
+static int open_listener ( const char *interface,
+			   struct hijack_listener *listener ) {
+	
+	/* Create socket */
+	listener->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
+	if ( listener->fd < 0 ) {
+		logmsg ( LOG_ERR, "Could not create socket: %s\n",
+			 strerror ( errno ) );
+		goto err;
+	}
+
+	/* Bind to local filename */
+	listener->sun.sun_family = AF_UNIX,
+	snprintf ( listener->sun.sun_path, sizeof ( listener->sun.sun_path ),
+		   "/var/run/hijack-%s", interface );
+	if ( bind ( listener->fd, ( struct sockaddr * ) &listener->sun,
+		    sizeof ( listener->sun ) ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not bind socket to %s: %s\n",
+			 listener->sun.sun_path, strerror ( errno ) );
+		goto err;
+	}
+
+	/* Set as a listening socket */
+	if ( listen ( listener->fd, 0 ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not listen to %s: %s\n",
+			 listener->sun.sun_path, strerror ( errno ) );
+		goto err;
+	}
+
+	return 0;
+	
+ err:
+	if ( listener->fd >= 0 )
+		close ( listener->fd );
+	return -1;
+}
+
+/**
+ * Listen on listener socket
+ *
+ */
+static int listen_for_hijackers ( struct hijack_listener *listener,
+				  const char *interface ) {
+	int fd;
+	pid_t child;
+	int rc;
+
+	logmsg ( LOG_INFO, "Listening on %s\n", listener->sun.sun_path );
+
+	while ( ! signalled ) {
+		/* Accept new connection, interruptibly */
+		siginterrupt ( SIGINT, 1 );
+		siginterrupt ( SIGHUP, 1 );
+		fd = accept ( listener->fd, NULL, 0 );
+		siginterrupt ( SIGINT, 0 );
+		siginterrupt ( SIGHUP, 0 );
+		if ( fd < 0 ) {
+			if ( errno == EINTR ) {
+				continue;
+			} else {
+				logmsg ( LOG_ERR, "accept failed: %s\n",
+					 strerror ( errno ) );
+				goto err;
+			}
+		}
+
+		/* Fork child process */
+		child = fork();
+		if ( child < 0 ) {
+			logmsg ( LOG_ERR, "fork failed: %s\n",
+				 strerror ( errno ) );
+			goto err;
+		}
+		if ( child == 0 ) {
+			/* I am the child; run the hijacker */
+			rc = run_hijacker ( interface, fd );
+			close ( fd );
+			exit ( rc );
+		}
+		
+		close ( fd );
+	}
+
+	logmsg ( LOG_INFO, "Stopped listening on %s\n",
+		 listener->sun.sun_path );
+	return 0;
+
+ err:
+	if ( fd >= 0 )
+		close ( fd );
+	return -1;
+}
+
+/**
+ * Close listener socket
+ *
+ */
+static void close_listener ( struct hijack_listener *listener ) {
+	close ( listener->fd );
+	unlink ( listener->sun.sun_path );
+}
+
+/**
+ * Print usage
+ *
+ */
+static void usage ( char **argv ) {
+	logmsg ( LOG_ERR,
+		 "Usage: %s [options]\n"
+		 "\n"
+		 "Options:\n"
+		 "  -h|--help               Print this help message\n"
+		 "  -i|--interface intf     Use specified network interface\n"
+		 "  -n|--nodaemon           Run in foreground\n",
+		 argv[0] );
+}
+
+/**
+ * Parse command-line options
+ *
+ */
+static int parse_options ( int argc, char **argv,
+			   struct hijack_options *options ) {
+	static struct option long_options[] = {
+		{ "interface", 1, NULL, 'i' },
+		{ "nodaemon", 0, NULL, 'n' },
+		{ "help", 0, NULL, 'h' },
+		{ },
+	};
+	int c;
+
+	/* Set default options */
+	memset ( options, 0, sizeof ( *options ) );
+	strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
+	options->daemonise = 1;
+
+	/* Parse command-line options */
+	while ( 1 ) {
+		int option_index = 0;
+		
+		c = getopt_long ( argc, argv, "i:hn", long_options,
+				  &option_index );
+		if ( c < 0 )
+			break;
+
+		switch ( c ) {
+		case 'i':
+			strncpy ( options->interface, optarg,
+				  sizeof ( options->interface ) );
+			break;
+		case 'n':
+			options->daemonise = 0;
+			break;
+		case 'h':
+			usage( argv );
+			return -1;
+		case '?':
+			/* Unrecognised option */
+			return -1;
+		default:
+			logmsg ( LOG_ERR, "Unrecognised option '-%c'\n", c );
+			return -1;
+		}
+	}
+
+	/* Check there's nothing left over on the command line */
+	if ( optind != argc ) {
+		usage ( argv );
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Daemonise
+ *
+ */
+static int daemonise ( const char *interface ) {
+	char pidfile[16 + IF_NAMESIZE + 4]; /* "/var/run/hijack-<intf>.pid" */
+	char pid[16];
+	int pidlen;
+	int fd = -1;
+
+	/* Daemonise */
+	if ( daemon ( 0, 0 ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not daemonise: %s\n",
+			 strerror ( errno ) );
+		goto err;
+	}
+	daemonised = 1; /* Direct messages to syslog now */
+
+	/* Open pid file */
+	snprintf ( pidfile, sizeof ( pidfile ), "/var/run/hijack-%s.pid",
+		   interface );
+	fd = open ( pidfile, ( O_WRONLY | O_CREAT | O_TRUNC ),
+		    ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) );
+	if ( fd < 0 ) {
+		logmsg ( LOG_ERR, "Could not open %s for writing: %s\n",
+			 pidfile, strerror ( errno ) );
+		goto err;
+	}
+
+	/* Write pid to file */
+	pidlen = snprintf ( pid, sizeof ( pid ), "%d\n", getpid() );
+	if ( write ( fd, pid, pidlen ) != pidlen ) {
+		logmsg ( LOG_ERR, "Could not write %s: %s\n",
+			 pidfile, strerror ( errno ) );
+		goto err;
+	}
+
+	close ( fd );
+	return 0;
+
+ err:
+	if ( fd >= 0 )
+		close ( fd );
+	return -1;
+}
+
+int main ( int argc, char **argv ) {
+	struct hijack_options options;
+	struct hijack_listener listener;
+	struct sigaction sa;
+
+	/* Parse command-line options */
+	if ( parse_options ( argc, argv, &options ) < 0 )
+		exit ( 1 );
+
+	/* Set up syslog connection */
+	openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON );
+
+	/* Set up listening socket */
+	if ( open_listener ( options.interface, &listener ) < 0 )
+		exit ( 1 );
+
+	/* Daemonise on demand */
+	if ( options.daemonise ) {
+		if ( daemonise ( options.interface ) < 0 )
+			exit ( 1 );
+	}
+
+	/* Avoid creating zombies */
+	memset ( &sa, 0, sizeof ( sa ) );
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = SA_RESTART | SA_NOCLDWAIT;
+	if ( sigaction ( SIGCHLD, &sa, NULL ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not set SIGCHLD handler: %s",
+			 strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Set 'signalled' flag on SIGINT or SIGHUP */
+	sa.sa_handler = flag_signalled;
+	sa.sa_flags = SA_RESTART | SA_RESETHAND;
+	if ( sigaction ( SIGINT, &sa, NULL ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not set SIGINT handler: %s",
+			 strerror ( errno ) );
+		exit ( 1 );
+	}
+	if ( sigaction ( SIGHUP, &sa, NULL ) < 0 ) {
+		logmsg ( LOG_ERR, "Could not set SIGHUP handler: %s",
+			 strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Listen for hijackers */
+	if ( listen_for_hijackers ( &listener, options.interface ) < 0 )
+		exit ( 1 );
+
+	close_listener ( &listener );
+	
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/iccfix.c b/qemu-0.15.x/roms/ipxe/src/util/iccfix.c
new file mode 100644
index 0000000..8b555c5
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/iccfix.c
@@ -0,0 +1,156 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <elf.h>
+#include <ipxe/tables.h>
+
+#define DEBUG 0
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define dprintf(...) do {						\
+	if ( DEBUG )							\
+		fprintf ( stderr, __VA_ARGS__ );			\
+	} while ( 0 )
+
+#ifdef SELF_INCLUDED
+
+/**
+ * Fix up ICC alignments
+ *
+ * @v elf		ELF header
+ * @ret rc		Return status code
+ *
+ * See comments in tables.h for an explanation of why this monstrosity
+ * is necessary.
+ */
+static int ICCFIX ( void *elf ) {
+	ELF_EHDR *ehdr = elf;
+	ELF_SHDR *shdr = ( elf + ehdr->e_shoff );
+	size_t shentsize = ehdr->e_shentsize;
+	unsigned int shnum = ehdr->e_shnum;
+	ELF_SHDR *strtab = ( ( ( void * ) shdr ) +
+			     ( ehdr->e_shstrndx * shentsize ) );
+	char *strings = ( elf + strtab->sh_offset );
+
+	for ( ; shnum-- ; shdr = ( ( ( void * ) shdr ) + shentsize ) ) {
+		char *name = ( strings + shdr->sh_name );
+		unsigned long align = shdr->sh_addralign;
+		unsigned long new_align;
+
+		if ( ( strncmp ( name, ".tbl.", 5 ) == 0 ) &&
+		     ( align >= ICC_ALIGN_HACK_FACTOR ) ) {
+			new_align = ( align / ICC_ALIGN_HACK_FACTOR );
+			shdr->sh_addralign = new_align;
+			dprintf ( "Section \"%s\": alignment %d->%d\n",
+				  name, align, new_align );
+		}
+	}
+	return 0;
+}
+
+#else /* SELF_INCLUDED */
+
+#define SELF_INCLUDED
+
+/* Include iccfix32() function */
+#define ELF_EHDR Elf32_Ehdr
+#define ELF_SHDR Elf32_Shdr
+#define ICCFIX iccfix32
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+/* Include iccfix64() function */
+#define ELF_EHDR Elf64_Ehdr
+#define ELF_SHDR Elf64_Shdr
+#define ICCFIX iccfix64
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+static int iccfix ( const char *filename ) {
+	int fd;
+	struct stat stat;
+	void *elf;
+	unsigned char *eident;
+	int rc;
+
+	/* Open and mmap file */
+	fd = open ( filename, O_RDWR );
+	if ( fd < 0 ) {
+		eprintf ( "Could not open %s: %s\n",
+			  filename, strerror ( errno ) );
+		rc = -1;
+		goto err_open;
+	}
+	if ( fstat ( fd, &stat ) < 0 ) {
+		eprintf ( "Could not determine size of %s: %s\n",
+			  filename, strerror ( errno ) );
+		rc = -1;
+		goto err_fstat;
+	}
+	elf = mmap ( NULL, stat.st_size, ( PROT_READ | PROT_WRITE ),
+		     MAP_SHARED, fd, 0 );
+	if ( elf == MAP_FAILED ) {
+		eprintf ( "Could not map %s: %s\n",
+			  filename, strerror ( errno ) );
+		rc = -1;
+		goto err_mmap;
+	}
+
+	/* Perform fixups */
+	eident = elf;
+	switch ( eident[EI_CLASS] ) {
+	case ELFCLASS32:
+		rc = iccfix32 ( elf );
+		break;
+	case ELFCLASS64:
+		rc = iccfix64 ( elf );
+		break;
+	default:
+		eprintf ( "Unknown ELF class %d in %s\n",
+			  eident[EI_CLASS], filename );
+		rc = -1;
+		break;
+	}
+
+	munmap ( elf, stat.st_size );
+ err_mmap:
+ err_fstat:
+	close ( fd );
+ err_open:
+	return rc;
+}
+
+int main ( int argc, char **argv ) {
+	int i;
+	int rc;
+
+	/* Parse command line */
+	if ( argc < 2 ) {
+		eprintf ( "Syntax: %s <object_file>...\n", argv[0] );
+		exit ( 1 );
+	}
+
+	/* Process each object in turn */
+	for ( i = 1 ; i < argc ; i++ ) {
+		if ( ( rc = iccfix ( argv[i] ) ) != 0 ) {
+			eprintf ( "Could not fix up %s\n", argv[i] );
+			exit ( 1 );
+		}
+	}
+
+	return 0;
+}
+
+#endif /* SELF_INCLUDED */
diff --git a/qemu-0.15.x/roms/ipxe/src/util/licence.pl b/qemu-0.15.x/roms/ipxe/src/util/licence.pl
new file mode 100755
index 0000000..c37685d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/licence.pl
@@ -0,0 +1,149 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+# List of licences we can handle
+my $known_licences = {
+  gpl_any => {
+    desc => "GPL (any version)",
+    can_subsume => {
+      public_domain => 1,
+      bsd3 => 1,
+      bsd2 => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  gpl2_or_later => {
+    desc => "GPL version 2 (or, at your option, any later version)",
+    can_subsume => {
+      gpl_any => 1,
+      public_domain => 1,
+      bsd3 => 1,
+      bsd2 => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  gpl2_only => {
+    desc => "GPL version 2 only",
+    can_subsume => {
+      gpl_any => 1,
+      gpl2_or_later => 1,
+      public_domain => 1,
+      bsd3 => 1,
+      bsd2 => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  public_domain => {
+    desc => "Public Domain",
+    can_subsume => {},
+  },
+  bsd4 => {
+    desc => "BSD Licence (with advertising clause)",
+    can_subsume => {
+      public_domain => 1,
+      bsd3 => 1,
+      bsd2 => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  bsd3 => {
+    desc => "BSD Licence (without advertising clause)",
+    can_subsume => {
+      public_domain => 1,
+      bsd2 => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  bsd2 => {
+    desc => "BSD Licence (without advertising or endorsement clauses)",
+    can_subsume => {
+      public_domain => 1,
+      mit  => 1,
+      isc  => 1,
+    },
+  },
+  mit => {
+    desc => "MIT/X11/Xorg Licence",
+    can_subsume => {
+      public_domain => 1,
+      isc => 1,
+    },
+  },
+  isc => {
+    desc => "ISC Licence",
+    can_subsume => {
+      public_domain => 1,
+    },
+  },
+};
+
+# Parse command-line options
+my $verbosity = 1;
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+  'verbose|v+' => sub { $verbosity++; },
+  'quiet|q+' => sub { $verbosity--; },
+) or die "Could not parse command-line options\n";
+
+# Parse licence list from command line
+my $licences = {};
+foreach my $licence ( @ARGV ) {
+  die "Unknown licence \"$licence\"\n"
+      unless exists $known_licences->{$licence};
+  $licences->{$licence} = $known_licences->{$licence};
+}
+die "No licences specified\n" unless %$licences;
+
+# Dump licence list
+if ( $verbosity >= 1 ) {
+  print "The following licences appear within this file:\n";
+  foreach my $licence ( keys %$licences ) {
+    print "  ".$licences->{$licence}->{desc}."\n"
+  }
+}
+
+# Apply licence compatibilities to reduce to a single resulting licence
+foreach my $licence ( keys %$licences ) {
+  # Skip already-deleted licences
+  next unless exists $licences->{$licence};
+  # Subsume any subsumable licences
+  foreach my $can_subsume ( keys %{$licences->{$licence}->{can_subsume}} ) {
+    if ( exists $licences->{$can_subsume} ) {
+      print $licences->{$licence}->{desc}." subsumes ".
+	  $licences->{$can_subsume}->{desc}."\n"
+	  if $verbosity >= 1;
+      delete $licences->{$can_subsume};
+    }
+  }
+}
+
+# Print resulting licence
+die "Cannot reduce to a single resulting licence!\n"
+    if ( keys %$licences ) != 1;
+( my $licence ) = keys %$licences;
+print "The overall licence for this file is:\n  " if $verbosity >= 1;
+print $licences->{$licence}->{desc}."\n";
diff --git a/qemu-0.15.x/roms/ipxe/src/util/mergerom.pl b/qemu-0.15.x/roms/ipxe/src/util/mergerom.pl
new file mode 100755
index 0000000..f9c5250
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/mergerom.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown at fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
+
+sub merge_entry_points {
+  my $baserom_entry = \shift;
+  my $rom_entry = \shift;
+  my $offset = shift;
+
+  if ( $$rom_entry ) {
+    my $old_entry = $$baserom_entry;
+    $$baserom_entry = ( $offset + $$rom_entry );
+    $$rom_entry = $old_entry;
+  }
+}
+
+my @romfiles = @ARGV;
+my @roms = map { my $rom = new Option::ROM; $rom->load($_); $rom } @romfiles;
+
+my $baserom = shift @roms;
+my $offset = $baserom->length;
+
+foreach my $rom ( @roms ) {
+
+  # Update base length
+  $baserom->{length} += $rom->{length};
+
+  # Merge initialisation entry point
+  merge_entry_points ( $baserom->{init}, $rom->{init}, $offset );
+
+  # Merge BOFM header
+  merge_entry_points ( $baserom->{bofm_header}, $rom->{bofm_header}, $offset );
+
+  # Update PCI header, if present in both
+  my $baserom_pci = $baserom->pci_header;
+  my $rom_pci = $rom->pci_header;
+  if ( $baserom_pci && $rom_pci ) {
+
+    # Update PCI lengths
+    $baserom_pci->{image_length} += $rom_pci->{image_length};
+    if ( exists $baserom_pci->{runtime_length} ) {
+      if ( exists $rom_pci->{runtime_length} ) {
+	$baserom_pci->{runtime_length} += $rom_pci->{runtime_length};
+      } else {
+	$baserom_pci->{runtime_length} += $rom_pci->{image_length};
+      }
+    }
+
+    # Merge CLP entry point
+    if ( exists ( $baserom_pci->{clp_entry} ) &&
+	 exists ( $rom_pci->{clp_entry} ) ) {
+      merge_entry_points ( $baserom_pci->{clp_entry}, $rom_pci->{clp_entry},
+			   $offset );
+    }
+  }
+
+  # Update PnP header, if present in both
+  my $baserom_pnp = $baserom->pnp_header;
+  my $rom_pnp = $rom->pnp_header;
+  if ( $baserom_pnp && $rom_pnp ) {
+    merge_entry_points ( $baserom_pnp->{bcv}, $rom_pnp->{bcv}, $offset );
+    merge_entry_points ( $baserom_pnp->{bdv}, $rom_pnp->{bdv}, $offset );
+    merge_entry_points ( $baserom_pnp->{bev}, $rom_pnp->{bev}, $offset );
+  }
+
+  # Fix checksum for this ROM segment
+  $rom->fix_checksum();
+
+  $offset += $rom->length;
+}
+
+$baserom->pnp_header->fix_checksum() if $baserom->pnp_header;
+$baserom->fix_checksum();
+$baserom->save ( "-" );
+foreach my $rom ( @roms ) {
+  $rom->save ( "-" );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/modrom.pl b/qemu-0.15.x/roms/ipxe/src/util/modrom.pl
new file mode 100755
index 0000000..cdac0b9
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/modrom.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+
+use Getopt::Std;
+
+use constant MINROMSIZE => 8192;
+use constant MAXROMSIZE => 262144;
+
+use constant PCI_PTR_LOC => 0x18;	# from beginning of ROM
+use constant PCI_HDR_SIZE => 0x18;
+use constant PNP_PTR_LOC => 0x1a;	# from beginning of ROM
+use constant PNP_HDR_SIZE => 0x20;
+use constant PNP_CHKSUM_OFF => 0x9;	# bytes from beginning of PnP header
+use constant PNP_DEVICE_OFF => 0x10;	# bytes from beginning of PnP header
+use constant PCI_VEND_ID_OFF => 0x4;	# bytes from beginning of PCI header
+use constant PCI_DEV_ID_OFF => 0x6;	# bytes from beginning of PCI header
+use constant PCI_SIZE_OFF => 0x10;	# bytes from beginning of PCI header
+
+use constant UNDI_PTR_LOC => 0x16;	# from beginning of ROM
+use constant UNDI_HDR_SIZE => 0x16;
+use constant UNDI_CHKSUM_OFF => 0x05;
+
+use strict;
+
+use vars qw(%opts);
+
+use bytes;
+
+sub getromsize ($) {
+	my ($romref) = @_;
+	my $i;
+
+	print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n"
+		if (substr($$romref, 0, 2) ne "\x55\xaa");
+	my $size = ord(substr($$romref, 2, 1)) * 512;
+	for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { }
+	print STDERR "$size is a strange size for a boot ROM\n"
+		if ($size > 0 and $i > $size);
+	return ($size);
+}
+
+sub addident ($) {
+	my ($romref) = @_;
+
+	return (0) unless (my $s = $opts{'i'});
+	# include the terminating NUL byte too
+	$s .= "\x00";
+	my $len = length($s);
+	# Put the identifier in only if the space is blank
+	my $pos = length($$romref) - $len - 2;
+	return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len));
+	substr($$romref, $pos, $len) = $s;
+	return ($pos);
+}
+
+sub pcipnpheaders ($$) {
+	my ($romref, $identoffset) = @_;
+	my ($pci_hdr_offset, $pnp_hdr_offset);
+
+	$pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2));
+	$pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2));
+	# Sanity checks
+	if ($pci_hdr_offset < PCI_PTR_LOC + 2
+		or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE
+		or $pnp_hdr_offset < PNP_PTR_LOC + 2
+		or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE
+		or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR'
+		or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') {
+		$pci_hdr_offset = $pnp_hdr_offset = 0;
+	} else {
+		printf "PCI header at %#x and PnP header at %#x\n",
+			$pci_hdr_offset, $pnp_hdr_offset;
+	}
+	if ($pci_hdr_offset > 0) {
+		my ($pci_vendor_id, $pci_device_id);
+		# if no -p option, just report what's there
+		if (!defined($opts{'p'})) {
+			$pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2));
+			$pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2));
+			printf "PCI Vendor ID %#x Device ID %#x\n",
+				$pci_vendor_id, $pci_device_id;
+		} else {
+			substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2)
+				= pack('v', length($$romref) / 512);
+			($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'});
+			substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)
+				= pack('v', oct($pci_vendor_id)) if ($pci_vendor_id);
+			substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)
+				= pack('v', oct($pci_device_id)) if ($pci_device_id);
+		}
+	}
+	if ($pnp_hdr_offset > 0 and defined($identoffset)) {
+		# Point to device id string at end of ROM image
+		substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2)
+			= pack('v', $identoffset);
+		substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00";
+		my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset,
+			PNP_HDR_SIZE));
+		substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum);
+	}
+}
+
+sub undiheaders ($) {
+	my ($romref) = @_;
+	my ($undi_hdr_offset);
+
+	$undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2));
+	# Sanity checks
+	if ($undi_hdr_offset < UNDI_PTR_LOC + 2
+		or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE
+		or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') {
+		$undi_hdr_offset = 0;
+	} else {
+		printf "UNDI header at %#x\n", $undi_hdr_offset;
+	}
+	if ($undi_hdr_offset > 0) {
+		substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00";
+		my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset,
+			UNDI_HDR_SIZE));
+		substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum);
+	}
+}
+
+sub writerom ($$) {
+	my ($filename, $romref) = @_;
+
+	open(R, ">$filename") or die "$filename: $!\n";
+	print R $$romref;
+	close(R);
+}
+
+sub checksum ($) {
+	my ($romref) = @_;
+
+	substr($$romref, 6, 1) = "\x00";
+	my $sum = unpack('%8C*', $$romref);
+	substr($$romref, 6, 1) = chr(256 - $sum);
+	# Double check
+	$sum = unpack('%8C*', $$romref);
+	if ($sum != 0) {
+		print "Checksum fails\n"
+	} elsif ($opts{'v'}) {
+		print "Checksum ok\n";
+	}
+}
+
+sub makerom () {
+	my ($rom, $romsize);
+
+	getopts('3xi:p:s:v', \%opts);
+	$ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n";
+	open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+	# Read in the whole ROM in one gulp
+	my $filesize = read(R, $rom, MAXROMSIZE+1);
+	close(R);
+	defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+	print "$filesize bytes read\n" if $opts{'v'};
+	# If PXE image, just fill the length field and write it out
+	if ($opts{'x'}) {
+		substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
+		&writerom($ARGV[0], \$rom);
+		return;
+	}
+	# Size specified with -s overrides value in 3rd byte in image
+	# -s 0 means round up to next 512 byte block
+	if (defined($opts{'s'})) {
+		if (($romsize = oct($opts{'s'})) <= 0) {
+			# NB: This roundup trick only works on powers of 2
+			$romsize = ($filesize + 511) & ~511
+		}
+	} else {
+		$romsize = &getromsize(\$rom);
+		# 0 put there by *loader.S means makerom should pick the size
+		if ($romsize == 0) {
+			# Shrink romsize down to the smallest power of two that will do
+			for ($romsize = MAXROMSIZE;
+				$romsize > MINROMSIZE and $romsize >= 2*$filesize;
+				$romsize /= 2) { }
+		}
+	}
+	if ($filesize > $romsize) {
+		print STDERR "ROM size of $romsize not big enough for data, ";
+		# NB: This roundup trick only works on powers of 2
+		$romsize = ($filesize + 511) & ~511;
+		print "will use $romsize instead\n"
+	}
+	# Pad with 0xFF to $romsize
+	$rom .= "\xFF" x ($romsize - length($rom));
+	if ($romsize >= 128 * 1024) {
+		print "Warning: ROM size exceeds extension BIOS limit\n";
+	}
+	substr($rom, 2, 1) = chr(($romsize / 512) % 256);
+	print "ROM size is $romsize\n" if $opts{'v'};
+	my $identoffset = &addident(\$rom);
+	&pcipnpheaders(\$rom, $identoffset);
+	&undiheaders(\$rom);
+	# 3c503 requires last two bytes to be 0x80
+	substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
+		if ($opts{'3'} and $romsize == MINROMSIZE);
+	&checksum(\$rom);
+	&writerom($ARGV[0], \$rom);
+}
+
+sub modrom () {
+	my ($rom);
+
+	getopts('p:v', \%opts);
+	$ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n";
+	open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+	# Read in the whole ROM in one gulp
+	my $filesize = read(R, $rom, MAXROMSIZE+1);
+	close(R);
+	defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+	print "$filesize bytes read\n" if $opts{'v'};
+	&pcipnpheaders(\$rom);
+	&undiheaders(\$rom);
+	&checksum(\$rom);
+	&writerom($ARGV[0], \$rom);
+}
+
+# Main routine. See how we were called and behave accordingly
+if ($0 =~ m:modrom(\.pl)?$:) {
+	&modrom();
+} else {
+	&makerom();
+}
+exit(0);
diff --git a/qemu-0.15.x/roms/ipxe/src/util/mucurses_test.c b/qemu-0.15.x/roms/ipxe/src/util/mucurses_test.c
new file mode 100644
index 0000000..586562d
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/mucurses_test.c
@@ -0,0 +1,63 @@
+#include "../include/curses.h"
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void get_iscsi_chap_secret( char * );
+void mdelay( int msecs );
+
+int main ( void ) {
+	char secret[16];
+	initscr();
+	echo();
+	werase(stdscr);
+	box( stdscr, '|', '-' );
+	get_iscsi_chap_secret(secret);
+
+	mvwprintw( stdscr, 3, 5, "password is \"%s\"", secret );
+	mdelay(2500);
+
+	stdscr->scr->exit(stdscr->scr);
+
+	return 0;
+}
+
+void get_iscsi_chap_secret( char *sec ) {
+	char 	*title = "Set new iSCSI CHAP secret",
+		*msg = "Configure the iSCSI access secret",
+		pw1[17], pw2[17];
+	WINDOW *secret;
+
+	secret = newwin( stdscr->height / 2,
+			 stdscr->width / 2,
+			 stdscr->height / 4,
+			 stdscr->width / 4 );
+
+	wborder( secret, '|', '|', '-', '-', '+', '+', '+', '+' );
+	mvwprintw( secret, 1, 2, "%s", title );
+	mvwhline( secret, 2, 1, '-' | secret->attrs, secret->width - 2 );
+	mvwprintw( secret, 4, 2, "%s", msg );
+	mvwprintw( secret, 6, 3, "secret" );
+	mvwprintw( secret, 8, 3, "confirm" );
+ start:
+	mvwhline( secret, 6, 12, '_' | secret->attrs, 16 );
+	mvwhline( secret, 8, 12, '_' | secret->attrs, 16 );
+
+	wmove( secret, 6, 12 );
+	wgetnstr( secret, pw1, 16 );
+	wmove( secret, 8, 12 );
+	wgetnstr( secret, pw2, 16 );
+
+	if ( strcmp( pw1, pw2 ) == 0 ) {
+		strcpy( sec, pw1 );
+		werase( secret );
+	}
+	else {
+		mvwprintw( secret, 10, 3, "Passwords do not match" );
+		goto start;
+	}
+}
+
+void mdelay ( int msecs ) {
+	usleep( msecs * 1000 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/nrv2b.c b/qemu-0.15.x/roms/ipxe/src/util/nrv2b.c
new file mode 100644
index 0000000..6bac4cd
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/nrv2b.c
@@ -0,0 +1,1501 @@
+/**************************************************************
+    Form adapted from lzhuf.c
+    written by Haruyasu Yoshizaki 11/20/1988
+    some minor changes 4/6/1989
+    comments translated by Haruhiko Okumura 4/7/1989
+
+    minor beautifications and adjustments for compiling under Linux
+    by Markus Gutschke <gutschk at math.uni-muenster.de>
+    						1997-01-27
+
+    Modifications to allow use as a filter by Ken Yap
+    <ken_yap at users.sourceforge.net>.
+
+						1997-07-01
+
+    Small mod to cope with running on big-endian machines
+    by Jim Hague <jim.hague at acm.org)
+						1998-02-06
+
+    Make compression statistics report shorter
+    by Ken Yap <ken_yap at users.sourceforge.net>.
+						2001-04-25
+
+    Replaced algorithm with nrv2b from ucl the compression
+    library from upx.  That code is:
+    Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+    And is distributed under the terms of the GPL.
+    The conversion was performed 
+    by Eric Biederman <ebiederman at lnxi.com>.
+                                             20 August 2002
+                                                
+**************************************************************/
+#define UCLPACK_COMPAT 0
+#define NDEBUG 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <limits.h>
+#include <assert.h>
+#if UCLPACK_COMPAT
+#include <netinet/in.h>
+#endif
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr     0
+#else
+#define Fprintf(x) fprintf x
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE  *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+
+#ifndef ENDIAN
+#define ENDIAN   0
+#endif
+#ifndef BITSIZE
+#define BITSIZE 32
+#endif
+
+static __inline__ void Error(char *message)
+{
+	Fprintf((stderr, "\n%s\n", message));
+	exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+	unsigned long res = 0;
+	int i;
+	union
+	{
+		unsigned char c[4];
+		unsigned long ul;
+	} u;
+
+	u.ul = ul;
+	for (i = 3; i >= 0; i--)
+		res = (res << 8) + u.c[i];
+	return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+	int i;
+	union
+	{
+		unsigned char c[4];
+		unsigned long ul;
+	} u;
+
+	for (i = 0; i < 4; i++)
+	{
+		u.c[i] = ul & 0xff;
+		ul >>= 8;
+	}
+	return u.ul;
+}
+#endif
+
+
+
+#if UCLPACK_COMPAT
+/* magic file header for compressed files */
+static const unsigned char magic[8] =
+{ 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a };
+
+#endif
+
+#ifdef ENCODE
+/********** NRV2B_99 compression **********/
+
+/* Note by limiting the ring buffer I have limited the maximum
+ * offset to 64K.  Since etherboot rarely gets that big it
+ * is not a problem and it gives me a firm guarantee
+ * that I will never get a 3 byte string match that is encodes
+ * to more than 9/8 it's original size.
+ * That guaranteee is important to for the inplace decompressor.
+ * There are better ways to do this if a larger offset and buffer
+ * would give better compression.
+ */
+#define N       (65536ul)           /* size of ring buffer */
+#define THRESHOLD       1           /* lower limit for match length */
+#define F            2048           /* upper limit for match length */
+#define M2_MAX_OFFSET                 0xd00
+
+/* note: to use default values pass -1, i.e. initialize
+ * this struct by a memset(x,0xff,sizeof(x)) */
+struct ucl_compress_config
+{
+	int bb_endian;
+	int bb_size;
+	unsigned int max_offset;
+	unsigned int max_match;
+	int s_level;
+	int h_level;
+	int p_level;
+	int c_flags;
+	unsigned int m_size;
+};
+
+struct ucl_compress
+{
+	int init;
+
+	unsigned int look;          /* bytes in lookahead buffer */
+	
+	unsigned int m_len;
+	unsigned int m_off;
+	
+	unsigned int last_m_len;
+	unsigned int last_m_off;
+	
+	const unsigned char *bp;
+	const unsigned char *ip;
+	const unsigned char *in;
+	const unsigned char *in_end;
+	unsigned char *out;
+	
+	uint64_t bb_b;
+	unsigned bb_k;
+	unsigned bb_c_endian;
+	unsigned bb_c_s;
+	unsigned bb_c_s8;
+	unsigned char *bb_p;
+	unsigned char *bb_op;
+	
+	struct ucl_compress_config conf;
+	unsigned int *result;
+
+	unsigned int textsize;      /* text size counter */
+	unsigned int codesize;      /* code size counter */
+	unsigned int printcount; /* counter for reporting progress every 1K
+				    bytes */
+
+	
+	/* some stats */
+	unsigned long lit_bytes;
+	unsigned long match_bytes;
+	unsigned long rep_bytes;
+	unsigned long lazy;
+};
+
+
+
+#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+#define UCL_E_OK               0
+#define UCL_E_INVALID_ARGUMENT 1
+#define UCL_E_OUT_OF_MEMORY    2
+#define UCL_E_ERROR            3
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define SWD_HSIZE	16384
+#define SWD_MAX_CHAIN	2048
+#define SWD_BEST_OFF    1
+
+#define HEAD3(b,p) \
+    (((0x9f5f*(((((uint32_t)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
+
+#define HEAD2(b,p)      (b[p] ^ ((unsigned)b[p+1]<<8))
+#define NIL2              UINT_MAX
+
+struct ucl_swd
+{
+/* public - "built-in" */
+	unsigned int n;
+	unsigned int f;
+	unsigned int threshold;
+	
+/* public - configuration */
+	unsigned int max_chain;
+	unsigned int nice_length;
+	int use_best_off;
+	unsigned int lazy_insert;
+	
+/* public - output */
+	unsigned int m_len;
+	unsigned int m_off;
+	unsigned int look;
+	int b_char;
+#if defined(SWD_BEST_OFF)
+	unsigned int best_off[ SWD_BEST_OFF ];
+#endif
+	
+/* semi public */
+	struct ucl_compress *c;
+	unsigned int m_pos;
+#if defined(SWD_BEST_OFF)
+	unsigned int best_pos[ SWD_BEST_OFF ];
+#endif
+	
+/* private */
+	const uint8_t *dict;
+	const uint8_t *dict_end;
+	unsigned int dict_len;
+	
+/* private */
+	unsigned int ip;                /* input pointer (lookahead) */
+	unsigned int bp;                /* buffer pointer */
+	unsigned int rp;                /* remove pointer */
+	unsigned int b_size;
+	
+	unsigned char *b_wrap;
+	
+	unsigned int node_count;
+	unsigned int first_rp;
+
+	unsigned char b [ N + F + F ];
+	unsigned int head3 [ SWD_HSIZE ];
+	unsigned int succ3 [ N + F ];
+	unsigned int best3 [ N + F ];
+	unsigned int llen3 [ SWD_HSIZE ];
+	unsigned int head2 [ 65536U ];
+};
+
+#define s_head3(s,key)        s->head3[key]
+
+
+#if !defined( NDEBUG)
+static void assert_match(const struct ucl_swd * swd, unsigned int m_len,
+	unsigned int m_off )
+
+{
+	const struct ucl_compress *c = swd->c;
+	unsigned int d_off;
+	
+	assert(m_len >= 2);
+	if (m_off <= (unsigned int) (c->bp - c->in))
+	{
+		assert(c->bp - m_off + m_len < c->ip);
+		assert(memcmp(c->bp, c->bp - m_off, m_len) == 0);
+	}
+	else
+	{
+		assert(swd->dict != NULL);
+		d_off = m_off - (unsigned int) (c->bp - c->in);
+		assert(d_off <= swd->dict_len);
+		if (m_len > d_off)
+		{
+			assert(memcmp(c->bp, swd->dict_end - d_off, d_off) ==
+				0);
+
+			assert(c->in + m_len - d_off < c->ip);
+			assert(memcmp(c->bp + d_off, c->in, m_len - d_off) ==
+				0);
+
+		}
+		else
+		{
+			assert(memcmp(c->bp, swd->dict_end - d_off, m_len) ==
+				0);
+
+		}
+	}
+}
+#else
+#  define assert_match(a,b,c)   ((void)0)
+#endif
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_initdict(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+
+{
+	s->dict = s->dict_end = NULL;
+	s->dict_len = 0;
+
+	if (!dict || dict_len <= 0)
+		return;
+	if (dict_len > s->n)
+	{
+		dict += dict_len - s->n;
+		dict_len = s->n;
+	}
+
+	s->dict = dict;
+	s->dict_len = dict_len;
+	s->dict_end = dict + dict_len;
+	memcpy(s->b,dict,dict_len);
+	s->ip = dict_len;
+}
+
+
+static
+void swd_insertdict(struct ucl_swd *s, unsigned int node, unsigned int len)
+{
+	unsigned int key;
+
+	s->node_count = s->n - len;
+	s->first_rp = node;
+
+	while (len-- > 0)
+	{
+		key = HEAD3(s->b,node);
+		s->succ3[node] = s_head3(s,key);
+		s->head3[key] = (unsigned int)(node);
+		s->best3[node] = (unsigned int)(s->f + 1);
+		s->llen3[key]++;
+		assert(s->llen3[key] <= s->n);
+
+		key = HEAD2(s->b,node);
+		s->head2[key] = (unsigned int)(node);
+
+		node++;
+	}
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+{
+	unsigned int i = 0;
+	int c = 0;
+
+	if (s->n == 0)
+		s->n = N;
+	if (s->f == 0)
+		s->f = F;
+	s->threshold = THRESHOLD;
+	if (s->n > N || s->f > F)
+		return UCL_E_INVALID_ARGUMENT;
+
+	/* defaults */
+	s->max_chain = SWD_MAX_CHAIN;
+	s->nice_length = s->f;
+	s->use_best_off = 0;
+	s->lazy_insert = 0;
+
+	s->b_size = s->n + s->f;
+	if (s->b_size + s->f >= UINT_MAX)
+		return UCL_E_ERROR;
+	s->b_wrap = s->b + s->b_size;
+	s->node_count = s->n;
+
+	memset(s->llen3, 0, sizeof(s->llen3[0]) * SWD_HSIZE);
+	for (i = 0; i < 65536U; i++)
+		s->head2[i] = NIL2;
+
+	s->ip = 0;
+	swd_initdict(s,dict,dict_len);
+	s->bp = s->ip;
+	s->first_rp = s->ip;
+
+	assert(s->ip + s->f <= s->b_size);
+
+	s->look = (unsigned int) (s->c->in_end - s->c->ip);
+	if (s->look > 0)
+	{
+		if (s->look > s->f)
+			s->look = s->f;
+		memcpy(&s->b[s->ip],s->c->ip,s->look);
+		s->c->ip += s->look;
+		s->ip += s->look;
+	}
+	if (s->ip == s->b_size)
+		s->ip = 0;
+
+	if (s->look >= 2 && s->dict_len > 0)
+		swd_insertdict(s,0,s->dict_len);
+
+	s->rp = s->first_rp;
+	if (s->rp >= s->node_count)
+		s->rp -= s->node_count;
+	else
+		s->rp += s->b_size - s->node_count;
+
+	/* unused i */
+	/* unused c */
+	return UCL_E_OK;
+}
+
+
+static
+void swd_exit(struct ucl_swd *s)
+{
+	/* unused s */
+
+}
+
+#define swd_pos2off(s,pos) \
+	(s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
+
+/***********************************************************************
+//
+************************************************************************/
+
+static __inline__
+void swd_getbyte(struct ucl_swd *s)
+{
+	int c;
+
+	if ((c = getbyte(*(s->c))) < 0)
+	{
+		if (s->look > 0)
+			--s->look;
+	}
+	else
+	{
+		s->b[s->ip] = (uint8_t)(c);
+		if (s->ip < s->f)
+			s->b_wrap[s->ip] = (uint8_t)(c);
+	}
+	if (++s->ip == s->b_size)
+		s->ip = 0;
+	if (++s->bp == s->b_size)
+		s->bp = 0;
+	if (++s->rp == s->b_size)
+		s->rp = 0;
+}
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+
+static __inline__
+void swd_remove_node(struct ucl_swd *s, unsigned int node)
+{
+	if (s->node_count == 0)
+	{
+		unsigned int key;
+		
+#ifdef UCL_DEBUG
+		if (s->first_rp != UINT_MAX)
+		{
+			if (node != s->first_rp)
+				printf("Remove %5d: %5d %5d %5d %5d %6d %6d\n",
+
+					node, s->rp, s->ip, s->bp, s->first_rp,
+					s->ip - node, s->ip - s->bp);
+			assert(node == s->first_rp);
+			s->first_rp = UINT_MAX;
+		}
+#endif
+		
+		key = HEAD3(s->b,node);
+		assert(s->llen3[key] > 0);
+		--s->llen3[key];
+		
+		key = HEAD2(s->b,node);
+		assert(s->head2[key] != NIL2);
+		if ((unsigned int) s->head2[key] == node)
+			s->head2[key] = NIL2;
+	}
+	else
+		--s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_accept(struct ucl_swd *s, unsigned int n)
+{
+	assert(n <= s->look);
+
+	if (n > 0) do
+	{
+		unsigned int key;
+
+		swd_remove_node(s,s->rp);
+
+		/* add bp into HEAD3 */
+		key = HEAD3(s->b,s->bp);
+		s->succ3[s->bp] = s_head3(s,key);
+		s->head3[key] = (unsigned int)(s->bp);
+		s->best3[s->bp] = (unsigned int)(s->f + 1);
+		s->llen3[key]++;
+		assert(s->llen3[key] <= s->n);
+
+		/* add bp into HEAD2 */
+		key = HEAD2(s->b,s->bp);
+		s->head2[key] = (unsigned int)(s->bp);
+
+		swd_getbyte(s);
+	} while (--n > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_search(struct ucl_swd *s, unsigned int node, unsigned int cnt)
+{
+	const unsigned char *p1;
+	const unsigned char *p2;
+	const unsigned char *px;
+
+	unsigned int m_len = s->m_len;
+	const unsigned char * b  = s->b;
+	const unsigned char * bp = s->b + s->bp;
+	const unsigned char * bx = s->b + s->bp + s->look;
+	unsigned char scan_end1;
+	
+	assert(s->m_len > 0);
+	
+	scan_end1 = bp[m_len - 1];
+	for ( ; cnt-- > 0; node = s->succ3[node])
+	{
+		p1 = bp;
+		p2 = b + node;
+		px = bx;
+		
+		assert(m_len < s->look);
+		
+		if (
+			p2[m_len - 1] == scan_end1 &&
+			p2[m_len] == p1[m_len] &&
+			p2[0] == p1[0] &&
+			p2[1] == p1[1])
+		{
+			unsigned int i;
+			assert(memcmp(bp,&b[node],3) == 0);
+			
+			p1 += 2; p2 += 2;
+			do {} while (++p1 < px && *p1 == *++p2);
+			i = p1 - bp;
+			
+#ifdef UCL_DEBUG
+			if (memcmp(bp,&b[node],i) != 0)
+				printf("%5ld %5ld %02x%02x %02x%02x\n",
+					(long)s->bp, (long) node,
+					bp[0], bp[1], b[node], b[node+1]);
+#endif
+			assert(memcmp(bp,&b[node],i) == 0);
+			
+#if defined(SWD_BEST_OFF)
+			if (i < SWD_BEST_OFF)
+			{
+				if (s->best_pos[i] == 0)
+					s->best_pos[i] = node + 1;
+			}
+#endif
+			if (i > m_len)
+			{
+				s->m_len = m_len = i;
+				s->m_pos = node;
+				if (m_len == s->look)
+					return;
+				if (m_len >= s->nice_length)
+					return;
+				if (m_len > (unsigned int) s->best3[node])
+					return;
+				scan_end1 = bp[m_len - 1];
+			}
+		}
+	}
+}
+
+static int swd_search2(struct ucl_swd *s)
+{
+	unsigned int key;
+	
+	assert(s->look >= 2);
+	assert(s->m_len > 0);
+	
+	key = s->head2[ HEAD2(s->b,s->bp) ];
+	if (key == NIL2)
+		return 0;
+#ifdef UCL_DEBUG
+	if (memcmp(&s->b[s->bp],&s->b[key],2) != 0)
+		printf("%5ld %5ld %02x%02x %02x%02x\n", (long)s->bp, (long)key,
+			s->b[s->bp], s->b[s->bp+1], s->b[key], s->b[key+1]);
+#endif
+	assert(memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+	if (s->best_pos[2] == 0)
+		s->best_pos[2] = key + 1;
+#endif
+	
+	if (s->m_len < 2)
+	{
+		s->m_len = 2;
+		s->m_pos = key;
+	}
+	return 1;
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_findbest(struct ucl_swd *s)
+{
+	unsigned int key;
+	unsigned int cnt, node;
+	unsigned int len;
+
+	assert(s->m_len > 0);
+
+	/* get current head, add bp into HEAD3 */
+	key = HEAD3(s->b,s->bp);
+	node = s->succ3[s->bp] = s_head3(s,key);
+	cnt = s->llen3[key]++;
+	assert(s->llen3[key] <= s->n + s->f);
+	if (cnt > s->max_chain && s->max_chain > 0)
+		cnt = s->max_chain;
+	s->head3[key] = (unsigned int)(s->bp);
+
+	s->b_char = s->b[s->bp];
+	len = s->m_len;
+	if (s->m_len >= s->look)
+	{
+		if (s->look == 0)
+			s->b_char = -1;
+		s->m_off = 0;
+		s->best3[s->bp] = (unsigned int)(s->f + 1);
+	}
+	else
+	{
+		if (swd_search2(s))
+			if (s->look >= 3)
+				swd_search(s,node,cnt);
+		if (s->m_len > len)
+			s->m_off = swd_pos2off(s,s->m_pos);
+		s->best3[s->bp] = (unsigned int)(s->m_len);
+
+#if defined(SWD_BEST_OFF)
+		if (s->use_best_off)
+		{
+			int i;
+			for (i = 2; i < SWD_BEST_OFF; i++)
+				if (s->best_pos[i] > 0)
+					s->best_off[i] =
+						swd_pos2off(s,s->best_pos[i]-1);
+
+				else
+					s->best_off[i] = 0;
+		}
+#endif
+	}
+
+	swd_remove_node(s,s->rp);
+
+	/* add bp into HEAD2 */
+	key = HEAD2(s->b,s->bp);
+	s->head2[key] = (unsigned int)(s->bp);
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+init_match ( struct ucl_compress *c, struct ucl_swd *s,
+	const uint8_t *dict, unsigned int dict_len,
+	uint32_t flags )
+{
+	int r;
+	
+	assert(!c->init);
+	c->init = 1;
+	
+	s->c = c;
+	
+	c->last_m_len = c->last_m_off = 0;
+	
+	c->textsize = c->codesize = c->printcount = 0;
+	c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
+	c->lazy = 0;
+	
+	r = swd_init(s,dict,dict_len);
+	if (r != UCL_E_OK)
+	{
+		swd_exit(s);
+		return r;
+	}
+	
+	s->use_best_off = (flags & 1) ? 1 : 0;
+	return UCL_E_OK;
+}
+
+static int
+find_match ( struct ucl_compress *c, struct ucl_swd *s,
+	unsigned int this_len, unsigned int skip )
+{
+	assert(c->init);
+	
+	if (skip > 0)
+	{
+		assert(this_len >= skip);
+		swd_accept(s, this_len - skip);
+		c->textsize += this_len - skip + 1;
+	}
+	else
+	{
+		assert(this_len <= 1);
+		c->textsize += this_len - skip;
+	}
+	
+	s->m_len = THRESHOLD;
+#ifdef SWD_BEST_OFF
+	if (s->use_best_off)
+		memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+	swd_findbest(s);
+	c->m_len = s->m_len;
+	c->m_off = s->m_off;
+	
+	swd_getbyte(s);
+	
+	if (s->b_char < 0)
+	{
+		c->look = 0;
+		c->m_len = 0;
+		swd_exit(s);
+	}
+	else
+	{
+		c->look = s->look + 1;
+	}
+	c->bp = c->ip - c->look;
+	
+#if 0
+	/* brute force match search */
+	if (c->m_len > THRESHOLD && c->m_len + 1 <= c->look)
+	{
+		const uint8_t *ip = c->bp;
+		const uint8_t *m  = c->bp - c->m_off;
+		const uint8_t *in = c->in;
+		
+		if (ip - in > N)
+			in = ip - N;
+		for (;;)
+		{
+			while (*in != *ip)
+				in++;
+			if (in == ip)
+				break;
+			if (in != m)
+				if (memcmp(in,ip,c->m_len+1) == 0)
+					printf("%p %p %p %5d\n",in,ip,m,c->m_len);
+
+			in++;
+		}
+	}
+#endif
+	
+	return UCL_E_OK;
+}
+
+
+static int bbConfig(struct ucl_compress *c, int endian, int bitsize)
+{
+	if (endian != -1)
+	{
+		if (endian != 0)
+			return UCL_E_ERROR;
+		c->bb_c_endian = endian;
+	}
+	if (bitsize != -1)
+	{
+		if (bitsize != 8 && bitsize != 16 && bitsize != 32 && bitsize != 64)
+			return UCL_E_ERROR;
+		c->bb_c_s = bitsize;
+		c->bb_c_s8 = bitsize / 8;
+	}
+	c->bb_b = 0; c->bb_k = 0;
+	c->bb_p = NULL;
+	c->bb_op = NULL;
+	return UCL_E_OK;
+}
+
+static void bbWriteBits(struct ucl_compress *c)
+{
+	uint8_t *p = c->bb_p;
+	uint64_t b = c->bb_b;
+
+	p[0] = (uint8_t)(b >>  0);
+	if (c->bb_c_s >= 16)
+	{
+		p[1] = (uint8_t)(b >>  8);
+		if (c->bb_c_s >= 32)
+		{
+			p[2] = (uint8_t)(b >> 16);
+			p[3] = (uint8_t)(b >> 24);
+			if (c->bb_c_s == 64)
+			{
+				p[4] = (uint8_t)(b >> 32);
+				p[5] = (uint8_t)(b >> 40);
+				p[6] = (uint8_t)(b >> 48);
+				p[7] = (uint8_t)(b >> 56);
+			}
+		}
+	}
+}
+
+
+static void bbPutBit(struct ucl_compress *c, unsigned bit)
+{
+	assert(bit == 0 || bit == 1);
+	assert(c->bb_k <= c->bb_c_s);
+
+	if (c->bb_k < c->bb_c_s)
+	{
+		if (c->bb_k == 0)
+		{
+			assert(c->bb_p == NULL);
+			c->bb_p = c->bb_op;
+			c->bb_op += c->bb_c_s8;
+		}
+		assert(c->bb_p != NULL);
+		assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+		c->bb_b = (c->bb_b << 1) + bit;
+		c->bb_k++;
+	}
+	else
+	{
+		assert(c->bb_p != NULL);
+		assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+		bbWriteBits(c);
+		c->bb_p = c->bb_op;
+		c->bb_op += c->bb_c_s8;
+		c->bb_b = bit;
+		c->bb_k = 1;
+	}
+}
+
+
+static void bbPutByte(struct ucl_compress *c, unsigned b)
+{
+	/**printf("putbyte %p %p %x  (%d)\n", op, bb_p, x, bb_k);*/
+	assert(c->bb_p == NULL || c->bb_p + c->bb_c_s8 <= c->bb_op);
+	*c->bb_op++ = (uint8_t)(b);
+}
+
+static void bbFlushBits(struct ucl_compress *c, unsigned filler_bit)
+{
+	if (c->bb_k > 0)
+	{
+		assert(c->bb_k <= c->bb_c_s);
+		while (c->bb_k != c->bb_c_s)
+			bbPutBit(c, filler_bit);
+		bbWriteBits(c);
+		c->bb_k = 0;
+	}
+	c->bb_p = NULL;
+}
+
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static void code_prefix_ss11(struct ucl_compress *c, uint32_t i)
+{
+	if (i >= 2)
+	{
+		uint32_t t = 4;
+		i += 2;
+		do {
+			t <<= 1;
+		} while (i >= t);
+		t >>= 1;
+		do {
+			t >>= 1;
+			bbPutBit(c, (i & t) ? 1 : 0);
+			bbPutBit(c, 0);
+		} while (t > 2);
+	}
+	bbPutBit(c, (unsigned)i & 1);
+	bbPutBit(c, 1);
+}
+
+static void
+code_match(struct ucl_compress *c, unsigned int m_len, const unsigned int m_off)
+
+{
+	while (m_len > c->conf.max_match)
+	{
+		code_match(c, c->conf.max_match - 3, m_off);
+		m_len -= c->conf.max_match - 3;
+	}
+	
+	c->match_bytes += m_len;
+	if (m_len > c->result[3])
+		c->result[3] = m_len;
+	if (m_off > c->result[1])
+		c->result[1] = m_off;
+
+	bbPutBit(c, 0);
+
+	if (m_off == c->last_m_off)
+	{
+		bbPutBit(c, 0);
+		bbPutBit(c, 1);
+	}
+	else
+	{
+		code_prefix_ss11(c, 1 + ((m_off - 1) >> 8));
+		bbPutByte(c, (unsigned)m_off - 1);
+	}
+	m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
+	if (m_len >= 4)
+	{
+		bbPutBit(c,0);
+		bbPutBit(c,0);
+		code_prefix_ss11(c, m_len - 4);
+	}
+	else
+	{
+		bbPutBit(c, m_len > 1);
+		bbPutBit(c, (unsigned)m_len & 1);
+	}
+
+	c->last_m_off = m_off;
+}
+
+static void
+code_run(struct ucl_compress *c, const uint8_t *ii, unsigned int lit)
+{
+	if (lit == 0)
+		return;
+	c->lit_bytes += lit;
+	if (lit > c->result[5])
+		c->result[5] = lit;
+	do {
+		bbPutBit(c, 1);
+		bbPutByte(c, *ii++);
+	} while (--lit > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+len_of_coded_match(struct ucl_compress *c, unsigned int m_len, unsigned int
+	m_off)
+
+{
+	int b;
+	if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+		|| m_off > c->conf.max_offset)
+		return -1;
+	assert(m_off > 0);
+	
+	m_len = m_len - 2 - (m_off > M2_MAX_OFFSET);
+	
+	if (m_off == c->last_m_off)
+		b = 1 + 2;
+	else
+	{
+		b = 1 + 10;
+		m_off = (m_off - 1) >> 8;
+		while (m_off > 0)
+		{
+			b += 2;
+			m_off >>= 1;
+		}
+	}
+
+	b += 2;
+	if (m_len < 3)
+		return b;
+	m_len -= 3;
+
+	do {
+		b += 2;
+		m_len >>= 1;
+	} while (m_len > 0);
+
+	return b;
+}
+
+int ucl_nrv2b_99_compress(
+	const uint8_t *in, unsigned long in_len,
+	uint8_t *out, unsigned long *out_len,
+	unsigned int *result)
+{
+	const uint8_t *ii;
+	unsigned int lit;
+	unsigned int m_len, m_off;
+	struct ucl_compress c_buffer;
+	struct ucl_compress * const c = &c_buffer;
+	struct ucl_swd *swd;
+	unsigned int result_buffer[16];
+	int r;
+
+/* max compression */
+#define SC_TRY_LAZY    2
+#define SC_GOOD_LENGTH F
+#define SC_MAX_LAZY    F
+#define SC_NICE_LENGTH F
+#define SC_MAX_CHAIN   4096
+#define SC_FLAGS       1
+#define SC_MAX_OFFSET  N
+	
+	memset(c, 0, sizeof(*c));
+	c->ip = c->in = in;
+	c->in_end = in + in_len;
+	c->out = out;
+	c->result = result ? result : result_buffer;
+	memset(c->result, 0, 16*sizeof(*c->result));
+	c->result[0] = c->result[2] = c->result[4] = UINT_MAX;
+	result = NULL;
+	memset(&c->conf, 0xff, sizeof(c->conf));
+	r = bbConfig(c, ENDIAN, BITSIZE);
+	if (r == 0)
+		r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size);
+	if (r != 0)
+		return UCL_E_INVALID_ARGUMENT;
+	c->bb_op = out;
+	
+	ii = c->ip;             /* point to start of literal run */
+	lit = 0;
+	
+
+	swd = (struct ucl_swd *) malloc(sizeof(*swd));
+	if (!swd)
+		return UCL_E_OUT_OF_MEMORY;
+
+	swd->f = F;
+	swd->n = N;
+	if (in_len >= 256 && in_len < swd->n)
+		swd->n = in_len;
+	if (swd->f < 8 || swd->n < 256)
+		return UCL_E_INVALID_ARGUMENT;
+
+	r = init_match(c,swd,NULL,0, SC_FLAGS);
+	if (r != UCL_E_OK)
+	{
+		free(swd);
+		return r;
+	}
+	if (SC_MAX_CHAIN > 0)
+		swd->max_chain = SC_MAX_CHAIN;
+	if (SC_NICE_LENGTH > 0)
+		swd->nice_length = SC_NICE_LENGTH;
+	if (c->conf.max_match < swd->nice_length)
+		swd->nice_length = c->conf.max_match;
+	
+	c->last_m_off = 1;
+	r = find_match(c,swd,0,0);
+	if (r != UCL_E_OK)
+		return r;
+	while (c->look > 0)
+	{
+		unsigned int ahead;
+		unsigned int max_ahead;
+		int l1, l2;
+		
+		c->codesize = c->bb_op - out;
+		
+		m_len = c->m_len;
+		m_off = c->m_off;
+		
+		assert(c->bp == c->ip - c->look);
+		assert(c->bp >= in);
+		if (lit == 0)
+			ii = c->bp;
+		assert(ii + lit == c->bp);
+		assert(swd->b_char == *(c->bp));
+		
+		if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+			|| m_off > c->conf.max_offset)
+		{
+			/* a literal */
+			lit++;
+			swd->max_chain = SC_MAX_CHAIN;
+			r = find_match(c,swd,1,0);
+			assert(r == 0);
+			continue;
+		}
+		
+		/* a match */
+		assert_match(swd,m_len,m_off);
+		
+		/* shall we try a lazy match ? */
+		ahead = 0;
+		if (SC_TRY_LAZY <= 0 || m_len >= SC_MAX_LAZY || m_off ==
+			c->last_m_off)
+
+		{
+			/* no */
+			l1 = 0;
+			max_ahead = 0;
+		}
+		else
+		{
+			/* yes, try a lazy match */
+			l1 = len_of_coded_match(c,m_len,m_off);
+			assert(l1 > 0);
+			max_ahead = SC_TRY_LAZY;
+			if ((m_len - 1) < max_ahead) {
+				max_ahead = m_len -1;
+			}
+		}
+		
+		while (ahead < max_ahead && c->look > m_len)
+		{
+			if (m_len >= SC_GOOD_LENGTH)
+				swd->max_chain = SC_MAX_CHAIN >> 2;
+			else
+				swd->max_chain = SC_MAX_CHAIN;
+			r = find_match(c,swd,1,0);
+			ahead++;
+			
+			assert(r == 0);
+			assert(c->look > 0);
+			assert(ii + lit + ahead == c->bp);
+			
+			if (c->m_len < 2)
+				continue;
+			l2 = len_of_coded_match(c,c->m_len,c->m_off);
+			if (l2 < 0)
+				continue;
+			if (l1 + (int)(ahead + c->m_len - m_len) * 5 > l2 +
+				(int)(ahead) * 9)
+			{
+				c->lazy++;
+				assert_match(swd,c->m_len,c->m_off);
+				lit += ahead;
+				assert(ii + lit == c->bp);
+				goto lazy_match_done;
+			}
+		}
+		
+		assert(ii + lit + ahead == c->bp);
+		
+		/* 1 - code run */
+		code_run(c,ii,lit);
+		lit = 0;
+		
+		/* 2 - code match */
+		code_match(c,m_len,m_off);
+		swd->max_chain = SC_MAX_CHAIN;
+		r = find_match(c,swd,m_len,1+ahead);
+		assert(r == 0);
+		
+	lazy_match_done: ;
+	}
+	
+	/* store final run */
+	code_run(c,ii,lit);
+	
+	/* EOF */
+	bbPutBit(c, 0);
+	code_prefix_ss11(c, 0x1000000U);
+	bbPutByte(c, 0xff);
+
+	bbFlushBits(c, 0);
+	
+	assert(c->textsize == in_len);
+	c->codesize = c->bb_op - out;
+	*out_len = c->bb_op - out;
+	
+#if 0
+	printf("%7ld %7ld -> %7ld   %7ld %7ld   %ld  (max: %d %d %d)\n",
+		(long) c->textsize, (long) in_len, (long) c->codesize,
+		c->match_bytes, c->lit_bytes,  c->lazy,
+		c->result[1], c->result[3], c->result[5]);
+#endif
+	assert(c->lit_bytes + c->match_bytes == in_len);
+	
+	swd_exit(swd);
+	free(swd);
+
+	return UCL_E_OK;
+}
+
+
+void Encode(void)  /* compression */
+{
+	uint8_t *in, *out;
+	unsigned long in_len, out_len;
+	uint32_t tw;
+	int r;
+	fseek(infile, 0, SEEK_END);
+	in_len = ftell(infile);
+#ifdef VERBOSE
+	if ((signed long)in_len < 0)
+		Fprintf((stderr, "Errno: %d", errno));
+#endif
+#if UCLPACK_COMPAT
+	{
+		uint8_t byte;
+		if (fwrite(magic, sizeof(magic), 1, outfile) != 1)
+			Error("Can't write.");
+		tw = htonl(0); /* flags */
+		if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+			Error("Can't write.");
+		byte = 0x2b;		/* method */
+		if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+			Error("Can't write.");
+		byte = 10;		/* level */
+		if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+			Error("Can't write.");
+		tw = htonl(256*1024);		/* block_size */
+		if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+			Error("Can't write.");
+		tw = htonl(in_len);
+		if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+			Error("Can't write.");	/* output size of text */
+	}
+#else
+	tw = host_to_i86ul(in_len);
+	if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+		Error("Can't write.");	/* output size of text */
+#endif	
+	if (in_len == 0)
+		return;
+	rewind(infile);
+
+	in = malloc(in_len);
+	out_len = in_len + (in_len/8) + 256;
+	out = malloc(out_len);
+	if (!in || !out) {
+		Error("Can't malloc");
+	}
+	if (fread(in, in_len, 1, infile) != 1) {
+		Error("Can't read");
+	}
+	r = ucl_nrv2b_99_compress(in, in_len, out, &out_len, 0 );
+	if (r != UCL_E_OK)
+		Error("Compression failure\n");
+#if UCLPACK_COMPAT
+	tw = htonl(out_len);
+	if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+		Error("Can't write.");	/* file size of text */
+
+#endif
+	if (fwrite(out, out_len, 1, outfile) != 1) {
+		Error("Write error\n");
+	}
+#if UCLPACK_COMPAT
+	tw = htonl(0); /* EOF marker */
+	if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+		Error("Can't write.");
+
+#endif
+
+#ifdef	LONG_REPORT
+	Fprintf((stdout, "input size    %ld bytes\n", in_len));
+	Fprintf((stdout, "output size   %ld bytes\n", out_len));
+	Fprintf((stdout, "input/output  %.3f\n", (double)in_len / out_len));
+#else
+	Fprintf((stdout, "input/output = %ld/%ld = %.3f\n", in_len, out_len,
+		(double)in_len / out_len));
+#endif
+	
+}
+
+#endif
+
+#ifdef DECODE
+
+#define GETBIT_8(bb, src, ilen) \
+    (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
+
+#define GETBIT_LE16(bb, src, ilen) \
+    (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))
+
+#define GETBIT_LE32(bb, src, ilen) \
+    (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
+    bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))
+
+#define GETBIT_LE64(bb, src, ilen) \
+    (bc > 0 ? ((bb>>--bc)&1) : (bc=63, \
+    bb=*(const uint64_t *)((src)+ilen),ilen+=8,(bb>>63)&1))
+
+#if ENDIAN == 0 && BITSIZE == 8
+#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 16
+#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 32
+#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 64
+#define GETBIT(bb, src, ilen) GETBIT_LE64(bb, src, ilen)
+#endif
+#ifndef GETBIT
+#error "Bad Combination of ENDIAN and BITSIZE values specified"
+#endif
+
+#undef SAFE
+
+#ifdef SAFE
+#define FAIL(x,r)   if (x) { Error(r); }
+#else
+#define FAIL(x,r)
+#endif
+
+void Decode(void)  /* recover */
+{
+	uint32_t tw;
+	uint8_t *src, *dst;
+	unsigned long max_src_len, src_len, dst_len;
+	unsigned long ilen = 0, olen = 0, last_m_off =  1;
+#if BITSIZE <= 32
+	uint32_t bb = 0;
+#elif BITSIZE == 64
+	uint64_t bb = 0;
+#endif
+	unsigned bc = 0;
+#if UCLPACK_COMPAT
+	if (fseek(infile, sizeof(magic) + sizeof(tw) + 1 + 1 + sizeof(tw),
+		SEEK_SET) != 0)
+
+		Error("Seek Error");
+	if (fread(&tw, sizeof(tw), 1, infile) < 1)
+		Error("Can't read"); /* read size of text */
+	dst_len = ntohl(tw);
+	if (fread(&tw, sizeof(tw), 1, infile) < 1)
+		Error("Can't read"); /* read size of file */
+	max_src_len = ntohl(tw);
+#else
+	if (fread(&tw, sizeof(tw), 1, infile) < 1)
+		Error("Can't read"); /* read size of text */
+	dst_len = i86ul_to_host(tw);
+	max_src_len = dst_len + (dst_len/8) + 256;
+#endif
+	if (dst_len == 0)
+		return;
+	dst = malloc(dst_len);
+	if (!dst)
+		Error("Can't malloc");
+	src = malloc(max_src_len);
+	if (!src)
+		Error("Can't malloc");
+	src_len = fread(src, 1, max_src_len, infile);
+	if (src_len <= 0) 
+		Error("Can't read");
+
+	for(;;) {
+		unsigned int m_off, m_len;
+		while(GETBIT(bb, src, ilen)) {
+			FAIL(ilen >= src_len, "input overrun");
+			FAIL(olen >= dst_len, "output  overrun");
+			dst[olen++] = src[ilen++];
+		}
+		m_off = 1;
+		do {
+			m_off = m_off*2 + GETBIT(bb, src, ilen);
+			FAIL(ilen >= src_len, "input overrun");
+			FAIL(m_off > 0xffffffU +3, "lookbehind overrun");
+		} while (!GETBIT(bb, src, ilen));
+		if (m_off == 2)
+		{
+			m_off = last_m_off;
+		}
+		else
+		{
+			FAIL(ilen >= src_len, "input overrun");
+			m_off = (m_off - 3)*256 + src[ilen++];
+			if (m_off == 0xffffffffU)
+				break;
+			last_m_off = ++m_off;
+		}
+		m_len = GETBIT(bb, src, ilen);
+		m_len = m_len*2 + GETBIT(bb, src, ilen);
+		if (m_len == 0) 
+		{
+			m_len++;
+			do {
+				m_len = m_len*2 + GETBIT(bb, src, ilen);
+				FAIL(ilen >= src_len, "input overrun");
+				FAIL(m_len >= dst_len, "output overrun");
+			} while(!GETBIT(bb, src, ilen));
+			m_len += 2;
+		}
+		m_len += (m_off > 0xd00);
+		FAIL(olen + m_len > dst_len, "output overrun");
+		FAIL(m_off > olen, "lookbeind overrun");
+		{
+			const uint8_t *m_pos;
+			m_pos = dst + olen - m_off;
+			dst[olen++] = *m_pos++;
+			do {
+				dst[olen++] = *m_pos++;
+			} while(--m_len > 0);
+		}
+	}
+	FAIL(ilen < src_len, "input not consumed");
+	FAIL(ilen > src_len, "input overrun");
+	assert(ilen == src_len);
+	Fprintf((stderr, "%12ld\n", olen));
+	if (dst_len != olen) {
+		fprintf(stderr, "length != expected length\n");
+	}
+	if (fwrite(dst, olen, 1, outfile) != 1)
+		Error("Write error\n");
+	free(src);
+	free(dst);
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+	char  *s;
+	FILE  *f;
+	int    c;
+	
+	if (argc == 2) {
+		outfile = stdout;
+		if ((f = tmpfile()) == NULL) {
+			perror("tmpfile");
+			return EXIT_FAILURE;
+		}
+		while ((c = getchar()) != EOF)
+			fputc(c, f);
+		rewind(infile = f);
+	}
+	else if (argc != 4) {
+		Fprintf((stderr, "'nrv2b e file1 file2' encodes file1 into file2.\n"
+			"'nrv2b d file2 file1' decodes file2 into file1.\n"));
+		return EXIT_FAILURE;
+	}
+	if (argc == 4) {
+		if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+			|| (s = argv[2], (infile  = fopen(s, "rb")) == NULL)
+			|| (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+			Fprintf((stderr, "??? %s\n", s));
+			return EXIT_FAILURE;
+		}
+	}
+	if (toupper(*argv[1]) == 'E')
+		Encode();
+	else
+		Decode();
+	fclose(infile);
+	fclose(outfile);
+	return EXIT_SUCCESS;
+}
+#endif
diff --git a/qemu-0.15.x/roms/ipxe/src/util/padimg.pl b/qemu-0.15.x/roms/ipxe/src/util/padimg.pl
new file mode 100755
index 0000000..4421aaf
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/padimg.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Fcntl;
+
+my $verbosity = 0;
+my $blksize = 512;
+my $byte = 0;
+
+my %opts = (
+  'verbose|v+' => sub { $verbosity++; },
+  'quiet|q+' => sub { $verbosity--; },
+  'blksize|s=o' => sub { $blksize = $_[1]; },
+  'byte|b=o' => sub { $byte = $_[1]; },
+);
+
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions ( %opts ) or die "Could not parse command-line options\n";
+
+while ( my $filename = shift ) {
+  die "$filename is not a file\n" unless -f $filename;
+  my $oldsize = -s $filename;
+  my $padsize = ( ( -$oldsize ) % $blksize );
+  my $newsize = ( $oldsize + $padsize );
+  next unless $padsize;
+  if ( $verbosity >= 1 ) {
+      printf "Padding %s from %d to %d bytes with %d x 0x%02x\n",
+	     $filename, $oldsize, $newsize, $padsize, $byte;
+  }
+  if ( $byte ) {
+    sysopen ( my $fh, $filename, ( O_WRONLY | O_APPEND ) )
+	or die "Could not open $filename for appending: $!\n";
+    syswrite $fh, ( chr ( $byte ) x $padsize )
+	or die "Could not append to $filename: $!\n";
+    close ( $fh );
+  } else {
+    truncate $filename, $newsize
+	or die "Could not resize $filename: $!\n";
+  }
+  die "Failed to pad $filename\n"
+      unless ( ( ( -s $filename ) % $blksize ) == 0 );
+}
diff --git a/qemu-0.15.x/roms/ipxe/src/util/parserom.pl b/qemu-0.15.x/roms/ipxe/src/util/parserom.pl
new file mode 100644
index 0000000..cf9f7c6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/parserom.pl
@@ -0,0 +1,66 @@
+#!/usr/bin/perl -w
+#
+# Parse PCI_ROM and ISA_ROM entries from a source file on stdin and
+# output the relevant Makefile variable definitions to stdout
+#
+# Based upon portions of Ken Yap's genrules.pl
+
+use strict;
+use warnings;
+
+die "Syntax: $0 driver_source.c" unless @ARGV == 1;
+my $source = shift;
+open DRV, "<$source" or die "Could not open $source: $!\n";
+
+( my $family, my $driver_name ) = ( $source =~ /^(.*?([^\/]+))\..$/ )
+    or die "Could not parse source file name \"$source\"\n";
+
+my $printed_family;
+
+sub rom {
+  ( my $type, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
+  my $ids = $vendor ? "$vendor,$device" : "-";
+  unless ( $printed_family ) {
+    print "\n";
+    print "# NIC\t\n";
+    print "# NIC\tfamily\t$family\n";
+    print "DRIVERS += $driver_name\n";
+    $printed_family = 1;
+  }
+  print "\n";
+  print "# NIC\t$image\t$ids\t$desc\n";
+  print "DRIVER_$image = $driver_name\n";
+  print "ROM_TYPE_$image = $type\n";
+  print "ROM_DESCRIPTION_$image = \"$desc\"\n";
+  print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
+  print "PCI_DEVICE_$image = 0x$device\n" if $device;
+  print "ROMS += $image\n" unless $dup;
+  print "ROMS_$driver_name += $image\n" unless $dup;
+}
+
+while ( <DRV> ) {
+  next unless /(PCI|ISA)_ROM\s*\(/;
+
+  if ( /^\s*PCI_ROM\s*\(
+         \s*0x([0-9A-Fa-f]{4})\s*, # PCI vendor
+         \s*0x([0-9A-Fa-f]{4})\s*, # PCI device
+         \s*\"([^\"]*)\"\s*,	   # Image
+         \s*\"([^\"]*)\"\s*,	   # Description
+         \s*.*\s*		   # Driver data
+       \)/x ) {
+    ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 );
+    next if ( $vendor eq "ffff" ) || ( $device eq "ffff" );
+    rom ( "pci", lc "${vendor}${device}", $desc, $vendor, $device );
+    rom ( "pci", $image, $desc, $vendor, $device, 1 );
+  } elsif ( /^\s*ISA_ROM\s*\(
+	      \s*\"([^\"]*)\"\s*,  # Image
+	      \s*\"([^\"]*)\"\s*   # Description
+	    \)/x ) {
+    ( my $image, my $desc ) = ( $1, $2 );
+    rom ( "isa", $image, $desc );
+  } else {
+    warn "Malformed PCI_ROM or ISA_ROM macro on line $. of $source\n";
+  }
+}
+
+close DRV;
diff --git a/qemu-0.15.x/roms/ipxe/src/util/sortobjdump.pl b/qemu-0.15.x/roms/ipxe/src/util/sortobjdump.pl
new file mode 100755
index 0000000..1373a7f
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/sortobjdump.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+# Sort the symbol table portion of the output of objdump -ht by
+# section, then by symbol value, then by size.  Used to enhance the
+# linker maps produced by "make bin/%.map" by also showing the values
+# of all non-global symbols.
+
+my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" );
+my %lines;
+while ( <> ) {
+  if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) {
+    # It's a header line containing a section definition; extract the
+    # section index and store it.  Also print the header line.
+    print;
+    ( my $index, my $section ) = ( $1, $2 );
+    $section_idx{$section} = sprintf ( "%02d", $index );
+  } elsif ( /^([0-9a-fA-F]+)\s.*?\s([\.\*]\S+)\s+([0-9a-fA-F]+)\s+(\S+)/ ) {
+    # It's a symbol line - store it in the hash, indexed by
+    # "<section_index>:<value>:<size>:<end_tag>".  <end_tag> is "0" if
+    # the symbol name is of the form xxx_end, "1" otherwise; this is
+    # done so that table end markers show up before any other symbols
+    # with the same value.
+    ( my $value, my $section, my $size, my $name ) = ( $1, $2, $3, $4 );
+    die "Unrecognised section \"$section\"\n"
+	unless exists $section_idx{$section};
+    my $section_idx = $section_idx{$section};
+    my $end = ( $name =~ /_end$/ ) ? "0" : "1";
+    my $key = $section_idx.":".$value.":".$size.":".$end;
+    $lines{$key} ||= '';
+    $lines{$key} .= $_;
+  } else {
+    # It's a generic header line: just print it.
+    print;
+  }
+}
+
+print $lines{$_} foreach sort keys %lines;
diff --git a/qemu-0.15.x/roms/ipxe/src/util/swapdevids.pl b/qemu-0.15.x/roms/ipxe/src/util/swapdevids.pl
new file mode 100755
index 0000000..c6255ae
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/swapdevids.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+#
+#	Program to reverse the device identifier IDs in the PCIR and PnP
+#	structures in a ROM for old non-compliant BIOSes
+#
+#	GPL, Ken Yap 2001
+#
+
+use bytes;
+
+use IO::Seekable;
+
+sub swaplocs ($$$)
+{
+	my ($dataref, $loc1, $loc2) = @_;
+	my ($t);
+
+	$t = substr($$dataref, $loc1, 1);
+	substr($$dataref, $loc1, 1) = substr($$dataref, $loc2, 1);
+	substr($$dataref, $loc2, 1) = $t;
+}
+
+sub printdevids ($$)
+{
+	my ($dataref, $loc) = @_;
+
+	return (sprintf "%02x %02x %02x", unpack('C3', substr($$dataref, $loc, 3)));
+}
+
+$#ARGV >= 0 or die "Usage: $0 romimage\n";
+$file = $ARGV[0];
+open(F, "+<$file") or die "$file: $!\n";
+binmode(F);
+# Handle up to 64kB ROM images
+$len = read(F, $data, 64*1024);
+defined($len) or die "$file: $!\n";
+substr($data, 0, 2) eq "\x55\xAA" or die "$file: Not a boot ROM image\n";
+($pci, $pnp) = unpack('v2', substr($data, 0x18, 4));
+($pci < $len and $pnp < $len) or die "$file: Not a PCI PnP ROM image\n";
+(substr($data, $pci, 4) eq 'PCIR' and substr($data, $pnp, 4) eq '$PnP')
+	or die "$file: No PCI and PNP structures, not a PCI PNP ROM image\n";
+&swaplocs(\$data, $pci+13, $pci+15);
+&swaplocs(\$data, $pnp+18, $pnp+20);
+seek(F, 0, SEEK_SET) or die "$file: Cannot seek to beginning\n";
+print F $data;
+close(F);
+print "PCI devids now: ", &printdevids(\$data, $pci+13), "\n";
+print "PnP devids now: ", &printdevids(\$data, $pnp+18), "\n";
+exit(0);
diff --git a/qemu-0.15.x/roms/ipxe/src/util/symcheck.pl b/qemu-0.15.x/roms/ipxe/src/util/symcheck.pl
new file mode 100755
index 0000000..8925ca6
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/symcheck.pl
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use constant WARNING_SIZE => 512;
+
+my $symtab = {};
+
+# Scan output of "objdump -w -t bin/blib.a" and build up symbol table
+#
+my $object;
+while ( <> ) {
+  chomp;
+  if ( /^In archive/ ) {
+    # Do nothing
+  } elsif ( /^$/ ) {
+    # Do nothing
+  } elsif ( /^(\S+\.o):\s+file format/ ) {
+    $object = $1;
+  } elsif ( /^SYMBOL TABLE:/ ) {
+    # Do nothing
+  } elsif ( /^([0-9a-fA-F]+)\s(l|g|\s)......\s(\S+)\s+([0-9a-fA-F]+)\s+(\S+)$/ ) {
+    my $value = $1;
+    my $scope = $2;
+    my $section = $3;
+    my $size = $4;
+    my $symbol = $5;
+    $symtab->{$object}->{$symbol} = {
+      global	=> ( $scope ne "l" ),
+      section	=> ( $section eq "*UND*" ? undef : $section ),
+      value	=> ( $value ? hex ( $value ) : 0 ),
+      size	=> ( $size ? hex ( $size ) : 0 ),
+    };
+  } else {
+    die "Unrecognized line \"$_\"";
+  }
+}
+
+# Add symbols that we know will be generated or required by the linker
+#
+foreach my $object ( keys %$symtab ) {
+  my $obj_symbol = "obj_$object";
+  $obj_symbol =~ s/\.o$//;
+  $obj_symbol =~ s/\W/_/g;
+  $symtab->{LINKER}->{$obj_symbol} = {
+    global	=> 1,
+    section	=> undef,
+    value	=> 0,
+    size	=> 0,
+  };
+}
+foreach my $link_sym qw ( __prefix _prefix _prefix_load_offset
+			  _prefix_size _prefix_progbits_size _prefix_size_pgh
+			  __text16 _text16 _text16_load_offset
+			  _text16_size _text16_progbits_size _text16_size_pgh
+			  __data16 _data16 _data16_load_offset
+			  _data16_size _data16_progbits_size _data16_size_pgh
+			  __text _text __data _data _textdata_load_offset
+			  _textdata_size _textdata_progbits_size
+			  __rodata __bss _end
+			  _payload_offset _max_align
+			  _load_size _load_size_pgh _load_size_sect
+			  pci_vendor_id pci_device_id ) {
+  $symtab->{LINKER}->{$link_sym} = {
+    global	=> 1,
+    section	=> '*ABS*',
+    value	=> 0,
+    size	=> 0,
+  };
+}
+
+# Add symbols that we know will be used by the debug system
+#
+foreach my $debug_sym qw ( dbg_autocolourise dbg_decolourise
+			   dbg_hex_dump_da ) {
+  $symtab->{DEBUG}->{$debug_sym} = {
+    global	=> 1,
+    section	=> undef,
+    value	=> 0,
+    size	=> 0,
+  };
+}
+
+# Build up requires, provides and shares symbol tables for global
+# symbols
+#
+my $globals = {};
+while ( ( my $object, my $symbols ) = each %$symtab ) {
+  while ( ( my $symbol, my $info ) = each %$symbols ) {
+    if ( $info->{global} ) {
+      my $category;
+      if ( ! defined $info->{section} ) {
+	$category = "requires";
+      } elsif ( $info->{section} eq "*COM*" ) {
+	$category = "shares";
+      } else {
+	$category = "provides";
+      }
+      $globals->{$symbol}->{$category}->{$object} = 1;
+    }
+  }
+}
+
+# Check for multiply defined, never-defined and unused global symbols
+#
+my $problems = {};
+while ( ( my $symbol, my $info ) = each %$globals ) {
+  my @provides = keys %{$info->{provides}};
+  my @requires = keys %{$info->{requires}};
+  my @shares = keys %{$info->{shares}};
+
+  if ( ( @provides == 0 ) && ( @shares == 1 ) ) {
+    # A symbol "shared" by just a single file is actually being
+    # provided by that file; it just doesn't have an initialiser.
+    @provides = @shares;
+    @shares = ();
+  }
+
+  if ( ( @requires > 0 ) && ( @provides == 0 ) && ( @shares == 0 ) ) {
+    # No object provides this symbol, but some objects require it.
+    $problems->{$_}->{nonexistent}->{$symbol} = 1 foreach @requires;
+  }
+
+  if ( ( @requires == 0 ) && ( @provides > 0 ) ) {
+    # No object requires this symbol, but some objects provide it.
+    foreach my $provide ( @provides ) {
+      if ( $provide eq "LINKER" ) {
+	# Linker-provided symbols are exempt from this check.
+      } elsif ( $symtab->{$provide}->{$symbol}->{section} =~ /^\.tbl\./ ) {
+	# Linker tables are exempt from this check.
+      } else {
+	$problems->{$provide}->{unused}->{$symbol} = 1;
+      }
+    }
+  }
+
+  if ( ( @shares > 0 ) && ( @provides > 0 ) ) {
+    # A shared symbol is being initialised by an object
+    $problems->{$_}->{shared}->{$symbol} = 1 foreach @provides;
+  }
+
+  if ( @provides > 1 ) {
+    # A non-shared symbol is defined in multiple objects
+    $problems->{$_}->{multiples}->{$symbol} = 1 foreach @provides;
+  }
+}
+
+# Check for excessively large local symbols.  Text and rodata symbols
+# are exempt from this check
+#
+while ( ( my $object, my $symbols ) = each %$symtab ) {
+  while ( ( my $symbol, my $info ) = each %$symbols ) {
+    if ( ( ! $info->{global} ) &&
+	 ( ( defined $info->{section} ) &&
+	   ! ( $info->{section} =~ /^(\.text|\.rodata)/ ) ) &&
+	 ( $info->{size} >= WARNING_SIZE ) ) {
+      $problems->{$object}->{large}->{$symbol} = 1;
+    }
+  }
+}
+
+# Print out error messages
+#
+my $errors = 0;
+my $warnings = 0;
+foreach my $object ( sort keys %$problems ) {
+  my @nonexistent = sort keys %{$problems->{$object}->{nonexistent}};
+  my @multiples = sort keys %{$problems->{$object}->{multiples}};
+  my @unused = sort keys %{$problems->{$object}->{unused}};
+  my @shared = sort keys %{$problems->{$object}->{shared}};
+  my @large = sort keys %{$problems->{$object}->{large}};
+
+  print "WARN $object provides unused symbol $_\n" foreach @unused;
+  $warnings += @unused;
+  print "WARN $object has large static symbol $_\n" foreach @large;
+  $warnings += @large;
+  print "ERR  $object requires non-existent symbol $_\n" foreach @nonexistent;
+  $errors += @nonexistent;
+  foreach my $symbol ( @multiples ) {
+    my @other_objects = sort grep { $_ ne $object }
+		        keys %{$globals->{$symbol}->{provides}};
+    print "ERR  $object provides symbol $symbol"
+	." (also provided by @other_objects)\n";
+  }
+  $errors += @multiples;
+  print "ERR  $object misuses shared symbol $_\n" foreach @shared;
+}
+
+print "$errors error(s), $warnings warning(s)\n";
+exit ( $errors ? 1 : 0 );
diff --git a/qemu-0.15.x/roms/ipxe/src/util/zbin.c b/qemu-0.15.x/roms/ipxe/src/util/zbin.c
new file mode 100644
index 0000000..f0df5ea
--- /dev/null
+++ b/qemu-0.15.x/roms/ipxe/src/util/zbin.c
@@ -0,0 +1,434 @@
+#include <stdio.h>
+#include <sys/stat.h>
+
+#define ENCODE
+#define VERBOSE
+#include "nrv2b.c"
+FILE *infile, *outfile;
+
+#define DEBUG 0
+
+struct input_file {
+	void *buf;
+	size_t len;
+};
+
+struct output_file {
+	void *buf;
+	size_t len;
+	size_t hdr_len;
+	size_t max_len;
+};
+
+struct zinfo_common {
+	char type[4];
+	char pad[12];
+};
+
+struct zinfo_copy {
+	char type[4];
+	uint32_t offset;
+	uint32_t len;
+	uint32_t align;
+};
+
+struct zinfo_pack {
+	char type[4];
+	uint32_t offset;
+	uint32_t len;
+	uint32_t align;
+};
+
+struct zinfo_payload {
+	char type[4];
+	uint32_t pad1;
+	uint32_t pad2;
+	uint32_t align;
+};
+
+struct zinfo_add {
+	char type[4];
+	uint32_t offset;
+	uint32_t divisor;
+	uint32_t pad;
+};
+
+union zinfo_record {
+	struct zinfo_common common;
+	struct zinfo_copy copy;
+	struct zinfo_pack pack;
+	struct zinfo_payload payload;
+	struct zinfo_add add;
+};
+
+struct zinfo_file {
+	union zinfo_record *zinfo;
+	unsigned int num_entries;
+};
+
+static unsigned long align ( unsigned long value, unsigned long align ) {
+	return ( ( value + align - 1 ) & ~( align - 1 ) );
+}
+
+static int read_file ( const char *filename, void **buf, size_t *len ) {
+	FILE *file;
+	struct stat stat;
+
+	file = fopen ( filename, "r" );
+	if ( ! file ) {
+		fprintf ( stderr, "Could not open %s: %s\n", filename,
+			  strerror ( errno ) );
+		goto err;
+	}
+
+	if ( fstat ( fileno ( file ), &stat ) < 0 ) {
+		fprintf ( stderr, "Could not stat %s: %s\n", filename,
+			  strerror ( errno ) );
+		goto err;
+	}
+
+	*len = stat.st_size;
+	*buf = malloc ( *len );
+	if ( ! *buf ) {
+		fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
+			  *len, filename, strerror ( errno ) );
+		goto err;
+	}
+
+	if ( fread ( *buf, 1, *len, file ) != *len ) {
+		fprintf ( stderr, "Could not read %zd bytes from %s: %s\n",
+			  *len, filename, strerror ( errno ) );
+		goto err;
+	}
+
+	fclose ( file );
+	return 0;
+
+ err:
+	if ( file )
+		fclose ( file );
+	return -1;
+}
+
+static int read_input_file ( const char *filename,
+			     struct input_file *input ) {
+	return read_file ( filename, &input->buf, &input->len );
+}
+
+static int read_zinfo_file ( const char *filename,
+			     struct zinfo_file *zinfo ) {
+	void *buf;
+	size_t len;
+
+	if ( read_file ( filename, &buf, &len ) < 0 )
+		return -1;
+
+	if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
+		fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
+			  filename, len );
+		return -1;
+	}
+
+	zinfo->zinfo = buf;
+	zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
+	return 0;
+}
+
+static int alloc_output_file ( size_t max_len, struct output_file *output ) {
+	output->len = 0;
+	output->max_len = ( max_len );
+	output->buf = malloc ( max_len );
+	if ( ! output->buf ) {
+		fprintf ( stderr, "Could not allocate %zd bytes for output\n",
+			  max_len );
+		return -1;
+	}
+	memset ( output->buf, 0xff, sizeof ( output->buf ) );
+	return 0;
+}
+
+static int process_zinfo_copy ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	struct zinfo_copy *copy = &zinfo->copy;
+	size_t offset = copy->offset;
+	size_t len = copy->len;
+
+	if ( ( offset + len ) > input->len ) {
+		fprintf ( stderr, "Input buffer overrun on copy\n" );
+		return -1;
+	}
+
+	output->len = align ( output->len, copy->align );
+	if ( ( output->len + len ) > output->max_len ) {
+		fprintf ( stderr, "Output buffer overrun on copy\n" );
+		return -1;
+	}
+
+	if ( DEBUG ) {
+		fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
+			  offset, ( offset + len ), output->len,
+			  ( output->len + len ) );
+	}
+
+	memcpy ( ( output->buf + output->len ),
+		 ( input->buf + offset ), len );
+	output->len += len;
+	return 0;
+}
+
+static int process_zinfo_pack ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	struct zinfo_pack *pack = &zinfo->pack;
+	size_t offset = pack->offset;
+	size_t len = pack->len;
+	unsigned long packed_len;
+
+	if ( ( offset + len ) > input->len ) {
+		fprintf ( stderr, "Input buffer overrun on pack\n" );
+		return -1;
+	}
+
+	output->len = align ( output->len, pack->align );
+	if ( output->len > output->max_len ) {
+		fprintf ( stderr, "Output buffer overrun on pack\n" );
+		return -1;
+	}
+
+	if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
+				     ( output->buf + output->len ),
+				     &packed_len, 0 ) != UCL_E_OK ) {
+		fprintf ( stderr, "Compression failure\n" );
+		return -1;
+	}
+
+	if ( DEBUG ) {
+		fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
+			  offset, ( offset + len ), output->len,
+			  ( size_t )( output->len + packed_len ) );
+	}
+
+	output->len += packed_len;
+	if ( output->len > output->max_len ) {
+		fprintf ( stderr, "Output buffer overrun on pack\n" );
+		return -1;
+	}
+
+	return 0;
+}
+
+static int process_zinfo_payl ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	struct zinfo_payload *payload = &zinfo->payload;
+
+	output->len = align ( output->len, payload->align );
+	output->hdr_len = output->len;
+
+	if ( DEBUG ) {
+		fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
+	}
+}
+
+static int process_zinfo_add ( struct input_file *input,
+			       struct output_file *output,
+			       size_t len,
+			       struct zinfo_add *add,
+			       size_t datasize ) {
+	size_t offset = add->offset;
+	void *target;
+	signed long addend;
+	unsigned long size;
+	signed long val;
+	unsigned long mask;
+
+	if ( ( offset + datasize ) > output->len ) {
+		fprintf ( stderr, "Add at %#zx outside output buffer\n",
+			  offset );
+		return -1;
+	}
+
+	target = ( output->buf + offset );
+	size = ( align ( len, add->divisor ) / add->divisor );
+
+	switch ( datasize ) {
+	case 1:
+		addend = *( ( int8_t * ) target );
+		break;
+	case 2:
+		addend = *( ( int16_t * ) target );
+		break;
+	case 4:
+		addend = *( ( int32_t * ) target );
+		break;
+	default:
+		fprintf ( stderr, "Unsupported add datasize %zd\n",
+			  datasize );
+		return -1;
+	}
+
+	val = size + addend;
+
+	/* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
+	mask = ( ( datasize < sizeof ( mask ) ) ?
+		 ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
+
+	if ( val < 0 ) {
+		fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
+			  ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
+			  offset, ( ( addend < 0 ) ? "under" : "over" ) );
+		return -1;
+	}
+
+	if ( val & ~mask ) {
+		fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
+			  "field (%d bytes too big)\n",
+			  ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
+			  offset, datasize,
+			  ( int )( ( val - mask - 1 ) * add->divisor ) );
+		return -1;
+	}
+
+	switch ( datasize ) {
+	case 1:
+		*( ( uint8_t * ) target ) = val;
+		break;
+	case 2:
+		*( ( uint16_t * ) target ) = val;
+		break;
+	case 4:
+		*( ( uint32_t * ) target ) = val;
+		break;
+	}
+
+	if ( DEBUG ) {
+		fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
+			  "%#lx\n", offset, ( offset + datasize ),
+			  ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
+			  len, add->divisor, val );
+	}
+
+	return 0;
+}
+
+static int process_zinfo_addb ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->len,
+				   &zinfo->add, 1 );
+}
+
+static int process_zinfo_addw ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->len,
+				   &zinfo->add, 2 );
+}
+
+static int process_zinfo_addl ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->len,
+				   &zinfo->add, 4 );
+}
+
+static int process_zinfo_adhb ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->hdr_len,
+				   &zinfo->add, 1 );
+}
+
+static int process_zinfo_adhw ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->hdr_len,
+				   &zinfo->add, 2 );
+}
+
+static int process_zinfo_adhl ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output, output->hdr_len,
+				   &zinfo->add, 4 );
+}
+
+struct zinfo_processor {
+	char *type;
+	int ( * process ) ( struct input_file *input,
+			    struct output_file *output,
+			    union zinfo_record *zinfo );
+};
+
+static struct zinfo_processor zinfo_processors[] = {
+	{ "COPY", process_zinfo_copy },
+	{ "PACK", process_zinfo_pack },
+	{ "PAYL", process_zinfo_payl },
+	{ "ADDB", process_zinfo_addb },
+	{ "ADDW", process_zinfo_addw },
+	{ "ADDL", process_zinfo_addl },
+	{ "ADHB", process_zinfo_adhb },
+	{ "ADHW", process_zinfo_adhw },
+	{ "ADHL", process_zinfo_adhl },
+};
+
+static int process_zinfo ( struct input_file *input,
+			   struct output_file *output,
+			   union zinfo_record *zinfo ) {
+	struct zinfo_common *common = &zinfo->common;
+	struct zinfo_processor *processor;
+	char type[ sizeof ( common->type ) + 1 ] = "";
+	unsigned int i;
+
+	strncat ( type, common->type, sizeof ( type ) - 1 );
+	for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
+			    sizeof ( zinfo_processors[0] ) ) ; i++ ) {
+		processor = &zinfo_processors[i];
+		if ( strcmp ( processor->type, type ) == 0 )
+			return processor->process ( input, output, zinfo );
+	}
+
+	fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
+	return -1;
+}
+
+static int write_output_file ( struct output_file *output ) {
+	if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
+		fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
+			  output->len, strerror ( errno ) );
+		return -1;
+	}
+	return 0;
+}
+
+int main ( int argc, char **argv ) {
+	struct input_file input;
+	struct output_file output;
+	struct zinfo_file zinfo;
+	unsigned int i;
+
+	if ( argc != 3 ) {
+		fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
+			  "> file.zbin\n", argv[0] );
+		exit ( 1 );
+	}
+
+	if ( read_input_file ( argv[1], &input ) < 0 )
+		exit ( 1 );
+	if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
+		exit ( 1 );
+	if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
+		exit ( 1 );
+
+	for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
+		if ( process_zinfo ( &input, &output,
+				     &zinfo.zinfo[i] ) < 0 )
+			exit ( 1 );
+	}
+
+	if ( write_output_file ( &output ) < 0 )
+		exit ( 1 );
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/.gitignore b/qemu-0.15.x/roms/seabios/.gitignore
new file mode 100644
index 0000000..f9990fe
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/.gitignore
@@ -0,0 +1,4 @@
+out
+*.pyc
+.config
+.config.old
diff --git a/qemu-0.15.x/roms/seabios/COPYING b/qemu-0.15.x/roms/seabios/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/qemu-0.15.x/roms/seabios/COPYING.LESSER b/qemu-0.15.x/roms/seabios/COPYING.LESSER
new file mode 100644
index 0000000..fc8a5de
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/COPYING.LESSER
@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/qemu-0.15.x/roms/seabios/Makefile b/qemu-0.15.x/roms/seabios/Makefile
new file mode 100644
index 0000000..9affb39
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/Makefile
@@ -0,0 +1,230 @@
+# SeaBIOS build system
+#
+# Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU LGPLv3 license.
+
+# Program version
+VERSION=pre-0.6.3-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname)
+
+# Output directory
+OUT=out/
+
+# Source files
+SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \
+        kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
+        pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
+        usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
+        virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c
+SRC16=$(SRCBOTH) system.c disk.c font.c
+SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
+      acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
+      lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c dev-i440fx.c \
+      pci_region.c
+SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
+              /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+# Default compiler flags
+COMMONCFLAGS = -I$(OUT) -Os -MD \
+               -Wall -Wno-strict-aliasing -Wold-style-definition \
+               $(call cc-option,$(CC),-Wtype-limits,) \
+               -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \
+               -mrtd -minline-all-stringops \
+               -freg-struct-return -ffreestanding -fomit-frame-pointer \
+               -fno-delete-null-pointer-checks \
+               -ffunction-sections -fdata-sections -fno-common
+COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+
+CFLAGS32FLAT = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0
+CFLAGSSEG = $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \
+            $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \
+            $(call cc-option,$(CC),-fno-tree-switch-conversion,)
+CFLAGS32SEG = $(CFLAGSSEG) -DMODE16=0 -g
+CFLAGS16INC = $(CFLAGSSEG) -DMODE16=1 \
+              $(call cc-option,$(CC),--param large-stack-frame=4,-fno-inline)
+CFLAGS16 = $(CFLAGS16INC) -g
+
+all: $(OUT) $(OUT)bios.bin
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+MAKEFLAGS += --no-print-directory
+endif
+
+OBJCOPY=objcopy
+OBJDUMP=objdump
+STRIP=strip
+
+.PHONY : all clean distclean FORCE
+
+vpath %.c src vgasrc
+vpath %.S src vgasrc
+
+################ Build rules
+
+# Verify the gcc configuration and test if -fwhole-program works.
+TESTGCC:=$(shell CC="$(CC)" tools/test-gcc.sh)
+ifeq "$(TESTGCC)" "-1"
+$(error "Please upgrade GCC")
+endif
+
+ifndef COMPSTRAT
+COMPSTRAT=$(TESTGCC)
+endif
+
+# Do a whole file compile - three methods are supported.
+ifeq "$(COMPSTRAT)" "1"
+# First method - use -fwhole-program without -combine.
+define whole-compile
+ at echo "  Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3
+endef
+else
+ifeq "$(COMPSTRAT)" "2"
+# Second menthod - don't use -fwhole-program at all.
+define whole-compile
+ at echo "  Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -c $3.tmp.c -o $3
+endef
+else
+# Third (and preferred) method - use -fwhole-program with -combine
+define whole-compile
+ at echo "  Compiling whole program $3"
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3
+endef
+endif
+endif
+
+%.strip.o: %.o
+	@echo "  Stripping $@"
+	$(Q)$(STRIP) $< -o $@
+
+$(OUT)%.s: %.c
+	@echo "  Compiling to assembler $@"
+	$(Q)$(CC) $(CFLAGS16INC) -S -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+	@echo "  Precompiling $@"
+	$(Q)$(CPP) -P -D__ASSEMBLY__ $< -o $@
+
+$(OUT)asm-offsets.s: $(OUT)autoconf.h
+
+$(OUT)asm-offsets.h: $(OUT)asm-offsets.s
+	@echo "  Generating offset file $@"
+	$(Q)./tools/gen-offsets.sh $< $@
+
+
+$(OUT)ccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
+
+$(OUT)code32seg.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@)
+
+$(OUT)ccode32flat.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@)
+
+$(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
+	@echo "  Compiling (16bit) $@"
+	$(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
+
+$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)code16.o tools/layoutrom.py
+	@echo "  Building ld scripts (version \"$(VERSION)\")"
+	$(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c
+	$(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
+	$(Q)$(LD) -melf_i386 -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o
+	$(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump
+	$(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump
+	$(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
+	$(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
+
+# These are actually built by tools/layoutrom.py above, but by pulling them
+# into an extra rule we prevent make -j from spawning layoutrom.py 4 times.
+$(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o: $(OUT)romlayout16.lds
+
+$(OUT)rom16.o: $(OUT)code16.o $(OUT)romlayout16.lds
+	@echo "  Linking $@"
+	$(Q)$(LD) -T $(OUT)romlayout16.lds $< -o $@
+
+$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
+	@echo "  Linking $@"
+	$(Q)$(LD) -T $(OUT)romlayout32seg.lds $< -o $@
+
+$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds
+	@echo "  Linking $@"
+	$(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
+
+$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
+	@echo "  Prepping $@"
+	$(Q)$(OBJDUMP) -thr $< > $<.objdump
+	$(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+	$(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin
+	$(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf
+
+
+################ VGA build rules
+
+# VGA src files
+SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \
+       vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c
+
+$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
+
+$(OUT)vgalayout16.o: vgaentry.S $(OUT)vgaccode.16.s $(OUT)asm-offsets.h
+	@echo "  Compiling (16bit) $@"
+	$(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ -Isrc $< -o $@
+
+$(OUT)vgarom.o: $(OUT)vgalayout16.o $(OUT)vgalayout.lds
+	@echo "  Linking $@"
+	$(Q)$(LD) --gc-sections -T $(OUT)vgalayout.lds $(OUT)vgalayout16.o -o $@
+
+$(OUT)vgabios.bin.raw: $(OUT)vgarom.o
+	@echo "  Extracting binary $@"
+	$(Q)$(OBJCOPY) -O binary $< $@
+
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py
+	@echo "  Finalizing rom $@"
+	$(Q)./tools/buildrom.py $< $@
+
+####### dsdt build rules
+src/%.hex: src/%.dsl
+	@echo "Compiling DSDT"
+	$(Q)cpp -P $< > $(OUT)$*.dsl.i
+	$(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i
+	$(Q)cp $(OUT)$*.hex $@
+
+$(OUT)ccode32flat.o: src/acpi-dsdt.hex
+
+####### Kconfig rules
+export HOSTCC             := $(CC)
+export CONFIG_SHELL       := sh
+export KCONFIG_AUTOHEADER := autoconf.h
+export KCONFIG_CONFIG     := $(CURDIR)/.config
+
+$(OUT)autoconf.h : $(KCONFIG_CONFIG)
+	$(Q)$(MAKE) silentoldconfig
+
+$(KCONFIG_CONFIG):
+	$(Q)$(MAKE) defconfig
+
+%onfig:
+	$(Q)mkdir -p $(OUT)/tools/kconfig/lxdialog
+	$(Q)mkdir -p $(OUT)/include/config
+	$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/tools/kconfig/Makefile srctree=$(CURDIR) src=tools/kconfig obj=tools/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $@
+
+####### Generic rules
+clean:
+	$(Q)rm -rf $(OUT)
+
+distclean: clean
+	$(Q)rm -f .config .config.old
+
+$(OUT):
+	$(Q)mkdir $@
+
+-include $(OUT)*.d
diff --git a/qemu-0.15.x/roms/seabios/README b/qemu-0.15.x/roms/seabios/README
new file mode 100644
index 0000000..8f1bd20
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/README
@@ -0,0 +1,190 @@
+This code implements an X86 legacy bios.  It is intended to be
+compiled using standard gnu tools (eg, gas and gcc).
+
+To build, one should be able to run "make" in the main directory.  The
+resulting file "out/bios.bin" contains the processed bios image.
+
+
+Testing of images:
+
+To test the bios under bochs, one will need to instruct bochs to use
+the new bios image.  Use the 'romimage' option - for example:
+
+bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'
+
+To test under qemu, one will need to create a directory with all the
+bios images and then overwrite the main bios image.  For example:
+
+cp /usr/share/qemu/*.bin mybiosdir/
+cp out/bios.bin mybiosdir/
+
+Once this is setup, one can instruct qemu to use the newly created
+directory for rom images.  For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img
+
+
+The following payloads have been tested:
+
+Freedos - see http://www.freedos.org/ .  Useful tests include: booting
+from installation cdrom, installing to hard drive and floppy, making
+sure hard drive and floppy boots then work.  It is also useful to take
+the bootable floppy and hard-drive images, write them to an el-torito
+bootable cdrom using the Linux mkisofs utility, and then boot those
+cdrom images.
+
+Linux - useful hard drive image available from
+http://fabrice.bellard.free.fr/qemu/linux-0.2.img.bz2 .  It is also
+useful to test standard distribution bootup and live cdroms.
+
+NetBSD - useful hard drive image available from
+http://nopid.free.fr/small.ffs.bz2 .  It is also useful to test
+standard distribution installation cdroms.
+
+
+Overview of files:
+
+The src/ directory contains the bios source code.  Several of the
+files are compiled twice - once for 16bit mode and once for 32bit
+mode.  (The build system will remove code that is not needed for a
+particular mode.)
+
+The tools/ directory contains helper utilities for manipulating and
+building the final rom.
+
+The out/ directory is created by the build process - it contains all
+temporary and final files.
+
+
+Build overview:
+
+The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
+The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
+options are used to optimize the process so that gcc can efficiently
+compile and discard unneeded code.  (In the code, one can use the
+macros 'VISIBLE16' and 'VISIBLE32' to instruct a symbol to be
+outputted in 16bit and 32bit mode respectively.)
+
+This resulting assembler code is pulled into romlayout.S.  The gas
+option ".code16gcc" is used prior to including the gcc generated
+assembler - this option enables gcc to generate valid 16 bit code.
+
+The post code (post.c) is entered, via the function _start(), in 32bit
+mode.  The 16bit post vector (in romlayout.S) transitions the cpu into
+32 bit mode before calling the post.c code.
+
+In the last step of compilation, the 32 bit code is merged into the 16
+bit code so that one binary file contains both.  Currently, both 16bit
+and 32bit code will be located in the 64K block at segment 0xf000.
+
+
+GCC 16 bit limitations:
+
+Although the 16bit code is compiled with gcc, developers need to be
+aware of the environment.  In particular, global variables _must_ be
+treated specially.
+
+The code has full access to stack variables and general purpose
+registers.  The entry code in romlayout.S will push the original
+registers on the stack before calling the C code and then pop them off
+(including any required changes) before returning from the interrupt.
+Changes to CS, DS, and ES segment registers in C code is also safe.
+Changes to other segment registers (SS, FS, GS) need to be restored
+manually.
+
+Stack variables (and pointers to stack variables) work as they
+normally do in standard C code.
+
+However, variables stored outside the stack need to be accessed via
+the GET_VAR and SET_VAR macros (or one of the helper macros described
+below).  This is due to the 16bit segment nature of the X86 cpu when
+it is in "real mode".  The C entry code will set DS and SS to point to
+the stack segment.  Variables not on the stack need to be accessed via
+an explicit segment register.  Any other access requires altering one
+of the other segment registers (usually ES) and then accessing the
+variable via that segment register.
+
+There are three low-level ways to access a remote variable:
+GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR.  The first set takes
+an explicit segment descriptor (eg, "CS") and offset.  The second set
+will take a segment id and offset, set ES to the segment id, and then
+make the access via the ES segment.  The last method is similar to the
+second, except it takes a pointer that would be valid in 32-bit flat
+mode instead of a segment/offset pair.
+
+Most BIOS variables are stored in global variables, the "BDA", or
+"EBDA" memory areas.  Because this is common, three sets of helper
+macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
+to simplify these accesses.
+
+Global variables defined in the C code can be read in 16bit mode if
+the variable declaration is marked with VAR16, VAR16VISIBLE,
+VAR16EXPORT, or VAR16FIXED.  The GET_GLOBAL macro will then allow read
+access to the variable.  Global variables are stored in the 0xf000
+segment, and their values are persistent across soft resets.  Because
+the f-segment is marked read-only during run-time, the 16bit code is
+not permitted to change the value of 16bit variables (use of the
+SET_GLOBAL macro from 16bit mode will cause a link error).  Code
+running in 32bit mode can not access variables with VAR16, but can
+access variables marked with VAR16VISIBLE, VAR16EXPORT, VAR16FIXED, or
+with no marking at all.  The 32bit code can use the GET/SET_GLOBAL
+macros, but they are not required.
+
+
+GCC 16 bit stack limitations:
+
+Another limitation of gcc is its use of 32-bit temporaries.  Gcc will
+allocate 32-bits of space for every variable - even if that variable
+is only defined as a 'u8' or 'u16'.  If one is not careful, using too
+much stack space can break old DOS applications.
+
+There does not appear to be explicit documentation on the minimum
+stack space available for bios calls.  However, Freedos has been
+observed to call into the bios with less than 150 bytes available.
+
+Note that the post code and boot code (irq 18/19) do not have a stack
+limitation because the entry points for these functions transition the
+cpu to 32bit mode and reset the stack to a known state.  Only the
+general purpose 16-bit service entry points are affected.
+
+There are some ways to reduce stack usage: making sure functions are
+tail-recursive often helps, reducing the number of parameters passed
+to functions often helps, sometimes reordering variable declarations
+helps, inlining of functions can sometimes help, and passing of packed
+structures can also help.  It is also possible to transition to/from
+an extra stack stored in the EBDA using the stack_hop helper function.
+
+Some useful stats: the overhead for the entry to a bios handler that
+takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
+interrupt insn, 32 bytes to store registers, and 4 bytes for call
+insn).  An entry to an ISR handler without args takes 30 bytes (6 + 20
++ 4).
+
+
+Debugging the bios:
+
+The bios will output information messages to a special debug port.
+Under qemu, one can view these messages by enabling the '#define
+DEBUG_BIOS' definition in 'qemu/hw/pc.c'.  Once this is done (and qemu
+is recompiled), one should see status messages on the console.
+
+The gdb-server mechanism of qemu is also useful.  One can use gdb with
+qemu to debug system images.  To use this, add '-s -S' to the qemu
+command line.  For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img -s -S
+
+Then, in another session, run gdb with either out/rom16.o (to debug
+bios 16bit code) or out/rom32.o (to debug bios 32bit code).  For
+example:
+
+gdb out/rom16.o
+
+Once in gdb, use the command "target remote localhost:1234" to have
+gdb connect to qemu.  See the qemu documentation for more information
+on using gdb and qemu in this mode.  Note that gdb seems to get
+breakpoints confused when the cpu is in 16-bit real mode.  This makes
+stepping through the program difficult (though 'step instruction'
+still works).  Also, one may need to set 16bit break points at both
+the cpu address and memory address (eg, break *0x1234 ; break
+*0xf1234).
diff --git a/qemu-0.15.x/roms/seabios/TODO b/qemu-0.15.x/roms/seabios/TODO
new file mode 100644
index 0000000..d49aeb8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/TODO
@@ -0,0 +1,29 @@
+If POST is rerun, try to do a machine reboot.
+
+Review changes committed to coreboot, virtualbox, qemu, kvm, and bochs
+cvs tip.
+  * bochs cvs (20100104):
+    -- changes synched
+  * coreboot (r3348):    (bochs 20060708)
+    -- no noteworthy enhancements
+  * qemu - now uses SeaBIOS
+  * kvm - now uses SeaBIOS
+  * virtualbox (r13560): (bochs 20061231)
+    -- lots of mouse changes, logo, scsi/etherboot hooks,
+       floppy data rate?, int19 calls post
+
+Possibly move code from entry_post in romlayout.S to C code in
+handle_resume and always call 16bit C code on post.
+
+The __call16 code does a long jump to the interrupt trampolines - this
+is unnecessary.
+
+Support PCIv3 roms?  Add support for PCI "configuration code"
+extensions?
+
+Possibly add option to eliminate tsc based delays on emulators.
+
+Add a kconfig style configuration program instead of requiring users
+to modify config.h.
+
+Possibly support sending debug information over EHCI debug port.
diff --git a/qemu-0.15.x/roms/seabios/src/Kconfig b/qemu-0.15.x/roms/seabios/src/Kconfig
new file mode 100644
index 0000000..6d55b23
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/Kconfig
@@ -0,0 +1,370 @@
+# Kconfig SeaBIOS configuration
+
+mainmenu "SeaBIOS Configuration"
+
+menu "General Features"
+
+    config COREBOOT
+        bool "Build for coreboot"
+        default n
+        help
+            Configure as a coreboot payload.
+
+    config THREADS
+        bool "Parallelize hardware init"
+        default y
+        help
+            Support running hardware initialization in parallel.
+    config THREAD_OPTIONROMS
+        depends on THREADS
+        bool "Hardware init during option ROM execution"
+        default n
+        help
+            Allow hardware init to run in parallel with optionrom execution.
+
+    config RELOCATE_INIT
+        bool "Copy init code to high memory"
+        default y
+        help
+            Support relocating the one time initialization code to high memory.
+
+    config BOOTMENU
+        depends on BOOT
+        bool "Bootmenu"
+        default y
+        help
+            Support an interactive boot menu at end of post.
+    config BOOTMENU_WAIT
+        depends on BOOTMENU
+        int "Bootmenu delay"
+        default 2500
+        help
+            Amount of time (in ms) to wait at menu before selecting normal boot.
+    config BOOTSPLASH
+        depends on BOOTMENU
+        bool "Graphical boot splash screen"
+        default y
+        help
+            Support showing a graphical boot splash screen.
+
+    config COREBOOT_FLASH
+        depends on COREBOOT
+        bool "coreboot CBFS support"
+        default y
+        help
+            Support searching coreboot flash format.
+    config LZMA
+        depends on COREBOOT_FLASH
+        bool "CBFS lzma support"
+        default y
+        help
+            Support CBFS files compressed using the lzma decompression
+            algorighm.
+    config FLASH_FLOPPY
+        depends on COREBOOT_FLASH
+        bool "Floppy images in CBFS"
+        default y
+        help
+            Support floppy images in coreboot flash.
+
+endmenu
+
+menu "Hardware support"
+    config ATA
+        depends on DRIVES
+        bool "ATA controllers"
+        default y
+        help
+            Support for IDE disk code.
+    config ATA_DMA
+        depends on ATA
+        bool "ATA DMA"
+        default n
+        help
+            Detect and try to use ATA bus mastering DMA controllers.
+    config ATA_PIO32
+        depends on ATA
+        bool "ATA 32bit PIO"
+        default n
+        help
+            Use 32bit PIO accesses on ATA (minor optimization on PCI transfers).
+    config AHCI
+        depends on DRIVES
+        bool "AHCI controllers"
+        default n
+        help
+            Support for AHCI disk code.
+    config VIRTIO_BLK
+        depends on DRIVES && !COREBOOT
+        bool "VirtIO controllers"
+        default y
+        help
+            Support boot from virtio storage.
+    config FLOPPY
+        depends on DRIVES
+        bool "Floppy controller"
+        default y
+        help
+            Support floppy drive access.
+
+    config PS2PORT
+        depends on KEYBOARD || MOUSE
+        bool "PS/2 port"
+        default y
+        help
+            Support PS2 ports (keyboard and mouse).
+
+    config USB
+        bool "USB"
+        default y
+        help
+            Support USB devices.
+    config USB_UHCI
+        depends on USB
+        bool "USB UHCI controllers"
+        default y
+        help
+            Support USB UHCI controllers.
+    config USB_OHCI
+        depends on USB
+        bool "USB OHCI controllers"
+        default y
+        help
+            Support USB OHCI controllers.
+    config USB_EHCI
+        depends on USB
+        bool "USB EHCI controllers"
+        default y
+        help
+            Support USB EHCI controllers.
+    config USB_MSC
+        depends on USB && DRIVES
+        bool "USB drives"
+        default y
+        help
+            Support USB disks.
+    config USB_HUB
+        depends on USB
+        bool "USB hubs"
+        default y
+        help
+            Support USB hubs.
+    config USB_KEYBOARD
+        depends on USB && KEYBOARD
+        bool "USB keyboards"
+        default y
+        help
+            Support USB keyboards.
+    config USB_MOUSE
+        depends on USB && MOUSE
+        bool "USB mice"
+        default y
+        help
+            Support USB mice.
+
+    config SERIAL
+        bool "Serial port"
+        default y
+        help
+            Support serial ports.  This also enables int 14 serial port calls.
+    config LPT
+        bool "Parallel port"
+        default y
+        help
+            Support parallel ports. This also enables int 17 parallel port calls.
+
+    config EXTRA_PCI_ROOTS
+        bool "Extra root buses"
+        default n
+        help
+            If the target machine has multiple independent root buses,
+            the extra buses may be specified here.
+    config PCI_ROOT1
+        depends on EXTRA_PCI_ROOTS
+        hex "Extra primary PCI root bus number"
+        default 0x00
+    config PCI_ROOT2
+        depends on EXTRA_PCI_ROOTS
+        hex "Extra secondary PCI root bus number"
+        default 0x00
+
+    config USE_SMM
+        depends on !COREBOOT
+        bool "System Management Mode (SMM)"
+        default y
+        help
+            Support System Management Mode (on emulators).
+    config MTRR_INIT
+        depends on !COREBOOT
+        bool "Initialize MTRRs"
+        default y
+        help
+            Initialize the Memory Type Range Registers (on emulators).
+endmenu
+
+menu "BIOS interfaces"
+    config DRIVES
+        bool "Drive interface"
+        default y
+        help
+            Support int13 disk/floppy drive functions.
+
+    config CDROM_BOOT
+        depends on DRIVES
+        bool "DVD/CDROM booting"
+        default y
+        help
+            Support for booting from a CD.  (El Torito spec support.)
+    config CDROM_EMU
+        depends on CDROM_BOOT
+        bool "DVD/CDROM boot drive emulation"
+        default y
+        help
+            Support bootable CDROMs that emulate a floppy/harddrive.
+
+    config PCIBIOS
+        bool "PCIBIOS interface"
+        default y
+        help
+            Support int 1a/b1 PCI BIOS calls.
+    config APMBIOS
+        bool "APM interface"
+        default y
+        help
+            Support int 15/53 APM BIOS calls.
+    config PNPBIOS
+        bool "PnP BIOS interface"
+        default y
+        help
+            Support PnP BIOS entry point.
+    config OPTIONROMS
+        bool "Option ROMS"
+        default y
+        help
+            Support finding and running option roms during POST.
+    config OPTIONROMS_DEPLOYED
+        depends on OPTIONROMS
+        bool "Option roms are already at 0xc0000-0xf0000"
+        default n
+        help
+            Select this if option ROMs are already copied to
+            0xc0000-0xf0000.  This must only be selected when using
+            Bochs or QEMU versions older than 0.12.
+    config OPTIONROMS_CHECKSUM
+        depends on OPTIONROMS
+        bool "Require correct checksum on option ROMs"
+        default y
+        help
+            Option ROMs are required to have correct checksums.
+            However, some option ROMs in the wild don't correctly
+            follow the specifications and have bad checksums.
+            Say N here to allow SeaBIOS to execute them anyways.
+
+            If unsure, say Y.
+    config PMM
+        depends on OPTIONROMS
+        bool "PMM interface"
+        default y
+        help
+            Support Post Memory Manager (PMM) entry point.
+    config BOOT
+        bool "Boot interface"
+        default y
+        help
+            Support int 19/18 system bootup support.
+    config KEYBOARD
+        bool "Keyboard interface"
+        default y
+        help
+            Support int 16 keyboard calls.
+    config KBD_CALL_INT15_4F
+        depends on KEYBOARD
+        bool "Keyboard hook interface"
+        default y
+        help
+            Support calling int155f on each keyboard event.
+    config MOUSE
+        bool "Mouse interface"
+        default y
+        help
+            Support for int15c2 mouse calls.
+
+    config S3_RESUME
+        bool "S3 resume"
+        default y
+        help
+            Support S3 resume handler.
+    config S3_RESUME_VGA_INIT
+        depends on S3_RESUME
+        bool "Run VGA rom on S3 resume"
+        default n
+        help
+            Run the vga rom during S3 resume.
+
+    config VGAHOOKS
+        depends on COREBOOT
+        bool "Hardware specific VGA helpers"
+        default y
+        help
+            Support int 155f BIOS callbacks specific to some Intel and
+            VIA on-board vga devices.
+
+    config DISABLE_A20
+        bool "Disable A20"
+        default n
+        help
+            Disable A20 on 16bit boot.
+endmenu
+
+menu "BIOS Tables"
+    config PIRTABLE
+        depends on !COREBOOT
+        bool "PIR table"
+        default y
+        help
+            Support generation of a PIR table in 0xf000 segment.
+    config MPTABLE
+        depends on !COREBOOT
+        bool "MPTable"
+        default y
+        help
+            Support generation of MPTable.
+    config SMBIOS
+        bool "SMBIOS"
+        default y
+        help
+            Support generation of SM BIOS tables.  This is also
+            sometimes called DMI.
+    config ACPI
+        depends on !COREBOOT
+        bool "ACPI"
+        default y
+        help
+            Support generation of ACPI tables.
+endmenu
+
+menu "Debugging"
+    config DEBUG_LEVEL
+        int "Debug level"
+        default 1
+        help
+            Control how verbose debug output is.  The higher the
+            number, the more verbose SeaBIOS will be.
+
+            Set to zero to disable debugging.
+
+    config DEBUG_SERIAL
+        depends on DEBUG_LEVEL != 0
+        bool "Serial port debugging"
+        default n
+        help
+            Send debugging information to serial port.
+
+    config SCREEN_AND_DEBUG
+        depends on DEBUG_LEVEL != 0
+        bool "Show screen writes on debug ports"
+        default y
+        help
+            Send characters that SeaBIOS writes to the screen to the
+            debug ports.
+endmenu
diff --git a/qemu-0.15.x/roms/seabios/src/acpi-dsdt.dsl b/qemu-0.15.x/roms/seabios/src/acpi-dsdt.dsl
new file mode 100644
index 0000000..7e8f478
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/acpi-dsdt.dsl
@@ -0,0 +1,926 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+DefinitionBlock (
+    "acpi-dsdt.aml",    // Output Filename
+    "DSDT",             // Signature
+    0x01,               // DSDT Compliance Revision
+    "BXPC",             // OEMID
+    "BXDSDT",           // TABLE ID
+    0x1                 // OEM Revision
+    )
+{
+    Scope (\)
+    {
+        /* Debug Output */
+        OperationRegion (DBG, SystemIO, 0x0402, 0x01)
+        Field (DBG, ByteAcc, NoLock, Preserve)
+        {
+            DBGB,   8,
+        }
+
+        /* Debug method - use this method to send output to the QEMU
+         * BIOS debug port.  This method handles strings, integers,
+         * and buffers.  For example: DBUG("abc") DBUG(0x123) */
+        Method(DBUG, 1) {
+            ToHexString(Arg0, Local0)
+            ToBuffer(Local0, Local0)
+            Subtract(SizeOf(Local0), 1, Local1)
+            Store(Zero, Local2)
+            While (LLess(Local2, Local1)) {
+                Store(DerefOf(Index(Local0, Local2)), DBGB)
+                Increment(Local2)
+            }
+            Store(0x0A, DBGB)
+        }
+    }
+
+    /* PCI Bus definition */
+    Scope(\_SB) {
+        Device(PCI0) {
+            Name (_HID, EisaId ("PNP0A03"))
+            Name (_ADR, 0x00)
+            Name (_UID, 1)
+            Name(_PRT, Package() {
+                /* PCI IRQ routing table, example from ACPI 2.0a specification,
+                   section 6.2.8.1 */
+                /* Note: we provide the same info as the PCI routing
+                   table of the Bochs BIOS */
+#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
+       Package() { nr##ffff, 0, lnk0, 0 }, \
+       Package() { nr##ffff, 1, lnk1, 0 }, \
+       Package() { nr##ffff, 2, lnk2, 0 }, \
+       Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
+               prt_slot0(0x0000),
+               /* Device 1 is power mgmt device, and can only use irq 9 */
+               Package() { 0x0001ffff, 0, LNKS, 0 },
+               Package() { 0x0001ffff, 1, LNKB, 0 },
+               Package() { 0x0001ffff, 2, LNKC, 0 },
+               Package() { 0x0001ffff, 3, LNKD, 0 },
+               prt_slot2(0x0002),
+               prt_slot3(0x0003),
+               prt_slot0(0x0004),
+               prt_slot1(0x0005),
+               prt_slot2(0x0006),
+               prt_slot3(0x0007),
+               prt_slot0(0x0008),
+               prt_slot1(0x0009),
+               prt_slot2(0x000a),
+               prt_slot3(0x000b),
+               prt_slot0(0x000c),
+               prt_slot1(0x000d),
+               prt_slot2(0x000e),
+               prt_slot3(0x000f),
+               prt_slot0(0x0010),
+               prt_slot1(0x0011),
+               prt_slot2(0x0012),
+               prt_slot3(0x0013),
+               prt_slot0(0x0014),
+               prt_slot1(0x0015),
+               prt_slot2(0x0016),
+               prt_slot3(0x0017),
+               prt_slot0(0x0018),
+               prt_slot1(0x0019),
+               prt_slot2(0x001a),
+               prt_slot3(0x001b),
+               prt_slot0(0x001c),
+               prt_slot1(0x001d),
+               prt_slot2(0x001e),
+               prt_slot3(0x001f),
+            })
+
+            OperationRegion(PCST, SystemIO, 0xae00, 0x08)
+            Field (PCST, DWordAcc, NoLock, WriteAsZeros)
+            {
+                PCIU, 32,
+                PCID, 32,
+            }
+
+            OperationRegion(SEJ, SystemIO, 0xae08, 0x04)
+            Field (SEJ, DWordAcc, NoLock, WriteAsZeros)
+            {
+                B0EJ, 32,
+            }
+
+            OperationRegion(RMVC, SystemIO, 0xae0c, 0x04)
+            Field(RMVC, DWordAcc, NoLock, WriteAsZeros)
+            {
+                PCRM, 32,
+            }
+
+#define hotplug_slot(name, nr) \
+            Device (S##name) {                    \
+               Name (_ADR, nr##0000)              \
+               Method (_EJ0,1) {                  \
+                    Store(ShiftLeft(1, nr), B0EJ) \
+                    Return (0x0)                  \
+               }                                  \
+               Name (_SUN, name)                  \
+            }
+
+	    hotplug_slot(1, 0x0001)
+	    hotplug_slot(2, 0x0002)
+	    hotplug_slot(3, 0x0003)
+	    hotplug_slot(4, 0x0004)
+	    hotplug_slot(5, 0x0005)
+	    hotplug_slot(6, 0x0006)
+	    hotplug_slot(7, 0x0007)
+	    hotplug_slot(8, 0x0008)
+	    hotplug_slot(9, 0x0009)
+	    hotplug_slot(10, 0x000a)
+	    hotplug_slot(11, 0x000b)
+	    hotplug_slot(12, 0x000c)
+	    hotplug_slot(13, 0x000d)
+	    hotplug_slot(14, 0x000e)
+	    hotplug_slot(15, 0x000f)
+	    hotplug_slot(16, 0x0010)
+	    hotplug_slot(17, 0x0011)
+	    hotplug_slot(18, 0x0012)
+	    hotplug_slot(19, 0x0013)
+	    hotplug_slot(20, 0x0014)
+	    hotplug_slot(21, 0x0015)
+	    hotplug_slot(22, 0x0016)
+	    hotplug_slot(23, 0x0017)
+	    hotplug_slot(24, 0x0018)
+	    hotplug_slot(25, 0x0019)
+	    hotplug_slot(26, 0x001a)
+	    hotplug_slot(27, 0x001b)
+	    hotplug_slot(28, 0x001c)
+	    hotplug_slot(29, 0x001d)
+	    hotplug_slot(30, 0x001e)
+	    hotplug_slot(31, 0x001f)
+
+            Name (_CRS, ResourceTemplate ()
+            {
+                WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+                    0x0000,             // Address Space Granularity
+                    0x0000,             // Address Range Minimum
+                    0x00FF,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0x0100,             // Address Length
+                    ,, )
+                IO (Decode16,
+                    0x0CF8,             // Address Range Minimum
+                    0x0CF8,             // Address Range Maximum
+                    0x01,               // Address Alignment
+                    0x08,               // Address Length
+                    )
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Address Space Granularity
+                    0x0000,             // Address Range Minimum
+                    0x0CF7,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0x0CF8,             // Address Length
+                    ,, , TypeStatic)
+                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+                    0x0000,             // Address Space Granularity
+                    0x0D00,             // Address Range Minimum
+                    0xFFFF,             // Address Range Maximum
+                    0x0000,             // Address Translation Offset
+                    0xF300,             // Address Length
+                    ,, , TypeStatic)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x00000000,         // Address Space Granularity
+                    0x000A0000,         // Address Range Minimum
+                    0x000BFFFF,         // Address Range Maximum
+                    0x00000000,         // Address Translation Offset
+                    0x00020000,         // Address Length
+                    ,, , AddressRangeMemory, TypeStatic)
+                DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+                    0x00000000,         // Address Space Granularity
+                    0xE0000000,         // Address Range Minimum
+                    0xFEBFFFFF,         // Address Range Maximum
+                    0x00000000,         // Address Translation Offset
+                    0x1EC00000,         // Address Length
+                    ,, , AddressRangeMemory, TypeStatic)
+            })
+        }
+
+        Device(HPET) {
+            Name(_HID,  EISAID("PNP0103"))
+            Name(_UID, 0)
+            Method (_STA, 0, NotSerialized) {
+                    Return(0x0F)
+            }
+            Name(_CRS, ResourceTemplate() {
+                DWordMemory(
+                    ResourceConsumer, PosDecode, MinFixed, MaxFixed,
+                    NonCacheable, ReadWrite,
+                    0x00000000,
+                    0xFED00000,
+                    0xFED003FF,
+                    0x00000000,
+                    0x00000400 /* 1K memory: FED00000 - FED003FF */
+                )
+            })
+        }
+    }
+
+    Scope(\_SB.PCI0) {
+        Device (VGA) {
+                 Name (_ADR, 0x00020000)
+                 Method (_S1D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+                 Method (_S2D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+                 Method (_S3D, 0, NotSerialized)
+                 {
+                         Return (0x00)
+                 }
+                 Method(_RMV) { Return (0x00) }
+        }
+
+	/* PIIX3 ISA bridge */
+        Device (ISA) {
+            Name (_ADR, 0x00010000)
+            Method(_RMV) { Return (0x00) }
+
+
+            /* PIIX PCI to ISA irq remapping */
+            OperationRegion (P40C, PCI_Config, 0x60, 0x04)
+
+            /* Real-time clock */
+            Device (RTC)
+            {
+                Name (_HID, EisaId ("PNP0B00"))
+                Name (_CRS, ResourceTemplate ()
+                {
+                    IO (Decode16, 0x0070, 0x0070, 0x10, 0x02)
+                    IRQNoFlags () {8}
+                    IO (Decode16, 0x0072, 0x0072, 0x02, 0x06)
+                })
+            }
+
+            /* Keyboard seems to be important for WinXP install */
+            Device (KBD)
+            {
+                Name (_HID, EisaId ("PNP0303"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                     Name (TMP, ResourceTemplate ()
+                     {
+                    IO (Decode16,
+                        0x0060,             // Address Range Minimum
+                        0x0060,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IO (Decode16,
+                        0x0064,             // Address Range Minimum
+                        0x0064,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IRQNoFlags ()
+                        {1}
+                    })
+                    Return (TMP)
+                }
+            }
+
+	    /* PS/2 mouse */
+            Device (MOU)
+            {
+                Name (_HID, EisaId ("PNP0F13"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (TMP, ResourceTemplate ()
+                    {
+                         IRQNoFlags () {12}
+                    })
+                    Return (TMP)
+                }
+            }
+
+	    /* PS/2 floppy controller */
+	    Device (FDC0)
+	    {
+	        Name (_HID, EisaId ("PNP0700"))
+		Method (_STA, 0, NotSerialized)
+		{
+		    Return (0x0F)
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+                        IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+                        IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+                        IRQNoFlags () {6}
+                        DMA (Compatibility, NotBusMaster, Transfer8) {2}
+                    })
+		    Return (BUF0)
+		}
+	    }
+
+	    /* Parallel port */
+	    Device (LPT)
+	    {
+	        Name (_HID, EisaId ("PNP0400"))
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSA, Local0)
+		    And (Local0, 0x80000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+			IRQNoFlags () {7}
+		    })
+		    Return (BUF0)
+		}
+	    }
+
+	    /* Serial Ports */
+	    Device (COM1)
+	    {
+	        Name (_HID, EisaId ("PNP0501"))
+		Name (_UID, 0x01)
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSC, Local0)
+		    And (Local0, 0x08000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+                	IRQNoFlags () {4}
+		    })
+		    Return (BUF0)
+		}
+	    }
+
+	    Device (COM2)
+	    {
+	        Name (_HID, EisaId ("PNP0501"))
+		Name (_UID, 0x02)
+		Method (_STA, 0, NotSerialized)
+		{
+		    Store (\_SB.PCI0.PX13.DRSC, Local0)
+		    And (Local0, 0x80000000, Local0)
+		    If (LEqual (Local0, 0))
+		    {
+			Return (0x00)
+		    }
+		    Else
+		    {
+			Return (0x0F)
+		    }
+		}
+		Method (_CRS, 0, NotSerialized)
+		{
+		    Name (BUF0, ResourceTemplate ()
+                    {
+			IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+                	IRQNoFlags () {3}
+		    })
+		    Return (BUF0)
+		}
+	    }
+        }
+
+	/* PIIX4 PM */
+        Device (PX13) {
+	    Name (_ADR, 0x00010003)
+
+	    OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
+	    Field (P13C, DWordAcc, NoLock, Preserve)
+	    {
+		DRSA, 32,
+		DRSB, 32,
+		DRSC, 32,
+		DRSE, 32,
+		DRSF, 32,
+		DRSG, 32,
+		DRSH, 32,
+		DRSI, 32,
+		DRSJ, 32
+	    }
+	}
+
+#define gen_pci_device(name, nr)                                \
+        Device(SL##name) {                                      \
+            Name (_ADR, nr##0000)                               \
+            Method (_RMV) {                                     \
+                If (And(\_SB.PCI0.PCRM, ShiftLeft(1, nr))) {    \
+                    Return (0x1)                                \
+                }                                               \
+                Return (0x0)                                    \
+            }                                                   \
+            Name (_SUN, name)                                   \
+        }
+
+        /* VGA (slot 1) and ISA bus (slot 2) defined above */
+	gen_pci_device(3, 0x0003)
+	gen_pci_device(4, 0x0004)
+	gen_pci_device(5, 0x0005)
+	gen_pci_device(6, 0x0006)
+	gen_pci_device(7, 0x0007)
+	gen_pci_device(8, 0x0008)
+	gen_pci_device(9, 0x0009)
+	gen_pci_device(10, 0x000a)
+	gen_pci_device(11, 0x000b)
+	gen_pci_device(12, 0x000c)
+	gen_pci_device(13, 0x000d)
+	gen_pci_device(14, 0x000e)
+	gen_pci_device(15, 0x000f)
+	gen_pci_device(16, 0x0010)
+	gen_pci_device(17, 0x0011)
+	gen_pci_device(18, 0x0012)
+	gen_pci_device(19, 0x0013)
+	gen_pci_device(20, 0x0014)
+	gen_pci_device(21, 0x0015)
+	gen_pci_device(22, 0x0016)
+	gen_pci_device(23, 0x0017)
+	gen_pci_device(24, 0x0018)
+	gen_pci_device(25, 0x0019)
+	gen_pci_device(26, 0x001a)
+	gen_pci_device(27, 0x001b)
+	gen_pci_device(28, 0x001c)
+	gen_pci_device(29, 0x001d)
+	gen_pci_device(30, 0x001e)
+	gen_pci_device(31, 0x001f)
+    }
+
+    /* PCI IRQs */
+    Scope(\_SB) {
+         Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
+         {
+             PRQ0,   8,
+             PRQ1,   8,
+             PRQ2,   8,
+             PRQ3,   8
+         }
+
+        Device(LNKA){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 1)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ0, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ0, 0x80, PRQ0)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ0, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ0)
+                }
+        }
+        Device(LNKB){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 2)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ1, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ1, 0x80, PRQ1)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ1, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ1)
+                }
+        }
+        Device(LNKC){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 3)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ2, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ2, 0x80, PRQ2)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ2, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ2)
+                }
+        }
+        Device(LNKD){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 4)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ3, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ3, 0x80, PRQ3)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ3, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ3)
+                }
+        }
+        Device(LNKS){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 5)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 9 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ0, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ0, 0x80, PRQ0)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {9}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ0, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+        }
+    }
+
+    /*
+     * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+     * must match piix4 emulation.
+     */
+    Name (\_S3, Package (0x04)
+    {
+        0x01,  /* PM1a_CNT.SLP_TYP */
+        0x01,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+    Name (\_S4, Package (0x04)
+    {
+        Zero,  /* PM1a_CNT.SLP_TYP */
+        Zero,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+    Name (\_S5, Package (0x04)
+    {
+        Zero,  /* PM1a_CNT.SLP_TYP */
+        Zero,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+
+    /* CPU hotplug */
+    Scope(\_SB) {
+        /* Objects filled in by run-time generated SSDT */
+        External(NTFY, MethodObj)
+        External(CPON, PkgObj)
+
+        /* Methods called by run-time generated SSDT Processor objects */
+        Method (CPMA, 1, NotSerialized) {
+            // _MAT method - create an madt apic buffer
+            // Local0 = CPON flag for this cpu
+            Store(DerefOf(Index(CPON, Arg0)), Local0)
+            // Local1 = Buffer (in madt apic form) to return
+            Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
+            // Update the processor id, lapic id, and enable/disable status
+            Store(Arg0, Index(Local1, 2))
+            Store(Arg0, Index(Local1, 3))
+            Store(Local0, Index(Local1, 4))
+            Return (Local1)
+        }
+        Method (CPST, 1, NotSerialized) {
+            // _STA method - return ON status of cpu
+            // Local0 = CPON flag for this cpu
+            Store(DerefOf(Index(CPON, Arg0)), Local0)
+            If (Local0) { Return(0xF) } Else { Return(0x0) }
+        }
+        Method (CPEJ, 2, NotSerialized) {
+            // _EJ0 method - eject callback
+            Sleep(200)
+        }
+
+        /* CPU hotplug notify method */
+        OperationRegion(PRST, SystemIO, 0xaf00, 32)
+        Field (PRST, ByteAcc, NoLock, Preserve)
+        {
+            PRS, 256
+        }
+        Method(PRSC, 0) {
+            // Local5 = active cpu bitmap
+            Store (PRS, Local5)
+            // Local2 = last read byte from bitmap
+            Store (Zero, Local2)
+            // Local0 = cpuid iterator
+            Store (Zero, Local0)
+            While (LLess(Local0, SizeOf(CPON))) {
+                // Local1 = CPON flag for this cpu
+                Store(DerefOf(Index(CPON, Local0)), Local1)
+                If (And(Local0, 0x07)) {
+                    // Shift down previously read bitmap byte
+                    ShiftRight(Local2, 1, Local2)
+                } Else {
+                    // Read next byte from cpu bitmap
+                    Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
+                }
+                // Local3 = active state for this cpu
+                Store(And(Local2, 1), Local3)
+
+                If (LNotEqual(Local1, Local3)) {
+                    // State change - update CPON with new state
+                    Store(Local3, Index(CPON, Local0))
+                    // Do CPU notify
+                    If (LEqual(Local3, 1)) {
+                        NTFY(Local0, 1)
+                    } Else {
+                        NTFY(Local0, 3)
+                    }
+                }
+                Increment(Local0)
+            }
+            Return(One)
+        }
+    }
+
+    Scope (\_GPE)
+    {
+        Name(_HID, "ACPI0006")
+
+        Method(_L00) {
+            Return(0x01)
+        }
+
+#define gen_pci_hotplug(nr)                                       \
+            If (And(\_SB.PCI0.PCIU, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 1)                        \
+            }                                                     \
+            If (And(\_SB.PCI0.PCID, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 3)                        \
+            }
+
+        Method(_L01) {
+            gen_pci_hotplug(1)
+            gen_pci_hotplug(2)
+            gen_pci_hotplug(3)
+            gen_pci_hotplug(4)
+            gen_pci_hotplug(5)
+            gen_pci_hotplug(6)
+            gen_pci_hotplug(7)
+            gen_pci_hotplug(8)
+            gen_pci_hotplug(9)
+            gen_pci_hotplug(10)
+            gen_pci_hotplug(11)
+            gen_pci_hotplug(12)
+            gen_pci_hotplug(13)
+            gen_pci_hotplug(14)
+            gen_pci_hotplug(15)
+            gen_pci_hotplug(16)
+            gen_pci_hotplug(17)
+            gen_pci_hotplug(18)
+            gen_pci_hotplug(19)
+            gen_pci_hotplug(20)
+            gen_pci_hotplug(21)
+            gen_pci_hotplug(22)
+            gen_pci_hotplug(23)
+            gen_pci_hotplug(24)
+            gen_pci_hotplug(25)
+            gen_pci_hotplug(26)
+            gen_pci_hotplug(27)
+            gen_pci_hotplug(28)
+            gen_pci_hotplug(29)
+            gen_pci_hotplug(30)
+            gen_pci_hotplug(31)
+
+            Return (0x01)
+
+        }
+        Method(_L02) {
+            // CPU hotplug event
+            Return(\_SB.PRSC())
+        }
+        Method(_L03) {
+            Return(0x01)
+        }
+        Method(_L04) {
+            Return(0x01)
+        }
+        Method(_L05) {
+            Return(0x01)
+        }
+        Method(_L06) {
+            Return(0x01)
+        }
+        Method(_L07) {
+            Return(0x01)
+        }
+        Method(_L08) {
+            Return(0x01)
+        }
+        Method(_L09) {
+            Return(0x01)
+        }
+        Method(_L0A) {
+            Return(0x01)
+        }
+        Method(_L0B) {
+            Return(0x01)
+        }
+        Method(_L0C) {
+            Return(0x01)
+        }
+        Method(_L0D) {
+            Return(0x01)
+        }
+        Method(_L0E) {
+            Return(0x01)
+        }
+        Method(_L0F) {
+            Return(0x01)
+        }
+    }
+
+}
diff --git a/qemu-0.15.x/roms/seabios/src/acpi-dsdt.hex b/qemu-0.15.x/roms/seabios/src/acpi-dsdt.hex
new file mode 100644
index 0000000..4fbb7e9
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/acpi-dsdt.hex
@@ -0,0 +1,1212 @@
+/*
+ * 
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20100528 [Jul  1 2010]
+ * Copyright (c) 2000 - 2010 Intel Corporation
+ * Supports ACPI Specification Revision 4.0a
+ * 
+ * Compilation of "out/acpi-dsdt.dsl.i" - Wed Jan  5 21:21:12 2011
+ * 
+ * C source code output
+ * AML code block contains 0x2560 bytes
+ *
+ */
+unsigned char AmlCode[] =
+{
+    0x44,0x53,0x44,0x54,0x60,0x25,0x00,0x00,  /* 00000000    "DSDT`%.." */
+    0x01,0xF7,0x42,0x58,0x50,0x43,0x00,0x00,  /* 00000008    "..BXPC.." */
+    0x42,0x58,0x44,0x53,0x44,0x54,0x00,0x00,  /* 00000010    "BXDSDT.." */
+    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C,  /* 00000018    "....INTL" */
+    0x28,0x05,0x10,0x20,0x10,0x49,0x04,0x5C,  /* 00000020    "(.. .I.\" */
+    0x00,0x5B,0x80,0x44,0x42,0x47,0x5F,0x01,  /* 00000028    ".[.DBG_." */
+    0x0B,0x02,0x04,0x01,0x5B,0x81,0x0B,0x44,  /* 00000030    "....[..D" */
+    0x42,0x47,0x5F,0x01,0x44,0x42,0x47,0x42,  /* 00000038    "BG_.DBGB" */
+    0x08,0x14,0x2C,0x44,0x42,0x55,0x47,0x01,  /* 00000040    "..,DBUG." */
+    0x98,0x68,0x60,0x96,0x60,0x60,0x74,0x87,  /* 00000048    ".h`.``t." */
+    0x60,0x01,0x61,0x70,0x00,0x62,0xA2,0x10,  /* 00000050    "`.ap.b.." */
+    0x95,0x62,0x61,0x70,0x83,0x88,0x60,0x62,  /* 00000058    ".bap..`b" */
+    0x00,0x44,0x42,0x47,0x42,0x75,0x62,0x70,  /* 00000060    ".DBGBubp" */
+    0x0A,0x0A,0x44,0x42,0x47,0x42,0x10,0x43,  /* 00000068    "..DBGB.C" */
+    0xD8,0x5F,0x53,0x42,0x5F,0x5B,0x82,0x44,  /* 00000070    "._SB_[.D" */
+    0xD3,0x50,0x43,0x49,0x30,0x08,0x5F,0x48,  /* 00000078    ".PCI0._H" */
+    0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03,0x08,  /* 00000080    "ID.A...." */
+    0x5F,0x41,0x44,0x52,0x00,0x08,0x5F,0x55,  /* 00000088    "_ADR.._U" */
+    0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x54,  /* 00000090    "ID.._PRT" */
+    0x12,0x4B,0x73,0x80,0x12,0x0B,0x04,0x0B,  /* 00000098    ".Ks....." */
+    0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x44,0x00,  /* 000000A0    "...LNKD." */
+    0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C,  /* 000000A8    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0C,0x04,0x0B,  /* 000000B0    "NKA....." */
+    0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x42,  /* 000000B8    "....LNKB" */
+    0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A,  /* 000000C0    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 000000C8    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C,  /* 000000D0    ".......L" */
+    0x4E,0x4B,0x53,0x00,0x12,0x0D,0x04,0x0C,  /* 000000D8    "NKS....." */
+    0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B,  /* 000000E0    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000000E8    "B......." */
+    0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000000F0    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,  /* 000000F8    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000100    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00,  /* 00000108    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000110    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C,  /* 00000118    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000120    "NKC....." */
+    0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000128    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000130    "KD......" */
+    0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000138    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000140    "A......." */
+    0x03,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000148    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00,  /* 00000150    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000158    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02,  /* 00000160    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000168    "LNKA...." */
+    0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C,  /* 00000170    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000178    "NKB....." */
+    0xFF,0xFF,0x04,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000180    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000188    "D......." */
+    0x04,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000190    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,  /* 00000198    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 000001A0    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,  /* 000001A8    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 000001B0    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x05,0x00,0x00,0x4C,  /* 000001B8    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 000001C0    "NKA....." */
+    0xFF,0xFF,0x05,0x00,0x01,0x4C,0x4E,0x4B,  /* 000001C8    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000001D0    "B......." */
+    0x05,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000001D8    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,  /* 000001E0    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000001E8    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x06,0x00,  /* 000001F0    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000001F8    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01,0x4C,  /* 00000200    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000208    "NKC....." */
+    0xFF,0xFF,0x06,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000210    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000218    "KD......" */
+    0xFF,0x06,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000220    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000228    "A......." */
+    0x07,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000230    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x07,0x00,  /* 00000238    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000240    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02,  /* 00000248    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000250    "LNKA...." */
+    0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x03,0x4C,  /* 00000258    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000260    "NKB....." */
+    0xFF,0xFF,0x08,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000268    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000270    "D......." */
+    0x08,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000278    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,  /* 00000280    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000288    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A,  /* 00000290    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000298    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x09,0x00,0x00,0x4C,  /* 000002A0    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 000002A8    "NKA....." */
+    0xFF,0xFF,0x09,0x00,0x01,0x4C,0x4E,0x4B,  /* 000002B0    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000002B8    "B......." */
+    0x09,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000002C0    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x09,  /* 000002C8    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000002D0    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0A,0x00,  /* 000002D8    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000002E0    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01,0x4C,  /* 000002E8    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000002F0    "NKC....." */
+    0xFF,0xFF,0x0A,0x00,0x0A,0x02,0x4C,0x4E,  /* 000002F8    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000300    "KD......" */
+    0xFF,0x0A,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000308    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000310    "A......." */
+    0x0B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000318    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0B,0x00,  /* 00000320    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000328    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02,  /* 00000330    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000338    "LNKA...." */
+    0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x03,0x4C,  /* 00000340    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000348    "NKB....." */
+    0xFF,0xFF,0x0C,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000350    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000358    "D......." */
+    0x0C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000360    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,  /* 00000368    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000370    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A,  /* 00000378    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000380    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x00,0x4C,  /* 00000388    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000390    "NKA....." */
+    0xFF,0xFF,0x0D,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000398    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000003A0    "B......." */
+    0x0D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000003A8    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0D,  /* 000003B0    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000003B8    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0E,0x00,  /* 000003C0    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000003C8    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01,0x4C,  /* 000003D0    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000003D8    "NKC....." */
+    0xFF,0xFF,0x0E,0x00,0x0A,0x02,0x4C,0x4E,  /* 000003E0    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000003E8    "KD......" */
+    0xFF,0x0E,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000003F0    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000003F8    "A......." */
+    0x0F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000400    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0F,0x00,  /* 00000408    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000410    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02,  /* 00000418    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000420    "LNKA...." */
+    0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x03,0x4C,  /* 00000428    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000430    "NKB....." */
+    0xFF,0xFF,0x10,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000438    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000440    "D......." */
+    0x10,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000448    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,  /* 00000450    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000458    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,0x0A,  /* 00000460    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000468    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x11,0x00,0x00,0x4C,  /* 00000470    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000478    "NKA....." */
+    0xFF,0xFF,0x11,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000480    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000488    "B......." */
+    0x11,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000490    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x11,  /* 00000498    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000004A0    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x12,0x00,  /* 000004A8    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000004B0    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x12,0x00,0x01,0x4C,  /* 000004B8    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000004C0    "NKC....." */
+    0xFF,0xFF,0x12,0x00,0x0A,0x02,0x4C,0x4E,  /* 000004C8    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000004D0    "KD......" */
+    0xFF,0x12,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000004D8    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000004E0    "A......." */
+    0x13,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000004E8    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x13,0x00,  /* 000004F0    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000004F8    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x02,  /* 00000500    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000508    "LNKA...." */
+    0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x03,0x4C,  /* 00000510    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000518    "NKB....." */
+    0xFF,0xFF,0x14,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000520    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000528    "D......." */
+    0x14,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000530    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,  /* 00000538    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000540    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,0x0A,  /* 00000548    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000550    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x15,0x00,0x00,0x4C,  /* 00000558    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000560    "NKA....." */
+    0xFF,0xFF,0x15,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000568    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000570    "B......." */
+    0x15,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000578    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x15,  /* 00000580    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000588    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x16,0x00,  /* 00000590    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000598    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x16,0x00,0x01,0x4C,  /* 000005A0    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000005A8    "NKC....." */
+    0xFF,0xFF,0x16,0x00,0x0A,0x02,0x4C,0x4E,  /* 000005B0    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000005B8    "KD......" */
+    0xFF,0x16,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000005C0    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000005C8    "A......." */
+    0x17,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000005D0    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x17,0x00,  /* 000005D8    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000005E0    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x02,  /* 000005E8    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000005F0    "LNKA...." */
+    0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x03,0x4C,  /* 000005F8    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000600    "NKB....." */
+    0xFF,0xFF,0x18,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000608    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000610    "D......." */
+    0x18,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000618    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,  /* 00000620    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000628    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,0x0A,  /* 00000630    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000638    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x19,0x00,0x00,0x4C,  /* 00000640    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000648    "NKA....." */
+    0xFF,0xFF,0x19,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000650    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000658    "B......." */
+    0x19,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000660    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x19,  /* 00000668    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000670    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1A,0x00,  /* 00000678    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000680    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x1A,0x00,0x01,0x4C,  /* 00000688    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000690    "NKC....." */
+    0xFF,0xFF,0x1A,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000698    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000006A0    "KD......" */
+    0xFF,0x1A,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000006A8    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000006B0    "A......." */
+    0x1B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000006B8    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1B,0x00,  /* 000006C0    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000006C8    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x02,  /* 000006D0    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000006D8    "LNKA...." */
+    0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x03,0x4C,  /* 000006E0    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 000006E8    "NKB....." */
+    0xFF,0xFF,0x1C,0x00,0x00,0x4C,0x4E,0x4B,  /* 000006F0    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000006F8    "D......." */
+    0x1C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000700    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,  /* 00000708    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000710    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,0x0A,  /* 00000718    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000720    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x1D,0x00,0x00,0x4C,  /* 00000728    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000730    "NKA....." */
+    0xFF,0xFF,0x1D,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000738    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000740    "B......." */
+    0x1D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000748    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1D,  /* 00000750    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000758    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1E,0x00,  /* 00000760    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000768    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x1E,0x00,0x01,0x4C,  /* 00000770    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000778    "NKC....." */
+    0xFF,0xFF,0x1E,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000780    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000788    "KD......" */
+    0xFF,0x1E,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000790    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000798    "A......." */
+    0x1F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000007A0    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1F,0x00,  /* 000007A8    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000007B0    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x02,  /* 000007B8    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000007C0    "LNKA...." */
+    0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x03,0x4C,  /* 000007C8    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x5B,0x80,0x50,0x43,  /* 000007D0    "NKB.[.PC" */
+    0x53,0x54,0x01,0x0B,0x00,0xAE,0x0A,0x08,  /* 000007D8    "ST......" */
+    0x5B,0x81,0x10,0x50,0x43,0x53,0x54,0x43,  /* 000007E0    "[..PCSTC" */
+    0x50,0x43,0x49,0x55,0x20,0x50,0x43,0x49,  /* 000007E8    "PCIU PCI" */
+    0x44,0x20,0x5B,0x80,0x53,0x45,0x4A,0x5F,  /* 000007F0    "D [.SEJ_" */
+    0x01,0x0B,0x08,0xAE,0x0A,0x04,0x5B,0x81,  /* 000007F8    "......[." */
+    0x0B,0x53,0x45,0x4A,0x5F,0x43,0x42,0x30,  /* 00000800    ".SEJ_CB0" */
+    0x45,0x4A,0x20,0x5B,0x80,0x52,0x4D,0x56,  /* 00000808    "EJ [.RMV" */
+    0x43,0x01,0x0B,0x0C,0xAE,0x0A,0x04,0x5B,  /* 00000810    "C......[" */
+    0x81,0x0B,0x52,0x4D,0x56,0x43,0x43,0x50,  /* 00000818    "..RMVCCP" */
+    0x43,0x52,0x4D,0x20,0x5B,0x82,0x25,0x53,  /* 00000820    "CRM [.%S" */
+    0x31,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000828    "1__._ADR" */
+    0x0C,0x00,0x00,0x01,0x00,0x14,0x0F,0x5F,  /* 00000830    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0A,0x02,0x42,  /* 00000838    "EJ0.p..B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000840    "0EJ..._S" */
+    0x55,0x4E,0x01,0x5B,0x82,0x26,0x53,0x32,  /* 00000848    "UN.[.&S2" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000850    "__._ADR." */
+    0x00,0x00,0x02,0x00,0x14,0x0F,0x5F,0x45,  /* 00000858    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x04,0x42,0x30,  /* 00000860    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000868    "EJ..._SU" */
+    0x4E,0x0A,0x02,0x5B,0x82,0x26,0x53,0x33,  /* 00000870    "N..[.&S3" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000878    "__._ADR." */
+    0x00,0x00,0x03,0x00,0x14,0x0F,0x5F,0x45,  /* 00000880    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x08,0x42,0x30,  /* 00000888    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000890    "EJ..._SU" */
+    0x4E,0x0A,0x03,0x5B,0x82,0x26,0x53,0x34,  /* 00000898    "N..[.&S4" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008A0    "__._ADR." */
+    0x00,0x00,0x04,0x00,0x14,0x0F,0x5F,0x45,  /* 000008A8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x10,0x42,0x30,  /* 000008B0    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000008B8    "EJ..._SU" */
+    0x4E,0x0A,0x04,0x5B,0x82,0x26,0x53,0x35,  /* 000008C0    "N..[.&S5" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008C8    "__._ADR." */
+    0x00,0x00,0x05,0x00,0x14,0x0F,0x5F,0x45,  /* 000008D0    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x20,0x42,0x30,  /* 000008D8    "J0.p. B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000008E0    "EJ..._SU" */
+    0x4E,0x0A,0x05,0x5B,0x82,0x26,0x53,0x36,  /* 000008E8    "N..[.&S6" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008F0    "__._ADR." */
+    0x00,0x00,0x06,0x00,0x14,0x0F,0x5F,0x45,  /* 000008F8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x40,0x42,0x30,  /* 00000900    "J0.p. at B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000908    "EJ..._SU" */
+    0x4E,0x0A,0x06,0x5B,0x82,0x26,0x53,0x37,  /* 00000910    "N..[.&S7" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000918    "__._ADR." */
+    0x00,0x00,0x07,0x00,0x14,0x0F,0x5F,0x45,  /* 00000920    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x80,0x42,0x30,  /* 00000928    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000930    "EJ..._SU" */
+    0x4E,0x0A,0x07,0x5B,0x82,0x27,0x53,0x38,  /* 00000938    "N..[.'S8" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000940    "__._ADR." */
+    0x00,0x00,0x08,0x00,0x14,0x10,0x5F,0x45,  /* 00000948    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0B,0x00,0x01,0x42,  /* 00000950    "J0.p...B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000958    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x08,0x5B,0x82,0x27,0x53,  /* 00000960    "UN..[.'S" */
+    0x39,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000968    "9__._ADR" */
+    0x0C,0x00,0x00,0x09,0x00,0x14,0x10,0x5F,  /* 00000970    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,0x02,  /* 00000978    "EJ0.p..." */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000980    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x09,0x5B,0x82,0x27,  /* 00000988    "SUN..[.'" */
+    0x53,0x31,0x30,0x5F,0x08,0x5F,0x41,0x44,  /* 00000990    "S10_._AD" */
+    0x52,0x0C,0x00,0x00,0x0A,0x00,0x14,0x10,  /* 00000998    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,  /* 000009A0    "_EJ0.p.." */
+    0x04,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 000009A8    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82,  /* 000009B0    "_SUN..[." */
+    0x27,0x53,0x31,0x31,0x5F,0x08,0x5F,0x41,  /* 000009B8    "'S11_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14,  /* 000009C0    "DR......" */
+    0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,  /* 000009C8    "._EJ0.p." */
+    0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 000009D0    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0B,0x5B,  /* 000009D8    "._SUN..[" */
+    0x82,0x27,0x53,0x31,0x32,0x5F,0x08,0x5F,  /* 000009E0    ".'S12_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x0C,0x00,  /* 000009E8    "ADR....." */
+    0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 000009F0    ".._EJ0.p" */
+    0x0B,0x00,0x10,0x42,0x30,0x45,0x4A,0xA4,  /* 000009F8    "...B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0C,  /* 00000A00    ".._SUN.." */
+    0x5B,0x82,0x27,0x53,0x31,0x33,0x5F,0x08,  /* 00000A08    "[.'S13_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0D,  /* 00000A10    "_ADR...." */
+    0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,  /* 00000A18    "..._EJ0." */
+    0x70,0x0B,0x00,0x20,0x42,0x30,0x45,0x4A,  /* 00000A20    "p.. B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000A28    "..._SUN." */
+    0x0D,0x5B,0x82,0x27,0x53,0x31,0x34,0x5F,  /* 00000A30    ".[.'S14_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000A38    "._ADR..." */
+    0x0E,0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,  /* 00000A40    "...._EJ0" */
+    0x01,0x70,0x0B,0x00,0x40,0x42,0x30,0x45,  /* 00000A48    ".p.. at B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000A50    "J..._SUN" */
+    0x0A,0x0E,0x5B,0x82,0x27,0x53,0x31,0x35,  /* 00000A58    "..[.'S15" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000A60    "_._ADR.." */
+    0x00,0x0F,0x00,0x14,0x10,0x5F,0x45,0x4A,  /* 00000A68    "....._EJ" */
+    0x30,0x01,0x70,0x0B,0x00,0x80,0x42,0x30,  /* 00000A70    "0.p...B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000A78    "EJ..._SU" */
+    0x4E,0x0A,0x0F,0x5B,0x82,0x29,0x53,0x31,  /* 00000A80    "N..[.)S1" */
+    0x36,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000A88    "6_._ADR." */
+    0x00,0x00,0x10,0x00,0x14,0x12,0x5F,0x45,  /* 00000A90    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x01,  /* 00000A98    "J0.p...." */
+    0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 00000AA0    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x10,0x5B,0x82,  /* 00000AA8    "_SUN..[." */
+    0x29,0x53,0x31,0x37,0x5F,0x08,0x5F,0x41,  /* 00000AB0    ")S17_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x11,0x00,0x14,  /* 00000AB8    "DR......" */
+    0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,  /* 00000AC0    "._EJ0.p." */
+    0x00,0x00,0x02,0x00,0x42,0x30,0x45,0x4A,  /* 00000AC8    "....B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000AD0    "..._SUN." */
+    0x11,0x5B,0x82,0x29,0x53,0x31,0x38,0x5F,  /* 00000AD8    ".[.)S18_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000AE0    "._ADR..." */
+    0x12,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,  /* 00000AE8    "...._EJ0" */
+    0x01,0x70,0x0C,0x00,0x00,0x04,0x00,0x42,  /* 00000AF0    ".p.....B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000AF8    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x12,0x5B,0x82,0x29,0x53,  /* 00000B00    "UN..[.)S" */
+    0x31,0x39,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000B08    "19_._ADR" */
+    0x0C,0x00,0x00,0x13,0x00,0x14,0x12,0x5F,  /* 00000B10    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,  /* 00000B18    "EJ0.p..." */
+    0x08,0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 00000B20    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x13,0x5B,  /* 00000B28    "._SUN..[" */
+    0x82,0x29,0x53,0x32,0x30,0x5F,0x08,0x5F,  /* 00000B30    ".)S20_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x14,0x00,  /* 00000B38    "ADR....." */
+    0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 00000B40    ".._EJ0.p" */
+    0x0C,0x00,0x00,0x10,0x00,0x42,0x30,0x45,  /* 00000B48    ".....B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000B50    "J..._SUN" */
+    0x0A,0x14,0x5B,0x82,0x29,0x53,0x32,0x31,  /* 00000B58    "..[.)S21" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000B60    "_._ADR.." */
+    0x00,0x15,0x00,0x14,0x12,0x5F,0x45,0x4A,  /* 00000B68    "....._EJ" */
+    0x30,0x01,0x70,0x0C,0x00,0x00,0x20,0x00,  /* 00000B70    "0.p... ." */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000B78    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x15,0x5B,0x82,0x29,  /* 00000B80    "SUN..[.)" */
+    0x53,0x32,0x32,0x5F,0x08,0x5F,0x41,0x44,  /* 00000B88    "S22_._AD" */
+    0x52,0x0C,0x00,0x00,0x16,0x00,0x14,0x12,  /* 00000B90    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,  /* 00000B98    "_EJ0.p.." */
+    0x00,0x40,0x00,0x42,0x30,0x45,0x4A,0xA4,  /* 00000BA0    ". at .B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x16,  /* 00000BA8    ".._SUN.." */
+    0x5B,0x82,0x29,0x53,0x32,0x33,0x5F,0x08,  /* 00000BB0    "[.)S23_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x17,  /* 00000BB8    "_ADR...." */
+    0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,  /* 00000BC0    "..._EJ0." */
+    0x70,0x0C,0x00,0x00,0x80,0x00,0x42,0x30,  /* 00000BC8    "p.....B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000BD0    "EJ..._SU" */
+    0x4E,0x0A,0x17,0x5B,0x82,0x29,0x53,0x32,  /* 00000BD8    "N..[.)S2" */
+    0x34,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000BE0    "4_._ADR." */
+    0x00,0x00,0x18,0x00,0x14,0x12,0x5F,0x45,  /* 00000BE8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x00,  /* 00000BF0    "J0.p...." */
+    0x01,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 00000BF8    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x18,0x5B,0x82,  /* 00000C00    "_SUN..[." */
+    0x29,0x53,0x32,0x35,0x5F,0x08,0x5F,0x41,  /* 00000C08    ")S25_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x19,0x00,0x14,  /* 00000C10    "DR......" */
+    0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,  /* 00000C18    "._EJ0.p." */
+    0x00,0x00,0x00,0x02,0x42,0x30,0x45,0x4A,  /* 00000C20    "....B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000C28    "..._SUN." */
+    0x19,0x5B,0x82,0x29,0x53,0x32,0x36,0x5F,  /* 00000C30    ".[.)S26_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000C38    "._ADR..." */
+    0x1A,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,  /* 00000C40    "...._EJ0" */
+    0x01,0x70,0x0C,0x00,0x00,0x00,0x04,0x42,  /* 00000C48    ".p.....B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000C50    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x29,0x53,  /* 00000C58    "UN..[.)S" */
+    0x32,0x37,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000C60    "27_._ADR" */
+    0x0C,0x00,0x00,0x1B,0x00,0x14,0x12,0x5F,  /* 00000C68    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,  /* 00000C70    "EJ0.p..." */
+    0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 00000C78    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1B,0x5B,  /* 00000C80    "._SUN..[" */
+    0x82,0x29,0x53,0x32,0x38,0x5F,0x08,0x5F,  /* 00000C88    ".)S28_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x1C,0x00,  /* 00000C90    "ADR....." */
+    0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 00000C98    ".._EJ0.p" */
+    0x0C,0x00,0x00,0x00,0x10,0x42,0x30,0x45,  /* 00000CA0    ".....B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000CA8    "J..._SUN" */
+    0x0A,0x1C,0x5B,0x82,0x29,0x53,0x32,0x39,  /* 00000CB0    "..[.)S29" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000CB8    "_._ADR.." */
+    0x00,0x1D,0x00,0x14,0x12,0x5F,0x45,0x4A,  /* 00000CC0    "....._EJ" */
+    0x30,0x01,0x70,0x0C,0x00,0x00,0x00,0x20,  /* 00000CC8    "0.p.... " */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000CD0    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x29,  /* 00000CD8    "SUN..[.)" */
+    0x53,0x33,0x30,0x5F,0x08,0x5F,0x41,0x44,  /* 00000CE0    "S30_._AD" */
+    0x52,0x0C,0x00,0x00,0x1E,0x00,0x14,0x12,  /* 00000CE8    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,  /* 00000CF0    "_EJ0.p.." */
+    0x00,0x00,0x40,0x42,0x30,0x45,0x4A,0xA4,  /* 00000CF8    ".. at B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1E,  /* 00000D00    ".._SUN.." */
+    0x5B,0x82,0x29,0x53,0x33,0x31,0x5F,0x08,  /* 00000D08    "[.)S31_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x1F,  /* 00000D10    "_ADR...." */
+    0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,  /* 00000D18    "..._EJ0." */
+    0x70,0x0C,0x00,0x00,0x00,0x80,0x42,0x30,  /* 00000D20    "p.....B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000D28    "EJ..._SU" */
+    0x4E,0x0A,0x1F,0x08,0x5F,0x43,0x52,0x53,  /* 00000D30    "N..._CRS" */
+    0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00,  /* 00000D38    ".B..n..." */
+    0x02,0x0C,0x00,0x00,0x00,0x00,0x00,0xFF,  /* 00000D40    "........" */
+    0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8,  /* 00000D48    ".....G.." */
+    0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00,  /* 00000D50    "........" */
+    0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7,  /* 00000D58    "........" */
+    0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00,  /* 00000D60    "........" */
+    0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF,  /* 00000D68    "........" */
+    0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00,  /* 00000D70    "........" */
+    0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,  /* 00000D78    "........" */
+    0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00,  /* 00000D80    "........" */
+    0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x87,  /* 00000D88    "........" */
+    0x17,0x00,0x00,0x0C,0x01,0x00,0x00,0x00,  /* 00000D90    "........" */
+    0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xBF,  /* 00000D98    "........" */
+    0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,  /* 00000DA0    "........" */
+    0x1E,0x79,0x00,0x5B,0x82,0x45,0x04,0x48,  /* 00000DA8    ".y.[.E.H" */
+    0x50,0x45,0x54,0x08,0x5F,0x48,0x49,0x44,  /* 00000DB0    "PET._HID" */
+    0x0C,0x41,0xD0,0x01,0x03,0x08,0x5F,0x55,  /* 00000DB8    ".A...._U" */
+    0x49,0x44,0x00,0x14,0x09,0x5F,0x53,0x54,  /* 00000DC0    "ID..._ST" */
+    0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,  /* 00000DC8    "A....._C" */
+    0x52,0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17,  /* 00000DD0    "RS......" */
+    0x00,0x00,0x0D,0x01,0x00,0x00,0x00,0x00,  /* 00000DD8    "........" */
+    0x00,0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE,  /* 00000DE0    "........" */
+    0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,  /* 00000DE8    "........" */
+    0x79,0x00,0x10,0x40,0x82,0x2E,0x5F,0x53,  /* 00000DF0    "y.. at .._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x5B,0x82,  /* 00000DF8    "B_PCI0[." */
+    0x33,0x56,0x47,0x41,0x5F,0x08,0x5F,0x41,  /* 00000E00    "3VGA_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x02,0x00,0x14,  /* 00000E08    "DR......" */
+    0x08,0x5F,0x53,0x31,0x44,0x00,0xA4,0x00,  /* 00000E10    "._S1D..." */
+    0x14,0x08,0x5F,0x53,0x32,0x44,0x00,0xA4,  /* 00000E18    ".._S2D.." */
+    0x00,0x14,0x08,0x5F,0x53,0x33,0x44,0x00,  /* 00000E20    "..._S3D." */
+    0xA4,0x00,0x14,0x08,0x5F,0x52,0x4D,0x56,  /* 00000E28    "...._RMV" */
+    0x00,0xA4,0x00,0x5B,0x82,0x4B,0x23,0x49,  /* 00000E30    "...[.K#I" */
+    0x53,0x41,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000E38    "SA_._ADR" */
+    0x0C,0x00,0x00,0x01,0x00,0x14,0x08,0x5F,  /* 00000E40    "......._" */
+    0x52,0x4D,0x56,0x00,0xA4,0x00,0x5B,0x80,  /* 00000E48    "RMV...[." */
+    0x50,0x34,0x30,0x43,0x02,0x0A,0x60,0x0A,  /* 00000E50    "P40C..`." */
+    0x04,0x5B,0x82,0x2D,0x52,0x54,0x43,0x5F,  /* 00000E58    ".[.-RTC_" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 00000E60    "._HID.A." */
+    0x0B,0x00,0x08,0x5F,0x43,0x52,0x53,0x11,  /* 00000E68    "..._CRS." */
+    0x18,0x0A,0x15,0x47,0x01,0x70,0x00,0x70,  /* 00000E70    "...G.p.p" */
+    0x00,0x10,0x02,0x22,0x00,0x01,0x47,0x01,  /* 00000E78    "..."..G." */
+    0x72,0x00,0x72,0x00,0x02,0x06,0x79,0x00,  /* 00000E80    "r.r...y." */
+    0x5B,0x82,0x44,0x04,0x4B,0x42,0x44,0x5F,  /* 00000E88    "[.D.KBD_" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 00000E90    "._HID.A." */
+    0x03,0x03,0x14,0x09,0x5F,0x53,0x54,0x41,  /* 00000E98    "...._STA" */
+    0x00,0xA4,0x0A,0x0F,0x14,0x29,0x5F,0x43,  /* 00000EA0    ".....)_C" */
+    0x52,0x53,0x00,0x08,0x54,0x4D,0x50,0x5F,  /* 00000EA8    "RS..TMP_" */
+    0x11,0x18,0x0A,0x15,0x47,0x01,0x60,0x00,  /* 00000EB0    "....G.`." */
+    0x60,0x00,0x01,0x01,0x47,0x01,0x64,0x00,  /* 00000EB8    "`...G.d." */
+    0x64,0x00,0x01,0x01,0x22,0x02,0x00,0x79,  /* 00000EC0    "d..."..y" */
+    0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B,0x82,  /* 00000EC8    "..TMP_[." */
+    0x33,0x4D,0x4F,0x55,0x5F,0x08,0x5F,0x48,  /* 00000ED0    "3MOU_._H" */
+    0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14,  /* 00000ED8    "ID.A...." */
+    0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,  /* 00000EE0    "._STA..." */
+    0x0F,0x14,0x19,0x5F,0x43,0x52,0x53,0x00,  /* 00000EE8    "..._CRS." */
+    0x08,0x54,0x4D,0x50,0x5F,0x11,0x08,0x0A,  /* 00000EF0    ".TMP_..." */
+    0x05,0x22,0x00,0x10,0x79,0x00,0xA4,0x54,  /* 00000EF8    "."..y..T" */
+    0x4D,0x50,0x5F,0x5B,0x82,0x47,0x04,0x46,  /* 00000F00    "MP_[.G.F" */
+    0x44,0x43,0x30,0x08,0x5F,0x48,0x49,0x44,  /* 00000F08    "DC0._HID" */
+    0x0C,0x41,0xD0,0x07,0x00,0x14,0x09,0x5F,  /* 00000F10    ".A....._" */
+    0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F,0x14,  /* 00000F18    "STA....." */
+    0x2C,0x5F,0x43,0x52,0x53,0x00,0x08,0x42,  /* 00000F20    ",_CRS..B" */
+    0x55,0x46,0x30,0x11,0x1B,0x0A,0x18,0x47,  /* 00000F28    "UF0....G" */
+    0x01,0xF2,0x03,0xF2,0x03,0x00,0x04,0x47,  /* 00000F30    ".......G" */
+    0x01,0xF7,0x03,0xF7,0x03,0x00,0x01,0x22,  /* 00000F38    "......."" */
+    0x40,0x00,0x2A,0x04,0x00,0x79,0x00,0xA4,  /* 00000F40    "@.*..y.." */
+    0x42,0x55,0x46,0x30,0x5B,0x82,0x4B,0x05,  /* 00000F48    "BUF0[.K." */
+    0x4C,0x50,0x54,0x5F,0x08,0x5F,0x48,0x49,  /* 00000F50    "LPT_._HI" */
+    0x44,0x0C,0x41,0xD0,0x04,0x00,0x14,0x28,  /* 00000F58    "D.A....(" */
+    0x5F,0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,  /* 00000F60    "_STA.p^^" */
+    0x5E,0x2E,0x50,0x58,0x31,0x33,0x44,0x52,  /* 00000F68    "^.PX13DR" */
+    0x53,0x41,0x60,0x7B,0x60,0x0C,0x00,0x00,  /* 00000F70    "SA`{`..." */
+    0x00,0x80,0x60,0xA0,0x06,0x93,0x60,0x00,  /* 00000F78    "..`...`." */
+    0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,  /* 00000F80    "........" */
+    0x21,0x5F,0x43,0x52,0x53,0x00,0x08,0x42,  /* 00000F88    "!_CRS..B" */
+    0x55,0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,  /* 00000F90    "UF0....G" */
+    0x01,0x78,0x03,0x78,0x03,0x08,0x08,0x22,  /* 00000F98    ".x.x..."" */
+    0x80,0x00,0x79,0x00,0xA4,0x42,0x55,0x46,  /* 00000FA0    "..y..BUF" */
+    0x30,0x5B,0x82,0x41,0x06,0x43,0x4F,0x4D,  /* 00000FA8    "0[.A.COM" */
+    0x31,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,  /* 00000FB0    "1._HID.A" */
+    0xD0,0x05,0x01,0x08,0x5F,0x55,0x49,0x44,  /* 00000FB8    "...._UID" */
+    0x01,0x14,0x28,0x5F,0x53,0x54,0x41,0x00,  /* 00000FC0    "..(_STA." */
+    0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31,  /* 00000FC8    "p^^^.PX1" */
+    0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60,  /* 00000FD0    "3DRSC`{`" */
+    0x0C,0x00,0x00,0x00,0x08,0x60,0xA0,0x06,  /* 00000FD8    ".....`.." */
+    0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4,  /* 00000FE0    ".`......" */
+    0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53,  /* 00000FE8    "...!_CRS" */
+    0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10,  /* 00000FF0    "..BUF0.." */
+    0x0A,0x0D,0x47,0x01,0xF8,0x03,0xF8,0x03,  /* 00000FF8    "..G....." */
+    0x00,0x08,0x22,0x10,0x00,0x79,0x00,0xA4,  /* 00001000    ".."..y.." */
+    0x42,0x55,0x46,0x30,0x5B,0x82,0x42,0x06,  /* 00001008    "BUF0[.B." */
+    0x43,0x4F,0x4D,0x32,0x08,0x5F,0x48,0x49,  /* 00001010    "COM2._HI" */
+    0x44,0x0C,0x41,0xD0,0x05,0x01,0x08,0x5F,  /* 00001018    "D.A...._" */
+    0x55,0x49,0x44,0x0A,0x02,0x14,0x28,0x5F,  /* 00001020    "UID...(_" */
+    0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E,  /* 00001028    "STA.p^^^" */
+    0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53,  /* 00001030    ".PX13DRS" */
+    0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00,  /* 00001038    "C`{`...." */
+    0x80,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4,  /* 00001040    ".`...`.." */
+    0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21,  /* 00001048    ".......!" */
+    0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55,  /* 00001050    "_CRS..BU" */
+    0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01,  /* 00001058    "F0....G." */
+    0xF8,0x02,0xF8,0x02,0x00,0x08,0x22,0x08,  /* 00001060    "......"." */
+    0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30,  /* 00001068    ".y..BUF0" */
+    0x5B,0x82,0x40,0x05,0x50,0x58,0x31,0x33,  /* 00001070    "[. at .PX13" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x03,0x00,  /* 00001078    "._ADR..." */
+    0x01,0x00,0x5B,0x80,0x50,0x31,0x33,0x43,  /* 00001080    "..[.P13C" */
+    0x02,0x0A,0x5C,0x0A,0x24,0x5B,0x81,0x33,  /* 00001088    "..\.$[.3" */
+    0x50,0x31,0x33,0x43,0x03,0x44,0x52,0x53,  /* 00001090    "P13C.DRS" */
+    0x41,0x20,0x44,0x52,0x53,0x42,0x20,0x44,  /* 00001098    "A DRSB D" */
+    0x52,0x53,0x43,0x20,0x44,0x52,0x53,0x45,  /* 000010A0    "RSC DRSE" */
+    0x20,0x44,0x52,0x53,0x46,0x20,0x44,0x52,  /* 000010A8    " DRSF DR" */
+    0x53,0x47,0x20,0x44,0x52,0x53,0x48,0x20,  /* 000010B0    "SG DRSH " */
+    0x44,0x52,0x53,0x49,0x20,0x44,0x52,0x53,  /* 000010B8    "DRSI DRS" */
+    0x4A,0x20,0x5B,0x82,0x2B,0x53,0x4C,0x33,  /* 000010C0    "J [.+SL3" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 000010C8    "_._ADR.." */
+    0x00,0x03,0x00,0x14,0x14,0x5F,0x52,0x4D,  /* 000010D0    "....._RM" */
+    0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43,0x52,  /* 000010D8    "V...{PCR" */
+    0x4D,0x0A,0x08,0x00,0xA4,0x01,0xA4,0x00,  /* 000010E0    "M......." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x03,0x5B,  /* 000010E8    "._SUN..[" */
+    0x82,0x2B,0x53,0x4C,0x34,0x5F,0x08,0x5F,  /* 000010F0    ".+SL4_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x04,0x00,  /* 000010F8    "ADR....." */
+    0x14,0x14,0x5F,0x52,0x4D,0x56,0x00,0xA0,  /* 00001100    ".._RMV.." */
+    0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A,0x10,  /* 00001108    ".{PCRM.." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001110    "......_S" */
+    0x55,0x4E,0x0A,0x04,0x5B,0x82,0x2B,0x53,  /* 00001118    "UN..[.+S" */
+    0x4C,0x35,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00001120    "L5_._ADR" */
+    0x0C,0x00,0x00,0x05,0x00,0x14,0x14,0x5F,  /* 00001128    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0B,0x7B,0x50,  /* 00001130    "RMV...{P" */
+    0x43,0x52,0x4D,0x0A,0x20,0x00,0xA4,0x01,  /* 00001138    "CRM. ..." */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00001140    "..._SUN." */
+    0x05,0x5B,0x82,0x2B,0x53,0x4C,0x36,0x5F,  /* 00001148    ".[.+SL6_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00001150    "._ADR..." */
+    0x06,0x00,0x14,0x14,0x5F,0x52,0x4D,0x56,  /* 00001158    "...._RMV" */
+    0x00,0xA0,0x0B,0x7B,0x50,0x43,0x52,0x4D,  /* 00001160    "...{PCRM" */
+    0x0A,0x40,0x00,0xA4,0x01,0xA4,0x00,0x08,  /* 00001168    ". at ......" */
+    0x5F,0x53,0x55,0x4E,0x0A,0x06,0x5B,0x82,  /* 00001170    "_SUN..[." */
+    0x2B,0x53,0x4C,0x37,0x5F,0x08,0x5F,0x41,  /* 00001178    "+SL7_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x07,0x00,0x14,  /* 00001180    "DR......" */
+    0x14,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0B,  /* 00001188    "._RMV..." */
+    0x7B,0x50,0x43,0x52,0x4D,0x0A,0x80,0x00,  /* 00001190    "{PCRM..." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001198    "....._SU" */
+    0x4E,0x0A,0x07,0x5B,0x82,0x2C,0x53,0x4C,  /* 000011A0    "N..[.,SL" */
+    0x38,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000011A8    "8_._ADR." */
+    0x00,0x00,0x08,0x00,0x14,0x15,0x5F,0x52,  /* 000011B0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,  /* 000011B8    "MV...{PC" */
+    0x52,0x4D,0x0B,0x00,0x01,0x00,0xA4,0x01,  /* 000011C0    "RM......" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 000011C8    "..._SUN." */
+    0x08,0x5B,0x82,0x2C,0x53,0x4C,0x39,0x5F,  /* 000011D0    ".[.,SL9_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 000011D8    "._ADR..." */
+    0x09,0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,  /* 000011E0    "...._RMV" */
+    0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,  /* 000011E8    "...{PCRM" */
+    0x0B,0x00,0x02,0x00,0xA4,0x01,0xA4,0x00,  /* 000011F0    "........" */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x09,0x5B,  /* 000011F8    "._SUN..[" */
+    0x82,0x2C,0x53,0x4C,0x31,0x30,0x08,0x5F,  /* 00001200    ".,SL10._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x0A,0x00,  /* 00001208    "ADR....." */
+    0x14,0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,  /* 00001210    ".._RMV.." */
+    0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,  /* 00001218    ".{PCRM.." */
+    0x04,0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,  /* 00001220    "......._" */
+    0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82,0x2C,  /* 00001228    "SUN..[.," */
+    0x53,0x4C,0x31,0x31,0x08,0x5F,0x41,0x44,  /* 00001230    "SL11._AD" */
+    0x52,0x0C,0x00,0x00,0x0B,0x00,0x14,0x15,  /* 00001238    "R......." */
+    0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,  /* 00001240    "_RMV...{" */
+    0x50,0x43,0x52,0x4D,0x0B,0x00,0x08,0x00,  /* 00001248    "PCRM...." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001250    "....._SU" */
+    0x4E,0x0A,0x0B,0x5B,0x82,0x2C,0x53,0x4C,  /* 00001258    "N..[.,SL" */
+    0x31,0x32,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001260    "12._ADR." */
+    0x00,0x00,0x0C,0x00,0x14,0x15,0x5F,0x52,  /* 00001268    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,  /* 00001270    "MV...{PC" */
+    0x52,0x4D,0x0B,0x00,0x10,0x00,0xA4,0x01,  /* 00001278    "RM......" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00001280    "..._SUN." */
+    0x0C,0x5B,0x82,0x2C,0x53,0x4C,0x31,0x33,  /* 00001288    ".[.,SL13" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00001290    "._ADR..." */
+    0x0D,0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,  /* 00001298    "...._RMV" */
+    0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,  /* 000012A0    "...{PCRM" */
+    0x0B,0x00,0x20,0x00,0xA4,0x01,0xA4,0x00,  /* 000012A8    ".. ....." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0D,0x5B,  /* 000012B0    "._SUN..[" */
+    0x82,0x2C,0x53,0x4C,0x31,0x34,0x08,0x5F,  /* 000012B8    ".,SL14._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x0E,0x00,  /* 000012C0    "ADR....." */
+    0x14,0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,  /* 000012C8    ".._RMV.." */
+    0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,  /* 000012D0    ".{PCRM.." */
+    0x40,0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,  /* 000012D8    "@......_" */
+    0x53,0x55,0x4E,0x0A,0x0E,0x5B,0x82,0x2C,  /* 000012E0    "SUN..[.," */
+    0x53,0x4C,0x31,0x35,0x08,0x5F,0x41,0x44,  /* 000012E8    "SL15._AD" */
+    0x52,0x0C,0x00,0x00,0x0F,0x00,0x14,0x15,  /* 000012F0    "R......." */
+    0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,  /* 000012F8    "_RMV...{" */
+    0x50,0x43,0x52,0x4D,0x0B,0x00,0x80,0x00,  /* 00001300    "PCRM...." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001308    "....._SU" */
+    0x4E,0x0A,0x0F,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001310    "N..[..SL" */
+    0x31,0x36,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001318    "16._ADR." */
+    0x00,0x00,0x10,0x00,0x14,0x17,0x5F,0x52,  /* 00001320    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001328    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x01,0x00,0x00,  /* 00001330    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001338    "....._SU" */
+    0x4E,0x0A,0x10,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001340    "N..[..SL" */
+    0x31,0x37,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001348    "17._ADR." */
+    0x00,0x00,0x11,0x00,0x14,0x17,0x5F,0x52,  /* 00001350    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001358    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x02,0x00,0x00,  /* 00001360    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001368    "....._SU" */
+    0x4E,0x0A,0x11,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001370    "N..[..SL" */
+    0x31,0x38,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001378    "18._ADR." */
+    0x00,0x00,0x12,0x00,0x14,0x17,0x5F,0x52,  /* 00001380    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001388    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x04,0x00,0x00,  /* 00001390    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001398    "....._SU" */
+    0x4E,0x0A,0x12,0x5B,0x82,0x2E,0x53,0x4C,  /* 000013A0    "N..[..SL" */
+    0x31,0x39,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000013A8    "19._ADR." */
+    0x00,0x00,0x13,0x00,0x14,0x17,0x5F,0x52,  /* 000013B0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000013B8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x08,0x00,0x00,  /* 000013C0    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000013C8    "....._SU" */
+    0x4E,0x0A,0x13,0x5B,0x82,0x2E,0x53,0x4C,  /* 000013D0    "N..[..SL" */
+    0x32,0x30,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000013D8    "20._ADR." */
+    0x00,0x00,0x14,0x00,0x14,0x17,0x5F,0x52,  /* 000013E0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000013E8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x10,0x00,0x00,  /* 000013F0    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000013F8    "....._SU" */
+    0x4E,0x0A,0x14,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001400    "N..[..SL" */
+    0x32,0x31,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001408    "21._ADR." */
+    0x00,0x00,0x15,0x00,0x14,0x17,0x5F,0x52,  /* 00001410    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001418    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x20,0x00,0x00,  /* 00001420    "RM... .." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001428    "....._SU" */
+    0x4E,0x0A,0x15,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001430    "N..[..SL" */
+    0x32,0x32,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001438    "22._ADR." */
+    0x00,0x00,0x16,0x00,0x14,0x17,0x5F,0x52,  /* 00001440    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001448    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x40,0x00,0x00,  /* 00001450    "RM... at .." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001458    "....._SU" */
+    0x4E,0x0A,0x16,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001460    "N..[..SL" */
+    0x32,0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001468    "23._ADR." */
+    0x00,0x00,0x17,0x00,0x14,0x17,0x5F,0x52,  /* 00001470    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001478    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x80,0x00,0x00,  /* 00001480    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001488    "....._SU" */
+    0x4E,0x0A,0x17,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001490    "N..[..SL" */
+    0x32,0x34,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001498    "24._ADR." */
+    0x00,0x00,0x18,0x00,0x14,0x17,0x5F,0x52,  /* 000014A0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000014A8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x01,0x00,  /* 000014B0    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000014B8    "....._SU" */
+    0x4E,0x0A,0x18,0x5B,0x82,0x2E,0x53,0x4C,  /* 000014C0    "N..[..SL" */
+    0x32,0x35,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000014C8    "25._ADR." */
+    0x00,0x00,0x19,0x00,0x14,0x17,0x5F,0x52,  /* 000014D0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000014D8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x02,0x00,  /* 000014E0    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000014E8    "....._SU" */
+    0x4E,0x0A,0x19,0x5B,0x82,0x2E,0x53,0x4C,  /* 000014F0    "N..[..SL" */
+    0x32,0x36,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000014F8    "26._ADR." */
+    0x00,0x00,0x1A,0x00,0x14,0x17,0x5F,0x52,  /* 00001500    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001508    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x04,0x00,  /* 00001510    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001518    "....._SU" */
+    0x4E,0x0A,0x1A,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001520    "N..[..SL" */
+    0x32,0x37,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001528    "27._ADR." */
+    0x00,0x00,0x1B,0x00,0x14,0x17,0x5F,0x52,  /* 00001530    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001538    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x08,0x00,  /* 00001540    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001548    "....._SU" */
+    0x4E,0x0A,0x1B,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001550    "N..[..SL" */
+    0x32,0x38,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001558    "28._ADR." */
+    0x00,0x00,0x1C,0x00,0x14,0x17,0x5F,0x52,  /* 00001560    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001568    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x10,0x00,  /* 00001570    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001578    "....._SU" */
+    0x4E,0x0A,0x1C,0x5B,0x82,0x2E,0x53,0x4C,  /* 00001580    "N..[..SL" */
+    0x32,0x39,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00001588    "29._ADR." */
+    0x00,0x00,0x1D,0x00,0x14,0x17,0x5F,0x52,  /* 00001590    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 00001598    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x20,0x00,  /* 000015A0    "RM.... ." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000015A8    "....._SU" */
+    0x4E,0x0A,0x1D,0x5B,0x82,0x2E,0x53,0x4C,  /* 000015B0    "N..[..SL" */
+    0x33,0x30,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000015B8    "30._ADR." */
+    0x00,0x00,0x1E,0x00,0x14,0x17,0x5F,0x52,  /* 000015C0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000015C8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x40,0x00,  /* 000015D0    "RM.... at ." */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000015D8    "....._SU" */
+    0x4E,0x0A,0x1E,0x5B,0x82,0x2E,0x53,0x4C,  /* 000015E0    "N..[..SL" */
+    0x33,0x31,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000015E8    "31._ADR." */
+    0x00,0x00,0x1F,0x00,0x14,0x17,0x5F,0x52,  /* 000015F0    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,0x43,  /* 000015F8    "MV...{PC" */
+    0x52,0x4D,0x0C,0x00,0x00,0x00,0x80,0x00,  /* 00001600    "RM......" */
+    0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00001608    "....._SU" */
+    0x4E,0x0A,0x1F,0x10,0x4B,0x3C,0x5F,0x53,  /* 00001610    "N...K<_S" */
+    0x42,0x5F,0x5B,0x81,0x24,0x2F,0x03,0x50,  /* 00001618    "B_[.$/.P" */
+    0x43,0x49,0x30,0x49,0x53,0x41,0x5F,0x50,  /* 00001620    "CI0ISA_P" */
+    0x34,0x30,0x43,0x01,0x50,0x52,0x51,0x30,  /* 00001628    "40C.PRQ0" */
+    0x08,0x50,0x52,0x51,0x31,0x08,0x50,0x52,  /* 00001630    ".PRQ1.PR" */
+    0x51,0x32,0x08,0x50,0x52,0x51,0x33,0x08,  /* 00001638    "Q2.PRQ3." */
+    0x5B,0x82,0x4D,0x0B,0x4C,0x4E,0x4B,0x41,  /* 00001640    "[.M.LNKA" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 00001648    "._HID.A." */
+    0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x01,  /* 00001650    "..._UID." */
+    0x08,0x5F,0x50,0x52,0x53,0x11,0x16,0x0A,  /* 00001658    "._PRS..." */
+    0x13,0x89,0x0E,0x00,0x09,0x03,0x05,0x00,  /* 00001660    "........" */
+    0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,0x00,  /* 00001668    "........" */
+    0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,0x53,  /* 00001670    "..y..._S" */
+    0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,  /* 00001678    "TA.p..`." */
+    0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x30,  /* 00001680    ".{..PRQ0" */
+    0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,  /* 00001688    "ap..`.`." */
+    0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,  /* 00001690    "._DIS.}P" */
+    0x52,0x51,0x30,0x0A,0x80,0x50,0x52,0x51,  /* 00001698    "RQ0..PRQ" */
+    0x30,0x14,0x45,0x04,0x5F,0x43,0x52,0x53,  /* 000016A0    "0.E._CRS" */
+    0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x0E,  /* 000016A8    "..PRR0.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x01,  /* 000016B0    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x8A,0x50,0x52,  /* 000016B8    "...y..PR" */
+    0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,0x5F,  /* 000016C0    "R0..TMP_" */
+    0x70,0x50,0x52,0x51,0x30,0x60,0xA0,0x0B,  /* 000016C8    "pPRQ0`.." */
+    0x95,0x60,0x0A,0x80,0x70,0x60,0x54,0x4D,  /* 000016D0    ".`..p`TM" */
+    0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D,  /* 000016D8    "P_..p.TM" */
+    0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14,  /* 000016E0    "P_.PRR0." */
+    0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,0x68,  /* 000016E8    "._SRS..h" */
+    0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,0x54,  /* 000016F0    "..TMP_pT" */
+    0x4D,0x50,0x5F,0x50,0x52,0x51,0x30,0x5B,  /* 000016F8    "MP_PRQ0[" */
+    0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x42,0x08,  /* 00001700    ".N.LNKB." */
+    0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,  /* 00001708    "_HID.A.." */
+    0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x02,  /* 00001710    ".._UID.." */
+    0x08,0x5F,0x50,0x52,0x53,0x11,0x16,0x0A,  /* 00001718    "._PRS..." */
+    0x13,0x89,0x0E,0x00,0x09,0x03,0x05,0x00,  /* 00001720    "........" */
+    0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,0x00,  /* 00001728    "........" */
+    0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,0x53,  /* 00001730    "..y..._S" */
+    0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,  /* 00001738    "TA.p..`." */
+    0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,  /* 00001740    ".{..PRQ1" */
+    0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,  /* 00001748    "ap..`.`." */
+    0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,  /* 00001750    "._DIS.}P" */
+    0x52,0x51,0x31,0x0A,0x80,0x50,0x52,0x51,  /* 00001758    "RQ1..PRQ" */
+    0x31,0x14,0x45,0x04,0x5F,0x43,0x52,0x53,  /* 00001760    "1.E._CRS" */
+    0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x0E,  /* 00001768    "..PRR0.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x01,  /* 00001770    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x8A,0x50,0x52,  /* 00001778    "...y..PR" */
+    0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,0x5F,  /* 00001780    "R0..TMP_" */
+    0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0B,  /* 00001788    "pPRQ1`.." */
+    0x95,0x60,0x0A,0x80,0x70,0x60,0x54,0x4D,  /* 00001790    ".`..p`TM" */
+    0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D,  /* 00001798    "P_..p.TM" */
+    0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14,  /* 000017A0    "P_.PRR0." */
+    0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,0x68,  /* 000017A8    "._SRS..h" */
+    0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,0x54,  /* 000017B0    "..TMP_pT" */
+    0x4D,0x50,0x5F,0x50,0x52,0x51,0x31,0x5B,  /* 000017B8    "MP_PRQ1[" */
+    0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x43,0x08,  /* 000017C0    ".N.LNKC." */
+    0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,  /* 000017C8    "_HID.A.." */
+    0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x03,  /* 000017D0    ".._UID.." */
+    0x08,0x5F,0x50,0x52,0x53,0x11,0x16,0x0A,  /* 000017D8    "._PRS..." */
+    0x13,0x89,0x0E,0x00,0x09,0x03,0x05,0x00,  /* 000017E0    "........" */
+    0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,0x00,  /* 000017E8    "........" */
+    0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,0x53,  /* 000017F0    "..y..._S" */
+    0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,  /* 000017F8    "TA.p..`." */
+    0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32,  /* 00001800    ".{..PRQ2" */
+    0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,  /* 00001808    "ap..`.`." */
+    0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,  /* 00001810    "._DIS.}P" */
+    0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51,  /* 00001818    "RQ2..PRQ" */
+    0x32,0x14,0x45,0x04,0x5F,0x43,0x52,0x53,  /* 00001820    "2.E._CRS" */
+    0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x0E,  /* 00001828    "..PRR0.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x01,  /* 00001830    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x8A,0x50,0x52,  /* 00001838    "...y..PR" */
+    0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,0x5F,  /* 00001840    "R0..TMP_" */
+    0x70,0x50,0x52,0x51,0x32,0x60,0xA0,0x0B,  /* 00001848    "pPRQ2`.." */
+    0x95,0x60,0x0A,0x80,0x70,0x60,0x54,0x4D,  /* 00001850    ".`..p`TM" */
+    0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D,  /* 00001858    "P_..p.TM" */
+    0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14,  /* 00001860    "P_.PRR0." */
+    0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,0x68,  /* 00001868    "._SRS..h" */
+    0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,0x54,  /* 00001870    "..TMP_pT" */
+    0x4D,0x50,0x5F,0x50,0x52,0x51,0x32,0x5B,  /* 00001878    "MP_PRQ2[" */
+    0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x44,0x08,  /* 00001880    ".N.LNKD." */
+    0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,  /* 00001888    "_HID.A.." */
+    0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x04,  /* 00001890    ".._UID.." */
+    0x08,0x5F,0x50,0x52,0x53,0x11,0x16,0x0A,  /* 00001898    "._PRS..." */
+    0x13,0x89,0x0E,0x00,0x09,0x03,0x05,0x00,  /* 000018A0    "........" */
+    0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,0x00,  /* 000018A8    "........" */
+    0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,0x53,  /* 000018B0    "..y..._S" */
+    0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,  /* 000018B8    "TA.p..`." */
+    0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x33,  /* 000018C0    ".{..PRQ3" */
+    0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,  /* 000018C8    "ap..`.`." */
+    0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,  /* 000018D0    "._DIS.}P" */
+    0x52,0x51,0x33,0x0A,0x80,0x50,0x52,0x51,  /* 000018D8    "RQ3..PRQ" */
+    0x33,0x14,0x45,0x04,0x5F,0x43,0x52,0x53,  /* 000018E0    "3.E._CRS" */
+    0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x0E,  /* 000018E8    "..PRR0.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x01,  /* 000018F0    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x8A,0x50,0x52,  /* 000018F8    "...y..PR" */
+    0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,0x5F,  /* 00001900    "R0..TMP_" */
+    0x70,0x50,0x52,0x51,0x33,0x60,0xA0,0x0B,  /* 00001908    "pPRQ3`.." */
+    0x95,0x60,0x0A,0x80,0x70,0x60,0x54,0x4D,  /* 00001910    ".`..p`TM" */
+    0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D,  /* 00001918    "P_..p.TM" */
+    0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14,  /* 00001920    "P_.PRR0." */
+    0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,0x68,  /* 00001928    "._SRS..h" */
+    0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,0x54,  /* 00001930    "..TMP_pT" */
+    0x4D,0x50,0x5F,0x50,0x52,0x51,0x33,0x5B,  /* 00001938    "MP_PRQ3[" */
+    0x82,0x4E,0x09,0x4C,0x4E,0x4B,0x53,0x08,  /* 00001940    ".N.LNKS." */
+    0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,  /* 00001948    "_HID.A.." */
+    0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x05,  /* 00001950    ".._UID.." */
+    0x08,0x5F,0x50,0x52,0x53,0x11,0x0E,0x0A,  /* 00001958    "._PRS..." */
+    0x0B,0x89,0x06,0x00,0x09,0x01,0x09,0x00,  /* 00001960    "........" */
+    0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,0x53,  /* 00001968    "..y..._S" */
+    0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,  /* 00001970    "TA.p..`." */
+    0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x30,  /* 00001978    ".{..PRQ0" */
+    0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,  /* 00001980    "ap..`.`." */
+    0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,  /* 00001988    "._DIS.}P" */
+    0x52,0x51,0x30,0x0A,0x80,0x50,0x52,0x51,  /* 00001990    "RQ0..PRQ" */
+    0x30,0x14,0x45,0x04,0x5F,0x43,0x52,0x53,  /* 00001998    "0.E._CRS" */
+    0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x0E,  /* 000019A0    "..PRR0.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x09,  /* 000019A8    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x8A,0x50,0x52,  /* 000019B0    "...y..PR" */
+    0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,0x5F,  /* 000019B8    "R0..TMP_" */
+    0x70,0x50,0x52,0x51,0x30,0x60,0xA0,0x0B,  /* 000019C0    "pPRQ0`.." */
+    0x95,0x60,0x0A,0x80,0x70,0x60,0x54,0x4D,  /* 000019C8    ".`..p`TM" */
+    0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D,  /* 000019D0    "P_..p.TM" */
+    0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x08,  /* 000019D8    "P_.PRR0." */
+    0x5F,0x53,0x33,0x5F,0x12,0x06,0x04,0x01,  /* 000019E0    "_S3_...." */
+    0x01,0x00,0x00,0x08,0x5F,0x53,0x34,0x5F,  /* 000019E8    "...._S4_" */
+    0x12,0x06,0x04,0x00,0x00,0x00,0x00,0x08,  /* 000019F0    "........" */
+    0x5F,0x53,0x35,0x5F,0x12,0x06,0x04,0x00,  /* 000019F8    "_S5_...." */
+    0x00,0x00,0x00,0x10,0x49,0x0E,0x5F,0x53,  /* 00001A00    "....I._S" */
+    0x42,0x5F,0x14,0x35,0x43,0x50,0x4D,0x41,  /* 00001A08    "B_.5CPMA" */
+    0x01,0x70,0x83,0x88,0x43,0x50,0x4F,0x4E,  /* 00001A10    ".p..CPON" */
+    0x68,0x00,0x60,0x70,0x11,0x0B,0x0A,0x08,  /* 00001A18    "h.`p...." */
+    0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,  /* 00001A20    "........" */
+    0x61,0x70,0x68,0x88,0x61,0x0A,0x02,0x00,  /* 00001A28    "aph.a..." */
+    0x70,0x68,0x88,0x61,0x0A,0x03,0x00,0x70,  /* 00001A30    "ph.a...p" */
+    0x60,0x88,0x61,0x0A,0x04,0x00,0xA4,0x61,  /* 00001A38    "`.a....a" */
+    0x14,0x1A,0x43,0x50,0x53,0x54,0x01,0x70,  /* 00001A40    "..CPST.p" */
+    0x83,0x88,0x43,0x50,0x4F,0x4E,0x68,0x00,  /* 00001A48    "..CPONh." */
+    0x60,0xA0,0x05,0x60,0xA4,0x0A,0x0F,0xA1,  /* 00001A50    "`..`...." */
+    0x03,0xA4,0x00,0x14,0x0A,0x43,0x50,0x45,  /* 00001A58    ".....CPE" */
+    0x4A,0x02,0x5B,0x22,0x0A,0xC8,0x5B,0x80,  /* 00001A60    "J.["..[." */
+    0x50,0x52,0x53,0x54,0x01,0x0B,0x00,0xAF,  /* 00001A68    "PRST...." */
+    0x0A,0x20,0x5B,0x81,0x0C,0x50,0x52,0x53,  /* 00001A70    ". [..PRS" */
+    0x54,0x01,0x50,0x52,0x53,0x5F,0x40,0x10,  /* 00001A78    "T.PRS_ at ." */
+    0x14,0x4C,0x06,0x50,0x52,0x53,0x43,0x00,  /* 00001A80    ".L.PRSC." */
+    0x70,0x50,0x52,0x53,0x5F,0x65,0x70,0x00,  /* 00001A88    "pPRS_ep." */
+    0x62,0x70,0x00,0x60,0xA2,0x46,0x05,0x95,  /* 00001A90    "bp.`.F.." */
+    0x60,0x87,0x43,0x50,0x4F,0x4E,0x70,0x83,  /* 00001A98    "`.CPONp." */
+    0x88,0x43,0x50,0x4F,0x4E,0x60,0x00,0x61,  /* 00001AA0    ".CPON`.a" */
+    0xA0,0x0A,0x7B,0x60,0x0A,0x07,0x00,0x7A,  /* 00001AA8    "..{`...z" */
+    0x62,0x01,0x62,0xA1,0x0C,0x70,0x83,0x88,  /* 00001AB0    "b.b..p.." */
+    0x65,0x7A,0x60,0x0A,0x03,0x00,0x00,0x62,  /* 00001AB8    "ez`....b" */
+    0x70,0x7B,0x62,0x01,0x00,0x63,0xA0,0x22,  /* 00001AC0    "p{b..c."" */
+    0x92,0x93,0x61,0x63,0x70,0x63,0x88,0x43,  /* 00001AC8    "..acpc.C" */
+    0x50,0x4F,0x4E,0x60,0x00,0xA0,0x0A,0x93,  /* 00001AD0    "PON`...." */
+    0x63,0x01,0x4E,0x54,0x46,0x59,0x60,0x01,  /* 00001AD8    "c.NTFY`." */
+    0xA1,0x08,0x4E,0x54,0x46,0x59,0x60,0x0A,  /* 00001AE0    "..NTFY`." */
+    0x03,0x75,0x60,0xA4,0x01,0x10,0x42,0xA7,  /* 00001AE8    ".u`...B." */
+    0x5F,0x47,0x50,0x45,0x08,0x5F,0x48,0x49,  /* 00001AF0    "_GPE._HI" */
+    0x44,0x0D,0x41,0x43,0x50,0x49,0x30,0x30,  /* 00001AF8    "D.ACPI00" */
+    0x30,0x36,0x00,0x14,0x08,0x5F,0x4C,0x30,  /* 00001B00    "06..._L0" */
+    0x30,0x00,0xA4,0x01,0x14,0x4C,0x9C,0x5F,  /* 00001B08    "0....L._" */
+    0x4C,0x30,0x31,0x00,0xA0,0x25,0x7B,0x5C,  /* 00001B10    "L01..%{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001B18    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0A,0x02,  /* 00001B20    "I0PCIU.." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001B28    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x5F,  /* 00001B30    "_PCI0S1_" */
+    0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,  /* 00001B38    "_..&{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001B40    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0A,0x02,0x00,0x86,  /* 00001B48    "PCID...." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001B50    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x5F,0x5F,0x0A,  /* 00001B58    "CI0S1__." */
+    0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001B60    "..%{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001B68    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0A,0x04,0x00,0x86,0x5C,  /* 00001B70    "CIU....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001B78    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x5F,0x5F,0x01,0xA0,  /* 00001B80    "I0S2__.." */
+    0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001B88    "&{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001B90    "_PCI0PCI" */
+    0x44,0x0A,0x04,0x00,0x86,0x5C,0x2F,0x03,  /* 00001B98    "D....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001BA0    "_SB_PCI0" */
+    0x53,0x32,0x5F,0x5F,0x0A,0x03,0xA0,0x25,  /* 00001BA8    "S2__...%" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001BB0    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00001BB8    "PCI0PCIU" */
+    0x0A,0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001BC0    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001BC8    "SB_PCI0S" */
+    0x33,0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,  /* 00001BD0    "3__..&{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001BD8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0A,0x08,  /* 00001BE0    "I0PCID.." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001BE8    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x33,0x5F,  /* 00001BF0    "_PCI0S3_" */
+    0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,  /* 00001BF8    "_...%{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001C00    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0A,0x10,0x00,  /* 00001C08    "0PCIU..." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001C10    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x34,0x5F,0x5F,  /* 00001C18    "PCI0S4__" */
+    0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001C20    "..&{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001C28    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0A,0x10,0x00,0x86,0x5C,  /* 00001C30    "CID....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001C38    "/._SB_PC" */
+    0x49,0x30,0x53,0x34,0x5F,0x5F,0x0A,0x03,  /* 00001C40    "I0S4__.." */
+    0xA0,0x25,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001C48    ".%{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001C50    "B_PCI0PC" */
+    0x49,0x55,0x0A,0x20,0x00,0x86,0x5C,0x2F,  /* 00001C58    "IU. ..\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001C60    "._SB_PCI" */
+    0x30,0x53,0x35,0x5F,0x5F,0x01,0xA0,0x26,  /* 00001C68    "0S5__..&" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001C70    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00001C78    "PCI0PCID" */
+    0x0A,0x20,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001C80    ". ..\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001C88    "SB_PCI0S" */
+    0x35,0x5F,0x5F,0x0A,0x03,0xA0,0x25,0x7B,  /* 00001C90    "5__...%{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001C98    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0A,  /* 00001CA0    "CI0PCIU." */
+    0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001CA8    "@..\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x36,  /* 00001CB0    "B_PCI0S6" */
+    0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,  /* 00001CB8    "__..&{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001CC0    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0A,0x40,0x00,  /* 00001CC8    "0PCID. at ." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001CD0    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x36,0x5F,0x5F,  /* 00001CD8    "PCI0S6__" */
+    0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,  /* 00001CE0    "...%{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001CE8    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0A,0x80,0x00,0x86,  /* 00001CF0    "PCIU...." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001CF8    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x37,0x5F,0x5F,0x01,  /* 00001D00    "CI0S7__." */
+    0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001D08    ".&{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001D10    "B_PCI0PC" */
+    0x49,0x44,0x0A,0x80,0x00,0x86,0x5C,0x2F,  /* 00001D18    "ID....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001D20    "._SB_PCI" */
+    0x30,0x53,0x37,0x5F,0x5F,0x0A,0x03,0xA0,  /* 00001D28    "0S7__..." */
+    0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001D30    "&{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001D38    "_PCI0PCI" */
+    0x55,0x0B,0x00,0x01,0x00,0x86,0x5C,0x2F,  /* 00001D40    "U.....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001D48    "._SB_PCI" */
+    0x30,0x53,0x38,0x5F,0x5F,0x01,0xA0,0x27,  /* 00001D50    "0S8__..'" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001D58    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00001D60    "PCI0PCID" */
+    0x0B,0x00,0x01,0x00,0x86,0x5C,0x2F,0x03,  /* 00001D68    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001D70    "_SB_PCI0" */
+    0x53,0x38,0x5F,0x5F,0x0A,0x03,0xA0,0x26,  /* 00001D78    "S8__...&" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001D80    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00001D88    "PCI0PCIU" */
+    0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,  /* 00001D90    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001D98    "_SB_PCI0" */
+    0x53,0x39,0x5F,0x5F,0x01,0xA0,0x27,0x7B,  /* 00001DA0    "S9__..'{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001DA8    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0B,  /* 00001DB0    "CI0PCID." */
+    0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001DB8    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001DC0    "SB_PCI0S" */
+    0x39,0x5F,0x5F,0x0A,0x03,0xA0,0x26,0x7B,  /* 00001DC8    "9__...&{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001DD0    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0B,  /* 00001DD8    "CI0PCIU." */
+    0x00,0x04,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001DE0    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001DE8    "SB_PCI0S" */
+    0x31,0x30,0x5F,0x01,0xA0,0x27,0x7B,0x5C,  /* 00001DF0    "10_..'{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001DF8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0B,0x00,  /* 00001E00    "I0PCID.." */
+    0x04,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001E08    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00001E10    "B_PCI0S1" */
+    0x30,0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,  /* 00001E18    "0_...&{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001E20    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0B,0x00,  /* 00001E28    "I0PCIU.." */
+    0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001E30    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00001E38    "B_PCI0S1" */
+    0x31,0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,  /* 00001E40    "1_..'{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001E48    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0B,0x00,0x08,  /* 00001E50    "0PCID..." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001E58    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x31,  /* 00001E60    "_PCI0S11" */
+    0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,  /* 00001E68    "_...&{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001E70    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0B,0x00,0x10,  /* 00001E78    "0PCIU..." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001E80    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x32,  /* 00001E88    "_PCI0S12" */
+    0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,  /* 00001E90    "_..'{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001E98    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0B,0x00,0x10,0x00,  /* 00001EA0    "PCID...." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001EA8    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x32,0x5F,  /* 00001EB0    "PCI0S12_" */
+    0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,  /* 00001EB8    "...&{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001EC0    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0B,0x00,0x20,0x00,  /* 00001EC8    "PCIU.. ." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001ED0    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x33,0x5F,  /* 00001ED8    "PCI0S13_" */
+    0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001EE0    "..'{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001EE8    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0B,0x00,0x20,0x00,0x86,  /* 00001EF0    "CID.. .." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001EF8    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x33,0x5F,0x0A,  /* 00001F00    "CI0S13_." */
+    0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001F08    "..&{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001F10    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0B,0x00,0x40,0x00,0x86,  /* 00001F18    "CIU.. at .." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001F20    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x34,0x5F,0x01,  /* 00001F28    "CI0S14_." */
+    0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001F30    ".'{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001F38    "B_PCI0PC" */
+    0x49,0x44,0x0B,0x00,0x40,0x00,0x86,0x5C,  /* 00001F40    "ID.. at ..\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001F48    "/._SB_PC" */
+    0x49,0x30,0x53,0x31,0x34,0x5F,0x0A,0x03,  /* 00001F50    "I0S14_.." */
+    0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001F58    ".&{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001F60    "B_PCI0PC" */
+    0x49,0x55,0x0B,0x00,0x80,0x00,0x86,0x5C,  /* 00001F68    "IU.....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001F70    "/._SB_PC" */
+    0x49,0x30,0x53,0x31,0x35,0x5F,0x01,0xA0,  /* 00001F78    "I0S15_.." */
+    0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001F80    "'{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001F88    "_PCI0PCI" */
+    0x44,0x0B,0x00,0x80,0x00,0x86,0x5C,0x2F,  /* 00001F90    "D.....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001F98    "._SB_PCI" */
+    0x30,0x53,0x31,0x35,0x5F,0x0A,0x03,0xA0,  /* 00001FA0    "0S15_..." */
+    0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001FA8    "({\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001FB0    "_PCI0PCI" */
+    0x55,0x0C,0x00,0x00,0x01,0x00,0x00,0x86,  /* 00001FB8    "U......." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001FC0    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x36,0x5F,0x01,  /* 00001FC8    "CI0S16_." */
+    0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001FD0    ".){\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001FD8    "B_PCI0PC" */
+    0x49,0x44,0x0C,0x00,0x00,0x01,0x00,0x00,  /* 00001FE0    "ID......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001FE8    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x36,0x5F,  /* 00001FF0    "PCI0S16_" */
+    0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,  /* 00001FF8    "...({\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002000    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x02,  /* 00002008    "PCIU...." */
+    0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002010    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00002018    "B_PCI0S1" */
+    0x37,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,  /* 00002020    "7_..){\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002028    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00,  /* 00002030    "0PCID..." */
+    0x02,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00002038    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00002040    "SB_PCI0S" */
+    0x31,0x37,0x5F,0x0A,0x03,0xA0,0x28,0x7B,  /* 00002048    "17_...({" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002050    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C,  /* 00002058    "CI0PCIU." */
+    0x00,0x00,0x04,0x00,0x00,0x86,0x5C,0x2F,  /* 00002060    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002068    "._SB_PCI" */
+    0x30,0x53,0x31,0x38,0x5F,0x01,0xA0,0x29,  /* 00002070    "0S18_..)" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002078    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00002080    "PCI0PCID" */
+    0x0C,0x00,0x00,0x04,0x00,0x00,0x86,0x5C,  /* 00002088    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002090    "/._SB_PC" */
+    0x49,0x30,0x53,0x31,0x38,0x5F,0x0A,0x03,  /* 00002098    "I0S18_.." */
+    0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 000020A0    ".({\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 000020A8    "B_PCI0PC" */
+    0x49,0x55,0x0C,0x00,0x00,0x08,0x00,0x00,  /* 000020B0    "IU......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 000020B8    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x39,0x5F,  /* 000020C0    "PCI0S19_" */
+    0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,  /* 000020C8    "..){\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 000020D0    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0C,0x00,0x00,0x08,0x00,  /* 000020D8    "CID....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 000020E0    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x39,  /* 000020E8    "_PCI0S19" */
+    0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,  /* 000020F0    "_...({\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000020F8    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00,  /* 00002100    "0PCIU..." */
+    0x10,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00002108    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00002110    "SB_PCI0S" */
+    0x32,0x30,0x5F,0x01,0xA0,0x29,0x7B,0x5C,  /* 00002118    "20_..){\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002120    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00,  /* 00002128    "I0PCID.." */
+    0x00,0x10,0x00,0x00,0x86,0x5C,0x2F,0x03,  /* 00002130    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002138    "_SB_PCI0" */
+    0x53,0x32,0x30,0x5F,0x0A,0x03,0xA0,0x28,  /* 00002140    "S20_...(" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002148    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00002150    "PCI0PCIU" */
+    0x0C,0x00,0x00,0x20,0x00,0x00,0x86,0x5C,  /* 00002158    "... ...\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002160    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x31,0x5F,0x01,0xA0,  /* 00002168    "I0S21_.." */
+    0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002170    "){\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002178    "_PCI0PCI" */
+    0x44,0x0C,0x00,0x00,0x20,0x00,0x00,0x86,  /* 00002180    "D... ..." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002188    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x31,0x5F,0x0A,  /* 00002190    "CI0S21_." */
+    0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00002198    "..({\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 000021A0    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0C,0x00,0x00,0x40,0x00,  /* 000021A8    "CIU... at ." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 000021B0    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x32,  /* 000021B8    "_PCI0S22" */
+    0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,  /* 000021C0    "_..){\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000021C8    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x40,  /* 000021D0    "PCID...@" */
+    0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 000021D8    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32,  /* 000021E0    "B_PCI0S2" */
+    0x32,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,  /* 000021E8    "2_...({\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000021F0    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00,  /* 000021F8    "I0PCIU.." */
+    0x00,0x80,0x00,0x00,0x86,0x5C,0x2F,0x03,  /* 00002200    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002208    "_SB_PCI0" */
+    0x53,0x32,0x33,0x5F,0x01,0xA0,0x29,0x7B,  /* 00002210    "S23_..){" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002218    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C,  /* 00002220    "CI0PCID." */
+    0x00,0x00,0x80,0x00,0x00,0x86,0x5C,0x2F,  /* 00002228    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002230    "._SB_PCI" */
+    0x30,0x53,0x32,0x33,0x5F,0x0A,0x03,0xA0,  /* 00002238    "0S23_..." */
+    0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002240    "({\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002248    "_PCI0PCI" */
+    0x55,0x0C,0x00,0x00,0x00,0x01,0x00,0x86,  /* 00002250    "U......." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002258    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x34,0x5F,0x01,  /* 00002260    "CI0S24_." */
+    0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002268    ".){\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00002270    "B_PCI0PC" */
+    0x49,0x44,0x0C,0x00,0x00,0x00,0x01,0x00,  /* 00002278    "ID......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002280    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x32,0x34,0x5F,  /* 00002288    "PCI0S24_" */
+    0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,  /* 00002290    "...({\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002298    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x00,  /* 000022A0    "PCIU...." */
+    0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 000022A8    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32,  /* 000022B0    "B_PCI0S2" */
+    0x35,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,  /* 000022B8    "5_..){\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000022C0    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00,  /* 000022C8    "0PCID..." */
+    0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 000022D0    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 000022D8    "SB_PCI0S" */
+    0x32,0x35,0x5F,0x0A,0x03,0xA0,0x28,0x7B,  /* 000022E0    "25_...({" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 000022E8    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C,  /* 000022F0    "CI0PCIU." */
+    0x00,0x00,0x00,0x04,0x00,0x86,0x5C,0x2F,  /* 000022F8    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002300    "._SB_PCI" */
+    0x30,0x53,0x32,0x36,0x5F,0x01,0xA0,0x29,  /* 00002308    "0S26_..)" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002310    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00002318    "PCI0PCID" */
+    0x0C,0x00,0x00,0x00,0x04,0x00,0x86,0x5C,  /* 00002320    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002328    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x36,0x5F,0x0A,0x03,  /* 00002330    "I0S26_.." */
+    0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002338    ".({\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00002340    "B_PCI0PC" */
+    0x49,0x55,0x0C,0x00,0x00,0x00,0x08,0x00,  /* 00002348    "IU......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002350    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x32,0x37,0x5F,  /* 00002358    "PCI0S27_" */
+    0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00002360    "..){\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00002368    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0C,0x00,0x00,0x00,0x08,  /* 00002370    "CID....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002378    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x37,  /* 00002380    "_PCI0S27" */
+    0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,  /* 00002388    "_...({\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002390    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00,  /* 00002398    "0PCIU..." */
+    0x00,0x10,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 000023A0    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 000023A8    "SB_PCI0S" */
+    0x32,0x38,0x5F,0x01,0xA0,0x29,0x7B,0x5C,  /* 000023B0    "28_..){\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000023B8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00,  /* 000023C0    "I0PCID.." */
+    0x00,0x00,0x10,0x00,0x86,0x5C,0x2F,0x03,  /* 000023C8    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000023D0    "_SB_PCI0" */
+    0x53,0x32,0x38,0x5F,0x0A,0x03,0xA0,0x28,  /* 000023D8    "S28_...(" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 000023E0    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 000023E8    "PCI0PCIU" */
+    0x0C,0x00,0x00,0x00,0x20,0x00,0x86,0x5C,  /* 000023F0    ".... ..\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000023F8    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x39,0x5F,0x01,0xA0,  /* 00002400    "I0S29_.." */
+    0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002408    "){\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002410    "_PCI0PCI" */
+    0x44,0x0C,0x00,0x00,0x00,0x20,0x00,0x86,  /* 00002418    "D.... .." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002420    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x39,0x5F,0x0A,  /* 00002428    "CI0S29_." */
+    0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00002430    "..({\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00002438    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0C,0x00,0x00,0x00,0x40,  /* 00002440    "CIU....@" */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002448    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x33,0x30,  /* 00002450    "_PCI0S30" */
+    0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,  /* 00002458    "_..){\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002460    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x00,  /* 00002468    "PCID...." */
+    0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002470    "@..\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33,  /* 00002478    "B_PCI0S3" */
+    0x30,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,  /* 00002480    "0_...({\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002488    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00,  /* 00002490    "I0PCIU.." */
+    0x00,0x00,0x80,0x00,0x86,0x5C,0x2F,0x03,  /* 00002498    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000024A0    "_SB_PCI0" */
+    0x53,0x33,0x31,0x5F,0x01,0xA0,0x29,0x7B,  /* 000024A8    "S31_..){" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 000024B0    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C,  /* 000024B8    "CI0PCID." */
+    0x00,0x00,0x00,0x80,0x00,0x86,0x5C,0x2F,  /* 000024C0    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000024C8    "._SB_PCI" */
+    0x30,0x53,0x33,0x31,0x5F,0x0A,0x03,0xA4,  /* 000024D0    "0S31_..." */
+    0x01,0x14,0x11,0x5F,0x4C,0x30,0x32,0x00,  /* 000024D8    "..._L02." */
+    0xA4,0x5C,0x2E,0x5F,0x53,0x42,0x5F,0x50,  /* 000024E0    ".\._SB_P" */
+    0x52,0x53,0x43,0x14,0x08,0x5F,0x4C,0x30,  /* 000024E8    "RSC.._L0" */
+    0x33,0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,  /* 000024F0    "3....._L" */
+    0x30,0x34,0x00,0xA4,0x01,0x14,0x08,0x5F,  /* 000024F8    "04....._" */
+    0x4C,0x30,0x35,0x00,0xA4,0x01,0x14,0x08,  /* 00002500    "L05....." */
+    0x5F,0x4C,0x30,0x36,0x00,0xA4,0x01,0x14,  /* 00002508    "_L06...." */
+    0x08,0x5F,0x4C,0x30,0x37,0x00,0xA4,0x01,  /* 00002510    "._L07..." */
+    0x14,0x08,0x5F,0x4C,0x30,0x38,0x00,0xA4,  /* 00002518    ".._L08.." */
+    0x01,0x14,0x08,0x5F,0x4C,0x30,0x39,0x00,  /* 00002520    "..._L09." */
+    0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,0x41,  /* 00002528    "...._L0A" */
+    0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,  /* 00002530    "....._L0" */
+    0x42,0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,  /* 00002538    "B....._L" */
+    0x30,0x43,0x00,0xA4,0x01,0x14,0x08,0x5F,  /* 00002540    "0C....._" */
+    0x4C,0x30,0x44,0x00,0xA4,0x01,0x14,0x08,  /* 00002548    "L0D....." */
+    0x5F,0x4C,0x30,0x45,0x00,0xA4,0x01,0x14,  /* 00002550    "_L0E...." */
+    0x08,0x5F,0x4C,0x30,0x46,0x00,0xA4,0x01   /* 00002558    "._L0F..." */
+};
diff --git a/qemu-0.15.x/roms/seabios/src/acpi.c b/qemu-0.15.x/roms/seabios/src/acpi.c
new file mode 100644
index 0000000..6428d9c
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/acpi.c
@@ -0,0 +1,694 @@
+// Support for generating ACPI tables (on emulators)
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "acpi.h" // struct rsdp_descriptor
+#include "util.h" // memcpy
+#include "pci.h" // pci_find_device
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "paravirt.h"
+#include "dev-i440fx.h" // piix4_fadt_init
+
+/****************************************************/
+/* ACPI tables init */
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+   BSD license) */
+
+struct acpi_table_header         /* ACPI common table header */
+{
+    ACPI_TABLE_HEADER_DEF
+} PACKED;
+
+/*
+ * ACPI 1.0 Root System Description Table (RSDT)
+ */
+#define RSDT_SIGNATURE 0x54445352 // RSDT
+struct rsdt_descriptor_rev1
+{
+    ACPI_TABLE_HEADER_DEF       /* ACPI common table header */
+    u32 table_offset_entry[0];  /* Array of pointers to other */
+    /* ACPI tables */
+} PACKED;
+
+/*
+ * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ */
+#define FACS_SIGNATURE 0x53434146 // FACS
+struct facs_descriptor_rev1
+{
+    u32 signature;           /* ACPI Signature */
+    u32 length;                 /* Length of structure, in bytes */
+    u32 hardware_signature;     /* Hardware configuration signature */
+    u32 firmware_waking_vector; /* ACPI OS waking vector */
+    u32 global_lock;            /* Global Lock */
+    u32 S4bios_f        : 1;    /* Indicates if S4BIOS support is present */
+    u32 reserved1       : 31;   /* Must be 0 */
+    u8  resverved3 [40];        /* Reserved - must be zero */
+} PACKED;
+
+
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC                0
+#define MULTIPLE_APIC           1
+
+
+/* Master MADT */
+
+#define APIC_SIGNATURE 0x43495041 // APIC
+struct multiple_apic_table
+{
+    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
+    u32 local_apic_address;     /* Physical address of local APIC */
+#if 0
+    u32 PCATcompat      : 1;    /* A one indicates system also has dual 8259s */
+    u32 reserved1       : 31;
+#else
+    u32 flags;
+#endif
+} PACKED;
+
+
+/* Values for Type in APIC sub-headers */
+
+#define APIC_PROCESSOR          0
+#define APIC_IO                 1
+#define APIC_XRUPT_OVERRIDE     2
+#define APIC_NMI                3
+#define APIC_LOCAL_NMI          4
+#define APIC_ADDRESS_OVERRIDE   5
+#define APIC_IO_SAPIC           6
+#define APIC_LOCAL_SAPIC        7
+#define APIC_XRUPT_SOURCE       8
+#define APIC_RESERVED           9           /* 9 and greater are reserved */
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+#define ACPI_SUB_HEADER_DEF   /* Common ACPI sub-structure header */\
+    u8  type;                               \
+    u8  length;
+
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
+{
+    ACPI_SUB_HEADER_DEF
+    u8  processor_id;           /* ACPI processor id */
+    u8  local_apic_id;          /* Processor's local APIC id */
+#if 0
+    u32 processor_enabled: 1;   /* Processor is usable if set */
+    u32 reserved2       : 31;   /* Reserved, must be zero */
+#else
+    u32 flags;
+#endif
+} PACKED;
+
+struct madt_io_apic
+{
+    ACPI_SUB_HEADER_DEF
+    u8  io_apic_id;             /* I/O APIC ID */
+    u8  reserved;               /* Reserved - must be zero */
+    u32 address;                /* APIC physical address */
+    u32 interrupt;              /* Global system interrupt where INTI
+                                 * lines start */
+} PACKED;
+
+/* IRQs 5,9,10,11 */
+#define PCI_ISA_IRQ_MASK    0x0e20
+
+struct madt_intsrcovr {
+    ACPI_SUB_HEADER_DEF
+    u8  bus;
+    u8  source;
+    u32 gsi;
+    u16 flags;
+} PACKED;
+
+/*
+ * ACPI 2.0 Generic Address Space definition.
+ */
+struct acpi_20_generic_address {
+    u8  address_space_id;
+    u8  register_bit_width;
+    u8  register_bit_offset;
+    u8  reserved;
+    u64 address;
+} PACKED;
+
+/*
+ * HPET Description Table
+ */
+struct acpi_20_hpet {
+    ACPI_TABLE_HEADER_DEF                    /* ACPI common table header */
+    u32           timer_block_id;
+    struct acpi_20_generic_address addr;
+    u8            hpet_number;
+    u16           min_tick;
+    u8            page_protect;
+} PACKED;
+#define ACPI_HPET_ADDRESS 0xFED00000UL
+
+/*
+ * SRAT (NUMA topology description) table
+ */
+
+#define SRAT_PROCESSOR          0
+#define SRAT_MEMORY             1
+
+struct system_resource_affinity_table
+{
+    ACPI_TABLE_HEADER_DEF
+    u32    reserved1;
+    u32    reserved2[2];
+} PACKED;
+
+struct srat_processor_affinity
+{
+    ACPI_SUB_HEADER_DEF
+    u8     proximity_lo;
+    u8     local_apic_id;
+    u32    flags;
+    u8     local_sapic_eid;
+    u8     proximity_hi[3];
+    u32    reserved;
+} PACKED;
+
+struct srat_memory_affinity
+{
+    ACPI_SUB_HEADER_DEF
+    u8     proximity[4];
+    u16    reserved1;
+    u32    base_addr_low,base_addr_high;
+    u32    length_low,length_high;
+    u32    reserved2;
+    u32    flags;
+    u32    reserved3[2];
+} PACKED;
+
+#include "acpi-dsdt.hex"
+
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
+{
+    h->signature = sig;
+    h->length = cpu_to_le32(len);
+    h->revision = rev;
+    memcpy(h->oem_id, CONFIG_APPNAME6, 6);
+    memcpy(h->oem_table_id, CONFIG_APPNAME4, 4);
+    memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4);
+    memcpy(h->oem_table_id + 4, (void*)&sig, 4);
+    h->oem_revision = cpu_to_le32(1);
+    h->asl_compiler_revision = cpu_to_le32(1);
+    h->checksum -= checksum(h, len);
+}
+
+static const struct pci_device_id fadt_init_tbl[] = {
+    /* PIIX4 Power Management device (for ACPI) */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+               piix4_fadt_init),
+
+    PCI_DEVICE_END
+};
+
+static void*
+build_fadt(int bdf)
+{
+    struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+    struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
+    void *dsdt = malloc_high(sizeof(AmlCode));
+
+    if (!fadt || !facs || !dsdt) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    /* FACS */
+    memset(facs, 0, sizeof(*facs));
+    facs->signature = FACS_SIGNATURE;
+    facs->length = cpu_to_le32(sizeof(*facs));
+
+    /* DSDT */
+    memcpy(dsdt, AmlCode, sizeof(AmlCode));
+
+    /* FADT */
+    memset(fadt, 0, sizeof(*fadt));
+    fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+    fadt->dsdt = cpu_to_le32((u32)dsdt);
+    fadt->model = 1;
+    fadt->reserved1 = 0;
+    int pm_sci_int = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+    fadt->sci_int = cpu_to_le16(pm_sci_int);
+    fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+    fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+    fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+    fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+    fadt->pm1_evt_len = 4;
+    fadt->pm1_cnt_len = 2;
+    fadt->pm_tmr_len = 4;
+    fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+    fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+    pci_init_device(fadt_init_tbl, bdf, fadt);
+    /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+    fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+
+    build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
+
+    return fadt;
+}
+
+static void*
+build_madt(void)
+{
+    int madt_size = (sizeof(struct multiple_apic_table)
+                     + sizeof(struct madt_processor_apic) * MaxCountCPUs
+                     + sizeof(struct madt_io_apic)
+                     + sizeof(struct madt_intsrcovr) * 16);
+    struct multiple_apic_table *madt = malloc_high(madt_size);
+    if (!madt) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(madt, 0, madt_size);
+    madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+    madt->flags = cpu_to_le32(1);
+    struct madt_processor_apic *apic = (void*)&madt[1];
+    int i;
+    for (i=0; i<MaxCountCPUs; i++) {
+        apic->type = APIC_PROCESSOR;
+        apic->length = sizeof(*apic);
+        apic->processor_id = i;
+        apic->local_apic_id = i;
+        if (i < CountCPUs)
+            apic->flags = cpu_to_le32(1);
+        else
+            apic->flags = cpu_to_le32(0);
+        apic++;
+    }
+    struct madt_io_apic *io_apic = (void*)apic;
+    io_apic->type = APIC_IO;
+    io_apic->length = sizeof(*io_apic);
+    io_apic->io_apic_id = CountCPUs;
+    io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+    io_apic->interrupt = cpu_to_le32(0);
+
+    struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
+    if (qemu_cfg_irq0_override()) {
+        memset(intsrcovr, 0, sizeof(*intsrcovr));
+        intsrcovr->type   = APIC_XRUPT_OVERRIDE;
+        intsrcovr->length = sizeof(*intsrcovr);
+        intsrcovr->source = 0;
+        intsrcovr->gsi    = 2;
+        intsrcovr->flags  = 0; /* conforms to bus specifications */
+        intsrcovr++;
+    }
+    for (i = 1; i < 16; i++) {
+        if (!(PCI_ISA_IRQ_MASK & (1 << i)))
+            /* No need for a INT source override structure. */
+            continue;
+        memset(intsrcovr, 0, sizeof(*intsrcovr));
+        intsrcovr->type   = APIC_XRUPT_OVERRIDE;
+        intsrcovr->length = sizeof(*intsrcovr);
+        intsrcovr->source = i;
+        intsrcovr->gsi    = i;
+        intsrcovr->flags  = 0xd; /* active high, level triggered */
+        intsrcovr++;
+    }
+
+    build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt, 1);
+    return madt;
+}
+
+// Encode a hex value
+static inline char getHex(u32 val) {
+    val &= 0x0f;
+    return (val <= 9) ? ('0' + val) : ('A' + val - 10);
+}
+
+// Encode a length in an SSDT.
+static u8 *
+encodeLen(u8 *ssdt_ptr, int length, int bytes)
+{
+    switch (bytes) {
+    default:
+    case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
+    case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
+    case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
+            ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
+            break;
+    case 1: ssdt_ptr[0] = length & 0x3f;
+    }
+    return ssdt_ptr + bytes;
+}
+
+// AML Processor() object.  See src/ssdt-proc.dsl for info.
+static unsigned char ssdt_proc[] = {
+    0x5b,0x83,0x42,0x05,0x43,0x50,0x41,0x41,
+    0xaa,0x10,0xb0,0x00,0x00,0x06,0x08,0x49,
+    0x44,0x5f,0x5f,0x0a,0xaa,0x08,0x5f,0x48,
+    0x49,0x44,0x0d,0x41,0x43,0x50,0x49,0x30,
+    0x30,0x30,0x37,0x00,0x14,0x0f,0x5f,0x4d,
+    0x41,0x54,0x00,0xa4,0x43,0x50,0x4d,0x41,
+    0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x53,
+    0x54,0x41,0x00,0xa4,0x43,0x50,0x53,0x54,
+    0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x45,
+    0x4a,0x30,0x01,0x43,0x50,0x45,0x4a,0x49,
+    0x44,0x5f,0x5f,0x68
+};
+#define SD_OFFSET_CPUHEX 6
+#define SD_OFFSET_CPUID1 8
+#define SD_OFFSET_CPUID2 20
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+static void*
+build_ssdt(void)
+{
+    int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+    // length = ScopeOp + procs + NTYF method + CPON package
+    int length = ((1+3+4)
+                  + (acpi_cpus * sizeof(ssdt_proc))
+                  + (1+2+5+(12*acpi_cpus))
+                  + (6+2+1+(1*acpi_cpus)));
+    u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length);
+    if (! ssdt) {
+        warn_noalloc();
+        return NULL;
+    }
+    u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header);
+
+    // build Scope(_SB_) header
+    *(ssdt_ptr++) = 0x10; // ScopeOp
+    ssdt_ptr = encodeLen(ssdt_ptr, length-1, 3);
+    *(ssdt_ptr++) = '_';
+    *(ssdt_ptr++) = 'S';
+    *(ssdt_ptr++) = 'B';
+    *(ssdt_ptr++) = '_';
+
+    // build Processor object for each processor
+    int i;
+    for (i=0; i<acpi_cpus; i++) {
+        memcpy(ssdt_ptr, ssdt_proc, sizeof(ssdt_proc));
+        ssdt_ptr[SD_OFFSET_CPUHEX] = getHex(i >> 4);
+        ssdt_ptr[SD_OFFSET_CPUHEX+1] = getHex(i);
+        ssdt_ptr[SD_OFFSET_CPUID1] = i;
+        ssdt_ptr[SD_OFFSET_CPUID2] = i;
+        ssdt_ptr += sizeof(ssdt_proc);
+    }
+
+    // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
+    *(ssdt_ptr++) = 0x14; // MethodOp
+    ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*acpi_cpus), 2);
+    *(ssdt_ptr++) = 'N';
+    *(ssdt_ptr++) = 'T';
+    *(ssdt_ptr++) = 'F';
+    *(ssdt_ptr++) = 'Y';
+    *(ssdt_ptr++) = 0x02;
+    for (i=0; i<acpi_cpus; i++) {
+        *(ssdt_ptr++) = 0xA0; // IfOp
+        ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
+        *(ssdt_ptr++) = 0x93; // LEqualOp
+        *(ssdt_ptr++) = 0x68; // Arg0Op
+        *(ssdt_ptr++) = 0x0A; // BytePrefix
+        *(ssdt_ptr++) = i;
+        *(ssdt_ptr++) = 0x86; // NotifyOp
+        *(ssdt_ptr++) = 'C';
+        *(ssdt_ptr++) = 'P';
+        *(ssdt_ptr++) = getHex(i >> 4);
+        *(ssdt_ptr++) = getHex(i);
+        *(ssdt_ptr++) = 0x69; // Arg1Op
+    }
+
+    // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
+    *(ssdt_ptr++) = 0x08; // NameOp
+    *(ssdt_ptr++) = 'C';
+    *(ssdt_ptr++) = 'P';
+    *(ssdt_ptr++) = 'O';
+    *(ssdt_ptr++) = 'N';
+    *(ssdt_ptr++) = 0x12; // PackageOp
+    ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
+    *(ssdt_ptr++) = acpi_cpus;
+    for (i=0; i<acpi_cpus; i++)
+        *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
+
+    build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+    //hexdump(ssdt, ssdt_ptr - ssdt);
+
+    return ssdt;
+}
+
+#define HPET_SIGNATURE 0x54455048 //HPET
+static void*
+build_hpet(void)
+{
+    struct acpi_20_hpet *hpet = malloc_high(sizeof(*hpet));
+    if (!hpet) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    memset(hpet, 0, sizeof(*hpet));
+    /* Note timer_block_id value must be kept in sync with value advertised by
+     * emulated hpet
+     */
+    hpet->timer_block_id = cpu_to_le32(0x8086a201);
+    hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS);
+    build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
+
+    return hpet;
+}
+
+static void
+acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+                       u64 base, u64 len, int node, int enabled)
+{
+    numamem->type = SRAT_MEMORY;
+    numamem->length = sizeof(*numamem);
+    memset (numamem->proximity, 0 ,4);
+    numamem->proximity[0] = node;
+    numamem->flags = cpu_to_le32(!!enabled);
+    numamem->base_addr_low = base & 0xFFFFFFFF;
+    numamem->base_addr_high = base >> 32;
+    numamem->length_low = len & 0xFFFFFFFF;
+    numamem->length_high = len >> 32;
+}
+
+#define SRAT_SIGNATURE 0x54415253 //HPET
+static void *
+build_srat(void)
+{
+    int nb_numa_nodes = qemu_cfg_get_numa_nodes();
+
+    if (nb_numa_nodes == 0)
+        return NULL;
+
+    u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+    if (!numadata) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes);
+
+    struct system_resource_affinity_table *srat;
+    int srat_size = sizeof(*srat) +
+        sizeof(struct srat_processor_affinity) * MaxCountCPUs +
+        sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+    srat = malloc_high(srat_size);
+    if (!srat) {
+        warn_noalloc();
+        free(numadata);
+        return NULL;
+    }
+
+    memset(srat, 0, srat_size);
+    srat->reserved1=1;
+    struct srat_processor_affinity *core = (void*)(srat + 1);
+    int i;
+    u64 curnode;
+
+    for (i = 0; i < MaxCountCPUs; ++i) {
+        core->type = SRAT_PROCESSOR;
+        core->length = sizeof(*core);
+        core->local_apic_id = i;
+        curnode = *numadata++;
+        core->proximity_lo = curnode;
+        memset(core->proximity_hi, 0, 3);
+        core->local_sapic_eid = 0;
+        if (i < CountCPUs)
+            core->flags = cpu_to_le32(1);
+        else
+            core->flags = 0;
+        core++;
+    }
+
+
+    /* the memory map is a bit tricky, it contains at least one hole
+     * from 640k-1M and possibly another one from 3.5G-4G.
+     */
+    struct srat_memory_affinity *numamem = (void*)core;
+    int slots = 0;
+    u64 mem_len, mem_base, next_base = 0;
+
+    acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+    next_base = 1024 * 1024;
+    numamem++;
+    slots++;
+    for (i = 1; i < nb_numa_nodes + 1; ++i) {
+        mem_base = next_base;
+        mem_len = *numadata++;
+        if (i == 1)
+            mem_len -= 1024 * 1024;
+        next_base = mem_base + mem_len;
+
+        /* Cut out the PCI hole */
+        if (mem_base <= RamSize && next_base > RamSize) {
+            mem_len -= next_base - RamSize;
+            if (mem_len > 0) {
+                acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+                numamem++;
+                slots++;
+            }
+            mem_base = 1ULL << 32;
+            mem_len = next_base - RamSize;
+            next_base += (1ULL << 32) - RamSize;
+        }
+        acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+        numamem++;
+        slots++;
+    }
+    for (; slots < nb_numa_nodes + 2; slots++) {
+        acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+        numamem++;
+    }
+
+    build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
+
+    free(numadata);
+    return srat;
+}
+
+static const struct pci_device_id acpi_find_tbl[] = {
+    /* PIIX4 Power Management device. */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
+
+    PCI_DEVICE_END,
+};
+
+struct rsdp_descriptor *RsdpAddr;
+
+#define MAX_ACPI_TABLES 20
+void
+acpi_bios_init(void)
+{
+    if (! CONFIG_ACPI)
+        return;
+
+    dprintf(3, "init ACPI tables\n");
+
+    // This code is hardcoded for PIIX4 Power Management device.
+    int bdf = pci_find_init_device(acpi_find_tbl, NULL);
+    if (bdf < 0)
+        // Device not found
+        return;
+
+    // Create initial rsdt table
+    struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp));
+    if (!rsdp) {
+        warn_noalloc();
+        return;
+    }
+
+    u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+
+#define ACPI_INIT_TABLE(X)                                   \
+    do {                                                     \
+        tables[tbl_idx] = (u32)(X);                          \
+        if (tables[tbl_idx])                                 \
+            tbl_idx++;                                       \
+    } while(0)
+
+    // Add tables
+    ACPI_INIT_TABLE(build_fadt(bdf));
+    ACPI_INIT_TABLE(build_ssdt());
+    ACPI_INIT_TABLE(build_madt());
+    ACPI_INIT_TABLE(build_hpet());
+    ACPI_INIT_TABLE(build_srat());
+
+    u16 i, external_tables = qemu_cfg_acpi_additional_tables();
+
+    for(i = 0; i < external_tables; i++) {
+        u16 len = qemu_cfg_next_acpi_table_len();
+        void *addr = malloc_high(len);
+        if (!addr) {
+            warn_noalloc();
+            continue;
+        }
+        ACPI_INIT_TABLE(qemu_cfg_next_acpi_table_load(addr, len));
+        if (tbl_idx == MAX_ACPI_TABLES) {
+            warn_noalloc();
+            break;
+        }
+    }
+
+    struct rsdt_descriptor_rev1 *rsdt;
+    size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
+    rsdt = malloc_high(rsdt_len);
+
+    if (!rsdt) {
+        warn_noalloc();
+        return;
+    }
+    memset(rsdt, 0, rsdt_len);
+    memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
+
+    build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
+
+    // Build rsdp pointer table
+    memset(rsdp, 0, sizeof(*rsdp));
+    rsdp->signature = RSDP_SIGNATURE;
+    memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);
+    rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
+    rsdp->checksum -= checksum(rsdp, 20);
+    RsdpAddr = rsdp;
+    dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
+}
+
+u32
+find_resume_vector(void)
+{
+    dprintf(4, "rsdp=%p\n", RsdpAddr);
+    if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+        return 0;
+    struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+    dprintf(4, "rsdt=%p\n", rsdt);
+    if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
+        return 0;
+    void *end = (void*)rsdt + rsdt->length;
+    int i;
+    for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
+        struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
+        if (!fadt || fadt->signature != FACP_SIGNATURE)
+            continue;
+        dprintf(4, "fadt=%p\n", fadt);
+        struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
+        dprintf(4, "facs=%p\n", facs);
+        if (! facs || facs->signature != FACS_SIGNATURE)
+            return 0;
+        // Found it.
+        dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
+        return facs->firmware_waking_vector;
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/acpi.h b/qemu-0.15.x/roms/seabios/src/acpi.h
new file mode 100644
index 0000000..e01315a
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/acpi.h
@@ -0,0 +1,101 @@
+#ifndef __ACPI_H
+#define __ACPI_H
+
+#include "types.h" // u32
+
+void acpi_bios_init(void);
+u32 find_resume_vector(void);
+
+#define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
+
+struct rsdp_descriptor {        /* Root System Descriptor Pointer */
+    u64 signature;              /* ACPI signature, contains "RSD PTR " */
+    u8  checksum;               /* To make sum of struct == 0 */
+    u8  oem_id [6];             /* OEM identification */
+    u8  revision;               /* Must be 0 for 1.0, 2 for 2.0 */
+    u32 rsdt_physical_address;  /* 32-bit physical address of RSDT */
+    u32 length;                 /* XSDT Length in bytes including hdr */
+    u64 xsdt_physical_address;  /* 64-bit physical address of XSDT */
+    u8  extended_checksum;      /* Checksum of entire table */
+    u8  reserved [3];           /* Reserved field must be 0 */
+};
+
+extern struct rsdp_descriptor *RsdpAddr;
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+   BSD license) */
+
+#define ACPI_TABLE_HEADER_DEF   /* ACPI common table header */ \
+    u32 signature;          /* ACPI signature (4 ASCII characters) */ \
+    u32 length;                 /* Length of table, in bytes, including header */ \
+    u8  revision;               /* ACPI Specification minor version # */ \
+    u8  checksum;               /* To make sum of entire table == 0 */ \
+    u8  oem_id [6];             /* OEM identification */ \
+    u8  oem_table_id [8];       /* OEM table identification */ \
+    u32 oem_revision;           /* OEM revision number */ \
+    u8  asl_compiler_id [4];    /* ASL compiler vendor ID */ \
+    u32 asl_compiler_revision;  /* ASL compiler revision number */
+
+
+/*
+ * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ */
+#define FACP_SIGNATURE 0x50434146 // FACP
+struct fadt_descriptor_rev1
+{
+    ACPI_TABLE_HEADER_DEF     /* ACPI common table header */
+    u32 firmware_ctrl;          /* Physical address of FACS */
+    u32 dsdt;                   /* Physical address of DSDT */
+    u8  model;                  /* System Interrupt Model */
+    u8  reserved1;              /* Reserved */
+    u16 sci_int;                /* System vector of SCI interrupt */
+    u32 smi_cmd;                /* Port address of SMI command port */
+    u8  acpi_enable;            /* Value to write to smi_cmd to enable ACPI */
+    u8  acpi_disable;           /* Value to write to smi_cmd to disable ACPI */
+    u8  S4bios_req;             /* Value to write to SMI CMD to enter S4BIOS state */
+    u8  reserved2;              /* Reserved - must be zero */
+    u32 pm1a_evt_blk;           /* Port address of Power Mgt 1a acpi_event Reg Blk */
+    u32 pm1b_evt_blk;           /* Port address of Power Mgt 1b acpi_event Reg Blk */
+    u32 pm1a_cnt_blk;           /* Port address of Power Mgt 1a Control Reg Blk */
+    u32 pm1b_cnt_blk;           /* Port address of Power Mgt 1b Control Reg Blk */
+    u32 pm2_cnt_blk;            /* Port address of Power Mgt 2 Control Reg Blk */
+    u32 pm_tmr_blk;             /* Port address of Power Mgt Timer Ctrl Reg Blk */
+    u32 gpe0_blk;               /* Port addr of General Purpose acpi_event 0 Reg Blk */
+    u32 gpe1_blk;               /* Port addr of General Purpose acpi_event 1 Reg Blk */
+    u8  pm1_evt_len;            /* Byte length of ports at pm1_x_evt_blk */
+    u8  pm1_cnt_len;            /* Byte length of ports at pm1_x_cnt_blk */
+    u8  pm2_cnt_len;            /* Byte Length of ports at pm2_cnt_blk */
+    u8  pm_tmr_len;             /* Byte Length of ports at pm_tm_blk */
+    u8  gpe0_blk_len;           /* Byte Length of ports at gpe0_blk */
+    u8  gpe1_blk_len;           /* Byte Length of ports at gpe1_blk */
+    u8  gpe1_base;              /* Offset in gpe model where gpe1 events start */
+    u8  reserved3;              /* Reserved */
+    u16 plvl2_lat;              /* Worst case HW latency to enter/exit C2 state */
+    u16 plvl3_lat;              /* Worst case HW latency to enter/exit C3 state */
+    u16 flush_size;             /* Size of area read to flush caches */
+    u16 flush_stride;           /* Stride used in flushing caches */
+    u8  duty_offset;            /* Bit location of duty cycle field in p_cnt reg */
+    u8  duty_width;             /* Bit width of duty cycle field in p_cnt reg */
+    u8  day_alrm;               /* Index to day-of-month alarm in RTC CMOS RAM */
+    u8  mon_alrm;               /* Index to month-of-year alarm in RTC CMOS RAM */
+    u8  century;                /* Index to century in RTC CMOS RAM */
+    u8  reserved4;              /* Reserved */
+    u8  reserved4a;             /* Reserved */
+    u8  reserved4b;             /* Reserved */
+#if 0
+    u32 wb_invd         : 1;    /* The wbinvd instruction works properly */
+    u32 wb_invd_flush   : 1;    /* The wbinvd flushes but does not invalidate */
+    u32 proc_c1         : 1;    /* All processors support C1 state */
+    u32 plvl2_up        : 1;    /* C2 state works on MP system */
+    u32 pwr_button      : 1;    /* Power button is handled as a generic feature */
+    u32 sleep_button    : 1;    /* Sleep button is handled as a generic feature, or not present */
+    u32 fixed_rTC       : 1;    /* RTC wakeup stat not in fixed register space */
+    u32 rtcs4           : 1;    /* RTC wakeup stat not possible from S4 */
+    u32 tmr_val_ext     : 1;    /* The tmr_val width is 32 bits (0 = 24 bits) */
+    u32 reserved5       : 23;   /* Reserved - must be zero */
+#else
+    u32 flags;
+#endif
+} PACKED;
+
+#endif // acpi.h
diff --git a/qemu-0.15.x/roms/seabios/src/ahci.c b/qemu-0.15.x/roms/seabios/src/ahci.c
new file mode 100644
index 0000000..b820e28
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ahci.c
@@ -0,0 +1,484 @@
+// Low level AHCI disk access
+//
+// Copyright (C) 2010 Gerd Hoffmann <kraxel at redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // add_bcv_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "ahci.h" // CDB_CMD_READ_10
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#define AHCI_MAX_RETRIES 5
+
+/****************************************************************
+ * these bits must run in both 16bit and 32bit modes
+ ****************************************************************/
+
+// prepare sata command fis
+static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
+{
+    memset_fl(fis, 0, sizeof(*fis));
+    SET_FLATPTR(fis->command, command);
+}
+
+static void sata_prep_readwrite(struct sata_cmd_fis *fis,
+                                struct disk_op_s *op, int iswrite)
+{
+    u64 lba = op->lba;
+    u8 command;
+
+    memset_fl(fis, 0, sizeof(*fis));
+
+    if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+        SET_FLATPTR(fis->sector_count2, op->count >> 8);
+        SET_FLATPTR(fis->lba_low2,      lba >> 24);
+        SET_FLATPTR(fis->lba_mid2,      lba >> 32);
+        SET_FLATPTR(fis->lba_high2,     lba >> 40);
+        lba &= 0xffffff;
+        command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+                   : ATA_CMD_READ_DMA_EXT);
+    } else {
+        command = (iswrite ? ATA_CMD_WRITE_DMA
+                   : ATA_CMD_READ_DMA);
+    }
+    SET_FLATPTR(fis->feature,      1); /* dma */
+    SET_FLATPTR(fis->command,      command);
+    SET_FLATPTR(fis->sector_count, op->count);
+    SET_FLATPTR(fis->lba_low,      lba);
+    SET_FLATPTR(fis->lba_mid,      lba >> 8);
+    SET_FLATPTR(fis->lba_high,     lba >> 16);
+    SET_FLATPTR(fis->device,       ((lba >> 24) & 0xf) | ATA_CB_DH_LBA);
+}
+
+static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 blocksize)
+{
+    memset_fl(fis, 0, sizeof(*fis));
+    SET_FLATPTR(fis->command,  ATA_CMD_PACKET);
+    SET_FLATPTR(fis->feature,  1); /* dma */
+    SET_FLATPTR(fis->lba_mid,  blocksize);
+    SET_FLATPTR(fis->lba_high, blocksize >> 8);
+}
+
+// ahci register access helpers
+static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
+{
+    u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+    return pci_readl(addr);
+}
+
+static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
+{
+    u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+    pci_writel(addr, val);
+}
+
+static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg)
+{
+    u32 ctrl_reg = 0x100;
+    ctrl_reg += pnr * 0x80;
+    ctrl_reg += port_reg;
+    return ctrl_reg;
+}
+
+static u32 ahci_port_readl(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg)
+{
+    u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+    return ahci_ctrl_readl(ctrl, ctrl_reg);
+}
+
+static void ahci_port_writel(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg, u32 val)
+{
+    u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+    ahci_ctrl_writel(ctrl, ctrl_reg, val);
+}
+
+// submit ahci command + wait for result
+static int ahci_command(struct ahci_port_s *port, int iswrite, int isatapi,
+                        void *buffer, u32 bsize)
+{
+    u32 val, status, success, flags;
+    struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl);
+    struct ahci_cmd_s  *cmd  = GET_GLOBAL(port->cmd);
+    struct ahci_fis_s  *fis  = GET_GLOBAL(port->fis);
+    struct ahci_list_s *list = GET_GLOBAL(port->list);
+    u32 pnr                  = GET_GLOBAL(port->pnr);
+
+    SET_FLATPTR(cmd->fis.reg,       0x27);
+    SET_FLATPTR(cmd->fis.pmp_type,  (1 << 7)); /* cmd fis */
+    SET_FLATPTR(cmd->prdt[0].base,  ((u32)buffer));
+    SET_FLATPTR(cmd->prdt[0].baseu, 0);
+    SET_FLATPTR(cmd->prdt[0].flags, bsize-1);
+
+    val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+    ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START);
+
+    if (ahci_port_readl(ctrl, pnr, PORT_CMD_ISSUE))
+        return -1;
+
+    flags = ((1 << 16) | /* one prd entry */
+             (1 << 10) | /* clear busy on ok */
+             (iswrite ? (1 << 6) : 0) |
+             (isatapi ? (1 << 5) : 0) |
+             (4 << 0)); /* fis length (dwords) */
+    SET_FLATPTR(list[0].flags, flags);
+    SET_FLATPTR(list[0].bytes,  bsize);
+    SET_FLATPTR(list[0].base,   ((u32)(cmd)));
+    SET_FLATPTR(list[0].baseu,  0);
+
+    dprintf(2, "AHCI/%d: send cmd ...\n", pnr);
+    SET_FLATPTR(fis->rfis[2], 0);
+    ahci_port_writel(ctrl, pnr, PORT_SCR_ACT, 1);
+    ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1);
+    while (ahci_port_readl(ctrl, pnr, PORT_CMD_ISSUE)) {
+        yield();
+    }
+    while ((status = GET_FLATPTR(fis->rfis[2])) == 0) {
+        yield();
+    }
+
+    success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF |
+                                  ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR)) &&
+               ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY)));
+    dprintf(2, "AHCI/%d: ... finished, status 0x%x, %s\n", pnr,
+            status, success ? "OK" : "ERROR");
+    return success ? 0 : -1;
+}
+
+#define CDROM_CDB_SIZE 12
+
+int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+    if (! CONFIG_AHCI)
+        return 0;
+
+    struct ahci_port_s *port = container_of(
+        op->drive_g, struct ahci_port_s, drive);
+    struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+    u8 *atapi = cdbcmd;
+    int i, rc;
+
+    sata_prep_atapi(&cmd->fis, blocksize);
+    for (i = 0; i < CDROM_CDB_SIZE; i++) {
+        SET_FLATPTR(cmd->atapi[i], atapi[i]);
+    }
+    rc = ahci_command(port, 0, 1, op->buf_fl,
+                      op->count * blocksize);
+    if (rc < 0)
+        return DISK_RET_EBADTRACK;
+    return DISK_RET_SUCCESS;
+}
+
+// read/write count blocks from a harddrive.
+static int
+ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
+{
+    struct ahci_port_s *port = container_of(
+        op->drive_g, struct ahci_port_s, drive);
+    struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+    int rc;
+
+    sata_prep_readwrite(&cmd->fis, op, iswrite);
+    rc = ahci_command(port, iswrite, 0, op->buf_fl,
+                      op->count * DISK_SECTOR_SIZE);
+    dprintf(2, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n",
+            iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc);
+    if (rc < 0)
+        return DISK_RET_EBADTRACK;
+    return DISK_RET_SUCCESS;
+}
+
+// command demuxer
+int process_ahci_op(struct disk_op_s *op)
+{
+    struct ahci_port_s *port;
+    u32 atapi;
+
+    if (!CONFIG_AHCI)
+        return 0;
+
+    port = container_of(op->drive_g, struct ahci_port_s, drive);
+    atapi = GET_GLOBAL(port->atapi);
+
+    if (atapi) {
+        switch (op->command) {
+        case CMD_READ:
+            return cdb_read(op);
+        case CMD_WRITE:
+        case CMD_FORMAT:
+            return DISK_RET_EWRITEPROTECT;
+        case CMD_RESET:
+            /* FIXME: what should we do here? */
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            return DISK_RET_SUCCESS;
+        default:
+            dprintf(1, "AHCI: unknown cdrom command %d\n", op->command);
+            op->count = 0;
+            return DISK_RET_EPARAM;
+        }
+    } else {
+        switch (op->command) {
+        case CMD_READ:
+            return ahci_disk_readwrite(op, 0);
+        case CMD_WRITE:
+            return ahci_disk_readwrite(op, 1);
+        case CMD_RESET:
+            /* FIXME: what should we do here? */
+        case CMD_FORMAT:
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            return DISK_RET_SUCCESS;
+        default:
+            dprintf(1, "AHCI: unknown disk command %d\n", op->command);
+            op->count = 0;
+            return DISK_RET_EPARAM;
+        }
+    }
+}
+
+/****************************************************************
+ * everything below is pure 32bit code
+ ****************************************************************/
+
+static void
+ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+    u32 val, count = 0;
+
+    /* disable FIS + CMD */
+    val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+    while (val & (PORT_CMD_FIS_RX | PORT_CMD_START |
+                  PORT_CMD_FIS_ON | PORT_CMD_LIST_ON) &&
+           count < AHCI_MAX_RETRIES) {
+        val &= ~(PORT_CMD_FIS_RX | PORT_CMD_START);
+        ahci_port_writel(ctrl, pnr, PORT_CMD, val);
+        ndelay(500);
+        val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+        count++;
+    }
+
+    /* clear status */
+    val = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
+    if (val)
+        ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, val);
+
+    /* disable + clear IRQs */
+    ahci_port_writel(ctrl, pnr, PORT_IRQ_MASK, val);
+    val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+    if (val)
+        ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+}
+
+static int
+ahci_port_probe(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+    u32 val, count = 0;
+
+    val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+    while (val & ((1 << 7) /* BSY */ |
+                  (1 << 3) /* DRQ */)) {
+        ndelay(500);
+        val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+        count++;
+        if (count >= AHCI_MAX_RETRIES)
+            return -1;
+    }
+
+    val = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
+    if ((val & 0x07) != 0x03)
+        return -1;
+    return 0;
+}
+
+#define MAXMODEL 40
+
+static struct ahci_port_s*
+ahci_port_init(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+    struct ahci_port_s *port = malloc_fseg(sizeof(*port));
+    char model[MAXMODEL+1];
+    u16 buffer[256];
+    u32 val;
+    int rc;
+
+    if (!port) {
+        warn_noalloc();
+        return NULL;
+    }
+    port->pnr = pnr;
+    port->ctrl = ctrl;
+    port->list = memalign_low(1024, 1024);
+    port->fis = memalign_low(256, 256);
+    port->cmd = memalign_low(256, 256);
+    if (port->list == NULL || port->fis == NULL || port->cmd == NULL) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(port->list, 0, 1024);
+    memset(port->fis, 0, 256);
+    memset(port->cmd, 0, 256);
+
+    ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list);
+    ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis);
+    val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+    ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_FIS_RX);
+
+    sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+    rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+    if (rc == 0) {
+        port->atapi = 1;
+    } else {
+        port->atapi = 0;
+        sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE);
+        rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+        if (rc < 0)
+            goto err;
+    }
+
+    port->drive.type = DTYPE_AHCI;
+    port->drive.cntl_id = pnr;
+    port->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+
+    if (!port->atapi) {
+        // found disk (ata)
+        port->drive.blksize = DISK_SECTOR_SIZE;
+        port->drive.pchs.cylinders = buffer[1];
+        port->drive.pchs.heads = buffer[3];
+        port->drive.pchs.spt = buffer[6];
+
+        u64 sectors;
+        if (buffer[83] & (1 << 10)) // word 83 - lba48 support
+            sectors = *(u64*)&buffer[100]; // word 100-103
+        else
+            sectors = *(u32*)&buffer[60]; // word 60 and word 61
+        port->drive.sectors = sectors;
+        u64 adjsize = sectors >> 11;
+        char adjprefix = 'M';
+        if (adjsize >= (1 << 16)) {
+            adjsize >>= 10;
+            adjprefix = 'G';
+        }
+        char *desc = znprintf(MAXDESCSIZE
+                              , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+                              , port->pnr
+                              , ata_extract_model(model, MAXMODEL, buffer)
+                              , ata_extract_version(buffer)
+                              , (u32)adjsize, adjprefix);
+        dprintf(1, "%s\n", desc);
+
+        // Register with bcv system.
+        boot_add_hd(&port->drive, desc, -1);
+    } else {
+        // found cdrom (atapi)
+        port->drive.blksize = CDROM_SECTOR_SIZE;
+        port->drive.sectors = (u64)-1;
+        u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+        char *desc = znprintf(MAXDESCSIZE
+                              , "DVD/CD [AHCI/%d: %s ATAPI-%d %s]"
+                              , port->pnr
+                              , ata_extract_model(model, MAXMODEL, buffer)
+                              , ata_extract_version(buffer)
+                              , (iscd ? "DVD/CD" : "Device"));
+        dprintf(1, "%s\n", desc);
+
+        // fill cdidmap
+        if (iscd)
+            boot_add_cd(&port->drive, desc, -1);
+    }
+
+    return port;
+
+err:
+    dprintf(1, "AHCI/%d: init failure, reset\n", port->pnr);
+    ahci_port_reset(ctrl, pnr);
+    return NULL;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ahci_detect(void *data)
+{
+    struct ahci_ctrl_s *ctrl = data;
+    struct ahci_port_s *port;
+    u32 pnr, max;
+    int rc;
+
+    max = ctrl->caps & 0x1f;
+    for (pnr = 0; pnr <= max; pnr++) {
+        if (!(ctrl->ports & (1 << pnr)))
+            continue;
+        dprintf(2, "AHCI/%d: probing\n", pnr);
+        ahci_port_reset(ctrl, pnr);
+        rc = ahci_port_probe(ctrl, pnr);
+        dprintf(1, "AHCI/%d: link %s\n", pnr, rc == 0 ? "up" : "down");
+        if (rc != 0)
+            continue;
+        port = ahci_port_init(ctrl, pnr);
+    }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+ahci_init_controller(int bdf)
+{
+    struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
+    u32 val;
+
+    if (!ctrl) {
+        warn_noalloc();
+        return;
+    }
+    ctrl->pci_bdf = bdf;
+    ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
+    ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+    dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n",
+            bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq);
+
+    pci_config_maskw(bdf, PCI_COMMAND, 0,
+                     PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+    val = ahci_ctrl_readl(ctrl, HOST_CTL);
+    ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
+
+    ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP);
+    ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL);
+    dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n",
+            ctrl->caps, ctrl->ports);
+
+    run_thread(ahci_detect, ctrl);
+}
+
+// Locate and init ahci controllers.
+static void
+ahci_init(void)
+{
+    // Scan PCI bus for ATA adapters
+    int bdf, max;
+    foreachpci(bdf, max) {
+        if (pci_config_readw(bdf, PCI_CLASS_DEVICE) != PCI_CLASS_STORAGE_SATA)
+            continue;
+        if (pci_config_readb(bdf, PCI_CLASS_PROG) != 1 /* AHCI rev 1 */)
+            continue;
+        ahci_init_controller(bdf);
+    }
+}
+
+void
+ahci_setup(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_AHCI)
+        return;
+
+    dprintf(3, "init ahci\n");
+    ahci_init();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ahci.h b/qemu-0.15.x/roms/seabios/src/ahci.h
new file mode 100644
index 0000000..0e13e00
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ahci.h
@@ -0,0 +1,196 @@
+#ifndef __AHCI_H
+#define __AHCI_H
+
+struct sata_cmd_fis {
+    u8 reg;
+    u8 pmp_type;
+    u8 command;
+    u8 feature;
+
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 device;
+
+    u8 lba_low2;
+    u8 lba_mid2;
+    u8 lba_high2;
+    u8 feature2;
+
+    u8 sector_count;
+    u8 sector_count2;
+    u8 res_1;
+    u8 control;
+
+    u8 res_2[64 - 16];
+};
+
+struct ahci_ctrl_s {
+    int pci_bdf;
+    u8  irq;
+    u32 iobase;
+    u32 caps;
+    u32 ports;
+};
+
+struct ahci_cmd_s {
+    struct sata_cmd_fis fis;
+    u8 atapi[0x20];
+    u8 res[0x20];
+    struct {
+        u32 base;
+        u32 baseu;
+        u32 res;
+        u32 flags;
+    } prdt[];
+};
+
+/* command list */
+struct ahci_list_s {
+    u32 flags;
+    u32 bytes;
+    u32 base;
+    u32 baseu;
+    u32 res[4];
+};
+
+struct ahci_fis_s {
+    u8 dsfis[0x1c];  /* dma setup */
+    u8 res_1[0x04];
+    u8 psfis[0x14];  /* pio setup */
+    u8 res_2[0x0c];
+    u8 rfis[0x14];   /* d2h register */
+    u8 res_3[0x04];
+    u8 sdbfis[0x08]; /* set device bits */
+    u8 ufis[0x40];   /* unknown */
+    u8 res_4[0x60];
+};
+
+struct ahci_port_s {
+    struct drive_s     drive;
+    struct ahci_ctrl_s *ctrl;
+    struct ahci_list_s *list;
+    struct ahci_fis_s  *fis;
+    struct ahci_cmd_s  *cmd;
+    u32                pnr;
+    u32                atapi;
+};
+
+void ahci_setup(void);
+int process_ahci_op(struct disk_op_s *op);
+int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+
+#define AHCI_IRQ_ON_SG            (1 << 31)
+#define AHCI_CMD_ATAPI            (1 << 5)
+#define AHCI_CMD_WRITE            (1 << 6)
+#define AHCI_CMD_PREFETCH         (1 << 7)
+#define AHCI_CMD_RESET            (1 << 8)
+#define AHCI_CMD_CLR_BUSY         (1 << 10)
+
+#define RX_FIS_D2H_REG            0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB                0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK                0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP                  0x00 /* host capabilities */
+#define HOST_CTL                  0x04 /* global host control */
+#define HOST_IRQ_STAT             0x08 /* interrupt status */
+#define HOST_PORTS_IMPL           0x0c /* bitmap of implemented ports */
+#define HOST_VERSION              0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET            (1 << 0)  /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN           (1 << 1)  /* global IRQ enable */
+#define HOST_CTL_AHCI_EN          (1 << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC              (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI             (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO              (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS              (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ              (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64               (1 << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR             0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI          0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR             0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI          0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT             0x10 /* interrupt status */
+#define PORT_IRQ_MASK             0x14 /* interrupt enable/disable mask */
+#define PORT_CMD                  0x18 /* port command */
+#define PORT_TFDATA               0x20 /* taskfile data */
+#define PORT_SIG                  0x24 /* device TF signature */
+#define PORT_SCR_STAT             0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL              0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR              0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT              0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE            0x38 /* command issue */
+#define PORT_RESERVED             0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES        (1 << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR           (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR         (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR    (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR           (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL      (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW         (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP          (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY           (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK         (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT          (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE          (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS          (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS          (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS         (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS         (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS      (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE           (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR |   \
+                                   PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY |    \
+                                   PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR            (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR |     \
+                                   PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ              (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |     \
+                                   PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |  \
+                                   PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI            (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON          (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON           (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX           (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO              (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON         (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP          (1 << 1) /* Spin up device */
+#define PORT_CMD_START            (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK         (0xf << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE       (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL      (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER      (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_IRQ_STAT_DHRS        (1 << 0) /* Device to Host Register FIS */
+#define PORT_IRQ_STAT_PSS         (1 << 1) /* PIO Setup FIS */
+#define PORT_IRQ_STAT_DSS         (1 << 2) /* DMA Setup FIS */
+#define PORT_IRQ_STAT_SDBS        (1 << 3) /* Set Device Bits */
+#define PORT_IRQ_STAT_UFS         (1 << 4) /* Unknown FIS */
+#define PORT_IRQ_STAT_DPS         (1 << 5) /* Descriptor Processed */
+#define PORT_IRQ_STAT_PCS         (1 << 6) /* Port Connect Change Status */
+#define PORT_IRQ_STAT_DMPS        (1 << 7) /* Device Mechanical Presence
+                                              Status */
+#define PORT_IRQ_STAT_PRCS        (1 << 22) /* File Ready Status */
+#define PORT_IRQ_STAT_IPMS        (1 << 23) /* Incorrect Port Multiplier
+                                               Status */
+#define PORT_IRQ_STAT_OFS         (1 << 24) /* Overflow Status */
+#define PORT_IRQ_STAT_INFS        (1 << 26) /* Interface Non-Fatal Error
+                                               Status */
+#define PORT_IRQ_STAT_IFS         (1 << 27) /* Interface Fatal Error */
+#define PORT_IRQ_STAT_HBDS        (1 << 28) /* Host Bus Data Error Status */
+#define PORT_IRQ_STAT_HBFS        (1 << 29) /* Host Bus Fatal Error Status */
+#define PORT_IRQ_STAT_TFES        (1 << 30) /* Task File Error Status */
+#define PORT_IRQ_STAT_CPDS        (1 << 31) /* Code Port Detect Status */
+
+#endif // ahci.h
diff --git a/qemu-0.15.x/roms/seabios/src/apm.c b/qemu-0.15.x/roms/seabios/src/apm.c
new file mode 100644
index 0000000..2029ae2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/apm.c
@@ -0,0 +1,238 @@
+// Basic support for apmbios callbacks.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2005 Struan Bartlett
+// Copyright (C) 2004 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "farptr.h" // GET_VAR
+#include "bregs.h" // struct bregs
+#include "ioport.h" // outb
+#include "util.h" // wait_irq
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+static void
+out_str(const char *str_cs)
+{
+    if (CONFIG_COREBOOT) {
+        dprintf(1, "APM request '%s'\n", str_cs);
+        return;
+    }
+
+    u8 *s = (u8*)str_cs;
+    for (;;) {
+        u8 c = GET_GLOBAL(*s);
+        if (!c)
+            break;
+        outb(c, PORT_BIOS_APM);
+        s++;
+    }
+}
+
+// APM installation check
+static void
+handle_155300(struct bregs *regs)
+{
+    regs->ah = 1; // APM major version
+    regs->al = 2; // APM minor version
+    regs->bh = 'P';
+    regs->bl = 'M';
+    // bit 0 : 16 bit interface supported
+    // bit 1 : 32 bit interface supported
+    regs->cx = 0x03;
+    set_success(regs);
+}
+
+// APM real mode interface connect
+static void
+handle_155301(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+// Assembler entry points defined in romlayout.S
+extern void apm16protected_entry(void);
+extern void apm32protected_entry(void);
+
+// APM 16 bit protected mode interface connect
+static void
+handle_155302(struct bregs *regs)
+{
+    regs->bx = (u32)apm16protected_entry;
+    regs->ax = SEG_BIOS; // 16 bit code segment base
+    regs->si = 0xfff0;   // 16 bit code segment size
+    regs->cx = SEG_BIOS; // data segment address
+    regs->di = 0xfff0;   // data segment length
+    set_success(regs);
+}
+
+// APM 32 bit protected mode interface connect
+static void
+handle_155303(struct bregs *regs)
+{
+    regs->ax = SEG_BIOS; // 32 bit code segment base
+    regs->ebx = (u32)apm32protected_entry;
+    regs->cx = SEG_BIOS; // 16 bit code segment base
+    // 32 bit code segment size (low 16 bits)
+    // 16 bit code segment size (high 16 bits)
+    regs->esi = 0xfff0fff0;
+    regs->dx = SEG_BIOS; // data segment address
+    regs->di = 0xfff0; // data segment length
+    set_success(regs);
+}
+
+// APM interface disconnect
+static void
+handle_155304(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+// APM cpu idle
+static void
+handle_155305(struct bregs *regs)
+{
+    wait_irq();
+    set_success(regs);
+}
+
+// APM cpu busy
+static void
+handle_155306(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+void
+apm_shutdown(void)
+{
+    irq_disable();
+    out_str("Shutdown");
+    for (;;)
+        hlt();
+}
+
+// APM Set Power State
+static void
+handle_155307(struct bregs *regs)
+{
+    if (regs->bx != 1) {
+        set_success(regs);
+        return;
+    }
+    switch (regs->cx) {
+    case 1:
+        out_str("Standby");
+        break;
+    case 2:
+        out_str("Suspend");
+        break;
+    case 3:
+        apm_shutdown();
+        break;
+    }
+    set_success(regs);
+}
+
+static void
+handle_155308(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+// Get Power Status
+static void
+handle_15530a(struct bregs *regs)
+{
+    regs->bh = 0x01; // on line
+    regs->bl = 0xff; // unknown battery status
+    regs->ch = 0x80; // no system battery
+    regs->cl = 0xff; // unknown remaining time
+    regs->dx = 0xffff; // unknown remaining time
+    regs->si = 0x00; // zero battery
+    set_success(regs);
+}
+
+#define RET_ENOEVENT 0x80
+
+// Get PM Event
+static void
+handle_15530b(struct bregs *regs)
+{
+    set_code_invalid_silent(regs, RET_ENOEVENT);
+}
+
+// APM Driver Version
+static void
+handle_15530e(struct bregs *regs)
+{
+    regs->ah = 1;
+    regs->al = 2;
+    set_success(regs);
+}
+
+// APM Engage / Disengage
+static void
+handle_15530f(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+// APM Get Capabilities
+static void
+handle_155310(struct bregs *regs)
+{
+    regs->bl = 0;
+    regs->cx = 0;
+    set_success(regs);
+}
+
+static void
+handle_1553XX(struct bregs *regs)
+{
+    set_unimplemented(regs);
+}
+
+void
+handle_1553(struct bregs *regs)
+{
+    if (! CONFIG_APMBIOS) {
+        set_code_invalid(regs, RET_EUNSUPPORTED);
+        return;
+    }
+
+    //debug_stub(regs);
+    switch (regs->al) {
+    case 0x00: handle_155300(regs); break;
+    case 0x01: handle_155301(regs); break;
+    case 0x02: handle_155302(regs); break;
+    case 0x03: handle_155303(regs); break;
+    case 0x04: handle_155304(regs); break;
+    case 0x05: handle_155305(regs); break;
+    case 0x06: handle_155306(regs); break;
+    case 0x07: handle_155307(regs); break;
+    case 0x08: handle_155308(regs); break;
+    case 0x0a: handle_15530a(regs); break;
+    case 0x0b: handle_15530b(regs); break;
+    case 0x0e: handle_15530e(regs); break;
+    case 0x0f: handle_15530f(regs); break;
+    case 0x10: handle_155310(regs); break;
+    default:   handle_1553XX(regs); break;
+    }
+}
+
+void VISIBLE16
+handle_apm16(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}
+
+void VISIBLE32SEG
+handle_apm32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/asm-offsets.c b/qemu-0.15.x/roms/seabios/src/asm-offsets.c
new file mode 100644
index 0000000..5035cef
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/asm-offsets.c
@@ -0,0 +1,31 @@
+// Generate assembler offsets.
+
+#include "gen-defs.h" // OFFSET
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // struct bios_data_area_s
+
+/* workaround for a warning with -Wmissing-prototypes */
+void foo(void) VISIBLE16;
+
+void foo(void)
+{
+    COMMENT("BREGS");
+    OFFSET(BREGS_es, bregs, es);
+    OFFSET(BREGS_ds, bregs, ds);
+    OFFSET(BREGS_eax, bregs, eax);
+    OFFSET(BREGS_ebx, bregs, ebx);
+    OFFSET(BREGS_ecx, bregs, ecx);
+    OFFSET(BREGS_edx, bregs, edx);
+    OFFSET(BREGS_ebp, bregs, ebp);
+    OFFSET(BREGS_esi, bregs, esi);
+    OFFSET(BREGS_edi, bregs, edi);
+    OFFSET(BREGS_flags, bregs, flags);
+    OFFSET(BREGS_code, bregs, code);
+
+    COMMENT("BDA");
+    OFFSET(BDA_ebda_seg, bios_data_area_s, ebda_seg);
+
+    COMMENT("EBDA");
+    DEFINE(EBDA_OFFSET_TOP_STACK, EBDA_OFFSET_TOP_STACK);
+    DEFINE(EBDA_SEGMENT_START, EBDA_SEGMENT_START);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ata.c b/qemu-0.15.x/roms/seabios/src/ata.c
new file mode 100644
index 0000000..397e402
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ata.c
@@ -0,0 +1,1044 @@
+// Low level ATA disk access
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "cmos.h" // inb_cmos
+#include "pic.h" // enable_hwirq
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // boot_add_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Wait for the specified ide state
+static inline int
+await_ide(u8 mask, u8 flags, u16 base, u16 timeout)
+{
+    u64 end = calc_future_tsc(timeout);
+    for (;;) {
+        u8 status = inb(base+ATA_CB_STAT);
+        if ((status & mask) == flags)
+            return status;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for the device to be not-busy.
+static int
+await_not_bsy(u16 base)
+{
+    return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT);
+}
+
+// Wait for the device to be ready.
+static int
+await_rdy(u16 base)
+{
+    return await_ide(ATA_CB_STAT_RDY, ATA_CB_STAT_RDY, base, IDE_TIMEOUT);
+}
+
+// Wait for ide state - pauses for one ata cycle first.
+static inline int
+pause_await_not_bsy(u16 iobase1, u16 iobase2)
+{
+    // Wait one PIO transfer cycle.
+    inb(iobase2 + ATA_CB_ASTAT);
+
+    return await_not_bsy(iobase1);
+}
+
+// Wait for ide state - pause for 400ns first.
+static inline int
+ndelay_await_not_bsy(u16 iobase1)
+{
+    ndelay(400);
+    return await_not_bsy(iobase1);
+}
+
+// Reset a drive
+static void
+ata_reset(struct atadrive_s *adrive_g)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u8 slave = GET_GLOBAL(adrive_g->slave);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+    dprintf(6, "ata_reset drive=%p\n", &adrive_g->drive);
+    // Pulse SRST
+    outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC);
+    udelay(5);
+    outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC);
+    msleep(2);
+
+    // wait for device to become not busy.
+    int status = await_not_bsy(iobase1);
+    if (status < 0)
+        goto done;
+    if (slave) {
+        // Change device.
+        u64 end = calc_future_tsc(IDE_TIMEOUT);
+        for (;;) {
+            outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH);
+            status = ndelay_await_not_bsy(iobase1);
+            if (status < 0)
+                goto done;
+            if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1)
+                break;
+            // Change drive request failed to take effect - retry.
+            if (check_tsc(end)) {
+                warn_timeout();
+                goto done;
+            }
+        }
+    } else {
+        // QEMU doesn't reset dh on reset, so set it explicitly.
+        outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH);
+    }
+
+    // On a user-reset request, wait for RDY if it is an ATA device.
+    u8 type=GET_GLOBAL(adrive_g->drive.type);
+    if (type == DTYPE_ATA)
+        status = await_rdy(iobase1);
+
+done:
+    // Enable interrupts
+    outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+    dprintf(6, "ata_reset exit status=%x\n", status);
+}
+
+// Check for drive RDY for 16bit interface command.
+static int
+isready(struct atadrive_s *adrive_g)
+{
+    // Read the status from controller
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u8 status = inb(iobase1 + ATA_CB_STAT);
+    if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY)
+        return DISK_RET_SUCCESS;
+    return DISK_RET_ENOTREADY;
+}
+
+// Default 16bit command demuxer for ATA and ATAPI devices.
+static int
+process_ata_misc_op(struct disk_op_s *op)
+{
+    if (!CONFIG_ATA)
+        return 0;
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    switch (op->command) {
+    case CMD_RESET:
+        ata_reset(adrive_g);
+        return DISK_RET_SUCCESS;
+    case CMD_ISREADY:
+        return isready(adrive_g);
+    case CMD_FORMAT:
+    case CMD_VERIFY:
+    case CMD_SEEK:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * ATA send command
+ ****************************************************************/
+
+struct ata_pio_command {
+    u8 feature;
+    u8 sector_count;
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 device;
+    u8 command;
+
+    u8 feature2;
+    u8 sector_count2;
+    u8 lba_low2;
+    u8 lba_mid2;
+    u8 lba_high2;
+};
+
+// Send an ata command to the drive.
+static int
+send_cmd(struct atadrive_s *adrive_g, struct ata_pio_command *cmd)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u8 slave = GET_GLOBAL(adrive_g->slave);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+
+    // Select device
+    int status = await_not_bsy(iobase1);
+    if (status < 0)
+        return status;
+    u8 newdh = ((cmd->device & ~ATA_CB_DH_DEV1)
+                | (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0));
+    u8 olddh = inb(iobase1 + ATA_CB_DH);
+    outb(newdh, iobase1 + ATA_CB_DH);
+    if ((olddh ^ newdh) & (1<<4)) {
+        // Was a device change - wait for device to become not busy.
+        status = ndelay_await_not_bsy(iobase1);
+        if (status < 0)
+            return status;
+    }
+
+    // Check for ATA_CMD_(READ|WRITE)_(SECTORS|DMA)_EXT commands.
+    if ((cmd->command & ~0x11) == ATA_CMD_READ_SECTORS_EXT) {
+        outb(cmd->feature2, iobase1 + ATA_CB_FR);
+        outb(cmd->sector_count2, iobase1 + ATA_CB_SC);
+        outb(cmd->lba_low2, iobase1 + ATA_CB_SN);
+        outb(cmd->lba_mid2, iobase1 + ATA_CB_CL);
+        outb(cmd->lba_high2, iobase1 + ATA_CB_CH);
+    }
+    outb(cmd->feature, iobase1 + ATA_CB_FR);
+    outb(cmd->sector_count, iobase1 + ATA_CB_SC);
+    outb(cmd->lba_low, iobase1 + ATA_CB_SN);
+    outb(cmd->lba_mid, iobase1 + ATA_CB_CL);
+    outb(cmd->lba_high, iobase1 + ATA_CB_CH);
+    outb(cmd->command, iobase1 + ATA_CB_CMD);
+
+    return 0;
+}
+
+// Wait for data after calling 'send_cmd'.
+static int
+ata_wait_data(u16 iobase1)
+{
+    int status = ndelay_await_not_bsy(iobase1);
+    if (status < 0)
+        return status;
+
+    if (status & ATA_CB_STAT_ERR) {
+        dprintf(6, "send_cmd : read error (status=%02x err=%02x)\n"
+                , status, inb(iobase1 + ATA_CB_ERR));
+        return -4;
+    }
+    if (!(status & ATA_CB_STAT_DRQ)) {
+        dprintf(6, "send_cmd : DRQ not set (status %02x)\n", status);
+        return -5;
+    }
+
+    return 0;
+}
+
+// Send an ata command that does not transfer any further data.
+int
+ata_cmd_nondata(struct atadrive_s *adrive_g, struct ata_pio_command *cmd)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+    // Disable interrupts
+    outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+    int ret = send_cmd(adrive_g, cmd);
+    if (ret)
+        goto fail;
+    ret = ndelay_await_not_bsy(iobase1);
+    if (ret < 0)
+        goto fail;
+
+    if (ret & ATA_CB_STAT_ERR) {
+        dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n"
+                , ret, inb(iobase1 + ATA_CB_ERR));
+        ret = -4;
+        goto fail;
+    }
+    if (ret & ATA_CB_STAT_DRQ) {
+        dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret);
+        ret = -5;
+        goto fail;
+    }
+
+fail:
+    // Enable interrupts
+    outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+    return ret;
+}
+
+
+/****************************************************************
+ * ATA PIO transfers
+ ****************************************************************/
+
+// Transfer 'op->count' blocks (of 'blocksize' bytes) to/from drive
+// 'op->drive_g'.
+static int
+ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize)
+{
+    dprintf(16, "ata_pio_transfer id=%p write=%d count=%d bs=%d buf=%p\n"
+            , op->drive_g, iswrite, op->count, blocksize, op->buf_fl);
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+    int count = op->count;
+    void *buf_fl = op->buf_fl;
+    int status;
+    for (;;) {
+        if (iswrite) {
+            // Write data to controller
+            dprintf(16, "Write sector id=%p dest=%p\n", op->drive_g, buf_fl);
+            if (CONFIG_ATA_PIO32)
+                outsl_fl(iobase1, buf_fl, blocksize / 4);
+            else
+                outsw_fl(iobase1, buf_fl, blocksize / 2);
+        } else {
+            // Read data from controller
+            dprintf(16, "Read sector id=%p dest=%p\n", op->drive_g, buf_fl);
+            if (CONFIG_ATA_PIO32)
+                insl_fl(iobase1, buf_fl, blocksize / 4);
+            else
+                insw_fl(iobase1, buf_fl, blocksize / 2);
+        }
+        buf_fl += blocksize;
+
+        status = pause_await_not_bsy(iobase1, iobase2);
+        if (status < 0) {
+            // Error
+            op->count -= count;
+            return status;
+        }
+
+        count--;
+        if (!count)
+            break;
+        status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR);
+        if (status != ATA_CB_STAT_DRQ) {
+            dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n"
+                    , status);
+            op->count -= count;
+            return -6;
+        }
+    }
+
+    status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+               | ATA_CB_STAT_ERR);
+    if (!iswrite)
+        status &= ~ATA_CB_STAT_DF;
+    if (status != 0) {
+        dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status);
+        return -7;
+    }
+
+    return 0;
+}
+
+
+/****************************************************************
+ * ATA DMA transfers
+ ****************************************************************/
+
+#define BM_CMD    0
+#define  BM_CMD_MEMWRITE  0x08
+#define  BM_CMD_START     0x01
+#define BM_STATUS 2
+#define  BM_STATUS_IRQ    0x04
+#define  BM_STATUS_ERROR  0x02
+#define  BM_STATUS_ACTIVE 0x01
+#define BM_TABLE  4
+
+struct sff_dma_prd {
+    u32 buf_fl;
+    u32 count;
+};
+
+// Check if DMA available and setup transfer if so.
+static int
+ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
+{
+    if (! CONFIG_ATA_DMA)
+        return -1;
+    u32 dest = (u32)op->buf_fl;
+    if (dest & 1)
+        // Need minimum alignment of 1.
+        return -1;
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+    if (! iomaster)
+        return -1;
+    u32 bytes = op->count * blocksize;
+    if (! bytes)
+        return -1;
+
+    // Build PRD dma structure.
+    struct sff_dma_prd *dma = MAKE_FLATPTR(
+        get_ebda_seg()
+        , (void*)offsetof(struct extended_bios_data_area_s, extra_stack));
+    struct sff_dma_prd *origdma = dma;
+    while (bytes) {
+        if (dma >= &origdma[16])
+            // Too many descriptors..
+            return -1;
+        u32 count = bytes;
+        u32 max = 0x10000 - (dest & 0xffff);
+        if (count > max)
+            count = max;
+
+        SET_FLATPTR(dma->buf_fl, dest);
+        bytes -= count;
+        if (!bytes)
+            // Last descriptor.
+            count |= 1<<31;
+        dprintf(16, "dma@%p: %08x %08x\n", dma, dest, count);
+        dest += count;
+        SET_FLATPTR(dma->count, count);
+        dma++;
+    }
+
+    // Program bus-master controller.
+    outl((u32)origdma, iomaster + BM_TABLE);
+    u8 oldcmd = inb(iomaster + BM_CMD) & ~(BM_CMD_MEMWRITE|BM_CMD_START);
+    outb(oldcmd | (iswrite ? 0x00 : BM_CMD_MEMWRITE), iomaster + BM_CMD);
+    outb(BM_STATUS_ERROR|BM_STATUS_IRQ, iomaster + BM_STATUS);
+
+    return 0;
+}
+
+// Transfer data using DMA.
+static int
+ata_dma_transfer(struct disk_op_s *op)
+{
+    if (! CONFIG_ATA_DMA)
+        return -1;
+    dprintf(16, "ata_dma_transfer id=%p buf=%p\n", op->drive_g, op->buf_fl);
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+
+    // Start bus-master controller.
+    u8 oldcmd = inb(iomaster + BM_CMD);
+    outb(oldcmd | BM_CMD_START, iomaster + BM_CMD);
+
+    u64 end = calc_future_tsc(IDE_TIMEOUT);
+    u8 status;
+    for (;;) {
+        status = inb(iomaster + BM_STATUS);
+        if (status & BM_STATUS_IRQ)
+            break;
+        // Transfer in progress
+        if (check_tsc(end)) {
+            // Timeout.
+            warn_timeout();
+            break;
+        }
+        yield();
+    }
+    outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD);
+
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+    int idestatus = pause_await_not_bsy(iobase1, iobase2);
+
+    if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ
+        && idestatus >= 0x00
+        && (idestatus & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+                         | ATA_CB_STAT_ERR)) == 0x00)
+        // Success.
+        return 0;
+
+    dprintf(6, "IDE DMA error (dma=%x ide=%x/%x/%x)\n", status, idestatus
+            , inb(iobase2 + ATA_CB_ASTAT), inb(iobase1 + ATA_CB_ERR));
+    op->count = 0;
+    return -1;
+}
+
+
+/****************************************************************
+ * ATA hard drive functions
+ ****************************************************************/
+
+// Transfer data to harddrive using PIO protocol.
+static int
+ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd)
+{
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+    // Disable interrupts
+    outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+    int ret = send_cmd(adrive_g, cmd);
+    if (ret)
+        goto fail;
+    ret = ata_wait_data(iobase1);
+    if (ret)
+        goto fail;
+    ret = ata_pio_transfer(op, iswrite, DISK_SECTOR_SIZE);
+
+fail:
+    // Enable interrupts
+    outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+    return ret;
+}
+
+// Transfer data to harddrive using DMA protocol.
+static int
+ata_dma_cmd_data(struct disk_op_s *op, struct ata_pio_command *cmd)
+{
+    if (! CONFIG_ATA_DMA)
+        return -1;
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    int ret = send_cmd(adrive_g, cmd);
+    if (ret)
+        return ret;
+    return ata_dma_transfer(op);
+}
+
+// Read/write count blocks from a harddrive.
+static int
+ata_readwrite(struct disk_op_s *op, int iswrite)
+{
+    u64 lba = op->lba;
+
+    int usepio = ata_try_dma(op, iswrite, DISK_SECTOR_SIZE);
+
+    struct ata_pio_command cmd;
+    memset(&cmd, 0, sizeof(cmd));
+
+    if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+        cmd.sector_count2 = op->count >> 8;
+        cmd.lba_low2 = lba >> 24;
+        cmd.lba_mid2 = lba >> 32;
+        cmd.lba_high2 = lba >> 40;
+        lba &= 0xffffff;
+
+        if (usepio)
+            cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS_EXT
+                           : ATA_CMD_READ_SECTORS_EXT);
+        else
+            cmd.command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+                           : ATA_CMD_READ_DMA_EXT);
+    } else {
+        if (usepio)
+            cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS
+                           : ATA_CMD_READ_SECTORS);
+        else
+            cmd.command = (iswrite ? ATA_CMD_WRITE_DMA
+                           : ATA_CMD_READ_DMA);
+    }
+
+    cmd.sector_count = op->count;
+    cmd.lba_low = lba;
+    cmd.lba_mid = lba >> 8;
+    cmd.lba_high = lba >> 16;
+    cmd.device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA;
+
+    int ret;
+    if (usepio)
+        ret = ata_pio_cmd_data(op, iswrite, &cmd);
+    else
+        ret = ata_dma_cmd_data(op, &cmd);
+    if (ret)
+        return DISK_RET_EBADTRACK;
+    return DISK_RET_SUCCESS;
+}
+
+// 16bit command demuxer for ATA harddrives.
+int
+process_ata_op(struct disk_op_s *op)
+{
+    if (!CONFIG_ATA)
+        return 0;
+
+    switch (op->command) {
+    case CMD_READ:
+        return ata_readwrite(op, 0);
+    case CMD_WRITE:
+        return ata_readwrite(op, 1);
+    default:
+        return process_ata_misc_op(op);
+    }
+}
+
+
+/****************************************************************
+ * ATAPI functions
+ ****************************************************************/
+
+#define CDROM_CDB_SIZE 12
+
+// Low-level atapi command transmit function.
+int
+atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+    if (! CONFIG_ATA)
+        return 0;
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+    struct ata_pio_command cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.lba_mid = blocksize;
+    cmd.lba_high = blocksize >> 8;
+    cmd.command = ATA_CMD_PACKET;
+
+    // Disable interrupts
+    outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+    int ret = send_cmd(adrive_g, &cmd);
+    if (ret)
+        goto fail;
+    ret = ata_wait_data(iobase1);
+    if (ret)
+        goto fail;
+
+    // Send command to device
+    outsw_fl(iobase1, MAKE_FLATPTR(GET_SEG(SS), cdbcmd), CDROM_CDB_SIZE / 2);
+
+    int status = pause_await_not_bsy(iobase1, iobase2);
+    if (status < 0) {
+        ret = status;
+        goto fail;
+    }
+
+    if (status & ATA_CB_STAT_ERR) {
+        u8 err = inb(iobase1 + ATA_CB_ERR);
+        // skip "Not Ready"
+        if (err != 0x20)
+            dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n"
+                    , status, err);
+        ret = -2;
+        goto fail;
+    }
+    if (!(status & ATA_CB_STAT_DRQ)) {
+        dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status);
+        ret = -3;
+        goto fail;
+    }
+
+    ret = ata_pio_transfer(op, 0, blocksize);
+
+fail:
+    // Enable interrupts
+    outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+    if (ret)
+        return DISK_RET_EBADTRACK;
+    return DISK_RET_SUCCESS;
+}
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_atapi_op(struct disk_op_s *op)
+{
+    if (!CONFIG_ATA)
+        return 0;
+    switch (op->command) {
+    case CMD_READ:
+        return cdb_read(op);
+    case CMD_FORMAT:
+    case CMD_WRITE:
+        return DISK_RET_EWRITEPROTECT;
+    default:
+        return process_ata_misc_op(op);
+    }
+}
+
+
+/****************************************************************
+ * ATA detect and init
+ ****************************************************************/
+
+// Send an identify device or identify device packet command.
+static int
+send_ata_identity(struct atadrive_s *adrive_g, u16 *buffer, int command)
+{
+    memset(buffer, 0, DISK_SECTOR_SIZE);
+
+    struct disk_op_s dop;
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = &adrive_g->drive;
+    dop.count = 1;
+    dop.lba = 1;
+    dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+
+    struct ata_pio_command cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.command = command;
+
+    return ata_pio_cmd_data(&dop, 0, &cmd);
+}
+
+// Extract the ATA/ATAPI version info.
+int
+ata_extract_version(u16 *buffer)
+{
+    // Extract ATA/ATAPI version.
+    u16 ataversion = buffer[80];
+    u8 version;
+    for (version=15; version>0; version--)
+        if (ataversion & (1<<version))
+            break;
+    return version;
+}
+
+#define MAXMODEL 40
+
+// Extract the ATA/ATAPI model info.
+char *
+ata_extract_model(char *model, u32 size, u16 *buffer)
+{
+    // Read model name
+    int i;
+    for (i=0; i<size/2; i++)
+        *(u16*)&model[i*2] = ntohs(buffer[27+i]);
+    model[size] = 0x00;
+    nullTrailingSpace(model);
+    return model;
+}
+
+// Common init code between ata and atapi
+static struct atadrive_s *
+init_atadrive(struct atadrive_s *dummy, u16 *buffer)
+{
+    struct atadrive_s *adrive_g = malloc_fseg(sizeof(*adrive_g));
+    if (!adrive_g) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(adrive_g, 0, sizeof(*adrive_g));
+    adrive_g->chan_gf = dummy->chan_gf;
+    adrive_g->slave = dummy->slave;
+    adrive_g->drive.cntl_id = adrive_g->chan_gf->chanid * 2 + dummy->slave;
+    adrive_g->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+    return adrive_g;
+}
+
+// Detect if the given drive is an atapi - initialize it if so.
+static struct atadrive_s *
+init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
+{
+    // Send an IDENTIFY_DEVICE_PACKET command to device
+    int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+    if (ret)
+        return NULL;
+
+    // Success - setup as ATAPI.
+    struct atadrive_s *adrive_g = init_atadrive(dummy, buffer);
+    if (!adrive_g)
+        return NULL;
+    adrive_g->drive.type = DTYPE_ATAPI;
+    adrive_g->drive.blksize = CDROM_SECTOR_SIZE;
+    adrive_g->drive.sectors = (u64)-1;
+    u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+    char model[MAXMODEL+1];
+    char *desc = znprintf(MAXDESCSIZE
+                          , "DVD/CD [ata%d-%d: %s ATAPI-%d %s]"
+                          , adrive_g->chan_gf->chanid, adrive_g->slave
+                          , ata_extract_model(model, MAXMODEL, buffer)
+                          , ata_extract_version(buffer)
+                          , (iscd ? "DVD/CD" : "Device"));
+    dprintf(1, "%s\n", desc);
+
+    // fill cdidmap
+    if (iscd) {
+        int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf,
+                                            adrive_g->chan_gf->chanid,
+                                            adrive_g->slave);
+        boot_add_cd(&adrive_g->drive, desc, prio);
+    }
+
+    return adrive_g;
+}
+
+// Detect if the given drive is a regular ata drive - initialize it if so.
+static struct atadrive_s *
+init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
+{
+    // Send an IDENTIFY_DEVICE command to device
+    int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_DEVICE);
+    if (ret)
+        return NULL;
+
+    // Success - setup as ATA.
+    struct atadrive_s *adrive_g = init_atadrive(dummy, buffer);
+    if (!adrive_g)
+        return NULL;
+    adrive_g->drive.type = DTYPE_ATA;
+    adrive_g->drive.blksize = DISK_SECTOR_SIZE;
+
+    adrive_g->drive.pchs.cylinders = buffer[1];
+    adrive_g->drive.pchs.heads = buffer[3];
+    adrive_g->drive.pchs.spt = buffer[6];
+
+    u64 sectors;
+    if (buffer[83] & (1 << 10)) // word 83 - lba48 support
+        sectors = *(u64*)&buffer[100]; // word 100-103
+    else
+        sectors = *(u32*)&buffer[60]; // word 60 and word 61
+    adrive_g->drive.sectors = sectors;
+    u64 adjsize = sectors >> 11;
+    char adjprefix = 'M';
+    if (adjsize >= (1 << 16)) {
+        adjsize >>= 10;
+        adjprefix = 'G';
+    }
+    char model[MAXMODEL+1];
+    char *desc = znprintf(MAXDESCSIZE
+                          , "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+                          , adrive_g->chan_gf->chanid, adrive_g->slave
+                          , ata_extract_model(model, MAXMODEL, buffer)
+                          , ata_extract_version(buffer)
+                          , (u32)adjsize, adjprefix);
+    dprintf(1, "%s\n", desc);
+
+    int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf,
+                                        adrive_g->chan_gf->chanid,
+                                        adrive_g->slave);
+    // Register with bcv system.
+    boot_add_hd(&adrive_g->drive, desc, prio);
+
+    return adrive_g;
+}
+
+static u64 SpinupEnd;
+
+// Wait for non-busy status and check for "floating bus" condition.
+static int
+powerup_await_non_bsy(u16 base)
+{
+    u8 orstatus = 0;
+    u8 status;
+    for (;;) {
+        status = inb(base+ATA_CB_STAT);
+        if (!(status & ATA_CB_STAT_BSY))
+            break;
+        orstatus |= status;
+        if (orstatus == 0xff) {
+            dprintf(4, "powerup IDE floating\n");
+            return orstatus;
+        }
+        if (check_tsc(SpinupEnd)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+    dprintf(6, "powerup iobase=%x st=%x\n", base, status);
+    return status;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ata_detect(void *data)
+{
+    struct ata_channel_s *chan_gf = data;
+    struct atadrive_s dummy;
+    memset(&dummy, 0, sizeof(dummy));
+    dummy.chan_gf = chan_gf;
+    // Device detection
+    int didreset = 0;
+    u8 slave;
+    for (slave=0; slave<=1; slave++) {
+        // Wait for not-bsy.
+        u16 iobase1 = chan_gf->iobase1;
+        int status = powerup_await_non_bsy(iobase1);
+        if (status < 0)
+            continue;
+        u8 newdh = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0;
+        outb(newdh, iobase1+ATA_CB_DH);
+        ndelay(400);
+        status = powerup_await_non_bsy(iobase1);
+        if (status < 0)
+            continue;
+
+        // Check if ioport registers look valid.
+        outb(newdh, iobase1+ATA_CB_DH);
+        u8 dh = inb(iobase1+ATA_CB_DH);
+        outb(0x55, iobase1+ATA_CB_SC);
+        outb(0xaa, iobase1+ATA_CB_SN);
+        u8 sc = inb(iobase1+ATA_CB_SC);
+        u8 sn = inb(iobase1+ATA_CB_SN);
+        dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n"
+                , chan_gf->chanid, slave, sc, sn, dh);
+        if (sc != 0x55 || sn != 0xaa || dh != newdh)
+            continue;
+
+        // Prepare new drive.
+        dummy.slave = slave;
+
+        // reset the channel
+        if (!didreset) {
+            ata_reset(&dummy);
+            didreset = 1;
+        }
+
+        // check for ATAPI
+        u16 buffer[256];
+        struct atadrive_s *adrive_g = init_drive_atapi(&dummy, buffer);
+        if (!adrive_g) {
+            // Didn't find an ATAPI drive - look for ATA drive.
+            u8 st = inb(iobase1+ATA_CB_STAT);
+            if (!st)
+                // Status not set - can't be a valid drive.
+                continue;
+
+            // Wait for RDY.
+            int ret = await_rdy(iobase1);
+            if (ret < 0)
+                continue;
+
+            // check for ATA.
+            adrive_g = init_drive_ata(&dummy, buffer);
+            if (!adrive_g)
+                // No ATA drive found
+                continue;
+        }
+
+        u16 resetresult = buffer[93];
+        dprintf(6, "ata_detect resetresult=%04x\n", resetresult);
+        if (!slave && (resetresult & 0xdf61) == 0x4041)
+            // resetresult looks valid and device 0 is responding to
+            // device 1 requests - device 1 must not be present - skip
+            // detection.
+            break;
+    }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+init_controller(int chanid, int bdf, int irq, u32 port1, u32 port2, u32 master)
+{
+    struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
+    if (!chan_gf) {
+        warn_noalloc();
+        return;
+    }
+    chan_gf->chanid = chanid;
+    chan_gf->irq = irq;
+    chan_gf->pci_bdf = bdf;
+    chan_gf->iobase1 = port1;
+    chan_gf->iobase2 = port2;
+    chan_gf->iomaster = master;
+    dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
+            , chanid, port1, port2, master, irq, bdf);
+    run_thread(ata_detect, chan_gf);
+}
+
+#define IRQ_ATA1 14
+#define IRQ_ATA2 15
+
+// Locate and init ata controllers.
+static void
+ata_init(void)
+{
+    // Scan PCI bus for ATA adapters
+    int count=0, pcicount=0;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        pcicount++;
+        if (pci_config_readw(bdf, PCI_CLASS_DEVICE) != PCI_CLASS_STORAGE_IDE)
+            continue;
+
+        u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+        u8 prog_if = pci_config_readb(bdf, PCI_CLASS_PROG);
+        int master = 0;
+        if (CONFIG_ATA_DMA && prog_if & 0x80) {
+            // Check for bus-mastering.
+            u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
+            if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+                master = bar & PCI_BASE_ADDRESS_IO_MASK;
+                pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+            }
+        }
+
+        u32 port1, port2, irq;
+        if (prog_if & 1) {
+            port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
+                     & PCI_BASE_ADDRESS_IO_MASK);
+            port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
+                     & PCI_BASE_ADDRESS_IO_MASK);
+            irq = pciirq;
+        } else {
+            port1 = PORT_ATA1_CMD_BASE;
+            port2 = PORT_ATA1_CTRL_BASE;
+            irq = IRQ_ATA1;
+        }
+        init_controller(count, bdf, irq, port1, port2, master);
+        count++;
+
+        if (prog_if & 4) {
+            port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
+                     & PCI_BASE_ADDRESS_IO_MASK);
+            port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
+                     & PCI_BASE_ADDRESS_IO_MASK);
+            irq = pciirq;
+        } else {
+            port1 = PORT_ATA2_CMD_BASE;
+            port2 = PORT_ATA2_CTRL_BASE;
+            irq = IRQ_ATA2;
+        }
+        init_controller(count, bdf, irq, port1, port2, master ? master + 8 : 0);
+        count++;
+    }
+
+    if (!CONFIG_COREBOOT && !pcicount) {
+        // No PCI devices found - probably a QEMU "-M isapc" machine.
+        // Try using ISA ports for ATA controllers.
+        init_controller(0, -1, IRQ_ATA1
+                        , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
+        init_controller(1, -1, IRQ_ATA2
+                        , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
+    }
+}
+
+void
+ata_setup(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_ATA)
+        return;
+
+    dprintf(3, "init hard drives\n");
+
+    SpinupEnd = calc_future_tsc(IDE_TIMEOUT);
+    ata_init();
+
+    SET_BDA(disk_control_byte, 0xc0);
+
+    enable_hwirq(14, FUNC16(entry_76));
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ata.h b/qemu-0.15.x/roms/seabios/src/ata.h
new file mode 100644
index 0000000..8fa2872
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ata.h
@@ -0,0 +1,153 @@
+#ifndef __ATA_H
+#define __ATA_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_MAX_ATA_INTERFACES
+#include "disk.h" // struct drive_s
+
+struct ata_channel_s {
+    u16 iobase1;
+    u16 iobase2;
+    u16 iomaster;
+    u8  irq;
+    u8  chanid;
+    int pci_bdf;
+};
+
+struct atadrive_s {
+    struct drive_s drive;
+    struct ata_channel_s *chan_gf;
+    u8 slave;
+};
+
+// ata.c
+char *ata_extract_model(char *model, u32 size, u16 *buffer);
+int ata_extract_version(u16 *buffer);
+int cdrom_read(struct disk_op_s *op);
+int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void ata_setup(void);
+int process_ata_op(struct disk_op_s *op);
+int process_atapi_op(struct disk_op_s *op);
+
+// Global defines -- ATA register and register bits.
+// command block & control block regs
+#define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
+#define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
+#define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
+#define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
+#define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
+#define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
+#define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
+#define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
+#define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
+#define ATA_CB_CMD   7   // command             out pio_base_addr1+7
+
+#define ATA_CB_ASTAT 2   // alternate status in     pio_base_addr2+2
+#define ATA_CB_DC    2   // device control      out pio_base_addr2+2
+#define ATA_CB_DA    3   // device address   in     pio_base_addr2+3
+
+#define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
+#define ATA_CB_ER_BBK  0x80    // ATA bad block
+#define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
+#define ATA_CB_ER_MC   0x20    // ATA media change
+#define ATA_CB_ER_IDNF 0x10    // ATA id not found
+#define ATA_CB_ER_MCR  0x08    // ATA media change request
+#define ATA_CB_ER_ABRT 0x04    // ATA command aborted
+#define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
+#define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
+
+#define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
+#define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
+#define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
+#define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
+#define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
+
+// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
+#define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
+#define ATA_CB_SC_P_REL    0x04   // ATAPI release
+#define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
+#define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
+
+// bits 7-4 of the device/head (CB_DH) reg
+#define ATA_CB_DH_DEV0 0xa0    // select device 0
+#define ATA_CB_DH_DEV1 0xb0    // select device 1
+#define ATA_CB_DH_LBA 0x40    // use LBA
+
+// status reg (CB_STAT and CB_ASTAT) bits
+#define ATA_CB_STAT_BSY  0x80  // busy
+#define ATA_CB_STAT_RDY  0x40  // ready
+#define ATA_CB_STAT_DF   0x20  // device fault
+#define ATA_CB_STAT_WFT  0x20  // write fault (old name)
+#define ATA_CB_STAT_SKC  0x10  // seek complete
+#define ATA_CB_STAT_SERV 0x10  // service
+#define ATA_CB_STAT_DRQ  0x08  // data request
+#define ATA_CB_STAT_CORR 0x04  // corrected
+#define ATA_CB_STAT_IDX  0x02  // index
+#define ATA_CB_STAT_ERR  0x01  // error (ATA)
+#define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
+
+// device control reg (CB_DC) bits
+#define ATA_CB_DC_HD15   0x08  // bit should always be set to one
+#define ATA_CB_DC_SRST   0x04  // soft reset
+#define ATA_CB_DC_NIEN   0x02  // disable interrupts
+
+// Most mandtory and optional ATA commands (from ATA-3),
+#define ATA_CMD_NOP                          0x00
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
+#define ATA_CMD_DEVICE_RESET                 0x08
+#define ATA_CMD_RECALIBRATE                  0x10
+#define ATA_CMD_READ_SECTORS                 0x20
+#define ATA_CMD_READ_SECTORS_EXT             0x24
+#define ATA_CMD_READ_DMA_EXT                 0x25
+#define ATA_CMD_READ_DMA_QUEUED_EXT          0x26
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS_EXT  0x27
+#define ATA_CMD_READ_MULTIPLE_EXT            0x29
+#define ATA_CMD_READ_LOG_EXT                 0x2F
+#define ATA_CMD_WRITE_SECTORS                0x30
+#define ATA_CMD_WRITE_SECTORS_EXT            0x34
+#define ATA_CMD_WRITE_DMA_EXT                0x35
+#define ATA_CMD_WRITE_DMA_QUEUED_EXT         0x36
+#define ATA_CMD_SET_MAX_ADDRESS_EXT          0x37
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
+#define ATA_CMD_WRITE_MULTIPLE_EXT           0x39
+#define ATA_CMD_WRITE_VERIFY                 0x3C
+#define ATA_CMD_WRITE_LOG_EXT                0x3F
+#define ATA_CMD_READ_VERIFY_SECTORS          0x40
+#define ATA_CMD_READ_VERIFY_SECTORS_EXT      0x42
+#define ATA_CMD_FORMAT_TRACK                 0x50
+#define ATA_CMD_SEEK                         0x70
+#define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_STANDBY_IMMEDIATE2           0x94
+#define ATA_CMD_IDLE_IMMEDIATE2              0x95
+#define ATA_CMD_STANDBY2                     0x96
+#define ATA_CMD_IDLE2                        0x97
+#define ATA_CMD_CHECK_POWER_MODE2            0x98
+#define ATA_CMD_SLEEP2                       0x99
+#define ATA_CMD_PACKET                       0xA0
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
+#define ATA_CMD_CFA_ERASE_SECTORS            0xC0
+#define ATA_CMD_READ_MULTIPLE                0xC4
+#define ATA_CMD_WRITE_MULTIPLE               0xC5
+#define ATA_CMD_SET_MULTIPLE_MODE            0xC6
+#define ATA_CMD_READ_DMA_QUEUED              0xC7
+#define ATA_CMD_READ_DMA                     0xC8
+#define ATA_CMD_WRITE_DMA                    0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED             0xCC
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
+#define ATA_CMD_STANDBY_IMMEDIATE            0xE0
+#define ATA_CMD_IDLE_IMMEDIATE               0xE1
+#define ATA_CMD_STANDBY                      0xE2
+#define ATA_CMD_IDLE                         0xE3
+#define ATA_CMD_READ_BUFFER                  0xE4
+#define ATA_CMD_CHECK_POWER_MODE             0xE5
+#define ATA_CMD_SLEEP                        0xE6
+#define ATA_CMD_FLUSH_CACHE                  0xE7
+#define ATA_CMD_WRITE_BUFFER                 0xE8
+#define ATA_CMD_IDENTIFY_DEVICE              0xEC
+#define ATA_CMD_SET_FEATURES                 0xEF
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS      0xF8
+#define ATA_CMD_SET_MAX                      0xF9
+
+#endif // ata.h
diff --git a/qemu-0.15.x/roms/seabios/src/biosvar.h b/qemu-0.15.x/roms/seabios/src/biosvar.h
new file mode 100644
index 0000000..2b755e3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/biosvar.h
@@ -0,0 +1,332 @@
+// Variable layouts of bios.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __BIOSVAR_H
+#define __BIOSVAR_H
+
+#include "types.h" // u8
+#include "farptr.h" // GET_FARVAR
+#include "config.h" // CONFIG_*
+#include "disk.h" // struct chs_s
+
+
+/****************************************************************
+ * Interupt vector table
+ ****************************************************************/
+
+struct rmode_IVT {
+    struct segoff_s ivec[256];
+};
+
+#define GET_IVT(vector)                                         \
+    GET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector])
+#define SET_IVT(vector, segoff)                                         \
+    SET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector], segoff)
+
+#define FUNC16(func) ({                                 \
+        ASSERT32FLAT();                                 \
+        extern void func (void);                        \
+        SEGOFF(SEG_BIOS, (u32)func - BUILD_BIOS_ADDR);  \
+    })
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+struct bios_data_area_s {
+    // 40:00
+    u16 port_com[4];
+    u16 port_lpt[3];
+    u16 ebda_seg;
+    // 40:10
+    u16 equipment_list_flags;
+    u8 pad1;
+    u16 mem_size_kb;
+    u8 pad2;
+    u8 ps2_ctrl_flag;
+    u8 kbd_flag0;
+    u8 kbd_flag1;
+    u8 alt_keypad;
+    u16 kbd_buf_head;
+    u16 kbd_buf_tail;
+    // 40:1e
+    u8 kbd_buf[32];
+    u8 floppy_recalibration_status;
+    u8 floppy_motor_status;
+    // 40:40
+    u8 floppy_motor_counter;
+    u8 floppy_last_status;
+    u8 floppy_return_status[7];
+    u8 video_mode;
+    u16 video_cols;
+    u16 video_pagesize;
+    u16 video_pagestart;
+    // 40:50
+    u16 cursor_pos[8];
+    // 40:60
+    u16 cursor_type;
+    u8 video_page;
+    u16 crtc_address;
+    u8 video_msr;
+    u8 video_pal;
+    struct segoff_s jump;
+    u8 other_6b;
+    u32 timer_counter;
+    // 40:70
+    u8 timer_rollover;
+    u8 break_flag;
+    u16 soft_reset_flag;
+    u8 disk_last_status;
+    u8 hdcount;
+    u8 disk_control_byte;
+    u8 port_disk;
+    u8 lpt_timeout[4];
+    u8 com_timeout[4];
+    // 40:80
+    u16 kbd_buf_start_offset;
+    u16 kbd_buf_end_offset;
+    u8 video_rows;
+    u16 char_height;
+    u8 video_ctl;
+    u8 video_switches;
+    u8 modeset_ctl;
+    u8 dcc_index;
+    u8 floppy_last_data_rate;
+    u8 disk_status_controller;
+    u8 disk_error_controller;
+    u8 disk_interrupt_flag;
+    u8 floppy_harddisk_info;
+    // 40:90
+    u8 floppy_media_state[4];
+    u8 floppy_track[2];
+    u8 kbd_flag2;
+    u8 kbd_led;
+    struct segoff_s user_wait_complete_flag;
+    u32 user_wait_timeout;
+    // 40:A0
+    u8 rtc_wait_flag;
+    u8 other_a1[7];
+    struct segoff_s video_savetable;
+    u8 other_ac[4];
+    // 40:B0
+    u8 other_b0[10];
+    u16 vbe_mode;
+} PACKED;
+
+// BDA floppy_recalibration_status bitdefs
+#define FRS_TIMEOUT (1<<7)
+
+// BDA rtc_wait_flag bitdefs
+#define RWS_WAIT_PENDING (1<<0)
+#define RWS_WAIT_ELAPSED (1<<7)
+
+// BDA floppy_media_state bitdefs
+#define FMS_DRIVE_STATE_MASK        (0x07)
+#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4)
+#define FMS_DOUBLE_STEPPING         (1<<5)
+#define FMS_DATA_RATE_MASK          (0xc0)
+
+// Accessor functions
+#define GET_BDA(var) \
+    GET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var)
+#define SET_BDA(var, val) \
+    SET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var, (val))
+#define CLEARBITS_BDA(var, val) do {                                    \
+        typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+        SET_BDA(var, (__val & ~(val)));                                 \
+    } while (0)
+#define SETBITS_BDA(var, val) do {                                      \
+        typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+        SET_BDA(var, (__val | (val)));                                  \
+    } while (0)
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+// DPTE definition
+struct dpte_s {
+    u16 iobase1;
+    u16 iobase2;
+    u8  prefix;
+    u8  unused;
+    u8  irq;
+    u8  blkcount;
+    u8  dma;
+    u8  pio;
+    u16 options;
+    u16 reserved;
+    u8  revision;
+    u8  checksum;
+};
+
+// ElTorito Device Emulation data
+struct cdemu_s {
+    struct drive_s *emulated_drive_gf;
+    u32 ilba;
+    u16 buffer_segment;
+    u16 load_segment;
+    u16 sector_count;
+    u8  active;
+    u8  media;
+    u8  emulated_extdrive;
+
+    // Virtual device
+    struct chs_s lchs;
+};
+
+struct fdpt_s {
+    u16 cylinders;
+    u8 heads;
+    u8 a0h_signature;
+    u8 phys_sectors;
+    u16 precompensation;
+    u8 reserved;
+    u8 drive_control_byte;
+    u16 phys_cylinders;
+    u8 phys_heads;
+    u16 landing_zone;
+    u8 sectors;
+    u8 checksum;
+} PACKED;
+
+struct usbkeyinfo {
+    union {
+        struct {
+            u8 modifiers;
+            u8 repeatcount;
+            u8 keys[6];
+        };
+        u64 data;
+    };
+};
+
+struct extended_bios_data_area_s {
+    u8 size;
+    u8 reserved1[0x21];
+    struct segoff_s far_call_pointer;
+    u8 mouse_flag1;
+    u8 mouse_flag2;
+    u8 mouse_data[0x08];
+    // 0x30
+    u8 other1[0x0d];
+
+    // 0x3d
+    struct fdpt_s fdpt[2];
+
+    // 0x5d
+    u8 other2[0xC4];
+
+    // 0x121 - Begin custom storage.
+    u8 ps2ctr;
+    struct usbkeyinfo usbkey_last;
+
+    int RTCusers;
+
+    // El Torito Emulation data
+    struct cdemu_s cdemu;
+
+    // Buffer for disk DPTE table
+    struct dpte_s dpte;
+
+    // Locks for removable devices
+    u8 cdrom_locks[CONFIG_MAX_EXTDRIVE];
+
+    u16 boot_sequence;
+
+    // Stack space available for code that needs it.
+    u8 extra_stack[512] __aligned(8);
+} PACKED;
+
+// The initial size and location of EBDA
+#define EBDA_SIZE_START \
+    DIV_ROUND_UP(sizeof(struct extended_bios_data_area_s), 1024)
+#define EBDA_SEGMENT_START \
+    FLATPTR_TO_SEG(BUILD_LOWRAM_END - EBDA_SIZE_START*1024)
+
+// Accessor functions
+static inline u16 get_ebda_seg(void) {
+    return GET_BDA(ebda_seg);
+}
+static inline struct extended_bios_data_area_s *
+get_ebda_ptr(void)
+{
+    ASSERT32FLAT();
+    return MAKE_FLATPTR(get_ebda_seg(), 0);
+}
+#define GET_EBDA2(eseg, var)                                            \
+    GET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var)
+#define SET_EBDA2(eseg, var, val)                                       \
+    SET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var, (val))
+#define GET_EBDA(var)                           \
+    GET_EBDA2(get_ebda_seg(), var)
+#define SET_EBDA(var, val)                      \
+    SET_EBDA2(get_ebda_seg(), var, (val))
+
+#define EBDA_OFFSET_TOP_STACK                                   \
+    offsetof(struct extended_bios_data_area_s, extra_stack[     \
+                 FIELD_SIZEOF(struct extended_bios_data_area_s  \
+                              , extra_stack)])
+
+
+/****************************************************************
+ * Global variables
+ ****************************************************************/
+
+#if MODE16 == 0 && MODESEGMENT == 1
+// In 32bit segmented mode %cs may not be readable and the code may be
+// relocated.  The entry code sets up %gs with a readable segment and
+// the code offset can be determined by get_global_offset().
+#define GLOBAL_SEGREG GS
+static inline u32 __attribute_const get_global_offset(void) {
+    u32 ret;
+    asm("  calll 1f\n"
+        "1:popl %0\n"
+        "  subl $1b, %0"
+        : "=r"(ret));
+    return ret;
+}
+#else
+#define GLOBAL_SEGREG CS
+static inline u32 __attribute_const get_global_offset(void) {
+    return 0;
+}
+#endif
+static inline u16 get_global_seg(void) {
+    return GET_SEG(GLOBAL_SEGREG);
+}
+#define GET_GLOBAL(var)                                                 \
+    GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var)              \
+                                             + get_global_offset()))
+#define SET_GLOBAL(var, val) do {               \
+        ASSERT32FLAT();                         \
+        (var) = (val);                          \
+    } while (0)
+#if MODESEGMENT
+#define GLOBALFLAT2GLOBAL(var) ((typeof(var))((void*)(var) - BUILD_BIOS_ADDR))
+#else
+#define GLOBALFLAT2GLOBAL(var) (var)
+#endif
+// Access a "flat" pointer known to point to the f-segment.
+#define GET_GLOBALFLAT(var) GET_GLOBAL(*GLOBALFLAT2GLOBAL(&(var)))
+
+
+/****************************************************************
+ * Bios Config Table
+ ****************************************************************/
+
+struct bios_config_table_s {
+    u16 size;
+    u8 model;
+    u8 submodel;
+    u8 biosrev;
+    u8 feature1, feature2, feature3, feature4, feature5;
+} PACKED;
+
+extern struct bios_config_table_s BIOS_CONFIG_TABLE __aligned(1);
+
+#endif // __BIOSVAR_H
diff --git a/qemu-0.15.x/roms/seabios/src/block.c b/qemu-0.15.x/roms/seabios/src/block.c
new file mode 100644
index 0000000..619db67
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/block.c
@@ -0,0 +1,324 @@
+// Disk setup and access
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // struct ata_s
+#include "biosvar.h" // GET_GLOBAL
+#include "cmos.h" // inb_cmos
+#include "util.h" // dprintf
+#include "ata.h" // process_ata_op
+#include "ahci.h" // process_ahci_op
+#include "usb-msc.h" // process_usb_op
+#include "virtio-blk.h" // process_virtio_op
+
+u8 FloppyCount VAR16VISIBLE;
+u8 CDCount;
+struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE;
+
+struct drive_s *
+getDrive(u8 exttype, u8 extdriveoffset)
+{
+    if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
+        return NULL;
+    struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
+    if (!drive_gf)
+        return NULL;
+    return GLOBALFLAT2GLOBAL(drive_gf);
+}
+
+int getDriveId(u8 exttype, struct drive_s *drive_g)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
+        if (getDrive(exttype, i) == drive_g)
+            return i;
+    return -1;
+}
+
+
+/****************************************************************
+ * Disk geometry translation
+ ****************************************************************/
+
+static u8
+get_translation(struct drive_s *drive_g)
+{
+    u8 type = GET_GLOBAL(drive_g->type);
+    if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
+        // Emulators pass in the translation info via nvram.
+        u8 ataid = GET_GLOBAL(drive_g->cntl_id);
+        u8 channel = ataid / 2;
+        u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
+        translation >>= 2 * (ataid % 4);
+        translation &= 0x03;
+        return translation;
+    }
+
+    // Otherwise use a heuristic to determine translation type.
+    u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+    u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+    u64 sectors = GET_GLOBAL(drive_g->sectors);
+    u64 psectors = (u64)heads * cylinders * spt;
+    if (!heads || !cylinders || !spt || psectors > sectors)
+        // pchs doesn't look valid - use LBA.
+        return TRANSLATION_LBA;
+
+    if (cylinders <= 1024 && heads <= 16 && spt <= 63)
+        return TRANSLATION_NONE;
+    if (cylinders * heads <= 131072)
+        return TRANSLATION_LARGE;
+    return TRANSLATION_LBA;
+}
+
+static void
+setup_translation(struct drive_s *drive_g)
+{
+    u8 translation = get_translation(drive_g);
+    SET_GLOBAL(drive_g->translation, translation);
+
+    u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+    u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+    u64 sectors = GET_GLOBAL(drive_g->sectors);
+    const char *desc = NULL;
+
+    switch (translation) {
+    default:
+    case TRANSLATION_NONE:
+        desc = "none";
+        break;
+    case TRANSLATION_LBA:
+        desc = "lba";
+        spt = 63;
+        if (sectors > 63*255*1024) {
+            heads = 255;
+            cylinders = 1024;
+            break;
+        }
+        u32 sect = (u32)sectors / 63;
+        heads = sect / 1024;
+        if (heads>128)
+            heads = 255;
+        else if (heads>64)
+            heads = 128;
+        else if (heads>32)
+            heads = 64;
+        else if (heads>16)
+            heads = 32;
+        else
+            heads = 16;
+        cylinders = sect / heads;
+        break;
+    case TRANSLATION_RECHS:
+        desc = "r-echs";
+        // Take care not to overflow
+        if (heads==16) {
+            if (cylinders>61439)
+                cylinders=61439;
+            heads=15;
+            cylinders = (u16)((u32)(cylinders)*16/15);
+        }
+        // then go through the large bitshift process
+    case TRANSLATION_LARGE:
+        if (translation == TRANSLATION_LARGE)
+            desc = "large";
+        while (cylinders > 1024) {
+            cylinders >>= 1;
+            heads <<= 1;
+
+            // If we max out the head count
+            if (heads > 127)
+                break;
+        }
+        break;
+    }
+    // clip to 1024 cylinders in lchs
+    if (cylinders > 1024)
+        cylinders = 1024;
+    dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
+            , drive_g
+            , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
+            , desc
+            , cylinders, heads, spt
+            , (u32)sectors);
+
+    SET_GLOBAL(drive_g->lchs.heads, heads);
+    SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
+    SET_GLOBAL(drive_g->lchs.spt, spt);
+}
+
+
+/****************************************************************
+ * Drive mapping
+ ****************************************************************/
+
+// Fill in Fixed Disk Parameter Table (located in ebda).
+static void
+fill_fdpt(struct drive_s *drive_g, int hdid)
+{
+    if (hdid > 1)
+        return;
+
+    u16 nlc   = GET_GLOBAL(drive_g->lchs.cylinders);
+    u16 nlh   = GET_GLOBAL(drive_g->lchs.heads);
+    u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
+
+    u16 npc   = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 nph   = GET_GLOBAL(drive_g->pchs.heads);
+    u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
+
+    struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
+    fdpt->precompensation = 0xffff;
+    fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
+    fdpt->landing_zone = npc;
+    fdpt->cylinders = nlc;
+    fdpt->heads = nlh;
+    fdpt->sectors = nlspt;
+
+    if (nlc != npc || nlh != nph || nlspt != npspt) {
+        // Logical mapping present - use extended structure.
+
+        // complies with Phoenix style Translated Fixed Disk Parameter
+        // Table (FDPT)
+        fdpt->phys_cylinders = npc;
+        fdpt->phys_heads = nph;
+        fdpt->phys_sectors = npspt;
+        fdpt->a0h_signature = 0xa0;
+
+        // Checksum structure.
+        fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
+    }
+
+    if (hdid == 0)
+        SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
+                                 struct extended_bios_data_area_s, fdpt[0])));
+    else
+        SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
+                                 struct extended_bios_data_area_s, fdpt[1])));
+}
+
+// Find spot to add a drive
+static void
+add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g)
+{
+    if (*count >= ARRAY_SIZE(IDMap[0])) {
+        warn_noalloc();
+        return;
+    }
+    idmap[*count] = drive_g;
+    *count = *count + 1;
+}
+
+// Map a hard drive
+void
+map_hd_drive(struct drive_s *drive_g)
+{
+    ASSERT32FLAT();
+    struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+    int hdid = bda->hdcount;
+    dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid);
+    add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
+
+    // Setup disk geometry translation.
+    setup_translation(drive_g);
+
+    // Fill "fdpt" structure.
+    fill_fdpt(drive_g, hdid);
+}
+
+// Map a cd
+void
+map_cd_drive(struct drive_s *drive_g)
+{
+    dprintf(3, "Mapping cd drive %p\n", drive_g);
+    add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
+}
+
+// Map a floppy
+void
+map_floppy_drive(struct drive_s *drive_g)
+{
+    dprintf(3, "Mapping floppy drive %p\n", drive_g);
+    add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
+
+    // Update equipment word bits for floppy
+    if (FloppyCount == 1) {
+        // 1 drive, ready for boot
+        SETBITS_BDA(equipment_list_flags, 0x01);
+        SET_BDA(floppy_harddisk_info, 0x07);
+    } else if (FloppyCount >= 2) {
+        // 2 drives, ready for boot
+        SETBITS_BDA(equipment_list_flags, 0x41);
+        SET_BDA(floppy_harddisk_info, 0x77);
+    }
+}
+
+
+/****************************************************************
+ * 16bit calling interface
+ ****************************************************************/
+
+// Execute a disk_op request.
+int
+process_op(struct disk_op_s *op)
+{
+    ASSERT16();
+    u8 type = GET_GLOBAL(op->drive_g->type);
+    switch (type) {
+    case DTYPE_FLOPPY:
+        return process_floppy_op(op);
+    case DTYPE_ATA:
+        return process_ata_op(op);
+    case DTYPE_ATAPI:
+        return process_atapi_op(op);
+    case DTYPE_RAMDISK:
+        return process_ramdisk_op(op);
+    case DTYPE_CDEMU:
+        return process_cdemu_op(op);
+    case DTYPE_USB:
+        return process_usb_op(op);
+    case DTYPE_VIRTIO:
+	return process_virtio_op(op);
+    case DTYPE_AHCI:
+	return process_ahci_op(op);
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+// Execute a "disk_op_s" request - this runs on a stack in the ebda.
+static int
+__send_disk_op(struct disk_op_s *op_far, u16 op_seg)
+{
+    struct disk_op_s dop;
+    memcpy_far(GET_SEG(SS), &dop
+               , op_seg, op_far
+               , sizeof(dop));
+
+    dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
+            , dop.drive_g, (u32)dop.lba, dop.buf_fl
+            , dop.count, dop.command);
+
+    int status = process_op(&dop);
+
+    // Update count with total sectors transferred.
+    SET_FARVAR(op_seg, op_far->count, dop.count);
+
+    return status;
+}
+
+// Execute a "disk_op_s" request by jumping to a stack in the ebda.
+int
+send_disk_op(struct disk_op_s *op)
+{
+    ASSERT16();
+    if (! CONFIG_DRIVES)
+        return -1;
+
+    return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/blockcmd.c b/qemu-0.15.x/roms/seabios/src/blockcmd.c
new file mode 100644
index 0000000..c9c6845
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/blockcmd.c
@@ -0,0 +1,81 @@
+// Support for several common scsi like command data block requests
+//
+// Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // htonl
+#include "disk.h" // struct disk_op_s
+#include "blockcmd.h" // struct cdb_request_sense
+#include "ata.h" // atapi_cmd_data
+#include "ahci.h" // atapi_cmd_data
+#include "usb-msc.h" // usb_cmd_data
+
+// Route command to low-level handler.
+static int
+cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+    u8 type = GET_GLOBAL(op->drive_g->type);
+    switch (type) {
+    case DTYPE_ATAPI:
+        return atapi_cmd_data(op, cdbcmd, blocksize);
+    case DTYPE_USB:
+        return usb_cmd_data(op, cdbcmd, blocksize);
+    case DTYPE_AHCI:
+        return ahci_cmd_data(op, cdbcmd, blocksize);
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+int
+cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
+{
+    struct cdb_request_sense cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.command = CDB_CMD_INQUIRY;
+    cmd.length = sizeof(*data);
+    op->count = 1;
+    op->buf_fl = data;
+    return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Request SENSE
+int
+cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
+{
+    struct cdb_request_sense cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.command = CDB_CMD_REQUEST_SENSE;
+    cmd.length = sizeof(*data);
+    op->count = 1;
+    op->buf_fl = data;
+    return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Request capacity
+int
+cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
+{
+    struct cdb_read_capacity cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.command = CDB_CMD_READ_CAPACITY;
+    op->count = 1;
+    op->buf_fl = data;
+    return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Read sectors.
+int
+cdb_read(struct disk_op_s *op)
+{
+    struct cdb_rwdata_10 cmd;
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.command = CDB_CMD_READ_10;
+    cmd.lba = htonl(op->lba);
+    cmd.count = htons(op->count);
+    return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
+}
diff --git a/qemu-0.15.x/roms/seabios/src/blockcmd.h b/qemu-0.15.x/roms/seabios/src/blockcmd.h
new file mode 100644
index 0000000..903c435
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/blockcmd.h
@@ -0,0 +1,77 @@
+// Definitions for SCSI style command data blocks.
+#ifndef __BLOCKCMD_H
+#define __BLOCKCMD_H
+
+#include "types.h" // u8
+
+#define CDB_CMD_READ_10 0x28
+#define CDB_CMD_VERIFY_10 0x2f
+#define CDB_CMD_WRITE_10 0x2a
+
+struct cdb_rwdata_10 {
+    u8 command;
+    u8 flags;
+    u32 lba;
+    u8 resreved_06;
+    u16 count;
+    u8 reserved_09;
+    u8 pad[6];
+} PACKED;
+
+#define CDB_CMD_READ_CAPACITY 0x25
+
+struct cdb_read_capacity {
+    u8 command;
+    u8 flags;
+    u8 resreved_02[8];
+    u8 pad[6];
+} PACKED;
+
+struct cdbres_read_capacity {
+    u32 sectors;
+    u32 blksize;
+} PACKED;
+
+#define CDB_CMD_INQUIRY 0x12
+#define CDB_CMD_REQUEST_SENSE 0x03
+
+struct cdb_request_sense {
+    u8 command;
+    u8 flags;
+    u16 reserved_02;
+    u8 length;
+    u8 reserved_05;
+    u8 pad[10];
+} PACKED;
+
+struct cdbres_request_sense {
+    u8 errcode;
+    u8 segment;
+    u8 flags;
+    u32 info;
+    u8 additional;
+    u32 specific;
+    u8 asc;
+    u8 ascq;
+    u32 reserved_0e;
+} PACKED;
+
+struct cdbres_inquiry {
+    u8 pdt;
+    u8 removable;
+    u8 reserved_02[2];
+    u8 additional;
+    u8 reserved_05[3];
+    char vendor[8];
+    char product[16];
+    char rev[4];
+} PACKED;
+
+// blockcmd.c
+int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data);
+int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data);
+int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_read(struct disk_op_s *op);
+
+#endif // blockcmd.h
diff --git a/qemu-0.15.x/roms/seabios/src/boot.c b/qemu-0.15.x/roms/seabios/src/boot.c
new file mode 100644
index 0000000..1cd4126
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/boot.c
@@ -0,0 +1,648 @@
+// Code to load disk image and start system boot.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "config.h" // CONFIG_*
+#include "disk.h" // cdrom_boot
+#include "bregs.h" // struct bregs
+#include "boot.h" // func defs
+#include "cmos.h" // inb_cmos
+#include "paravirt.h" // romfile_loadfile
+#include "pci.h" //pci_bdf_to_*
+
+
+/****************************************************************
+ * Boot priority ordering
+ ****************************************************************/
+
+static char **Bootorder;
+static int BootorderCount;
+
+static void
+loadBootOrder(void)
+{
+    char *f = romfile_loadfile("bootorder", NULL);
+    if (!f)
+        return;
+
+    int i = 0;
+    BootorderCount = 1;
+    while (f[i]) {
+        if (f[i] == '\n')
+            BootorderCount++;
+        i++;
+    }
+    Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
+    if (!Bootorder) {
+        warn_noalloc();
+        free(f);
+        BootorderCount = 0;
+        return;
+    }
+
+    dprintf(3, "boot order:\n");
+    i = 0;
+    do {
+        Bootorder[i] = f;
+        f = strchr(f, '\n');
+        if (f)
+            *(f++) = '\0';
+        nullTrailingSpace(Bootorder[i]);
+        dprintf(3, "%d: %s\n", i+1, Bootorder[i]);
+        i++;
+    } while (f);
+}
+
+// See if 'str' starts with 'glob' - if glob contains an '*' character
+// it will match any number of characters in str that aren't a '/' or
+// the next glob character.
+static char *
+glob_prefix(const char *glob, const char *str)
+{
+    for (;;) {
+        if (!*glob && (!*str || *str == '/'))
+            return (char*)str;
+        if (*glob == '*') {
+            if (!*str || *str == '/' || *str == glob[1])
+                glob++;
+            else
+                str++;
+            continue;
+        }
+        if (*glob != *str)
+            return NULL;
+        glob++;
+        str++;
+    }
+}
+
+// Search the bootorder list for the given glob pattern.
+static int
+find_prio(const char *glob)
+{
+    dprintf(1, "Searching bootorder for: %s\n", glob);
+    int i;
+    for (i = 0; i < BootorderCount; i++)
+        if (glob_prefix(glob, Bootorder[i]))
+            return i+1;
+    return -1;
+}
+
+#define FW_PCI_DOMAIN "/pci at i0cf8"
+
+static char *
+build_pci_path(char *buf, int max, const char *devname, int bdf)
+{
+    // Build the string path of a bdf - for example: /pci at i0cf8/isa at 1,2
+    char *p = buf;
+    int parent = pci_bdf_to_bus(bdf);
+    if (PCIpaths)
+        parent = PCIpaths[parent];
+    int parentdev = parent & 0xffff;
+    if (parent & PP_PCIBRIDGE) {
+        p = build_pci_path(p, max, "pci-bridge", parentdev);
+    } else {
+        if (parentdev)
+            p += snprintf(p, max, "/pci-root@%x", parentdev);
+        p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+    }
+
+    int dev = pci_bdf_to_dev(bdf), fn = pci_bdf_to_fn(bdf);
+    p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
+    if (fn)
+        p += snprintf(p, buf+max-p, ",%x", fn);
+    return p;
+}
+
+int bootprio_find_pci_device(int bdf)
+{
+    // Find pci device - for example: /pci at i0cf8/ethernet at 5
+    char desc[256];
+    build_pci_path(desc, sizeof(desc), "*", bdf);
+    return find_prio(desc);
+}
+
+int bootprio_find_ata_device(int bdf, int chanid, int slave)
+{
+    if (bdf == -1)
+        // support only pci machine for now
+        return -1;
+    // Find ata drive - for example: /pci at i0cf8/ide at 1,1/drive at 1/disk at 0
+    char desc[256], *p;
+    p = build_pci_path(desc, sizeof(desc), "*", bdf);
+    snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave);
+    return find_prio(desc);
+}
+
+int bootprio_find_fdc_device(int bdf, int port, int fdid)
+{
+    if (bdf == -1)
+        // support only pci machine for now
+        return -1;
+    // Find floppy - for example: /pci at i0cf8/isa at 1/fdc at 03f1/floppy at 0
+    char desc[256], *p;
+    p = build_pci_path(desc, sizeof(desc), "isa", bdf);
+    snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
+    return find_prio(desc);
+}
+
+int bootprio_find_pci_rom(int bdf, int instance)
+{
+    // Find pci rom - for example: /pci at i0cf8/scsi at 3:rom2
+    char desc[256], *p;
+    p = build_pci_path(desc, sizeof(desc), "*", bdf);
+    if (instance)
+        snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+    return find_prio(desc);
+}
+
+int bootprio_find_named_rom(const char *name, int instance)
+{
+    // Find named rom - for example: /rom at genroms/linuxboot.bin
+    char desc[256], *p;
+    p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
+    if (instance)
+        snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+    return find_prio(desc);
+}
+
+int bootprio_find_usb(int bdf, u64 path)
+{
+    // Find usb - for example: /pci at i0cf8/usb at 1,2/hub at 1/network at 0/ethernet at 0
+    int i;
+    char desc[256], *p;
+    p = build_pci_path(desc, sizeof(desc), "usb", bdf);
+    for (i=56; i>0; i-=8) {
+        int port = (path >> i) & 0xff;
+        if (port != 0xff)
+            p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port);
+    }
+    snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff));
+    return find_prio(desc);
+}
+
+
+/****************************************************************
+ * Boot setup
+ ****************************************************************/
+
+static int CheckFloppySig = 1;
+
+#define DEFAULT_PRIO           9999
+
+static int DefaultFloppyPrio = 101;
+static int DefaultCDPrio     = 102;
+static int DefaultHDPrio     = 103;
+static int DefaultBEVPrio    = 104;
+
+void
+boot_setup(void)
+{
+    if (! CONFIG_BOOT)
+        return;
+
+    SET_EBDA(boot_sequence, 0xffff);
+
+    if (!CONFIG_COREBOOT) {
+        // On emulators, get boot order from nvram.
+        if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)
+            CheckFloppySig = 0;
+        u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
+                         | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
+        DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
+            = DefaultBEVPrio = DEFAULT_PRIO;
+        int i;
+        for (i=101; i<104; i++) {
+            u32 val = bootorder & 0x0f;
+            bootorder >>= 4;
+            switch (val) {
+            case 1: DefaultFloppyPrio = i; break;
+            case 2: DefaultHDPrio = i;     break;
+            case 3: DefaultCDPrio = i;     break;
+            case 4: DefaultBEVPrio = i;    break;
+            }
+        }
+    }
+
+    loadBootOrder();
+}
+
+
+/****************************************************************
+ * BootList handling
+ ****************************************************************/
+
+struct bootentry_s {
+    int type;
+    union {
+        u32 data;
+        struct segoff_s vector;
+        struct drive_s *drive;
+    };
+    int priority;
+    const char *description;
+    struct bootentry_s *next;
+};
+static struct bootentry_s *BootList;
+
+#define IPL_TYPE_FLOPPY      0x01
+#define IPL_TYPE_HARDDISK    0x02
+#define IPL_TYPE_CDROM       0x03
+#define IPL_TYPE_CBFS        0x20
+#define IPL_TYPE_BEV         0x80
+#define IPL_TYPE_BCV         0x81
+
+static void
+bootentry_add(int type, int prio, u32 data, const char *desc)
+{
+    if (! CONFIG_BOOT)
+        return;
+    struct bootentry_s *be = malloc_tmp(sizeof(*be));
+    if (!be) {
+        warn_noalloc();
+        return;
+    }
+    be->type = type;
+    be->priority = prio;
+    be->data = data;
+    be->description = desc ?: "?";
+    dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
+            , be->description, type, prio, data);
+
+    // Add entry in sorted order.
+    struct bootentry_s **pprev;
+    for (pprev = &BootList; *pprev; pprev = &(*pprev)->next) {
+        struct bootentry_s *pos = *pprev;
+        if (be->priority < pos->priority)
+            break;
+        if (be->priority > pos->priority)
+            continue;
+        if (be->type < pos->type)
+            break;
+        if (be->type > pos->type)
+            continue;
+        if (be->type <= IPL_TYPE_CDROM
+            && (be->drive->type < pos->drive->type
+                || (be->drive->type == pos->drive->type
+                    && be->drive->cntl_id < pos->drive->cntl_id)))
+            break;
+    }
+    be->next = *pprev;
+    *pprev = be;
+}
+
+// Return the given priority if it's set - defaultprio otherwise.
+static inline int defPrio(int priority, int defaultprio) {
+    return (priority < 0) ? defaultprio : priority;
+}
+
+// Add a BEV vector for a given pnp compatible option rom.
+void
+boot_add_bev(u16 seg, u16 bev, u16 desc, int prio)
+{
+    bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio)
+                  , SEGOFF(seg, bev).segoff
+                  , desc ? MAKE_FLATPTR(seg, desc) : "Unknown");
+    DefaultBEVPrio = DEFAULT_PRIO;
+}
+
+// Add a bcv entry for an expansion card harddrive or legacy option rom
+void
+boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio)
+{
+    bootentry_add(IPL_TYPE_BCV, defPrio(prio, DEFAULT_PRIO)
+                  , SEGOFF(seg, ip).segoff
+                  , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom");
+}
+
+void
+boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio)
+{
+    bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
+                  , (u32)drive_g, desc);
+}
+
+void
+boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
+{
+    bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
+                  , (u32)drive_g, desc);
+}
+
+void
+boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
+{
+    bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
+                  , (u32)drive_g, desc);
+}
+
+// Add a CBFS payload entry
+void
+boot_add_cbfs(void *data, const char *desc, int prio)
+{
+    bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc);
+}
+
+
+/****************************************************************
+ * Boot menu and BCV execution
+ ****************************************************************/
+
+// Show IPL option menu.
+static void
+interactive_bootmenu(void)
+{
+    if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
+        return;
+
+    while (get_keystroke(0) >= 0)
+        ;
+
+    printf("Press F12 for boot menu.\n\n");
+
+    enable_bootsplash();
+    int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
+    disable_bootsplash();
+    if (scan_code != 0x86)
+        /* not F12 */
+        return;
+
+    while (get_keystroke(0) >= 0)
+        ;
+
+    printf("Select boot device:\n\n");
+    wait_threads();
+
+    // Show menu items
+    struct bootentry_s *pos = BootList;
+    int maxmenu = 0;
+    while (pos) {
+        char desc[60];
+        maxmenu++;
+        printf("%d. %s\n", maxmenu
+               , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        pos = pos->next;
+    }
+
+    // Get key press
+    for (;;) {
+        scan_code = get_keystroke(1000);
+        if (scan_code >= 1 && scan_code <= maxmenu+1)
+            break;
+    }
+    printf("\n");
+    if (scan_code == 0x01)
+        // ESC
+        return;
+
+    // Find entry and make top priority.
+    int choice = scan_code - 1;
+    struct bootentry_s **pprev = &BootList;
+    while (--choice)
+        pprev = &(*pprev)->next;
+    pos = *pprev;
+    *pprev = pos->next;
+    pos->next = BootList;
+    BootList = pos;
+    pos->priority = 0;
+}
+
+// BEV (Boot Execution Vector) list
+struct bev_s {
+    int type;
+    u32 vector;
+};
+static struct bev_s BEV[20];
+static int BEVCount;
+static int HaveHDBoot, HaveFDBoot;
+
+static void
+add_bev(int type, u32 vector)
+{
+    if (type == IPL_TYPE_HARDDISK && HaveHDBoot++)
+        return;
+    if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
+        return;
+    if (BEVCount >= ARRAY_SIZE(BEV))
+        return;
+    struct bev_s *bev = &BEV[BEVCount++];
+    bev->type = type;
+    bev->vector = vector;
+}
+
+// Prepare for boot - show menu and run bcvs.
+void
+boot_prep(void)
+{
+    if (! CONFIG_BOOT) {
+        wait_threads();
+        return;
+    }
+
+    // XXX - show available drives?
+
+    // Allow user to modify BCV/IPL order.
+    interactive_bootmenu();
+    wait_threads();
+
+    // Map drives and populate BEV list
+    struct bootentry_s *pos = BootList;
+    while (pos) {
+        switch (pos->type) {
+        case IPL_TYPE_BCV:
+            call_bcv(pos->vector.seg, pos->vector.offset);
+            add_bev(IPL_TYPE_HARDDISK, 0);
+            break;
+        case IPL_TYPE_FLOPPY:
+            map_floppy_drive(pos->drive);
+            add_bev(IPL_TYPE_FLOPPY, 0);
+            break;
+        case IPL_TYPE_HARDDISK:
+            map_hd_drive(pos->drive);
+            add_bev(IPL_TYPE_HARDDISK, 0);
+            break;
+        case IPL_TYPE_CDROM:
+            map_cd_drive(pos->drive);
+            // NO BREAK
+        default:
+            add_bev(pos->type, pos->data);
+            break;
+        }
+        pos = pos->next;
+    }
+
+    // If nothing added a floppy/hd boot - add it manually.
+    add_bev(IPL_TYPE_FLOPPY, 0);
+    add_bev(IPL_TYPE_HARDDISK, 0);
+}
+
+
+/****************************************************************
+ * Boot code (int 18/19)
+ ****************************************************************/
+
+// Jump to a bootup entry point.
+static void
+call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
+{
+    dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    br.code = bootsegip;
+    // Set the magic number in ax and the boot drive in dl.
+    br.dl = bootdrv;
+    br.ax = 0xaa55;
+    call16(&br);
+}
+
+// Boot from a disk (either floppy or harddrive)
+static void
+boot_disk(u8 bootdrv, int checksig)
+{
+    u16 bootseg = 0x07c0;
+
+    // Read sector
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    br.dl = bootdrv;
+    br.es = bootseg;
+    br.ah = 2;
+    br.al = 1;
+    br.cl = 1;
+    call16_int(0x13, &br);
+
+    if (br.flags & F_CF) {
+        printf("Boot failed: could not read the boot disk\n\n");
+        return;
+    }
+
+    if (checksig) {
+        struct mbr_s *mbr = (void*)0;
+        if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
+            printf("Boot failed: not a bootable disk\n\n");
+            return;
+        }
+    }
+
+    /* Canonicalize bootseg:bootip */
+    u16 bootip = (bootseg & 0x0fff) << 4;
+    bootseg &= 0xf000;
+
+    call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CD-ROM
+static void
+boot_cdrom(struct drive_s *drive_g)
+{
+    if (! CONFIG_CDROM_BOOT)
+        return;
+    printf("Booting from DVD/CD...\n");
+
+    int status = cdrom_boot(drive_g);
+    if (status) {
+        printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
+        return;
+    }
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+    u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
+    /* Canonicalize bootseg:bootip */
+    u16 bootip = (bootseg & 0x0fff) << 4;
+    bootseg &= 0xf000;
+
+    call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CBFS payload
+static void
+boot_cbfs(struct cbfs_file *file)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+        return;
+    printf("Booting from CBFS...\n");
+    cbfs_run_payload(file);
+}
+
+// Boot from a BEV entry on an optionrom.
+static void
+boot_rom(u32 vector)
+{
+    printf("Booting from ROM...\n");
+    struct segoff_s so;
+    so.segoff = vector;
+    call_boot_entry(so, 0);
+}
+
+// Determine next boot method and attempt a boot using it.
+static void
+do_boot(u16 seq_nr)
+{
+    if (! CONFIG_BOOT)
+        panic("Boot support not compiled in.\n");
+
+    if (seq_nr >= BEVCount) {
+        printf("No bootable device.\n");
+        // Loop with irqs enabled - this allows ctrl+alt+delete to work.
+        for (;;)
+            wait_irq();
+    }
+
+    // Boot the given BEV type.
+    struct bev_s *ie = &BEV[seq_nr];
+    switch (ie->type) {
+    case IPL_TYPE_FLOPPY:
+        printf("Booting from Floppy...\n");
+        boot_disk(0x00, CheckFloppySig);
+        break;
+    case IPL_TYPE_HARDDISK:
+        printf("Booting from Hard Disk...\n");
+        boot_disk(0x80, 1);
+        break;
+    case IPL_TYPE_CDROM:
+        boot_cdrom((void*)ie->vector);
+        break;
+    case IPL_TYPE_CBFS:
+        boot_cbfs((void*)ie->vector);
+        break;
+    case IPL_TYPE_BEV:
+        boot_rom(ie->vector);
+        break;
+    }
+
+    // Boot failed: invoke the boot recovery function
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x18, &br);
+}
+
+// Boot Failure recovery: try the next device.
+void VISIBLE32FLAT
+handle_18(void)
+{
+    debug_serial_setup();
+    debug_enter(NULL, DEBUG_HDL_18);
+    u16 ebda_seg = get_ebda_seg();
+    u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
+    SET_EBDA2(ebda_seg, boot_sequence, seq);
+    do_boot(seq);
+}
+
+// INT 19h Boot Load Service Entry Point
+void VISIBLE32FLAT
+handle_19(void)
+{
+    debug_serial_setup();
+    debug_enter(NULL, DEBUG_HDL_19);
+    SET_EBDA(boot_sequence, 0);
+    do_boot(0);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/boot.h b/qemu-0.15.x/roms/seabios/src/boot.h
new file mode 100644
index 0000000..a6f358f
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/boot.h
@@ -0,0 +1,22 @@
+// Storage for boot definitions.
+#ifndef __BOOT_H
+#define __BOOT_H
+
+// boot.c
+void boot_setup(void);
+void boot_add_bev(u16 seg, u16 bev, u16 desc, int prio);
+void boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio);
+struct drive_s;
+void boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_hd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cbfs(void *data, const char *desc, int prio);
+void boot_prep(void);
+int bootprio_find_pci_device(int bdf);
+int bootprio_find_ata_device(int bdf, int chanid, int slave);
+int bootprio_find_fdc_device(int bdf, int port, int fdid);
+int bootprio_find_pci_rom(int bdf, int instance);
+int bootprio_find_named_rom(const char *name, int instance);
+int bootprio_find_usb(int bdf, u64 path);
+
+#endif // __BOOT_H
diff --git a/qemu-0.15.x/roms/seabios/src/bootsplash.c b/qemu-0.15.x/roms/seabios/src/bootsplash.c
new file mode 100644
index 0000000..cf1a603
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/bootsplash.c
@@ -0,0 +1,255 @@
+// Option rom scanning code.
+//
+// Copyright (C) 2009-2010  coresystems GmbH
+// Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "jpeg.h" // splash
+#include "biosvar.h" // SET_EBDA
+#include "paravirt.h" // romfile_find
+
+
+/****************************************************************
+ * VESA structures
+ ****************************************************************/
+
+struct vesa_info {
+    u32 vesa_signature;
+    u16 vesa_version;
+    struct segoff_s oem_string_ptr;
+    u8 capabilities[4];
+    struct segoff_s video_mode_ptr;
+    u16 total_memory;
+    u16 oem_software_rev;
+    struct segoff_s oem_vendor_name_ptr;
+    struct segoff_s oem_product_name_ptr;
+    struct segoff_s oem_product_rev_ptr;
+    u8 reserved[222];
+    u8 oem_data[256];
+} PACKED;
+
+#define VESA_SIGNATURE 0x41534556 // VESA
+#define VBE2_SIGNATURE 0x32454256 // VBE2
+
+struct vesa_mode_info {
+    u16 mode_attributes;
+    u8 win_a_attributes;
+    u8 win_b_attributes;
+    u16 win_granularity;
+    u16 win_size;
+    u16 win_a_segment;
+    u16 win_b_segment;
+    u32 win_func_ptr;
+    u16 bytes_per_scanline;
+    u16 x_resolution;
+    u16 y_resolution;
+    u8 x_charsize;
+    u8 y_charsize;
+    u8 number_of_planes;
+    u8 bits_per_pixel;
+    u8 number_of_banks;
+    u8 memory_model;
+    u8 bank_size;
+    u8 number_of_image_pages;
+    u8 reserved_page;
+    u8 red_mask_size;
+    u8 red_mask_pos;
+    u8 green_mask_size;
+    u8 green_mask_pos;
+    u8 blue_mask_size;
+    u8 blue_mask_pos;
+    u8 reserved_mask_size;
+    u8 reserved_mask_pos;
+    u8 direct_color_mode_info;
+    void *phys_base_ptr;
+    u32 offscreen_mem_offset;
+    u16 offscreen_mem_size;
+    u8 reserved[206];
+} PACKED;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Call int10 vga handler.
+static void
+call16_int10(struct bregs *br)
+{
+    br->flags = F_IF;
+    start_preempt();
+    call16_int(0x10, br);
+    finish_preempt();
+}
+
+
+/****************************************************************
+ * VGA text / graphics console
+ ****************************************************************/
+
+void
+enable_vga_console(void)
+{
+    dprintf(1, "Turning on vga text mode console\n");
+    struct bregs br;
+
+    /* Enable VGA text mode */
+    memset(&br, 0, sizeof(br));
+    br.ax = 0x0003;
+    call16_int10(&br);
+
+    // Write to screen.
+    printf("SeaBIOS (version %s)\n\n", VERSION);
+}
+
+static int
+find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info
+               , int width, int height)
+{
+    dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height);
+    u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr);
+    for (;; videomodes++) {
+        u16 videomode = *videomodes;
+        if (videomode == 0xffff) {
+            dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n"
+                    , width, height);
+            return -1;
+        }
+        struct bregs br;
+        memset(&br, 0, sizeof(br));
+        br.ax = 0x4f01;
+        br.cx = (1 << 14) | videomode;
+        br.di = FLATPTR_TO_OFFSET(mode_info);
+        br.es = FLATPTR_TO_SEG(mode_info);
+        call16_int10(&br);
+        if (br.ax != 0x4f) {
+            dprintf(1, "get_mode failed.\n");
+            continue;
+        }
+        if (mode_info->x_resolution != width
+            || mode_info->y_resolution != height)
+            continue;
+        u8 depth = mode_info->bits_per_pixel;
+        if (depth != 16 && depth != 24 && depth != 32)
+            continue;
+        return videomode;
+    }
+}
+
+static int BootsplashActive;
+
+void
+enable_bootsplash(void)
+{
+    if (!CONFIG_BOOTSPLASH)
+        return;
+    dprintf(3, "Checking for bootsplash\n");
+    int filesize;
+    u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
+    if (!filedata)
+        return;
+
+    u8 *picture = NULL;
+    struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
+    struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
+    struct jpeg_decdata *jpeg = jpeg_alloc();
+    if (!jpeg || !vesa_info || !mode_info) {
+        warn_noalloc();
+        goto done;
+    }
+
+    /* Check whether we have a VESA 2.0 compliant BIOS */
+    memset(vesa_info, 0, sizeof(struct vesa_info));
+    vesa_info->vesa_signature = VBE2_SIGNATURE;
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.ax = 0x4f00;
+    br.di = FLATPTR_TO_OFFSET(vesa_info);
+    br.es = FLATPTR_TO_SEG(vesa_info);
+    call16_int10(&br);
+    if (vesa_info->vesa_signature != VESA_SIGNATURE) {
+        dprintf(1,"No VBE2 found.\n");
+        goto done;
+    }
+
+    /* Print some debugging information about our card. */
+    char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr);
+    char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
+    dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
+            vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff,
+            vendor, product);
+
+    // Parse jpeg and get image size.
+    dprintf(5, "Decoding bootsplash.jpg\n");
+    int ret = jpeg_decode(jpeg, filedata);
+    if (ret) {
+        dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
+        goto done;
+    }
+    int width, height;
+    jpeg_get_size(jpeg, &width, &height);
+
+    // Try to find a graphics mode with the corresponding dimensions.
+    int videomode = find_videomode(vesa_info, mode_info, width, height);
+    if (videomode < 0)
+        goto done;
+    void *framebuffer = mode_info->phys_base_ptr;
+    int depth = mode_info->bits_per_pixel;
+    dprintf(3, "mode: %04x\n", videomode);
+    dprintf(3, "framebuffer: %p\n", framebuffer);
+    dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
+    dprintf(3, "bits per pixel: %d\n", depth);
+
+    // Allocate space for image and decompress it.
+    int imagesize = width * height * (depth / 8);
+    picture = malloc_tmphigh(imagesize);
+    if (!picture) {
+        warn_noalloc();
+        goto done;
+    }
+    dprintf(5, "Decompressing bootsplash.jpg\n");
+    ret = jpeg_show(jpeg, picture, width, height, depth);
+    if (ret) {
+        dprintf(1, "jpeg_show failed with return code %d...\n", ret);
+        goto done;
+    }
+
+    /* Switch to graphics mode */
+    dprintf(5, "Switching to graphics mode\n");
+    memset(&br, 0, sizeof(br));
+    br.ax = 0x4f02;
+    br.bx = (1 << 14) | videomode;
+    call16_int10(&br);
+    if (br.ax != 0x4f) {
+        dprintf(1, "set_mode failed.\n");
+        goto done;
+    }
+
+    /* Show the picture */
+    dprintf(5, "Showing bootsplash.jpg\n");
+    iomemcpy(framebuffer, picture, imagesize);
+    dprintf(5, "Bootsplash copy complete\n");
+    BootsplashActive = 1;
+
+done:
+    free(filedata);
+    free(picture);
+    free(vesa_info);
+    free(mode_info);
+    free(jpeg);
+    return;
+}
+
+void
+disable_bootsplash(void)
+{
+    if (!CONFIG_BOOTSPLASH || !BootsplashActive)
+        return;
+    BootsplashActive = 0;
+    enable_vga_console();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/bregs.h b/qemu-0.15.x/roms/seabios/src/bregs.h
new file mode 100644
index 0000000..9a381d0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/bregs.h
@@ -0,0 +1,96 @@
+// Structure layout of cpu registers the the bios uses.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef __BREGS_H
+#define __BREGS_H
+
+// CPU flag bitdefs
+#define F_CF (1<<0)
+#define F_ZF (1<<6)
+#define F_IF (1<<9)
+
+// CR0 flags
+#define CR0_PG (1<<31) // Paging
+#define CR0_CD (1<<30) // Cache disable
+#define CR0_NW (1<<29) // Not Write-through
+#define CR0_PE (1<<0)  // Protection enable
+
+
+#ifndef __ASSEMBLY__
+
+#include "farptr.h" // struct segoff_s
+
+/****************************************************************
+ * Registers saved/restored in romlayout.S
+ ****************************************************************/
+
+#include "types.h" // u16
+
+#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
+
+// Layout of registers passed in to irq handlers.  Note that this
+// layout corresponds to code in romlayout.S - don't change it here
+// without also updating the assembler code.
+struct bregs {
+    u16 ds;
+    u16 es;
+    UREG(edi, di, di_hi, di_lo);
+    UREG(esi, si, si_hi, si_lo);
+    UREG(ebp, bp, bp_hi, bp_lo);
+    UREG(ebx, bx, bh, bl);
+    UREG(edx, dx, dh, dl);
+    UREG(ecx, cx, ch, cl);
+    UREG(eax, ax, ah, al);
+    struct segoff_s code;
+    u16 flags;
+} PACKED;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+set_cf(struct bregs *regs, int cond)
+{
+    if (cond)
+        regs->flags |= F_CF;
+    else
+        regs->flags &= ~F_CF;
+}
+
+// Frequently used return codes
+#define RET_EUNSUPPORTED 0x86
+
+static inline void
+set_success(struct bregs *regs)
+{
+    set_cf(regs, 0);
+}
+
+static inline void
+set_code_success(struct bregs *regs)
+{
+    regs->ah = 0;
+    set_cf(regs, 0);
+}
+
+static inline void
+set_invalid_silent(struct bregs *regs)
+{
+    set_cf(regs, 1);
+}
+
+static inline void
+set_code_invalid_silent(struct bregs *regs, u8 code)
+{
+    regs->ah = code;
+    set_cf(regs, 1);
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // bregs.h
diff --git a/qemu-0.15.x/roms/seabios/src/cdrom.c b/qemu-0.15.x/roms/seabios/src/cdrom.c
new file mode 100644
index 0000000..3769dfa
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/cdrom.c
@@ -0,0 +1,379 @@
+// Support for booting from cdroms (the "El Torito" spec).
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // cdrom_13
+#include "util.h" // memset
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "ata.h" // ATA_CMD_REQUEST_SENSE
+#include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
+
+
+/****************************************************************
+ * CD emulation
+ ****************************************************************/
+
+struct drive_s *cdemu_drive_gf VAR16VISIBLE;
+u8 *cdemu_buf_fl VAR16VISIBLE;
+
+static int
+cdemu_read(struct disk_op_s *op)
+{
+    u16 ebda_seg = get_ebda_seg();
+    struct drive_s *drive_g;
+    drive_g = GLOBALFLAT2GLOBAL(GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf));
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = op->command;
+    dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4;
+
+    int count = op->count;
+    op->count = 0;
+    u8 *cdbuf_fl = GET_GLOBAL(cdemu_buf_fl);
+
+    if (op->lba & 3) {
+        // Partial read of first block.
+        dop.count = 1;
+        dop.buf_fl = cdbuf_fl;
+        int ret = process_op(&dop);
+        if (ret)
+            return ret;
+        u8 thiscount = 4 - (op->lba & 3);
+        if (thiscount > count)
+            thiscount = count;
+        count -= thiscount;
+        memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512);
+        op->buf_fl += thiscount * 512;
+        op->count += thiscount;
+        dop.lba++;
+    }
+
+    if (count > 3) {
+        // Read n number of regular blocks.
+        dop.count = count / 4;
+        dop.buf_fl = op->buf_fl;
+        int ret = process_op(&dop);
+        op->count += dop.count * 4;
+        if (ret)
+            return ret;
+        u8 thiscount = count & ~3;
+        count &= 3;
+        op->buf_fl += thiscount * 512;
+        dop.lba += thiscount / 4;
+    }
+
+    if (count) {
+        // Partial read on last block.
+        dop.count = 1;
+        dop.buf_fl = cdbuf_fl;
+        int ret = process_op(&dop);
+        if (ret)
+            return ret;
+        u8 thiscount = count;
+        memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512);
+        op->count += thiscount;
+    }
+
+    return DISK_RET_SUCCESS;
+}
+
+int
+process_cdemu_op(struct disk_op_s *op)
+{
+    if (!CONFIG_CDROM_EMU)
+        return 0;
+
+    switch (op->command) {
+    case CMD_READ:
+        return cdemu_read(op);
+    case CMD_WRITE:
+    case CMD_FORMAT:
+        return DISK_RET_EWRITEPROTECT;
+    case CMD_VERIFY:
+    case CMD_RESET:
+    case CMD_SEEK:
+    case CMD_ISREADY:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+void
+cdemu_setup(void)
+{
+    if (!CONFIG_CDROM_EMU)
+        return;
+    if (!CDCount)
+        return;
+
+    struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
+    u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
+    if (!drive_g || !buf) {
+        warn_noalloc();
+        free(drive_g);
+        free(buf);
+        return;
+    }
+    cdemu_drive_gf = drive_g;
+    cdemu_buf_fl = buf;
+    memset(drive_g, 0, sizeof(*drive_g));
+    drive_g->type = DTYPE_CDEMU;
+    drive_g->blksize = DISK_SECTOR_SIZE;
+    drive_g->sectors = (u64)-1;
+}
+
+struct eltorito_s {
+    u8 size;
+    u8 media;
+    u8 emulated_drive;
+    u8 controller_index;
+    u32 ilba;
+    u16 device_spec;
+    u16 buffer_segment;
+    u16 load_segment;
+    u16 sector_count;
+    u8 cylinders;
+    u8 sectors;
+    u8 heads;
+};
+
+#define SET_INT13ET(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
+
+// ElTorito - Terminate disk emu
+void
+cdemu_134b(struct bregs *regs)
+{
+    // FIXME ElTorito Hardcoded
+    u16 ebda_seg = get_ebda_seg();
+    SET_INT13ET(regs, size, 0x13);
+    SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
+    SET_INT13ET(regs, emulated_drive
+                , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
+    struct drive_s *drive_gf = GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf);
+    u8 cntl_id = 0;
+    if (drive_gf)
+        cntl_id = GET_GLOBALFLAT(drive_gf->cntl_id);
+    SET_INT13ET(regs, controller_index, cntl_id / 2);
+    SET_INT13ET(regs, device_spec, cntl_id % 2);
+    SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
+    SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
+    SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
+    SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
+    SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
+    SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
+    SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
+
+    // If we have to terminate emulation
+    if (regs->al == 0x00) {
+        // FIXME ElTorito Various. Should be handled accordingly to spec
+        SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
+
+        // XXX - update floppy/hd count.
+    }
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+
+/****************************************************************
+ * CD booting
+ ****************************************************************/
+
+static int
+atapi_is_ready(struct disk_op_s *op)
+{
+    dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g);
+
+    /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
+     * reported by the device.  If the device reports "IN PROGRESS",
+     * 30 seconds is added. */
+    struct cdbres_read_capacity info;
+    int in_progress = 0;
+    u64 end = calc_future_tsc(5000);
+    for (;;) {
+        if (check_tsc(end)) {
+            dprintf(1, "read capacity failed\n");
+            return -1;
+        }
+
+        int ret = cdb_read_capacity(op, &info);
+        if (!ret)
+            // Success
+            break;
+
+        struct cdbres_request_sense sense;
+        ret = cdb_get_sense(op, &sense);
+        if (ret)
+            // Error - retry.
+            continue;
+
+        // Sense succeeded.
+        if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
+            dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
+            return -1;
+        }
+
+        if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
+            /* IN PROGRESS OF BECOMING READY */
+            printf("Waiting for device to detect medium... ");
+            /* Allow 30 seconds more */
+            end = calc_future_tsc(30000);
+            in_progress = 1;
+        }
+    }
+
+    u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+    if (blksize != GET_GLOBAL(op->drive_g->blksize)) {
+        printf("Unsupported sector size %u\n", blksize);
+        return -1;
+    }
+
+    dprintf(6, "sectors=%u\n", sectors);
+    printf("%dMB medium detected\n", sectors>>(20-11));
+    return 0;
+}
+
+int
+cdrom_boot(struct drive_s *drive_g)
+{
+    struct disk_op_s dop;
+    int cdid = getDriveId(EXTTYPE_CD, drive_g);
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = drive_g;
+    if (!dop.drive_g || cdid < 0)
+        return 1;
+
+    int ret = atapi_is_ready(&dop);
+    if (ret)
+        dprintf(1, "atapi_is_ready returned %d\n", ret);
+
+    // Read the Boot Record Volume Descriptor
+    u8 buffer[2048];
+    dop.lba = 0x11;
+    dop.count = 1;
+    dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+    ret = cdb_read(&dop);
+    if (ret)
+        return 3;
+
+    // Validity checks
+    if (buffer[0])
+        return 4;
+    if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
+        return 5;
+
+    // ok, now we calculate the Boot catalog address
+    u32 lba = *(u32*)&buffer[0x47];
+
+    // And we read the Boot Catalog
+    dop.lba = lba;
+    dop.count = 1;
+    ret = cdb_read(&dop);
+    if (ret)
+        return 7;
+
+    // Validation entry
+    if (buffer[0x00] != 0x01)
+        return 8;   // Header
+    if (buffer[0x01] != 0x00)
+        return 9;   // Platform
+    if (buffer[0x1E] != 0x55)
+        return 10;  // key 1
+    if (buffer[0x1F] != 0xAA)
+        return 10;  // key 2
+
+    // Initial/Default Entry
+    if (buffer[0x20] != 0x88)
+        return 11; // Bootable
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 media = buffer[0x21];
+    SET_EBDA2(ebda_seg, cdemu.media, media);
+
+    SET_EBDA2(ebda_seg, cdemu.emulated_drive_gf, dop.drive_g);
+
+    u16 boot_segment = *(u16*)&buffer[0x22];
+    if (!boot_segment)
+        boot_segment = 0x07C0;
+    SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
+    SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
+
+    u16 nbsectors = *(u16*)&buffer[0x26];
+    SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
+
+    lba = *(u32*)&buffer[0x28];
+    SET_EBDA2(ebda_seg, cdemu.ilba, lba);
+
+    // And we read the image in memory
+    dop.lba = lba;
+    dop.count = DIV_ROUND_UP(nbsectors, 4);
+    dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
+    ret = cdb_read(&dop);
+    if (ret)
+        return 12;
+
+    if (media == 0) {
+        // No emulation requested - return success.
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
+        return 0;
+    }
+
+    // Emulation of a floppy/harddisk requested
+    if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
+        return 13;
+
+    // Set emulated drive id and increase bios installed hardware
+    // number of devices
+    if (media < 4) {
+        // Floppy emulation
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
+        // XXX - get and set actual floppy count.
+        SETBITS_BDA(equipment_list_flags, 0x41);
+
+        switch (media) {
+        case 0x01:  // 1.2M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        case 0x02:  // 1.44M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        case 0x03:  // 2.88M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        }
+    } else {
+        // Harddrive emulation
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
+        SET_BDA(hdcount, GET_BDA(hdcount) + 1);
+
+        // Peak at partition table to get chs.
+        struct mbr_s *mbr = (void*)0;
+        u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
+        u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
+        u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
+
+        SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
+        SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
+                  , ((sptcyl<<2)&0x300) + cyllow + 1);
+        SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
+    }
+
+    // everything is ok, so from now on, the emulation is active
+    SET_EBDA2(ebda_seg, cdemu.active, 0x01);
+    dprintf(6, "cdemu media=%d\n", media);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/clock.c b/qemu-0.15.x/roms/seabios/src/clock.c
new file mode 100644
index 0000000..fcdc698
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/clock.c
@@ -0,0 +1,650 @@
+// 16bit code to handle system clocks.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "util.h" // debug_enter
+#include "disk.h" // floppy_tick
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_GLOBAL
+#include "usb-hid.h" // usb_check_event
+
+// RTC register flags
+#define RTC_A_UIP 0x80
+
+#define RTC_B_SET  0x80
+#define RTC_B_PIE  0x40
+#define RTC_B_AIE  0x20
+#define RTC_B_UIE  0x10
+#define RTC_B_BIN  0x04
+#define RTC_B_24HR 0x02
+#define RTC_B_DSE  0x01
+
+
+// Bits for PORT_PS2_CTRLB
+#define PPCB_T2GATE (1<<0)
+#define PPCB_SPKR   (1<<1)
+#define PPCB_T2OUT  (1<<5)
+
+// Bits for PORT_PIT_MODE
+#define PM_SEL_TIMER0   (0<<6)
+#define PM_SEL_TIMER1   (1<<6)
+#define PM_SEL_TIMER2   (2<<6)
+#define PM_SEL_READBACK (3<<6)
+#define PM_ACCESS_LATCH  (0<<4)
+#define PM_ACCESS_LOBYTE (1<<4)
+#define PM_ACCESS_HIBYTE (2<<4)
+#define PM_ACCESS_WORD   (3<<4)
+#define PM_MODE0 (0<<1)
+#define PM_MODE1 (1<<1)
+#define PM_MODE2 (2<<1)
+#define PM_MODE3 (3<<1)
+#define PM_MODE4 (4<<1)
+#define PM_MODE5 (5<<1)
+#define PM_CNT_BINARY (0<<0)
+#define PM_CNT_BCD    (1<<0)
+
+
+/****************************************************************
+ * TSC timer
+ ****************************************************************/
+
+#define CALIBRATE_COUNT 0x800   // Approx 1.7ms
+
+u32 cpu_khz VAR16VISIBLE;
+
+static void
+calibrate_tsc(void)
+{
+    // Setup "timer2"
+    u8 orig = inb(PORT_PS2_CTRLB);
+    outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
+    /* binary, mode 0, LSB/MSB, Ch 2 */
+    outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
+    /* LSB of ticks */
+    outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
+    /* MSB of ticks */
+    outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
+
+    u64 start = rdtscll();
+    while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
+        ;
+    u64 end = rdtscll();
+
+    // Restore PORT_PS2_CTRLB
+    outb(orig, PORT_PS2_CTRLB);
+
+    // Store calibrated cpu khz.
+    u64 diff = end - start;
+    dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
+            , (u32)start, (u32)end, (u32)diff);
+    u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
+    SET_GLOBAL(cpu_khz, hz / 1000);
+
+    dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
+}
+
+static void
+tscdelay(u64 diff)
+{
+    u64 start = rdtscll();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        cpu_relax();
+}
+
+static void
+tscsleep(u64 diff)
+{
+    u64 start = rdtscll();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        yield();
+}
+
+void ndelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void udelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void mdelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz));
+}
+
+void nsleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void usleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void msleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz));
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u64
+calc_future_tsc(u32 msecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return rdtscll() + ((u64)khz * msecs);
+}
+u64
+calc_future_tsc_usec(u32 usecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return rdtscll() + ((u64)(khz/1000) * usecs);
+}
+
+
+/****************************************************************
+ * Init
+ ****************************************************************/
+
+static int
+rtc_updating(void)
+{
+    // This function checks to see if the update-in-progress bit
+    // is set in CMOS Status Register A.  If not, it returns 0.
+    // If it is set, it tries to wait until there is a transition
+    // to 0, and will return 0 if such a transition occurs.  A -1
+    // is returned only after timing out.  The maximum period
+    // that this bit should be set is constrained to (1984+244)
+    // useconds, but we wait for longer just to be sure.
+
+    if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+        return 0;
+    u64 end = calc_future_tsc(15);
+    for (;;) {
+        if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+            return 0;
+        if (check_tsc(end))
+            // update-in-progress never transitioned to 0
+            return -1;
+        yield();
+    }
+}
+
+static void
+pit_setup(void)
+{
+    // timer0: binary count, 16bit count, mode 2
+    outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
+    // maximum count of 0000H = 18.2Hz
+    outb(0x0, PORT_PIT_COUNTER0);
+    outb(0x0, PORT_PIT_COUNTER0);
+}
+
+static void
+init_rtc(void)
+{
+    outb_cmos(0x26, CMOS_STATUS_A);    // 32,768Khz src, 976.5625us updates
+    u8 regB = inb_cmos(CMOS_STATUS_B);
+    outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B);
+    inb_cmos(CMOS_STATUS_C);
+    inb_cmos(CMOS_STATUS_D);
+}
+
+static u32
+bcd2bin(u8 val)
+{
+    return (val & 0xf) + ((val >> 4) * 10);
+}
+
+void
+timer_setup(void)
+{
+    dprintf(3, "init timer\n");
+    calibrate_tsc();
+    pit_setup();
+
+    init_rtc();
+    rtc_updating();
+    u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
+    u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
+    u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
+    u32 ticks = (hours * 60 + minutes) * 60 + seconds;
+    ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
+    SET_BDA(timer_counter, ticks);
+
+    enable_hwirq(0, FUNC16(entry_08));
+    enable_hwirq(8, FUNC16(entry_70));
+}
+
+
+/****************************************************************
+ * Standard clock functions
+ ****************************************************************/
+
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_ticks(u32 count)
+{
+    return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+calc_future_timer(u32 msecs)
+{
+    if (!msecs)
+        return GET_BDA(timer_counter);
+    u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+    u32 ticks = DIV_ROUND_UP(kticks, 1000);
+    return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+    return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+            < (TICKS_PER_DAY/2));
+}
+
+// get current clock count
+static void
+handle_1a00(struct bregs *regs)
+{
+    yield();
+    u32 ticks = GET_BDA(timer_counter);
+    regs->cx = ticks >> 16;
+    regs->dx = ticks;
+    regs->al = GET_BDA(timer_rollover);
+    SET_BDA(timer_rollover, 0); // reset flag
+    set_success(regs);
+}
+
+// Set Current Clock Count
+static void
+handle_1a01(struct bregs *regs)
+{
+    u32 ticks = (regs->cx << 16) | regs->dx;
+    SET_BDA(timer_counter, ticks);
+    SET_BDA(timer_rollover, 0); // reset flag
+    // XXX - should use set_code_success()?
+    regs->ah = 0;
+    set_success(regs);
+}
+
+// Read CMOS Time
+static void
+handle_1a02(struct bregs *regs)
+{
+    if (rtc_updating()) {
+        set_invalid(regs);
+        return;
+    }
+
+    regs->dh = inb_cmos(CMOS_RTC_SECONDS);
+    regs->cl = inb_cmos(CMOS_RTC_MINUTES);
+    regs->ch = inb_cmos(CMOS_RTC_HOURS);
+    regs->dl = inb_cmos(CMOS_STATUS_B) & RTC_B_DSE;
+    regs->ah = 0;
+    regs->al = regs->ch;
+    set_success(regs);
+}
+
+// Set CMOS Time
+static void
+handle_1a03(struct bregs *regs)
+{
+    // Using a debugger, I notice the following masking/setting
+    // of bits in Status Register B, by setting Reg B to
+    // a few values and getting its value after INT 1A was called.
+    //
+    //        try#1       try#2       try#3
+    // before 1111 1101   0111 1101   0000 0000
+    // after  0110 0010   0110 0010   0000 0010
+    //
+    // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+    // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
+    if (rtc_updating()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+    }
+    outb_cmos(regs->dh, CMOS_RTC_SECONDS);
+    outb_cmos(regs->cl, CMOS_RTC_MINUTES);
+    outb_cmos(regs->ch, CMOS_RTC_HOURS);
+    // Set Daylight Savings time enabled bit to requested value
+    u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE))
+               | RTC_B_24HR | (regs->dl & RTC_B_DSE));
+    outb_cmos(val8, CMOS_STATUS_B);
+    regs->ah = 0;
+    regs->al = val8; // val last written to Reg B
+    set_success(regs);
+}
+
+// Read CMOS Date
+static void
+handle_1a04(struct bregs *regs)
+{
+    regs->ah = 0;
+    if (rtc_updating()) {
+        set_invalid(regs);
+        return;
+    }
+    regs->cl = inb_cmos(CMOS_RTC_YEAR);
+    regs->dh = inb_cmos(CMOS_RTC_MONTH);
+    regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH);
+    if (CONFIG_COREBOOT) {
+        if (regs->cl > 0x80)
+            regs->ch = 0x19;
+        else
+            regs->ch = 0x20;
+    } else {
+        regs->ch = inb_cmos(CMOS_CENTURY);
+    }
+    regs->al = regs->ch;
+    set_success(regs);
+}
+
+// Set CMOS Date
+static void
+handle_1a05(struct bregs *regs)
+{
+    // Using a debugger, I notice the following masking/setting
+    // of bits in Status Register B, by setting Reg B to
+    // a few values and getting its value after INT 1A was called.
+    //
+    //        try#1       try#2       try#3       try#4
+    // before 1111 1101   0111 1101   0000 0010   0000 0000
+    // after  0110 1101   0111 1101   0000 0010   0000 0000
+    //
+    // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+    // My assumption: RegB = (RegB & 01111111b)
+    if (rtc_updating()) {
+        init_rtc();
+        set_invalid(regs);
+        return;
+    }
+    outb_cmos(regs->cl, CMOS_RTC_YEAR);
+    outb_cmos(regs->dh, CMOS_RTC_MONTH);
+    outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH);
+    if (!CONFIG_COREBOOT)
+        outb_cmos(regs->ch, CMOS_CENTURY);
+    // clear halt-clock bit
+    u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET;
+    outb_cmos(val8, CMOS_STATUS_B);
+    regs->ah = 0;
+    regs->al = val8; // AL = val last written to Reg B
+    set_success(regs);
+}
+
+// Set Alarm Time in CMOS
+static void
+handle_1a06(struct bregs *regs)
+{
+    // Using a debugger, I notice the following masking/setting
+    // of bits in Status Register B, by setting Reg B to
+    // a few values and getting its value after INT 1A was called.
+    //
+    //        try#1       try#2       try#3
+    // before 1101 1111   0101 1111   0000 0000
+    // after  0110 1111   0111 1111   0010 0000
+    //
+    // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+    // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
+    u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
+    regs->ax = 0;
+    if (val8 & RTC_B_AIE) {
+        // Alarm interrupt enabled already
+        set_invalid(regs);
+        return;
+    }
+    if (rtc_updating()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+    }
+    outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
+    outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
+    outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
+    // enable Status Reg B alarm bit, clear halt clock bit
+    outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B);
+    set_success(regs);
+}
+
+// Turn off Alarm
+static void
+handle_1a07(struct bregs *regs)
+{
+    // Using a debugger, I notice the following masking/setting
+    // of bits in Status Register B, by setting Reg B to
+    // a few values and getting its value after INT 1A was called.
+    //
+    //        try#1       try#2       try#3       try#4
+    // before 1111 1101   0111 1101   0010 0000   0010 0010
+    // after  0100 0101   0101 0101   0000 0000   0000 0010
+    //
+    // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+    // My assumption: RegB = (RegB & 01010111b)
+    u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
+    // clear clock-halt bit, disable alarm bit
+    outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B);
+    regs->ah = 0;
+    regs->al = val8; // val last written to Reg B
+    set_success(regs);
+}
+
+// Unsupported
+static void
+handle_1aXX(struct bregs *regs)
+{
+    set_unimplemented(regs);
+}
+
+// INT 1Ah Time-of-day Service Entry Point
+void VISIBLE16
+handle_1a(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_1a);
+    switch (regs->ah) {
+    case 0x00: handle_1a00(regs); break;
+    case 0x01: handle_1a01(regs); break;
+    case 0x02: handle_1a02(regs); break;
+    case 0x03: handle_1a03(regs); break;
+    case 0x04: handle_1a04(regs); break;
+    case 0x05: handle_1a05(regs); break;
+    case 0x06: handle_1a06(regs); break;
+    case 0x07: handle_1a07(regs); break;
+    case 0xb1: handle_1ab1(regs); break;
+    default:   handle_1aXX(regs); break;
+    }
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+    debug_isr(DEBUG_ISR_08);
+
+    floppy_tick();
+
+    u32 counter = GET_BDA(timer_counter);
+    counter++;
+    // compare to one days worth of timer ticks at 18.2 hz
+    if (counter >= TICKS_PER_DAY) {
+        // there has been a midnight rollover at this point
+        counter = 0;
+        SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
+    }
+
+    SET_BDA(timer_counter, counter);
+
+    usb_check_event();
+
+    // chain to user timer tick INT #0x1c
+    u32 eax=0, flags;
+    call16_simpint(0x1c, &eax, &flags);
+
+    eoi_pic1();
+}
+
+
+/****************************************************************
+ * Periodic timer
+ ****************************************************************/
+
+void
+useRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count+1);
+    if (count)
+        return;
+    // Turn on the Periodic Interrupt timer
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
+}
+
+void
+releaseRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count-1);
+    if (count != 1)
+        return;
+    // Clear the Periodic Interrupt.
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
+}
+
+static int
+set_usertimer(u32 usecs, u16 seg, u16 offset)
+{
+    if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)
+        return -1;
+
+    // Interval not already set.
+    SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING);  // Set status byte.
+    SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset));
+    SET_BDA(user_wait_timeout, usecs);
+    useRTC();
+    return 0;
+}
+
+static void
+clear_usertimer(void)
+{
+    if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING))
+        return;
+    // Turn off status byte.
+    SET_BDA(rtc_wait_flag, 0);
+    releaseRTC();
+}
+
+#define RET_ECLOCKINUSE  0x83
+
+// Wait for CX:DX microseconds
+void
+handle_1586(struct bregs *regs)
+{
+    // Use the rtc to wait for the specified time.
+    u8 statusflag = 0;
+    u32 count = (regs->cx << 16) | regs->dx;
+    int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag);
+    if (ret) {
+        set_code_invalid(regs, RET_ECLOCKINUSE);
+        return;
+    }
+    while (!statusflag)
+        wait_irq();
+    set_success(regs);
+}
+
+// Set Interval requested.
+static void
+handle_158300(struct bregs *regs)
+{
+    int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx);
+    if (ret)
+        // Interval already set.
+        set_code_invalid(regs, RET_EUNSUPPORTED);
+    else
+        set_success(regs);
+}
+
+// Clear interval requested
+static void
+handle_158301(struct bregs *regs)
+{
+    clear_usertimer();
+    set_success(regs);
+}
+
+static void
+handle_1583XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+    regs->al--;
+}
+
+void
+handle_1583(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_158300(regs); break;
+    case 0x01: handle_158301(regs); break;
+    default:   handle_1583XX(regs); break;
+    }
+}
+
+#define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024)
+
+// int70h: IRQ8 - CMOS RTC
+void VISIBLE16
+handle_70(void)
+{
+    debug_isr(DEBUG_ISR_70);
+
+    // Check which modes are enabled and have occurred.
+    u8 registerB = inb_cmos(CMOS_STATUS_B);
+    u8 registerC = inb_cmos(CMOS_STATUS_C);
+
+    if (!(registerB & (RTC_B_PIE|RTC_B_AIE)))
+        goto done;
+    if (registerC & RTC_B_AIE) {
+        // Handle Alarm Interrupt.
+        u32 eax=0, flags;
+        call16_simpint(0x4a, &eax, &flags);
+    }
+    if (!(registerC & RTC_B_PIE))
+        goto done;
+
+    // Handle Periodic Interrupt.
+
+    check_preempt();
+
+    if (!GET_BDA(rtc_wait_flag))
+        goto done;
+
+    // Wait Interval (Int 15, AH=83) active.
+    u32 time = GET_BDA(user_wait_timeout);  // Time left in microseconds.
+    if (time < USEC_PER_RTC) {
+        // Done waiting - write to specified flag byte.
+        struct segoff_s segoff = GET_BDA(user_wait_complete_flag);
+        u16 ptr_seg = segoff.seg;
+        u8 *ptr_far = (u8*)(segoff.offset+0);
+        u8 oldval = GET_FARVAR(ptr_seg, *ptr_far);
+        SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80);
+
+        clear_usertimer();
+    } else {
+        // Continue waiting.
+        time -= USEC_PER_RTC;
+        SET_BDA(user_wait_timeout, time);
+    }
+
+done:
+    eoi_pic2();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/cmos.h b/qemu-0.15.x/roms/seabios/src/cmos.h
new file mode 100644
index 0000000..e4b6462
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/cmos.h
@@ -0,0 +1,74 @@
+// Definitions for X86 CMOS non-volatile memory access.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __CMOS_H
+#define __CMOS_H
+
+#define CMOS_RTC_SECONDS         0x00
+#define CMOS_RTC_SECONDS_ALARM   0x01
+#define CMOS_RTC_MINUTES         0x02
+#define CMOS_RTC_MINUTES_ALARM   0x03
+#define CMOS_RTC_HOURS           0x04
+#define CMOS_RTC_HOURS_ALARM     0x05
+#define CMOS_RTC_DAY_WEEK        0x06
+#define CMOS_RTC_DAY_MONTH       0x07
+#define CMOS_RTC_MONTH           0x08
+#define CMOS_RTC_YEAR            0x09
+#define CMOS_STATUS_A            0x0a
+#define CMOS_STATUS_B            0x0b
+#define CMOS_STATUS_C            0x0c
+#define CMOS_STATUS_D            0x0d
+#define CMOS_RESET_CODE          0x0f
+#define CMOS_FLOPPY_DRIVE_TYPE   0x10
+#define CMOS_DISK_DATA           0x12
+#define CMOS_EQUIPMENT_INFO      0x14
+#define CMOS_DISK_DRIVE1_TYPE    0x19
+#define CMOS_DISK_DRIVE2_TYPE    0x1a
+#define CMOS_DISK_DRIVE1_CYL     0x1b
+#define CMOS_DISK_DRIVE2_CYL     0x24
+#define CMOS_MEM_EXTMEM_LOW      0x30
+#define CMOS_MEM_EXTMEM_HIGH     0x31
+#define CMOS_CENTURY             0x32
+#define CMOS_MEM_EXTMEM2_LOW     0x34
+#define CMOS_MEM_EXTMEM2_HIGH    0x35
+#define CMOS_BIOS_BOOTFLAG1      0x38
+#define CMOS_BIOS_DISKTRANSFLAG  0x39
+#define CMOS_BIOS_BOOTFLAG2      0x3d
+#define CMOS_MEM_HIGHMEM_LOW     0x5b
+#define CMOS_MEM_HIGHMEM_MID     0x5c
+#define CMOS_MEM_HIGHMEM_HIGH    0x5d
+#define CMOS_BIOS_SMP_COUNT      0x5f
+
+// CMOS_FLOPPY_DRIVE_TYPE bitdefs
+#define CFD_NO_DRIVE 0
+#define CFD_360KB    1
+#define CFD_12MB     2
+#define CFD_720KB    3
+#define CFD_144MB    4
+#define CFD_288MB    5
+
+#ifndef __ASSEMBLY__
+
+#include "ioport.h" // inb, outb
+
+static inline u8
+inb_cmos(u8 reg)
+{
+    reg |= NMI_DISABLE_BIT;
+    outb(reg, PORT_CMOS_INDEX);
+    return inb(PORT_CMOS_DATA);
+}
+
+static inline void
+outb_cmos(u8 val, u8 reg)
+{
+    reg |= NMI_DISABLE_BIT;
+    outb(reg, PORT_CMOS_INDEX);
+    outb(val, PORT_CMOS_DATA);
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // cmos.h
diff --git a/qemu-0.15.x/roms/seabios/src/config.h b/qemu-0.15.x/roms/seabios/src/config.h
new file mode 100644
index 0000000..5b40488
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/config.h
@@ -0,0 +1,123 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "autoconf.h"
+
+// Configuration definitions.
+
+//#define CONFIG_APPNAME  "QEMU"
+//#define CONFIG_CPUNAME8 "QEMUCPU "
+//#define CONFIG_APPNAME6 "QEMU  "
+//#define CONFIG_APPNAME4 "QEMU"
+#define CONFIG_APPNAME  "Bochs"
+#define CONFIG_CPUNAME8 "BOCHSCPU"
+#define CONFIG_APPNAME6 "BOCHS "
+#define CONFIG_APPNAME4 "BXPC"
+
+// When option roms are not pre-deployed, SeaBIOS can copy an optionrom
+// from flash for up to 2 devices.
+#define OPTIONROM_VENDEV_1 0x00000000
+#define OPTIONROM_MEM_1 0x00000000
+#define OPTIONROM_VENDEV_2 0x00000000
+#define OPTIONROM_MEM_2 0x00000000
+
+// Maximum number of map entries in the e820 map
+#define CONFIG_MAX_E820 32
+// Space to reserve in f-segment for dynamic allocations
+#define CONFIG_MAX_BIOSTABLE 2048
+// Space to reserve in high-memory for tables
+#define CONFIG_MAX_HIGHTABLE (64*1024)
+// Largest supported externaly facing drive id
+#define CONFIG_MAX_EXTDRIVE 16
+
+#define CONFIG_MODEL_ID      0xFC
+#define CONFIG_SUBMODEL_ID   0x00
+#define CONFIG_BIOS_REVISION 0x01
+
+// Various memory addresses used by the code.
+#define BUILD_STACK_ADDR          0x7000
+#define BUILD_S3RESUME_STACK_ADDR 0x1000
+#define BUILD_AP_BOOT_ADDR        0x10000
+#define BUILD_EBDA_MINIMUM        0x90000
+#define BUILD_LOWRAM_END          0xa0000
+#define BUILD_ROM_START           0xc0000
+#define BUILD_BIOS_ADDR           0xf0000
+#define BUILD_BIOS_SIZE           0x10000
+// 32KB for shadow ram copying (works around emulator deficiencies)
+#define BUILD_BIOS_TMP_ADDR       0x30000
+#define BUILD_MAX_HIGHMEM         0xe0000000
+
+// Support old pci mem assignment behaviour
+//#define CONFIG_OLD_PCIMEM_ASSIGNMENT    1
+#if CONFIG_OLD_PCIMEM_ASSIGNMENT
+#define BUILD_PCIMEM_START        0xf0000000
+#define BUILD_PCIMEM_SIZE         (BUILD_PCIMEM_END - BUILD_PCIMEM_START)
+#define BUILD_PCIMEM_END          0xfec00000    /* IOAPIC is mapped at */
+#define BUILD_PCIPREFMEM_START    0
+#define BUILD_PCIPREFMEM_SIZE     0
+#define BUILD_PCIPREFMEM_END      0
+#else
+#define BUILD_PCIMEM_START        0xf0000000
+#define BUILD_PCIMEM_SIZE         0x08000000    /* half- of pci window */
+#define BUILD_PCIMEM_END          (BUILD_PCIMEM_START + BUILD_PCIMEM_SIZE)
+#define BUILD_PCIPREFMEM_START    BUILD_PCIMEM_END
+#define BUILD_PCIPREFMEM_SIZE     (BUILD_PCIPREFMEM_END - BUILD_PCIPREFMEM_START)
+#define BUILD_PCIPREFMEM_END      0xfec00000    /* IOAPIC is mapped at */
+#endif
+
+#define BUILD_APIC_ADDR           0xfee00000
+#define BUILD_IOAPIC_ADDR         0xfec00000
+
+#define BUILD_SMM_INIT_ADDR       0x38000
+#define BUILD_SMM_ADDR            0xa8000
+#define BUILD_SMM_SIZE            0x8000
+
+// Important real-mode segments
+#define SEG_IVT      0x0000
+#define SEG_BDA      0x0040
+#define SEG_BIOS     0xf000
+
+// Segment definitions in protected mode (see rombios32_gdt in misc.c)
+#define SEG32_MODE32_CS    (1 << 3)
+#define SEG32_MODE32_DS    (2 << 3)
+#define SEG32_MODE16_CS    (3 << 3)
+#define SEG32_MODE16_DS    (4 << 3)
+#define SEG32_MODE16BIG_CS (5 << 3)
+#define SEG32_MODE16BIG_DS (6 << 3)
+
+// Debugging levels.  If non-zero and CONFIG_DEBUG_LEVEL is greater
+// than the specified value, then the corresponding irq handler will
+// report every enter event.
+#define DEBUG_ISR_02 1
+#define DEBUG_HDL_05 1
+#define DEBUG_ISR_08 20
+#define DEBUG_ISR_09 9
+#define DEBUG_ISR_0e 9
+#define DEBUG_HDL_10 20
+#define DEBUG_HDL_11 2
+#define DEBUG_HDL_12 2
+#define DEBUG_HDL_13 10
+#define DEBUG_HDL_14 2
+#define DEBUG_HDL_15 9
+#define DEBUG_HDL_16 9
+#define DEBUG_HDL_17 2
+#define DEBUG_HDL_18 1
+#define DEBUG_HDL_19 1
+#define DEBUG_HDL_1a 9
+#define DEBUG_HDL_40 1
+#define DEBUG_ISR_70 9
+#define DEBUG_ISR_74 9
+#define DEBUG_ISR_75 1
+#define DEBUG_ISR_76 10
+#define DEBUG_ISR_hwpic1 5
+#define DEBUG_ISR_hwpic2 5
+#define DEBUG_HDL_pnp 1
+#define DEBUG_HDL_pmm 1
+#define DEBUG_HDL_pcibios32 9
+#define DEBUG_HDL_apm 9
+
+#define DEBUG_unimplemented 2
+#define DEBUG_invalid 3
+#define DEBUG_thread 2
+
+#endif // config.h
diff --git a/qemu-0.15.x/roms/seabios/src/coreboot.c b/qemu-0.15.x/roms/seabios/src/coreboot.c
new file mode 100644
index 0000000..f627531
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/coreboot.c
@@ -0,0 +1,617 @@
+// Coreboot interface support.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "memmap.h" // add_e820
+#include "util.h" // dprintf
+#include "pci.h" // struct pir_header
+#include "acpi.h" // struct rsdp_descriptor
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "biosvar.h" // GET_EBDA
+#include "lzmadecode.h" // LzmaDecode
+#include "smbios.h" // smbios_init
+#include "boot.h" // boot_add_cbfs
+
+
+/****************************************************************
+ * Memory map
+ ****************************************************************/
+
+struct cb_header {
+    u32 signature;
+    u32 header_bytes;
+    u32 header_checksum;
+    u32 table_bytes;
+    u32 table_checksum;
+    u32 table_entries;
+};
+
+#define CB_SIGNATURE 0x4f49424C // "LBIO"
+
+struct cb_memory_range {
+    u64 start;
+    u64 size;
+    u32 type;
+};
+
+#define CB_MEM_TABLE    16
+
+struct cb_memory {
+    u32 tag;
+    u32 size;
+    struct cb_memory_range map[0];
+};
+
+#define CB_TAG_MEMORY 0x01
+
+#define MEM_RANGE_COUNT(_rec) \
+        (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
+
+struct cb_mainboard {
+    u32 tag;
+    u32 size;
+    u8  vendor_idx;
+    u8  part_idx;
+    char  strings[0];
+};
+
+#define CB_TAG_MAINBOARD 0x0003
+
+struct cb_forward {
+    u32 tag;
+    u32 size;
+    u64 forward;
+};
+
+#define CB_TAG_FORWARD 0x11
+
+static u16
+ipchksum(char *buf, int count)
+{
+    u16 *p = (u16*)buf;
+    u32 sum = 0;
+    while (count > 1) {
+        sum += *p++;
+        count -= 2;
+    }
+    if (count)
+        sum += *(u8*)p;
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+    return ~sum;
+}
+
+// Try to locate the coreboot header in a given address range.
+static struct cb_header *
+find_cb_header(char *addr, int len)
+{
+    char *end = addr + len;
+    for (; addr < end; addr += 16) {
+        struct cb_header *cbh = (struct cb_header *)addr;
+        if (cbh->signature != CB_SIGNATURE)
+            continue;
+        if (! cbh->table_bytes)
+            continue;
+        if (ipchksum(addr, sizeof(*cbh)) != 0)
+            continue;
+        if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
+            != cbh->table_checksum)
+            continue;
+        return cbh;
+    }
+    return NULL;
+}
+
+// Try to find the coreboot memory table in the given coreboot table.
+static void *
+find_cb_subtable(struct cb_header *cbh, u32 tag)
+{
+    char *tbl = (char *)cbh + sizeof(*cbh);
+    int i;
+    for (i=0; i<cbh->table_entries; i++) {
+        struct cb_memory *cbm = (struct cb_memory *)tbl;
+        tbl += cbm->size;
+        if (cbm->tag == tag)
+            return cbm;
+    }
+    return NULL;
+}
+
+static struct cb_memory *CBMemTable;
+
+// Populate max ram and e820 map info by scanning for a coreboot table.
+static void
+coreboot_fill_map(void)
+{
+    dprintf(3, "Attempting to find coreboot table\n");
+
+    // Find coreboot table.
+    struct cb_header *cbh = find_cb_header(0, 0x1000);
+    if (!cbh)
+        goto fail;
+    struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
+    if (cbf) {
+        dprintf(3, "Found coreboot table forwarder.\n");
+        cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
+        if (!cbh)
+            goto fail;
+    }
+    dprintf(3, "Now attempting to find coreboot memory map\n");
+    struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
+    if (!cbm)
+        goto fail;
+
+    u64 maxram = 0, maxram_over4G = 0;
+    int i, count = MEM_RANGE_COUNT(cbm);
+    for (i=0; i<count; i++) {
+        struct cb_memory_range *m = &cbm->map[i];
+        u32 type = m->type;
+        if (type == CB_MEM_TABLE) {
+            type = E820_RESERVED;
+        } else if (type == E820_ACPI || type == E820_RAM) {
+            u64 end = m->start + m->size;
+            if (end > 0x100000000ull) {
+                end -= 0x100000000ull;
+                if (end > maxram_over4G)
+                    maxram_over4G = end;
+            } else if (end > maxram)
+                maxram = end;
+        }
+        add_e820(m->start, m->size, type);
+    }
+
+    RamSize = maxram;
+    RamSizeOver4G = maxram_over4G;
+
+    // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
+    // confuses grub.  So, override it.
+    add_e820(0, 16*1024, E820_RAM);
+
+    struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
+    if (cbmb) {
+        const char *vendor = &cbmb->strings[cbmb->vendor_idx];
+        const char *part = &cbmb->strings[cbmb->part_idx];
+        dprintf(1, "Found mainboard %s %s\n", vendor, part);
+
+        vgahook_setup(vendor, part);
+    }
+
+    return;
+
+fail:
+    // No table found..  Use 16Megs as a dummy value.
+    dprintf(1, "Unable to find coreboot table!\n");
+    RamSize = 16*1024*1024;
+    RamSizeOver4G = 0;
+    add_e820(0, 16*1024*1024, E820_RAM);
+    return;
+}
+
+
+/****************************************************************
+ * BIOS table copying
+ ****************************************************************/
+
+static void
+copy_pir(void *pos)
+{
+    struct pir_header *p = pos;
+    if (p->signature != PIR_SIGNATURE)
+        return;
+    if (PirOffset)
+        return;
+    if (p->size < sizeof(*p))
+        return;
+    if (checksum(pos, p->size) != 0)
+        return;
+    void *newpos = malloc_fseg(p->size);
+    if (!newpos) {
+        warn_noalloc();
+        return;
+    }
+    dprintf(1, "Copying PIR from %p to %p\n", pos, newpos);
+    memcpy(newpos, pos, p->size);
+    PirOffset = (u32)newpos - BUILD_BIOS_ADDR;
+}
+
+static void
+copy_mptable(void *pos)
+{
+    struct mptable_floating_s *p = pos;
+    if (p->signature != MPTABLE_SIGNATURE)
+        return;
+    if (!p->physaddr)
+        return;
+    if (checksum(pos, sizeof(*p)) != 0)
+        return;
+    u32 length = p->length * 16;
+    u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
+    struct mptable_floating_s *newpos = malloc_fseg(length + mpclength);
+    if (!newpos) {
+        warn_noalloc();
+        return;
+    }
+    dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos);
+    memcpy(newpos, pos, length);
+    newpos->physaddr = (u32)newpos + length;
+    newpos->checksum -= checksum(newpos, sizeof(*newpos));
+    memcpy((void*)newpos + length, (void*)p->physaddr, mpclength);
+}
+
+static void
+copy_acpi_rsdp(void *pos)
+{
+    if (RsdpAddr)
+        return;
+    struct rsdp_descriptor *p = pos;
+    if (p->signature != RSDP_SIGNATURE)
+        return;
+    u32 length = 20;
+    if (checksum(pos, length) != 0)
+        return;
+    if (p->revision > 1) {
+        length = p->length;
+        if (checksum(pos, length) != 0)
+            return;
+    }
+    void *newpos = malloc_fseg(length);
+    if (!newpos) {
+        warn_noalloc();
+        return;
+    }
+    dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos);
+    memcpy(newpos, pos, length);
+    RsdpAddr = newpos;
+}
+
+// Attempt to find (and relocate) any standard bios tables found in a
+// given address range.
+static void
+scan_tables(u32 start, u32 size)
+{
+    void *p = (void*)ALIGN(start, 16);
+    void *end = (void*)start + size;
+    for (; p<end; p += 16) {
+        copy_pir(p);
+        copy_mptable(p);
+        copy_acpi_rsdp(p);
+    }
+}
+
+void
+coreboot_copy_biostable(void)
+{
+    struct cb_memory *cbm = CBMemTable;
+    if (! CONFIG_COREBOOT || !cbm)
+        return;
+
+    dprintf(3, "Relocating coreboot bios tables\n");
+
+    // Scan CB_MEM_TABLE areas for bios tables.
+    int i, count = MEM_RANGE_COUNT(cbm);
+    for (i=0; i<count; i++) {
+        struct cb_memory_range *m = &cbm->map[i];
+        if (m->type == CB_MEM_TABLE)
+            scan_tables(m->start, m->size);
+    }
+
+    // XXX - just create dummy smbios table for now - should detect if
+    // smbios/dmi table is found from coreboot and use that instead.
+    smbios_init();
+}
+
+
+/****************************************************************
+ * ulzma
+ ****************************************************************/
+
+// Uncompress data in flash to an area of memory.
+static int
+ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
+{
+    dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
+    CLzmaDecoderState state;
+    int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
+    if (ret != LZMA_RESULT_OK) {
+        dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
+        return -1;
+    }
+    u8 scratch[15980];
+    int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+    if (need > sizeof(scratch)) {
+        dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
+        return -1;
+    }
+    state.Probs = (CProb *)scratch;
+
+    u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
+    if (dstlen > maxlen) {
+        dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
+        return -1;
+    }
+    u32 inProcessed, outProcessed;
+    ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
+                     , &inProcessed, dst, dstlen, &outProcessed);
+    if (ret) {
+        dprintf(1, "LzmaDecode returned %d\n", ret);
+        return -1;
+    }
+    return dstlen;
+}
+
+
+/****************************************************************
+ * Coreboot flash format
+ ****************************************************************/
+
+#define CBFS_HEADER_MAGIC 0x4F524243
+#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+    u32 magic;
+    u32 version;
+    u32 romsize;
+    u32 bootblocksize;
+    u32 align;
+    u32 offset;
+    u32 pad[2];
+} PACKED;
+
+static struct cbfs_header *CBHDR;
+
+static void
+cbfs_setup(void)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+        return;
+
+    CBHDR = *(void **)CBFS_HEADPTR_ADDR;
+    if (CBHDR->magic != htonl(CBFS_HEADER_MAGIC)) {
+        dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
+                , CBHDR, CBHDR->magic, htonl(CBFS_HEADER_MAGIC));
+        CBHDR = NULL;
+        return;
+    }
+
+    dprintf(1, "Found CBFS header at %p\n", CBHDR);
+}
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+    u64 magic;
+    u32 len;
+    u32 type;
+    u32 checksum;
+    u32 offset;
+    char filename[0];
+} PACKED;
+
+// Verify a cbfs entry looks valid.
+static struct cbfs_file *
+cbfs_verify(struct cbfs_file *file)
+{
+    if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize)))
+        return NULL;
+    u64 magic = file->magic;
+    if (magic == CBFS_FILE_MAGIC) {
+        dprintf(5, "Found CBFS file %s\n", file->filename);
+        return file;
+    }
+    return NULL;
+}
+
+// Return the first file in the CBFS archive
+static struct cbfs_file *
+cbfs_getfirst(void)
+{
+    if (! CBHDR)
+        return NULL;
+    return cbfs_verify((void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset)));
+}
+
+// Return the file after the given file.
+static struct cbfs_file *
+cbfs_getnext(struct cbfs_file *file)
+{
+    file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align));
+    return cbfs_verify(file);
+}
+
+// Find the file with the given filename.
+struct cbfs_file *
+cbfs_findfile(const char *fname)
+{
+    dprintf(3, "Searching CBFS for %s\n", fname);
+    struct cbfs_file *file;
+    for (file = cbfs_getfirst(); file; file = cbfs_getnext(file))
+        if (strcmp(fname, file->filename) == 0)
+            return file;
+    return NULL;
+}
+
+// Find next file with the given filename prefix.
+struct cbfs_file *
+cbfs_findprefix(const char *prefix, struct cbfs_file *last)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+        return NULL;
+
+    dprintf(3, "Searching CBFS for prefix %s\n", prefix);
+    int len = strlen(prefix);
+    struct cbfs_file *file;
+    if (! last)
+        file = cbfs_getfirst();
+    else
+        file = cbfs_getnext(last);
+    for (; file; file = cbfs_getnext(file))
+        if (memcmp(prefix, file->filename, len) == 0)
+            return file;
+    return NULL;
+}
+
+// Find a file with the given filename (possibly with ".lzma" extension).
+struct cbfs_file *
+cbfs_finddatafile(const char *fname)
+{
+    int fnlen = strlen(fname);
+    struct cbfs_file *file = NULL;
+    for (;;) {
+        file = cbfs_findprefix(fname, file);
+        if (!file)
+            return NULL;
+        if (file->filename[fnlen] == '\0'
+            || strcmp(&file->filename[fnlen], ".lzma") == 0)
+            return file;
+    }
+}
+
+// Determine whether the file has a ".lzma" extension.
+static int
+cbfs_iscomp(struct cbfs_file *file)
+{
+    int fnamelen = strlen(file->filename);
+    return fnamelen > 5 && strcmp(&file->filename[fnamelen-5], ".lzma") == 0;
+}
+
+// Return the filename of a given file.
+const char *
+cbfs_filename(struct cbfs_file *file)
+{
+    return file->filename;
+}
+
+// Determine the uncompressed size of a datafile.
+u32
+cbfs_datasize(struct cbfs_file *file)
+{
+    void *src = (void*)file + ntohl(file->offset);
+    if (cbfs_iscomp(file))
+        return *(u32*)(src + LZMA_PROPERTIES_SIZE);
+    return ntohl(file->len);
+}
+
+// Copy a file to memory (uncompressing if necessary)
+int
+cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+        return -1;
+
+    u32 size = ntohl(file->len);
+    void *src = (void*)file + ntohl(file->offset);
+    if (cbfs_iscomp(file)) {
+        // Compressed - copy to temp ram and uncompress it.
+        void *temp = malloc_tmphigh(size);
+        if (!temp)
+            return -1;
+        iomemcpy(temp, src, size);
+        int ret = ulzma(dst, maxlen, temp, size);
+        yield();
+        free(temp);
+        return ret;
+    }
+
+    // Not compressed.
+    dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
+    if (size > maxlen) {
+        warn_noalloc();
+        return -1;
+    }
+    iomemcpy(dst, src, size);
+    return size;
+}
+
+struct cbfs_payload_segment {
+    u32 type;
+    u32 compression;
+    u32 offset;
+    u64 load_addr;
+    u32 len;
+    u32 mem_len;
+} PACKED;
+
+#define PAYLOAD_SEGMENT_BSS    0x20535342
+#define PAYLOAD_SEGMENT_ENTRY  0x52544E45
+
+#define CBFS_COMPRESS_NONE  0
+#define CBFS_COMPRESS_LZMA  1
+
+struct cbfs_payload {
+    struct cbfs_payload_segment segments[1];
+};
+
+void
+cbfs_run_payload(struct cbfs_file *file)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+        return;
+    dprintf(1, "Run %s\n", file->filename);
+    struct cbfs_payload *pay = (void*)file + ntohl(file->offset);
+    struct cbfs_payload_segment *seg = pay->segments;
+    for (;;) {
+        void *src = (void*)pay + ntohl(seg->offset);
+        void *dest = (void*)ntohl((u32)seg->load_addr);
+        u32 src_len = ntohl(seg->len);
+        u32 dest_len = ntohl(seg->mem_len);
+        switch (seg->type) {
+        case PAYLOAD_SEGMENT_BSS:
+            dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
+            memset(dest, 0, dest_len);
+            break;
+        case PAYLOAD_SEGMENT_ENTRY: {
+            dprintf(1, "Calling addr %p\n", dest);
+            void (*func)() = dest;
+            func();
+            return;
+        }
+        default:
+            dprintf(3, "Segment %x %d@%p -> %d@%p\n"
+                    , seg->type, src_len, src, dest_len, dest);
+            if (seg->compression == htonl(CBFS_COMPRESS_NONE)) {
+                if (src_len > dest_len)
+                    src_len = dest_len;
+                memcpy(dest, src, src_len);
+            } else if (CONFIG_LZMA
+                       && seg->compression == htonl(CBFS_COMPRESS_LZMA)) {
+                int ret = ulzma(dest, dest_len, src, src_len);
+                if (ret < 0)
+                    return;
+                src_len = ret;
+            } else {
+                dprintf(1, "No support for compression type %x\n"
+                        , seg->compression);
+                return;
+            }
+            if (dest_len > src_len)
+                memset(dest + src_len, 0, dest_len - src_len);
+            break;
+        }
+        seg++;
+    }
+}
+
+// Register payloads in "img/" directory with boot system.
+void
+cbfs_payload_setup(void)
+{
+    struct cbfs_file *file = NULL;
+    for (;;) {
+        file = cbfs_findprefix("img/", file);
+        if (!file)
+            break;
+        const char *filename = cbfs_filename(file);
+        char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
+        boot_add_cbfs(file, desc, bootprio_find_named_rom(filename, 0));
+    }
+}
+
+void
+coreboot_setup(void)
+{
+    coreboot_fill_map();
+    cbfs_setup();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/dev-i440fx.c b/qemu-0.15.x/roms/seabios/src/dev-i440fx.c
new file mode 100644
index 0000000..346f6d0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/dev-i440fx.c
@@ -0,0 +1,116 @@
+// initialization function which are specific to i440fx chipset
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// Copyright (C) 2010 Isaku Yamahata <yamahata at valinux co jp>
+// Split out from pciinit.c
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+//
+
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "util.h" // dprintf
+#include "ioport.h" // outb
+#include "pci.h" // pci_config_writeb
+#include "pci_ids.h"
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "acpi.h"
+#include "dev-i440fx.h"
+
+#define I440FX_PAM0     0x59
+
+void i440fx_bios_make_writable(u16 bdf, void *arg)
+{
+    make_bios_writable_intel(bdf, I440FX_PAM0);
+}
+
+void i440fx_bios_make_readonly(u16 bdf, void *arg)
+{
+    make_bios_readonly_intel(bdf, I440FX_PAM0);
+}
+
+/* PIIX3/PIIX4 PCI to ISA bridge */
+void piix_isa_bridge_init(u16 bdf, void *arg)
+{
+    int i, irq;
+    u8 elcr[2];
+
+    elcr[0] = 0x00;
+    elcr[1] = 0x00;
+    for (i = 0; i < 4; i++) {
+        irq = pci_irqs[i];
+        /* set to trigger level */
+        elcr[irq >> 3] |= (1 << (irq & 7));
+        /* activate irq remapping in PIIX */
+        pci_config_writeb(bdf, 0x60 + i, irq);
+    }
+    outb(elcr[0], 0x4d0);
+    outb(elcr[1], 0x4d1);
+    dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
+/* PIIX3/PIIX4 IDE */
+void piix_ide_init(u16 bdf, void *arg)
+{
+    pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0
+    pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1
+    pci_bios_allocate_regions(bdf, NULL);
+}
+
+/* PIIX4 Power Management device (for ACPI) */
+void piix4_pm_init(u16 bdf, void *arg)
+{
+    // acpi sci is hardwired to 9
+    pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
+    pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1);
+    pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */
+    pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
+    pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
+}
+
+#define PIIX4_ACPI_ENABLE       0xf1
+#define PIIX4_ACPI_DISABLE      0xf0
+#define PIIX4_GPE0_BLK          0xafe0
+#define PIIX4_GPE0_BLK_LEN      4
+
+void piix4_fadt_init(u16 bdf, void *arg)
+{
+    struct fadt_descriptor_rev1 *fadt = arg;
+    fadt->acpi_enable = PIIX4_ACPI_ENABLE;
+    fadt->acpi_disable = PIIX4_ACPI_DISABLE;
+    fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK);
+    fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN;
+}
+
+#define I440FX_SMRAM    0x72
+#define PIIX_DEVACTB    0x58
+#define PIIX_APMC_EN    (1 << 25)
+
+// This code is hardcoded for PIIX4 Power Management device.
+void piix4_apmc_smm_init(u16 bdf, void *arg)
+{
+    int i440_bdf = pci_find_device(PCI_VENDOR_ID_INTEL
+                                   , PCI_DEVICE_ID_INTEL_82441);
+    if (i440_bdf < 0)
+        return;
+
+    /* check if SMM init is already done */
+    u32 value = pci_config_readl(bdf, PIIX_DEVACTB);
+    if (value & PIIX_APMC_EN)
+        return;
+
+    /* enable the SMM memory window */
+    pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+    smm_save_and_copy();
+
+    /* enable SMI generation when writing to the APMC register */
+    pci_config_writel(bdf, PIIX_DEVACTB, value | PIIX_APMC_EN);
+
+    smm_relocate_and_restore();
+
+    /* close the SMM memory window and enable normal SMM */
+    pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/dev-i440fx.h b/qemu-0.15.x/roms/seabios/src/dev-i440fx.h
new file mode 100644
index 0000000..ab5a4d1
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/dev-i440fx.h
@@ -0,0 +1,14 @@
+#ifndef __I440FX_H
+#define __I440FX_H
+
+#include "types.h" // u16
+
+void i440fx_bios_make_writable(u16 bdf, void *arg);
+void i440fx_bios_make_readonly(u16 bdf, void *arg);
+void piix_isa_bridge_init(u16 bdf, void *arg);
+void piix_ide_init(u16 bdf, void *arg);
+void piix4_pm_init(u16 bdf, void *arg);
+void piix4_fadt_init(u16 bdf, void *arg);
+void piix4_apmc_smm_init(u16 bdf, void *arg);
+
+#endif // __I440FX_H
diff --git a/qemu-0.15.x/roms/seabios/src/disk.c b/qemu-0.15.x/roms/seabios/src/disk.c
new file mode 100644
index 0000000..8f7c61f
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/disk.c
@@ -0,0 +1,896 @@
+// 16bit code to access hard drives.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // floppy_13
+#include "biosvar.h" // SET_BDA
+#include "config.h" // CONFIG_*
+#include "util.h" // debug_enter
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "pci.h" // pci_bdf_to_bus
+#include "ata.h" // ATA_CB_DC
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+void
+__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
+{
+    u8 code = linecode;
+    if (regs->dl < EXTSTART_HD)
+        SET_BDA(floppy_last_status, code);
+    else
+        SET_BDA(disk_last_status, code);
+    if (code)
+        __set_code_invalid(regs, linecode, fname);
+    else
+        set_code_success(regs);
+}
+
+void
+__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+    u8 code = linecode;
+    if (regs->dl < EXTSTART_HD)
+        SET_BDA(floppy_last_status, code);
+    else
+        SET_BDA(disk_last_status, code);
+    __set_code_unimplemented(regs, linecode, fname);
+}
+
+static void
+__disk_stub(struct bregs *regs, int lineno, const char *fname)
+{
+    __warn_unimplemented(regs, lineno, fname);
+    __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
+}
+
+#define DISK_STUB(regs)                         \
+    __disk_stub((regs), __LINE__, __func__)
+
+// Get the cylinders/heads/sectors for the given drive.
+static void
+fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
+{
+    if (CONFIG_CDROM_EMU
+        && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) {
+        // Emulated drive - get info from ebda.  (It's not possible to
+        // populate the geometry directly in the driveid because the
+        // geometry is only known after the bios segment is made
+        // read-only).
+        u16 ebda_seg = get_ebda_seg();
+        *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
+        *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
+        *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
+        return;
+    }
+    *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
+    *nlh = GET_GLOBAL(drive_g->lchs.heads);
+    *nlspt = GET_GLOBAL(drive_g->lchs.spt);
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void
+basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = command;
+
+    u8 count = regs->al;
+    u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
+    u16 sector = regs->cl & 0x3f;
+    u16 head = regs->dh;
+
+    if (count > 128 || count == 0 || sector == 0) {
+        warn_invalid(regs);
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+    dop.count = count;
+
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    // sanity check on cyl heads, sec
+    if (cylinder >= nlc || head >= nlh || sector > nlspt) {
+        warn_invalid(regs);
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    // translate lchs to lba
+    dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+               + (u32)sector - 1);
+
+    dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+
+    int status = send_disk_op(&dop);
+
+    regs->al = dop.count;
+
+    disk_ret(regs, status);
+}
+
+// Perform read/write/verify using new-style "int13ext" accesses.
+static void
+extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+    struct disk_op_s dop;
+    // Get lba and check.
+    dop.lba = GET_INT13EXT(regs, lba);
+    dop.command = command;
+    dop.drive_g = drive_g;
+    if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
+        warn_invalid(regs);
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
+    dop.count = GET_INT13EXT(regs, count);
+
+    int status = send_disk_op(&dop);
+
+    SET_INT13EXT(regs, count, dop.count);
+
+    disk_ret(regs, status);
+}
+
+
+/****************************************************************
+ * Hard Drive functions
+ ****************************************************************/
+
+// disk controller reset
+static void
+disk_1300(struct bregs *regs, struct drive_s *drive_g)
+{
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_RESET;
+    int status = send_disk_op(&dop);
+    disk_ret(regs, status);
+}
+
+// read disk status
+static void
+disk_1301(struct bregs *regs, struct drive_s *drive_g)
+{
+    u8 v;
+    if (regs->dl < EXTSTART_HD)
+        // Floppy
+        v = GET_BDA(floppy_last_status);
+    else
+        v = GET_BDA(disk_last_status);
+    regs->ah = v;
+    set_cf(regs, v);
+    // XXX - clear disk_last_status?
+}
+
+// read disk sectors
+static void
+disk_1302(struct bregs *regs, struct drive_s *drive_g)
+{
+    basic_access(regs, drive_g, CMD_READ);
+}
+
+// write disk sectors
+static void
+disk_1303(struct bregs *regs, struct drive_s *drive_g)
+{
+    basic_access(regs, drive_g, CMD_WRITE);
+}
+
+// verify disk sectors
+static void
+disk_1304(struct bregs *regs, struct drive_s *drive_g)
+{
+    basic_access(regs, drive_g, CMD_VERIFY);
+}
+
+// format disk track
+static void
+disk_1305(struct bregs *regs, struct drive_s *drive_g)
+{
+    debug_stub(regs);
+
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    u8 num_sectors = regs->al;
+    u8 head        = regs->dh;
+
+    if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_FORMAT;
+    dop.lba = head;
+    dop.count = num_sectors;
+    dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+    int status = send_disk_op(&dop);
+    disk_ret(regs, status);
+}
+
+// read disk drive parameters
+static void
+disk_1308(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    // Get logical geometry from table
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+    nlc--;
+    nlh--;
+    u8 count;
+    if (regs->dl < EXTSTART_HD) {
+        // Floppy
+        count = GET_GLOBAL(FloppyCount);
+
+        if (CONFIG_CDROM_EMU
+            && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)))
+            regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
+        else
+            regs->bx = GET_GLOBAL(drive_g->floppy_type);
+
+        // set es & di to point to 11 byte diskette param table in ROM
+        regs->es = SEG_BIOS;
+        regs->di = (u32)&diskette_param_table2;
+    } else if (regs->dl < EXTSTART_CD) {
+        // Hard drive
+        count = GET_BDA(hdcount);
+        nlc--;  // last sector reserved
+    } else {
+        // Not supported on CDROM
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
+        u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+        if (((emudrive ^ regs->dl) & 0x80) == 0)
+            // Note extra drive due to emulation.
+            count++;
+        if (regs->dl < EXTSTART_HD && count > 2)
+            // Max of two floppy drives.
+            count = 2;
+    }
+
+    regs->al = 0;
+    regs->ch = nlc & 0xff;
+    regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
+    regs->dh = nlh;
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+    regs->dl = count;
+}
+
+// initialize drive parameters
+static void
+disk_1309(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// seek to specified cylinder
+static void
+disk_130c(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// alternate disk reset
+static void
+disk_130d(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// check drive ready
+static void
+disk_1310(struct bregs *regs, struct drive_s *drive_g)
+{
+    // should look at 40:8E also???
+
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_ISREADY;
+    int status = send_disk_op(&dop);
+    disk_ret(regs, status);
+}
+
+// recalibrate
+static void
+disk_1311(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// controller internal diagnostic
+static void
+disk_1314(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// read disk drive size
+static void
+disk_1315(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+    if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
+        // Floppy or cdrom
+        regs->ah = 1;
+        return;
+    }
+    // Hard drive
+
+    // Get logical geometry from table
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    // Compute sector count seen by int13
+    u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
+    regs->cx = lba >> 16;
+    regs->dx = lba & 0xffff;
+    regs->ah = 3; // hard disk accessible
+}
+
+static void
+disk_1316(struct bregs *regs, struct drive_s *drive_g)
+{
+    if (regs->dl >= EXTSTART_HD) {
+        // Hard drive
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+    disk_ret(regs, DISK_RET_ECHANGED);
+}
+
+// IBM/MS installation check
+static void
+disk_1341(struct bregs *regs, struct drive_s *drive_g)
+{
+    regs->bx = 0xaa55;  // install check
+    regs->cx = 0x0007;  // ext disk access and edd, removable supported
+    disk_ret(regs, DISK_RET_SUCCESS);
+    regs->ah = 0x30;    // EDD 3.0
+}
+
+// IBM/MS extended read
+static void
+disk_1342(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_READ);
+}
+
+// IBM/MS extended write
+static void
+disk_1343(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_WRITE);
+}
+
+// IBM/MS verify
+static void
+disk_1344(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_VERIFY);
+}
+
+// lock
+static void
+disk_134500(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+    if (locks == 0xff) {
+        regs->al = 1;
+        disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
+        return;
+    }
+    SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
+    regs->al = 1;
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// unlock
+static void
+disk_134501(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+    if (locks == 0x00) {
+        regs->al = 0;
+        disk_ret(regs, DISK_RET_ENOTLOCKED);
+        return;
+    }
+    locks--;
+    SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
+    regs->al = (locks ? 1 : 0);
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// status
+static void
+disk_134502(struct bregs *regs, struct drive_s *drive_g)
+{
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA(cdrom_locks[cdid]);
+    regs->al = (locks ? 1 : 0);
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS lock/unlock drive
+static void
+disk_1345(struct bregs *regs, struct drive_s *drive_g)
+{
+    if (regs->dl < EXTSTART_CD) {
+        // Always success for HD
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+
+    switch (regs->al) {
+    case 0x00: disk_134500(regs, drive_g); break;
+    case 0x01: disk_134501(regs, drive_g); break;
+    case 0x02: disk_134502(regs, drive_g); break;
+    default:   disk_1345XX(regs, drive_g); break;
+    }
+}
+
+// IBM/MS eject media
+static void
+disk_1346(struct bregs *regs, struct drive_s *drive_g)
+{
+    if (regs->dl < EXTSTART_CD) {
+        // Volume Not Removable
+        disk_ret(regs, DISK_RET_ENOTREMOVABLE);
+        return;
+    }
+
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA(cdrom_locks[cdid]);
+    if (locks != 0) {
+        disk_ret(regs, DISK_RET_ELOCKED);
+        return;
+    }
+
+    // FIXME should handle 0x31 no media in device
+    // FIXME should handle 0xb5 valid request failed
+
+    // Call removable media eject
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.ah = 0x52;
+    br.dl = regs->dl;
+    call16_int(0x15, &br);
+
+    if (br.ah || br.flags & F_CF) {
+        disk_ret(regs, DISK_RET_ELOCKED);
+        return;
+    }
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended seek
+static void
+disk_1347(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_SEEK);
+}
+
+// IBM/MS get drive parameters
+static void
+disk_1348(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 size = GET_INT13DPT(regs, size);
+    u16 t13 = size == 74;
+
+    // Buffer is too small
+    if (size < 26) {
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    // EDD 1.x
+
+    u8  type    = GET_GLOBAL(drive_g->type);
+    u16 npc     = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 nph     = GET_GLOBAL(drive_g->pchs.heads);
+    u16 npspt   = GET_GLOBAL(drive_g->pchs.spt);
+    u64 lba     = GET_GLOBAL(drive_g->sectors);
+    u16 blksize = GET_GLOBAL(drive_g->blksize);
+
+    dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
+            , size, type, npc, nph, npspt, (u32)lba, blksize);
+
+    SET_INT13DPT(regs, size, 26);
+    if (type == DTYPE_ATAPI) {
+        // 0x74 = removable, media change, lockable, max values
+        SET_INT13DPT(regs, infos, 0x74);
+        SET_INT13DPT(regs, cylinders, 0xffffffff);
+        SET_INT13DPT(regs, heads, 0xffffffff);
+        SET_INT13DPT(regs, spt, 0xffffffff);
+        SET_INT13DPT(regs, sector_count, (u64)-1);
+    } else {
+        if (lba > (u64)npspt*nph*0x3fff) {
+            SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
+            SET_INT13DPT(regs, cylinders, 0x3fff);
+        } else {
+            SET_INT13DPT(regs, infos, 0x02); // geometry is valid
+            SET_INT13DPT(regs, cylinders, (u32)npc);
+        }
+        SET_INT13DPT(regs, heads, (u32)nph);
+        SET_INT13DPT(regs, spt, (u32)npspt);
+        SET_INT13DPT(regs, sector_count, lba);
+    }
+    SET_INT13DPT(regs, blksize, blksize);
+
+    if (size < 30 ||
+        (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) {
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+
+    // EDD 2.x
+
+    int bdf;
+    u16 iobase1 = 0;
+    u64 device_path = 0;
+    u8 channel = 0;
+    SET_INT13DPT(regs, size, 30);
+    if (type == DTYPE_ATA || type == DTYPE_ATAPI) {
+        u16 ebda_seg = get_ebda_seg();
+
+        SET_INT13DPT(regs, dpte_segment, ebda_seg);
+        SET_INT13DPT(regs, dpte_offset
+                     , offsetof(struct extended_bios_data_area_s, dpte));
+
+        // Fill in dpte
+        struct atadrive_s *adrive_g = container_of(
+            drive_g, struct atadrive_s, drive);
+        struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+        u8 slave = GET_GLOBAL(adrive_g->slave);
+        u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+        u8 irq = GET_GLOBALFLAT(chan_gf->irq);
+        iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+        bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
+        device_path = slave;
+        channel = GET_GLOBALFLAT(chan_gf->chanid);
+
+        u16 options = 0;
+        if (type == DTYPE_ATA) {
+            u8 translation = GET_GLOBAL(drive_g->translation);
+            if (translation != TRANSLATION_NONE) {
+                options |= 1<<3; // CHS translation
+                if (translation == TRANSLATION_LBA)
+                    options |= 1<<9;
+                if (translation == TRANSLATION_RECHS)
+                    options |= 3<<9;
+            }
+        } else {
+            // ATAPI
+            options |= 1<<5; // removable device
+            options |= 1<<6; // atapi device
+        }
+        options |= 1<<4; // lba translation
+        if (CONFIG_ATA_PIO32)
+            options |= 1<<7;
+
+        SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
+        SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
+        SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+                                          | ATA_CB_DH_LBA));
+        SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
+        SET_EBDA2(ebda_seg, dpte.irq, irq);
+        SET_EBDA2(ebda_seg, dpte.blkcount, 1);
+        SET_EBDA2(ebda_seg, dpte.dma, 0);
+        SET_EBDA2(ebda_seg, dpte.pio, 0);
+        SET_EBDA2(ebda_seg, dpte.options, options);
+        SET_EBDA2(ebda_seg, dpte.reserved, 0);
+        SET_EBDA2(ebda_seg, dpte.revision, 0x11);
+
+        u8 sum = checksum_far(
+            ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
+        SET_EBDA2(ebda_seg, dpte.checksum, -sum);
+    } else {
+        SET_INT13DPT(regs, dpte_segment, 0);
+        SET_INT13DPT(regs, dpte_offset, 0);
+        bdf = GET_GLOBAL(drive_g->cntl_id);
+    }
+
+    if (size < 66) {
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+
+    // EDD 3.x
+    SET_INT13DPT(regs, key, 0xbedd);
+    SET_INT13DPT(regs, dpi_length, t13 ? 44 : 36);
+    SET_INT13DPT(regs, reserved1, 0);
+    SET_INT13DPT(regs, reserved2, 0);
+
+    if (bdf != -1) {
+        SET_INT13DPT(regs, host_bus[0], 'P');
+        SET_INT13DPT(regs, host_bus[1], 'C');
+        SET_INT13DPT(regs, host_bus[2], 'I');
+        SET_INT13DPT(regs, host_bus[3], ' ');
+
+        u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
+                    | (pci_bdf_to_fn(bdf) << 16));
+        if (t13)
+            path |= channel << 24;
+
+        SET_INT13DPT(regs, iface_path, path);
+    } else {
+        // ISA
+        SET_INT13DPT(regs, host_bus[0], 'I');
+        SET_INT13DPT(regs, host_bus[1], 'S');
+        SET_INT13DPT(regs, host_bus[2], 'A');
+        SET_INT13DPT(regs, host_bus[3], ' ');
+
+        SET_INT13DPT(regs, iface_path, iobase1);
+    }
+
+    if (type != DTYPE_VIRTIO) {
+        SET_INT13DPT(regs, iface_type[0], 'A');
+        SET_INT13DPT(regs, iface_type[1], 'T');
+        SET_INT13DPT(regs, iface_type[2], 'A');
+        SET_INT13DPT(regs, iface_type[3], ' ');
+    } else {
+        SET_INT13DPT(regs, iface_type[0], 'S');
+        SET_INT13DPT(regs, iface_type[1], 'C');
+        SET_INT13DPT(regs, iface_type[2], 'S');
+        SET_INT13DPT(regs, iface_type[3], 'I');
+    }
+    SET_INT13DPT(regs, iface_type[4], ' ');
+    SET_INT13DPT(regs, iface_type[5], ' ');
+    SET_INT13DPT(regs, iface_type[6], ' ');
+    SET_INT13DPT(regs, iface_type[7], ' ');
+
+    if (t13) {
+        SET_INT13DPT(regs, t13.device_path[0], device_path);
+        SET_INT13DPT(regs, t13.device_path[1], 0);
+
+        SET_INT13DPT(regs, t13.checksum
+                     , -checksum_far(regs->ds, (void*)(regs->si+30), 43));
+    } else {
+        SET_INT13DPT(regs, phoenix.device_path, device_path);
+
+        SET_INT13DPT(regs, phoenix.checksum
+                     , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
+    }
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended media change
+static void
+disk_1349(struct bregs *regs, struct drive_s *drive_g)
+{
+    if (regs->dl < EXTSTART_CD) {
+        // Always success for HD
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+    set_invalid(regs);
+    // always send changed ??
+    regs->ah = DISK_RET_ECHANGED;
+}
+
+static void
+disk_134e01(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e03(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e04(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e06(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS set hardware configuration
+static void
+disk_134e(struct bregs *regs, struct drive_s *drive_g)
+{
+    switch (regs->al) {
+    case 0x01: disk_134e01(regs, drive_g); break;
+    case 0x03: disk_134e03(regs, drive_g); break;
+    case 0x04: disk_134e04(regs, drive_g); break;
+    case 0x06: disk_134e06(regs, drive_g); break;
+    default:   disk_134eXX(regs, drive_g); break;
+    }
+}
+
+static void
+disk_13XX(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+static void
+disk_13(struct bregs *regs, struct drive_s *drive_g)
+{
+    //debug_stub(regs);
+
+    // clear completion flag
+    SET_BDA(disk_interrupt_flag, 0);
+
+    switch (regs->ah) {
+    case 0x00: disk_1300(regs, drive_g); break;
+    case 0x01: disk_1301(regs, drive_g); break;
+    case 0x02: disk_1302(regs, drive_g); break;
+    case 0x03: disk_1303(regs, drive_g); break;
+    case 0x04: disk_1304(regs, drive_g); break;
+    case 0x05: disk_1305(regs, drive_g); break;
+    case 0x08: disk_1308(regs, drive_g); break;
+    case 0x09: disk_1309(regs, drive_g); break;
+    case 0x0c: disk_130c(regs, drive_g); break;
+    case 0x0d: disk_130d(regs, drive_g); break;
+    case 0x10: disk_1310(regs, drive_g); break;
+    case 0x11: disk_1311(regs, drive_g); break;
+    case 0x14: disk_1314(regs, drive_g); break;
+    case 0x15: disk_1315(regs, drive_g); break;
+    case 0x16: disk_1316(regs, drive_g); break;
+    case 0x41: disk_1341(regs, drive_g); break;
+    case 0x42: disk_1342(regs, drive_g); break;
+    case 0x43: disk_1343(regs, drive_g); break;
+    case 0x44: disk_1344(regs, drive_g); break;
+    case 0x45: disk_1345(regs, drive_g); break;
+    case 0x46: disk_1346(regs, drive_g); break;
+    case 0x47: disk_1347(regs, drive_g); break;
+    case 0x48: disk_1348(regs, drive_g); break;
+    case 0x49: disk_1349(regs, drive_g); break;
+    case 0x4e: disk_134e(regs, drive_g); break;
+    default:   disk_13XX(regs, drive_g); break;
+    }
+}
+
+static void
+floppy_13(struct bregs *regs, struct drive_s *drive_g)
+{
+    // Only limited commands are supported on floppies.
+    switch (regs->ah) {
+    case 0x00:
+    case 0x01:
+    case 0x02:
+    case 0x03:
+    case 0x04:
+    case 0x05:
+    case 0x08:
+    case 0x15:
+    case 0x16:
+        disk_13(regs, drive_g);
+        break;
+    default:   disk_13XX(regs, drive_g); break;
+    }
+}
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+static void
+handle_legacy_disk(struct bregs *regs, u8 extdrive)
+{
+    if (! CONFIG_DRIVES) {
+        // XXX - support handle_1301 anyway?
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    if (extdrive < EXTSTART_HD) {
+        struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
+        if (!drive_g)
+            goto fail;
+        floppy_13(regs, drive_g);
+        return;
+    }
+
+    struct drive_s *drive_g;
+    if (extdrive >= EXTSTART_CD)
+        drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
+    else
+        drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
+    if (!drive_g)
+        goto fail;
+    disk_13(regs, drive_g);
+    return;
+
+fail:
+    // XXX - support 1301/1308/1315 anyway?
+    disk_ret(regs, DISK_RET_EPARAM);
+}
+
+void VISIBLE16
+handle_40(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_40);
+    handle_legacy_disk(regs, regs->dl);
+}
+
+// INT 13h Fixed Disk Services Entry Point
+void VISIBLE16
+handle_13(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_13);
+    u8 extdrive = regs->dl;
+
+    if (CONFIG_CDROM_EMU) {
+        if (regs->ah == 0x4b) {
+            cdemu_134b(regs);
+            return;
+        }
+        u16 ebda_seg = get_ebda_seg();
+        if (GET_EBDA2(ebda_seg, cdemu.active)) {
+            u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+            if (extdrive == emudrive) {
+                // Access to an emulated drive.
+                struct drive_s *cdemu_g;
+                cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
+                if (regs->ah > 0x16) {
+                    // Only old-style commands supported.
+                    disk_13XX(regs, cdemu_g);
+                    return;
+                }
+                disk_13(regs, cdemu_g);
+                return;
+            }
+            if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
+                // Adjust id to make room for emulated drive.
+                extdrive--;
+        }
+    }
+    handle_legacy_disk(regs, extdrive);
+}
+
+// record completion in BIOS task complete flag
+void VISIBLE16
+handle_76(void)
+{
+    debug_isr(DEBUG_ISR_76);
+    SET_BDA(disk_interrupt_flag, 0xff);
+    eoi_pic2();
+}
+
+// Old Fixed Disk Parameter Table (newer tables are in the ebda).
+struct fdpt_s OldFDPT VAR16FIXED(0xe401);
diff --git a/qemu-0.15.x/roms/seabios/src/disk.h b/qemu-0.15.x/roms/seabios/src/disk.h
new file mode 100644
index 0000000..10a0051
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/disk.h
@@ -0,0 +1,259 @@
+// Definitions for X86 bios disks.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __DISK_H
+#define __DISK_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_*
+#include "farptr.h" // struct segoff_s
+
+#define DISK_RET_SUCCESS       0x00
+#define DISK_RET_EPARAM        0x01
+#define DISK_RET_EADDRNOTFOUND 0x02
+#define DISK_RET_EWRITEPROTECT 0x03
+#define DISK_RET_ECHANGED      0x06
+#define DISK_RET_EBOUNDARY     0x09
+#define DISK_RET_EBADTRACK     0x0c
+#define DISK_RET_ECONTROLLER   0x20
+#define DISK_RET_ETIMEOUT      0x80
+#define DISK_RET_ENOTLOCKED    0xb0
+#define DISK_RET_ELOCKED       0xb1
+#define DISK_RET_ENOTREMOVABLE 0xb2
+#define DISK_RET_ETOOMANYLOCKS 0xb4
+#define DISK_RET_EMEDIA        0xC0
+#define DISK_RET_ENOTREADY     0xAA
+
+
+/****************************************************************
+ * Interface structs
+ ****************************************************************/
+
+// Bios disk structures.
+struct int13ext_s {
+    u8  size;
+    u8  reserved;
+    u16 count;
+    struct segoff_s data;
+    u64 lba;
+} PACKED;
+
+#define GET_INT13EXT(regs,var)                                          \
+    GET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var)
+#define SET_INT13EXT(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var, (val))
+
+// Disk Physical Table definition
+struct int13dpt_s {
+    u16 size;
+    u16 infos;
+    u32 cylinders;
+    u32 heads;
+    u32 spt;
+    u64 sector_count;
+    u16 blksize;
+    u16 dpte_offset;
+    u16 dpte_segment;
+    u16 key;
+    u8  dpi_length;
+    u8  reserved1;
+    u16 reserved2;
+    u8  host_bus[4];
+    u8  iface_type[8];
+    u64 iface_path;
+    union {
+        struct {
+            u64 device_path;
+            u8  reserved3;
+            u8  checksum;
+        } phoenix;
+        struct {
+            u64 device_path[2];
+            u8  reserved3;
+            u8  checksum;
+        } t13;
+    };
+} PACKED;
+
+#define GET_INT13DPT(regs,var)                                          \
+    GET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var)
+#define SET_INT13DPT(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var, (val))
+
+// Floppy "Disk Base Table"
+struct floppy_dbt_s {
+    u8 specify1;
+    u8 specify2;
+    u8 shutoff_ticks;
+    u8 bps_code;
+    u8 sectors;
+    u8 interblock_len;
+    u8 data_len;
+    u8 gap_len;
+    u8 fill_byte;
+    u8 settle_time;
+    u8 startup_time;
+} PACKED;
+
+struct floppy_ext_dbt_s {
+    struct floppy_dbt_s dbt;
+    // Extra fields
+    u8 max_track;
+    u8 data_rate;
+    u8 drive_type;
+} PACKED;
+
+// Helper function for setting up a return code.
+struct bregs;
+void __disk_ret(struct bregs *regs, u32 linecode, const char *fname);
+#define disk_ret(regs, code) \
+    __disk_ret((regs), (code) | (__LINE__ << 8), __func__)
+void __disk_ret_unimplemented(struct bregs *regs, u32 linecode
+                              , const char *fname);
+#define disk_ret_unimplemented(regs, code) \
+    __disk_ret_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+
+/****************************************************************
+ * Master boot record
+ ****************************************************************/
+
+struct packed_chs_s {
+    u8 heads;
+    u8 sptcyl;
+    u8 cyllow;
+};
+
+struct partition_s {
+    u8 status;
+    struct packed_chs_s first;
+    u8 type;
+    struct packed_chs_s last;
+    u32 lba;
+    u32 count;
+} PACKED;
+
+struct mbr_s {
+    u8 code[440];
+    // 0x01b8
+    u32 diskseg;
+    // 0x01bc
+    u16 null;
+    // 0x01be
+    struct partition_s partitions[4];
+    // 0x01fe
+    u16 signature;
+} PACKED;
+
+#define MBR_SIGNATURE 0xaa55
+
+
+/****************************************************************
+ * Disk command request
+ ****************************************************************/
+
+struct disk_op_s {
+    u64 lba;
+    void *buf_fl;
+    struct drive_s *drive_g;
+    u16 count;
+    u8 command;
+};
+
+#define CMD_RESET   0x00
+#define CMD_READ    0x02
+#define CMD_WRITE   0x03
+#define CMD_VERIFY  0x04
+#define CMD_FORMAT  0x05
+#define CMD_SEEK    0x07
+#define CMD_ISREADY 0x10
+
+
+/****************************************************************
+ * Global storage
+ ****************************************************************/
+
+struct chs_s {
+    u16 heads;      // # heads
+    u16 cylinders;  // # cylinders
+    u16 spt;        // # sectors / track
+};
+
+struct drive_s {
+    u8 type;            // Driver type (DTYPE_*)
+    u8 floppy_type;     // Type of floppy (only for floppy drives).
+    struct chs_s lchs;  // Logical CHS
+    u64 sectors;        // Total sectors count
+    u32 cntl_id;        // Unique id for a given driver type.
+    u8 removable;       // Is media removable (currently unused)
+
+    // Info for EDD calls
+    u8 translation;     // type of translation
+    u16 blksize;        // block size
+    struct chs_s pchs;  // Physical CHS
+};
+
+#define DISK_SECTOR_SIZE  512
+#define CDROM_SECTOR_SIZE 2048
+
+#define DTYPE_NONE     0x00
+#define DTYPE_FLOPPY   0x01
+#define DTYPE_ATA      0x02
+#define DTYPE_ATAPI    0x03
+#define DTYPE_RAMDISK  0x04
+#define DTYPE_CDEMU    0x05
+#define DTYPE_USB      0x06
+#define DTYPE_VIRTIO   0x07
+#define DTYPE_AHCI     0x08
+
+#define MAXDESCSIZE 80
+
+#define TRANSLATION_NONE  0
+#define TRANSLATION_LBA   1
+#define TRANSLATION_LARGE 2
+#define TRANSLATION_RECHS 3
+
+#define EXTTYPE_FLOPPY 0
+#define EXTTYPE_HD 1
+#define EXTTYPE_CD 2
+
+#define EXTSTART_HD 0x80
+#define EXTSTART_CD 0xE0
+
+
+/****************************************************************
+ * Function defs
+ ****************************************************************/
+
+// block.c
+extern u8 FloppyCount, CDCount;
+struct drive_s *getDrive(u8 exttype, u8 extdriveoffset);
+int getDriveId(u8 exttype, struct drive_s *drive_g);
+void map_floppy_drive(struct drive_s *drive_g);
+void map_hd_drive(struct drive_s *drive_g);
+void map_cd_drive(struct drive_s *drive_g);
+int process_op(struct disk_op_s *op);
+int send_disk_op(struct disk_op_s *op);
+
+// floppy.c
+extern struct floppy_ext_dbt_s diskette_param_table2;
+void floppy_setup(void);
+struct drive_s *init_floppy(int floppyid, int ftype);
+int find_floppy_type(u32 size);
+int process_floppy_op(struct disk_op_s *op);
+void floppy_tick(void);
+
+// cdrom.c
+extern struct drive_s *cdemu_drive_gf;
+int process_cdemu_op(struct disk_op_s *op);
+void cdemu_setup(void);
+void cdemu_134b(struct bregs *regs);
+int cdrom_boot(struct drive_s *drive_g);
+
+// ramdisk.c
+void ramdisk_setup(void);
+int process_ramdisk_op(struct disk_op_s *op);
+
+#endif // disk.h
diff --git a/qemu-0.15.x/roms/seabios/src/entryfuncs.S b/qemu-0.15.x/roms/seabios/src/entryfuncs.S
new file mode 100644
index 0000000..afc5e61
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/entryfuncs.S
@@ -0,0 +1,173 @@
+// Macros for entering C code
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Entry macros
+ ****************************************************************/
+
+        // Call a C function - this does the minimal work necessary to
+        // call into C.  It sets up %ds, backs up %es, and backs up
+        // those registers that are call clobbered by the C compiler.
+        .macro ENTRY cfunc
+        cli         // In case something far-calls instead of using "int"
+        cld
+        pushl %eax              // Save registers clobbered by C code
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %ax           // Move %ss to %ds
+        movw %ax, %ds
+        pushl %esp              // Backup %esp, then clear high bits
+        movzwl %sp, %esp
+        calll \cfunc
+        popl %esp               // Restore %esp (including high bits)
+        popw %ds                // Restore registers saved above
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // As above, but get calling function from stack.
+        .macro ENTRY_ST
+        cli
+        cld
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        pushl %esp              // Backup %esp, then clear high bits
+        movzwl %sp, %esp
+        movl 16(%esp), %ecx     // Get calling function
+        movl %eax, 16(%esp)     // Save %eax
+        calll *%ecx
+        popl %esp               // Restore %esp (including high bits)
+        popw %ds                // Restore registers saved above
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // Call a C function with current register list as an
+        // argument.  This backs up the registers and sets %eax
+        // to point to the backup.  On return, the registers are
+        // restored from the structure.
+        .macro ENTRY_ARG cfunc
+        cli
+        cld
+        pushl %eax              // Save registers (matches struct bregs)
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        movw %ss, %ax           // Move %ss to %ds
+        movw %ax, %ds
+        movl %esp, %ebx         // Backup %esp, then zero high bits
+        movzwl %sp, %esp
+        movl %esp, %eax         // First arg is pointer to struct bregs
+        calll \cfunc
+        movl %ebx, %esp         // Restore %esp (including high bits)
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // As above, but get calling function from stack.
+        .macro ENTRY_ARG_ST
+        cli
+        cld
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        movl %esp, %ebx         // Backup %esp, then zero high bits
+        movzwl %sp, %esp
+        movl 28(%esp), %ecx     // Get calling function
+        movl %eax, 28(%esp)     // Save %eax
+        movl %esp, %eax         // First arg is pointer to struct bregs
+        calll *%ecx
+        movl %ebx, %esp         // Restore %esp (including high bits)
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // Same as ENTRY_ARG, but don't mangle %esp
+        .macro ENTRY_ARG_ESP cfunc
+        cli
+        cld
+        pushl %eax              // Save registers (matches struct bregs)
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        movw %ss, %ax           // Move %ss to %ds
+        movw %ax, %ds
+        movl %esp, %eax         // First arg is pointer to struct bregs
+        calll \cfunc
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // Reset stack, transition to 32bit mode, and call a C function.
+        // Clobbers %ax
+        .macro ENTRY_INTO32 cfunc
+        xorw %ax, %ax
+        movw %ax, %ss
+        movl $ BUILD_STACK_ADDR , %esp
+        movl $ \cfunc , %edx
+        jmp transition32
+        .endm
+
+        // Declare a function
+        .macro DECLFUNC func
+        .section .text.asm.\func
+        .global \func
+        .endm
+
+        // Declare an exported function
+        .macro EXPORTFUNC func
+        .section .text.asm.export.\func
+        .global \func
+        .endm
diff --git a/qemu-0.15.x/roms/seabios/src/farptr.h b/qemu-0.15.x/roms/seabios/src/farptr.h
new file mode 100644
index 0000000..3dbf545
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/farptr.h
@@ -0,0 +1,204 @@
+// Code to access multiple segments within gcc.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __FARPTR_H
+#define __FARPTR_H
+
+#include "ioport.h" // insb
+
+// Dummy definitions used to make sure gcc understands dependencies
+// between SET_SEG and GET/READ/WRITE_SEG macros.
+extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS;
+extern u16 __segment_FS, __segment_GS;
+
+// Low level macros for reading/writing memory via a segment selector.
+#define READ8_SEG(prefix, SEG, value, var)                      \
+    __asm__(prefix "movb %%" #SEG ":%1, %b0" : "=Qi"(value)     \
+            : "m"(var), "m"(__segment_ ## SEG))
+#define READ16_SEG(prefix, SEG, value, var)                     \
+    __asm__(prefix "movw %%" #SEG ":%1, %w0" : "=ri"(value)     \
+            : "m"(var), "m"(__segment_ ## SEG))
+#define READ32_SEG(prefix, SEG, value, var)                     \
+    __asm__(prefix "movl %%" #SEG ":%1, %0" : "=ri"(value)      \
+            : "m"(var), "m"(__segment_ ## SEG))
+#define READ64_SEG(prefix, SEG, value, var) do {                \
+        union u64_u32_u __value;                                \
+        union u64_u32_u *__r64_ptr = (union u64_u32_u *)&(var); \
+        READ32_SEG(prefix, SEG, __value.hi, __r64_ptr->hi);     \
+        READ32_SEG(prefix, SEG, __value.lo, __r64_ptr->lo);     \
+        *(u64*)&(value) = __value.val;                          \
+    } while (0)
+#define WRITE8_SEG(prefix, SEG, var, value)                     \
+    __asm__(prefix "movb %b1, %%" #SEG ":%0" : "=m"(var)        \
+            : "Q"(value), "m"(__segment_ ## SEG))
+#define WRITE16_SEG(prefix, SEG, var, value)                    \
+    __asm__(prefix "movw %w1, %%" #SEG ":%0" : "=m"(var)        \
+            : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE32_SEG(prefix, SEG, var, value)                    \
+    __asm__(prefix "movl %1, %%" #SEG ":%0" : "=m"(var)         \
+            : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE64_SEG(prefix, SEG, var, value) do {               \
+        union u64_u32_u __value;                                \
+        union u64_u32_u *__w64_ptr = (union u64_u32_u *)&(var); \
+        typeof(var) __value_tmp = (value);                      \
+        __value.val = *(u64*)&__value_tmp;                      \
+        WRITE32_SEG(prefix, SEG, __w64_ptr->hi, __value.hi);    \
+        WRITE32_SEG(prefix, SEG, __w64_ptr->lo, __value.lo);    \
+    } while (0)
+
+// Macros for automatically choosing the appropriate memory size
+// access method.
+extern void __force_link_error__unknown_type(void);
+
+#define __GET_VAR(prefix, seg, var) ({          \
+    typeof(var) __val;                          \
+    if (sizeof(__val) == 1)                     \
+        READ8_SEG(prefix, seg, __val, var);     \
+    else if (sizeof(__val) == 2)                \
+        READ16_SEG(prefix, seg, __val, var);    \
+    else if (sizeof(__val) == 4)                \
+        READ32_SEG(prefix, seg, __val, var);    \
+    else if (sizeof(__val) == 8)                \
+        READ64_SEG(prefix, seg, __val, var);    \
+    else                                        \
+        __force_link_error__unknown_type();     \
+    __val; })
+
+#define __SET_VAR(prefix, seg, var, val) do {           \
+        if (sizeof(var) == 1)                           \
+            WRITE8_SEG(prefix, seg, var, (val));        \
+        else if (sizeof(var) == 2)                      \
+            WRITE16_SEG(prefix, seg, var, (val));       \
+        else if (sizeof(var) == 4)                      \
+            WRITE32_SEG(prefix, seg, var, (val));       \
+        else if (sizeof(var) == 8)                      \
+            WRITE64_SEG(prefix, seg, var, (val));       \
+        else                                            \
+            __force_link_error__unknown_type();         \
+    } while (0)
+
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value)                                   \
+    __asm__("movw %w1, %%" #SEG : "=m"(__segment_ ## SEG)       \
+            : "rm"(value))
+#define __GET_SEG(SEG) ({                                       \
+    u16 __seg;                                                  \
+    __asm__("movw %%" #SEG ", %w0" : "=rm"(__seg)               \
+            : "m"(__segment_ ## SEG));                          \
+    __seg;})
+
+// Macros for accessing a variable in another segment.  (They
+// automatically update the %es segment and then make the appropriate
+// access.)
+#define __GET_FARVAR(seg, var) ({               \
+    SET_SEG(ES, (seg));                         \
+    GET_VAR(ES, (var)); })
+#define __SET_FARVAR(seg, var, val) do {        \
+        typeof(var) __sfv_val = (val);          \
+        SET_SEG(ES, (seg));                     \
+        SET_VAR(ES, (var), __sfv_val);          \
+    } while (0)
+
+// Macros for accesssing a 32bit flat mode pointer from 16bit real
+// mode.  (They automatically update the %es segment, break the
+// pointer into segment/offset, and then make the access.)
+#define __GET_FLATPTR(ptr) ({                                   \
+    typeof(&(ptr)) __ptr = &(ptr);                              \
+    GET_FARVAR(FLATPTR_TO_SEG(__ptr)                            \
+               , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr)); })
+#define __SET_FLATPTR(ptr, val) do {                            \
+        typeof (&(ptr)) __ptr = &(ptr);                         \
+        SET_FARVAR(FLATPTR_TO_SEG(__ptr)                        \
+                   , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr)   \
+                   , (val));                                    \
+    } while (0)
+
+// Macros for converting to/from 32bit flat mode pointers to their
+// equivalent 16bit segment/offset values.
+#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 4)
+#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xf)
+#define MAKE_FLATPTR(seg,off) ((void*)(((u32)(seg)<<4)+(u32)(off)))
+
+
+#if MODESEGMENT == 1
+
+// Definitions when using segmented mode.
+#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var))
+#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val))
+#define GET_VAR(seg, var) __GET_VAR("", seg, (var))
+#define SET_VAR(seg, var, val) __SET_VAR("", seg, (var), (val))
+#define SET_SEG(SEG, value) __SET_SEG(SEG, (value))
+#define GET_SEG(SEG) __GET_SEG(SEG)
+#define GET_FLATPTR(ptr) __GET_FLATPTR(ptr)
+#define SET_FLATPTR(ptr, val) __SET_FLATPTR((ptr), (val))
+
+static inline void insb_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    insb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insw_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    insw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insl_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    insl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsb_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    outsb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsw_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    outsw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsl_fl(u16 port, void *ptr_fl, u16 count) {
+    SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+    outsl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+
+#else
+
+// In 32-bit flat mode there is no need to mess with the segments.
+#define GET_FARVAR(seg, var) \
+    (*((typeof(&(var)))MAKE_FLATPTR((seg), &(var))))
+#define SET_FARVAR(seg, var, val) \
+    do { GET_FARVAR((seg), (var)) = (val); } while (0)
+#define GET_VAR(seg, var) (var)
+#define SET_VAR(seg, var, val) do { (var) = (val); } while (0)
+#define SET_SEG(SEG, value) ((void)(value))
+#define GET_SEG(SEG) 0
+#define GET_FLATPTR(ptr) (ptr)
+#define SET_FLATPTR(ptr, val) do { (ptr) = (val); } while (0)
+
+#define insb_fl(port, ptr_fl, count) insb(port, ptr_fl, count)
+#define insw_fl(port, ptr_fl, count) insw(port, ptr_fl, count)
+#define insl_fl(port, ptr_fl, count) insl(port, ptr_fl, count)
+#define outsb_fl(port, ptr_fl, count) outsb(port, ptr_fl, count)
+#define outsw_fl(port, ptr_fl, count) outsw(port, ptr_fl, count)
+#define outsl_fl(port, ptr_fl, count) outsl(port, ptr_fl, count)
+
+#endif
+
+// Definition for common 16bit segment/offset pointers.
+struct segoff_s {
+    union {
+        struct {
+            u16 offset;
+            u16 seg;
+        };
+        u32 segoff;
+    };
+};
+#define SEGOFF(s,o) ({struct segoff_s __so; __so.offset=(o); __so.seg=(s); __so;})
+
+static inline struct segoff_s FLATPTR_TO_SEGOFF(void *p) {
+    return SEGOFF(FLATPTR_TO_SEG(p), FLATPTR_TO_OFFSET(p));
+}
+static inline void *SEGOFF_TO_FLATPTR(struct segoff_s so) {
+    return MAKE_FLATPTR(so.seg, so.offset);
+}
+
+#endif // farptr.h
diff --git a/qemu-0.15.x/roms/seabios/src/floppy.c b/qemu-0.15.x/roms/seabios/src/floppy.c
new file mode 100644
index 0000000..edc675d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/floppy.c
@@ -0,0 +1,622 @@
+// 16bit code to access floppy drives.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "disk.h" // DISK_RET_SUCCESS
+#include "config.h" // CONFIG_FLOPPY
+#include "biosvar.h" // SET_BDA
+#include "util.h" // wait_irq
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+#include "pci.h" // pci_to_bdf
+#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA
+
+#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
+#define FLOPPY_DATALEN 0xff   // Not used - because size code is 0x02
+#define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
+#define FLOPPY_FILLBYTE 0xf6
+#define FLOPPY_GAPLEN 0x1B
+#define FLOPPY_FORMAT_GAPLEN 0x6c
+
+// New diskette parameter table adding 3 parameters from IBM
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored.  I set parameters for 1.44M
+// floppy here
+struct floppy_ext_dbt_s diskette_param_table2 VAR16VISIBLE = {
+    .dbt = {
+        .specify1       = 0xAF, // step rate 12ms, head unload 240ms
+        .specify2       = 0x02, // head load time 4ms, DMA used
+        .shutoff_ticks  = FLOPPY_MOTOR_TICKS, // ~2 seconds
+        .bps_code       = FLOPPY_SIZE_CODE,
+        .sectors        = 18,
+        .interblock_len = FLOPPY_GAPLEN,
+        .data_len       = FLOPPY_DATALEN,
+        .gap_len        = FLOPPY_FORMAT_GAPLEN,
+        .fill_byte      = FLOPPY_FILLBYTE,
+        .settle_time    = 0x0F, // 15ms
+        .startup_time   = 0x08, // 1 second
+    },
+    .max_track      = 79,   // maximum track
+    .data_rate      = 0,    // data transfer rate
+    .drive_type     = 4,    // drive type in cmos
+};
+
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored.  I set parameters for 1.44M
+// floppy here
+struct floppy_dbt_s diskette_param_table VAR16FIXED(0xefc7) = {
+    .specify1       = 0xAF,
+    .specify2       = 0x02,
+    .shutoff_ticks  = FLOPPY_MOTOR_TICKS,
+    .bps_code       = FLOPPY_SIZE_CODE,
+    .sectors        = 18,
+    .interblock_len = FLOPPY_GAPLEN,
+    .data_len       = FLOPPY_DATALEN,
+    .gap_len        = FLOPPY_FORMAT_GAPLEN,
+    .fill_byte      = FLOPPY_FILLBYTE,
+    .settle_time    = 0x0F,
+    .startup_time   = 0x08,
+};
+
+struct floppyinfo_s {
+    struct chs_s chs;
+    u8 config_data;
+    u8 media_state;
+};
+
+struct floppyinfo_s FloppyInfo[] VAR16VISIBLE = {
+    // Unknown
+    { {0, 0, 0}, 0x00, 0x00},
+    // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors
+    { {2, 40, 9}, 0x00, 0x25},
+    // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors
+    { {2, 80, 15}, 0x00, 0x25},
+    // 3 - 720KB, 3.5"  - 2 heads, 80 tracks, 9 sectors
+    { {2, 80, 9}, 0x00, 0x17},
+    // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors
+    { {2, 80, 18}, 0x00, 0x17},
+    // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors
+    { {2, 80, 36}, 0xCC, 0xD7},
+    // 6 - 160k, 5.25"  - 1 heads, 40 tracks, 8 sectors
+    { {1, 40, 8}, 0x00, 0x27},
+    // 7 - 180k, 5.25"  - 1 heads, 40 tracks, 9 sectors
+    { {1, 40, 9}, 0x00, 0x27},
+    // 8 - 320k, 5.25"  - 2 heads, 40 tracks, 8 sectors
+    { {2, 40, 8}, 0x00, 0x27},
+};
+
+struct drive_s *
+init_floppy(int floppyid, int ftype)
+{
+    if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) {
+        dprintf(1, "Bad floppy type %d\n", ftype);
+        return NULL;
+    }
+
+    struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
+    if (!drive_g) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(drive_g, 0, sizeof(*drive_g));
+    drive_g->cntl_id = floppyid;
+    drive_g->type = DTYPE_FLOPPY;
+    drive_g->blksize = DISK_SECTOR_SIZE;
+    drive_g->floppy_type = ftype;
+    drive_g->sectors = (u64)-1;
+
+    memcpy(&drive_g->lchs, &FloppyInfo[ftype].chs
+           , sizeof(FloppyInfo[ftype].chs));
+    return drive_g;
+}
+
+static void
+addFloppy(int floppyid, int ftype)
+{
+    struct drive_s *drive_g = init_floppy(floppyid, ftype);
+    if (!drive_g)
+        return;
+    char *desc = znprintf(MAXDESCSIZE, "Floppy [drive %c]", 'A' + floppyid);
+    int bdf = pci_find_class(PCI_CLASS_BRIDGE_ISA); /* isa-to-pci bridge */
+    int prio = bootprio_find_fdc_device(bdf, PORT_FD_BASE, floppyid);
+    boot_add_floppy(drive_g, desc, prio);
+}
+
+void
+floppy_setup(void)
+{
+    if (! CONFIG_FLOPPY)
+        return;
+    dprintf(3, "init floppy drives\n");
+
+    if (CONFIG_COREBOOT) {
+        // XXX - disable floppies on coreboot for now.
+    } else {
+        u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+        if (type & 0xf0)
+            addFloppy(0, type >> 4);
+        if (type & 0x0f)
+            addFloppy(1, type & 0x0f);
+    }
+
+    outb(0x02, PORT_DMA1_MASK_REG);
+
+    enable_hwirq(6, FUNC16(entry_0e));
+}
+
+// Find a floppy type that matches a given image size.
+int
+find_floppy_type(u32 size)
+{
+    int i;
+    for (i=1; i<ARRAY_SIZE(FloppyInfo); i++) {
+        struct chs_s *c = &FloppyInfo[i].chs;
+        if (c->cylinders * c->heads * c->spt * DISK_SECTOR_SIZE == size)
+            return i;
+    }
+    return -1;
+}
+
+
+/****************************************************************
+ * Low-level floppy IO
+ ****************************************************************/
+
+static void
+floppy_reset_controller(void)
+{
+    // Reset controller
+    u8 val8 = inb(PORT_FD_DOR);
+    outb(val8 & ~0x04, PORT_FD_DOR);
+    outb(val8 | 0x04, PORT_FD_DOR);
+
+    // Wait for controller to come out of reset
+    while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+        ;
+}
+
+static int
+wait_floppy_irq(void)
+{
+    ASSERT16();
+    u8 v;
+    for (;;) {
+        if (!GET_BDA(floppy_motor_counter))
+            return -1;
+        v = GET_BDA(floppy_recalibration_status);
+        if (v & FRS_TIMEOUT)
+            break;
+        // Could use wait_irq() here, but that causes issues on
+        // bochs, so use yield() instead.
+        yield();
+    }
+
+    v &= ~FRS_TIMEOUT;
+    SET_BDA(floppy_recalibration_status, v);
+    return 0;
+}
+
+static void
+floppy_prepare_controller(u8 floppyid)
+{
+    CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+    // turn on motor of selected drive, DMA & int enabled, normal operation
+    u8 prev_reset = inb(PORT_FD_DOR) & 0x04;
+    u8 dor = 0x10;
+    if (floppyid)
+        dor = 0x20;
+    dor |= 0x0c;
+    dor |= floppyid;
+    outb(dor, PORT_FD_DOR);
+
+    // reset the disk motor timeout value of INT 08
+    SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
+
+    // wait for drive readiness
+    while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+        ;
+
+    if (!prev_reset)
+        wait_floppy_irq();
+}
+
+static int
+floppy_pio(u8 *cmd, u8 cmdlen)
+{
+    floppy_prepare_controller(cmd[1] & 1);
+
+    // send command to controller
+    u8 i;
+    for (i=0; i<cmdlen; i++)
+        outb(cmd[i], PORT_FD_DATA);
+
+    int ret = wait_floppy_irq();
+    if (ret) {
+        floppy_reset_controller();
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+floppy_cmd(struct disk_op_s *op, u16 count, u8 *cmd, u8 cmdlen)
+{
+    // es:bx = pointer to where to place information from diskette
+    u32 addr = (u32)op->buf_fl;
+
+    // check for 64K boundary overrun
+    u16 end = count - 1;
+    u32 last_addr = addr + end;
+    if ((addr >> 16) != (last_addr >> 16))
+        return DISK_RET_EBOUNDARY;
+
+    u8 mode_register = 0x4a; // single mode, increment, autoinit disable,
+    if (cmd[0] == 0xe6)
+        // read
+        mode_register = 0x46;
+
+    //DEBUGF("floppy dma c2\n");
+    outb(0x06, PORT_DMA1_MASK_REG);
+    outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+    outb(addr, PORT_DMA_ADDR_2);
+    outb(addr>>8, PORT_DMA_ADDR_2);
+    outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+    outb(end, PORT_DMA_CNT_2);
+    outb(end>>8, PORT_DMA_CNT_2);
+
+    // port 0b: DMA-1 Mode Register
+    // transfer type=write, channel 2
+    outb(mode_register, PORT_DMA1_MODE_REG);
+
+    // port 81: DMA-1 Page Register, channel 2
+    outb(addr>>16, PORT_DMA_PAGE_2);
+
+    outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2
+
+    int ret = floppy_pio(cmd, cmdlen);
+    if (ret)
+        return DISK_RET_ETIMEOUT;
+
+    // check port 3f4 for accessibility to status bytes
+    if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+        return DISK_RET_ECONTROLLER;
+
+    // read 7 return status bytes from controller
+    u8 i;
+    for (i=0; i<7; i++) {
+        u8 v = inb(PORT_FD_DATA);
+        cmd[i] = v;
+        SET_BDA(floppy_return_status[i], v);
+    }
+
+    return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy media sense
+ ****************************************************************/
+
+static inline void
+set_diskette_current_cyl(u8 floppyid, u8 cyl)
+{
+    SET_BDA(floppy_track[floppyid], cyl);
+}
+
+static void
+floppy_drive_recal(u8 floppyid)
+{
+    // send Recalibrate command (2 bytes) to controller
+    u8 data[12];
+    data[0] = 0x07;  // 07: Recalibrate
+    data[1] = floppyid; // 0=drive0, 1=drive1
+    floppy_pio(data, 2);
+
+    SETBITS_BDA(floppy_recalibration_status, 1<<floppyid);
+    set_diskette_current_cyl(floppyid, 0);
+}
+
+static int
+floppy_media_sense(struct drive_s *drive_g)
+{
+    // for now cheat and get drive type from CMOS,
+    // assume media is same as drive type
+
+    // ** config_data **
+    // Bitfields for diskette media control:
+    // Bit(s)  Description (Table M0028)
+    //  7-6  last data rate set by controller
+    //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5-4  last diskette drive step rate selected
+    //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+    //  3-2  {data rate at start of operation}
+    //  1-0  reserved
+
+    // ** media_state **
+    // Bitfields for diskette drive media state:
+    // Bit(s)  Description (Table M0030)
+    //  7-6  data rate
+    //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5  double stepping required (e.g. 360kB in 1.2MB)
+    //  4  media type established
+    //  3  drive capable of supporting 4MB media
+    //  2-0  on exit from BIOS, contains
+    //    000 trying 360kB in 360kB
+    //    001 trying 360kB in 1.2MB
+    //    010 trying 1.2MB in 1.2MB
+    //    011 360kB in 360kB established
+    //    100 360kB in 1.2MB established
+    //    101 1.2MB in 1.2MB established
+    //    110 reserved
+    //    111 all other formats/drives
+
+    u8 ftype = GET_GLOBAL(drive_g->floppy_type);
+    SET_BDA(floppy_last_data_rate, GET_GLOBAL(FloppyInfo[ftype].config_data));
+    u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+    SET_BDA(floppy_media_state[floppyid]
+            , GET_GLOBAL(FloppyInfo[ftype].media_state));
+    return DISK_RET_SUCCESS;
+}
+
+static int
+check_recal_drive(struct drive_s *drive_g)
+{
+    u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+    if ((GET_BDA(floppy_recalibration_status) & (1<<floppyid))
+        && (GET_BDA(floppy_media_state[floppyid]) & FMS_MEDIA_DRIVE_ESTABLISHED))
+        // Media is known.
+        return DISK_RET_SUCCESS;
+
+    // Recalibrate drive.
+    floppy_drive_recal(floppyid);
+
+    // Sense media.
+    return floppy_media_sense(drive_g);
+}
+
+
+/****************************************************************
+ * Floppy handlers
+ ****************************************************************/
+
+static void
+lba2chs(struct disk_op_s *op, u8 *track, u8 *sector, u8 *head)
+{
+    u32 lba = op->lba;
+
+    u32 tmp = lba + 1;
+    u16 nlspt = GET_GLOBAL(op->drive_g->lchs.spt);
+    *sector = tmp % nlspt;
+
+    tmp /= nlspt;
+    u16 nlh = GET_GLOBAL(op->drive_g->lchs.heads);
+    *head = tmp % nlh;
+
+    tmp /= nlh;
+    *track = tmp;
+}
+
+// diskette controller reset
+static int
+floppy_reset(struct disk_op_s *op)
+{
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    set_diskette_current_cyl(floppyid, 0); // current cylinder
+    return DISK_RET_SUCCESS;
+}
+
+// Read Diskette Sectors
+static int
+floppy_read(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // send read-normal-data command (9 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0xe6; // e6: read normal data
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = track;
+    data[3] = head;
+    data[4] = sector;
+    data[5] = FLOPPY_SIZE_CODE;
+    data[6] = sector + op->count - 1; // last sector to read on track
+    data[7] = FLOPPY_GAPLEN;
+    data[8] = FLOPPY_DATALEN;
+
+    res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+    if (res)
+        goto fail;
+
+    if (data[0] & 0xc0) {
+        res = DISK_RET_ECONTROLLER;
+        goto fail;
+    }
+
+    // ??? should track be new val from return_status[3] ?
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// Write Diskette Sectors
+static int
+floppy_write(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // send write-normal-data command (9 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0xc5; // c5: write normal data
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = track;
+    data[3] = head;
+    data[4] = sector;
+    data[5] = FLOPPY_SIZE_CODE;
+    data[6] = sector + op->count - 1; // last sector to write on track
+    data[7] = FLOPPY_GAPLEN;
+    data[8] = FLOPPY_DATALEN;
+
+    res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+    if (res)
+        goto fail;
+
+    if (data[0] & 0xc0) {
+        if (data[1] & 0x02)
+            res = DISK_RET_EWRITEPROTECT;
+        else
+            res = DISK_RET_ECONTROLLER;
+        goto fail;
+    }
+
+    // ??? should track be new val from return_status[3] ?
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// Verify Diskette Sectors
+static int
+floppy_verify(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // ??? should track be new val from return_status[3] ?
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// format diskette track
+static int
+floppy_format(struct disk_op_s *op)
+{
+    int ret = check_recal_drive(op->drive_g);
+    if (ret)
+        return ret;
+
+    u8 head = op->lba;
+
+    // send format-track command (6 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0x4d; // 4d: format track
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = FLOPPY_SIZE_CODE;
+    data[3] = op->count; // number of sectors per track
+    data[4] = FLOPPY_FORMAT_GAPLEN;
+    data[5] = FLOPPY_FILLBYTE;
+
+    ret = floppy_cmd(op, op->count * 4, data, 6);
+    if (ret)
+        return ret;
+
+    if (data[0] & 0xc0) {
+        if (data[1] & 0x02)
+            return DISK_RET_EWRITEPROTECT;
+        return DISK_RET_ECONTROLLER;
+    }
+
+    set_diskette_current_cyl(floppyid, 0);
+    return DISK_RET_SUCCESS;
+}
+
+int
+process_floppy_op(struct disk_op_s *op)
+{
+    if (!CONFIG_FLOPPY)
+        return 0;
+
+    switch (op->command) {
+    case CMD_RESET:
+        return floppy_reset(op);
+    case CMD_READ:
+        return floppy_read(op);
+    case CMD_WRITE:
+        return floppy_write(op);
+    case CMD_VERIFY:
+        return floppy_verify(op);
+    case CMD_FORMAT:
+        return floppy_format(op);
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * HW irqs
+ ****************************************************************/
+
+// INT 0Eh Diskette Hardware ISR Entry Point
+void VISIBLE16
+handle_0e(void)
+{
+    debug_isr(DEBUG_ISR_0e);
+    if (! CONFIG_FLOPPY)
+        goto done;
+
+    if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) {
+        outb(0x08, PORT_FD_DATA); // sense interrupt status
+        while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+            ;
+        do {
+            inb(PORT_FD_DATA);
+        } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
+    }
+    // diskette interrupt has occurred
+    SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+done:
+    eoi_pic1();
+}
+
+// Called from int08 handler.
+void
+floppy_tick(void)
+{
+    if (! CONFIG_FLOPPY)
+        return;
+
+    // time to turn off drive(s)?
+    u8 fcount = GET_BDA(floppy_motor_counter);
+    if (fcount) {
+        fcount--;
+        SET_BDA(floppy_motor_counter, fcount);
+        if (fcount == 0)
+            // turn motor(s) off
+            outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR);
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/font.c b/qemu-0.15.x/roms/seabios/src/font.c
new file mode 100644
index 0000000..3f8662f
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/font.c
@@ -0,0 +1,139 @@
+#include "types.h" // u8
+
+// Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+
+/*
+ * This font comes from the fntcol16.zip package (c) by  Joseph Gil
+ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * This font is public domain
+ */
+u8 vgafont8[128*8] VAR16FIXED(0xfa6e) = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+    0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+    0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+    0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+    0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+    0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+    0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+    0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+    0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+    0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+    0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+    0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+    0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+    0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+    0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+    0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+    0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+    0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+    0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+    0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+    0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+    0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+    0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+    0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+    0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+    0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+    0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+    0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+    0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+    0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+    0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+    0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+    0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+    0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+    0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+    0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+    0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+    0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+    0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+    0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+    0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+    0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+    0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+    0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+    0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+    0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+    0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+    0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+    0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+    0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+    0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+    0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+    0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+    0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+    0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+    0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+    0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+    0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+    0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+    0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+    0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+    0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+    0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+    0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+    0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+    0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+    0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+    0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+    0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+    0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+    0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+    0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+    0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+    0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+    0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+    0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+    0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+    0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+    0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+    0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+    0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+    0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+    0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+    0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+    0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+    0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+    0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+    0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+    0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+    0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+    0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+    0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+    0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+    0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+    0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+    0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+    0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+    0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+    0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+    0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+};
diff --git a/qemu-0.15.x/roms/seabios/src/gen-defs.h b/qemu-0.15.x/roms/seabios/src/gen-defs.h
new file mode 100644
index 0000000..dabf64c
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/gen-defs.h
@@ -0,0 +1,19 @@
+// Tool for building defintions accessible from assembler code.  This
+// is based on code from the Linux Kernel.
+#ifndef __GEN_DEFS_H
+#define __GEN_DEFS_H
+
+
+#define DEFINE(sym, val) \
+    asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() \
+    asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+    DEFINE(sym, offsetof(struct str, mem))
+
+#define COMMENT(x) \
+    asm volatile("\n->#" x)
+
+#endif // gen-defs.h
diff --git a/qemu-0.15.x/roms/seabios/src/ioport.h b/qemu-0.15.x/roms/seabios/src/ioport.h
new file mode 100644
index 0000000..3282fb4
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ioport.h
@@ -0,0 +1,136 @@
+// Definitions for X86 IO port access.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __IOPORT_H
+#define __IOPORT_H
+
+#define PORT_DMA_ADDR_2        0x0004
+#define PORT_DMA_CNT_2         0x0005
+#define PORT_DMA1_MASK_REG     0x000a
+#define PORT_DMA1_MODE_REG     0x000b
+#define PORT_DMA1_CLEAR_FF_REG 0x000c
+#define PORT_DMA1_MASTER_CLEAR 0x000d
+#define PORT_PIC1_CMD          0x0020
+#define PORT_PIC1_DATA         0x0021
+#define PORT_PIT_COUNTER0      0x0040
+#define PORT_PIT_COUNTER1      0x0041
+#define PORT_PIT_COUNTER2      0x0042
+#define PORT_PIT_MODE          0x0043
+#define PORT_PS2_DATA          0x0060
+#define PORT_PS2_CTRLB         0x0061
+#define PORT_PS2_STATUS        0x0064
+#define PORT_CMOS_INDEX        0x0070
+#define PORT_CMOS_DATA         0x0071
+#define PORT_DIAG              0x0080
+#define PORT_DMA_PAGE_2        0x0081
+#define PORT_A20               0x0092
+#define PORT_PIC2_CMD          0x00a0
+#define PORT_PIC2_DATA         0x00a1
+#define PORT_SMI_CMD           0x00b2
+#define PORT_SMI_STATUS        0x00b3
+#define PORT_DMA2_MASK_REG     0x00d4
+#define PORT_DMA2_MODE_REG     0x00d6
+#define PORT_DMA2_MASTER_CLEAR 0x00da
+#define PORT_MATH_CLEAR        0x00f0
+#define PORT_ATA2_CMD_BASE     0x0170
+#define PORT_ATA1_CMD_BASE     0x01f0
+#define PORT_LPT2              0x0278
+#define PORT_SERIAL4           0x02e8
+#define PORT_SERIAL2           0x02f8
+#define PORT_ATA2_CTRL_BASE    0x0374
+#define PORT_LPT1              0x0378
+#define PORT_SERIAL3           0x03e8
+#define PORT_ATA1_CTRL_BASE    0x03f4
+#define PORT_FD_BASE           0x03f0
+#define PORT_FD_DOR            0x03f2
+#define PORT_FD_STATUS         0x03f4
+#define PORT_FD_DATA           0x03f5
+#define PORT_HD_DATA           0x03f6
+#define PORT_FD_DIR            0x03f7
+#define PORT_SERIAL1           0x03f8
+#define PORT_PCI_CMD           0x0cf8
+#define PORT_PCI_REBOOT        0x0cf9
+#define PORT_PCI_DATA          0x0cfc
+#define PORT_BIOS_DEBUG        0x0402
+#define PORT_QEMU_CFG_CTL      0x0510
+#define PORT_QEMU_CFG_DATA     0x0511
+#define PORT_ACPI_PM_BASE      0xb000
+#define PORT_SMB_BASE          0xb100
+#define PORT_BIOS_APM          0x8900
+
+// Serial port offsets
+#define SEROFF_DATA    0
+#define SEROFF_DLL     0
+#define SEROFF_IER     1
+#define SEROFF_DLH     1
+#define SEROFF_IIR     2
+#define SEROFF_LCR     3
+#define SEROFF_LSR     5
+#define SEROFF_MSR     6
+
+// PORT_A20 bitdefs
+#define A20_ENABLE_BIT 0x02
+
+// PORT_CMOS_INDEX nmi disable bit
+#define NMI_DISABLE_BIT 0x80
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u8
+
+static inline void outb(u8 value, u16 port) {
+    __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outw(u16 value, u16 port) {
+    __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outl(u32 value, u16 port) {
+    __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline u8 inb(u16 port) {
+    u8 value;
+    __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
+    return value;
+}
+static inline u16 inw(u16 port) {
+    u16 value;
+    __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port));
+    return value;
+}
+static inline u32 inl(u16 port) {
+    u32 value;
+    __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port));
+    return value;
+}
+
+static inline void insb(u16 port, u8 *data, u32 count) {
+    asm volatile("rep insb (%%dx), %%es:(%%edi)"
+                 : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insw(u16 port, u16 *data, u32 count) {
+    asm volatile("rep insw (%%dx), %%es:(%%edi)"
+                 : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insl(u16 port, u32 *data, u32 count) {
+    asm volatile("rep insl (%%dx), %%es:(%%edi)"
+                 : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+// XXX - outs not limited to es segment
+static inline void outsb(u16 port, u8 *data, u32 count) {
+    asm volatile("rep outsb %%es:(%%esi), (%%dx)"
+                 : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsw(u16 port, u16 *data, u32 count) {
+    asm volatile("rep outsw %%es:(%%esi), (%%dx)"
+                 : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsl(u16 port, u32 *data, u32 count) {
+    asm volatile("rep outsl %%es:(%%esi), (%%dx)"
+                 : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // ioport.h
diff --git a/qemu-0.15.x/roms/seabios/src/jpeg.c b/qemu-0.15.x/roms/seabios/src/jpeg.c
new file mode 100644
index 0000000..1068291
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/jpeg.c
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (C) 2001, Novell Inc.
+ * Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+ * 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. Neither the name of Novell nor the names of the contributors may 
+ *    be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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.
+ * 
+ */
+
+/*
+ * a tiny jpeg decoder.
+ *
+ * written in August 2001 by Michael Schroeder <mls at suse.de>
+ *
+ */
+
+#define __LITTLE_ENDIAN
+#include "util.h"
+#include "jpeg.h"
+#define ISHIFT 11
+
+#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
+#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
+#define ITOINT(a) ((a) >> ISHIFT)
+
+#ifndef __P
+# define __P(x) x
+#endif
+
+/* special markers */
+#define M_BADHUFF        -1
+#define M_EOF                0x80
+
+struct in {
+    unsigned char *p;
+    unsigned int bits;
+    int left;
+    int marker;
+
+    int (*func) __P((void *));
+    void *data;
+};
+
+/*********************************/
+struct dec_hufftbl;
+struct enc_hufftbl;
+
+union hufftblp {
+    struct dec_hufftbl *dhuff;
+    struct enc_hufftbl *ehuff;
+};
+
+struct scan {
+    int dc;               /* old dc value */
+
+    union hufftblp hudc;
+    union hufftblp huac;
+    int next;             /* when to switch to next scan */
+
+    int cid;              /* component id */
+    int hv;               /* horiz/vert, copied from comp */
+    int tq;               /* quant tbl, copied from comp */
+};
+
+/*********************************/
+
+#define DECBITS 10        /* seems to be the optimum */
+
+struct dec_hufftbl {
+    int maxcode[17];
+    int valptr[16];
+    unsigned char vals[256];
+    unsigned int llvals[1 << DECBITS];
+};
+
+static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
+static int dec_readmarker __P((struct in *));
+static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
+
+static void setinput __P((struct in *, unsigned char *));
+/*********************************/
+
+#undef PREC
+#define PREC int
+
+static void idctqtab __P((unsigned char *, PREC *));
+static void idct __P((int *, int *, PREC *, PREC, int));
+static void scaleidctqtab __P((PREC *, PREC));
+
+/*********************************/
+
+static void initcol __P((PREC[][64]));
+
+static void col221111 __P((int *, unsigned char *, int));
+static void col221111_16 __P((int *, unsigned char *, int));
+static void col221111_32 __P((int *, unsigned char *, int));
+
+/*********************************/
+
+#define ERR_NO_SOI 1
+#define ERR_NOT_8BIT 2
+#define ERR_HEIGHT_MISMATCH 3
+#define ERR_WIDTH_MISMATCH 4
+#define ERR_BAD_WIDTH_OR_HEIGHT 5
+#define ERR_TOO_MANY_COMPPS 6
+#define ERR_ILLEGAL_HV 7
+#define ERR_QUANT_TABLE_SELECTOR 8
+#define ERR_NOT_YCBCR_221111 9
+#define ERR_UNKNOWN_CID_IN_SCAN 10
+#define ERR_NOT_SEQUENTIAL_DCT 11
+#define ERR_WRONG_MARKER 12
+#define ERR_NO_EOI 13
+#define ERR_BAD_TABLES 14
+#define ERR_DEPTH_MISMATCH 15
+
+/*********************************/
+
+#define M_SOI   0xd8
+#define M_APP0  0xe0
+#define M_DQT   0xdb
+#define M_SOF0  0xc0
+#define M_DHT   0xc4
+#define M_DRI   0xdd
+#define M_SOS   0xda
+#define M_RST0  0xd0
+#define M_EOI   0xd9
+#define M_COM   0xfe
+
+struct comp {
+    int cid;
+    int hv;
+    int tq;
+};
+
+#define MAXCOMP 4
+struct jpginfo {
+    int nc;   /* number of components */
+    int ns;   /* number of scans */
+    int dri;  /* restart interval */
+    int nm;   /* mcus til next marker */
+    int rm;   /* next restart marker */
+};
+
+struct jpeg_decdata {
+    int dcts[6 * 64 + 16];
+    int out[64 * 6];
+    int dquant[3][64];
+
+    unsigned char *datap;
+    struct jpginfo info;
+    struct comp comps[MAXCOMP];
+    struct scan dscans[MAXCOMP];
+    unsigned char quant[4][64];
+    struct dec_hufftbl dhuff[4];
+    struct in in;
+
+    int height, width;
+};
+
+static int getbyte(struct jpeg_decdata *jpeg)
+{
+    return *jpeg->datap++;
+}
+
+static int getword(struct jpeg_decdata *jpeg)
+{
+    int c1, c2;
+    c1 = *jpeg->datap++;
+    c2 = *jpeg->datap++;
+    return c1 << 8 | c2;
+}
+
+static int readtables(struct jpeg_decdata *jpeg, int till)
+{
+    int m, l, i, j, lq, pq, tq;
+    int tc, th, tt;
+
+    for (;;) {
+        if (getbyte(jpeg) != 0xff)
+            return -1;
+        if ((m = getbyte(jpeg)) == till)
+            break;
+
+        switch (m) {
+        case 0xc2:
+            return 0;
+
+        case M_DQT:
+            lq = getword(jpeg);
+            while (lq > 2) {
+                pq = getbyte(jpeg);
+                tq = pq & 15;
+                if (tq > 3)
+                    return -1;
+                pq >>= 4;
+                if (pq != 0)
+                    return -1;
+                for (i = 0; i < 64; i++)
+                    jpeg->quant[tq][i] = getbyte(jpeg);
+                lq -= 64 + 1;
+            }
+            break;
+
+        case M_DHT:
+            l = getword(jpeg);
+            while (l > 2) {
+                int hufflen[16], k;
+                unsigned char huffvals[256];
+
+                tc = getbyte(jpeg);
+                th = tc & 15;
+                tc >>= 4;
+                tt = tc * 2 + th;
+                if (tc > 1 || th > 1)
+                    return -1;
+                for (i = 0; i < 16; i++)
+                    hufflen[i] = getbyte(jpeg);
+                l -= 1 + 16;
+                k = 0;
+                for (i = 0; i < 16; i++) {
+                    for (j = 0; j < hufflen[i]; j++)
+                        huffvals[k++] = getbyte(jpeg);
+                    l -= hufflen[i];
+                }
+                dec_makehuff(jpeg->dhuff + tt, hufflen, huffvals);
+            }
+            break;
+
+        case M_DRI:
+            l = getword(jpeg);
+            jpeg->info.dri = getword(jpeg);
+            break;
+
+        default:
+            l = getword(jpeg);
+            while (l-- > 2)
+                getbyte(jpeg);
+            break;
+        }
+    }
+    return 0;
+}
+
+static void dec_initscans(struct jpeg_decdata *jpeg)
+{
+    int i;
+
+    jpeg->info.nm = jpeg->info.dri + 1;
+    jpeg->info.rm = M_RST0;
+    for (i = 0; i < jpeg->info.ns; i++)
+        jpeg->dscans[i].dc = 0;
+}
+
+static int dec_checkmarker(struct jpeg_decdata *jpeg)
+{
+    int i;
+
+    if (dec_readmarker(&jpeg->in) != jpeg->info.rm)
+        return -1;
+    jpeg->info.nm = jpeg->info.dri;
+    jpeg->info.rm = (jpeg->info.rm + 1) & ~0x08;
+    for (i = 0; i < jpeg->info.ns; i++)
+        jpeg->dscans[i].dc = 0;
+    return 0;
+}
+
+struct jpeg_decdata *jpeg_alloc(void)
+{
+    struct jpeg_decdata *jpeg = malloc_tmphigh(sizeof(*jpeg));
+    return jpeg;
+}
+
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf)
+{
+    int i, j, m, tac, tdc;
+
+    if (!jpeg || !buf)
+        return -1;
+    jpeg->datap = buf;
+    if (getbyte(jpeg) != 0xff)
+        return ERR_NO_SOI;
+    if (getbyte(jpeg) != M_SOI)
+        return ERR_NO_SOI;
+    if (readtables(jpeg, M_SOF0))
+        return ERR_BAD_TABLES;
+    getword(jpeg);
+    i = getbyte(jpeg);
+    if (i != 8)
+        return ERR_NOT_8BIT;
+    jpeg->height = getword(jpeg);
+    jpeg->width = getword(jpeg);
+    if ((jpeg->height & 15) || (jpeg->width & 15))
+        return ERR_BAD_WIDTH_OR_HEIGHT;
+    jpeg->info.nc = getbyte(jpeg);
+    if (jpeg->info.nc > MAXCOMP)
+        return ERR_TOO_MANY_COMPPS;
+    for (i = 0; i < jpeg->info.nc; i++) {
+        int h, v;
+        jpeg->comps[i].cid = getbyte(jpeg);
+        jpeg->comps[i].hv = getbyte(jpeg);
+        v = jpeg->comps[i].hv & 15;
+        h = jpeg->comps[i].hv >> 4;
+        jpeg->comps[i].tq = getbyte(jpeg);
+        if (h > 3 || v > 3)
+            return ERR_ILLEGAL_HV;
+        if (jpeg->comps[i].tq > 3)
+            return ERR_QUANT_TABLE_SELECTOR;
+    }
+    if (readtables(jpeg, M_SOS))
+        return ERR_BAD_TABLES;
+    getword(jpeg);
+    jpeg->info.ns = getbyte(jpeg);
+    if (jpeg->info.ns != 3)
+        return ERR_NOT_YCBCR_221111;
+    for (i = 0; i < 3; i++) {
+        jpeg->dscans[i].cid = getbyte(jpeg);
+        tdc = getbyte(jpeg);
+        tac = tdc & 15;
+        tdc >>= 4;
+        if (tdc > 1 || tac > 1)
+            return ERR_QUANT_TABLE_SELECTOR;
+        for (j = 0; j < jpeg->info.nc; j++)
+            if (jpeg->comps[j].cid == jpeg->dscans[i].cid)
+                break;
+        if (j == jpeg->info.nc)
+            return ERR_UNKNOWN_CID_IN_SCAN;
+        jpeg->dscans[i].hv = jpeg->comps[j].hv;
+        jpeg->dscans[i].tq = jpeg->comps[j].tq;
+        jpeg->dscans[i].hudc.dhuff = &jpeg->dhuff[tdc];
+        jpeg->dscans[i].huac.dhuff = &jpeg->dhuff[2 + tac];
+    }
+
+    i = getbyte(jpeg);
+    j = getbyte(jpeg);
+    m = getbyte(jpeg);
+
+    if (i != 0 || j != 63 || m != 0)
+        return ERR_NOT_SEQUENTIAL_DCT;
+
+    if (jpeg->dscans[0].cid != 1 || jpeg->dscans[1].cid != 2
+        || jpeg->dscans[2].cid != 3)
+        return ERR_NOT_YCBCR_221111;
+
+    if (jpeg->dscans[0].hv != 0x22 || jpeg->dscans[1].hv != 0x11
+        || jpeg->dscans[2].hv != 0x11)
+        return ERR_NOT_YCBCR_221111;
+
+    idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]);
+    idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]);
+    idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]);
+    initcol(jpeg->dquant);
+    setinput(&jpeg->in, jpeg->datap);
+
+#if 0
+    /* landing zone */
+    img[len] = 0;
+    img[len + 1] = 0xff;
+    img[len + 2] = M_EOF;
+#endif
+
+    dec_initscans(jpeg);
+
+    return 0;
+}
+
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height)
+{
+    *width = jpeg->width;
+    *height = jpeg->height;
+}
+
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic
+              , int width, int height, int depth)
+{
+    int m, mcusx, mcusy, mx, my;
+    int max[6];
+
+    if (jpeg->height != height)
+        return ERR_HEIGHT_MISMATCH;
+    if (jpeg->width != width)
+        return ERR_WIDTH_MISMATCH;
+
+    mcusx = jpeg->width >> 4;
+    mcusy = jpeg->height >> 4;
+
+    jpeg->dscans[0].next = 6 - 4;
+    jpeg->dscans[1].next = 6 - 4 - 1;
+    jpeg->dscans[2].next = 6 - 4 - 1 - 1;        /* 411 encoding */
+    for (my = 0; my < mcusy; my++) {
+        for (mx = 0; mx < mcusx; mx++) {
+            if (jpeg->info.dri && !--jpeg->info.nm)
+                if (dec_checkmarker(jpeg))
+                    return ERR_WRONG_MARKER;
+
+            decode_mcus(&jpeg->in, jpeg->dcts, 6, jpeg->dscans, max);
+            idct(jpeg->dcts, jpeg->out, jpeg->dquant[0],
+                 IFIX(128.5), max[0]);
+            idct(jpeg->dcts + 64, jpeg->out + 64, jpeg->dquant[0],
+                 IFIX(128.5), max[1]);
+            idct(jpeg->dcts + 128, jpeg->out + 128, jpeg->dquant[0],
+                 IFIX(128.5), max[2]);
+            idct(jpeg->dcts + 192, jpeg->out + 192, jpeg->dquant[0],
+                 IFIX(128.5), max[3]);
+            idct(jpeg->dcts + 256, jpeg->out + 256, jpeg->dquant[1],
+                 IFIX(0.5), max[4]);
+            idct(jpeg->dcts + 320, jpeg->out + 320, jpeg->dquant[2],
+                 IFIX(0.5), max[5]);
+
+            switch (depth) {
+            case 32:
+                col221111_32(jpeg->out,
+                             pic + (my * 16 * mcusx + mx) * 16 * 4,
+                             mcusx * 16 * 4);
+                break;
+            case 24:
+                col221111(jpeg->out,
+                          pic + (my * 16 * mcusx + mx) * 16 * 3,
+                          mcusx * 16 * 3);
+                break;
+            case 16:
+                col221111_16(jpeg->out,
+                             pic + (my * 16 * mcusx + mx) * (16 * 2),
+                             mcusx * (16 * 2));
+                break;
+            default:
+                return ERR_DEPTH_MISMATCH;
+                break;
+            }
+        }
+    }
+
+    m = dec_readmarker(&jpeg->in);
+    if (m != M_EOI)
+        return ERR_NO_EOI;
+
+    return 0;
+}
+
+/****************************************************************/
+/**************       huffman decoder             ***************/
+/****************************************************************/
+
+static int fillbits __P((struct in *, int, unsigned int));
+static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int));
+
+static void setinput(struct in *in, unsigned char *p)
+{
+    in->p = p;
+    in->left = 0;
+    in->bits = 0;
+    in->marker = 0;
+}
+
+static int fillbits(struct in *in, int le, unsigned int bi)
+{
+    int b, m;
+
+    if (in->marker) {
+        if (le <= 16)
+            in->bits = bi << 16, le += 16;
+        return le;
+    }
+    while (le <= 24) {
+        b = *in->p++;
+        if (b == 0xff && (m = *in->p++) != 0) {
+            if (m == M_EOF) {
+                if (in->func && (m = in->func(in->data)) == 0)
+                    continue;
+            }
+            in->marker = m;
+            if (le <= 16)
+                bi = bi << 16, le += 16;
+            break;
+        }
+        bi = bi << 8 | b;
+        le += 8;
+    }
+    in->bits = bi;                /* tmp... 2 return values needed */
+    return le;
+}
+
+static int dec_readmarker(struct in *in)
+{
+    int m;
+
+    in->left = fillbits(in, in->left, in->bits);
+    if ((m = in->marker) == 0)
+        return 0;
+    in->left = 0;
+    in->marker = 0;
+    return m;
+}
+
+#define LEBI_DCL       int le, bi
+#define LEBI_GET(in)   (le = in->left, bi = in->bits)
+#define LEBI_PUT(in)   (in->left = le, in->bits = bi)
+
+#define GETBITS(in, n) (                                     \
+  (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
+  (le -= (n)),                                               \
+  bi >> le & ((1 << (n)) - 1)                                \
+)
+
+#define UNGETBITS(in, n) ( \
+  le += (n)                \
+)
+
+
+static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp,
+                    int c, int i)
+{
+    LEBI_DCL;
+
+    LEBI_GET(in);
+    if (i) {
+        UNGETBITS(in, i & 127);
+        *runp = i >> 8 & 15;
+        i >>= 16;
+    } else {
+        for (i = DECBITS;
+             (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++);
+        if (i >= 16) {
+            in->marker = M_BADHUFF;
+            return 0;
+        }
+        i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
+        *runp = i >> 4;
+        i &= 15;
+    }
+    if (i == 0) {                /* sigh, 0xf0 is 11 bit */
+        LEBI_PUT(in);
+        return 0;
+    }
+    /* receive part */
+    c = GETBITS(in, i);
+    if (c < (1 << (i - 1)))
+        c += (-1 << i) + 1;
+    LEBI_PUT(in);
+    return c;
+}
+
+#define DEC_REC(in, hu, r, i)         (  \
+  r = GETBITS(in, DECBITS),              \
+  i = hu->llvals[r],                     \
+  i & 128 ?                              \
+    (                                    \
+      UNGETBITS(in, i & 127),            \
+      r = i >> 8 & 15,                   \
+      i >> 16                            \
+    )                                    \
+  :                                      \
+    (                                    \
+      LEBI_PUT(in),                      \
+      i = dec_rec2(in, hu, &r, r, i),    \
+      LEBI_GET(in),                      \
+      i                                  \
+    )                                    \
+)
+
+static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc,
+                        int *maxp)
+{
+    struct dec_hufftbl *hu;
+    int i, r, t;
+    LEBI_DCL;
+
+    memset(dct, 0, n * 64 * sizeof(*dct));
+    LEBI_GET(in);
+    while (n-- > 0) {
+        hu = sc->hudc.dhuff;
+        *dct++ = (sc->dc += DEC_REC(in, hu, r, t));
+
+        hu = sc->huac.dhuff;
+        i = 63;
+        while (i > 0) {
+            t = DEC_REC(in, hu, r, t);
+            if (t == 0 && r == 0) {
+                dct += i;
+                break;
+            }
+            dct += r;
+            *dct++ = t;
+            i -= r + 1;
+        }
+        *maxp++ = 64 - i;
+        if (n == sc->next)
+            sc++;
+    }
+    LEBI_PUT(in);
+}
+
+static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen,
+                         unsigned char *huffvals)
+{
+    int code, k, i, j, d, x, c, v;
+    for (i = 0; i < (1 << DECBITS); i++)
+        hu->llvals[i] = 0;
+
+    /*
+     * llvals layout:
+     *
+     * value v already known, run r, backup u bits:
+     *  vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
+     * value unknown, size b bits, run r, backup u bits:
+     *  000000000000bbbb 0000 rrrr 0 uuuuuuu
+     * value and size unknown:
+     *  0000000000000000 0000 0000 0 0000000
+     */
+
+    code = 0;
+    k = 0;
+    for (i = 0; i < 16; i++, code <<= 1) {        /* sizes */
+        hu->valptr[i] = k;
+        for (j = 0; j < hufflen[i]; j++) {
+            hu->vals[k] = *huffvals++;
+            if (i < DECBITS) {
+                c = code << (DECBITS - 1 - i);
+                v = hu->vals[k] & 0x0f;        /* size */
+                for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
+                    if (v + i < DECBITS) {        /* both fit in table */
+                        x = d >> (DECBITS - 1 - v - i);
+                        if (v && x < (1 << (v - 1)))
+                            x += (-1 << v) + 1;
+                        x = x << 16 | (hu->vals[k] & 0xf0) << 4 |
+                            (DECBITS - (i + 1 + v)) | 128;
+                    } else
+                        x = v << 16 | (hu->vals[k] & 0xf0) << 4 |
+                            (DECBITS - (i + 1));
+                    hu->llvals[c | d] = x;
+                }
+            }
+            code++;
+            k++;
+        }
+        hu->maxcode[i] = code;
+    }
+    hu->maxcode[16] = 0x20000;        /* always terminate decode */
+}
+
+/****************************************************************/
+/**************             idct                  ***************/
+/****************************************************************/
+
+#define ONE ((PREC)IFIX(1.))
+#define S2  ((PREC)IFIX(0.382683432))
+#define C2  ((PREC)IFIX(0.923879532))
+#define C4  ((PREC)IFIX(0.707106781))
+
+#define S22 ((PREC)IFIX(2 * 0.382683432))
+#define C22 ((PREC)IFIX(2 * 0.923879532))
+#define IC4 ((PREC)IFIX(1 / 0.707106781))
+
+#define C3IC1 ((PREC)IFIX(0.847759065))        /* c3/c1 */
+#define C5IC1 ((PREC)IFIX(0.566454497))        /* c5/c1 */
+#define C7IC1 ((PREC)IFIX(0.198912367))        /* c7/c1 */
+
+#define XPP(a,b) (t = a + b, b = a - b, a = t)
+#define XMP(a,b) (t = a - b, b = a + b, a = t)
+#define XPM(a,b) (t = a + b, b = b - a, a = t)
+
+#define ROT(a,b,s,c) (  t = IMULT(a + b, s),      \
+                        a = IMULT(a, c - s) + t,  \
+                        b = IMULT(b, c + s) - t)
+
+#define IDCT                \
+(                           \
+  XPP(t0, t1),              \
+  XMP(t2, t3),              \
+  t2 = IMULT(t2, IC4) - t3, \
+  XPP(t0, t3),              \
+  XPP(t1, t2),              \
+  XMP(t4, t7),              \
+  XPP(t5, t6),              \
+  XMP(t5, t7),              \
+  t5 = IMULT(t5, IC4),      \
+  ROT(t4, t6, S22, C22),    \
+  t6 -= t7,                 \
+  t5 -= t6,                 \
+  t4 -= t5,                 \
+  XPP(t0, t7),              \
+  XPP(t1, t6),              \
+  XPP(t2, t5),              \
+  XPP(t3, t4)               \
+)
+
+static unsigned char zig2[64] = {
+     0,  2,  3,  9, 10, 20, 21, 35,
+    14, 16, 25, 31, 39, 46, 50, 57,
+     5,  7, 12, 18, 23, 33, 37, 48,
+    27, 29, 41, 44, 52, 55, 59, 62,
+    15, 26, 30, 40, 45, 51, 56, 58,
+     1,  4,  8, 11, 19, 22, 34, 36,
+    28, 42, 43, 53, 54, 60, 61, 63,
+     6, 13, 17, 24, 32, 38, 47, 49
+};
+
+static void idct(int *in, int *out, PREC * quant, PREC off, int max)
+{
+    PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
+    PREC tmp[64], *tmpp;
+    int i, j;
+    unsigned char *zig2p;
+
+    t0 = off;
+    if (max == 1) {
+        t0 += in[0] * quant[0];
+        for (i = 0; i < 64; i++)
+            out[i] = ITOINT(t0);
+        return;
+    }
+    zig2p = zig2;
+    tmpp = tmp;
+    for (i = 0; i < 8; i++) {
+        j = *zig2p++;
+        t0 += in[j] * quant[j];
+        j = *zig2p++;
+        t5 = in[j] * quant[j];
+        j = *zig2p++;
+        t2 = in[j] * quant[j];
+        j = *zig2p++;
+        t7 = in[j] * quant[j];
+        j = *zig2p++;
+        t1 = in[j] * quant[j];
+        j = *zig2p++;
+        t4 = in[j] * quant[j];
+        j = *zig2p++;
+        t3 = in[j] * quant[j];
+        j = *zig2p++;
+        t6 = in[j] * quant[j];
+        IDCT;
+        tmpp[0 * 8] = t0;
+        tmpp[1 * 8] = t1;
+        tmpp[2 * 8] = t2;
+        tmpp[3 * 8] = t3;
+        tmpp[4 * 8] = t4;
+        tmpp[5 * 8] = t5;
+        tmpp[6 * 8] = t6;
+        tmpp[7 * 8] = t7;
+        tmpp++;
+        t0 = 0;
+    }
+    for (i = 0; i < 8; i++) {
+        t0 = tmp[8 * i + 0];
+        t1 = tmp[8 * i + 1];
+        t2 = tmp[8 * i + 2];
+        t3 = tmp[8 * i + 3];
+        t4 = tmp[8 * i + 4];
+        t5 = tmp[8 * i + 5];
+        t6 = tmp[8 * i + 6];
+        t7 = tmp[8 * i + 7];
+        IDCT;
+        out[8 * i + 0] = ITOINT(t0);
+        out[8 * i + 1] = ITOINT(t1);
+        out[8 * i + 2] = ITOINT(t2);
+        out[8 * i + 3] = ITOINT(t3);
+        out[8 * i + 4] = ITOINT(t4);
+        out[8 * i + 5] = ITOINT(t5);
+        out[8 * i + 6] = ITOINT(t6);
+        out[8 * i + 7] = ITOINT(t7);
+    }
+}
+
+static unsigned char zig[64] = {
+     0,  1,  5,  6, 14, 15, 27, 28,
+     2,  4,  7, 13, 16, 26, 29, 42,
+     3,  8, 12, 17, 25, 30, 41, 43,
+     9, 11, 18, 24, 31, 40, 44, 53,
+    10, 19, 23, 32, 39, 45, 52, 54,
+    20, 22, 33, 38, 46, 51, 55, 60,
+    21, 34, 37, 47, 50, 56, 59, 61,
+    35, 36, 48, 49, 57, 58, 62, 63
+};
+
+static PREC aaidct[8] = {
+    IFIX(0.3535533906), IFIX(0.4903926402),
+    IFIX(0.4619397663), IFIX(0.4157348062),
+    IFIX(0.3535533906), IFIX(0.2777851165),
+    IFIX(0.1913417162), IFIX(0.0975451610)
+};
+
+
+static void idctqtab(unsigned char *qin, PREC * qout)
+{
+    int i, j;
+
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 8; j++)
+            qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
+                IMULT(aaidct[i], aaidct[j]);
+}
+
+static void scaleidctqtab(PREC * q, PREC sc)
+{
+    int i;
+
+    for (i = 0; i < 64; i++)
+        q[i] = IMULT(q[i], sc);
+}
+
+/****************************************************************/
+/**************          color decoder            ***************/
+/****************************************************************/
+
+#define ROUND
+
+/*
+ * YCbCr Color transformation:
+ *
+ * y:0..255   Cb:-128..127   Cr:-128..127
+ *
+ *      R = Y                + 1.40200 * Cr
+ *      G = Y - 0.34414 * Cb - 0.71414 * Cr
+ *      B = Y + 1.77200 * Cb
+ *
+ * =>
+ *      Cr *= 1.40200;
+ *      Cb *= 1.77200;
+ *      Cg = 0.19421 * Cb + .50937 * Cr;
+ *      R = Y + Cr;
+ *      G = Y - Cg;
+ *      B = Y + Cb;
+ *
+ * =>
+ *      Cg = (50 * Cb + 130 * Cr + 128) >> 8;
+ */
+
+static void initcol(PREC q[][64])
+{
+    scaleidctqtab(q[1], IFIX(1.77200));
+    scaleidctqtab(q[2], IFIX(1.40200));
+}
+
+/* This is optimized for the stupid sun SUNWspro compiler. */
+#define STORECLAMP(a,x)                          \
+(                                                \
+  (a) = (x),                                     \
+  (unsigned int)(x) >= 256 ?                     \
+    ((a) = (x) < 0 ? 0 : 255)                    \
+  :                                              \
+    0                                            \
+)
+
+#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
+
+#ifdef ROUND
+
+#define CBCRCG(yin, xin)                         \
+(                                                \
+  cb = outc[0 +yin*8+xin],                       \
+  cr = outc[64+yin*8+xin],                       \
+  cg = (50 * cb + 130 * cr + 128) >> 8           \
+)
+
+#else
+
+#define CBCRCG(yin, xin)                         \
+(                                                \
+  cb = outc[0 +yin*8+xin],                       \
+  cr = outc[64+yin*8+xin],                       \
+  cg = (3 * cb + 8 * cr) >> 4                    \
+)
+
+#endif
+
+#define PIC(yin, xin, p, xout)                   \
+(                                                \
+  y = outy[(yin) * 8 + xin],                     \
+  STORECLAMP(p[(xout) * 3 + 0], y + cr),         \
+  STORECLAMP(p[(xout) * 3 + 1], y - cg),         \
+  STORECLAMP(p[(xout) * 3 + 2], y + cb)          \
+)
+
+#ifdef __LITTLE_ENDIAN
+#define PIC_16(yin, xin, p, xout, add)           \
+(                                                \
+  y = outy[(yin) * 8 + xin],                     \
+  y = ((CLAMP(y + cr + add*2+1) & 0xf8) <<  8) | \
+      ((CLAMP(y - cg + add    ) & 0xfc) <<  3) | \
+      ((CLAMP(y + cb + add*2+1)       ) >>  3),  \
+  p[(xout) * 2 + 0] = y & 0xff,                  \
+  p[(xout) * 2 + 1] = y >> 8                     \
+)
+#else
+#ifdef CONFIG_PPC
+#define PIC_16(yin, xin, p, xout, add)           \
+(                                                \
+  y = outy[(yin) * 8 + xin],                     \
+  y = ((CLAMP(y + cr + add*2+1) & 0xf8) <<  7) | \
+      ((CLAMP(y - cg + add*2+1) & 0xf8) <<  2) | \
+      ((CLAMP(y + cb + add*2+1)       ) >>  3),  \
+  p[(xout) * 2 + 0] = y >> 8,                    \
+  p[(xout) * 2 + 1] = y & 0xff                   \
+)
+#else
+#define PIC_16(yin, xin, p, xout, add)           \
+(                                                \
+  y = outy[(yin) * 8 + xin],                     \
+  y = ((CLAMP(y + cr + add*2+1) & 0xf8) <<  8) | \
+      ((CLAMP(y - cg + add    ) & 0xfc) <<  3) | \
+      ((CLAMP(y + cb + add*2+1)       ) >>  3),  \
+  p[(xout) * 2 + 0] = y >> 8,                    \
+  p[(xout) * 2 + 1] = y & 0xff                   \
+)
+#endif
+#endif
+
+#define PIC_32(yin, xin, p, xout)               \
+(                                               \
+  y = outy[(yin) * 8 + xin],                    \
+  STORECLAMP(p[(xout) * 4 + 0], y + cr),        \
+  STORECLAMP(p[(xout) * 4 + 1], y - cg),        \
+  STORECLAMP(p[(xout) * 4 + 2], y + cb),        \
+  p[(xout) * 4 + 3] = 0                         \
+)
+
+#define PIC221111(xin)                                              \
+(                                                                   \
+  CBCRCG(0, xin),                                                   \
+  PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0),       \
+  PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1),       \
+  PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0),       \
+  PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1)        \
+)
+
+#define PIC221111_16(xin)                                           \
+(                                                                   \
+  CBCRCG(0, xin),                                                   \
+  PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
+  PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
+  PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
+  PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2)  \
+)
+
+#define PIC221111_32(xin)                                           \
+(                                                                   \
+  CBCRCG(0, xin),                                                   \
+  PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0),    \
+  PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1),    \
+  PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0),    \
+  PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1)     \
+)
+
+static void col221111(int *out, unsigned char *pic, int width)
+{
+    int i, j, k;
+    unsigned char *pic0, *pic1;
+    int *outy, *outc;
+    int cr, cg, cb, y;
+
+    pic0 = pic;
+    pic1 = pic + width;
+    outy = out;
+    outc = out + 64 * 4;
+    for (i = 2; i > 0; i--) {
+        for (j = 4; j > 0; j--) {
+            for (k = 0; k < 8; k++) {
+                PIC221111(k);
+            }
+            outc += 8;
+            outy += 16;
+            pic0 += 2 * width;
+            pic1 += 2 * width;
+        }
+        outy += 64 * 2 - 16 * 4;
+    }
+}
+
+static void col221111_16(int *out, unsigned char *pic, int width)
+{
+    int i, j, k;
+    unsigned char *pic0, *pic1;
+    int *outy, *outc;
+    int cr, cg, cb, y;
+
+    pic0 = pic;
+    pic1 = pic + width;
+    outy = out;
+    outc = out + 64 * 4;
+    for (i = 2; i > 0; i--) {
+        for (j = 4; j > 0; j--) {
+            for (k = 0; k < 8; k++) {
+                PIC221111_16(k);
+            }
+            outc += 8;
+            outy += 16;
+            pic0 += 2 * width;
+            pic1 += 2 * width;
+        }
+        outy += 64 * 2 - 16 * 4;
+    }
+}
+
+static void col221111_32(int *out, unsigned char *pic, int width)
+{
+    int i, j, k;
+    unsigned char *pic0, *pic1;
+    int *outy, *outc;
+    int cr, cg, cb, y;
+
+    pic0 = pic;
+    pic1 = pic + width;
+    outy = out;
+    outc = out + 64 * 4;
+    for (i = 2; i > 0; i--) {
+        for (j = 4; j > 0; j--) {
+            for (k = 0; k < 8; k++) {
+                PIC221111_32(k);
+            }
+            outc += 8;
+            outy += 16;
+            pic0 += 2 * width;
+            pic1 += 2 * width;
+        }
+        outy += 64 * 2 - 16 * 4;
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/jpeg.h b/qemu-0.15.x/roms/seabios/src/jpeg.h
new file mode 100644
index 0000000..a2ac501
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/jpeg.h
@@ -0,0 +1,11 @@
+#ifndef __JPEG_H
+#define __JPEG_H
+
+struct jpeg_decdata;
+struct jpeg_decdata *jpeg_alloc(void);
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf);
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height);
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic
+              , int width, int height, int depth);
+
+#endif
diff --git a/qemu-0.15.x/roms/seabios/src/kbd.c b/qemu-0.15.x/roms/seabios/src/kbd.c
new file mode 100644
index 0000000..1977c5d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/kbd.c
@@ -0,0 +1,573 @@
+// 16bit code to handle keyboard requests.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "util.h" // debug_enter
+#include "config.h" // CONFIG_*
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_kbd_command
+#include "usb-hid.h" // usb_kbd_command
+
+// Bit definitions for BDA kbd_flag[012]
+#define KF0_RSHIFT       (1<<0)
+#define KF0_LSHIFT       (1<<1)
+#define KF0_CTRLACTIVE   (1<<2)
+#define KF0_ALTACTIVE    (1<<3)
+#define KF0_SCROLLACTIVE (1<<4)
+#define KF0_NUMACTIVE    (1<<5)
+#define KF0_CAPSACTIVE   (1<<6)
+
+#define KF1_LCTRL        (1<<0)
+#define KF1_LALT         (1<<1)
+#define KF1_PAUSEACTIVE  (1<<3)
+#define KF1_SCROLL       (1<<4)
+#define KF1_NUM          (1<<5)
+#define KF1_CAPS         (1<<6)
+
+#define KF2_LAST_E1    (1<<0)
+#define KF2_LAST_E0    (1<<1)
+#define KF2_RCTRL      (1<<2)
+#define KF2_RALT       (1<<3)
+#define KF2_101KBD     (1<<4)
+
+void
+kbd_setup(void)
+{
+    dprintf(3, "init keyboard\n");
+    u16 x = offsetof(struct bios_data_area_s, kbd_buf);
+    SET_BDA(kbd_flag2, KF2_101KBD);
+    SET_BDA(kbd_buf_head, x);
+    SET_BDA(kbd_buf_tail, x);
+    SET_BDA(kbd_buf_start_offset, x);
+
+    SET_BDA(kbd_buf_end_offset
+            , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
+}
+
+static u8
+enqueue_key(u8 scan_code, u8 ascii_code)
+{
+    u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+    u16 buffer_end   = GET_BDA(kbd_buf_end_offset);
+
+    u16 buffer_head = GET_BDA(kbd_buf_head);
+    u16 buffer_tail = GET_BDA(kbd_buf_tail);
+
+    u16 temp_tail = buffer_tail;
+    buffer_tail += 2;
+    if (buffer_tail >= buffer_end)
+        buffer_tail = buffer_start;
+
+    if (buffer_tail == buffer_head)
+        return 0;
+
+    SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0), ascii_code);
+    SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code);
+    SET_BDA(kbd_buf_tail, buffer_tail);
+    return 1;
+}
+
+static void
+dequeue_key(struct bregs *regs, int incr, int extended)
+{
+    yield();
+    u16 buffer_head;
+    u16 buffer_tail;
+    for (;;) {
+        buffer_head = GET_BDA(kbd_buf_head);
+        buffer_tail = GET_BDA(kbd_buf_tail);
+
+        if (buffer_head != buffer_tail)
+            break;
+        if (!incr) {
+            regs->flags |= F_ZF;
+            return;
+        }
+        wait_irq();
+    }
+
+    u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
+    u8 scan_code  = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1));
+    if ((ascii_code == 0xF0 && scan_code != 0)
+        || (ascii_code == 0xE0 && !extended))
+        ascii_code = 0;
+    regs->ax = (scan_code << 8) | ascii_code;
+
+    if (!incr) {
+        regs->flags &= ~F_ZF;
+        return;
+    }
+    u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+    u16 buffer_end   = GET_BDA(kbd_buf_end_offset);
+
+    buffer_head += 2;
+    if (buffer_head >= buffer_end)
+        buffer_head = buffer_start;
+    SET_BDA(kbd_buf_head, buffer_head);
+}
+
+static inline int
+kbd_command(int command, u8 *param)
+{
+    if (usb_kbd_active())
+        return usb_kbd_command(command, param);
+    return ps2_kbd_command(command, param);
+}
+
+// read keyboard input
+static void
+handle_1600(struct bregs *regs)
+{
+    dequeue_key(regs, 1, 0);
+}
+
+// check keyboard status
+static void
+handle_1601(struct bregs *regs)
+{
+    dequeue_key(regs, 0, 0);
+}
+
+// get shift flag status
+static void
+handle_1602(struct bregs *regs)
+{
+    yield();
+    regs->al = GET_BDA(kbd_flag0);
+}
+
+// store key-stroke into buffer
+static void
+handle_1605(struct bregs *regs)
+{
+    regs->al = !enqueue_key(regs->ch, regs->cl);
+}
+
+// GET KEYBOARD FUNCTIONALITY
+static void
+handle_1609(struct bregs *regs)
+{
+    // bit Bochs Description
+    //  7    0   reserved
+    //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
+    //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
+    //  4    1   INT 16/AH=0Ah supported
+    //  3    0   INT 16/AX=0306h supported
+    //  2    0   INT 16/AX=0305h supported
+    //  1    0   INT 16/AX=0304h supported
+    //  0    0   INT 16/AX=0300h supported
+    //
+    regs->al = 0x30;
+}
+
+// GET KEYBOARD ID
+static void
+handle_160a(struct bregs *regs)
+{
+    u8 param[2];
+    int ret = kbd_command(ATKBD_CMD_GETID, param);
+    if (ret) {
+        regs->bx = 0;
+        return;
+    }
+    regs->bx = (param[1] << 8) | param[0];
+}
+
+// read MF-II keyboard input
+static void
+handle_1610(struct bregs *regs)
+{
+    dequeue_key(regs, 1, 1);
+}
+
+// check MF-II keyboard status
+static void
+handle_1611(struct bregs *regs)
+{
+    dequeue_key(regs, 0, 1);
+}
+
+// get extended keyboard status
+static void
+handle_1612(struct bregs *regs)
+{
+    yield();
+    regs->al = GET_BDA(kbd_flag0);
+    regs->ah = ((GET_BDA(kbd_flag1) & ~(KF2_RCTRL|KF2_RALT))
+                | (GET_BDA(kbd_flag2) & (KF2_RCTRL|KF2_RALT)));
+    //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
+}
+
+static void
+handle_166f(struct bregs *regs)
+{
+    if (regs->al == 0x08)
+        // unsupported, aka normal keyboard
+        regs->ah = 2;
+}
+
+// keyboard capability check called by DOS 5.0+ keyb
+static void
+handle_1692(struct bregs *regs)
+{
+    // function int16 ah=0x10-0x12 supported
+    regs->ah = 0x80;
+}
+
+// 122 keys capability check called by DOS 5.0+ keyb
+static void
+handle_16a2(struct bregs *regs)
+{
+    // don't change AH : function int16 ah=0x20-0x22 NOT supported
+}
+
+static void
+handle_16XX(struct bregs *regs)
+{
+    warn_unimplemented(regs);
+}
+
+static void
+set_leds(void)
+{
+    u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07;
+    u8 kbd_led = GET_BDA(kbd_led);
+    u8 led_flags = kbd_led & 0x07;
+    if (shift_flags == led_flags)
+        return;
+
+    int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
+    if (ret)
+        // Error
+        return;
+    kbd_led = (kbd_led & ~0x07) | shift_flags;
+    SET_BDA(kbd_led, kbd_led);
+}
+
+// INT 16h Keyboard Service Entry Point
+void VISIBLE16
+handle_16(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_16);
+    if (! CONFIG_KEYBOARD)
+        return;
+
+    // XXX - set_leds should be called from irq handler
+    set_leds();
+
+    switch (regs->ah) {
+    case 0x00: handle_1600(regs); break;
+    case 0x01: handle_1601(regs); break;
+    case 0x02: handle_1602(regs); break;
+    case 0x05: handle_1605(regs); break;
+    case 0x09: handle_1609(regs); break;
+    case 0x0a: handle_160a(regs); break;
+    case 0x10: handle_1610(regs); break;
+    case 0x11: handle_1611(regs); break;
+    case 0x12: handle_1612(regs); break;
+    case 0x92: handle_1692(regs); break;
+    case 0xa2: handle_16a2(regs); break;
+    case 0x6f: handle_166f(regs); break;
+    default:   handle_16XX(regs); break;
+    }
+}
+
+#define none 0
+#define MNUM KF0_NUMACTIVE
+#define MCAP KF0_CAPSACTIVE
+
+static struct scaninfo {
+    u16 normal;
+    u16 shift;
+    u16 control;
+    u16 alt;
+    u8 lock_flags;
+} scan_to_scanascii[] VAR16 = {
+    {   none,   none,   none,   none, none },
+    { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
+    { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
+    { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
+    { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
+    { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
+    { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
+    { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
+    { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
+    { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
+    { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
+    { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
+    { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
+    { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
+    { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
+    { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
+    { 0x1071, 0x1051, 0x1011, 0x1000, MCAP }, /* Q */
+    { 0x1177, 0x1157, 0x1117, 0x1100, MCAP }, /* W */
+    { 0x1265, 0x1245, 0x1205, 0x1200, MCAP }, /* E */
+    { 0x1372, 0x1352, 0x1312, 0x1300, MCAP }, /* R */
+    { 0x1474, 0x1454, 0x1414, 0x1400, MCAP }, /* T */
+    { 0x1579, 0x1559, 0x1519, 0x1500, MCAP }, /* Y */
+    { 0x1675, 0x1655, 0x1615, 0x1600, MCAP }, /* U */
+    { 0x1769, 0x1749, 0x1709, 0x1700, MCAP }, /* I */
+    { 0x186f, 0x184f, 0x180f, 0x1800, MCAP }, /* O */
+    { 0x1970, 0x1950, 0x1910, 0x1900, MCAP }, /* P */
+    { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
+    { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
+    { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
+    {   none,   none,   none,   none, none }, /* L Ctrl */
+    { 0x1e61, 0x1e41, 0x1e01, 0x1e00, MCAP }, /* A */
+    { 0x1f73, 0x1f53, 0x1f13, 0x1f00, MCAP }, /* S */
+    { 0x2064, 0x2044, 0x2004, 0x2000, MCAP }, /* D */
+    { 0x2166, 0x2146, 0x2106, 0x2100, MCAP }, /* F */
+    { 0x2267, 0x2247, 0x2207, 0x2200, MCAP }, /* G */
+    { 0x2368, 0x2348, 0x2308, 0x2300, MCAP }, /* H */
+    { 0x246a, 0x244a, 0x240a, 0x2400, MCAP }, /* J */
+    { 0x256b, 0x254b, 0x250b, 0x2500, MCAP }, /* K */
+    { 0x266c, 0x264c, 0x260c, 0x2600, MCAP }, /* L */
+    { 0x273b, 0x273a,   none,   none, none }, /* ;: */
+    { 0x2827, 0x2822,   none,   none, none }, /* '" */
+    { 0x2960, 0x297e,   none,   none, none }, /* `~ */
+    {   none,   none,   none,   none, none }, /* L shift */
+    { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
+    { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, MCAP }, /* Z */
+    { 0x2d78, 0x2d58, 0x2d18, 0x2d00, MCAP }, /* X */
+    { 0x2e63, 0x2e43, 0x2e03, 0x2e00, MCAP }, /* C */
+    { 0x2f76, 0x2f56, 0x2f16, 0x2f00, MCAP }, /* V */
+    { 0x3062, 0x3042, 0x3002, 0x3000, MCAP }, /* B */
+    { 0x316e, 0x314e, 0x310e, 0x3100, MCAP }, /* N */
+    { 0x326d, 0x324d, 0x320d, 0x3200, MCAP }, /* M */
+    { 0x332c, 0x333c,   none,   none, none }, /* ,< */
+    { 0x342e, 0x343e,   none,   none, none }, /* .> */
+    { 0x352f, 0x353f,   none,   none, none }, /* /? */
+    {   none,   none,   none,   none, none }, /* R Shift */
+    { 0x372a, 0x372a,   none,   none, none }, /* * */
+    {   none,   none,   none,   none, none }, /* L Alt */
+    { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
+    {   none,   none,   none,   none, none }, /* caps lock */
+    { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
+    { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
+    { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
+    { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
+    { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
+    { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
+    { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
+    { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
+    { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
+    { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
+    {   none,   none,   none,   none, none }, /* Num Lock */
+    {   none,   none,   none,   none, none }, /* Scroll Lock */
+    { 0x4700, 0x4737, 0x7700,   none, MNUM }, /* 7 Home */
+    { 0x4800, 0x4838,   none,   none, MNUM }, /* 8 UP */
+    { 0x4900, 0x4939, 0x8400,   none, MNUM }, /* 9 PgUp */
+    { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
+    { 0x4b00, 0x4b34, 0x7300,   none, MNUM }, /* 4 Left */
+    { 0x4c00, 0x4c35,   none,   none, MNUM }, /* 5 */
+    { 0x4d00, 0x4d36, 0x7400,   none, MNUM }, /* 6 Right */
+    { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
+    { 0x4f00, 0x4f31, 0x7500,   none, MNUM }, /* 1 End */
+    { 0x5000, 0x5032,   none,   none, MNUM }, /* 2 Down */
+    { 0x5100, 0x5133, 0x7600,   none, MNUM }, /* 3 PgDn */
+    { 0x5200, 0x5230,   none,   none, MNUM }, /* 0 Ins */
+    { 0x5300, 0x532e,   none,   none, MNUM }, /* Del */
+    {   none,   none,   none,   none, none },
+    {   none,   none,   none,   none, none },
+    { 0x565c, 0x567c,   none,   none, none }, /* \| */
+    { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+    { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
+};
+
+// Handle a scancode read from the ps2 port.  Note that "noinline" is
+// used to make sure the call to call16_simpint in process_key doesn't
+// have the overhead of this function's stack.
+static void noinline
+__process_key(u8 scancode)
+{
+    u8 flags0 = GET_BDA(kbd_flag0);
+    u8 flags1 = GET_BDA(kbd_flag1);
+    u8 flags2 = GET_BDA(kbd_flag2);
+
+    if (flags2 & KF2_LAST_E1) {
+        // Part of "pause" key (sequence is e1 1d 45 e1 9d c5)
+        if ((scancode & ~0x80) == 0x1d)
+            // Second key of sequence
+            return;
+        // Third key of sequence - clear flag.
+        flags2 &= ~KF2_LAST_E1;
+        SET_BDA(kbd_flag2, flags2);
+
+        if (scancode == 0xc5) {
+            // Final key in sequence.
+
+            // XXX - do actual pause.
+        }
+        return;
+    }
+
+    // XXX - PrtScr should cause int 0x05
+    // XXX - Ctrl+Break should cause int 0x1B
+    // XXX - SysReq should cause int 0x15/0x85
+
+    switch (scancode) {
+    case 0x00:
+        dprintf(1, "KBD: int09 handler: AL=0\n");
+        return;
+
+    case 0x3a: /* Caps Lock press */
+        flags0 ^= KF0_CAPSACTIVE;
+        flags1 |= KF1_CAPS;
+        break;
+    case 0xba: /* Caps Lock release */
+        flags1 &= ~KF1_CAPS;
+        break;
+
+    case 0x2a: /* L Shift press */
+        flags0 |= KF0_LSHIFT;
+        break;
+    case 0xaa: /* L Shift release */
+        flags0 &= ~KF0_LSHIFT;
+        break;
+
+    case 0x36: /* R Shift press */
+        flags0 |= KF0_RSHIFT;
+        break;
+    case 0xb6: /* R Shift release */
+        flags0 &= ~KF0_RSHIFT;
+        break;
+
+    case 0x1d: /* Ctrl press */
+        flags0 |= KF0_CTRLACTIVE;
+        if (flags2 & KF2_LAST_E0)
+            flags2 |= KF2_RCTRL;
+        else
+            flags1 |= KF1_LCTRL;
+        break;
+    case 0x9d: /* Ctrl release */
+        flags0 &= ~KF0_CTRLACTIVE;
+        if (flags2 & KF2_LAST_E0)
+            flags2 &= ~KF2_RCTRL;
+        else
+            flags1 &= ~KF1_LCTRL;
+        break;
+
+    case 0x38: /* Alt press */
+        flags0 |= KF0_ALTACTIVE;
+        if (flags2 & KF2_LAST_E0)
+            flags2 |= KF2_RALT;
+        else
+            flags1 |= KF1_LALT;
+        break;
+    case 0xb8: /* Alt release */
+        flags0 &= ~KF0_ALTACTIVE;
+        if (flags2 & KF2_LAST_E0)
+            flags2 &= ~KF2_RALT;
+        else
+            flags1 &= ~KF1_LALT;
+        break;
+
+    case 0x45: /* Num Lock press */
+        flags1 |= KF1_NUM;
+        flags0 ^= KF0_NUMACTIVE;
+        break;
+    case 0xc5: /* Num Lock release */
+        flags1 &= ~KF1_NUM;
+        break;
+
+    case 0x46: /* Scroll Lock press */
+        flags1 |= KF1_SCROLL;
+        flags0 ^= KF0_SCROLLACTIVE;
+        break;
+    case 0xc6: /* Scroll Lock release */
+        flags1 &= ~KF1_SCROLL;
+        break;
+
+    case 0xe0:
+        // Extended key
+        flags2 |= KF2_LAST_E0;
+        SET_BDA(kbd_flag2, flags2);
+        return;
+    case 0xe1:
+        // Start of pause key sequence
+        flags2 |= KF2_LAST_E1;
+        break;
+
+    default:
+        if (scancode & 0x80)
+            // toss key releases
+            break;
+        if (scancode == 0x53
+            && ((flags0 & (KF0_CTRLACTIVE|KF0_ALTACTIVE))
+                == (KF0_CTRLACTIVE|KF0_ALTACTIVE))) {
+            // Ctrl+alt+del - reset machine.
+            SET_BDA(soft_reset_flag, 0x1234);
+            reset_vector();
+        }
+        if (scancode >= ARRAY_SIZE(scan_to_scanascii)) {
+            dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n"
+                    , scancode);
+            return;
+        }
+        u8 asciicode;
+        struct scaninfo *info = &scan_to_scanascii[scancode];
+        if (flags0 & KF0_ALTACTIVE) {
+            asciicode = GET_GLOBAL(info->alt);
+            scancode = GET_GLOBAL(info->alt) >> 8;
+        } else if (flags0 & KF0_CTRLACTIVE) {
+            asciicode = GET_GLOBAL(info->control);
+            scancode = GET_GLOBAL(info->control) >> 8;
+        } else if (flags2 & KF2_LAST_E0
+                   && scancode >= 0x47 && scancode <= 0x53) {
+            /* extended keys handling */
+            asciicode = 0xe0;
+            scancode = GET_GLOBAL(info->normal) >> 8;
+        } else if (flags0 & (KF0_RSHIFT|KF0_LSHIFT)) {
+            /* check if lock state should be ignored because a SHIFT
+             * key is pressed */
+
+            if (flags0 & GET_GLOBAL(info->lock_flags)) {
+                asciicode = GET_GLOBAL(info->normal);
+                scancode = GET_GLOBAL(info->normal) >> 8;
+            } else {
+                asciicode = GET_GLOBAL(info->shift);
+                scancode = GET_GLOBAL(info->shift) >> 8;
+            }
+        } else {
+            /* check if lock is on */
+            if (flags0 & GET_GLOBAL(info->lock_flags)) {
+                asciicode = GET_GLOBAL(info->shift);
+                scancode = GET_GLOBAL(info->shift) >> 8;
+            } else {
+                asciicode = GET_GLOBAL(info->normal);
+                scancode = GET_GLOBAL(info->normal) >> 8;
+            }
+        }
+        if (scancode==0 && asciicode==0)
+            dprintf(1, "KBD: scancode & asciicode are zero?\n");
+        enqueue_key(scancode, asciicode);
+        break;
+    }
+    flags2 &= ~KF2_LAST_E0;
+
+    SET_BDA(kbd_flag0, flags0);
+    SET_BDA(kbd_flag1, flags1);
+    SET_BDA(kbd_flag2, flags2);
+}
+
+void
+process_key(u8 key)
+{
+    if (!CONFIG_KEYBOARD)
+        return;
+
+    if (CONFIG_KBD_CALL_INT15_4F) {
+        // allow for keyboard intercept
+        u32 eax = (0x4f << 8) | key;
+        u32 flags;
+        call16_simpint(0x15, &eax, &flags);
+        if (!(flags & F_CF))
+            return;
+        key = eax;
+    }
+    __process_key(key);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/lzmadecode.c b/qemu-0.15.x/roms/seabios/src/lzmadecode.c
new file mode 100644
index 0000000..65819b5
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/lzmadecode.c
@@ -0,0 +1,398 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "lzmadecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  *inSizeProcessed = 0;
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  RC_INIT(inStream, inSize);
+
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        matchByte = outStream[nowPos - rep0];
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            
+            if (nowPos == 0)
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            previousByte = outStream[nowPos - rep0];
+            outStream[nowPos++] = previousByte;
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      if (rep0 > nowPos)
+        return LZMA_RESULT_DATA_ERROR;
+
+
+      do
+      {
+        previousByte = outStream[nowPos - rep0];
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/lzmadecode.h b/qemu-0.15.x/roms/seabios/src/lzmadecode.h
new file mode 100644
index 0000000..dedde0d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/lzmadecode.h
@@ -0,0 +1,67 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+typedef unsigned char Byte;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+typedef UInt32 SizeT;
+
+#define CProb UInt16
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+
+} CLzmaDecoderState;
+
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/qemu-0.15.x/roms/seabios/src/memmap.c b/qemu-0.15.x/roms/seabios/src/memmap.c
new file mode 100644
index 0000000..ea05953
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/memmap.c
@@ -0,0 +1,127 @@
+// Support for building memory maps suitable for int 15 e820 calls.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "memmap.h" // struct e820entry
+#include "util.h" // dprintf.h
+#include "biosvar.h" // SET_EBDA
+
+
+/****************************************************************
+ * e820 memory map
+ ****************************************************************/
+
+// Remove an entry from the e820_list.
+static void
+remove_e820(int i)
+{
+    e820_count--;
+    memmove(&e820_list[i], &e820_list[i+1]
+            , sizeof(e820_list[0]) * (e820_count - i));
+}
+
+// Insert an entry in the e820_list at the given position.
+static void
+insert_e820(int i, u64 start, u64 size, u32 type)
+{
+    if (e820_count >= CONFIG_MAX_E820) {
+        warn_noalloc();
+        return;
+    }
+
+    memmove(&e820_list[i+1], &e820_list[i]
+            , sizeof(e820_list[0]) * (e820_count - i));
+    e820_count++;
+    struct e820entry *e = &e820_list[i];
+    e->start = start;
+    e->size = size;
+    e->type = type;
+}
+
+// Show the current e820_list.
+static void
+dump_map(void)
+{
+    dprintf(1, "e820 map has %d items:\n", e820_count);
+    int i;
+    for (i=0; i<e820_count; i++) {
+        struct e820entry *e = &e820_list[i];
+        u64 e_end = e->start + e->size;
+        dprintf(1, "  %d: %08x%08x - %08x%08x = %d\n", i
+                , (u32)(e->start >> 32), (u32)e->start
+                , (u32)(e_end >> 32), (u32)e_end
+                , e->type);
+    }
+}
+
+// Add a new entry to the list.  This scans for overlaps and keeps the
+// list sorted.
+void
+add_e820(u64 start, u64 size, u32 type)
+{
+    dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
+
+    if (! size)
+        // Huh?  Nothing to do.
+        return;
+
+    // Find position of new item (splitting existing item if needed).
+    u64 end = start + size;
+    int i;
+    for (i=0; i<e820_count; i++) {
+        struct e820entry *e = &e820_list[i];
+        u64 e_end = e->start + e->size;
+        if (start > e_end)
+            continue;
+        // Found position - check if an existing item needs to be split.
+        if (start > e->start) {
+            if (type == e->type) {
+                // Same type - merge them.
+                size += start - e->start;
+                start = e->start;
+            } else {
+                // Split existing item.
+                e->size = start - e->start;
+                i++;
+                if (e_end > end)
+                    insert_e820(i, end, e_end - end, e->type);
+            }
+        }
+        break;
+    }
+    // Remove/adjust existing items that are overlapping.
+    while (i<e820_count) {
+        struct e820entry *e = &e820_list[i];
+        if (end < e->start)
+            // No overlap - done.
+            break;
+        u64 e_end = e->start + e->size;
+        if (end >= e_end) {
+            // Existing item completely overlapped - remove it.
+            remove_e820(i);
+            continue;
+        }
+        // Not completely overlapped - adjust its start.
+        e->start = end;
+        e->size = e_end - end;
+        if (type == e->type) {
+            // Same type - merge them.
+            size += e->size;
+            remove_e820(i);
+        }
+        break;
+    }
+    // Insert new item.
+    if (type != E820_HOLE)
+        insert_e820(i, start, size, type);
+    //dump_map();
+}
+
+// Report on final memory locations.
+void
+memmap_finalize(void)
+{
+    dump_map();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/memmap.h b/qemu-0.15.x/roms/seabios/src/memmap.h
new file mode 100644
index 0000000..01c7ddb
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/memmap.h
@@ -0,0 +1,32 @@
+#ifndef __E820MAP_H
+#define __E820MAP_H
+
+#include "types.h" // u64
+
+#define E820_RAM          1
+#define E820_RESERVED     2
+#define E820_ACPI         3
+#define E820_NVS          4
+#define E820_UNUSABLE     5
+#define E820_HOLE         ((u32)-1) // Useful for removing entries
+
+struct e820entry {
+    u64 start;
+    u64 size;
+    u32 type;
+};
+
+void add_e820(u64 start, u64 size, u32 type);
+void memmap_finalize(void);
+
+// A typical OS page size
+#define PAGE_SIZE 4096
+
+// e820 map storage (defined in system.c)
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+// Space for exported bios tables (defined in misc.c)
+extern char BiosTableSpace[];
+
+#endif // e820map.h
diff --git a/qemu-0.15.x/roms/seabios/src/misc.c b/qemu-0.15.x/roms/seabios/src/misc.c
new file mode 100644
index 0000000..9db49e3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/misc.c
@@ -0,0 +1,190 @@
+// Code for misc 16bit handlers and variables.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // debug_enter
+#include "pic.h" // enable_hwirq
+
+// Amount of continuous ram under 4Gig
+u32 RamSize VAR16VISIBLE;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Space for bios tables built an run-time.
+char BiosTableSpace[CONFIG_MAX_BIOSTABLE] __aligned(MALLOC_MIN_ALIGN) VAR16VISIBLE;
+
+
+/****************************************************************
+ * Misc 16bit ISRs
+ ****************************************************************/
+
+// INT 12h Memory Size Service Entry Point
+void VISIBLE16
+handle_12(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_12);
+    regs->ax = GET_BDA(mem_size_kb);
+}
+
+// INT 11h Equipment List Service Entry Point
+void VISIBLE16
+handle_11(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_11);
+    regs->ax = GET_BDA(equipment_list_flags);
+}
+
+// INT 05h Print Screen Service Entry Point
+void VISIBLE16
+handle_05(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_05);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_10);
+    // dont do anything, since the VGA BIOS handles int10h requests
+}
+
+// NMI handler
+void VISIBLE16
+handle_02(void)
+{
+    debug_isr(DEBUG_ISR_02);
+}
+
+void
+mathcp_setup(void)
+{
+    dprintf(3, "math cp init\n");
+    // 80x87 coprocessor installed
+    SETBITS_BDA(equipment_list_flags, 0x02);
+    enable_hwirq(13, FUNC16(entry_75));
+}
+
+// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
+void VISIBLE16
+handle_75(void)
+{
+    debug_isr(DEBUG_ISR_75);
+
+    // clear irq13
+    outb(0, PORT_MATH_CLEAR);
+    // clear interrupt
+    eoi_pic2();
+    // legacy nmi call
+    u32 eax=0, flags;
+    call16_simpint(0x02, &eax, &flags);
+}
+
+
+/****************************************************************
+ * BIOS_CONFIG_TABLE
+ ****************************************************************/
+
+// DMA channel 3 used by hard disk BIOS
+#define CBT_F1_DMA3USED (1<<7)
+// 2nd interrupt controller (8259) installed
+#define CBT_F1_2NDPIC   (1<<6)
+// Real-Time Clock installed
+#define CBT_F1_RTC      (1<<5)
+// INT 15/AH=4Fh called upon INT 09h
+#define CBT_F1_INT154F  (1<<4)
+// wait for external event (INT 15/AH=41h) supported
+#define CBT_F1_WAITEXT  (1<<3)
+// extended BIOS area allocated (usually at top of RAM)
+#define CBT_F1_EBDA     (1<<2)
+// bus is Micro Channel instead of ISA
+#define CBT_F1_MCA      (1<<1)
+// system has dual bus (Micro Channel + ISA)
+#define CBT_F1_MCAISA   (1<<0)
+
+// INT 16/AH=09h (keyboard functionality) supported
+#define CBT_F2_INT1609  (1<<6)
+
+struct bios_config_table_s BIOS_CONFIG_TABLE VAR16FIXED(0xe6f5) = {
+    .size     = sizeof(BIOS_CONFIG_TABLE) - 2,
+    .model    = CONFIG_MODEL_ID,
+    .submodel = CONFIG_SUBMODEL_ID,
+    .biosrev  = CONFIG_BIOS_REVISION,
+    .feature1 = (
+        CBT_F1_2NDPIC | CBT_F1_RTC | CBT_F1_EBDA
+        | (CONFIG_KBD_CALL_INT15_4F ? CBT_F1_INT154F : 0)),
+    .feature2 = CBT_F2_INT1609,
+    .feature3 = 0,
+    .feature4 = 0,
+    .feature5 = 0,
+};
+
+
+/****************************************************************
+ * GDT and IDT tables
+ ****************************************************************/
+
+// Real mode IDT descriptor
+struct descloc_s rmode_IDT_info VAR16VISIBLE = {
+    .length = sizeof(struct rmode_IVT) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0),
+};
+
+// Dummy IDT that forces a machine shutdown if an irq happens in
+// protected mode.
+u8 dummy_IDT VAR16VISIBLE;
+
+// Protected mode IDT descriptor
+struct descloc_s pmode_IDT_info VAR16VISIBLE = {
+    .length = sizeof(dummy_IDT) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_BIOS, &dummy_IDT),
+};
+
+// GDT
+u64 rombios32_gdt[] VAR16VISIBLE __aligned(8) = {
+    // First entry can't be used.
+    0x0000000000000000LL,
+    // 32 bit flat code segment (SEG32_MODE32_CS)
+    GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_B,
+    // 32 bit flat data segment (SEG32_MODE32_DS)
+    GDT_GRANLIMIT(0xffffffff) | GDT_DATA | GDT_B,
+    // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS)
+    GDT_LIMIT(BUILD_BIOS_SIZE-1) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+    // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
+    GDT_LIMIT(0x0ffff) | GDT_DATA,
+    // 16 bit code segment base=0xf0000 limit=0xffffffff (SEG32_MODE16BIG_CS)
+    GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+    // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS)
+    GDT_GRANLIMIT(0xffffffff) | GDT_DATA,
+};
+
+// GDT descriptor
+struct descloc_s rombios32_gdt_48 VAR16VISIBLE = {
+    .length = sizeof(rombios32_gdt) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_BIOS, rombios32_gdt),
+};
+
+
+/****************************************************************
+ * Misc fixed vars
+ ****************************************************************/
+
+char BiosCopyright[] VAR16FIXED(0xff00) =
+    "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team.";
+
+// BIOS build date
+char BiosDate[] VAR16FIXED(0xfff5) = "06/23/99";
+
+u8 BiosModelId VAR16FIXED(0xfffe) = CONFIG_MODEL_ID;
+
+u8 BiosChecksum VAR16FIXED(0xffff);
+
+// XXX - Initial Interrupt Vector Offsets Loaded by POST
+u8 InitVectors[13] VAR16FIXED(0xfef3);
+
+// XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES
+u8 VideoParams[88] VAR16FIXED(0xf0a4);
diff --git a/qemu-0.15.x/roms/seabios/src/mouse.c b/qemu-0.15.x/roms/seabios/src/mouse.c
new file mode 100644
index 0000000..09273b0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/mouse.c
@@ -0,0 +1,344 @@
+// 16bit code to handle mouse events.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_EBDA
+#include "util.h" // debug_isr
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_mouse_command
+#include "usb-hid.h" // usb_mouse_command
+
+void
+mouse_setup(void)
+{
+    if (! CONFIG_MOUSE)
+        return;
+    dprintf(3, "init mouse\n");
+    // pointing device installed
+    SETBITS_BDA(equipment_list_flags, 0x04);
+}
+
+static inline int
+mouse_command(int command, u8 *param)
+{
+    if (usb_mouse_active())
+        return usb_mouse_command(command, param);
+    return ps2_mouse_command(command, param);
+}
+
+#define RET_SUCCESS      0x00
+#define RET_EINVFUNCTION 0x01
+#define RET_EINVINPUT    0x02
+#define RET_EINTERFACE   0x03
+#define RET_ENEEDRESEND  0x04
+#define RET_ENOHANDLER   0x05
+
+static int
+disable_mouse(u16 ebda_seg)
+{
+    u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
+    ps2ctr |= I8042_CTR_AUXDIS;
+    ps2ctr &= ~I8042_CTR_AUXINT;
+    SET_EBDA2(ebda_seg, ps2ctr, ps2ctr);
+
+    return mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+}
+
+// Disable Mouse
+static void
+mouse_15c20000(struct bregs *regs)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int ret = disable_mouse(ebda_seg);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+// Enable Mouse
+static void
+mouse_15c20001(struct bregs *regs)
+{
+    u16 ebda_seg = get_ebda_seg();
+    u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+    if ((mouse_flags_2 & 0x80) == 0) {
+        set_code_invalid(regs, RET_ENOHANDLER);
+        return;
+    }
+
+    u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
+    ps2ctr &= ~I8042_CTR_AUXDIS;
+    ps2ctr |= I8042_CTR_AUXINT;
+    SET_EBDA2(ebda_seg, ps2ctr, ps2ctr);
+
+    int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+static void
+mouse_15c200XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Disable/Enable Mouse
+static void
+mouse_15c200(struct bregs *regs)
+{
+    switch (regs->bh) {
+    case 0x00: mouse_15c20000(regs); break;
+    case 0x01: mouse_15c20001(regs); break;
+    default:   mouse_15c200XX(regs); break;
+    }
+}
+
+// Reset Mouse
+static void
+mouse_15c201(struct bregs *regs)
+{
+    u8 param[2];
+    int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param);
+    if (ret) {
+        set_code_invalid(regs, RET_ENEEDRESEND);
+        return;
+    }
+    regs->bl = param[0];
+    regs->bh = param[1];
+    set_code_success(regs);
+}
+
+// Set Sample Rate
+static void
+mouse_15c202(struct bregs *regs)
+{
+    static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
+    if (regs->bh >= ARRAY_SIZE(sample_rates)) {
+        set_code_invalid(regs, RET_EINVINPUT);
+        return;
+    }
+    u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
+    int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+// Set Resolution
+static void
+mouse_15c203(struct bregs *regs)
+{
+    // BH:
+    //      0 =  25 dpi, 1 count  per millimeter
+    //      1 =  50 dpi, 2 counts per millimeter
+    //      2 = 100 dpi, 4 counts per millimeter
+    //      3 = 200 dpi, 8 counts per millimeter
+    if (regs->bh >= 4) {
+        set_code_invalid(regs, RET_EINVINPUT);
+        return;
+    }
+    u8 param = regs->bh;
+    int ret = mouse_command(PSMOUSE_CMD_SETRES, &param);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+// Get Device ID
+static void
+mouse_15c204(struct bregs *regs)
+{
+    u8 param[2];
+    int ret = mouse_command(PSMOUSE_CMD_GETID, param);
+    if (ret) {
+        set_code_invalid(regs, RET_ENEEDRESEND);
+        return;
+    }
+    regs->bh = param[0];
+    set_code_success(regs);
+}
+
+// Initialize Mouse
+static void
+mouse_15c205(struct bregs *regs)
+{
+    if (regs->bh != 3) {
+        set_code_invalid(regs, RET_EINTERFACE);
+        return;
+    }
+    u16 ebda_seg = get_ebda_seg();
+    SET_EBDA2(ebda_seg, mouse_flag1, 0x00);
+    SET_EBDA2(ebda_seg, mouse_flag2, regs->bh);
+
+    // Reset Mouse
+    mouse_15c201(regs);
+}
+
+// Return Status
+static void
+mouse_15c20600(struct bregs *regs)
+{
+    u8 param[3];
+    int ret = mouse_command(PSMOUSE_CMD_GETINFO, param);
+    if (ret) {
+        set_code_invalid(regs, RET_ENEEDRESEND);
+        return;
+    }
+    regs->bl = param[0];
+    regs->cl = param[1];
+    regs->dl = param[2];
+    set_code_success(regs);
+}
+
+// Set Scaling Factor to 1:1
+static void
+mouse_15c20601(struct bregs *regs)
+{
+    int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+// Set Scaling Factor to 2:1
+static void
+mouse_15c20602(struct bregs *regs)
+{
+    int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL);
+    if (ret)
+        set_code_invalid(regs, RET_ENEEDRESEND);
+    else
+        set_code_success(regs);
+}
+
+static void
+mouse_15c206XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Return Status & Set Scaling Factor...
+static void
+mouse_15c206(struct bregs *regs)
+{
+    switch (regs->bh) {
+    case 0x00: mouse_15c20600(regs); break;
+    case 0x01: mouse_15c20601(regs); break;
+    case 0x02: mouse_15c20602(regs); break;
+    default:   mouse_15c206XX(regs); break;
+    }
+}
+
+// Set Mouse Handler Address
+static void
+mouse_15c207(struct bregs *regs)
+{
+    struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
+    u16 ebda_seg = get_ebda_seg();
+    u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+    if (! farptr.segoff) {
+        /* remove handler */
+        if ((mouse_flags_2 & 0x80) != 0) {
+            mouse_flags_2 &= ~0x80;
+            disable_mouse(ebda_seg);
+        }
+    } else {
+        /* install handler */
+        mouse_flags_2 |= 0x80;
+    }
+    SET_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2);
+    SET_EBDA2(ebda_seg, far_call_pointer, farptr);
+    set_code_success(regs);
+}
+
+static void
+mouse_15c2XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+void
+handle_15c2(struct bregs *regs)
+{
+    //debug_stub(regs);
+
+    if (! CONFIG_MOUSE) {
+        set_code_invalid(regs, RET_EUNSUPPORTED);
+        return;
+    }
+
+    switch (regs->al) {
+    case 0x00: mouse_15c200(regs); break;
+    case 0x01: mouse_15c201(regs); break;
+    case 0x02: mouse_15c202(regs); break;
+    case 0x03: mouse_15c203(regs); break;
+    case 0x04: mouse_15c204(regs); break;
+    case 0x05: mouse_15c205(regs); break;
+    case 0x06: mouse_15c206(regs); break;
+    case 0x07: mouse_15c207(regs); break;
+    default:   mouse_15c2XX(regs); break;
+    }
+}
+
+void noinline
+process_mouse(u8 data)
+{
+    if (!CONFIG_MOUSE)
+        return;
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1);
+    u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+
+    if (! (mouse_flags_2 & 0x80))
+        // far call handler not installed
+        return;
+
+    u8 package_count = mouse_flags_2 & 0x07;
+    u8 index = mouse_flags_1 & 0x07;
+    SET_EBDA2(ebda_seg, mouse_data[index], data);
+
+    if ((index+1) < package_count) {
+        mouse_flags_1++;
+        SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1);
+        return;
+    }
+
+    u16 status = GET_EBDA2(ebda_seg, mouse_data[0]);
+    u16 X      = GET_EBDA2(ebda_seg, mouse_data[1]);
+    u16 Y      = GET_EBDA2(ebda_seg, mouse_data[2]);
+    SET_EBDA2(ebda_seg, mouse_flag1, 0);
+
+    struct segoff_s func = GET_EBDA2(ebda_seg, far_call_pointer);
+    dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
+            , status, X, Y, func.seg, func.offset);
+
+    asm volatile(
+        "pushl %%ebp\n"
+        "sti\n"
+
+        "pushl %0\n"
+        "pushw %w1\n"  // status
+        "pushw %w2\n"  // X
+        "pushw %w3\n"  // Y
+        "pushw $0\n"   // Z
+        "lcallw *8(%%esp)\n"
+        "addl $12, %%esp\n"
+
+        "cli\n"
+        "cld\n"
+        "popl %%ebp"
+        : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y)
+        :
+        : "edi", "esi", "cc", "memory");
+}
diff --git a/qemu-0.15.x/roms/seabios/src/mptable.c b/qemu-0.15.x/roms/seabios/src/mptable.c
new file mode 100644
index 0000000..e5952c3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/mptable.c
@@ -0,0 +1,206 @@
+// MPTable generation (on emulators)
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "paravirt.h" // qemu_cfg_irq0_override
+#include "pci.h"
+#include "pci_regs.h"
+
+void
+mptable_init(void)
+{
+    if (! CONFIG_MPTABLE)
+        return;
+
+    dprintf(3, "init MPTable\n");
+
+    // Config structure in temp area.
+    struct mptable_config_s *config = malloc_tmp(32*1024);
+    if (!config) {
+        warn_noalloc();
+        return;
+    }
+    memset(config, 0, sizeof(*config));
+    config->signature = MPCONFIG_SIGNATURE;
+    config->spec = 4;
+    memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid));
+    memcpy(config->productid, "0.1         ", sizeof(config->productid));
+    config->lapic = BUILD_APIC_ADDR;
+
+    // Detect cpu info
+    u32 cpuid_signature, ebx, ecx, cpuid_features;
+    cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+    if (! cpuid_signature) {
+        // Use default values.
+        cpuid_signature = 0x600;
+        cpuid_features = 0x201;
+    }
+    int pkgcpus = 1;
+    if (cpuid_features & (1 << 28)) {
+        /* Only populate the MPS tables with the first logical CPU in
+           each package */
+        pkgcpus = (ebx >> 16) & 0xff;
+        pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */
+    }
+    u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff;
+
+    // CPU definitions.
+    struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus;
+    int i;
+    for (i = 0; i < MaxCountCPUs; i+=pkgcpus) {
+        memset(cpu, 0, sizeof(*cpu));
+        cpu->type = MPT_TYPE_CPU;
+        cpu->apicid = i;
+        cpu->apicver = apic_version;
+        /* cpu flags: enabled, bootstrap cpu */
+        cpu->cpuflag = ((i<CountCPUs) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
+        cpu->cpusignature = cpuid_signature;
+        cpu->featureflag = cpuid_features;
+        cpu++;
+    }
+    int entrycount = cpu - cpus;
+
+    // PCI buses
+    struct mpt_bus *buses = (void*)cpu, *bus = buses;
+    int bdf, max, lastbus = -1;
+    foreachpci(bdf, max) {
+        int curbus = pci_bdf_to_bus(bdf);
+        if (curbus == lastbus)
+            continue;
+        lastbus = curbus;
+        memset(bus, 0, sizeof(*bus));
+        bus->type = MPT_TYPE_BUS;
+        bus->busid = curbus;
+        memcpy(bus->bustype, "PCI   ", sizeof(bus->bustype));
+        bus++;
+    }
+
+    /* isa bus */
+    int isabusid;
+    memset(bus, 0, sizeof(*bus));
+    bus->type = MPT_TYPE_BUS;
+    isabusid = bus->busid = lastbus + 1;
+    memcpy(bus->bustype, "ISA   ", sizeof(bus->bustype));
+    bus++;
+    entrycount += bus - buses;
+
+    /* ioapic */
+    u8 ioapic_id = CountCPUs;
+    struct mpt_ioapic *ioapic = (void*)bus;
+    memset(ioapic, 0, sizeof(*ioapic));
+    ioapic->type = MPT_TYPE_IOAPIC;
+    ioapic->apicid = ioapic_id;
+    ioapic->apicver = 0x11;
+    ioapic->flags = 1; // enable
+    ioapic->apicaddr = BUILD_IOAPIC_ADDR;
+    entrycount++;
+
+    /* irqs */
+    struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs;
+    int dev = -1;
+    unsigned short mask = 0, pinmask = 0;
+
+    foreachpci(bdf, max) {
+        int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+        int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+        if (pin == 0)
+            continue;
+        if (dev != pci_bdf_to_busdev(bdf)) {
+            dev = pci_bdf_to_busdev(bdf);
+            pinmask = 0;
+        }
+        if (pinmask & (1 << pin)) /* pin was seen already */
+            continue;
+        pinmask |= (1 << pin);
+        mask |= (1 << irq);
+        memset(intsrc, 0, sizeof(*intsrc));
+        intsrc->type = MPT_TYPE_INTSRC;
+        intsrc->irqtype = 0; /* INT */
+        intsrc->irqflag = 1; /* active high */
+        intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
+        intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
+        intsrc->dstapic = ioapic_id;
+        intsrc->dstirq = irq;
+        intsrc++;
+    }
+
+    for (i = 0; i < 16; i++) {
+        memset(intsrc, 0, sizeof(*intsrc));
+        if (mask & (1 << i))
+            continue;
+        intsrc->type = MPT_TYPE_INTSRC;
+        intsrc->irqtype = 0; /* INT */
+        intsrc->irqflag = 0; /* conform to bus spec */
+        intsrc->srcbus = isabusid; /* ISA bus */
+        intsrc->srcbusirq = i;
+        intsrc->dstapic = ioapic_id;
+        intsrc->dstirq = i;
+        if (qemu_cfg_irq0_override()) {
+            /* Destination 2 is covered by irq0->inti2 override (i ==
+               0). Source IRQ 2 is unused */
+            if (i == 0)
+                intsrc->dstirq = 2;
+            else if (i == 2)
+                intsrc--;
+        }
+        intsrc++;
+    }
+
+    /* Local interrupt assignment */
+    intsrc->type = MPT_TYPE_LOCAL_INT;
+    intsrc->irqtype = 3; /* ExtINT */
+    intsrc->irqflag = 0; /* PO, EL default */
+    intsrc->srcbus = isabusid; /* ISA */
+    intsrc->srcbusirq = 0;
+    intsrc->dstapic = 0; /* BSP == APIC #0 */
+    intsrc->dstirq = 0; /* LINTIN0 */
+    intsrc++;
+
+    intsrc->type = MPT_TYPE_LOCAL_INT;
+    intsrc->irqtype = 1; /* NMI */
+    intsrc->irqflag = 0; /* PO, EL default */
+    intsrc->srcbus = isabusid; /* ISA */
+    intsrc->srcbusirq = 0;
+    intsrc->dstapic = 0; /* BSP == APIC #0 */
+    intsrc->dstirq = 1; /* LINTIN1 */
+    intsrc++;
+    entrycount += intsrc - intsrcs;
+
+    // Finalize config structure.
+    int length = (void*)intsrc - (void*)config;
+    config->entrycount = entrycount;
+    config->length = length;
+    config->checksum -= checksum(config, length);
+
+    // Allocate final memory locations.  (In theory the config
+    // structure can go in high memory, but Linux kernels before
+    // v2.6.30 crash with that.)
+    struct mptable_config_s *finalconfig = malloc_fseg(length);
+    struct mptable_floating_s *floating = malloc_fseg(sizeof(*floating));
+    if (!finalconfig || !floating) {
+        warn_noalloc();
+        free(config);
+        free(finalconfig);
+        free(floating);
+        return;
+    }
+    memcpy(finalconfig, config, length);
+    free(config);
+
+    /* floating pointer structure */
+    memset(floating, 0, sizeof(*floating));
+    floating->signature = MPTABLE_SIGNATURE;
+    floating->physaddr = (u32)finalconfig;
+    floating->length = 1;
+    floating->spec_rev = 4;
+    floating->checksum -= checksum(floating, sizeof(*floating));
+
+    dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n",
+            floating, finalconfig, length);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/mptable.h b/qemu-0.15.x/roms/seabios/src/mptable.h
new file mode 100644
index 0000000..c4e3c51
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/mptable.h
@@ -0,0 +1,80 @@
+#ifndef __MPTABLE_H
+#define __MPTABLE_H
+
+#include "types.h" // u32
+
+#define MPTABLE_SIGNATURE 0x5f504d5f  // "_MP_"
+
+struct mptable_floating_s {
+    u32 signature;
+    u32 physaddr;
+    u8 length;
+    u8 spec_rev;
+    u8 checksum;
+    u8 feature1;
+    u8 feature2;
+    u8 reserved[3];
+};
+
+#define MPCONFIG_SIGNATURE 0x504d4350  // "PCMP"
+
+struct mptable_config_s {
+    u32 signature;
+    u16 length;
+    u8 spec;
+    u8 checksum;
+    char oemid[8];
+    char productid[12];
+    u32 oemptr;
+    u16 oemsize;
+    u16 entrycount;
+    u32 lapic;
+    u16 exttable_length;
+    u8 exttable_checksum;
+    u8 reserved;
+} PACKED;
+
+#define MPT_TYPE_CPU 0
+#define MPT_TYPE_BUS 1
+#define MPT_TYPE_IOAPIC 2
+#define MPT_TYPE_INTSRC 3
+#define MPT_TYPE_LOCAL_INT 4
+
+struct mpt_cpu {
+    u8 type;
+    u8 apicid;
+    u8 apicver;
+    u8 cpuflag;
+    u32 cpusignature;
+    u32 featureflag;
+    u32 reserved[2];
+} PACKED;
+
+struct mpt_bus {
+    u8 type;
+    u8 busid;
+    char bustype[6];
+} PACKED;
+
+struct mpt_ioapic {
+    u8 type;
+    u8 apicid;
+    u8 apicver;
+    u8 flags;
+    u32 apicaddr;
+} PACKED;
+
+struct mpt_intsrc {
+    u8 type;
+    u8 irqtype;
+    u16 irqflag;
+    u8 srcbus;
+    u8 srcbusirq;
+    u8 dstapic;
+    u8 dstirq;
+} PACKED;
+
+// mptable.c
+void mptable_init(void);
+
+#endif // mptable.h
diff --git a/qemu-0.15.x/roms/seabios/src/mtrr.c b/qemu-0.15.x/roms/seabios/src/mtrr.c
new file mode 100644
index 0000000..0502c18
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/mtrr.c
@@ -0,0 +1,102 @@
+// Initialize MTRRs - mostly useful on KVM.
+//
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+
+#define MSR_MTRRcap                    0x000000fe
+#define MSR_MTRRfix64K_00000           0x00000250
+#define MSR_MTRRfix16K_80000           0x00000258
+#define MSR_MTRRfix16K_A0000           0x00000259
+#define MSR_MTRRfix4K_C0000            0x00000268
+#define MSR_MTRRfix4K_C8000            0x00000269
+#define MSR_MTRRfix4K_D0000            0x0000026a
+#define MSR_MTRRfix4K_D8000            0x0000026b
+#define MSR_MTRRfix4K_E0000            0x0000026c
+#define MSR_MTRRfix4K_E8000            0x0000026d
+#define MSR_MTRRfix4K_F0000            0x0000026e
+#define MSR_MTRRfix4K_F8000            0x0000026f
+#define MSR_MTRRdefType                0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MTRR_MEMTYPE_UC 0
+#define MTRR_MEMTYPE_WC 1
+#define MTRR_MEMTYPE_WT 4
+#define MTRR_MEMTYPE_WP 5
+#define MTRR_MEMTYPE_WB 6
+
+void mtrr_setup(void)
+{
+    if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT)
+        return;
+
+    u32 eax, ebx, ecx, edx, cpuid_features;
+    cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+    if (!(cpuid_features & CPUID_MTRR))
+        return;
+    if (!(cpuid_features & CPUID_MSR))
+        return;
+
+    dprintf(3, "init mtrr\n");
+
+    u32 mtrr_cap = rdmsr(MSR_MTRRcap);
+    int vcnt = mtrr_cap & 0xff;
+    int fix = mtrr_cap & 0x100;
+    if (!vcnt || !fix)
+       return;
+
+    // Disable MTRRs
+    wrmsr_smp(MSR_MTRRdefType, 0);
+
+    // Set fixed MTRRs
+    union u64b {
+        u8 valb[8];
+        u64 val;
+    } u;
+    u.val = 0;
+    int i;
+    for (i = 0; i < 8; i++)
+        if (RamSize >= 65536 * (i + 1))
+            u.valb[i] = MTRR_MEMTYPE_WB;
+    wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+    u.val = 0;
+    for (i = 0; i < 8; i++)
+        if (RamSize >= 0x80000 + 16384 * (i + 1))
+            u.valb[i] = MTRR_MEMTYPE_WB;
+    wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+    wrmsr_smp(MSR_MTRRfix16K_A0000, 0);   // 0xA0000-0xC0000 is uncached
+    int j;
+    for (j = 0; j < 8; j++) {
+        u.val = 0;
+        for (i = 0; i < 8; i++)
+            if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
+                u.valb[i] = MTRR_MEMTYPE_WP;
+        wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
+    }
+
+    // Set variable MTRRs
+    int phys_bits = 36;
+    cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
+    if (eax >= 0x80000008) {
+            /* Get physical bits from leaf 0x80000008 (if available) */
+            cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
+            phys_bits = eax & 0xff;
+    }
+    u64 phys_mask = ((1ull << phys_bits) - 1);
+    for (i=0; i<vcnt; i++) {
+        wrmsr_smp(MTRRphysBase_MSR(i), 0);
+        wrmsr_smp(MTRRphysMask_MSR(i), 0);
+    }
+    /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+    wrmsr_smp(MTRRphysBase_MSR(0), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
+    wrmsr_smp(MTRRphysMask_MSR(0)
+              , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
+
+    // Enable fixed and variable MTRRs; set default type.
+    wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/optionroms.c b/qemu-0.15.x/roms/seabios/src/optionroms.c
new file mode 100644
index 0000000..37a4e6c
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/optionroms.c
@@ -0,0 +1,495 @@
+// Option rom scanning code.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "pci_regs.h" // PCI_ROM_ADDRESS
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+#include "boot.h" // IPL
+#include "paravirt.h" // qemu_cfg_*
+
+
+/****************************************************************
+ * Definitions
+ ****************************************************************/
+
+struct rom_header {
+    u16 signature;
+    u8 size;
+    u8 initVector[4];
+    u8 reserved[17];
+    u16 pcioffset;
+    u16 pnpoffset;
+} PACKED;
+
+struct pci_data {
+    u32 signature;
+    u16 vendor;
+    u16 device;
+    u16 vitaldata;
+    u16 dlen;
+    u8 drevision;
+    u8 class_lo;
+    u16 class_hi;
+    u16 ilen;
+    u16 irevision;
+    u8 type;
+    u8 indicator;
+    u16 reserved;
+} PACKED;
+
+struct pnp_data {
+    u32 signature;
+    u8 revision;
+    u8 len;
+    u16 nextoffset;
+    u8 reserved_08;
+    u8 checksum;
+    u32 devid;
+    u16 manufacturer;
+    u16 productname;
+    u8 type_lo;
+    u16 type_hi;
+    u8 dev_flags;
+    u16 bcv;
+    u16 dv;
+    u16 bev;
+    u16 reserved_1c;
+    u16 staticresource;
+} PACKED;
+
+#define OPTION_ROM_SIGNATURE 0xaa55
+#define OPTION_ROM_ALIGN 2048
+#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0])
+#define PCI_ROM_SIGNATURE 0x52494350 // PCIR
+#define PCIROM_CODETYPE_X86 0
+
+// The end of the last deployed rom.
+u32 RomEnd = BUILD_ROM_START;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Execute a given option rom.
+static void
+__callrom(struct rom_header *rom, u16 offset, u16 bdf)
+{
+    u16 seg = FLATPTR_TO_SEG(rom);
+    dprintf(1, "Running option rom at %04x:%04x\n", seg, offset);
+
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    br.ax = bdf;
+    br.bx = 0xffff;
+    br.dx = 0xffff;
+    br.es = SEG_BIOS;
+    br.di = get_pnp_offset();
+    br.code = SEGOFF(seg, offset);
+    start_preempt();
+    call16big(&br);
+    finish_preempt();
+
+    debug_serial_setup();
+}
+
+// Execute a given option rom at the standard entry vector.
+static void
+callrom(struct rom_header *rom, u16 bdf)
+{
+    __callrom(rom, OPTION_ROM_INITVECTOR, bdf);
+}
+
+// Execute a BCV option rom registered via add_bcv().
+void
+call_bcv(u16 seg, u16 ip)
+{
+    __callrom(MAKE_FLATPTR(seg, 0), ip, 0);
+}
+
+// Verify that an option rom looks valid
+static int
+is_valid_rom(struct rom_header *rom)
+{
+    dprintf(6, "Checking rom %p (sig %x size %d)\n"
+            , rom, rom->signature, rom->size);
+    if (rom->signature != OPTION_ROM_SIGNATURE)
+        return 0;
+    if (! rom->size)
+        return 0;
+    u32 len = rom->size * 512;
+    u8 sum = checksum(rom, len);
+    if (sum != 0) {
+        dprintf(1, "Found option rom with bad checksum: loc=%p len=%d sum=%x\n"
+                , rom, len, sum);
+        if (CONFIG_OPTIONROMS_CHECKSUM)
+            return 0;
+    }
+    return 1;
+}
+
+// Check if a valid option rom has a pnp struct; return it if so.
+static struct pnp_data *
+get_pnp_rom(struct rom_header *rom)
+{
+    struct pnp_data *pnp = (void*)((u8*)rom + rom->pnpoffset);
+    if (pnp->signature != PNP_SIGNATURE)
+        return NULL;
+    return pnp;
+}
+
+// Check for multiple pnp option rom headers.
+static struct pnp_data *
+get_pnp_next(struct rom_header *rom, struct pnp_data *pnp)
+{
+    if (! pnp->nextoffset)
+        return NULL;
+    pnp = (void*)((u8*)rom + pnp->nextoffset);
+    if (pnp->signature != PNP_SIGNATURE)
+        return NULL;
+    return pnp;
+}
+
+// Check if a valid option rom has a pci struct; return it if so.
+static struct pci_data *
+get_pci_rom(struct rom_header *rom)
+{
+    struct pci_data *pci = (void*)((u32)rom + rom->pcioffset);
+    if (pci->signature != PCI_ROM_SIGNATURE)
+        return NULL;
+    return pci;
+}
+
+// Return start of code in 0xc0000-0xf0000 space.
+static inline u32 _max_rom(void) {
+    extern u8 code32flat_start[], code32init_end[];
+    return CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start;
+}
+// Return the memory position up to which roms may be located.
+static inline u32 max_rom(void) {
+    u32 end = _max_rom();
+    return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end;
+}
+
+// Copy a rom to its permanent location below 1MiB
+static struct rom_header *
+copy_rom(struct rom_header *rom)
+{
+    u32 romsize = rom->size * 512;
+    if (RomEnd + romsize > max_rom()) {
+        // Option rom doesn't fit.
+        warn_noalloc();
+        return NULL;
+    }
+    dprintf(4, "Copying option rom (size %d) from %p to %x\n"
+            , romsize, rom, RomEnd);
+    iomemcpy((void*)RomEnd, rom, romsize);
+    return (void*)RomEnd;
+}
+
+// Run rom init code and note rom size.
+static int
+init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
+{
+    if (! is_valid_rom(rom))
+        return -1;
+
+    if (isvga || get_pnp_rom(rom))
+        // Only init vga and PnP roms here.
+        callrom(rom, bdf);
+
+    RomEnd = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+
+    return 0;
+}
+
+#define RS_PCIROM (1LL<<33)
+
+static void
+setRomSource(u64 *sources, struct rom_header *rom, u64 source)
+{
+    if (sources)
+        sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN] = source;
+}
+
+static int
+getRomPriority(u64 *sources, struct rom_header *rom, int instance)
+{
+    u64 source = sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+    if (!source)
+        return -1;
+    if (source & RS_PCIROM)
+        return bootprio_find_pci_rom(source, instance);
+    return bootprio_find_named_rom(romfile_name(source), instance);
+}
+
+/****************************************************************
+ * Roms in CBFS
+ ****************************************************************/
+
+// Check if an option rom is at a hardcoded location or in CBFS.
+static struct rom_header *
+lookup_hardcode(u32 vendev)
+{
+    if (OPTIONROM_VENDEV_1
+        && ((OPTIONROM_VENDEV_1 >> 16)
+            | ((OPTIONROM_VENDEV_1 & 0xffff)) << 16) == vendev)
+        return copy_rom((void*)OPTIONROM_MEM_1);
+    if (OPTIONROM_VENDEV_2
+        && ((OPTIONROM_VENDEV_2 >> 16)
+            | ((OPTIONROM_VENDEV_2 & 0xffff)) << 16) == vendev)
+        return copy_rom((void*)OPTIONROM_MEM_2);
+    char fname[17];
+    snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
+             , pci_vd_to_ven(vendev), pci_vd_to_dev(vendev));
+    int ret = romfile_copy(romfile_find(fname), (void*)RomEnd
+                           , max_rom() - RomEnd);
+    if (ret <= 0)
+        return NULL;
+    return (void*)RomEnd;
+}
+
+// Run all roms in a given CBFS directory.
+static void
+run_file_roms(const char *prefix, int isvga, u64 *sources)
+{
+    u32 file = 0;
+    for (;;) {
+        file = romfile_findprefix(prefix, file);
+        if (!file)
+            break;
+        struct rom_header *rom = (void*)RomEnd;
+        int ret = romfile_copy(file, rom, max_rom() - RomEnd);
+        if (ret > 0) {
+            setRomSource(sources, rom, file);
+            init_optionrom(rom, 0, isvga);
+        }
+    }
+}
+
+
+/****************************************************************
+ * PCI roms
+ ****************************************************************/
+
+// Map the option rom of a given PCI device.
+static struct rom_header *
+map_pcirom(u16 bdf, u32 vendev)
+{
+    dprintf(6, "Attempting to map option rom on dev %02x:%02x.%x\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+
+    u8 htype = pci_config_readb(bdf, PCI_HEADER_TYPE);
+    if ((htype & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
+        dprintf(6, "Skipping non-normal pci device (type=%x)\n", htype);
+        return NULL;
+    }
+
+    u32 orig = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+    pci_config_writel(bdf, PCI_ROM_ADDRESS, ~PCI_ROM_ADDRESS_ENABLE);
+    u32 sz = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+
+    dprintf(6, "Option rom sizing returned %x %x\n", orig, sz);
+    orig &= ~PCI_ROM_ADDRESS_ENABLE;
+    if (!sz || sz == 0xffffffff)
+        goto fail;
+
+    if (orig == sz || (u32)(orig + 4*1024*1024) < 20*1024*1024) {
+        // Don't try to map to a pci addresses at its max, in the last
+        // 4MiB of ram, or the first 16MiB of ram.
+        dprintf(6, "Preset rom address doesn't look valid\n");
+        goto fail;
+    }
+
+    // Looks like a rom - enable it.
+    pci_config_writel(bdf, PCI_ROM_ADDRESS, orig | PCI_ROM_ADDRESS_ENABLE);
+
+    struct rom_header *rom = (void*)orig;
+    for (;;) {
+        dprintf(5, "Inspecting possible rom at %p (vd=%04x:%04x"
+                " bdf=%02x:%02x.%x)\n"
+                , rom, pci_vd_to_ven(vendev), pci_vd_to_dev(vendev)
+                , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+        if (rom->signature != OPTION_ROM_SIGNATURE) {
+            dprintf(6, "No option rom signature (got %x)\n", rom->signature);
+            goto fail;
+        }
+        struct pci_data *pci = get_pci_rom(rom);
+        if (! pci) {
+            dprintf(6, "No valid pci signature found\n");
+            goto fail;
+        }
+
+        u32 vd = pci_vd(pci->vendor, pci->device);
+        if (vd == vendev && pci->type == PCIROM_CODETYPE_X86)
+            // A match
+            break;
+        dprintf(6, "Didn't match dev/ven (got %08x) or type (got %d)\n"
+                , vd, pci->type);
+        if (pci->indicator & 0x80) {
+            dprintf(6, "No more images left\n");
+            goto fail;
+        }
+        rom = (void*)((u32)rom + pci->ilen * 512);
+    }
+
+    rom = copy_rom(rom);
+    pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+    return rom;
+fail:
+    // Not valid - restore original and exit.
+    pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+    return NULL;
+}
+
+// Attempt to map and initialize the option rom on a given PCI device.
+static int
+init_pcirom(u16 bdf, int isvga, u64 *sources)
+{
+    u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+    dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
+            , pci_vd_to_ven(vendev), pci_vd_to_dev(vendev));
+    struct rom_header *rom = lookup_hardcode(vendev);
+    if (! rom)
+        rom = map_pcirom(bdf, vendev);
+    if (! rom)
+        // No ROM present.
+        return -1;
+    setRomSource(sources, rom, RS_PCIROM | bdf);
+    return init_optionrom(rom, bdf, isvga);
+}
+
+
+/****************************************************************
+ * Non-VGA option rom init
+ ****************************************************************/
+
+void
+optionrom_setup(void)
+{
+    if (! CONFIG_OPTIONROMS)
+        return;
+
+    dprintf(1, "Scan for option roms\n");
+    u64 sources[(BUILD_BIOS_ADDR - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+    memset(sources, 0, sizeof(sources));
+    u32 post_vga = RomEnd;
+
+    if (CONFIG_OPTIONROMS_DEPLOYED) {
+        // Option roms are already deployed on the system.
+        u32 pos = RomEnd;
+        while (pos < max_rom()) {
+            int ret = init_optionrom((void*)pos, 0, 0);
+            if (ret)
+                pos += OPTION_ROM_ALIGN;
+            else
+                pos = RomEnd;
+        }
+    } else {
+        // Find and deploy PCI roms.
+        int bdf, max;
+        foreachpci(bdf, max) {
+            u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+            if (v == 0x0000 || v == 0xffff || v == PCI_CLASS_DISPLAY_VGA
+                || (CONFIG_ATA && v == PCI_CLASS_STORAGE_IDE))
+                continue;
+            init_pcirom(bdf, 0, sources);
+        }
+
+        // Find and deploy CBFS roms not associated with a device.
+        run_file_roms("genroms/", 0, sources);
+    }
+
+    // All option roms found and deployed - now build BEV/BCV vectors.
+
+    u32 pos = post_vga;
+    while (pos < RomEnd) {
+        struct rom_header *rom = (void*)pos;
+        if (! is_valid_rom(rom)) {
+            pos += OPTION_ROM_ALIGN;
+            continue;
+        }
+        pos += ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+        struct pnp_data *pnp = get_pnp_rom(rom);
+        if (! pnp) {
+            // Legacy rom.
+            boot_add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0
+                         , getRomPriority(sources, rom, 0));
+            continue;
+        }
+        // PnP rom.
+        if (pnp->bev) {
+            // Can boot system - add to IPL list.
+            boot_add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname
+                         , getRomPriority(sources, rom, 0));
+        } else {
+            // Check for BCV (there may be multiple).
+            int instance = 0;
+            while (pnp && pnp->bcv) {
+                boot_add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname
+                             , getRomPriority(sources, rom, instance++));
+                pnp = get_pnp_next(rom, pnp);
+            }
+        }
+    }
+}
+
+
+/****************************************************************
+ * VGA init
+ ****************************************************************/
+
+// Call into vga code to turn on console.
+void
+vga_setup(void)
+{
+    if (! CONFIG_OPTIONROMS)
+        return;
+
+    dprintf(1, "Scan for VGA option rom\n");
+
+    if (CONFIG_OPTIONROMS_DEPLOYED) {
+        // Option roms are already deployed on the system.
+        init_optionrom((void*)BUILD_ROM_START, 0, 1);
+    } else {
+        // Clear option rom memory
+        memset((void*)RomEnd, 0, _max_rom() - RomEnd);
+
+        // Find and deploy PCI VGA rom.
+        int bdf = VGAbdf = pci_find_vga();
+        if (bdf >= 0)
+            init_pcirom(bdf, 1, NULL);
+
+        // Find and deploy CBFS vga-style roms not associated with a device.
+        run_file_roms("vgaroms/", 1, NULL);
+    }
+
+    if (RomEnd == BUILD_ROM_START) {
+        // No VGA rom found
+        RomEnd += OPTION_ROM_ALIGN;
+        return;
+    }
+
+    enable_vga_console();
+}
+
+void
+s3_resume_vga_init(void)
+{
+    if (!CONFIG_S3_RESUME_VGA_INIT)
+        return;
+    struct rom_header *rom = (void*)BUILD_ROM_START;
+    if (! is_valid_rom(rom))
+        return;
+    callrom(rom, 0);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/output.c b/qemu-0.15.x/roms/seabios/src/output.c
new file mode 100644
index 0000000..4c9f95b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/output.c
@@ -0,0 +1,582 @@
+// Raw screen writing and debug output code.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include <stdarg.h> // va_list
+
+#include "farptr.h" // GET_VAR
+#include "util.h" // printf
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+struct putcinfo {
+    void (*func)(struct putcinfo *info, char c);
+};
+
+
+/****************************************************************
+ * Debug output
+ ****************************************************************/
+
+#define DEBUG_PORT PORT_SERIAL1
+#define DEBUG_TIMEOUT 100000
+
+void
+debug_serial_setup(void)
+{
+    if (!CONFIG_DEBUG_SERIAL)
+        return;
+    // setup for serial logging: 8N1
+    u8 oldparam, newparam = 0x03;
+    oldparam = inb(DEBUG_PORT+SEROFF_LCR);
+    outb(newparam, DEBUG_PORT+SEROFF_LCR);
+    // Disable irqs
+    u8 oldier, newier = 0;
+    oldier = inb(DEBUG_PORT+SEROFF_IER);
+    outb(newier, DEBUG_PORT+SEROFF_IER);
+
+    if (oldparam != newparam || oldier != newier)
+        dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
+                , oldparam, oldier, newparam, newier);
+}
+
+// Write a character to the serial port.
+static void
+debug_serial(char c)
+{
+    if (!CONFIG_DEBUG_SERIAL)
+        return;
+    int timeout = DEBUG_TIMEOUT;
+    while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
+        if (!timeout--)
+            // Ran out of time.
+            return;
+    outb(c, DEBUG_PORT+SEROFF_DATA);
+}
+
+// Make sure all serial port writes have been completely sent.
+static void
+debug_serial_flush(void)
+{
+    if (!CONFIG_DEBUG_SERIAL)
+        return;
+    int timeout = DEBUG_TIMEOUT;
+    while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
+        if (!timeout--)
+            // Ran out of time.
+            return;
+}
+
+// Write a character to debug port(s).
+static void
+putc_debug(struct putcinfo *action, char c)
+{
+    if (! CONFIG_DEBUG_LEVEL)
+        return;
+    if (! CONFIG_COREBOOT)
+        // Send character to debug port.
+        outb(c, PORT_BIOS_DEBUG);
+    if (c == '\n')
+        debug_serial('\r');
+    debug_serial(c);
+}
+
+// In segmented mode just need a dummy variable (putc_debug is always
+// used anyway), and in 32bit flat mode need a pointer to the 32bit
+// instance of putc_debug().
+#if MODE16
+static struct putcinfo debuginfo VAR16;
+#elif MODESEGMENT
+static struct putcinfo debuginfo VAR32SEG;
+#else
+static struct putcinfo debuginfo = { putc_debug };
+#endif
+
+
+/****************************************************************
+ * Screen writing
+ ****************************************************************/
+
+// Show a character on the screen.
+static void
+screenc(char c)
+{
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    br.ah = 0x0e;
+    br.al = c;
+    call16_int(0x10, &br);
+}
+
+// Handle a character from a printf request.
+static void
+putc_screen(struct putcinfo *action, char c)
+{
+    if (CONFIG_SCREEN_AND_DEBUG)
+        putc_debug(&debuginfo, c);
+    if (c == '\n')
+        screenc('\r');
+    screenc(c);
+}
+
+static struct putcinfo screeninfo = { putc_screen };
+
+
+/****************************************************************
+ * Xprintf code
+ ****************************************************************/
+
+// Output a character.
+static void
+putc(struct putcinfo *action, char c)
+{
+    if (MODESEGMENT) {
+        // Only debugging output supported in segmented mode.
+        putc_debug(action, c);
+        return;
+    }
+
+    void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
+    func(action, c);
+}
+
+// Ouptut a string.
+static void
+puts(struct putcinfo *action, const char *s)
+{
+    if (!MODESEGMENT && !s)
+        s = "(NULL)";
+    for (; *s; s++)
+        putc(action, *s);
+}
+
+// Output a string that is in the CS segment.
+static void
+puts_cs(struct putcinfo *action, const char *s)
+{
+    char *vs = (char*)s;
+    for (;; vs++) {
+        char c = GET_GLOBAL(*vs);
+        if (!c)
+            break;
+        putc(action, c);
+    }
+}
+
+// Output an unsigned integer.
+static void
+putuint(struct putcinfo *action, u32 val)
+{
+    char buf[12];
+    char *d = &buf[sizeof(buf) - 1];
+    *d-- = '\0';
+    for (;;) {
+        *d = (val % 10) + '0';
+        val /= 10;
+        if (!val)
+            break;
+        d--;
+    }
+    puts(action, d);
+}
+
+// Output a single digit hex character.
+static inline void
+putsinglehex(struct putcinfo *action, u32 val)
+{
+    if (val <= 9)
+        val = '0' + val;
+    else
+        val = 'a' + val - 10;
+    putc(action, val);
+}
+
+// Output an integer in hexadecimal.
+static void
+puthex(struct putcinfo *action, u32 val, int width, int spacepad)
+{
+    if (!width) {
+        u32 tmp = val;
+        width = 1;
+        while (tmp >>= 4)
+            width++;
+    } else if (spacepad)  {
+        u32 tmp = val;
+        u32 count = 1;
+        while (tmp >>= 4)
+            count++;
+        if (width > count) {
+            count = width - count;
+            width -= count;
+            while (count--)
+                putc(action, ' ');
+        }
+    }
+
+    switch (width) {
+    default: putsinglehex(action, (val >> 28) & 0xf);
+    case 7:  putsinglehex(action, (val >> 24) & 0xf);
+    case 6:  putsinglehex(action, (val >> 20) & 0xf);
+    case 5:  putsinglehex(action, (val >> 16) & 0xf);
+    case 4:  putsinglehex(action, (val >> 12) & 0xf);
+    case 3:  putsinglehex(action, (val >> 8) & 0xf);
+    case 2:  putsinglehex(action, (val >> 4) & 0xf);
+    case 1:  putsinglehex(action, (val >> 0) & 0xf);
+    }
+}
+
+static inline int
+isdigit(u8 c)
+{
+    return ((u8)(c - '0')) < 10;
+}
+
+static void
+bvprintf(struct putcinfo *action, const char *fmt, va_list args)
+{
+    const char *s = fmt;
+    for (;; s++) {
+        char c = GET_GLOBAL(*(u8*)s);
+        if (!c)
+            break;
+        if (c != '%') {
+            putc(action, c);
+            continue;
+        }
+        const char *n = s+1;
+        int field_width = 0;
+        int spacepad = 1;
+        for (;;) {
+            c = GET_GLOBAL(*(u8*)n);
+            if (!isdigit(c))
+                break;
+            if (!field_width && (c == '0'))
+                spacepad = 0;
+            else
+                field_width = field_width * 10 + c - '0';
+            n++;
+        }
+        if (c == 'l') {
+            // Ignore long format indicator
+            n++;
+            c = GET_GLOBAL(*(u8*)n);
+        }
+        s32 val;
+        const char *sarg;
+        switch (c) {
+        case '%':
+            putc(action, '%');
+            break;
+        case 'd':
+            val = va_arg(args, s32);
+            if (val < 0) {
+                putc(action, '-');
+                val = -val;
+            }
+            putuint(action, val);
+            break;
+        case 'u':
+            val = va_arg(args, s32);
+            putuint(action, val);
+            break;
+        case 'p':
+            /* %p always has 0x prepended */
+            putc(action, '0');
+            putc(action, 'x');
+            field_width = 8;
+            spacepad = 0;
+        case 'x':
+            val = va_arg(args, s32);
+            puthex(action, val, field_width, spacepad);
+            break;
+        case 'c':
+            val = va_arg(args, int);
+            putc(action, val);
+            break;
+        case '.':
+            // Hack to support "%.s" - meaning string on stack.
+            if (GET_GLOBAL(*(u8*)(n+1)) != 's')
+                break;
+            n++;
+            sarg = va_arg(args, const char *);
+            puts(action, sarg);
+            break;
+        case 's':
+            sarg = va_arg(args, const char *);
+            puts_cs(action, sarg);
+            break;
+        default:
+            putc(action, '%');
+            n = s;
+        }
+        s = n;
+    }
+}
+
+void
+panic(const char *fmt, ...)
+{
+    if (CONFIG_DEBUG_LEVEL) {
+        va_list args;
+        va_start(args, fmt);
+        bvprintf(&debuginfo, fmt, args);
+        va_end(args);
+        debug_serial_flush();
+    }
+
+    // XXX - use PANIC PORT.
+    irq_disable();
+    for (;;)
+        hlt();
+}
+
+void
+__dprintf(const char *fmt, ...)
+{
+    if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
+        && *fmt != '\\' && *fmt != '/') {
+        struct thread_info *cur = getCurThread();
+        if (cur != &MainThread) {
+            // Show "thread id" for this debug message.
+            putc_debug(&debuginfo, '|');
+            puthex(&debuginfo, (u32)cur, 8, 0);
+            putc_debug(&debuginfo, '|');
+            putc_debug(&debuginfo, ' ');
+        }
+    }
+
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&debuginfo, fmt, args);
+    va_end(args);
+    debug_serial_flush();
+}
+
+void
+printf(const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&screeninfo, fmt, args);
+    va_end(args);
+    if (CONFIG_SCREEN_AND_DEBUG)
+        debug_serial_flush();
+}
+
+
+/****************************************************************
+ * snprintf
+ ****************************************************************/
+
+struct snprintfinfo {
+    struct putcinfo info;
+    char *str, *end;
+};
+
+static void
+putc_str(struct putcinfo *info, char c)
+{
+    struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
+    if (sinfo->str >= sinfo->end)
+        return;
+    *sinfo->str = c;
+    sinfo->str++;
+}
+
+// Build a formatted string.  Note, this function returns the actual
+// number of bytes used (not including null) even in the overflow
+// case.
+int
+snprintf(char *str, size_t size, const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    if (!size)
+        return 0;
+    struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&sinfo.info, fmt, args);
+    va_end(args);
+    char *end = sinfo.str;
+    if (end >= sinfo.end)
+        end = sinfo.end - 1;
+    *end = '\0';
+    return end - str;
+}
+
+// Build a formatted string - malloc'ing the memory.
+char *
+znprintf(size_t size, const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    if (!size)
+        return NULL;
+    char *str = malloc_tmp(size);
+    if (!str) {
+        warn_noalloc();
+        return NULL;
+    }
+    struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&sinfo.info, fmt, args);
+    va_end(args);
+    char *end = sinfo.str;
+    if (end >= sinfo.end)
+        end = sinfo.end - 1;
+    *end = '\0';
+    return str;
+}
+
+
+/****************************************************************
+ * Misc helpers
+ ****************************************************************/
+
+void
+hexdump(const void *d, int len)
+{
+    int count=0;
+    while (len > 0) {
+        if (count % 8 == 0) {
+            putc(&debuginfo, '\n');
+            puthex(&debuginfo, count*4, 8, 0);
+            putc(&debuginfo, ':');
+        } else {
+            putc(&debuginfo, ' ');
+        }
+        puthex(&debuginfo, *(u32*)d, 8, 0);
+        count++;
+        len-=4;
+        d+=4;
+    }
+    putc(&debuginfo, '\n');
+    debug_serial_flush();
+}
+
+static void
+dump_regs(struct bregs *regs)
+{
+    if (!regs) {
+        dprintf(1, "  NULL\n");
+        return;
+    }
+    dprintf(1, "   a=%08x  b=%08x  c=%08x  d=%08x ds=%04x es=%04x ss=%04x\n"
+            , regs->eax, regs->ebx, regs->ecx, regs->edx
+            , regs->ds, regs->es, GET_SEG(SS));
+    dprintf(1, "  si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x  f=%04x\n"
+            , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
+            , regs->code.seg, regs->code.offset, regs->flags);
+}
+
+// Report entry to an Interrupt Service Routine (ISR).
+void
+__debug_isr(const char *fname)
+{
+    puts_cs(&debuginfo, fname);
+    putc(&debuginfo, '\n');
+    debug_serial_flush();
+}
+
+// Function called on handler startup.
+void
+__debug_enter(struct bregs *regs, const char *fname)
+{
+    dprintf(1, "enter %s:\n", fname);
+    dump_regs(regs);
+}
+
+// Send debugging output info.
+void
+__debug_stub(struct bregs *regs, int lineno, const char *fname)
+{
+    dprintf(1, "stub %s:%d:\n", fname, lineno);
+    dump_regs(regs);
+}
+
+// Report on an invalid parameter.
+void
+__warn_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+    if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
+        dprintf(1, "invalid %s:%d:\n", fname, lineno);
+        dump_regs(regs);
+    }
+}
+
+// Report on an unimplemented feature.
+void
+__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+    if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
+        dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
+        dump_regs(regs);
+    }
+}
+
+// Report a detected internal inconsistency.
+void
+__warn_internalerror(int lineno, const char *fname)
+{
+    dprintf(1, "WARNING - internal error detected at %s:%d!\n"
+            , fname, lineno);
+}
+
+// Report on an allocation failure.
+void
+__warn_noalloc(int lineno, const char *fname)
+{
+    dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
+            , fname, lineno);
+}
+
+// Report on a timeout exceeded.
+void
+__warn_timeout(int lineno, const char *fname)
+{
+    dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
+}
+
+// Report a handler reporting an invalid parameter to the caller.
+void
+__set_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+    __warn_invalid(regs, lineno, fname);
+    set_invalid_silent(regs);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+    __warn_unimplemented(regs, lineno, fname);
+    set_invalid_silent(regs);
+}
+
+// Report a handler reporting an invalid parameter code to the
+// caller.  Note, the lineno and return code are encoded in the same
+// parameter as gcc does a better job of scheduling function calls
+// when there are 3 or less parameters.
+void
+__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
+{
+    u8 code = linecode;
+    u32 lineno = linecode >> 8;
+    __warn_invalid(regs, lineno, fname);
+    set_code_invalid_silent(regs, code);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+    u8 code = linecode;
+    u32 lineno = linecode >> 8;
+    __warn_unimplemented(regs, lineno, fname);
+    set_code_invalid_silent(regs, code);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/paravirt.c b/qemu-0.15.x/roms/seabios/src/paravirt.c
new file mode 100644
index 0000000..09e3d23
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/paravirt.c
@@ -0,0 +1,411 @@
+// Paravirtualization support.
+//
+// Copyright (C) 2009 Red Hat Inc.
+//
+// Authors:
+//  Gleb Natapov <gnatapov at redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_COREBOOT
+#include "util.h" // ntoh[ls]
+#include "ioport.h" // outw
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "smbios.h" // struct smbios_structure_header
+
+int qemu_cfg_present;
+
+static void
+qemu_cfg_select(u16 f)
+{
+    outw(f, PORT_QEMU_CFG_CTL);
+}
+
+static void
+qemu_cfg_read(u8 *buf, int len)
+{
+    insb(PORT_QEMU_CFG_DATA, buf, len);
+}
+
+static void
+qemu_cfg_skip(int len)
+{
+    while (len--)
+        inb(PORT_QEMU_CFG_DATA);
+}
+
+static void
+qemu_cfg_read_entry(void *buf, int e, int len)
+{
+    qemu_cfg_select(e);
+    qemu_cfg_read(buf, len);
+}
+
+void qemu_cfg_port_probe(void)
+{
+    char *sig = "QEMU";
+    int i;
+
+    if (CONFIG_COREBOOT)
+        return;
+
+    qemu_cfg_present = 1;
+
+    qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+    for (i = 0; i < 4; i++)
+        if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
+            qemu_cfg_present = 0;
+            break;
+        }
+    dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
+}
+
+void qemu_cfg_get_uuid(u8 *uuid)
+{
+    if (!qemu_cfg_present)
+        return;
+
+    qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
+}
+
+int qemu_cfg_show_boot_menu(void)
+{
+    u16 v;
+    if (!qemu_cfg_present)
+        return 1;
+
+    qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
+
+    return v;
+}
+
+int qemu_cfg_irq0_override(void)
+{
+    u8 v;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
+
+    return v;
+}
+
+u16 qemu_cfg_acpi_additional_tables(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
+
+    return cnt;
+}
+
+u16 qemu_cfg_next_acpi_table_len(void)
+{
+    u16 len;
+
+    qemu_cfg_read((u8*)&len, sizeof(len));
+
+    return len;
+}
+
+void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
+{
+    qemu_cfg_read(addr, len);
+    return addr;
+}
+
+u16 qemu_cfg_smbios_entries(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+
+    return cnt;
+}
+
+u32 qemu_cfg_e820_entries(void)
+{
+    u32 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
+    return cnt;
+}
+
+void* qemu_cfg_e820_load_next(void *addr)
+{
+    qemu_cfg_read(addr, sizeof(struct e820_reservation));
+    return addr;
+}
+
+struct smbios_header {
+    u16 length;
+    u8 type;
+} PACKED;
+
+struct smbios_field {
+    struct smbios_header header;
+    u8 type;
+    u16 offset;
+    u8 data[];
+} PACKED;
+
+struct smbios_table {
+    struct smbios_header header;
+    u8 data[];
+} PACKED;
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
+{
+    int i;
+
+    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+        struct smbios_field field;
+
+        qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
+        field.header.length -= sizeof(struct smbios_header);
+
+        if (field.header.type != SMBIOS_FIELD_ENTRY) {
+            qemu_cfg_skip(field.header.length);
+            continue;
+        }
+
+        qemu_cfg_read((u8 *)&field.type,
+                      sizeof(field) - sizeof(struct smbios_header));
+        field.header.length -= sizeof(field) - sizeof(struct smbios_header);
+
+        if (field.type != type || field.offset != offset) {
+            qemu_cfg_skip(field.header.length);
+            continue;
+        }
+
+        qemu_cfg_read(addr, field.header.length);
+        return (size_t)field.header.length;
+    }
+    return 0;
+}
+
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+                                  unsigned *max_struct_size, char *end)
+{
+    static u64 used_bitmap[4] = { 0 };
+    char *start = *p;
+    int i;
+
+    /* Check if we've already reported these tables */
+    if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+        return 1;
+
+    /* Don't introduce spurious end markers */
+    if (type == 127)
+        return 0;
+
+    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+        struct smbios_table table;
+        struct smbios_structure_header *header = (void *)*p;
+        int string;
+
+        qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
+        table.header.length -= sizeof(struct smbios_header);
+
+        if (table.header.type != SMBIOS_TABLE_ENTRY) {
+            qemu_cfg_skip(table.header.length);
+            continue;
+        }
+
+        if (end - *p < sizeof(struct smbios_structure_header)) {
+            warn_noalloc();
+            break;
+        }
+
+        qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
+        table.header.length -= sizeof(struct smbios_structure_header);
+
+        if (header->type != type) {
+            qemu_cfg_skip(table.header.length);
+            continue;
+        }
+
+        *p += sizeof(struct smbios_structure_header);
+
+        /* Entries end with a double NULL char, if there's a string at
+         * the end (length is greater than formatted length), the string
+         * terminator provides the first NULL. */
+        string = header->length < table.header.length +
+                 sizeof(struct smbios_structure_header);
+
+        /* Read the rest and terminate the entry */
+        if (end - *p < table.header.length) {
+            warn_noalloc();
+            *p -= sizeof(struct smbios_structure_header);
+            continue;
+        }
+        qemu_cfg_read((u8 *)*p, table.header.length);
+        *p += table.header.length;
+        *((u8*)*p) = 0;
+        (*p)++;
+        if (!string) {
+            *((u8*)*p) = 0;
+            (*p)++;
+        }
+
+        (*nr_structs)++;
+        if (*p - (char *)header > *max_struct_size)
+            *max_struct_size = *p - (char *)header;
+    }
+
+    if (start != *p) {
+        /* Mark that we've reported on this type */
+        used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+        return 1;
+    }
+
+    return 0;
+}
+
+int qemu_cfg_get_numa_nodes(void)
+{
+    u64 cnt;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
+
+    return (int)cnt;
+}
+
+void qemu_cfg_get_numa_data(u64 *data, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        qemu_cfg_read((u8*)(data + i), sizeof(u64));
+}
+
+u16 qemu_cfg_get_max_cpus(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
+
+    return cnt;
+}
+
+static QemuCfgFile LastFile;
+
+static u32
+__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
+{
+    if (!qemu_cfg_present)
+        return 0;
+
+    u32 count;
+    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+    count = ntohl(count);
+    u32 e;
+    for (e = 0; e < count; e++) {
+        qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+        u32 select = ntohs(LastFile.select);
+        if (select <= prevselect)
+            continue;
+        if (memcmp(prefix, LastFile.name, prefixlen) == 0)
+            return select;
+    }
+    return 0;
+}
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
+{
+    return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
+}
+
+u32 qemu_cfg_find_file(const char *name)
+{
+    return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
+}
+
+static int
+__qemu_cfg_set_file(u32 select)
+{
+    if (!qemu_cfg_present || !select)
+        return -1;
+    if (select == ntohs(LastFile.select))
+        return 0;
+
+    u32 count;
+    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+    count = ntohl(count);
+    u32 e;
+    for (e = 0; e < count; e++) {
+        qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+        if (select == ntohs(LastFile.select))
+            return 0;
+    }
+    return -1;
+}
+
+int qemu_cfg_size_file(u32 select)
+{
+    if (__qemu_cfg_set_file(select))
+        return -1;
+    return ntohl(LastFile.size);
+}
+
+const char* qemu_cfg_name_file(u32 select)
+{
+    if (__qemu_cfg_set_file(select))
+        return NULL;
+    return LastFile.name;
+}
+
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
+{
+    if (__qemu_cfg_set_file(select))
+        return -1;
+    int len = qemu_cfg_size_file(select);
+    if (len < 0 || len > maxlen)
+        return -1;
+    qemu_cfg_read_entry(dst, select, len);
+    return len;
+}
+
+// Helper function to find, malloc_tmphigh, and copy a romfile.  This
+// function adds a trailing zero to the malloc'd copy.
+void *
+romfile_loadfile(const char *name, int *psize)
+{
+    u32 file = romfile_find(name);
+    if (!file)
+        return NULL;
+
+    int filesize = romfile_size(file);
+    if (!filesize)
+        return NULL;
+
+    char *data = malloc_tmphigh(filesize+1);
+    if (!data) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
+    romfile_copy(file, data, filesize);
+    if (psize)
+        *psize = filesize;
+    data[filesize] = '\0';
+    return data;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/paravirt.h b/qemu-0.15.x/roms/seabios/src/paravirt.h
new file mode 100644
index 0000000..7bf34b1
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/paravirt.h
@@ -0,0 +1,108 @@
+#ifndef __PV_H
+#define __PV_H
+
+#include "util.h"
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE     0x40000000
+
+static inline int kvm_para_available(void)
+{
+    unsigned int eax, ebx, ecx, edx;
+    char signature[13];
+
+    cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+    memcpy(signature + 0, &ebx, 4);
+    memcpy(signature + 4, &ecx, 4);
+    memcpy(signature + 8, &edx, 4);
+    signature[12] = 0;
+
+    if (strcmp(signature, "KVMKVMKVM") == 0)
+        return 1;
+
+    return 0;
+}
+
+#define QEMU_CFG_SIGNATURE		0x00
+#define QEMU_CFG_ID			0x01
+#define QEMU_CFG_UUID			0x02
+#define QEMU_CFG_NUMA			0x0d
+#define QEMU_CFG_BOOT_MENU		0x0e
+#define QEMU_CFG_MAX_CPUS		0x0f
+#define QEMU_CFG_FILE_DIR               0x19
+#define QEMU_CFG_ARCH_LOCAL		0x8000
+#define QEMU_CFG_ACPI_TABLES		(QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES		(QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE		(QEMU_CFG_ARCH_LOCAL + 2)
+#define QEMU_CFG_E820_TABLE		(QEMU_CFG_ARCH_LOCAL + 3)
+
+extern int qemu_cfg_present;
+
+void qemu_cfg_port_probe(void);
+int qemu_cfg_show_boot_menu(void);
+void qemu_cfg_get_uuid(u8 *uuid);
+int qemu_cfg_irq0_override(void);
+u16 qemu_cfg_acpi_additional_tables(void);
+u16 qemu_cfg_next_acpi_table_len(void);
+void *qemu_cfg_next_acpi_table_load(void *addr, u16 len);
+u16 qemu_cfg_smbios_entries(void);
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr);
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+                                  unsigned *max_struct_size, char *end);
+int qemu_cfg_get_numa_nodes(void);
+void qemu_cfg_get_numa_data(u64 *data, int n);
+u16 qemu_cfg_get_max_cpus(void);
+
+typedef struct QemuCfgFile {
+    u32  size;        /* file size */
+    u16  select;      /* write this to 0x510 to read it */
+    u16  reserved;
+    char name[56];
+} QemuCfgFile;
+
+struct e820_reservation {
+    u64 address;
+    u64 length;
+    u32 type;
+};
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect);
+u32 qemu_cfg_find_file(const char *name);
+int qemu_cfg_size_file(u32 select);
+const char* qemu_cfg_name_file(u32 select);
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen);
+
+// Wrappers that select cbfs or qemu_cfg file interface.
+static inline u32 romfile_findprefix(const char *prefix, u32 previd) {
+    if (CONFIG_COREBOOT)
+        return (u32)cbfs_findprefix(prefix, (void*)previd);
+    return qemu_cfg_next_prefix_file(prefix, previd);
+}
+static inline u32 romfile_find(const char *name) {
+    if (CONFIG_COREBOOT)
+        return (u32)cbfs_finddatafile(name);
+    return qemu_cfg_find_file(name);
+}
+static inline u32 romfile_size(u32 fileid) {
+    if (CONFIG_COREBOOT)
+        return cbfs_datasize((void*)fileid);
+    return qemu_cfg_size_file(fileid);
+}
+static inline int romfile_copy(u32 fileid, void *dst, u32 maxlen) {
+    if (CONFIG_COREBOOT)
+        return cbfs_copyfile((void*)fileid, dst, maxlen);
+    return qemu_cfg_read_file(fileid, dst, maxlen);
+}
+static inline const char* romfile_name(u32 fileid) {
+    if (CONFIG_COREBOOT)
+        return cbfs_filename((void*)fileid);
+    return qemu_cfg_name_file(fileid);
+}
+void *romfile_loadfile(const char *name, int *psize);
+
+u32 qemu_cfg_e820_entries(void);
+void* qemu_cfg_e820_load_next(void *addr);
+
+#endif
diff --git a/qemu-0.15.x/roms/seabios/src/pci.c b/qemu-0.15.x/roms/seabios/src/pci.c
new file mode 100644
index 0000000..944a393
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pci.c
@@ -0,0 +1,304 @@
+// PCI config space access functions.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // pci_config_writel
+#include "ioport.h" // outl
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "farptr.h" // CONFIG_*
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    outl(val, PORT_PCI_DATA);
+}
+
+void pci_config_writew(u16 bdf, u32 addr, u16 val)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    outw(val, PORT_PCI_DATA + (addr & 2));
+}
+
+void pci_config_writeb(u16 bdf, u32 addr, u8 val)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    outb(val, PORT_PCI_DATA + (addr & 3));
+}
+
+u32 pci_config_readl(u16 bdf, u32 addr)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    return inl(PORT_PCI_DATA);
+}
+
+u16 pci_config_readw(u16 bdf, u32 addr)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    return inw(PORT_PCI_DATA + (addr & 2));
+}
+
+u8 pci_config_readb(u16 bdf, u32 addr)
+{
+    outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+    return inb(PORT_PCI_DATA + (addr & 3));
+}
+
+void
+pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on)
+{
+    u16 val = pci_config_readw(bdf, addr);
+    val = (val & ~off) | on;
+    pci_config_writew(bdf, addr, val);
+}
+
+// Helper function for foreachpci() macro - return next device
+int
+pci_next(int bdf, int *pmax)
+{
+    if (pci_bdf_to_fn(bdf) == 1
+        && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
+        // Last found device wasn't a multi-function device - skip to
+        // the next device.
+        bdf += 7;
+
+    int max = *pmax;
+    for (;;) {
+        if (bdf >= max) {
+            if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
+                bdf = CONFIG_PCI_ROOT1 << 8;
+            else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
+                bdf = CONFIG_PCI_ROOT2 << 8;
+            else
+            	return -1;
+            *pmax = max = bdf + 0x0100;
+        }
+
+        u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
+        if (v != 0x0000 && v != 0xffff)
+            // Device is present.
+            break;
+
+        if (pci_bdf_to_fn(bdf) == 0)
+            bdf += 8;
+        else
+            bdf += 1;
+    }
+
+    // Check if found device is a bridge.
+    u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
+    v &= 0x7f;
+    if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+        v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
+        int newmax = (v & 0xff00) + 0x0100;
+        if (newmax > max)
+            *pmax = newmax;
+    }
+
+    return bdf;
+}
+
+// Find a vga device with legacy address decoding enabled.
+int
+pci_find_vga(void)
+{
+    int bdf = 0x0000, max = 0x0100;
+    for (;;) {
+        if (bdf >= max) {
+            if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
+                bdf = CONFIG_PCI_ROOT1 << 8;
+            else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
+                bdf = CONFIG_PCI_ROOT2 << 8;
+            else
+            	return -1;
+            max = bdf + 0x0100;
+        }
+
+        u16 cls = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+        if (cls == 0x0000 || cls == 0xffff) {
+            // Device not present.
+            if (pci_bdf_to_fn(bdf) == 0)
+                bdf += 8;
+            else
+                bdf += 1;
+            continue;
+        }
+        if (cls == PCI_CLASS_DISPLAY_VGA) {
+            u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
+            if (cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)
+                // Found active vga card
+                return bdf;
+        }
+
+        // Check if device is a bridge.
+        u8 hdr = pci_config_readb(bdf, PCI_HEADER_TYPE);
+        u8 ht = hdr & 0x7f;
+        if (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS) {
+            u32 ctrl = pci_config_readb(bdf, PCI_BRIDGE_CONTROL);
+            if (ctrl & PCI_BRIDGE_CTL_VGA) {
+                // Found a VGA enabled bridge.
+                u32 pbus = pci_config_readl(bdf, PCI_PRIMARY_BUS);
+                bdf = (pbus & 0xff00);
+                max = bdf + 0x100;
+                continue;
+            }
+        }
+
+        if (pci_bdf_to_fn(bdf) == 0 && (hdr & 0x80) == 0)
+            // Last found device wasn't a multi-function device - skip to
+            // the next device.
+            bdf += 8;
+        else
+            bdf += 1;
+    }
+}
+
+// Search for a device with the specified vendor and device ids.
+int
+pci_find_device(u16 vendid, u16 devid)
+{
+    u32 id = (devid << 16) | vendid;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
+        if (v == id)
+            return bdf;
+    }
+    return -1;
+}
+
+// Search for a device with the specified class id.
+int
+pci_find_class(u16 classid)
+{
+    int bdf, max;
+    foreachpci(bdf, max) {
+        u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+        if (v == classid)
+            return bdf;
+    }
+    return -1;
+}
+
+int *PCIpaths;
+
+// Build the PCI path designations.
+void
+pci_path_setup(void)
+{
+    PCIpaths = malloc_tmp(sizeof(*PCIpaths) * 256);
+    if (!PCIpaths)
+        return;
+    memset(PCIpaths, 0, sizeof(*PCIpaths) * 256);
+
+    int roots = 0;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        int bus = pci_bdf_to_bus(bdf);
+        if (! PCIpaths[bus])
+            PCIpaths[bus] = (roots++) | PP_ROOT;
+
+        // Check if found device is a bridge.
+        u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
+        v &= 0x7f;
+        if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+            v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
+            int childbus = (v >> 8) & 0xff;
+            if (childbus > bus)
+                PCIpaths[childbus] = bdf | PP_PCIBRIDGE;
+        }
+    }
+}
+
+int pci_init_device(const struct pci_device_id *ids, u16 bdf, void *arg)
+{
+    u16 vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
+    u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
+    u16 class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+
+    while (ids->vendid || ids->class_mask) {
+        if ((ids->vendid == PCI_ANY_ID || ids->vendid == vendor_id) &&
+            (ids->devid == PCI_ANY_ID || ids->devid == device_id) &&
+            !((ids->class ^ class) & ids->class_mask)) {
+            if (ids->func) {
+                ids->func(bdf, arg);
+            }
+            return 0;
+        }
+        ids++;
+    }
+    return -1;
+}
+
+int pci_find_init_device(const struct pci_device_id *ids, void *arg)
+{
+    int bdf, max;
+
+    foreachpci(bdf, max) {
+        if (pci_init_device(ids, bdf, arg) == 0) {
+            return bdf;
+        }
+    }
+    return -1;
+}
+
+void
+pci_reboot(void)
+{
+    u8 v = inb(PORT_PCI_REBOOT) & ~6;
+    outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
+    udelay(50);
+    outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
+    udelay(50);
+}
+
+// helper functions to access pci mmio bars from real mode
+
+u32 VISIBLE32FLAT
+pci_readl_32(u32 addr)
+{
+    dprintf(3, "32: pci read : %x\n", addr);
+    return readl((void*)addr);
+}
+
+u32 pci_readl(u32 addr)
+{
+    if (MODESEGMENT) {
+        dprintf(3, "16: pci read : %x\n", addr);
+        extern void _cfunc32flat_pci_readl_32(u32 addr);
+        return call32(_cfunc32flat_pci_readl_32, addr, -1);
+    } else {
+        return pci_readl_32(addr);
+    }
+}
+
+struct reg32 {
+    u32 addr;
+    u32 data;
+};
+
+void VISIBLE32FLAT
+pci_writel_32(struct reg32 *reg32)
+{
+    dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
+    writel((void*)(reg32->addr), reg32->data);
+}
+
+void pci_writel(u32 addr, u32 val)
+{
+    struct reg32 reg32 = { .addr = addr, .data = val };
+    if (MODESEGMENT) {
+        dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
+                reg32.addr, reg32.data, GET_SEG(SS), &reg32);
+        void *flatptr = MAKE_FLATPTR(GET_SEG(SS), &reg32);
+        extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
+        call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
+    } else {
+        pci_writel_32(&reg32);
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pci.h b/qemu-0.15.x/roms/seabios/src/pci.h
new file mode 100644
index 0000000..9869a26
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pci.h
@@ -0,0 +1,148 @@
+#ifndef __PCI_H
+#define __PCI_H
+
+#include "types.h" // u32
+
+static inline u8 pci_bdf_to_bus(u16 bdf) {
+    return bdf >> 8;
+}
+static inline u8 pci_bdf_to_devfn(u16 bdf) {
+    return bdf & 0xff;
+}
+static inline u16 pci_bdf_to_busdev(u16 bdf) {
+    return bdf & ~0x07;
+}
+static inline u8 pci_bdf_to_dev(u16 bdf) {
+    return (bdf >> 3) & 0x1f;
+}
+static inline u8 pci_bdf_to_fn(u16 bdf) {
+    return bdf & 0x07;
+}
+static inline u16 pci_to_bdf(int bus, int dev, int fn) {
+    return (bus<<8) | (dev<<3) | fn;
+}
+static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) {
+    return (bus << 8) | devfn;
+}
+
+static inline u32 pci_vd(u16 vendor, u16 device) {
+    return (device << 16) | vendor;
+}
+static inline u16 pci_vd_to_ven(u32 vd) {
+    return vd & 0xffff;
+}
+static inline u16 pci_vd_to_dev(u32 vd) {
+    return vd >> 16;
+}
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val);
+void pci_config_writew(u16 bdf, u32 addr, u16 val);
+void pci_config_writeb(u16 bdf, u32 addr, u8 val);
+u32 pci_config_readl(u16 bdf, u32 addr);
+u16 pci_config_readw(u16 bdf, u32 addr);
+u8 pci_config_readb(u16 bdf, u32 addr);
+void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on);
+
+int pci_find_vga(void);
+int pci_find_device(u16 vendid, u16 devid);
+int pci_find_class(u16 classid);
+
+#define PP_ROOT      (1<<17)
+#define PP_PCIBRIDGE (1<<18)
+extern int *PCIpaths;
+void pci_path_setup(void);
+
+int pci_next(int bdf, int *pmax);
+#define foreachpci(BDF, MAX)                    \
+    for (MAX=0x0100, BDF=pci_next(0, &MAX)      \
+         ; BDF >= 0                             \
+         ; BDF=pci_next(BDF+1, &MAX))
+
+#define foreachpci_in_bus(BDF, MAX, BUS)                                \
+    for (MAX = pci_bus_devfn_to_bdf(BUS, 0) + 0x0100,                   \
+         BDF = pci_next(pci_bus_devfn_to_bdf(BUS, 0), &MAX)             \
+         ; BDF >= 0 && BDF < pci_bus_devfn_to_bdf(BUS, 0) + 0x0100      \
+         ; MAX = pci_bus_devfn_to_bdf(BUS, 0) + 0x0100,                 \
+           BDF = pci_next(BDF + 1, &MAX))
+
+#define PCI_ANY_ID      (~0)
+struct pci_device_id {
+    u32 vendid;
+    u32 devid;
+    u32 class;
+    u32 class_mask;
+    void (*func)(u16 bdf, void *arg);
+};
+
+#define PCI_DEVICE(vendor_id, device_id, init_func)     \
+    {                                                   \
+        .vendid = (vendor_id),                          \
+        .devid = (device_id),                           \
+        .class = PCI_ANY_ID,                            \
+        .class_mask = 0,                                \
+        .func = (init_func)                             \
+    }
+
+#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func)   \
+    {                                                                   \
+        .vendid = (vendor_id),                                          \
+        .devid = (device_id),                                           \
+        .class = (class_code),                                          \
+        .class_mask = ~0,                                               \
+        .func = (init_func)                                             \
+    }
+
+#define PCI_DEVICE_END                          \
+    {                                           \
+        .vendid = 0,                            \
+    }
+
+int pci_init_device(const struct pci_device_id *table, u16 bdf, void *arg);
+int pci_find_init_device(const struct pci_device_id *ids, void *arg);
+void pci_reboot(void);
+
+// helper functions to access pci mmio bars from real mode
+u32 pci_readl(u32 addr);
+void pci_writel(u32 addr, u32 val);
+
+// pirtable.c
+void create_pirtable(void);
+
+
+/****************************************************************
+ * PIR table
+ ****************************************************************/
+
+extern u16 PirOffset;
+
+struct link_info {
+    u8 link;
+    u16 bitmap;
+} PACKED;
+
+struct pir_slot {
+    u8 bus;
+    u8 dev;
+    struct link_info links[4];
+    u8 slot_nr;
+    u8 reserved;
+} PACKED;
+
+struct pir_header {
+    u32 signature;
+    u16 version;
+    u16 size;
+    u8 router_bus;
+    u8 router_devfunc;
+    u16 exclusive_irqs;
+    u32 compatible_devid;
+    u32 miniport_data;
+    u8 reserved[11];
+    u8 checksum;
+    struct pir_slot slots[0];
+} PACKED;
+
+#define PIR_SIGNATURE 0x52495024 // $PIR
+
+
+#endif
diff --git a/qemu-0.15.x/roms/seabios/src/pci_ids.h b/qemu-0.15.x/roms/seabios/src/pci_ids.h
new file mode 100644
index 0000000..e1cded2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pci_ids.h
@@ -0,0 +1,2610 @@
+/*
+ *	PCI Class, Vendor and Device IDs
+ *
+ *	Please keep sorted.
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED		0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
+
+#define PCI_BASE_CLASS_STORAGE		0x01
+#define PCI_CLASS_STORAGE_SCSI		0x0100
+#define PCI_CLASS_STORAGE_IDE		0x0101
+#define PCI_CLASS_STORAGE_FLOPPY	0x0102
+#define PCI_CLASS_STORAGE_IPI		0x0103
+#define PCI_CLASS_STORAGE_RAID		0x0104
+#define PCI_CLASS_STORAGE_SATA		0x0106
+#define PCI_CLASS_STORAGE_SATA_AHCI	0x010601
+#define PCI_CLASS_STORAGE_SAS		0x0107
+#define PCI_CLASS_STORAGE_OTHER		0x0180
+
+#define PCI_BASE_CLASS_NETWORK		0x02
+#define PCI_CLASS_NETWORK_ETHERNET	0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
+#define PCI_CLASS_NETWORK_FDDI		0x0202
+#define PCI_CLASS_NETWORK_ATM		0x0203
+#define PCI_CLASS_NETWORK_OTHER		0x0280
+
+#define PCI_BASE_CLASS_DISPLAY		0x03
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_CLASS_DISPLAY_XGA		0x0301
+#define PCI_CLASS_DISPLAY_3D		0x0302
+#define PCI_CLASS_DISPLAY_OTHER		0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA	0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
+#define PCI_CLASS_MULTIMEDIA_PHONE	0x0402
+#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
+
+#define PCI_BASE_CLASS_MEMORY		0x05
+#define PCI_CLASS_MEMORY_RAM		0x0500
+#define PCI_CLASS_MEMORY_FLASH		0x0501
+#define PCI_CLASS_MEMORY_OTHER		0x0580
+
+#define PCI_BASE_CLASS_BRIDGE		0x06
+#define PCI_CLASS_BRIDGE_HOST		0x0600
+#define PCI_CLASS_BRIDGE_ISA		0x0601
+#define PCI_CLASS_BRIDGE_EISA		0x0602
+#define PCI_CLASS_BRIDGE_MC		0x0603
+#define PCI_CLASS_BRIDGE_PCI		0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA		0x0605
+#define PCI_CLASS_BRIDGE_NUBUS		0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS	0x0607
+#define PCI_CLASS_BRIDGE_RACEWAY	0x0608
+#define PCI_CLASS_BRIDGE_OTHER		0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION	0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM	0x0703
+#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
+
+#define PCI_BASE_CLASS_SYSTEM		0x08
+#define PCI_CLASS_SYSTEM_PIC		0x0800
+#define PCI_CLASS_SYSTEM_PIC_IOAPIC	0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC	0x080020
+#define PCI_CLASS_SYSTEM_DMA		0x0801
+#define PCI_CLASS_SYSTEM_TIMER		0x0802
+#define PCI_CLASS_SYSTEM_RTC		0x0803
+#define PCI_CLASS_SYSTEM_PCI_HOTPLUG	0x0804
+#define PCI_CLASS_SYSTEM_SDHCI		0x0805
+#define PCI_CLASS_SYSTEM_OTHER		0x0880
+
+#define PCI_BASE_CLASS_INPUT		0x09
+#define PCI_CLASS_INPUT_KEYBOARD	0x0900
+#define PCI_CLASS_INPUT_PEN		0x0901
+#define PCI_CLASS_INPUT_MOUSE		0x0902
+#define PCI_CLASS_INPUT_SCANNER		0x0903
+#define PCI_CLASS_INPUT_GAMEPORT	0x0904
+#define PCI_CLASS_INPUT_OTHER		0x0980
+
+#define PCI_BASE_CLASS_DOCKING		0x0a
+#define PCI_CLASS_DOCKING_GENERIC	0x0a00
+#define PCI_CLASS_DOCKING_OTHER		0x0a80
+
+#define PCI_BASE_CLASS_PROCESSOR	0x0b
+#define PCI_CLASS_PROCESSOR_386		0x0b00
+#define PCI_CLASS_PROCESSOR_486		0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
+#define PCI_CLASS_PROCESSOR_MIPS	0x0b30
+#define PCI_CLASS_PROCESSOR_CO		0x0b40
+
+#define PCI_BASE_CLASS_SERIAL		0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI	0x0c0010
+#define PCI_CLASS_SERIAL_ACCESS		0x0c01
+#define PCI_CLASS_SERIAL_SSA		0x0c02
+#define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI	0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI	0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI	0x0c0320
+#define PCI_CLASS_SERIAL_FIBER		0x0c04
+#define PCI_CLASS_SERIAL_SMBUS		0x0c05
+
+#define PCI_BASE_CLASS_WIRELESS			0x0d
+#define PCI_CLASS_WIRELESS_RF_CONTROLLER	0x0d10
+#define PCI_CLASS_WIRELESS_WHCI			0x0d1010
+
+#define PCI_BASE_CLASS_INTELLIGENT	0x0e
+#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
+
+#define PCI_BASE_CLASS_SATELLITE	0x0f
+#define PCI_CLASS_SATELLITE_TV		0x0f00
+#define PCI_CLASS_SATELLITE_AUDIO	0x0f01
+#define PCI_CLASS_SATELLITE_VOICE	0x0f03
+#define PCI_CLASS_SATELLITE_DATA	0x0f04
+
+#define PCI_BASE_CLASS_CRYPT		0x10
+#define PCI_CLASS_CRYPT_NETWORK		0x1000
+#define PCI_CLASS_CRYPT_ENTERTAINMENT	0x1001
+#define PCI_CLASS_CRYPT_OTHER		0x1080
+
+#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11
+#define PCI_CLASS_SP_DPIO		0x1100
+#define PCI_CLASS_SP_OTHER		0x1180
+
+#define PCI_CLASS_OTHERS		0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_TTTECH		0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322	0x000a
+
+#define PCI_VENDOR_ID_DYNALINK		0x0675
+#define PCI_DEVICE_ID_DYNALINK_IS64PH	0x1702
+
+#define PCI_VENDOR_ID_BERKOM			0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T		0xffa1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT		0xffa2
+#define PCI_DEVICE_ID_BERKOM_A4T		0xffa4
+#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO	0xffa8
+
+#define PCI_VENDOR_ID_COMPAQ		0x0e11
+#define PCI_DEVICE_ID_COMPAQ_TOKENRING	0x0508
+#define PCI_DEVICE_ID_COMPAQ_TACHYON	0xa0fc
+#define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I	0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI	0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
+#define PCI_DEVICE_ID_COMPAQ_CISS	0xb060
+#define PCI_DEVICE_ID_COMPAQ_CISSB	0xb178
+#define PCI_DEVICE_ID_COMPAQ_CISSC	0x46
+#define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
+
+#define PCI_VENDOR_ID_NCR		0x1000
+#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
+#define PCI_DEVICE_ID_NCR_53C810	0x0001
+#define PCI_DEVICE_ID_NCR_53C820	0x0002
+#define PCI_DEVICE_ID_NCR_53C825	0x0003
+#define PCI_DEVICE_ID_NCR_53C815	0x0004
+#define PCI_DEVICE_ID_LSI_53C810AP	0x0005
+#define PCI_DEVICE_ID_NCR_53C860	0x0006
+#define PCI_DEVICE_ID_LSI_53C1510	0x000a
+#define PCI_DEVICE_ID_NCR_53C896	0x000b
+#define PCI_DEVICE_ID_NCR_53C895	0x000c
+#define PCI_DEVICE_ID_NCR_53C885	0x000d
+#define PCI_DEVICE_ID_NCR_53C875	0x000f
+#define PCI_DEVICE_ID_NCR_53C1510	0x0010
+#define PCI_DEVICE_ID_LSI_53C895A	0x0012
+#define PCI_DEVICE_ID_LSI_53C875A	0x0013
+#define PCI_DEVICE_ID_LSI_53C1010_33	0x0020
+#define PCI_DEVICE_ID_LSI_53C1010_66	0x0021
+#define PCI_DEVICE_ID_LSI_53C1030	0x0030
+#define PCI_DEVICE_ID_LSI_1030_53C1035	0x0032
+#define PCI_DEVICE_ID_LSI_53C1035	0x0040
+#define PCI_DEVICE_ID_NCR_53C875J	0x008f
+#define PCI_DEVICE_ID_LSI_FC909		0x0621
+#define PCI_DEVICE_ID_LSI_FC929		0x0622
+#define PCI_DEVICE_ID_LSI_FC929_LAN	0x0623
+#define PCI_DEVICE_ID_LSI_FC919		0x0624
+#define PCI_DEVICE_ID_LSI_FC919_LAN	0x0625
+#define PCI_DEVICE_ID_LSI_FC929X	0x0626
+#define PCI_DEVICE_ID_LSI_FC939X	0x0642
+#define PCI_DEVICE_ID_LSI_FC949X	0x0640
+#define PCI_DEVICE_ID_LSI_FC949ES	0x0646
+#define PCI_DEVICE_ID_LSI_FC919X	0x0628
+#define PCI_DEVICE_ID_NCR_YELLOWFIN	0x0701
+#define PCI_DEVICE_ID_LSI_61C102	0x0901
+#define PCI_DEVICE_ID_LSI_63C815	0x1000
+#define PCI_DEVICE_ID_LSI_SAS1064	0x0050
+#define PCI_DEVICE_ID_LSI_SAS1064R	0x0411
+#define PCI_DEVICE_ID_LSI_SAS1066	0x005E
+#define PCI_DEVICE_ID_LSI_SAS1068	0x0054
+#define PCI_DEVICE_ID_LSI_SAS1064A	0x005C
+#define PCI_DEVICE_ID_LSI_SAS1064E	0x0056
+#define PCI_DEVICE_ID_LSI_SAS1066E	0x005A
+#define PCI_DEVICE_ID_LSI_SAS1068E	0x0058
+#define PCI_DEVICE_ID_LSI_SAS1078	0x0060
+
+#define PCI_VENDOR_ID_ATI		0x1002
+/* Mach64 */
+#define PCI_DEVICE_ID_ATI_68800		0x4158
+#define PCI_DEVICE_ID_ATI_215CT222	0x4354
+#define PCI_DEVICE_ID_ATI_210888CX	0x4358
+#define PCI_DEVICE_ID_ATI_215ET222	0x4554
+/* Mach64 / Rage */
+#define PCI_DEVICE_ID_ATI_215GB		0x4742
+#define PCI_DEVICE_ID_ATI_215GD		0x4744
+#define PCI_DEVICE_ID_ATI_215GI		0x4749
+#define PCI_DEVICE_ID_ATI_215GP		0x4750
+#define PCI_DEVICE_ID_ATI_215GQ		0x4751
+#define PCI_DEVICE_ID_ATI_215XL		0x4752
+#define PCI_DEVICE_ID_ATI_215GT		0x4754
+#define PCI_DEVICE_ID_ATI_215GTB	0x4755
+#define PCI_DEVICE_ID_ATI_215_IV	0x4756
+#define PCI_DEVICE_ID_ATI_215_IW	0x4757
+#define PCI_DEVICE_ID_ATI_215_IZ	0x475A
+#define PCI_DEVICE_ID_ATI_210888GX	0x4758
+#define PCI_DEVICE_ID_ATI_215_LB	0x4c42
+#define PCI_DEVICE_ID_ATI_215_LD	0x4c44
+#define PCI_DEVICE_ID_ATI_215_LG	0x4c47
+#define PCI_DEVICE_ID_ATI_215_LI	0x4c49
+#define PCI_DEVICE_ID_ATI_215_LM	0x4c4D
+#define PCI_DEVICE_ID_ATI_215_LN	0x4c4E
+#define PCI_DEVICE_ID_ATI_215_LR	0x4c52
+#define PCI_DEVICE_ID_ATI_215_LS	0x4c53
+#define PCI_DEVICE_ID_ATI_264_LT	0x4c54
+/* Mach64 VT */
+#define PCI_DEVICE_ID_ATI_264VT		0x5654
+#define PCI_DEVICE_ID_ATI_264VU		0x5655
+#define PCI_DEVICE_ID_ATI_264VV		0x5656
+/* Rage128 GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_RE	0x5245
+#define PCI_DEVICE_ID_ATI_RAGE128_RF	0x5246
+#define PCI_DEVICE_ID_ATI_RAGE128_RG	0x5247
+/* Rage128 VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_RK	0x524b
+#define PCI_DEVICE_ID_ATI_RAGE128_RL	0x524c
+#define PCI_DEVICE_ID_ATI_RAGE128_SE	0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_SF	0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_SG	0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SH	0x5348
+#define PCI_DEVICE_ID_ATI_RAGE128_SK	0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_SL	0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_SM	0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_SN	0x534e
+/* Rage128 Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_TF	0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_TL	0x544c
+#define PCI_DEVICE_ID_ATI_RAGE128_TR	0x5452
+#define PCI_DEVICE_ID_ATI_RAGE128_TS	0x5453
+#define PCI_DEVICE_ID_ATI_RAGE128_TT	0x5454
+#define PCI_DEVICE_ID_ATI_RAGE128_TU	0x5455
+/* Rage128 M3 */
+#define PCI_DEVICE_ID_ATI_RAGE128_LE	0x4c45
+#define PCI_DEVICE_ID_ATI_RAGE128_LF	0x4c46
+/* Rage128 M4 */
+#define PCI_DEVICE_ID_ATI_RAGE128_MF    0x4d46
+#define PCI_DEVICE_ID_ATI_RAGE128_ML    0x4d4c
+/* Rage128 Pro GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_PA	0x5041
+#define PCI_DEVICE_ID_ATI_RAGE128_PB	0x5042
+#define PCI_DEVICE_ID_ATI_RAGE128_PC	0x5043
+#define PCI_DEVICE_ID_ATI_RAGE128_PD	0x5044
+#define PCI_DEVICE_ID_ATI_RAGE128_PE	0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PF	0x5046
+/* Rage128 Pro VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_PG	0x5047
+#define PCI_DEVICE_ID_ATI_RAGE128_PH	0x5048
+#define PCI_DEVICE_ID_ATI_RAGE128_PI	0x5049
+#define PCI_DEVICE_ID_ATI_RAGE128_PJ	0x504A
+#define PCI_DEVICE_ID_ATI_RAGE128_PK	0x504B
+#define PCI_DEVICE_ID_ATI_RAGE128_PL	0x504C
+#define PCI_DEVICE_ID_ATI_RAGE128_PM	0x504D
+#define PCI_DEVICE_ID_ATI_RAGE128_PN	0x504E
+#define PCI_DEVICE_ID_ATI_RAGE128_PO	0x504F
+#define PCI_DEVICE_ID_ATI_RAGE128_PP	0x5050
+#define PCI_DEVICE_ID_ATI_RAGE128_PQ	0x5051
+#define PCI_DEVICE_ID_ATI_RAGE128_PR	0x5052
+#define PCI_DEVICE_ID_ATI_RAGE128_PS	0x5053
+#define PCI_DEVICE_ID_ATI_RAGE128_PT	0x5054
+#define PCI_DEVICE_ID_ATI_RAGE128_PU	0x5055
+#define PCI_DEVICE_ID_ATI_RAGE128_PV	0x5056
+#define PCI_DEVICE_ID_ATI_RAGE128_PW	0x5057
+#define PCI_DEVICE_ID_ATI_RAGE128_PX	0x5058
+/* Rage128 M4 */
+/* Radeon R100 */
+#define PCI_DEVICE_ID_ATI_RADEON_QD	0x5144
+#define PCI_DEVICE_ID_ATI_RADEON_QE	0x5145
+#define PCI_DEVICE_ID_ATI_RADEON_QF	0x5146
+#define PCI_DEVICE_ID_ATI_RADEON_QG	0x5147
+/* Radeon RV100 (VE) */
+#define PCI_DEVICE_ID_ATI_RADEON_QY	0x5159
+#define PCI_DEVICE_ID_ATI_RADEON_QZ	0x515a
+/* Radeon R200 (8500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QL	0x514c
+#define PCI_DEVICE_ID_ATI_RADEON_QN	0x514e
+#define PCI_DEVICE_ID_ATI_RADEON_QO	0x514f
+#define PCI_DEVICE_ID_ATI_RADEON_Ql	0x516c
+#define PCI_DEVICE_ID_ATI_RADEON_BB	0x4242
+/* Radeon R200 (9100) */
+#define PCI_DEVICE_ID_ATI_RADEON_QM	0x514d
+/* Radeon RV200 (7500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QW	0x5157
+#define PCI_DEVICE_ID_ATI_RADEON_QX	0x5158
+/* Radeon NV-100 */
+/* Radeon RV250 (9000) */
+#define PCI_DEVICE_ID_ATI_RADEON_Id	0x4964
+#define PCI_DEVICE_ID_ATI_RADEON_Ie	0x4965
+#define PCI_DEVICE_ID_ATI_RADEON_If	0x4966
+#define PCI_DEVICE_ID_ATI_RADEON_Ig	0x4967
+/* Radeon RV280 (9200) */
+#define PCI_DEVICE_ID_ATI_RADEON_Ya	0x5961
+#define PCI_DEVICE_ID_ATI_RADEON_Yd	0x5964
+/* Radeon R300 (9500) */
+/* Radeon R300 (9700) */
+#define PCI_DEVICE_ID_ATI_RADEON_ND	0x4e44
+#define PCI_DEVICE_ID_ATI_RADEON_NE	0x4e45
+#define PCI_DEVICE_ID_ATI_RADEON_NF	0x4e46
+#define PCI_DEVICE_ID_ATI_RADEON_NG	0x4e47
+/* Radeon R350 (9800) */
+/* Radeon RV350 (9600) */
+/* Radeon M6 */
+#define PCI_DEVICE_ID_ATI_RADEON_LY	0x4c59
+#define PCI_DEVICE_ID_ATI_RADEON_LZ	0x4c5a
+/* Radeon M7 */
+#define PCI_DEVICE_ID_ATI_RADEON_LW	0x4c57
+#define PCI_DEVICE_ID_ATI_RADEON_LX	0x4c58
+/* Radeon M9 */
+#define PCI_DEVICE_ID_ATI_RADEON_Ld	0x4c64
+#define PCI_DEVICE_ID_ATI_RADEON_Le	0x4c65
+#define PCI_DEVICE_ID_ATI_RADEON_Lf	0x4c66
+#define PCI_DEVICE_ID_ATI_RADEON_Lg	0x4c67
+/* Radeon */
+/* RadeonIGP */
+#define PCI_DEVICE_ID_ATI_RS100		0xcab0
+#define PCI_DEVICE_ID_ATI_RS200		0xcab2
+#define PCI_DEVICE_ID_ATI_RS200_B	0xcbb2
+#define PCI_DEVICE_ID_ATI_RS250		0xcab3
+#define PCI_DEVICE_ID_ATI_RS300_100	0x5830
+#define PCI_DEVICE_ID_ATI_RS300_133	0x5831
+#define PCI_DEVICE_ID_ATI_RS300_166	0x5832
+#define PCI_DEVICE_ID_ATI_RS300_200	0x5833
+#define PCI_DEVICE_ID_ATI_RS350_100     0x7830
+#define PCI_DEVICE_ID_ATI_RS350_133     0x7831
+#define PCI_DEVICE_ID_ATI_RS350_166     0x7832
+#define PCI_DEVICE_ID_ATI_RS350_200     0x7833
+#define PCI_DEVICE_ID_ATI_RS400_100     0x5a30
+#define PCI_DEVICE_ID_ATI_RS400_133     0x5a31
+#define PCI_DEVICE_ID_ATI_RS400_166     0x5a32
+#define PCI_DEVICE_ID_ATI_RS400_200     0x5a33
+#define PCI_DEVICE_ID_ATI_RS480         0x5950
+/* ATI IXP Chipset */
+#define PCI_DEVICE_ID_ATI_IXP200_IDE	0x4349
+#define PCI_DEVICE_ID_ATI_IXP200_SMBUS	0x4353
+#define PCI_DEVICE_ID_ATI_IXP300_SMBUS	0x4363
+#define PCI_DEVICE_ID_ATI_IXP300_IDE	0x4369
+#define PCI_DEVICE_ID_ATI_IXP300_SATA   0x436e
+#define PCI_DEVICE_ID_ATI_IXP400_SMBUS	0x4372
+#define PCI_DEVICE_ID_ATI_IXP400_IDE	0x4376
+#define PCI_DEVICE_ID_ATI_IXP400_SATA   0x4379
+#define PCI_DEVICE_ID_ATI_IXP400_SATA2	0x437a
+#define PCI_DEVICE_ID_ATI_IXP600_SATA	0x4380
+#define PCI_DEVICE_ID_ATI_SBX00_SMBUS	0x4385
+#define PCI_DEVICE_ID_ATI_IXP600_IDE	0x438c
+#define PCI_DEVICE_ID_ATI_IXP700_SATA	0x4390
+#define PCI_DEVICE_ID_ATI_IXP700_IDE	0x439c
+
+#define PCI_VENDOR_ID_VLSI		0x1004
+#define PCI_DEVICE_ID_VLSI_82C592	0x0005
+#define PCI_DEVICE_ID_VLSI_82C593	0x0006
+#define PCI_DEVICE_ID_VLSI_82C594	0x0007
+#define PCI_DEVICE_ID_VLSI_82C597	0x0009
+#define PCI_DEVICE_ID_VLSI_82C541	0x000c
+#define PCI_DEVICE_ID_VLSI_82C543	0x000d
+#define PCI_DEVICE_ID_VLSI_82C532	0x0101
+#define PCI_DEVICE_ID_VLSI_82C534	0x0102
+#define PCI_DEVICE_ID_VLSI_82C535	0x0104
+#define PCI_DEVICE_ID_VLSI_82C147	0x0105
+#define PCI_DEVICE_ID_VLSI_VAS96011	0x0702
+
+#define PCI_VENDOR_ID_ADL		0x1005
+#define PCI_DEVICE_ID_ADL_2301		0x2301
+
+#define PCI_VENDOR_ID_NS		0x100b
+#define PCI_DEVICE_ID_NS_87415		0x0002
+#define PCI_DEVICE_ID_NS_87560_LIO	0x000e
+#define PCI_DEVICE_ID_NS_87560_USB	0x0012
+#define PCI_DEVICE_ID_NS_83815		0x0020
+#define PCI_DEVICE_ID_NS_83820		0x0022
+#define PCI_DEVICE_ID_NS_CS5535_ISA	0x002b
+#define PCI_DEVICE_ID_NS_CS5535_IDE	0x002d
+#define PCI_DEVICE_ID_NS_CS5535_AUDIO	0x002e
+#define PCI_DEVICE_ID_NS_CS5535_USB	0x002f
+#define PCI_DEVICE_ID_NS_GX_VIDEO	0x0030
+#define PCI_DEVICE_ID_NS_SATURN		0x0035
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE	0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI	0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE	0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO	0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO	0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS	0x0505
+#define PCI_DEVICE_ID_NS_SC1100_BRIDGE	0x0510
+#define PCI_DEVICE_ID_NS_SC1100_SMI	0x0511
+#define PCI_DEVICE_ID_NS_SC1100_XBUS	0x0515
+#define PCI_DEVICE_ID_NS_87410		0xd001
+
+#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE  0x0028
+
+#define PCI_VENDOR_ID_TSENG		0x100c
+#define PCI_DEVICE_ID_TSENG_W32P_2	0x3202
+#define PCI_DEVICE_ID_TSENG_W32P_b	0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_c	0x3206
+#define PCI_DEVICE_ID_TSENG_W32P_d	0x3207
+#define PCI_DEVICE_ID_TSENG_ET6000	0x3208
+
+#define PCI_VENDOR_ID_WEITEK		0x100e
+#define PCI_DEVICE_ID_WEITEK_P9000	0x9001
+#define PCI_DEVICE_ID_WEITEK_P9100	0x9100
+
+#define PCI_VENDOR_ID_DEC		0x1011
+#define PCI_DEVICE_ID_DEC_BRD		0x0001
+#define PCI_DEVICE_ID_DEC_TULIP		0x0002
+#define PCI_DEVICE_ID_DEC_TGA		0x0004
+#define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
+#define PCI_DEVICE_ID_DEC_TGA2		0x000D
+#define PCI_DEVICE_ID_DEC_FDDI		0x000F
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
+#define PCI_DEVICE_ID_DEC_21142		0x0019
+#define PCI_DEVICE_ID_DEC_21052		0x0021
+#define PCI_DEVICE_ID_DEC_21150		0x0022
+#define PCI_DEVICE_ID_DEC_21152		0x0024
+#define PCI_DEVICE_ID_DEC_21153		0x0025
+#define PCI_DEVICE_ID_DEC_21154		0x0026
+#define PCI_DEVICE_ID_DEC_21285		0x1065
+#define PCI_DEVICE_ID_COMPAQ_42XX	0x0046
+
+#define PCI_VENDOR_ID_CIRRUS		0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548	0x0038
+#define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
+#define PCI_DEVICE_ID_CIRRUS_5434_4	0x00a4
+#define PCI_DEVICE_ID_CIRRUS_5434_8	0x00a8
+#define PCI_DEVICE_ID_CIRRUS_5436	0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446	0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5480	0x00bc
+#define PCI_DEVICE_ID_CIRRUS_5462	0x00d0
+#define PCI_DEVICE_ID_CIRRUS_5464	0x00d4
+#define PCI_DEVICE_ID_CIRRUS_5465	0x00d6
+#define PCI_DEVICE_ID_CIRRUS_6729	0x1100
+#define PCI_DEVICE_ID_CIRRUS_6832	0x1110
+#define PCI_DEVICE_ID_CIRRUS_7543	0x1202
+#define PCI_DEVICE_ID_CIRRUS_4610	0x6001
+#define PCI_DEVICE_ID_CIRRUS_4612	0x6003
+#define PCI_DEVICE_ID_CIRRUS_4615	0x6004
+
+#define PCI_VENDOR_ID_IBM		0x1014
+#define PCI_DEVICE_ID_IBM_TR		0x0018
+#define PCI_DEVICE_ID_IBM_TR_WAKE	0x003e
+#define PCI_DEVICE_ID_IBM_CPC710_PCI64	0x00fc
+#define PCI_DEVICE_ID_IBM_SNIPE		0x0180
+#define PCI_DEVICE_ID_IBM_CITRINE		0x028C
+#define PCI_DEVICE_ID_IBM_GEMSTONE		0xB166
+#define PCI_DEVICE_ID_IBM_OBSIDIAN		0x02BD
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1	0x0031
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2	0x0219
+#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX		0x021A
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM	0x0251
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361
+#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL	0x252
+
+#define PCI_VENDOR_ID_UNISYS		0x1018
+#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C
+
+#define PCI_VENDOR_ID_COMPEX2		0x101a /* pci.ids says "AT&T GIS (NCR)" */
+#define PCI_DEVICE_ID_COMPEX2_100VG	0x0005
+
+#define PCI_VENDOR_ID_WD		0x101c
+#define PCI_DEVICE_ID_WD_90C		0xc24a
+
+#define PCI_VENDOR_ID_AMI		0x101e
+#define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
+#define PCI_DEVICE_ID_AMI_MEGARAID	0x9010
+#define PCI_DEVICE_ID_AMI_MEGARAID2	0x9060
+
+#define PCI_VENDOR_ID_AMD		0x1022
+#define PCI_DEVICE_ID_AMD_K8_NB		0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP	0x1101
+#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL	0x1102
+#define PCI_DEVICE_ID_AMD_K8_NB_MISC	0x1103
+#define PCI_DEVICE_ID_AMD_10H_NB_HT	0x1200
+#define PCI_DEVICE_ID_AMD_10H_NB_MAP	0x1201
+#define PCI_DEVICE_ID_AMD_10H_NB_DRAM	0x1202
+#define PCI_DEVICE_ID_AMD_10H_NB_MISC	0x1203
+#define PCI_DEVICE_ID_AMD_10H_NB_LINK	0x1204
+#define PCI_DEVICE_ID_AMD_11H_NB_HT	0x1300
+#define PCI_DEVICE_ID_AMD_11H_NB_MAP	0x1301
+#define PCI_DEVICE_ID_AMD_11H_NB_DRAM	0x1302
+#define PCI_DEVICE_ID_AMD_11H_NB_MISC	0x1303
+#define PCI_DEVICE_ID_AMD_11H_NB_LINK	0x1304
+#define PCI_DEVICE_ID_AMD_LANCE		0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
+#define PCI_DEVICE_ID_AMD_SCSI		0x2020
+#define PCI_DEVICE_ID_AMD_SERENADE	0x36c0
+#define PCI_DEVICE_ID_AMD_FE_GATE_7006	0x7006
+#define PCI_DEVICE_ID_AMD_FE_GATE_7007	0x7007
+#define PCI_DEVICE_ID_AMD_FE_GATE_700C	0x700C
+#define PCI_DEVICE_ID_AMD_FE_GATE_700E	0x700E
+#define PCI_DEVICE_ID_AMD_COBRA_7401	0x7401
+#define PCI_DEVICE_ID_AMD_VIPER_7409	0x7409
+#define PCI_DEVICE_ID_AMD_VIPER_740B	0x740B
+#define PCI_DEVICE_ID_AMD_VIPER_7410	0x7410
+#define PCI_DEVICE_ID_AMD_VIPER_7411	0x7411
+#define PCI_DEVICE_ID_AMD_VIPER_7413	0x7413
+#define PCI_DEVICE_ID_AMD_VIPER_7440	0x7440
+#define PCI_DEVICE_ID_AMD_OPUS_7441	0x7441
+#define PCI_DEVICE_ID_AMD_OPUS_7443	0x7443
+#define PCI_DEVICE_ID_AMD_VIPER_7443	0x7443
+#define PCI_DEVICE_ID_AMD_OPUS_7445	0x7445
+#define PCI_DEVICE_ID_AMD_8111_LPC	0x7468
+#define PCI_DEVICE_ID_AMD_8111_IDE	0x7469
+#define PCI_DEVICE_ID_AMD_8111_SMBUS2	0x746a
+#define PCI_DEVICE_ID_AMD_8111_SMBUS	0x746b
+#define PCI_DEVICE_ID_AMD_8111_AUDIO	0x746d
+#define PCI_DEVICE_ID_AMD_8151_0	0x7454
+#define PCI_DEVICE_ID_AMD_8131_BRIDGE	0x7450
+#define PCI_DEVICE_ID_AMD_8131_APIC	0x7451
+#define PCI_DEVICE_ID_AMD_8132_BRIDGE	0x7458
+#define PCI_DEVICE_ID_AMD_CS5536_ISA    0x2090
+#define PCI_DEVICE_ID_AMD_CS5536_FLASH  0x2091
+#define PCI_DEVICE_ID_AMD_CS5536_AUDIO  0x2093
+#define PCI_DEVICE_ID_AMD_CS5536_OHC    0x2094
+#define PCI_DEVICE_ID_AMD_CS5536_EHC    0x2095
+#define PCI_DEVICE_ID_AMD_CS5536_UDC    0x2096
+#define PCI_DEVICE_ID_AMD_CS5536_UOC    0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_IDE    0x209A
+
+#define PCI_DEVICE_ID_AMD_LX_VIDEO  0x2081
+#define PCI_DEVICE_ID_AMD_LX_AES    0x2082
+
+#define PCI_VENDOR_ID_TRIDENT		0x1023
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX	0x2001
+#define PCI_DEVICE_ID_TRIDENT_9320	0x9320
+#define PCI_DEVICE_ID_TRIDENT_9388	0x9388
+#define PCI_DEVICE_ID_TRIDENT_9397	0x9397
+#define PCI_DEVICE_ID_TRIDENT_939A	0x939A
+#define PCI_DEVICE_ID_TRIDENT_9520	0x9520
+#define PCI_DEVICE_ID_TRIDENT_9525	0x9525
+#define PCI_DEVICE_ID_TRIDENT_9420	0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440	0x9440
+#define PCI_DEVICE_ID_TRIDENT_9660	0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750	0x9750
+#define PCI_DEVICE_ID_TRIDENT_9850	0x9850
+#define PCI_DEVICE_ID_TRIDENT_9880	0x9880
+#define PCI_DEVICE_ID_TRIDENT_8400	0x8400
+#define PCI_DEVICE_ID_TRIDENT_8420	0x8420
+#define PCI_DEVICE_ID_TRIDENT_8500	0x8500
+
+#define PCI_VENDOR_ID_AI		0x1025
+#define PCI_DEVICE_ID_AI_M1435		0x1435
+
+#define PCI_VENDOR_ID_DELL		0x1028
+#define PCI_DEVICE_ID_DELL_RACIII	0x0008
+#define PCI_DEVICE_ID_DELL_RAC4		0x0012
+#define PCI_DEVICE_ID_DELL_PERC5	0x0015
+
+#define PCI_VENDOR_ID_MATROX		0x102B
+#define PCI_DEVICE_ID_MATROX_MGA_2	0x0518
+#define PCI_DEVICE_ID_MATROX_MIL	0x0519
+#define PCI_DEVICE_ID_MATROX_MYS	0x051A
+#define PCI_DEVICE_ID_MATROX_MIL_2	0x051b
+#define PCI_DEVICE_ID_MATROX_MYS_AGP	0x051e
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP	0x051f
+#define PCI_DEVICE_ID_MATROX_MGA_IMP	0x0d10
+#define PCI_DEVICE_ID_MATROX_G100_MM	0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP	0x1001
+#define PCI_DEVICE_ID_MATROX_G200_PCI	0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP	0x0521
+#define	PCI_DEVICE_ID_MATROX_G400	0x0525
+#define	PCI_DEVICE_ID_MATROX_G200EV_PCI	0x0530
+#define PCI_DEVICE_ID_MATROX_G550	0x2527
+#define PCI_DEVICE_ID_MATROX_VIA	0x4536
+
+#define PCI_VENDOR_ID_CT		0x102c
+#define PCI_DEVICE_ID_CT_69000		0x00c0
+#define PCI_DEVICE_ID_CT_65545		0x00d8
+#define PCI_DEVICE_ID_CT_65548		0x00dc
+#define PCI_DEVICE_ID_CT_65550		0x00e0
+#define PCI_DEVICE_ID_CT_65554		0x00e4
+#define PCI_DEVICE_ID_CT_65555		0x00e5
+
+#define PCI_VENDOR_ID_MIRO		0x1031
+#define PCI_DEVICE_ID_MIRO_36050	0x5601
+#define PCI_DEVICE_ID_MIRO_DC10PLUS	0x7efe
+#define PCI_DEVICE_ID_MIRO_DC30PLUS	0xd801
+
+#define PCI_VENDOR_ID_NEC		0x1033
+#define PCI_DEVICE_ID_NEC_CBUS_1	0x0001 /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_LOCAL		0x0002 /* Local Bridge */
+#define PCI_DEVICE_ID_NEC_ATM		0x0003 /* ATM LAN Controller */
+#define PCI_DEVICE_ID_NEC_R4000		0x0004 /* R4000 Bridge */
+#define PCI_DEVICE_ID_NEC_486		0x0005 /* 486 Like Peripheral Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_1	0x0006 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_UXBUS		0x0007 /* UX-Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_2	0x0008 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_GRAPH		0x0009 /* PCI-CoreGraph Bridge */
+#define PCI_DEVICE_ID_NEC_VL		0x0016 /* PCI-VL Bridge */
+#define PCI_DEVICE_ID_NEC_STARALPHA2	0x002c /* STAR ALPHA2 */
+#define PCI_DEVICE_ID_NEC_CBUS_2	0x002d /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_USB		0x0035 /* PCI-USB Host */
+#define PCI_DEVICE_ID_NEC_CBUS_3	0x003b
+#define PCI_DEVICE_ID_NEC_NAPCCARD	0x003e
+#define PCI_DEVICE_ID_NEC_PCX2		0x0046 /* PowerVR */
+#define PCI_DEVICE_ID_NEC_VRC5476       0x009b
+#define PCI_DEVICE_ID_NEC_VRC4173	0x00a5
+#define PCI_DEVICE_ID_NEC_VRC5477_AC97  0x00a6
+#define PCI_DEVICE_ID_NEC_PC9821CS01    0x800c /* PC-9821-CS01 */
+#define PCI_DEVICE_ID_NEC_PC9821NRB06   0x800d /* PC-9821NR-B06 */
+
+#define PCI_VENDOR_ID_FD		0x1036
+#define PCI_DEVICE_ID_FD_36C70		0x0000
+
+#define PCI_VENDOR_ID_SI		0x1039
+#define PCI_DEVICE_ID_SI_5591_AGP	0x0001
+#define PCI_DEVICE_ID_SI_6202		0x0002
+#define PCI_DEVICE_ID_SI_503		0x0008
+#define PCI_DEVICE_ID_SI_ACPI		0x0009
+#define PCI_DEVICE_ID_SI_SMBUS		0x0016
+#define PCI_DEVICE_ID_SI_LPC		0x0018
+#define PCI_DEVICE_ID_SI_5597_VGA	0x0200
+#define PCI_DEVICE_ID_SI_6205		0x0205
+#define PCI_DEVICE_ID_SI_501		0x0406
+#define PCI_DEVICE_ID_SI_496		0x0496
+#define PCI_DEVICE_ID_SI_300		0x0300
+#define PCI_DEVICE_ID_SI_315H		0x0310
+#define PCI_DEVICE_ID_SI_315		0x0315
+#define PCI_DEVICE_ID_SI_315PRO		0x0325
+#define PCI_DEVICE_ID_SI_530		0x0530
+#define PCI_DEVICE_ID_SI_540		0x0540
+#define PCI_DEVICE_ID_SI_550		0x0550
+#define PCI_DEVICE_ID_SI_540_VGA	0x5300
+#define PCI_DEVICE_ID_SI_550_VGA	0x5315
+#define PCI_DEVICE_ID_SI_620		0x0620
+#define PCI_DEVICE_ID_SI_630		0x0630
+#define PCI_DEVICE_ID_SI_633		0x0633
+#define PCI_DEVICE_ID_SI_635		0x0635
+#define PCI_DEVICE_ID_SI_640		0x0640
+#define PCI_DEVICE_ID_SI_645		0x0645
+#define PCI_DEVICE_ID_SI_646		0x0646
+#define PCI_DEVICE_ID_SI_648		0x0648
+#define PCI_DEVICE_ID_SI_650		0x0650
+#define PCI_DEVICE_ID_SI_651		0x0651
+#define PCI_DEVICE_ID_SI_655		0x0655
+#define PCI_DEVICE_ID_SI_661		0x0661
+#define PCI_DEVICE_ID_SI_730		0x0730
+#define PCI_DEVICE_ID_SI_733		0x0733
+#define PCI_DEVICE_ID_SI_630_VGA	0x6300
+#define PCI_DEVICE_ID_SI_735		0x0735
+#define PCI_DEVICE_ID_SI_740		0x0740
+#define PCI_DEVICE_ID_SI_741		0x0741
+#define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_746		0x0746
+#define PCI_DEVICE_ID_SI_755		0x0755
+#define PCI_DEVICE_ID_SI_760		0x0760
+#define PCI_DEVICE_ID_SI_900		0x0900
+#define PCI_DEVICE_ID_SI_961		0x0961
+#define PCI_DEVICE_ID_SI_962		0x0962
+#define PCI_DEVICE_ID_SI_963		0x0963
+#define PCI_DEVICE_ID_SI_965		0x0965
+#define PCI_DEVICE_ID_SI_966		0x0966
+#define PCI_DEVICE_ID_SI_968		0x0968
+#define PCI_DEVICE_ID_SI_1180		0x1180
+#define PCI_DEVICE_ID_SI_5511		0x5511
+#define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5517		0x5517
+#define PCI_DEVICE_ID_SI_5518		0x5518
+#define PCI_DEVICE_ID_SI_5571		0x5571
+#define PCI_DEVICE_ID_SI_5581		0x5581
+#define PCI_DEVICE_ID_SI_5582		0x5582
+#define PCI_DEVICE_ID_SI_5591		0x5591
+#define PCI_DEVICE_ID_SI_5596		0x5596
+#define PCI_DEVICE_ID_SI_5597		0x5597
+#define PCI_DEVICE_ID_SI_5598		0x5598
+#define PCI_DEVICE_ID_SI_5600		0x5600
+#define PCI_DEVICE_ID_SI_7012		0x7012
+#define PCI_DEVICE_ID_SI_7013		0x7013
+#define PCI_DEVICE_ID_SI_7016		0x7016
+#define PCI_DEVICE_ID_SI_7018		0x7018
+
+#define PCI_VENDOR_ID_HP		0x103c
+#define PCI_DEVICE_ID_HP_VISUALIZE_EG	0x1005
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX6	0x1006
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX4	0x1008
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX2	0x100a
+#define PCI_DEVICE_ID_HP_TACHYON	0x1028
+#define PCI_DEVICE_ID_HP_TACHLITE	0x1029
+#define PCI_DEVICE_ID_HP_J2585A		0x1030
+#define PCI_DEVICE_ID_HP_J2585B		0x1031
+#define PCI_DEVICE_ID_HP_J2973A		0x1040
+#define PCI_DEVICE_ID_HP_J2970A		0x1042
+#define PCI_DEVICE_ID_HP_DIVA		0x1048
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1	0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2	0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO	0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC	0x10f1
+#define PCI_DEVICE_ID_HP_VISUALIZE_FXE	0x108b
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME	0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE	0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR	0x1227
+#define PCI_DEVICE_ID_HP_ZX1_IOC	0x122a
+#define PCI_DEVICE_ID_HP_PCIX_LBA	0x122e
+#define PCI_DEVICE_ID_HP_SX1000_IOC	0x127c
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST	0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX	0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3	0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE	0x132a
+#define PCI_DEVICE_ID_HP_CISSA		0x3220
+#define PCI_DEVICE_ID_HP_CISSC		0x3230
+#define PCI_DEVICE_ID_HP_CISSD		0x3238
+#define PCI_DEVICE_ID_HP_CISSE		0x323a
+#define PCI_DEVICE_ID_HP_ZX2_IOC	0x4031
+
+#define PCI_VENDOR_ID_PCTECH		0x1042
+#define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
+#define PCI_DEVICE_ID_PCTECH_RZ1001	0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
+
+#define PCI_VENDOR_ID_ASUSTEK		0x1043
+#define PCI_DEVICE_ID_ASUSTEK_0675	0x0675
+
+#define PCI_VENDOR_ID_DPT		0x1044
+#define PCI_DEVICE_ID_DPT		0xa400
+
+#define PCI_VENDOR_ID_OPTI		0x1045
+#define PCI_DEVICE_ID_OPTI_82C558	0xc558
+#define PCI_DEVICE_ID_OPTI_82C621	0xc621
+#define PCI_DEVICE_ID_OPTI_82C700	0xc700
+#define PCI_DEVICE_ID_OPTI_82C825	0xd568
+
+#define PCI_VENDOR_ID_ELSA		0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK	0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000	0x3000
+
+#define PCI_VENDOR_ID_BUSLOGIC		      0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER    0x1040
+#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT     0x8130
+
+#define PCI_VENDOR_ID_TI		0x104c
+#define PCI_DEVICE_ID_TI_TVP4020	0x3d07
+#define PCI_DEVICE_ID_TI_4450		0x8011
+#define PCI_DEVICE_ID_TI_TSB43AB22	0x8023
+#define PCI_DEVICE_ID_TI_XX21_XX11	0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM	0x8033
+#define PCI_DEVICE_ID_TI_XX21_XX11_SD	0x8034
+#define PCI_DEVICE_ID_TI_X515		0x8036
+#define PCI_DEVICE_ID_TI_XX12		0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM	0x803b
+#define PCI_DEVICE_ID_TI_1130		0xac12
+#define PCI_DEVICE_ID_TI_1031		0xac13
+#define PCI_DEVICE_ID_TI_1131		0xac15
+#define PCI_DEVICE_ID_TI_1250		0xac16
+#define PCI_DEVICE_ID_TI_1220		0xac17
+#define PCI_DEVICE_ID_TI_1221		0xac19
+#define PCI_DEVICE_ID_TI_1210		0xac1a
+#define PCI_DEVICE_ID_TI_1450		0xac1b
+#define PCI_DEVICE_ID_TI_1225		0xac1c
+#define PCI_DEVICE_ID_TI_1251A		0xac1d
+#define PCI_DEVICE_ID_TI_1211		0xac1e
+#define PCI_DEVICE_ID_TI_1251B		0xac1f
+#define PCI_DEVICE_ID_TI_4410		0xac41
+#define PCI_DEVICE_ID_TI_4451		0xac42
+#define PCI_DEVICE_ID_TI_4510		0xac44
+#define PCI_DEVICE_ID_TI_4520		0xac46
+#define PCI_DEVICE_ID_TI_7510		0xac47
+#define PCI_DEVICE_ID_TI_7610		0xac48
+#define PCI_DEVICE_ID_TI_7410		0xac49
+#define PCI_DEVICE_ID_TI_1410		0xac50
+#define PCI_DEVICE_ID_TI_1420		0xac51
+#define PCI_DEVICE_ID_TI_1451A		0xac52
+#define PCI_DEVICE_ID_TI_1620		0xac54
+#define PCI_DEVICE_ID_TI_1520		0xac55
+#define PCI_DEVICE_ID_TI_1510		0xac56
+#define PCI_DEVICE_ID_TI_X620		0xac8d
+#define PCI_DEVICE_ID_TI_X420		0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM	0xac8f
+
+#define PCI_VENDOR_ID_SONY		0x104d
+
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2		0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940F	0x5a5a
+#define PCI_DEVICE_ID_WINBOND2_6692	0x6692
+
+#define PCI_VENDOR_ID_ANIGMA		0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575	0x0100
+  
+#define PCI_VENDOR_ID_EFAR		0x1055
+#define PCI_DEVICE_ID_EFAR_SLC90E66_1	0x9130
+#define PCI_DEVICE_ID_EFAR_SLC90E66_3	0x9463
+
+#define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
+#define PCI_DEVICE_ID_MOTOROLA_MPC107	0x0004
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
+#define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
+#define PCI_DEVICE_ID_MOTOROLA_HARRIER	0x480b
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200	0x5803
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200B	0x5809
+
+#define PCI_VENDOR_ID_PROMISE		0x105a
+#define PCI_DEVICE_ID_PROMISE_20265	0x0d30
+#define PCI_DEVICE_ID_PROMISE_20267	0x4d30
+#define PCI_DEVICE_ID_PROMISE_20246	0x4d33
+#define PCI_DEVICE_ID_PROMISE_20262	0x4d38
+#define PCI_DEVICE_ID_PROMISE_20263	0x0D38
+#define PCI_DEVICE_ID_PROMISE_20268	0x4d68
+#define PCI_DEVICE_ID_PROMISE_20269	0x4d69
+#define PCI_DEVICE_ID_PROMISE_20270	0x6268
+#define PCI_DEVICE_ID_PROMISE_20271	0x6269
+#define PCI_DEVICE_ID_PROMISE_20275	0x1275
+#define PCI_DEVICE_ID_PROMISE_20276	0x5275
+#define PCI_DEVICE_ID_PROMISE_20277	0x7275
+
+#define PCI_VENDOR_ID_UMC		0x1060
+#define PCI_DEVICE_ID_UMC_UM8673F	0x0101
+#define PCI_DEVICE_ID_UMC_UM8886BF	0x673a
+#define PCI_DEVICE_ID_UMC_UM8886A	0x886a
+
+#define PCI_VENDOR_ID_PICOPOWER		0x1066
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523	0x0002
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP	0x8002
+
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960_P	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960_PD	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960_PG	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960_LA	0x0020
+#define PCI_DEVICE_ID_MYLEX_DAC960_LP	0x0050
+#define PCI_DEVICE_ID_MYLEX_DAC960_BA	0xBA56
+#define PCI_DEVICE_ID_MYLEX_DAC960_GEM	0xB166
+
+#define PCI_VENDOR_ID_APPLE		0x106b
+#define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
+#define PCI_DEVICE_ID_APPLE_HYDRA	0x000e
+#define PCI_DEVICE_ID_APPLE_UNI_N_FW	0x0018
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP	0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC	0x0021
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP	0x0024
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P	0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15	0x002d
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15	0x002e
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2	0x0032
+#define PCI_DEVICE_ID_APPLE_UNI_N_ATA	0x0033
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2	0x0034
+#define PCI_DEVICE_ID_APPLE_IPID_ATA100	0x003b
+#define PCI_DEVICE_ID_APPLE_K2_ATA100	0x0043
+#define PCI_DEVICE_ID_APPLE_U3_AGP	0x004b
+#define PCI_DEVICE_ID_APPLE_K2_GMAC	0x004c
+#define PCI_DEVICE_ID_APPLE_SH_ATA      0x0050
+#define PCI_DEVICE_ID_APPLE_SH_SUNGEM   0x0051
+#define PCI_DEVICE_ID_APPLE_U3L_AGP	0x0058
+#define PCI_DEVICE_ID_APPLE_U3H_AGP	0x0059
+#define PCI_DEVICE_ID_APPLE_IPID2_AGP	0x0066
+#define PCI_DEVICE_ID_APPLE_IPID2_ATA	0x0069
+#define PCI_DEVICE_ID_APPLE_IPID2_FW	0x006a
+#define PCI_DEVICE_ID_APPLE_IPID2_GMAC	0x006b
+#define PCI_DEVICE_ID_APPLE_TIGON3	0x1645
+
+#define PCI_VENDOR_ID_YAMAHA		0x1073
+#define PCI_DEVICE_ID_YAMAHA_724	0x0004
+#define PCI_DEVICE_ID_YAMAHA_724F	0x000d
+#define PCI_DEVICE_ID_YAMAHA_740	0x000a
+#define PCI_DEVICE_ID_YAMAHA_740C	0x000c
+#define PCI_DEVICE_ID_YAMAHA_744	0x0010
+#define PCI_DEVICE_ID_YAMAHA_754	0x0012
+
+#define PCI_VENDOR_ID_QLOGIC		0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP10160	0x1016
+#define PCI_DEVICE_ID_QLOGIC_ISP1020	0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1080	0x1080
+#define PCI_DEVICE_ID_QLOGIC_ISP12160	0x1216
+#define PCI_DEVICE_ID_QLOGIC_ISP1240	0x1240
+#define PCI_DEVICE_ID_QLOGIC_ISP1280	0x1280
+#define PCI_DEVICE_ID_QLOGIC_ISP2100	0x2100
+#define PCI_DEVICE_ID_QLOGIC_ISP2200	0x2200
+#define PCI_DEVICE_ID_QLOGIC_ISP2300	0x2300
+#define PCI_DEVICE_ID_QLOGIC_ISP2312	0x2312
+#define PCI_DEVICE_ID_QLOGIC_ISP2322	0x2322
+#define PCI_DEVICE_ID_QLOGIC_ISP6312	0x6312
+#define PCI_DEVICE_ID_QLOGIC_ISP6322	0x6322
+#define PCI_DEVICE_ID_QLOGIC_ISP2422	0x2422
+#define PCI_DEVICE_ID_QLOGIC_ISP2432	0x2432
+#define PCI_DEVICE_ID_QLOGIC_ISP2512	0x2512
+#define PCI_DEVICE_ID_QLOGIC_ISP2522	0x2522
+#define PCI_DEVICE_ID_QLOGIC_ISP5422	0x5422
+#define PCI_DEVICE_ID_QLOGIC_ISP5432	0x5432
+
+#define PCI_VENDOR_ID_CYRIX		0x1078
+#define PCI_DEVICE_ID_CYRIX_5510	0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER	0x0001
+#define PCI_DEVICE_ID_CYRIX_5520	0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY	0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_IDE	0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO	0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO	0x0104
+
+#define PCI_VENDOR_ID_CONTAQ		0x1080
+#define PCI_DEVICE_ID_CONTAQ_82C693	0xc693
+
+#define PCI_VENDOR_ID_OLICOM		0x108d
+#define PCI_DEVICE_ID_OLICOM_OC2325	0x0012
+#define PCI_DEVICE_ID_OLICOM_OC2183	0x0013
+#define PCI_DEVICE_ID_OLICOM_OC2326	0x0014
+
+#define PCI_VENDOR_ID_SUN		0x108e
+#define PCI_DEVICE_ID_SUN_EBUS		0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL	0x1001
+#define PCI_DEVICE_ID_SUN_RIO_EBUS	0x1100
+#define PCI_DEVICE_ID_SUN_RIO_GEM	0x1101
+#define PCI_DEVICE_ID_SUN_RIO_1394	0x1102
+#define PCI_DEVICE_ID_SUN_RIO_USB	0x1103
+#define PCI_DEVICE_ID_SUN_GEM		0x2bad
+#define PCI_DEVICE_ID_SUN_SIMBA		0x5000
+#define PCI_DEVICE_ID_SUN_PBM		0x8000
+#define PCI_DEVICE_ID_SUN_SCHIZO	0x8001
+#define PCI_DEVICE_ID_SUN_SABRE		0xa000
+#define PCI_DEVICE_ID_SUN_HUMMINGBIRD	0xa001
+#define PCI_DEVICE_ID_SUN_TOMATILLO	0xa801
+#define PCI_DEVICE_ID_SUN_CASSINI	0xabba
+
+#define PCI_VENDOR_ID_CMD		0x1095
+#define PCI_DEVICE_ID_CMD_643		0x0643
+#define PCI_DEVICE_ID_CMD_646		0x0646
+#define PCI_DEVICE_ID_CMD_648		0x0648
+#define PCI_DEVICE_ID_CMD_649		0x0649
+
+#define PCI_DEVICE_ID_SII_680		0x0680
+#define PCI_DEVICE_ID_SII_3112		0x3112
+#define PCI_DEVICE_ID_SII_1210SA	0x0240
+
+#define PCI_VENDOR_ID_BROOKTREE		0x109e
+#define PCI_DEVICE_ID_BROOKTREE_878	0x0878
+#define PCI_DEVICE_ID_BROOKTREE_879	0x0879
+
+#define PCI_VENDOR_ID_SGI		0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3		0x0003
+#define PCI_DEVICE_ID_SGI_LITHIUM	0x1002
+#define PCI_DEVICE_ID_SGI_IOC4		0x100a
+
+#define PCI_VENDOR_ID_WINBOND		0x10ad
+#define PCI_DEVICE_ID_WINBOND_82C105	0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553	0x0565
+
+#define PCI_VENDOR_ID_PLX		0x10b5
+#define PCI_DEVICE_ID_PLX_R685		0x1030
+#define PCI_DEVICE_ID_PLX_ROMULUS	0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800	0x1076
+#define PCI_DEVICE_ID_PLX_1077		0x1077
+#define PCI_DEVICE_ID_PLX_SPCOM200	0x1103
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO	0x1151
+#define PCI_DEVICE_ID_PLX_R753		0x1152
+#define PCI_DEVICE_ID_PLX_OLITEC	0x1187
+#define PCI_DEVICE_ID_PLX_PCI200SYN	0x3196
+#define PCI_DEVICE_ID_PLX_9030          0x9030
+#define PCI_DEVICE_ID_PLX_9050		0x9050
+#define PCI_DEVICE_ID_PLX_9080		0x9080
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2	0xa001
+
+#define PCI_VENDOR_ID_MADGE		0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2		0x0002
+
+#define PCI_VENDOR_ID_3COM		0x10b7
+#define PCI_DEVICE_ID_3COM_3C985	0x0001
+#define PCI_DEVICE_ID_3COM_3C940	0x1700
+#define PCI_DEVICE_ID_3COM_3C339	0x3390
+#define PCI_DEVICE_ID_3COM_3C359	0x3590
+#define PCI_DEVICE_ID_3COM_3C940B	0x80eb
+#define PCI_DEVICE_ID_3COM_3CR990	0x9900
+#define PCI_DEVICE_ID_3COM_3CR990_TX_95	0x9902
+#define PCI_DEVICE_ID_3COM_3CR990_TX_97	0x9903
+#define PCI_DEVICE_ID_3COM_3CR990B	0x9904
+#define PCI_DEVICE_ID_3COM_3CR990_FX	0x9905
+#define PCI_DEVICE_ID_3COM_3CR990SVR95	0x9908
+#define PCI_DEVICE_ID_3COM_3CR990SVR97	0x9909
+#define PCI_DEVICE_ID_3COM_3CR990SVR	0x990a
+
+#define PCI_VENDOR_ID_AL		0x10b9
+#define PCI_DEVICE_ID_AL_M1533		0x1533
+#define PCI_DEVICE_ID_AL_M1535 		0x1535
+#define PCI_DEVICE_ID_AL_M1541		0x1541
+#define PCI_DEVICE_ID_AL_M1563		0x1563
+#define PCI_DEVICE_ID_AL_M1621		0x1621
+#define PCI_DEVICE_ID_AL_M1631		0x1631
+#define PCI_DEVICE_ID_AL_M1632		0x1632
+#define PCI_DEVICE_ID_AL_M1641		0x1641
+#define PCI_DEVICE_ID_AL_M1644		0x1644
+#define PCI_DEVICE_ID_AL_M1647		0x1647
+#define PCI_DEVICE_ID_AL_M1651		0x1651
+#define PCI_DEVICE_ID_AL_M1671		0x1671
+#define PCI_DEVICE_ID_AL_M1681		0x1681
+#define PCI_DEVICE_ID_AL_M1683		0x1683
+#define PCI_DEVICE_ID_AL_M1689		0x1689
+#define PCI_DEVICE_ID_AL_M5219		0x5219
+#define PCI_DEVICE_ID_AL_M5228		0x5228
+#define PCI_DEVICE_ID_AL_M5229		0x5229
+#define PCI_DEVICE_ID_AL_M5451		0x5451
+#define PCI_DEVICE_ID_AL_M7101		0x7101
+
+#define PCI_VENDOR_ID_NEOMAGIC		0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
+#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
+#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
+
+#define PCI_VENDOR_ID_TCONRAD		0x10da
+#define PCI_DEVICE_ID_TCONRAD_TOKENRING	0x0508
+
+#define PCI_VENDOR_ID_NVIDIA			0x10de
+#define PCI_DEVICE_ID_NVIDIA_TNT		0x0020
+#define PCI_DEVICE_ID_NVIDIA_TNT2		0x0028
+#define PCI_DEVICE_ID_NVIDIA_UTNT2		0x0029
+#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN        0x002a
+#define PCI_DEVICE_ID_NVIDIA_VTNT2		0x002C
+#define PCI_DEVICE_ID_NVIDIA_UVTNT2		0x002D
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS	0x0034
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE	0x0035
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA	0x0036
+#define PCI_DEVICE_ID_NVIDIA_NVENET_10		0x0037
+#define PCI_DEVICE_ID_NVIDIA_NVENET_11		0x0038
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2	0x003e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800       0x0041
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE    0x0042
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT    0x0045
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000     0x004E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS	0x0052
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE	0x0053
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA	0x0054
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2	0x0055
+#define PCI_DEVICE_ID_NVIDIA_NVENET_8		0x0056
+#define PCI_DEVICE_ID_NVIDIA_NVENET_9		0x0057
+#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO	0x0059
+#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE		0x005d
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS	0x0064
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE	0x0065
+#define PCI_DEVICE_ID_NVIDIA_NVENET_2		0x0066
+#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM		0x0069
+#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO		0x006a
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS	0x0084
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE	0x0085
+#define PCI_DEVICE_ID_NVIDIA_NVENET_4		0x0086
+#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM	0x0089
+#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO		0x008a
+#define PCI_DEVICE_ID_NVIDIA_NVENET_5		0x008c
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA	0x008e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT   0x0090
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX	0x0091
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800   0x0098
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099
+#define PCI_DEVICE_ID_NVIDIA_ITNT2		0x00A0
+#define PCI_DEVICE_ID_GEFORCE_6800A             0x00c1
+#define PCI_DEVICE_ID_GEFORCE_6800A_LE          0x00c2
+#define PCI_DEVICE_ID_GEFORCE_GO_6800           0x00c8
+#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA     0x00c9
+#define PCI_DEVICE_ID_QUADRO_FX_GO1400          0x00cc
+#define PCI_DEVICE_ID_QUADRO_FX_1400            0x00ce
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3		0x00d1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS	0x00d4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE	0x00d5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_3		0x00d6
+#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM		0x00d9
+#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO		0x00da
+#define PCI_DEVICE_ID_NVIDIA_NVENET_7		0x00df
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S		0x00e1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA	0x00e3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS	0x00e4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE	0x00e5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_6		0x00e6
+#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO		0x00ea
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2	0x00ee
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT   0x00f9
+#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280	0x00fd
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR	0x0100
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR	0x0101
+#define PCI_DEVICE_ID_NVIDIA_QUADRO		0x0103
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX	0x0110
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2	0x0111
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO	0x0112
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR	0x0113
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT	0x0140
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600	0x0141
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL	0x0145
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540	0x014E
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200	0x014F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS	0x0150
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2	0x0151
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200    0x0164
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250    0x0166
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1  0x0167
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1  0x0168
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460	0x0170
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440	0x0171
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420	0x0172
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE	0x0173
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO	0x0174
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO	0x0175
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO    0x0177
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL	0x0178
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200	0x017A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL	0x017B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL	0x017C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000   0x0185
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO    0x0186
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO    0x0187
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL    0x0188
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC    0x0189
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS    0x018A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL    0x018B
+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE		0x01a4
+#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO		0x01b1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS	0x01b4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
+#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM		0x01c1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_1		0x01c3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2		0x01e0
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC		0x0203
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B      0x0211
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE   0x0212
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT   0x0215
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600	0x0250
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400	0x0251
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200	0x0253
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL	0x0258
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL	0x0259
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL	0x025B
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS	0x0264
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE	0x0265
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA	0x0266
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2	0x0267
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS	0x0368
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE	0x036E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA	0x037E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2	0x037F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_12		0x0268
+#define PCI_DEVICE_ID_NVIDIA_NVENET_13		0x0269
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800	0x0280
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X    0x0281
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE     0x0282
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO       0x0286
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL        0x0288
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL        0x0289
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL       0x028C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA  0x0301
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800        0x0302
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000         0x0308
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000         0x0309
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA  0x0311
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600        0x0312
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE      0x0314
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600      0x031A
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650      0x031B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700        0x031C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200        0x0320
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA  0x0321
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1      0x0322
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE      0x0323
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200      0x0324
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250      0x0325
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500        0x0326
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100        0x0327
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32   0x0328
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200	    0x0329
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI     0x032A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500          0x032B
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300      0x032C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100      0x032D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA  0x0330
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900        0x0331
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT      0x0332
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA  0x0333
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT      0x0334
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000         0x0338
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700          0x033F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA  0x0341
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700        0x0342
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE      0x0343
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE      0x0344
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1    0x0347
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14              0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15              0x0373
+#define PCI_DEVICE_ID_NVIDIA_NVENET_16              0x03E5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_17              0x03E6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA      0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS	    0x03EB
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE       0x03EC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_18              0x03EE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_19              0x03EF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2     0x03F6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3     0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS	    0x0446
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE	    0x0448
+#define PCI_DEVICE_ID_NVIDIA_NVENET_20              0x0450
+#define PCI_DEVICE_ID_NVIDIA_NVENET_21              0x0451
+#define PCI_DEVICE_ID_NVIDIA_NVENET_22              0x0452
+#define PCI_DEVICE_ID_NVIDIA_NVENET_23              0x0453
+#define PCI_DEVICE_ID_NVIDIA_NVENET_24              0x054C
+#define PCI_DEVICE_ID_NVIDIA_NVENET_25              0x054D
+#define PCI_DEVICE_ID_NVIDIA_NVENET_26              0x054E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_27              0x054F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_28              0x07DC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_29              0x07DD
+#define PCI_DEVICE_ID_NVIDIA_NVENET_30              0x07DE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_31              0x07DF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE       0x0560
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE       0x056C
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE       0x0759
+#define PCI_DEVICE_ID_NVIDIA_NVENET_32              0x0760
+#define PCI_DEVICE_ID_NVIDIA_NVENET_33              0x0761
+#define PCI_DEVICE_ID_NVIDIA_NVENET_34              0x0762
+#define PCI_DEVICE_ID_NVIDIA_NVENET_35              0x0763
+#define PCI_DEVICE_ID_NVIDIA_NVENET_36              0x0AB0
+#define PCI_DEVICE_ID_NVIDIA_NVENET_37              0x0AB1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_38              0x0AB2
+#define PCI_DEVICE_ID_NVIDIA_NVENET_39              0x0AB3
+
+#define PCI_VENDOR_ID_IMS		0x10e0
+#define PCI_DEVICE_ID_IMS_TT128		0x9128
+#define PCI_DEVICE_ID_IMS_TT3D		0x9135
+
+#define PCI_VENDOR_ID_INTERG		0x10ea
+#define PCI_DEVICE_ID_INTERG_1682	0x1682
+#define PCI_DEVICE_ID_INTERG_2000	0x2000
+#define PCI_DEVICE_ID_INTERG_2010	0x2010
+#define PCI_DEVICE_ID_INTERG_5000	0x5000
+#define PCI_DEVICE_ID_INTERG_5050	0x5050
+
+#define PCI_VENDOR_ID_REALTEK		0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139	0x8139
+
+#define PCI_VENDOR_ID_XILINX		0x10ee
+#define PCI_DEVICE_ID_RME_DIGI96	0x3fc0
+#define PCI_DEVICE_ID_RME_DIGI96_8	0x3fc1
+#define PCI_DEVICE_ID_RME_DIGI96_8_PRO	0x3fc2
+#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
+
+#define PCI_VENDOR_ID_INIT		0x1101
+
+#define PCI_VENDOR_ID_CREATIVE		0x1102 /* duplicate: ECTIVA */
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1	0x0002
+
+#define PCI_VENDOR_ID_ECTIVA		0x1102 /* duplicate: CREATIVE */
+#define PCI_DEVICE_ID_ECTIVA_EV1938	0x8938
+
+#define PCI_VENDOR_ID_TTI		0x1103
+#define PCI_DEVICE_ID_TTI_HPT343	0x0003
+#define PCI_DEVICE_ID_TTI_HPT366	0x0004
+#define PCI_DEVICE_ID_TTI_HPT372	0x0005
+#define PCI_DEVICE_ID_TTI_HPT302	0x0006
+#define PCI_DEVICE_ID_TTI_HPT371	0x0007
+#define PCI_DEVICE_ID_TTI_HPT374	0x0008
+#define PCI_DEVICE_ID_TTI_HPT372N	0x0009	/* apparently a 372N variant? */
+
+#define PCI_VENDOR_ID_VIA		0x1106
+#define PCI_DEVICE_ID_VIA_8763_0	0x0198
+#define PCI_DEVICE_ID_VIA_8380_0	0x0204
+#define PCI_DEVICE_ID_VIA_3238_0	0x0238
+#define PCI_DEVICE_ID_VIA_PT880		0x0258
+#define PCI_DEVICE_ID_VIA_PT880ULTRA	0x0308
+#define PCI_DEVICE_ID_VIA_PX8X0_0	0x0259
+#define PCI_DEVICE_ID_VIA_3269_0	0x0269
+#define PCI_DEVICE_ID_VIA_K8T800PRO_0	0x0282
+#define PCI_DEVICE_ID_VIA_3296_0	0x0296
+#define PCI_DEVICE_ID_VIA_8363_0	0x0305
+#define PCI_DEVICE_ID_VIA_P4M800CE	0x0314
+#define PCI_DEVICE_ID_VIA_P4M890	0x0327
+#define PCI_DEVICE_ID_VIA_VT3324	0x0324
+#define PCI_DEVICE_ID_VIA_VT3336	0x0336
+#define PCI_DEVICE_ID_VIA_VT3351	0x0351
+#define PCI_DEVICE_ID_VIA_VT3364	0x0364
+#define PCI_DEVICE_ID_VIA_8371_0	0x0391
+#define PCI_DEVICE_ID_VIA_8501_0	0x0501
+#define PCI_DEVICE_ID_VIA_82C561	0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1	0x0571
+#define PCI_DEVICE_ID_VIA_82C576	0x0576
+#define PCI_DEVICE_ID_VIA_82C586_0	0x0586
+#define PCI_DEVICE_ID_VIA_82C596	0x0596
+#define PCI_DEVICE_ID_VIA_82C597_0	0x0597
+#define PCI_DEVICE_ID_VIA_82C598_0	0x0598
+#define PCI_DEVICE_ID_VIA_8601_0	0x0601
+#define PCI_DEVICE_ID_VIA_8605_0	0x0605
+#define PCI_DEVICE_ID_VIA_82C686	0x0686
+#define PCI_DEVICE_ID_VIA_82C691_0	0x0691
+#define PCI_DEVICE_ID_VIA_82C576_1	0x1571
+#define PCI_DEVICE_ID_VIA_82C586_2	0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3	0x3040
+#define PCI_DEVICE_ID_VIA_82C596_3	0x3050
+#define PCI_DEVICE_ID_VIA_82C596B_3	0x3051
+#define PCI_DEVICE_ID_VIA_82C686_4	0x3057
+#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
+#define PCI_DEVICE_ID_VIA_8233_5	0x3059
+#define PCI_DEVICE_ID_VIA_8233_0	0x3074
+#define PCI_DEVICE_ID_VIA_8633_0	0x3091
+#define PCI_DEVICE_ID_VIA_8367_0	0x3099
+#define PCI_DEVICE_ID_VIA_8653_0	0x3101
+#define PCI_DEVICE_ID_VIA_8622		0x3102
+#define PCI_DEVICE_ID_VIA_8235_USB_2	0x3104
+#define PCI_DEVICE_ID_VIA_8233C_0	0x3109
+#define PCI_DEVICE_ID_VIA_8361		0x3112
+#define PCI_DEVICE_ID_VIA_XM266		0x3116
+#define PCI_DEVICE_ID_VIA_612X		0x3119
+#define PCI_DEVICE_ID_VIA_862X_0	0x3123
+#define PCI_DEVICE_ID_VIA_8753_0	0x3128
+#define PCI_DEVICE_ID_VIA_8233A		0x3147
+#define PCI_DEVICE_ID_VIA_8703_51_0	0x3148
+#define PCI_DEVICE_ID_VIA_8237_SATA	0x3149
+#define PCI_DEVICE_ID_VIA_XN266		0x3156
+#define PCI_DEVICE_ID_VIA_6410		0x3164
+#define PCI_DEVICE_ID_VIA_8754C_0	0x3168
+#define PCI_DEVICE_ID_VIA_8235		0x3177
+#define PCI_DEVICE_ID_VIA_8385_0	0x3188
+#define PCI_DEVICE_ID_VIA_8377_0	0x3189
+#define PCI_DEVICE_ID_VIA_8378_0	0x3205
+#define PCI_DEVICE_ID_VIA_8783_0	0x3208
+#define PCI_DEVICE_ID_VIA_8237		0x3227
+#define PCI_DEVICE_ID_VIA_8251		0x3287
+#define PCI_DEVICE_ID_VIA_8237A		0x3337
+#define PCI_DEVICE_ID_VIA_8237S		0x3372
+#define PCI_DEVICE_ID_VIA_SATA_EIDE	0x5324
+#define PCI_DEVICE_ID_VIA_8231		0x8231
+#define PCI_DEVICE_ID_VIA_8231_4	0x8235
+#define PCI_DEVICE_ID_VIA_8365_1	0x8305
+#define PCI_DEVICE_ID_VIA_CX700		0x8324
+#define PCI_DEVICE_ID_VIA_CX700_IDE	0x0581
+#define PCI_DEVICE_ID_VIA_VX800		0x8353
+#define PCI_DEVICE_ID_VIA_8371_1	0x8391
+#define PCI_DEVICE_ID_VIA_82C598_1	0x8598
+#define PCI_DEVICE_ID_VIA_838X_1	0xB188
+#define PCI_DEVICE_ID_VIA_83_87XX_1	0xB198
+
+#define PCI_VENDOR_ID_SIEMENS           0x110A
+#define PCI_DEVICE_ID_SIEMENS_DSCC4     0x2102
+
+#define PCI_VENDOR_ID_VORTEX		0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT60x0	0x0000
+#define PCI_DEVICE_ID_VORTEX_GDT6000B	0x0001
+#define PCI_DEVICE_ID_VORTEX_GDT6x10	0x0002
+#define PCI_DEVICE_ID_VORTEX_GDT6x20	0x0003
+#define PCI_DEVICE_ID_VORTEX_GDT6530	0x0004
+#define PCI_DEVICE_ID_VORTEX_GDT6550	0x0005
+#define PCI_DEVICE_ID_VORTEX_GDT6x17	0x0006
+#define PCI_DEVICE_ID_VORTEX_GDT6x27	0x0007
+#define PCI_DEVICE_ID_VORTEX_GDT6537	0x0008
+#define PCI_DEVICE_ID_VORTEX_GDT6557	0x0009
+#define PCI_DEVICE_ID_VORTEX_GDT6x15	0x000a
+#define PCI_DEVICE_ID_VORTEX_GDT6x25	0x000b
+#define PCI_DEVICE_ID_VORTEX_GDT6535	0x000c
+#define PCI_DEVICE_ID_VORTEX_GDT6555	0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP	0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP	0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP	0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP	0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP	0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP	0x0105
+
+#define PCI_VENDOR_ID_EF		0x111a
+#define PCI_DEVICE_ID_EF_ATM_FPGA	0x0000
+#define PCI_DEVICE_ID_EF_ATM_ASIC	0x0002
+#define PCI_DEVICE_ID_EF_ATM_LANAI2	0x0003
+#define PCI_DEVICE_ID_EF_ATM_LANAIHB	0x0005
+
+#define PCI_VENDOR_ID_IDT		0x111d
+#define PCI_DEVICE_ID_IDT_IDT77201	0x0001
+
+#define PCI_VENDOR_ID_FORE		0x1127
+#define PCI_DEVICE_ID_FORE_PCA200E	0x0300
+
+#define PCI_VENDOR_ID_PHILIPS		0x1131
+#define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
+#define PCI_DEVICE_ID_PHILIPS_SAA9730	0x9730
+
+#define PCI_VENDOR_ID_EICON		0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20	0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20_U	0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201	0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202	0xe00b
+#define PCI_DEVICE_ID_EICON_MAESTRA	0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP	0xe014
+
+#define PCI_VENDOR_ID_CISCO		0x1137
+
+#define PCI_VENDOR_ID_ZIATECH		0x1138
+#define PCI_DEVICE_ID_ZIATECH_5550_HC	0x5550
+ 
+
+#define PCI_VENDOR_ID_SYSKONNECT	0x1148
+#define PCI_DEVICE_ID_SYSKONNECT_TR	0x4200
+#define PCI_DEVICE_ID_SYSKONNECT_GE	0x4300
+#define PCI_DEVICE_ID_SYSKONNECT_YU	0x4320
+#define PCI_DEVICE_ID_SYSKONNECT_9DXX	0x4400
+#define PCI_DEVICE_ID_SYSKONNECT_9MXX	0x4500
+
+#define PCI_VENDOR_ID_DIGI		0x114f
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E	0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E	0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A	0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A	0x0073
+#define PCI_DEVICE_ID_NEO_2DB9          0x00C8
+#define PCI_DEVICE_ID_NEO_2DB9PRI       0x00C9
+#define PCI_DEVICE_ID_NEO_2RJ45         0x00CA
+#define PCI_DEVICE_ID_NEO_2RJ45PRI      0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM        0x00F4
+
+#define PCI_VENDOR_ID_XIRCOM		0x115d
+#define PCI_DEVICE_ID_XIRCOM_RBM56G	0x0101
+#define PCI_DEVICE_ID_XIRCOM_X3201_MDM	0x0103
+
+#define PCI_VENDOR_ID_SERVERWORKS	  0x1166
+#define PCI_DEVICE_ID_SERVERWORKS_HE	  0x0008
+#define PCI_DEVICE_ID_SERVERWORKS_LE	  0x0009
+#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB	0x0036
+#define PCI_DEVICE_ID_SERVERWORKS_EPB	  0x0103
+#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE	0x0132
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4	  0x0200
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5	  0x0201
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6    0x0203
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
+
+#define PCI_VENDOR_ID_SBE		0x1176
+#define PCI_DEVICE_ID_SBE_WANXL100	0x0301
+#define PCI_DEVICE_ID_SBE_WANXL200	0x0302
+#define PCI_DEVICE_ID_SBE_WANXL400	0x0104
+
+#define PCI_VENDOR_ID_TOSHIBA		0x1179
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO	0x0102
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1	0x0103
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2	0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC100	0x0617
+
+#define PCI_VENDOR_ID_TOSHIBA_2		0x102f
+#define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU	0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939	0x0032
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
+#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
+
+#define PCI_VENDOR_ID_ATTO		0x117c
+
+#define PCI_VENDOR_ID_RICOH		0x1180
+#define PCI_DEVICE_ID_RICOH_RL5C465	0x0465
+#define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
+#define PCI_DEVICE_ID_RICOH_RL5C475	0x0475
+#define PCI_DEVICE_ID_RICOH_RL5C476	0x0476
+#define PCI_DEVICE_ID_RICOH_RL5C478	0x0478
+#define PCI_DEVICE_ID_RICOH_R5C822	0x0822
+#define PCI_DEVICE_ID_RICOH_R5C832	0x0832
+#define PCI_DEVICE_ID_RICOH_R5C843	0x0843
+
+#define PCI_VENDOR_ID_DLINK		0x1186
+#define PCI_DEVICE_ID_DLINK_DGE510T	0x4c00
+
+#define PCI_VENDOR_ID_ARTOP		0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
+#define PCI_DEVICE_ID_ARTOP_ATP860	0x0006
+#define PCI_DEVICE_ID_ARTOP_ATP860R	0x0007
+#define PCI_DEVICE_ID_ARTOP_ATP865	0x0008
+#define PCI_DEVICE_ID_ARTOP_ATP865R	0x0009
+#define PCI_DEVICE_ID_ARTOP_AEC7610	0x8002
+#define PCI_DEVICE_ID_ARTOP_AEC7612UW	0x8010
+#define PCI_DEVICE_ID_ARTOP_AEC7612U	0x8020
+#define PCI_DEVICE_ID_ARTOP_AEC7612S	0x8030
+#define PCI_DEVICE_ID_ARTOP_AEC7612D	0x8040
+#define PCI_DEVICE_ID_ARTOP_AEC7612SUW	0x8050
+#define PCI_DEVICE_ID_ARTOP_8060	0x8060
+
+#define PCI_VENDOR_ID_ZEITNET		0x1193
+#define PCI_DEVICE_ID_ZEITNET_1221	0x0001
+#define PCI_DEVICE_ID_ZEITNET_1225	0x0002
+
+#define PCI_VENDOR_ID_FUJITSU_ME	0x119e
+#define PCI_DEVICE_ID_FUJITSU_FS155	0x0001
+#define PCI_DEVICE_ID_FUJITSU_FS50	0x0003
+
+#define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
+
+#define PCI_VENDOR_ID_MARVELL		0x11ab
+#define PCI_DEVICE_ID_MARVELL_GT64111	0x4146
+#define PCI_DEVICE_ID_MARVELL_GT64260	0x6430
+#define PCI_DEVICE_ID_MARVELL_MV64360	0x6460
+#define PCI_DEVICE_ID_MARVELL_MV64460	0x6480
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND	0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD	0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC	0x4102
+
+#define PCI_VENDOR_ID_V3		0x11b0
+#define PCI_DEVICE_ID_V3_V960		0x0001
+#define PCI_DEVICE_ID_V3_V351		0x0002
+
+#define PCI_VENDOR_ID_ATT		0x11c1
+#define PCI_DEVICE_ID_ATT_VENUS_MODEM	0x480
+
+#define PCI_VENDOR_ID_SPECIALIX		0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
+#define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
+#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
+
+#define PCI_VENDOR_ID_ANALOG_DEVICES	0x11d4
+#define PCI_DEVICE_ID_AD1889JS		0x1889
+
+#define PCI_DEVICE_ID_SEGA_BBA		0x1234
+
+#define PCI_VENDOR_ID_ZORAN		0x11de
+#define PCI_DEVICE_ID_ZORAN_36057	0x6057
+#define PCI_DEVICE_ID_ZORAN_36120	0x6120
+
+#define PCI_VENDOR_ID_COMPEX		0x11f6
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4	0x0112
+
+#define PCI_VENDOR_ID_RP		0x11fe
+#define PCI_DEVICE_ID_RP32INTF		0x0001
+#define PCI_DEVICE_ID_RP8INTF		0x0002
+#define PCI_DEVICE_ID_RP16INTF		0x0003
+#define PCI_DEVICE_ID_RP4QUAD		0x0004
+#define PCI_DEVICE_ID_RP8OCTA		0x0005
+#define PCI_DEVICE_ID_RP8J		0x0006
+#define PCI_DEVICE_ID_RP4J		0x0007
+#define PCI_DEVICE_ID_RP8SNI		0x0008	
+#define PCI_DEVICE_ID_RP16SNI		0x0009	
+#define PCI_DEVICE_ID_RPP4		0x000A
+#define PCI_DEVICE_ID_RPP8		0x000B
+#define PCI_DEVICE_ID_RP4M		0x000D
+#define PCI_DEVICE_ID_RP2_232		0x000E
+#define PCI_DEVICE_ID_RP2_422		0x000F
+#define PCI_DEVICE_ID_URP32INTF		0x0801
+#define PCI_DEVICE_ID_URP8INTF		0x0802
+#define PCI_DEVICE_ID_URP16INTF		0x0803
+#define PCI_DEVICE_ID_URP8OCTA		0x0805
+#define PCI_DEVICE_ID_UPCI_RM3_8PORT	0x080C       
+#define PCI_DEVICE_ID_UPCI_RM3_4PORT	0x080D
+#define PCI_DEVICE_ID_CRP16INTF		0x0903       
+
+#define PCI_VENDOR_ID_CYCLADES		0x120e
+#define PCI_DEVICE_ID_CYCLOM_Y_Lo	0x0100
+#define PCI_DEVICE_ID_CYCLOM_Y_Hi	0x0101
+#define PCI_DEVICE_ID_CYCLOM_4Y_Lo	0x0102
+#define PCI_DEVICE_ID_CYCLOM_4Y_Hi	0x0103
+#define PCI_DEVICE_ID_CYCLOM_8Y_Lo	0x0104
+#define PCI_DEVICE_ID_CYCLOM_8Y_Hi	0x0105
+#define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
+#define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
+#define PCI_DEVICE_ID_PC300_RX_2	0x0300
+#define PCI_DEVICE_ID_PC300_RX_1	0x0301
+#define PCI_DEVICE_ID_PC300_TE_2	0x0310
+#define PCI_DEVICE_ID_PC300_TE_1	0x0311
+#define PCI_DEVICE_ID_PC300_TE_M_2	0x0320
+#define PCI_DEVICE_ID_PC300_TE_M_1	0x0321
+
+#define PCI_VENDOR_ID_ESSENTIAL		0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
+
+#define PCI_VENDOR_ID_O2		0x1217
+#define PCI_DEVICE_ID_O2_6729		0x6729
+#define PCI_DEVICE_ID_O2_6730		0x673a
+#define PCI_DEVICE_ID_O2_6832		0x6832
+#define PCI_DEVICE_ID_O2_6836		0x6836
+
+#define PCI_VENDOR_ID_3DFX		0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2	0x0002
+#define PCI_DEVICE_ID_3DFX_BANSHEE	0x0003
+#define PCI_DEVICE_ID_3DFX_VOODOO3	0x0005
+#define PCI_DEVICE_ID_3DFX_VOODOO5	0x0009
+
+#define PCI_VENDOR_ID_AVM		0x1244
+#define PCI_DEVICE_ID_AVM_B1		0x0700
+#define PCI_DEVICE_ID_AVM_C4		0x0800
+#define PCI_DEVICE_ID_AVM_A1		0x0a00
+#define PCI_DEVICE_ID_AVM_A1_V2		0x0e00
+#define PCI_DEVICE_ID_AVM_C2		0x1100
+#define PCI_DEVICE_ID_AVM_T1		0x1200
+
+#define PCI_VENDOR_ID_STALLION		0x124d
+
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT    		0x1259
+#define PCI_SUBDEVICE_ID_AT_2700FX	0x2701
+#define PCI_SUBDEVICE_ID_AT_2701FX	0x2703
+
+#define PCI_VENDOR_ID_ESS		0x125d
+#define PCI_DEVICE_ID_ESS_ESS1968	0x1968
+#define PCI_DEVICE_ID_ESS_ESS1978	0x1978
+#define PCI_DEVICE_ID_ESS_ALLEGRO_1	0x1988
+#define PCI_DEVICE_ID_ESS_ALLEGRO	0x1989
+#define PCI_DEVICE_ID_ESS_CANYON3D_2LE	0x1990
+#define PCI_DEVICE_ID_ESS_CANYON3D_2	0x1992
+#define PCI_DEVICE_ID_ESS_MAESTRO3	0x1998
+#define PCI_DEVICE_ID_ESS_MAESTRO3_1	0x1999
+#define PCI_DEVICE_ID_ESS_MAESTRO3_HW	0x199a
+#define PCI_DEVICE_ID_ESS_MAESTRO3_2	0x199b
+
+#define PCI_VENDOR_ID_SATSAGEM		0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY	0x1016
+
+#define PCI_VENDOR_ID_ENSONIQ		0x1274
+#define PCI_DEVICE_ID_ENSONIQ_CT5880	0x5880
+#define PCI_DEVICE_ID_ENSONIQ_ES1370	0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371	0x1371
+
+#define PCI_VENDOR_ID_TRANSMETA		0x1279
+#define PCI_DEVICE_ID_EFFICEON		0x0060
+
+#define PCI_VENDOR_ID_ROCKWELL		0x127A
+
+#define PCI_VENDOR_ID_ITE		0x1283
+#define PCI_DEVICE_ID_ITE_8211		0x8211
+#define PCI_DEVICE_ID_ITE_8212		0x8212
+#define PCI_DEVICE_ID_ITE_8213		0x8213
+#define PCI_DEVICE_ID_ITE_8152		0x8152
+#define PCI_DEVICE_ID_ITE_8872		0x8872
+#define PCI_DEVICE_ID_ITE_IT8330G_0	0xe886
+
+/* formerly Platform Tech */
+#define PCI_DEVICE_ID_ESS_ESS0100	0x0100
+
+#define PCI_VENDOR_ID_ALTEON		0x12ae
+
+#define PCI_SUBVENDOR_ID_CONNECT_TECH			0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232		0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232		0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232		0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485		0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4	0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485		0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2	0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485		0x0008
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6	0x0009
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1	0x000A
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1	0x000B
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ		0x000C
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM		0x000D
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI		0x0100
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2		0x0201
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4		0x0202
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232	0x0300
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232	0x0301
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232	0x0302
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1	0x0310
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2	0x0311
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4	0x0312
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2	0x0320
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4	0x0321
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8	0x0322
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485	0x0330
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485	0x0331
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485	0x0332
+
+#define PCI_VENDOR_ID_NVIDIA_SGS	0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST		0x12E0
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4		0x0031
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8		0x0021
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16	0x0011
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC	0x0041
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS		0x124D
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4		0xF001
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8		0xF010
+
+#define PCI_VENDOR_ID_AUREAL		0x12eb
+#define PCI_DEVICE_ID_AUREAL_VORTEX_1	0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX_2	0x0002
+#define PCI_DEVICE_ID_AUREAL_ADVANTAGE	0x0003
+
+#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
+#define PCI_DEVICE_ID_LML_33R10		0x8a02
+
+#define PCI_VENDOR_ID_ESDGMBH		0x12fe
+#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111
+
+#define PCI_VENDOR_ID_SIIG		0x131f
+#define PCI_SUBVENDOR_ID_SIIG		0x131f
+#define PCI_DEVICE_ID_SIIG_1S_10x_550	0x1000
+#define PCI_DEVICE_ID_SIIG_1S_10x_650	0x1001
+#define PCI_DEVICE_ID_SIIG_1S_10x_850	0x1002
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x	0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x	0x1021
+#define PCI_DEVICE_ID_SIIG_2S_10x_550	0x1030
+#define PCI_DEVICE_ID_SIIG_2S_10x_650	0x1031
+#define PCI_DEVICE_ID_SIIG_2S_10x_850	0x1032
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
+#define PCI_DEVICE_ID_SIIG_4S_10x_550	0x1050
+#define PCI_DEVICE_ID_SIIG_4S_10x_650	0x1051
+#define PCI_DEVICE_ID_SIIG_4S_10x_850	0x1052
+#define PCI_DEVICE_ID_SIIG_1S_20x_550	0x2000
+#define PCI_DEVICE_ID_SIIG_1S_20x_650	0x2001
+#define PCI_DEVICE_ID_SIIG_1S_20x_850	0x2002
+#define PCI_DEVICE_ID_SIIG_1P_20x	0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x	0x2021
+#define PCI_DEVICE_ID_SIIG_2S_20x_550	0x2030
+#define PCI_DEVICE_ID_SIIG_2S_20x_650	0x2031
+#define PCI_DEVICE_ID_SIIG_2S_20x_850	0x2032
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
+#define PCI_DEVICE_ID_SIIG_4S_20x_550	0x2050
+#define PCI_DEVICE_ID_SIIG_4S_20x_650	0x2051
+#define PCI_DEVICE_ID_SIIG_4S_20x_850	0x2052
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
+#define PCI_DEVICE_ID_SIIG_8S_20x_550	0x2080
+#define PCI_DEVICE_ID_SIIG_8S_20x_650	0x2081
+#define PCI_DEVICE_ID_SIIG_8S_20x_850	0x2082
+#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL	0x2050
+
+#define PCI_VENDOR_ID_RADISYS		0x1331
+
+#define PCI_VENDOR_ID_MICRO_MEMORY		0x1332
+#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN	0x5415
+#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN	0x5425
+#define PCI_DEVICE_ID_MICRO_MEMORY_6155		0x6155
+
+#define PCI_VENDOR_ID_DOMEX		0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D	0x0001
+
+#define PCI_VENDOR_ID_INTASHIELD	0x135a
+#define PCI_DEVICE_ID_INTASHIELD_IS200	0x0d80
+#define PCI_DEVICE_ID_INTASHIELD_IS400	0x0dc0
+
+#define PCI_VENDOR_ID_QUATECH		0x135C
+#define PCI_DEVICE_ID_QUATECH_QSC100	0x0010
+#define PCI_DEVICE_ID_QUATECH_DSC100	0x0020
+#define PCI_DEVICE_ID_QUATECH_ESC100D	0x0050
+#define PCI_DEVICE_ID_QUATECH_ESC100M	0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
+
+#define PCI_VENDOR_ID_SEALEVEL		0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530	0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2	0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422	0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232	0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4	0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8	0x7801
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM8	0x7804
+
+#define PCI_VENDOR_ID_HYPERCOPE		0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX	0x9050
+#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO	0x0104
+#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO		0x0106
+#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO	0x0107
+#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2	0x0108
+
+#define PCI_VENDOR_ID_KAWASAKI		0x136b
+#define PCI_DEVICE_ID_MCHIP_KL5A72002	0xff01
+
+#define PCI_VENDOR_ID_CNET		0x1371
+#define PCI_DEVICE_ID_CNET_GIGACARD	0x434e
+
+#define PCI_VENDOR_ID_LMC		0x1376
+#define PCI_DEVICE_ID_LMC_HSSI		0x0003
+#define PCI_DEVICE_ID_LMC_DS3		0x0004
+#define PCI_DEVICE_ID_LMC_SSI		0x0005
+#define PCI_DEVICE_ID_LMC_T1		0x0006
+
+#define PCI_VENDOR_ID_NETGEAR		0x1385
+#define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
+
+#define PCI_VENDOR_ID_APPLICOM		0x1389
+#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
+#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
+#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
+
+#define PCI_VENDOR_ID_MOXA		0x1393
+#define PCI_DEVICE_ID_MOXA_RC7000	0x0001
+#define PCI_DEVICE_ID_MOXA_CP102	0x1020
+#define PCI_DEVICE_ID_MOXA_CP102UL	0x1021
+#define PCI_DEVICE_ID_MOXA_CP102U	0x1022
+#define PCI_DEVICE_ID_MOXA_C104		0x1040
+#define PCI_DEVICE_ID_MOXA_CP104U	0x1041
+#define PCI_DEVICE_ID_MOXA_CP104JU	0x1042
+#define PCI_DEVICE_ID_MOXA_CP104EL	0x1043
+#define PCI_DEVICE_ID_MOXA_CT114	0x1140
+#define PCI_DEVICE_ID_MOXA_CP114	0x1141
+#define PCI_DEVICE_ID_MOXA_CP118U	0x1180
+#define PCI_DEVICE_ID_MOXA_CP118EL	0x1181
+#define PCI_DEVICE_ID_MOXA_CP132	0x1320
+#define PCI_DEVICE_ID_MOXA_CP132U	0x1321
+#define PCI_DEVICE_ID_MOXA_CP134U	0x1340
+#define PCI_DEVICE_ID_MOXA_C168		0x1680
+#define PCI_DEVICE_ID_MOXA_CP168U	0x1681
+#define PCI_DEVICE_ID_MOXA_CP168EL	0x1682
+#define PCI_DEVICE_ID_MOXA_CP204J	0x2040
+#define PCI_DEVICE_ID_MOXA_C218		0x2180
+#define PCI_DEVICE_ID_MOXA_C320		0x3200
+
+#define PCI_VENDOR_ID_CCD		0x1397
+#define PCI_DEVICE_ID_CCD_HFC4S		0x08B4
+#define PCI_SUBDEVICE_ID_CCD_PMX2S	0x1234
+#define PCI_DEVICE_ID_CCD_HFC8S		0x16B8
+#define PCI_DEVICE_ID_CCD_2BD0		0x2bd0
+#define PCI_DEVICE_ID_CCD_HFCE1		0x30B1
+#define PCI_SUBDEVICE_ID_CCD_SPD4S	0x3136
+#define PCI_SUBDEVICE_ID_CCD_SPDE1	0x3137
+#define PCI_DEVICE_ID_CCD_B000		0xb000
+#define PCI_DEVICE_ID_CCD_B006		0xb006
+#define PCI_DEVICE_ID_CCD_B007		0xb007
+#define PCI_DEVICE_ID_CCD_B008		0xb008
+#define PCI_DEVICE_ID_CCD_B009		0xb009
+#define PCI_DEVICE_ID_CCD_B00A		0xb00a
+#define PCI_DEVICE_ID_CCD_B00B		0xb00b
+#define PCI_DEVICE_ID_CCD_B00C		0xb00c
+#define PCI_DEVICE_ID_CCD_B100		0xb100
+#define PCI_SUBDEVICE_ID_CCD_IOB4ST	0xB520
+#define PCI_SUBDEVICE_ID_CCD_IOB8STR	0xB521
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST	0xB522
+#define PCI_SUBDEVICE_ID_CCD_IOB1E1	0xB523
+#define PCI_SUBDEVICE_ID_CCD_SWYX4S	0xB540
+#define PCI_SUBDEVICE_ID_CCD_JH4S20	0xB550
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1	0xB552
+#define PCI_SUBDEVICE_ID_CCD_BN4S	0xB560
+#define PCI_SUBDEVICE_ID_CCD_BN8S	0xB562
+#define PCI_SUBDEVICE_ID_CCD_BNE1	0xB563
+#define PCI_SUBDEVICE_ID_CCD_BNE1D	0xB564
+#define PCI_SUBDEVICE_ID_CCD_BNE1DP	0xB565
+#define PCI_SUBDEVICE_ID_CCD_BN2S	0xB566
+#define PCI_SUBDEVICE_ID_CCD_BN1SM	0xB567
+#define PCI_SUBDEVICE_ID_CCD_BN4SM	0xB568
+#define PCI_SUBDEVICE_ID_CCD_BN2SM	0xB569
+#define PCI_SUBDEVICE_ID_CCD_BNE1M	0xB56A
+#define PCI_SUBDEVICE_ID_CCD_BN8SP	0xB56B
+#define PCI_SUBDEVICE_ID_CCD_HFC4S	0xB620
+#define PCI_SUBDEVICE_ID_CCD_HFC8S	0xB622
+#define PCI_DEVICE_ID_CCD_B700		0xb700
+#define PCI_DEVICE_ID_CCD_B701		0xb701
+#define PCI_SUBDEVICE_ID_CCD_HFCE1	0xC523
+#define PCI_SUBDEVICE_ID_CCD_OV2S	0xE884
+#define PCI_SUBDEVICE_ID_CCD_OV4S	0xE888
+#define PCI_SUBDEVICE_ID_CCD_OV8S	0xE998
+
+#define PCI_VENDOR_ID_EXAR		0x13a8
+#define PCI_DEVICE_ID_EXAR_XR17C152	0x0152
+#define PCI_DEVICE_ID_EXAR_XR17C154	0x0154
+#define PCI_DEVICE_ID_EXAR_XR17C158	0x0158
+
+#define PCI_VENDOR_ID_MICROGATE		0x13c0
+#define PCI_DEVICE_ID_MICROGATE_USC	0x0010
+#define PCI_DEVICE_ID_MICROGATE_SCA	0x0030
+
+#define PCI_VENDOR_ID_3WARE		0x13C1
+#define PCI_DEVICE_ID_3WARE_1000	0x1000
+#define PCI_DEVICE_ID_3WARE_7000	0x1001
+#define PCI_DEVICE_ID_3WARE_9000	0x1002
+
+#define PCI_VENDOR_ID_IOMEGA		0x13ca
+#define PCI_DEVICE_ID_IOMEGA_BUZ	0x4231
+
+#define PCI_VENDOR_ID_ABOCOM		0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1       0x2BD1
+
+#define PCI_VENDOR_ID_SUNDANCE		0x13f0
+
+#define PCI_VENDOR_ID_CMEDIA		0x13f6
+#define PCI_DEVICE_ID_CMEDIA_CM8338A	0x0100
+#define PCI_DEVICE_ID_CMEDIA_CM8338B	0x0101
+#define PCI_DEVICE_ID_CMEDIA_CM8738	0x0111
+#define PCI_DEVICE_ID_CMEDIA_CM8738B	0x0112
+
+#define PCI_VENDOR_ID_LAVA		0x1407
+#define PCI_DEVICE_ID_LAVA_DSERIAL	0x0100 /* 2x 16550 */
+#define PCI_DEVICE_ID_LAVA_QUATRO_A	0x0101 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUATRO_B	0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_A	0x0180 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_B	0x0181 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS	0x0200 /* 2x 16650 */
+#define PCI_DEVICE_ID_LAVA_QUAD_A	0x0201 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUAD_B	0x0202 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_SSERIAL	0x0500 /* 1x 16550 */
+#define PCI_DEVICE_ID_LAVA_PORT_650	0x0600 /* 1x 16650 */
+#define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
+#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR	0x8800
+
+#define PCI_VENDOR_ID_TIMEDIA		0x1409
+#define PCI_DEVICE_ID_TIMEDIA_1889	0x7168
+
+#define PCI_VENDOR_ID_ICE		0x1412
+#define PCI_DEVICE_ID_ICE_1712		0x1712
+#define PCI_DEVICE_ID_VT1724		0x1724
+
+#define PCI_VENDOR_ID_OXSEMI		0x1415
+#define PCI_DEVICE_ID_OXSEMI_12PCI840	0x8403
+#define PCI_DEVICE_ID_OXSEMI_PCIe840		0xC000
+#define PCI_DEVICE_ID_OXSEMI_PCIe840_G		0xC004
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0		0xC100
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G	0xC104
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1		0xC110
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G	0xC114
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U	0xC118
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU	0xC11C
+#define PCI_DEVICE_ID_OXSEMI_16PCI954	0x9501
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N	0x9511
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP	0x9513
+#define PCI_DEVICE_ID_OXSEMI_16PCI952	0x9521
+#define PCI_DEVICE_ID_OXSEMI_16PCI952PP	0x9523
+
+#define PCI_VENDOR_ID_CHELSIO		0x1425
+
+#define PCI_VENDOR_ID_SAMSUNG		0x144d
+
+#define PCI_VENDOR_ID_MYRICOM		0x14c1
+
+#define PCI_VENDOR_ID_TITAN		0x14D2
+#define PCI_DEVICE_ID_TITAN_010L	0x8001
+#define PCI_DEVICE_ID_TITAN_100L	0x8010
+#define PCI_DEVICE_ID_TITAN_110L	0x8011
+#define PCI_DEVICE_ID_TITAN_200L	0x8020
+#define PCI_DEVICE_ID_TITAN_210L	0x8021
+#define PCI_DEVICE_ID_TITAN_400L	0x8040
+#define PCI_DEVICE_ID_TITAN_800L	0x8080
+#define PCI_DEVICE_ID_TITAN_100		0xA001
+#define PCI_DEVICE_ID_TITAN_200		0xA005
+#define PCI_DEVICE_ID_TITAN_400		0xA003
+#define PCI_DEVICE_ID_TITAN_800B	0xA004
+
+#define PCI_VENDOR_ID_PANACOM		0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM	0x0402
+
+#define PCI_VENDOR_ID_SIPACKETS		0x14d9
+#define PCI_DEVICE_ID_SP1011		0x0010
+
+#define PCI_VENDOR_ID_AFAVLAB		0x14db
+#define PCI_DEVICE_ID_AFAVLAB_P028	0x2180
+#define PCI_DEVICE_ID_AFAVLAB_P030	0x2182
+#define PCI_SUBDEVICE_ID_AFAVLAB_P061		0x2150
+
+#define PCI_VENDOR_ID_BROADCOM		0x14e4
+#define PCI_DEVICE_ID_TIGON3_5752	0x1600
+#define PCI_DEVICE_ID_TIGON3_5752M	0x1601
+#define PCI_DEVICE_ID_NX2_5709		0x1639
+#define PCI_DEVICE_ID_NX2_5709S		0x163a
+#define PCI_DEVICE_ID_TIGON3_5700	0x1644
+#define PCI_DEVICE_ID_TIGON3_5701	0x1645
+#define PCI_DEVICE_ID_TIGON3_5702	0x1646
+#define PCI_DEVICE_ID_TIGON3_5703	0x1647
+#define PCI_DEVICE_ID_TIGON3_5704	0x1648
+#define PCI_DEVICE_ID_TIGON3_5704S_2	0x1649
+#define PCI_DEVICE_ID_NX2_5706		0x164a
+#define PCI_DEVICE_ID_NX2_5708		0x164c
+#define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
+#define PCI_DEVICE_ID_NX2_57710		0x164e
+#define PCI_DEVICE_ID_NX2_57711		0x164f
+#define PCI_DEVICE_ID_NX2_57711E	0x1650
+#define PCI_DEVICE_ID_TIGON3_5705	0x1653
+#define PCI_DEVICE_ID_TIGON3_5705_2	0x1654
+#define PCI_DEVICE_ID_TIGON3_5720	0x1658
+#define PCI_DEVICE_ID_TIGON3_5721	0x1659
+#define PCI_DEVICE_ID_TIGON3_5722	0x165a
+#define PCI_DEVICE_ID_TIGON3_5723	0x165b
+#define PCI_DEVICE_ID_TIGON3_5705M	0x165d
+#define PCI_DEVICE_ID_TIGON3_5705M_2	0x165e
+#define PCI_DEVICE_ID_TIGON3_5714	0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S	0x1669
+#define PCI_DEVICE_ID_TIGON3_5780	0x166a
+#define PCI_DEVICE_ID_TIGON3_5780S	0x166b
+#define PCI_DEVICE_ID_TIGON3_5705F	0x166e
+#define PCI_DEVICE_ID_TIGON3_5754M	0x1672
+#define PCI_DEVICE_ID_TIGON3_5755M	0x1673
+#define PCI_DEVICE_ID_TIGON3_5756	0x1674
+#define PCI_DEVICE_ID_TIGON3_5750	0x1676
+#define PCI_DEVICE_ID_TIGON3_5751	0x1677
+#define PCI_DEVICE_ID_TIGON3_5715	0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S	0x1679
+#define PCI_DEVICE_ID_TIGON3_5754	0x167a
+#define PCI_DEVICE_ID_TIGON3_5755	0x167b
+#define PCI_DEVICE_ID_TIGON3_5750M	0x167c
+#define PCI_DEVICE_ID_TIGON3_5751M	0x167d
+#define PCI_DEVICE_ID_TIGON3_5751F	0x167e
+#define PCI_DEVICE_ID_TIGON3_5787F	0x167f
+#define PCI_DEVICE_ID_TIGON3_5761E	0x1680
+#define PCI_DEVICE_ID_TIGON3_5761	0x1681
+#define PCI_DEVICE_ID_TIGON3_5764	0x1684
+#define PCI_DEVICE_ID_TIGON3_5787M	0x1693
+#define PCI_DEVICE_ID_TIGON3_5782	0x1696
+#define PCI_DEVICE_ID_TIGON3_5784	0x1698
+#define PCI_DEVICE_ID_TIGON3_5785	0x1699
+#define PCI_DEVICE_ID_TIGON3_5786	0x169a
+#define PCI_DEVICE_ID_TIGON3_5787	0x169b
+#define PCI_DEVICE_ID_TIGON3_5788	0x169c
+#define PCI_DEVICE_ID_TIGON3_5789	0x169d
+#define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
+#define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
+#define PCI_DEVICE_ID_TIGON3_5704S	0x16a8
+#define PCI_DEVICE_ID_NX2_5706S		0x16aa
+#define PCI_DEVICE_ID_NX2_5708S		0x16ac
+#define PCI_DEVICE_ID_TIGON3_5702A3	0x16c6
+#define PCI_DEVICE_ID_TIGON3_5703A3	0x16c7
+#define PCI_DEVICE_ID_TIGON3_5781	0x16dd
+#define PCI_DEVICE_ID_TIGON3_5753	0x16f7
+#define PCI_DEVICE_ID_TIGON3_5753M	0x16fd
+#define PCI_DEVICE_ID_TIGON3_5753F	0x16fe
+#define PCI_DEVICE_ID_TIGON3_5901	0x170d
+#define PCI_DEVICE_ID_BCM4401B1		0x170c
+#define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
+#define PCI_DEVICE_ID_TIGON3_5906	0x1712
+#define PCI_DEVICE_ID_TIGON3_5906M	0x1713
+#define PCI_DEVICE_ID_BCM4401		0x4401
+#define PCI_DEVICE_ID_BCM4401B0		0x4402
+
+#define PCI_VENDOR_ID_TOPIC		0x151f
+#define PCI_DEVICE_ID_TOPIC_TP560	0x0000
+
+#define PCI_VENDOR_ID_MAINPINE		0x1522
+#define PCI_DEVICE_ID_MAINPINE_PBRIDGE	0x0100
+#define PCI_VENDOR_ID_ENE		0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD	0x0550
+#define PCI_DEVICE_ID_ENE_CB712_SD_2	0x0551
+#define PCI_DEVICE_ID_ENE_CB714_SD	0x0750
+#define PCI_DEVICE_ID_ENE_CB714_SD_2	0x0751
+#define PCI_DEVICE_ID_ENE_1211		0x1211
+#define PCI_DEVICE_ID_ENE_1225		0x1225
+#define PCI_DEVICE_ID_ENE_1410		0x1410
+#define PCI_DEVICE_ID_ENE_710		0x1411
+#define PCI_DEVICE_ID_ENE_712		0x1412
+#define PCI_DEVICE_ID_ENE_1420		0x1420
+#define PCI_DEVICE_ID_ENE_720		0x1421
+#define PCI_DEVICE_ID_ENE_722		0x1422
+
+#define PCI_SUBVENDOR_ID_PERLE          0x155f
+#define PCI_SUBDEVICE_ID_PCI_RAS4       0xf001
+#define PCI_SUBDEVICE_ID_PCI_RAS8       0xf010
+
+#define PCI_VENDOR_ID_SYBA		0x1592
+#define PCI_DEVICE_ID_SYBA_2P_EPP	0x0782
+#define PCI_DEVICE_ID_SYBA_1P_ECP	0x0783
+
+#define PCI_VENDOR_ID_MORETON		0x15aa
+#define PCI_DEVICE_ID_RASTEL_2PORT	0x2000
+
+#define PCI_VENDOR_ID_ZOLTRIX		0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2bd0 
+
+#define PCI_VENDOR_ID_MELLANOX		0x15b3
+#define PCI_DEVICE_ID_MELLANOX_TAVOR	0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE	0x5a46
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL	0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI	0x6274
+
+#define PCI_VENDOR_ID_QUICKNET		0x15e2
+#define PCI_DEVICE_ID_QUICKNET_XJ	0x0500
+
+/*
+ * ADDI-DATA GmbH communication cards <info at addi-data.com>
+ */
+#define PCI_VENDOR_ID_ADDIDATA_OLD             0x10E8
+#define PCI_VENDOR_ID_ADDIDATA                 0x15B8
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500        0x7000
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420        0x7001
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300        0x7002
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800        0x818E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2      0x7009
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2      0x700A
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2      0x700B
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3      0x700C
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3      0x700D
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3      0x700E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3      0x700F
+
+#define PCI_VENDOR_ID_PDC		0x15e9
+
+#define PCI_VENDOR_ID_FARSITE           0x1619
+#define PCI_DEVICE_ID_FARSITE_T2P       0x0400
+#define PCI_DEVICE_ID_FARSITE_T4P       0x0440
+#define PCI_DEVICE_ID_FARSITE_T1U       0x0610
+#define PCI_DEVICE_ID_FARSITE_T2U       0x0620
+#define PCI_DEVICE_ID_FARSITE_T4U       0x0640
+#define PCI_DEVICE_ID_FARSITE_TE1       0x1610
+#define PCI_DEVICE_ID_FARSITE_TE1C      0x1612
+
+#define PCI_VENDOR_ID_ARIMA		0x161f
+
+#define PCI_VENDOR_ID_BROCADE		0x1657
+
+#define PCI_VENDOR_ID_SIBYTE		0x166d
+#define PCI_DEVICE_ID_BCM1250_PCI	0x0001
+#define PCI_DEVICE_ID_BCM1250_HT	0x0002
+
+#define PCI_VENDOR_ID_ATHEROS		0x168c
+
+#define PCI_VENDOR_ID_NETCELL		0x169c
+#define PCI_DEVICE_ID_REVOLUTION	0x0044
+
+#define PCI_VENDOR_ID_CENATEK		0x16CA
+#define PCI_DEVICE_ID_CENATEK_IDE	0x0001
+
+#define PCI_VENDOR_ID_VITESSE		0x1725
+#define PCI_DEVICE_ID_VITESSE_VSC7174	0x7174
+
+#define PCI_VENDOR_ID_LINKSYS		0x1737
+#define PCI_DEVICE_ID_LINKSYS_EG1064	0x1064
+
+#define PCI_VENDOR_ID_ALTIMA		0x173b
+#define PCI_DEVICE_ID_ALTIMA_AC1000	0x03e8
+#define PCI_DEVICE_ID_ALTIMA_AC1001	0x03e9
+#define PCI_DEVICE_ID_ALTIMA_AC9100	0x03ea
+#define PCI_DEVICE_ID_ALTIMA_AC1003	0x03eb
+
+#define PCI_VENDOR_ID_BELKIN		0x1799
+#define PCI_DEVICE_ID_BELKIN_F5D7010V7	0x701f
+
+#define PCI_VENDOR_ID_RDC		0x17f3
+#define PCI_DEVICE_ID_RDC_R6020		0x6020
+#define PCI_DEVICE_ID_RDC_R6030		0x6030
+#define PCI_DEVICE_ID_RDC_R6040		0x6040
+#define PCI_DEVICE_ID_RDC_R6060		0x6060
+#define PCI_DEVICE_ID_RDC_R6061		0x6061
+
+#define PCI_VENDOR_ID_LENOVO		0x17aa
+
+#define PCI_VENDOR_ID_ARECA		0x17d3
+#define PCI_DEVICE_ID_ARECA_1110	0x1110
+#define PCI_DEVICE_ID_ARECA_1120	0x1120
+#define PCI_DEVICE_ID_ARECA_1130	0x1130
+#define PCI_DEVICE_ID_ARECA_1160	0x1160
+#define PCI_DEVICE_ID_ARECA_1170	0x1170
+#define PCI_DEVICE_ID_ARECA_1200	0x1200
+#define PCI_DEVICE_ID_ARECA_1201	0x1201
+#define PCI_DEVICE_ID_ARECA_1202	0x1202
+#define PCI_DEVICE_ID_ARECA_1210	0x1210
+#define PCI_DEVICE_ID_ARECA_1220	0x1220
+#define PCI_DEVICE_ID_ARECA_1230	0x1230
+#define PCI_DEVICE_ID_ARECA_1260	0x1260
+#define PCI_DEVICE_ID_ARECA_1270	0x1270
+#define PCI_DEVICE_ID_ARECA_1280	0x1280
+#define PCI_DEVICE_ID_ARECA_1380	0x1380
+#define PCI_DEVICE_ID_ARECA_1381	0x1381
+#define PCI_DEVICE_ID_ARECA_1680	0x1680
+#define PCI_DEVICE_ID_ARECA_1681	0x1681
+
+#define PCI_VENDOR_ID_S2IO		0x17d5
+#define	PCI_DEVICE_ID_S2IO_WIN		0x5731
+#define	PCI_DEVICE_ID_S2IO_UNI		0x5831
+#define PCI_DEVICE_ID_HERC_WIN		0x5732
+#define PCI_DEVICE_ID_HERC_UNI		0x5832
+
+#define PCI_VENDOR_ID_SITECOM		0x182d
+#define PCI_DEVICE_ID_SITECOM_DC105V2	0x3069
+
+#define PCI_VENDOR_ID_TOPSPIN		0x1867
+
+#define PCI_VENDOR_ID_TDI               0x192E
+#define PCI_DEVICE_ID_TDI_EHCI          0x0101
+
+#define PCI_VENDOR_ID_FREESCALE		0x1957
+#define PCI_DEVICE_ID_MPC8548E		0x0012
+#define PCI_DEVICE_ID_MPC8548		0x0013
+#define PCI_DEVICE_ID_MPC8543E		0x0014
+#define PCI_DEVICE_ID_MPC8543		0x0015
+#define PCI_DEVICE_ID_MPC8547E		0x0018
+#define PCI_DEVICE_ID_MPC8545E		0x0019
+#define PCI_DEVICE_ID_MPC8545		0x001a
+#define PCI_DEVICE_ID_MPC8568E		0x0020
+#define PCI_DEVICE_ID_MPC8568		0x0021
+#define PCI_DEVICE_ID_MPC8567E		0x0022
+#define PCI_DEVICE_ID_MPC8567		0x0023
+#define PCI_DEVICE_ID_MPC8533E		0x0030
+#define PCI_DEVICE_ID_MPC8533		0x0031
+#define PCI_DEVICE_ID_MPC8544E		0x0032
+#define PCI_DEVICE_ID_MPC8544		0x0033
+#define PCI_DEVICE_ID_MPC8572E		0x0040
+#define PCI_DEVICE_ID_MPC8572		0x0041
+#define PCI_DEVICE_ID_MPC8536E		0x0050
+#define PCI_DEVICE_ID_MPC8536		0x0051
+#define PCI_DEVICE_ID_MPC8641		0x7010
+#define PCI_DEVICE_ID_MPC8641D		0x7011
+#define PCI_DEVICE_ID_MPC8610		0x7018
+
+#define PCI_VENDOR_ID_PASEMI		0x1959
+
+#define PCI_VENDOR_ID_ATTANSIC		0x1969
+#define PCI_DEVICE_ID_ATTANSIC_L1	0x1048
+#define PCI_DEVICE_ID_ATTANSIC_L2	0x2048
+
+#define PCI_VENDOR_ID_JMICRON		0x197B
+#define PCI_DEVICE_ID_JMICRON_JMB360	0x2360
+#define PCI_DEVICE_ID_JMICRON_JMB361	0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB363	0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB365	0x2365
+#define PCI_DEVICE_ID_JMICRON_JMB366	0x2366
+#define PCI_DEVICE_ID_JMICRON_JMB368	0x2368
+#define PCI_DEVICE_ID_JMICRON_JMB38X_SD	0x2381
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MS	0x2383
+
+#define PCI_VENDOR_ID_KORENIX		0x1982
+#define PCI_DEVICE_ID_KORENIX_JETCARDF0	0x1600
+#define PCI_DEVICE_ID_KORENIX_JETCARDF1	0x16ff
+
+#define PCI_VENDOR_ID_TEKRAM		0x1de1
+#define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
+
+#define PCI_VENDOR_ID_TEHUTI		0x1fc9
+#define PCI_DEVICE_ID_TEHUTI_3009	0x3009
+#define PCI_DEVICE_ID_TEHUTI_3010	0x3010
+#define PCI_DEVICE_ID_TEHUTI_3014	0x3014
+
+#define PCI_VENDOR_ID_HINT             0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013
+
+#define PCI_VENDOR_ID_3DLABS		0x3d3d
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2	0x0007
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V	0x0009
+
+#define PCI_VENDOR_ID_NETXEN		0x4040
+#define PCI_DEVICE_ID_NX2031_10GXSR	0x0001
+#define PCI_DEVICE_ID_NX2031_10GCX4	0x0002
+#define PCI_DEVICE_ID_NX2031_4GCU	0x0003
+#define PCI_DEVICE_ID_NX2031_IMEZ	0x0004
+#define PCI_DEVICE_ID_NX2031_HMEZ	0x0005
+#define PCI_DEVICE_ID_NX2031_XG_MGMT	0x0024
+#define PCI_DEVICE_ID_NX2031_XG_MGMT2	0x0025
+#define PCI_DEVICE_ID_NX3031		0x0100
+
+#define PCI_VENDOR_ID_AKS		0x416c
+#define PCI_DEVICE_ID_AKS_ALADDINCARD	0x0100
+
+#define PCI_VENDOR_ID_S3		0x5333
+#define PCI_DEVICE_ID_S3_TRIO		0x8811
+#define PCI_DEVICE_ID_S3_868		0x8880
+#define PCI_DEVICE_ID_S3_968		0x88f0
+#define PCI_DEVICE_ID_S3_SAVAGE4	0x8a25
+#define PCI_DEVICE_ID_S3_PROSAVAGE8	0x8d04
+#define PCI_DEVICE_ID_S3_SONICVIBES	0xca00
+
+#define PCI_VENDOR_ID_DUNORD		0x5544
+#define PCI_DEVICE_ID_DUNORD_I3000	0x0001
+
+#define PCI_VENDOR_ID_DCI		0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4	0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8	0x0002
+#define PCI_DEVICE_ID_DCI_PCCOM2	0x0004
+
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_DEVICE_ID_INTEL_EESSC	0x0008
+#define PCI_DEVICE_ID_INTEL_PXHD_0	0x0320
+#define PCI_DEVICE_ID_INTEL_PXHD_1	0x0321
+#define PCI_DEVICE_ID_INTEL_PXH_0	0x0329
+#define PCI_DEVICE_ID_INTEL_PXH_1	0x032A
+#define PCI_DEVICE_ID_INTEL_PXHV	0x032C
+#define PCI_DEVICE_ID_INTEL_82375	0x0482
+#define PCI_DEVICE_ID_INTEL_82424	0x0483
+#define PCI_DEVICE_ID_INTEL_82378	0x0484
+#define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM	0x0962
+#define PCI_DEVICE_ID_INTEL_82815_MC	0x1130
+#define PCI_DEVICE_ID_INTEL_82815_CGC	0x1132
+#define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
+#define PCI_DEVICE_ID_INTEL_7505_0	0x2550  
+#define PCI_DEVICE_ID_INTEL_7205_0	0x255d
+#define PCI_DEVICE_ID_INTEL_82437	0x122d
+#define PCI_DEVICE_ID_INTEL_82371FB_0	0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1	0x1230
+#define PCI_DEVICE_ID_INTEL_82371MX	0x1234
+#define PCI_DEVICE_ID_INTEL_82441	0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB	0x124b
+#define PCI_DEVICE_ID_INTEL_82439	0x1250
+#define PCI_DEVICE_ID_INTEL_80960_RP	0x1960
+#define PCI_DEVICE_ID_INTEL_82840_HB	0x1a21
+#define PCI_DEVICE_ID_INTEL_82845_HB	0x1a30
+#define PCI_DEVICE_ID_INTEL_IOAT	0x1a38
+#define PCI_DEVICE_ID_INTEL_82801AA_0	0x2410
+#define PCI_DEVICE_ID_INTEL_82801AA_1	0x2411
+#define PCI_DEVICE_ID_INTEL_82801AA_3	0x2413
+#define PCI_DEVICE_ID_INTEL_82801AA_5	0x2415
+#define PCI_DEVICE_ID_INTEL_82801AA_6	0x2416
+#define PCI_DEVICE_ID_INTEL_82801AA_8	0x2418
+#define PCI_DEVICE_ID_INTEL_82801AB_0	0x2420
+#define PCI_DEVICE_ID_INTEL_82801AB_1	0x2421
+#define PCI_DEVICE_ID_INTEL_82801AB_3	0x2423
+#define PCI_DEVICE_ID_INTEL_82801AB_5	0x2425
+#define PCI_DEVICE_ID_INTEL_82801AB_6	0x2426
+#define PCI_DEVICE_ID_INTEL_82801AB_8	0x2428
+#define PCI_DEVICE_ID_INTEL_82801BA_0	0x2440
+#define PCI_DEVICE_ID_INTEL_82801BA_2	0x2443
+#define PCI_DEVICE_ID_INTEL_82801BA_4	0x2445
+#define PCI_DEVICE_ID_INTEL_82801BA_6	0x2448
+#define PCI_DEVICE_ID_INTEL_82801BA_8	0x244a
+#define PCI_DEVICE_ID_INTEL_82801BA_9	0x244b
+#define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
+#define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
+#define PCI_DEVICE_ID_INTEL_82801E_0	0x2450
+#define PCI_DEVICE_ID_INTEL_82801E_11	0x245b
+#define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
+#define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
+#define PCI_DEVICE_ID_INTEL_82801CA_5	0x2485
+#define PCI_DEVICE_ID_INTEL_82801CA_6	0x2486
+#define PCI_DEVICE_ID_INTEL_82801CA_10	0x248a
+#define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
+#define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
+#define PCI_DEVICE_ID_INTEL_82801DB_0	0x24c0
+#define PCI_DEVICE_ID_INTEL_82801DB_1	0x24c1
+#define PCI_DEVICE_ID_INTEL_82801DB_3	0x24c3
+#define PCI_DEVICE_ID_INTEL_82801DB_5	0x24c5
+#define PCI_DEVICE_ID_INTEL_82801DB_6	0x24c6
+#define PCI_DEVICE_ID_INTEL_82801DB_9	0x24c9
+#define PCI_DEVICE_ID_INTEL_82801DB_10	0x24ca
+#define PCI_DEVICE_ID_INTEL_82801DB_11	0x24cb
+#define PCI_DEVICE_ID_INTEL_82801DB_12  0x24cc
+#define PCI_DEVICE_ID_INTEL_82801EB_0	0x24d0
+#define PCI_DEVICE_ID_INTEL_82801EB_1	0x24d1
+#define PCI_DEVICE_ID_INTEL_82801EB_3	0x24d3
+#define PCI_DEVICE_ID_INTEL_82801EB_5	0x24d5
+#define PCI_DEVICE_ID_INTEL_82801EB_6	0x24d6
+#define PCI_DEVICE_ID_INTEL_82801EB_11	0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12	0x24dc
+#define PCI_DEVICE_ID_INTEL_82801EB_13	0x24dd
+#define PCI_DEVICE_ID_INTEL_ESB_1	0x25a1
+#define PCI_DEVICE_ID_INTEL_ESB_2	0x25a2
+#define PCI_DEVICE_ID_INTEL_ESB_4	0x25a4
+#define PCI_DEVICE_ID_INTEL_ESB_5	0x25a6
+#define PCI_DEVICE_ID_INTEL_ESB_9	0x25ab
+#define PCI_DEVICE_ID_INTEL_82820_HB	0x2500
+#define PCI_DEVICE_ID_INTEL_82820_UP_HB	0x2501
+#define PCI_DEVICE_ID_INTEL_82850_HB	0x2530
+#define PCI_DEVICE_ID_INTEL_82860_HB	0x2531
+#define PCI_DEVICE_ID_INTEL_E7501_MCH	0x254c
+#define PCI_DEVICE_ID_INTEL_82845G_HB	0x2560
+#define PCI_DEVICE_ID_INTEL_82845G_IG	0x2562
+#define PCI_DEVICE_ID_INTEL_82865_HB	0x2570
+#define PCI_DEVICE_ID_INTEL_82865_IG	0x2572
+#define PCI_DEVICE_ID_INTEL_82875_HB	0x2578
+#define PCI_DEVICE_ID_INTEL_82915G_HB	0x2580
+#define PCI_DEVICE_ID_INTEL_82915G_IG	0x2582
+#define PCI_DEVICE_ID_INTEL_82915GM_HB	0x2590
+#define PCI_DEVICE_ID_INTEL_82915GM_IG	0x2592
+#define PCI_DEVICE_ID_INTEL_5000_ERR	0x25F0
+#define PCI_DEVICE_ID_INTEL_5000_FBD0	0x25F5
+#define PCI_DEVICE_ID_INTEL_5000_FBD1	0x25F6
+#define PCI_DEVICE_ID_INTEL_82945G_HB	0x2770
+#define PCI_DEVICE_ID_INTEL_82945G_IG	0x2772
+#define PCI_DEVICE_ID_INTEL_3000_HB	0x2778
+#define PCI_DEVICE_ID_INTEL_82945GM_HB	0x27A0
+#define PCI_DEVICE_ID_INTEL_82945GM_IG	0x27A2
+#define PCI_DEVICE_ID_INTEL_ICH6_0	0x2640
+#define PCI_DEVICE_ID_INTEL_ICH6_1	0x2641
+#define PCI_DEVICE_ID_INTEL_ICH6_2	0x2642
+#define PCI_DEVICE_ID_INTEL_ICH6_16	0x266a
+#define PCI_DEVICE_ID_INTEL_ICH6_17	0x266d
+#define PCI_DEVICE_ID_INTEL_ICH6_18	0x266e
+#define PCI_DEVICE_ID_INTEL_ICH6_19	0x266f
+#define PCI_DEVICE_ID_INTEL_ESB2_0	0x2670
+#define PCI_DEVICE_ID_INTEL_ESB2_14	0x2698
+#define PCI_DEVICE_ID_INTEL_ESB2_17	0x269b
+#define PCI_DEVICE_ID_INTEL_ESB2_18	0x269e
+#define PCI_DEVICE_ID_INTEL_ICH7_0	0x27b8
+#define PCI_DEVICE_ID_INTEL_ICH7_1	0x27b9
+#define PCI_DEVICE_ID_INTEL_ICH7_30	0x27b0
+#define PCI_DEVICE_ID_INTEL_ICH7_31	0x27bd
+#define PCI_DEVICE_ID_INTEL_ICH7_17	0x27da
+#define PCI_DEVICE_ID_INTEL_ICH7_19	0x27dd
+#define PCI_DEVICE_ID_INTEL_ICH7_20	0x27de
+#define PCI_DEVICE_ID_INTEL_ICH7_21	0x27df
+#define PCI_DEVICE_ID_INTEL_ICH8_0	0x2810
+#define PCI_DEVICE_ID_INTEL_ICH8_1	0x2811
+#define PCI_DEVICE_ID_INTEL_ICH8_2	0x2812
+#define PCI_DEVICE_ID_INTEL_ICH8_3	0x2814
+#define PCI_DEVICE_ID_INTEL_ICH8_4	0x2815
+#define PCI_DEVICE_ID_INTEL_ICH8_5	0x283e
+#define PCI_DEVICE_ID_INTEL_ICH8_6	0x2850
+#define PCI_DEVICE_ID_INTEL_ICH9_0	0x2910
+#define PCI_DEVICE_ID_INTEL_ICH9_1	0x2917
+#define PCI_DEVICE_ID_INTEL_ICH9_2	0x2912
+#define PCI_DEVICE_ID_INTEL_ICH9_3	0x2913
+#define PCI_DEVICE_ID_INTEL_ICH9_4	0x2914
+#define PCI_DEVICE_ID_INTEL_ICH9_5	0x2919
+#define PCI_DEVICE_ID_INTEL_ICH9_6	0x2930
+#define PCI_DEVICE_ID_INTEL_ICH9_7	0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_8	0x2918
+#define PCI_DEVICE_ID_INTEL_82855PM_HB	0x3340
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG4	0x3429
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG5	0x342a
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG6	0x342b
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG7	0x342c
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG0	0x3430
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG1	0x3431
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG2	0x3432
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG3	0x3433
+#define PCI_DEVICE_ID_INTEL_82830_HB	0x3575
+#define PCI_DEVICE_ID_INTEL_82830_CGC	0x3577
+#define PCI_DEVICE_ID_INTEL_82855GM_HB	0x3580
+#define PCI_DEVICE_ID_INTEL_82855GM_IG	0x3582
+#define PCI_DEVICE_ID_INTEL_E7520_MCH	0x3590
+#define PCI_DEVICE_ID_INTEL_E7320_MCH	0x3592
+#define PCI_DEVICE_ID_INTEL_MCH_PA	0x3595
+#define PCI_DEVICE_ID_INTEL_MCH_PA1	0x3596
+#define PCI_DEVICE_ID_INTEL_MCH_PB	0x3597
+#define PCI_DEVICE_ID_INTEL_MCH_PB1	0x3598
+#define PCI_DEVICE_ID_INTEL_MCH_PC	0x3599
+#define PCI_DEVICE_ID_INTEL_MCH_PC1	0x359a
+#define PCI_DEVICE_ID_INTEL_E7525_MCH	0x359e
+#define PCI_DEVICE_ID_INTEL_IOAT_CNB	0x360b
+#define PCI_DEVICE_ID_INTEL_FBD_CNB	0x360c
+#define PCI_DEVICE_ID_INTEL_ICH10_0	0x3a14
+#define PCI_DEVICE_ID_INTEL_ICH10_1	0x3a16
+#define PCI_DEVICE_ID_INTEL_ICH10_2	0x3a18
+#define PCI_DEVICE_ID_INTEL_ICH10_3	0x3a1a
+#define PCI_DEVICE_ID_INTEL_ICH10_4	0x3a30
+#define PCI_DEVICE_ID_INTEL_ICH10_5	0x3a60
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN	0x3b00
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX	0x3b1f
+#define PCI_DEVICE_ID_INTEL_PCH_SMBUS	0x3b30
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB	0x402f
+#define PCI_DEVICE_ID_INTEL_5100_16	0x65f0
+#define PCI_DEVICE_ID_INTEL_5100_21	0x65f5
+#define PCI_DEVICE_ID_INTEL_5100_22	0x65f6
+#define PCI_DEVICE_ID_INTEL_5400_ERR	0x4030
+#define PCI_DEVICE_ID_INTEL_5400_FBD0	0x4035
+#define PCI_DEVICE_ID_INTEL_5400_FBD1	0x4036
+#define PCI_DEVICE_ID_INTEL_IOAT_SCNB	0x65ff
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_0	0x5031
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_1	0x5032
+#define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB	0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
+#define PCI_DEVICE_ID_INTEL_82810_MC1	0x7120
+#define PCI_DEVICE_ID_INTEL_82810_IG1	0x7121
+#define PCI_DEVICE_ID_INTEL_82810_MC3	0x7122
+#define PCI_DEVICE_ID_INTEL_82810_IG3	0x7123
+#define PCI_DEVICE_ID_INTEL_82810E_MC	0x7124
+#define PCI_DEVICE_ID_INTEL_82810E_IG	0x7125
+#define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
+#define PCI_DEVICE_ID_INTEL_440MX	0x7195
+#define PCI_DEVICE_ID_INTEL_440MX_6	0x7196
+#define PCI_DEVICE_ID_INTEL_82443MX_0	0x7198
+#define PCI_DEVICE_ID_INTEL_82443MX_1	0x7199
+#define PCI_DEVICE_ID_INTEL_82443MX_3	0x719b
+#define PCI_DEVICE_ID_INTEL_82443GX_0	0x71a0
+#define PCI_DEVICE_ID_INTEL_82443GX_2	0x71a2
+#define PCI_DEVICE_ID_INTEL_82372FB_1	0x7601
+#define PCI_DEVICE_ID_INTEL_SCH_LPC	0x8119
+#define PCI_DEVICE_ID_INTEL_SCH_IDE	0x811a
+#define PCI_DEVICE_ID_INTEL_82454GX	0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
+#define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX     0x84cb
+#define PCI_DEVICE_ID_INTEL_84460GX	0x84ea
+#define PCI_DEVICE_ID_INTEL_IXP4XX	0x8500
+#define PCI_DEVICE_ID_INTEL_IXP2800	0x9004
+#define PCI_DEVICE_ID_INTEL_S21152BB	0xb152
+
+#define PCI_VENDOR_ID_SCALEMP		0x8686
+#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL	0x1010
+
+#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
+#define PCI_DEVICE_ID_COMPUTONE_PG	0x0302
+#define PCI_SUBVENDOR_ID_COMPUTONE	0x8e0e
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG4	0x0001
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG8	0x0002
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG6	0x0003
+
+#define PCI_VENDOR_ID_KTI		0x8e2e
+
+#define PCI_VENDOR_ID_ADAPTEC		0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821	0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602	0x3860
+#define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
+#define PCI_DEVICE_ID_ADAPTEC_3860	0x6038
+#define PCI_DEVICE_ID_ADAPTEC_1480A	0x6075
+#define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
+#define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
+#define PCI_DEVICE_ID_ADAPTEC_7870	0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7871	0x7178
+#define PCI_DEVICE_ID_ADAPTEC_7872	0x7278
+#define PCI_DEVICE_ID_ADAPTEC_7873	0x7378
+#define PCI_DEVICE_ID_ADAPTEC_7874	0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895	0x7895
+#define PCI_DEVICE_ID_ADAPTEC_7880	0x8078
+#define PCI_DEVICE_ID_ADAPTEC_7881	0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
+#define PCI_DEVICE_ID_ADAPTEC_7883	0x8378
+#define PCI_DEVICE_ID_ADAPTEC_7884	0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885	0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886	0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887	0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888	0x8878
+
+#define PCI_VENDOR_ID_ADAPTEC2		0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2	0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2	0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B	0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_7890	0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2	0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D	0x0051
+#define PCI_DEVICE_ID_ADAPTEC2_7896	0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A	0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B	0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D	0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P	0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A	0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
+#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN   0x0500
+#define PCI_DEVICE_ID_ADAPTEC2_SCAMP	0x0503
+
+#define PCI_VENDOR_ID_HOLTEK		0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565	0x6565
+
+#define PCI_VENDOR_ID_NETMOS		0x9710
+#define PCI_DEVICE_ID_NETMOS_9705	0x9705
+#define PCI_DEVICE_ID_NETMOS_9715	0x9715
+#define PCI_DEVICE_ID_NETMOS_9735	0x9735
+#define PCI_DEVICE_ID_NETMOS_9745	0x9745
+#define PCI_DEVICE_ID_NETMOS_9755	0x9755
+#define PCI_DEVICE_ID_NETMOS_9805	0x9805
+#define PCI_DEVICE_ID_NETMOS_9815	0x9815
+#define PCI_DEVICE_ID_NETMOS_9835	0x9835
+#define PCI_DEVICE_ID_NETMOS_9845	0x9845
+#define PCI_DEVICE_ID_NETMOS_9855	0x9855
+
+#define PCI_VENDOR_ID_3COM_2		0xa727
+
+#define PCI_VENDOR_ID_DIGIUM		0xd161
+#define PCI_DEVICE_ID_DIGIUM_HFC4S	0xb410
+
+#define PCI_SUBVENDOR_ID_EXSYS		0xd84d
+#define PCI_SUBDEVICE_ID_EXSYS_4014	0x4014
+#define PCI_SUBDEVICE_ID_EXSYS_4055	0x4055
+
+#define PCI_VENDOR_ID_TIGERJET		0xe159
+#define PCI_DEVICE_ID_TIGERJET_300	0x0001
+#define PCI_DEVICE_ID_TIGERJET_100	0x0002
+
+#define PCI_VENDOR_ID_XILINX_RME	0xea60
+#define PCI_DEVICE_ID_RME_DIGI32	0x9896
+#define PCI_DEVICE_ID_RME_DIGI32_PRO	0x9897
+#define PCI_DEVICE_ID_RME_DIGI32_8	0x9898
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET	0x1af4
+#define PCI_DEVICE_ID_VIRTIO_BLK	0x1001
diff --git a/qemu-0.15.x/roms/seabios/src/pci_region.c b/qemu-0.15.x/roms/seabios/src/pci_region.c
new file mode 100644
index 0000000..1d9de71
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pci_region.c
@@ -0,0 +1,77 @@
+// helper functions to manage pci io/memory/prefetch memory region
+//
+// Copyright (C) 2009 Isaku Yamahata <yamahata at valinux co jp>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+//
+//
+
+#include "util.h"
+
+#define PCI_REGION_DISABLED     (-1)
+
+void pci_region_init(struct pci_region *r, u32 first, u32 last)
+{
+    r->first = first;
+    r->last = last;
+
+    r->cur_first = r->first;
+}
+
+// PCI_REGION_DISABLED represents that the region is in special state.
+// its value is chosen such that cur_first can't be PCI_REGION_DISABLED
+// normally.
+// NOTE: the area right below 4G is used for LAPIC, so such area can't
+//       be used for PCI memory.
+u32 pci_region_disable(struct pci_region *r)
+{
+    return r->cur_first = PCI_REGION_DISABLED;
+}
+
+static int pci_region_disabled(const struct pci_region *r)
+{
+    return r->cur_first == PCI_REGION_DISABLED;
+}
+
+static u32 pci_region_alloc_align(struct pci_region *r, u32 size, u32 align)
+{
+    if (pci_region_disabled(r)) {
+        return 0;
+    }
+
+    u32 s = ALIGN(r->cur_first, align);
+    if (s > r->last || s < r->cur_first) {
+        return 0;
+    }
+    u32 e = s + size;
+    if (e < s || e - 1 > r->last) {
+        return 0;
+    }
+    r->cur_first = e;
+    return s;
+}
+
+u32 pci_region_alloc(struct pci_region *r, u32 size)
+{
+    return pci_region_alloc_align(r, size, size);
+}
+
+u32 pci_region_align(struct pci_region *r, u32 align)
+{
+    return pci_region_alloc_align(r, 0, align);
+}
+
+void pci_region_revert(struct pci_region *r, u32 addr)
+{
+    r->cur_first = addr;
+}
+
+u32 pci_region_addr(const struct pci_region *r)
+{
+    return r->cur_first;
+}
+
+u32 pci_region_size(const struct pci_region *r)
+{
+    return r->last - r->first + 1;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pci_regs.h b/qemu-0.15.x/roms/seabios/src/pci_regs.h
new file mode 100644
index 0000000..e5effd4
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pci_regs.h
@@ -0,0 +1,556 @@
+/*
+ *	pci_regs.h
+ *
+ *	PCI standard defines
+ *	Copyright 1994, Drew Eckhardt
+ *	Copyright 1997--1999 Martin Mares <mj at ucw.cz>
+ *
+ *	For more information, please consult the following manuals (look at
+ *	http://www.pcisig.com/ for how to get them):
+ *
+ *	PCI BIOS Specification
+ *	PCI Local Bus Specification
+ *	PCI to PCI Bridge Specification
+ *	PCI System Design Guide
+ *
+ * 	For hypertransport information, please consult the following manuals
+ * 	from http://www.hypertransport.org
+ *
+ *	The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#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_COMMAND_MASTER	0x4	/* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL	0x8	/* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE	0x10	/* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20	/* Enable palette snooping */
+#define  PCI_COMMAND_PARITY	0x40	/* Enable parity checking */
+#define  PCI_COMMAND_WAIT 	0x80	/* Enable address/data stepping */
+#define  PCI_COMMAND_SERR	0x100	/* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK	0x200	/* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS		0x06	/* 16 bits */
+#define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */
+#define  PCI_STATUS_66MHZ	0x20	/* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK	0x80	/* Accept fast-back to back */
+#define  PCI_STATUS_PARITY	0x100	/* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK	0x600	/* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST		0x000
+#define  PCI_STATUS_DEVSEL_MEDIUM	0x200
+#define  PCI_STATUS_DEVSEL_SLOW		0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT	0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT	0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT	0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR	0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY	0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION	0x08	/* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID		0x08	/* Revision ID */
+#define PCI_CLASS_PROG		0x09	/* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE	0x0a	/* Device class */
+
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
+#define PCI_HEADER_TYPE		0x0e	/* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL		0
+#define  PCI_HEADER_TYPE_BRIDGE		1
+#define  PCI_HEADER_TYPE_CARDBUS	2
+
+#define PCI_BIST		0x0f	/* 8 bits */
+#define  PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define  PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back.  Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#define PCI_BASE_ADDRESS_1	0x14	/* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2	0x18	/* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3	0x1c	/* 32 bits */
+#define PCI_BASE_ADDRESS_4	0x20	/* 32 bits */
+#define PCI_BASE_ADDRESS_5	0x24	/* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE		0x01	/* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO	0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY	0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK	0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH	0x08	/* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK	(~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK	(~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS		0x28
+#define PCI_SUBSYSTEM_VENDOR_ID	0x2c
+#define PCI_SUBSYSTEM_ID	0x2e
+#define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE	0x01
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#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 */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS		0x18	/* Primary bus number */
+#define PCI_SECONDARY_BUS	0x19	/* Secondary bus number */
+#define PCI_SUBORDINATE_BUS	0x1a	/* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER	0x1b	/* Latency timer for secondary interface */
+#define PCI_IO_BASE		0x1c	/* I/O range behind the bridge */
+#define PCI_IO_LIMIT		0x1d
+#define  PCI_IO_RANGE_TYPE_MASK	0x0fUL	/* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16	0x00
+#define  PCI_IO_RANGE_TYPE_32	0x01
+#define  PCI_IO_RANGE_MASK	(~0x0fUL)
+#define PCI_SEC_STATUS		0x1e	/* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE		0x20	/* Memory range behind */
+#define PCI_MEMORY_LIMIT	0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_MEMORY_RANGE_MASK	(~0x0fUL)
+#define PCI_PREF_MEMORY_BASE	0x24	/* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT	0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_PREF_RANGE_TYPE_32	0x00
+#define  PCI_PREF_RANGE_TYPE_64	0x01
+#define  PCI_PREF_RANGE_MASK	(~0x0fUL)
+#define PCI_PREF_BASE_UPPER32	0x28	/* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32	0x2c
+#define PCI_IO_BASE_UPPER16	0x30	/* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16	0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1	0x38	/* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL	0x3e
+#define  PCI_BRIDGE_CTL_PARITY	0x01	/* Enable parity detection on secondary interface */
+#define  PCI_BRIDGE_CTL_SERR	0x02	/* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_ISA	0x04	/* Enable ISA mode */
+#define  PCI_BRIDGE_CTL_VGA	0x08	/* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT	0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET	0x40	/* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK	0x80	/* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST	0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS	0x16	/* Secondary status */
+#define PCI_CB_PRIMARY_BUS	0x18	/* PCI bus number */
+#define PCI_CB_CARD_BUS		0x19	/* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS	0x1a	/* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER	0x1b	/* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0	0x1c
+#define PCI_CB_MEMORY_LIMIT_0	0x20
+#define PCI_CB_MEMORY_BASE_1	0x24
+#define PCI_CB_MEMORY_LIMIT_1	0x28
+#define PCI_CB_IO_BASE_0	0x2c
+#define PCI_CB_IO_BASE_0_HI	0x2e
+#define PCI_CB_IO_LIMIT_0	0x30
+#define PCI_CB_IO_LIMIT_0_HI	0x32
+#define PCI_CB_IO_BASE_1	0x34
+#define PCI_CB_IO_BASE_1_HI	0x36
+#define PCI_CB_IO_LIMIT_1	0x38
+#define PCI_CB_IO_LIMIT_1_HI	0x3a
+#define  PCI_CB_IO_RANGE_MASK	(~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL	0x3e
+#define  PCI_CB_BRIDGE_CTL_PARITY	0x01	/* Similar to standard bridge control register */
+#define  PCI_CB_BRIDGE_CTL_SERR		0x02
+#define  PCI_CB_BRIDGE_CTL_ISA		0x04
+#define  PCI_CB_BRIDGE_CTL_VGA		0x08
+#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT	0x20
+#define  PCI_CB_BRIDGE_CTL_CB_RESET	0x40	/* CardBus reset */
+#define  PCI_CB_BRIDGE_CTL_16BIT_INT	0x80	/* Enable interrupt for 16-bit cards */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100	/* Prefetch enable for both memory regions */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define  PCI_CB_BRIDGE_CTL_POST_WRITES	0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID	0x40
+#define PCI_CB_SUBSYSTEM_ID		0x42
+#define PCI_CB_LEGACY_MODE_BASE		0x44	/* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID		0	/* Capability ID */
+#define  PCI_CAP_ID_PM		0x01	/* Power Management */
+#define  PCI_CAP_ID_AGP		0x02	/* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD		0x03	/* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
+#define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
+#define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_HT		0x08	/* HyperTransport */
+#define  PCI_CAP_ID_VNDR	0x09	/* Vendor specific */
+#define  PCI_CAP_ID_DBG		0x0A	/* Debug port */
+#define  PCI_CAP_ID_CCRC	0x0B	/* CompactPCI Central Resource Control */
+#define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
+#define  PCI_CAP_ID_SSVID	0x0D	/* Bridge subsystem vendor/device ID */
+#define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
+#define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
+#define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
+#define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF		4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC		2	/* PM Capabilities Register */
+#define  PCI_PM_CAP_VER_MASK	0x0007	/* Version */
+#define  PCI_PM_CAP_PME_CLOCK	0x0008	/* PME clock required */
+#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
+#define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization */
+#define  PCI_PM_CAP_AUX_POWER	0x01C0	/* Auxilliary power support mask */
+#define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
+#define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
+#define  PCI_PM_CAP_PME		0x0800	/* PME pin supported */
+#define  PCI_PM_CAP_PME_MASK	0xF800	/* PME Mask of all supported states */
+#define  PCI_PM_CAP_PME_D0	0x0800	/* PME# from D0 */
+#define  PCI_PM_CAP_PME_D1	0x1000	/* PME# from D1 */
+#define  PCI_PM_CAP_PME_D2	0x2000	/* PME# from D2 */
+#define  PCI_PM_CAP_PME_D3	0x4000	/* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3cold	0x8000	/* PME# from D3 (cold) */
+#define  PCI_PM_CAP_PME_SHIFT	11	/* Start of the PME Mask in PMC */
+#define PCI_PM_CTRL		4	/* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_NO_SOFT_RESET	0x0004	/* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS	0x8000	/* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS	6	/* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3	0x40	/* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE	0x80	/* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER	7	/* (??) */
+#define PCI_PM_SIZEOF		8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION		2	/* BCD version number */
+#define PCI_AGP_RFU		3	/* Rest of capability flags */
+#define PCI_AGP_STATUS		4	/* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK	0xff000000	/* Maximum number of requests - 1 */
+#define  PCI_AGP_STATUS_SBA	0x0200	/* Sideband addressing supported */
+#define  PCI_AGP_STATUS_64BIT	0x0020	/* 64-bit addressing supported */
+#define  PCI_AGP_STATUS_FW	0x0010	/* FW transfers supported */
+#define  PCI_AGP_STATUS_RATE4	0x0004	/* 4x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE2	0x0002	/* 2x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE1	0x0001	/* 1x transfer rate supported */
+#define PCI_AGP_COMMAND		8	/* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
+#define  PCI_AGP_COMMAND_SBA	0x0200	/* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP	0x0100	/* Allow processing of AGP transactions */
+#define  PCI_AGP_COMMAND_64BIT	0x0020 	/* Allow processing of 64-bit addresses */
+#define  PCI_AGP_COMMAND_FW	0x0010 	/* Force FW transfers */
+#define  PCI_AGP_COMMAND_RATE4	0x0004	/* Use 4x rate */
+#define  PCI_AGP_COMMAND_RATE2	0x0002	/* Use 2x rate */
+#define  PCI_AGP_COMMAND_RATE1	0x0001	/* Use 1x rate */
+#define PCI_AGP_SIZEOF		12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR		2	/* Address to access (15 bits!) */
+#define  PCI_VPD_ADDR_MASK	0x7fff	/* Address mask */
+#define  PCI_VPD_ADDR_F		0x8000	/* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA		4	/* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR		2	/* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS	0x1f	/* Number of expansion slots available */
+#define  PCI_SID_ESR_FIC	0x20	/* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR	3	/* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS		2	/* Various flags */
+#define  PCI_MSI_FLAGS_64BIT	0x80	/* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE	0x70	/* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK	0x0e	/* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE	0x01	/* MSI feature enabled */
+#define  PCI_MSI_FLAGS_MASKBIT	0x100	/* 64-bit mask bits allowed */
+#define PCI_MSI_RFU		3	/* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO	4	/* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI	8	/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
+#define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
+#define PCI_MSI_MASK_BIT	16	/* Mask bits register */
+
+/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+#define PCI_MSIX_FLAGS		2
+#define  PCI_MSIX_FLAGS_QSIZE	0x7FF
+#define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
+#define  PCI_MSIX_FLAGS_MASKALL	(1 << 14)
+#define PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
+#define PCI_MSIX_FLAGS_BITMASK	(1 << 0)
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR		2	/* Control and Status Register */
+#define  PCI_CHSWP_DHA		0x01	/* Device Hiding Arm */
+#define  PCI_CHSWP_EIM		0x02	/* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE		0x04	/* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO		0x08	/* LED On / Off */
+#define  PCI_CHSWP_PI		0x30	/* Programming Interface */
+#define  PCI_CHSWP_EXT		0x40	/* ENUM# status - extraction */
+#define  PCI_CHSWP_INS		0x80	/* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD		2	/* Modes & Features */
+#define  PCI_X_CMD_DPERR_E	0x0001	/* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
+#define  PCI_X_CMD_READ_512	0x0000	/* 512 byte maximum read byte count */
+#define  PCI_X_CMD_READ_1K	0x0004	/* 1Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_2K	0x0008	/* 2Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_4K	0x000c	/* 4Kbyte maximum read byte count */
+#define  PCI_X_CMD_MAX_READ	0x000c	/* Max Memory Read Byte Count */
+				/* Max # of outstanding split transactions */
+#define  PCI_X_CMD_SPLIT_1	0x0000	/* Max 1 */
+#define  PCI_X_CMD_SPLIT_2	0x0010	/* Max 2 */
+#define  PCI_X_CMD_SPLIT_3	0x0020	/* Max 3 */
+#define  PCI_X_CMD_SPLIT_4	0x0030	/* Max 4 */
+#define  PCI_X_CMD_SPLIT_8	0x0040	/* Max 8 */
+#define  PCI_X_CMD_SPLIT_12	0x0050	/* Max 12 */
+#define  PCI_X_CMD_SPLIT_16	0x0060	/* Max 16 */
+#define  PCI_X_CMD_SPLIT_32	0x0070	/* Max 32 */
+#define  PCI_X_CMD_MAX_SPLIT	0x0070	/* Max Outstanding Split Transactions */
+#define  PCI_X_CMD_VERSION(x) 	(((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS		4	/* PCI-X capabilities */
+#define  PCI_X_STATUS_DEVFN	0x000000ff	/* A copy of devfn */
+#define  PCI_X_STATUS_BUS	0x0000ff00	/* A copy of bus nr */
+#define  PCI_X_STATUS_64BIT	0x00010000	/* 64-bit device */
+#define  PCI_X_STATUS_133MHZ	0x00020000	/* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC	0x00040000	/* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL	0x00080000	/* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX	0x00100000	/* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ	0x00600000	/* Designed Max Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT	0x03800000	/* Designed Max Outstanding Split Transactions */
+#define  PCI_X_STATUS_MAX_CUM	0x1c000000	/* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR	0x20000000	/* Rcvd Split Completion Error Msg */
+#define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
+#define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS		2	/* Capabilities register */
+#define PCI_EXP_FLAGS_VERS	0x000f	/* Capability version */
+#define PCI_EXP_FLAGS_TYPE	0x00f0	/* Device/Port type */
+#define  PCI_EXP_TYPE_ENDPOINT	0x0	/* Express Endpoint */
+#define  PCI_EXP_TYPE_LEG_END	0x1	/* Legacy Endpoint */
+#define  PCI_EXP_TYPE_ROOT_PORT 0x4	/* Root Port */
+#define  PCI_EXP_TYPE_UPSTREAM	0x5	/* Upstream Port */
+#define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
+#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCI/PCI-X Bridge */
+#define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ	0x3e00	/* Interrupt message number */
+#define PCI_EXP_DEVCAP		4	/* Device capabilities */
+#define  PCI_EXP_DEVCAP_PAYLOAD	0x07	/* Max_Payload_Size */
+#define  PCI_EXP_DEVCAP_PHANTOM	0x18	/* Phantom functions */
+#define  PCI_EXP_DEVCAP_EXT_TAG	0x20	/* Extended tags */
+#define  PCI_EXP_DEVCAP_L0S	0x1c0	/* L0s Acceptable Latency */
+#define  PCI_EXP_DEVCAP_L1	0xe00	/* L1 Acceptable Latency */
+#define  PCI_EXP_DEVCAP_ATN_BUT	0x1000	/* Attention Button Present */
+#define  PCI_EXP_DEVCAP_ATN_IND	0x2000	/* Attention Indicator Present */
+#define  PCI_EXP_DEVCAP_PWR_IND	0x4000	/* Power Indicator Present */
+#define  PCI_EXP_DEVCAP_RBER	0x8000	/* Role-Based Error Reporting */
+#define  PCI_EXP_DEVCAP_PWR_VAL	0x3fc0000 /* Slot Power Limit Value */
+#define  PCI_EXP_DEVCAP_PWR_SCL	0xc000000 /* Slot Power Limit Scale */
+#define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL		8	/* Device Control */
+#define  PCI_EXP_DEVCTL_CERE	0x0001	/* Correctable Error Reporting En. */
+#define  PCI_EXP_DEVCTL_NFERE	0x0002	/* Non-Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_FERE	0x0004	/* Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_URRE	0x0008	/* Unsupported Request Reporting En. */
+#define  PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define  PCI_EXP_DEVCTL_PAYLOAD	0x00e0	/* Max_Payload_Size */
+#define  PCI_EXP_DEVCTL_EXT_TAG	0x0100	/* Extended Tag Field Enable */
+#define  PCI_EXP_DEVCTL_PHANTOM	0x0200	/* Phantom Functions Enable */
+#define  PCI_EXP_DEVCTL_AUX_PME	0x0400	/* Auxiliary Power PM Enable */
+#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+#define  PCI_EXP_DEVCTL_READRQ	0x7000	/* Max_Read_Request_Size */
+#define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
+#define PCI_EXP_DEVSTA		10	/* Device Status */
+#define  PCI_EXP_DEVSTA_CED	0x01	/* Correctable Error Detected */
+#define  PCI_EXP_DEVSTA_NFED	0x02	/* Non-Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_FED	0x04	/* Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_URD	0x08	/* Unsupported Request Detected */
+#define  PCI_EXP_DEVSTA_AUXPD	0x10	/* AUX Power Detected */
+#define  PCI_EXP_DEVSTA_TRPND	0x20	/* Transactions Pending */
+#define PCI_EXP_LNKCAP		12	/* Link Capabilities */
+#define  PCI_EXP_LNKCAP_ASPMS	0xc00	/* ASPM Support */
+#define  PCI_EXP_LNKCAP_L0SEL	0x7000	/* L0s Exit Latency */
+#define  PCI_EXP_LNKCAP_L1EL	0x38000	/* L1 Exit Latency */
+#define  PCI_EXP_LNKCAP_CLKPM	0x40000	/* L1 Clock Power Management */
+#define PCI_EXP_LNKCTL		16	/* Link Control */
+#define  PCI_EXP_LNKCTL_RL	0x20	/* Retrain Link */
+#define  PCI_EXP_LNKCTL_CCC	0x40	/* Common Clock COnfiguration */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100	/* Enable clkreq */
+#define PCI_EXP_LNKSTA		18	/* Link Status */
+#define  PCI_EXP_LNKSTA_LT	0x800	/* Link Training */
+#define  PCI_EXP_LNKSTA_SLC	0x1000	/* Slot Clock Configuration */
+#define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
+#define PCI_EXP_SLTCTL		24	/* Slot Control */
+#define PCI_EXP_SLTSTA		26	/* Slot Status */
+#define PCI_EXP_RTCTL		28	/* Root Control */
+#define  PCI_EXP_RTCTL_SECEE	0x01	/* System Error on Correctable Error */
+#define  PCI_EXP_RTCTL_SENFEE	0x02	/* System Error on Non-Fatal Error */
+#define  PCI_EXP_RTCTL_SEFEE	0x04	/* System Error on Fatal Error */
+#define  PCI_EXP_RTCTL_PMEIE	0x08	/* PME Interrupt Enable */
+#define  PCI_EXP_RTCTL_CRSSVE	0x10	/* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP		30	/* Root Capabilities */
+#define PCI_EXP_RTSTA		32	/* Root Status */
+#define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
+#define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
+#define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
+#define  PCI_EXP_DEVCTL2_ARI	0x20	/* Alternative Routing-ID */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header)		((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR	1
+#define PCI_EXT_CAP_ID_VC	2
+#define PCI_EXT_CAP_ID_DSN	3
+#define PCI_EXT_CAP_ID_PWR	4
+#define PCI_EXT_CAP_ID_ARI	14
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
+#define  PCI_ERR_UNC_TRAIN	0x00000001	/* Training */
+#define  PCI_ERR_UNC_DLP	0x00000010	/* Data Link Protocol */
+#define  PCI_ERR_UNC_POISON_TLP	0x00001000	/* Poisoned TLP */
+#define  PCI_ERR_UNC_FCP	0x00002000	/* Flow Control Protocol */
+#define  PCI_ERR_UNC_COMP_TIME	0x00004000	/* Completion Timeout */
+#define  PCI_ERR_UNC_COMP_ABORT	0x00008000	/* Completer Abort */
+#define  PCI_ERR_UNC_UNX_COMP	0x00010000	/* Unexpected Completion */
+#define  PCI_ERR_UNC_RX_OVER	0x00020000	/* Receiver Overflow */
+#define  PCI_ERR_UNC_MALF_TLP	0x00040000	/* Malformed TLP */
+#define  PCI_ERR_UNC_ECRC	0x00080000	/* ECRC Error Status */
+#define  PCI_ERR_UNC_UNSUP	0x00100000	/* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK	8	/* Uncorrectable Error Mask */
+	/* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER	12	/* Uncorrectable Error Severity */
+	/* Same bits as above */
+#define PCI_ERR_COR_STATUS	16	/* Correctable Error Status */
+#define  PCI_ERR_COR_RCVR	0x00000001	/* Receiver Error Status */
+#define  PCI_ERR_COR_BAD_TLP	0x00000040	/* Bad TLP Status */
+#define  PCI_ERR_COR_BAD_DLLP	0x00000080	/* Bad DLLP Status */
+#define  PCI_ERR_COR_REP_ROLL	0x00000100	/* REPLAY_NUM Rollover */
+#define  PCI_ERR_COR_REP_TIMER	0x00001000	/* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK	20	/* Correctable Error Mask */
+	/* Same bits as above */
+#define PCI_ERR_CAP		24	/* Advanced Error Capabilities */
+#define  PCI_ERR_CAP_FEP(x)	((x) & 31)	/* First Error Pointer */
+#define  PCI_ERR_CAP_ECRC_GENC	0x00000020	/* ECRC Generation Capable */
+#define  PCI_ERR_CAP_ECRC_GENE	0x00000040	/* ECRC Generation Enable */
+#define  PCI_ERR_CAP_ECRC_CHKC	0x00000080	/* ECRC Check Capable */
+#define  PCI_ERR_CAP_ECRC_CHKE	0x00000100	/* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG	28	/* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND	44	/* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN		0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN	0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN	0x00000004
+#define PCI_ERR_ROOT_STATUS	48
+#define PCI_ERR_ROOT_COR_RCV		0x00000001	/* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV	0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV		0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV	0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL	0x00000010	/* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV	0x00000020	/* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV		0x00000040	/* Fatal Received */
+#define PCI_ERR_ROOT_COR_SRC	52
+#define PCI_ERR_ROOT_SRC	54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1	4
+#define PCI_VC_PORT_REG2	8
+#define PCI_VC_PORT_CTRL	12
+#define PCI_VC_PORT_STATUS	14
+#define PCI_VC_RES_CAP		16
+#define PCI_VC_RES_CTRL		20
+#define PCI_VC_RES_STATUS	26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR		4	/* Data Select Register */
+#define PCI_PWR_DATA		8	/* Data Register */
+#define  PCI_PWR_DATA_BASE(x)	((x) & 0xff)	    /* Base Power */
+#define  PCI_PWR_DATA_SCALE(x)	(((x) >> 8) & 3)    /* Data Scale */
+#define  PCI_PWR_DATA_PM_SUB(x)	(((x) >> 10) & 7)   /* PM Sub State */
+#define  PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define  PCI_PWR_DATA_TYPE(x)	(((x) >> 15) & 7)   /* Type */
+#define  PCI_PWR_DATA_RAIL(x)	(((x) >> 18) & 7)   /* Power Rail */
+#define PCI_PWR_CAP		12	/* Capability */
+#define  PCI_PWR_CAP_BUDGET(x)	((x) & 1)	/* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK	0xE0
+#define HT_CAPTYPE_SLAVE	0x00	/* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST		0x20	/* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK	0xF8
+#define HT_CAPTYPE_IRQ		0x80	/* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40	0xA0	/* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2	/* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP	0x90	/* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF	0x98	/* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING	0xA8	/* MSI Mapping Capability */
+#define  HT_MSI_FLAGS		0x02		/* Offset to flags */
+#define  HT_MSI_FLAGS_ENABLE	0x1		/* Mapping enable */
+#define  HT_MSI_FLAGS_FIXED	0x2		/* Fixed mapping only */
+#define  HT_MSI_FIXED_ADDR	0x00000000FEE00000ULL	/* Fixed addr */
+#define  HT_MSI_ADDR_LO		0x04		/* Offset to low addr bits */
+#define  HT_MSI_ADDR_LO_MASK	0xFFF00000	/* Low address bit mask */
+#define  HT_MSI_ADDR_HI		0x08		/* Offset to high addr bits */
+#define HT_CAPTYPE_DIRECT_ROUTE	0xB0	/* Direct routing configuration */
+#define HT_CAPTYPE_VCSET	0xB8	/* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY	0xC0	/* Retry on error configuration */
+#define HT_CAPTYPE_GEN3		0xD0	/* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM		0xE0	/* Hypertransport powermanagement configuration */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP		0x04	/* ARI Capability Register */
+#define  PCI_ARI_CAP_MFVC	0x0001	/* MFVC Function Groups Capability */
+#define  PCI_ARI_CAP_ACS	0x0002	/* ACS Function Groups Capability */
+#define  PCI_ARI_CAP_NFN(x)	(((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL		0x06	/* ARI Control Register */
+#define  PCI_ARI_CTRL_MFVC	0x0001	/* MFVC Function Groups Enable */
+#define  PCI_ARI_CTRL_ACS	0x0002	/* ACS Function Groups Enable */
+#define  PCI_ARI_CTRL_FG(x)	(((x) >> 4) & 7) /* Function Group */
+
+#endif /* LINUX_PCI_REGS_H */
diff --git a/qemu-0.15.x/roms/seabios/src/pcibios.c b/qemu-0.15.x/roms/seabios/src/pcibios.c
new file mode 100644
index 0000000..a23248b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pcibios.c
@@ -0,0 +1,234 @@
+// PCI BIOS (int 1a/b1) calls
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u32
+#include "util.h" // handle_1ab1
+#include "pci.h" // pci_config_readl
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "pci_regs.h" // PCI_VENDOR_ID
+
+// romlayout.S
+extern void bios32_entry(void);
+extern void pcibios32_entry(void);
+
+#define RET_FUNC_NOT_SUPPORTED 0x81
+#define RET_BAD_VENDOR_ID      0x83
+#define RET_DEVICE_NOT_FOUND   0x86
+#define RET_BUFFER_TOO_SMALL   0x89
+
+// installation check
+static void
+handle_1ab101(struct bregs *regs)
+{
+    // Find max bus.
+    int bdf, max;
+    foreachpci(bdf, max) {
+    }
+
+    regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
+    regs->bx = 0x0210; // PCI version 2.10
+    regs->cl = pci_bdf_to_bus(max - 1);
+    regs->edx = 0x20494350; // "PCI "
+    regs->edi = (u32)pcibios32_entry + BUILD_BIOS_ADDR;
+    set_code_success(regs);
+}
+
+// find pci device
+static void
+handle_1ab102(struct bregs *regs)
+{
+    u32 id = (regs->cx << 16) | regs->dx;
+    int count = regs->si;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
+        if (v != id)
+            continue;
+        if (count--)
+            continue;
+        regs->bx = bdf;
+        set_code_success(regs);
+        return;
+    }
+    set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// find class code
+static void
+handle_1ab103(struct bregs *regs)
+{
+    int count = regs->si;
+    u32 classprog = regs->ecx;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
+        if ((v>>8) != classprog)
+            continue;
+        if (count--)
+            continue;
+        regs->bx = bdf;
+        set_code_success(regs);
+        return;
+    }
+    set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// read configuration byte
+static void
+handle_1ab108(struct bregs *regs)
+{
+    regs->cl = pci_config_readb(regs->bx, regs->di);
+    set_code_success(regs);
+}
+
+// read configuration word
+static void
+handle_1ab109(struct bregs *regs)
+{
+    regs->cx = pci_config_readw(regs->bx, regs->di);
+    set_code_success(regs);
+}
+
+// read configuration dword
+static void
+handle_1ab10a(struct bregs *regs)
+{
+    regs->ecx = pci_config_readl(regs->bx, regs->di);
+    set_code_success(regs);
+}
+
+// write configuration byte
+static void
+handle_1ab10b(struct bregs *regs)
+{
+    pci_config_writeb(regs->bx, regs->di, regs->cl);
+    set_code_success(regs);
+}
+
+// write configuration word
+static void
+handle_1ab10c(struct bregs *regs)
+{
+    pci_config_writew(regs->bx, regs->di, regs->cx);
+    set_code_success(regs);
+}
+
+// write configuration dword
+static void
+handle_1ab10d(struct bregs *regs)
+{
+    pci_config_writel(regs->bx, regs->di, regs->ecx);
+    set_code_success(regs);
+}
+
+// get irq routing options
+static void
+handle_1ab10e(struct bregs *regs)
+{
+    struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
+    if (! pirtable_g) {
+        set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
+        return;
+    }
+
+    struct param_s {
+        u16 size;
+        u16 buf_off;
+        u16 buf_seg;
+    } *param_far = (void*)(regs->di+0);
+
+    // Validate and update size.
+    u16 bufsize = GET_FARVAR(regs->es, param_far->size);
+    u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
+    SET_FARVAR(regs->es, param_far->size, pirsize);
+    if (bufsize < pirsize) {
+        set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
+        return;
+    }
+
+    // Get dest buffer.
+    void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
+    u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
+
+    // Memcpy pir table slots to dest buffer.
+    memcpy_far(buf_seg, buf_far
+               , get_global_seg()
+               , (void*)(pirtable_g->slots) + get_global_offset()
+               , pirsize);
+
+    // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
+    regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
+    set_code_success(regs);
+}
+
+static void
+handle_1ab1XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
+}
+
+void
+handle_1ab1(struct bregs *regs)
+{
+    //debug_stub(regs);
+
+    if (! CONFIG_PCIBIOS) {
+        set_invalid(regs);
+        return;
+    }
+
+    switch (regs->al) {
+    case 0x01: handle_1ab101(regs); break;
+    case 0x02: handle_1ab102(regs); break;
+    case 0x03: handle_1ab103(regs); break;
+    case 0x08: handle_1ab108(regs); break;
+    case 0x09: handle_1ab109(regs); break;
+    case 0x0a: handle_1ab10a(regs); break;
+    case 0x0b: handle_1ab10b(regs); break;
+    case 0x0c: handle_1ab10c(regs); break;
+    case 0x0d: handle_1ab10d(regs); break;
+    case 0x0e: handle_1ab10e(regs); break;
+    default:   handle_1ab1XX(regs); break;
+    }
+}
+
+
+/****************************************************************
+ * 32bit interface
+ ****************************************************************/
+
+// Entry point for 32bit pci bios functions.
+void VISIBLE32SEG
+handle_pcibios32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_pcibios32);
+    handle_1ab1(regs);
+}
+
+struct bios32_s {
+    u32 signature;
+    u32 entry;
+    u8 version;
+    u8 length;
+    u8 checksum;
+    u8 reserved[5];
+} PACKED;
+
+struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
+    .signature = 0x5f32335f, // _32_
+    .length = sizeof(BIOS32HEADER) / 16,
+};
+
+void
+bios32_setup(void)
+{
+    dprintf(3, "init bios32\n");
+
+    BIOS32HEADER.entry = (u32)bios32_entry;
+    BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pciinit.c b/qemu-0.15.x/roms/seabios/src/pciinit.c
new file mode 100644
index 0000000..ee2e72d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pciinit.c
@@ -0,0 +1,418 @@
+// Initialize PCI devices (on emulators)
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_config_readl
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_COMMAND
+#include "dev-i440fx.h"
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+static void pci_bios_init_device_in_bus(int bus);
+
+static struct pci_region pci_bios_io_region;
+static struct pci_region pci_bios_mem_region;
+static struct pci_region pci_bios_prefmem_region;
+
+/* host irqs corresponding to PCI irqs A-D */
+const u8 pci_irqs[4] = {
+    10, 10, 11, 11
+};
+
+static u32 pci_bar(u16 bdf, int region_num)
+{
+    if (region_num != PCI_ROM_SLOT) {
+        return PCI_BASE_ADDRESS_0 + region_num * 4;
+    }
+
+#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+    u8 type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+    type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
+}
+
+static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr)
+{
+    u32 ofs;
+
+    ofs = pci_bar(bdf, region_num);
+
+    pci_config_writel(bdf, ofs, addr);
+    dprintf(1, "region %d: 0x%08x\n", region_num, addr);
+}
+
+/*
+ * return value
+ *      0:     32bit BAR
+ *      non 0: 64bit BAR
+ */
+static int pci_bios_allocate_region(u16 bdf, int region_num)
+{
+    struct pci_region *r;
+    u32 ofs = pci_bar(bdf, region_num);
+
+    u32 old = pci_config_readl(bdf, ofs);
+    u32 mask;
+    if (region_num == PCI_ROM_SLOT) {
+        mask = PCI_ROM_ADDRESS_MASK;
+        pci_config_writel(bdf, ofs, mask);
+    } else {
+        if (old & PCI_BASE_ADDRESS_SPACE_IO)
+            mask = PCI_BASE_ADDRESS_IO_MASK;
+        else
+            mask = PCI_BASE_ADDRESS_MEM_MASK;
+        pci_config_writel(bdf, ofs, ~0);
+    }
+    u32 val = pci_config_readl(bdf, ofs);
+    pci_config_writel(bdf, ofs, old);
+
+    u32 size = (~(val & mask)) + 1;
+    if (val != 0) {
+        const char *type;
+        const char *msg;
+        if (val & PCI_BASE_ADDRESS_SPACE_IO) {
+            r = &pci_bios_io_region;
+            type = "io";
+            msg = "";
+        } else if ((val & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
+                   /* keep behaviour on bus = 0 */
+                   pci_bdf_to_bus(bdf) != 0 &&
+                   /* If pci_bios_prefmem_addr == 0, keep old behaviour */
+                   pci_region_addr(&pci_bios_prefmem_region) != 0) {
+            r = &pci_bios_prefmem_region;
+            type = "prefmem";
+            msg = "decrease BUILD_PCIMEM_SIZE and recompile. size %x";
+        } else {
+            r = &pci_bios_mem_region;
+            type = "mem";
+            msg = "increase BUILD_PCIMEM_SIZE and recompile.";
+        }
+        u32 addr = pci_region_alloc(r, size);
+        if (addr > 0) {
+            pci_set_io_region_addr(bdf, region_num, addr);
+        } else {
+            size = 0;
+            dprintf(1,
+                    "%s region of (bdf 0x%x bar %d) can't be mapped. "
+                    "%s size %x\n",
+                    type, bdf, region_num, msg, pci_region_size(r));
+        }
+    }
+
+    int is_64bit = !(val & PCI_BASE_ADDRESS_SPACE_IO) &&
+        (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64;
+    if (is_64bit && size > 0) {
+        pci_config_writel(bdf, ofs + 4, 0);
+    }
+    return is_64bit;
+}
+
+void pci_bios_allocate_regions(u16 bdf, void *arg)
+{
+    int i;
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        int is_64bit = pci_bios_allocate_region(bdf, i);
+        if (is_64bit){
+            i++;
+        }
+    }
+}
+
+/* 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(u16 bdf, int irq_num)
+{
+    int slot_addend = pci_bdf_to_dev(bdf) - 1;
+    return (irq_num + slot_addend) & 3;
+}
+
+static const struct pci_device_id pci_isa_bridge_tbl[] = {
+    /* PIIX3/PIIX4 PCI to ISA bridge */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
+               piix_isa_bridge_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+               piix_isa_bridge_init),
+
+    PCI_DEVICE_END
+};
+
+#define PCI_IO_ALIGN            4096
+#define PCI_IO_SHIFT            8
+#define PCI_MEMORY_ALIGN        (1UL << 20)
+#define PCI_MEMORY_SHIFT        16
+#define PCI_PREF_MEMORY_ALIGN   (1UL << 20)
+#define PCI_PREF_MEMORY_SHIFT   16
+
+static void pci_bios_init_device_bridge(u16 bdf, void *arg)
+{
+    pci_bios_allocate_region(bdf, 0);
+    pci_bios_allocate_region(bdf, 1);
+    pci_bios_allocate_region(bdf, PCI_ROM_SLOT);
+
+    u32 io_old = pci_region_addr(&pci_bios_io_region);
+    u32 mem_old = pci_region_addr(&pci_bios_mem_region);
+    u32 prefmem_old = pci_region_addr(&pci_bios_prefmem_region);
+
+    /* IO BASE is assumed to be 16 bit */
+    if (pci_region_align(&pci_bios_io_region, PCI_IO_ALIGN) == 0) {
+        pci_region_disable(&pci_bios_io_region);
+    }
+    if (pci_region_align(&pci_bios_mem_region, PCI_MEMORY_ALIGN) == 0) {
+        pci_region_disable(&pci_bios_mem_region);
+    }
+    if (pci_region_align(&pci_bios_prefmem_region,
+                         PCI_PREF_MEMORY_ALIGN) == 0) {
+        pci_region_disable(&pci_bios_prefmem_region);
+    }
+
+    u32 io_base = pci_region_addr(&pci_bios_io_region);
+    u32 mem_base = pci_region_addr(&pci_bios_mem_region);
+    u32 prefmem_base = pci_region_addr(&pci_bios_prefmem_region);
+
+    u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+    if (secbus > 0) {
+        pci_bios_init_device_in_bus(secbus);
+    }
+
+    u32 io_end = pci_region_align(&pci_bios_io_region, PCI_IO_ALIGN);
+    if (io_end == 0) {
+        pci_region_revert(&pci_bios_io_region, io_old);
+        io_base = 0xffff;
+        io_end = 1;
+    }
+    pci_config_writeb(bdf, PCI_IO_BASE, io_base >> PCI_IO_SHIFT);
+    pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
+    pci_config_writeb(bdf, PCI_IO_LIMIT, (io_end - 1) >> PCI_IO_SHIFT);
+    pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
+
+    u32 mem_end = pci_region_align(&pci_bios_mem_region, PCI_MEMORY_ALIGN);
+    if (mem_end == 0) {
+        pci_region_revert(&pci_bios_mem_region, mem_old);
+        mem_base = 0xffffffff;
+        mem_end = 1;
+    }
+    pci_config_writew(bdf, PCI_MEMORY_BASE, mem_base >> PCI_MEMORY_SHIFT);
+    pci_config_writew(bdf, PCI_MEMORY_LIMIT, (mem_end -1) >> PCI_MEMORY_SHIFT);
+
+    u32 prefmem_end = pci_region_align(&pci_bios_prefmem_region,
+                                       PCI_PREF_MEMORY_ALIGN);
+    if (prefmem_end == 0) {
+        pci_region_revert(&pci_bios_prefmem_region, prefmem_old);
+        prefmem_base = 0xffffffff;
+        prefmem_end = 1;
+    }
+    pci_config_writew(bdf, PCI_PREF_MEMORY_BASE,
+                      prefmem_base >> PCI_PREF_MEMORY_SHIFT);
+    pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT,
+                      (prefmem_end - 1) >> PCI_PREF_MEMORY_SHIFT);
+    pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
+    pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
+
+    dprintf(1, "PCI: br io   = [0x%x, 0x%x)\n", io_base, io_end);
+    dprintf(1, "PCI: br mem  = [0x%x, 0x%x)\n", mem_base, mem_end);
+    dprintf(1, "PCI: br pref = [0x%x, 0x%x)\n", prefmem_base, prefmem_end);
+
+    u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
+    cmd &= ~PCI_COMMAND_IO;
+    if (io_end > io_base) {
+        cmd |= PCI_COMMAND_IO;
+    }
+    cmd &= ~PCI_COMMAND_MEMORY;
+    if (mem_end > mem_base || prefmem_end > prefmem_base) {
+        cmd |= PCI_COMMAND_MEMORY;
+    }
+    cmd |= PCI_COMMAND_MASTER;
+    pci_config_writew(bdf, PCI_COMMAND, cmd);
+
+    pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_SERR);
+}
+
+static void storage_ide_init(u16 bdf, void *arg)
+{
+    /* IDE: we map it as in ISA mode */
+    pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE);
+    pci_set_io_region_addr(bdf, 1, PORT_ATA1_CTRL_BASE);
+    pci_set_io_region_addr(bdf, 2, PORT_ATA2_CMD_BASE);
+    pci_set_io_region_addr(bdf, 3, PORT_ATA2_CTRL_BASE);
+}
+
+static void pic_ibm_init(u16 bdf, void *arg)
+{
+    /* PIC, IBM, MPIC & MPIC2 */
+    pci_set_io_region_addr(bdf, 0, 0x80800000 + 0x00040000);
+}
+
+static void apple_macio_init(u16 bdf, void *arg)
+{
+    /* macio bridge */
+    pci_set_io_region_addr(bdf, 0, 0x80800000);
+}
+
+static const struct pci_device_id pci_class_tbl[] = {
+    /* STORAGE IDE */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
+                     PCI_CLASS_STORAGE_IDE, piix_ide_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+                     PCI_CLASS_STORAGE_IDE, piix_ide_init),
+    PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+                     storage_ide_init),
+
+    /* PIC, IBM, MIPC & MPIC2 */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
+                     pic_ibm_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
+                     pic_ibm_init),
+
+    /* 0xff00 */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init),
+
+    /* PCI bridge */
+    PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI,
+                     pci_bios_init_device_bridge),
+
+    /* default */
+    PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID, pci_bios_allocate_regions),
+
+    PCI_DEVICE_END,
+};
+
+static const struct pci_device_id pci_device_tbl[] = {
+    /* PIIX4 Power Management device (for ACPI) */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+               piix4_pm_init),
+
+    PCI_DEVICE_END,
+};
+
+static void pci_bios_init_device(u16 bdf)
+{
+    int pin, pic_irq, vendor_id, device_id;
+
+    vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
+    device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
+    dprintf(1, "PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_devfn(bdf), vendor_id, device_id);
+    pci_init_device(pci_class_tbl, bdf, NULL);
+
+    /* enable memory mappings */
+    pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    /* map the interrupt */
+    pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+    if (pin != 0) {
+        pin = pci_slot_get_pirq(bdf, pin - 1);
+        pic_irq = pci_irqs[pin];
+        pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pic_irq);
+    }
+
+    pci_init_device(pci_device_tbl, bdf, NULL);
+}
+
+static void pci_bios_init_device_in_bus(int bus)
+{
+    int bdf, max;
+    foreachpci_in_bus(bdf, max, bus) {
+        pci_bios_init_device(bdf);
+    }
+}
+
+static void
+pci_bios_init_bus_rec(int bus, u8 *pci_bus)
+{
+    int bdf, max;
+    u16 class;
+
+    dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
+
+    /* prevent accidental access to unintended devices */
+    foreachpci_in_bus(bdf, max, bus) {
+        class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+        if (class == PCI_CLASS_BRIDGE_PCI) {
+            pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255);
+            pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0);
+        }
+    }
+
+    foreachpci_in_bus(bdf, max, bus) {
+        class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+        if (class != PCI_CLASS_BRIDGE_PCI) {
+            continue;
+        }
+        dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf);
+
+        u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS);
+        if (pribus != bus) {
+            dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus);
+            pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus);
+        } else {
+            dprintf(1, "PCI: primary bus = 0x%x\n", pribus);
+        }
+
+        u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+        (*pci_bus)++;
+        if (*pci_bus != secbus) {
+            dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n",
+                    secbus, *pci_bus);
+            secbus = *pci_bus;
+            pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus);
+        } else {
+            dprintf(1, "PCI: secondary bus = 0x%x\n", secbus);
+        }
+
+        /* set to max for access to all subordinate buses.
+           later set it to accurate value */
+        u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS);
+        pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255);
+
+        pci_bios_init_bus_rec(secbus, pci_bus);
+
+        if (subbus != *pci_bus) {
+            dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
+                    subbus, *pci_bus);
+            subbus = *pci_bus;
+        } else {
+            dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
+        }
+        pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus);
+    }
+}
+
+static void
+pci_bios_init_bus(void)
+{
+    u8 pci_bus = 0;
+    pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
+}
+
+void
+pci_setup(void)
+{
+    if (CONFIG_COREBOOT)
+        // Already done by coreboot.
+        return;
+
+    dprintf(3, "pci setup\n");
+
+    pci_region_init(&pci_bios_io_region, 0xc000, 64 * 1024 - 1);
+    pci_region_init(&pci_bios_mem_region,
+                    BUILD_PCIMEM_START, BUILD_PCIMEM_END - 1);
+    pci_region_init(&pci_bios_prefmem_region,
+                    BUILD_PCIPREFMEM_START, BUILD_PCIPREFMEM_END - 1);
+
+    pci_bios_init_bus();
+
+    int bdf, max;
+    foreachpci(bdf, max) {
+        pci_init_device(pci_isa_bridge_tbl, bdf, NULL);
+    }
+    pci_bios_init_device_in_bus(0 /* host bus */);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pic.c b/qemu-0.15.x/roms/seabios/src/pic.c
new file mode 100644
index 0000000..8992a8b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pic.c
@@ -0,0 +1,52 @@
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pic.h" // get_pic1_isr
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+
+void
+set_pics(u8 irq0, u8 irq8)
+{
+    // Send ICW1 (select OCW1 + will send ICW4)
+    outb(0x11, PORT_PIC1_CMD);
+    outb(0x11, PORT_PIC2_CMD);
+    // Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15)
+    outb(irq0, PORT_PIC1_DATA);
+    outb(irq8, PORT_PIC2_DATA);
+    // Send ICW3 (cascaded pic ids)
+    outb(0x04, PORT_PIC1_DATA);
+    outb(0x02, PORT_PIC2_DATA);
+    // Send ICW4 (enable 8086 mode)
+    outb(0x01, PORT_PIC1_DATA);
+    outb(0x01, PORT_PIC2_DATA);
+    // Mask all irqs (except cascaded PIC2 irq)
+    outb(~PIC1_IRQ2, PORT_PIC1_DATA);
+    outb(~0, PORT_PIC2_DATA);
+}
+
+void
+pic_setup(void)
+{
+    dprintf(3, "init pic\n");
+    set_pics(0x08, 0x70);
+}
+
+// Handler for otherwise unused hardware irqs.
+void VISIBLE16
+handle_hwpic1(struct bregs *regs)
+{
+    dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", get_pic1_isr());
+    eoi_pic1();
+}
+
+void VISIBLE16
+handle_hwpic2(struct bregs *regs)
+{
+    dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", get_pic2_isr());
+    eoi_pic2();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pic.h b/qemu-0.15.x/roms/seabios/src/pic.h
new file mode 100644
index 0000000..c75af3e
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pic.h
@@ -0,0 +1,97 @@
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __PIC_H
+#define __PIC_H
+
+#include "ioport.h" // PORT_PIC*
+#include "biosvar.h" // SET_IVT
+
+// PORT_PIC1 bitdefs
+#define PIC1_IRQ0  (1<<0)
+#define PIC1_IRQ1  (1<<1)
+#define PIC1_IRQ2  (1<<2)
+#define PIC1_IRQ5  (1<<5)
+#define PIC1_IRQ6  (1<<6)
+// PORT_PIC2 bitdefs
+#define PIC2_IRQ8  (1<<0)
+#define PIC2_IRQ12 (1<<4)
+#define PIC2_IRQ13 (1<<5)
+#define PIC2_IRQ14 (1<<6)
+
+static inline void
+eoi_pic1(void)
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+eoi_pic2(void)
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC2_CMD);
+    eoi_pic1();
+}
+
+static inline void
+unmask_pic1(u8 irq)
+{
+    outb(inb(PORT_PIC1_DATA) & ~irq, PORT_PIC1_DATA);
+}
+
+static inline void
+unmask_pic2(u8 irq)
+{
+    outb(inb(PORT_PIC2_DATA) & ~irq, PORT_PIC2_DATA);
+}
+
+static inline void
+mask_pic1(u8 irq)
+{
+    outb(inb(PORT_PIC1_DATA) | irq, PORT_PIC1_DATA);
+}
+
+static inline void
+mask_pic2(u8 irq)
+{
+    outb(inb(PORT_PIC2_DATA) | irq, PORT_PIC2_DATA);
+}
+
+static inline u8
+get_pic1_isr(void)
+{
+    // 0x0b == select OCW1 + read ISR
+    outb(0x0b, PORT_PIC1_CMD);
+    return inb(PORT_PIC1_CMD);
+}
+
+static inline u8
+get_pic2_isr(void)
+{
+    // 0x0b == select OCW1 + read ISR
+    outb(0x0b, PORT_PIC2_CMD);
+    return inb(PORT_PIC2_CMD);
+}
+
+static inline void
+enable_hwirq(int hwirq, struct segoff_s func)
+{
+    int vector;
+    if (hwirq < 8) {
+        unmask_pic1(1 << hwirq);
+        vector = 0x08 + hwirq;
+    } else {
+        unmask_pic2(1 << (hwirq - 8));
+        vector = 0x70 + hwirq - 8;
+    }
+    SET_IVT(vector, func);
+}
+
+void set_pics(u8 irq0, u8 irq8);
+void pic_setup(void);
+
+#endif // pic.h
diff --git a/qemu-0.15.x/roms/seabios/src/pirtable.c b/qemu-0.15.x/roms/seabios/src/pirtable.c
new file mode 100644
index 0000000..4c3f1ff
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pirtable.c
@@ -0,0 +1,105 @@
+// PIR table generation (for emulators)
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // struct pir_header
+#include "util.h" // checksum
+#include "biosvar.h" // SET_EBDA
+
+u16 PirOffset VAR16VISIBLE;
+
+struct pir_table {
+    struct pir_header pir;
+    struct pir_slot slots[6];
+} PACKED;
+
+extern struct pir_table PIR_TABLE;
+#if CONFIG_PIRTABLE && !CONFIG_COREBOOT
+struct pir_table PIR_TABLE __aligned(16) VAR16EXPORT = {
+    .pir = {
+        .version = 0x0100,
+        .size = sizeof(struct pir_table),
+        .router_devfunc = 0x08,
+        .compatible_devid = 0x122e8086,
+    },
+    .slots = {
+        {
+            // first slot entry PCI-to-ISA (embedded)
+            .dev = 1<<3,
+            .links = {
+                {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 0, // embedded
+        }, {
+            // second slot entry: 1st PCI slot
+            .dev = 2<<3,
+            .links = {
+                {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 1,
+        }, {
+            // third slot entry: 2nd PCI slot
+            .dev = 3<<3,
+            .links = {
+                {.link = 0x62, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x63, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x60, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x61, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 2,
+        }, {
+            // 4th slot entry: 3rd PCI slot
+            .dev = 4<<3,
+            .links = {
+                {.link = 0x63, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x60, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x61, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x62, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 3,
+        }, {
+            // 5th slot entry: 4rd PCI slot
+            .dev = 5<<3,
+            .links = {
+                {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 4,
+        }, {
+            // 6th slot entry: 5rd PCI slot
+            .dev = 6<<3,
+            .links = {
+                {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+                {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+                {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+                {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+            },
+            .slot_nr = 5,
+        },
+    }
+};
+#endif // CONFIG_PIRTABLE && !CONFIG_COREBOOT
+
+void
+create_pirtable(void)
+{
+    if (! CONFIG_PIRTABLE)
+        return;
+
+    dprintf(3, "init PIR table\n");
+
+    PIR_TABLE.pir.signature = PIR_SIGNATURE;
+    PIR_TABLE.pir.checksum -= checksum(&PIR_TABLE, sizeof(PIR_TABLE));
+    PirOffset = (u32)&PIR_TABLE.pir - BUILD_BIOS_ADDR;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pmm.c b/qemu-0.15.x/roms/seabios/src/pmm.c
new file mode 100644
index 0000000..e0770ac
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pmm.c
@@ -0,0 +1,588 @@
+// Post memory manager (PMM) calls
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "memmap.h" // struct e820entry
+#include "farptr.h" // GET_FARVAR
+#include "biosvar.h" // GET_BDA
+
+
+#if MODESEGMENT
+// The 16bit pmm entry points runs in "big real" mode, and can
+// therefore read/write to the 32bit malloc variables.
+#define GET_PMMVAR(var) ({                      \
+            SET_SEG(ES, 0);                     \
+            __GET_VAR("addr32 ", ES, (var)); })
+#define SET_PMMVAR(var, val) do {               \
+        SET_SEG(ES, 0);                         \
+        __SET_VAR("addr32 ", ES, (var), (val)); \
+    } while (0)
+#else
+#define GET_PMMVAR(var) (var)
+#define SET_PMMVAR(var, val) do { (var) = (val); } while (0)
+#endif
+
+// Information on a reserved area.
+struct allocinfo_s {
+    struct allocinfo_s *next, **pprev;
+    void *data, *dataend, *allocend;
+};
+
+// Information on a tracked memory allocation.
+struct allocdetail_s {
+    struct allocinfo_s detailinfo;
+    struct allocinfo_s datainfo;
+    u32 handle;
+};
+
+// The various memory zones.
+struct zone_s {
+    struct allocinfo_s *info;
+};
+
+struct zone_s ZoneLow VAR32FLATVISIBLE;
+struct zone_s ZoneHigh VAR32FLATVISIBLE;
+struct zone_s ZoneFSeg VAR32FLATVISIBLE;
+struct zone_s ZoneTmpLow VAR32FLATVISIBLE;
+struct zone_s ZoneTmpHigh VAR32FLATVISIBLE;
+
+struct zone_s *Zones[] VAR32FLATVISIBLE = {
+    &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
+};
+
+
+/****************************************************************
+ * low-level memory reservations
+ ****************************************************************/
+
+// Find and reserve space from a given zone
+static void *
+allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
+{
+    struct allocinfo_s *info;
+    for (info = GET_PMMVAR(zone->info); info; info = GET_PMMVAR(info->next)) {
+        void *dataend = GET_PMMVAR(info->dataend);
+        void *allocend = GET_PMMVAR(info->allocend);
+        void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
+        if (newallocend >= dataend && newallocend <= allocend) {
+            // Found space - now reserve it.
+            struct allocinfo_s **pprev = GET_PMMVAR(info->pprev);
+            if (!fill)
+                fill = newallocend;
+            SET_PMMVAR(fill->next, info);
+            SET_PMMVAR(fill->pprev, pprev);
+            SET_PMMVAR(fill->data, newallocend);
+            SET_PMMVAR(fill->dataend, newallocend + size);
+            SET_PMMVAR(fill->allocend, allocend);
+
+            SET_PMMVAR(info->allocend, newallocend);
+            SET_PMMVAR(info->pprev, &fill->next);
+            SET_PMMVAR(*pprev, fill);
+            return newallocend;
+        }
+    }
+    return NULL;
+}
+
+// Release space allocated with allocSpace()
+static void
+freeSpace(struct allocinfo_s *info)
+{
+    struct allocinfo_s *next = GET_PMMVAR(info->next);
+    struct allocinfo_s **pprev = GET_PMMVAR(info->pprev);
+    SET_PMMVAR(*pprev, next);
+    if (next) {
+        if (GET_PMMVAR(next->allocend) == GET_PMMVAR(info->data))
+            SET_PMMVAR(next->allocend, GET_PMMVAR(info->allocend));
+        SET_PMMVAR(next->pprev, pprev);
+    }
+}
+
+// Add new memory to a zone
+static void
+addSpace(struct zone_s *zone, void *start, void *end)
+{
+    // Find position to add space
+    struct allocinfo_s **pprev = &zone->info, *info;
+    for (;;) {
+        info = GET_PMMVAR(*pprev);
+        if (!info || GET_PMMVAR(info->data) < start)
+            break;
+        pprev = &info->next;
+    }
+
+    // Add space using temporary allocation info.
+    struct allocdetail_s tempdetail;
+    tempdetail.datainfo.next = info;
+    tempdetail.datainfo.pprev = pprev;
+    tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
+    tempdetail.datainfo.allocend = end;
+    struct allocdetail_s *tempdetailp = MAKE_FLATPTR(GET_SEG(SS), &tempdetail);
+    SET_PMMVAR(*pprev, &tempdetailp->datainfo);
+    if (info)
+        SET_PMMVAR(info->pprev, &tempdetailp->datainfo.next);
+
+    // Allocate final allocation info.
+    struct allocdetail_s *detail = allocSpace(
+        &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+    if (!detail) {
+        detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+                            , MALLOC_MIN_ALIGN, NULL);
+        if (!detail) {
+            SET_PMMVAR(*tempdetail.datainfo.pprev, tempdetail.datainfo.next);
+            if (tempdetail.datainfo.next)
+                SET_PMMVAR(tempdetail.datainfo.next->pprev
+                           , tempdetail.datainfo.pprev);
+            warn_noalloc();
+            return;
+        }
+    }
+
+    // Replace temp alloc space with final alloc space
+    memcpy_fl(&detail->datainfo, &tempdetailp->datainfo
+              , sizeof(detail->datainfo));
+    SET_PMMVAR(detail->handle, PMM_DEFAULT_HANDLE);
+
+    SET_PMMVAR(*tempdetail.datainfo.pprev, &detail->datainfo);
+    if (tempdetail.datainfo.next)
+        SET_PMMVAR(tempdetail.datainfo.next->pprev, &detail->datainfo.next);
+}
+
+// Search all zones for an allocation obtained from allocSpace()
+static struct allocinfo_s *
+findAlloc(void *data)
+{
+    int i;
+    for (i=0; i<ARRAY_SIZE(Zones); i++) {
+        struct zone_s *zone = GET_PMMVAR(Zones[i]);
+        struct allocinfo_s *info;
+        for (info = GET_PMMVAR(zone->info); info; info = GET_PMMVAR(info->next))
+            if (GET_PMMVAR(info->data) == data)
+                return info;
+    }
+    return NULL;
+}
+
+// Return the last sentinal node of a zone
+static struct allocinfo_s *
+findLast(struct zone_s *zone)
+{
+    struct allocinfo_s *info = GET_PMMVAR(zone->info);
+    if (!info)
+        return NULL;
+    for (;;) {
+        struct allocinfo_s *next = GET_PMMVAR(info->next);
+        if (!next)
+            return info;
+        info = next;
+    }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_setup(void)
+{
+    ASSERT32FLAT();
+    dprintf(3, "malloc setup\n");
+
+    // Populate temp high ram
+    u32 highram = 0;
+    int i;
+    for (i=e820_count-1; i>=0; i--) {
+        struct e820entry *en = &e820_list[i];
+        u64 end = en->start + en->size;
+        if (end < 1024*1024)
+            break;
+        if (en->type != E820_RAM || end > 0xffffffff)
+            continue;
+        u32 s = en->start, e = end;
+        if (!highram) {
+            u32 newe = ALIGN_DOWN(e - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
+            if (newe <= e && newe >= s) {
+                highram = newe;
+                e = newe;
+            }
+        }
+        addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+    }
+
+    // Populate other regions
+    addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+    addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
+    addSpace(&ZoneLow, (void*)BUILD_LOWRAM_END, (void*)BUILD_LOWRAM_END);
+    if (highram) {
+        addSpace(&ZoneHigh, (void*)highram
+                 , (void*)highram + CONFIG_MAX_HIGHTABLE);
+        add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
+    }
+}
+
+void
+malloc_finalize(void)
+{
+    dprintf(3, "malloc finalize\n");
+
+    // Reserve more low-mem if needed.
+    u32 endlow = GET_BDA(mem_size_kb)*1024;
+    add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+
+    // Give back unused high ram.
+    struct allocinfo_s *info = findLast(&ZoneHigh);
+    if (info) {
+        u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
+        add_e820((u32)info->dataend, giveback, E820_RAM);
+        dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
+    }
+}
+
+
+/****************************************************************
+ * ebda movement
+ ****************************************************************/
+
+// Move ebda
+static int
+relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
+{
+    u32 lowram = GET_BDA(mem_size_kb) * 1024;
+    if (oldebda != lowram)
+        // EBDA isn't at end of ram - give up.
+        return -1;
+
+    // Do copy (this assumes memcpy copies forward - otherwise memmove
+    // is needed)
+    memcpy_fl((void*)newebda, (void*)oldebda, ebda_size * 1024);
+
+    // Update indexes
+    dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda);
+    SET_BDA(mem_size_kb, newebda / 1024);
+    SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda));
+    return 0;
+}
+
+// Support expanding the ZoneLow dynamically.
+static void
+zonelow_expand(u32 size, u32 align)
+{
+    struct allocinfo_s *info = findLast(&ZoneLow);
+    if (!info)
+        return;
+    u32 oldpos = (u32)GET_PMMVAR(info->allocend);
+    u32 newpos = ALIGN_DOWN(oldpos - size, align);
+    u32 bottom = (u32)GET_PMMVAR(info->dataend);
+    if (newpos >= bottom && newpos <= oldpos)
+        // Space already present.
+        return;
+    u16 ebda_seg = get_ebda_seg();
+    u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
+    u8 ebda_size = GET_EBDA2(ebda_seg, size);
+    u32 ebda_end = ebda_pos + ebda_size * 1024;
+    if (ebda_end != bottom)
+        // Something else is after ebda - can't use any existing space.
+        newpos = ALIGN_DOWN(ebda_end - size, align);
+    u32 newbottom = ALIGN_DOWN(newpos, 1024);
+    u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
+    if (newebda < BUILD_EBDA_MINIMUM)
+        // Not enough space.
+        return;
+
+    // Move ebda
+    int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
+    if (ret)
+        return;
+
+    // Update zone
+    if (ebda_end == bottom) {
+        SET_PMMVAR(info->data, (void*)newbottom);
+        SET_PMMVAR(info->dataend, (void*)newbottom);
+    } else
+        addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+}
+
+// Check if can expand the given zone to fulfill an allocation
+static void *
+allocExpandSpace(struct zone_s *zone, u32 size, u32 align
+                 , struct allocinfo_s *fill)
+{
+    void *data = allocSpace(zone, size, align, fill);
+    if (data || zone != &ZoneLow)
+        return data;
+
+    // Make sure to not move ebda while an optionrom is running.
+    if (unlikely(wait_preempt())) {
+        data = allocSpace(zone, size, align, fill);
+        if (data)
+            return data;
+    }
+
+    zonelow_expand(size, align);
+    return allocSpace(zone, size, align, fill);
+}
+
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate memory from the given zone and track it as a PMM allocation
+void * __malloc
+pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
+{
+    if (!size)
+        return NULL;
+
+    // Find and reserve space for bookkeeping.
+    struct allocdetail_s *detail = allocSpace(
+        &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+    if (!detail) {
+        detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+                            , MALLOC_MIN_ALIGN, NULL);
+        if (!detail)
+            return NULL;
+    }
+
+    // Find and reserve space for main allocation
+    void *data = allocExpandSpace(zone, size, align, &detail->datainfo);
+    if (!data) {
+        freeSpace(&detail->detailinfo);
+        return NULL;
+    }
+
+    dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
+            " ret=%p (detail=%p)\n"
+            , zone, handle, size, align
+            , data, detail);
+    SET_PMMVAR(detail->handle, handle);
+
+    return data;
+}
+
+// Free a data block allocated with pmm_malloc
+int
+pmm_free(void *data)
+{
+    struct allocinfo_s *info = findAlloc(data);
+    if (!info || data == (void*)info || data == GET_PMMVAR(info->dataend))
+        return -1;
+    struct allocdetail_s *detail = container_of(
+        info, struct allocdetail_s, datainfo);
+    dprintf(8, "pmm_free %p (detail=%p)\n", data, detail);
+    freeSpace(info);
+    freeSpace(&detail->detailinfo);
+    return 0;
+}
+
+// Find the amount of free space in a given zone.
+static u32
+pmm_getspace(struct zone_s *zone)
+{
+    // XXX - doesn't account for ZoneLow being able to grow.
+    // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS
+    u32 maxspace = 0;
+    struct allocinfo_s *info;
+    for (info = GET_PMMVAR(zone->info); info; info = GET_PMMVAR(info->next)) {
+        u32 space = GET_PMMVAR(info->allocend) - GET_PMMVAR(info->dataend);
+        if (space > maxspace)
+            maxspace = space;
+    }
+
+    if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
+        return maxspace;
+    // Account for space needed for PMM tracking.
+    u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN);
+    if (maxspace <= reserve)
+        return 0;
+    return maxspace - reserve;
+}
+
+// Find the data block allocated with pmm_malloc with a given handle.
+static void *
+pmm_find(u32 handle)
+{
+    int i;
+    for (i=0; i<ARRAY_SIZE(Zones); i++) {
+        struct zone_s *zone = GET_PMMVAR(Zones[i]);
+        struct allocinfo_s *info;
+        for (info = GET_PMMVAR(zone->info); info
+                 ; info = GET_PMMVAR(info->next)) {
+            if (GET_PMMVAR(info->data) != (void*)info)
+                continue;
+            struct allocdetail_s *detail = container_of(
+                info, struct allocdetail_s, detailinfo);
+            if (GET_PMMVAR(detail->handle) == handle)
+                return GET_PMMVAR(detail->datainfo.data);
+        }
+    }
+    return NULL;
+}
+
+
+/****************************************************************
+ * pmm interface
+ ****************************************************************/
+
+struct pmmheader {
+    u32 signature;
+    u8 version;
+    u8 length;
+    u8 checksum;
+    u16 entry_offset;
+    u16 entry_seg;
+    u8 reserved[5];
+} PACKED;
+
+extern struct pmmheader PMMHEADER;
+
+#define PMM_SIGNATURE 0x4d4d5024 // $PMM
+
+#if CONFIG_PMM
+struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
+    .version = 0x01,
+    .length = sizeof(PMMHEADER),
+    .entry_seg = SEG_BIOS,
+};
+#endif
+
+#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
+
+// PMM - allocate
+static u32
+handle_pmm00(u16 *args)
+{
+    u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
+    u16 flags = args[5];
+    dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
+            , length, handle, flags);
+    struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
+    if (flags & 8) {
+        // Permanent memory request.
+        lowzone = &ZoneLow;
+        highzone = &ZoneHigh;
+    }
+    if (!length) {
+        // Memory size request
+        switch (flags & 3) {
+        default:
+        case 0:
+            return 0;
+        case 1:
+            return pmm_getspace(lowzone);
+        case 2:
+            return pmm_getspace(highzone);
+        case 3: {
+            u32 spacelow = pmm_getspace(lowzone);
+            u32 spacehigh = pmm_getspace(highzone);
+            if (spacelow > spacehigh)
+                return spacelow;
+            return spacehigh;
+        }
+        }
+    }
+    u32 size = length * 16;
+    if ((s32)size <= 0)
+        return 0;
+    u32 align = MALLOC_MIN_ALIGN;
+    if (flags & 4) {
+        align = 1<<__ffs(size);
+        if (align < MALLOC_MIN_ALIGN)
+            align = MALLOC_MIN_ALIGN;
+    }
+    switch (flags & 3) {
+    default:
+    case 0:
+        return 0;
+    case 1:
+        return (u32)pmm_malloc(lowzone, handle, size, align);
+    case 2:
+        return (u32)pmm_malloc(highzone, handle, size, align);
+    case 3: {
+        void *data = pmm_malloc(lowzone, handle, size, align);
+        if (data)
+            return (u32)data;
+        return (u32)pmm_malloc(highzone, handle, size, align);
+    }
+    }
+}
+
+// PMM - find
+static u32
+handle_pmm01(u16 *args)
+{
+    u32 handle = *(u32*)&args[1];
+    dprintf(3, "pmm01: handle=%x\n", handle);
+    if (handle == PMM_DEFAULT_HANDLE)
+        return 0;
+    return (u32)pmm_find(handle);
+}
+
+// PMM - deallocate
+static u32
+handle_pmm02(u16 *args)
+{
+    u32 buffer = *(u32*)&args[1];
+    dprintf(3, "pmm02: buffer=%x\n", buffer);
+    int ret = pmm_free((void*)buffer);
+    if (ret)
+        // Error
+        return 1;
+    return 0;
+}
+
+static u32
+handle_pmmXX(u16 *args)
+{
+    return PMM_FUNCTION_NOT_SUPPORTED;
+}
+
+u32 VISIBLE16
+handle_pmm(u16 *args)
+{
+    if (! CONFIG_PMM)
+        return PMM_FUNCTION_NOT_SUPPORTED;
+
+    u16 arg1 = args[0];
+    dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
+
+    switch (arg1) {
+    case 0x00: return handle_pmm00(args);
+    case 0x01: return handle_pmm01(args);
+    case 0x02: return handle_pmm02(args);
+    default:   return handle_pmmXX(args);
+    }
+}
+
+// romlayout.S
+extern void entry_pmm(void);
+
+void
+pmm_setup(void)
+{
+    if (! CONFIG_PMM)
+        return;
+
+    dprintf(3, "init PMM\n");
+
+    PMMHEADER.signature = PMM_SIGNATURE;
+    PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
+    PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
+}
+
+void
+pmm_finalize(void)
+{
+    if (! CONFIG_PMM)
+        return;
+
+    dprintf(3, "finalize PMM\n");
+
+    PMMHEADER.signature = 0;
+    PMMHEADER.entry_offset = 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/pnpbios.c b/qemu-0.15.x/roms/seabios/src/pnpbios.c
new file mode 100644
index 0000000..b1bebc9
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/pnpbios.c
@@ -0,0 +1,103 @@
+// PNP BIOS calls
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "farptr.h" // SET_FARVAR
+
+struct pnpheader {
+    u32 signature;
+    u8 version;
+    u8 length;
+    u16 control;
+    u8 checksum;
+    u32 eventloc;
+    u16 real_ip;
+    u16 real_cs;
+    u16 prot_ip;
+    u32 prot_base;
+    u32 oemid;
+    u16 real_ds;
+    u32 prot_database;
+} PACKED;
+
+extern struct pnpheader PNPHEADER;
+extern char pnp_string[];
+
+#if CONFIG_PNPBIOS
+struct pnpheader PNPHEADER __aligned(16) VAR16EXPORT = {
+    .signature = PNP_SIGNATURE,
+    .version = 0x10,
+    .length = sizeof(PNPHEADER),
+    .real_cs = SEG_BIOS,
+    .prot_base = BUILD_BIOS_ADDR,
+    .real_ds = SEG_BIOS,
+    .prot_database = BUILD_BIOS_ADDR,
+};
+#else
+// We need a copy of this string in the 0xf000 segment, but we are not
+// actually a PnP BIOS, so make sure it is *not* aligned, so OSes will
+// not see it if they scan.
+char pnp_string[] __aligned(2) VAR16VISIBLE = " $PnP";
+#endif
+
+#define FUNCTION_NOT_SUPPORTED 0x82
+
+// BBS - Get Version and Installation Check
+static u16
+handle_pnp60(u16 *args)
+{
+    u16 version_ptr = args[1];
+    u16 version_seg = args[2];
+    SET_FARVAR(version_seg, *(u16*)(version_ptr+0), 0x0101);
+    return 0;
+}
+
+static u16
+handle_pnpXX(u16 *args)
+{
+    return FUNCTION_NOT_SUPPORTED;
+}
+
+u16 VISIBLE16
+handle_pnp(u16 *args)
+{
+    if (! CONFIG_PNPBIOS)
+        return FUNCTION_NOT_SUPPORTED;
+
+    u16 arg1 = args[0];
+    dprintf(DEBUG_HDL_pnp, "pnp call arg1=%x\n", arg1);
+
+    switch (arg1) {
+    case 0x60: return handle_pnp60(args);
+    default:   return handle_pnpXX(args);
+    }
+}
+
+u16
+get_pnp_offset(void)
+{
+    if (! CONFIG_PNPBIOS)
+        return (u32)pnp_string + 1 - BUILD_BIOS_ADDR;
+    return (u32)&PNPHEADER - BUILD_BIOS_ADDR;
+}
+
+// romlayout.S
+extern void entry_pnp_real(void);
+extern void entry_pnp_prot(void);
+
+void
+pnp_setup(void)
+{
+    if (! CONFIG_PNPBIOS)
+        return;
+
+    dprintf(3, "init PNPBIOS table\n");
+
+    PNPHEADER.real_ip = (u32)entry_pnp_real - BUILD_BIOS_ADDR;
+    PNPHEADER.prot_ip = (u32)entry_pnp_prot - BUILD_BIOS_ADDR;
+    PNPHEADER.checksum -= checksum(&PNPHEADER, sizeof(PNPHEADER));
+}
diff --git a/qemu-0.15.x/roms/seabios/src/post.c b/qemu-0.15.x/roms/seabios/src/post.c
new file mode 100644
index 0000000..7d2b5f2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/post.c
@@ -0,0 +1,389 @@
+// 32bit code to Power On Self Test (POST) a machine.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // PORT_*
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_*
+#include "util.h" // memset
+#include "biosvar.h" // struct bios_data_area_s
+#include "disk.h" // floppy_drive_setup
+#include "ata.h" // ata_setup
+#include "ahci.h" // ahci_setup
+#include "memmap.h" // add_e820
+#include "pic.h" // pic_setup
+#include "pci.h" // create_pirtable
+#include "acpi.h" // acpi_bios_init
+#include "bregs.h" // struct bregs
+#include "mptable.h" // mptable_init
+#include "boot.h" // IPL
+#include "usb.h" // usb_setup
+#include "smbios.h" // smbios_init
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "ps2port.h" // ps2port_setup
+#include "virtio-blk.h" // virtio_blk_setup
+
+
+/****************************************************************
+ * BIOS init
+ ****************************************************************/
+
+static void
+init_ivt(void)
+{
+    dprintf(3, "init ivt\n");
+
+    // Initialize all vectors to the default handler.
+    int i;
+    for (i=0; i<256; i++)
+        SET_IVT(i, FUNC16(entry_iret_official));
+
+    // Initialize all hw vectors to a default hw handler.
+    for (i=0x08; i<=0x0f; i++)
+        SET_IVT(i, FUNC16(entry_hwpic1));
+    for (i=0x70; i<=0x77; i++)
+        SET_IVT(i, FUNC16(entry_hwpic2));
+
+    // Initialize software handlers.
+    SET_IVT(0x02, FUNC16(entry_02));
+    SET_IVT(0x10, FUNC16(entry_10));
+    SET_IVT(0x11, FUNC16(entry_11));
+    SET_IVT(0x12, FUNC16(entry_12));
+    SET_IVT(0x13, FUNC16(entry_13_official));
+    SET_IVT(0x14, FUNC16(entry_14));
+    SET_IVT(0x15, FUNC16(entry_15));
+    SET_IVT(0x16, FUNC16(entry_16));
+    SET_IVT(0x17, FUNC16(entry_17));
+    SET_IVT(0x18, FUNC16(entry_18));
+    SET_IVT(0x19, FUNC16(entry_19_official));
+    SET_IVT(0x1a, FUNC16(entry_1a));
+    SET_IVT(0x40, FUNC16(entry_40));
+
+    // INT 60h-66h reserved for user interrupt
+    for (i=0x60; i<=0x66; i++)
+        SET_IVT(i, SEGOFF(0, 0));
+
+    // set vector 0x79 to zero
+    // this is used by 'gardian angel' protection system
+    SET_IVT(0x79, SEGOFF(0, 0));
+
+    SET_IVT(0x1E, SEGOFF(SEG_BIOS, (u32)&diskette_param_table2 - BUILD_BIOS_ADDR));
+}
+
+static void
+init_bda(void)
+{
+    dprintf(3, "init bda\n");
+
+    struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+    memset(bda, 0, sizeof(*bda));
+
+    int esize = EBDA_SIZE_START;
+    SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize);
+    u16 ebda_seg = EBDA_SEGMENT_START;
+    SET_BDA(ebda_seg, ebda_seg);
+
+    // Init ebda
+    struct extended_bios_data_area_s *ebda = get_ebda_ptr();
+    memset(ebda, 0, sizeof(*ebda));
+    ebda->size = esize;
+
+    add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA2(ebda_seg, size) * 1024
+             , E820_RESERVED);
+}
+
+static void
+ram_probe(void)
+{
+    dprintf(3, "Find memory size\n");
+    if (CONFIG_COREBOOT) {
+        coreboot_setup();
+    } else {
+        // On emulators, get memory size from nvram.
+        u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
+                  | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
+        if (rs)
+            rs += 16 * 1024 * 1024;
+        else
+            rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
+                   | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
+                  + 1 * 1024 * 1024);
+        RamSize = rs;
+        add_e820(0, rs, E820_RAM);
+
+        // Check for memory over 4Gig
+        u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
+                    | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
+                    | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
+        RamSizeOver4G = high;
+        add_e820(0x100000000ull, high, E820_RAM);
+
+        /* reserve 256KB BIOS area at the end of 4 GB */
+        add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+    }
+
+    // Don't declare any memory between 0xa0000 and 0x100000
+    add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+
+    // Mark known areas as reserved.
+    add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+
+    u32 count = qemu_cfg_e820_entries();
+    if (count) {
+        struct e820_reservation entry;
+        int i;
+
+        for (i = 0; i < count; i++) {
+            qemu_cfg_e820_load_next(&entry);
+            add_e820(entry.address, entry.length, entry.type);
+        }
+    } else if (kvm_para_available()) {
+        // Backwards compatibility - provide hard coded range.
+        // 4 pages before the bios, 3 pages for vmx tss pages, the
+        // other page for EPT real mode pagetable
+        add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+    }
+
+    dprintf(1, "Ram Size=0x%08x (0x%08x%08x high)\n"
+            , RamSize, (u32)(RamSizeOver4G >> 32), (u32)RamSizeOver4G);
+}
+
+static void
+init_bios_tables(void)
+{
+    if (CONFIG_COREBOOT) {
+        coreboot_copy_biostable();
+        return;
+    }
+
+    create_pirtable();
+
+    mptable_init();
+
+    smbios_init();
+
+    acpi_bios_init();
+}
+
+// Initialize hardware devices
+static void
+init_hw(void)
+{
+    usb_setup();
+    ps2port_setup();
+    lpt_setup();
+    serial_setup();
+
+    floppy_setup();
+    ata_setup();
+    ahci_setup();
+    cbfs_payload_setup();
+    ramdisk_setup();
+    virtio_blk_setup();
+}
+
+// Begin the boot process by invoking an int0x19 in 16bit mode.
+void VISIBLE32FLAT
+startBoot(void)
+{
+    // Clear low-memory allocations (required by PMM spec).
+    memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
+
+    dprintf(3, "Jump to int19\n");
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x19, &br);
+}
+
+// Main setup code.
+static void
+maininit(void)
+{
+    // Setup ivt/bda/ebda
+    init_ivt();
+    init_bda();
+
+    // Init base pc hardware.
+    pic_setup();
+    timer_setup();
+    mathcp_setup();
+
+    // Initialize mtrr
+    mtrr_setup();
+
+    // Initialize pci
+    pci_setup();
+    pci_path_setup();
+    smm_init();
+
+    // Initialize internal tables
+    boot_setup();
+
+    // Start hardware initialization (if optionrom threading)
+    if (CONFIG_THREADS && CONFIG_THREAD_OPTIONROMS)
+        init_hw();
+
+    // Find and initialize other cpus
+    smp_probe();
+
+    // Setup interfaces that option roms may need
+    bios32_setup();
+    pmm_setup();
+    pnp_setup();
+    kbd_setup();
+    mouse_setup();
+    init_bios_tables();
+
+    // Run vga option rom
+    vga_setup();
+
+    // Do hardware initialization (if running synchronously)
+    if (!CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS) {
+        init_hw();
+        wait_threads();
+    }
+
+    // Run option roms
+    optionrom_setup();
+
+    // Run BCVs and show optional boot menu
+    boot_prep();
+
+    // Finalize data structures before boot
+    cdemu_setup();
+    pmm_finalize();
+    malloc_finalize();
+    memmap_finalize();
+
+    // Setup bios checksum.
+    BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE);
+
+    // Write protect bios memory.
+    make_bios_readonly();
+
+    // Invoke int 19 to start boot process.
+    startBoot();
+}
+
+
+/****************************************************************
+ * Code relocation
+ ****************************************************************/
+
+// Update given relocs for the code at 'dest' with a given 'delta'
+static void
+updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta)
+{
+    u32 *reloc;
+    for (reloc = rstart; reloc < rend; reloc++)
+        *((u32*)(dest + *reloc)) += delta;
+}
+
+// Start of Power On Self Test - the BIOS initilization.  This
+// function sets up for and attempts relocation of the init code.
+static void
+reloc_init(void)
+{
+    if (!CONFIG_RELOCATE_INIT) {
+        maininit();
+        return;
+    }
+    // Symbols populated by the build.
+    extern u8 code32flat_start[];
+    extern u8 _reloc_min_align[];
+    extern u32 _reloc_abs_start[], _reloc_abs_end[];
+    extern u32 _reloc_rel_start[], _reloc_rel_end[];
+    extern u32 _reloc_init_start[], _reloc_init_end[];
+    extern u8 code32init_start[], code32init_end[];
+
+    // Allocate space for init code.
+    u32 initsize = code32init_end - code32init_start;
+    u32 align = (u32)&_reloc_min_align;
+    void *dest = memalign_tmp(align, initsize);
+    if (!dest)
+        panic("No space for init relocation.\n");
+
+    // Copy code and update relocs (init absolute, init relative, and runtime)
+    dprintf(1, "Relocating init from %p to %p (size %d)\n"
+            , code32init_start, dest, initsize);
+    s32 delta = dest - (void*)code32init_start;
+    memcpy(dest, code32init_start, initsize);
+    updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta);
+    updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta);
+    updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
+
+    // Call maininit() in relocated code.
+    void (*func)(void) = (void*)maininit + delta;
+    barrier();
+    func();
+}
+
+// Start of Power On Self Test (POST) - the BIOS initilization phase.
+// This function sets up for and attempts relocation of the init code.
+void VISIBLE32INIT
+post(void)
+{
+    // Detect ram and setup internal malloc.
+    qemu_cfg_port_probe();
+    ram_probe();
+    malloc_setup();
+
+    reloc_init();
+}
+
+
+/****************************************************************
+ * POST entry point
+ ****************************************************************/
+
+static int HaveRunPost;
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+    dprintf(1, "Attempting a hard reboot\n");
+
+    // Setup for reset on qemu.
+    if (! CONFIG_COREBOOT) {
+        qemu_prep_reset();
+        if (HaveRunPost)
+            apm_shutdown();
+    }
+
+    // Try keyboard controller reboot.
+    i8042_reboot();
+
+    // Try PCI 0xcf9 reboot
+    pci_reboot();
+
+    // Try triple fault
+    asm volatile("int3");
+
+    panic("Could not reboot");
+}
+
+// 32-bit entry point.
+void VISIBLE32FLAT
+_start(void)
+{
+    init_dma();
+
+    debug_serial_setup();
+    dprintf(1, "Start bios (version %s)\n", VERSION);
+
+    if (HaveRunPost)
+        // This is a soft reboot - invoke a hard reboot.
+        tryReboot();
+
+    // Allow writes to modify bios area (0xf0000)
+    make_bios_writable();
+    HaveRunPost = 1;
+
+    // Perform main setup code.
+    post();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ps2port.c b/qemu-0.15.x/roms/seabios/src/ps2port.c
new file mode 100644
index 0000000..d1e6d48
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ps2port.c
@@ -0,0 +1,472 @@
+// Support for handling the PS/2 mouse/keyboard ports.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "ps2port.h" // ps2_kbd_command
+#include "pic.h" // eoi_pic1
+
+
+/****************************************************************
+ * Low level i8042 commands.
+ ****************************************************************/
+
+// Timeout value.
+#define I8042_CTL_TIMEOUT       10000
+
+#define I8042_BUFFER_SIZE       16
+
+static int
+i8042_wait_read(void)
+{
+    dprintf(7, "i8042_wait_read\n");
+    int i;
+    for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+        u8 status = inb(PORT_PS2_STATUS);
+        if (status & I8042_STR_OBF)
+            return 0;
+        udelay(50);
+    }
+    warn_timeout();
+    return -1;
+}
+
+static int
+i8042_wait_write(void)
+{
+    dprintf(7, "i8042_wait_write\n");
+    int i;
+    for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+        u8 status = inb(PORT_PS2_STATUS);
+        if (! (status & I8042_STR_IBF))
+            return 0;
+        udelay(50);
+    }
+    warn_timeout();
+    return -1;
+}
+
+static int
+i8042_flush(void)
+{
+    dprintf(7, "i8042_flush\n");
+    int i;
+    for (i=0; i<I8042_BUFFER_SIZE; i++) {
+        u8 status = inb(PORT_PS2_STATUS);
+        if (! (status & I8042_STR_OBF))
+            return 0;
+        udelay(50);
+        u8 data = inb(PORT_PS2_DATA);
+        dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
+    }
+
+    warn_timeout();
+    return -1;
+}
+
+static int
+__i8042_command(int command, u8 *param)
+{
+    int receive = (command >> 8) & 0xf;
+    int send = (command >> 12) & 0xf;
+
+    // Send the command.
+    int ret = i8042_wait_write();
+    if (ret)
+        return ret;
+    outb(command, PORT_PS2_STATUS);
+
+    // Send parameters (if any).
+    int i;
+    for (i = 0; i < send; i++) {
+        ret = i8042_wait_write();
+        if (ret)
+            return ret;
+        outb(param[i], PORT_PS2_DATA);
+    }
+
+    // Receive parameters (if any).
+    for (i = 0; i < receive; i++) {
+        ret = i8042_wait_read();
+        if (ret)
+            return ret;
+        param[i] = inb(PORT_PS2_DATA);
+        dprintf(7, "i8042 param=%x\n", param[i]);
+    }
+
+    return 0;
+}
+
+static int
+i8042_command(int command, u8 *param)
+{
+    dprintf(7, "i8042_command cmd=%x\n", command);
+    int ret = __i8042_command(command, param);
+    if (ret)
+        dprintf(2, "i8042 command %x failed\n", command);
+    return ret;
+}
+
+static int
+i8042_kbd_write(u8 c)
+{
+    dprintf(7, "i8042_kbd_write c=%d\n", c);
+    int ret = i8042_wait_write();
+    if (! ret)
+        outb(c, PORT_PS2_DATA);
+    return ret;
+}
+
+static int
+i8042_aux_write(u8 c)
+{
+    return i8042_command(I8042_CMD_AUX_SEND, &c);
+}
+
+void
+i8042_reboot(void)
+{
+    int i;
+    for (i=0; i<10; i++) {
+        i8042_wait_write();
+        udelay(50);
+        outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */
+        udelay(50);
+    }
+}
+
+
+/****************************************************************
+ * Device commands.
+ ****************************************************************/
+
+#define PS2_RET_ACK             0xfa
+#define PS2_RET_NAK             0xfe
+
+static int
+ps2_recvbyte(int aux, int needack, int timeout)
+{
+    u64 end = calc_future_tsc(timeout);
+    for (;;) {
+        u8 status = inb(PORT_PS2_STATUS);
+        if (status & I8042_STR_OBF) {
+            u8 data = inb(PORT_PS2_DATA);
+            dprintf(7, "ps2 read %x\n", data);
+
+            if (!!(status & I8042_STR_AUXDATA) == aux) {
+                if (!needack)
+                    return data;
+                if (data == PS2_RET_ACK)
+                    return data;
+                if (data == PS2_RET_NAK) {
+                    dprintf(1, "Got ps2 nak (status=%x)\n", status);
+                    return data;
+                }
+            }
+
+            // This data not part of command - just discard it.
+            dprintf(1, "Discarding ps2 data %02x (status=%02x)\n", data, status);
+        }
+
+        if (check_tsc(end)) {
+            // Don't warn on second byte of a reset
+            if (timeout > 100)
+                warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+static int
+ps2_sendbyte(int aux, u8 command, int timeout)
+{
+    dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command);
+    int ret;
+    if (aux)
+        ret = i8042_aux_write(command);
+    else
+        ret = i8042_kbd_write(command);
+    if (ret)
+        return ret;
+
+    // Read ack.
+    ret = ps2_recvbyte(aux, 1, timeout);
+    if (ret < 0)
+        return ret;
+    if (ret != PS2_RET_ACK)
+        return -1;
+
+    return 0;
+}
+
+static int
+__ps2_command(int aux, int command, u8 *param)
+{
+    int ret2;
+    int receive = (command >> 8) & 0xf;
+    int send = (command >> 12) & 0xf;
+
+    // Disable interrupts and keyboard/mouse.
+    u8 ps2ctr = GET_EBDA(ps2ctr);
+    u8 newctr = ((ps2ctr | I8042_CTR_AUXDIS | I8042_CTR_KBDDIS)
+                 & ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT));
+    dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
+    int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+    if (ret)
+        return ret;
+
+    // Flush any interrupts already pending.
+    yield();
+
+    // Enable port command is being sent to.
+    if (aux)
+        newctr &= ~I8042_CTR_AUXDIS;
+    else
+        newctr &= ~I8042_CTR_KBDDIS;
+    ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+    if (ret)
+        goto fail;
+
+    if (command == ATKBD_CMD_RESET_BAT) {
+        // Reset is special wrt timeouts and bytes received.
+
+        // Send command.
+        ret = ps2_sendbyte(aux, command, 1000);
+        if (ret)
+            goto fail;
+
+        // Receive parameters.
+        ret = ps2_recvbyte(aux, 0, 4000);
+        if (ret < 0)
+            goto fail;
+        param[0] = ret;
+        ret = ps2_recvbyte(aux, 0, 100);
+        if (ret < 0)
+            // Some devices only respond with one byte on reset.
+            ret = 0;
+        param[1] = ret;
+    } else if (command == ATKBD_CMD_GETID) {
+        // Getid is special wrt bytes received.
+
+        // Send command.
+        ret = ps2_sendbyte(aux, command, 200);
+        if (ret)
+            goto fail;
+
+        // Receive parameters.
+        ret = ps2_recvbyte(aux, 0, 500);
+        if (ret < 0)
+            goto fail;
+        param[0] = ret;
+        if (ret == 0xab || ret == 0xac || ret == 0x2b || ret == 0x5d
+            || ret == 0x60 || ret == 0x47) {
+            // These ids (keyboards) return two bytes.
+            ret = ps2_recvbyte(aux, 0, 500);
+            if (ret < 0)
+                goto fail;
+            param[1] = ret;
+        } else {
+            param[1] = 0;
+        }
+    } else {
+        // Send command.
+        ret = ps2_sendbyte(aux, command, 200);
+        if (ret)
+            goto fail;
+
+        // Send parameters (if any).
+        int i;
+        for (i = 0; i < send; i++) {
+            ret = ps2_sendbyte(aux, param[i], 200);
+            if (ret)
+                goto fail;
+        }
+
+        // Receive parameters (if any).
+        for (i = 0; i < receive; i++) {
+            ret = ps2_recvbyte(aux, 0, 500);
+            if (ret < 0)
+                goto fail;
+            param[i] = ret;
+        }
+    }
+
+    ret = 0;
+
+fail:
+    // Restore interrupts and keyboard/mouse.
+    ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
+    if (ret2)
+        return ret2;
+
+    return ret;
+}
+
+static int
+ps2_command(int aux, int command, u8 *param)
+{
+    dprintf(7, "ps2_command aux=%d cmd=%x\n", aux, command);
+    int ret = __ps2_command(aux, command, param);
+    if (ret)
+        dprintf(2, "ps2 command %x failed (aux=%d)\n", command, aux);
+    return ret;
+}
+
+int
+ps2_kbd_command(int command, u8 *param)
+{
+    return ps2_command(0, command, param);
+}
+
+int
+ps2_mouse_command(int command, u8 *param)
+{
+    return ps2_command(1, command, param);
+}
+
+
+/****************************************************************
+ * IRQ handlers
+ ****************************************************************/
+
+// INT74h : PS/2 mouse hardware interrupt
+void VISIBLE16
+handle_74(void)
+{
+    if (! CONFIG_PS2PORT)
+        return;
+
+    debug_isr(DEBUG_ISR_74);
+
+    u8 v = inb(PORT_PS2_STATUS);
+    if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
+        != (I8042_STR_OBF|I8042_STR_AUXDATA)) {
+        dprintf(1, "ps2 mouse irq but no mouse data.\n");
+        goto done;
+    }
+    v = inb(PORT_PS2_DATA);
+
+    if (!(GET_EBDA(ps2ctr) & I8042_CTR_AUXINT))
+        // Interrupts not enabled.
+        goto done;
+
+    process_mouse(v);
+
+done:
+    eoi_pic2();
+}
+
+// INT09h : Keyboard Hardware Service Entry Point
+void VISIBLE16
+handle_09(void)
+{
+    if (! CONFIG_PS2PORT)
+        return;
+
+    debug_isr(DEBUG_ISR_09);
+
+    // read key from keyboard controller
+    u8 v = inb(PORT_PS2_STATUS);
+    if (v & I8042_STR_AUXDATA) {
+        dprintf(1, "ps2 keyboard irq but found mouse data?!\n");
+        goto done;
+    }
+    v = inb(PORT_PS2_DATA);
+
+    if (!(GET_EBDA(ps2ctr) & I8042_CTR_KBDINT))
+        // Interrupts not enabled.
+        goto done;
+
+    process_key(v);
+
+done:
+    eoi_pic1();
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+keyboard_init(void *data)
+{
+    /* flush incoming keys */
+    int ret = i8042_flush();
+    if (ret)
+        return;
+
+    // Controller self-test.
+    u8 param[2];
+    ret = i8042_command(I8042_CMD_CTL_TEST, param);
+    if (ret)
+        return;
+    if (param[0] != 0x55) {
+        dprintf(1, "i8042 self test failed (got %x not 0x55)\n", param[0]);
+        return;
+    }
+
+    // Controller keyboard test.
+    ret = i8042_command(I8042_CMD_KBD_TEST, param);
+    if (ret)
+        return;
+    if (param[0] != 0x00) {
+        dprintf(1, "i8042 keyboard test failed (got %x not 0x00)\n", param[0]);
+        return;
+    }
+
+    // Disable keyboard and mouse events.
+    SET_EBDA(ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
+
+
+    /* ------------------- keyboard side ------------------------*/
+    /* reset keyboard and self test  (keyboard side) */
+    ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
+    if (ret)
+        return;
+    if (param[0] != 0xaa) {
+        dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]);
+        return;
+    }
+
+    /* Disable keyboard */
+    ret = ps2_kbd_command(ATKBD_CMD_RESET_DIS, NULL);
+    if (ret)
+        return;
+
+    // Set scancode command (mode 2)
+    param[0] = 0x02;
+    ret = ps2_kbd_command(ATKBD_CMD_SSCANSET, param);
+    if (ret)
+        return;
+
+    // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
+    SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+
+    /* Enable keyboard */
+    ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
+    if (ret)
+        return;
+
+    dprintf(1, "PS2 keyboard initialized\n");
+}
+
+void
+ps2port_setup(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_PS2PORT)
+        return;
+    dprintf(3, "init ps2port\n");
+
+    enable_hwirq(1, FUNC16(entry_09));
+    enable_hwirq(12, FUNC16(entry_74));
+
+    run_thread(keyboard_init, NULL);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ps2port.h b/qemu-0.15.x/roms/seabios/src/ps2port.h
new file mode 100644
index 0000000..dcae391
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ps2port.h
@@ -0,0 +1,63 @@
+// Basic ps2 port (keyboard/mouse) command handling.
+#ifndef __PS2PORT_H
+#define __PS2PORT_H
+
+#include "types.h" // u8
+
+// Standard commands.
+#define I8042_CMD_CTL_RCTR      0x0120
+#define I8042_CMD_CTL_WCTR      0x1060
+#define I8042_CMD_CTL_TEST      0x01aa
+
+#define I8042_CMD_KBD_TEST      0x01ab
+#define I8042_CMD_KBD_DISABLE   0x00ad
+#define I8042_CMD_KBD_ENABLE    0x00ae
+
+#define I8042_CMD_AUX_DISABLE   0x00a7
+#define I8042_CMD_AUX_ENABLE    0x00a8
+#define I8042_CMD_AUX_SEND      0x10d4
+
+// Keyboard commands
+#define ATKBD_CMD_SETLEDS       0x10ed
+#define ATKBD_CMD_SSCANSET      0x10f0
+#define ATKBD_CMD_GETID         0x02f2
+#define ATKBD_CMD_ENABLE        0x00f4
+#define ATKBD_CMD_RESET_DIS     0x00f5
+#define ATKBD_CMD_RESET_BAT     0x02ff
+
+// Mouse commands
+#define PSMOUSE_CMD_SETSCALE11  0x00e6
+#define PSMOUSE_CMD_SETSCALE21  0x00e7
+#define PSMOUSE_CMD_SETRES      0x10e8
+#define PSMOUSE_CMD_GETINFO     0x03e9
+#define PSMOUSE_CMD_GETID       0x02f2
+#define PSMOUSE_CMD_SETRATE     0x10f3
+#define PSMOUSE_CMD_ENABLE      0x00f4
+#define PSMOUSE_CMD_DISABLE     0x00f5
+#define PSMOUSE_CMD_RESET_BAT   0x02ff
+
+// Status register bits.
+#define I8042_STR_PARITY        0x80
+#define I8042_STR_TIMEOUT       0x40
+#define I8042_STR_AUXDATA       0x20
+#define I8042_STR_KEYLOCK       0x10
+#define I8042_STR_CMDDAT        0x08
+#define I8042_STR_MUXERR        0x04
+#define I8042_STR_IBF           0x02
+#define I8042_STR_OBF           0x01
+
+// Control register bits.
+#define I8042_CTR_KBDINT        0x01
+#define I8042_CTR_AUXINT        0x02
+#define I8042_CTR_IGNKEYLOCK    0x08
+#define I8042_CTR_KBDDIS        0x10
+#define I8042_CTR_AUXDIS        0x20
+#define I8042_CTR_XLATE         0x40
+
+// functions
+void i8042_reboot(void);
+int ps2_kbd_command(int command, u8 *param);
+int ps2_mouse_command(int command, u8 *param);
+void ps2port_setup(void);
+
+#endif // ps2port.h
diff --git a/qemu-0.15.x/roms/seabios/src/ramdisk.c b/qemu-0.15.x/roms/seabios/src/ramdisk.c
new file mode 100644
index 0000000..bae30e2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ramdisk.c
@@ -0,0 +1,105 @@
+// Code for emulating a drive via high-memory accesses.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // process_ramdisk_op
+#include "util.h" // dprintf
+#include "memmap.h" // add_e820
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+
+void
+ramdisk_setup(void)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+        return;
+
+    // Find image.
+    struct cbfs_file *file = cbfs_findprefix("floppyimg/", NULL);
+    if (!file)
+        return;
+    const char *filename = cbfs_filename(file);
+    u32 size = cbfs_datasize(file);
+    dprintf(3, "Found floppy file %s of size %d\n", filename, size);
+    int ftype = find_floppy_type(size);
+    if (ftype < 0) {
+        dprintf(3, "No floppy type found for ramdisk size\n");
+        return;
+    }
+
+    // Allocate ram for image.
+    void *pos = memalign_tmphigh(PAGE_SIZE, size);
+    if (!pos) {
+        warn_noalloc();
+        return;
+    }
+    add_e820((u32)pos, size, E820_RESERVED);
+
+    // Copy image into ram.
+    cbfs_copyfile(file, pos, size);
+
+    // Setup driver.
+    struct drive_s *drive_g = init_floppy((u32)pos, ftype);
+    if (!drive_g)
+        return;
+    drive_g->type = DTYPE_RAMDISK;
+    dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos);
+    char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]);
+    boot_add_floppy(drive_g, desc, bootprio_find_named_rom(filename, 0));
+}
+
+static int
+ramdisk_copy(struct disk_op_s *op, int iswrite)
+{
+    u32 offset = GET_GLOBAL(op->drive_g->cntl_id);
+    offset += (u32)op->lba * DISK_SECTOR_SIZE;
+    u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl);
+    u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset);
+
+    u64 gdt[6];
+    if (iswrite) {
+        gdt[2] = opd;
+        gdt[3] = ramd;
+    } else {
+        gdt[2] = ramd;
+        gdt[3] = opd;
+    }
+
+    // Call int 1587 to copy data.
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_CF|F_IF;
+    br.ah = 0x87;
+    br.es = GET_SEG(SS);
+    br.si = (u32)gdt;
+    br.cx = op->count * DISK_SECTOR_SIZE / 2;
+    call16_int(0x15, &br);
+
+    if (br.flags & F_CF)
+        return DISK_RET_EBADTRACK;
+    return DISK_RET_SUCCESS;
+}
+
+int
+process_ramdisk_op(struct disk_op_s *op)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+        return 0;
+
+    switch (op->command) {
+    case CMD_READ:
+        return ramdisk_copy(op, 0);
+    case CMD_WRITE:
+        return ramdisk_copy(op, 1);
+    case CMD_VERIFY:
+    case CMD_FORMAT:
+    case CMD_RESET:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/resume.c b/qemu-0.15.x/roms/seabios/src/resume.c
new file mode 100644
index 0000000..20e2e3d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/resume.c
@@ -0,0 +1,125 @@
+// Code for handling calls to "post" that are resume related.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "ioport.h" // outb
+#include "pic.h" // eoi_pic2
+#include "biosvar.h" // struct bios_data_area_s
+#include "bregs.h" // struct bregs
+#include "acpi.h" // find_resume_vector
+
+// Reset DMA controller
+void
+init_dma(void)
+{
+    // first reset the DMA controllers
+    outb(0, PORT_DMA1_MASTER_CLEAR);
+    outb(0, PORT_DMA2_MASTER_CLEAR);
+
+    // then initialize the DMA controllers
+    outb(0xc0, PORT_DMA2_MODE_REG);
+    outb(0x00, PORT_DMA2_MASK_REG);
+}
+
+// Handler for post calls that look like a resume.
+void VISIBLE16
+handle_resume(u8 status)
+{
+    init_dma();
+
+    debug_serial_setup();
+    dprintf(1, "In resume (status=%d)\n", status);
+
+    switch (status) {
+    case 0xfe:
+        if (CONFIG_S3_RESUME) {
+            // S3 resume request.  Jump to 32bit mode to handle the resume.
+            asm volatile(
+                "movw %w1, %%ss\n"
+                "movl %0, %%esp\n"
+                "movl $_cfunc32flat_s3_resume, %%edx\n"
+                "jmp transition32\n"
+                : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0)
+                );
+            break;
+        }
+        // NO BREAK
+    case 0x00:
+    case 0x0d ... 0xfd:
+    case 0xff:
+        // Normal post - now that status has been cleared a reset will
+        // run regular boot code..
+        reset_vector();
+        break;
+
+    case 0x05:
+        // flush keyboard (issue EOI) and jump via 40h:0067h
+        eoi_pic2();
+        // NO BREAK
+    case 0x0a:
+#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
+        // resume execution by jump via 40h:0067h
+        asm volatile(
+            "movw %w1, %%ds\n"
+            "ljmpw *%0\n"
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
+            );
+        break;
+
+    case 0x0b:
+        // resume execution via IRET via 40h:0067h
+        asm volatile(
+            "movw %w1, %%ds\n"
+            "lssw %0, %%sp\n"
+            "iretw\n"
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
+            );
+        break;
+
+    case 0x0c:
+        // resume execution via RETF via 40h:0067h
+        asm volatile(
+            "movw %w1, %%ds\n"
+            "lssw %0, %%sp\n"
+            "lretw\n"
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
+            );
+        break;
+    }
+
+    panic("Unimplemented shutdown status: %02x\n", status);
+}
+
+void VISIBLE32FLAT
+s3_resume(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_S3_RESUME)
+        panic("S3 resume support not compiled in.\n");
+
+    dprintf(1, "In 32bit resume\n");
+
+    smm_init();
+
+    s3_resume_vga_init();
+
+    make_bios_readonly();
+
+    u32 s3_resume_vector = find_resume_vector();
+
+    // Invoke the resume vector.
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    if (s3_resume_vector) {
+        dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
+        br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
+    } else {
+        dprintf(1, "No resume vector set!\n");
+        // Jump to the post vector to restart with a normal boot.
+        br.code = SEGOFF(SEG_BIOS, (u32)reset_vector - BUILD_BIOS_ADDR);
+    }
+    call16big(&br);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/romlayout.S b/qemu-0.15.x/roms/seabios/src/romlayout.S
new file mode 100644
index 0000000..f540c1e
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/romlayout.S
@@ -0,0 +1,589 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Include of 16bit C code
+ ****************************************************************/
+
+        .code16gcc
+#include "ccode.16.s"
+
+#include "config.h" // CONFIG_*
+#include "ioport.h" // PORT_A20
+#include "bregs.h" // CR0_*
+#include "cmos.h" // CMOS_RESET_CODE
+#include "asm-offsets.h" // BREGS_*
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * Call trampolines
+ ****************************************************************/
+
+// Place CPU into 32bit mode from 16bit mode.
+// %edx = return location (in 32bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+        DECLFUNC transition32
+transition32:
+        movl %eax, %ecx
+
+        // Disable irqs (and clear direction flag)
+        cli
+        cld
+
+        // Disable nmi
+        movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
+        outb %al, $PORT_CMOS_INDEX
+        inb $PORT_CMOS_DATA, %al
+
+        // enable a20
+        inb $PORT_A20, %al
+        orb $A20_ENABLE_BIT, %al
+        outb %al, $PORT_A20
+
+        // Set segment descriptors
+        lidtw %cs:pmode_IDT_info
+        lgdtw %cs:rombios32_gdt_48
+
+        // Enable protected mode
+        movl %cr0, %eax
+        orl $CR0_PE, %eax
+        movl %eax, %cr0
+
+        // start 32bit protected mode code
+        ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
+
+        .code32
+1:
+        // init data segments
+        movl $SEG32_MODE32_DS, %eax
+        movw %ax, %ds
+        movw %ax, %es
+        movw %ax, %ss
+        movw %ax, %fs
+        movw %ax, %gs
+
+        movl %ecx, %eax
+        jmpl *%edx
+
+// Place CPU into 16bit mode from 32bit mode.
+// %edx = return location (in 16bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+        DECLFUNC transition16
+        .global transition16big
+transition16:
+        movl %eax, %ecx
+
+        // restore data segment limits to 0xffff
+        movl $SEG32_MODE16_DS, %eax
+        movw %ax, %ds
+        movw %ax, %es
+        movw %ax, %ss
+        movw %ax, %fs
+        movw %ax, %gs
+
+#if CONFIG_DISABLE_A20
+        // disable a20
+        inb $PORT_A20, %al
+        andb $~A20_ENABLE_BIT, %al
+        outb %al, $PORT_A20
+#endif
+
+        // Jump to 16bit mode
+        ljmpw $SEG32_MODE16_CS, $1f
+
+transition16big:
+        movl %eax, %ecx
+
+        movl $SEG32_MODE16BIG_DS, %eax
+        movw %ax, %ds
+        movw %ax, %es
+        movw %ax, %ss
+        movw %ax, %fs
+        movw %ax, %gs
+
+        ljmpw $SEG32_MODE16BIG_CS, $1f
+
+        .code16gcc
+1:
+        // Disable protected mode
+        movl %cr0, %eax
+        andl $~CR0_PE, %eax
+        movl %eax, %cr0
+
+        // far jump to flush CPU queue after transition to real mode
+        ljmpw $SEG_BIOS, $2f
+
+2:
+        // restore IDT to normal real-mode defaults
+        lidtw %cs:rmode_IDT_info
+
+        // Clear segment registers
+        xorw %ax, %ax
+        movw %ax, %fs
+        movw %ax, %gs
+        movw %ax, %es
+        movw %ax, %ds
+        movw %ax, %ss  // Assume stack is in segment 0
+
+        movl %ecx, %eax
+        jmpl *%edx
+
+// Call a 16bit function from 16bit mode with a specified cpu register state
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags
+        DECLFUNC __call16
+__call16:
+        // Save %eax, %ebp
+        pushl %ebp
+        pushl %eax
+
+        // Setup for iretw call
+        pushw %cs
+        pushw $1f               // return point
+        pushw BREGS_flags(%eax) // flags
+        pushl BREGS_code(%eax)  // CS:IP
+
+        // Load calling registers.
+        movl BREGS_edi(%eax), %edi
+        movl BREGS_esi(%eax), %esi
+        movl BREGS_ebp(%eax), %ebp
+        movl BREGS_ebx(%eax), %ebx
+        movl BREGS_edx(%eax), %edx
+        movl BREGS_ecx(%eax), %ecx
+        movw BREGS_es(%eax), %es
+        movw BREGS_ds(%eax), %ds
+        movl %ss:BREGS_eax(%eax), %eax
+
+        // Invoke call
+        iretw                   // XXX - just do a lcalll
+1:
+        // Store flags, eax, ecx
+        pushfw
+        pushl %eax
+        movl 0x06(%esp), %eax
+        movl %ecx, %ss:BREGS_ecx(%eax)
+        movw %ds, %ss:BREGS_ds(%eax)
+        movw %ss, %cx
+        movw %cx, %ds           // Restore %ds == %ss
+        popl %ecx
+        movl %ecx, BREGS_eax(%eax)
+        popw %cx
+        movw %cx, BREGS_flags(%eax)
+
+        // Store remaining registers
+        movw %es, BREGS_es(%eax)
+        movl %edi, BREGS_edi(%eax)
+        movl %esi, BREGS_esi(%eax)
+        movl %ebp, BREGS_ebp(%eax)
+        movl %ebx, BREGS_ebx(%eax)
+        movl %edx, BREGS_edx(%eax)
+
+        // Remove %eax, restore %ebp
+        popl %eax
+        popl %ebp
+
+        retl
+
+// Call a 16bit function from 32bit mode.
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt
+        DECLFUNC __call16_from32
+        .global __call16big_from32
+        .code32
+__call16_from32:
+        movl $1f, %edx
+        jmp transition16
+__call16big_from32:
+        movl $1f, %edx
+        jmp transition16big
+
+        // Make call.
+        .code16gcc
+1:      calll __call16
+        // Return via transition32
+        movl $(2f + BUILD_BIOS_ADDR), %edx
+        jmp transition32
+        .code32
+2:      retl
+
+        .code16gcc
+// IRQ trampolines
+        .macro IRQ_TRAMPOLINE num
+        DECLFUNC irq_trampoline_0x\num
+        irq_trampoline_0x\num :
+        int $0x\num
+        lretw
+        .endm
+
+        IRQ_TRAMPOLINE 10
+        IRQ_TRAMPOLINE 13
+        IRQ_TRAMPOLINE 15
+        IRQ_TRAMPOLINE 16
+        IRQ_TRAMPOLINE 18
+        IRQ_TRAMPOLINE 19
+
+
+/****************************************************************
+ * POST entry point
+ ****************************************************************/
+
+        DECLFUNC entry_post
+entry_post:
+        // Enable cache
+        movl %cr0, %eax
+        andl $~(CR0_CD|CR0_NW), %eax
+        movl %eax, %cr0
+
+        // Disable interrupts
+        cli
+        cld
+
+        // Check for restart indicator.
+        movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
+        outb %al, $PORT_CMOS_INDEX
+        inb $PORT_CMOS_DATA, %al
+        cmpb $0x0, %al
+        jnz 1f
+
+        // Normal entry point
+        ENTRY_INTO32 _cfunc32flat__start
+
+        // Entry point when a post call looks like a resume.
+1:
+        // Save old shutdown status.
+        movl %eax, %ebx
+
+        // Clear shutdown status register.
+        movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
+        outb %al, $PORT_CMOS_INDEX
+        xorl %eax, %eax
+        outb %al, $PORT_CMOS_DATA
+
+        // Use a stack in EBDA
+        movw $SEG_BDA, %ax
+        movw %ax, %ds
+        movw BDA_ebda_seg, %ax
+
+        cmpw $EBDA_SEGMENT_START, %ax
+        jle 2f
+        // EBDA segment doesn't look valid - use startup value.
+        movw $EBDA_SEGMENT_START, %ax
+
+2:      movw %ax, %ds
+        movw %ax, %ss
+        movl $EBDA_OFFSET_TOP_STACK, %esp
+
+        // Call handler.
+        movl %ebx, %eax
+        jmp handle_resume
+
+
+/****************************************************************
+ * Misc. entry points.
+ ****************************************************************/
+
+// PMM entry point
+        DECLFUNC entry_pmm
+entry_pmm:
+        pushl %esp              // Backup %esp, then clear high bits
+        movzwl %sp, %esp
+        pushfl                  // Save registers clobbered by C code
+        cli
+        cld
+        pushl %eax
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        leal 28(%esp), %eax     // %eax points to start of args
+        calll handle_pmm
+        movw %ax, 12(%esp)      // Modify %ax:%dx to return %eax
+        shrl $16, %eax
+        movw %ax, 4(%esp)
+        popw %ds                // Restore saved registers
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        popfl
+        popl %esp
+        lretw
+
+// PnP entry points
+        DECLFUNC entry_pnp_real
+        .global entry_pnp_prot
+entry_pnp_prot:
+        pushl %esp
+        jmp 1f
+entry_pnp_real:
+        pushl %esp              // Backup %esp, then clear high bits
+        movzwl %sp, %esp
+1:
+        pushfl                  // Save registers clobbered by C code
+        cli
+        cld
+        pushl %eax
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        leal 28(%esp), %eax     // %eax points to start of u16 args
+        calll handle_pnp
+        movw %ax, 12(%esp)      // Modify %eax to return %ax
+        popw %ds
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        popfl
+        popl %esp
+        lretw
+
+// APM entry points
+        DECLFUNC apm16protected_entry
+apm16protected_entry:
+        pushfw          // save flags
+        pushl %eax      // dummy
+        ENTRY_ARG handle_apm16
+        addw $4, %sp    // pop dummy
+        popfw           // restore flags
+        lretw
+
+        .code32
+        DECLFUNC apm32protected_entry
+apm32protected_entry:
+        pushfl
+        pushl %gs
+        pushl %cs               // Move second descriptor after %cs to %gs
+        addl $16, (%esp)
+        popl %gs
+        ENTRY_ARG_ESP _cfunc32seg_handle_apm32
+        popl %gs
+        popfl
+        lretl
+
+// PCI-BIOS 32bit entry point
+        DECLFUNC pcibios32_entry
+pcibios32_entry:
+        pushfl
+        pushl %gs               // Backup %gs and set %gs=%ds
+        pushl %ds
+        popl %gs
+        ENTRY_ARG_ESP _cfunc32seg_handle_pcibios32
+        popl %gs
+        popfl
+        lretl
+
+// BIOS32 support
+        EXPORTFUNC bios32_entry
+bios32_entry:
+        pushfl
+#if CONFIG_PCIBIOS
+        // Check for PCI-BIOS request
+        cmpl $0x49435024, %eax // $PCI
+        jne 1f
+        movl $BUILD_BIOS_ADDR, %ebx
+        movl $BUILD_BIOS_SIZE, %ecx
+        movl $pcibios32_entry, %edx
+        xorb %al, %al
+        jmp 2f
+#endif
+        // Unknown request
+1:      movb $0x80, %al
+        // Return to caller
+2:      popfl
+        lretl
+
+// 32bit elf entry point
+        EXPORTFUNC post32
+post32:
+        cli
+        cld
+        lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
+        lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
+        movl $SEG32_MODE32_DS, %eax
+        movw %ax, %ds
+        movw %ax, %es
+        movw %ax, %fs
+        movw %ax, %gs
+        movw %ax, %ss
+        movl $BUILD_STACK_ADDR, %esp
+        ljmpl $SEG32_MODE32_CS, $_cfunc32flat__start
+
+        .code16gcc
+
+
+/****************************************************************
+ * Interrupt entry points
+ ****************************************************************/
+
+        // Main entry point for interrupts without args
+        DECLFUNC irqentry
+irqentry:
+        ENTRY_ST
+        iretw
+
+        // Main entry point for interrupts with args
+        DECLFUNC irqentryarg
+irqentryarg:
+        ENTRY_ARG_ST
+        iretw
+
+        // Define an entry point for an interrupt (no args passed).
+        .macro IRQ_ENTRY num
+        .global entry_\num
+        entry_\num :
+        pushl $ handle_\num
+        jmp irqentry
+        .endm
+
+        .macro DECL_IRQ_ENTRY num
+        DECLFUNC entry_\num
+        IRQ_ENTRY \num
+        .endm
+
+        // Define an entry point for an interrupt (can read/modify args).
+        .macro IRQ_ENTRY_ARG num
+        .global entry_\num
+        entry_\num :
+        pushl $ handle_\num
+        jmp irqentryarg
+        .endm
+
+        .macro DECL_IRQ_ENTRY_ARG num
+        DECLFUNC entry_\num
+        IRQ_ENTRY_ARG \num
+        .endm
+
+        // Various entry points (that don't require a fixed location).
+        DECL_IRQ_ENTRY_ARG 13
+        DECL_IRQ_ENTRY 76
+        DECL_IRQ_ENTRY 70
+        DECL_IRQ_ENTRY 74
+        DECL_IRQ_ENTRY 75
+        DECL_IRQ_ENTRY hwpic1
+        DECL_IRQ_ENTRY hwpic2
+
+        // int 18/19 are special - they reset stack and call into 32bit mode.
+        DECLFUNC entry_19
+entry_19:
+        ENTRY_INTO32 _cfunc32flat_handle_19
+
+        DECLFUNC entry_18
+entry_18:
+        ENTRY_INTO32 _cfunc32flat_handle_18
+
+
+/****************************************************************
+ * Fixed position entry points
+ ****************************************************************/
+
+        // Specify a location in the fixed part of bios area.
+        .macro ORG addr
+        .section .fixedaddr.\addr
+        .endm
+
+        ORG 0xe05b
+entry_post_official:
+        jmp entry_post
+
+        ORG 0xe2c3
+        IRQ_ENTRY 02
+
+        ORG 0xe3fe
+        .global entry_13_official
+entry_13_official:
+        jmp entry_13
+
+        // 0xe401 - OldFDPT in disk.c
+
+        ORG 0xe6f2
+        .global entry_19_official
+entry_19_official:
+        jmp entry_19
+
+        // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c
+
+        // 0xe729 - BaudTable in serial.c
+
+        ORG 0xe739
+        IRQ_ENTRY_ARG 14
+
+        ORG 0xe82e
+        IRQ_ENTRY_ARG 16
+
+        ORG 0xe987
+        IRQ_ENTRY 09
+
+        ORG 0xec59
+        IRQ_ENTRY_ARG 40
+
+        ORG 0xef57
+        IRQ_ENTRY 0e
+
+        // 0xefc7 - diskette_param_table in floppy.c
+
+        ORG 0xefd2
+        IRQ_ENTRY_ARG 17
+
+        ORG 0xf045
+entry_10_0x0f:
+        // XXX - INT 10 Functions 0-Fh Entry Point
+        iretw
+
+        ORG 0xf065
+        IRQ_ENTRY_ARG 10
+
+        // 0xf0a4 - VideoParams in misc.c
+
+        ORG 0xf841
+        IRQ_ENTRY_ARG 12
+
+        ORG 0xf84d
+        IRQ_ENTRY_ARG 11
+
+        ORG 0xf859
+        IRQ_ENTRY_ARG 15
+
+        // 0xfa6e - vgafont8 in font.c
+
+        ORG 0xfe6e
+        IRQ_ENTRY_ARG 1a
+
+        ORG 0xfea5
+        IRQ_ENTRY 08
+
+        // 0xfef3 - InitVectors in misc.c
+
+        // 0xff00 - BiosCopyright in misc.c
+
+        ORG 0xff53
+        .global entry_iret_official
+entry_iret_official:
+        iretw
+
+        ORG 0xff54
+        IRQ_ENTRY_ARG 05
+
+        ORG 0xfff0 // Power-up Entry Point
+        .global reset_vector
+reset_vector:
+        ljmpw $SEG_BIOS, $entry_post_official
+
+        // 0xfff5 - BiosDate in misc.c
+
+        // 0xfffe - BiosModelId in misc.c
+
+        // 0xffff - BiosChecksum in misc.c
+
+        .end
diff --git a/qemu-0.15.x/roms/seabios/src/serial.c b/qemu-0.15.x/roms/seabios/src/serial.c
new file mode 100644
index 0000000..21b4bd0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/serial.c
@@ -0,0 +1,315 @@
+// 16bit code to handle serial and printer services.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "util.h" // debug_enter
+#include "bregs.h" // struct bregs
+
+
+/****************************************************************
+ * COM ports
+ ****************************************************************/
+
+static u16
+detect_serial(u16 port, u8 timeout, u8 count)
+{
+    outb(0x02, port+SEROFF_IER);
+    u8 ier = inb(port+SEROFF_IER);
+    if (ier != 0x02)
+        return 0;
+    u8 iir = inb(port+SEROFF_IIR);
+    if ((iir & 0x3f) != 0x02)
+        return 0;
+
+    outb(0x00, port+SEROFF_IER);
+    SET_BDA(port_com[count], port);
+    SET_BDA(com_timeout[count], timeout);
+    return 1;
+}
+
+void
+serial_setup(void)
+{
+    if (! CONFIG_SERIAL)
+        return;
+    dprintf(3, "init serial\n");
+
+    u16 count = 0;
+    count += detect_serial(PORT_SERIAL1, 0x0a, count);
+    count += detect_serial(PORT_SERIAL2, 0x0a, count);
+    count += detect_serial(PORT_SERIAL3, 0x0a, count);
+    count += detect_serial(PORT_SERIAL4, 0x0a, count);
+    dprintf(1, "Found %d serial ports\n", count);
+
+    // Equipment word bits 9..11 determing # serial ports
+    u16 eqb = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9));
+}
+
+static u16
+getComAddr(struct bregs *regs)
+{
+    if (regs->dx >= 4) {
+        set_invalid(regs);
+        return 0;
+    }
+    u16 addr = GET_BDA(port_com[regs->dx]);
+    if (! addr)
+        set_invalid(regs);
+    return addr;
+}
+
+// SERIAL - INITIALIZE PORT
+static void
+handle_1400(struct bregs *regs)
+{
+    u16 addr = getComAddr(regs);
+    if (!addr)
+        return;
+    outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR);
+    if ((regs->al & 0xE0) == 0) {
+        outb(0x17, addr+SEROFF_DLL);
+        outb(0x04, addr+SEROFF_DLH);
+    } else {
+        u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
+        outb(val16 & 0xFF, addr+SEROFF_DLL);
+        outb(val16 >> 8, addr+SEROFF_DLH);
+    }
+    outb(regs->al & 0x1F, addr+SEROFF_LCR);
+    regs->ah = inb(addr+SEROFF_LSR);
+    regs->al = inb(addr+SEROFF_MSR);
+    set_success(regs);
+}
+
+// SERIAL - WRITE CHARACTER TO PORT
+static void
+handle_1401(struct bregs *regs)
+{
+    u16 addr = getComAddr(regs);
+    if (!addr)
+        return;
+    u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
+    for (;;) {
+        u8 lsr = inb(addr+SEROFF_LSR);
+        if ((lsr & 0x60) == 0x60) {
+            // Success - can write data
+            outb(regs->al, addr+SEROFF_DATA);
+            // XXX - reread lsr?
+            regs->ah = lsr;
+            break;
+        }
+        if (check_timer(end)) {
+            // Timed out - can't write data.
+            regs->ah = lsr | 0x80;
+            break;
+        }
+        yield();
+    }
+    set_success(regs);
+}
+
+// SERIAL - READ CHARACTER FROM PORT
+static void
+handle_1402(struct bregs *regs)
+{
+    u16 addr = getComAddr(regs);
+    if (!addr)
+        return;
+    u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
+    for (;;) {
+        u8 lsr = inb(addr+SEROFF_LSR);
+        if (lsr & 0x01) {
+            // Success - can read data
+            regs->al = inb(addr+SEROFF_DATA);
+            regs->ah = lsr;
+            break;
+        }
+        if (check_timer(end)) {
+            // Timed out - can't read data.
+            regs->ah = lsr | 0x80;
+            break;
+        }
+        yield();
+    }
+    set_success(regs);
+}
+
+// SERIAL - GET PORT STATUS
+static void
+handle_1403(struct bregs *regs)
+{
+    u16 addr = getComAddr(regs);
+    if (!addr)
+        return;
+    regs->ah = inb(addr+SEROFF_LSR);
+    regs->al = inb(addr+SEROFF_MSR);
+    set_success(regs);
+}
+
+static void
+handle_14XX(struct bregs *regs)
+{
+    set_unimplemented(regs);
+}
+
+// INT 14h Serial Communications Service Entry Point
+void VISIBLE16
+handle_14(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_14);
+    if (! CONFIG_SERIAL) {
+        handle_14XX(regs);
+        return;
+    }
+
+    switch (regs->ah) {
+    case 0x00: handle_1400(regs); break;
+    case 0x01: handle_1401(regs); break;
+    case 0x02: handle_1402(regs); break;
+    case 0x03: handle_1403(regs); break;
+    default:   handle_14XX(regs); break;
+    }
+}
+
+// XXX - Baud Rate Generator Table
+u8 BaudTable[16] VAR16FIXED(0xe729);
+
+
+/****************************************************************
+ * LPT ports
+ ****************************************************************/
+
+static u16
+detect_parport(u16 port, u8 timeout, u8 count)
+{
+    // clear input mode
+    outb(inb(port+2) & 0xdf, port+2);
+
+    outb(0xaa, port);
+    if (inb(port) != 0xaa)
+        // Not present
+        return 0;
+    SET_BDA(port_lpt[count], port);
+    SET_BDA(lpt_timeout[count], timeout);
+    return 1;
+}
+
+void
+lpt_setup(void)
+{
+    if (! CONFIG_LPT)
+        return;
+    dprintf(3, "init lpt\n");
+
+    u16 count = 0;
+    count += detect_parport(PORT_LPT1, 0x14, count);
+    count += detect_parport(PORT_LPT2, 0x14, count);
+    dprintf(1, "Found %d lpt ports\n", count);
+
+    // Equipment word bits 14..15 determing # parallel ports
+    u16 eqb = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14));
+}
+
+static u16
+getLptAddr(struct bregs *regs)
+{
+    if (regs->dx >= 3) {
+        set_invalid(regs);
+        return 0;
+    }
+    u16 addr = GET_BDA(port_lpt[regs->dx]);
+    if (! addr)
+        set_invalid(regs);
+    return addr;
+}
+
+// INT 17 - PRINTER - WRITE CHARACTER
+static void
+handle_1700(struct bregs *regs)
+{
+    u16 addr = getLptAddr(regs);
+    if (!addr)
+        return;
+
+    u32 end = calc_future_timer_ticks(GET_BDA(lpt_timeout[regs->dx]));
+
+    outb(regs->al, addr);
+    u8 val8 = inb(addr+2);
+    outb(val8 | 0x01, addr+2); // send strobe
+    udelay(5);
+    outb(val8 & ~0x01, addr+2);
+
+    for (;;) {
+        u8 v = inb(addr+1);
+        if (!(v & 0x40)) {
+            // Success
+            regs->ah = v ^ 0x48;
+            break;
+        }
+        if (check_timer(end)) {
+            // Timeout
+            regs->ah = (v ^ 0x48) | 0x01;
+            break;
+        }
+        yield();
+    }
+
+    set_success(regs);
+}
+
+// INT 17 - PRINTER - INITIALIZE PORT
+static void
+handle_1701(struct bregs *regs)
+{
+    u16 addr = getLptAddr(regs);
+    if (!addr)
+        return;
+
+    u8 val8 = inb(addr+2);
+    outb(val8 & ~0x04, addr+2); // send init
+    udelay(5);
+    outb(val8 | 0x04, addr+2);
+
+    regs->ah = inb(addr+1) ^ 0x48;
+    set_success(regs);
+}
+
+// INT 17 - PRINTER - GET STATUS
+static void
+handle_1702(struct bregs *regs)
+{
+    u16 addr = getLptAddr(regs);
+    if (!addr)
+        return;
+    regs->ah = inb(addr+1) ^ 0x48;
+    set_success(regs);
+}
+
+static void
+handle_17XX(struct bregs *regs)
+{
+    set_unimplemented(regs);
+}
+
+// INT17h : Printer Service Entry Point
+void VISIBLE16
+handle_17(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_17);
+    if (! CONFIG_LPT) {
+        handle_17XX(regs);
+        return;
+    }
+
+    switch (regs->ah) {
+    case 0x00: handle_1700(regs); break;
+    case 0x01: handle_1701(regs); break;
+    case 0x02: handle_1702(regs); break;
+    default:   handle_17XX(regs); break;
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/shadow.c b/qemu-0.15.x/roms/seabios/src/shadow.c
new file mode 100644
index 0000000..ed530e0
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/shadow.c
@@ -0,0 +1,151 @@
+// Support for enabling/disabling BIOS ram shadowing.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // memcpy
+#include "pci.h" // pci_config_writeb
+#include "config.h" // CONFIG_*
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "dev-i440fx.h"
+
+// On the emulators, the bios at 0xf0000 is also at 0xffff0000
+#define BIOS_SRC_OFFSET 0xfff00000
+
+// Enable shadowing and copy bios.
+static void
+__make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+    // Make ram from 0xc0000-0xf0000 writable
+    int clear = 0;
+    int i;
+    for (i=0; i<6; i++) {
+        u32 pam = pam0 + 1 + i;
+        int reg = pci_config_readb(bdf, pam);
+        if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
+            // Need to copy optionroms to work around qemu implementation
+            void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
+            memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
+            pci_config_writeb(bdf, pam, 0x33);
+            memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
+            clear = 1;
+        } else {
+            pci_config_writeb(bdf, pam, 0x33);
+        }
+    }
+    if (clear)
+        memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+
+    // Make ram from 0xf0000-0x100000 writable
+    int reg = pci_config_readb(bdf, pam0);
+    pci_config_writeb(bdf, pam0, 0x30);
+    if (reg & 0x10)
+        // Ram already present.
+        return;
+
+    // Copy bios.
+    extern u8 code32flat_start[], code32flat_end[];
+    memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+           , code32flat_end - code32flat_start);
+}
+
+void
+make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+    int reg = pci_config_readb(bdf, pam0);
+    if (!(reg & 0x10)) {
+        // QEMU doesn't fully implement the piix shadow capabilities -
+        // if ram isn't backing the bios segment when shadowing is
+        // disabled, the code itself wont be in memory.  So, run the
+        // code from the high-memory flash location.
+        u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
+        void (*func)(u16 bdf, u32 pam0) = (void*)pos;
+        func(bdf, pam0);
+        return;
+    }
+    // Ram already present - just enable writes
+    __make_bios_writable_intel(bdf, pam0);
+}
+
+void
+make_bios_readonly_intel(u16 bdf, u32 pam0)
+{
+    // Flush any pending writes before locking memory.
+    wbinvd();
+
+    // Write protect roms from 0xc0000-0xf0000
+    int i;
+    for (i=0; i<6; i++) {
+        u32 mem = BUILD_ROM_START + i * 32*1024;
+        u32 pam = pam0 + 1 + i;
+        if (RomEnd <= mem + 16*1024) {
+            if (RomEnd > mem)
+                pci_config_writeb(bdf, pam, 0x31);
+            break;
+        }
+        pci_config_writeb(bdf, pam, 0x11);
+    }
+
+    // Write protect 0xf0000-0x100000
+    pci_config_writeb(bdf, pam0, 0x10);
+}
+
+static const struct pci_device_id dram_controller_make_writable_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+               i440fx_bios_make_writable),
+    PCI_DEVICE_END
+};
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable(void)
+{
+    if (CONFIG_COREBOOT)
+        return;
+
+    dprintf(3, "enabling shadow ram\n");
+
+    // at this point, statically allocated variables can't be written.
+    // so stack should be used.
+
+    // Locate chip controlling ram shadowing.
+    int bdf = pci_find_init_device(dram_controller_make_writable_tbl, NULL);
+    if (bdf < 0) {
+        dprintf(1, "Unable to unlock ram - bridge not found\n");
+    }
+}
+
+static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+               i440fx_bios_make_readonly),
+    PCI_DEVICE_END
+};
+
+// Make the BIOS code segment area (0xf0000) read-only.
+void
+make_bios_readonly(void)
+{
+    if (CONFIG_COREBOOT)
+        return;
+
+    dprintf(3, "locking shadow ram\n");
+    int bdf = pci_find_init_device(dram_controller_make_readonly_tbl, NULL);
+    if (bdf < 0) {
+        dprintf(1, "Unable to lock ram - bridge not found\n");
+    }
+}
+
+void
+qemu_prep_reset(void)
+{
+    if (CONFIG_COREBOOT)
+        return;
+    // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
+    // reset, so do that manually before invoking a hard reset.
+    make_bios_writable();
+    extern u8 code32flat_start[], code32flat_end[];
+    memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+           , code32flat_end - code32flat_start);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/smbios.c b/qemu-0.15.x/roms/seabios/src/smbios.c
new file mode 100644
index 0000000..8df0f2d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/smbios.c
@@ -0,0 +1,514 @@
+// smbios table generation (on emulators)
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "paravirt.h" // qemu_cfg_smbios_load_field
+#include "smbios.h" // struct smbios_entry_point
+
+static void
+smbios_entry_point_init(u16 max_structure_size,
+                        u16 structure_table_length,
+                        void *structure_table_address,
+                        u16 number_of_structures)
+{
+    struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
+    void *finaltable = malloc_high(structure_table_length);
+    if (!ep || !finaltable) {
+        warn_noalloc();
+        free(ep);
+        free(finaltable);
+        return;
+    }
+    memcpy(finaltable, structure_table_address, structure_table_length);
+
+    memcpy(ep->anchor_string, "_SM_", 4);
+    ep->length = 0x1f;
+    ep->smbios_major_version = 2;
+    ep->smbios_minor_version = 4;
+    ep->max_structure_size = max_structure_size;
+    ep->entry_point_revision = 0;
+    memset(ep->formatted_area, 0, 5);
+    memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
+
+    ep->structure_table_length = structure_table_length;
+    ep->structure_table_address = (u32)finaltable;
+    ep->number_of_structures = number_of_structures;
+    ep->smbios_bcd_revision = 0x24;
+
+    ep->checksum -= checksum(ep, 0x10);
+
+    ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10);
+
+    dprintf(1, "SMBIOS ptr=%p table=%p\n", ep, finaltable);
+}
+
+#define load_str_field_with_default(type, field, def)                   \
+    do {                                                                \
+        size = qemu_cfg_smbios_load_field(type,                         \
+                                 offsetof(struct smbios_type_##type,    \
+                                          field), end);                 \
+        if (size > 0) {                                                 \
+            end += size;                                                \
+        } else {                                                        \
+            memcpy(end, def, sizeof(def));                              \
+            end += sizeof(def);                                         \
+        }                                                               \
+        p->field = ++str_index;                                         \
+    } while (0)
+
+#define load_str_field_or_skip(type, field)                             \
+    do {                                                                \
+        size = qemu_cfg_smbios_load_field(type,                         \
+                                 offsetof(struct smbios_type_##type,    \
+                                          field), end);                 \
+        if (size > 0) {                                                 \
+            end += size;                                                \
+            p->field = ++str_index;                                     \
+        } else {                                                        \
+            p->field = 0;                                               \
+        }                                                               \
+    } while (0)
+
+#define set_field_with_default(type, field, def)                        \
+    do {                                                                \
+        if (!qemu_cfg_smbios_load_field(type,                           \
+                                 offsetof(struct smbios_type_##type,    \
+                                          field), &p->field)) {         \
+            p->field = def;                                             \
+        }                                                               \
+    } while (0)
+
+/* Type 0 -- BIOS Information */
+#define RELEASE_DATE_STR "01/01/2007"
+static void *
+smbios_init_type_0(void *start)
+{
+    struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_0);
+    size_t size;
+    int str_index = 0;
+
+    p->header.type = 0;
+    p->header.length = sizeof(struct smbios_type_0);
+    p->header.handle = 0;
+
+    load_str_field_with_default(0, vendor_str, CONFIG_APPNAME);
+    load_str_field_with_default(0, bios_version_str, CONFIG_APPNAME);
+
+    p->bios_starting_address_segment = 0xe800;
+
+    load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
+
+    p->bios_rom_size = 0; /* FIXME */
+
+    if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
+                                                bios_characteristics),
+                                    &p->bios_characteristics)) {
+        memset(p->bios_characteristics, 0, 8);
+        /* BIOS characteristics not supported */
+        p->bios_characteristics[0] = 0x08;
+    }
+
+    if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
+                                    bios_characteristics_extension_bytes),
+                                    &p->bios_characteristics_extension_bytes)) {
+        p->bios_characteristics_extension_bytes[0] = 0;
+        /* Enable targeted content distribution. Needed for SVVP */
+        p->bios_characteristics_extension_bytes[1] = 4;
+    }
+
+    set_field_with_default(0, system_bios_major_release, 1);
+    set_field_with_default(0, system_bios_minor_release, 0);
+    set_field_with_default(0, embedded_controller_major_release, 0xff);
+    set_field_with_default(0, embedded_controller_minor_release, 0xff);
+
+    *end = 0;
+    end++;
+
+    return end;
+}
+
+/* Type 1 -- System Information */
+static void *
+smbios_init_type_1(void *start)
+{
+    struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_1);
+    size_t size;
+    int str_index = 0;
+
+    p->header.type = 1;
+    p->header.length = sizeof(struct smbios_type_1);
+    p->header.handle = 0x100;
+
+    load_str_field_with_default(1, manufacturer_str, CONFIG_APPNAME);
+    load_str_field_with_default(1, product_name_str, CONFIG_APPNAME);
+    load_str_field_or_skip(1, version_str);
+    load_str_field_or_skip(1, serial_number_str);
+
+    if (!qemu_cfg_smbios_load_field(1, offsetof(struct smbios_type_1,
+                                                  uuid), &p->uuid)) {
+        memset(p->uuid, 0, 16);
+    }
+
+    set_field_with_default(1, wake_up_type, 0x06); /* power switch */
+
+    load_str_field_or_skip(1, sku_number_str);
+    load_str_field_or_skip(1, family_str);
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
+/* Type 3 -- System Enclosure */
+static void *
+smbios_init_type_3(void *start)
+{
+    struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_3);
+    size_t size;
+    int str_index = 0;
+
+    p->header.type = 3;
+    p->header.length = sizeof(struct smbios_type_3);
+    p->header.handle = 0x300;
+
+    load_str_field_with_default(3, manufacturer_str, CONFIG_APPNAME);
+    set_field_with_default(3, type, 0x01); /* other */
+
+    load_str_field_or_skip(3, version_str);
+    load_str_field_or_skip(3, serial_number_str);
+    load_str_field_or_skip(3, asset_tag_number_str);
+
+    set_field_with_default(3, boot_up_state, 0x03); /* safe */
+    set_field_with_default(3, power_supply_state, 0x03); /* safe */
+    set_field_with_default(3, thermal_state, 0x03); /* safe */
+    set_field_with_default(3, security_status, 0x02); /* unknown */
+
+    set_field_with_default(3, oem_defined, 0);
+    set_field_with_default(3, height, 0);
+    set_field_with_default(3, number_of_power_cords, 0);
+    set_field_with_default(3, contained_element_count, 0);
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
+/* Type 4 -- Processor Information */
+static void *
+smbios_init_type_4(void *start, unsigned int cpu_number)
+{
+    struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_4);
+    size_t size;
+    int str_index = 0;
+    char name[1024];
+
+    p->header.type = 4;
+    p->header.length = sizeof(struct smbios_type_4);
+    p->header.handle = 0x400 + cpu_number;
+
+    size = qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
+                                                  socket_designation_str),
+                                                  name);
+    if (size)
+        snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
+    else
+        snprintf(name, sizeof(name), "CPU%2x", cpu_number);
+
+    memcpy(end, name, strlen(name) + 1);
+    end += strlen(name) + 1;
+    p->socket_designation_str = ++str_index;
+
+    set_field_with_default(4, processor_type, 0x03); /* CPU */
+    set_field_with_default(4, processor_family, 0x01); /* other */
+
+    load_str_field_with_default(4, processor_manufacturer_str, CONFIG_APPNAME);
+
+    if (!qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
+                                    processor_id), p->processor_id)) {
+        u32 cpuid_signature, ebx, ecx, cpuid_features;
+        cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+        p->processor_id[0] = cpuid_signature;
+        p->processor_id[1] = cpuid_features;
+    }
+
+    load_str_field_or_skip(4, processor_version_str);
+    set_field_with_default(4, voltage, 0);
+    set_field_with_default(4, external_clock, 0);
+
+    set_field_with_default(4, max_speed, 2000);
+    set_field_with_default(4, current_speed, 2000);
+
+    set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */
+    set_field_with_default(4, processor_upgrade, 0x01); /* other */
+
+    /* cache information structure not provided */
+    p->l1_cache_handle =  0xffff;
+    p->l2_cache_handle =  0xffff;
+    p->l3_cache_handle =  0xffff;
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
+/* Type 16 -- Physical Memory Array */
+static void *
+smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs)
+{
+    struct smbios_type_16 *p = (struct smbios_type_16*)start;
+
+    p->header.type = 16;
+    p->header.length = sizeof(struct smbios_type_16);
+    p->header.handle = 0x1000;
+
+    set_field_with_default(16, location, 0x01); /* other */
+    set_field_with_default(16, use, 0x03); /* system memory */
+    /* Multi-bit ECC to make Microsoft happy */
+    set_field_with_default(16, error_correction, 0x06);
+    /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */
+    p->maximum_capacity = memory_size_mb < 2 << 20 ?
+                          memory_size_mb << 10 : 0x80000000;
+    p->memory_error_information_handle = 0xfffe; /* none provided */
+    p->number_of_memory_devices = nr_mem_devs;
+
+    start += sizeof(struct smbios_type_16);
+    *((u16 *)start) = 0;
+
+    return start + 2;
+}
+
+/* Type 17 -- Memory Device */
+static void *
+smbios_init_type_17(void *start, u32 size_mb, int instance)
+{
+    struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_17);
+    size_t size;
+    int str_index = 0;
+    char name[1024];
+
+    p->header.type = 17;
+    p->header.length = sizeof(struct smbios_type_17);
+    p->header.handle = 0x1100 + instance;
+
+    p->physical_memory_array_handle = 0x1000;
+    set_field_with_default(17, total_width, 64);
+    set_field_with_default(17, data_width, 64);
+/* TODO: should assert in case something is wrong   ASSERT((memory_size_mb & ~0x7fff) == 0); */
+    p->size = size_mb;
+    set_field_with_default(17, form_factor, 0x09); /* DIMM */
+    p->device_set = 0;
+
+    size = qemu_cfg_smbios_load_field(17, offsetof(struct smbios_type_17,
+                                                   device_locator_str),
+                                                   name);
+    if (size)
+        snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
+    else
+        snprintf(name, sizeof(name), "DIMM %d", instance);
+
+    memcpy(end, name, strlen(name) + 1);
+    end += strlen(name) + 1;
+    p->device_locator_str = ++str_index;
+
+    load_str_field_or_skip(17, bank_locator_str);
+    set_field_with_default(17, memory_type, 0x07); /* RAM */
+    set_field_with_default(17, type_detail, 0);
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
+/* Type 19 -- Memory Array Mapped Address */
+static void *
+smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance)
+{
+    struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+
+    p->header.type = 19;
+    p->header.length = sizeof(struct smbios_type_19);
+    p->header.handle = 0x1300 + instance;
+
+    p->starting_address = start_mb << 10;
+    p->ending_address = p->starting_address + (size_mb << 10) - 1;
+    p->memory_array_handle = 0x1000;
+    p->partition_width = 1;
+
+    start += sizeof(struct smbios_type_19);
+    *((u16 *)start) = 0;
+
+    return start + 2;
+}
+
+/* Type 20 -- Memory Device Mapped Address */
+static void *
+smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance,
+                    int dev_handle, int array_handle)
+{
+    struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+
+    p->header.type = 20;
+    p->header.length = sizeof(struct smbios_type_20);
+    p->header.handle = 0x1400 + instance;
+
+    p->starting_address = start_mb << 10;
+    p->ending_address = p->starting_address + (size_mb << 10) - 1;
+    p->memory_device_handle = 0x1100 + dev_handle;
+    p->memory_array_mapped_address_handle = 0x1300 + array_handle;
+    p->partition_row_position = 1;
+    p->interleave_position = 0;
+    p->interleaved_data_depth = 0;
+
+    start += sizeof(struct smbios_type_20);
+
+    *((u16 *)start) = 0;
+    return start+2;
+}
+
+/* Type 32 -- System Boot Information */
+static void *
+smbios_init_type_32(void *start)
+{
+    struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+
+    p->header.type = 32;
+    p->header.length = sizeof(struct smbios_type_32);
+    p->header.handle = 0x2000;
+    memset(p->reserved, 0, 6);
+    set_field_with_default(32, boot_status, 0); /* no errors detected */
+
+    start += sizeof(struct smbios_type_32);
+    *((u16 *)start) = 0;
+
+    return start+2;
+}
+
+/* Type 127 -- End of Table */
+static void *
+smbios_init_type_127(void *start)
+{
+    struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+
+    p->header.type = 127;
+    p->header.length = sizeof(struct smbios_type_127);
+    p->header.handle = 0x7f00;
+
+    start += sizeof(struct smbios_type_127);
+    *((u16 *)start) = 0;
+
+    return start + 2;
+}
+
+#define TEMPSMBIOSSIZE (32 * 1024)
+
+void
+smbios_init(void)
+{
+    if (! CONFIG_SMBIOS)
+        return;
+
+    dprintf(3, "init SMBIOS tables\n");
+
+    char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
+    if (! start) {
+        warn_noalloc();
+        return;
+    }
+
+    u32 nr_structs = 0, max_struct_size = 0;
+    char *q, *p = start;
+    char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127);
+
+#define add_struct(type, args...)                                       \
+    do {                                                                \
+        if (!qemu_cfg_smbios_load_external(type, &p, &nr_structs,       \
+                                           &max_struct_size, end)) {    \
+            q = smbios_init_type_##type(args);                          \
+            nr_structs++;                                               \
+            if ((q - p) > max_struct_size)                              \
+                max_struct_size = q - p;                                \
+            p = q;                                                      \
+        }                                                               \
+    } while (0)
+
+    add_struct(0, p);
+    add_struct(1, p);
+    add_struct(3, p);
+
+    int cpu_num;
+    for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
+        add_struct(4, p, cpu_num);
+
+    int ram_mb = (RamSize + RamSizeOver4G) >> 20;
+    int nr_mem_devs = (ram_mb + 0x3fff) >> 14;
+    add_struct(16, p, ram_mb, nr_mem_devs);
+
+    int i, j;
+    for (i = 0; i < nr_mem_devs; i++) {
+        u32 dev_mb = ((i == (nr_mem_devs - 1))
+                      ? (((ram_mb - 1) & 0x3fff) + 1)
+                      : 16384);
+        add_struct(17, p, dev_mb, i);
+    }
+
+    add_struct(19, p, 0, RamSize >> 20, 0);
+    if (RamSizeOver4G)
+        add_struct(19, p, 4096, RamSizeOver4G >> 20, 1);
+
+    add_struct(20, p, 0, RamSize >> 20, 0, 0, 0);
+    if (RamSizeOver4G) {
+        u32 start_mb = 4096;
+        for (j = 1, i = 0; i < nr_mem_devs; i++, j++) {
+            u32 dev_mb = ((i == (nr_mem_devs - 1))
+                               ? (((ram_mb - 1) & 0x3fff) + 1)
+                               : 16384);
+            if (i == 0)
+                dev_mb -= RamSize >> 20;
+
+            add_struct(20, p, start_mb, dev_mb, j, i, 1);
+            start_mb += dev_mb;
+        }
+    }
+
+    add_struct(32, p);
+    /* Add any remaining provided entries before the end marker */
+    for (i = 0; i < 256; i++)
+        qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,
+                                      end);
+    add_struct(127, p);
+
+#undef add_struct
+
+    smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
+    free(start);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/smbios.h b/qemu-0.15.x/roms/seabios/src/smbios.h
new file mode 100644
index 0000000..7bf2bed
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/smbios.h
@@ -0,0 +1,166 @@
+#ifndef __SMBIOS_H
+#define __SMBIOS_H
+
+// smbios.c
+void smbios_init(void);
+
+/* SMBIOS entry point -- must be written to a 16-bit aligned address
+   between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+    char anchor_string[4];
+    u8 checksum;
+    u8 length;
+    u8 smbios_major_version;
+    u8 smbios_minor_version;
+    u16 max_structure_size;
+    u8 entry_point_revision;
+    u8 formatted_area[5];
+    char intermediate_anchor_string[5];
+    u8 intermediate_checksum;
+    u16 structure_table_length;
+    u32 structure_table_address;
+    u16 number_of_structures;
+    u8 smbios_bcd_revision;
+} PACKED;
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+    u8 type;
+    u8 length;
+    u16 handle;
+} PACKED;
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+    struct smbios_structure_header header;
+    u8 vendor_str;
+    u8 bios_version_str;
+    u16 bios_starting_address_segment;
+    u8 bios_release_date_str;
+    u8 bios_rom_size;
+    u8 bios_characteristics[8];
+    u8 bios_characteristics_extension_bytes[2];
+    u8 system_bios_major_release;
+    u8 system_bios_minor_release;
+    u8 embedded_controller_major_release;
+    u8 embedded_controller_minor_release;
+} PACKED;
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+    struct smbios_structure_header header;
+    u8 manufacturer_str;
+    u8 product_name_str;
+    u8 version_str;
+    u8 serial_number_str;
+    u8 uuid[16];
+    u8 wake_up_type;
+    u8 sku_number_str;
+    u8 family_str;
+} PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+    struct smbios_structure_header header;
+    u8 manufacturer_str;
+    u8 type;
+    u8 version_str;
+    u8 serial_number_str;
+    u8 asset_tag_number_str;
+    u8 boot_up_state;
+    u8 power_supply_state;
+    u8 thermal_state;
+    u8 security_status;
+    u32 oem_defined;
+    u8 height;
+    u8 number_of_power_cords;
+    u8 contained_element_count;
+    // contained elements follow
+} PACKED;
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+    struct smbios_structure_header header;
+    u8 socket_designation_str;
+    u8 processor_type;
+    u8 processor_family;
+    u8 processor_manufacturer_str;
+    u32 processor_id[2];
+    u8 processor_version_str;
+    u8 voltage;
+    u16 external_clock;
+    u16 max_speed;
+    u16 current_speed;
+    u8 status;
+    u8 processor_upgrade;
+    u16 l1_cache_handle;
+    u16 l2_cache_handle;
+    u16 l3_cache_handle;
+} PACKED;
+
+/* SMBIOS type 16 - Physical Memory Array
+ *   Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+    struct smbios_structure_header header;
+    u8 location;
+    u8 use;
+    u8 error_correction;
+    u32 maximum_capacity;
+    u16 memory_error_information_handle;
+    u16 number_of_memory_devices;
+} PACKED;
+
+/* SMBIOS type 17 - Memory Device
+ *   Associated with one type 19
+ */
+struct smbios_type_17 {
+    struct smbios_structure_header header;
+    u16 physical_memory_array_handle;
+    u16 memory_error_information_handle;
+    u16 total_width;
+    u16 data_width;
+    u16 size;
+    u8 form_factor;
+    u8 device_set;
+    u8 device_locator_str;
+    u8 bank_locator_str;
+    u8 memory_type;
+    u16 type_detail;
+} PACKED;
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+    struct smbios_structure_header header;
+    u32 starting_address;
+    u32 ending_address;
+    u16 memory_array_handle;
+    u8 partition_width;
+} PACKED;
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+    struct smbios_structure_header header;
+    u32 starting_address;
+    u32 ending_address;
+    u16 memory_device_handle;
+    u16 memory_array_mapped_address_handle;
+    u8 partition_row_position;
+    u8 interleave_position;
+    u8 interleaved_data_depth;
+} PACKED;
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+    struct smbios_structure_header header;
+    u8 reserved[6];
+    u8 boot_status;
+} PACKED;
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+    struct smbios_structure_header header;
+} PACKED;
+
+#endif // smbios.h
diff --git a/qemu-0.15.x/roms/seabios/src/smm.c b/qemu-0.15.x/roms/seabios/src/smm.c
new file mode 100644
index 0000000..7e52892
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/smm.c
@@ -0,0 +1,127 @@
+// System Management Mode support (on emulators)
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // pci_config_writel
+#include "util.h" // wbinvd
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outb
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "dev-i440fx.h"
+
+ASM32FLAT(
+    ".global smm_relocation_start\n"
+    ".global smm_relocation_end\n"
+    ".global smm_code_start\n"
+    ".global smm_code_end\n"
+    "  .code16\n"
+
+    /* code to relocate SMBASE to 0xa0000 */
+    "smm_relocation_start:\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
+    "  addr32 mov (%ebx), %al\n"  /* revision ID to see if x86_64 or x86 */
+    "  cmp $0x64, %al\n"
+    "  je 1f\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
+    "  jmp 2f\n"
+    "1:\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
+    "2:\n"
+    "  movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
+    "  addr32 movl %eax, (%ebx)\n"
+    /* indicate to the BIOS that the SMM code was executed */
+    "  mov $0x00, %al\n"
+    "  movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
+    "  outb %al, %dx\n"
+    "  rsm\n"
+    "smm_relocation_end:\n"
+
+    /* minimal SMM code to enable or disable ACPI */
+    "smm_code_start:\n"
+    "  movw $" __stringify(PORT_SMI_CMD) ", %dx\n"
+    "  inb %dx, %al\n"
+    "  cmp $0xf0, %al\n"
+    "  jne 1f\n"
+
+    /* ACPI disable */
+    "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+    "  inw %dx, %ax\n"
+    "  andw $~1, %ax\n"
+    "  outw %ax, %dx\n"
+
+    "  jmp 2f\n"
+
+    "1:\n"
+    "  cmp $0xf1, %al\n"
+    "  jne 2f\n"
+
+    /* ACPI enable */
+    "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+    "  inw %dx, %ax\n"
+    "  orw $1, %ax\n"
+    "  outw %ax, %dx\n"
+
+    "2:\n"
+    "  rsm\n"
+    "smm_code_end:\n"
+    "  .code32\n"
+    );
+
+extern u8 smm_relocation_start, smm_relocation_end;
+extern u8 smm_code_start, smm_code_end;
+
+void
+smm_save_and_copy(void)
+{
+    /* save original memory content */
+    memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
+
+    /* copy the SMM relocation code */
+    memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start,
+           &smm_relocation_end - &smm_relocation_start);
+}
+
+void
+smm_relocate_and_restore(void)
+{
+    /* init APM status port */
+    outb(0x01, PORT_SMI_STATUS);
+
+    /* raise an SMI interrupt */
+    outb(0x00, PORT_SMI_CMD);
+
+    /* wait until SMM code executed */
+    while (inb(PORT_SMI_STATUS) != 0x00)
+        ;
+
+    /* restore original memory content */
+    memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
+
+    /* copy the SMM code */
+    memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
+           , &smm_code_end - &smm_code_start);
+    wbinvd();
+}
+
+static const struct pci_device_id smm_init_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+               piix4_apmc_smm_init),
+
+    PCI_DEVICE_END,
+};
+
+void
+smm_init(void)
+{
+    if (CONFIG_COREBOOT)
+        // SMM only supported on emulators.
+        return;
+    if (!CONFIG_USE_SMM)
+        return;
+
+    dprintf(3, "init smm\n");
+    pci_find_init_device(smm_init_tbl, NULL);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/smp.c b/qemu-0.15.x/roms/seabios/src/smp.c
new file mode 100644
index 0000000..40f5451
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/smp.c
@@ -0,0 +1,129 @@
+// CPU count detection
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_BIOS_SMP_COUNT
+#include "paravirt.h"
+
+#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
+#define APIC_SVR     ((u8*)BUILD_APIC_ADDR + 0x0F0)
+#define APIC_LINT0   ((u8*)BUILD_APIC_ADDR + 0x350)
+#define APIC_LINT1   ((u8*)BUILD_APIC_ADDR + 0x360)
+
+#define APIC_ENABLED 0x0100
+
+struct { u32 ecx, eax, edx; } smp_mtrr[16] VAR16VISIBLE;
+u32 smp_mtrr_count VAR16VISIBLE;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+    wrmsr(index, val);
+    if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr))
+        return;
+    smp_mtrr[smp_mtrr_count].ecx = index;
+    smp_mtrr[smp_mtrr_count].eax = val;
+    smp_mtrr[smp_mtrr_count].edx = val >> 32;
+    smp_mtrr_count++;
+}
+
+u32 CountCPUs VAR16VISIBLE;
+u32 MaxCountCPUs VAR16VISIBLE;
+extern void smp_ap_boot_code(void);
+ASM16(
+    "  .global smp_ap_boot_code\n"
+    "smp_ap_boot_code:\n"
+
+    // Setup data segment
+    "  movw $" __stringify(SEG_BIOS) ", %ax\n"
+    "  movw %ax, %ds\n"
+
+    // MTRR setup
+    "  movl $smp_mtrr, %esi\n"
+    "  movl smp_mtrr_count, %ebx\n"
+    "1:testl %ebx, %ebx\n"
+    "  jz 2f\n"
+    "  movl 0(%esi), %ecx\n"
+    "  movl 4(%esi), %eax\n"
+    "  movl 8(%esi), %edx\n"
+    "  wrmsr\n"
+    "  addl $12, %esi\n"
+    "  decl %ebx\n"
+    "  jmp 1b\n"
+    "2:\n"
+
+    // Increment the cpu counter
+    "  lock incl CountCPUs\n"
+
+    // Halt the processor.
+    "1:hlt\n"
+    "  jmp 1b\n"
+    );
+
+// find and initialize the CPUs by launching a SIPI to them
+void
+smp_probe(void)
+{
+    ASSERT32FLAT();
+    u32 eax, ebx, ecx, cpuid_features;
+    cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+    if (eax < 1 || !(cpuid_features & CPUID_APIC)) {
+        // No apic - only the main cpu is present.
+        dprintf(1, "No apic - only the main cpu is present.\n");
+        CountCPUs= 1;
+        MaxCountCPUs = 1;
+        return;
+    }
+
+    // Init the counter.
+    writel(&CountCPUs, 1);
+
+    // Setup jump trampoline to counter code.
+    u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+    // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
+    u64 new = (0xea | ((u64)SEG_BIOS<<24)
+               | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
+    *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+    // enable local APIC
+    u32 val = readl(APIC_SVR);
+    writel(APIC_SVR, val | APIC_ENABLED);
+
+    if (! CONFIG_COREBOOT) {
+        /* Set LINT0 as Ext_INT, level triggered */
+        writel(APIC_LINT0, 0x8700);
+
+        /* Set LINT1 as NMI, level triggered */
+        writel(APIC_LINT1, 0x8400);
+    }
+
+    // broadcast SIPI
+    barrier();
+    writel(APIC_ICR_LOW, 0x000C4500);
+    u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
+    writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+    // Wait for other CPUs to process the SIPI.
+    if (CONFIG_COREBOOT) {
+        msleep(10);
+    } else {
+        u8 cmos_smp_count = inb_cmos(CMOS_BIOS_SMP_COUNT);
+        while (cmos_smp_count + 1 != readl(&CountCPUs))
+            yield();
+    }
+
+    // Restore memory.
+    *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+    MaxCountCPUs = qemu_cfg_get_max_cpus();
+    if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+        MaxCountCPUs = CountCPUs;
+
+    dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", readl(&CountCPUs),
+        MaxCountCPUs);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/ssdt-proc.dsl b/qemu-0.15.x/roms/seabios/src/ssdt-proc.dsl
new file mode 100644
index 0000000..358afa8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/ssdt-proc.dsl
@@ -0,0 +1,50 @@
+/* This file is the basis for the ssdt_proc[] variable in src/acpi.c.
+ * It defines the contents of the per-cpu Processor() object.  At
+ * runtime, a dynamically generated SSDT will contain one copy of this
+ * AML snippet for every possible cpu in the system.  The objects will
+ * be placed in the \_SB_ namespace.
+ *
+ * To generate a new ssdt_proc[], run the commands:
+ *   cpp -P src/ssdt-proc.dsl > out/ssdt-proc.dsl.i
+ *   iasl -ta -p out/ssdt-proc out/ssdt-proc.dsl.i
+ *   tail -c +37 < out/ssdt-proc.aml | hexdump -e '"    " 8/1 "0x%02x," "\n"'
+ * and then cut-and-paste the output into the src/acpi.c ssdt_proc[]
+ * array.
+ *
+ * In addition to the aml code generated from this file, the
+ * src/acpi.c file creates a NTFY method with an entry for each cpu:
+ *     Method(NTFY, 2) {
+ *         If (LEqual(Arg0, 0x00)) { Notify(CP00, Arg1) }
+ *         If (LEqual(Arg0, 0x01)) { Notify(CP01, Arg1) }
+ *         ...
+ *     }
+ * and a CPON array with the list of active and inactive cpus:
+ *     Name(CPON, Package() { One, One, ..., Zero, Zero, ... })
+ */
+DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1)
+/*  v------------------ DO NOT EDIT ------------------v */
+{
+    Processor (CPAA, 0xAA, 0x0000b010, 0x06) {
+        Name (ID, 0xAA)
+/*  ^------------------ DO NOT EDIT ------------------^
+ *
+ * The src/acpi.c code requires the above layout so that it can update
+ * CPAA and 0xAA with the appropriate CPU id (see
+ * SD_OFFSET_CPUHEX/CPUID1/CPUID2).  Don't change the above without
+ * also updating the C code.
+ */
+        Name (_HID, "ACPI0007")
+        External(CPMA, MethodObj)
+        External(CPST, MethodObj)
+        External(CPEJ, MethodObj)
+        Method(_MAT, 0) {
+            Return(CPMA(ID))
+        }
+        Method (_STA, 0) {
+            Return(CPST(ID))
+        }
+        Method (_EJ0, 1, NotSerialized) {
+            CPEJ(ID, Arg0)
+        }
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/stacks.c b/qemu-0.15.x/roms/seabios/src/stacks.c
new file mode 100644
index 0000000..53bf669
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/stacks.c
@@ -0,0 +1,395 @@
+// Code for manipulating stack locations.
+//
+// Copyright (C) 2009-2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // get_ebda_seg
+#include "util.h" // dprintf
+#include "bregs.h" // CR0_PE
+
+// Thread info - stored at bottom of each thread stack - don't change
+// without also updating the inline assembler below.
+struct thread_info {
+    struct thread_info *next;
+    void *stackpos;
+    struct thread_info **pprev;
+};
+struct thread_info VAR32FLATVISIBLE MainThread = {
+    &MainThread, NULL, &MainThread.next
+};
+
+
+/****************************************************************
+ * Low level helpers
+ ****************************************************************/
+
+static inline u32 getcr0(void) {
+    u32 cr0;
+    asm("movl %%cr0, %0" : "=r"(cr0));
+    return cr0;
+}
+static inline void sgdt(struct descloc_s *desc) {
+    asm("sgdtl %0" : "=m"(*desc));
+}
+static inline void lgdt(struct descloc_s *desc) {
+    asm("lgdtl %0" : : "m"(*desc) : "memory");
+}
+
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32
+call32(void *func, u32 eax, u32 errret)
+{
+    ASSERT16();
+    u32 cr0 = getcr0();
+    if (cr0 & CR0_PE)
+        // Called in 16bit protected mode?!
+        return errret;
+
+    // Backup cmos index register and disable nmi
+    u8 cmosindex = inb(PORT_CMOS_INDEX);
+    outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
+    inb(PORT_CMOS_DATA);
+
+    // Backup fs/gs and gdt
+    u16 fs = GET_SEG(FS), gs = GET_SEG(GS);
+    struct descloc_s gdt;
+    sgdt(&gdt);
+
+    u32 bkup_ss, bkup_esp;
+    asm volatile(
+        // Backup ss/esp / set esp to flat stack location
+        "  movl %%ss, %0\n"
+        "  movl %%esp, %1\n"
+        "  shll $4, %0\n"
+        "  addl %0, %%esp\n"
+        "  shrl $4, %0\n"
+
+        // Transition to 32bit mode, call func, return to 16bit
+        "  movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n"
+        "  jmp transition32\n"
+        "  .code32\n"
+        "1:calll *%3\n"
+        "  movl $2f, %%edx\n"
+        "  jmp transition16big\n"
+
+        // Restore ds/ss/esp
+        "  .code16gcc\n"
+        "2:movl %0, %%ds\n"
+        "  movl %0, %%ss\n"
+        "  movl %1, %%esp\n"
+        : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax)
+        : "r" (func)
+        : "ecx", "edx", "cc", "memory");
+
+    // Restore gdt and fs/gs
+    lgdt(&gdt);
+    SET_SEG(FS, fs);
+    SET_SEG(GS, gs);
+
+    // Restore cmos index register
+    outb(cmosindex, PORT_CMOS_INDEX);
+    inb(PORT_CMOS_DATA);
+    return eax;
+}
+
+// 16bit trampoline for enabling irqs from 32bit mode.
+ASM16(
+    "  .global trampoline_checkirqs\n"
+    "trampoline_checkirqs:\n"
+    "  rep ; nop\n"
+    "  lretw"
+    );
+
+static void
+check_irqs(void)
+{
+    if (MODESEGMENT) {
+        asm volatile(
+            "sti\n"
+            "nop\n"
+            "rep ; nop\n"
+            "cli\n"
+            "cld\n"
+            : : :"memory");
+        return;
+    }
+    extern void trampoline_checkirqs();
+    struct bregs br;
+    br.flags = F_IF;
+    br.code.seg = SEG_BIOS;
+    br.code.offset = (u32)&trampoline_checkirqs;
+    call16big(&br);
+}
+
+// 16bit trampoline for waiting for an irq from 32bit mode.
+ASM16(
+    "  .global trampoline_waitirq\n"
+    "trampoline_waitirq:\n"
+    "  sti\n"
+    "  hlt\n"
+    "  lretw"
+    );
+
+// Wait for next irq to occur.
+void
+wait_irq(void)
+{
+    if (MODESEGMENT) {
+        asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+        return;
+    }
+    if (CONFIG_THREADS && MainThread.next != &MainThread) {
+        // Threads still active - do a yield instead.
+        yield();
+        return;
+    }
+    extern void trampoline_waitirq();
+    struct bregs br;
+    br.flags = 0;
+    br.code.seg = SEG_BIOS;
+    br.code.offset = (u32)&trampoline_waitirq;
+    call16big(&br);
+}
+
+
+/****************************************************************
+ * Stack in EBDA
+ ****************************************************************/
+
+// Switch to the extra stack in ebda and call a function.
+inline u32
+stack_hop(u32 eax, u32 edx, void *func)
+{
+    ASSERT16();
+    u16 ebda_seg = get_ebda_seg(), bkup_ss;
+    u32 bkup_esp;
+    asm volatile(
+        // Backup current %ss/%esp values.
+        "movw %%ss, %w3\n"
+        "movl %%esp, %4\n"
+        // Copy ebda seg to %ds/%ss and set %esp
+        "movw %w6, %%ds\n"
+        "movw %w6, %%ss\n"
+        "movl %5, %%esp\n"
+        // Call func
+        "calll *%2\n"
+        // Restore segments and stack
+        "movw %w3, %%ds\n"
+        "movw %w3, %%ss\n"
+        "movl %4, %%esp"
+        : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp)
+        : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg)
+        : "cc", "memory");
+    return eax;
+}
+
+
+/****************************************************************
+ * Threads
+ ****************************************************************/
+
+#define THREADSTACKSIZE 4096
+int VAR16VISIBLE CanPreempt;
+
+// Return the 'struct thread_info' for the currently running thread.
+struct thread_info *
+getCurThread(void)
+{
+    u32 esp = getesp();
+    if (esp <= BUILD_STACK_ADDR)
+        return &MainThread;
+    return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
+}
+
+// Switch to next thread stack.
+static void
+switch_next(struct thread_info *cur)
+{
+    struct thread_info *next = cur->next;
+    if (cur == next)
+        // Nothing to do.
+        return;
+    asm volatile(
+        "  pushl $1f\n"                 // store return pc
+        "  pushl %%ebp\n"               // backup %ebp
+        "  movl %%esp, 4(%%eax)\n"      // cur->stackpos = %esp
+        "  movl 4(%%ecx), %%esp\n"      // %esp = next->stackpos
+        "  popl %%ebp\n"                // restore %ebp
+        "  retl\n"                      // restore pc
+        "1:\n"
+        : "+a"(cur), "+c"(next)
+        :
+        : "ebx", "edx", "esi", "edi", "cc", "memory");
+}
+
+// Briefly permit irqs to occur.
+void
+yield(void)
+{
+    if (MODESEGMENT || !CONFIG_THREADS) {
+        // Just directly check irqs.
+        check_irqs();
+        return;
+    }
+    struct thread_info *cur = getCurThread();
+    if (cur == &MainThread)
+        // Permit irqs to fire
+        check_irqs();
+
+    // Switch to the next thread
+    switch_next(cur);
+}
+
+// Last thing called from a thread (called on "next" stack).
+static void
+__end_thread(struct thread_info *old)
+{
+    old->next->pprev = old->pprev;
+    *old->pprev = old->next;
+    free(old);
+    dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old);
+    if (MainThread.next == &MainThread)
+        dprintf(1, "All threads complete.\n");
+}
+
+// Create a new thread and start executing 'func' in it.
+void
+run_thread(void (*func)(void*), void *data)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_THREADS)
+        goto fail;
+    struct thread_info *thread;
+    thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
+    if (!thread)
+        goto fail;
+
+    thread->stackpos = (void*)thread + THREADSTACKSIZE;
+    struct thread_info *cur = getCurThread();
+    thread->next = cur;
+    thread->pprev = cur->pprev;
+    cur->pprev = &thread->next;
+    *thread->pprev = thread;
+
+    dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
+    asm volatile(
+        // Start thread
+        "  pushl $1f\n"                 // store return pc
+        "  pushl %%ebp\n"               // backup %ebp
+        "  movl %%esp, 4(%%edx)\n"      // cur->stackpos = %esp
+        "  movl 4(%%ebx), %%esp\n"      // %esp = thread->stackpos
+        "  calll *%%ecx\n"              // Call func
+
+        // End thread
+        "  movl (%%ebx), %%ecx\n"       // %ecx = thread->next
+        "  movl 4(%%ecx), %%esp\n"      // %esp = next->stackpos
+        "  movl %%ebx, %%eax\n"
+        "  calll %4\n"                  // call __end_thread(thread)
+        "  popl %%ebp\n"                // restore %ebp
+        "  retl\n"                      // restore pc
+        "1:\n"
+        : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
+        : "m"(*(u8*)__end_thread)
+        : "esi", "edi", "cc", "memory");
+    return;
+
+fail:
+    func(data);
+}
+
+// Wait for all threads (other than the main thread) to complete.
+void
+wait_threads(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_THREADS)
+        return;
+    while (MainThread.next != &MainThread)
+        yield();
+}
+
+void
+mutex_lock(struct mutex_s *mutex)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_THREADS)
+        return;
+    while (mutex->isLocked)
+        yield();
+    mutex->isLocked = 1;
+}
+
+void
+mutex_unlock(struct mutex_s *mutex)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_THREADS)
+        return;
+    mutex->isLocked = 0;
+}
+
+
+/****************************************************************
+ * Thread preemption
+ ****************************************************************/
+
+static u32 PreemptCount;
+
+// Turn on RTC irqs and arrange for them to check the 32bit threads.
+void
+start_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS)
+        return;
+    CanPreempt = 1;
+    PreemptCount = 0;
+    useRTC();
+}
+
+// Turn off RTC irqs / stop checking for thread execution.
+void
+finish_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) {
+        yield();
+        return;
+    }
+    CanPreempt = 0;
+    releaseRTC();
+    dprintf(9, "Done preempt - %d checks\n", PreemptCount);
+    yield();
+}
+
+// Check if preemption is on, and wait for it to complete if so.
+int
+wait_preempt(void)
+{
+    if (MODESEGMENT || !CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS
+        || !CanPreempt)
+        return 0;
+    while (CanPreempt)
+        yield();
+    return 1;
+}
+
+// Try to execute 32bit threads.
+void VISIBLE32INIT
+yield_preempt(void)
+{
+    PreemptCount++;
+    switch_next(&MainThread);
+}
+
+// 16bit code that checks if threads are pending and executes them if so.
+void
+check_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS
+        || !GET_GLOBAL(CanPreempt)
+        || GET_FLATPTR(MainThread.next) == &MainThread)
+        return;
+
+    extern void _cfunc32flat_yield_preempt(void);
+    call32(_cfunc32flat_yield_preempt, 0, 0);
+}
diff --git a/qemu-0.15.x/roms/seabios/src/system.c b/qemu-0.15.x/roms/seabios/src/system.c
new file mode 100644
index 0000000..898c3cc
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/system.c
@@ -0,0 +1,365 @@
+// Handler for int 0x15 "system" calls
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // memcpy_far
+#include "biosvar.h" // BIOS_CONFIG_TABLE
+#include "ioport.h" // inb
+#include "memmap.h" // E820_RAM
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+
+// Use PS2 System Control port A to set A20 enable
+static inline u8
+set_a20(u8 cond)
+{
+    // get current setting first
+    u8 newval, oldval = inb(PORT_A20);
+    if (cond)
+        newval = oldval | A20_ENABLE_BIT;
+    else
+        newval = oldval & ~A20_ENABLE_BIT;
+    outb(newval, PORT_A20);
+
+    return (oldval & A20_ENABLE_BIT) != 0;
+}
+
+static void
+handle_152400(struct bregs *regs)
+{
+    set_a20(0);
+    set_code_success(regs);
+}
+
+static void
+handle_152401(struct bregs *regs)
+{
+    set_a20(1);
+    set_code_success(regs);
+}
+
+static void
+handle_152402(struct bregs *regs)
+{
+    regs->al = (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
+    set_code_success(regs);
+}
+
+static void
+handle_152403(struct bregs *regs)
+{
+    regs->bx = 3;
+    set_code_success(regs);
+}
+
+static void
+handle_1524XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_1524(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_152400(regs); break;
+    case 0x01: handle_152401(regs); break;
+    case 0x02: handle_152402(regs); break;
+    case 0x03: handle_152403(regs); break;
+    default:   handle_1524XX(regs); break;
+    }
+}
+
+// removable media eject
+static void
+handle_1552(struct bregs *regs)
+{
+    set_code_success(regs);
+}
+
+static void
+handle_1587(struct bregs *regs)
+{
+    // +++ should probably have descriptor checks
+    // +++ should have exception handlers
+
+    u8 prev_a20_enable = set_a20(1); // enable A20 line
+
+    // 128K max of transfer on 386+ ???
+    // source == destination ???
+
+    // ES:SI points to descriptor table
+    // offset   use     initially  comments
+    // ==============================================
+    // 00..07   Unused  zeros      Null descriptor
+    // 08..0f   GDT     zeros      filled in by BIOS
+    // 10..17   source  ssssssss   source of data
+    // 18..1f   dest    dddddddd   destination of data
+    // 20..27   CS      zeros      filled in by BIOS
+    // 28..2f   SS      zeros      filled in by BIOS
+
+// check for access rights of source & dest here
+
+    // Initialize GDT descriptor
+    u32 si = regs->si;
+    u64 *gdt_far = (void*)si;
+    u16 gdt_seg = regs->es;
+    u32 loc = (u32)MAKE_FLATPTR(gdt_seg, gdt_far);
+    SET_FARVAR(gdt_seg, gdt_far[1], GDT_DATA | GDT_LIMIT((6*sizeof(u64))-1)
+               | GDT_BASE(loc));
+    // Initialize CS descriptor
+    SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+               | GDT_BASE(BUILD_BIOS_ADDR));
+    // Initialize SS descriptor
+    loc = (u32)MAKE_FLATPTR(GET_SEG(SS), 0);
+    SET_FARVAR(gdt_seg, gdt_far[5], GDT_DATA | GDT_LIMIT(0x0ffff)
+               | GDT_BASE(loc));
+
+    u16 count = regs->cx;
+    asm volatile(
+        // Load new descriptor tables
+        "  lgdtw %%es:(1<<3)(%%si)\n"
+        "  lidtw %%cs:pmode_IDT_info\n"
+
+        // Enable protected mode
+        "  movl %%cr0, %%eax\n"
+        "  orl $" __stringify(CR0_PE) ", %%eax\n"
+        "  movl %%eax, %%cr0\n"
+
+        // far jump to flush CPU queue after transition to protected mode
+        "  ljmpw $(4<<3), $1f\n"
+
+        // GDT points to valid descriptor table, now load DS, ES
+        "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00
+        "  movw %%ax, %%ds\n"
+        "  movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00
+        "  movw %%ax, %%es\n"
+
+        // move CX words from DS:SI to ES:DI
+        "  xorw %%si, %%si\n"
+        "  xorw %%di, %%di\n"
+        "  rep movsw\n"
+
+        // Restore DS and ES segment limits to 0xffff
+        "  movw $(5<<3), %%ax\n" // 5th descriptor in table (SS)
+        "  movw %%ax, %%ds\n"
+        "  movw %%ax, %%es\n"
+
+        // Disable protected mode
+        "  movl %%cr0, %%eax\n"
+        "  andl $~" __stringify(CR0_PE) ", %%eax\n"
+        "  movl %%eax, %%cr0\n"
+
+        // far jump to flush CPU queue after transition to real mode
+        "  ljmpw $" __stringify(SEG_BIOS) ", $2f\n"
+
+        // restore IDT to normal real-mode defaults
+        "2:lidtw %%cs:rmode_IDT_info\n"
+
+        // Restore %ds (from %ss)
+        "  movw %%ss, %%ax\n"
+        "  movw %%ax, %%ds\n"
+        : "+c"(count), "+S"(si)
+        : : "eax", "di", "cc"); // XXX - also clobbers %es
+
+    set_a20(prev_a20_enable);
+
+    set_code_success(regs);
+}
+
+// Get the amount of extended memory (above 1M)
+static void
+handle_1588(struct bregs *regs)
+{
+    u32 rs = GET_GLOBAL(RamSize);
+
+    // According to Ralf Brown's interrupt the limit should be 15M,
+    // but real machines mostly return max. 63M.
+    if (rs > 64*1024*1024)
+        regs->ax = 63 * 1024;
+    else
+        regs->ax = (rs - 1*1024*1024) / 1024;
+    set_success(regs);
+}
+
+// Switch to protected mode
+static void
+handle_1589(struct bregs *regs)
+{
+    set_a20(1);
+
+    set_pics(regs->bl, regs->bh);
+
+    u64 *gdt_far = (void*)(regs->si + 0);
+    u16 gdt_seg = regs->es;
+    SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+               | GDT_BASE(BUILD_BIOS_ADDR));
+
+    regs->ds = 3<<3; // 3rd gdt descriptor is %ds
+    regs->es = 4<<3; // 4th gdt descriptor is %es
+    regs->code.seg = 6<<3; // 6th gdt descriptor is %cs
+
+    set_code_success(regs);
+
+    asm volatile(
+        // Load new descriptor tables
+        "  lgdtw %%es:(1<<3)(%%si)\n"
+        "  lidtw %%es:(2<<3)(%%si)\n"
+
+        // Enable protected mode
+        "  movl %%cr0, %%eax\n"
+        "  orl $" __stringify(CR0_PE) ", %%eax\n"
+        "  movl %%eax, %%cr0\n"
+
+        // far jump to flush CPU queue after transition to protected mode
+        "  ljmpw $(7<<3), $1f\n"
+
+        // GDT points to valid descriptor table, now load SS
+        "1:movw $(5<<3), %%ax\n"
+        "  movw %%ax, %%ds\n"
+        "  movw %%ax, %%ss\n"
+        :
+        : "S"(gdt_far)
+        : "eax", "cc");
+}
+
+// Device busy interrupt.  Called by Int 16h when no key available
+static void
+handle_1590(struct bregs *regs)
+{
+}
+
+// Interrupt complete.  Called by Int 16h when key becomes available
+static void
+handle_1591(struct bregs *regs)
+{
+}
+
+// keyboard intercept
+static void
+handle_154f(struct bregs *regs)
+{
+    set_invalid_silent(regs);
+}
+
+static void
+handle_15c0(struct bregs *regs)
+{
+    regs->es = SEG_BIOS;
+    regs->bx = (u32)&BIOS_CONFIG_TABLE;
+    set_code_success(regs);
+}
+
+static void
+handle_15c1(struct bregs *regs)
+{
+    regs->es = get_ebda_seg();
+    set_success(regs);
+}
+
+static void
+handle_15e801(struct bregs *regs)
+{
+    // my real system sets ax and bx to 0
+    // this is confirmed by Ralph Brown list
+    // but syslinux v1.48 is known to behave
+    // strangely if ax is set to 0
+    // regs.u.r16.ax = 0;
+    // regs.u.r16.bx = 0;
+
+    u32 rs = GET_GLOBAL(RamSize);
+
+    // Get the amount of extended memory (above 1M)
+    if (rs > 16*1024*1024) {
+        // limit to 15M
+        regs->cx = 15*1024;
+        // Get the amount of extended memory above 16M in 64k blocks
+        regs->dx = (rs - 16*1024*1024) / (64*1024);
+    } else {
+        regs->cx = (rs - 1*1024*1024) / 1024;
+        regs->dx = 0;
+    }
+
+    // Set configured memory equal to extended memory
+    regs->ax = regs->cx;
+    regs->bx = regs->dx;
+
+    set_success(regs);
+}
+
+// Info on e820 map location and size.
+struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
+int e820_count VAR16VISIBLE;
+
+static void
+handle_15e820(struct bregs *regs)
+{
+    int count = GET_GLOBAL(e820_count);
+    if (regs->edx != 0x534D4150 || regs->bx >= count
+        || regs->ecx < sizeof(e820_list[0])) {
+        set_code_invalid(regs, RET_EUNSUPPORTED);
+        return;
+    }
+
+    memcpy_far(regs->es, (void*)(regs->di+0)
+               , get_global_seg(), &e820_list[regs->bx]
+               , sizeof(e820_list[0]));
+    if (regs->bx == count-1)
+        regs->ebx = 0;
+    else
+        regs->ebx++;
+    regs->eax = 0x534D4150;
+    regs->ecx = sizeof(e820_list[0]);
+    set_success(regs);
+}
+
+static void
+handle_15e8XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_15e8(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x01: handle_15e801(regs); break;
+    case 0x20: handle_15e820(regs); break;
+    default:   handle_15e8XX(regs); break;
+    }
+}
+
+static void
+handle_15XX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+// INT 15h System Services Entry Point
+void VISIBLE16
+handle_15(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_15);
+    switch (regs->ah) {
+    case 0x24: handle_1524(regs); break;
+    case 0x4f: handle_154f(regs); break;
+    case 0x52: handle_1552(regs); break;
+    case 0x53: handle_1553(regs); break;
+    case 0x5f: handle_155f(regs); break;
+    case 0x83: handle_1583(regs); break;
+    case 0x86: handle_1586(regs); break;
+    case 0x87: handle_1587(regs); break;
+    case 0x88: handle_1588(regs); break;
+    case 0x89: handle_1589(regs); break;
+    case 0x90: handle_1590(regs); break;
+    case 0x91: handle_1591(regs); break;
+    case 0xc0: handle_15c0(regs); break;
+    case 0xc1: handle_15c1(regs); break;
+    case 0xc2: handle_15c2(regs); break;
+    case 0xe8: handle_15e8(regs); break;
+    default:   handle_15XX(regs); break;
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/types.h b/qemu-0.15.x/roms/seabios/src/types.h
new file mode 100644
index 0000000..c0c6d26
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/types.h
@@ -0,0 +1,142 @@
+// Basic type definitions for X86 cpus.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __TYPES_H
+#define __TYPES_H
+
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+typedef unsigned long long u64;
+typedef signed long long s64;
+typedef u32 size_t;
+
+union u64_u32_u {
+    struct { u32 hi, lo; };
+    u64 val;
+};
+
+#ifdef MANUAL_NO_JUMP_TABLE
+# define default case 775324556: asm(""); default
+#endif
+
+#ifdef WHOLE_PROGRAM
+# define __VISIBLE __attribute__((externally_visible))
+#else
+# define __VISIBLE
+#endif
+
+#define UNIQSEC __FILE__ "." __stringify(__LINE__)
+
+#define __noreturn __attribute__((noreturn))
+extern void __force_link_error__only_in_32bit_flat(void) __noreturn;
+extern void __force_link_error__only_in_32bit_segmented(void) __noreturn;
+extern void __force_link_error__only_in_16bit(void) __noreturn;
+
+#define __ASM(code) asm(".section .text.asm." UNIQSEC "\n\t" code)
+
+#if MODE16 == 1
+// Notes a function as externally visible in the 16bit code chunk.
+# define VISIBLE16 __VISIBLE
+// Notes a function as externally visible in the 32bit flat code chunk.
+# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline
+// Notes a 32bit flat function that will only be called during init.
+# define VISIBLE32INIT VISIBLE32FLAT
+// Notes a function as externally visible in the 32bit segmented code chunk.
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+// Designate a variable as (only) visible to 16bit code.
+# define VAR16 __section(".data16." UNIQSEC)
+// Designate a variable as visible to 16bit, 32bit, and assembler code.
+# define VAR16VISIBLE VAR16 __VISIBLE
+// Designate a variable as externally visible (in addition to all internal code).
+# define VAR16EXPORT __section(".data16.export." UNIQSEC) __VISIBLE
+// Designate a variable at a specific 16bit address
+# define VAR16FIXED(addr) __aligned(1) __VISIBLE __section(".fixedaddr." __stringify(addr))
+// Designate a variable as (only) visible to 32bit segmented code.
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+// Designate a 32bit variable also available in 16bit "big real" mode.
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+// Designate top-level assembler as 16bit only.
+# define ASM16(code) __ASM(code)
+// Designate top-level assembler as 32bit flat only.
+# define ASM32FLAT(code)
+// Compile time check for a given mode.
+# define ASSERT16() do { } while (0)
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#elif MODESEGMENT == 1
+# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline
+# define VISIBLE32INIT VISIBLE32FLAT
+# define VISIBLE32SEG __VISIBLE
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".data32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+# define ASM16(code)
+# define ASM32FLAT(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() do { } while (0)
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#else
+# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".text.runtime." UNIQSEC) __VISIBLE
+# define VISIBLE32INIT __section(".text.init." UNIQSEC) __VISIBLE
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".data.runtime." UNIQSEC) __VISIBLE
+# define ASM16(code)
+# define ASM32FLAT(code) __ASM(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() do { } while (0)
+#endif
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DIV_ROUND_CLOSEST(x, divisor)({                 \
+            typeof(divisor) __divisor = divisor;        \
+            (((x) + ((__divisor) / 2)) / (__divisor));  \
+        })
+#define ALIGN(x,a)              __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask)    (((x)+(mask))&~(mask))
+#define ALIGN_DOWN(x,a)         ((x) & ~((typeof(x))(a)-1))
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define likely(x)       __builtin_expect(!!(x), 1)
+#define unlikely(x)     __builtin_expect(!!(x), 0)
+
+#define NULL ((void*)0)
+
+#define __weak __attribute__((weak))
+#define __section(S) __attribute__((section(S)))
+
+#define PACKED __attribute__((packed))
+#define __aligned(x) __attribute__((aligned(x)))
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define noinline __attribute__((noinline))
+#define __always_inline inline __attribute__((always_inline))
+#define __malloc __attribute__((__malloc__))
+#define __attribute_const __attribute__((__const__))
+
+#define __stringify_1(x)        #x
+#define __stringify(x)          __stringify_1(x)
+
+#endif // types.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-ehci.c b/qemu-0.15.x/roms/seabios/src/usb-ehci.c
new file mode 100644
index 0000000..f11924a
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-ehci.c
@@ -0,0 +1,761 @@
+// Code for handling EHCI USB controllers.
+//
+// Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-ehci.h" // struct ehci_qh
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+#include "usb-uhci.h" // init_uhci
+#include "usb-ohci.h" // init_ohci
+
+struct companion_s {
+    u16 bdf;
+    u16 type;
+};
+
+struct usb_ehci_s {
+    struct usb_s usb;
+    struct ehci_caps *caps;
+    struct ehci_regs *regs;
+    struct ehci_qh *async_qh;
+    struct companion_s companion[8];
+    int checkports;
+    int legacycount;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+#define EHCI_TIME_POSTPOWER 20
+#define EHCI_TIME_POSTRESET 2
+
+// Check if need companion controllers for full/low speed devices
+static void
+ehci_note_port(struct usb_ehci_s *cntl)
+{
+    if (--cntl->checkports)
+        // Ports still being detected.
+        return;
+    if (! cntl->legacycount)
+        // No full/low speed devices found.
+        return;
+    // Start companion controllers.
+    int i;
+    for (i=0; i<ARRAY_SIZE(cntl->companion); i++) {
+        u16 type = cntl->companion[i].type;
+        if (type == USB_TYPE_UHCI)
+            uhci_init(cntl->companion[i].bdf, cntl->usb.busid + i);
+        else if (type == USB_TYPE_OHCI)
+            ohci_init(cntl->companion[i].bdf, cntl->usb.busid + i);
+        else
+            return;
+    }
+}
+
+// Check if device attached to port
+static int
+ehci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+    u32 *portreg = &cntl->regs->portsc[port];
+    u32 portsc = readl(portreg);
+
+    // Power up port.
+    if (!(portsc & PORT_POWER)) {
+        portsc |= PORT_POWER;
+        writel(portreg, portsc);
+        msleep(EHCI_TIME_POSTPOWER);
+    } else {
+        msleep(1); // XXX - time for connect to be detected.
+    }
+    portsc = readl(portreg);
+
+    if (!(portsc & PORT_CONNECT))
+        // No device present
+        goto doneearly;
+
+    if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
+        // low speed device
+        cntl->legacycount++;
+        writel(portreg, portsc | PORT_OWNER);
+        goto doneearly;
+    }
+
+    // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+    // Begin reset on port
+    portsc = (portsc & ~PORT_PE) | PORT_RESET;
+    writel(portreg, portsc);
+    msleep(USB_TIME_DRSTR);
+    return 0;
+
+doneearly:
+    ehci_note_port(cntl);
+    return -1;
+}
+
+// Reset device on port
+static int
+ehci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+    u32 *portreg = &cntl->regs->portsc[port];
+    u32 portsc = readl(portreg);
+
+    // Finish reset on port
+    portsc &= ~PORT_RESET;
+    writel(portreg, portsc);
+    msleep(EHCI_TIME_POSTRESET);
+
+    int rv = -1;
+    portsc = readl(portreg);
+    if (!(portsc & PORT_CONNECT))
+        // No longer connected
+        goto resetfail;
+    if (!(portsc & PORT_PE)) {
+        // full speed device
+        cntl->legacycount++;
+        writel(portreg, portsc | PORT_OWNER);
+        goto resetfail;
+    }
+
+    rv = USB_HIGHSPEED;
+resetfail:
+    ehci_note_port(cntl);
+    return rv;
+}
+
+// Disable port
+static void
+ehci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+    u32 *portreg = &cntl->regs->portsc[port];
+    u32 portsc = readl(portreg);
+    writel(portreg, portsc & ~PORT_PE);
+}
+
+static struct usbhub_op_s ehci_HubOp = {
+    .detect = ehci_hub_detect,
+    .reset = ehci_hub_reset,
+    .disconnect = ehci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ehci_ports(struct usb_ehci_s *cntl)
+{
+    ASSERT32FLAT();
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.cntl = &cntl->usb;
+    hub.portcount = cntl->checkports;
+    hub.op = &ehci_HubOp;
+    usb_enumerate(&hub);
+    return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+configure_ehci(void *data)
+{
+    struct usb_ehci_s *cntl = data;
+
+    // Allocate ram for schedule storage
+    struct ehci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+    struct ehci_qh *intr_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*intr_qh));
+    struct ehci_qh *async_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*async_qh));
+    if (!fl || !intr_qh || !async_qh) {
+        warn_noalloc();
+        goto fail;
+    }
+
+    // XXX - check for halted?
+
+    // Reset the HC
+    u32 cmd = readl(&cntl->regs->usbcmd);
+    writel(&cntl->regs->usbcmd, (cmd & ~(CMD_ASE | CMD_PSE)) | CMD_HCRESET);
+    u64 end = calc_future_tsc(250);
+    for (;;) {
+        cmd = readl(&cntl->regs->usbcmd);
+        if (!(cmd & CMD_HCRESET))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            goto fail;
+        }
+        yield();
+    }
+
+    // Disable interrupts (just to be safe).
+    writel(&cntl->regs->usbintr, 0);
+
+    // Set schedule to point to primary intr queue head
+    memset(intr_qh, 0, sizeof(*intr_qh));
+    intr_qh->next = EHCI_PTR_TERM;
+    intr_qh->info2 = (0x01 << QH_SMASK_SHIFT);
+    intr_qh->token = QTD_STS_HALT;
+    intr_qh->qtd_next = intr_qh->alt_next = EHCI_PTR_TERM;
+    int i;
+    for (i=0; i<ARRAY_SIZE(fl->links); i++)
+        fl->links[i] = (u32)intr_qh | EHCI_PTR_QH;
+    writel(&cntl->regs->periodiclistbase, (u32)fl);
+
+    // Set async list to point to primary async queue head
+    memset(async_qh, 0, sizeof(*async_qh));
+    async_qh->next = (u32)async_qh | EHCI_PTR_QH;
+    async_qh->info1 = QH_HEAD;
+    async_qh->token = QTD_STS_HALT;
+    async_qh->qtd_next = async_qh->alt_next = EHCI_PTR_TERM;
+    cntl->async_qh = async_qh;
+    writel(&cntl->regs->asynclistbase, (u32)async_qh);
+
+    // Enable queues
+    writel(&cntl->regs->usbcmd, cmd | CMD_ASE | CMD_PSE | CMD_RUN);
+
+    // Set default of high speed for root hub.
+    writel(&cntl->regs->configflag, 1);
+    cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
+
+    // Find devices
+    int count = check_ehci_ports(cntl);
+    free_pipe(cntl->usb.defaultpipe);
+    if (count)
+        // Success
+        return;
+
+    // No devices found - shutdown and free controller.
+    writel(&cntl->regs->usbcmd, cmd & ~CMD_RUN);
+    msleep(4);  // 2ms to stop reading memory - XXX
+fail:
+    free(fl);
+    free(intr_qh);
+    free(async_qh);
+    free(cntl);
+}
+
+int
+ehci_init(u16 bdf, int busid, int compbdf)
+{
+    if (! CONFIG_USB_EHCI)
+        return -1;
+
+    u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+    struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+    u32 hcc_params = readl(&caps->hccparams);
+    if (hcc_params & HCC_64BIT_ADDR) {
+        dprintf(1, "No support for 64bit EHCI\n");
+        return -1;
+    }
+
+    struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    cntl->usb.bdf = bdf;
+    cntl->usb.type = USB_TYPE_EHCI;
+    cntl->caps = caps;
+    cntl->regs = (void*)caps + readb(&caps->caplength);
+
+    dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+            , pci_bdf_to_fn(bdf), cntl->regs);
+
+    pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+    // XXX - check for and disable SMM control?
+
+    // Find companion controllers.
+    int count = 0;
+    int max = pci_to_bdf(pci_bdf_to_bus(bdf) + 1, 0, 0);
+    for (;;) {
+        if (compbdf < 0 || compbdf >= bdf)
+            break;
+        u32 code = pci_config_readl(compbdf, PCI_CLASS_REVISION) >> 8;
+        if (code == PCI_CLASS_SERIAL_USB_UHCI) {
+            cntl->companion[count].bdf = compbdf;
+            cntl->companion[count].type = USB_TYPE_UHCI;
+            count++;
+        } else if (code == PCI_CLASS_SERIAL_USB_OHCI) {
+            cntl->companion[count].bdf = compbdf;
+            cntl->companion[count].type = USB_TYPE_OHCI;
+            count++;
+        }
+        compbdf = pci_next(compbdf+1, &max);
+    }
+
+    run_thread(configure_ehci, cntl);
+    return 0;
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (qh->qtd_next & EHCI_PTR_TERM)
+            // XXX - confirm
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for next USB async frame to start - for ensuring safe memory release.
+static void
+ehci_waittick(struct usb_ehci_s *cntl)
+{
+    if (MODE16) {
+        msleep(10);
+        return;
+    }
+    // Wait for access to "doorbell"
+    barrier();
+    u32 cmd, sts;
+    u64 end = calc_future_tsc(100);
+    for (;;) {
+        sts = readl(&cntl->regs->usbsts);
+        if (!(sts & STS_IAA)) {
+            cmd = readl(&cntl->regs->usbcmd);
+            if (!(cmd & CMD_IAAD))
+                break;
+        }
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+    // Ring "doorbell"
+    writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
+    // Wait for completion
+    for (;;) {
+        sts = readl(&cntl->regs->usbsts);
+        if (sts & STS_IAA)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+    // Ack completion
+    writel(&cntl->regs->usbsts, STS_IAA);
+}
+
+struct ehci_pipe {
+    struct ehci_qh qh;
+    struct ehci_qtd *next_td, *tds;
+    void *data;
+    struct usb_pipe pipe;
+};
+
+void
+ehci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_EHCI)
+        return;
+    dprintf(7, "ehci_free_pipe %p\n", p);
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    struct usb_ehci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+    struct ehci_qh *start = cntl->async_qh;
+    struct ehci_qh *pos = start;
+    for (;;) {
+        struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS);
+        if (next == start) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        if (next == &pipe->qh) {
+            pos->next = next->next;
+            ehci_waittick(cntl);
+            free(pipe);
+            return;
+        }
+        pos = next;
+    }
+}
+
+struct usb_pipe *
+ehci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ehci_pipe *pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+    pipe->qh.token = QTD_STS_HALT;
+
+    // Add queue head to controller list.
+    struct ehci_qh *async_qh = cntl->async_qh;
+    pipe->qh.next = async_qh->next;
+    barrier();
+    async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+    return &pipe->pipe;
+}
+
+static int
+fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
+{
+    u32 dest = (u32)buf;
+    u32 *pos = td->buf;
+    while (bytes) {
+        if (pos >= &td->buf[ARRAY_SIZE(td->buf)])
+            // More data than can transfer in a single qtd - only use
+            // full packets to prevent a babble error.
+            return ALIGN_DOWN(dest - (u32)buf, maxpacket);
+        u32 count = bytes;
+        u32 max = 0x1000 - (dest & 0xfff);
+        if (count > max)
+            count = max;
+        *pos = dest;
+        bytes -= count;
+        dest += count;
+        pos++;
+    }
+    return dest - (u32)buf;
+}
+
+int
+ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB_EHCI)
+        return -1;
+    dprintf(5, "ehci_control %p\n", p);
+    if (datasize > 4*4096 || cmdsize > 4*4096) {
+        // XXX - should support larger sizes.
+        warn_noalloc();
+        return -1;
+    }
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    struct usb_ehci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+    u16 maxpacket = pipe->pipe.maxpacket;
+    int speed = pipe->pipe.speed;
+
+    // Setup fields in qh
+    pipe->qh.info1 = (
+        (1 << QH_MULT_SHIFT) | (speed != USB_HIGHSPEED ? QH_CONTROL : 0)
+        | (maxpacket << QH_MAXPACKET_SHIFT)
+        | QH_TOGGLECONTROL
+        | (speed << QH_SPEED_SHIFT)
+        | (pipe->pipe.ep << QH_EP_SHIFT)
+        | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+    pipe->qh.info2 = ((1 << QH_MULT_SHIFT)
+                      | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+                      | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT));
+
+    // Setup transfer descriptors
+    struct ehci_qtd *tds = memalign_tmphigh(EHCI_QTD_ALIGN, sizeof(*tds) * 3);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+    memset(tds, 0, sizeof(*tds) * 3);
+    struct ehci_qtd *td = tds;
+
+    td->qtd_next = (u32)&td[1];
+    td->alt_next = EHCI_PTR_TERM;
+    td->token = (ehci_explen(cmdsize) | QTD_STS_ACTIVE
+                 | QTD_PID_SETUP | ehci_maxerr(3));
+    fillTDbuffer(td, maxpacket, cmd, cmdsize);
+    td++;
+
+    if (datasize) {
+        td->qtd_next = (u32)&td[1];
+        td->alt_next = EHCI_PTR_TERM;
+        td->token = (QTD_TOGGLE | ehci_explen(datasize) | QTD_STS_ACTIVE
+                     | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+        fillTDbuffer(td, maxpacket, data, datasize);
+        td++;
+    }
+
+    td->qtd_next = EHCI_PTR_TERM;
+    td->alt_next = EHCI_PTR_TERM;
+    td->token = (QTD_TOGGLE | QTD_STS_ACTIVE
+                 | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3));
+
+    // Transfer data
+    barrier();
+    pipe->qh.qtd_next = (u32)tds;
+    barrier();
+    pipe->qh.token = 0;
+    int ret = ehci_wait_qh(cntl, &pipe->qh);
+    pipe->qh.token = QTD_STS_HALT;
+    if (ret) {
+        pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+        // XXX - halt qh?
+        ehci_waittick(cntl);
+    }
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+ehci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    // XXX - this func is same as alloc_control except for malloc_low
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+    pipe->qh.token = QTD_STS_HALT;
+
+    // Add queue head to controller list.
+    struct ehci_qh *async_qh = cntl->async_qh;
+    pipe->qh.next = async_qh->next;
+    barrier();
+    async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+    return &pipe->pipe;
+}
+
+static int
+ehci_wait_td(struct ehci_qtd *td)
+{
+    u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+    u32 status;
+    for (;;) {
+        status = td->token;
+        if (!(status & QTD_STS_ACTIVE))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+    if (status & QTD_STS_HALT) {
+        dprintf(1, "ehci_wait_td error - status=%x\n", status);
+        return -2;
+    }
+    return 0;
+}
+
+#define STACKQTDS 4
+
+int
+ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+    if (! CONFIG_USB_EHCI)
+        return -1;
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
+            , &pipe->qh, dir, data, datasize);
+
+    // Allocate 4 tds on stack (16byte aligned)
+    u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
+    struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
+    memset(tds, 0, sizeof(*tds) * STACKQTDS);
+
+    // Setup fields in qh
+    u16 maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    SET_FLATPTR(pipe->qh.info1
+                , ((1 << QH_MULT_SHIFT)
+                   | (maxpacket << QH_MAXPACKET_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.speed) << QH_SPEED_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.ep) << QH_EP_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.devaddr) << QH_DEVADDR_SHIFT)));
+    SET_FLATPTR(pipe->qh.info2
+                , ((1 << QH_MULT_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.tt_port) << QH_HUBPORT_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT)));
+    barrier();
+    SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+    barrier();
+    SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE);
+
+    int tdpos = 0;
+    while (datasize) {
+        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+        int ret = ehci_wait_td(td);
+        if (ret)
+            goto fail;
+
+        struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+                                                 , &tds[tdpos % STACKQTDS]);
+
+        int transfer = fillTDbuffer(td, maxpacket, data, datasize);
+        td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl);
+        td->alt_next = EHCI_PTR_TERM;
+        barrier();
+        td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE
+                     | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+
+        data += transfer;
+        datasize -= transfer;
+    }
+    int i;
+    for (i=0; i<STACKQTDS; i++) {
+        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+        int ret = ehci_wait_td(td);
+        if (ret)
+            goto fail;
+    }
+
+    return 0;
+fail:
+    dprintf(1, "ehci_send_bulk failed\n");
+    SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM);
+    SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM);
+    // XXX - halt qh?
+    struct usb_ehci_s *cntl = container_of(
+        GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb);
+    ehci_waittick(cntl);
+    return -1;
+}
+
+struct usb_pipe *
+ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 10)
+        frameexp = 10;
+    int maxpacket = dummy->maxpacket;
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
+    struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+    struct ehci_qtd *tds = memalign_low(EHCI_QTD_ALIGN, sizeof(*tds) * count);
+    void *data = malloc_low(maxpacket * count);
+    if (!pipe || !tds || !data) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->next_td = pipe->tds = tds;
+    pipe->data = data;
+
+    pipe->qh.info1 = (
+        (1 << QH_MULT_SHIFT)
+        | (maxpacket << QH_MAXPACKET_SHIFT)
+        | (pipe->pipe.speed << QH_SPEED_SHIFT)
+        | (pipe->pipe.ep << QH_EP_SHIFT)
+        | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+    pipe->qh.info2 = ((1 << QH_MULT_SHIFT)
+                      | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+                      | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT)
+                      | (0x01 << QH_SMASK_SHIFT)
+                      | (0x1c << QH_CMASK_SHIFT));
+    pipe->qh.qtd_next = (u32)tds;
+
+    int i;
+    for (i=0; i<count; i++) {
+        struct ehci_qtd *td = &tds[i];
+        td->qtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]);
+        td->alt_next = EHCI_PTR_TERM;
+        td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+                     | QTD_PID_IN | ehci_maxerr(3));
+        td->buf[0] = (u32)data + maxpacket * i;
+    }
+
+    // Add to interrupt schedule.
+    struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase);
+    if (frameexp == 0) {
+        // Add to existing interrupt entry.
+        struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS);
+        pipe->qh.next = intr_qh->next;
+        barrier();
+        intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+    } else {
+        int startpos = 1<<(frameexp-1);
+        pipe->qh.next = fl->links[startpos];
+        barrier();
+        for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+            fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH;
+    }
+
+    return &pipe->pipe;
+fail:
+    free(pipe);
+    free(tds);
+    free(data);
+    return NULL;
+}
+
+int
+ehci_poll_intr(struct usb_pipe *p, void *data)
+{
+    ASSERT16();
+    if (! CONFIG_USB_EHCI)
+        return -1;
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    struct ehci_qtd *td = GET_FLATPTR(pipe->next_td);
+    u32 token = GET_FLATPTR(td->token);
+    if (token & QTD_STS_ACTIVE)
+        // No intrs found.
+        return -1;
+    // XXX - check for errors.
+
+    // Copy data.
+    int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    int pos = td - GET_FLATPTR(pipe->tds);
+    void *tddata = GET_FLATPTR(pipe->data) + maxpacket * pos;
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+               , maxpacket);
+
+    // Reenable this td.
+    struct ehci_qtd *next = (void*)(GET_FLATPTR(td->qtd_next) & ~EHCI_PTR_BITS);
+    SET_FLATPTR(pipe->next_td, next);
+    SET_FLATPTR(td->buf[0], (u32)tddata);
+    barrier();
+    SET_FLATPTR(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+                            | QTD_PID_IN | ehci_maxerr(3)));
+
+    return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-ehci.h b/qemu-0.15.x/roms/seabios/src/usb-ehci.h
new file mode 100644
index 0000000..bb8df52
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-ehci.h
@@ -0,0 +1,173 @@
+#ifndef __USB_EHCI_H
+#define __USB_EHCI_H
+
+// usb-ehci.c
+int ehci_init(u16 bdf, int busid, int compbdf);
+struct usb_pipe;
+void ehci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ehci_alloc_control_pipe(struct usb_pipe *dummy);
+int ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *ehci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int ehci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ehci structs and flags
+ ****************************************************************/
+
+struct ehci_caps {
+    u8 caplength;
+    u8 reserved_01;
+    u16 hciversion;
+    u32 hcsparams;
+    u32 hccparams;
+    u64 portroute;
+} PACKED;
+
+#define HCC_64BIT_ADDR 1
+
+#define HCS_N_PORTS_MASK 0xf
+
+struct ehci_regs {
+    u32 usbcmd;
+    u32 usbsts;
+    u32 usbintr;
+    u32 frindex;
+    u32 ctrldssegment;
+    u32 periodiclistbase;
+    u32 asynclistbase;
+    u32 reserved[9];
+    u32 configflag;
+    u32 portsc[0];
+} PACKED;
+
+#define CMD_PARK        (1<<11)
+#define CMD_PARK_CNT(c) (((c)>>8)&3)
+#define CMD_LRESET      (1<<7)
+#define CMD_IAAD        (1<<6)
+#define CMD_ASE         (1<<5)
+#define CMD_PSE         (1<<4)
+#define CMD_HCRESET     (1<<1)
+#define CMD_RUN         (1<<0)
+
+#define STS_ASS         (1<<15)
+#define STS_PSS         (1<<14)
+#define STS_RECL        (1<<13)
+#define STS_HALT        (1<<12)
+#define STS_IAA         (1<<5)
+#define STS_FATAL       (1<<4)
+#define STS_FLR         (1<<3)
+#define STS_PCD         (1<<2)
+#define STS_ERR         (1<<1)
+#define STS_INT         (1<<0)
+
+#define FLAG_CF         (1<<0)
+
+#define PORT_WKOC_E     (1<<22)
+#define PORT_WKDISC_E   (1<<21)
+#define PORT_WKCONN_E   (1<<20)
+#define PORT_TEST_PKT   (0x4<<16)
+#define PORT_LED_OFF    (0<<14)
+#define PORT_LED_AMBER  (1<<14)
+#define PORT_LED_GREEN  (2<<14)
+#define PORT_LED_MASK   (3<<14)
+#define PORT_OWNER      (1<<13)
+#define PORT_POWER      (1<<12)
+#define PORT_LINESTATUS_MASK   (3<<10)
+#define PORT_LINESTATUS_KSTATE (1<<10)
+#define PORT_RESET      (1<<8)
+#define PORT_SUSPEND    (1<<7)
+#define PORT_RESUME     (1<<6)
+#define PORT_OCC        (1<<5)
+#define PORT_OC         (1<<4)
+#define PORT_PEC        (1<<3)
+#define PORT_PE         (1<<2)
+#define PORT_CSC        (1<<1)
+#define PORT_CONNECT    (1<<0)
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
+
+
+#define EHCI_QH_ALIGN 64 // Can't span a 4K boundary, so increase to 64
+
+struct ehci_qh {
+    u32 next;
+    u32 info1;
+    u32 info2;
+    u32 current;
+
+    u32 qtd_next;
+    u32 alt_next;
+    u32 token;
+    u32 buf[5];
+    // u32 buf_hi[5];
+} PACKED;
+
+#define QH_CONTROL       (1 << 27)
+#define QH_MAXPACKET_SHIFT 16
+#define QH_MAXPACKET_MASK  (0x7ff << QH_MAXPACKET_SHIFT)
+#define QH_HEAD          (1 << 15)
+#define QH_TOGGLECONTROL (1 << 14)
+#define QH_SPEED_SHIFT   12
+#define QH_SPEED_MASK    (0x3 << QH_SPEED_SHIFT)
+#define QH_EP_SHIFT      8
+#define QH_EP_MASK       (0xf << QH_EP_SHIFT)
+#define QH_DEVADDR_SHIFT 0
+#define QH_DEVADDR_MASK  (0x7f << QH_DEVADDR_SHIFT)
+
+#define QH_SMASK_SHIFT   0
+#define QH_SMASK_MASK    (0xff << QH_SMASK_SHIFT)
+#define QH_CMASK_SHIFT   8
+#define QH_CMASK_MASK    (0xff << QH_CMASK_SHIFT)
+#define QH_HUBADDR_SHIFT 16
+#define QH_HUBADDR_MASK  (0x7f << QH_HUBADDR_SHIFT)
+#define QH_HUBPORT_SHIFT 23
+#define QH_HUBPORT_MASK  (0x7f << QH_HUBPORT_SHIFT)
+#define QH_MULT_SHIFT    30
+#define QH_MULT_MASK     (0x3 << QH_MULT_SHIFT)
+
+#define EHCI_PTR_BITS           0x001F
+#define EHCI_PTR_TERM           0x0001
+#define EHCI_PTR_QH             0x0002
+
+
+#define EHCI_QTD_ALIGN 32
+
+struct ehci_qtd {
+    u32 qtd_next;
+    u32 alt_next;
+    u32 token;
+    u32 buf[5];
+    //u32 buf_hi[5];
+} PACKED;
+
+#define QTD_TOGGLE      (1 << 31)
+#define QTD_LENGTH_SHIFT 16
+#define QTD_LENGTH_MASK (0x7fff << QTD_LENGTH_SHIFT)
+#define QTD_CERR_SHIFT  10
+#define QTD_CERR_MASK   (0x3 << QTD_CERR_SHIFT)
+#define QTD_IOC         (1 << 15)
+#define QTD_PID_OUT     (0x0 << 8)
+#define QTD_PID_IN      (0x1 << 8)
+#define QTD_PID_SETUP   (0x2 << 8)
+#define QTD_STS_ACTIVE  (1 << 7)
+#define QTD_STS_HALT    (1 << 6)
+#define QTD_STS_DBE     (1 << 5)
+#define QTD_STS_BABBLE  (1 << 4)
+#define QTD_STS_XACT    (1 << 3)
+#define QTD_STS_MMF     (1 << 2)
+#define QTD_STS_STS     (1 << 1)
+#define QTD_STS_PING    (1 << 0)
+
+#define ehci_explen(len) (((len) << QTD_LENGTH_SHIFT) & QTD_LENGTH_MASK)
+
+#define ehci_maxerr(err) (((err) << QTD_CERR_SHIFT) & QTD_CERR_MASK)
+
+
+struct ehci_framelist {
+    u32 links[1024];
+} PACKED;
+
+#endif // usb-ehci.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-hid.c b/qemu-0.15.x/roms/seabios/src/usb-hid.c
new file mode 100644
index 0000000..168b7fa
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-hid.c
@@ -0,0 +1,418 @@
+// Code for handling USB Human Interface Devices (HID).
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "usb-hid.h" // usb_keyboard_setup
+#include "config.h" // CONFIG_*
+#include "usb.h" // usb_ctrlrequest
+#include "biosvar.h" // GET_GLOBAL
+#include "ps2port.h" // ATKBD_CMD_GETID
+
+struct usb_pipe *keyboard_pipe VAR16VISIBLE;
+struct usb_pipe *mouse_pipe VAR16VISIBLE;
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Send USB HID protocol message.
+static int
+set_protocol(struct usb_pipe *pipe, u16 val)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+    req.bRequest = HID_REQ_SET_PROTOCOL;
+    req.wValue = val;
+    req.wIndex = 0;
+    req.wLength = 0;
+    return send_default_control(pipe, &req, NULL);
+}
+
+// Send USB HID SetIdle request.
+static int
+set_idle(struct usb_pipe *pipe, int ms)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+    req.bRequest = HID_REQ_SET_IDLE;
+    req.wValue = (ms/4)<<8;
+    req.wIndex = 0;
+    req.wLength = 0;
+    return send_default_control(pipe, &req, NULL);
+}
+
+#define KEYREPEATWAITMS 500
+#define KEYREPEATMS 33
+
+static int
+usb_kbd_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    if (! CONFIG_USB_KEYBOARD)
+        return -1;
+    if (keyboard_pipe)
+        // XXX - this enables the first found keyboard (could be random)
+        return -1;
+
+    if (epdesc->wMaxPacketSize != 8)
+        return -1;
+
+    // Enable "boot" protocol.
+    int ret = set_protocol(pipe, 0);
+    if (ret)
+        return -1;
+    // Periodically send reports to enable key repeat.
+    ret = set_idle(pipe, KEYREPEATMS);
+    if (ret)
+        return -1;
+
+    keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
+    if (!keyboard_pipe)
+        return -1;
+
+    dprintf(1, "USB keyboard initialized\n");
+    return 0;
+}
+
+static int
+usb_mouse_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    if (! CONFIG_USB_MOUSE)
+        return -1;
+    if (mouse_pipe)
+        // XXX - this enables the first found mouse (could be random)
+        return -1;
+
+    if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
+        return -1;
+
+    // Enable "boot" protocol.
+    int ret = set_protocol(pipe, 0);
+    if (ret)
+        return -1;
+
+    mouse_pipe = alloc_intr_pipe(pipe, epdesc);
+    if (!mouse_pipe)
+        return -1;
+
+    dprintf(1, "USB mouse initialized\n");
+    return 0;
+}
+
+// Initialize a found USB HID device (if applicable).
+int
+usb_hid_init(struct usb_pipe *pipe
+             , struct usb_interface_descriptor *iface, int imax)
+{
+    if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
+        return -1;
+    dprintf(2, "usb_hid_init %p\n", pipe);
+
+    if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
+        // Doesn't support boot protocol.
+        return -1;
+
+    // Find intr in endpoint.
+    struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
+        iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
+    if (!epdesc) {
+        dprintf(1, "No usb hid intr in?\n");
+        return -1;
+    }
+
+    if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
+        return usb_kbd_init(pipe, epdesc);
+    if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+        return usb_mouse_init(pipe, epdesc);
+    return -1;
+}
+
+
+/****************************************************************
+ * Keyboard events
+ ****************************************************************/
+
+// Mapping from USB key id to ps2 key sequence.
+static u16 KeyToScanCode[] VAR16 = {
+    0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
+    0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
+    0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
+    0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
+    0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
+    0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
+    0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
+    0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+    0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
+    0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
+    0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
+    0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
+    0x0048, 0x0049, 0x0052, 0x0053
+};
+
+// Mapping from USB modifier id to ps2 key sequence.
+static u16 ModifierToScanCode[] VAR16 = {
+    //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
+    0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
+};
+
+#define RELEASEBIT 0x80
+
+// Format of USB keyboard event data
+struct keyevent {
+    u8 modifiers;
+    u8 reserved;
+    u8 keys[6];
+};
+
+// Translate data from KeyToScanCode[] to calls to process_key().
+static void
+prockeys(u16 keys)
+{
+    if (keys > 0xff) {
+        u8 key = keys>>8;
+        if (key == 0xe1) {
+            // Pause key
+            process_key(0xe1);
+            process_key(0x1d | (keys & RELEASEBIT));
+            process_key(0x45 | (keys & RELEASEBIT));
+            return;
+        }
+        process_key(key);
+    }
+    process_key(keys);
+}
+
+// Handle a USB key press/release event.
+static void
+procscankey(u8 key, u8 flags)
+{
+    if (key >= ARRAY_SIZE(KeyToScanCode))
+        return;
+    u16 keys = GET_GLOBAL(KeyToScanCode[key]);
+    if (keys)
+        prockeys(keys | flags);
+}
+
+// Handle a USB modifier press/release event.
+static void
+procmodkey(u8 mods, u8 flags)
+{
+    int i;
+    for (i=0; mods; i++)
+        if (mods & (1<<i)) {
+            // Modifier key change.
+            prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
+            mods &= ~(1<<i);
+        }
+}
+
+// Process USB keyboard data.
+static void noinline
+handle_key(struct keyevent *data)
+{
+    dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
+
+    // Load old keys.
+    u16 ebda_seg = get_ebda_seg();
+    struct usbkeyinfo old;
+    old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
+
+    // Check for keys no longer pressed.
+    int addpos = 0;
+    int i;
+    for (i=0; i<ARRAY_SIZE(old.keys); i++) {
+        u8 key = old.keys[i];
+        if (!key)
+            break;
+        int j;
+        for (j=0;; j++) {
+            if (j>=ARRAY_SIZE(data->keys)) {
+                // Key released.
+                procscankey(key, RELEASEBIT);
+                if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
+                    // Last pressed key released - disable repeat.
+                    old.repeatcount = 0xff;
+                break;
+            }
+            if (data->keys[j] == key) {
+                // Key still pressed.
+                data->keys[j] = 0;
+                old.keys[addpos++] = key;
+                break;
+            }
+        }
+    }
+    procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
+
+    // Process new keys
+    procmodkey(data->modifiers & ~old.modifiers, 0);
+    old.modifiers = data->modifiers;
+    for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+        u8 key = data->keys[i];
+        if (!key)
+            continue;
+        // New key pressed.
+        procscankey(key, 0);
+        old.keys[addpos++] = key;
+        old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
+    }
+    if (addpos < ARRAY_SIZE(old.keys))
+        old.keys[addpos] = 0;
+
+    // Check for key repeat event.
+    if (addpos) {
+        if (!old.repeatcount)
+            procscankey(old.keys[addpos-1], 0);
+        else if (old.repeatcount != 0xff)
+            old.repeatcount--;
+    }
+
+    // Update old keys
+    SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
+}
+
+// Check if a USB keyboard event is pending and process it if so.
+static void
+usb_check_key(void)
+{
+    if (! CONFIG_USB_KEYBOARD)
+        return;
+    struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
+    if (!pipe)
+        return;
+
+    for (;;) {
+        struct keyevent data;
+        int ret = usb_poll_intr(pipe, &data);
+        if (ret)
+            break;
+        handle_key(&data);
+    }
+}
+
+// Test if USB keyboard is active.
+inline int
+usb_kbd_active(void)
+{
+    if (! CONFIG_USB_KEYBOARD)
+        return 0;
+    return GET_GLOBAL(keyboard_pipe) != NULL;
+}
+
+// Handle a ps2 style keyboard command.
+inline int
+usb_kbd_command(int command, u8 *param)
+{
+    if (! CONFIG_USB_KEYBOARD)
+        return -1;
+    dprintf(9, "usb keyboard cmd=%x\n", command);
+    switch (command) {
+    case ATKBD_CMD_GETID:
+        // Return the id of a standard AT keyboard.
+        param[0] = 0xab;
+        param[1] = 0x83;
+        return 0;
+    default:
+        return -1;
+    }
+}
+
+
+/****************************************************************
+ * Mouse events
+ ****************************************************************/
+
+// Format of USB mouse event data
+struct mouseevent {
+    u8 buttons;
+    u8 x, y;
+    u8 reserved[5];
+};
+
+// Process USB mouse data.
+static void
+handle_mouse(struct mouseevent *data)
+{
+    dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
+
+    s8 x = data->x, y = -data->y;
+    u8 flag = ((data->buttons & 0x7) | (1<<3)
+               | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
+    process_mouse(flag);
+    process_mouse(x);
+    process_mouse(y);
+}
+
+// Check if a USB mouse event is pending and process it if so.
+static void
+usb_check_mouse(void)
+{
+    if (! CONFIG_USB_MOUSE)
+        return;
+    struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
+    if (!pipe)
+        return;
+
+    for (;;) {
+        struct mouseevent data;
+        int ret = usb_poll_intr(pipe, &data);
+        if (ret)
+            break;
+        handle_mouse(&data);
+    }
+}
+
+// Test if USB mouse is active.
+inline int
+usb_mouse_active(void)
+{
+    if (! CONFIG_USB_MOUSE)
+        return 0;
+    return GET_GLOBAL(mouse_pipe) != NULL;
+}
+
+// Handle a ps2 style mouse command.
+inline int
+usb_mouse_command(int command, u8 *param)
+{
+    if (! CONFIG_USB_MOUSE)
+        return -1;
+    dprintf(9, "usb mouse cmd=%x\n", command);
+    switch (command) {
+    case PSMOUSE_CMD_ENABLE:
+    case PSMOUSE_CMD_DISABLE:
+    case PSMOUSE_CMD_SETSCALE11:
+        return 0;
+    case PSMOUSE_CMD_SETSCALE21:
+    case PSMOUSE_CMD_SETRATE:
+    case PSMOUSE_CMD_SETRES:
+        // XXX
+        return 0;
+    case PSMOUSE_CMD_RESET_BAT:
+    case PSMOUSE_CMD_GETID:
+        // Return the id of a standard AT mouse.
+        param[0] = 0xaa;
+        param[1] = 0x00;
+        return 0;
+
+    case PSMOUSE_CMD_GETINFO:
+        param[0] = 0x00;
+        param[1] = 4;
+        param[2] = 100;
+        return 0;
+
+    default:
+        return -1;
+    }
+}
+
+// Check for USB events pending - called periodically from timer interrupt.
+void
+usb_check_event(void)
+{
+    usb_check_key();
+    usb_check_mouse();
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-hid.h b/qemu-0.15.x/roms/seabios/src/usb-hid.h
new file mode 100644
index 0000000..7fbcf4b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-hid.h
@@ -0,0 +1,31 @@
+#ifndef __USB_HID_H
+#define __USB_HID_H
+
+// usb-hid.c
+struct usb_interface_descriptor;
+struct usb_pipe;
+int usb_hid_init(struct usb_pipe *pipe
+                 , struct usb_interface_descriptor *iface, int imax);
+inline int usb_kbd_active(void);
+inline int usb_kbd_command(int command, u8 *param);
+inline int usb_mouse_active(void);
+inline int usb_mouse_command(int command, u8 *param);
+void usb_check_event(void);
+
+
+/****************************************************************
+ * hid flags
+ ****************************************************************/
+
+#define USB_INTERFACE_SUBCLASS_BOOT     1
+#define USB_INTERFACE_PROTOCOL_KEYBOARD 1
+#define USB_INTERFACE_PROTOCOL_MOUSE    2
+
+#define HID_REQ_GET_REPORT              0x01
+#define HID_REQ_GET_IDLE                0x02
+#define HID_REQ_GET_PROTOCOL            0x03
+#define HID_REQ_SET_REPORT              0x09
+#define HID_REQ_SET_IDLE                0x0A
+#define HID_REQ_SET_PROTOCOL            0x0B
+
+#endif // ush-hid.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-hub.c b/qemu-0.15.x/roms/seabios/src/usb-hub.c
new file mode 100644
index 0000000..b2d9ff2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-hub.c
@@ -0,0 +1,185 @@
+// Code for handling standard USB hubs.
+//
+// Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_USB_HUB
+#include "usb-hub.h" // struct usb_hub_descriptor
+#include "usb.h" // struct usb_s
+
+static int
+get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
+    req.bRequest = USB_REQ_GET_DESCRIPTOR;
+    req.wValue = USB_DT_HUB<<8;
+    req.wIndex = 0;
+    req.wLength = sizeof(*desc);
+    return send_default_control(pipe, &req, desc);
+}
+
+static int
+set_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+    req.bRequest = USB_REQ_SET_FEATURE;
+    req.wValue = feature;
+    req.wIndex = port + 1;
+    req.wLength = 0;
+    mutex_lock(&hub->lock);
+    int ret = send_default_control(hub->pipe, &req, NULL);
+    mutex_unlock(&hub->lock);
+    return ret;
+}
+
+static int
+clear_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+    req.bRequest = USB_REQ_CLEAR_FEATURE;
+    req.wValue = feature;
+    req.wIndex = port + 1;
+    req.wLength = 0;
+    mutex_lock(&hub->lock);
+    int ret = send_default_control(hub->pipe, &req, NULL);
+    mutex_unlock(&hub->lock);
+    return ret;
+}
+
+static int
+get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
+    req.bRequest = USB_REQ_GET_STATUS;
+    req.wValue = 0;
+    req.wIndex = port + 1;
+    req.wLength = sizeof(*sts);
+    mutex_lock(&hub->lock);
+    int ret = send_default_control(hub->pipe, &req, sts);
+    mutex_unlock(&hub->lock);
+    return ret;
+}
+
+// Check if device attached to port
+static int
+usb_hub_detect(struct usbhub_s *hub, u32 port)
+{
+    // Turn on power to port.
+    int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER);
+    if (ret)
+        goto fail;
+
+    // Wait for port power to stabilize.
+    msleep(hub->powerwait);
+
+    // Check periodically for a device connect.
+    struct usb_port_status sts;
+    u64 end = calc_future_tsc(USB_TIME_SIGATT);
+    for (;;) {
+        ret = get_port_status(hub, port, &sts);
+        if (ret)
+            goto fail;
+        if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
+            // Device connected.
+            break;
+        if (check_tsc(end))
+            // No device found.
+            return -1;
+        msleep(5);
+    }
+
+    // XXX - wait USB_TIME_ATTDB time?
+
+    return 0;
+
+fail:
+    dprintf(1, "Failure on hub port %d detect\n", port);
+    return -1;
+}
+
+// Disable port
+static void
+usb_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+    int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
+    if (ret)
+        dprintf(1, "Failure on hub port %d disconnect\n", port);
+}
+
+// Reset device on port
+static int
+usb_hub_reset(struct usbhub_s *hub, u32 port)
+{
+    int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET);
+    if (ret)
+        goto fail;
+
+    // Wait for reset to complete.
+    struct usb_port_status sts;
+    u64 end = calc_future_tsc(USB_TIME_DRST * 2);
+    for (;;) {
+        ret = get_port_status(hub, port, &sts);
+        if (ret)
+            goto fail;
+        if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            goto fail;
+        }
+        msleep(5);
+    }
+
+    // Reset complete.
+    if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
+        // Device no longer present
+        return -1;
+
+    return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK)
+            >> USB_PORT_STAT_SPEED_SHIFT);
+
+fail:
+    dprintf(1, "Failure on hub port %d reset\n", port);
+    usb_hub_disconnect(hub, port);
+    return -1;
+}
+
+static struct usbhub_op_s HubOp = {
+    .detect = usb_hub_detect,
+    .reset = usb_hub_reset,
+    .disconnect = usb_hub_disconnect,
+};
+
+// Configure a usb hub and then find devices connected to it.
+int
+usb_hub_init(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_USB_HUB)
+        return -1;
+
+    struct usb_hub_descriptor desc;
+    int ret = get_hub_desc(pipe, &desc);
+    if (ret)
+        return ret;
+
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.pipe = pipe;
+    hub.cntl = pipe->cntl;
+    hub.powerwait = desc.bPwrOn2PwrGood * 2;
+    hub.portcount = desc.bNbrPorts;
+    hub.op = &HubOp;
+    usb_enumerate(&hub);
+
+    dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);
+    if (hub.devcount)
+        return 0;
+    return -1;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-hub.h b/qemu-0.15.x/roms/seabios/src/usb-hub.h
new file mode 100644
index 0000000..7672028
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-hub.h
@@ -0,0 +1,60 @@
+#ifndef __USB_HUB_H
+#define __USB_HUB_H
+
+// usb-hub.c
+struct usb_pipe;
+int usb_hub_init(struct usb_pipe *pipe);
+
+
+/****************************************************************
+ * hub flags
+ ****************************************************************/
+
+#define USB_DT_HUB                      (USB_TYPE_CLASS | 0x09)
+
+struct usb_hub_descriptor {
+    u8  bDescLength;
+    u8  bDescriptorType;
+    u8  bNbrPorts;
+    u16 wHubCharacteristics;
+    u8  bPwrOn2PwrGood;
+    u8  bHubContrCurrent;
+    // Variable length fields for DeviceRemovable[], PortPwrCtrlMask[] follow.
+} PACKED;
+
+#define USB_PORT_FEAT_CONNECTION        0
+#define USB_PORT_FEAT_ENABLE            1
+#define USB_PORT_FEAT_SUSPEND           2
+#define USB_PORT_FEAT_OVER_CURRENT      3
+#define USB_PORT_FEAT_RESET             4
+#define USB_PORT_FEAT_POWER             8
+#define USB_PORT_FEAT_LOWSPEED          9
+#define USB_PORT_FEAT_C_CONNECTION      16
+#define USB_PORT_FEAT_C_ENABLE          17
+#define USB_PORT_FEAT_C_SUSPEND         18
+#define USB_PORT_FEAT_C_OVER_CURRENT    19
+#define USB_PORT_FEAT_C_RESET           20
+#define USB_PORT_FEAT_TEST              21
+#define USB_PORT_FEAT_INDICATOR         22
+#define USB_PORT_FEAT_C_PORT_L1         23
+
+struct usb_port_status {
+    u16 wPortStatus;
+    u16 wPortChange;
+} PACKED;
+
+#define USB_PORT_STAT_CONNECTION        0x0001
+#define USB_PORT_STAT_ENABLE            0x0002
+#define USB_PORT_STAT_SUSPEND           0x0004
+#define USB_PORT_STAT_OVERCURRENT       0x0008
+#define USB_PORT_STAT_RESET             0x0010
+#define USB_PORT_STAT_L1                0x0020
+#define USB_PORT_STAT_POWER             0x0100
+#define USB_PORT_STAT_SPEED_SHIFT       9
+#define USB_PORT_STAT_SPEED_MASK        (0x3 << USB_PORT_STAT_SPEED_SHIFT)
+#define USB_PORT_STAT_LOW_SPEED         0x0200
+#define USB_PORT_STAT_HIGH_SPEED        0x0400
+#define USB_PORT_STAT_TEST              0x0800
+#define USB_PORT_STAT_INDICATOR         0x1000
+
+#endif // ush-hid.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-msc.c b/qemu-0.15.x/roms/seabios/src/usb-msc.c
new file mode 100644
index 0000000..1aa57d1
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-msc.c
@@ -0,0 +1,260 @@
+// Code for handling USB Mass Storage Controller devices.
+//
+// Copyright (C) 2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_USB_MSC
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+#include "blockcmd.h" // cdb_read
+#include "disk.h" // DTYPE_USB
+#include "boot.h" // boot_add_hd
+
+struct usbdrive_s {
+    struct drive_s drive;
+    struct usb_pipe *bulkin, *bulkout;
+};
+
+
+/****************************************************************
+ * Bulk-only drive command processing
+ ****************************************************************/
+
+#define USB_CDB_SIZE 12
+
+#define CBW_SIGNATURE 0x43425355 // USBC
+
+struct cbw_s {
+    u32 dCBWSignature;
+    u32 dCBWTag;
+    u32 dCBWDataTransferLength;
+    u8 bmCBWFlags;
+    u8 bCBWLUN;
+    u8 bCBWCBLength;
+    u8 CBWCB[16];
+} PACKED;
+
+#define CSW_SIGNATURE 0x53425355 // USBS
+
+struct csw_s {
+    u32 dCSWSignature;
+    u32 dCSWTag;
+    u32 dCSWDataResidue;
+    u8 bCSWStatus;
+} PACKED;
+
+// Low-level usb command transmit function.
+int
+usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+    if (!CONFIG_USB_MSC)
+        return 0;
+
+    dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+            , op->drive_g, 0, op->count, blocksize, op->buf_fl);
+    struct usbdrive_s *udrive_g = container_of(
+        op->drive_g, struct usbdrive_s, drive);
+    struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin);
+    struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout);
+
+    // Setup command block wrapper.
+    u32 bytes = blocksize * op->count;
+    struct cbw_s cbw;
+    memset(&cbw, 0, sizeof(cbw));
+    cbw.dCBWSignature = CBW_SIGNATURE;
+    cbw.dCBWTag = 999; // XXX
+    cbw.dCBWDataTransferLength = bytes;
+    cbw.bmCBWFlags = USB_DIR_IN; // XXX
+    cbw.bCBWLUN = 0; // XXX
+    cbw.bCBWCBLength = USB_CDB_SIZE;
+    memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+
+    // Transfer cbw to device.
+    int ret = usb_send_bulk(bulkout, USB_DIR_OUT
+                            , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
+    if (ret)
+        goto fail;
+
+    // Transfer data from device.
+    ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes);
+    if (ret)
+        goto fail;
+
+    // Transfer csw info.
+    struct csw_s csw;
+    ret = usb_send_bulk(bulkin, USB_DIR_IN
+                        , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw));
+    if (ret)
+        goto fail;
+
+    if (!csw.bCSWStatus)
+        return DISK_RET_SUCCESS;
+    if (csw.bCSWStatus == 2)
+        goto fail;
+
+    op->count -= csw.dCSWDataResidue / blocksize;
+    return DISK_RET_EBADTRACK;
+
+fail:
+    // XXX - reset connection
+    dprintf(1, "USB transmission failed\n");
+    op->count = 0;
+    return DISK_RET_EBADTRACK;
+}
+
+
+/****************************************************************
+ * Drive ops
+ ****************************************************************/
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_usb_op(struct disk_op_s *op)
+{
+    if (!CONFIG_USB_MSC)
+        return 0;
+    switch (op->command) {
+    case CMD_READ:
+        return cdb_read(op);
+    case CMD_FORMAT:
+    case CMD_WRITE:
+        return DISK_RET_EWRITEPROTECT;
+    case CMD_RESET:
+    case CMD_ISREADY:
+    case CMD_VERIFY:
+    case CMD_SEEK:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+setup_drive_cdrom(struct disk_op_s *op, char *desc)
+{
+    op->drive_g->blksize = CDROM_SECTOR_SIZE;
+    op->drive_g->sectors = (u64)-1;
+    struct usb_pipe *pipe = container_of(
+        op->drive_g, struct usbdrive_s, drive)->bulkout;
+    int prio = bootprio_find_usb(pipe->cntl->bdf, pipe->path);
+    boot_add_cd(op->drive_g, desc, prio);
+    return 0;
+}
+
+static int
+setup_drive_hd(struct disk_op_s *op, char *desc)
+{
+    struct cdbres_read_capacity info;
+    int ret = cdb_read_capacity(op, &info);
+    if (ret)
+        return ret;
+    // XXX - retry for some timeout?
+
+    u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+    if (blksize != DISK_SECTOR_SIZE) {
+        if (blksize == CDROM_SECTOR_SIZE)
+            return setup_drive_cdrom(op, desc);
+        dprintf(1, "Unsupported USB MSC block size %d\n", blksize);
+        return -1;
+    }
+    op->drive_g->blksize = blksize;
+    op->drive_g->sectors = sectors;
+    dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors);
+
+    // Register with bcv system.
+    struct usb_pipe *pipe = container_of(
+        op->drive_g, struct usbdrive_s, drive)->bulkout;
+    int prio = bootprio_find_usb(pipe->cntl->bdf, pipe->path);
+    boot_add_hd(op->drive_g, desc, prio);
+
+    return 0;
+}
+
+// Configure a usb msc device.
+int
+usb_msc_init(struct usb_pipe *pipe
+             , struct usb_interface_descriptor *iface, int imax)
+{
+    if (!CONFIG_USB_MSC)
+        return -1;
+
+    // Verify right kind of device
+    if ((iface->bInterfaceSubClass != US_SC_SCSI &&
+	 iface->bInterfaceSubClass != US_SC_ATAPI_8070 &&
+	 iface->bInterfaceSubClass != US_SC_ATAPI_8020)
+        || iface->bInterfaceProtocol != US_PR_BULK) {
+        dprintf(1, "Unsupported MSC USB device (subclass=%02x proto=%02x)\n"
+                , iface->bInterfaceSubClass, iface->bInterfaceProtocol);
+        return -1;
+    }
+
+    // Allocate drive structure.
+    struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g));
+    if (!udrive_g) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(udrive_g, 0, sizeof(*udrive_g));
+    udrive_g->drive.type = DTYPE_USB;
+
+    // Find bulk in and bulk out endpoints.
+    struct usb_endpoint_descriptor *indesc = findEndPointDesc(
+        iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
+    struct usb_endpoint_descriptor *outdesc = findEndPointDesc(
+        iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
+    if (!indesc || !outdesc)
+        goto fail;
+    udrive_g->bulkin = alloc_bulk_pipe(pipe, indesc);
+    udrive_g->bulkout = alloc_bulk_pipe(pipe, outdesc);
+    if (!udrive_g->bulkin || !udrive_g->bulkout)
+        goto fail;
+
+    // Validate drive and find block size and sector count.
+    struct disk_op_s dop;
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = &udrive_g->drive;
+    struct cdbres_inquiry data;
+    int ret = cdb_get_inquiry(&dop, &data);
+    if (ret)
+        goto fail;
+    char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
+    char rev[sizeof(data.rev)+1];
+    strtcpy(vendor, data.vendor, sizeof(vendor));
+    nullTrailingSpace(vendor);
+    strtcpy(product, data.product, sizeof(product));
+    nullTrailingSpace(product);
+    strtcpy(rev, data.rev, sizeof(rev));
+    nullTrailingSpace(rev);
+    int pdt = data.pdt & 0x1f;
+    int removable = !!(data.removable & 0x80);
+    dprintf(1, "USB MSC vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
+            , vendor, product, rev, pdt, removable);
+    udrive_g->drive.removable = removable;
+
+    if (pdt == USB_MSC_TYPE_CDROM) {
+        char *desc = znprintf(MAXDESCSIZE, "DVD/CD [USB Drive %s %s %s]"
+                              , vendor, product, rev);
+        ret = setup_drive_cdrom(&dop, desc);
+    } else {
+        char *desc = znprintf(MAXDESCSIZE, "USB Drive %s %s %s"
+                              , vendor, product, rev);
+        ret = setup_drive_hd(&dop, desc);
+    }
+    if (ret)
+        goto fail;
+
+    return 0;
+fail:
+    dprintf(1, "Unable to configure USB MSC device.\n");
+    free(udrive_g);
+    return -1;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-msc.h b/qemu-0.15.x/roms/seabios/src/usb-msc.h
new file mode 100644
index 0000000..71adb20
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-msc.h
@@ -0,0 +1,27 @@
+#ifndef __USB_MSC_H
+#define __USB_MSC_H
+
+// usb-msc.c
+struct disk_op_s;
+int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+struct usb_interface_descriptor;
+struct usb_pipe;
+int usb_msc_init(struct usb_pipe *pipe
+                 , struct usb_interface_descriptor *iface, int imax);
+int process_usb_op(struct disk_op_s *op);
+
+
+/****************************************************************
+ * MSC flags
+ ****************************************************************/
+
+#define US_SC_ATAPI_8020   0x02
+#define US_SC_ATAPI_8070   0x05
+#define US_SC_SCSI         0x06
+
+#define US_PR_BULK         0x50
+
+#define USB_MSC_TYPE_DISK  0x00
+#define USB_MSC_TYPE_CDROM 0x05
+
+#endif // ush-msc.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-ohci.c b/qemu-0.15.x/roms/seabios/src/usb-ohci.c
new file mode 100644
index 0000000..86eba0d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-ohci.c
@@ -0,0 +1,532 @@
+// Code for handling OHCI USB controllers.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "usb-ohci.h" // struct ohci_hcca
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+#define FIT                     (1 << 31)
+
+struct usb_ohci_s {
+    struct usb_s usb;
+    struct ohci_regs *regs;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to port
+static int
+ohci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+    u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
+    if (!(sts & RH_PS_CCS))
+        // No device.
+        return -1;
+
+    // XXX - need to wait for USB_TIME_ATTDB if just powered up?
+
+    return 0;
+}
+
+// Disable port
+static void
+ohci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+    writel(&cntl->regs->roothub_portstatus[port], RH_PS_CCS|RH_PS_LSDA);
+}
+
+// Reset device on port
+static int
+ohci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+    writel(&cntl->regs->roothub_portstatus[port], RH_PS_PRS);
+    u32 sts;
+    u64 end = calc_future_tsc(USB_TIME_DRSTR * 2);
+    for (;;) {
+        sts = readl(&cntl->regs->roothub_portstatus[port]);
+        if (!(sts & RH_PS_PRS))
+            // XXX - need to ensure USB_TIME_DRSTR time in reset?
+            break;
+        if (check_tsc(end)) {
+            // Timeout.
+            warn_timeout();
+            ohci_hub_disconnect(hub, port);
+            return -1;
+        }
+        yield();
+    }
+
+    if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES))
+        // Device no longer present
+        return -1;
+
+    return !!(sts & RH_PS_LSDA);
+}
+
+static struct usbhub_op_s ohci_HubOp = {
+    .detect = ohci_hub_detect,
+    .reset = ohci_hub_reset,
+    .disconnect = ohci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ohci_ports(struct usb_ohci_s *cntl)
+{
+    ASSERT32FLAT();
+    // Turn on power for all devices on roothub.
+    u32 rha = readl(&cntl->regs->roothub_a);
+    rha &= ~(RH_A_PSM | RH_A_OCPM);
+    writel(&cntl->regs->roothub_status, RH_HS_LPSC);
+    writel(&cntl->regs->roothub_b, RH_B_PPCM);
+    msleep((rha >> 24) * 2);
+    // XXX - need to sleep for USB_TIME_SIGATT if just powered up?
+
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.cntl = &cntl->usb;
+    hub.portcount = rha & RH_A_NDP;
+    hub.op = &ohci_HubOp;
+    usb_enumerate(&hub);
+    return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca)
+{
+    u32 oldfminterval = readl(&cntl->regs->fminterval);
+    u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+
+    // XXX - check if already running?
+
+    // Do reset
+    writel(&cntl->regs->control, OHCI_USB_RESET | oldrwc);
+    readl(&cntl->regs->control); // flush writes
+    msleep(USB_TIME_DRSTR);
+
+    // Do software init (min 10us, max 2ms)
+    u64 end = calc_future_tsc_usec(10);
+    writel(&cntl->regs->cmdstatus, OHCI_HCR);
+    for (;;) {
+        u32 status = readl(&cntl->regs->cmdstatus);
+        if (! status & OHCI_HCR)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+    }
+
+    // Init memory
+    writel(&cntl->regs->ed_controlhead, 0);
+    writel(&cntl->regs->ed_bulkhead, 0);
+    writel(&cntl->regs->hcca, (u32)hcca);
+
+    // Init fminterval
+    u32 fi = oldfminterval & 0x3fff;
+    writel(&cntl->regs->fminterval
+           , (((oldfminterval & FIT) ^ FIT)
+              | fi | (((6 * (fi - 210)) / 7) << 16)));
+    writel(&cntl->regs->periodicstart, ((9 * fi) / 10) & 0x3fff);
+    readl(&cntl->regs->control); // flush writes
+
+    // XXX - verify that fminterval was setup correctly.
+
+    // Go into operational state
+    writel(&cntl->regs->control
+           , (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | OHCI_CTRL_PLE
+              | OHCI_USB_OPER | oldrwc));
+    readl(&cntl->regs->control); // flush writes
+
+    return 0;
+}
+
+static void
+stop_ohci(struct usb_ohci_s *cntl)
+{
+    u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+    writel(&cntl->regs->control, oldrwc);
+    readl(&cntl->regs->control); // flush writes
+}
+
+static void
+configure_ohci(void *data)
+{
+    struct usb_ohci_s *cntl = data;
+
+    // Allocate memory
+    struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
+    struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
+    if (!hcca || !intr_ed) {
+        warn_noalloc();
+        goto free;
+    }
+    memset(hcca, 0, sizeof(*hcca));
+    memset(intr_ed, 0, sizeof(*intr_ed));
+    intr_ed->hwINFO = ED_SKIP;
+    int i;
+    for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
+        hcca->int_table[i] = (u32)intr_ed;
+
+    int ret = start_ohci(cntl, hcca);
+    if (ret)
+        goto err;
+
+    int count = check_ohci_ports(cntl);
+    free_pipe(cntl->usb.defaultpipe);
+    if (! count)
+        goto err;
+    return;
+
+err:
+    stop_ohci(cntl);
+free:
+    free(hcca);
+    free(intr_ed);
+}
+
+void
+ohci_init(u16 bdf, int busid)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    cntl->usb.bdf = bdf;
+    cntl->usb.type = USB_TYPE_OHCI;
+
+    u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+    cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+
+    dprintf(1, "OHCI init on dev %02x:%02x.%x (regs=%p)\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+            , pci_bdf_to_fn(bdf), cntl->regs);
+
+    // Enable bus mastering and memory access.
+    pci_config_maskw(bdf, PCI_COMMAND
+                     , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY);
+
+    // XXX - check for and disable SMM control?
+
+    // Disable interrupts
+    writel(&cntl->regs->intrdisable, ~0);
+    writel(&cntl->regs->intrstatus, ~0);
+
+    run_thread(configure_ohci, cntl);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_ed(struct ohci_ed *ed)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (ed->hwHeadP == ed->hwTailP)
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct usb_ohci_s *cntl)
+{
+    barrier();
+    struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    u32 startframe = hcca->frame_no;
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (hcca->frame_no != startframe)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+static void
+signal_freelist(struct usb_ohci_s *cntl)
+{
+    u32 v = readl(&cntl->regs->control);
+    if (v & OHCI_CTRL_CLE) {
+        writel(&cntl->regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+        ohci_waittick(cntl);
+        writel(&cntl->regs->ed_controlcurrent, 0);
+        writel(&cntl->regs->ed_bulkcurrent, 0);
+        writel(&cntl->regs->control, v);
+    } else {
+        ohci_waittick(cntl);
+    }
+}
+
+struct ohci_pipe {
+    struct ohci_ed ed;
+    struct usb_pipe pipe;
+    void *data;
+    int count;
+    struct ohci_td *tds;
+};
+
+void
+ohci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    dprintf(7, "ohci_free_pipe %p\n", p);
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct usb_ohci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ohci_s, usb);
+
+    u32 *pos = &cntl->regs->ed_controlhead;
+    for (;;) {
+        struct ohci_ed *next = (void*)*pos;
+        if (!next) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        if (next == &pipe->ed) {
+            *pos = next->hwNextED;
+            signal_freelist(cntl);
+            free(pipe);
+            return;
+        }
+        pos = &next->hwNextED;
+    }
+}
+
+struct usb_pipe *
+ohci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    struct usb_ohci_s *cntl = container_of(
+        dummy->cntl, struct usb_ohci_s, usb);
+    dprintf(7, "ohci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->ed.hwINFO = ED_SKIP;
+
+    // Add queue head to controller list.
+    pipe->ed.hwNextED = cntl->regs->ed_controlhead;
+    barrier();
+    cntl->regs->ed_controlhead = (u32)&pipe->ed;
+    return &pipe->pipe;
+}
+
+int
+ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    if (! CONFIG_USB_OHCI)
+        return -1;
+    dprintf(5, "ohci_control %p\n", p);
+    if (datasize > 4096) {
+        // XXX - should support larger sizes.
+        warn_noalloc();
+        return -1;
+    }
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct usb_ohci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ohci_s, usb);
+    int maxpacket = pipe->pipe.maxpacket;
+    int lowspeed = pipe->pipe.speed;
+    int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+    // Setup transfer descriptors
+    struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+    struct ohci_td *td = tds;
+    td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC;
+    td->hwCBP = (u32)cmd;
+    td->hwNextTD = (u32)&td[1];
+    td->hwBE = (u32)cmd + cmdsize - 1;
+    td++;
+    if (datasize) {
+        td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC;
+        td->hwCBP = (u32)data;
+        td->hwNextTD = (u32)&td[1];
+        td->hwBE = (u32)data + datasize - 1;
+        td++;
+    }
+    td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC;
+    td->hwCBP = 0;
+    td->hwNextTD = (u32)&td[1];
+    td->hwBE = 0;
+    td++;
+
+    // Transfer data
+    pipe->ed.hwINFO = ED_SKIP;
+    barrier();
+    pipe->ed.hwHeadP = (u32)tds;
+    pipe->ed.hwTailP = (u32)td;
+    barrier();
+    pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+    writel(&cntl->regs->cmdstatus, OHCI_CLF);
+
+    int ret = wait_ed(&pipe->ed);
+    pipe->ed.hwINFO = ED_SKIP;
+    if (ret)
+        ohci_waittick(cntl);
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+ohci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    dprintf(1, "OHCI Bulk transfers not supported.\n");
+    return NULL;
+}
+
+int
+ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+    return -1;
+}
+
+struct usb_pipe *
+ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    struct usb_ohci_s *cntl = container_of(
+        dummy->cntl, struct usb_ohci_s, usb);
+    dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 5)
+        frameexp = 5;
+    int maxpacket = dummy->maxpacket;
+    int lowspeed = dummy->speed;
+    int devaddr = dummy->devaddr | (dummy->ep << 7);
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms)+1;
+    struct ohci_pipe *pipe = malloc_low(sizeof(*pipe));
+    struct ohci_td *tds = malloc_low(sizeof(*tds) * count);
+    void *data = malloc_low(maxpacket * count);
+    if (!pipe || !tds || !data)
+        goto err;
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->data = data;
+    pipe->count = count;
+    pipe->tds = tds;
+
+    struct ohci_ed *ed = &pipe->ed;
+    ed->hwHeadP = (u32)&tds[0];
+    ed->hwTailP = (u32)&tds[count-1];
+    ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+
+    int i;
+    for (i=0; i<count-1; i++) {
+        tds[i].hwINFO = TD_DP_IN | TD_T_TOGGLE | TD_CC;
+        tds[i].hwCBP = (u32)data + maxpacket * i;
+        tds[i].hwNextTD = (u32)&tds[i+1];
+        tds[i].hwBE = tds[i].hwCBP + maxpacket - 1;
+    }
+
+    // Add to interrupt schedule.
+    barrier();
+    struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    if (frameexp == 0) {
+        // Add to existing interrupt entry.
+        struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
+        ed->hwNextED = intr_ed->hwNextED;
+        intr_ed->hwNextED = (u32)ed;
+    } else {
+        int startpos = 1<<(frameexp-1);
+        ed->hwNextED = hcca->int_table[startpos];
+        for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+            hcca->int_table[i] = (u32)ed;
+    }
+
+    return &pipe->pipe;
+
+err:
+    free(pipe);
+    free(tds);
+    free(data);
+    return NULL;
+}
+
+int
+ohci_poll_intr(struct usb_pipe *p, void *data)
+{
+    ASSERT16();
+    if (! CONFIG_USB_OHCI)
+        return -1;
+
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct ohci_td *tds = GET_FLATPTR(pipe->tds);
+    struct ohci_td *head = (void*)GET_FLATPTR(pipe->ed.hwHeadP);
+    struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
+    int count = GET_FLATPTR(pipe->count);
+    int pos = (tail - tds + 1) % count;
+    struct ohci_td *next = &tds[pos];
+    if (head == next)
+        // No intrs found.
+        return -1;
+    // XXX - check for errors.
+
+    // Copy data.
+    int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    void *pipedata = GET_FLATPTR(pipe->data);
+    void *intrdata = pipedata + maxpacket * pos;
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
+               , maxpacket);
+
+    // Reenable this td.
+    SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC);
+    intrdata = pipedata + maxpacket * (tail-tds);
+    SET_FLATPTR(tail->hwCBP, (u32)intrdata);
+    SET_FLATPTR(tail->hwNextTD, (u32)next);
+    SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
+    barrier();
+    SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-ohci.h b/qemu-0.15.x/roms/seabios/src/usb-ohci.h
new file mode 100644
index 0000000..7dd2f09
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-ohci.h
@@ -0,0 +1,143 @@
+#ifndef __USB_OHCI_H
+#define __USB_OHCI_H
+
+// usb-ohci.c
+void ohci_init(u16 bdf, int busid);
+struct usb_pipe;
+void ohci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ohci_alloc_control_pipe(struct usb_pipe *dummy);
+int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *ohci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int ohci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ohci structs and flags
+ ****************************************************************/
+
+struct ohci_ed {
+    u32 hwINFO;
+    u32 hwTailP;
+    u32 hwHeadP;
+    u32 hwNextED;
+} PACKED;
+
+#define ED_ISO          (1 << 15)
+#define ED_SKIP         (1 << 14)
+#define ED_LOWSPEED     (1 << 13)
+#define ED_OUT          (0x01 << 11)
+#define ED_IN           (0x02 << 11)
+
+#define ED_C            (0x02)
+#define ED_H            (0x01)
+
+struct ohci_td {
+    u32 hwINFO;
+    u32 hwCBP;
+    u32 hwNextTD;
+    u32 hwBE;
+} PACKED;
+
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_DI       0x00E00000
+
+#define TD_DONE     0x00020000
+#define TD_ISO      0x00010000
+
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_R        0x00040000
+
+struct ohci_hcca {
+    u32  int_table[32];
+    u32  frame_no;
+    u32  done_head;
+    u8   reserved[120];
+} PACKED;
+
+struct ohci_regs {
+    u32  revision;
+    u32  control;
+    u32  cmdstatus;
+    u32  intrstatus;
+    u32  intrenable;
+    u32  intrdisable;
+
+    u32  hcca;
+    u32  ed_periodcurrent;
+    u32  ed_controlhead;
+    u32  ed_controlcurrent;
+    u32  ed_bulkhead;
+    u32  ed_bulkcurrent;
+    u32  donehead;
+
+    u32  fminterval;
+    u32  fmremaining;
+    u32  fmnumber;
+    u32  periodicstart;
+    u32  lsthresh;
+
+    u32  roothub_a;
+    u32  roothub_b;
+    u32  roothub_status;
+    u32  roothub_portstatus[15];
+} PACKED;
+
+#define OHCI_CTRL_CBSR  (3 << 0)
+#define OHCI_CTRL_PLE   (1 << 2)
+#define OHCI_CTRL_CLE   (1 << 4)
+#define OHCI_CTRL_BLE   (1 << 5)
+#define OHCI_CTRL_HCFS  (3 << 6)
+#       define OHCI_USB_RESET   (0 << 6)
+#       define OHCI_USB_OPER    (2 << 6)
+#define OHCI_CTRL_RWC   (1 << 9)
+
+#define OHCI_HCR        (1 << 0)
+#define OHCI_CLF        (1 << 1)
+
+#define OHCI_INTR_MIE   (1 << 31)
+
+#define RH_PS_CCS            0x00000001
+#define RH_PS_PES            0x00000002
+#define RH_PS_PSS            0x00000004
+#define RH_PS_POCI           0x00000008
+#define RH_PS_PRS            0x00000010
+#define RH_PS_PPS            0x00000100
+#define RH_PS_LSDA           0x00000200
+#define RH_PS_CSC            0x00010000
+#define RH_PS_PESC           0x00020000
+#define RH_PS_PSSC           0x00040000
+#define RH_PS_OCIC           0x00080000
+#define RH_PS_PRSC           0x00100000
+
+#define RH_HS_LPS            0x00000001
+#define RH_HS_OCI            0x00000002
+#define RH_HS_DRWE           0x00008000
+#define RH_HS_LPSC           0x00010000
+#define RH_HS_OCIC           0x00020000
+#define RH_HS_CRWE           0x80000000
+
+#define RH_B_DR         0x0000ffff
+#define RH_B_PPCM       0xffff0000
+
+#define RH_A_NDP        (0xff << 0)
+#define RH_A_PSM        (1 << 8)
+#define RH_A_NPS        (1 << 9)
+#define RH_A_DT         (1 << 10)
+#define RH_A_OCPM       (1 << 11)
+#define RH_A_NOCP       (1 << 12)
+#define RH_A_POTPGT     (0xff << 24)
+
+#endif // usb-ohci.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb-uhci.c b/qemu-0.15.x/roms/seabios/src/usb-uhci.c
new file mode 100644
index 0000000..40f83bb
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-uhci.c
@@ -0,0 +1,604 @@
+// Code for handling UHCI USB controllers.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-uhci.h" // USBLEGSUP
+#include "pci_regs.h" // PCI_BASE_ADDRESS_4
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+struct usb_uhci_s {
+    struct usb_s usb;
+    u16 iobase;
+    struct uhci_qh *control_qh, *bulk_qh;
+    struct uhci_framelist *framelist;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to a given port
+static int
+uhci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+    u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+
+    u16 status = inw(ioport);
+    if (!(status & USBPORTSC_CCS))
+        // No device
+        return -1;
+
+    // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+    // Begin reset on port
+    outw(USBPORTSC_PR, ioport);
+    msleep(USB_TIME_DRSTR);
+    return 0;
+}
+
+// Reset device on port
+static int
+uhci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+    struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+    u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+
+    // Finish reset on port
+    outw(0, ioport);
+    udelay(6); // 64 high-speed bit times
+    u16 status = inw(ioport);
+    if (!(status & USBPORTSC_CCS))
+        // No longer connected
+        return -1;
+    outw(USBPORTSC_PE, ioport);
+    return !!(status & USBPORTSC_LSDA);
+}
+
+// Disable port
+static void
+uhci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+    u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+    outw(0, ioport);
+}
+
+static struct usbhub_op_s uhci_HubOp = {
+    .detect = uhci_hub_detect,
+    .reset = uhci_hub_reset,
+    .disconnect = uhci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_uhci_ports(struct usb_uhci_s *cntl)
+{
+    ASSERT32FLAT();
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.cntl = &cntl->usb;
+    hub.portcount = 2;
+    hub.op = &uhci_HubOp;
+    usb_enumerate(&hub);
+    return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+reset_uhci(struct usb_uhci_s *cntl, u16 bdf)
+{
+    // XXX - don't reset if not needed.
+
+    // Reset PIRQ and SMI
+    pci_config_writew(bdf, USBLEGSUP, USBLEGSUP_RWC);
+
+    // Reset the HC
+    outw(USBCMD_HCRESET, cntl->iobase + USBCMD);
+    udelay(5);
+
+    // Disable interrupts and commands (just to be safe).
+    outw(0, cntl->iobase + USBINTR);
+    outw(0, cntl->iobase + USBCMD);
+}
+
+static void
+configure_uhci(void *data)
+{
+    struct usb_uhci_s *cntl = data;
+
+    // Allocate ram for schedule storage
+    struct uhci_td *term_td = malloc_high(sizeof(*term_td));
+    struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+    struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh));
+    struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
+    if (!term_td || !fl || !intr_qh || !term_qh) {
+        warn_noalloc();
+        goto fail;
+    }
+
+    // Work around for PIIX errata
+    memset(term_td, 0, sizeof(*term_td));
+    term_td->link = UHCI_PTR_TERM;
+    term_td->token = (uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT)
+                      | USB_PID_IN);
+    memset(term_qh, 0, sizeof(*term_qh));
+    term_qh->element = (u32)term_td;
+    term_qh->link = UHCI_PTR_TERM;
+
+    // Set schedule to point to primary intr queue head
+    memset(intr_qh, 0, sizeof(*intr_qh));
+    intr_qh->element = UHCI_PTR_TERM;
+    intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
+    int i;
+    for (i=0; i<ARRAY_SIZE(fl->links); i++)
+        fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
+    cntl->framelist = fl;
+    cntl->control_qh = cntl->bulk_qh = intr_qh;
+    barrier();
+
+    // Set the frame length to the default: 1 ms exactly
+    outb(USBSOF_DEFAULT, cntl->iobase + USBSOF);
+
+    // Store the frame list base address
+    outl((u32)fl->links, cntl->iobase + USBFLBASEADD);
+
+    // Set the current frame number
+    outw(0, cntl->iobase + USBFRNUM);
+
+    // Mark as configured and running with a 64-byte max packet.
+    outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD);
+
+    // Find devices
+    int count = check_uhci_ports(cntl);
+    free_pipe(cntl->usb.defaultpipe);
+    if (count)
+        // Success
+        return;
+
+    // No devices found - shutdown and free controller.
+    outw(0, cntl->iobase + USBCMD);
+fail:
+    free(term_td);
+    free(fl);
+    free(intr_qh);
+    free(term_qh);
+    free(cntl);
+}
+
+void
+uhci_init(u16 bdf, int busid)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    cntl->usb.bdf = bdf;
+    cntl->usb.type = USB_TYPE_UHCI;
+    cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
+                    & PCI_BASE_ADDRESS_IO_MASK);
+
+    dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+            , pci_bdf_to_fn(bdf), cntl->iobase);
+
+    pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+    reset_uhci(cntl, bdf);
+
+    run_thread(configure_uhci, cntl);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (qh->element & UHCI_PTR_TERM)
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS);
+            dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n"
+                    , qh, td, td->status
+                    , inw(cntl->iobase + USBCMD)
+                    , inw(cntl->iobase + USBSTS));
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+uhci_waittick(u16 iobase)
+{
+    barrier();
+    u16 startframe = inw(iobase + USBFRNUM);
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (inw(iobase + USBFRNUM) != startframe)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+struct uhci_pipe {
+    struct uhci_qh qh;
+    struct uhci_td *next_td;
+    struct usb_pipe pipe;
+    u16 iobase;
+    u8 toggle;
+};
+
+void
+uhci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    dprintf(7, "uhci_free_pipe %p\n", p);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct usb_uhci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+    struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS);
+    for (;;) {
+        u32 link = pos->link;
+        if (link == UHCI_PTR_TERM) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+        if (next == &pipe->qh) {
+            pos->link = next->link;
+            if (cntl->control_qh == next)
+                cntl->control_qh = pos;
+            if (cntl->bulk_qh == next)
+                cntl->bulk_qh = pos;
+            uhci_waittick(cntl->iobase);
+            free(pipe);
+            return;
+        }
+        pos = next;
+    }
+}
+
+struct usb_pipe *
+uhci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.element = UHCI_PTR_TERM;
+    pipe->iobase = cntl->iobase;
+
+    // Add queue head to controller list.
+    struct uhci_qh *control_qh = cntl->control_qh;
+    pipe->qh.link = control_qh->link;
+    barrier();
+    control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+    if (cntl->bulk_qh == control_qh)
+        cntl->bulk_qh = &pipe->qh;
+    return &pipe->pipe;
+}
+
+int
+uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB_UHCI)
+        return -1;
+    dprintf(5, "uhci_control %p\n", p);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct usb_uhci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+    int maxpacket = pipe->pipe.maxpacket;
+    int lowspeed = pipe->pipe.speed;
+    int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+    // Setup transfer descriptors
+    int count = 2 + DIV_ROUND_UP(datasize, maxpacket);
+    struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+
+    tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH;
+    tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                     | TD_CTRL_ACTIVE);
+    tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                    | USB_PID_SETUP);
+    tds[0].buffer = (void*)cmd;
+    int toggle = TD_TOKEN_TOGGLE;
+    int i;
+    for (i=1; i<count-1; i++) {
+        tds[i].link = (u32)&tds[i+1] | UHCI_PTR_DEPTH;
+        tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                         | TD_CTRL_ACTIVE);
+        int len = (i == count-2 ? (datasize - (i-1)*maxpacket) : maxpacket);
+        tds[i].token = (uhci_explen(len) | toggle
+                        | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                        | (dir ? USB_PID_IN : USB_PID_OUT));
+        tds[i].buffer = data + (i-1) * maxpacket;
+        toggle ^= TD_TOKEN_TOGGLE;
+    }
+    tds[i].link = UHCI_PTR_TERM;
+    tds[i].status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0)
+                     | TD_CTRL_ACTIVE);
+    tds[i].token = (uhci_explen(0) | TD_TOKEN_TOGGLE
+                    | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                    | (dir ? USB_PID_OUT : USB_PID_IN));
+    tds[i].buffer = 0;
+
+    // Transfer data
+    barrier();
+    pipe->qh.element = (u32)&tds[0];
+    int ret = wait_qh(cntl, &pipe->qh);
+    if (ret) {
+        pipe->qh.element = UHCI_PTR_TERM;
+        uhci_waittick(pipe->iobase);
+    }
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+uhci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.element = UHCI_PTR_TERM;
+    pipe->iobase = cntl->iobase;
+
+    // Add queue head to controller list.
+    struct uhci_qh *bulk_qh = cntl->bulk_qh;
+    pipe->qh.link = bulk_qh->link;
+    barrier();
+    bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+
+    return &pipe->pipe;
+}
+
+static int
+wait_td(struct uhci_td *td)
+{
+    u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+    u32 status;
+    for (;;) {
+        status = td->status;
+        if (!(status & TD_CTRL_ACTIVE))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+    if (status & TD_CTRL_ANY_ERROR) {
+        dprintf(1, "wait_td error - status=%x\n", status);
+        return -2;
+    }
+    return 0;
+}
+
+#define STACKTDS 4
+#define TDALIGN 16
+
+int
+uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+    if (! CONFIG_USB_UHCI)
+        return -1;
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    dprintf(7, "uhci_send_bulk qh=%p dir=%d data=%p size=%d\n"
+            , &pipe->qh, dir, data, datasize);
+    int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    int lowspeed = GET_FLATPTR(pipe->pipe.speed);
+    int devaddr = (GET_FLATPTR(pipe->pipe.devaddr)
+                   | (GET_FLATPTR(pipe->pipe.ep) << 7));
+    int toggle = GET_FLATPTR(pipe->toggle) ? TD_TOKEN_TOGGLE : 0;
+
+    // Allocate 4 tds on stack (16byte aligned)
+    u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
+    struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN);
+    memset(tds, 0, sizeof(*tds) * STACKTDS);
+
+    // Enable tds
+    barrier();
+    SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+
+    int tdpos = 0;
+    while (datasize) {
+        struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+        int ret = wait_td(td);
+        if (ret)
+            goto fail;
+
+        int transfer = datasize;
+        if (transfer > maxpacket)
+            transfer = maxpacket;
+        struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+                                                 , &tds[tdpos % STACKTDS]);
+        td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl);
+        td->token = (uhci_explen(transfer) | toggle
+                     | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                     | (dir ? USB_PID_IN : USB_PID_OUT));
+        td->buffer = data;
+        barrier();
+        td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                      | TD_CTRL_ACTIVE);
+        toggle ^= TD_TOKEN_TOGGLE;
+
+        data += transfer;
+        datasize -= transfer;
+    }
+    int i;
+    for (i=0; i<STACKTDS; i++) {
+        struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+        int ret = wait_td(td);
+        if (ret)
+            goto fail;
+    }
+
+    SET_FLATPTR(pipe->toggle, !!toggle);
+    return 0;
+fail:
+    dprintf(1, "uhci_send_bulk failed\n");
+    SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+    uhci_waittick(GET_FLATPTR(pipe->iobase));
+    return -1;
+}
+
+struct usb_pipe *
+uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 10)
+        frameexp = 10;
+    int maxpacket = dummy->maxpacket;
+    int lowspeed = dummy->speed;
+    int devaddr = dummy->devaddr | (dummy->ep << 7);
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
+    count = ALIGN(count, 2);
+    struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+    struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
+    void *data = malloc_low(maxpacket * count);
+    if (!pipe || !tds || !data) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.element = (u32)tds;
+    pipe->next_td = &tds[0];
+    pipe->iobase = cntl->iobase;
+
+    int toggle = 0;
+    int i;
+    for (i=0; i<count; i++) {
+        tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
+        tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                         | TD_CTRL_ACTIVE);
+        tds[i].token = (uhci_explen(maxpacket) | toggle
+                        | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                        | USB_PID_IN);
+        tds[i].buffer = data + maxpacket * i;
+        toggle ^= TD_TOKEN_TOGGLE;
+    }
+
+    // Add to interrupt schedule.
+    struct uhci_framelist *fl = cntl->framelist;
+    if (frameexp == 0) {
+        // Add to existing interrupt entry.
+        struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+        pipe->qh.link = intr_qh->link;
+        barrier();
+        intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+        if (cntl->control_qh == intr_qh)
+            cntl->control_qh = &pipe->qh;
+        if (cntl->bulk_qh == intr_qh)
+            cntl->bulk_qh = &pipe->qh;
+    } else {
+        int startpos = 1<<(frameexp-1);
+        pipe->qh.link = fl->links[startpos];
+        barrier();
+        for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+            fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
+    }
+
+    return &pipe->pipe;
+fail:
+    free(pipe);
+    free(tds);
+    free(data);
+    return NULL;
+}
+
+int
+uhci_poll_intr(struct usb_pipe *p, void *data)
+{
+    ASSERT16();
+    if (! CONFIG_USB_UHCI)
+        return -1;
+
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct uhci_td *td = GET_FLATPTR(pipe->next_td);
+    u32 status = GET_FLATPTR(td->status);
+    u32 token = GET_FLATPTR(td->token);
+    if (status & TD_CTRL_ACTIVE)
+        // No intrs found.
+        return -1;
+    // XXX - check for errors.
+
+    // Copy data.
+    void *tddata = GET_FLATPTR(td->buffer);
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+               , uhci_expected_length(token));
+
+    // Reenable this td.
+    struct uhci_td *next = (void*)(GET_FLATPTR(td->link) & ~UHCI_PTR_BITS);
+    SET_FLATPTR(pipe->next_td, next);
+    barrier();
+    SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
+                             | TD_CTRL_ACTIVE));
+
+    return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb-uhci.h b/qemu-0.15.x/roms/seabios/src/usb-uhci.h
new file mode 100644
index 0000000..3c2c298
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb-uhci.h
@@ -0,0 +1,128 @@
+#ifndef __USB_UHCI_H
+#define __USB_UHCI_H
+
+// usb-uhci.c
+void uhci_init(u16 bdf, int busid);
+struct usb_pipe;
+void uhci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *uhci_alloc_control_pipe(struct usb_pipe *dummy);
+int uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *uhci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int uhci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * uhci structs and flags
+ ****************************************************************/
+
+/* USB port status and control registers */
+#define USBPORTSC1      16
+#define USBPORTSC2      18
+#define   USBPORTSC_CCS         0x0001  /* Current Connect Status
+                                         * ("device present") */
+#define   USBPORTSC_CSC         0x0002  /* Connect Status Change */
+#define   USBPORTSC_PE          0x0004  /* Port Enable */
+#define   USBPORTSC_PEC         0x0008  /* Port Enable Change */
+#define   USBPORTSC_DPLUS       0x0010  /* D+ high (line status) */
+#define   USBPORTSC_DMINUS      0x0020  /* D- high (line status) */
+#define   USBPORTSC_RD          0x0040  /* Resume Detect */
+#define   USBPORTSC_RES1        0x0080  /* reserved, always 1 */
+#define   USBPORTSC_LSDA        0x0100  /* Low Speed Device Attached */
+#define   USBPORTSC_PR          0x0200  /* Port Reset */
+
+/* Legacy support register */
+#define USBLEGSUP               0xc0
+#define   USBLEGSUP_RWC         0x8f00  /* the R/WC bits */
+
+/* Command register */
+#define USBCMD          0
+#define   USBCMD_RS             0x0001  /* Run/Stop */
+#define   USBCMD_HCRESET        0x0002  /* Host reset */
+#define   USBCMD_GRESET         0x0004  /* Global reset */
+#define   USBCMD_EGSM           0x0008  /* Global Suspend Mode */
+#define   USBCMD_FGR            0x0010  /* Force Global Resume */
+#define   USBCMD_SWDBG          0x0020  /* SW Debug mode */
+#define   USBCMD_CF             0x0040  /* Config Flag (sw only) */
+#define   USBCMD_MAXP           0x0080  /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS          2
+#define   USBSTS_USBINT         0x0001  /* Interrupt due to IOC */
+#define   USBSTS_ERROR          0x0002  /* Interrupt due to error */
+#define   USBSTS_RD             0x0004  /* Resume Detect */
+#define   USBSTS_HSE            0x0008  /* Host System Error: PCI problems */
+#define   USBSTS_HCPE           0x0010  /* Host Controller Process Error:
+                                         * the schedule is buggy */
+#define   USBSTS_HCH            0x0020  /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR         4
+#define   USBINTR_TIMEOUT       0x0001  /* Timeout/CRC error enable */
+#define   USBINTR_RESUME        0x0002  /* Resume interrupt enable */
+#define   USBINTR_IOC           0x0004  /* Interrupt On Complete enable */
+#define   USBINTR_SP            0x0008  /* Short packet interrupt enable */
+
+#define USBFRNUM        6
+#define USBFLBASEADD    8
+#define USBSOF          12
+#define   USBSOF_DEFAULT        64      /* Frame length is exactly 1 ms */
+
+struct uhci_framelist {
+    u32 links[1024];
+} PACKED;
+
+#define TD_CTRL_SPD             (1 << 29)       /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK      (3 << 27)       /* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT     27
+#define TD_CTRL_LS              (1 << 26)       /* Low Speed Device */
+#define TD_CTRL_IOS             (1 << 25)       /* Isochronous Select */
+#define TD_CTRL_IOC             (1 << 24)       /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE          (1 << 23)       /* TD Active */
+#define TD_CTRL_STALLED         (1 << 22)       /* TD Stalled */
+#define TD_CTRL_DBUFERR         (1 << 21)       /* Data Buffer Error */
+#define TD_CTRL_BABBLE          (1 << 20)       /* Babble Detected */
+#define TD_CTRL_NAK             (1 << 19)       /* NAK Received */
+#define TD_CTRL_CRCTIMEO        (1 << 18)       /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF        (1 << 17)       /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK     0x7FF   /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR       (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+                                 TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \
+                                 TD_CTRL_BITSTUFF)
+#define uhci_maxerr(err)                ((err) << TD_CTRL_C_ERR_SHIFT)
+
+#define TD_TOKEN_DEVADDR_SHIFT  8
+#define TD_TOKEN_TOGGLE_SHIFT   19
+#define TD_TOKEN_TOGGLE         (1 << 19)
+#define TD_TOKEN_EXPLEN_SHIFT   21
+#define TD_TOKEN_EXPLEN_MASK    0x7FF   /* expected length, encoded as n-1 */
+#define TD_TOKEN_PID_MASK       0xFF
+
+#define uhci_explen(len)        ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
+                                        TD_TOKEN_EXPLEN_SHIFT)
+
+#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \
+                                        1) & TD_TOKEN_EXPLEN_MASK)
+
+struct uhci_td {
+    u32 link;
+    u32 status;
+    u32 token;
+    void *buffer;
+} PACKED;
+
+struct uhci_qh {
+    u32 link;
+    u32 element;
+} PACKED;
+
+#define UHCI_PTR_BITS           0x000F
+#define UHCI_PTR_TERM           0x0001
+#define UHCI_PTR_QH             0x0002
+#define UHCI_PTR_DEPTH          0x0004
+#define UHCI_PTR_BREADTH        0x0000
+
+#endif // usb-uhci.h
diff --git a/qemu-0.15.x/roms/seabios/src/usb.c b/qemu-0.15.x/roms/seabios/src/usb.c
new file mode 100644
index 0000000..a07bc1f
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb.c
@@ -0,0 +1,473 @@
+// Main code for handling USB controllers and devices.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "pci_regs.h" // PCI_CLASS_REVISION
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "usb-uhci.h" // uhci_init
+#include "usb-ohci.h" // ohci_init
+#include "usb-ehci.h" // ehci_init
+#include "usb-hid.h" // usb_keyboard_setup
+#include "usb-hub.h" // usb_hub_init
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Controller function wrappers
+ ****************************************************************/
+
+// Free an allocated control or bulk pipe.
+void
+free_pipe(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    if (!pipe)
+        return;
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_free_pipe(pipe);
+    case USB_TYPE_OHCI:
+        return ohci_free_pipe(pipe);
+    case USB_TYPE_EHCI:
+        return ehci_free_pipe(pipe);
+    }
+}
+
+// Allocate a control pipe to a default endpoint (which can only be
+// used by 32bit code)
+static struct usb_pipe *
+alloc_default_control_pipe(struct usb_pipe *dummy)
+{
+    switch (dummy->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_control_pipe(dummy);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_control_pipe(dummy);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_control_pipe(dummy);
+    }
+}
+
+// Send a message on a control pipe using the default control descriptor.
+static int
+send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    case USB_TYPE_OHCI:
+        return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    case USB_TYPE_EHCI:
+        return ehci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    }
+}
+
+// Fill "pipe" endpoint info from an endpoint descriptor.
+static void
+desc2pipe(struct usb_pipe *newpipe, struct usb_pipe *origpipe
+          , struct usb_endpoint_descriptor *epdesc)
+{
+    memcpy(newpipe, origpipe, sizeof(*newpipe));
+    newpipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+    newpipe->maxpacket = epdesc->wMaxPacketSize;
+}
+
+struct usb_pipe *
+alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    struct usb_pipe dummy;
+    desc2pipe(&dummy, pipe, epdesc);
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_bulk_pipe(&dummy);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_bulk_pipe(&dummy);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_bulk_pipe(&dummy);
+    }
+}
+
+int
+usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
+{
+    switch (GET_FLATPTR(pipe_fl->type)) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_send_bulk(pipe_fl, dir, data, datasize);
+    case USB_TYPE_OHCI:
+        return ohci_send_bulk(pipe_fl, dir, data, datasize);
+    case USB_TYPE_EHCI:
+        return ehci_send_bulk(pipe_fl, dir, data, datasize);
+    }
+}
+
+struct usb_pipe *
+alloc_intr_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    struct usb_pipe dummy;
+    desc2pipe(&dummy, pipe, epdesc);
+    // Find the exponential period of the requested time.
+    int period = epdesc->bInterval;
+    int frameexp;
+    if (pipe->speed != USB_HIGHSPEED)
+        frameexp = (period <= 0) ? 0 : __fls(period);
+    else
+        frameexp = (period <= 4) ? 0 : period - 4;
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_intr_pipe(&dummy, frameexp);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_intr_pipe(&dummy, frameexp);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_intr_pipe(&dummy, frameexp);
+    }
+}
+
+int noinline
+usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
+{
+    switch (GET_FLATPTR(pipe_fl->type)) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_poll_intr(pipe_fl, data);
+    case USB_TYPE_OHCI:
+        return ohci_poll_intr(pipe_fl, data);
+    case USB_TYPE_EHCI:
+        return ehci_poll_intr(pipe_fl, data);
+    }
+}
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Find the first endpoing of a given type in an interface description.
+struct usb_endpoint_descriptor *
+findEndPointDesc(struct usb_interface_descriptor *iface, int imax
+                 , int type, int dir)
+{
+    struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
+    for (;;) {
+        if ((void*)epdesc >= (void*)iface + imax
+            || epdesc->bDescriptorType == USB_DT_INTERFACE) {
+            return NULL;
+        }
+        if (epdesc->bDescriptorType == USB_DT_ENDPOINT
+            && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
+            && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
+            return epdesc;
+        epdesc = (void*)epdesc + epdesc->bLength;
+    }
+}
+
+// Send a message to the default control pipe of a device.
+int
+send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+                     , void *data)
+{
+    return send_control(pipe, req->bRequestType & USB_DIR_IN
+                        , req, sizeof(*req), data, req->wLength);
+}
+
+// Get the first 8 bytes of the device descriptor.
+static int
+get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+    req.bRequest = USB_REQ_GET_DESCRIPTOR;
+    req.wValue = USB_DT_DEVICE<<8;
+    req.wIndex = 0;
+    req.wLength = 8;
+    return send_default_control(pipe, &req, dinfo);
+}
+
+static struct usb_config_descriptor *
+get_device_config(struct usb_pipe *pipe)
+{
+    struct usb_config_descriptor cfg;
+
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+    req.bRequest = USB_REQ_GET_DESCRIPTOR;
+    req.wValue = USB_DT_CONFIG<<8;
+    req.wIndex = 0;
+    req.wLength = sizeof(cfg);
+    int ret = send_default_control(pipe, &req, &cfg);
+    if (ret)
+        return NULL;
+
+    void *config = malloc_tmphigh(cfg.wTotalLength);
+    if (!config)
+        return NULL;
+    req.wLength = cfg.wTotalLength;
+    ret = send_default_control(pipe, &req, config);
+    if (ret)
+        return NULL;
+    //hexdump(config, cfg.wTotalLength);
+    return config;
+}
+
+static int
+set_configuration(struct usb_pipe *pipe, u16 val)
+{
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+    req.bRequest = USB_REQ_SET_CONFIGURATION;
+    req.wValue = val;
+    req.wIndex = 0;
+    req.wLength = 0;
+    return send_default_control(pipe, &req, NULL);
+}
+
+
+/****************************************************************
+ * Initialization and enumeration
+ ****************************************************************/
+
+// Assign an address to a device in the default state on the given
+// controller.
+static struct usb_pipe *
+usb_set_address(struct usbhub_s *hub, int port, int speed)
+{
+    ASSERT32FLAT();
+    struct usb_s *cntl = hub->cntl;
+    dprintf(3, "set_address %p\n", cntl);
+    if (cntl->maxaddr >= USB_MAXADDR)
+        return NULL;
+
+    struct usb_pipe *defpipe = cntl->defaultpipe;
+    if (!defpipe) {
+        // Create a pipe for the default address.
+        struct usb_pipe dummy;
+        memset(&dummy, 0, sizeof(dummy));
+        dummy.cntl = cntl;
+        dummy.type = cntl->type;
+        dummy.maxpacket = 8;
+        dummy.path = (u64)-1;
+        cntl->defaultpipe = defpipe = alloc_default_control_pipe(&dummy);
+        if (!defpipe)
+            return NULL;
+    }
+    defpipe->speed = speed;
+    if (hub->pipe) {
+        if (hub->pipe->speed == USB_HIGHSPEED) {
+            defpipe->tt_devaddr = hub->pipe->devaddr;
+            defpipe->tt_port = port;
+        } else {
+            defpipe->tt_devaddr = hub->pipe->tt_devaddr;
+            defpipe->tt_port = hub->pipe->tt_port;
+        }
+    } else {
+        defpipe->tt_devaddr = defpipe->tt_port = 0;
+    }
+
+    msleep(USB_TIME_RSTRCY);
+
+    struct usb_ctrlrequest req;
+    req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+    req.bRequest = USB_REQ_SET_ADDRESS;
+    req.wValue = cntl->maxaddr + 1;
+    req.wIndex = 0;
+    req.wLength = 0;
+    int ret = send_default_control(defpipe, &req, NULL);
+    if (ret)
+        return NULL;
+
+    msleep(USB_TIME_SETADDR_RECOVERY);
+
+    cntl->maxaddr++;
+    defpipe->devaddr = cntl->maxaddr;
+    struct usb_pipe *pipe = alloc_default_control_pipe(defpipe);
+    defpipe->devaddr = 0;
+    if (hub->pipe)
+        pipe->path = hub->pipe->path;
+    pipe->path = (pipe->path << 8) | port;
+    return pipe;
+}
+
+// Called for every found device - see if a driver is available for
+// this device and do setup if so.
+static int
+configure_usb_device(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    dprintf(3, "config_usb: %p\n", pipe);
+
+    // Set the max packet size for endpoint 0 of this device.
+    struct usb_device_descriptor dinfo;
+    int ret = get_device_info8(pipe, &dinfo);
+    if (ret)
+        return 0;
+    dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
+            , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
+            , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0);
+    if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
+        return 0;
+    pipe->maxpacket = dinfo.bMaxPacketSize0;
+
+    // Get configuration
+    struct usb_config_descriptor *config = get_device_config(pipe);
+    if (!config)
+        return 0;
+
+    // Determine if a driver exists for this device - only look at the
+    // first interface of the first configuration.
+    struct usb_interface_descriptor *iface = (void*)(&config[1]);
+    if (iface->bInterfaceClass != USB_CLASS_HID
+        && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
+        && iface->bInterfaceClass != USB_CLASS_HUB)
+        // Not a supported device.
+        goto fail;
+
+    // Set the configuration.
+    ret = set_configuration(pipe, config->bConfigurationValue);
+    if (ret)
+        goto fail;
+
+    // Configure driver.
+    int imax = (void*)config + config->wTotalLength - (void*)iface;
+    if (iface->bInterfaceClass == USB_CLASS_HUB)
+        ret = usb_hub_init(pipe);
+    else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+        ret = usb_msc_init(pipe, iface, imax);
+    else
+        ret = usb_hid_init(pipe, iface, imax);
+    if (ret)
+        goto fail;
+
+    free(config);
+    return 1;
+fail:
+    free(config);
+    return 0;
+}
+
+static void
+usb_init_hub_port(void *data)
+{
+    struct usbhub_s *hub = data;
+    u32 port = hub->port; // XXX - find better way to pass port
+
+    // Detect if device present (and possibly start reset)
+    int ret = hub->op->detect(hub, port);
+    if (ret)
+        // No device present
+        goto done;
+
+    // Reset port and determine device speed
+    mutex_lock(&hub->cntl->resetlock);
+    ret = hub->op->reset(hub, port);
+    if (ret < 0)
+        // Reset failed
+        goto resetfail;
+
+    // Set address of port
+    struct usb_pipe *pipe = usb_set_address(hub, port, ret);
+    if (!pipe) {
+        hub->op->disconnect(hub, port);
+        goto resetfail;
+    }
+    mutex_unlock(&hub->cntl->resetlock);
+
+    // Configure the device
+    int count = configure_usb_device(pipe);
+    free_pipe(pipe);
+    if (!count)
+        hub->op->disconnect(hub, port);
+    hub->devcount += count;
+done:
+    hub->threads--;
+    return;
+
+resetfail:
+    mutex_unlock(&hub->cntl->resetlock);
+    goto done;
+}
+
+void
+usb_enumerate(struct usbhub_s *hub)
+{
+    u32 portcount = hub->portcount;
+    hub->threads = portcount;
+
+    // Launch a thread for every port.
+    int i;
+    for (i=0; i<portcount; i++) {
+        hub->port = i;
+        run_thread(usb_init_hub_port, hub);
+    }
+
+    // Wait for threads to complete.
+    while (hub->threads)
+        yield();
+}
+
+void
+usb_setup(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB)
+        return;
+
+    dprintf(3, "init usb\n");
+
+    // Look for USB controllers
+    int ehcibdf = -1;
+    int count = 0;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        u32 code = pci_config_readl(bdf, PCI_CLASS_REVISION) >> 8;
+
+        if (code >> 8 != PCI_CLASS_SERIAL_USB)
+            continue;
+
+        if (bdf > ehcibdf) {
+            // Check to see if this device has an ehci controller
+            ehcibdf = bdf;
+            u32 ehcicode = code;
+            int found = 0;
+            for (;;) {
+                if (ehcicode == PCI_CLASS_SERIAL_USB_EHCI) {
+                    // Found an ehci controller.
+                    int ret = ehci_init(ehcibdf, count++, bdf);
+                    if (ret)
+                        // Error
+                        break;
+                    count += found;
+                    bdf = ehcibdf;
+                    code = 0;
+                    break;
+                }
+                if (ehcicode >> 8 == PCI_CLASS_SERIAL_USB)
+                    found++;
+                ehcibdf = pci_next(ehcibdf+1, &max);
+                if (ehcibdf < 0
+                    || pci_bdf_to_busdev(ehcibdf) != pci_bdf_to_busdev(bdf))
+                    // No ehci controller found.
+                    break;
+                ehcicode = pci_config_readl(ehcibdf, PCI_CLASS_REVISION) >> 8;
+            }
+        }
+
+        if (code == PCI_CLASS_SERIAL_USB_UHCI)
+            uhci_init(bdf, count++);
+        else if (code == PCI_CLASS_SERIAL_USB_OHCI)
+            ohci_init(bdf, count++);
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/usb.h b/qemu-0.15.x/roms/seabios/src/usb.h
new file mode 100644
index 0000000..966e94b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/usb.h
@@ -0,0 +1,216 @@
+// USB functions and data.
+#ifndef __USB_H
+#define __USB_H
+
+#include "util.h" // struct mutex_s
+
+// Information on a USB end point.
+struct usb_pipe {
+    struct usb_s *cntl;
+    u64 path;
+    u8 type;
+    u8 ep;
+    u8 devaddr;
+    u8 speed;
+    u16 maxpacket;
+    u8 tt_devaddr;
+    u8 tt_port;
+};
+
+// Common information for usb controllers.
+struct usb_s {
+    struct usb_pipe *defaultpipe;
+    struct mutex_s resetlock;
+    int busid;
+    u16 bdf;
+    u8 type;
+    u8 maxaddr;
+};
+
+// Information for enumerating USB hubs
+struct usbhub_s {
+    struct usbhub_op_s *op;
+    struct usb_pipe *pipe;
+    struct usb_s *cntl;
+    struct mutex_s lock;
+    u32 powerwait;
+    u32 port;
+    u32 threads;
+    u32 portcount;
+    u32 devcount;
+};
+
+// Hub callback (32bit) info
+struct usbhub_op_s {
+    int (*detect)(struct usbhub_s *hub, u32 port);
+    int (*reset)(struct usbhub_s *hub, u32 port);
+    void (*disconnect)(struct usbhub_s *hub, u32 port);
+};
+
+#define USB_TYPE_UHCI 1
+#define USB_TYPE_OHCI 2
+#define USB_TYPE_EHCI 3
+
+#define USB_FULLSPEED 0
+#define USB_LOWSPEED  1
+#define USB_HIGHSPEED 2
+
+#define USB_MAXADDR 127
+
+
+/****************************************************************
+ * usb structs and flags
+ ****************************************************************/
+
+// USB mandated timings (in ms)
+#define USB_TIME_SIGATT 100
+#define USB_TIME_ATTDB  100
+#define USB_TIME_DRST   10
+#define USB_TIME_DRSTR  50
+#define USB_TIME_RSTRCY 10
+
+#define USB_TIME_SETADDR_RECOVERY 2
+
+#define USB_PID_OUT                     0xe1
+#define USB_PID_IN                      0x69
+#define USB_PID_SETUP                   0x2d
+
+#define USB_DIR_OUT                     0               /* to device */
+#define USB_DIR_IN                      0x80            /* to host */
+
+#define USB_TYPE_MASK                   (0x03 << 5)
+#define USB_TYPE_STANDARD               (0x00 << 5)
+#define USB_TYPE_CLASS                  (0x01 << 5)
+#define USB_TYPE_VENDOR                 (0x02 << 5)
+#define USB_TYPE_RESERVED               (0x03 << 5)
+
+#define USB_RECIP_MASK                  0x1f
+#define USB_RECIP_DEVICE                0x00
+#define USB_RECIP_INTERFACE             0x01
+#define USB_RECIP_ENDPOINT              0x02
+#define USB_RECIP_OTHER                 0x03
+
+#define USB_REQ_GET_STATUS              0x00
+#define USB_REQ_CLEAR_FEATURE           0x01
+#define USB_REQ_SET_FEATURE             0x03
+#define USB_REQ_SET_ADDRESS             0x05
+#define USB_REQ_GET_DESCRIPTOR          0x06
+#define USB_REQ_SET_DESCRIPTOR          0x07
+#define USB_REQ_GET_CONFIGURATION       0x08
+#define USB_REQ_SET_CONFIGURATION       0x09
+#define USB_REQ_GET_INTERFACE           0x0A
+#define USB_REQ_SET_INTERFACE           0x0B
+#define USB_REQ_SYNCH_FRAME             0x0C
+
+struct usb_ctrlrequest {
+    u8 bRequestType;
+    u8 bRequest;
+    u16 wValue;
+    u16 wIndex;
+    u16 wLength;
+} PACKED;
+
+#define USB_DT_DEVICE                   0x01
+#define USB_DT_CONFIG                   0x02
+#define USB_DT_STRING                   0x03
+#define USB_DT_INTERFACE                0x04
+#define USB_DT_ENDPOINT                 0x05
+#define USB_DT_DEVICE_QUALIFIER         0x06
+#define USB_DT_OTHER_SPEED_CONFIG       0x07
+
+struct usb_device_descriptor {
+    u8  bLength;
+    u8  bDescriptorType;
+
+    u16 bcdUSB;
+    u8  bDeviceClass;
+    u8  bDeviceSubClass;
+    u8  bDeviceProtocol;
+    u8  bMaxPacketSize0;
+    u16 idVendor;
+    u16 idProduct;
+    u16 bcdDevice;
+    u8  iManufacturer;
+    u8  iProduct;
+    u8  iSerialNumber;
+    u8  bNumConfigurations;
+} PACKED;
+
+#define USB_CLASS_PER_INTERFACE         0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                 1
+#define USB_CLASS_COMM                  2
+#define USB_CLASS_HID                   3
+#define USB_CLASS_PHYSICAL              5
+#define USB_CLASS_STILL_IMAGE           6
+#define USB_CLASS_PRINTER               7
+#define USB_CLASS_MASS_STORAGE          8
+#define USB_CLASS_HUB                   9
+
+struct usb_config_descriptor {
+    u8  bLength;
+    u8  bDescriptorType;
+
+    u16 wTotalLength;
+    u8  bNumInterfaces;
+    u8  bConfigurationValue;
+    u8  iConfiguration;
+    u8  bmAttributes;
+    u8  bMaxPower;
+} PACKED;
+
+struct usb_interface_descriptor {
+    u8  bLength;
+    u8  bDescriptorType;
+
+    u8  bInterfaceNumber;
+    u8  bAlternateSetting;
+    u8  bNumEndpoints;
+    u8  bInterfaceClass;
+    u8  bInterfaceSubClass;
+    u8  bInterfaceProtocol;
+    u8  iInterface;
+} PACKED;
+
+struct usb_endpoint_descriptor {
+    u8  bLength;
+    u8  bDescriptorType;
+
+    u8  bEndpointAddress;
+    u8  bmAttributes;
+    u16 wMaxPacketSize;
+    u8  bInterval;
+} PACKED;
+
+#define USB_ENDPOINT_NUMBER_MASK        0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK           0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK      0x03    /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL       0
+#define USB_ENDPOINT_XFER_ISOC          1
+#define USB_ENDPOINT_XFER_BULK          2
+#define USB_ENDPOINT_XFER_INT           3
+#define USB_ENDPOINT_MAX_ADJUSTABLE     0x80
+
+
+/****************************************************************
+ * function defs
+ ****************************************************************/
+
+// usb.c
+void usb_setup(void);
+void usb_enumerate(struct usbhub_s *hub);
+int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+                         , void *data);
+int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+void free_pipe(struct usb_pipe *pipe);
+struct usb_pipe *alloc_bulk_pipe(struct usb_pipe *pipe
+                                 , struct usb_endpoint_descriptor *epdesc);
+struct usb_pipe *alloc_intr_pipe(struct usb_pipe *pipe
+                                 , struct usb_endpoint_descriptor *epdesc);
+int usb_poll_intr(struct usb_pipe *pipe, void *data);
+struct usb_endpoint_descriptor *findEndPointDesc(
+    struct usb_interface_descriptor *iface, int imax, int type, int dir);
+u32 mkendpFromDesc(struct usb_pipe *pipe
+                   , struct usb_endpoint_descriptor *epdesc);
+
+#endif // usb.h
diff --git a/qemu-0.15.x/roms/seabios/src/util.c b/qemu-0.15.x/roms/seabios/src/util.c
new file mode 100644
index 0000000..ed73d63
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/util.c
@@ -0,0 +1,324 @@
+// Misc utility functions.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // call16
+#include "bregs.h" // struct bregs
+#include "config.h" // BUILD_STACK_ADDR
+
+
+/****************************************************************
+ * 16bit calls
+ ****************************************************************/
+
+// Call a function with a specified register state.  Note that on
+// return, the interrupt enable/disable flag may be altered.
+inline void
+call16(struct bregs *callregs)
+{
+    if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR)
+        panic("call16 with invalid stack\n");
+    asm volatile(
+#if MODE16 == 1
+        "calll __call16\n"
+        "cli\n"
+        "cld"
+#else
+        "calll __call16_from32"
+#endif
+        : "+a" (callregs), "+m" (*callregs)
+        :
+        : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+call16big(struct bregs *callregs)
+{
+    ASSERT32FLAT();
+    if (getesp() > BUILD_STACK_ADDR)
+        panic("call16 with invalid stack\n");
+    asm volatile(
+        "calll __call16big_from32"
+        : "+a" (callregs), "+m" (*callregs)
+        :
+        : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+__call16_int(struct bregs *callregs, u16 offset)
+{
+    if (MODESEGMENT)
+        callregs->code.seg = GET_SEG(CS);
+    else
+        callregs->code.seg = SEG_BIOS;
+    callregs->code.offset = offset;
+    call16(callregs);
+}
+
+
+/****************************************************************
+ * String ops
+ ****************************************************************/
+
+// Sum the bytes in the specified area.
+u8
+checksum_far(u16 buf_seg, void *buf_far, u32 len)
+{
+    SET_SEG(ES, buf_seg);
+    u32 i;
+    u8 sum = 0;
+    for (i=0; i<len; i++)
+        sum += GET_VAR(ES, ((u8*)buf_far)[i]);
+    return sum;
+}
+
+u8
+checksum(void *buf, u32 len)
+{
+    return checksum_far(GET_SEG(SS), buf, len);
+}
+
+size_t
+strlen(const char *s)
+{
+    if (__builtin_constant_p(s))
+        return __builtin_strlen(s);
+    const char *p = s;
+    while (*p)
+        p++;
+    return p-s;
+}
+
+// Compare two areas of memory.
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+    while (n) {
+        if (*(u8*)s1 != *(u8*)s2)
+            return *(u8*)s1 < *(u8*)s2 ? -1 : 1;
+        s1++;
+        s2++;
+        n--;
+    }
+    return 0;
+}
+
+// Compare two strings.
+int
+strcmp(const char *s1, const char *s2)
+{
+    for (;;) {
+        if (*s1 != *s2)
+            return *s1 < *s2 ? -1 : 1;
+        if (! *s1)
+            return 0;
+        s1++;
+        s2++;
+    }
+}
+
+inline void
+memset_far(u16 d_seg, void *d_far, u8 c, size_t len)
+{
+    SET_SEG(ES, d_seg);
+    asm volatile(
+        "rep stosb %%es:(%%di)"
+        : "+c"(len), "+D"(d_far)
+        : "a"(c)
+        : "cc", "memory");
+}
+
+inline void
+memset16_far(u16 d_seg, void *d_far, u16 c, size_t len)
+{
+    len /= 2;
+    SET_SEG(ES, d_seg);
+    asm volatile(
+        "rep stosw %%es:(%%di)"
+        : "+c"(len), "+D"(d_far)
+        : "a"(c)
+        : "cc", "memory");
+}
+
+void *
+memset(void *s, int c, size_t n)
+{
+    while (n)
+        ((char *)s)[--n] = c;
+    return s;
+}
+
+void memset_fl(void *ptr, u8 val, size_t size)
+{
+    if (MODESEGMENT)
+        memset_far(FLATPTR_TO_SEG(ptr), (void*)(FLATPTR_TO_OFFSET(ptr)),
+                   val, size);
+    else
+        memset(ptr, val, size);
+}
+
+inline void
+memcpy_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
+{
+    SET_SEG(ES, d_seg);
+    u16 bkup_ds;
+    asm volatile(
+        "movw %%ds, %w0\n"
+        "movw %w4, %%ds\n"
+        "rep movsb (%%si),%%es:(%%di)\n"
+        "movw %w0, %%ds"
+        : "=&r"(bkup_ds), "+c"(len), "+S"(s_far), "+D"(d_far)
+        : "r"(s_seg)
+        : "cc", "memory");
+}
+
+inline void
+memcpy_fl(void *d_fl, const void *s_fl, size_t len)
+{
+    if (MODESEGMENT)
+        memcpy_far(FLATPTR_TO_SEG(d_fl), (void*)FLATPTR_TO_OFFSET(d_fl)
+                   , FLATPTR_TO_SEG(s_fl), (void*)FLATPTR_TO_OFFSET(s_fl)
+                   , len);
+    else
+        memcpy(d_fl, s_fl, len);
+}
+
+void *
+#undef memcpy
+memcpy(void *d1, const void *s1, size_t len)
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+{
+    SET_SEG(ES, GET_SEG(SS));
+    void *d = d1;
+    if (((u32)d1 | (u32)s1 | len) & 3) {
+        // non-aligned memcpy
+        asm volatile(
+            "rep movsb (%%esi),%%es:(%%edi)"
+            : "+c"(len), "+S"(s1), "+D"(d)
+            : : "cc", "memory");
+        return d1;
+    }
+    // Common case - use 4-byte copy
+    len /= 4;
+    asm volatile(
+        "rep movsl (%%esi),%%es:(%%edi)"
+        : "+c"(len), "+S"(s1), "+D"(d)
+        : : "cc", "memory");
+    return d1;
+}
+
+// Copy to/from memory mapped IO.  IO mem is very slow, so yield
+// periodically.
+void
+iomemcpy(void *d, const void *s, u32 len)
+{
+    yield();
+    while (len > 3) {
+        u32 copylen = len;
+        if (copylen > 2048)
+            copylen = 2048;
+        copylen /= 4;
+        len -= copylen * 4;
+        asm volatile(
+            "rep movsl (%%esi),%%es:(%%edi)"
+            : "+c"(copylen), "+S"(s), "+D"(d)
+            : : "cc", "memory");
+        yield();
+    }
+    if (len)
+        // Copy any remaining bytes.
+        memcpy(d, s, len);
+}
+
+void *
+memmove(void *d, const void *s, size_t len)
+{
+    if (s >= d)
+        return memcpy(d, s, len);
+
+    d += len-1;
+    s += len-1;
+    while (len--) {
+        *(char*)d = *(char*)s;
+        d--;
+        s--;
+    }
+
+    return d;
+}
+
+// Copy a string - truncating it if necessary.
+char *
+strtcpy(char *dest, const char *src, size_t len)
+{
+    char *d = dest;
+    while (--len && *src != '\0')
+        *d++ = *src++;
+    *d = '\0';
+    return dest;
+}
+
+// locate first occurance of character c in the string s
+char *
+strchr(const char *s, int c)
+{
+    for (; *s; s++)
+        if (*s == c)
+            return (char*)s;
+    return NULL;
+}
+
+// Remove any trailing blank characters (spaces, new lines, carriage returns)
+void
+nullTrailingSpace(char *buf)
+{
+    int len = strlen(buf);
+    char *end = &buf[len-1];
+    while (end >= buf && *end <= ' ')
+        *(end--) = '\0';
+}
+
+/****************************************************************
+ * Keyboard calls
+ ****************************************************************/
+
+// See if a keystroke is pending in the keyboard buffer.
+static int
+check_for_keystroke(void)
+{
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    br.ah = 1;
+    call16_int(0x16, &br);
+    return !(br.flags & F_ZF);
+}
+
+// Return a keystroke - waiting forever if necessary.
+static int
+get_raw_keystroke(void)
+{
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x16, &br);
+    return br.ah;
+}
+
+// Read a keystroke - waiting up to 'msec' milliseconds.
+int
+get_keystroke(int msec)
+{
+    u32 end = calc_future_timer(msec);
+    for (;;) {
+        if (check_for_keystroke())
+            return get_raw_keystroke();
+        if (check_timer(end))
+            return -1;
+        wait_irq();
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/util.h b/qemu-0.15.x/roms/seabios/src/util.h
new file mode 100644
index 0000000..2160b37
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/util.h
@@ -0,0 +1,500 @@
+// Basic x86 asm functions and function defs.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include "types.h" // u32
+
+static inline void irq_disable(void)
+{
+    asm volatile("cli": : :"memory");
+}
+
+static inline void irq_enable(void)
+{
+    asm volatile("sti": : :"memory");
+}
+
+static inline unsigned long irq_save(void)
+{
+    unsigned long flags;
+    asm volatile("pushfl ; popl %0" : "=g" (flags): :"memory");
+    irq_disable();
+    return flags;
+}
+
+static inline void irq_restore(unsigned long flags)
+{
+    asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
+}
+
+static inline void cpu_relax(void)
+{
+    asm volatile("rep ; nop": : :"memory");
+}
+
+static inline void nop(void)
+{
+    asm volatile("nop");
+}
+
+static inline void hlt(void)
+{
+    asm volatile("hlt": : :"memory");
+}
+
+static inline void wbinvd(void)
+{
+    asm volatile("wbinvd": : :"memory");
+}
+
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
+static inline void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+    asm("cpuid"
+        : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+        : "0" (index));
+}
+
+static inline u64 rdmsr(u32 index)
+{
+    u64 ret;
+    asm ("rdmsr" : "=A"(ret) : "c"(index));
+    return ret;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+    asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static inline u64 rdtscll(void)
+{
+    u64 val;
+    asm volatile("rdtsc" : "=A" (val));
+    return val;
+}
+
+static inline u32 __ffs(u32 word)
+{
+    asm("bsf %1,%0"
+        : "=r" (word)
+        : "rm" (word));
+    return word;
+}
+static inline u32 __fls(u32 word)
+{
+    asm("bsr %1,%0"
+        : "=r" (word)
+        : "rm" (word));
+    return word;
+}
+
+static inline u16 __htons_constant(u16 val) {
+    return (val<<8) | (val>>8);
+}
+static inline u32 __htonl_constant(u32 val) {
+    return (val<<24) | ((val&0xff00)<<8) | ((val&0xff0000)>>8) | (val>>24);
+}
+static inline u32 __htonl(u32 val) {
+    asm("bswapl %0" : "+r"(val));
+    return val;
+}
+#define htonl(x) (__builtin_constant_p((u32)(x)) ? __htonl_constant(x) : __htonl(x))
+#define ntohl(x) htonl(x)
+#define htons(x) __htons_constant(x)
+#define ntohs(x) htons(x)
+
+static inline u16 cpu_to_le16(u16 x)
+{
+    return x;
+}
+
+static inline u32 cpu_to_le32(u32 x)
+{
+    return x;
+}
+
+static inline u32 getesp(void) {
+    u32 esp;
+    asm("movl %%esp, %0" : "=rm"(esp));
+    return esp;
+}
+
+static inline void writel(void *addr, u32 val) {
+    *(volatile u32 *)addr = val;
+}
+static inline void writew(void *addr, u16 val) {
+    *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+    *(volatile u8 *)addr = val;
+}
+static inline u32 readl(const void *addr) {
+    return *(volatile const u32 *)addr;
+}
+static inline u16 readw(const void *addr) {
+    return *(volatile const u16 *)addr;
+}
+static inline u8 readb(const void *addr) {
+    return *(volatile const u8 *)addr;
+}
+
+#define call16_simpint(nr, peax, pflags) do {                           \
+        ASSERT16();                                                     \
+        asm volatile(                                                   \
+            "pushl %%ebp\n"                                             \
+            "sti\n"                                                     \
+            "stc\n"                                                     \
+            "int %2\n"                                                  \
+            "pushfl\n"                                                  \
+            "popl %1\n"                                                 \
+            "cli\n"                                                     \
+            "cld\n"                                                     \
+            "popl %%ebp"                                                \
+            : "+a"(*peax), "=c"(*pflags)                                \
+            : "i"(nr)                                                   \
+            : "ebx", "edx", "esi", "edi", "cc", "memory");              \
+    } while (0)
+
+// GDT bits
+#define GDT_CODE     (0x9bULL << 40) // Code segment - P,R,A bits also set
+#define GDT_DATA     (0x93ULL << 40) // Data segment - W,A bits also set
+#define GDT_B        (0x1ULL << 54)  // Big flag
+#define GDT_G        (0x1ULL << 55)  // Granularity flag
+// GDT bits for segment base
+#define GDT_BASE(v)  ((((u64)(v) & 0xff000000) << 32)           \
+                      | (((u64)(v) & 0x00ffffff) << 16))
+// GDT bits for segment limit (0-1Meg)
+#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32)   \
+                      | (((u64)(v) & 0x0000ffff) << 0))
+// GDT bits for segment limit (0-4Gig in 4K chunks)
+#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
+
+struct descloc_s {
+    u16 length;
+    u32 addr;
+} PACKED;
+
+// util.c
+struct bregs;
+inline void call16(struct bregs *callregs);
+inline void call16big(struct bregs *callregs);
+inline void __call16_int(struct bregs *callregs, u16 offset);
+#define call16_int(nr, callregs) do {                           \
+        extern void irq_trampoline_ ##nr ();                    \
+        __call16_int((callregs), (u32)&irq_trampoline_ ##nr );  \
+    } while (0)
+u8 checksum_far(u16 buf_seg, void *buf_far, u32 len);
+u8 checksum(void *buf, u32 len);
+size_t strlen(const char *s);
+int memcmp(const void *s1, const void *s2, size_t n);
+int strcmp(const char *s1, const char *s2);
+inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
+inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
+void *memset(void *s, int c, size_t n);
+void memset_fl(void *ptr, u8 val, size_t size);
+inline void memcpy_far(u16 d_seg, void *d_far
+                       , u16 s_seg, const void *s_far, size_t len);
+void memcpy_fl(void *d_fl, const void *s_fl, size_t len);
+void *memcpy(void *d1, const void *s1, size_t len);
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+void iomemcpy(void *d, const void *s, u32 len);
+void *memmove(void *d, const void *s, size_t len);
+char *strtcpy(char *dest, const char *src, size_t len);
+char *strchr(const char *s, int c);
+void nullTrailingSpace(char *buf);
+int get_keystroke(int msec);
+
+// stacks.c
+u32 call32(void *func, u32 eax, u32 errret);
+inline u32 stack_hop(u32 eax, u32 edx, void *func);
+extern struct thread_info MainThread;
+struct thread_info *getCurThread(void);
+void yield(void);
+void wait_irq(void);
+void run_thread(void (*func)(void*), void *data);
+void wait_threads(void);
+struct mutex_s { u32 isLocked; };
+void mutex_lock(struct mutex_s *mutex);
+void mutex_unlock(struct mutex_s *mutex);
+void start_preempt(void);
+void finish_preempt(void);
+int wait_preempt(void);
+void check_preempt(void);
+
+// output.c
+void debug_serial_setup(void);
+void panic(const char *fmt, ...)
+    __attribute__ ((format (printf, 1, 2))) __noreturn;
+void printf(const char *fmt, ...)
+    __attribute__ ((format (printf, 1, 2)));
+int snprintf(char *str, size_t size, const char *fmt, ...)
+    __attribute__ ((format (printf, 3, 4)));
+char * znprintf(size_t size, const char *fmt, ...)
+    __attribute__ ((format (printf, 2, 3)));
+void __dprintf(const char *fmt, ...)
+    __attribute__ ((format (printf, 1, 2)));
+void __debug_enter(struct bregs *regs, const char *fname);
+void __debug_isr(const char *fname);
+void __debug_stub(struct bregs *regs, int lineno, const char *fname);
+void __warn_invalid(struct bregs *regs, int lineno, const char *fname);
+void __warn_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __warn_internalerror(int lineno, const char *fname);
+void __warn_noalloc(int lineno, const char *fname);
+void __warn_timeout(int lineno, const char *fname);
+void __set_invalid(struct bregs *regs, int lineno, const char *fname);
+void __set_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname);
+void __set_code_unimplemented(struct bregs *regs, u32 linecode
+                              , const char *fname);
+void hexdump(const void *d, int len);
+
+#define dprintf(lvl, fmt, args...) do {                         \
+        if (CONFIG_DEBUG_LEVEL && (lvl) <= CONFIG_DEBUG_LEVEL)  \
+            __dprintf((fmt) , ##args );                         \
+    } while (0)
+#define debug_enter(regs, lvl) do {                     \
+        if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL)       \
+            __debug_enter((regs), __func__);            \
+    } while (0)
+#define debug_isr(lvl) do {                             \
+        if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL)       \
+            __debug_isr(__func__);                      \
+    } while (0)
+#define debug_stub(regs)                        \
+    __debug_stub((regs), __LINE__, __func__)
+#define warn_invalid(regs)                      \
+    __warn_invalid((regs), __LINE__, __func__)
+#define warn_unimplemented(regs)                        \
+    __warn_unimplemented((regs), __LINE__, __func__)
+#define warn_internalerror()                    \
+    __warn_internalerror(__LINE__, __func__)
+#define warn_noalloc()                          \
+    __warn_noalloc(__LINE__, __func__)
+#define warn_timeout()                          \
+    __warn_timeout(__LINE__, __func__)
+#define set_invalid(regs)                       \
+    __set_invalid((regs), __LINE__, __func__)
+#define set_code_invalid(regs, code)                                    \
+    __set_code_invalid((regs), (code) | (__LINE__ << 8), __func__)
+#define set_unimplemented(regs)                         \
+    __set_unimplemented((regs), __LINE__, __func__)
+#define set_code_unimplemented(regs, code)                              \
+    __set_code_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+// kbd.c
+void kbd_setup(void);
+void handle_15c2(struct bregs *regs);
+void process_key(u8 key);
+
+// mouse.c
+void mouse_setup(void);
+void process_mouse(u8 data);
+
+// system.c
+extern u32 RamSize;
+extern u64 RamSizeOver4G;
+void mathcp_setup(void);
+
+// serial.c
+void serial_setup(void);
+void lpt_setup(void);
+
+// clock.c
+#define PIT_TICK_RATE 1193180   // Underlying HZ of PIT
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+static inline int check_tsc(u64 end) {
+    return (s64)(rdtscll() - end) > 0;
+}
+void timer_setup(void);
+void ndelay(u32 count);
+void udelay(u32 count);
+void mdelay(u32 count);
+void nsleep(u32 count);
+void usleep(u32 count);
+void msleep(u32 count);
+u64 calc_future_tsc(u32 msecs);
+u64 calc_future_tsc_usec(u32 usecs);
+u32 calc_future_timer_ticks(u32 count);
+u32 calc_future_timer(u32 msecs);
+int check_timer(u32 end);
+void handle_1583(struct bregs *regs);
+void handle_1586(struct bregs *regs);
+void useRTC(void);
+void releaseRTC(void);
+
+// apm.c
+void apm_shutdown(void);
+void handle_1553(struct bregs *regs);
+
+// pcibios.c
+void handle_1ab1(struct bregs *regs);
+void bios32_setup(void);
+
+// shadow.c
+void make_bios_writable(void);
+void make_bios_readonly(void);
+void make_bios_writable_intel(u16 bdf, u32 pam0);
+void make_bios_readonly_intel(u16 bdf, u32 pam0);
+void qemu_prep_reset(void);
+
+// smm.c
+void smm_save_and_copy(void);
+void smm_relocate_and_restore(void);
+
+// pci_region.c
+// region allocator. pci region allocates the requested region
+// sequentially with overflow check.
+struct pci_region {
+    // The region is [first, last].
+    u32 first;
+    u32 last;
+
+    // The next allocation starts from here.
+    // i.e. [start, cur_first) is allocated.
+    // Right after initialization cur_first == first.
+    u32 cur_first;
+};
+// initialize the pci_region of [first, last]
+// last must not be 0xffffffff
+void pci_region_init(struct pci_region *r, u32 first, u32 last);
+// allocate the region of size
+u32 pci_region_alloc(struct pci_region *r, u32 size);
+// make the next allocation aligned to align
+u32 pci_region_align(struct pci_region *r, u32 align);
+// revert the allocation to addr.
+void pci_region_revert(struct pci_region *r, u32 addr);
+// make the allocation fail.
+u32 pci_region_disable(struct pci_region *r);
+// returns the current allocation point.
+u32 pci_region_addr(const struct pci_region *r);
+// returns the region size.
+u32 pci_region_size(const struct pci_region *r);
+
+// pciinit.c
+extern const u8 pci_irqs[4];
+void pci_bios_allocate_regions(u16 bdf, void *arg);
+void pci_setup(void);
+
+// smm.c
+void smm_init(void);
+
+// smp.c
+extern u32 CountCPUs;
+extern u32 MaxCountCPUs;
+void wrmsr_smp(u32 index, u64 val);
+void smp_probe(void);
+
+// coreboot.c
+struct cbfs_file;
+struct cbfs_file *cbfs_finddatafile(const char *fname);
+struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last);
+u32 cbfs_datasize(struct cbfs_file *file);
+const char *cbfs_filename(struct cbfs_file *file);
+int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen);
+void cbfs_run_payload(struct cbfs_file *file);
+void coreboot_copy_biostable(void);
+void cbfs_payload_setup(void);
+void coreboot_setup(void);
+
+// vgahooks.c
+extern int VGAbdf;
+void handle_155f(struct bregs *regs);
+void vgahook_setup(const char *vendor, const char *part);
+
+// optionroms.c
+void call_bcv(u16 seg, u16 ip);
+void optionrom_setup(void);
+void vga_setup(void);
+void s3_resume_vga_init(void);
+extern u32 RomEnd;
+
+// bootsplash.c
+void enable_vga_console(void);
+void enable_bootsplash(void);
+void disable_bootsplash(void);
+
+// resume.c
+void init_dma(void);
+
+// pnpbios.c
+#define PNP_SIGNATURE 0x506e5024 // $PnP
+u16 get_pnp_offset(void);
+void pnp_setup(void);
+
+// pmm.c
+extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+void malloc_setup(void);
+void malloc_finalize(void);
+void *pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align);
+int pmm_free(void *data);
+void pmm_setup(void);
+void pmm_finalize(void);
+#define PMM_DEFAULT_HANDLE 0xFFFFFFFF
+// Minimum alignment of malloc'd memory
+#define MALLOC_MIN_ALIGN 16
+// Helper functions for memory allocation.
+static inline void *malloc_low(u32 size) {
+    return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_high(u32 size) {
+    return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_fseg(u32 size) {
+    return pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmplow(u32 size) {
+    return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmphigh(u32 size) {
+    return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmp(u32 size) {
+    void *ret = malloc_tmphigh(size);
+    if (ret)
+        return ret;
+    return malloc_tmplow(size);
+}
+static inline void *memalign_low(u32 align, u32 size) {
+    return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_high(u32 align, u32 size) {
+    return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmplow(u32 align, u32 size) {
+    return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmphigh(u32 align, u32 size) {
+    return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmp(u32 align, u32 size) {
+    void *ret = memalign_tmphigh(align, size);
+    if (ret)
+        return ret;
+    return memalign_tmplow(align, size);
+}
+static inline void free(void *data) {
+    pmm_free(data);
+}
+
+// mtrr.c
+void mtrr_setup(void);
+
+// romlayout.S
+void reset_vector(void) __noreturn;
+
+// misc.c
+extern u8 BiosChecksum;
+
+// version (auto generated file out/version.c)
+extern const char VERSION[];
+
+#endif // util.h
diff --git a/qemu-0.15.x/roms/seabios/src/vgahooks.c b/qemu-0.15.x/roms/seabios/src/vgahooks.c
new file mode 100644
index 0000000..eb4dfa8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/vgahooks.c
@@ -0,0 +1,316 @@
+// Hooks for via vgabios calls into main bios.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // set_code_invalid
+#include "biosvar.h" // GET_GLOBAL
+#include "pci.h" // pci_find_device
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_VENDOR_ID_VIA
+#include "util.h" // handle_155f
+#include "config.h" // CONFIG_*
+
+// The Bus/Dev/Fn of the primary VGA device.
+int VGAbdf VAR16VISIBLE = -1;
+// Coreboot board detected.
+int CBmainboard VAR16VISIBLE;
+
+#define MAINBOARD_DEFAULT	0
+#define KONTRON_986LCD_M	1
+#define GETAC_P470		2
+#define RODA_RK886EX		3
+
+struct mainboards {
+	char *vendor;
+	char *device;
+	int type;
+};
+
+struct mainboards mainboard_list[] = {
+	{ "KONTRON",	"986LCD-M",	KONTRON_986LCD_M },
+	{ "GETAC",	"P470",		GETAC_P470 },
+	{ "RODA",	"RK886EX",	RODA_RK886EX },
+};
+
+static void
+handle_155fXX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+
+/****************************************************************
+ * Via hooks
+ ****************************************************************/
+
+static void
+via_155f01(struct bregs *regs)
+{
+    regs->eax = 0x5f;
+    regs->cl = 2; // panel type =  2 = 1024 * 768
+    set_success(regs);
+    dprintf(1, "Warning: VGA panel type is hardcoded\n");
+}
+
+static void
+via_155f02(struct bregs *regs)
+{
+    regs->eax = 0x5f;
+    regs->bx = 2;
+    regs->cx = 0x401;  // PAL + crt only
+    regs->dx = 0;  // TV Layout - default
+    set_success(regs);
+    dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
+}
+
+static int
+getFBSize(u16 bdf)
+{
+    /* FB config */
+    u8 reg = pci_config_readb(bdf, 0xa1);
+
+    /* GFX disabled ? */
+    if (!(reg & 0x80))
+        return -1;
+
+    static u8 mem_power[] VAR16 = {0, 3, 4, 5, 6, 7, 8, 9};
+    return GET_GLOBAL(mem_power[(reg >> 4) & 0x7]);
+}
+
+static int
+getViaRamSpeed(u16 bdf)
+{
+    return (pci_config_readb(bdf, 0x90) & 0x07) + 3;
+}
+
+static int
+getAMDRamSpeed(void)
+{
+    int bdf = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
+    if (bdf < 0)
+        return -1;
+
+    /* mem clk 0 = DDR2 400 */
+    return (pci_config_readb(bdf, 0x94) & 0x7) + 6;
+}
+
+/* int 0x15 - 5f18
+
+   ECX = unknown/dont care
+   EBX[3..0] Frame Buffer Size 2^N MiB
+   EBX[7..4] Memory speed:
+       0: SDR  66Mhz
+       1: SDR 100Mhz
+       2: SDR 133Mhz
+       3: DDR 100Mhz (PC1600 or DDR200)
+       4: DDR 133Mhz (PC2100 or DDR266)
+       5: DDR 166Mhz (PC2700 or DDR333)
+       6: DDR 200Mhz (PC3200 or DDR400)
+       7: DDR2 133Mhz (DDR2 533)
+       8: DDR2 166Mhz (DDR2 667)
+       9: DDR2 200Mhz (DDR2 800)
+       A: DDR2 233Mhz (DDR2 1066)
+       B: and above: Unknown
+   EBX[?..8] Total memory size?
+   EAX = 0x5f for success
+*/
+
+#define PCI_DEVICE_ID_VIA_K8M890CE_3    0x3336
+#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
+
+static void
+via_155f18(struct bregs *regs)
+{
+    int ramspeed, fbsize;
+
+    int bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_K8M890CE_3);
+    if (bdf >= 0) {
+        fbsize = getFBSize(bdf);
+        ramspeed = getAMDRamSpeed();
+        goto done;
+    }
+    bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
+    if (bdf >= 0) {
+        fbsize = getFBSize(bdf);
+        ramspeed = getViaRamSpeed(bdf);
+        goto done;
+    }
+
+    dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
+    fbsize = 5; // 32M frame buffer
+    ramspeed = 4; // MCLK = DDR266
+
+done:
+    if (fbsize < 0 || ramspeed < 0) {
+        set_code_invalid(regs, RET_EUNSUPPORTED);
+        return;
+    }
+    regs->eax = 0x5f;
+    regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
+    regs->ecx = 0x060;
+    set_success(regs);
+}
+
+static void
+via_155f19(struct bregs *regs)
+{
+    set_invalid_silent(regs);
+}
+
+static void
+via_155f(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x01: via_155f01(regs); break;
+    case 0x02: via_155f02(regs); break;
+    case 0x18: via_155f18(regs); break;
+    case 0x19: via_155f19(regs); break;
+    default:   handle_155fXX(regs); break;
+    }
+}
+
+/****************************************************************
+ * Intel VGA hooks
+ ****************************************************************/
+#define BOOT_DISPLAY_DEFAULT	(0)
+#define BOOT_DISPLAY_CRT        (1 << 0)
+#define BOOT_DISPLAY_TV         (1 << 1)
+#define BOOT_DISPLAY_EFP        (1 << 2)
+#define BOOT_DISPLAY_LCD        (1 << 3)
+#define BOOT_DISPLAY_CRT2       (1 << 4)
+#define BOOT_DISPLAY_TV2        (1 << 5)
+#define BOOT_DISPLAY_EFP2       (1 << 6)
+#define BOOT_DISPLAY_LCD2       (1 << 7)
+ 
+static void
+roda_155f35(struct bregs *regs)
+{
+    regs->ax = 0x005f;
+    // regs->cl = BOOT_DISPLAY_DEFAULT;
+    regs->cl = BOOT_DISPLAY_LCD;
+    set_success(regs);
+}
+
+static void
+roda_155f40(struct bregs *regs)
+{
+    u8 display_id;
+    //display_id = inb(0x60f) & 0x0f; // Correct according to Crete
+    display_id = 3; // Correct according to empirical studies
+
+    regs->ax = 0x005f;
+    regs->cl = display_id;
+    set_success(regs);
+}
+
+static void
+roda_155f(struct bregs *regs)
+{
+    dprintf(1, "Executing RODA specific interrupt %02x.\n", regs->al);
+    switch (regs->al) {
+    case 0x35: roda_155f35(regs); break;
+    case 0x40: roda_155f40(regs); break;
+    default:   handle_155fXX(regs); break;
+    }
+}
+
+static void
+kontron_155f35(struct bregs *regs)
+{
+    regs->ax = 0x005f;
+    regs->cl = BOOT_DISPLAY_CRT;
+    set_success(regs);
+}
+
+static void
+kontron_155f40(struct bregs *regs)
+{
+    u8 display_id;
+    display_id = 3;
+
+    regs->ax = 0x005f;
+    regs->cl = display_id;
+    set_success(regs);
+}
+
+static void
+kontron_155f(struct bregs *regs)
+{
+    dprintf(1, "Executing Kontron specific interrupt %02x.\n", regs->al);
+    switch (regs->al) {
+    case 0x35: kontron_155f35(regs); break;
+    case 0x40: kontron_155f40(regs); break;
+    default:   handle_155fXX(regs); break;
+    }
+}
+
+static void
+getac_155f(struct bregs *regs)
+{
+    dprintf(1, "Executing Getac specific interrupt %02x.\n", regs->al);
+    switch (regs->al) {
+    default:   handle_155fXX(regs); break;
+    }
+}
+
+/****************************************************************
+ * Entry and setup
+ ****************************************************************/
+
+// Main 16bit entry point
+void
+handle_155f(struct bregs *regs)
+{
+    int bdf, cbmb;
+
+    if (! CONFIG_VGAHOOKS)
+        goto fail;
+
+    cbmb = GET_GLOBAL(CBmainboard);
+
+    switch (cbmb) {
+    case KONTRON_986LCD_M:
+        kontron_155f(regs);
+	return;
+    case RODA_RK886EX:
+        roda_155f(regs);
+	return;
+    case GETAC_P470:
+        getac_155f(regs);
+	return;
+    case MAINBOARD_DEFAULT:
+        bdf = GET_GLOBAL(VGAbdf);
+        if (bdf < 0)
+            goto fail;
+
+        u16 vendor = pci_config_readw(bdf, PCI_VENDOR_ID);
+        if (vendor == PCI_VENDOR_ID_VIA) {
+            via_155f(regs);
+            return;
+        }
+    }
+
+fail:
+    handle_155fXX(regs);
+}
+
+// Setup
+void
+vgahook_setup(const char *vendor, const char *part)
+{
+    int i;
+
+    if (! CONFIG_VGAHOOKS)
+        return;
+
+    for (i=0; i<(sizeof(mainboard_list) / sizeof(mainboard_list[0])); i++) {
+        if (!strcmp(vendor, mainboard_list[i].vendor) &&
+            !strcmp(part, mainboard_list[i].device)) {
+            printf("Found mainboard %s %s\n", vendor, part);
+            CBmainboard = mainboard_list[i].type;
+            break;
+        }
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-blk.c b/qemu-0.15.x/roms/seabios/src/virtio-blk.c
new file mode 100644
index 0000000..bd9e2ad
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-blk.c
@@ -0,0 +1,184 @@
+// Virtio block boot support.
+//
+// Copyright (C) 2010 Red Hat Inc.
+//
+// Authors:
+//  Gleb Natapov <gnatapov at redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "boot.h" // boot_add_hd
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-blk.h"
+#include "disk.h"
+
+struct virtiodrive_s {
+    struct drive_s drive;
+    struct vring_virtqueue *vq;
+    u16 ioaddr;
+};
+
+static int
+virtio_blk_op(struct disk_op_s *op, int write)
+{
+    struct virtiodrive_s *vdrive_g =
+        container_of(op->drive_g, struct virtiodrive_s, drive);
+    struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq);
+    struct virtio_blk_outhdr hdr = {
+        .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
+        .ioprio = 0,
+        .sector = op->lba,
+    };
+    u8 status = VIRTIO_BLK_S_UNSUPP;
+    struct vring_list sg[] = {
+        {
+            .addr	= MAKE_FLATPTR(GET_SEG(SS), &hdr),
+            .length	= sizeof(hdr),
+        },
+        {
+            .addr	= op->buf_fl,
+            .length	= GET_GLOBAL(vdrive_g->drive.blksize) * op->count,
+        },
+        {
+            .addr	= MAKE_FLATPTR(GET_SEG(SS), &status),
+            .length	= sizeof(status),
+        },
+    };
+
+    /* Add to virtqueue and kick host */
+    if (write)
+        vring_add_buf(vq, sg, 2, 1, 0, 0);
+    else
+        vring_add_buf(vq, sg, 1, 2, 0, 0);
+    vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1);
+
+    /* Wait for reply */
+    while (!vring_more_used(vq))
+        usleep(5);
+
+    /* Reclaim virtqueue element */
+    vring_get_buf(vq, NULL);
+
+    /* Clear interrupt status register.  Avoid leaving interrupts stuck if
+     * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+     */
+    vp_get_isr(GET_GLOBAL(vdrive_g->ioaddr));
+
+    return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int
+process_virtio_op(struct disk_op_s *op)
+{
+    if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+        return 0;
+    switch (op->command) {
+    case CMD_READ:
+        return virtio_blk_op(op, 0);
+    case CMD_WRITE:
+        return virtio_blk_op(op, 1);
+    case CMD_FORMAT:
+    case CMD_RESET:
+    case CMD_ISREADY:
+    case CMD_VERIFY:
+    case CMD_SEEK:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+static void
+init_virtio_blk(u16 bdf)
+{
+    dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
+            pci_bdf_to_dev(bdf));
+    struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g));
+    struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+    if (!vdrive_g || !vq) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(vdrive_g, 0, sizeof(*vdrive_g));
+    memset(vq, 0, sizeof(*vq));
+    vdrive_g->drive.type = DTYPE_VIRTIO;
+    vdrive_g->drive.cntl_id = bdf;
+    vdrive_g->vq = vq;
+
+    u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
+        PCI_BASE_ADDRESS_IO_MASK;
+
+    vdrive_g->ioaddr = ioaddr;
+
+    vp_reset(ioaddr);
+    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+                  VIRTIO_CONFIG_S_DRIVER );
+
+    if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) {
+        dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
+                pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+        goto fail;
+    }
+
+    struct virtio_blk_config cfg;
+    vp_get(ioaddr, 0, &cfg, sizeof(cfg));
+
+    u32 f = vp_get_features(ioaddr);
+    vdrive_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+        cfg.blk_size : DISK_SECTOR_SIZE;
+
+    vdrive_g->drive.sectors = cfg.capacity;
+    dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
+            pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+            vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors);
+
+    if (vdrive_g->drive.blksize != DISK_SECTOR_SIZE) {
+        dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+                pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+                vdrive_g->drive.blksize);
+        goto fail;
+    }
+
+    vdrive_g->drive.pchs.cylinders = cfg.cylinders;
+    vdrive_g->drive.pchs.heads = cfg.heads;
+    vdrive_g->drive.pchs.spt = cfg.sectors;
+    char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x",
+                          pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+
+    boot_add_hd(&vdrive_g->drive, desc, bootprio_find_pci_device(bdf));
+
+    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+                  VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+    return;
+
+fail:
+    free(vdrive_g);
+    free(vq);
+}
+
+void
+virtio_blk_setup(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+        return;
+
+    dprintf(3, "init virtio-blk\n");
+
+    int bdf, max;
+    u32 id = PCI_VENDOR_ID_REDHAT_QUMRANET | (PCI_DEVICE_ID_VIRTIO_BLK << 16);
+    foreachpci(bdf, max) {
+        u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
+        if (v != id)
+            continue;
+        init_virtio_blk(bdf);
+    }
+}
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-blk.h b/qemu-0.15.x/roms/seabios/src/virtio-blk.h
new file mode 100644
index 0000000..7243704
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-blk.h
@@ -0,0 +1,43 @@
+#ifndef _VIRTIO_BLK_H
+#define _VIRTIO_BLK_H
+
+struct virtio_blk_config
+{
+    u64 capacity;
+    u32 size_max;
+    u32 seg_max;
+    u16 cylinders;
+    u8 heads;
+    u8 sectors;
+    u32 blk_size;
+    u8 physical_block_exp;
+    u8 alignment_offset;
+    u16 min_io_size;
+    u32 opt_io_size;
+} __attribute__((packed));
+
+#define VIRTIO_BLK_F_BLK_SIZE 6
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN		0
+#define VIRTIO_BLK_T_OUT	1
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr {
+    /* VIRTIO_BLK_T* */
+    u32 type;
+    /* io priority. */
+    u32 ioprio;
+    /* Sector (ie. 512 byte offset) */
+    u64 sector;
+};
+
+#define VIRTIO_BLK_S_OK		0
+#define VIRTIO_BLK_S_IOERR	1
+#define VIRTIO_BLK_S_UNSUPP	2
+
+struct disk_op_s;
+int process_virtio_op(struct disk_op_s *op);
+void virtio_blk_setup(void);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-pci.c b/qemu-0.15.x/roms/seabios/src/virtio-pci.c
new file mode 100644
index 0000000..db19e97
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-pci.c
@@ -0,0 +1,69 @@
+/* virtio-pci.c - pci interface for virtio interface
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ *  Copyright IBM Corp. 2007
+ *  Authors: Anthony Liguori  <aliguori at us.ibm.com>
+ *
+ *  Adopted for Seabios: Gleb Natapov <gleb at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "virtio-ring.h"
+#include "virtio-pci.h"
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "util.h" // dprintf
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq)
+{
+   struct vring * vr = &vq->vring;
+   u16 num;
+
+   ASSERT32FLAT();
+   /* select the queue */
+
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+   /* check if the queue is available */
+
+   num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+   if (!num) {
+       dprintf(1, "ERROR: queue size is 0\n");
+       return -1;
+   }
+
+   if (num > MAX_QUEUE_NUM) {
+       dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+       return -1;
+   }
+
+   /* check if the queue is already active */
+
+   if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+       dprintf(1, "ERROR: queue already active\n");
+       return -1;
+   }
+
+   vq->queue_index = queue_index;
+
+   /* initialize the queue */
+
+   vring_init(vr, num, (unsigned char*)&vq->queue);
+
+   /* activate the queue
+    *
+    * NOTE: vr->desc is initialized by vring_init()
+    */
+
+   outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+        ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+   return num;
+}
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-pci.h b/qemu-0.15.x/roms/seabios/src/virtio-pci.h
new file mode 100644
index 0000000..d21d5a5
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-pci.h
@@ -0,0 +1,104 @@
+#ifndef _VIRTIO_PCI_H
+#define _VIRTIO_PCI_H
+
+#include "ioport.h" // inl
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES        0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES       4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN            8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM            12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL            14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY         16
+
+/* An 8-bit device status register.  */
+#define VIRTIO_PCI_STATUS               18
+
+/* An 8-bit r/o interrupt status register.  Reading the value will return the
+ * current contents of the ISR and will also clear it.  This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR                  19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG           0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG               20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION          0
+
+static inline u32 vp_get_features(unsigned int ioaddr)
+{
+   return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+static inline void vp_set_features(unsigned int ioaddr, u32 features)
+{
+        outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+}
+
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
+                     void *buf, unsigned len)
+{
+   u8 *ptr = buf;
+   unsigned i;
+
+   for (i = 0; i < len; i++)
+           ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+}
+
+static inline u8 vp_get_status(unsigned int ioaddr)
+{
+   return inb(ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline void vp_set_status(unsigned int ioaddr, u8 status)
+{
+   if (status == 0)        /* reset */
+           return;
+   outb(status, ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline u8 vp_get_isr(unsigned int ioaddr)
+{
+   return inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_reset(unsigned int ioaddr)
+{
+   outb(0, ioaddr + VIRTIO_PCI_STATUS);
+   (void)inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_notify(unsigned int ioaddr, int queue_index)
+{
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
+{
+   /* select the queue */
+
+   outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+   /* deactivate the queue */
+
+   outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
+}
+
+struct vring_virtqueue;
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq);
+#endif /* _VIRTIO_PCI_H_ */
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-ring.c b/qemu-0.15.x/roms/seabios/src/virtio-ring.c
new file mode 100644
index 0000000..97a3ffe
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-ring.c
@@ -0,0 +1,151 @@
+/* virtio-pci.c - virtio ring management
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier at bull.net>
+ *
+ *  some parts from Linux Virtio Ring
+ *
+ *  Copyright Rusty Russell IBM Corporation 2007
+ *
+ *  Adopted for Seabios: Gleb Natapov <gleb at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ *
+ *
+ */
+
+#include "virtio-ring.h"
+#include "virtio-pci.h"
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+#define BUG() do {                                      \
+        dprintf(1, "BUG: failure at %s:%d/%s()!\n",     \
+                __FILE__, __LINE__, __func__);          \
+                while(1);                               \
+        } while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+
+/*
+ * vring_more_used
+ *
+ * is there some used buffers ?
+ *
+ */
+
+int vring_more_used(struct vring_virtqueue *vq)
+{
+    struct vring_used *used = GET_FLATPTR(vq->vring.used);
+    int more = GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(used->idx);
+    /* Make sure ring reads are done after idx read above. */
+    smp_rmb();
+    return more;
+}
+
+/*
+ * vring_free
+ *
+ * put at the begin of the free list the current desc[head]
+ */
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head)
+{
+    struct vring *vr = &vq->vring;
+    struct vring_desc *desc = GET_FLATPTR(vr->desc);
+    unsigned int i;
+
+    /* find end of given descriptor */
+
+    i = head;
+    while (GET_FLATPTR(desc[i].flags) & VRING_DESC_F_NEXT)
+        i = GET_FLATPTR(desc[i].next);
+
+    /* link it with free list and point to it */
+
+    SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head));
+    SET_FLATPTR(vq->free_head, head);
+}
+
+/*
+ * vring_get_buf
+ *
+ * get a buffer from the used list
+ *
+ */
+
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
+{
+    struct vring *vr = &vq->vring;
+    struct vring_used_elem *elem;
+    struct vring_used *used = GET_FLATPTR(vq->vring.used);
+    u32 id;
+    int ret;
+
+//    BUG_ON(!vring_more_used(vq));
+
+    elem = &used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)];
+    id = GET_FLATPTR(elem->id);
+    if (len != NULL)
+        *len = GET_FLATPTR(elem->len);
+
+    ret = GET_FLATPTR(vq->vdata[id]);
+
+    vring_detach(vq, id);
+
+    SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(vq->last_used_idx) + 1);
+
+    return ret;
+}
+
+void vring_add_buf(struct vring_virtqueue *vq,
+                   struct vring_list list[],
+                   unsigned int out, unsigned int in,
+                   int index, int num_added)
+{
+    struct vring *vr = &vq->vring;
+    int i, av, head, prev;
+    struct vring_desc *desc = GET_FLATPTR(vr->desc);
+    struct vring_avail *avail = GET_FLATPTR(vr->avail);
+
+    BUG_ON(out + in == 0);
+
+    prev = 0;
+    head = GET_FLATPTR(vq->free_head);
+    for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) {
+        SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT);
+        SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+        SET_FLATPTR(desc[i].len, list->length);
+        prev = i;
+        list++;
+    }
+    for ( ; in; i = GET_FLATPTR(desc[i].next), in--) {
+        SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
+        SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+        SET_FLATPTR(desc[i].len, list->length);
+        prev = i;
+        list++;
+    }
+    SET_FLATPTR(desc[prev].flags,
+                GET_FLATPTR(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+
+    SET_FLATPTR(vq->free_head, i);
+
+    SET_FLATPTR(vq->vdata[head], index);
+
+    av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num);
+    SET_FLATPTR(avail->ring[av], head);
+}
+
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+{
+    struct vring *vr = &vq->vring;
+    struct vring_avail *avail = GET_FLATPTR(vr->avail);
+
+    /* Make sure idx update is done after ring write. */
+    smp_wmb();
+    SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added);
+
+    vp_notify(ioaddr, GET_FLATPTR(vq->queue_index));
+}
diff --git a/qemu-0.15.x/roms/seabios/src/virtio-ring.h b/qemu-0.15.x/roms/seabios/src/virtio-ring.h
new file mode 100644
index 0000000..b7a7aaf
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/src/virtio-ring.h
@@ -0,0 +1,131 @@
+#ifndef _VIRTIO_RING_H
+#define _VIRTIO_RING_H
+
+#include "types.h" // u64
+#include "memmap.h" // PAGE_SIZE
+
+#define PAGE_SHIFT 12
+#define PAGE_MASK  (PAGE_SIZE-1)
+
+#define virt_to_phys(v) (unsigned long)(v)
+#define phys_to_virt(p) (void*)(p)
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER          2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK       4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED          0x80
+
+#define MAX_QUEUE_NUM      (128)
+
+#define VRING_DESC_F_NEXT  1
+#define VRING_DESC_F_WRITE 2
+
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+#define VRING_USED_F_NO_NOTIFY     1
+
+struct vring_desc
+{
+   u64 addr;
+   u32 len;
+   u16 flags;
+   u16 next;
+};
+
+struct vring_avail
+{
+   u16 flags;
+   u16 idx;
+   u16 ring[0];
+};
+
+struct vring_used_elem
+{
+   u32 id;
+   u32 len;
+};
+
+struct vring_used
+{
+   u16 flags;
+   u16 idx;
+   struct vring_used_elem ring[];
+};
+
+struct vring {
+   unsigned int num;
+   struct vring_desc *desc;
+   struct vring_avail *avail;
+   struct vring_used *used;
+};
+
+#define vring_size(num) \
+   (((((sizeof(struct vring_desc) * num) + \
+      (sizeof(struct vring_avail) + sizeof(u16) * num)) \
+         + PAGE_MASK) & ~PAGE_MASK) + \
+         (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+
+typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)];
+
+struct vring_virtqueue {
+   virtio_queue_t queue;
+   struct vring vring;
+   u16 free_head;
+   u16 last_used_idx;
+   u16 vdata[MAX_QUEUE_NUM];
+   /* PCI */
+   int queue_index;
+};
+
+struct vring_list {
+  char *addr;
+  unsigned int length;
+};
+
+static inline void vring_init(struct vring *vr,
+                         unsigned int num, unsigned char *queue)
+{
+   unsigned int i;
+   unsigned long pa;
+
+   ASSERT32FLAT();
+   vr->num = num;
+
+   /* physical address of desc must be page aligned */
+
+   pa = virt_to_phys(queue);
+   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+   vr->desc = phys_to_virt(pa);
+
+   vr->avail = (struct vring_avail *)&vr->desc[num];
+   /* disable interrupts */
+   vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+   /* physical address of used must be page aligned */
+
+   pa = virt_to_phys(&vr->avail->ring[num]);
+   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+   vr->used = phys_to_virt(pa);
+
+   for (i = 0; i < num - 1; i++)
+           vr->desc[i].next = i + 1;
+   vr->desc[i].next = 0;
+}
+
+int vring_more_used(struct vring_virtqueue *vq);
+void vring_detach(struct vring_virtqueue *vq, unsigned int head);
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
+void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
+                   unsigned int out, unsigned int in,
+                   int index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+
+#endif /* _VIRTIO_RING_H_ */
diff --git a/qemu-0.15.x/roms/seabios/tools/buildrom.py b/qemu-0.15.x/roms/seabios/tools/buildrom.py
new file mode 100755
index 0000000..19b715a
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/buildrom.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# Fill in checksum/size of an option rom, and pad it to proper length.
+#
+# Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+def alignpos(pos, alignbytes):
+    mask = alignbytes - 1
+    return (pos + mask) & ~mask
+
+def checksum(data):
+    ords = map(ord, data)
+    return sum(ords)
+
+def main():
+    inname = sys.argv[1]
+    outname = sys.argv[2]
+
+    # Read data in
+    f = open(inname, 'rb')
+    data = f.read()
+    count = len(data)
+
+    # Pad to a 512 byte boundary
+    data += "\0" * (alignpos(count, 512) - count)
+    count = len(data)
+
+    # Fill in size field; clear checksum field
+    data = data[:2] + chr(count/512) + data[3:6] + "\0" + data[7:]
+
+    # Checksum rom
+    newsum = (256 - checksum(data)) & 0xff
+    data = data[:6] + chr(newsum) + data[7:]
+
+    # Write new rom
+    f = open(outname, 'wb')
+    f.write(data)
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/checkrom.py b/qemu-0.15.x/roms/seabios/tools/checkrom.py
new file mode 100755
index 0000000..69d65e8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/checkrom.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Script to check a bios image and report info on it.
+#
+# Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import layoutrom
+
+def main():
+    # Get args
+    objinfo, rawfile, outfile = sys.argv[1:]
+
+    # Read in symbols
+    objinfofile = open(objinfo, 'rb')
+    symbols = layoutrom.parseObjDump(objinfofile, 'in')[1]
+
+    # Read in raw file
+    f = open(rawfile, 'rb')
+    rawdata = f.read()
+    f.close()
+    datasize = len(rawdata)
+    finalsize = 64*1024
+    if datasize > 64*1024:
+        finalsize = 128*1024
+        if datasize > 128*1024:
+            finalsize = 256*1024
+
+    # Sanity checks
+    start = symbols['code32flat_start'].offset
+    end = symbols['code32flat_end'].offset
+    expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
+    if end != expend:
+        print "Error!  Code does not end at 0x%x (got 0x%x)" % (
+            expend, end)
+        sys.exit(1)
+    if datasize > finalsize:
+        print "Error!  Code is too big (0x%x vs 0x%x)" % (
+            datasize, finalsize)
+        sys.exit(1)
+    expdatasize = end - start
+    if datasize != expdatasize:
+        print "Error!  Unknown extra data (0x%x vs 0x%x)" % (
+            datasize, expdatasize)
+        sys.exit(1)
+
+    # Print statistics
+    runtimesize = datasize
+    if '_reloc_abs_start' in symbols:
+        runtimesize = end - symbols['code32init_end'].offset
+    print "Total size: %d  Fixed: %d  Free: %d (used %.1f%% of %dKiB rom)" % (
+        datasize, runtimesize, finalsize - datasize
+        , (datasize / float(finalsize)) * 100.0
+        , finalsize / 1024)
+
+    # Write final file
+    f = open(outfile, 'wb')
+    f.write(("\0" * (finalsize - datasize)) + rawdata)
+    f.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/checkstack.py b/qemu-0.15.x/roms/seabios/tools/checkstack.py
new file mode 100755
index 0000000..428c296
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/checkstack.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# Script that tries to find how much stack space each function in an
+# object is using.
+#
+# Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+#   objdump -m i386 -M i8086 -M suffix -d out/rom16.o | tools/checkstack.py
+
+import sys
+import re
+
+# Functions that change stacks
+STACKHOP = ['__send_disk_op']
+# List of functions we can assume are never called.
+#IGNORE = ['panic', '__dprintf']
+IGNORE = ['panic']
+
+OUTPUTDESC = """
+#funcname1[preamble_stack_usage,max_usage_with_callers]:
+#    insn_addr:called_function [usage_at_call_point+caller_preamble,total_usage]
+#
+#funcname2[p,m,max_usage_to_yield_point]:
+#    insn_addr:called_function [u+c,t,usage_to_yield_point]
+"""
+
+# Find out maximum stack usage for a function
+def calcmaxstack(funcs, funcaddr):
+    info = funcs[funcaddr]
+    # Find max of all nested calls.
+    maxusage = info[1]
+    maxyieldusage = doesyield = 0
+    if info[3] is not None:
+        maxyieldusage = info[3]
+        doesyield = 1
+    info[2] = maxusage
+    info[4] = info[3]
+    seenbefore = {}
+    totcalls = 0
+    for insnaddr, calladdr, usage in info[6]:
+        callinfo = funcs.get(calladdr)
+        if callinfo is None:
+            continue
+        if callinfo[2] is None:
+            calcmaxstack(funcs, calladdr)
+        if callinfo[0] not in seenbefore:
+            seenbefore[callinfo[0]] = 1
+            totcalls += 1 + callinfo[5]
+        funcnameroot = callinfo[0].split('.')[0]
+        if funcnameroot in IGNORE:
+            # This called function is ignored - don't contribute it to
+            # the max stack.
+            continue
+        if funcnameroot in STACKHOP:
+            if usage > maxusage:
+                maxusage = usage
+            if callinfo[4] is not None:
+                doesyield = 1
+                if usage > maxyieldusage:
+                    maxyieldusage = usage
+            continue
+        totusage = usage + callinfo[2]
+        if totusage > maxusage:
+            maxusage = totusage
+        if callinfo[4] is not None:
+            doesyield = 1
+            totyieldusage = usage + callinfo[4]
+            if totyieldusage > maxyieldusage:
+                maxyieldusage = totyieldusage
+    info[2] = maxusage
+    if doesyield:
+        info[4] = maxyieldusage
+    info[5] = totcalls
+
+# Try to arrange output so that functions that call each other are
+# near each other.
+def orderfuncs(funcaddrs, availfuncs):
+    l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr)
+         for funcaddr in funcaddrs if funcaddr in availfuncs]
+    l.sort()
+    l.reverse()
+    out = []
+    while l:
+        count, name, funcaddr = l.pop(0)
+        if funcaddr not in availfuncs:
+            continue
+        calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]]
+        del availfuncs[funcaddr]
+        out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr]
+    return out
+
+# Update function info with a found "yield" point.
+def noteYield(info, stackusage):
+    prevyield = info[3]
+    if prevyield is None or prevyield < stackusage:
+        info[3] = stackusage
+
+# Update function info with a found "call" point.
+def noteCall(info, subfuncs, insnaddr, calladdr, stackusage):
+    if (calladdr, stackusage) in subfuncs:
+        # Already noted a nearly identical call - ignore this one.
+        return
+    info[6].append((insnaddr, calladdr, stackusage))
+    subfuncs[(calladdr, stackusage)] = 1
+
+hex_s = r'[0-9a-f]+'
+re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
+re_asm = re.compile(
+    r'^[ ]*(?P<insnaddr>' + hex_s
+    + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
+    + r') <(?P<ref>.*)>)?$')
+re_usestack = re.compile(
+    r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
+
+def calc():
+    # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
+    #                    , yieldusage, maxyieldusage, totalcalls
+    #                    , [(insnaddr, calladdr, stackusage), ...]]
+    funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]}
+    cur = None
+    atstart = 0
+    stackusage = 0
+
+    # Parse input lines
+    for line in sys.stdin.readlines():
+        m = re_func.match(line)
+        if m is not None:
+            # Found function
+            funcaddr = int(m.group('funcaddr'), 16)
+            funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []]
+            stackusage = 0
+            atstart = 1
+            subfuncs = {}
+            continue
+        m = re_asm.match(line)
+        if m is not None:
+            insn = m.group('insn')
+
+            im = re_usestack.match(insn)
+            if im is not None:
+                if insn.startswith('pushl') or insn.startswith('pushfl'):
+                    stackusage += 4
+                    continue
+                elif insn.startswith('pushw') or insn.startswith('pushfw'):
+                    stackusage += 2
+                    continue
+                stackusage += int(im.group('num'), 16)
+
+            if atstart:
+                if insn == 'movl   %esp,%ebp':
+                    # Still part of initial header
+                    continue
+                cur[1] = stackusage
+                atstart = 0
+
+            insnaddr = m.group('insnaddr')
+            calladdr = m.group('calladdr')
+            if calladdr is None:
+                if insn.startswith('lcallw'):
+                    noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4)
+                    noteYield(cur, stackusage + 4)
+                elif insn.startswith('int'):
+                    noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6)
+                    noteYield(cur, stackusage + 6)
+                elif insn.startswith('sti'):
+                    noteYield(cur, stackusage)
+                else:
+                    # misc instruction
+                    continue
+            else:
+                # Jump or call insn
+                calladdr = int(calladdr, 16)
+                ref = m.group('ref')
+                if '+' in ref:
+                    # Inter-function jump.
+                    pass
+                elif insn.startswith('j'):
+                    # Tail call
+                    noteCall(cur, subfuncs, insnaddr, calladdr, 0)
+                elif insn.startswith('calll'):
+                    noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4)
+                else:
+                    print "unknown call", ref
+                    noteCall(cur, subfuncs, insnaddr, calladdr, stackusage)
+            # Reset stack usage to preamble usage
+            stackusage = cur[1]
+
+        #print "other", repr(line)
+
+    # Calculate maxstackusage
+    for funcaddr, info in funcs.items():
+        if info[2] is not None:
+            continue
+        calcmaxstack(funcs, funcaddr)
+
+    # Sort functions for output
+    funcaddrs = orderfuncs(funcs.keys(), funcs.copy())
+
+    # Show all functions
+    print OUTPUTDESC
+    for funcaddr in funcaddrs:
+        name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \
+            funcs[funcaddr]
+        if maxusage == 0 and maxyieldusage is None:
+            continue
+        yieldstr = ""
+        if maxyieldusage is not None:
+            yieldstr = ",%d" % maxyieldusage
+        print "\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr)
+        for insnaddr, calladdr, stackusage in calls:
+            callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None))
+            yieldstr = ""
+            if callinfo[4] is not None:
+                yieldstr = ",%d" % (stackusage + callinfo[4])
+            print "    %04s:%-40s [%d+%d,%d%s]" % (
+                insnaddr, callinfo[0], stackusage, callinfo[1]
+                , stackusage+callinfo[2], yieldstr)
+
+def main():
+    calc()
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/checksum.py b/qemu-0.15.x/roms/seabios/tools/checksum.py
new file mode 100755
index 0000000..8c7665d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/checksum.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# Script to report the checksum of a file.
+#
+# Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+def main():
+    data = sys.stdin.read()
+    ords = map(ord, data)
+    print "sum=%x\n" % sum(ords)
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/gen-offsets.sh b/qemu-0.15.x/roms/seabios/tools/gen-offsets.sh
new file mode 100755
index 0000000..99fdc53
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/gen-offsets.sh
@@ -0,0 +1,17 @@
+:
+# Extract definitions from an assembler file.  This is based on code
+# from the Linux Kernel.
+INFILE=$1
+OUTFILE=$2
+cat > "$OUTFILE" <<EOF
+// This is an auto-generated file.  DO NOT EDIT!
+// Generated with "$0 $@"
+#ifndef __ASM_OFFSETS_H
+#define __ASM_OFFSETS_H
+EOF
+sed -ne "/^->/{s:->#\(.*\):/* \1 */:; \
+        s:^->\([^ ]*\) [\$\#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+        s:->::; p;}" < "$INFILE" >> "$OUTFILE"
+cat >> "$OUTFILE" <<EOF
+#endif // asm-offsets.h
+EOF
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/.gitignore b/qemu-0.15.x/roms/seabios/tools/kconfig/.gitignore
new file mode 100644
index 0000000..624f650
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/.gitignore
@@ -0,0 +1,23 @@
+#
+# Generated files
+#
+config*
+lex.*.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
+
+#
+# configuration programs
+#
+conf
+mconf
+nconf
+qconf
+gconf
+kxgettext
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/Makefile b/qemu-0.15.x/roms/seabios/tools/kconfig/Makefile
new file mode 100644
index 0000000..890243b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/Makefile
@@ -0,0 +1,361 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
+	localmodconfig localyesconfig
+
+ifdef KBUILD_KCONFIG
+Kconfig := $(KBUILD_KCONFIG)
+else
+Kconfig := Kconfig
+endif
+
+xconfig: $(obj)/qconf
+	$< $(Kconfig)
+
+gconfig: $(obj)/gconf
+	$< $(Kconfig)
+
+menuconfig: $(obj)/mconf
+	$< $(Kconfig)
+
+config: $(obj)/conf
+	$< --oldaskconfig $(Kconfig)
+
+nconfig: $(obj)/nconf
+	$< $(Kconfig)
+
+oldconfig: $(obj)/conf
+	$< --$@ $(Kconfig)
+
+silentoldconfig: $(obj)/conf
+	@echo "  Build Kconfig config file"
+	$(Q)mkdir -p include/generated
+	$(Q)$< --$@ $(Kconfig)
+
+# if no path is given, then use src directory to find file
+ifdef LSMOD
+LSMOD_F := $(LSMOD)
+ifeq ($(findstring /,$(LSMOD)),)
+  LSMOD_F := $(objtree)/$(LSMOD)
+endif
+endif
+
+localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+	$(Q)mkdir -p include/generated
+	$(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
+	$(Q)if [ -f .config ]; then 					\
+			cmp -s .tmp.config .config ||			\
+			(mv -f .config .config.old.1;			\
+			 mv -f .tmp.config .config;			\
+			 $(obj)/conf --silentoldconfig $(Kconfig);	\
+			 mv -f .config.old.1 .config.old)		\
+	else								\
+			mv -f .tmp.config .config;			\
+			$(obj)/conf --silentoldconfig $(Kconfig);	\
+	fi
+	$(Q)rm -f .tmp.config
+
+localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
+	$(Q)mkdir -p include/generated
+	$(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
+	$(Q)sed -i s/=m/=y/ .tmp.config
+	$(Q)if [ -f .config ]; then					\
+			cmp -s .tmp.config .config ||			\
+			(mv -f .config .config.old.1;			\
+			 mv -f .tmp.config .config;			\
+			 $(obj)/conf --silentoldconfig $(Kconfig);	\
+			 mv -f .config.old.1 .config.old)		\
+	else								\
+			mv -f .tmp.config .config;			\
+			$(obj)/conf --silentoldconfig $(Kconfig);	\
+	fi
+	$(Q)rm -f .tmp.config
+
+# Create new linux.pot file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+	$(Q)echo "  GEN config"
+	$(Q)xgettext --default-domain=linux              \
+	    --add-comments --keyword=_ --keyword=N_      \
+	    --from-code=UTF-8                            \
+	    --files-from=tools/kconfig/POTFILES.in     \
+	    --output $(obj)/config.pot
+	$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+	$(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+	$(Q)(for i in `ls arch/*/Kconfig`;               \
+	    do                                           \
+		echo "  GEN $$i";                        \
+		$(obj)/kxgettext $$i                     \
+		     >> $(obj)/config.pot;               \
+	    done )
+	$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+	    --output $(obj)/linux.pot
+	$(Q)rm -f arch/um/Kconfig.arch
+	$(Q)rm -f $(obj)/config.pot
+
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
+
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+	$< --$@ $(Kconfig)
+
+PHONY += listnewconfig oldnoconfig savedefconfig defconfig
+
+listnewconfig oldnoconfig: $(obj)/conf
+	$< --$@ $(Kconfig)
+
+savedefconfig: $(obj)/conf
+	$< --$@=defconfig $(Kconfig)
+
+defconfig: $(obj)/conf
+	@echo "  Build default config"
+	$(Q)$< --defconfig=/dev/null $(Kconfig)
+
+# Help text used by make help
+help:
+	@echo  '  config	  - Update current config utilising a line-oriented program'
+	@echo  '  nconfig         - Update current config utilising a ncurses menu based program'
+	@echo  '  menuconfig	  - Update current config utilising a menu based program'
+	@echo  '  xconfig	  - Update current config utilising a QT based front-end'
+	@echo  '  gconfig	  - Update current config utilising a GTK based front-end'
+	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
+	@echo  '  localmodconfig  - Update current config disabling modules not loaded'
+	@echo  '  localyesconfig  - Update current config converting local mods to core'
+	@echo  '  silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
+	@echo  '  defconfig	  - New config with default from ARCH supplied defconfig'
+	@echo  '  savedefconfig   - Save current config as ./defconfig (minimal config)'
+	@echo  '  allnoconfig	  - New config where all options are answered with no'
+	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
+	@echo  '  allmodconfig	  - New config selecting modules when possible'
+	@echo  '  alldefconfig    - New config with all symbols set to default'
+	@echo  '  randconfig	  - New config with random answer to all options'
+	@echo  '  listnewconfig   - List new options'
+	@echo  '  oldnoconfig     - Same as silentoldconfig but set new symbols to n (unset)'
+
+# lxdialog stuff
+check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# Use recursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                    -DLOCALE
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:	  Used for defconfig, oldconfig and related targets
+# nconf:  Used for the nconfig target.
+#         Utilizes ncurses
+# mconf:  Used for the menuconfig target
+#         Utilizes the lxdialog package
+# qconf:  Used for the xconfig target
+#         Based on QT which needs to be installed to compile it
+# gconf:  Used for the gconfig target
+#         Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs	:= conf.o  zconf.tab.o
+mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
+nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
+kxgettext-objs	:= kxgettext.o zconf.tab.o
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),nconfig)
+	hostprogs-y += nconf
+endif
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+	hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+	qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+	gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs	:= qconf.o
+qconf-objs	:= kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs	:= gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
+		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files     += mconf qconf gconf nconf
+clean-files     += config.pot linux.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(obj)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+	$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o	:= -I$(src)
+HOSTCFLAGS_zconf.tab.o	:= -I$(src)
+
+HOSTLOADLIBES_qconf	= $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o	= $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf	= `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTCFLAGS_gconf.o	= `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf	= -lmenu -lpanel -lncurses
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+	@set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
+	if ! pkg-config --exists QtCore 2> /dev/null; then \
+	    echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \
+	    pkg-config --exists qt 2> /dev/null && pkg=qt; \
+	    pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+	    if [ -n "$$pkg" ]; then \
+	      cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+	      libs="\$$(shell pkg-config $$pkg --libs)"; \
+	      moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+	      dir="$$(pkg-config $$pkg --variable=prefix)"; \
+	    else \
+	      for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+	        if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+	      done; \
+	      if [ -z "$$dir" ]; then \
+	        echo "*"; \
+	        echo "* Unable to find any QT installation. Please make sure that"; \
+	        echo "* the QT4 or QT3 development package is correctly installed and"; \
+	        echo "* either qmake can be found or install pkg-config or set"; \
+	        echo "* the QTDIR environment variable to the correct location."; \
+	        echo "*"; \
+	        false; \
+	      fi; \
+	      libpath=$$dir/lib; lib=qt; osdir=""; \
+	      $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+	        osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+	      test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+	      test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+	      cflags="-I$$dir/include"; \
+	      libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+	      moc="$$dir/bin/moc"; \
+	    fi; \
+	    if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+	      echo "*"; \
+	      echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+	      echo "*"; \
+	      moc="/usr/bin/moc"; \
+	    fi; \
+	else \
+	  cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
+	  libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
+	  binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \
+	  moc="$$binpath/bin/moc"; \
+	fi; \
+	echo "KC_QT_CFLAGS=$$cflags" > $@; \
+	echo "KC_QT_LIBS=$$libs" >> $@; \
+	echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+	@if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then		\
+		if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then			\
+			touch $@;								\
+		else									\
+			echo "*"; 							\
+			echo "* GTK+ is present but version >= 2.0.0 is required.";	\
+			echo "*";							\
+			false;								\
+		fi									\
+	else										\
+		echo "*"; 								\
+		echo "* Unable to find the GTK+ installation. Please make sure that"; 	\
+		echo "* the GTK+ 2.0 development package is correctly installed..."; 	\
+		echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; 		\
+		echo "*"; 								\
+		false;									\
+	fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+	$(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+	sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+	intltool-extract --type=gettext/glade $(obj)/gconf.glade
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+	bison -l -b $* -p $(notdir $*) $<
+	cp $@ $@_shipped
+
+lex.%.c: %.l
+	flex -L -P$(notdir $*) -o$@ $<
+	cp $@ $@_shipped
+
+%.hash.c: %.gperf
+	gperf < $< > $@
+	cp $@ $@_shipped
+
+endif
+
+VPATH := $(srctree)
+
+$(obj)/%:: $(src)/%_shipped
+	$(Q)cat $< > $@
+
+host-cobjs      := $(sort $(foreach m,$(hostprogs-y),$($(m)-objs)))
+host-cobjs      := $(addprefix $(obj)/,$(host-cobjs))
+hostprogs-y     := $(addprefix $(obj)/,$(hostprogs-y))
+$(host-cobjs) : $(obj)/%.o : $(src)/%.c
+	$(Q)$(HOSTCC) -I$(obj) -I$(srctree)/$(src) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(HOST_EXTRACFLAGS) -c -o $@ $<
+$(hostprogs-y) : $(obj)/% : $(host-cobjs)
+	$(Q)$(HOSTCC) $(HOSTLDFLAGS) -o $@ $(addprefix $(obj)/,$($(@F)-objs)) $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/POTFILES.in b/qemu-0.15.x/roms/seabios/tools/kconfig/POTFILES.in
new file mode 100644
index 0000000..f0baccd
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/POTFILES.in
@@ -0,0 +1,12 @@
+tools/kconfig/lxdialog/checklist.c
+tools/kconfig/lxdialog/inputbox.c
+tools/kconfig/lxdialog/menubox.c
+tools/kconfig/lxdialog/textbox.c
+tools/kconfig/lxdialog/util.c
+tools/kconfig/lxdialog/yesno.c
+tools/kconfig/mconf.c
+tools/kconfig/conf.c
+tools/kconfig/confdata.c
+tools/kconfig/gconf.c
+tools/kconfig/gconf.glade.h
+tools/kconfig/qconf.cc
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/check.sh b/qemu-0.15.x/roms/seabios/tools/kconfig/check.sh
new file mode 100755
index 0000000..fa59cbf
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/check.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+	gettext("");
+	return 0;
+}
+EOF
+if [ ! "$?" -eq "0"  ]; then
+	echo -DKBUILD_NO_NLS;
+fi
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/conf.c b/qemu-0.15.x/roms/seabios/tools/kconfig/conf.c
new file mode 100644
index 0000000..659326c
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/conf.c
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+	oldaskconfig,
+	silentoldconfig,
+	oldconfig,
+	allnoconfig,
+	allyesconfig,
+	allmodconfig,
+	alldefconfig,
+	randconfig,
+	defconfig,
+	savedefconfig,
+	listnewconfig,
+	oldnoconfig,
+} input_mode = oldaskconfig;
+
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	menu_get_ext_help(menu, &help);
+
+	printf("\n%s\n", str_get(&help));
+	str_free(&help);
+}
+
+static void strip(char *str)
+{
+	char *p = str;
+	int l;
+
+	while ((isspace(*p)))
+		p++;
+	l = strlen(p);
+	if (p != str)
+		memmove(str, p, l + 1);
+	if (!l)
+		return;
+	p = str + l - 1;
+	while ((isspace(*p)))
+		*p-- = 0;
+}
+
+static void check_stdin(void)
+{
+	if (!valid_stdin) {
+		printf(_("aborted!\n\n"));
+		printf(_("Console input/output is redirected. "));
+		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+		exit(1);
+	}
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+	enum symbol_type type = sym_get_type(sym);
+
+	if (!sym_has_value(sym))
+		printf(_("(NEW) "));
+
+	line[0] = '\n';
+	line[1] = 0;
+
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return 0;
+	}
+
+	switch (input_mode) {
+	case oldconfig:
+	case silentoldconfig:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return 0;
+		}
+		check_stdin();
+	case oldaskconfig:
+		fflush(stdout);
+		xfgets(line, 128, stdin);
+		return 1;
+	default:
+		break;
+	}
+
+	switch (type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		printf("%s\n", def);
+		return 1;
+	default:
+		;
+	}
+	printf("%s", line);
+	return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	const char *def;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		printf("(%s) ", sym->name);
+		def = sym_get_string_value(sym);
+		if (sym_get_string_value(sym))
+			printf("[%s] ", def);
+		if (!conf_askvalue(sym, def))
+			return 0;
+		switch (line[0]) {
+		case '\n':
+			break;
+		case '?':
+			/* print help */
+			if (line[1] == '\n') {
+				print_help(menu);
+				def = NULL;
+				break;
+			}
+		default:
+			line[strlen(line)-1] = 0;
+			def = line;
+		}
+		if (def && sym_set_string_value(sym, def))
+			return 0;
+	}
+}
+
+static int conf_sym(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	tristate oldval, newval;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		if (sym->name)
+			printf("(%s) ", sym->name);
+		putchar('[');
+		oldval = sym_get_tristate_value(sym);
+		switch (oldval) {
+		case no:
+			putchar('N');
+			break;
+		case mod:
+			putchar('M');
+			break;
+		case yes:
+			putchar('Y');
+			break;
+		}
+		if (oldval != no && sym_tristate_within_range(sym, no))
+			printf("/n");
+		if (oldval != mod && sym_tristate_within_range(sym, mod))
+			printf("/m");
+		if (oldval != yes && sym_tristate_within_range(sym, yes))
+			printf("/y");
+		if (menu_has_help(menu))
+			printf("/?");
+		printf("] ");
+		if (!conf_askvalue(sym, sym_get_string_value(sym)))
+			return 0;
+		strip(line);
+
+		switch (line[0]) {
+		case 'n':
+		case 'N':
+			newval = no;
+			if (!line[1] || !strcmp(&line[1], "o"))
+				break;
+			continue;
+		case 'm':
+		case 'M':
+			newval = mod;
+			if (!line[1])
+				break;
+			continue;
+		case 'y':
+		case 'Y':
+			newval = yes;
+			if (!line[1] || !strcmp(&line[1], "es"))
+				break;
+			continue;
+		case 0:
+			newval = oldval;
+			break;
+		case '?':
+			goto help;
+		default:
+			continue;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			return 0;
+help:
+		print_help(menu);
+	}
+}
+
+static int conf_choice(struct menu *menu)
+{
+	struct symbol *sym, *def_sym;
+	struct menu *child;
+	bool is_new;
+
+	sym = menu->sym;
+	is_new = !sym_has_value(sym);
+	if (sym_is_changable(sym)) {
+		conf_sym(menu);
+		sym_calc_value(sym);
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			return 0;
+		case yes:
+			break;
+		}
+	} else {
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+			return 0;
+		case yes:
+			break;
+		}
+	}
+
+	while (1) {
+		int cnt, def;
+
+		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+		def_sym = sym_get_choice_value(sym);
+		cnt = def = 0;
+		line[0] = 0;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (!child->sym) {
+				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+				continue;
+			}
+			cnt++;
+			if (child->sym == def_sym) {
+				def = cnt;
+				printf("%*c", indent, '>');
+			} else
+				printf("%*c", indent, ' ');
+			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+			if (child->sym->name)
+				printf(" (%s)", child->sym->name);
+			if (!sym_has_value(child->sym))
+				printf(_(" (NEW)"));
+			printf("\n");
+		}
+		printf(_("%*schoice"), indent - 1, "");
+		if (cnt == 1) {
+			printf("[1]: 1\n");
+			goto conf_childs;
+		}
+		printf("[1-%d", cnt);
+		if (menu_has_help(menu))
+			printf("?");
+		printf("]: ");
+		switch (input_mode) {
+		case oldconfig:
+		case silentoldconfig:
+			if (!is_new) {
+				cnt = def;
+				printf("%d\n", cnt);
+				break;
+			}
+			check_stdin();
+		case oldaskconfig:
+			fflush(stdout);
+			xfgets(line, 128, stdin);
+			strip(line);
+			if (line[0] == '?') {
+				print_help(menu);
+				continue;
+			}
+			if (!line[0])
+				cnt = def;
+			else if (isdigit(line[0]))
+				cnt = atoi(line);
+			else
+				continue;
+			break;
+		default:
+			break;
+		}
+
+	conf_childs:
+		for (child = menu->list; child; child = child->next) {
+			if (!child->sym || !menu_is_visible(child))
+				continue;
+			if (!--cnt)
+				break;
+		}
+		if (!child)
+			continue;
+		if (line[strlen(line) - 1] == '?') {
+			print_help(child);
+			continue;
+		}
+		sym_set_choice_value(sym, child->sym);
+		for (child = child->list; child; child = child->next) {
+			indent += 2;
+			conf(child);
+			indent -= 2;
+		}
+		return 1;
+	}
+}
+
+static void conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (prop) {
+		const char *prompt;
+
+		switch (prop->type) {
+		case P_MENU:
+			if ((input_mode == silentoldconfig ||
+			     input_mode == listnewconfig ||
+			     input_mode == oldnoconfig) &&
+			    rootEntry != menu) {
+				check_conf(menu);
+				return;
+			}
+		case P_COMMENT:
+			prompt = menu_get_prompt(menu);
+			if (prompt)
+				printf("%*c\n%*c %s\n%*c\n",
+					indent, '*',
+					indent, '*', _(prompt),
+					indent, '*');
+		default:
+			;
+		}
+	}
+
+	if (!sym)
+		goto conf_childs;
+
+	if (sym_is_choice(sym)) {
+		conf_choice(menu);
+		if (sym->curr.tri != mod)
+			return;
+		goto conf_childs;
+	}
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		conf_string(menu);
+		break;
+	default:
+		conf_sym(menu);
+		break;
+	}
+
+conf_childs:
+	if (sym)
+		indent += 2;
+	for (child = menu->list; child; child = child->next)
+		conf(child);
+	if (sym)
+		indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	if (sym && !sym_has_value(sym)) {
+		if (sym_is_changable(sym) ||
+		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+			if (input_mode == listnewconfig) {
+				if (sym->name && !sym_is_choice_value(sym)) {
+					printf("%s%s\n", CONFIG_, sym->name);
+				}
+			} else if (input_mode != oldnoconfig) {
+				if (!conf_cnt++)
+					printf(_("*\n* Restart config...\n*\n"));
+				rootEntry = menu_get_parent_menu(menu);
+				conf(rootEntry);
+			}
+		}
+	}
+
+	for (child = menu->list; child; child = child->next)
+		check_conf(child);
+}
+
+static struct option long_opts[] = {
+	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
+	{"oldconfig",       no_argument,       NULL, oldconfig},
+	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
+	{"defconfig",       optional_argument, NULL, defconfig},
+	{"savedefconfig",   required_argument, NULL, savedefconfig},
+	{"allnoconfig",     no_argument,       NULL, allnoconfig},
+	{"allyesconfig",    no_argument,       NULL, allyesconfig},
+	{"allmodconfig",    no_argument,       NULL, allmodconfig},
+	{"alldefconfig",    no_argument,       NULL, alldefconfig},
+	{"randconfig",      no_argument,       NULL, randconfig},
+	{"listnewconfig",   no_argument,       NULL, listnewconfig},
+	{"oldnoconfig",     no_argument,       NULL, oldnoconfig},
+	{NULL, 0, NULL, 0}
+};
+
+int main(int ac, char **av)
+{
+	int opt;
+	const char *name;
+	struct stat tmpstat;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
+		input_mode = (enum input_mode)opt;
+		switch (opt) {
+		case silentoldconfig:
+			sync_kconfig = 1;
+			break;
+		case defconfig:
+		case savedefconfig:
+			defconfig_file = optarg;
+			break;
+		case randconfig:
+		{
+			struct timeval now;
+			unsigned int seed;
+
+			/*
+			 * Use microseconds derived seed,
+			 * compensate for systems where it may be zero
+			 */
+			gettimeofday(&now, NULL);
+
+			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+			srand(seed);
+			break;
+		}
+		case '?':
+			fprintf(stderr, _("See README for usage info\n"));
+			exit(1);
+			break;
+		}
+	}
+	if (ac == optind) {
+		printf(_("%s: Kconfig file missing\n"), av[0]);
+		exit(1);
+	}
+	name = av[optind];
+	conf_parse(name);
+	//zconfdump(stdout);
+	if (sync_kconfig) {
+		name = conf_get_configname();
+		if (stat(name, &tmpstat)) {
+			fprintf(stderr, _("***\n"
+				"*** Configuration file \"%s\" not found!\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"), name);
+			exit(1);
+		}
+	}
+
+	switch (input_mode) {
+	case defconfig:
+		if (!defconfig_file)
+			defconfig_file = conf_get_default_confname();
+		if (conf_read(defconfig_file)) {
+			printf(_("***\n"
+				"*** Can't find default configuration \"%s\"!\n"
+				"***\n"), defconfig_file);
+			exit(1);
+		}
+		break;
+	case savedefconfig:
+	case silentoldconfig:
+	case oldaskconfig:
+	case oldconfig:
+	case listnewconfig:
+	case oldnoconfig:
+		conf_read(NULL);
+		break;
+	case allnoconfig:
+	case allyesconfig:
+	case allmodconfig:
+	case alldefconfig:
+	case randconfig:
+		name = getenv("KCONFIG_ALLCONFIG");
+		if (name && !stat(name, &tmpstat)) {
+			conf_read_simple(name, S_DEF_USER);
+			break;
+		}
+		switch (input_mode) {
+		case allnoconfig:	name = "allno.config"; break;
+		case allyesconfig:	name = "allyes.config"; break;
+		case allmodconfig:	name = "allmod.config"; break;
+		case alldefconfig:	name = "alldef.config"; break;
+		case randconfig:	name = "allrandom.config"; break;
+		default: break;
+		}
+		if (!stat(name, &tmpstat))
+			conf_read_simple(name, S_DEF_USER);
+		else if (!stat("all.config", &tmpstat))
+			conf_read_simple("all.config", S_DEF_USER);
+		break;
+	default:
+		break;
+	}
+
+	if (sync_kconfig) {
+		if (conf_get_changed()) {
+			name = getenv("KCONFIG_NOSILENTUPDATE");
+			if (name && *name) {
+				fprintf(stderr,
+					_("\n*** The configuration requires explicit update.\n\n"));
+				return 1;
+			}
+		}
+		valid_stdin = isatty(0) && isatty(1) && isatty(2);
+	}
+
+	switch (input_mode) {
+	case allnoconfig:
+		conf_set_all_new_symbols(def_no);
+		break;
+	case allyesconfig:
+		conf_set_all_new_symbols(def_yes);
+		break;
+	case allmodconfig:
+		conf_set_all_new_symbols(def_mod);
+		break;
+	case alldefconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case randconfig:
+		conf_set_all_new_symbols(def_random);
+		break;
+	case defconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case savedefconfig:
+		break;
+	case oldaskconfig:
+		rootEntry = &rootmenu;
+		conf(&rootmenu);
+		input_mode = silentoldconfig;
+		/* fall through */
+	case oldconfig:
+	case listnewconfig:
+	case oldnoconfig:
+	case silentoldconfig:
+		/* Update until a loop caused no more changes */
+		do {
+			conf_cnt = 0;
+			check_conf(&rootmenu);
+		} while (conf_cnt &&
+			 (input_mode != listnewconfig &&
+			  input_mode != oldnoconfig));
+		break;
+	}
+
+	if (sync_kconfig) {
+		/* silentoldconfig is used during the build so we shall update autoconf.
+		 * All other commands are only used to generate a config.
+		 */
+		if (conf_get_changed() && conf_write(NULL)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
+		if (conf_write_autoconf()) {
+			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+			return 1;
+		}
+	} else if (input_mode == savedefconfig) {
+		if (conf_write_defconfig(defconfig_file)) {
+			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+			        defconfig_file);
+			return 1;
+		}
+	} else if (input_mode != listnewconfig) {
+		if (conf_write(NULL)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
+	}
+	return 0;
+}
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(str, size, in)
+	char *str;
+	int size;
+	FILE *in;
+{
+	if (fgets(str, size, in) == NULL)
+		fprintf(stderr, "\nError in reading or end of file.\n");
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/confdata.c b/qemu-0.15.x/roms/seabios/tools/kconfig/confdata.c
new file mode 100644
index 0000000..f110bf5
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/confdata.c
@@ -0,0 +1,1062 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *fmt, va_list ap)
+{
+	printf("#\n# ");
+	vprintf(fmt, ap);
+	printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+	conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+	conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (conf_message_callback)
+		conf_message_callback(fmt, ap);
+}
+
+const char *conf_get_configname(void)
+{
+	char *name = getenv("KCONFIG_CONFIG");
+
+	return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+	char *name = getenv("KCONFIG_AUTOCONFIG");
+
+	return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+	struct symbol *sym;
+	const char *src;
+	static char res_value[SYMBOL_MAXLENGTH];
+	char *dst, name[SYMBOL_MAXLENGTH];
+
+	res_value[0] = 0;
+	dst = name;
+	while ((src = strchr(in, '$'))) {
+		strncat(res_value, in, src - in);
+		src++;
+		dst = name;
+		while (isalnum(*src) || *src == '_')
+			*dst++ = *src++;
+		*dst = 0;
+		sym = sym_lookup(name, 0);
+		sym_calc_value(sym);
+		strcat(res_value, sym_get_string_value(sym));
+		in = src;
+	}
+	strcat(res_value, in);
+
+	return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+	struct stat buf;
+	static char fullname[PATH_MAX+1];
+	char *env, *name;
+
+	name = conf_expand_value(conf_defname);
+	env = getenv(SRCTREE);
+	if (env) {
+		sprintf(fullname, "%s/%s", env, name);
+		if (!stat(fullname, &buf))
+			return fullname;
+	}
+	return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+	char *p2;
+
+	switch (sym->type) {
+	case S_TRISTATE:
+		if (p[0] == 'm') {
+			sym->def[def].tri = mod;
+			sym->flags |= def_flags;
+			break;
+		}
+	case S_BOOLEAN:
+		if (p[0] == 'y') {
+			sym->def[def].tri = yes;
+			sym->flags |= def_flags;
+			break;
+		}
+		if (p[0] == 'n') {
+			sym->def[def].tri = no;
+			sym->flags |= def_flags;
+			break;
+		}
+		conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+		break;
+	case S_OTHER:
+		if (*p != '"') {
+			for (p2 = p; *p2 && !isspace(*p2); p2++)
+				;
+			sym->type = S_STRING;
+			goto done;
+		}
+	case S_STRING:
+		if (*p++ != '"')
+			break;
+		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+			if (*p2 == '"') {
+				*p2 = 0;
+				break;
+			}
+			memmove(p2, p2 + 1, strlen(p2));
+		}
+		if (!p2) {
+			conf_warning("invalid string found");
+			return 1;
+		}
+	case S_INT:
+	case S_HEX:
+	done:
+		if (sym_string_valid(sym, p)) {
+			sym->def[def].val = strdup(p);
+			sym->flags |= def_flags;
+		} else {
+			conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+			return 1;
+		}
+		break;
+	default:
+		;
+	}
+	return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+	FILE *in = NULL;
+	char line[1024];
+	char *p, *p2;
+	struct symbol *sym;
+	int i, def_flags;
+
+	if (name) {
+		in = zconf_fopen(name);
+	} else {
+		struct property *prop;
+
+		name = conf_get_configname();
+		in = zconf_fopen(name);
+		if (in)
+			goto load;
+		sym_add_change_count(1);
+		if (!sym_defconfig_list) {
+			if (modules_sym)
+				sym_calc_value(modules_sym);
+			return 1;
+		}
+
+		for_all_defaults(sym_defconfig_list, prop) {
+			if (expr_calc_value(prop->visible.expr) == no ||
+			    prop->expr->type != E_SYMBOL)
+				continue;
+			name = conf_expand_value(prop->expr->left.sym->name);
+			in = zconf_fopen(name);
+			if (in) {
+				conf_message(_("using defaults found in %s"),
+					 name);
+				goto load;
+			}
+		}
+	}
+	if (!in)
+		return 1;
+
+load:
+	conf_filename = name;
+	conf_lineno = 0;
+	conf_warnings = 0;
+	conf_unsaved = 0;
+
+	def_flags = SYMBOL_DEF << def;
+	for_all_symbols(i, sym) {
+		sym->flags |= SYMBOL_CHANGED;
+		sym->flags &= ~(def_flags|SYMBOL_VALID);
+		if (sym_is_choice(sym))
+			sym->flags |= def_flags;
+		switch (sym->type) {
+		case S_INT:
+		case S_HEX:
+		case S_STRING:
+			if (sym->def[def].val)
+				free(sym->def[def].val);
+		default:
+			sym->def[def].val = NULL;
+			sym->def[def].tri = no;
+		}
+	}
+
+	while (fgets(line, sizeof(line), in)) {
+		conf_lineno++;
+		sym = NULL;
+		if (line[0] == '#') {
+			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+				continue;
+			p = strchr(line + 2 + strlen(CONFIG_), ' ');
+			if (!p)
+				continue;
+			*p++ = 0;
+			if (strncmp(p, "is not set", 10))
+				continue;
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 2 + strlen(CONFIG_));
+				if (!sym) {
+					sym_add_change_count(1);
+					goto setsym;
+				}
+			} else {
+				sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_BOOLEAN;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("override: reassigning to symbol %s", sym->name);
+			}
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				sym->def[def].tri = no;
+				sym->flags |= def_flags;
+				break;
+			default:
+				;
+			}
+		} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+			p = strchr(line + strlen(CONFIG_), '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+			p2 = strchr(p, '\n');
+			if (p2) {
+				*p2-- = 0;
+				if (*p2 == '\r')
+					*p2 = 0;
+			}
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + strlen(CONFIG_));
+				if (!sym) {
+					sym_add_change_count(1);
+					goto setsym;
+				}
+			} else {
+				sym = sym_lookup(line + strlen(CONFIG_), 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_OTHER;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("override: reassigning to symbol %s", sym->name);
+			}
+			if (conf_set_sym_val(sym, def, def_flags, p))
+				continue;
+		} else {
+			if (line[0] != '\r' && line[0] != '\n')
+				conf_warning("unexpected data");
+			continue;
+		}
+setsym:
+		if (sym && sym_is_choice_value(sym)) {
+			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+			switch (sym->def[def].tri) {
+			case no:
+				break;
+			case mod:
+				if (cs->def[def].tri == yes) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags &= ~def_flags;
+				}
+				break;
+			case yes:
+				if (cs->def[def].tri != no)
+					conf_warning("override: %s changes choice state", sym->name);
+				cs->def[def].val = sym;
+				break;
+			}
+			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+		}
+	}
+	fclose(in);
+
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+	return 0;
+}
+
+int conf_read(const char *name)
+{
+	struct symbol *sym, *choice_sym;
+	struct property *prop;
+	struct expr *e;
+	int i, flags;
+
+	sym_set_change_count(0);
+
+	if (conf_read_simple(name, S_DEF_USER))
+		return 1;
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+			goto sym_ok;
+		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+			/* check that calculated value agrees with saved value */
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+					break;
+				if (!sym_is_choice(sym))
+					goto sym_ok;
+			default:
+				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+					goto sym_ok;
+				break;
+			}
+		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+			/* no previous value and not saved */
+			goto sym_ok;
+		conf_unsaved++;
+		/* maybe print value in verbose mode... */
+	sym_ok:
+		if (!sym_is_choice(sym))
+			continue;
+		/* The choice symbol only has a set value (and thus is not new)
+		 * if all its visible childs have values.
+		 */
+		prop = sym_get_choice_prop(sym);
+		flags = sym->flags;
+		expr_list_for_each_sym(prop->expr, e, choice_sym)
+			if (choice_sym->visible != no)
+				flags &= choice_sym->flags;
+		sym->flags &= flags | ~SYMBOL_DEF_USER;
+	}
+
+	for_all_symbols(i, sym) {
+		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+			/* Reset values of generates values, so they'll appear
+			 * as new, if they should become visible, but that
+			 * doesn't quite work if the Kconfig and the saved
+			 * configuration disagree.
+			 */
+			if (sym->visible == no && !conf_unsaved)
+				sym->flags &= ~SYMBOL_DEF_USER;
+			switch (sym->type) {
+			case S_STRING:
+			case S_INT:
+			case S_HEX:
+				/* Reset a string value if it's out of range */
+				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+					break;
+				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+				conf_unsaved++;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	sym_add_change_count(conf_warnings || conf_unsaved);
+
+	return 0;
+}
+
+/* Write a S_STRING */
+static void conf_write_string(bool headerfile, const char *name,
+                              const char *str, FILE *out)
+{
+	int l;
+	if (headerfile)
+		fprintf(out, "#define %s%s \"", CONFIG_, name);
+	else
+		fprintf(out, "%s%s=\"", CONFIG_, name);
+
+	while (1) {
+		l = strcspn(str, "\"\\");
+		if (l) {
+			xfwrite(str, l, 1, out);
+			str += l;
+		}
+		if (!*str)
+			break;
+		fprintf(out, "\\%c", *str++);
+	}
+	fputs("\"\n", out);
+}
+
+static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+{
+	const char *str;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			if (write_no)
+				fprintf(out, "# %s%s is not set\n",
+				    CONFIG_, sym->name);
+			break;
+		case mod:
+			fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
+			break;
+		case yes:
+			fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+			break;
+		}
+		break;
+	case S_STRING:
+		conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+		break;
+	case S_HEX:
+	case S_INT:
+		str = sym_get_string_value(sym);
+		fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+		break;
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	}
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+	struct symbol *sym;
+	struct menu *menu;
+	FILE *out;
+
+	out = fopen(filename, "w");
+	if (!out)
+		return 1;
+
+	sym_clear_all_valid();
+
+	/* Traverse all menus to find all relevant symbols */
+	menu = rootmenu.list;
+
+	while (menu != NULL)
+	{
+		sym = menu->sym;
+		if (sym == NULL) {
+			if (!menu_is_visible(menu))
+				goto next_menu;
+		} else if (!sym_is_choice(sym)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & SYMBOL_WRITE))
+				goto next_menu;
+			sym->flags &= ~SYMBOL_WRITE;
+			/* If we cannot change the symbol - skip */
+			if (!sym_is_changable(sym))
+				goto next_menu;
+			/* If symbol equals to default value - skip */
+			if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+				goto next_menu;
+
+			/*
+			 * If symbol is a choice value and equals to the
+			 * default for a choice - skip.
+			 * But only if value is bool and equal to "y" and
+			 * choice is not "optional".
+			 * (If choice is "optional" then all values can be "n")
+			 */
+			if (sym_is_choice_value(sym)) {
+				struct symbol *cs;
+				struct symbol *ds;
+
+				cs = prop_get_symbol(sym_get_choice_prop(sym));
+				ds = sym_choice_default(cs);
+				if (!sym_is_optional(cs) && sym == ds) {
+					if ((sym->type == S_BOOLEAN) &&
+					    sym_get_tristate_value(sym) == yes)
+						goto next_menu;
+				}
+			}
+			conf_write_symbol(sym, out, true);
+		}
+next_menu:
+		if (menu->list != NULL) {
+			menu = menu->list;
+		}
+		else if (menu->next != NULL) {
+			menu = menu->next;
+		} else {
+			while ((menu = menu->parent)) {
+				if (menu->next != NULL) {
+					menu = menu->next;
+					break;
+				}
+			}
+		}
+	}
+	fclose(out);
+	return 0;
+}
+
+int conf_write(const char *name)
+{
+	FILE *out;
+	struct symbol *sym;
+	struct menu *menu;
+	const char *basename;
+	const char *str;
+	char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+	time_t now;
+	int use_timestamp = 1;
+	char *env;
+
+	dirname[0] = 0;
+	if (name && name[0]) {
+		struct stat st;
+		char *slash;
+
+		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+			strcpy(dirname, name);
+			strcat(dirname, "/");
+			basename = conf_get_configname();
+		} else if ((slash = strrchr(name, '/'))) {
+			int size = slash - name + 1;
+			memcpy(dirname, name, size);
+			dirname[size] = 0;
+			if (slash[1])
+				basename = slash + 1;
+			else
+				basename = conf_get_configname();
+		} else
+			basename = name;
+	} else
+		basename = conf_get_configname();
+
+	sprintf(newname, "%s%s", dirname, basename);
+	env = getenv("KCONFIG_OVERWRITECONFIG");
+	if (!env || !*env) {
+		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+		out = fopen(tmpname, "w");
+	} else {
+		*tmpname = 0;
+		out = fopen(newname, "w");
+	}
+	if (!out)
+		return 1;
+
+	time(&now);
+	env = getenv("KCONFIG_NOTIMESTAMP");
+	if (env && *env)
+		use_timestamp = 0;
+
+	fprintf(out, _("#\n"
+		       "# Automatically generated make config: don't edit\n"
+		       "# %s\n"
+		       "%s%s"
+		       "#\n"),
+		     rootmenu.prompt->text,
+		     use_timestamp ? "# " : "",
+		     use_timestamp ? ctime(&now) : "");
+
+	if (!conf_get_changed())
+		sym_clear_all_valid();
+
+	menu = rootmenu.list;
+	while (menu) {
+		sym = menu->sym;
+		if (!sym) {
+			if (!menu_is_visible(menu))
+				goto next;
+			str = menu_get_prompt(menu);
+			fprintf(out, "\n"
+				     "#\n"
+				     "# %s\n"
+				     "#\n", str);
+		} else if (!(sym->flags & SYMBOL_CHOICE)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & SYMBOL_WRITE))
+				goto next;
+			sym->flags &= ~SYMBOL_WRITE;
+			/* Write config symbol to file */
+			conf_write_symbol(sym, out, true);
+		}
+
+next:
+		if (menu->list) {
+			menu = menu->list;
+			continue;
+		}
+		if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+	fclose(out);
+
+	if (*tmpname) {
+		strcat(dirname, basename);
+		strcat(dirname, ".old");
+		rename(newname, dirname);
+		if (rename(tmpname, newname))
+			return 1;
+	}
+
+	conf_message(_("configuration written to %s"), newname);
+
+	sym_set_change_count(0);
+
+	return 0;
+}
+
+static int conf_split_config(void)
+{
+	const char *name;
+	char path[PATH_MAX+1];
+	char *s, *d, c;
+	struct symbol *sym;
+	struct stat sb;
+	int res, i, fd;
+
+	name = conf_get_autoconfig_name();
+	conf_read_simple(name, S_DEF_AUTO);
+
+	if (chdir("include/config"))
+		return 1;
+
+	res = 0;
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+			continue;
+		if (sym->flags & SYMBOL_WRITE) {
+			if (sym->flags & SYMBOL_DEF_AUTO) {
+				/*
+				 * symbol has old and new value,
+				 * so compare them...
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) ==
+					    sym->def[S_DEF_AUTO].tri)
+						continue;
+					break;
+				case S_STRING:
+				case S_HEX:
+				case S_INT:
+					if (!strcmp(sym_get_string_value(sym),
+						    sym->def[S_DEF_AUTO].val))
+						continue;
+					break;
+				default:
+					break;
+				}
+			} else {
+				/*
+				 * If there is no old value, only 'no' (unset)
+				 * is allowed as new value.
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) == no)
+						continue;
+					break;
+				default:
+					break;
+				}
+			}
+		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
+			/* There is neither an old nor a new value. */
+			continue;
+		/* else
+		 *	There is an old value, but no new value ('no' (unset)
+		 *	isn't saved in auto.conf, so the old value is always
+		 *	different from 'no').
+		 */
+
+		/* Replace all '_' and append ".h" */
+		s = sym->name;
+		d = path;
+		while ((c = *s++)) {
+			c = tolower(c);
+			*d++ = (c == '_') ? '/' : c;
+		}
+		strcpy(d, ".h");
+
+		/* Assume directory path already exists. */
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+		if (fd == -1) {
+			if (errno != ENOENT) {
+				res = 1;
+				break;
+			}
+			/*
+			 * Create directory components,
+			 * unless they exist already.
+			 */
+			d = path;
+			while ((d = strchr(d, '/'))) {
+				*d = 0;
+				if (stat(path, &sb) && mkdir(path, 0755)) {
+					res = 1;
+					goto out;
+				}
+				*d++ = '/';
+			}
+			/* Try it again. */
+			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+			if (fd == -1) {
+				res = 1;
+				break;
+			}
+		}
+		close(fd);
+	}
+out:
+	if (chdir("../.."))
+		return 1;
+
+	return res;
+}
+
+int conf_write_autoconf(void)
+{
+	struct symbol *sym;
+	const char *str;
+	const char *name;
+	FILE *out, *tristate, *out_h;
+	time_t now;
+	int i;
+
+	sym_clear_all_valid();
+
+	file_write_dep("include/config/auto.conf.cmd");
+
+	if (conf_split_config())
+		return 1;
+
+	out = fopen(".tmpconfig", "w");
+	if (!out)
+		return 1;
+
+	tristate = fopen(".tmpconfig_tristate", "w");
+	if (!tristate) {
+		fclose(out);
+		return 1;
+	}
+
+	out_h = fopen(".tmpconfig.h", "w");
+	if (!out_h) {
+		fclose(out);
+		fclose(tristate);
+		return 1;
+	}
+
+	time(&now);
+	fprintf(out, "#\n"
+		     "# Automatically generated make config: don't edit\n"
+		     "# %s\n"
+		     "# %s"
+		     "#\n",
+		     rootmenu.prompt->text, ctime(&now));
+	fprintf(tristate, "#\n"
+			  "# Automatically generated - do not edit\n"
+			  "\n");
+	fprintf(out_h, "/*\n"
+		       " * Automatically generated C config: don't edit\n"
+		       " * %s\n"
+		       " * %s"
+		       " */\n",
+		       rootmenu.prompt->text, ctime(&now));
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (!sym->name)
+			continue;
+		if (!(sym->flags & SYMBOL_WRITE)) {
+			if (sym->type == S_BOOLEAN || sym->type == S_HEX
+			    || sym->type == S_INT)
+				fprintf(out_h, "#define %s%s 0\n",
+					CONFIG_, sym->name);
+			continue;
+		}
+
+		/* write symbol to config file */
+		conf_write_symbol(sym, out, false);
+
+		/* update autoconf and tristate files */
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			switch (sym_get_tristate_value(sym)) {
+			case no:
+				fprintf(out_h, "#define %s%s 0\n",
+				    CONFIG_, sym->name);
+				break;
+			case mod:
+				fprintf(tristate, "%s%s=M\n",
+				    CONFIG_, sym->name);
+				fprintf(out_h, "#define %s%s_MODULE 1\n",
+				    CONFIG_, sym->name);
+				break;
+			case yes:
+				if (sym->type == S_TRISTATE)
+					fprintf(tristate,"%s%s=Y\n",
+					    CONFIG_, sym->name);
+				fprintf(out_h, "#define %s%s 1\n",
+				    CONFIG_, sym->name);
+				break;
+			}
+			break;
+		case S_STRING:
+			conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
+			break;
+		case S_HEX:
+			str = sym_get_string_value(sym);
+			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+				fprintf(out_h, "#define %s%s 0x%s\n",
+				    CONFIG_, sym->name, str);
+				break;
+			}
+		case S_INT:
+			str = sym_get_string_value(sym);
+			fprintf(out_h, "#define %s%s %s\n",
+			    CONFIG_, sym->name, str);
+			break;
+		default:
+			break;
+		}
+	}
+	fclose(out);
+	fclose(tristate);
+	fclose(out_h);
+
+	name = getenv("KCONFIG_AUTOHEADER");
+	if (!name)
+		name = "include/generated/autoconf.h";
+	if (rename(".tmpconfig.h", name))
+		return 1;
+	name = getenv("KCONFIG_TRISTATE");
+	if (!name)
+		name = "include/config/tristate.conf";
+	if (rename(".tmpconfig_tristate", name))
+		return 1;
+	name = conf_get_autoconfig_name();
+	/*
+	 * This must be the last step, kbuild has a dependency on auto.conf
+	 * and this marks the successful completion of the previous steps.
+	 */
+	if (rename(".tmpconfig", name))
+		return 1;
+
+	return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+	int _sym_change_count = sym_change_count;
+	sym_change_count = count;
+	if (conf_changed_callback &&
+	    (bool)_sym_change_count != (bool)count)
+		conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+	sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+	return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+	conf_changed_callback = fn;
+}
+
+static void randomize_choice_values(struct symbol *csym)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct expr *e;
+	int cnt, def;
+
+	/*
+	 * If choice is mod then we may have more items selected
+	 * and if no then no-one.
+	 * In both cases stop.
+	 */
+	if (csym->curr.tri != yes)
+		return;
+
+	prop = sym_get_choice_prop(csym);
+
+	/* count entries in choice block */
+	cnt = 0;
+	expr_list_for_each_sym(prop->expr, e, sym)
+		cnt++;
+
+	/*
+	 * find a random value and set it to yes,
+	 * set the rest to no so we have only one set
+	 */
+	def = (rand() % cnt);
+
+	cnt = 0;
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		if (def == cnt++) {
+			sym->def[S_DEF_USER].tri = yes;
+			csym->def[S_DEF_USER].val = sym;
+		}
+		else {
+			sym->def[S_DEF_USER].tri = no;
+		}
+	}
+	csym->flags |= SYMBOL_DEF_USER;
+	/* clear VALID to get value calculated */
+	csym->flags &= ~(SYMBOL_VALID);
+}
+
+static void set_all_choice_values(struct symbol *csym)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct expr *e;
+
+	prop = sym_get_choice_prop(csym);
+
+	/*
+	 * Set all non-assinged choice values to no
+	 */
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		if (!sym_has_value(sym))
+			sym->def[S_DEF_USER].tri = no;
+	}
+	csym->flags |= SYMBOL_DEF_USER;
+	/* clear VALID to get value calculated */
+	csym->flags &= ~(SYMBOL_VALID);
+}
+
+void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+	struct symbol *sym, *csym;
+	int i, cnt;
+
+	for_all_symbols(i, sym) {
+		if (sym_has_value(sym))
+			continue;
+		switch (sym_get_type(sym)) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			switch (mode) {
+			case def_yes:
+				sym->def[S_DEF_USER].tri = yes;
+				break;
+			case def_mod:
+				sym->def[S_DEF_USER].tri = mod;
+				break;
+			case def_no:
+				sym->def[S_DEF_USER].tri = no;
+				break;
+			case def_random:
+				cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+				sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+				break;
+			default:
+				continue;
+			}
+			if (!(sym_is_choice(sym) && mode == def_random))
+				sym->flags |= SYMBOL_DEF_USER;
+			break;
+		default:
+			break;
+		}
+
+	}
+
+	sym_clear_all_valid();
+
+	/*
+	 * We have different type of choice blocks.
+	 * If curr.tri equals to mod then we can select several
+	 * choice symbols in one block.
+	 * In this case we do nothing.
+	 * If curr.tri equals yes then only one symbol can be
+	 * selected in a choice block and we set it to yes,
+	 * and the rest to no.
+	 */
+	for_all_symbols(i, csym) {
+		if (sym_has_value(csym) || !sym_is_choice(csym))
+			continue;
+
+		sym_calc_value(csym);
+		if (mode == def_random)
+			randomize_choice_values(csym);
+		else
+			set_all_choice_values(csym);
+	}
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/expr.c b/qemu-0.15.x/roms/seabios/tools/kconfig/expr.c
new file mode 100644
index 0000000..0010034
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/expr.c
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR	0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = E_SYMBOL;
+	e->left.sym = sym;
+	return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = ce;
+	return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = e1;
+	e->right.expr = e2;
+	return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.sym = s1;
+	e->right.sym = s2;
+	return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+	struct expr *e;
+
+	if (!org)
+		return NULL;
+
+	e = malloc(sizeof(*org));
+	memcpy(e, org, sizeof(*org));
+	switch (org->type) {
+	case E_SYMBOL:
+		e->left = org->left;
+		break;
+	case E_NOT:
+		e->left.expr = expr_copy(org->left.expr);
+		break;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		e->left.sym = org->left.sym;
+		e->right.sym = org->right.sym;
+		break;
+	case E_AND:
+	case E_OR:
+	case E_LIST:
+		e->left.expr = expr_copy(org->left.expr);
+		e->right.expr = expr_copy(org->right.expr);
+		break;
+	default:
+		printf("can't copy type %d\n", e->type);
+		free(e);
+		e = NULL;
+		break;
+	}
+
+	return e;
+}
+
+void expr_free(struct expr *e)
+{
+	if (!e)
+		return;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		break;
+	case E_NOT:
+		expr_free(e->left.expr);
+		return;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		break;
+	case E_OR:
+	case E_AND:
+		expr_free(e->left.expr);
+		expr_free(e->right.expr);
+		break;
+	default:
+		printf("how to free type %d?\n", e->type);
+		break;
+	}
+	free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+	if (e1->type == type) {
+		__expr_eliminate_eq(type, &e1->left.expr, &e2);
+		__expr_eliminate_eq(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		__expr_eliminate_eq(type, &e1, &e2->left.expr);
+		__expr_eliminate_eq(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+	    e1->left.sym == e2->left.sym &&
+	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+		return;
+	if (!expr_eq(e1, e2))
+		return;
+	trans_count++;
+	expr_free(e1); expr_free(e2);
+	switch (type) {
+	case E_OR:
+		e1 = expr_alloc_symbol(&symbol_no);
+		e2 = expr_alloc_symbol(&symbol_no);
+		break;
+	case E_AND:
+		e1 = expr_alloc_symbol(&symbol_yes);
+		e2 = expr_alloc_symbol(&symbol_yes);
+		break;
+	default:
+		;
+	}
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+	if (!e1 || !e2)
+		return;
+	switch (e1->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e1->type, ep1, ep2);
+	default:
+		;
+	}
+	if (e1->type != e2->type) switch (e2->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e2->type, ep1, ep2);
+	default:
+		;
+	}
+	e1 = expr_eliminate_yn(e1);
+	e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+	int res, old_count;
+
+	if (e1->type != e2->type)
+		return 0;
+	switch (e1->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+	case E_SYMBOL:
+		return e1->left.sym == e2->left.sym;
+	case E_NOT:
+		return expr_eq(e1->left.expr, e2->left.expr);
+	case E_AND:
+	case E_OR:
+		e1 = expr_copy(e1);
+		e2 = expr_copy(e2);
+		old_count = trans_count;
+		expr_eliminate_eq(&e1, &e2);
+		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+		       e1->left.sym == e2->left.sym);
+		expr_free(e1);
+		expr_free(e2);
+		trans_count = old_count;
+		return res;
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+
+	if (DEBUG_EXPR) {
+		expr_fprint(e1, stdout);
+		printf(" = ");
+		expr_fprint(e2, stdout);
+		printf(" ?\n");
+	}
+
+	return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (e) switch (e->type) {
+	case E_AND:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		break;
+	case E_OR:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_AND:
+	case E_OR:
+	case E_NOT:
+		e->left.expr = expr_trans_bool(e->left.expr);
+		e->right.expr = expr_trans_bool(e->right.expr);
+		break;
+	case E_UNEQUAL:
+		// FOO!=n -> FOO
+		if (e->left.sym->type == S_TRISTATE) {
+			if (e->right.sym == &symbol_no) {
+				e->type = E_SYMBOL;
+				e->right.sym = NULL;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='m') -> (a!='n')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='n') -> (a!='m')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+			// (a='m') || (a='n') -> (a!='y')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+		}
+	}
+	if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+			return expr_alloc_symbol(&symbol_yes);
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") || (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+
+	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+		// (a) && (a='y') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+		// (a) && (a!='n') -> (a)
+		return expr_alloc_symbol(sym1);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+		// (a) && (a!='m') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e1->right.sym;
+			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e2->right.sym;
+			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='m') -> (a='n')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+			// (a!='m') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+			return NULL;
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") && (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp;
+
+	if (e1->type == type) {
+		expr_eliminate_dups1(type, &e1->left.expr, &e2);
+		expr_eliminate_dups1(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups1(type, &e1, &e2->left.expr);
+		expr_eliminate_dups1(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR: case E_AND:
+		expr_eliminate_dups1(e1->type, &e1, &e1);
+	default:
+		;
+	}
+
+	switch (type) {
+	case E_OR:
+		tmp = expr_join_or(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	case E_AND:
+		tmp = expr_join_and(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp, *tmp1, *tmp2;
+
+	if (e1->type == type) {
+		expr_eliminate_dups2(type, &e1->left.expr, &e2);
+		expr_eliminate_dups2(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups2(type, &e1, &e2->left.expr);
+		expr_eliminate_dups2(type, &e1, &e2->right.expr);
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO || BAR) && (!FOO && !BAR) -> n
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_and(&tmp1, &tmp2);
+		if (expr_is_yes(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_no);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	case E_AND:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO && BAR) || (!FOO || !BAR) -> y
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_or(&tmp1, &tmp2);
+		if (expr_is_no(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+	int oldcount;
+	if (!e)
+		return e;
+
+	oldcount = trans_count;
+	while (1) {
+		trans_count = 0;
+		switch (e->type) {
+		case E_OR: case E_AND:
+			expr_eliminate_dups1(e->type, &e, &e);
+			expr_eliminate_dups2(e->type, &e, &e);
+		default:
+			;
+		}
+		if (!trans_count)
+			break;
+		e = expr_eliminate_yn(e);
+	}
+	trans_count = oldcount;
+	return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+	case E_SYMBOL:
+	case E_LIST:
+		break;
+	default:
+		e->left.expr = expr_transform(e->left.expr);
+		e->right.expr = expr_transform(e->right.expr);
+	}
+
+	switch (e->type) {
+	case E_EQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_no;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_yes;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_NOT:
+		switch (e->left.expr->type) {
+		case E_NOT:
+			// !!a -> a
+			tmp = e->left.expr->left.expr;
+			free(e->left.expr);
+			free(e);
+			e = tmp;
+			e = expr_transform(e);
+			break;
+		case E_EQUAL:
+		case E_UNEQUAL:
+			// !a='x' -> a!='x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+			break;
+		case E_OR:
+			// !(a || b) -> !a && !b
+			tmp = e->left.expr;
+			e->type = E_AND;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_AND:
+			// !(a && b) -> !a || !b
+			tmp = e->left.expr;
+			e->type = E_OR;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_SYMBOL:
+			if (e->left.expr->left.sym == &symbol_yes) {
+				// !'y' -> 'n'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_mod) {
+				// !'m' -> 'm'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_mod;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_no) {
+				// !'n' -> 'y'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				break;
+			}
+			break;
+		default:
+			;
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return 0;
+
+	switch (dep->type) {
+	case E_AND:
+	case E_OR:
+		return expr_contains_symbol(dep->left.expr, sym) ||
+		       expr_contains_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return dep->left.sym == sym ||
+		       dep->right.sym == sym;
+	case E_NOT:
+		return expr_contains_symbol(dep->left.expr, sym);
+	default:
+		;
+	}
+	return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return false;
+
+	switch (dep->type) {
+	case E_AND:
+		return expr_depends_symbol(dep->left.expr, sym) ||
+		       expr_depends_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+				return true;
+		}
+		break;
+	case E_UNEQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_no)
+				return true;
+		}
+		break;
+	default:
+		;
+	}
+ 	return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_AND, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_OR, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	if (e1->type == type) {
+		expr_extract_eq(type, ep, &e1->left.expr, &e2);
+		expr_extract_eq(type, ep, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_extract_eq(type, ep, ep1, &e2->left.expr);
+		expr_extract_eq(type, ep, ep1, &e2->right.expr);
+		return;
+	}
+	if (expr_eq(e1, e2)) {
+		*ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+		expr_free(e2);
+		if (type == E_AND) {
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = expr_alloc_symbol(&symbol_yes);
+		} else if (type == E_OR) {
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = expr_alloc_symbol(&symbol_no);
+		}
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+	struct expr *e1, *e2;
+
+	if (!e) {
+		e = expr_alloc_symbol(sym);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	}
+	switch (e->type) {
+	case E_AND:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_OR:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_NOT:
+		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+	case E_UNEQUAL:
+	case E_EQUAL:
+		if (type == E_EQUAL) {
+			if (sym == &symbol_yes)
+				return expr_copy(e);
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_no);
+			if (sym == &symbol_no)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+		} else {
+			if (sym == &symbol_yes)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_yes);
+			if (sym == &symbol_no)
+				return expr_copy(e);
+		}
+		break;
+	case E_SYMBOL:
+		return expr_alloc_comp(type, e->left.sym, sym);
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+	return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+	tristate val1, val2;
+	const char *str1, *str2;
+
+	if (!e)
+		return yes;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		sym_calc_value(e->left.sym);
+		return e->left.sym->curr.tri;
+	case E_AND:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_AND(val1, val2);
+	case E_OR:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_OR(val1, val2);
+	case E_NOT:
+		val1 = expr_calc_value(e->left.expr);
+		return EXPR_NOT(val1);
+	case E_EQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? yes : no;
+	case E_UNEQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? no : yes;
+	default:
+		printf("expr_calc_value: %d?\n", e->type);
+		return no;
+	}
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+	return 1;
+#else
+	if (t1 == t2)
+		return 0;
+	switch (t1) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		if (t2 == E_NOT)
+			return 1;
+	case E_NOT:
+		if (t2 == E_AND)
+			return 1;
+	case E_AND:
+		if (t2 == E_OR)
+			return 1;
+	case E_OR:
+		if (t2 == E_LIST)
+			return 1;
+	case E_LIST:
+		if (t2 == 0)
+			return 1;
+	default:
+		return -1;
+	}
+	printf("[%dgt%d?]", t1, t2);
+	return 0;
+#endif
+}
+
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+	if (e == NULL)
+		return NULL;
+
+	while (e->type != E_SYMBOL)
+		e = e->left.expr;
+
+	return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+	struct expr *ret;
+
+	switch (e1->type) {
+	case E_OR:
+		return expr_alloc_and(
+		    expr_simplify_unmet_dep(e1->left.expr, e2),
+		    expr_simplify_unmet_dep(e1->right.expr, e2));
+	case E_AND: {
+		struct expr *e;
+		e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+		e = expr_eliminate_dups(e);
+		ret = (!expr_eq(e, e1)) ? e1 : NULL;
+		expr_free(e);
+		break;
+		}
+	default:
+		ret = e1;
+		break;
+	}
+
+	return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+	if (!e) {
+		fn(data, NULL, "y");
+		return;
+	}
+
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, "(");
+	switch (e->type) {
+	case E_SYMBOL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		break;
+	case E_NOT:
+		fn(data, NULL, "!");
+		expr_print(e->left.expr, fn, data, E_NOT);
+		break;
+	case E_EQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "!=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_OR:
+		expr_print(e->left.expr, fn, data, E_OR);
+		fn(data, NULL, " || ");
+		expr_print(e->right.expr, fn, data, E_OR);
+		break;
+	case E_AND:
+		expr_print(e->left.expr, fn, data, E_AND);
+		fn(data, NULL, " && ");
+		expr_print(e->right.expr, fn, data, E_AND);
+		break;
+	case E_LIST:
+		fn(data, e->right.sym, e->right.sym->name);
+		if (e->left.expr) {
+			fn(data, NULL, " ^ ");
+			expr_print(e->left.expr, fn, data, E_LIST);
+		}
+		break;
+	case E_RANGE:
+		fn(data, NULL, "[");
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, " ");
+		fn(data, e->right.sym, e->right.sym->name);
+		fn(data, NULL, "]");
+		break;
+	default:
+	  {
+		char buf[32];
+		sprintf(buf, "<unknown type %d>", e->type);
+		fn(data, NULL, buf);
+		break;
+	  }
+	}
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+	xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+	expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+	struct gstr *gs = (struct gstr*)data;
+	const char *sym_str = NULL;
+
+	if (sym)
+		sym_str = sym_get_string_value(sym);
+
+	if (gs->max_width) {
+		unsigned extra_length = strlen(str);
+		const char *last_cr = strrchr(gs->s, '\n');
+		unsigned last_line_length;
+
+		if (sym_str)
+			extra_length += 4 + strlen(sym_str);
+
+		if (!last_cr)
+			last_cr = gs->s;
+
+		last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+		if ((last_line_length + extra_length) > gs->max_width)
+			str_append(gs, "\\\n");
+	}
+
+	str_append(gs, str);
+	if (sym && sym->type != S_UNKNOWN)
+		str_printf(gs, " [=%s]", sym_str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+	expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/expr.h b/qemu-0.15.x/roms/seabios/tools/kconfig/expr.h
new file mode 100644
index 0000000..3d238db
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/expr.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+	struct file *next;
+	struct file *parent;
+	const char *name;
+	int lineno;
+	int flags;
+};
+
+#define FILE_BUSY		0x0001
+#define FILE_SCANNED		0x0002
+
+typedef enum tristate {
+	no, mod, yes
+} tristate;
+
+enum expr_type {
+	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+	struct expr *expr;
+	struct symbol *sym;
+};
+
+struct expr {
+	enum expr_type type;
+	union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)		(2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+	for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+	struct expr *expr;
+	tristate tri;
+};
+
+struct symbol_value {
+	void *val;
+	tristate tri;
+};
+
+enum symbol_type {
+	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,		/* values read from auto.conf */
+	S_DEF_DEF3,		/* Reserved for UI usage */
+	S_DEF_DEF4,		/* Reserved for UI usage */
+	S_DEF_COUNT
+};
+
+struct symbol {
+	struct symbol *next;
+	char *name;
+	enum symbol_type type;
+	struct symbol_value curr;
+	struct symbol_value def[S_DEF_COUNT];
+	tristate visible;
+	int flags;
+	struct property *prop;
+	struct expr_value dir_dep;
+	struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST      0x0001  /* symbol is const */
+#define SYMBOL_CHECK      0x0008  /* used during dependency checking */
+#define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL  0x0020  /* used as a value in a choice block */
+#define SYMBOL_VALID      0x0080  /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE      0x0200  /* ? */
+#define SYMBOL_CHANGED    0x0400  /* ? */
+#define SYMBOL_AUTO       0x1000  /* value from environment variable */
+#define SYMBOL_CHECKED    0x2000  /* used during dependency checking */
+#define SYMBOL_WARNED     0x8000  /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF        0x10000  /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER   0x10000  /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO   0x20000  /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
+
+#define SYMBOL_MAXLENGTH	256
+#define SYMBOL_HASHSIZE		9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ *         default y
+ *         prompt "foo prompt"
+ *         select BAR
+ * config BAZ
+ *         int "BAZ Value"
+ *         range 1..255
+ */
+enum prop_type {
+	P_UNKNOWN,
+	P_PROMPT,   /* prompt "foo prompt" or "BAZ Value" */
+	P_COMMENT,  /* text associated with a comment */
+	P_MENU,     /* prompt associated with a menuconfig option */
+	P_DEFAULT,  /* default y */
+	P_CHOICE,   /* choice value */
+	P_SELECT,   /* select BAR */
+	P_RANGE,    /* range 7..100 (for a symbol) */
+	P_ENV,      /* value from environment variable */
+	P_SYMBOL,   /* where a symbol is defined */
+};
+
+struct property {
+	struct property *next;     /* next property - null if last */
+	struct symbol *sym;        /* the symbol for which the property is associated */
+	enum prop_type type;       /* type of property */
+	const char *text;          /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+	struct expr_value visible;
+	struct expr *expr;         /* the optional conditional part of the property */
+	struct menu *menu;         /* the menu the property are associated with
+	                            * valid for: P_SELECT, P_RANGE, P_CHOICE,
+	                            * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+	struct file *file;         /* what file was this property defined */
+	int lineno;                /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->text)
+
+struct menu {
+	struct menu *next;
+	struct menu *parent;
+	struct menu *list;
+	struct symbol *sym;
+	struct property *prompt;
+	struct expr *visibility;
+	struct expr *dep;
+	unsigned int flags;
+	char *help;
+	struct file *file;
+	int lineno;
+	void *data;
+};
+
+#define MENU_CHANGED		0x0001
+#define MENU_ROOT		0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.c b/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.c
new file mode 100644
index 0000000..b7f31f2
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.c
@@ -0,0 +1,1577 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms at tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+enum {
+	OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL;	// left  frame
+GtkWidget *tree2_w = NULL;	// right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+	COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+	COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+	COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+const char *dbg_sym_flags(int val)
+{
+	static char buf[256];
+
+	bzero(buf, 256);
+
+	if (val & SYMBOL_CONST)
+		strcat(buf, "const/");
+	if (val & SYMBOL_CHECK)
+		strcat(buf, "check/");
+	if (val & SYMBOL_CHOICE)
+		strcat(buf, "choice/");
+	if (val & SYMBOL_CHOICEVAL)
+		strcat(buf, "choiceval/");
+	if (val & SYMBOL_VALID)
+		strcat(buf, "valid/");
+	if (val & SYMBOL_OPTIONAL)
+		strcat(buf, "optional/");
+	if (val & SYMBOL_WRITE)
+		strcat(buf, "write/");
+	if (val & SYMBOL_CHANGED)
+		strcat(buf, "changed/");
+	if (val & SYMBOL_AUTO)
+		strcat(buf, "auto/");
+
+	buf[strlen(buf) - 1] = '\0';
+
+	return buf;
+}
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+	GdkPixmap *pixmap;
+	GdkBitmap *mask;
+	GtkToolButton *button;
+	GtkWidget *image;
+
+	pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+					      &style->bg[GTK_STATE_NORMAL],
+					      xpm);
+
+	button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+	image = gtk_image_new_from_pixmap(pixmap, mask);
+	gtk_widget_show(image);
+	gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+	GladeXML *xml;
+	GtkWidget *widget;
+	GtkTextBuffer *txtbuf;
+	GtkStyle *style;
+
+	xml = glade_xml_new(glade_file, "window1", NULL);
+	if (!xml)
+		g_error(_("GUI loading failed !\n"));
+	glade_xml_signal_autoconnect(xml);
+
+	main_wnd = glade_xml_get_widget(xml, "window1");
+	hpaned = glade_xml_get_widget(xml, "hpaned1");
+	vpaned = glade_xml_get_widget(xml, "vpaned1");
+	tree1_w = glade_xml_get_widget(xml, "treeview1");
+	tree2_w = glade_xml_get_widget(xml, "treeview2");
+	text_w = glade_xml_get_widget(xml, "textview3");
+
+	back_btn = glade_xml_get_widget(xml, "button1");
+	gtk_widget_set_sensitive(back_btn, FALSE);
+
+	widget = glade_xml_get_widget(xml, "show_name1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_name);
+
+	widget = glade_xml_get_widget(xml, "show_range1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_range);
+
+	widget = glade_xml_get_widget(xml, "show_data1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_value);
+
+	save_btn = glade_xml_get_widget(xml, "button3");
+	save_menu_item = glade_xml_get_widget(xml, "save1");
+	conf_set_changed_callback(conf_changed);
+
+	style = gtk_widget_get_style(main_wnd);
+	widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0	/* Use stock Gtk icons instead */
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button1", (gchar **) xpm_back);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button2", (gchar **) xpm_load);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button3", (gchar **) xpm_save);
+#endif
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button4", (gchar **) xpm_single_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button5", (gchar **) xpm_split_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button6", (gchar **) xpm_tree_view);
+
+#if 0
+	switch (view_mode) {
+	case SINGLE_VIEW:
+		widget = glade_xml_get_widget(xml, "button4");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	case SPLIT_VIEW:
+		widget = glade_xml_get_widget(xml, "button5");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	case FULL_VIEW:
+		widget = glade_xml_get_widget(xml, "button6");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	}
+#endif
+	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+					  "foreground", "red",
+					  "weight", PANGO_WEIGHT_BOLD,
+					  NULL);
+	tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+					  /*"style", PANGO_STYLE_OBLIQUE, */
+					  NULL);
+
+	gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
+
+	gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+	gint i;
+
+	tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_POINTER, GDK_TYPE_COLOR,
+					  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+					  G_TYPE_BOOLEAN);
+	model2 = GTK_TREE_MODEL(tree2);
+
+	for (parents[0] = NULL, i = 1; i < 256; i++)
+		parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+	tree1 = gtk_tree_store_new(COL_NUMBER,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_POINTER, GDK_TYPE_COLOR,
+				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+				   G_TYPE_BOOLEAN);
+	model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+	GtkCellRenderer *renderer;
+	GtkTreeSelection *sel;
+	GtkTreeViewColumn *column;
+
+	gtk_tree_view_set_model(view, model1);
+	gtk_tree_view_set_headers_visible(view, TRUE);
+	gtk_tree_view_set_rules_hint(view, FALSE);
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_append_column(view, column);
+	gtk_tree_view_column_set_title(column, _("Options"));
+
+	renderer = gtk_cell_renderer_toggle_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "active", COL_BTNACT,
+					    "inconsistent", COL_BTNINC,
+					    "visible", COL_BTNVIS,
+					    "radio", COL_BTNRAD, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "text", COL_OPTION,
+					    "foreground-gdk",
+					    COL_COLOR, NULL);
+
+	sel = gtk_tree_view_get_selection(view);
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+	gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+			    const gchar * path_string,
+			    const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+			     gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+	GtkCellRenderer *renderer;
+	GtkTreeSelection *sel;
+	GtkTreeViewColumn *column;
+	gint i;
+
+	gtk_tree_view_set_model(view, model2);
+	gtk_tree_view_set_headers_visible(view, TRUE);
+	gtk_tree_view_set_rules_hint(view, FALSE);
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_append_column(view, column);
+	gtk_tree_view_column_set_title(column, _("Options"));
+
+	renderer = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "pixbuf", COL_PIXBUF,
+					    "visible", COL_PIXVIS, NULL);
+	renderer = gtk_cell_renderer_toggle_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "active", COL_BTNACT,
+					    "inconsistent", COL_BTNINC,
+					    "visible", COL_BTNVIS,
+					    "radio", COL_BTNRAD, NULL);
+	/*g_signal_connect(G_OBJECT(renderer), "toggled",
+	   G_CALLBACK(renderer_toggled), NULL); */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "text", COL_OPTION,
+					    "foreground-gdk",
+					    COL_COLOR, NULL);
+
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    _("Name"), renderer,
+						    "text", COL_NAME,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "N", renderer,
+						    "text", COL_NO,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "M", renderer,
+						    "text", COL_MOD,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "Y", renderer,
+						    "text", COL_YES,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    _("Value"), renderer,
+						    "text", COL_VALUE,
+						    "editable",
+						    COL_EDIT,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	g_signal_connect(G_OBJECT(renderer), "edited",
+			 G_CALLBACK(renderer_edited), NULL);
+
+	column = gtk_tree_view_get_column(view, COL_NAME);
+	gtk_tree_view_column_set_visible(column, show_name);
+	column = gtk_tree_view_get_column(view, COL_NO);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_MOD);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_YES);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_VALUE);
+	gtk_tree_view_column_set_visible(column, show_value);
+
+	if (resizeable) {
+		for (i = 0; i < COL_VALUE; i++) {
+			column = gtk_tree_view_get_column(view, i);
+			gtk_tree_view_column_set_resizable(column, TRUE);
+		}
+	}
+
+	sel = gtk_tree_view_get_selection(view);
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	const char *prompt = _(menu_get_prompt(menu));
+	struct gstr help = str_new();
+
+	menu_get_ext_help(menu, &help);
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	gtk_text_buffer_get_bounds(buffer, &start, &end);
+	gtk_text_buffer_delete(buffer, &start, &end);
+	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+					 NULL);
+	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
+					 NULL);
+	str_free(&help);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	const char *msg = message;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	gtk_text_buffer_get_bounds(buffer, &start, &end);
+	gtk_text_buffer_delete(buffer, &start, &end);
+	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+					 NULL);
+	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+					 NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+				 gpointer user_data)
+{
+	GtkWidget *dialog, *label;
+	gint result;
+
+	if (!conf_get_changed())
+		return FALSE;
+
+	dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+					     GTK_WINDOW(main_wnd),
+					     (GtkDialogFlags)
+					     (GTK_DIALOG_MODAL |
+					      GTK_DIALOG_DESTROY_WITH_PARENT),
+					     GTK_STOCK_OK,
+					     GTK_RESPONSE_YES,
+					     GTK_STOCK_NO,
+					     GTK_RESPONSE_NO,
+					     GTK_STOCK_CANCEL,
+					     GTK_RESPONSE_CANCEL, NULL);
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+					GTK_RESPONSE_CANCEL);
+
+	label = gtk_label_new(_("\nSave configuration ?\n"));
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+	gtk_widget_show(label);
+
+	result = gtk_dialog_run(GTK_DIALOG(dialog));
+	switch (result) {
+	case GTK_RESPONSE_YES:
+		on_save_activate(NULL, NULL);
+		return FALSE;
+	case GTK_RESPONSE_NO:
+		return FALSE;
+	case GTK_RESPONSE_CANCEL:
+	case GTK_RESPONSE_DELETE_EVENT:
+	default:
+		gtk_widget_destroy(dialog);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+	gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+			GtkRequisition * requisition, gpointer user_data)
+{
+	static gint old_h;
+	gint w, h;
+
+	if (widget->window == NULL)
+		gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+	else
+		gdk_window_get_size(widget->window, &w, &h);
+
+	if (h == old_h)
+		return;
+	old_h = h;
+
+	gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+	const gchar *fn;
+
+	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+					     (user_data));
+
+	if (conf_read(fn))
+		text_insert_msg(_("Error"), _("Unable to load configuration !"));
+	else
+		display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *fs;
+
+	fs = gtk_file_selection_new(_("Load file..."));
+	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+			 "clicked",
+			 G_CALLBACK(load_filename), (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->ok_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->cancel_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	if (conf_write(NULL))
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+	const gchar *fn;
+
+	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+					     (user_data));
+
+	if (conf_write(fn))
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+	gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *fs;
+
+	fs = gtk_file_selection_new(_("Save file as..."));
+	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+			 "clicked",
+			 G_CALLBACK(store_filename), (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->ok_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->cancel_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	if (!on_window1_delete_event(NULL, NULL, NULL))
+		gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+	opt_mode = OPT_NORMAL;
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+	opt_mode = OPT_ALL;
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+	opt_mode = OPT_PROMPT;
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *intro_text = _(
+	    "Welcome to gkc, the GTK+ graphical configuration tool\n"
+	    "For each option, a blank box indicates the feature is disabled, a\n"
+	    "check indicates it is enabled, and a dot indicates that it is to\n"
+	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
+	    "\n"
+	    "If you do not see an option (e.g., a device driver) that you\n"
+	    "believe should be present, try turning on Show All Options\n"
+	    "under the Options menu.\n"
+	    "Although there is no cross reference yet to help you figure out\n"
+	    "what other options must be enabled to support the option you\n"
+	    "are interested in, you can still view the help of a grayed-out\n"
+	    "option.\n"
+	    "\n"
+	    "Toggling Show Debug Info under the Options menu will show \n"
+	    "the dependencies, which you can then match by examining other options.");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, intro_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *about_text =
+	    _("gkc is copyright (c) 2002 Romain Lievin <roms at lpg.ticalc.org>.\n"
+	      "Based on the source code from Roman Zippel.\n");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, about_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *license_text =
+	    _("gkc is released under the terms of the GNU GPL v2.\n"
+	      "For more information, please see the source code or\n"
+	      "visit http://www.fsf.org/licenses/licenses.html\n");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, license_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+	enum prop_type ptype;
+
+	current = current->parent;
+	ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+	if (ptype != P_MENU)
+		current = current->parent;
+	display_tree_part();
+
+	if (current == &rootmenu)
+		gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+	on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+	view_mode = SINGLE_VIEW;
+	gtk_paned_set_position(GTK_PANED(hpaned), 0);
+	gtk_widget_hide(tree1_w);
+	current = &rootmenu;
+	display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+	gint w, h;
+	view_mode = SPLIT_VIEW;
+	gtk_widget_show(tree1_w);
+	gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+	gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	display_list();
+
+	/* Disable back btn, like in full mode. */
+	gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+	view_mode = FULL_VIEW;
+	gtk_paned_set_position(GTK_PANED(hpaned), 0);
+	gtk_widget_hide(tree1_w);
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);
+	gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+			    const gchar * path_string,
+			    const gchar * new_text, gpointer user_data)
+{
+	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+	GtkTreeIter iter;
+	const char *old_def, *new_def;
+	struct menu *menu;
+	struct symbol *sym;
+
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return;
+
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+	sym = menu->sym;
+
+	gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+	new_def = new_text;
+
+	sym_set_string_value(sym, new_def);
+
+	update_tree(&rootmenu, NULL);
+
+	gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+	struct symbol *sym = menu->sym;
+	tristate oldval, newval;
+
+	if (!sym)
+		return;
+
+	if (col == COL_NO)
+		newval = no;
+	else if (col == COL_MOD)
+		newval = mod;
+	else if (col == COL_YES)
+		newval = yes;
+	else
+		return;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldval = sym_get_tristate_value(sym);
+		if (!sym_tristate_within_range(sym, newval))
+			newval = yes;
+		sym_set_tristate_value(sym, newval);
+		if (view_mode == FULL_VIEW)
+			update_tree(&rootmenu, NULL);
+		else if (view_mode == SPLIT_VIEW) {
+			update_tree(browsed, NULL);
+			display_list();
+		}
+		else if (view_mode == SINGLE_VIEW)
+			display_tree_part();	//fixme: keep exp/coll
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+	default:
+		break;
+	}
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+	if (!menu->sym)
+		return;
+
+	sym_toggle_tristate_value(menu->sym);
+	if (view_mode == FULL_VIEW)
+		update_tree(&rootmenu, NULL);
+	else if (view_mode == SPLIT_VIEW) {
+		update_tree(browsed, NULL);
+		display_list();
+	}
+	else if (view_mode == SINGLE_VIEW)
+		display_tree_part();	//fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
+			     gchar * path_string, gpointer user_data)
+{
+	GtkTreePath *path, *sel_path = NULL;
+	GtkTreeIter iter, sel_iter;
+	GtkTreeSelection *sel;
+	struct menu *menu;
+
+	path = gtk_tree_path_new_from_string(path_string);
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return;
+
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+	if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+		sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+	if (!sel_path)
+		goto out1;
+	if (gtk_tree_path_compare(path, sel_path))
+		goto out2;
+
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+	toggle_sym_value(menu);
+
+      out2:
+	gtk_tree_path_free(sel_path);
+      out1:
+	gtk_tree_path_free(path);
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+	gint i;
+
+	for (i = 0; i < COL_NUMBER; i++) {
+		GtkTreeViewColumn *col;
+
+		col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+		if (col == column)
+			return i;
+	}
+
+	return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+				GdkEventButton * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+	gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+	gint tx = (gint) event->x;
+	gint ty = (gint) event->y;
+	gint cx, cy;
+
+	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+				      &cy);
+#else
+	gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+	if (path == NULL)
+		return FALSE;
+
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return FALSE;
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+	col = column2index(column);
+	if (event->type == GDK_2BUTTON_PRESS) {
+		enum prop_type ptype;
+		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+		if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+			// goes down into menu
+			current = menu;
+			display_tree_part();
+			gtk_widget_set_sensitive(back_btn, TRUE);
+		} else if ((col == COL_OPTION)) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	} else {
+		if (col == COL_VALUE) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		} else if (col == COL_NO || col == COL_MOD
+			   || col == COL_YES) {
+			change_sym_value(menu, col);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	}
+
+	return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+			     GdkEventKey * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+	gint col;
+
+	gtk_tree_view_get_cursor(view, &path, &column);
+	if (path == NULL)
+		return FALSE;
+
+	if (event->keyval == GDK_space) {
+		if (gtk_tree_view_row_expanded(view, path))
+			gtk_tree_view_collapse_row(view, path);
+		else
+			gtk_tree_view_expand_row(view, path, FALSE);
+		return TRUE;
+	}
+	if (event->keyval == GDK_KP_Enter) {
+	}
+	if (widget == tree1_w)
+		return FALSE;
+
+	gtk_tree_model_get_iter(model2, &iter, path);
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+	if (!strcasecmp(event->string, "n"))
+		col = COL_NO;
+	else if (!strcasecmp(event->string, "m"))
+		col = COL_MOD;
+	else if (!strcasecmp(event->string, "y"))
+		col = COL_YES;
+	else
+		col = -1;
+	change_sym_value(menu, col);
+
+	return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+	GtkTreeSelection *selection;
+	GtkTreeIter iter;
+	struct menu *menu;
+
+	selection = gtk_tree_view_get_selection(treeview);
+	if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+		gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+		text_insert_help(menu);
+	}
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+				GdkEventButton * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+
+	gint tx = (gint) event->x;
+	gint ty = (gint) event->y;
+	gint cx, cy;
+
+	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+				      &cy);
+	if (path == NULL)
+		return FALSE;
+
+	gtk_tree_model_get_iter(model1, &iter, path);
+	gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+	if (event->type == GDK_2BUTTON_PRESS) {
+		toggle_sym_value(menu);
+		current = menu;
+		display_tree_part();
+	} else {
+		browsed = menu;
+		display_tree_part();
+	}
+
+	gtk_widget_realize(tree2_w);
+	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+	gtk_widget_grab_focus(tree2_w);
+
+	return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+	static gchar *row[COL_NUMBER];
+	struct symbol *sym = menu->sym;
+	const char *def;
+	int stype;
+	tristate val;
+	enum prop_type ptype;
+	int i;
+
+	for (i = COL_OPTION; i <= COL_COLOR; i++)
+		g_free(row[i]);
+	bzero(row, sizeof(row));
+
+	row[COL_OPTION] =
+	    g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+			    sym && !sym_has_value(sym) ? "(NEW)" : "");
+
+	if (opt_mode == OPT_ALL && !menu_is_visible(menu))
+		row[COL_COLOR] = g_strdup("DarkGray");
+	else if (opt_mode == OPT_PROMPT &&
+			menu_has_prompt(menu) && !menu_is_visible(menu))
+		row[COL_COLOR] = g_strdup("DarkGray");
+	else
+		row[COL_COLOR] = g_strdup("Black");
+
+	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	switch (ptype) {
+	case P_MENU:
+		row[COL_PIXBUF] = (gchar *) xpm_menu;
+		if (view_mode == SINGLE_VIEW)
+			row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	case P_COMMENT:
+		row[COL_PIXBUF] = (gchar *) xpm_void;
+		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	default:
+		row[COL_PIXBUF] = (gchar *) xpm_void;
+		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+		break;
+	}
+
+	if (!sym)
+		return row;
+	row[COL_NAME] = g_strdup(sym->name);
+
+	sym_calc_value(sym);
+	sym->flags &= ~SYMBOL_CHANGED;
+
+	if (sym_is_choice(sym)) {	// parse childs for getting final value
+		struct menu *child;
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child)
+			    && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		if (def_menu)
+			row[COL_VALUE] =
+			    g_strdup(_(menu_get_prompt(def_menu)));
+	}
+	if (sym->flags & SYMBOL_CHOICEVAL)
+		row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+	stype = sym_get_type(sym);
+	switch (stype) {
+	case S_BOOLEAN:
+		if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+		if (sym_is_choice(sym))
+			break;
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			row[COL_NO] = g_strdup("N");
+			row[COL_VALUE] = g_strdup("N");
+			row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+			break;
+		case mod:
+			row[COL_MOD] = g_strdup("M");
+			row[COL_VALUE] = g_strdup("M");
+			row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+			break;
+		case yes:
+			row[COL_YES] = g_strdup("Y");
+			row[COL_VALUE] = g_strdup("Y");
+			row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+			break;
+		}
+
+		if (val != no && sym_tristate_within_range(sym, no))
+			row[COL_NO] = g_strdup("_");
+		if (val != mod && sym_tristate_within_range(sym, mod))
+			row[COL_MOD] = g_strdup("_");
+		if (val != yes && sym_tristate_within_range(sym, yes))
+			row[COL_YES] = g_strdup("_");
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		def = sym_get_string_value(sym);
+		row[COL_VALUE] = g_strdup(def);
+		row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	}
+
+	return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+	GdkColor color;
+	gboolean success;
+	GdkPixbuf *pix;
+
+	pix = gdk_pixbuf_new_from_xpm_data((const char **)
+					   row[COL_PIXBUF]);
+
+	gdk_color_parse(row[COL_COLOR], &color);
+	gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+				  FALSE, FALSE, &success);
+
+	gtk_tree_store_set(tree, node,
+			   COL_OPTION, row[COL_OPTION],
+			   COL_NAME, row[COL_NAME],
+			   COL_NO, row[COL_NO],
+			   COL_MOD, row[COL_MOD],
+			   COL_YES, row[COL_YES],
+			   COL_VALUE, row[COL_VALUE],
+			   COL_MENU, (gpointer) menu,
+			   COL_COLOR, &color,
+			   COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+			   COL_PIXBUF, pix,
+			   COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+			   COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+			   COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+			   COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+			   COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+			   -1);
+
+	g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+	GtkTreeIter *parent = parents[indent - 1];
+	GtkTreeIter *node = parents[indent];
+
+	gtk_tree_store_append(tree, node, parent);
+	set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+				    struct menu *tofind)
+{
+	GtkTreeIter iter;
+	GtkTreeIter *child = &iter;
+	gboolean valid;
+	GtkTreeIter *ret;
+
+	valid = gtk_tree_model_iter_children(model2, child, parent);
+	while (valid) {
+		struct menu *menu;
+
+		gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+		if (menu == tofind) {
+			memcpy(&found, child, sizeof(GtkTreeIter));
+			return &found;
+		}
+
+		ret = gtktree_iter_find_node(child, tofind);
+		if (ret)
+			return ret;
+
+		valid = gtk_tree_model_iter_next(model2, child);
+	}
+
+	return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+	struct menu *child1;
+	GtkTreeIter iter, tmp;
+	GtkTreeIter *child2 = &iter;
+	gboolean valid;
+	GtkTreeIter *sibling;
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *menu1, *menu2;
+
+	if (src == &rootmenu)
+		indent = 1;
+
+	valid = gtk_tree_model_iter_children(model2, child2, dst);
+	for (child1 = src->list; child1; child1 = child1->next) {
+
+		prop = child1->prompt;
+		sym = child1->sym;
+
+	      reparse:
+		menu1 = child1;
+		if (valid)
+			gtk_tree_model_get(model2, child2, COL_MENU,
+					   &menu2, -1);
+		else
+			menu2 = NULL;	// force adding of a first child
+
+#ifdef DEBUG
+		printf("%*c%s | %s\n", indent, ' ',
+		       menu1 ? menu_get_prompt(menu1) : "nil",
+		       menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+		if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
+		    (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+		    (opt_mode == OPT_ALL    && !menu_get_prompt(child1))) {
+
+			/* remove node */
+			if (gtktree_iter_find_node(dst, menu1) != NULL) {
+				memcpy(&tmp, child2, sizeof(GtkTreeIter));
+				valid = gtk_tree_model_iter_next(model2,
+								 child2);
+				gtk_tree_store_remove(tree2, &tmp);
+				if (!valid)
+					return;		/* next parent */
+				else
+					goto reparse;	/* next child */
+			} else
+				continue;
+		}
+
+		if (menu1 != menu2) {
+			if (gtktree_iter_find_node(dst, menu1) == NULL) {	// add node
+				if (!valid && !menu2)
+					sibling = NULL;
+				else
+					sibling = child2;
+				gtk_tree_store_insert_before(tree2,
+							     child2,
+							     dst, sibling);
+				set_node(child2, menu1, fill_row(menu1));
+				if (menu2 == NULL)
+					valid = TRUE;
+			} else {	// remove node
+				memcpy(&tmp, child2, sizeof(GtkTreeIter));
+				valid = gtk_tree_model_iter_next(model2,
+								 child2);
+				gtk_tree_store_remove(tree2, &tmp);
+				if (!valid)
+					return;	// next parent
+				else
+					goto reparse;	// next child
+			}
+		} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+			set_node(child2, menu1, fill_row(menu1));
+		}
+
+		indent++;
+		update_tree(child1, child2);
+		indent--;
+
+		valid = gtk_tree_model_iter_next(model2, child2);
+	}
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	enum prop_type ptype;
+
+	if (menu == &rootmenu) {
+		indent = 1;
+		current = &rootmenu;
+	}
+
+	for (child = menu->list; child; child = child->next) {
+		prop = child->prompt;
+		sym = child->sym;
+		ptype = prop ? prop->type : P_UNKNOWN;
+
+		if (sym)
+			sym->flags &= ~SYMBOL_CHANGED;
+
+		if ((view_mode == SPLIT_VIEW)
+		    && !(child->flags & MENU_ROOT) && (tree == tree1))
+			continue;
+
+		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+		    && (tree == tree2))
+			continue;
+
+		if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
+		    (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
+		    (opt_mode == OPT_ALL    && menu_get_prompt(child)))
+			place_node(child, fill_row(child));
+#ifdef DEBUG
+		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+		printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+		printf("%s", prop_get_type_name(ptype));
+		printf(" | ");
+		if (sym) {
+			printf("%s", sym_type_name(sym->type));
+			printf(" | ");
+			printf("%s", dbg_sym_flags(sym->flags));
+			printf("\n");
+		} else
+			printf("\n");
+#endif
+		if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+		    && (tree == tree2))
+			continue;
+/*
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+		    || (view_mode == FULL_VIEW)
+		    || (view_mode == SPLIT_VIEW))*/
+		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+		    || (view_mode == FULL_VIEW)
+		    || (view_mode == SPLIT_VIEW)) {
+			indent++;
+			display_tree(child);
+			indent--;
+		}
+	}
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	if (view_mode == SINGLE_VIEW)
+		display_tree(current);
+	else if (view_mode == SPLIT_VIEW)
+		display_tree(browsed);
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+	if (tree1)
+		gtk_tree_store_clear(tree1);
+
+	tree = tree1;
+	display_tree(&rootmenu);
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+	tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+	struct menu *child;
+	static int menu_cnt = 0;
+
+	menu->flags |= MENU_ROOT;
+	for (child = menu->list; child; child = child->next) {
+		if (child->prompt && child->prompt->type == P_MENU) {
+			menu_cnt++;
+			fixup_rootmenu(child);
+			menu_cnt--;
+		} else if (!menu_cnt)
+			fixup_rootmenu(child);
+	}
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+	const char *name;
+	char *env;
+	gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+	kconfig_load();
+#endif
+
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset(PACKAGE, "UTF-8");
+	textdomain(PACKAGE);
+
+	/* GTK stuffs */
+	gtk_set_locale();
+	gtk_init(&ac, &av);
+	glade_init();
+
+	//add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+	//add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+	/* Determine GUI path */
+	env = getenv(SRCTREE);
+	if (env)
+		glade_file = g_strconcat(env, "/tools/kconfig/gconf.glade", NULL);
+	else if (av[0][0] == '/')
+		glade_file = g_strconcat(av[0], ".glade", NULL);
+	else
+		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+	/* Conf stuffs */
+	if (ac > 1 && av[1][0] == '-') {
+		switch (av[1][1]) {
+		case 'a':
+			//showAll = 1;
+			break;
+		case 'h':
+		case '?':
+			printf("%s <config>\n", av[0]);
+			exit(0);
+		}
+		name = av[2];
+	} else
+		name = av[1];
+
+	conf_parse(name);
+	fixup_rootmenu(&rootmenu);
+	conf_read(NULL);
+
+	/* Load the interface and connect signals */
+	init_main_window(glade_file);
+	init_tree_model();
+	init_left_tree();
+	init_right_tree();
+
+	switch (view_mode) {
+	case SINGLE_VIEW:
+		display_tree_part();
+		break;
+	case SPLIT_VIEW:
+		display_list();
+		break;
+	case FULL_VIEW:
+		display_tree(&rootmenu);
+		break;
+	}
+
+	gtk_main();
+
+	return 0;
+}
+
+static void conf_changed(void)
+{
+	bool changed = conf_get_changed();
+	gtk_widget_set_sensitive(save_btn, changed);
+	gtk_widget_set_sensitive(save_menu_item, changed);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.glade b/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.glade
new file mode 100644
index 0000000..aa483cb
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/gconf.glade
@@ -0,0 +1,661 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+  <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+  <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+	<widget class="GtkMenuBar" id="menubar1">
+	  <property name="visible">True</property>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="file1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_File</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="file1_menu">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="load1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Load a config file</property>
+		      <property name="label" translatable="yes">_Load</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_load1_activate"/>
+		      <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image39">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-open</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Save the config in .config</property>
+		      <property name="label" translatable="yes">_Save</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_save_activate"/>
+		      <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image40">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-save</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save_as1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Save the config in a file</property>
+		      <property name="label" translatable="yes">Save _as</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_save_as1_activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image41">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-save-as</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separator1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="quit1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Quit</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_quit1_activate"/>
+		      <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image42">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-quit</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="options1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Options</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="options1_menu">
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_name1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show name</property>
+		      <property name="label" translatable="yes">Show _name</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_name1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_range1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+		      <property name="label" translatable="yes">Show _range</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_range1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_data1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show value of the option</property>
+		      <property name="label" translatable="yes">Show _data</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_data1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separator2">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkRadioMenuItem" id="set_option_mode1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show normal options</property>
+		      <property name="label" translatable="yes">Show normal options</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">True</property>
+		      <signal name="activate" handler="on_set_option_mode1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkRadioMenuItem" id="set_option_mode2">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show all options</property>
+		      <property name="label" translatable="yes">Show all _options</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <property name="group">set_option_mode1</property>
+		      <signal name="activate" handler="on_set_option_mode2_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkRadioMenuItem" id="set_option_mode3">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show all options with prompts</property>
+		      <property name="label" translatable="yes">Show all prompt options</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <property name="group">set_option_mode1</property>
+		      <signal name="activate" handler="on_set_option_mode3_activate"/>
+		    </widget>
+		  </child>
+
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="help1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Help</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="help1_menu">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="introduction1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Introduction</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+		      <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image43">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-dialog-question</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="about1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_About</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+		      <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image44">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-properties</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="license1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_License</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image45">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-justify-fill</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHandleBox" id="handlebox1">
+	  <property name="visible">True</property>
+	  <property name="shadow_type">GTK_SHADOW_OUT</property>
+	  <property name="handle_position">GTK_POS_LEFT</property>
+	  <property name="snap_edge">GTK_POS_TOP</property>
+
+	  <child>
+	    <widget class="GtkToolbar" id="toolbar1">
+	      <property name="visible">True</property>
+	      <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+	      <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+	      <property name="tooltips">True</property>
+	      <property name="show_arrow">True</property>
+
+	      <child>
+		<widget class="GtkToolButton" id="button1">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+		  <property name="label" translatable="yes">Back</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-undo</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_back_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem1">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button2">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Load a config file</property>
+		  <property name="label" translatable="yes">Load</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-open</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_load_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button3">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Save a config file</property>
+		  <property name="label" translatable="yes">Save</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-save</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_save_activate"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem2">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator2">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button4">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Single view</property>
+		  <property name="label" translatable="yes">Single</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button5">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Split view</property>
+		  <property name="label" translatable="yes">Split</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button6">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Full view</property>
+		  <property name="label" translatable="yes">Full</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem3">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator3">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button7">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+		  <property name="label" translatable="yes">Collapse</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-remove</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_collapse_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button8">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+		  <property name="label" translatable="yes">Expand</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-add</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_expand_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHPaned" id="hpaned1">
+	  <property name="width_request">1</property>
+	  <property name="visible">True</property>
+	  <property name="can_focus">True</property>
+	  <property name="position">0</property>
+
+	  <child>
+	    <widget class="GtkScrolledWindow" id="scrolledwindow1">
+	      <property name="visible">True</property>
+	      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+	      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+	      <property name="shadow_type">GTK_SHADOW_IN</property>
+	      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+	      <child>
+		<widget class="GtkTreeView" id="treeview1">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="headers_visible">True</property>
+		  <property name="rules_hint">False</property>
+		  <property name="reorderable">False</property>
+		  <property name="enable_search">False</property>
+		  <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+		  <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+		  <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="shrink">True</property>
+	      <property name="resize">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkVPaned" id="vpaned1">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="position">0</property>
+
+	      <child>
+		<widget class="GtkScrolledWindow" id="scrolledwindow2">
+		  <property name="visible">True</property>
+		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="shadow_type">GTK_SHADOW_IN</property>
+		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		  <child>
+		    <widget class="GtkTreeView" id="treeview2">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="has_focus">True</property>
+		      <property name="headers_visible">True</property>
+		      <property name="rules_hint">False</property>
+		      <property name="reorderable">False</property>
+		      <property name="enable_search">False</property>
+		      <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+		      <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+		      <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="shrink">True</property>
+		  <property name="resize">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkScrolledWindow" id="scrolledwindow3">
+		  <property name="visible">True</property>
+		  <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="shadow_type">GTK_SHADOW_IN</property>
+		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		  <child>
+		    <widget class="GtkTextView" id="textview3">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">False</property>
+		      <property name="overwrite">False</property>
+		      <property name="accepts_tab">True</property>
+		      <property name="justification">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap_mode">GTK_WRAP_WORD</property>
+		      <property name="cursor_visible">True</property>
+		      <property name="pixels_above_lines">0</property>
+		      <property name="pixels_below_lines">0</property>
+		      <property name="pixels_inside_wrap">0</property>
+		      <property name="left_margin">0</property>
+		      <property name="right_margin">0</property>
+		      <property name="indent">0</property>
+		      <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="shrink">True</property>
+		  <property name="resize">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="shrink">True</property>
+	      <property name="resize">True</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/images.c b/qemu-0.15.x/roms/seabios/tools/kconfig/images.c
new file mode 100644
index 0000000..d4f84bd
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/images.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .      . . ",
+" .     .. . ",
+" . .  ..  . ",
+" . ....   . ",
+" .  ..    . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" . ..     . ",
+" . ....   . ",
+" . ...... . ",
+" . ...... . ",
+" . ....   . ",
+" . ..     . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .......... ",
+" ..  ...... ",
+" ..    .... ",
+" ..      .. ",
+" ..      .. ",
+" ..    .... ",
+" ..  ...... ",
+" .......... ",
+" .......... ",
+"            "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .     .. . ",
+" .   .... . ",
+" . ...... . ",
+" . ...... . ",
+" .   .... . ",
+" .     .. . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            "};
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/kconfig_load.c b/qemu-0.15.x/roms/seabios/tools/kconfig/kconfig_load.c
new file mode 100644
index 0000000..2d0cff8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/kconfig_load.c
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg)	type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+	void *handle;
+	char *error;
+
+	handle = dlopen("./libkconfig.so", RTLD_LAZY);
+	if (!handle) {
+		handle = dlopen("./tools/kconfig/libkconfig.so", RTLD_LAZY);
+		if (!handle) {
+			fprintf(stderr, "%s\n", dlerror());
+			exit(1);
+		}
+	}
+
+#define P(name,type,arg)			\
+{						\
+	name ## _p = dlsym(handle, #name);	\
+        if ((error = dlerror()))  {		\
+                fprintf(stderr, "%s\n", error);	\
+		exit(1);			\
+	}					\
+}
+#include "lkc_proto.h"
+#undef P
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/kxgettext.c b/qemu-0.15.x/roms/seabios/tools/kconfig/kxgettext.c
new file mode 100644
index 0000000..e9d8e79
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/kxgettext.c
@@ -0,0 +1,236 @@
+/*
+ * Arnaldo Carvalho de Melo <acme at conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+	char *bfp = bf;
+	int multiline = strchr(text, '\n') != NULL;
+	int eol = 0;
+	int textlen = strlen(text);
+
+	if ((textlen > 0) && (text[textlen-1] == '\n'))
+		eol = 1;
+
+	*bfp++ = '"';
+	--len;
+
+	if (multiline) {
+		*bfp++ = '"';
+		*bfp++ = '\n';
+		*bfp++ = '"';
+		len -= 3;
+	}
+
+	while (*text != '\0' && len > 1) {
+		if (*text == '"')
+			*bfp++ = '\\';
+		else if (*text == '\n') {
+			*bfp++ = '\\';
+			*bfp++ = 'n';
+			*bfp++ = '"';
+			*bfp++ = '\n';
+			*bfp++ = '"';
+			len -= 5;
+			++text;
+			goto next;
+		}
+		else if (*text == '\\') {
+			*bfp++ = '\\';
+			len--;
+		}
+		*bfp++ = *text++;
+next:
+		--len;
+	}
+
+	if (multiline && eol)
+		bfp -= 3;
+
+	*bfp++ = '"';
+	*bfp = '\0';
+
+	return bf;
+}
+
+struct file_line {
+	struct file_line *next;
+	const char *file;
+	int lineno;
+};
+
+static struct file_line *file_line__new(const char *file, int lineno)
+{
+	struct file_line *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->file   = file;
+	self->lineno = lineno;
+	self->next   = NULL;
+out:
+	return self;
+}
+
+struct message {
+	const char	 *msg;
+	const char	 *option;
+	struct message	 *next;
+	struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option,
+				    const char *file, int lineno)
+{
+	struct message *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->files = file_line__new(file, lineno);
+	if (self->files == NULL)
+		goto out_fail;
+
+	self->msg = strdup(msg);
+	if (self->msg == NULL)
+		goto out_fail_msg;
+
+	self->option = option;
+	self->next = NULL;
+out:
+	return self;
+out_fail_msg:
+	free(self->files);
+out_fail:
+	free(self);
+	self = NULL;
+	goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		if (strcmp(m->msg, msg) == 0)
+			break;
+		m = m->next;
+	}
+
+	return m;
+}
+
+static int message__add_file_line(struct message *self, const char *file,
+				  int lineno)
+{
+	int rc = -1;
+	struct file_line *fl = file_line__new(file, lineno);
+
+	if (fl == NULL)
+		goto out;
+
+	fl->next    = self->files;
+	self->files = fl;
+	rc = 0;
+out:
+	return rc;
+}
+
+static int message__add(const char *msg, char *option, const char *file,
+			int lineno)
+{
+	int rc = 0;
+	char bf[16384];
+	char *escaped = escape(msg, bf, sizeof(bf));
+	struct message *m = mesage__find(escaped);
+
+	if (m != NULL)
+		rc = message__add_file_line(m, file, lineno);
+	else {
+		m = message__new(escaped, option, file, lineno);
+
+		if (m != NULL) {
+			m->next	      = message__list;
+			message__list = m;
+		} else
+			rc = -1;
+	}
+	return rc;
+}
+
+static void menu_build_message_list(struct menu *menu)
+{
+	struct menu *child;
+
+	message__add(menu_get_prompt(menu), NULL,
+		     menu->file == NULL ? "Root Menu" : menu->file->name,
+		     menu->lineno);
+
+	if (menu->sym != NULL && menu_has_help(menu))
+		message__add(menu_get_help(menu), menu->sym->name,
+			     menu->file == NULL ? "Root Menu" : menu->file->name,
+			     menu->lineno);
+
+	for (child = menu->list; child != NULL; child = child->next)
+		if (child->prompt != NULL)
+			menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+	struct file_line *fl = self->files;
+
+	putchar('\n');
+	if (self->option != NULL)
+		printf("# %s:00000\n", self->option);
+
+	printf("#: %s:%d", fl->file, fl->lineno);
+	fl = fl->next;
+
+	while (fl != NULL) {
+		printf(", %s:%d", fl->file, fl->lineno);
+		fl = fl->next;
+	}
+
+	putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+	message__print_file_lineno(self);
+
+	printf("msgid %s\n"
+	       "msgstr \"\"\n", self->msg);
+}
+
+static void menu__xgettext(void)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		/* skip empty lines ("") */
+		if (strlen(m->msg) > sizeof("\"\""))
+			message__print_gettext_msgid_msgstr(m);
+		m = m->next;
+	}
+}
+
+int main(int ac, char **av)
+{
+	conf_parse(av[1]);
+
+	menu_build_message_list(menu_get_root_menu(NULL));
+	menu__xgettext();
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lex.zconf.c_shipped b/qemu-0.15.x/roms/seabios/tools/kconfig/lex.zconf.c_shipped
new file mode 100644
index 0000000..6eb0397
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lex.zconf.c_shipped
@@ -0,0 +1,2430 @@
+
+#line 3 "scripts/kconfig/lex.zconf.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via zconfrestart()), so that the user can continue scanning by
+	 * just pointing zconfin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	zconfleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+#define YY_NO_INPUT 1
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+	text = malloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+	text = malloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *zconfget_in (void );
+
+void zconfset_in  (FILE * in_str  );
+
+FILE *zconfget_out (void );
+
+void zconfset_out  (FILE * out_str  );
+
+int zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	errno=0; \
+	while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+	{ \
+		if( errno != EINTR) \
+		{ \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+			break; \
+		} \
+		errno=0; \
+		clearerr(zconfin); \
+	}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+	int str = 0;
+	int ts, i;
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! zconfin )
+			zconfin = stdin;
+
+		if ( ! zconfout )
+			zconfout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			zconfensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				zconf_create_buffer(zconfin,YY_BUF_SIZE );
+		}
+
+		zconf_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of zconftext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+			++yy_cp;
+
+		yy_current_state = -yy_current_state;
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+	current_file->lineno++;
+	return T_EOL;
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+	unput(zconftext[0]);
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+	YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+		str = zconftext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+	YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+	YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+	}
+	YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+	}
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+		if (str == zconftext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(zconftext, 1);
+	}
+	YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+		ts = 0;
+		for (i = 0; i < zconfleng; i++) {
+			if (zconftext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+		while (zconfleng) {
+			if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+				break;
+			zconfleng--;
+		}
+		append_string(zconftext, zconfleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(zconfin);
+	yyterminate();
+}
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+	YY_BREAK
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed zconfin at a new source and called
+			 * zconflex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( zconfwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * zconftext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			zconfrestart(zconfin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	yy_current_state = yy_nxt[yy_current_state][1];
+	yy_is_jam = (yy_current_state <= 0);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up zconftext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					zconfrestart(zconfin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( zconfwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve zconftext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+	}
+
+	zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+	zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		zconfpop_buffer_state();
+	 *		zconfpush_buffer_state(new_buffer);
+     */
+	zconfensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	zconf_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (zconfwrap()) processing, but the only time this flag
+	 * is looked at is after zconfwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	zconf_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		zconffree((void *) b->yy_ch_buf  );
+
+	zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	zconf_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	zconfensure_buffer_stack();
+
+	/* This block is copied from zconf_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from zconf_switch_to_buffer. */
+	zconf_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	zconf_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		zconf_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	zconf_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+    
+	return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) zconfalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = zconf_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		zconftext[zconfleng] = (yy_hold_char); \
+		(yy_c_buf_p) = zconftext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		zconfleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		zconf_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		zconfpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	zconffree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+	free( (char *) ptr );	/* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = malloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+	current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+	struct file *file = file_lookup(name);
+	struct buffer *buf = malloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	zconfin = zconf_fopen(file->name);
+	if (!zconfin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
+		exit(1);
+	}
+	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	if (file->flags & FILE_BUSY) {
+		printf("%s:%d: do not source '%s' from itself\n",
+		       zconf_curname(), zconf_lineno(), name);
+		exit(1);
+	}
+	if (file->flags & FILE_SCANNED) {
+		printf("%s:%d: file '%s' is already sourced from '%s'\n",
+		       zconf_curname(), zconf_lineno(), name,
+		       file->parent->name);
+		exit(1);
+	}
+	file->flags |= FILE_BUSY;
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file->flags |= FILE_SCANNED;
+	current_file->flags &= ~FILE_BUSY;
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(zconfin);
+		zconf_delete_buffer(YY_CURRENT_BUFFER);
+		zconf_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lkc.h b/qemu-0.15.x/roms/seabios/tools/kconfig/lkc.h
new file mode 100644
index 0000000..febf0c9
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lkc.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)	extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)	extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#ifndef PACKAGE
+#define PACKAGE "linux"
+#endif
+
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+
+#define TF_COMMAND	0x0001
+#define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+enum conf_def_mode {
+	def_default,
+	def_yes,
+	def_mod,
+	def_no,
+	def_random
+};
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
+#define T_OPT_ENV		3
+
+struct kconf_id {
+	int name;
+	int token;
+	unsigned int flags;
+	enum symbol_type stype;
+};
+
+#ifdef YYDEBUG
+extern int zconfdebug;
+#endif
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+const char *zconf_curname(void);
+
+/* conf.c */
+void xfgets(char *str, int size, FILE *in);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+void conf_set_all_new_symbols(enum conf_def_mode mode);
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+	if (fwrite(str, len, count, out) < count)
+		fprintf(stderr, "\nError in writing or end of file.\n");
+}
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+	size_t len;
+	char  *s;
+	/*
+	* when max_width is not zero long lines in string s (if any) get
+	* wrapped not to exceed the max_width value
+	*/
+	int max_width;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+	return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+	return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+	return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lkc_proto.h b/qemu-0.15.x/roms/seabios/tools/kconfig/lkc_proto.h
new file mode 100644
index 0000000..17342fe
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lkc_proto.h
@@ -0,0 +1,53 @@
+#include <stdarg.h>
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_expand_string_value,const char *,(const char *in));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/.gitignore b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/.gitignore
new file mode 100644
index 0000000..90b08ff
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/.gitignore
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+lxdialog
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644
index 0000000..a8999d8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog.  This version has been
+significantly modified from the original.  It is for use by the Linux
+kernel configuration script.  Please do not bother Savio Lam with 
+questions about this program.
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/check-lxdialog.sh b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644
index 0000000..82cc3a8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/check-lxdialog.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+	for ext in so a dylib ; do
+		for lib in ncursesw ncurses curses ; do
+			$cc -print-file-name=lib${lib}.${ext} | grep -q /
+			if [ $? -eq 0 ]; then
+				echo "-l${lib}"
+				exit
+			fi
+		done
+	done
+	exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+	if [ -f /usr/include/ncurses/ncurses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+	elif [ -f /usr/include/ncurses/curses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+	elif [ -f /usr/include/ncursesw/curses.h ]; then
+		echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
+	elif [ -f /usr/include/ncurses.h ]; then
+		echo '-DCURSES_LOC="<ncurses.h>"'
+	else
+		echo '-DCURSES_LOC="<curses.h>"'
+	fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+        $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
+	if [ $? != 0 ]; then
+	    echo " *** Unable to find the ncurses libraries or the"       1>&2
+	    echo " *** required header files."                            1>&2
+	    echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+	    echo " *** "                                                  1>&2
+	    echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+	    echo " *** "                                                  1>&2
+	    exit 1
+	fi
+}
+
+usage() {
+	printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
+}
+
+if [ $# -eq 0 ]; then
+	usage
+	exit 1
+fi
+
+cc=""
+case "$1" in
+	"-check")
+		shift
+		cc="$@"
+		check
+		;;
+	"-ccflags")
+		ccflags
+		;;
+	"-ldflags")
+		shift
+		cc="$@"
+		ldflags
+		;;
+	"*")
+		usage
+		exit 1
+		;;
+esac
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/checklist.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/checklist.c
new file mode 100644
index 0000000..a2eb80f
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/checklist.c
@@ -0,0 +1,332 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert at sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini at ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	if (!item_is_tag(':'))
+		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, list_item[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, list_item + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+	free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("Select"), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
+	}
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 6))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 6))
+		return -ERRDISPLAYTOOSMALL;
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+	              x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+	         dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
+
+	check_x = (list_width - check_x) / 2;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+		case '?':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/dialog.h b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/dialog.h
new file mode 100644
index 0000000..b5211fc
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/dialog.h
@@ -0,0 +1,230 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)		/*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* promtp displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+	      chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+		  int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+		    int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/inputbox.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/inputbox.c
new file mode 100644
index 0000000..dd8e587
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/inputbox.c
@@ -0,0 +1,238 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+                    const char *init)
+{
+	int i, x, y, box_y, box_x, box_width;
+	int input_x = 0, scroll = 0, key = 0, button = -1;
+	char *instr = dialog_input_result;
+	WINDOW *dialog;
+
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - 2))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - 2))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	/* Draw the input field box */
+	box_width = width - 6;
+	getyx(dialog, y, x);
+	box_y = y + 2;
+	box_x = (width - box_width) / 2;
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	print_buttons(dialog, height, width, 0);
+
+	/* Set up the initial value */
+	wmove(dialog, box_y, box_x);
+	wattrset(dialog, dlg.inputbox.atr);
+
+	input_x = strlen(instr);
+
+	if (input_x >= box_width) {
+		scroll = input_x - box_width + 1;
+		input_x = box_width - 1;
+		for (i = 0; i < box_width - 1; i++)
+			waddch(dialog, instr[scroll + i]);
+	} else {
+		waddstr(dialog, instr);
+	}
+
+	wmove(dialog, box_y, box_x + input_x);
+
+	wrefresh(dialog);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		if (button == -1) {	/* Input box selected */
+			switch (key) {
+			case TAB:
+			case KEY_UP:
+			case KEY_DOWN:
+				break;
+			case KEY_LEFT:
+				continue;
+			case KEY_RIGHT:
+				continue;
+			case KEY_BACKSPACE:
+			case 127:
+				if (input_x || scroll) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (!input_x) {
+						scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++)
+							waddch(dialog,
+							       instr[scroll + input_x + i] ?
+							       instr[scroll + input_x + i] : ' ');
+						input_x = strlen(instr) - scroll;
+					} else
+						input_x--;
+					instr[scroll + input_x] = '\0';
+					mvwaddch(dialog, box_y, input_x + box_x, ' ');
+					wmove(dialog, box_y, input_x + box_x);
+					wrefresh(dialog);
+				}
+				continue;
+			default:
+				if (key < 0x100 && isprint(key)) {
+					if (scroll + input_x < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						instr[scroll + input_x] = key;
+						instr[scroll + input_x + 1] = '\0';
+						if (input_x == box_width - 1) {
+							scroll++;
+							wmove(dialog, box_y, box_x);
+							for (i = 0; i < box_width - 1; i++)
+								waddch(dialog, instr [scroll + i]);
+						} else {
+							wmove(dialog, box_y, input_x++ + box_x);
+							waddch(dialog, key);
+						}
+						wrefresh(dialog);
+					} else
+						flash();	/* Alarm user about overflow */
+					continue;
+				}
+			}
+		}
+		switch (key) {
+		case 'O':
+		case 'o':
+			delwin(dialog);
+			return 0;
+		case 'H':
+		case 'h':
+			delwin(dialog);
+			return 1;
+		case KEY_UP:
+		case KEY_LEFT:
+			switch (button) {
+			case -1:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 0:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			case 1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			}
+			break;
+		case TAB:
+		case KEY_DOWN:
+		case KEY_RIGHT:
+			switch (button) {
+			case -1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			case 0:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 1:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			}
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return (button == -1 ? 0 : button);
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return KEY_ESC;		/* ESC pressed */
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/menubox.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/menubox.c
new file mode 100644
index 0000000..1d60473
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/menubox.c
@@ -0,0 +1,434 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god at clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec at shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+                          int selected, int hotkey)
+{
+	int j;
+	char *menu_item = malloc(menu_width + 1);
+
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
+	j = first_alpha(menu_item, "YyNnMmHh");
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < menu_width; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
+	if (hotkey) {
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
+	}
+	if (selected) {
+		wmove(win, line_y, item_x + 1);
+	}
+	free(menu_item);
+	wrefresh(win);
+}
+
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+			 int height)
+{
+	int cur_y, cur_x;
+
+	getyx(win, cur_y, cur_x);
+
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+	wrefresh(win);
+
+	if ((height < item_no) && (scroll + height < item_no)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	wmove(win, cur_y, cur_x);
+	wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+	int x = width / 2 - 16;
+	int y = height - 2;
+
+	print_button(win, gettext("Select"), y, x, selected == 0);
+	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+
+	wmove(win, y, x + 1 + 12 * selected);
+	wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+	/* Scroll menu up */
+	scrollok(win, TRUE);
+	wscrl(win, n);
+	scrollok(win, FALSE);
+	*scroll = *scroll + n;
+	wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
+{
+	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
+	int key = 0, button = 0, scroll = 0, choice = 0;
+	int first_item =  0, max_choice;
+	WINDOW *dialog, *menu;
+
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < 15 || width < 65)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
+	max_choice = MIN(menu_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	menu_width = width - 6;
+	box_y = height - menu_height - 5;
+	box_x = (width - menu_width) / 2 - 1;
+
+	/* create new window for the menu */
+	menu = subwin(dialog, menu_height, menu_width,
+		      y + box_y + 1, x + box_x + 1);
+	keypad(menu, TRUE);
+
+	/* draw a box around the menu items */
+	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
+
+	/* Set choice to default item */
+	item_foreach()
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
+	}
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
+		else
+			scroll = first_item = choice - max_choice / 2;
+		choice = choice - scroll;
+	}
+
+	/* Print the menu */
+	for (i = 0; i < max_choice; i++) {
+		print_item(first_item + i, i, i == choice);
+	}
+
+	wnoutrefresh(menu);
+
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
+
+	print_buttons(dialog, height, width, 0);
+	wmove(menu, choice, item_x + 1);
+	wrefresh(menu);
+
+	while (key != KEY_ESC) {
+		key = wgetch(menu);
+
+		if (key < 256 && isalpha(key))
+			key = tolower(key);
+
+		if (strchr("ynmh", key))
+			i = max_choice;
+		else {
+			for (i = choice + 1; i < max_choice; i++) {
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
+					break;
+			}
+			if (i == max_choice)
+				for (i = 0; i < max_choice; i++) {
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
+						break;
+				}
+		}
+
+		if (i < max_choice ||
+		    key == KEY_UP || key == KEY_DOWN ||
+		    key == '-' || key == '+' ||
+		    key == KEY_PPAGE || key == KEY_NPAGE) {
+			/* Remove highligt of current item */
+			print_item(scroll + choice, choice, FALSE);
+
+			if (key == KEY_UP || key == '-') {
+				if (choice < 2 && scroll) {
+					/* Scroll menu down */
+					do_scroll(menu, &scroll, -1);
+
+					print_item(scroll, 0, FALSE);
+				} else
+					choice = MAX(choice - 1, 0);
+
+			} else if (key == KEY_DOWN || key == '+') {
+				print_item(scroll+choice, choice, FALSE);
+
+				if ((choice > max_choice - 3) &&
+				    (scroll + max_choice < item_count())) {
+					/* Scroll menu up */
+					do_scroll(menu, &scroll, 1);
+
+					print_item(scroll+max_choice - 1,
+						   max_choice - 1, FALSE);
+				} else
+					choice = MIN(choice + 1, max_choice - 1);
+
+			} else if (key == KEY_PPAGE) {
+				scrollok(menu, TRUE);
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll > 0) {
+						do_scroll(menu, &scroll, -1);
+						print_item(scroll, 0, FALSE);
+					} else {
+						if (choice > 0)
+							choice--;
+					}
+				}
+
+			} else if (key == KEY_NPAGE) {
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll + max_choice < item_count()) {
+						do_scroll(menu, &scroll, 1);
+						print_item(scroll+max_choice-1,
+							   max_choice - 1, FALSE);
+					} else {
+						if (choice + 1 < max_choice)
+							choice++;
+					}
+				}
+			} else
+				choice = i;
+
+			print_item(scroll + choice, choice, TRUE);
+
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
+
+			wnoutrefresh(dialog);
+			wrefresh(menu);
+
+			continue;	/* wait for another key press */
+		}
+
+		switch (key) {
+		case KEY_LEFT:
+		case TAB:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 2 : (button > 2 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(menu);
+			break;
+		case ' ':
+		case 's':
+		case 'y':
+		case 'n':
+		case 'm':
+		case '/':
+		case 'h':
+		case '?':
+		case 'z':
+		case '\n':
+			/* save scroll info */
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			switch (key) {
+			case 'h':
+			case '?':
+				return 2;
+			case 's':
+			case 'y':
+				return 3;
+			case 'n':
+				return 4;
+			case 'm':
+				return 5;
+			case ' ':
+				return 6;
+			case '/':
+				return 7;
+			case 'z':
+				return 8;
+			case '\n':
+				return button;
+			}
+			return 0;
+		case 'e':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
+			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
+		}
+	}
+	delwin(menu);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/textbox.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/textbox.c
new file mode 100644
index 0000000..c704712
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/textbox.c
@@ -0,0 +1,391 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+							  int cur_y, int cur_x)
+{
+	print_page(box, boxh, boxw);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+		   int initial_height, int initial_width)
+{
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	int passed_end;
+	WINDOW *dialog, *box;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < 8 || width < 8)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+	keypad(box, TRUE);
+
+	/* register the new window, along with its borders */
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+	wnoutrefresh(dialog);
+	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
+
+	/* Print first page of text */
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+	while ((key != KEY_ESC) && (key != '\n')) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'E':	/* Exit */
+		case 'e':
+		case 'X':
+		case 'x':
+			delwin(box);
+			delwin(dialog);
+			return 0;
+		case 'g':	/* First page */
+		case KEY_HOME:
+			if (!begin_reached) {
+				begin_reached = 1;
+				page = buf;
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x);
+			}
+			break;
+		case 'G':	/* Last page */
+		case KEY_END:
+
+			end_reached = 1;
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'K':	/* Previous line */
+		case 'k':
+		case KEY_UP:
+			if (!begin_reached) {
+				back_lines(page_length + 1);
+
+				/* We don't call print_page() here but use
+				 * scrolling to ensure faster screen update.
+				 * However, 'end_reached' and 'page_length'
+				 * should still be updated, and 'page' should
+				 * point to start of next page. This is done
+				 * by calling get_line() in the following
+				 * 'for' loop. */
+				scrollok(box, TRUE);
+				wscrl(box, -1);	/* Scroll box region down one line */
+				scrollok(box, FALSE);
+				page_length = 0;
+				passed_end = 0;
+				for (i = 0; i < boxh; i++) {
+					if (!i) {
+						/* print first line of page */
+						print_line(box, 0, boxw);
+						wnoutrefresh(box);
+					} else
+						/* Called to update 'end_reached' and 'page' */
+						get_line();
+					if (!passed_end)
+						page_length++;
+					if (end_reached && !passed_end)
+						passed_end = 1;
+				}
+
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case 'B':	/* Previous page */
+		case 'b':
+		case KEY_PPAGE:
+			if (begin_reached)
+				break;
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'J':	/* Next line */
+		case 'j':
+		case KEY_DOWN:
+			if (!end_reached) {
+				begin_reached = 0;
+				scrollok(box, TRUE);
+				scroll(box);	/* Scroll box region up one line */
+				scrollok(box, FALSE);
+				print_line(box, boxh - 1, boxw);
+				wnoutrefresh(box);
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case KEY_NPAGE:	/* Next page */
+		case ' ':
+			if (end_reached)
+				break;
+
+			begin_reached = 0;
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case '0':	/* Beginning of line */
+		case 'H':	/* Scroll left */
+		case 'h':
+		case KEY_LEFT:
+			if (hscroll <= 0)
+				break;
+
+			if (key == '0')
+				hscroll = 0;
+			else
+				hscroll--;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'L':	/* Scroll right */
+		case 'l':
+		case KEY_RIGHT:
+			if (hscroll >= MAX_LEN)
+				break;
+			hscroll++;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+	delwin(box);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+	int i;
+
+	begin_reached = 0;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
+			}
+		}
+		if (page == buf) {
+			begin_reached = 1;
+			return;
+		}
+		page--;
+		do {
+			if (page == buf) {
+				begin_reached = 1;
+				return;
+			}
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+	int i, passed_end = 0;
+
+	page_length = 0;
+	for (i = 0; i < height; i++) {
+		print_line(win, i, width);
+		if (!passed_end)
+			page_length++;
+		if (end_reached && !passed_end)
+			passed_end = 1;
+	}
+	wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+	int y, x;
+	char *line;
+
+	line = get_line();
+	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
+	wmove(win, row, 0);	/* move cursor to correct line */
+	waddch(win, ' ');
+	waddnstr(win, line, MIN(strlen(line), width - 2));
+
+	getyx(win, y, x);
+	/* Clear 'residue' of previous line */
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < width - x; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+	int i = 0;
+	static char line[MAX_LEN + 1];
+
+	end_reached = 0;
+	while (*page != '\n') {
+		if (*page == '\0') {
+			if (!end_reached) {
+				end_reached = 1;
+				break;
+			}
+		} else if (i < MAX_LEN)
+			line[i++] = *(page++);
+		else {
+			/* Truncate lines longer than MAX_LEN characters */
+			if (i == MAX_LEN)
+				line[i++] = '\0';
+			page++;
+		}
+	}
+	if (i <= MAX_LEN)
+		line[i] = '\0';
+	if (!end_reached)
+		page++;		/* move pass '\n' */
+
+	return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+	int percent;
+
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+	wprintw(win, "(%3d%%)", percent);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/util.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/util.c
new file mode 100644
index 0000000..f2375ad
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/util.c
@@ -0,0 +1,657 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 0;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+	int use_color;
+
+	use_color = set_theme(theme);
+	if (use_color && has_colors()) {
+		start_color();
+		init_dialog_colors();
+	} else
+		set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+	int i, j;
+
+	wattrset(win, attr);
+	for (i = 0; i < height; i++) {
+		wmove(win, i, 0);
+		for (j = 0; j < width; j++)
+			waddch(win, ' ');
+	}
+	touchwin(win);
+}
+
+void dialog_clear(void)
+{
+	attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+	/* Display background title if it exists ... - SLH */
+	if (dlg.backtitle != NULL) {
+		int i;
+
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+		wmove(stdscr, 1, 1);
+		for (i = 1; i < COLS - 1; i++)
+			waddch(stdscr, ACS_HLINE);
+	}
+	wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+	int height, width;
+
+	initscr();		/* Init curses */
+	getmaxyx(stdscr, height, width);
+	if (height < 19 || width < 80) {
+		endwin();
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	dlg.backtitle = backtitle;
+	color_setup(getenv("MENUCONFIG_COLOR"));
+
+	keypad(stdscr, TRUE);
+	cbreak();
+	noecho();
+	dialog_clear();
+
+	return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+	/* move cursor back to original position */
+	move(y, x);
+	refresh();
+	endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+	if (title) {
+		int tlen = MIN(width - 2, strlen(title));
+		wattrset(dialog, dlg.title.atr);
+		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+		waddch(dialog, ' ');
+	}
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+	int newl, cur_x, cur_y;
+	int i, prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+	strcpy(tempstr, prompt);
+
+	prompt_len = strlen(tempstr);
+
+	/*
+	 * Remove newlines
+	 */
+	for (i = 0; i < prompt_len; i++) {
+		if (tempstr[i] == '\n')
+			tempstr[i] = ' ';
+	}
+
+	if (prompt_len <= width - x * 2) {	/* If prompt is short */
+		wmove(win, y, (width - prompt_len) / 2);
+		waddstr(win, tempstr);
+	} else {
+		cur_x = x;
+		cur_y = y;
+		newl = 1;
+		word = tempstr;
+		while (word && *word) {
+			sp = strchr(word, ' ');
+			if (sp)
+				*sp++ = 0;
+
+			/* Wrap to next line if either the word does not fit,
+			   or it is the first word of a new sentence, and it is
+			   short, and the next word does not fit. */
+			room = width - cur_x;
+			wlen = strlen(word);
+			if (wlen > room ||
+			    (newl && wlen < 4 && sp
+			     && wlen + 1 + strlen(sp) > room
+			     && (!(sp2 = strchr(sp, ' '))
+				 || wlen + 1 + (sp2 - sp) > room))) {
+				cur_y++;
+				cur_x = x;
+			}
+			wmove(win, cur_y, cur_x);
+			waddstr(win, word);
+			getyx(win, cur_y, cur_x);
+			cur_x++;
+			if (sp && *sp == ' ') {
+				cur_x++;	/* double space */
+				while (*++sp == ' ') ;
+				newl = 1;
+			} else
+				newl = 0;
+			word = sp;
+		}
+	}
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+	int i, temp;
+
+	wmove(win, y, x);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, "<");
+	temp = strspn(label, " ");
+	label += temp;
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	for (i = 0; i < temp; i++)
+		waddch(win, ' ');
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
+	waddch(win, label[0]);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	waddstr(win, (char *)label + 1);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, ">");
+	wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+	 chtype box, chtype border)
+{
+	int i, j;
+
+	wattrset(win, 0);
+	for (i = 0; i < height; i++) {
+		wmove(win, y + i, x);
+		for (j = 0; j < width; j++)
+			if (!i && !j)
+				waddch(win, border | ACS_ULCORNER);
+			else if (i == height - 1 && !j)
+				waddch(win, border | ACS_LLCORNER);
+			else if (!i && j == width - 1)
+				waddch(win, box | ACS_URCORNER);
+			else if (i == height - 1 && j == width - 1)
+				waddch(win, box | ACS_LRCORNER);
+			else if (!i)
+				waddch(win, border | ACS_HLINE);
+			else if (i == height - 1)
+				waddch(win, box | ACS_HLINE);
+			else if (!j)
+				waddch(win, border | ACS_VLINE);
+			else if (j == width - 1)
+				waddch(win, box | ACS_VLINE);
+			else
+				waddch(win, box | ' ');
+	}
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+	int i;
+
+	if (has_colors()) {	/* Whether terminal supports color? */
+		wattrset(win, dlg.shadow.atr);
+		wmove(win, y + height, x + 2);
+		for (i = 0; i < width; i++)
+			waddch(win, winch(win) & A_CHARTEXT);
+		for (i = y + 1; i < y + height + 1; i++) {
+			wmove(win, i, x + width);
+			waddch(win, winch(win) & A_CHARTEXT);
+			waddch(win, winch(win) & A_CHARTEXT);
+		}
+		wnoutrefresh(win);
+	}
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+	int i, in_paren = 0, c;
+
+	for (i = 0; i < strlen(string); i++) {
+		c = tolower(string[i]);
+
+		if (strchr("<[(", c))
+			++in_paren;
+		if (strchr(">])", c) && in_paren > 0)
+			--in_paren;
+
+		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+        size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/yesno.c b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/yesno.c
new file mode 100644
index 0000000..4e6e809
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/lxdialog/yesno.c
@@ -0,0 +1,114 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 10;
+	int y = height - 2;
+
+	print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+	print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
+
+	wmove(dialog, y, x + 1 + 13 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+	int i, x, y, key = 0, button = 0;
+	WINDOW *dialog;
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 4))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 4))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	print_buttons(dialog, height, width, 0);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'Y':
+		case 'y':
+			delwin(dialog);
+			return 0;
+		case 'N':
+		case 'n':
+			delwin(dialog);
+			return 1;
+
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return button;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/mconf.c b/qemu-0.15.x/roms/seabios/tools/kconfig/mconf.c
new file mode 100644
index 0000000..d433c7a
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/mconf.c
@@ -0,0 +1,862 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky at ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme at conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+"  [ ] can be built in or removed\n"
+"  < > can be built in, modularized or removed\n"
+"  { } can be built in or modularized (selected by other feature)\n"
+"  - - are selected by other feature,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit> and <Help>.\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"o  To toggle the display of hidden options, press <Z>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu, rather\n"
+"than the default multimenu hierarchy, run the menuconfig with\n"
+"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono       => selects colors suitable for monochrome displays\n"
+" blackbg    => selects a color scheme with black background\n"
+" classic    => theme with blue background. The classic look\n"
+" bluetitle  => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+	"Arrow keys navigate the menu.  "
+	"<Enter> selects submenus --->.  "
+	"Highlighted letters are hotkeys.  "
+	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+	"Use the arrow keys to navigate this window or "
+	"press the hotkey of the item you wish to select "
+	"followed by the <SPACE BAR>. "
+	"Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+	"Please enter a decimal value. "
+	"Fractions will not be accepted.  "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+	"Please enter a hexadecimal value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+	"Please enter a string value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+	"This feature depends on another which has been configured as a module.\n"
+	"As a result, this feature will be built as a module."),
+load_config_text[] = N_(
+	"Enter the name of the configuration file you wish to load.  "
+	"Accept the name shown to restore the configuration you "
+	"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep several different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"If you have saved a previous configuration in a file other than the\n"
+	"default one, entering its name here will allow you to modify that\n"
+	"configuration.\n"
+	"\n"
+	"If you are uncertain, then you have probably never used alternate\n"
+	"configuration files. You should therefore leave this blank to abort.\n"),
+save_config_text[] = N_(
+	"Enter a filename to which this configuration should be saved "
+	"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep different configurations\n"
+	"available on a single machine.\n"
+	"\n"
+	"Entering a file name here will allow you to later retrieve, modify\n"
+	"and use the current configuration as an alternate to whatever\n"
+	"configuration options you have selected at that time.\n"
+	"\n"
+	"If you are uncertain what all this means then you should probably\n"
+	"leave this blank.\n"),
+search_help[] = N_(
+	"\n"
+	"Search for symbols and display their relations.\n"
+	"Regular expressions are allowed.\n"
+	"Example: search for \"^FOO\"\n"
+	"Result:\n"
+	"-----------------------------------------------------------------\n"
+	"Symbol: FOO [=m]\n"
+	"Prompt: Foo bus is used to drive the bar HW\n"
+	"Defined at drivers/pci/Kconfig:47\n"
+	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+	"Location:\n"
+	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+	"    -> PCI support (PCI [=y])\n"
+	"      -> PCI access mode (<choice> [=y])\n"
+	"Selects: LIBCRC32\n"
+	"Selected by: BAR\n"
+	"-----------------------------------------------------------------\n"
+	"o The line 'Prompt:' shows the text used in the menu structure for\n"
+	"  this symbol\n"
+	"o The 'Defined at' line tell at what file / line number the symbol\n"
+	"  is defined\n"
+	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+	"  this symbol to be visible in the menu (selectable)\n"
+	"o The 'Location:' lines tell where in the menu structure this symbol\n"
+	"  is located\n"
+	"    A location followed by a [=y] indicate that this is a selectable\n"
+	"    menu item - and current value is displayed inside brackets.\n"
+	"o The 'Selects:' line tell what symbol will be automatically\n"
+	"  selected if this symbol is selected (y or m)\n"
+	"o The 'Selected by' line tell what symbol has selected this symbol\n"
+	"\n"
+	"Only relevant lines are shown.\n"
+	"\n\n"
+	"Search examples:\n"
+	"Examples: USB	=> find all symbols containing USB\n"
+	"          ^USB => find all symbols starting with USB\n"
+	"          USB$ => find all symbols ending with USB\n"
+	"\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+static int show_all_options;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+	static char menu_backtitle[PATH_MAX+128];
+	int size;
+
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+	                "%s - %s", config_filename, rootmenu.prompt->text);
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+	set_dialog_backtitle(menu_backtitle);
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+}
+
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	char *dialog_input;
+	int dres;
+again:
+	dialog_clear();
+	dres = dialog_inputbox(_("Search Configuration Parameter"),
+			      _("Enter " CONFIG_ " (sub)string to search for "
+				"(with or without \"" CONFIG_ "\")"),
+			      10, 75, "");
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_helptext(_("Search Configuration"), search_help);
+		goto again;
+	default:
+		return;
+	}
+
+	/* strip the prefix if necessary */
+	dialog_input = dialog_input_result;
+	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+		dialog_input += strlen(CONFIG_);
+
+	sym_arr = sym_re_search(dialog_input);
+	res = get_relations_str(sym_arr);
+	free(sym_arr);
+	show_textbox(_("Search Results"), str_get(&res), 0, 0);
+	str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	int type, tmp, doint = 2;
+	tristate val;
+	char ch;
+	bool visible;
+
+	/*
+	 * note: menu_is_visible() has side effect that it will
+	 * recalc the value of the symbol.
+	 */
+	visible = menu_is_visible(menu);
+	if (show_all_options && !menu_has_prompt(menu))
+		return;
+	else if (!show_all_options && !visible)
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (!sym) {
+		if (prop && menu != current_menu) {
+			const char *prompt = menu_get_prompt(menu);
+			switch (prop->type) {
+			case P_MENU:
+				child_count++;
+				prompt = _(prompt);
+				if (single_menu_mode) {
+					item_make("%s%*c%s",
+						  menu->data ? "-->" : "++>",
+						  indent + 1, ' ', prompt);
+				} else
+					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
+
+				item_set_tag('m');
+				item_set_data(menu);
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			case P_COMMENT:
+				if (prompt) {
+					child_count++;
+					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+				break;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make("---%*c%s", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+			}
+		} else
+			doint = 0;
+		goto conf_childs;
+	}
+
+	type = sym_get_type(sym);
+	if (sym_is_choice(sym)) {
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		child_count++;
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child) && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		val = sym_get_tristate_value(sym);
+		if (sym_is_changable(sym)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make("[%c]", val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				item_make("<%c>", ch);
+				break;
+			}
+			item_set_tag('t');
+			item_set_data(menu);
+		} else {
+			item_make("   ");
+			item_set_tag(def_menu ? 't' : ':');
+			item_set_data(menu);
+		}
+
+		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+			item_set_tag(':');
+			item_set_data(menu);
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make("   ");
+			item_set_tag(':');
+			item_set_data(menu);
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make("[%c]", val == no ? ' ' : '*');
+				else
+					item_make("-%c-", val == no ? ' ' : '*');
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				if (sym_is_changable(sym)) {
+					if (sym->rev_dep.tri == mod)
+						item_make("{%c}", ch);
+					else
+						item_make("<%c>", ch);
+				} else
+					item_make("-%c-", ch);
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+				item_make("(%s)", sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
+					     "" : _(" (NEW)"));
+				item_set_tag('s');
+				item_set_data(menu);
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
+			  "" : _(" (NEW)"));
+		if (menu->prompt->type == P_MENU) {
+			item_add_str("  --->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+	struct menu *submenu;
+	const char *prompt = menu_get_prompt(menu);
+	struct symbol *sym;
+	struct menu *active_menu = NULL;
+	int res;
+	int s_scroll = 0;
+
+	while (1) {
+		item_reset();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+		if (menu == &rootmenu) {
+			item_make("--- ");
+			item_set_tag(':');
+			item_make(_("    Load an Alternate Configuration File"));
+			item_set_tag('L');
+			item_make(_("    Save an Alternate Configuration File"));
+			item_set_tag('S');
+		}
+		dialog_clear();
+		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+				  _(menu_instructions),
+				  active_menu, &s_scroll);
+		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+			break;
+		if (!item_activate_selected())
+			continue;
+		if (!item_tag())
+			continue;
+
+		submenu = item_data();
+		active_menu = item_data();
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
+
+		switch (res) {
+		case 0:
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data = (void *) (long) !submenu->data;
+				else
+					conf(submenu);
+				break;
+			case 't':
+				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt->type == P_MENU)
+					conf(submenu);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			case 'L':
+				conf_load();
+				break;
+			case 'S':
+				conf_save();
+				break;
+			}
+			break;
+		case 2:
+			if (sym)
+				show_help(submenu);
+			else
+				show_helptext(_("README"), _(mconf_readme));
+			break;
+		case 3:
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					show_textbox(NULL, setmod_text, 6, 74);
+			}
+			break;
+		case 4:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 5:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		case 6:
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu);
+			break;
+		case 7:
+			search_conf();
+			break;
+		case 8:
+			show_all_options = !show_all_options;
+			break;
+		}
+	}
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+	dialog_clear();
+	dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+	show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	help.max_width = getmaxx(stdscr) - 10;
+	menu_get_ext_help(menu, &help);
+
+	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = _(menu_get_prompt(menu));
+	struct menu *child;
+	struct symbol *active;
+
+	active = sym_get_choice_value(menu->sym);
+	while (1) {
+		int res;
+		int selected;
+		item_reset();
+
+		current_menu = menu;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (child->sym)
+				item_make("%s", _(menu_get_prompt(child)));
+			else {
+				item_make("*** %s ***", _(menu_get_prompt(child)));
+				item_set_tag(':');
+			}
+			item_set_data(child);
+			if (child->sym == active)
+				item_set_selected(1);
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_set_tag('X');
+		}
+		dialog_clear();
+		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+					_(radiolist_instructions),
+					 15, 70, 6);
+		selected = item_activate_selected();
+		switch (res) {
+		case 0:
+			if (selected) {
+				child = item_data();
+				if (!child->sym)
+					break;
+
+				sym_set_tristate_value(child->sym, yes);
+			}
+			return;
+		case 1:
+			if (selected) {
+				child = item_data();
+				show_help(child);
+				active = child->sym;
+			} else
+				show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		case -ERRDISPLAYTOOSMALL:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+
+	while (1) {
+		int res;
+		const char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = _(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = _(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = _(inputbox_instructions_string);
+			break;
+		default:
+			heading = _("Internal mconf error!");
+		}
+		dialog_clear();
+		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+				      heading, 10, 75,
+				      sym_get_string_value(menu->sym));
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym, dialog_input_result))
+				return;
+			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, load_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				sym_set_change_count(1);
+				return;
+			}
+			show_textbox(NULL, _("File does not exist!"), 5, 38);
+			break;
+		case 1:
+			show_helptext(_("Load Alternate Configuration"), load_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, save_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_write(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				return;
+			}
+			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+			break;
+		case 1:
+			show_helptext(_("Save Alternate Configuration"), save_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+int main(int ac, char **av)
+{
+	int saved_x, saved_y;
+	char *mode;
+	int res;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("MENUCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	initscr();
+
+	getyx(stdscr, saved_y, saved_x);
+	if (init_dialog(NULL)) {
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+		return 1;
+	}
+
+	set_config_filename(conf_get_configname());
+	do {
+		conf(&rootmenu);
+		dialog_clear();
+		if (conf_get_changed())
+			res = dialog_yesno(NULL,
+					   _("Do you wish to save your "
+					     "new configuration?\n"
+					     "<ESC><ESC> to continue."),
+					   6, 60);
+		else
+			res = -1;
+	} while (res == KEY_ESC);
+	end_dialog(saved_x, saved_y);
+
+	switch (res) {
+	case 0:
+		if (conf_write(filename)) {
+			fprintf(stderr, _("\n\n"
+				"Error while writing of the configuration.\n"
+				"Your configuration changes were NOT saved."
+				"\n\n"));
+			return 1;
+		}
+	case -1:
+		printf(_("\n\n"
+			"*** End of the configuration.\n"
+			"*** Execute 'make' to start the build or try 'make help'."
+			"\n\n"));
+		break;
+	default:
+		fprintf(stderr, _("\n\n"
+			"Your configuration changes were NOT saved."
+			"\n\n"));
+	}
+
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/menu.c b/qemu-0.15.x/roms/seabios/tools/kconfig/menu.c
new file mode 100644
index 0000000..5fdf10d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/menu.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static const char nohelp_text[] = N_(
+	"There is no help available for this option.\n");
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+void _menu_init(void)
+{
+	current_entry = current_menu = &rootmenu;
+	last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+	struct menu *menu;
+
+	menu = malloc(sizeof(*menu));
+	memset(menu, 0, sizeof(*menu));
+	menu->sym = sym;
+	menu->parent = current_menu;
+	menu->file = current_file;
+	menu->lineno = zconf_lineno();
+
+	*last_entry_ptr = menu;
+	last_entry_ptr = &menu->next;
+	current_entry = menu;
+	if (sym)
+		menu_add_symbol(P_SYMBOL, sym, NULL);
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+	menu_end_entry();
+	last_entry_ptr = &current_entry->list;
+	return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+	last_entry_ptr = &current_menu->next;
+	current_menu = current_menu->parent;
+}
+
+static struct expr *menu_check_dep(struct expr *e)
+{
+	if (!e)
+		return e;
+
+	switch (e->type) {
+	case E_NOT:
+		e->left.expr = menu_check_dep(e->left.expr);
+		break;
+	case E_OR:
+	case E_AND:
+		e->left.expr = menu_check_dep(e->left.expr);
+		e->right.expr = menu_check_dep(e->right.expr);
+		break;
+	case E_SYMBOL:
+		/* change 'm' into 'm' && MODULES */
+		if (e->left.sym == &symbol_mod)
+			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+		break;
+	default:
+		break;
+	}
+	return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+	struct symbol *sym = current_entry->sym;
+
+	if (sym->type == type)
+		return;
+	if (sym->type == S_UNKNOWN) {
+		sym->type = type;
+		return;
+	}
+	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
+	    sym->name ? sym->name : "<choice>",
+	    sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+	struct property *prop = prop_alloc(type, current_entry->sym);
+
+	prop->menu = current_entry;
+	prop->expr = expr;
+	prop->visible.expr = menu_check_dep(dep);
+
+	if (prompt) {
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
+		if (current_entry->prompt && current_entry != &rootmenu)
+			prop_warn(prop, "prompt redefined");
+
+		/* Apply all upper menus' visibilities to actual prompts. */
+		if(type == P_PROMPT) {
+			struct menu *menu = current_entry;
+
+			while ((menu = menu->parent) != NULL) {
+				if (!menu->visibility)
+					continue;
+				prop->visible.expr
+					= expr_alloc_and(prop->visible.expr,
+							 menu->visibility);
+			}
+		}
+
+		current_entry->prompt = prop;
+	}
+	prop->text = prompt;
+
+	return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+	return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_visibility(struct expr *expr)
+{
+	current_entry->visibility = expr_alloc_and(current_entry->visibility,
+	    expr);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+	struct property *prop;
+
+	switch (token) {
+	case T_OPT_MODULES:
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(current_entry->sym);
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	case T_OPT_ENV:
+		prop_add_env(arg);
+		break;
+	}
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
+{
+	return sym2->type == S_INT || sym2->type == S_HEX ||
+	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+static void sym_check_prop(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *sym2;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_DEFAULT:
+			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+			    prop->expr->type != E_SYMBOL)
+				prop_warn(prop,
+				    "default for config symbol '%s'"
+				    " must be a single symbol", sym->name);
+			if (prop->expr->type != E_SYMBOL)
+				break;
+			sym2 = prop_get_symbol(prop);
+			if (sym->type == S_HEX || sym->type == S_INT) {
+				if (!menu_validate_number(sym, sym2))
+					prop_warn(prop,
+					    "'%s': number is invalid",
+					    sym->name);
+			}
+			break;
+		case P_SELECT:
+			sym2 = prop_get_symbol(prop);
+			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+				prop_warn(prop,
+				    "config symbol '%s' uses select, but is "
+				    "not boolean or tristate", sym->name);
+			else if (sym2->type != S_UNKNOWN &&
+			         sym2->type != S_BOOLEAN &&
+			         sym2->type != S_TRISTATE)
+				prop_warn(prop,
+				    "'%s' has wrong type. 'select' only "
+				    "accept arguments of boolean and "
+				    "tristate type", sym2->name);
+			break;
+		case P_RANGE:
+			if (sym->type != S_INT && sym->type != S_HEX)
+				prop_warn(prop, "range is only allowed "
+				                "for int or hex symbols");
+			if (!menu_validate_number(sym, prop->expr->left.sym) ||
+			    !menu_validate_number(sym, prop->expr->right.sym))
+				prop_warn(prop, "range is invalid");
+			break;
+		default:
+			;
+		}
+	}
+}
+
+void menu_finalize(struct menu *parent)
+{
+	struct menu *menu, *last_menu;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+	sym = parent->sym;
+	if (parent->list) {
+		if (sym && sym_is_choice(sym)) {
+			if (sym->type == S_UNKNOWN) {
+				/* find the first choice value to find out choice type */
+				current_entry = parent;
+				for (menu = parent->list; menu; menu = menu->next) {
+					if (menu->sym && menu->sym->type != S_UNKNOWN) {
+						menu_set_type(menu->sym->type);
+						break;
+					}
+				}
+			}
+			/* set the type of the remaining choice values */
+			for (menu = parent->list; menu; menu = menu->next) {
+				current_entry = menu;
+				if (menu->sym && menu->sym->type == S_UNKNOWN)
+					menu_set_type(sym->type);
+			}
+			parentdep = expr_alloc_symbol(sym);
+		} else if (parent->prompt)
+			parentdep = parent->prompt->visible.expr;
+		else
+			parentdep = parent->dep;
+
+		for (menu = parent->list; menu; menu = menu->next) {
+			basedep = expr_transform(menu->dep);
+			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+			basedep = expr_eliminate_dups(basedep);
+			menu->dep = basedep;
+			if (menu->sym)
+				prop = menu->sym->prop;
+			else
+				prop = menu->prompt;
+			for (; prop; prop = prop->next) {
+				if (prop->menu != menu)
+					continue;
+				dep = expr_transform(prop->visible.expr);
+				dep = expr_alloc_and(expr_copy(basedep), dep);
+				dep = expr_eliminate_dups(dep);
+				if (menu->sym && menu->sym->type != S_TRISTATE)
+					dep = expr_trans_bool(dep);
+				prop->visible.expr = dep;
+				if (prop->type == P_SELECT) {
+					struct symbol *es = prop_get_symbol(prop);
+					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+				}
+			}
+		}
+		for (menu = parent->list; menu; menu = menu->next)
+			menu_finalize(menu);
+	} else if (sym) {
+		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+		basedep = expr_eliminate_dups(expr_transform(basedep));
+		last_menu = NULL;
+		for (menu = parent->next; menu; menu = menu->next) {
+			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+			if (!expr_contains_symbol(dep, sym))
+				break;
+			if (expr_depends_symbol(dep, sym))
+				goto next;
+			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+			dep = expr_eliminate_dups(expr_transform(dep));
+			dep2 = expr_copy(basedep);
+			expr_eliminate_eq(&dep, &dep2);
+			expr_free(dep);
+			if (!expr_is_yes(dep2)) {
+				expr_free(dep2);
+				break;
+			}
+			expr_free(dep2);
+		next:
+			menu_finalize(menu);
+			menu->parent = parent;
+			last_menu = menu;
+		}
+		if (last_menu) {
+			parent->list = parent->next;
+			parent->next = last_menu->next;
+			last_menu->next = NULL;
+		}
+
+		sym->dir_dep.expr = parent->dep;
+	}
+	for (menu = parent->list; menu; menu = menu->next) {
+		if (sym && sym_is_choice(sym) &&
+		    menu->sym && !sym_is_choice_value(menu->sym)) {
+			current_entry = menu;
+			menu->sym->flags |= SYMBOL_CHOICEVAL;
+			if (!menu->prompt)
+				menu_warn(menu, "choice value must have a prompt");
+			for (prop = menu->sym->prop; prop; prop = prop->next) {
+				if (prop->type == P_DEFAULT)
+					prop_warn(prop, "defaults for choice "
+						  "values not supported");
+				if (prop->menu == menu)
+					continue;
+				if (prop->type == P_PROMPT &&
+				    prop->menu->parent->sym != sym)
+					prop_warn(prop, "choice value used outside its choice group");
+			}
+			/* Non-tristate choice values of tristate choices must
+			 * depend on the choice being set to Y. The choice
+			 * values' dependencies were propagated to their
+			 * properties above, so the change here must be re-
+			 * propagated.
+			 */
+			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+				menu->dep = expr_alloc_and(basedep, menu->dep);
+				for (prop = menu->sym->prop; prop; prop = prop->next) {
+					if (prop->menu != menu)
+						continue;
+					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+									    prop->visible.expr);
+				}
+			}
+			menu_add_symbol(P_CHOICE, sym, NULL);
+			prop = sym_get_choice_prop(sym);
+			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+				;
+			*ep = expr_alloc_one(E_LIST, NULL);
+			(*ep)->right.sym = menu->sym;
+		}
+		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+			for (last_menu = menu->list; ; last_menu = last_menu->next) {
+				last_menu->parent = parent;
+				if (!last_menu->next)
+					break;
+			}
+			last_menu->next = menu->next;
+			menu->next = menu->list;
+			menu->list = NULL;
+		}
+	}
+
+	if (sym && !(sym->flags & SYMBOL_WARNED)) {
+		if (sym->type == S_UNKNOWN)
+			menu_warn(parent, "config symbol defined without type");
+
+		if (sym_is_choice(sym) && !parent->prompt)
+			menu_warn(parent, "choice must have a prompt");
+
+		/* Check properties connected to this symbol */
+		sym_check_prop(sym);
+		sym->flags |= SYMBOL_WARNED;
+	}
+
+	if (sym && !sym_is_optional(sym) && parent->prompt) {
+		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+				expr_alloc_and(parent->prompt->visible.expr,
+					expr_alloc_symbol(&symbol_mod)));
+	}
+}
+
+bool menu_has_prompt(struct menu *menu)
+{
+	if (!menu->prompt)
+		return false;
+	return true;
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+	struct menu *child;
+	struct symbol *sym;
+	tristate visible;
+
+	if (!menu->prompt)
+		return false;
+
+	if (menu->visibility) {
+		if (expr_calc_value(menu->visibility) == no)
+			return no;
+	}
+
+	sym = menu->sym;
+	if (sym) {
+		sym_calc_value(sym);
+		visible = menu->prompt->visible.tri;
+	} else
+		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+	if (visible != no)
+		return true;
+
+	if (!sym || sym_get_tristate_value(menu->sym) == no)
+		return false;
+
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child)) {
+			if (sym)
+				sym->flags |= SYMBOL_DEF_USER;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+	if (menu->prompt)
+		return menu->prompt->text;
+	else if (menu->sym)
+		return menu->sym->name;
+	return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+	return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+	enum prop_type type;
+
+	for (; menu != &rootmenu; menu = menu->parent) {
+		type = menu->prompt ? menu->prompt->type : 0;
+		if (type == P_MENU)
+			break;
+	}
+	return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+	return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+	if (menu->help)
+		return menu->help;
+	else
+		return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+	int i, j;
+	struct menu *submenu[8], *menu;
+
+	str_printf(r, _("Prompt: %s\n"), _(prop->text));
+	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+		prop->menu->lineno);
+	if (!expr_is_yes(prop->visible.expr)) {
+		str_append(r, _("  Depends on: "));
+		expr_gstr_print(prop->visible.expr, r);
+		str_append(r, "\n");
+	}
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+		submenu[i++] = menu;
+	if (i > 0) {
+		str_printf(r, _("  Location:\n"));
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : _("<choice>"),
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+	bool hit;
+	struct property *prop;
+
+	if (sym && sym->name) {
+		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+			   sym_get_string_value(sym));
+		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
+		if (sym->type == S_INT || sym->type == S_HEX) {
+			prop = sym_get_range_prop(sym);
+			if (prop) {
+				str_printf(r, "Range : ");
+				expr_gstr_print(prop->expr, r);
+				str_append(r, "\n");
+			}
+		}
+	}
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop);
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, _("  Selected by: "));
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym);
+	if (!i)
+		str_append(&res, _("No matches found.\n"));
+	return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+	struct symbol *sym = menu->sym;
+
+	if (menu_has_help(menu)) {
+		if (sym->name) {
+			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+			str_append(help, _(menu_get_help(menu)));
+			str_append(help, "\n");
+		}
+	} else {
+		str_append(help, nohelp_text);
+	}
+	if (sym)
+		get_symbol_str(help, sym);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.c b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.c
new file mode 100644
index 0000000..db56377
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.c
@@ -0,0 +1,1561 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar at gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static const char nconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+"  [ ] can be built in or removed\n"
+"  < > can be built in, modularized or removed\n"
+"  { } can be built in or modularized (selected by other feature)\n"
+"  - - are selected by other feature,\n"
+"  XXX cannot be selected. Use Symbol Info to find out why,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change use <Enter> or <Space>. Goto submenu by \n"
+"   pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Searching: pressing '/' triggers interactive search mode.\n"
+"              nconfig performs a case insensitive search for the string\n"
+"              in the menu prompts (no regex support).\n"
+"              Pressing the up/down keys highlights the previous/next\n"
+"              matching item. Backspace removes one character from the\n"
+"              match string. Pressing either '/' again or ESC exits\n"
+"              search mode. All other keys behave normally.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
+"\n"
+"o  To get help with an item, press <F1>\n"
+"   Shortcut: Press <h> or <?>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, press <F1>\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, press <F1>.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"nconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a nconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting nconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use nconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, nconfig will look rather bad.  nconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"nconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu, rather\n"
+"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
+"environment variable set to single_menu. Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"),
+menu_no_f_instructions[] = N_(
+" You do not have function keys support. Please follow the\n"
+" following instructions:\n"
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options.\n"
+" Press <Esc> or <left-arrow> to go back one menu,\n"
+" <?> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+" <Esc> always leaves the current window.\n"),
+menu_instructions[] = N_(
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options\n"
+" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
+" <?>, <F1> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+" <Esc> always leaves the current window\n"),
+radiolist_instructions[] = N_(
+" Use the arrow keys to navigate this window or\n"
+" press the hotkey of the item you wish to select\n"
+" followed by the <SPACE BAR>.\n"
+" Press <?>, <F1> or <h> for additional information about this option.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another which\n"
+"has been configured as a module.\n"
+"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+"There is no help available for this option.\n"),
+load_config_text[] = N_(
+"Enter the name of the configuration file you wish to load.\n"
+"Accept the name shown to restore the configuration you\n"
+"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep several different\n"
+"configurations available on a single machine.\n"
+"\n"
+"If you have saved a previous configuration in a file other than the\n"
+"default one, entering its name here will allow you to modify that\n"
+"configuration.\n"
+"\n"
+"If you are uncertain, then you have probably never used alternate\n"
+"configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep different configurations\n"
+"available on a single machine.\n"
+"\n"
+"Entering a file name here will allow you to later retrieve, modify\n"
+"and use the current configuration as an alternate to whatever\n"
+"configuration options you have selected at that time.\n"
+"\n"
+"If you are uncertain what all this means then you should probably\n"
+"leave this blank.\n"),
+search_help[] = N_(
+"\n"
+"Search for symbols and display their relations. Regular expressions\n"
+"are allowed.\n"
+"Example: search for \"^FOO\"\n"
+"Result:\n"
+"-----------------------------------------------------------------\n"
+"Symbol: FOO [ = m]\n"
+"Prompt: Foo bus is used to drive the bar HW\n"
+"Defined at drivers/pci/Kconfig:47\n"
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+"Location:\n"
+"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+"    -> PCI support (PCI [ = y])\n"
+"      -> PCI access mode (<choice> [ = y])\n"
+"Selects: LIBCRC32\n"
+"Selected by: BAR\n"
+"-----------------------------------------------------------------\n"
+"o The line 'Prompt:' shows the text used in the menu structure for\n"
+"  this symbol\n"
+"o The 'Defined at' line tell at what file / line number the symbol\n"
+"  is defined\n"
+"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+"  this symbol to be visible in the menu (selectable)\n"
+"o The 'Location:' lines tell where in the menu structure this symbol\n"
+"  is located\n"
+"    A location followed by a [ = y] indicate that this is a selectable\n"
+"    menu item - and current value is displayed inside brackets.\n"
+"o The 'Selects:' line tell what symbol will be automatically\n"
+"  selected if this symbol is selected (y or m)\n"
+"o The 'Selected by' line tell what symbol has selected this symbol\n"
+"\n"
+"Only relevant lines are shown.\n"
+"\n\n"
+"Search examples:\n"
+"Examples: USB  => find all symbols containing USB\n"
+"          ^USB => find all symbols starting with USB\n"
+"          USB$ => find all symbols ending with USB\n"
+"\n");
+
+struct mitem {
+	char str[256];
+	char tag;
+	void *usrptr;
+	int is_visible;
+};
+
+#define MAX_MENU_ITEMS 4096
+static int show_all_items;
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+/* the window in which all information appears */
+static WINDOW *main_window;
+/* the largest size of the menu window */
+static int mwin_max_lines;
+static int mwin_max_cols;
+/* the window in which we show option buttons */
+static MENU *curses_menu;
+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
+static struct mitem k_menu_items[MAX_MENU_ITEMS];
+static int items_num;
+static int global_exit;
+/* the currently selected button */
+const char *current_instructions = menu_instructions;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_help(struct menu *menu);
+static int do_exit(void);
+static void setup_windows(void);
+static void search_conf(void);
+
+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
+static void handle_f1(int *key, struct menu *current_item);
+static void handle_f2(int *key, struct menu *current_item);
+static void handle_f3(int *key, struct menu *current_item);
+static void handle_f4(int *key, struct menu *current_item);
+static void handle_f5(int *key, struct menu *current_item);
+static void handle_f6(int *key, struct menu *current_item);
+static void handle_f7(int *key, struct menu *current_item);
+static void handle_f8(int *key, struct menu *current_item);
+static void handle_f9(int *key, struct menu *current_item);
+
+struct function_keys {
+	const char *key_str;
+	const char *func;
+	function_key key;
+	function_key_handler_t handler;
+};
+
+static const int function_keys_num = 9;
+struct function_keys function_keys[] = {
+	{
+		.key_str = "F1",
+		.func = "Help",
+		.key = F_HELP,
+		.handler = handle_f1,
+	},
+	{
+		.key_str = "F2",
+		.func = "Sym Info",
+		.key = F_SYMBOL,
+		.handler = handle_f2,
+	},
+	{
+		.key_str = "F3",
+		.func = "Insts",
+		.key = F_INSTS,
+		.handler = handle_f3,
+	},
+	{
+		.key_str = "F4",
+		.func = "Config",
+		.key = F_CONF,
+		.handler = handle_f4,
+	},
+	{
+		.key_str = "F5",
+		.func = "Back",
+		.key = F_BACK,
+		.handler = handle_f5,
+	},
+	{
+		.key_str = "F6",
+		.func = "Save",
+		.key = F_SAVE,
+		.handler = handle_f6,
+	},
+	{
+		.key_str = "F7",
+		.func = "Load",
+		.key = F_LOAD,
+		.handler = handle_f7,
+	},
+	{
+		.key_str = "F8",
+		.func = "Sym Search",
+		.key = F_SEARCH,
+		.handler = handle_f8,
+	},
+	{
+		.key_str = "F9",
+		.func = "Exit",
+		.key = F_EXIT,
+		.handler = handle_f9,
+	},
+};
+
+static void print_function_line(void)
+{
+	int i;
+	int offset = 1;
+	const int skip = 1;
+
+	for (i = 0; i < function_keys_num; i++) {
+		wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+		mvwprintw(main_window, LINES-3, offset,
+				"%s",
+				function_keys[i].key_str);
+		wattrset(main_window, attributes[FUNCTION_TEXT]);
+		offset += strlen(function_keys[i].key_str);
+		mvwprintw(main_window, LINES-3,
+				offset, "%s",
+				function_keys[i].func);
+		offset += strlen(function_keys[i].func) + skip;
+	}
+	wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+	show_scroll_win(main_window,
+			_("README"), _(nconf_readme));
+	return;
+}
+
+/* symbole help */
+static void handle_f2(int *key, struct menu *current_item)
+{
+	show_help(current_item);
+	return;
+}
+
+/* instructions */
+static void handle_f3(int *key, struct menu *current_item)
+{
+	show_scroll_win(main_window,
+			_("Instructions"),
+			_(current_instructions));
+	return;
+}
+
+/* config */
+static void handle_f4(int *key, struct menu *current_item)
+{
+	int res = btn_dialog(main_window,
+			_("Show all symbols?"),
+			2,
+			"   <Show All>   ",
+			"<Don't show all>");
+	if (res == 0)
+		show_all_items = 1;
+	else if (res == 1)
+		show_all_items = 0;
+
+	return;
+}
+
+/* back */
+static void handle_f5(int *key, struct menu *current_item)
+{
+	*key = KEY_LEFT;
+	return;
+}
+
+/* save */
+static void handle_f6(int *key, struct menu *current_item)
+{
+	conf_save();
+	return;
+}
+
+/* load */
+static void handle_f7(int *key, struct menu *current_item)
+{
+	conf_load();
+	return;
+}
+
+/* search */
+static void handle_f8(int *key, struct menu *current_item)
+{
+	search_conf();
+	return;
+}
+
+/* exit */
+static void handle_f9(int *key, struct menu *current_item)
+{
+	do_exit();
+	return;
+}
+
+/* return != 0 to indicate the key was handles */
+static int process_special_keys(int *key, struct menu *menu)
+{
+	int i;
+
+	if (*key == KEY_RESIZE) {
+		setup_windows();
+		return 1;
+	}
+
+	for (i = 0; i < function_keys_num; i++) {
+		if (*key == KEY_F(function_keys[i].key) ||
+		    *key == '0' + function_keys[i].key){
+			function_keys[i].handler(key, menu);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void clean_items(void)
+{
+	int i;
+	for (i = 0; curses_menu_items[i]; i++)
+		free_item(curses_menu_items[i]);
+	bzero(curses_menu_items, sizeof(curses_menu_items));
+	bzero(k_menu_items, sizeof(k_menu_items));
+	items_num = 0;
+}
+
+typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
+	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
+
+/* return the index of the matched item, or -1 if no such item exists */
+static int get_mext_match(const char *match_str, match_f flag)
+{
+	int match_start = item_index(current_item(curses_menu));
+	int index;
+
+	if (flag == FIND_NEXT_MATCH_DOWN)
+		++match_start;
+	else if (flag == FIND_NEXT_MATCH_UP)
+		--match_start;
+
+	index = match_start;
+	index = (index + items_num) % items_num;
+	while (true) {
+		char *str = k_menu_items[index].str;
+		if (strcasestr(str, match_str) != 0)
+			return index;
+		if (flag == FIND_NEXT_MATCH_UP ||
+		    flag == MATCH_TINKER_PATTERN_UP)
+			--index;
+		else
+			++index;
+		index = (index + items_num) % items_num;
+		if (index == match_start)
+			return -1;
+	}
+}
+
+/* Make a new item. */
+static void item_make(struct menu *menu, char tag, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (items_num > MAX_MENU_ITEMS-1)
+		return;
+
+	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
+	k_menu_items[items_num].tag = tag;
+	k_menu_items[items_num].usrptr = menu;
+	if (menu != NULL)
+		k_menu_items[items_num].is_visible =
+			menu_is_visible(menu);
+	else
+		k_menu_items[items_num].is_visible = 1;
+
+	va_start(ap, fmt);
+	vsnprintf(k_menu_items[items_num].str,
+		  sizeof(k_menu_items[items_num].str),
+		  fmt, ap);
+	va_end(ap);
+
+	if (!k_menu_items[items_num].is_visible)
+		memcpy(k_menu_items[items_num].str, "XXX", 3);
+
+	curses_menu_items[items_num] = new_item(
+			k_menu_items[items_num].str,
+			k_menu_items[items_num].str);
+	set_item_userptr(curses_menu_items[items_num],
+			&k_menu_items[items_num]);
+	/*
+	if (!k_menu_items[items_num].is_visible)
+		item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
+	*/
+
+	items_num++;
+	curses_menu_items[items_num] = NULL;
+}
+
+/* very hackish. adds a string to the last item added */
+static void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+	int index = items_num-1;
+	char new_str[256];
+	char tmp_str[256];
+
+	if (index < 0)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(new_str, sizeof(new_str), fmt, ap);
+	va_end(ap);
+	snprintf(tmp_str, sizeof(tmp_str), "%s%s",
+			k_menu_items[index].str, new_str);
+	strncpy(k_menu_items[index].str,
+		tmp_str,
+		sizeof(k_menu_items[index].str));
+
+	free_item(curses_menu_items[index]);
+	curses_menu_items[index] = new_item(
+			k_menu_items[index].str,
+			k_menu_items[index].str);
+	set_item_userptr(curses_menu_items[index],
+			&k_menu_items[index]);
+}
+
+/* get the tag of the currently selected item */
+static char item_tag(void)
+{
+	ITEM *cur;
+	struct mitem *mcur;
+
+	cur = current_item(curses_menu);
+	if (cur == NULL)
+		return 0;
+	mcur = (struct mitem *) item_userptr(cur);
+	return mcur->tag;
+}
+
+static int curses_item_index(void)
+{
+	return  item_index(current_item(curses_menu));
+}
+
+static void *item_data(void)
+{
+	ITEM *cur;
+	struct mitem *mcur;
+
+	cur = current_item(curses_menu);
+	if (!cur)
+		return NULL;
+	mcur = (struct mitem *) item_userptr(cur);
+	return mcur->usrptr;
+
+}
+
+static int item_is_tag(char tag)
+{
+	return item_tag() == tag;
+}
+
+static char filename[PATH_MAX+1];
+static char menu_backtitle[PATH_MAX+128];
+static const char *set_config_filename(const char *config_filename)
+{
+	int size;
+
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+			"%s - %s", config_filename, rootmenu.prompt->text);
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+	return menu_backtitle;
+}
+
+/* return = 0 means we are successful.
+ * -1 means go on doing what you were doing
+ */
+static int do_exit(void)
+{
+	int res;
+	if (!conf_get_changed()) {
+		global_exit = 1;
+		return 0;
+	}
+	res = btn_dialog(main_window,
+			_("Do you wish to save your new configuration?\n"
+				"<ESC> to cancel and resume nconfig."),
+			2,
+			"   <save>   ",
+			"<don't save>");
+	if (res == KEY_EXIT) {
+		global_exit = 0;
+		return -1;
+	}
+
+	/* if we got here, the user really wants to exit */
+	switch (res) {
+	case 0:
+		res = conf_write(filename);
+		if (res)
+			btn_dialog(
+				main_window,
+				_("Error during writing of configuration.\n"
+				  "Your configuration changes were NOT saved."),
+				  1,
+				  "<OK>");
+		break;
+	default:
+		btn_dialog(
+			main_window,
+			_("Your configuration changes were NOT saved."),
+			1,
+			"<OK>");
+		break;
+	}
+	global_exit = 1;
+	return 0;
+}
+
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	char dialog_input_result[100];
+	char *dialog_input;
+	int dres;
+again:
+	dres = dialog_inputbox(main_window,
+			_("Search Configuration Parameter"),
+			_("Enter " CONFIG_ " (sub)string to search for "
+				"(with or without \"" CONFIG_ "\")"),
+			"", dialog_input_result, 99);
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_scroll_win(main_window,
+				_("Search Configuration"), search_help);
+		goto again;
+	default:
+		return;
+	}
+
+	/* strip the prefix if necessary */
+	dialog_input = dialog_input_result;
+	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+		dialog_input += strlen(CONFIG_);
+
+	sym_arr = sym_re_search(dialog_input);
+	res = get_relations_str(sym_arr);
+	free(sym_arr);
+	show_scroll_win(main_window,
+			_("Search Results"), str_get(&res));
+	str_free(&res);
+}
+
+
+static void build_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	int type, tmp, doint = 2;
+	tristate val;
+	char ch;
+
+	if (!menu || (!show_all_items && !menu_is_visible(menu)))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (!sym) {
+		if (prop && menu != current_menu) {
+			const char *prompt = menu_get_prompt(menu);
+			enum prop_type ptype;
+			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+			switch (ptype) {
+			case P_MENU:
+				child_count++;
+				prompt = _(prompt);
+				if (single_menu_mode) {
+					item_make(menu, 'm',
+						"%s%*c%s",
+						menu->data ? "-->" : "++>",
+						indent + 1, ' ', prompt);
+				} else
+					item_make(menu, 'm',
+						"   %*c%s  --->",
+						indent + 1,
+						' ', prompt);
+
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			case P_COMMENT:
+				if (prompt) {
+					child_count++;
+					item_make(menu, ':',
+						"   %*c*** %s ***",
+						indent + 1, ' ',
+						_(prompt));
+				}
+				break;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make(menu, ':', "---%*c%s",
+						indent + 1, ' ',
+						_(prompt));
+				}
+			}
+		} else
+			doint = 0;
+		goto conf_childs;
+	}
+
+	type = sym_get_type(sym);
+	if (sym_is_choice(sym)) {
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		child_count++;
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child) && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		val = sym_get_tristate_value(sym);
+		if (sym_is_changable(sym)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make(menu, 't', "[%c]",
+						val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes:
+					ch = '*';
+					break;
+				case mod:
+					ch = 'M';
+					break;
+				default:
+					ch = ' ';
+					break;
+				}
+				item_make(menu, 't', "<%c>", ch);
+				break;
+			}
+		} else {
+			item_make(menu, def_menu ? 't' : ':', "   ");
+		}
+
+		item_add_str("%*c%s", indent + 1,
+				' ', _(menu_get_prompt(menu)));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)",
+					_(menu_get_prompt(def_menu)));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make(menu, ':',
+				"---%*c%s", indent + 1,
+				' ', _(menu_get_prompt(menu)));
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make(menu, ':', "   ");
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make(menu, 't', "[%c]",
+						val == no ? ' ' : '*');
+				else
+					item_make(menu, 't', "-%c-",
+						val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes:
+					ch = '*';
+					break;
+				case mod:
+					ch = 'M';
+					break;
+				default:
+					ch = ' ';
+					break;
+				}
+				if (sym_is_changable(sym)) {
+					if (sym->rev_dep.tri == mod)
+						item_make(menu,
+							't', "{%c}", ch);
+					else
+						item_make(menu,
+							't', "<%c>", ch);
+				} else
+					item_make(menu, 't', "-%c-", ch);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym));
+				item_make(menu, 's', "    (%s)",
+						sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ',
+						_(menu_get_prompt(menu)),
+						(sym_has_value(sym) ||
+						 !sym_is_changable(sym)) ? "" :
+						_(" (NEW)"));
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ',
+				_(menu_get_prompt(menu)),
+				(sym_has_value(sym) || !sym_is_changable(sym)) ?
+				"" : _(" (NEW)"));
+		if (menu->prompt && menu->prompt->type == P_MENU) {
+			item_add_str("  --->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void reset_menu(void)
+{
+	unpost_menu(curses_menu);
+	clean_items();
+}
+
+/* adjust the menu to show this item.
+ * prefer not to scroll the menu if possible*/
+static void center_item(int selected_index, int *last_top_row)
+{
+	int toprow;
+
+	set_top_row(curses_menu, *last_top_row);
+	toprow = top_row(curses_menu);
+	if (selected_index < toprow ||
+	    selected_index >= toprow+mwin_max_lines) {
+		toprow = max(selected_index-mwin_max_lines/2, 0);
+		if (toprow >= item_count(curses_menu)-mwin_max_lines)
+			toprow = item_count(curses_menu)-mwin_max_lines;
+		set_top_row(curses_menu, toprow);
+	}
+	set_current_item(curses_menu,
+			curses_menu_items[selected_index]);
+	*last_top_row = toprow;
+	post_menu(curses_menu);
+	refresh_all_windows(main_window);
+}
+
+/* this function assumes reset_menu has been called before */
+static void show_menu(const char *prompt, const char *instructions,
+		int selected_index, int *last_top_row)
+{
+	int maxx, maxy;
+	WINDOW *menu_window;
+
+	current_instructions = instructions;
+
+	clear();
+	wattrset(main_window, attributes[NORMAL]);
+	print_in_middle(stdscr, 1, 0, COLS,
+			menu_backtitle,
+			attributes[MAIN_HEADING]);
+
+	wattrset(main_window, attributes[MAIN_MENU_BOX]);
+	box(main_window, 0, 0);
+	wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+	mvwprintw(main_window, 0, 3, " %s ", prompt);
+	wattrset(main_window, attributes[NORMAL]);
+
+	set_menu_items(curses_menu, curses_menu_items);
+
+	/* position the menu at the middle of the screen */
+	scale_menu(curses_menu, &maxy, &maxx);
+	maxx = min(maxx, mwin_max_cols-2);
+	maxy = mwin_max_lines;
+	menu_window = derwin(main_window,
+			maxy,
+			maxx,
+			2,
+			(mwin_max_cols-maxx)/2);
+	keypad(menu_window, TRUE);
+	set_menu_win(curses_menu, menu_window);
+	set_menu_sub(curses_menu, menu_window);
+
+	/* must reassert this after changing items, otherwise returns to a
+	 * default of 16
+	 */
+	set_menu_format(curses_menu, maxy, 1);
+	center_item(selected_index, last_top_row);
+	set_menu_format(curses_menu, maxy, 1);
+
+	print_function_line();
+
+	/* Post the menu */
+	post_menu(curses_menu);
+	refresh_all_windows(main_window);
+}
+
+static void adj_match_dir(match_f *match_direction)
+{
+	if (*match_direction == FIND_NEXT_MATCH_DOWN)
+		*match_direction =
+			MATCH_TINKER_PATTERN_DOWN;
+	else if (*match_direction == FIND_NEXT_MATCH_UP)
+		*match_direction =
+			MATCH_TINKER_PATTERN_UP;
+	/* else, do no change.. */
+}
+
+struct match_state
+{
+	int in_search;
+	match_f match_direction;
+	char pattern[256];
+};
+
+/* Return 0 means I have handled the key. In such a case, ans should hold the
+ * item to center, or -1 otherwise.
+ * Else return -1 .
+ */
+static int do_match(int key, struct match_state *state, int *ans)
+{
+	char c = (char) key;
+	int terminate_search = 0;
+	*ans = -1;
+	if (key == '/' || (state->in_search && key == 27)) {
+		move(0, 0);
+		refresh();
+		clrtoeol();
+		state->in_search = 1-state->in_search;
+		bzero(state->pattern, sizeof(state->pattern));
+		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
+		return 0;
+	} else if (!state->in_search)
+		return 1;
+
+	if (isalnum(c) || isgraph(c) || c == ' ') {
+		state->pattern[strlen(state->pattern)] = c;
+		state->pattern[strlen(state->pattern)] = '\0';
+		adj_match_dir(&state->match_direction);
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_DOWN) {
+		state->match_direction = FIND_NEXT_MATCH_DOWN;
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_UP) {
+		state->match_direction = FIND_NEXT_MATCH_UP;
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_BACKSPACE || key == 127) {
+		state->pattern[strlen(state->pattern)-1] = '\0';
+		adj_match_dir(&state->match_direction);
+	} else
+		terminate_search = 1;
+
+	if (terminate_search) {
+		state->in_search = 0;
+		bzero(state->pattern, sizeof(state->pattern));
+		move(0, 0);
+		refresh();
+		clrtoeol();
+		return -1;
+	}
+	return 0;
+}
+
+static void conf(struct menu *menu)
+{
+	struct menu *submenu = 0;
+	const char *prompt = menu_get_prompt(menu);
+	struct symbol *sym;
+	struct menu *active_menu = NULL;
+	int res;
+	int current_index = 0;
+	int last_top_row = 0;
+	struct match_state match_state = {
+		.in_search = 0,
+		.match_direction = MATCH_TINKER_PATTERN_DOWN,
+		.pattern = "",
+	};
+
+	while (!global_exit) {
+		reset_menu();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+
+		show_menu(prompt ? _(prompt) : _("Main Menu"),
+				_(menu_instructions),
+				current_index, &last_top_row);
+		keypad((menu_win(curses_menu)), TRUE);
+		while (!global_exit) {
+			if (match_state.in_search) {
+				mvprintw(0, 0,
+					"searching: %s", match_state.pattern);
+				clrtoeol();
+			}
+			refresh_all_windows(main_window);
+			res = wgetch(menu_win(curses_menu));
+			if (!res)
+				break;
+			if (do_match(res, &match_state, &current_index) == 0) {
+				if (current_index != -1)
+					center_item(current_index,
+						    &last_top_row);
+				continue;
+			}
+			if (process_special_keys(&res,
+						(struct menu *) item_data()))
+				break;
+			switch (res) {
+			case KEY_DOWN:
+				menu_driver(curses_menu, REQ_DOWN_ITEM);
+				break;
+			case KEY_UP:
+				menu_driver(curses_menu, REQ_UP_ITEM);
+				break;
+			case KEY_NPAGE:
+				menu_driver(curses_menu, REQ_SCR_DPAGE);
+				break;
+			case KEY_PPAGE:
+				menu_driver(curses_menu, REQ_SCR_UPAGE);
+				break;
+			case KEY_HOME:
+				menu_driver(curses_menu, REQ_FIRST_ITEM);
+				break;
+			case KEY_END:
+				menu_driver(curses_menu, REQ_LAST_ITEM);
+				break;
+			case 'h':
+			case '?':
+				show_help((struct menu *) item_data());
+				break;
+			}
+			if (res == 10 || res == 27 ||
+				res == 32 || res == 'n' || res == 'y' ||
+				res == KEY_LEFT || res == KEY_RIGHT ||
+				res == 'm')
+				break;
+			refresh_all_windows(main_window);
+		}
+
+		refresh_all_windows(main_window);
+		/* if ESC or left*/
+		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
+			break;
+
+		/* remember location in the menu */
+		last_top_row = top_row(curses_menu);
+		current_index = curses_item_index();
+
+		if (!item_tag())
+			continue;
+
+		submenu = (struct menu *) item_data();
+		active_menu = (struct menu *)item_data();
+		if (!submenu || !menu_is_visible(submenu))
+			continue;
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
+
+		switch (res) {
+		case ' ':
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu);
+			break;
+		case KEY_RIGHT:
+		case 10: /* ENTER WAS PRESSED */
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data =
+						(void *) (long) !submenu->data;
+				else
+					conf(submenu);
+				break;
+			case 't':
+				if (sym_is_choice(sym) &&
+				    sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt &&
+					 submenu->prompt->type == P_MENU)
+					conf(submenu);
+				else if (res == 10)
+					sym_toggle_tristate_value(sym);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			}
+			break;
+		case 'y':
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					btn_dialog(main_window, setmod_text, 0);
+			}
+			break;
+		case 'n':
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 'm':
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		}
+	}
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+	char buf[1024];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	btn_dialog(main_window, buf, 1, "<OK>");
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	if (menu && menu->sym && menu_has_help(menu)) {
+		if (menu->sym->name) {
+			str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
+			str_append(&help, _(menu_get_help(menu)));
+			str_append(&help, "\n");
+			get_symbol_str(&help, menu->sym);
+		} else {
+			str_append(&help, _(menu_get_help(menu)));
+		}
+	} else {
+		str_append(&help, nohelp_text);
+	}
+	show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = _(menu_get_prompt(menu));
+	struct menu *child = 0;
+	struct symbol *active;
+	int selected_index = 0;
+	int last_top_row = 0;
+	int res, i = 0;
+	struct match_state match_state = {
+		.in_search = 0,
+		.match_direction = MATCH_TINKER_PATTERN_DOWN,
+		.pattern = "",
+	};
+
+	active = sym_get_choice_value(menu->sym);
+	/* this is mostly duplicated from the conf() function. */
+	while (!global_exit) {
+		reset_menu();
+
+		for (i = 0, child = menu->list; child; child = child->next) {
+			if (!show_all_items && !menu_is_visible(child))
+				continue;
+
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_make(child, ':', "<X> %s",
+						_(menu_get_prompt(child)));
+			else if (child->sym)
+				item_make(child, ':', "    %s",
+						_(menu_get_prompt(child)));
+			else
+				item_make(child, ':', "*** %s ***",
+						_(menu_get_prompt(child)));
+
+			if (child->sym == active){
+				last_top_row = top_row(curses_menu);
+				selected_index = i;
+			}
+			i++;
+		}
+		show_menu(prompt ? _(prompt) : _("Choice Menu"),
+				_(radiolist_instructions),
+				selected_index,
+				&last_top_row);
+		while (!global_exit) {
+			if (match_state.in_search) {
+				mvprintw(0, 0, "searching: %s",
+					 match_state.pattern);
+				clrtoeol();
+			}
+			refresh_all_windows(main_window);
+			res = wgetch(menu_win(curses_menu));
+			if (!res)
+				break;
+			if (do_match(res, &match_state, &selected_index) == 0) {
+				if (selected_index != -1)
+					center_item(selected_index,
+						    &last_top_row);
+				continue;
+			}
+			if (process_special_keys(
+						&res,
+						(struct menu *) item_data()))
+				break;
+			switch (res) {
+			case KEY_DOWN:
+				menu_driver(curses_menu, REQ_DOWN_ITEM);
+				break;
+			case KEY_UP:
+				menu_driver(curses_menu, REQ_UP_ITEM);
+				break;
+			case KEY_NPAGE:
+				menu_driver(curses_menu, REQ_SCR_DPAGE);
+				break;
+			case KEY_PPAGE:
+				menu_driver(curses_menu, REQ_SCR_UPAGE);
+				break;
+			case KEY_HOME:
+				menu_driver(curses_menu, REQ_FIRST_ITEM);
+				break;
+			case KEY_END:
+				menu_driver(curses_menu, REQ_LAST_ITEM);
+				break;
+			case 'h':
+			case '?':
+				show_help((struct menu *) item_data());
+				break;
+			}
+			if (res == 10 || res == 27 || res == ' ' ||
+					res == KEY_LEFT){
+				break;
+			}
+			refresh_all_windows(main_window);
+		}
+		/* if ESC or left */
+		if (res == 27 || res == KEY_LEFT)
+			break;
+
+		child = item_data();
+		if (!child || !menu_is_visible(child) || !child->sym)
+			continue;
+		switch (res) {
+		case ' ':
+		case  10:
+		case KEY_RIGHT:
+			sym_set_tristate_value(child->sym, yes);
+			return;
+		case 'h':
+		case '?':
+			show_help(child);
+			active = child->sym;
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+	char dialog_input_result[256];
+
+	while (1) {
+		int res;
+		const char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = _(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = _(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = _(inputbox_instructions_string);
+			break;
+		default:
+			heading = _("Internal nconf error!");
+		}
+		res = dialog_inputbox(main_window,
+				prompt ? _(prompt) : _("Main Menu"),
+				heading,
+				sym_get_string_value(menu->sym),
+				dialog_input_result,
+				sizeof(dialog_input_result));
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym,
+						dialog_input_result))
+				return;
+			btn_dialog(main_window,
+				_("You have made an invalid entry."), 0);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+	char dialog_input_result[256];
+	while (1) {
+		int res;
+		res = dialog_inputbox(main_window,
+				NULL, load_config_text,
+				filename,
+				dialog_input_result,
+				sizeof(dialog_input_result));
+		switch (res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				sym_set_change_count(1);
+				return;
+			}
+			btn_dialog(main_window, _("File does not exist!"), 0);
+			break;
+		case 1:
+			show_scroll_win(main_window,
+					_("Load Alternate Configuration"),
+					load_config_help);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	char dialog_input_result[256];
+	while (1) {
+		int res;
+		res = dialog_inputbox(main_window,
+				NULL, save_config_text,
+				filename,
+				dialog_input_result,
+				sizeof(dialog_input_result));
+		switch (res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			res = conf_write(dialog_input_result);
+			if (!res) {
+				set_config_filename(dialog_input_result);
+				return;
+			}
+			btn_dialog(main_window, _("Can't create file! "
+				"Probably a nonexistent directory."),
+				1, "<OK>");
+			break;
+		case 1:
+			show_scroll_win(main_window,
+				_("Save Alternate Configuration"),
+				save_config_help);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+void setup_windows(void)
+{
+	if (main_window != NULL)
+		delwin(main_window);
+
+	/* set up the menu and menu window */
+	main_window = newwin(LINES-2, COLS-2, 2, 1);
+	keypad(main_window, TRUE);
+	mwin_max_lines = LINES-7;
+	mwin_max_cols = COLS-6;
+
+	/* panels order is from bottom to top */
+	new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+	char *mode;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("NCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	/* Initialize curses */
+	initscr();
+	/* set color theme */
+	set_colors();
+
+	cbreak();
+	noecho();
+	keypad(stdscr, TRUE);
+	curs_set(0);
+
+	if (COLS < 75 || LINES < 20) {
+		endwin();
+		printf("Your terminal should have at "
+			"least 20 lines and 75 columns\n");
+		return 1;
+	}
+
+	notimeout(stdscr, FALSE);
+	ESCDELAY = 1;
+
+	/* set btns menu */
+	curses_menu = new_menu(curses_menu_items);
+	menu_opts_off(curses_menu, O_SHOWDESC);
+	menu_opts_on(curses_menu, O_SHOWMATCH);
+	menu_opts_on(curses_menu, O_ONEVALUE);
+	menu_opts_on(curses_menu, O_NONCYCLIC);
+	menu_opts_on(curses_menu, O_IGNORECASE);
+	set_menu_mark(curses_menu, " ");
+	set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
+	set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
+	set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+
+	set_config_filename(conf_get_configname());
+	setup_windows();
+
+	/* check for KEY_FUNC(1) */
+	if (has_key(KEY_F(1)) == FALSE) {
+		show_scroll_win(main_window,
+				_("Instructions"),
+				_(menu_no_f_instructions));
+	}
+
+	conf_set_message_callback(conf_message_callback);
+	/* do the work */
+	while (!global_exit) {
+		conf(&rootmenu);
+		if (!global_exit && do_exit() == 0)
+			break;
+	}
+	/* ok, we are done */
+	unpost_menu(curses_menu);
+	free_menu(curses_menu);
+	delwin(main_window);
+	clear();
+	refresh();
+	endwin();
+	return 0;
+}
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.gui.c b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.gui.c
new file mode 100644
index 0000000..f8137b3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.gui.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar at gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#include "nconf.h"
+
+/* a list of all the different widgets we use */
+attributes_t attributes[ATTR_MAX+1] = {0};
+
+/* available colors:
+   COLOR_BLACK   0
+   COLOR_RED     1
+   COLOR_GREEN   2
+   COLOR_YELLOW  3
+   COLOR_BLUE    4
+   COLOR_MAGENTA 5
+   COLOR_CYAN    6
+   COLOR_WHITE   7
+   */
+static void set_normal_colors(void)
+{
+	init_pair(NORMAL, -1, -1);
+	init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
+
+	/* FORE is for the selected item */
+	init_pair(MAIN_MENU_FORE, -1, -1);
+	/* BACK for all the rest */
+	init_pair(MAIN_MENU_BACK, -1, -1);
+	init_pair(MAIN_MENU_GREY, -1, -1);
+	init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
+	init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
+
+	init_pair(SCROLLWIN_TEXT, -1, -1);
+	init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
+	init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
+
+	init_pair(DIALOG_TEXT, -1, -1);
+	init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
+	init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
+	init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
+
+	init_pair(INPUT_BOX, COLOR_YELLOW, -1);
+	init_pair(INPUT_HEADING, COLOR_GREEN, -1);
+	init_pair(INPUT_TEXT, -1, -1);
+	init_pair(INPUT_FIELD, -1, -1);
+
+	init_pair(FUNCTION_HIGHLIGHT, -1, -1);
+	init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
+}
+
+/* available attributes:
+   A_NORMAL        Normal display (no highlight)
+   A_STANDOUT      Best highlighting mode of the terminal.
+   A_UNDERLINE     Underlining
+   A_REVERSE       Reverse video
+   A_BLINK         Blinking
+   A_DIM           Half bright
+   A_BOLD          Extra bright or bold
+   A_PROTECT       Protected mode
+   A_INVIS         Invisible or blank mode
+   A_ALTCHARSET    Alternate character set
+   A_CHARTEXT      Bit-mask to extract a character
+   COLOR_PAIR(n)   Color-pair number n
+   */
+static void normal_color_theme(void)
+{
+	/* automatically add color... */
+#define mkattr(name, attr) do { \
+attributes[name] = attr | COLOR_PAIR(name); } while (0)
+	mkattr(NORMAL, NORMAL);
+	mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+	mkattr(MAIN_MENU_FORE, A_REVERSE);
+	mkattr(MAIN_MENU_BACK, A_NORMAL);
+	mkattr(MAIN_MENU_GREY, A_NORMAL);
+	mkattr(MAIN_MENU_HEADING, A_BOLD);
+	mkattr(MAIN_MENU_BOX, A_NORMAL);
+
+	mkattr(SCROLLWIN_TEXT, A_NORMAL);
+	mkattr(SCROLLWIN_HEADING, A_BOLD);
+	mkattr(SCROLLWIN_BOX, A_BOLD);
+
+	mkattr(DIALOG_TEXT, A_BOLD);
+	mkattr(DIALOG_BOX, A_BOLD);
+	mkattr(DIALOG_MENU_FORE, A_STANDOUT);
+	mkattr(DIALOG_MENU_BACK, A_NORMAL);
+
+	mkattr(INPUT_BOX, A_NORMAL);
+	mkattr(INPUT_HEADING, A_BOLD);
+	mkattr(INPUT_TEXT, A_NORMAL);
+	mkattr(INPUT_FIELD, A_UNDERLINE);
+
+	mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
+	mkattr(FUNCTION_TEXT, A_REVERSE);
+}
+
+static void no_colors_theme(void)
+{
+	/* automatically add highlight, no color */
+#define mkattrn(name, attr) { attributes[name] = attr; }
+
+	mkattrn(NORMAL, NORMAL);
+	mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+	mkattrn(MAIN_MENU_FORE, A_STANDOUT);
+	mkattrn(MAIN_MENU_BACK, A_NORMAL);
+	mkattrn(MAIN_MENU_GREY, A_NORMAL);
+	mkattrn(MAIN_MENU_HEADING, A_BOLD);
+	mkattrn(MAIN_MENU_BOX, A_NORMAL);
+
+	mkattrn(SCROLLWIN_TEXT, A_NORMAL);
+	mkattrn(SCROLLWIN_HEADING, A_BOLD);
+	mkattrn(SCROLLWIN_BOX, A_BOLD);
+
+	mkattrn(DIALOG_TEXT, A_NORMAL);
+	mkattrn(DIALOG_BOX, A_BOLD);
+	mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
+	mkattrn(DIALOG_MENU_BACK, A_NORMAL);
+
+	mkattrn(INPUT_BOX, A_BOLD);
+	mkattrn(INPUT_HEADING, A_BOLD);
+	mkattrn(INPUT_TEXT, A_NORMAL);
+	mkattrn(INPUT_FIELD, A_UNDERLINE);
+
+	mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
+	mkattrn(FUNCTION_TEXT, A_REVERSE);
+}
+
+void set_colors()
+{
+	start_color();
+	use_default_colors();
+	set_normal_colors();
+	if (has_colors()) {
+		normal_color_theme();
+	} else {
+		/* give defaults */
+		no_colors_theme();
+	}
+}
+
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+		int starty,
+		int startx,
+		int width,
+		const char *string,
+		chtype color)
+{      int length, x, y;
+	float temp;
+
+
+	if (win == NULL)
+		win = stdscr;
+	getyx(win, y, x);
+	if (startx != 0)
+		x = startx;
+	if (starty != 0)
+		y = starty;
+	if (width == 0)
+		width = 80;
+
+	length = strlen(string);
+	temp = (width - length) / 2;
+	x = startx + (int)temp;
+	(void) wattrset(win, color);
+	mvwprintw(win, y, x, "%s", string);
+	refresh();
+}
+
+int get_line_no(const char *text)
+{
+	int i;
+	int total = 1;
+
+	if (!text)
+		return 0;
+
+	for (i = 0; text[i] != '\0'; i++)
+		if (text[i] == '\n')
+			total++;
+	return total;
+}
+
+const char *get_line(const char *text, int line_no)
+{
+	int i;
+	int lines = 0;
+
+	if (!text)
+		return 0;
+
+	for (i = 0; text[i] != '\0' && lines < line_no; i++)
+		if (text[i] == '\n')
+			lines++;
+	return text+i;
+}
+
+int get_line_length(const char *line)
+{
+	int res = 0;
+	while (*line != '\0' && *line != '\n') {
+		line++;
+		res++;
+	}
+	return res;
+}
+
+/* print all lines to the window. */
+void fill_window(WINDOW *win, const char *text)
+{
+	int x, y;
+	int total_lines = get_line_no(text);
+	int i;
+
+	getmaxyx(win, y, x);
+	/* do not go over end of line */
+	total_lines = min(total_lines, y);
+	for (i = 0; i < total_lines; i++) {
+		char tmp[x+10];
+		const char *line = get_line(text, i);
+		int len = get_line_length(line);
+		strncpy(tmp, line, min(len, x));
+		tmp[len] = '\0';
+		mvwprintw(win, i, 0, "%s", tmp);
+	}
+}
+
+/* get the message, and buttons.
+ * each button must be a char*
+ * return the selected button
+ *
+ * this dialog is used for 2 different things:
+ * 1) show a text box, no buttons.
+ * 2) show a dialog, with horizontal buttons
+ */
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
+{
+	va_list ap;
+	char *btn;
+	int btns_width = 0;
+	int msg_lines = 0;
+	int msg_width = 0;
+	int total_width;
+	int win_rows = 0;
+	WINDOW *win;
+	WINDOW *msg_win;
+	WINDOW *menu_win;
+	MENU *menu;
+	ITEM *btns[btn_num+1];
+	int i, x, y;
+	int res = -1;
+
+
+	va_start(ap, btn_num);
+	for (i = 0; i < btn_num; i++) {
+		btn = va_arg(ap, char *);
+		btns[i] = new_item(btn, "");
+		btns_width += strlen(btn)+1;
+	}
+	va_end(ap);
+	btns[btn_num] = NULL;
+
+	/* find the widest line of msg: */
+	msg_lines = get_line_no(msg);
+	for (i = 0; i < msg_lines; i++) {
+		const char *line = get_line(msg, i);
+		int len = get_line_length(line);
+		if (msg_width < len)
+			msg_width = len;
+	}
+
+	total_width = max(msg_width, btns_width);
+	/* place dialog in middle of screen */
+	y = (LINES-(msg_lines+4))/2;
+	x = (COLS-(total_width+4))/2;
+
+
+	/* create the windows */
+	if (btn_num > 0)
+		win_rows = msg_lines+4;
+	else
+		win_rows = msg_lines+2;
+
+	win = newwin(win_rows, total_width+4, y, x);
+	keypad(win, TRUE);
+	menu_win = derwin(win, 1, btns_width, win_rows-2,
+			1+(total_width+2-btns_width)/2);
+	menu = new_menu(btns);
+	msg_win = derwin(win, win_rows-2, msg_width, 1,
+			1+(total_width+2-msg_width)/2);
+
+	set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
+	set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+
+	(void) wattrset(win, attributes[DIALOG_BOX]);
+	box(win, 0, 0);
+
+	/* print message */
+	(void) wattrset(msg_win, attributes[DIALOG_TEXT]);
+	fill_window(msg_win, msg);
+
+	set_menu_win(menu, win);
+	set_menu_sub(menu, menu_win);
+	set_menu_format(menu, 1, btn_num);
+	menu_opts_off(menu, O_SHOWDESC);
+	menu_opts_off(menu, O_SHOWMATCH);
+	menu_opts_on(menu, O_ONEVALUE);
+	menu_opts_on(menu, O_NONCYCLIC);
+	set_menu_mark(menu, "");
+	post_menu(menu);
+
+
+	touchwin(win);
+	refresh_all_windows(main_window);
+	while ((res = wgetch(win))) {
+		switch (res) {
+		case KEY_LEFT:
+			menu_driver(menu, REQ_LEFT_ITEM);
+			break;
+		case KEY_RIGHT:
+			menu_driver(menu, REQ_RIGHT_ITEM);
+			break;
+		case 10: /* ENTER */
+		case 27: /* ESCAPE */
+		case ' ':
+		case KEY_F(F_BACK):
+		case KEY_F(F_EXIT):
+			break;
+		}
+		touchwin(win);
+		refresh_all_windows(main_window);
+
+		if (res == 10 || res == ' ') {
+			res = item_index(current_item(menu));
+			break;
+		} else if (res == 27 || res == KEY_F(F_BACK) ||
+				res == KEY_F(F_EXIT)) {
+			res = KEY_EXIT;
+			break;
+		}
+	}
+
+	unpost_menu(menu);
+	free_menu(menu);
+	for (i = 0; i < btn_num; i++)
+		free_item(btns[i]);
+
+	delwin(win);
+	return res;
+}
+
+int dialog_inputbox(WINDOW *main_window,
+		const char *title, const char *prompt,
+		const char *init, char *result, int result_len)
+{
+	int prompt_lines = 0;
+	int prompt_width = 0;
+	WINDOW *win;
+	WINDOW *prompt_win;
+	WINDOW *form_win;
+	PANEL *panel;
+	int i, x, y;
+	int res = -1;
+	int cursor_position = strlen(init);
+
+
+	/* find the widest line of msg: */
+	prompt_lines = get_line_no(prompt);
+	for (i = 0; i < prompt_lines; i++) {
+		const char *line = get_line(prompt, i);
+		int len = get_line_length(line);
+		prompt_width = max(prompt_width, len);
+	}
+
+	if (title)
+		prompt_width = max(prompt_width, strlen(title));
+
+	/* place dialog in middle of screen */
+	y = (LINES-(prompt_lines+4))/2;
+	x = (COLS-(prompt_width+4))/2;
+
+	strncpy(result, init, result_len);
+
+	/* create the windows */
+	win = newwin(prompt_lines+6, prompt_width+7, y, x);
+	prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
+	form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
+	keypad(form_win, TRUE);
+
+	(void) wattrset(form_win, attributes[INPUT_FIELD]);
+
+	(void) wattrset(win, attributes[INPUT_BOX]);
+	box(win, 0, 0);
+	(void) wattrset(win, attributes[INPUT_HEADING]);
+	if (title)
+		mvwprintw(win, 0, 3, "%s", title);
+
+	/* print message */
+	(void) wattrset(prompt_win, attributes[INPUT_TEXT]);
+	fill_window(prompt_win, prompt);
+
+	mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+	mvwprintw(form_win, 0, 0, "%s", result);
+
+	/* create panels */
+	panel = new_panel(win);
+
+	/* show the cursor */
+	curs_set(1);
+
+	touchwin(win);
+	refresh_all_windows(main_window);
+	while ((res = wgetch(form_win))) {
+		int len = strlen(result);
+		switch (res) {
+		case 10: /* ENTER */
+		case 27: /* ESCAPE */
+		case KEY_F(F_HELP):
+		case KEY_F(F_EXIT):
+		case KEY_F(F_BACK):
+			break;
+		case 127:
+		case KEY_BACKSPACE:
+			if (cursor_position > 0) {
+				memmove(&result[cursor_position-1],
+						&result[cursor_position],
+						len-cursor_position+1);
+				cursor_position--;
+			}
+			break;
+		case KEY_DC:
+			if (cursor_position >= 0 && cursor_position < len) {
+				memmove(&result[cursor_position],
+						&result[cursor_position+1],
+						len-cursor_position+1);
+			}
+			break;
+		case KEY_UP:
+		case KEY_RIGHT:
+			if (cursor_position < len &&
+			    cursor_position < min(result_len, prompt_width))
+				cursor_position++;
+			break;
+		case KEY_DOWN:
+		case KEY_LEFT:
+			if (cursor_position > 0)
+				cursor_position--;
+			break;
+		default:
+			if ((isgraph(res) || isspace(res)) &&
+					len-2 < result_len) {
+				/* insert the char at the proper position */
+				memmove(&result[cursor_position+1],
+						&result[cursor_position],
+						len+1);
+				result[cursor_position] = res;
+				cursor_position++;
+			} else {
+				mvprintw(0, 0, "unknow key: %d\n", res);
+			}
+			break;
+		}
+		wmove(form_win, 0, 0);
+		wclrtoeol(form_win);
+		mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+		mvwprintw(form_win, 0, 0, "%s", result);
+		wmove(form_win, 0, cursor_position);
+		touchwin(win);
+		refresh_all_windows(main_window);
+
+		if (res == 10) {
+			res = 0;
+			break;
+		} else if (res == 27 || res == KEY_F(F_BACK) ||
+				res == KEY_F(F_EXIT)) {
+			res = KEY_EXIT;
+			break;
+		} else if (res == KEY_F(F_HELP)) {
+			res = 1;
+			break;
+		}
+	}
+
+	/* hide the cursor */
+	curs_set(0);
+	del_panel(panel);
+	delwin(prompt_win);
+	delwin(form_win);
+	delwin(win);
+	return res;
+}
+
+/* refresh all windows in the correct order */
+void refresh_all_windows(WINDOW *main_window)
+{
+	update_panels();
+	touchwin(main_window);
+	refresh();
+}
+
+/* layman's scrollable window... */
+void show_scroll_win(WINDOW *main_window,
+		const char *title,
+		const char *text)
+{
+	int res;
+	int total_lines = get_line_no(text);
+	int x, y;
+	int start_x = 0, start_y = 0;
+	int text_lines = 0, text_cols = 0;
+	int total_cols = 0;
+	int win_cols = 0;
+	int win_lines = 0;
+	int i = 0;
+	WINDOW *win;
+	WINDOW *pad;
+	PANEL *panel;
+
+	/* find the widest line of msg: */
+	total_lines = get_line_no(text);
+	for (i = 0; i < total_lines; i++) {
+		const char *line = get_line(text, i);
+		int len = get_line_length(line);
+		total_cols = max(total_cols, len+2);
+	}
+
+	/* create the pad */
+	pad = newpad(total_lines+10, total_cols+10);
+	(void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
+	fill_window(pad, text);
+
+	win_lines = min(total_lines+4, LINES-2);
+	win_cols = min(total_cols+2, COLS-2);
+	text_lines = max(win_lines-4, 0);
+	text_cols = max(win_cols-2, 0);
+
+	/* place window in middle of screen */
+	y = (LINES-win_lines)/2;
+	x = (COLS-win_cols)/2;
+
+	win = newwin(win_lines, win_cols, y, x);
+	keypad(win, TRUE);
+	/* show the help in the help window, and show the help panel */
+	(void) wattrset(win, attributes[SCROLLWIN_BOX]);
+	box(win, 0, 0);
+	(void) wattrset(win, attributes[SCROLLWIN_HEADING]);
+	mvwprintw(win, 0, 3, " %s ", title);
+	panel = new_panel(win);
+
+	/* handle scrolling */
+	do {
+
+		copywin(pad, win, start_y, start_x, 2, 2, text_lines,
+				text_cols, 0);
+		print_in_middle(win,
+				text_lines+2,
+				0,
+				text_cols,
+				"<OK>",
+				attributes[DIALOG_MENU_FORE]);
+		wrefresh(win);
+
+		res = wgetch(win);
+		switch (res) {
+		case KEY_NPAGE:
+		case ' ':
+			start_y += text_lines-2;
+			break;
+		case KEY_PPAGE:
+			start_y -= text_lines+2;
+			break;
+		case KEY_HOME:
+			start_y = 0;
+			break;
+		case KEY_END:
+			start_y = total_lines-text_lines;
+			break;
+		case KEY_DOWN:
+		case 'j':
+			start_y++;
+			break;
+		case KEY_UP:
+		case 'k':
+			start_y--;
+			break;
+		case KEY_LEFT:
+		case 'h':
+			start_x--;
+			break;
+		case KEY_RIGHT:
+		case 'l':
+			start_x++;
+			break;
+		}
+		if (res == 10 || res == 27 || res == 'q'
+		    || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
+			break;
+		}
+		if (start_y < 0)
+			start_y = 0;
+		if (start_y >= total_lines-text_lines)
+			start_y = total_lines-text_lines;
+		if (start_x < 0)
+			start_x = 0;
+		if (start_x >= total_cols-text_cols)
+			start_x = total_cols-text_cols;
+	} while (res);
+
+	del_panel(panel);
+	delwin(win);
+	refresh_all_windows(main_window);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.h b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.h
new file mode 100644
index 0000000..58fbda8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/nconf.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar at gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <curses.h>
+#include <menu.h>
+#include <panel.h>
+#include <form.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "ncurses.h"
+
+#define max(a, b) ({\
+		typeof(a) _a = a;\
+		typeof(b) _b = b;\
+		_a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+		typeof(a) _a = a;\
+		typeof(b) _b = b;\
+		_a < _b ? _a : _b; })
+
+typedef enum {
+	NORMAL = 1,
+	MAIN_HEADING,
+	MAIN_MENU_BOX,
+	MAIN_MENU_FORE,
+	MAIN_MENU_BACK,
+	MAIN_MENU_GREY,
+	MAIN_MENU_HEADING,
+	SCROLLWIN_TEXT,
+	SCROLLWIN_HEADING,
+	SCROLLWIN_BOX,
+	DIALOG_TEXT,
+	DIALOG_MENU_FORE,
+	DIALOG_MENU_BACK,
+	DIALOG_BOX,
+	INPUT_BOX,
+	INPUT_HEADING,
+	INPUT_TEXT,
+	INPUT_FIELD,
+	FUNCTION_TEXT,
+	FUNCTION_HIGHLIGHT,
+	ATTR_MAX
+} attributes_t;
+extern attributes_t attributes[];
+
+typedef enum {
+	F_HELP = 1,
+	F_SYMBOL = 2,
+	F_INSTS = 3,
+	F_CONF = 4,
+	F_BACK = 5,
+	F_SAVE = 6,
+	F_LOAD = 7,
+	F_SEARCH = 8,
+	F_EXIT = 9,
+} function_key;
+
+void set_colors(void);
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+		int starty,
+		int startx,
+		int width,
+		const char *string,
+		chtype color);
+int get_line_length(const char *line);
+int get_line_no(const char *text);
+const char *get_line(const char *text, int line_no);
+void fill_window(WINDOW *win, const char *text);
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
+int dialog_inputbox(WINDOW *main_window,
+		const char *title, const char *prompt,
+		const char *init, char *result, int result_len);
+void refresh_all_windows(WINDOW *main_window);
+void show_scroll_win(WINDOW *main_window,
+		const char *title,
+		const char *text);
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.cc b/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.cc
new file mode 100644
index 0000000..06dd2e3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.cc
@@ -0,0 +1,1787 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qglobal.h>
+
+#if QT_VERSION < 0x040000
+#include <qmainwindow.h>
+#include <qvbox.h>
+#include <qvaluelist.h>
+#include <qtextbrowser.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qpopupmenu.h>
+#else
+#include <q3mainwindow.h>
+#include <q3vbox.h>
+#include <q3valuelist.h>
+#include <q3textbrowser.h>
+#include <q3action.h>
+#include <q3header.h>
+#include <q3filedialog.h>
+#include <q3dragobject.h>
+#include <q3popupmenu.h>
+#endif
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qregexp.h>
+#include <qevent.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+static ConfigSettings *configSettings;
+
+Q3Action *ConfigMainWindow::saveAction;
+
+static inline QString qgettext(const char* str)
+{
+	return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+	return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+	Q3ValueList<int> result;
+	QStringList entryList = readListEntry(key, ok);
+	QStringList::Iterator it;
+
+	for (it = entryList.begin(); it != entryList.end(); ++it)
+		result.push_back((*it).toInt());
+
+	return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
+{
+	QStringList stringList;
+	Q3ValueList<int>::ConstIterator it;
+
+	for (it = value.begin(); it != value.end(); ++it)
+		stringList.push_back(QString::number(*it));
+	return writeEntry(key, stringList);
+}
+
+
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+	Parent::okRename(col);
+	sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+	listView()->updateList(this);
+}
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+	ConfigList* list;
+	struct symbol* sym;
+	struct property *prop;
+	QString prompt;
+	int type;
+	tristate expr;
+
+	list = listView();
+	if (goParent) {
+		setPixmap(promptColIdx, list->menuBackPix);
+		prompt = "..";
+		goto set_prompt;
+	}
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	prompt = _(menu_get_prompt(menu));
+
+	if (prop) switch (prop->type) {
+	case P_MENU:
+		if (list->mode == singleMode || list->mode == symbolMode) {
+			/* a menuconfig entry is displayed differently
+			 * depending whether it's at the view root or a child.
+			 */
+			if (sym && list->rootEntry == menu)
+				break;
+			setPixmap(promptColIdx, list->menuPix);
+		} else {
+			if (sym)
+				break;
+			setPixmap(promptColIdx, 0);
+		}
+		goto set_prompt;
+	case P_COMMENT:
+		setPixmap(promptColIdx, 0);
+		goto set_prompt;
+	default:
+		;
+	}
+	if (!sym)
+		goto set_prompt;
+
+	setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		char ch;
+
+		if (!sym_is_changable(sym) && list->optMode == normalOpt) {
+			setPixmap(promptColIdx, 0);
+			setText(noColIdx, QString::null);
+			setText(modColIdx, QString::null);
+			setText(yesColIdx, QString::null);
+			break;
+		}
+		expr = sym_get_tristate_value(sym);
+		switch (expr) {
+		case yes:
+			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+				setPixmap(promptColIdx, list->choiceYesPix);
+			else
+				setPixmap(promptColIdx, list->symbolYesPix);
+			setText(yesColIdx, "Y");
+			ch = 'Y';
+			break;
+		case mod:
+			setPixmap(promptColIdx, list->symbolModPix);
+			setText(modColIdx, "M");
+			ch = 'M';
+			break;
+		default:
+			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+				setPixmap(promptColIdx, list->choiceNoPix);
+			else
+				setPixmap(promptColIdx, list->symbolNoPix);
+			setText(noColIdx, "N");
+			ch = 'N';
+			break;
+		}
+		if (expr != no)
+			setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+		if (expr != mod)
+			setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+		if (expr != yes)
+			setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+		setText(dataColIdx, QChar(ch));
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		const char* data;
+
+		data = sym_get_string_value(sym);
+
+		int i = list->mapIdx(dataColIdx);
+		if (i >= 0)
+			setRenameEnabled(i, TRUE);
+		setText(dataColIdx, data);
+		if (type == S_STRING)
+			prompt = QString("%1: %2").arg(prompt).arg(data);
+		else
+			prompt = QString("(%2) %1").arg(prompt).arg(data);
+		break;
+	}
+	if (!sym_has_value(sym) && visible)
+		prompt += _(" (NEW)");
+set_prompt:
+	setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+	ConfigItem* i;
+
+	visible = v;
+	if (!menu)
+		return;
+
+	sym_calc_value(menu->sym);
+	if (menu->flags & MENU_CHANGED) {
+		/* the menu entry changed, so update all list items */
+		menu->flags &= ~MENU_CHANGED;
+		for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+			i->updateMenu();
+	} else if (listView()->updateAll)
+		updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+	ConfigList* list = listView();
+
+	if (visible) {
+		if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+			Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+		else
+			Parent::paintCell(p, cg, column, width, align);
+	} else
+		Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+	if (menu) {
+		ConfigList* list = listView();
+		nextItem = (ConfigItem*)menu->data;
+		menu->data = this;
+
+		if (list->mode != fullMode)
+			setOpen(TRUE);
+		sym_calc_value(menu->sym);
+	}
+	updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+	if (menu) {
+		ConfigItem** ip = (ConfigItem**)&menu->data;
+		for (; *ip; ip = &(*ip)->nextItem) {
+			if (*ip == this) {
+				*ip = nextItem;
+				break;
+			}
+		}
+	}
+}
+
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+	: Parent(parent)
+{
+	connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+	item = i;
+	if (sym_get_string_value(item->menu->sym))
+		setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+	else
+		setText(QString::null);
+	Parent::show();
+	setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+	switch (e->key()) {
+	case Qt::Key_Escape:
+		break;
+	case Qt::Key_Return:
+	case Qt::Key_Enter:
+		sym_set_string_value(item->menu->sym, text().latin1());
+		parent()->updateList(item);
+		break;
+	default:
+		Parent::keyPressEvent(e);
+		return;
+	}
+	e->accept();
+	parent()->list->setFocus();
+	hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, const char *name)
+	: Parent(p, name),
+	  updateAll(false),
+	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+	  showName(false), showRange(false), showData(false), optMode(normalOpt),
+	  rootEntry(0), headerPopup(0)
+{
+	int i;
+
+	setSorting(-1);
+	setRootIsDecorated(TRUE);
+	disabledColorGroup = palette().active();
+	disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+	inactivedColorGroup = palette().active();
+	inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+	connect(this, SIGNAL(selectionChanged(void)),
+		SLOT(updateSelection(void)));
+
+	if (name) {
+		configSettings->beginGroup(name);
+		showName = configSettings->readBoolEntry("/showName", false);
+		showRange = configSettings->readBoolEntry("/showRange", false);
+		showData = configSettings->readBoolEntry("/showData", false);
+		optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+
+	for (i = 0; i < colNr; i++)
+		colMap[i] = colRevMap[i] = -1;
+	addColumn(promptColIdx, _("Option"));
+
+	reinit();
+}
+
+bool ConfigList::menuSkip(struct menu *menu)
+{
+	if (optMode == normalOpt && menu_is_visible(menu))
+		return false;
+	if (optMode == promptOpt && menu_has_prompt(menu))
+		return false;
+	if (optMode == allOpt)
+		return false;
+	return true;
+}
+
+void ConfigList::reinit(void)
+{
+	removeColumn(dataColIdx);
+	removeColumn(yesColIdx);
+	removeColumn(modColIdx);
+	removeColumn(noColIdx);
+	removeColumn(nameColIdx);
+
+	if (showName)
+		addColumn(nameColIdx, _("Name"));
+	if (showRange) {
+		addColumn(noColIdx, "N");
+		addColumn(modColIdx, "M");
+		addColumn(yesColIdx, "Y");
+	}
+	if (showData)
+		addColumn(dataColIdx, _("Value"));
+
+	updateListAll();
+}
+
+void ConfigList::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showName", showName);
+		configSettings->writeEntry("/showRange", showRange);
+		configSettings->writeEntry("/showData", showData);
+		configSettings->writeEntry("/optionMode", (int)optMode);
+		configSettings->endGroup();
+	}
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+	ConfigItem* item = (ConfigItem*)menu->data;
+
+	for (; item; item = item->nextItem) {
+		if (this == item->listView())
+			break;
+	}
+
+	return item;
+}
+
+void ConfigList::updateSelection(void)
+{
+	struct menu *menu;
+	enum prop_type type;
+
+	ConfigItem* item = (ConfigItem*)selectedItem();
+	if (!item)
+		return;
+
+	menu = item->menu;
+	emit menuChanged(menu);
+	if (!menu)
+		return;
+	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (mode == menuMode && type == P_MENU)
+		emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+	ConfigItem* last = 0;
+
+	if (!rootEntry) {
+		if (mode != listMode)
+			goto update;
+		Q3ListViewItemIterator it(this);
+		ConfigItem* item;
+
+		for (; it.current(); ++it) {
+			item = (ConfigItem*)it.current();
+			if (!item->menu)
+				continue;
+			item->testUpdateMenu(menu_is_visible(item->menu));
+		}
+		return;
+	}
+
+	if (rootEntry != &rootmenu && (mode == singleMode ||
+	    (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+		item = firstChild();
+		if (!item)
+			item = new ConfigItem(this, 0, true);
+		last = item;
+	}
+	if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+	    rootEntry->sym && rootEntry->prompt) {
+		item = last ? last->nextSibling() : firstChild();
+		if (!item)
+			item = new ConfigItem(this, last, rootEntry, true);
+		else
+			item->testUpdateMenu(true);
+
+		updateMenuList(item, rootEntry);
+		triggerUpdate();
+		return;
+	}
+update:
+	updateMenuList(this, rootEntry);
+	triggerUpdate();
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+	struct symbol* sym;
+	int type;
+	tristate oldval;
+
+	sym = item->menu ? item->menu->sym : 0;
+	if (!sym)
+		return;
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldval = sym_get_tristate_value(sym);
+
+		if (!sym_set_tristate_value(sym, val))
+			return;
+		if (oldval == no && item->menu->list)
+			item->setOpen(TRUE);
+		parent()->updateList(item);
+		break;
+	}
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+	struct symbol* sym;
+	struct menu* menu;
+	int type, oldexpr, newexpr;
+
+	menu = item->menu;
+	if (!menu)
+		return;
+	sym = menu->sym;
+	if (!sym) {
+		if (item->menu->list)
+			item->setOpen(!item->isOpen());
+		return;
+	}
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldexpr = sym_get_tristate_value(sym);
+		newexpr = sym_toggle_tristate_value(sym);
+		if (item->menu->list) {
+			if (oldexpr == newexpr)
+				item->setOpen(!item->isOpen());
+			else if (oldexpr == no)
+				item->setOpen(TRUE);
+		}
+		if (oldexpr != newexpr)
+			parent()->updateList(item);
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		if (colMap[dataColIdx] >= 0)
+			item->startRename(colMap[dataColIdx]);
+		else
+			parent()->lineEdit->show(item);
+		break;
+	}
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+	enum prop_type type;
+
+	if (rootEntry == menu)
+		return;
+	type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (type != P_MENU)
+		return;
+	updateMenuList(this, 0);
+	rootEntry = menu;
+	updateListAll();
+	setSelected(currentItem(), hasFocus());
+	ensureItemVisible(currentItem());
+}
+
+void ConfigList::setParentMenu(void)
+{
+	ConfigItem* item;
+	struct menu *oldroot;
+
+	oldroot = rootEntry;
+	if (rootEntry == &rootmenu)
+		return;
+	setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+	Q3ListViewItemIterator it(this);
+	for (; (item = (ConfigItem*)it.current()); it++) {
+		if (item->menu == oldroot) {
+			setCurrentItem(item);
+			ensureItemVisible(item);
+			break;
+		}
+	}
+}
+
+/*
+ * update all the children of a menu entry
+ *   removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+	struct menu* child;
+	ConfigItem* item;
+	ConfigItem* last;
+	bool visible;
+	enum prop_type type;
+
+	if (!menu) {
+		while ((item = parent->firstChild()))
+			delete item;
+		return;
+	}
+
+	last = parent->firstChild();
+	if (last && !last->goParent)
+		last = 0;
+	for (child = menu->list; child; child = child->next) {
+		item = last ? last->nextSibling() : parent->firstChild();
+		type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+		switch (mode) {
+		case menuMode:
+			if (!(child->flags & MENU_ROOT))
+				goto hide;
+			break;
+		case symbolMode:
+			if (child->flags & MENU_ROOT)
+				goto hide;
+			break;
+		default:
+			break;
+		}
+
+		visible = menu_is_visible(child);
+		if (!menuSkip(child)) {
+			if (!child->sym && !child->list && !child->prompt)
+				continue;
+			if (!item || item->menu != child)
+				item = new ConfigItem(parent, last, child, visible);
+			else
+				item->testUpdateMenu(visible);
+
+			if (mode == fullMode || mode == menuMode || type != P_MENU)
+				updateMenuList(item, child);
+			else
+				updateMenuList(item, 0);
+			last = item;
+			continue;
+		}
+	hide:
+		if (item && item->menu == child) {
+			last = parent->firstChild();
+			if (last == item)
+				last = 0;
+			else while (last->nextSibling() != item)
+				last = last->nextSibling();
+			delete item;
+		}
+	}
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+	Q3ListViewItem* i = currentItem();
+	ConfigItem* item;
+	struct menu *menu;
+	enum prop_type type;
+
+	if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
+		emit parentSelected();
+		ev->accept();
+		return;
+	}
+
+	if (!i) {
+		Parent::keyPressEvent(ev);
+		return;
+	}
+	item = (ConfigItem*)i;
+
+	switch (ev->key()) {
+	case Qt::Key_Return:
+	case Qt::Key_Enter:
+		if (item->goParent) {
+			emit parentSelected();
+			break;
+		}
+		menu = item->menu;
+		if (!menu)
+			break;
+		type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+		if (type == P_MENU && rootEntry != menu &&
+		    mode != fullMode && mode != menuMode) {
+			emit menuSelected(menu);
+			break;
+		}
+	case Qt::Key_Space:
+		changeValue(item);
+		break;
+	case Qt::Key_N:
+		setValue(item, no);
+		break;
+	case Qt::Key_M:
+		setValue(item, mod);
+		break;
+	case Qt::Key_Y:
+		setValue(item, yes);
+		break;
+	default:
+		Parent::keyPressEvent(ev);
+		return;
+	}
+	ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+	//QPoint p(contentsToViewport(e->pos()));
+	//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+	QPoint p(contentsToViewport(e->pos()));
+	ConfigItem* item = (ConfigItem*)itemAt(p);
+	struct menu *menu;
+	enum prop_type ptype;
+	const QPixmap* pm;
+	int idx, x;
+
+	if (!item)
+		goto skip;
+
+	menu = item->menu;
+	x = header()->offset() + p.x();
+	idx = colRevMap[header()->sectionAt(x)];
+	switch (idx) {
+	case promptColIdx:
+		pm = item->pixmap(promptColIdx);
+		if (pm) {
+			int off = header()->sectionPos(0) + itemMargin() +
+				treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+			if (x >= off && x < off + pm->width()) {
+				if (item->goParent) {
+					emit parentSelected();
+					break;
+				} else if (!menu)
+					break;
+				ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+				if (ptype == P_MENU && rootEntry != menu &&
+				    mode != fullMode && mode != menuMode)
+					emit menuSelected(menu);
+				else
+					changeValue(item);
+			}
+		}
+		break;
+	case noColIdx:
+		setValue(item, no);
+		break;
+	case modColIdx:
+		setValue(item, mod);
+		break;
+	case yesColIdx:
+		setValue(item, yes);
+		break;
+	case dataColIdx:
+		changeValue(item);
+		break;
+	}
+
+skip:
+	//printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+	//QPoint p(contentsToViewport(e->pos()));
+	//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+	QPoint p(contentsToViewport(e->pos()));
+	ConfigItem* item = (ConfigItem*)itemAt(p);
+	struct menu *menu;
+	enum prop_type ptype;
+
+	if (!item)
+		goto skip;
+	if (item->goParent) {
+		emit parentSelected();
+		goto skip;
+	}
+	menu = item->menu;
+	if (!menu)
+		goto skip;
+	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+		emit menuSelected(menu);
+	else if (menu->sym)
+		changeValue(item);
+
+skip:
+	//printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+	struct menu *menu = NULL;
+
+	Parent::focusInEvent(e);
+
+	ConfigItem* item = (ConfigItem *)currentItem();
+	if (item) {
+		setSelected(item, TRUE);
+		menu = item->menu;
+	}
+	emit gotFocus(menu);
+}
+
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+	if (e->y() <= header()->geometry().bottom()) {
+		if (!headerPopup) {
+			Q3Action *action;
+
+			headerPopup = new Q3PopupMenu(this);
+			action = new Q3Action(NULL, _("Show Name"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowName(bool)));
+			  connect(parent(), SIGNAL(showNameChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showName);
+			  action->addTo(headerPopup);
+			action = new Q3Action(NULL, _("Show Range"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowRange(bool)));
+			  connect(parent(), SIGNAL(showRangeChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showRange);
+			  action->addTo(headerPopup);
+			action = new Q3Action(NULL, _("Show Data"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowData(bool)));
+			  connect(parent(), SIGNAL(showDataChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showData);
+			  action->addTo(headerPopup);
+		}
+		headerPopup->exec(e->globalPos());
+		e->accept();
+	} else
+		e->ignore();
+}
+
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+	: Parent(parent, name)
+{
+	list = new ConfigList(this, name);
+	lineEdit = new ConfigLineEdit(this);
+	lineEdit->hide();
+
+	this->nextView = viewList;
+	viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+	ConfigView** vp;
+
+	for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+		if (*vp == this) {
+			*vp = nextView;
+			break;
+		}
+	}
+}
+
+void ConfigView::setOptionMode(QAction *act)
+{
+	if (act == showNormalAction)
+		list->optMode = normalOpt;
+	else if (act == showAllAction)
+		list->optMode = allOpt;
+	else
+		list->optMode = promptOpt;
+
+	list->updateListAll();
+}
+
+void ConfigView::setShowName(bool b)
+{
+	if (list->showName != b) {
+		list->showName = b;
+		list->reinit();
+		emit showNameChanged(b);
+	}
+}
+
+void ConfigView::setShowRange(bool b)
+{
+	if (list->showRange != b) {
+		list->showRange = b;
+		list->reinit();
+		emit showRangeChanged(b);
+	}
+}
+
+void ConfigView::setShowData(bool b)
+{
+	if (list->showData != b) {
+		list->showData = b;
+		list->reinit();
+		emit showDataChanged(b);
+	}
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+	Q3ListViewItemIterator it(this);
+
+	for (; it.current(); it++)
+		it.current()->setOpen(open);
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+	ConfigView* v;
+
+	for (v = viewList; v; v = v->nextView)
+		v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+	ConfigView* v;
+
+	for (v = viewList; v; v = v->nextView)
+		v->list->updateListAll();
+}
+
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+	: Parent(parent, name), sym(0), _menu(0)
+{
+	if (name) {
+		configSettings->beginGroup(name);
+		_showDebug = configSettings->readBoolEntry("/showDebug", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+}
+
+void ConfigInfoView::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showDebug", showDebug());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+	if (_showDebug != b) {
+		_showDebug = b;
+		if (_menu)
+			menuInfo();
+		else if (sym)
+			symbolInfo();
+		emit showDebugChanged(b);
+	}
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+	if (_menu == m)
+		return;
+	_menu = m;
+	sym = NULL;
+	if (!_menu)
+		clear();
+	else
+		menuInfo();
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+	QString str;
+
+	str += "<big>Symbol: <b>";
+	str += print_filter(sym->name);
+	str += "</b></big><br><br>value: ";
+	str += print_filter(sym_get_string_value(sym));
+	str += "<br>visibility: ";
+	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+	str += "<br>";
+	str += debug_info(sym);
+
+	setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+	struct symbol* sym;
+	QString head, debug, help;
+
+	sym = _menu->sym;
+	if (sym) {
+		if (_menu->prompt) {
+			head += "<big><b>";
+			head += print_filter(_(_menu->prompt->text));
+			head += "</b></big>";
+			if (sym->name) {
+				head += " (";
+				if (showDebug())
+					head += QString().sprintf("<a href=\"s%p\">", sym);
+				head += print_filter(sym->name);
+				if (showDebug())
+					head += "</a>";
+				head += ")";
+			}
+		} else if (sym->name) {
+			head += "<big><b>";
+			if (showDebug())
+				head += QString().sprintf("<a href=\"s%p\">", sym);
+			head += print_filter(sym->name);
+			if (showDebug())
+				head += "</a>";
+			head += "</b></big>";
+		}
+		head += "<br><br>";
+
+		if (showDebug())
+			debug = debug_info(sym);
+
+		struct gstr help_gstr = str_new();
+		menu_get_ext_help(_menu, &help_gstr);
+		help = print_filter(str_get(&help_gstr));
+		str_free(&help_gstr);
+	} else if (_menu->prompt) {
+		head += "<big><b>";
+		head += print_filter(_(_menu->prompt->text));
+		head += "</b></big><br><br>";
+		if (showDebug()) {
+			if (_menu->prompt->visible.expr) {
+				debug += "  dep: ";
+				expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+				debug += "<br><br>";
+			}
+		}
+	}
+	if (showDebug())
+		debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
+
+	setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+	QString debug;
+
+	debug += "type: ";
+	debug += print_filter(sym_type_name(sym->type));
+	if (sym_is_choice(sym))
+		debug += " (choice)";
+	debug += "<br>";
+	if (sym->rev_dep.expr) {
+		debug += "reverse dep: ";
+		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+		debug += "<br>";
+	}
+	for (struct property *prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_PROMPT:
+		case P_MENU:
+			debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+			debug += print_filter(_(prop->text));
+			debug += "</a><br>";
+			break;
+		case P_DEFAULT:
+		case P_SELECT:
+		case P_RANGE:
+		case P_ENV:
+			debug += prop_get_type_name(prop->type);
+			debug += ": ";
+			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+			break;
+		case P_CHOICE:
+			if (sym_is_choice(sym)) {
+				debug += "choice: ";
+				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+				debug += "<br>";
+			}
+			break;
+		default:
+			debug += "unknown property: ";
+			debug += prop_get_type_name(prop->type);
+			debug += "<br>";
+		}
+		if (prop->visible.expr) {
+			debug += "    dep: ";
+			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+		}
+	}
+	debug += "<br>";
+
+	return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
+{
+	QRegExp re("[<>&\"\\n]");
+	QString res = str;
+	for (int i = 0; (i = res.find(re, i)) >= 0;) {
+		switch (res[i].latin1()) {
+		case '<':
+			res.replace(i, 1, "<");
+			i += 4;
+			break;
+		case '>':
+			res.replace(i, 1, ">");
+			i += 4;
+			break;
+		case '&':
+			res.replace(i, 1, "&");
+			i += 5;
+			break;
+		case '"':
+			res.replace(i, 1, """);
+			i += 6;
+			break;
+		case '\n':
+			res.replace(i, 1, "<br>");
+			i += 4;
+			break;
+		}
+	}
+	return res;
+}
+
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
+{
+	QString* text = reinterpret_cast<QString*>(data);
+	QString str2 = print_filter(str);
+
+	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+		*text += QString().sprintf("<a href=\"s%p\">", sym);
+		*text += str2;
+		*text += "</a>";
+	} else
+		*text += str2;
+}
+
+Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+	Q3PopupMenu* popup = Parent::createPopupMenu(pos);
+	Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
+	  action->setToggleAction(TRUE);
+	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+	  action->setOn(showDebug());
+	popup->insertSeparator();
+	action->addTo(popup);
+	return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+	Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
+	: Parent(parent, name), result(NULL)
+{
+	setCaption("Search Config");
+
+	QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+	QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+	layout2->addWidget(new QLabel(_("Find:"), this));
+	editField = new QLineEdit(this);
+	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+	layout2->addWidget(editField);
+	searchButton = new QPushButton(_("Search"), this);
+	searchButton->setAutoDefault(FALSE);
+	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+	layout2->addWidget(searchButton);
+	layout1->addLayout(layout2);
+
+	split = new QSplitter(this);
+	split->setOrientation(Qt::Vertical);
+	list = new ConfigView(split, name);
+	list->list->mode = listMode;
+	info = new ConfigInfoView(split, name);
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		info, SLOT(setInfo(struct menu *)));
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		parent, SLOT(setMenuLink(struct menu *)));
+
+	layout1->addWidget(split);
+
+	if (name) {
+		int x, y, width, height;
+		bool ok;
+
+		configSettings->beginGroup(name);
+		width = configSettings->readNumEntry("/window width", parent->width() / 2);
+		height = configSettings->readNumEntry("/window height", parent->height() / 2);
+		resize(width, height);
+		x = configSettings->readNumEntry("/window x", 0, &ok);
+		if (ok)
+			y = configSettings->readNumEntry("/window y", 0, &ok);
+		if (ok)
+			move(x, y);
+		Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
+		if (ok)
+			split->setSizes(sizes);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/window x", pos().x());
+		configSettings->writeEntry("/window y", pos().y());
+		configSettings->writeEntry("/window width", size().width());
+		configSettings->writeEntry("/window height", size().height());
+		configSettings->writeSizes("/split", split->sizes());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigSearchWindow::search(void)
+{
+	struct symbol **p;
+	struct property *prop;
+	ConfigItem *lastItem = NULL;
+
+	free(result);
+	list->list->clear();
+	info->clear();
+
+	result = sym_re_search(editField->text().latin1());
+	if (!result)
+		return;
+	for (p = result; *p; p++) {
+		for_all_prompts((*p), prop)
+			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+						  menu_is_visible(prop->menu));
+	}
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+	: searchWindow(0)
+{
+	QMenuBar* menu;
+	bool ok;
+	int x, y, width, height;
+	char title[256];
+
+	QDesktopWidget *d = configApp->desktop();
+	snprintf(title, sizeof(title), "%s%s",
+		rootmenu.prompt->text,
+#if QT_VERSION < 0x040000
+		" (Qt3)"
+#else
+		""
+#endif
+		);
+	setCaption(title);
+
+	width = configSettings->readNumEntry("/window width", d->width() - 64);
+	height = configSettings->readNumEntry("/window height", d->height() - 64);
+	resize(width, height);
+	x = configSettings->readNumEntry("/window x", 0, &ok);
+	if (ok)
+		y = configSettings->readNumEntry("/window y", 0, &ok);
+	if (ok)
+		move(x, y);
+
+	split1 = new QSplitter(this);
+	split1->setOrientation(Qt::Horizontal);
+	setCentralWidget(split1);
+
+	menuView = new ConfigView(split1, "menu");
+	menuList = menuView->list;
+
+	split2 = new QSplitter(split1);
+	split2->setOrientation(Qt::Vertical);
+
+	// create config tree
+	configView = new ConfigView(split2, "config");
+	configList = configView->list;
+
+	helpText = new ConfigInfoView(split2, "help");
+	helpText->setTextFormat(Qt::RichText);
+
+	setTabOrder(configList, helpText);
+	configList->setFocus();
+
+	menu = menuBar();
+	toolBar = new Q3ToolBar("Tools", this);
+
+	backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
+	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+	  backAction->setEnabled(FALSE);
+	Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
+	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
+	Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
+	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+	saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
+	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+	conf_set_changed_callback(conf_changed);
+	// Set saveAction's initial state
+	conf_changed();
+	Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
+	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+	Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
+	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+	Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+	Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+	Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+	Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
+	  showNameAction->setToggleAction(TRUE);
+	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+	  showNameAction->setOn(configView->showName());
+	Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
+	  showRangeAction->setToggleAction(TRUE);
+	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+	  showRangeAction->setOn(configList->showRange);
+	Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
+	  showDataAction->setToggleAction(TRUE);
+	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+	  showDataAction->setOn(configList->showData);
+
+	QActionGroup *optGroup = new QActionGroup(this);
+	optGroup->setExclusive(TRUE);
+	connect(optGroup, SIGNAL(selected(QAction *)), configView,
+		SLOT(setOptionMode(QAction *)));
+	connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+		SLOT(setOptionMode(QAction *)));
+
+#if QT_VERSION >= 0x040000
+	configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
+	configView->showAllAction = new QAction(_("Show All Options"), optGroup);
+	configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
+#else
+	configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
+	configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
+	configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
+#endif
+	configView->showNormalAction->setToggleAction(TRUE);
+	configView->showNormalAction->setOn(configList->optMode == normalOpt);
+	configView->showAllAction->setToggleAction(TRUE);
+	configView->showAllAction->setOn(configList->optMode == allOpt);
+	configView->showPromptAction->setToggleAction(TRUE);
+	configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
+	Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
+	  showDebugAction->setToggleAction(TRUE);
+	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+	  showDebugAction->setOn(helpText->showDebug());
+
+	Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
+	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+	Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
+	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+	// init tool bar
+	backAction->addTo(toolBar);
+	toolBar->addSeparator();
+	loadAction->addTo(toolBar);
+	saveAction->addTo(toolBar);
+	toolBar->addSeparator();
+	singleViewAction->addTo(toolBar);
+	splitViewAction->addTo(toolBar);
+	fullViewAction->addTo(toolBar);
+
+	// create config menu
+	Q3PopupMenu* config = new Q3PopupMenu(this);
+	menu->insertItem(_("&File"), config);
+	loadAction->addTo(config);
+	saveAction->addTo(config);
+	saveAsAction->addTo(config);
+	config->insertSeparator();
+	quitAction->addTo(config);
+
+	// create edit menu
+	Q3PopupMenu* editMenu = new Q3PopupMenu(this);
+	menu->insertItem(_("&Edit"), editMenu);
+	searchAction->addTo(editMenu);
+
+	// create options menu
+	Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
+	menu->insertItem(_("&Option"), optionMenu);
+	showNameAction->addTo(optionMenu);
+	showRangeAction->addTo(optionMenu);
+	showDataAction->addTo(optionMenu);
+	optionMenu->insertSeparator();
+	optGroup->addTo(optionMenu);
+	optionMenu->insertSeparator();
+
+	// create help menu
+	Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
+	menu->insertSeparator();
+	menu->insertItem(_("&Help"), helpMenu);
+	showIntroAction->addTo(helpMenu);
+	showAboutAction->addTo(helpMenu);
+
+	connect(configList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(configList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+	connect(configList, SIGNAL(parentSelected()),
+		SLOT(goBack()));
+	connect(menuList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+
+	connect(configList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		SLOT(listFocusChanged(void)));
+	connect(helpText, SIGNAL(menuSelected(struct menu *)),
+		SLOT(setMenuLink(struct menu *)));
+
+	QString listMode = configSettings->readEntry("/listMode", "symbol");
+	if (listMode == "single")
+		showSingleView();
+	else if (listMode == "full")
+		showFullView();
+	else /*if (listMode == "split")*/
+		showSplitView();
+
+	// UI setup done, restore splitter positions
+	Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+	if (ok)
+		split1->setSizes(sizes);
+
+	sizes = configSettings->readSizes("/split2", &ok);
+	if (ok)
+		split2->setSizes(sizes);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+	QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
+	if (s.isNull())
+		return;
+	if (conf_read(QFile::encodeName(s)))
+		QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
+	ConfigView::updateListAll();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+	if (conf_write(NULL))
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+	QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
+	if (s.isNull())
+		return;
+	if (conf_write(QFile::encodeName(s)))
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::searchConfig(void)
+{
+	if (!searchWindow)
+		searchWindow = new ConfigSearchWindow(this, "search");
+	searchWindow->show();
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+	configList->setRootMenu(menu);
+	if (configList->rootEntry->parent == &rootmenu)
+		backAction->setEnabled(FALSE);
+	else
+		backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+	struct menu *parent;
+	ConfigList* list = NULL;
+	ConfigItem* item;
+
+	if (configList->menuSkip(menu))
+		return;
+
+	switch (configList->mode) {
+	case singleMode:
+		list = configList;
+		parent = menu_get_parent_menu(menu);
+		if (!parent)
+			return;
+		list->setRootMenu(parent);
+		break;
+	case symbolMode:
+		if (menu->flags & MENU_ROOT) {
+			configList->setRootMenu(menu);
+			configList->clearSelection();
+			list = menuList;
+		} else {
+			list = configList;
+			parent = menu_get_parent_menu(menu->parent);
+			if (!parent)
+				return;
+			item = menuList->findConfigItem(parent);
+			if (item) {
+				menuList->setSelected(item, TRUE);
+				menuList->ensureItemVisible(item);
+			}
+			list->setRootMenu(parent);
+		}
+		break;
+	case fullMode:
+		list = configList;
+		break;
+	default:
+		break;
+	}
+
+	if (list) {
+		item = list->findConfigItem(menu);
+		if (item) {
+			list->setSelected(item, TRUE);
+			list->ensureItemVisible(item);
+			list->setFocus();
+		}
+	}
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+	if (menuList->mode == menuMode)
+		configList->clearSelection();
+}
+
+void ConfigMainWindow::goBack(void)
+{
+	ConfigItem* item;
+
+	configList->setParentMenu();
+	if (configList->rootEntry == &rootmenu)
+		backAction->setEnabled(FALSE);
+	item = (ConfigItem*)menuList->selectedItem();
+	while (item) {
+		if (item->menu == configList->rootEntry) {
+			menuList->setSelected(item, TRUE);
+			break;
+		}
+		item = (ConfigItem*)item->parent();
+	}
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+	menuView->hide();
+	menuList->setRootMenu(0);
+	configList->mode = singleMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(TRUE);
+	configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+	configList->mode = symbolMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(TRUE);
+	configApp->processEvents();
+	menuList->mode = menuMode;
+	menuList->setRootMenu(&rootmenu);
+	menuList->setAllOpen(TRUE);
+	menuView->show();
+	menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+	menuView->hide();
+	menuList->setRootMenu(0);
+	configList->mode = fullMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(FALSE);
+	configList->setFocus();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+	if (!conf_get_changed()) {
+		e->accept();
+		return;
+	}
+	QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
+			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+	mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
+	mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
+	mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
+	switch (mb.exec()) {
+	case QMessageBox::Yes:
+		conf_write(NULL);
+	case QMessageBox::No:
+		e->accept();
+		break;
+	case QMessageBox::Cancel:
+		e->ignore();
+		break;
+	}
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+	static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
+		"For each option, a blank box indicates the feature is disabled, a check\n"
+		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
+		"as a module.  Clicking on the box will cycle through the three states.\n\n"
+		"If you do not see an option (e.g., a device driver) that you believe\n"
+		"should be present, try turning on Show All Options under the Options menu.\n"
+		"Although there is no cross reference yet to help you figure out what other\n"
+		"options must be enabled to support the option you are interested in, you can\n"
+		"still view the help of a grayed-out option.\n\n"
+		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+		"which you can then match by examining other options.\n\n");
+
+	QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+	static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>.\n\n"
+		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
+
+	QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+	configSettings->writeEntry("/window x", pos().x());
+	configSettings->writeEntry("/window y", pos().y());
+	configSettings->writeEntry("/window width", size().width());
+	configSettings->writeEntry("/window height", size().height());
+
+	QString entry;
+	switch(configList->mode) {
+	case singleMode :
+		entry = "single";
+		break;
+
+	case symbolMode :
+		entry = "split";
+		break;
+
+	case fullMode :
+		entry = "full";
+		break;
+
+	default:
+		break;
+	}
+	configSettings->writeEntry("/listMode", entry);
+
+	configSettings->writeSizes("/split1", split1->sizes());
+	configSettings->writeSizes("/split2", split2->sizes());
+}
+
+void ConfigMainWindow::conf_changed(void)
+{
+	if (saveAction)
+		saveAction->setEnabled(conf_get_changed());
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+	struct menu *child;
+	static int menu_cnt = 0;
+
+	menu->flags |= MENU_ROOT;
+	for (child = menu->list; child; child = child->next) {
+		if (child->prompt && child->prompt->type == P_MENU) {
+			menu_cnt++;
+			fixup_rootmenu(child);
+			menu_cnt--;
+		} else if (!menu_cnt)
+			fixup_rootmenu(child);
+	}
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+	printf(_("%s <config>\n"), progname);
+	exit(0);
+}
+
+int main(int ac, char** av)
+{
+	ConfigMainWindow* v;
+	const char *name;
+
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+#ifndef LKC_DIRECT_LINK
+	kconfig_load();
+#endif
+
+	progname = av[0];
+	configApp = new QApplication(ac, av);
+	if (ac > 1 && av[1][0] == '-') {
+		switch (av[1][1]) {
+		case 'h':
+		case '?':
+			usage();
+		}
+		name = av[2];
+	} else
+		name = av[1];
+	if (!name)
+		usage();
+
+	conf_parse(name);
+	fixup_rootmenu(&rootmenu);
+	conf_read(NULL);
+	//zconfdump(stdout);
+
+	configSettings = new ConfigSettings();
+	configSettings->beginGroup("/kconfig/qconf");
+	v = new ConfigMainWindow();
+
+	//zconfdump(stdout);
+	configApp->setMainWidget(v);
+	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+	v->show();
+	configApp->exec();
+
+	configSettings->endGroup();
+	delete configSettings;
+
+	return 0;
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.h b/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.h
new file mode 100644
index 0000000..91677d9
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/qconf.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#if QT_VERSION < 0x040000
+#include <qlistview.h>
+#else
+#include <q3listview.h>
+#endif
+#include <qsettings.h>
+
+#if QT_VERSION < 0x040000
+#define Q3ValueList             QValueList
+#define Q3PopupMenu             QPopupMenu
+#define Q3ListView              QListView
+#define Q3ListViewItem          QListViewItem
+#define Q3VBox                  QVBox
+#define Q3TextBrowser           QTextBrowser
+#define Q3MainWindow            QMainWindow
+#define Q3Action                QAction
+#define Q3ToolBar               QToolBar
+#define Q3ListViewItemIterator  QListViewItemIterator
+#define Q3FileDialog            QFileDialog
+#endif
+
+class ConfigView;
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+class ConfigSettings : public QSettings {
+public:
+	Q3ValueList<int> readSizes(const QString& key, bool *ok);
+	bool writeSizes(const QString& key, const Q3ValueList<int>& value);
+};
+
+enum colIdx {
+	promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+	singleMode, menuMode, symbolMode, fullMode, listMode
+};
+enum optionMode {
+	normalOpt = 0, allOpt, promptOpt
+};
+
+class ConfigList : public Q3ListView {
+	Q_OBJECT
+	typedef class Q3ListView Parent;
+public:
+	ConfigList(ConfigView* p, const char *name = 0);
+	void reinit(void);
+	ConfigView* parent(void) const
+	{
+		return (ConfigView*)Parent::parent();
+	}
+	ConfigItem* findConfigItem(struct menu *);
+
+protected:
+	void keyPressEvent(QKeyEvent *e);
+	void contentsMousePressEvent(QMouseEvent *e);
+	void contentsMouseReleaseEvent(QMouseEvent *e);
+	void contentsMouseMoveEvent(QMouseEvent *e);
+	void contentsMouseDoubleClickEvent(QMouseEvent *e);
+	void focusInEvent(QFocusEvent *e);
+	void contextMenuEvent(QContextMenuEvent *e);
+
+public slots:
+	void setRootMenu(struct menu *menu);
+
+	void updateList(ConfigItem *item);
+	void setValue(ConfigItem* item, tristate val);
+	void changeValue(ConfigItem* item);
+	void updateSelection(void);
+	void saveSettings(void);
+signals:
+	void menuChanged(struct menu *menu);
+	void menuSelected(struct menu *menu);
+	void parentSelected(void);
+	void gotFocus(struct menu *);
+
+public:
+	void updateListAll(void)
+	{
+		updateAll = true;
+		updateList(NULL);
+		updateAll = false;
+	}
+	ConfigList* listView()
+	{
+		return this;
+	}
+	ConfigItem* firstChild() const
+	{
+		return (ConfigItem *)Parent::firstChild();
+	}
+	int mapIdx(colIdx idx)
+	{
+		return colMap[idx];
+	}
+	void addColumn(colIdx idx, const QString& label)
+	{
+		colMap[idx] = Parent::addColumn(label);
+		colRevMap[colMap[idx]] = idx;
+	}
+	void removeColumn(colIdx idx)
+	{
+		int col = colMap[idx];
+		if (col >= 0) {
+			Parent::removeColumn(col);
+			colRevMap[col] = colMap[idx] = -1;
+		}
+	}
+	void setAllOpen(bool open);
+	void setParentMenu(void);
+
+	bool menuSkip(struct menu *);
+
+	template <class P>
+	void updateMenuList(P*, struct menu*);
+
+	bool updateAll;
+
+	QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+	QPixmap choiceYesPix, choiceNoPix;
+	QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+	bool showName, showRange, showData;
+	enum listMode mode;
+	enum optionMode optMode;
+	struct menu *rootEntry;
+	QColorGroup disabledColorGroup;
+	QColorGroup inactivedColorGroup;
+	Q3PopupMenu* headerPopup;
+
+private:
+	int colMap[colNr];
+	int colRevMap[colNr];
+};
+
+class ConfigItem : public Q3ListViewItem {
+	typedef class Q3ListViewItem Parent;
+public:
+	ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
+	: Parent(parent, after), menu(m), visible(v), goParent(false)
+	{
+		init();
+	}
+	ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+	: Parent(parent, after), menu(m), visible(v), goParent(false)
+	{
+		init();
+	}
+	ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
+	: Parent(parent, after), menu(0), visible(v), goParent(true)
+	{
+		init();
+	}
+	~ConfigItem(void);
+	void init(void);
+	void okRename(int col);
+	void updateMenu(void);
+	void testUpdateMenu(bool v);
+	ConfigList* listView() const
+	{
+		return (ConfigList*)Parent::listView();
+	}
+	ConfigItem* firstChild() const
+	{
+		return (ConfigItem *)Parent::firstChild();
+	}
+	ConfigItem* nextSibling() const
+	{
+		return (ConfigItem *)Parent::nextSibling();
+	}
+	void setText(colIdx idx, const QString& text)
+	{
+		Parent::setText(listView()->mapIdx(idx), text);
+	}
+	QString text(colIdx idx) const
+	{
+		return Parent::text(listView()->mapIdx(idx));
+	}
+	void setPixmap(colIdx idx, const QPixmap& pm)
+	{
+		Parent::setPixmap(listView()->mapIdx(idx), pm);
+	}
+	const QPixmap* pixmap(colIdx idx) const
+	{
+		return Parent::pixmap(listView()->mapIdx(idx));
+	}
+	void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+	ConfigItem* nextItem;
+	struct menu *menu;
+	bool visible;
+	bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+	Q_OBJECT
+	typedef class QLineEdit Parent;
+public:
+	ConfigLineEdit(ConfigView* parent);
+	ConfigView* parent(void) const
+	{
+		return (ConfigView*)Parent::parent();
+	}
+	void show(ConfigItem *i);
+	void keyPressEvent(QKeyEvent *e);
+
+public:
+	ConfigItem *item;
+};
+
+class ConfigView : public Q3VBox {
+	Q_OBJECT
+	typedef class Q3VBox Parent;
+public:
+	ConfigView(QWidget* parent, const char *name = 0);
+	~ConfigView(void);
+	static void updateList(ConfigItem* item);
+	static void updateListAll(void);
+
+	bool showName(void) const { return list->showName; }
+	bool showRange(void) const { return list->showRange; }
+	bool showData(void) const { return list->showData; }
+public slots:
+	void setShowName(bool);
+	void setShowRange(bool);
+	void setShowData(bool);
+	void setOptionMode(QAction *);
+signals:
+	void showNameChanged(bool);
+	void showRangeChanged(bool);
+	void showDataChanged(bool);
+public:
+	ConfigList* list;
+	ConfigLineEdit* lineEdit;
+
+	static ConfigView* viewList;
+	ConfigView* nextView;
+
+	static QAction *showNormalAction;
+	static QAction *showAllAction;
+	static QAction *showPromptAction;
+};
+
+class ConfigInfoView : public Q3TextBrowser {
+	Q_OBJECT
+	typedef class Q3TextBrowser Parent;
+public:
+	ConfigInfoView(QWidget* parent, const char *name = 0);
+	bool showDebug(void) const { return _showDebug; }
+
+public slots:
+	void setInfo(struct menu *menu);
+	void saveSettings(void);
+	void setShowDebug(bool);
+
+signals:
+	void showDebugChanged(bool);
+	void menuSelected(struct menu *);
+
+protected:
+	void symbolInfo(void);
+	void menuInfo(void);
+	QString debug_info(struct symbol *sym);
+	static QString print_filter(const QString &str);
+	static void expr_print_help(void *data, struct symbol *sym, const char *str);
+	Q3PopupMenu* createPopupMenu(const QPoint& pos);
+	void contentsContextMenuEvent(QContextMenuEvent *e);
+
+	struct symbol *sym;
+	struct menu *_menu;
+	bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+	Q_OBJECT
+	typedef class QDialog Parent;
+public:
+	ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
+
+public slots:
+	void saveSettings(void);
+	void search(void);
+
+protected:
+	QLineEdit* editField;
+	QPushButton* searchButton;
+	QSplitter* split;
+	ConfigView* list;
+	ConfigInfoView* info;
+
+	struct symbol **result;
+};
+
+class ConfigMainWindow : public Q3MainWindow {
+	Q_OBJECT
+
+	static Q3Action *saveAction;
+	static void conf_changed(void);
+public:
+	ConfigMainWindow(void);
+public slots:
+	void changeMenu(struct menu *);
+	void setMenuLink(struct menu *);
+	void listFocusChanged(void);
+	void goBack(void);
+	void loadConfig(void);
+	void saveConfig(void);
+	void saveConfigAs(void);
+	void searchConfig(void);
+	void showSingleView(void);
+	void showSplitView(void);
+	void showFullView(void);
+	void showIntro(void);
+	void showAbout(void);
+	void saveSettings(void);
+
+protected:
+	void closeEvent(QCloseEvent *e);
+
+	ConfigSearchWindow *searchWindow;
+	ConfigView *menuView;
+	ConfigList *menuList;
+	ConfigView *configView;
+	ConfigList *configList;
+	ConfigInfoView *helpText;
+	Q3ToolBar *toolBar;
+	Q3Action *backAction;
+	QSplitter* split1;
+	QSplitter* split2;
+};
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/symbol.c b/qemu-0.15.x/roms/seabios/tools/kconfig/symbol.c
new file mode 100644
index 0000000..a796c95
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/symbol.c
@@ -0,0 +1,1260 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+	.name = "y",
+	.curr = { "y", yes },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+	.name = "m",
+	.curr = { "m", mod },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+	.name = "n",
+	.curr = { "n", no },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+	.name = "",
+	.curr = { "", no },
+	.flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
+{
+	struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+	prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+	struct symbol *sym;
+	struct utsname uts;
+	static bool inited = false;
+
+	if (inited)
+		return;
+	inited = true;
+
+	uname(&uts);
+
+	sym = sym_lookup("UNAME_RELEASE", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+	enum symbol_type type = sym->type;
+
+	if (type == S_TRISTATE) {
+		if (sym_is_choice_value(sym) && sym->visible == yes)
+			type = S_BOOLEAN;
+		else if (modules_val == no)
+			type = S_BOOLEAN;
+	}
+	return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+	switch (type) {
+	case S_BOOLEAN:
+		return "boolean";
+	case S_TRISTATE:
+		return "tristate";
+	case S_INT:
+		return "integer";
+	case S_HEX:
+		return "hex";
+	case S_STRING:
+		return "string";
+	case S_UNKNOWN:
+		return "unknown";
+	case S_OTHER:
+		break;
+	}
+	return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_choices(sym, prop)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_ENV)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static struct property *sym_get_range_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_RANGE) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+	sym_calc_value(sym);
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		break;
+	}
+	return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+	struct property *prop;
+	int base, val, val2;
+	char str[64];
+
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		return;
+	}
+	prop = sym_get_range_prop(sym);
+	if (!prop)
+		return;
+	val = strtol(sym->curr.val, NULL, base);
+	val2 = sym_get_range_val(prop->expr->left.sym, base);
+	if (val >= val2) {
+		val2 = sym_get_range_val(prop->expr->right.sym, base);
+		if (val <= val2)
+			return;
+	}
+	if (sym->type == S_INT)
+		sprintf(str, "%d", val2);
+	else
+		sprintf(str, "0x%x", val2);
+	sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+	struct property *prop;
+	tristate tri;
+
+	/* any prompt visible? */
+	tri = no;
+	for_all_prompts(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		tri = EXPR_OR(tri, prop->visible.tri);
+	}
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+		tri = yes;
+	if (sym->visible != tri) {
+		sym->visible = tri;
+		sym_set_changed(sym);
+	}
+	if (sym_is_choice_value(sym))
+		return;
+	/* defaulting to "yes" if no explicit "depends on" are given */
+	tri = yes;
+	if (sym->dir_dep.expr)
+		tri = expr_calc_value(sym->dir_dep.expr);
+	if (tri == mod)
+		tri = yes;
+	if (sym->dir_dep.tri != tri) {
+		sym->dir_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+	tri = no;
+	if (sym->rev_dep.expr)
+		tri = expr_calc_value(sym->rev_dep.expr);
+	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+		tri = yes;
+	if (sym->rev_dep.tri != tri) {
+		sym->rev_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+}
+
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* any of the defaults visible? */
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri == no)
+			continue;
+		def_sym = prop_get_symbol(prop);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* just get the first visible value */
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym)
+		if (def_sym->visible != no)
+			return def_sym;
+
+	/* failed to locate any defaults */
+	return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* first calculate all choice values' visibilities */
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym)
+		sym_calc_visibility(def_sym);
+
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym && def_sym->visible != no)
+		return def_sym;
+
+	def_sym = sym_choice_default(sym);
+
+	if (def_sym == NULL)
+		/* no choice? reset tristate value */
+		sym->curr.tri = no;
+
+	return def_sym;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+	struct symbol_value newval, oldval;
+	struct property *prop;
+	struct expr *e;
+
+	if (!sym)
+		return;
+
+	if (sym->flags & SYMBOL_VALID)
+		return;
+	sym->flags |= SYMBOL_VALID;
+
+	oldval = sym->curr;
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		newval = symbol_empty.curr;
+		break;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		newval = symbol_no.curr;
+		break;
+	default:
+		sym->curr.val = sym->name;
+		sym->curr.tri = no;
+		return;
+	}
+	if (!sym_is_choice_value(sym))
+		sym->flags &= ~SYMBOL_WRITE;
+
+	sym_calc_visibility(sym);
+
+	/* set default if recursively called */
+	sym->curr = newval;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		if (sym_is_choice_value(sym) && sym->visible == yes) {
+			prop = sym_get_choice_prop(sym);
+			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+		} else {
+			if (sym->visible != no) {
+				/* if the symbol is visible use the user value
+				 * if available, otherwise try the default value
+				 */
+				sym->flags |= SYMBOL_WRITE;
+				if (sym_has_value(sym)) {
+					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+							      sym->visible);
+					goto calc_newval;
+				}
+			}
+			if (sym->rev_dep.tri != no)
+				sym->flags |= SYMBOL_WRITE;
+			if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop) {
+					sym->flags |= SYMBOL_WRITE;
+					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+							      prop->visible.tri);
+				}
+			}
+		calc_newval:
+			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+				struct expr *e;
+				e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+				    sym->dir_dep.expr);
+				fprintf(stderr, "warning: (");
+				expr_fprint(e, stderr);
+				fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+					sym->name);
+				expr_fprint(sym->dir_dep.expr, stderr);
+				fprintf(stderr, ")\n");
+				expr_free(e);
+			}
+			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+		}
+		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+			newval.tri = yes;
+		break;
+	case S_STRING:
+	case S_HEX:
+	case S_INT:
+		if (sym->visible != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym)) {
+				newval.val = sym->def[S_DEF_USER].val;
+				break;
+			}
+		}
+		prop = sym_get_default_prop(sym);
+		if (prop) {
+			struct symbol *ds = prop_get_symbol(prop);
+			if (ds) {
+				sym->flags |= SYMBOL_WRITE;
+				sym_calc_value(ds);
+				newval.val = ds->curr.val;
+			}
+		}
+		break;
+	default:
+		;
+	}
+
+	sym->curr = newval;
+	if (sym_is_choice(sym) && newval.tri == yes)
+		sym->curr.val = sym_calc_choice(sym);
+	sym_validate_range(sym);
+
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+		sym_set_changed(sym);
+		if (modules_sym == sym) {
+			sym_set_all_changed();
+			modules_val = modules_sym->curr.tri;
+		}
+	}
+
+	if (sym_is_choice(sym)) {
+		struct symbol *choice_sym;
+
+		prop = sym_get_choice_prop(sym);
+		expr_list_for_each_sym(prop->expr, e, choice_sym) {
+			if ((sym->flags & SYMBOL_WRITE) &&
+			    choice_sym->visible != no)
+				choice_sym->flags |= SYMBOL_WRITE;
+			if (sym->flags & SYMBOL_CHANGED)
+				sym_set_changed(choice_sym);
+		}
+	}
+
+	if (sym->flags & SYMBOL_AUTO)
+		sym->flags &= ~SYMBOL_WRITE;
+}
+
+void sym_clear_all_valid(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym->flags &= ~SYMBOL_VALID;
+	sym_add_change_count(1);
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+	struct property *prop;
+
+	sym->flags |= SYMBOL_CHANGED;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu)
+			prop->menu->flags |= MENU_CHANGED;
+	}
+}
+
+void sym_set_all_changed(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+	int type = sym_get_type(sym);
+
+	if (sym->visible == no)
+		return false;
+
+	if (type != S_BOOLEAN && type != S_TRISTATE)
+		return false;
+
+	if (type == S_BOOLEAN && val == mod)
+		return false;
+	if (sym->visible <= sym->rev_dep.tri)
+		return false;
+	if (sym_is_choice_value(sym) && sym->visible == yes)
+		return val == yes;
+	return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+	tristate oldval = sym_get_tristate_value(sym);
+
+	if (oldval != val && !sym_tristate_within_range(sym, val))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+	/*
+	 * setting a choice value also resets the new flag of the choice
+	 * symbol and all other choice values.
+	 */
+	if (sym_is_choice_value(sym) && val == yes) {
+		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+		struct property *prop;
+		struct expr *e;
+
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
+		prop = sym_get_choice_prop(cs);
+		for (e = prop->expr; e; e = e->left.expr) {
+			if (e->right.sym->visible != no)
+				e->right.sym->flags |= SYMBOL_DEF_USER;
+		}
+	}
+
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
+		sym_clear_all_valid();
+
+	return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+	tristate oldval, newval;
+
+	oldval = newval = sym_get_tristate_value(sym);
+	do {
+		switch (newval) {
+		case no:
+			newval = mod;
+			break;
+		case mod:
+			newval = yes;
+			break;
+		case yes:
+			newval = no;
+			break;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			break;
+	} while (oldval != newval);
+	return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+	signed char ch;
+
+	switch (sym->type) {
+	case S_STRING:
+		return true;
+	case S_INT:
+		ch = *str++;
+		if (ch == '-')
+			ch = *str++;
+		if (!isdigit(ch))
+			return false;
+		if (ch == '0' && *str != 0)
+			return false;
+		while ((ch = *str++)) {
+			if (!isdigit(ch))
+				return false;
+		}
+		return true;
+	case S_HEX:
+		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+			str += 2;
+		ch = *str++;
+		do {
+			if (!isxdigit(ch))
+				return false;
+		} while ((ch = *str++));
+		return true;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+		case 'm': case 'M':
+		case 'n': case 'N':
+			return true;
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+	struct property *prop;
+	int val;
+
+	switch (sym->type) {
+	case S_STRING:
+		return sym_string_valid(sym, str);
+	case S_INT:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 10);
+		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 10);
+	case S_HEX:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 16);
+		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 16);
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+			return sym_tristate_within_range(sym, yes);
+		case 'm': case 'M':
+			return sym_tristate_within_range(sym, mod);
+		case 'n': case 'N':
+			return sym_tristate_within_range(sym, no);
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+	const char *oldval;
+	char *val;
+	int size;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (newval[0]) {
+		case 'y': case 'Y':
+			return sym_set_tristate_value(sym, yes);
+		case 'm': case 'M':
+			return sym_set_tristate_value(sym, mod);
+		case 'n': case 'N':
+			return sym_set_tristate_value(sym, no);
+		}
+		return false;
+	default:
+		;
+	}
+
+	if (!sym_string_within_range(sym, newval))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+
+	oldval = sym->def[S_DEF_USER].val;
+	size = strlen(newval) + 1;
+	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+		size += 2;
+		sym->def[S_DEF_USER].val = val = malloc(size);
+		*val++ = '0';
+		*val++ = 'x';
+	} else if (!oldval || strcmp(oldval, newval))
+		sym->def[S_DEF_USER].val = val = malloc(size);
+	else
+		return true;
+
+	strcpy(val, newval);
+	free((void *)oldval);
+	sym_clear_all_valid();
+
+	return true;
+}
+
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *ds;
+	const char *str;
+	tristate val;
+
+	sym_calc_visibility(sym);
+	sym_calc_value(modules_sym);
+	val = symbol_no.curr.tri;
+	str = symbol_empty.curr.val;
+
+	/* If symbol has a default value look it up */
+	prop = sym_get_default_prop(sym);
+	if (prop != NULL) {
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			/* The visibility may limit the value from yes => mod */
+			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+			break;
+		default:
+			/*
+			 * The following fails to handle the situation
+			 * where a default value is further limited by
+			 * the valid range.
+			 */
+			ds = prop_get_symbol(prop);
+			if (ds != NULL) {
+				sym_calc_value(ds);
+				str = (const char *)ds->curr.val;
+			}
+		}
+	}
+
+	/* Handle select statements */
+	val = EXPR_OR(val, sym->rev_dep.tri);
+
+	/* transpose mod to yes if modules are not enabled */
+	if (val == mod)
+		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+			val = yes;
+
+	/* transpose mod to yes if type is bool */
+	if (sym->type == S_BOOLEAN && val == mod)
+		val = yes;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (val) {
+		case no: return "n";
+		case mod: return "m";
+		case yes: return "y";
+		}
+	case S_INT:
+	case S_HEX:
+		return str;
+	case S_STRING:
+		return str;
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	}
+	return "";
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+	tristate val;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			return "n";
+		case mod:
+			return "m";
+		case yes:
+			return "y";
+		}
+		break;
+	default:
+		;
+	}
+	return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+	return sym->visible > sym->rev_dep.tri;
+}
+
+static unsigned strhash(const char *s)
+{
+	/* fnv32 hash */
+	unsigned hash = 2166136261U;
+	for (; *s; s++)
+		hash = (hash ^ *s) * 0x01000193;
+	return hash;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+	struct symbol *symbol;
+	char *new_name;
+	int hash;
+
+	if (name) {
+		if (name[0] && !name[1]) {
+			switch (name[0]) {
+			case 'y': return &symbol_yes;
+			case 'm': return &symbol_mod;
+			case 'n': return &symbol_no;
+			}
+		}
+		hash = strhash(name) % SYMBOL_HASHSIZE;
+
+		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+			if (symbol->name &&
+			    !strcmp(symbol->name, name) &&
+			    (flags ? symbol->flags & flags
+				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+				return symbol;
+		}
+		new_name = strdup(name);
+	} else {
+		new_name = NULL;
+		hash = 0;
+	}
+
+	symbol = malloc(sizeof(*symbol));
+	memset(symbol, 0, sizeof(*symbol));
+	symbol->name = new_name;
+	symbol->type = S_UNKNOWN;
+	symbol->flags |= flags;
+
+	symbol->next = symbol_hash[hash];
+	symbol_hash[hash] = symbol;
+
+	return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+	struct symbol *symbol = NULL;
+	int hash = 0;
+
+	if (!name)
+		return NULL;
+
+	if (name[0] && !name[1]) {
+		switch (name[0]) {
+		case 'y': return &symbol_yes;
+		case 'm': return &symbol_mod;
+		case 'n': return &symbol_no;
+		}
+	}
+	hash = strhash(name) % SYMBOL_HASHSIZE;
+
+	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+		if (symbol->name &&
+		    !strcmp(symbol->name, name) &&
+		    !(symbol->flags & SYMBOL_CONST))
+				break;
+	}
+
+	return symbol;
+}
+
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+	const char *src;
+	char *res;
+	size_t reslen;
+
+	reslen = strlen(in) + 1;
+	res = malloc(reslen);
+	res[0] = '\0';
+
+	while ((src = strchr(in, '$'))) {
+		char *p, name[SYMBOL_MAXLENGTH];
+		const char *symval = "";
+		struct symbol *sym;
+		size_t newlen;
+
+		strncat(res, in, src - in);
+		src++;
+
+		p = name;
+		while (isalnum(*src) || *src == '_')
+			*p++ = *src++;
+		*p = '\0';
+
+		sym = sym_find(name);
+		if (sym != NULL) {
+			sym_calc_value(sym);
+			symval = sym_get_string_value(sym);
+		}
+
+		newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+		if (newlen > reslen) {
+			reslen = newlen;
+			res = realloc(res, reslen);
+		}
+
+		strcat(res, symval);
+		in = src;
+	}
+	strcat(res, in);
+
+	return res;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+	struct symbol *sym, **sym_arr = NULL;
+	int i, cnt, size;
+	regex_t re;
+
+	cnt = size = 0;
+	/* Skip if empty */
+	if (strlen(pattern) == 0)
+		return NULL;
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+		return NULL;
+
+	for_all_symbols(i, sym) {
+		if (sym->flags & SYMBOL_CONST || !sym->name)
+			continue;
+		if (regexec(&re, sym->name, 0, NULL, 0))
+			continue;
+		if (cnt + 1 >= size) {
+			void *tmp = sym_arr;
+			size += 16;
+			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+			if (!sym_arr) {
+				free(tmp);
+				return NULL;
+			}
+		}
+		sym_calc_value(sym);
+		sym_arr[cnt++] = sym;
+	}
+	if (sym_arr)
+		sym_arr[cnt] = NULL;
+	regfree(&re);
+
+	return sym_arr;
+}
+
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note inser() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+	struct dep_stack *prev, *next;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+	memset(stack, 0, sizeof(*stack));
+	if (check_top)
+		check_top->next = stack;
+	stack->prev = check_top;
+	stack->sym = sym;
+	check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+	check_top = check_top->prev;
+	if (check_top)
+		check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+	struct dep_stack *stack;
+	struct symbol *sym, *next_sym;
+	struct menu *menu = NULL;
+	struct property *prop;
+	struct dep_stack cv_stack;
+
+	if (sym_is_choice_value(last_sym)) {
+		dep_stack_insert(&cv_stack, last_sym);
+		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+	}
+
+	for (stack = check_top; stack != NULL; stack = stack->prev)
+		if (stack->sym == last_sym)
+			break;
+	if (!stack) {
+		fprintf(stderr, "unexpected recursive dependency error\n");
+		return;
+	}
+
+	for (; stack; stack = stack->next) {
+		sym = stack->sym;
+		next_sym = stack->next ? stack->next->sym : last_sym;
+		prop = stack->prop;
+		if (prop == NULL)
+			prop = stack->sym->prop;
+
+		/* for choice values find the menu entry (used below) */
+		if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+			for (prop = sym->prop; prop; prop = prop->next) {
+				menu = prop->menu;
+				if (prop->menu)
+					break;
+			}
+		}
+		if (stack->sym == last_sym)
+			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+				prop->file->name, prop->lineno);
+		if (stack->expr) {
+			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				prop_get_type_name(prop->type),
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (stack->prop) {
+			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice(sym)) {
+			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice_value(sym)) {
+			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else {
+			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		}
+	}
+
+	if (check_top == &cv_stack)
+		dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+	struct symbol *sym;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_OR:
+	case E_AND:
+		sym = sym_check_expr_deps(e->left.expr);
+		if (sym)
+			return sym;
+		return sym_check_expr_deps(e->right.expr);
+	case E_NOT:
+		return sym_check_expr_deps(e->left.expr);
+	case E_EQUAL:
+	case E_UNEQUAL:
+		sym = sym_check_deps(e->left.sym);
+		if (sym)
+			return sym;
+		return sym_check_deps(e->right.sym);
+	case E_SYMBOL:
+		return sym_check_deps(e->left.sym);
+	default:
+		break;
+	}
+	printf("Oops! How to check %d?\n", e->type);
+	return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, sym);
+
+	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+	if (sym2)
+		goto out;
+
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->type == P_CHOICE || prop->type == P_SELECT)
+			continue;
+		stack.prop = prop;
+		sym2 = sym_check_expr_deps(prop->visible.expr);
+		if (sym2)
+			break;
+		if (prop->type != P_DEFAULT || sym_is_choice(sym))
+			continue;
+		stack.expr = prop->expr;
+		sym2 = sym_check_expr_deps(prop->expr);
+		if (sym2)
+			break;
+		stack.expr = NULL;
+	}
+
+out:
+	dep_stack_remove();
+
+	return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	struct expr *e;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, choice);
+
+	prop = sym_get_choice_prop(choice);
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	sym2 = sym_check_sym_deps(choice);
+	choice->flags &= ~SYMBOL_CHECK;
+	if (sym2)
+		goto out;
+
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		sym2 = sym_check_sym_deps(sym);
+		if (sym2)
+			break;
+	}
+out:
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags &= ~SYMBOL_CHECK;
+
+	if (sym2 && sym_is_choice_value(sym2) &&
+	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+		sym2 = choice;
+
+	dep_stack_remove();
+
+	return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK) {
+		sym_check_print_recursive(sym);
+		return sym;
+	}
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
+
+	if (sym_is_choice_value(sym)) {
+		struct dep_stack stack;
+
+		/* for choice groups start the check with main choice symbol */
+		dep_stack_insert(&stack, sym);
+		prop = sym_get_choice_prop(sym);
+		sym2 = sym_check_deps(prop_get_symbol(prop));
+		dep_stack_remove();
+	} else if (sym_is_choice(sym)) {
+		sym2 = sym_check_choice_deps(sym);
+	} else {
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+		sym2 = sym_check_sym_deps(sym);
+		sym->flags &= ~SYMBOL_CHECK;
+	}
+
+	if (sym2 && sym2 == sym)
+		sym2 = NULL;
+
+	return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+	struct property *prop;
+	struct property **propp;
+
+	prop = malloc(sizeof(*prop));
+	memset(prop, 0, sizeof(*prop));
+	prop->type = type;
+	prop->sym = sym;
+	prop->file = current_file;
+	prop->lineno = zconf_lineno();
+
+	/* append property to the prop list of symbol */
+	if (sym) {
+		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+			;
+		*propp = prop;
+	}
+
+	return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+	if (prop->expr && (prop->expr->type == E_SYMBOL ||
+			   prop->expr->type == E_LIST))
+		return prop->expr->left.sym;
+	return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+	switch (type) {
+	case P_PROMPT:
+		return "prompt";
+	case P_ENV:
+		return "env";
+	case P_COMMENT:
+		return "comment";
+	case P_MENU:
+		return "menu";
+	case P_DEFAULT:
+		return "default";
+	case P_CHOICE:
+		return "choice";
+	case P_SELECT:
+		return "select";
+	case P_RANGE:
+		return "range";
+	case P_SYMBOL:
+		return "symbol";
+	case P_UNKNOWN:
+		break;
+	}
+	return "unknown";
+}
+
+static void prop_add_env(const char *env)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	char *p;
+
+	sym = current_entry->sym;
+	sym->flags |= SYMBOL_AUTO;
+	for_all_properties(sym, prop, P_ENV) {
+		sym2 = prop_get_symbol(prop);
+		if (strcmp(sym2->name, env))
+			menu_warn(current_entry, "redefining environment symbol from %s",
+				  sym2->name);
+		return;
+	}
+
+	prop = prop_alloc(P_ENV, sym);
+	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+	sym_env_list->right.sym = sym;
+
+	p = getenv(env);
+	if (p)
+		sym_add_default(sym, p);
+	else
+		menu_warn(current_entry, "environment variable %s undefined", env);
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/util.c b/qemu-0.15.x/roms/seabios/tools/kconfig/util.c
new file mode 100644
index 0000000..6330cc8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/util.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel at linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam at ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+	struct file *file;
+	const char *file_name = sym_expand_string_value(name);
+
+	for (file = file_list; file; file = file->next) {
+		if (!strcmp(name, file->name)) {
+			free((void *)file_name);
+			return file;
+		}
+	}
+
+	file = malloc(sizeof(*file));
+	memset(file, 0, sizeof(*file));
+	file->name = file_name;
+	file->next = file_list;
+	file_list = file;
+	return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+	struct symbol *sym, *env_sym;
+	struct expr *e;
+	struct file *file;
+	FILE *out;
+
+	if (!name)
+		name = ".kconfig.d";
+	out = fopen("..config.tmp", "w");
+	if (!out)
+		return 1;
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next) {
+		if (file->next)
+			fprintf(out, "\t%s \\\n", file->name);
+		else
+			fprintf(out, "\t%s\n", file->name);
+	}
+	fprintf(out, "\n%s: \\\n"
+		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+	expr_list_for_each_sym(sym_env_list, e, sym) {
+		struct property *prop;
+		const char *value;
+
+		prop = sym_get_env_prop(sym);
+		env_sym = prop_get_symbol(prop);
+		if (!env_sym)
+			continue;
+		value = getenv(env_sym->name);
+		if (!value)
+			value = "";
+		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+		fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+		fprintf(out, "endif\n");
+	}
+
+	fprintf(out, "\n$(deps_config): ;\n");
+	fclose(out);
+	rename("..config.tmp", name);
+	return 0;
+}
+
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+	struct gstr gs;
+	gs.s = malloc(sizeof(char) * 64);
+	gs.len = 64;
+	gs.max_width = 0;
+	strcpy(gs.s, "\0");
+	return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+	struct gstr gs;
+	gs.s = strdup(s);
+	gs.len = strlen(s) + 1;
+	gs.max_width = 0;
+	return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+	if (gs->s)
+		free(gs->s);
+	gs->s = NULL;
+	gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+	size_t l;
+	if (s) {
+		l = strlen(gs->s) + strlen(s) + 1;
+		if (l > gs->len) {
+			gs->s   = realloc(gs->s, l);
+			gs->len = l;
+		}
+		strcat(gs->s, s);
+	}
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+	va_list ap;
+	char s[10000]; /* big enough... */
+	va_start(ap, fmt);
+	vsnprintf(s, sizeof(s), fmt, ap);
+	str_append(gs, s);
+	va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+	return gs->s;
+}
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.gperf b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.gperf
new file mode 100644
index 0000000..c9e690e
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.gperf
@@ -0,0 +1,47 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+
+%%
+mainmenu,	T_MAINMENU,	TF_COMMAND
+menu,		T_MENU,		TF_COMMAND
+endmenu,	T_ENDMENU,	TF_COMMAND
+source,		T_SOURCE,	TF_COMMAND
+choice,		T_CHOICE,	TF_COMMAND
+endchoice,	T_ENDCHOICE,	TF_COMMAND
+comment,	T_COMMENT,	TF_COMMAND
+config,		T_CONFIG,	TF_COMMAND
+menuconfig,	T_MENUCONFIG,	TF_COMMAND
+help,		T_HELP,		TF_COMMAND
+if,		T_IF,		TF_COMMAND|TF_PARAM
+endif,		T_ENDIF,	TF_COMMAND
+depends,	T_DEPENDS,	TF_COMMAND
+optional,	T_OPTIONAL,	TF_COMMAND
+default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
+prompt,		T_PROMPT,	TF_COMMAND
+tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
+def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE
+bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
+boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
+def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
+int,		T_TYPE,		TF_COMMAND, S_INT
+hex,		T_TYPE,		TF_COMMAND, S_HEX
+string,		T_TYPE,		TF_COMMAND, S_STRING
+select,		T_SELECT,	TF_COMMAND
+range,		T_RANGE,	TF_COMMAND
+visible,	T_VISIBLE,	TF_COMMAND
+option,		T_OPTION,	TF_COMMAND
+on,		T_ON,		TF_PARAM
+modules,	T_OPT_MODULES,	TF_OPTION
+defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION
+env,		T_OPT_ENV,	TF_OPTION
+%%
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.hash.c_shipped b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.hash.c_shipped
new file mode 100644
index 0000000..4055d5d
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.hash.c_shipped
@@ -0,0 +1,245 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf at gnu.org>."
+#endif
+
+struct kconf_id;
+
+static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+/* maximum key range = 50, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 40,  5,
+       0,  0,  5, 52,  0, 20, 52, 52, 10, 20,
+       5,  0, 35, 52,  0, 30,  0, 15,  0, 52,
+      15, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("hex")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("string")];
+    char kconf_id_strings_str37[sizeof("visible")];
+    char kconf_id_strings_str41[sizeof("prompt")];
+    char kconf_id_strings_str42[sizeof("depends")];
+    char kconf_id_strings_str44[sizeof("bool")];
+    char kconf_id_strings_str46[sizeof("select")];
+    char kconf_id_strings_str47[sizeof("boolean")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+    char kconf_id_strings_str51[sizeof("source")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "env",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "config",
+    "def_tristate",
+    "hex",
+    "defconfig_list",
+    "if",
+    "int",
+    "modules",
+    "tristate",
+    "menu",
+    "comment",
+    "menuconfig",
+    "string",
+    "visible",
+    "prompt",
+    "depends",
+    "bool",
+    "select",
+    "boolean",
+    "mainmenu",
+    "source"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 32,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 51
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_OPT_ENV,	TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_HELP,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,		T_TYPE,		TF_COMMAND, S_HEX},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_INT},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_VISIBLE,	TF_COMMAND},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_DEPENDS,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,	T_MAINMENU,	TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51,		T_SOURCE,	TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.l b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.l
new file mode 100644
index 0000000..3dbaec1
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.l
@@ -0,0 +1,360 @@
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%option noinput
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+	text = malloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+	text = malloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+%}
+
+ws	[ \n\t]
+n	[A-Za-z0-9_]
+
+%%
+	int str = 0;
+	int ts, i;
+
+[ \t]*#.*\n	|
+[ \t]*\n	{
+	current_file->lineno++;
+	return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+	{
+	BEGIN(COMMAND);
+}
+
+.	{
+	unput(yytext[0]);
+	BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+	{n}+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	.
+	\n	{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+}
+
+<PARAM>{
+	"&&"	return T_AND;
+	"||"	return T_OR;
+	"("	return T_OPEN_PAREN;
+	")"	return T_CLOSE_PAREN;
+	"!"	return T_NOT;
+	"="	return T_EQUAL;
+	"!="	return T_UNEQUAL;
+	\"|\'	{
+		str = yytext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	---	/* ignore */
+	({n}|[-/.])+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	#.*	/* comment */
+	\\\n	current_file->lineno++;
+	.
+	<<EOF>> {
+		BEGIN(INITIAL);
+	}
+}
+
+<STRING>{
+	[^'"\\\n]+/\n	{
+		append_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	[^'"\\\n]+	{
+		append_string(yytext, yyleng);
+	}
+	\\.?/\n	{
+		append_string(yytext + 1, yyleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	\\.?	{
+		append_string(yytext + 1, yyleng - 1);
+	}
+	\'|\"	{
+		if (str == yytext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(yytext, 1);
+	}
+	\n	{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	<<EOF>>	{
+		BEGIN(INITIAL);
+	}
+}
+
+<HELP>{
+	[ \t]+	{
+		ts = 0;
+		for (i = 0; i < yyleng; i++) {
+			if (yytext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	[ \t]*\n/[^ \t\n] {
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	[ \t]*\n	{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	[^ \t\n].* {
+		while (yyleng) {
+			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+				break;
+			yyleng--;
+		}
+		append_string(yytext, yyleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	<<EOF>>	{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+}
+
+<<EOF>>	{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(yyin);
+	yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	yyin = zconf_fopen(name);
+	if (!yyin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = malloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+	current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+	struct file *file = file_lookup(name);
+	struct buffer *buf = malloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	yyin = zconf_fopen(file->name);
+	if (!yyin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
+		exit(1);
+	}
+	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	if (file->flags & FILE_BUSY) {
+		printf("%s:%d: do not source '%s' from itself\n",
+		       zconf_curname(), zconf_lineno(), name);
+		exit(1);
+	}
+	if (file->flags & FILE_SCANNED) {
+		printf("%s:%d: file '%s' is already sourced from '%s'\n",
+		       zconf_curname(), zconf_lineno(), name,
+		       file->parent->name);
+		exit(1);
+	}
+	file->flags |= FILE_BUSY;
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file->flags |= FILE_SCANNED;
+	current_file->flags &= ~FILE_BUSY;
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(yyin);
+		yy_delete_buffer(YY_CURRENT_BUFFER);
+		yy_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.tab.c_shipped b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.tab.c_shipped
new file mode 100644
index 0000000..4c5495e
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.tab.c_shipped
@@ -0,0 +1,2505 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse         zconfparse
+#define yylex           zconflex
+#define yyerror         zconferror
+#define yylval          zconflval
+#define yychar          zconfchar
+#define yydebug         zconfdebug
+#define yynerrs         zconfnerrs
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_TYPE = 274,
+     T_DEFAULT = 275,
+     T_SELECT = 276,
+     T_RANGE = 277,
+     T_VISIBLE = 278,
+     T_OPTION = 279,
+     T_ON = 280,
+     T_WORD = 281,
+     T_WORD_QUOTE = 282,
+     T_UNEQUAL = 283,
+     T_CLOSE_PAREN = 284,
+     T_OPEN_PAREN = 285,
+     T_EOL = 286,
+     T_OR = 287,
+     T_AND = 288,
+     T_EQUAL = 289,
+     T_NOT = 290
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	struct kconf_id *id;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  11
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   290
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  36
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  50
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  118
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  191
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   290
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     6,     8,    11,    13,    14,    17,    20,
+      23,    26,    31,    36,    40,    42,    44,    46,    48,    50,
+      52,    54,    56,    58,    60,    62,    64,    66,    68,    72,
+      75,    79,    82,    86,    89,    90,    93,    96,    99,   102,
+     105,   108,   112,   117,   122,   127,   133,   137,   138,   142,
+     143,   146,   150,   153,   155,   159,   160,   163,   166,   169,
+     172,   175,   180,   184,   187,   192,   193,   196,   200,   202,
+     206,   207,   210,   213,   216,   220,   224,   228,   230,   234,
+     235,   238,   241,   244,   248,   252,   255,   258,   261,   262,
+     265,   268,   271,   276,   277,   280,   283,   286,   287,   290,
+     292,   294,   297,   300,   303,   305,   308,   309,   312,   314,
+     318,   322,   326,   329,   333,   337,   339,   341,   342
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      37,     0,    -1,    81,    38,    -1,    38,    -1,    63,    39,
+      -1,    39,    -1,    -1,    39,    41,    -1,    39,    55,    -1,
+      39,    67,    -1,    39,    80,    -1,    39,    26,     1,    31,
+      -1,    39,    40,     1,    31,    -1,    39,     1,    31,    -1,
+      16,    -1,    18,    -1,    19,    -1,    21,    -1,    17,    -1,
+      22,    -1,    20,    -1,    23,    -1,    31,    -1,    61,    -1,
+      71,    -1,    44,    -1,    46,    -1,    69,    -1,    26,     1,
+      31,    -1,     1,    31,    -1,    10,    26,    31,    -1,    43,
+      47,    -1,    11,    26,    31,    -1,    45,    47,    -1,    -1,
+      47,    48,    -1,    47,    49,    -1,    47,    75,    -1,    47,
+      73,    -1,    47,    42,    -1,    47,    31,    -1,    19,    78,
+      31,    -1,    18,    79,    82,    31,    -1,    20,    83,    82,
+      31,    -1,    21,    26,    82,    31,    -1,    22,    84,    84,
+      82,    31,    -1,    24,    50,    31,    -1,    -1,    50,    26,
+      51,    -1,    -1,    34,    79,    -1,     7,    85,    31,    -1,
+      52,    56,    -1,    80,    -1,    53,    58,    54,    -1,    -1,
+      56,    57,    -1,    56,    75,    -1,    56,    73,    -1,    56,
+      31,    -1,    56,    42,    -1,    18,    79,    82,    31,    -1,
+      19,    78,    31,    -1,    17,    31,    -1,    20,    26,    82,
+      31,    -1,    -1,    58,    41,    -1,    14,    83,    81,    -1,
+      80,    -1,    59,    62,    60,    -1,    -1,    62,    41,    -1,
+      62,    67,    -1,    62,    55,    -1,     3,    79,    81,    -1,
+       4,    79,    31,    -1,    64,    76,    74,    -1,    80,    -1,
+      65,    68,    66,    -1,    -1,    68,    41,    -1,    68,    67,
+      -1,    68,    55,    -1,     6,    79,    31,    -1,     9,    79,
+      31,    -1,    70,    74,    -1,    12,    31,    -1,    72,    13,
+      -1,    -1,    74,    75,    -1,    74,    31,    -1,    74,    42,
+      -1,    16,    25,    83,    31,    -1,    -1,    76,    77,    -1,
+      76,    31,    -1,    23,    82,    -1,    -1,    79,    82,    -1,
+      26,    -1,    27,    -1,     5,    31,    -1,     8,    31,    -1,
+      15,    31,    -1,    31,    -1,    81,    31,    -1,    -1,    14,
+      83,    -1,    84,    -1,    84,    34,    84,    -1,    84,    28,
+      84,    -1,    30,    83,    29,    -1,    35,    83,    -1,    83,
+      32,    83,    -1,    83,    33,    83,    -1,    26,    -1,    27,
+      -1,    -1,    26,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   108,   108,   108,   110,   110,   112,   114,   115,   116,
+     117,   118,   119,   123,   127,   127,   127,   127,   127,   127,
+     127,   127,   131,   132,   133,   134,   135,   136,   140,   141,
+     147,   155,   161,   169,   179,   181,   182,   183,   184,   185,
+     186,   189,   197,   203,   213,   219,   225,   228,   230,   241,
+     242,   247,   256,   261,   269,   272,   274,   275,   276,   277,
+     278,   281,   287,   298,   304,   314,   316,   321,   329,   337,
+     340,   342,   343,   344,   349,   356,   363,   368,   376,   379,
+     381,   382,   383,   386,   394,   401,   408,   414,   421,   423,
+     424,   425,   428,   436,   438,   439,   442,   449,   451,   456,
+     457,   460,   461,   462,   466,   467,   470,   471,   474,   475,
+     476,   477,   478,   479,   480,   483,   484,   487,   488
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+  "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
+  "common_stmt", "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
+  "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
+  "comment", "comment_stmt", "help_start", "help", "depends_list",
+  "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
+  "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    36,    37,    37,    38,    38,    39,    39,    39,    39,
+      39,    39,    39,    39,    40,    40,    40,    40,    40,    40,
+      40,    40,    41,    41,    41,    41,    41,    41,    42,    42,
+      43,    44,    45,    46,    47,    47,    47,    47,    47,    47,
+      47,    48,    48,    48,    48,    48,    49,    50,    50,    51,
+      51,    52,    53,    54,    55,    56,    56,    56,    56,    56,
+      56,    57,    57,    57,    57,    58,    58,    59,    60,    61,
+      62,    62,    62,    62,    63,    64,    65,    66,    67,    68,
+      68,    68,    68,    69,    70,    71,    72,    73,    74,    74,
+      74,    74,    75,    76,    76,    76,    77,    78,    78,    79,
+      79,    80,    80,    80,    81,    81,    82,    82,    83,    83,
+      83,    83,    83,    83,    83,    84,    84,    85,    85
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     2,     1,     2,     1,     0,     2,     2,     2,
+       2,     4,     4,     3,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     3,     2,
+       3,     2,     3,     2,     0,     2,     2,     2,     2,     2,
+       2,     3,     4,     4,     4,     5,     3,     0,     3,     0,
+       2,     3,     2,     1,     3,     0,     2,     2,     2,     2,
+       2,     4,     3,     2,     4,     0,     2,     3,     1,     3,
+       0,     2,     2,     2,     3,     3,     3,     1,     3,     0,
+       2,     2,     2,     3,     3,     2,     2,     2,     0,     2,
+       2,     2,     4,     0,     2,     2,     2,     0,     2,     1,
+       1,     2,     2,     2,     1,     2,     0,     2,     1,     3,
+       3,     3,     2,     3,     3,     1,     1,     0,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       6,     0,   104,     0,     3,     0,     6,     6,    99,   100,
+       0,     1,     0,     0,     0,     0,   117,     0,     0,     0,
+       0,     0,     0,    14,    18,    15,    16,    20,    17,    19,
+      21,     0,    22,     0,     7,    34,    25,    34,    26,    55,
+      65,     8,    70,    23,    93,    79,     9,    27,    88,    24,
+      10,     0,   105,     2,    74,    13,     0,   101,     0,   118,
+       0,   102,     0,     0,     0,   115,   116,     0,     0,     0,
+     108,   103,     0,     0,     0,     0,     0,     0,     0,    88,
+       0,     0,    75,    83,    51,    84,    30,    32,     0,   112,
+       0,     0,    67,     0,     0,    11,    12,     0,     0,     0,
+       0,    97,     0,     0,     0,    47,     0,    40,    39,    35,
+      36,     0,    38,    37,     0,     0,    97,     0,    59,    60,
+      56,    58,    57,    66,    54,    53,    71,    73,    69,    72,
+      68,   106,    95,     0,    94,    80,    82,    78,    81,    77,
+      90,    91,    89,   111,   113,   114,   110,   109,    29,    86,
+       0,   106,     0,   106,   106,   106,     0,     0,     0,    87,
+      63,   106,     0,   106,     0,    96,     0,     0,    41,    98,
+       0,     0,   106,    49,    46,    28,     0,    62,     0,   107,
+      92,    42,    43,    44,     0,     0,    48,    61,    64,    45,
+      50
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     3,     4,     5,    33,    34,   108,    35,    36,    37,
+      38,    74,   109,   110,   157,   186,    39,    40,   124,    41,
+      76,   120,    77,    42,   128,    43,    78,     6,    44,    45,
+     137,    46,    80,    47,    48,    49,   111,   112,    81,   113,
+      79,   134,   152,   153,    50,     7,   165,    69,    70,    60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -90
+static const yytype_int16 yypact[] =
+{
+       4,    42,   -90,    96,   -90,   111,   -90,    15,   -90,   -90,
+      75,   -90,    82,    42,   104,    42,   110,   107,    42,   115,
+     125,    -4,   121,   -90,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   162,   -90,   163,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   139,   -90,   -90,   138,   -90,   142,   -90,   143,   -90,
+     152,   -90,   164,   167,   168,   -90,   -90,    -4,    -4,    77,
+     -18,   -90,   177,   185,    33,    71,   195,   247,   236,    -2,
+     236,   171,   -90,   -90,   -90,   -90,   -90,   -90,    41,   -90,
+      -4,    -4,   138,    97,    97,   -90,   -90,   186,   187,   194,
+      42,    42,    -4,   196,    97,   -90,   219,   -90,   -90,   -90,
+     -90,   210,   -90,   -90,   204,    42,    42,   199,   -90,   -90,
+     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   222,   -90,   223,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   -90,   -90,   -90,   215,   -90,   -90,   -90,   -90,   -90,
+      -4,   222,   228,   222,    -5,   222,    97,    35,   229,   -90,
+     -90,   222,   232,   222,    -4,   -90,   135,   233,   -90,   -90,
+     234,   235,   222,   240,   -90,   -90,   237,   -90,   239,   -13,
+     -90,   -90,   -90,   -90,   244,    42,   -90,   -90,   -90,   -90,
+     -90
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -90,   -90,   269,   271,   -90,    23,   -70,   -90,   -90,   -90,
+     -90,   243,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -48,
+     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,
+     -90,   -20,   -90,   -90,   -90,   -90,   -90,   206,   205,   -68,
+     -90,   -90,   169,    -1,    27,    -7,   118,   -66,   -89,   -90
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -86
+static const yytype_int16 yytable[] =
+{
+      10,    88,    89,    54,   146,   147,   119,     1,   122,   164,
+      93,   141,    56,   142,    58,   156,    94,    62,     1,    90,
+      91,   131,    65,    66,   144,   145,    67,    90,    91,   132,
+     127,    68,   136,   -31,    97,     2,   154,   -31,   -31,   -31,
+     -31,   -31,   -31,   -31,   -31,    98,    52,   -31,   -31,    99,
+     -31,   100,   101,   102,   103,   104,   -31,   105,   129,   106,
+     138,   173,    92,   141,   107,   142,   174,   172,     8,     9,
+     143,   -33,    97,    90,    91,   -33,   -33,   -33,   -33,   -33,
+     -33,   -33,   -33,    98,   166,   -33,   -33,    99,   -33,   100,
+     101,   102,   103,   104,   -33,   105,    11,   106,   179,   151,
+     123,   126,   107,   135,   125,   130,     2,   139,     2,    90,
+      91,    -5,    12,    55,   161,    13,    14,    15,    16,    17,
+      18,    19,    20,    65,    66,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    57,    59,    31,    61,    -4,
+      12,    63,    32,    13,    14,    15,    16,    17,    18,    19,
+      20,    64,    71,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    72,    73,    31,   180,    90,    91,    52,
+      32,   -85,    97,    82,    83,   -85,   -85,   -85,   -85,   -85,
+     -85,   -85,   -85,    84,   190,   -85,   -85,    99,   -85,   -85,
+     -85,   -85,   -85,   -85,   -85,    85,    97,   106,    86,    87,
+     -52,   -52,   140,   -52,   -52,   -52,   -52,    98,    95,   -52,
+     -52,    99,   114,   115,   116,   117,    96,   148,   149,   150,
+     158,   106,   155,   159,    97,   163,   118,   -76,   -76,   -76,
+     -76,   -76,   -76,   -76,   -76,   160,   164,   -76,   -76,    99,
+      13,    14,    15,    16,    17,    18,    19,    20,    91,   106,
+      21,    22,    14,    15,   140,    17,    18,    19,    20,   168,
+     175,    21,    22,   177,   181,   182,   183,    32,   187,   167,
+     188,   169,   170,   171,   185,   189,    53,    51,    32,   176,
+      75,   178,   121,     0,   133,   162,     0,     0,     0,     0,
+     184
+};
+
+static const yytype_int16 yycheck[] =
+{
+       1,    67,    68,    10,    93,    94,    76,     3,    76,    14,
+      28,    81,    13,    81,    15,   104,    34,    18,     3,    32,
+      33,    23,    26,    27,    90,    91,    30,    32,    33,    31,
+      78,    35,    80,     0,     1,    31,   102,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    31,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    78,    26,
+      80,    26,    69,   133,    31,   133,    31,   156,    26,    27,
+      29,     0,     1,    32,    33,     4,     5,     6,     7,     8,
+       9,    10,    11,    12,   150,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,     0,    26,   164,   100,
+      77,    78,    31,    80,    77,    78,    31,    80,    31,    32,
+      33,     0,     1,    31,   115,     4,     5,     6,     7,     8,
+       9,    10,    11,    26,    27,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    31,    26,    26,    31,     0,
+       1,    26,    31,     4,     5,     6,     7,     8,     9,    10,
+      11,    26,    31,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,     1,     1,    26,    31,    32,    33,    31,
+      31,     0,     1,    31,    31,     4,     5,     6,     7,     8,
+       9,    10,    11,    31,   185,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    31,     1,    26,    31,    31,
+       5,     6,    31,     8,     9,    10,    11,    12,    31,    14,
+      15,    16,    17,    18,    19,    20,    31,    31,    31,    25,
+       1,    26,    26,    13,     1,    26,    31,     4,     5,     6,
+       7,     8,     9,    10,    11,    31,    14,    14,    15,    16,
+       4,     5,     6,     7,     8,     9,    10,    11,    33,    26,
+      14,    15,     5,     6,    31,     8,     9,    10,    11,    31,
+      31,    14,    15,    31,    31,    31,    31,    31,    31,   151,
+      31,   153,   154,   155,    34,    31,     7,     6,    31,   161,
+      37,   163,    76,    -1,    79,   116,    -1,    -1,    -1,    -1,
+     172
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,    31,    37,    38,    39,    63,    81,    26,    27,
+      79,     0,     1,     4,     5,     6,     7,     8,     9,    10,
+      11,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    26,    31,    40,    41,    43,    44,    45,    46,    52,
+      53,    55,    59,    61,    64,    65,    67,    69,    70,    71,
+      80,    39,    31,    38,    81,    31,    79,    31,    79,    26,
+      85,    31,    79,    26,    26,    26,    27,    30,    35,    83,
+      84,    31,     1,     1,    47,    47,    56,    58,    62,    76,
+      68,    74,    31,    31,    31,    31,    31,    31,    83,    83,
+      32,    33,    81,    28,    34,    31,    31,     1,    12,    16,
+      18,    19,    20,    21,    22,    24,    26,    31,    42,    48,
+      49,    72,    73,    75,    17,    18,    19,    20,    31,    42,
+      57,    73,    75,    41,    54,    80,    41,    55,    60,    67,
+      80,    23,    31,    74,    77,    41,    55,    66,    67,    80,
+      31,    42,    75,    29,    83,    83,    84,    84,    31,    31,
+      25,    79,    78,    79,    83,    26,    84,    50,     1,    13,
+      31,    79,    78,    26,    14,    82,    83,    82,    31,    82,
+      82,    82,    84,    26,    31,    31,    82,    31,    82,    83,
+      31,    31,    31,    31,    82,    34,    51,    31,    31,    31,
+      79
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 53: /* "choice_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+      case 59: /* "if_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+      case 65: /* "menu_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+
+      default:
+	break;
+    }
+}
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 10:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 11:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+    break;
+
+  case 12:
+
+    {
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+;}
+    break;
+
+  case 13:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 28:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+    break;
+
+  case 29:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 30:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 31:
+
+    {
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 32:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 33:
+
+    {
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 41:
+
+    {
+	menu_set_type((yyvsp[(1) - (3)].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[(1) - (3)].id)->stype);
+;}
+    break;
+
+  case 42:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 43:
+
+    {
+	menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+	if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+		menu_set_type((yyvsp[(1) - (4)].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[(1) - (4)].id)->stype);
+;}
+    break;
+
+  case 44:
+
+    {
+	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 45:
+
+    {
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 48:
+
+    {
+	struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+	else
+		zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+	free((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 49:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 50:
+
+    { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+    break;
+
+  case 51:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+	sym->flags |= SYMBOL_AUTO;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 52:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 53:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 61:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 62:
+
+    {
+	if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+		menu_set_type((yyvsp[(1) - (3)].id)->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			(yyvsp[(1) - (3)].id)->stype);
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 63:
+
+    {
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 64:
+
+    {
+	if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 67:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep((yyvsp[(2) - (3)].expr));
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 68:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 74:
+
+    {
+	menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+;}
+    break;
+
+  case 75:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 76:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 77:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 83:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+	zconf_nextfile((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 84:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 85:
+
+    {
+	menu_end_entry();
+;}
+    break;
+
+  case 86:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+;}
+    break;
+
+  case 87:
+
+    {
+	current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+    break;
+
+  case 92:
+
+    {
+	menu_add_dep((yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 96:
+
+    {
+	menu_add_visibility((yyvsp[(2) - (2)].expr));
+;}
+    break;
+
+  case 98:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+    break;
+
+  case 101:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 102:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 103:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 107:
+
+    { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+    break;
+
+  case 108:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+    break;
+
+  case 109:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 110:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 111:
+
+    { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+    break;
+
+  case 112:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+    break;
+
+  case 113:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 114:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 115:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 116:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 117:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+
+
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (yymsg);
+	  }
+	else
+	  {
+	    yyerror (YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	_menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+        }
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "\nchoice\n");
+	else
+		fprintf(out, "\nconfig %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
diff --git a/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.y b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.y
new file mode 100644
index 0000000..49fb4ab
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/kconfig/zconf.y
@@ -0,0 +1,749 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 30
+
+%union
+{
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		$$->file->name, $$->lineno);
+	if (current_menu == $$)
+		menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
+%%
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
+
+stmt_list:
+	  /* empty */
+	| stmt_list common_stmt
+	| stmt_list choice_stmt
+	| stmt_list menu_stmt
+	| stmt_list end			{ zconf_error("unexpected end statement"); }
+	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
+	| stmt_list option_name error T_EOL
+{
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+	| stmt_list error T_EOL		{ zconf_error("invalid statement"); }
+;
+
+option_name:
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
+;
+
+common_stmt:
+	  T_EOL
+	| if_stmt
+	| comment_stmt
+	| config_stmt
+	| menuconfig_stmt
+	| source_stmt
+;
+
+option_error:
+	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); }
+	| error T_EOL			{ zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+	  /* empty */
+	| config_option_list config_option
+	| config_option_list symbol_option
+	| config_option_list depends
+	| config_option_list help
+	| config_option_list option_error
+	| config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+	menu_add_expr(P_DEFAULT, $2, $3);
+	if ($1->stype != S_UNKNOWN)
+		menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+	  /* empty */
+	| symbol_option_list T_WORD symbol_option_arg
+{
+	struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, $3);
+	else
+		zconfprint("warning: ignoring unknown option %s", $2);
+	free($2);
+};
+
+symbol_option_arg:
+	  /* empty */		{ $$ = NULL; }
+	| T_EQUAL prompt	{ $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+	struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+	sym->flags |= SYMBOL_AUTO;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+	$$ = menu_add_menu();
+};
+
+choice_end: end
+{
+	if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+	  /* empty */
+	| choice_option_list choice_option
+	| choice_option_list depends
+	| choice_option_list help
+	| choice_option_list T_EOL
+	| choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+		menu_set_type($1->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			$1->stype);
+	} else
+		YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+	if ($1->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+};
+
+choice_block:
+	  /* empty */
+	| choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep($2);
+	$$ = menu_add_menu();
+};
+
+if_end: end
+{
+	if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+	  /* empty */
+	| if_block common_stmt
+	| if_block menu_stmt
+	| if_block choice_stmt
+;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+	menu_add_prompt(P_MENU, $2, NULL);
+};
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu visibility_list depends_list
+{
+	$$ = menu_add_menu();
+};
+
+menu_end: end
+{
+	if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+	  /* empty */
+	| menu_block common_stmt
+	| menu_block menu_stmt
+	| menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+	zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+	menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+	current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+	  /* empty */
+	| depends_list depends
+	| depends_list T_EOL
+	| depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+	menu_add_dep($3);
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* visibility option */
+
+visibility_list:
+	  /* empty */
+	| visibility_list visible
+	| visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+	menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+	  /* empty */
+	| prompt if_expr
+{
+	menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt:	  T_WORD
+	| T_WORD_QUOTE
+;
+
+end:	  T_ENDMENU T_EOL	{ $$ = $1; }
+	| T_ENDCHOICE T_EOL	{ $$ = $1; }
+	| T_ENDIF T_EOL		{ $$ = $1; }
+;
+
+nl:
+	  T_EOL
+	| nl T_EOL
+;
+
+if_expr:  /* empty */			{ $$ = NULL; }
+	| T_IF expr			{ $$ = $2; }
+;
+
+expr:	  symbol				{ $$ = expr_alloc_symbol($1); }
+	| symbol T_EQUAL symbol			{ $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+	| symbol T_UNEQUAL symbol		{ $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+	| T_OPEN_PAREN expr T_CLOSE_PAREN	{ $$ = $2; }
+	| T_NOT expr				{ $$ = expr_alloc_one(E_NOT, $2); }
+	| expr T_OR expr			{ $$ = expr_alloc_two(E_OR, $1, $3); }
+	| expr T_AND expr			{ $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
+	| T_WORD_QUOTE	{ $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */			{ $$ = NULL; }
+	| T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	_menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+        }
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "\nchoice\n");
+	else
+		fprintf(out, "\nconfig %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/qemu-0.15.x/roms/seabios/tools/layoutrom.py b/qemu-0.15.x/roms/seabios/tools/layoutrom.py
new file mode 100755
index 0000000..d2ba674
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/layoutrom.py
@@ -0,0 +1,579 @@
+#!/usr/bin/env python
+# Script to analyze code and arrange ld sections.
+#
+# Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT!  This is an autogenerated file.  See tools/layoutrom.py. */
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH("i386")
+SECTIONS
+{
+"""
+COMMONTRAILER = """
+
+        /* Discard regular data sections to force a link error if
+         * code attempts to access data not marked with VAR16 (or other
+         * appropriate macro)
+         */
+        /DISCARD/ : {
+                *(.text*) *(.data*) *(.bss*) *(.rodata*)
+                *(COMMON) *(.discard*) *(.eh_frame)
+                }
+}
+"""
+
+
+######################################################################
+# Determine section locations
+######################################################################
+
+# Align 'pos' to 'alignbytes' offset
+def alignpos(pos, alignbytes):
+    mask = alignbytes - 1
+    return (pos + mask) & ~mask
+
+# Determine the final addresses for a list of sections that end at an
+# address.
+def setSectionsStart(sections, endaddr, minalign=1):
+    totspace = 0
+    for section in sections:
+        if section.align > minalign:
+            minalign = section.align
+        totspace = alignpos(totspace, section.align) + section.size
+    startaddr = (endaddr - totspace) / minalign * minalign
+    curaddr = startaddr
+    # out = [(addr, sectioninfo), ...]
+    out = []
+    for section in sections:
+        curaddr = alignpos(curaddr, section.align)
+        section.finalloc = curaddr
+        curaddr += section.size
+    return startaddr
+
+# The 16bit code can't exceed 64K of space.
+BUILD_BIOS_ADDR = 0xf0000
+BUILD_BIOS_SIZE = 0x10000
+
+# Layout the 16bit code.  This ensures sections with fixed offset
+# requirements are placed in the correct location.  It also places the
+# 16bit code as high as possible in the f-segment.
+def fitSections(sections, fillsections):
+    # fixedsections = [(addr, section), ...]
+    fixedsections = []
+    for section in sections:
+        if section.name.startswith('.fixedaddr.'):
+            addr = int(section.name[11:], 16)
+            section.finalloc = addr
+            fixedsections.append((addr, section))
+            if section.align != 1:
+                print "Error: Fixed section %s has non-zero alignment (%d)" % (
+                    section.name, section.align)
+                sys.exit(1)
+    fixedsections.sort()
+    firstfixed = fixedsections[0][0]
+
+    # Find freespace in fixed address area
+    # fixedAddr = [(freespace, section), ...]
+    fixedAddr = []
+    for i in range(len(fixedsections)):
+        fixedsectioninfo = fixedsections[i]
+        addr, section = fixedsectioninfo
+        if i == len(fixedsections) - 1:
+            nextaddr = BUILD_BIOS_SIZE
+        else:
+            nextaddr = fixedsections[i+1][0]
+        avail = nextaddr - addr - section.size
+        fixedAddr.append((avail, section))
+    fixedAddr.sort()
+
+    # Attempt to fit other sections into fixed area
+    canrelocate = [(section.size, section.align, section.name, section)
+                   for section in fillsections]
+    canrelocate.sort()
+    canrelocate = [section for size, align, name, section in canrelocate]
+    totalused = 0
+    for freespace, fixedsection in fixedAddr:
+        addpos = fixedsection.finalloc + fixedsection.size
+        totalused += fixedsection.size
+        nextfixedaddr = addpos + freespace
+#        print "Filling section %x uses %d, next=%x, available=%d" % (
+#            fixedsection.finalloc, fixedsection.size, nextfixedaddr, freespace)
+        while 1:
+            canfit = None
+            for fitsection in canrelocate:
+                if addpos + fitsection.size > nextfixedaddr:
+                    # Can't fit and nothing else will fit.
+                    break
+                fitnextaddr = alignpos(addpos, fitsection.align) + fitsection.size
+#                print "Test %s - %x vs %x" % (
+#                    fitsection.name, fitnextaddr, nextfixedaddr)
+                if fitnextaddr > nextfixedaddr:
+                    # This item can't fit.
+                    continue
+                canfit = (fitnextaddr, fitsection)
+            if canfit is None:
+                break
+            # Found a section that can fit.
+            fitnextaddr, fitsection = canfit
+            canrelocate.remove(fitsection)
+            fitsection.finalloc = addpos
+            addpos = fitnextaddr
+            totalused += fitsection.size
+#            print "    Adding %s (size %d align %d) pos=%x avail=%d" % (
+#                fitsection[2], fitsection[0], fitsection[1]
+#                , fitnextaddr, nextfixedaddr - fitnextaddr)
+
+    # Report stats
+    total = BUILD_BIOS_SIZE-firstfixed
+    slack = total - totalused
+    print ("Fixed space: 0x%x-0x%x  total: %d  slack: %d"
+           "  Percent slack: %.1f%%" % (
+            firstfixed, BUILD_BIOS_SIZE, total, slack,
+            (float(slack) / total) * 100.0))
+
+    return firstfixed
+
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, category, prefix):
+    return [section for section in sections
+            if section.category == category and section.name.startswith(prefix)]
+
+def doLayout(sections):
+    # Determine 16bit positions
+    textsections = getSectionsPrefix(sections, '16', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '16', '.rodata.str1.1')
+                      + getSectionsPrefix(sections, '16', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '16', '.data16.')
+    fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.')
+
+    firstfixed = fitSections(fixedsections, textsections)
+    remsections = [s for s in textsections+rodatasections+datasections
+                   if s.finalloc is None]
+    code16_start = setSectionsStart(remsections, firstfixed)
+
+    # Determine 32seg positions
+    textsections = getSectionsPrefix(sections, '32seg', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '32seg', '.rodata.str1.1')
+                      +getSectionsPrefix(sections, '32seg', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '32seg', '.data32seg.')
+
+    code32seg_start = setSectionsStart(
+        textsections + rodatasections + datasections, code16_start)
+
+    # Determine 32flat runtime positions
+    textsections = getSectionsPrefix(sections, '32flat', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32flat', '.rodata')
+    datasections = getSectionsPrefix(sections, '32flat', '.data.')
+    bsssections = getSectionsPrefix(sections, '32flat', '.bss.')
+
+    code32flat_start = setSectionsStart(
+        textsections + rodatasections + datasections + bsssections
+        , code32seg_start + BUILD_BIOS_ADDR, 16)
+
+    # Determine 32flat init positions
+    textsections = getSectionsPrefix(sections, '32init', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32init', '.rodata')
+    datasections = getSectionsPrefix(sections, '32init', '.data.')
+    bsssections = getSectionsPrefix(sections, '32init', '.bss.')
+
+    code32init_start = setSectionsStart(
+        textsections + rodatasections + datasections + bsssections
+        , code32flat_start, 16)
+
+    # Print statistics
+    size16 = BUILD_BIOS_SIZE - code16_start
+    size32seg = code16_start - code32seg_start
+    size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
+    size32init = code32flat_start - code32init_start
+    print "16bit size:           %d" % size16
+    print "32bit segmented size: %d" % size32seg
+    print "32bit flat size:      %d" % size32flat
+    print "32bit flat init size: %d" % size32init
+
+
+######################################################################
+# Linker script output
+######################################################################
+
+# Write LD script includes for the given cross references
+def outXRefs(sections):
+    xrefs = {}
+    out = ""
+    for section in sections:
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if (symbol.section is None
+                or (symbol.section.fileid == section.fileid
+                    and symbol.name == reloc.symbolname)
+                or reloc.symbolname in xrefs):
+                continue
+            xrefs[reloc.symbolname] = 1
+            addr = symbol.section.finalloc + symbol.offset
+            if (section.fileid == '32flat'
+                and symbol.section.fileid in ('16', '32seg')):
+                addr += BUILD_BIOS_ADDR
+            out += "%s = 0x%x ;\n" % (reloc.symbolname, addr)
+    return out
+
+# Write LD script includes for the given sections using relative offsets
+def outRelSections(sections, startsym):
+    out = ""
+    for section in sections:
+        out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym)
+        if section.name == '.rodata.str1.1':
+            out += "_rodata = . ;\n"
+        out += "*(%s)\n" % (section.name,)
+    return out
+
+def getSectionsFile(sections, fileid, defaddr=0):
+    sections = [(section.finalloc, section)
+                for section in sections if section.fileid == fileid]
+    sections.sort()
+    sections = [section for addr, section in sections]
+    pos = defaddr
+    if sections:
+        pos = sections[0].finalloc
+    return sections, pos
+
+# Layout the 32bit segmented code.  This places the code as high as possible.
+def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat):
+    # Write 16bit linker script
+    sections16, code16_start = getSectionsFile(sections, '16')
+    output = open(out16, 'wb')
+    output.write(COMMONHEADER + outXRefs(sections16) + """
+    code16_start = 0x%x ;
+    .text16 code16_start : {
+""" % (code16_start)
+                 + outRelSections(sections16, 'code16_start')
+                 + """
+    }
+"""
+                 + COMMONTRAILER)
+    output.close()
+
+    # Write 32seg linker script
+    sections32seg, code32seg_start = getSectionsFile(
+        sections, '32seg', code16_start)
+    output = open(out32seg, 'wb')
+    output.write(COMMONHEADER + outXRefs(sections32seg) + """
+    code32seg_start = 0x%x ;
+    .text32seg code32seg_start : {
+""" % (code32seg_start)
+                 + outRelSections(sections32seg, 'code32seg_start')
+                 + """
+    }
+"""
+                 + COMMONTRAILER)
+    output.close()
+
+    # Write 32flat linker script
+    sections32flat, code32flat_start = getSectionsFile(
+        sections, '32flat', code32seg_start)
+    relocstr = ""
+    relocminalign = 0
+    if genreloc:
+        # Generate relocations
+        relocstr, size, relocminalign = genRelocs(sections)
+        code32flat_start -= size
+    output = open(out32flat, 'wb')
+    output.write(COMMONHEADER
+                 + outXRefs(sections32flat) + """
+    %s = 0x%x ;
+    _reloc_min_align = 0x%x ;
+    code32flat_start = 0x%x ;
+    .text code32flat_start : {
+""" % (entrysym.name,
+       entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
+       relocminalign, code32flat_start)
+                 + relocstr
+                 + """
+        code32init_start = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
+                                  , 'code32flat_start')
+                 + """
+        code32init_end = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
+                                  , 'code32flat_start')
+                 + """
+        . = ( 0x%x - code32flat_start ) ;
+        *(.text32seg)
+        . = ( 0x%x - code32flat_start ) ;
+        *(.text16)
+        code32flat_end = ABSOLUTE(.) ;
+    } :text
+""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
+                 + COMMONTRAILER
+                 + """
+ENTRY(%s)
+PHDRS
+{
+        text PT_LOAD AT ( code32flat_start ) ;
+}
+""" % (entrysym.name,))
+    output.close()
+
+
+######################################################################
+# Detection of init code
+######################################################################
+
+# Determine init section relocations
+def genRelocs(sections):
+    absrelocs = []
+    relrelocs = []
+    initrelocs = []
+    minalign = 16
+    for section in sections:
+        if section.category == '32init' and section.align > minalign:
+            minalign = section.align
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if symbol.section is None:
+                continue
+            relocpos = section.finalloc + reloc.offset
+            if (reloc.type == 'R_386_32' and section.category == '32init'
+                and symbol.section.category == '32init'):
+                # Absolute relocation
+                absrelocs.append(relocpos)
+            elif (reloc.type == 'R_386_PC32' and section.category == '32init'
+                  and symbol.section.category != '32init'):
+                # Relative relocation
+                relrelocs.append(relocpos)
+            elif (section.category != '32init'
+                  and symbol.section.category == '32init'):
+                # Relocation to the init section
+                if section.fileid in ('16', '32seg'):
+                    relocpos += BUILD_BIOS_ADDR
+                initrelocs.append(relocpos)
+    absrelocs.sort()
+    relrelocs.sort()
+    initrelocs.sort()
+    out = ("        _reloc_abs_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in absrelocs])
+           + "        _reloc_abs_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_rel_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in relrelocs])
+           + "        _reloc_rel_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_init_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,)
+                      for pos in initrelocs])
+           + "        _reloc_init_end = ABSOLUTE(.) ;\n")
+    return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign
+
+def markRuntime(section, sections):
+    if (section is None or not section.keep or section.category is not None
+        or '.init.' in section.name or section.fileid != '32flat'):
+        return
+    section.category = '32flat'
+    # Recursively mark all sections this section points to
+    for reloc in section.relocs:
+        markRuntime(reloc.symbol.section, sections)
+
+def findInit(sections):
+    # Recursively find and mark all "runtime" sections.
+    for section in sections:
+        if '.runtime.' in section.name or '.export.' in section.name:
+            markRuntime(section, sections)
+    for section in sections:
+        if section.category is not None:
+            continue
+        if section.fileid == '32flat':
+            section.category = '32init'
+        else:
+            section.category = section.fileid
+
+
+######################################################################
+# Section garbage collection
+######################################################################
+
+CFUNCPREFIX = [('_cfunc16_', 0), ('_cfunc32seg_', 1), ('_cfunc32flat_', 2)]
+
+# Find and keep the section associated with a symbol (if available).
+def keepsymbol(reloc, infos, pos, isxref):
+    symbolname = reloc.symbolname
+    mustbecfunc = 0
+    for symprefix, needpos in CFUNCPREFIX:
+        if symbolname.startswith(symprefix):
+            if needpos != pos:
+                return -1
+            symbolname = symbolname[len(symprefix):]
+            mustbecfunc = 1
+            break
+    symbol = infos[pos][1].get(symbolname)
+    if (symbol is None or symbol.section is None
+        or symbol.section.name.startswith('.discard.')):
+        return -1
+    isdestcfunc = (symbol.section.name.startswith('.text.')
+                   and not symbol.section.name.startswith('.text.asm.'))
+    if ((mustbecfunc and not isdestcfunc)
+        or (not mustbecfunc and isdestcfunc and isxref)):
+        return -1
+
+    reloc.symbol = symbol
+    keepsection(symbol.section, infos, pos)
+    return 0
+
+# Note required section, and recursively set all referenced sections
+# as required.
+def keepsection(section, infos, pos=0):
+    if section.keep:
+        # Already kept - nothing to do.
+        return
+    section.keep = 1
+    # Keep all sections that this section points to
+    for reloc in section.relocs:
+        ret = keepsymbol(reloc, infos, pos, 0)
+        if not ret:
+            continue
+        # Not in primary sections - it may be a cross 16/32 reference
+        ret = keepsymbol(reloc, infos, (pos+1)%3, 1)
+        if not ret:
+            continue
+        ret = keepsymbol(reloc, infos, (pos+2)%3, 1)
+        if not ret:
+            continue
+
+# Determine which sections are actually referenced and need to be
+# placed into the output file.
+def gc(info16, info32seg, info32flat):
+    # infos = ((sections16, symbols16), (sect32seg, sym32seg)
+    #          , (sect32flat, sym32flat))
+    infos = (info16, info32seg, info32flat)
+    # Start by keeping sections that are globally visible.
+    for section in info16[0]:
+        if section.name.startswith('.fixedaddr.') or '.export.' in section.name:
+            keepsection(section, infos)
+    return [section for section in info16[0]+info32seg[0]+info32flat[0]
+            if section.keep]
+
+
+######################################################################
+# Startup and input parsing
+######################################################################
+
+class Section:
+    name = size = alignment = fileid = relocs = None
+    finalloc = category = keep = None
+class Reloc:
+    offset = type = symbolname = symbol = None
+class Symbol:
+    name = offset = section = None
+
+# Read in output from objdump
+def parseObjDump(file, fileid):
+    # sections = [section, ...]
+    sections = []
+    sectionmap = {}
+    # symbols[symbolname] = symbol
+    symbols = {}
+
+    state = None
+    for line in file.readlines():
+        line = line.rstrip()
+        if line == 'Sections:':
+            state = 'section'
+            continue
+        if line == 'SYMBOL TABLE:':
+            state = 'symbol'
+            continue
+        if line.startswith('RELOCATION RECORDS FOR ['):
+            sectionname = line[24:-2]
+            if sectionname.startswith('.debug_'):
+                # Skip debugging sections (to reduce parsing time)
+                state = None
+                continue
+            state = 'reloc'
+            relocsection = sectionmap[sectionname]
+            continue
+
+        if state == 'section':
+            try:
+                idx, name, size, vma, lma, fileoff, align = line.split()
+                if align[:3] != '2**':
+                    continue
+                section = Section()
+                section.name = name
+                section.size = int(size, 16)
+                section.align = 2**int(align[3:])
+                section.fileid = fileid
+                section.relocs = []
+                sections.append(section)
+                sectionmap[name] = section
+            except ValueError:
+                pass
+            continue
+        if state == 'symbol':
+            try:
+                sectionname, size, name = line[17:].split()
+                symbol = Symbol()
+                symbol.size = int(size, 16)
+                symbol.offset = int(line[:8], 16)
+                symbol.name = name
+                symbol.section = sectionmap.get(sectionname)
+                symbols[name] = symbol
+            except ValueError:
+                pass
+            continue
+        if state == 'reloc':
+            try:
+                off, type, symbolname = line.split()
+                reloc = Reloc()
+                reloc.offset = int(off, 16)
+                reloc.type = type
+                reloc.symbolname = symbolname
+                reloc.symbol = symbols.get(symbolname)
+                if reloc.symbol is None:
+                    # Some binutils (2.20.1) give section name instead
+                    # of a symbol - create a dummy symbol.
+                    reloc.symbol = symbol = Symbol()
+                    symbol.size = 0
+                    symbol.offset = 0
+                    symbol.name = symbolname
+                    symbol.section = sectionmap.get(symbolname)
+                    symbols[symbolname] = symbol
+                relocsection.relocs.append(reloc)
+            except ValueError:
+                pass
+    return sections, symbols
+
+def main():
+    # Get output name
+    in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:]
+
+    # Read in the objdump information
+    infile16 = open(in16, 'rb')
+    infile32seg = open(in32seg, 'rb')
+    infile32flat = open(in32flat, 'rb')
+
+    # infoX = (sections, symbols)
+    info16 = parseObjDump(infile16, '16')
+    info32seg = parseObjDump(infile32seg, '32seg')
+    info32flat = parseObjDump(infile32flat, '32flat')
+
+    # Figure out which sections to keep.
+    sections = gc(info16, info32seg, info32flat)
+
+    # Separate 32bit flat into runtime and init parts
+    findInit(sections)
+
+    # Determine the final memory locations of each kept section.
+    doLayout(sections)
+
+    # Write out linker script files.
+    entrysym = info16[1]['post32']
+    genreloc = '_reloc_abs_start' in info32flat[1]
+    writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/readserial.py b/qemu-0.15.x/roms/seabios/tools/readserial.py
new file mode 100755
index 0000000..9c955c6
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/readserial.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+# Script that can read from a serial device and show timestamps.
+#
+# Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+#   tools/readserial.py /dev/ttyUSB0 115200
+
+import sys
+import time
+import select
+import optparse
+
+# Reset time counter after this much idle time.
+RESTARTINTERVAL = 60
+# Alter timing reports based on how much time would be spent writing
+# to serial.
+ADJUSTBAUD = 1
+# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
+# bits + 1 stop bit.
+BITSPERBYTE = 10
+
+def readserial(infile, logfile, baudrate):
+    lasttime = 0
+    byteadjust = 0.0
+    if ADJUSTBAUD:
+        byteadjust = float(BITSPERBYTE) / baudrate
+    while 1:
+        # Read data
+        try:
+            res = select.select([infile, sys.stdin], [], [])
+        except KeyboardInterrupt:
+            sys.stdout.write("\n")
+            break
+        if sys.stdin in res[0]:
+            # Got keyboard input - force reset on next serial input
+            sys.stdin.read(1)
+            lasttime = 0
+            if len(res[0]) == 1:
+                continue
+        d = infile.read(4096)
+        if not d:
+            break
+        datatime = time.time()
+
+        datatime -= len(d) * byteadjust
+
+        # Reset start time if no data for some time
+        if datatime - lasttime > RESTARTINTERVAL:
+            starttime = datatime
+            charcount = 0
+            isnewline = 1
+            msg = "\n\n======= %s (adjust=%d)\n" % (
+                time.asctime(time.localtime(datatime)), ADJUSTBAUD)
+            sys.stdout.write(msg)
+            logfile.write(msg)
+        lasttime = datatime
+
+        # Translate unprintable chars; add timestamps
+        out = ""
+        for c in d:
+            if isnewline:
+                delta = datatime - starttime - (charcount * byteadjust)
+                out += "%06.3f: " % delta
+                isnewline = 0
+            oc = ord(c)
+            charcount += 1
+            datatime += byteadjust
+            if oc == 0x0d:
+                continue
+            if oc == 0x00:
+                out += "<00>\n"
+                isnewline = 1
+                continue
+            if oc == 0x0a:
+                out += "\n"
+                isnewline = 1
+                continue
+            if oc < 0x20 or oc >= 0x7f and oc != 0x09:
+                out += "<%02x>" % oc
+                continue
+            out += c
+
+        sys.stdout.write(out)
+        sys.stdout.flush()
+        logfile.write(out)
+        logfile.flush()
+
+def main():
+    usage = "%prog [options] [<serialdevice> [<baud>]]"
+    opts = optparse.OptionParser(usage)
+    opts.add_option("-f", "--file",
+                    action="store_false", dest="serial", default=True,
+                    help="read from file instead of serialdevice")
+    opts.add_option("-n", "--no-adjust",
+                    action="store_false", dest="adjustbaud", default=True,
+                    help="don't adjust times by serial rate")
+    options, args = opts.parse_args()
+    serialport = 0
+    baud = 115200
+    if len(args) > 2:
+        opts.error("Too many arguments")
+    if len(args) > 0:
+        serialport = args[0]
+    if len(args) > 1:
+        baud = int(args[1])
+    global ADJUSTBAUD
+    ADJUSTBAUD=options.adjustbaud
+
+    if options.serial:
+        # Read from serial port
+        try:
+            import serial
+        except ImportError:
+            print """
+Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
+On Linux machines try: yum install pyserial
+Or: apt-get install python-serial
+"""
+            sys.exit(1)
+        ser = serial.Serial(serialport, baud, timeout=0)
+    else:
+        # Read from a file
+        ser = open(serialport, 'rb')
+        import fcntl
+        import os
+        fcntl.fcntl(ser, fcntl.F_SETFL
+                    , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+    logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
+    f = open(logname, 'wb')
+    readserial(ser, f, baud)
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/tools/test-gcc.sh b/qemu-0.15.x/roms/seabios/tools/test-gcc.sh
new file mode 100755
index 0000000..ce3497b
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/test-gcc.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Script to test if gcc "-fwhole-program" works properly.
+
+mkdir -p out
+TMPFILE1=out/tmp_testcompile1.c
+TMPFILE1o=out/tmp_testcompile1.o
+TMPFILE2=out/tmp_testcompile2.c
+TMPFILE2o=out/tmp_testcompile2.o
+TMPFILE3o=out/tmp_testcompile3.o
+
+# Test for "-fwhole-program".  Older versions of gcc (pre v4.1) don't
+# support the whole-program optimization - detect that.
+$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+    echo "  Working around no -fwhole-program" > /dev/fd/2
+    echo 2
+    exit 0
+fi
+
+# Test if "visible" variables and functions are marked global.  On
+# OpenSuse 10.3 "visible" variables declared with "extern" first
+# aren't marked as global in the resulting assembler.  On Ubuntu 7.10
+# "visible" functions aren't marked as global in the resulting
+# assembler.
+cat - > $TMPFILE1 <<EOF
+void __attribute__((externally_visible)) t1() { }
+extern unsigned char v1;
+unsigned char v1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
+EOF
+$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
+cat - > $TMPFILE2 <<EOF
+void t1();
+extern unsigned char v1;
+int __attribute__((externally_visible)) main() { t1(); return v1; }
+EOF
+$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
+$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+    echo "  Working around non-functional -fwhole-program" > /dev/fd/2
+    echo 2
+    exit 0
+fi
+
+# Test if "-combine" works.  On Ubuntu 8.04 the compiler doesn't work
+# correctly with combine and the "struct bregs" register due to the
+# anonymous unions and structs.  On Fedora Core 12 the compiler throws
+# an internal compiler error when multiple files access global
+# variables with debugging enabled.
+cat - > $TMPFILE1 <<EOF
+// Look for anonymous union/struct failure
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+// Look for global variable failure.
+struct s1_s { int v; } g1;
+void __attribute__((externally_visible)) func2() {
+    struct s1_s *l1 = &g1;
+    l1->v=0;
+}
+EOF
+cat - > $TMPFILE2 <<EOF
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+extern struct s1_s g1;
+void func3() {
+    &g1;
+}
+EOF
+$CC -O -g -fwhole-program -combine -c $TMPFILE1 $TMPFILE2 -o $TMPFILE1o > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+    echo 0
+else
+    echo "  Working around non-functional -combine" > /dev/fd/2
+    echo 1
+fi
+
+# Also, on several compilers, -combine fails if code is emitted with a
+# reference to an extern variable that is later found to be externally
+# visible - the compiler does not mark those variables as global.
+# This is being worked around by ordering the compile objects to avoid
+# this case.
+
+# Also, the Ubuntu 8.04 compiler has a bug causing corruption when the
+# "ebp" register is clobberred in an "asm" statement.  The code has
+# been modified to not clobber "ebp" - no test is available yet.
+
+rm -f $TMPFILE1 $TMPFILE1o $TMPFILE2 $TMPFILE2o $TMPFILE3o
diff --git a/qemu-0.15.x/roms/seabios/tools/transdump.py b/qemu-0.15.x/roms/seabios/tools/transdump.py
new file mode 100755
index 0000000..4caaeb7
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/tools/transdump.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# This script is useful for taking the output of memdump() and
+# converting it back into binary output.  This can be useful, for
+# example, when one wants to push that data into other tools like
+# objdump or hexdump.
+#
+# (C) Copyright 2010 Kevin O'Connor <kevin at koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+def unhex(str):
+    return int(str, 16)
+
+def parseMem(filehdl):
+    mem = []
+    for line in filehdl:
+        parts = line.split(':')
+        if len(parts) < 2:
+            continue
+        try:
+            vaddr = unhex(parts[0])
+            parts = parts[1].split()
+            mem.extend([unhex(v) for v in parts])
+        except ValueError:
+            continue
+    return mem
+
+def printUsage():
+    sys.stderr.write("Usage:\n %s <file | ->\n"
+                     % (sys.argv[0],))
+    sys.exit(1)
+
+def main():
+    if len(sys.argv) != 2:
+        printUsage()
+    filename = sys.argv[1]
+    if filename == '-':
+        filehdl = sys.stdin
+    else:
+        filehdl = open(filename, 'r')
+    mem = parseMem(filehdl)
+    for i in mem:
+        sys.stdout.write(struct.pack("<I", i))
+
+if __name__ == '__main__':
+    main()
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/clext.c b/qemu-0.15.x/roms/seabios/vgasrc/clext.c
new file mode 100644
index 0000000..36ccad3
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/clext.c
@@ -0,0 +1,390 @@
+//  QEMU Cirrus CLGD 54xx VGABIOS Extension.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//  Copyright (c) 2004 Makoto Suzuki (suzu)
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "vgatables.h" // cirrus_init
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+struct cirrus_mode_s {
+    /* + 0 */
+    u16 mode;
+    u16 width;
+    u16 height;
+    u16 depth;
+    /* + 8 */
+    u16 hidden_dac; /* 0x3c6 */
+    u16 *seq; /* 0x3c4 */
+    u16 *graph; /* 0x3ce */
+    u16 *crtc; /* 0x3d4 */
+    /* +16 */
+    u8 bitsperpixel;
+    u8 vesacolortype;
+    u8 vesaredmask;
+    u8 vesaredpos;
+    u8 vesagreenmask;
+    u8 vesagreenpos;
+    u8 vesabluemask;
+    u8 vesabluepos;
+    /* +24 */
+    u8 vesareservedmask;
+    u8 vesareservedpos;
+};
+
+/* VGA */
+static u16 cseq_vga[] VAR16 = {0x0007,0xffff};
+static u16 cgraph_vga[] VAR16 = {0x0009,0x000a,0x000b,0xffff};
+static u16 ccrtc_vga[] VAR16 = {0x001a,0x001b,0x001d,0xffff};
+
+/* extensions */
+static u16 cgraph_svgacolor[] VAR16 = {
+    0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
+    0x0009,0x000a,0x000b,
+    0xffff
+};
+/* 640x480x8 */
+static u16 cseq_640x480x8[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+    0x580b,0x580c,0x580d,0x580e,
+    0x0412,0x0013,0x2017,
+    0x331b,0x331c,0x331d,0x331e,
+    0xffff
+};
+static u16 ccrtc_640x480x8[] VAR16 = {
+    0x2c11,
+    0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+    0x4009,0x000c,0x000d,
+    0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 640x480x16 */
+static u16 cseq_640x480x16[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+    0x580b,0x580c,0x580d,0x580e,
+    0x0412,0x0013,0x2017,
+    0x331b,0x331c,0x331d,0x331e,
+    0xffff
+};
+static u16 ccrtc_640x480x16[] VAR16 = {
+    0x2c11,
+    0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+    0x4009,0x000c,0x000d,
+    0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 640x480x24 */
+static u16 cseq_640x480x24[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+    0x580b,0x580c,0x580d,0x580e,
+    0x0412,0x0013,0x2017,
+    0x331b,0x331c,0x331d,0x331e,
+    0xffff
+};
+static u16 ccrtc_640x480x24[] VAR16 = {
+    0x2c11,
+    0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+    0x4009,0x000c,0x000d,
+    0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+    0x001a,0x321b,0x001d,
+    0xffff
+};
+/* 800x600x8 */
+static u16 cseq_800x600x8[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+    0x230b,0x230c,0x230d,0x230e,
+    0x0412,0x0013,0x2017,
+    0x141b,0x141c,0x141d,0x141e,
+    0xffff
+};
+static u16 ccrtc_800x600x8[] VAR16 = {
+    0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+    0x6009,0x000c,0x000d,
+    0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 800x600x16 */
+static u16 cseq_800x600x16[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+    0x230b,0x230c,0x230d,0x230e,
+    0x0412,0x0013,0x2017,
+    0x141b,0x141c,0x141d,0x141e,
+    0xffff
+};
+static u16 ccrtc_800x600x16[] VAR16 = {
+    0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+    0x6009,0x000c,0x000d,
+    0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 800x600x24 */
+static u16 cseq_800x600x24[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+    0x230b,0x230c,0x230d,0x230e,
+    0x0412,0x0013,0x2017,
+    0x141b,0x141c,0x141d,0x141e,
+    0xffff
+};
+static u16 ccrtc_800x600x24[] VAR16 = {
+    0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+    0x6009,0x000c,0x000d,
+    0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
+    0x001a,0x321b,0x001d,
+    0xffff
+};
+/* 1024x768x8 */
+static u16 cseq_1024x768x8[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1024x768x8[] VAR16 = {
+    0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 1024x768x16 */
+static u16 cseq_1024x768x16[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1024x768x16[] VAR16 = {
+    0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x321b,0x001d,
+    0xffff
+};
+/* 1024x768x24 */
+static u16 cseq_1024x768x24[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1024x768x24[] VAR16 = {
+    0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x321b,0x001d,
+    0xffff
+};
+/* 1280x1024x8 */
+static u16 cseq_1280x1024x8[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1280x1024x8[] VAR16 = {
+    0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+/* 1280x1024x16 */
+static u16 cseq_1280x1024x16[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1280x1024x16[] VAR16 = {
+    0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x321b,0x001d,
+    0xffff
+};
+
+/* 1600x1200x8 */
+static u16 cseq_1600x1200x8[] VAR16 = {
+    0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+    0x760b,0x760c,0x760d,0x760e,
+    0x0412,0x0013,0x2017,
+    0x341b,0x341c,0x341d,0x341e,
+    0xffff
+};
+static u16 ccrtc_1600x1200x8[] VAR16 = {
+    0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+    0x6009,0x000c,0x000d,
+    0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+
+static struct cirrus_mode_s cirrus_modes[] VAR16 = {
+    {0x5f,640,480,8,0x00,
+     cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x64,640,480,16,0xe1,
+     cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x66,640,480,15,0xf0,
+     cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+     6,5,10,5,5,5,0,1,15},
+    {0x71,640,480,24,0xe5,
+     cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
+     6,8,16,8,8,8,0,0,0},
+
+    {0x5c,800,600,8,0x00,
+     cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x65,800,600,16,0xe1,
+     cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x67,800,600,15,0xf0,
+     cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+     6,5,10,5,5,5,0,1,15},
+
+    {0x60,1024,768,8,0x00,
+     cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x74,1024,768,16,0xe1,
+     cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x68,1024,768,15,0xf0,
+     cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+     6,5,10,5,5,5,0,1,15},
+
+    {0x78,800,600,24,0xe5,
+     cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
+     6,8,16,8,8,8,0,0,0},
+    {0x79,1024,768,24,0xe5,
+     cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
+     6,8,16,8,8,8,0,0,0},
+
+    {0x6d,1280,1024,8,0x00,
+     cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x69,1280,1024,15,0xf0,
+     cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+     6,5,10,5,5,5,0,1,15},
+    {0x75,1280,1024,16,0xe1,
+     cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+     6,5,11,6,5,5,0,0,0},
+
+    {0x7b,1600,1200,8,0x00,
+     cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
+     4,0,0,0,0,0,0,0,0},
+
+    {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
+     0xff,0,0,0,0,0,0,0,0},
+};
+
+static struct cirrus_mode_s *
+cirrus_get_modeentry(u8 mode)
+{
+    struct cirrus_mode_s *table_g = cirrus_modes;
+    while (table_g < &cirrus_modes[ARRAY_SIZE(cirrus_modes)]) {
+        u16 tmode = GET_GLOBAL(table_g->mode);
+        if (tmode == mode)
+            return table_g;
+        table_g++;
+    }
+    return NULL;
+}
+
+static void
+cirrus_switch_mode_setregs(u16 *data, u16 port)
+{
+    for (;;) {
+        u16 val = GET_GLOBAL(*data);
+        if (val == 0xffff)
+            return;
+        outw(val, port);
+        data++;
+    }
+}
+
+static u16
+cirrus_get_crtc(void)
+{
+    if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
+        return VGAREG_VGA_CRTC_ADDRESS;
+    return VGAREG_MDA_CRTC_ADDRESS;
+}
+
+static void
+cirrus_switch_mode(struct cirrus_mode_s *table)
+{
+    // Unlock cirrus special
+    outw(0x1206, VGAREG_SEQU_ADDRESS);
+    cirrus_switch_mode_setregs(GET_GLOBAL(table->seq), VGAREG_SEQU_ADDRESS);
+    cirrus_switch_mode_setregs(GET_GLOBAL(table->graph), VGAREG_GRDC_ADDRESS);
+    cirrus_switch_mode_setregs(GET_GLOBAL(table->crtc), cirrus_get_crtc());
+
+    outb(0x00, VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    outb(GET_GLOBAL(table->hidden_dac), VGAREG_PEL_MASK);
+    outb(0xff, VGAREG_PEL_MASK);
+
+    u8 vesacolortype = GET_GLOBAL(table->vesacolortype);
+    u8 v = vgahw_get_single_palette_reg(0x10) & 0xfe;
+    if (vesacolortype == 3)
+        v |= 0x41;
+    else if (vesacolortype)
+        v |= 0x01;
+    vgahw_set_single_palette_reg(0x10, v);
+}
+
+void
+cirrus_set_video_mode(u8 mode)
+{
+    dprintf(1, "cirrus mode %d\n", mode);
+    SET_BDA(vbe_mode, 0);
+    struct cirrus_mode_s *table_g = cirrus_get_modeentry(mode & 0x7f);
+    if (table_g) {
+        //XXX - cirrus_set_video_mode_extended(table);
+        return;
+    }
+    table_g = cirrus_get_modeentry(0xfe);
+    cirrus_switch_mode(table_g);
+    dprintf(1, "cirrus mode switch regular\n");
+}
+
+static int
+cirrus_check(void)
+{
+    outw(0x9206, VGAREG_SEQU_ADDRESS);
+    return inb(VGAREG_SEQU_DATA) == 0x12;
+}
+
+void
+cirrus_init(void)
+{
+    dprintf(1, "cirrus init\n");
+    if (! cirrus_check())
+        return;
+    dprintf(1, "cirrus init 2\n");
+
+    // memory setup
+    outb(0x0f, VGAREG_SEQU_ADDRESS);
+    u8 v = inb(VGAREG_SEQU_DATA);
+    outb(((v & 0x18) << 8) | 0x0a, VGAREG_SEQU_ADDRESS);
+    // set vga mode
+    outw(0x0007, VGAREG_SEQU_ADDRESS);
+    // reset bitblt
+    outw(0x0431, VGAREG_GRDC_ADDRESS);
+    outw(0x0031, VGAREG_GRDC_ADDRESS);
+}
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vga.c b/qemu-0.15.x/roms/seabios/vgasrc/vga.c
new file mode 100644
index 0000000..d734e23
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vga.c
@@ -0,0 +1,1387 @@
+// VGA bios implementation
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+// TODO:
+//  * review correctness of converted asm by comparing with RBIL
+//
+//  * convert vbe/clext code
+
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // memset
+#include "vgatables.h" // find_vga_entry
+
+// XXX
+#define CONFIG_VBE 0
+#define CONFIG_CIRRUS 0
+
+// XXX
+#define DEBUG_VGA_POST 1
+#define DEBUG_VGA_10 3
+
+#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+call16_vgaint(u32 eax, u32 ebx)
+{
+    asm volatile(
+        "int $0x10\n"
+        "cli\n"
+        "cld"
+        :
+        : "a"(eax), "b"(ebx)
+        : "cc", "memory");
+}
+
+static void
+perform_gray_scale_summing(u16 start, u16 count)
+{
+    vgahw_screen_disable();
+    int i;
+    for (i = start; i < start+count; i++) {
+        u8 rgb[3];
+        vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1);
+
+        // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+        u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
+        if (intensity > 0x3f)
+            intensity = 0x3f;
+
+        vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
+    }
+    vgahw_screen_enable();
+}
+
+static void
+set_cursor_shape(u8 start, u8 end)
+{
+    start &= 0x3f;
+    end &= 0x1f;
+
+    u16 curs = (start << 8) + end;
+    SET_BDA(cursor_type, curs);
+
+    u8 modeset_ctl = GET_BDA(modeset_ctl);
+    u16 cheight = GET_BDA(char_height);
+    if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
+        if (end != (start + 1))
+            start = ((start + 1) * cheight / 8) - 1;
+        else
+            start = ((end + 1) * cheight / 8) - 2;
+        end = ((end + 1) * cheight / 8) - 1;
+    }
+    vgahw_set_cursor_shape(start, end);
+}
+
+static u16
+get_cursor_shape(u8 page)
+{
+    if (page > 7)
+        return 0;
+    // FIXME should handle VGA 14/16 lines
+    return GET_BDA(cursor_type);
+}
+
+static void
+set_cursor_pos(struct cursorpos cp)
+{
+    // Should not happen...
+    if (cp.page > 7)
+        return;
+
+    // Bios cursor pos
+    SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
+
+    // Set the hardware cursor
+    u8 current = GET_BDA(video_page);
+    if (cp.page != current)
+        return;
+
+    // Get the dimensions
+    u16 nbcols = GET_BDA(video_cols);
+    u16 nbrows = GET_BDA(video_rows) + 1;
+
+    // Calculate the address knowing nbcols nbrows and page num
+    u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
+                   + cp.x + cp.y * nbcols);
+
+    vgahw_set_cursor_pos(address);
+}
+
+static struct cursorpos
+get_cursor_pos(u8 page)
+{
+    if (page == 0xff)
+        // special case - use current page
+        page = GET_BDA(video_page);
+    if (page > 7) {
+        struct cursorpos cp = { 0, 0, 0xfe };
+        return cp;
+    }
+    // FIXME should handle VGA 14/16 lines
+    u16 xy = GET_BDA(cursor_pos[page]);
+    struct cursorpos cp = {xy, xy>>8, page};
+    return cp;
+}
+
+static void
+set_active_page(u8 page)
+{
+    if (page > 7)
+        return;
+
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // Get pos curs pos for the right page
+    struct cursorpos cp = get_cursor_pos(page);
+
+    u16 address;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+        // Get the dimensions
+        u16 nbcols = GET_BDA(video_cols);
+        u16 nbrows = GET_BDA(video_rows) + 1;
+
+        // Calculate the address knowing nbcols nbrows and page num
+        address = SCREEN_MEM_START(nbcols, nbrows, page);
+        SET_BDA(video_pagestart, address);
+
+        // Start address
+        address = SCREEN_IO_START(nbcols, nbrows, page);
+    } else {
+        struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+        address = page * GET_GLOBAL(vparam_g->slength);
+    }
+
+    vgahw_set_active_page(address);
+
+    // And change the BIOS page
+    SET_BDA(video_page, page);
+
+    dprintf(1, "Set active page %02x address %04x\n", page, address);
+
+    // Display the cursor, now the page is active
+    set_cursor_pos(cp);
+}
+
+static void
+set_scan_lines(u8 lines)
+{
+    vgahw_set_scan_lines(lines);
+    if (lines == 8)
+        set_cursor_shape(0x06, 0x07);
+    else
+        set_cursor_shape(lines - 4, lines - 3);
+    SET_BDA(char_height, lines);
+    u16 vde = vgahw_get_vde();
+    u8 rows = vde / lines;
+    SET_BDA(video_rows, rows - 1);
+    u16 cols = GET_BDA(video_cols);
+    SET_BDA(video_pagesize, rows * cols * 2);
+}
+
+
+/****************************************************************
+ * Character writing
+ ****************************************************************/
+
+// Scroll the screen one line.  This function is designed to be called
+// tail-recursive to reduce stack usage.
+static void noinline
+scroll_one(u16 nbrows, u16 nbcols, u8 page)
+{
+    struct cursorpos ul = {0, 0, page};
+    struct cursorpos lr = {nbcols-1, nbrows-1, page};
+    vgafb_scroll(1, -1, ul, lr);
+}
+
+// Write a character to the screen at a given position.  Implement
+// special characters and scroll the screen if necessary.
+static void
+write_teletype(struct cursorpos *pcp, struct carattr ca)
+{
+    struct cursorpos cp = *pcp;
+
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    switch (ca.car) {
+    case 7:
+        //FIXME should beep
+        break;
+    case 8:
+        if (cp.x > 0)
+            cp.x--;
+        break;
+    case '\r':
+        cp.x = 0;
+        break;
+    case '\n':
+        cp.y++;
+        break;
+    case '\t':
+        do {
+            struct carattr dummyca = {' ', ca.attr, ca.use_attr};
+            vgafb_write_char(cp, dummyca);
+            cp.x++;
+        } while (cp.x < nbcols && cp.x % 8);
+        break;
+    default:
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
+
+    // Do we need to wrap ?
+    if (cp.x == nbcols) {
+        cp.x = 0;
+        cp.y++;
+    }
+    // Do we need to scroll ?
+    if (cp.y < nbrows) {
+        *pcp = cp;
+        return;
+    }
+    // Scroll screen
+    cp.y--;
+    *pcp = cp;
+    scroll_one(nbrows, nbcols, cp.page);
+}
+
+// Write out a buffer of alternating characters and attributes.
+static void
+write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
+{
+    while (count--) {
+        u8 car = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+        u8 attr = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+
+        struct carattr ca = {car, attr, 1};
+        write_teletype(pcp, ca);
+    }
+}
+
+// Write out a buffer of characters.
+static void
+write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
+{
+    while (count--) {
+        u8 car = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+
+        struct carattr ca = {car, attr, 1};
+        write_teletype(pcp, ca);
+    }
+}
+
+
+/****************************************************************
+ * Save and restore bda state
+ ****************************************************************/
+
+static void
+save_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
+    SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
+    SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
+    SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
+    SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
+    SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
+    SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
+    SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
+    SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
+    SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
+    u16 i;
+    for (i=0; i<8; i++)
+        SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
+    SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
+    SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
+    /* current font */
+    SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
+    SET_FARVAR(seg, info->font1, GET_IVT(0x43));
+}
+
+static void
+restore_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
+    SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
+    SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
+    SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
+    SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
+    SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
+    SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
+    SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
+    SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
+    SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
+    u16 i;
+    for (i = 0; i < 8; i++)
+        SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
+    SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
+    SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
+    /* current font */
+    SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
+    SET_IVT(0x43, GET_FARVAR(seg, info->font1));
+}
+
+
+/****************************************************************
+ * VGA int 10 handler
+ ****************************************************************/
+
+// set video mode
+static void
+handle_1000(struct bregs *regs)
+{
+    u8 noclearmem = regs->al & 0x80;
+    u8 mode = regs->al & 0x7f;
+
+    // Set regs->al
+    if (mode > 7)
+        regs->al = 0x20;
+    else if (mode == 6)
+        regs->al = 0x3f;
+    else
+        regs->al = 0x30;
+
+    if (CONFIG_CIRRUS)
+        cirrus_set_video_mode(mode);
+
+    if (CONFIG_VBE)
+        if (vbe_has_vbe_display())
+            dispi_set_enable(VBE_DISPI_DISABLED);
+
+    // find the entry in the video modes
+    struct vgamode_s *vmode_g = find_vga_entry(mode);
+    dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
+    if (!vmode_g)
+        return;
+
+    // Read the bios mode set control
+    u8 modeset_ctl = GET_BDA(modeset_ctl);
+
+    // Then we know the number of lines
+// FIXME
+
+    // if palette loading (bit 3 of modeset ctl = 0)
+    if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
+        vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
+
+        // From which palette
+        u8 *palette_g = GET_GLOBAL(vmode_g->dac);
+        u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
+
+        // Always 256*3 values
+        vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
+        u16 i;
+        for (i = palsize; i < 0x0100; i++) {
+            static u8 rgb[3] VAR16;
+            vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
+        }
+
+        if ((modeset_ctl & 0x02) == 0x02)
+            perform_gray_scale_summing(0x00, 0x100);
+    }
+
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    vgahw_set_mode(vparam_g);
+
+    if (noclearmem == 0x00)
+        clear_screen(vmode_g);
+
+    // Set CRTC address VGA or MDA
+    u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+    if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
+        crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+    // Set the BIOS mem
+    u16 cheight = GET_GLOBAL(vparam_g->cheight);
+    SET_BDA(video_mode, mode);
+    SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
+    SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
+    SET_BDA(crtc_address, crtc_addr);
+    SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
+    SET_BDA(char_height, cheight);
+    SET_BDA(video_ctl, (0x60 | noclearmem));
+    SET_BDA(video_switches, 0xF9);
+    SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
+
+    // FIXME We nearly have the good tables. to be reworked
+    SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
+    SET_BDA(video_savetable
+            , SEGOFF(get_global_seg(), (u32)video_save_pointer_table));
+
+    // FIXME
+    SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
+    SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
+
+    // Set cursor shape
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        set_cursor_shape(0x06, 0x07);
+    // Set cursor pos for page 0..7
+    int i;
+    for (i = 0; i < 8; i++) {
+        struct cursorpos cp = {0, 0, i};
+        set_cursor_pos(cp);
+    }
+
+    // Set active page 0
+    set_active_page(0x00);
+
+    // Write the fonts in memory
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+        call16_vgaint(0x1104, 0);
+        call16_vgaint(0x1103, 0);
+    }
+    // Set the ints 0x1F and 0x43
+    SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
+
+    switch (cheight) {
+    case 8:
+        SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
+        break;
+    case 14:
+        SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
+        break;
+    case 16:
+        SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
+        break;
+    }
+}
+
+static void
+handle_1001(struct bregs *regs)
+{
+    set_cursor_shape(regs->ch, regs->cl);
+}
+
+static void
+handle_1002(struct bregs *regs)
+{
+    struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+    set_cursor_pos(cp);
+}
+
+static void
+handle_1003(struct bregs *regs)
+{
+    regs->cx = get_cursor_shape(regs->bh);
+    struct cursorpos cp = get_cursor_pos(regs->bh);
+    regs->dl = cp.x;
+    regs->dh = cp.y;
+}
+
+// Read light pen pos (unimplemented)
+static void
+handle_1004(struct bregs *regs)
+{
+    debug_stub(regs);
+    regs->ax = regs->bx = regs->cx = regs->dx = 0;
+}
+
+static void
+handle_1005(struct bregs *regs)
+{
+    set_active_page(regs->al);
+}
+
+static void
+verify_scroll(struct bregs *regs, int dir)
+{
+    u8 page = GET_BDA(video_page);
+    struct cursorpos ul = {regs->cl, regs->ch, page};
+    struct cursorpos lr = {regs->dl, regs->dh, page};
+
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    if (lr.y >= nbrows)
+        lr.y = nbrows - 1;
+    u16 nbcols = GET_BDA(video_cols);
+    if (lr.x >= nbcols)
+        lr.x = nbcols - 1;
+
+    if (ul.x > lr.x || ul.y > lr.y)
+        return;
+
+    u16 nblines = regs->al;
+    if (!nblines || nblines > lr.y - ul.y + 1)
+        nblines = lr.y - ul.y + 1;
+
+    vgafb_scroll(dir * nblines, regs->bh, ul, lr);
+}
+
+static void
+handle_1006(struct bregs *regs)
+{
+    verify_scroll(regs, 1);
+}
+
+static void
+handle_1007(struct bregs *regs)
+{
+    verify_scroll(regs, -1);
+}
+
+static void
+handle_1008(struct bregs *regs)
+{
+    struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
+    regs->al = ca.car;
+    regs->ah = ca.attr;
+}
+
+static void noinline
+write_chars(u8 page, struct carattr ca, u16 count)
+{
+    struct cursorpos cp = get_cursor_pos(page);
+    while (count--) {
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
+}
+
+static void
+handle_1009(struct bregs *regs)
+{
+    struct carattr ca = {regs->al, regs->bl, 1};
+    write_chars(regs->bh, ca, regs->cx);
+}
+
+static void
+handle_100a(struct bregs *regs)
+{
+    struct carattr ca = {regs->al, regs->bl, 0};
+    write_chars(regs->bh, ca, regs->cx);
+}
+
+
+static void
+handle_100b00(struct bregs *regs)
+{
+    vgahw_set_border_color(regs->bl);
+}
+
+static void
+handle_100b01(struct bregs *regs)
+{
+    vgahw_set_palette(regs->bl);
+}
+
+static void
+handle_100bXX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_100b(struct bregs *regs)
+{
+    switch (regs->bh) {
+    case 0x00: handle_100b00(regs); break;
+    case 0x01: handle_100b01(regs); break;
+    default:   handle_100bXX(regs); break;
+    }
+}
+
+
+static void
+handle_100c(struct bregs *regs)
+{
+    // XXX - page (regs->bh) is unused
+    vgafb_write_pixel(regs->al, regs->cx, regs->dx);
+}
+
+static void
+handle_100d(struct bregs *regs)
+{
+    // XXX - page (regs->bh) is unused
+    regs->al = vgafb_read_pixel(regs->cx, regs->dx);
+}
+
+static void noinline
+handle_100e(struct bregs *regs)
+{
+    // Ralf Brown Interrupt list is WRONG on bh(page)
+    // We do output only on the current page !
+    struct carattr ca = {regs->al, regs->bl, 0};
+    struct cursorpos cp = get_cursor_pos(0xff);
+    write_teletype(&cp, ca);
+    set_cursor_pos(cp);
+}
+
+static void
+handle_100f(struct bregs *regs)
+{
+    regs->bh = GET_BDA(video_page);
+    regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
+    regs->ah = GET_BDA(video_cols);
+}
+
+
+static void
+handle_101000(struct bregs *regs)
+{
+    if (regs->bl > 0x14)
+        return;
+    vgahw_set_single_palette_reg(regs->bl, regs->bh);
+}
+
+static void
+handle_101001(struct bregs *regs)
+{
+    vgahw_set_overscan_border_color(regs->bh);
+}
+
+static void
+handle_101002(struct bregs *regs)
+{
+    vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void
+handle_101003(struct bregs *regs)
+{
+    vgahw_toggle_intensity(regs->bl);
+}
+
+static void
+handle_101007(struct bregs *regs)
+{
+    if (regs->bl > 0x14)
+        return;
+    regs->bh = vgahw_get_single_palette_reg(regs->bl);
+}
+
+static void
+handle_101008(struct bregs *regs)
+{
+    regs->bh = vgahw_get_overscan_border_color();
+}
+
+static void
+handle_101009(struct bregs *regs)
+{
+    vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void noinline
+handle_101010(struct bregs *regs)
+{
+    u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
+    vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
+}
+
+static void
+handle_101012(struct bregs *regs)
+{
+    vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101013(struct bregs *regs)
+{
+    vgahw_select_video_dac_color_page(regs->bl, regs->bh);
+}
+
+static void noinline
+handle_101015(struct bregs *regs)
+{
+    u8 rgb[3];
+    vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
+    regs->dh = rgb[0];
+    regs->ch = rgb[1];
+    regs->cl = rgb[2];
+}
+
+static void
+handle_101017(struct bregs *regs)
+{
+    vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101018(struct bregs *regs)
+{
+    vgahw_set_pel_mask(regs->bl);
+}
+
+static void
+handle_101019(struct bregs *regs)
+{
+    regs->bl = vgahw_get_pel_mask();
+}
+
+static void
+handle_10101a(struct bregs *regs)
+{
+    vgahw_read_video_dac_state(&regs->bl, &regs->bh);
+}
+
+static void
+handle_10101b(struct bregs *regs)
+{
+    perform_gray_scale_summing(regs->bx, regs->cx);
+}
+
+static void
+handle_1010XX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_1010(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101000(regs); break;
+    case 0x01: handle_101001(regs); break;
+    case 0x02: handle_101002(regs); break;
+    case 0x03: handle_101003(regs); break;
+    case 0x07: handle_101007(regs); break;
+    case 0x08: handle_101008(regs); break;
+    case 0x09: handle_101009(regs); break;
+    case 0x10: handle_101010(regs); break;
+    case 0x12: handle_101012(regs); break;
+    case 0x13: handle_101013(regs); break;
+    case 0x15: handle_101015(regs); break;
+    case 0x17: handle_101017(regs); break;
+    case 0x18: handle_101018(regs); break;
+    case 0x19: handle_101019(regs); break;
+    case 0x1a: handle_10101a(regs); break;
+    case 0x1b: handle_10101b(regs); break;
+    default:   handle_1010XX(regs); break;
+    }
+}
+
+
+static void
+handle_101100(struct bregs *regs)
+{
+    vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+                    , regs->dx, regs->bl, regs->bh);
+}
+
+static void
+handle_101101(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+}
+
+static void
+handle_101102(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+}
+
+static void
+handle_101103(struct bregs *regs)
+{
+    vgahw_set_text_block_specifier(regs->bl);
+}
+
+static void
+handle_101104(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+}
+
+static void
+handle_101110(struct bregs *regs)
+{
+    vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+                    , regs->dx, regs->bl, regs->bh);
+    set_scan_lines(regs->bh);
+}
+
+static void
+handle_101111(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+    set_scan_lines(14);
+}
+
+static void
+handle_101112(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+    set_scan_lines(8);
+}
+
+static void
+handle_101114(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+    set_scan_lines(16);
+}
+
+static void
+handle_101130(struct bregs *regs)
+{
+    switch (regs->bh) {
+    case 0x00: {
+        struct segoff_s so = GET_IVT(0x1f);
+        regs->es = so.seg;
+        regs->bp = so.offset;
+        break;
+    }
+    case 0x01: {
+        struct segoff_s so = GET_IVT(0x43);
+        regs->es = so.seg;
+        regs->bp = so.offset;
+        break;
+    }
+    case 0x02:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont14;
+        break;
+    case 0x03:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont8;
+        break;
+    case 0x04:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont8 + 128 * 8;
+        break;
+    case 0x05:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont14alt;
+        break;
+    case 0x06:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont16;
+        break;
+    case 0x07:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont16alt;
+        break;
+    default:
+        dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
+        return;
+    }
+    // Set byte/char of on screen font
+    regs->cx = GET_BDA(char_height) & 0xff;
+
+    // Set Highest char row
+    regs->dx = GET_BDA(video_rows);
+}
+
+static void
+handle_1011XX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_1011(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101100(regs); break;
+    case 0x01: handle_101101(regs); break;
+    case 0x02: handle_101102(regs); break;
+    case 0x03: handle_101103(regs); break;
+    case 0x04: handle_101104(regs); break;
+    case 0x10: handle_101110(regs); break;
+    case 0x11: handle_101111(regs); break;
+    case 0x12: handle_101112(regs); break;
+    case 0x14: handle_101114(regs); break;
+    case 0x30: handle_101130(regs); break;
+    default:   handle_1011XX(regs); break;
+    }
+}
+
+
+static void
+handle_101210(struct bregs *regs)
+{
+    u16 crtc_addr = GET_BDA(crtc_address);
+    if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
+        regs->bx = 0x0103;
+    else
+        regs->bx = 0x0003;
+    regs->cx = GET_BDA(video_switches) & 0x0f;
+}
+
+static void
+handle_101230(struct bregs *regs)
+{
+    u8 mctl = GET_BDA(modeset_ctl);
+    u8 vswt = GET_BDA(video_switches);
+    switch (regs->al) {
+    case 0x00:
+        // 200 lines
+        mctl = (mctl & ~0x10) | 0x80;
+        vswt = (vswt & ~0x0f) | 0x08;
+        break;
+    case 0x01:
+        // 350 lines
+        mctl &= ~0x90;
+        vswt = (vswt & ~0x0f) | 0x09;
+        break;
+    case 0x02:
+        // 400 lines
+        mctl = (mctl & ~0x80) | 0x10;
+        vswt = (vswt & ~0x0f) | 0x09;
+        break;
+    default:
+        dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
+        break;
+    }
+    SET_BDA(modeset_ctl, mctl);
+    SET_BDA(video_switches, vswt);
+    regs->al = 0x12;
+}
+
+static void
+handle_101231(struct bregs *regs)
+{
+    u8 v = (regs->al & 0x01) << 3;
+    u8 mctl = GET_BDA(video_ctl) & ~0x08;
+    SET_BDA(video_ctl, mctl | v);
+    regs->al = 0x12;
+}
+
+static void
+handle_101232(struct bregs *regs)
+{
+    vgahw_enable_video_addressing(regs->al);
+    regs->al = 0x12;
+}
+
+static void
+handle_101233(struct bregs *regs)
+{
+    u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
+    u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
+    SET_BDA(modeset_ctl, v | v2);
+    regs->al = 0x12;
+}
+
+static void
+handle_101234(struct bregs *regs)
+{
+    u8 v = (regs->al & 0x01) ^ 0x01;
+    u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
+    SET_BDA(modeset_ctl, v | v2);
+    regs->al = 0x12;
+}
+
+static void
+handle_101235(struct bregs *regs)
+{
+    debug_stub(regs);
+    regs->al = 0x12;
+}
+
+static void
+handle_101236(struct bregs *regs)
+{
+    debug_stub(regs);
+    regs->al = 0x12;
+}
+
+static void
+handle_1012XX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_1012(struct bregs *regs)
+{
+    switch (regs->bl) {
+    case 0x10: handle_101210(regs); break;
+    case 0x30: handle_101230(regs); break;
+    case 0x31: handle_101231(regs); break;
+    case 0x32: handle_101232(regs); break;
+    case 0x33: handle_101233(regs); break;
+    case 0x34: handle_101234(regs); break;
+    case 0x35: handle_101235(regs); break;
+    case 0x36: handle_101236(regs); break;
+    default:   handle_1012XX(regs); break;
+    }
+
+    // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
+}
+
+
+// Write string
+static void noinline
+handle_1013(struct bregs *regs)
+{
+    struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+    // if row=0xff special case : use current cursor position
+    if (cp.y == 0xff)
+        cp = get_cursor_pos(cp.page);
+    u8 flag = regs->al;
+    if (flag & 2)
+        write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
+    else
+        write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
+
+    if (flag & 1)
+        set_cursor_pos(cp);
+}
+
+
+static void
+handle_101a00(struct bregs *regs)
+{
+    regs->bx = GET_BDA(dcc_index);
+    regs->al = 0x1a;
+}
+
+static void
+handle_101a01(struct bregs *regs)
+{
+    SET_BDA(dcc_index, regs->bl);
+    dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
+    regs->al = 0x1a;
+}
+
+static void
+handle_101aXX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_101a(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101a00(regs); break;
+    case 0x01: handle_101a01(regs); break;
+    default:   handle_101aXX(regs); break;
+    }
+}
+
+
+struct funcInfo {
+    u16 static_functionality_off;
+    u16 static_functionality_seg;
+    u8 bda_0x49[30];
+    u8 bda_0x84[3];
+    u8 dcc_index;
+    u8 dcc_alt;
+    u16 colors;
+    u8 pages;
+    u8 scan_lines;
+    u8 primary_char;
+    u8 secondar_char;
+    u8 misc;
+    u8 non_vga_mode;
+    u8 reserved_2f[2];
+    u8 video_mem;
+    u8 save_flags;
+    u8 disp_info;
+    u8 reserved_34[12];
+};
+
+static void
+handle_101b(struct bregs *regs)
+{
+    u16 seg = regs->es;
+    struct funcInfo *info = (void*)(regs->di+0);
+    memset_far(seg, info, 0, sizeof(*info));
+    // Address of static functionality table
+    SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
+    SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
+
+    // Hard coded copy from BIOS area. Should it be cleaner ?
+    memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
+               , sizeof(info->bda_0x49));
+    memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
+               , sizeof(info->bda_0x84));
+
+    SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
+    SET_FARVAR(seg, info->colors, 16);
+    SET_FARVAR(seg, info->pages, 8);
+    SET_FARVAR(seg, info->scan_lines, 2);
+    SET_FARVAR(seg, info->video_mem, 3);
+    regs->al = 0x1B;
+}
+
+
+static void
+handle_101c00(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 size = 0;
+    if (flags & 1)
+        size += sizeof(struct saveVideoHardware);
+    if (flags & 2)
+        size += sizeof(struct saveBDAstate);
+    if (flags & 4)
+        size += sizeof(struct saveDACcolors);
+    regs->bx = size;
+    regs->al = 0x1c;
+}
+
+static void
+handle_101c01(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_save_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        save_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_save_dac_state(seg, data);
+    regs->al = 0x1c;
+}
+
+static void
+handle_101c02(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_restore_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        restore_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_restore_dac_state(seg, data);
+    regs->al = 0x1c;
+}
+
+static void
+handle_101cXX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_101c(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101c00(regs); break;
+    case 0x01: handle_101c01(regs); break;
+    case 0x02: handle_101c02(regs); break;
+    default:   handle_101cXX(regs); break;
+    }
+}
+
+
+static void
+handle_104f00(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
+    // XXX - OR cirrus_vesa_00h
+}
+
+static void
+handle_104f01(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+    // XXX - OR cirrus_vesa_01h
+}
+
+static void
+handle_104f02(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
+    // XXX - OR cirrus_vesa_02h
+}
+
+static void
+handle_104f03(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_current_mode
+    // XXX - OR cirrus_vesa_03h
+}
+
+static void
+handle_104f04(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+}
+
+static void
+handle_104f05(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_display_window_control
+    // XXX - OR cirrus_vesa_05h
+}
+
+static void
+handle_104f06(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_logical_scan_line_length
+    // XXX - OR cirrus_vesa_06h
+}
+
+static void
+handle_104f07(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_display_start
+    // XXX - OR cirrus_vesa_07h
+}
+
+static void
+handle_104f08(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_dac_palette_format
+}
+
+static void
+handle_104f0a(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_protected_mode_interface
+}
+
+static void
+handle_104fXX(struct bregs *regs)
+{
+    debug_stub(regs);
+    regs->ax = 0x0100;
+}
+
+static void
+handle_104f(struct bregs *regs)
+{
+    if (! CONFIG_VBE || !vbe_has_vbe_display()) {
+        handle_104fXX(regs);
+        return;
+    }
+
+    switch (regs->al) {
+    case 0x00: handle_104f00(regs); break;
+    case 0x01: handle_104f01(regs); break;
+    case 0x02: handle_104f02(regs); break;
+    case 0x03: handle_104f03(regs); break;
+    case 0x04: handle_104f04(regs); break;
+    case 0x05: handle_104f05(regs); break;
+    case 0x06: handle_104f06(regs); break;
+    case 0x07: handle_104f07(regs); break;
+    case 0x08: handle_104f08(regs); break;
+    case 0x0a: handle_104f0a(regs); break;
+    default:   handle_104fXX(regs); break;
+    }
+}
+
+
+static void
+handle_10XX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_VGA_10);
+    switch (regs->ah) {
+    case 0x00: handle_1000(regs); break;
+    case 0x01: handle_1001(regs); break;
+    case 0x02: handle_1002(regs); break;
+    case 0x03: handle_1003(regs); break;
+    case 0x04: handle_1004(regs); break;
+    case 0x05: handle_1005(regs); break;
+    case 0x06: handle_1006(regs); break;
+    case 0x07: handle_1007(regs); break;
+    case 0x08: handle_1008(regs); break;
+    case 0x09: handle_1009(regs); break;
+    case 0x0a: handle_100a(regs); break;
+    case 0x0b: handle_100b(regs); break;
+    case 0x0c: handle_100c(regs); break;
+    case 0x0d: handle_100d(regs); break;
+    case 0x0e: handle_100e(regs); break;
+    case 0x0f: handle_100f(regs); break;
+    case 0x10: handle_1010(regs); break;
+    case 0x11: handle_1011(regs); break;
+    case 0x12: handle_1012(regs); break;
+    case 0x13: handle_1013(regs); break;
+    case 0x1a: handle_101a(regs); break;
+    case 0x1b: handle_101b(regs); break;
+    case 0x1c: handle_101c(regs); break;
+    case 0x4f: handle_104f(regs); break;
+    default:   handle_10XX(regs); break;
+    }
+}
+
+
+/****************************************************************
+ * VGA post
+ ****************************************************************/
+
+static void
+init_bios_area(void)
+{
+    // init detected hardware BIOS Area
+    // set 80x25 color (not clear from RBIL but usual)
+    u16 eqf = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
+
+    // Just for the first int10 find its children
+
+    // the default char height
+    SET_BDA(char_height, 0x10);
+
+    // Clear the screen
+    SET_BDA(video_ctl, 0x60);
+
+    // Set the basic screen we have
+    SET_BDA(video_switches, 0xf9);
+
+    // Set the basic modeset options
+    SET_BDA(modeset_ctl, 0x51);
+
+    // Set the  default MSR
+    SET_BDA(video_msr, 0x09);
+}
+
+void VISIBLE16
+vga_post(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_VGA_POST);
+
+    vgahw_init();
+
+    init_bios_area();
+
+    if (CONFIG_VBE)
+        vbe_init();
+
+    extern void entry_10(void);
+    SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
+
+    if (CONFIG_CIRRUS)
+        cirrus_init();
+
+    // XXX - clear screen and display info
+
+    // XXX: fill it
+    SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
+    SET_VGA(video_save_pointer_table[1], get_global_seg());
+
+    // Fixup checksum
+    extern u8 _rom_header_size, _rom_header_checksum;
+    SET_VGA(_rom_header_checksum, 0);
+    u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
+    SET_VGA(_rom_header_checksum, sum);
+}
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgaentry.S b/qemu-0.15.x/roms/seabios/vgasrc/vgaentry.S
new file mode 100644
index 0000000..fbfa9f7
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgaentry.S
@@ -0,0 +1,48 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Include of 16bit C code
+ ****************************************************************/
+
+        .code16gcc
+#include "vgaccode.16.s"
+
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * Rom Header
+ ****************************************************************/
+
+        .section .rom.header
+        .global _rom_header, _rom_header_size, _rom_header_checksum
+_rom_header:
+        .word 0xaa55
+_rom_header_size:
+        .byte 0
+_rom_header_entry:
+        jmp _optionrom_entry
+_rom_header_checksum:
+        .byte 0
+_rom_header_other:
+        .space 21
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+        DECLFUNC _optionrom_entry
+_optionrom_entry:
+        ENTRY_ARG vga_post
+        lretw
+
+        DECLFUNC entry_10
+entry_10:
+        ENTRY_ARG handle_10
+        iretw
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgafb.c b/qemu-0.15.x/roms/seabios/vgasrc/vgafb.c
new file mode 100644
index 0000000..866f7f8
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgafb.c
@@ -0,0 +1,512 @@
+// Code for manipulating VGA framebuffers.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "util.h" // memset_far
+#include "vgatables.h" // find_vga_entry
+
+
+/****************************************************************
+ * Screen scrolling
+ ****************************************************************/
+
+static inline void *
+memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
+{
+    for (; lines; lines--, dst+=stride, src+=stride)
+        memcpy_far(seg, dst, seg, src, copylen);
+    return dst;
+}
+
+static inline void
+memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
+{
+    for (; lines; lines--, dst+=stride)
+        memset_far(seg, dst, val, setlen);
+}
+
+static inline void
+memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
+{
+    for (; lines; lines--, dst+=stride)
+        memset16_far(seg, dst, val, setlen);
+}
+
+static void
+scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
+           , struct cursorpos ul, struct cursorpos lr)
+{
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    int stride = GET_BDA(video_cols);
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
+    }
+    int cols = lr.x - ul.x + 1;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        vgahw_grdc_write(0x05, 0x01);
+        dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
+                                 , (rows - nblines) * cheight);
+    }
+    if (attr < 0)
+        attr = 0;
+    vgahw_grdc_write(0x05, 0x02);
+    memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
+    vgahw_grdc_write(0x05, 0x00);
+}
+
+static void
+scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
+{
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    int stride = GET_BDA(video_cols) * bpp;
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
+    }
+    int cols = (lr.x - ul.x + 1) * bpp;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
+                      , stride, (rows - nblines) * cheight / 2);
+        dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
+                                 , stride, (rows - nblines) * cheight / 2);
+    }
+    if (attr < 0)
+        attr = 0;
+    memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
+                  , stride, nblines * cheight / 2);
+    memset_stride(SEG_CTEXT, dest_far, attr, cols
+                  , stride, nblines * cheight / 2);
+}
+
+static void
+scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
+{
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+    void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
+    int stride = nbcols * 2;
+    if (nblines >= 0) {
+        dest_far += ul.y * stride + ul.x * 2;
+        src_far = dest_far + nblines * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far += lr.y * stride + ul.x * 2;
+        src_far = dest_far - nblines * stride;
+        stride = -stride;
+    }
+    int cols = (lr.x - ul.x + 1) * 2;
+    int rows = lr.y - ul.y + 1;
+    u16 seg = GET_GLOBAL(vmode_g->sstart);
+    if (nblines < rows)
+        dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
+                                 , (rows - nblines));
+    if (attr < 0)
+        attr = 0x07;
+    attr = (attr << 8) | ' ';
+    memset16_stride(seg, dest_far, attr, cols, stride, nblines);
+}
+
+void
+vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // FIXME gfx mode not complete
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        scroll_text(vmode_g, nblines, attr, ul, lr);
+        break;
+    case PLANAR4:
+    case PLANAR1:
+        scroll_pl4(vmode_g, nblines, attr, ul, lr);
+        break;
+    case CGA:
+        scroll_cga(vmode_g, nblines, attr, ul, lr);
+        break;
+    default:
+        dprintf(1, "Scroll in graphics mode\n");
+    }
+}
+
+void
+clear_screen(struct vgamode_s *vmode_g)
+{
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+        break;
+    case CGA:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
+        break;
+    default:
+        // XXX - old code gets/sets/restores sequ register 2 to 0xf -
+        // but it should always be 0xf anyway.
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
+    }
+}
+
+
+/****************************************************************
+ * Read/write characters to screen
+ ****************************************************************/
+
+static void
+write_gfx_char_pl4(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    u8 *fdata_g;
+    switch (cheight) {
+    case 14:
+        fdata_g = vgafont14;
+        break;
+    case 16:
+        fdata_g = vgafont16;
+        break;
+    default:
+        fdata_g = vgafont8;
+    }
+    u16 addr = cp.x + cp.y * cheight * nbcols;
+    u16 src = ca.car * cheight;
+    vgahw_sequ_write(0x02, 0x0f);
+    vgahw_grdc_write(0x05, 0x02);
+    if (ca.attr & 0x80)
+        vgahw_grdc_write(0x03, 0x18);
+    else
+        vgahw_grdc_write(0x03, 0x00);
+    u8 i;
+    for (i = 0; i < cheight; i++) {
+        u8 *dest_far = (void*)(addr + i * nbcols);
+        u8 j;
+        for (j = 0; j < 8; j++) {
+            u8 mask = 0x80 >> j;
+            vgahw_grdc_write(0x08, mask);
+            GET_FARVAR(SEG_GRAPH, *dest_far);
+            if (GET_GLOBAL(fdata_g[src + i]) & mask)
+                SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
+            else
+                SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
+        }
+    }
+    vgahw_grdc_write(0x08, 0xff);
+    vgahw_grdc_write(0x05, 0x00);
+    vgahw_grdc_write(0x03, 0x00);
+}
+
+static void
+write_gfx_char_cga(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    u8 *fdata_g = vgafont8;
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    u16 addr = (cp.x * bpp) + cp.y * 320;
+    u16 src = ca.car * 8;
+    u8 i;
+    for (i = 0; i < 8; i++) {
+        u8 *dest_far = (void*)(addr + (i >> 1) * 80);
+        if (i & 1)
+            dest_far += 0x2000;
+        u8 mask = 0x80;
+        if (bpp == 1) {
+            u8 data = 0;
+            if (ca.attr & 0x80)
+                data = GET_FARVAR(SEG_CTEXT, *dest_far);
+            u8 j;
+            for (j = 0; j < 8; j++) {
+                if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+                    if (ca.attr & 0x80)
+                        data ^= (ca.attr & 0x01) << (7 - j);
+                    else
+                        data |= (ca.attr & 0x01) << (7 - j);
+                }
+                mask >>= 1;
+            }
+            SET_FARVAR(SEG_CTEXT, *dest_far, data);
+        } else {
+            while (mask > 0) {
+                u8 data = 0;
+                if (ca.attr & 0x80)
+                    data = GET_FARVAR(SEG_CTEXT, *dest_far);
+                u8 j;
+                for (j = 0; j < 4; j++) {
+                    if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+                        if (ca.attr & 0x80)
+                            data ^= (ca.attr & 0x03) << ((3 - j) * 2);
+                        else
+                            data |= (ca.attr & 0x03) << ((3 - j) * 2);
+                    }
+                    mask >>= 1;
+                }
+                SET_FARVAR(SEG_CTEXT, *dest_far, data);
+                dest_far += 1;
+            }
+        }
+    }
+}
+
+static void
+write_gfx_char_lin(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    // Get the dimensions
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    u8 *fdata_g = vgafont8;
+    u16 addr = cp.x * 8 + cp.y * nbcols * 64;
+    u16 src = ca.car * 8;
+    u8 i;
+    for (i = 0; i < 8; i++) {
+        u8 *dest_far = (void*)(addr + i * nbcols * 8);
+        u8 mask = 0x80;
+        u8 j;
+        for (j = 0; j < 8; j++) {
+            u8 data = 0x00;
+            if (GET_GLOBAL(fdata_g[src + i]) & mask)
+                data = ca.attr;
+            SET_FARVAR(SEG_GRAPH, dest_far[j], data);
+            mask >>= 1;
+        }
+    }
+}
+
+static void
+write_text_char(struct vgamode_s *vmode_g
+                , struct cursorpos cp, struct carattr ca)
+{
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    // Compute the address
+    void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                                + (cp.x + cp.y * nbcols) * 2);
+
+    if (ca.use_attr) {
+        u16 dummy = (ca.attr << 8) | ca.car;
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
+    } else {
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
+    }
+}
+
+void
+vgafb_write_char(struct cursorpos cp, struct carattr ca)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // FIXME gfx mode not complete
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        write_text_char(vmode_g, cp, ca);
+        break;
+    case PLANAR4:
+    case PLANAR1:
+        write_gfx_char_pl4(vmode_g, cp, ca);
+        break;
+    case CGA:
+        write_gfx_char_cga(vmode_g, cp, ca);
+        break;
+    case LINEAR8:
+        write_gfx_char_lin(vmode_g, cp, ca);
+        break;
+    }
+}
+
+struct carattr
+vgafb_read_char(struct cursorpos cp)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        goto fail;
+
+    if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
+        // FIXME gfx mode
+        dprintf(1, "Read char in graphics mode\n");
+        goto fail;
+    }
+
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    // Compute the address
+    u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                               + (cp.x + cp.y * nbcols) * 2);
+    u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
+    struct carattr ca = {v, v>>8, 0};
+    return ca;
+
+fail: ;
+    struct carattr ca2 = {0, 0, 0};
+    return ca2;
+}
+
+
+/****************************************************************
+ * Read/write pixels
+ ****************************************************************/
+
+void
+vgafb_write_pixel(u8 color, u16 x, u16 y)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        return;
+
+    u8 *addr_far, mask, attr, data;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case PLANAR4:
+    case PLANAR1:
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
+        vgahw_grdc_write(0x08, mask);
+        vgahw_grdc_write(0x05, 0x02);
+        data = GET_FARVAR(SEG_GRAPH, *addr_far);
+        if (color & 0x80)
+            vgahw_grdc_write(0x03, 0x18);
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
+        vgahw_grdc_write(0x08, 0xff);
+        vgahw_grdc_write(0x05, 0x00);
+        vgahw_grdc_write(0x03, 0x00);
+        break;
+    case CGA:
+        if (GET_GLOBAL(vmode_g->pixbits) == 2)
+            addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+        else
+            addr_far = (void*)((x >> 3) + (y >> 1) * 80);
+        if (y & 1)
+            addr_far += 0x2000;
+        data = GET_FARVAR(SEG_CTEXT, *addr_far);
+        if (GET_GLOBAL(vmode_g->pixbits) == 2) {
+            attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
+            mask = 0x03 << ((3 - (x & 0x03)) * 2);
+        } else {
+            attr = (color & 0x01) << (7 - (x & 0x07));
+            mask = 0x01 << (7 - (x & 0x07));
+        }
+        if (color & 0x80) {
+            data ^= attr;
+        } else {
+            data &= ~mask;
+            data |= attr;
+        }
+        SET_FARVAR(SEG_CTEXT, *addr_far, data);
+        break;
+    case LINEAR8:
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
+        break;
+    }
+}
+
+u8
+vgafb_read_pixel(u16 x, u16 y)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return 0;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        return 0;
+
+    u8 *addr_far, mask, attr=0, data, i;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case PLANAR4:
+    case PLANAR1:
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
+        attr = 0x00;
+        for (i = 0; i < 4; i++) {
+            vgahw_grdc_write(0x04, i);
+            data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
+            if (data > 0)
+                attr |= (0x01 << i);
+        }
+        break;
+    case CGA:
+        addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+        if (y & 1)
+            addr_far += 0x2000;
+        data = GET_FARVAR(SEG_CTEXT, *addr_far);
+        if (GET_GLOBAL(vmode_g->pixbits) == 2)
+            attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
+        else
+            attr = (data >> (7 - (x & 0x07))) & 0x01;
+        break;
+    case LINEAR8:
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+        attr = GET_FARVAR(SEG_GRAPH, *addr_far);
+        break;
+    }
+    return attr;
+}
+
+
+/****************************************************************
+ * Font loading
+ ****************************************************************/
+
+void
+vgafb_load_font(u16 seg, void *src_far, u16 count
+                , u16 start, u8 destflags, u8 fontsize)
+{
+    get_font_access();
+    u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
+    void *dest_far = (void*)(blockaddr + start*32);
+    u16 i;
+    for (i = 0; i < count; i++)
+        memcpy_far(SEG_GRAPH, dest_far + i*32
+                   , seg, src_far + i*fontsize, fontsize);
+    release_font_access();
+}
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgafonts.c b/qemu-0.15.x/roms/seabios/vgasrc/vgafonts.c
new file mode 100644
index 0000000..8c1752c
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgafonts.c
@@ -0,0 +1,785 @@
+#include "vgatables.h" // vgafont8
+
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */
+u8 vgafont8[256 * 8] VAR16 = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+    0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+    0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+    0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+    0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+    0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+    0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+    0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+    0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+    0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+    0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+    0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+    0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+    0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+    0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+    0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+    0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+    0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+    0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+    0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+    0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+    0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+    0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+    0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+    0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+    0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+    0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+    0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+    0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+    0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+    0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+    0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+    0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+    0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+    0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+    0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+    0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+    0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+    0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+    0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+    0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+    0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+    0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+    0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+    0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+    0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+    0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+    0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+    0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+    0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+    0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+    0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+    0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+    0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+    0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+    0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+    0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+    0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+    0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+    0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+    0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+    0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+    0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+    0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+    0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+    0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+    0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+    0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+    0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+    0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+    0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+    0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+    0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+    0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+    0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+    0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+    0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+    0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+    0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+    0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+    0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+    0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+    0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+    0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+    0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+    0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+    0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+    0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+    0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+    0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+    0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+    0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+    0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+    0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+    0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+    0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+    0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+    0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+    0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+    0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+    0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+    0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+    0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+    0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+    0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+    0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+    0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+    0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+    0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+    0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+    0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+    0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+    0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+    0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+    0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+    0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+    0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+    0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+    0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+    0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+    0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+    0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+    0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+    0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+    0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+    0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+    0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+    0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+    0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+    0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+    0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+    0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+    0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+    0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+    0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+    0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+    0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+    0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+    0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+    0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+    0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+    0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+    0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+    0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+    0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+    0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+    0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+    0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+    0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+    0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+    0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+    0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+    0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+    0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+    0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+    0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+    0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+    0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+    0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+    0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+    0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+    0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+    0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+    0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+    0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+    0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+    0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+    0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+    0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+    0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+    0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+    0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+    0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+    0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+    0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+    0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+    0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+    0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+    0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+    0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+    0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont14[256 * 14] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont16[256 * 16] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+u8 vgafont14alt[1] VAR16;
+u8 vgafont16alt[1] VAR16;
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgaio.c b/qemu-0.15.x/roms/seabios/vgasrc/vgaio.c
new file mode 100644
index 0000000..ffded34
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgaio.c
@@ -0,0 +1,555 @@
+// VGA io port access
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // outb
+#include "farptr.h" // SET_FARVAR
+#include "biosvar.h" // GET_BDA
+#include "vgatables.h" // VGAREG_*
+
+// TODO
+//  * replace direct in/out calls with wrapper functions
+
+
+/****************************************************************
+ * Attribute control
+ ****************************************************************/
+
+void
+vgahw_screen_disable(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x00, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_screen_enable(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_border_color(u8 color)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x00, VGAREG_ACTL_ADDRESS);
+    u8 v1 = color & 0x0f;
+    if (v1 & 0x08)
+        v1 += 0x08;
+    outb(v1, VGAREG_ACTL_WRITE_DATA);
+
+    u8 v2 = color & 0x10;
+    int i;
+    for (i = 1; i < 4; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+
+        u8 cur = inb(VGAREG_ACTL_READ_DATA);
+        cur &= 0xef;
+        cur |= v2;
+        outb(cur, VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_overscan_border_color(u8 color)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    outb(color, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_overscan_border_color(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    u8 v = inb(VGAREG_ACTL_READ_DATA);
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    return v;
+}
+
+void
+vgahw_set_palette(u8 palid)
+{
+    inb(VGAREG_ACTL_RESET);
+    palid &= 0x01;
+    int i;
+    for (i = 1; i < 4; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+
+        u8 v = inb(VGAREG_ACTL_READ_DATA);
+        v &= 0xfe;
+        v |= palid;
+        outb(v, VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_single_palette_reg(u8 reg, u8 val)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(reg, VGAREG_ACTL_ADDRESS);
+    outb(val, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_single_palette_reg(u8 reg)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(reg, VGAREG_ACTL_ADDRESS);
+    u8 v = inb(VGAREG_ACTL_READ_DATA);
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    return v;
+}
+
+void
+vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
+{
+    inb(VGAREG_ACTL_RESET);
+    int i;
+    for (i = 0; i < 0x10; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+        u8 val = GET_FARVAR(seg, *data_far);
+        outb(val, VGAREG_ACTL_WRITE_DATA);
+        data_far++;
+    }
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
+{
+    int i;
+    for (i = 0; i < 0x10; i++) {
+        inb(VGAREG_ACTL_RESET);
+        outb(i, VGAREG_ACTL_ADDRESS);
+        SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+        data_far++;
+    }
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_toggle_intensity(u8 flag)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
+    outb(val, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_select_video_dac_color_page(u8 flag, u8 data)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val = inb(VGAREG_ACTL_READ_DATA);
+    if (!(flag & 0x01)) {
+        // select paging mode
+        val = (val & 0x7f) | (data << 7);
+        outb(val, VGAREG_ACTL_WRITE_DATA);
+        outb(0x20, VGAREG_ACTL_ADDRESS);
+        return;
+    }
+    // select page
+    inb(VGAREG_ACTL_RESET);
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    if (!(val & 0x80))
+        data <<= 2;
+    data &= 0x0f;
+    outb(data, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
+
+    inb(VGAREG_ACTL_RESET);
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
+    if (!(val1 & 0x01))
+        val2 >>= 2;
+
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+
+    *pmode = val1;
+    *curpage = val2;
+}
+
+
+/****************************************************************
+ * DAC control
+ ****************************************************************/
+
+void
+vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
+{
+    outb(start, VGAREG_DAC_WRITE_ADDRESS);
+    while (count) {
+        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+        data_far++;
+        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+        data_far++;
+        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+        data_far++;
+        count--;
+    }
+}
+
+void
+vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
+{
+    outb(start, VGAREG_DAC_READ_ADDRESS);
+    while (count) {
+        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+        data_far++;
+        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+        data_far++;
+        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+        data_far++;
+        count--;
+    }
+}
+
+void
+vgahw_set_pel_mask(u8 val)
+{
+    outb(val, VGAREG_PEL_MASK);
+}
+
+u8
+vgahw_get_pel_mask(void)
+{
+    return inb(VGAREG_PEL_MASK);
+}
+
+void
+vgahw_save_dac_state(u16 seg, struct saveDACcolors *info)
+{
+    /* XXX: check this */
+    SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
+    SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
+    SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
+    vgahw_get_dac_regs(seg, info->dac, 0, 256);
+    SET_FARVAR(seg, info->color_select, 0);
+}
+
+void
+vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
+{
+    outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
+    vgahw_set_dac_regs(seg, info->dac, 0, 256);
+    outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
+}
+
+
+/****************************************************************
+ * Memory control
+ ****************************************************************/
+
+void
+vgahw_sequ_write(u8 index, u8 value)
+{
+    outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
+}
+
+void
+vgahw_grdc_write(u8 index, u8 value)
+{
+    outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
+}
+
+void
+vgahw_set_text_block_specifier(u8 spec)
+{
+    outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
+}
+
+void
+get_font_access(void)
+{
+    outw(0x0100, VGAREG_SEQU_ADDRESS);
+    outw(0x0402, VGAREG_SEQU_ADDRESS);
+    outw(0x0704, VGAREG_SEQU_ADDRESS);
+    outw(0x0300, VGAREG_SEQU_ADDRESS);
+    outw(0x0204, VGAREG_GRDC_ADDRESS);
+    outw(0x0005, VGAREG_GRDC_ADDRESS);
+    outw(0x0406, VGAREG_GRDC_ADDRESS);
+}
+
+void
+release_font_access(void)
+{
+    outw(0x0100, VGAREG_SEQU_ADDRESS);
+    outw(0x0302, VGAREG_SEQU_ADDRESS);
+    outw(0x0304, VGAREG_SEQU_ADDRESS);
+    outw(0x0300, VGAREG_SEQU_ADDRESS);
+    u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
+    outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
+    outw(0x0004, VGAREG_GRDC_ADDRESS);
+    outw(0x1005, VGAREG_GRDC_ADDRESS);
+}
+
+
+/****************************************************************
+ * CRTC registers
+ ****************************************************************/
+
+static u16
+get_crtc(void)
+{
+    return GET_BDA(crtc_address);
+}
+
+void
+vgahw_set_cursor_shape(u8 start, u8 end)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0a, crtc_addr);
+    outb(start, crtc_addr + 1);
+    outb(0x0b, crtc_addr);
+    outb(end, crtc_addr + 1);
+}
+
+void
+vgahw_set_active_page(u16 address)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0c, crtc_addr);
+    outb((address & 0xff00) >> 8, crtc_addr + 1);
+    outb(0x0d, crtc_addr);
+    outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_cursor_pos(u16 address)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0e, crtc_addr);
+    outb((address & 0xff00) >> 8, crtc_addr + 1);
+    outb(0x0f, crtc_addr);
+    outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_scan_lines(u8 lines)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x09, crtc_addr);
+    u8 crtc_r9 = inb(crtc_addr + 1);
+    crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+    outb(crtc_r9, crtc_addr + 1);
+}
+
+// Get vertical display end
+u16
+vgahw_get_vde(void)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x12, crtc_addr);
+    u16 vde = inb(crtc_addr + 1);
+    outb(0x07, crtc_addr);
+    u8 ovl = inb(crtc_addr + 1);
+    vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+    return vde;
+}
+
+
+/****************************************************************
+ * Save/Restore/Set state
+ ****************************************************************/
+
+void
+vgahw_save_state(u16 seg, struct saveVideoHardware *info)
+{
+    u16 crtc_addr = get_crtc();
+    SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
+    SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
+    SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
+    inb(VGAREG_ACTL_RESET);
+    u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
+    SET_FARVAR(seg, info->actl_index, ar_index);
+    SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
+
+    u16 i;
+    for (i=0; i<4; i++) {
+        outb(i+1, VGAREG_SEQU_ADDRESS);
+        SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
+    }
+    outb(0, VGAREG_SEQU_ADDRESS);
+    SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
+
+    for (i=0; i<25; i++) {
+        outb(i, crtc_addr);
+        SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
+    }
+
+    for (i=0; i<20; i++) {
+        inb(VGAREG_ACTL_RESET);
+        outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+        SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
+    }
+    inb(VGAREG_ACTL_RESET);
+
+    for (i=0; i<9; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
+    }
+
+    SET_FARVAR(seg, info->crtc_addr, crtc_addr);
+
+    /* XXX: read plane latches */
+    for (i=0; i<4; i++)
+        SET_FARVAR(seg, info->plane_latch[i], 0);
+}
+
+void
+vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
+{
+    // Reset Attribute Ctl flip-flop
+    inb(VGAREG_ACTL_RESET);
+
+    u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
+
+    u16 i;
+    for (i=0; i<4; i++) {
+        outb(i+1, VGAREG_SEQU_ADDRESS);
+        outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
+    }
+    outb(0, VGAREG_SEQU_ADDRESS);
+    outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
+
+    // Disable CRTC write protection
+    outw(0x0011, crtc_addr);
+    // Set CRTC regs
+    for (i=0; i<25; i++)
+        if (i != 0x11) {
+            outb(i, crtc_addr);
+            outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
+        }
+    // select crtc base address
+    u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+    if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
+        v |= 0x01;
+    outb(v, VGAREG_WRITE_MISC_OUTPUT);
+
+    // enable write protection if needed
+    outb(0x11, crtc_addr);
+    outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
+
+    // Set Attribute Ctl
+    u16 ar_index = GET_FARVAR(seg, info->actl_index);
+    inb(VGAREG_ACTL_RESET);
+    for (i=0; i<20; i++) {
+        outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+        outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(ar_index, VGAREG_ACTL_ADDRESS);
+    inb(VGAREG_ACTL_RESET);
+
+    for (i=0; i<9; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
+    }
+
+    outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
+    outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
+    outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
+    outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
+}
+
+void
+vgahw_set_mode(struct VideoParam_s *vparam_g)
+{
+    // Reset Attribute Ctl flip-flop
+    inb(VGAREG_ACTL_RESET);
+
+    // Set Attribute Ctl
+    u16 i;
+    for (i = 0; i <= 0x13; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    outb(0x00, VGAREG_ACTL_WRITE_DATA);
+
+    // Set Sequencer Ctl
+    outb(0, VGAREG_SEQU_ADDRESS);
+    outb(0x03, VGAREG_SEQU_DATA);
+    for (i = 1; i <= 4; i++) {
+        outb(i, VGAREG_SEQU_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
+    }
+
+    // Set Grafx Ctl
+    for (i = 0; i <= 8; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
+    }
+
+    // Set CRTC address VGA or MDA
+    u8 miscreg = GET_GLOBAL(vparam_g->miscreg);
+    u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+    if (!(miscreg & 1))
+        crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+    // Disable CRTC write protection
+    outw(0x0011, crtc_addr);
+    // Set CRTC regs
+    for (i = 0; i <= 0x18; i++) {
+        outb(i, crtc_addr);
+        outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
+    }
+
+    // Set the misc register
+    outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
+
+    // Enable video
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    inb(VGAREG_ACTL_RESET);
+}
+
+
+/****************************************************************
+ * Misc
+ ****************************************************************/
+
+void
+vgahw_enable_video_addressing(u8 disable)
+{
+    u8 v = (disable & 1) ? 0x00 : 0x02;
+    u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
+    outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
+}
+
+void
+vgahw_init(void)
+{
+    // switch to color mode and enable CPU access 480 lines
+    outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
+    // more than 64k 3C4/04
+    outb(0x04, VGAREG_SEQU_ADDRESS);
+    outb(0x02, VGAREG_SEQU_DATA);
+}
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgalayout.lds.S b/qemu-0.15.x/roms/seabios/vgasrc/vgalayout.lds.S
new file mode 100644
index 0000000..08a5f32
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgalayout.lds.S
@@ -0,0 +1,24 @@
+// Linker definitions for an option rom
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH("i386")
+ENTRY(_optionrom_entry)
+SECTIONS
+{
+        .text 0 : {
+                KEEP(*(.rom.header))
+                *(.text.*)
+                _rodata = . ;
+                *(.rodata.__func__.*)
+                *(.rodata.str1.1)
+                *(.data16.*)
+                }
+
+        // Discard regular data sections to force a link error if
+        // 16bit code attempts to access data not marked with VAR16.
+        /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+}
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgatables.c b/qemu-0.15.x/roms/seabios/vgasrc/vgatables.c
new file mode 100644
index 0000000..0587e65
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgatables.c
@@ -0,0 +1,438 @@
+// Tables used by VGA bios
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin at koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "vgatables.h" // struct VideoParamTableEntry_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Video parameter table
+ ****************************************************************/
+
+struct VideoParam_s video_param_table[] VAR16 = {
+    // index=0x00 no mode defined
+    {},
+    // index=0x01 no mode defined
+    {},
+    // index=0x02 no mode defined
+    {},
+    // index=0x03 no mode defined
+    {},
+    // index=0x04 vga mode 0x04
+    { 40, 24, 8, 0x0800,      /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x05 vga mode 0x05 */
+    { 40, 24, 8, 0x0800,     /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x06 vga mode 0x06 */
+    { 80, 24, 8, 0x1000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x01, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x07 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x08 no mode defined */
+    {},
+    /* index=0x09 no mode defined */
+    {},
+    /* index=0x0a no mode defined */
+    {},
+    /* index=0x0b no mode defined */
+    {},
+    /* index=0x0c no mode defined */
+    {},
+    /* index=0x0d vga mode 0x0d */
+    { 40, 24, 8, 0x2000,     /* tw, th-1, ch, slength */
+      { 0x09, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+        0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x0e vga mode 0x0e */
+    { 80, 24, 8, 0x4000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+        0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x0f no mode defined */
+    {},
+    /* index=0x10 no mode defined */
+    {},
+    /* index=0x11 vga mode 0x0f */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+        0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x12 vga mode 0x10 */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x13 no mode defined */
+    {},
+    /* index=0x14 no mode defined */
+    {},
+    /* index=0x15 no mode defined */
+    {},
+    /* index=0x16 no mode defined */
+    {},
+    /* index=0x17 vga mode 0x01 */
+    { 40, 24, 16, 0x0800,    /* tw, th-1, ch, slength */
+      { 0x08, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x18 vga mode 0x03 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x19 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1a vga mode 0x11 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1b vga mode 0x12 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x1c vga mode 0x13 */
+    { 40, 24, 8, 0x0000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x0e },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+        0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+        0x41, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x1d vga mode 0x6a */
+    { 100, 36, 16, 0x0000,   /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+};
+
+
+/****************************************************************
+ * Palette definitions
+ ****************************************************************/
+
+/* Mono */
+static u8 palette0[] VAR16 = {
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f
+};
+
+static u8 palette1[] VAR16 = {
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette2[] VAR16 = {
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,
+  0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+  0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a,
+  0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+  0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f,
+  0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+  0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a,
+  0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+  0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f,
+  0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+  0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a,
+  0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette3[] VAR16 = {
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+  0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+  0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b,
+  0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+  0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28,
+  0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f,
+  0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+  0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00,
+  0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+  0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f,
+  0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+  0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f,
+  0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+  0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f,
+  0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+  0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37,
+  0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+  0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f,
+  0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+  0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d,
+  0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+  0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a,
+  0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+  0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c,
+  0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+  0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00,
+  0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+  0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15,
+  0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+  0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c,
+  0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+  0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e,
+  0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+  0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18,
+  0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+  0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c,
+  0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+  0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14,
+  0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+  0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a,
+  0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+  0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10,
+  0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+  0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00,
+  0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+  0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c,
+  0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+  0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10,
+  0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+  0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08,
+  0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+  0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e,
+  0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+  0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10,
+  0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+  0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b,
+  0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+  0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f,
+  0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+
+/****************************************************************
+ * Video mode list
+ ****************************************************************/
+
+#define PAL(x) x, sizeof(x)
+#define VPARAM(x) &video_param_table[x]
+
+static struct vgamode_s vga_modes[] VAR16 = {
+    //mode vparam        model bits  sstart     pelm  dac
+    {0x00, VPARAM(0x17), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x01, VPARAM(0x17), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x02, VPARAM(0x18), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x03, VPARAM(0x18), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x04, VPARAM(0x04), CGA,     2, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x05, VPARAM(0x05), CGA,     2, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x06, VPARAM(0x06), CGA,     1, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x07, VPARAM(0x07), MTEXT,   4, SEG_MTEXT, 0xFF, PAL(palette0)},
+    {0x0D, VPARAM(0x0d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+    {0x0E, VPARAM(0x0e), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+    {0x0F, VPARAM(0x11), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette0)},
+    {0x10, VPARAM(0x12), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x11, VPARAM(0x1a), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x12, VPARAM(0x1b), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x13, VPARAM(0x1c), LINEAR8, 8, SEG_GRAPH, 0xFF, PAL(palette3)},
+    {0x6A, VPARAM(0x1d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+};
+
+struct vgamode_s *
+find_vga_entry(u8 mode)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(vga_modes); i++) {
+        struct vgamode_s *vmode_g = &vga_modes[i];
+        if (GET_GLOBAL(vmode_g->svgamode) == mode)
+            return vmode_g;
+    }
+    return NULL;
+}
+
+u16 video_save_pointer_table[14] VAR16;
+
+
+/****************************************************************
+ * Static functionality table
+ ****************************************************************/
+
+u8 static_functionality[0x10] VAR16 = {
+ /* 0 */ 0xff,  // All modes supported #1
+ /* 1 */ 0xe0,  // All modes supported #2
+ /* 2 */ 0x0f,  // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00,  // reserved
+ /* 7 */ 0x07,  // 200, 350, 400 scan lines
+ /* 8 */ 0x02,  // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08,  // total number of charset blocks in text mode
+ /* a */ 0xe7,  // Change to add new functions
+ /* b */ 0x0c,  // Change to add new functions
+ /* c */ 0x00,  // reserved
+ /* d */ 0x00,  // reserved
+ /* e */ 0x00,  // Change to add new functions
+ /* f */ 0x00   // reserved
+};
diff --git a/qemu-0.15.x/roms/seabios/vgasrc/vgatables.h b/qemu-0.15.x/roms/seabios/vgasrc/vgatables.h
new file mode 100644
index 0000000..1e76b3a
--- /dev/null
+++ b/qemu-0.15.x/roms/seabios/vgasrc/vgatables.h
@@ -0,0 +1,217 @@
+#ifndef __VGATABLES_H
+#define __VGATABLES_H
+
+#include "types.h" // u8
+#include "farptr.h" // struct segoff_s
+
+/*
+ *
+ * VGA registers
+ *
+ */
+#define VGAREG_ACTL_ADDRESS            0x3c0
+#define VGAREG_ACTL_WRITE_DATA         0x3c0
+#define VGAREG_ACTL_READ_DATA          0x3c1
+
+#define VGAREG_INPUT_STATUS            0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT       0x3c2
+#define VGAREG_VIDEO_ENABLE            0x3c3
+#define VGAREG_SEQU_ADDRESS            0x3c4
+#define VGAREG_SEQU_DATA               0x3c5
+
+#define VGAREG_PEL_MASK                0x3c6
+#define VGAREG_DAC_STATE               0x3c7
+#define VGAREG_DAC_READ_ADDRESS        0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS       0x3c8
+#define VGAREG_DAC_DATA                0x3c9
+
+#define VGAREG_READ_FEATURE_CTL        0x3ca
+#define VGAREG_READ_MISC_OUTPUT        0x3cc
+
+#define VGAREG_GRDC_ADDRESS            0x3ce
+#define VGAREG_GRDC_DATA               0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS        0x3b4
+#define VGAREG_MDA_CRTC_DATA           0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS        0x3d4
+#define VGAREG_VGA_CRTC_DATA           0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL   0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL   0x3da
+#define VGAREG_ACTL_RESET              0x3da
+
+#define VGAREG_MDA_MODECTL             0x3b8
+#define VGAREG_CGA_MODECTL             0x3d8
+#define VGAREG_CGA_PALETTE             0x3d9
+
+/* Video memory */
+#define SEG_GRAPH 0xA000
+#define SEG_CTEXT 0xB800
+#define SEG_MTEXT 0xB000
+
+/*
+ * Tables of default values for each mode
+ */
+#define TEXT       0x80
+
+#define CTEXT      (0x00 | TEXT)
+#define MTEXT      (0x01 | TEXT)
+#define CGA        0x02
+#define PLANAR1    0x03
+#define PLANAR4    0x04
+#define LINEAR8    0x05
+
+// for SVGA
+#define LINEAR15   0x10
+#define LINEAR16   0x11
+#define LINEAR24   0x12
+#define LINEAR32   0x13
+
+#define SCREEN_IO_START(x,y,p) (((((x)*(y)) | 0x00ff) + 1) * (p))
+#define SCREEN_MEM_START(x,y,p) SCREEN_IO_START(((x)*2),(y),(p))
+
+/* standard BIOS Video Parameter Table */
+struct VideoParam_s {
+    u8 twidth;
+    u8 theightm1;
+    u8 cheight;
+    u16 slength;
+    u8 sequ_regs[4];
+    u8 miscreg;
+    u8 crtc_regs[25];
+    u8 actl_regs[20];
+    u8 grdc_regs[9];
+} PACKED;
+
+struct vgamode_s {
+    u8 svgamode;
+    struct VideoParam_s *vparam;
+    u8 memmodel;    /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+    u8 pixbits;
+    u16 sstart;
+    u8 pelmask;
+    u8 *dac;
+    u16 dacsize;
+};
+
+struct saveVideoHardware {
+    u8 sequ_index;
+    u8 crtc_index;
+    u8 grdc_index;
+    u8 actl_index;
+    u8 feature;
+    u8 sequ_regs[4];
+    u8 sequ0;
+    u8 crtc_regs[25];
+    u8 actl_regs[20];
+    u8 grdc_regs[9];
+    u16 crtc_addr;
+    u8 plane_latch[4];
+};
+
+struct saveBDAstate {
+    u8 video_mode;
+    u16 video_cols;
+    u16 video_pagesize;
+    u16 crtc_address;
+    u8 video_rows;
+    u16 char_height;
+    u8 video_ctl;
+    u8 video_switches;
+    u8 modeset_ctl;
+    u16 cursor_type;
+    u16 cursor_pos[8];
+    u16 video_pagestart;
+    u8 video_page;
+    /* current font */
+    struct segoff_s font0;
+    struct segoff_s font1;
+};
+
+struct saveDACcolors {
+    u8 rwmode;
+    u8 peladdr;
+    u8 pelmask;
+    u8 dac[768];
+    u8 color_select;
+};
+
+// vgatables.c
+struct vgamode_s *find_vga_entry(u8 mode);
+extern u16 video_save_pointer_table[];
+extern struct VideoParam_s video_param_table[];
+extern u8 static_functionality[];
+
+// vgafonts.c
+extern u8 vgafont8[];
+extern u8 vgafont14[];
+extern u8 vgafont16[];
+extern u8 vgafont14alt[];
+extern u8 vgafont16alt[];
+
+// vga.c
+struct carattr {
+    u8 car, attr, use_attr;
+};
+struct cursorpos {
+    u8 x, y, page;
+};
+
+// vgafb.c
+void clear_screen(struct vgamode_s *vmode_g);
+void vgafb_scroll(int nblines, int attr
+                  , struct cursorpos ul, struct cursorpos lr);
+void vgafb_write_char(struct cursorpos cp, struct carattr ca);
+struct carattr vgafb_read_char(struct cursorpos cp);
+void vgafb_write_pixel(u8 color, u16 x, u16 y);
+u8 vgafb_read_pixel(u16 x, u16 y);
+void vgafb_load_font(u16 seg, void *src_far, u16 count
+                     , u16 start, u8 destflags, u8 fontsize);
+
+// vgaio.c
+void vgahw_screen_disable(void);
+void vgahw_screen_enable(void);
+void vgahw_set_border_color(u8 color);
+void vgahw_set_overscan_border_color(u8 color);
+u8 vgahw_get_overscan_border_color(void);
+void vgahw_set_palette(u8 palid);
+void vgahw_set_single_palette_reg(u8 reg, u8 val);
+u8 vgahw_get_single_palette_reg(u8 reg);
+void vgahw_set_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_get_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_toggle_intensity(u8 flag);
+void vgahw_select_video_dac_color_page(u8 flag, u8 data);
+void vgahw_read_video_dac_state(u8 *pmode, u8 *curpage);
+void vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_set_pel_mask(u8 val);
+u8 vgahw_get_pel_mask(void);
+void vgahw_save_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_sequ_write(u8 index, u8 value);
+void vgahw_grdc_write(u8 index, u8 value);
+void vgahw_set_text_block_specifier(u8 spec);
+void get_font_access(void);
+void release_font_access(void);
+void vgahw_set_cursor_shape(u8 start, u8 end);
+void vgahw_set_active_page(u16 address);
+void vgahw_set_cursor_pos(u16 address);
+void vgahw_set_scan_lines(u8 lines);
+u16 vgahw_get_vde(void);
+void vgahw_save_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_restore_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_set_mode(struct VideoParam_s *vparam_g);
+void vgahw_enable_video_addressing(u8 disable);
+void vgahw_init(void);
+
+// clext.c
+void cirrus_set_video_mode(u8 mode);
+void cirrus_init(void);
+
+// vbe.c -- not implemented yet.
+#define VBE_DISPI_DISABLED              0x00
+void dispi_set_enable(int enable);
+void vbe_init(void);
+int vbe_has_vbe_display(void);
+
+#endif // vgatables.h
diff --git a/qemu-0.15.x/roms/vgabios/.cvsignore b/qemu-0.15.x/roms/vgabios/.cvsignore
new file mode 100644
index 0000000..1df04b7
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/.cvsignore
@@ -0,0 +1 @@
+vbetables.h
diff --git a/qemu-0.15.x/roms/vgabios/BUGS b/qemu-0.15.x/roms/vgabios/BUGS
new file mode 100644
index 0000000..785f4dc
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/BUGS
@@ -0,0 +1,3 @@
+Not all the functions have been implemented yet.
+
+Please report any bugs to <info at vruppert.de>
diff --git a/qemu-0.15.x/roms/vgabios/COPYING b/qemu-0.15.x/roms/vgabios/COPYING
new file mode 100644
index 0000000..223ede7
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/qemu-0.15.x/roms/vgabios/ChangeLog b/qemu-0.15.x/roms/vgabios/ChangeLog
new file mode 100644
index 0000000..dbaed5d
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/ChangeLog
@@ -0,0 +1,1311 @@
+2009-04-07 20:18  vruppert
+
+	* vgabios.c (1.69):
+
+	- biosfn_write_teletype: fixed attribute when scrolling in text mode
+
+2009-04-06 20:17  vruppert
+
+	* ChangeLog (1.28), README (1.17):
+
+	- preparing for release 0.6c
+
+2009-01-25 16:46  vruppert
+
+	* vbe.c (1.62), vbe.h (1.28), vbetables-gen.c (1.5):
+
+	- added support for a lot more non-standard VBE modes (e.g. widescreen modes)
+	- requires latest Bochs VBE code (16 MB video memory, VBE_DISPI_ID5, VRAM size
+	  in 64k pages stored in VBE register)
+	- check if VBE mode is supported with current VRAM size
+
+2009-01-24 11:02  vruppert
+
+	* clext.c (1.14), vbe.c (1.61), vgabios.c (1.68):
+
+	- use VBE LFB address from PCI base address if present (rewrite of the cirrus
+	  specific function in main vgabios code)
+	- removed unnecessary spaces
+
+2008-12-14 09:29  vruppert
+
+	* clext.c (1.13):
+
+	- added DPMS support to cirrus vgabios (patch from Gleb Natapov)
+
+2008-05-30 17:28  vruppert
+
+	* README (1.16):
+
+	- updated for release 0.6b
+
+2008-05-22 12:55  vruppert
+
+	* ChangeLog (1.27), README (1.15):
+
+	- preparations for release 0.6b
+
+2008-05-11 08:40  vruppert
+
+	* biossums.c (1.6):
+
+	- fixed a warning
+
+2008-03-02 08:47  vruppert
+
+	* vbe.c (1.60):
+
+	- added debug message for unsupported VBE modes
+
+2008-02-24 09:18  vruppert
+
+	* vbe.c (1.59):
+
+	- in LFB modes the number of banks must be set to 1
+
+2008-01-27 10:44  vruppert
+
+	* Makefile (1.21), biossums.c (1.5), vgabios.c (1.67):
+
+	- added PCI data structure for the Cirrus VGABIOS images
+	- added support for the PCI data structure in biossums
+	- updated year in copyright
+
+2008-01-26 11:46  vruppert
+
+	* BUGS (1.4), Makefile (1.20), README (1.14), TODO (1.13), vbe_display_api.txt (1.14):
+
+	- whitespace cleanup
+
+2006-11-26 10:43  vruppert
+
+	* Makefile (1.19):
+
+	- disable the generation of linemarkers by the preprocessor, since the latest
+	  versions of bcc don't like them
+
+2006-09-02 13:15  vruppert
+
+	* biossums.c (1.4):
+
+	- the biossums utility no longer modifies VGABIOS images with proper checksum
+	  and size
+
+2006-08-19 14:28  vruppert
+
+	* Changelog (1.26), README (1.13), TODO (1.12):
+
+	- updates for 0.6a release
+
+2006-08-19 09:39  vruppert
+
+	* vbe.c (1.58):
+
+	- improved VGA compatible setup for VBE modes (disable CGA and Hercules
+	  compatible memory layout)
+
+2006-08-18 20:39  vruppert
+
+	* vbe.c (1.57):
+
+	- improved VGA compatible setup for >=8bpp VBE modes (CRTC doubleword mode and
+	  GRDC shift register setting added)
+	- now using symbolic name for CRTC address register
+
+2006-08-15 20:42  vruppert
+
+	* vbe.c (1.56), vbetables-gen.c (1.4):
+
+	- init 4bpp VBE modes by a temporary switch to VGA mode 0x6A
+	- all 4bpp VBE modes now enabled
+
+2006-08-14 20:24  vruppert
+
+	* vbe.c (1.55):
+
+	- VGA compatible setup for VBE modes improved (Bochs hack can be removed now)
+
+2006-08-12 07:51  vruppert
+
+	* .cvsignore (1.1):
+
+	- .cvsignore added for auto-generated file
+
+2006-08-12 07:47  vruppert
+
+	* vbe.c (1.54), vbe.h (1.27), vbe_display_api.txt (1.13), vbetables-gen.c (1.3):
+
+	- cleaned up VBE memory size definitions (removed duplicate defines, main
+	  definition now in vbetables-gen.c)
+
+2006-08-09 21:28  vruppert
+
+	* vbetables.h (1.30):
+
+	- removed auto-generated file
+
+2006-08-09 21:26  vruppert
+
+	* vbe.c (1.53), vbe.h (1.26), vbe_display_api.txt (1.12), vbetables-gen.c (1.2),
+	  vbetables.h (1.29):
+
+	- VBE video memory increased to 8 MB
+	- VBE dispi ID changed to B0C4
+	- documentation update
+
+2006-07-11 08:03  vruppert
+
+	* Makefile (1.18), vbetables-gen.c (1.1), vbetables.h (1.28):
+
+	- generate vbetables.h dynamicly
+	  * initial patch from the qemu project by Fabrice Bellard
+	  * only add modes that fit in video memory (still 4 MB)
+	  * several other fixes (e.g. 4 bpp specific stuff, number of pages)
+
+2006-07-10 07:47  vruppert
+
+	* vgabios.c (1.66):
+
+	- biosfn_scroll(): check variable 'i' for underflowing when scrolling downwards
+	  to avoid screen corruption
+
+2006-07-10 07:47  vruppert
+
+	* vbe.c (1.52):
+
+	- VBE set bank functions failure handling added
+	- VBE get/set logical scan line length fixes for the 4bpp mode
+
+2006-07-08 13:27  vruppert
+
+	* vbe.c (1.51), vbetables.h (1.27):
+
+	- added special case for the 4 bpp when setting VBE display start
+	- VBE mode table fixes
+
+2006-07-07 13:30  vruppert
+
+	* clext.c (1.12):
+
+	- bank pointer must be set to 0 after a mode set
+
+2006-06-21 16:58  vruppert
+
+	* vbe.c (1.50), vbetables.h (1.26):
+
+	- improved VBE display capabilities check (X resulution checked now)
+	- removed obsolete defines (LFB always available, always generate dynamic list)
+	- CR/LF to LF fixes
+
+2006-06-18 15:22  vruppert
+
+	* clext.c (1.11), vbe.c (1.49), vbe.h (1.25), vbetables.h (1.25), vgabios.c
+	  (1.65):
+
+	- applied patch from the qemu project (Fabrice Bellard)
+	  * Cirrus SVGA now supports the "no clear" bit when switching to Cirrus or
+	    VESA mode
+	  * Bochs VBE protected mode interface improved
+	  * save/restore video state support for Bochs VBE and standard VGA added
+	  * Bochs VBE prepared for more modi
+
+2006-03-25 10:19  vruppert
+
+	* clext.c (1.10), vgabios.c (1.64), vgatables.h (1.10):
+
+	- applied patch from Fabrice Bellard
+	 * added minimal support for the video parameter table (VPT)
+	 * added Cirrus SVGA mode 0x7b (1600x1200x8)
+
+2005-12-26 19:50  vruppert
+
+	* vbe.c (1.48), vgabios.c (1.63):
+
+	- Bochs VBE protected mode interface added (based on a patch by malc at pulsesoft.com)
+
+2005-12-26 19:50  vruppert
+
+	* biossums.c (1.3):
+
+	- biossums utility now supports VGABIOS sizes up to 64 kBytes
+
+2005-09-21 18:45  vruppert
+
+	* vgatables.h (1.9):
+
+	- mode 0x11: all color planes must be enabled in this 2-color VGA mode
+
+2005-08-30 18:41  vruppert
+
+	* biossums.c (1.2):
+
+	- missing license text added in biossums.c
+
+2005-07-02 18:39  vruppert
+
+	* vgabios.c (1.62):
+
+	- BIOS configuration word usually reports initial mode 80x25 color text
+	- vgabios function 0x0e (write teletype): linefeed (0x0a) only increments the
+	  cursor row value
+
+2005-05-24 16:50  vruppert
+
+	* vbe.c (1.47), vgabios.c (1.61):
+
+	- output to the vgabios info port can be disabled now. It is still enabled by
+	  default and always possible in debug mode. (based on a patch from Alex Beregszaszi)
+
+2005-05-20 16:06  vruppert
+
+	* vbe.c (1.46), vgabios.c (1.60):
+
+	- fixed return value for the default case in the VBE section (non-debug mode)
+	- removed unused macros HALT and PANIC_PORT
+
+2005-03-07 20:39  vruppert
+
+	* README (1.9):
+
+	- updates for 0.5a release
+
+2005-03-06 13:06  vruppert
+
+	* Makefile (1.17):
+
+	- vgabios files with cirrus support added to release target
+
+2005-03-06 12:24  vruppert
+
+	* Makefile (1.16):
+
+	- cross compilation support added (patch from Alex Beregszaszi)
+
+2005-03-05 13:03  vruppert
+
+	* BUGS (1.3), README (1.8), TODO (1.11):
+
+	- documentation updates
+
+2004-12-04 15:26  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.61), VGABIOS-lgpl-latest.cirrus.bin
+	  (1.13), VGABIOS-lgpl-latest.cirrus.debug.bin (1.13),
+	  VGABIOS-lgpl-latest.debug.bin (1.61), clext.c (1.9):
+
+	- Cirrus extension: support for 1280x1024x15 and 1280x1024x16 modes added (patch
+	  from Fabrice Bellard)
+
+2004-08-08 16:53  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.60), VGABIOS-lgpl-latest.cirrus.bin (1.12),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.12),
+	  VGABIOS-lgpl-latest.debug.bin (1.60), clext.c (1.8):
+
+	- use single bank mode for VBE
+	- enable 16k granularity for VBE only
+
+2004-07-30 19:33  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.59), VGABIOS-lgpl-latest.cirrus.bin (1.11),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.11),
+	  VGABIOS-lgpl-latest.debug.bin (1.59), clext.c (1.7):
+
+	- cirrus init: set standard vga mode and reset bitblt
+
+2004-07-22 18:38  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.58), VGABIOS-lgpl-latest.cirrus.bin (1.10),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.10),
+	  VGABIOS-lgpl-latest.debug.bin (1.58), clext.c (1.6), vbe.c (1.45),
+	  vbetables.h (1.24):
+
+	- cirrus extension: tables for mode 1280x1024x8 added
+	- vbe: dispi_set_xres() and dispi_set_virt_width() now modify vga compatible
+	  registers
+	- vbe: mode list entry for mode 800x600x4 fixed
+
+2004-07-18 20:23  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.57), VGABIOS-lgpl-latest.cirrus.bin (1.9),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.9),
+	  VGABIOS-lgpl-latest.debug.bin (1.57), vgabios.c (1.59), vgatables.h (1.8):
+
+	- disable CRTC write protection before setting new values
+	- CRTC line for mode 0x6a fixed
+
+2004-07-07 16:08  vruppert
+
+	* Makefile (1.15), VGABIOS-lgpl-latest.bin (1.56),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.8), VGABIOS-lgpl-latest.cirrus.debug.bin (1.8),
+	  VGABIOS-lgpl-latest.debug.bin (1.56), biossums.c (1.1), clext.c (1.5):
+
+	- biossums utility for the Bochs BIOS adapted for the LGPL'd VGABIOS
+	- VESA3 PMINFO checksum calculated in the source
+	- 24 bpp mode entries fixed (patch from Fabrice Bellard)
+
+2004-06-25 18:28  vruppert
+
+	* VGABIOS-lgpl-latest.cirrus.bin (1.7), VGABIOS-lgpl-latest.cirrus.debug.bin (1.7),
+	  clext.c (1.4):
+
+	- 4MB memory probe added (patch from Fabrice Bellard)
+
+2004-06-25 17:31  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.55), VGABIOS-lgpl-latest.cirrus.bin (1.6),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.6),
+	  VGABIOS-lgpl-latest.debug.bin (1.55), clext.c (1.3):
+
+	- fixed value of sequencer reset register in cirrus mode table
+	- fixed possible overflow error if cirrus start address is >256k
+
+2004-06-23 21:11  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.54), VGABIOS-lgpl-latest.cirrus.bin (1.5),
+	  VGABIOS-lgpl-latest.cirrus.debug.bin (1.5),
+	  VGABIOS-lgpl-latest.debug.bin (1.54), clext.c (1.2):
+
+	- applied new patch for the cirrus extension from suzu
+	  * enable VESA LFB support if a Cirrus PCI adapter is detected
+	  * prepared VBE3 protected mode info block (test case required)
+	- added VBE functions 4F06h and 4F07h
+	- some bugfixes
+
+2004-06-17 18:57  vruppert
+
+	* Makefile (1.14), VGABIOS-lgpl-latest.bin (1.53),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.2), VGABIOS-lgpl-latest.cirrus.debug.bin (1.2),
+	  VGABIOS-lgpl-latest.debug.bin (1.53):
+
+	- fixed makefile targets for the binaries with cirrus extension
+
+2004-06-16 21:11  vruppert
+
+	* Makefile (1.13), VGABIOS-lgpl-latest.bin (1.52),
+	  VGABIOS-lgpl-latest.cirrus.bin (1.1), VGABIOS-lgpl-latest.cirrus.debug.bin (1.1),
+	  VGABIOS-lgpl-latest.debug.bin (1.52), clext.c (1.1), vgabios.c (1.58):
+
+	- applied suzu's cirrus extension patch. Cirrus SVGA detection, most of the
+	  cirrus-specific modes and some basic VBE features are present now.
+
+2004-05-31 21:15  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.51), VGABIOS-lgpl-latest.debug.bin (1.51),
+	  vgabios.c (1.57):
+
+	- write character in planar graphics modes: sequencer map mask must be 0x0f and
+	  bit operation must be 'replace' if bit 7 of attribute is clear
+	- read/write pixel in planar graphics modes: bit mask setup simplified
+
+2004-05-11 18:08  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.50), VGABIOS-lgpl-latest.debug.bin (1.50),
+	  vgabios.c (1.56):
+
+	- biosfn_select_vert_res rewritten in assembler
+	- scroll text in planar graphics modes: attribute for blank line fixed
+	- write character in planar graphics modes: graphics controller values fixed
+
+2004-05-09 20:32  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.49), VGABIOS-lgpl-latest.debug.bin (1.49),
+	  vbe.c (1.44), vbe.h (1.24), vgabios.c (1.55):
+
+	- VBE init code and some dispi ioport functions rewritten in assembler
+	- text scroll functions for CGA graphics modes added
+	- scroll text in graphics modes: attribute for blank line fixed
+
+2004-05-08 16:06  vruppert
+
+	* BUGS (1.2), README (1.7), TODO (1.10), VGABIOS-lgpl-latest.bin (1.48),
+	  VGABIOS-lgpl-latest.debug.bin (1.48), vbe.c (1.43), vbe.h (1.23),
+	  vbe_display_api.txt (1.11), vgabios.c (1.54):
+
+	- VBE internal functions dispi_set_enable and dispi_set_bank now called both from C
+	  and asm code
+	- VBE function 0x03 rewritten in assembler
+	- VBE function 0x08 cleaned up
+	- text output and scroll functions for graphics modes rewritten using case
+	  structures
+	- documentation and comments updated
+
+2004-05-06 21:18  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.47), VGABIOS-lgpl-latest.debug.bin (1.47),
+	  vbe.c (1.42), vbe.h (1.22), vgabios.c (1.53):
+
+	- VBE functions 0x05, 0x06, 0x07 and some dispi ioport functions rewritten in
+	  assembler
+	- VBE functions 0x06 and 0x07: get functions now supported, 15 bpp bug fixed
+
+2004-05-05 19:24  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.46), VGABIOS-lgpl-latest.debug.bin (1.46),
+	  vbe.c (1.41), vbe.h (1.21), vbe_display_api.txt (1.10), vgabios.c (1.52):
+
+	- 8 bit DAC capability flag set
+	- vbe_biosfn_set_get_dac_palette_format implemented
+	- VBE api description updated
+	- C definitions from header files now used assembler code
+
+2004-05-02 17:27  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.45), VGABIOS-lgpl-latest.debug.bin (1.45),
+	  vgabios.c (1.51):
+
+	- text scroll functions for PLANAR1/PLANAR4 graphics modes added
+	- function biosfn_get_ega_info rewritten in assembler
+	- read/write graphics pixel functions rewritten using a case structure
+
+2004-05-01 16:03  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.44), VGABIOS-lgpl-latest.debug.bin (1.44),
+	  vgabios.c (1.50):
+
+	- biosfn_enable_cursor_emulation rewritten in assembler
+	- remap of the cursor shape depends on modeset control bit 0
+	- text output in PLANAR4 modes now supports attribute bit 7 (XOR with background)
+
+2004-04-25 20:13  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.43), VGABIOS-lgpl-latest.debug.bin (1.43),
+	  vgabios.c (1.49), vgatables.h (1.7):
+
+	- table entries for vga mode 0x0f fixed (PLANAR2 exists on EGA only)
+	- function release_font_access now supports the monochrome text mode
+	- PLANAR1 modes now supported in text output functions and read/write pixel
+	- function AH=0x12/BL=0x32 rewritten in assembler
+
+2004-04-25 08:45  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.42), VGABIOS-lgpl-latest.debug.bin (1.42),
+	  vgabios.c (1.48):
+
+	- block address calculation in font functions fixed
+	- functions AX=0x1103, AH=0x12/BL=0x31 and AH=0x12/BL=0x33 rewritten in assembler
+
+2004-04-24 09:59  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.41), VGABIOS-lgpl-latest.debug.bin (1.41),
+	  vgabios.c (1.47):
+
+	- read/write graphics pixel for PLANAR4 modes added
+	- CGA specific functions (group AH = 0x0B) implemented
+
+2004-04-23 14:34  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.40), VGABIOS-lgpl-latest.debug.bin (1.40),
+	  vgabios.c (1.46):
+
+	- remaining palette and dac read/write functions (except gray scale summing)
+	  rewritten in assembler
+
+2004-04-18 13:43  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.39), VGABIOS-lgpl-latest.debug.bin (1.39),
+	  vgabios.c (1.45):
+
+	- some palette and dac read/write functions rewritten in assembler
+	- main int10 debug message now works with assembler functions, too
+
+2004-04-18 09:15  japj
+
+	* vbe.c (1.40):
+
+	updated my email address + put vgabios url in the bios copyright string
+	(instead of my old email address)
+
+2004-04-17 07:18  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.38), VGABIOS-lgpl-latest.debug.bin (1.38),
+	  vgabios.c (1.44):
+
+	- biosfn_set_video_mode: don't load DAC registers if default palette loading is
+	  disabled. Perform gray scale summing if enabled.
+	- biosfn_perform_gray_scale_summing: switch between DAC read and write mode is
+	  required to make this function work. Maximum DAC value always set to 0x3f.
+
+2004-04-08 17:50  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.37), VGABIOS-lgpl-latest.debug.bin (1.37),
+	  vgabios.c (1.43):
+
+	- write character function for the LINEAR8 mode
+	- get_font_access() and release_font_access() rewritten in assembler
+	- fixed wrong variable name in the init code
+
+2004-04-06 19:31  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.36), VGABIOS-lgpl-latest.debug.bin (1.36),
+	  vgabios.c (1.42):
+
+	- init functions rewitten in assembler
+	- function biosfn_set_display_code rewritten in assembler
+
+2004-04-05 19:40  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.35), VGABIOS-lgpl-latest.debug.bin (1.35),
+	  vgabios.c (1.41):
+
+	- functions biosfn_get_video_mode() and biosfn_read_display_code() rewritten
+	  in assembler
+
+2004-04-04 18:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.34), VGABIOS-lgpl-latest.debug.bin (1.34),
+	  vgabios.c (1.40):
+
+	- write character function for CGA modes added
+	- read/write graphics pixel for CGA and LINEAR8 modes added
+
+2004-02-23 21:08  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.33), VGABIOS-lgpl-latest.debug.bin (1.33),
+	  vbe.c (1.39):
+
+	- dispi_get_max_bpp(): restore the original value of the vbe enable register
+
+2004-02-22 14:17  vruppert
+
+	* README (1.6), vbe.c (1.38), vbe.h (1.20), vbe_display_api.txt (1.9),
+	  VGABIOS-lgpl-latest.bin (1.32), VGABIOS-lgpl-latest.debug.bin (1.32):
+
+	- new function dispi_get_max_bpp() returns the bpp capabilities of the Bochs gui
+	- create the mode list depending on the supported bpp capability
+	- unused stuff removed
+	- documentation updated
+
+2004-02-21 18:20  vruppert
+
+	* vbe.c (1.37), vbe.h (1.19), vbetables.h (1.23),
+	  VGABIOS-lgpl-latest.bin (1.31), VGABIOS-lgpl-latest.debug.bin (1.31):
+
+	- dynamicly genarated vbe mode_info list works now
+
+2003-11-17 21:04  vruppert
+
+	* vbe.c (1.36), vbetables.h (1.22), vgabios.c (1.39), vgatables.h (1.6),
+	  VGABIOS-lgpl-latest.bin (1.30), VGABIOS-lgpl-latest.debug.bin (1.30):
+
+	- new VBE presence flag stored at unused BDA address 0xB9
+	- VBE init code rewritten
+	- added BIOS TTY flag for VBE mode 0x0102 (TODO: scrolling)
+	- vgabios_init_func: load and activate text font already done by set_video_mode
+	- function biosfn_get_all_palette_reg() fixed
+
+2003-11-06 00:26  cbothamy
+
+	* README (1.5):
+
+	  - add changes for 0.4c release
+
+2003-11-06 00:22  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.29), VGABIOS-lgpl-latest.debug.bin
+	  (1.29):
+
+	  - compile vgabios.c rev1.38
+
+2003-11-06 00:21  cbothamy
+
+	* vgabios.c (1.38):
+
+	  - activate char table after loading it when setting a text video
+	  mode
+
+2003-11-06 00:19  cbothamy
+
+	* Makefile (1.12):
+
+	  - when making a release, remove unwanted files first, and exclude
+	  CVS from the tarball
+
+2003-11-04 22:50  cbothamy
+
+	* ChangeLog (1.20, v0_4b):
+
+	  - update ChangeLog for 0.4b release
+
+2003-11-04 22:49  cbothamy
+
+	* README (1.4, v0_4b):
+
+	  - update Changes for 0.4b release
+
+2003-11-04 20:26  vruppert
+
+	* vgabios.c (1.37), VGABIOS-lgpl-latest.bin (1.28),
+	  VGABIOS-lgpl-latest.debug.bin (1.28) (utags: v0_4b):
+
+	  - biosfn_get_font_info(): character height must be returned in CX
+
+2003-11-03 21:57  vruppert
+
+	* vbe.c (1.35, v0_4b), vgabios.c (1.36), VGABIOS-lgpl-latest.bin
+	  (1.27), VGABIOS-lgpl-latest.debug.bin (1.27):
+
+	  - the 'noclearmem' flag is not stored in the 'current video mode'
+	  register (0040h:0049h) - VBE also stores the 'noclear' flag in
+	  the 'video control' register (0040h:0087h)
+
+2003-10-05 10:06  vruppert
+
+	* vbe.h (1.18, v0_4b), vbe_display_api.txt (1.8, v0_4b),
+	  VGABIOS-lgpl-latest.bin (1.26), VGABIOS-lgpl-latest.debug.bin
+	  (1.26):
+
+	  - changed VBE i/o registers to 0x01CE/CF (suggestion from Daniel
+	  Gimpelevich)
+
+2003-08-18 18:38  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.25), VGABIOS-lgpl-latest.debug.bin
+	  (1.25), vgabios.c (1.35):
+
+	  - wrong offsets to the character tables (INT 0x1F/0x43) fixed
+	  (underscore added) - functions accessing the CRT controller
+	  optimized using a local variable 'crtc_addr'
+
+2003-08-17 15:46  cbothamy
+
+	* ChangeLog (1.19, v0_4a):
+
+	  - ChangeLog is now automatically generated by running "cvs2cl -r
+	  -t -P -S" - update ChangeLog for 0.4a release
+
+2003-08-17 15:44  cbothamy
+
+	* README (1.3, v0_4a):
+
+	  - added the old ChangeLog in the HOSTORY section of the README
+	  file - update History for 0.4a release, with a summary of Changes
+
+2003-08-17 15:24  cbothamy
+
+	* Makefile (1.11, v0_4b, v0_4a):
+
+	  - fix Makefile for "release" target
+
+2003-08-16 01:49  cbothamy
+
+	* Makefile (1.10), README (1.2), VGABIOS-lgpl-latest.bin (1.24,
+	  v0_4a), VGABIOS-lgpl-latest.debug.bin (1.24, v0_4a), vgabios.c
+	  (1.34, v0_4a):
+
+	  - update the Makefile for releases - remove references to old
+	  plex86 website - update the Makefile so it build
+	  VGABIOS-lgpl-latest.bin and	VGABIOS-lgpl-latest.debug.bin
+
+2003-08-07 18:17  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.23), VGABIOS-lgpl-latest.debug.bin
+	  (1.23):
+
+	  - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-08-07 17:54  vruppert
+
+	* vbe.c (1.34), vgatables.h (1.5, v0_4b) (utags: v0_4a):
+
+	  - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-07-20 18:05  vruppert
+
+	* vgabios.c (1.33), VGABIOS-lgpl-latest.bin (1.22),
+	  VGABIOS-lgpl-latest.debug.bin (1.22):
+
+	  - fixed a few functions accessing the attribute controller
+
+2003-07-19 09:33  vruppert
+
+	* vgabios.c (1.32), VGABIOS-lgpl-latest.bin (1.21),
+	  VGABIOS-lgpl-latest.debug.bin (1.21):
+
+	  - re-enable video after programming the attribute controller -
+	  biosfn_set_all_palette_reg(): number of palette registers fixed
+
+2003-07-16 22:32  vruppert
+
+	* ChangeLog (1.18), vbe.c (1.33), vbe.h (1.17, v0_4a),
+	  vbe_display_api.txt (1.7, v0_4a), vgabios.c (1.31),
+	  VGABIOS-lgpl-latest.bin (1.20), VGABIOS-lgpl-latest.debug.bin
+	  (1.20):
+
+	  - LFB flag now stored in the register VBE_DISPI_INDEX_ENABLE -
+	  release date in Changelog fixed - release date of VBE BIOS 0.6
+	  was the same as VGA BIOS 0.3b - year changed in copyright
+	  messages
+
+2003-07-15 12:40  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.19), VGABIOS-lgpl-latest.debug.bin
+	  (1.19):
+
+	  - new function dispi_get_bpp() - function
+	  vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+	  number of image pages of all VBE modes fixed
+
+2003-07-15 12:35  vruppert
+
+	* vbe.c (1.32), vbetables.h (1.21, v0_4b, v0_4a):
+
+	  - new function dispi_get_bpp() - function
+	  vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+	  number of image pages of all VBE modes fixed
+
+2003-07-14 19:45  vruppert
+
+	* vbe_display_api.txt (1.6):
+
+	  - description of VBE_DISPI_ interface 0xb0c2 added
+
+2003-07-10 19:07  vruppert
+
+	* vbe.c (1.31), vbetables.h (1.20), VGABIOS-lgpl-latest.bin (1.18),
+	  VGABIOS-lgpl-latest.debug.bin (1.18):
+
+	  - 15 bpp VBE modes added - "Bochs own" mode 0x142 (640x480x32bpp)
+	  added
+
+2003-07-01 19:00  vruppert
+
+	* vbe.c (1.30), vbe.h (1.16), vbetables.h (1.19),
+	  VGABIOS-lgpl-latest.bin (1.17), VGABIOS-lgpl-latest.debug.bin
+	  (1.17):
+
+	  - VBE preserve display memory feature implemented - VBE mode
+	  entries 0x117 and 0x118 added
+
+2003-06-30 21:27  vruppert
+
+	* vbe.c (1.29), vbe.h (1.15), vbetables.h (1.18),
+	  VGABIOS-lgpl-latest.bin (1.16), VGABIOS-lgpl-latest.debug.bin
+	  (1.16):
+
+	  - VBE mode info blocks of modes with >8bpp enabled - VBE modes
+	  with 24 bpp: bytes per scanline fixed - vbe_biosfn_set_mode() now
+	  supports >8bpp - VBE will be enabled with new VBE_DISPI_ID2
+	  (0xB0C2)
+
+2003-06-29 12:53  vruppert
+
+	* vbetables.h (1.17), VGABIOS-lgpl-latest.bin (1.15),
+	  VGABIOS-lgpl-latest.debug.bin (1.15):
+
+	  - duplicate lines with VBE_MODE_ATTRIBUTE_GRAPHICS_MODE removed -
+	  VBE mode info items of currently unsupported modes fixed
+
+2003-06-15 21:19  vruppert
+
+	* vgabios.c (1.30), VGABIOS-lgpl-latest.bin (1.14),
+	  VGABIOS-lgpl-latest.debug.bin (1.14):
+
+	  - function write_gfx_char() rewritten
+
+2003-04-26 09:27  vruppert
+
+	* VGABIOS-lgpl-latest.debug.bin (1.13):
+
+	  - added missing VBE function dispi_get_bank() - added missing
+	  return codes for VBE function 4F05h - memory size is always
+	  reported in VBE function 4F00h - fixed scan line length for VBE
+	  mode 0102h - fixed function set_active_page() for graphics modes
+	  - fixed the page sizes of some VGA modes
+
+2003-04-26 09:22  vruppert
+
+	* vbe.c (1.28), vbetables.h (1.16), vgabios.c (1.29), vgatables.h
+	  (1.4), VGABIOS-lgpl-latest.bin (1.13):
+
+	  - added missing VBE function dispi_get_bank() - added missing
+	  return codes for VBE function 4F05h - memory size is always
+	  reported in VBE function 4F00h - fixed scan line length for VBE
+	  mode 0102h - fixed function set_active_page() for graphics modes
+	  - fixed the page sizes of some VGA modes
+
+2003-04-20 09:51  vruppert
+
+	* vgabios.c (1.28), vgatables.h (1.3), VGABIOS-lgpl-latest.bin
+	  (1.12), VGABIOS-lgpl-latest.debug.bin (1.12):
+
+	  - function write_gfx_char() now supports different font sizes -
+	  some entries of the static functionality table fixed
+
+2003-04-18 09:23  vruppert
+
+	* vbe.c (1.27), vbe.h (1.14), vbetables.h (1.15):
+
+	  - applied patch #1331   * new function dispi_set_bank_farcall()
+	  * VBE mode info item WinFuncPtr points to the new function if the
+	  flag	   VBE_WINDOW_ATTRIBUTE_RELOCATABLE is set   * flag
+	  VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE added
+
+2003-02-11 20:17  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.11), VGABIOS-lgpl-latest.debug.bin
+	  (1.11), vbe.c (1.26), vbetables.h (1.14):
+
+	  - VBE mode search rewritten	* improved function
+	  mode_info_find_mode() is now used by the VBE functions     0x4F01
+	  and 0x4F02   * removed all mode list entries with the LFB bit
+	  set. LFB detection is now	present in the function
+	  mode_info_find_mode()
+
+2003-02-09 20:59  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.10), VGABIOS-lgpl-latest.debug.bin
+	  (1.10), vgabios.c (1.27):
+
+	  - function write_gfx_char(): memory address now calculated in
+	  this function;   background color is always black - function
+	  biosfn_write_char_attr(): the count parameter is now used in
+	  graphics   modes too - function biosfn_write_char_only() works
+	  the same way as function   biosfn_write_char_attr() in graphics
+	  mode - copying charmap data optimized using memcpyb()
+
+2003-02-09 11:36  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.9), VGABIOS-lgpl-latest.debug.bin
+	  (1.9):
+
+	  - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+	  modes with the LFB flag set removed from the list (Linux doesn't
+	   like mode numbers > 0x07ff)
+
+2003-02-09 11:02  vruppert
+
+	* vbe.c (1.25), vbe.h (1.13), vbetables.h (1.13):
+
+	  - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+	  modes with the LFB flag set removed from the list (Linux doesn't
+	   like mode numbers > 0x07ff)
+
+2003-02-08 13:04  vruppert
+
+	* vbe.c (1.24), vgabios.c (1.26):
+
+	  - vbe_biosfn_return_current_mode() now returns the active
+	  standard VGA mode   TODO: return VESA mode if enabled -
+	  biosfn_set_video_mode() now clears the screen in CGA mode
+	  correctly - write character functions are now working in all
+	  PLANAR4 graphics modes - added stubs for unimplemented features
+	  in graphics modes
+
+2003-02-04 22:19  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.8), VGABIOS-lgpl-latest.debug.bin
+	  (1.8):
+
+	  - set video mode: clear vga memory in graphics mode - set video
+	  mode: load default font in text mode - write character
+	  implemented for graphics mode 0x12
+
+2003-02-04 22:06  vruppert
+
+	* vgabios.c (1.25):
+
+	  - set video mode: clear vga memory in graphics mode - set video
+	  mode: load default font in text mode - write character
+	  implemented for graphics mode 0x12
+
+2003-01-21 19:30  vruppert
+
+	* vgabios.c (1.24):
+
+	  - remap the cursor size if the char height is > 8 and the new
+	  values are < 8
+
+2003-01-20 18:24  cbothamy
+
+	* Makefile (1.9):
+
+	  - fix so make -j2 does not overwrite temp files
+
+2003-01-19 12:35  vruppert
+
+	* vgabios.c (1.23):
+
+	  - function set_scan_lines() recalculates the number of rows and
+	  the page size - new values for char height, text rows and page
+	  size are stored in the BIOS	data segment - asm helper function
+	  idiv_u added
+
+2003-01-15 18:49  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.7), VGABIOS-lgpl-latest.debug.bin
+	  (1.7):
+
+	  - compile vgabios rev 1.22
+
+2003-01-15 18:49  cbothamy
+
+	* vgabios.c (1.22):
+
+	  - fix bug found by ams : a 8bits index value was compared to
+	  0x100 in some cases	in biosfn_set_all_dac_reg,
+	  biosfn_read_all_dac_reg, biosfn_perform_gray_scale_summing
+
+2003-01-15 17:34  cbothamy
+
+	* Makefile (1.8):
+
+	  - fix symbol table file names, discovered by ams
+
+2003-01-04 21:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.6), VGABIOS-lgpl-latest.debug.bin
+	  (1.6), vgabios.c (1.21):
+
+	  - biosfn_set_video_mode(): reset attribute controller flip-flop
+	  before setting   up the controller's registers (bug found with
+	  amidiag)
+
+2003-01-04 09:50  vruppert
+
+	* vbe.c (1.23):
+
+	  - VBE function 0x00 returns VBE 1.x compatible information if no
+	  VBE signature   is present
+
+2003-01-01 12:44  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.5), VGABIOS-lgpl-latest.debug.bin
+	  (1.5):
+
+	  - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-12-31 18:07  vruppert
+
+	* vgatables.h (1.2):
+
+	  - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-11-23 10:38  cbothamy
+
+	* ChangeLog (1.17, v0_3b):
+
+	  - fix changelog for 0.3b release
+
+2002-10-20 17:12  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.4), VGABIOS-lgpl-latest.debug.bin
+	  (1.4), vgabios.c (1.20) (utags: v0_3b):
+
+	  - new function set_scan_lines() for the font size change (patch
+	  from Hartmut Birr) - cursor shape start and end must be updated
+	  in set_scan_lines() - set_scan_lines() is called by the functions
+	  0x1110, 0x1111, 0x1112 and 0x1114   after copying the font data
+
+2002-10-04 08:20  vruppert
+
+	* VGABIOS-lgpl-latest.bin (1.3), VGABIOS-lgpl-latest.debug.bin
+	  (1.3), vgabios.c (1.19):
+
+	  - biosfn_set_single_dac_reg(): the red value is stored in DH
+
+2002-09-19 19:05  cbothamy
+
+	* VGABIOS-lgpl-latest.bin (1.2), VGABIOS-lgpl-latest.debug.bin
+	  (1.2):
+
+	  - updated with latest changes
+
+2002-09-19 19:03  cbothamy
+
+	* ChangeLog (1.16), Makefile (1.7, v0_3b), vbe.c (1.22, v0_3b),
+	  vgabios.c (1.18), vgabios.h (1.3, v0_4b, v0_4a, v0_3b):
+
+	  - updated the Makefile - removed display of copyrights.  -
+	  changed the Copyright string to "LGPL VGABios developers"
+
+2002-09-08 21:14  vruppert
+
+	* vgabios.c (1.17):
+
+	  - set the cursor shape depending on the current font height -
+	  clear BL before calling int 0x10 function 0x1103 in
+	  vgabios_init_func
+
+2002-08-23 22:58  cbothamy
+
+	* vbe.c (1.21), vbetables.h (1.12, v0_3b):
+
+	  - added lfb-mode numbers (patch from mathis)
+
+2002-07-21 21:57  japj
+
+	* vbe.c (1.20), vgabios.c (1.16):
+
+	  gcc2/3 preprocessing fix
+
+2002-05-18 16:55  cbothamy
+
+	* vgabios.c (1.15):
+
+	  - include patch from Volker that adds some text font functions
+
+2002-05-01 23:13  japj
+
+	* VGABIOS-lgpl-latest.bin (1.1), VGABIOS-lgpl-latest.debug.bin
+	  (1.1):
+
+	  adding latest bin & debug bin of the vgabios
+
+2002-04-29 14:50  japj
+
+	* ChangeLog (1.15), vbe.c (1.19), vbe.h (1.12, v0_3b), vbetables.h
+	  (1.11), vgabios.c (1.14):
+
+	  - applying hw scrolling/multibuffering patch
+
+2002-04-25 21:59  japj
+
+	* Makefile (1.6), vbe.c (1.18), vgabios.c (1.13):
+
+	  - reverting #asm/##asm & endasm patch (does not work with with
+	  cygwin)
+
+2002-04-19 19:38  japj
+
+	* Makefile (1.5), vbe.c (1.17), vgabios.c (1.12):
+
+	  - fixing preprocessing of vgabios with latest gcc (from Mandrake
+	  8.2)
+
+2002-04-08 23:44  japj
+
+	* ChangeLog (1.14), vbe_display_api.txt (1.5, v0_3b):
+
+	  - preparing docs for new DISPI interface (for hardware scrolling)
+
+2002-04-03 19:06  japj
+
+	* ChangeLog (1.13), TODO (1.9, v0_4b, v0_4a, v0_3b), vbe.c (1.16):
+
+	  - defaulting LFB on + updated changelog & todo
+
+2002-04-03 00:38  cbothamy
+
+	* vbe.c (1.15), vgabios.c (1.11):
+
+	  - changed the logging ports to 0x500 -> 0x502
+
+2002-03-14 17:54  japj
+
+	* vbe.c (1.14):
+
+	  - vbetables.h is dependant upon some defines (VBE_HAVE_LFB), so
+	  put the include *after* the define
+
+2002-03-13 21:47  japj
+
+	* ChangeLog (1.12), TODO (1.8), vbe.c (1.13), vbetables.h (1.10),
+	  vgabios.c (1.10):
+
+	  - made LFB dependant upon define - not implement vbe functions
+	  return failure - updated todo & docs for things after bochs 1.4
+
+2002-03-13 19:46  japj
+
+	* vbe.h (1.11), vbe_display_api.txt (1.4):
+
+	  - added max video memory + documented what is in the 0xb0c0
+	  interface
+
+2002-03-12 02:33  cbothamy
+
+	* ChangeLog (1.11), Makefile (1.4):
+
+	  - updated for 0.3a. Merged vgabios.bin and vbebios.bin
+
+2002-03-10 21:36  japj
+
+	* ChangeLog (1.10), vbetables.h (1.9):
+
+	  - added LFB modes for testing with vbe-lfb patch in Bochs
+
+2002-03-10 17:42  japj
+
+	* vbe.c (1.12, v0_3a):
+
+	  - show people when they do NOT have VBE support available
+
+2002-03-10 17:36  japj
+
+	* TODO (1.7, v0_3a), vbe.c (1.11), vbe.h (1.10, v0_3a), vgabios.c
+	  (1.9, v0_3a):
+
+	  - cleanup of vbe internal functions (set 8bpp mode is now
+	  dependant on ModeInfo content instead of hardcoded functions)
+
+2002-03-10 17:20  cbothamy
+
+	* ChangeLog (1.9, v0_3a), TODO (1.6):
+
+	  - updated for 0.3a
+
+2002-03-10 17:19  cbothamy
+
+	* vbe.c (1.10), vbe.h (1.9):
+
+	  - added vbe_has_vbe_display function that detects an attached vbe
+	  display
+
+2002-03-10 17:12  cbothamy
+
+	* vgabios.c (1.8):
+
+	  - vbe calls are done only if a vbe display is detected
+
+2002-03-10 11:25  japj
+
+	* vbe.h (1.8), vbe_display_api.txt (1.3, v0_3a):
+
+	  - preparing for LFB support
+
+2002-03-09 14:25  japj
+
+	* vgabios.c (1.7):
+
+	  - fixing initial cursor shape to _ instead of -
+
+2002-03-08 23:08  japj
+
+	* ChangeLog (1.8), TODO (1.5), vbe.c (1.9), vbe.h (1.7), vgabios.c
+	  (1.6):
+
+	  - updating vbe code to new API
+
+2002-03-08 21:48  japj
+
+	* vbe.c (1.8), vbe.h (1.6), vbetables.h (1.8, v0_3a):
+
+	  - updating vbe code with #defines from API
+
+2002-03-08 21:31  japj
+
+	* vbe_display_api.txt (1.2):
+
+	  - adding some text about how banks work
+
+2002-03-08 21:09  japj
+
+	* ChangeLog (1.7), vbe_display_api.txt (1.1):
+
+	  - adding vbe_display_api documentation
+
+2002-03-07 21:36  japj
+
+	* ChangeLog (1.6), vbe.c (1.7), vbetables.h (1.7):
+
+	  - added 1024x768xbpp support - some more cleanups/comments
+
+2002-03-06 21:55  japj
+
+	* ChangeLog (1.5), TODO (1.4), vbe.c (1.6), vbetables.h (1.6),
+	  vgabios.c (1.5):
+
+	  - updated changelog with new modi - added 640x480x8 (Mandrake
+	  Installer can use this!) - added pre VBE2 compatible 'detection'
+	  - fixed problem when normal vga set mode wouldn't disable vbe
+	  mode
+
+2002-03-06 20:59  japj
+
+	* TODO (1.3), vbe.c (1.5), vbe.h (1.5), vbetables.h (1.5),
+	  vgabios.c (1.4):
+
+	  - adding 640x400x8 and 800x600x8 vbe support	 (this depends
+	  HEAVILY on my bochs vga code patch - japj)
+
+2002-03-06 18:00  japj
+
+	* vbe.c (1.4), vbe.h (1.4), vbetables.h (1.4):
+
+	  - implemented banked & lfb support for 320x200x8bpp	(some fixes
+	  for vbetest program not displaying anything)
+
+2002-03-05 20:25  japj
+
+	* Makefile (1.3, v0_3a):
+
+	  for vbe debug bios: - print debugging information in assembly
+	  output - print source code in assembly output
+
+2002-03-01 19:39  japj
+
+	* ChangeLog (1.4), TODO (1.2), vbe.c (1.3), vbe.h (1.3),
+	  vbetables.h (1.3):
+
+	  - added vbe support for 320x200x8 using the standard vgamode
+	  (0x13)
+
+2002-02-19 00:29  japj
+
+	* ChangeLog (1.3):
+
+	  - updating ChangeLog with lfbprof
+
+2002-02-18 23:26  japj
+
+	* tests/lfbprof/: lfbprof.c (1.2), lfbprof.h (1.2) (utags: v0_3a,
+	  v0_3b, v0_4a, v0_4b):
+
+	  - fixed unsigned short for mode list (-1 != 0xffff otherwise) -
+	  fixed LfbMapRealPointer macro mask problem (some modes were
+	  skipped) - added some extra 'debugging' printf's
+
+2002-02-18 23:07  japj
+
+	* tests/lfbprof/: Makefile (1.1, v0_4b, v0_4a, v0_3b, v0_3a),
+	  lfbprof.c (1.1), lfbprof.h (1.1):
+
+	  - Adding lfbprof testprogram (for vbe testing purposes)   It
+	  needs to be compiled with the Watcom C Compiler
+
+2002-02-18 18:48  japj
+
+	* vbe.c (1.2), vbe.h (1.2):
+
+	  - cosmetic updates to vbe.c/h + added bunch of FIXMEs for work
+	  that needs to be done
+
+2002-02-18 18:34  japj
+
+	* vbetables.h (1.2):
+
+	  - cosmetic updates in vbetables.h
+
+2002-02-18 18:32  japj
+
+	* ChangeLog (1.2):
+
+	  updated changelog with merge of vbebios 0.2
+
+2002-02-18 18:07  japj
+
+	* vgabios.c (1.3):
+
+	  - small cosmetic cleanup in vgabios vbe code + added FIXMEs
+
+2002-02-18 17:55  japj
+
+	* Makefile (1.2), dataseghack (1.2, v0_4b, v0_4a, v0_3b, v0_3a),
+	  vbe.c (1.1), vbe.h (1.1), vbetables.h (1.1), vgabios.c (1.2),
+	  vgabios.h (1.2, v0_3a):
+
+	  - merging with vbebios 0.2 release
+
+2002-02-18 11:31  cbothamy
+
+	* BUGS (1.1, v0_4b, v0_4a, v0_3b, v0_3a), COPYING (1.1, v0_4b,
+	  v0_4a, v0_3b, v0_3a), ChangeLog (1.1), Makefile (1.1), Notes
+	  (1.1, v0_4b, v0_4a, v0_3b, v0_3a), README (1.1, v0_3b, v0_3a),
+	  TODO (1.1), dataseghack (1.1), vgabios.c (1.1), vgabios.h (1.1),
+	  vgafonts.h (1.1, v0_4b, v0_4a, v0_3b, v0_3a), vgatables.h (1.1,
+	  v0_3b, v0_3a), tests/testbios.c (1.1, v0_4b, v0_4a, v0_3b,
+	  v0_3a):
+
+	  - initial import
+
diff --git a/qemu-0.15.x/roms/vgabios/Makefile b/qemu-0.15.x/roms/vgabios/Makefile
new file mode 100644
index 0000000..578721a
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/Makefile
@@ -0,0 +1,103 @@
+SHELL = /bin/sh
+
+CC      = gcc
+CFLAGS  = -g -O2 -Wall -Wstrict-prototypes
+LDFLAGS = 
+
+GCC = gcc
+BCC = bcc
+AS86 = as86
+
+RELEASE = `pwd | sed "s-.*/--"`
+RELDATE = `date '+%d %b %Y'`
+RELVERS = `pwd | sed "s-.*/--" | sed "s/vgabios//" | sed "s/-//"`
+
+VGABIOS_DATE = "-DVGABIOS_DATE=\"$(RELDATE)\""
+
+all: bios cirrus-bios stdvga-bios vmware-bios qxl-bios
+
+bios: vgabios.bin vgabios.debug.bin
+
+cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
+
+stdvga-bios: vgabios-stdvga.bin vgabios-stdvga.debug.bin
+
+vmware-bios: vgabios-vmware.bin vgabios-vmware.debug.bin
+
+qxl-bios: vgabios-qxl.bin vgabios-qxl.debug.bin
+
+clean:
+	/bin/rm -f  biossums vbetables-gen vbetables.h *.o *.s *.ld86 \
+          temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak
+
+dist-clean: clean
+
+# source files
+VGA_FILES := vgabios.c vgabios.h vgafonts.h vgatables.h
+VBE_FILES := vbe.h vbe.c vbetables.h
+
+# build flags
+vgabios.bin              : VGAFLAGS := -DVBE -DPCI_VID=0x1234
+vgabios.debug.bin        : VGAFLAGS := -DVBE -DPCI_VID=0x1234 -DDEBUG
+vgabios-cirrus.bin       : VGAFLAGS := -DCIRRUS -DPCIBIOS 
+vgabios-cirrus.debug.bin : VGAFLAGS := -DCIRRUS -DPCIBIOS -DCIRRUS_DEBUG
+vgabios-stdvga.bin       : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x1234 -DPCI_DID=0x1111
+vgabios-stdvga.debug.bin : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x1234 -DPCI_DID=0x1111 -DDEBUG
+vgabios-vmware.bin       : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x15ad -DPCI_DID=0x0405
+vgabios-vmware.debug.bin : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x15ad -DPCI_DID=0x0405 -DDEBUG
+vgabios-qxl.bin          : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x1b36 -DPCI_DID=0x0100
+vgabios-qxl.debug.bin    : VGAFLAGS := -DVBE -DPCIBIOS -DPCI_VID=0x1b36 -DPCI_DID=0x0100 -DDEBUG
+
+# dist names
+vgabios.bin              : DISTNAME := VGABIOS-lgpl-latest.bin
+vgabios.debug.bin        : DISTNAME := VGABIOS-lgpl-latest.debug.bin
+vgabios-cirrus.bin       : DISTNAME := VGABIOS-lgpl-latest.cirrus.bin
+vgabios-cirrus.debug.bin : DISTNAME := VGABIOS-lgpl-latest.cirrus.debug.bin
+vgabios-stdvga.bin       : DISTNAME := VGABIOS-lgpl-latest.stdvga.bin
+vgabios-stdvga.debug.bin : DISTNAME := VGABIOS-lgpl-latest.stdvga.debug.bin
+vgabios-vmware.bin       : DISTNAME := VGABIOS-lgpl-latest.vmware.bin
+vgabios-vmware.debug.bin : DISTNAME := VGABIOS-lgpl-latest.vmware.debug.bin
+vgabios-qxl.bin          : DISTNAME := VGABIOS-lgpl-latest.qxl.bin
+vgabios-qxl.debug.bin    : DISTNAME := VGABIOS-lgpl-latest.qxl.debug.bin
+
+# dependencies
+vgabios.bin              : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios.debug.bin        : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-cirrus.bin       : $(VGA_FILES) clext.c biossums
+vgabios-cirrus.debug.bin : $(VGA_FILES) clext.c biossums
+vgabios-stdvga.bin       : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-stdvga.debug.bin : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-vmware.bin       : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-vmware.debug.bin : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-qxl.bin          : $(VGA_FILES) $(VBE_FILES) biossums
+vgabios-qxl.debug.bin    : $(VGA_FILES) $(VBE_FILES) biossums
+
+# build rule
+%.bin:
+	$(GCC) -E -P vgabios.c $(VGABIOS_VERS) $(VGAFLAGS) $(VGABIOS_DATE) > _$*_.c
+	$(BCC) -o $*.s -C-c -D__i86__ -S -0 _$*_.c
+	sed -e 's/^\.text//' -e 's/^\.data//' $*.s > _$*_.s
+	$(AS86) _$*_.s -b $*.bin -u -w- -g -0 -j -O -l $*.txt
+	rm -f _$*_.s _$*_.c $*.s
+	mv $*.bin $(DISTNAME)
+	./biossums $(DISTNAME)
+	ls -l $(DISTNAME)
+
+release: 
+	VGABIOS_VERS=\"-DVGABIOS_VERS=\\\"$(RELVERS)\\\"\" make bios cirrus-bios
+	/bin/rm -f  *.o *.s *.ld86 \
+          temp.awk.* vgabios.*.orig _vgabios_.*.c core *.bak .#*
+	cp VGABIOS-lgpl-latest.bin ../$(RELEASE).bin
+	cp VGABIOS-lgpl-latest.debug.bin ../$(RELEASE).debug.bin
+	cp VGABIOS-lgpl-latest.cirrus.bin ../$(RELEASE).cirrus.bin
+	cp VGABIOS-lgpl-latest.cirrus.debug.bin ../$(RELEASE).cirrus.debug.bin
+	tar czvf ../$(RELEASE).tgz --exclude CVS -C .. $(RELEASE)/
+
+biossums: biossums.c
+	$(CC) -o biossums biossums.c
+
+vbetables-gen: vbetables-gen.c
+	$(CC) -o vbetables-gen vbetables-gen.c
+
+vbetables.h: vbetables-gen
+	./vbetables-gen > $@
diff --git a/qemu-0.15.x/roms/vgabios/Notes b/qemu-0.15.x/roms/vgabios/Notes
new file mode 100644
index 0000000..d5b708d
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/Notes
@@ -0,0 +1,11 @@
+Development notes
+-----------------
+
+- need to split video init function
+    1. set bios variables
+    2. do the real init with io based on bios variables
+
+- characters format switching will set the bios
+  variables and call function #2 above
+
+- need to rework the tables as explained in Interrupt list
diff --git a/qemu-0.15.x/roms/vgabios/README b/qemu-0.15.x/roms/vgabios/README
new file mode 100644
index 0000000..c68b573
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/README
@@ -0,0 +1,226 @@
+Plex86/Bochs VGABios
+--------------------
+
+The goal of this project is to have a LGPL'd Video Bios in plex86,
+Bochs and qemu.
+This VGA Bios is very specific to the emulated VGA card.
+It is NOT meant to drive a physical vga card.
+
+
+Cirrus SVGA extension
+---------------------
+
+The Cirrus SVGA extension is designed for the Cirrus emulation in Bochs and
+qemu. The initial patch for the Cirrus extension has been written by Makoto
+Suzuki (suzu).
+
+
+Install
+-------
+To compile the VGA Bios you will need :
+- gcc
+- bcc
+- as86
+- ld86
+
+Untar the archive, and type make. You should get a "VGABIOS-lgpl-latest.bin"
+file. Alternatively, you can use the binary file "VGABIOS-lgpl-latest.bin",
+i have compiled for you.
+
+Edit your plex86/bochs conf file, and modify the load-rom command in the
+VGA BIOS section, to point to the new vgabios image file.
+
+
+Debugging
+---------
+You can get a very basic debugging system: messages printed by the vgabios.
+You have to register the "unmapped" device driver in plex86 or bochs, and make
+sure it grabs port 0xfff0.
+
+Comment the #undef DEBUG at the beginning of vgabios.c.
+You can then use the "printf" function in the bios.
+
+
+Testing
+-------
+Look at the "testvga.c" file in the archive. This is a minimal Turbo C 2.0
+source file that calls a few int10 functions. Feel free to modify it to suit
+your needs.
+
+
+Copyright and License
+---------------------
+This program has been written by Christophe Bothamy
+It is protected by the GNU Lesser Public License, which you should
+have received a copy of along with this package.
+
+
+Reverse Engineering
+-------------------
+The VGA Bios has been written without reverse-engineering any existing Bios.
+
+
+Acknowledgment
+--------------
+The source code contains code ripped from rombios.c of plex86, written
+by Kevin Lawton <kevin2001 at yahoo.com>
+
+The source code contains fonts from fntcol16.zip (c) by Joseph Gil avalable at :
+ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+These fonts are public domain
+
+The source code is based on information taken from :
+- Kevin Lawton's vga card emulation for bochs/plex86
+- Ralf Brown's interrupts list avalaible at
+  http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+- Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+- Michael Abrash's Graphics Programming Black Book
+- Francois Gervais' book "programmation des cartes graphiques cga-ega-vga"
+  edited by sybex
+- DOSEMU 1.0.1 source code for several tables values and formulas
+
+
+Feedback
+--------
+Please report any bugs, comments, patches for this VGA Bios to info at vruppert.de
+You can find the latest release at : http://www.nongnu.org/vgabios/
+For any information on bochs, visit the website http://bochs.sourceforge.net/
+For any information on qemu, visit the website http://fabrice.bellard.free.fr/qemu/
+
+
+History
+-------
+vgabios-0.6c : Apr 08 2009
+  - Volker
+    . added DPMS support to cirrus vgabios (patch from Gleb Natapov)
+    . use VBE LFB address from PCI base address if present
+    . added support for a lot more non-standard VBE modes (e.g. widescreen modes)
+    . minor bugfixes
+
+vgabios-0.6b : May 30 2008
+  - Volker
+    . added PCI data structure for the Cirrus VGABIOS images
+    . minor bugfixes in biossums utility, VBE support and makefile
+
+vgabios-0.6a : Aug 19 2006
+  - Volker
+    . added minimal support for the video parameter table (VPT)
+    . Cirrus SVGA now supports the "no clear" bit in Cirrus and VESA mode
+    . Bochs VBE protected mode interface improved
+    . save/restore video state support for Bochs VBE and standard VGA added
+    . generate vbetables.h dynamicly
+    . VBE video memory increased to 8 MB (VBE dispi ID changed to B0C4)
+    . lots of 4bpp VBE fixes (all 4bpp VBE modes now enabled)
+    . VGA compatible setup for VBE modes added
+
+vgabios-0.5d : Dec 29 2005
+  - Volker
+    . Bochs VBE protected mode interface added (based on a patch by malc at pulsesoft.com)
+    . biossums utility now supports VGABIOS sizes up to 64 kBytes
+    . VGA mode 0x11: all color planes must be enabled in this 2-color VGA mode
+
+vgabios-0.5c : Jul 07 2005
+  - Volker
+    . BIOS configuration word usually reports initial mode 80x25 color text
+    . vgabios function 0x0e (write teletype): linefeed (0x0a) only increments the
+      cursor row value
+
+vgabios-0.5b : May 24 2005
+  - Volker
+    . fixed return value for the default case in the VBE section (non-debug mode)
+    . removed unused stuff
+
+vgabios-0.5a : Mar 07 2005
+  - Volker
+    . Cirrus SVGA extension (initial patches from Makoto Suzuki, improvements
+      from Fabrice Bellard)
+    . vgabios image size is now exactly 32k with a checksum
+    . a lot of vgabios and vbe functions rewritten in assembler
+    . dynamicly generated VBE mode info list
+    . write character function for CGA and LINEAR8 modes
+    . read/write graphics pixel for some graphics modes
+    . text scroll feature for some graphics modes
+    . VBE 8-bit DAC support
+
+vgabios-0.4c : Nov 06 2003
+  - Christophe
+    . fix font problem on initial screen of NT4 Loader
+    
+vgabios-0.4b : Nov 04 2003
+  - Volker
+    . fix offset of character tables
+    . optimizations of CRT controller accesses
+    . VBE i/o registers changed to 0x01CE/CF 
+      (suggestion from Daniel Gimpelevich)
+    . "noclear" flag stored in BIOS area
+    . fix character height returned by get_font_info function
+
+vgabios-0.4a : Aug 17 2003
+  - Volker
+    . VBE mode search rewritten (VBE modes with LFB bit removed)
+    . many bugfixes and optimizations
+    . write character function implemented for graphics modes
+    . support for 15bpp, 16bpp, 24bpp and 32bpp VBE modes added
+    . SVGA mode 0x6A added
+    . VBE modes 0x102, 0x117, 0x118 and 0x142 (Bochs specific)
+
+vgabios-0.3b : Nov 23 2002
+  - Christophe
+    . added lfb-mode numbers (patch from mathis)
+    . updated the Makefile
+    . removed display of copyrights.
+    . changed the Copyright string to "LGPL VGABios developers"
+  - Volker
+    . set the cursor shape depending on the current font height
+    . clear BL before calling int 0x10 function 0x1103 in vgabios_init_func
+    . added some text font functions
+  - Jeroen
+    . Forced to new DISPI (0xb0c1) interface (requires latest bochs vbe code)
+    . Added multibuffering support
+    . Added new DISPI interface for: virt width, height, x offset, y offset
+    . Added LFB modes (to be used with the vbe-lfb patch in bochs)
+      see VBE_HAVE_LFB in vbe.c (currently default enabled)
+    . updated TODO & docs for changes after bochs 1.4
+
+vgabios-0.3a : Mar 10 2002
+  - Christophe
+    . Fixed bug in function ah=13
+  - Jeroen
+    . updated vbebios implementation to new api
+    . added vbe_display_api documentation
+    . added 640x400x8, 640x480x8, 800x600x8, 1024x768
+      (>640x480 needs a special bochs patch atm)
+    . added 320x200x8 vbe support (uses the standard 320x200x8 vga mode to
+      display, this allows for testing & having something on screen as well,
+      at least until bochs host side display is up & running)
+    . adding lfbprof (vbe) testprogram (+some small fixes to it)
+    . merging with vbebios 0.2
+
+vgabios-0.2b : Nov 19 2001
+  - Christophe
+    . Fixed bug in function ah=13
+
+vgabios-0.2a : Nov 09 2001
+  - Christophe
+    . Included bugfix from techt at pikeonline.net about grayscale summing
+    . Added the "IBM" string at org 0x1e as Bart Oldeman suggested
+    . Fixed DS and ES that where inverted in the int10 parameters list!
+    . The following have been implemented :
+	- function ax=1a00, ax=1a01, ah=1b
+	- function ax=1130
+    . Added debug messages for unimplemented/unknown functions
+      Must be compiled with DEBUG defined. The output is trapped
+      by the unknown-ioport driver of plex/bochs (port 0xfff0 is used)
+
+vgabios-0.1a : May 8 2001
+  - Christophe
+    . First release. The work has been focused only on text mode.
+    . The following have been implemented :
+	- inits
+	- int 10 handler
+	- functions ah=00, ah=01, ah=02, ah=03, ah=05, ah=06, ah=07, ah=08
+	  ah=09, ah=0a, ah=0e, ah=0f, ax=1000, ax=1001, ax=1002, ax=1003
+	  ax=1007, ax=1008, ax=1009, ax=1010, ax=1012, ax=1013, ax=1015
+	  ax=1017, ax=1018, ax=1019, ax=101a, ax=101b, ah=12 bl=10,
+	  ah=12 bl=30, ah=12 bl=31, ah=12 bl=32, ah=12 bl=33, ah=12 bl=34
+	  ah=13
diff --git a/qemu-0.15.x/roms/vgabios/TODO b/qemu-0.15.x/roms/vgabios/TODO
new file mode 100644
index 0000000..b08ee4b
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/TODO
@@ -0,0 +1,26 @@
+Short term :
+------------
+
+General
+  - Fix init mode (ah=00). Should use more BIOS variables
+  - Add new functionalities and modify static functionality table
+  - Performance : 16 bits IO
+
+v0.7
+  - Implement the remaining functions (don't know if all are needed):
+	- chargen ax=1120, ax=1121, ax=1122, ax=1123, ax=1124
+	- display switch interface ah=12 bl=35
+	- video refresh control ah=12 bl=36
+  - Graphic modes
+
+v1.0
+  - Bugfixes
+
+
+=================================================================================================
+VBE:
+----
+Long term:
+- have plex86 host side display interface
+- have text io functions in vbe mode
+
diff --git a/qemu-0.15.x/roms/vgabios/biossums.c b/qemu-0.15.x/roms/vgabios/biossums.c
new file mode 100644
index 0000000..d5816f4
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/biossums.c
@@ -0,0 +1,282 @@
+/* biossums.c  --- written by Eike W. for the Bochs BIOS */
+/* adapted for the LGPL'd VGABIOS by vruppert */
+
+/*  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define MAX_BIOS_DATA 0x10000
+
+long chksum_bios_get_offset( byte* data, long offset );
+byte chksum_bios_calc_value( byte* data, long offset );
+byte chksum_bios_get_value(  byte* data, long offset );
+void chksum_bios_set_value(  byte* data, long offset, byte value );
+
+#define PMID_LEN        20
+#define PMID_CHKSUM     19
+
+long chksum_pmid_get_offset( byte* data, long offset );
+byte chksum_pmid_calc_value( byte* data, long offset );
+byte chksum_pmid_get_value(  byte* data, long offset );
+void chksum_pmid_set_value(  byte* data, long offset, byte value );
+
+#define PCIR_LEN        24
+
+long chksum_pcir_get_offset( byte* data, long offset );
+
+
+byte bios_data[MAX_BIOS_DATA];
+long bios_len;
+
+
+int main(int argc, char* argv[])
+{
+  FILE* stream;
+  long  offset, tmp_offset, pcir_offset;
+  byte  bios_len_byte, cur_val = 0, new_val = 0;
+  int   hits, modified;
+
+  if (argc != 2) {
+    printf( "Error. Need a file-name as an argument.\n" );
+    exit( EXIT_FAILURE );
+  }
+
+  if ((stream = fopen(argv[1], "rb")) == NULL) {
+    printf("Error opening %s for reading.\n", argv[1]);
+    exit(EXIT_FAILURE);
+  }
+  memset(bios_data, 0, MAX_BIOS_DATA);
+  bios_len = fread(bios_data, 1, MAX_BIOS_DATA, stream);
+  if (bios_len > MAX_BIOS_DATA) {
+    printf("Error reading max. 65536 Bytes from %s.\n", argv[1]);
+    fclose(stream);
+    exit(EXIT_FAILURE);
+  }
+  fclose(stream);
+  modified = 0;
+  if (bios_len < 0x8000) {
+    bios_len = 0x8000;
+    modified = 1;
+  } else if ((bios_len & 0x1FF) != 0) {
+    bios_len = (bios_len + 0x200) & ~0x1FF;
+    modified = 1;
+  }
+  bios_len_byte = (byte)(bios_len / 512);
+  if (bios_len_byte != bios_data[2]) {
+    if (modified == 0) {
+      bios_len += 0x200;
+    }
+    bios_data[2] = (byte)(bios_len / 512);
+    modified = 1;
+  }
+
+  hits   = 0;
+  offset = 0L;
+  while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) {
+    offset  = tmp_offset;
+    cur_val = chksum_pmid_get_value(  bios_data, offset );
+    new_val = chksum_pmid_calc_value( bios_data, offset );
+    printf( "\nPMID entry at: 0x%4lX\n", offset  );
+    printf( "Current checksum:     0x%02X\n",   cur_val );
+    printf( "Calculated checksum:  0x%02X  ",   new_val );
+    hits++;
+  }
+  if ((hits == 1) && (cur_val != new_val)) {
+    printf("Setting checksum.");
+    chksum_pmid_set_value( bios_data, offset, new_val );
+    if (modified == 0) {
+      bios_len += 0x200;
+      bios_data[2]++;
+    }
+    modified = 1;
+  }
+  if (hits >= 2) {
+    printf( "Multiple PMID entries! No checksum set." );
+  }
+  if (hits) {
+    printf("\n");
+  }
+
+  offset = 0L;
+  pcir_offset = chksum_pcir_get_offset( bios_data, offset );
+  if (pcir_offset != -1L) {
+    if (bios_data[pcir_offset + 16] != bios_data[2]) {
+      bios_data[pcir_offset + 16] = bios_data[2];
+      if (modified == 0) {
+        bios_len += 0x200;
+        bios_data[2]++;
+        bios_data[pcir_offset + 16]++;
+      }
+      modified = 1;
+    }
+  }
+
+  offset  = 0L;
+  do {
+    offset  = chksum_bios_get_offset(bios_data, offset);
+    cur_val = chksum_bios_get_value(bios_data, offset);
+    new_val = chksum_bios_calc_value(bios_data, offset);
+    if ((cur_val != new_val) && (modified == 0)) {
+      bios_len += 0x200;
+      bios_data[2]++;
+      if (pcir_offset != -1L) {
+        bios_data[pcir_offset + 16]++;
+      }
+      modified = 1;
+    } else {
+      printf("\nBios checksum at:   0x%4lX\n", offset);
+      printf("Current checksum:     0x%02X\n", cur_val);
+      printf("Calculated checksum:  0x%02X  ", new_val);
+      if (cur_val != new_val) {
+        printf("Setting checksum.");
+        chksum_bios_set_value(bios_data, offset, new_val);
+        cur_val = new_val;
+        modified = 1;
+      }
+      printf( "\n" );
+    }
+  } while (cur_val != new_val);
+
+  if (modified == 1) {
+    if ((stream = fopen( argv[1], "wb")) == NULL) {
+      printf("Error opening %s for writing.\n", argv[1]);
+      exit(EXIT_FAILURE);
+    }
+    if (fwrite(bios_data, 1, bios_len, stream) < bios_len) {
+      printf("Error writing %d KBytes to %s.\n", bios_len / 1024, argv[1]);
+      fclose(stream);
+      exit(EXIT_FAILURE);
+    }
+    fclose(stream);
+  }
+
+  return (EXIT_SUCCESS);
+}
+
+
+void check( int okay, char* message ) {
+
+  if( !okay ) {
+    printf( "\n\nError. %s.\n", message );
+    exit( EXIT_FAILURE );
+  }
+}
+
+
+long chksum_bios_get_offset( byte* data, long offset ) {
+
+  return (bios_len - 1);
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+  int   i;
+  byte  sum;
+
+  sum = 0;
+  for( i = 0; i < offset; i++ ) {
+    sum = sum + *( data + i );
+  }
+  sum = -sum;          /* iso ensures -s + s == 0 on unsigned types */
+  return( sum );
+}
+
+
+byte chksum_bios_get_value( byte* data, long offset ) {
+
+  return( *( data + offset ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+  *( data + offset ) = value;
+}
+
+
+byte chksum_pmid_calc_value( byte* data, long offset ) {
+
+  int           i;
+  int           len;
+  byte sum;
+
+  len = PMID_LEN;
+  check((offset + len) <= (bios_len - 1), "PMID entry length out of bounds" );
+  sum = 0;
+  for( i = 0; i < len; i++ ) {
+    if( i != PMID_CHKSUM ) {
+      sum = sum + *( data + offset + i );
+    }
+  }
+  sum = -sum;
+  return( sum );
+}
+
+
+long chksum_pmid_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  while ((offset + PMID_LEN) < (bios_len - 1)) {
+    offset = offset + 1;
+    if( *( data + offset + 0 ) == 'P' && \
+        *( data + offset + 1 ) == 'M' && \
+        *( data + offset + 2 ) == 'I' && \
+        *( data + offset + 3 ) == 'D' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
+
+
+byte chksum_pmid_get_value( byte* data, long offset ) {
+
+  check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" );
+  return(  *( data + offset + PMID_CHKSUM ) );
+}
+
+
+void chksum_pmid_set_value( byte* data, long offset, byte value ) {
+
+  check((offset + PMID_CHKSUM) <= (bios_len - 1), "PMID checksum out of bounds" );
+  *( data + offset + PMID_CHKSUM ) = value;
+}
+
+
+long chksum_pcir_get_offset( byte* data, long offset ) {
+
+  long result = -1L;
+
+  while ((offset + PCIR_LEN) < (bios_len - 1)) {
+    offset = offset + 1;
+    if( *( data + offset + 0 ) == 'P' && \
+        *( data + offset + 1 ) == 'C' && \
+        *( data + offset + 2 ) == 'I' && \
+        *( data + offset + 3 ) == 'R' ) {
+      result = offset;
+      break;
+    }
+  }
+  return( result );
+}
diff --git a/qemu-0.15.x/roms/vgabios/clext.c b/qemu-0.15.x/roms/vgabios/clext.c
new file mode 100644
index 0000000..b0b6834
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/clext.c
@@ -0,0 +1,1641 @@
+//
+//  QEMU Cirrus CLGD 54xx VGABIOS Extension.
+//
+//  Copyright (c) 2004 Makoto Suzuki (suzu)
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+
+//#define CIRRUS_VESA3_PMINFO
+#ifdef VBE
+#undef CIRRUS_VESA3_PMINFO
+#endif
+
+#define PM_BIOSMEM_CURRENT_MODE 0x449
+#define PM_BIOSMEM_CRTC_ADDRESS 0x463
+#define PM_BIOSMEM_VBE_MODE 0x4BA
+
+typedef struct
+{
+  /* + 0 */
+  unsigned short mode;
+  unsigned short width;
+  unsigned short height;
+  unsigned short depth;
+  /* + 8 */
+  unsigned short hidden_dac; /* 0x3c6 */
+  unsigned short *seq; /* 0x3c4 */
+  unsigned short *graph; /* 0x3ce */
+  unsigned short *crtc; /* 0x3d4 */
+  /* +16 */
+  unsigned char bitsperpixel;
+  unsigned char vesacolortype;
+  unsigned char vesaredmask;
+  unsigned char vesaredpos;
+  unsigned char vesagreenmask;
+  unsigned char vesagreenpos;
+  unsigned char vesabluemask;
+  unsigned char vesabluepos;
+  /* +24 */
+  unsigned char vesareservedmask;
+  unsigned char vesareservedpos;
+} cirrus_mode_t;
+#define CIRRUS_MODE_SIZE 26
+
+
+/* For VESA BIOS 3.0 */
+#define CIRRUS_PM16INFO_SIZE 20
+
+/* VGA */
+unsigned short cseq_vga[] = {0x0007,0xffff};
+unsigned short cgraph_vga[] = {0x0009,0x000a,0x000b,0xffff};
+unsigned short ccrtc_vga[] = {0x001a,0x001b,0x001d,0xffff};
+
+/* extensions */
+unsigned short cgraph_svgacolor[] = {
+0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
+0x0009,0x000a,0x000b,
+0xffff
+};
+/* 640x480x8 */
+unsigned short cseq_640x480x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x8[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 640x480x16 */
+unsigned short cseq_640x480x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x16[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 640x480x24 */
+unsigned short cseq_640x480x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x580b,0x580c,0x580d,0x580e,
+0x0412,0x0013,0x2017,
+0x331b,0x331c,0x331d,0x331e,
+0xffff
+};
+unsigned short ccrtc_640x480x24[] = {
+0x2c11,
+0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+0x4009,0x000c,0x000d,
+0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 800x600x8 */
+unsigned short cseq_800x600x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x8[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 800x600x16 */
+unsigned short cseq_800x600x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x16[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 800x600x24 */
+unsigned short cseq_800x600x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x230b,0x230c,0x230d,0x230e,
+0x0412,0x0013,0x2017,
+0x141b,0x141c,0x141d,0x141e,
+0xffff
+};
+unsigned short ccrtc_800x600x24[] = {
+0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+0x6009,0x000c,0x000d,
+0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1024x768x8 */
+unsigned short cseq_1024x768x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x8[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 1024x768x16 */
+unsigned short cseq_1024x768x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x16[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1024x768x24 */
+unsigned short cseq_1024x768x24[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1024x768x24[] = {
+0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+/* 1280x1024x8 */
+unsigned short cseq_1280x1024x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1280x1024x8[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+/* 1280x1024x16 */
+unsigned short cseq_1280x1024x16[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1280x1024x16[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x321b,0x001d,
+0xffff
+};
+
+/* 1600x1200x8 */
+unsigned short cseq_1600x1200x8[] = {
+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+0x760b,0x760c,0x760d,0x760e,
+0x0412,0x0013,0x2017,
+0x341b,0x341c,0x341d,0x341e,
+0xffff
+};
+unsigned short ccrtc_1600x1200x8[] = {
+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+0x6009,0x000c,0x000d,
+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+0x001a,0x221b,0x001d,
+0xffff
+};
+
+cirrus_mode_t cirrus_modes[] =
+{
+ {0x5f,640,480,8,0x00,
+   cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x64,640,480,16,0xe1,
+   cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x66,640,480,15,0xf0,
+   cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+   6,5,10,5,5,5,0,1,15},
+ {0x71,640,480,24,0xe5,
+   cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
+   6,8,16,8,8,8,0,0,0},
+
+ {0x5c,800,600,8,0x00,
+   cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x65,800,600,16,0xe1,
+   cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x67,800,600,15,0xf0,
+   cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+   6,5,10,5,5,5,0,1,15},
+
+ {0x60,1024,768,8,0x00,
+   cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x74,1024,768,16,0xe1,
+   cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+   6,5,11,6,5,5,0,0,0},
+ {0x68,1024,768,15,0xf0,
+   cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+   6,5,10,5,5,5,0,1,15},
+
+ {0x78,800,600,24,0xe5,
+   cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
+   6,8,16,8,8,8,0,0,0},
+ {0x79,1024,768,24,0xe5,
+   cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
+   6,8,16,8,8,8,0,0,0},
+
+ {0x6d,1280,1024,8,0x00,
+   cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
+   4,0,0,0,0,0,0,0,0},
+ {0x69,1280,1024,15,0xf0,
+   cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+   6,5,10,5,5,5,0,1,15},
+ {0x75,1280,1024,16,0xe1,
+   cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+   6,5,11,6,5,5,0,0,0},
+
+ {0x7b,1600,1200,8,0x00,
+   cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
+   4,0,0,0,0,0,0,0,0},
+
+ {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
+   0xff,0,0,0,0,0,0,0,0},
+ {0xff,0,0,0,0,0,0,0,0,
+   0xff,0,0,0,0,0,0,0,0},
+};
+
+unsigned char cirrus_id_table[] = {
+  // 5430
+  0xA0, 0x32,
+  // 5446
+  0xB8, 0x39,
+
+  0xff, 0xff
+};
+
+
+unsigned short cirrus_vesa_modelist[] = {
+// 640x480x8
+  0x101, 0x5f,
+// 640x480x15
+  0x110, 0x66,
+// 640x480x16
+  0x111, 0x64,
+// 640x480x24
+  0x112, 0x71,
+// 800x600x8
+  0x103, 0x5c,
+// 800x600x15
+  0x113, 0x67,
+// 800x600x16
+  0x114, 0x65,
+// 800x600x24
+  0x115, 0x78,
+// 1024x768x8
+  0x105, 0x60,
+// 1024x768x15
+  0x116, 0x68,
+// 1024x768x16
+  0x117, 0x74,
+// 1024x768x24
+  0x118, 0x79,
+// 1280x1024x8
+  0x107, 0x6d,
+// 1280x1024x15
+  0x119, 0x69,
+// 1280x1024x16
+  0x11a, 0x75,
+// invalid
+  0xffff,0xffff
+};
+
+
+ASM_START
+
+cirrus_installed:
+.ascii "cirrus-compatible VGA is detected"
+.byte 0x0d,0x0a
+.byte 0x0d,0x0a,0x00
+
+cirrus_not_installed:
+.ascii "cirrus-compatible VGA is not detected"
+.byte 0x0d,0x0a
+.byte 0x0d,0x0a,0x00
+
+cirrus_vesa_vendorname:
+cirrus_vesa_productname:
+cirrus_vesa_oemname:
+.ascii "VGABIOS Cirrus extension"
+.byte 0
+cirrus_vesa_productrevision:
+.ascii "1.0"
+.byte 0
+
+cirrus_init:
+  call cirrus_check
+  jnz no_cirrus
+  SET_INT_VECTOR(0x10, #0xC000, #cirrus_int10_handler)
+  mov al, #0x0f ; memory setup
+  mov dx, #0x3C4
+  out dx, al
+  inc dx
+  in  al, dx
+  and al, #0x18
+  mov ah, al
+  mov al, #0x0a
+  dec dx
+  out dx, ax
+  mov ax, #0x0007 ; set vga mode
+  out dx, ax
+  mov ax, #0x0431 ; reset bitblt
+  mov dx, #0x3CE
+  out dx, ax
+  mov ax, #0x0031
+  out dx, ax
+no_cirrus:
+  ret
+
+cirrus_display_info:
+  push ds
+  push si
+  push cs
+  pop ds
+  call cirrus_check
+  mov si, #cirrus_not_installed
+  jnz cirrus_msgnotinstalled
+  mov si, #cirrus_installed
+
+cirrus_msgnotinstalled:
+  call _display_string
+  pop si
+  pop ds
+  ret
+
+cirrus_check:
+  push ax
+  push dx
+  mov ax, #0x9206
+  mov dx, #0x3C4
+  out dx, ax
+  inc dx
+  in al, dx
+  cmp al, #0x12
+  pop dx
+  pop ax
+  ret
+
+
+cirrus_int10_handler:
+  pushf
+  push bp
+  cmp ah, #0x00  ;; set video mode
+  jz cirrus_set_video_mode
+  cmp ah, #0x12  ;; cirrus extension
+  jz cirrus_extbios
+  cmp ah, #0x4F  ;; VESA extension
+  jz cirrus_vesa
+
+cirrus_unhandled:
+  pop bp
+  popf
+  jmp vgabios_int10_handler
+
+cirrus_return:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  pop bp
+  popf
+  iret
+
+cirrus_set_video_mode:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  push si
+  push ax
+  push bx
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  xor bx, bx
+  mov [PM_BIOSMEM_VBE_MODE], bx
+  pop ds
+  pop bx
+  call cirrus_get_modeentry
+  jnc cirrus_set_video_mode_extended
+  mov al, #0xfe
+  call cirrus_get_modeentry_nomask
+  call cirrus_switch_mode
+  pop ax
+  pop si
+  jmp cirrus_unhandled
+
+cirrus_extbios:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  cmp bl, #0x80
+  jb cirrus_unhandled
+  cmp bl, #0xAF
+  ja cirrus_unhandled
+  push bx
+  and bx, #0x7F
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_extbios_handlers[bx]
+  pop bx
+  push #cirrus_return
+  push bp
+  ret
+
+cirrus_vesa:
+#ifdef CIRRUS_DEBUG
+  call cirrus_debug_dump
+#endif
+  cmp al, #0x10
+  ja cirrus_vesa_not_handled
+  push bx
+  xor bx, bx
+  mov bl, al
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_vesa_handlers[bx]
+  pop bx
+  push #cirrus_return
+  push bp
+  ret
+
+cirrus_vesa_not_handled:
+  mov ax, #0x014F ;; not implemented
+  jmp cirrus_return
+
+#ifdef CIRRUS_DEBUG
+cirrus_debug_dump:
+  push es
+  push ds
+  pusha
+  push cs
+  pop ds
+  call _cirrus_debugmsg
+  popa
+  pop ds
+  pop es
+  ret
+#endif
+
+cirrus_set_video_mode_extended:
+  call cirrus_switch_mode
+  pop ax ;; mode
+  test al, #0x80
+  jnz cirrus_set_video_mode_extended_1
+  push ax
+  mov ax, #0xffff ; set to 0xff to keep win 2K happy
+  call cirrus_clear_vram
+  pop ax
+cirrus_set_video_mode_extended_1:
+  and al, #0x7f
+
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  mov [PM_BIOSMEM_CURRENT_MODE], al
+  pop ds
+
+  mov al, #0x20
+
+  pop si
+  jmp cirrus_return
+
+cirrus_vesa_pmbios_init:
+  retf
+cirrus_vesa_pmbios_entry:
+  pushf
+  push bp
+  cmp ah, #0x4F
+  jnz cirrus_vesa_pmbios_unimplemented
+  cmp al, #0x0F
+  ja cirrus_vesa_pmbios_unimplemented
+  push bx
+  xor bx, bx
+  mov bl, al
+  shl bx, 1
+ db 0x2e ;; cs:
+  mov bp, cirrus_vesa_handlers[bx]
+  pop bx
+  push #cirrus_vesa_pmbios_return
+  push bp
+  ret
+cirrus_vesa_pmbios_unimplemented:
+  mov ax, #0x014F
+cirrus_vesa_pmbios_return:
+  pop bp
+  popf
+  retf
+
+; in si:mode table
+cirrus_switch_mode:
+  push ds
+  push bx
+  push dx
+  push cs
+  pop ds
+
+  mov bx, [si+10] ;; seq
+  mov dx, #0x3c4
+  mov ax, #0x1206
+  out dx, ax ;; Unlock cirrus special
+  call cirrus_switch_mode_setregs
+
+  mov bx, [si+12] ;; graph
+  mov dx, #0x3ce
+  call cirrus_switch_mode_setregs
+
+  mov bx, [si+14] ;; crtc
+  call cirrus_get_crtc
+  call cirrus_switch_mode_setregs
+
+  mov dx, #0x3c6
+  mov al, #0x00
+  out dx, al
+  in al, dx
+  in al, dx
+  in al, dx
+  in al, dx
+  mov al, [si+8]  ;; hidden dac
+  out dx, al
+  mov al, #0xff
+  out dx, al
+
+  mov al, #0x00
+  mov bl, [si+17]  ;; memory model
+  or  bl, bl
+  jz is_text_mode
+  mov al, #0x01
+  cmp bl, #0x03
+  jnz is_text_mode
+  or al, #0x40
+is_text_mode:
+  mov bl, #0x10
+  call biosfn_get_single_palette_reg
+  and bh, #0xfe
+  or bh, al
+  call biosfn_set_single_palette_reg
+
+  pop dx
+  pop bx
+  pop ds
+  ret
+
+cirrus_enable_16k_granularity:
+  push ax
+  push dx
+  mov dx, #0x3ce
+  mov al, #0x0b
+  out dx, al
+  inc dx
+  in al, dx
+  or al, #0x20 ;; enable 16k
+  out dx, al
+  pop dx
+  pop ax
+  ret
+
+cirrus_switch_mode_setregs:
+csms_1:
+  mov ax, [bx]
+  cmp ax, #0xffff
+  jz csms_2
+  out dx, ax
+  add bx, #0x2
+  jmp csms_1
+csms_2:
+  ret
+
+cirrus_extbios_80h:
+  push dx
+  call cirrus_get_crtc
+  mov al, #0x27
+  out dx, al
+  inc dx
+  in al, dx
+  mov bx, #_cirrus_id_table
+c80h_1:
+ db 0x2e ;; cs:
+  mov ah, [bx]
+  cmp ah, al
+  jz c80h_2
+  cmp ah, #0xff
+  jz c80h_2
+  inc bx
+  inc bx
+  jmp c80h_1
+c80h_2:
+ db 0x2e ;; cs:
+  mov al, 0x1[bx]
+  pop dx
+  mov ah, #0x00
+  xor bx, bx
+  ret
+
+cirrus_extbios_81h:
+  mov ax, #0x100 ;; XXX
+  ret
+cirrus_extbios_82h:
+  push dx
+  call cirrus_get_crtc
+  xor ax, ax
+  mov al, #0x27
+  out dx, al
+  inc dx
+  in al, dx
+  and al, #0x03
+  mov ah, #0xAF
+  pop dx
+  ret
+
+cirrus_extbios_85h:
+  push cx
+  push dx
+  mov dx, #0x3C4
+  mov al, #0x0f ;; get DRAM band width
+  out dx, al
+  inc dx
+  in al, dx
+  ;; al = 4 << bandwidth
+  mov cl, al
+  shr cl, #0x03
+  and cl, #0x03
+  cmp cl, #0x03
+  je c85h2
+  mov al, #0x04
+  shl al, cl
+  jmp c85h3
+c85h2:
+;; 4MB or 2MB
+  and al, #0x80
+  mov al, #0x20 ;; 2 MB
+  je c85h3
+  mov al, #0x40 ;; 4 MB
+c85h3:
+  pop dx
+  pop cx
+  ret
+
+cirrus_extbios_9Ah:
+  mov ax, #0x4060
+  mov cx, #0x1132
+  ret
+
+cirrus_extbios_A0h:
+  call cirrus_get_modeentry
+  mov ah, #0x01
+  sbb ah, #0x00
+  mov bx, cirrus_extbios_A0h_callback
+  mov si, #0xffff
+  mov di, bx
+  mov ds, bx
+  mov es, bx
+  ret
+
+cirrus_extbios_A0h_callback:
+  ;; fatal: not implemented yet
+  cli
+  hlt
+  retf
+
+cirrus_extbios_A1h:
+  mov bx, #0x0E00 ;; IBM 8512/8513, color
+  ret
+
+cirrus_extbios_A2h:
+  mov al, #0x07   ;; HSync 31.5 - 64.0 kHz
+  ret
+
+cirrus_extbios_AEh:
+  mov al, #0x01   ;; High Refresh 75Hz
+  ret
+
+cirrus_extbios_unimplemented:
+  ret
+
+cirrus_vesa_00h:
+  push ds
+  push si
+  mov bp, di
+  push es
+  pop ds
+  cld
+  mov ax, [di]
+  cmp ax, #0x4256 ;; VB
+  jnz cv00_1
+  mov ax, [di+2]
+  cmp ax, #0x3245 ;; E2
+  jnz cv00_1
+  ;; VBE2
+  lea di, 0x14[bp]
+  mov ax, #0x0100 ;; soft ver.
+  stosw
+  mov ax, # cirrus_vesa_vendorname
+  stosw
+  mov ax, cs
+  stosw
+  mov ax, # cirrus_vesa_productname
+  stosw
+  mov ax, cs
+  stosw
+  mov ax, # cirrus_vesa_productrevision
+  stosw
+  mov ax, cs
+  stosw
+cv00_1:
+  mov di, bp
+  mov ax, #0x4556 ;; VE
+  stosw
+  mov ax, #0x4153 ;; SA
+  stosw
+  mov ax, #0x0200 ;; v2.00
+  stosw
+  mov ax, # cirrus_vesa_oemname
+  stosw
+  mov ax, cs
+  stosw
+  xor ax, ax ;; caps
+  stosw
+  stosw
+  lea ax, 0x40[bp]
+  stosw
+  mov ax, es
+  stosw
+  call cirrus_extbios_85h ;; vram in 64k
+  mov ah, #0x00
+  stosw
+
+  push cs
+  pop ds
+  lea di, 0x40[bp]
+  mov si, #_cirrus_vesa_modelist
+cv00_2:
+  lodsw
+  stosw
+  add si, #2
+  cmp ax, #0xffff
+  jnz cv00_2
+
+  mov ax, #0x004F
+  mov di, bp
+  pop si
+  pop ds
+  ret
+
+cirrus_vesa_01h:
+  mov ax, cx
+  and ax, #0x3fff
+  call cirrus_vesamode_to_mode
+  cmp ax, #0xffff
+  jnz cirrus_vesa_01h_1
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_01h_1:
+  push ds
+  push si
+  push cx
+  push dx
+  push bx
+  mov bp, di
+  cld
+  push cs
+  pop ds
+  call cirrus_get_modeentry_nomask
+
+  push di
+  xor ax, ax
+  mov cx, #0x80
+  rep
+    stosw ;; clear buffer
+  pop di
+
+  mov ax, #0x003b ;; mode
+  stosw
+  mov ax, #0x0007 ;; attr
+  stosw
+  mov ax, #0x0010 ;; granularity =16K
+  stosw
+  mov ax, #0x0040 ;; size =64K
+  stosw
+  mov ax, #0xA000 ;; segment A
+  stosw
+  xor ax, ax ;; no segment B
+  stosw
+  mov ax, #cirrus_vesa_05h_farentry
+  stosw
+  mov ax, cs
+  stosw
+  call cirrus_get_line_offset_entry
+  stosw ;; bytes per scan line
+  mov ax, [si+2] ;; width
+  stosw
+  mov ax, [si+4] ;; height
+  stosw
+  mov ax, #0x08
+  stosb
+  mov ax, #0x10
+  stosb
+  mov al, #1 ;; count of planes
+  stosb
+  mov al, [si+6] ;; bpp
+  stosb
+  mov al, #0x1 ;; XXX number of banks
+  stosb
+  mov al, [si+17]
+  stosb ;; memory model
+  mov al, #0x0   ;; XXX size of bank in K
+  stosb
+  call cirrus_get_line_offset_entry
+  mov bx, [si+4]
+  mul bx ;; dx:ax=vramdisp
+  or ax, ax
+  jz cirrus_vesa_01h_3
+  inc dx
+cirrus_vesa_01h_3:
+  call cirrus_extbios_85h ;; al=vram in 64k
+  mov ah, #0x00
+  mov cx, dx
+  xor dx, dx
+  div cx
+  dec ax
+  stosb  ;; number of image pages = vramtotal/vramdisp-1
+  mov al, #0x00
+  stosb
+
+  ;; v1.2+ stuffs
+  push si
+  add si, #18
+  movsw
+  movsw
+  movsw
+  movsw
+  pop si
+
+  mov ah, [si+16]
+  mov al, #0x0
+  sub ah, #9
+  rcl al, #1 ; bit 0=palette flag
+  stosb ;; direct screen mode info
+
+  ;; v2.0+ stuffs
+  ;; 32-bit LFB address
+  xor ax, ax
+  stosw
+  mov ax, #0x1013 ;; vendor Cirrus
+  call _pci_get_lfb_addr
+  stosw
+  or ax, ax
+  jz cirrus_vesa_01h_4
+  push di
+  mov di, bp
+ db 0x26 ;; es:
+  mov ax, [di]
+  or ax, #0x0080 ;; mode bit 7:LFB
+  stosw
+  pop di
+cirrus_vesa_01h_4:
+
+  xor ax, ax
+  stosw ; reserved
+  stosw ; reserved
+  stosw ; reserved
+
+  mov ax, #0x004F
+  mov di, bp
+  pop bx
+  pop dx
+  pop cx
+  pop si
+  pop ds
+
+  test cx, #0x4000 ;; LFB flag
+  jz cirrus_vesa_01h_5
+  push cx
+ db 0x26 ;; es:
+  mov cx, [di]
+  cmp cx, #0x0080 ;; is LFB supported?
+  jnz cirrus_vesa_01h_6
+  mov ax, #0x014F ;; error - no LFB
+cirrus_vesa_01h_6:
+  pop cx
+cirrus_vesa_01h_5:
+  ret
+
+cirrus_vesa_02h:
+  ;; XXX support CRTC registers
+  test bx, #0x3e00
+  jnz cirrus_vesa_02h_2 ;; unknown flags
+  mov ax, bx
+  and ax, #0x1ff ;; bit 8-0 mode
+  cmp ax, #0x100 ;; legacy VGA mode
+  jb cirrus_vesa_02h_legacy
+  call cirrus_vesamode_to_mode
+  cmp ax, #0xffff
+  jnz cirrus_vesa_02h_1
+cirrus_vesa_02h_2:
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_02h_legacy:
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  cmp byte ptr [cirrus_vesa_is_protected_mode], #0
+  jnz cirrus_vesa_02h_2
+#endif // CIRRUS_VESA3_PMINFO
+  int #0x10
+  mov ax, #0x004F
+  ret
+cirrus_vesa_02h_1:
+  push si
+  push ax
+  call cirrus_get_modeentry_nomask
+  call cirrus_switch_mode
+  test bx, #0x4000 ;; LFB
+  jnz cirrus_vesa_02h_3
+  call cirrus_enable_16k_granularity
+cirrus_vesa_02h_3:
+  test bx, #0x8000 ;; no clear
+  jnz cirrus_vesa_02h_4
+  push ax
+  xor ax,ax
+  call cirrus_clear_vram
+  pop ax
+cirrus_vesa_02h_4:
+  pop ax
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov si, [cirrus_vesa_sel0000_data]
+#else
+  xor si, si
+#endif
+  mov ds, si
+  mov [PM_BIOSMEM_CURRENT_MODE], al
+  mov [PM_BIOSMEM_VBE_MODE], bx
+  pop ds
+  pop si
+  mov ax, #0x004F
+  ret
+
+cirrus_vesa_03h:
+  push ds
+#ifdef CIRRUS_VESA3_PMINFO
+ db 0x2e ;; cs:
+  mov ax, [cirrus_vesa_sel0000_data]
+#else
+  xor ax, ax
+#endif
+  mov  ds, ax
+  mov  bx, # PM_BIOSMEM_VBE_MODE
+  mov  ax, [bx]
+  mov  bx, ax
+  test bx, bx
+  jnz   cirrus_vesa_03h_1
+  mov  bx, # PM_BIOSMEM_CURRENT_MODE
+  mov  al, [bx]
+  mov  bl, al
+  xor  bh, bh
+cirrus_vesa_03h_1:
+  mov  ax, #0x004f
+  pop  ds
+  ret
+
+cirrus_vesa_05h_farentry:
+  call cirrus_vesa_05h
+  retf
+
+cirrus_vesa_05h:
+  cmp bl, #0x01
+  ja cirrus_vesa_05h_1
+  cmp bh, #0x00
+  jz cirrus_vesa_05h_setmempage
+  cmp bh, #0x01
+  jz cirrus_vesa_05h_getmempage
+cirrus_vesa_05h_1:
+  jmp cirrus_vesa_unimplemented
+cirrus_vesa_05h_setmempage:
+  or dh, dh ; address must be < 0x100
+  jnz cirrus_vesa_05h_1
+  push dx
+  mov al, bl ;; bl=bank number
+  add al, #0x09
+  mov ah, dl ;; dx=window address in granularity
+  mov dx, #0x3ce
+  out dx, ax
+  pop dx
+  mov ax, #0x004F
+  ret
+cirrus_vesa_05h_getmempage:
+  mov al, bl ;; bl=bank number
+  add al, #0x09
+  mov dx, #0x3ce
+  out dx, al
+  inc dx
+  in al, dx
+  xor dx, dx
+  mov dl, al ;; dx=window address in granularity
+  mov ax, #0x004F
+  ret
+
+cirrus_vesa_06h:
+  mov  ax, cx
+  cmp  bl, #0x01
+  je   cirrus_vesa_06h_3
+  cmp  bl, #0x02
+  je   cirrus_vesa_06h_2
+  jb   cirrus_vesa_06h_1
+  mov  ax, #0x0100
+  ret
+cirrus_vesa_06h_1:
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  mov  ax, cx
+  mul  bx
+cirrus_vesa_06h_2:
+  call cirrus_set_line_offset
+cirrus_vesa_06h_3:
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  xor  dx, dx
+  call cirrus_get_line_offset
+  push ax
+  div  bx
+  mov  cx, ax
+  pop  bx
+  call cirrus_extbios_85h ;; al=vram in 64k
+  xor  dx, dx
+  mov  dl, al
+  xor  ax, ax
+  div  bx
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+
+cirrus_vesa_07h:
+  cmp  bl, #0x80
+  je   cirrus_vesa_07h_1
+  cmp  bl, #0x01
+  je   cirrus_vesa_07h_2
+  jb   cirrus_vesa_07h_1
+  mov  ax, #0x0100
+  ret
+cirrus_vesa_07h_1:
+  push dx
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  mov  ax, cx
+  mul  bx
+  pop  bx
+  push ax
+  call cirrus_get_line_offset
+  mul  bx
+  pop  bx
+  add  ax, bx
+  jnc  cirrus_vesa_07h_3
+  inc  dx
+cirrus_vesa_07h_3:
+  push dx
+  and  dx, #0x0003
+  mov  bx, #0x04
+  div  bx
+  pop  dx
+  shr  dx, #2
+  call cirrus_set_start_addr
+  mov  ax, #0x004f
+  ret
+cirrus_vesa_07h_2:
+  call cirrus_get_start_addr
+  shl  dx, #2
+  push dx
+  mov  bx, #0x04
+  mul  bx
+  pop  bx
+  or   dx, bx
+  push ax
+  call cirrus_get_line_offset
+  mov  bx, ax
+  pop  ax
+  div  bx
+  push ax
+  push dx
+  call cirrus_get_bpp_bytes
+  mov  bl, al
+  xor  bh, bh
+  pop  ax
+  xor  dx, dx
+  div  bx
+  mov  cx, ax
+  pop  dx
+  mov  ax, #0x004f
+  ret
+
+cirrus_vesa_10h:
+  cmp bl, #0x00
+  jne cirrus_vesa_10h_01
+  mov bx, #0x0f30
+  mov ax, #0x004f
+  ret
+cirrus_vesa_10h_01:
+  cmp bl, #0x01
+  jne cirrus_vesa_10h_02
+  push dx
+  push ds
+  mov dx, #0x40
+  mov ds, dx
+  mov [0xb9], bh
+  pop ds
+  pop dx
+  mov ax, #0x004f
+  ret
+cirrus_vesa_10h_02:
+  cmp bl, #0x02
+  jne cirrus_vesa_unimplemented
+  push dx
+  push ds
+  mov dx, #0x40
+  mov ds, dx
+  mov bh, [0xb9]
+  pop ds
+  pop dx
+  mov ax, #0x004f
+  ret
+
+cirrus_vesa_unimplemented:
+  mov ax, #0x014F ;; not implemented
+  ret
+
+
+;; in ax:vesamode, out ax:cirrusmode
+cirrus_vesamode_to_mode:
+  push ds
+  push cx
+  push si
+  push cs
+  pop ds
+  mov cx, #0xffff
+  mov si, #_cirrus_vesa_modelist
+cvtm_1:
+  cmp [si],ax
+  jz cvtm_2
+  cmp [si],cx
+  jz cvtm_2
+  add si, #4
+  jmp cvtm_1
+cvtm_2:
+  mov ax,[si+2]
+  pop si
+  pop cx
+  pop ds
+  ret
+
+  ; cirrus_get_crtc
+  ;; NOTE - may be called in protected mode
+cirrus_get_crtc:
+  push ds
+  push ax
+  mov  dx, #0x3cc
+  in   al, dx
+  and  al, #0x01
+  shl  al, #5
+  mov  dx, #0x3b4
+  add  dl, al
+  pop  ax
+  pop  ds
+  ret
+
+;; in - al:mode, out - cflag:result, si:table, ax:destroyed
+cirrus_get_modeentry:
+  and al, #0x7f
+cirrus_get_modeentry_nomask:
+  mov si, #_cirrus_modes
+cgm_1:
+ db 0x2e ;; cs:
+  mov ah, [si]
+  cmp al, ah
+  jz cgm_2
+  cmp ah, #0xff
+  jz cgm_4
+  add si, # CIRRUS_MODE_SIZE
+  jmp cgm_1
+cgm_4:
+  xor si, si
+  stc ;; video mode is not supported
+  jmp cgm_3
+cgm_2:
+  clc ;; video mode is supported
+cgm_3:
+  ret
+
+;; out - al:bytes per pixel
+cirrus_get_bpp_bytes:
+  push dx
+  mov  dx, #0x03c4
+  mov  al, #0x07
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x0e
+  cmp  al, #0x06
+  jne  cirrus_get_bpp_bytes_1
+  and  al, #0x02
+cirrus_get_bpp_bytes_1:
+  shr  al, #1
+  cmp  al, #0x04
+  je  cirrus_get_bpp_bytes_2
+  inc  al
+cirrus_get_bpp_bytes_2:
+  pop  dx
+  ret
+
+;; in - ax: new line offset
+cirrus_set_line_offset:
+  shr  ax, #3
+  push ax
+  call cirrus_get_crtc
+  mov  al, #0x13
+  out  dx, al
+  inc  dx
+  pop  ax
+  out  dx, al
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  shl  ah, #4
+  in   al, dx
+  and  al, #ef
+  or   al, ah
+  out  dx, al
+  ret
+
+;; out - ax: active line offset
+cirrus_get_line_offset:
+  push dx
+  push bx
+  call cirrus_get_crtc
+  mov  al, #0x13
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  bl, al
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  ah, al
+  shr  ah, #4
+  and  ah, #0x01
+  mov  al, bl
+  shl  ax, #3
+  pop  bx
+  pop  dx
+  ret
+
+;; in - si: table
+;; out - ax: line offset for mode
+cirrus_get_line_offset_entry:
+  push bx
+  mov  bx, [si+14] ;; crtc table
+  push bx
+offset_loop1:
+  mov  ax, [bx]
+  cmp  al, #0x13
+  je   offset_found1
+  inc  bx
+  inc  bx
+  jnz  offset_loop1
+offset_found1:
+  xor  al, al
+  shr  ax, #5
+  pop  bx
+  push ax
+offset_loop2:
+  mov  ax, [bx]
+  cmp  al, #0x1b
+  je offset_found2
+  inc  bx
+  inc  bx
+  jnz offset_loop2
+offset_found2:
+  pop  bx
+  and  ax, #0x1000
+  shr  ax, #1
+  or   ax, bx
+  pop  bx
+  ret
+
+;; in - new address in DX:AX
+cirrus_set_start_addr:
+  push bx
+  push dx
+  push ax
+  call cirrus_get_crtc
+  mov  al, #0x0d
+  out  dx, al
+  inc  dx
+  pop  ax
+  out  dx, al
+  dec  dx
+  mov  al, #0x0c
+  out  dx, al
+  inc  dx
+  mov  al, ah
+  out  dx, al
+  dec  dx
+  mov  al, #0x1d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x7f
+  pop  bx
+  mov  ah, bl
+  shl  bl, #4
+  and  bl, #0x80
+  or   al, bl
+  out  dx, al
+  dec  dx
+  mov  bl, ah
+  and  ah, #0x01
+  shl  bl, #1
+  and  bl, #0x0c
+  or   ah, bl
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0xf2
+  or   al, ah
+  out  dx, al
+  pop  bx
+  ret
+
+;; out - current address in DX:AX
+cirrus_get_start_addr:
+  push bx
+  call cirrus_get_crtc
+  mov  al, #0x0c
+  out  dx, al
+  inc  dx
+  in   al, dx
+  mov  ah, al
+  dec  dx
+  mov  al, #0x0d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  push ax
+  dec  dx
+  mov  al, #0x1b
+  out  dx, al
+  inc  dx
+  in   al, dx
+  dec  dx
+  mov  bl, al
+  and  al, #0x01
+  and  bl, #0x0c
+  shr  bl, #1
+  or   bl, al
+  mov  al, #0x1d
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0x80
+  shr  al, #4
+  or   bl, al
+  mov  dl, bl
+  xor  dh, dh
+  pop  ax
+  pop  bx
+  ret
+
+cirrus_clear_vram:
+  pusha
+  push es
+  mov si, ax
+
+  call cirrus_enable_16k_granularity
+  call cirrus_extbios_85h
+  shl al, #2
+  mov bl, al
+  xor ah,ah
+cirrus_clear_vram_1:
+  mov al, #0x09
+  mov dx, #0x3ce
+  out dx, ax
+  push ax
+  mov cx, #0xa000
+  mov es, cx
+  xor di, di
+  mov ax, si
+  mov cx, #8192
+  cld
+  rep 
+      stosw
+  pop ax
+  inc ah
+  cmp ah, bl
+  jne cirrus_clear_vram_1
+
+  xor ah,ah
+  mov dx, #0x3ce
+  out dx, ax
+
+  pop es
+  popa
+  ret
+
+cirrus_extbios_handlers:
+  ;; 80h
+  dw cirrus_extbios_80h
+  dw cirrus_extbios_81h
+  dw cirrus_extbios_82h
+  dw cirrus_extbios_unimplemented
+  ;; 84h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_85h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 88h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 8Ch
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 90h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 94h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; 98h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_9Ah
+  dw cirrus_extbios_unimplemented
+  ;; 9Ch
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; A0h
+  dw cirrus_extbios_A0h
+  dw cirrus_extbios_A1h
+  dw cirrus_extbios_A2h
+  dw cirrus_extbios_unimplemented
+  ;; A4h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; A8h
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  ;; ACh
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_unimplemented
+  dw cirrus_extbios_AEh
+  dw cirrus_extbios_unimplemented
+
+cirrus_vesa_handlers:
+  ;; 00h
+  dw cirrus_vesa_00h
+  dw cirrus_vesa_01h
+  dw cirrus_vesa_02h
+  dw cirrus_vesa_03h
+  ;; 04h
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_05h
+  dw cirrus_vesa_06h
+  dw cirrus_vesa_07h
+  ;; 08h
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  ;; 0Ch
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  dw cirrus_vesa_unimplemented
+  ;; 10h
+  dw cirrus_vesa_10h
+
+
+ASM_END
+
+#ifdef CIRRUS_VESA3_PMINFO
+ASM_START
+cirrus_vesa_pminfo:
+  /* + 0 */
+  .byte 0x50,0x4d,0x49,0x44 ;; signature[4]
+  /* + 4 */
+  dw cirrus_vesa_pmbios_entry ;; entry_bios
+  dw cirrus_vesa_pmbios_init  ;; entry_init
+  /* + 8 */
+cirrus_vesa_sel0000_data:
+  dw 0x0000 ;; sel_00000
+cirrus_vesa_selA000_data:
+  dw 0xA000 ;; sel_A0000
+  /* +12 */
+cirrus_vesa_selB000_data:
+  dw 0xB000 ;; sel_B0000
+cirrus_vesa_selB800_data:
+  dw 0xB800 ;; sel_B8000
+  /* +16 */
+cirrus_vesa_selC000_data:
+  dw 0xC000 ;; sel_C0000
+cirrus_vesa_is_protected_mode:
+  ;; protected mode flag and checksum
+  dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \
+     + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01
+ASM_END
+#endif // CIRRUS_VESA3_PMINFO
+
+
+#ifdef CIRRUS_DEBUG
+static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05))
+  printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
diff --git a/qemu-0.15.x/roms/vgabios/dataseghack b/qemu-0.15.x/roms/vgabios/dataseghack
new file mode 100755
index 0000000..02a2d4c
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/dataseghack
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+awk \
+  'BEGIN { }\
+  /^\.text/,/DATA_SEG_DEFS_HERE/ { print }\
+  END { }'\
+  $1 > temp.awk.1
+
+awk \
+  'BEGIN { i = 0; last = "hello" }\
+  /BLOCK_STRINGS_BEGIN/,/^\.bss/ { if ( i > 1 ) { print last } last = $0; i = i + 1 }\
+  END { }'\
+  $1 > temp.awk.2
+
+awk \
+  'BEGIN { }\
+  /DATA_SEG_DEFS_HERE/,/BLOCK_STRINGS_BEGIN/ { print }\
+  END { }'\
+  $1 > temp.awk.3
+
+cp $1 $1.orig
+cat temp.awk.1 temp.awk.2 temp.awk.3 | sed -e 's/^\.data//' -e 's/^\.bss//' -e 's/^\.text//' > $1
+/bin/rm -f temp.awk.1 temp.awk.2 temp.awk.3 $1.orig
diff --git a/qemu-0.15.x/roms/vgabios/tests/lfbprof/Makefile b/qemu-0.15.x/roms/vgabios/tests/lfbprof/Makefile
new file mode 100644
index 0000000..7c42e38
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/tests/lfbprof/Makefile
@@ -0,0 +1,5 @@
+# Very simple makefile for LFBPROF.C using Watcom C++ 10.0a with DOS4GW
+
+lfbprof.exe: lfbprof.c lfbprof.h
+    wcl386 -zq -s -d2 lfbprof.c
+
diff --git a/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.c b/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.c
new file mode 100644
index 0000000..df37452
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.c
@@ -0,0 +1,594 @@
+/****************************************************************************
+*
+*                   VBE 2.0 Linear Framebuffer Profiler
+*                    By Kendall Bennett and Brian Hook
+*
+* Filename:     LFBPROF.C
+* Language:     ANSI C
+* Environment:  Watcom C/C++ 10.0a with DOS4GW
+*
+* Description:  Simple program to profile the speed of screen clearing
+*               and full screen BitBlt operations using a VESA VBE 2.0
+*               linear framebuffer from 32 bit protected mode.
+*
+*               For simplicity, this program only supports 256 color
+*               SuperVGA video modes that support a linear framebuffer.
+*
+*
+* 2002/02/18: Jeroen Janssen <japj at xs4all dot nl>
+*               - fixed unsigned short for mode list (-1 != 0xffff otherwise)
+*               - fixed LfbMapRealPointer macro mask problem (some modes were skipped)
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <dos.h>
+#include "lfbprof.h"
+
+/*---------------------------- Global Variables ---------------------------*/
+
+int     VESABuf_len = 1024;         /* Length of VESABuf                */
+int     VESABuf_sel = 0;            /* Selector for VESABuf             */
+int     VESABuf_rseg;               /* Real mode segment of VESABuf     */
+unsigned short   modeList[50];      /* List of available VBE modes      */
+float   clearsPerSec;               /* Number of clears per second      */
+float   clearsMbPerSec;             /* Memory transfer for clears       */
+float   bitBltsPerSec;              /* Number of BitBlt's per second    */
+float   bitBltsMbPerSec;            /* Memory transfer for bitblt's     */
+int     xres,yres;                  /* Video mode resolution            */
+int     bytesperline;               /* Bytes per scanline for mode      */
+long    imageSize;                  /* Length of the video image        */
+char    *LFBPtr;                	/* Pointer to linear framebuffer    */
+
+/*------------------------- DPMI interface routines -----------------------*/
+
+void DPMI_allocRealSeg(int size,int *sel,int *r_seg)
+/****************************************************************************
+*
+* Function:     DPMI_allocRealSeg
+* Parameters:   size    - Size of memory block to allocate
+*               sel     - Place to return protected mode selector
+*               r_seg   - Place to return real mode segment
+*
+* Description:  Allocates a block of real mode memory using DPMI services.
+*               This routine returns both a protected mode selector and
+*               real mode segment for accessing the memory block.
+*
+****************************************************************************/
+{
+    union REGS      r;
+
+    r.w.ax = 0x100;                 /* DPMI allocate DOS memory         */
+    r.w.bx = (size + 0xF) >> 4;     /* number of paragraphs             */
+    int386(0x31, &r, &r);
+    if (r.w.cflag)
+        FatalError("DPMI_allocRealSeg failed!");
+    *sel = r.w.dx;                  /* Protected mode selector          */
+    *r_seg = r.w.ax;                /* Real mode segment                */
+}
+
+void DPMI_freeRealSeg(unsigned sel)
+/****************************************************************************
+*
+* Function:     DPMI_allocRealSeg
+* Parameters:   sel - Protected mode selector of block to free
+*
+* Description:  Frees a block of real mode memory.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 0x101;                 /* DPMI free DOS memory             */
+    r.w.dx = sel;                   /* DX := selector from 0x100        */
+    int386(0x31, &r, &r);
+}
+
+typedef struct {
+    long    edi;
+    long    esi;
+    long    ebp;
+    long    reserved;
+    long    ebx;
+    long    edx;
+    long    ecx;
+    long    eax;
+    short   flags;
+    short   es,ds,fs,gs,ip,cs,sp,ss;
+    } _RMREGS;
+
+#define IN(reg)     rmregs.e##reg = in->x.reg
+#define OUT(reg)    out->x.reg = rmregs.e##reg
+
+int DPMI_int86(int intno, RMREGS *in, RMREGS *out)
+/****************************************************************************
+*
+* Function:     DPMI_int86
+* Parameters:   intno   - Interrupt number to issue
+*               in      - Pointer to structure for input registers
+*               out     - Pointer to structure for output registers
+* Returns:      Value returned by interrupt in AX
+*
+* Description:  Issues a real mode interrupt using DPMI services.
+*
+****************************************************************************/
+{
+    _RMREGS         rmregs;
+    union REGS      r;
+    struct SREGS    sr;
+
+    memset(&rmregs, 0, sizeof(rmregs));
+    IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di);
+
+    segread(&sr);
+    r.w.ax = 0x300;                 /* DPMI issue real interrupt        */
+    r.h.bl = intno;
+    r.h.bh = 0;
+    r.w.cx = 0;
+    sr.es = sr.ds;
+    r.x.edi = (unsigned)&rmregs;
+    int386x(0x31, &r, &r, &sr);     /* Issue the interrupt              */
+
+    OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di);
+    out->x.cflag = rmregs.flags & 0x1;
+    return out->x.ax;
+}
+
+int DPMI_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs)
+/****************************************************************************
+*
+* Function:     DPMI_int86
+* Parameters:   intno   - Interrupt number to issue
+*               in      - Pointer to structure for input registers
+*               out     - Pointer to structure for output registers
+*               sregs   - Values to load into segment registers
+* Returns:      Value returned by interrupt in AX
+*
+* Description:  Issues a real mode interrupt using DPMI services.
+*
+****************************************************************************/
+{
+    _RMREGS         rmregs;
+    union REGS      r;
+    struct SREGS    sr;
+
+    memset(&rmregs, 0, sizeof(rmregs));
+    IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di);
+    rmregs.es = sregs->es;
+    rmregs.ds = sregs->ds;
+
+    segread(&sr);
+    r.w.ax = 0x300;                 /* DPMI issue real interrupt        */
+    r.h.bl = intno;
+    r.h.bh = 0;
+    r.w.cx = 0;
+    sr.es = sr.ds;
+    r.x.edi = (unsigned)&rmregs;
+    int386x(0x31, &r, &r, &sr);     /* Issue the interrupt */
+
+    OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di);
+    sregs->es = rmregs.es;
+    sregs->cs = rmregs.cs;
+    sregs->ss = rmregs.ss;
+    sregs->ds = rmregs.ds;
+    out->x.cflag = rmregs.flags & 0x1;
+    return out->x.ax;
+}
+
+int DPMI_allocSelector(void)
+/****************************************************************************
+*
+* Function:     DPMI_allocSelector
+* Returns:      Newly allocated protected mode selector
+*
+* Description:  Allocates a new protected mode selector using DPMI
+*               services. This selector has a base address and limit of 0.
+*
+****************************************************************************/
+{
+    int         sel;
+    union REGS  r;
+
+    r.w.ax = 0;                     /* DPMI allocate selector           */
+    r.w.cx = 1;                     /* Allocate a single selector       */
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_allocSelector() failed!");
+    sel = r.w.ax;
+
+    r.w.ax = 9;                     /* DPMI set access rights           */
+    r.w.bx = sel;
+    r.w.cx = 0x8092;                /* 32 bit page granular             */
+    int386(0x31, &r, &r);
+    return sel;
+}
+
+long DPMI_mapPhysicalToLinear(long physAddr,long limit)
+/****************************************************************************
+*
+* Function:     DPMI_mapPhysicalToLinear
+* Parameters:   physAddr    - Physical memory address to map
+*               limit       - Length-1 of physical memory region to map
+* Returns:      Starting linear address for mapped memory
+*
+* Description:  Maps a section of physical memory into the linear address
+*               space of a process using DPMI calls. Note that this linear
+*               address cannot be used directly, but must be used as the
+*               base address for a selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 0x800;                 /* DPMI map physical to linear      */
+    r.w.bx = physAddr >> 16;
+    r.w.cx = physAddr & 0xFFFF;
+    r.w.si = limit >> 16;
+    r.w.di = limit & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_mapPhysicalToLinear() failed!");
+    return ((long)r.w.bx << 16) + r.w.cx;
+}
+
+void DPMI_setSelectorBase(int sel,long linAddr)
+/****************************************************************************
+*
+* Function:     DPMI_setSelectorBase
+* Parameters:   sel     - Selector to change base address for
+*               linAddr - Linear address used for new base address
+*
+* Description:  Sets the base address for the specified selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 7;                     /* DPMI set selector base address   */
+    r.w.bx = sel;
+    r.w.cx = linAddr >> 16;
+    r.w.dx = linAddr & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_setSelectorBase() failed!");
+}
+
+void DPMI_setSelectorLimit(int sel,long limit)
+/****************************************************************************
+*
+* Function:     DPMI_setSelectorLimit
+* Parameters:   sel     - Selector to change limit for
+*               limit   - Limit-1 for the selector
+*
+* Description:  Sets the memory limit for the specified selector.
+*
+****************************************************************************/
+{
+    union REGS  r;
+
+    r.w.ax = 8;                     /* DPMI set selector limit          */
+    r.w.bx = sel;
+    r.w.cx = limit >> 16;
+    r.w.dx = limit & 0xFFFF;
+    int386(0x31, &r, &r);
+    if (r.x.cflag)
+        FatalError("DPMI_setSelectorLimit() failed!");
+}
+
+/*-------------------------- VBE Interface routines -----------------------*/
+
+void FatalError(char *msg)
+{
+    fprintf(stderr,"%s\n", msg);
+    exit(1);
+}
+
+static void ExitVBEBuf(void)
+{
+    DPMI_freeRealSeg(VESABuf_sel);
+}
+
+void VBE_initRMBuf(void)
+/****************************************************************************
+*
+* Function:     VBE_initRMBuf
+* Description:  Initialises the VBE transfer buffer in real mode memory.
+*               This routine is called by the VESAVBE module every time
+*               it needs to use the transfer buffer, so we simply allocate
+*               it once and then return.
+*
+****************************************************************************/
+{
+    if (!VESABuf_sel) {
+        DPMI_allocRealSeg(VESABuf_len, &VESABuf_sel, &VESABuf_rseg);
+        atexit(ExitVBEBuf);
+        }
+}
+
+void VBE_callESDI(RMREGS *regs, void *buffer, int size)
+/****************************************************************************
+*
+* Function:     VBE_callESDI
+* Parameters:   regs    - Registers to load when calling VBE
+*               buffer  - Buffer to copy VBE info block to
+*               size    - Size of buffer to fill
+*
+* Description:  Calls the VESA VBE and passes in a buffer for the VBE to
+*               store information in, which is then copied into the users
+*               buffer space. This works in protected mode as the buffer
+*               passed to the VESA VBE is allocated in conventional
+*               memory, and is then copied into the users memory block.
+*
+****************************************************************************/
+{
+    RMSREGS sregs;
+
+    VBE_initRMBuf();
+    sregs.es = VESABuf_rseg;
+    regs->x.di = 0;
+    _fmemcpy(MK_FP(VESABuf_sel,0),buffer,size);
+    DPMI_int86x(0x10, regs, regs, &sregs);
+    _fmemcpy(buffer,MK_FP(VESABuf_sel,0),size);
+}
+
+int VBE_detect(void)
+/****************************************************************************
+*
+* Function:     VBE_detect
+* Parameters:   vgaInfo - Place to store the VGA information block
+* Returns:      VBE version number, or 0 if not detected.
+*
+* Description:  Detects if a VESA VBE is out there and functioning
+*               correctly. If we detect a VBE interface we return the
+*               VGAInfoBlock returned by the VBE and the VBE version number.
+*
+****************************************************************************/
+{
+    RMREGS      regs;
+    unsigned    short    *p1,*p2;
+    VBE_vgaInfo vgaInfo;
+
+    /* Put 'VBE2' into the signature area so that the VBE 2.0 BIOS knows
+     * that we have passed a 512 byte extended block to it, and wish
+     * the extended information to be filled in.
+     */
+    strncpy(vgaInfo.VESASignature,"VBE2",4);
+
+    /* Get the SuperVGA Information block */
+    regs.x.ax = 0x4F00;
+    VBE_callESDI(&regs, &vgaInfo, sizeof(VBE_vgaInfo));
+    if (regs.x.ax != 0x004F)
+        return 0;
+    if (strncmp(vgaInfo.VESASignature,"VESA",4) != 0)
+        return 0;
+
+    /* Now that we have detected a VBE interface, copy the list of available
+     * video modes into our local buffer. We *must* copy this mode list,
+     * since the VBE will build the mode list in the VBE_vgaInfo buffer
+     * that we have passed, so the next call to the VBE will trash the
+     * list of modes.
+     */
+    printf("videomodeptr %x\n",vgaInfo.VideoModePtr);
+    p1 = LfbMapRealPointer(vgaInfo.VideoModePtr);
+    p2 = modeList;
+    while (*p1 != -1)
+    {
+        printf("found mode %x\n",*p1);
+        *p2++ = *p1++;
+    }
+    *p2 = -1;
+    return vgaInfo.VESAVersion;
+}
+
+int VBE_getModeInfo(int mode,VBE_modeInfo *modeInfo)
+/****************************************************************************
+*
+* Function:     VBE_getModeInfo
+* Parameters:   mode        - VBE mode to get information for
+*               modeInfo    - Place to store VBE mode information
+* Returns:      1 on success, 0 if function failed.
+*
+* Description:  Obtains information about a specific video mode from the
+*               VBE. You should use this function to find the video mode
+*               you wish to set, as the new VBE 2.0 mode numbers may be
+*               completely arbitrary.
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+
+    regs.x.ax = 0x4F01;             /* Get mode information         */
+    regs.x.cx = mode;
+    VBE_callESDI(&regs, modeInfo, sizeof(VBE_modeInfo));
+    if (regs.x.ax != 0x004F)
+        return 0;
+    if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0)
+        return 0;
+    return 1;
+}
+
+void VBE_setVideoMode(int mode)
+/****************************************************************************
+*
+* Function:     VBE_setVideoMode
+* Parameters:   mode    - VBE mode number to initialise
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+    regs.x.ax = 0x4F02;
+    regs.x.bx = mode;
+    DPMI_int86(0x10,&regs,&regs);
+}
+
+/*-------------------- Application specific routines ----------------------*/
+
+void *GetPtrToLFB(long physAddr)
+/****************************************************************************
+*
+* Function:     GetPtrToLFB
+* Parameters:   physAddr    - Physical memory address of linear framebuffer
+* Returns:      Far pointer to the linear framebuffer memory
+*
+****************************************************************************/
+{
+    int     sel;
+    long    linAddr,limit = (4096 * 1024) - 1;
+
+//	sel = DPMI_allocSelector();
+	linAddr = DPMI_mapPhysicalToLinear(physAddr,limit);
+//	DPMI_setSelectorBase(sel,linAddr);
+//	DPMI_setSelectorLimit(sel,limit);
+//	return MK_FP(sel,0);
+	return (void*)linAddr;
+}
+
+void AvailableModes(void)
+/****************************************************************************
+*
+* Function:     AvailableModes
+*
+* Description:  Display a list of available LFB mode resolutions.
+*
+****************************************************************************/
+{
+    unsigned short           *p;
+    VBE_modeInfo    modeInfo;
+
+    printf("Usage: LFBPROF <xres> <yres>\n\n");
+    printf("Available 256 color video modes:\n");
+    for (p = modeList; *p != -1; p++) {
+        if (VBE_getModeInfo(*p, &modeInfo)) {
+            /* Filter out only 8 bit linear framebuffer modes */
+            if ((modeInfo.ModeAttributes & vbeMdLinear) == 0)
+                continue;
+            if (modeInfo.MemoryModel != vbeMemPK
+                || modeInfo.BitsPerPixel != 8
+                || modeInfo.NumberOfPlanes != 1)
+                continue;
+            printf("    %4d x %4d %d bits per pixel\n",
+                modeInfo.XResolution, modeInfo.YResolution,
+                modeInfo.BitsPerPixel);
+            }
+        }
+    exit(1);
+}
+
+void InitGraphics(int x,int y)
+/****************************************************************************
+*
+* Function:     InitGraphics
+* Parameters:   x,y - Requested video mode resolution
+*
+* Description:  Initialise the specified video mode. We search through
+*               the list of available video modes for one that matches
+*               the resolution and color depth are are looking for.
+*
+****************************************************************************/
+{
+    unsigned short           *p;
+    VBE_modeInfo    modeInfo;
+    printf("InitGraphics\n");
+
+    for (p = modeList; *p != -1; p++) {
+        if (VBE_getModeInfo(*p, &modeInfo)) {
+            /* Filter out only 8 bit linear framebuffer modes */
+            if ((modeInfo.ModeAttributes & vbeMdLinear) == 0)
+                continue;
+            if (modeInfo.MemoryModel != vbeMemPK
+                || modeInfo.BitsPerPixel != 8
+                || modeInfo.NumberOfPlanes != 1)
+                continue;
+            if (modeInfo.XResolution != x || modeInfo.YResolution != y)
+                continue;
+            xres = x;
+            yres = y;
+            bytesperline = modeInfo.BytesPerScanLine;
+            imageSize = bytesperline * yres;
+            VBE_setVideoMode(*p | vbeUseLFB);
+            LFBPtr = GetPtrToLFB(modeInfo.PhysBasePtr);
+            return;
+            }
+        }
+    printf("Valid video mode not found\n");
+    exit(1);
+}
+
+void EndGraphics(void)
+/****************************************************************************
+*
+* Function:     EndGraphics
+*
+* Description:  Restores text mode.
+*
+****************************************************************************/
+{
+    RMREGS  regs;
+    printf("EndGraphics\n");
+    regs.x.ax = 0x3;
+    DPMI_int86(0x10, &regs, &regs);
+}
+
+void ProfileMode(void)
+/****************************************************************************
+*
+* Function:     ProfileMode
+*
+* Description:  Profiles framebuffer performance for simple screen clearing
+*               and for copying from system memory to video memory (BitBlt).
+*               This routine thrashes the CPU cache by cycling through
+*               enough system memory buffers to invalidate the entire
+*               CPU external cache before re-using the first memory buffer
+*               again.
+*
+****************************************************************************/
+{
+    int     i,numClears,numBlts,maxImages;
+    long    startTicks,endTicks;
+    void    *image[10],*dst;
+    printf("ProfileMode\n");
+
+    /* Profile screen clearing operation */
+    startTicks = LfbGetTicks();
+    numClears = 0;
+    while ((LfbGetTicks() - startTicks) < 182)
+		LfbMemset(LFBPtr,numClears++,imageSize);
+	endTicks = LfbGetTicks();
+	clearsPerSec = numClears / ((endTicks - startTicks) * 0.054925);
+	clearsMbPerSec = (clearsPerSec * imageSize) / 1048576.0;
+
+	/* Profile system memory to video memory copies */
+	maxImages = ((512 * 1024U) / imageSize) + 2;
+	for (i = 0; i < maxImages; i++) {
+		image[i] = malloc(imageSize);
+		if (image[i] == NULL)
+			FatalError("Not enough memory to profile BitBlt!");
+		memset(image[i],i+1,imageSize);
+		}
+	startTicks = LfbGetTicks();
+	numBlts = 0;
+	while ((LfbGetTicks() - startTicks) < 182)
+		LfbMemcpy(LFBPtr,image[numBlts++ % maxImages],imageSize);
+    endTicks = LfbGetTicks();
+    bitBltsPerSec = numBlts / ((endTicks - startTicks) * 0.054925);
+    bitBltsMbPerSec = (bitBltsPerSec * imageSize) / 1048576.0;
+}
+
+void main(int argc, char *argv[])
+{
+    if (VBE_detect() < 0x200)
+        FatalError("This program requires VBE 2.0; Please install UniVBE 5.1.");
+    if (argc != 3)
+        AvailableModes();       /* Display available modes              */
+
+    InitGraphics(atoi(argv[1]),atoi(argv[2]));  /* Start graphics       */
+    ProfileMode();              /* Profile the video mode               */
+    EndGraphics();              /* Restore text mode                    */
+
+    printf("Profiling results for %dx%d 8 bits per pixel.\n",xres,yres);
+    printf("%3.2f clears/s, %2.2f Mb/s\n", clearsPerSec, clearsMbPerSec);
+    printf("%3.2f bitBlt/s, %2.2f Mb/s\n", bitBltsPerSec, bitBltsMbPerSec);
+}
diff --git a/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.h b/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.h
new file mode 100644
index 0000000..bae0e09
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/tests/lfbprof/lfbprof.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+*
+*                   VBE 2.0 Linear Framebuffer Profiler
+*                    By Kendall Bennett and Brian Hook
+*
+* Filename:     LFBPROF.H
+* Language:     ANSI C
+* Environment:  Watcom C/C++ 10.0a with DOS4GW
+*
+* Description:  Header file for the LFBPROF.C progam.
+*
+****************************************************************************/
+
+#ifndef __LFBPROF_H
+#define __LFBPROF_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/* SuperVGA information block */
+
+typedef struct {
+    char    VESASignature[4];       /* 'VESA' 4 byte signature          */
+    short   VESAVersion;            /* VBE version number               */
+    long    OemStringPtr;           /* Pointer to OEM string            */
+    long    Capabilities;           /* Capabilities of video card       */
+    long    VideoModePtr;           /* Pointer to supported modes       */
+    short   TotalMemory;            /* Number of 64kb memory blocks     */
+
+    /* VBE 2.0 extensions */
+
+    short   OemSoftwareRev;         /* OEM Software revision number     */
+    long    OemVendorNamePtr;       /* Pointer to Vendor Name string    */
+    long    OemProductNamePtr;      /* Pointer to Product Name string   */
+    long    OemProductRevPtr;       /* Pointer to Product Revision str  */
+    char    reserved[222];          /* Pad to 256 byte block size       */
+    char    OemDATA[256];           /* Scratch pad for OEM data         */
+    } VBE_vgaInfo;
+
+/* SuperVGA mode information block */
+
+typedef struct {
+    short   ModeAttributes;         /* Mode attributes                  */
+    char    WinAAttributes;         /* Window A attributes              */
+    char    WinBAttributes;         /* Window B attributes              */
+    short   WinGranularity;         /* Window granularity in k          */
+    short   WinSize;                /* Window size in k                 */
+    short   WinASegment;            /* Window A segment                 */
+    short   WinBSegment;            /* Window B segment                 */
+    long    WinFuncPtr;             /* Pointer to window function       */
+    short   BytesPerScanLine;       /* Bytes per scanline               */
+    short   XResolution;            /* Horizontal resolution            */
+    short   YResolution;            /* Vertical resolution              */
+    char    XCharSize;              /* Character cell width             */
+    char    YCharSize;              /* Character cell height            */
+    char    NumberOfPlanes;         /* Number of memory planes          */
+    char    BitsPerPixel;           /* Bits per pixel                   */
+    char    NumberOfBanks;          /* Number of CGA style banks        */
+    char    MemoryModel;            /* Memory model type                */
+    char    BankSize;               /* Size of CGA style banks          */
+    char    NumberOfImagePages;     /* Number of images pages           */
+    char    res1;                   /* Reserved                         */
+    char    RedMaskSize;            /* Size of direct color red mask    */
+    char    RedFieldPosition;       /* Bit posn of lsb of red mask      */
+    char    GreenMaskSize;          /* Size of direct color green mask  */
+    char    GreenFieldPosition;     /* Bit posn of lsb of green mask    */
+    char    BlueMaskSize;           /* Size of direct color blue mask   */
+    char    BlueFieldPosition;      /* Bit posn of lsb of blue mask     */
+    char    RsvdMaskSize;           /* Size of direct color res mask    */
+    char    RsvdFieldPosition;      /* Bit posn of lsb of res mask      */
+    char    DirectColorModeInfo;    /* Direct color mode attributes     */
+
+    /* VBE 2.0 extensions */
+
+    long    PhysBasePtr;            /* Physical address for linear buf  */
+    long    OffScreenMemOffset;     /* Pointer to start of offscreen mem*/
+    short   OffScreenMemSize;       /* Amount of offscreen mem in 1K's  */
+    char    res2[206];              /* Pad to 256 byte block size       */
+    } VBE_modeInfo;
+
+#define vbeMemPK        4           /* Packed Pixel memory model        */
+#define vbeUseLFB       0x4000      /* Enable linear framebuffer mode   */
+
+/* Flags for the mode attributes returned by VBE_getModeInfo. If
+ * vbeMdNonBanked is set to 1 and vbeMdLinear is also set to 1, then only
+ * the linear framebuffer mode is available.
+ */
+
+#define vbeMdAvailable  0x0001      /* Video mode is available          */
+#define vbeMdColorMode  0x0008      /* Mode is a color video mode       */
+#define vbeMdGraphMode  0x0010      /* Mode is a graphics mode          */
+#define vbeMdNonBanked  0x0040      /* Banked mode is not supported     */
+#define vbeMdLinear     0x0080      /* Linear mode supported            */
+
+/* Structures for issuing real mode interrupts with DPMI */
+
+struct _RMWORDREGS {
+    unsigned short ax, bx, cx, dx, si, di, cflag;
+    };
+
+struct _RMBYTEREGS {
+    unsigned char   al, ah, bl, bh, cl, ch, dl, dh;
+    };
+
+typedef union {
+    struct  _RMWORDREGS x;
+    struct  _RMBYTEREGS h;
+    } RMREGS;
+
+typedef struct {
+    unsigned short  es;
+    unsigned short  cs;
+    unsigned short  ss;
+    unsigned short  ds;
+    } RMSREGS;
+
+/* Inline assembler block fill/move routines */
+
+void LfbMemset(void *p,int c,int n);
+#pragma aux LfbMemset =             \
+	"shr    ecx,2"                  \
+	"xor    eax,eax"                \
+	"mov    al,bl"                  \
+	"shl    ebx,8"                  \
+	"or     ax,bx"                  \
+	"mov    ebx,eax"                \
+	"shl    ebx,16"                 \
+	"or     eax,ebx"                \
+	"rep    stosd"                  \
+	parm [edi] [ebx] [ecx];
+
+void LfbMemcpy(void *dst,void *src,int n);
+#pragma aux LfbMemcpy =             \
+	"shr    ecx,2"                  \
+	"rep    movsd"                  \
+	parm [edi] [esi] [ecx];
+
+/* Map a real mode pointer into address space */
+
+#define LfbMapRealPointer(p)    (void*)(((unsigned)((p)  & 0xFFFF0000) >> 12) + ((p) & 0xFFFF))
+
+/* Get the current timer tick count */
+
+#define LfbGetTicks()       *((long*)0x46C)
+
+#pragma pack()
+
+#endif  /* __LFBPROF_H */
diff --git a/qemu-0.15.x/roms/vgabios/tests/testbios.c b/qemu-0.15.x/roms/vgabios/tests/testbios.c
new file mode 100644
index 0000000..99da5a6
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/tests/testbios.c
@@ -0,0 +1,353 @@
+/* 
+   This is a little turbo C program that executes
+   several int10, and let you inspect the content
+   of the vgabios area
+
+   It is used to test the behavior of the vgabios
+*/
+
+#include <stdio.h>
+#include <dos.h>
+#include <conio.h>
+
+
+typedef unsigned char  Bit8u;
+typedef unsigned short Bit16u;
+
+typedef struct
+{Bit8u initial;
+ Bit8u current;
+ Bit16u nbcols;
+ Bit16u regen;
+ Bit16u start;
+ Bit16u curpos[8];
+ Bit8u curtyp;
+ Bit8u curpage;
+ Bit16u crtc;
+ Bit16u msr;
+ Bit16u cgapal;
+ Bit8u nbrows;
+ Bit16u cheight;
+ Bit8u ctl;
+ Bit8u switches;
+ Bit8u modeset;
+ Bit8u dcc;
+ Bit16u vsseg;
+ Bit16u vsoffset;
+} BIOSAREA;
+
+void int10ax0003(struct REGPACK *regs)
+{
+ regs->r_ax=0x0003;
+ intr(0x10,regs);
+}
+
+void int10ax02(struct REGPACK *regs)
+{
+ regs->r_ax=0x0200;
+ regs->r_bx=0x0000;
+ regs->r_dx=0x1710;
+ intr(0x10,regs);
+ printf("We are now at 24/17");
+}
+
+void int10ax03(struct REGPACK *regs)
+{
+ regs->r_ax=0x0300;
+ regs->r_bx=0x0000;
+ intr(0x10,regs);
+ printf("\nCursor is ax%04x cx%04x dx%04x\n",regs->r_ax,regs->r_cx,regs->r_dx);
+}
+
+void int10ax0501(struct REGPACK *regs)
+{
+ regs->r_ax=0x0501;
+ intr(0x10,regs);
+ regs->r_ax=0x0e61;
+ regs->r_bx=0x0000;
+ intr(0x10,regs);
+ printf("We are now on page 2");
+}
+
+void int10ax0602(struct REGPACK *regs)
+{
+ regs->r_ax=0x0602;
+ regs->r_bx=0x0700;
+ regs->r_cx=0x0101;
+ regs->r_dx=0x0a0a;
+ intr(0x10,regs);
+ printf("Scrolled 2 up");
+}
+
+void int10ax0702(struct REGPACK *regs)
+{
+ regs->r_ax=0x0702;
+ regs->r_bx=0x0700;
+ regs->r_cx=0x0101;
+ regs->r_dx=0x0a0a;
+ intr(0x10,regs);
+ printf("Scrolled 2 down");
+}
+
+void int10ax08(struct REGPACK *regs)
+{
+ regs->r_ax=0x0800;
+ regs->r_bx=0x0000;
+ intr(0x10,regs);
+}
+
+void int10ax09(struct REGPACK *regs)
+{
+ char attr;
+ regs->r_ax=0x0501;
+ intr(0x10,regs);
+ for(attr=0;attr<16;attr++)
+  {printf("%02x ",attr);
+   regs->r_ax=0x0961+attr;
+   regs->r_bx=0x0100+attr;
+   regs->r_cx=0x0016;
+   intr(0x10,regs);
+   printf("\n");
+  }
+}
+
+void int10ax0a(struct REGPACK *regs)
+{
+ regs->r_ax=0x0501;
+ intr(0x10,regs);
+ regs->r_ax=0x0a62;
+ regs->r_bx=0x0101;
+ regs->r_cx=0x0016;
+ intr(0x10,regs);
+}
+
+void int10ax0f(struct REGPACK *regs)
+{
+ regs->r_ax=0x0501;
+ intr(0x10,regs);
+ regs->r_ax=0x0f00;
+ intr(0x10,regs);
+}
+
+void int10ax1b(struct REGPACK *regs)
+{unsigned char table[64];
+ unsigned char far *ptable;
+ int  i;
+
+ regs->r_ax=0x0501;
+ intr(0x10,regs);
+ regs->r_ax=0x1b00;
+ regs->r_bx=0x0000;
+ ptable=&table;
+ regs->r_es=FP_SEG(ptable);
+ regs->r_di=FP_OFF(ptable);
+ printf("Read state info in %04x:%04x\n",regs->r_es,regs->r_di);
+ intr(0x10,regs);
+
+ for(i=0;i<64;i++)
+  {if(i%16==0)printf("\n%02x ",i);
+   printf("%02x ",table[i]);
+  }
+ printf("\n");
+}
+
+static unsigned char var[64];
+
+void int10ax13(struct REGPACK *regs)
+{unsigned char far *pvar;
+
+ pvar=&var;
+
+ regs->r_ax=0x1300;
+ regs->r_bx=0x000b;
+ regs->r_dx=0x1010;
+ regs->r_cx=0x0002;
+ regs->r_es=FP_SEG(pvar);
+ regs->r_bp=FP_OFF(pvar);
+ pokeb(regs->r_es,regs->r_bp,'t');
+ pokeb(regs->r_es,regs->r_bp+1,'b');
+ printf("Writing from %04x:%04x\n",regs->r_es,regs->r_bp);
+ intr(0x10,regs);
+ 
+}
+
+void switch_50(struct REGPACK *regs)
+{
+ regs->r_ax=0x1202;
+ regs->r_bx=0x3000;
+ intr(0x10,regs);
+ regs->r_ax=0x0003;
+ intr(0x10,regs);
+ regs->r_ax=0x1112;
+ regs->r_bx=0x0000;
+ intr(0x10,regs);
+}
+
+char exec_function(struct REGPACK *regs)
+{char c;
+
+ printf("--- Functions --------------------\n");
+ printf("a. int10 ax0003\t");
+ printf("b. int10 ax02\t");
+ printf("c. int10 ax03\t");
+ printf("d. int10 ax0501\n");
+ printf("e. int10 ax0602\t");
+ printf("f. int10 ax0702\t");
+ printf("g. int10 ax08\t");
+ printf("h. int10 ax09\t");
+ printf("i. int10 ax0a\n");
+ printf("j. int10 ax0f\t");
+ printf("k. int10 ax1b\t");
+ printf("l. int10 ax13\n");
+ printf("q. Quit\t");
+ printf("r. switch to 50 lines\n");
+ c=getche();
+ 
+ switch(c)
+  {case 'a':
+    int10ax0003(regs);
+    break;
+   case 'b':
+    int10ax02(regs);
+    break;
+   case 'c':
+    int10ax03(regs);
+    break;
+   case 'd':
+    int10ax0501(regs);
+    break;
+   case 'e':
+    int10ax0602(regs);
+    break;
+   case 'f':
+    int10ax0702(regs);
+    break;
+   case 'g':
+    int10ax08(regs);
+    break;
+   case 'h':
+    int10ax09(regs);
+    break;
+   case 'i':
+    int10ax0a(regs);
+    break;
+   case 'j':
+    int10ax0f(regs);
+    break;
+   case 'k':
+    int10ax1b(regs);
+    break;
+   case 'l':
+    int10ax13(regs);
+    break;
+   case 'q':
+    break;
+   case 'r':
+    switch_50(regs);
+    break;
+   default:
+    printf("No such function!\n");
+  }
+
+ if(c=='q')return 1;
+ while(kbhit()==0);
+ c=getch();
+ 
+ return 0;
+}
+
+void read_bios_area(BIOSAREA *biosarea)
+{
+ biosarea->initial=peekb(0x40,0x10);
+ biosarea->current=peekb(0x40,0x49);
+ biosarea->nbcols=peek(0x40,0x4a);
+ biosarea->regen=peek(0x40,0x4c);
+ biosarea->start=peek(0x40,0x4e);
+ biosarea->curpos[0]=peek(0x40,0x50);
+ biosarea->curpos[1]=peek(0x40,0x52);
+ biosarea->curpos[2]=peek(0x40,0x54);
+ biosarea->curpos[3]=peek(0x40,0x56);
+ biosarea->curpos[4]=peek(0x40,0x58);
+ biosarea->curpos[5]=peek(0x40,0x5a);
+ biosarea->curpos[6]=peek(0x40,0x5c);
+ biosarea->curpos[7]=peek(0x40,0x5e);
+ biosarea->curtyp=peek(0x40,0x60);
+ biosarea->curpage=peekb(0x40,0x62);
+ biosarea->crtc=peek(0x40,0x63);
+ biosarea->msr=peekb(0x40,0x65);
+ biosarea->cgapal=peekb(0x40,0x66);
+ biosarea->nbrows=peekb(0x40,0x84);
+ biosarea->cheight=peek(0x40,0x85);
+ biosarea->ctl=peekb(0x40,0x87);
+ biosarea->switches=peekb(0x40,0x88);
+ biosarea->modeset=peekb(0x40,0x89);
+ biosarea->dcc=peekb(0x40,0x8a);
+ biosarea->vsseg=peek(0x40,0xa8);
+ biosarea->vsoffset=peek(0x40,0xaa);
+}
+
+void show_bios_area(BIOSAREA *biosarea)
+{
+ printf("--- BIOS area --------------------\n");
+ printf("initial : %02x\t",biosarea->initial);
+ printf("current : %02x\t",biosarea->current);
+ printf("nbcols  : %04x\t",biosarea->nbcols);
+ printf("regen   : %04x\t",biosarea->regen);
+ printf("start   : %04x\n",biosarea->start);
+ printf("curpos  : %04x %04x %04x %04x %04x %04x %04x %04x\n",
+   biosarea->curpos[0], biosarea->curpos[1], biosarea->curpos[2], biosarea->curpos[3],
+   biosarea->curpos[4], biosarea->curpos[5], biosarea->curpos[6], biosarea->curpos[7]);
+ printf("curtyp  : %04x\t",biosarea->curtyp);
+ printf("curpage : %02x\t",biosarea->curpage);
+ printf("crtc    : %04x\t",biosarea->crtc);
+ printf("msr     : %04x\n",biosarea->msr);
+ printf("cgapal  : %04x\t",biosarea->cgapal);
+ printf("nbrows-1: %02x\t",biosarea->nbrows);
+ printf("cheight : %04x\t",biosarea->cheight);
+ printf("ctl     : %02x\n",biosarea->ctl);
+ printf("switches: %02x\t",biosarea->switches);
+ printf("modeset : %02x\t",biosarea->modeset);
+ printf("dcc     : %02x\t",biosarea->dcc);
+ printf("vs      : %04x:%04x\n",biosarea->vsseg,biosarea->vsoffset);
+}
+
+void show_regs(struct REGPACK *regs)
+{
+ printf("--- Registers --------------------\n");
+ printf("ax %04x\t",regs->r_ax);
+ printf("bx %04x\t",regs->r_bx);
+ printf("cx %04x\t",regs->r_cx);
+ printf("dx %04x\t",regs->r_dx);
+ printf("ds %04x\t",regs->r_ds);
+ printf("si %04x\t",regs->r_si);
+ printf("es %04x\t",regs->r_es);
+ printf("di %04x\n",regs->r_di);
+}
+
+void reset_videomode()
+{
+ struct REGPACK regs;
+
+ regs.r_ax=0x0003;
+ intr(0x10,&regs);
+}
+
+void main()
+{
+
+ BIOSAREA biosarea;
+ struct REGPACK regs;
+
+ directvideo=0;
+ 
+ while(1)
+  {
+   read_bios_area(&biosarea);
+
+   reset_videomode();
+   show_bios_area(&biosarea);
+   show_regs(&regs);
+
+   if(exec_function(&regs)!=0)break;
+  }
+}
diff --git a/qemu-0.15.x/roms/vgabios/vbe.c b/qemu-0.15.x/roms/vgabios/vbe.c
new file mode 100644
index 0000000..1fab2f9
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vbe.c
@@ -0,0 +1,1456 @@
+// ============================================================================================
+//  
+//  Copyright (C) 2002 Jeroen Janssen
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+// ============================================================================================
+//  
+//  This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card. 
+//  You can NOT drive any physical vga card with it. 
+//
+// ============================================================================================
+//  
+//  This VBE Bios is based on information taken from :
+//   - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org
+//
+// ============================================================================================
+
+
+// defines available
+
+// disable VESA/VBE2 check in vbe info
+//#define VBE2_NO_VESA_CHECK
+
+
+#include "vbe.h"
+#include "vbetables.h"
+
+// The current OEM Software Revision of this VBE Bios
+#define VBE_OEM_SOFTWARE_REV 0x0002;
+
+extern char vbebios_copyright;
+extern char vbebios_vendor_name;
+extern char vbebios_product_name;
+extern char vbebios_product_revision;
+
+ASM_START
+// FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
+_vbebios_copyright:
+.ascii       "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/"
+.byte        0x00
+
+_vbebios_vendor_name:
+.ascii       "Bochs/Plex86 Developers"
+.byte        0x00
+
+_vbebios_product_name:
+.ascii       "Bochs/Plex86 VBE Adapter"
+.byte        0x00
+
+_vbebios_product_revision:
+.ascii       "$Id$"
+.byte        0x00
+
+_vbebios_info_string:
+.ascii      "Bochs VBE Display Adapter enabled"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+_no_vbebios_info_string:
+.ascii      "NO Bochs VBE Support available!"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte 0x00
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vbe_init:
+.ascii      "VBE Bios $Id$"
+.byte	0x0a,0x0d, 0x00
+#endif
+
+  .align 2
+vesa_pm_start:
+  dw vesa_pm_set_window - vesa_pm_start
+  dw vesa_pm_set_display_start - vesa_pm_start
+  dw vesa_pm_unimplemented - vesa_pm_start
+  dw vesa_pm_io_ports_table - vesa_pm_start
+vesa_pm_io_ports_table:
+  dw VBE_DISPI_IOPORT_INDEX
+  dw VBE_DISPI_IOPORT_INDEX + 1
+  dw VBE_DISPI_IOPORT_DATA
+  dw VBE_DISPI_IOPORT_DATA + 1
+  dw 0xffff
+  dw 0xffff
+
+  USE32
+vesa_pm_set_window:
+  cmp  bx, #0x00
+  je  vesa_pm_set_display_window1
+  mov  ax, #0x0100
+  ret
+vesa_pm_set_display_window1:
+  mov  ax, dx
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  in   ax, dx
+  pop  dx
+  cmp  dx, ax
+  jne  illegal_window
+  mov  ax, #0x004f
+  ret
+illegal_window:
+  mov  ax, #0x014f
+  ret
+
+vesa_pm_set_display_start:
+  cmp  bl, #0x80
+  je   vesa_pm_set_display_start1
+  cmp  bl, #0x00
+  je   vesa_pm_set_display_start1
+  mov  ax, #0x0100
+  ret
+vesa_pm_set_display_start1:
+; convert offset to (X, Y) coordinate 
+; (would be simpler to change Bochs VBE API...)
+  push eax
+  push ecx
+  push edx
+  push esi
+  push edi
+  shl edx, #16
+  and ecx, #0xffff
+  or ecx, edx
+  shl ecx, #2
+  mov eax, ecx
+
+  push eax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  movzx ecx, ax
+
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  movzx esi, ax
+  pop  eax
+
+  cmp esi, #4
+  jz bpp4_mode
+  add esi, #7
+  shr esi, #3
+  imul ecx, esi
+  xor edx, edx
+  div ecx
+  mov edi, eax
+  mov eax, edx
+  xor edx, edx
+  div esi
+  jmp set_xy_regs
+
+bpp4_mode:
+  shr ecx, #1
+  xor edx, edx
+  div ecx
+  mov edi, eax
+  mov eax, edx
+  shl eax, #1
+
+set_xy_regs:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+
+  mov  ax, di
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+
+  pop edi
+  pop esi
+  pop edx
+  pop ecx
+  pop eax
+  mov  ax, #0x004f
+  ret
+
+vesa_pm_unimplemented:
+  mov ax, #0x014f
+  ret
+  USE16
+vesa_pm_end:
+
+; DISPI ioport functions
+
+dispi_get_id:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ID
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_set_id:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ID
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+ASM_END
+
+static void dispi_set_xres(xres)
+  Bit16u xres;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+  push ax
+  push dx
+
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  mov  ax, 4[bp] ; xres
+  out  dx, ax
+
+  pop  dx
+  pop  ax
+  pop  bp
+ASM_END
+}
+
+static void dispi_set_yres(yres)
+  Bit16u yres;
+{
+  outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES);
+  outw(VBE_DISPI_IOPORT_DATA,yres);
+}
+
+static void dispi_set_bpp(bpp)
+  Bit16u bpp;
+{
+  outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP);
+  outw(VBE_DISPI_IOPORT_DATA,bpp);
+}
+
+ASM_START
+; AL = bits per pixel / AH = bytes per pixel
+dispi_get_bpp:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  mov  ah, al
+  shr  ah, 3
+  test al, #0x07
+  jz   get_bpp_noinc
+  inc  ah
+get_bpp_noinc:
+  pop  dx
+  ret
+
+; get display capabilities
+
+_dispi_get_max_xres:
+  push dx
+  push bx
+  call dispi_get_enable
+  mov  bx, ax
+  or   ax, # VBE_DISPI_GETCAPS
+  call _dispi_set_enable
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  ax, bx
+  call _dispi_set_enable
+  pop  ax
+  pop  bx
+  pop  dx
+  ret
+
+_dispi_get_max_bpp:
+  push dx
+  push bx
+  call dispi_get_enable
+  mov  bx, ax
+  or   ax, # VBE_DISPI_GETCAPS
+  call _dispi_set_enable
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  ax, bx
+  call _dispi_set_enable
+  pop  ax
+  pop  bx
+  pop  dx
+  ret
+
+_dispi_set_enable:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ENABLE
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_enable:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_ENABLE
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+_dispi_set_bank:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_bank:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BANK
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+ASM_END
+
+static void dispi_set_bank_farcall()
+{
+ASM_START
+  cmp bx,#0x0100
+  je dispi_set_bank_farcall_get
+  or bx,bx
+  jnz dispi_set_bank_farcall_error
+  mov ax,dx
+  push dx
+  push ax
+  mov ax,# VBE_DISPI_INDEX_BANK
+  mov dx,# VBE_DISPI_IOPORT_INDEX
+  out dx,ax
+  pop ax
+  mov dx,# VBE_DISPI_IOPORT_DATA
+  out dx,ax
+  in  ax,dx
+  pop dx
+  cmp dx,ax
+  jne dispi_set_bank_farcall_error
+  mov ax, #0x004f
+  retf
+dispi_set_bank_farcall_get:
+  mov ax,# VBE_DISPI_INDEX_BANK
+  mov dx,# VBE_DISPI_IOPORT_INDEX
+  out dx,ax
+  mov dx,# VBE_DISPI_IOPORT_DATA
+  in ax,dx
+  mov dx,ax
+  retf
+dispi_set_bank_farcall_error:
+  mov ax,#0x014F
+  retf
+ASM_END
+}
+
+ASM_START
+dispi_set_x_offset:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_x_offset:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_X_OFFSET
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_set_y_offset:
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_y_offset:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_Y_OFFSET
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+vga_set_virt_width:
+  push ax
+  push bx
+  push dx
+  mov  bx, ax
+  call dispi_get_bpp
+  cmp  al, #0x04
+  ja   set_width_svga
+  shr  bx, #1
+set_width_svga:
+  shr  bx, #3
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ah, bl
+  mov  al, #0x13
+  out  dx, ax
+  pop  dx
+  pop  bx
+  pop  ax
+  ret
+
+dispi_set_virt_width:
+  call vga_set_virt_width
+  push dx
+  push ax
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  pop  ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  out  dx, ax
+  pop  dx
+  ret
+
+dispi_get_virt_width:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+dispi_get_virt_height:
+  push dx
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_VIRT_HEIGHT
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  pop  dx
+  ret
+
+_vga_compat_setup:
+  push ax
+  push dx
+
+  ; set CRT X resolution
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_XRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  push ax
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ax, #0x0011
+  out  dx, ax
+  pop  ax
+  push ax
+  shr  ax, #3
+  dec  ax
+  mov  ah, al
+  mov  al, #0x01
+  out  dx, ax
+  pop  ax
+  call vga_set_virt_width
+
+  ; set CRT Y resolution
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_YRES
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  dec  ax
+  push ax
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ah, al
+  mov  al, #0x12
+  out  dx, ax
+  pop  ax
+  mov  al, #0x07
+  out  dx, al
+  inc  dx
+  in   al, dx
+  and  al, #0xbd
+  test ah, #0x01
+  jz   bit8_clear
+  or   al, #0x02
+bit8_clear:
+  test ah, #0x02
+  jz   bit9_clear
+  or   al, #0x40
+bit9_clear:
+  out  dx, al
+
+  ; other settings
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  ax, #0x0009
+  out  dx, ax
+  mov  al, #0x17
+  out  dx, al
+  mov  dx, # VGAREG_VGA_CRTC_DATA
+  in   al, dx
+  or   al, #0x03
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_RESET
+  in   al, dx
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  mov  al, #0x10
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_READ_DATA
+  in   al, dx
+  or   al, #0x01
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  out  dx, al
+  mov  al, #0x20
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_ADDRESS
+  mov  ax, #0x0506
+  out  dx, ax
+  mov  dx, # VGAREG_SEQU_ADDRESS
+  mov  ax, #0x0f02
+  out  dx, ax
+
+  ; settings for >= 8bpp
+  mov  dx, # VBE_DISPI_IOPORT_INDEX
+  mov  ax, # VBE_DISPI_INDEX_BPP
+  out  dx, ax
+  mov  dx, # VBE_DISPI_IOPORT_DATA
+  in   ax, dx
+  cmp  al, #0x08
+  jb   vga_compat_end
+  mov  dx, # VGAREG_VGA_CRTC_ADDRESS
+  mov  al, #0x14
+  out  dx, al
+  mov  dx, # VGAREG_VGA_CRTC_DATA
+  in   al, dx
+  or   al, #0x40
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_RESET
+  in   al, dx
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  mov  al, #0x10
+  out  dx, al
+  mov  dx, # VGAREG_ACTL_READ_DATA
+  in   al, dx
+  or   al, #0x40
+  mov  dx, # VGAREG_ACTL_ADDRESS
+  out  dx, al
+  mov  al, #0x20
+  out  dx, al
+  mov  dx, # VGAREG_SEQU_ADDRESS
+  mov  al, #0x04
+  out  dx, al
+  mov  dx, # VGAREG_SEQU_DATA
+  in   al, dx
+  or   al, #0x08
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_ADDRESS
+  mov  al, #0x05
+  out  dx, al
+  mov  dx, # VGAREG_GRDC_DATA
+  in   al, dx
+  and  al, #0x9f
+  or   al, #0x40
+  out  dx, al
+
+vga_compat_end:
+  pop  dx
+  pop  ax
+ASM_END
+
+
+// ModeInfo helper function
+static ModeInfoListItem* mode_info_find_mode(mode, using_lfb)
+  Bit16u mode; Boolean using_lfb;
+{
+  ModeInfoListItem  *cur_info=&mode_info_list;
+
+  while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST)
+  {
+    if (cur_info->mode == mode)
+    {
+      if (!using_lfb)
+      {
+        return cur_info;
+      }
+      else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
+      {
+        return cur_info;
+      }
+      else
+      {
+        cur_info++;
+      }
+    }
+    else
+    {
+      cur_info++;
+    }
+  }
+
+  return 0;
+}
+
+ASM_START
+
+; Has VBE display - Returns true if VBE display detected
+
+_vbe_has_vbe_display:
+  push ds
+  push bx
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  mov  bx, # BIOSMEM_VBE_FLAG
+  mov  al, [bx]
+  and  al, #0x01
+  xor  ah, ah
+  pop  bx
+  pop  ds
+  ret
+
+; VBE Init - Initialise the Vesa Bios Extension Code
+; This function does a sanity check on the host side display code interface.
+
+vbe_init:
+  mov  ax, # VBE_DISPI_ID0
+  call dispi_set_id
+  call dispi_get_id
+  cmp  ax, # VBE_DISPI_ID0
+  jne  no_vbe_interface
+  push ds
+  push bx
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  mov  bx, # BIOSMEM_VBE_FLAG
+  mov  al, #0x01
+  mov  [bx], al
+  pop  bx
+  pop  ds
+  mov  ax, # VBE_DISPI_ID5
+  call dispi_set_id
+no_vbe_interface:
+#if defined(USE_BX_INFO) || defined(DEBUG)
+  mov  bx, #msg_vbe_init
+  push bx
+  call _printf
+  inc  sp
+  inc  sp
+#endif
+  ret
+
+; VBE Display Info - Display information on screen about the VBE
+
+vbe_display_info:
+  call _vbe_has_vbe_display
+  test ax, ax
+  jz   no_vbe_flag
+  mov  ax, #0xc000
+  mov  ds, ax
+  mov  si, #_vbebios_info_string
+  jmp  _display_string
+no_vbe_flag:
+  mov  ax, #0xc000
+  mov  ds, ax
+  mov  si, #_no_vbebios_info_string
+  jmp  _display_string
+
+; helper function for memory size calculation
+
+lmulul:
+  and eax, #0x0000FFFF
+  shl ebx, #16
+  or  eax, ebx
+  SEG SS
+  mul eax, dword ptr [di]
+  mov ebx, eax
+  shr ebx, #16
+  ret
+ASM_END
+
+/** Function 00h - Return VBE Controller Information
+ * 
+ * Input:
+ *              AX      = 4F00h
+ *              ES:DI   = Pointer to buffer in which to place VbeInfoBlock structure
+ *                        (VbeSignature should be VBE2 when VBE 2.0 information is desired and
+ *                        the info block is 512 bytes in size)
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_return_controller_information(AX, ES, DI)
+Bit16u *AX;Bit16u ES;Bit16u DI;
+{
+        Bit16u            ss=get_SS();
+        VbeInfoBlock      vbe_info_block;
+        Bit16u            status;
+        Bit16u            result;
+        Bit16u            vbe2_info;
+        Bit16u            cur_mode=0;
+        Bit16u            cur_ptr=34;
+        Bit16u            size_64k;
+        ModeInfoListItem  *cur_info=&mode_info_list;
+
+        status = read_word(ss, AX);
+
+#ifdef DEBUG
+        printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
+#endif
+
+        vbe2_info = 0;
+#ifdef VBE2_NO_VESA_CHECK
+#else
+        // get vbe_info_block into local variable
+        memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block));
+
+        // check for VBE2 signature
+        if (((vbe_info_block.VbeSignature[0] == 'V') &&
+             (vbe_info_block.VbeSignature[1] == 'B') &&
+             (vbe_info_block.VbeSignature[2] == 'E') &&
+             (vbe_info_block.VbeSignature[3] == '2')) ||
+
+            ((vbe_info_block.VbeSignature[0] == 'V') &&
+             (vbe_info_block.VbeSignature[1] == 'E') &&
+             (vbe_info_block.VbeSignature[2] == 'S') &&
+             (vbe_info_block.VbeSignature[3] == 'A')) )
+        {
+                vbe2_info = 1;
+#ifdef DEBUG
+                printf("VBE correct VESA/VBE2 signature found\n");
+#endif
+        }
+#endif
+
+        // VBE Signature
+        vbe_info_block.VbeSignature[0] = 'V';
+        vbe_info_block.VbeSignature[1] = 'E';
+        vbe_info_block.VbeSignature[2] = 'S';
+        vbe_info_block.VbeSignature[3] = 'A';
+
+        // VBE Version supported
+        vbe_info_block.VbeVersion = 0x0200;
+
+        // OEM String
+        vbe_info_block.OemStringPtr_Seg = 0xc000;
+        vbe_info_block.OemStringPtr_Off = &vbebios_copyright;
+
+        // Capabilities
+        vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
+        vbe_info_block.Capabilities[1] = 0;
+        vbe_info_block.Capabilities[2] = 0;
+        vbe_info_block.Capabilities[3] = 0;
+
+        // VBE Video Mode Pointer (dynamicly generated from the mode_info_list)
+        vbe_info_block.VideoModePtr_Seg= ES ;
+        vbe_info_block.VideoModePtr_Off= DI + 34;
+
+        // VBE Total Memory (in 64k blocks)
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
+        vbe_info_block.TotalMemory = inw(VBE_DISPI_IOPORT_DATA);
+
+        if (vbe2_info)
+        {
+                // OEM Stuff
+                vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
+                vbe_info_block.OemVendorNamePtr_Seg = 0xc000;
+                vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name;
+                vbe_info_block.OemProductNamePtr_Seg = 0xc000;
+                vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name;
+                vbe_info_block.OemProductRevPtr_Seg = 0xc000;
+                vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision;
+
+                // copy updates in vbe_info_block back
+                memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block));
+        }
+        else
+        {
+                // copy updates in vbe_info_block back (VBE 1.x compatibility)
+                memcpyb(ES, DI, ss, &vbe_info_block, 256);
+        }
+
+        do
+        {
+                size_64k = (Bit16u)((Bit32u)cur_info->info.XResolution * cur_info->info.XResolution * cur_info->info.BitsPerPixel) >> 19;
+
+                if ((cur_info->info.XResolution <= dispi_get_max_xres()) &&
+                    (cur_info->info.BitsPerPixel <= dispi_get_max_bpp()) &&
+                    (size_64k <= vbe_info_block.TotalMemory)) {
+#ifdef DEBUG
+                  printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode);
+#endif
+                  write_word(ES, DI + cur_ptr, cur_info->mode);
+                  cur_mode++;
+                  cur_ptr+=2;
+                } else {
+#ifdef DEBUG
+                  printf("VBE mode %x (xres=%x / bpp=%02x) not supported \n", cur_info->mode,cur_info->info.XResolution,cur_info->info.BitsPerPixel);
+#endif
+                }
+                cur_info++;
+        } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST);
+
+        // Add vesa mode list terminator
+        write_word(ES, DI + cur_ptr, cur_info->mode);
+
+        result = 0x4f;
+
+        write_word(ss, AX, result);
+}
+
+
+/** Function 01h - Return VBE Mode Information
+ * 
+ * Input:
+ *              AX      = 4F01h
+ *              CX      = Mode Number
+ *              ES:DI   = Pointer to buffer in which to place ModeInfoBlock structure
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI)
+Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI;
+{
+        Bit16u            result=0x0100;
+        Bit16u            ss=get_SS();
+        ModeInfoBlock     info;
+        ModeInfoListItem  *cur_info;
+        Boolean           using_lfb;
+        Bit16u            lfb_addr;
+
+#ifdef DEBUG
+        printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
+#endif
+
+        using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+
+        CX = (CX & 0x1ff);
+
+        cur_info = mode_info_find_mode(CX, using_lfb, &cur_info);
+
+        if (cur_info != 0)
+        {
+#ifdef DEBUG
+                printf("VBE found mode %x\n",CX);
+#endif
+                memsetb(ss, &info, 0, sizeof(ModeInfoBlock));
+                memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact));
+                if (using_lfb) {
+                  info.NumberOfBanks = 1;
+                }
+#ifdef PCI_VID
+                lfb_addr = pci_get_lfb_addr(PCI_VID);
+#else
+                lfb_addr = 0;
+#endif
+                if (lfb_addr > 0) {
+                  info.PhysBasePtr = ((Bit32u)lfb_addr << 16);
+                }
+                if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
+                  info.WinFuncPtr = 0xC0000000UL;
+                  *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall);
+                }
+
+                result = 0x4f;
+        }
+        else
+        {
+#ifdef DEBUG
+                printf("VBE *NOT* found mode %x\n",CX);
+#endif
+                result = 0x100;
+        }
+
+        if (result == 0x4f)
+        {
+                // copy updates in mode_info_block back
+                memcpyb(ES, DI, ss, &info, sizeof(info));
+        }
+
+        write_word(ss, AX, result);
+}
+
+/** Function 02h - Set VBE Mode
+ * 
+ * Input:
+ *              AX      = 4F02h
+ *              BX      = Desired Mode to set
+ *              ES:DI   = Pointer to CRTCInfoBlock structure
+ * Output:
+ *              AX      = VBE Return Status
+ * 
+ */
+void vbe_biosfn_set_mode(AX, BX, ES, DI)
+Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI;
+{
+        Bit16u            ss = get_SS();
+        Bit16u            result;
+        ModeInfoListItem  *cur_info;
+        Boolean           using_lfb;
+        Bit8u             no_clear;
+        Bit8u             lfb_flag;
+
+        using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+        lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0;
+        no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0;
+
+        BX = (BX & 0x1ff);
+
+        //result=read_word(ss,AX);
+
+        // check for non vesa mode
+        if (BX<VBE_MODE_VESA_DEFINED)
+        {
+                Bit8u   mode;
+
+                dispi_set_enable(VBE_DISPI_DISABLED);
+                // call the vgabios in order to set the video mode
+                // this allows for going back to textmode with a VBE call (some applications expect that to work)
+
+                mode=(BX & 0xff);
+                biosfn_set_video_mode(mode);
+                result = 0x4f;
+        }
+
+        cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
+
+        if (cur_info != 0)
+        {
+#ifdef DEBUG
+                printf("VBE found mode %x, setting:\n", BX);
+                printf("\txres%x yres%x bpp%x\n",
+                        cur_info->info.XResolution,
+                        cur_info->info.YResolution,
+                        cur_info->info.BitsPerPixel);
+#endif
+
+                // first disable current mode (when switching between vesa modi)
+                dispi_set_enable(VBE_DISPI_DISABLED);
+
+                if (cur_info->info.BitsPerPixel == 4)
+                {
+                  biosfn_set_video_mode(0x6a);
+                }
+
+                dispi_set_bpp(cur_info->info.BitsPerPixel);
+                dispi_set_xres(cur_info->info.XResolution);
+                dispi_set_yres(cur_info->info.YResolution);
+                dispi_set_bank(0);
+                dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
+                vga_compat_setup();
+
+                write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
+                write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
+
+                result = 0x4f;
+        }
+        else
+        {
+#ifdef DEBUG
+                printf("VBE *NOT* found mode %x\n" , BX);
+#endif
+                result = 0x100;
+
+                // FIXME: redirect non VBE modi to normal VGA bios operation
+                //        (switch back to VGA mode
+                if (BX == 3)
+                        result = 0x4f;
+        }
+
+        write_word(ss, AX, result);
+}
+
+/** Function 03h - Return Current VBE Mode
+ * 
+ * Input:
+ *              AX      = 4F03h
+ * Output:
+ *              AX      = VBE Return Status
+ *              BX      = Current VBE Mode
+ * 
+ */
+ASM_START
+vbe_biosfn_return_current_mode:
+  push ds
+  mov  ax, # BIOSMEM_SEG
+  mov  ds, ax
+  call dispi_get_enable
+  and  ax, # VBE_DISPI_ENABLED
+  jz   no_vbe_mode
+  mov  bx, # BIOSMEM_VBE_MODE
+  mov  ax, [bx]
+  mov  bx, ax
+  jnz  vbe_03_ok
+no_vbe_mode:
+  mov  bx, # BIOSMEM_CURRENT_MODE
+  mov  al, [bx]
+  mov  bl, al
+  xor  bh, bh
+vbe_03_ok:
+  mov  ax, #0x004f
+  pop  ds
+  ret
+ASM_END
+
+
+Bit16u vbe_biosfn_read_video_state_size()
+{
+    return 9 * 2;
+}
+
+void vbe_biosfn_save_video_state(ES, BX)
+     Bit16u ES; Bit16u BX;
+{
+    Bit16u enable, i;
+
+    outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+    enable = inw(VBE_DISPI_IOPORT_DATA);
+    write_word(ES, BX, enable);
+    BX += 2;
+    if (!(enable & VBE_DISPI_ENABLED)) 
+        return;
+    for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
+        if (i != VBE_DISPI_INDEX_ENABLE) {
+            outw(VBE_DISPI_IOPORT_INDEX, i);
+            write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
+            BX += 2;
+        }
+    }
+}
+
+
+void vbe_biosfn_restore_video_state(ES, BX)
+     Bit16u ES; Bit16u BX;
+{
+    Bit16u enable, i;
+
+    enable = read_word(ES, BX);
+    BX += 2;
+
+    if (!(enable & VBE_DISPI_ENABLED)) {
+        outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+        outw(VBE_DISPI_IOPORT_DATA, enable);
+    } else {
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
+        outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+        BX += 2;
+        outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
+        outw(VBE_DISPI_IOPORT_DATA, enable);
+
+        for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
+            outw(VBE_DISPI_IOPORT_INDEX, i);
+            outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
+            BX += 2;
+        }
+    }
+}
+
+/** Function 04h - Save/Restore State
+ * 
+ * Input:
+ *              AX      = 4F04h
+ *              DL      = 00h Return Save/Restore State buffer size
+ *                        01h Save State
+ *                        02h Restore State
+ *              CX      = Requested states
+ *              ES:BX   = Pointer to buffer (if DL <> 00h)
+ * Output:
+ *              AX      = VBE Return Status
+ *              BX      = Number of 64-byte blocks to hold the state buffer (if DL=00h)
+ * 
+ */
+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
+Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
+{
+    Bit16u ss=get_SS();
+    Bit16u result, val;
+
+    result = 0x4f;
+    switch(GET_DL()) {
+    case 0x00:
+        val = biosfn_read_video_state_size2(CX);
+#ifdef DEBUG
+        printf("VGA state size=%x\n", val);
+#endif
+        if (CX & 8)
+            val += vbe_biosfn_read_video_state_size();
+        write_word(ss, BX, val);
+        break;
+    case 0x01:
+        val = read_word(ss, BX);
+        val = biosfn_save_video_state(CX, ES, val);
+#ifdef DEBUG
+        printf("VGA save_state offset=%x\n", val);
+#endif
+        if (CX & 8)
+            vbe_biosfn_save_video_state(ES, val);
+        break;
+    case 0x02:
+        val = read_word(ss, BX);
+        val = biosfn_restore_video_state(CX, ES, val);
+#ifdef DEBUG
+        printf("VGA restore_state offset=%x\n", val);
+#endif
+        if (CX & 8)
+            vbe_biosfn_restore_video_state(ES, val);
+        break;
+    default:
+        // function failed
+        result = 0x100;
+        break;
+    }
+    write_word(ss, AX, result);
+}
+
+/** Function 05h - Display Window Control
+ * 
+ * Input:
+ *              AX      = 4F05h
+ *     (16-bit) BH      = 00h Set memory window
+ *                      = 01h Get memory window
+ *              BL      = Window number
+ *                      = 00h Window A
+ *                      = 01h Window B
+ *              DX      = Window number in video memory in window
+ *                        granularity units (Set Memory Window only)
+ * Note:
+ *              If this function is called while in a linear frame buffer mode,
+ *              this function must fail with completion code AH=03h
+ * 
+ * Output:
+ *              AX      = VBE Return Status
+ *              DX      = Window number in window granularity units
+ *                        (Get Memory Window only)
+ */
+ASM_START
+vbe_biosfn_display_window_control:
+  cmp  bl, #0x00
+  jne  vbe_05_failed
+  cmp  bh, #0x01
+  je   get_display_window
+  jb   set_display_window
+  mov  ax, #0x0100
+  ret
+set_display_window:
+  mov  ax, dx
+  call _dispi_set_bank
+  call dispi_get_bank
+  cmp  ax, dx
+  jne  vbe_05_failed
+  mov  ax, #0x004f
+  ret
+get_display_window:
+  call dispi_get_bank
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+vbe_05_failed:
+  mov  ax, #0x014f
+  ret
+ASM_END
+
+
+/** Function 06h - Set/Get Logical Scan Line Length
+ *
+ * Input:
+ *              AX      = 4F06h
+ *              BL      = 00h Set Scan Line Length in Pixels
+ *                      = 01h Get Scan Line Length
+ *                      = 02h Set Scan Line Length in Bytes
+ *                      = 03h Get Maximum Scan Line Length
+ *              CX      = If BL=00h Desired Width in Pixels
+ *                        If BL=02h Desired Width in Bytes
+ *                        (Ignored for Get Functions)
+ * 
+ * Output: 
+ *              AX      = VBE Return Status
+ *              BX      = Bytes Per Scan Line
+ *              CX      = Actual Pixels Per Scan Line
+ *                        (truncated to nearest complete pixel)
+ *              DX      = Maximum Number of Scan Lines 
+ */
+ASM_START
+vbe_biosfn_set_get_logical_scan_line_length:
+  mov  ax, cx
+  cmp  bl, #0x01
+  je   get_logical_scan_line_length
+  cmp  bl, #0x02
+  je   set_logical_scan_line_bytes
+  jb   set_logical_scan_line_pixels
+  mov  ax, #0x0100
+  ret
+set_logical_scan_line_bytes:
+  push ax
+  call dispi_get_bpp
+  xor  bh, bh
+  mov  bl, ah
+  or   bl, bl
+  jnz  no_4bpp_1
+  shl  ax, #3
+  mov  bl, #1
+no_4bpp_1:
+  xor  dx, dx
+  pop  ax
+  div  bx
+set_logical_scan_line_pixels:
+  call dispi_set_virt_width
+get_logical_scan_line_length:
+  call dispi_get_bpp
+  xor  bh, bh
+  mov  bl, ah
+  call dispi_get_virt_width
+  mov  cx, ax
+  or   bl, bl
+  jnz  no_4bpp_2
+  shr  ax, #3
+  mov  bl, #1
+no_4bpp_2:
+  mul  bx
+  mov  bx, ax
+  call dispi_get_virt_height
+  mov  dx, ax
+  mov  ax, #0x004f
+  ret
+ASM_END
+
+
+/** Function 07h - Set/Get Display Start
+ * 
+ * Input(16-bit):
+ *              AX      = 4F07h
+ *              BH      = 00h Reserved and must be 00h
+ *              BL      = 00h Set Display Start
+ *                      = 01h Get Display Start
+ *                      = 02h Schedule Display Start (Alternate)
+ *                      = 03h Schedule Stereoscopic Display Start
+ *                      = 04h Get Scheduled Display Start Status
+ *                      = 05h Enable Stereoscopic Mode
+ *                      = 06h Disable Stereoscopic Mode
+ *                      = 80h Set Display Start during Vertical Retrace
+ *                      = 82h Set Display Start during Vertical Retrace (Alternate)
+ *                      = 83h Set Stereoscopic Display Start during Vertical Retrace
+ *              ECX     = If BL=02h/82h Display Start Address in bytes
+ *                        If BL=03h/83h Left Image Start Address in bytes
+ *              EDX     = If BL=03h/83h Right Image Start Address in bytes
+ *              CX      = If BL=00h/80h First Displayed Pixel In Scan Line
+ *              DX      = If BL=00h/80h First Displayed Scan Line
+ *
+ * Output:
+ *              AX      = VBE Return Status
+ *              BH      = If BL=01h Reserved and will be 0
+ *              CX      = If BL=01h First Displayed Pixel In Scan Line
+ *                        If BL=04h 0 if flip has not occurred, not 0 if it has
+ *              DX      = If BL=01h First Displayed Scan Line
+ *
+ * Input(32-bit): 
+ *              BH      = 00h Reserved and must be 00h
+ *              BL      = 00h Set Display Start
+ *                      = 80h Set Display Start during Vertical Retrace
+ *              CX      = Bits 0-15 of display start address
+ *              DX      = Bits 16-31 of display start address
+ *              ES      = Selector for memory mapped registers 
+ */
+ASM_START
+vbe_biosfn_set_get_display_start:
+  cmp  bl, #0x80
+  je   set_display_start
+  cmp  bl, #0x01
+  je   get_display_start
+  jb   set_display_start
+  mov  ax, #0x0100
+  ret
+set_display_start:
+  mov  ax, cx
+  call dispi_set_x_offset
+  mov  ax, dx
+  call dispi_set_y_offset
+  mov  ax, #0x004f
+  ret
+get_display_start:
+  call dispi_get_x_offset
+  mov  cx, ax
+  call dispi_get_y_offset
+  mov  dx, ax
+  xor  bh, bh
+  mov  ax, #0x004f
+  ret
+ASM_END
+  
+
+/** Function 08h - Set/Get Dac Palette Format
+ * 
+ * Input:
+ *              AX      = 4F08h
+ *              BL      = 00h set DAC palette width
+ *                      = 01h get DAC palette width
+ *              BH      = If BL=00h: desired number of bits per primary color
+ * Output:
+ *              AX      = VBE Return Status
+ *              BH      = current number of bits per primary color (06h = standard VGA)
+ */
+ASM_START
+vbe_biosfn_set_get_dac_palette_format:
+  cmp  bl, #0x01
+  je   get_dac_palette_format
+  jb   set_dac_palette_format
+  mov  ax, #0x0100
+  ret
+set_dac_palette_format:
+  call dispi_get_enable
+  cmp  bh, #0x06
+  je   set_normal_dac
+  cmp  bh, #0x08
+  jne  vbe_08_unsupported
+  or   ax, # VBE_DISPI_8BIT_DAC
+  jnz  set_dac_mode
+set_normal_dac:
+  and  ax, #~ VBE_DISPI_8BIT_DAC
+set_dac_mode:
+  call _dispi_set_enable
+get_dac_palette_format:
+  mov  bh, #0x06
+  call dispi_get_enable
+  and  ax, # VBE_DISPI_8BIT_DAC
+  jz   vbe_08_ok
+  mov  bh, #0x08
+vbe_08_ok:
+  mov  ax, #0x004f
+  ret
+vbe_08_unsupported:
+  mov  ax, #0x014f
+  ret
+ASM_END
+
+
+/** Function 09h - Set/Get Palette Data
+ * 
+ * Input:
+ *              AX      = 4F09h
+ * Output:
+ *              AX      = VBE Return Status
+ *
+ * FIXME: incomplete API description, Input & Output
+ */
+void vbe_biosfn_set_get_palette_data(AX)
+{
+}
+
+/** Function 0Ah - Return VBE Protected Mode Interface
+ * Input:    AX   = 4F0Ah   VBE 2.0 Protected Mode Interface
+ *           BL   = 00h          Return protected mode table
+ *
+ *
+ * Output:   AX   =         Status
+ *           ES   =         Real Mode Segment of Table
+ *           DI   =         Offset of Table
+ *           CX   =         Length of Table including protected mode code
+ *                          (for copying purposes)
+ */
+ASM_START
+vbe_biosfn_return_protected_mode_interface:
+  test bl, bl
+  jnz _fail
+  mov di, #0xc000
+  mov es, di
+  mov di, # vesa_pm_start
+  mov cx, # vesa_pm_end
+  sub cx, di
+  mov ax, #0x004f
+  ret
+_fail:
+  mov ax, #0x014f
+  ret
+ASM_END
diff --git a/qemu-0.15.x/roms/vgabios/vbe.h b/qemu-0.15.x/roms/vgabios/vbe.h
new file mode 100644
index 0000000..72cb045
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vbe.h
@@ -0,0 +1,315 @@
+#ifndef vbe_h_included
+#define vbe_h_included
+
+#include "vgabios.h"
+
+// DISPI helper function
+void dispi_set_enable(enable);
+
+/** VBE int10 API
+ *
+ *  See the function descriptions in vbe.c for more information
+ */
+Boolean vbe_has_vbe_display();
+void vbe_biosfn_return_controller_information(AX, ES, DI);
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI);
+void vbe_biosfn_set_mode(AX, BX, ES, DI);
+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX);
+void vbe_biosfn_set_get_palette_data(AX);
+void vbe_biosfn_return_protected_mode_interface(AX);
+
+// The official VBE Information Block
+typedef struct VbeInfoBlock
+{ 
+   Bit8u  VbeSignature[4];
+   Bit16u VbeVersion;
+   Bit16u OemStringPtr_Off;
+   Bit16u OemStringPtr_Seg;
+   Bit8u  Capabilities[4];
+   Bit16u VideoModePtr_Off;
+   Bit16u VideoModePtr_Seg;
+   Bit16u TotalMemory;
+   Bit16u OemSoftwareRev;
+   Bit16u OemVendorNamePtr_Off;
+   Bit16u OemVendorNamePtr_Seg;
+   Bit16u OemProductNamePtr_Off;
+   Bit16u OemProductNamePtr_Seg;
+   Bit16u OemProductRevPtr_Off;
+   Bit16u OemProductRevPtr_Seg;
+   Bit16u  Reserved[111]; // used for dynamicly generated mode list
+   Bit8u  OemData[256];
+} VbeInfoBlock;
+
+
+// This one is for compactly storing a static list of mode info blocks
+// this saves us 189 bytes per block
+typedef struct ModeInfoBlockCompact
+{
+// Mandatory information for all VBE revisions
+   Bit16u ModeAttributes;
+   Bit8u  WinAAttributes;
+   Bit8u  WinBAttributes;
+   Bit16u WinGranularity;
+   Bit16u WinSize;
+   Bit16u WinASegment;
+   Bit16u WinBSegment;
+   Bit32u WinFuncPtr;
+   Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+   Bit16u XResolution;
+   Bit16u YResolution;
+   Bit8u  XCharSize;
+   Bit8u  YCharSize;
+   Bit8u  NumberOfPlanes;
+   Bit8u  BitsPerPixel;
+   Bit8u  NumberOfBanks;
+   Bit8u  MemoryModel;
+   Bit8u  BankSize;
+   Bit8u  NumberOfImagePages;
+   Bit8u  Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+   Bit8u  RedMaskSize;
+   Bit8u  RedFieldPosition;
+   Bit8u  GreenMaskSize;
+   Bit8u  GreenFieldPosition;
+   Bit8u  BlueMaskSize;
+   Bit8u  BlueFieldPosition;
+   Bit8u  RsvdMaskSize;
+   Bit8u  RsvdFieldPosition;
+   Bit8u  DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+   Bit32u PhysBasePtr;
+   Bit32u OffScreenMemOffset;
+   Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+   Bit16u LinBytesPerScanLine;
+   Bit8u  BnkNumberOfPages;
+   Bit8u  LinNumberOfPages;
+   Bit8u  LinRedMaskSize;
+   Bit8u  LinRedFieldPosition;
+   Bit8u  LinGreenMaskSize;
+   Bit8u  LinGreenFieldPosition;
+   Bit8u  LinBlueMaskSize;
+   Bit8u  LinBlueFieldPosition;
+   Bit8u  LinRsvdMaskSize;
+   Bit8u  LinRsvdFieldPosition;
+   Bit32u MaxPixelClock;
+//   Bit8u  Reserved[189]; // DO NOT PUT THIS IN HERE because of Compact Mode Info storage in bios 
+} ModeInfoBlockCompact;
+
+typedef struct ModeInfoBlock
+{
+// Mandatory information for all VBE revisions
+   Bit16u ModeAttributes;
+   Bit8u  WinAAttributes;
+   Bit8u  WinBAttributes;
+   Bit16u WinGranularity;
+   Bit16u WinSize;
+   Bit16u WinASegment;
+   Bit16u WinBSegment;
+   Bit32u WinFuncPtr;
+   Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+   Bit16u XResolution;
+   Bit16u YResolution;
+   Bit8u  XCharSize;
+   Bit8u  YCharSize;
+   Bit8u  NumberOfPlanes;
+   Bit8u  BitsPerPixel;
+   Bit8u  NumberOfBanks;
+   Bit8u  MemoryModel;
+   Bit8u  BankSize;
+   Bit8u  NumberOfImagePages;
+   Bit8u  Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+   Bit8u  RedMaskSize;
+   Bit8u  RedFieldPosition;
+   Bit8u  GreenMaskSize;
+   Bit8u  GreenFieldPosition;
+   Bit8u  BlueMaskSize;
+   Bit8u  BlueFieldPosition;
+   Bit8u  RsvdMaskSize;
+   Bit8u  RsvdFieldPosition;
+   Bit8u  DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+   Bit32u PhysBasePtr;
+   Bit32u OffScreenMemOffset;
+   Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+   Bit16u LinBytesPerScanLine;
+   Bit8u  BnkNumberOfPages;
+   Bit8u  LinNumberOfPages;
+   Bit8u  LinRedMaskSize;
+   Bit8u  LinRedFieldPosition;
+   Bit8u  LinGreenMaskSize;
+   Bit8u  LinGreenFieldPosition;
+   Bit8u  LinBlueMaskSize;
+   Bit8u  LinBlueFieldPosition;
+   Bit8u  LinRsvdMaskSize;
+   Bit8u  LinRsvdFieldPosition;
+   Bit32u MaxPixelClock;
+   Bit8u  Reserved[189];
+} ModeInfoBlock;
+
+typedef struct ModeInfoListItem
+{
+  Bit16u                mode;
+  ModeInfoBlockCompact  info;
+} ModeInfoListItem;
+
+// VBE Return Status Info
+// AL
+#define VBE_RETURN_STATUS_SUPPORTED                      0x4F
+#define VBE_RETURN_STATUS_UNSUPPORTED                    0x00
+// AH
+#define VBE_RETURN_STATUS_SUCCESSFULL                    0x00
+#define VBE_RETURN_STATUS_FAILED                         0x01
+#define VBE_RETURN_STATUS_NOT_SUPPORTED                  0x02
+#define VBE_RETURN_STATUS_INVALID                        0x03
+
+// VBE Mode Numbers
+
+#define VBE_MODE_VESA_DEFINED                            0x0100
+#define VBE_MODE_REFRESH_RATE_USE_CRTC                   0x0800
+#define VBE_MODE_LINEAR_FRAME_BUFFER                     0x4000
+#define VBE_MODE_PRESERVE_DISPLAY_MEMORY                 0x8000
+
+// VBE GFX Mode Number
+
+#define VBE_VESA_MODE_640X400X8                          0x100
+#define VBE_VESA_MODE_640X480X8                          0x101
+#define VBE_VESA_MODE_800X600X4                          0x102
+#define VBE_VESA_MODE_800X600X8                          0x103
+#define VBE_VESA_MODE_1024X768X4                         0x104
+#define VBE_VESA_MODE_1024X768X8                         0x105
+#define VBE_VESA_MODE_1280X1024X4                        0x106
+#define VBE_VESA_MODE_1280X1024X8                        0x107
+#define VBE_VESA_MODE_320X200X1555                       0x10D
+#define VBE_VESA_MODE_320X200X565                        0x10E
+#define VBE_VESA_MODE_320X200X888                        0x10F
+#define VBE_VESA_MODE_640X480X1555                       0x110
+#define VBE_VESA_MODE_640X480X565                        0x111
+#define VBE_VESA_MODE_640X480X888                        0x112
+#define VBE_VESA_MODE_800X600X1555                       0x113
+#define VBE_VESA_MODE_800X600X565                        0x114
+#define VBE_VESA_MODE_800X600X888                        0x115
+#define VBE_VESA_MODE_1024X768X1555                      0x116
+#define VBE_VESA_MODE_1024X768X565                       0x117
+#define VBE_VESA_MODE_1024X768X888                       0x118
+#define VBE_VESA_MODE_1280X1024X1555                     0x119
+#define VBE_VESA_MODE_1280X1024X565                      0x11A
+#define VBE_VESA_MODE_1280X1024X888                      0x11B
+#define VBE_VESA_MODE_1600X1200X8                        0x11C
+#define VBE_VESA_MODE_1600X1200X1555                     0x11D
+#define VBE_VESA_MODE_1600X1200X565                      0x11E
+#define VBE_VESA_MODE_1600X1200X888                      0x11F
+
+// BOCHS/PLEX86 'own' mode numbers
+#define VBE_OWN_MODE_320X200X8888                        0x140
+#define VBE_OWN_MODE_640X400X8888                        0x141
+#define VBE_OWN_MODE_640X480X8888                        0x142
+#define VBE_OWN_MODE_800X600X8888                        0x143
+#define VBE_OWN_MODE_1024X768X8888                       0x144
+#define VBE_OWN_MODE_1280X1024X8888                      0x145
+#define VBE_OWN_MODE_320X200X8                           0x146
+#define VBE_OWN_MODE_1600X1200X8888                      0x147
+#define VBE_OWN_MODE_1152X864X8                          0x148
+#define VBE_OWN_MODE_1152X864X1555                       0x149
+#define VBE_OWN_MODE_1152X864X565                        0x14a
+#define VBE_OWN_MODE_1152X864X888                        0x14b
+#define VBE_OWN_MODE_1152X864X8888                       0x14c
+
+#define VBE_VESA_MODE_END_OF_LIST                        0xFFFF
+
+// Capabilities
+
+#define VBE_CAPABILITY_8BIT_DAC                          0x0001
+#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE                0x0002
+#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT              0x0004
+#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT              0x0008
+#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC               0x0010
+
+// Mode Attributes
+
+#define VBE_MODE_ATTRIBUTE_SUPPORTED                     0x0001
+#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE  0x0002
+#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT              0x0004
+#define VBE_MODE_ATTRIBUTE_COLOR_MODE                    0x0008
+#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE                 0x0010
+#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE            0x0020
+#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW      0x0040
+#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE      0x0080
+#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE              0x0100
+#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE                0x0200
+#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER        0x0400
+#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800
+#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS    0x1000
+
+#define VBE_MODE_ATTTRIBUTE_LFB_ONLY                     ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE )
+
+// Window attributes
+
+#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE                 0x01
+#define VBE_WINDOW_ATTRIBUTE_READABLE                    0x02
+#define VBE_WINDOW_ATTRIBUTE_WRITEABLE                   0x04
+
+// Memory model
+
+#define VBE_MEMORYMODEL_TEXT_MODE                        0x00
+#define VBE_MEMORYMODEL_CGA_GRAPHICS                     0x01
+#define VBE_MEMORYMODEL_HERCULES_GRAPHICS                0x02
+#define VBE_MEMORYMODEL_PLANAR                           0x03
+#define VBE_MEMORYMODEL_PACKED_PIXEL                     0x04
+#define VBE_MEMORYMODEL_NON_CHAIN_4_256                  0x05
+#define VBE_MEMORYMODEL_DIRECT_COLOR                     0x06
+#define VBE_MEMORYMODEL_YUV                              0x07
+
+// DirectColorModeInfo
+
+#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE          0x01
+#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE          0x02
+
+// GUEST <-> HOST Communication API
+
+// FIXME: either dynamicly ask host for this or put somewhere high in physical memory
+//        like 0xE0000000
+
+
+  #define VBE_DISPI_BANK_ADDRESS           0xA0000
+  #define VBE_DISPI_BANK_SIZE_KB           64
+
+  #define VBE_DISPI_MAX_XRES               2560
+  #define VBE_DISPI_MAX_YRES               1600
+
+  #define VBE_DISPI_IOPORT_INDEX           0x01CE
+  #define VBE_DISPI_IOPORT_DATA            0x01CF
+
+  #define VBE_DISPI_INDEX_ID               0x0
+  #define VBE_DISPI_INDEX_XRES             0x1
+  #define VBE_DISPI_INDEX_YRES             0x2
+  #define VBE_DISPI_INDEX_BPP              0x3
+  #define VBE_DISPI_INDEX_ENABLE           0x4
+  #define VBE_DISPI_INDEX_BANK             0x5
+  #define VBE_DISPI_INDEX_VIRT_WIDTH       0x6
+  #define VBE_DISPI_INDEX_VIRT_HEIGHT      0x7
+  #define VBE_DISPI_INDEX_X_OFFSET         0x8
+  #define VBE_DISPI_INDEX_Y_OFFSET         0x9
+  #define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
+
+  #define VBE_DISPI_ID0                    0xB0C0
+  #define VBE_DISPI_ID1                    0xB0C1
+  #define VBE_DISPI_ID2                    0xB0C2
+  #define VBE_DISPI_ID3                    0xB0C3
+  #define VBE_DISPI_ID4                    0xB0C4
+  #define VBE_DISPI_ID5                    0xB0C5
+
+  #define VBE_DISPI_DISABLED               0x00
+  #define VBE_DISPI_ENABLED                0x01
+  #define VBE_DISPI_GETCAPS                0x02
+  #define VBE_DISPI_8BIT_DAC               0x20
+  #define VBE_DISPI_LFB_ENABLED            0x40
+  #define VBE_DISPI_NOCLEARMEM             0x80
+
+  #define VBE_DISPI_LFB_PHYSICAL_ADDRESS   0xE0000000
+
+#endif
diff --git a/qemu-0.15.x/roms/vgabios/vbe_display_api.txt b/qemu-0.15.x/roms/vgabios/vbe_display_api.txt
new file mode 100644
index 0000000..fddb78b
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vbe_display_api.txt
@@ -0,0 +1,237 @@
+VBE Display API
+-------------------------------------------------------------------------------------------------------------
+  This document is part of the Bochs/VBEBios documentation,
+  it specifies the bochs host <-> vbebios client communication.
+  
+  That means, the display code implementation and the vbebios code depend
+  very heavily on each other. As such, this documents needs be synchronised
+  between bochs CVS and the vgabios CVS.
+  
+  This document does not describe how the VBEBios implements the VBE2/3 spec.
+  This document does not describe how the Bochs display code will display gfx based upon this spec.
+
+
+API History
+-----------
+0xb0c0            supports the following VBE_DISPI_ interfaces (present in Bochs 1.4):
+                  VBE_DISPI_INDEX_ID
+                  VBE_DISPI_INDEX_XRES
+                  VBE_DISPI_INDEX_YRES
+                  VBE_DISPI_INDEX_BPP
+                  VBE_DISPI_INDEX_ENABLE
+                  VBE_DISPI_INDEX_BANK
+
+                  Bpp format supported is:
+                  VBE_DISPI_BPP_8
+
+0xb0c1            supports 0xb0c0 VBE_DISPI_ interfaces, additional interfaces (present in Bochs 2.0):
+                  VBE_DISPI_INDEX_VIRT_WIDTH
+                  VBE_DISPI_INDEX_VIRT_HEIGHT
+                  VBE_DISPI_INDEX_X_OFFSET
+                  VBE_DISPI_INDEX_Y_OFFSET
+
+0xb0c2            supports 0xb0c1 VBE_DISPI_ interfaces, interfaces updated for
+                  additional features (present in Bochs 2.1):
+                  VBE_DISPI_INDEX_BPP supports >8bpp color depth (value = bits)
+                  VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_NOCLEARMEM and VBE_DISPI_LFB_ENABLED
+                  VBE i/o registers changed from 0xFF80/81 to 0x01CE/CF
+
+0xb0c3            supports 0xb0c2 VBE_DISPI_ interfaces, interfaces updated for
+                  additional features:
+                  VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_GETCAPS and VBE_DISPI_8BIT_DAC
+
+0xb0c4            VBE video memory increased to 8 MB
+
+
+History
+-------
+  Version 0.6     2002 Nov 23  Jeroen Janssen
+                  - Added LFB support
+                  - Added Virt width, height and x,y offset
+
+  Version 0.5     2002 March 08   Jeroen Janssen
+                  - Added documentation about panic behaviour / current limits of the data values.
+                  - Changed BPP API (in order to include future (A)RGB formats)
+                  - Initial version (based upon extended display text of the vbe bochs display patch)
+
+
+Todo
+----
+  Version 0.6+    [random order]
+                  - Add lots of different (A)RGB formats
+  
+References
+----------
+  [VBE3]          VBE 3 Specification at
+                  http://www.vesa.org/vbe3.pdf
+
+  [BOCHS]         Bochs Open Source IA-32 Emulator at
+                  http://bochs.sourceforge.net
+
+  [VBEBIOS]       VBE Bios for Bochs at
+                  http://savannah.gnu.org/projects/vgabios/
+
+  [Screenshots]   Screenshots of programs using the VBE Bios at
+                  http://japj.org/projects/bochs_plex86/screenshots.html
+
+Abbreviations
+-------------
+  VBE             Vesa Bios Extension
+  DISPI           (Bochs) Display Interface
+  BPP             Bits Per Pixel
+  LFB             Linear Frame Buffer
+
+
+#defines
+--------
+vbetables-gen.c
+  #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8
+
+vbe.h
+  #define VBE_DISPI_BANK_ADDRESS          0xA0000
+  #define VBE_DISPI_BANK_SIZE_KB          64
+
+  #define VBE_DISPI_MAX_XRES              1024
+  #define VBE_DISPI_MAX_YRES              768
+
+  #define VBE_DISPI_IOPORT_INDEX          0x01CE
+  #define VBE_DISPI_IOPORT_DATA           0x01CF
+
+  #define VBE_DISPI_INDEX_ID              0x0
+  #define VBE_DISPI_INDEX_XRES            0x1
+  #define VBE_DISPI_INDEX_YRES            0x2
+  #define VBE_DISPI_INDEX_BPP             0x3
+  #define VBE_DISPI_INDEX_ENABLE          0x4
+  #define VBE_DISPI_INDEX_BANK            0x5
+  #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+  #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+  #define VBE_DISPI_INDEX_X_OFFSET        0x8
+  #define VBE_DISPI_INDEX_Y_OFFSET        0x9
+
+  #define VBE_DISPI_ID0                   0xB0C0
+  #define VBE_DISPI_ID1                   0xB0C1
+  #define VBE_DISPI_ID2                   0xB0C2
+  #define VBE_DISPI_ID3                   0xB0C3
+  #define VBE_DISPI_ID4                   0xB0C4
+
+  #define VBE_DISPI_DISABLED              0x00
+  #define VBE_DISPI_ENABLED               0x01
+  #define VBE_DISPI_VBE_ENABLED           0x40
+  #define VBE_DISPI_NOCLEARMEM            0x80
+
+  #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+API
+---
+  The display api works by using a index (VBE_DISPI_IOPORT_INDEX) and
+  data (VBE_DISPI_IOPORT_DATA) ioport. One writes the index of the parameter to the index port.
+  Next, the parameter value can be read or written.
+
+[0xb0c0]
+  * VBE_DISPI_INDEX_ID  : WORD {R,W}
+    This parameter can be used to detect the current display API (both bochs & vbebios).
+    The bios writes VBE_DISPI_ID0 to the dataport and reads it back again.
+    This way, the display code knows the vbebios 'ID' and the vbebios can check if the correct
+    display code is present.
+    As a result, a PANIC can be generated if an incompatible vbebios/display code combination is detected.
+    This panic can be generated from the bochs display code (NOT the bios, see Notes).
+
+    Example values: VBE_DISPI_ID0
+
+  * VBE_DISPI_INDEX_XRES : WORD {R,W}
+    This parameter can be used to read/write the vbe display X resolution (in pixels).
+    It's illegal to set the XRES when the VBE is enabled (display code should generate PANIC).
+
+    If the value written exceeds VBE_DISPI_MAX_XRES, the display code needs to generate a PANIC.
+
+    Example values:   320,640,800,1024
+
+  * VBE_DISPI_INDEX_YRES : WORD {R,W}
+    This parameter can be used to read/write the vbe display Y resolution (in pixels).
+    It's illegal to set the YRES when the VBE is enabled (display code should generate PANIC).
+
+    If the value written exceeds VBE_DISPI_MAX_YRES, the display code needs to generate a PANIC.
+
+    Example values:   200,400,480,600,768
+
+  * VBE_DISPI_INDEX_BPP : WORD {R,W}
+    This parameter can be used to read/write the vbe display BPP.
+    It's illegal to set the BPP when the VBE is enabled (display code should generate PANIC).
+
+    If the value written is an incompatible BPP, the display code needs to generate a PANIC.
+
+    Example values:   VBE_DISPI_BPP_8
+
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    This parameter can be used to read/write the vbe ENABLED state.
+    If the bios writes VBE_DISPI_ENABLED then the display code will setup a hostside display mode
+    with the current XRES, YRES and BPP settings.
+    If the bios write VBE_DISPI_DISABLED then the display code will switch back to normal vga mode behaviour.
+
+    Example values: VBE_DISPI_ENABLED, VBE_DISPI_DISABLED
+
+  * VBE_DISPI_INDEX_BANK : WORD {R,W}
+    This parameter can be used to read/write the current selected BANK (at 0xA0000).
+    This can be used for switching banks in banked mode.
+
+[0xb0c1]
+  * VBE_DISPI_INDEX_VIRT_WIDTH : WORD {R,W}
+    This parameter can be used to read/write the current virtual width.
+    Upon enabling a mode, this will be set to the current xres
+    Setting this field during enabled mode will result in the virtual width to be changed.
+    Value will be adjusted if current setting is not possible.
+
+  * VBE_DISPI_INDEX_VIRT_HEIGHT : WORD {R}
+    This parameter can be read in order to obtain the current virtual height.
+    This setting will be adjusted after setting a virtual width in order to stay within limit of video memory.
+
+  * VBE_DISPI_INDEX_X_OFFSET : WORD {R,W}
+    The current X offset (in pixels!) of the visible screen part.
+    Writing a new offset will also result in a complete screen refresh.
+
+  * VBE_DISPI_INDEX_Y_OFFSET : WORD {R,W}
+    The current Y offset (in pixels!) of the visible screen part.
+    Writing a new offset will also result in a complete screen refresh.
+
+
+[0xb0c2]
+  * VBE_DISPI_INDEX_BPP : WORD {R,W}
+    The value written is now the number of bits per pixel. A value of 0 is treated
+    the same as 8 for backward compatibilty. These values are supported: 8, 15,
+    16, 24 and 32. The value of 4 is not yet handled in the VBE code.
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    The new flag VBE_DISPI_NOCLEARMEM allows to preserve the VBE video memory.
+    The new flag VBE_DISPI_LFB_ENABLED indicates the usage of the LFB.
+
+[0xb0c3]
+  * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+    If the new flag VBE_DISPI_GETCAPS is enabled, the xres, yres and bpp registers
+    return the gui capabilities.
+    The new flag VBE_DISPI_8BIT_DAC switches the DAC to 8 bit mode.
+
+[0xb0c4]
+  * VBE_DISPI_TOTAL_VIDEO_MEMORY_MB set to 8 (moved to auto-generated vbetables.h)
+
+Displaying GFX (banked mode)
+--------------
+  What happens is that the total screen is devided in banks of 'VBE_DISPI_BANK_SIZE_KB' KiloByte in size.
+  If you want to set a pixel you can calculate its bank by doing:
+
+    offset = pixel_x + pixel_y * resolution_x;
+    bank = offset / 64 Kb (rounded 1.9999 -> 1)
+
+    bank_pixel_pos = offset - bank * 64Kb
+
+  Now you can set the current bank and put the pixel at VBE_DISPI_BANK_ADDRESS + bank_pixel_pos
+
+Displaying GFX (linear frame buffer mode)
+--------------
+  NOT WRITTEN YET
+
+Notes
+-----
+  * Since the XRES/YRES/BPP may not be written when VBE is enabled, if you want to switch from one VBE mode
+    to another, you will need to disable VBE first.
+
+  * Note when the bios doesn't find a valid DISPI_ID, it can disable the VBE functions. This allows people to
+    use the same bios for both vbe enabled and disabled bochs executables.
diff --git a/qemu-0.15.x/roms/vgabios/vbetables-gen.c b/qemu-0.15.x/roms/vgabios/vbetables-gen.c
new file mode 100644
index 0000000..550935a
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vbetables-gen.c
@@ -0,0 +1,261 @@
+/* Generate the VGABIOS VBE Tables */
+#include <stdlib.h>
+#include <stdio.h>
+
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 16
+
+typedef struct {
+    int width;
+    int height;
+    int depth;
+    int mode;
+} ModeInfo;
+
+ModeInfo modes[] = {
+    /* standard VESA modes */
+{ 640, 400, 8                          , 0x100},
+{ 640, 480, 8                          , 0x101},
+{ 800, 600, 4                          , 0x102},
+{ 800, 600, 8                          , 0x103},
+{ 1024, 768, 4                         , 0x104},
+{ 1024, 768, 8                         , 0x105},
+{ 1280, 1024, 4                        , 0x106},
+{ 1280, 1024, 8                        , 0x107},
+{ 320, 200, 15                       , 0x10D},
+{ 320, 200, 16                        , 0x10E},
+{ 320, 200, 24                        , 0x10F},
+{ 640, 480, 15                       , 0x110},
+{ 640, 480, 16                        , 0x111},
+{ 640, 480, 24                        , 0x112},
+{ 800, 600, 15                       , 0x113},
+{ 800, 600, 16                        , 0x114},
+{ 800, 600, 24                        , 0x115},
+{ 1024, 768, 15                      , 0x116},
+{ 1024, 768, 16                       , 0x117},
+{ 1024, 768, 24                       , 0x118},
+{ 1280, 1024, 15                     , 0x119},
+{ 1280, 1024, 16                      , 0x11A},
+{ 1280, 1024, 24                      , 0x11B},
+{ 1600, 1200, 8                        , 0x11C},
+{ 1600, 1200, 15                     , 0x11D},
+{ 1600, 1200, 16                      , 0x11E},
+{ 1600, 1200, 24                      , 0x11F},
+
+      /* BOCHS/PLEX86 'own' mode numbers */
+{ 320, 200, 32                       , 0x140},
+{ 640, 400, 32                       , 0x141},
+{ 640, 480, 32                       , 0x142},
+{ 800, 600, 32                       , 0x143},
+{ 1024, 768, 32                      , 0x144},
+{ 1280, 1024, 32                     , 0x145},
+{ 320, 200, 8                        , 0x146},
+{ 1600, 1200, 32                     , 0x147},
+{ 1152, 864, 8                       , 0x148},
+{ 1152, 864, 15                      , 0x149},
+{ 1152, 864, 16                      , 0x14a},
+{ 1152, 864, 24                      , 0x14b},
+{ 1152, 864, 32                      , 0x14c},
+{ 1280, 800, 16                      , 0x178},
+{ 1280, 800, 24                      , 0x179},
+{ 1280, 800, 32                      , 0x17a},
+{ 1280, 960, 16                      , 0x17b},
+{ 1280, 960, 24                      , 0x17c},
+{ 1280, 960, 32                      , 0x17d},
+{ 1440, 900, 16                      , 0x17e},
+{ 1440, 900, 24                      , 0x17f},
+{ 1440, 900, 32                      , 0x180},
+{ 1400, 1050, 16                     , 0x181},
+{ 1400, 1050, 24                     , 0x182},
+{ 1400, 1050, 32                     , 0x183},
+{ 1680, 1050, 16                     , 0x184},
+{ 1680, 1050, 24                     , 0x185},
+{ 1680, 1050, 32                     , 0x186},
+{ 1920, 1200, 16                     , 0x187},
+{ 1920, 1200, 24                     , 0x188},
+{ 1920, 1200, 32                     , 0x189},
+{ 2560, 1600, 16                     , 0x18a},
+{ 2560, 1600, 24                     , 0x18b},
+{ 2560, 1600, 32                     , 0x18c},
+{ 0, },
+};
+
+int main(int argc, char **argv)
+{
+  const ModeInfo *pm;
+  int pages, pitch;
+  int r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
+  const char *str;
+  long vram_size = VBE_DISPI_TOTAL_VIDEO_MEMORY_MB * 1024 * 1024;
+
+  printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n");
+  printf("#define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB %d\n\n", VBE_DISPI_TOTAL_VIDEO_MEMORY_MB);
+  printf("static ModeInfoListItem mode_info_list[]=\n");
+  printf("{\n");
+  for (pm = modes; pm->mode != 0; pm++) {
+    if (pm->depth == 4)
+      pitch = (pm->width + 7) / 8;
+    else
+      pitch = pm->width * ((pm->depth + 7) / 8);
+    pages = vram_size / (pm->height * pitch);
+    if (pages > 0) {
+      printf("{ 0x%04x, /* %dx%dx%d */\n", 
+             pm->mode, pm->width, pm->height, pm->depth);
+      if (pm->depth == 4)
+        printf("{ /*Bit16u ModeAttributes*/ %s,\n", 
+               "VBE_MODE_ATTRIBUTE_SUPPORTED | "
+               "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
+               "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
+               "VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT | "
+               "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
+      else
+        printf("{ /*Bit16u ModeAttributes*/ %s,\n", 
+               "VBE_MODE_ATTRIBUTE_SUPPORTED | "
+               "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
+               "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
+               "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | "
+               "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
+      printf("/*Bit8u  WinAAttributes*/ %s,\n",
+             "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | "
+             "VBE_WINDOW_ATTRIBUTE_READABLE | "
+             "VBE_WINDOW_ATTRIBUTE_WRITEABLE");
+
+      printf("/*Bit8u  WinBAttributes*/ %d,\n", 0);
+
+      printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
+
+      printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
+
+      printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH");
+
+      printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0);
+
+      printf("/*Bit32u WinFuncPtr*/ %d,\n", 0);
+
+      printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch);
+
+      // Mandatory information for VBE 1.2 and above
+      printf("/*Bit16u XResolution*/ %d,\n", pm->width);
+      printf("/*Bit16u YResolution*/ %d,\n", pm->height);
+      printf("/*Bit8u  XCharSize*/ %d,\n", 8);
+      printf("/*Bit8u  YCharSize*/ %d,\n", 16);
+      if (pm->depth == 4) {
+        printf("/*Bit8u  NumberOfPlanes*/ %d,\n", 4);
+      } else {
+        printf("/*Bit8u  NumberOfPlanes*/ %d,\n", 1);
+      }
+      printf("/*Bit8u  BitsPerPixel*/ %d,\n", pm->depth);
+      printf("/*Bit8u  NumberOfBanks*/ %d,\n", 
+             (pm->height * pitch + 65535) / 65536);
+
+      if (pm->depth == 4)
+        str = "VBE_MEMORYMODEL_PLANAR";
+      else if (pm->depth == 8)
+        str = "VBE_MEMORYMODEL_PACKED_PIXEL";
+      else
+        str = "VBE_MEMORYMODEL_DIRECT_COLOR";
+      printf("/*Bit8u  MemoryModel*/ %s,\n", str);
+      printf("/*Bit8u  BankSize*/ %d,\n", 0);
+      if (pm->depth == 4)
+        printf("/*Bit8u  NumberOfImagePages*/ %d,\n", (pages / 4) - 1);
+      else
+        printf("/*Bit8u  NumberOfImagePages*/ %d,\n", pages - 1);
+      printf("/*Bit8u  Reserved_page*/ %d,\n", 0);
+
+      // Direct Color fields (required for direct/6 and YUV/7 memory models)
+      switch(pm->depth) {
+        case 15:
+          r_size = 5;
+          r_pos = 10;
+          g_size = 5;
+          g_pos = 5;
+          b_size = 5;
+          b_pos = 0;
+          a_size = 1;
+          a_pos = 15;
+          break;
+        case 16:
+          r_size = 5;
+          r_pos = 11;
+          g_size = 6;
+          g_pos = 5;
+          b_size = 5;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+        case 24:
+          r_size = 8;
+          r_pos = 16;
+          g_size = 8;
+          g_pos = 8;
+          b_size = 8;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+        case 32:
+          r_size = 8;
+          r_pos = 16;
+          g_size = 8;
+          g_pos = 8;
+          b_size = 8;
+          b_pos = 0;
+          a_size = 8;
+          a_pos = 24;
+          break;
+        default:
+          r_size = 0;
+          r_pos = 0;
+          g_size = 0;
+          g_pos = 0;
+          b_size = 0;
+          b_pos = 0;
+          a_size = 0;
+          a_pos = 0;
+          break;
+      }
+
+      printf("/*Bit8u  RedMaskSize*/ %d,\n", r_size);               
+      printf("/*Bit8u  RedFieldPosition*/ %d,\n", r_pos);          
+      printf("/*Bit8u  GreenMaskSize*/ %d,\n", g_size);             
+      printf("/*Bit8u  GreenFieldPosition*/ %d,\n", g_pos);        
+      printf("/*Bit8u  BlueMaskSize*/ %d,\n", b_size);              
+      printf("/*Bit8u  BlueFieldPosition*/ %d,\n", b_pos);         
+      printf("/*Bit8u  RsvdMaskSize*/ %d,\n", a_size);              
+      printf("/*Bit8u  RsvdFieldPosition*/ %d,\n", a_pos);         
+      if (pm->depth == 32)
+        printf("/*Bit8u  DirectColorModeInfo*/ %s,\n",
+               "VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE");
+      else
+        printf("/*Bit8u  DirectColorModeInfo*/ %s,\n", "0");
+
+// Mandatory information for VBE 2.0 and above
+      if (pm->depth > 4)
+        printf("/*Bit32u PhysBasePtr*/ %s,\n",
+               "VBE_DISPI_LFB_PHYSICAL_ADDRESS");
+      else
+        printf("/*Bit32u PhysBasePtr*/ %s,\n", "0");
+      printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0);
+      printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0);
+      // Mandatory information for VBE 3.0 and above
+      printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch);
+      printf("/*Bit8u  BnkNumberOfPages*/ %d,\n", 0);
+      printf("/*Bit8u  LinNumberOfPages*/ %d,\n", 0);
+      printf("/*Bit8u  LinRedMaskSize*/ %d,\n", r_size);
+      printf("/*Bit8u  LinRedFieldPosition*/ %d,\n", r_pos);
+      printf("/*Bit8u  LinGreenMaskSize*/ %d,\n", g_size);
+      printf("/*Bit8u  LinGreenFieldPosition*/ %d,\n", g_pos);
+      printf("/*Bit8u  LinBlueMaskSize*/ %d,\n", b_size);
+      printf("/*Bit8u  LinBlueFieldPosition*/ %d,\n", b_pos);
+      printf("/*Bit8u  LinRsvdMaskSize*/ %d,\n", a_size);
+      printf("/*Bit8u  LinRsvdFieldPosition*/ %d,\n", a_pos);
+      printf("/*Bit32u MaxPixelClock*/ %d,\n", 0);
+      printf("} },\n");
+    }
+  }
+  printf("{ VBE_VESA_MODE_END_OF_LIST,\n");
+  printf("{ 0,\n");
+  printf("} },\n");
+  printf("};\n");
+  return 0;
+}
diff --git a/qemu-0.15.x/roms/vgabios/vgabios.c b/qemu-0.15.x/roms/vgabios/vgabios.c
new file mode 100644
index 0000000..c1e312b
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vgabios.c
@@ -0,0 +1,3923 @@
+// ============================================================================================
+/*
+ * vgabios.c
+ */
+// ============================================================================================
+//  
+//  Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// 
+// ============================================================================================
+//  
+//  This VGA Bios is specific to the plex86/bochs Emulated VGA card. 
+//  You can NOT drive any physical vga card with it. 
+//     
+// ============================================================================================
+//  
+//  This file contains code ripped from :
+//   - rombios.c of plex86 
+//
+//  This VGA Bios contains fonts from :
+//   - fntcol16.zip (c) by Joseph Gil avalable at :
+//      ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+//     These fonts are public domain 
+//
+//  This VGA Bios is based on information taken from :
+//   - Kevin Lawton's vga card emulation for bochs/plex86
+//   - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+//   - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+//   - Michael Abrash's Graphics Programming Black Book
+//   - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
+//   - DOSEMU 1.0.1 source code for several tables values and formulas
+//
+// Thanks for patches, comments and ideas to :
+//   - techt at pikeonline.net
+//
+// ============================================================================================
+
+#include "vgabios.h"
+
+#ifdef VBE
+#include "vbe.h"
+#endif
+
+#define USE_BX_INFO
+
+/* Declares */
+static Bit8u          read_byte();
+static Bit16u         read_word();
+static void           write_byte();
+static void           write_word();
+static Bit8u          inb();
+static Bit16u         inw();
+static void           outb();
+static void           outw();
+
+static Bit16u         get_SS();
+
+// Output
+static void           printf();
+static void           unimplemented();
+static void           unknown();
+
+static Bit8u find_vga_entry();
+
+static void memsetb();
+static void memsetw();
+static void memcpyb();
+static void memcpyw();
+
+static void biosfn_set_video_mode();
+static void biosfn_set_cursor_shape();
+static void biosfn_set_cursor_pos();
+static void biosfn_get_cursor_pos();
+static void biosfn_set_active_page();
+static void biosfn_scroll();
+static void biosfn_read_char_attr();
+static void biosfn_write_char_attr();
+static void biosfn_write_char_only();
+static void biosfn_write_pixel();
+static void biosfn_read_pixel();
+static void biosfn_write_teletype();
+static void biosfn_perform_gray_scale_summing();
+static void biosfn_load_text_user_pat();
+static void biosfn_load_text_8_14_pat();
+static void biosfn_load_text_8_8_pat();
+static void biosfn_load_text_8_16_pat();
+static void biosfn_load_gfx_8_8_chars();
+static void biosfn_load_gfx_user_chars();
+static void biosfn_load_gfx_8_14_chars();
+static void biosfn_load_gfx_8_8_dd_chars();
+static void biosfn_load_gfx_8_16_chars();
+static void biosfn_get_font_info();
+static void biosfn_alternate_prtsc();
+static void biosfn_switch_video_interface();
+static void biosfn_enable_video_refresh_control();
+static void biosfn_write_string();
+static void biosfn_read_state_info();
+static void biosfn_read_video_state_size();
+static Bit16u biosfn_save_video_state();
+static Bit16u biosfn_restore_video_state();
+extern Bit8u video_save_pointer_table[];
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END   #endasm
+
+ASM_START
+
+MACRO SET_INT_VECTOR
+  push ds
+  xor ax, ax
+  mov ds, ax
+  mov ax, ?3
+  mov ?1*4, ax
+  mov ax, ?2
+  mov ?1*4+2, ax
+  pop ds
+MEND
+
+ASM_END
+
+ASM_START
+.text
+.rom
+.org 0
+
+use16 386
+
+vgabios_start:
+.byte	0x55, 0xaa	/* BIOS signature, required for BIOS extensions */
+
+.byte	0x40		/* BIOS extension length in units of 512 bytes */
+
+
+vgabios_entry_point:
+           
+  jmp vgabios_init_func
+
+#ifdef PCIBIOS
+.org 0x18
+.word vgabios_pci_data
+#endif
+
+// Info from Bart Oldeman
+.org 0x1e
+.ascii  "IBM"
+.byte   0x00
+
+vgabios_name:
+.ascii	"Plex86/Bochs VGABios"
+#ifdef PCIBIOS
+.ascii	" (PCI)"
+#endif
+.ascii	" "
+.byte	0x00
+
+vgabios_version:
+#ifndef VGABIOS_VERS
+.ascii	"current-cvs"
+#else
+.ascii VGABIOS_VERS
+#endif
+.ascii	" "
+
+vgabios_date:
+.ascii  VGABIOS_DATE
+.byte   0x0a,0x0d
+.byte	0x00
+
+vgabios_copyright:
+.ascii	"(C) 2008 the LGPL VGABios developers Team"
+.byte	0x0a,0x0d
+.byte	0x00
+
+vgabios_license:
+.ascii	"This VGA/VBE Bios is released under the GNU LGPL"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+vgabios_website:
+.ascii	"Please visit :"
+.byte	0x0a,0x0d
+;;.ascii  " . http://www.plex86.org"
+;;.byte	0x0a,0x0d
+.ascii	" . http://bochs.sourceforge.net"
+.byte	0x0a,0x0d
+.ascii	" . http://www.nongnu.org/vgabios"
+.byte	0x0a,0x0d
+.byte	0x0a,0x0d
+.byte	0x00
+
+#ifdef PCIBIOS
+vgabios_pci_data:
+.ascii "PCIR"
+#ifdef CIRRUS
+.word 0x1013
+.word 0x00b8 // CLGD5446
+#else
+#ifdef PCI_VID
+.word PCI_VID
+.word PCI_DID
+#else
+#error "Unknown PCI vendor and device id"
+#endif
+#endif
+.word 0 // reserved
+.word 0x18 // dlen
+.byte 0 // revision
+.byte 0x0 // class,hi: vga display
+.word 0x300 // class,lo: vga display
+.word 0x40 // bios size
+.word 1 // revision
+.byte 0 // intel x86 data
+.byte 0x80 // last image
+.word 0 // reserved
+#endif
+
+
+;; ============================================================================================
+;;
+;; Init Entry point
+;;
+;; ============================================================================================
+vgabios_init_func:
+
+;; init vga card
+  call init_vga_card
+
+;; init basic bios vars
+  call init_bios_area
+
+#ifdef VBE  
+;; init vbe functions
+  call vbe_init  
+#endif
+
+;; set int10 vect
+  SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
+
+#ifdef CIRRUS
+  call cirrus_init
+#endif
+
+;; display splash screen
+  call _display_splash_screen
+
+;; init video mode and clear the screen
+  mov ax,#0x0003
+  int #0x10
+
+;; show info
+  call _display_info
+
+#ifdef VBE  
+;; show vbe info
+  call vbe_display_info  
+#endif
+
+#ifdef CIRRUS
+;; show cirrus info
+  call cirrus_display_info
+#endif
+
+  retf
+ASM_END
+
+/*
+ *  int10 handled here
+ */
+ASM_START
+vgabios_int10_handler:
+  pushf
+#ifdef DEBUG
+  push es
+  push ds
+  pusha
+  mov   bx, #0xc000
+  mov   ds, bx
+  call _int10_debugmsg
+  popa
+  pop ds
+  pop es
+#endif
+  cmp   ah, #0x0f
+  jne   int10_test_1A
+  call  biosfn_get_video_mode
+  jmp   int10_end
+int10_test_1A:
+  cmp   ah, #0x1a
+  jne   int10_test_0B
+  call  biosfn_group_1A
+  jmp   int10_end
+int10_test_0B:
+  cmp   ah, #0x0b
+  jne   int10_test_1103
+  call  biosfn_group_0B
+  jmp   int10_end
+int10_test_1103:
+  cmp   ax, #0x1103
+  jne   int10_test_12
+  call  biosfn_set_text_block_specifier
+  jmp   int10_end
+int10_test_12:
+  cmp   ah, #0x12
+  jne   int10_test_101B
+  cmp   bl, #0x10
+  jne   int10_test_BL30
+  call  biosfn_get_ega_info
+  jmp   int10_end
+int10_test_BL30:
+  cmp   bl, #0x30
+  jne   int10_test_BL31
+  call  biosfn_select_vert_res
+  jmp   int10_end
+int10_test_BL31:
+  cmp   bl, #0x31
+  jne   int10_test_BL32
+  call  biosfn_enable_default_palette_loading
+  jmp   int10_end
+int10_test_BL32:
+  cmp   bl, #0x32
+  jne   int10_test_BL33
+  call  biosfn_enable_video_addressing
+  jmp   int10_end
+int10_test_BL33:
+  cmp   bl, #0x33
+  jne   int10_test_BL34
+  call  biosfn_enable_grayscale_summing
+  jmp   int10_end
+int10_test_BL34:
+  cmp   bl, #0x34
+  jne   int10_normal
+  call  biosfn_enable_cursor_emulation
+  jmp   int10_end
+int10_test_101B:
+  cmp   ax, #0x101b
+  je    int10_normal
+  cmp   ah, #0x10
+#ifndef VBE
+  jne   int10_normal
+#else
+  jne   int10_test_4F
+#endif
+  call  biosfn_group_10
+  jmp   int10_end
+#ifdef VBE
+int10_test_4F:
+  cmp   ah, #0x4f
+  jne   int10_normal
+  cmp   al, #0x03
+  jne   int10_test_vbe_05
+  call  vbe_biosfn_return_current_mode
+  jmp   int10_end
+int10_test_vbe_05:
+  cmp   al, #0x05
+  jne   int10_test_vbe_06
+  call  vbe_biosfn_display_window_control
+  jmp   int10_end
+int10_test_vbe_06:
+  cmp   al, #0x06
+  jne   int10_test_vbe_07
+  call  vbe_biosfn_set_get_logical_scan_line_length
+  jmp   int10_end
+int10_test_vbe_07:
+  cmp   al, #0x07
+  jne   int10_test_vbe_08
+  call  vbe_biosfn_set_get_display_start
+  jmp   int10_end
+int10_test_vbe_08:
+  cmp   al, #0x08
+  jne   int10_test_vbe_0A
+  call  vbe_biosfn_set_get_dac_palette_format
+  jmp   int10_end
+int10_test_vbe_0A:
+  cmp   al, #0x0A
+  jne   int10_normal
+  call  vbe_biosfn_return_protected_mode_interface
+  jmp   int10_end
+#endif
+
+int10_normal:
+  push es
+  push ds
+  pusha
+
+;; We have to set ds to access the right data segment
+  mov   bx, #0xc000
+  mov   ds, bx
+  call _int10_func
+
+  popa
+  pop ds
+  pop es
+int10_end:
+  popf
+  iret
+ASM_END
+
+#include "vgatables.h"
+#include "vgafonts.h"
+
+/*
+ * Boot time harware inits 
+ */
+ASM_START
+init_vga_card:
+;; switch to color mode and enable CPU access 480 lines
+  mov dx, #0x3C2
+  mov al, #0xC3
+  outb dx,al
+
+;; more than 64k 3C4/04
+  mov dx, #0x3C4
+  mov al, #0x04
+  outb dx,al
+  mov dx, #0x3C5
+  mov al, #0x02
+  outb dx,al
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+  mov  bx, #msg_vga_init
+  push bx
+  call _printf
+#endif
+  inc  sp
+  inc  sp
+  ret
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vga_init:
+.ascii "VGABios $Id$"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Boot time bios area inits 
+ */
+ASM_START
+init_bios_area:
+  push  ds
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+
+;; init detected hardware BIOS Area
+  mov   bx, # BIOSMEM_INITIAL_MODE
+  mov   ax, [bx]
+  and   ax, #0xffcf
+;; set 80x25 color (not clear from RBIL but usual)
+  or    ax, #0x0020
+  mov   [bx], ax
+
+;; Just for the first int10 find its children
+
+;; the default char height
+  mov   bx, # BIOSMEM_CHAR_HEIGHT
+  mov   al, #0x10
+  mov   [bx], al
+
+;; Clear the screen 
+  mov   bx, # BIOSMEM_VIDEO_CTL
+  mov   al, #0x60
+  mov   [bx], al
+
+;; Set the basic screen we have
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   al, #0xf9
+  mov   [bx], al
+
+;; Set the basic modeset options
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, #0x51
+  mov   [bx], al
+
+;; Set the  default MSR
+  mov   bx, # BIOSMEM_CURRENT_MSR
+  mov   al, #0x09
+  mov   [bx], al
+
+  pop ds
+  ret
+
+_video_save_pointer_table:
+  .word _video_param_table
+  .word 0xc000
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+  .word 0 /* XXX: fill it */
+  .word 0
+
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Boot time Splash screen
+ */
+static void display_splash_screen()
+{
+}
+
+// --------------------------------------------------------------------------------------------
+/*
+ *  Tell who we are
+ */
+
+static void display_info()
+{
+ASM_START
+ mov ax,#0xc000
+ mov ds,ax
+ mov si,#vgabios_name
+ call _display_string
+ mov si,#vgabios_version
+ call _display_string
+ 
+ ;;mov si,#vgabios_copyright
+ ;;call _display_string
+ ;;mov si,#crlf
+ ;;call _display_string
+
+ mov si,#vgabios_license
+ call _display_string
+ mov si,#vgabios_website
+ call _display_string
+ASM_END
+}
+
+static void display_string()
+{
+ // Get length of string
+ASM_START
+ mov ax,ds
+ mov es,ax
+ mov di,si
+ xor cx,cx
+ not cx
+ xor al,al
+ cld
+ repne 
+  scasb
+ not cx
+ dec cx
+ push cx
+
+ mov ax,#0x0300
+ mov bx,#0x0000
+ int #0x10
+ 
+ pop cx
+ mov ax,#0x1301
+ mov bx,#0x000b
+ mov bp,si
+ int #0x10
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+#ifdef DEBUG
+static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ // 0E is write char...
+ if(GET_AH()!=0x0E)
+  printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+/*
+ * int10 main dispatcher
+ */
+static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+
+ // BIOS functions
+ switch(GET_AH())
+  {
+   case 0x00:
+     biosfn_set_video_mode(GET_AL());
+     switch(GET_AL()&0x7F)
+      {case 6: 
+        SET_AL(0x3F);
+        break;
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 7:
+        SET_AL(0x30);
+        break;
+      default:
+        SET_AL(0x20);
+      }
+     break;
+   case 0x01:
+     biosfn_set_cursor_shape(GET_CH(),GET_CL());
+     break;
+   case 0x02:
+     biosfn_set_cursor_pos(GET_BH(),DX);
+     break;
+   case 0x03:
+     biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
+     break;
+   case 0x04:
+     // Read light pen pos (unimplemented)
+#ifdef DEBUG
+     unimplemented();
+#endif
+     AX=0x00;
+     BX=0x00;
+     CX=0x00;
+     DX=0x00;
+     break;
+   case 0x05:
+     biosfn_set_active_page(GET_AL());
+     break;
+   case 0x06:
+     biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
+     break;
+   case 0x07:
+     biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
+     break;
+   case 0x08:
+     biosfn_read_char_attr(GET_BH(),&AX);
+     break;
+   case 0x09:
+     biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
+     break;
+   case 0x0A:
+     biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
+     break;
+   case 0x0C:
+     biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
+     break;
+   case 0x0D:
+     biosfn_read_pixel(GET_BH(),CX,DX,&AX);
+     break;
+   case 0x0E:
+     // Ralf Brown Interrupt list is WRONG on bh(page)
+     // We do output only on the current page !
+     biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
+     break;
+   case 0x10:
+     // All other functions of group AH=0x10 rewritten in assembler
+     biosfn_perform_gray_scale_summing(BX,CX);
+     break;
+   case 0x11:
+     switch(GET_AL())
+      {
+       case 0x00:
+       case 0x10:
+        biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
+        break;
+       case 0x01:
+       case 0x11:
+        biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
+        break;
+       case 0x02:
+       case 0x12:
+        biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
+        break;
+       case 0x04:
+       case 0x14:
+        biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
+        break;
+       case 0x20:
+        biosfn_load_gfx_8_8_chars(ES,BP);
+        break;
+       case 0x21:
+        biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
+        break;
+       case 0x22:
+        biosfn_load_gfx_8_14_chars(GET_BL());
+        break;
+       case 0x23:
+        biosfn_load_gfx_8_8_dd_chars(GET_BL());
+        break;
+       case 0x24:
+        biosfn_load_gfx_8_16_chars(GET_BL());
+        break;
+       case 0x30:
+        biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     
+     break;
+   case 0x12:
+     switch(GET_BL())
+      {
+       case 0x20:
+        biosfn_alternate_prtsc();
+        break;
+       case 0x35:
+        biosfn_switch_video_interface(GET_AL(),ES,DX);
+        SET_AL(0x12);
+        break;
+       case 0x36:
+        biosfn_enable_video_refresh_control(GET_AL());
+        SET_AL(0x12);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     break;
+   case 0x13:
+     biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
+     break;
+   case 0x1B:
+     biosfn_read_state_info(BX,ES,DI);
+     SET_AL(0x1B);
+     break;
+   case 0x1C:
+     switch(GET_AL())
+      {
+       case 0x00:
+        biosfn_read_video_state_size(CX,&BX);
+        break;
+       case 0x01:
+        biosfn_save_video_state(CX,ES,BX);
+        break;
+       case 0x02:
+        biosfn_restore_video_state(CX,ES,BX);
+        break;
+#ifdef DEBUG
+       default:
+        unknown();
+#endif
+      }
+     SET_AL(0x1C);
+     break;
+
+#ifdef VBE 
+   case 0x4f:
+     if (vbe_has_vbe_display()) {
+       switch(GET_AL())
+       {
+         case 0x00:
+          vbe_biosfn_return_controller_information(&AX,ES,DI);
+          break;
+         case 0x01:
+          vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+          break;
+         case 0x02:
+          vbe_biosfn_set_mode(&AX,BX,ES,DI);
+          break;
+         case 0x04:
+          vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+          break;
+         case 0x09:
+          //FIXME
+#ifdef DEBUG
+          unimplemented();
+#endif
+          // function failed
+          AX=0x100;
+          break;
+         case 0x0A:
+          //FIXME
+#ifdef DEBUG
+          unimplemented();
+#endif
+          // function failed
+          AX=0x100;
+          break;
+         default:
+#ifdef DEBUG
+          unknown();
+#endif   		 
+          // function failed
+          AX=0x100;
+          }
+        }
+        else {
+          // No VBE display
+          AX=0x0100;
+          }
+        break;
+#endif
+
+#ifdef DEBUG
+   default:
+     unknown();
+#endif
+  }
+}
+
+// ============================================================================================
+// 
+// BIOS functions
+// 
+// ============================================================================================
+
+static void biosfn_set_video_mode(mode) Bit8u mode; 
+{// mode: Bit 7 is 1 if no clear screen
+
+ // Should we clear the screen ?
+ Bit8u noclearmem=mode&0x80;
+ Bit8u line,mmask,*palette,vpti;
+ Bit16u i,twidth,theightm1,cheight;
+ Bit8u modeset_ctl,video_ctl,vga_switches;
+ Bit16u crtc_addr;
+ 
+#ifdef VBE
+ if (vbe_has_vbe_display()) { 
+   dispi_set_enable(VBE_DISPI_DISABLED);
+  }
+#endif // def VBE
+ 
+ // The real mode
+ mode=mode&0x7f;
+
+ // find the entry in the video modes
+ line=find_vga_entry(mode);
+
+#ifdef DEBUG
+ printf("mode search %02x found line %02x\n",mode,line);
+#endif
+
+ if(line==0xFF)
+  return;
+
+ vpti=line_to_vpti[line];
+ twidth=video_param_table[vpti].twidth;
+ theightm1=video_param_table[vpti].theightm1;
+ cheight=video_param_table[vpti].cheight;
+ 
+ // Read the bios vga control
+ video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
+
+ // Read the bios vga switches
+ vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
+
+ // Read the bios mode set control
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if((modeset_ctl&0x08)==0)
+  {// Set the PEL mask
+   outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
+
+   // Set the whole dac always, from 0
+   outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+
+   // From which palette
+   switch(vga_modes[line].dacmodel)
+    {case 0:
+      palette=&palette0;
+      break;
+     case 1:
+      palette=&palette1;
+      break;
+     case 2:
+      palette=&palette2;
+      break;
+     case 3:
+      palette=&palette3;
+      break;
+    }
+   // Always 256*3 values
+   for(i=0;i<0x0100;i++)
+    {if(i<=dac_regs[vga_modes[line].dacmodel])
+      {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
+       outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
+       outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
+      }
+     else
+      {outb(VGAREG_DAC_DATA,0);
+       outb(VGAREG_DAC_DATA,0);
+       outb(VGAREG_DAC_DATA,0);
+      }
+    }
+   if((modeset_ctl&0x02)==0x02)
+    {
+     biosfn_perform_gray_scale_summing(0x00, 0x100);
+    }
+  }
+
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ // Set Attribute Ctl
+ for(i=0;i<=0x13;i++)
+  {outb(VGAREG_ACTL_ADDRESS,i);
+   outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
+  }
+ outb(VGAREG_ACTL_ADDRESS,0x14);
+ outb(VGAREG_ACTL_WRITE_DATA,0x00);
+
+ // Set Sequencer Ctl
+ outb(VGAREG_SEQU_ADDRESS,0);
+ outb(VGAREG_SEQU_DATA,0x03);
+ for(i=1;i<=4;i++)
+  {outb(VGAREG_SEQU_ADDRESS,i);
+   outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
+  }
+
+ // Set Grafx Ctl
+ for(i=0;i<=8;i++)
+  {outb(VGAREG_GRDC_ADDRESS,i);
+   outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
+  }
+
+ // Set CRTC address VGA or MDA 
+ crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ outw(crtc_addr,0x0011);
+ // Set CRTC regs
+ for(i=0;i<=0x18;i++)
+  {outb(crtc_addr,i);
+   outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
+  }
+
+ // Set the misc register
+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
+
+ // Enable video
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+ inb(VGAREG_ACTL_RESET);
+
+ if(noclearmem==0x00)
+  {
+   if(vga_modes[line].class==TEXT)
+    {
+     memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
+    }
+   else
+    {
+     if(mode<0x0d)
+      {
+       memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
+      }
+     else
+      {
+       outb( VGAREG_SEQU_ADDRESS, 0x02 );
+       mmask = inb( VGAREG_SEQU_DATA );
+       outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
+       memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
+       outb( VGAREG_SEQU_DATA, mmask );
+      }
+    }
+  }
+
+ // Set the BIOS mem
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08);    // 8 is VGA should be ok for now
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
+
+ // FIXME
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
+ 
+ // Set cursor shape
+ if(vga_modes[line].class==TEXT)
+  {
+   biosfn_set_cursor_shape(0x06,0x07);
+  }
+
+ // Set cursor pos for page 0..7
+ for(i=0;i<8;i++)
+  biosfn_set_cursor_pos(i,0x0000);
+
+ // Set active page 0
+ biosfn_set_active_page(0x00);
+
+ // Write the fonts in memory
+ if(vga_modes[line].class==TEXT)
+  { 
+ASM_START
+  ;; copy and activate 8x16 font
+  mov ax, #0x1104
+  mov bl, #0x00
+  int #0x10
+  mov ax, #0x1103
+  mov bl, #0x00
+  int #0x10
+ASM_END
+  }
+
+ // Set the ints 0x1F and 0x43
+ASM_START
+ SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
+ASM_END
+
+  switch(cheight)
+   {case 8:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
+ASM_END
+     break;
+    case 14:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
+ASM_END
+     break;
+    case 16:
+ASM_START
+     SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
+ASM_END
+     break;
+   }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_shape (CH,CL) 
+Bit8u CH;Bit8u CL; 
+{Bit16u cheight,curs,crtc_addr;
+ Bit8u modeset_ctl;
+
+ CH&=0x3f;
+ CL&=0x1f;
+
+ curs=(CH<<8)+CL;
+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
+
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+ cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
+ if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
+  {
+   if(CL!=(CH+1))
+    {
+     CH = ((CH+1) * cheight / 8) -1;
+    }
+   else
+    {
+     CH = ((CL+1) * cheight / 8) - 2;
+    }
+   CL = ((CL+1) * cheight / 8) - 1;
+  }
+
+ // CTRC regs 0x0a and 0x0b
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0a);
+ outb(crtc_addr+1,CH);
+ outb(crtc_addr,0x0b);
+ outb(crtc_addr+1,CL);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_pos (page, cursor) 
+Bit8u page;Bit16u cursor;
+{
+ Bit8u xcurs,ycurs,current;
+ Bit16u nbcols,nbrows,address,crtc_addr;
+
+ // Should not happen...
+ if(page>7)return;
+
+ // Bios cursor pos
+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
+
+ // Set the hardware cursor
+ current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+ if(page==current)
+  {
+   // Get the dimensions
+   nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+   nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+   xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+ 
+   // Calculate the address knowing nbcols nbrows and page num
+   address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
+   
+   // CRTC regs 0x0e and 0x0f
+   crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+   outb(crtc_addr,0x0e);
+   outb(crtc_addr+1,(address&0xff00)>>8);
+   outb(crtc_addr,0x0f);
+   outb(crtc_addr+1,address&0x00ff);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_cursor_pos (page,shape, pos) 
+Bit8u page;Bit16u *shape;Bit16u *pos;
+{
+ Bit16u ss=get_SS();
+
+ // Default
+ write_word(ss, shape, 0);
+ write_word(ss, pos, 0);
+
+ if(page>7)return;
+ // FIXME should handle VGA 14/16 lines
+ write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
+ write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_active_page (page) 
+Bit8u page;
+{
+ Bit16u cursor,dummy,crtc_addr;
+ Bit16u nbcols,nbrows,address;
+ Bit8u mode,line;
+
+ if(page>7)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get pos curs pos for the right page 
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Get the dimensions
+   nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+   nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ 
+   // Calculate the address knowing nbcols nbrows and page num
+   address=SCREEN_MEM_START(nbcols,nbrows,page);
+   write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
+
+   // Start address
+   address=SCREEN_IO_START(nbcols,nbrows,page);
+  }
+ else
+  {
+   address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
+  }
+
+ // CRTC regs 0x0c and 0x0d
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0c);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0d);
+ outb(crtc_addr+1,address&0x00ff);
+
+ // And change the BIOS page
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
+
+#ifdef DEBUG
+ printf("Set active page %02x address %04x\n",page,address);
+#endif
+
+ // Display the cursor, now the page is active
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=ysrc*cheight*nbcols+xstart;
+ dest=ydest*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0105);
+ for(i=0;i<cheight;i++)
+  {
+   memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=ystart*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ for(i=0;i<cheight;i++)
+  {
+   memsetb(0xa000,dest+i*nbcols,attr,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=((ysrc*cheight*nbcols)>>1)+xstart;
+ dest=((ydest*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+  {
+   if (i & 1)
+     memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
+   else
+     memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=((ystart*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+  {
+   if (i & 1)
+     memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
+   else
+     memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
+Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
+{
+ // page == 0xFF if current
+
+ Bit8u mode,line,cheight,bpp,cols;
+ Bit16u nbcols,nbrows,i;
+ Bit16u address;
+
+ if(rul>rlr)return;
+ if(cul>clr)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ // Get the current page
+ if(page==0xFF)
+  page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ if(rlr>=nbrows)rlr=nbrows-1;
+ if(clr>=nbcols)clr=nbcols-1;
+ if(nblines>nbrows)nblines=0;
+ cols=clr-cul+1;
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page);
+#ifdef DEBUG
+   printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
+#endif
+
+   if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+    {
+     memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
+    }
+   else
+    {// if Scroll up
+     if(dir==SCROLL_UP)
+      {for(i=rul;i<=rlr;i++)
+        {
+         if((i+nblines>rlr)||(nblines==0))
+          memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+         else
+          memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
+        }
+      }
+     else
+      {for(i=rlr;i>=rul;i--)
+        {
+         if((i<rul+nblines)||(nblines==0))
+          memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+         else
+          memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
+         if (i>rlr) break;
+        }
+      }
+    }
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   switch(vga_modes[line].memmodel)
+    {
+     case PLANAR4:
+     case PLANAR1:
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         outw(VGAREG_GRDC_ADDRESS, 0x0205);
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
+         outw(VGAREG_GRDC_ADDRESS, 0x0005);
+        }
+       else
+        {// if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(nblines==0))
+              vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
+            }
+          }
+         else
+          {for(i=rlr;i>=rul;i--)
+            {
+             if((i<rul+nblines)||(nblines==0))
+              vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
+             if (i>rlr) break;
+            }
+          }
+        }
+       break;
+     case CGA:
+       bpp=vga_modes[line].pixbits;
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
+        }
+       else
+        {
+         if(bpp==2)
+          {
+           cul<<=1;
+           cols<<=1;
+           nbcols<<=1;
+          }
+         // if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(nblines==0))
+              vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
+            }
+          }
+         else
+          {for(i=rlr;i>=rul;i--)
+            {
+             if((i<rul+nblines)||(nblines==0))
+              vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
+             if (i>rlr) break;
+            }
+          }
+        }
+       break;
+#ifdef DEBUG
+     default:
+       printf("Scroll in graphics mode ");
+       unimplemented();
+#endif
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_char_attr (page,car) 
+Bit8u page;Bit16u *car;
+{Bit16u ss=get_SS();
+ Bit8u xcurs,ycurs,mode,line;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   write_word(ss,car,read_word(vga_modes[line].sstart,address));
+  }
+ else
+  {
+   // FIXME gfx mode
+#ifdef DEBUG
+   unimplemented();
+#endif
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
+{
+ Bit8u i,j,mask;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ switch(cheight)
+  {case 14:
+    fdata = &vgafont14;
+    break;
+   case 16:
+    fdata = &vgafont16;
+    break;
+   default:
+    fdata = &vgafont8;
+  }
+ addr=xcurs+ycurs*cheight*nbcols;
+ src = car * cheight;
+ outw(VGAREG_SEQU_ADDRESS, 0x0f02);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ if(attr&0x80)
+  {
+   outw(VGAREG_GRDC_ADDRESS, 0x1803);
+  }
+ else
+  {
+   outw(VGAREG_GRDC_ADDRESS, 0x0003);
+  }
+ for(i=0;i<cheight;i++)
+  {
+   dest=addr+i*nbcols;
+   for(j=0;j<8;j++)
+    {
+     mask=0x80>>j;
+     outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+     read_byte(0xa000,dest);
+     if(fdata[src+i]&mask)
+      {
+       write_byte(0xa000,dest,attr&0x0f);
+      }
+     else
+      {
+       write_byte(0xa000,dest,0x00);
+      }
+    }
+  }
+ASM_START
+  mov dx, # VGAREG_GRDC_ADDRESS
+  mov ax, #0xff08
+  out dx, ax
+  mov ax, #0x0005
+  out dx, ax
+  mov ax, #0x0003
+  out dx, ax
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=(xcurs*bpp)+ycurs*320;
+ src = car * 8;
+ for(i=0;i<8;i++)
+  {
+   dest=addr+(i>>1)*80;
+   if (i & 1) dest += 0x2000;
+   mask = 0x80;
+   if (bpp == 1)
+    {
+     if (attr & 0x80)
+      {
+       data = read_byte(0xb800,dest);
+      }
+     else
+      {
+       data = 0x00;
+      }
+     for(j=0;j<8;j++)
+      {
+       if (fdata[src+i] & mask)
+        {
+         if (attr & 0x80)
+          {
+           data ^= (attr & 0x01) << (7-j);
+          }
+         else
+          {
+           data |= (attr & 0x01) << (7-j);
+          }
+        }
+       mask >>= 1;
+      }
+     write_byte(0xb800,dest,data);
+    }
+   else
+    {
+     while (mask > 0)
+      {
+       if (attr & 0x80)
+        {
+         data = read_byte(0xb800,dest);
+        }
+       else
+        {
+         data = 0x00;
+        }
+       for(j=0;j<4;j++)
+        {
+         if (fdata[src+i] & mask)
+          {
+           if (attr & 0x80)
+            {
+             data ^= (attr & 0x03) << ((3-j)*2);
+            }
+           else
+            {
+             data |= (attr & 0x03) << ((3-j)*2);
+            }
+          }
+         mask >>= 1;
+        }
+       write_byte(0xb800,dest,data);
+       dest += 1;
+      }
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=xcurs*8+ycurs*nbcols*64;
+ src = car * 8;
+ for(i=0;i<8;i++)
+  {
+   dest=addr+i*nbcols*8;
+   mask = 0x80;
+   for(j=0;j<8;j++)
+    {
+     data = 0x00;
+     if (fdata[src+i] & mask)
+      {
+       data = attr;
+      }
+     write_byte(0xa000,dest+j,data);
+     mask >>= 1;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_attr (car,page,attr,count) 
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   dummy=((Bit16u)attr<<8)+car;
+   memsetw(vga_modes[line].sstart,address,dummy,count);
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   bpp=vga_modes[line].pixbits;
+   while((count-->0) && (xcurs<nbcols))
+    {
+     switch(vga_modes[line].memmodel)
+      {
+       case PLANAR4:
+       case PLANAR1:
+         write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+         break;
+       case CGA:
+         write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+         break;
+       case LINEAR8:
+         write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+         break;
+#ifdef DEBUG
+       default:
+         unimplemented();
+#endif
+      }
+     xcurs++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_only (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+  {
+   // Compute the address
+   address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+   while(count-->0)
+    {write_byte(vga_modes[line].sstart,address,car);
+     address+=2;
+    }
+  }
+ else
+  {
+   // FIXME gfx mode not complete
+   cheight=video_param_table[line_to_vpti[line]].cheight;
+   bpp=vga_modes[line].pixbits;
+   while((count-->0) && (xcurs<nbcols))
+    {
+     switch(vga_modes[line].memmodel)
+      {
+       case PLANAR4:
+       case PLANAR1:
+         write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+         break;
+       case CGA:
+         write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+         break;
+       case LINEAR8:
+         write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+         break;
+#ifdef DEBUG
+       default:
+         unimplemented();
+#endif
+      }
+     xcurs++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_0B:
+  cmp   bh, #0x00
+  je    biosfn_set_border_color
+  cmp   bh, #0x01
+  je    biosfn_set_palette
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+biosfn_set_border_color:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x00
+  out   dx, al
+  mov   al, bl
+  and   al, #0x0f
+  test  al, #0x08
+  jz    set_low_border
+  add   al, #0x08
+set_low_border:
+  out   dx, al
+  mov   cl, #0x01
+  and   bl, #0x10
+set_intensity_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xef
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_intensity_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+biosfn_set_palette:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   cl, #0x01
+  and   bl, #0x01
+set_cga_palette_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xfe
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_cga_palette_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
+{
+ Bit8u mode,line,mask,attr,data;
+ Bit16u addr;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+  {
+   case PLANAR4:
+   case PLANAR1:
+     addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+     mask = 0x80 >> (CX & 0x07);
+     outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+     outw(VGAREG_GRDC_ADDRESS, 0x0205);
+     data = read_byte(0xa000,addr);
+     if (AL & 0x80)
+      {
+       outw(VGAREG_GRDC_ADDRESS, 0x1803);
+      }
+     write_byte(0xa000,addr,AL);
+ASM_START
+     mov dx, # VGAREG_GRDC_ADDRESS
+     mov ax, #0xff08
+     out dx, ax
+     mov ax, #0x0005
+     out dx, ax
+     mov ax, #0x0003
+     out dx, ax
+ASM_END
+     break;
+   case CGA:
+     if(vga_modes[line].pixbits==2)
+      {
+       addr=(CX>>2)+(DX>>1)*80;
+      }
+     else
+      {
+       addr=(CX>>3)+(DX>>1)*80;
+      }
+     if (DX & 1) addr += 0x2000;
+     data = read_byte(0xb800,addr);
+     if(vga_modes[line].pixbits==2)
+      {
+       attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
+       mask = 0x03 << ((3 - (CX & 0x03)) * 2);
+      }
+     else
+      {
+       attr = (AL & 0x01) << (7 - (CX & 0x07));
+       mask = 0x01 << (7 - (CX & 0x07));
+      }
+     if (AL & 0x80)
+      {
+       data ^= attr;
+      }
+     else
+      {
+       data &= ~mask;
+       data |= attr;
+      }
+     write_byte(0xb800,addr,data);
+     break;
+   case LINEAR8:
+     addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+     write_byte(0xa000,addr,AL);
+     break;
+#ifdef DEBUG
+   default:
+     unimplemented();
+#endif
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
+{
+ Bit8u mode,line,mask,attr,data,i;
+ Bit16u addr;
+ Bit16u ss=get_SS();
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+  {
+   case PLANAR4:
+   case PLANAR1:
+     addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+     mask = 0x80 >> (CX & 0x07);
+     attr = 0x00;
+     for(i=0;i<4;i++)
+      {
+       outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
+       data = read_byte(0xa000,addr) & mask;
+       if (data > 0) attr |= (0x01 << i);
+      }
+     break;
+   case CGA:
+     addr=(CX>>2)+(DX>>1)*80;
+     if (DX & 1) addr += 0x2000;
+     data = read_byte(0xb800,addr);
+     if(vga_modes[line].pixbits==2)
+      {
+       attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
+      }
+     else
+      {
+       attr = (data >> (7 - (CX & 0x07))) & 0x01;
+      }
+     break;
+   case LINEAR8:
+     addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+     attr=read_byte(0xa000,addr);
+     break;
+   default:
+#ifdef DEBUG
+     unimplemented();
+#endif
+     attr = 0;
+  }
+ write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_teletype (car, page, attr, flag) 
+Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
+{// flag = WITH_ATTR / NO_ATTR
+
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // special case if page is 0xff, use current page
+ if(page==0xff)
+  page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ switch(car)
+  {
+   case 7:
+    //FIXME should beep
+    break;
+
+   case 8:
+    if(xcurs>0)xcurs--;
+    break;
+
+   case '\r':
+    xcurs=0;
+    break;
+
+   case '\n':
+    ycurs++;
+    break;
+
+   case '\t':
+    do
+     {
+      biosfn_write_teletype(' ',page,attr,flag);
+      biosfn_get_cursor_pos(page,&dummy,&cursor);
+      xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+     }while(xcurs%8==0);
+    break;
+
+   default:
+
+    if(vga_modes[line].class==TEXT)
+     {
+      // Compute the address  
+      address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+      // Write the char 
+      write_byte(vga_modes[line].sstart,address,car);
+
+      if(flag==WITH_ATTR)
+       write_byte(vga_modes[line].sstart,address+1,attr);
+     }
+    else
+     {
+      // FIXME gfx mode not complete
+      cheight=video_param_table[line_to_vpti[line]].cheight;
+      bpp=vga_modes[line].pixbits;
+      switch(vga_modes[line].memmodel)
+       {
+        case PLANAR4:
+        case PLANAR1:
+          write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+          break;
+        case CGA:
+          write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+          break;
+        case LINEAR8:
+          write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+          break;
+#ifdef DEBUG
+        default:
+          unimplemented();
+#endif
+       }
+     }
+    xcurs++;
+  }
+
+ // Do we need to wrap ?
+ if(xcurs==nbcols)
+  {xcurs=0;
+   ycurs++;
+  }
+
+ // Do we need to scroll ?
+ if(ycurs==nbrows)
+  {
+   if(vga_modes[line].class==TEXT)
+    {
+     address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+(ycurs-1)*nbcols)*2;
+     attr=read_byte(vga_modes[line].sstart,address+1);
+     biosfn_scroll(0x01,attr,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+    }
+   else
+    {
+     biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+    }
+   ycurs-=1;
+  }
+
+ // Set the cursor for the page
+ cursor=ycurs; cursor<<=8; cursor+=xcurs;
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_video_mode:
+  push  ds
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  push  bx
+  mov   bx, # BIOSMEM_CURRENT_PAGE
+  mov   al, [bx]
+  pop   bx
+  mov   bh, al
+  push  bx
+  mov   bx, # BIOSMEM_VIDEO_CTL
+  mov   ah, [bx]
+  and   ah, #0x80
+  mov   bx, # BIOSMEM_CURRENT_MODE
+  mov   al, [bx]
+  or    al, ah
+  mov   bx, # BIOSMEM_NB_COLS
+  mov   ah, [bx]
+  pop   bx
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_10:
+  cmp   al, #0x00
+  jne   int10_test_1001
+  jmp   biosfn_set_single_palette_reg
+int10_test_1001:
+  cmp   al, #0x01
+  jne   int10_test_1002
+  jmp   biosfn_set_overscan_border_color
+int10_test_1002:
+  cmp   al, #0x02
+  jne   int10_test_1003
+  jmp   biosfn_set_all_palette_reg
+int10_test_1003:
+  cmp   al, #0x03
+  jne   int10_test_1007
+  jmp   biosfn_toggle_intensity
+int10_test_1007:
+  cmp   al, #0x07
+  jne   int10_test_1008
+  jmp   biosfn_get_single_palette_reg
+int10_test_1008:
+  cmp   al, #0x08
+  jne   int10_test_1009
+  jmp   biosfn_read_overscan_border_color
+int10_test_1009:
+  cmp   al, #0x09
+  jne   int10_test_1010
+  jmp   biosfn_get_all_palette_reg
+int10_test_1010:
+  cmp   al, #0x10
+  jne   int10_test_1012
+  jmp  biosfn_set_single_dac_reg
+int10_test_1012:
+  cmp   al, #0x12
+  jne   int10_test_1013
+  jmp   biosfn_set_all_dac_reg
+int10_test_1013:
+  cmp   al, #0x13
+  jne   int10_test_1015
+  jmp   biosfn_select_video_dac_color_page
+int10_test_1015:
+  cmp   al, #0x15
+  jne   int10_test_1017
+  jmp   biosfn_read_single_dac_reg
+int10_test_1017:
+  cmp   al, #0x17
+  jne   int10_test_1018
+  jmp   biosfn_read_all_dac_reg
+int10_test_1018:
+  cmp   al, #0x18
+  jne   int10_test_1019
+  jmp   biosfn_set_pel_mask
+int10_test_1019:
+  cmp   al, #0x19
+  jne   int10_test_101A
+  jmp   biosfn_read_pel_mask
+int10_test_101A:
+  cmp   al, #0x1a
+  jne   int10_group_10_unknown
+  jmp   biosfn_read_video_dac_state
+int10_group_10_unknown:
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+
+biosfn_set_single_palette_reg:
+  cmp   bl, #0x14
+  ja    no_actl_reg1
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   al, bh
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+no_actl_reg1:
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_overscan_border_color:
+  push  bx
+  mov   bl, #0x11
+  call  biosfn_set_single_palette_reg
+  pop   bx
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_palette_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   cl, #0x00
+  mov   dx, # VGAREG_ACTL_ADDRESS
+set_palette_loop:
+  mov   al, cl
+  out   dx, al
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  inc   cl
+  cmp   cl, #0x10
+  jne   set_palette_loop
+  mov   al, #0x11
+  out   dx, al
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_toggle_intensity:
+  push  ax
+  push  bx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xf7
+  and   bl, #0x01
+  shl   bl, 3
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_single_palette_reg:
+  cmp   bl, #0x14
+  ja    no_actl_reg2
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bh, al
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+no_actl_reg2:
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_overscan_border_color:
+  push  ax
+  push  bx
+  mov   bl, #0x11
+  call  biosfn_get_single_palette_reg
+  mov   al, bh
+  pop   bx
+  mov   bh, al
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_all_palette_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   bx, dx
+  mov   cl, #0x00
+get_palette_loop:
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  inc   cl
+  cmp   cl, #0x10
+  jne   get_palette_loop
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x11
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_single_dac_reg:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_DAC_WRITE_ADDRESS
+  mov   al, bl
+  out   dx, al
+  mov   dx, # VGAREG_DAC_DATA
+  pop   ax
+  push  ax
+  mov   al, ah
+  out   dx, al
+  mov   al, ch
+  out   dx, al
+  mov   al, cl
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_dac_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_DAC_WRITE_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_DAC_DATA
+set_dac_loop:
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  seg   es
+  mov   al, [bx]
+  out   dx, al
+  inc   bx
+  dec   cx
+  jnz   set_dac_loop
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_video_dac_color_page:
+  push  ax
+  push  bx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   bl, #0x01
+  jnz   set_dac_page
+  and   al, #0x7f
+  shl   bh, 7
+  or    al, bh
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  jmp   set_actl_normal
+set_dac_page:
+  push  ax
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x14
+  out   dx, al
+  pop   ax
+  and   al, #0x80
+  jnz   set_dac_16_page
+  shl   bh, 2
+set_dac_16_page:
+  and   bh, #0x0f
+  mov   al, bh
+  out   dx, al
+set_actl_normal:
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_single_dac_reg:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_DAC_READ_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   ax
+  mov   ah, al
+  mov   dx, # VGAREG_DAC_DATA
+  in    al, dx
+  xchg  al, ah
+  push  ax
+  in    al, dx
+  mov   ch, al
+  in    al, dx
+  mov   cl, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_all_dac_reg:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_DAC_READ_ADDRESS
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  push  dx
+  mov   bx, dx
+  mov   dx, # VGAREG_DAC_DATA
+read_dac_loop:
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  in    al, dx
+  seg   es
+  mov   [bx], al
+  inc   bx
+  dec   cx
+  jnz   read_dac_loop
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_pel_mask:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_PEL_MASK
+  mov   al, bl
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_pel_mask:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_PEL_MASK
+  in    al, dx
+  mov   bl, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_video_dac_state:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x10
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bl, al
+  shr   bl, 7
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x14
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  mov   bh, al
+  and   bh, #0x0f
+  test  bl, #0x01
+  jnz   get_dac_16_page
+  shr   bh, 2
+get_dac_16_page:
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_perform_gray_scale_summing (start,count) 
+Bit16u start;Bit16u count;
+{Bit8u r,g,b;
+ Bit16u i;
+ Bit16u index;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x00);
+
+ for( index = 0; index < count; index++ ) 
+  {
+   // set read address and switch to read mode
+   outb(VGAREG_DAC_READ_ADDRESS,start);
+   // get 6-bit wide RGB data values
+   r=inb( VGAREG_DAC_DATA );
+   g=inb( VGAREG_DAC_DATA );
+   b=inb( VGAREG_DAC_DATA );
+
+   // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+   i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
+
+   if(i>0x3f)i=0x3f;
+ 
+   // set write address and switch to write mode
+   outb(VGAREG_DAC_WRITE_ADDRESS,start);
+   // write new intensity value
+   outb( VGAREG_DAC_DATA, i&0xff );
+   outb( VGAREG_DAC_DATA, i&0xff );
+   outb( VGAREG_DAC_DATA, i&0xff );
+   start++;
+  }  
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+}
+
+// --------------------------------------------------------------------------------------------
+static void get_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0402
+ out dx, ax
+ mov ax, #0x0704
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0x0204
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0406
+ out dx, ax
+ASM_END
+}
+
+static void release_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0302
+ out dx, ax
+ mov ax, #0x0304
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in  al, dx
+ and al, #0x01
+ shl al, 2
+ or  al, #0x0a
+ mov ah, al
+ mov al, #0x06
+ mov dx, # VGAREG_GRDC_ADDRESS
+ out dx, ax
+ mov ax, #0x0004
+ out dx, ax
+ mov ax, #0x1005
+ out dx, ax
+ASM_END
+}
+
+ASM_START
+idiv_u:
+  xor dx,dx
+  div bx
+  ret
+ASM_END
+
+static void set_scan_lines(lines) Bit8u lines;
+{
+ Bit16u crtc_addr,cols,page,vde;
+ Bit8u crtc_r9,ovl,rows;
+
+ crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr, 0x09);
+ crtc_r9 = inb(crtc_addr+1);
+ crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+ outb(crtc_addr+1, crtc_r9);
+ if(lines==8)
+  {
+   biosfn_set_cursor_shape(0x06,0x07);
+  }
+ else
+  {
+   biosfn_set_cursor_shape(lines-4,lines-3);
+  }
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
+ outb(crtc_addr, 0x12);
+ vde = inb(crtc_addr+1);
+ outb(crtc_addr, 0x07);
+ ovl = inb(crtc_addr+1);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ rows = vde / lines;
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
+ cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
+}
+
+static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<CX;i++)
+  {
+   src = BP + i * BH;
+   dest = blockaddr + (DX + i) * 32;
+   memcpyb(0xA000, dest, ES, src, BH);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(BH);
+  }
+}
+
+static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 14;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(14);
+  }
+}
+
+static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 8;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(8);
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_text_block_specifier:
+  push  ax
+  push  dx
+  mov   dx, # VGAREG_SEQU_ADDRESS
+  mov   ah, bl
+  mov   al, #0x03
+  out   dx, ax
+  pop   dx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+  {
+   src = i * 16;
+   dest = blockaddr + i * 32;
+   memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
+  }
+ release_font_access();
+ if(AL>=0x10)
+  {
+   set_scan_lines(16);
+  }
+}
+
+static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_font_info (BH,ES,BP,CX,DX) 
+Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
+{Bit16u ss=get_SS();
+ 
+ switch(BH)
+  {case 0x00:
+    write_word(ss,ES,read_word(0x00,0x1f*4));
+    write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
+    break;
+   case 0x01:
+    write_word(ss,ES,read_word(0x00,0x43*4));
+    write_word(ss,BP,read_word(0x00,(0x43*4)+2));
+    break;
+   case 0x02:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont14);
+    break;
+   case 0x03:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont8);
+    break;
+   case 0x04:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont8+128*8);
+    break;
+   case 0x05:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont14alt);
+    break;
+   case 0x06:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont16);
+    break;
+   case 0x07:
+    write_word(ss,ES,0xC000);
+    write_word(ss,BP,vgafont16alt);
+    break;
+   default:
+    #ifdef DEBUG
+     printf("Get font info BH(%02x) was discarded\n",BH);
+    #endif
+    return;
+  }
+ // Set byte/char of on screen font
+ write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
+
+ // Set Highest char row
+ write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_ega_info:
+  push  ds
+  push  ax
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  xor   ch, ch
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   cl, [bx]
+  and   cl, #0x0f
+  mov   bx, # BIOSMEM_CRTC_ADDRESS
+  mov   ax, [bx]
+  mov   bx, #0x0003
+  cmp   ax, # VGAREG_MDA_CRTC_ADDRESS
+  jne   mode_ega_color
+  mov   bh, #0x01
+mode_ega_color:
+  pop   ax
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_alternate_prtsc()
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_vert_res:
+
+; res : 00 200 lines, 01 350 lines, 02 400 lines
+
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   ah, [bx]
+  cmp   dl, #0x01
+  je    vert_res_350
+  jb    vert_res_200
+  cmp   dl, #0x02
+  je    vert_res_400
+#ifdef DEBUG
+  mov   al, dl
+  xor   ah, ah
+  push  ax
+  mov   bx, #msg_vert_res
+  push  bx
+  call  _printf
+  add   sp, #4
+#endif
+  jmp   set_retcode
+vert_res_400:
+
+  ; reset modeset ctl bit 7 and set bit 4
+  ; set switches bit 3-0 to 0x09
+
+  and   al, #0x7f
+  or    al, #0x10
+  and   ah, #0xf0
+  or    ah, #0x09
+  jnz   set_vert_res
+vert_res_350:
+
+  ; reset modeset ctl bit 7 and bit 4
+  ; set switches bit 3-0 to 0x09
+
+  and   al, #0x6f
+  and   ah, #0xf0
+  or    ah, #0x09
+  jnz   set_vert_res
+vert_res_200:
+
+  ; set modeset ctl bit 7 and reset bit 4
+  ; set switches bit 3-0 to 0x08
+
+  and   al, #0xef
+  or    al, #0x80
+  and   ah, #0xf0
+  or    ah, #0x08
+set_vert_res:
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   [bx], al
+  mov   bx, # BIOSMEM_SWITCHES
+  mov   [bx], ah
+set_retcode:
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+#ifdef DEBUG
+msg_vert_res:
+.ascii "Select vert res (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+
+
+biosfn_enable_default_palette_loading:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  shl   dl, 3
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xf7
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+
+biosfn_enable_video_addressing:
+  push  bx
+  push  dx
+  mov   bl, al
+  and   bl, #0x01
+  xor   bl, #0x01
+  shl   bl, 1
+  mov   dx, # VGAREG_READ_MISC_OUTPUT
+  in    al, dx
+  and   al, #0xfd
+  or    al, bl
+  mov   dx, # VGAREG_WRITE_MISC_OUTPUT
+  out   dx, al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  ret
+
+
+biosfn_enable_grayscale_summing:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  xor   dl, #0x01
+  shl   dl, 1
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xfd
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+
+
+biosfn_enable_cursor_emulation:
+  push  ds
+  push  bx
+  push  dx
+  mov   dl, al
+  and   dl, #0x01
+  xor   dl, #0x01
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_MODESET_CTL
+  mov   al, [bx]
+  and   al, #0xfe
+  or    al, dl
+  mov   [bx], al
+  mov   ax, #0x1212
+  pop   dx
+  pop   bx
+  pop   ds
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset) 
+Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
+{
+ Bit16u newcurs,oldcurs,dummy;
+ Bit8u car,carattr;
+
+ // Read curs info for the page
+ biosfn_get_cursor_pos(page,&dummy,&oldcurs);
+
+ // if row=0xff special case : use current cursor position
+ if(row==0xff)
+  {col=oldcurs&0x00ff;
+   row=(oldcurs&0xff00)>>8;
+  }
+
+ newcurs=row; newcurs<<=8; newcurs+=col;
+ biosfn_set_cursor_pos(page,newcurs);
+ 
+ while(count--!=0)
+  {
+   car=read_byte(seg,offset++);
+   if((flag&0x02)!=0)
+    attr=read_byte(seg,offset++);
+
+   biosfn_write_teletype(car,page,attr,WITH_ATTR);
+  }
+ 
+ // Set back curs pos 
+ if((flag&0x01)==0)
+  biosfn_set_cursor_pos(page,oldcurs);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_1A:
+  cmp   al, #0x00
+  je    biosfn_read_display_code
+  cmp   al, #0x01
+  je    biosfn_set_display_code
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+biosfn_read_display_code:
+  push  ds
+  push  ax
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   bx, # BIOSMEM_DCC_INDEX
+  mov   al, [bx]
+  mov   bl, al
+  xor   bh, bh
+  pop   ax
+  mov   al, ah
+  pop   ds
+  ret
+biosfn_set_display_code:
+  push  ds
+  push  ax
+  push  bx
+  mov   ax, # BIOSMEM_SEG
+  mov   ds, ax
+  mov   ax, bx
+  mov   bx, # BIOSMEM_DCC_INDEX
+  mov   [bx], al
+#ifdef DEBUG
+  mov   al, ah
+  xor   ah, ah
+  push  ax
+  mov   bx, #msg_alt_dcc
+  push  bx
+  call  _printf
+  add   sp, #4
+#endif
+  pop   bx
+  pop   ax
+  mov   al, ah
+  pop   ds
+  ret
+
+#ifdef DEBUG
+msg_alt_dcc:
+.ascii "Alternate Display code (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_state_info (BX,ES,DI) 
+Bit16u BX;Bit16u ES;Bit16u DI;
+{
+ // Address of static functionality table
+ write_word(ES,DI+0x00,&static_functionality);
+ write_word(ES,DI+0x02,0xC000);
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
+ memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
+ 
+ write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
+ write_byte(ES,DI+0x26,0);
+ write_byte(ES,DI+0x27,16);
+ write_byte(ES,DI+0x28,0);
+ write_byte(ES,DI+0x29,8);
+ write_byte(ES,DI+0x2a,2);
+ write_byte(ES,DI+0x2b,0);
+ write_byte(ES,DI+0x2c,0);
+ write_byte(ES,DI+0x31,3);
+ write_byte(ES,DI+0x32,0);
+ 
+ memsetb(ES,DI+0x33,0,13);
+}
+
+// --------------------------------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------
+static Bit16u biosfn_read_video_state_size2 (CX) 
+     Bit16u CX;
+{
+    Bit16u size;
+    size = 0;
+    if (CX & 1) {
+        size += 0x46;
+    }
+    if (CX & 2) {
+        size += (5 + 8 + 5) * 2 + 6;
+    }
+    if (CX & 4) {
+        size += 3 + 256 * 3 + 1;
+}
+    return size;
+}
+
+static void biosfn_read_video_state_size (CX, BX) 
+     Bit16u CX; Bit16u *BX;
+{
+    Bit16u ss=get_SS();
+    write_word(ss, BX, biosfn_read_video_state_size2(CX));
+}
+
+static Bit16u biosfn_save_video_state (CX,ES,BX) 
+     Bit16u CX;Bit16u ES;Bit16u BX;
+{
+    Bit16u i, v, crtc_addr, ar_index;
+
+    crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
+    if (CX & 1) {
+        write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
+        write_byte(ES, BX, inb(crtc_addr)); BX++;
+        write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
+        inb(VGAREG_ACTL_RESET);
+        ar_index = inb(VGAREG_ACTL_ADDRESS);
+        write_byte(ES, BX, ar_index); BX++;
+        write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
+
+        for(i=1;i<=4;i++){
+            outb(VGAREG_SEQU_ADDRESS, i);
+            write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+        }
+        outb(VGAREG_SEQU_ADDRESS, 0);
+        write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
+
+        for(i=0;i<=0x18;i++) {
+            outb(crtc_addr,i);
+            write_byte(ES, BX, inb(crtc_addr+1)); BX++;
+        }
+
+        for(i=0;i<=0x13;i++) {
+            inb(VGAREG_ACTL_RESET);
+            outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+            write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
+        }
+        inb(VGAREG_ACTL_RESET);
+
+        for(i=0;i<=8;i++) {
+            outb(VGAREG_GRDC_ADDRESS,i);
+            write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
+        }
+
+        write_word(ES, BX, crtc_addr); BX+= 2;
+
+        /* XXX: read plane latches */
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+        write_byte(ES, BX, 0); BX++;
+    }
+    if (CX & 2) {
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
+        for(i=0;i<8;i++) {
+            write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
+            BX += 2;
+        }
+        write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
+        write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
+        /* current font */
+        write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
+        write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
+    }
+    if (CX & 4) {
+        /* XXX: check this */
+        write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
+        write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
+        write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
+        // Set the whole dac always, from 0
+        outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+        for(i=0;i<256*3;i++) {
+            write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
+        }
+        write_byte(ES, BX, 0); BX++; /* color select register */
+    }
+    return BX;
+}
+
+static Bit16u biosfn_restore_video_state (CX,ES,BX) 
+     Bit16u CX;Bit16u ES;Bit16u BX;
+{
+    Bit16u i, crtc_addr, v, addr1, ar_index;
+
+    if (CX & 1) {
+        // Reset Attribute Ctl flip-flop
+        inb(VGAREG_ACTL_RESET);
+
+        crtc_addr = read_word(ES, BX + 0x40);
+        addr1 = BX;
+        BX += 5;
+        
+        for(i=1;i<=4;i++){
+            outb(VGAREG_SEQU_ADDRESS, i);
+            outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+        }
+        outb(VGAREG_SEQU_ADDRESS, 0);
+        outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
+
+        // Disable CRTC write protection
+        outw(crtc_addr,0x0011);
+        // Set CRTC regs
+        for(i=0;i<=0x18;i++) {
+            if (i != 0x11) {
+                outb(crtc_addr,i);
+                outb(crtc_addr+1, read_byte(ES, BX));
+            }
+            BX++;
+        }
+        // select crtc base address
+        v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+        if (crtc_addr = 0x3d4)
+            v |= 0x01;
+        outb(VGAREG_WRITE_MISC_OUTPUT, v);
+
+        // enable write protection if needed
+        outb(crtc_addr, 0x11);
+        outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
+        
+        // Set Attribute Ctl
+        ar_index = read_byte(ES, addr1 + 0x03);
+        inb(VGAREG_ACTL_RESET);
+        for(i=0;i<=0x13;i++) {
+            outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
+            outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
+        }
+        outb(VGAREG_ACTL_ADDRESS, ar_index);
+        inb(VGAREG_ACTL_RESET);
+        
+        for(i=0;i<=8;i++) {
+            outb(VGAREG_GRDC_ADDRESS,i);
+            outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
+        }
+        BX += 2; /* crtc_addr */
+        BX += 4; /* plane latches */
+        
+        outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
+        outb(crtc_addr, read_byte(ES, addr1)); addr1++;
+        outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
+        addr1++;
+        outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
+    }
+    if (CX & 2) {
+        write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
+        write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
+        write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
+        write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
+        write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
+        write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
+        for(i=0;i<8;i++) {
+            write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
+            BX += 2;
+        }
+        write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
+        write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
+        /* current font */
+        write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
+        write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
+    }
+    if (CX & 4) {
+        BX++;
+        v = read_byte(ES, BX); BX++;
+        outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
+        // Set the whole dac always, from 0
+        outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+        for(i=0;i<256*3;i++) {
+            outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
+        }
+        BX++;
+        outb(VGAREG_DAC_WRITE_ADDRESS, v);
+    }
+    return BX;
+}
+
+// ============================================================================================
+//
+// Video Utils
+//
+// ============================================================================================
+ 
+// --------------------------------------------------------------------------------------------
+static Bit8u find_vga_entry(mode) 
+Bit8u mode;
+{
+ Bit8u i,line=0xFF;
+ for(i=0;i<=MODE_MAX;i++)
+  if(vga_modes[i].svgamode==mode)
+   {line=i;
+    break;
+   }
+ return line;
+}
+
+/* =========================================================== */
+/*
+ * Misc Utils
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static void memsetb(seg,offset,value,count)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u value;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+
+    mov  cx, 10[bp] ; count
+    cmp  cx, #0x00
+    je   memsetb_end
+    mov  ax, 4[bp] ; segment
+    mov  es, ax
+    mov  ax, 6[bp] ; offset
+    mov  di, ax
+    mov  al, 8[bp] ; value
+    cld
+    rep
+     stosb
+
+memsetb_end:
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memsetw(seg,offset,value,count)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u value;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+
+    mov  cx, 10[bp] ; count
+    cmp  cx, #0x00
+    je   memsetw_end
+    mov  ax, 4[bp] ; segment
+    mov  es, ax
+    mov  ax, 6[bp] ; offset
+    mov  di, ax
+    mov  ax, 8[bp] ; value
+    cld
+    rep
+     stosw
+
+memsetw_end:
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyb(dseg,doffset,sseg,soffset,count)
+  Bit16u dseg;
+  Bit16u doffset;
+  Bit16u sseg;
+  Bit16u soffset;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+    push ds
+    push si
+
+    mov  cx, 12[bp] ; count
+    cmp  cx, #0x0000
+    je   memcpyb_end
+    mov  ax, 4[bp] ; dsegment
+    mov  es, ax
+    mov  ax, 6[bp] ; doffset
+    mov  di, ax
+    mov  ax, 8[bp] ; ssegment
+    mov  ds, ax
+    mov  ax, 10[bp] ; soffset
+    mov  si, ax
+    cld
+    rep
+     movsb
+
+memcpyb_end:
+    pop si
+    pop ds
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyw(dseg,doffset,sseg,soffset,count)
+  Bit16u dseg;
+  Bit16u doffset;
+  Bit16u sseg;
+  Bit16u soffset;
+  Bit16u count;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push cx
+    push es
+    push di
+    push ds
+    push si
+
+    mov  cx, 12[bp] ; count
+    cmp  cx, #0x0000
+    je   memcpyw_end
+    mov  ax, 4[bp] ; dsegment
+    mov  es, ax
+    mov  ax, 6[bp] ; doffset
+    mov  di, ax
+    mov  ax, 8[bp] ; ssegment
+    mov  ds, ax
+    mov  ax, 10[bp] ; soffset
+    mov  si, ax
+    cld
+    rep
+     movsw
+
+memcpyw_end:
+    pop si
+    pop ds
+    pop di
+    pop es
+    pop cx
+    pop ax
+
+  pop bp
+ASM_END
+}
+
+/* =========================================================== */
+/*
+ * These functions where ripped from Kevin's rombios.c
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static Bit8u
+read_byte(seg, offset)
+  Bit16u seg;
+  Bit16u offset;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  al, [bx]
+    ;; al = return value (byte)
+    pop  ds
+    pop  bx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static Bit16u
+read_word(seg, offset)
+  Bit16u seg;
+  Bit16u offset;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  ax, [bx]
+    ;; ax = return value (word)
+    pop  ds
+    pop  bx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_byte(seg, offset, data)
+  Bit16u seg;
+  Bit16u offset;
+  Bit8u  data;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  al, 8[bp] ; data byte
+    mov  [bx], al  ; write data byte
+    pop  ds
+    pop  bx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_word(seg, offset, data)
+  Bit16u seg;
+  Bit16u offset;
+  Bit16u data;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push bx
+    push ds
+    mov  ax, 4[bp] ; segment
+    mov  ds, ax
+    mov  bx, 6[bp] ; offset
+    mov  ax, 8[bp] ; data word
+    mov  [bx], ax  ; write data word
+    pop  ds
+    pop  bx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ Bit8u
+inb(port)
+  Bit16u port;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push dx
+    mov  dx, 4[bp]
+    in   al, dx
+    pop  dx
+
+  pop  bp
+ASM_END
+}
+
+  Bit16u
+inw(port)
+  Bit16u port;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push dx
+    mov  dx, 4[bp]
+    in   ax, dx
+    pop  dx
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+  void
+outb(port, val)
+  Bit16u port;
+  Bit8u  val;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push dx
+    mov  dx, 4[bp]
+    mov  al, 6[bp]
+    out  dx, al
+    pop  dx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+  void
+outw(port, val)
+  Bit16u port;
+  Bit16u  val;
+{
+ASM_START
+  push bp
+  mov  bp, sp
+
+    push ax
+    push dx
+    mov  dx, 4[bp]
+    mov  ax, 6[bp]
+    out  dx, ax
+    pop  dx
+    pop  ax
+
+  pop  bp
+ASM_END
+}
+
+Bit16u get_SS()
+{
+ASM_START
+  mov  ax, ss
+ASM_END
+}
+
+#ifdef DEBUG
+void unimplemented()
+{
+ printf("--> Unimplemented\n");
+}
+
+void unknown()
+{
+ printf("--> Unknown int10\n");
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
+void printf(s)
+  Bit8u *s;
+{
+  Bit8u c, format_char;
+  Boolean  in_format;
+  unsigned format_width, i;
+  Bit16u  *arg_ptr;
+  Bit16u   arg_seg, arg, digit, nibble, shift_count;
+
+  arg_ptr = &s;
+  arg_seg = get_SS();
+
+  in_format = 0;
+  format_width = 0;
+
+  while (c = read_byte(0xc000, s)) {
+    if ( c == '%' ) {
+      in_format = 1;
+      format_width = 0;
+      }
+    else if (in_format) {
+      if ( (c>='0') && (c<='9') ) {
+        format_width = (format_width * 10) + (c - '0');
+        }
+      else if (c == 'x') {
+        arg_ptr++; // increment to next arg
+        arg = read_word(arg_seg, arg_ptr);
+        if (format_width == 0)
+          format_width = 4;
+        i = 0;
+        digit = format_width - 1;
+        for (i=0; i<format_width; i++) {
+          nibble = (arg >> (4 * digit)) & 0x000f;
+          if (nibble <= 9)
+            outb(0x0500, nibble + '0');
+          else
+            outb(0x0500, (nibble - 10) + 'A');
+          digit--;
+          }
+        in_format = 0;
+        }
+      //else if (c == 'd') {
+      //  in_format = 0;
+      //  }
+      }
+    else {
+      outb(0x0500, c);
+      }
+    s ++;
+    }
+}
+#endif
+
+ASM_START
+  ; get LFB address from PCI
+  ; in - ax: PCI device vendor
+  ; out - ax: LFB address (high 16 bit)
+  ;; NOTE - may be called in protected mode
+_pci_get_lfb_addr:
+  push bx
+  push cx
+  push dx
+  push eax
+    mov bx, ax
+    xor cx, cx
+    mov dl, #0x00
+    call pci_read_reg
+    cmp ax, #0xffff
+    jz pci_get_lfb_addr_fail
+ pci_get_lfb_addr_next_dev:
+    mov dl, #0x00
+    call pci_read_reg
+    cmp ax, bx ;; check vendor
+    jz pci_get_lfb_addr_found
+    add cx, #0x8
+    cmp cx, #0x200 ;; search bus #0 and #1
+    jb pci_get_lfb_addr_next_dev
+ pci_get_lfb_addr_fail:
+    xor dx, dx ;; no LFB
+    jmp pci_get_lfb_addr_return
+ pci_get_lfb_addr_found:
+    mov dl, #0x10 ;; I/O space #0
+    call pci_read_reg
+    test ax, #0xfff1
+    jz pci_get_lfb_addr_success
+    mov dl, #0x14 ;; I/O space #1
+    call pci_read_reg
+    test ax, #0xfff1
+    jnz pci_get_lfb_addr_fail
+ pci_get_lfb_addr_success:
+    shr eax, #16
+    mov dx, ax ;; LFB address
+ pci_get_lfb_addr_return:
+  pop eax
+  mov ax, dx
+  pop dx
+  pop cx
+  pop bx
+  ret
+
+  ; read PCI register
+  ; in - cx: device/function
+  ; in - dl: register
+  ; out - eax: value
+pci_read_reg:
+  mov eax, #0x00800000
+  mov ax, cx
+  shl eax, #8
+  mov al, dl
+  mov dx, #0xcf8
+  out dx, eax
+  add dl, #4
+  in  eax, dx
+  ret
+ASM_END
+
+#ifdef VBE
+#include "vbe.c"
+#endif
+
+#ifdef CIRRUS
+#include "clext.c"
+#endif
+
+// --------------------------------------------------------------------------------------------
+
+ASM_START 
+;; DATA_SEG_DEFS_HERE
+ASM_END
+
+ASM_START
+.ascii "vgabios ends here"
+.byte  0x00
+vgabios_end:
+.byte 0xCB
+;; BLOCK_STRINGS_BEGIN
+ASM_END
diff --git a/qemu-0.15.x/roms/vgabios/vgabios.h b/qemu-0.15.x/roms/vgabios/vgabios.h
new file mode 100644
index 0000000..3ad4bae
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vgabios.h
@@ -0,0 +1,47 @@
+#ifndef vgabios_h_included
+#define vgabios_h_included
+
+/* Types */
+typedef unsigned char  Bit8u;
+typedef unsigned short Bit16u;
+typedef unsigned long  Bit32u;
+typedef unsigned short Boolean;
+
+/* Defines */
+
+#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
+#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
+#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
+#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
+#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
+#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
+#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
+#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
+
+#define GET_AL() ( AX & 0x00ff )
+#define GET_BL() ( BX & 0x00ff )
+#define GET_CL() ( CX & 0x00ff )
+#define GET_DL() ( DX & 0x00ff )
+#define GET_AH() ( AX >> 8 )
+#define GET_BH() ( BX >> 8 )
+#define GET_CH() ( CX >> 8 )
+#define GET_DH() ( DX >> 8 )
+
+#define SET_CF()     FLAGS |= 0x0001
+#define CLEAR_CF()   FLAGS &= 0xfffe
+#define GET_CF()     (FLAGS & 0x0001)
+
+#define SET_ZF()     FLAGS |= 0x0040
+#define CLEAR_ZF()   FLAGS &= 0xffbf
+#define GET_ZF()     (FLAGS & 0x0040)
+
+#define SCROLL_DOWN 0
+#define SCROLL_UP   1
+#define NO_ATTR     2
+#define WITH_ATTR   3
+
+#define SCREEN_SIZE(x,y) (((x*y*2)|0x00ff)+1)
+#define SCREEN_MEM_START(x,y,p) ((((x*y*2)|0x00ff)+1)*p)
+#define SCREEN_IO_START(x,y,p) ((((x*y)|0x00ff)+1)*p)
+
+#endif
diff --git a/qemu-0.15.x/roms/vgabios/vgafonts.h b/qemu-0.15.x/roms/vgabios/vgafonts.h
new file mode 100644
index 0000000..0c213e6
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vgafonts.h
@@ -0,0 +1,784 @@
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */ 
+static Bit8u vgafont8[256*8]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14[256*14]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont16[256*16]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14alt[1]={0x00};
+static Bit8u vgafont16alt[1]={0x00};
diff --git a/qemu-0.15.x/roms/vgabios/vgatables.h b/qemu-0.15.x/roms/vgabios/vgatables.h
new file mode 100644
index 0000000..3ac96bb
--- /dev/null
+++ b/qemu-0.15.x/roms/vgabios/vgatables.h
@@ -0,0 +1,622 @@
+/*
+ *
+ * BIOS Memory 
+ *
+ */
+#define BIOSMEM_SEG 0x40
+
+#define BIOSMEM_INITIAL_MODE  0x10
+#define BIOSMEM_CURRENT_MODE  0x49
+#define BIOSMEM_NB_COLS       0x4A
+#define BIOSMEM_PAGE_SIZE     0x4C
+#define BIOSMEM_CURRENT_START 0x4E
+#define BIOSMEM_CURSOR_POS    0x50
+#define BIOSMEM_CURSOR_TYPE   0x60
+#define BIOSMEM_CURRENT_PAGE  0x62
+#define BIOSMEM_CRTC_ADDRESS  0x63
+#define BIOSMEM_CURRENT_MSR   0x65
+#define BIOSMEM_CURRENT_PAL   0x66
+#define BIOSMEM_NB_ROWS       0x84
+#define BIOSMEM_CHAR_HEIGHT   0x85
+#define BIOSMEM_VIDEO_CTL     0x87
+#define BIOSMEM_SWITCHES      0x88
+#define BIOSMEM_MODESET_CTL   0x89
+#define BIOSMEM_DCC_INDEX     0x8A
+#define BIOSMEM_VS_POINTER    0xA8
+#define BIOSMEM_VBE_FLAG      0xB9
+#define BIOSMEM_VBE_MODE      0xBA
+
+
+/*
+ *
+ * VGA registers
+ *
+ */
+#define VGAREG_ACTL_ADDRESS            0x3c0
+#define VGAREG_ACTL_WRITE_DATA         0x3c0
+#define VGAREG_ACTL_READ_DATA          0x3c1
+
+#define VGAREG_INPUT_STATUS            0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT       0x3c2
+#define VGAREG_VIDEO_ENABLE            0x3c3
+#define VGAREG_SEQU_ADDRESS            0x3c4
+#define VGAREG_SEQU_DATA               0x3c5
+
+#define VGAREG_PEL_MASK                0x3c6
+#define VGAREG_DAC_STATE               0x3c7
+#define VGAREG_DAC_READ_ADDRESS        0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS       0x3c8
+#define VGAREG_DAC_DATA                0x3c9
+
+#define VGAREG_READ_FEATURE_CTL        0x3ca
+#define VGAREG_READ_MISC_OUTPUT        0x3cc
+
+#define VGAREG_GRDC_ADDRESS            0x3ce
+#define VGAREG_GRDC_DATA               0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS        0x3b4
+#define VGAREG_MDA_CRTC_DATA           0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS        0x3d4
+#define VGAREG_VGA_CRTC_DATA           0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL   0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL   0x3da
+#define VGAREG_ACTL_RESET              0x3da
+
+#define VGAREG_MDA_MODECTL             0x3b8
+#define VGAREG_CGA_MODECTL             0x3d8
+#define VGAREG_CGA_PALETTE             0x3d9
+
+/* Video memory */
+#define VGAMEM_GRAPH 0xA000
+#define VGAMEM_CTEXT 0xB800
+#define VGAMEM_MTEXT 0xB000
+
+/*
+ *
+ * Tables of default values for each mode
+ *
+ */
+#define MODE_MAX   15
+#define TEXT       0x00
+#define GRAPH      0x01
+
+#define CTEXT      0x00
+#define MTEXT      0x01
+#define CGA        0x02
+#define PLANAR1    0x03
+#define PLANAR4    0x04
+#define LINEAR8    0x05
+
+// for SVGA
+#define LINEAR15   0x10
+#define LINEAR16   0x11
+#define LINEAR24   0x12
+#define LINEAR32   0x13
+
+typedef struct
+{Bit8u  svgamode;
+ Bit8u  class;    /* TEXT, GRAPH */
+ Bit8u  memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+ Bit8u  pixbits;
+ Bit16u sstart;
+ Bit8u  pelmask;
+ Bit8u  dacmodel; /* 0 1 2 3 */
+} VGAMODES;
+
+static VGAMODES vga_modes[MODE_MAX+1]=
+{//mode  class  model bits sstart  pelm  dac
+ {0x00, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x01, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x02, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x03, TEXT,  CTEXT,   4, 0xB800, 0xFF, 0x02},
+ {0x04, GRAPH, CGA,     2, 0xB800, 0xFF, 0x01},
+ {0x05, GRAPH, CGA,     2, 0xB800, 0xFF, 0x01},
+ {0x06, GRAPH, CGA,     1, 0xB800, 0xFF, 0x01},
+ {0x07, TEXT,  MTEXT,   4, 0xB000, 0xFF, 0x00},
+ {0x0D, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
+ {0x0E, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
+ {0x0F, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x00},
+ {0x10, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
+ {0x11, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x02},
+ {0x12, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
+ {0x13, GRAPH, LINEAR8, 8, 0xA000, 0xFF, 0x03},
+ {0x6A, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02}
+};
+
+/* convert index in vga_modes[] to index in video_param_table[] */
+static Bit8u line_to_vpti[MODE_MAX+1]={
+    0x17, 0x17, 0x18, 0x18, 0x04, 0x05, 0x06, 0x07, 
+    0x0d, 0x0e, 0x11, 0x12, 0x1a, 0x1b, 0x1c, 0x1d,
+};
+
+/* Default Palette */
+#define DAC_MAX_MODEL 3
+
+static Bit8u dac_regs[DAC_MAX_MODEL+1]=
+{0x3f,0x3f,0x3f,0xff};
+
+/* standard BIOS Video Parameter Table */
+typedef struct {
+    Bit8u  twidth;
+    Bit8u  theightm1;
+    Bit8u  cheight;
+    Bit8u  slength_l;
+    Bit8u  slength_h;
+    Bit8u  sequ_regs[4];
+    Bit8u  miscreg;
+    Bit8u  crtc_regs[25];
+    Bit8u  actl_regs[20];
+    Bit8u  grdc_regs[9];
+} VideoParamTableEntry;
+
+static VideoParamTableEntry video_param_table[30] = {
+{
+ /* index=0x00 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x01 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x02 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x03 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x04 vga mode 0x04 */
+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x05 vga mode 0x05 */
+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x06 vga mode 0x06 */
+ 80, 24, 8, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x01, 0x01, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
+ 0xff, /* crtc_regs */
+ 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x07 vga mode 0x07 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x66, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x08 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x09 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0a no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0b no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0c no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x0d vga mode 0x0d */
+ 40, 24, 8, 0x00, 0x20, /* tw, th-1, ch, slength */
+ 0x09, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x0e vga mode 0x0e */
+ 80, 24, 8, 0x00, 0x40, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x0f no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x10 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x11 vga mode 0x0f */
+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xa3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x12 vga mode 0x10 */
+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xa3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x13 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x14 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x15 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x16 no mode defined */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+},
+{
+ /* index=0x17 vga mode 0x01 */
+ 40, 24, 16, 0x00, 0x08, /* tw, th-1, ch, slength */
+ 0x08, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x67, /* miscreg */
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x18 vga mode 0x03 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x67, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x19 vga mode 0x07 */
+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
+ 0x66, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1a vga mode 0x11 */
+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1b vga mode 0x12 */
+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1c vga mode 0x13 */
+ 40, 24, 8, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x0e, /* sequ_regs */
+ 0x63, /* miscreg */
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x41, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+{
+ /* index=0x1d vga mode 0x6a */
+ 100, 36, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
+ 0xe3, /* miscreg */
+ 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+ 0xff, /* crtc_regs */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
+},
+};
+
+/* Mono */
+static Bit8u palette0[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+  0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette1[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette2[63+1][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+  0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+  0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+  0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+  0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+  0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+  0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f 
+};
+
+static Bit8u palette3[256][3]=
+{
+  0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+  0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+  0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+  0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+  0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+  0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+  0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+  0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+  0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+  0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+  0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+  0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+  0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+  0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+  0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+  0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+  0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+  0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+  0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+  0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+  0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+  0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+  0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+  0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+  0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+  0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+  0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+  0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+  0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+  0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+  0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+static Bit8u static_functionality[0x10]=
+{
+ /* 0 */ 0xff,  // All modes supported #1
+ /* 1 */ 0xe0,  // All modes supported #2
+ /* 2 */ 0x0f,  // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00,  // reserved
+ /* 7 */ 0x07,  // 200, 350, 400 scan lines
+ /* 8 */ 0x02,  // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08,  // total number of charset blocks in text mode
+ /* a */ 0xe7,  // Change to add new functions
+ /* b */ 0x0c,  // Change to add new functions
+ /* c */ 0x00,  // reserved
+ /* d */ 0x00,  // reserved
+ /* e */ 0x00,  // Change to add new functions
+ /* f */ 0x00   // reserved
+};
diff --git a/qemu-0.15.x/rules.mak b/qemu-0.15.x/rules.mak
new file mode 100644
index 0000000..612ae37
--- /dev/null
+++ b/qemu-0.15.x/rules.mak
@@ -0,0 +1,72 @@
+
+# Don't use implicit rules or variables
+# we have explicit rules for everything
+MAKEFLAGS += -rR
+
+# Files with this suffixes are final, don't try to generate them
+# using implicit rules
+%.d:
+%.h:
+%.c:
+%.m:
+%.mak:
+
+# Flags for dependency generation
+QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
+
+%.o: %.c
+	$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  CC    $(TARGET_DIR)$@")
+
+ifeq ($(LIBTOOL),)
+%.lo: %.c
+	@echo "missing libtool. please install and rerun configure"; exit 1
+else
+%.lo: %.c
+	$(call quiet-command,libtool --mode=compile --quiet --tag=CC $(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  lt CC $@")
+endif
+
+%.o: %.S
+	$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  AS    $(TARGET_DIR)$@")
+
+%.o: %.m
+	$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  OBJC  $(TARGET_DIR)$@")
+
+LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS),"  LINK  $(TARGET_DIR)$@")
+
+%$(EXESUF): %.o
+	$(call LINK,$^)
+
+%.a:
+	$(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"  AR    $(TARGET_DIR)$@")
+
+quiet-command = $(if $(V),$1,$(if $(2), at echo $2 && $1, @$1))
+
+# cc-option
+# Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
+
+cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
+              >/dev/null 2>&1 && echo OK), $2, $3)
+
+VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi
+set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
+
+# find-in-path
+# Usage: $(call find-in-path, prog)
+# Looks in the PATH if the argument contains no slash, else only considers one
+# specific directory.  Returns an # empty string if the program doesn't exist
+# there.
+find-in-path = $(if $(find-string /, $1), \
+        $(wildcard $1), \
+        $(wildcard $(patsubst %, %/$1, $(subst :, ,$(PATH)))))
+
+# Generate timestamp files for .h include files
+
+%.h: %.h-timestamp
+	@test -f $@ || cp $< $@
+
+%.h-timestamp: %.mak
+	$(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, "  GEN   $*.h")
+	@cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h
+
+# will delete the target of a rule if commands exit with a nonzero exit status
+.DELETE_ON_ERROR:
diff --git a/qemu-0.15.x/rwhandler.c b/qemu-0.15.x/rwhandler.c
new file mode 100644
index 0000000..bb2238f
--- /dev/null
+++ b/qemu-0.15.x/rwhandler.c
@@ -0,0 +1,87 @@
+#include "rwhandler.h"
+#include "ioport.h"
+#include "cpu-all.h"
+
+#define RWHANDLER_WRITE(name, len, type) \
+static void name(void *opaque, type addr, uint32_t value) \
+{\
+    struct ReadWriteHandler *handler = opaque;\
+    handler->write(handler, addr, value, len);\
+}
+
+#define RWHANDLER_READ(name, len, type) \
+static uint32_t name(void *opaque, type addr) \
+{ \
+    struct ReadWriteHandler *handler = opaque; \
+    return handler->read(handler, addr, len); \
+}
+
+RWHANDLER_WRITE(cpu_io_memory_simple_writeb, 1, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readb, 1, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writew, 2, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readw, 2, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writel, 4, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readl, 4, target_phys_addr_t);
+
+static CPUWriteMemoryFunc * const cpu_io_memory_simple_write[] = {
+    &cpu_io_memory_simple_writeb,
+    &cpu_io_memory_simple_writew,
+    &cpu_io_memory_simple_writel,
+};
+
+static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = {
+    &cpu_io_memory_simple_readb,
+    &cpu_io_memory_simple_readw,
+    &cpu_io_memory_simple_readl,
+};
+
+int cpu_register_io_memory_simple(struct ReadWriteHandler *handler, int endian)
+{
+    if (!handler->read || !handler->write) {
+        return -1;
+    }
+    return cpu_register_io_memory(cpu_io_memory_simple_read,
+                                  cpu_io_memory_simple_write,
+                                  handler, endian);
+}
+
+RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
+RWHANDLER_READ(ioport_simple_readb, 1, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writew, 2, uint32_t);
+RWHANDLER_READ(ioport_simple_readw, 2, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writel, 4, uint32_t);
+RWHANDLER_READ(ioport_simple_readl, 4, uint32_t);
+
+int register_ioport_simple(ReadWriteHandler* handler,
+                           pio_addr_t start, int length, int size)
+{
+    IOPortWriteFunc *write;
+    IOPortReadFunc *read;
+    int r;
+    switch (size) {
+    case 1:
+        write = ioport_simple_writeb;
+        read = ioport_simple_readb;
+        break;
+    case 2:
+        write = ioport_simple_writew;
+        read = ioport_simple_readw;
+        break;
+    default:
+        write = ioport_simple_writel;
+        read = ioport_simple_readl;
+    }
+    if (handler->write) {
+        r = register_ioport_write(start, length, size, write, handler);
+        if (r < 0) {
+            return r;
+        }
+    }
+    if (handler->read) {
+        r = register_ioport_read(start, length, size, read, handler);
+        if (r < 0) {
+            return r;
+        }
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/rwhandler.h b/qemu-0.15.x/rwhandler.h
new file mode 100644
index 0000000..b2a5790
--- /dev/null
+++ b/qemu-0.15.x/rwhandler.h
@@ -0,0 +1,27 @@
+#ifndef READ_WRITE_HANDLER_H
+#define READ_WRITE_HANDLER_H
+
+#include "qemu-common.h"
+#include "ioport.h"
+
+typedef struct ReadWriteHandler ReadWriteHandler;
+
+/* len is guaranteed to be one of 1, 2 or 4, addr is guaranteed to fit in an
+ * appropriate type (io/memory/etc). They do not need to be range checked. */
+typedef void WriteHandlerFunc(ReadWriteHandler *, pcibus_t addr,
+                              uint32_t value, int len);
+typedef uint32_t ReadHandlerFunc(ReadWriteHandler *, pcibus_t addr, int len);
+
+struct ReadWriteHandler {
+    WriteHandlerFunc *write;
+    ReadHandlerFunc *read;
+};
+
+/* Helpers for when we want to use a single routine with length. */
+/* CPU memory handler: both read and write must be present. */
+int cpu_register_io_memory_simple(ReadWriteHandler *, int endian);
+/* io port handler: can supply only read or write handlers. */
+int register_ioport_simple(ReadWriteHandler *,
+                           pio_addr_t start, int length, int size);
+
+#endif
diff --git a/qemu-0.15.x/s390-dis.c b/qemu-0.15.x/s390-dis.c
new file mode 100644
index 0000000..8abcdf0
--- /dev/null
+++ b/qemu-0.15.x/s390-dis.c
@@ -0,0 +1,1796 @@
+/* opcodes/s390-dis.c revision 1.12 */
+/* s390-dis.c -- Disassemble S390 instructions
+   Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky at de.ibm.com).
+
+   This file is part of GDB, GAS and the GNU binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "qemu-common.h"
+#include "dis-asm.h"
+
+/* include/opcode/s390.h revision 1.9 */
+/* s390.h -- Header file for S390 opcode table
+   Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky at de.ibm.com).
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef S390_H
+#define S390_H
+
+/* List of instruction sets variations. */
+
+enum s390_opcode_mode_val
+  {
+    S390_OPCODE_ESA = 0,
+    S390_OPCODE_ZARCH
+  };
+
+enum s390_opcode_cpu_val
+  {
+    S390_OPCODE_G5 = 0,
+    S390_OPCODE_G6,
+    S390_OPCODE_Z900,
+    S390_OPCODE_Z990,
+    S390_OPCODE_Z9_109,
+    S390_OPCODE_Z9_EC,
+    S390_OPCODE_Z10
+  };
+
+/* The opcode table is an array of struct s390_opcode.  */
+
+struct s390_opcode
+  {
+    /* The opcode name.  */
+    const char * name;
+
+    /* The opcode itself.  Those bits which will be filled in with
+       operands are zeroes.  */
+    unsigned char opcode[6];
+
+    /* The opcode mask.  This is used by the disassembler.  This is a
+       mask containing ones indicating those bits which must match the
+       opcode field, and zeroes indicating those bits which need not
+       match (and are presumably filled in by operands).  */
+    unsigned char mask[6];
+
+    /* The opcode length in bytes. */
+    int oplen;
+
+    /* An array of operand codes.  Each code is an index into the
+       operand table.  They appear in the order which the operands must
+       appear in assembly code, and are terminated by a zero.  */
+    unsigned char operands[6];
+
+    /* Bitmask of execution modes this opcode is available for.  */
+    unsigned int modes;
+
+    /* First cpu this opcode is available for.  */
+    enum s390_opcode_cpu_val min_cpu;
+  };
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+/* QEMU: Mark these static.  */
+static const struct s390_opcode s390_opcodes[];
+static const int                s390_num_opcodes;
+
+/* A opcode format table for the .insn pseudo mnemonic.  */
+static const struct s390_opcode s390_opformats[];
+static const int                s390_num_opformats;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* The operands table is an array of struct s390_operand.  */
+
+struct s390_operand
+  {
+    /* The number of bits in the operand.  */
+    int bits;
+
+    /* How far the operand is left shifted in the instruction.  */
+    int shift;
+
+    /* One bit syntax flags.  */
+    unsigned long flags;
+  };
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+static const struct s390_operand s390_operands[];
+
+/* Values defined for the flags field of a struct s390_operand.  */
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define S390_OPERAND_GPR 0x1
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'. */
+#define S390_OPERAND_FPR 0x2
+
+/* This operand names an access register.  The disassembler
+   prints these with a leading 'a'.  */
+#define S390_OPERAND_AR 0x4
+
+/* This operand names a control register.  The disassembler
+   prints these with a leading 'c'.  */
+#define S390_OPERAND_CR 0x8
+
+/* This operand is a displacement.  */
+#define S390_OPERAND_DISP 0x10
+
+/* This operand names a base register.  */
+#define S390_OPERAND_BASE 0x20
+
+/* This operand names an index register, it can be skipped.  */
+#define S390_OPERAND_INDEX 0x40
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define S390_OPERAND_PCREL 0x80
+
+/* This operand takes signed values.  */
+#define S390_OPERAND_SIGNED 0x100
+
+/* This operand is a length.  */
+#define S390_OPERAND_LENGTH 0x200
+
+/* This operand is optional. Only a single operand at the end of
+   the instruction may be optional.  */
+#define S390_OPERAND_OPTIONAL 0x400
+
+/* QEMU-ADD */
+/* ??? Not quite the format the assembler takes, but easy to implement
+   without recourse to the table generator.  */
+#define S390_OPERAND_CCODE  0x800
+
+static const char s390_ccode_name[16][4] = {
+    "n",    /* 0000 */
+    "o",    /* 0001 */
+    "h",    /* 0010 */
+    "nle",  /* 0011 */
+    "l",    /* 0100 */
+    "nhe",  /* 0101 */
+    "lh",   /* 0110 */
+    "ne",   /* 0111 */
+    "e",    /* 1000 */
+    "nlh",  /* 1001 */
+    "he",   /* 1010 */
+    "nl",   /* 1011 */
+    "le",   /* 1100 */
+    "nh",   /* 1101 */
+    "no",   /* 1110 */
+    "a"     /* 1111 */
+};
+/* QEMU-END */
+
+#endif /* S390_H */
+
+static int init_flag = 0;
+static int opc_index[256];
+
+/* QEMU: We've disabled the architecture check below.  */
+/* static int current_arch_mask = 0; */
+
+/* Set up index table for first opcode byte.  */
+
+static void
+init_disasm (struct disassemble_info *info)
+{
+  const struct s390_opcode *opcode;
+  const struct s390_opcode *opcode_end;
+
+  memset (opc_index, 0, sizeof (opc_index));
+  opcode_end = s390_opcodes + s390_num_opcodes;
+  for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
+    {
+      opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
+      while ((opcode < opcode_end) &&
+	     (opcode[1].opcode[0] == opcode->opcode[0]))
+	opcode++;
+    }
+
+#ifdef QEMU_DISABLE
+  switch (info->mach)
+    {
+    case bfd_mach_s390_31:
+      current_arch_mask = 1 << S390_OPCODE_ESA;
+      break;
+    case bfd_mach_s390_64:
+      current_arch_mask = 1 << S390_OPCODE_ZARCH;
+      break;
+    default:
+      abort ();
+    }
+#endif /* QEMU_DISABLE */
+
+  init_flag = 1;
+}
+
+/* Extracts an operand value from an instruction.  */
+
+static inline unsigned int
+s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
+{
+  unsigned int val;
+  int bits;
+
+  /* Extract fragments of the operand byte for byte.  */
+  insn += operand->shift / 8;
+  bits = (operand->shift & 7) + operand->bits;
+  val = 0;
+  do
+    {
+      val <<= 8;
+      val |= (unsigned int) *insn++;
+      bits -= 8;
+    }
+  while (bits > 0);
+  val >>= -bits;
+  val &= ((1U << (operand->bits - 1)) << 1) - 1;
+
+  /* Check for special long displacement case.  */
+  if (operand->bits == 20 && operand->shift == 20)
+    val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
+
+  /* Sign extend value if the operand is signed or pc relative.  */
+  if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
+      && (val & (1U << (operand->bits - 1))))
+    val |= (-1U << (operand->bits - 1)) << 1;
+
+  /* Double value if the operand is pc relative.  */
+  if (operand->flags & S390_OPERAND_PCREL)
+    val <<= 1;
+
+  /* Length x in an instructions has real length x + 1.  */
+  if (operand->flags & S390_OPERAND_LENGTH)
+    val++;
+  return val;
+}
+
+/* Print a S390 instruction.  */
+
+int
+print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  bfd_byte buffer[6];
+  const struct s390_opcode *opcode;
+  const struct s390_opcode *opcode_end;
+  unsigned int value;
+  int status, opsize, bufsize;
+  char separator;
+
+  if (init_flag == 0)
+    init_disasm (info);
+
+  /* The output looks better if we put 6 bytes on a line.  */
+  info->bytes_per_line = 6;
+
+  /* Every S390 instruction is max 6 bytes long.  */
+  memset (buffer, 0, 6);
+  status = (*info->read_memory_func) (memaddr, buffer, 6, info);
+  if (status != 0)
+    {
+      for (bufsize = 0; bufsize < 6; bufsize++)
+	if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
+	  break;
+      if (bufsize <= 0)
+	{
+	  (*info->memory_error_func) (status, memaddr, info);
+	  return -1;
+	}
+      /* Opsize calculation looks strange but it works
+	 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
+	 11xxxxxx -> 6 bytes.  */
+      opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
+      status = opsize > bufsize;
+    }
+  else
+    {
+      bufsize = 6;
+      opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
+    }
+
+  if (status == 0)
+    {
+      /* Find the first match in the opcode table.  */
+      opcode_end = s390_opcodes + s390_num_opcodes;
+      for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
+	   (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
+	   opcode++)
+	{
+	  const struct s390_operand *operand;
+	  const unsigned char *opindex;
+
+#ifdef QEMU_DISABLE
+	  /* Check architecture.  */
+	  if (!(opcode->modes & current_arch_mask))
+	    continue;
+#endif /* QEMU_DISABLE */
+
+	  /* Check signature of the opcode.  */
+	  if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
+	      || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
+	      || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
+	      || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
+	      || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
+	    continue;
+
+	  /* The instruction is valid.  */
+/* QEMU-MOD */
+         (*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+         if (s390_operands[opcode->operands[0]].flags & S390_OPERAND_CCODE)
+           separator = 0;
+         else
+           separator = '\t';
+/* QEMU-END */
+
+	  /* Extract the operands.  */
+	  for (opindex = opcode->operands; *opindex != 0; opindex++)
+	    {
+	      unsigned int value;
+
+	      operand = s390_operands + *opindex;
+	      value = s390_extract_operand (buffer, operand);
+
+	      if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
+		continue;
+	      if ((operand->flags & S390_OPERAND_BASE) &&
+		  value == 0 && separator == '(')
+		{
+		  separator = ',';
+		  continue;
+		}
+
+	      if (separator)
+		(*info->fprintf_func) (info->stream, "%c", separator);
+
+	      if (operand->flags & S390_OPERAND_GPR)
+		(*info->fprintf_func) (info->stream, "%%r%i", value);
+	      else if (operand->flags & S390_OPERAND_FPR)
+		(*info->fprintf_func) (info->stream, "%%f%i", value);
+	      else if (operand->flags & S390_OPERAND_AR)
+		(*info->fprintf_func) (info->stream, "%%a%i", value);
+	      else if (operand->flags & S390_OPERAND_CR)
+		(*info->fprintf_func) (info->stream, "%%c%i", value);
+	      else if (operand->flags & S390_OPERAND_PCREL)
+		(*info->print_address_func) (memaddr + (int) value, info);
+	      else if (operand->flags & S390_OPERAND_SIGNED)
+		(*info->fprintf_func) (info->stream, "%i", (int) value);
+/* QEMU-ADD */
+              else if (operand->flags & S390_OPERAND_CCODE)
+                {
+		  (*info->fprintf_func) (info->stream, "%s",
+                                         s390_ccode_name[(int) value]);
+                  separator = '\t';
+                  continue;
+                }
+/* QEMU-END */
+	      else
+		(*info->fprintf_func) (info->stream, "%u", value);
+
+	      if (operand->flags & S390_OPERAND_DISP)
+		{
+		  separator = '(';
+		}
+	      else if (operand->flags & S390_OPERAND_BASE)
+		{
+		  (*info->fprintf_func) (info->stream, ")");
+		  separator = ',';
+		}
+	      else
+		separator = ',';
+	    }
+
+	  /* Found instruction, printed it, return its size.  */
+	  return opsize;
+	}
+      /* No matching instruction found, fall through to hex print.  */
+    }
+
+  if (bufsize >= 4)
+    {
+      value = (unsigned int) buffer[0];
+      value = (value << 8) + (unsigned int) buffer[1];
+      value = (value << 8) + (unsigned int) buffer[2];
+      value = (value << 8) + (unsigned int) buffer[3];
+      (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
+      return 4;
+    }
+  else if (bufsize >= 2)
+    {
+      value = (unsigned int) buffer[0];
+      value = (value << 8) + (unsigned int) buffer[1];
+      (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
+      return 2;
+    }
+  else
+    {
+      value = (unsigned int) buffer[0];
+      (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
+      return 1;
+    }
+}
+
+/* opcodes/s390-opc.c revision 1.16 */
+/* s390-opc.c -- S390 opcode list
+   Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky at de.ibm.com).
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* This file holds the S390 opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+
+/* The operands table.
+   The fields are bits, shift, insert, extract, flags.  */
+
+static const struct s390_operand s390_operands[] =
+{
+#define UNUSED 0
+  { 0, 0, 0 },                    /* Indicates the end of the operand list */
+
+#define R_8    1                  /* GPR starting at position 8 */
+  { 4, 8, S390_OPERAND_GPR },
+#define R_12   2                  /* GPR starting at position 12 */
+  { 4, 12, S390_OPERAND_GPR },
+#define R_16   3                  /* GPR starting at position 16 */
+  { 4, 16, S390_OPERAND_GPR },
+#define R_20   4                  /* GPR starting at position 20 */
+  { 4, 20, S390_OPERAND_GPR },
+#define R_24   5                  /* GPR starting at position 24 */
+  { 4, 24, S390_OPERAND_GPR },
+#define R_28   6                  /* GPR starting at position 28 */
+  { 4, 28, S390_OPERAND_GPR },
+#define R_32   7                  /* GPR starting at position 32 */
+  { 4, 32, S390_OPERAND_GPR },
+
+#define F_8    8                  /* FPR starting at position 8 */
+  { 4, 8, S390_OPERAND_FPR },
+#define F_12   9                  /* FPR starting at position 12 */
+  { 4, 12, S390_OPERAND_FPR },
+#define F_16   10                 /* FPR starting at position 16 */
+  { 4, 16, S390_OPERAND_FPR },
+#define F_20   11                 /* FPR starting at position 16 */
+  { 4, 16, S390_OPERAND_FPR },
+#define F_24   12                 /* FPR starting at position 24 */
+  { 4, 24, S390_OPERAND_FPR },
+#define F_28   13                 /* FPR starting at position 28 */
+  { 4, 28, S390_OPERAND_FPR },
+#define F_32   14                 /* FPR starting at position 32 */
+  { 4, 32, S390_OPERAND_FPR },
+
+#define A_8    15                 /* Access reg. starting at position 8 */
+  { 4, 8, S390_OPERAND_AR },
+#define A_12   16                 /* Access reg. starting at position 12 */
+  { 4, 12, S390_OPERAND_AR },
+#define A_24   17                 /* Access reg. starting at position 24 */
+  { 4, 24, S390_OPERAND_AR },
+#define A_28   18                 /* Access reg. starting at position 28 */
+  { 4, 28, S390_OPERAND_AR },
+
+#define C_8    19                 /* Control reg. starting at position 8 */
+  { 4, 8, S390_OPERAND_CR },
+#define C_12   20                 /* Control reg. starting at position 12 */
+  { 4, 12, S390_OPERAND_CR },
+
+#define B_16   21                 /* Base register starting at position 16 */
+  { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR },
+#define B_32   22                 /* Base register starting at position 32 */
+  { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR },
+
+#define X_12   23                 /* Index register starting at position 12 */
+  { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR },
+
+#define D_20   24                 /* Displacement starting at position 20 */
+  { 12, 20, S390_OPERAND_DISP },
+#define D_36   25                 /* Displacement starting at position 36 */
+  { 12, 36, S390_OPERAND_DISP },
+#define D20_20 26		  /* 20 bit displacement starting at 20 */
+  { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED },
+
+#define L4_8   27                 /* 4 bit length starting at position 8 */
+  { 4, 8, S390_OPERAND_LENGTH },
+#define L4_12  28                 /* 4 bit length starting at position 12 */
+  { 4, 12, S390_OPERAND_LENGTH },
+#define L8_8   29                 /* 8 bit length starting at position 8 */
+  { 8, 8, S390_OPERAND_LENGTH },
+
+#define U4_8   30                 /* 4 bit unsigned value starting at 8 */
+  { 4, 8, 0 },
+#define U4_12  31                 /* 4 bit unsigned value starting at 12 */
+  { 4, 12, 0 },
+#define U4_16  32                 /* 4 bit unsigned value starting at 16 */
+  { 4, 16, 0 },
+#define U4_20  33                 /* 4 bit unsigned value starting at 20 */
+  { 4, 20, 0 },
+#define U8_8   34                 /* 8 bit unsigned value starting at 8 */
+  { 8, 8, 0 },
+#define U8_16  35                 /* 8 bit unsigned value starting at 16 */
+  { 8, 16, 0 },
+#define I16_16 36                 /* 16 bit signed value starting at 16 */
+  { 16, 16, S390_OPERAND_SIGNED },
+#define U16_16 37                 /* 16 bit unsigned value starting at 16 */
+  { 16, 16, 0 },
+#define J16_16 38                 /* PC relative jump offset at 16 */
+  { 16, 16, S390_OPERAND_PCREL },
+#define J32_16 39                 /* PC relative long offset at 16 */
+  { 32, 16, S390_OPERAND_PCREL },
+#define I32_16 40		  /* 32 bit signed value starting at 16 */
+  { 32, 16, S390_OPERAND_SIGNED },
+#define U32_16 41		  /* 32 bit unsigned value starting at 16 */
+  { 32, 16, 0 },
+#define M_16   42                 /* 4 bit optional mask starting at 16 */
+  { 4, 16, S390_OPERAND_OPTIONAL },
+#define RO_28  43                 /* optional GPR starting at position 28 */
+  { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) },
+
+/* QEMU-ADD: */
+#define M4_12 44                  /* 4-bit condition-code starting at 12 */
+  { 4, 12, S390_OPERAND_CCODE },
+#define M4_32 45                  /* 4-bit condition-code starting at 32 */
+  { 4, 32, S390_OPERAND_CCODE },
+#define I8_32 46                  /* 8 bit signed value starting at 32 */
+  { 8, 32, S390_OPERAND_SIGNED },
+/* QEMU-END */
+};
+
+
+/* Macros used to form opcodes.  */
+
+/* 8/16/48 bit opcodes.  */
+#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 }
+#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \
+                  (x >> 16) & 255, (x >> 8) & 255, x & 255}
+
+/* The new format of the INSTR_x_y and MASK_x_y defines is based
+   on the following rules:
+   1) the middle part of the definition (x in INSTR_x_y) is the official
+      names of the instruction format that you can find in the principals
+      of operation.
+   2) the last part of the definition (y in INSTR_x_y) gives you an idea
+      which operands the binary represenation of the instruction has.
+      The meanings of the letters in y are:
+      a - access register
+      c - control register
+      d - displacement, 12 bit
+      f - floating pointer register
+      i - signed integer, 4, 8, 16 or 32 bit
+      l - length, 4 or 8 bit
+      p - pc relative
+      r - general purpose register
+      u - unsigned integer, 4, 8, 16 or 32 bit
+      m - mode field, 4 bit
+      0 - operand skipped.
+      The order of the letters reflects the layout of the format in
+      storage and not the order of the paramaters of the instructions.
+      The use of the letters is not a 100% match with the PoP but it is
+      quite close.
+
+      For example the instruction "mvo" is defined in the PoP as follows:
+
+      MVO  D1(L1,B1),D2(L2,B2)   [SS]
+
+      --------------------------------------
+      | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 |
+      --------------------------------------
+       0      8    12   16   20   32   36
+
+      The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD.  */
+
+#define INSTR_E          2, { 0,0,0,0,0,0 }                    /* e.g. pr    */
+#define INSTR_RIE_RRP    6, { R_8,R_12,J16_16,0,0,0 }          /* e.g. brxhg */
+#define INSTR_RIL_0P     6, { J32_16,0,0,0,0 }                 /* e.g. jg    */
+#define INSTR_RIL_RP     6, { R_8,J32_16,0,0,0,0 }             /* e.g. brasl */
+#define INSTR_RIL_UP     6, { U4_8,J32_16,0,0,0,0 }            /* e.g. brcl  */
+#define INSTR_RIL_RI     6, { R_8,I32_16,0,0,0,0 }             /* e.g. afi   */
+#define INSTR_RIL_RU     6, { R_8,U32_16,0,0,0,0 }             /* e.g. alfi  */
+#define INSTR_RI_0P      4, { J16_16,0,0,0,0,0 }               /* e.g. j     */
+#define INSTR_RI_RI      4, { R_8,I16_16,0,0,0,0 }             /* e.g. ahi   */
+#define INSTR_RI_RP      4, { R_8,J16_16,0,0,0,0 }             /* e.g. brct  */
+#define INSTR_RI_RU      4, { R_8,U16_16,0,0,0,0 }             /* e.g. tml   */
+#define INSTR_RI_UP      4, { U4_8,J16_16,0,0,0,0 }            /* e.g. brc   */
+#define INSTR_RRE_00     4, { 0,0,0,0,0,0 }                    /* e.g. palb  */
+#define INSTR_RRE_0R     4, { R_28,0,0,0,0,0 }                 /* e.g. tb    */
+#define INSTR_RRE_AA     4, { A_24,A_28,0,0,0,0 }              /* e.g. cpya  */
+#define INSTR_RRE_AR     4, { A_24,R_28,0,0,0,0 }              /* e.g. sar   */
+#define INSTR_RRE_F0     4, { F_24,0,0,0,0,0 }                 /* e.g. sqer  */
+#define INSTR_RRE_FF     4, { F_24,F_28,0,0,0,0 }              /* e.g. debr  */
+#define INSTR_RRE_R0     4, { R_24,0,0,0,0,0 }                 /* e.g. ipm   */
+#define INSTR_RRE_RA     4, { R_24,A_28,0,0,0,0 }              /* e.g. ear   */
+#define INSTR_RRE_RF     4, { R_24,F_28,0,0,0,0 }              /* e.g. cefbr */
+#define INSTR_RRE_RR     4, { R_24,R_28,0,0,0,0 }              /* e.g. lura  */
+#define INSTR_RRE_FR     4, { F_24,R_28,0,0,0,0 }              /* e.g. ldgr  */
+/* Actually efpc and sfpc do not take an optional operand.
+   This is just a workaround for existing code e.g. glibc.  */
+#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 }             /* efpc, sfpc */
+#define INSTR_RRF_F0FF   4, { F_16,F_24,F_28,0,0,0 }           /* e.g. madbr */
+#define INSTR_RRF_F0FF2  4, { F_24,F_16,F_28,0,0,0 }           /* e.g. cpsdr */
+#define INSTR_RRF_F0FR   4, { F_24,F_16,R_28,0,0,0 }           /* e.g. iedtr */
+#define INSTR_RRF_FUFF   4, { F_24,F_16,F_28,U4_20,0,0 }       /* e.g. didbr */
+#define INSTR_RRF_RURR   4, { R_24,R_28,R_16,U4_20,0,0 }       /* e.g. .insn */
+#define INSTR_RRF_R0RR   4, { R_24,R_28,R_16,0,0,0 }           /* e.g. idte  */
+#define INSTR_RRF_U0FF   4, { F_24,U4_16,F_28,0,0,0 }          /* e.g. fixr  */
+#define INSTR_RRF_U0RF   4, { R_24,U4_16,F_28,0,0,0 }          /* e.g. cfebr */
+#define INSTR_RRF_UUFF   4, { F_24,U4_16,F_28,U4_20,0,0 }      /* e.g. fidtr */
+#define INSTR_RRF_0UFF   4, { F_24,F_28,U4_20,0,0,0 }          /* e.g. ldetr */
+#define INSTR_RRF_FFFU   4, { F_24,F_16,F_28,U4_20,0,0 }       /* e.g. qadtr */
+#define INSTR_RRF_M0RR   4, { R_24,R_28,M_16,0,0,0 }           /* e.g. sske  */
+#define INSTR_RR_0R      2, { R_12, 0,0,0,0,0 }                /* e.g. br    */
+#define INSTR_RR_FF      2, { F_8,F_12,0,0,0,0 }               /* e.g. adr   */
+#define INSTR_RR_R0      2, { R_8, 0,0,0,0,0 }                 /* e.g. spm   */
+#define INSTR_RR_RR      2, { R_8,R_12,0,0,0,0 }               /* e.g. lr    */
+#define INSTR_RR_U0      2, { U8_8, 0,0,0,0,0 }                /* e.g. svc   */
+#define INSTR_RR_UR      2, { U4_8,R_12,0,0,0,0 }              /* e.g. bcr   */
+#define INSTR_RRR_F0FF   4, { F_24,F_28,F_16,0,0,0 }           /* e.g. ddtr  */
+#define INSTR_RSE_RRRD   6, { R_8,R_12,D_20,B_16,0,0 }         /* e.g. lmh   */
+#define INSTR_RSE_CCRD   6, { C_8,C_12,D_20,B_16,0,0 }         /* e.g. lmh   */
+#define INSTR_RSE_RURD   6, { R_8,U4_12,D_20,B_16,0,0 }        /* e.g. icmh  */
+#define INSTR_RSL_R0RD   6, { R_8,D_20,B_16,0,0,0 }            /* e.g. tp    */
+#define INSTR_RSI_RRP    4, { R_8,R_12,J16_16,0,0,0 }          /* e.g. brxh  */
+#define INSTR_RSY_RRRD   6, { R_8,R_12,D20_20,B_16,0,0 }       /* e.g. stmy  */
+#define INSTR_RSY_RURD   6, { R_8,U4_12,D20_20,B_16,0,0 }      /* e.g. icmh  */
+#define INSTR_RSY_AARD   6, { A_8,A_12,D20_20,B_16,0,0 }       /* e.g. lamy  */
+#define INSTR_RSY_CCRD   6, { C_8,C_12,D20_20,B_16,0,0 }       /* e.g. lamy  */
+#define INSTR_RS_AARD    4, { A_8,A_12,D_20,B_16,0,0 }         /* e.g. lam   */
+#define INSTR_RS_CCRD    4, { C_8,C_12,D_20,B_16,0,0 }         /* e.g. lctl  */
+#define INSTR_RS_R0RD    4, { R_8,D_20,B_16,0,0,0 }            /* e.g. sll   */
+#define INSTR_RS_RRRD    4, { R_8,R_12,D_20,B_16,0,0 }         /* e.g. cs    */
+#define INSTR_RS_RURD    4, { R_8,U4_12,D_20,B_16,0,0 }        /* e.g. icm   */
+#define INSTR_RXE_FRRD   6, { F_8,D_20,X_12,B_16,0,0 }         /* e.g. axbr  */
+#define INSTR_RXE_RRRD   6, { R_8,D_20,X_12,B_16,0,0 }         /* e.g. lg    */
+#define INSTR_RXF_FRRDF  6, { F_32,F_8,D_20,X_12,B_16,0 }      /* e.g. madb  */
+#define INSTR_RXF_RRRDR  6, { R_32,R_8,D_20,X_12,B_16,0 }      /* e.g. .insn */
+#define INSTR_RXY_RRRD   6, { R_8,D20_20,X_12,B_16,0,0 }       /* e.g. ly    */
+#define INSTR_RXY_FRRD   6, { F_8,D20_20,X_12,B_16,0,0 }       /* e.g. ley   */
+#define INSTR_RX_0RRD    4, { D_20,X_12,B_16,0,0,0 }           /* e.g. be    */
+#define INSTR_RX_FRRD    4, { F_8,D_20,X_12,B_16,0,0 }         /* e.g. ae    */
+#define INSTR_RX_RRRD    4, { R_8,D_20,X_12,B_16,0,0 }         /* e.g. l     */
+#define INSTR_RX_URRD    4, { U4_8,D_20,X_12,B_16,0,0 }        /* e.g. bc    */
+#define INSTR_SI_URD     4, { D_20,B_16,U8_8,0,0,0 }           /* e.g. cli   */
+#define INSTR_SIY_URD    6, { D20_20,B_16,U8_8,0,0,0 }         /* e.g. tmy   */
+#define INSTR_SSE_RDRD   6, { D_20,B_16,D_36,B_32,0,0 }        /* e.g. mvsdk */
+#define INSTR_SS_L0RDRD  6, { D_20,L8_8,B_16,D_36,B_32,0     } /* e.g. mvc   */
+#define INSTR_SS_L2RDRD  6, { D_20,B_16,D_36,L8_8,B_32,0     } /* e.g. pka   */
+#define INSTR_SS_LIRDRD  6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp   */
+#define INSTR_SS_LLRDRD  6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack  */
+#define INSTR_SS_RRRDRD  6, { D_20,R_8,B_16,D_36,B_32,R_12 }   /* e.g. mvck  */
+#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 }   /* e.g. plo   */
+#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 }   /* e.g. lmd   */
+#define INSTR_S_00       4, { 0,0,0,0,0,0 }                    /* e.g. hsch  */
+#define INSTR_S_RD       4, { D_20,B_16,0,0,0,0 }              /* e.g. lpsw  */
+#define INSTR_SSF_RRDRD  6, { D_20,B_16,D_36,B_32,R_8,0 }      /* e.g. mvcos */
+
+#define MASK_E           { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIE_RRP     { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RIL_0P      { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RP      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_UP      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RI      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RU      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_0P       { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RI       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RP       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RU       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_UP       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRE_00      { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define MASK_RRE_0R      { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 }
+#define MASK_RRE_AA      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_AR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_F0      { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 }
+#define MASK_RRE_FF      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_R0      { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 }
+#define MASK_RRE_RA      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RF      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_FR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RR_OPT  { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FF2   { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FR    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_FUFF    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_RURR    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_R0RR    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_U0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_U0RF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_UUFF    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_0UFF    { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 }
+#define MASK_RRF_FFFU    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_M0RR    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RR_0R       { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_FF       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_R0       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_RR       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_U0       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_UR       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRR_F0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RSE_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSE_CCRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSE_RURD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSL_R0RD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSI_RRP     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_AARD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_CCRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_R0RD     { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_RRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_RURD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RSY_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_RURD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_AARD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_CCRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXE_FRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXE_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXF_FRRDF   { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXF_RRRDR   { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXY_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXY_FRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RX_0RRD     { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_FRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_RRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_URRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SI_URD      { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SIY_URD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_SSE_RDRD    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_L0RDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_L2RDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_LIRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_LLRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD2  { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD3  { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_S_00        { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define MASK_S_RD        { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SSF_RRDRD   { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+
+/* QEMU-ADD: */
+#define INSTR_RIE_MRRP   6, { M4_32,R_8,R_12,J16_16,0,0 }	/* e.g. crj */
+#define MASK_RIE_MRRP    { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff }
+
+#define INSTR_RIE_MRIP   6, { M4_12,R_8,I8_32,J16_16,0,0 }      /* e.g. cij */
+#define MASK_RIE_MRIP    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+/* QEMU-END */
+
+/* The opcode formats table (blueprints for .insn pseudo mnemonic).  */
+
+static const struct s390_opcode s390_opformats[] =
+  {
+  { "e",	OP8(0x00LL),	MASK_E,		INSTR_E,	3, 0 },
+  { "ri",	OP8(0x00LL),	MASK_RI_RI,	INSTR_RI_RI,	3, 0 },
+  { "rie",	OP8(0x00LL),	MASK_RIE_RRP,	INSTR_RIE_RRP,	3, 0 },
+  { "ril",	OP8(0x00LL),	MASK_RIL_RP,	INSTR_RIL_RP,	3, 0 },
+  { "rilu",	OP8(0x00LL),	MASK_RIL_RU,	INSTR_RIL_RU,	3, 0 },
+  { "rr",	OP8(0x00LL),	MASK_RR_RR,	INSTR_RR_RR,	3, 0 },
+  { "rre",	OP8(0x00LL),	MASK_RRE_RR,	INSTR_RRE_RR,	3, 0 },
+  { "rrf",	OP8(0x00LL),	MASK_RRF_RURR,	INSTR_RRF_RURR,	3, 0 },
+  { "rs",	OP8(0x00LL),	MASK_RS_RRRD,	INSTR_RS_RRRD,	3, 0 },
+  { "rse",	OP8(0x00LL),	MASK_RSE_RRRD,	INSTR_RSE_RRRD,	3, 0 },
+  { "rsi",	OP8(0x00LL),	MASK_RSI_RRP,	INSTR_RSI_RRP,	3, 0 },
+  { "rsy",	OP8(0x00LL),	MASK_RSY_RRRD,	INSTR_RSY_RRRD,	3, 3 },
+  { "rx",	OP8(0x00LL),	MASK_RX_RRRD,	INSTR_RX_RRRD,	3, 0 },
+  { "rxe",	OP8(0x00LL),	MASK_RXE_RRRD,	INSTR_RXE_RRRD,	3, 0 },
+  { "rxf",	OP8(0x00LL),	MASK_RXF_RRRDR,	INSTR_RXF_RRRDR,3, 0 },
+  { "rxy",	OP8(0x00LL),	MASK_RXY_RRRD,	INSTR_RXY_RRRD,	3, 3 },
+  { "s",	OP8(0x00LL),	MASK_S_RD,	INSTR_S_RD,	3, 0 },
+  { "si",	OP8(0x00LL),	MASK_SI_URD,	INSTR_SI_URD,	3, 0 },
+  { "siy",	OP8(0x00LL),	MASK_SIY_URD,	INSTR_SIY_URD,	3, 3 },
+  { "ss",	OP8(0x00LL),	MASK_SS_RRRDRD,	INSTR_SS_RRRDRD,3, 0 },
+  { "sse",	OP8(0x00LL),	MASK_SSE_RDRD,	INSTR_SSE_RDRD,	3, 0 },
+  { "ssf",	OP8(0x00LL),	MASK_SSF_RRDRD,	INSTR_SSF_RRDRD,3, 0 },
+};
+
+static const int s390_num_opformats =
+  sizeof (s390_opformats) / sizeof (s390_opformats[0]);
+
+/* include "s390-opc.tab" generated from opcodes/s390-opc.txt rev 1.17 */
+/* The opcode table. This file was generated by s390-mkopc.
+
+   The format of the opcode table is:
+
+   NAME	     OPCODE	MASK	OPERANDS
+
+   Name is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches.  */
+
+static const struct s390_opcode s390_opcodes[] =
+  {
+  { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0},
+  { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2},
+  { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0},
+  { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
+  { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
+  { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0},
+  { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
+  { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
+  { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3},
+  { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0},
+  { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3},
+  { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2},
+  { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3},
+  { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2},
+  { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3},
+  { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2},
+  { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0},
+  { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2},
+  { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
+  { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
+  { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4},
+  { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+/* QEMU-ADD: */
+  { "msfi",  OP16(0xc201ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6},
+  { "msgfi", OP16(0xc200ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6},
+/* QEMU-END */
+  { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2},
+  { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2},
+  { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2},
+  { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4},
+  { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2},
+  { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3},
+  { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3},
+  { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
+  { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
+  { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5},
+  { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5},
+  { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5},
+  { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5},
+  { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5},
+  { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5},
+  { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0},
+  { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5},
+  { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0},
+  { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5},
+  { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0},
+  { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0},
+  { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5},
+  { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5},
+  { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2},
+  { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2},
+  { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4},
+  { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4},
+  { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0},
+  { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0},
+  { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0},
+  { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0},
+  { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0},
+  { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0},
+  { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2},
+  { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0},
+  { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0},
+  { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0},
+  { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0},
+  { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0},
+  { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0},
+  { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0},
+  { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0},
+  { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0},
+  { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0},
+  { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0},
+  { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0},
+  { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2},
+  { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2},
+  { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2},
+  { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2},
+  { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5},
+  { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0},
+  { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0},
+  { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0},
+
+/* QEMU-ADD: */
+  { "crj",   OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+  { "cgrj",  OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+  { "clrj",  OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+  { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+
+  { "cij",   OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+  { "cgij",  OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+  { "clij",  OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+  { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+
+  { "lrl",   OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+  { "lgrl",  OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+  { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+/* QEMU-END */
+};
+
+static const int s390_num_opcodes =
+  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);
diff --git a/qemu-0.15.x/s390.ld b/qemu-0.15.x/s390.ld
new file mode 100644
index 0000000..a9c5370
--- /dev/null
+++ b/qemu-0.15.x/s390.ld
@@ -0,0 +1,201 @@
+OUTPUT_FORMAT("elf32-s390", "elf32-s390",
+	      "elf32-s390")
+OUTPUT_ARCH(s390:31-bit)
+ENTRY(_start)
+/* __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.dyn        :
+    {
+      *(.rel.init)
+      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+      *(.rel.fini)
+      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+      *(.rel.ctors)
+      *(.rel.dtors)
+      *(.rel.got)
+      *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+      *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+      *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+      *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+    }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+      *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+      *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+      *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x07070707
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x07070707
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x07070707
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x1000) + (. & (0x1000 - 1));
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .);
+    PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .);
+    PROVIDE (___sbss_end = .);
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/qemu-0.15.x/savevm.c b/qemu-0.15.x/savevm.c
new file mode 100644
index 0000000..79db4cb
--- /dev/null
+++ b/qemu-0.15.x/savevm.c
@@ -0,0 +1,2179 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef CONFIG_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+#include <linux/rtc.h>
+#endif
+#endif
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>
+#include <sys/timeb.h>
+#include <mmsystem.h>
+#define getopt_long_only getopt_long
+#define memalign(align, size) malloc(size)
+#endif
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "hw/qdev.h"
+#include "net.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "audio/audio.h"
+#include "migration.h"
+#include "qemu_socket.h"
+#include "qemu-queue.h"
+#include "cpus.h"
+
+#define SELF_ANNOUNCE_ROUNDS 5
+
+#ifndef ETH_P_RARP
+#define ETH_P_RARP 0x8035
+#endif
+#define ARP_HTYPE_ETH 0x0001
+#define ARP_PTYPE_IP 0x0800
+#define ARP_OP_REQUEST_REV 0x3
+
+static int announce_self_create(uint8_t *buf,
+				uint8_t *mac_addr)
+{
+    /* Ethernet header. */
+    memset(buf, 0xff, 6);         /* destination MAC addr */
+    memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
+    *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
+
+    /* RARP header. */
+    *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
+    *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
+    *(buf + 18) = 6; /* hardware addr length (ethernet) */
+    *(buf + 19) = 4; /* protocol addr length (IPv4) */
+    *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
+    memcpy(buf + 22, mac_addr, 6); /* source hw addr */
+    memset(buf + 28, 0x00, 4);     /* source protocol addr */
+    memcpy(buf + 32, mac_addr, 6); /* target hw addr */
+    memset(buf + 38, 0x00, 4);     /* target protocol addr */
+
+    /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
+    memset(buf + 42, 0x00, 18);
+
+    return 60; /* len (FCS will be added by hardware) */
+}
+
+static void qemu_announce_self_iter(NICState *nic, void *opaque)
+{
+    uint8_t buf[60];
+    int len;
+
+    len = announce_self_create(buf, nic->conf->macaddr.a);
+
+    qemu_send_packet_raw(&nic->nc, buf, len);
+}
+
+
+static void qemu_announce_self_once(void *opaque)
+{
+    static int count = SELF_ANNOUNCE_ROUNDS;
+    QEMUTimer *timer = *(QEMUTimer **)opaque;
+
+    qemu_foreach_nic(qemu_announce_self_iter, NULL);
+
+    if (--count) {
+        /* delay 50ms, 150ms, 250ms, ... */
+        qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) +
+                       50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
+    } else {
+	    qemu_del_timer(timer);
+	    qemu_free_timer(timer);
+    }
+}
+
+void qemu_announce_self(void)
+{
+	static QEMUTimer *timer;
+	timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer);
+	qemu_announce_self_once(&timer);
+}
+
+/***********************************************************/
+/* savevm/loadvm support */
+
+#define IO_BUF_SIZE 32768
+
+struct QEMUFile {
+    QEMUFilePutBufferFunc *put_buffer;
+    QEMUFileGetBufferFunc *get_buffer;
+    QEMUFileCloseFunc *close;
+    QEMUFileRateLimit *rate_limit;
+    QEMUFileSetRateLimit *set_rate_limit;
+    QEMUFileGetRateLimit *get_rate_limit;
+    void *opaque;
+    int is_write;
+
+    int64_t buf_offset; /* start of buffer when writing, end of buffer
+                           when reading */
+    int buf_index;
+    int buf_size; /* 0 when writing */
+    uint8_t buf[IO_BUF_SIZE];
+
+    int has_error;
+};
+
+typedef struct QEMUFileStdio
+{
+    FILE *stdio_file;
+    QEMUFile *file;
+} QEMUFileStdio;
+
+typedef struct QEMUFileSocket
+{
+    int fd;
+    QEMUFile *file;
+} QEMUFileSocket;
+
+static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileSocket *s = opaque;
+    ssize_t len;
+
+    do {
+        len = qemu_recv(s->fd, buf, size, 0);
+    } while (len == -1 && socket_error() == EINTR);
+
+    if (len == -1)
+        len = -socket_error();
+
+    return len;
+}
+
+static int socket_close(void *opaque)
+{
+    QEMUFileSocket *s = opaque;
+    qemu_free(s);
+    return 0;
+}
+
+static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    return fwrite(buf, 1, size, s->stdio_file);
+}
+
+static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    FILE *fp = s->stdio_file;
+    int bytes;
+
+    do {
+        clearerr(fp);
+        bytes = fread(buf, 1, size, fp);
+    } while ((bytes == 0) && ferror(fp) && (errno == EINTR));
+    return bytes;
+}
+
+static int stdio_pclose(void *opaque)
+{
+    QEMUFileStdio *s = opaque;
+    int ret;
+    ret = pclose(s->stdio_file);
+    qemu_free(s);
+    return ret;
+}
+
+static int stdio_fclose(void *opaque)
+{
+    QEMUFileStdio *s = opaque;
+    fclose(s->stdio_file);
+    qemu_free(s);
+    return 0;
+}
+
+QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
+{
+    QEMUFileStdio *s;
+
+    if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
+        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
+        return NULL;
+    }
+
+    s = qemu_mallocz(sizeof(QEMUFileStdio));
+
+    s->stdio_file = stdio_file;
+
+    if(mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, 
+				 NULL, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, 
+				 NULL, NULL, NULL);
+    }
+    return s->file;
+}
+
+QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
+{
+    FILE *popen_file;
+
+    popen_file = popen(command, mode);
+    if(popen_file == NULL) {
+        return NULL;
+    }
+
+    return qemu_popen(popen_file, mode);
+}
+
+int qemu_stdio_fd(QEMUFile *f)
+{
+    QEMUFileStdio *p;
+    int fd;
+
+    p = (QEMUFileStdio *)f->opaque;
+    fd = fileno(p->stdio_file);
+
+    return fd;
+}
+
+QEMUFile *qemu_fdopen(int fd, const char *mode)
+{
+    QEMUFileStdio *s;
+
+    if (mode == NULL ||
+	(mode[0] != 'r' && mode[0] != 'w') ||
+	mode[1] != 'b' || mode[2] != 0) {
+        fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
+        return NULL;
+    }
+
+    s = qemu_mallocz(sizeof(QEMUFileStdio));
+    s->stdio_file = fdopen(fd, mode);
+    if (!s->stdio_file)
+        goto fail;
+
+    if(mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, 
+				 NULL, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, 
+				 NULL, NULL, NULL);
+    }
+    return s->file;
+
+fail:
+    qemu_free(s);
+    return NULL;
+}
+
+QEMUFile *qemu_fopen_socket(int fd)
+{
+    QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
+
+    s->fd = fd;
+    s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, 
+			     NULL, NULL, NULL);
+    return s->file;
+}
+
+static int file_put_buffer(void *opaque, const uint8_t *buf,
+                            int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    fseek(s->stdio_file, pos, SEEK_SET);
+    return fwrite(buf, 1, size, s->stdio_file);
+}
+
+static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    fseek(s->stdio_file, pos, SEEK_SET);
+    return fread(buf, 1, size, s->stdio_file);
+}
+
+QEMUFile *qemu_fopen(const char *filename, const char *mode)
+{
+    QEMUFileStdio *s;
+
+    if (mode == NULL ||
+	(mode[0] != 'r' && mode[0] != 'w') ||
+	mode[1] != 'b' || mode[2] != 0) {
+        fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
+        return NULL;
+    }
+
+    s = qemu_mallocz(sizeof(QEMUFileStdio));
+
+    s->stdio_file = fopen(filename, mode);
+    if (!s->stdio_file)
+        goto fail;
+    
+    if(mode[0] == 'w') {
+        s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, 
+				 NULL, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, 
+			       NULL, NULL, NULL);
+    }
+    return s->file;
+fail:
+    qemu_free(s);
+    return NULL;
+}
+
+static int block_put_buffer(void *opaque, const uint8_t *buf,
+                           int64_t pos, int size)
+{
+    bdrv_save_vmstate(opaque, buf, pos, size);
+    return size;
+}
+
+static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    return bdrv_load_vmstate(opaque, buf, pos, size);
+}
+
+static int bdrv_fclose(void *opaque)
+{
+    return 0;
+}
+
+static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
+{
+    if (is_writable)
+        return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, 
+			      NULL, NULL, NULL);
+    return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
+}
+
+QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit,
+                         QEMUFileGetRateLimit *get_rate_limit)
+{
+    QEMUFile *f;
+
+    f = qemu_mallocz(sizeof(QEMUFile));
+
+    f->opaque = opaque;
+    f->put_buffer = put_buffer;
+    f->get_buffer = get_buffer;
+    f->close = close;
+    f->rate_limit = rate_limit;
+    f->set_rate_limit = set_rate_limit;
+    f->get_rate_limit = get_rate_limit;
+    f->is_write = 0;
+
+    return f;
+}
+
+int qemu_file_has_error(QEMUFile *f)
+{
+    return f->has_error;
+}
+
+void qemu_file_set_error(QEMUFile *f)
+{
+    f->has_error = 1;
+}
+
+void qemu_fflush(QEMUFile *f)
+{
+    if (!f->put_buffer)
+        return;
+
+    if (f->is_write && f->buf_index > 0) {
+        int len;
+
+        len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
+        if (len > 0)
+            f->buf_offset += f->buf_index;
+        else
+            f->has_error = 1;
+        f->buf_index = 0;
+    }
+}
+
+static void qemu_fill_buffer(QEMUFile *f)
+{
+    int len;
+
+    if (!f->get_buffer)
+        return;
+
+    if (f->is_write)
+        abort();
+
+    len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+    if (len > 0) {
+        f->buf_index = 0;
+        f->buf_size = len;
+        f->buf_offset += len;
+    } else if (len != -EAGAIN)
+        f->has_error = 1;
+}
+
+int qemu_fclose(QEMUFile *f)
+{
+    int ret = 0;
+    qemu_fflush(f);
+    if (f->close)
+        ret = f->close(f->opaque);
+    qemu_free(f);
+    return ret;
+}
+
+void qemu_file_put_notify(QEMUFile *f)
+{
+    f->put_buffer(f->opaque, NULL, 0, 0);
+}
+
+void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
+{
+    int l;
+
+    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+        fprintf(stderr,
+                "Attempted to write to buffer while read buffer is not empty\n");
+        abort();
+    }
+
+    while (!f->has_error && size > 0) {
+        l = IO_BUF_SIZE - f->buf_index;
+        if (l > size)
+            l = size;
+        memcpy(f->buf + f->buf_index, buf, l);
+        f->is_write = 1;
+        f->buf_index += l;
+        buf += l;
+        size -= l;
+        if (f->buf_index >= IO_BUF_SIZE)
+            qemu_fflush(f);
+    }
+}
+
+void qemu_put_byte(QEMUFile *f, int v)
+{
+    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+        fprintf(stderr,
+                "Attempted to write to buffer while read buffer is not empty\n");
+        abort();
+    }
+
+    f->buf[f->buf_index++] = v;
+    f->is_write = 1;
+    if (f->buf_index >= IO_BUF_SIZE)
+        qemu_fflush(f);
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+{
+    int size, l;
+
+    if (f->is_write)
+        abort();
+
+    size = size1;
+    while (size > 0) {
+        l = f->buf_size - f->buf_index;
+        if (l == 0) {
+            qemu_fill_buffer(f);
+            l = f->buf_size - f->buf_index;
+            if (l == 0)
+                break;
+        }
+        if (l > size)
+            l = size;
+        memcpy(buf, f->buf + f->buf_index, l);
+        f->buf_index += l;
+        buf += l;
+        size -= l;
+    }
+    return size1 - size;
+}
+
+static int qemu_peek_byte(QEMUFile *f)
+{
+    if (f->is_write)
+        abort();
+
+    if (f->buf_index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        if (f->buf_index >= f->buf_size)
+            return 0;
+    }
+    return f->buf[f->buf_index];
+}
+
+int qemu_get_byte(QEMUFile *f)
+{
+    if (f->is_write)
+        abort();
+
+    if (f->buf_index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        if (f->buf_index >= f->buf_size)
+            return 0;
+    }
+    return f->buf[f->buf_index++];
+}
+
+int64_t qemu_ftell(QEMUFile *f)
+{
+    return f->buf_offset - f->buf_size + f->buf_index;
+}
+
+int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
+{
+    if (whence == SEEK_SET) {
+        /* nothing to do */
+    } else if (whence == SEEK_CUR) {
+        pos += qemu_ftell(f);
+    } else {
+        /* SEEK_END not supported */
+        return -1;
+    }
+    if (f->put_buffer) {
+        qemu_fflush(f);
+        f->buf_offset = pos;
+    } else {
+        f->buf_offset = pos;
+        f->buf_index = 0;
+        f->buf_size = 0;
+    }
+    return pos;
+}
+
+int qemu_file_rate_limit(QEMUFile *f)
+{
+    if (f->rate_limit)
+        return f->rate_limit(f->opaque);
+
+    return 0;
+}
+
+int64_t qemu_file_get_rate_limit(QEMUFile *f)
+{
+    if (f->get_rate_limit)
+        return f->get_rate_limit(f->opaque);
+
+    return 0;
+}
+
+int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
+{
+    /* any failed or completed migration keeps its state to allow probing of
+     * migration data, but has no associated file anymore */
+    if (f && f->set_rate_limit)
+        return f->set_rate_limit(f->opaque, new_rate);
+
+    return 0;
+}
+
+void qemu_put_be16(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, v >> 8);
+    qemu_put_byte(f, v);
+}
+
+void qemu_put_be32(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, v >> 24);
+    qemu_put_byte(f, v >> 16);
+    qemu_put_byte(f, v >> 8);
+    qemu_put_byte(f, v);
+}
+
+void qemu_put_be64(QEMUFile *f, uint64_t v)
+{
+    qemu_put_be32(f, v >> 32);
+    qemu_put_be32(f, v);
+}
+
+unsigned int qemu_get_be16(QEMUFile *f)
+{
+    unsigned int v;
+    v = qemu_get_byte(f) << 8;
+    v |= qemu_get_byte(f);
+    return v;
+}
+
+unsigned int qemu_get_be32(QEMUFile *f)
+{
+    unsigned int v;
+    v = qemu_get_byte(f) << 24;
+    v |= qemu_get_byte(f) << 16;
+    v |= qemu_get_byte(f) << 8;
+    v |= qemu_get_byte(f);
+    return v;
+}
+
+uint64_t qemu_get_be64(QEMUFile *f)
+{
+    uint64_t v;
+    v = (uint64_t)qemu_get_be32(f) << 32;
+    v |= qemu_get_be32(f);
+    return v;
+}
+
+/* bool */
+
+static int get_bool(QEMUFile *f, void *pv, size_t size)
+{
+    bool *v = pv;
+    *v = qemu_get_byte(f);
+    return 0;
+}
+
+static void put_bool(QEMUFile *f, void *pv, size_t size)
+{
+    bool *v = pv;
+    qemu_put_byte(f, *v);
+}
+
+const VMStateInfo vmstate_info_bool = {
+    .name = "bool",
+    .get  = get_bool,
+    .put  = put_bool,
+};
+
+/* 8 bit int */
+
+static int get_int8(QEMUFile *f, void *pv, size_t size)
+{
+    int8_t *v = pv;
+    qemu_get_s8s(f, v);
+    return 0;
+}
+
+static void put_int8(QEMUFile *f, void *pv, size_t size)
+{
+    int8_t *v = pv;
+    qemu_put_s8s(f, v);
+}
+
+const VMStateInfo vmstate_info_int8 = {
+    .name = "int8",
+    .get  = get_int8,
+    .put  = put_int8,
+};
+
+/* 16 bit int */
+
+static int get_int16(QEMUFile *f, void *pv, size_t size)
+{
+    int16_t *v = pv;
+    qemu_get_sbe16s(f, v);
+    return 0;
+}
+
+static void put_int16(QEMUFile *f, void *pv, size_t size)
+{
+    int16_t *v = pv;
+    qemu_put_sbe16s(f, v);
+}
+
+const VMStateInfo vmstate_info_int16 = {
+    .name = "int16",
+    .get  = get_int16,
+    .put  = put_int16,
+};
+
+/* 32 bit int */
+
+static int get_int32(QEMUFile *f, void *pv, size_t size)
+{
+    int32_t *v = pv;
+    qemu_get_sbe32s(f, v);
+    return 0;
+}
+
+static void put_int32(QEMUFile *f, void *pv, size_t size)
+{
+    int32_t *v = pv;
+    qemu_put_sbe32s(f, v);
+}
+
+const VMStateInfo vmstate_info_int32 = {
+    .name = "int32",
+    .get  = get_int32,
+    .put  = put_int32,
+};
+
+/* 32 bit int. See that the received value is the same than the one
+   in the field */
+
+static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
+{
+    int32_t *v = pv;
+    int32_t v2;
+    qemu_get_sbe32s(f, &v2);
+
+    if (*v == v2)
+        return 0;
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_int32_equal = {
+    .name = "int32 equal",
+    .get  = get_int32_equal,
+    .put  = put_int32,
+};
+
+/* 32 bit int. See that the received value is the less or the same
+   than the one in the field */
+
+static int get_int32_le(QEMUFile *f, void *pv, size_t size)
+{
+    int32_t *old = pv;
+    int32_t new;
+    qemu_get_sbe32s(f, &new);
+
+    if (*old <= new)
+        return 0;
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_int32_le = {
+    .name = "int32 equal",
+    .get  = get_int32_le,
+    .put  = put_int32,
+};
+
+/* 64 bit int */
+
+static int get_int64(QEMUFile *f, void *pv, size_t size)
+{
+    int64_t *v = pv;
+    qemu_get_sbe64s(f, v);
+    return 0;
+}
+
+static void put_int64(QEMUFile *f, void *pv, size_t size)
+{
+    int64_t *v = pv;
+    qemu_put_sbe64s(f, v);
+}
+
+const VMStateInfo vmstate_info_int64 = {
+    .name = "int64",
+    .get  = get_int64,
+    .put  = put_int64,
+};
+
+/* 8 bit unsigned int */
+
+static int get_uint8(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t *v = pv;
+    qemu_get_8s(f, v);
+    return 0;
+}
+
+static void put_uint8(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t *v = pv;
+    qemu_put_8s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint8 = {
+    .name = "uint8",
+    .get  = get_uint8,
+    .put  = put_uint8,
+};
+
+/* 16 bit unsigned int */
+
+static int get_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    uint16_t *v = pv;
+    qemu_get_be16s(f, v);
+    return 0;
+}
+
+static void put_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    uint16_t *v = pv;
+    qemu_put_be16s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint16 = {
+    .name = "uint16",
+    .get  = get_uint16,
+    .put  = put_uint16,
+};
+
+/* 32 bit unsigned int */
+
+static int get_uint32(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    qemu_get_be32s(f, v);
+    return 0;
+}
+
+static void put_uint32(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    qemu_put_be32s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint32 = {
+    .name = "uint32",
+    .get  = get_uint32,
+    .put  = put_uint32,
+};
+
+/* 32 bit uint. See that the received value is the same than the one
+   in the field */
+
+static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    uint32_t v2;
+    qemu_get_be32s(f, &v2);
+
+    if (*v == v2) {
+        return 0;
+    }
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint32_equal = {
+    .name = "uint32 equal",
+    .get  = get_uint32_equal,
+    .put  = put_uint32,
+};
+
+/* 64 bit unsigned int */
+
+static int get_uint64(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    qemu_get_be64s(f, v);
+    return 0;
+}
+
+static void put_uint64(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    qemu_put_be64s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint64 = {
+    .name = "uint64",
+    .get  = get_uint64,
+    .put  = put_uint64,
+};
+
+/* 8 bit int. See that the received value is the same than the one
+   in the field */
+
+static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t *v = pv;
+    uint8_t v2;
+    qemu_get_8s(f, &v2);
+
+    if (*v == v2)
+        return 0;
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint8_equal = {
+    .name = "uint8 equal",
+    .get  = get_uint8_equal,
+    .put  = put_uint8,
+};
+
+/* 16 bit unsigned int int. See that the received value is the same than the one
+   in the field */
+
+static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
+{
+    uint16_t *v = pv;
+    uint16_t v2;
+    qemu_get_be16s(f, &v2);
+
+    if (*v == v2)
+        return 0;
+    return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint16_equal = {
+    .name = "uint16 equal",
+    .get  = get_uint16_equal,
+    .put  = put_uint16,
+};
+
+/* timers  */
+
+static int get_timer(QEMUFile *f, void *pv, size_t size)
+{
+    QEMUTimer *v = pv;
+    qemu_get_timer(f, v);
+    return 0;
+}
+
+static void put_timer(QEMUFile *f, void *pv, size_t size)
+{
+    QEMUTimer *v = pv;
+    qemu_put_timer(f, v);
+}
+
+const VMStateInfo vmstate_info_timer = {
+    .name = "timer",
+    .get  = get_timer,
+    .put  = put_timer,
+};
+
+/* uint8_t buffers */
+
+static int get_buffer(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t *v = pv;
+    qemu_get_buffer(f, v, size);
+    return 0;
+}
+
+static void put_buffer(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t *v = pv;
+    qemu_put_buffer(f, v, size);
+}
+
+const VMStateInfo vmstate_info_buffer = {
+    .name = "buffer",
+    .get  = get_buffer,
+    .put  = put_buffer,
+};
+
+/* unused buffers: space that was used for some fields that are
+   not useful anymore */
+
+static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
+{
+    uint8_t buf[1024];
+    int block_len;
+
+    while (size > 0) {
+        block_len = MIN(sizeof(buf), size);
+        size -= block_len;
+        qemu_get_buffer(f, buf, block_len);
+    }
+   return 0;
+}
+
+static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
+{
+    static const uint8_t buf[1024];
+    int block_len;
+
+    while (size > 0) {
+        block_len = MIN(sizeof(buf), size);
+        size -= block_len;
+        qemu_put_buffer(f, buf, block_len);
+    }
+}
+
+const VMStateInfo vmstate_info_unused_buffer = {
+    .name = "unused_buffer",
+    .get  = get_unused_buffer,
+    .put  = put_unused_buffer,
+};
+
+typedef struct CompatEntry {
+    char idstr[256];
+    int instance_id;
+} CompatEntry;
+
+typedef struct SaveStateEntry {
+    QTAILQ_ENTRY(SaveStateEntry) entry;
+    char idstr[256];
+    int instance_id;
+    int alias_id;
+    int version_id;
+    int section_id;
+    SaveSetParamsHandler *set_params;
+    SaveLiveStateHandler *save_live_state;
+    SaveStateHandler *save_state;
+    LoadStateHandler *load_state;
+    const VMStateDescription *vmsd;
+    void *opaque;
+    CompatEntry *compat;
+    int no_migrate;
+} SaveStateEntry;
+
+
+static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
+    QTAILQ_HEAD_INITIALIZER(savevm_handlers);
+static int global_section_id;
+
+static int calculate_new_instance_id(const char *idstr)
+{
+    SaveStateEntry *se;
+    int instance_id = 0;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (strcmp(idstr, se->idstr) == 0
+            && instance_id <= se->instance_id) {
+            instance_id = se->instance_id + 1;
+        }
+    }
+    return instance_id;
+}
+
+static int calculate_compat_instance_id(const char *idstr)
+{
+    SaveStateEntry *se;
+    int instance_id = 0;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (!se->compat)
+            continue;
+
+        if (strcmp(idstr, se->compat->idstr) == 0
+            && instance_id <= se->compat->instance_id) {
+            instance_id = se->compat->instance_id + 1;
+        }
+    }
+    return instance_id;
+}
+
+/* TODO: Individual devices generally have very little idea about the rest
+   of the system, so instance_id should be removed/replaced.
+   Meanwhile pass -1 as instance_id if you do not already have a clearly
+   distinguishing id for all instances of your device class. */
+int register_savevm_live(DeviceState *dev,
+                         const char *idstr,
+                         int instance_id,
+                         int version_id,
+                         SaveSetParamsHandler *set_params,
+                         SaveLiveStateHandler *save_live_state,
+                         SaveStateHandler *save_state,
+                         LoadStateHandler *load_state,
+                         void *opaque)
+{
+    SaveStateEntry *se;
+
+    se = qemu_mallocz(sizeof(SaveStateEntry));
+    se->version_id = version_id;
+    se->section_id = global_section_id++;
+    se->set_params = set_params;
+    se->save_live_state = save_live_state;
+    se->save_state = save_state;
+    se->load_state = load_state;
+    se->opaque = opaque;
+    se->vmsd = NULL;
+    se->no_migrate = 0;
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *id = dev->parent_bus->info->get_dev_path(dev);
+        if (id) {
+            pstrcpy(se->idstr, sizeof(se->idstr), id);
+            pstrcat(se->idstr, sizeof(se->idstr), "/");
+            qemu_free(id);
+
+            se->compat = qemu_mallocz(sizeof(CompatEntry));
+            pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
+            se->compat->instance_id = instance_id == -1 ?
+                         calculate_compat_instance_id(idstr) : instance_id;
+            instance_id = -1;
+        }
+    }
+    pstrcat(se->idstr, sizeof(se->idstr), idstr);
+
+    if (instance_id == -1) {
+        se->instance_id = calculate_new_instance_id(se->idstr);
+    } else {
+        se->instance_id = instance_id;
+    }
+    assert(!se->compat || se->instance_id == 0);
+    /* add at the end of list */
+    QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
+    return 0;
+}
+
+int register_savevm(DeviceState *dev,
+                    const char *idstr,
+                    int instance_id,
+                    int version_id,
+                    SaveStateHandler *save_state,
+                    LoadStateHandler *load_state,
+                    void *opaque)
+{
+    return register_savevm_live(dev, idstr, instance_id, version_id,
+                                NULL, NULL, save_state, load_state, opaque);
+}
+
+void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
+{
+    SaveStateEntry *se, *new_se;
+    char id[256] = "";
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *path = dev->parent_bus->info->get_dev_path(dev);
+        if (path) {
+            pstrcpy(id, sizeof(id), path);
+            pstrcat(id, sizeof(id), "/");
+            qemu_free(path);
+        }
+    }
+    pstrcat(id, sizeof(id), idstr);
+
+    QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+        if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
+            QTAILQ_REMOVE(&savevm_handlers, se, entry);
+            if (se->compat) {
+                qemu_free(se->compat);
+            }
+            qemu_free(se);
+        }
+    }
+}
+
+/* mark a device as not to be migrated, that is the device should be
+   unplugged before migration */
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+                                                            void *opaque)
+{
+    SaveStateEntry *se;
+    char id[256] = "";
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *path = dev->parent_bus->info->get_dev_path(dev);
+        if (path) {
+            pstrcpy(id, sizeof(id), path);
+            pstrcat(id, sizeof(id), "/");
+            qemu_free(path);
+        }
+    }
+    pstrcat(id, sizeof(id), idstr);
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
+            se->no_migrate = 1;
+        }
+    }
+}
+
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+                                   const VMStateDescription *vmsd,
+                                   void *opaque, int alias_id,
+                                   int required_for_version)
+{
+    SaveStateEntry *se;
+
+    /* If this triggers, alias support can be dropped for the vmsd. */
+    assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
+
+    se = qemu_mallocz(sizeof(SaveStateEntry));
+    se->version_id = vmsd->version_id;
+    se->section_id = global_section_id++;
+    se->save_live_state = NULL;
+    se->save_state = NULL;
+    se->load_state = NULL;
+    se->opaque = opaque;
+    se->vmsd = vmsd;
+    se->alias_id = alias_id;
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *id = dev->parent_bus->info->get_dev_path(dev);
+        if (id) {
+            pstrcpy(se->idstr, sizeof(se->idstr), id);
+            pstrcat(se->idstr, sizeof(se->idstr), "/");
+            qemu_free(id);
+
+            se->compat = qemu_mallocz(sizeof(CompatEntry));
+            pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
+            se->compat->instance_id = instance_id == -1 ?
+                         calculate_compat_instance_id(vmsd->name) : instance_id;
+            instance_id = -1;
+        }
+    }
+    pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
+
+    if (instance_id == -1) {
+        se->instance_id = calculate_new_instance_id(se->idstr);
+    } else {
+        se->instance_id = instance_id;
+    }
+    assert(!se->compat || se->instance_id == 0);
+    /* add at the end of list */
+    QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
+    return 0;
+}
+
+int vmstate_register(DeviceState *dev, int instance_id,
+                     const VMStateDescription *vmsd, void *opaque)
+{
+    return vmstate_register_with_alias_id(dev, instance_id, vmsd,
+                                          opaque, -1, 0);
+}
+
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+                        void *opaque)
+{
+    SaveStateEntry *se, *new_se;
+
+    QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+        if (se->vmsd == vmsd && se->opaque == opaque) {
+            QTAILQ_REMOVE(&savevm_handlers, se, entry);
+            if (se->compat) {
+                qemu_free(se->compat);
+            }
+            qemu_free(se);
+        }
+    }
+}
+
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque);
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                   void *opaque);
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, int version_id)
+{
+    VMStateField *field = vmsd->fields;
+    int ret;
+
+    if (version_id > vmsd->version_id) {
+        return -EINVAL;
+    }
+    if (version_id < vmsd->minimum_version_id_old) {
+        return -EINVAL;
+    }
+    if  (version_id < vmsd->minimum_version_id) {
+        return vmsd->load_state_old(f, opaque, version_id);
+    }
+    if (vmsd->pre_load) {
+        int ret = vmsd->pre_load(opaque);
+        if (ret)
+            return ret;
+    }
+    while(field->name) {
+        if ((field->field_exists &&
+             field->field_exists(opaque, version_id)) ||
+            (!field->field_exists &&
+             field->version_id <= version_id)) {
+            void *base_addr = opaque + field->offset;
+            int i, n_elems = 1;
+            int size = field->size;
+
+            if (field->flags & VMS_VBUFFER) {
+                size = *(int32_t *)(opaque+field->size_offset);
+                if (field->flags & VMS_MULTIPLY) {
+                    size *= field->size;
+                }
+            }
+            if (field->flags & VMS_ARRAY) {
+                n_elems = field->num;
+            } else if (field->flags & VMS_VARRAY_INT32) {
+                n_elems = *(int32_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT32) {
+                n_elems = *(uint32_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT16) {
+                n_elems = *(uint16_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT8) {
+                n_elems = *(uint8_t *)(opaque+field->num_offset);
+            }
+            if (field->flags & VMS_POINTER) {
+                base_addr = *(void **)base_addr + field->start;
+            }
+            for (i = 0; i < n_elems; i++) {
+                void *addr = base_addr + size * i;
+
+                if (field->flags & VMS_ARRAY_OF_POINTER) {
+                    addr = *(void **)addr;
+                }
+                if (field->flags & VMS_STRUCT) {
+                    ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
+                } else {
+                    ret = field->info->get(f, addr, size);
+
+                }
+                if (ret < 0) {
+                    return ret;
+                }
+            }
+        }
+        field++;
+    }
+    ret = vmstate_subsection_load(f, vmsd, opaque);
+    if (ret != 0) {
+        return ret;
+    }
+    if (vmsd->post_load) {
+        return vmsd->post_load(opaque, version_id);
+    }
+    return 0;
+}
+
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+                        void *opaque)
+{
+    VMStateField *field = vmsd->fields;
+
+    if (vmsd->pre_save) {
+        vmsd->pre_save(opaque);
+    }
+    while(field->name) {
+        if (!field->field_exists ||
+            field->field_exists(opaque, vmsd->version_id)) {
+            void *base_addr = opaque + field->offset;
+            int i, n_elems = 1;
+            int size = field->size;
+
+            if (field->flags & VMS_VBUFFER) {
+                size = *(int32_t *)(opaque+field->size_offset);
+                if (field->flags & VMS_MULTIPLY) {
+                    size *= field->size;
+                }
+            }
+            if (field->flags & VMS_ARRAY) {
+                n_elems = field->num;
+            } else if (field->flags & VMS_VARRAY_INT32) {
+                n_elems = *(int32_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT16) {
+                n_elems = *(uint16_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT8) {
+                n_elems = *(uint8_t *)(opaque+field->num_offset);
+            }
+            if (field->flags & VMS_POINTER) {
+                base_addr = *(void **)base_addr + field->start;
+            }
+            for (i = 0; i < n_elems; i++) {
+                void *addr = base_addr + size * i;
+
+                if (field->flags & VMS_ARRAY_OF_POINTER) {
+                    addr = *(void **)addr;
+                }
+                if (field->flags & VMS_STRUCT) {
+                    vmstate_save_state(f, field->vmsd, addr);
+                } else {
+                    field->info->put(f, addr, size);
+                }
+            }
+        }
+        field++;
+    }
+    vmstate_subsection_save(f, vmsd, opaque);
+}
+
+static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
+{
+    if (!se->vmsd) {         /* Old style */
+        return se->load_state(f, se->opaque, version_id);
+    }
+    return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
+}
+
+static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
+{
+    if (!se->vmsd) {         /* Old style */
+        se->save_state(f, se->opaque);
+        return;
+    }
+    vmstate_save_state(f,se->vmsd, se->opaque);
+}
+
+#define QEMU_VM_FILE_MAGIC           0x5145564d
+#define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
+#define QEMU_VM_FILE_VERSION         0x00000003
+
+#define QEMU_VM_EOF                  0x00
+#define QEMU_VM_SECTION_START        0x01
+#define QEMU_VM_SECTION_PART         0x02
+#define QEMU_VM_SECTION_END          0x03
+#define QEMU_VM_SECTION_FULL         0x04
+#define QEMU_VM_SUBSECTION           0x05
+
+bool qemu_savevm_state_blocked(Monitor *mon)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->no_migrate) {
+            monitor_printf(mon, "state blocked by non-migratable device '%s'\n",
+                           se->idstr);
+            return true;
+        }
+    }
+    return false;
+}
+
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
+                            int shared)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if(se->set_params == NULL) {
+            continue;
+	}
+	se->set_params(blk_enable, shared, se->opaque);
+    }
+    
+    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        int len;
+
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_START);
+        qemu_put_be32(f, se->section_id);
+
+        /* ID string */
+        len = strlen(se->idstr);
+        qemu_put_byte(f, len);
+        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+        qemu_put_be32(f, se->instance_id);
+        qemu_put_be32(f, se->version_id);
+
+        se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+    }
+
+    if (qemu_file_has_error(f)) {
+        qemu_savevm_state_cancel(mon, f);
+        return -EIO;
+    }
+
+    return 0;
+}
+
+int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
+{
+    SaveStateEntry *se;
+    int ret = 1;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_PART);
+        qemu_put_be32(f, se->section_id);
+
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
+        if (!ret) {
+            /* Do not proceed to the next vmstate before this one reported
+               completion of the current stage. This serializes the migration
+               and reduces the probability that a faster changing state is
+               synchronized over and over again. */
+            break;
+        }
+    }
+
+    if (ret)
+        return 1;
+
+    if (qemu_file_has_error(f)) {
+        qemu_savevm_state_cancel(mon, f);
+        return -EIO;
+    }
+
+    return 0;
+}
+
+int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    cpu_synchronize_all_states();
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_END);
+        qemu_put_be32(f, se->section_id);
+
+        se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+    }
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        int len;
+
+	if (se->save_state == NULL && se->vmsd == NULL)
+	    continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
+        qemu_put_be32(f, se->section_id);
+
+        /* ID string */
+        len = strlen(se->idstr);
+        qemu_put_byte(f, len);
+        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+        qemu_put_be32(f, se->instance_id);
+        qemu_put_be32(f, se->version_id);
+
+        vmstate_save(f, se);
+    }
+
+    qemu_put_byte(f, QEMU_VM_EOF);
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->save_live_state) {
+            se->save_live_state(mon, f, -1, se->opaque);
+        }
+    }
+}
+
+static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
+{
+    int saved_vm_running;
+    int ret;
+
+    saved_vm_running = vm_running;
+    vm_stop(VMSTOP_SAVEVM);
+
+    if (qemu_savevm_state_blocked(mon)) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    ret = qemu_savevm_state_begin(mon, f, 0, 0);
+    if (ret < 0)
+        goto out;
+
+    do {
+        ret = qemu_savevm_state_iterate(mon, f);
+        if (ret < 0)
+            goto out;
+    } while (ret == 0);
+
+    ret = qemu_savevm_state_complete(mon, f);
+
+out:
+    if (qemu_file_has_error(f))
+        ret = -EIO;
+
+    if (!ret && saved_vm_running)
+        vm_start();
+
+    return ret;
+}
+
+static SaveStateEntry *find_se(const char *idstr, int instance_id)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (!strcmp(se->idstr, idstr) &&
+            (instance_id == se->instance_id ||
+             instance_id == se->alias_id))
+            return se;
+        /* Migrating from an older version? */
+        if (strstr(se->idstr, idstr) && se->compat) {
+            if (!strcmp(se->compat->idstr, idstr) &&
+                (instance_id == se->compat->instance_id ||
+                 instance_id == se->alias_id))
+                return se;
+        }
+    }
+    return NULL;
+}
+
+static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
+{
+    while(sub && sub->needed) {
+        if (strcmp(idstr, sub->vmsd->name) == 0) {
+            return sub->vmsd;
+        }
+        sub++;
+    }
+    return NULL;
+}
+
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                   void *opaque)
+{
+    const VMStateSubsection *sub = vmsd->subsections;
+
+    if (!sub || !sub->needed) {
+        return 0;
+    }
+
+    while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+        char idstr[256];
+        int ret;
+        uint8_t version_id, len;
+        const VMStateDescription *sub_vmsd;
+
+        qemu_get_byte(f); /* subsection */
+        len = qemu_get_byte(f);
+        qemu_get_buffer(f, (uint8_t *)idstr, len);
+        idstr[len] = 0;
+        version_id = qemu_get_be32(f);
+
+        sub_vmsd = vmstate_get_subsection(sub, idstr);
+        if (sub_vmsd == NULL) {
+            return -ENOENT;
+        }
+        assert(!sub_vmsd->subsections);
+        ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
+        if (ret) {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque)
+{
+    const VMStateSubsection *sub = vmsd->subsections;
+
+    while (sub && sub->needed) {
+        if (sub->needed(opaque)) {
+            const VMStateDescription *vmsd = sub->vmsd;
+            uint8_t len;
+
+            qemu_put_byte(f, QEMU_VM_SUBSECTION);
+            len = strlen(vmsd->name);
+            qemu_put_byte(f, len);
+            qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
+            qemu_put_be32(f, vmsd->version_id);
+            assert(!vmsd->subsections);
+            vmstate_save_state(f, vmsd, opaque);
+        }
+        sub++;
+    }
+}
+
+typedef struct LoadStateEntry {
+    QLIST_ENTRY(LoadStateEntry) entry;
+    SaveStateEntry *se;
+    int section_id;
+    int version_id;
+} LoadStateEntry;
+
+int qemu_loadvm_state(QEMUFile *f)
+{
+    QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
+        QLIST_HEAD_INITIALIZER(loadvm_handlers);
+    LoadStateEntry *le, *new_le;
+    uint8_t section_type;
+    unsigned int v;
+    int ret;
+
+    if (qemu_savevm_state_blocked(default_mon)) {
+        return -EINVAL;
+    }
+
+    v = qemu_get_be32(f);
+    if (v != QEMU_VM_FILE_MAGIC)
+        return -EINVAL;
+
+    v = qemu_get_be32(f);
+    if (v == QEMU_VM_FILE_VERSION_COMPAT) {
+        fprintf(stderr, "SaveVM v2 format is obsolete and don't work anymore\n");
+        return -ENOTSUP;
+    }
+    if (v != QEMU_VM_FILE_VERSION)
+        return -ENOTSUP;
+
+    while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
+        uint32_t instance_id, version_id, section_id;
+        SaveStateEntry *se;
+        char idstr[257];
+        int len;
+
+        switch (section_type) {
+        case QEMU_VM_SECTION_START:
+        case QEMU_VM_SECTION_FULL:
+            /* Read section start */
+            section_id = qemu_get_be32(f);
+            len = qemu_get_byte(f);
+            qemu_get_buffer(f, (uint8_t *)idstr, len);
+            idstr[len] = 0;
+            instance_id = qemu_get_be32(f);
+            version_id = qemu_get_be32(f);
+
+            /* Find savevm section */
+            se = find_se(idstr, instance_id);
+            if (se == NULL) {
+                fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            /* Validate version */
+            if (version_id > se->version_id) {
+                fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
+                        version_id, idstr, se->version_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            /* Add entry */
+            le = qemu_mallocz(sizeof(*le));
+
+            le->se = se;
+            le->section_id = section_id;
+            le->version_id = version_id;
+            QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
+
+            ret = vmstate_load(f, le->se, le->version_id);
+            if (ret < 0) {
+                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+                        instance_id, idstr);
+                goto out;
+            }
+            break;
+        case QEMU_VM_SECTION_PART:
+        case QEMU_VM_SECTION_END:
+            section_id = qemu_get_be32(f);
+
+            QLIST_FOREACH(le, &loadvm_handlers, entry) {
+                if (le->section_id == section_id) {
+                    break;
+                }
+            }
+            if (le == NULL) {
+                fprintf(stderr, "Unknown savevm section %d\n", section_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            ret = vmstate_load(f, le->se, le->version_id);
+            if (ret < 0) {
+                fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
+                        section_id);
+                goto out;
+            }
+            break;
+        default:
+            fprintf(stderr, "Unknown savevm section type %d\n", section_type);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    cpu_synchronize_all_post_init();
+
+    ret = 0;
+
+out:
+    QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
+        QLIST_REMOVE(le, entry);
+        qemu_free(le);
+    }
+
+    if (qemu_file_has_error(f))
+        ret = -EIO;
+
+    return ret;
+}
+
+static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
+                              const char *name)
+{
+    QEMUSnapshotInfo *sn_tab, *sn;
+    int nb_sns, i, ret;
+
+    ret = -ENOENT;
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns < 0)
+        return ret;
+    for(i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
+            *sn_info = *sn;
+            ret = 0;
+            break;
+        }
+    }
+    qemu_free(sn_tab);
+    return ret;
+}
+
+/*
+ * Deletes snapshots of a given name in all opened images.
+ */
+static int del_existing_snapshots(Monitor *mon, const char *name)
+{
+    BlockDriverState *bs;
+    QEMUSnapshotInfo sn1, *snapshot = &sn1;
+    int ret;
+
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+        if (bdrv_can_snapshot(bs) &&
+            bdrv_snapshot_find(bs, snapshot, name) >= 0)
+        {
+            ret = bdrv_snapshot_delete(bs, name);
+            if (ret < 0) {
+                monitor_printf(mon,
+                               "Error while deleting snapshot on '%s'\n",
+                               bdrv_get_device_name(bs));
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+void do_savevm(Monitor *mon, const QDict *qdict)
+{
+    BlockDriverState *bs, *bs1;
+    QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
+    int ret;
+    QEMUFile *f;
+    int saved_vm_running;
+    uint32_t vm_state_size;
+#ifdef _WIN32
+    struct _timeb tb;
+    struct tm *ptm;
+#else
+    struct timeval tv;
+    struct tm tm;
+#endif
+    const char *name = qdict_get_try_str(qdict, "name");
+
+    /* Verify if there is a device that doesn't support snapshots and is writable */
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+
+        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+            continue;
+        }
+
+        if (!bdrv_can_snapshot(bs)) {
+            monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n",
+                               bdrv_get_device_name(bs));
+            return;
+        }
+    }
+
+    bs = bdrv_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No block device can accept snapshots\n");
+        return;
+    }
+
+    saved_vm_running = vm_running;
+    vm_stop(VMSTOP_SAVEVM);
+
+    memset(sn, 0, sizeof(*sn));
+
+    /* fill auxiliary fields */
+#ifdef _WIN32
+    _ftime(&tb);
+    sn->date_sec = tb.time;
+    sn->date_nsec = tb.millitm * 1000000;
+#else
+    gettimeofday(&tv, NULL);
+    sn->date_sec = tv.tv_sec;
+    sn->date_nsec = tv.tv_usec * 1000;
+#endif
+    sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
+
+    if (name) {
+        ret = bdrv_snapshot_find(bs, old_sn, name);
+        if (ret >= 0) {
+            pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
+            pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
+        } else {
+            pstrcpy(sn->name, sizeof(sn->name), name);
+        }
+    } else {
+#ifdef _WIN32
+        ptm = localtime(&tb.time);
+        strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm);
+#else
+        /* cast below needed for OpenBSD where tv_sec is still 'long' */
+        localtime_r((const time_t *)&tv.tv_sec, &tm);
+        strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
+#endif
+    }
+
+    /* Delete old snapshots of the same name */
+    if (name && del_existing_snapshots(mon, name) < 0) {
+        goto the_end;
+    }
+
+    /* save the VM state */
+    f = qemu_fopen_bdrv(bs, 1);
+    if (!f) {
+        monitor_printf(mon, "Could not open VM state file\n");
+        goto the_end;
+    }
+    ret = qemu_savevm_state(mon, f);
+    vm_state_size = qemu_ftell(f);
+    qemu_fclose(f);
+    if (ret < 0) {
+        monitor_printf(mon, "Error %d while writing VM\n", ret);
+        goto the_end;
+    }
+
+    /* create the snapshots */
+
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
+            /* Write VM state size only to the image that contains the state */
+            sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
+            ret = bdrv_snapshot_create(bs1, sn);
+            if (ret < 0) {
+                monitor_printf(mon, "Error while creating snapshot on '%s'\n",
+                               bdrv_get_device_name(bs1));
+            }
+        }
+    }
+
+ the_end:
+    if (saved_vm_running)
+        vm_start();
+}
+
+int load_vmstate(const char *name)
+{
+    BlockDriverState *bs, *bs_vm_state;
+    QEMUSnapshotInfo sn;
+    QEMUFile *f;
+    int ret;
+
+    bs_vm_state = bdrv_snapshots();
+    if (!bs_vm_state) {
+        error_report("No block device supports snapshots");
+        return -ENOTSUP;
+    }
+
+    /* Don't even try to load empty VM states */
+    ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
+    if (ret < 0) {
+        return ret;
+    } else if (sn.vm_state_size == 0) {
+        error_report("This is a disk-only snapshot. Revert to it offline "
+            "using qemu-img.");
+        return -EINVAL;
+    }
+
+    /* Verify if there is any device that doesn't support snapshots and is
+    writable and check if the requested snapshot is available too. */
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+
+        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+            continue;
+        }
+
+        if (!bdrv_can_snapshot(bs)) {
+            error_report("Device '%s' is writable but does not support snapshots.",
+                               bdrv_get_device_name(bs));
+            return -ENOTSUP;
+        }
+
+        ret = bdrv_snapshot_find(bs, &sn, name);
+        if (ret < 0) {
+            error_report("Device '%s' does not have the requested snapshot '%s'",
+                           bdrv_get_device_name(bs), name);
+            return ret;
+        }
+    }
+
+    /* Flush all IO requests so they don't interfere with the new state.  */
+    qemu_aio_flush();
+
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+        if (bdrv_can_snapshot(bs)) {
+            ret = bdrv_snapshot_goto(bs, name);
+            if (ret < 0) {
+                error_report("Error %d while activating snapshot '%s' on '%s'",
+                             ret, name, bdrv_get_device_name(bs));
+                return ret;
+            }
+        }
+    }
+
+    /* restore the VM state */
+    f = qemu_fopen_bdrv(bs_vm_state, 0);
+    if (!f) {
+        error_report("Could not open VM state file");
+        return -EINVAL;
+    }
+
+    qemu_system_reset(VMRESET_SILENT);
+    ret = qemu_loadvm_state(f);
+
+    qemu_fclose(f);
+    if (ret < 0) {
+        error_report("Error %d while loading VM state", ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+void do_delvm(Monitor *mon, const QDict *qdict)
+{
+    BlockDriverState *bs, *bs1;
+    int ret;
+    const char *name = qdict_get_str(qdict, "name");
+
+    bs = bdrv_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No block device supports snapshots\n");
+        return;
+    }
+
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
+            ret = bdrv_snapshot_delete(bs1, name);
+            if (ret < 0) {
+                if (ret == -ENOTSUP)
+                    monitor_printf(mon,
+                                   "Snapshots not supported on device '%s'\n",
+                                   bdrv_get_device_name(bs1));
+                else
+                    monitor_printf(mon, "Error %d while deleting snapshot on "
+                                   "'%s'\n", ret, bdrv_get_device_name(bs1));
+            }
+        }
+    }
+}
+
+void do_info_snapshots(Monitor *mon)
+{
+    BlockDriverState *bs, *bs1;
+    QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
+    int nb_sns, i, ret, available;
+    int total;
+    int *available_snapshots;
+    char buf[256];
+
+    bs = bdrv_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No available block device supports snapshots\n");
+        return;
+    }
+
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns < 0) {
+        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+        return;
+    }
+
+    if (nb_sns == 0) {
+        monitor_printf(mon, "There is no snapshot available.\n");
+        return;
+    }
+
+    available_snapshots = qemu_mallocz(sizeof(int) * nb_sns);
+    total = 0;
+    for (i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        available = 1;
+        bs1 = NULL;
+
+        while ((bs1 = bdrv_next(bs1))) {
+            if (bdrv_can_snapshot(bs1) && bs1 != bs) {
+                ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
+                if (ret < 0) {
+                    available = 0;
+                    break;
+                }
+            }
+        }
+
+        if (available) {
+            available_snapshots[total] = i;
+            total++;
+        }
+    }
+
+    if (total > 0) {
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+        for (i = 0; i < total; i++) {
+            sn = &sn_tab[available_snapshots[i]];
+            monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+        }
+    } else {
+        monitor_printf(mon, "There is no suitable snapshot available\n");
+    }
+
+    qemu_free(sn_tab);
+    qemu_free(available_snapshots);
+
+}
diff --git a/qemu-0.15.x/scripts/checkpatch.pl b/qemu-0.15.x/scripts/checkpatch.pl
new file mode 100755
index 0000000..3498425
--- /dev/null
+++ b/qemu-0.15.x/scripts/checkpatch.pl
@@ -0,0 +1,2913 @@
+#!/usr/bin/perl -w
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp at austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw at uk.ibm.com> (new conditions, test suite)
+# (c) 2008-2010 Andy Whitcroft <apw at canonical.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s at .*/@@g;
+
+my $V = '0.31';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $root;
+my %debug;
+my $help = 0;
+
+sub help {
+	my ($exitcode) = @_;
+
+	print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+  -q, --quiet                quiet
+  --no-tree                  run without a kernel tree
+  --no-signoff               do not check for 'Signed-off-by' line
+  --patch                    treat FILE as patchfile (default)
+  --emacs                    emacs compile window format
+  --terse                    one line per report
+  -f, --file                 treat FILE as regular source file
+  --subjective, --strict     enable more subjective tests
+  --root=PATH                PATH to the kernel tree root
+  --no-summary               suppress the per-file summary
+  --mailback                 only produce a report in case of warnings/errors
+  --summary-file             include the filename in summary
+  --debug KEY=[0|1]          turn on/off debugging of KEY, where KEY is one of
+                             'values', 'possible', 'type', and 'attr' (default
+                             is all off)
+  --test-only=WORD           report only warnings/errors containing WORD
+                             literally
+  -h, --help, --version      display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+	exit($exitcode);
+}
+
+GetOptions(
+	'q|quiet+'	=> \$quiet,
+	'tree!'		=> \$tree,
+	'signoff!'	=> \$chk_signoff,
+	'patch!'	=> \$chk_patch,
+	'emacs!'	=> \$emacs,
+	'terse!'	=> \$terse,
+	'f|file!'	=> \$file,
+	'subjective!'	=> \$check,
+	'strict!'	=> \$check,
+	'root=s'	=> \$root,
+	'summary!'	=> \$summary,
+	'mailback!'	=> \$mailback,
+	'summary-file!'	=> \$summary_file,
+
+	'debug=s'	=> \%debug,
+	'test-only=s'	=> \$tst_only,
+	'h|help'	=> \$help,
+	'version'	=> \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+	print "$P: no input files\n";
+	exit(1);
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+	## no critic
+	eval "\${dbg_$key} = '$debug{$key}';";
+	die "$@" if ($@);
+}
+
+my $rpt_cleaners = 0;
+
+if ($terse) {
+	$emacs = 1;
+	$quiet++;
+}
+
+if ($tree) {
+	if (defined $root) {
+		if (!top_of_kernel_tree($root)) {
+			die "$P: $root: --root does not point at a valid tree\n";
+		}
+	} else {
+		if (top_of_kernel_tree('.')) {
+			$root = '.';
+		} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+						top_of_kernel_tree($1)) {
+			$root = $1;
+		}
+	}
+
+	if (!defined $root) {
+		print "Must be run from the top-level dir. of a kernel tree\n";
+		exit(2);
+	}
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident	= qr{
+			[A-Za-z_][A-Za-z\d_]*
+			(?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+		}x;
+our $Storage	= qr{extern|static|asmlinkage};
+our $Sparse	= qr{
+			__user|
+			__kernel|
+			__force|
+			__iomem|
+			__must_check|
+			__init_refok|
+			__kprobes|
+			__ref
+		}x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute	= qr{
+			const|
+			__percpu|
+			__nocast|
+			__safe|
+			__bitwise__|
+			__packed__|
+			__packed2__|
+			__naked|
+			__maybe_unused|
+			__always_unused|
+			__noreturn|
+			__used|
+			__cold|
+			__noclone|
+			__deprecated|
+			__read_mostly|
+			__kprobes|
+			__(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+			____cacheline_aligned|
+			____cacheline_aligned_in_smp|
+			____cacheline_internodealigned_in_smp|
+			__weak
+		  }x;
+our $Modifier;
+our $Inline	= qr{inline|__always_inline|noinline};
+our $Member	= qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval	= qr{$Ident(?:$Member)*};
+
+our $Constant	= qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
+our $Assignment	= qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Operators	= qr{
+			<=|>=|==|!=|
+			=>|->|<<|>>|<|>|!|~|
+			&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+		  }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $UTF8	= qr {
+	[\x09\x0A\x0D\x20-\x7E]              # ASCII
+	| [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+	|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+	| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+	|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+	|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+	| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+	|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+}x;
+
+our $typeTypedefs = qr{(?x:
+	(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+	atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+	printk|
+	pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
+	(dev|netdev|netif)_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+	WARN|
+	panic
+)};
+
+our @typeList = (
+	qr{void},
+	qr{(?:unsigned\s+)?char},
+	qr{(?:unsigned\s+)?short},
+	qr{(?:unsigned\s+)?int},
+	qr{(?:unsigned\s+)?long},
+	qr{(?:unsigned\s+)?long\s+int},
+	qr{(?:unsigned\s+)?long\s+long},
+	qr{(?:unsigned\s+)?long\s+long\s+int},
+	qr{unsigned},
+	qr{float},
+	qr{double},
+	qr{bool},
+	qr{struct\s+$Ident},
+	qr{union\s+$Ident},
+	qr{enum\s+$Ident},
+	qr{${Ident}_t},
+	qr{${Ident}_handler},
+	qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+	qr{fastcall},
+);
+
+our $allowed_asm_includes = qr{(?x:
+	irq|
+	memory
+)};
+# memory.h: ARM has a custom one
+
+sub build_types {
+	my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
+	my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+	$Modifier	= qr{(?:$Attribute|$Sparse|$mods)};
+	$NonptrType	= qr{
+			(?:$Modifier\s+|const\s+)*
+			(?:
+				(?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+				(?:$typeTypedefs\b)|
+				(?:${all}\b)
+			)
+			(?:\s+$Modifier|\s+const)*
+		  }x;
+	$Type	= qr{
+			$NonptrType
+			(?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+			(?:\s+$Inline|\s+$Modifier)*
+		  }x;
+	$Declare	= qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+$chk_signoff = 0 if ($file);
+
+my @dep_includes = ();
+my @dep_functions = ();
+my $removal = "Documentation/feature-removal-schedule.txt";
+if ($tree && -f "$root/$removal") {
+	open(my $REMOVE, '<', "$root/$removal") ||
+				die "$P: $removal: open failed - $!\n";
+	while (<$REMOVE>) {
+		if (/^Check:\s+(.*\S)/) {
+			for my $entry (split(/[, ]+/, $1)) {
+				if ($entry =~ m at include/(.*)@) {
+					push(@dep_includes, $1);
+
+				} elsif ($entry !~ m@/@) {
+					push(@dep_functions, $entry);
+				}
+			}
+		}
+	}
+	close($REMOVE);
+}
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+	my $FILE;
+	if ($file) {
+		open($FILE, '-|', "diff -u /dev/null $filename") ||
+			die "$P: $filename: diff failed - $!\n";
+	} elsif ($filename eq '-') {
+		open($FILE, '<&STDIN');
+	} else {
+		open($FILE, '<', "$filename") ||
+			die "$P: $filename: open failed - $!\n";
+	}
+	if ($filename eq '-') {
+		$vname = 'Your patch';
+	} else {
+		$vname = $filename;
+	}
+	while (<$FILE>) {
+		chomp;
+		push(@rawlines, $_);
+	}
+	close($FILE);
+	if (!process($filename)) {
+		$exit = 1;
+	}
+	@rawlines = ();
+	@lines = ();
+}
+
+exit($exit);
+
+sub top_of_kernel_tree {
+	my ($root) = @_;
+
+	my @tree_check = (
+		"COPYING", "MAINTAINERS", "Makefile",
+		"README", "docs", "VERSION",
+		"vl.c"
+	);
+
+	foreach my $check (@tree_check) {
+		if (! -e $root . '/' . $check) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+sub expand_tabs {
+	my ($str) = @_;
+
+	my $res = '';
+	my $n = 0;
+	for my $c (split(//, $str)) {
+		if ($c eq "\t") {
+			$res .= ' ';
+			$n++;
+			for (; ($n % 8) != 0; $n++) {
+				$res .= ' ';
+			}
+			next;
+		}
+		$res .= $c;
+		$n++;
+	}
+
+	return $res;
+}
+sub copy_spacing {
+	(my $res = shift) =~ tr/\t/ /c;
+	return $res;
+}
+
+sub line_stats {
+	my ($line) = @_;
+
+	# Drop the diff line leader and expand tabs
+	$line =~ s/^.//;
+	$line = expand_tabs($line);
+
+	# Pick the indent from the front of the line.
+	my ($white) = ($line =~ /^(\s*)/);
+
+	return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+	my ($in_comment) = @_;
+
+	if ($in_comment) {
+		$sanitise_quote = '*/';
+	} else {
+		$sanitise_quote = '';
+	}
+}
+sub sanitise_line {
+	my ($line) = @_;
+
+	my $res = '';
+	my $l = '';
+
+	my $qlen = 0;
+	my $off = 0;
+	my $c;
+
+	# Always copy over the diff marker.
+	$res = substr($line, 0, 1);
+
+	for ($off = 1; $off < length($line); $off++) {
+		$c = substr($line, $off, 1);
+
+		# Comments we are wacking completly including the begin
+		# and end, all to $;.
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+			$sanitise_quote = '*/';
+
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+			$sanitise_quote = '';
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+			$sanitise_quote = '//';
+
+			substr($res, $off, 2, $sanitise_quote);
+			$off++;
+			next;
+		}
+
+		# A \ in a string means ignore the next character.
+		if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+		    $c eq "\\") {
+			substr($res, $off, 2, 'XX');
+			$off++;
+			next;
+		}
+		# Regular quotes.
+		if ($c eq "'" || $c eq '"') {
+			if ($sanitise_quote eq '') {
+				$sanitise_quote = $c;
+
+				substr($res, $off, 1, $c);
+				next;
+			} elsif ($sanitise_quote eq $c) {
+				$sanitise_quote = '';
+			}
+		}
+
+		#print "c<$c> SQ<$sanitise_quote>\n";
+		if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+			substr($res, $off, 1, 'X');
+		} else {
+			substr($res, $off, 1, $c);
+		}
+	}
+
+	if ($sanitise_quote eq '//') {
+		$sanitise_quote = '';
+	}
+
+	# The pathname on a #include may be surrounded by '<' and '>'.
+	if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@\<.*\>@<$clean>@;
+
+	# The whole of a #error is a string.
+	} elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+	}
+
+	return $res;
+}
+
+sub ctx_statement_block {
+	my ($linenr, $remain, $off) = @_;
+	my $line = $linenr - 1;
+	my $blk = '';
+	my $soff = $off;
+	my $coff = $off - 1;
+	my $coff_set = 0;
+
+	my $loff = 0;
+
+	my $type = '';
+	my $level = 0;
+	my @stack = ();
+	my $p;
+	my $c;
+	my $len = 0;
+
+	my $remainder;
+	while (1) {
+		@stack = (['', 0]) if ($#stack == -1);
+
+		#warn "CSB: blk<$blk> remain<$remain>\n";
+		# If we are about to drop off the end, pull in more
+		# context.
+		if ($off >= $len) {
+			for (; $remain > 0; $line++) {
+				last if (!defined $lines[$line]);
+				next if ($lines[$line] =~ /^-/);
+				$remain--;
+				$loff = $len;
+				$blk .= $lines[$line] . "\n";
+				$len = length($blk);
+				$line++;
+				last;
+			}
+			# Bail if there is no further context.
+			#warn "CSB: blk<$blk> off<$off> len<$len>\n";
+			if ($off >= $len) {
+				last;
+			}
+		}
+		$p = $c;
+		$c = substr($blk, $off, 1);
+		$remainder = substr($blk, $off);
+
+		#warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+		# Handle nested #if/#else.
+		if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, [ $type, $level ]);
+		} elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+			($type, $level) = @{$stack[$#stack - 1]};
+		} elsif ($remainder =~ /^#\s*endif\b/) {
+			($type, $level) = @{pop(@stack)};
+		}
+
+		# Statement ends at the ';' or a close '}' at the
+		# outermost level.
+		if ($level == 0 && $c eq ';') {
+			last;
+		}
+
+		# An else is really a conditional as long as its not else if
+		if ($level == 0 && $coff_set == 0 &&
+				(!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+				$remainder =~ /^(else)(?:\s|{)/ &&
+				$remainder !~ /^else\s+if\b/) {
+			$coff = $off + length($1) - 1;
+			$coff_set = 1;
+			#warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+			#warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+		}
+
+		if (($type eq '' || $type eq '(') && $c eq '(') {
+			$level++;
+			$type = '(';
+		}
+		if ($type eq '(' && $c eq ')') {
+			$level--;
+			$type = ($level != 0)? '(' : '';
+
+			if ($level == 0 && $coff < $soff) {
+				$coff = $off;
+				$coff_set = 1;
+				#warn "CSB: mark coff<$coff>\n";
+			}
+		}
+		if (($type eq '' || $type eq '{') && $c eq '{') {
+			$level++;
+			$type = '{';
+		}
+		if ($type eq '{' && $c eq '}') {
+			$level--;
+			$type = ($level != 0)? '{' : '';
+
+			if ($level == 0) {
+				if (substr($blk, $off + 1, 1) eq ';') {
+					$off++;
+				}
+				last;
+			}
+		}
+		$off++;
+	}
+	# We are truly at the end, so shuffle to the next line.
+	if ($off == $len) {
+		$loff = $len + 1;
+		$line++;
+		$remain--;
+	}
+
+	my $statement = substr($blk, $soff, $off - $soff + 1);
+	my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+	#warn "STATEMENT<$statement>\n";
+	#warn "CONDITION<$condition>\n";
+
+	#print "coff<$coff> soff<$off> loff<$loff>\n";
+
+	return ($statement, $condition,
+			$line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+	my ($stmt) = @_;
+
+	# Strip the diff line prefixes and rip blank lines at start and end.
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+	my ($stmt) = @_;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+	my ($stmt) = @_;
+
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*{//;
+	$stmt =~ s/}\s*$//;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+	my @stmt_statements = ($stmt =~ /;/g);
+
+	my $stmt_lines = $#stmt_lines + 2;
+	my $stmt_statements = $#stmt_statements + 1;
+
+	if ($stmt_lines > $stmt_statements) {
+		return $stmt_lines;
+	} else {
+		return $stmt_statements;
+	}
+}
+
+sub ctx_statement_full {
+	my ($linenr, $remain, $off) = @_;
+	my ($statement, $condition, $level);
+
+	my (@chunks);
+
+	# Grab the first conditional/block pair.
+	($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+	#print "F: c<$condition> s<$statement> remain<$remain>\n";
+	push(@chunks, [ $condition, $statement ]);
+	if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+		return ($level, $linenr, @chunks);
+	}
+
+	# Pull in the following conditional/block pairs and see if they
+	# could continue the statement.
+	for (;;) {
+		($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+		#print "C: c<$condition> s<$statement> remain<$remain>\n";
+		last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+		#print "C: push\n";
+		push(@chunks, [ $condition, $statement ]);
+	}
+
+	return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+	my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+	my $line;
+	my $start = $linenr - 1;
+	my $blk = '';
+	my @o;
+	my @c;
+	my @res = ();
+
+	my $level = 0;
+	my @stack = ($level);
+	for ($line = $start; $remain > 0; $line++) {
+		next if ($rawlines[$line] =~ /^-/);
+		$remain--;
+
+		$blk .= $rawlines[$line];
+
+		# Handle nested #if/#else.
+		if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, $level);
+		} elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+			$level = $stack[$#stack - 1];
+		} elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
+			$level = pop(@stack);
+		}
+
+		foreach my $c (split(//, $lines[$line])) {
+			##print "C<$c>L<$level><$open$close>O<$off>\n";
+			if ($off > 0) {
+				$off--;
+				next;
+			}
+
+			if ($c eq $close && $level > 0) {
+				$level--;
+				last if ($level == 0);
+			} elsif ($c eq $open) {
+				$level++;
+			}
+		}
+
+		if (!$outer || $level <= 1) {
+			push(@res, $rawlines[$line]);
+		}
+
+		last if ($level == 0);
+	}
+
+	return ($level, @res);
+}
+sub ctx_block_outer {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+	return @r;
+}
+sub ctx_block {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+	return @r;
+}
+sub ctx_statement {
+	my ($linenr, $remain, $off) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+	return @r;
+}
+sub ctx_block_level {
+	my ($linenr, $remain) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+	my ($linenr, $remain, $off) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+	my ($first_line, $end_line) = @_;
+
+	# Catch a comment on the end of the line itself.
+	my ($current_comment) = ($rawlines[$end_line - 1] =~ m at .*(/\*.*\*/)\s*(?:\\\s*)?$@);
+	return $current_comment if (defined $current_comment);
+
+	# Look through the context and try and figure out if there is a
+	# comment.
+	my $in_comment = 0;
+	$current_comment = '';
+	for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+		my $line = $rawlines[$linenr - 1];
+		#warn "           $line\n";
+		if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+			$in_comment = 1;
+		}
+		if ($line =~ m@/\*@) {
+			$in_comment = 1;
+		}
+		if (!$in_comment && $current_comment ne '') {
+			$current_comment = '';
+		}
+		$current_comment .= $line . "\n" if ($in_comment);
+		if ($line =~ m@\*/@) {
+			$in_comment = 0;
+		}
+	}
+
+	chomp($current_comment);
+	return($current_comment);
+}
+sub ctx_has_comment {
+	my ($first_line, $end_line) = @_;
+	my $cmt = ctx_locate_comment($first_line, $end_line);
+
+	##print "LINE: $rawlines[$end_line - 1 ]\n";
+	##print "CMMT: $cmt\n";
+
+	return ($cmt ne '');
+}
+
+sub raw_line {
+	my ($linenr, $cnt) = @_;
+
+	my $offset = $linenr - 1;
+	$cnt++;
+
+	my $line;
+	while ($cnt) {
+		$line = $rawlines[$offset++];
+		next if (defined($line) && $line =~ /^-/);
+		$cnt--;
+	}
+
+	return $line;
+}
+
+sub cat_vet {
+	my ($vet) = @_;
+	my ($res, $coded);
+
+	$res = '';
+	while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+		$res .= $1;
+		if ($2 ne '') {
+			$coded = sprintf("^%c", unpack('C', $2) + 64);
+			$res .= $coded;
+		}
+	}
+	$res =~ s/$/\$/;
+
+	return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+	$av_preprocessor = 0;
+	$av_pending = '_';
+	@av_paren_type = ('E');
+	$av_pend_colon = 'O';
+}
+
+sub annotate_values {
+	my ($stream, $type) = @_;
+
+	my $res;
+	my $var = '_' x length($stream);
+	my $cur = $stream;
+
+	print "$stream\n" if ($dbg_values > 1);
+
+	while (length($cur)) {
+		@av_paren_type = ('E') if ($#av_paren_type < 0);
+		print " <" . join('', @av_paren_type) .
+				"> <$type> <$av_pending>" if ($dbg_values > 1);
+		if ($cur =~ /^(\s+)/o) {
+			print "WS($1)\n" if ($dbg_values > 1);
+			if ($1 =~ /\n/ && $av_preprocessor) {
+				$type = pop(@av_paren_type);
+				$av_preprocessor = 0;
+			}
+
+		} elsif ($cur =~ /^(\(\s*$Type\s*)\)/) {
+			print "CAST($1)\n" if ($dbg_values > 1);
+			push(@av_paren_type, $type);
+			$type = 'C';
+
+		} elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
+			print "DECLARE($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^($Modifier)\s*/) {
+			print "MODIFIER($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+			print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+			if ($2 ne '') {
+				$av_pending = 'N';
+			}
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+			print "UNDEF($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+
+		} elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+			print "PRE_START($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+			print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+			print "PRE_END($1)\n" if ($dbg_values > 1);
+
+			$av_preprocessor = 1;
+
+			# Assume all arms of the conditional end as this
+			# one does, and continue as if the #endif was not here.
+			pop(@av_paren_type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\\\n)/o) {
+			print "PRECONT($1)\n" if ($dbg_values > 1);
+
+		} elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+			print "ATTR($1)\n" if ($dbg_values > 1);
+			$av_pending = $type;
+			$type = 'N';
+
+		} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+			print "SIZEOF($1)\n" if ($dbg_values > 1);
+			if (defined $2) {
+				$av_pending = 'V';
+			}
+			$type = 'N';
+
+		} elsif ($cur =~ /^(if|while|for)\b/o) {
+			print "COND($1)\n" if ($dbg_values > 1);
+			$av_pending = 'E';
+			$type = 'N';
+
+		} elsif ($cur =~/^(case)/o) {
+			print "CASE($1)\n" if ($dbg_values > 1);
+			$av_pend_colon = 'C';
+			$type = 'N';
+
+		} elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+			print "KEYWORD($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\()/o) {
+			print "PAREN('$1')\n" if ($dbg_values > 1);
+			push(@av_paren_type, $av_pending);
+			$av_pending = '_';
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\))/o) {
+			my $new_type = pop(@av_paren_type);
+			if ($new_type ne '_') {
+				$type = $new_type;
+				print "PAREN('$1') -> $type\n"
+							if ($dbg_values > 1);
+			} else {
+				print "PAREN('$1')\n" if ($dbg_values > 1);
+			}
+
+		} elsif ($cur =~ /^($Ident)\s*\(/o) {
+			print "FUNC($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+			$av_pending = 'V';
+
+		} elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+			if (defined $2 && $type eq 'C' || $type eq 'T') {
+				$av_pend_colon = 'B';
+			} elsif ($type eq 'E') {
+				$av_pend_colon = 'L';
+			}
+			print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Ident|$Constant)/o) {
+			print "IDENT($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Assignment)/o) {
+			print "ASSIGN($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~/^(;|{|})/) {
+			print "END($1)\n" if ($dbg_values > 1);
+			$type = 'E';
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~/^(,)/) {
+			print "COMMA($1)\n" if ($dbg_values > 1);
+			$type = 'C';
+
+		} elsif ($cur =~ /^(\?)/o) {
+			print "QUESTION($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(:)/o) {
+			print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+			substr($var, length($res), 1, $av_pend_colon);
+			if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+				$type = 'E';
+			} else {
+				$type = 'N';
+			}
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~ /^(\[)/o) {
+			print "CLOSE($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+			my $variant;
+
+			print "OPV($1)\n" if ($dbg_values > 1);
+			if ($type eq 'V') {
+				$variant = 'B';
+			} else {
+				$variant = 'U';
+			}
+
+			substr($var, length($res), 1, $variant);
+			$type = 'N';
+
+		} elsif ($cur =~ /^($Operators)/o) {
+			print "OP($1)\n" if ($dbg_values > 1);
+			if ($1 ne '++' && $1 ne '--') {
+				$type = 'N';
+			}
+
+		} elsif ($cur =~ /(^.)/o) {
+			print "C($1)\n" if ($dbg_values > 1);
+		}
+		if (defined $1) {
+			$cur = substr($cur, length($1));
+			$res .= $type x length($1);
+		}
+	}
+
+	return ($res, $var);
+}
+
+sub possible {
+	my ($possible, $line) = @_;
+	my $notPermitted = qr{(?:
+		^(?:
+			$Modifier|
+			$Storage|
+			$Type|
+			DEFINE_\S+
+		)$|
+		^(?:
+			goto|
+			return|
+			case|
+			else|
+			asm|__asm__|
+			do
+		)(?:\s|$)|
+		^(?:typedef|struct|enum)\b
+	    )}x;
+	warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+	if ($possible !~ $notPermitted) {
+		# Check for modifiers.
+		$possible =~ s/\s*$Storage\s*//g;
+		$possible =~ s/\s*$Sparse\s*//g;
+		if ($possible =~ /^\s*$/) {
+
+		} elsif ($possible =~ /\s/) {
+			$possible =~ s/\s*$Type\s*//g;
+			for my $modifier (split(' ', $possible)) {
+				if ($modifier !~ $notPermitted) {
+					warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+					push(@modifierList, $modifier);
+				}
+			}
+
+		} else {
+			warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+			push(@typeList, $possible);
+		}
+		build_types();
+	} else {
+		warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+	}
+}
+
+my $prefix = '';
+
+sub report {
+	if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+		return 0;
+	}
+	my $line = $prefix . $_[0];
+
+	$line = (split('\n', $line))[0] . "\n" if ($terse);
+
+	push(our @report, $line);
+
+	return 1;
+}
+sub report_dump {
+	our @report;
+}
+sub ERROR {
+	if (report("ERROR: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_error++;
+	}
+}
+sub WARN {
+	if (report("WARNING: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_warn++;
+	}
+}
+sub CHK {
+	if ($check && report("CHECK: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_chk++;
+	}
+}
+
+sub check_absolute_file {
+	my ($absolute, $herecurr) = @_;
+	my $file = $absolute;
+
+	##print "absolute<$absolute>\n";
+
+	# See if any suffix of this path is a path within the tree.
+	while ($file =~ s@^[^/]*/@@) {
+		if (-f "$root/$file") {
+			##print "file<$file>\n";
+			last;
+		}
+	}
+	if (! -f _)  {
+		return 0;
+	}
+
+	# It is, so see if the prefix is acceptable.
+	my $prefix = $absolute;
+	substr($prefix, -length($file)) = '';
+
+	##print "prefix<$prefix>\n";
+	if ($prefix ne ".../") {
+		WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+	}
+}
+
+sub process {
+	my $filename = shift;
+
+	my $linenr=0;
+	my $prevline="";
+	my $prevrawline="";
+	my $stashline="";
+	my $stashrawline="";
+
+	my $length;
+	my $indent;
+	my $previndent=0;
+	my $stashindent=0;
+
+	our $clean = 1;
+	my $signoff = 0;
+	my $is_patch = 0;
+
+	our @report = ();
+	our $cnt_lines = 0;
+	our $cnt_error = 0;
+	our $cnt_warn = 0;
+	our $cnt_chk = 0;
+
+	# Trace the real file/line as we go.
+	my $realfile = '';
+	my $realline = 0;
+	my $realcnt = 0;
+	my $here = '';
+	my $in_comment = 0;
+	my $comment_edge = 0;
+	my $first_line = 0;
+	my $p1_prefix = '';
+
+	my $prev_values = 'E';
+
+	# suppression flags
+	my %suppress_ifbraces;
+	my %suppress_whiletrailers;
+	my %suppress_export;
+
+	# Pre-scan the patch sanitizing the lines.
+	# Pre-scan the patch looking for any __setup documentation.
+	#
+	my @setup_docs = ();
+	my $setup_docs = 0;
+
+	sanitise_line_reset();
+	my $line;
+	foreach my $rawline (@rawlines) {
+		$linenr++;
+		$line = $rawline;
+
+		if ($rawline=~/^\+\+\+\s+(\S+)/) {
+			$setup_docs = 0;
+			if ($1 =~ m at Documentation/kernel-parameters.txt$@) {
+				$setup_docs = 1;
+			}
+			#next;
+		}
+		if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			$in_comment = 0;
+
+			# Guestimate if this is a continuing comment.  Run
+			# the context looking for a comment "edge".  If this
+			# edge is a close comment then we must be in a comment
+			# at context start.
+			my $edge;
+			my $cnt = $realcnt;
+			for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+				next if (defined $rawlines[$ln - 1] &&
+					 $rawlines[$ln - 1] =~ /^-/);
+				$cnt--;
+				#print "RAW<$rawlines[$ln - 1]>\n";
+				last if (!defined $rawlines[$ln - 1]);
+				if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+				    $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+					($edge) = $1;
+					last;
+				}
+			}
+			if (defined $edge && $edge eq '*/') {
+				$in_comment = 1;
+			}
+
+			# Guestimate if this is a continuing comment.  If this
+			# is the start of a diff block and this line starts
+			# ' *' then it is very likely a comment.
+			if (!defined $edge &&
+			    $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+			{
+				$in_comment = 1;
+			}
+
+			##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+			sanitise_line_reset($in_comment);
+
+		} elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+			# Standardise the strings and chars within the input to
+			# simplify matching -- only bother with positive lines.
+			$line = sanitise_line($rawline);
+		}
+		push(@lines, $line);
+
+		if ($realcnt > 1) {
+			$realcnt-- if ($line =~ /^(?:\+| |$)/);
+		} else {
+			$realcnt = 0;
+		}
+
+		#print "==>$rawline\n";
+		#print "-->$line\n";
+
+		if ($setup_docs && $line =~ /^\+/) {
+			push(@setup_docs, $line);
+		}
+	}
+
+	$prefix = '';
+
+	$realcnt = 0;
+	$linenr = 0;
+	foreach my $line (@lines) {
+		$linenr++;
+
+		my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+		if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$is_patch = 1;
+			$first_line = $linenr + 1;
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			annotate_reset();
+			$prev_values = 'E';
+
+			%suppress_ifbraces = ();
+			%suppress_whiletrailers = ();
+			%suppress_export = ();
+			next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+		} elsif ($line =~ /^( |\+|$)/) {
+			$realline++;
+			$realcnt-- if ($realcnt != 0);
+
+			# Measure the line length and indent.
+			($length, $indent) = line_stats($rawline);
+
+			# Track the previous line.
+			($prevline, $stashline) = ($stashline, $line);
+			($previndent, $stashindent) = ($stashindent, $indent);
+			($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+			#warn "line<$line>\n";
+
+		} elsif ($realcnt == 1) {
+			$realcnt--;
+		}
+
+		my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+		$prefix = "$filename:$realline: " if ($emacs && $file);
+		$prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+		$here = "#$linenr: " if (!$file);
+		$here = "#$realline: " if ($file);
+
+		# extract the filename as it passes
+		if ($line =~ /^diff --git.*?(\S+)$/) {
+			$realfile = $1;
+			$realfile =~ s@^([^/]*)/@@;
+
+		} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
+			$realfile = $1;
+			$realfile =~ s@^([^/]*)/@@;
+
+			$p1_prefix = $1;
+			if (!$file && $tree && $p1_prefix ne '' &&
+			    -e "$root/$p1_prefix") {
+				WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+			}
+
+			if ($realfile =~ m@^include/asm/@) {
+				ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+			}
+			next;
+		}
+
+		$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+		my $hereline = "$here\n$rawline\n";
+		my $herecurr = "$here\n$rawline\n";
+		my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+		$cnt_lines++ if ($realcnt != 0);
+
+# Check for incorrect file permissions
+		if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+			my $permhere = $here . "FILE: $realfile\n";
+			if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+				ERROR("do not set execute permissions for source files\n" . $permhere);
+			}
+		}
+
+#check the patch for a signoff:
+		if ($line =~ /^\s*signed-off-by:/i) {
+			# This is a signoff, if ugly, so do not double report.
+			$signoff++;
+			if (!($line =~ /^\s*Signed-off-by:/)) {
+				WARN("Signed-off-by: is the preferred form\n" .
+					$herecurr);
+			}
+			if ($line =~ /^\s*signed-off-by:\S/i) {
+				WARN("space required after Signed-off-by:\n" .
+					$herecurr);
+			}
+		}
+
+# Check for wrappage within a valid hunk of the file
+		if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+			ERROR("patch seems to be corrupt (line wrapped?)\n" .
+				$herecurr) if (!$emitted_corrupt++);
+		}
+
+# Check for absolute kernel paths.
+		if ($tree) {
+			while ($line =~ m{(?:^|\s)(/\S*)}g) {
+				my $file = $1;
+
+				if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+				    check_absolute_file($1, $herecurr)) {
+					#
+				} else {
+					check_absolute_file($file, $herecurr);
+				}
+			}
+		}
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+		if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+		    $rawline !~ m/^$UTF8*$/) {
+			my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+			my $blank = copy_spacing($rawline);
+			my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+			my $hereptr = "$hereline$ptr\n";
+
+			ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+		}
+
+# ignore non-hunk lines and lines being removed
+		next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+		if ($line =~ /^\+.*\015/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("DOS line endings\n" . $herevet);
+
+		} elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("trailing whitespace\n" . $herevet);
+			$rpt_cleaners = 1;
+		}
+
+# check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
+		if ($realfile =~ /Kconfig/ &&
+		    $line =~ /\+\s*(?:---)?help(?:---)?$/) {
+			my $length = 0;
+			my $cnt = $realcnt;
+			my $ln = $linenr + 1;
+			my $f;
+			my $is_end = 0;
+			while ($cnt > 0 && defined $lines[$ln - 1]) {
+				$f = $lines[$ln - 1];
+				$cnt-- if ($lines[$ln - 1] !~ /^-/);
+				$is_end = $lines[$ln - 1] =~ /^\+/;
+				$ln++;
+
+				next if ($f =~ /^-/);
+				$f =~ s/^.//;
+				$f =~ s/#.*//;
+				$f =~ s/^\s+//;
+				next if ($f =~ /^$/);
+				if ($f =~ /^\s*config\s/) {
+					$is_end = 1;
+					last;
+				}
+				$length++;
+			}
+			WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
+			#print "is_end<$is_end> length<$length>\n";
+		}
+
+# check we are in a valid source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#80 column limit
+		if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+		    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+		    !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ ||
+		    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
+		    $length > 80)
+		{
+			WARN("line over 80 characters\n" . $herecurr);
+		}
+
+# check for spaces before a quoted newline
+		if ($rawline =~ /^.*\".*\s\\n/) {
+			WARN("unnecessary whitespace before a quoted newline\n" . $herecurr);
+		}
+
+# check for adding lines without a newline.
+		if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+			WARN("adding a line without newline at end of file\n" . $herecurr);
+		}
+
+# Blackfin: use hi/lo macros
+		if ($realfile =~ m at arch/blackfin/.*\.S$@) {
+			if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+			}
+			if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("use the HI() macro, not (... >> 16)\n" . $herevet);
+			}
+		}
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|pl)$/);
+
+# in QEMU, no tabs are allowed
+		if ($rawline =~ /^\+.*\t/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("code indent should never use tabs\n" . $herevet);
+			$rpt_cleaners = 1;
+		}
+
+# check we are in a valid C source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c)$/);
+
+# check for RCS/CVS revision markers
+		if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+			WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+		}
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+		if ($line =~ /__builtin_bfin_csync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+		if ($line =~ /__builtin_bfin_ssync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+
+# Check for potential 'bare' types
+		my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+		    $realline_next);
+		if ($realcnt && $line =~ /.\s*\S/) {
+			($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+				ctx_statement_block($linenr, $realcnt, 0);
+			$stat =~ s/\n./\n /g;
+			$cond =~ s/\n./\n /g;
+
+			# Find the real next line.
+			$realline_next = $line_nr_next;
+			if (defined $realline_next &&
+			    (!defined $lines[$realline_next - 1] ||
+			     substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+				$realline_next++;
+			}
+
+			my $s = $stat;
+			$s =~ s/{.*$//s;
+
+			# Ignore goto labels.
+			if ($s =~ /$Ident:\*$/s) {
+
+			# Ignore functions being called
+			} elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+			} elsif ($s =~ /^.\s*else\b/s) {
+
+			# declarations always start with types
+			} elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+				my $type = $1;
+				$type =~ s/\s+/ /g;
+				possible($type, "A:" . $s);
+
+			# definitions in global scope can only start with types
+			} elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+				possible($1, "B:" . $s);
+			}
+
+			# any (foo ... *) is a pointer cast, and foo is a type
+			while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+				possible($1, "C:" . $s);
+			}
+
+			# Check for any sort of function declaration.
+			# int foo(something bar, other baz);
+			# void (*store_gdt)(x86_descr_ptr *);
+			if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+				my ($name_len) = length($1);
+
+				my $ctx = $s;
+				substr($ctx, 0, $name_len + 1, '');
+				$ctx =~ s/\)[^\)]*$//;
+
+				for my $arg (split(/\s*,\s*/, $ctx)) {
+					if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+						possible($1, "D:" . $s);
+					}
+				}
+			}
+
+		}
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+		if ($line=~/\bswitch\s*\(.*\)/) {
+			my $err = '';
+			my $sep = '';
+			my @ctx = ctx_block_outer($linenr, $realcnt);
+			shift(@ctx);
+			for my $ctx (@ctx) {
+				my ($clen, $cindent) = line_stats($ctx);
+				if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+							$indent != $cindent) {
+					$err .= "$sep$ctx\n";
+					$sep = '';
+				} else {
+					$sep = "[...]\n";
+				}
+			}
+			if ($err ne '') {
+				ERROR("switch and case should be at the same indent\n$hereline$err");
+			}
+		}
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+		if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+			my $pre_ctx = "$1$2";
+
+			my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+			my $ctx_cnt = $realcnt - $#ctx - 1;
+			my $ctx = join("\n", @ctx);
+
+			my $ctx_ln = $linenr;
+			my $ctx_skip = $realcnt;
+
+			while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+					defined $lines[$ctx_ln - 1] &&
+					$lines[$ctx_ln - 1] =~ /^-/)) {
+				##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+				$ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+				$ctx_ln++;
+			}
+
+			#print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+			#print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+			if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+				ERROR("that open brace { should be on the previous line\n" .
+					"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+			}
+			if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+			    $ctx =~ /\)\s*\;\s*$/ &&
+			    defined $lines[$ctx_ln - 1])
+			{
+				my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+				if ($nindent > $indent) {
+					WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
+						"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+				}
+			}
+		}
+
+# Check relative indent for conditionals and blocks.
+		if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+			my ($s, $c) = ($stat, $cond);
+
+			substr($s, 0, length($c), '');
+
+			# Make sure we remove the line prefixes as we have
+			# none on the first line, and are going to readd them
+			# where necessary.
+			$s =~ s/\n./\n/gs;
+
+			# Find out how long the conditional actually is.
+			my @newlines = ($c =~ /\n/gs);
+			my $cond_lines = 1 + $#newlines;
+
+			# We want to check the first line inside the block
+			# starting at the end of the conditional, so remove:
+			#  1) any blank line termination
+			#  2) any opening brace { on end of the line
+			#  3) any do (...) {
+			my $continuation = 0;
+			my $check = 0;
+			$s =~ s/^.*\bdo\b//;
+			$s =~ s/^\s*{//;
+			if ($s =~ s/^\s*\\//) {
+				$continuation = 1;
+			}
+			if ($s =~ s/^\s*?\n//) {
+				$check = 1;
+				$cond_lines++;
+			}
+
+			# Also ignore a loop construct at the end of a
+			# preprocessor statement.
+			if (($prevline =~ /^.\s*#\s*define\s/ ||
+			    $prevline =~ /\\\s*$/) && $continuation == 0) {
+				$check = 0;
+			}
+
+			my $cond_ptr = -1;
+			$continuation = 0;
+			while ($cond_ptr != $cond_lines) {
+				$cond_ptr = $cond_lines;
+
+				# If we see an #else/#elif then the code
+				# is not linear.
+				if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+					$check = 0;
+				}
+
+				# Ignore:
+				#  1) blank lines, they should be at 0,
+				#  2) preprocessor lines, and
+				#  3) labels.
+				if ($continuation ||
+				    $s =~ /^\s*?\n/ ||
+				    $s =~ /^\s*#\s*?/ ||
+				    $s =~ /^\s*$Ident\s*:/) {
+					$continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+					if ($s =~ s/^.*?\n//) {
+						$cond_lines++;
+					}
+				}
+			}
+
+			my (undef, $sindent) = line_stats("+" . $s);
+			my $stat_real = raw_line($linenr, $cond_lines);
+
+			# Check if either of these lines are modified, else
+			# this is not this patch's fault.
+			if (!defined($stat_real) ||
+			    $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+				$check = 0;
+			}
+			if (defined($stat_real) && $cond_lines > 1) {
+				$stat_real = "[...]\n$stat_real";
+			}
+
+			#print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+			if ($check && (($sindent % 4) != 0 ||
+			    ($sindent <= $indent && $s ne ''))) {
+				WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+			}
+		}
+
+		# Track the 'values' across context and added lines.
+		my $opline = $line; $opline =~ s/^./ /;
+		my ($curr_values, $curr_vars) =
+				annotate_values($opline . "\n", $prev_values);
+		$curr_values = $prev_values . $curr_values;
+		if ($dbg_values) {
+			my $outline = $opline; $outline =~ s/\t/ /g;
+			print "$linenr > .$outline\n";
+			print "$linenr > $curr_values\n";
+			print "$linenr >  $curr_vars\n";
+		}
+		$prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+		if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+		if ($dbg_type) {
+			if ($line =~ /^.\s*$Declare\s*$/) {
+				ERROR("TEST: is type\n" . $herecurr);
+			} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+				ERROR("TEST: is not type ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+# TEST: allow direct testing of the attribute matcher.
+		if ($dbg_attr) {
+			if ($line =~ /^.\s*$Modifier\s*$/) {
+				ERROR("TEST: is attr\n" . $herecurr);
+			} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+				ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+
+# check for initialisation to aggregates open brace on the next line
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /(?:^|[^=])=\s*$/) {
+			ERROR("that open brace { should be on the previous line\n" . $hereprev);
+		}
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+		if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+			my $path = $1;
+			if ($path =~ m{//}) {
+				ERROR("malformed #include filename\n" .
+					$herecurr);
+			}
+		}
+
+# no C99 // comments
+		if ($line =~ m{//}) {
+			ERROR("do not use C99 // comments\n" . $herecurr);
+		}
+		# Remove C99 comments.
+		$line =~ s@//.*@@;
+		$opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+		if (defined $realline_next &&
+		    exists $lines[$realline_next - 1] &&
+		    !defined $suppress_export{$realline_next} &&
+		    ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+			# Handle definitions which produce identifiers with
+			# a prefix:
+			#   XXX(foo);
+			#   EXPORT_SYMBOL(something_foo);
+			my $name = $1;
+			if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+			    $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+				$suppress_export{$realline_next} = 1;
+
+			} elsif ($stat !~ /(?:
+				\n.}\s*$|
+				^.DEFINE_$Ident\(\Q$name\E\)|
+				^.DECLARE_$Ident\(\Q$name\E\)|
+				^.LIST_HEAD\(\Q$name\E\)|
+				^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+				\b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+			    )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+				$suppress_export{$realline_next} = 2;
+			} else {
+				$suppress_export{$realline_next} = 1;
+			}
+		}
+		if (!defined $suppress_export{$linenr} &&
+		    $prevline =~ /^.\s*$/ &&
+		    ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+			$suppress_export{$linenr} = 2;
+		}
+		if (defined $suppress_export{$linenr} &&
+		    $suppress_export{$linenr} == 2) {
+			WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+		}
+
+# check for global initialisers.
+		if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+			ERROR("do not initialise globals to 0 or NULL\n" .
+				$herecurr);
+		}
+# check for static initialisers.
+		if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+			ERROR("do not initialise statics to 0 or NULL\n" .
+				$herecurr);
+		}
+
+# * goes on variable not on type
+		# (char*[ const])
+		if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
+			my ($from, $to) = ($1, $1);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+
+			#print "from<$from> to<$to>\n";
+			if ($from ne $to) {
+				ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
+			}
+		} elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
+			my ($from, $to, $ident) = ($1, $1, $2);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+			# Modifiers should have spaces.
+			$to =~ s/(\b$Modifier$)/$1 /;
+
+			#print "from<$from> to<$to> ident<$ident>\n";
+			if ($from ne $to && $ident !~ /^$Modifier$/) {
+				ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
+			}
+		}
+
+# # no BUG() or BUG_ON()
+# 		if ($line =~ /\b(BUG|BUG_ON)\b/) {
+# 			print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+# 			print "$herecurr";
+# 			$clean = 0;
+# 		}
+
+		if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+			WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+		}
+
+# printk should use KERN_* levels.  Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk.  In summary the current
+# printk includes all preceeding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+		if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+			my $ok = 0;
+			for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+				#print "CHECK<$lines[$ln - 1]\n";
+				# we have a preceeding printk if it ends
+				# with "\n" ignore it, else it is to blame
+				if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+					if ($rawlines[$ln - 1] !~ m{\\n"}) {
+						$ok = 1;
+					}
+					last;
+				}
+			}
+			if ($ok == 0) {
+				WARN("printk() should include KERN_ facility level\n" . $herecurr);
+			}
+		}
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+		if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
+		    !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
+			ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
+		}
+
+# open braces for enum, union and struct go on the same line.
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+			ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
+		}
+
+# missing space after union, struct or enum definition
+		if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+		    WARN("missing space after $1 definition\n" . $herecurr);
+		}
+
+# check for spacing round square brackets; allowed:
+#  1. with a type on the left -- int [] a;
+#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
+		while ($line =~ /(.*?\s)\[/g) {
+			my ($where, $prefix) = ($-[1], $1);
+			if ($prefix !~ /$Type\s+$/ &&
+			    ($where != 0 || $prefix !~ /^.\s+$/) &&
+			    $prefix !~ /{\s+$/) {
+				ERROR("space prohibited before open square bracket '['\n" . $herecurr);
+			}
+		}
+
+# check for spaces between functions and their parentheses.
+		while ($line =~ /($Ident)\s+\(/g) {
+			my $name = $1;
+			my $ctx_before = substr($line, 0, $-[1]);
+			my $ctx = "$ctx_before$name";
+
+			# Ignore those directives where spaces _are_ permitted.
+			if ($name =~ /^(?:
+				if|for|while|switch|return|case|
+				volatile|__volatile__|
+				__attribute__|format|__extension__|
+				asm|__asm__)$/x)
+			{
+
+			# cpp #define statements have non-optional spaces, ie
+			# if there is a space between the name and the open
+			# parenthesis it is simply not a parameter group.
+			} elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+			# cpp #elif statement condition may start with a (
+			} elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+			# If this whole things ends with a type its most
+			# likely a typedef for a function.
+			} elsif ($ctx =~ /$Type$/) {
+
+			} else {
+				WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr);
+			}
+		}
+# Check operator spacing.
+		if (!($line=~/\#\s*include/)) {
+			my $ops = qr{
+				<<=|>>=|<=|>=|==|!=|
+				\+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+				=>|->|<<|>>|<|>|=|!|~|
+				&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+				\?|:
+			}x;
+			my @elements = split(/($ops|;)/, $opline);
+			my $off = 0;
+
+			my $blank = copy_spacing($opline);
+
+			for (my $n = 0; $n < $#elements; $n += 2) {
+				$off += length($elements[$n]);
+
+				# Pick up the preceeding and succeeding characters.
+				my $ca = substr($opline, 0, $off);
+				my $cc = '';
+				if (length($opline) >= ($off + length($elements[$n + 1]))) {
+					$cc = substr($opline, $off + length($elements[$n + 1]));
+				}
+				my $cb = "$ca$;$cc";
+
+				my $a = '';
+				$a = 'V' if ($elements[$n] ne '');
+				$a = 'W' if ($elements[$n] =~ /\s$/);
+				$a = 'C' if ($elements[$n] =~ /$;$/);
+				$a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+				$a = 'O' if ($elements[$n] eq '');
+				$a = 'E' if ($ca =~ /^\s*$/);
+
+				my $op = $elements[$n + 1];
+
+				my $c = '';
+				if (defined $elements[$n + 2]) {
+					$c = 'V' if ($elements[$n + 2] ne '');
+					$c = 'W' if ($elements[$n + 2] =~ /^\s/);
+					$c = 'C' if ($elements[$n + 2] =~ /^$;/);
+					$c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+					$c = 'O' if ($elements[$n + 2] eq '');
+					$c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+				} else {
+					$c = 'E';
+				}
+
+				my $ctx = "${a}x${c}";
+
+				my $at = "(ctx:$ctx)";
+
+				my $ptr = substr($blank, 0, $off) . "^";
+				my $hereptr = "$hereline$ptr\n";
+
+				# Pull out the value of this operator.
+				my $op_type = substr($curr_values, $off + 1, 1);
+
+				# Get the full operator variant.
+				my $opv = $op . substr($curr_vars, $off, 1);
+
+				# Ignore operators passed as parameters.
+				if ($op_type ne 'V' &&
+				    $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+#				# Ignore comments
+#				} elsif ($op =~ /^$;+$/) {
+
+				# ; should have either the end of line or a space or \ after it
+				} elsif ($op eq ';') {
+					if ($ctx !~ /.x[WEBC]/ &&
+					    $cc !~ /^\\/ && $cc !~ /^;/) {
+						ERROR("space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# // is a comment
+				} elsif ($op eq '//') {
+
+				# No spaces for:
+				#   ->
+				#   :   when part of a bitfield
+				} elsif ($op eq '->' || $opv eq ':B') {
+					if ($ctx =~ /Wx.|.xW/) {
+						ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
+					}
+
+				# , must have a space on the right.
+                                # not required when having a single },{ on one line
+				} elsif ($op eq ',') {
+					if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ &&
+                                            ($elements[$n] . $elements[$n + 2]) !~ " *}{") {
+						ERROR("space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# '*' as part of a type definition -- reported already.
+				} elsif ($opv eq '*_') {
+					#warn "'*' is part of type\n";
+
+				# unary operators should have a space before and
+				# none after.  May be left adjacent to another
+				# unary operator, or a cast
+				} elsif ($op eq '!' || $op eq '~' ||
+					 $opv eq '*U' || $opv eq '-U' ||
+					 $opv eq '&U' || $opv eq '&&U') {
+					if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+						ERROR("space required before that '$op' $at\n" . $hereptr);
+					}
+					if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+						# A unary '*' may be const
+
+					} elsif ($ctx =~ /.xW/) {
+						ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+				# unary ++ and unary -- are allowed no space on one side.
+				} elsif ($op eq '++' or $op eq '--') {
+					if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+						ERROR("space required one side of that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /Wx[BE]/ ||
+					    ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+						ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /ExW/) {
+						ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+
+				# << and >> may either have or not have spaces both sides
+				} elsif ($op eq '<<' or $op eq '>>' or
+					 $op eq '&' or $op eq '^' or $op eq '|' or
+					 $op eq '+' or $op eq '-' or
+					 $op eq '*' or $op eq '/' or
+					 $op eq '%')
+				{
+					if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+						ERROR("need consistent spacing around '$op' $at\n" .
+							$hereptr);
+					}
+
+				# A colon needs no spaces before when it is
+				# terminating a case value or a label.
+				} elsif ($opv eq ':C' || $opv eq ':L') {
+					if ($ctx =~ /Wx./) {
+						ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+					}
+
+				# All the others need spaces both sides.
+				} elsif ($ctx !~ /[EWC]x[CWE]/) {
+					my $ok = 0;
+
+					# Ignore email addresses <foo at bar>
+					if (($op eq '<' &&
+					     $cc =~ /^\S+\@\S+>/) ||
+					    ($op eq '>' &&
+					     $ca =~ /<\S+\@\S+$/))
+					{
+						$ok = 1;
+					}
+
+					# Ignore ?:
+					if (($opv eq ':O' && $ca =~ /\?$/) ||
+					    ($op eq '?' && $cc =~ /^:/)) {
+						$ok = 1;
+					}
+
+					if ($ok == 0) {
+						ERROR("spaces required around that '$op' $at\n" . $hereptr);
+					}
+				}
+				$off += length($elements[$n + 1]);
+			}
+		}
+
+# check for multiple assignments
+		if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+			CHK("multiple assignments should be avoided\n" . $herecurr);
+		}
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+## 		if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+## 		    $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+## 			# Remove any bracketed sections to ensure we do not
+## 			# falsly report the parameters of functions.
+## 			my $ln = $line;
+## 			while ($ln =~ s/\([^\(\)]*\)//g) {
+## 			}
+## 			if ($ln =~ /,/) {
+## 				WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+## 			}
+## 		}
+
+#need space before brace following if, while, etc
+		if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
+		    $line =~ /do{/) {
+			ERROR("space required before the open brace '{'\n" . $herecurr);
+		}
+
+# closing brace should have a space following it when it has anything
+# on the line
+		if ($line =~ /}(?!(?:,|;|\)))\S/) {
+			ERROR("space required after that close brace '}'\n" . $herecurr);
+		}
+
+# check spacing on square brackets
+		if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+			ERROR("space prohibited after that open square bracket '['\n" . $herecurr);
+		}
+		if ($line =~ /\s\]/) {
+			ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
+		}
+
+# check spacing on parentheses
+		if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+		    $line !~ /for\s*\(\s+;/) {
+			ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
+		}
+		if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+		    $line !~ /for\s*\(.*;\s+\)/ &&
+		    $line !~ /:\s+\)/) {
+			ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
+		}
+
+#goto labels aren't indented, allow a single space however
+		if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+		   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+			WARN("labels should not be indented\n" . $herecurr);
+		}
+
+# Return is not a function.
+		if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+			my $spacing = $1;
+			my $value = $2;
+
+			# Flatten any parentheses
+			$value =~ s/\(/ \(/g;
+			$value =~ s/\)/\) /g;
+			while ($value =~ s/\[[^\{\}]*\]/1/ ||
+			       $value !~ /(?:$Ident|-?$Constant)\s*
+					     $Compare\s*
+					     (?:$Ident|-?$Constant)/x &&
+			       $value =~ s/\([^\(\)]*\)/1/) {
+			}
+#print "value<$value>\n";
+			if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
+				ERROR("return is not a function, parentheses are not required\n" . $herecurr);
+
+			} elsif ($spacing !~ /\s+/) {
+				ERROR("space required before the open parenthesis '('\n" . $herecurr);
+			}
+		}
+# Return of what appears to be an errno should normally be -'ve
+		if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+			my $name = $1;
+			if ($name ne 'EOF' && $name ne 'ERROR') {
+				CHK("return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+			}
+		}
+
+# Need a space before open parenthesis after if, while etc
+		if ($line=~/\b(if|while|for|switch)\(/) {
+			ERROR("space required before the open parenthesis '('\n" . $herecurr);
+		}
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+		if ($line =~ /do\s*(?!{)/) {
+			my ($stat_next) = ctx_statement_block($line_nr_next,
+						$remain_next, $off_next);
+			$stat_next =~ s/\n./\n /g;
+			##print "stat<$stat> stat_next<$stat_next>\n";
+
+			if ($stat_next =~ /^\s*while\b/) {
+				# If the statement carries leading newlines,
+				# then count those as offsets.
+				my ($whitespace) =
+					($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+				my $offset =
+					statement_rawlines($whitespace) - 1;
+
+				$suppress_whiletrailers{$line_nr_next +
+								$offset} = 1;
+			}
+		}
+		if (!defined $suppress_whiletrailers{$linenr} &&
+		    $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+			my ($s, $c) = ($stat, $cond);
+
+			if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+				ERROR("do not use assignment in if condition\n" . $herecurr);
+			}
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+			$s =~ s/$;//g; 	# Remove any comments
+			if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+			    $c !~ /}\s*while\s*/)
+			{
+				# Find out how long the conditional actually is.
+				my @newlines = ($c =~ /\n/gs);
+				my $cond_lines = 1 + $#newlines;
+				my $stat_real = '';
+
+				$stat_real = raw_line($linenr, $cond_lines)
+							. "\n" if ($cond_lines);
+				if (defined($stat_real) && $cond_lines > 1) {
+					$stat_real = "[...]\n$stat_real";
+				}
+
+				ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
+			}
+		}
+
+# Check for bitwise tests written as boolean
+		if ($line =~ /
+			(?:
+				(?:\[|\(|\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\|)
+			|
+				(?:\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\||\)|\])
+			)/x)
+		{
+			WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+		}
+
+# if and else should not have general statements after it
+		if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+			my $s = $1;
+			$s =~ s/$;//g; 	# Remove any comments
+			if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+				ERROR("trailing statements should be on next line\n" . $herecurr);
+			}
+		}
+# if should not continue a brace
+		if ($line =~ /}\s*if\b/) {
+			ERROR("trailing statements should be on next line\n" .
+				$herecurr);
+		}
+# case and default should not have general statements after them
+		if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+		    $line !~ /\G(?:
+			(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+			\s*return\s+
+		    )/xg)
+		{
+			ERROR("trailing statements should be on next line\n" . $herecurr);
+		}
+
+		# Check for }<nl>else {, these must be at the same
+		# indent level to be relevant to each other.
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+						$previndent == $indent) {
+			ERROR("else should follow close brace '}'\n" . $hereprev);
+		}
+
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+						$previndent == $indent) {
+			my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+
+			if ($s =~ /^\s*;/) {
+				ERROR("while should follow close brace '}'\n" . $hereprev);
+			}
+		}
+
+#studly caps, commented out until figure out how to distinguish between use of existing and adding new
+#		if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
+#		    print "No studly caps, use _\n";
+#		    print "$herecurr";
+#		    $clean = 0;
+#		}
+
+#no spaces allowed after \ in define
+		if ($line=~/\#\s*define.*\\\s$/) {
+			WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
+		}
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+		if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+			my $file = "$1.h";
+			my $checkfile = "include/linux/$file";
+			if (-f "$root/$checkfile" &&
+			    $realfile ne $checkfile &&
+			    $1 !~ /$allowed_asm_includes/)
+			{
+				if ($realfile =~ m{^arch/}) {
+					CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				} else {
+					WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				}
+			}
+		}
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+		if ($realfile !~ m@/vmlinux.lds.h$@ &&
+		    $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+			my $ln = $linenr;
+			my $cnt = $realcnt;
+			my ($off, $dstat, $dcond, $rest);
+			my $ctx = '';
+
+			my $args = defined($1);
+
+			# Find the end of the macro and limit our statement
+			# search to that.
+			while ($cnt > 0 && defined $lines[$ln - 1] &&
+				$lines[$ln - 1] =~ /^(?:-|..*\\$)/)
+			{
+				$ctx .= $rawlines[$ln - 1] . "\n";
+				$cnt-- if ($lines[$ln - 1] !~ /^-/);
+				$ln++;
+			}
+			$ctx .= $rawlines[$ln - 1];
+
+			($dstat, $dcond, $ln, $cnt, $off) =
+				ctx_statement_block($linenr, $ln - $linenr + 1, 0);
+			#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+			#print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+			# Extract the remainder of the define (if any) and
+			# rip off surrounding spaces, and trailing \'s.
+			$rest = '';
+			while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+				#print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
+				if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
+					$rest .= substr($lines[$ln - 1], $off) . "\n";
+					$cnt--;
+				}
+				$ln++;
+				$off = 0;
+			}
+			$rest =~ s/\\\n.//g;
+			$rest =~ s/^\s*//s;
+			$rest =~ s/\s*$//s;
+
+			# Clean up the original statement.
+			if ($args) {
+				substr($dstat, 0, length($dcond), '');
+			} else {
+				$dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
+			}
+			$dstat =~ s/$;//g;
+			$dstat =~ s/\\\n.//g;
+			$dstat =~ s/^\s*//s;
+			$dstat =~ s/\s*$//s;
+
+			# Flatten any parentheses and braces
+			while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+			       $dstat =~ s/\{[^\{\}]*\}/1/ ||
+			       $dstat =~ s/\[[^\{\}]*\]/1/)
+			{
+			}
+
+			my $exceptions = qr{
+				$Declare|
+				module_param_named|
+				MODULE_PARAM_DESC|
+				DECLARE_PER_CPU|
+				DEFINE_PER_CPU|
+				__typeof__\(|
+				union|
+				struct|
+				\.$Ident\s*=\s*|
+				^\"|\"$
+			}x;
+			#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+			if ($rest ne '' && $rest ne ',') {
+				if ($rest !~ /while\s*\(/ &&
+				    $dstat !~ /$exceptions/)
+				{
+					ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+				}
+
+			} elsif ($ctx !~ /;/) {
+				if ($dstat ne '' &&
+				    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
+				    $dstat !~ /$exceptions/ &&
+				    $dstat !~ /^\.$Ident\s*=/ &&
+				    $dstat =~ /$Operators/)
+				{
+					ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+				}
+			}
+		}
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+#	.
+#	ALIGN(...)
+#	VMLINUX_SYMBOL(...)
+		if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+			WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+		}
+
+# check for missing bracing round if etc
+		if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) {
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, 1);
+			#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+			#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+			if ($#chunks >= 0 && $level == 0) {
+				my $allowed = 0;
+				my $seen = 0;
+				my $herectx = $here . "\n";
+				my $ln = $linenr - 1;
+				for my $chunk (@chunks) {
+					my ($cond, $block) = @{$chunk};
+
+					# If the condition carries leading newlines, then count those as offsets.
+					my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+					my $offset = statement_rawlines($whitespace) - 1;
+
+					#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+					# We have looked at and allowed this specific line.
+					$suppress_ifbraces{$ln + $offset} = 1;
+
+					$herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+					$ln += statement_rawlines($block) - 1;
+
+					substr($block, 0, length($cond), '');
+
+					$seen++ if ($block =~ /^\s*{/);
+
+					#print "cond<$cond> block<$block> allowed<$allowed>\n";
+					if (statement_lines($cond) > 1) {
+						#print "APW: ALLOWED: cond<$cond>\n";
+						$allowed = 1;
+					}
+					if ($block =~/\b(?:if|for|while)\b/) {
+						#print "APW: ALLOWED: block<$block>\n";
+						$allowed = 1;
+					}
+					if (statement_block_size($block) > 1) {
+						#print "APW: ALLOWED: lines block<$block>\n";
+						$allowed = 1;
+					}
+				}
+				if (!$seen) {
+					WARN("braces {} are necessary for all arms of this statement\n" . $herectx);
+				}
+			}
+		}
+		if (!defined $suppress_ifbraces{$linenr - 1} &&
+					$line =~ /\b(if|while|for|else)\b/ &&
+					$line !~ /\#\s*if/ &&
+					$line !~ /\#\s*else/) {
+			my $allowed = 0;
+
+			# Check the pre-context.
+			if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+				#print "APW: ALLOWED: pre<$1>\n";
+				$allowed = 1;
+			}
+
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, $-[0]);
+
+			# Check the condition.
+			my ($cond, $block) = @{$chunks[0]};
+			#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+			if (defined $cond) {
+				substr($block, 0, length($cond), '');
+			}
+			if (statement_lines($cond) > 1) {
+				#print "APW: ALLOWED: cond<$cond>\n";
+				$allowed = 1;
+			}
+			if ($block =~/\b(?:if|for|while)\b/) {
+				#print "APW: ALLOWED: block<$block>\n";
+				$allowed = 1;
+			}
+			if (statement_block_size($block) > 1) {
+				#print "APW: ALLOWED: lines block<$block>\n";
+				$allowed = 1;
+			}
+			# Check the post-context.
+			if (defined $chunks[1]) {
+				my ($cond, $block) = @{$chunks[1]};
+				if (defined $cond) {
+					substr($block, 0, length($cond), '');
+				}
+				if ($block =~ /^\s*\{/) {
+					#print "APW: ALLOWED: chunk-1 block<$block>\n";
+					$allowed = 1;
+				}
+			}
+			if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) {
+				my $herectx = $here . "\n";;
+				my $cnt = statement_rawlines($block);
+
+				for (my $n = 0; $n < $cnt; $n++) {
+					$herectx .= raw_line($linenr, $n) . "\n";;
+				}
+
+				WARN("braces {} are necessary even for single statement blocks\n" . $herectx);
+			}
+		}
+
+# don't include deprecated include files (uses RAW line)
+		for my $inc (@dep_includes) {
+			if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
+				ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+			}
+		}
+
+# don't use deprecated functions
+		for my $func (@dep_functions) {
+			if ($line =~ /\b$func\b/) {
+				ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+			}
+		}
+
+# no volatiles please
+		my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+		if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+			WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+		}
+
+# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
+		if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
+			ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr);
+		}
+
+# warn about #if 0
+		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+			CHK("if this code is redundant consider removing it\n" .
+				$herecurr);
+		}
+
+# check for needless kfree() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+				WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+# check for needless usb_free_urb() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+				WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+
+# prefer usleep_range over udelay
+		if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) {
+			# ignore udelay's < 10, however
+			if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) {
+				CHK("usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
+			}
+		}
+
+# warn about unexpectedly long msleep's
+		if ($line =~ /\bmsleep\s*\((\d+)\);/) {
+			if ($1 < 20) {
+				WARN("msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line);
+			}
+		}
+
+# warn about #ifdefs in C files
+#		if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+#			print "#ifdef in C files should be avoided\n";
+#			print "$herecurr";
+#			$clean = 0;
+#		}
+
+# warn about spacing in #ifdefs
+		if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+			ERROR("exactly one space required after that #$1\n" . $herecurr);
+		}
+
+# check for spinlock_t definitions without a comment.
+		if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+		    $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+			my $which = $1;
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("$1 definition without comment\n" . $herecurr);
+			}
+		}
+# check for memory barriers without a comment.
+		if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("memory barrier without comment\n" . $herecurr);
+			}
+		}
+# check of hardware specific defines
+		if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m at include/asm-@) {
+			CHK("architecture specific defines should be avoided\n" .  $herecurr);
+		}
+
+# Check that the storage class is at the beginning of a declaration
+		if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+			WARN("storage class should be at the beginning of the declaration\n" . $herecurr)
+		}
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+		if ($line =~ /\b$Type\s+$Inline\b/ ||
+		    $line =~ /\b$Inline\s+$Storage\b/) {
+			ERROR("inline keyword should sit between storage class and type\n" . $herecurr);
+		}
+
+# Check for __inline__ and __inline, prefer inline
+		if ($line =~ /\b(__inline__|__inline)\b/) {
+			WARN("plain inline is preferred over $1\n" . $herecurr);
+		}
+
+# check for sizeof(&)
+		if ($line =~ /\bsizeof\s*\(\s*\&/) {
+			WARN("sizeof(& should be avoided\n" . $herecurr);
+		}
+
+# check for new externs in .c files.
+		if ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+		{
+			my $function_name = $1;
+			my $paren_space = $2;
+
+			my $s = $stat;
+			if (defined $cond) {
+				substr($s, 0, length($cond), '');
+			}
+			if ($s =~ /^\s*;/ &&
+			    $function_name ne 'uninitialized_var')
+			{
+				WARN("externs should be avoided in .c files\n" .  $herecurr);
+			}
+
+			if ($paren_space =~ /\n/) {
+				WARN("arguments for function declarations should follow identifier\n" . $herecurr);
+			}
+
+		} elsif ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*extern\s+/)
+		{
+			WARN("externs should be avoided in .c files\n" .  $herecurr);
+		}
+
+# checks for new __setup's
+		if ($rawline =~ /\b__setup\("([^"]*)"/) {
+			my $name = $1;
+
+			if (!grep(/$name/, @setup_docs)) {
+				CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+			}
+		}
+
+# check for pointless casting of kmalloc return
+		if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) {
+			WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+		}
+
+# check for gcc specific __FUNCTION__
+		if ($line =~ /__FUNCTION__/) {
+			WARN("__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
+		}
+
+# check for semaphores used as mutexes
+		if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+			WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
+		}
+# check for semaphores used as mutexes
+		if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
+			WARN("consider using a completion\n" . $herecurr);
+
+		}
+# recommend strict_strto* over simple_strto*
+		if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+			WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+		}
+# check for __initcall(), use device_initcall() explicitly please
+		if ($line =~ /^.\s*__initcall\s*\(/) {
+			WARN("please use device_initcall() instead of __initcall()\n" . $herecurr);
+		}
+# check for various ops structs, ensure they are const.
+		my $struct_ops = qr{acpi_dock_ops|
+				address_space_operations|
+				backlight_ops|
+				block_device_operations|
+				dentry_operations|
+				dev_pm_ops|
+				dma_map_ops|
+				extent_io_ops|
+				file_lock_operations|
+				file_operations|
+				hv_ops|
+				ide_dma_ops|
+				intel_dvo_dev_ops|
+				item_operations|
+				iwl_ops|
+				kgdb_arch|
+				kgdb_io|
+				kset_uevent_ops|
+				lock_manager_operations|
+				microcode_ops|
+				mtrr_ops|
+				neigh_ops|
+				nlmsvc_binding|
+				pci_raw_ops|
+				pipe_buf_operations|
+				platform_hibernation_ops|
+				platform_suspend_ops|
+				proto_ops|
+				rpc_pipe_ops|
+				seq_operations|
+				snd_ac97_build_ops|
+				soc_pcmcia_socket_ops|
+				stacktrace_ops|
+				sysfs_ops|
+				tty_operations|
+				usb_mon_operations|
+				wd_ops}x;
+		if ($line !~ /\bconst\b/ &&
+		    $line =~ /\bstruct\s+($struct_ops)\b/) {
+			WARN("struct $1 should normally be const\n" .
+				$herecurr);
+		}
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+		if ($line =~ /\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+		{
+			WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+		}
+
+# check for %L{u,d,i} in strings
+		my $string;
+		while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+			$string = substr($rawline, $-[1], $+[1] - $-[1]);
+			$string =~ s/%%/__/g;
+			if ($string =~ /(?<!%)%L[udi]/) {
+				WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+				last;
+			}
+		}
+
+# whine mightly about in_atomic
+		if ($line =~ /\bin_atomic\s*\(/) {
+			if ($realfile =~ m@^drivers/@) {
+				ERROR("do not use in_atomic in drivers\n" . $herecurr);
+			} elsif ($realfile !~ m@^kernel/@) {
+				WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+			}
+		}
+
+# check for lockdep_set_novalidate_class
+		if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
+		    $line =~ /__lockdep_no_validate__\s*\)/ ) {
+			if ($realfile !~ m@^kernel/lockdep@ &&
+			    $realfile !~ m@^include/linux/lockdep@ &&
+			    $realfile !~ m@^drivers/base/core@) {
+				ERROR("lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
+			}
+		}
+	}
+
+	# If we have no input at all, then there is nothing to report on
+	# so just keep quiet.
+	if ($#rawlines == -1) {
+		exit(0);
+	}
+
+	# In mailback mode only produce a report in the negative, for
+	# things that appear to be patches.
+	if ($mailback && ($clean == 1 || !$is_patch)) {
+		exit(0);
+	}
+
+	# This is not a patch, and we are are in 'no-patch' mode so
+	# just keep quiet.
+	if (!$chk_patch && !$is_patch) {
+		exit(0);
+	}
+
+	if (!$is_patch) {
+		ERROR("Does not appear to be a unified-diff format patch\n");
+	}
+	if ($is_patch && $chk_signoff && $signoff == 0) {
+		ERROR("Missing Signed-off-by: line(s)\n");
+	}
+
+	print report_dump();
+	if ($summary && !($clean == 1 && $quiet == 1)) {
+		print "$filename " if ($summary_file);
+		print "total: $cnt_error errors, $cnt_warn warnings, " .
+			(($check)? "$cnt_chk checks, " : "") .
+			"$cnt_lines lines checked\n";
+		print "\n" if ($quiet == 0);
+	}
+
+	if ($quiet == 0) {
+		# If there were whitespace errors which cleanpatch can fix
+		# then suggest that.
+#		if ($rpt_cleaners) {
+#			print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+#			print "      scripts/cleanfile\n\n";
+#		}
+	}
+
+	if ($clean == 1 && $quiet == 0) {
+		print "$vname has no obvious style problems and is ready for submission.\n"
+	}
+	if ($clean == 0 && $quiet == 0) {
+		print "$vname has style problems, please review.  If any of these errors\n";
+		print "are false positives report them to the maintainer, see\n";
+		print "CHECKPATCH in MAINTAINERS.\n";
+	}
+
+	return $clean;
+}
diff --git a/qemu-0.15.x/scripts/create_config b/qemu-0.15.x/scripts/create_config
new file mode 100755
index 0000000..0098e68
--- /dev/null
+++ b/qemu-0.15.x/scripts/create_config
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+echo "/* Automatically generated by create_config - do not modify */"
+
+while read line; do
+
+case $line in
+ VERSION=*) # configuration
+    version=${line#*=}
+    echo "#define QEMU_VERSION \"$version\""
+    ;;
+ PKGVERSION=*) # configuration
+    pkgversion=${line#*=}
+    echo "#define QEMU_PKGVERSION \"$pkgversion\""
+    ;;
+ prefix=* | [a-z]*dir=*) # directory configuration
+    name=${line%=*}
+    value=${line#*=}
+    define_name=`echo $name | tr '[:lower:]' '[:upper:]'`
+    eval "define_value=\"$value\""
+    echo "#define CONFIG_QEMU_$define_name \"$define_value\""
+    # save for the next definitions
+    eval "$name=\$define_value"
+    ;;
+ CONFIG_AUDIO_DRIVERS=*)
+    drivers=${line#*=}
+    echo "#define CONFIG_AUDIO_DRIVERS \\"
+    for drv in $drivers; do
+      echo "    &${drv}_audio_driver,\\"
+    done
+    echo ""
+    ;;
+ CONFIG_BDRV_WHITELIST=*)
+    echo "#define CONFIG_BDRV_WHITELIST \\"
+    for drv in ${line#*=}; do
+      echo "    \"${drv}\",\\"
+    done
+    echo "    NULL"
+    ;;
+ CONFIG_*=y) # configuration
+    name=${line%=*}
+    echo "#define $name 1"
+    ;;
+ CONFIG_*=*) # configuration
+    name=${line%=*}
+    value=${line#*=}
+    echo "#define $name $value"
+    ;;
+ ARCH=*) # configuration
+    arch=${line#*=}
+    arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
+    echo "#define HOST_$arch_name 1"
+    ;;
+ HOST_USB=*)
+    # do nothing
+    ;;
+ HOST_CC=*)
+    # do nothing
+    ;;
+ HOST_*=y) # configuration
+    name=${line%=*}
+    echo "#define $name 1"
+    ;;
+ HOST_*=*) # configuration
+    name=${line%=*}
+    value=${line#*=}
+    echo "#define $name $value"
+    ;;
+ TARGET_ARCH=*) # configuration
+    target_arch=${line#*=}
+    echo "#define TARGET_ARCH \"$target_arch\""
+    ;;
+ TARGET_BASE_ARCH=*) # configuration
+    target_base_arch=${line#*=}
+    if [ "$target_base_arch" != "$target_arch" ]; then
+      base_arch_name=`echo $target_base_arch | tr '[:lower:]' '[:upper:]'`
+      echo "#define TARGET_$base_arch_name 1"
+    fi
+    ;;
+ TARGET_XML_FILES=*)
+    # do nothing
+    ;;
+ TARGET_ABI_DIR=*)
+    # do nothing
+    ;;
+ TARGET_ARCH2=*)
+    # do nothing
+    ;;
+ TARGET_DIRS=*)
+    # do nothing
+    ;;
+ TARGET_*=y) # configuration
+    name=${line%=*}
+    echo "#define $name 1"
+    ;;
+ TARGET_*=*) # configuration
+    name=${line%=*}
+    value=${line#*=}
+    echo "#define $name $value"
+    ;;
+esac
+
+done # read
diff --git a/qemu-0.15.x/scripts/feature_to_c.sh b/qemu-0.15.x/scripts/feature_to_c.sh
new file mode 100644
index 0000000..b62da8a
--- /dev/null
+++ b/qemu-0.15.x/scripts/feature_to_c.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# Convert text files to compilable C arrays.
+#
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+output=$1
+shift
+
+if test -z "$output" || test -z "$1"; then
+  echo "Usage: $0 OUTPUTFILE INPUTFILE..."
+  exit 1
+fi
+
+if test -e "$output"; then
+  echo "Output file \"$output\" already exists; refusing to overwrite."
+  exit 1
+fi
+
+for input; do
+  arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
+
+  ${AWK:-awk} 'BEGIN { n = 0
+      printf "#include \"config.h\"\n"
+      printf "#include \"qemu-common.h\"\n"
+      printf "#include \"gdbstub.h\"\n"
+      print "static const char '$arrayname'[] = {"
+      for (i = 0; i < 255; i++)
+        _ord_[sprintf("%c", i)] = i
+    } {
+      split($0, line, "");
+      printf "  "
+      for (i = 1; i <= length($0); i++) {
+        c = line[i]
+        if (c == "'\''") {
+          printf "'\''\\'\'''\'', "
+        } else if (c == "\\") {
+          printf "'\''\\\\'\'', "
+        } else if (_ord_[c] >= 32 && _ord_[c] < 127) {
+	  printf "'\''%s'\'', ", c
+        } else {
+          printf "'\''\\%03o'\'', ", _ord_[c]
+        }
+        if (i % 10 == 0)
+          printf "\n   "
+      }
+      printf "'\''\\n'\'', \n"
+    } END {
+      print "  0 };"
+    }' < $input >> $output
+done
+
+echo >> $output
+echo "const char *const xml_builtin[][2] = {" >> $output
+
+for input; do
+  basename=`echo $input | sed 's,.*/,,'`
+  arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
+  echo "  { \"$basename\", $arrayname }," >> $output
+done
+
+echo "  { (char *)0, (char *)0 }" >> $output
+echo "};" >> $output
diff --git a/qemu-0.15.x/scripts/get_maintainer.pl b/qemu-0.15.x/scripts/get_maintainer.pl
new file mode 100755
index 0000000..d9c48e0
--- /dev/null
+++ b/qemu-0.15.x/scripts/get_maintainer.pl
@@ -0,0 +1,2149 @@
+#!/usr/bin/perl -w
+# (c) 2007, Joe Perches <joe at perches.com>
+#           created from checkpatch.pl
+#
+# Print selected MAINTAINERS information for
+# the files modified in a patch or for a file
+#
+# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
+#        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
+#
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+my $V = '0.26';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $lk_path = "./";
+my $email = 1;
+my $email_usename = 1;
+my $email_maintainer = 1;
+my $email_list = 1;
+my $email_subscriber_list = 0;
+my $email_git_penguin_chiefs = 0;
+my $email_git = 0;
+my $email_git_all_signature_types = 0;
+my $email_git_blame = 0;
+my $email_git_blame_signatures = 1;
+my $email_git_fallback = 1;
+my $email_git_min_signatures = 1;
+my $email_git_max_maintainers = 5;
+my $email_git_min_percent = 5;
+my $email_git_since = "1-year-ago";
+my $email_hg_since = "-365";
+my $interactive = 0;
+my $email_remove_duplicates = 1;
+my $email_use_mailmap = 1;
+my $output_multiline = 1;
+my $output_separator = ", ";
+my $output_roles = 0;
+my $output_rolestats = 1;
+my $scm = 0;
+my $web = 0;
+my $subsystem = 0;
+my $status = 0;
+my $keywords = 1;
+my $sections = 0;
+my $file_emails = 0;
+my $from_filename = 0;
+my $pattern_depth = 0;
+my $version = 0;
+my $help = 0;
+
+my $vcs_used = 0;
+
+my $exit = 0;
+
+my %commit_author_hash;
+my %commit_signer_hash;
+
+my @penguin_chief = ();
+push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
+#Andrew wants in on most everything - 2009/01/14
+#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
+
+my @penguin_chief_names = ();
+foreach my $chief (@penguin_chief) {
+    if ($chief =~ m/^(.*):(.*)/) {
+	my $chief_name = $1;
+	my $chief_addr = $2;
+	push(@penguin_chief_names, $chief_name);
+    }
+}
+my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+
+# Signature types of people who are either
+# 	a) responsible for the code in question, or
+# 	b) familiar enough with it to give relevant feedback
+my @signature_tags = ();
+push(@signature_tags, "Signed-off-by:");
+push(@signature_tags, "Reviewed-by:");
+push(@signature_tags, "Acked-by:");
+
+# rfc822 email address - preloaded methods go here.
+my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
+my $rfc822_char = '[\\000-\\377]';
+
+# VCS command support: class-like functions and strings
+
+my %VCS_cmds;
+
+my %VCS_cmds_git = (
+    "execute_cmd" => \&git_execute_cmd,
+    "available" => '(which("git") ne "") && (-d ".git")',
+    "find_signers_cmd" =>
+	"git log --no-color --since=\$email_git_since " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n' .
+		      '%b%n"' .
+	    " -- \$file",
+    "find_commit_signers_cmd" =>
+	"git log --no-color " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n' .
+		      '%b%n"' .
+	    " -1 \$commit",
+    "find_commit_author_cmd" =>
+	"git log --no-color " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n"' .
+	    " -1 \$commit",
+    "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
+    "blame_file_cmd" => "git blame -l \$file",
+    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([0-9a-f]+) ",
+    "author_pattern" => "^GitAuthor: (.*)",
+    "subject_pattern" => "^GitSubject: (.*)",
+);
+
+my %VCS_cmds_hg = (
+    "execute_cmd" => \&hg_execute_cmd,
+    "available" => '(which("hg") ne "") && (-d ".hg")',
+    "find_signers_cmd" =>
+	"hg log --date=\$email_hg_since " .
+	    "--template='HgCommit: {node}\\n" .
+	                "HgAuthor: {author}\\n" .
+			"HgSubject: {desc}\\n'" .
+	    " -- \$file",
+    "find_commit_signers_cmd" =>
+	"hg log " .
+	    "--template='HgSubject: {desc}\\n'" .
+	    " -r \$commit",
+    "find_commit_author_cmd" =>
+	"hg log " .
+	    "--template='HgCommit: {node}\\n" .
+		        "HgAuthor: {author}\\n" .
+			"HgSubject: {desc|firstline}\\n'" .
+	    " -r \$commit",
+    "blame_range_cmd" => "",		# not supported
+    "blame_file_cmd" => "hg blame -n \$file",
+    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([ 0-9a-f]+):",
+    "author_pattern" => "^HgAuthor: (.*)",
+    "subject_pattern" => "^HgSubject: (.*)",
+);
+
+my $conf = which_conf(".get_maintainer.conf");
+if (-f $conf) {
+    my @conf_args;
+    open(my $conffile, '<', "$conf")
+	or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+
+    while (<$conffile>) {
+	my $line = $_;
+
+	$line =~ s/\s*\n?$//g;
+	$line =~ s/^\s*//g;
+	$line =~ s/\s+/ /g;
+
+	next if ($line =~ m/^\s*#/);
+	next if ($line =~ m/^\s*$/);
+
+	my @words = split(" ", $line);
+	foreach my $word (@words) {
+	    last if ($word =~ m/^#/);
+	    push (@conf_args, $word);
+	}
+    }
+    close($conffile);
+    unshift(@ARGV, @conf_args) if @conf_args;
+}
+
+if (!GetOptions(
+		'email!' => \$email,
+		'git!' => \$email_git,
+		'git-all-signature-types!' => \$email_git_all_signature_types,
+		'git-blame!' => \$email_git_blame,
+		'git-blame-signatures!' => \$email_git_blame_signatures,
+		'git-fallback!' => \$email_git_fallback,
+		'git-chief-penguins!' => \$email_git_penguin_chiefs,
+		'git-min-signatures=i' => \$email_git_min_signatures,
+		'git-max-maintainers=i' => \$email_git_max_maintainers,
+		'git-min-percent=i' => \$email_git_min_percent,
+		'git-since=s' => \$email_git_since,
+		'hg-since=s' => \$email_hg_since,
+		'i|interactive!' => \$interactive,
+		'remove-duplicates!' => \$email_remove_duplicates,
+		'mailmap!' => \$email_use_mailmap,
+		'm!' => \$email_maintainer,
+		'n!' => \$email_usename,
+		'l!' => \$email_list,
+		's!' => \$email_subscriber_list,
+		'multiline!' => \$output_multiline,
+		'roles!' => \$output_roles,
+		'rolestats!' => \$output_rolestats,
+		'separator=s' => \$output_separator,
+		'subsystem!' => \$subsystem,
+		'status!' => \$status,
+		'scm!' => \$scm,
+		'web!' => \$web,
+		'pattern-depth=i' => \$pattern_depth,
+		'k|keywords!' => \$keywords,
+		'sections!' => \$sections,
+		'fe|file-emails!' => \$file_emails,
+		'f|file' => \$from_filename,
+		'v|version' => \$version,
+		'h|help|usage' => \$help,
+		)) {
+    die "$P: invalid argument - use --help if necessary\n";
+}
+
+if ($help != 0) {
+    usage();
+    exit 0;
+}
+
+if ($version != 0) {
+    print("${P} ${V}\n");
+    exit 0;
+}
+
+if (-t STDIN && !@ARGV) {
+    # We're talking to a terminal, but have no command line arguments.
+    die "$P: missing patchfile or -f file - use --help if necessary\n";
+}
+
+$output_multiline = 0 if ($output_separator ne ", ");
+$output_rolestats = 1 if ($interactive);
+$output_roles = 1 if ($output_rolestats);
+
+if ($sections) {
+    $email = 0;
+    $email_list = 0;
+    $scm = 0;
+    $status = 0;
+    $subsystem = 0;
+    $web = 0;
+    $keywords = 0;
+    $interactive = 0;
+} else {
+    my $selections = $email + $scm + $status + $subsystem + $web;
+    if ($selections == 0) {
+	die "$P:  Missing required option: email, scm, status, subsystem or web\n";
+    }
+}
+
+if ($email &&
+    ($email_maintainer + $email_list + $email_subscriber_list +
+     $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
+    die "$P: Please select at least 1 email option\n";
+}
+
+if (!top_of_tree($lk_path)) {
+    die "$P: The current directory does not appear to be "
+	. "a QEMU source tree.\n";
+}
+
+## Read MAINTAINERS for type/value pairs
+
+my @typevalue = ();
+my %keyword_hash;
+
+open (my $maint, '<', "${lk_path}MAINTAINERS")
+    or die "$P: Can't open MAINTAINERS: $!\n";
+while (<$maint>) {
+    my $line = $_;
+
+    if ($line =~ m/^(\C):\s*(.*)/) {
+	my $type = $1;
+	my $value = $2;
+
+	##Filename pattern matching
+	if ($type eq "F" || $type eq "X") {
+	    $value =~ s@\.@\\\. at g;       ##Convert . to \.
+	    $value =~ s/\*/\.\*/g;       ##Convert * to .*
+	    $value =~ s/\?/\./g;         ##Convert ? to .
+	    ##if pattern is a directory and it lacks a trailing slash, add one
+	    if ((-d $value)) {
+		$value =~ s@([^/])$@$1/@;
+	    }
+	} elsif ($type eq "K") {
+	    $keyword_hash{@typevalue} = $value;
+	}
+	push(@typevalue, "$type:$value");
+    } elsif (!/^(\s)*$/) {
+	$line =~ s/\n$//g;
+	push(@typevalue, $line);
+    }
+}
+close($maint);
+
+
+#
+# Read mail address map
+#
+
+my $mailmap;
+
+read_mailmap();
+
+sub read_mailmap {
+    $mailmap = {
+	names => {},
+	addresses => {}
+    };
+
+    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+
+    open(my $mailmap_file, '<', "${lk_path}.mailmap")
+	or warn "$P: Can't open .mailmap: $!\n";
+
+    while (<$mailmap_file>) {
+	s/#.*$//; #strip comments
+	s/^\s+|\s+$//g; #trim
+
+	next if (/^\s*$/); #skip empty lines
+	#entries have one of the following formats:
+	# name1 <mail1>
+	# <mail1> <mail2>
+	# name1 <mail1> <mail2>
+	# name1 <mail1> name2 <mail2>
+	# (see man git-shortlog)
+	if (/^(.+)<(.+)>$/) {
+	    my $real_name = $1;
+	    my $address = $2;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $address) = parse_email("$real_name <$address>");
+	    $mailmap->{names}->{$address} = $real_name;
+
+	} elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
+	    my $real_address = $1;
+	    my $wrong_address = $2;
+
+	    $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+	} elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
+	    my $real_name = $1;
+	    my $real_address = $2;
+	    my $wrong_address = $3;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $real_address) =
+		parse_email("$real_name <$real_address>");
+	    $mailmap->{names}->{$wrong_address} = $real_name;
+	    $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+	} elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) {
+	    my $real_name = $1;
+	    my $real_address = $2;
+	    my $wrong_name = $3;
+	    my $wrong_address = $4;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $real_address) =
+		parse_email("$real_name <$real_address>");
+
+	    $wrong_name =~ s/\s+$//;
+	    ($wrong_name, $wrong_address) =
+		parse_email("$wrong_name <$wrong_address>");
+
+	    my $wrong_email = format_email($wrong_name, $wrong_address, 1);
+	    $mailmap->{names}->{$wrong_email} = $real_name;
+	    $mailmap->{addresses}->{$wrong_email} = $real_address;
+	}
+    }
+    close($mailmap_file);
+}
+
+## use the filenames on the command line or find the filenames in the patchfiles
+
+my @files = ();
+my @range = ();
+my @keyword_tvi = ();
+my @file_emails = ();
+
+if (!@ARGV) {
+    push(@ARGV, "&STDIN");
+}
+
+foreach my $file (@ARGV) {
+    if ($file ne "&STDIN") {
+	##if $file is a directory and it lacks a trailing slash, add one
+	if ((-d $file)) {
+	    $file =~ s@([^/])$@$1/@;
+	} elsif (!(-f $file)) {
+	    die "$P: file '${file}' not found\n";
+	}
+    }
+    if ($from_filename) {
+	push(@files, $file);
+	if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
+	    open(my $f, '<', $file)
+		or die "$P: Can't open $file: $!\n";
+	    my $text = do { local($/) ; <$f> };
+	    close($f);
+	    if ($keywords) {
+		foreach my $line (keys %keyword_hash) {
+		    if ($text =~ m/$keyword_hash{$line}/x) {
+			push(@keyword_tvi, $line);
+		    }
+		}
+	    }
+	    if ($file_emails) {
+		my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g;
+		push(@file_emails, clean_file_emails(@poss_addr));
+	    }
+	}
+    } else {
+	my $file_cnt = @files;
+	my $lastfile;
+
+	open(my $patch, "< $file")
+	    or die "$P: Can't open $file: $!\n";
+
+	# We can check arbitrary information before the patch
+	# like the commit message, mail headers, etc...
+	# This allows us to match arbitrary keywords against any part
+	# of a git format-patch generated file (subject tags, etc...)
+
+	my $patch_prefix = "";			#Parsing the intro
+
+	while (<$patch>) {
+	    my $patch_line = $_;
+	    if (m/^\+\+\+\s+(\S+)/) {
+		my $filename = $1;
+		$filename =~ s@^[^/]*/@@;
+		$filename =~ s@\n@@;
+		$lastfile = $filename;
+		push(@files, $filename);
+		$patch_prefix = "^[+-].*";	#Now parsing the actual patch
+	    } elsif (m/^\@\@ -(\d+),(\d+)/) {
+		if ($email_git_blame) {
+		    push(@range, "$lastfile:$1:$2");
+		}
+	    } elsif ($keywords) {
+		foreach my $line (keys %keyword_hash) {
+		    if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
+			push(@keyword_tvi, $line);
+		    }
+		}
+	    }
+	}
+	close($patch);
+
+	if ($file_cnt == @files) {
+	    warn "$P: file '${file}' doesn't appear to be a patch.  "
+		. "Add -f to options?\n";
+	}
+	@files = sort_and_uniq(@files);
+    }
+}
+
+ at file_emails = uniq(@file_emails);
+
+my %email_hash_name;
+my %email_hash_address;
+my @email_to = ();
+my %hash_list_to;
+my @list_to = ();
+my @scm = ();
+my @web = ();
+my @subsystem = ();
+my @status = ();
+my %deduplicate_name_hash = ();
+my %deduplicate_address_hash = ();
+my $signature_pattern;
+
+my @maintainers = get_maintainers();
+
+if (@maintainers) {
+    @maintainers = merge_email(@maintainers);
+    output(@maintainers);
+}
+
+if ($scm) {
+    @scm = uniq(@scm);
+    output(@scm);
+}
+
+if ($status) {
+    @status = uniq(@status);
+    output(@status);
+}
+
+if ($subsystem) {
+    @subsystem = uniq(@subsystem);
+    output(@subsystem);
+}
+
+if ($web) {
+    @web = uniq(@web);
+    output(@web);
+}
+
+exit($exit);
+
+sub range_is_maintained {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+	my $line = $typevalue[$i];
+	if ($line =~ m/^(\C):\s*(.*)/) {
+	    my $type = $1;
+	    my $value = $2;
+	    if ($type eq 'S') {
+		if ($value =~ /(maintain|support)/i) {
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+sub range_has_maintainer {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+	my $line = $typevalue[$i];
+	if ($line =~ m/^(\C):\s*(.*)/) {
+	    my $type = $1;
+	    my $value = $2;
+	    if ($type eq 'M') {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+sub get_maintainers {
+    %email_hash_name = ();
+    %email_hash_address = ();
+    %commit_author_hash = ();
+    %commit_signer_hash = ();
+    @email_to = ();
+    %hash_list_to = ();
+    @list_to = ();
+    @scm = ();
+    @web = ();
+    @subsystem = ();
+    @status = ();
+    %deduplicate_name_hash = ();
+    %deduplicate_address_hash = ();
+    if ($email_git_all_signature_types) {
+	$signature_pattern = "(.+?)[Bb][Yy]:";
+    } else {
+	$signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+    }
+
+    # Find responsible parties
+
+    my %exact_pattern_match_hash = ();
+
+    foreach my $file (@files) {
+
+	my %hash;
+	my $tvi = find_first_section();
+	while ($tvi < @typevalue) {
+	    my $start = find_starting_index($tvi);
+	    my $end = find_ending_index($tvi);
+	    my $exclude = 0;
+	    my $i;
+
+	    #Do not match excluded file patterns
+
+	    for ($i = $start; $i < $end; $i++) {
+		my $line = $typevalue[$i];
+		if ($line =~ m/^(\C):\s*(.*)/) {
+		    my $type = $1;
+		    my $value = $2;
+		    if ($type eq 'X') {
+			if (file_match_pattern($file, $value)) {
+			    $exclude = 1;
+			    last;
+			}
+		    }
+		}
+	    }
+
+	    if (!$exclude) {
+		for ($i = $start; $i < $end; $i++) {
+		    my $line = $typevalue[$i];
+		    if ($line =~ m/^(\C):\s*(.*)/) {
+			my $type = $1;
+			my $value = $2;
+			if ($type eq 'F') {
+			    if (file_match_pattern($file, $value)) {
+				my $value_pd = ($value =~ tr@/@@);
+				my $file_pd = ($file  =~ tr@/@@);
+				$value_pd++ if (substr($value,-1,1) ne "/");
+				$value_pd = -1 if ($value =~ /^\.\*/);
+				if ($value_pd >= $file_pd &&
+				    range_is_maintained($start, $end) &&
+				    range_has_maintainer($start, $end)) {
+				    $exact_pattern_match_hash{$file} = 1;
+				}
+				if ($pattern_depth == 0 ||
+				    (($file_pd - $value_pd) < $pattern_depth)) {
+				    $hash{$tvi} = $value_pd;
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	    $tvi = $end + 1;
+	}
+
+	foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+	    add_categories($line);
+	    if ($sections) {
+		my $i;
+		my $start = find_starting_index($line);
+		my $end = find_ending_index($line);
+		for ($i = $start; $i < $end; $i++) {
+		    my $line = $typevalue[$i];
+		    if ($line =~ /^[FX]:/) {		##Restore file patterns
+			$line =~ s/([^\\])\.([^\*])/$1\?$2/g;
+			$line =~ s/([^\\])\.$/$1\?/g;	##Convert . back to ?
+			$line =~ s/\\\./\./g;       	##Convert \. to .
+			$line =~ s/\.\*/\*/g;       	##Convert .* to *
+		    }
+		    $line =~ s/^([A-Z]):/$1:\t/g;
+		    print("$line\n");
+		}
+		print("\n");
+	    }
+	}
+    }
+
+    if ($keywords) {
+	@keyword_tvi = sort_and_uniq(@keyword_tvi);
+	foreach my $line (@keyword_tvi) {
+	    add_categories($line);
+	}
+    }
+
+    foreach my $email (@email_to, @list_to) {
+	$email->[0] = deduplicate_email($email->[0]);
+    }
+
+    foreach my $file (@files) {
+	if ($email &&
+	    ($email_git || ($email_git_fallback &&
+			    !$exact_pattern_match_hash{$file}))) {
+	    vcs_file_signoffs($file);
+	}
+	if ($email && $email_git_blame) {
+	    vcs_file_blame($file);
+	}
+    }
+
+    if ($email) {
+	foreach my $chief (@penguin_chief) {
+	    if ($chief =~ m/^(.*):(.*)/) {
+		my $email_address;
+
+		$email_address = format_email($1, $2, $email_usename);
+		if ($email_git_penguin_chiefs) {
+		    push(@email_to, [$email_address, 'chief penguin']);
+		} else {
+		    @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+		}
+	    }
+	}
+
+	foreach my $email (@file_emails) {
+	    my ($name, $address) = parse_email($email);
+
+	    my $tmp_email = format_email($name, $address, $email_usename);
+	    push_email_address($tmp_email, '');
+	    add_role($tmp_email, 'in file');
+	}
+    }
+
+    my @to = ();
+    if ($email || $email_list) {
+	if ($email) {
+	    @to = (@to, @email_to);
+	}
+	if ($email_list) {
+	    @to = (@to, @list_to);
+	}
+    }
+
+    if ($interactive) {
+	@to = interactive_get_maintainers(\@to);
+    }
+
+    return @to;
+}
+
+sub file_match_pattern {
+    my ($file, $pattern) = @_;
+    if (substr($pattern, -1) eq "/") {
+	if ($file =~ m@^$pattern@) {
+	    return 1;
+	}
+    } else {
+	if ($file =~ m@^$pattern@) {
+	    my $s1 = ($file =~ tr@/@@);
+	    my $s2 = ($pattern =~ tr@/@@);
+	    if ($s1 == $s2) {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+sub usage {
+    print <<EOT;
+usage: $P [options] patchfile
+       $P [options] -f file|directory
+version: $V
+
+MAINTAINER field selection options:
+  --email => print email address(es) if any
+    --git => include recent git \*-by: signers
+    --git-all-signature-types => include signers regardless of signature type
+        or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
+    --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
+    --git-chief-penguins => include ${penguin_chiefs}
+    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
+    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
+    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
+    --git-blame => use git blame to find modified commits for patch or file
+    --git-since => git history to use (default: $email_git_since)
+    --hg-since => hg history to use (default: $email_hg_since)
+    --interactive => display a menu (mostly useful if used with the --git option)
+    --m => include maintainer(s) if any
+    --n => include name 'Full Name <addr\@domain.tld>'
+    --l => include list(s) if any
+    --s => include subscriber only list(s) if any
+    --remove-duplicates => minimize duplicate email names/addresses
+    --roles => show roles (status:subsystem, git-signer, list, etc...)
+    --rolestats => show roles and statistics (commits/total_commits, %)
+    --file-emails => add email addresses found in -f file (default: 0 (off))
+  --scm => print SCM tree(s) if any
+  --status => print status if any
+  --subsystem => print subsystem name if any
+  --web => print website(s) if any
+
+Output type options:
+  --separator [, ] => separator for multiple entries on 1 line
+    using --separator also sets --nomultiline if --separator is not [, ]
+  --multiline => print 1 entry per line
+
+Other options:
+  --pattern-depth => Number of pattern directory traversals (default: 0 (all))
+  --keywords => scan patch for keywords (default: $keywords)
+  --sections => print all of the subsystem sections with pattern matches
+  --mailmap => use .mailmap file (default: $email_use_mailmap)
+  --version => show version
+  --help => show this help information
+
+Default options:
+  [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0
+   --remove-duplicates --rolestats]
+
+Notes:
+  Using "-f directory" may give unexpected results:
+      Used with "--git", git signators for _all_ files in and below
+          directory are examined as git recurses directories.
+          Any specified X: (exclude) pattern matches are _not_ ignored.
+      Used with "--nogit", directory is used as a pattern match,
+          no individual file within the directory or subdirectory
+          is matched.
+      Used with "--git-blame", does not iterate all files in directory
+  Using "--git-blame" is slow and may add old committers and authors
+      that are no longer active maintainers to the output.
+  Using "--roles" or "--rolestats" with git send-email --cc-cmd or any
+      other automated tools that expect only ["name"] <email address>
+      may not work because of additional output after <email address>.
+  Using "--rolestats" and "--git-blame" shows the #/total=% commits,
+      not the percentage of the entire file authored.  # of commits is
+      not a good measure of amount of code authored.  1 major commit may
+      contain a thousand lines, 5 trivial commits may modify a single line.
+  If git is not installed, but mercurial (hg) is installed and an .hg
+      repository exists, the following options apply to mercurial:
+          --git,
+          --git-min-signatures, --git-max-maintainers, --git-min-percent, and
+          --git-blame
+      Use --hg-since not --git-since to control date selection
+  File ".get_maintainer.conf", if it exists in the QEMU source root
+      directory, can change whatever get_maintainer defaults are desired.
+      Entries in this file can be any command line argument.
+      This file is prepended to any additional command line arguments.
+      Multiple lines and # comments are allowed.
+EOT
+}
+
+sub top_of_tree {
+    my ($lk_path) = @_;
+
+    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
+	$lk_path .= "/";
+    }
+    if (    (-f "${lk_path}COPYING")
+        && (-f "${lk_path}MAINTAINERS")
+        && (-f "${lk_path}Makefile")
+        && (-d "${lk_path}docs")
+        && (-f "${lk_path}VERSION")
+        && (-f "${lk_path}vl.c")) {
+	return 1;
+    }
+    return 0;
+}
+
+sub parse_email {
+    my ($formatted_email) = @_;
+
+    my $name = "";
+    my $address = "";
+
+    if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
+	$name = $1;
+	$address = $2;
+    } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
+	$address = $1;
+    } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
+	$address = $1;
+    }
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {  	 ##has "must quote" chars
+	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+	$name = "\"$name\"";
+    }
+
+    return ($name, $address);
+}
+
+sub format_email {
+    my ($name, $address, $usename) = @_;
+
+    my $formatted_email;
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
+	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+	$name = "\"$name\"";
+    }
+
+    if ($usename) {
+	if ("$name" eq "") {
+	    $formatted_email = "$address";
+	} else {
+	    $formatted_email = "$name <$address>";
+	}
+    } else {
+	$formatted_email = $address;
+    }
+
+    return $formatted_email;
+}
+
+sub find_first_section {
+    my $index = 0;
+
+    while ($index < @typevalue) {
+	my $tv = $typevalue[$index];
+	if (($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index++;
+    }
+
+    return $index;
+}
+
+sub find_starting_index {
+    my ($index) = @_;
+
+    while ($index > 0) {
+	my $tv = $typevalue[$index];
+	if (!($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index--;
+    }
+
+    return $index;
+}
+
+sub find_ending_index {
+    my ($index) = @_;
+
+    while ($index < @typevalue) {
+	my $tv = $typevalue[$index];
+	if (!($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index++;
+    }
+
+    return $index;
+}
+
+sub get_maintainer_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $role;
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+	$subsystem = substr($subsystem, 0, 17);
+	$subsystem =~ s/\s*$//;
+	$subsystem = $subsystem . "...";
+    }
+
+    for ($i = $start + 1; $i < $end; $i++) {
+	my $tv = $typevalue[$i];
+	if ($tv =~ m/^(\C):\s*(.*)/) {
+	    my $ptype = $1;
+	    my $pvalue = $2;
+	    if ($ptype eq "S") {
+		$role = $pvalue;
+	    }
+	}
+    }
+
+    $role = lc($role);
+    if      ($role eq "supported") {
+	$role = "supporter";
+    } elsif ($role eq "maintained") {
+	$role = "maintainer";
+    } elsif ($role eq "odd fixes") {
+	$role = "odd fixer";
+    } elsif ($role eq "orphan") {
+	$role = "orphan minder";
+    } elsif ($role eq "obsolete") {
+	$role = "obsolete minder";
+    } elsif ($role eq "buried alive in reporters") {
+	$role = "chief penguin";
+    }
+
+    return $role . ":" . $subsystem;
+}
+
+sub get_list_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+	$subsystem = substr($subsystem, 0, 17);
+	$subsystem =~ s/\s*$//;
+	$subsystem = $subsystem . "...";
+    }
+
+    if ($subsystem eq "THE REST") {
+	$subsystem = "";
+    }
+
+    return $subsystem;
+}
+
+sub add_categories {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    push(@subsystem, $typevalue[$start]);
+
+    for ($i = $start + 1; $i < $end; $i++) {
+	my $tv = $typevalue[$i];
+	if ($tv =~ m/^(\C):\s*(.*)/) {
+	    my $ptype = $1;
+	    my $pvalue = $2;
+	    if ($ptype eq "L") {
+		my $list_address = $pvalue;
+		my $list_additional = "";
+		my $list_role = get_list_role($i);
+
+		if ($list_role ne "") {
+		    $list_role = ":" . $list_role;
+		}
+		if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
+		    $list_address = $1;
+		    $list_additional = $2;
+		}
+		if ($list_additional =~ m/subscribers-only/) {
+		    if ($email_subscriber_list) {
+			if (!$hash_list_to{lc($list_address)}) {
+			    $hash_list_to{lc($list_address)} = 1;
+			    push(@list_to, [$list_address,
+					    "subscriber list${list_role}"]);
+			}
+		    }
+		} else {
+		    if ($email_list) {
+			if (!$hash_list_to{lc($list_address)}) {
+			    $hash_list_to{lc($list_address)} = 1;
+			    push(@list_to, [$list_address,
+					    "open list${list_role}"]);
+			}
+		    }
+		}
+	    } elsif ($ptype eq "M") {
+		my ($name, $address) = parse_email($pvalue);
+		if ($name eq "") {
+		    if ($i > 0) {
+			my $tv = $typevalue[$i - 1];
+			if ($tv =~ m/^(\C):\s*(.*)/) {
+			    if ($1 eq "P") {
+				$name = $2;
+				$pvalue = format_email($name, $address, $email_usename);
+			    }
+			}
+		    }
+		}
+		if ($email_maintainer) {
+		    my $role = get_maintainer_role($i);
+		    push_email_addresses($pvalue, $role);
+		}
+	    } elsif ($ptype eq "T") {
+		push(@scm, $pvalue);
+	    } elsif ($ptype eq "W") {
+		push(@web, $pvalue);
+	    } elsif ($ptype eq "S") {
+		push(@status, $pvalue);
+	    }
+	}
+    }
+}
+
+sub email_inuse {
+    my ($name, $address) = @_;
+
+    return 1 if (($name eq "") && ($address eq ""));
+    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
+    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
+
+    return 0;
+}
+
+sub push_email_address {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+
+    if ($address eq "") {
+	return 0;
+    }
+
+    if (!$email_remove_duplicates) {
+	push(@email_to, [format_email($name, $address, $email_usename), $role]);
+    } elsif (!email_inuse($name, $address)) {
+	push(@email_to, [format_email($name, $address, $email_usename), $role]);
+	$email_hash_name{lc($name)}++ if ($name ne "");
+	$email_hash_address{lc($address)}++;
+    }
+
+    return 1;
+}
+
+sub push_email_addresses {
+    my ($address, $role) = @_;
+
+    my @address_list = ();
+
+    if (rfc822_valid($address)) {
+	push_email_address($address, $role);
+    } elsif (@address_list = rfc822_validlist($address)) {
+	my $array_count = shift(@address_list);
+	while (my $entry = shift(@address_list)) {
+	    push_email_address($entry, $role);
+	}
+    } else {
+	if (!push_email_address($address, $role)) {
+	    warn("Invalid MAINTAINERS address: '" . $address . "'\n");
+	}
+    }
+}
+
+sub add_role {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, $email_usename);
+
+    foreach my $entry (@email_to) {
+	if ($email_remove_duplicates) {
+	    my ($entry_name, $entry_address) = parse_email($entry->[0]);
+	    if (($name eq $entry_name || $address eq $entry_address)
+		&& ($role eq "" || !($entry->[1] =~ m/$role/))
+	    ) {
+		if ($entry->[1] eq "") {
+		    $entry->[1] = "$role";
+		} else {
+		    $entry->[1] = "$entry->[1],$role";
+		}
+	    }
+	} else {
+	    if ($email eq $entry->[0]
+		&& ($role eq "" || !($entry->[1] =~ m/$role/))
+	    ) {
+		if ($entry->[1] eq "") {
+		    $entry->[1] = "$role";
+		} else {
+		    $entry->[1] = "$entry->[1],$role";
+		}
+	    }
+	}
+    }
+}
+
+sub which {
+    my ($bin) = @_;
+
+    foreach my $path (split(/:/, $ENV{PATH})) {
+	if (-e "$path/$bin") {
+	    return "$path/$bin";
+	}
+    }
+
+    return "";
+}
+
+sub which_conf {
+    my ($conf) = @_;
+
+    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+	if (-e "$path/$conf") {
+	    return "$path/$conf";
+	}
+    }
+
+    return "";
+}
+
+sub mailmap_email {
+    my ($line) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, 1);
+    my $real_name = $name;
+    my $real_address = $address;
+
+    if (exists $mailmap->{names}->{$email} ||
+	exists $mailmap->{addresses}->{$email}) {
+	if (exists $mailmap->{names}->{$email}) {
+	    $real_name = $mailmap->{names}->{$email};
+	}
+	if (exists $mailmap->{addresses}->{$email}) {
+	    $real_address = $mailmap->{addresses}->{$email};
+	}
+    } else {
+	if (exists $mailmap->{names}->{$address}) {
+	    $real_name = $mailmap->{names}->{$address};
+	}
+	if (exists $mailmap->{addresses}->{$address}) {
+	    $real_address = $mailmap->{addresses}->{$address};
+	}
+    }
+    return format_email($real_name, $real_address, 1);
+}
+
+sub mailmap {
+    my (@addresses) = @_;
+
+    my @mapped_emails = ();
+    foreach my $line (@addresses) {
+	push(@mapped_emails, mailmap_email($line));
+    }
+    merge_by_realname(@mapped_emails) if ($email_use_mailmap);
+    return @mapped_emails;
+}
+
+sub merge_by_realname {
+    my %address_map;
+    my (@emails) = @_;
+
+    foreach my $email (@emails) {
+	my ($name, $address) = parse_email($email);
+	if (exists $address_map{$name}) {
+	    $address = $address_map{$name};
+	    $email = format_email($name, $address, 1);
+	} else {
+	    $address_map{$name} = $address;
+	}
+    }
+}
+
+sub git_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    $output =~ s/^\s*//gm;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub hg_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub extract_formatted_signatures {
+    my (@signature_lines) = @_;
+
+    my @type = @signature_lines;
+
+    s/\s*(.*):.*/$1/ for (@type);
+
+    # cut -f2- -d":"
+    s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
+
+## Reformat email addresses (with names) to avoid badly written signatures
+
+    foreach my $signer (@signature_lines) {
+	$signer = deduplicate_email($signer);
+    }
+
+    return (\@type, \@signature_lines);
+}
+
+sub vcs_find_signers {
+    my ($cmd) = @_;
+    my $commits;
+    my @lines = ();
+    my @signatures = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    my $pattern = $VCS_cmds{"commit_pattern"};
+
+    $commits = grep(/$pattern/, @lines);	# of commits
+
+    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
+
+    return (0, @signatures) if !@signatures;
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    if (!$email_git_penguin_chiefs) {
+	@signatures = grep(!/${penguin_chiefs}/i, @signatures);
+    }
+
+    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+
+    return ($commits, @$signers_ref);
+}
+
+sub vcs_find_author {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    if (!$email_git_penguin_chiefs) {
+	@lines = grep(!/${penguin_chiefs}/i, @lines);
+    }
+
+    return @lines if !@lines;
+
+    my @authors = ();
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+	    my $author = $1;
+	    my ($name, $address) = parse_email($author);
+	    $author = format_email($name, $address, 1);
+	    push(@authors, $author);
+	}
+    }
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    return @authors;
+}
+
+sub vcs_save_commits {
+    my ($cmd) = @_;
+    my @lines = ();
+    my @commits = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
+	    push(@commits, $1);
+	}
+    }
+
+    return @commits;
+}
+
+sub vcs_blame {
+    my ($file) = @_;
+    my $cmd;
+    my @commits = ();
+
+    return @commits if (!(-f $file));
+
+    if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
+	my @all_commits = ();
+
+	$cmd = $VCS_cmds{"blame_file_cmd"};
+	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	@all_commits = vcs_save_commits($cmd);
+
+	foreach my $file_range_diff (@range) {
+	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+	    my $diff_file = $1;
+	    my $diff_start = $2;
+	    my $diff_length = $3;
+	    next if ("$file" ne "$diff_file");
+	    for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
+		push(@commits, $all_commits[$i]);
+	    }
+	}
+    } elsif (@range) {
+	foreach my $file_range_diff (@range) {
+	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+	    my $diff_file = $1;
+	    my $diff_start = $2;
+	    my $diff_length = $3;
+	    next if ("$file" ne "$diff_file");
+	    $cmd = $VCS_cmds{"blame_range_cmd"};
+	    $cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	    push(@commits, vcs_save_commits($cmd));
+	}
+    } else {
+	$cmd = $VCS_cmds{"blame_file_cmd"};
+	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	@commits = vcs_save_commits($cmd);
+    }
+
+    foreach my $commit (@commits) {
+	$commit =~ s/^\^//g;
+    }
+
+    return @commits;
+}
+
+my $printed_novcs = 0;
+sub vcs_exists {
+    %VCS_cmds = %VCS_cmds_git;
+    return 1 if eval $VCS_cmds{"available"};
+    %VCS_cmds = %VCS_cmds_hg;
+    return 2 if eval $VCS_cmds{"available"};
+    %VCS_cmds = ();
+    if (!$printed_novcs) {
+	warn("$P: No supported VCS found.  Add --nogit to options?\n");
+	warn("Using a git repository produces better results.\n");
+	warn("Try latest git repository using:\n");
+	warn("git clone git://git.qemu.org/qemu.git\n");
+	$printed_novcs = 1;
+    }
+    return 0;
+}
+
+sub vcs_is_git {
+    vcs_exists();
+    return $vcs_used == 1;
+}
+
+sub vcs_is_hg {
+    return $vcs_used == 2;
+}
+
+sub interactive_get_maintainers {
+    my ($list_ref) = @_;
+    my @list = @$list_ref;
+
+    vcs_exists();
+
+    my %selected;
+    my %authored;
+    my %signed;
+    my $count = 0;
+    my $maintained = 0;
+    foreach my $entry (@list) {
+	$maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
+	$selected{$count} = 1;
+	$authored{$count} = 0;
+	$signed{$count} = 0;
+	$count++;
+    }
+
+    #menu loop
+    my $done = 0;
+    my $print_options = 0;
+    my $redraw = 1;
+    while (!$done) {
+	$count = 0;
+	if ($redraw) {
+	    printf STDERR "\n%1s %2s %-65s",
+			  "*", "#", "email/list and role:stats";
+	    if ($email_git ||
+		($email_git_fallback && !$maintained) ||
+		$email_git_blame) {
+		print STDERR "auth sign";
+	    }
+	    print STDERR "\n";
+	    foreach my $entry (@list) {
+		my $email = $entry->[0];
+		my $role = $entry->[1];
+		my $sel = "";
+		$sel = "*" if ($selected{$count});
+		my $commit_author = $commit_author_hash{$email};
+		my $commit_signer = $commit_signer_hash{$email};
+		my $authored = 0;
+		my $signed = 0;
+		$authored++ for (@{$commit_author});
+		$signed++ for (@{$commit_signer});
+		printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+		printf STDERR "%4d %4d", $authored, $signed
+		    if ($authored > 0 || $signed > 0);
+		printf STDERR "\n     %s\n", $role;
+		if ($authored{$count}) {
+		    my $commit_author = $commit_author_hash{$email};
+		    foreach my $ref (@{$commit_author}) {
+			print STDERR "     Author: @{$ref}[1]\n";
+		    }
+		}
+		if ($signed{$count}) {
+		    my $commit_signer = $commit_signer_hash{$email};
+		    foreach my $ref (@{$commit_signer}) {
+			print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
+		    }
+		}
+
+		$count++;
+	    }
+	}
+	my $date_ref = \$email_git_since;
+	$date_ref = \$email_hg_since if (vcs_is_hg());
+	if ($print_options) {
+	    $print_options = 0;
+	    if (vcs_exists()) {
+		print STDERR <<EOT
+
+Version Control options:
+g  use git history      [$email_git]
+gf use git-fallback     [$email_git_fallback]
+b  use git blame        [$email_git_blame]
+bs use blame signatures [$email_git_blame_signatures]
+c# minimum commits      [$email_git_min_signatures]
+%# min percent          [$email_git_min_percent]
+d# history to use       [$$date_ref]
+x# max maintainers      [$email_git_max_maintainers]
+t  all signature types  [$email_git_all_signature_types]
+m  use .mailmap         [$email_use_mailmap]
+EOT
+	    }
+	    print STDERR <<EOT
+
+Additional options:
+0  toggle all
+tm toggle maintainers
+tg toggle git entries
+tl toggle open list entries
+ts toggle subscriber list entries
+f  emails in file       [$file_emails]
+k  keywords in file     [$keywords]
+r  remove duplicates    [$email_remove_duplicates]
+p# pattern match depth  [$pattern_depth]
+EOT
+	}
+	print STDERR
+"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+	my $input = <STDIN>;
+	chomp($input);
+
+	$redraw = 1;
+	my $rerun = 0;
+	my @wish = split(/[, ]+/, $input);
+	foreach my $nr (@wish) {
+	    $nr = lc($nr);
+	    my $sel = substr($nr, 0, 1);
+	    my $str = substr($nr, 1);
+	    my $val = 0;
+	    $val = $1 if $str =~ /^(\d+)$/;
+
+	    if ($sel eq "y") {
+		$interactive = 0;
+		$done = 1;
+		$output_rolestats = 0;
+		$output_roles = 0;
+		last;
+	    } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
+		$selected{$nr - 1} = !$selected{$nr - 1};
+	    } elsif ($sel eq "*" || $sel eq '^') {
+		my $toggle = 0;
+		$toggle = 1 if ($sel eq '*');
+		for (my $i = 0; $i < $count; $i++) {
+		    $selected{$i} = $toggle;
+		}
+	    } elsif ($sel eq "0") {
+		for (my $i = 0; $i < $count; $i++) {
+		    $selected{$i} = !$selected{$i};
+		}
+	    } elsif ($sel eq "t") {
+		if (lc($str) eq "m") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
+		    }
+		} elsif (lc($str) eq "g") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
+		    }
+		} elsif (lc($str) eq "l") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(open list)/i);
+		    }
+		} elsif (lc($str) eq "s") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(subscriber list)/i);
+		    }
+		}
+	    } elsif ($sel eq "a") {
+		if ($val > 0 && $val <= $count) {
+		    $authored{$val - 1} = !$authored{$val - 1};
+		} elsif ($str eq '*' || $str eq '^') {
+		    my $toggle = 0;
+		    $toggle = 1 if ($str eq '*');
+		    for (my $i = 0; $i < $count; $i++) {
+			$authored{$i} = $toggle;
+		    }
+		}
+	    } elsif ($sel eq "s") {
+		if ($val > 0 && $val <= $count) {
+		    $signed{$val - 1} = !$signed{$val - 1};
+		} elsif ($str eq '*' || $str eq '^') {
+		    my $toggle = 0;
+		    $toggle = 1 if ($str eq '*');
+		    for (my $i = 0; $i < $count; $i++) {
+			$signed{$i} = $toggle;
+		    }
+		}
+	    } elsif ($sel eq "o") {
+		$print_options = 1;
+		$redraw = 1;
+	    } elsif ($sel eq "g") {
+		if ($str eq "f") {
+		    bool_invert(\$email_git_fallback);
+		} else {
+		    bool_invert(\$email_git);
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "b") {
+		if ($str eq "s") {
+		    bool_invert(\$email_git_blame_signatures);
+		} else {
+		    bool_invert(\$email_git_blame);
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "c") {
+		if ($val > 0) {
+		    $email_git_min_signatures = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "x") {
+		if ($val > 0) {
+		    $email_git_max_maintainers = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "%") {
+		if ($str ne "" && $val >= 0) {
+		    $email_git_min_percent = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "d") {
+		if (vcs_is_git()) {
+		    $email_git_since = $str;
+		} elsif (vcs_is_hg()) {
+		    $email_hg_since = $str;
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "t") {
+		bool_invert(\$email_git_all_signature_types);
+		$rerun = 1;
+	    } elsif ($sel eq "f") {
+		bool_invert(\$file_emails);
+		$rerun = 1;
+	    } elsif ($sel eq "r") {
+		bool_invert(\$email_remove_duplicates);
+		$rerun = 1;
+	    } elsif ($sel eq "m") {
+		bool_invert(\$email_use_mailmap);
+		read_mailmap();
+		$rerun = 1;
+	    } elsif ($sel eq "k") {
+		bool_invert(\$keywords);
+		$rerun = 1;
+	    } elsif ($sel eq "p") {
+		if ($str ne "" && $val >= 0) {
+		    $pattern_depth = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "h" || $sel eq "?") {
+		print STDERR <<EOT
+
+Interactive mode allows you to select the various maintainers, submitters,
+commit signers and mailing lists that could be CC'd on a patch.
+
+Any *'d entry is selected.
+
+If you have git or hg installed, you can choose to summarize the commit
+history of files in the patch.  Also, each line of the current file can
+be matched to its commit author and that commits signers with blame.
+
+Various knobs exist to control the length of time for active commit
+tracking, the maximum number of commit authors and signers to add,
+and such.
+
+Enter selections at the prompt until you are satisfied that the selected
+maintainers are appropriate.  You may enter multiple selections separated
+by either commas or spaces.
+
+EOT
+	    } else {
+		print STDERR "invalid option: '$nr'\n";
+		$redraw = 0;
+	    }
+	}
+	if ($rerun) {
+	    print STDERR "git-blame can be very slow, please have patience..."
+		if ($email_git_blame);
+	    goto &get_maintainers;
+	}
+    }
+
+    #drop not selected entries
+    $count = 0;
+    my @new_emailto = ();
+    foreach my $entry (@list) {
+	if ($selected{$count}) {
+	    push(@new_emailto, $list[$count]);
+	}
+	$count++;
+    }
+    return @new_emailto;
+}
+
+sub bool_invert {
+    my ($bool_ref) = @_;
+
+    if ($$bool_ref) {
+	$$bool_ref = 0;
+    } else {
+	$$bool_ref = 1;
+    }
+}
+
+sub deduplicate_email {
+    my ($email) = @_;
+
+    my $matched = 0;
+    my ($name, $address) = parse_email($email);
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+
+    return $email if (!$email_remove_duplicates);
+
+    ($name, $address) = parse_email($email);
+
+    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
+	$name = $deduplicate_name_hash{lc($name)}->[0];
+	$address = $deduplicate_name_hash{lc($name)}->[1];
+	$matched = 1;
+    } elsif ($deduplicate_address_hash{lc($address)}) {
+	$name = $deduplicate_address_hash{lc($address)}->[0];
+	$address = $deduplicate_address_hash{lc($address)}->[1];
+	$matched = 1;
+    }
+    if (!$matched) {
+	$deduplicate_name_hash{lc($name)} = [ $name, $address ];
+	$deduplicate_address_hash{lc($address)} = [ $name, $address ];
+    }
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+    return $email;
+}
+
+sub save_commits_by_author {
+    my (@lines) = @_;
+
+    my @authors = ();
+    my @commits = ();
+    my @subjects = ();
+
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+	    my $author = $1;
+	    $author = deduplicate_email($author);
+	    push(@authors, $author);
+	}
+	push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+	push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+    }
+
+    for (my $i = 0; $i < @authors; $i++) {
+	my $exists = 0;
+	foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
+	    if (@{$ref}[0] eq $commits[$i] &&
+		@{$ref}[1] eq $subjects[$i]) {
+		$exists = 1;
+		last;
+	    }
+	}
+	if (!$exists) {
+	    push(@{$commit_author_hash{$authors[$i]}},
+		 [ ($commits[$i], $subjects[$i]) ]);
+	}
+    }
+}
+
+sub save_commits_by_signer {
+    my (@lines) = @_;
+
+    my $commit = "";
+    my $subject = "";
+
+    foreach my $line (@lines) {
+	$commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+	$subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+	if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
+	    my @signatures = ($line);
+	    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+	    my @types = @$types_ref;
+	    my @signers = @$signers_ref;
+
+	    my $type = $types[0];
+	    my $signer = $signers[0];
+
+	    $signer = deduplicate_email($signer);
+
+	    my $exists = 0;
+	    foreach my $ref(@{$commit_signer_hash{$signer}}) {
+		if (@{$ref}[0] eq $commit &&
+		    @{$ref}[1] eq $subject &&
+		    @{$ref}[2] eq $type) {
+		    $exists = 1;
+		    last;
+		}
+	    }
+	    if (!$exists) {
+		push(@{$commit_signer_hash{$signer}},
+		     [ ($commit, $subject, $type) ]);
+	    }
+	}
+    }
+}
+
+sub vcs_assign {
+    my ($role, $divisor, @lines) = @_;
+
+    my %hash;
+    my $count = 0;
+
+    return if (@lines <= 0);
+
+    if ($divisor <= 0) {
+	warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
+	$divisor = 1;
+    }
+
+    @lines = mailmap(@lines);
+
+    return if (@lines <= 0);
+
+    @lines = sort(@lines);
+
+    # uniq -c
+    $hash{$_}++ for @lines;
+
+    # sort -rn
+    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+	my $sign_offs = $hash{$line};
+	my $percent = $sign_offs * 100 / $divisor;
+
+	$percent = 100 if ($percent > 100);
+	$count++;
+	last if ($sign_offs < $email_git_min_signatures ||
+		 $count > $email_git_max_maintainers ||
+		 $percent < $email_git_min_percent);
+	push_email_address($line, '');
+	if ($output_rolestats) {
+	    my $fmt_percent = sprintf("%.0f", $percent);
+	    add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
+	} else {
+	    add_role($line, $role);
+	}
+    }
+}
+
+sub vcs_file_signoffs {
+    my ($file) = @_;
+
+    my @signers = ();
+    my $commits;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    my $cmd = $VCS_cmds{"find_signers_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
+
+    ($commits, @signers) = vcs_find_signers($cmd);
+
+    foreach my $signer (@signers) {
+	$signer = deduplicate_email($signer);
+    }
+
+    vcs_assign("commit_signer", $commits, @signers);
+}
+
+sub vcs_file_blame {
+    my ($file) = @_;
+
+    my @signers = ();
+    my @all_commits = ();
+    my @commits = ();
+    my $total_commits;
+    my $total_lines;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    @all_commits = vcs_blame($file);
+    @commits = uniq(@all_commits);
+    $total_commits = @commits;
+    $total_lines = @all_commits;
+
+    if ($email_git_blame_signatures) {
+	if (vcs_is_hg()) {
+	    my $commit_count;
+	    my @commit_signers = ();
+	    my $commit = join(" -r ", @commits);
+	    my $cmd;
+
+	    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+	    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+	    ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+	    push(@signers, @commit_signers);
+	} else {
+	    foreach my $commit (@commits) {
+		my $commit_count;
+		my @commit_signers = ();
+		my $cmd;
+
+		$cmd = $VCS_cmds{"find_commit_signers_cmd"};
+		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+		($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+		push(@signers, @commit_signers);
+	    }
+	}
+    }
+
+    if ($from_filename) {
+	if ($output_rolestats) {
+	    my @blame_signers;
+	    if (vcs_is_hg()) {{		# Double brace for last exit
+		my $commit_count;
+		my @commit_signers = ();
+		@commits = uniq(@commits);
+		@commits = sort(@commits);
+		my $commit = join(" -r ", @commits);
+		my $cmd;
+
+		$cmd = $VCS_cmds{"find_commit_author_cmd"};
+		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+		my @lines = ();
+
+		@lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+		if (!$email_git_penguin_chiefs) {
+		    @lines = grep(!/${penguin_chiefs}/i, @lines);
+		}
+
+		last if !@lines;
+
+		my @authors = ();
+		foreach my $line (@lines) {
+		    if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+			my $author = $1;
+			$author = deduplicate_email($author);
+			push(@authors, $author);
+		    }
+		}
+
+		save_commits_by_author(@lines) if ($interactive);
+		save_commits_by_signer(@lines) if ($interactive);
+
+		push(@signers, @authors);
+	    }}
+	    else {
+		foreach my $commit (@commits) {
+		    my $i;
+		    my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+		    $cmd =~ s/(\$\w+)/$1/eeg;	#interpolate $cmd
+		    my @author = vcs_find_author($cmd);
+		    next if !@author;
+
+		    my $formatted_author = deduplicate_email($author[0]);
+
+		    my $count = grep(/$commit/, @all_commits);
+		    for ($i = 0; $i < $count ; $i++) {
+			push(@blame_signers, $formatted_author);
+		    }
+		}
+	    }
+	    if (@blame_signers) {
+		vcs_assign("authored lines", $total_lines, @blame_signers);
+	    }
+	}
+	foreach my $signer (@signers) {
+	    $signer = deduplicate_email($signer);
+	}
+	vcs_assign("commits", $total_commits, @signers);
+    } else {
+	foreach my $signer (@signers) {
+	    $signer = deduplicate_email($signer);
+	}
+	vcs_assign("modified commits", $total_commits, @signers);
+    }
+}
+
+sub uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub sort_and_uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = sort @parms;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub clean_file_emails {
+    my (@file_emails) = @_;
+    my @fmt_emails = ();
+
+    foreach my $email (@file_emails) {
+	$email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
+	my ($name, $address) = parse_email($email);
+	if ($name eq '"[,\.]"') {
+	    $name = "";
+	}
+
+	my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
+	if (@nw > 2) {
+	    my $first = $nw[@nw - 3];
+	    my $middle = $nw[@nw - 2];
+	    my $last = $nw[@nw - 1];
+
+	    if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
+		 (length($first) == 2 && substr($first, -1) eq ".")) ||
+		(length($middle) == 1 ||
+		 (length($middle) == 2 && substr($middle, -1) eq "."))) {
+		$name = "$first $middle $last";
+	    } else {
+		$name = "$middle $last";
+	    }
+	}
+
+	if (substr($name, -1) =~ /[,\.]/) {
+	    $name = substr($name, 0, length($name) - 1);
+	} elsif (substr($name, -2) =~ /[,\.]"/) {
+	    $name = substr($name, 0, length($name) - 2) . '"';
+	}
+
+	if (substr($name, 0, 1) =~ /[,\.]/) {
+	    $name = substr($name, 1, length($name) - 1);
+	} elsif (substr($name, 0, 2) =~ /"[,\.]/) {
+	    $name = '"' . substr($name, 2, length($name) - 2);
+	}
+
+	my $fmt_email = format_email($name, $address, $email_usename);
+	push(@fmt_emails, $fmt_email);
+    }
+    return @fmt_emails;
+}
+
+sub merge_email {
+    my @lines;
+    my %saw;
+
+    for (@_) {
+	my ($address, $role) = @$_;
+	if (!$saw{$address}) {
+	    if ($output_roles) {
+		push(@lines, "$address ($role)");
+	    } else {
+		push(@lines, $address);
+	    }
+	    $saw{$address} = 1;
+	}
+    }
+
+    return @lines;
+}
+
+sub output {
+    my (@parms) = @_;
+
+    if ($output_multiline) {
+	foreach my $line (@parms) {
+	    print("${line}\n");
+	}
+    } else {
+	print(join($output_separator, @parms));
+	print("\n");
+    }
+}
+
+my $rfc822re;
+
+sub make_rfc822re {
+#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
+#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
+#   This regexp will only work on addresses which have had comments stripped
+#   and replaced with rfc822_lwsp.
+
+    my $specials = '()<>@,;:\\\\".\\[\\]';
+    my $controls = '\\000-\\037\\177';
+
+    my $dtext = "[^\\[\\]\\r\\\\]";
+    my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
+
+    my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
+
+#   Use zero-width assertion to spot the limit of an atom.  A simple
+#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
+    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
+    my $word = "(?:$atom|$quoted_string)";
+    my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
+
+    my $sub_domain = "(?:$atom|$domain_literal)";
+    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
+
+    my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
+
+    my $phrase = "$word*";
+    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
+    my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
+    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
+
+    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
+    my $address = "(?:$mailbox|$group)";
+
+    return "$rfc822_lwsp*$address";
+}
+
+sub rfc822_strip_comments {
+    my $s = shift;
+#   Recursively remove comments, and replace with a single space.  The simpler
+#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
+#   chars in atoms, for example.
+
+    while ($s =~ s/^((?:[^"\\]|\\.)*
+                    (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
+                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
+    return $s;
+}
+
+#   valid: returns true if the parameter is an RFC822 valid address
+#
+sub rfc822_valid {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+
+    return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
+}
+
+#   validlist: In scalar context, returns true if the parameter is an RFC822
+#              valid list of addresses.
+#
+#              In list context, returns an empty list on failure (an invalid
+#              address was found); otherwise a list whose first element is the
+#              number of addresses found and whose remaining elements are the
+#              addresses.  This is needed to disambiguate failure (invalid)
+#              from success with no addresses found, because an empty string is
+#              a valid list.
+
+sub rfc822_validlist {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+    # * null list items are valid according to the RFC
+    # * the '1' business is to aid in distinguishing failure from no results
+
+    my @r;
+    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
+	$s =~ m/^$rfc822_char*$/) {
+        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
+            push(@r, $1);
+        }
+        return wantarray ? (scalar(@r), @r) : 1;
+    }
+    return wantarray ? () : 0;
+}
diff --git a/qemu-0.15.x/scripts/hxtool b/qemu-0.15.x/scripts/hxtool
new file mode 100644
index 0000000..7ca83ed
--- /dev/null
+++ b/qemu-0.15.x/scripts/hxtool
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+hxtoh()
+{
+    flag=1
+    while read -r str; do
+        case $str in
+            HXCOMM*)
+            ;;
+            STEXI*|ETEXI*|SQMP*|EQMP*) flag=$(($flag^1))
+            ;;
+            *)
+            test $flag -eq 1 && printf "%s\n" "$str"
+            ;;
+        esac
+    done
+}
+
+hxtotexi()
+{
+    flag=0
+    line=1
+    while read -r str; do
+        case "$str" in
+            HXCOMM*)
+            ;;
+            STEXI*)
+            if test $flag -eq 1 ; then
+                echo "line $line: syntax error: expected ETEXI, found $str" >&2
+                exit 1
+            fi
+            flag=1
+            ;;
+            ETEXI*)
+            if test $flag -ne 1 ; then
+                echo "line $line: syntax error: expected STEXI, found $str" >&2
+                exit 1
+            fi
+            flag=0
+            ;;
+            SQMP*|EQMP*)
+            if test $flag -eq 1 ; then
+                echo "line $line: syntax error: expected ETEXI, found $str" >&2
+                exit 1
+            fi
+            ;;
+            DEFHEADING*)
+            echo "$(expr "$str" : "DEFHEADING(\(.*\))")"
+            ;;
+            *)
+            test $flag -eq 1 && echo "$str"
+            ;;
+        esac
+        line=$((line+1))
+    done
+}
+
+hxtoqmp()
+{
+    IFS=
+    flag=0
+    line=1
+    while read -r str; do
+        case "$str" in
+            HXCOMM*)
+            ;;
+            SQMP*)
+            if test $flag -eq 1 ; then
+                echo "line $line: syntax error: expected EQMP, found $str" >&2
+                exit 1
+            fi
+            flag=1
+            ;;
+            EQMP*)
+            if test $flag -ne 1 ; then
+                echo "line $line: syntax error: expected SQMP, found $str" >&2
+                exit 1
+            fi
+            flag=0
+            ;;
+            STEXI*|ETEXI*)
+            if test $flag -eq 1 ; then
+                echo "line $line: syntax error: expected EQMP, found $str" >&2
+                exit 1
+            fi
+            ;;
+            *)
+            test $flag -eq 1 && echo "$str"
+            ;;
+        esac
+        line=$((line+1))
+    done
+}
+
+case "$1" in
+"-h") hxtoh ;;
+"-t") hxtotexi ;;
+"-q") hxtoqmp ;;
+*) exit 1 ;;
+esac
+
+exit 0
diff --git a/qemu-0.15.x/scripts/make_device_config.sh b/qemu-0.15.x/scripts/make_device_config.sh
new file mode 100644
index 0000000..5d14885
--- /dev/null
+++ b/qemu-0.15.x/scripts/make_device_config.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+# Construct a target device config file from a default, pulling in any
+# files from include directives.
+
+dest=$1.tmp
+dep=$1.d
+src=$2
+src_dir=`dirname $src`
+all_includes=
+
+process_includes () {
+  cat $1 | grep '^include' | \
+  while read include file ; do
+    all_includes="$all_includes $src_dir/$file"
+    process_includes $src_dir/$file
+  done
+}
+
+f=$src
+while [ -n "$f" ] ; do
+  f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'`
+  [ $? = 0 ] || exit 1
+  all_includes="$all_includes $f"
+done
+process_includes $src > $dest
+
+cat $src $all_includes | grep -v '^include' > $dest
+echo "$1: $all_includes" > $dep
diff --git a/qemu-0.15.x/scripts/ordereddict.py b/qemu-0.15.x/scripts/ordereddict.py
new file mode 100644
index 0000000..7242b50
--- /dev/null
+++ b/qemu-0.15.x/scripts/ordereddict.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# 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.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__end
+        except AttributeError:
+            self.clear()
+        self.update(*args, **kwds)
+
+    def clear(self):
+        self.__end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.__map = {}                 # key --> [key, prev, next]
+        dict.clear(self)
+
+    def __setitem__(self, key, value):
+        if key not in self:
+            end = self.__end
+            curr = end[1]
+            curr[2] = end[1] = self.__map[key] = [key, curr, end]
+        dict.__setitem__(self, key, value)
+
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        key, prev, next = self.__map.pop(key)
+        prev[2] = next
+        next[1] = prev
+
+    def __iter__(self):
+        end = self.__end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.__end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def popitem(self, last=True):
+        if not self:
+            raise KeyError('dictionary is empty')
+        if last:
+            key = reversed(self).next()
+        else:
+            key = iter(self).next()
+        value = self.pop(key)
+        return key, value
+
+    def __reduce__(self):
+        items = [[k, self[k]] for k in self]
+        tmp = self.__map, self.__end
+        del self.__map, self.__end
+        inst_dict = vars(self).copy()
+        self.__map, self.__end = tmp
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def keys(self):
+        return list(self)
+
+    setdefault = DictMixin.setdefault
+    update = DictMixin.update
+    pop = DictMixin.pop
+    values = DictMixin.values
+    items = DictMixin.items
+    iterkeys = DictMixin.iterkeys
+    itervalues = DictMixin.itervalues
+    iteritems = DictMixin.iteritems
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, self.items())
+
+    def copy(self):
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedDict):
+            if len(self) != len(other):
+                return False
+            for p, q in  zip(self.items(), other.items()):
+                if p != q:
+                    return False
+            return True
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
diff --git a/qemu-0.15.x/scripts/qapi-commands.py b/qemu-0.15.x/scripts/qapi-commands.py
new file mode 100644
index 0000000..9ad4c54
--- /dev/null
+++ b/qemu-0.15.x/scripts/qapi-commands.py
@@ -0,0 +1,385 @@
+#
+# QAPI command marshaller generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori at us.ibm.com>
+#  Michael Roth    <mdroth at linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+def generate_command_decl(name, args, ret_type):
+    arglist=""
+    for argname, argtype, optional, structured in parse_args(args):
+        argtype = c_type(argtype)
+        if argtype == "char *":
+            argtype = "const char *"
+        if optional:
+            arglist += "bool has_%s, " % c_var(argname)
+        arglist += "%s %s, " % (argtype, c_var(argname))
+    return mcgen('''
+%(ret_type)s qmp_%(name)s(%(args)sError **errp);
+''',
+                 ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+
+def gen_sync_call(name, args, ret_type, indent=0):
+    ret = ""
+    arglist=""
+    retval=""
+    if ret_type:
+        retval = "retval = "
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            arglist += "has_%s, " % c_var(argname)
+        arglist += "%s, " % (c_var(argname))
+    push_indent(indent)
+    ret = mcgen('''
+%(retval)sqmp_%(name)s(%(args)serrp);
+
+''',
+                name=c_var(name), args=arglist, retval=retval).rstrip()
+    if ret_type:
+        ret += "\n" + mcgen(''''
+%(marshal_output_call)s
+''',
+                            marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
+    pop_indent(indent)
+    return ret.rstrip()
+
+
+def gen_marshal_output_call(name, ret_type):
+    if not ret_type:
+        return ""
+    return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+
+def gen_visitor_output_containers_decl(ret_type):
+    ret = ""
+    push_indent()
+    if ret_type:
+        ret += mcgen('''
+QmpOutputVisitor *mo;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret
+
+def gen_visitor_input_containers_decl(args):
+    ret = ""
+
+    push_indent()
+    if len(args) > 0:
+        ret += mcgen('''
+QmpInputVisitor *mi;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret.rstrip()
+
+def gen_visitor_input_vars_decl(args):
+    ret = ""
+    push_indent()
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+bool has_%(argname)s = false;
+''',
+                         argname=c_var(argname))
+        if c_type(argtype).endswith("*"):
+            ret += mcgen('''
+%(argtype)s %(argname)s = NULL;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+        else:
+            ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+
+    pop_indent()
+    return ret.rstrip()
+
+def gen_visitor_input_block(args, obj, dealloc=False):
+    ret = ""
+    if len(args) == 0:
+        return ret
+
+    push_indent()
+
+    if dealloc:
+        ret += mcgen('''
+md = qapi_dealloc_visitor_new();
+v = qapi_dealloc_get_visitor(md);
+''')
+    else:
+        ret += mcgen('''
+mi = qmp_input_visitor_new(%(obj)s);
+v = qmp_input_get_visitor(mi);
+''',
+                     obj=obj)
+
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
+if (has_%(c_name)s) {
+''',
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+        ret += mcgen('''
+visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp);
+''',
+                      c_name=c_var(argname), name=argname, argtype=argtype)
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(v, errp);
+''')
+
+    if dealloc:
+        ret += mcgen('''
+qapi_dealloc_visitor_cleanup(md);
+''')
+    else:
+        ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
+''')
+    pop_indent()
+    return ret.rstrip()
+
+def gen_marshal_output(name, args, ret_type):
+    if not ret_type:
+        return ""
+    ret = mcgen('''
+static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+{
+    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+    QmpOutputVisitor *mo = qmp_output_visitor_new();
+    Visitor *v;
+
+    v = qmp_output_get_visitor(mo);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    if (!error_is_set(errp)) {
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+    qmp_output_visitor_cleanup(mo);
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+            c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type)
+
+    return ret
+
+def gen_marshal_input(name, args, ret_type):
+    ret = mcgen('''
+static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
+{
+''',
+                c_name=c_var(name))
+
+    if ret_type:
+        if c_type(ret_type).endswith("*"):
+            retval = "    %s retval = NULL;" % c_type(ret_type)
+        else:
+            retval = "    %s retval;" % c_type(ret_type)
+        ret += mcgen('''
+%(retval)s
+''',
+                     retval=retval)
+
+    if len(args) > 0:
+        ret += mcgen('''
+%(visitor_input_containers_decl)s
+%(visitor_input_vars_decl)s
+
+%(visitor_input_block)s
+
+''',
+                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
+                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+
+    ret += mcgen('''
+    if (error_is_set(errp)) {
+        goto out;
+    }
+%(sync_call)s
+''',
+                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
+    ret += mcgen('''
+
+out:
+''')
+    ret += mcgen('''
+%(visitor_input_block_cleanup)s
+    return;
+}
+''',
+                 visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True))
+    return ret
+
+def gen_registry(commands):
+    registry=""
+    push_indent()
+    for cmd in commands:
+        registry += mcgen('''
+qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
+''',
+                     name=cmd['command'], c_name=c_var(cmd['command']))
+    pop_indent()
+    ret = mcgen('''
+static void qmp_init_marshal(void)
+{
+%(registry)s
+}
+
+qapi_init(qmp_init_marshal);
+''',
+                registry=registry.rstrip())
+    return ret
+
+def gen_command_decl_prologue(header, guard, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI function prototypes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "%(prefix)sqapi-types.h"
+#include "error.h"
+
+''',
+                 header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    return ret
+
+def gen_command_def_prologue(prefix="", proxy=False):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QMP->QAPI command dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',
+                prefix=prefix)
+    if not proxy:
+        ret += '#include "%sqmp-commands.h"' % prefix
+    return ret + "\n"
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+dispatch_type = "sync"
+c_file = 'qmp-marshal.c'
+h_file = 'qmp-commands.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-t", "--type"):
+        dispatch_type = a
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+exprs = parse_schema(sys.stdin)
+commands = filter(lambda expr: expr.has_key('command'), exprs)
+
+if dispatch_type == "sync":
+    fdecl = open(h_file, 'w')
+    fdef = open(c_file, 'w')
+    ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    fdecl.write(ret)
+    ret = gen_command_def_prologue(prefix=prefix)
+    fdef.write(ret)
+
+    for cmd in commands:
+        arglist = []
+        ret_type = None
+        if cmd.has_key('data'):
+            arglist = cmd['data']
+        if cmd.has_key('returns'):
+            ret_type = cmd['returns']
+        ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
+        fdecl.write(ret)
+        if ret_type:
+            ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n"
+            fdef.write(ret)
+        ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n"
+        fdef.write(ret)
+
+    fdecl.write("\n#endif");
+    ret = gen_registry(commands)
+    fdef.write(ret)
+
+    fdef.flush()
+    fdef.close()
+    fdecl.flush()
+    fdecl.close()
diff --git a/qemu-0.15.x/scripts/qapi-types.py b/qemu-0.15.x/scripts/qapi-types.py
new file mode 100644
index 0000000..cece325
--- /dev/null
+++ b/qemu-0.15.x/scripts/qapi-types.py
@@ -0,0 +1,270 @@
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori at us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_fwd_struct(name, members):
+    return mcgen('''
+typedef struct %(name)s %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name)
+
+def generate_struct(structname, fieldname, members):
+    ret = mcgen('''
+struct %(name)s
+{
+''',
+          name=structname)
+
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+    bool has_%(c_name)s;
+''',
+                         c_name=c_var(argname))
+        if structured:
+            push_indent()
+            ret += generate_struct("", argname, argentry)
+            pop_indent()
+        else:
+            ret += mcgen('''
+    %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(argentry), c_name=c_var(argname))
+
+    if len(fieldname):
+        fieldname = " " + fieldname
+    ret += mcgen('''
+}%(field)s;
+''',
+            field=fieldname)
+
+    return ret
+
+def generate_enum_lookup(name, values):
+    ret = mcgen('''
+const char *%(name)s_lookup[] = {
+''',
+                         name=name)
+    i = 0
+    for value in values:
+        ret += mcgen('''
+    "%(value)s",
+''',
+                     value=c_var(value).lower())
+
+    ret += mcgen('''
+    NULL,
+};
+
+''')
+    return ret
+
+def generate_enum(name, values):
+    lookup_decl = mcgen('''
+extern const char *%(name)s_lookup[];
+''',
+                name=name)
+
+    enum_decl = mcgen('''
+typedef enum %(name)s
+{
+''',
+                name=name)
+
+    i = 0
+    for value in values:
+        enum_decl += mcgen('''
+    %(abbrev)s_%(value)s = %(i)d,
+''',
+                     abbrev=de_camel_case(name).upper(),
+                     value=c_var(value).upper(),
+                     i=i)
+        i += 1
+
+    enum_decl += mcgen('''
+} %(name)s;
+''',
+                 name=name)
+
+    return lookup_decl + enum_decl
+
+def generate_union(name, typeinfo):
+    ret = mcgen('''
+struct %(name)s
+{
+    %(name)sKind kind;
+    union {
+''',
+                name=name)
+
+    for key in typeinfo:
+        ret += mcgen('''
+        %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(typeinfo[key]),
+                     c_name=c_var(key))
+
+    ret += mcgen('''
+    };
+};
+''')
+
+    return ret
+
+def generate_type_cleanup_decl(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+def generate_type_cleanup(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+    QapiDeallocVisitor *md;
+    Visitor *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-types.c'
+h_file = 'qapi-types.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * deallocation functions for schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *  Michael Roth      <mdroth at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+                  guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_fwd_struct(expr['type'], expr['data'])
+    elif expr.has_key('enum'):
+        ret += generate_enum(expr['enum'], expr['data'])
+        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
+    elif expr.has_key('union'):
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+    else:
+        continue
+    fdecl.write(ret)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+        ret += generate_type_cleanup_decl(expr['type'])
+        fdef.write(generate_type_cleanup(expr['type']) + "\n")
+    elif expr.has_key('union'):
+        ret += generate_union(expr['union'], expr['data'])
+    else:
+        continue
+    fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
diff --git a/qemu-0.15.x/scripts/qapi-visit.py b/qemu-0.15.x/scripts/qapi-visit.py
new file mode 100644
index 0000000..252230e
--- /dev/null
+++ b/qemu-0.15.x/scripts/qapi-visit.py
@@ -0,0 +1,246 @@
+#
+# QAPI visitor generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori at us.ibm.com>
+#  Michael Roth    <mdroth at linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_visit_struct_body(field_prefix, members):
+    ret = ""
+    if len(field_prefix):
+        field_prefix = field_prefix + "."
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(m, (obj && *obj) ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
+if ((*obj)->%(prefix)shas_%(c_name)s) {
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+
+        if structured:
+            ret += mcgen('''
+visit_start_struct(m, NULL, "", "%(name)s", 0, errp);
+''',
+                         name=argname)
+            ret += generate_visit_struct_body(field_prefix + argname, argentry)
+            ret += mcgen('''
+visit_end_struct(m, errp);
+''')
+        else:
+            ret += mcgen('''
+visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         type=type_name(argentry), c_name=c_var(argname),
+                         name=argname)
+
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(m, errp);
+''')
+    return ret
+
+def generate_visit_struct(name, members):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+''',
+                name=name)
+    push_indent()
+    ret += generate_visit_struct_body("", members)
+    pop_indent()
+
+    ret += mcgen('''
+    visit_end_struct(m, errp);
+}
+''')
+    return ret
+
+def generate_visit_list(name, members):
+    return mcgen('''
+
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+{
+    GenericList *i;
+
+    visit_start_list(m, name, errp);
+
+    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+        %(name)sList *native_i = (%(name)sList *)i;
+        visit_type_%(name)s(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+''',
+                name=name)
+
+def generate_visit_enum(name, members):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+{
+    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
+}
+''',
+                 name=name)
+
+def generate_visit_union(name, members):
+    ret = generate_visit_enum('%sKind' % name, members.keys())
+
+    ret += mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+}
+''',
+                 name=name)
+
+    return ret
+
+def generate_declaration(name, members, genlist=True):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+                 name=name)
+
+    return ret
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-visit.c'
+h_file = 'qapi-visit.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor functions
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "%(header)s"
+''',
+                 header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor function
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-visit-core.h"
+#include "%(prefix)sqapi-types.h"
+''',
+                  prefix=prefix, guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    if expr.has_key('type'):
+        ret = generate_visit_struct(expr['type'], expr['data'])
+        ret += generate_visit_list(expr['type'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_declaration(expr['type'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('union'):
+        ret = generate_visit_union(expr['union'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
+        ret += generate_declaration(expr['union'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('enum'):
+        ret = generate_visit_enum(expr['enum'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum(expr['enum'], expr['data'])
+        fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/qemu-0.15.x/scripts/qapi.py b/qemu-0.15.x/scripts/qapi.py
new file mode 100644
index 0000000..56af232
--- /dev/null
+++ b/qemu-0.15.x/scripts/qapi.py
@@ -0,0 +1,203 @@
+#
+# QAPI helper library
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori at us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+
+def tokenize(data):
+    while len(data):
+        if data[0] in ['{', '}', ':', ',', '[', ']']:
+            yield data[0]
+            data = data[1:]
+        elif data[0] in ' \n':
+            data = data[1:]
+        elif data[0] == "'":
+            data = data[1:]
+            string = ''
+            while data[0] != "'":
+                string += data[0]
+                data = data[1:]
+            data = data[1:]
+            yield string
+
+def parse(tokens):
+    if tokens[0] == '{':
+        ret = OrderedDict()
+        tokens = tokens[1:]
+        while tokens[0] != '}':
+            key = tokens[0]
+            tokens = tokens[1:]
+
+            tokens = tokens[1:] # :
+
+            value, tokens = parse(tokens)
+
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+
+            ret[key] = value
+        tokens = tokens[1:]
+        return ret, tokens
+    elif tokens[0] == '[':
+        ret = []
+        tokens = tokens[1:]
+        while tokens[0] != ']':
+            value, tokens = parse(tokens)
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+            ret.append(value)
+        tokens = tokens[1:]
+        return ret, tokens
+    else:
+        return tokens[0], tokens[1:]
+
+def evaluate(string):
+    return parse(map(lambda x: x, tokenize(string)))[0]
+
+def parse_schema(fp):
+    exprs = []
+    expr = ''
+    expr_eval = None
+
+    for line in fp:
+        if line.startswith('#') or line == '\n':
+            continue
+
+        if line.startswith(' '):
+            expr += line
+        elif expr:
+            expr_eval = evaluate(expr)
+            if expr_eval.has_key('enum'):
+                add_enum(expr_eval['enum'])
+            elif expr_eval.has_key('union'):
+                add_enum('%sKind' % expr_eval['union'])
+            exprs.append(expr_eval)
+            expr = line
+        else:
+            expr += line
+
+    if expr:
+        expr_eval = evaluate(expr)
+        if expr_eval.has_key('enum'):
+            add_enum(expr_eval['enum'])
+        elif expr_eval.has_key('union'):
+            add_enum('%sKind' % expr_eval['union'])
+        exprs.append(expr_eval)
+
+    return exprs
+
+def parse_args(typeinfo):
+    for member in typeinfo:
+        argname = member
+        argentry = typeinfo[member]
+        optional = False
+        structured = False
+        if member.startswith('*'):
+            argname = member[1:]
+            optional = True
+        if isinstance(argentry, OrderedDict):
+            structured = True
+        yield (argname, argentry, optional, structured)
+
+def de_camel_case(name):
+    new_name = ''
+    for ch in name:
+        if ch.isupper() and new_name:
+            new_name += '_'
+        if ch == '-':
+            new_name += '_'
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def camel_case(name):
+    new_name = ''
+    first = True
+    for ch in name:
+        if ch in ['_', '-']:
+            first = True
+        elif first:
+            new_name += ch.upper()
+            first = False
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def c_var(name):
+    return '_'.join(name.split('-')).lstrip("*")
+
+def c_list_type(name):
+    return '%sList' % name
+
+def type_name(name):
+    if type(name) == list:
+        return c_list_type(name[0])
+    return name
+
+enum_types = []
+
+def add_enum(name):
+    global enum_types
+    enum_types.append(name)
+
+def is_enum(name):
+    global enum_types
+    return (name in enum_types)
+
+def c_type(name):
+    if name == 'str':
+        return 'char *'
+    elif name == 'int':
+        return 'int64_t'
+    elif name == 'bool':
+        return 'bool'
+    elif name == 'number':
+        return 'double'
+    elif type(name) == list:
+        return '%s *' % c_list_type(name[0])
+    elif is_enum(name):
+        return name
+    elif name == None or len(name) == 0:
+        return 'void'
+    elif name == name.upper():
+        return '%sEvent *' % camel_case(name)
+    else:
+        return '%s *' % name
+
+def genindent(count):
+    ret = ""
+    for i in range(count):
+        ret += " "
+    return ret
+
+indent_level = 0
+
+def push_indent(indent_amount=4):
+    global indent_level
+    indent_level += indent_amount
+
+def pop_indent(indent_amount=4):
+    global indent_level
+    indent_level -= indent_amount
+
+def cgen(code, **kwds):
+    indent = genindent(indent_level)
+    lines = code.split('\n')
+    lines = map(lambda x: indent + x, lines)
+    return '\n'.join(lines) % kwds + '\n'
+
+def mcgen(code, **kwds):
+    return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
+
+def basename(filename):
+    return filename.split("/")[-1]
+
+def guardname(filename):
+    return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()
diff --git a/qemu-0.15.x/scripts/qemu-binfmt-conf.sh b/qemu-0.15.x/scripts/qemu-binfmt-conf.sh
new file mode 100644
index 0000000..83a44d8
--- /dev/null
+++ b/qemu-0.15.x/scripts/qemu-binfmt-conf.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390 program execution by the kernel
+
+# load the binfmt_misc module
+if [ ! -d /proc/sys/fs/binfmt_misc ]; then
+  /sbin/modprobe binfmt_misc
+fi
+if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
+  mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
+fi
+
+# probe cpu type
+cpu=`uname -m`
+case "$cpu" in
+  i386|i486|i586|i686|i86pc|BePC|x86_64)
+    cpu="i386"
+  ;;
+  m68k)
+    cpu="m68k"
+  ;;
+  mips*)
+    cpu="mips"
+  ;;
+  "Power Macintosh"|ppc|ppc64)
+    cpu="ppc"
+  ;;
+  armv[4-9]*)
+    cpu="arm"
+  ;;
+esac
+
+# register the interpreter for each cpu except for the native one
+if [ $cpu != "i386" ] ; then
+    echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
+    echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "alpha" ] ; then
+    echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "arm" ] ; then
+    echo   ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "sparc" ] ; then
+    echo   ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "ppc" ] ; then
+    echo   ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "m68k" ] ; then
+    echo   'Please check cpu value and header information for m68k!'
+    echo   ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "mips" ] ; then
+    # FIXME: We could use the other endianness on a MIPS host.
+    echo   ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register
+fi
+if [ $cpu != "sh" ] ; then
+    echo    ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register
+    echo    ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register
+if [ $cpu != "s390x" ] ; then
+    echo   ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register
+fi
diff --git a/qemu-0.15.x/scripts/refresh-pxe-roms.sh b/qemu-0.15.x/scripts/refresh-pxe-roms.sh
new file mode 100755
index 0000000..14d5860
--- /dev/null
+++ b/qemu-0.15.x/scripts/refresh-pxe-roms.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+# PXE ROM build script
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#   Authors: Alex Williamson <alex.williamson at redhat.com>
+#
+# Usage: Run from root of qemu tree
+# ./scripts/refresh-pxe-roms.sh
+
+QEMU_DIR=$PWD
+ROM_DIR="pc-bios"
+BUILD_DIR="roms/ipxe"
+LOCAL_CONFIG="src/config/local/general.h"
+
+function cleanup ()
+{
+    if [ -n "$SAVED_CONFIG" ]; then
+        cp "$SAVED_CONFIG" "$BUILD_DIR"/"$LOCAL_CONFIG"
+        rm "$SAVED_CONFIG"
+    fi
+    cd "$QEMU_DIR"
+}
+
+function make_rom ()
+{
+    cd "$BUILD_DIR"/src
+
+    BUILD_LOG=$(mktemp)
+
+    echo Building "$2"...
+    make bin/"$1".rom > "$BUILD_LOG" 2>&1
+    if [ $? -ne 0 ]; then
+        echo Build failed
+        tail --lines=100 "$BUILD_LOG"
+        rm "$BUILD_LOG"
+        cleanup
+        exit 1
+    fi
+    rm "$BUILD_LOG"
+
+    cp bin/"$1".rom "$QEMU_DIR"/"$ROM_DIR"/"$2"
+
+    cd "$QEMU_DIR"
+}
+
+if [ ! -d "$QEMU_DIR"/"$ROM_DIR" ]; then
+    echo "error: can't find $ROM_DIR directory," \
+         "run me from the root of the qemu tree"
+    exit 1
+fi
+
+if [ ! -d "$BUILD_DIR"/src ]; then
+    echo "error: $BUILD_DIR not populated, try:"
+    echo "  git submodule init $BUILD_DIR"
+    echo "  git submodule update $BUILD_DIR"
+    exit 1
+fi
+
+if [ -e "$BUILD_DIR"/"$LOCAL_CONFIG" ]; then
+    SAVED_CONFIG=$(mktemp)
+    cp "$BUILD_DIR"/"$LOCAL_CONFIG" "$SAVED_CONFIG"
+fi
+
+echo "#undef BANNER_TIMEOUT" > "$BUILD_DIR"/"$LOCAL_CONFIG"
+echo "#define BANNER_TIMEOUT 0" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+
+IPXE_VERSION=$(cd "$BUILD_DIR" && git describe --tags)
+if [ -z "$IPXE_VERSION" ]; then
+    echo "error: unable to retrieve git version"
+    cleanup
+    exit 1
+fi
+
+echo "#undef PRODUCT_NAME" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+echo "#define PRODUCT_NAME \"iPXE $IPXE_VERSION\"" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+
+make_rom 8086100e pxe-e1000.rom
+make_rom 80861209 pxe-eepro100.rom
+make_rom 10500940 pxe-ne2k_pci.rom
+make_rom 10222000 pxe-pcnet.rom
+make_rom 10ec8139 pxe-rtl8139.rom
+make_rom 1af41000 pxe-virtio.rom
+
+echo done
+cleanup
diff --git a/qemu-0.15.x/scripts/signrom.sh b/qemu-0.15.x/scripts/signrom.sh
new file mode 100755
index 0000000..9dc5c63
--- /dev/null
+++ b/qemu-0.15.x/scripts/signrom.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# Option ROM Signing utility
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright Novell Inc, 2009
+#   Authors: Alexander Graf <agraf at suse.de>
+#
+# Syntax: signrom.sh <input> <output>
+
+# did we get proper arguments?
+test "$1" -a "$2" || exit 1
+
+sum=0
+
+# find out the file size
+x=`dd if="$1" bs=1 count=1 skip=2 2>/dev/null | od -t u1 -A n`
+#size=`expr $x \* 512 - 1`
+size=$(( $x * 512 - 1 ))
+
+# now get the checksum
+nums=`od -A n -t u1 -v -N $size "$1"`
+for i in ${nums}; do
+    # add each byte's value to sum
+    sum=`expr \( $sum + $i \) % 256`
+done
+
+sum=$(( (256 - $sum) % 256 ))
+sum_octal=$( printf "%o" $sum )
+
+# and write the output file
+cp "$1" "$2"
+printf "\\$sum_octal" | dd of="$2" bs=1 count=1 seek=$size conv=notrunc 2>/dev/null
diff --git a/qemu-0.15.x/scripts/simpletrace.py b/qemu-0.15.x/scripts/simpletrace.py
new file mode 100755
index 0000000..2ad5699
--- /dev/null
+++ b/qemu-0.15.x/scripts/simpletrace.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#
+# Pretty-printer for simple trace backend binary trace files
+#
+# Copyright IBM, Corp. 2010
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# For help see docs/tracing.txt
+
+import struct
+import re
+import inspect
+
+header_event_id = 0xffffffffffffffff
+header_magic    = 0xf2b177cb0aa429b4
+header_version  = 0
+dropped_event_id = 0xfffffffffffffffe
+
+trace_fmt = '=QQQQQQQQ'
+trace_len = struct.calcsize(trace_fmt)
+event_re  = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
+
+def parse_events(fobj):
+    """Parse a trace-events file into {event_num: (name, arg1, ...)}."""
+
+    def get_argnames(args):
+        """Extract argument names from a parameter list."""
+        return tuple(arg.split()[-1].lstrip('*') for arg in args.split(','))
+
+    events = {dropped_event_id: ('dropped', 'count')}
+    event_num = 0
+    for line in fobj:
+        m = event_re.match(line.strip())
+        if m is None:
+            continue
+
+        disable, name, args = m.groups()
+        events[event_num] = (name,) + get_argnames(args)
+        event_num += 1
+    return events
+
+def read_record(fobj):
+    """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
+    s = fobj.read(trace_len)
+    if len(s) != trace_len:
+        return None
+    return struct.unpack(trace_fmt, s)
+
+def read_trace_file(fobj):
+    """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6)."""
+    header = read_record(fobj)
+    if header is None or \
+       header[0] != header_event_id or \
+       header[1] != header_magic or \
+       header[2] != header_version:
+        raise ValueError('not a trace file or incompatible version')
+
+    while True:
+        rec = read_record(fobj)
+        if rec is None:
+            break
+
+        yield rec
+
+class Analyzer(object):
+    """A trace file analyzer which processes trace records.
+
+    An analyzer can be passed to run() or process().  The begin() method is
+    invoked, then each trace record is processed, and finally the end() method
+    is invoked.
+
+    If a method matching a trace event name exists, it is invoked to process
+    that trace record.  Otherwise the catchall() method is invoked."""
+
+    def begin(self):
+        """Called at the start of the trace."""
+        pass
+
+    def catchall(self, event, rec):
+        """Called if no specific method for processing a trace event has been found."""
+        pass
+
+    def end(self):
+        """Called at the end of the trace."""
+        pass
+
+def process(events, log, analyzer):
+    """Invoke an analyzer on each event in a log."""
+    if isinstance(events, str):
+        events = parse_events(open(events, 'r'))
+    if isinstance(log, str):
+        log = open(log, 'rb')
+
+    def build_fn(analyzer, event):
+        fn = getattr(analyzer, event[0], None)
+        if fn is None:
+            return analyzer.catchall
+
+        event_argcount = len(event) - 1
+        fn_argcount = len(inspect.getargspec(fn)[0]) - 1
+        if fn_argcount == event_argcount + 1:
+            # Include timestamp as first argument
+            return lambda _, rec: fn(*rec[1:2 + fn_argcount])
+        else:
+            # Just arguments, no timestamp
+            return lambda _, rec: fn(*rec[2:2 + fn_argcount])
+
+    analyzer.begin()
+    fn_cache = {}
+    for rec in read_trace_file(log):
+        event_num = rec[0]
+        event = events[event_num]
+        if event_num not in fn_cache:
+            fn_cache[event_num] = build_fn(analyzer, event)
+        fn_cache[event_num](event, rec)
+    analyzer.end()
+
+def run(analyzer):
+    """Execute an analyzer on a trace file given on the command-line.
+
+    This function is useful as a driver for simple analysis scripts.  More
+    advanced scripts will want to call process() instead."""
+    import sys
+
+    if len(sys.argv) != 3:
+        sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
+        sys.exit(1)
+
+    events = parse_events(open(sys.argv[1], 'r'))
+    process(events, sys.argv[2], analyzer)
+
+if __name__ == '__main__':
+    class Formatter(Analyzer):
+        def __init__(self):
+            self.last_timestamp = None
+
+        def catchall(self, event, rec):
+            timestamp = rec[1]
+            if self.last_timestamp is None:
+                self.last_timestamp = timestamp
+            delta_ns = timestamp - self.last_timestamp
+            self.last_timestamp = timestamp
+
+            fields = [event[0], '%0.3f' % (delta_ns / 1000.0)]
+            for i in xrange(1, len(event)):
+                fields.append('%s=0x%x' % (event[i], rec[i + 1]))
+            print ' '.join(fields)
+
+    run(Formatter())
diff --git a/qemu-0.15.x/scripts/texi2pod.pl b/qemu-0.15.x/scripts/texi2pod.pl
new file mode 100755
index 0000000..9ed056a
--- /dev/null
+++ b/qemu-0.15.x/scripts/texi2pod.pl
@@ -0,0 +1,477 @@
+#! /usr/bin/perl -w
+
+#   Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING.  If not,
+# see <http://www.gnu.org/licenses/>.
+
+# This does trivial (and I mean _trivial_) conversion of Texinfo
+# markup to Perl POD format.  It's intended to be used to extract
+# something suitable for a manpage from a Texinfo document.
+
+$output = 0;
+$skipping = 0;
+%sects = ();
+$section = "";
+ at icstack = ();
+ at endwstack = ();
+ at skstack = ();
+ at instack = ();
+$shift = "";
+%defs = ();
+$fnno = 1;
+$inf = "";
+$ibase = "";
+ at ipath = ();
+
+while ($_ = shift) {
+    if (/^-D(.*)$/) {
+	if ($1 ne "") {
+	    $flag = $1;
+	} else {
+	    $flag = shift;
+	}
+	$value = "";
+	($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
+	die "no flag specified for -D\n"
+	    unless $flag ne "";
+	die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
+	    unless $flag =~ /^[a-zA-Z0-9_-]+$/;
+	$defs{$flag} = $value;
+    } elsif (/^-I(.*)$/) {
+	if ($1 ne "") {
+	    $flag = $1;
+	} else {
+	    $flag = shift;
+	}
+        push (@ipath, $flag);
+    } elsif (/^-/) {
+	usage();
+    } else {
+	$in = $_, next unless defined $in;
+	$out = $_, next unless defined $out;
+	usage();
+    }
+}
+
+if (defined $in) {
+    $inf = gensym();
+    open($inf, "<$in") or die "opening \"$in\": $!\n";
+    $ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
+} else {
+    $inf = \*STDIN;
+}
+
+if (defined $out) {
+    open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
+}
+
+while(defined $inf) {
+while(<$inf>) {
+    # Certain commands are discarded without further processing.
+    /^\@(?:
+	 [a-z]+index		# @*index: useful only in complete manual
+	 |need			# @need: useful only in printed manual
+	 |(?:end\s+)?group	# @group .. @end group: ditto
+	 |page			# @page: ditto
+	 |node			# @node: useful only in .info file
+	 |(?:end\s+)?ifnottex   # @ifnottex .. @end ifnottex: use contents
+	)\b/x and next;
+
+    chomp;
+
+    # Look for filename and title markers.
+    /^\@setfilename\s+([^.]+)/ and $fn = $1, next;
+    /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
+
+    # Identify a man title but keep only the one we are interested in.
+    /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
+	if (exists $defs{$1}) {
+	    $fn = $1;
+	    $tl = postprocess($2);
+	}
+	next;
+    };
+
+    # Look for blocks surrounded by @c man begin SECTION ... @c man end.
+    # This really oughta be @ifman ... @end ifman and the like, but such
+    # would require rev'ing all other Texinfo translators.
+    /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
+	$output = 1 if exists $defs{$2};
+        $sect = $1;
+	next;
+    };
+    /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
+    /^\@c\s+man\s+end/ and do {
+	$sects{$sect} = "" unless exists $sects{$sect};
+	$sects{$sect} .= postprocess($section);
+	$section = "";
+	$output = 0;
+	next;
+    };
+
+    # handle variables
+    /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
+	$defs{$1} = $2;
+	next;
+    };
+    /^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
+	delete $defs{$1};
+	next;
+    };
+
+    next unless $output;
+
+    # Discard comments.  (Can't do it above, because then we'd never see
+    # @c man lines.)
+    /^\@c\b/ and next;
+
+    # End-block handler goes up here because it needs to operate even
+    # if we are skipping.
+    /^\@end\s+([a-z]+)/ and do {
+	# Ignore @end foo, where foo is not an operation which may
+	# cause us to skip, if we are presently skipping.
+	my $ended = $1;
+	next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/;
+
+	die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
+	die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
+
+	$endw = pop @endwstack;
+
+	if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
+	    $skipping = pop @skstack;
+	    next;
+	} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
+	    $shift = "";
+	    $_ = "";	# need a paragraph break
+	} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
+	    $_ = "\n=back\n";
+	    $ic = pop @icstack;
+	} elsif ($ended eq "multitable") {
+	    $_ = "\n=back\n";
+	} else {
+	    die "unknown command \@end $ended at line $.\n";
+	}
+    };
+
+    # We must handle commands which can cause skipping even while we
+    # are skipping, otherwise we will not process nested conditionals
+    # correctly.
+    /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = "ifset";
+	$skipping = 1 unless exists $defs{$1};
+	next;
+    };
+
+    /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = "ifclear";
+	$skipping = 1 if exists $defs{$1};
+	next;
+    };
+
+    /^\@(ignore|menu|iftex|copying)\b/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = $1;
+	$skipping = 1;
+	next;
+    };
+
+    next if $skipping;
+
+    # Character entities.  First the ones that can be replaced by raw text
+    # or discarded outright:
+    s/\@copyright\{\}/(c)/g;
+    s/\@dots\{\}/.../g;
+    s/\@enddots\{\}/..../g;
+    s/\@([.!? ])/$1/g;
+    s/\@[:-]//g;
+    s/\@bullet(?:\{\})?/*/g;
+    s/\@TeX\{\}/TeX/g;
+    s/\@pounds\{\}/\#/g;
+    s/\@minus(?:\{\})?/-/g;
+    s/\\,/,/g;
+
+    # Now the ones that have to be replaced by special escapes
+    # (which will be turned back into text by unmunge())
+    s/&/&/g;
+    s/\@\{/{/g;
+    s/\@\}/}/g;
+    s/\@\@/&at;/g;
+
+    # Inside a verbatim block, handle @var specially.
+    if ($shift ne "") {
+	s/\@var\{([^\}]*)\}/<$1>/g;
+    }
+
+    # POD doesn't interpret E<> inside a verbatim block.
+    if ($shift eq "") {
+	s/</</g;
+	s/>/>/g;
+    } else {
+	s/</</g;
+	s/>/>/g;
+    }
+
+    # Single line command handlers.
+
+    /^\@include\s+(.+)$/ and do {
+	push @instack, $inf;
+	$inf = gensym();
+	$file = postprocess($1);
+
+	# Try cwd and $ibase, then explicit -I paths.
+	$done = 0;
+	foreach $path ("", $ibase, @ipath) {
+	    $mypath = $file;
+	    $mypath = $path . "/" . $mypath if ($path ne "");
+	    open($inf, "<" . $mypath) and ($done = 1, last);
+	}
+	die "cannot find $file" if !$done;
+	next;
+    };
+
+    /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
+	and $_ = "\n=head2 $1\n";
+    /^\@subsection\s+(.+)$/
+	and $_ = "\n=head3 $1\n";
+    /^\@subsubsection\s+(.+)$/
+	and $_ = "\n=head4 $1\n";
+
+    # Block command handlers:
+    /^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	if (defined $1) {
+	    $ic = $1;
+	} else {
+	    $ic = '*';
+	}
+	$_ = "\n=over 4\n";
+	$endw = "itemize";
+    };
+
+    /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	if (defined $1) {
+	    $ic = $1 . ".";
+	} else {
+	    $ic = "1.";
+	}
+	$_ = "\n=over 4\n";
+	$endw = "enumerate";
+    };
+
+    /^\@multitable\s.*/ and do {
+	push @endwstack, $endw;
+	$endw = "multitable";
+	$_ = "\n=over 4\n";
+    };
+
+    /^\@([fv]?table)\s+(\@[a-z]+)/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	$endw = $1;
+	$ic = $2;
+	$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
+	$ic =~ s/\@(?:code|kbd)/C/;
+	$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
+	$ic =~ s/\@(?:file)/F/;
+	$_ = "\n=over 4\n";
+    };
+
+    /^\@((?:small)?example|display)/ and do {
+	push @endwstack, $endw;
+	$endw = $1;
+	$shift = "\t";
+	$_ = "";	# need a paragraph break
+    };
+
+    /^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do {
+	@columns = ();
+	for $column (split (/\s*\@tab\s*/, $1)) {
+	    # @strong{...} is used a @headitem work-alike
+	    $column =~ s/^\@strong{(.*)}$/$1/;
+	    push @columns, $column;
+	}
+	$_ = "\n=item ".join (" : ", @columns)."\n";
+    };
+
+    /^\@itemx?\s*(.+)?$/ and do {
+	if (defined $1) {
+	    # Entity escapes prevent munging by the <> processing below.
+	    $_ = "\n=item $ic\<$1\>\n";
+	} else {
+	    $_ = "\n=item $ic\n";
+	    $ic =~ y/A-Ya-y/B-Zb-z/;
+	    $ic =~ s/(\d+)/$1 + 1/eg;
+	}
+    };
+
+    $section .= $shift.$_."\n";
+}
+# End of current file.
+close($inf);
+$inf = pop @instack;
+}
+
+die "No filename or title\n" unless defined $fn && defined $tl;
+
+$sects{NAME} = "$fn \- $tl\n";
+$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
+
+for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
+	      BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
+    if(exists $sects{$sect}) {
+	$head = $sect;
+	$head =~ s/SEEALSO/SEE ALSO/;
+	print "=head1 $head\n\n";
+	print scalar unmunge ($sects{$sect});
+	print "\n";
+    }
+}
+
+sub usage
+{
+    die "usage: $0 [-D toggle...] [infile [outfile]]\n";
+}
+
+sub postprocess
+{
+    local $_ = $_[0];
+
+    # @value{foo} is replaced by whatever 'foo' is defined as.
+    while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
+	if (! exists $defs{$2}) {
+	    print STDERR "Option $2 not defined\n";
+	    s/\Q$1\E//;
+	} else {
+	    $value = $defs{$2};
+	    s/\Q$1\E/$value/;
+	}
+    }
+
+    # Formatting commands.
+    # Temporary escape for @r.
+    s/\@r\{([^\}]*)\}/R<$1>/g;
+    s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
+    s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
+    s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
+    s/\@sc\{([^\}]*)\}/\U$1/g;
+    s/\@file\{([^\}]*)\}/F<$1>/g;
+    s/\@w\{([^\}]*)\}/S<$1>/g;
+    s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
+
+    # keep references of the form @ref{...}, print them bold
+    s/\@(?:ref)\{([^\}]*)\}/B<$1>/g;
+
+    # Change double single quotes to double quotes.
+    s/''/"/g;
+    s/``/"/g;
+
+    # Cross references are thrown away, as are @noindent and @refill.
+    # (@noindent is impossible in .pod, and @refill is unnecessary.)
+    # @* is also impossible in .pod; we discard it and any newline that
+    # follows it.  Similarly, our macro @gol must be discarded.
+
+    s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
+    s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
+    s/;\s+\@pxref\{(?:[^\}]*)\}//g;
+    s/\@noindent\s*//g;
+    s/\@refill//g;
+    s/\@gol//g;
+    s/\@\*\s*\n?//g;
+
+    # Anchors are thrown away
+    s/\@anchor\{(?:[^\}]*)\}//g;
+
+    # @uref can take one, two, or three arguments, with different
+    # semantics each time.  @url and @email are just like @uref with
+    # one argument, for our purposes.
+    s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g;
+    s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
+    s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
+
+    # Un-escape <> at this point.
+    s/</</g;
+    s/>/>/g;
+
+    # Now un-nest all B<>, I<>, R<>.  Theoretically we could have
+    # indefinitely deep nesting; in practice, one level suffices.
+    1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1</g;
+
+    # Replace R<...> with bare ...; eliminate empty markup, B<>;
+    # shift white space at the ends of [BI]<...> expressions outside
+    # the expression.
+    s/R<([^<>]*)>/$1/g;
+    s/[BI]<>//g;
+    s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
+    s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
+
+    # Extract footnotes.  This has to be done after all other
+    # processing because otherwise the regexp will choke on formatting
+    # inside @footnote.
+    while (/\@footnote/g) {
+	s/\@footnote\{([^\}]+)\}/[$fnno]/;
+	add_footnote($1, $fnno);
+	$fnno++;
+    }
+
+    return $_;
+}
+
+sub unmunge
+{
+    # Replace escaped symbols with their equivalents.
+    local $_ = $_[0];
+
+    s/</E<lt>/g;
+    s/>/E<gt>/g;
+    s/{/\{/g;
+    s/}/\}/g;
+    s/&at;/\@/g;
+    s/&/&/g;
+    return $_;
+}
+
+sub add_footnote
+{
+    unless (exists $sects{FOOTNOTES}) {
+	$sects{FOOTNOTES} = "\n=over 4\n\n";
+    }
+
+    $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
+    $sects{FOOTNOTES} .= $_[0];
+    $sects{FOOTNOTES} .= "\n\n";
+}
+
+# stolen from Symbol.pm
+{
+    my $genseq = 0;
+    sub gensym
+    {
+	my $name = "GEN" . $genseq++;
+	my $ref = \*{$name};
+	delete $::{$name};
+	return $ref;
+    }
+}
diff --git a/qemu-0.15.x/scripts/tracetool b/qemu-0.15.x/scripts/tracetool
new file mode 100755
index 0000000..2155a57
--- /dev/null
+++ b/qemu-0.15.x/scripts/tracetool
@@ -0,0 +1,637 @@
+#!/bin/sh
+#
+# Code generator for trace events
+#
+# Copyright IBM, Corp. 2010
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+# Disable pathname expansion, makes processing text with '*' characters simpler
+set -f
+
+usage()
+{
+    cat >&2 <<EOF
+usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
+Generate tracing code for a file on stdin.
+
+Backends:
+  --nop     Tracing disabled
+  --simple  Simple built-in backend
+  --stderr  Stderr built-in backend
+  --ust     LTTng User Space Tracing backend
+  --dtrace  DTrace/SystemTAP backend
+
+Output formats:
+  -h     Generate .h file
+  -c     Generate .c file
+  -d     Generate .d file (DTrace only)
+  --stap Generate .stp file (DTrace with SystemTAP only)
+
+Options:
+  --binary       [path]    Full path to QEMU binary
+  --target-arch  [arch]    QEMU emulator target arch
+  --target-type  [type]    QEMU emulator target type ('system' or 'user')
+  --probe-prefix [prefix]  Prefix for dtrace probe names
+                           (default: qemu-\$targettype-\$targetarch)
+
+EOF
+    exit 1
+}
+
+# Get the name of a trace event
+get_name()
+{
+    echo ${1%%\(*}
+}
+
+# Get the argument list of a trace event, including types and names
+get_args()
+{
+    local args
+    args=${1#*\(}
+    args=${args%%\)*}
+    echo "$args"
+}
+
+# Get the argument name list of a trace event
+get_argnames()
+{
+    local nfields field name sep
+    nfields=0
+    sep="$2"
+    for field in $(get_args "$1"); do
+        nfields=$((nfields + 1))
+
+        # Drop pointer star
+        field=${field#\*}
+
+        # Only argument names have commas at the end
+        name=${field%,}
+        test "$field" = "$name" && continue
+
+        printf "%s%s " $name $sep
+    done
+
+    # Last argument name
+    if [ "$nfields" -gt 1 ]
+    then
+        printf "%s" "$name"
+    fi
+}
+
+# Get the number of arguments to a trace event
+get_argc()
+{
+    local name argc
+    argc=0
+    for name in $(get_argnames "$1", ","); do
+        argc=$((argc + 1))
+    done
+    echo $argc
+}
+
+# Get the format string for a trace event
+get_fmt()
+{
+    local fmt
+    fmt=${1#*\"}
+    fmt=${fmt%\"*}
+    echo "$fmt"
+}
+
+# Get the state of a trace event
+get_state()
+{
+    local str disable state
+    str=$(get_name "$1")
+    disable=${str##disable }
+    if [ "$disable" = "$str" ] ; then
+        state=1
+    else
+        state=0
+    fi
+    echo "$state"
+}
+
+linetoh_begin_nop()
+{
+    return
+}
+
+linetoh_nop()
+{
+    local name args
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+
+    # Define an empty function for the trace event
+    cat <<EOF
+static inline void trace_$name($args)
+{
+}
+EOF
+}
+
+linetoh_end_nop()
+{
+    return
+}
+
+linetoc_begin_nop()
+{
+    return
+}
+
+linetoc_nop()
+{
+    # No need for function definitions in nop backend
+    return
+}
+
+linetoc_end_nop()
+{
+    return
+}
+
+linetoh_begin_simple()
+{
+    cat <<EOF
+#include "simpletrace.h"
+EOF
+
+    simple_event_num=0
+}
+
+cast_args_to_uint64_t()
+{
+    local arg
+    for arg in $(get_argnames "$1", ","); do
+        printf "%s" "(uint64_t)(uintptr_t)$arg"
+    done
+}
+
+linetoh_simple()
+{
+    local name args argc trace_args state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argc=$(get_argc "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ]; then
+        name=${name##disable }
+    fi
+
+    trace_args="$simple_event_num"
+    if [ "$argc" -gt 0 ]
+    then
+        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
+    fi
+
+    cat <<EOF
+static inline void trace_$name($args)
+{
+    trace$argc($trace_args);
+}
+EOF
+
+    simple_event_num=$((simple_event_num + 1))
+}
+
+linetoh_end_simple()
+{
+    cat <<EOF
+#define NR_TRACE_EVENTS $simple_event_num
+extern TraceEvent trace_list[NR_TRACE_EVENTS];
+EOF
+}
+
+linetoc_begin_simple()
+{
+    cat <<EOF
+#include "trace.h"
+
+TraceEvent trace_list[] = {
+EOF
+    simple_event_num=0
+
+}
+
+linetoc_simple()
+{
+    local name state
+    name=$(get_name "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+    cat <<EOF
+{.tp_name = "$name", .state=$state},
+EOF
+    simple_event_num=$((simple_event_num + 1))
+}
+
+linetoc_end_simple()
+{
+    cat <<EOF
+};
+EOF
+}
+
+#STDERR
+linetoh_begin_stderr()
+{
+    cat <<EOF
+#include <stdio.h>
+EOF
+}
+
+linetoh_stderr()
+{
+    local name args argnames argc fmt
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1" ",")
+    argc=$(get_argc "$1")
+    fmt=$(get_fmt "$1")
+
+    if [ "$argc" -gt 0 ]; then
+        argnames=", $argnames"
+    fi
+
+    cat <<EOF
+static inline void trace_$name($args)
+{
+    fprintf(stderr, "$name $fmt\n" $argnames);
+}
+EOF
+}
+
+linetoh_end_stderr()
+{
+return
+}
+
+linetoc_begin_stderr()
+{
+return
+}
+
+linetoc_stderr()
+{
+return
+}
+
+linetoc_end_stderr()
+{
+return
+}
+#END OF STDERR
+
+# Clean up after UST headers which pollute the namespace
+ust_clean_namespace() {
+    cat <<EOF
+#undef mutex_lock
+#undef mutex_unlock
+#undef inline
+#undef wmb
+EOF
+}
+
+linetoh_begin_ust()
+{
+    echo "#include <ust/tracepoint.h>"
+    ust_clean_namespace
+}
+
+linetoh_ust()
+{
+    local name args argnames
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1", ",")
+
+    cat <<EOF
+DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
+#define trace_$name trace_ust_$name
+EOF
+}
+
+linetoh_end_ust()
+{
+    return
+}
+
+linetoc_begin_ust()
+{
+    cat <<EOF
+#include <ust/marker.h>
+$(ust_clean_namespace)
+#include "trace.h"
+EOF
+}
+
+linetoc_ust()
+{
+    local name args argnames fmt
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1", ",")
+    [ -z "$argnames" ] || argnames=", $argnames"
+    fmt=$(get_fmt "$1")
+
+    cat <<EOF
+DEFINE_TRACE(ust_$name);
+
+static void ust_${name}_probe($args)
+{
+    trace_mark(ust, $name, "$fmt"$argnames);
+}
+EOF
+
+    # Collect names for later
+    names="$names $name"
+}
+
+linetoc_end_ust()
+{
+    cat <<EOF
+static void __attribute__((constructor)) trace_init(void)
+{
+EOF
+
+    for name in $names; do
+        cat <<EOF
+    register_trace_ust_$name(ust_${name}_probe);
+EOF
+    done
+
+    echo "}"
+}
+
+linetoh_begin_dtrace()
+{
+    cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+    local name args argnames state nameupper
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1", ",")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+
+    # Define an empty function for the trace event
+    cat <<EOF
+static inline void trace_$name($args) {
+    if (QEMU_${nameupper}_ENABLED()) {
+        QEMU_${nameupper}($argnames);
+    }
+}
+EOF
+}
+
+linetoh_end_dtrace()
+{
+    return
+}
+
+linetoc_begin_dtrace()
+{
+    return
+}
+
+linetoc_dtrace()
+{
+    # No need for function definitions in dtrace backend
+    return
+}
+
+linetoc_end_dtrace()
+{
+    return
+}
+
+linetod_begin_dtrace()
+{
+    cat <<EOF
+provider qemu {
+EOF
+}
+
+linetod_dtrace()
+{
+    local name args state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # DTrace provider syntax expects foo() for empty
+    # params, not foo(void)
+    if [ "$args" = "void" ]; then
+       args=""
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+        probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+    cat <<EOF
+};
+EOF
+}
+
+linetostap_begin_dtrace()
+{
+    return
+}
+
+linetostap_dtrace()
+{
+    local i arg name args arglist state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    arglist=$(get_argnames "$1", "")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+probe $probeprefix.$name = process("$binary").mark("$name")
+{
+EOF
+
+    i=1
+    for arg in $arglist
+    do
+        # 'limit' is a reserved keyword
+        if [ "$arg" = "limit" ]; then
+          arg="_limit"
+        fi
+        cat <<EOF
+  $arg = \$arg$i;
+EOF
+        i="$((i+1))"
+    done
+
+    cat <<EOF
+}
+EOF
+}
+
+linetostap_end_dtrace()
+{
+    return
+}
+
+# Process stdin by calling begin, line, and end functions for the backend
+convert()
+{
+    local begin process_line end str disable
+    begin="lineto$1_begin_$backend"
+    process_line="lineto$1_$backend"
+    end="lineto$1_end_$backend"
+
+    "$begin"
+
+    while read -r str; do
+        # Skip comments and empty lines
+        test -z "${str%%#*}" && continue
+
+        # Process the line.  The nop backend handles disabled lines.
+        disable=${str%%disable *}
+        echo
+        if test -z "$disable"; then
+            # Pass the disabled state as an arg for the simple
+            # or DTrace backends which handle it dynamically.
+            # For all other backends, call lineto$1_nop()
+            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
+                "$process_line" "$str"
+            else
+                "lineto$1_nop" "${str##disable }"
+            fi
+        else
+            "$process_line" "$str"
+        fi
+    done
+
+    echo
+    "$end"
+}
+
+tracetoh()
+{
+    cat <<EOF
+#ifndef TRACE_H
+#define TRACE_H
+
+/* This file is autogenerated by tracetool, do not edit. */
+
+#include "qemu-common.h"
+EOF
+    convert h
+    echo "#endif /* TRACE_H */"
+}
+
+tracetoc()
+{
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert c
+}
+
+tracetod()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "DTrace probe generator not applicable to $backend backend"
+       exit 1
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert d
+}
+
+tracetostap()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "SystemTAP tapset generator not applicable to $backend backend"
+       exit 1
+    fi
+    if [ -z "$binary" ]; then
+       echo "--binary is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    if [ -z "$probeprefix" -a -z "$targettype" ]; then
+       echo "--target-type is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
+       echo "--target-arch is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    if [ -z "$probeprefix" ]; then
+        probeprefix="qemu.$targettype.$targetarch";
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert stap
+}
+
+
+backend=
+output=
+binary=
+targettype=
+targetarch=
+probeprefix=
+
+
+until [ -z "$1" ]
+do
+  case "$1" in
+    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
+
+    "--binary") shift ; binary="$1" ;;
+    "--target-arch") shift ; targetarch="$1" ;;
+    "--target-type") shift ; targettype="$1" ;;
+    "--probe-prefix") shift ; probeprefix="$1" ;;
+
+    "-h" | "-c" | "-d") output="${1#-}" ;;
+    "--stap") output="${1#--}" ;;
+
+    "--check-backend") exit 0 ;; # used by ./configure to test for backend
+
+    "--list-backends") # used by ./configure to list available backends
+          echo "nop simple stderr ust dtrace"
+          exit 0
+          ;;
+
+    *)
+      usage;;
+  esac
+  shift
+done
+
+if [ "$backend" = "" -o "$output" = "" ]; then
+  usage
+fi
+
+gen="traceto$output"
+"$gen"
+
+exit 0
diff --git a/qemu-0.15.x/scripts/update-linux-headers.sh b/qemu-0.15.x/scripts/update-linux-headers.sh
new file mode 100755
index 0000000..9d2a4bc
--- /dev/null
+++ b/qemu-0.15.x/scripts/update-linux-headers.sh
@@ -0,0 +1,55 @@
+#!/bin/sh -e
+#
+# Update Linux kernel headers QEMU requires from a specified kernel tree.
+#
+# Copyright (C) 2011 Siemens AG
+#
+# Authors:
+#  Jan Kiszka        <jan.kiszka at siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+# See the COPYING file in the top-level directory.
+
+tmpdir=`mktemp -d`
+linux="$1"
+output="$2"
+
+if [ -z "$linux" ] || ! [ -d "$linux" ]; then
+    cat << EOF
+usage: update-kernel-headers.sh LINUX_PATH [OUTPUT_PATH]
+
+LINUX_PATH      Linux kernel directory to obtain the headers from
+OUTPUT_PATH     output directory, usually the qemu source tree (default: $PWD)
+EOF
+    exit 1
+fi
+
+if [ -z "$output" ]; then
+    output="$PWD"
+fi
+
+for arch in x86 powerpc s390; do
+    make -C "$linux" INSTALL_HDR_PATH="$tmpdir" SRCARCH=$arch headers_install
+
+    rm -rf "$output/linux-headers/asm-$arch"
+    mkdir -p "$output/linux-headers/asm-$arch"
+    for header in kvm.h kvm_para.h; do
+        cp "$tmpdir/include/asm/$header" "$output/linux-headers/asm-$arch"
+    done
+    if [ $arch = x86 ]; then
+        cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86"
+    fi
+done
+
+rm -rf "$output/linux-headers/linux"
+mkdir -p "$output/linux-headers/linux"
+for header in kvm.h kvm_para.h vhost.h virtio_config.h virtio_ring.h; do
+    cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
+done
+if [ -L "$linux/source" ]; then
+    cp "$linux/source/COPYING" "$output/linux-headers"
+else
+    cp "$linux/COPYING" "$output/linux-headers"
+fi
+
+rm -rf "$tmpdir"
diff --git a/qemu-0.15.x/sh4-dis.c b/qemu-0.15.x/sh4-dis.c
new file mode 100644
index 0000000..673bc78
--- /dev/null
+++ b/qemu-0.15.x/sh4-dis.c
@@ -0,0 +1,2077 @@
+/* Disassemble SH instructions.
+   Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include "dis-asm.h"
+
+#define DEFINE_TABLE
+
+typedef enum
+  {
+    HEX_0,
+    HEX_1,
+    HEX_2,
+    HEX_3,
+    HEX_4,
+    HEX_5,
+    HEX_6,
+    HEX_7,
+    HEX_8,
+    HEX_9,
+    HEX_A,
+    HEX_B,
+    HEX_C,
+    HEX_D,
+    HEX_E,
+    HEX_F,
+    HEX_XX00,
+    HEX_00YY,
+    REG_N,
+    REG_N_D,     /* nnn0 */
+    REG_N_B01,   /* nn01 */
+    REG_M,
+    SDT_REG_N,
+    REG_NM,
+    REG_B,
+    BRANCH_12,
+    BRANCH_8,
+    IMM0_4,
+    IMM0_4BY2,
+    IMM0_4BY4,
+    IMM1_4,
+    IMM1_4BY2,
+    IMM1_4BY4,
+    PCRELIMM_8BY2,
+    PCRELIMM_8BY4,
+    IMM0_8,
+    IMM0_8BY2,
+    IMM0_8BY4,
+    IMM1_8,
+    IMM1_8BY2,
+    IMM1_8BY4,
+    PPI,
+    NOPX,
+    NOPY,
+    MOVX,
+    MOVY,
+    MOVX_NOPY,
+    MOVY_NOPX,
+    PSH,
+    PMUL,
+    PPI3,
+    PPI3NC,
+    PDC,
+    PPIC,
+    REPEAT,
+    IMM0_3c,	/* xxxx 0iii */
+    IMM0_3s,	/* xxxx 1iii */
+    IMM0_3Uc,	/* 0iii xxxx */
+    IMM0_3Us,	/* 1iii xxxx */
+    IMM0_20_4,
+    IMM0_20,	/* follows IMM0_20_4 */
+    IMM0_20BY8,	/* follows IMM0_20_4 */
+    DISP0_12,
+    DISP0_12BY2,
+    DISP0_12BY4,
+    DISP0_12BY8,
+    DISP1_12,
+    DISP1_12BY2,
+    DISP1_12BY4,
+    DISP1_12BY8
+  }
+sh_nibble_type;
+
+typedef enum
+  {
+    A_END,
+    A_BDISP12,
+    A_BDISP8,
+    A_DEC_M,
+    A_DEC_N,
+    A_DISP_GBR,
+    A_PC,
+    A_DISP_PC,
+    A_DISP_PC_ABS,
+    A_DISP_REG_M,
+    A_DISP_REG_N,
+    A_GBR,
+    A_IMM,
+    A_INC_M,
+    A_INC_N,
+    A_IND_M,
+    A_IND_N,
+    A_IND_R0_REG_M,
+    A_IND_R0_REG_N,
+    A_MACH,
+    A_MACL,
+    A_PR,
+    A_R0,
+    A_R0_GBR,
+    A_REG_M,
+    A_REG_N,
+    A_REG_B,
+    A_SR,
+    A_VBR,
+    A_TBR,
+    A_DISP_TBR,
+    A_DISP2_TBR,
+    A_DEC_R15,
+    A_INC_R15,
+    A_MOD,
+    A_RE,
+    A_RS,
+    A_DSR,
+    DSP_REG_M,
+    DSP_REG_N,
+    DSP_REG_X,
+    DSP_REG_Y,
+    DSP_REG_E,
+    DSP_REG_F,
+    DSP_REG_G,
+    DSP_REG_A_M,
+    DSP_REG_AX,
+    DSP_REG_XY,
+    DSP_REG_AY,
+    DSP_REG_YX,
+    AX_INC_N,
+    AY_INC_N,
+    AXY_INC_N,
+    AYX_INC_N,
+    AX_IND_N,
+    AY_IND_N,
+    AXY_IND_N,
+    AYX_IND_N,
+    AX_PMOD_N,
+    AXY_PMOD_N,
+    AY_PMOD_N,
+    AYX_PMOD_N,
+    AS_DEC_N,
+    AS_INC_N,
+    AS_IND_N,
+    AS_PMOD_N,
+    A_A0,
+    A_X0,
+    A_X1,
+    A_Y0,
+    A_Y1,
+    A_SSR,
+    A_SPC,
+    A_SGR,
+    A_DBR,
+    F_REG_N,
+    F_REG_M,
+    D_REG_N,
+    D_REG_M,
+    X_REG_N, /* Only used for argument parsing.  */
+    X_REG_M, /* Only used for argument parsing.  */
+    DX_REG_N,
+    DX_REG_M,
+    V_REG_N,
+    V_REG_M,
+    XMTRX_M4,
+    F_FR0,
+    FPUL_N,
+    FPUL_M,
+    FPSCR_N,
+    FPSCR_M
+  }
+sh_arg_type;
+
+typedef enum
+  {
+    A_A1_NUM =   5,
+    A_A0_NUM =   7,
+    A_X0_NUM, A_X1_NUM, A_Y0_NUM, A_Y1_NUM,
+    A_M0_NUM, A_A1G_NUM, A_M1_NUM, A_A0G_NUM
+  }
+sh_dsp_reg_nums;
+
+#define arch_sh1_base	0x0001
+#define arch_sh2_base	0x0002
+#define arch_sh3_base	0x0004
+#define arch_sh4_base	0x0008
+#define arch_sh4a_base	0x0010
+#define arch_sh2a_base  0x0020
+
+/* This is an annotation on instruction types, but we abuse the arch
+   field in instructions to denote it.  */
+#define arch_op32       0x00100000 /* This is a 32-bit opcode.  */
+
+#define arch_sh_no_mmu	0x04000000
+#define arch_sh_has_mmu 0x08000000
+#define arch_sh_no_co	0x10000000 /* neither FPU nor DSP co-processor */
+#define arch_sh_sp_fpu	0x20000000 /* single precision FPU */
+#define arch_sh_dp_fpu	0x40000000 /* double precision FPU */
+#define arch_sh_has_dsp	0x80000000
+
+
+#define arch_sh_base_mask 0x0000003f
+#define arch_opann_mask   0x00100000
+#define arch_sh_mmu_mask  0x0c000000
+#define arch_sh_co_mask   0xf0000000
+
+
+#define arch_sh1	(arch_sh1_base|arch_sh_no_mmu|arch_sh_no_co)
+#define arch_sh2	(arch_sh2_base|arch_sh_no_mmu|arch_sh_no_co)
+#define arch_sh2a	(arch_sh2a_base|arch_sh_no_mmu|arch_sh_dp_fpu)
+#define arch_sh2a_nofpu	(arch_sh2a_base|arch_sh_no_mmu|arch_sh_no_co)
+#define arch_sh2e	(arch_sh2_base|arch_sh2a_base|arch_sh_no_mmu|arch_sh_sp_fpu)
+#define arch_sh_dsp	(arch_sh2_base|arch_sh_no_mmu|arch_sh_has_dsp)
+#define arch_sh3_nommu	(arch_sh3_base|arch_sh_no_mmu|arch_sh_no_co)
+#define arch_sh3	(arch_sh3_base|arch_sh_has_mmu|arch_sh_no_co)
+#define arch_sh3e	(arch_sh3_base|arch_sh_has_mmu|arch_sh_sp_fpu)
+#define arch_sh3_dsp	(arch_sh3_base|arch_sh_has_mmu|arch_sh_has_dsp)
+#define arch_sh4	(arch_sh4_base|arch_sh_has_mmu|arch_sh_dp_fpu)
+#define arch_sh4a	(arch_sh4a_base|arch_sh_has_mmu|arch_sh_dp_fpu)
+#define arch_sh4al_dsp	(arch_sh4a_base|arch_sh_has_mmu|arch_sh_has_dsp)
+#define arch_sh4_nofpu	(arch_sh4_base|arch_sh_has_mmu|arch_sh_no_co)
+#define arch_sh4a_nofpu	(arch_sh4a_base|arch_sh_has_mmu|arch_sh_no_co)
+#define arch_sh4_nommu_nofpu (arch_sh4_base|arch_sh_no_mmu|arch_sh_no_co)
+
+#define SH_MERGE_ARCH_SET(SET1, SET2) ((SET1) & (SET2))
+#define SH_VALID_BASE_ARCH_SET(SET) (((SET) & arch_sh_base_mask) != 0)
+#define SH_VALID_MMU_ARCH_SET(SET)  (((SET) & arch_sh_mmu_mask) != 0)
+#define SH_VALID_CO_ARCH_SET(SET)   (((SET) & arch_sh_co_mask) != 0)
+#define SH_VALID_ARCH_SET(SET) \
+  (SH_VALID_BASE_ARCH_SET (SET) \
+   && SH_VALID_MMU_ARCH_SET (SET) \
+   && SH_VALID_CO_ARCH_SET (SET))
+#define SH_MERGE_ARCH_SET_VALID(SET1, SET2) \
+  SH_VALID_ARCH_SET (SH_MERGE_ARCH_SET (SET1, SET2))
+
+#define SH_ARCH_SET_HAS_FPU(SET) \
+  (((SET) & (arch_sh_sp_fpu | arch_sh_dp_fpu)) != 0)
+#define SH_ARCH_SET_HAS_DSP(SET) \
+  (((SET) & arch_sh_has_dsp) != 0)
+
+/* This is returned from the functions below when an error occurs
+   (in addition to a call to BFD_FAIL). The value should allow
+   the tools to continue to function in most cases - there may
+   be some confusion between DSP and FPU etc.  */
+#define SH_ARCH_UNKNOWN_ARCH 0xffffffff
+
+/* These are defined in bfd/cpu-sh.c .  */
+unsigned int sh_get_arch_from_bfd_mach (unsigned long mach);
+unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach);
+unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set);
+/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */
+
+/* Below are the 'architecture sets'.
+   They describe the following inheritance graph:
+
+                SH1
+                 |
+                SH2
+   .------------'|`--------------------.
+  /              |                      \
+SH-DSP          SH3-nommu               SH2E
+ |               |`--------.             |
+ |               |          \            |
+ |              SH3     SH4-nommu-nofpu  |
+ |               |           |           |
+ | .------------'|`----------+---------. |
+ |/                         /           \|
+ |               | .-------'             |
+ |               |/                      |
+SH3-dsp         SH4-nofpu               SH3E
+ |               |`--------------------. |
+ |               |                      \|
+ |              SH4A-nofpu              SH4
+ | .------------' `--------------------. |
+ |/                                     \|
+SH4AL-dsp                               SH4A
+
+*/
+
+/* Central branches */
+#define arch_sh1_up       (arch_sh1 | arch_sh2_up)
+#define arch_sh2_up       (arch_sh2 | arch_sh2e_up | arch_sh2a_nofpu_up | arch_sh3_nommu_up | arch_sh_dsp_up)
+#define arch_sh3_nommu_up (arch_sh3_nommu | arch_sh3_up | arch_sh4_nommu_nofpu_up)
+#define arch_sh3_up       (arch_sh3 | arch_sh3e_up | arch_sh3_dsp_up | arch_sh4_nofp_up)
+#define arch_sh4_nommu_nofpu_up (arch_sh4_nommu_nofpu | arch_sh4_nofp_up)
+#define arch_sh4_nofp_up  (arch_sh4_nofpu | arch_sh4_up | arch_sh4a_nofp_up)
+#define arch_sh4a_nofp_up (arch_sh4a_nofpu | arch_sh4a_up | arch_sh4al_dsp_up)
+
+/* Right branch */
+#define arch_sh2e_up (arch_sh2e | arch_sh2a_up | arch_sh3e_up)
+#define arch_sh3e_up (arch_sh3e | arch_sh4_up)
+#define arch_sh4_up  (arch_sh4 | arch_sh4a_up)
+#define arch_sh4a_up (arch_sh4a)
+
+/* Left branch */
+#define arch_sh_dsp_up    (arch_sh_dsp | arch_sh3_dsp_up)
+#define arch_sh3_dsp_up   (arch_sh3_dsp | arch_sh4al_dsp_up)
+#define arch_sh4al_dsp_up (arch_sh4al_dsp)
+
+/* SH 2a branched off SH2e, adding a lot but not all of SH4 and SH4a.  */
+#define arch_sh2a_up        (arch_sh2a)
+#define arch_sh2a_nofpu_up  (arch_sh2a_nofpu | arch_sh2a_up)
+
+
+typedef struct
+{
+  const char *name;
+  sh_arg_type arg[4];
+  sh_nibble_type nibbles[9];
+  unsigned int arch;
+} sh_opcode_info;
+
+#ifdef DEFINE_TABLE
+
+const sh_opcode_info sh_table[] =
+  {
+/* 0111nnnni8*1.... add #<imm>,<REG_N>  */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM0_8}, arch_sh1_up},
+
+/* 0011nnnnmmmm1100 add <REG_M>,<REG_N> */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}, arch_sh1_up},
+
+/* 0011nnnnmmmm1110 addc <REG_M>,<REG_N>*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}, arch_sh1_up},
+
+/* 0011nnnnmmmm1111 addv <REG_M>,<REG_N>*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}, arch_sh1_up},
+
+/* 11001001i8*1.... and #<imm>,R0       */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM0_8}, arch_sh1_up},
+
+/* 0010nnnnmmmm1001 and <REG_M>,<REG_N> */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}, arch_sh1_up},
+
+/* 11001101i8*1.... and.b #<imm>,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM0_8}, arch_sh1_up},
+
+/* 1010i12......... bra <bdisp12>       */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}, arch_sh1_up},
+
+/* 1011i12......... bsr <bdisp12>       */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}, arch_sh1_up},
+
+/* 10001001i8p1.... bt <bdisp8>         */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}, arch_sh1_up},
+
+/* 10001011i8p1.... bf <bdisp8>         */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}, arch_sh1_up},
+
+/* 10001101i8p1.... bt.s <bdisp8>       */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up},
+
+/* 10001101i8p1.... bt/s <bdisp8>       */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up},
+
+/* 10001111i8p1.... bf.s <bdisp8>       */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up},
+
+/* 10001111i8p1.... bf/s <bdisp8>       */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up},
+
+/* 0000000010001000 clrdmxy             */{"clrdmxy",{0},{HEX_0,HEX_0,HEX_8,HEX_8}, arch_sh4al_dsp_up},
+
+/* 0000000000101000 clrmac              */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}, arch_sh1_up},
+
+/* 0000000001001000 clrs                */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}, arch_sh1_up},
+
+/* 0000000000001000 clrt                */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}, arch_sh1_up},
+
+/* 10001000i8*1.... cmp/eq #<imm>,R0    */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM0_8}, arch_sh1_up},
+
+/* 0011nnnnmmmm0000 cmp/eq <REG_M>,<REG_N>*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}, arch_sh1_up},
+
+/* 0011nnnnmmmm0011 cmp/ge <REG_M>,<REG_N>*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}, arch_sh1_up},
+
+/* 0011nnnnmmmm0111 cmp/gt <REG_M>,<REG_N>*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}, arch_sh1_up},
+
+/* 0011nnnnmmmm0110 cmp/hi <REG_M>,<REG_N>*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}, arch_sh1_up},
+
+/* 0011nnnnmmmm0010 cmp/hs <REG_M>,<REG_N>*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}, arch_sh1_up},
+
+/* 0100nnnn00010101 cmp/pl <REG_N>      */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}, arch_sh1_up},
+
+/* 0100nnnn00010001 cmp/pz <REG_N>      */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}, arch_sh1_up},
+
+/* 0010nnnnmmmm1100 cmp/str <REG_M>,<REG_N>*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}, arch_sh1_up},
+
+/* 0010nnnnmmmm0111 div0s <REG_M>,<REG_N>*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}, arch_sh1_up},
+
+/* 0000000000011001 div0u               */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}, arch_sh1_up},
+
+/* 0011nnnnmmmm0100 div1 <REG_M>,<REG_N>*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}, arch_sh1_up},
+
+/* 0110nnnnmmmm1110 exts.b <REG_M>,<REG_N>*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}, arch_sh1_up},
+
+/* 0110nnnnmmmm1111 exts.w <REG_M>,<REG_N>*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}, arch_sh1_up},
+
+/* 0110nnnnmmmm1100 extu.b <REG_M>,<REG_N>*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}, arch_sh1_up},
+
+/* 0110nnnnmmmm1101 extu.w <REG_M>,<REG_N>*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}, arch_sh1_up},
+
+/* 0000nnnn11100011 icbi @<REG_N>       */{"icbi",{A_IND_N},{HEX_0,REG_N,HEX_E,HEX_3}, arch_sh4a_nofp_up},
+
+/* 0100nnnn00101011 jmp @<REG_N>        */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}, arch_sh1_up},
+
+/* 0100nnnn00001011 jsr @<REG_N>        */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}, arch_sh1_up},
+
+/* 0100nnnn00001110 ldc <REG_N>,SR      */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}, arch_sh1_up},
+
+/* 0100nnnn00011110 ldc <REG_N>,GBR     */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}, arch_sh1_up},
+
+/* 0100nnnn00111010 ldc <REG_N>,SGR     */{"ldc",{A_REG_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up},
+
+/* 0100mmmm01001010 ldc <REG_M>,TBR     */{"ldc",{A_REG_M,A_TBR},{HEX_4,REG_M,HEX_4,HEX_A}, arch_sh2a_nofpu_up},
+
+/* 0100nnnn00101110 ldc <REG_N>,VBR     */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}, arch_sh1_up},
+
+/* 0100nnnn01011110 ldc <REG_N>,MOD     */{"ldc",{A_REG_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_E}, arch_sh_dsp_up},
+
+/* 0100nnnn01111110 ldc <REG_N>,RE     */{"ldc",{A_REG_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_E}, arch_sh_dsp_up},
+
+/* 0100nnnn01101110 ldc <REG_N>,RS     */{"ldc",{A_REG_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_E}, arch_sh_dsp_up},
+
+/* 0100nnnn00111110 ldc <REG_N>,SSR     */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}, arch_sh3_nommu_up},
+
+/* 0100nnnn01001110 ldc <REG_N>,SPC     */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}, arch_sh3_nommu_up},
+
+/* 0100nnnn11111010 ldc <REG_N>,DBR     */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up},
+
+/* 0100nnnn1xxx1110 ldc <REG_N>,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}, arch_sh3_nommu_up},
+
+/* 0100nnnn00000111 ldc.l @<REG_N>+,SR  */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}, arch_sh1_up},
+
+/* 0100nnnn00010111 ldc.l @<REG_N>+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}, arch_sh1_up},
+
+/* 0100nnnn00100111 ldc.l @<REG_N>+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}, arch_sh1_up},
+
+/* 0100nnnn00110110 ldc.l @<REG_N>+,SGR */{"ldc.l",{A_INC_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_6}, arch_sh4_nommu_nofpu_up},
+
+/* 0100nnnn01010111 ldc.l @<REG_N>+,MOD */{"ldc.l",{A_INC_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_7}, arch_sh_dsp_up},
+
+/* 0100nnnn01110111 ldc.l @<REG_N>+,RE */{"ldc.l",{A_INC_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_7}, arch_sh_dsp_up},
+
+/* 0100nnnn01100111 ldc.l @<REG_N>+,RS */{"ldc.l",{A_INC_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_7}, arch_sh_dsp_up},
+
+/* 0100nnnn00110111 ldc.l @<REG_N>+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}, arch_sh3_nommu_up},
+
+/* 0100nnnn01000111 ldc.l @<REG_N>+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}, arch_sh3_nommu_up},
+
+/* 0100nnnn11110110 ldc.l @<REG_N>+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_6}, arch_sh4_nommu_nofpu_up},
+
+/* 0100nnnn1xxx0111 ldc.l <REG_N>,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}, arch_sh3_nommu_up},
+
+/* 0100mmmm00110100 ldrc <REG_M>        */{"ldrc",{A_REG_M},{HEX_4,REG_M,HEX_3,HEX_4}, arch_sh4al_dsp_up},
+/* 10001010i8*1.... ldrc #<imm>         */{"ldrc",{A_IMM},{HEX_8,HEX_A,IMM0_8}, arch_sh4al_dsp_up},
+
+/* 10001110i8p2.... ldre @(<disp>,PC)	*/{"ldre",{A_DISP_PC},{HEX_8,HEX_E,PCRELIMM_8BY2}, arch_sh_dsp_up},
+
+/* 10001100i8p2.... ldrs @(<disp>,PC)	*/{"ldrs",{A_DISP_PC},{HEX_8,HEX_C,PCRELIMM_8BY2}, arch_sh_dsp_up},
+
+/* 0100nnnn00001010 lds <REG_N>,MACH    */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}, arch_sh1_up},
+
+/* 0100nnnn00011010 lds <REG_N>,MACL    */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}, arch_sh1_up},
+
+/* 0100nnnn00101010 lds <REG_N>,PR      */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}, arch_sh1_up},
+
+/* 0100nnnn01101010 lds <REG_N>,DSR	*/{"lds",{A_REG_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn01111010 lds <REG_N>,A0	*/{"lds",{A_REG_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn10001010 lds <REG_N>,X0	*/{"lds",{A_REG_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn10011010 lds <REG_N>,X1	*/{"lds",{A_REG_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn10101010 lds <REG_N>,Y0	*/{"lds",{A_REG_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn10111010 lds <REG_N>,Y1	*/{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
+
+/* 0100nnnn01011010 lds <REG_N>,FPUL    */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up},
+
+/* 0100nnnn01101010 lds <REG_M>,FPSCR   */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up},
+
+/* 0100nnnn00000110 lds.l @<REG_N>+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up},
+
+/* 0100nnnn00010110 lds.l @<REG_N>+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}, arch_sh1_up},
+
+/* 0100nnnn00100110 lds.l @<REG_N>+,PR  */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}, arch_sh1_up},
+
+/* 0100nnnn01100110 lds.l @<REG_N>+,DSR	*/{"lds.l",{A_INC_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn01110110 lds.l @<REG_N>+,A0	*/{"lds.l",{A_INC_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn10000110 lds.l @<REG_N>+,X0	*/{"lds.l",{A_INC_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn10010110 lds.l @<REG_N>+,X1	*/{"lds.l",{A_INC_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn10100110 lds.l @<REG_N>+,Y0	*/{"lds.l",{A_INC_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn10110110 lds.l @<REG_N>+,Y1	*/{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up},
+
+/* 0100nnnn01010110 lds.l @<REG_M>+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up},
+
+/* 0100nnnn01100110 lds.l @<REG_M>+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up},
+
+/* 0000000000111000 ldtlb               */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up},
+
+/* 0100nnnnmmmm1111 mac.w @<REG_M>+,@<REG_N>+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}, arch_sh1_up},
+
+/* 1110nnnni8*1.... mov #<imm>,<REG_N>  */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM0_8}, arch_sh1_up},
+
+/* 0110nnnnmmmm0011 mov <REG_M>,<REG_N> */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}, arch_sh1_up},
+
+/* 0000nnnnmmmm0100 mov.b <REG_M>,@(R0,<REG_N>)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}, arch_sh1_up},
+
+/* 0010nnnnmmmm0100 mov.b <REG_M>, at -<REG_N>*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}, arch_sh1_up},
+
+/* 0010nnnnmmmm0000 mov.b <REG_M>,@<REG_N>*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}, arch_sh1_up},
+
+/* 10000100mmmmi4*1 mov.b @(<disp>,<REG_M>),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM0_4}, arch_sh1_up},
+
+/* 11000100i8*1.... mov.b @(<disp>,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM0_8}, arch_sh1_up},
+
+/* 0000nnnnmmmm1100 mov.b @(R0,<REG_M>),<REG_N>*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}, arch_sh1_up},
+
+/* 0110nnnnmmmm0100 mov.b @<REG_M>+,<REG_N>*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}, arch_sh1_up},
+
+/* 0110nnnnmmmm0000 mov.b @<REG_M>,<REG_N>*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}, arch_sh1_up},
+
+/* 10000000mmmmi4*1 mov.b R0,@(<disp>,<REG_M>)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM1_4}, arch_sh1_up},
+
+/* 11000000i8*1.... mov.b R0,@(<disp>,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM1_8}, arch_sh1_up},
+
+/* 0100nnnn10001011 mov.b R0,@<REG_N>+ */{"mov.b",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_8,HEX_B}, arch_sh2a_nofpu_up},
+/* 0100nnnn11001011 mov.b @-<REG_M>,R0 */{"mov.b",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_C,HEX_B}, arch_sh2a_nofpu_up},
+/* 0011nnnnmmmm0001 0000dddddddddddd mov.b <REG_M>,@(<DISP12>,<REG_N>) */
+{"mov.b",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnnmmmm0001 0100dddddddddddd mov.b @(<DISP12>,<REG_M>),<REG_N> */
+{"mov.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_4,DISP0_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0001nnnnmmmmi4*4 mov.l <REG_M>,@(<disp>,<REG_N>)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM1_4BY4}, arch_sh1_up},
+
+/* 0000nnnnmmmm0110 mov.l <REG_M>,@(R0,<REG_N>)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}, arch_sh1_up},
+
+/* 0010nnnnmmmm0110 mov.l <REG_M>, at -<REG_N>*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}, arch_sh1_up},
+
+/* 0010nnnnmmmm0010 mov.l <REG_M>,@<REG_N>*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}, arch_sh1_up},
+
+/* 0101nnnnmmmmi4*4 mov.l @(<disp>,<REG_M>),<REG_N>*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM0_4BY4}, arch_sh1_up},
+
+/* 11000110i8*4.... mov.l @(<disp>,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM0_8BY4}, arch_sh1_up},
+
+/* 1101nnnni8p4.... mov.l @(<disp>,PC),<REG_N>*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}, arch_sh1_up},
+
+/* 0000nnnnmmmm1110 mov.l @(R0,<REG_M>),<REG_N>*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}, arch_sh1_up},
+
+/* 0110nnnnmmmm0110 mov.l @<REG_M>+,<REG_N>*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}, arch_sh1_up},
+
+/* 0110nnnnmmmm0010 mov.l @<REG_M>,<REG_N>*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}, arch_sh1_up},
+
+/* 11000010i8*4.... mov.l R0,@(<disp>,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM1_8BY4}, arch_sh1_up},
+
+/* 0100nnnn10101011 mov.l R0,@<REG_N>+ */{"mov.l",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_A,HEX_B}, arch_sh2a_nofpu_up},
+/* 0100nnnn11001011 mov.l @-<REG_M>,R0 */{"mov.l",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_B}, arch_sh2a_nofpu_up},
+/* 0011nnnnmmmm0001 0010dddddddddddd mov.l <REG_M>,@(<DISP12>,<REG_N>) */
+{"mov.l",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_2,DISP1_12BY4}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnnmmmm0001 0110dddddddddddd mov.l @(<DISP12>,<REG_M>),<REG_N> */
+{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_6,DISP0_12BY4}, arch_sh2a_nofpu_up | arch_op32},
+/* 0000nnnnmmmm0101 mov.w <REG_M>,@(R0,<REG_N>)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}, arch_sh1_up},
+
+/* 0010nnnnmmmm0101 mov.w <REG_M>, at -<REG_N>*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}, arch_sh1_up},
+
+/* 0010nnnnmmmm0001 mov.w <REG_M>,@<REG_N>*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}, arch_sh1_up},
+
+/* 10000101mmmmi4*2 mov.w @(<disp>,<REG_M>),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM0_4BY2}, arch_sh1_up},
+
+/* 11000101i8*2.... mov.w @(<disp>,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM0_8BY2}, arch_sh1_up},
+
+/* 1001nnnni8p2.... mov.w @(<disp>,PC),<REG_N>*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}, arch_sh1_up},
+
+/* 0000nnnnmmmm1101 mov.w @(R0,<REG_M>),<REG_N>*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}, arch_sh1_up},
+
+/* 0110nnnnmmmm0101 mov.w @<REG_M>+,<REG_N>*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}, arch_sh1_up},
+
+/* 0110nnnnmmmm0001 mov.w @<REG_M>,<REG_N>*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}, arch_sh1_up},
+
+/* 10000001mmmmi4*2 mov.w R0,@(<disp>,<REG_M>)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM1_4BY2}, arch_sh1_up},
+
+/* 11000001i8*2.... mov.w R0,@(<disp>,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM1_8BY2}, arch_sh1_up},
+
+/* 0100nnnn10011011 mov.w R0,@<REG_N>+ */{"mov.w",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_9,HEX_B}, arch_sh2a_nofpu_up},
+/* 0100nnnn11011011 mov.w @-<REG_M>,R0 */{"mov.w",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_D,HEX_B}, arch_sh2a_nofpu_up},
+/* 0011nnnnmmmm0001 0001dddddddddddd mov.w <REG_M>,@(<DISP12>,<REG_N>) */
+{"mov.w",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_1,DISP1_12BY2}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnnmmmm0001 0101dddddddddddd mov.w @(<DISP12>,<REG_M>),<REG_N> */
+{"mov.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_5,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32},
+/* 11000111i8p4.... mova @(<disp>,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}, arch_sh1_up},
+/* 0000nnnn11000011 movca.l R0,@<REG_N> */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}, arch_sh4_nommu_nofpu_up},
+
+/* 0000nnnn01110011 movco.l r0,@<REG_N> */{"movco.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_7,HEX_3}, arch_sh4a_nofp_up},
+/* 0000mmmm01100011 movli.l @<REG_M>,r0 */{"movli.l",{A_IND_M,A_R0},{HEX_0,REG_M,HEX_6,HEX_3}, arch_sh4a_nofp_up},
+
+/* 0000nnnn00101001 movt <REG_N>        */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}, arch_sh1_up},
+
+/* 0100mmmm10101001 movua.l @<REG_M>,r0 */{"movua.l",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_A,HEX_9}, arch_sh4a_nofp_up},
+/* 0100mmmm11101001 movua.l @<REG_M>+,r0 */{"movua.l",{A_INC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_9}, arch_sh4a_nofp_up},
+
+/* 0010nnnnmmmm1111 muls.w <REG_M>,<REG_N>*/{"muls.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up},
+/* 0010nnnnmmmm1111 muls <REG_M>,<REG_N>*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up},
+
+/* 0000nnnnmmmm0111 mul.l <REG_M>,<REG_N>*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh2_up},
+
+/* 0010nnnnmmmm1110 mulu.w <REG_M>,<REG_N>*/{"mulu.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up},
+/* 0010nnnnmmmm1110 mulu <REG_M>,<REG_N>*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up},
+
+/* 0110nnnnmmmm1011 neg <REG_M>,<REG_N> */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}, arch_sh1_up},
+
+/* 0110nnnnmmmm1010 negc <REG_M>,<REG_N>*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}, arch_sh1_up},
+
+/* 0000000000001001 nop                 */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}, arch_sh1_up},
+
+/* 0110nnnnmmmm0111 not <REG_M>,<REG_N> */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}, arch_sh1_up},
+/* 0000nnnn10010011 ocbi @<REG_N>       */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}, arch_sh4_nommu_nofpu_up},
+
+/* 0000nnnn10100011 ocbp @<REG_N>       */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}, arch_sh4_nommu_nofpu_up},
+
+/* 0000nnnn10110011 ocbwb @<REG_N>      */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}, arch_sh4_nommu_nofpu_up},
+
+
+/* 11001011i8*1.... or #<imm>,R0        */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM0_8}, arch_sh1_up},
+
+/* 0010nnnnmmmm1011 or <REG_M>,<REG_N>  */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}, arch_sh1_up},
+
+/* 11001111i8*1.... or.b #<imm>,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM0_8}, arch_sh1_up},
+
+/* 0000nnnn10000011 pref @<REG_N>       */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}, arch_sh4_nommu_nofpu_up | arch_sh2a_nofpu_up},
+
+/* 0000nnnn11010011 prefi @<REG_N>      */{"prefi",{A_IND_N},{HEX_0,REG_N,HEX_D,HEX_3}, arch_sh4a_nofp_up},
+
+/* 0100nnnn00100100 rotcl <REG_N>       */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}, arch_sh1_up},
+
+/* 0100nnnn00100101 rotcr <REG_N>       */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}, arch_sh1_up},
+
+/* 0100nnnn00000100 rotl <REG_N>        */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}, arch_sh1_up},
+
+/* 0100nnnn00000101 rotr <REG_N>        */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}, arch_sh1_up},
+
+/* 0000000000101011 rte                 */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}, arch_sh1_up},
+
+/* 0000000000001011 rts                 */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}, arch_sh1_up},
+
+/* 0000000010011000 setdmx              */{"setdmx",{0},{HEX_0,HEX_0,HEX_9,HEX_8}, arch_sh4al_dsp_up},
+/* 0000000011001000 setdmy              */{"setdmy",{0},{HEX_0,HEX_0,HEX_C,HEX_8}, arch_sh4al_dsp_up},
+
+/* 0000000001011000 sets                */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}, arch_sh1_up},
+/* 0000000000011000 sett                */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}, arch_sh1_up},
+
+/* 0100nnnn00010100 setrc <REG_N>       */{"setrc",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up},
+
+/* 10000010i8*1.... setrc #<imm>        */{"setrc",{A_IMM},{HEX_8,HEX_2,IMM0_8}, arch_sh_dsp_up},
+
+/* repeat start end <REG_N>       	*/{"repeat",{A_DISP_PC,A_DISP_PC,A_REG_N},{REPEAT,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up},
+
+/* repeat start end #<imm>        	*/{"repeat",{A_DISP_PC,A_DISP_PC,A_IMM},{REPEAT,HEX_2,IMM0_8,HEX_8}, arch_sh_dsp_up},
+
+/* 0100nnnnmmmm1100 shad <REG_M>,<REG_N>*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}, arch_sh3_nommu_up | arch_sh2a_nofpu_up},
+
+/* 0100nnnnmmmm1101 shld <REG_M>,<REG_N>*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}, arch_sh3_nommu_up | arch_sh2a_nofpu_up},
+
+/* 0100nnnn00100000 shal <REG_N>        */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}, arch_sh1_up},
+
+/* 0100nnnn00100001 shar <REG_N>        */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}, arch_sh1_up},
+
+/* 0100nnnn00000000 shll <REG_N>        */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}, arch_sh1_up},
+
+/* 0100nnnn00101000 shll16 <REG_N>      */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}, arch_sh1_up},
+
+/* 0100nnnn00001000 shll2 <REG_N>       */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}, arch_sh1_up},
+
+/* 0100nnnn00011000 shll8 <REG_N>       */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}, arch_sh1_up},
+
+/* 0100nnnn00000001 shlr <REG_N>        */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}, arch_sh1_up},
+
+/* 0100nnnn00101001 shlr16 <REG_N>      */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}, arch_sh1_up},
+
+/* 0100nnnn00001001 shlr2 <REG_N>       */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}, arch_sh1_up},
+
+/* 0100nnnn00011001 shlr8 <REG_N>       */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}, arch_sh1_up},
+
+/* 0000000000011011 sleep               */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}, arch_sh1_up},
+
+/* 0000nnnn00000010 stc SR,<REG_N>      */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}, arch_sh1_up},
+
+/* 0000nnnn00010010 stc GBR,<REG_N>     */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}, arch_sh1_up},
+
+/* 0000nnnn00100010 stc VBR,<REG_N>     */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}, arch_sh1_up},
+
+/* 0000nnnn01010010 stc MOD,<REG_N>     */{"stc",{A_MOD,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_2}, arch_sh_dsp_up},
+
+/* 0000nnnn01110010 stc RE,<REG_N>     */{"stc",{A_RE,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up},
+
+/* 0000nnnn01100010 stc RS,<REG_N>     */{"stc",{A_RS,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up},
+
+/* 0000nnnn00110010 stc SSR,<REG_N>     */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}, arch_sh3_nommu_up},
+
+/* 0000nnnn01000010 stc SPC,<REG_N>     */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}, arch_sh3_nommu_up},
+
+/* 0000nnnn00111010 stc SGR,<REG_N>     */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up},
+
+/* 0000nnnn11111010 stc DBR,<REG_N>     */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up},
+
+/* 0000nnnn1xxx0010 stc Rn_BANK,<REG_N> */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}, arch_sh3_nommu_up},
+
+/* 0000nnnn01001010 stc TBR,<REG_N> */ {"stc",{A_TBR,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_A}, arch_sh2a_nofpu_up},
+
+/* 0100nnnn00000011 stc.l SR, at -<REG_N>  */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}, arch_sh1_up},
+
+/* 0100nnnn00100011 stc.l VBR, at -<REG_N> */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}, arch_sh1_up},
+
+/* 0100nnnn01010011 stc.l MOD, at -<REG_N> */{"stc.l",{A_MOD,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_3}, arch_sh_dsp_up},
+
+/* 0100nnnn01110011 stc.l RE, at -<REG_N>  */{"stc.l",{A_RE,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}, arch_sh_dsp_up},
+
+/* 0100nnnn01100011 stc.l RS, at -<REG_N>  */{"stc.l",{A_RS,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}, arch_sh_dsp_up},
+
+/* 0100nnnn00110011 stc.l SSR, at -<REG_N> */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}, arch_sh3_nommu_up},
+
+/* 0100nnnn01000011 stc.l SPC, at -<REG_N> */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}, arch_sh3_nommu_up},
+
+/* 0100nnnn00010011 stc.l GBR, at -<REG_N> */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}, arch_sh1_up},
+
+/* 0100nnnn00110010 stc.l SGR, at -<REG_N> */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_2}, arch_sh4_nommu_nofpu_up},
+
+/* 0100nnnn11110010 stc.l DBR, at -<REG_N> */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_F,HEX_2}, arch_sh4_nommu_nofpu_up},
+
+/* 0100nnnn1xxx0011 stc.l Rn_BANK, at -<REG_N> */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}, arch_sh3_nommu_up},
+
+/* 0000nnnn00001010 sts MACH,<REG_N>    */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}, arch_sh1_up},
+
+/* 0000nnnn00011010 sts MACL,<REG_N>    */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}, arch_sh1_up},
+
+/* 0000nnnn00101010 sts PR,<REG_N>      */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}, arch_sh1_up},
+
+/* 0000nnnn01101010 sts DSR,<REG_N>	*/{"sts",{A_DSR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn01111010 sts A0,<REG_N>	*/{"sts",{A_A0,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn10001010 sts X0,<REG_N>	*/{"sts",{A_X0,A_REG_N},{HEX_0,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn10011010 sts X1,<REG_N>	*/{"sts",{A_X1,A_REG_N},{HEX_0,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn10101010 sts Y0,<REG_N>	*/{"sts",{A_Y0,A_REG_N},{HEX_0,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn10111010 sts Y1,<REG_N>	*/{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
+
+/* 0000nnnn01011010 sts FPUL,<REG_N>    */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up},
+
+/* 0000nnnn01101010 sts FPSCR,<REG_N>   */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up},
+
+/* 0100nnnn00000010 sts.l MACH, at -<REG_N>*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up},
+
+/* 0100nnnn00010010 sts.l MACL, at -<REG_N>*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}, arch_sh1_up},
+
+/* 0100nnnn00100010 sts.l PR, at -<REG_N>  */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}, arch_sh1_up},
+
+/* 0100nnnn01100110 sts.l DSR, at -<REG_N>	*/{"sts.l",{A_DSR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn01110110 sts.l A0, at -<REG_N>	*/{"sts.l",{A_A0,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn10000110 sts.l X0, at -<REG_N>	*/{"sts.l",{A_X0,A_DEC_N},{HEX_4,REG_N,HEX_8,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn10010110 sts.l X1, at -<REG_N>	*/{"sts.l",{A_X1,A_DEC_N},{HEX_4,REG_N,HEX_9,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn10100110 sts.l Y0, at -<REG_N>	*/{"sts.l",{A_Y0,A_DEC_N},{HEX_4,REG_N,HEX_A,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn10110110 sts.l Y1, at -<REG_N>	*/{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up},
+
+/* 0100nnnn01010010 sts.l FPUL, at -<REG_N>*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up},
+
+/* 0100nnnn01100010 sts.l FPSCR, at -<REG_N>*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up},
+
+/* 0011nnnnmmmm1000 sub <REG_M>,<REG_N> */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up},
+
+/* 0011nnnnmmmm1010 subc <REG_M>,<REG_N>*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}, arch_sh1_up},
+
+/* 0011nnnnmmmm1011 subv <REG_M>,<REG_N>*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}, arch_sh1_up},
+
+/* 0110nnnnmmmm1000 swap.b <REG_M>,<REG_N>*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}, arch_sh1_up},
+
+/* 0110nnnnmmmm1001 swap.w <REG_M>,<REG_N>*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}, arch_sh1_up},
+
+/* 0000000010101011 synco               */{"synco",{0},{HEX_0,HEX_0,HEX_A,HEX_B}, arch_sh4a_nofp_up},
+
+/* 0100nnnn00011011 tas.b @<REG_N>      */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}, arch_sh1_up},
+
+/* 11000011i8*1.... trapa #<imm>        */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM0_8}, arch_sh1_up},
+
+/* 11001000i8*1.... tst #<imm>,R0       */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM0_8}, arch_sh1_up},
+
+/* 0010nnnnmmmm1000 tst <REG_M>,<REG_N> */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}, arch_sh1_up},
+
+/* 11001100i8*1.... tst.b #<imm>,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM0_8}, arch_sh1_up},
+
+/* 11001010i8*1.... xor #<imm>,R0       */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM0_8}, arch_sh1_up},
+
+/* 0010nnnnmmmm1010 xor <REG_M>,<REG_N> */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}, arch_sh1_up},
+
+/* 11001110i8*1.... xor.b #<imm>,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM0_8}, arch_sh1_up},
+
+/* 0010nnnnmmmm1101 xtrct <REG_M>,<REG_N>*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}, arch_sh1_up},
+
+/* 0000nnnnmmmm0111 mul.l <REG_M>,<REG_N>*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh1_up},
+
+/* 0100nnnn00010000 dt <REG_N>          */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}, arch_sh2_up},
+
+/* 0011nnnnmmmm1101 dmuls.l <REG_M>,<REG_N>*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}, arch_sh2_up},
+
+/* 0011nnnnmmmm0101 dmulu.l <REG_M>,<REG_N>*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}, arch_sh2_up},
+
+/* 0000nnnnmmmm1111 mac.l @<REG_M>+,@<REG_N>+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}, arch_sh2_up},
+
+/* 0000nnnn00100011 braf <REG_N>       */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}, arch_sh2_up},
+
+/* 0000nnnn00000011 bsrf <REG_N>       */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}, arch_sh2_up},
+
+/* 111101nnmmmm0000 movs.w @-<REG_N>,<DSP_REG_M> */   {"movs.w",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_0}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0001 movs.w @<REG_N>,<DSP_REG_M> */    {"movs.w",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_4}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0010 movs.w @<REG_N>+,<DSP_REG_M> */   {"movs.w",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_8}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0011 movs.w @<REG_N>+r8,<DSP_REG_M> */ {"movs.w",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_C}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0100 movs.w <DSP_REG_M>, at -<REG_N> */   {"movs.w",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_1}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0101 movs.w <DSP_REG_M>,@<REG_N> */    {"movs.w",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_5}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0110 movs.w <DSP_REG_M>,@<REG_N>+ */   {"movs.w",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_9}, arch_sh_dsp_up},
+
+/* 111101nnmmmm0111 movs.w <DSP_REG_M>,@<REG_N>+r8 */ {"movs.w",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_D}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1000 movs.l @-<REG_N>,<DSP_REG_M> */   {"movs.l",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_2}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1001 movs.l @<REG_N>,<DSP_REG_M> */    {"movs.l",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_6}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1010 movs.l @<REG_N>+,<DSP_REG_M> */   {"movs.l",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_A}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1011 movs.l @<REG_N>+r8,<DSP_REG_M> */ {"movs.l",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_E}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1100 movs.l <DSP_REG_M>, at -<REG_N> */   {"movs.l",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_3}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1101 movs.l <DSP_REG_M>,@<REG_N> */    {"movs.l",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_7}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1110 movs.l <DSP_REG_M>,@<REG_N>+ */   {"movs.l",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_B}, arch_sh_dsp_up},
+
+/* 111101nnmmmm1111 movs.l <DSP_REG_M>,@<REG_N>+r8 */ {"movs.l",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_F}, arch_sh_dsp_up},
+
+/* 0*0*0*00** nopx */ {"nopx",{0},{PPI,NOPX}, arch_sh_dsp_up},
+/* *0*0*0**00 nopy */ {"nopy",{0},{PPI,NOPY}, arch_sh_dsp_up},
+/* n*m*0*01** movx.w @<REG_N>,<DSP_REG_X> */    {"movx.w",{AX_IND_N,DSP_REG_X},{PPI,MOVX,HEX_1}, arch_sh_dsp_up},
+/* n*m*0*10** movx.w @<REG_N>+,<DSP_REG_X> */   {"movx.w",{AX_INC_N,DSP_REG_X},{PPI,MOVX,HEX_2}, arch_sh_dsp_up},
+/* n*m*0*11** movx.w @<REG_N>+r8,<DSP_REG_X> */ {"movx.w",{AX_PMOD_N,DSP_REG_X},{PPI,MOVX,HEX_3}, arch_sh_dsp_up},
+/* n*m*1*01** movx.w <DSP_REG_M>,@<REG_N> */    {"movx.w",{DSP_REG_A_M,AX_IND_N},{PPI,MOVX,HEX_9}, arch_sh_dsp_up},
+/* n*m*1*10** movx.w <DSP_REG_M>,@<REG_N>+ */   {"movx.w",{DSP_REG_A_M,AX_INC_N},{PPI,MOVX,HEX_A}, arch_sh_dsp_up},
+/* n*m*1*11** movx.w <DSP_REG_M>,@<REG_N>+r8 */ {"movx.w",{DSP_REG_A_M,AX_PMOD_N},{PPI,MOVX,HEX_B}, arch_sh_dsp_up},
+
+/* nnmm000100 movx.w @<REG_Axy>,<DSP_REG_XY> */ {"movx.w",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_4}, arch_sh4al_dsp_up},
+/* nnmm001000 movx.w @<REG_Axy>+,<DSP_REG_XY> */{"movx.w",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_8}, arch_sh4al_dsp_up},
+/* nnmm001100 movx.w @<REG_Axy>+r8,<DSP_REG_XY> */{"movx.w",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_C}, arch_sh4al_dsp_up},
+/* nnmm100100 movx.w <DSP_REG_AX>,@<REG_Axy> */ {"movx.w",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_2,HEX_4}, arch_sh4al_dsp_up},
+/* nnmm101000 movx.w <DSP_REG_AX>,@<REG_Axy>+ */{"movx.w",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_2,HEX_8}, arch_sh4al_dsp_up},
+/* nnmm101100 movx.w <DSP_REG_AX>,@<REG_Axy>+r8 */{"movx.w",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_2,HEX_C}, arch_sh4al_dsp_up},
+
+/* nnmm010100 movx.l @<REG_Axy>,<DSP_REG_XY> */ {"movx.l",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_4}, arch_sh4al_dsp_up},
+/* nnmm011000 movx.l @<REG_Axy>+,<DSP_REG_XY> */{"movx.l",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_8}, arch_sh4al_dsp_up},
+/* nnmm011100 movx.l @<REG_Axy>+r8,<DSP_REG_XY> */{"movx.l",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_C}, arch_sh4al_dsp_up},
+/* nnmm110100 movx.l <DSP_REG_AX>,@<REG_Axy> */ {"movx.l",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_3,HEX_4}, arch_sh4al_dsp_up},
+/* nnmm111000 movx.l <DSP_REG_AX>,@<REG_Axy>+ */{"movx.l",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_3,HEX_8}, arch_sh4al_dsp_up},
+/* nnmm111100 movx.l <DSP_REG_AX>,@<REG_Axy>+r8 */{"movx.l",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_3,HEX_C}, arch_sh4al_dsp_up},
+
+/* *n*m*0**01 movy.w @<REG_N>,<DSP_REG_Y> */    {"movy.w",{AY_IND_N,DSP_REG_Y},{PPI,MOVY,HEX_1}, arch_sh_dsp_up},
+/* *n*m*0**10 movy.w @<REG_N>+,<DSP_REG_Y> */   {"movy.w",{AY_INC_N,DSP_REG_Y},{PPI,MOVY,HEX_2}, arch_sh_dsp_up},
+/* *n*m*0**11 movy.w @<REG_N>+r9,<DSP_REG_Y> */ {"movy.w",{AY_PMOD_N,DSP_REG_Y},{PPI,MOVY,HEX_3}, arch_sh_dsp_up},
+/* *n*m*1**01 movy.w <DSP_REG_M>,@<REG_N> */    {"movy.w",{DSP_REG_A_M,AY_IND_N},{PPI,MOVY,HEX_9}, arch_sh_dsp_up},
+/* *n*m*1**10 movy.w <DSP_REG_M>,@<REG_N>+ */   {"movy.w",{DSP_REG_A_M,AY_INC_N},{PPI,MOVY,HEX_A}, arch_sh_dsp_up},
+/* *n*m*1**11 movy.w <DSP_REG_M>,@<REG_N>+r9 */ {"movy.w",{DSP_REG_A_M,AY_PMOD_N},{PPI,MOVY,HEX_B}, arch_sh_dsp_up},
+
+/* nnmm000001 movy.w @<REG_Ayx>,<DSP_REG_YX> */ {"movy.w",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_1}, arch_sh4al_dsp_up},
+/* nnmm000010 movy.w @<REG_Ayx>+,<DSP_REG_YX> */{"movy.w",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_2}, arch_sh4al_dsp_up},
+/* nnmm000011 movy.w @<REG_Ayx>+r8,<DSP_REG_YX> */{"movy.w",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_3}, arch_sh4al_dsp_up},
+/* nnmm010001 movy.w <DSP_REG_AY>,@<REG_Ayx> */ {"movy.w",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_1,HEX_1}, arch_sh4al_dsp_up},
+/* nnmm010010 movy.w <DSP_REG_AY>,@<REG_Ayx>+ */{"movy.w",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_1,HEX_2}, arch_sh4al_dsp_up},
+/* nnmm010011 movy.w <DSP_REG_AY>,@<REG_Ayx>+r8 */{"movy.w",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_1,HEX_3}, arch_sh4al_dsp_up},
+
+/* nnmm100001 movy.l @<REG_Ayx>,<DSP_REG_YX> */ {"movy.l",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_1}, arch_sh4al_dsp_up},
+/* nnmm100010 movy.l @<REG_Ayx>+,<DSP_REG_YX> */{"movy.l",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_2}, arch_sh4al_dsp_up},
+/* nnmm100011 movy.l @<REG_Ayx>+r8,<DSP_REG_YX> */{"movy.l",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_3}, arch_sh4al_dsp_up},
+/* nnmm110001 movy.l <DSP_REG_AY>,@<REG_Ayx> */ {"movy.l",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_3,HEX_1}, arch_sh4al_dsp_up},
+/* nnmm110010 movy.l <DSP_REG_AY>,@<REG_Ayx>+ */{"movy.l",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_3,HEX_2}, arch_sh4al_dsp_up},
+/* nnmm110011 movy.l <DSP_REG_AY>,@<REG_Ayx>+r8 */{"movy.l",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_3,HEX_3}, arch_sh4al_dsp_up},
+
+/* 01aaeeffxxyyggnn pmuls Se,Sf,Dg */ {"pmuls",{DSP_REG_E,DSP_REG_F,DSP_REG_G},{PPI,PMUL}, arch_sh_dsp_up},
+/* 10100000xxyynnnn psubc <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"psubc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_0}, arch_sh_dsp_up},
+/* 10110000xxyynnnn paddc <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"paddc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_0}, arch_sh_dsp_up},
+/* 10000100xxyynnnn pcmp <DSP_REG_X>,<DSP_REG_Y> */
+{"pcmp", {DSP_REG_X,DSP_REG_Y},{PPI,PPI3,HEX_8,HEX_4}, arch_sh_dsp_up},
+/* 10100100xxyynnnn pwsb <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"pwsb", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_4}, arch_sh_dsp_up},
+/* 10110100xxyynnnn pwad <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"pwad", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_4}, arch_sh_dsp_up},
+/* 10001000xxyynnnn pabs <DSP_REG_X>,<DSP_REG_N> */
+{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_8,HEX_8}, arch_sh_dsp_up},
+/* 1000100!xx01nnnn pabs <DSP_REG_X>,<DSP_REG_N> */
+{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9,HEX_1}, arch_sh4al_dsp_up},
+/* 10101000xxyynnnn pabs <DSP_REG_Y>,<DSP_REG_N> */
+{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_A,HEX_8}, arch_sh_dsp_up},
+/* 1010100!01yynnnn pabs <DSP_REG_Y>,<DSP_REG_N> */
+{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9,HEX_4}, arch_sh4al_dsp_up},
+/* 10011000xxyynnnn prnd <DSP_REG_X>,<DSP_REG_N> */
+{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_9,HEX_8}, arch_sh_dsp_up},
+/* 1001100!xx01nnnn prnd <DSP_REG_X>,<DSP_REG_N> */
+{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_1}, arch_sh4al_dsp_up},
+/* 10111000xxyynnnn prnd <DSP_REG_Y>,<DSP_REG_N> */
+{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_B,HEX_8}, arch_sh_dsp_up},
+/* 1011100!01yynnnn prnd <DSP_REG_Y>,<DSP_REG_N> */
+{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_4}, arch_sh4al_dsp_up},
+
+{"dct",{0},{PPI,PDC,HEX_1}, arch_sh_dsp_up},
+{"dcf",{0},{PPI,PDC,HEX_2}, arch_sh_dsp_up},
+
+/* 10000001xxyynnnn pshl <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"pshl", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_1}, arch_sh_dsp_up},
+/* 00000iiiiiiinnnn pshl #<imm>,<DSP_REG_N> */ {"pshl",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_0}, arch_sh_dsp_up},
+/* 10010001xxyynnnn psha <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"psha", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_1}, arch_sh_dsp_up},
+/* 00010iiiiiiinnnn psha #<imm>,<DSP_REG_N> */ {"psha",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_1}, arch_sh_dsp_up},
+/* 10100001xxyynnnn psub <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"psub", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_1}, arch_sh_dsp_up},
+/* 10000101xxyynnnn psub <DSP_REG_Y>,<DSP_REG_X>,<DSP_REG_N> */
+{"psub", {DSP_REG_Y,DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_5}, arch_sh4al_dsp_up},
+/* 10110001xxyynnnn padd <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"padd", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_1}, arch_sh_dsp_up},
+/* 10010101xxyynnnn pand <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"pand", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_5}, arch_sh_dsp_up},
+/* 10100101xxyynnnn pxor <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"pxor", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_5}, arch_sh_dsp_up},
+/* 10110101xxyynnnn por  <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
+{"por",  {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_5}, arch_sh_dsp_up},
+/* 10001001xxyynnnn pdec <DSP_REG_X>,<DSP_REG_N> */
+{"pdec", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9}, arch_sh_dsp_up},
+/* 10101001xxyynnnn pdec <DSP_REG_Y>,<DSP_REG_N> */
+{"pdec", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9}, arch_sh_dsp_up},
+/* 10011001xx00nnnn pinc <DSP_REG_X>,<DSP_REG_N> */
+{"pinc", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_XX00}, arch_sh_dsp_up},
+/* 1011100100yynnnn pinc <DSP_REG_Y>,<DSP_REG_N> */
+{"pinc", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_00YY}, arch_sh_dsp_up},
+/* 10001101xxyynnnn pclr <DSP_REG_N> */
+{"pclr", {DSP_REG_N},{PPI,PPIC,HEX_8,HEX_D}, arch_sh_dsp_up},
+/* 10011101xx00nnnn pdmsb <DSP_REG_X>,<DSP_REG_N> */
+{"pdmsb", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_XX00}, arch_sh_dsp_up},
+/* 1011110100yynnnn pdmsb <DSP_REG_Y>,<DSP_REG_N> */
+{"pdmsb", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_00YY}, arch_sh_dsp_up},
+/* 11001001xxyynnnn pneg  <DSP_REG_X>,<DSP_REG_N> */
+{"pneg",  {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_9}, arch_sh_dsp_up},
+/* 11101001xxyynnnn pneg  <DSP_REG_Y>,<DSP_REG_N> */
+{"pneg",  {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_E,HEX_9}, arch_sh_dsp_up},
+/* 11011001xxyynnnn pcopy <DSP_REG_X>,<DSP_REG_N> */
+{"pcopy", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_9}, arch_sh_dsp_up},
+/* 11111001xxyynnnn pcopy <DSP_REG_Y>,<DSP_REG_N> */
+{"pcopy", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_F,HEX_9}, arch_sh_dsp_up},
+/* 11001101xxyynnnn psts MACH,<DSP_REG_N> */
+{"psts", {A_MACH,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_D}, arch_sh_dsp_up},
+/* 11011101xxyynnnn psts MACL,<DSP_REG_N> */
+{"psts", {A_MACL,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_D}, arch_sh_dsp_up},
+/* 11101101xxyynnnn plds <DSP_REG_N>,MACH */
+{"plds", {DSP_REG_N,A_MACH},{PPI,PPIC,HEX_E,HEX_D}, arch_sh_dsp_up},
+/* 11111101xxyynnnn plds <DSP_REG_N>,MACL */
+{"plds", {DSP_REG_N,A_MACL},{PPI,PPIC,HEX_F,HEX_D}, arch_sh_dsp_up},
+/* 10011101xx01zzzz pswap <DSP_REG_X>,<DSP_REG_N> */
+{"pswap", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_1}, arch_sh4al_dsp_up},
+/* 1011110101yyzzzz pswap <DSP_REG_Y>,<DSP_REG_N> */
+{"pswap", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_4}, arch_sh4al_dsp_up},
+
+/* 1111nnnn01011101 fabs <F_REG_N>     */{"fabs",{F_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh2e_up},
+/* 1111nnn001011101 fabs <D_REG_N>     */{"fabs",{D_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0000 fadd <F_REG_M>,<F_REG_N>*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh2e_up},
+/* 1111nnn0mmm00000 fadd <D_REG_M>,<D_REG_N>*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0100 fcmp/eq <F_REG_M>,<F_REG_N>*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh2e_up},
+/* 1111nnn0mmm00100 fcmp/eq <D_REG_M>,<D_REG_N>*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0101 fcmp/gt <F_REG_M>,<F_REG_N>*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh2e_up},
+/* 1111nnn0mmm00101 fcmp/gt <D_REG_M>,<D_REG_N>*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnn010111101 fcnvds <D_REG_N>,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N_D,HEX_B,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnn010101101 fcnvsd FPUL,<D_REG_N>*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_A,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0011 fdiv <F_REG_M>,<F_REG_N>*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh2e_up},
+/* 1111nnn0mmm00011 fdiv <D_REG_M>,<D_REG_N>*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnmm11101101 fipr <V_REG_M>,<V_REG_N>*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}, arch_sh4_up},
+
+/* 1111nnnn10001101 fldi0 <F_REG_N>    */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}, arch_sh2e_up},
+
+/* 1111nnnn10011101 fldi1 <F_REG_N>    */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}, arch_sh2e_up},
+
+/* 1111nnnn00011101 flds <F_REG_N>,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}, arch_sh2e_up},
+
+/* 1111nnnn00101101 float FPUL,<F_REG_N>*/{"float",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh2e_up},
+/* 1111nnn000101101 float FPUL,<D_REG_N>*/{"float",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm1110 fmac FR0,<F_REG_M>,<F_REG_N>*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}, arch_sh2e_up},
+
+/* 1111nnnnmmmm1100 fmov <F_REG_M>,<F_REG_N>*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh2e_up},
+/* 1111nnn1mmmm1100 fmov <DX_REG_M>,<DX_REG_N>*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm1000 fmov @<REG_M>,<F_REG_N>*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up},
+/* 1111nnn1mmmm1000 fmov @<REG_M>,<DX_REG_N>*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm1010 fmov <F_REG_M>,@<REG_N>*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up},
+/* 1111nnnnmmm11010 fmov <DX_REG_M>,@<REG_N>*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm1001 fmov @<REG_M>+,<F_REG_N>*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up},
+/* 1111nnn1mmmm1001 fmov @<REG_M>+,<DX_REG_N>*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm1011 fmov <F_REG_M>, at -<REG_N>*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up},
+/* 1111nnnnmmm11011 fmov <DX_REG_M>, at -<REG_N>*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0110 fmov @(R0,<REG_M>),<F_REG_N>*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up},
+/* 1111nnn1mmmm0110 fmov @(R0,<REG_M>),<DX_REG_N>*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmmm0111 fmov <F_REG_M>,@(R0,<REG_N>)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up},
+/* 1111nnnnmmm10111 fmov <DX_REG_M>,@(R0,<REG_N>)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnn1mmmm1000 fmov.d @<REG_M>,<DX_REG_N>*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmm11010 fmov.d <DX_REG_M>,@<REG_N>*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnn1mmmm1001 fmov.d @<REG_M>+,<DX_REG_N>*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmm11011 fmov.d <DX_REG_M>, at -<REG_N>*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnn1mmmm0110 fmov.d @(R0,<REG_M>),<DX_REG_N>*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnnmmm10111 fmov.d <DX_REG_M>,@(R0,<REG_N>)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up},
+/* 0011nnnnmmmm0001 0011dddddddddddd fmov.d <F_REG_M>,@(<DISP12>,<REG_N>) */
+{"fmov.d",{DX_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY8}, arch_sh2a_up | arch_op32},
+/* 0011nnnnmmmm0001 0111dddddddddddd fmov.d @(<DISP12>,<REG_M>),F_REG_N */
+{"fmov.d",{A_DISP_REG_M,DX_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY8}, arch_sh2a_up | arch_op32},
+
+/* 1111nnnnmmmm1000 fmov.s @<REG_M>,<F_REG_N>*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up},
+
+/* 1111nnnnmmmm1010 fmov.s <F_REG_M>,@<REG_N>*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up},
+
+/* 1111nnnnmmmm1001 fmov.s @<REG_M>+,<F_REG_N>*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up},
+
+/* 1111nnnnmmmm1011 fmov.s <F_REG_M>, at -<REG_N>*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up},
+
+/* 1111nnnnmmmm0110 fmov.s @(R0,<REG_M>),<F_REG_N>*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up},
+
+/* 1111nnnnmmmm0111 fmov.s <F_REG_M>,@(R0,<REG_N>)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up},
+/* 0011nnnnmmmm0001 0011dddddddddddd fmov.s <F_REG_M>,@(<DISP12>,<REG_N>) */
+{"fmov.s",{F_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY4}, arch_sh2a_up | arch_op32},
+/* 0011nnnnmmmm0001 0111dddddddddddd fmov.s @(<DISP12>,<REG_M>),F_REG_N */
+{"fmov.s",{A_DISP_REG_M,F_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY4}, arch_sh2a_up | arch_op32},
+
+/* 1111nnnnmmmm0010 fmul <F_REG_M>,<F_REG_N>*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh2e_up},
+/* 1111nnn0mmm00010 fmul <D_REG_M>,<D_REG_N>*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnn01001101 fneg <F_REG_N>     */{"fneg",{F_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh2e_up},
+/* 1111nnn001001101 fneg <D_REG_N>     */{"fneg",{D_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111011111111101 fpchg               */{"fpchg",{0},{HEX_F,HEX_7,HEX_F,HEX_D}, arch_sh4a_up},
+
+/* 1111101111111101 frchg               */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}, arch_sh4_up},
+
+/* 1111nnn011111101 fsca FPUL,<D_REG_N> */{"fsca",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_F,HEX_D}, arch_sh4_up},
+
+/* 1111001111111101 fschg               */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnn01101101 fsqrt <F_REG_N>    */{"fsqrt",{F_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh3e_up | arch_sh2a_up},
+/* 1111nnn001101101 fsqrt <D_REG_N>    */{"fsqrt",{D_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnn01111101 fsrra <F_REG_N>    */{"fsrra",{F_REG_N},{HEX_F,REG_N,HEX_7,HEX_D}, arch_sh4_up},
+
+/* 1111nnnn00001101 fsts FPUL,<F_REG_N>*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}, arch_sh2e_up},
+
+/* 1111nnnnmmmm0001 fsub <F_REG_M>,<F_REG_N>*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh2e_up},
+/* 1111nnn0mmm00001 fsub <D_REG_M>,<D_REG_N>*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nnnn00111101 ftrc <F_REG_N>,FPUL*/{"ftrc",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh2e_up},
+/* 1111nnnn00111101 ftrc <D_REG_N>,FPUL*/{"ftrc",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh4_up | arch_sh2a_up},
+
+/* 1111nn0111111101 ftrv XMTRX_M4,<V_REG_n>*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_N_B01,HEX_F,HEX_D}, arch_sh4_up},
+
+  /* 10000110nnnn0iii bclr #<imm>, <REG_N> */  {"bclr",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3c}, arch_sh2a_nofpu_up},
+  /* 0011nnnn0iii1001 0000dddddddddddd bclr.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bclr.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+  /* 10000111nnnn1iii bld #<imm>, <REG_N> */   {"bld",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3s}, arch_sh2a_nofpu_up},
+  /* 0011nnnn0iii1001 0011dddddddddddd bld.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bld.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_3,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+  /* 10000110nnnn1iii bset #<imm>, <REG_N> */  {"bset",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3s}, arch_sh2a_nofpu_up},
+  /* 0011nnnn0iii1001 0001dddddddddddd bset.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bset.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_1,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+  /* 10000111nnnn0iii bst #<imm>, <REG_N> */   {"bst",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3c}, arch_sh2a_nofpu_up},
+  /* 0011nnnn0iii1001 0010dddddddddddd bst.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bst.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_2,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+  /* 0100nnnn10010001 clips.b <REG_N> */       {"clips.b",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_1}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10010101 clips.w <REG_N> */       {"clips.w",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_5}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10000001 clipu.b <REG_N> */       {"clipu.b",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_1}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10000101 clipu.w <REG_N> */       {"clipu.w",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_5}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10010100 divs R0,<REG_N> */       {"divs",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_9,HEX_4}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10000100 divu R0,<REG_N> */       {"divu",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_4}, arch_sh2a_nofpu_up},
+  /* 0100mmmm01001011 jsr/n @<REG_M>  */       {"jsr/n",{A_IND_M},{HEX_4,REG_M,HEX_4,HEX_B}, arch_sh2a_nofpu_up},
+  /* 10000011dddddddd jsr/n @@(<disp>,TBR) */  {"jsr/n",{A_DISP2_TBR},{HEX_8,HEX_3,IMM0_8BY4}, arch_sh2a_nofpu_up},
+  /* 0100mmmm11100101 ldbank @<REG_M>,R0 */    {"ldbank",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_5}, arch_sh2a_nofpu_up},
+  /* 0100mmmm11110001 movml.l <REG_M>, at -R15 */ {"movml.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_1}, arch_sh2a_nofpu_up},
+  /* 0100mmmm11110101 movml.l @R15+,<REG_M> */ {"movml.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_5}, arch_sh2a_nofpu_up},
+  /* 0100mmmm11110000 movml.l <REG_M>, at -R15 */ {"movmu.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_0}, arch_sh2a_nofpu_up},
+  /* 0100mmmm11110100 movml.l @R15+,<REG_M> */ {"movmu.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_4}, arch_sh2a_nofpu_up},
+  /* 0000nnnn00111001 movrt <REG_N> */         {"movrt",{A_REG_N},{HEX_0,REG_N,HEX_3,HEX_9}, arch_sh2a_nofpu_up},
+  /* 0100nnnn10000000 mulr R0,<REG_N> */       {"mulr",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_0}, arch_sh2a_nofpu_up},
+  /* 0000000001101000 nott */                  {"nott",{A_END},{HEX_0,HEX_0,HEX_6,HEX_8}, arch_sh2a_nofpu_up},
+  /* 0000000001011011 resbank */               {"resbank",{A_END},{HEX_0,HEX_0,HEX_5,HEX_B}, arch_sh2a_nofpu_up},
+  /* 0000000001101011 rts/n */                 {"rts/n",{A_END},{HEX_0,HEX_0,HEX_6,HEX_B}, arch_sh2a_nofpu_up},
+  /* 0000mmmm01111011 rtv/n <REG_M>*/          {"rtv/n",{A_REG_M},{HEX_0,REG_M,HEX_7,HEX_B}, arch_sh2a_nofpu_up},
+  /* 0100nnnn11100001 stbank R0,@<REG_N>*/     {"stbank",{A_R0,A_IND_N},{HEX_4,REG_N,HEX_E,HEX_1}, arch_sh2a_nofpu_up},
+
+/* 0011nnnn0iii1001 0100dddddddddddd band.b #<imm>,@(<DISP12>,<REG_N>) */
+{"band.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_4,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnn0iii1001 1100dddddddddddd bandnot.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bandnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_C,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnn0iii1001 1011dddddddddddd bldnot.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bldnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_B,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnn0iii1001 0101dddddddddddd bor.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_5,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnn0iii1001 1101dddddddddddd bornot.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bornot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_D,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnn0iii1001 0110dddddddddddd bxor.b #<imm>,@(<DISP12>,<REG_N>) */
+{"bxor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_6,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0000nnnniiii0000 iiiiiiiiiiiiiiii movi20 #<imm>,<REG_N> */
+{"movi20",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_0,IMM0_20}, arch_sh2a_nofpu_up | arch_op32},
+/* 0000nnnniiii0001 iiiiiiiiiiiiiiii movi20s #<imm>,<REG_N> */
+{"movi20s",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_1,IMM0_20BY8}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnnmmmm0001 1000dddddddddddd movu.b @(<DISP12>,<REG_M>),<REG_N> */
+{"movu.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_8,DISP0_12}, arch_sh2a_nofpu_up | arch_op32},
+/* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(<DISP12>,<REG_M>),<REG_N> */
+{"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32},
+
+{ 0, {0}, {0}, 0 }
+};
+
+#endif
+
+#ifdef ARCH_all
+#define INCLUDE_SHMEDIA
+#endif
+
+static void
+print_movxy (const sh_opcode_info *op, int rn, int rm,
+             fprintf_function fprintf_fn, void *stream)
+{
+  int n;
+
+  fprintf_fn (stream, "%s\t", op->name);
+  for (n = 0; n < 2; n++)
+    {
+      switch (op->arg[n])
+	{
+	case A_IND_N:
+	case AX_IND_N:
+	case AXY_IND_N:
+	case AY_IND_N:
+	case AYX_IND_N:
+	  fprintf_fn (stream, "@r%d", rn);
+	  break;
+	case A_INC_N:
+	case AX_INC_N:
+	case AXY_INC_N:
+	case AY_INC_N:
+	case AYX_INC_N:
+	  fprintf_fn (stream, "@r%d+", rn);
+	  break;
+	case AX_PMOD_N:
+	case AXY_PMOD_N:
+	  fprintf_fn (stream, "@r%d+r8", rn);
+	  break;
+	case AY_PMOD_N:
+	case AYX_PMOD_N:
+	  fprintf_fn (stream, "@r%d+r9", rn);
+	  break;
+	case DSP_REG_A_M:
+	  fprintf_fn (stream, "a%c", '0' + rm);
+	  break;
+	case DSP_REG_X:
+	  fprintf_fn (stream, "x%c", '0' + rm);
+	  break;
+	case DSP_REG_Y:
+	  fprintf_fn (stream, "y%c", '0' + rm);
+	  break;
+	case DSP_REG_AX:
+	  fprintf_fn (stream, "%c%c",
+		      (rm & 1) ? 'x' : 'a',
+		      (rm & 2) ? '1' : '0');
+	  break;
+	case DSP_REG_XY:
+	  fprintf_fn (stream, "%c%c",
+		      (rm & 1) ? 'y' : 'x',
+		      (rm & 2) ? '1' : '0');
+	  break;
+	case DSP_REG_AY:
+	  fprintf_fn (stream, "%c%c",
+		      (rm & 2) ? 'y' : 'a',
+		      (rm & 1) ? '1' : '0');
+	  break;
+	case DSP_REG_YX:
+	  fprintf_fn (stream, "%c%c",
+		      (rm & 2) ? 'x' : 'y',
+		      (rm & 1) ? '1' : '0');
+	  break;
+	default:
+	  abort ();
+	}
+      if (n == 0)
+	fprintf_fn (stream, ",");
+    }
+}
+
+/* Print a double data transfer insn.  INSN is just the lower three
+   nibbles of the insn, i.e. field a and the bit that indicates if
+   a parallel processing insn follows.
+   Return nonzero if a field b of a parallel processing insns follows.  */
+
+static void
+print_insn_ddt (int insn, struct disassemble_info *info)
+{
+  fprintf_function fprintf_fn = info->fprintf_func;
+  void *stream = info->stream;
+
+  /* If this is just a nop, make sure to emit something.  */
+  if (insn == 0x000)
+    fprintf_fn (stream, "nopx\tnopy");
+
+  /* If a parallel processing insn was printed before,
+     and we got a non-nop, emit a tab.  */
+  if ((insn & 0x800) && (insn & 0x3ff))
+    fprintf_fn (stream, "\t");
+
+  /* Check if either the x or y part is invalid.  */
+  if (((insn & 0xc) == 0 && (insn & 0x2a0))
+      || ((insn & 3) == 0 && (insn & 0x150)))
+    if (info->mach != bfd_mach_sh_dsp
+        && info->mach != bfd_mach_sh3_dsp)
+      {
+	static const sh_opcode_info *first_movx, *first_movy;
+	const sh_opcode_info *op;
+	int is_movy;
+
+	if (! first_movx)
+	  {
+	    for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;)
+	      first_movx++;
+	    for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;)
+	      first_movy++;
+	  }
+
+	is_movy = ((insn & 3) != 0);
+
+	if (is_movy)
+	  op = first_movy;
+	else
+	  op = first_movx;
+
+	while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3)
+	       || op->nibbles[3] != (unsigned) (insn & 0xf))
+	  op++;
+
+	print_movxy (op,
+		     (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0)
+		      + 2 * is_movy
+		      + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)),
+		     (insn >> 6) & 3,
+		     fprintf_fn, stream);
+      }
+    else
+      fprintf_fn (stream, ".word 0x%x", insn);
+  else
+    {
+      static const sh_opcode_info *first_movx, *first_movy;
+      const sh_opcode_info *opx, *opy;
+      unsigned int insn_x, insn_y;
+
+      if (! first_movx)
+	{
+	  for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;)
+	    first_movx++;
+	  for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;)
+	    first_movy++;
+	}
+      insn_x = (insn >> 2) & 0xb;
+      if (insn_x)
+	{
+	  for (opx = first_movx; opx->nibbles[2] != insn_x;)
+	    opx++;
+	  print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1,
+		       fprintf_fn, stream);
+	}
+      insn_y = (insn & 3) | ((insn >> 1) & 8);
+      if (insn_y)
+	{
+	  if (insn_x)
+	    fprintf_fn (stream, "\t");
+	  for (opy = first_movy; opy->nibbles[2] != insn_y;)
+	    opy++;
+	  print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1,
+		       fprintf_fn, stream);
+	}
+    }
+}
+
+static void
+print_dsp_reg (int rm, fprintf_function fprintf_fn, void *stream)
+{
+  switch (rm)
+    {
+    case A_A1_NUM:
+      fprintf_fn (stream, "a1");
+      break;
+    case A_A0_NUM:
+      fprintf_fn (stream, "a0");
+      break;
+    case A_X0_NUM:
+      fprintf_fn (stream, "x0");
+      break;
+    case A_X1_NUM:
+      fprintf_fn (stream, "x1");
+      break;
+    case A_Y0_NUM:
+      fprintf_fn (stream, "y0");
+      break;
+    case A_Y1_NUM:
+      fprintf_fn (stream, "y1");
+      break;
+    case A_M0_NUM:
+      fprintf_fn (stream, "m0");
+      break;
+    case A_A1G_NUM:
+      fprintf_fn (stream, "a1g");
+      break;
+    case A_M1_NUM:
+      fprintf_fn (stream, "m1");
+      break;
+    case A_A0G_NUM:
+      fprintf_fn (stream, "a0g");
+      break;
+    default:
+      fprintf_fn (stream, "0x%x", rm);
+      break;
+    }
+}
+
+static void
+print_insn_ppi (int field_b, struct disassemble_info *info)
+{
+  static const char *sx_tab[] = { "x0", "x1", "a0", "a1" };
+  static const char *sy_tab[] = { "y0", "y1", "m0", "m1" };
+  fprintf_function fprintf_fn = info->fprintf_func;
+  void *stream = info->stream;
+  unsigned int nib1, nib2, nib3;
+  unsigned int altnib1, nib4;
+  const char *dc = NULL;
+  const sh_opcode_info *op;
+
+  if ((field_b & 0xe800) == 0)
+    {
+      fprintf_fn (stream, "psh%c\t#%d,",
+		  field_b & 0x1000 ? 'a' : 'l',
+		  (field_b >> 4) & 127);
+      print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
+      return;
+    }
+  if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)
+    {
+      static const char *du_tab[] = { "x0", "y0", "a0", "a1" };
+      static const char *se_tab[] = { "x0", "x1", "y0", "a1" };
+      static const char *sf_tab[] = { "y0", "y1", "x0", "a1" };
+      static const char *sg_tab[] = { "m0", "m1", "a0", "a1" };
+
+      if (field_b & 0x2000)
+	{
+	  fprintf_fn (stream, "p%s %s,%s,%s\t",
+		      (field_b & 0x1000) ? "add" : "sub",
+		      sx_tab[(field_b >> 6) & 3],
+		      sy_tab[(field_b >> 4) & 3],
+		      du_tab[(field_b >> 0) & 3]);
+	}
+      else if ((field_b & 0xf0) == 0x10
+	       && info->mach != bfd_mach_sh_dsp
+	       && info->mach != bfd_mach_sh3_dsp)
+	{
+	  fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]);
+	}
+      else if ((field_b & 0xf3) != 0)
+	{
+	  fprintf_fn (stream, ".word 0x%x\t", field_b);
+	}
+      fprintf_fn (stream, "pmuls%c%s,%s,%s",
+		  field_b & 0x2000 ? ' ' : '\t',
+		  se_tab[(field_b >> 10) & 3],
+		  sf_tab[(field_b >>  8) & 3],
+		  sg_tab[(field_b >>  2) & 3]);
+      return;
+    }
+
+  nib1 = PPIC;
+  nib2 = field_b >> 12 & 0xf;
+  nib3 = field_b >> 8 & 0xf;
+  nib4 = field_b >> 4 & 0xf;
+  switch (nib3 & 0x3)
+    {
+    case 0:
+      dc = "";
+      nib1 = PPI3;
+      break;
+    case 1:
+      dc = "";
+      break;
+    case 2:
+      dc = "dct ";
+      nib3 -= 1;
+      break;
+    case 3:
+      dc = "dcf ";
+      nib3 -= 2;
+      break;
+    }
+  if (nib1 == PPI3)
+    altnib1 = PPI3NC;
+  else
+    altnib1 = nib1;
+  for (op = sh_table; op->name; op++)
+    {
+      if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1)
+	  && op->nibbles[2] == nib2
+	  && op->nibbles[3] == nib3)
+	{
+	  int n;
+
+	  switch (op->nibbles[4])
+	    {
+	    case HEX_0:
+	      break;
+	    case HEX_XX00:
+	      if ((nib4 & 3) != 0)
+		continue;
+	      break;
+	    case HEX_1:
+	      if ((nib4 & 3) != 1)
+		continue;
+	      break;
+	    case HEX_00YY:
+	      if ((nib4 & 0xc) != 0)
+		continue;
+	      break;
+	    case HEX_4:
+	      if ((nib4 & 0xc) != 4)
+		continue;
+	      break;
+	    default:
+	      abort ();
+	    }
+	  fprintf_fn (stream, "%s%s\t", dc, op->name);
+	  for (n = 0; n < 3 && op->arg[n] != A_END; n++)
+	    {
+	      if (n && op->arg[1] != A_END)
+		fprintf_fn (stream, ",");
+	      switch (op->arg[n])
+		{
+		case DSP_REG_N:
+		  print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
+		  break;
+		case DSP_REG_X:
+		  fprintf_fn (stream, "%s", sx_tab[(field_b >> 6) & 3]);
+		  break;
+		case DSP_REG_Y:
+		  fprintf_fn (stream, "%s", sy_tab[(field_b >> 4) & 3]);
+		  break;
+		case A_MACH:
+		  fprintf_fn (stream, "mach");
+		  break;
+		case A_MACL:
+		  fprintf_fn (stream, "macl");
+		  break;
+		default:
+		  abort ();
+		}
+	    }
+	  return;
+	}
+    }
+  /* Not found.  */
+  fprintf_fn (stream, ".word 0x%x", field_b);
+}
+
+/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff
+   (ie. the upper nibble is missing).  */
+int
+print_insn_sh (bfd_vma memaddr, struct disassemble_info *info)
+{
+  fprintf_function fprintf_fn = info->fprintf_func;
+  void *stream = info->stream;
+  unsigned char insn[4];
+  unsigned char nibs[8];
+  int status;
+  bfd_vma relmask = ~(bfd_vma) 0;
+  const sh_opcode_info *op;
+  unsigned int target_arch;
+  int allow_op32;
+
+  switch (info->mach)
+    {
+    case bfd_mach_sh:
+      target_arch = arch_sh1;
+      break;
+    case bfd_mach_sh4:
+      target_arch = arch_sh4;
+      break;
+    case bfd_mach_sh5:
+#ifdef INCLUDE_SHMEDIA
+      status = print_insn_sh64 (memaddr, info);
+      if (status != -2)
+	return status;
+#endif
+      /* When we get here for sh64, it's because we want to disassemble
+	 SHcompact, i.e. arch_sh4.  */
+      target_arch = arch_sh4;
+      break;
+    default:
+      fprintf (stderr, "sh architecture not supported\n");
+      return -1;
+    }
+
+  status = info->read_memory_func (memaddr, insn, 2, info);
+
+  if (status != 0)
+    {
+      info->memory_error_func (status, memaddr, info);
+      return -1;
+    }
+
+  if (info->endian == BFD_ENDIAN_LITTLE)
+    {
+      nibs[0] = (insn[1] >> 4) & 0xf;
+      nibs[1] = insn[1] & 0xf;
+
+      nibs[2] = (insn[0] >> 4) & 0xf;
+      nibs[3] = insn[0] & 0xf;
+    }
+  else
+    {
+      nibs[0] = (insn[0] >> 4) & 0xf;
+      nibs[1] = insn[0] & 0xf;
+
+      nibs[2] = (insn[1] >> 4) & 0xf;
+      nibs[3] = insn[1] & 0xf;
+    }
+  status = info->read_memory_func (memaddr + 2, insn + 2, 2, info);
+  if (status != 0)
+    allow_op32 = 0;
+  else
+    {
+      allow_op32 = 1;
+
+      if (info->endian == BFD_ENDIAN_LITTLE)
+	{
+	  nibs[4] = (insn[3] >> 4) & 0xf;
+	  nibs[5] = insn[3] & 0xf;
+
+	  nibs[6] = (insn[2] >> 4) & 0xf;
+	  nibs[7] = insn[2] & 0xf;
+	}
+      else
+	{
+	  nibs[4] = (insn[2] >> 4) & 0xf;
+	  nibs[5] = insn[2] & 0xf;
+
+	  nibs[6] = (insn[3] >> 4) & 0xf;
+	  nibs[7] = insn[3] & 0xf;
+	}
+    }
+
+  if (nibs[0] == 0xf && (nibs[1] & 4) == 0
+      && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up))
+    {
+      if (nibs[1] & 8)
+	{
+	  int field_b;
+
+	  status = info->read_memory_func (memaddr + 2, insn, 2, info);
+
+	  if (status != 0)
+	    {
+	      info->memory_error_func (status, memaddr + 2, info);
+	      return -1;
+	    }
+
+	  if (info->endian == BFD_ENDIAN_LITTLE)
+	    field_b = insn[1] << 8 | insn[0];
+	  else
+	    field_b = insn[0] << 8 | insn[1];
+
+	  print_insn_ppi (field_b, info);
+	  print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
+	  return 4;
+	}
+      print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
+      return 2;
+    }
+  for (op = sh_table; op->name; op++)
+    {
+      int n;
+      int imm = 0;
+      int rn = 0;
+      int rm = 0;
+      int rb = 0;
+      int disp_pc;
+      bfd_vma disp_pc_addr = 0;
+      int disp = 0;
+      int has_disp = 0;
+      int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4;
+
+      if (!allow_op32
+	  && SH_MERGE_ARCH_SET (op->arch, arch_op32))
+	goto fail;
+
+      if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch))
+	goto fail;
+      for (n = 0; n < max_n; n++)
+	{
+	  int i = op->nibbles[n];
+
+	  if (i < 16)
+	    {
+	      if (nibs[n] == i)
+		continue;
+	      goto fail;
+	    }
+	  switch (i)
+	    {
+	    case BRANCH_8:
+	      imm = (nibs[2] << 4) | (nibs[3]);
+	      if (imm & 0x80)
+		imm |= ~0xff;
+	      imm = ((char) imm) * 2 + 4;
+	      goto ok;
+	    case BRANCH_12:
+	      imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
+	      if (imm & 0x800)
+		imm |= ~0xfff;
+	      imm = imm * 2 + 4;
+	      goto ok;
+	    case IMM0_3c:
+	      if (nibs[3] & 0x8)
+		goto fail;
+	      imm = nibs[3] & 0x7;
+	      break;
+	    case IMM0_3s:
+	      if (!(nibs[3] & 0x8))
+		goto fail;
+	      imm = nibs[3] & 0x7;
+	      break;
+	    case IMM0_3Uc:
+	      if (nibs[2] & 0x8)
+		goto fail;
+	      imm = nibs[2] & 0x7;
+	      break;
+	    case IMM0_3Us:
+	      if (!(nibs[2] & 0x8))
+		goto fail;
+	      imm = nibs[2] & 0x7;
+	      break;
+	    case DISP0_12:
+	    case DISP1_12:
+	      disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7];
+	      has_disp = 1;
+	      goto ok;
+	    case DISP0_12BY2:
+	    case DISP1_12BY2:
+	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1;
+	      relmask = ~(bfd_vma) 1;
+	      has_disp = 1;
+	      goto ok;
+	    case DISP0_12BY4:
+	    case DISP1_12BY4:
+	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2;
+	      relmask = ~(bfd_vma) 3;
+	      has_disp = 1;
+	      goto ok;
+	    case DISP0_12BY8:
+	    case DISP1_12BY8:
+	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3;
+	      relmask = ~(bfd_vma) 7;
+	      has_disp = 1;
+	      goto ok;
+	    case IMM0_20_4:
+	      break;
+	    case IMM0_20:
+	      imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
+		     | (nibs[6] << 4) | nibs[7]);
+	      if (imm & 0x80000)
+		imm -= 0x100000;
+	      goto ok;
+	    case IMM0_20BY8:
+	      imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
+		     | (nibs[6] << 4) | nibs[7]);
+	      imm <<= 8;
+	      if (imm & 0x8000000)
+		imm -= 0x10000000;
+	      goto ok;
+	    case IMM0_4:
+	    case IMM1_4:
+	      imm = nibs[3];
+	      goto ok;
+	    case IMM0_4BY2:
+	    case IMM1_4BY2:
+	      imm = nibs[3] << 1;
+	      goto ok;
+	    case IMM0_4BY4:
+	    case IMM1_4BY4:
+	      imm = nibs[3] << 2;
+	      goto ok;
+	    case IMM0_8:
+	    case IMM1_8:
+	      imm = (nibs[2] << 4) | nibs[3];
+	      disp = imm;
+	      has_disp = 1;
+	      if (imm & 0x80)
+		imm -= 0x100;
+	      goto ok;
+	    case PCRELIMM_8BY2:
+	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
+	      relmask = ~(bfd_vma) 1;
+	      goto ok;
+	    case PCRELIMM_8BY4:
+	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
+	      relmask = ~(bfd_vma) 3;
+	      goto ok;
+	    case IMM0_8BY2:
+	    case IMM1_8BY2:
+	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
+	      goto ok;
+	    case IMM0_8BY4:
+	    case IMM1_8BY4:
+	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
+	      goto ok;
+	    case REG_N_D:
+	      if ((nibs[n] & 1) != 0)
+		goto fail;
+	      /* fall through */
+	    case REG_N:
+	      rn = nibs[n];
+	      break;
+	    case REG_M:
+	      rm = nibs[n];
+	      break;
+	    case REG_N_B01:
+	      if ((nibs[n] & 0x3) != 1 /* binary 01 */)
+		goto fail;
+	      rn = (nibs[n] & 0xc) >> 2;
+	      break;
+	    case REG_NM:
+	      rn = (nibs[n] & 0xc) >> 2;
+	      rm = (nibs[n] & 0x3);
+	      break;
+	    case REG_B:
+	      rb = nibs[n] & 0x07;
+	      break;
+	    case SDT_REG_N:
+	      /* sh-dsp: single data transfer.  */
+	      rn = nibs[n];
+	      if ((rn & 0xc) != 4)
+		goto fail;
+	      rn = rn & 0x3;
+	      rn |= (!(rn & 2)) << 2;
+	      break;
+	    case PPI:
+	    case REPEAT:
+	      goto fail;
+	    default:
+	      abort ();
+	    }
+	}
+
+    ok:
+      /* sh2a has D_REG but not X_REG.  We don't know the pattern
+	 doesn't match unless we check the output args to see if they
+	 make sense.  */
+      if (target_arch == arch_sh2a
+	  && ((op->arg[0] == DX_REG_M && (rm & 1) != 0)
+	      || (op->arg[1] == DX_REG_N && (rn & 1) != 0)))
+	goto fail;
+
+      fprintf_fn (stream, "%s\t", op->name);
+      disp_pc = 0;
+      for (n = 0; n < 3 && op->arg[n] != A_END; n++)
+	{
+	  if (n && op->arg[1] != A_END)
+	    fprintf_fn (stream, ",");
+	  switch (op->arg[n])
+	    {
+	    case A_IMM:
+	      fprintf_fn (stream, "#%d", imm);
+	      break;
+	    case A_R0:
+	      fprintf_fn (stream, "r0");
+	      break;
+	    case A_REG_N:
+	      fprintf_fn (stream, "r%d", rn);
+	      break;
+	    case A_INC_N:
+	    case AS_INC_N:
+	      fprintf_fn (stream, "@r%d+", rn);
+	      break;
+	    case A_DEC_N:
+	    case AS_DEC_N:
+	      fprintf_fn (stream, "@-r%d", rn);
+	      break;
+	    case A_IND_N:
+	    case AS_IND_N:
+	      fprintf_fn (stream, "@r%d", rn);
+	      break;
+	    case A_DISP_REG_N:
+	      fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn);
+	      break;
+	    case AS_PMOD_N:
+	      fprintf_fn (stream, "@r%d+r8", rn);
+	      break;
+	    case A_REG_M:
+	      fprintf_fn (stream, "r%d", rm);
+	      break;
+	    case A_INC_M:
+	      fprintf_fn (stream, "@r%d+", rm);
+	      break;
+	    case A_DEC_M:
+	      fprintf_fn (stream, "@-r%d", rm);
+	      break;
+	    case A_IND_M:
+	      fprintf_fn (stream, "@r%d", rm);
+	      break;
+	    case A_DISP_REG_M:
+	      fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm);
+	      break;
+	    case A_REG_B:
+	      fprintf_fn (stream, "r%d_bank", rb);
+	      break;
+	    case A_DISP_PC:
+	      disp_pc = 1;
+	      disp_pc_addr = imm + 4 + (memaddr & relmask);
+	      (*info->print_address_func) (disp_pc_addr, info);
+	      break;
+	    case A_IND_R0_REG_N:
+	      fprintf_fn (stream, "@(r0,r%d)", rn);
+	      break;
+	    case A_IND_R0_REG_M:
+	      fprintf_fn (stream, "@(r0,r%d)", rm);
+	      break;
+	    case A_DISP_GBR:
+	      fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm);
+	      break;
+	    case A_TBR:
+	      fprintf_fn (stream, "tbr");
+	      break;
+	    case A_DISP2_TBR:
+	      fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm);
+	      break;
+	    case A_INC_R15:
+	      fprintf_fn (stream, "@r15+");
+	      break;
+	    case A_DEC_R15:
+	      fprintf_fn (stream, "@-r15");
+	      break;
+	    case A_R0_GBR:
+	      fprintf_fn (stream, "@(r0,gbr)");
+	      break;
+	    case A_BDISP12:
+	    case A_BDISP8:
+                {
+                    bfd_vma addr;
+                    addr = imm + memaddr;
+                    (*info->print_address_func) (addr, info);
+                }
+	      break;
+	    case A_SR:
+	      fprintf_fn (stream, "sr");
+	      break;
+	    case A_GBR:
+	      fprintf_fn (stream, "gbr");
+	      break;
+	    case A_VBR:
+	      fprintf_fn (stream, "vbr");
+	      break;
+	    case A_DSR:
+	      fprintf_fn (stream, "dsr");
+	      break;
+	    case A_MOD:
+	      fprintf_fn (stream, "mod");
+	      break;
+	    case A_RE:
+	      fprintf_fn (stream, "re");
+	      break;
+	    case A_RS:
+	      fprintf_fn (stream, "rs");
+	      break;
+	    case A_A0:
+	      fprintf_fn (stream, "a0");
+	      break;
+	    case A_X0:
+	      fprintf_fn (stream, "x0");
+	      break;
+	    case A_X1:
+	      fprintf_fn (stream, "x1");
+	      break;
+	    case A_Y0:
+	      fprintf_fn (stream, "y0");
+	      break;
+	    case A_Y1:
+	      fprintf_fn (stream, "y1");
+	      break;
+	    case DSP_REG_M:
+	      print_dsp_reg (rm, fprintf_fn, stream);
+	      break;
+	    case A_SSR:
+	      fprintf_fn (stream, "ssr");
+	      break;
+	    case A_SPC:
+	      fprintf_fn (stream, "spc");
+	      break;
+	    case A_MACH:
+	      fprintf_fn (stream, "mach");
+	      break;
+	    case A_MACL:
+	      fprintf_fn (stream, "macl");
+	      break;
+	    case A_PR:
+	      fprintf_fn (stream, "pr");
+	      break;
+	    case A_SGR:
+	      fprintf_fn (stream, "sgr");
+	      break;
+	    case A_DBR:
+	      fprintf_fn (stream, "dbr");
+	      break;
+	    case F_REG_N:
+	      fprintf_fn (stream, "fr%d", rn);
+	      break;
+	    case F_REG_M:
+	      fprintf_fn (stream, "fr%d", rm);
+	      break;
+	    case DX_REG_N:
+	      if (rn & 1)
+		{
+		  fprintf_fn (stream, "xd%d", rn & ~1);
+		  break;
+		}
+	    case D_REG_N:
+	      fprintf_fn (stream, "dr%d", rn);
+	      break;
+	    case DX_REG_M:
+	      if (rm & 1)
+		{
+		  fprintf_fn (stream, "xd%d", rm & ~1);
+		  break;
+		}
+	    case D_REG_M:
+	      fprintf_fn (stream, "dr%d", rm);
+	      break;
+	    case FPSCR_M:
+	    case FPSCR_N:
+	      fprintf_fn (stream, "fpscr");
+	      break;
+	    case FPUL_M:
+	    case FPUL_N:
+	      fprintf_fn (stream, "fpul");
+	      break;
+	    case F_FR0:
+	      fprintf_fn (stream, "fr0");
+	      break;
+	    case V_REG_N:
+	      fprintf_fn (stream, "fv%d", rn * 4);
+	      break;
+	    case V_REG_M:
+	      fprintf_fn (stream, "fv%d", rm * 4);
+	      break;
+	    case XMTRX_M4:
+	      fprintf_fn (stream, "xmtrx");
+	      break;
+	    default:
+	      abort ();
+	    }
+	}
+
+#if 0
+      /* This code prints instructions in delay slots on the same line
+         as the instruction which needs the delay slots.  This can be
+         confusing, since other disassembler don't work this way, and
+         it means that the instructions are not all in a line.  So I
+         disabled it.  Ian.  */
+      if (!(info->flags & 1)
+	  && (op->name[0] == 'j'
+	      || (op->name[0] == 'b'
+		  && (op->name[1] == 'r'
+		      || op->name[1] == 's'))
+	      || (op->name[0] == 'r' && op->name[1] == 't')
+	      || (op->name[0] == 'b' && op->name[2] == '.')))
+	{
+	  info->flags |= 1;
+	  fprintf_fn (stream, "\t(slot ");
+	  print_insn_sh (memaddr + 2, info);
+	  info->flags &= ~1;
+	  fprintf_fn (stream, ")");
+	  return 4;
+	}
+#endif
+
+      if (disp_pc && strcmp (op->name, "mova") != 0)
+	{
+	  int size;
+	  bfd_byte bytes[4];
+
+	  if (relmask == ~(bfd_vma) 1)
+	    size = 2;
+	  else
+	    size = 4;
+	  status = info->read_memory_func (disp_pc_addr, bytes, size, info);
+	  if (status == 0)
+	    {
+	      unsigned int val;
+
+	      if (size == 2)
+		{
+		  if (info->endian == BFD_ENDIAN_LITTLE)
+		    val = bfd_getl16 (bytes);
+		  else
+		    val = bfd_getb16 (bytes);
+		}
+	      else
+		{
+		  if (info->endian == BFD_ENDIAN_LITTLE)
+		    val = bfd_getl32 (bytes);
+		  else
+		    val = bfd_getb32 (bytes);
+		}
+	      if ((*info->symbol_at_address_func) (val, info))
+		{
+		  fprintf_fn (stream, "\t! ");
+		  (*info->print_address_func) (val, info);
+		}
+	      else
+		fprintf_fn (stream, "\t! 0x%x", val);
+	    }
+	}
+
+      return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2;
+    fail:
+      ;
+
+    }
+  fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
+  return 2;
+}
diff --git a/qemu-0.15.x/simpletrace.c b/qemu-0.15.x/simpletrace.c
new file mode 100644
index 0000000..de355e9
--- /dev/null
+++ b/qemu-0.15.x/simpletrace.c
@@ -0,0 +1,355 @@
+/*
+ * Simple trace backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+#include "qemu-timer.h"
+#include "trace.h"
+
+/** Trace file header event ID */
+#define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
+
+/** Trace file magic number */
+#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
+
+/** Trace file version number, bump if format changes */
+#define HEADER_VERSION 0
+
+/** Records were dropped event ID */
+#define DROPPED_EVENT_ID (~(uint64_t)0 - 1)
+
+/** Trace record is valid */
+#define TRACE_RECORD_VALID ((uint64_t)1 << 63)
+
+/** Trace buffer entry */
+typedef struct {
+    uint64_t event;
+    uint64_t timestamp_ns;
+    uint64_t x1;
+    uint64_t x2;
+    uint64_t x3;
+    uint64_t x4;
+    uint64_t x5;
+    uint64_t x6;
+} TraceRecord;
+
+enum {
+    TRACE_BUF_LEN = 4096,
+    TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
+};
+
+/*
+ * Trace records are written out by a dedicated thread.  The thread waits for
+ * records to become available, writes them out, and then waits again.
+ */
+static pthread_mutex_t trace_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t trace_available_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t trace_empty_cond = PTHREAD_COND_INITIALIZER;
+static bool trace_available;
+static bool trace_writeout_enabled;
+
+static TraceRecord trace_buf[TRACE_BUF_LEN];
+static unsigned int trace_idx;
+static FILE *trace_fp;
+static char *trace_file_name = NULL;
+
+/**
+ * Read a trace record from the trace buffer
+ *
+ * @idx         Trace buffer index
+ * @record      Trace record to fill
+ *
+ * Returns false if the record is not valid.
+ */
+static bool get_trace_record(unsigned int idx, TraceRecord *record)
+{
+    if (!(trace_buf[idx].event & TRACE_RECORD_VALID)) {
+        return false;
+    }
+
+    __sync_synchronize(); /* read memory barrier before accessing record */
+
+    *record = trace_buf[idx];
+    record->event &= ~TRACE_RECORD_VALID;
+    return true;
+}
+
+/**
+ * Kick writeout thread
+ *
+ * @wait        Whether to wait for writeout thread to complete
+ */
+static void flush_trace_file(bool wait)
+{
+    pthread_mutex_lock(&trace_lock);
+    trace_available = true;
+    pthread_cond_signal(&trace_available_cond);
+
+    if (wait) {
+        pthread_cond_wait(&trace_empty_cond, &trace_lock);
+    }
+
+    pthread_mutex_unlock(&trace_lock);
+}
+
+static void wait_for_trace_records_available(void)
+{
+    pthread_mutex_lock(&trace_lock);
+    while (!(trace_available && trace_writeout_enabled)) {
+        pthread_cond_signal(&trace_empty_cond);
+        pthread_cond_wait(&trace_available_cond, &trace_lock);
+    }
+    trace_available = false;
+    pthread_mutex_unlock(&trace_lock);
+}
+
+static void *writeout_thread(void *opaque)
+{
+    TraceRecord record;
+    unsigned int writeout_idx = 0;
+    unsigned int num_available, idx;
+    size_t unused __attribute__ ((unused));
+
+    for (;;) {
+        wait_for_trace_records_available();
+
+        num_available = trace_idx - writeout_idx;
+        if (num_available > TRACE_BUF_LEN) {
+            record = (TraceRecord){
+                .event = DROPPED_EVENT_ID,
+                .x1 = num_available,
+            };
+            unused = fwrite(&record, sizeof(record), 1, trace_fp);
+            writeout_idx += num_available;
+        }
+
+        idx = writeout_idx % TRACE_BUF_LEN;
+        while (get_trace_record(idx, &record)) {
+            trace_buf[idx].event = 0; /* clear valid bit */
+            unused = fwrite(&record, sizeof(record), 1, trace_fp);
+            idx = ++writeout_idx % TRACE_BUF_LEN;
+        }
+
+        fflush(trace_fp);
+    }
+    return NULL;
+}
+
+static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
+                  uint64_t x4, uint64_t x5, uint64_t x6)
+{
+    unsigned int idx;
+    uint64_t timestamp;
+
+    if (!trace_list[event].state) {
+        return;
+    }
+
+    timestamp = get_clock();
+
+    idx = __sync_fetch_and_add(&trace_idx, 1) % TRACE_BUF_LEN;
+    trace_buf[idx] = (TraceRecord){
+        .event = event,
+        .timestamp_ns = timestamp,
+        .x1 = x1,
+        .x2 = x2,
+        .x3 = x3,
+        .x4 = x4,
+        .x5 = x5,
+        .x6 = x6,
+    };
+    __sync_synchronize(); /* write barrier before marking as valid */
+    trace_buf[idx].event |= TRACE_RECORD_VALID;
+
+    if ((idx + 1) % TRACE_BUF_FLUSH_THRESHOLD == 0) {
+        flush_trace_file(false);
+    }
+}
+
+void trace0(TraceEventID event)
+{
+    trace(event, 0, 0, 0, 0, 0, 0);
+}
+
+void trace1(TraceEventID event, uint64_t x1)
+{
+    trace(event, x1, 0, 0, 0, 0, 0);
+}
+
+void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
+{
+    trace(event, x1, x2, 0, 0, 0, 0);
+}
+
+void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
+{
+    trace(event, x1, x2, x3, 0, 0, 0);
+}
+
+void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
+{
+    trace(event, x1, x2, x3, x4, 0, 0);
+}
+
+void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
+{
+    trace(event, x1, x2, x3, x4, x5, 0);
+}
+
+void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
+{
+    trace(event, x1, x2, x3, x4, x5, x6);
+}
+
+void st_set_trace_file_enabled(bool enable)
+{
+    if (enable == !!trace_fp) {
+        return; /* no change */
+    }
+
+    /* Halt trace writeout */
+    flush_trace_file(true);
+    trace_writeout_enabled = false;
+    flush_trace_file(true);
+
+    if (enable) {
+        static const TraceRecord header = {
+            .event = HEADER_EVENT_ID,
+            .timestamp_ns = HEADER_MAGIC,
+            .x1 = HEADER_VERSION,
+        };
+
+        trace_fp = fopen(trace_file_name, "w");
+        if (!trace_fp) {
+            return;
+        }
+
+        if (fwrite(&header, sizeof header, 1, trace_fp) != 1) {
+            fclose(trace_fp);
+            trace_fp = NULL;
+            return;
+        }
+
+        /* Resume trace writeout */
+        trace_writeout_enabled = true;
+        flush_trace_file(false);
+    } else {
+        fclose(trace_fp);
+        trace_fp = NULL;
+    }
+}
+
+/**
+ * Set the name of a trace file
+ *
+ * @file        The trace file name or NULL for the default name-<pid> set at
+ *              config time
+ */
+bool st_set_trace_file(const char *file)
+{
+    st_set_trace_file_enabled(false);
+
+    free(trace_file_name);
+
+    if (!file) {
+        if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
+            trace_file_name = NULL;
+            return false;
+        }
+    } else {
+        if (asprintf(&trace_file_name, "%s", file) < 0) {
+            trace_file_name = NULL;
+            return false;
+        }
+    }
+
+    st_set_trace_file_enabled(true);
+    return true;
+}
+
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    stream_printf(stream, "Trace file \"%s\" %s.\n",
+                  trace_file_name, trace_fp ? "on" : "off");
+}
+
+void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    unsigned int i;
+
+    for (i = 0; i < TRACE_BUF_LEN; i++) {
+        TraceRecord record;
+
+        if (!get_trace_record(i, &record)) {
+            continue;
+        }
+        stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
+                      " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
+                      record.event, record.x1, record.x2,
+                      record.x3, record.x4, record.x5,
+                      record.x6);
+    }
+}
+
+void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    unsigned int i;
+
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        stream_printf(stream, "%s [Event ID %u] : state %u\n",
+                      trace_list[i].tp_name, i, trace_list[i].state);
+    }
+}
+
+bool st_change_trace_event_state(const char *name, bool enabled)
+{
+    unsigned int i;
+
+    for (i = 0; i < NR_TRACE_EVENTS; i++) {
+        if (!strcmp(trace_list[i].tp_name, name)) {
+            trace_list[i].state = enabled;
+            return true;
+        }
+    }
+    return false;
+}
+
+void st_flush_trace_buffer(void)
+{
+    flush_trace_file(true);
+}
+
+bool st_init(const char *file)
+{
+    pthread_t thread;
+    pthread_attr_t attr;
+    sigset_t set, oldset;
+    int ret;
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    sigfillset(&set);
+    pthread_sigmask(SIG_SETMASK, &set, &oldset);
+    ret = pthread_create(&thread, &attr, writeout_thread, NULL);
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+
+    if (ret != 0) {
+        return false;
+    }
+
+    atexit(st_flush_trace_buffer);
+    st_set_trace_file(file);
+    return true;
+}
diff --git a/qemu-0.15.x/simpletrace.h b/qemu-0.15.x/simpletrace.h
new file mode 100644
index 0000000..8d893bd
--- /dev/null
+++ b/qemu-0.15.x/simpletrace.h
@@ -0,0 +1,48 @@
+/*
+ * Simple trace backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef SIMPLETRACE_H
+#define SIMPLETRACE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#ifdef CONFIG_SIMPLE_TRACE
+typedef uint64_t TraceEventID;
+
+typedef struct {
+    const char *tp_name;
+    bool state;
+} TraceEvent;
+
+void trace0(TraceEventID event);
+void trace1(TraceEventID event, uint64_t x1);
+void trace2(TraceEventID event, uint64_t x1, uint64_t x2);
+void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
+void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
+void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
+void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
+void st_print_trace(FILE *stream, fprintf_function stream_printf);
+void st_print_trace_events(FILE *stream, fprintf_function stream_printf);
+bool st_change_trace_event_state(const char *tname, bool tstate);
+void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
+void st_set_trace_file_enabled(bool enable);
+bool st_set_trace_file(const char *file);
+void st_flush_trace_buffer(void);
+bool st_init(const char *file);
+#else
+static inline bool st_init(const char *file)
+{
+    return true;
+}
+#endif /* !CONFIG_SIMPLE_TRACE */
+
+#endif /* SIMPLETRACE_H */
diff --git a/qemu-0.15.x/slirp/COPYRIGHT b/qemu-0.15.x/slirp/COPYRIGHT
new file mode 100644
index 0000000..1bc83d4
--- /dev/null
+++ b/qemu-0.15.x/slirp/COPYRIGHT
@@ -0,0 +1,61 @@
+Slirp was written by Danny Gasparovski.
+Copyright (c), 1995,1996 All Rights Reserved.
+
+Slirp is maintained by Kelly Price <tygris+slirp at erols.com>
+
+Slirp is free software; "free" as in you don't have to pay for it, and you
+are free to do whatever you want with it.  I do not accept any donations,
+monetary or otherwise, for Slirp.  Instead, I would ask you to pass this
+potential donation to your favorite charity.  In fact, I encourage
+*everyone* who finds Slirp useful to make a small donation to their
+favorite charity (for example, GreenPeace).  This is not a requirement, but
+a suggestion from someone who highly values the service they provide.
+
+The copyright terms and conditions:
+
+---BEGIN---
+
+ Copyright (c) 1995,1996 Danny Gasparovski.  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 ``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
+ DANNY GASPAROVSKI 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.
+
+---END---
+
+This basically means you can do anything you want with the software, except
+1) call it your own, and 2) claim warranty on it.  There is no warranty for
+this software.  None.  Nada.  If you lose a million dollars while using
+Slirp, that's your loss not mine.  So, ***USE AT YOUR OWN RISK!***.
+
+If these conditions cannot be met due to legal restrictions (E.g. where it
+is against the law to give out Software without warranty), you must cease
+using the software and delete all copies you have.
+
+Slirp uses code that is copyrighted by the following people/organizations:
+
+Juha Pirkola.
+Gregory M. Christy.
+The Regents of the University of California.
+Carnegie Mellon University.
+The Australian National University.
+RSA Data Security, Inc.
+
+Please read the top of each source file for the details on the various
+copyrights.
diff --git a/qemu-0.15.x/slirp/bootp.c b/qemu-0.15.x/slirp/bootp.c
new file mode 100644
index 0000000..1eb2ed1
--- /dev/null
+++ b/qemu-0.15.x/slirp/bootp.c
@@ -0,0 +1,314 @@
+/*
+ * QEMU BOOTP/DHCP server
+ *
+ * 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 <slirp.h>
+
+/* XXX: only DHCP is supported */
+
+#define LEASE_TIME (24 * 3600)
+
+static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) \
+do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); } while (0)
+#else
+#define DPRINTF(fmt, ...) do{}while(0)
+#endif
+
+static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        bc = &slirp->bootp_clients[i];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &slirp->bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
+    return bc;
+}
+
+static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    uint32_t req_addr = ntohl(paddr->s_addr);
+    uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
+    BOOTPClient *bc;
+
+    if (req_addr >= dhcp_addr &&
+        req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
+        bc = &slirp->bootp_clients[req_addr - dhcp_addr];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
+            bc->allocated = 1;
+            return bc;
+        }
+    }
+    return NULL;
+}
+
+static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
+                              const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &slirp->bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
+    return bc;
+}
+
+static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+                        struct in_addr *preq_addr)
+{
+    const uint8_t *p, *p_end;
+    int len, tag;
+
+    *pmsg_type = 0;
+    preq_addr->s_addr = htonl(0L);
+
+    p = bp->bp_vend;
+    p_end = p + DHCP_OPT_LEN;
+    if (memcmp(p, rfc1533_cookie, 4) != 0)
+        return;
+    p += 4;
+    while (p < p_end) {
+        tag = p[0];
+        if (tag == RFC1533_PAD) {
+            p++;
+        } else if (tag == RFC1533_END) {
+            break;
+        } else {
+            p++;
+            if (p >= p_end)
+                break;
+            len = *p++;
+            DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
+
+            switch(tag) {
+            case RFC2132_MSG_TYPE:
+                if (len >= 1)
+                    *pmsg_type = p[0];
+                break;
+            case RFC2132_REQ_ADDR:
+                if (len >= 4) {
+                    memcpy(&(preq_addr->s_addr), p, 4);
+                }
+                break;
+            default:
+                break;
+            }
+            p += len;
+        }
+    }
+    if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
+        bp->bp_ciaddr.s_addr) {
+        memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
+    }
+}
+
+static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+{
+    BOOTPClient *bc = NULL;
+    struct mbuf *m;
+    struct bootp_t *rbp;
+    struct sockaddr_in saddr, daddr;
+    struct in_addr preq_addr;
+    int dhcp_msg_type, val;
+    uint8_t *q;
+
+    /* extract exact DHCP msg type */
+    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
+    DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+    if (preq_addr.s_addr != htonl(0L))
+        DPRINTF(" req_addr=%08x\n", ntohl(preq_addr.s_addr));
+    else
+        DPRINTF("\n");
+
+    if (dhcp_msg_type == 0)
+        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
+
+    if (dhcp_msg_type != DHCPDISCOVER &&
+        dhcp_msg_type != DHCPREQUEST)
+        return;
+    /* XXX: this is a hack to get the client mac address */
+    memcpy(slirp->client_ethaddr, bp->bp_hwaddr, 6);
+
+    m = m_get(slirp);
+    if (!m) {
+        return;
+    }
+    m->m_data += IF_MAXLINKHDR;
+    rbp = (struct bootp_t *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+    memset(rbp, 0, sizeof(struct bootp_t));
+
+    if (dhcp_msg_type == DHCPDISCOVER) {
+        if (preq_addr.s_addr != htonl(0L)) {
+            bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+            if (bc) {
+                daddr.sin_addr = preq_addr;
+            }
+        }
+        if (!bc) {
+         new_addr:
+            bc = get_new_addr(slirp, &daddr.sin_addr, slirp->client_ethaddr);
+            if (!bc) {
+                DPRINTF("no address left\n");
+                return;
+            }
+        }
+        memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+    } else if (preq_addr.s_addr != htonl(0L)) {
+        bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+        if (bc) {
+            daddr.sin_addr = preq_addr;
+            memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+        } else {
+            daddr.sin_addr.s_addr = 0;
+        }
+    } else {
+        bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
+        if (!bc) {
+            /* if never assigned, behaves as if it was already
+               assigned (windows fix because it remembers its address) */
+            goto new_addr;
+        }
+    }
+
+    saddr.sin_addr = slirp->vhost_addr;
+    saddr.sin_port = htons(BOOTP_SERVER);
+
+    daddr.sin_port = htons(BOOTP_CLIENT);
+
+    rbp->bp_op = BOOTP_REPLY;
+    rbp->bp_xid = bp->bp_xid;
+    rbp->bp_htype = 1;
+    rbp->bp_hlen = 6;
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+
+    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+
+    q = rbp->bp_vend;
+    memcpy(q, rfc1533_cookie, 4);
+    q += 4;
+
+    if (bc) {
+        DPRINTF("%s addr=%08x\n",
+                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
+                ntohl(daddr.sin_addr.s_addr));
+
+        if (dhcp_msg_type == DHCPDISCOVER) {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPOFFER;
+        } else /* DHCPREQUEST */ {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPACK;
+        }
+
+        if (slirp->bootp_filename)
+            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
+                     slirp->bootp_filename);
+
+        *q++ = RFC2132_SRV_ID;
+        *q++ = 4;
+        memcpy(q, &saddr.sin_addr, 4);
+        q += 4;
+
+        *q++ = RFC1533_NETMASK;
+        *q++ = 4;
+        memcpy(q, &slirp->vnetwork_mask, 4);
+        q += 4;
+
+        if (!slirp->restricted) {
+            *q++ = RFC1533_GATEWAY;
+            *q++ = 4;
+            memcpy(q, &saddr.sin_addr, 4);
+            q += 4;
+
+            *q++ = RFC1533_DNS;
+            *q++ = 4;
+            memcpy(q, &slirp->vnameserver_addr, 4);
+            q += 4;
+        }
+
+        *q++ = RFC2132_LEASE_TIME;
+        *q++ = 4;
+        val = htonl(LEASE_TIME);
+        memcpy(q, &val, 4);
+        q += 4;
+
+        if (*slirp->client_hostname) {
+            val = strlen(slirp->client_hostname);
+            *q++ = RFC1533_HOSTNAME;
+            *q++ = val;
+            memcpy(q, slirp->client_hostname, val);
+            q += val;
+        }
+    } else {
+        static const char nak_msg[] = "requested address not available";
+
+        DPRINTF("nak'ed addr=%08x\n", ntohl(preq_addr.s_addr));
+
+        *q++ = RFC2132_MSG_TYPE;
+        *q++ = 1;
+        *q++ = DHCPNAK;
+
+        *q++ = RFC2132_MESSAGE;
+        *q++ = sizeof(nak_msg) - 1;
+        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
+        q += sizeof(nak_msg) - 1;
+    }
+    *q = RFC1533_END;
+
+    daddr.sin_addr.s_addr = 0xffffffffu;
+
+    m->m_len = sizeof(struct bootp_t) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+}
+
+void bootp_input(struct mbuf *m)
+{
+    struct bootp_t *bp = mtod(m, struct bootp_t *);
+
+    if (bp->bp_op == BOOTP_REQUEST) {
+        bootp_reply(m->slirp, bp);
+    }
+}
diff --git a/qemu-0.15.x/slirp/bootp.h b/qemu-0.15.x/slirp/bootp.h
new file mode 100644
index 0000000..30c30ab
--- /dev/null
+++ b/qemu-0.15.x/slirp/bootp.h
@@ -0,0 +1,122 @@
+/* bootp/dhcp defines */
+
+#define BOOTP_SERVER	67
+#define BOOTP_CLIENT	68
+
+#define BOOTP_REQUEST	1
+#define BOOTP_REPLY	2
+
+#define RFC1533_COOKIE		99, 130, 83, 99
+#define RFC1533_PAD		0
+#define RFC1533_NETMASK		1
+#define RFC1533_TIMEOFFSET	2
+#define RFC1533_GATEWAY		3
+#define RFC1533_TIMESERVER	4
+#define RFC1533_IEN116NS	5
+#define RFC1533_DNS		6
+#define RFC1533_LOGSERVER	7
+#define RFC1533_COOKIESERVER	8
+#define RFC1533_LPRSERVER	9
+#define RFC1533_IMPRESSSERVER	10
+#define RFC1533_RESOURCESERVER	11
+#define RFC1533_HOSTNAME	12
+#define RFC1533_BOOTFILESIZE	13
+#define RFC1533_MERITDUMPFILE	14
+#define RFC1533_DOMAINNAME	15
+#define RFC1533_SWAPSERVER	16
+#define RFC1533_ROOTPATH	17
+#define RFC1533_EXTENSIONPATH	18
+#define RFC1533_IPFORWARDING	19
+#define RFC1533_IPSOURCEROUTING	20
+#define RFC1533_IPPOLICYFILTER	21
+#define RFC1533_IPMAXREASSEMBLY	22
+#define RFC1533_IPTTL		23
+#define RFC1533_IPMTU		24
+#define RFC1533_IPMTUPLATEAU	25
+#define RFC1533_INTMTU		26
+#define RFC1533_INTLOCALSUBNETS	27
+#define RFC1533_INTBROADCAST	28
+#define RFC1533_INTICMPDISCOVER	29
+#define RFC1533_INTICMPRESPOND	30
+#define RFC1533_INTROUTEDISCOVER 31
+#define RFC1533_INTROUTESOLICIT	32
+#define RFC1533_INTSTATICROUTES	33
+#define RFC1533_LLTRAILERENCAP	34
+#define RFC1533_LLARPCACHETMO	35
+#define RFC1533_LLETHERNETENCAP	36
+#define RFC1533_TCPTTL		37
+#define RFC1533_TCPKEEPALIVETMO	38
+#define RFC1533_TCPKEEPALIVEGB	39
+#define RFC1533_NISDOMAIN	40
+#define RFC1533_NISSERVER	41
+#define RFC1533_NTPSERVER	42
+#define RFC1533_VENDOR		43
+#define RFC1533_NBNS		44
+#define RFC1533_NBDD		45
+#define RFC1533_NBNT		46
+#define RFC1533_NBSCOPE		47
+#define RFC1533_XFS		48
+#define RFC1533_XDM		49
+
+#define RFC2132_REQ_ADDR	50
+#define RFC2132_LEASE_TIME      51
+#define RFC2132_MSG_TYPE	53
+#define RFC2132_SRV_ID		54
+#define RFC2132_PARAM_LIST	55
+#define RFC2132_MESSAGE		56
+#define RFC2132_MAX_SIZE	57
+#define RFC2132_RENEWAL_TIME    58
+#define RFC2132_REBIND_TIME     59
+
+#define DHCPDISCOVER		1
+#define DHCPOFFER		2
+#define DHCPREQUEST		3
+#define DHCPACK			5
+#define DHCPNAK			6
+
+#define RFC1533_VENDOR_MAJOR	0
+#define RFC1533_VENDOR_MINOR	0
+
+#define RFC1533_VENDOR_MAGIC	128
+#define RFC1533_VENDOR_ADDPARM	129
+#define	RFC1533_VENDOR_ETHDEV	130
+#define RFC1533_VENDOR_HOWTO    132
+#define RFC1533_VENDOR_MNUOPTS	160
+#define RFC1533_VENDOR_SELECTION 176
+#define RFC1533_VENDOR_MOTD	184
+#define RFC1533_VENDOR_NUMOFMOTD 8
+#define RFC1533_VENDOR_IMG	192
+#define RFC1533_VENDOR_NUMOFIMG	16
+
+#define RFC1533_END		255
+#define BOOTP_VENDOR_LEN	64
+#define DHCP_OPT_LEN		312
+
+struct bootp_t {
+    struct ip ip;
+    struct udphdr udp;
+    uint8_t bp_op;
+    uint8_t bp_htype;
+    uint8_t bp_hlen;
+    uint8_t bp_hops;
+    uint32_t bp_xid;
+    uint16_t bp_secs;
+    uint16_t unused;
+    struct in_addr bp_ciaddr;
+    struct in_addr bp_yiaddr;
+    struct in_addr bp_siaddr;
+    struct in_addr bp_giaddr;
+    uint8_t bp_hwaddr[16];
+    uint8_t bp_sname[64];
+    uint8_t bp_file[128];
+    uint8_t bp_vend[DHCP_OPT_LEN];
+};
+
+typedef struct {
+    uint16_t allocated;
+    uint8_t macaddr[6];
+} BOOTPClient;
+
+#define NB_BOOTP_CLIENTS 16
+
+void bootp_input(struct mbuf *m);
diff --git a/qemu-0.15.x/slirp/cksum.c b/qemu-0.15.x/slirp/cksum.c
new file mode 100644
index 0000000..e43867d
--- /dev/null
+++ b/qemu-0.15.x/slirp/cksum.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1988, 1992, 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. 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.
+ *
+ *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
+ * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
+ */
+
+#include <slirp.h>
+
+/*
+ * Checksum routine for Internet Protocol family headers (Portable Version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * XXX Since we will never span more than 1 mbuf, we can optimise this
+ */
+
+#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1];        \
+        (void)ADDCARRY(sum);}
+
+int cksum(struct mbuf *m, int len)
+{
+	register uint16_t *w;
+	register int sum = 0;
+	register int mlen = 0;
+	int byte_swapped = 0;
+
+	union {
+		uint8_t  c[2];
+		uint16_t s;
+	} s_util;
+	union {
+		uint16_t s[2];
+		uint32_t l;
+	} l_util;
+
+	if (m->m_len == 0)
+	   goto cont;
+	w = mtod(m, uint16_t *);
+
+	mlen = m->m_len;
+
+	if (len < mlen)
+	   mlen = len;
+#ifdef DEBUG
+	len -= mlen;
+#endif
+	/*
+	 * Force to even boundary.
+	 */
+	if ((1 & (long) w) && (mlen > 0)) {
+		REDUCE;
+		sum <<= 8;
+		s_util.c[0] = *(uint8_t *)w;
+		w = (uint16_t *)((int8_t *)w + 1);
+		mlen--;
+		byte_swapped = 1;
+	}
+	/*
+	 * Unroll the loop to make overhead from
+	 * branches &c small.
+	 */
+	while ((mlen -= 32) >= 0) {
+		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+		sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+		sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
+		sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
+		w += 16;
+	}
+	mlen += 32;
+	while ((mlen -= 8) >= 0) {
+		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+		w += 4;
+	}
+	mlen += 8;
+	if (mlen == 0 && byte_swapped == 0)
+	   goto cont;
+	REDUCE;
+	while ((mlen -= 2) >= 0) {
+		sum += *w++;
+	}
+
+	if (byte_swapped) {
+		REDUCE;
+		sum <<= 8;
+		if (mlen == -1) {
+			s_util.c[1] = *(uint8_t *)w;
+			sum += s_util.s;
+			mlen = 0;
+		} else
+
+		   mlen = -1;
+	} else if (mlen == -1)
+	   s_util.c[0] = *(uint8_t *)w;
+
+cont:
+#ifdef DEBUG
+	if (len) {
+		DEBUG_ERROR((dfd, "cksum: out of data\n"));
+		DEBUG_ERROR((dfd, " len = %d\n", len));
+	}
+#endif
+	if (mlen == -1) {
+		/* The last mbuf has odd # of bytes. Follow the
+		 standard (the odd byte may be shifted left by 8 bits
+			   or not as determined by endian-ness of the machine) */
+		s_util.c[1] = 0;
+		sum += s_util.s;
+	}
+	REDUCE;
+	return (~sum & 0xffff);
+}
diff --git a/qemu-0.15.x/slirp/debug.h b/qemu-0.15.x/slirp/debug.h
new file mode 100644
index 0000000..6cfa61e
--- /dev/null
+++ b/qemu-0.15.x/slirp/debug.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+
+#define DBG_CALL 0x1
+#define DBG_MISC 0x2
+#define DBG_ERROR 0x4
+
+#define dfd stderr
+
+extern int slirp_debug;
+
+#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); }
+#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); }
+#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); }
+#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); }
+#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); }
+
+#else
+
+#define DEBUG_CALL(x)
+#define DEBUG_ARG(x, y)
+#define DEBUG_ARGS(x)
+#define DEBUG_MISC(x)
+#define DEBUG_ERROR(x)
+
+#endif
diff --git a/qemu-0.15.x/slirp/if.c b/qemu-0.15.x/slirp/if.c
new file mode 100644
index 0000000..0f04e13
--- /dev/null
+++ b/qemu-0.15.x/slirp/if.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
+
+static void
+ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
+{
+	ifm->ifs_next = ifmhead->ifs_next;
+	ifmhead->ifs_next = ifm;
+	ifm->ifs_prev = ifmhead;
+	ifm->ifs_next->ifs_prev = ifm;
+}
+
+static void
+ifs_remque(struct mbuf *ifm)
+{
+	ifm->ifs_prev->ifs_next = ifm->ifs_next;
+	ifm->ifs_next->ifs_prev = ifm->ifs_prev;
+}
+
+void
+if_init(Slirp *slirp)
+{
+    slirp->if_fastq.ifq_next = slirp->if_fastq.ifq_prev = &slirp->if_fastq;
+    slirp->if_batchq.ifq_next = slirp->if_batchq.ifq_prev = &slirp->if_batchq;
+    slirp->next_m = &slirp->if_batchq;
+}
+
+/*
+ * if_output: Queue packet into an output queue.
+ * There are 2 output queue's, if_fastq and if_batchq.
+ * Each output queue is a doubly linked list of double linked lists
+ * of mbufs, each list belonging to one "session" (socket).  This
+ * way, we can output packets fairly by sending one packet from each
+ * session, instead of all the packets from one session, then all packets
+ * from the next session, etc.  Packets on the if_fastq get absolute
+ * priority, but if one session hogs the link, it gets "downgraded"
+ * to the batchq until it runs out of packets, then it'll return
+ * to the fastq (eg. if the user does an ls -alR in a telnet session,
+ * it'll temporarily get downgraded to the batchq)
+ */
+void
+if_output(struct socket *so, struct mbuf *ifm)
+{
+	Slirp *slirp = ifm->slirp;
+	struct mbuf *ifq;
+	int on_fastq = 1;
+
+	DEBUG_CALL("if_output");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("ifm = %lx", (long)ifm);
+
+	/*
+	 * First remove the mbuf from m_usedlist,
+	 * since we're gonna use m_next and m_prev ourselves
+	 * XXX Shouldn't need this, gotta change dtom() etc.
+	 */
+	if (ifm->m_flags & M_USEDLIST) {
+		remque(ifm);
+		ifm->m_flags &= ~M_USEDLIST;
+	}
+
+	/*
+	 * See if there's already a batchq list for this session.
+	 * This can include an interactive session, which should go on fastq,
+	 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
+	 * We mustn't put this packet back on the fastq (or we'll send it out of order)
+	 * XXX add cache here?
+	 */
+	for (ifq = slirp->if_batchq.ifq_prev; ifq != &slirp->if_batchq;
+	     ifq = ifq->ifq_prev) {
+		if (so == ifq->ifq_so) {
+			/* A match! */
+			ifm->ifq_so = so;
+			ifs_insque(ifm, ifq->ifs_prev);
+			goto diddit;
+		}
+	}
+
+	/* No match, check which queue to put it on */
+	if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
+		ifq = slirp->if_fastq.ifq_prev;
+		on_fastq = 1;
+		/*
+		 * Check if this packet is a part of the last
+		 * packet's session
+		 */
+		if (ifq->ifq_so == so) {
+			ifm->ifq_so = so;
+			ifs_insque(ifm, ifq->ifs_prev);
+			goto diddit;
+		}
+	} else
+		ifq = slirp->if_batchq.ifq_prev;
+
+	/* Create a new doubly linked list for this session */
+	ifm->ifq_so = so;
+	ifs_init(ifm);
+	insque(ifm, ifq);
+
+diddit:
+	slirp->if_queued++;
+
+	if (so) {
+		/* Update *_queued */
+		so->so_queued++;
+		so->so_nqueued++;
+		/*
+		 * Check if the interactive session should be downgraded to
+		 * the batchq.  A session is downgraded if it has queued 6
+		 * packets without pausing, and at least 3 of those packets
+		 * have been sent over the link
+		 * (XXX These are arbitrary numbers, probably not optimal..)
+		 */
+		if (on_fastq && ((so->so_nqueued >= 6) &&
+				 (so->so_nqueued - so->so_queued) >= 3)) {
+
+			/* Remove from current queue... */
+			remque(ifm->ifs_next);
+
+			/* ...And insert in the new.  That'll teach ya! */
+			insque(ifm->ifs_next, &slirp->if_batchq);
+		}
+	}
+
+#ifndef FULL_BOLT
+	/*
+	 * This prevents us from malloc()ing too many mbufs
+	 */
+	if_start(ifm->slirp);
+#endif
+}
+
+/*
+ * Send a packet
+ * We choose a packet based on it's position in the output queues;
+ * If there are packets on the fastq, they are sent FIFO, before
+ * everything else.  Otherwise we choose the first packet from the
+ * batchq and send it.  the next packet chosen will be from the session
+ * after this one, then the session after that one, and so on..  So,
+ * for example, if there are 3 ftp session's fighting for bandwidth,
+ * one packet will be sent from the first session, then one packet
+ * from the second session, then one packet from the third, then back
+ * to the first, etc. etc.
+ */
+void
+if_start(Slirp *slirp)
+{
+	struct mbuf *ifm, *ifqt;
+
+	DEBUG_CALL("if_start");
+
+	if (slirp->if_queued == 0)
+	   return; /* Nothing to do */
+
+ again:
+        /* check if we can really output */
+        if (!slirp_can_output(slirp->opaque))
+            return;
+
+	/*
+	 * See which queue to get next packet from
+	 * If there's something in the fastq, select it immediately
+	 */
+	if (slirp->if_fastq.ifq_next != &slirp->if_fastq) {
+		ifm = slirp->if_fastq.ifq_next;
+	} else {
+		/* Nothing on fastq, see if next_m is valid */
+		if (slirp->next_m != &slirp->if_batchq)
+		   ifm = slirp->next_m;
+		else
+		   ifm = slirp->if_batchq.ifq_next;
+
+		/* Set which packet to send on next iteration */
+		slirp->next_m = ifm->ifq_next;
+	}
+	/* Remove it from the queue */
+	ifqt = ifm->ifq_prev;
+	remque(ifm);
+	slirp->if_queued--;
+
+	/* If there are more packets for this session, re-queue them */
+	if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
+		insque(ifm->ifs_next, ifqt);
+		ifs_remque(ifm);
+	}
+
+	/* Update so_queued */
+	if (ifm->ifq_so) {
+		if (--ifm->ifq_so->so_queued == 0)
+		   /* If there's no more queued, reset nqueued */
+		   ifm->ifq_so->so_nqueued = 0;
+	}
+
+	/* Encapsulate the packet for sending */
+        if_encap(slirp, (uint8_t *)ifm->m_data, ifm->m_len);
+
+        m_free(ifm);
+
+	if (slirp->if_queued)
+	   goto again;
+}
diff --git a/qemu-0.15.x/slirp/if.h b/qemu-0.15.x/slirp/if.h
new file mode 100644
index 0000000..2dac1c7
--- /dev/null
+++ b/qemu-0.15.x/slirp/if.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _IF_H_
+#define _IF_H_
+
+#define IF_COMPRESS	0x01	/* We want compression */
+#define IF_NOCOMPRESS	0x02	/* Do not do compression */
+#define IF_AUTOCOMP	0x04	/* Autodetect (default) */
+#define IF_NOCIDCOMP	0x08	/* CID compression */
+
+#define IF_MTU 1500
+#define IF_MRU 1500
+#define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
+
+/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
+#define IF_MAXLINKHDR (2 + 14 + 40)
+
+#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
+
+#endif
diff --git a/qemu-0.15.x/slirp/ip.h b/qemu-0.15.x/slirp/ip.h
new file mode 100644
index 0000000..48ea38e
--- /dev/null
+++ b/qemu-0.15.x/slirp/ip.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)ip.h	8.1 (Berkeley) 6/10/93
+ * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
+ */
+
+#ifndef _IP_H_
+#define _IP_H_
+
+#ifdef HOST_WORDS_BIGENDIAN
+# ifndef NTOHL
+#  define NTOHL(d)
+# endif
+# ifndef NTOHS
+#  define NTOHS(d)
+# endif
+# ifndef HTONL
+#  define HTONL(d)
+# endif
+# ifndef HTONS
+#  define HTONS(d)
+# endif
+#else
+# ifndef NTOHL
+#  define NTOHL(d) ((d) = ntohl((d)))
+# endif
+# ifndef NTOHS
+#  define NTOHS(d) ((d) = ntohs((uint16_t)(d)))
+# endif
+# ifndef HTONL
+#  define HTONL(d) ((d) = htonl((d)))
+# endif
+# ifndef HTONS
+#  define HTONS(d) ((d) = htons((uint16_t)(d)))
+# endif
+#endif
+
+typedef uint32_t n_long;                 /* long as received from the net */
+
+/*
+ * Definitions for internet protocol version 4.
+ * Per RFC 791, September 1981.
+ */
+#define	IPVERSION	4
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip {
+#ifdef HOST_WORDS_BIGENDIAN
+	u_int ip_v:4,			/* version */
+		ip_hl:4;		/* header length */
+#else
+	u_int ip_hl:4,		/* header length */
+		ip_v:4;			/* version */
+#endif
+	uint8_t		ip_tos;			/* type of service */
+	uint16_t	ip_len;			/* total length */
+	uint16_t	ip_id;			/* identification */
+	uint16_t	ip_off;			/* fragment offset field */
+#define	IP_DF 0x4000			/* don't fragment flag */
+#define	IP_MF 0x2000			/* more fragments flag */
+#define	IP_OFFMASK 0x1fff		/* mask for fragmenting bits */
+	uint8_t ip_ttl;			/* time to live */
+	uint8_t ip_p;			/* protocol */
+	uint16_t	ip_sum;			/* checksum */
+	struct	in_addr ip_src,ip_dst;	/* source and dest address */
+} __attribute__((packed));
+
+#define	IP_MAXPACKET	65535		/* maximum packet size */
+
+/*
+ * Definitions for IP type of service (ip_tos)
+ */
+#define	IPTOS_LOWDELAY		0x10
+#define	IPTOS_THROUGHPUT	0x08
+#define	IPTOS_RELIABILITY	0x04
+
+/*
+ * Definitions for options.
+ */
+#define	IPOPT_COPIED(o)		((o)&0x80)
+#define	IPOPT_CLASS(o)		((o)&0x60)
+#define	IPOPT_NUMBER(o)		((o)&0x1f)
+
+#define	IPOPT_CONTROL		0x00
+#define	IPOPT_RESERVED1		0x20
+#define	IPOPT_DEBMEAS		0x40
+#define	IPOPT_RESERVED2		0x60
+
+#define	IPOPT_EOL		0		/* end of option list */
+#define	IPOPT_NOP		1		/* no operation */
+
+#define	IPOPT_RR		7		/* record packet route */
+#define	IPOPT_TS		68		/* timestamp */
+#define	IPOPT_SECURITY		130		/* provide s,c,h,tcc */
+#define	IPOPT_LSRR		131		/* loose source route */
+#define	IPOPT_SATID		136		/* satnet id */
+#define	IPOPT_SSRR		137		/* strict source route */
+
+/*
+ * Offsets to fields in options other than EOL and NOP.
+ */
+#define	IPOPT_OPTVAL		0		/* option ID */
+#define	IPOPT_OLEN		1		/* option length */
+#define IPOPT_OFFSET		2		/* offset within option */
+#define	IPOPT_MINOFF		4		/* min value of above */
+
+/*
+ * Time stamp option structure.
+ */
+struct	ip_timestamp {
+	uint8_t	ipt_code;		/* IPOPT_TS */
+	uint8_t	ipt_len;		/* size of structure (variable) */
+	uint8_t	ipt_ptr;		/* index of current entry */
+#ifdef HOST_WORDS_BIGENDIAN
+	u_int	ipt_oflw:4,		/* overflow counter */
+		ipt_flg:4;		/* flags, see below */
+#else
+	u_int	ipt_flg:4,		/* flags, see below */
+		ipt_oflw:4;		/* overflow counter */
+#endif
+	union ipt_timestamp {
+		n_long	ipt_time[1];
+		struct	ipt_ta {
+			struct in_addr ipt_addr;
+			n_long ipt_time;
+		} ipt_ta[1];
+	} ipt_timestamp;
+} __attribute__((packed));
+
+/* flag bits for ipt_flg */
+#define	IPOPT_TS_TSONLY		0		/* timestamps only */
+#define	IPOPT_TS_TSANDADDR	1		/* timestamps and addresses */
+#define	IPOPT_TS_PRESPEC	3		/* specified modules only */
+
+/* bits for security (not byte swapped) */
+#define	IPOPT_SECUR_UNCLASS	0x0000
+#define	IPOPT_SECUR_CONFID	0xf135
+#define	IPOPT_SECUR_EFTO	0x789a
+#define	IPOPT_SECUR_MMMM	0xbc4d
+#define	IPOPT_SECUR_RESTR	0xaf13
+#define	IPOPT_SECUR_SECRET	0xd788
+#define	IPOPT_SECUR_TOPSECRET	0x6bc5
+
+/*
+ * Internet implementation parameters.
+ */
+#define	MAXTTL		255		/* maximum time to live (seconds) */
+#define	IPDEFTTL	64		/* default ttl, from RFC 1340 */
+#define	IPFRAGTTL	60		/* time to live for frags, slowhz */
+#define	IPTTLDEC	1		/* subtracted when forwarding */
+
+#define	IP_MSS		576		/* default maximum segment size */
+
+#if SIZEOF_CHAR_P == 4
+struct mbuf_ptr {
+	struct mbuf *mptr;
+	uint32_t dummy;
+} __attribute__((packed));
+#else
+struct mbuf_ptr {
+	struct mbuf *mptr;
+} __attribute__((packed));
+#endif
+struct qlink {
+	void *next, *prev;
+};
+
+/*
+ * Overlay for ip header used by other protocols (tcp, udp).
+ */
+struct ipovly {
+	struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
+	uint8_t	ih_x1;			/* (unused) */
+	uint8_t	ih_pr;			/* protocol */
+	uint16_t	ih_len;			/* protocol length */
+	struct	in_addr ih_src;		/* source internet address */
+	struct	in_addr ih_dst;		/* destination internet address */
+} __attribute__((packed));
+
+/*
+ * Ip reassembly queue structure.  Each fragment
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+ * size 28 bytes
+ */
+struct ipq {
+        struct qlink frag_link;			/* to ip headers of fragments */
+	struct qlink ip_link;				/* to other reass headers */
+	uint8_t	ipq_ttl;		/* time for reass q to live */
+	uint8_t	ipq_p;			/* protocol of this fragment */
+	uint16_t	ipq_id;			/* sequence id for reassembly */
+	struct	in_addr ipq_src,ipq_dst;
+} __attribute__((packed));
+
+/*
+ * Ip header, when holding a fragment.
+ *
+ * Note: ipf_link must be at same offset as frag_link above
+ */
+struct	ipasfrag {
+	struct qlink ipf_link;
+	struct ip ipf_ip;
+} __attribute__((packed));
+
+#define ipf_off      ipf_ip.ip_off
+#define ipf_tos      ipf_ip.ip_tos
+#define ipf_len      ipf_ip.ip_len
+#define ipf_next     ipf_link.next
+#define ipf_prev     ipf_link.prev
+
+/*
+ * Structure stored in mbuf in inpcb.ip_options
+ * and passed to ip_output when ip options are in use.
+ * The actual length of the options (including ipopt_dst)
+ * is in m_len.
+ */
+#define MAX_IPOPTLEN	40
+
+struct ipoption {
+	struct	in_addr ipopt_dst;	/* first-hop dst if source routed */
+	int8_t	ipopt_list[MAX_IPOPTLEN];	/* options proper */
+} __attribute__((packed));
+
+#endif
diff --git a/qemu-0.15.x/slirp/ip_icmp.c b/qemu-0.15.x/slirp/ip_icmp.c
new file mode 100644
index 0000000..4b43994
--- /dev/null
+++ b/qemu-0.15.x/slirp/ip_icmp.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
+ * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+/* The message sent when emulating PING */
+/* Be nice and tell them it's just a pseudo-ping packet */
+static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
+
+/* list of actions for icmp_error() on RX of an icmp message */
+static const int icmp_flush[19] = {
+/*  ECHO REPLY (0)  */   0,
+		         1,
+		         1,
+/* DEST UNREACH (3) */   1,
+/* SOURCE QUENCH (4)*/   1,
+/* REDIRECT (5) */       1,
+		         1,
+		         1,
+/* ECHO (8) */           0,
+/* ROUTERADVERT (9) */   1,
+/* ROUTERSOLICIT (10) */ 1,
+/* TIME EXCEEDED (11) */ 1,
+/* PARAMETER PROBLEM (12) */ 1,
+/* TIMESTAMP (13) */     0,
+/* TIMESTAMP REPLY (14) */ 0,
+/* INFO (15) */          0,
+/* INFO REPLY (16) */    0,
+/* ADDR MASK (17) */     0,
+/* ADDR MASK REPLY (18) */ 0
+};
+
+void icmp_init(Slirp *slirp)
+{
+    slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
+    slirp->icmp_last_so = &slirp->icmp;
+}
+
+static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
+{
+    struct ip *ip = mtod(m, struct ip *);
+    struct sockaddr_in addr;
+
+    so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (so->s == -1) {
+        return -1;
+    }
+
+    so->so_m = m;
+    so->so_faddr = ip->ip_dst;
+    so->so_laddr = ip->ip_src;
+    so->so_iptos = ip->ip_tos;
+    so->so_type = IPPROTO_ICMP;
+    so->so_state = SS_ISFCONNECTED;
+    so->so_expire = curtime + SO_EXPIRE;
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr = so->so_faddr;
+
+    insque(so, &so->slirp->icmp);
+
+    if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
+               (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
+                    errno, strerror(errno)));
+        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+        icmp_detach(so);
+    }
+
+    return 0;
+}
+
+void icmp_detach(struct socket *so)
+{
+    closesocket(so->s);
+    sofree(so);
+}
+
+/*
+ * Process a received ICMP message.
+ */
+void
+icmp_input(struct mbuf *m, int hlen)
+{
+  register struct icmp *icp;
+  register struct ip *ip=mtod(m, struct ip *);
+  int icmplen=ip->ip_len;
+  Slirp *slirp = m->slirp;
+
+  DEBUG_CALL("icmp_input");
+  DEBUG_ARG("m = %lx", (long )m);
+  DEBUG_ARG("m_len = %d", m->m_len);
+
+  /*
+   * Locate icmp structure in mbuf, and check
+   * that its not corrupted and of at least minimum length.
+   */
+  if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
+  freeit:
+    m_free(m);
+    goto end_error;
+  }
+
+  m->m_len -= hlen;
+  m->m_data += hlen;
+  icp = mtod(m, struct icmp *);
+  if (cksum(m, icmplen)) {
+    goto freeit;
+  }
+  m->m_len += hlen;
+  m->m_data -= hlen;
+
+  DEBUG_ARG("icmp_type = %d", icp->icmp_type);
+  switch (icp->icmp_type) {
+  case ICMP_ECHO:
+    ip->ip_len += hlen;	             /* since ip_input subtracts this */
+    if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
+      icmp_reflect(m);
+    } else if (slirp->restricted) {
+        goto freeit;
+    } else {
+      struct socket *so;
+      struct sockaddr_in addr;
+      if ((so = socreate(slirp)) == NULL) goto freeit;
+      if (icmp_send(so, m, hlen) == 0) {
+        return;
+      }
+      if(udp_attach(so) == -1) {
+	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
+		    errno,strerror(errno)));
+	sofree(so);
+	m_free(m);
+	goto end_error;
+      }
+      so->so_m = m;
+      so->so_faddr = ip->ip_dst;
+      so->so_fport = htons(7);
+      so->so_laddr = ip->ip_src;
+      so->so_lport = htons(9);
+      so->so_iptos = ip->ip_tos;
+      so->so_type = IPPROTO_ICMP;
+      so->so_state = SS_ISFCONNECTED;
+
+      /* Send the packet */
+      addr.sin_family = AF_INET;
+      if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+          slirp->vnetwork_addr.s_addr) {
+	/* It's an alias */
+	if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+	  if (get_dns_addr(&addr.sin_addr) < 0)
+	    addr.sin_addr = loopback_addr;
+	} else {
+	  addr.sin_addr = loopback_addr;
+	}
+      } else {
+	addr.sin_addr = so->so_faddr;
+      }
+      addr.sin_port = so->so_fport;
+      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
+		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
+	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
+		    errno,strerror(errno)));
+	icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	udp_detach(so);
+      }
+    } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
+    break;
+  case ICMP_UNREACH:
+    /* XXX? report error? close socket? */
+  case ICMP_TIMXCEED:
+  case ICMP_PARAMPROB:
+  case ICMP_SOURCEQUENCH:
+  case ICMP_TSTAMP:
+  case ICMP_MASKREQ:
+  case ICMP_REDIRECT:
+    m_free(m);
+    break;
+
+  default:
+    m_free(m);
+  } /* swith */
+
+end_error:
+  /* m is m_free()'d xor put in a socket xor or given to ip_send */
+  return;
+}
+
+
+/*
+ *	Send an ICMP message in response to a situation
+ *
+ *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
+ *			MUST NOT change this header information.
+ *			MUST NOT reply to a multicast/broadcast IP address.
+ *			MUST NOT reply to a multicast/broadcast MAC address.
+ *			MUST reply to only the first fragment.
+ */
+/*
+ * Send ICMP_UNREACH back to the source regarding msrc.
+ * mbuf *msrc is used as a template, but is NOT m_free()'d.
+ * It is reported as the bad ip packet.  The header should
+ * be fully correct and in host byte order.
+ * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
+ * packet.  The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
+ */
+
+#define ICMP_MAXDATALEN (IP_MSS-28)
+void
+icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+           const char *message)
+{
+  unsigned hlen, shlen, s_ip_len;
+  register struct ip *ip;
+  register struct icmp *icp;
+  register struct mbuf *m;
+
+  DEBUG_CALL("icmp_error");
+  DEBUG_ARG("msrc = %lx", (long )msrc);
+  DEBUG_ARG("msrc_len = %d", msrc->m_len);
+
+  if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
+
+  /* check msrc */
+  if(!msrc) goto end_error;
+  ip = mtod(msrc, struct ip *);
+#ifdef DEBUG
+  { char bufa[20], bufb[20];
+    strcpy(bufa, inet_ntoa(ip->ip_src));
+    strcpy(bufb, inet_ntoa(ip->ip_dst));
+    DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
+  }
+#endif
+  if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */
+
+  shlen=ip->ip_hl << 2;
+  s_ip_len=ip->ip_len;
+  if(ip->ip_p == IPPROTO_ICMP) {
+    icp = (struct icmp *)((char *)ip + shlen);
+    /*
+     *	Assume any unknown ICMP type is an error. This isn't
+     *	specified by the RFC, but think about it..
+     */
+    if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
+  }
+
+  /* make a copy */
+  m = m_get(msrc->slirp);
+  if (!m) {
+      goto end_error;
+  }
+
+  { int new_m_size;
+    new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
+    if(new_m_size>m->m_size) m_inc(m, new_m_size);
+  }
+  memcpy(m->m_data, msrc->m_data, msrc->m_len);
+  m->m_len = msrc->m_len;                        /* copy msrc to m */
+
+  /* make the header of the reply packet */
+  ip  = mtod(m, struct ip *);
+  hlen= sizeof(struct ip );     /* no options in reply */
+
+  /* fill in icmp */
+  m->m_data += hlen;
+  m->m_len -= hlen;
+
+  icp = mtod(m, struct icmp *);
+
+  if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
+  else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
+    s_ip_len=ICMP_MAXDATALEN;
+
+  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */
+
+  /* min. size = 8+sizeof(struct ip)+8 */
+
+  icp->icmp_type = type;
+  icp->icmp_code = code;
+  icp->icmp_id = 0;
+  icp->icmp_seq = 0;
+
+  memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len);   /* report the ip packet */
+  HTONS(icp->icmp_ip.ip_len);
+  HTONS(icp->icmp_ip.ip_id);
+  HTONS(icp->icmp_ip.ip_off);
+
+#ifdef DEBUG
+  if(message) {           /* DEBUG : append message to ICMP packet */
+    int message_len;
+    char *cpnt;
+    message_len=strlen(message);
+    if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
+    cpnt=(char *)m->m_data+m->m_len;
+    memcpy(cpnt, message, message_len);
+    m->m_len+=message_len;
+  }
+#endif
+
+  icp->icmp_cksum = 0;
+  icp->icmp_cksum = cksum(m, m->m_len);
+
+  m->m_data -= hlen;
+  m->m_len += hlen;
+
+  /* fill in ip */
+  ip->ip_hl = hlen >> 2;
+  ip->ip_len = m->m_len;
+
+  ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */
+
+  ip->ip_ttl = MAXTTL;
+  ip->ip_p = IPPROTO_ICMP;
+  ip->ip_dst = ip->ip_src;    /* ip adresses */
+  ip->ip_src = m->slirp->vhost_addr;
+
+  (void ) ip_output((struct socket *)NULL, m);
+
+end_error:
+  return;
+}
+#undef ICMP_MAXDATALEN
+
+/*
+ * Reflect the ip packet back to the source
+ */
+void
+icmp_reflect(struct mbuf *m)
+{
+  register struct ip *ip = mtod(m, struct ip *);
+  int hlen = ip->ip_hl << 2;
+  int optlen = hlen - sizeof(struct ip );
+  register struct icmp *icp;
+
+  /*
+   * Send an icmp packet back to the ip level,
+   * after supplying a checksum.
+   */
+  m->m_data += hlen;
+  m->m_len -= hlen;
+  icp = mtod(m, struct icmp *);
+
+  icp->icmp_type = ICMP_ECHOREPLY;
+  icp->icmp_cksum = 0;
+  icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
+
+  m->m_data -= hlen;
+  m->m_len += hlen;
+
+  /* fill in ip */
+  if (optlen > 0) {
+    /*
+     * Strip out original options by copying rest of first
+     * mbuf's data back, and adjust the IP length.
+     */
+    memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
+	    (unsigned )(m->m_len - hlen));
+    hlen -= optlen;
+    ip->ip_hl = hlen >> 2;
+    ip->ip_len -= optlen;
+    m->m_len -= optlen;
+  }
+
+  ip->ip_ttl = MAXTTL;
+  { /* swap */
+    struct in_addr icmp_dst;
+    icmp_dst = ip->ip_dst;
+    ip->ip_dst = ip->ip_src;
+    ip->ip_src = icmp_dst;
+  }
+
+  (void ) ip_output((struct socket *)NULL, m);
+}
+
+void icmp_receive(struct socket *so)
+{
+    struct mbuf *m = so->so_m;
+    struct ip *ip = mtod(m, struct ip *);
+    int hlen = ip->ip_hl << 2;
+    u_char error_code;
+    struct icmp *icp;
+    int id, len;
+
+    m->m_data += hlen;
+    m->m_len -= hlen;
+    icp = mtod(m, struct icmp *);
+
+    id = icp->icmp_id;
+    len = qemu_recv(so->s, icp, m->m_len, 0);
+    icp->icmp_id = id;
+
+    m->m_data -= hlen;
+    m->m_len += hlen;
+
+    if (len == -1 || len == 0) {
+        if (errno == ENETUNREACH) {
+            error_code = ICMP_UNREACH_NET;
+        } else {
+            error_code = ICMP_UNREACH_HOST;
+        }
+        DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
+                    strerror(errno)));
+        icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
+    } else {
+        icmp_reflect(so->so_m);
+        so->so_m = NULL; /* Don't m_free() it again! */
+    }
+    icmp_detach(so);
+}
diff --git a/qemu-0.15.x/slirp/ip_icmp.h b/qemu-0.15.x/slirp/ip_icmp.h
new file mode 100644
index 0000000..b3da1f2
--- /dev/null
+++ b/qemu-0.15.x/slirp/ip_icmp.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)ip_icmp.h	8.1 (Berkeley) 6/10/93
+ * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
+ */
+
+#ifndef _NETINET_IP_ICMP_H_
+#define _NETINET_IP_ICMP_H_
+
+/*
+ * Interface Control Message Protocol Definitions.
+ * Per RFC 792, September 1981.
+ */
+
+typedef uint32_t n_time;
+
+/*
+ * Structure of an icmp header.
+ */
+struct icmp {
+	u_char	icmp_type;		/* type of message, see below */
+	u_char	icmp_code;		/* type sub code */
+	u_short	icmp_cksum;		/* ones complement cksum of struct */
+	union {
+		u_char ih_pptr;			/* ICMP_PARAMPROB */
+		struct in_addr ih_gwaddr;	/* ICMP_REDIRECT */
+		struct ih_idseq {
+			u_short	icd_id;
+			u_short	icd_seq;
+		} ih_idseq;
+		int ih_void;
+
+		/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+		struct ih_pmtu {
+			u_short ipm_void;
+			u_short ipm_nextmtu;
+		} ih_pmtu;
+	} icmp_hun;
+#define	icmp_pptr	icmp_hun.ih_pptr
+#define	icmp_gwaddr	icmp_hun.ih_gwaddr
+#define	icmp_id		icmp_hun.ih_idseq.icd_id
+#define	icmp_seq	icmp_hun.ih_idseq.icd_seq
+#define	icmp_void	icmp_hun.ih_void
+#define	icmp_pmvoid	icmp_hun.ih_pmtu.ipm_void
+#define	icmp_nextmtu	icmp_hun.ih_pmtu.ipm_nextmtu
+	union {
+		struct id_ts {
+			n_time its_otime;
+			n_time its_rtime;
+			n_time its_ttime;
+		} id_ts;
+		struct id_ip  {
+			struct ip idi_ip;
+			/* options and then 64 bits of data */
+		} id_ip;
+		uint32_t	id_mask;
+		char		id_data[1];
+	} icmp_dun;
+#define	icmp_otime	icmp_dun.id_ts.its_otime
+#define	icmp_rtime	icmp_dun.id_ts.its_rtime
+#define	icmp_ttime	icmp_dun.id_ts.its_ttime
+#define	icmp_ip		icmp_dun.id_ip.idi_ip
+#define	icmp_mask	icmp_dun.id_mask
+#define	icmp_data	icmp_dun.id_data
+};
+
+/*
+ * Lower bounds on packet lengths for various types.
+ * For the error advice packets must first insure that the
+ * packet is large enought to contain the returned ip header.
+ * Only then can we do the check to see if 64 bits of packet
+ * data have been returned, since we need to check the returned
+ * ip header length.
+ */
+#define	ICMP_MINLEN	8				/* abs minimum */
+#define	ICMP_TSLEN	(8 + 3 * sizeof (n_time))	/* timestamp */
+#define	ICMP_MASKLEN	12				/* address mask */
+#define	ICMP_ADVLENMIN	(8 + sizeof (struct ip) + 8)	/* min */
+#define	ICMP_ADVLEN(p)	(8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+	/* N.B.: must separately check that ip_hl >= 5 */
+
+/*
+ * Definition of type and code field values.
+ */
+#define	ICMP_ECHOREPLY		0		/* echo reply */
+#define	ICMP_UNREACH		3		/* dest unreachable, codes: */
+#define		ICMP_UNREACH_NET	0		/* bad net */
+#define		ICMP_UNREACH_HOST	1		/* bad host */
+#define		ICMP_UNREACH_PROTOCOL	2		/* bad protocol */
+#define		ICMP_UNREACH_PORT	3		/* bad port */
+#define		ICMP_UNREACH_NEEDFRAG	4		/* IP_DF caused drop */
+#define		ICMP_UNREACH_SRCFAIL	5		/* src route failed */
+#define		ICMP_UNREACH_NET_UNKNOWN 6		/* unknown net */
+#define		ICMP_UNREACH_HOST_UNKNOWN 7		/* unknown host */
+#define		ICMP_UNREACH_ISOLATED	8		/* src host isolated */
+#define		ICMP_UNREACH_NET_PROHIB	9		/* prohibited access */
+#define		ICMP_UNREACH_HOST_PROHIB 10		/* ditto */
+#define		ICMP_UNREACH_TOSNET	11		/* bad tos for net */
+#define		ICMP_UNREACH_TOSHOST	12		/* bad tos for host */
+#define	ICMP_SOURCEQUENCH	4		/* packet lost, slow down */
+#define	ICMP_REDIRECT		5		/* shorter route, codes: */
+#define		ICMP_REDIRECT_NET	0		/* for network */
+#define		ICMP_REDIRECT_HOST	1		/* for host */
+#define		ICMP_REDIRECT_TOSNET	2		/* for tos and net */
+#define		ICMP_REDIRECT_TOSHOST	3		/* for tos and host */
+#define	ICMP_ECHO		8		/* echo service */
+#define	ICMP_ROUTERADVERT	9		/* router advertisement */
+#define	ICMP_ROUTERSOLICIT	10		/* router solicitation */
+#define	ICMP_TIMXCEED		11		/* time exceeded, code: */
+#define		ICMP_TIMXCEED_INTRANS	0		/* ttl==0 in transit */
+#define		ICMP_TIMXCEED_REASS	1		/* ttl==0 in reass */
+#define	ICMP_PARAMPROB		12		/* ip header bad */
+#define		ICMP_PARAMPROB_OPTABSENT 1		/* req. opt. absent */
+#define	ICMP_TSTAMP		13		/* timestamp request */
+#define	ICMP_TSTAMPREPLY	14		/* timestamp reply */
+#define	ICMP_IREQ		15		/* information request */
+#define	ICMP_IREQREPLY		16		/* information reply */
+#define	ICMP_MASKREQ		17		/* address mask request */
+#define	ICMP_MASKREPLY		18		/* address mask reply */
+
+#define	ICMP_MAXTYPE		18
+
+#define	ICMP_INFOTYPE(type) \
+	((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
+	(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
+	(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
+	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
+	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
+
+void icmp_init(Slirp *slirp);
+void icmp_input(struct mbuf *, int);
+void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+                const char *message);
+void icmp_reflect(struct mbuf *);
+void icmp_receive(struct socket *so);
+void icmp_detach(struct socket *so);
+
+#endif
diff --git a/qemu-0.15.x/slirp/ip_input.c b/qemu-0.15.x/slirp/ip_input.c
new file mode 100644
index 0000000..5e67631
--- /dev/null
+++ b/qemu-0.15.x/slirp/ip_input.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
+ * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP are
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include <osdep.h>
+#include "ip_icmp.h"
+
+static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
+static void ip_freef(Slirp *slirp, struct ipq *fp);
+static void ip_enq(register struct ipasfrag *p,
+                   register struct ipasfrag *prev);
+static void ip_deq(register struct ipasfrag *p);
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void
+ip_init(Slirp *slirp)
+{
+    slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
+    udp_init(slirp);
+    tcp_init(slirp);
+    icmp_init(slirp);
+}
+
+/*
+ * Ip input routine.  Checksum and byte swap header.  If fragmented
+ * try to reassemble.  Process options.  Pass to next level.
+ */
+void
+ip_input(struct mbuf *m)
+{
+	Slirp *slirp = m->slirp;
+	register struct ip *ip;
+	int hlen;
+
+	DEBUG_CALL("ip_input");
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("m_len = %d", m->m_len);
+
+	if (m->m_len < sizeof (struct ip)) {
+		return;
+	}
+
+	ip = mtod(m, struct ip *);
+
+	if (ip->ip_v != IPVERSION) {
+		goto bad;
+	}
+
+	hlen = ip->ip_hl << 2;
+	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
+	  goto bad;                                  /* or packet too short */
+	}
+
+        /* keep ip header intact for ICMP reply
+	 * ip->ip_sum = cksum(m, hlen);
+	 * if (ip->ip_sum) {
+	 */
+	if(cksum(m,hlen)) {
+	  goto bad;
+	}
+
+	/*
+	 * Convert fields to host representation.
+	 */
+	NTOHS(ip->ip_len);
+	if (ip->ip_len < hlen) {
+		goto bad;
+	}
+	NTOHS(ip->ip_id);
+	NTOHS(ip->ip_off);
+
+	/*
+	 * Check that the amount of data in the buffers
+	 * is as at least much as the IP header would have us expect.
+	 * Trim mbufs if longer than we expect.
+	 * Drop packet if shorter than we expect.
+	 */
+	if (m->m_len < ip->ip_len) {
+		goto bad;
+	}
+
+	/* Should drop packet if mbuf too long? hmmm... */
+	if (m->m_len > ip->ip_len)
+	   m_adj(m, ip->ip_len - m->m_len);
+
+	/* check ip_ttl for a correct ICMP reply */
+	if(ip->ip_ttl==0) {
+	  icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
+	  goto bad;
+	}
+
+	/*
+	 * If offset or IP_MF are set, must reassemble.
+	 * Otherwise, nothing need be done.
+	 * (We could look in the reassembly queue to see
+	 * if the packet was previously fragmented,
+	 * but it's not worth the time; just let them time out.)
+	 *
+	 * XXX This should fail, don't fragment yet
+	 */
+	if (ip->ip_off &~ IP_DF) {
+	  register struct ipq *fp;
+      struct qlink *l;
+		/*
+		 * Look for queue of fragments
+		 * of this datagram.
+		 */
+		for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
+		     l = l->next) {
+            fp = container_of(l, struct ipq, ip_link);
+            if (ip->ip_id == fp->ipq_id &&
+                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+                    ip->ip_p == fp->ipq_p)
+		    goto found;
+        }
+        fp = NULL;
+	found:
+
+		/*
+		 * Adjust ip_len to not reflect header,
+		 * set ip_mff if more fragments are expected,
+		 * convert offset of this to bytes.
+		 */
+		ip->ip_len -= hlen;
+		if (ip->ip_off & IP_MF)
+		  ip->ip_tos |= 1;
+		else
+		  ip->ip_tos &= ~1;
+
+		ip->ip_off <<= 3;
+
+		/*
+		 * If datagram marked as having more fragments
+		 * or if this is not the first fragment,
+		 * attempt reassembly; if it succeeds, proceed.
+		 */
+		if (ip->ip_tos & 1 || ip->ip_off) {
+			ip = ip_reass(slirp, ip, fp);
+                        if (ip == NULL)
+				return;
+			m = dtom(slirp, ip);
+		} else
+			if (fp)
+		   	   ip_freef(slirp, fp);
+
+	} else
+		ip->ip_len -= hlen;
+
+	/*
+	 * Switch out to protocol's input routine.
+	 */
+	switch (ip->ip_p) {
+	 case IPPROTO_TCP:
+		tcp_input(m, hlen, (struct socket *)NULL);
+		break;
+	 case IPPROTO_UDP:
+		udp_input(m, hlen);
+		break;
+	 case IPPROTO_ICMP:
+		icmp_input(m, hlen);
+		break;
+	 default:
+		m_free(m);
+	}
+	return;
+bad:
+	m_free(m);
+	return;
+}
+
+#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
+#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
+/*
+ * Take incoming datagram fragment and try to
+ * reassemble it into whole datagram.  If a chain for
+ * reassembly of this datagram already exists, then it
+ * is given as fp; otherwise have to make a chain.
+ */
+static struct ip *
+ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
+{
+	register struct mbuf *m = dtom(slirp, ip);
+	register struct ipasfrag *q;
+	int hlen = ip->ip_hl << 2;
+	int i, next;
+
+	DEBUG_CALL("ip_reass");
+	DEBUG_ARG("ip = %lx", (long)ip);
+	DEBUG_ARG("fp = %lx", (long)fp);
+	DEBUG_ARG("m = %lx", (long)m);
+
+	/*
+	 * Presence of header sizes in mbufs
+	 * would confuse code below.
+         * Fragment m_data is concatenated.
+	 */
+	m->m_data += hlen;
+	m->m_len -= hlen;
+
+	/*
+	 * If first fragment to arrive, create a reassembly queue.
+	 */
+        if (fp == NULL) {
+	  struct mbuf *t = m_get(slirp);
+
+	  if (t == NULL) {
+	      goto dropfrag;
+	  }
+	  fp = mtod(t, struct ipq *);
+	  insque(&fp->ip_link, &slirp->ipq.ip_link);
+	  fp->ipq_ttl = IPFRAGTTL;
+	  fp->ipq_p = ip->ip_p;
+	  fp->ipq_id = ip->ip_id;
+	  fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
+	  fp->ipq_src = ip->ip_src;
+	  fp->ipq_dst = ip->ip_dst;
+	  q = (struct ipasfrag *)fp;
+	  goto insert;
+	}
+
+	/*
+	 * Find a segment which begins after this one does.
+	 */
+	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+            q = q->ipf_next)
+		if (q->ipf_off > ip->ip_off)
+			break;
+
+	/*
+	 * If there is a preceding segment, it may provide some of
+	 * our data already.  If so, drop the data from the incoming
+	 * segment.  If it provides all of our data, drop us.
+	 */
+	if (q->ipf_prev != &fp->frag_link) {
+        struct ipasfrag *pq = q->ipf_prev;
+		i = pq->ipf_off + pq->ipf_len - ip->ip_off;
+		if (i > 0) {
+			if (i >= ip->ip_len)
+				goto dropfrag;
+			m_adj(dtom(slirp, ip), i);
+			ip->ip_off += i;
+			ip->ip_len -= i;
+		}
+	}
+
+	/*
+	 * While we overlap succeeding segments trim them or,
+	 * if they are completely covered, dequeue them.
+	 */
+	while (q != (struct ipasfrag*)&fp->frag_link &&
+            ip->ip_off + ip->ip_len > q->ipf_off) {
+		i = (ip->ip_off + ip->ip_len) - q->ipf_off;
+		if (i < q->ipf_len) {
+			q->ipf_len -= i;
+			q->ipf_off += i;
+			m_adj(dtom(slirp, q), i);
+			break;
+		}
+		q = q->ipf_next;
+		m_free(dtom(slirp, q->ipf_prev));
+		ip_deq(q->ipf_prev);
+	}
+
+insert:
+	/*
+	 * Stick new segment in its place;
+	 * check for complete reassembly.
+	 */
+	ip_enq(iptofrag(ip), q->ipf_prev);
+	next = 0;
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
+            q = q->ipf_next) {
+		if (q->ipf_off != next)
+                        return NULL;
+		next += q->ipf_len;
+	}
+	if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
+                return NULL;
+
+	/*
+	 * Reassembly is complete; concatenate fragments.
+	 */
+    q = fp->frag_link.next;
+	m = dtom(slirp, q);
+
+	q = (struct ipasfrag *) q->ipf_next;
+	while (q != (struct ipasfrag*)&fp->frag_link) {
+	  struct mbuf *t = dtom(slirp, q);
+	  q = (struct ipasfrag *) q->ipf_next;
+	  m_cat(m, t);
+	}
+
+	/*
+	 * Create header for new ip packet by
+	 * modifying header of first packet;
+	 * dequeue and discard fragment reassembly header.
+	 * Make header visible.
+	 */
+	q = fp->frag_link.next;
+
+	/*
+	 * If the fragments concatenated to an mbuf that's
+	 * bigger than the total size of the fragment, then and
+	 * m_ext buffer was alloced. But fp->ipq_next points to
+	 * the old buffer (in the mbuf), so we must point ip
+	 * into the new buffer.
+	 */
+	if (m->m_flags & M_EXT) {
+	  int delta = (char *)q - m->m_dat;
+	  q = (struct ipasfrag *)(m->m_ext + delta);
+	}
+
+    ip = fragtoip(q);
+	ip->ip_len = next;
+	ip->ip_tos &= ~1;
+	ip->ip_src = fp->ipq_src;
+	ip->ip_dst = fp->ipq_dst;
+	remque(&fp->ip_link);
+	(void) m_free(dtom(slirp, fp));
+	m->m_len += (ip->ip_hl << 2);
+	m->m_data -= (ip->ip_hl << 2);
+
+	return ip;
+
+dropfrag:
+	m_free(m);
+        return NULL;
+}
+
+/*
+ * Free a fragment reassembly header and all
+ * associated datagrams.
+ */
+static void
+ip_freef(Slirp *slirp, struct ipq *fp)
+{
+	register struct ipasfrag *q, *p;
+
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
+		p = q->ipf_next;
+		ip_deq(q);
+		m_free(dtom(slirp, q));
+	}
+	remque(&fp->ip_link);
+	(void) m_free(dtom(slirp, fp));
+}
+
+/*
+ * Put an ip fragment on a reassembly chain.
+ * Like insque, but pointers in middle of structure.
+ */
+static void
+ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
+{
+	DEBUG_CALL("ip_enq");
+	DEBUG_ARG("prev = %lx", (long)prev);
+	p->ipf_prev =  prev;
+	p->ipf_next = prev->ipf_next;
+	((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
+	prev->ipf_next = p;
+}
+
+/*
+ * To ip_enq as remque is to insque.
+ */
+static void
+ip_deq(register struct ipasfrag *p)
+{
+	((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
+	((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
+}
+
+/*
+ * IP timer processing;
+ * if a timer expires on a reassembly
+ * queue, discard it.
+ */
+void
+ip_slowtimo(Slirp *slirp)
+{
+    struct qlink *l;
+
+	DEBUG_CALL("ip_slowtimo");
+
+    l = slirp->ipq.ip_link.next;
+
+        if (l == NULL)
+	   return;
+
+    while (l != &slirp->ipq.ip_link) {
+        struct ipq *fp = container_of(l, struct ipq, ip_link);
+        l = l->next;
+		if (--fp->ipq_ttl == 0) {
+			ip_freef(slirp, fp);
+		}
+    }
+}
+
+/*
+ * Do option processing on a datagram,
+ * possibly discarding it if bad options are encountered,
+ * or forwarding it if source-routed.
+ * Returns 1 if packet has been forwarded/freed,
+ * 0 if the packet should be processed further.
+ */
+
+#ifdef notdef
+
+int
+ip_dooptions(m)
+	struct mbuf *m;
+{
+	register struct ip *ip = mtod(m, struct ip *);
+	register u_char *cp;
+	register struct ip_timestamp *ipt;
+	register struct in_ifaddr *ia;
+	int opt, optlen, cnt, off, code, type, forward = 0;
+	struct in_addr *sin, dst;
+typedef uint32_t n_time;
+	n_time ntime;
+
+	dst = ip->ip_dst;
+	cp = (u_char *)(ip + 1);
+	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[IPOPT_OPTVAL];
+		if (opt == IPOPT_EOL)
+			break;
+		if (opt == IPOPT_NOP)
+			optlen = 1;
+		else {
+			optlen = cp[IPOPT_OLEN];
+			if (optlen <= 0 || optlen > cnt) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+		}
+		switch (opt) {
+
+		default:
+			break;
+
+		/*
+		 * Source routing with record.
+		 * Find interface with current destination address.
+		 * If none on this machine then drop if strictly routed,
+		 * or do nothing if loosely routed.
+		 * Record interface address and bring up next address
+		 * component.  If strictly routed make sure next
+		 * address is on directly accessible net.
+		 */
+		case IPOPT_LSRR:
+		case IPOPT_SSRR:
+			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+				goto bad;
+			}
+			ipaddr.sin_addr = ip->ip_dst;
+			ia = (struct in_ifaddr *)
+				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
+			if (ia == 0) {
+				if (opt == IPOPT_SSRR) {
+					type = ICMP_UNREACH;
+					code = ICMP_UNREACH_SRCFAIL;
+					goto bad;
+				}
+				/*
+				 * Loose routing, and not at next destination
+				 * yet; nothing to do except forward.
+				 */
+				break;
+			}
+			off--;			/ * 0 origin *  /
+			if (off > optlen - sizeof(struct in_addr)) {
+				/*
+				 * End of source route.  Should be for us.
+				 */
+				save_rte(cp, ip->ip_src);
+				break;
+			}
+			/*
+			 * locate outgoing interface
+			 */
+			bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
+			    sizeof(ipaddr.sin_addr));
+			if (opt == IPOPT_SSRR) {
+#define	INA	struct in_ifaddr *
+#define	SA	struct sockaddr *
+ 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
+				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
+			} else
+				ia = ip_rtaddr(ipaddr.sin_addr);
+			if (ia == 0) {
+				type = ICMP_UNREACH;
+				code = ICMP_UNREACH_SRCFAIL;
+				goto bad;
+			}
+			ip->ip_dst = ipaddr.sin_addr;
+			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+			    (caddr_t)(cp + off), sizeof(struct in_addr));
+			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+			/*
+			 * Let ip_intr's mcast routing check handle mcast pkts
+			 */
+			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
+			break;
+
+		case IPOPT_RR:
+			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+				goto bad;
+			}
+			/*
+			 * If no space remains, ignore.
+			 */
+			off--;			 * 0 origin *
+			if (off > optlen - sizeof(struct in_addr))
+				break;
+			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
+			    sizeof(ipaddr.sin_addr));
+			/*
+			 * locate outgoing interface; if we're the destination,
+			 * use the incoming interface (should be same).
+			 */
+			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
+			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
+				type = ICMP_UNREACH;
+				code = ICMP_UNREACH_HOST;
+				goto bad;
+			}
+			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+			    (caddr_t)(cp + off), sizeof(struct in_addr));
+			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+			break;
+
+		case IPOPT_TS:
+			code = cp - (u_char *)ip;
+			ipt = (struct ip_timestamp *)cp;
+			if (ipt->ipt_len < 5)
+				goto bad;
+			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
+				if (++ipt->ipt_oflw == 0)
+					goto bad;
+				break;
+			}
+			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
+			switch (ipt->ipt_flg) {
+
+			case IPOPT_TS_TSONLY:
+				break;
+
+			case IPOPT_TS_TSANDADDR:
+				if (ipt->ipt_ptr + sizeof(n_time) +
+				    sizeof(struct in_addr) > ipt->ipt_len)
+					goto bad;
+				ipaddr.sin_addr = dst;
+				ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
+							    m->m_pkthdr.rcvif);
+				if (ia == 0)
+					continue;
+				bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
+				    (caddr_t)sin, sizeof(struct in_addr));
+				ipt->ipt_ptr += sizeof(struct in_addr);
+				break;
+
+			case IPOPT_TS_PRESPEC:
+				if (ipt->ipt_ptr + sizeof(n_time) +
+				    sizeof(struct in_addr) > ipt->ipt_len)
+					goto bad;
+				bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
+				    sizeof(struct in_addr));
+				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
+					continue;
+				ipt->ipt_ptr += sizeof(struct in_addr);
+				break;
+
+			default:
+				goto bad;
+			}
+			ntime = iptime();
+			bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
+			    sizeof(n_time));
+			ipt->ipt_ptr += sizeof(n_time);
+		}
+	}
+	if (forward) {
+		ip_forward(m, 1);
+		return (1);
+	}
+	return (0);
+bad:
+ 	icmp_error(m, type, code, 0, 0);
+
+	return (1);
+}
+
+#endif /* notdef */
+
+/*
+ * Strip out IP options, at higher
+ * level protocol in the kernel.
+ * Second argument is buffer to which options
+ * will be moved, and return value is their length.
+ * (XXX) should be deleted; last arg currently ignored.
+ */
+void
+ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
+{
+	register int i;
+	struct ip *ip = mtod(m, struct ip *);
+	register caddr_t opts;
+	int olen;
+
+	olen = (ip->ip_hl<<2) - sizeof (struct ip);
+	opts = (caddr_t)(ip + 1);
+	i = m->m_len - (sizeof (struct ip) + olen);
+	memcpy(opts, opts  + olen, (unsigned)i);
+	m->m_len -= olen;
+
+	ip->ip_hl = sizeof(struct ip) >> 2;
+}
diff --git a/qemu-0.15.x/slirp/ip_output.c b/qemu-0.15.x/slirp/ip_output.c
new file mode 100644
index 0000000..c82830f
--- /dev/null
+++ b/qemu-0.15.x/slirp/ip_output.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *	@(#)ip_output.c	8.3 (Berkeley) 1/21/94
+ * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP are
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF_THRESH 10
+
+/*
+ * IP output.  The packet in mbuf chain m contains a skeletal IP
+ * header (with len, off, ttl, proto, tos, src, dst).
+ * The mbuf chain containing the packet will be freed.
+ * The mbuf opt, if present, will not be freed.
+ */
+int
+ip_output(struct socket *so, struct mbuf *m0)
+{
+	Slirp *slirp = m0->slirp;
+	register struct ip *ip;
+	register struct mbuf *m = m0;
+	register int hlen = sizeof(struct ip );
+	int len, off, error = 0;
+
+	DEBUG_CALL("ip_output");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m0 = %lx", (long)m0);
+
+	ip = mtod(m, struct ip *);
+	/*
+	 * Fill in IP header.
+	 */
+	ip->ip_v = IPVERSION;
+	ip->ip_off &= IP_DF;
+	ip->ip_id = htons(slirp->ip_id++);
+	ip->ip_hl = hlen >> 2;
+
+	/*
+	 * If small enough for interface, can just send directly.
+	 */
+	if ((uint16_t)ip->ip_len <= IF_MTU) {
+		ip->ip_len = htons((uint16_t)ip->ip_len);
+		ip->ip_off = htons((uint16_t)ip->ip_off);
+		ip->ip_sum = 0;
+		ip->ip_sum = cksum(m, hlen);
+
+		if_output(so, m);
+		goto done;
+	}
+
+	/*
+	 * Too large for interface; fragment if possible.
+	 * Must be able to put at least 8 bytes per fragment.
+	 */
+	if (ip->ip_off & IP_DF) {
+		error = -1;
+		goto bad;
+	}
+
+	len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
+	if (len < 8) {
+		error = -1;
+		goto bad;
+	}
+
+    {
+	int mhlen, firstlen = len;
+	struct mbuf **mnext = &m->m_nextpkt;
+
+	/*
+	 * Loop through length of segment after first fragment,
+	 * make new header and copy data of each part and link onto chain.
+	 */
+	m0 = m;
+	mhlen = sizeof (struct ip);
+	for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
+	  register struct ip *mhip;
+	  m = m_get(slirp);
+          if (m == NULL) {
+	    error = -1;
+	    goto sendorfree;
+	  }
+	  m->m_data += IF_MAXLINKHDR;
+	  mhip = mtod(m, struct ip *);
+	  *mhip = *ip;
+
+	  m->m_len = mhlen;
+	  mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
+	  if (ip->ip_off & IP_MF)
+	    mhip->ip_off |= IP_MF;
+	  if (off + len >= (uint16_t)ip->ip_len)
+	    len = (uint16_t)ip->ip_len - off;
+	  else
+	    mhip->ip_off |= IP_MF;
+	  mhip->ip_len = htons((uint16_t)(len + mhlen));
+
+	  if (m_copy(m, m0, off, len) < 0) {
+	    error = -1;
+	    goto sendorfree;
+	  }
+
+	  mhip->ip_off = htons((uint16_t)mhip->ip_off);
+	  mhip->ip_sum = 0;
+	  mhip->ip_sum = cksum(m, mhlen);
+	  *mnext = m;
+	  mnext = &m->m_nextpkt;
+	}
+	/*
+	 * Update first fragment by trimming what's been copied out
+	 * and updating header, then send each fragment (in order).
+	 */
+	m = m0;
+	m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
+	ip->ip_len = htons((uint16_t)m->m_len);
+	ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
+	ip->ip_sum = 0;
+	ip->ip_sum = cksum(m, hlen);
+sendorfree:
+	for (m = m0; m; m = m0) {
+		m0 = m->m_nextpkt;
+                m->m_nextpkt = NULL;
+		if (error == 0)
+			if_output(so, m);
+		else
+			m_free(m);
+	}
+    }
+
+done:
+	return (error);
+
+bad:
+	m_free(m0);
+	goto done;
+}
diff --git a/qemu-0.15.x/slirp/libslirp.h b/qemu-0.15.x/slirp/libslirp.h
new file mode 100644
index 0000000..67c70e3
--- /dev/null
+++ b/qemu-0.15.x/slirp/libslirp.h
@@ -0,0 +1,56 @@
+#ifndef _LIBSLIRP_H
+#define _LIBSLIRP_H
+
+#include <qemu-common.h>
+
+#ifdef CONFIG_SLIRP
+
+struct Slirp;
+typedef struct Slirp Slirp;
+
+int get_dns_addr(struct in_addr *pdns_addr);
+
+Slirp *slirp_init(int restricted, struct in_addr vnetwork,
+                  struct in_addr vnetmask, struct in_addr vhost,
+                  const char *vhostname, const char *tftp_path,
+                  const char *bootfile, struct in_addr vdhcp_start,
+                  struct in_addr vnameserver, void *opaque);
+void slirp_cleanup(Slirp *slirp);
+
+void slirp_select_fill(int *pnfds,
+                       fd_set *readfds, fd_set *writefds, fd_set *xfds);
+
+void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
+                       int select_error);
+
+void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
+
+/* you must provide the following functions: */
+int slirp_can_output(void *opaque);
+void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len);
+
+int slirp_add_hostfwd(Slirp *slirp, int is_udp,
+                      struct in_addr host_addr, int host_port,
+                      struct in_addr guest_addr, int guest_port);
+int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
+                         struct in_addr host_addr, int host_port);
+int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
+                   struct in_addr *guest_addr, int guest_port);
+
+void slirp_connection_info(Slirp *slirp, Monitor *mon);
+
+void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
+                       int guest_port, const uint8_t *buf, int size);
+size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
+                             int guest_port);
+
+#else /* !CONFIG_SLIRP */
+
+static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
+                                     fd_set *writefds, fd_set *xfds) { }
+
+static inline void slirp_select_poll(fd_set *readfds, fd_set *writefds,
+                                     fd_set *xfds, int select_error) { }
+#endif /* !CONFIG_SLIRP */
+
+#endif
diff --git a/qemu-0.15.x/slirp/main.h b/qemu-0.15.x/slirp/main.h
new file mode 100644
index 0000000..0dd8d81
--- /dev/null
+++ b/qemu-0.15.x/slirp/main.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#define TOWRITEMAX 512
+
+extern int slirp_socket;
+extern int slirp_socket_unit;
+extern int slirp_socket_port;
+extern uint32_t slirp_socket_addr;
+extern char *slirp_socket_passwd;
+extern int ctty_closed;
+
+/*
+ * Get the difference in 2 times from updtim()
+ * Allow for wraparound times, "just in case"
+ * x is the greater of the 2 (current time) and y is
+ * what it's being compared against.
+ */
+#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
+
+extern char *slirp_tty;
+extern char *exec_shell;
+extern u_int curtime;
+extern fd_set *global_readfds, *global_writefds, *global_xfds;
+extern struct in_addr loopback_addr;
+extern char *username;
+extern char *socket_path;
+extern int towrite_max;
+extern int ppp_exit;
+extern int tcp_keepintvl;
+
+#define PROTO_SLIP 0x1
+#ifdef USE_PPP
+#define PROTO_PPP 0x2
+#endif
+
+void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len);
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/qemu-0.15.x/slirp/mbuf.c b/qemu-0.15.x/slirp/mbuf.c
new file mode 100644
index 0000000..ce2eb84
--- /dev/null
+++ b/qemu-0.15.x/slirp/mbuf.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+/*
+ * mbuf's in SLiRP are much simpler than the real mbufs in
+ * FreeBSD.  They are fixed size, determined by the MTU,
+ * so that one whole packet can fit.  Mbuf's cannot be
+ * chained together.  If there's more data than the mbuf
+ * could hold, an external malloced buffer is pointed to
+ * by m_ext (and the data pointers) and M_EXT is set in
+ * the flags
+ */
+
+#include <slirp.h>
+
+#define MBUF_THRESH 30
+
+/*
+ * Find a nice value for msize
+ * XXX if_maxlinkhdr already in mtu
+ */
+#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
+
+void
+m_init(Slirp *slirp)
+{
+    slirp->m_freelist.m_next = slirp->m_freelist.m_prev = &slirp->m_freelist;
+    slirp->m_usedlist.m_next = slirp->m_usedlist.m_prev = &slirp->m_usedlist;
+}
+
+/*
+ * Get an mbuf from the free list, if there are none
+ * malloc one
+ *
+ * Because fragmentation can occur if we alloc new mbufs and
+ * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
+ * which tells m_free to actually free() it
+ */
+struct mbuf *
+m_get(Slirp *slirp)
+{
+	register struct mbuf *m;
+	int flags = 0;
+
+	DEBUG_CALL("m_get");
+
+	if (slirp->m_freelist.m_next == &slirp->m_freelist) {
+		m = (struct mbuf *)malloc(SLIRP_MSIZE);
+		if (m == NULL) goto end_error;
+		slirp->mbuf_alloced++;
+		if (slirp->mbuf_alloced > MBUF_THRESH)
+			flags = M_DOFREE;
+		m->slirp = slirp;
+	} else {
+		m = slirp->m_freelist.m_next;
+		remque(m);
+	}
+
+	/* Insert it in the used list */
+	insque(m,&slirp->m_usedlist);
+	m->m_flags = (flags | M_USEDLIST);
+
+	/* Initialise it */
+	m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
+	m->m_data = m->m_dat;
+	m->m_len = 0;
+        m->m_nextpkt = NULL;
+        m->m_prevpkt = NULL;
+end_error:
+	DEBUG_ARG("m = %lx", (long )m);
+	return m;
+}
+
+void
+m_free(struct mbuf *m)
+{
+
+  DEBUG_CALL("m_free");
+  DEBUG_ARG("m = %lx", (long )m);
+
+  if(m) {
+	/* Remove from m_usedlist */
+	if (m->m_flags & M_USEDLIST)
+	   remque(m);
+
+	/* If it's M_EXT, free() it */
+	if (m->m_flags & M_EXT)
+	   free(m->m_ext);
+
+	/*
+	 * Either free() it or put it on the free list
+	 */
+	if (m->m_flags & M_DOFREE) {
+		m->slirp->mbuf_alloced--;
+		free(m);
+	} else if ((m->m_flags & M_FREELIST) == 0) {
+		insque(m,&m->slirp->m_freelist);
+		m->m_flags = M_FREELIST; /* Clobber other flags */
+	}
+  } /* if(m) */
+}
+
+/*
+ * Copy data from one mbuf to the end of
+ * the other.. if result is too big for one mbuf, malloc()
+ * an M_EXT data segment
+ */
+void
+m_cat(struct mbuf *m, struct mbuf *n)
+{
+	/*
+	 * If there's no room, realloc
+	 */
+	if (M_FREEROOM(m) < n->m_len)
+		m_inc(m,m->m_size+MINCSIZE);
+
+	memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
+	m->m_len += n->m_len;
+
+	m_free(n);
+}
+
+
+/* make m size bytes large */
+void
+m_inc(struct mbuf *m, int size)
+{
+	int datasize;
+
+	/* some compiles throw up on gotos.  This one we can fake. */
+        if(m->m_size>size) return;
+
+        if (m->m_flags & M_EXT) {
+	  datasize = m->m_data - m->m_ext;
+	  m->m_ext = (char *)realloc(m->m_ext,size);
+	  m->m_data = m->m_ext + datasize;
+        } else {
+	  char *dat;
+	  datasize = m->m_data - m->m_dat;
+	  dat = (char *)malloc(size);
+	  memcpy(dat, m->m_dat, m->m_size);
+
+	  m->m_ext = dat;
+	  m->m_data = m->m_ext + datasize;
+	  m->m_flags |= M_EXT;
+        }
+
+        m->m_size = size;
+
+}
+
+
+
+void
+m_adj(struct mbuf *m, int len)
+{
+	if (m == NULL)
+		return;
+	if (len >= 0) {
+		/* Trim from head */
+		m->m_data += len;
+		m->m_len -= len;
+	} else {
+		/* Trim from tail */
+		len = -len;
+		m->m_len -= len;
+	}
+}
+
+
+/*
+ * Copy len bytes from m, starting off bytes into n
+ */
+int
+m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
+{
+	if (len > M_FREEROOM(n))
+		return -1;
+
+	memcpy((n->m_data + n->m_len), (m->m_data + off), len);
+	n->m_len += len;
+	return 0;
+}
+
+
+/*
+ * Given a pointer into an mbuf, return the mbuf
+ * XXX This is a kludge, I should eliminate the need for it
+ * Fortunately, it's not used often
+ */
+struct mbuf *
+dtom(Slirp *slirp, void *dat)
+{
+	struct mbuf *m;
+
+	DEBUG_CALL("dtom");
+	DEBUG_ARG("dat = %lx", (long )dat);
+
+	/* bug corrected for M_EXT buffers */
+	for (m = slirp->m_usedlist.m_next; m != &slirp->m_usedlist;
+	     m = m->m_next) {
+	  if (m->m_flags & M_EXT) {
+	    if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
+	      return m;
+	  } else {
+	    if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
+	      return m;
+	  }
+	}
+
+	DEBUG_ERROR((dfd, "dtom failed"));
+
+	return (struct mbuf *)0;
+}
diff --git a/qemu-0.15.x/slirp/mbuf.h b/qemu-0.15.x/slirp/mbuf.h
new file mode 100644
index 0000000..b74544b
--- /dev/null
+++ b/qemu-0.15.x/slirp/mbuf.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *	@(#)mbuf.h	8.3 (Berkeley) 1/21/94
+ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
+ */
+
+#ifndef _MBUF_H_
+#define _MBUF_H_
+
+#define MINCSIZE 4096	/* Amount to increase mbuf if too small */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) -	convert mbuf pointer to data pointer of correct type
+ */
+#define mtod(m,t)	((t)(m)->m_data)
+
+/* XXX About mbufs for slirp:
+ * Only one mbuf is ever used in a chain, for each "cell" of data.
+ * m_nextpkt points to the next packet, if fragmented.
+ * If the data is too large, the M_EXT is used, and a larger block
+ * is alloced.  Therefore, m_free[m] must check for M_EXT and if set
+ * free the m_ext.  This is inefficient memory-wise, but who cares.
+ */
+
+/* XXX should union some of these! */
+/* header at beginning of each mbuf: */
+struct m_hdr {
+	struct	mbuf *mh_next;		/* Linked list of mbufs */
+	struct	mbuf *mh_prev;
+	struct	mbuf *mh_nextpkt;	/* Next packet in queue/record */
+	struct	mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
+	int	mh_flags;	  /* Misc flags */
+
+	int	mh_size;		/* Size of data */
+	struct	socket *mh_so;
+
+	caddr_t	mh_data;		/* Location of data */
+	int	mh_len;			/* Amount of data in this mbuf */
+};
+
+/*
+ * How much room is in the mbuf, from m_data to the end of the mbuf
+ */
+#define M_ROOM(m) ((m->m_flags & M_EXT)? \
+			(((m)->m_ext + (m)->m_size) - (m)->m_data) \
+		   : \
+			(((m)->m_dat + (m)->m_size) - (m)->m_data))
+
+/*
+ * How much free room there is
+ */
+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
+#define M_TRAILINGSPACE M_FREEROOM
+
+struct mbuf {
+	struct	m_hdr m_hdr;
+	Slirp *slirp;
+	union M_dat {
+		char	m_dat_[1]; /* ANSI don't like 0 sized arrays */
+		char	*m_ext_;
+	} M_dat;
+};
+
+#define m_next		m_hdr.mh_next
+#define m_prev		m_hdr.mh_prev
+#define m_nextpkt	m_hdr.mh_nextpkt
+#define m_prevpkt	m_hdr.mh_prevpkt
+#define m_flags		m_hdr.mh_flags
+#define	m_len		m_hdr.mh_len
+#define	m_data		m_hdr.mh_data
+#define m_size		m_hdr.mh_size
+#define m_dat		M_dat.m_dat_
+#define m_ext		M_dat.m_ext_
+#define m_so		m_hdr.mh_so
+
+#define ifq_prev m_prev
+#define ifq_next m_next
+#define ifs_prev m_prevpkt
+#define ifs_next m_nextpkt
+#define ifq_so m_so
+
+#define M_EXT			0x01	/* m_ext points to more (malloced) data */
+#define M_FREELIST		0x02	/* mbuf is on free list */
+#define M_USEDLIST		0x04	/* XXX mbuf is on used list (for dtom()) */
+#define M_DOFREE		0x08	/* when m_free is called on the mbuf, free()
+					 * it rather than putting it on the free list */
+
+void m_init(Slirp *);
+struct mbuf * m_get(Slirp *);
+void m_free(struct mbuf *);
+void m_cat(register struct mbuf *, register struct mbuf *);
+void m_inc(struct mbuf *, int);
+void m_adj(struct mbuf *, int);
+int m_copy(struct mbuf *, struct mbuf *, int, int);
+struct mbuf * dtom(Slirp *, void *);
+
+#endif
diff --git a/qemu-0.15.x/slirp/misc.c b/qemu-0.15.x/slirp/misc.c
new file mode 100644
index 0000000..6002550
--- /dev/null
+++ b/qemu-0.15.x/slirp/misc.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include <libslirp.h>
+
+#include "monitor.h"
+
+#ifdef DEBUG
+int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
+#endif
+
+struct quehead {
+	struct quehead *qh_link;
+	struct quehead *qh_rlink;
+};
+
+inline void
+insque(void *a, void *b)
+{
+	register struct quehead *element = (struct quehead *) a;
+	register struct quehead *head = (struct quehead *) b;
+	element->qh_link = head->qh_link;
+	head->qh_link = (struct quehead *)element;
+	element->qh_rlink = (struct quehead *)head;
+	((struct quehead *)(element->qh_link))->qh_rlink
+	= (struct quehead *)element;
+}
+
+inline void
+remque(void *a)
+{
+  register struct quehead *element = (struct quehead *) a;
+  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+  element->qh_rlink = NULL;
+}
+
+int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
+             struct in_addr addr, int port)
+{
+	struct ex_list *tmp_ptr;
+
+	/* First, check if the port is "bound" */
+	for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
+		if (port == tmp_ptr->ex_fport &&
+		    addr.s_addr == tmp_ptr->ex_addr.s_addr)
+			return -1;
+	}
+
+	tmp_ptr = *ex_ptr;
+	*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
+	(*ex_ptr)->ex_fport = port;
+	(*ex_ptr)->ex_addr = addr;
+	(*ex_ptr)->ex_pty = do_pty;
+	(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
+	(*ex_ptr)->ex_next = tmp_ptr;
+	return 0;
+}
+
+#ifndef HAVE_STRERROR
+
+/*
+ * For systems with no strerror
+ */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(error)
+	int error;
+{
+	if (error < sys_nerr)
+	   return sys_errlist[error];
+	else
+	   return "Unknown error.";
+}
+
+#endif
+
+
+#ifdef _WIN32
+
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+    /* not implemented */
+    return 0;
+}
+
+#else
+
+/*
+ * XXX This is ugly
+ * We create and bind a socket, then fork off to another
+ * process, which connects to this socket, after which we
+ * exec the wanted program.  If something (strange) happens,
+ * the accept() call could block us forever.
+ *
+ * do_pty = 0   Fork/exec inetd style
+ * do_pty = 1   Fork/exec using slirp.telnetd
+ * do_ptr = 2   Fork/exec using pty
+ */
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+	int s;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(addr);
+	int opt;
+        int master = -1;
+	const char *argv[256];
+	/* don't want to clobber the original */
+	char *bptr;
+	const char *curarg;
+	int c, i, ret;
+	pid_t pid;
+
+	DEBUG_CALL("fork_exec");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("ex = %lx", (long)ex);
+	DEBUG_ARG("do_pty = %lx", (long)do_pty);
+
+	if (do_pty == 2) {
+                return 0;
+	} else {
+		addr.sin_family = AF_INET;
+		addr.sin_port = 0;
+		addr.sin_addr.s_addr = INADDR_ANY;
+
+		if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
+		    bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
+		    listen(s, 1) < 0) {
+			lprint("Error: inet socket: %s\n", strerror(errno));
+			closesocket(s);
+
+			return 0;
+		}
+	}
+
+	pid = fork();
+	switch(pid) {
+	 case -1:
+		lprint("Error: fork failed: %s\n", strerror(errno));
+		close(s);
+		if (do_pty == 2)
+		   close(master);
+		return 0;
+
+	 case 0:
+                setsid();
+
+		/* Set the DISPLAY */
+		if (do_pty == 2) {
+			(void) close(master);
+#ifdef TIOCSCTTY /* XXXXX */
+			ioctl(s, TIOCSCTTY, (char *)NULL);
+#endif
+		} else {
+			getsockname(s, (struct sockaddr *)&addr, &addrlen);
+			close(s);
+			/*
+			 * Connect to the socket
+			 * XXX If any of these fail, we're in trouble!
+	 		 */
+			s = qemu_socket(AF_INET, SOCK_STREAM, 0);
+			addr.sin_addr = loopback_addr;
+                        do {
+                            ret = connect(s, (struct sockaddr *)&addr, addrlen);
+                        } while (ret < 0 && errno == EINTR);
+		}
+
+		dup2(s, 0);
+		dup2(s, 1);
+		dup2(s, 2);
+		for (s = getdtablesize() - 1; s >= 3; s--)
+		   close(s);
+
+		i = 0;
+		bptr = qemu_strdup(ex); /* No need to free() this */
+		if (do_pty == 1) {
+			/* Setup "slirp.telnetd -x" */
+			argv[i++] = "slirp.telnetd";
+			argv[i++] = "-x";
+			argv[i++] = bptr;
+		} else
+		   do {
+			/* Change the string into argv[] */
+			curarg = bptr;
+			while (*bptr != ' ' && *bptr != (char)0)
+			   bptr++;
+			c = *bptr;
+			*bptr++ = (char)0;
+			argv[i++] = strdup(curarg);
+		   } while (c);
+
+                argv[i] = NULL;
+		execvp(argv[0], (char **)argv);
+
+		/* Ooops, failed, let's tell the user why */
+        fprintf(stderr, "Error: execvp of %s failed: %s\n",
+                argv[0], strerror(errno));
+		close(0); close(1); close(2); /* XXX */
+		exit(1);
+
+	 default:
+		qemu_add_child_watch(pid);
+		if (do_pty == 2) {
+			close(s);
+			so->s = master;
+		} else {
+			/*
+			 * XXX this could block us...
+			 * XXX Should set a timer here, and if accept() doesn't
+		 	 * return after X seconds, declare it a failure
+		 	 * The only reason this will block forever is if socket()
+		 	 * of connect() fail in the child process
+		 	 */
+                        do {
+                            so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
+                        } while (so->s < 0 && errno == EINTR);
+                        closesocket(s);
+			opt = 1;
+			setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+			opt = 1;
+			setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+		}
+		fd_nonblock(so->s);
+
+		/* Append the telnet options now */
+                if (so->so_m != NULL && do_pty == 1)  {
+			sbappend(so, so->so_m);
+                        so->so_m = NULL;
+		}
+
+		return 1;
+	}
+}
+#endif
+
+#ifndef HAVE_STRDUP
+char *
+strdup(str)
+	const char *str;
+{
+	char *bptr;
+
+	bptr = (char *)malloc(strlen(str)+1);
+	strcpy(bptr, str);
+
+	return bptr;
+}
+#endif
+
+#include "monitor.h"
+
+void lprint(const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    monitor_vprintf(default_mon, format, args);
+    va_end(args);
+}
+
+void
+u_sleep(int usec)
+{
+	struct timeval t;
+	fd_set fdset;
+
+	FD_ZERO(&fdset);
+
+	t.tv_sec = 0;
+	t.tv_usec = usec * 1000;
+
+	select(0, &fdset, &fdset, &fdset, &t);
+}
+
+/*
+ * Set fd blocking and non-blocking
+ */
+
+void
+fd_nonblock(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 1;
+#else
+        int opt = 1;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt |= O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+void
+fd_block(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 0;
+#else
+	int opt = 0;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt &= ~O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+void slirp_connection_info(Slirp *slirp, Monitor *mon)
+{
+    const char * const tcpstates[] = {
+        [TCPS_CLOSED]       = "CLOSED",
+        [TCPS_LISTEN]       = "LISTEN",
+        [TCPS_SYN_SENT]     = "SYN_SENT",
+        [TCPS_SYN_RECEIVED] = "SYN_RCVD",
+        [TCPS_ESTABLISHED]  = "ESTABLISHED",
+        [TCPS_CLOSE_WAIT]   = "CLOSE_WAIT",
+        [TCPS_FIN_WAIT_1]   = "FIN_WAIT_1",
+        [TCPS_CLOSING]      = "CLOSING",
+        [TCPS_LAST_ACK]     = "LAST_ACK",
+        [TCPS_FIN_WAIT_2]   = "FIN_WAIT_2",
+        [TCPS_TIME_WAIT]    = "TIME_WAIT",
+    };
+    struct in_addr dst_addr;
+    struct sockaddr_in src;
+    socklen_t src_len;
+    uint16_t dst_port;
+    struct socket *so;
+    const char *state;
+    char buf[20];
+    int n;
+
+    monitor_printf(mon, "  Protocol[State]    FD  Source Address  Port   "
+                        "Dest. Address  Port RecvQ SendQ\n");
+
+    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
+        if (so->so_state & SS_HOSTFWD) {
+            state = "HOST_FORWARD";
+        } else if (so->so_tcpcb) {
+            state = tcpstates[so->so_tcpcb->t_state];
+        } else {
+            state = "NONE";
+        }
+        if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
+            src_len = sizeof(src);
+            getsockname(so->s, (struct sockaddr *)&src, &src_len);
+            dst_addr = so->so_laddr;
+            dst_port = so->so_lport;
+        } else {
+            src.sin_addr = so->so_laddr;
+            src.sin_port = so->so_lport;
+            dst_addr = so->so_faddr;
+            dst_port = so->so_fport;
+        }
+        n = snprintf(buf, sizeof(buf), "  TCP[%s]", state);
+        memset(&buf[n], ' ', 19 - n);
+        buf[19] = 0;
+        monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
+                       ntohs(src.sin_port));
+        monitor_printf(mon, "%15s %5d %5d %5d\n",
+                       inet_ntoa(dst_addr), ntohs(dst_port),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+
+    for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
+        if (so->so_state & SS_HOSTFWD) {
+            n = snprintf(buf, sizeof(buf), "  UDP[HOST_FORWARD]");
+            src_len = sizeof(src);
+            getsockname(so->s, (struct sockaddr *)&src, &src_len);
+            dst_addr = so->so_laddr;
+            dst_port = so->so_lport;
+        } else {
+            n = snprintf(buf, sizeof(buf), "  UDP[%d sec]",
+                         (so->so_expire - curtime) / 1000);
+            src.sin_addr = so->so_laddr;
+            src.sin_port = so->so_lport;
+            dst_addr = so->so_faddr;
+            dst_port = so->so_fport;
+        }
+        memset(&buf[n], ' ', 19 - n);
+        buf[19] = 0;
+        monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
+                       ntohs(src.sin_port));
+        monitor_printf(mon, "%15s %5d %5d %5d\n",
+                       inet_ntoa(dst_addr), ntohs(dst_port),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+
+    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
+        n = snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
+                     (so->so_expire - curtime) / 1000);
+        src.sin_addr = so->so_laddr;
+        dst_addr = so->so_faddr;
+        memset(&buf[n], ' ', 19 - n);
+        buf[19] = 0;
+        monitor_printf(mon, "%s %3d %15s  -    ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
+        monitor_printf(mon, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+}
diff --git a/qemu-0.15.x/slirp/misc.h b/qemu-0.15.x/slirp/misc.h
new file mode 100644
index 0000000..ed40a10
--- /dev/null
+++ b/qemu-0.15.x/slirp/misc.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _MISC_H_
+#define _MISC_H_
+
+struct ex_list {
+	int ex_pty;			/* Do we want a pty? */
+	struct in_addr ex_addr;		/* Server address */
+	int ex_fport;                   /* Port to telnet to */
+	const char *ex_exec;            /* Command line of what to exec */
+	struct ex_list *ex_next;
+};
+
+#ifndef HAVE_STRDUP
+char *strdup(const char *);
+#endif
+
+void do_wait(int);
+
+#define EMU_NONE 0x0
+
+/* TCP emulations */
+#define EMU_CTL 0x1
+#define EMU_FTP 0x2
+#define EMU_KSH 0x3
+#define EMU_IRC 0x4
+#define EMU_REALAUDIO 0x5
+#define EMU_RLOGIN 0x6
+#define EMU_IDENT 0x7
+#define EMU_RSH 0x8
+
+#define EMU_NOCONNECT 0x10	/* Don't connect */
+
+struct tos_t {
+    uint16_t lport;
+    uint16_t fport;
+    uint8_t tos;
+    uint8_t emu;
+};
+
+struct emu_t {
+    uint16_t lport;
+    uint16_t fport;
+    uint8_t tos;
+    uint8_t emu;
+    struct emu_t *next;
+};
+
+extern int x_port, x_server, x_display;
+
+int show_x(char *, struct socket *);
+void redir_x(uint32_t, int, int, int);
+void slirp_insque(void *, void *);
+void slirp_remque(void *);
+int add_exec(struct ex_list **, int, char *, struct in_addr, int);
+int slirp_openpty(int *, int *);
+int fork_exec(struct socket *so, const char *ex, int do_pty);
+void snooze_hup(int);
+void snooze(void);
+void relay(int);
+void add_emu(char *);
+void u_sleep(int);
+void fd_nonblock(int);
+void fd_block(int);
+int rsh_exec(struct socket *, struct socket *, char *, char *, char *);
+
+#endif
diff --git a/qemu-0.15.x/slirp/sbuf.c b/qemu-0.15.x/slirp/sbuf.c
new file mode 100644
index 0000000..5a1ccbf
--- /dev/null
+++ b/qemu-0.15.x/slirp/sbuf.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+
+void
+sbfree(struct sbuf *sb)
+{
+	free(sb->sb_data);
+}
+
+void
+sbdrop(struct sbuf *sb, int num)
+{
+	/*
+	 * We can only drop how much we have
+	 * This should never succeed
+	 */
+	if(num > sb->sb_cc)
+		num = sb->sb_cc;
+	sb->sb_cc -= num;
+	sb->sb_rptr += num;
+	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
+		sb->sb_rptr -= sb->sb_datalen;
+
+}
+
+void
+sbreserve(struct sbuf *sb, int size)
+{
+	if (sb->sb_data) {
+		/* Already alloced, realloc if necessary */
+		if (sb->sb_datalen != size) {
+			sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+			sb->sb_cc = 0;
+			if (sb->sb_wptr)
+			   sb->sb_datalen = size;
+			else
+			   sb->sb_datalen = 0;
+		}
+	} else {
+		sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
+		sb->sb_cc = 0;
+		if (sb->sb_wptr)
+		   sb->sb_datalen = size;
+		else
+		   sb->sb_datalen = 0;
+	}
+}
+
+/*
+ * Try and write() to the socket, whatever doesn't get written
+ * append to the buffer... for a host with a fast net connection,
+ * this prevents an unnecessary copy of the data
+ * (the socket is non-blocking, so we won't hang)
+ */
+void
+sbappend(struct socket *so, struct mbuf *m)
+{
+	int ret = 0;
+
+	DEBUG_CALL("sbappend");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("m->m_len = %d", m->m_len);
+
+	/* Shouldn't happen, but...  e.g. foreign host closes connection */
+	if (m->m_len <= 0) {
+		m_free(m);
+		return;
+	}
+
+	/*
+	 * If there is urgent data, call sosendoob
+	 * if not all was sent, sowrite will take care of the rest
+	 * (The rest of this function is just an optimisation)
+	 */
+	if (so->so_urgc) {
+		sbappendsb(&so->so_rcv, m);
+		m_free(m);
+		sosendoob(so);
+		return;
+	}
+
+	/*
+	 * We only write if there's nothing in the buffer,
+	 * ottherwise it'll arrive out of order, and hence corrupt
+	 */
+	if (!so->so_rcv.sb_cc)
+	   ret = slirp_send(so, m->m_data, m->m_len, 0);
+
+	if (ret <= 0) {
+		/*
+		 * Nothing was written
+		 * It's possible that the socket has closed, but
+		 * we don't need to check because if it has closed,
+		 * it will be detected in the normal way by soread()
+		 */
+		sbappendsb(&so->so_rcv, m);
+	} else if (ret != m->m_len) {
+		/*
+		 * Something was written, but not everything..
+		 * sbappendsb the rest
+		 */
+		m->m_len -= ret;
+		m->m_data += ret;
+		sbappendsb(&so->so_rcv, m);
+	} /* else */
+	/* Whatever happened, we free the mbuf */
+	m_free(m);
+}
+
+/*
+ * Copy the data from m into sb
+ * The caller is responsible to make sure there's enough room
+ */
+static void
+sbappendsb(struct sbuf *sb, struct mbuf *m)
+{
+	int len, n,  nn;
+
+	len = m->m_len;
+
+	if (sb->sb_wptr < sb->sb_rptr) {
+		n = sb->sb_rptr - sb->sb_wptr;
+		if (n > len) n = len;
+		memcpy(sb->sb_wptr, m->m_data, n);
+	} else {
+		/* Do the right edge first */
+		n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
+		if (n > len) n = len;
+		memcpy(sb->sb_wptr, m->m_data, n);
+		len -= n;
+		if (len) {
+			/* Now the left edge */
+			nn = sb->sb_rptr - sb->sb_data;
+			if (nn > len) nn = len;
+			memcpy(sb->sb_data,m->m_data+n,nn);
+			n += nn;
+		}
+	}
+
+	sb->sb_cc += n;
+	sb->sb_wptr += n;
+	if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
+		sb->sb_wptr -= sb->sb_datalen;
+}
+
+/*
+ * Copy data from sbuf to a normal, straight buffer
+ * Don't update the sbuf rptr, this will be
+ * done in sbdrop when the data is acked
+ */
+void
+sbcopy(struct sbuf *sb, int off, int len, char *to)
+{
+	char *from;
+
+	from = sb->sb_rptr + off;
+	if (from >= sb->sb_data + sb->sb_datalen)
+		from -= sb->sb_datalen;
+
+	if (from < sb->sb_wptr) {
+		if (len > sb->sb_cc) len = sb->sb_cc;
+		memcpy(to,from,len);
+	} else {
+		/* re-use off */
+		off = (sb->sb_data + sb->sb_datalen) - from;
+		if (off > len) off = len;
+		memcpy(to,from,off);
+		len -= off;
+		if (len)
+		   memcpy(to+off,sb->sb_data,len);
+	}
+}
diff --git a/qemu-0.15.x/slirp/sbuf.h b/qemu-0.15.x/slirp/sbuf.h
new file mode 100644
index 0000000..4f22e7c
--- /dev/null
+++ b/qemu-0.15.x/slirp/sbuf.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _SBUF_H_
+#define _SBUF_H_
+
+#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
+#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
+
+struct sbuf {
+	u_int	sb_cc;		/* actual chars in buffer */
+	u_int	sb_datalen;	/* Length of data  */
+	char	*sb_wptr;	/* write pointer. points to where the next
+				 * bytes should be written in the sbuf */
+	char	*sb_rptr;	/* read pointer. points to where the next
+				 * byte should be read from the sbuf */
+	char	*sb_data;	/* Actual data */
+};
+
+void sbfree(struct sbuf *);
+void sbdrop(struct sbuf *, int);
+void sbreserve(struct sbuf *, int);
+void sbappend(struct socket *, struct mbuf *);
+void sbcopy(struct sbuf *, int, int, char *);
+
+#endif
diff --git a/qemu-0.15.x/slirp/slirp.c b/qemu-0.15.x/slirp/slirp.c
new file mode 100644
index 0000000..df787ea
--- /dev/null
+++ b/qemu-0.15.x/slirp/slirp.c
@@ -0,0 +1,1150 @@
+/*
+ * libslirp glue
+ *
+ * Copyright (c) 2004-2008 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "slirp.h"
+#include "hw/hw.h"
+
+/* host loopback address */
+struct in_addr loopback_addr;
+
+/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
+static const uint8_t special_ethaddr[6] = {
+    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+
+/* XXX: suppress those select globals */
+fd_set *global_readfds, *global_writefds, *global_xfds;
+
+u_int curtime;
+static u_int time_fasttimo, last_slowtimo;
+static int do_slowtimo;
+
+static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
+    QTAILQ_HEAD_INITIALIZER(slirp_instances);
+
+static struct in_addr dns_addr;
+static u_int dns_addr_time;
+
+#ifdef _WIN32
+
+int get_dns_addr(struct in_addr *pdns_addr)
+{
+    FIXED_INFO *FixedInfo=NULL;
+    ULONG    BufLen;
+    DWORD    ret;
+    IP_ADDR_STRING *pIPAddr;
+    struct in_addr tmp_addr;
+
+    if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) {
+        *pdns_addr = dns_addr;
+        return 0;
+    }
+
+    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
+    BufLen = sizeof(FIXED_INFO);
+
+    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        FixedInfo = GlobalAlloc(GPTR, BufLen);
+    }
+
+    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
+        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        return -1;
+    }
+
+    pIPAddr = &(FixedInfo->DnsServerList);
+    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
+    *pdns_addr = tmp_addr;
+    dns_addr = tmp_addr;
+    dns_addr_time = curtime;
+    if (FixedInfo) {
+        GlobalFree(FixedInfo);
+        FixedInfo = NULL;
+    }
+    return 0;
+}
+
+static void winsock_cleanup(void)
+{
+    WSACleanup();
+}
+
+#else
+
+static struct stat dns_addr_stat;
+
+int get_dns_addr(struct in_addr *pdns_addr)
+{
+    char buff[512];
+    char buff2[257];
+    FILE *f;
+    int found = 0;
+    struct in_addr tmp_addr;
+
+    if (dns_addr.s_addr != 0) {
+        struct stat old_stat;
+        if ((curtime - dns_addr_time) < 1000) {
+            *pdns_addr = dns_addr;
+            return 0;
+        }
+        old_stat = dns_addr_stat;
+        if (stat("/etc/resolv.conf", &dns_addr_stat) != 0)
+            return -1;
+        if ((dns_addr_stat.st_dev == old_stat.st_dev)
+            && (dns_addr_stat.st_ino == old_stat.st_ino)
+            && (dns_addr_stat.st_size == old_stat.st_size)
+            && (dns_addr_stat.st_mtime == old_stat.st_mtime)) {
+            *pdns_addr = dns_addr;
+            return 0;
+        }
+    }
+
+    f = fopen("/etc/resolv.conf", "r");
+    if (!f)
+        return -1;
+
+#ifdef DEBUG
+    lprint("IP address of your DNS(s): ");
+#endif
+    while (fgets(buff, 512, f) != NULL) {
+        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
+            if (!inet_aton(buff2, &tmp_addr))
+                continue;
+            /* If it's the first one, set it to dns_addr */
+            if (!found) {
+                *pdns_addr = tmp_addr;
+                dns_addr = tmp_addr;
+                dns_addr_time = curtime;
+            }
+#ifdef DEBUG
+            else
+                lprint(", ");
+#endif
+            if (++found > 3) {
+#ifdef DEBUG
+                lprint("(more)");
+#endif
+                break;
+            }
+#ifdef DEBUG
+            else
+                lprint("%s", inet_ntoa(tmp_addr));
+#endif
+        }
+    }
+    fclose(f);
+    if (!found)
+        return -1;
+    return 0;
+}
+
+#endif
+
+static void slirp_init_once(void)
+{
+    static int initialized;
+#ifdef _WIN32
+    WSADATA Data;
+#endif
+
+    if (initialized) {
+        return;
+    }
+    initialized = 1;
+
+#ifdef _WIN32
+    WSAStartup(MAKEWORD(2,0), &Data);
+    atexit(winsock_cleanup);
+#endif
+
+    loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
+}
+
+static void slirp_state_save(QEMUFile *f, void *opaque);
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
+
+Slirp *slirp_init(int restricted, struct in_addr vnetwork,
+                  struct in_addr vnetmask, struct in_addr vhost,
+                  const char *vhostname, const char *tftp_path,
+                  const char *bootfile, struct in_addr vdhcp_start,
+                  struct in_addr vnameserver, void *opaque)
+{
+    Slirp *slirp = qemu_mallocz(sizeof(Slirp));
+
+    slirp_init_once();
+
+    slirp->restricted = restricted;
+
+    if_init(slirp);
+    ip_init(slirp);
+
+    /* Initialise mbufs *after* setting the MTU */
+    m_init(slirp);
+
+    slirp->vnetwork_addr = vnetwork;
+    slirp->vnetwork_mask = vnetmask;
+    slirp->vhost_addr = vhost;
+    if (vhostname) {
+        pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
+                vhostname);
+    }
+    if (tftp_path) {
+        slirp->tftp_prefix = qemu_strdup(tftp_path);
+    }
+    if (bootfile) {
+        slirp->bootp_filename = qemu_strdup(bootfile);
+    }
+    slirp->vdhcp_startaddr = vdhcp_start;
+    slirp->vnameserver_addr = vnameserver;
+
+    slirp->opaque = opaque;
+
+    register_savevm(NULL, "slirp", 0, 3,
+                    slirp_state_save, slirp_state_load, slirp);
+
+    QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
+
+    return slirp;
+}
+
+void slirp_cleanup(Slirp *slirp)
+{
+    QTAILQ_REMOVE(&slirp_instances, slirp, entry);
+
+    unregister_savevm(NULL, "slirp", slirp);
+
+    qemu_free(slirp->tftp_prefix);
+    qemu_free(slirp->bootp_filename);
+    qemu_free(slirp);
+}
+
+#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
+
+void slirp_select_fill(int *pnfds,
+                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    Slirp *slirp;
+    struct socket *so, *so_next;
+    int nfds;
+
+    if (QTAILQ_EMPTY(&slirp_instances)) {
+        return;
+    }
+
+    /* fail safe */
+    global_readfds = NULL;
+    global_writefds = NULL;
+    global_xfds = NULL;
+
+    nfds = *pnfds;
+	/*
+	 * First, TCP sockets
+	 */
+	do_slowtimo = 0;
+
+	QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+		/*
+		 * *_slowtimo needs calling if there are IP fragments
+		 * in the fragment queue, or there are TCP connections active
+		 */
+		do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
+		    (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
+
+		for (so = slirp->tcb.so_next; so != &slirp->tcb;
+		     so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * See if we need a tcp_fasttimo
+			 */
+			if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
+			   time_fasttimo = curtime; /* Flag when we want a fasttimo */
+
+			/*
+			 * NOFDREF can include still connecting to local-host,
+			 * newly socreated() sockets etc. Don't want to select these.
+	 		 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+			/*
+			 * Set for reading sockets which are accepting
+			 */
+			if (so->so_state & SS_FACCEPTCONN) {
+                                FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing sockets which are connecting
+			 */
+			if (so->so_state & SS_ISFCONNECTING) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing if we are connected, can send more, and
+			 * we have something to send
+			 */
+			if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+			}
+
+			/*
+			 * Set for reading (and urgent data) if we are connected, can
+			 * receive more, and we have room for it XXX /2 ?
+			 */
+			if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+				FD_SET(so->s, readfds);
+				FD_SET(so->s, xfds);
+				UPD_NFDS(so->s);
+			}
+		}
+
+		/*
+		 * UDP sockets
+		 */
+		for (so = slirp->udb.so_next; so != &slirp->udb;
+		     so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * See if it's timed out
+			 */
+			if (so->so_expire) {
+				if (so->so_expire <= curtime) {
+					udp_detach(so);
+					continue;
+				} else
+					do_slowtimo = 1; /* Let socket expire */
+			}
+
+			/*
+			 * When UDP packets are received from over the
+			 * link, they're sendto()'d straight away, so
+			 * no need for setting for writing
+			 * Limit the number of packets queued by this session
+			 * to 4.  Note that even though we try and limit this
+			 * to 4 packets, the session could have more queued
+			 * if the packets needed to be fragmented
+			 * (XXX <= 4 ?)
+			 */
+			if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+				FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+			}
+		}
+
+                /*
+                 * ICMP sockets
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                    so_next = so->so_next;
+
+                    /*
+                     * See if it's timed out
+                     */
+                    if (so->so_expire) {
+                        if (so->so_expire <= curtime) {
+                            icmp_detach(so);
+                            continue;
+                        } else {
+                            do_slowtimo = 1; /* Let socket expire */
+                        }
+                    }
+
+                    if (so->so_state & SS_ISFCONNECTED) {
+                        FD_SET(so->s, readfds);
+                        UPD_NFDS(so->s);
+                    }
+                }
+	}
+
+        *pnfds = nfds;
+}
+
+void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
+                       int select_error)
+{
+    Slirp *slirp;
+    struct socket *so, *so_next;
+    int ret;
+
+    if (QTAILQ_EMPTY(&slirp_instances)) {
+        return;
+    }
+
+    global_readfds = readfds;
+    global_writefds = writefds;
+    global_xfds = xfds;
+
+    curtime = qemu_get_clock_ms(rt_clock);
+
+    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+	/*
+	 * See if anything has timed out
+	 */
+		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+			tcp_fasttimo(slirp);
+			time_fasttimo = 0;
+		}
+		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+			ip_slowtimo(slirp);
+			tcp_slowtimo(slirp);
+			last_slowtimo = curtime;
+		}
+
+	/*
+	 * Check sockets
+	 */
+	if (!select_error) {
+		/*
+		 * Check TCP sockets
+		 */
+		for (so = slirp->tcb.so_next; so != &slirp->tcb;
+		     so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * FD_ISSET is meaningless on these sockets
+			 * (and they can crash the program)
+			 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+			/*
+			 * Check for URG data
+			 * This will soread as well, so no need to
+			 * test for readfds below if this succeeds
+			 */
+			if (FD_ISSET(so->s, xfds))
+			   sorecvoob(so);
+			/*
+			 * Check sockets for reading
+			 */
+			else if (FD_ISSET(so->s, readfds)) {
+				/*
+				 * Check for incoming connections
+				 */
+				if (so->so_state & SS_FACCEPTCONN) {
+					tcp_connect(so);
+					continue;
+				} /* else */
+				ret = soread(so);
+
+				/* Output it if we read something */
+				if (ret > 0)
+				   tcp_output(sototcpcb(so));
+			}
+
+			/*
+			 * Check sockets for writing
+			 */
+			if (FD_ISSET(so->s, writefds)) {
+			  /*
+			   * Check for non-blocking, still-connecting sockets
+			   */
+			  if (so->so_state & SS_ISFCONNECTING) {
+			    /* Connected */
+			    so->so_state &= ~SS_ISFCONNECTING;
+
+			    ret = send(so->s, (const void *) &ret, 0, 0);
+			    if (ret < 0) {
+			      /* XXXXX Must fix, zero bytes is a NOP */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+
+			      /* else failed */
+			      so->so_state &= SS_PERSISTENT_MASK;
+			      so->so_state |= SS_NOFDREF;
+			    }
+			    /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+			    /*
+			     * Continue tcp_input
+			     */
+			    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+			    /* continue; */
+			  } else
+			    ret = sowrite(so);
+			  /*
+			   * XXXXX If we wrote something (a lot), there
+			   * could be a need for a window update.
+			   * In the worst case, the remote will send
+			   * a window probe to get things going again
+			   */
+			}
+
+			/*
+			 * Probe a still-connecting, non-blocking socket
+			 * to check if it's still alive
+	 	 	 */
+#ifdef PROBE_CONN
+			if (so->so_state & SS_ISFCONNECTING) {
+                          ret = qemu_recv(so->s, &ret, 0,0);
+
+			  if (ret < 0) {
+			    /* XXX */
+			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				errno == EINPROGRESS || errno == ENOTCONN)
+			      continue; /* Still connecting, continue */
+
+			    /* else failed */
+			    so->so_state &= SS_PERSISTENT_MASK;
+			    so->so_state |= SS_NOFDREF;
+
+			    /* tcp_input will take care of it */
+			  } else {
+			    ret = send(so->s, &ret, 0,0);
+			    if (ret < 0) {
+			      /* XXX */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+			      /* else failed */
+			      so->so_state &= SS_PERSISTENT_MASK;
+			      so->so_state |= SS_NOFDREF;
+			    } else
+			      so->so_state &= ~SS_ISFCONNECTING;
+
+			  }
+			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
+			} /* SS_ISFCONNECTING */
+#endif
+		}
+
+		/*
+		 * Now UDP sockets.
+		 * Incoming packets are sent straight away, they're not buffered.
+		 * Incoming UDP data isn't buffered either.
+		 */
+		for (so = slirp->udb.so_next; so != &slirp->udb;
+		     so = so_next) {
+			so_next = so->so_next;
+
+			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                            sorecvfrom(so);
+                        }
+		}
+
+                /*
+                 * Check incoming ICMP relies.
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                     so_next = so->so_next;
+
+                    if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                        icmp_receive(so);
+                    }
+                }
+	}
+
+	/*
+	 * See if we can start outputting
+	 */
+	if (slirp->if_queued) {
+	    if_start(slirp);
+	}
+    }
+
+	/* clear global file descriptor sets.
+	 * these reside on the stack in vl.c
+	 * so they're unusable if we're not in
+	 * slirp_select_fill or slirp_select_poll.
+	 */
+	 global_readfds = NULL;
+	 global_writefds = NULL;
+	 global_xfds = NULL;
+}
+
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+
+#define	ARPOP_REQUEST	1		/* ARP request			*/
+#define	ARPOP_REPLY	2		/* ARP reply			*/
+
+struct ethhdr
+{
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	unsigned short	h_proto;		/* packet type ID field	*/
+};
+
+struct arphdr
+{
+	unsigned short	ar_hrd;		/* format of hardware address	*/
+	unsigned short	ar_pro;		/* format of protocol address	*/
+	unsigned char	ar_hln;		/* length of hardware address	*/
+	unsigned char	ar_pln;		/* length of protocol address	*/
+	unsigned short	ar_op;		/* ARP opcode (command)		*/
+
+	 /*
+	  *	 Ethernet looks like this : This bit is variable sized however...
+	  */
+	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
+	uint32_t		ar_sip;			/* sender IP address		*/
+	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
+	uint32_t		ar_tip	;		/* target IP address		*/
+} __attribute__((packed));
+
+static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
+{
+    struct ethhdr *eh = (struct ethhdr *)pkt;
+    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
+    uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
+    struct ethhdr *reh = (struct ethhdr *)arp_reply;
+    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
+    int ar_op;
+    struct ex_list *ex_ptr;
+
+    ar_op = ntohs(ah->ar_op);
+    switch(ar_op) {
+    case ARPOP_REQUEST:
+        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
+            slirp->vnetwork_addr.s_addr) {
+            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
+                ah->ar_tip == slirp->vhost_addr.s_addr)
+                goto arp_ok;
+            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
+                    goto arp_ok;
+            }
+            return;
+        arp_ok:
+            memset(arp_reply, 0, sizeof(arp_reply));
+            /* XXX: make an ARP request to have the client address */
+            memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
+
+            /* ARP request for alias/dns mac address */
+            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
+            reh->h_proto = htons(ETH_P_ARP);
+
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REPLY);
+            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
+            rah->ar_sip = ah->ar_tip;
+            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
+            rah->ar_tip = ah->ar_sip;
+            slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
+        }
+        break;
+    case ARPOP_REPLY:
+        /* reply to request of client mac address ? */
+        if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
+            ah->ar_sip == slirp->client_ipaddr.s_addr) {
+            memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
+{
+    struct mbuf *m;
+    int proto;
+
+    if (pkt_len < ETH_HLEN)
+        return;
+
+    proto = ntohs(*(uint16_t *)(pkt + 12));
+    switch(proto) {
+    case ETH_P_ARP:
+        arp_input(slirp, pkt, pkt_len);
+        break;
+    case ETH_P_IP:
+        m = m_get(slirp);
+        if (!m)
+            return;
+        /* Note: we add to align the IP header */
+        if (M_FREEROOM(m) < pkt_len + 2) {
+            m_inc(m, pkt_len + 2);
+        }
+        m->m_len = pkt_len + 2;
+        memcpy(m->m_data + 2, pkt, pkt_len);
+
+        m->m_data += 2 + ETH_HLEN;
+        m->m_len -= 2 + ETH_HLEN;
+
+        ip_input(m);
+        break;
+    default:
+        break;
+    }
+}
+
+/* output the IP packet to the ethernet device */
+void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
+{
+    uint8_t buf[1600];
+    struct ethhdr *eh = (struct ethhdr *)buf;
+
+    if (ip_data_len + ETH_HLEN > sizeof(buf))
+        return;
+    
+    if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
+        struct ethhdr *reh = (struct ethhdr *)arp_req;
+        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
+        const struct ip *iph = (const struct ip *)ip_data;
+
+        /* If the client addr is not known, there is no point in
+           sending the packet to it. Normally the sender should have
+           done an ARP request to get its MAC address. Here we do it
+           in place of sending the packet and we hope that the sender
+           will retry sending its packet. */
+        memset(reh->h_dest, 0xff, ETH_ALEN);
+        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+        memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
+        reh->h_proto = htons(ETH_P_ARP);
+        rah->ar_hrd = htons(1);
+        rah->ar_pro = htons(ETH_P_IP);
+        rah->ar_hln = ETH_ALEN;
+        rah->ar_pln = 4;
+        rah->ar_op = htons(ARPOP_REQUEST);
+        /* source hw addr */
+        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+        memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
+        /* source IP */
+        rah->ar_sip = slirp->vhost_addr.s_addr;
+        /* target hw addr (none) */
+        memset(rah->ar_tha, 0, ETH_ALEN);
+        /* target IP */
+        rah->ar_tip = iph->ip_dst.s_addr;
+        slirp->client_ipaddr = iph->ip_dst;
+        slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+    } else {
+        memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
+        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
+        /* XXX: not correct */
+        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
+        eh->h_proto = htons(ETH_P_IP);
+        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
+        slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
+    }
+}
+
+/* Drop host forwarding rule, return 0 if found. */
+int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
+                         int host_port)
+{
+    struct socket *so;
+    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
+    struct sockaddr_in addr;
+    int port = htons(host_port);
+    socklen_t addr_len;
+
+    for (so = head->so_next; so != head; so = so->so_next) {
+        addr_len = sizeof(addr);
+        if ((so->so_state & SS_HOSTFWD) &&
+            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
+            addr.sin_addr.s_addr == host_addr.s_addr &&
+            addr.sin_port == port) {
+            close(so->s);
+            sofree(so);
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
+                      int host_port, struct in_addr guest_addr, int guest_port)
+{
+    if (!guest_addr.s_addr) {
+        guest_addr = slirp->vdhcp_startaddr;
+    }
+    if (is_udp) {
+        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
+                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
+            return -1;
+    } else {
+        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
+                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
+            return -1;
+    }
+    return 0;
+}
+
+int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
+                   struct in_addr *guest_addr, int guest_port)
+{
+    if (!guest_addr->s_addr) {
+        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
+            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
+    }
+    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
+        slirp->vnetwork_addr.s_addr ||
+        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
+        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
+        return -1;
+    }
+    return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
+                    htons(guest_port));
+}
+
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
+{
+	if (so->s == -1 && so->extra) {
+		qemu_chr_write(so->extra, buf, len);
+		return len;
+	}
+
+	return send(so->s, buf, len, flags);
+}
+
+static struct socket *
+slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
+{
+    struct socket *so;
+
+    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
+        if (so->so_faddr.s_addr == guest_addr.s_addr &&
+            htons(so->so_fport) == guest_port) {
+            return so;
+        }
+    }
+    return NULL;
+}
+
+size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
+                             int guest_port)
+{
+	struct iovec iov[2];
+	struct socket *so;
+
+	so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+
+	if (!so || so->so_state & SS_NOFDREF)
+		return 0;
+
+	if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
+		return 0;
+
+	return sopreprbuf(so, iov, NULL);
+}
+
+void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
+                       const uint8_t *buf, int size)
+{
+    int ret;
+    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+
+    if (!so)
+        return;
+
+    ret = soreadbuf(so, (const char *)buf, size);
+
+    if (ret > 0)
+        tcp_output(sototcpcb(so));
+}
+
+static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    qemu_put_sbe16(f, tp->t_state);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        qemu_put_sbe16(f, tp->t_timer[i]);
+    qemu_put_sbe16(f, tp->t_rxtshift);
+    qemu_put_sbe16(f, tp->t_rxtcur);
+    qemu_put_sbe16(f, tp->t_dupacks);
+    qemu_put_be16(f, tp->t_maxseg);
+    qemu_put_sbyte(f, tp->t_force);
+    qemu_put_be16(f, tp->t_flags);
+    qemu_put_be32(f, tp->snd_una);
+    qemu_put_be32(f, tp->snd_nxt);
+    qemu_put_be32(f, tp->snd_up);
+    qemu_put_be32(f, tp->snd_wl1);
+    qemu_put_be32(f, tp->snd_wl2);
+    qemu_put_be32(f, tp->iss);
+    qemu_put_be32(f, tp->snd_wnd);
+    qemu_put_be32(f, tp->rcv_wnd);
+    qemu_put_be32(f, tp->rcv_nxt);
+    qemu_put_be32(f, tp->rcv_up);
+    qemu_put_be32(f, tp->irs);
+    qemu_put_be32(f, tp->rcv_adv);
+    qemu_put_be32(f, tp->snd_max);
+    qemu_put_be32(f, tp->snd_cwnd);
+    qemu_put_be32(f, tp->snd_ssthresh);
+    qemu_put_sbe16(f, tp->t_idle);
+    qemu_put_sbe16(f, tp->t_rtt);
+    qemu_put_be32(f, tp->t_rtseq);
+    qemu_put_sbe16(f, tp->t_srtt);
+    qemu_put_sbe16(f, tp->t_rttvar);
+    qemu_put_be16(f, tp->t_rttmin);
+    qemu_put_be32(f, tp->max_sndwnd);
+    qemu_put_byte(f, tp->t_oobflags);
+    qemu_put_byte(f, tp->t_iobc);
+    qemu_put_sbe16(f, tp->t_softerror);
+    qemu_put_byte(f, tp->snd_scale);
+    qemu_put_byte(f, tp->rcv_scale);
+    qemu_put_byte(f, tp->request_r_scale);
+    qemu_put_byte(f, tp->requested_s_scale);
+    qemu_put_be32(f, tp->ts_recent);
+    qemu_put_be32(f, tp->ts_recent_age);
+    qemu_put_be32(f, tp->last_ack_sent);
+}
+
+static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off;
+
+    qemu_put_be32(f, sbuf->sb_cc);
+    qemu_put_be32(f, sbuf->sb_datalen);
+    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+}
+
+static void slirp_socket_save(QEMUFile *f, struct socket *so)
+{
+    qemu_put_be32(f, so->so_urgc);
+    qemu_put_be32(f, so->so_faddr.s_addr);
+    qemu_put_be32(f, so->so_laddr.s_addr);
+    qemu_put_be16(f, so->so_fport);
+    qemu_put_be16(f, so->so_lport);
+    qemu_put_byte(f, so->so_iptos);
+    qemu_put_byte(f, so->so_emu);
+    qemu_put_byte(f, so->so_type);
+    qemu_put_be32(f, so->so_state);
+    slirp_sbuf_save(f, &so->so_rcv);
+    slirp_sbuf_save(f, &so->so_snd);
+    slirp_tcp_save(f, so->so_tcpcb);
+}
+
+static void slirp_bootp_save(QEMUFile *f, Slirp *slirp)
+{
+    int i;
+
+    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        qemu_put_be16(f, slirp->bootp_clients[i].allocated);
+        qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6);
+    }
+}
+
+static void slirp_state_save(QEMUFile *f, void *opaque)
+{
+    Slirp *slirp = opaque;
+    struct ex_list *ex_ptr;
+
+    for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+        if (ex_ptr->ex_pty == 3) {
+            struct socket *so;
+            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
+                                       ntohs(ex_ptr->ex_fport));
+            if (!so)
+                continue;
+
+            qemu_put_byte(f, 42);
+            slirp_socket_save(f, so);
+        }
+    qemu_put_byte(f, 0);
+
+    qemu_put_be16(f, slirp->ip_id);
+
+    slirp_bootp_save(f, slirp);
+}
+
+static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    tp->t_state = qemu_get_sbe16(f);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        tp->t_timer[i] = qemu_get_sbe16(f);
+    tp->t_rxtshift = qemu_get_sbe16(f);
+    tp->t_rxtcur = qemu_get_sbe16(f);
+    tp->t_dupacks = qemu_get_sbe16(f);
+    tp->t_maxseg = qemu_get_be16(f);
+    tp->t_force = qemu_get_sbyte(f);
+    tp->t_flags = qemu_get_be16(f);
+    tp->snd_una = qemu_get_be32(f);
+    tp->snd_nxt = qemu_get_be32(f);
+    tp->snd_up = qemu_get_be32(f);
+    tp->snd_wl1 = qemu_get_be32(f);
+    tp->snd_wl2 = qemu_get_be32(f);
+    tp->iss = qemu_get_be32(f);
+    tp->snd_wnd = qemu_get_be32(f);
+    tp->rcv_wnd = qemu_get_be32(f);
+    tp->rcv_nxt = qemu_get_be32(f);
+    tp->rcv_up = qemu_get_be32(f);
+    tp->irs = qemu_get_be32(f);
+    tp->rcv_adv = qemu_get_be32(f);
+    tp->snd_max = qemu_get_be32(f);
+    tp->snd_cwnd = qemu_get_be32(f);
+    tp->snd_ssthresh = qemu_get_be32(f);
+    tp->t_idle = qemu_get_sbe16(f);
+    tp->t_rtt = qemu_get_sbe16(f);
+    tp->t_rtseq = qemu_get_be32(f);
+    tp->t_srtt = qemu_get_sbe16(f);
+    tp->t_rttvar = qemu_get_sbe16(f);
+    tp->t_rttmin = qemu_get_be16(f);
+    tp->max_sndwnd = qemu_get_be32(f);
+    tp->t_oobflags = qemu_get_byte(f);
+    tp->t_iobc = qemu_get_byte(f);
+    tp->t_softerror = qemu_get_sbe16(f);
+    tp->snd_scale = qemu_get_byte(f);
+    tp->rcv_scale = qemu_get_byte(f);
+    tp->request_r_scale = qemu_get_byte(f);
+    tp->requested_s_scale = qemu_get_byte(f);
+    tp->ts_recent = qemu_get_be32(f);
+    tp->ts_recent_age = qemu_get_be32(f);
+    tp->last_ack_sent = qemu_get_be32(f);
+    tcp_template(tp);
+}
+
+static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off, sb_cc, sb_datalen;
+
+    sb_cc = qemu_get_be32(f);
+    sb_datalen = qemu_get_be32(f);
+
+    sbreserve(sbuf, sb_datalen);
+
+    if (sbuf->sb_datalen != sb_datalen)
+        return -ENOMEM;
+
+    sbuf->sb_cc = sb_cc;
+
+    off = qemu_get_sbe32(f);
+    sbuf->sb_wptr = sbuf->sb_data + off;
+    off = qemu_get_sbe32(f);
+    sbuf->sb_rptr = sbuf->sb_data + off;
+    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+
+    return 0;
+}
+
+static int slirp_socket_load(QEMUFile *f, struct socket *so)
+{
+    if (tcp_attach(so) < 0)
+        return -ENOMEM;
+
+    so->so_urgc = qemu_get_be32(f);
+    so->so_faddr.s_addr = qemu_get_be32(f);
+    so->so_laddr.s_addr = qemu_get_be32(f);
+    so->so_fport = qemu_get_be16(f);
+    so->so_lport = qemu_get_be16(f);
+    so->so_iptos = qemu_get_byte(f);
+    so->so_emu = qemu_get_byte(f);
+    so->so_type = qemu_get_byte(f);
+    so->so_state = qemu_get_be32(f);
+    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
+        return -ENOMEM;
+    if (slirp_sbuf_load(f, &so->so_snd) < 0)
+        return -ENOMEM;
+    slirp_tcp_load(f, so->so_tcpcb);
+
+    return 0;
+}
+
+static void slirp_bootp_load(QEMUFile *f, Slirp *slirp)
+{
+    int i;
+
+    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        slirp->bootp_clients[i].allocated = qemu_get_be16(f);
+        qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6);
+    }
+}
+
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
+{
+    Slirp *slirp = opaque;
+    struct ex_list *ex_ptr;
+
+    while (qemu_get_byte(f)) {
+        int ret;
+        struct socket *so = socreate(slirp);
+
+        if (!so)
+            return -ENOMEM;
+
+        ret = slirp_socket_load(f, so);
+
+        if (ret < 0)
+            return ret;
+
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
+            slirp->vnetwork_addr.s_addr) {
+            return -EINVAL;
+        }
+        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+            if (ex_ptr->ex_pty == 3 &&
+                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
+                so->so_fport == ex_ptr->ex_fport) {
+                break;
+            }
+        }
+        if (!ex_ptr)
+            return -EINVAL;
+
+        so->extra = (void *)ex_ptr->ex_exec;
+    }
+
+    if (version_id >= 2) {
+        slirp->ip_id = qemu_get_be16(f);
+    }
+
+    if (version_id >= 3) {
+        slirp_bootp_load(f, slirp);
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/slirp/slirp.h b/qemu-0.15.x/slirp/slirp.h
new file mode 100644
index 0000000..16bb6ba
--- /dev/null
+++ b/qemu-0.15.x/slirp/slirp.h
@@ -0,0 +1,325 @@
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include "config-host.h"
+#include "slirp_config.h"
+
+#ifdef _WIN32
+# include <inttypes.h>
+
+typedef char *caddr_t;
+
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <sys/timeb.h>
+# include <iphlpapi.h>
+
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# define EINPROGRESS WSAEINPROGRESS
+# define ENOTCONN WSAENOTCONN
+# define EHOSTUNREACH WSAEHOSTUNREACH
+# define ENETUNREACH WSAENETUNREACH
+# define ECONNREFUSED WSAECONNREFUSED
+#else
+# define ioctlsocket ioctl
+# define closesocket(s) close(s)
+# if !defined(__HAIKU__)
+#  define O_BINARY 0
+# endif
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+
+#include <sys/time.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef HAVE_MEMMOVE
+#define memmove(x, y, z) bcopy(y, x, z)
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/uio.h>
+#endif
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+/* Systems lacking strdup() definition in <string.h>. */
+#if defined(ultrix)
+char *strdup(const char *);
+#endif
+
+/* Systems lacking malloc() definition in <stdlib.h>. */
+#if defined(ultrix) || defined(hcx)
+void *malloc(size_t arg);
+void free(void *ptr);
+#endif
+
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *cp, struct in_addr *ia);
+#endif
+
+#include <fcntl.h>
+#ifndef NO_UNIX_SOCKETS
+#include <sys/un.h>
+#endif
+#include <signal.h>
+#ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+#endif
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+
+#if defined(HAVE_SYS_IOCTL_H)
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#ifdef USE_PPP
+#include <ppp/slirppp.h>
+#endif
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <sys/stat.h>
+
+/* Avoid conflicting with the libc insque() and remque(), which
+   have different prototypes. */
+#define insque slirp_insque
+#define remque slirp_remque
+
+#ifdef HAVE_SYS_STROPTS_H
+#include <sys/stropts.h>
+#endif
+
+#include "debug.h"
+
+#include "qemu-queue.h"
+
+#include "libslirp.h"
+#include "ip.h"
+#include "tcp.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "udp.h"
+#include "ip_icmp.h"
+#include "mbuf.h"
+#include "sbuf.h"
+#include "socket.h"
+#include "if.h"
+#include "main.h"
+#include "misc.h"
+#ifdef USE_PPP
+#include "ppp/pppd.h"
+#include "ppp/ppp.h"
+#endif
+
+#include "bootp.h"
+#include "tftp.h"
+
+/* osdep.c */
+int qemu_socket(int domain, int type, int protocol);
+
+
+struct Slirp {
+    QTAILQ_ENTRY(Slirp) entry;
+
+    /* virtual network configuration */
+    struct in_addr vnetwork_addr;
+    struct in_addr vnetwork_mask;
+    struct in_addr vhost_addr;
+    struct in_addr vdhcp_startaddr;
+    struct in_addr vnameserver_addr;
+
+    /* ARP cache for the guest IP addresses (XXX: allow many entries) */
+    uint8_t client_ethaddr[6];
+
+    struct in_addr client_ipaddr;
+    char client_hostname[33];
+
+    int restricted;
+    struct timeval tt;
+    struct ex_list *exec_list;
+
+    /* mbuf states */
+    struct mbuf m_freelist, m_usedlist;
+    int mbuf_alloced;
+
+    /* if states */
+    int if_queued;          /* number of packets queued so far */
+    struct mbuf if_fastq;   /* fast queue (for interactive data) */
+    struct mbuf if_batchq;  /* queue for non-interactive data */
+    struct mbuf *next_m;    /* pointer to next mbuf to output */
+
+    /* ip states */
+    struct ipq ipq;         /* ip reass. queue */
+    uint16_t ip_id;         /* ip packet ctr, for ids */
+
+    /* bootp/dhcp states */
+    BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
+    char *bootp_filename;
+
+    /* tcp states */
+    struct socket tcb;
+    struct socket *tcp_last_so;
+    tcp_seq tcp_iss;        /* tcp initial send seq # */
+    uint32_t tcp_now;       /* for RFC 1323 timestamps */
+
+    /* udp states */
+    struct socket udb;
+    struct socket *udp_last_so;
+
+    /* icmp states */
+    struct socket icmp;
+    struct socket *icmp_last_so;
+
+    /* tftp states */
+    char *tftp_prefix;
+    struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
+
+    void *opaque;
+};
+
+extern Slirp *slirp_instance;
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+#ifndef FULL_BOLT
+void if_start(Slirp *);
+#else
+void if_start(struct ttys *);
+#endif
+
+#ifndef HAVE_STRERROR
+ char *strerror(int error);
+#endif
+
+#ifndef HAVE_INDEX
+ char *index(const char *, int);
+#endif
+
+#ifndef HAVE_GETHOSTID
+ long gethostid(void);
+#endif
+
+void lprint(const char *, ...) GCC_FMT_ATTR(1, 2);
+
+#ifndef _WIN32
+#include <netdb.h>
+#endif
+
+#define DEFAULT_BAUD 115200
+
+#define SO_OPTIONS DO_KEEPALIVE
+#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
+
+/* cksum.c */
+int cksum(struct mbuf *m, int len);
+
+/* if.c */
+void if_init(Slirp *);
+void if_output(struct socket *, struct mbuf *);
+
+/* ip_input.c */
+void ip_init(Slirp *);
+void ip_input(struct mbuf *);
+void ip_slowtimo(Slirp *);
+void ip_stripoptions(register struct mbuf *, struct mbuf *);
+
+/* ip_output.c */
+int ip_output(struct socket *, struct mbuf *);
+
+/* tcp_input.c */
+void tcp_input(register struct mbuf *, int, struct socket *);
+int tcp_mss(register struct tcpcb *, u_int);
+
+/* tcp_output.c */
+int tcp_output(register struct tcpcb *);
+void tcp_setpersist(register struct tcpcb *);
+
+/* tcp_subr.c */
+void tcp_init(Slirp *);
+void tcp_template(struct tcpcb *);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int);
+struct tcpcb * tcp_newtcpcb(struct socket *);
+struct tcpcb * tcp_close(register struct tcpcb *);
+void tcp_sockclosed(struct tcpcb *);
+int tcp_fconnect(struct socket *);
+void tcp_connect(struct socket *);
+int tcp_attach(struct socket *);
+uint8_t tcp_tos(struct socket *);
+int tcp_emu(struct socket *, struct mbuf *);
+int tcp_ctl(struct socket *);
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
+
+#ifdef USE_PPP
+#define MIN_MRU MINMRU
+#define MAX_MRU MAXMRU
+#else
+#define MIN_MRU 128
+#define MAX_MRU 16384
+#endif
+
+#ifndef _WIN32
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#define max(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+#ifdef _WIN32
+#undef errno
+#define errno (WSAGetLastError())
+#endif
+
+#endif
diff --git a/qemu-0.15.x/slirp/slirp_config.h b/qemu-0.15.x/slirp/slirp_config.h
new file mode 100644
index 0000000..18db45c
--- /dev/null
+++ b/qemu-0.15.x/slirp/slirp_config.h
@@ -0,0 +1,188 @@
+/*
+ * User definable configuration options
+ */
+
+/* Define if you want the connection to be probed */
+/* XXX Not working yet, so ignore this for now */
+#undef PROBE_CONN
+
+/* Define to 1 if you want KEEPALIVE timers */
+#define DO_KEEPALIVE 0
+
+/* Define to MAX interfaces you expect to use at once */
+/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */
+/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */
+#define MAX_INTERFACES 1
+#define MAX_PPP_INTERFACES 1
+
+/* Define if you want slirp's socket in /tmp */
+/* XXXXXX Do this in ./configure */
+#undef USE_TMPSOCKET
+
+/* Define if you want slirp to use cfsetXspeed() on the terminal */
+#undef DO_CFSETSPEED
+
+/* Define this if you want slirp to write to the tty as fast as it can */
+/* This should only be set if you are using load-balancing, slirp does a */
+/* pretty good job on single modems already, and seting this will make */
+/* interactive sessions less responsive */
+/* XXXXX Talk about having fast modem as unit 0 */
+#undef FULL_BOLT
+
+/*
+ * Define if you want slirp to use less CPU
+ * You will notice a small lag in interactive sessions, but it's not that bad
+ * Things like Netscape/ftp/etc. are completely unaffected
+ * This is mainly for sysadmins who have many slirp users
+ */
+#undef USE_LOWCPU
+
+/* Define this if your compiler doesn't like prototypes */
+#ifndef __STDC__
+#define NO_PROTOTYPES
+#endif
+
+/*********************************************************/
+/*
+ * Autoconf defined configuration options
+ * You shouldn't need to touch any of these
+ */
+
+/* Ignore this */
+#undef DUMMY_PPP
+
+/* Define if you have unistd.h */
+#define HAVE_UNISTD_H
+
+/* Define if you have stdlib.h */
+#define HAVE_STDLIB_H
+
+/* Define if you have sys/ioctl.h */
+#undef HAVE_SYS_IOCTL_H
+#ifndef _WIN32
+#define HAVE_SYS_IOCTL_H
+#endif
+
+/* Define if you have sys/filio.h */
+#undef HAVE_SYS_FILIO_H
+#ifdef __APPLE__
+#define HAVE_SYS_FILIO_H
+#endif
+
+/* Define if you have strerror */
+#define HAVE_STRERROR
+
+/* Define if you have strdup() */
+#define HAVE_STRDUP
+
+/* Define according to how time.h should be included */
+#define TIME_WITH_SYS_TIME 0
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have sys/bitypes.h */
+#undef HAVE_SYS_BITYPES_H
+
+/* Define if the machine is big endian */
+//#undef HOST_WORDS_BIGENDIAN
+
+/* Define if you have readv */
+#undef HAVE_READV
+
+/* Define if iovec needs to be declared */
+#undef DECLARE_IOVEC
+#ifdef _WIN32
+#define DECLARE_IOVEC
+#endif
+
+/* Define if you have a POSIX.1 sys/wait.h */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have sys/select.h */
+#undef HAVE_SYS_SELECT_H
+#ifndef _WIN32
+#define HAVE_SYS_SELECT_H
+#endif
+
+/* Define if you have strings.h */
+#define HAVE_STRING_H
+
+/* Define if you have arpa/inet.h */
+#undef HAVE_ARPA_INET_H
+#ifndef _WIN32
+#define HAVE_ARPA_INET_H
+#endif
+
+/* Define if you have sys/signal.h */
+#undef HAVE_SYS_SIGNAL_H
+
+/* Define if you have sys/stropts.h */
+#undef HAVE_SYS_STROPTS_H
+
+/* Define to whatever your compiler thinks inline should be */
+//#define inline inline
+
+/* Define to whatever your compiler thinks const should be */
+//#define const const
+
+/* Define if your compiler doesn't like prototypes */
+#undef NO_PROTOTYPES
+
+/* Define to sizeof(char) */
+#define SIZEOF_CHAR 1
+
+/* Define to sizeof(short) */
+#define SIZEOF_SHORT 2
+
+/* Define to sizeof(int) */
+#define SIZEOF_INT 4
+
+/* Define to sizeof(char *) */
+#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8)
+
+/* Define if you have random() */
+#undef HAVE_RANDOM
+
+/* Define if you have srandom() */
+#undef HAVE_SRANDOM
+
+/* Define if you have inet_aton */
+#undef HAVE_INET_ATON
+#ifndef _WIN32
+#define HAVE_INET_ATON
+#endif
+
+/* Define if you have setenv */
+#undef HAVE_SETENV
+
+/* Define if you have index() */
+#define HAVE_INDEX
+
+/* Define if you have bcmp() */
+#undef HAVE_BCMP
+
+/* Define if you have drand48 */
+#undef HAVE_DRAND48
+
+/* Define if you have memmove */
+#define HAVE_MEMMOVE
+
+/* Define if you have gethostid */
+#define HAVE_GETHOSTID
+
+/* Define if you DON'T have unix-domain sockets */
+#undef NO_UNIX_SOCKETS
+#ifdef _WIN32
+#define NO_UNIX_SOCKETS
+#endif
+
+/* Define if you have revoke() */
+#undef HAVE_REVOKE
+
+/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */
+#undef HAVE_GRANTPT
+
+/* Define if you have fchmod */
+#undef HAVE_FCHMOD
+
+/* Define if you have <sys/type32.h> */
+#undef HAVE_SYS_TYPES32_H
diff --git a/qemu-0.15.x/slirp/socket.c b/qemu-0.15.x/slirp/socket.c
new file mode 100644
index 0000000..77b0c98
--- /dev/null
+++ b/qemu-0.15.x/slirp/socket.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "qemu-common.h"
+#include <slirp.h>
+#include "ip_icmp.h"
+#ifdef __sun__
+#include <sys/filio.h>
+#endif
+
+static void sofcantrcvmore(struct socket *so);
+static void sofcantsendmore(struct socket *so);
+
+struct socket *
+solookup(struct socket *head, struct in_addr laddr, u_int lport,
+         struct in_addr faddr, u_int fport)
+{
+	struct socket *so;
+
+	for (so = head->so_next; so != head; so = so->so_next) {
+		if (so->so_lport == lport &&
+		    so->so_laddr.s_addr == laddr.s_addr &&
+		    so->so_faddr.s_addr == faddr.s_addr &&
+		    so->so_fport == fport)
+		   break;
+	}
+
+	if (so == head)
+	   return (struct socket *)NULL;
+	return so;
+
+}
+
+/*
+ * Create a new socket, initialise the fields
+ * It is the responsibility of the caller to
+ * insque() it into the correct linked-list
+ */
+struct socket *
+socreate(Slirp *slirp)
+{
+  struct socket *so;
+
+  so = (struct socket *)malloc(sizeof(struct socket));
+  if(so) {
+    memset(so, 0, sizeof(struct socket));
+    so->so_state = SS_NOFDREF;
+    so->s = -1;
+    so->slirp = slirp;
+  }
+  return(so);
+}
+
+/*
+ * remque and free a socket, clobber cache
+ */
+void
+sofree(struct socket *so)
+{
+  Slirp *slirp = so->slirp;
+
+  if (so->so_emu==EMU_RSH && so->extra) {
+	sofree(so->extra);
+	so->extra=NULL;
+  }
+  if (so == slirp->tcp_last_so) {
+      slirp->tcp_last_so = &slirp->tcb;
+  } else if (so == slirp->udp_last_so) {
+      slirp->udp_last_so = &slirp->udb;
+  } else if (so == slirp->icmp_last_so) {
+      slirp->icmp_last_so = &slirp->icmp;
+  }
+  m_free(so->so_m);
+
+  if(so->so_next && so->so_prev)
+    remque(so);  /* crashes if so is not in a queue */
+
+  free(so);
+}
+
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
+{
+	int n, lss, total;
+	struct sbuf *sb = &so->so_snd;
+	int len = sb->sb_datalen - sb->sb_cc;
+	int mss = so->so_tcpcb->t_maxseg;
+
+	DEBUG_CALL("sopreprbuf");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	if (len <= 0)
+		return 0;
+
+	iov[0].iov_base = sb->sb_wptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
+	if (sb->sb_wptr < sb->sb_rptr) {
+		iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
+		/* Should never succeed, but... */
+		if (iov[0].iov_len > len)
+		   iov[0].iov_len = len;
+		if (iov[0].iov_len > mss)
+		   iov[0].iov_len -= iov[0].iov_len%mss;
+		n = 1;
+	} else {
+		iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
+		/* Should never succeed, but... */
+		if (iov[0].iov_len > len) iov[0].iov_len = len;
+		len -= iov[0].iov_len;
+		if (len) {
+			iov[1].iov_base = sb->sb_data;
+			iov[1].iov_len = sb->sb_rptr - sb->sb_data;
+			if(iov[1].iov_len > len)
+			   iov[1].iov_len = len;
+			total = iov[0].iov_len + iov[1].iov_len;
+			if (total > mss) {
+				lss = total%mss;
+				if (iov[1].iov_len > lss) {
+					iov[1].iov_len -= lss;
+					n = 2;
+				} else {
+					lss -= iov[1].iov_len;
+					iov[0].iov_len -= lss;
+					n = 1;
+				}
+			} else
+				n = 2;
+		} else {
+			if (iov[0].iov_len > mss)
+			   iov[0].iov_len -= iov[0].iov_len%mss;
+			n = 1;
+		}
+	}
+	if (np)
+		*np = n;
+
+	return iov[0].iov_len + (n - 1) * iov[1].iov_len;
+}
+
+/*
+ * Read from so's socket into sb_snd, updating all relevant sbuf fields
+ * NOTE: This will only be called if it is select()ed for reading, so
+ * a read() of 0 (or less) means it's disconnected
+ */
+int
+soread(struct socket *so)
+{
+	int n, nn;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soread");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	sopreprbuf(so, iov, &n);
+
+#ifdef HAVE_READV
+	nn = readv(so->s, (struct iovec *)iov, n);
+	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
+#else
+	nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
+#endif
+	if (nn <= 0) {
+		if (nn < 0 && (errno == EINTR || errno == EAGAIN))
+			return 0;
+		else {
+			DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
+			sofcantrcvmore(so);
+			tcp_sockclosed(sototcpcb(so));
+			return -1;
+		}
+	}
+
+#ifndef HAVE_READV
+	/*
+	 * If there was no error, try and read the second time round
+	 * We read again if n = 2 (ie, there's another part of the buffer)
+	 * and we read as much as we could in the first read
+	 * We don't test for <= 0 this time, because there legitimately
+	 * might not be any more data (since the socket is non-blocking),
+	 * a close will be detected on next iteration.
+	 * A return of -1 wont (shouldn't) happen, since it didn't happen above
+	 */
+	if (n == 2 && nn == iov[0].iov_len) {
+            int ret;
+            ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+            if (ret > 0)
+                nn += ret;
+        }
+
+	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
+#endif
+
+	/* Update fields */
+	sb->sb_cc += nn;
+	sb->sb_wptr += nn;
+	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_wptr -= sb->sb_datalen;
+	return nn;
+}
+
+int soreadbuf(struct socket *so, const char *buf, int size)
+{
+    int n, nn, copy = size;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soreadbuf");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	if (sopreprbuf(so, iov, &n) < size)
+        goto err;
+
+    nn = MIN(iov[0].iov_len, copy);
+    memcpy(iov[0].iov_base, buf, nn);
+
+    copy -= nn;
+    buf += nn;
+
+    if (copy == 0)
+        goto done;
+
+    memcpy(iov[1].iov_base, buf, copy);
+
+done:
+    /* Update fields */
+	sb->sb_cc += size;
+	sb->sb_wptr += size;
+	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_wptr -= sb->sb_datalen;
+    return size;
+err:
+
+    sofcantrcvmore(so);
+    tcp_sockclosed(sototcpcb(so));
+    fprintf(stderr, "soreadbuf buffer to small");
+    return -1;
+}
+
+/*
+ * Get urgent data
+ *
+ * When the socket is created, we set it SO_OOBINLINE,
+ * so when OOB data arrives, we soread() it and everything
+ * in the send buffer is sent as urgent data
+ */
+void
+sorecvoob(struct socket *so)
+{
+	struct tcpcb *tp = sototcpcb(so);
+
+	DEBUG_CALL("sorecvoob");
+	DEBUG_ARG("so = %lx", (long)so);
+
+	/*
+	 * We take a guess at how much urgent data has arrived.
+	 * In most situations, when urgent data arrives, the next
+	 * read() should get all the urgent data.  This guess will
+	 * be wrong however if more data arrives just after the
+	 * urgent data, or the read() doesn't return all the
+	 * urgent data.
+	 */
+	soread(so);
+	tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
+	tp->t_force = 1;
+	tcp_output(tp);
+	tp->t_force = 0;
+}
+
+/*
+ * Send urgent data
+ * There's a lot duplicated code here, but...
+ */
+int
+sosendoob(struct socket *so)
+{
+	struct sbuf *sb = &so->so_rcv;
+	char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
+
+	int n, len;
+
+	DEBUG_CALL("sosendoob");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
+
+	if (so->so_urgc > 2048)
+	   so->so_urgc = 2048; /* XXXX */
+
+	if (sb->sb_rptr < sb->sb_wptr) {
+		/* We can send it directly */
+		n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+		so->so_urgc -= n;
+
+		DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+	} else {
+		/*
+		 * Since there's no sendv or sendtov like writev,
+		 * we must copy all data to a linear buffer then
+		 * send it all
+		 */
+		len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+		if (len > so->so_urgc) len = so->so_urgc;
+		memcpy(buff, sb->sb_rptr, len);
+		so->so_urgc -= len;
+		if (so->so_urgc) {
+			n = sb->sb_wptr - sb->sb_data;
+			if (n > so->so_urgc) n = so->so_urgc;
+			memcpy((buff + len), sb->sb_data, n);
+			so->so_urgc -= n;
+			len += n;
+		}
+		n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+#ifdef DEBUG
+		if (n != len)
+		   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+#endif
+		DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+	}
+
+	sb->sb_cc -= n;
+	sb->sb_rptr += n;
+	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_rptr -= sb->sb_datalen;
+
+	return n;
+}
+
+/*
+ * Write data from so_rcv to so's socket,
+ * updating all sbuf field as necessary
+ */
+int
+sowrite(struct socket *so)
+{
+	int  n,nn;
+	struct sbuf *sb = &so->so_rcv;
+	int len = sb->sb_cc;
+	struct iovec iov[2];
+
+	DEBUG_CALL("sowrite");
+	DEBUG_ARG("so = %lx", (long)so);
+
+	if (so->so_urgc) {
+		sosendoob(so);
+		if (sb->sb_cc == 0)
+			return 0;
+	}
+
+	/*
+	 * No need to check if there's something to write,
+	 * sowrite wouldn't have been called otherwise
+	 */
+
+	iov[0].iov_base = sb->sb_rptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
+	if (sb->sb_rptr < sb->sb_wptr) {
+		iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
+		/* Should never succeed, but... */
+		if (iov[0].iov_len > len) iov[0].iov_len = len;
+		n = 1;
+	} else {
+		iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+		if (iov[0].iov_len > len) iov[0].iov_len = len;
+		len -= iov[0].iov_len;
+		if (len) {
+			iov[1].iov_base = sb->sb_data;
+			iov[1].iov_len = sb->sb_wptr - sb->sb_data;
+			if (iov[1].iov_len > len) iov[1].iov_len = len;
+			n = 2;
+		} else
+			n = 1;
+	}
+	/* Check if there's urgent data to send, and if so, send it */
+
+#ifdef HAVE_READV
+	nn = writev(so->s, (const struct iovec *)iov, n);
+
+	DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
+#else
+	nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
+#endif
+	/* This should never happen, but people tell me it does *shrug* */
+	if (nn < 0 && (errno == EAGAIN || errno == EINTR))
+		return 0;
+
+	if (nn <= 0) {
+		DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
+			so->so_state, errno));
+		sofcantsendmore(so);
+		tcp_sockclosed(sototcpcb(so));
+		return -1;
+	}
+
+#ifndef HAVE_READV
+	if (n == 2 && nn == iov[0].iov_len) {
+            int ret;
+            ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
+            if (ret > 0)
+                nn += ret;
+        }
+        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
+#endif
+
+	/* Update sbuf */
+	sb->sb_cc -= nn;
+	sb->sb_rptr += nn;
+	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_rptr -= sb->sb_datalen;
+
+	/*
+	 * If in DRAIN mode, and there's no more data, set
+	 * it CANTSENDMORE
+	 */
+	if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
+		sofcantsendmore(so);
+
+	return nn;
+}
+
+/*
+ * recvfrom() a UDP socket
+ */
+void
+sorecvfrom(struct socket *so)
+{
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(struct sockaddr_in);
+
+	DEBUG_CALL("sorecvfrom");
+	DEBUG_ARG("so = %lx", (long)so);
+
+	if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
+	  char buff[256];
+	  int len;
+
+	  len = recvfrom(so->s, buff, 256, 0,
+			 (struct sockaddr *)&addr, &addrlen);
+	  /* XXX Check if reply is "correct"? */
+
+	  if(len == -1 || len == 0) {
+	    u_char code=ICMP_UNREACH_PORT;
+
+	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
+	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
+
+	    DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
+			errno,strerror(errno)));
+	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
+	  } else {
+	    icmp_reflect(so->so_m);
+            so->so_m = NULL; /* Don't m_free() it again! */
+	  }
+	  /* No need for this socket anymore, udp_detach it */
+	  udp_detach(so);
+	} else {                            	/* A "normal" UDP packet */
+	  struct mbuf *m;
+          int len;
+#ifdef _WIN32
+          unsigned long n;
+#else
+          int n;
+#endif
+
+	  m = m_get(so->slirp);
+	  if (!m) {
+	      return;
+	  }
+	  m->m_data += IF_MAXLINKHDR;
+
+	  /*
+	   * XXX Shouldn't FIONREAD packets destined for port 53,
+	   * but I don't know the max packet size for DNS lookups
+	   */
+	  len = M_FREEROOM(m);
+	  /* if (so->so_fport != htons(53)) { */
+	  ioctlsocket(so->s, FIONREAD, &n);
+
+	  if (n > len) {
+	    n = (m->m_data - m->m_dat) + m->m_len + n + 1;
+	    m_inc(m, n);
+	    len = M_FREEROOM(m);
+	  }
+	  /* } */
+
+	  m->m_len = recvfrom(so->s, m->m_data, len, 0,
+			      (struct sockaddr *)&addr, &addrlen);
+	  DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
+		      m->m_len, errno,strerror(errno)));
+	  if(m->m_len<0) {
+	    u_char code=ICMP_UNREACH_PORT;
+
+	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
+	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
+
+	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
+	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
+	    m_free(m);
+	  } else {
+	  /*
+	   * Hack: domain name lookup will be used the most for UDP,
+	   * and since they'll only be used once there's no need
+	   * for the 4 minute (or whatever) timeout... So we time them
+	   * out much quicker (10 seconds  for now...)
+	   */
+	    if (so->so_expire) {
+	      if (so->so_fport == htons(53))
+		so->so_expire = curtime + SO_EXPIREFAST;
+	      else
+		so->so_expire = curtime + SO_EXPIRE;
+	    }
+
+	    /*
+	     * If this packet was destined for CTL_ADDR,
+	     * make it look like that's where it came from, done by udp_output
+	     */
+	    udp_output(so, m, &addr);
+	  } /* rx error */
+	} /* if ping packet */
+}
+
+/*
+ * sendto() a socket
+ */
+int
+sosendto(struct socket *so, struct mbuf *m)
+{
+	Slirp *slirp = so->slirp;
+	int ret;
+	struct sockaddr_in addr;
+
+	DEBUG_CALL("sosendto");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+
+        addr.sin_family = AF_INET;
+	if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+	    slirp->vnetwork_addr.s_addr) {
+	  /* It's an alias */
+	  if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+	    if (get_dns_addr(&addr.sin_addr) < 0)
+	      addr.sin_addr = loopback_addr;
+	  } else {
+	    addr.sin_addr = loopback_addr;
+	  }
+	} else
+	  addr.sin_addr = so->so_faddr;
+	addr.sin_port = so->so_fport;
+
+	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+
+	/* Don't care what port we get */
+	ret = sendto(so->s, m->m_data, m->m_len, 0,
+		     (struct sockaddr *)&addr, sizeof (struct sockaddr));
+	if (ret < 0)
+		return -1;
+
+	/*
+	 * Kill the socket if there's no reply in 4 minutes,
+	 * but only if it's an expirable socket
+	 */
+	if (so->so_expire)
+		so->so_expire = curtime + SO_EXPIRE;
+	so->so_state &= SS_PERSISTENT_MASK;
+	so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */
+	return 0;
+}
+
+/*
+ * Listen for incoming TCP connections
+ */
+struct socket *
+tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
+           u_int lport, int flags)
+{
+	struct sockaddr_in addr;
+	struct socket *so;
+	int s, opt = 1;
+	socklen_t addrlen = sizeof(addr);
+	memset(&addr, 0, addrlen);
+
+	DEBUG_CALL("tcp_listen");
+	DEBUG_ARG("haddr = %x", haddr);
+	DEBUG_ARG("hport = %d", hport);
+	DEBUG_ARG("laddr = %x", laddr);
+	DEBUG_ARG("lport = %d", lport);
+	DEBUG_ARG("flags = %x", flags);
+
+	so = socreate(slirp);
+	if (!so) {
+	  return NULL;
+	}
+
+	/* Don't tcp_attach... we don't need so_snd nor so_rcv */
+	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
+		free(so);
+		return NULL;
+	}
+	insque(so, &slirp->tcb);
+
+	/*
+	 * SS_FACCEPTONCE sockets must time out.
+	 */
+	if (flags & SS_FACCEPTONCE)
+	   so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
+
+	so->so_state &= SS_PERSISTENT_MASK;
+	so->so_state |= (SS_FACCEPTCONN | flags);
+	so->so_lport = lport; /* Kept in network format */
+	so->so_laddr.s_addr = laddr; /* Ditto */
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = haddr;
+	addr.sin_port = hport;
+
+	if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
+	    (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
+	    (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+	    (listen(s,1) < 0)) {
+		int tmperrno = errno; /* Don't clobber the real reason we failed */
+
+		close(s);
+		sofree(so);
+		/* Restore the real errno */
+#ifdef _WIN32
+		WSASetLastError(tmperrno);
+#else
+		errno = tmperrno;
+#endif
+		return NULL;
+	}
+	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+
+	getsockname(s,(struct sockaddr *)&addr,&addrlen);
+	so->so_fport = addr.sin_port;
+	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
+	   so->so_faddr = slirp->vhost_addr;
+	else
+	   so->so_faddr = addr.sin_addr;
+
+	so->s = s;
+	return so;
+}
+
+/*
+ * Various session state calls
+ * XXX Should be #define's
+ * The socket state stuff needs work, these often get call 2 or 3
+ * times each when only 1 was needed
+ */
+void
+soisfconnecting(struct socket *so)
+{
+	so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
+			  SS_FCANTSENDMORE|SS_FWDRAIN);
+	so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
+}
+
+void
+soisfconnected(struct socket *so)
+{
+	so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
+	so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
+}
+
+static void
+sofcantrcvmore(struct socket *so)
+{
+	if ((so->so_state & SS_NOFDREF) == 0) {
+		shutdown(so->s,0);
+		if(global_writefds) {
+		  FD_CLR(so->s,global_writefds);
+		}
+	}
+	so->so_state &= ~(SS_ISFCONNECTING);
+	if (so->so_state & SS_FCANTSENDMORE) {
+	   so->so_state &= SS_PERSISTENT_MASK;
+	   so->so_state |= SS_NOFDREF; /* Don't select it */
+	} else {
+	   so->so_state |= SS_FCANTRCVMORE;
+	}
+}
+
+static void
+sofcantsendmore(struct socket *so)
+{
+	if ((so->so_state & SS_NOFDREF) == 0) {
+            shutdown(so->s,1);           /* send FIN to fhost */
+            if (global_readfds) {
+                FD_CLR(so->s,global_readfds);
+            }
+            if (global_xfds) {
+                FD_CLR(so->s,global_xfds);
+            }
+	}
+	so->so_state &= ~(SS_ISFCONNECTING);
+	if (so->so_state & SS_FCANTRCVMORE) {
+	   so->so_state &= SS_PERSISTENT_MASK;
+	   so->so_state |= SS_NOFDREF; /* as above */
+	} else {
+	   so->so_state |= SS_FCANTSENDMORE;
+	}
+}
+
+/*
+ * Set write drain mode
+ * Set CANTSENDMORE once all data has been write()n
+ */
+void
+sofwdrain(struct socket *so)
+{
+	if (so->so_rcv.sb_cc)
+		so->so_state |= SS_FWDRAIN;
+	else
+		sofcantsendmore(so);
+}
diff --git a/qemu-0.15.x/slirp/socket.h b/qemu-0.15.x/slirp/socket.h
new file mode 100644
index 0000000..857b0da
--- /dev/null
+++ b/qemu-0.15.x/slirp/socket.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _SLIRP_SOCKET_H_
+#define _SLIRP_SOCKET_H_
+
+#define SO_EXPIRE 240000
+#define SO_EXPIREFAST 10000
+
+/*
+ * Our socket structure
+ */
+
+struct socket {
+  struct socket *so_next,*so_prev;      /* For a linked list of sockets */
+
+  int s;                           /* The actual socket */
+
+  Slirp *slirp;			   /* managing slirp instance */
+
+			/* XXX union these with not-yet-used sbuf params */
+  struct mbuf *so_m;	           /* Pointer to the original SYN packet,
+				    * for non-blocking connect()'s, and
+				    * PING reply's */
+  struct tcpiphdr *so_ti;	   /* Pointer to the original ti within
+				    * so_mconn, for non-blocking connections */
+  int so_urgc;
+  struct in_addr so_faddr;	   /* foreign host table entry */
+  struct in_addr so_laddr;	   /* local host table entry */
+  uint16_t so_fport;		   /* foreign port */
+  uint16_t so_lport;		   /* local port */
+
+  uint8_t	so_iptos;	/* Type of service */
+  uint8_t	so_emu;		/* Is the socket emulated? */
+
+  u_char	so_type;		/* Type of socket, UDP or TCP */
+  int	so_state;		/* internal state flags SS_*, below */
+
+  struct 	tcpcb *so_tcpcb;	/* pointer to TCP protocol control block */
+  u_int	so_expire;		/* When the socket will expire */
+
+  int	so_queued;		/* Number of packets queued from this socket */
+  int	so_nqueued;		/* Number of packets queued in a row
+				 * Used to determine when to "downgrade" a session
+					 * from fastq to batchq */
+
+  struct sbuf so_rcv;		/* Receive buffer */
+  struct sbuf so_snd;		/* Send buffer */
+  void * extra;			/* Extra pointer */
+};
+
+
+/*
+ * Socket state bits. (peer means the host on the Internet,
+ * local host means the host on the other end of the modem)
+ */
+#define SS_NOFDREF		0x001	/* No fd reference */
+
+#define SS_ISFCONNECTING	0x002	/* Socket is connecting to peer (non-blocking connect()'s) */
+#define SS_ISFCONNECTED		0x004	/* Socket is connected to peer */
+#define SS_FCANTRCVMORE		0x008	/* Socket can't receive more from peer (for half-closes) */
+#define SS_FCANTSENDMORE	0x010	/* Socket can't send more to peer (for half-closes) */
+#define SS_FWDRAIN		0x040	/* We received a FIN, drain data and set SS_FCANTSENDMORE */
+
+#define SS_CTL			0x080
+#define SS_FACCEPTCONN		0x100	/* Socket is accepting connections from a host on the internet */
+#define SS_FACCEPTONCE		0x200	/* If set, the SS_FACCEPTCONN socket will die after one accept */
+
+#define SS_PERSISTENT_MASK	0xf000	/* Unremovable state bits */
+#define SS_HOSTFWD		0x1000	/* Socket describes host->guest forwarding */
+#define SS_INCOMING		0x2000	/* Connection was initiated by a host on the internet */
+
+struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
+struct socket * socreate(Slirp *);
+void sofree(struct socket *);
+int soread(struct socket *);
+void sorecvoob(struct socket *);
+int sosendoob(struct socket *);
+int sowrite(struct socket *);
+void sorecvfrom(struct socket *);
+int sosendto(struct socket *, struct mbuf *);
+struct socket * tcp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
+                               int);
+void soisfconnecting(register struct socket *);
+void soisfconnected(register struct socket *);
+void sofwdrain(struct socket *);
+struct iovec; /* For win32 */
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
+int soreadbuf(struct socket *so, const char *buf, int size);
+
+#endif /* _SOCKET_H_ */
diff --git a/qemu-0.15.x/slirp/tcp.h b/qemu-0.15.x/slirp/tcp.h
new file mode 100644
index 0000000..9d06836
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)tcp.h	8.1 (Berkeley) 6/10/93
+ * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
+ */
+
+#ifndef _TCP_H_
+#define _TCP_H_
+
+typedef	uint32_t tcp_seq;
+
+#define      PR_SLOWHZ       2               /* 2 slow timeouts per second (approx) */
+#define      PR_FASTHZ       5               /* 5 fast timeouts per second (not important) */
+
+#define TCP_SNDSPACE 8192
+#define TCP_RCVSPACE 8192
+
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+struct tcphdr {
+	uint16_t th_sport;              /* source port */
+	uint16_t th_dport;              /* destination port */
+	tcp_seq	th_seq;			/* sequence number */
+	tcp_seq	th_ack;			/* acknowledgement number */
+#ifdef HOST_WORDS_BIGENDIAN
+	u_int	th_off:4,		/* data offset */
+		th_x2:4;		/* (unused) */
+#else
+	u_int	th_x2:4,		/* (unused) */
+		th_off:4;		/* data offset */
+#endif
+	uint8_t th_flags;
+#define	TH_FIN	0x01
+#define	TH_SYN	0x02
+#define	TH_RST	0x04
+#define	TH_PUSH	0x08
+#define	TH_ACK	0x10
+#define	TH_URG	0x20
+	uint16_t th_win;                /* window */
+	uint16_t th_sum;                /* checksum */
+	uint16_t th_urp;                /* urgent pointer */
+};
+
+#include "tcp_var.h"
+
+#define	TCPOPT_EOL		0
+#define	TCPOPT_NOP		1
+#define	TCPOPT_MAXSEG		2
+#define    TCPOLEN_MAXSEG		4
+#define TCPOPT_WINDOW		3
+#define    TCPOLEN_WINDOW		3
+#define TCPOPT_SACK_PERMITTED	4		/* Experimental */
+#define    TCPOLEN_SACK_PERMITTED	2
+#define TCPOPT_SACK		5		/* Experimental */
+#define TCPOPT_TIMESTAMP	8
+#define    TCPOLEN_TIMESTAMP		10
+#define    TCPOLEN_TSTAMP_APPA		(TCPOLEN_TIMESTAMP+2) /* appendix A */
+
+#define TCPOPT_TSTAMP_HDR	\
+    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ *
+ * We make this 1460 because we only care about Ethernet in the qemu context.
+ */
+#define	TCP_MSS	1460
+
+#define	TCP_MAXWIN	65535	/* largest value for (unscaled) window */
+
+#define TCP_MAX_WINSHIFT	14	/* maximum window shift */
+
+/*
+ * User-settable options (used with setsockopt).
+ *
+ * We don't use the system headers on unix because we have conflicting
+ * local structures. We can't avoid the system definitions on Windows,
+ * so we undefine them.
+ */
+#undef TCP_NODELAY
+#define	TCP_NODELAY	0x01	/* don't delay send to coalesce packets */
+#undef TCP_MAXSEG
+
+/*
+ * TCP FSM state definitions.
+ * Per RFC793, September, 1981.
+ */
+
+#define TCP_NSTATES     11
+
+#define TCPS_CLOSED             0       /* closed */
+#define TCPS_LISTEN             1       /* listening for connection */
+#define TCPS_SYN_SENT           2       /* active, have sent syn */
+#define TCPS_SYN_RECEIVED       3       /* have send and received syn */
+/* states < TCPS_ESTABLISHED are those where connections not established */
+#define TCPS_ESTABLISHED        4       /* established */
+#define TCPS_CLOSE_WAIT         5       /* rcvd fin, waiting for close */
+/* states > TCPS_CLOSE_WAIT are those where user has closed */
+#define TCPS_FIN_WAIT_1         6       /* have closed, sent fin */
+#define TCPS_CLOSING            7       /* closed xchd FIN; await FIN ACK */
+#define TCPS_LAST_ACK           8       /* had fin and close; await FIN ACK */
+/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
+#define TCPS_FIN_WAIT_2         9       /* have closed, fin is acked */
+#define TCPS_TIME_WAIT          10      /* in 2*msl quiet wait after close */
+
+#define TCPS_HAVERCVDSYN(s)     ((s) >= TCPS_SYN_RECEIVED)
+#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
+#define TCPS_HAVERCVDFIN(s)     ((s) >= TCPS_TIME_WAIT)
+
+/*
+ * TCP sequence numbers are 32 bit integers operated
+ * on with modular arithmetic.  These macros can be
+ * used to compare such integers.
+ */
+#define SEQ_LT(a,b)     ((int)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b)     ((int)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b)    ((int)((a)-(b)) >= 0)
+
+/*
+ * Macros to initialize tcp sequence numbers for
+ * send and receive from initial send and receive
+ * sequence numbers.
+ */
+#define tcp_rcvseqinit(tp) \
+     (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
+
+#define tcp_sendseqinit(tp) \
+    (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
+
+#define TCP_ISSINCR     (125*1024)      /* increment for tcp_iss each second */
+
+#endif
diff --git a/qemu-0.15.x/slirp/tcp_input.c b/qemu-0.15.x/slirp/tcp_input.c
new file mode 100644
index 0000000..c1214c0
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_input.c
@@ -0,0 +1,1487 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
+ *	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. 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.
+ *
+ *	@(#)tcp_input.c	8.5 (Berkeley) 4/10/94
+ * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include "ip_icmp.h"
+
+#define	TCPREXMTTHRESH 3
+
+#define TCP_PAWS_IDLE	(24 * 24 * 60 * 60 * PR_SLOWHZ)
+
+/* for modulo comparisons of timestamps */
+#define TSTMP_LT(a,b)	((int)((a)-(b)) < 0)
+#define TSTMP_GEQ(a,b)	((int)((a)-(b)) >= 0)
+
+/*
+ * Insert segment ti into reassembly queue of tcp with
+ * control block tp.  Return TH_FIN if reassembly now includes
+ * a segment with FIN.  The macro form does the common case inline
+ * (segment is the next to be received on an established connection,
+ * and the queue is empty), avoiding linkage into and removal
+ * from the queue and repetition of various conversions.
+ * Set DELACK for segments received in order, but ack immediately
+ * when segments are out of order (so fast retransmit can work).
+ */
+#ifdef TCP_ACK_HACK
+#define TCP_REASS(tp, ti, m, so, flags) {\
+       if ((ti)->ti_seq == (tp)->rcv_nxt && \
+           tcpfrag_list_empty(tp) && \
+           (tp)->t_state == TCPS_ESTABLISHED) {\
+               if (ti->ti_flags & TH_PUSH) \
+                       tp->t_flags |= TF_ACKNOW; \
+               else \
+                       tp->t_flags |= TF_DELACK; \
+               (tp)->rcv_nxt += (ti)->ti_len; \
+               flags = (ti)->ti_flags & TH_FIN; \
+               if (so->so_emu) { \
+		       if (tcp_emu((so),(m))) sbappend((so), (m)); \
+	       } else \
+	       	       sbappend((so), (m)); \
+	} else {\
+               (flags) = tcp_reass((tp), (ti), (m)); \
+               tp->t_flags |= TF_ACKNOW; \
+       } \
+}
+#else
+#define	TCP_REASS(tp, ti, m, so, flags) { \
+	if ((ti)->ti_seq == (tp)->rcv_nxt && \
+        tcpfrag_list_empty(tp) && \
+	    (tp)->t_state == TCPS_ESTABLISHED) { \
+		tp->t_flags |= TF_DELACK; \
+		(tp)->rcv_nxt += (ti)->ti_len; \
+		flags = (ti)->ti_flags & TH_FIN; \
+		if (so->so_emu) { \
+			if (tcp_emu((so),(m))) sbappend(so, (m)); \
+		} else \
+			sbappend((so), (m)); \
+	} else { \
+		(flags) = tcp_reass((tp), (ti), (m)); \
+		tp->t_flags |= TF_ACKNOW; \
+	} \
+}
+#endif
+static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
+                          struct tcpiphdr *ti);
+static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
+
+static int
+tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
+          struct mbuf *m)
+{
+	register struct tcpiphdr *q;
+	struct socket *so = tp->t_socket;
+	int flags;
+
+	/*
+	 * Call with ti==NULL after become established to
+	 * force pre-ESTABLISHED data up to user socket.
+	 */
+        if (ti == NULL)
+		goto present;
+
+	/*
+	 * Find a segment which begins after this one does.
+	 */
+	for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
+            q = tcpiphdr_next(q))
+		if (SEQ_GT(q->ti_seq, ti->ti_seq))
+			break;
+
+	/*
+	 * If there is a preceding segment, it may provide some of
+	 * our data already.  If so, drop the data from the incoming
+	 * segment.  If it provides all of our data, drop us.
+	 */
+	if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) {
+		register int i;
+		q = tcpiphdr_prev(q);
+		/* conversion to int (in i) handles seq wraparound */
+		i = q->ti_seq + q->ti_len - ti->ti_seq;
+		if (i > 0) {
+			if (i >= ti->ti_len) {
+				m_free(m);
+				/*
+				 * Try to present any queued data
+				 * at the left window edge to the user.
+				 * This is needed after the 3-WHS
+				 * completes.
+				 */
+				goto present;   /* ??? */
+			}
+			m_adj(m, i);
+			ti->ti_len -= i;
+			ti->ti_seq += i;
+		}
+		q = tcpiphdr_next(q);
+	}
+	ti->ti_mbuf = m;
+
+	/*
+	 * While we overlap succeeding segments trim them or,
+	 * if they are completely covered, dequeue them.
+	 */
+	while (!tcpfrag_list_end(q, tp)) {
+		register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
+		if (i <= 0)
+			break;
+		if (i < q->ti_len) {
+			q->ti_seq += i;
+			q->ti_len -= i;
+			m_adj(q->ti_mbuf, i);
+			break;
+		}
+		q = tcpiphdr_next(q);
+		m = tcpiphdr_prev(q)->ti_mbuf;
+		remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
+		m_free(m);
+	}
+
+	/*
+	 * Stick new segment in its place.
+	 */
+	insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q)));
+
+present:
+	/*
+	 * Present data to user, advancing rcv_nxt through
+	 * completed sequence space.
+	 */
+	if (!TCPS_HAVEESTABLISHED(tp->t_state))
+		return (0);
+	ti = tcpfrag_list_first(tp);
+	if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
+		return (0);
+	if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
+		return (0);
+	do {
+		tp->rcv_nxt += ti->ti_len;
+		flags = ti->ti_flags & TH_FIN;
+		remque(tcpiphdr2qlink(ti));
+		m = ti->ti_mbuf;
+		ti = tcpiphdr_next(ti);
+		if (so->so_state & SS_FCANTSENDMORE)
+			m_free(m);
+		else {
+			if (so->so_emu) {
+				if (tcp_emu(so,m)) sbappend(so, m);
+			} else
+				sbappend(so, m);
+		}
+	} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
+	return (flags);
+}
+
+/*
+ * TCP input routine, follows pages 65-76 of the
+ * protocol specification dated September, 1981 very closely.
+ */
+void
+tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
+{
+  	struct ip save_ip, *ip;
+	register struct tcpiphdr *ti;
+	caddr_t optp = NULL;
+	int optlen = 0;
+	int len, tlen, off;
+        register struct tcpcb *tp = NULL;
+	register int tiflags;
+        struct socket *so = NULL;
+	int todrop, acked, ourfinisacked, needoutput = 0;
+	int iss = 0;
+	u_long tiwin;
+	int ret;
+    struct ex_list *ex_ptr;
+    Slirp *slirp;
+
+	DEBUG_CALL("tcp_input");
+	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
+		    (long )m, iphlen, (long )inso ));
+
+	/*
+	 * If called with m == 0, then we're continuing the connect
+	 */
+	if (m == NULL) {
+		so = inso;
+		slirp = so->slirp;
+
+		/* Re-set a few variables */
+		tp = sototcpcb(so);
+		m = so->so_m;
+                so->so_m = NULL;
+		ti = so->so_ti;
+		tiwin = ti->ti_win;
+		tiflags = ti->ti_flags;
+
+		goto cont_conn;
+	}
+	slirp = m->slirp;
+
+	/*
+	 * Get IP and TCP header together in first mbuf.
+	 * Note: IP leaves IP header in first mbuf.
+	 */
+	ti = mtod(m, struct tcpiphdr *);
+	if (iphlen > sizeof(struct ip )) {
+	  ip_stripoptions(m, (struct mbuf *)0);
+	  iphlen=sizeof(struct ip );
+	}
+	/* XXX Check if too short */
+
+
+	/*
+	 * Save a copy of the IP header in case we want restore it
+	 * for sending an ICMP error message in response.
+	 */
+	ip=mtod(m, struct ip *);
+	save_ip = *ip;
+	save_ip.ip_len+= iphlen;
+
+	/*
+	 * Checksum extended TCP header and data.
+	 */
+	tlen = ((struct ip *)ti)->ip_len;
+        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	ti->ti_x1 = 0;
+	ti->ti_len = htons((uint16_t)tlen);
+	len = sizeof(struct ip ) + tlen;
+	if(cksum(m, len)) {
+	  goto drop;
+	}
+
+	/*
+	 * Check that TCP offset makes sense,
+	 * pull out TCP options and adjust length.		XXX
+	 */
+	off = ti->ti_off << 2;
+	if (off < sizeof (struct tcphdr) || off > tlen) {
+	  goto drop;
+	}
+	tlen -= off;
+	ti->ti_len = tlen;
+	if (off > sizeof (struct tcphdr)) {
+	  optlen = off - sizeof (struct tcphdr);
+	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+	}
+	tiflags = ti->ti_flags;
+
+	/*
+	 * Convert TCP protocol specific fields to host format.
+	 */
+	NTOHL(ti->ti_seq);
+	NTOHL(ti->ti_ack);
+	NTOHS(ti->ti_win);
+	NTOHS(ti->ti_urp);
+
+	/*
+	 * Drop TCP, IP headers and TCP options.
+	 */
+	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+
+    if (slirp->restricted) {
+        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+            if (ex_ptr->ex_fport == ti->ti_dport &&
+                ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
+                break;
+            }
+        }
+        if (!ex_ptr)
+            goto drop;
+    }
+	/*
+	 * Locate pcb for segment.
+	 */
+findso:
+	so = slirp->tcp_last_so;
+	if (so->so_fport != ti->ti_dport ||
+	    so->so_lport != ti->ti_sport ||
+	    so->so_laddr.s_addr != ti->ti_src.s_addr ||
+	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {
+		so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
+			       ti->ti_dst, ti->ti_dport);
+		if (so)
+			slirp->tcp_last_so = so;
+	}
+
+	/*
+	 * If the state is CLOSED (i.e., TCB does not exist) then
+	 * all data in the incoming segment is discarded.
+	 * If the TCB exists but is in CLOSED state, it is embryonic,
+	 * but should either do a listen or a connect soon.
+	 *
+	 * state == CLOSED means we've done socreate() but haven't
+	 * attached it to a protocol yet...
+	 *
+	 * XXX If a TCB does not exist, and the TH_SYN flag is
+	 * the only flag set, then create a session, mark it
+	 * as if it was LISTENING, and continue...
+	 */
+        if (so == NULL) {
+	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
+	    goto dropwithreset;
+
+	  if ((so = socreate(slirp)) == NULL)
+	    goto dropwithreset;
+	  if (tcp_attach(so) < 0) {
+	    free(so); /* Not sofree (if it failed, it's not insqued) */
+	    goto dropwithreset;
+	  }
+
+	  sbreserve(&so->so_snd, TCP_SNDSPACE);
+	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
+
+	  so->so_laddr = ti->ti_src;
+	  so->so_lport = ti->ti_sport;
+	  so->so_faddr = ti->ti_dst;
+	  so->so_fport = ti->ti_dport;
+
+	  if ((so->so_iptos = tcp_tos(so)) == 0)
+	    so->so_iptos = ((struct ip *)ti)->ip_tos;
+
+	  tp = sototcpcb(so);
+	  tp->t_state = TCPS_LISTEN;
+	}
+
+        /*
+         * If this is a still-connecting socket, this probably
+         * a retransmit of the SYN.  Whether it's a retransmit SYN
+	 * or something else, we nuke it.
+         */
+        if (so->so_state & SS_ISFCONNECTING)
+                goto drop;
+
+	tp = sototcpcb(so);
+
+	/* XXX Should never fail */
+        if (tp == NULL)
+		goto dropwithreset;
+	if (tp->t_state == TCPS_CLOSED)
+		goto drop;
+
+	tiwin = ti->ti_win;
+
+	/*
+	 * Segment received on connection.
+	 * Reset idle time and keep-alive timer.
+	 */
+	tp->t_idle = 0;
+	if (SO_OPTIONS)
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
+	else
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
+
+	/*
+	 * Process options if not in LISTEN state,
+	 * else do it below (after getting remote address).
+	 */
+	if (optp && tp->t_state != TCPS_LISTEN)
+		tcp_dooptions(tp, (u_char *)optp, optlen, ti);
+
+	/*
+	 * Header prediction: check for the two common cases
+	 * of a uni-directional data xfer.  If the packet has
+	 * no control flags, is in-sequence, the window didn't
+	 * change and we're not retransmitting, it's a
+	 * candidate.  If the length is zero and the ack moved
+	 * forward, we're the sender side of the xfer.  Just
+	 * free the data acked & wake any higher level process
+	 * that was blocked waiting for space.  If the length
+	 * is non-zero and the ack didn't move, we're the
+	 * receiver side.  If we're getting packets in-order
+	 * (the reassembly queue is empty), add the data to
+	 * the socket buffer and note that we need a delayed ack.
+	 *
+	 * XXX Some of these tests are not needed
+	 * eg: the tiwin == tp->snd_wnd prevents many more
+	 * predictions.. with no *real* advantage..
+	 */
+	if (tp->t_state == TCPS_ESTABLISHED &&
+	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+	    ti->ti_seq == tp->rcv_nxt &&
+	    tiwin && tiwin == tp->snd_wnd &&
+	    tp->snd_nxt == tp->snd_max) {
+		if (ti->ti_len == 0) {
+			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
+			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
+			    tp->snd_cwnd >= tp->snd_wnd) {
+				/*
+				 * this is a pure ack for outstanding data.
+				 */
+				if (tp->t_rtt &&
+				    SEQ_GT(ti->ti_ack, tp->t_rtseq))
+					tcp_xmit_timer(tp, tp->t_rtt);
+				acked = ti->ti_ack - tp->snd_una;
+				sbdrop(&so->so_snd, acked);
+				tp->snd_una = ti->ti_ack;
+				m_free(m);
+
+				/*
+				 * If all outstanding data are acked, stop
+				 * retransmit timer, otherwise restart timer
+				 * using current (possibly backed-off) value.
+				 * If process is waiting for space,
+				 * wakeup/selwakeup/signal.  If data
+				 * are ready to send, let tcp_output
+				 * decide between more output or persist.
+				 */
+				if (tp->snd_una == tp->snd_max)
+					tp->t_timer[TCPT_REXMT] = 0;
+				else if (tp->t_timer[TCPT_PERSIST] == 0)
+					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+
+				/*
+				 * This is called because sowwakeup might have
+				 * put data into so_snd.  Since we don't so sowwakeup,
+				 * we don't need this.. XXX???
+				 */
+				if (so->so_snd.sb_cc)
+					(void) tcp_output(tp);
+
+				return;
+			}
+		} else if (ti->ti_ack == tp->snd_una &&
+		    tcpfrag_list_empty(tp) &&
+		    ti->ti_len <= sbspace(&so->so_rcv)) {
+			/*
+			 * this is a pure, in-sequence data packet
+			 * with nothing on the reassembly queue and
+			 * we have enough buffer space to take it.
+			 */
+			tp->rcv_nxt += ti->ti_len;
+			/*
+			 * Add data to socket buffer.
+			 */
+			if (so->so_emu) {
+				if (tcp_emu(so,m)) sbappend(so, m);
+			} else
+				sbappend(so, m);
+
+			/*
+			 * If this is a short packet, then ACK now - with Nagel
+			 *	congestion avoidance sender won't send more until
+			 *	he gets an ACK.
+			 *
+			 * It is better to not delay acks at all to maximize
+			 * TCP throughput.  See RFC 2581.
+			 */
+			tp->t_flags |= TF_ACKNOW;
+			tcp_output(tp);
+			return;
+		}
+	} /* header prediction */
+	/*
+	 * Calculate amount of space in receive window,
+	 * and then do TCP input processing.
+	 * Receive window is amount of space in rcv queue,
+	 * but not less than advertised window.
+	 */
+	{ int win;
+          win = sbspace(&so->so_rcv);
+	  if (win < 0)
+	    win = 0;
+	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
+	}
+
+	switch (tp->t_state) {
+
+	/*
+	 * If the state is LISTEN then ignore segment if it contains an RST.
+	 * If the segment contains an ACK then it is bad and send a RST.
+	 * If it does not contain a SYN then it is not interesting; drop it.
+	 * Don't bother responding if the destination was a broadcast.
+	 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
+	 * tp->iss, and send a segment:
+	 *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
+	 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
+	 * Fill in remote peer address fields if not previously specified.
+	 * Enter SYN_RECEIVED state, and process any other fields of this
+	 * segment in this state.
+	 */
+	case TCPS_LISTEN: {
+
+	  if (tiflags & TH_RST)
+	    goto drop;
+	  if (tiflags & TH_ACK)
+	    goto dropwithreset;
+	  if ((tiflags & TH_SYN) == 0)
+	    goto drop;
+
+	  /*
+	   * This has way too many gotos...
+	   * But a bit of spaghetti code never hurt anybody :)
+	   */
+
+	  /*
+	   * If this is destined for the control address, then flag to
+	   * tcp_ctl once connected, otherwise connect
+	   */
+	  if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+	      slirp->vnetwork_addr.s_addr) {
+	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
+		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
+		/* May be an add exec */
+		for (ex_ptr = slirp->exec_list; ex_ptr;
+		     ex_ptr = ex_ptr->ex_next) {
+		  if(ex_ptr->ex_fport == so->so_fport &&
+		     so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
+		    so->so_state |= SS_CTL;
+		    break;
+		  }
+		}
+		if (so->so_state & SS_CTL) {
+		    goto cont_input;
+		}
+	    }
+	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
+	  }
+
+	  if (so->so_emu & EMU_NOCONNECT) {
+	    so->so_emu &= ~EMU_NOCONNECT;
+	    goto cont_input;
+	  }
+
+	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
+	    u_char code=ICMP_UNREACH_NET;
+	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
+			errno,strerror(errno)));
+	    if(errno == ECONNREFUSED) {
+	      /* ACK the SYN, send RST to refuse the connection */
+	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
+			  TH_RST|TH_ACK);
+	    } else {
+	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
+	      HTONL(ti->ti_seq);             /* restore tcp header */
+	      HTONL(ti->ti_ack);
+	      HTONS(ti->ti_win);
+	      HTONS(ti->ti_urp);
+	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+	      *ip=save_ip;
+	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
+	    }
+            tcp_close(tp);
+	    m_free(m);
+	  } else {
+	    /*
+	     * Haven't connected yet, save the current mbuf
+	     * and ti, and return
+	     * XXX Some OS's don't tell us whether the connect()
+	     * succeeded or not.  So we must time it out.
+	     */
+	    so->so_m = m;
+	    so->so_ti = ti;
+	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+	    tp->t_state = TCPS_SYN_RECEIVED;
+	  }
+	  return;
+
+	cont_conn:
+	  /* m==NULL
+	   * Check if the connect succeeded
+	   */
+	  if (so->so_state & SS_NOFDREF) {
+	    tp = tcp_close(tp);
+	    goto dropwithreset;
+	  }
+	cont_input:
+	  tcp_template(tp);
+
+	  if (optp)
+	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);
+
+	  if (iss)
+	    tp->iss = iss;
+	  else
+	    tp->iss = slirp->tcp_iss;
+	  slirp->tcp_iss += TCP_ISSINCR/2;
+	  tp->irs = ti->ti_seq;
+	  tcp_sendseqinit(tp);
+	  tcp_rcvseqinit(tp);
+	  tp->t_flags |= TF_ACKNOW;
+	  tp->t_state = TCPS_SYN_RECEIVED;
+	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+	  goto trimthenstep6;
+	} /* case TCPS_LISTEN */
+
+	/*
+	 * If the state is SYN_SENT:
+	 *	if seg contains an ACK, but not for our SYN, drop the input.
+	 *	if seg contains a RST, then drop the connection.
+	 *	if seg does not contain SYN, then drop it.
+	 * Otherwise this is an acceptable SYN segment
+	 *	initialize tp->rcv_nxt and tp->irs
+	 *	if seg contains ack then advance tp->snd_una
+	 *	if SYN has been acked change to ESTABLISHED else SYN_RCVD state
+	 *	arrange for segment to be acked (eventually)
+	 *	continue processing rest of data/controls, beginning with URG
+	 */
+	case TCPS_SYN_SENT:
+		if ((tiflags & TH_ACK) &&
+		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||
+		     SEQ_GT(ti->ti_ack, tp->snd_max)))
+			goto dropwithreset;
+
+		if (tiflags & TH_RST) {
+                        if (tiflags & TH_ACK) {
+                                tcp_drop(tp, 0); /* XXX Check t_softerror! */
+                        }
+			goto drop;
+		}
+
+		if ((tiflags & TH_SYN) == 0)
+			goto drop;
+		if (tiflags & TH_ACK) {
+			tp->snd_una = ti->ti_ack;
+			if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+				tp->snd_nxt = tp->snd_una;
+		}
+
+		tp->t_timer[TCPT_REXMT] = 0;
+		tp->irs = ti->ti_seq;
+		tcp_rcvseqinit(tp);
+		tp->t_flags |= TF_ACKNOW;
+		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
+			soisfconnected(so);
+			tp->t_state = TCPS_ESTABLISHED;
+
+			(void) tcp_reass(tp, (struct tcpiphdr *)0,
+				(struct mbuf *)0);
+			/*
+			 * if we didn't have to retransmit the SYN,
+			 * use its rtt as our initial srtt & rtt var.
+			 */
+			if (tp->t_rtt)
+				tcp_xmit_timer(tp, tp->t_rtt);
+		} else
+			tp->t_state = TCPS_SYN_RECEIVED;
+
+trimthenstep6:
+		/*
+		 * Advance ti->ti_seq to correspond to first data byte.
+		 * If data, trim to stay within window,
+		 * dropping FIN if necessary.
+		 */
+		ti->ti_seq++;
+		if (ti->ti_len > tp->rcv_wnd) {
+			todrop = ti->ti_len - tp->rcv_wnd;
+			m_adj(m, -todrop);
+			ti->ti_len = tp->rcv_wnd;
+			tiflags &= ~TH_FIN;
+		}
+		tp->snd_wl1 = ti->ti_seq - 1;
+		tp->rcv_up = ti->ti_seq;
+		goto step6;
+	} /* switch tp->t_state */
+	/*
+	 * States other than LISTEN or SYN_SENT.
+	 * Check that at least some bytes of segment are within
+	 * receive window.  If segment begins before rcv_nxt,
+	 * drop leading data (and SYN); if nothing left, just ack.
+	 */
+	todrop = tp->rcv_nxt - ti->ti_seq;
+	if (todrop > 0) {
+		if (tiflags & TH_SYN) {
+			tiflags &= ~TH_SYN;
+			ti->ti_seq++;
+			if (ti->ti_urp > 1)
+				ti->ti_urp--;
+			else
+				tiflags &= ~TH_URG;
+			todrop--;
+		}
+		/*
+		 * Following if statement from Stevens, vol. 2, p. 960.
+		 */
+		if (todrop > ti->ti_len
+		    || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
+			/*
+			 * Any valid FIN must be to the left of the window.
+			 * At this point the FIN must be a duplicate or out
+			 * of sequence; drop it.
+			 */
+			tiflags &= ~TH_FIN;
+
+			/*
+			 * Send an ACK to resynchronize and drop any data.
+			 * But keep on processing for RST or ACK.
+			 */
+			tp->t_flags |= TF_ACKNOW;
+			todrop = ti->ti_len;
+		}
+		m_adj(m, todrop);
+		ti->ti_seq += todrop;
+		ti->ti_len -= todrop;
+		if (ti->ti_urp > todrop)
+			ti->ti_urp -= todrop;
+		else {
+			tiflags &= ~TH_URG;
+			ti->ti_urp = 0;
+		}
+	}
+	/*
+	 * If new data are received on a connection after the
+	 * user processes are gone, then RST the other end.
+	 */
+	if ((so->so_state & SS_NOFDREF) &&
+	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
+		tp = tcp_close(tp);
+		goto dropwithreset;
+	}
+
+	/*
+	 * If segment ends after window, drop trailing data
+	 * (and PUSH and FIN); if nothing left, just ACK.
+	 */
+	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
+	if (todrop > 0) {
+		if (todrop >= ti->ti_len) {
+			/*
+			 * If a new connection request is received
+			 * while in TIME_WAIT, drop the old connection
+			 * and start over if the sequence numbers
+			 * are above the previous ones.
+			 */
+			if (tiflags & TH_SYN &&
+			    tp->t_state == TCPS_TIME_WAIT &&
+			    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
+				iss = tp->rcv_nxt + TCP_ISSINCR;
+				tp = tcp_close(tp);
+				goto findso;
+			}
+			/*
+			 * If window is closed can only take segments at
+			 * window edge, and have to drop data and PUSH from
+			 * incoming segments.  Continue processing, but
+			 * remember to ack.  Otherwise, drop segment
+			 * and ack.
+			 */
+			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
+				tp->t_flags |= TF_ACKNOW;
+			} else {
+				goto dropafterack;
+			}
+		}
+		m_adj(m, -todrop);
+		ti->ti_len -= todrop;
+		tiflags &= ~(TH_PUSH|TH_FIN);
+	}
+
+	/*
+	 * If the RST bit is set examine the state:
+	 *    SYN_RECEIVED STATE:
+	 *	If passive open, return to LISTEN state.
+	 *	If active open, inform user that connection was refused.
+	 *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
+	 *	Inform user that connection was reset, and close tcb.
+	 *    CLOSING, LAST_ACK, TIME_WAIT STATES
+	 *	Close the tcb.
+	 */
+	if (tiflags&TH_RST) switch (tp->t_state) {
+
+	case TCPS_SYN_RECEIVED:
+	case TCPS_ESTABLISHED:
+	case TCPS_FIN_WAIT_1:
+	case TCPS_FIN_WAIT_2:
+	case TCPS_CLOSE_WAIT:
+		tp->t_state = TCPS_CLOSED;
+                tcp_close(tp);
+		goto drop;
+
+	case TCPS_CLOSING:
+	case TCPS_LAST_ACK:
+	case TCPS_TIME_WAIT:
+                tcp_close(tp);
+		goto drop;
+	}
+
+	/*
+	 * If a SYN is in the window, then this is an
+	 * error and we send an RST and drop the connection.
+	 */
+	if (tiflags & TH_SYN) {
+		tp = tcp_drop(tp,0);
+		goto dropwithreset;
+	}
+
+	/*
+	 * If the ACK bit is off we drop the segment and return.
+	 */
+	if ((tiflags & TH_ACK) == 0) goto drop;
+
+	/*
+	 * Ack processing.
+	 */
+	switch (tp->t_state) {
+	/*
+	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
+	 * ESTABLISHED state and continue processing, otherwise
+	 * send an RST.  una<=ack<=max
+	 */
+	case TCPS_SYN_RECEIVED:
+
+		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
+		    SEQ_GT(ti->ti_ack, tp->snd_max))
+			goto dropwithreset;
+		tp->t_state = TCPS_ESTABLISHED;
+		/*
+		 * The sent SYN is ack'ed with our sequence number +1
+		 * The first data byte already in the buffer will get
+		 * lost if no correction is made.  This is only needed for
+		 * SS_CTL since the buffer is empty otherwise.
+		 * tp->snd_una++; or:
+		 */
+		tp->snd_una=ti->ti_ack;
+		if (so->so_state & SS_CTL) {
+		  /* So tcp_ctl reports the right state */
+		  ret = tcp_ctl(so);
+		  if (ret == 1) {
+		    soisfconnected(so);
+		    so->so_state &= ~SS_CTL;   /* success XXX */
+		  } else if (ret == 2) {
+		    so->so_state &= SS_PERSISTENT_MASK;
+		    so->so_state |= SS_NOFDREF; /* CTL_CMD */
+		  } else {
+		    needoutput = 1;
+		    tp->t_state = TCPS_FIN_WAIT_1;
+		  }
+		} else {
+		  soisfconnected(so);
+		}
+
+		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
+		tp->snd_wl1 = ti->ti_seq - 1;
+		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
+		goto synrx_to_est;
+		/* fall into ... */
+
+	/*
+	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
+	 * ACKs.  If the ack is in the range
+	 *	tp->snd_una < ti->ti_ack <= tp->snd_max
+	 * then advance tp->snd_una to ti->ti_ack and drop
+	 * data from the retransmission queue.  If this ACK reflects
+	 * more up to date window information we update our window information.
+	 */
+	case TCPS_ESTABLISHED:
+	case TCPS_FIN_WAIT_1:
+	case TCPS_FIN_WAIT_2:
+	case TCPS_CLOSE_WAIT:
+	case TCPS_CLOSING:
+	case TCPS_LAST_ACK:
+	case TCPS_TIME_WAIT:
+
+		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
+			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
+			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
+				      (long )m, (long )so));
+				/*
+				 * If we have outstanding data (other than
+				 * a window probe), this is a completely
+				 * duplicate ack (ie, window info didn't
+				 * change), the ack is the biggest we've
+				 * seen and we've seen exactly our rexmt
+				 * threshold of them, assume a packet
+				 * has been dropped and retransmit it.
+				 * Kludge snd_nxt & the congestion
+				 * window so we send only this one
+				 * packet.
+				 *
+				 * We know we're losing at the current
+				 * window size so do congestion avoidance
+				 * (set ssthresh to half the current window
+				 * and pull our congestion window back to
+				 * the new ssthresh).
+				 *
+				 * Dup acks mean that packets have left the
+				 * network (they're now cached at the receiver)
+				 * so bump cwnd by the amount in the receiver
+				 * to keep a constant cwnd packets in the
+				 * network.
+				 */
+				if (tp->t_timer[TCPT_REXMT] == 0 ||
+				    ti->ti_ack != tp->snd_una)
+					tp->t_dupacks = 0;
+				else if (++tp->t_dupacks == TCPREXMTTHRESH) {
+					tcp_seq onxt = tp->snd_nxt;
+					u_int win =
+					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+						tp->t_maxseg;
+
+					if (win < 2)
+						win = 2;
+					tp->snd_ssthresh = win * tp->t_maxseg;
+					tp->t_timer[TCPT_REXMT] = 0;
+					tp->t_rtt = 0;
+					tp->snd_nxt = ti->ti_ack;
+					tp->snd_cwnd = tp->t_maxseg;
+					(void) tcp_output(tp);
+					tp->snd_cwnd = tp->snd_ssthresh +
+					       tp->t_maxseg * tp->t_dupacks;
+					if (SEQ_GT(onxt, tp->snd_nxt))
+						tp->snd_nxt = onxt;
+					goto drop;
+				} else if (tp->t_dupacks > TCPREXMTTHRESH) {
+					tp->snd_cwnd += tp->t_maxseg;
+					(void) tcp_output(tp);
+					goto drop;
+				}
+			} else
+				tp->t_dupacks = 0;
+			break;
+		}
+	synrx_to_est:
+		/*
+		 * If the congestion window was inflated to account
+		 * for the other side's cached packets, retract it.
+		 */
+		if (tp->t_dupacks > TCPREXMTTHRESH &&
+		    tp->snd_cwnd > tp->snd_ssthresh)
+			tp->snd_cwnd = tp->snd_ssthresh;
+		tp->t_dupacks = 0;
+		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
+			goto dropafterack;
+		}
+		acked = ti->ti_ack - tp->snd_una;
+
+		/*
+		 * If transmit timer is running and timed sequence
+		 * number was acked, update smoothed round trip time.
+		 * Since we now have an rtt measurement, cancel the
+		 * timer backoff (cf., Phil Karn's retransmit alg.).
+		 * Recompute the initial retransmit timer.
+		 */
+		if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
+			tcp_xmit_timer(tp,tp->t_rtt);
+
+		/*
+		 * If all outstanding data is acked, stop retransmit
+		 * timer and remember to restart (more output or persist).
+		 * If there is more data to be acked, restart retransmit
+		 * timer, using current (possibly backed-off) value.
+		 */
+		if (ti->ti_ack == tp->snd_max) {
+			tp->t_timer[TCPT_REXMT] = 0;
+			needoutput = 1;
+		} else if (tp->t_timer[TCPT_PERSIST] == 0)
+			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+		/*
+		 * When new data is acked, open the congestion window.
+		 * If the window gives us less than ssthresh packets
+		 * in flight, open exponentially (maxseg per packet).
+		 * Otherwise open linearly: maxseg per window
+		 * (maxseg^2 / cwnd per packet).
+		 */
+		{
+		  register u_int cw = tp->snd_cwnd;
+		  register u_int incr = tp->t_maxseg;
+
+		  if (cw > tp->snd_ssthresh)
+		    incr = incr * incr / cw;
+		  tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
+		}
+		if (acked > so->so_snd.sb_cc) {
+			tp->snd_wnd -= so->so_snd.sb_cc;
+			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
+			ourfinisacked = 1;
+		} else {
+			sbdrop(&so->so_snd, acked);
+			tp->snd_wnd -= acked;
+			ourfinisacked = 0;
+		}
+		tp->snd_una = ti->ti_ack;
+		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+			tp->snd_nxt = tp->snd_una;
+
+		switch (tp->t_state) {
+
+		/*
+		 * In FIN_WAIT_1 STATE in addition to the processing
+		 * for the ESTABLISHED state if our FIN is now acknowledged
+		 * then enter FIN_WAIT_2.
+		 */
+		case TCPS_FIN_WAIT_1:
+			if (ourfinisacked) {
+				/*
+				 * If we can't receive any more
+				 * data, then closing user can proceed.
+				 * Starting the timer is contrary to the
+				 * specification, but if we don't get a FIN
+				 * we'll hang forever.
+				 */
+				if (so->so_state & SS_FCANTRCVMORE) {
+					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
+				}
+				tp->t_state = TCPS_FIN_WAIT_2;
+			}
+			break;
+
+	 	/*
+		 * In CLOSING STATE in addition to the processing for
+		 * the ESTABLISHED state if the ACK acknowledges our FIN
+		 * then enter the TIME-WAIT state, otherwise ignore
+		 * the segment.
+		 */
+		case TCPS_CLOSING:
+			if (ourfinisacked) {
+				tp->t_state = TCPS_TIME_WAIT;
+				tcp_canceltimers(tp);
+				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			}
+			break;
+
+		/*
+		 * In LAST_ACK, we may still be waiting for data to drain
+		 * and/or to be acked, as well as for the ack of our FIN.
+		 * If our FIN is now acknowledged, delete the TCB,
+		 * enter the closed state and return.
+		 */
+		case TCPS_LAST_ACK:
+			if (ourfinisacked) {
+                                tcp_close(tp);
+				goto drop;
+			}
+			break;
+
+		/*
+		 * In TIME_WAIT state the only thing that should arrive
+		 * is a retransmission of the remote FIN.  Acknowledge
+		 * it and restart the finack timer.
+		 */
+		case TCPS_TIME_WAIT:
+			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			goto dropafterack;
+		}
+	} /* switch(tp->t_state) */
+
+step6:
+	/*
+	 * Update window information.
+	 * Don't look at window if no ACK: TAC's send garbage on first SYN.
+	 */
+	if ((tiflags & TH_ACK) &&
+	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
+	    (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
+	    (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
+		tp->snd_wnd = tiwin;
+		tp->snd_wl1 = ti->ti_seq;
+		tp->snd_wl2 = ti->ti_ack;
+		if (tp->snd_wnd > tp->max_sndwnd)
+			tp->max_sndwnd = tp->snd_wnd;
+		needoutput = 1;
+	}
+
+	/*
+	 * Process segments with URG.
+	 */
+	if ((tiflags & TH_URG) && ti->ti_urp &&
+	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+		/*
+		 * This is a kludge, but if we receive and accept
+		 * random urgent pointers, we'll crash in
+		 * soreceive.  It's hard to imagine someone
+		 * actually wanting to send this much urgent data.
+		 */
+		if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
+			ti->ti_urp = 0;
+			tiflags &= ~TH_URG;
+			goto dodata;
+		}
+		/*
+		 * If this segment advances the known urgent pointer,
+		 * then mark the data stream.  This should not happen
+		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
+		 * a FIN has been received from the remote side.
+		 * In these states we ignore the URG.
+		 *
+		 * According to RFC961 (Assigned Protocols),
+		 * the urgent pointer points to the last octet
+		 * of urgent data.  We continue, however,
+		 * to consider it to indicate the first octet
+		 * of data past the urgent section as the original
+		 * spec states (in one of two places).
+		 */
+		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
+			tp->rcv_up = ti->ti_seq + ti->ti_urp;
+			so->so_urgc =  so->so_rcv.sb_cc +
+				(tp->rcv_up - tp->rcv_nxt); /* -1; */
+			tp->rcv_up = ti->ti_seq + ti->ti_urp;
+
+		}
+	} else
+		/*
+		 * If no out of band data is expected,
+		 * pull receive urgent pointer along
+		 * with the receive window.
+		 */
+		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
+			tp->rcv_up = tp->rcv_nxt;
+dodata:
+
+	/*
+	 * Process the segment text, merging it into the TCP sequencing queue,
+	 * and arranging for acknowledgment of receipt if necessary.
+	 * This process logically involves adjusting tp->rcv_wnd as data
+	 * is presented to the user (this happens in tcp_usrreq.c,
+	 * case PRU_RCVD).  If a FIN has already been received on this
+	 * connection then we just ignore the text.
+	 */
+	if ((ti->ti_len || (tiflags&TH_FIN)) &&
+	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+		TCP_REASS(tp, ti, m, so, tiflags);
+	} else {
+		m_free(m);
+		tiflags &= ~TH_FIN;
+	}
+
+	/*
+	 * If FIN is received ACK the FIN and let the user know
+	 * that the connection is closing.
+	 */
+	if (tiflags & TH_FIN) {
+		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+			/*
+			 * If we receive a FIN we can't send more data,
+			 * set it SS_FDRAIN
+                         * Shutdown the socket if there is no rx data in the
+			 * buffer.
+			 * soread() is called on completion of shutdown() and
+			 * will got to TCPS_LAST_ACK, and use tcp_output()
+			 * to send the FIN.
+			 */
+			sofwdrain(so);
+
+			tp->t_flags |= TF_ACKNOW;
+			tp->rcv_nxt++;
+		}
+		switch (tp->t_state) {
+
+	 	/*
+		 * In SYN_RECEIVED and ESTABLISHED STATES
+		 * enter the CLOSE_WAIT state.
+		 */
+		case TCPS_SYN_RECEIVED:
+		case TCPS_ESTABLISHED:
+		  if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
+		    tp->t_state = TCPS_LAST_ACK;
+		  else
+		    tp->t_state = TCPS_CLOSE_WAIT;
+		  break;
+
+	 	/*
+		 * If still in FIN_WAIT_1 STATE FIN has not been acked so
+		 * enter the CLOSING state.
+		 */
+		case TCPS_FIN_WAIT_1:
+			tp->t_state = TCPS_CLOSING;
+			break;
+
+	 	/*
+		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
+		 * starting the time-wait timer, turning off the other
+		 * standard timers.
+		 */
+		case TCPS_FIN_WAIT_2:
+			tp->t_state = TCPS_TIME_WAIT;
+			tcp_canceltimers(tp);
+			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			break;
+
+		/*
+		 * In TIME_WAIT state restart the 2 MSL time_wait timer.
+		 */
+		case TCPS_TIME_WAIT:
+			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+			break;
+		}
+	}
+
+	/*
+	 * If this is a small packet, then ACK now - with Nagel
+	 *      congestion avoidance sender won't send more until
+	 *      he gets an ACK.
+	 *
+	 * See above.
+	 */
+	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
+	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
+		tp->t_flags |= TF_ACKNOW;
+	}
+
+	/*
+	 * Return any desired output.
+	 */
+	if (needoutput || (tp->t_flags & TF_ACKNOW)) {
+		(void) tcp_output(tp);
+	}
+	return;
+
+dropafterack:
+	/*
+	 * Generate an ACK dropping incoming segment if it occupies
+	 * sequence space, where the ACK reflects our state.
+	 */
+	if (tiflags & TH_RST)
+		goto drop;
+	m_free(m);
+	tp->t_flags |= TF_ACKNOW;
+	(void) tcp_output(tp);
+	return;
+
+dropwithreset:
+	/* reuses m if m!=NULL, m_free() unnecessary */
+	if (tiflags & TH_ACK)
+		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
+	else {
+		if (tiflags & TH_SYN) ti->ti_len++;
+		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
+		    TH_RST|TH_ACK);
+	}
+
+	return;
+
+drop:
+	/*
+	 * Drop space held by incoming segment and return.
+	 */
+	m_free(m);
+
+	return;
+}
+
+static void
+tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
+{
+	uint16_t mss;
+	int opt, optlen;
+
+	DEBUG_CALL("tcp_dooptions");
+	DEBUG_ARGS((dfd," tp = %lx  cnt=%i \n", (long )tp, cnt));
+
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[0];
+		if (opt == TCPOPT_EOL)
+			break;
+		if (opt == TCPOPT_NOP)
+			optlen = 1;
+		else {
+			optlen = cp[1];
+			if (optlen <= 0)
+				break;
+		}
+		switch (opt) {
+
+		default:
+			continue;
+
+		case TCPOPT_MAXSEG:
+			if (optlen != TCPOLEN_MAXSEG)
+				continue;
+			if (!(ti->ti_flags & TH_SYN))
+				continue;
+			memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));
+			NTOHS(mss);
+			(void) tcp_mss(tp, mss);	/* sets t_maxseg */
+			break;
+		}
+	}
+}
+
+
+/*
+ * Pull out of band byte out of a segment so
+ * it doesn't appear in the user's data queue.
+ * It is still reflected in the segment length for
+ * sequencing purposes.
+ */
+
+#ifdef notdef
+
+void
+tcp_pulloutofband(so, ti, m)
+	struct socket *so;
+	struct tcpiphdr *ti;
+	register struct mbuf *m;
+{
+	int cnt = ti->ti_urp - 1;
+
+	while (cnt >= 0) {
+		if (m->m_len > cnt) {
+			char *cp = mtod(m, caddr_t) + cnt;
+			struct tcpcb *tp = sototcpcb(so);
+
+			tp->t_iobc = *cp;
+			tp->t_oobflags |= TCPOOB_HAVEDATA;
+			memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1));
+			m->m_len--;
+			return;
+		}
+		cnt -= m->m_len;
+		m = m->m_next; /* XXX WRONG! Fix it! */
+		if (m == 0)
+			break;
+	}
+	panic("tcp_pulloutofband");
+}
+
+#endif /* notdef */
+
+/*
+ * Collect new round-trip time estimate
+ * and update averages and current timeout.
+ */
+
+static void
+tcp_xmit_timer(register struct tcpcb *tp, int rtt)
+{
+	register short delta;
+
+	DEBUG_CALL("tcp_xmit_timer");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("rtt = %d", rtt);
+
+	if (tp->t_srtt != 0) {
+		/*
+		 * srtt is stored as fixed point with 3 bits after the
+		 * binary point (i.e., scaled by 8).  The following magic
+		 * is equivalent to the smoothing algorithm in rfc793 with
+		 * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
+		 * point).  Adjust rtt to origin 0.
+		 */
+		delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
+		if ((tp->t_srtt += delta) <= 0)
+			tp->t_srtt = 1;
+		/*
+		 * We accumulate a smoothed rtt variance (actually, a
+		 * smoothed mean difference), then set the retransmit
+		 * timer to smoothed rtt + 4 times the smoothed variance.
+		 * rttvar is stored as fixed point with 2 bits after the
+		 * binary point (scaled by 4).  The following is
+		 * equivalent to rfc793 smoothing with an alpha of .75
+		 * (rttvar = rttvar*3/4 + |delta| / 4).  This replaces
+		 * rfc793's wired-in beta.
+		 */
+		if (delta < 0)
+			delta = -delta;
+		delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
+		if ((tp->t_rttvar += delta) <= 0)
+			tp->t_rttvar = 1;
+	} else {
+		/*
+		 * No rtt measurement yet - use the unsmoothed rtt.
+		 * Set the variance to half the rtt (so our first
+		 * retransmit happens at 3*rtt).
+		 */
+		tp->t_srtt = rtt << TCP_RTT_SHIFT;
+		tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
+	}
+	tp->t_rtt = 0;
+	tp->t_rxtshift = 0;
+
+	/*
+	 * the retransmit should happen at rtt + 4 * rttvar.
+	 * Because of the way we do the smoothing, srtt and rttvar
+	 * will each average +1/2 tick of bias.  When we compute
+	 * the retransmit timer, we want 1/2 tick of rounding and
+	 * 1 extra tick because of +-1/2 tick uncertainty in the
+	 * firing of the timer.  The bias will give us exactly the
+	 * 1.5 tick we need.  But, because the bias is
+	 * statistical, we have to test that we don't drop below
+	 * the minimum feasible timer (which is 2 ticks).
+	 */
+	TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
+	    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
+
+	/*
+	 * We received an ack for a packet that wasn't retransmitted;
+	 * it is probably safe to discard any error indications we've
+	 * received recently.  This isn't quite right, but close enough
+	 * for now (a route might have failed after we sent a segment,
+	 * and the return path might not be symmetrical).
+	 */
+	tp->t_softerror = 0;
+}
+
+/*
+ * Determine a reasonable value for maxseg size.
+ * If the route is known, check route for mtu.
+ * If none, use an mss that can be handled on the outgoing
+ * interface without forcing IP to fragment; if bigger than
+ * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
+ * to utilize large mbufs.  If no route is found, route has no mtu,
+ * or the destination isn't local, use a default, hopefully conservative
+ * size (usually 512 or the default IP max size, but no more than the mtu
+ * of the interface), as we can't discover anything about intervening
+ * gateways or networks.  We also initialize the congestion/slow start
+ * window to be a single segment if the destination isn't local.
+ * While looking at the routing entry, we also initialize other path-dependent
+ * parameters from pre-set or cached values in the routing entry.
+ */
+
+int
+tcp_mss(struct tcpcb *tp, u_int offer)
+{
+	struct socket *so = tp->t_socket;
+	int mss;
+
+	DEBUG_CALL("tcp_mss");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("offer = %d", offer);
+
+	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
+	if (offer)
+		mss = min(mss, offer);
+	mss = max(mss, 32);
+	if (mss < tp->t_maxseg || offer != 0)
+	   tp->t_maxseg = mss;
+
+	tp->snd_cwnd = mss;
+
+	sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ?
+                                               (mss - (TCP_SNDSPACE % mss)) :
+                                               0));
+	sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ?
+                                               (mss - (TCP_RCVSPACE % mss)) :
+                                               0));
+
+	DEBUG_MISC((dfd, " returning mss = %d\n", mss));
+
+	return mss;
+}
diff --git a/qemu-0.15.x/slirp/tcp_output.c b/qemu-0.15.x/slirp/tcp_output.c
new file mode 100644
index 0000000..779314b
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_output.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *	@(#)tcp_output.c	8.3 (Berkeley) 12/30/93
+ * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+static const u_char  tcp_outflags[TCP_NSTATES] = {
+	TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
+	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
+	TH_FIN|TH_ACK, TH_ACK, TH_ACK,
+};
+
+
+#define MAX_TCPOPTLEN	32	/* max # bytes that go in options */
+
+/*
+ * Tcp output routine: figure out what should be sent and send it.
+ */
+int
+tcp_output(struct tcpcb *tp)
+{
+	register struct socket *so = tp->t_socket;
+	register long len, win;
+	int off, flags, error;
+	register struct mbuf *m;
+	register struct tcpiphdr *ti;
+	u_char opt[MAX_TCPOPTLEN];
+	unsigned optlen, hdrlen;
+	int idle, sendalot;
+
+	DEBUG_CALL("tcp_output");
+	DEBUG_ARG("tp = %lx", (long )tp);
+
+	/*
+	 * Determine length of data that should be transmitted,
+	 * and flags that will be used.
+	 * If there is some data or critical controls (SYN, RST)
+	 * to send, then transmit; otherwise, investigate further.
+	 */
+	idle = (tp->snd_max == tp->snd_una);
+	if (idle && tp->t_idle >= tp->t_rxtcur)
+		/*
+		 * We have been idle for "a while" and no acks are
+		 * expected to clock out any data we send --
+		 * slow start to get ack "clock" running again.
+		 */
+		tp->snd_cwnd = tp->t_maxseg;
+again:
+	sendalot = 0;
+	off = tp->snd_nxt - tp->snd_una;
+	win = min(tp->snd_wnd, tp->snd_cwnd);
+
+	flags = tcp_outflags[tp->t_state];
+
+	DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
+
+	/*
+	 * If in persist timeout with window of 0, send 1 byte.
+	 * Otherwise, if window is small but nonzero
+	 * and timer expired, we will send what we can
+	 * and go to transmit state.
+	 */
+	if (tp->t_force) {
+		if (win == 0) {
+			/*
+			 * If we still have some data to send, then
+			 * clear the FIN bit.  Usually this would
+			 * happen below when it realizes that we
+			 * aren't sending all the data.  However,
+			 * if we have exactly 1 byte of unset data,
+			 * then it won't clear the FIN bit below,
+			 * and if we are in persist state, we wind
+			 * up sending the packet without recording
+			 * that we sent the FIN bit.
+			 *
+			 * We can't just blindly clear the FIN bit,
+			 * because if we don't have any more data
+			 * to send then the probe will be the FIN
+			 * itself.
+			 */
+			if (off < so->so_snd.sb_cc)
+				flags &= ~TH_FIN;
+			win = 1;
+		} else {
+			tp->t_timer[TCPT_PERSIST] = 0;
+			tp->t_rxtshift = 0;
+		}
+	}
+
+	len = min(so->so_snd.sb_cc, win) - off;
+
+	if (len < 0) {
+		/*
+		 * If FIN has been sent but not acked,
+		 * but we haven't been called to retransmit,
+		 * len will be -1.  Otherwise, window shrank
+		 * after we sent into it.  If window shrank to 0,
+		 * cancel pending retransmit and pull snd_nxt
+		 * back to (closed) window.  We will enter persist
+		 * state below.  If the window didn't close completely,
+		 * just wait for an ACK.
+		 */
+		len = 0;
+		if (win == 0) {
+			tp->t_timer[TCPT_REXMT] = 0;
+			tp->snd_nxt = tp->snd_una;
+		}
+	}
+
+	if (len > tp->t_maxseg) {
+		len = tp->t_maxseg;
+		sendalot = 1;
+	}
+	if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+		flags &= ~TH_FIN;
+
+	win = sbspace(&so->so_rcv);
+
+	/*
+	 * Sender silly window avoidance.  If connection is idle
+	 * and can send all data, a maximum segment,
+	 * at least a maximum default-size segment do it,
+	 * or are forced, do it; otherwise don't bother.
+	 * If peer's buffer is tiny, then send
+	 * when window is at least half open.
+	 * If retransmitting (possibly after persist timer forced us
+	 * to send into a small window), then must resend.
+	 */
+	if (len) {
+		if (len == tp->t_maxseg)
+			goto send;
+		if ((1 || idle || tp->t_flags & TF_NODELAY) &&
+		    len + off >= so->so_snd.sb_cc)
+			goto send;
+		if (tp->t_force)
+			goto send;
+		if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
+			goto send;
+		if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+			goto send;
+	}
+
+	/*
+	 * Compare available window to amount of window
+	 * known to peer (as advertised window less
+	 * next expected input).  If the difference is at least two
+	 * max size segments, or at least 50% of the maximum possible
+	 * window, then want to send a window update to peer.
+	 */
+	if (win > 0) {
+		/*
+		 * "adv" is the amount we can increase the window,
+		 * taking into account that we are limited by
+		 * TCP_MAXWIN << tp->rcv_scale.
+		 */
+		long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
+			(tp->rcv_adv - tp->rcv_nxt);
+
+		if (adv >= (long) (2 * tp->t_maxseg))
+			goto send;
+		if (2 * adv >= (long) so->so_rcv.sb_datalen)
+			goto send;
+	}
+
+	/*
+	 * Send if we owe peer an ACK.
+	 */
+	if (tp->t_flags & TF_ACKNOW)
+		goto send;
+	if (flags & (TH_SYN|TH_RST))
+		goto send;
+	if (SEQ_GT(tp->snd_up, tp->snd_una))
+		goto send;
+	/*
+	 * If our state indicates that FIN should be sent
+	 * and we have not yet done so, or we're retransmitting the FIN,
+	 * then we need to send.
+	 */
+	if (flags & TH_FIN &&
+	    ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+		goto send;
+
+	/*
+	 * TCP window updates are not reliable, rather a polling protocol
+	 * using ``persist'' packets is used to insure receipt of window
+	 * updates.  The three ``states'' for the output side are:
+	 *	idle			not doing retransmits or persists
+	 *	persisting		to move a small or zero window
+	 *	(re)transmitting	and thereby not persisting
+	 *
+	 * tp->t_timer[TCPT_PERSIST]
+	 *	is set when we are in persist state.
+	 * tp->t_force
+	 *	is set when we are called to send a persist packet.
+	 * tp->t_timer[TCPT_REXMT]
+	 *	is set when we are retransmitting
+	 * The output side is idle when both timers are zero.
+	 *
+	 * If send window is too small, there is data to transmit, and no
+	 * retransmit or persist is pending, then go to persist state.
+	 * If nothing happens soon, send when timer expires:
+	 * if window is nonzero, transmit what we can,
+	 * otherwise force out a byte.
+	 */
+	if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
+	    tp->t_timer[TCPT_PERSIST] == 0) {
+		tp->t_rxtshift = 0;
+		tcp_setpersist(tp);
+	}
+
+	/*
+	 * No reason to send a segment, just return.
+	 */
+	return (0);
+
+send:
+	/*
+	 * Before ESTABLISHED, force sending of initial options
+	 * unless TCP set not to do any options.
+	 * NOTE: we assume that the IP/TCP header plus TCP options
+	 * always fit in a single mbuf, leaving room for a maximum
+	 * link header, i.e.
+	 *	max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
+	 */
+	optlen = 0;
+	hdrlen = sizeof (struct tcpiphdr);
+	if (flags & TH_SYN) {
+		tp->snd_nxt = tp->iss;
+		if ((tp->t_flags & TF_NOOPT) == 0) {
+			uint16_t mss;
+
+			opt[0] = TCPOPT_MAXSEG;
+			opt[1] = 4;
+			mss = htons((uint16_t) tcp_mss(tp, 0));
+			memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss));
+			optlen = 4;
+		}
+ 	}
+
+ 	hdrlen += optlen;
+
+	/*
+	 * Adjust data length if insertion of options will
+	 * bump the packet length beyond the t_maxseg length.
+	 */
+	 if (len > tp->t_maxseg - optlen) {
+		len = tp->t_maxseg - optlen;
+		sendalot = 1;
+	 }
+
+	/*
+	 * Grab a header mbuf, attaching a copy of data to
+	 * be transmitted, and initialize the header from
+	 * the template for sends on this connection.
+	 */
+	if (len) {
+		m = m_get(so->slirp);
+		if (m == NULL) {
+			error = 1;
+			goto out;
+		}
+		m->m_data += IF_MAXLINKHDR;
+		m->m_len = hdrlen;
+
+		sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
+		m->m_len += len;
+
+		/*
+		 * If we're sending everything we've got, set PUSH.
+		 * (This will keep happy those implementations which only
+		 * give data to the user when a buffer fills or
+		 * a PUSH comes in.)
+		 */
+		if (off + len == so->so_snd.sb_cc)
+			flags |= TH_PUSH;
+	} else {
+		m = m_get(so->slirp);
+		if (m == NULL) {
+			error = 1;
+			goto out;
+		}
+		m->m_data += IF_MAXLINKHDR;
+		m->m_len = hdrlen;
+	}
+
+	ti = mtod(m, struct tcpiphdr *);
+
+	memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
+
+	/*
+	 * Fill in fields, remembering maximum advertised
+	 * window for use in delaying messages about window sizes.
+	 * If resending a FIN, be sure not to use a new sequence number.
+	 */
+	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
+	    tp->snd_nxt == tp->snd_max)
+		tp->snd_nxt--;
+	/*
+	 * If we are doing retransmissions, then snd_nxt will
+	 * not reflect the first unsent octet.  For ACK only
+	 * packets, we do not want the sequence number of the
+	 * retransmitted packet, we want the sequence number
+	 * of the next unsent octet.  So, if there is no data
+	 * (and no SYN or FIN), use snd_max instead of snd_nxt
+	 * when filling in ti_seq.  But if we are in persist
+	 * state, snd_max might reflect one byte beyond the
+	 * right edge of the window, so use snd_nxt in that
+	 * case, since we know we aren't doing a retransmission.
+	 * (retransmit and persist are mutually exclusive...)
+	 */
+	if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
+		ti->ti_seq = htonl(tp->snd_nxt);
+	else
+		ti->ti_seq = htonl(tp->snd_max);
+	ti->ti_ack = htonl(tp->rcv_nxt);
+	if (optlen) {
+		memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen);
+		ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
+	}
+	ti->ti_flags = flags;
+	/*
+	 * Calculate receive window.  Don't shrink window,
+	 * but avoid silly window syndrome.
+	 */
+	if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg)
+		win = 0;
+	if (win > (long)TCP_MAXWIN << tp->rcv_scale)
+		win = (long)TCP_MAXWIN << tp->rcv_scale;
+	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
+		win = (long)(tp->rcv_adv - tp->rcv_nxt);
+	ti->ti_win = htons((uint16_t) (win>>tp->rcv_scale));
+
+	if (SEQ_GT(tp->snd_up, tp->snd_una)) {
+		ti->ti_urp = htons((uint16_t)(tp->snd_up - ntohl(ti->ti_seq)));
+		ti->ti_flags |= TH_URG;
+	} else
+		/*
+		 * If no urgent pointer to send, then we pull
+		 * the urgent pointer to the left edge of the send window
+		 * so that it doesn't drift into the send window on sequence
+		 * number wraparound.
+		 */
+		tp->snd_up = tp->snd_una;		/* drag it along */
+
+	/*
+	 * Put TCP length in extended header, and then
+	 * checksum extended header and data.
+	 */
+	if (len + optlen)
+		ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) +
+		    optlen + len));
+	ti->ti_sum = cksum(m, (int)(hdrlen + len));
+
+	/*
+	 * In transmit state, time the transmission and arrange for
+	 * the retransmit.  In persist state, just set snd_max.
+	 */
+	if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
+		tcp_seq startseq = tp->snd_nxt;
+
+		/*
+		 * Advance snd_nxt over sequence space of this segment.
+		 */
+		if (flags & (TH_SYN|TH_FIN)) {
+			if (flags & TH_SYN)
+				tp->snd_nxt++;
+			if (flags & TH_FIN) {
+				tp->snd_nxt++;
+				tp->t_flags |= TF_SENTFIN;
+			}
+		}
+		tp->snd_nxt += len;
+		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
+			tp->snd_max = tp->snd_nxt;
+			/*
+			 * Time this transmission if not a retransmission and
+			 * not currently timing anything.
+			 */
+			if (tp->t_rtt == 0) {
+				tp->t_rtt = 1;
+				tp->t_rtseq = startseq;
+			}
+		}
+
+		/*
+		 * Set retransmit timer if not currently set,
+		 * and not doing an ack or a keep-alive probe.
+		 * Initial value for retransmit timer is smoothed
+		 * round-trip time + 2 * round-trip time variance.
+		 * Initialize shift counter which is used for backoff
+		 * of retransmit time.
+		 */
+		if (tp->t_timer[TCPT_REXMT] == 0 &&
+		    tp->snd_nxt != tp->snd_una) {
+			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+			if (tp->t_timer[TCPT_PERSIST]) {
+				tp->t_timer[TCPT_PERSIST] = 0;
+				tp->t_rxtshift = 0;
+			}
+		}
+	} else
+		if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
+			tp->snd_max = tp->snd_nxt + len;
+
+	/*
+	 * Fill in IP length and desired time to live and
+	 * send to IP level.  There should be a better way
+	 * to handle ttl and tos; we could keep them in
+	 * the template, but need a way to checksum without them.
+	 */
+	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
+
+    {
+
+	((struct ip *)ti)->ip_len = m->m_len;
+
+	((struct ip *)ti)->ip_ttl = IPDEFTTL;
+	((struct ip *)ti)->ip_tos = so->so_iptos;
+
+	error = ip_output(so, m);
+    }
+	if (error) {
+out:
+		return (error);
+	}
+
+	/*
+	 * Data sent (as far as we can tell).
+	 * If this advertises a larger window than any other segment,
+	 * then remember the size of the advertised window.
+	 * Any pending ACK has now been sent.
+	 */
+	if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
+		tp->rcv_adv = tp->rcv_nxt + win;
+	tp->last_ack_sent = tp->rcv_nxt;
+	tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
+	if (sendalot)
+		goto again;
+
+	return (0);
+}
+
+void
+tcp_setpersist(struct tcpcb *tp)
+{
+    int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
+
+	/*
+	 * Start/restart persistence timer.
+	 */
+	TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
+	    t * tcp_backoff[tp->t_rxtshift],
+	    TCPTV_PERSMIN, TCPTV_PERSMAX);
+	if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
+		tp->t_rxtshift++;
+}
diff --git a/qemu-0.15.x/slirp/tcp_subr.c b/qemu-0.15.x/slirp/tcp_subr.c
new file mode 100644
index 0000000..61079b1
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_subr.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *	@(#)tcp_subr.c	8.1 (Berkeley) 6/10/93
+ * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+/* patchable/settable parameters for tcp */
+/* Don't do rfc1323 performance enhancements */
+#define TCP_DO_RFC1323 0
+
+/*
+ * Tcp initialization
+ */
+void
+tcp_init(Slirp *slirp)
+{
+    slirp->tcp_iss = 1;		/* wrong */
+    slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
+    slirp->tcp_last_so = &slirp->tcb;
+}
+
+/*
+ * Create template to be used to send tcp packets on a connection.
+ * Call after host entry created, fills
+ * in a skeletal tcp/ip header, minimizing the amount of work
+ * necessary when the connection is used.
+ */
+void
+tcp_template(struct tcpcb *tp)
+{
+	struct socket *so = tp->t_socket;
+	register struct tcpiphdr *n = &tp->t_template;
+
+	n->ti_mbuf = NULL;
+	n->ti_x1 = 0;
+	n->ti_pr = IPPROTO_TCP;
+	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+	n->ti_src = so->so_faddr;
+	n->ti_dst = so->so_laddr;
+	n->ti_sport = so->so_fport;
+	n->ti_dport = so->so_lport;
+
+	n->ti_seq = 0;
+	n->ti_ack = 0;
+	n->ti_x2 = 0;
+	n->ti_off = 5;
+	n->ti_flags = 0;
+	n->ti_win = 0;
+	n->ti_sum = 0;
+	n->ti_urp = 0;
+}
+
+/*
+ * Send a single message to the TCP at address specified by
+ * the given TCP/IP header.  If m == 0, then we make a copy
+ * of the tcpiphdr at ti and send directly to the addressed host.
+ * This is used to force keep alive messages out using the TCP
+ * template for a connection tp->t_template.  If flags are given
+ * then we send a message back to the TCP which originated the
+ * segment ti, and discard the mbuf containing it and any other
+ * attached mbufs.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ */
+void
+tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
+            tcp_seq ack, tcp_seq seq, int flags)
+{
+	register int tlen;
+	int win = 0;
+
+	DEBUG_CALL("tcp_respond");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("ti = %lx", (long)ti);
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("ack = %u", ack);
+	DEBUG_ARG("seq = %u", seq);
+	DEBUG_ARG("flags = %x", flags);
+
+	if (tp)
+		win = sbspace(&tp->t_socket->so_rcv);
+        if (m == NULL) {
+		if ((m = m_get(tp->t_socket->slirp)) == NULL)
+			return;
+		tlen = 0;
+		m->m_data += IF_MAXLINKHDR;
+		*mtod(m, struct tcpiphdr *) = *ti;
+		ti = mtod(m, struct tcpiphdr *);
+		flags = TH_ACK;
+	} else {
+		/*
+		 * ti points into m so the next line is just making
+		 * the mbuf point to ti
+		 */
+		m->m_data = (caddr_t)ti;
+
+		m->m_len = sizeof (struct tcpiphdr);
+		tlen = 0;
+#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+		xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
+		xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+#undef xchg
+	}
+	ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
+	tlen += sizeof (struct tcpiphdr);
+	m->m_len = tlen;
+
+        ti->ti_mbuf = NULL;
+	ti->ti_x1 = 0;
+	ti->ti_seq = htonl(seq);
+	ti->ti_ack = htonl(ack);
+	ti->ti_x2 = 0;
+	ti->ti_off = sizeof (struct tcphdr) >> 2;
+	ti->ti_flags = flags;
+	if (tp)
+		ti->ti_win = htons((uint16_t) (win >> tp->rcv_scale));
+	else
+		ti->ti_win = htons((uint16_t)win);
+	ti->ti_urp = 0;
+	ti->ti_sum = 0;
+	ti->ti_sum = cksum(m, tlen);
+	((struct ip *)ti)->ip_len = tlen;
+
+	if(flags & TH_RST)
+	  ((struct ip *)ti)->ip_ttl = MAXTTL;
+	else
+	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
+
+	(void) ip_output((struct socket *)0, m);
+}
+
+/*
+ * Create a new TCP control block, making an
+ * empty reassembly queue and hooking it to the argument
+ * protocol control block.
+ */
+struct tcpcb *
+tcp_newtcpcb(struct socket *so)
+{
+	register struct tcpcb *tp;
+
+	tp = (struct tcpcb *)malloc(sizeof(*tp));
+	if (tp == NULL)
+		return ((struct tcpcb *)0);
+
+	memset((char *) tp, 0, sizeof(struct tcpcb));
+	tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
+	tp->t_maxseg = TCP_MSS;
+
+	tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
+	tp->t_socket = so;
+
+	/*
+	 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
+	 * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
+	 * reasonable initial retransmit time.
+	 */
+	tp->t_srtt = TCPTV_SRTTBASE;
+	tp->t_rttvar = TCPTV_SRTTDFLT << 2;
+	tp->t_rttmin = TCPTV_MIN;
+
+	TCPT_RANGESET(tp->t_rxtcur,
+	    ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
+	    TCPTV_MIN, TCPTV_REXMTMAX);
+
+	tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+	tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+	tp->t_state = TCPS_CLOSED;
+
+	so->so_tcpcb = tp;
+
+	return (tp);
+}
+
+/*
+ * Drop a TCP connection, reporting
+ * the specified error.  If connection is synchronized,
+ * then send a RST to peer.
+ */
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
+{
+	DEBUG_CALL("tcp_drop");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("errno = %d", errno);
+
+	if (TCPS_HAVERCVDSYN(tp->t_state)) {
+		tp->t_state = TCPS_CLOSED;
+		(void) tcp_output(tp);
+	}
+	return (tcp_close(tp));
+}
+
+/*
+ * Close a TCP control block:
+ *	discard all space held by the tcp
+ *	discard internet protocol block
+ *	wake up any sleepers
+ */
+struct tcpcb *
+tcp_close(struct tcpcb *tp)
+{
+	register struct tcpiphdr *t;
+	struct socket *so = tp->t_socket;
+	Slirp *slirp = so->slirp;
+	register struct mbuf *m;
+
+	DEBUG_CALL("tcp_close");
+	DEBUG_ARG("tp = %lx", (long )tp);
+
+	/* free the reassembly queue, if any */
+	t = tcpfrag_list_first(tp);
+	while (!tcpfrag_list_end(t, tp)) {
+		t = tcpiphdr_next(t);
+		m = tcpiphdr_prev(t)->ti_mbuf;
+		remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
+		m_free(m);
+	}
+	free(tp);
+        so->so_tcpcb = NULL;
+	/* clobber input socket cache if we're closing the cached connection */
+	if (so == slirp->tcp_last_so)
+		slirp->tcp_last_so = &slirp->tcb;
+	closesocket(so->s);
+	sbfree(&so->so_rcv);
+	sbfree(&so->so_snd);
+	sofree(so);
+	return ((struct tcpcb *)0);
+}
+
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ * We can let the user exit from the close as soon as the FIN is acked.
+ */
+void
+tcp_sockclosed(struct tcpcb *tp)
+{
+
+	DEBUG_CALL("tcp_sockclosed");
+	DEBUG_ARG("tp = %lx", (long)tp);
+
+	switch (tp->t_state) {
+
+	case TCPS_CLOSED:
+	case TCPS_LISTEN:
+	case TCPS_SYN_SENT:
+		tp->t_state = TCPS_CLOSED;
+		tp = tcp_close(tp);
+		break;
+
+	case TCPS_SYN_RECEIVED:
+	case TCPS_ESTABLISHED:
+		tp->t_state = TCPS_FIN_WAIT_1;
+		break;
+
+	case TCPS_CLOSE_WAIT:
+		tp->t_state = TCPS_LAST_ACK;
+		break;
+	}
+	if (tp)
+		tcp_output(tp);
+}
+
+/*
+ * Connect to a host on the Internet
+ * Called by tcp_input
+ * Only do a connect, the tcp fields will be set in tcp_input
+ * return 0 if there's a result of the connect,
+ * else return -1 means we're still connecting
+ * The return value is almost always -1 since the socket is
+ * nonblocking.  Connect returns after the SYN is sent, and does
+ * not wait for ACK+SYN.
+ */
+int tcp_fconnect(struct socket *so)
+{
+  Slirp *slirp = so->slirp;
+  int ret=0;
+
+  DEBUG_CALL("tcp_fconnect");
+  DEBUG_ARG("so = %lx", (long )so);
+
+  if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
+    int opt, s=so->s;
+    struct sockaddr_in addr;
+
+    fd_nonblock(s);
+    opt = 1;
+    setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
+    opt = 1;
+    setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
+
+    addr.sin_family = AF_INET;
+    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+        slirp->vnetwork_addr.s_addr) {
+      /* It's an alias */
+      if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+	if (get_dns_addr(&addr.sin_addr) < 0)
+	  addr.sin_addr = loopback_addr;
+      } else {
+	addr.sin_addr = loopback_addr;
+      }
+    } else
+      addr.sin_addr = so->so_faddr;
+    addr.sin_port = so->so_fport;
+
+    DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
+		"addr.sin_addr.s_addr=%.16s\n",
+		ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+    /* We don't care what port we get */
+    ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
+
+    /*
+     * If it's not in progress, it failed, so we just return 0,
+     * without clearing SS_NOFDREF
+     */
+    soisfconnecting(so);
+  }
+
+  return(ret);
+}
+
+/*
+ * Accept the socket and connect to the local-host
+ *
+ * We have a problem. The correct thing to do would be
+ * to first connect to the local-host, and only if the
+ * connection is accepted, then do an accept() here.
+ * But, a) we need to know who's trying to connect
+ * to the socket to be able to SYN the local-host, and
+ * b) we are already connected to the foreign host by
+ * the time it gets to accept(), so... We simply accept
+ * here and SYN the local-host.
+ */
+void
+tcp_connect(struct socket *inso)
+{
+	Slirp *slirp = inso->slirp;
+	struct socket *so;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(struct sockaddr_in);
+	struct tcpcb *tp;
+	int s, opt;
+
+	DEBUG_CALL("tcp_connect");
+	DEBUG_ARG("inso = %lx", (long)inso);
+
+	/*
+	 * If it's an SS_ACCEPTONCE socket, no need to socreate()
+	 * another socket, just use the accept() socket.
+	 */
+	if (inso->so_state & SS_FACCEPTONCE) {
+		/* FACCEPTONCE already have a tcpcb */
+		so = inso;
+	} else {
+		if ((so = socreate(slirp)) == NULL) {
+			/* If it failed, get rid of the pending connection */
+			closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
+			return;
+		}
+		if (tcp_attach(so) < 0) {
+			free(so); /* NOT sofree */
+			return;
+		}
+		so->so_laddr = inso->so_laddr;
+		so->so_lport = inso->so_lport;
+	}
+
+	(void) tcp_mss(sototcpcb(so), 0);
+
+	if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
+		tcp_close(sototcpcb(so)); /* This will sofree() as well */
+		return;
+	}
+	fd_nonblock(s);
+	opt = 1;
+	setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+	opt = 1;
+	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+	opt = 1;
+	setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
+
+	so->so_fport = addr.sin_port;
+	so->so_faddr = addr.sin_addr;
+	/* Translate connections from localhost to the real hostname */
+	if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
+	   so->so_faddr = slirp->vhost_addr;
+
+	/* Close the accept() socket, set right state */
+	if (inso->so_state & SS_FACCEPTONCE) {
+		closesocket(so->s); /* If we only accept once, close the accept() socket */
+		so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
+					   /* if it's not FACCEPTONCE, it's already NOFDREF */
+	}
+	so->s = s;
+	so->so_state |= SS_INCOMING;
+
+	so->so_iptos = tcp_tos(so);
+	tp = sototcpcb(so);
+
+	tcp_template(tp);
+
+	tp->t_state = TCPS_SYN_SENT;
+	tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+	tp->iss = slirp->tcp_iss;
+	slirp->tcp_iss += TCP_ISSINCR/2;
+	tcp_sendseqinit(tp);
+	tcp_output(tp);
+}
+
+/*
+ * Attach a TCPCB to a socket.
+ */
+int
+tcp_attach(struct socket *so)
+{
+	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
+	   return -1;
+
+	insque(so, &so->slirp->tcb);
+
+	return 0;
+}
+
+/*
+ * Set the socket's type of service field
+ */
+static const struct tos_t tcptos[] = {
+	  {0, 20, IPTOS_THROUGHPUT, 0},	/* ftp data */
+	  {21, 21, IPTOS_LOWDELAY,  EMU_FTP},	/* ftp control */
+	  {0, 23, IPTOS_LOWDELAY, 0},	/* telnet */
+	  {0, 80, IPTOS_THROUGHPUT, 0},	/* WWW */
+	  {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT},	/* rlogin */
+	  {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT},	/* shell */
+	  {0, 544, IPTOS_LOWDELAY, EMU_KSH},		/* kshell */
+	  {0, 543, IPTOS_LOWDELAY, 0},	/* klogin */
+	  {0, 6667, IPTOS_THROUGHPUT, EMU_IRC},	/* IRC */
+	  {0, 6668, IPTOS_THROUGHPUT, EMU_IRC},	/* IRC undernet */
+	  {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
+	  {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
+	  {0, 0, 0, 0}
+};
+
+static struct emu_t *tcpemu = NULL;
+
+/*
+ * Return TOS according to the above table
+ */
+uint8_t
+tcp_tos(struct socket *so)
+{
+	int i = 0;
+	struct emu_t *emup;
+
+	while(tcptos[i].tos) {
+		if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
+		    (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
+			so->so_emu = tcptos[i].emu;
+			return tcptos[i].tos;
+		}
+		i++;
+	}
+
+	/* Nope, lets see if there's a user-added one */
+	for (emup = tcpemu; emup; emup = emup->next) {
+		if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
+		    (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
+			so->so_emu = emup->emu;
+			return emup->tos;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Emulate programs that try and connect to us
+ * This includes ftp (the data connection is
+ * initiated by the server) and IRC (DCC CHAT and
+ * DCC SEND) for now
+ *
+ * NOTE: It's possible to crash SLiRP by sending it
+ * unstandard strings to emulate... if this is a problem,
+ * more checks are needed here
+ *
+ * XXX Assumes the whole command came in one packet
+ *
+ * XXX Some ftp clients will have their TOS set to
+ * LOWDELAY and so Nagel will kick in.  Because of this,
+ * we'll get the first letter, followed by the rest, so
+ * we simply scan for ORT instead of PORT...
+ * DCC doesn't have this problem because there's other stuff
+ * in the packet before the DCC command.
+ *
+ * Return 1 if the mbuf m is still valid and should be
+ * sbappend()ed
+ *
+ * NOTE: if you return 0 you MUST m_free() the mbuf!
+ */
+int
+tcp_emu(struct socket *so, struct mbuf *m)
+{
+	Slirp *slirp = so->slirp;
+	u_int n1, n2, n3, n4, n5, n6;
+        char buff[257];
+	uint32_t laddr;
+	u_int lport;
+	char *bptr;
+
+	DEBUG_CALL("tcp_emu");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+
+	switch(so->so_emu) {
+		int x, i;
+
+	 case EMU_IDENT:
+		/*
+		 * Identification protocol as per rfc-1413
+		 */
+
+		{
+			struct socket *tmpso;
+			struct sockaddr_in addr;
+			socklen_t addrlen = sizeof(struct sockaddr_in);
+			struct sbuf *so_rcv = &so->so_rcv;
+
+			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
+			so_rcv->sb_wptr += m->m_len;
+			so_rcv->sb_rptr += m->m_len;
+			m->m_data[m->m_len] = 0; /* NULL terminate */
+			if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
+				if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
+					HTONS(n1);
+					HTONS(n2);
+					/* n2 is the one on our host */
+					for (tmpso = slirp->tcb.so_next;
+					     tmpso != &slirp->tcb;
+					     tmpso = tmpso->so_next) {
+						if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
+						    tmpso->so_lport == n2 &&
+						    tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
+						    tmpso->so_fport == n1) {
+							if (getsockname(tmpso->s,
+								(struct sockaddr *)&addr, &addrlen) == 0)
+							   n2 = ntohs(addr.sin_port);
+							break;
+						}
+					}
+				}
+                                so_rcv->sb_cc = snprintf(so_rcv->sb_data,
+                                                         so_rcv->sb_datalen,
+                                                         "%d,%d\r\n", n1, n2);
+				so_rcv->sb_rptr = so_rcv->sb_data;
+				so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
+			}
+			m_free(m);
+			return 0;
+		}
+
+        case EMU_FTP: /* ftp */
+                *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
+		if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
+			/*
+			 * Need to emulate the PORT command
+			 */
+			x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
+				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
+			if (x < 6)
+			   return 1;
+
+			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+			lport = htons((n5 << 8) | (n6));
+
+			if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
+			                     lport, SS_FACCEPTONCE)) == NULL) {
+			   return 1;
+			}
+			n6 = ntohs(so->so_fport);
+
+			n5 = (n6 >> 8) & 0xff;
+			n6 &= 0xff;
+
+			laddr = ntohl(so->so_faddr.s_addr);
+
+			n1 = ((laddr >> 24) & 0xff);
+			n2 = ((laddr >> 16) & 0xff);
+			n3 = ((laddr >> 8)  & 0xff);
+			n4 =  (laddr & 0xff);
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "ORT %d,%d,%d,%d,%d,%d\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+			return 1;
+		} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
+			/*
+			 * Need to emulate the PASV response
+			 */
+			x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
+				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
+			if (x < 6)
+			   return 1;
+
+			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+			lport = htons((n5 << 8) | (n6));
+
+			if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
+			                     lport, SS_FACCEPTONCE)) == NULL) {
+			   return 1;
+			}
+			n6 = ntohs(so->so_fport);
+
+			n5 = (n6 >> 8) & 0xff;
+			n6 &= 0xff;
+
+			laddr = ntohl(so->so_faddr.s_addr);
+
+			n1 = ((laddr >> 24) & 0xff);
+			n2 = ((laddr >> 16) & 0xff);
+			n3 = ((laddr >> 8)  & 0xff);
+			n4 =  (laddr & 0xff);
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+			m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+
+			return 1;
+		}
+
+		return 1;
+
+	 case EMU_KSH:
+		/*
+		 * The kshell (Kerberos rsh) and shell services both pass
+		 * a local port port number to carry signals to the server
+		 * and stderr to the client.  It is passed at the beginning
+		 * of the connection as a NUL-terminated decimal ASCII string.
+		 */
+		so->so_emu = 0;
+		for (lport = 0, i = 0; i < m->m_len-1; ++i) {
+			if (m->m_data[i] < '0' || m->m_data[i] > '9')
+				return 1;       /* invalid number */
+			lport *= 10;
+			lport += m->m_data[i] - '0';
+		}
+		if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
+		    (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
+		                     htons(lport), SS_FACCEPTONCE)) != NULL)
+                    m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
+                                        ntohs(so->so_fport)) + 1;
+		return 1;
+
+	 case EMU_IRC:
+		/*
+		 * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
+		 */
+		*(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
+		if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
+			 return 1;
+
+		/* The %256s is for the broken mIRC */
+		if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
+			if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+			                     htonl(laddr), htons(lport),
+			                     SS_FACCEPTONCE)) == NULL) {
+				return 1;
+			}
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC CHAT chat %lu %u%c\n",
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), 1);
+		} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+			if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+			                     htonl(laddr), htons(lport),
+			                     SS_FACCEPTONCE)) == NULL) {
+				return 1;
+			}
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC SEND %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+		} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+			if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+			                     htonl(laddr), htons(lport),
+			                     SS_FACCEPTONCE)) == NULL) {
+				return 1;
+			}
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC MOVE %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+		}
+		return 1;
+
+	 case EMU_REALAUDIO:
+                /*
+		 * RealAudio emulation - JP. We must try to parse the incoming
+		 * data and try to find the two characters that contain the
+		 * port number. Then we redirect an udp port and replace the
+		 * number with the real port we got.
+		 *
+		 * The 1.0 beta versions of the player are not supported
+		 * any more.
+		 *
+		 * A typical packet for player version 1.0 (release version):
+		 *
+		 * 0000:50 4E 41 00 05
+		 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
+		 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
+		 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
+		 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
+		 *
+		 * Now the port number 0x1BD7 is found at offset 0x04 of the
+		 * Now the port number 0x1BD7 is found at offset 0x04 of the
+		 * second packet. This time we received five bytes first and
+		 * then the rest. You never know how many bytes you get.
+		 *
+		 * A typical packet for player version 2.0 (beta):
+		 *
+		 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
+		 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
+		 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
+		 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
+		 * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
+		 *
+		 * Port number 0x1BC1 is found at offset 0x0d.
+		 *
+		 * This is just a horrible switch statement. Variable ra tells
+		 * us where we're going.
+		 */
+
+		bptr = m->m_data;
+		while (bptr < m->m_data + m->m_len) {
+			u_short p;
+			static int ra = 0;
+			char ra_tbl[4];
+
+			ra_tbl[0] = 0x50;
+			ra_tbl[1] = 0x4e;
+			ra_tbl[2] = 0x41;
+			ra_tbl[3] = 0;
+
+			switch (ra) {
+			 case 0:
+			 case 2:
+			 case 3:
+				if (*bptr++ != ra_tbl[ra]) {
+					ra = 0;
+					continue;
+				}
+				break;
+
+			 case 1:
+				/*
+				 * We may get 0x50 several times, ignore them
+				 */
+				if (*bptr == 0x50) {
+					ra = 1;
+					bptr++;
+					continue;
+				} else if (*bptr++ != ra_tbl[ra]) {
+					ra = 0;
+					continue;
+				}
+				break;
+
+			 case 4:
+				/*
+				 * skip version number
+				 */
+				bptr++;
+				break;
+
+			 case 5:
+				/*
+				 * The difference between versions 1.0 and
+				 * 2.0 is here. For future versions of
+				 * the player this may need to be modified.
+				 */
+				if (*(bptr + 1) == 0x02)
+				   bptr += 8;
+				else
+				   bptr += 4;
+				break;
+
+			 case 6:
+				/* This is the field containing the port
+				 * number that RA-player is listening to.
+				 */
+				lport = (((u_char*)bptr)[0] << 8)
+				+ ((u_char *)bptr)[1];
+				if (lport < 6970)
+				   lport += 256;   /* don't know why */
+				if (lport < 6970 || lport > 7170)
+				   return 1;       /* failed */
+
+				/* try to get udp port between 6970 - 7170 */
+				for (p = 6970; p < 7071; p++) {
+					if (udp_listen(slirp, INADDR_ANY,
+						       htons(p),
+						       so->so_laddr.s_addr,
+						       htons(lport),
+						       SS_FACCEPTONCE)) {
+						break;
+					}
+				}
+				if (p == 7071)
+				   p = 0;
+				*(u_char *)bptr++ = (p >> 8) & 0xff;
+                                *(u_char *)bptr = p & 0xff;
+				ra = 0;
+				return 1;   /* port redirected, we're done */
+				break;
+
+			 default:
+				ra = 0;
+			}
+			ra++;
+		}
+		return 1;
+
+	 default:
+		/* Ooops, not emulated, won't call tcp_emu again */
+		so->so_emu = 0;
+		return 1;
+	}
+}
+
+/*
+ * Do misc. config of SLiRP while its running.
+ * Return 0 if this connections is to be closed, 1 otherwise,
+ * return 2 if this is a command-line connection
+ */
+int tcp_ctl(struct socket *so)
+{
+    Slirp *slirp = so->slirp;
+    struct sbuf *sb = &so->so_snd;
+    struct ex_list *ex_ptr;
+    int do_pty;
+
+    DEBUG_CALL("tcp_ctl");
+    DEBUG_ARG("so = %lx", (long )so);
+
+    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+        /* Check if it's pty_exec */
+        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+            if (ex_ptr->ex_fport == so->so_fport &&
+                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
+                if (ex_ptr->ex_pty == 3) {
+                    so->s = -1;
+                    so->extra = (void *)ex_ptr->ex_exec;
+                    return 1;
+                }
+                do_pty = ex_ptr->ex_pty;
+                DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
+                return fork_exec(so, ex_ptr->ex_exec, do_pty);
+            }
+        }
+    }
+    sb->sb_cc =
+        snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
+                 "Error: No application configured.\r\n");
+    sb->sb_wptr += sb->sb_cc;
+    return 0;
+}
diff --git a/qemu-0.15.x/slirp/tcp_timer.c b/qemu-0.15.x/slirp/tcp_timer.c
new file mode 100644
index 0000000..6c5bb11
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_timer.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *	@(#)tcp_timer.c	8.1 (Berkeley) 6/10/93
+ * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
+ */
+
+#include <slirp.h>
+
+static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
+
+/*
+ * Fast timeout routine for processing delayed acks
+ */
+void
+tcp_fasttimo(Slirp *slirp)
+{
+	register struct socket *so;
+	register struct tcpcb *tp;
+
+	DEBUG_CALL("tcp_fasttimo");
+
+	so = slirp->tcb.so_next;
+	if (so)
+	for (; so != &slirp->tcb; so = so->so_next)
+		if ((tp = (struct tcpcb *)so->so_tcpcb) &&
+		    (tp->t_flags & TF_DELACK)) {
+			tp->t_flags &= ~TF_DELACK;
+			tp->t_flags |= TF_ACKNOW;
+			(void) tcp_output(tp);
+		}
+}
+
+/*
+ * Tcp protocol timeout routine called every 500 ms.
+ * Updates the timers in all active tcb's and
+ * causes finite state machine actions if timers expire.
+ */
+void
+tcp_slowtimo(Slirp *slirp)
+{
+	register struct socket *ip, *ipnxt;
+	register struct tcpcb *tp;
+	register int i;
+
+	DEBUG_CALL("tcp_slowtimo");
+
+	/*
+	 * Search through tcb's and update active timers.
+	 */
+	ip = slirp->tcb.so_next;
+        if (ip == NULL) {
+            return;
+        }
+	for (; ip != &slirp->tcb; ip = ipnxt) {
+		ipnxt = ip->so_next;
+		tp = sototcpcb(ip);
+                if (tp == NULL) {
+                        continue;
+                }
+		for (i = 0; i < TCPT_NTIMERS; i++) {
+			if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
+				tcp_timers(tp,i);
+				if (ipnxt->so_prev != ip)
+					goto tpgone;
+			}
+		}
+		tp->t_idle++;
+		if (tp->t_rtt)
+		   tp->t_rtt++;
+tpgone:
+		;
+	}
+	slirp->tcp_iss += TCP_ISSINCR/PR_SLOWHZ;	/* increment iss */
+	slirp->tcp_now++;				/* for timestamps */
+}
+
+/*
+ * Cancel all timers for TCP tp.
+ */
+void
+tcp_canceltimers(struct tcpcb *tp)
+{
+	register int i;
+
+	for (i = 0; i < TCPT_NTIMERS; i++)
+		tp->t_timer[i] = 0;
+}
+
+const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
+   { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
+
+/*
+ * TCP timer processing.
+ */
+static struct tcpcb *
+tcp_timers(register struct tcpcb *tp, int timer)
+{
+	register int rexmt;
+
+	DEBUG_CALL("tcp_timers");
+
+	switch (timer) {
+
+	/*
+	 * 2 MSL timeout in shutdown went off.  If we're closed but
+	 * still waiting for peer to close and connection has been idle
+	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
+	 * control block.  Otherwise, check again in a bit.
+	 */
+	case TCPT_2MSL:
+		if (tp->t_state != TCPS_TIME_WAIT &&
+		    tp->t_idle <= TCP_MAXIDLE)
+			tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
+		else
+			tp = tcp_close(tp);
+		break;
+
+	/*
+	 * Retransmission timer went off.  Message has not
+	 * been acked within retransmit interval.  Back off
+	 * to a longer retransmit interval and retransmit one segment.
+	 */
+	case TCPT_REXMT:
+
+		/*
+		 * XXXXX If a packet has timed out, then remove all the queued
+		 * packets for that session.
+		 */
+
+		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
+			/*
+			 * This is a hack to suit our terminal server here at the uni of canberra
+			 * since they have trouble with zeroes... It usually lets them through
+			 * unharmed, but under some conditions, it'll eat the zeros.  If we
+			 * keep retransmitting it, it'll keep eating the zeroes, so we keep
+			 * retransmitting, and eventually the connection dies...
+			 * (this only happens on incoming data)
+			 *
+			 * So, if we were gonna drop the connection from too many retransmits,
+			 * don't... instead halve the t_maxseg, which might break up the NULLs and
+			 * let them through
+			 *
+			 * *sigh*
+			 */
+
+			tp->t_maxseg >>= 1;
+			if (tp->t_maxseg < 32) {
+				/*
+				 * We tried our best, now the connection must die!
+				 */
+				tp->t_rxtshift = TCP_MAXRXTSHIFT;
+				tp = tcp_drop(tp, tp->t_softerror);
+				/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
+				return (tp); /* XXX */
+			}
+
+			/*
+			 * Set rxtshift to 6, which is still at the maximum
+			 * backoff time
+			 */
+			tp->t_rxtshift = 6;
+		}
+		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+		TCPT_RANGESET(tp->t_rxtcur, rexmt,
+		    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
+		tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+		/*
+		 * If losing, let the lower level know and try for
+		 * a better route.  Also, if we backed off this far,
+		 * our srtt estimate is probably bogus.  Clobber it
+		 * so we'll take the next rtt measurement as our srtt;
+		 * move the current srtt into rttvar to keep the current
+		 * retransmit times until then.
+		 */
+		if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
+			tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
+			tp->t_srtt = 0;
+		}
+		tp->snd_nxt = tp->snd_una;
+		/*
+		 * If timing a segment in this window, stop the timer.
+		 */
+		tp->t_rtt = 0;
+		/*
+		 * Close the congestion window down to one segment
+		 * (we'll open it by one segment for each ack we get).
+		 * Since we probably have a window's worth of unacked
+		 * data accumulated, this "slow start" keeps us from
+		 * dumping all that data as back-to-back packets (which
+		 * might overwhelm an intermediate gateway).
+		 *
+		 * There are two phases to the opening: Initially we
+		 * open by one mss on each ack.  This makes the window
+		 * size increase exponentially with time.  If the
+		 * window is larger than the path can handle, this
+		 * exponential growth results in dropped packet(s)
+		 * almost immediately.  To get more time between
+		 * drops but still "push" the network to take advantage
+		 * of improving conditions, we switch from exponential
+		 * to linear window opening at some threshold size.
+		 * For a threshold, we use half the current window
+		 * size, truncated to a multiple of the mss.
+		 *
+		 * (the minimum cwnd that will give us exponential
+		 * growth is 2 mss.  We don't allow the threshold
+		 * to go below this.)
+		 */
+		{
+		u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
+		if (win < 2)
+			win = 2;
+		tp->snd_cwnd = tp->t_maxseg;
+		tp->snd_ssthresh = win * tp->t_maxseg;
+		tp->t_dupacks = 0;
+		}
+		(void) tcp_output(tp);
+		break;
+
+	/*
+	 * Persistence timer into zero window.
+	 * Force a byte to be output, if possible.
+	 */
+	case TCPT_PERSIST:
+		tcp_setpersist(tp);
+		tp->t_force = 1;
+		(void) tcp_output(tp);
+		tp->t_force = 0;
+		break;
+
+	/*
+	 * Keep-alive timer went off; send something
+	 * or drop connection if idle for too long.
+	 */
+	case TCPT_KEEP:
+		if (tp->t_state < TCPS_ESTABLISHED)
+			goto dropit;
+
+		if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) {
+		    	if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
+				goto dropit;
+			/*
+			 * Send a packet designed to force a response
+			 * if the peer is up and reachable:
+			 * either an ACK if the connection is still alive,
+			 * or an RST if the peer has closed the connection
+			 * due to timeout or reboot.
+			 * Using sequence number tp->snd_una-1
+			 * causes the transmitted zero-length segment
+			 * to lie outside the receive window;
+			 * by the protocol spec, this requires the
+			 * correspondent TCP to respond.
+			 */
+			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
+			    tp->rcv_nxt, tp->snd_una - 1, 0);
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
+		} else
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
+		break;
+
+	dropit:
+		tp = tcp_drop(tp, 0);
+		break;
+	}
+
+	return (tp);
+}
diff --git a/qemu-0.15.x/slirp/tcp_timer.h b/qemu-0.15.x/slirp/tcp_timer.h
new file mode 100644
index 0000000..ff17914
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_timer.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)tcp_timer.h	8.1 (Berkeley) 6/10/93
+ * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
+ */
+
+#ifndef _TCP_TIMER_H_
+#define _TCP_TIMER_H_
+
+/*
+ * Definitions of the TCP timers.  These timers are counted
+ * down PR_SLOWHZ times a second.
+ */
+#define	TCPT_NTIMERS	4
+
+#define	TCPT_REXMT	0		/* retransmit */
+#define	TCPT_PERSIST	1		/* retransmit persistence */
+#define	TCPT_KEEP	2		/* keep alive */
+#define	TCPT_2MSL	3		/* 2*msl quiet time timer */
+
+/*
+ * The TCPT_REXMT timer is used to force retransmissions.
+ * The TCP has the TCPT_REXMT timer set whenever segments
+ * have been sent for which ACKs are expected but not yet
+ * received.  If an ACK is received which advances tp->snd_una,
+ * then the retransmit timer is cleared (if there are no more
+ * outstanding segments) or reset to the base value (if there
+ * are more ACKs expected).  Whenever the retransmit timer goes off,
+ * we retransmit one unacknowledged segment, and do a backoff
+ * on the retransmit timer.
+ *
+ * The TCPT_PERSIST timer is used to keep window size information
+ * flowing even if the window goes shut.  If all previous transmissions
+ * have been acknowledged (so that there are no retransmissions in progress),
+ * and the window is too small to bother sending anything, then we start
+ * the TCPT_PERSIST timer.  When it expires, if the window is nonzero,
+ * we go to transmit state.  Otherwise, at intervals send a single byte
+ * into the peer's window to force him to update our window information.
+ * We do this at most as often as TCPT_PERSMIN time intervals,
+ * but no more frequently than the current estimate of round-trip
+ * packet time.  The TCPT_PERSIST timer is cleared whenever we receive
+ * a window update from the peer.
+ *
+ * The TCPT_KEEP timer is used to keep connections alive.  If an
+ * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
+ * but not yet established, then we drop the connection.  Once the connection
+ * is established, if the connection is idle for TCPTV_KEEP_IDLE time
+ * (and keepalives have been enabled on the socket), we begin to probe
+ * the connection.  We force the peer to send us a segment by sending:
+ *	<SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
+ * This segment is (deliberately) outside the window, and should elicit
+ * an ack segment in response from the peer.  If, despite the TCPT_KEEP
+ * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
+ * amount of time probing, then we drop the connection.
+ */
+
+/*
+ * Time constants.
+ */
+#define TCPTV_MSL       ( 5*PR_SLOWHZ)          /* max seg lifetime (hah!) */
+
+#define	TCPTV_SRTTBASE	0			/* base roundtrip time;
+						   if 0, no idea yet */
+#define	TCPTV_SRTTDFLT	(  3*PR_SLOWHZ)		/* assumed RTT if no info */
+
+#define	TCPTV_PERSMIN	(  5*PR_SLOWHZ)		/* retransmit persistence */
+#define	TCPTV_PERSMAX	( 60*PR_SLOWHZ)		/* maximum persist interval */
+
+#define	TCPTV_KEEP_INIT	( 75*PR_SLOWHZ)		/* initial connect keep alive */
+#define	TCPTV_KEEP_IDLE	(120*60*PR_SLOWHZ)	/* dflt time before probing */
+#define	TCPTV_KEEPINTVL	( 75*PR_SLOWHZ)		/* default probe interval */
+#define	TCPTV_KEEPCNT	8			/* max probes before drop */
+
+#define	TCPTV_MIN	(  1*PR_SLOWHZ)		/* minimum allowable value */
+#define TCPTV_REXMTMAX  ( 12*PR_SLOWHZ)		/* max allowable REXMT value */
+
+#define	TCP_LINGERTIME	120			/* linger at most 2 minutes */
+
+#define TCP_MAXRXTSHIFT 12                      /* maximum retransmits */
+
+
+/*
+ * Force a time value to be in a certain range.
+ */
+#define	TCPT_RANGESET(tv, value, tvmin, tvmax) { \
+	(tv) = (value); \
+	if ((tv) < (tvmin)) \
+		(tv) = (tvmin); \
+	else if ((tv) > (tvmax)) \
+		(tv) = (tvmax); \
+}
+
+extern const int tcp_backoff[];
+
+struct tcpcb;
+
+void tcp_fasttimo(Slirp *);
+void tcp_slowtimo(Slirp *);
+void tcp_canceltimers(struct tcpcb *);
+
+#endif
diff --git a/qemu-0.15.x/slirp/tcp_var.h b/qemu-0.15.x/slirp/tcp_var.h
new file mode 100644
index 0000000..004193f
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcp_var.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1982, 1986, 1993, 1994
+ *	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. 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.
+ *
+ *	@(#)tcp_var.h	8.3 (Berkeley) 4/10/94
+ * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
+ */
+
+#ifndef _TCP_VAR_H_
+#define _TCP_VAR_H_
+
+#include "tcpip.h"
+#include "tcp_timer.h"
+
+/*
+ * Tcp control block, one per tcp; fields:
+ */
+struct tcpcb {
+	struct tcpiphdr *seg_next;	/* sequencing queue */
+	struct tcpiphdr *seg_prev;
+	short	t_state;		/* state of this connection */
+	short	t_timer[TCPT_NTIMERS];	/* tcp timers */
+	short	t_rxtshift;		/* log(2) of rexmt exp. backoff */
+	short	t_rxtcur;		/* current retransmit value */
+	short	t_dupacks;		/* consecutive dup acks recd */
+	u_short	t_maxseg;		/* maximum segment size */
+	char	t_force;		/* 1 if forcing out a byte */
+	u_short	t_flags;
+#define	TF_ACKNOW	0x0001		/* ack peer immediately */
+#define	TF_DELACK	0x0002		/* ack, but try to delay it */
+#define	TF_NODELAY	0x0004		/* don't delay packets to coalesce */
+#define	TF_NOOPT	0x0008		/* don't use tcp options */
+#define	TF_SENTFIN	0x0010		/* have sent FIN */
+#define	TF_REQ_SCALE	0x0020		/* have/will request window scaling */
+#define	TF_RCVD_SCALE	0x0040		/* other side has requested scaling */
+#define	TF_REQ_TSTMP	0x0080		/* have/will request timestamps */
+#define	TF_RCVD_TSTMP	0x0100		/* a timestamp was received in SYN */
+#define	TF_SACK_PERMIT	0x0200		/* other side said I could SACK */
+
+	struct	tcpiphdr t_template;    /* static skeletal packet for xmit */
+
+	struct	socket *t_socket;		/* back pointer to socket */
+/*
+ * The following fields are used as in the protocol specification.
+ * See RFC783, Dec. 1981, page 21.
+ */
+/* send sequence variables */
+	tcp_seq	snd_una;		/* send unacknowledged */
+	tcp_seq	snd_nxt;		/* send next */
+	tcp_seq	snd_up;			/* send urgent pointer */
+	tcp_seq	snd_wl1;		/* window update seg seq number */
+	tcp_seq	snd_wl2;		/* window update seg ack number */
+	tcp_seq	iss;			/* initial send sequence number */
+	uint32_t snd_wnd;		/* send window */
+/* receive sequence variables */
+	uint32_t rcv_wnd;		/* receive window */
+	tcp_seq	rcv_nxt;		/* receive next */
+	tcp_seq	rcv_up;			/* receive urgent pointer */
+	tcp_seq	irs;			/* initial receive sequence number */
+/*
+ * Additional variables for this implementation.
+ */
+/* receive variables */
+	tcp_seq	rcv_adv;		/* advertised window */
+/* retransmit variables */
+	tcp_seq	snd_max;		/* highest sequence number sent;
+					 * used to recognize retransmits
+					 */
+/* congestion control (for slow start, source quench, retransmit after loss) */
+	uint32_t snd_cwnd;		/* congestion-controlled window */
+	uint32_t snd_ssthresh;		/* snd_cwnd size threshold for
+					 * for slow start exponential to
+					 * linear switch
+					 */
+/*
+ * transmit timing stuff.  See below for scale of srtt and rttvar.
+ * "Variance" is actually smoothed difference.
+ */
+	short	t_idle;			/* inactivity time */
+	short	t_rtt;			/* round trip time */
+	tcp_seq	t_rtseq;		/* sequence number being timed */
+	short	t_srtt;			/* smoothed round-trip time */
+	short	t_rttvar;		/* variance in round-trip time */
+	u_short	t_rttmin;		/* minimum rtt allowed */
+	uint32_t max_sndwnd;		/* largest window peer has offered */
+
+/* out-of-band data */
+	char	t_oobflags;		/* have some */
+	char	t_iobc;			/* input character */
+#define	TCPOOB_HAVEDATA	0x01
+#define	TCPOOB_HADDATA	0x02
+	short	t_softerror;		/* possible error not yet reported */
+
+/* RFC 1323 variables */
+	u_char	snd_scale;		/* window scaling for send window */
+	u_char	rcv_scale;		/* window scaling for recv window */
+	u_char	request_r_scale;	/* pending window scaling */
+	u_char	requested_s_scale;
+	uint32_t	ts_recent;		/* timestamp echo data */
+	uint32_t	ts_recent_age;		/* when last updated */
+	tcp_seq	last_ack_sent;
+
+};
+
+#define	sototcpcb(so)	((so)->so_tcpcb)
+
+/*
+ * The smoothed round-trip time and estimated variance
+ * are stored as fixed point numbers scaled by the values below.
+ * For convenience, these scales are also used in smoothing the average
+ * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
+ * With these scales, srtt has 3 bits to the right of the binary point,
+ * and thus an "ALPHA" of 0.875.  rttvar has 2 bits to the right of the
+ * binary point, and is smoothed with an ALPHA of 0.75.
+ */
+#define	TCP_RTT_SCALE		8	/* multiplier for srtt; 3 bits frac. */
+#define	TCP_RTT_SHIFT		3	/* shift for srtt; 3 bits frac. */
+#define	TCP_RTTVAR_SCALE	4	/* multiplier for rttvar; 2 bits */
+#define	TCP_RTTVAR_SHIFT	2	/* multiplier for rttvar; 2 bits */
+
+/*
+ * The initial retransmission should happen at rtt + 4 * rttvar.
+ * Because of the way we do the smoothing, srtt and rttvar
+ * will each average +1/2 tick of bias.  When we compute
+ * the retransmit timer, we want 1/2 tick of rounding and
+ * 1 extra tick because of +-1/2 tick uncertainty in the
+ * firing of the timer.  The bias will give us exactly the
+ * 1.5 tick we need.  But, because the bias is
+ * statistical, we have to test that we don't drop below
+ * the minimum feasible timer (which is 2 ticks).
+ * This macro assumes that the value of TCP_RTTVAR_SCALE
+ * is the same as the multiplier for rttvar.
+ */
+#define	TCP_REXMTVAL(tp) \
+	(((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
+
+#endif
diff --git a/qemu-0.15.x/slirp/tcpip.h b/qemu-0.15.x/slirp/tcpip.h
new file mode 100644
index 0000000..7974ce3
--- /dev/null
+++ b/qemu-0.15.x/slirp/tcpip.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)tcpip.h	8.1 (Berkeley) 6/10/93
+ * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
+ */
+
+#ifndef _TCPIP_H_
+#define _TCPIP_H_
+
+/*
+ * Tcp+ip header, after ip options removed.
+ */
+struct tcpiphdr {
+	struct 	ipovly ti_i;		/* overlaid ip structure */
+	struct	tcphdr ti_t;		/* tcp header */
+};
+#define	ti_mbuf		ti_i.ih_mbuf.mptr
+#define	ti_x1		ti_i.ih_x1
+#define	ti_pr		ti_i.ih_pr
+#define	ti_len		ti_i.ih_len
+#define	ti_src		ti_i.ih_src
+#define	ti_dst		ti_i.ih_dst
+#define	ti_sport	ti_t.th_sport
+#define	ti_dport	ti_t.th_dport
+#define	ti_seq		ti_t.th_seq
+#define	ti_ack		ti_t.th_ack
+#define	ti_x2		ti_t.th_x2
+#define	ti_off		ti_t.th_off
+#define	ti_flags	ti_t.th_flags
+#define	ti_win		ti_t.th_win
+#define	ti_sum		ti_t.th_sum
+#define	ti_urp		ti_t.th_urp
+
+#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink)))
+#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink)))
+#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
+#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
+#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
+#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
+#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
+
+/*
+ * Just a clean way to get to the first byte
+ * of the packet
+ */
+struct tcpiphdr_2 {
+	struct tcpiphdr dummy;
+	char first_char;
+};
+
+#endif
diff --git a/qemu-0.15.x/slirp/tftp.c b/qemu-0.15.x/slirp/tftp.c
new file mode 100644
index 0000000..8055ccc
--- /dev/null
+++ b/qemu-0.15.x/slirp/tftp.c
@@ -0,0 +1,422 @@
+/*
+ * tftp.c - a simple, read-only tftp server for qemu
+ *
+ * Copyright (c) 2004 Magnus Damm <damm at opensource.se>
+ *
+ * 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 <slirp.h>
+#include "qemu-common.h"
+
+static inline int tftp_session_in_use(struct tftp_session *spt)
+{
+    return (spt->slirp != NULL);
+}
+
+static inline void tftp_session_update(struct tftp_session *spt)
+{
+    spt->timestamp = curtime;
+}
+
+static void tftp_session_terminate(struct tftp_session *spt)
+{
+    qemu_free(spt->filename);
+    spt->slirp = NULL;
+}
+
+static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
+{
+  struct tftp_session *spt;
+  int k;
+
+  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
+    spt = &slirp->tftp_sessions[k];
+
+    if (!tftp_session_in_use(spt))
+        goto found;
+
+    /* sessions time out after 5 inactive seconds */
+    if ((int)(curtime - spt->timestamp) > 5000) {
+        qemu_free(spt->filename);
+        goto found;
+    }
+  }
+
+  return -1;
+
+ found:
+  memset(spt, 0, sizeof(*spt));
+  memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
+  spt->client_port = tp->udp.uh_sport;
+  spt->slirp = slirp;
+
+  tftp_session_update(spt);
+
+  return k;
+}
+
+static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
+{
+  struct tftp_session *spt;
+  int k;
+
+  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
+    spt = &slirp->tftp_sessions[k];
+
+    if (tftp_session_in_use(spt)) {
+      if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
+	if (spt->client_port == tp->udp.uh_sport) {
+	  return k;
+	}
+      }
+    }
+  }
+
+  return -1;
+}
+
+static int tftp_read_data(struct tftp_session *spt, uint16_t block_nr,
+                          uint8_t *buf, int len)
+{
+  int fd;
+  int bytes_read = 0;
+
+  fd = open(spt->filename, O_RDONLY | O_BINARY);
+
+  if (fd < 0) {
+    return -1;
+  }
+
+  if (len) {
+    lseek(fd, block_nr * 512, SEEK_SET);
+
+    bytes_read = read(fd, buf, len);
+  }
+
+  close(fd);
+
+  return bytes_read;
+}
+
+static int tftp_send_oack(struct tftp_session *spt,
+                          const char *key, uint32_t value,
+                          struct tftp_t *recv_tp)
+{
+    struct sockaddr_in saddr, daddr;
+    struct mbuf *m;
+    struct tftp_t *tp;
+    int n = 0;
+
+    m = m_get(spt->slirp);
+
+    if (!m)
+	return -1;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += IF_MAXLINKHDR;
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+
+    tp->tp_op = htons(TFTP_OACK);
+    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
+                  key) + 1;
+    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
+                  value) + 1;
+
+    saddr.sin_addr = recv_tp->ip.ip_dst;
+    saddr.sin_port = recv_tp->udp.uh_dport;
+
+    daddr.sin_addr = spt->client_ip;
+    daddr.sin_port = spt->client_port;
+
+    m->m_len = sizeof(struct tftp_t) - 514 + n -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+    return 0;
+}
+
+static void tftp_send_error(struct tftp_session *spt,
+                            uint16_t errorcode, const char *msg,
+                            struct tftp_t *recv_tp)
+{
+  struct sockaddr_in saddr, daddr;
+  struct mbuf *m;
+  struct tftp_t *tp;
+
+  m = m_get(spt->slirp);
+
+  if (!m) {
+    goto out;
+  }
+
+  memset(m->m_data, 0, m->m_size);
+
+  m->m_data += IF_MAXLINKHDR;
+  tp = (void *)m->m_data;
+  m->m_data += sizeof(struct udpiphdr);
+
+  tp->tp_op = htons(TFTP_ERROR);
+  tp->x.tp_error.tp_error_code = htons(errorcode);
+  pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
+
+  saddr.sin_addr = recv_tp->ip.ip_dst;
+  saddr.sin_port = recv_tp->udp.uh_dport;
+
+  daddr.sin_addr = spt->client_ip;
+  daddr.sin_port = spt->client_port;
+
+  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+
+  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+out:
+  tftp_session_terminate(spt);
+}
+
+static int tftp_send_data(struct tftp_session *spt,
+                          uint16_t block_nr,
+			  struct tftp_t *recv_tp)
+{
+  struct sockaddr_in saddr, daddr;
+  struct mbuf *m;
+  struct tftp_t *tp;
+  int nobytes;
+
+  if (block_nr < 1) {
+    return -1;
+  }
+
+  m = m_get(spt->slirp);
+
+  if (!m) {
+    return -1;
+  }
+
+  memset(m->m_data, 0, m->m_size);
+
+  m->m_data += IF_MAXLINKHDR;
+  tp = (void *)m->m_data;
+  m->m_data += sizeof(struct udpiphdr);
+
+  tp->tp_op = htons(TFTP_DATA);
+  tp->x.tp_data.tp_block_nr = htons(block_nr);
+
+  saddr.sin_addr = recv_tp->ip.ip_dst;
+  saddr.sin_port = recv_tp->udp.uh_dport;
+
+  daddr.sin_addr = spt->client_ip;
+  daddr.sin_port = spt->client_port;
+
+  nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
+
+  if (nobytes < 0) {
+    m_free(m);
+
+    /* send "file not found" error back */
+
+    tftp_send_error(spt, 1, "File not found", tp);
+
+    return -1;
+  }
+
+  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+
+  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+  if (nobytes == 512) {
+    tftp_session_update(spt);
+  }
+  else {
+    tftp_session_terminate(spt);
+  }
+
+  return 0;
+}
+
+static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
+{
+  struct tftp_session *spt;
+  int s, k;
+  size_t prefix_len;
+  char *req_fname;
+
+  /* check if a session already exists and if so terminate it */
+  s = tftp_session_find(slirp, tp);
+  if (s >= 0) {
+    tftp_session_terminate(&slirp->tftp_sessions[s]);
+  }
+
+  s = tftp_session_allocate(slirp, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  spt = &slirp->tftp_sessions[s];
+
+  /* unspecifed prefix means service disabled */
+  if (!slirp->tftp_prefix) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  /* skip header fields */
+  k = 0;
+  pktlen -= offsetof(struct tftp_t, x.tp_buf);
+
+  /* prepend tftp_prefix */
+  prefix_len = strlen(slirp->tftp_prefix);
+  spt->filename = qemu_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
+  memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
+  spt->filename[prefix_len] = '/';
+
+  /* get name */
+  req_fname = spt->filename + prefix_len + 1;
+
+  while (1) {
+    if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+    }
+    req_fname[k] = tp->x.tp_buf[k];
+    if (req_fname[k++] == '\0') {
+      break;
+    }
+  }
+
+  /* check mode */
+  if ((pktlen - k) < 6) {
+    tftp_send_error(spt, 2, "Access violation", tp);
+    return;
+  }
+
+  if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
+      tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
+      return;
+  }
+
+  k += 6; /* skipping octet */
+
+  /* do sanity checks on the filename */
+  if (!strncmp(req_fname, "../", 3) ||
+      req_fname[strlen(req_fname) - 1] == '/' ||
+      strstr(req_fname, "/../")) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  /* check if the file exists */
+  if (tftp_read_data(spt, 0, NULL, 0) < 0) {
+      tftp_send_error(spt, 1, "File not found", tp);
+      return;
+  }
+
+  if (tp->x.tp_buf[pktlen - 1] != 0) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  while (k < pktlen) {
+      const char *key, *value;
+
+      key = &tp->x.tp_buf[k];
+      k += strlen(key) + 1;
+
+      if (k >= pktlen) {
+	  tftp_send_error(spt, 2, "Access violation", tp);
+	  return;
+      }
+
+      value = &tp->x.tp_buf[k];
+      k += strlen(value) + 1;
+
+      if (strcasecmp(key, "tsize") == 0) {
+	  int tsize = atoi(value);
+	  struct stat stat_p;
+
+	  if (tsize == 0) {
+	      if (stat(spt->filename, &stat_p) == 0)
+		  tsize = stat_p.st_size;
+	      else {
+		  tftp_send_error(spt, 1, "File not found", tp);
+		  return;
+	      }
+	  }
+
+	  tftp_send_oack(spt, "tsize", tsize, tp);
+	  return;
+      }
+  }
+
+  tftp_send_data(spt, 1, tp);
+}
+
+static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
+{
+  int s;
+
+  s = tftp_session_find(slirp, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  if (tftp_send_data(&slirp->tftp_sessions[s],
+		     ntohs(tp->x.tp_data.tp_block_nr) + 1,
+		     tp) < 0) {
+    return;
+  }
+}
+
+static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
+{
+  int s;
+
+  s = tftp_session_find(slirp, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  tftp_session_terminate(&slirp->tftp_sessions[s]);
+}
+
+void tftp_input(struct mbuf *m)
+{
+  struct tftp_t *tp = (struct tftp_t *)m->m_data;
+
+  switch(ntohs(tp->tp_op)) {
+  case TFTP_RRQ:
+    tftp_handle_rrq(m->slirp, tp, m->m_len);
+    break;
+
+  case TFTP_ACK:
+    tftp_handle_ack(m->slirp, tp, m->m_len);
+    break;
+
+  case TFTP_ERROR:
+    tftp_handle_error(m->slirp, tp, m->m_len);
+    break;
+  }
+}
diff --git a/qemu-0.15.x/slirp/tftp.h b/qemu-0.15.x/slirp/tftp.h
new file mode 100644
index 0000000..72e5e91
--- /dev/null
+++ b/qemu-0.15.x/slirp/tftp.h
@@ -0,0 +1,43 @@
+/* tftp defines */
+
+#define TFTP_SESSIONS_MAX 3
+
+#define TFTP_SERVER	69
+
+#define TFTP_RRQ    1
+#define TFTP_WRQ    2
+#define TFTP_DATA   3
+#define TFTP_ACK    4
+#define TFTP_ERROR  5
+#define TFTP_OACK   6
+
+#define TFTP_FILENAME_MAX 512
+
+struct tftp_t {
+  struct ip ip;
+  struct udphdr udp;
+  uint16_t tp_op;
+  union {
+    struct {
+      uint16_t tp_block_nr;
+      uint8_t tp_buf[512];
+    } tp_data;
+    struct {
+      uint16_t tp_error_code;
+      uint8_t tp_msg[512];
+    } tp_error;
+    char tp_buf[512 + 2];
+  } x;
+};
+
+struct tftp_session {
+    Slirp *slirp;
+    char *filename;
+
+    struct in_addr client_ip;
+    uint16_t client_port;
+
+    int timestamp;
+};
+
+void tftp_input(struct mbuf *m);
diff --git a/qemu-0.15.x/slirp/udp.c b/qemu-0.15.x/slirp/udp.c
new file mode 100644
index 0000000..5b060f3
--- /dev/null
+++ b/qemu-0.15.x/slirp/udp.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *	@(#)udp_usrreq.c	8.4 (Berkeley) 1/21/94
+ * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include "ip_icmp.h"
+
+static uint8_t udp_tos(struct socket *so);
+
+void
+udp_init(Slirp *slirp)
+{
+    slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
+    slirp->udp_last_so = &slirp->udb;
+}
+/* m->m_data  points at ip packet header
+ * m->m_len   length ip packet
+ * ip->ip_len length data (IPDU)
+ */
+void
+udp_input(register struct mbuf *m, int iphlen)
+{
+	Slirp *slirp = m->slirp;
+	register struct ip *ip;
+	register struct udphdr *uh;
+	int len;
+	struct ip save_ip;
+	struct socket *so;
+
+	DEBUG_CALL("udp_input");
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("iphlen = %d", iphlen);
+
+	/*
+	 * Strip IP options, if any; should skip this,
+	 * make available to user, and use on returned packets,
+	 * but we don't yet have a way to check the checksum
+	 * with options still present.
+	 */
+	if(iphlen > sizeof(struct ip)) {
+		ip_stripoptions(m, (struct mbuf *)0);
+		iphlen = sizeof(struct ip);
+	}
+
+	/*
+	 * Get IP and UDP header together in first mbuf.
+	 */
+	ip = mtod(m, struct ip *);
+	uh = (struct udphdr *)((caddr_t)ip + iphlen);
+
+	/*
+	 * Make mbuf data length reflect UDP length.
+	 * If not enough data to reflect UDP length, drop.
+	 */
+	len = ntohs((uint16_t)uh->uh_ulen);
+
+	if (ip->ip_len != len) {
+		if (len > ip->ip_len) {
+			goto bad;
+		}
+		m_adj(m, len - ip->ip_len);
+		ip->ip_len = len;
+	}
+
+	/*
+	 * Save a copy of the IP header in case we want restore it
+	 * for sending an ICMP error message in response.
+	 */
+	save_ip = *ip;
+	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
+
+	/*
+	 * Checksum extended UDP header and data.
+	 */
+	if (uh->uh_sum) {
+      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
+	  ((struct ipovly *)ip)->ih_x1 = 0;
+	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
+	  if(cksum(m, len + sizeof(struct ip))) {
+	    goto bad;
+	  }
+	}
+
+        /*
+         *  handle DHCP/BOOTP
+         */
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
+            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+             ip->ip_dst.s_addr == 0xffffffff)) {
+                bootp_input(m);
+                goto bad;
+            }
+
+        /*
+         *  handle TFTP
+         */
+        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
+            tftp_input(m);
+            goto bad;
+        }
+
+        if (slirp->restricted) {
+            goto bad;
+        }
+
+	/*
+	 * Locate pcb for datagram.
+	 */
+	so = slirp->udp_last_so;
+	if (so->so_lport != uh->uh_sport ||
+	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
+		struct socket *tmp;
+
+		for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
+		     tmp = tmp->so_next) {
+			if (tmp->so_lport == uh->uh_sport &&
+			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
+				so = tmp;
+				break;
+			}
+		}
+		if (tmp == &slirp->udb) {
+		  so = NULL;
+		} else {
+		  slirp->udp_last_so = so;
+		}
+	}
+
+	if (so == NULL) {
+	  /*
+	   * If there's no socket for this packet,
+	   * create one
+	   */
+	  so = socreate(slirp);
+	  if (!so) {
+	      goto bad;
+	  }
+	  if(udp_attach(so) == -1) {
+	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
+			errno,strerror(errno)));
+	    sofree(so);
+	    goto bad;
+	  }
+
+	  /*
+	   * Setup fields
+	   */
+	  so->so_laddr = ip->ip_src;
+	  so->so_lport = uh->uh_sport;
+
+	  if ((so->so_iptos = udp_tos(so)) == 0)
+	    so->so_iptos = ip->ip_tos;
+
+	  /*
+	   * XXXXX Here, check if it's in udpexec_list,
+	   * and if it is, do the fork_exec() etc.
+	   */
+	}
+
+        so->so_faddr = ip->ip_dst; /* XXX */
+        so->so_fport = uh->uh_dport; /* XXX */
+
+	iphlen += sizeof(struct udphdr);
+	m->m_len -= iphlen;
+	m->m_data += iphlen;
+
+	/*
+	 * Now we sendto() the packet.
+	 */
+	if(sosendto(so,m) == -1) {
+	  m->m_len += iphlen;
+	  m->m_data -= iphlen;
+	  *ip=save_ip;
+	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
+	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	}
+
+	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+
+	/* restore the orig mbuf packet */
+	m->m_len += iphlen;
+	m->m_data -= iphlen;
+	*ip=save_ip;
+	so->so_m=m;         /* ICMP backup */
+
+	return;
+bad:
+	m_free(m);
+	return;
+}
+
+int udp_output2(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos)
+{
+	register struct udpiphdr *ui;
+	int error = 0;
+
+	DEBUG_CALL("udp_output");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
+	DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
+
+	/*
+	 * Adjust for header
+	 */
+	m->m_data -= sizeof(struct udpiphdr);
+	m->m_len += sizeof(struct udpiphdr);
+
+	/*
+	 * Fill in mbuf with extended UDP header
+	 * and addresses and length put into network format.
+	 */
+	ui = mtod(m, struct udpiphdr *);
+    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	ui->ui_x1 = 0;
+	ui->ui_pr = IPPROTO_UDP;
+	ui->ui_len = htons(m->m_len - sizeof(struct ip));
+	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
+        ui->ui_src = saddr->sin_addr;
+	ui->ui_dst = daddr->sin_addr;
+	ui->ui_sport = saddr->sin_port;
+	ui->ui_dport = daddr->sin_port;
+	ui->ui_ulen = ui->ui_len;
+
+	/*
+	 * Stuff checksum and output datagram.
+	 */
+	ui->ui_sum = 0;
+	if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
+		ui->ui_sum = 0xffff;
+	((struct ip *)ui)->ip_len = m->m_len;
+
+	((struct ip *)ui)->ip_ttl = IPDEFTTL;
+	((struct ip *)ui)->ip_tos = iptos;
+
+	error = ip_output(so, m);
+
+	return (error);
+}
+
+int udp_output(struct socket *so, struct mbuf *m,
+               struct sockaddr_in *addr)
+
+{
+    Slirp *slirp = so->slirp;
+    struct sockaddr_in saddr, daddr;
+
+    saddr = *addr;
+    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+        slirp->vnetwork_addr.s_addr) {
+        uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
+
+        if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
+            saddr.sin_addr = slirp->vhost_addr;
+        } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
+                   so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+            saddr.sin_addr = so->so_faddr;
+        }
+    }
+    daddr.sin_addr = so->so_laddr;
+    daddr.sin_port = so->so_lport;
+
+    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
+}
+
+int
+udp_attach(struct socket *so)
+{
+  if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
+    so->so_expire = curtime + SO_EXPIRE;
+    insque(so, &so->slirp->udb);
+  }
+  return(so->s);
+}
+
+void
+udp_detach(struct socket *so)
+{
+	closesocket(so->s);
+	sofree(so);
+}
+
+static const struct tos_t udptos[] = {
+	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
+	{0, 0, 0, 0}
+};
+
+static uint8_t
+udp_tos(struct socket *so)
+{
+	int i = 0;
+
+	while(udptos[i].tos) {
+		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
+		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
+		    	so->so_emu = udptos[i].emu;
+			return udptos[i].tos;
+		}
+		i++;
+	}
+
+	return 0;
+}
+
+struct socket *
+udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
+           u_int lport, int flags)
+{
+	struct sockaddr_in addr;
+	struct socket *so;
+	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
+
+	so = socreate(slirp);
+	if (!so) {
+	    return NULL;
+	}
+	so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
+	so->so_expire = curtime + SO_EXPIRE;
+	insque(so, &slirp->udb);
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = haddr;
+	addr.sin_port = hport;
+
+	if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
+		udp_detach(so);
+		return NULL;
+	}
+	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+
+	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
+	so->so_fport = addr.sin_port;
+	if (addr.sin_addr.s_addr == 0 ||
+	    addr.sin_addr.s_addr == loopback_addr.s_addr) {
+	   so->so_faddr = slirp->vhost_addr;
+	} else {
+	   so->so_faddr = addr.sin_addr;
+	}
+	so->so_lport = lport;
+	so->so_laddr.s_addr = laddr;
+	if (flags != SS_FACCEPTONCE)
+	   so->so_expire = 0;
+
+	so->so_state &= SS_PERSISTENT_MASK;
+	so->so_state |= SS_ISFCONNECTED | flags;
+
+	return so;
+}
diff --git a/qemu-0.15.x/slirp/udp.h b/qemu-0.15.x/slirp/udp.h
new file mode 100644
index 0000000..9b5c3cf
--- /dev/null
+++ b/qemu-0.15.x/slirp/udp.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *	@(#)udp.h	8.1 (Berkeley) 6/10/93
+ * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
+ */
+
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#define UDP_TTL 0x60
+#define UDP_UDPDATALEN 16192
+
+/*
+ * Udp protocol header.
+ * Per RFC 768, September, 1981.
+ */
+struct udphdr {
+    uint16_t uh_sport;          /* source port */
+    uint16_t uh_dport;          /* destination port */
+    int16_t  uh_ulen;           /* udp length */
+    uint16_t uh_sum;            /* udp checksum */
+};
+
+/*
+ * UDP kernel structures and variables.
+ */
+struct udpiphdr {
+	        struct  ipovly ui_i;            /* overlaid ip structure */
+	        struct  udphdr ui_u;            /* udp header */
+};
+#define ui_mbuf         ui_i.ih_mbuf.mptr
+#define ui_x1           ui_i.ih_x1
+#define ui_pr           ui_i.ih_pr
+#define ui_len          ui_i.ih_len
+#define ui_src          ui_i.ih_src
+#define ui_dst          ui_i.ih_dst
+#define ui_sport        ui_u.uh_sport
+#define ui_dport        ui_u.uh_dport
+#define ui_ulen         ui_u.uh_ulen
+#define ui_sum          ui_u.uh_sum
+
+/*
+ * Names for UDP sysctl objects
+ */
+#define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
+#define UDPCTL_MAXID            2
+
+struct mbuf;
+
+void udp_init(Slirp *);
+void udp_input(register struct mbuf *, int);
+int udp_output(struct socket *, struct mbuf *, struct sockaddr_in *);
+int udp_attach(struct socket *);
+void udp_detach(struct socket *);
+struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
+                           int);
+int udp_output2(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos);
+#endif
diff --git a/qemu-0.15.x/softmmu-semi.h b/qemu-0.15.x/softmmu-semi.h
new file mode 100644
index 0000000..86a9f8a
--- /dev/null
+++ b/qemu-0.15.x/softmmu-semi.h
@@ -0,0 +1,70 @@
+/*
+ * Helper routines to provide target memory access for semihosting
+ * syscalls in system emulation mode.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+static inline uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
+{
+    uint32_t val;
+
+    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
+    return tswap32(val);
+}
+static inline uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
+{
+    uint8_t val;
+
+    cpu_memory_rw_debug(env, addr, &val, 1, 0);
+    return val;
+}
+
+#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; })
+#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
+#define get_user_ual(arg, p) get_user_u32(arg, p)
+
+static inline void softmmu_tput32(CPUState *env, uint32_t addr, uint32_t val)
+{
+    val = tswap32(val);
+    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 1);
+}
+#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
+#define put_user_ual(arg, p) put_user_u32(arg, p)
+
+static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
+                               int copy)
+{
+    uint8_t *p;
+    /* TODO: Make this something that isn't fixed size.  */
+    p = malloc(len);
+    if (copy)
+        cpu_memory_rw_debug(env, addr, p, len, 0);
+    return p;
+}
+#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
+static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
+{
+    char *p;
+    char *s;
+    uint8_t c;
+    /* TODO: Make this something that isn't fixed size.  */
+    s = p = malloc(1024);
+    do {
+        cpu_memory_rw_debug(env, addr, &c, 1, 0);
+        addr++;
+        *(p++) = c;
+    } while (c);
+    return s;
+}
+#define lock_user_string(p) softmmu_lock_user_string(env, p)
+static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
+                                target_ulong len)
+{
+    if (len)
+        cpu_memory_rw_debug(env, addr, p, len, 1);
+    free(p);
+}
+#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
diff --git a/qemu-0.15.x/softmmu_defs.h b/qemu-0.15.x/softmmu_defs.h
new file mode 100644
index 0000000..e38bb75
--- /dev/null
+++ b/qemu-0.15.x/softmmu_defs.h
@@ -0,0 +1,22 @@
+#ifndef SOFTMMU_DEFS_H
+#define SOFTMMU_DEFS_H
+
+uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx);
+void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx);
+uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx);
+void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx);
+uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx);
+void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx);
+uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx);
+void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx);
+
+uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx);
+void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx);
+uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx);
+void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx);
+uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx);
+void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx);
+uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx);
+void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx);
+
+#endif
diff --git a/qemu-0.15.x/softmmu_exec.h b/qemu-0.15.x/softmmu_exec.h
new file mode 100644
index 0000000..28d1d53
--- /dev/null
+++ b/qemu-0.15.x/softmmu_exec.h
@@ -0,0 +1,153 @@
+/* Common softmmu definitions and inline routines.  */
+
+/* XXX: find something cleaner.
+ * Furthermore, this is false for 64 bits targets
+ */
+#define ldul_user       ldl_user
+#define ldul_kernel     ldl_kernel
+#define ldul_hypv       ldl_hypv
+#define ldul_executive  ldl_executive
+#define ldul_supervisor ldl_supervisor
+
+#include "softmmu_defs.h"
+
+#define ACCESS_TYPE 0
+#define MEMSUFFIX MMU_MODE0_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ACCESS_TYPE 1
+#define MEMSUFFIX MMU_MODE1_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#if (NB_MMU_MODES >= 3)
+
+#define ACCESS_TYPE 2
+#define MEMSUFFIX MMU_MODE2_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 3) */
+
+#if (NB_MMU_MODES >= 4)
+
+#define ACCESS_TYPE 3
+#define MEMSUFFIX MMU_MODE3_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 4) */
+
+#if (NB_MMU_MODES >= 5)
+
+#define ACCESS_TYPE 4
+#define MEMSUFFIX MMU_MODE4_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 5) */
+
+#if (NB_MMU_MODES >= 6)
+
+#define ACCESS_TYPE 5
+#define MEMSUFFIX MMU_MODE5_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 6) */
+
+#if (NB_MMU_MODES > 6)
+#error "NB_MMU_MODES > 6 is not supported for now"
+#endif /* (NB_MMU_MODES > 6) */
+
+/* these access are slower, they must be as rare as possible */
+#define ACCESS_TYPE (NB_MMU_MODES)
+#define MEMSUFFIX _data
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ldub(p) ldub_data(p)
+#define ldsb(p) ldsb_data(p)
+#define lduw(p) lduw_data(p)
+#define ldsw(p) ldsw_data(p)
+#define ldl(p) ldl_data(p)
+#define ldq(p) ldq_data(p)
+
+#define stb(p, v) stb_data(p, v)
+#define stw(p, v) stw_data(p, v)
+#define stl(p, v) stl_data(p, v)
+#define stq(p, v) stq_data(p, v)
diff --git a/qemu-0.15.x/softmmu_header.h b/qemu-0.15.x/softmmu_header.h
new file mode 100644
index 0000000..2f95c33
--- /dev/null
+++ b/qemu-0.15.x/softmmu_header.h
@@ -0,0 +1,198 @@
+/*
+ *  Software MMU support
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if DATA_SIZE == 8
+#define SUFFIX q
+#define USUFFIX q
+#define DATA_TYPE uint64_t
+#elif DATA_SIZE == 4
+#define SUFFIX l
+#define USUFFIX l
+#define DATA_TYPE uint32_t
+#elif DATA_SIZE == 2
+#define SUFFIX w
+#define USUFFIX uw
+#define DATA_TYPE uint16_t
+#define DATA_STYPE int16_t
+#elif DATA_SIZE == 1
+#define SUFFIX b
+#define USUFFIX ub
+#define DATA_TYPE uint8_t
+#define DATA_STYPE int8_t
+#else
+#error unsupported data size
+#endif
+
+#if ACCESS_TYPE < (NB_MMU_MODES)
+
+#define CPU_MMU_INDEX ACCESS_TYPE
+#define MMUSUFFIX _mmu
+
+#elif ACCESS_TYPE == (NB_MMU_MODES)
+
+#define CPU_MMU_INDEX (cpu_mmu_index(env))
+#define MMUSUFFIX _mmu
+
+#elif ACCESS_TYPE == (NB_MMU_MODES + 1)
+
+#define CPU_MMU_INDEX (cpu_mmu_index(env))
+#define MMUSUFFIX _cmmu
+
+#else
+#error invalid ACCESS_TYPE
+#endif
+
+#if DATA_SIZE == 8
+#define RES_TYPE uint64_t
+#else
+#define RES_TYPE uint32_t
+#endif
+
+#if ACCESS_TYPE == (NB_MMU_MODES + 1)
+#define ADDR_READ addr_code
+#else
+#define ADDR_READ addr_read
+#endif
+
+/* generic load/store macros */
+
+static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
+{
+    int page_index;
+    RES_TYPE res;
+    target_ulong addr;
+    unsigned long physaddr;
+    int mmu_idx;
+
+    addr = ptr;
+    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    mmu_idx = CPU_MMU_INDEX;
+    if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
+                 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
+        res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
+    } else {
+        physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+        res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
+    }
+    return res;
+}
+
+#if DATA_SIZE <= 2
+static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
+{
+    int res, page_index;
+    target_ulong addr;
+    unsigned long physaddr;
+    int mmu_idx;
+
+    addr = ptr;
+    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    mmu_idx = CPU_MMU_INDEX;
+    if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
+                 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
+        res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
+    } else {
+        physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+        res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
+    }
+    return res;
+}
+#endif
+
+#if ACCESS_TYPE != (NB_MMU_MODES + 1)
+
+/* generic store macro */
+
+static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
+{
+    int page_index;
+    target_ulong addr;
+    unsigned long physaddr;
+    int mmu_idx;
+
+    addr = ptr;
+    page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    mmu_idx = CPU_MMU_INDEX;
+    if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write !=
+                 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
+        glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx);
+    } else {
+        physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+        glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
+    }
+}
+
+#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */
+
+#if ACCESS_TYPE != (NB_MMU_MODES + 1)
+
+#if DATA_SIZE == 8
+static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr)
+{
+    union {
+        float64 d;
+        uint64_t i;
+    } u;
+    u.i = glue(ldq, MEMSUFFIX)(ptr);
+    return u.d;
+}
+
+static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v)
+{
+    union {
+        float64 d;
+        uint64_t i;
+    } u;
+    u.d = v;
+    glue(stq, MEMSUFFIX)(ptr, u.i);
+}
+#endif /* DATA_SIZE == 8 */
+
+#if DATA_SIZE == 4
+static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = glue(ldl, MEMSUFFIX)(ptr);
+    return u.f;
+}
+
+static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = v;
+    glue(stl, MEMSUFFIX)(ptr, u.i);
+}
+#endif /* DATA_SIZE == 4 */
+
+#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */
+
+#undef RES_TYPE
+#undef DATA_TYPE
+#undef DATA_STYPE
+#undef SUFFIX
+#undef USUFFIX
+#undef DATA_SIZE
+#undef CPU_MMU_INDEX
+#undef MMUSUFFIX
+#undef ADDR_READ
diff --git a/qemu-0.15.x/softmmu_template.h b/qemu-0.15.x/softmmu_template.h
new file mode 100644
index 0000000..c2df9ec
--- /dev/null
+++ b/qemu-0.15.x/softmmu_template.h
@@ -0,0 +1,332 @@
+/*
+ *  Software MMU support
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu-timer.h"
+
+#define DATA_SIZE (1 << SHIFT)
+
+#if DATA_SIZE == 8
+#define SUFFIX q
+#define USUFFIX q
+#define DATA_TYPE uint64_t
+#elif DATA_SIZE == 4
+#define SUFFIX l
+#define USUFFIX l
+#define DATA_TYPE uint32_t
+#elif DATA_SIZE == 2
+#define SUFFIX w
+#define USUFFIX uw
+#define DATA_TYPE uint16_t
+#elif DATA_SIZE == 1
+#define SUFFIX b
+#define USUFFIX ub
+#define DATA_TYPE uint8_t
+#else
+#error unsupported data size
+#endif
+
+#ifdef SOFTMMU_CODE_ACCESS
+#define READ_ACCESS_TYPE 2
+#define ADDR_READ addr_code
+#else
+#define READ_ACCESS_TYPE 0
+#define ADDR_READ addr_read
+#endif
+
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                        int mmu_idx,
+                                                        void *retaddr);
+static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
+                                              target_ulong addr,
+                                              void *retaddr)
+{
+    DATA_TYPE res;
+    int index;
+    index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+    physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+    env->mem_io_pc = (unsigned long)retaddr;
+    if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
+            && !can_do_io(env)) {
+        cpu_io_recompile(env, retaddr);
+    }
+
+    env->mem_io_vaddr = addr;
+#if SHIFT <= 2
+    res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
+#else
+#ifdef TARGET_WORDS_BIGENDIAN
+    res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
+    res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
+#else
+    res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
+    res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
+#endif
+#endif /* SHIFT > 2 */
+    return res;
+}
+
+/* handle all cases except unaligned access which span two pages */
+DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                      int mmu_idx)
+{
+    DATA_TYPE res;
+    int index;
+    target_ulong tlb_addr;
+    target_phys_addr_t ioaddr;
+    unsigned long addend;
+    void *retaddr;
+
+    /* test if there is match for unaligned or IO access */
+    /* XXX: could done more in memory macro in a non portable way */
+    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
+    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        if (tlb_addr & ~TARGET_PAGE_MASK) {
+            /* IO access */
+            if ((addr & (DATA_SIZE - 1)) != 0)
+                goto do_unaligned_access;
+            retaddr = GETPC();
+            ioaddr = env->iotlb[mmu_idx][index];
+            res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+            /* slow unaligned access (it spans two pages or IO) */
+        do_unaligned_access:
+            retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+#endif
+            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
+                                                         mmu_idx, retaddr);
+        } else {
+            /* unaligned/aligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = GETPC();
+                do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+            }
+#endif
+            addend = env->tlb_table[mmu_idx][index].addend;
+            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+        }
+    } else {
+        /* the page is not in the TLB : fill it */
+        retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+#endif
+        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        goto redo;
+    }
+    return res;
+}
+
+/* handle all unaligned cases */
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                        int mmu_idx,
+                                                        void *retaddr)
+{
+    DATA_TYPE res, res1, res2;
+    int index, shift;
+    target_phys_addr_t ioaddr;
+    unsigned long addend;
+    target_ulong tlb_addr, addr1, addr2;
+
+    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
+    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        if (tlb_addr & ~TARGET_PAGE_MASK) {
+            /* IO access */
+            if ((addr & (DATA_SIZE - 1)) != 0)
+                goto do_unaligned_access;
+            ioaddr = env->iotlb[mmu_idx][index];
+            res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        do_unaligned_access:
+            /* slow unaligned access (it spans two pages) */
+            addr1 = addr & ~(DATA_SIZE - 1);
+            addr2 = addr1 + DATA_SIZE;
+            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
+                                                          mmu_idx, retaddr);
+            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
+                                                          mmu_idx, retaddr);
+            shift = (addr & (DATA_SIZE - 1)) * 8;
+#ifdef TARGET_WORDS_BIGENDIAN
+            res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
+#else
+            res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
+#endif
+            res = (DATA_TYPE)res;
+        } else {
+            /* unaligned/aligned access in the same page */
+            addend = env->tlb_table[mmu_idx][index].addend;
+            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+        }
+    } else {
+        /* the page is not in the TLB : fill it */
+        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        goto redo;
+    }
+    return res;
+}
+
+#ifndef SOFTMMU_CODE_ACCESS
+
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                   DATA_TYPE val,
+                                                   int mmu_idx,
+                                                   void *retaddr);
+
+static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
+                                          DATA_TYPE val,
+                                          target_ulong addr,
+                                          void *retaddr)
+{
+    int index;
+    index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+    physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+    if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
+            && !can_do_io(env)) {
+        cpu_io_recompile(env, retaddr);
+    }
+
+    env->mem_io_vaddr = addr;
+    env->mem_io_pc = (unsigned long)retaddr;
+#if SHIFT <= 2
+    io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
+#else
+#ifdef TARGET_WORDS_BIGENDIAN
+    io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
+    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
+#else
+    io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
+    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
+#endif
+#endif /* SHIFT > 2 */
+}
+
+void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                 DATA_TYPE val,
+                                                 int mmu_idx)
+{
+    target_phys_addr_t ioaddr;
+    unsigned long addend;
+    target_ulong tlb_addr;
+    void *retaddr;
+    int index;
+
+    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        if (tlb_addr & ~TARGET_PAGE_MASK) {
+            /* IO access */
+            if ((addr & (DATA_SIZE - 1)) != 0)
+                goto do_unaligned_access;
+            retaddr = GETPC();
+            ioaddr = env->iotlb[mmu_idx][index];
+            glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        do_unaligned_access:
+            retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+#endif
+            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
+                                                   mmu_idx, retaddr);
+        } else {
+            /* aligned/unaligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = GETPC();
+                do_unaligned_access(addr, 1, mmu_idx, retaddr);
+            }
+#endif
+            addend = env->tlb_table[mmu_idx][index].addend;
+            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+        }
+    } else {
+        /* the page is not in the TLB : fill it */
+        retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+#endif
+        tlb_fill(addr, 1, mmu_idx, retaddr);
+        goto redo;
+    }
+}
+
+/* handles all unaligned cases */
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                   DATA_TYPE val,
+                                                   int mmu_idx,
+                                                   void *retaddr)
+{
+    target_phys_addr_t ioaddr;
+    unsigned long addend;
+    target_ulong tlb_addr;
+    int index, i;
+
+    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        if (tlb_addr & ~TARGET_PAGE_MASK) {
+            /* IO access */
+            if ((addr & (DATA_SIZE - 1)) != 0)
+                goto do_unaligned_access;
+            ioaddr = env->iotlb[mmu_idx][index];
+            glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        do_unaligned_access:
+            /* XXX: not efficient, but simple */
+            /* Note: relies on the fact that tlb_fill() does not remove the
+             * previous page from the TLB cache.  */
+            for(i = DATA_SIZE - 1; i >= 0; i--) {
+#ifdef TARGET_WORDS_BIGENDIAN
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
+                                          mmu_idx, retaddr);
+#else
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
+                                          mmu_idx, retaddr);
+#endif
+            }
+        } else {
+            /* aligned/unaligned access in the same page */
+            addend = env->tlb_table[mmu_idx][index].addend;
+            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+        }
+    } else {
+        /* the page is not in the TLB : fill it */
+        tlb_fill(addr, 1, mmu_idx, retaddr);
+        goto redo;
+    }
+}
+
+#endif /* !defined(SOFTMMU_CODE_ACCESS) */
+
+#undef READ_ACCESS_TYPE
+#undef SHIFT
+#undef DATA_TYPE
+#undef SUFFIX
+#undef USUFFIX
+#undef DATA_SIZE
+#undef ADDR_READ
diff --git a/qemu-0.15.x/sparc-dis.c b/qemu-0.15.x/sparc-dis.c
new file mode 100644
index 0000000..cdd337a
--- /dev/null
+++ b/qemu-0.15.x/sparc-dis.c
@@ -0,0 +1,3275 @@
+/*
+ * These files from binutils are concatenated:
+ * include/opcode/sparc.h, opcodes/sparc-opc.c, opcodes/sparc-dis.c
+ */
+
+/* include/opcode/sparc.h */
+
+/* Definitions for opcode table for the sparc.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000, 2002,
+   2003, 2005 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and
+   the GNU Binutils.
+
+   GAS/GDB is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GAS/GDB is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS or GDB; see the file COPYING. If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include "dis-asm.h"
+
+/* The SPARC opcode table (and other related data) is defined in
+   the opcodes library in sparc-opc.c.  If you change anything here, make
+   sure you fix up that file, and vice versa.  */
+
+ /* FIXME-someday: perhaps the ,a's and such should be embedded in the
+    instruction's name rather than the args.  This would make gas faster, pinsn
+    slower, but would mess up some macros a bit.  xoxorich. */
+
+/* List of instruction sets variations.
+   These values are such that each element is either a superset of a
+   preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P
+   returns non-zero.
+   The values are indices into `sparc_opcode_archs' defined in sparc-opc.c.
+   Don't change this without updating sparc-opc.c.  */
+
+enum sparc_opcode_arch_val
+{
+  SPARC_OPCODE_ARCH_V6 = 0,
+  SPARC_OPCODE_ARCH_V7,
+  SPARC_OPCODE_ARCH_V8,
+  SPARC_OPCODE_ARCH_SPARCLET,
+  SPARC_OPCODE_ARCH_SPARCLITE,
+  /* V9 variants must appear last.  */
+  SPARC_OPCODE_ARCH_V9,
+  SPARC_OPCODE_ARCH_V9A, /* V9 with ultrasparc additions.  */
+  SPARC_OPCODE_ARCH_V9B, /* V9 with ultrasparc and cheetah additions.  */
+  SPARC_OPCODE_ARCH_BAD  /* Error return from sparc_opcode_lookup_arch.  */
+};
+
+/* The highest architecture in the table.  */
+#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1)
+
+/* Given an enum sparc_opcode_arch_val, return the bitmask to use in
+   insn encoding/decoding.  */
+#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch))
+
+/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9.  */
+#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9)
+
+/* Table of cpu variants.  */
+
+typedef struct sparc_opcode_arch
+{
+  const char *name;
+  /* Mask of sparc_opcode_arch_val's supported.
+     EG: For v7 this would be
+     (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)).
+     These are short's because sparc_opcode.architecture is.  */
+  short supported;
+} sparc_opcode_arch;
+
+static const struct sparc_opcode_arch sparc_opcode_archs[];
+
+/* Return the bitmask of supported architectures for ARCH.  */
+#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported)
+
+/* Non-zero if ARCH1 conflicts with ARCH2.
+   IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa.  */
+#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \
+ (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
+   != SPARC_OPCODE_SUPPORTED (ARCH1)) \
+  && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
+     != SPARC_OPCODE_SUPPORTED (ARCH2)))
+
+/* Structure of an opcode table entry.  */
+
+typedef struct sparc_opcode
+{
+  const char *name;
+  unsigned long match;  /* Bits that must be set.  */
+  unsigned long lose;   /* Bits that must not be set.  */
+  const char *args;
+  /* This was called "delayed" in versions before the flags.  */
+  char flags;
+  short architecture;   /* Bitmask of sparc_opcode_arch_val's.  */
+} sparc_opcode;
+
+#define F_DELAYED       1       /* Delayed branch.  */
+#define F_ALIAS         2       /* Alias for a "real" instruction.  */
+#define F_UNBR          4       /* Unconditional branch.  */
+#define F_CONDBR        8       /* Conditional branch.  */
+#define F_JSR           16      /* Subroutine call.  */
+#define F_FLOAT         32      /* Floating point instruction (not a branch).  */
+#define F_FBR           64      /* Floating point branch.  */
+/* FIXME: Add F_ANACHRONISTIC flag for v9.  */
+
+/* All sparc opcodes are 32 bits, except for the `set' instruction (really a
+   macro), which is 64 bits. It is handled as a special case.
+
+   The match component is a mask saying which bits must match a particular
+   opcode in order for an instruction to be an instance of that opcode.
+
+   The args component is a string containing one character for each operand of the
+   instruction.
+
+   Kinds of operands:
+        #       Number used by optimizer.       It is ignored.
+        1       rs1 register.
+        2       rs2 register.
+        d       rd register.
+        e       frs1 floating point register.
+        v       frs1 floating point register (double/even).
+        V       frs1 floating point register (quad/multiple of 4).
+        f       frs2 floating point register.
+        B       frs2 floating point register (double/even).
+        R       frs2 floating point register (quad/multiple of 4).
+        g       frsd floating point register.
+        H       frsd floating point register (double/even).
+        J       frsd floating point register (quad/multiple of 4).
+        b       crs1 coprocessor register
+        c       crs2 coprocessor register
+        D       crsd coprocessor register
+        m       alternate space register (asr) in rd
+        M       alternate space register (asr) in rs1
+        h       22 high bits.
+        X       5 bit unsigned immediate
+        Y       6 bit unsigned immediate
+        3       SIAM mode (3 bits). (v9b)
+        K       MEMBAR mask (7 bits). (v9)
+        j       10 bit Immediate. (v9)
+        I       11 bit Immediate. (v9)
+        i       13 bit Immediate.
+        n       22 bit immediate.
+        k       2+14 bit PC relative immediate. (v9)
+        G       19 bit PC relative immediate. (v9)
+        l       22 bit PC relative immediate.
+        L       30 bit PC relative immediate.
+        a       Annul.  The annul bit is set.
+        A       Alternate address space. Stored as 8 bits.
+        C       Coprocessor state register.
+        F       floating point state register.
+        p       Processor state register.
+        N       Branch predict clear ",pn" (v9)
+        T       Branch predict set ",pt" (v9)
+        z       %icc. (v9)
+        Z       %xcc. (v9)
+        q       Floating point queue.
+        r       Single register that is both rs1 and rd.
+        O       Single register that is both rs2 and rd.
+        Q       Coprocessor queue.
+        S       Special case.
+        t       Trap base register.
+        w       Window invalid mask register.
+        y       Y register.
+        u       sparclet coprocessor registers in rd position
+        U       sparclet coprocessor registers in rs1 position
+        E       %ccr. (v9)
+        s       %fprs. (v9)
+        P       %pc.  (v9)
+        W       %tick.  (v9)
+        o       %asi. (v9)
+        6       %fcc0. (v9)
+        7       %fcc1. (v9)
+        8       %fcc2. (v9)
+        9       %fcc3. (v9)
+        !       Privileged Register in rd (v9)
+        ?       Privileged Register in rs1 (v9)
+        *       Prefetch function constant. (v9)
+        x       OPF field (v9 impdep).
+        0       32/64 bit immediate for set or setx (v9) insns
+        _       Ancillary state register in rd (v9a)
+        /       Ancillary state register in rs1 (v9a)
+
+  The following chars are unused: (note: ,[] are used as punctuation)
+  [45].  */
+
+#define OP2(x)          (((x) & 0x7) << 22)  /* Op2 field of format2 insns.  */
+#define OP3(x)          (((x) & 0x3f) << 19) /* Op3 field of format3 insns.  */
+#define OP(x)           ((unsigned) ((x) & 0x3) << 30) /* Op field of all insns.  */
+#define OPF(x)          (((x) & 0x1ff) << 5) /* Opf field of float insns.  */
+#define OPF_LOW5(x)     OPF ((x) & 0x1f)     /* V9.  */
+#define F3F(x, y, z)    (OP (x) | OP3 (y) | OPF (z)) /* Format3 float insns.  */
+#define F3I(x)          (((x) & 0x1) << 13)  /* Immediate field of format 3 insns.  */
+#define F2(x, y)        (OP (x) | OP2(y))    /* Format 2 insns.  */
+#define F3(x, y, z)     (OP (x) | OP3(y) | F3I(z)) /* Format3 insns.  */
+#define F1(x)           (OP (x))
+#define DISP30(x)       ((x) & 0x3fffffff)
+#define ASI(x)          (((x) & 0xff) << 5)  /* Asi field of format3 insns.  */
+#define RS2(x)          ((x) & 0x1f)         /* Rs2 field.  */
+#define SIMM13(x)       ((x) & 0x1fff)       /* Simm13 field.  */
+#define RD(x)           (((x) & 0x1f) << 25) /* Destination register field.  */
+#define RS1(x)          (((x) & 0x1f) << 14) /* Rs1 field.  */
+#define ASI_RS2(x)      (SIMM13 (x))
+#define MEMBAR(x)       ((x) & 0x7f)
+#define SLCPOP(x)       (((x) & 0x7f) << 6)  /* Sparclet cpop.  */
+
+#define ANNUL   (1 << 29)
+#define BPRED   (1 << 19)       /* V9.  */
+#define IMMED   F3I (1)
+#define RD_G0   RD (~0)
+#define RS1_G0  RS1 (~0)
+#define RS2_G0  RS2 (~0)
+
+static const struct sparc_opcode sparc_opcodes[];
+
+static const char *sparc_decode_asi_v8 (int);
+static const char *sparc_decode_asi_v9 (int);
+static const char *sparc_decode_membar (int);
+static const char *sparc_decode_prefetch (int);
+static const char *sparc_decode_sparclet_cpreg (int);
+
+/* Local Variables:
+   fill-column: 131
+   comment-column: 0
+   End: */
+
+/* opcodes/sparc-opc.c */
+
+/* Table of opcodes for the sparc.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2002, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This file is part of the BFD library.
+
+   BFD is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   BFD is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this software; see the file COPYING.  If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+/* FIXME-someday: perhaps the ,a's and such should be embedded in the
+   instruction's name rather than the args.  This would make gas faster, pinsn
+   slower, but would mess up some macros a bit.  xoxorich. */
+
+/* Some defines to make life easy.  */
+#define MASK_V6         SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6)
+#define MASK_V7         SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7)
+#define MASK_V8         SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)
+#define MASK_SPARCLET   SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET)
+#define MASK_SPARCLITE  SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
+#define MASK_V9         SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9)
+#define MASK_V9A        SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A)
+#define MASK_V9B        SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B)
+
+/* Bit masks of architectures supporting the insn.  */
+
+#define v6              (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \
+                         | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
+/* v6 insns not supported on the sparclet.  */
+#define v6notlet        (MASK_V6 | MASK_V7 | MASK_V8 \
+                         | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
+#define v7              (MASK_V7 | MASK_V8 | MASK_SPARCLET \
+                         | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
+/* Although not all insns are implemented in hardware, sparclite is defined
+   to be a superset of v8.  Unimplemented insns trap and are then theoretically
+   implemented in software.
+   It's not clear that the same is true for sparclet, although the docs
+   suggest it is.  Rather than complicating things, the sparclet assembler
+   recognizes all v8 insns.  */
+#define v8              (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \
+                         | MASK_V9 | MASK_V9A | MASK_V9B)
+#define sparclet        (MASK_SPARCLET)
+#define sparclite       (MASK_SPARCLITE)
+#define v9              (MASK_V9 | MASK_V9A | MASK_V9B)
+#define v9a             (MASK_V9A | MASK_V9B)
+#define v9b             (MASK_V9B)
+/* v6 insns not supported by v9.  */
+#define v6notv9         (MASK_V6 | MASK_V7 | MASK_V8 \
+                         | MASK_SPARCLET | MASK_SPARCLITE)
+/* v9a instructions which would appear to be aliases to v9's impdep's
+   otherwise.  */
+#define v9notv9a        (MASK_V9)
+
+/* Table of opcode architectures.
+   The order is defined in opcode/sparc.h.  */
+
+static const struct sparc_opcode_arch sparc_opcode_archs[] =
+{
+  { "v6", MASK_V6 },
+  { "v7", MASK_V6 | MASK_V7 },
+  { "v8", MASK_V6 | MASK_V7 | MASK_V8 },
+  { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET },
+  { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE },
+  /* ??? Don't some v8 privileged insns conflict with v9?  */
+  { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 },
+  /* v9 with ultrasparc additions */
+  { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A },
+  /* v9 with cheetah additions */
+  { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B },
+  { NULL, 0 }
+};
+
+/* Branch condition field.  */
+#define COND(x)         (((x) & 0xf) << 25)
+
+/* v9: Move (MOVcc and FMOVcc) condition field.  */
+#define MCOND(x,i_or_f) ((((i_or_f) & 1) << 18) | (((x) >> 11) & (0xf << 14))) /* v9 */
+
+/* v9: Move register (MOVRcc and FMOVRcc) condition field.  */
+#define RCOND(x)        (((x) & 0x7) << 10)     /* v9 */
+
+#define CONDA   (COND (0x8))
+#define CONDCC  (COND (0xd))
+#define CONDCS  (COND (0x5))
+#define CONDE   (COND (0x1))
+#define CONDG   (COND (0xa))
+#define CONDGE  (COND (0xb))
+#define CONDGU  (COND (0xc))
+#define CONDL   (COND (0x3))
+#define CONDLE  (COND (0x2))
+#define CONDLEU (COND (0x4))
+#define CONDN   (COND (0x0))
+#define CONDNE  (COND (0x9))
+#define CONDNEG (COND (0x6))
+#define CONDPOS (COND (0xe))
+#define CONDVC  (COND (0xf))
+#define CONDVS  (COND (0x7))
+
+#define CONDNZ  CONDNE
+#define CONDZ   CONDE
+#define CONDGEU CONDCC
+#define CONDLU  CONDCS
+
+#define FCONDA          (COND (0x8))
+#define FCONDE          (COND (0x9))
+#define FCONDG          (COND (0x6))
+#define FCONDGE         (COND (0xb))
+#define FCONDL          (COND (0x4))
+#define FCONDLE         (COND (0xd))
+#define FCONDLG         (COND (0x2))
+#define FCONDN          (COND (0x0))
+#define FCONDNE         (COND (0x1))
+#define FCONDO          (COND (0xf))
+#define FCONDU          (COND (0x7))
+#define FCONDUE         (COND (0xa))
+#define FCONDUG         (COND (0x5))
+#define FCONDUGE        (COND (0xc))
+#define FCONDUL         (COND (0x3))
+#define FCONDULE        (COND (0xe))
+
+#define FCONDNZ FCONDNE
+#define FCONDZ  FCONDE
+
+#define ICC             (0)     /* v9 */
+#define XCC             (1 << 12) /* v9 */
+#define FCC(x)          (((x) & 0x3) << 11) /* v9 */
+#define FBFCC(x)        (((x) & 0x3) << 20)     /* v9 */
+
+/* The order of the opcodes in the table is significant:
+
+        * The assembler requires that all instances of the same mnemonic must
+        be consecutive. If they aren't, the assembler will bomb at runtime.
+
+        * The disassembler should not care about the order of the opcodes.  */
+
+/* Entries for commutative arithmetic operations.  */
+/* ??? More entries can make use of this.  */
+#define COMMUTEOP(opcode, op3, arch_mask) \
+{ opcode,       F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0),        "1,2,d", 0, arch_mask }, \
+{ opcode,       F3(2, op3, 1), F3(~2, ~op3, ~1),                "1,i,d", 0, arch_mask }, \
+{ opcode,       F3(2, op3, 1), F3(~2, ~op3, ~1),                "i,1,d", 0, arch_mask }
+
+static const struct sparc_opcode sparc_opcodes[] = {
+
+{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0),              "[1+2],d", 0, v6 },
+{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0,       "[1],d", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1),              "[1+i],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1),              "[i+1],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0),              "[1+2],g", 0, v6 },
+{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0,       "[1],g", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1),              "[1+i],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1),              "[i+1],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0,       "[i],g", 0, v6 },
+{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0),   "[1],g", 0, v6 }, /* ld [rs1+0],d */
+
+{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0),       "[1+2],F", 0, v6 },
+{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0),       "[1+i],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0),       "[i+1],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 },
+{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */
+
+{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0),              "[1+2],D", 0, v6notv9 },
+{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0,       "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1),              "[1+i],D", 0, v6notv9 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1),              "[i+1],D", 0, v6notv9 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0,       "[i],D", 0, v6notv9 },
+{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0),   "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */
+{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0),              "[1+2],C", 0, v6notv9 },
+{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0,       "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1),              "[1+i],C", 0, v6notv9 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1),              "[i+1],C", 0, v6notv9 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0,       "[i],C", 0, v6notv9 },
+{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0),   "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */
+
+/* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the
+   'ld' pseudo-op in v9.  */
+{ "lduw",       F3(3, 0x00, 0), F3(~3, ~0x00, ~0),              "[1+2],d", F_ALIAS, v9 },
+{ "lduw",       F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0,       "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */
+{ "lduw",       F3(3, 0x00, 1), F3(~3, ~0x00, ~1),              "[1+i],d", F_ALIAS, v9 },
+{ "lduw",       F3(3, 0x00, 1), F3(~3, ~0x00, ~1),              "[i+1],d", F_ALIAS, v9 },
+{ "lduw",       F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0,       "[i],d", F_ALIAS, v9 },
+{ "lduw",       F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0),   "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */
+
+{ "ldd",        F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "ldd",        F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */
+{ "ldd",        F3(3, 0x03, 1), F3(~3, ~0x03, ~1),              "[1+i],d", 0, v6 },
+{ "ldd",        F3(3, 0x03, 1), F3(~3, ~0x03, ~1),              "[i+1],d", 0, v6 },
+{ "ldd",        F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ldd",        F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ldd [rs1+0],d */
+{ "ldd",        F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0),      "[1+2],H", 0, v6 },
+{ "ldd",        F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0),  "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */
+{ "ldd",        F3(3, 0x23, 1), F3(~3, ~0x23, ~1),              "[1+i],H", 0, v6 },
+{ "ldd",        F3(3, 0x23, 1), F3(~3, ~0x23, ~1),              "[i+1],H", 0, v6 },
+{ "ldd",        F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0,       "[i],H", 0, v6 },
+{ "ldd",        F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0),   "[1],H", 0, v6 }, /* ldd [rs1+0],d */
+
+{ "ldd",        F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0),      "[1+2],D", 0, v6notv9 },
+{ "ldd",        F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0),  "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */
+{ "ldd",        F3(3, 0x33, 1), F3(~3, ~0x33, ~1),              "[1+i],D", 0, v6notv9 },
+{ "ldd",        F3(3, 0x33, 1), F3(~3, ~0x33, ~1),              "[i+1],D", 0, v6notv9 },
+{ "ldd",        F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0,       "[i],D", 0, v6notv9 },
+{ "ldd",        F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0),   "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */
+
+{ "ldq",        F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0),      "[1+2],J", 0, v9 },
+{ "ldq",        F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0),  "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */
+{ "ldq",        F3(3, 0x22, 1), F3(~3, ~0x22, ~1),              "[1+i],J", 0, v9 },
+{ "ldq",        F3(3, 0x22, 1), F3(~3, ~0x22, ~1),              "[i+1],J", 0, v9 },
+{ "ldq",        F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0,       "[i],J", 0, v9 },
+{ "ldq",        F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0),   "[1],J", 0, v9 }, /* ldd [rs1+0],d */
+
+{ "ldsb",       F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "ldsb",       F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */
+{ "ldsb",       F3(3, 0x09, 1), F3(~3, ~0x09, ~1),              "[1+i],d", 0, v6 },
+{ "ldsb",       F3(3, 0x09, 1), F3(~3, ~0x09, ~1),              "[i+1],d", 0, v6 },
+{ "ldsb",       F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ldsb",       F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ldsb [rs1+0],d */
+
+{ "ldsh",       F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */
+{ "ldsh",       F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "ldsh",       F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1),              "[1+i],d", 0, v6 },
+{ "ldsh",       F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1),              "[i+1],d", 0, v6 },
+{ "ldsh",       F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ldsh",       F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ldsh [rs1+0],d */
+
+{ "ldstub",     F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "ldstub",     F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */
+{ "ldstub",     F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1),              "[1+i],d", 0, v6 },
+{ "ldstub",     F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1),              "[i+1],d", 0, v6 },
+{ "ldstub",     F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ldstub",     F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ldstub [rs1+0],d */
+
+{ "ldsw",       F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0),      "[1+2],d", 0, v9 },
+{ "ldsw",       F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0),  "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */
+{ "ldsw",       F3(3, 0x08, 1), F3(~3, ~0x08, ~1),              "[1+i],d", 0, v9 },
+{ "ldsw",       F3(3, 0x08, 1), F3(~3, ~0x08, ~1),              "[i+1],d", 0, v9 },
+{ "ldsw",       F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0,       "[i],d", 0, v9 },
+{ "ldsw",       F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0),   "[1],d", 0, v9 }, /* ldsw [rs1+0],d */
+
+{ "ldub",       F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "ldub",       F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */
+{ "ldub",       F3(3, 0x01, 1), F3(~3, ~0x01, ~1),              "[1+i],d", 0, v6 },
+{ "ldub",       F3(3, 0x01, 1), F3(~3, ~0x01, ~1),              "[i+1],d", 0, v6 },
+{ "ldub",       F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "ldub",       F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* ldub [rs1+0],d */
+
+{ "lduh",       F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0),      "[1+2],d", 0, v6 },
+{ "lduh",       F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0),  "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */
+{ "lduh",       F3(3, 0x02, 1), F3(~3, ~0x02, ~1),              "[1+i],d", 0, v6 },
+{ "lduh",       F3(3, 0x02, 1), F3(~3, ~0x02, ~1),              "[i+1],d", 0, v6 },
+{ "lduh",       F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0,       "[i],d", 0, v6 },
+{ "lduh",       F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0),   "[1],d", 0, v6 }, /* lduh [rs1+0],d */
+
+{ "ldx",        F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0),      "[1+2],d", 0, v9 },
+{ "ldx",        F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0),  "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */
+{ "ldx",        F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1),              "[1+i],d", 0, v9 },
+{ "ldx",        F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1),              "[i+1],d", 0, v9 },
+{ "ldx",        F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0,       "[i],d", 0, v9 },
+{ "ldx",        F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0),   "[1],d", 0, v9 }, /* ldx [rs1+0],d */
+
+{ "ldx",        F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 },
+{ "ldx",        F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1),  "[1],F", 0, v9 }, /* ld [rs1+%g0],d */
+{ "ldx",        F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 },
+{ "ldx",        F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 },
+{ "ldx",        F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1),  "[i],F", 0, v9 },
+{ "ldx",        F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */
+
+{ "lda",        F3(3, 0x10, 0), F3(~3, ~0x10, ~0),              "[1+2]A,d", 0, v6 },
+{ "lda",        F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */
+{ "lda",        F3(3, 0x10, 1), F3(~3, ~0x10, ~1),              "[1+i]o,d", 0, v9 },
+{ "lda",        F3(3, 0x10, 1), F3(~3, ~0x10, ~1),              "[i+1]o,d", 0, v9 },
+{ "lda",        F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "lda",        F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+{ "lda",        F3(3, 0x30, 0), F3(~3, ~0x30, ~0),              "[1+2]A,g", 0, v9 },
+{ "lda",        F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0,       "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */
+{ "lda",        F3(3, 0x30, 1), F3(~3, ~0x30, ~1),              "[1+i]o,g", 0, v9 },
+{ "lda",        F3(3, 0x30, 1), F3(~3, ~0x30, ~1),              "[i+1]o,g", 0, v9 },
+{ "lda",        F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0,       "[i]o,g", 0, v9 },
+{ "lda",        F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0),   "[1]o,g", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldda",       F3(3, 0x13, 0), F3(~3, ~0x13, ~0),              "[1+2]A,d", 0, v6 },
+{ "ldda",       F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */
+{ "ldda",       F3(3, 0x13, 1), F3(~3, ~0x13, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldda",       F3(3, 0x13, 1), F3(~3, ~0x13, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldda",       F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldda",       F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldda",       F3(3, 0x33, 0), F3(~3, ~0x33, ~0),              "[1+2]A,H", 0, v9 },
+{ "ldda",       F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0,       "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */
+{ "ldda",       F3(3, 0x33, 1), F3(~3, ~0x33, ~1),              "[1+i]o,H", 0, v9 },
+{ "ldda",       F3(3, 0x33, 1), F3(~3, ~0x33, ~1),              "[i+1]o,H", 0, v9 },
+{ "ldda",       F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0,       "[i]o,H", 0, v9 },
+{ "ldda",       F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0),   "[1]o,H", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldqa",       F3(3, 0x32, 0), F3(~3, ~0x32, ~0),              "[1+2]A,J", 0, v9 },
+{ "ldqa",       F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0,       "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */
+{ "ldqa",       F3(3, 0x32, 1), F3(~3, ~0x32, ~1),              "[1+i]o,J", 0, v9 },
+{ "ldqa",       F3(3, 0x32, 1), F3(~3, ~0x32, ~1),              "[i+1]o,J", 0, v9 },
+{ "ldqa",       F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0,       "[i]o,J", 0, v9 },
+{ "ldqa",       F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0),   "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */
+
+{ "ldsba",      F3(3, 0x19, 0), F3(~3, ~0x19, ~0),              "[1+2]A,d", 0, v6 },
+{ "ldsba",      F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */
+{ "ldsba",      F3(3, 0x19, 1), F3(~3, ~0x19, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldsba",      F3(3, 0x19, 1), F3(~3, ~0x19, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldsba",      F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldsba",      F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldsha",      F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0),              "[1+2]A,d", 0, v6 },
+{ "ldsha",      F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */
+{ "ldsha",      F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldsha",      F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldsha",      F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldsha",      F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldstuba",    F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0),              "[1+2]A,d", 0, v6 },
+{ "ldstuba",    F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */
+{ "ldstuba",    F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldstuba",    F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldstuba",    F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldstuba",    F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "ldswa",      F3(3, 0x18, 0), F3(~3, ~0x18, ~0),              "[1+2]A,d", 0, v9 },
+{ "ldswa",      F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0,       "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */
+{ "ldswa",      F3(3, 0x18, 1), F3(~3, ~0x18, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldswa",      F3(3, 0x18, 1), F3(~3, ~0x18, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldswa",      F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldswa",      F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "lduba",      F3(3, 0x11, 0), F3(~3, ~0x11, ~0),              "[1+2]A,d", 0, v6 },
+{ "lduba",      F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */
+{ "lduba",      F3(3, 0x11, 1), F3(~3, ~0x11, ~1),              "[1+i]o,d", 0, v9 },
+{ "lduba",      F3(3, 0x11, 1), F3(~3, ~0x11, ~1),              "[i+1]o,d", 0, v9 },
+{ "lduba",      F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "lduba",      F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "lduha",      F3(3, 0x12, 0), F3(~3, ~0x12, ~0),              "[1+2]A,d", 0, v6 },
+{ "lduha",      F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0,       "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */
+{ "lduha",      F3(3, 0x12, 1), F3(~3, ~0x12, ~1),              "[1+i]o,d", 0, v9 },
+{ "lduha",      F3(3, 0x12, 1), F3(~3, ~0x12, ~1),              "[i+1]o,d", 0, v9 },
+{ "lduha",      F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "lduha",      F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "lduwa",      F3(3, 0x10, 0), F3(~3, ~0x10, ~0),              "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */
+{ "lduwa",      F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0,       "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */
+{ "lduwa",      F3(3, 0x10, 1), F3(~3, ~0x10, ~1),              "[1+i]o,d", F_ALIAS, v9 },
+{ "lduwa",      F3(3, 0x10, 1), F3(~3, ~0x10, ~1),              "[i+1]o,d", F_ALIAS, v9 },
+{ "lduwa",      F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0,       "[i]o,d", F_ALIAS, v9 },
+{ "lduwa",      F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0),   "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */
+
+{ "ldxa",       F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0),              "[1+2]A,d", 0, v9 },
+{ "ldxa",       F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0,       "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */
+{ "ldxa",       F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1),              "[1+i]o,d", 0, v9 },
+{ "ldxa",       F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1),              "[i+1]o,d", 0, v9 },
+{ "ldxa",       F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "ldxa",       F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
+
+{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0),              "d,[1+2]", 0, v6 },
+{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0),          "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1),                      "d,[1+i]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1),                      "d,[i+1]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0,               "d,[i]", 0, v6 },
+{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0),           "d,[1]", 0, v6 }, /* st d,[rs1+0] */
+{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0),              "g,[1+2]", 0, v6 },
+{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0),          "g,[1]", 0, v6 }, /* st d[rs1+%g0] */
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1),                      "g,[1+i]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1),                      "g,[i+1]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0,               "g,[i]", 0, v6 },
+{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0),           "g,[1]", 0, v6 }, /* st d,[rs1+0] */
+
+{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0),              "D,[1+2]", 0, v6notv9 },
+{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0),          "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1),                      "D,[1+i]", 0, v6notv9 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1),                      "D,[i+1]", 0, v6notv9 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0,               "D,[i]", 0, v6notv9 },
+{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0),           "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */
+{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0),              "C,[1+2]", 0, v6notv9 },
+{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0),          "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1),                      "C,[1+i]", 0, v6notv9 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1),                      "C,[i+1]", 0, v6notv9 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0,               "C,[i]", 0, v6notv9 },
+{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0),           "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */
+
+{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0),        "F,[1+2]", 0, v6 },
+{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0),    "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0,                "F,[1+i]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0,                "F,[i+1]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0,         "F,[i]", 0, v6 },
+{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0),     "F,[1]", 0, v6 }, /* st d,[rs1+0] */
+
+{ "stw",        F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v9 },
+{ "stw",        F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
+{ "stw",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[1+i]", F_ALIAS, v9 },
+{ "stw",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[i+1]", F_ALIAS, v9 },
+{ "stw",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v9 },
+{ "stw",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
+{ "stsw",       F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v9 },
+{ "stsw",       F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
+{ "stsw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[1+i]", F_ALIAS, v9 },
+{ "stsw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[i+1]", F_ALIAS, v9 },
+{ "stsw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v9 },
+{ "stsw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
+{ "stuw",       F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v9 },
+{ "stuw",       F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
+{ "stuw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[1+i]", F_ALIAS, v9 },
+{ "stuw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[i+1]", F_ALIAS, v9 },
+{ "stuw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v9 },
+{ "stuw",       F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
+
+{ "spill",      F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "spill",      F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */
+{ "spill",      F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "spill",      F3(3, 0x04, 1), F3(~3, ~0x04, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "spill",      F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "spill",      F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */
+
+{ "sta",        F3(3, 0x14, 0), F3(~3, ~0x14, ~0),              "d,[1+2]A", 0, v6 },
+{ "sta",        F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0),      "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */
+{ "sta",        F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[1+i]o", 0, v9 },
+{ "sta",        F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[i+1]o", 0, v9 },
+{ "sta",        F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0,       "d,[i]o", 0, v9 },
+{ "sta",        F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0),   "d,[1]o", 0, v9 }, /* st d,[rs1+0] */
+
+{ "sta",        F3(3, 0x34, 0), F3(~3, ~0x34, ~0),              "g,[1+2]A", 0, v9 },
+{ "sta",        F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0),      "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */
+{ "sta",        F3(3, 0x34, 1), F3(~3, ~0x34, ~1),              "g,[1+i]o", 0, v9 },
+{ "sta",        F3(3, 0x34, 1), F3(~3, ~0x34, ~1),              "g,[i+1]o", 0, v9 },
+{ "sta",        F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0,       "g,[i]o", 0, v9 },
+{ "sta",        F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0),   "g,[1]o", 0, v9 }, /* st d,[rs1+0] */
+
+{ "stwa",       F3(3, 0x14, 0), F3(~3, ~0x14, ~0),              "d,[1+2]A", F_ALIAS, v9 },
+{ "stwa",       F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
+{ "stwa",       F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stwa",       F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stwa",       F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stwa",       F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
+{ "stswa",      F3(3, 0x14, 0), F3(~3, ~0x14, ~0),              "d,[1+2]A", F_ALIAS, v9 },
+{ "stswa",      F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
+{ "stswa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stswa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stswa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stswa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
+{ "stuwa",      F3(3, 0x14, 0), F3(~3, ~0x14, ~0),              "d,[1+2]A", F_ALIAS, v9 },
+{ "stuwa",      F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
+{ "stuwa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stuwa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stuwa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stuwa",      F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
+
+{ "stb",        F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0),      "d,[1+2]", 0, v6 },
+{ "stb",        F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0),  "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */
+{ "stb",        F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[1+i]", 0, v6 },
+{ "stb",        F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[i+1]", 0, v6 },
+{ "stb",        F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0,       "d,[i]", 0, v6 },
+{ "stb",        F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0),   "d,[1]", 0, v6 }, /* stb d,[rs1+0] */
+
+{ "stsb",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "stsb",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */
+{ "stsb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "stsb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "stsb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "stsb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */
+{ "stub",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "stub",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */
+{ "stub",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "stub",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "stub",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "stub",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */
+
+{ "stba",       F3(3, 0x15, 0), F3(~3, ~0x15, ~0),              "d,[1+2]A", 0, v6 },
+{ "stba",       F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0),      "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */
+{ "stba",       F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[1+i]o", 0, v9 },
+{ "stba",       F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[i+1]o", 0, v9 },
+{ "stba",       F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0,       "d,[i]o", 0, v9 },
+{ "stba",       F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0),   "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */
+
+{ "stsba",      F3(3, 0x15, 0), F3(~3, ~0x15, ~0),              "d,[1+2]A", F_ALIAS, v6 },
+{ "stsba",      F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */
+{ "stsba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stsba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stsba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stsba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */
+{ "stuba",      F3(3, 0x15, 0), F3(~3, ~0x15, ~0),              "d,[1+2]A", F_ALIAS, v6 },
+{ "stuba",      F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */
+{ "stuba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stuba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stuba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stuba",      F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */
+
+{ "std",        F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0),      "d,[1+2]", 0, v6 },
+{ "std",        F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0),  "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std",        F3(3, 0x07, 1), F3(~3, ~0x07, ~1),              "d,[1+i]", 0, v6 },
+{ "std",        F3(3, 0x07, 1), F3(~3, ~0x07, ~1),              "d,[i+1]", 0, v6 },
+{ "std",        F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0,       "d,[i]", 0, v6 },
+{ "std",        F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0),   "d,[1]", 0, v6 }, /* std d,[rs1+0] */
+
+{ "std",        F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0),      "q,[1+2]", 0, v6notv9 },
+{ "std",        F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0),  "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
+{ "std",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1),              "q,[1+i]", 0, v6notv9 },
+{ "std",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1),              "q,[i+1]", 0, v6notv9 },
+{ "std",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0,       "q,[i]", 0, v6notv9 },
+{ "std",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0),   "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
+{ "std",        F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0),      "H,[1+2]", 0, v6 },
+{ "std",        F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0),  "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */
+{ "std",        F3(3, 0x27, 1), F3(~3, ~0x27, ~1),              "H,[1+i]", 0, v6 },
+{ "std",        F3(3, 0x27, 1), F3(~3, ~0x27, ~1),              "H,[i+1]", 0, v6 },
+{ "std",        F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0,       "H,[i]", 0, v6 },
+{ "std",        F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0),   "H,[1]", 0, v6 }, /* std d,[rs1+0] */
+
+{ "std",        F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0),      "Q,[1+2]", 0, v6notv9 },
+{ "std",        F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0),  "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
+{ "std",        F3(3, 0x36, 1), F3(~3, ~0x36, ~1),              "Q,[1+i]", 0, v6notv9 },
+{ "std",        F3(3, 0x36, 1), F3(~3, ~0x36, ~1),              "Q,[i+1]", 0, v6notv9 },
+{ "std",        F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0,       "Q,[i]", 0, v6notv9 },
+{ "std",        F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0),   "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
+{ "std",        F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0),      "D,[1+2]", 0, v6notv9 },
+{ "std",        F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0),  "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
+{ "std",        F3(3, 0x37, 1), F3(~3, ~0x37, ~1),              "D,[1+i]", 0, v6notv9 },
+{ "std",        F3(3, 0x37, 1), F3(~3, ~0x37, ~1),              "D,[i+1]", 0, v6notv9 },
+{ "std",        F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0,       "D,[i]", 0, v6notv9 },
+{ "std",        F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0),   "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
+
+{ "spilld",     F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "spilld",     F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */
+{ "spilld",     F3(3, 0x07, 1), F3(~3, ~0x07, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "spilld",     F3(3, 0x07, 1), F3(~3, ~0x07, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "spilld",     F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "spilld",     F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */
+
+{ "stda",       F3(3, 0x17, 0), F3(~3, ~0x17, ~0),              "d,[1+2]A", 0, v6 },
+{ "stda",       F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0),      "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */
+{ "stda",       F3(3, 0x17, 1), F3(~3, ~0x17, ~1),              "d,[1+i]o", 0, v9 },
+{ "stda",       F3(3, 0x17, 1), F3(~3, ~0x17, ~1),              "d,[i+1]o", 0, v9 },
+{ "stda",       F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0,       "d,[i]o", 0, v9 },
+{ "stda",       F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0),   "d,[1]o", 0, v9 }, /* std d,[rs1+0] */
+{ "stda",       F3(3, 0x37, 0), F3(~3, ~0x37, ~0),              "H,[1+2]A", 0, v9 },
+{ "stda",       F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0),      "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */
+{ "stda",       F3(3, 0x37, 1), F3(~3, ~0x37, ~1),              "H,[1+i]o", 0, v9 },
+{ "stda",       F3(3, 0x37, 1), F3(~3, ~0x37, ~1),              "H,[i+1]o", 0, v9 },
+{ "stda",       F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0,       "H,[i]o", 0, v9 },
+{ "stda",       F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0),   "H,[1]o", 0, v9 }, /* std d,[rs1+0] */
+
+{ "sth",        F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0),      "d,[1+2]", 0, v6 },
+{ "sth",        F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0),  "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */
+{ "sth",        F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[1+i]", 0, v6 },
+{ "sth",        F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[i+1]", 0, v6 },
+{ "sth",        F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0,       "d,[i]", 0, v6 },
+{ "sth",        F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0),   "d,[1]", 0, v6 }, /* sth d,[rs1+0] */
+
+{ "stsh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "stsh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */
+{ "stsh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "stsh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "stsh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "stsh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */
+{ "stuh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0),      "d,[1+2]", F_ALIAS, v6 },
+{ "stuh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0),  "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */
+{ "stuh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[1+i]", F_ALIAS, v6 },
+{ "stuh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1),              "d,[i+1]", F_ALIAS, v6 },
+{ "stuh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0,       "d,[i]", F_ALIAS, v6 },
+{ "stuh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0),   "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */
+
+{ "stha",       F3(3, 0x16, 0), F3(~3, ~0x16, ~0),              "d,[1+2]A", 0, v6 },
+{ "stha",       F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0),      "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */
+{ "stha",       F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[1+i]o", 0, v9 },
+{ "stha",       F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[i+1]o", 0, v9 },
+{ "stha",       F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0,       "d,[i]o", 0, v9 },
+{ "stha",       F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0),   "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */
+
+{ "stsha",      F3(3, 0x16, 0), F3(~3, ~0x16, ~0),              "d,[1+2]A", F_ALIAS, v6 },
+{ "stsha",      F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */
+{ "stsha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stsha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stsha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stsha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */
+{ "stuha",      F3(3, 0x16, 0), F3(~3, ~0x16, ~0),              "d,[1+2]A", F_ALIAS, v6 },
+{ "stuha",      F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0),      "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */
+{ "stuha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[1+i]o", F_ALIAS, v9 },
+{ "stuha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1),              "d,[i+1]o", F_ALIAS, v9 },
+{ "stuha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0,       "d,[i]o", F_ALIAS, v9 },
+{ "stuha",      F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0),   "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */
+
+{ "stx",        F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0),      "d,[1+2]", 0, v9 },
+{ "stx",        F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0),  "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */
+{ "stx",        F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1),              "d,[1+i]", 0, v9 },
+{ "stx",        F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1),              "d,[i+1]", 0, v9 },
+{ "stx",        F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0,       "d,[i]", 0, v9 },
+{ "stx",        F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0),   "d,[1]", 0, v9 }, /* stx d,[rs1+0] */
+
+{ "stx",        F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 },
+{ "stx",        F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */
+{ "stx",        F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1),         "F,[1+i]", 0, v9 },
+{ "stx",        F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1),         "F,[i+1]", 0, v9 },
+{ "stx",        F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1),  "F,[i]", 0, v9 },
+{ "stx",        F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */
+
+{ "stxa",       F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0),              "d,[1+2]A", 0, v9 },
+{ "stxa",       F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0),      "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */
+{ "stxa",       F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1),              "d,[1+i]o", 0, v9 },
+{ "stxa",       F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1),              "d,[i+1]o", 0, v9 },
+{ "stxa",       F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0,       "d,[i]o", 0, v9 },
+{ "stxa",       F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0),   "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */
+
+{ "stq",        F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0),      "J,[1+2]", 0, v9 },
+{ "stq",        F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0),  "J,[1]", 0, v9 }, /* stq [rs1+%g0] */
+{ "stq",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1),              "J,[1+i]", 0, v9 },
+{ "stq",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1),              "J,[i+1]", 0, v9 },
+{ "stq",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0,       "J,[i]", 0, v9 },
+{ "stq",        F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0),   "J,[1]", 0, v9 }, /* stq [rs1+0] */
+
+{ "stqa",       F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0),      "J,[1+2]A", 0, v9 },
+{ "stqa",       F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0),  "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */
+{ "stqa",       F3(3, 0x36, 1), F3(~3, ~0x36, ~1),              "J,[1+i]o", 0, v9 },
+{ "stqa",       F3(3, 0x36, 1), F3(~3, ~0x36, ~1),              "J,[i+1]o", 0, v9 },
+{ "stqa",       F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0,       "J,[i]o", 0, v9 },
+{ "stqa",       F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0),   "J,[1]o", 0, v9 }, /* stqa [rs1+0] */
+
+{ "swap",       F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0),      "[1+2],d", 0, v7 },
+{ "swap",       F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0),  "[1],d", 0, v7 }, /* swap [rs1+%g0],d */
+{ "swap",       F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1),              "[1+i],d", 0, v7 },
+{ "swap",       F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1),              "[i+1],d", 0, v7 },
+{ "swap",       F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0,       "[i],d", 0, v7 },
+{ "swap",       F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0),   "[1],d", 0, v7 }, /* swap [rs1+0],d */
+
+{ "swapa",      F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0),              "[1+2]A,d", 0, v7 },
+{ "swapa",      F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0),      "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */
+{ "swapa",      F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1),              "[1+i]o,d", 0, v9 },
+{ "swapa",      F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1),              "[i+1]o,d", 0, v9 },
+{ "swapa",      F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0,       "[i]o,d", 0, v9 },
+{ "swapa",      F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0),   "[1]o,d", 0, v9 }, /* swap [rs1+0],d */
+
+{ "restore",    F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0),                      "1,2,d", 0, v6 },
+{ "restore",    F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0),     "", 0, v6 }, /* restore %g0,%g0,%g0 */
+{ "restore",    F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1),                              "1,i,d", 0, v6 },
+{ "restore",    F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0),      "", 0, v6 }, /* restore %g0,0,%g0 */
+
+{ "rett",       F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0),        "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */
+{ "rett",       F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0),    "1", F_UNBR|F_DELAYED, v6 },    /* rett rs1,%g0 */
+{ "rett",       F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0,                "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */
+{ "rett",       F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0,                "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */
+{ "rett",       F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0,         "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */
+{ "rett",       F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0,         "i", F_UNBR|F_DELAYED, v6 },    /* rett X */
+{ "rett",       F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0),     "1", F_UNBR|F_DELAYED, v6 },    /* rett rs1+0 */
+
+{ "save",       F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "save",       F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1),              "1,i,d", 0, v6 },
+{ "save",       0x81e00000,     ~0x81e00000,                    "", F_ALIAS, v6 },
+
+{ "ret",  F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8),            "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */
+{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */
+
+{ "jmpl",       F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0),      "1+2,d", F_JSR|F_DELAYED, v6 },
+{ "jmpl",       F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0),  "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */
+{ "jmpl",       F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0),   "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */
+{ "jmpl",       F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0,       "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */
+{ "jmpl",       F3(2, 0x38, 1), F3(~2, ~0x38, ~1),              "1+i,d", F_JSR|F_DELAYED, v6 },
+{ "jmpl",       F3(2, 0x38, 1), F3(~2, ~0x38, ~1),              "i+1,d", F_JSR|F_DELAYED, v6 },
+
+{ "done",       F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "retry",      F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "saved",      F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "restored",   F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "allclean",   F3(2, 0x31, 0)|RD(2), F3(~2, ~0x31, ~0)|RD(~2)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "otherw",     F3(2, 0x31, 0)|RD(3), F3(~2, ~0x31, ~0)|RD(~3)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "normalw",    F3(2, 0x31, 0)|RD(4), F3(~2, ~0x31, ~0)|RD(~4)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "invalw",     F3(2, 0x31, 0)|RD(5), F3(~2, ~0x31, ~0)|RD(~5)|RS1_G0|SIMM13(~0),       "", 0, v9 },
+{ "sir",        F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0,              "i", 0, v9 },
+
+{ "flush",      F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0),      "1+2", 0, v8 },
+{ "flush",      F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0),  "1", 0, v8 }, /* flush rs1+%g0 */
+{ "flush",      F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0),   "1", 0, v8 }, /* flush rs1+0 */
+{ "flush",      F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0,       "i", 0, v8 }, /* flush %g0+i */
+{ "flush",      F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1),              "1+i", 0, v8 },
+{ "flush",      F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1),              "i+1", 0, v8 },
+
+/* IFLUSH was renamed to FLUSH in v8.  */
+{ "iflush",     F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0),      "1+2", F_ALIAS, v6 },
+{ "iflush",     F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0),  "1", F_ALIAS, v6 }, /* flush rs1+%g0 */
+{ "iflush",     F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0),   "1", F_ALIAS, v6 }, /* flush rs1+0 */
+{ "iflush",     F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0,       "i", F_ALIAS, v6 },
+{ "iflush",     F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1),              "1+i", F_ALIAS, v6 },
+{ "iflush",     F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1),              "i+1", F_ALIAS, v6 },
+
+{ "return",     F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0),      "1+2", 0, v9 },
+{ "return",     F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0),  "1", 0, v9 }, /* return rs1+%g0 */
+{ "return",     F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0),   "1", 0, v9 }, /* return rs1+0 */
+{ "return",     F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0,       "i", 0, v9 }, /* return %g0+i */
+{ "return",     F3(2, 0x39, 1), F3(~2, ~0x39, ~1),              "1+i", 0, v9 },
+{ "return",     F3(2, 0x39, 1), F3(~2, ~0x39, ~1),              "i+1", 0, v9 },
+
+{ "flushw",     F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0),     "", 0, v9 },
+
+{ "membar",     F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 },
+{ "stbar",      F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 },
+
+{ "prefetch",   F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0),              "[1+2],*", 0, v9 },
+{ "prefetch",   F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0,       "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */
+{ "prefetch",   F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1),              "[1+i],*", 0, v9 },
+{ "prefetch",   F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1),              "[i+1],*", 0, v9 },
+{ "prefetch",   F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0,       "[i],*", 0, v9 },
+{ "prefetch",   F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0),   "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */
+{ "prefetcha",  F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0),              "[1+2]A,*", 0, v9 },
+{ "prefetcha",  F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0,       "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */
+{ "prefetcha",  F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1),              "[1+i]o,*", 0, v9 },
+{ "prefetcha",  F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1),              "[i+1]o,*", 0, v9 },
+{ "prefetcha",  F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0,       "[i]o,*", 0, v9 },
+{ "prefetcha",  F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0),   "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */
+
+{ "sll",        F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5),    "1,2,d", 0, v6 },
+{ "sll",        F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5),    "1,X,d", 0, v6 },
+{ "sra",        F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5),    "1,2,d", 0, v6 },
+{ "sra",        F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5),    "1,X,d", 0, v6 },
+{ "srl",        F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5),    "1,2,d", 0, v6 },
+{ "srl",        F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5),    "1,X,d", 0, v6 },
+
+{ "sllx",       F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5),    "1,2,d", 0, v9 },
+{ "sllx",       F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6),    "1,Y,d", 0, v9 },
+{ "srax",       F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5),    "1,2,d", 0, v9 },
+{ "srax",       F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6),    "1,Y,d", 0, v9 },
+{ "srlx",       F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5),    "1,2,d", 0, v9 },
+{ "srlx",       F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6),    "1,Y,d", 0, v9 },
+
+{ "mulscc",     F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "mulscc",     F3(2, 0x24, 1), F3(~2, ~0x24, ~1),              "1,i,d", 0, v6 },
+
+{ "divscc",     F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0),      "1,2,d", 0, sparclite },
+{ "divscc",     F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1),              "1,i,d", 0, sparclite },
+
+{ "scan",       F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0),      "1,2,d", 0, sparclet|sparclite },
+{ "scan",       F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1),              "1,i,d", 0, sparclet|sparclite },
+
+{ "popc",       F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 },
+{ "popc",       F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0,       "i,d", 0, v9 },
+
+{ "clr",        F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0),     "d", F_ALIAS, v6 }, /* or %g0,%g0,d */
+{ "clr",        F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0),            "d", F_ALIAS, v6 }, /* or %g0,0,d       */
+{ "clr",        F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0),                "[1+2]", F_ALIAS, v6 },
+{ "clr",        F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0),            "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */
+{ "clr",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0,                        "[1+i]", F_ALIAS, v6 },
+{ "clr",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0,                        "[i+1]", F_ALIAS, v6 },
+{ "clr",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0,                 "[i]", F_ALIAS, v6 },
+{ "clr",        F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0),             "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */
+
+{ "clrb",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0),        "[1+2]", F_ALIAS, v6 },
+{ "clrb",       F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0),    "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */
+{ "clrb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0,                "[1+i]", F_ALIAS, v6 },
+{ "clrb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0,                "[i+1]", F_ALIAS, v6 },
+{ "clrb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0,         "[i]", F_ALIAS, v6 },
+{ "clrb",       F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0),     "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */
+
+{ "clrh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0),        "[1+2]", F_ALIAS, v6 },
+{ "clrh",       F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0),    "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */
+{ "clrh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0,                "[1+i]", F_ALIAS, v6 },
+{ "clrh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0,                "[i+1]", F_ALIAS, v6 },
+{ "clrh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0,         "[i]", F_ALIAS, v6 },
+{ "clrh",       F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0),     "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */
+
+{ "clrx",       F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0),        "[1+2]", F_ALIAS, v9 },
+{ "clrx",       F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0),    "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */
+{ "clrx",       F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0,                "[1+i]", F_ALIAS, v9 },
+{ "clrx",       F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0,                "[i+1]", F_ALIAS, v9 },
+{ "clrx",       F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0,         "[i]", F_ALIAS, v9 },
+{ "clrx",       F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0),     "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */
+
+{ "orcc",       F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "orcc",       F3(2, 0x12, 1), F3(~2, ~0x12, ~1),              "1,i,d", 0, v6 },
+{ "orcc",       F3(2, 0x12, 1), F3(~2, ~0x12, ~1),              "i,1,d", 0, v6 },
+
+/* This is not a commutative instruction.  */
+{ "orncc",      F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "orncc",      F3(2, 0x16, 1), F3(~2, ~0x16, ~1),              "1,i,d", 0, v6 },
+
+/* This is not a commutative instruction.  */
+{ "orn",        F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "orn",        F3(2, 0x06, 1), F3(~2, ~0x06, ~1),              "1,i,d", 0, v6 },
+
+{ "tst",        F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0),    "1", 0, v6 }, /* orcc rs1, %g0, %g0 */
+{ "tst",        F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */
+{ "tst",        F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0),     "1", 0, v6 }, /* orcc rs1, 0, %g0 */
+
+{ "wr", F3(2, 0x30, 0),         F3(~2, ~0x30, ~0)|ASI(~0),              "1,2,m", 0, v8 }, /* wr r,r,%asrX */
+{ "wr", F3(2, 0x30, 1),         F3(~2, ~0x30, ~1),                      "1,i,m", 0, v8 }, /* wr r,i,%asrX */
+{ "wr", F3(2, 0x30, 0),         F3(~2, ~0x30, ~0)|ASI_RS2(~0),          "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */
+{ "wr", F3(2, 0x30, 0),         F3(~2, ~0x30, ~0)|RD_G0|ASI(~0),        "1,2,y", 0, v6 }, /* wr r,r,%y */
+{ "wr", F3(2, 0x30, 1),         F3(~2, ~0x30, ~1)|RD_G0,                "1,i,y", 0, v6 }, /* wr r,i,%y */
+{ "wr", F3(2, 0x30, 0),         F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0),    "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */
+{ "wr", F3(2, 0x31, 0),         F3(~2, ~0x31, ~0)|RD_G0|ASI(~0),        "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */
+{ "wr", F3(2, 0x31, 1),         F3(~2, ~0x31, ~1)|RD_G0,                "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */
+{ "wr", F3(2, 0x31, 0),         F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0),    "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */
+{ "wr", F3(2, 0x32, 0),         F3(~2, ~0x32, ~0)|RD_G0|ASI(~0),        "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */
+{ "wr", F3(2, 0x32, 1),         F3(~2, ~0x32, ~1)|RD_G0,                "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */
+{ "wr", F3(2, 0x32, 0),         F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0),    "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */
+{ "wr", F3(2, 0x33, 0),         F3(~2, ~0x33, ~0)|RD_G0|ASI(~0),        "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */
+{ "wr", F3(2, 0x33, 1),         F3(~2, ~0x33, ~1)|RD_G0,                "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */
+{ "wr", F3(2, 0x33, 0),         F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0),    "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */
+
+{ "wr", F3(2, 0x30, 0)|RD(2),   F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0),       "1,2,E", 0, v9 }, /* wr r,r,%ccr */
+{ "wr", F3(2, 0x30, 1)|RD(2),   F3(~2, ~0x30, ~1)|RD(~2),               "1,i,E", 0, v9 }, /* wr r,i,%ccr */
+{ "wr", F3(2, 0x30, 0)|RD(3),   F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0),       "1,2,o", 0, v9 }, /* wr r,r,%asi */
+{ "wr", F3(2, 0x30, 1)|RD(3),   F3(~2, ~0x30, ~1)|RD(~3),               "1,i,o", 0, v9 }, /* wr r,i,%asi */
+{ "wr", F3(2, 0x30, 0)|RD(6),   F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0),       "1,2,s", 0, v9 }, /* wr r,r,%fprs */
+{ "wr", F3(2, 0x30, 1)|RD(6),   F3(~2, ~0x30, ~1)|RD(~6),               "1,i,s", 0, v9 }, /* wr r,i,%fprs */
+
+{ "wr", F3(2, 0x30, 0)|RD(16),  F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%pcr */
+{ "wr", F3(2, 0x30, 1)|RD(16),  F3(~2, ~0x30, ~1)|RD(~16),              "1,i,_", 0, v9a }, /* wr r,i,%pcr */
+{ "wr", F3(2, 0x30, 0)|RD(17),  F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%pic */
+{ "wr", F3(2, 0x30, 1)|RD(17),  F3(~2, ~0x30, ~1)|RD(~17),              "1,i,_", 0, v9a }, /* wr r,i,%pic */
+{ "wr", F3(2, 0x30, 0)|RD(18),  F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%dcr */
+{ "wr", F3(2, 0x30, 1)|RD(18),  F3(~2, ~0x30, ~1)|RD(~18),              "1,i,_", 0, v9a }, /* wr r,i,%dcr */
+{ "wr", F3(2, 0x30, 0)|RD(19),  F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%gsr */
+{ "wr", F3(2, 0x30, 1)|RD(19),  F3(~2, ~0x30, ~1)|RD(~19),              "1,i,_", 0, v9a }, /* wr r,i,%gsr */
+{ "wr", F3(2, 0x30, 0)|RD(20),  F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%set_softint */
+{ "wr", F3(2, 0x30, 1)|RD(20),  F3(~2, ~0x30, ~1)|RD(~20),              "1,i,_", 0, v9a }, /* wr r,i,%set_softint */
+{ "wr", F3(2, 0x30, 0)|RD(21),  F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */
+{ "wr", F3(2, 0x30, 1)|RD(21),  F3(~2, ~0x30, ~1)|RD(~21),              "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */
+{ "wr", F3(2, 0x30, 0)|RD(22),  F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%softint */
+{ "wr", F3(2, 0x30, 1)|RD(22),  F3(~2, ~0x30, ~1)|RD(~22),              "1,i,_", 0, v9a }, /* wr r,i,%softint */
+{ "wr", F3(2, 0x30, 0)|RD(23),  F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0),      "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */
+{ "wr", F3(2, 0x30, 1)|RD(23),  F3(~2, ~0x30, ~1)|RD(~23),              "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */
+{ "wr", F3(2, 0x30, 0)|RD(24),  F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0),      "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */
+{ "wr", F3(2, 0x30, 1)|RD(24),  F3(~2, ~0x30, ~1)|RD(~24),              "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */
+{ "wr", F3(2, 0x30, 0)|RD(25),  F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0),      "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */
+{ "wr", F3(2, 0x30, 1)|RD(25),  F3(~2, ~0x30, ~1)|RD(~25),              "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */
+
+{ "rd", F3(2, 0x28, 0),                 F3(~2, ~0x28, ~0)|SIMM13(~0),           "M,d", 0, v8 }, /* rd %asrX,r */
+{ "rd", F3(2, 0x28, 0),                 F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0),    "y,d", 0, v6 }, /* rd %y,r */
+{ "rd", F3(2, 0x29, 0),                 F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0),    "p,d", 0, v6notv9 }, /* rd %psr,r */
+{ "rd", F3(2, 0x2a, 0),                 F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0),    "w,d", 0, v6notv9 }, /* rd %wim,r */
+{ "rd", F3(2, 0x2b, 0),                 F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0),    "t,d", 0, v6notv9 }, /* rd %tbr,r */
+
+{ "rd", F3(2, 0x28, 0)|RS1(2),          F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0),   "E,d", 0, v9 }, /* rd %ccr,r */
+{ "rd", F3(2, 0x28, 0)|RS1(3),          F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0),   "o,d", 0, v9 }, /* rd %asi,r */
+{ "rd", F3(2, 0x28, 0)|RS1(4),          F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0),   "W,d", 0, v9 }, /* rd %tick,r */
+{ "rd", F3(2, 0x28, 0)|RS1(5),          F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0),   "P,d", 0, v9 }, /* rd %pc,r */
+{ "rd", F3(2, 0x28, 0)|RS1(6),          F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0),   "s,d", 0, v9 }, /* rd %fprs,r */
+
+{ "rd", F3(2, 0x28, 0)|RS1(16),         F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %pcr,r */
+{ "rd", F3(2, 0x28, 0)|RS1(17),         F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %pic,r */
+{ "rd", F3(2, 0x28, 0)|RS1(18),         F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %dcr,r */
+{ "rd", F3(2, 0x28, 0)|RS1(19),         F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %gsr,r */
+{ "rd", F3(2, 0x28, 0)|RS1(22),         F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %softint,r */
+{ "rd", F3(2, 0x28, 0)|RS1(23),         F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0),  "/,d", 0, v9a }, /* rd %tick_cmpr,r */
+{ "rd", F3(2, 0x28, 0)|RS1(24),         F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0),  "/,d", 0, v9b }, /* rd %sys_tick,r */
+{ "rd", F3(2, 0x28, 0)|RS1(25),         F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0),  "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */
+
+{ "rdpr",       F3(2, 0x2a, 0),         F3(~2, ~0x2a, ~0)|SIMM13(~0),   "?,d", 0, v9 },   /* rdpr %priv,r */
+{ "wrpr",       F3(2, 0x32, 0),         F3(~2, ~0x32, ~0),              "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */
+{ "wrpr",       F3(2, 0x32, 0),         F3(~2, ~0x32, ~0)|SIMM13(~0),   "1,!", 0, v9 },   /* wrpr r1,%priv */
+{ "wrpr",       F3(2, 0x32, 1),         F3(~2, ~0x32, ~1),              "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */
+{ "wrpr",       F3(2, 0x32, 1),         F3(~2, ~0x32, ~1),              "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */
+{ "wrpr",       F3(2, 0x32, 1),         F3(~2, ~0x32, ~1)|RS1(~0),      "i,!", 0, v9 },   /* wrpr i,%priv */
+
+{ "rdhpr",      F3(2, 0x29, 0),         F3(~2, ~0x29, ~0)|SIMM13(~0),   "$,d", 0, v9 },   /* rdhpr %hpriv,r */
+{ "wrhpr",      F3(2, 0x33, 0),         F3(~2, ~0x33, ~0),              "1,2,%", 0, v9 }, /* wrhpr r1,r2,%hpriv */
+{ "wrhpr",      F3(2, 0x33, 0),         F3(~2, ~0x33, ~0)|SIMM13(~0),   "1,%", 0, v9 },   /* wrhpr r1,%hpriv */
+{ "wrhpr",      F3(2, 0x33, 1),         F3(~2, ~0x33, ~1),              "1,i,%", 0, v9 }, /* wrhpr r1,i,%hpriv */
+{ "wrhpr",      F3(2, 0x33, 1),         F3(~2, ~0x33, ~1),              "i,1,%", F_ALIAS, v9 }, /* wrhpr i,r1,%hpriv */
+{ "wrhpr",      F3(2, 0x33, 1),         F3(~2, ~0x33, ~1)|RS1(~0),      "i,%", 0, v9 },   /* wrhpr i,%hpriv */
+
+/* ??? This group seems wrong.  A three operand move?  */
+{ "mov",        F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0),              "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1),                      "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */
+{ "mov",        F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0),        "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0,                "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */
+{ "mov",        F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0),        "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */
+{ "mov",        F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0,                "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */
+{ "mov",        F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0),        "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */
+{ "mov",        F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0,                "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */
+{ "mov",        F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0),        "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */
+{ "mov",        F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0,                "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */
+
+{ "mov",        F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0),           "M,d", F_ALIAS, v8 }, /* rd %asr1,r */
+{ "mov",        F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0),    "y,d", F_ALIAS, v6 }, /* rd %y,r */
+{ "mov",        F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0),    "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */
+{ "mov",        F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0),    "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */
+{ "mov",        F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0),    "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */
+
+{ "mov",        F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0),          "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1),                      "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0),           "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */
+{ "mov",        F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0),    "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0,                "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */
+{ "mov",        F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0),     "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */
+{ "mov",        F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0),    "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */
+{ "mov",        F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0,                "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */
+{ "mov",        F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0),     "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */
+{ "mov",        F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0),    "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */
+{ "mov",        F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0,                "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */
+{ "mov",        F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0),     "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */
+{ "mov",        F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0),    "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */
+{ "mov",        F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0,                "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */
+{ "mov",        F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0),     "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */
+
+{ "mov",        F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0),       "2,d", 0, v6 }, /* or %g0,rs2,d */
+{ "mov",        F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0,               "i,d", 0, v6 }, /* or %g0,i,d   */
+{ "mov",        F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0),          "1,d", 0, v6 }, /* or rs1,%g0,d   */
+{ "mov",        F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0),           "1,d", 0, v6 }, /* or rs1,0,d */
+
+{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1),              "1,i,d", 0, v6 },
+{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1),              "i,1,d", 0, v6 },
+
+{ "bset",       F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0),      "2,r", F_ALIAS, v6 },   /* or rd,rs2,rd */
+{ "bset",       F3(2, 0x02, 1), F3(~2, ~0x02, ~1),              "i,r", F_ALIAS, v6 },   /* or rd,i,rd */
+
+/* This is not a commutative instruction.  */
+{ "andn",       F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "andn",       F3(2, 0x05, 1), F3(~2, ~0x05, ~1),              "1,i,d", 0, v6 },
+
+/* This is not a commutative instruction.  */
+{ "andncc",     F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "andncc",     F3(2, 0x15, 1), F3(~2, ~0x15, ~1),              "1,i,d", 0, v6 },
+
+{ "bclr",       F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0),      "2,r", F_ALIAS, v6 },   /* andn rd,rs2,rd */
+{ "bclr",       F3(2, 0x05, 1), F3(~2, ~0x05, ~1),              "i,r", F_ALIAS, v6 },   /* andn rd,i,rd */
+
+{ "cmp",        F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0),        "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */
+{ "cmp",        F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0,                "1,i", 0, v6 }, /* subcc rs1,i,%g0 */
+
+{ "sub",        F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "sub",        F3(2, 0x04, 1), F3(~2, ~0x04, ~1),              "1,i,d", 0, v6 },
+
+{ "subcc",      F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "subcc",      F3(2, 0x14, 1), F3(~2, ~0x14, ~1),              "1,i,d", 0, v6 },
+
+{ "subx",       F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0),      "1,2,d", 0, v6notv9 },
+{ "subx",       F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1),              "1,i,d", 0, v6notv9 },
+{ "subc",       F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "subc",       F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1),              "1,i,d", 0, v9 },
+
+{ "subxcc",     F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0),      "1,2,d", 0, v6notv9 },
+{ "subxcc",     F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1),              "1,i,d", 0, v6notv9 },
+{ "subccc",     F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "subccc",     F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1),              "1,i,d", 0, v9 },
+
+{ "and",        F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "and",        F3(2, 0x01, 1), F3(~2, ~0x01, ~1),              "1,i,d", 0, v6 },
+{ "and",        F3(2, 0x01, 1), F3(~2, ~0x01, ~1),              "i,1,d", 0, v6 },
+
+{ "andcc",      F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "andcc",      F3(2, 0x11, 1), F3(~2, ~0x11, ~1),              "1,i,d", 0, v6 },
+{ "andcc",      F3(2, 0x11, 1), F3(~2, ~0x11, ~1),              "i,1,d", 0, v6 },
+
+{ "dec",        F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 },      /* sub rd,1,rd */
+{ "dec",        F3(2, 0x04, 1),             F3(~2, ~0x04, ~1),                 "i,r", F_ALIAS, v8 },    /* sub rd,imm,rd */
+{ "deccc",      F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 },      /* subcc rd,1,rd */
+{ "deccc",      F3(2, 0x14, 1),             F3(~2, ~0x14, ~1),                 "i,r", F_ALIAS, v8 },    /* subcc rd,imm,rd */
+{ "inc",        F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 },      /* add rd,1,rd */
+{ "inc",        F3(2, 0x00, 1),             F3(~2, ~0x00, ~1),                 "i,r", F_ALIAS, v8 },    /* add rd,imm,rd */
+{ "inccc",      F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 },      /* addcc rd,1,rd */
+{ "inccc",      F3(2, 0x10, 1),             F3(~2, ~0x10, ~1),                 "i,r", F_ALIAS, v8 },    /* addcc rd,imm,rd */
+
+{ "btst",       F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 },  /* andcc rs1,rs2,%g0 */
+{ "btst",       F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 },  /* andcc rs1,i,%g0 */
+
+{ "neg",        F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */
+{ "neg",        F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */
+
+{ "add",        F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "add",        F3(2, 0x00, 1), F3(~2, ~0x00, ~1),              "1,i,d", 0, v6 },
+{ "add",        F3(2, 0x00, 1), F3(~2, ~0x00, ~1),              "i,1,d", 0, v6 },
+{ "addcc",      F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "addcc",      F3(2, 0x10, 1), F3(~2, ~0x10, ~1),              "1,i,d", 0, v6 },
+{ "addcc",      F3(2, 0x10, 1), F3(~2, ~0x10, ~1),              "i,1,d", 0, v6 },
+
+{ "addx",       F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0),      "1,2,d", 0, v6notv9 },
+{ "addx",       F3(2, 0x08, 1), F3(~2, ~0x08, ~1),              "1,i,d", 0, v6notv9 },
+{ "addx",       F3(2, 0x08, 1), F3(~2, ~0x08, ~1),              "i,1,d", 0, v6notv9 },
+{ "addc",       F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "addc",       F3(2, 0x08, 1), F3(~2, ~0x08, ~1),              "1,i,d", 0, v9 },
+{ "addc",       F3(2, 0x08, 1), F3(~2, ~0x08, ~1),              "i,1,d", 0, v9 },
+
+{ "addxcc",     F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0),      "1,2,d", 0, v6notv9 },
+{ "addxcc",     F3(2, 0x18, 1), F3(~2, ~0x18, ~1),              "1,i,d", 0, v6notv9 },
+{ "addxcc",     F3(2, 0x18, 1), F3(~2, ~0x18, ~1),              "i,1,d", 0, v6notv9 },
+{ "addccc",     F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "addccc",     F3(2, 0x18, 1), F3(~2, ~0x18, ~1),              "1,i,d", 0, v9 },
+{ "addccc",     F3(2, 0x18, 1), F3(~2, ~0x18, ~1),              "i,1,d", 0, v9 },
+
+{ "smul",       F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "smul",       F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1),              "1,i,d", 0, v8 },
+{ "smul",       F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1),              "i,1,d", 0, v8 },
+{ "smulcc",     F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "smulcc",     F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1),              "1,i,d", 0, v8 },
+{ "smulcc",     F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1),              "i,1,d", 0, v8 },
+{ "umul",       F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "umul",       F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1),              "1,i,d", 0, v8 },
+{ "umul",       F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1),              "i,1,d", 0, v8 },
+{ "umulcc",     F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "umulcc",     F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1),              "1,i,d", 0, v8 },
+{ "umulcc",     F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1),              "i,1,d", 0, v8 },
+{ "sdiv",       F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "sdiv",       F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1),              "1,i,d", 0, v8 },
+{ "sdiv",       F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1),              "i,1,d", 0, v8 },
+{ "sdivcc",     F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "sdivcc",     F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1),              "1,i,d", 0, v8 },
+{ "sdivcc",     F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1),              "i,1,d", 0, v8 },
+{ "udiv",       F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "udiv",       F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1),              "1,i,d", 0, v8 },
+{ "udiv",       F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1),              "i,1,d", 0, v8 },
+{ "udivcc",     F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0),      "1,2,d", 0, v8 },
+{ "udivcc",     F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1),              "1,i,d", 0, v8 },
+{ "udivcc",     F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1),              "i,1,d", 0, v8 },
+
+{ "mulx",       F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "mulx",       F3(2, 0x09, 1), F3(~2, ~0x09, ~1),              "1,i,d", 0, v9 },
+{ "sdivx",      F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "sdivx",      F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1),              "1,i,d", 0, v9 },
+{ "udivx",      F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0),      "1,2,d", 0, v9 },
+{ "udivx",      F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1),              "1,i,d", 0, v9 },
+
+{ "call",       F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 },
+{ "call",       F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 },
+
+{ "call",       F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0),     "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */
+{ "call",       F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0),     "1+2,#", F_JSR|F_DELAYED, v6 },
+{ "call",       F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */
+{ "call",       F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 },
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),             "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),             "1+i,#", F_JSR|F_DELAYED, v6 },
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),             "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf),             "i+1,#", F_JSR|F_DELAYED, v6 },
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0,      "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0,      "i,#", F_JSR|F_DELAYED, v6 },
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0),  "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */
+{ "call",       F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0),  "1,#", F_JSR|F_DELAYED, v6 },
+
+
+/* Conditional instructions.
+
+   Because this part of the table was such a mess earlier, I have
+   macrofied it so that all the branches and traps are generated from
+   a single-line description of each condition value.  John Gilmore. */
+
+/* Define branches -- one annulled, one without, etc. */
+#define br(opcode, mask, lose, flags) \
+ { opcode, (mask)|ANNUL, (lose),       ",a l",   (flags), v6 }, \
+ { opcode, (mask)      , (lose)|ANNUL, "l",     (flags), v6 }
+
+#define brx(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), "Z,G",      (flags), v9 }, \
+ { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), ",T Z,G",   (flags), v9 }, \
+ { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a Z,G",   (flags), v9 }, \
+ { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a,T Z,G", (flags), v9 }, \
+ { opcode, (mask)|(2<<20), ANNUL|BPRED|(lose), ",N Z,G",   (flags), v9 }, \
+ { opcode, (mask)|(2<<20)|ANNUL, BPRED|(lose), ",a,N Z,G", (flags), v9 }, \
+ { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), "z,G",      (flags), v9 }, \
+ { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), ",T z,G",   (flags), v9 }, \
+ { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a z,G",   (flags), v9 }, \
+ { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a,T z,G", (flags), v9 }, \
+ { opcode, (mask), ANNUL|BPRED|(lose)|(2<<20), ",N z,G",   (flags), v9 }, \
+ { opcode, (mask)|ANNUL, BPRED|(lose)|(2<<20), ",a,N z,G", (flags), v9 }
+
+/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */
+#define tr(opcode, mask, lose, flags) \
+ { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i",   (flags), v9 }, /* %g0 + imm */ \
+ { opcode, (mask)|(2<<11)|IMMED, (lose),        "Z,1+i", (flags), v9 }, /* rs1 + imm */ \
+ { opcode, (mask)|(2<<11), IMMED|(lose),        "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \
+ { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1",   (flags), v9 }, /* rs1 + %g0 */ \
+ { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i",   (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \
+ { opcode, (mask)|IMMED, (lose),        "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \
+ { opcode, (mask), IMMED|(lose),        "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \
+ { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1",   (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \
+ { opcode, (mask)|IMMED, (lose)|RS1_G0,         "i",     (flags), v6 }, /* %g0 + imm */ \
+ { opcode, (mask)|IMMED, (lose),                "1+i",   (flags), v6 }, /* rs1 + imm */ \
+ { opcode, (mask), IMMED|(lose),                "1+2",   (flags), v6 }, /* rs1 + rs2 */ \
+ { opcode, (mask), IMMED|(lose)|RS2_G0,         "1",     (flags), v6 } /* rs1 + %g0 */
+
+/* v9: We must put `brx' before `br', to ensure that we never match something
+   v9: against an expression unless it is an expression.  Otherwise, we end
+   v9: up with undefined symbol tables entries, because they get added, but
+   v9: are not deleted if the pattern fails to match.  */
+
+/* Define both branches and traps based on condition mask */
+#define cond(bop, top, mask, flags) \
+  brx(bop, F2(0, 1)|(mask), F2(~0, ~1)|((~mask)&COND(~0)), F_DELAYED|(flags)), /* v9 */ \
+  br(bop,  F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \
+  tr(top,  F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), ((flags) & ~(F_UNBR|F_CONDBR)))
+
+/* Define all the conditions, all the branches, all the traps.  */
+
+/* Standard branch, trap mnemonics */
+cond ("b",      "ta",   CONDA, F_UNBR),
+/* Alternative form (just for assembly, not for disassembly) */
+cond ("ba",     "t",    CONDA, F_UNBR|F_ALIAS),
+
+cond ("bcc",    "tcc",  CONDCC, F_CONDBR),
+cond ("bcs",    "tcs",  CONDCS, F_CONDBR),
+cond ("be",     "te",   CONDE, F_CONDBR),
+cond ("beq",    "teq",  CONDE, F_CONDBR|F_ALIAS),
+cond ("bg",     "tg",   CONDG, F_CONDBR),
+cond ("bgt",    "tgt",  CONDG, F_CONDBR|F_ALIAS),
+cond ("bge",    "tge",  CONDGE, F_CONDBR),
+cond ("bgeu",   "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */
+cond ("bgu",    "tgu",  CONDGU, F_CONDBR),
+cond ("bl",     "tl",   CONDL, F_CONDBR),
+cond ("blt",    "tlt",  CONDL, F_CONDBR|F_ALIAS),
+cond ("ble",    "tle",  CONDLE, F_CONDBR),
+cond ("bleu",   "tleu", CONDLEU, F_CONDBR),
+cond ("blu",    "tlu",  CONDLU, F_CONDBR|F_ALIAS), /* for cs */
+cond ("bn",     "tn",   CONDN, F_CONDBR),
+cond ("bne",    "tne",  CONDNE, F_CONDBR),
+cond ("bneg",   "tneg", CONDNEG, F_CONDBR),
+cond ("bnz",    "tnz",  CONDNZ, F_CONDBR|F_ALIAS), /* for ne */
+cond ("bpos",   "tpos", CONDPOS, F_CONDBR),
+cond ("bvc",    "tvc",  CONDVC, F_CONDBR),
+cond ("bvs",    "tvs",  CONDVS, F_CONDBR),
+cond ("bz",     "tz",   CONDZ, F_CONDBR|F_ALIAS), /* for e */
+
+#undef cond
+#undef br
+#undef brr /* v9 */
+#undef tr
+
+#define brr(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, (mask)|BPRED, ANNUL|(lose), "1,k",      F_DELAYED|(flags), v9 }, \
+ { opcode, (mask)|BPRED, ANNUL|(lose), ",T 1,k",   F_DELAYED|(flags), v9 }, \
+ { opcode, (mask)|BPRED|ANNUL, (lose), ",a 1,k",   F_DELAYED|(flags), v9 }, \
+ { opcode, (mask)|BPRED|ANNUL, (lose), ",a,T 1,k", F_DELAYED|(flags), v9 }, \
+ { opcode, (mask), ANNUL|BPRED|(lose), ",N 1,k",   F_DELAYED|(flags), v9 }, \
+ { opcode, (mask)|ANNUL, BPRED|(lose), ",a,N 1,k", F_DELAYED|(flags), v9 }
+
+#define condr(bop, mask, flags) /* v9 */ \
+  brr(bop, F2(0, 3)|COND(mask), F2(~0, ~3)|COND(~(mask)), (flags)) /* v9 */
+
+/* v9 */ condr("brnz", 0x5, F_CONDBR),
+/* v9 */ condr("brz", 0x1, F_CONDBR),
+/* v9 */ condr("brgez", 0x7, F_CONDBR),
+/* v9 */ condr("brlz", 0x3, F_CONDBR),
+/* v9 */ condr("brlez", 0x2, F_CONDBR),
+/* v9 */ condr("brgz", 0x6, F_CONDBR),
+
+#undef condr /* v9 */
+#undef brr /* v9 */
+
+#define movr(opcode, mask, flags) /* v9 */ \
+ { opcode, F3(2, 0x2f, 0)|RCOND(mask), F3(~2, ~0x2f, ~0)|RCOND(~(mask)), "1,2,d", (flags), v9 }, \
+ { opcode, F3(2, 0x2f, 1)|RCOND(mask), F3(~2, ~0x2f, ~1)|RCOND(~(mask)), "1,j,d", (flags), v9 }
+
+#define fmrrs(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, (mask), (lose), "1,f,g", (flags) | F_FLOAT, v9 }
+#define fmrrd(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, (mask), (lose), "1,B,H", (flags) | F_FLOAT, v9 }
+#define fmrrq(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, (mask), (lose), "1,R,J", (flags) | F_FLOAT, v9 }
+
+#define fmovrs(mop, mask, flags) /* v9 */ \
+  fmrrs(mop, F3(2, 0x35, 0)|OPF_LOW5(5)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~5)|RCOND(~(mask)), (flags)) /* v9 */
+#define fmovrd(mop, mask, flags) /* v9 */ \
+  fmrrd(mop, F3(2, 0x35, 0)|OPF_LOW5(6)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~6)|RCOND(~(mask)), (flags)) /* v9 */
+#define fmovrq(mop, mask, flags) /* v9 */ \
+  fmrrq(mop, F3(2, 0x35, 0)|OPF_LOW5(7)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~7)|RCOND(~(mask)), (flags)) /* v9 */
+
+/* v9 */ movr("movrne", 0x5, 0),
+/* v9 */ movr("movre", 0x1, 0),
+/* v9 */ movr("movrgez", 0x7, 0),
+/* v9 */ movr("movrlz", 0x3, 0),
+/* v9 */ movr("movrlez", 0x2, 0),
+/* v9 */ movr("movrgz", 0x6, 0),
+/* v9 */ movr("movrnz", 0x5, F_ALIAS),
+/* v9 */ movr("movrz", 0x1, F_ALIAS),
+
+/* v9 */ fmovrs("fmovrsne", 0x5, 0),
+/* v9 */ fmovrs("fmovrse", 0x1, 0),
+/* v9 */ fmovrs("fmovrsgez", 0x7, 0),
+/* v9 */ fmovrs("fmovrslz", 0x3, 0),
+/* v9 */ fmovrs("fmovrslez", 0x2, 0),
+/* v9 */ fmovrs("fmovrsgz", 0x6, 0),
+/* v9 */ fmovrs("fmovrsnz", 0x5, F_ALIAS),
+/* v9 */ fmovrs("fmovrsz", 0x1, F_ALIAS),
+
+/* v9 */ fmovrd("fmovrdne", 0x5, 0),
+/* v9 */ fmovrd("fmovrde", 0x1, 0),
+/* v9 */ fmovrd("fmovrdgez", 0x7, 0),
+/* v9 */ fmovrd("fmovrdlz", 0x3, 0),
+/* v9 */ fmovrd("fmovrdlez", 0x2, 0),
+/* v9 */ fmovrd("fmovrdgz", 0x6, 0),
+/* v9 */ fmovrd("fmovrdnz", 0x5, F_ALIAS),
+/* v9 */ fmovrd("fmovrdz", 0x1, F_ALIAS),
+
+/* v9 */ fmovrq("fmovrqne", 0x5, 0),
+/* v9 */ fmovrq("fmovrqe", 0x1, 0),
+/* v9 */ fmovrq("fmovrqgez", 0x7, 0),
+/* v9 */ fmovrq("fmovrqlz", 0x3, 0),
+/* v9 */ fmovrq("fmovrqlez", 0x2, 0),
+/* v9 */ fmovrq("fmovrqgz", 0x6, 0),
+/* v9 */ fmovrq("fmovrqnz", 0x5, F_ALIAS),
+/* v9 */ fmovrq("fmovrqz", 0x1, F_ALIAS),
+
+#undef movr /* v9 */
+#undef fmovr /* v9 */
+#undef fmrr /* v9 */
+
+#define movicc(opcode, cond, flags) /* v9 */ \
+  { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|XCC|(1<<11), "z,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|XCC|(1<<11), "z,I,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|(1<<11),     "Z,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|(1<<11),     "Z,I,d", flags, v9 }
+
+#define movfcc(opcode, fcond, flags) /* v9 */ \
+  { opcode, F3(2, 0x2c, 0)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~0), "6,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~1), "6,I,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 0)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~0), "7,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~1), "7,I,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 0)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~0), "8,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~1), "8,I,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 0)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~0), "9,2,d", flags, v9 }, \
+  { opcode, F3(2, 0x2c, 1)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~1), "9,I,d", flags, v9 }
+
+#define movcc(opcode, cond, fcond, flags) /* v9 */ \
+  movfcc (opcode, fcond, flags), /* v9 */ \
+  movicc (opcode, cond, flags) /* v9 */
+
+/* v9 */ movcc  ("mova",        CONDA, FCONDA, 0),
+/* v9 */ movicc ("movcc",       CONDCC, 0),
+/* v9 */ movicc ("movgeu",      CONDGEU, F_ALIAS),
+/* v9 */ movicc ("movcs",       CONDCS, 0),
+/* v9 */ movicc ("movlu",       CONDLU, F_ALIAS),
+/* v9 */ movcc  ("move",        CONDE, FCONDE, 0),
+/* v9 */ movcc  ("movg",        CONDG, FCONDG, 0),
+/* v9 */ movcc  ("movge",       CONDGE, FCONDGE, 0),
+/* v9 */ movicc ("movgu",       CONDGU, 0),
+/* v9 */ movcc  ("movl",        CONDL, FCONDL, 0),
+/* v9 */ movcc  ("movle",       CONDLE, FCONDLE, 0),
+/* v9 */ movicc ("movleu",      CONDLEU, 0),
+/* v9 */ movfcc ("movlg",       FCONDLG, 0),
+/* v9 */ movcc  ("movn",        CONDN, FCONDN, 0),
+/* v9 */ movcc  ("movne",       CONDNE, FCONDNE, 0),
+/* v9 */ movicc ("movneg",      CONDNEG, 0),
+/* v9 */ movcc  ("movnz",       CONDNZ, FCONDNZ, F_ALIAS),
+/* v9 */ movfcc ("movo",        FCONDO, 0),
+/* v9 */ movicc ("movpos",      CONDPOS, 0),
+/* v9 */ movfcc ("movu",        FCONDU, 0),
+/* v9 */ movfcc ("movue",       FCONDUE, 0),
+/* v9 */ movfcc ("movug",       FCONDUG, 0),
+/* v9 */ movfcc ("movuge",      FCONDUGE, 0),
+/* v9 */ movfcc ("movul",       FCONDUL, 0),
+/* v9 */ movfcc ("movule",      FCONDULE, 0),
+/* v9 */ movicc ("movvc",       CONDVC, 0),
+/* v9 */ movicc ("movvs",       CONDVS, 0),
+/* v9 */ movcc  ("movz",        CONDZ, FCONDZ, F_ALIAS),
+
+#undef movicc /* v9 */
+#undef movfcc /* v9 */
+#undef movcc /* v9 */
+
+#define FM_SF 1         /* v9 - values for fpsize */
+#define FM_DF 2         /* v9 */
+#define FM_QF 3         /* v9 */
+
+#define fmoviccx(opcode, fpsize, args, cond, flags) /* v9 */ \
+{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0),  F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0),  "z," args, flags, v9 }, \
+{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0),  F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0),  "Z," args, flags, v9 }
+
+#define fmovfccx(opcode, fpsize, args, fcond, flags) /* v9 */ \
+{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags, v9 }, \
+{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags, v9 }, \
+{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags, v9 }, \
+{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags, v9 }
+
+/* FIXME: use fmovicc/fmovfcc? */ /* v9 */
+#define fmovccx(opcode, fpsize, args, cond, fcond, flags) /* v9 */ \
+{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0),  F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0),  "z," args, flags | F_FLOAT, v9 }, \
+{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6," args, flags | F_FLOAT, v9 }, \
+{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0),  F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0),  "Z," args, flags | F_FLOAT, v9 }, \
+{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7," args, flags | F_FLOAT, v9 }, \
+{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8," args, flags | F_FLOAT, v9 }, \
+{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9," args, flags | F_FLOAT, v9 }
+
+#define fmovicc(suffix, cond, flags) /* v9 */ \
+fmoviccx("fmovd" suffix, FM_DF, "B,H", cond, flags),            \
+fmoviccx("fmovq" suffix, FM_QF, "R,J", cond, flags),            \
+fmoviccx("fmovs" suffix, FM_SF, "f,g", cond, flags)
+
+#define fmovfcc(suffix, fcond, flags) /* v9 */ \
+fmovfccx("fmovd" suffix, FM_DF, "B,H", fcond, flags),           \
+fmovfccx("fmovq" suffix, FM_QF, "R,J", fcond, flags),           \
+fmovfccx("fmovs" suffix, FM_SF, "f,g", fcond, flags)
+
+#define fmovcc(suffix, cond, fcond, flags) /* v9 */ \
+fmovccx("fmovd" suffix, FM_DF, "B,H", cond, fcond, flags),      \
+fmovccx("fmovq" suffix, FM_QF, "R,J", cond, fcond, flags),      \
+fmovccx("fmovs" suffix, FM_SF, "f,g", cond, fcond, flags)
+
+/* v9 */ fmovcc  ("a", CONDA, FCONDA, 0),
+/* v9 */ fmovicc ("cc", CONDCC, 0),
+/* v9 */ fmovicc ("cs", CONDCS, 0),
+/* v9 */ fmovcc  ("e", CONDE, FCONDE, 0),
+/* v9 */ fmovcc  ("g", CONDG, FCONDG, 0),
+/* v9 */ fmovcc  ("ge", CONDGE, FCONDGE, 0),
+/* v9 */ fmovicc ("geu", CONDGEU, F_ALIAS),
+/* v9 */ fmovicc ("gu", CONDGU, 0),
+/* v9 */ fmovcc  ("l", CONDL, FCONDL, 0),
+/* v9 */ fmovcc  ("le", CONDLE, FCONDLE, 0),
+/* v9 */ fmovicc ("leu", CONDLEU, 0),
+/* v9 */ fmovfcc ("lg", FCONDLG, 0),
+/* v9 */ fmovicc ("lu", CONDLU, F_ALIAS),
+/* v9 */ fmovcc  ("n", CONDN, FCONDN, 0),
+/* v9 */ fmovcc  ("ne", CONDNE, FCONDNE, 0),
+/* v9 */ fmovicc ("neg", CONDNEG, 0),
+/* v9 */ fmovcc  ("nz", CONDNZ, FCONDNZ, F_ALIAS),
+/* v9 */ fmovfcc ("o", FCONDO, 0),
+/* v9 */ fmovicc ("pos", CONDPOS, 0),
+/* v9 */ fmovfcc ("u", FCONDU, 0),
+/* v9 */ fmovfcc ("ue", FCONDUE, 0),
+/* v9 */ fmovfcc ("ug", FCONDUG, 0),
+/* v9 */ fmovfcc ("uge", FCONDUGE, 0),
+/* v9 */ fmovfcc ("ul", FCONDUL, 0),
+/* v9 */ fmovfcc ("ule", FCONDULE, 0),
+/* v9 */ fmovicc ("vc", CONDVC, 0),
+/* v9 */ fmovicc ("vs", CONDVS, 0),
+/* v9 */ fmovcc  ("z", CONDZ, FCONDZ, F_ALIAS),
+
+#undef fmoviccx /* v9 */
+#undef fmovfccx /* v9 */
+#undef fmovccx /* v9 */
+#undef fmovicc /* v9 */
+#undef fmovfcc /* v9 */
+#undef fmovcc /* v9 */
+#undef FM_DF /* v9 */
+#undef FM_QF /* v9 */
+#undef FM_SF /* v9 */
+
+/* Coprocessor branches.  */
+#define CBR(opcode, mask, lose, flags, arch) \
+ { opcode, (mask), ANNUL | (lose), "l",    flags | F_DELAYED, arch }, \
+ { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED, arch }
+
+/* Floating point branches.  */
+#define FBR(opcode, mask, lose, flags) \
+ { opcode, (mask), ANNUL | (lose), "l",    flags | F_DELAYED | F_FBR, v6 }, \
+ { opcode, (mask) | ANNUL, (lose), ",a l", flags | F_DELAYED | F_FBR, v6 }
+
+/* V9 extended floating point branches.  */
+#define FBRX(opcode, mask, lose, flags) /* v9 */ \
+ { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G",      flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a,T 6,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(0)|(mask), ANNUL|BPRED|FBFCC(~0)|(lose), ",N 6,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(0)|(mask)|ANNUL, BPRED|FBFCC(~0)|(lose), ",a,N 6,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), "7,G",      flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), ",T 7,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a 7,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a,T 7,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask), ANNUL|BPRED|FBFCC(~1)|(lose), ",N 7,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(1)|(mask)|ANNUL, BPRED|FBFCC(~1)|(lose), ",a,N 7,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), "8,G",      flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), ",T 8,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a 8,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a,T 8,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask), ANNUL|BPRED|FBFCC(~2)|(lose), ",N 8,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(2)|(mask)|ANNUL, BPRED|FBFCC(~2)|(lose), ",a,N 8,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), "9,G",      flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), ",T 9,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G",   flags|F_DELAYED|F_FBR, v9 }, \
+ { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 }
+
+/* v9: We must put `FBRX' before `FBR', to ensure that we never match
+   v9: something against an expression unless it is an expression.  Otherwise,
+   v9: we end up with undefined symbol tables entries, because they get added,
+   v9: but are not deleted if the pattern fails to match.  */
+
+#define CONDFC(fop, cop, mask, flags) \
+  FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
+  FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \
+  CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet)
+
+#define CONDFCL(fop, cop, mask, flags) \
+  FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
+  FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \
+  CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6)
+
+#define CONDF(fop, mask, flags) \
+  FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
+  FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags)
+
+CONDFC  ("fb",    "cb",    0x8, F_UNBR),
+CONDFCL ("fba",   "cba",   0x8, F_UNBR|F_ALIAS),
+CONDFC  ("fbe",   "cb0",   0x9, F_CONDBR),
+CONDF   ("fbz",            0x9, F_CONDBR|F_ALIAS),
+CONDFC  ("fbg",   "cb2",   0x6, F_CONDBR),
+CONDFC  ("fbge",  "cb02",  0xb, F_CONDBR),
+CONDFC  ("fbl",   "cb1",   0x4, F_CONDBR),
+CONDFC  ("fble",  "cb01",  0xd, F_CONDBR),
+CONDFC  ("fblg",  "cb12",  0x2, F_CONDBR),
+CONDFCL ("fbn",   "cbn",   0x0, F_UNBR),
+CONDFC  ("fbne",  "cb123", 0x1, F_CONDBR),
+CONDF   ("fbnz",           0x1, F_CONDBR|F_ALIAS),
+CONDFC  ("fbo",   "cb012", 0xf, F_CONDBR),
+CONDFC  ("fbu",   "cb3",   0x7, F_CONDBR),
+CONDFC  ("fbue",  "cb03",  0xa, F_CONDBR),
+CONDFC  ("fbug",  "cb23",  0x5, F_CONDBR),
+CONDFC  ("fbuge", "cb023", 0xc, F_CONDBR),
+CONDFC  ("fbul",  "cb13",  0x3, F_CONDBR),
+CONDFC  ("fbule", "cb013", 0xe, F_CONDBR),
+
+#undef CONDFC
+#undef CONDFCL
+#undef CONDF
+#undef CBR
+#undef FBR
+#undef FBRX     /* v9 */
+
+{ "jmp",        F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0),        "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */
+{ "jmp",        F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0),    "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */
+{ "jmp",        F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0,                "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */
+{ "jmp",        F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0,                "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */
+{ "jmp",        F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0,         "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */
+{ "jmp",        F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0),     "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */
+
+{ "nop",        F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */
+
+{ "set",        F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 },
+{ "setuw",      F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 },
+{ "setsw",      F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 },
+{ "setx",       F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 },
+
+{ "sethi",      F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 },
+
+{ "taddcc",     F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "taddcc",     F3(2, 0x20, 1), F3(~2, ~0x20, ~1),              "1,i,d", 0, v6 },
+{ "taddcc",     F3(2, 0x20, 1), F3(~2, ~0x20, ~1),              "i,1,d", 0, v6 },
+{ "taddcctv",   F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "taddcctv",   F3(2, 0x22, 1), F3(~2, ~0x22, ~1),              "1,i,d", 0, v6 },
+{ "taddcctv",   F3(2, 0x22, 1), F3(~2, ~0x22, ~1),              "i,1,d", 0, v6 },
+
+{ "tsubcc",     F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "tsubcc",     F3(2, 0x21, 1), F3(~2, ~0x21, ~1),              "1,i,d", 0, v6 },
+{ "tsubcctv",   F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "tsubcctv",   F3(2, 0x23, 1), F3(~2, ~0x23, ~1),              "1,i,d", 0, v6 },
+
+{ "unimp",      F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 },
+{ "illtrap",    F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 },
+
+/* This *is* a commutative instruction.  */
+{ "xnor",       F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "xnor",       F3(2, 0x07, 1), F3(~2, ~0x07, ~1),              "1,i,d", 0, v6 },
+{ "xnor",       F3(2, 0x07, 1), F3(~2, ~0x07, ~1),              "i,1,d", 0, v6 },
+/* This *is* a commutative instruction.  */
+{ "xnorcc",     F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "xnorcc",     F3(2, 0x17, 1), F3(~2, ~0x17, ~1),              "1,i,d", 0, v6 },
+{ "xnorcc",     F3(2, 0x17, 1), F3(~2, ~0x17, ~1),              "i,1,d", 0, v6 },
+{ "xor",        F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "xor",        F3(2, 0x03, 1), F3(~2, ~0x03, ~1),              "1,i,d", 0, v6 },
+{ "xor",        F3(2, 0x03, 1), F3(~2, ~0x03, ~1),              "i,1,d", 0, v6 },
+{ "xorcc",      F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0),      "1,2,d", 0, v6 },
+{ "xorcc",      F3(2, 0x13, 1), F3(~2, ~0x13, ~1),              "1,i,d", 0, v6 },
+{ "xorcc",      F3(2, 0x13, 1), F3(~2, ~0x13, ~1),              "i,1,d", 0, v6 },
+
+{ "not",        F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */
+{ "not",        F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */
+
+{ "btog",       F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0),      "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */
+{ "btog",       F3(2, 0x03, 1), F3(~2, ~0x03, ~1),              "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */
+
+/* FPop1 and FPop2 are not instructions.  Don't accept them.  */
+
+{ "fdtoi",      F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 },
+{ "fstoi",      F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 },
+{ "fqtoi",      F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 },
+
+{ "fdtox",      F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,H", F_FLOAT, v9 },
+{ "fstox",      F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,H", F_FLOAT, v9 },
+{ "fqtox",      F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,H", F_FLOAT, v9 },
+
+{ "fitod",      F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 },
+{ "fitos",      F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 },
+{ "fitoq",      F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 },
+
+{ "fxtod",      F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "B,H", F_FLOAT, v9 },
+{ "fxtos",      F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "B,g", F_FLOAT, v9 },
+{ "fxtoq",      F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "B,J", F_FLOAT, v9 },
+
+{ "fdtoq",      F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 },
+{ "fdtos",      F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 },
+{ "fqtod",      F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 },
+{ "fqtos",      F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 },
+{ "fstod",      F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 },
+{ "fstoq",      F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 },
+
+{ "fdivd",      F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 },
+{ "fdivq",      F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 },
+{ "fdivx",      F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 },
+{ "fdivs",      F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 },
+{ "fmuld",      F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 },
+{ "fmulq",      F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 },
+{ "fmulx",      F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 },
+{ "fmuls",      F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 },
+
+{ "fdmulq",     F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 },
+{ "fdmulx",     F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 },
+{ "fsmuld",     F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 },
+
+{ "fsqrtd",     F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 },
+{ "fsqrtq",     F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 },
+{ "fsqrtx",     F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 },
+{ "fsqrts",     F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 },
+
+{ "fabsd",      F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 },
+{ "fabsq",      F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 },
+{ "fabsx",      F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
+{ "fabss",      F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 },
+{ "fmovd",      F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 },
+{ "fmovq",      F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 },
+{ "fmovx",      F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
+{ "fmovs",      F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 },
+{ "fnegd",      F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 },
+{ "fnegq",      F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 },
+{ "fnegx",      F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
+{ "fnegs",      F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 },
+
+{ "faddd",      F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 },
+{ "faddq",      F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 },
+{ "faddx",      F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 },
+{ "fadds",      F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 },
+{ "fsubd",      F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 },
+{ "fsubq",      F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 },
+{ "fsubx",      F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 },
+{ "fsubs",      F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 },
+
+#define CMPFCC(x)       (((x)&0x3)<<25)
+
+{ "fcmpd",                F3F(2, 0x35, 0x052),            F3F(~2, ~0x35, ~0x052)|RD_G0,  "v,B",   F_FLOAT, v6 },
+{ "fcmpd",      CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052),        "6,v,B", F_FLOAT, v9 },
+{ "fcmpd",      CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052),        "7,v,B", F_FLOAT, v9 },
+{ "fcmpd",      CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052),        "8,v,B", F_FLOAT, v9 },
+{ "fcmpd",      CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052),        "9,v,B", F_FLOAT, v9 },
+{ "fcmped",               F3F(2, 0x35, 0x056),            F3F(~2, ~0x35, ~0x056)|RD_G0,  "v,B",   F_FLOAT, v6 },
+{ "fcmped",     CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056),        "6,v,B", F_FLOAT, v9 },
+{ "fcmped",     CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056),        "7,v,B", F_FLOAT, v9 },
+{ "fcmped",     CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056),        "8,v,B", F_FLOAT, v9 },
+{ "fcmped",     CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056),        "9,v,B", F_FLOAT, v9 },
+{ "fcmpq",                F3F(2, 0x35, 0x053),            F3F(~2, ~0x35, ~0x053)|RD_G0,  "V,R", F_FLOAT, v8 },
+{ "fcmpq",      CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053),        "6,V,R", F_FLOAT, v9 },
+{ "fcmpq",      CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053),        "7,V,R", F_FLOAT, v9 },
+{ "fcmpq",      CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053),        "8,V,R", F_FLOAT, v9 },
+{ "fcmpq",      CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053),        "9,V,R", F_FLOAT, v9 },
+{ "fcmpeq",               F3F(2, 0x35, 0x057),            F3F(~2, ~0x35, ~0x057)|RD_G0,  "V,R", F_FLOAT, v8 },
+{ "fcmpeq",     CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057),        "6,V,R", F_FLOAT, v9 },
+{ "fcmpeq",     CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057),        "7,V,R", F_FLOAT, v9 },
+{ "fcmpeq",     CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057),        "8,V,R", F_FLOAT, v9 },
+{ "fcmpeq",     CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057),        "9,V,R", F_FLOAT, v9 },
+{ "fcmpx",                F3F(2, 0x35, 0x053),            F3F(~2, ~0x35, ~0x053)|RD_G0,  "V,R", F_FLOAT|F_ALIAS, v8 },
+{ "fcmpx",      CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053),        "6,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpx",      CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053),        "7,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpx",      CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053),        "8,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpx",      CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053),        "9,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpex",               F3F(2, 0x35, 0x057),            F3F(~2, ~0x35, ~0x057)|RD_G0,  "V,R", F_FLOAT|F_ALIAS, v8 },
+{ "fcmpex",     CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057),        "6,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpex",     CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057),        "7,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpex",     CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057),        "8,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmpex",     CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057),        "9,V,R", F_FLOAT|F_ALIAS, v9 },
+{ "fcmps",                F3F(2, 0x35, 0x051),            F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f",   F_FLOAT, v6 },
+{ "fcmps",      CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051),        "6,e,f", F_FLOAT, v9 },
+{ "fcmps",      CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051),        "7,e,f", F_FLOAT, v9 },
+{ "fcmps",      CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051),        "8,e,f", F_FLOAT, v9 },
+{ "fcmps",      CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051),        "9,e,f", F_FLOAT, v9 },
+{ "fcmpes",               F3F(2, 0x35, 0x055),            F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f",   F_FLOAT, v6 },
+{ "fcmpes",     CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055),        "6,e,f", F_FLOAT, v9 },
+{ "fcmpes",     CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055),        "7,e,f", F_FLOAT, v9 },
+{ "fcmpes",     CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055),        "8,e,f", F_FLOAT, v9 },
+{ "fcmpes",     CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055),        "9,e,f", F_FLOAT, v9 },
+
+/* These Extended FPop (FIFO) instructions are new in the Fujitsu
+   MB86934, replacing the CPop instructions from v6 and later
+   processors.  */
+
+#define EFPOP1_2(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op)|RS1_G0, args, 0, sparclite }
+#define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op),        args, 0, sparclite }
+#define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0,  args, 0, sparclite }
+
+EFPOP1_2 ("efitod",     0x0c8, "f,H"),
+EFPOP1_2 ("efitos",     0x0c4, "f,g"),
+EFPOP1_2 ("efdtoi",     0x0d2, "B,g"),
+EFPOP1_2 ("efstoi",     0x0d1, "f,g"),
+EFPOP1_2 ("efstod",     0x0c9, "f,H"),
+EFPOP1_2 ("efdtos",     0x0c6, "B,g"),
+EFPOP1_2 ("efmovs",     0x001, "f,g"),
+EFPOP1_2 ("efnegs",     0x005, "f,g"),
+EFPOP1_2 ("efabss",     0x009, "f,g"),
+EFPOP1_2 ("efsqrtd",    0x02a, "B,H"),
+EFPOP1_2 ("efsqrts",    0x029, "f,g"),
+EFPOP1_3 ("efaddd",     0x042, "v,B,H"),
+EFPOP1_3 ("efadds",     0x041, "e,f,g"),
+EFPOP1_3 ("efsubd",     0x046, "v,B,H"),
+EFPOP1_3 ("efsubs",     0x045, "e,f,g"),
+EFPOP1_3 ("efdivd",     0x04e, "v,B,H"),
+EFPOP1_3 ("efdivs",     0x04d, "e,f,g"),
+EFPOP1_3 ("efmuld",     0x04a, "v,B,H"),
+EFPOP1_3 ("efmuls",     0x049, "e,f,g"),
+EFPOP1_3 ("efsmuld",    0x069, "e,f,H"),
+EFPOP2_2 ("efcmpd",     0x052, "v,B"),
+EFPOP2_2 ("efcmped",    0x056, "v,B"),
+EFPOP2_2 ("efcmps",     0x051, "e,f"),
+EFPOP2_2 ("efcmpes",    0x055, "e,f"),
+
+#undef EFPOP1_2
+#undef EFPOP1_3
+#undef EFPOP2_2
+
+/* These are marked F_ALIAS, so that they won't conflict with sparclite insns
+   present.  Otherwise, the F_ALIAS flag is ignored.  */
+{ "cpop1",      F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 },
+{ "cpop2",      F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 },
+
+/* sparclet specific insns */
+
+COMMUTEOP ("umac", 0x3e, sparclet),
+COMMUTEOP ("smac", 0x3f, sparclet),
+COMMUTEOP ("umacd", 0x2e, sparclet),
+COMMUTEOP ("smacd", 0x2f, sparclet),
+COMMUTEOP ("umuld", 0x09, sparclet),
+COMMUTEOP ("smuld", 0x0d, sparclet),
+
+{ "shuffle",    F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0),      "1,2,d", 0, sparclet },
+{ "shuffle",    F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1),              "1,i,d", 0, sparclet },
+
+/* The manual isn't completely accurate on these insns.  The `rs2' field is
+   treated as being 6 bits to account for 6 bit immediates to cpush.  It is
+   assumed that it is intended that bit 5 is 0 when rs2 contains a reg.  */
+#define BIT5 (1<<5)
+{ "crdcxt",     F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0),    "U,d", 0, sparclet },
+{ "cwrcxt",     F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0),    "1,u", 0, sparclet },
+{ "cpush",      F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0),     "1,2", 0, sparclet },
+{ "cpush",      F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0),          "1,Y", 0, sparclet },
+{ "cpusha",     F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0),     "1,2", 0, sparclet },
+{ "cpusha",     F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0),          "1,Y", 0, sparclet },
+{ "cpull",      F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet },
+#undef BIT5
+
+/* sparclet coprocessor branch insns */
+#define SLCBCC2(opcode, mask, lose) \
+ { opcode, (mask), ANNUL|(lose), "l",    F_DELAYED|F_CONDBR, sparclet }, \
+ { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet }
+#define SLCBCC(opcode, mask) \
+  SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)))
+
+/* cbn,cba can't be defined here because they're defined elsewhere and GAS
+   requires all mnemonics of the same name to be consecutive.  */
+/*SLCBCC("cbn", 0), - already defined */
+SLCBCC("cbe", 1),
+SLCBCC("cbf", 2),
+SLCBCC("cbef", 3),
+SLCBCC("cbr", 4),
+SLCBCC("cber", 5),
+SLCBCC("cbfr", 6),
+SLCBCC("cbefr", 7),
+/*SLCBCC("cba", 8), - already defined */
+SLCBCC("cbne", 9),
+SLCBCC("cbnf", 10),
+SLCBCC("cbnef", 11),
+SLCBCC("cbnr", 12),
+SLCBCC("cbner", 13),
+SLCBCC("cbnfr", 14),
+SLCBCC("cbnefr", 15),
+
+#undef SLCBCC2
+#undef SLCBCC
+
+{ "casa",       F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 },
+{ "casa",       F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 },
+{ "casxa",      F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 },
+{ "casxa",      F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 },
+
+/* v9 synthetic insns */
+{ "iprefetch",  F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */
+{ "signx",      F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */
+{ "signx",      F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */
+{ "clruw",      F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */
+{ "clruw",      F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */
+{ "cas",        F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */
+{ "casl",       F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */
+{ "casx",       F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */
+{ "casxl",      F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */
+
+/* Ultrasparc extensions */
+{ "shutdown",   F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a },
+
+/* FIXME: Do we want to mark these as F_FLOAT, or something similar?  */
+{ "fpadd16",    F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a },
+{ "fpadd16s",   F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a },
+{ "fpadd32",    F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a },
+{ "fpadd32s",   F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a },
+{ "fpsub16",    F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a },
+{ "fpsub16s",   F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a },
+{ "fpsub32",    F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a },
+{ "fpsub32s",   F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a },
+
+{ "fpack32",    F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a },
+{ "fpack16",    F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a },
+{ "fpackfix",   F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a },
+{ "fexpand",    F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a },
+{ "fpmerge",    F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a },
+
+/* Note that the mixing of 32/64 bit regs is intentional.  */
+{ "fmul8x16",           F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a },
+{ "fmul8x16au",         F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a },
+{ "fmul8x16al",         F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a },
+{ "fmul8sux16",         F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a },
+{ "fmul8ulx16",         F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a },
+{ "fmuld8sux16",        F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a },
+{ "fmuld8ulx16",        F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a },
+
+{ "alignaddr",  F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a },
+{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a },
+{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a },
+
+{ "fzero",      F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a },
+{ "fzeros",     F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a },
+{ "fone",       F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a },
+{ "fones",      F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a },
+{ "fsrc1",      F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a },
+{ "fsrc1s",     F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a },
+{ "fsrc2",      F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a },
+{ "fsrc2s",     F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a },
+{ "fnot1",      F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a },
+{ "fnot1s",     F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a },
+{ "fnot2",      F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a },
+{ "fnot2s",     F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a },
+{ "for",        F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a },
+{ "fors",       F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a },
+{ "fnor",       F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a },
+{ "fnors",      F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a },
+{ "fand",       F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a },
+{ "fands",      F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a },
+{ "fnand",      F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a },
+{ "fnands",     F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a },
+{ "fxor",       F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a },
+{ "fxors",      F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a },
+{ "fxnor",      F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a },
+{ "fxnors",     F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a },
+{ "fornot1",    F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a },
+{ "fornot1s",   F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a },
+{ "fornot2",    F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a },
+{ "fornot2s",   F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a },
+{ "fandnot1",   F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a },
+{ "fandnot1s",  F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a },
+{ "fandnot2",   F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a },
+{ "fandnot2s",  F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a },
+
+{ "fcmpgt16",   F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a },
+{ "fcmpgt32",   F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a },
+{ "fcmple16",   F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a },
+{ "fcmple32",   F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a },
+{ "fcmpne16",   F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a },
+{ "fcmpne32",   F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a },
+{ "fcmpeq16",   F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a },
+{ "fcmpeq32",   F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a },
+
+{ "edge8",      F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a },
+{ "edge8l",     F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a },
+{ "edge16",     F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a },
+{ "edge16l",    F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a },
+{ "edge32",     F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a },
+{ "edge32l",    F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a },
+
+{ "pdist",      F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a },
+
+{ "array8",     F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a },
+{ "array16",    F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a },
+{ "array32",    F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a },
+
+/* Cheetah instructions */
+{ "edge8n",    F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b },
+{ "edge8ln",   F3F(2, 0x36, 0x003), F3F(~2, ~0x36, ~0x003), "1,2,d", 0, v9b },
+{ "edge16n",   F3F(2, 0x36, 0x005), F3F(~2, ~0x36, ~0x005), "1,2,d", 0, v9b },
+{ "edge16ln",  F3F(2, 0x36, 0x007), F3F(~2, ~0x36, ~0x007), "1,2,d", 0, v9b },
+{ "edge32n",   F3F(2, 0x36, 0x009), F3F(~2, ~0x36, ~0x009), "1,2,d", 0, v9b },
+{ "edge32ln",  F3F(2, 0x36, 0x00b), F3F(~2, ~0x36, ~0x00b), "1,2,d", 0, v9b },
+
+{ "bmask",     F3F(2, 0x36, 0x019), F3F(~2, ~0x36, ~0x019), "1,2,d", 0, v9b },
+{ "bshuffle",  F3F(2, 0x36, 0x04c), F3F(~2, ~0x36, ~0x04c), "v,B,H", 0, v9b },
+
+{ "siam",      F3F(2, 0x36, 0x081), F3F(~2, ~0x36, ~0x081)|RD_G0|RS1_G0|RS2(~7), "3", 0, v9b },
+
+/* More v9 specific insns, these need to come last so they do not clash
+   with v9a instructions such as "edge8" which looks like impdep1. */
+
+#define IMPDEP(name, code) \
+{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \
+{ name, F3(2, code, 1), F3(~2, ~code, ~1),         "1,i,d", 0, v9notv9a }, \
+{ name, F3(2, code, 0), F3(~2, ~code, ~0),         "x,1,2,d", 0, v9notv9a }, \
+{ name, F3(2, code, 0), F3(~2, ~code, ~0),         "x,e,f,g", 0, v9notv9a }
+
+IMPDEP ("impdep1", 0x36),
+IMPDEP ("impdep2", 0x37),
+
+#undef IMPDEP
+
+};
+
+static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0]));
+
+/* Utilities for argument parsing.  */
+
+typedef struct
+{
+  int value;
+  const char *name;
+} arg;
+
+/* Look up VALUE in TABLE.  */
+
+static const char *
+lookup_value (const arg *table, int value)
+{
+  const arg *p;
+
+  for (p = table; p->name; ++p)
+    if (value == p->value)
+      return p->name;
+
+  return NULL;
+}
+
+/* Handle ASI's.  */
+
+static const arg asi_table_v8[] =
+{
+  { 0x00, "#ASI_M_RES00" },
+  { 0x01, "#ASI_M_UNA01" },
+  { 0x02, "#ASI_M_MXCC" },
+  { 0x03, "#ASI_M_FLUSH_PROBE" },
+  { 0x04, "#ASI_M_MMUREGS" },
+  { 0x05, "#ASI_M_TLBDIAG" },
+  { 0x06, "#ASI_M_DIAGS" },
+  { 0x07, "#ASI_M_IODIAG" },
+  { 0x08, "#ASI_M_USERTXT" },
+  { 0x09, "#ASI_M_KERNELTXT" },
+  { 0x0A, "#ASI_M_USERDATA" },
+  { 0x0B, "#ASI_M_KERNELDATA" },
+  { 0x0C, "#ASI_M_TXTC_TAG" },
+  { 0x0D, "#ASI_M_TXTC_DATA" },
+  { 0x0E, "#ASI_M_DATAC_TAG" },
+  { 0x0F, "#ASI_M_DATAC_DATA" },
+  { 0x10, "#ASI_M_FLUSH_PAGE" },
+  { 0x11, "#ASI_M_FLUSH_SEG" },
+  { 0x12, "#ASI_M_FLUSH_REGION" },
+  { 0x13, "#ASI_M_FLUSH_CTX" },
+  { 0x14, "#ASI_M_FLUSH_USER" },
+  { 0x17, "#ASI_M_BCOPY" },
+  { 0x18, "#ASI_M_IFLUSH_PAGE" },
+  { 0x19, "#ASI_M_IFLUSH_SEG" },
+  { 0x1A, "#ASI_M_IFLUSH_REGION" },
+  { 0x1B, "#ASI_M_IFLUSH_CTX" },
+  { 0x1C, "#ASI_M_IFLUSH_USER" },
+  { 0x1F, "#ASI_M_BFILL" },
+  { 0x20, "#ASI_M_BYPASS" },
+  { 0x29, "#ASI_M_FBMEM" },
+  { 0x2A, "#ASI_M_VMEUS" },
+  { 0x2B, "#ASI_M_VMEPS" },
+  { 0x2C, "#ASI_M_VMEUT" },
+  { 0x2D, "#ASI_M_VMEPT" },
+  { 0x2E, "#ASI_M_SBUS" },
+  { 0x2F, "#ASI_M_CTL" },
+  { 0x31, "#ASI_M_FLUSH_IWHOLE" },
+  { 0x36, "#ASI_M_IC_FLCLEAR" },
+  { 0x37, "#ASI_M_DC_FLCLEAR" },
+  { 0x39, "#ASI_M_DCDR" },
+  { 0x40, "#ASI_M_VIKING_TMP1" },
+  { 0x41, "#ASI_M_VIKING_TMP2" },
+  { 0x4c, "#ASI_M_ACTION" },
+  { 0, NULL }
+};
+
+static const arg asi_table_v9[] =
+{
+  /* These are in the v9 architecture manual.  */
+  /* The shorter versions appear first, they're here because Sun's as has them.
+     Sun's as uses #ASI_P_L instead of #ASI_PL (which appears in the
+     UltraSPARC architecture manual).  */
+  { 0x04, "#ASI_N" },
+  { 0x0c, "#ASI_N_L" },
+  { 0x10, "#ASI_AIUP" },
+  { 0x11, "#ASI_AIUS" },
+  { 0x18, "#ASI_AIUP_L" },
+  { 0x19, "#ASI_AIUS_L" },
+  { 0x80, "#ASI_P" },
+  { 0x81, "#ASI_S" },
+  { 0x82, "#ASI_PNF" },
+  { 0x83, "#ASI_SNF" },
+  { 0x88, "#ASI_P_L" },
+  { 0x89, "#ASI_S_L" },
+  { 0x8a, "#ASI_PNF_L" },
+  { 0x8b, "#ASI_SNF_L" },
+  { 0x04, "#ASI_NUCLEUS" },
+  { 0x0c, "#ASI_NUCLEUS_LITTLE" },
+  { 0x10, "#ASI_AS_IF_USER_PRIMARY" },
+  { 0x11, "#ASI_AS_IF_USER_SECONDARY" },
+  { 0x18, "#ASI_AS_IF_USER_PRIMARY_LITTLE" },
+  { 0x19, "#ASI_AS_IF_USER_SECONDARY_LITTLE" },
+  { 0x80, "#ASI_PRIMARY" },
+  { 0x81, "#ASI_SECONDARY" },
+  { 0x82, "#ASI_PRIMARY_NOFAULT" },
+  { 0x83, "#ASI_SECONDARY_NOFAULT" },
+  { 0x88, "#ASI_PRIMARY_LITTLE" },
+  { 0x89, "#ASI_SECONDARY_LITTLE" },
+  { 0x8a, "#ASI_PRIMARY_NOFAULT_LITTLE" },
+  { 0x8b, "#ASI_SECONDARY_NOFAULT_LITTLE" },
+  /* These are UltraSPARC extensions.  */
+  { 0x14, "#ASI_PHYS_USE_EC"},
+  { 0x15, "#ASI_PHYS_BYPASS_EC_WITH_EBIT"},
+  { 0x45, "#ASI_LSU_CONTROL_REG"},
+  { 0x47, "#ASI_DCACHE_TAG"},
+  { 0x4a, "#ASI_UPA_CONFIG_REG"},
+  { 0x50, "#ASI_IMMU" },
+  { 0x51, "#ASI_IMMU_TSB_8KB_PTR_REG" },
+  { 0x52, "#ASI_IMMU_TSB_64KB_PTR_REG" },
+  /*{ 0x53, "#reserved?" },*/
+  { 0x54, "#ASI_ITLB_DATA_IN_REG" },
+  { 0x55, "#ASI_ITLB_DATA_ACCESS_REG" },
+  { 0x56, "#ASI_ITLB_TAG_READ_REG" },
+  { 0x57, "#ASI_IMMU_DEMAP" },
+  { 0x58, "#ASI_DMMU" },
+  { 0x59, "#ASI_DMMU_TSB_8KB_PTR_REG" },
+  { 0x5a, "#ASI_DMMU_TSB_64KB_PTR_REG" },
+  { 0x5b, "#ASI_DMMU_TSB_DIRECT_PTR_REG" },
+  { 0x5c, "#ASI_DTLB_DATA_IN_REG" },
+  { 0x5d, "#ASI_DTLB_DATA_ACCESS_REG" },
+  { 0x5e, "#ASI_DTLB_TAG_READ_REG" },
+  { 0x5f, "#ASI_DMMU_DEMAP" },
+  { 0x67, "#ASI_IC_TAG"},
+  /* FIXME: There are dozens of them.  Not sure we want them all.
+     Most are for kernel building but some are for vis type stuff.  */
+  { 0, NULL }
+};
+
+/* Return the name for ASI value VALUE or NULL if not found.  */
+
+static const char *
+sparc_decode_asi_v9 (int value)
+{
+  return lookup_value (asi_table_v9, value);
+}
+
+static const char *
+sparc_decode_asi_v8 (int value)
+{
+  return lookup_value (asi_table_v8, value);
+}
+
+/* Handle membar masks.  */
+
+static const arg membar_table[] =
+{
+  { 0x40, "#Sync" },
+  { 0x20, "#MemIssue" },
+  { 0x10, "#Lookaside" },
+  { 0x08, "#StoreStore" },
+  { 0x04, "#LoadStore" },
+  { 0x02, "#StoreLoad" },
+  { 0x01, "#LoadLoad" },
+  { 0, NULL }
+};
+
+/* Return the name for membar value VALUE or NULL if not found.  */
+
+static const char *
+sparc_decode_membar (int value)
+{
+  return lookup_value (membar_table, value);
+}
+
+/* Handle prefetch args.  */
+
+static const arg prefetch_table[] =
+{
+  { 0, "#n_reads" },
+  { 1, "#one_read" },
+  { 2, "#n_writes" },
+  { 3, "#one_write" },
+  { 4, "#page" },
+  { 16, "#invalidate" },
+  { 0, NULL }
+};
+
+/* Return the name for prefetch value VALUE or NULL if not found.  */
+
+static const char *
+sparc_decode_prefetch (int value)
+{
+  return lookup_value (prefetch_table, value);
+}
+
+/* Handle sparclet coprocessor registers.  */
+
+static const arg sparclet_cpreg_table[] =
+{
+  { 0, "%ccsr" },
+  { 1, "%ccfr" },
+  { 2, "%cccrcr" },
+  { 3, "%ccpr" },
+  { 4, "%ccsr2" },
+  { 5, "%cccrr" },
+  { 6, "%ccrstr" },
+  { 0, NULL }
+};
+
+/* Return the name for sparclet cpreg value VALUE or NULL if not found.  */
+
+static const char *
+sparc_decode_sparclet_cpreg (int value)
+{
+  return lookup_value (sparclet_cpreg_table, value);
+}
+
+#undef MASK_V9
+
+/* opcodes/sparc-dis.c */
+
+/* Print SPARC instructions.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* Bitmask of v9 architectures.  */
+#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
+                 | (1 << SPARC_OPCODE_ARCH_V9A) \
+                 | (1 << SPARC_OPCODE_ARCH_V9B))
+/* 1 if INSN is for v9 only.  */
+#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
+/* 1 if INSN is for v9.  */
+#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
+
+/* The sorted opcode table.  */
+static const sparc_opcode **sorted_opcodes;
+
+/* For faster lookup, after insns are sorted they are hashed.  */
+/* ??? I think there is room for even more improvement.  */
+
+#define HASH_SIZE 256
+/* It is important that we only look at insn code bits as that is how the
+   opcode table is hashed.  OPCODE_BITS is a table of valid bits for each
+   of the main types (0,1,2,3).  */
+static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
+#define HASH_INSN(INSN) \
+  ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
+typedef struct sparc_opcode_hash
+{
+  struct sparc_opcode_hash *next;
+  const sparc_opcode *opcode;
+} sparc_opcode_hash;
+
+static sparc_opcode_hash *opcode_hash_table[HASH_SIZE];
+
+/* Sign-extend a value which is N bits long.  */
+#define SEX(value, bits) \
+        ((((int)(value)) << ((8 * sizeof (int)) - bits))        \
+                         >> ((8 * sizeof (int)) - bits) )
+
+static const char * const reg_names[] =
+{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
+  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
+  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
+  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
+  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
+  "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
+  "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
+/* psr, wim, tbr, fpsr, cpsr are v8 only.  */
+  "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
+};
+
+#define freg_names      (&reg_names[4 * 8])
+
+/* These are ordered according to there register number in
+   rdpr and wrpr insns.  */
+static const char * const v9_priv_reg_names[] =
+{
+  "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
+  "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
+  "wstate", "fq", "gl"
+  /* "ver" - special cased */
+};
+
+/* These are ordered according to there register number in
+   rdhpr and wrhpr insns.  */
+static const char * const v9_hpriv_reg_names[] =
+{
+  "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver",
+  "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13",
+  "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20",
+  "resv21", "resv22", "resv23", "resv24", "resv25", "resv26", "resv27",
+  "resv28", "resv29", "resv30", "hstick_cmpr"
+};
+
+/* These are ordered according to there register number in
+   rd and wr insns (-16).  */
+static const char * const v9a_asr_reg_names[] =
+{
+  "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
+  "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"
+};
+
+/* Macros used to extract instruction fields.  Not all fields have
+   macros defined here, only those which are actually used.  */
+
+#define X_RD(i)      (((i) >> 25) & 0x1f)
+#define X_RS1(i)     (((i) >> 14) & 0x1f)
+#define X_LDST_I(i)  (((i) >> 13) & 1)
+#define X_ASI(i)     (((i) >> 5) & 0xff)
+#define X_RS2(i)     (((i) >> 0) & 0x1f)
+#define X_IMM(i,n)   (((i) >> 0) & ((1 << (n)) - 1))
+#define X_SIMM(i,n)  SEX (X_IMM ((i), (n)), (n))
+#define X_DISP22(i)  (((i) >> 0) & 0x3fffff)
+#define X_IMM22(i)   X_DISP22 (i)
+#define X_DISP30(i)  (((i) >> 0) & 0x3fffffff)
+
+/* These are for v9.  */
+#define X_DISP16(i)  (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
+#define X_DISP19(i)  (((i) >> 0) & 0x7ffff)
+#define X_MEMBAR(i)  ((i) & 0x7f)
+
+/* Here is the union which was used to extract instruction fields
+   before the shift and mask macros were written.
+
+   union sparc_insn
+     {
+       unsigned long int code;
+       struct
+         {
+           unsigned int anop:2;
+           #define      op      ldst.anop
+           unsigned int anrd:5;
+           #define      rd      ldst.anrd
+           unsigned int op3:6;
+           unsigned int anrs1:5;
+           #define      rs1     ldst.anrs1
+           unsigned int i:1;
+           unsigned int anasi:8;
+           #define      asi     ldst.anasi
+           unsigned int anrs2:5;
+           #define      rs2     ldst.anrs2
+           #define      shcnt   rs2
+         } ldst;
+       struct
+         {
+           unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
+           unsigned int IMM13:13;
+           #define      imm13   IMM13.IMM13
+         } IMM13;
+       struct
+         {
+           unsigned int anop:2;
+           unsigned int a:1;
+           unsigned int cond:4;
+           unsigned int op2:3;
+           unsigned int DISP22:22;
+           #define      disp22  branch.DISP22
+           #define      imm22   disp22
+         } branch;
+       struct
+         {
+           unsigned int anop:2;
+           unsigned int a:1;
+           unsigned int z:1;
+           unsigned int rcond:3;
+           unsigned int op2:3;
+           unsigned int DISP16HI:2;
+           unsigned int p:1;
+           unsigned int _rs1:5;
+           unsigned int DISP16LO:14;
+         } branch16;
+       struct
+         {
+           unsigned int anop:2;
+           unsigned int adisp30:30;
+           #define      disp30  call.adisp30
+         } call;
+     };  */
+
+/* Nonzero if INSN is the opcode for a delayed branch.  */
+
+static int
+is_delayed_branch (unsigned long insn)
+{
+  sparc_opcode_hash *op;
+
+  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
+    {
+      const sparc_opcode *opcode = op->opcode;
+
+      if ((opcode->match & insn) == opcode->match
+          && (opcode->lose & insn) == 0)
+        return opcode->flags & F_DELAYED;
+    }
+  return 0;
+}
+
+/* extern void qsort (); */
+
+/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
+   to compare_opcodes.  */
+static unsigned int current_arch_mask;
+
+/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values.  */
+
+static int
+compute_arch_mask (unsigned long mach)
+{
+  switch (mach)
+    {
+    case 0 :
+    case bfd_mach_sparc :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);
+    case bfd_mach_sparc_sparclet :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
+    case bfd_mach_sparc_sparclite :
+    case bfd_mach_sparc_sparclite_le :
+      /* sparclites insns are recognized by default (because that's how
+         they've always been treated, for better or worse).  Kludge this by
+         indicating generic v8 is also selected.  */
+      return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
+              | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
+    case bfd_mach_sparc_v8plus :
+    case bfd_mach_sparc_v9 :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
+    case bfd_mach_sparc_v8plusa :
+    case bfd_mach_sparc_v9a :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
+    case bfd_mach_sparc_v8plusb :
+    case bfd_mach_sparc_v9b :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B);
+    }
+  abort ();
+}
+
+/* Compare opcodes A and B.  */
+
+static int
+compare_opcodes (const void * a, const void * b)
+{
+  sparc_opcode *op0 = * (sparc_opcode **) a;
+  sparc_opcode *op1 = * (sparc_opcode **) b;
+  unsigned long int match0 = op0->match, match1 = op1->match;
+  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
+  register unsigned int i;
+
+  /* If one (and only one) insn isn't supported by the current architecture,
+     prefer the one that is.  If neither are supported, but they're both for
+     the same architecture, continue processing.  Otherwise (both unsupported
+     and for different architectures), prefer lower numbered arch's (fudged
+     by comparing the bitmasks).  */
+  if (op0->architecture & current_arch_mask)
+    {
+      if (! (op1->architecture & current_arch_mask))
+        return -1;
+    }
+  else
+    {
+      if (op1->architecture & current_arch_mask)
+        return 1;
+      else if (op0->architecture != op1->architecture)
+        return op0->architecture - op1->architecture;
+    }
+
+  /* If a bit is set in both match and lose, there is something
+     wrong with the opcode table.  */
+  if (match0 & lose0)
+    {
+      fprintf
+        (stderr,
+         /* xgettext:c-format */
+         _("Internal error:  bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
+         op0->name, match0, lose0);
+      op0->lose &= ~op0->match;
+      lose0 = op0->lose;
+    }
+
+  if (match1 & lose1)
+    {
+      fprintf
+        (stderr,
+         /* xgettext:c-format */
+         _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
+         op1->name, match1, lose1);
+      op1->lose &= ~op1->match;
+      lose1 = op1->lose;
+    }
+
+  /* Because the bits that are variable in one opcode are constant in
+     another, it is important to order the opcodes in the right order.  */
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (match0 & x) != 0;
+      int x1 = (match1 & x) != 0;
+
+      if (x0 != x1)
+        return x1 - x0;
+    }
+
+  for (i = 0; i < 32; ++i)
+    {
+      unsigned long int x = 1 << i;
+      int x0 = (lose0 & x) != 0;
+      int x1 = (lose1 & x) != 0;
+
+      if (x0 != x1)
+        return x1 - x0;
+    }
+
+  /* They are functionally equal.  So as long as the opcode table is
+     valid, we can put whichever one first we want, on aesthetic grounds.  */
+
+  /* Our first aesthetic ground is that aliases defer to real insns.  */
+  {
+    int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
+
+    if (alias_diff != 0)
+      /* Put the one that isn't an alias first.  */
+      return alias_diff;
+  }
+
+  /* Except for aliases, two "identical" instructions had
+     better have the same opcode.  This is a sanity check on the table.  */
+  i = strcmp (op0->name, op1->name);
+  if (i)
+    {
+      if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary.  */
+        return i;
+      else
+        fprintf (stderr,
+                 /* xgettext:c-format */
+                 _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"),
+                 op0->name, op1->name);
+    }
+
+  /* Fewer arguments are preferred.  */
+  {
+    int length_diff = strlen (op0->args) - strlen (op1->args);
+
+    if (length_diff != 0)
+      /* Put the one with fewer arguments first.  */
+      return length_diff;
+  }
+
+  /* Put 1+i before i+1.  */
+  {
+    char *p0 = (char *) strchr (op0->args, '+');
+    char *p1 = (char *) strchr (op1->args, '+');
+
+    if (p0 && p1)
+      {
+        /* There is a plus in both operands.  Note that a plus
+           sign cannot be the first character in args,
+           so the following [-1]'s are valid.  */
+        if (p0[-1] == 'i' && p1[1] == 'i')
+          /* op0 is i+1 and op1 is 1+i, so op1 goes first.  */
+          return 1;
+        if (p0[1] == 'i' && p1[-1] == 'i')
+          /* op0 is 1+i and op1 is i+1, so op0 goes first.  */
+          return -1;
+      }
+  }
+
+  /* Put 1,i before i,1.  */
+  {
+    int i0 = strncmp (op0->args, "i,1", 3) == 0;
+    int i1 = strncmp (op1->args, "i,1", 3) == 0;
+
+    if (i0 ^ i1)
+      return i0 - i1;
+  }
+
+  /* They are, as far as we can tell, identical.
+     Since qsort may have rearranged the table partially, there is
+     no way to tell which one was first in the opcode table as
+     written, so just say there are equal.  */
+  /* ??? This is no longer true now that we sort a vector of pointers,
+     not the table itself.  */
+  return 0;
+}
+
+/* Build a hash table from the opcode table.
+   OPCODE_TABLE is a sorted list of pointers into the opcode table.  */
+
+static void
+build_hash_table (const sparc_opcode **opcode_table,
+                  sparc_opcode_hash **hash_table,
+                  int num_opcodes)
+{
+  int i;
+  int hash_count[HASH_SIZE];
+  static sparc_opcode_hash *hash_buf = NULL;
+
+  /* Start at the end of the table and work backwards so that each
+     chain is sorted.  */
+
+  memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
+  memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
+  if (hash_buf != NULL)
+    free (hash_buf);
+  hash_buf = malloc (sizeof (* hash_buf) * num_opcodes);
+  for (i = num_opcodes - 1; i >= 0; --i)
+    {
+      int hash = HASH_INSN (opcode_table[i]->match);
+      sparc_opcode_hash *h = &hash_buf[i];
+
+      h->next = hash_table[hash];
+      h->opcode = opcode_table[i];
+      hash_table[hash] = h;
+      ++hash_count[hash];
+    }
+
+#if 0 /* for debugging */
+  {
+    int min_count = num_opcodes, max_count = 0;
+    int total;
+
+    for (i = 0; i < HASH_SIZE; ++i)
+      {
+        if (hash_count[i] < min_count)
+          min_count = hash_count[i];
+        if (hash_count[i] > max_count)
+          max_count = hash_count[i];
+        total += hash_count[i];
+      }
+
+    printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
+            min_count, max_count, (double) total / HASH_SIZE);
+  }
+#endif
+}
+
+/* Print one instruction from MEMADDR on INFO->STREAM.
+
+   We suffix the instruction with a comment that gives the absolute
+   address involved, as well as its symbolic form, if the instruction
+   is preceded by a findable `sethi' and it either adds an immediate
+   displacement to that register, or it is an `add' or `or' instruction
+   on that register.  */
+
+int
+print_insn_sparc (bfd_vma memaddr, disassemble_info *info)
+{
+  FILE *stream = info->stream;
+  bfd_byte buffer[4];
+  unsigned long insn;
+  sparc_opcode_hash *op;
+  /* Nonzero of opcode table has been initialized.  */
+  static int opcodes_initialized = 0;
+  /* bfd mach number of last call.  */
+  static unsigned long current_mach = 0;
+  bfd_vma (*getword) (const unsigned char *);
+
+  if (!opcodes_initialized
+      || info->mach != current_mach)
+    {
+      int i;
+
+      current_arch_mask = compute_arch_mask (info->mach);
+
+      if (!opcodes_initialized)
+        sorted_opcodes =
+          malloc (sparc_num_opcodes * sizeof (sparc_opcode *));
+      /* Reset the sorted table so we can resort it.  */
+      for (i = 0; i < sparc_num_opcodes; ++i)
+        sorted_opcodes[i] = &sparc_opcodes[i];
+      qsort ((char *) sorted_opcodes, sparc_num_opcodes,
+             sizeof (sorted_opcodes[0]), compare_opcodes);
+
+      build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
+      current_mach = info->mach;
+      opcodes_initialized = 1;
+    }
+
+  {
+    int status =
+      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
+
+    if (status != 0)
+      {
+        (*info->memory_error_func) (status, memaddr, info);
+        return -1;
+      }
+  }
+
+  /* On SPARClite variants such as DANlite (sparc86x), instructions
+     are always big-endian even when the machine is in little-endian mode.  */
+  if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
+    getword = bfd_getb32;
+  else
+    getword = bfd_getl32;
+
+  insn = getword (buffer);
+
+  info->insn_info_valid = 1;                    /* We do return this info.  */
+  info->insn_type = dis_nonbranch;              /* Assume non branch insn.  */
+  info->branch_delay_insns = 0;                 /* Assume no delay.  */
+  info->target = 0;                             /* Assume no target known.  */
+
+  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
+    {
+      const sparc_opcode *opcode = op->opcode;
+
+      /* If the insn isn't supported by the current architecture, skip it.  */
+      if (! (opcode->architecture & current_arch_mask))
+        continue;
+
+      if ((opcode->match & insn) == opcode->match
+          && (opcode->lose & insn) == 0)
+        {
+          /* Nonzero means that we have found an instruction which has
+             the effect of adding or or'ing the imm13 field to rs1.  */
+          int imm_added_to_rs1 = 0;
+          int imm_ored_to_rs1 = 0;
+
+          /* Nonzero means that we have found a plus sign in the args
+             field of the opcode table.  */
+          int found_plus = 0;
+
+          /* Nonzero means we have an annulled branch.  */
+          /* int is_annulled = 0; */ /* see FIXME below */
+
+          /* Do we have an `add' or `or' instruction combining an
+             immediate with rs1?  */
+          if (opcode->match == 0x80102000) /* or */
+            imm_ored_to_rs1 = 1;
+          if (opcode->match == 0x80002000) /* add */
+            imm_added_to_rs1 = 1;
+
+          if (X_RS1 (insn) != X_RD (insn)
+              && strchr (opcode->args, 'r') != NULL)
+              /* Can't do simple format if source and dest are different.  */
+              continue;
+          if (X_RS2 (insn) != X_RD (insn)
+              && strchr (opcode->args, 'O') != NULL)
+              /* Can't do simple format if source and dest are different.  */
+              continue;
+
+          (*info->fprintf_func) (stream, "%s", opcode->name);
+
+          {
+            const char *s;
+
+            if (opcode->args[0] != ',')
+              (*info->fprintf_func) (stream, " ");
+
+            for (s = opcode->args; *s != '\0'; ++s)
+              {
+                while (*s == ',')
+                  {
+                    (*info->fprintf_func) (stream, ",");
+                    ++s;
+                    switch (*s)
+                      {
+                      case 'a':
+                        (*info->fprintf_func) (stream, "a");
+                        /* is_annulled = 1; */ /* see FIXME below */
+                        ++s;
+                        continue;
+                      case 'N':
+                        (*info->fprintf_func) (stream, "pn");
+                        ++s;
+                        continue;
+
+                      case 'T':
+                        (*info->fprintf_func) (stream, "pt");
+                        ++s;
+                        continue;
+
+                      default:
+                        break;
+                      }
+                  }
+
+                (*info->fprintf_func) (stream, " ");
+
+                switch (*s)
+                  {
+                  case '+':
+                    found_plus = 1;
+                    /* Fall through.  */
+
+                  default:
+                    (*info->fprintf_func) (stream, "%c", *s);
+                    break;
+
+                  case '#':
+                    (*info->fprintf_func) (stream, "0");
+                    break;
+
+#define reg(n)  (*info->fprintf_func) (stream, "%%%s", reg_names[n])
+                  case '1':
+                  case 'r':
+                    reg (X_RS1 (insn));
+                    break;
+
+                  case '2':
+                  case 'O':
+                    reg (X_RS2 (insn));
+                    break;
+
+                  case 'd':
+                    reg (X_RD (insn));
+                    break;
+#undef  reg
+
+#define freg(n)         (*info->fprintf_func) (stream, "%%%s", freg_names[n])
+#define fregx(n)        (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
+                  case 'e':
+                    freg (X_RS1 (insn));
+                    break;
+                  case 'v':     /* Double/even.  */
+                  case 'V':     /* Quad/multiple of 4.  */
+                    fregx (X_RS1 (insn));
+                    break;
+
+                  case 'f':
+                    freg (X_RS2 (insn));
+                    break;
+                  case 'B':     /* Double/even.  */
+                  case 'R':     /* Quad/multiple of 4.  */
+                    fregx (X_RS2 (insn));
+                    break;
+
+                  case 'g':
+                    freg (X_RD (insn));
+                    break;
+                  case 'H':     /* Double/even.  */
+                  case 'J':     /* Quad/multiple of 4.  */
+                    fregx (X_RD (insn));
+                    break;
+#undef  freg
+#undef  fregx
+
+#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
+                  case 'b':
+                    creg (X_RS1 (insn));
+                    break;
+
+                  case 'c':
+                    creg (X_RS2 (insn));
+                    break;
+
+                  case 'D':
+                    creg (X_RD (insn));
+                    break;
+#undef  creg
+
+                  case 'h':
+                    (*info->fprintf_func) (stream, "%%hi(%#x)",
+                                           ((unsigned) 0xFFFFFFFF
+                                            & ((int) X_IMM22 (insn) << 10)));
+                    break;
+
+                  case 'i':     /* 13 bit immediate.  */
+                  case 'I':     /* 11 bit immediate.  */
+                  case 'j':     /* 10 bit immediate.  */
+                    {
+                      int imm;
+
+                      if (*s == 'i')
+                        imm = X_SIMM (insn, 13);
+                      else if (*s == 'I')
+                        imm = X_SIMM (insn, 11);
+                      else
+                        imm = X_SIMM (insn, 10);
+
+                      /* Check to see whether we have a 1+i, and take
+                         note of that fact.
+
+                         Note: because of the way we sort the table,
+                         we will be matching 1+i rather than i+1,
+                         so it is OK to assume that i is after +,
+                         not before it.  */
+                      if (found_plus)
+                        imm_added_to_rs1 = 1;
+
+                      if (imm <= 9)
+                        (*info->fprintf_func) (stream, "%d", imm);
+                      else
+                        (*info->fprintf_func) (stream, "%#x", imm);
+                    }
+                    break;
+
+                  case 'X':     /* 5 bit unsigned immediate.  */
+                  case 'Y':     /* 6 bit unsigned immediate.  */
+                    {
+                      int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
+
+                      if (imm <= 9)
+                        (info->fprintf_func) (stream, "%d", imm);
+                      else
+                        (info->fprintf_func) (stream, "%#x", (unsigned) imm);
+                    }
+                    break;
+
+                  case '3':
+                    (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3));
+                    break;
+
+                  case 'K':
+                    {
+                      int mask = X_MEMBAR (insn);
+                      int bit = 0x40, printed_one = 0;
+                      const char *name;
+
+                      if (mask == 0)
+                        (info->fprintf_func) (stream, "0");
+                      else
+                        while (bit)
+                          {
+                            if (mask & bit)
+                              {
+                                if (printed_one)
+                                  (info->fprintf_func) (stream, "|");
+                                name = sparc_decode_membar (bit);
+                                (info->fprintf_func) (stream, "%s", name);
+                                printed_one = 1;
+                              }
+                            bit >>= 1;
+                          }
+                      break;
+                    }
+
+                  case 'k':
+                    info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
+                    (*info->print_address_func) (info->target, info);
+                    break;
+
+                  case 'G':
+                    info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
+                    (*info->print_address_func) (info->target, info);
+                    break;
+
+                  case '6':
+                  case '7':
+                  case '8':
+                  case '9':
+                    (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
+                    break;
+
+                  case 'z':
+                    (*info->fprintf_func) (stream, "%%icc");
+                    break;
+
+                  case 'Z':
+                    (*info->fprintf_func) (stream, "%%xcc");
+                    break;
+
+                  case 'E':
+                    (*info->fprintf_func) (stream, "%%ccr");
+                    break;
+
+                  case 's':
+                    (*info->fprintf_func) (stream, "%%fprs");
+                    break;
+
+                  case 'o':
+                    (*info->fprintf_func) (stream, "%%asi");
+                    break;
+
+                  case 'W':
+                    (*info->fprintf_func) (stream, "%%tick");
+                    break;
+
+                  case 'P':
+                    (*info->fprintf_func) (stream, "%%pc");
+                    break;
+
+                  case '?':
+                    if (X_RS1 (insn) == 31)
+                      (*info->fprintf_func) (stream, "%%ver");
+                    else if ((unsigned) X_RS1 (insn) < 17)
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9_priv_reg_names[X_RS1 (insn)]);
+                    else
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    break;
+
+                  case '!':
+                    if ((unsigned) X_RD (insn) < 17)
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9_priv_reg_names[X_RD (insn)]);
+                    else
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    break;
+
+                  case '$':
+                    if ((unsigned) X_RS1 (insn) < 32)
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9_hpriv_reg_names[X_RS1 (insn)]);
+                    else
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    break;
+
+                  case '%':
+                    if ((unsigned) X_RD (insn) < 32)
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9_hpriv_reg_names[X_RD (insn)]);
+                    else
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    break;
+
+                  case '/':
+                    if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25)
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    else
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9a_asr_reg_names[X_RS1 (insn)-16]);
+                    break;
+
+                  case '_':
+                    if (X_RD (insn) < 16 || X_RD (insn) > 25)
+                      (*info->fprintf_func) (stream, "%%reserved");
+                    else
+                      (*info->fprintf_func) (stream, "%%%s",
+                                             v9a_asr_reg_names[X_RD (insn)-16]);
+                    break;
+
+                  case '*':
+                    {
+                      const char *name = sparc_decode_prefetch (X_RD (insn));
+
+                      if (name)
+                        (*info->fprintf_func) (stream, "%s", name);
+                      else
+                        (*info->fprintf_func) (stream, "%ld", X_RD (insn));
+                      break;
+                    }
+
+                  case 'M':
+                    (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn));
+                    break;
+
+                  case 'm':
+                    (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn));
+                    break;
+
+                  case 'L':
+                    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
+                    (*info->print_address_func) (info->target, info);
+                    break;
+
+                  case 'n':
+                    (*info->fprintf_func)
+                      (stream, "%#x", SEX (X_DISP22 (insn), 22));
+                    break;
+
+                  case 'l':
+                    info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
+                    (*info->print_address_func) (info->target, info);
+                    break;
+
+                  case 'A':
+                    {
+                      const char *name;
+
+                      if ((info->mach == bfd_mach_sparc_v8plusa) ||
+                          ((info->mach >= bfd_mach_sparc_v9) &&
+                           (info->mach <= bfd_mach_sparc_v9b)))
+                        name = sparc_decode_asi_v9 (X_ASI (insn));
+                      else
+                        name = sparc_decode_asi_v8 (X_ASI (insn));
+
+                      if (name)
+                        (*info->fprintf_func) (stream, "%s", name);
+                      else
+                        (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn));
+                      break;
+                    }
+
+                  case 'C':
+                    (*info->fprintf_func) (stream, "%%csr");
+                    break;
+
+                  case 'F':
+                    (*info->fprintf_func) (stream, "%%fsr");
+                    break;
+
+                  case 'p':
+                    (*info->fprintf_func) (stream, "%%psr");
+                    break;
+
+                  case 'q':
+                    (*info->fprintf_func) (stream, "%%fq");
+                    break;
+
+                  case 'Q':
+                    (*info->fprintf_func) (stream, "%%cq");
+                    break;
+
+                  case 't':
+                    (*info->fprintf_func) (stream, "%%tbr");
+                    break;
+
+                  case 'w':
+                    (*info->fprintf_func) (stream, "%%wim");
+                    break;
+
+                  case 'x':
+                    (*info->fprintf_func) (stream, "%ld",
+                                           ((X_LDST_I (insn) << 8)
+                                            + X_ASI (insn)));
+                    break;
+
+                  case 'y':
+                    (*info->fprintf_func) (stream, "%%y");
+                    break;
+
+                  case 'u':
+                  case 'U':
+                    {
+                      int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
+                      const char *name = sparc_decode_sparclet_cpreg (val);
+
+                      if (name)
+                        (*info->fprintf_func) (stream, "%s", name);
+                      else
+                        (*info->fprintf_func) (stream, "%%cpreg(%d)", val);
+                      break;
+                    }
+                  }
+              }
+          }
+
+          /* If we are adding or or'ing something to rs1, then
+             check to see whether the previous instruction was
+             a sethi to the same register as in the sethi.
+             If so, attempt to print the result of the add or
+             or (in this context add and or do the same thing)
+             and its symbolic value.  */
+          if (imm_ored_to_rs1 || imm_added_to_rs1)
+            {
+              unsigned long prev_insn;
+              int errcode;
+
+              if (memaddr >= 4)
+                errcode =
+                  (*info->read_memory_func)
+                  (memaddr - 4, buffer, sizeof (buffer), info);
+              else
+                errcode = 1;
+
+              prev_insn = getword (buffer);
+
+              if (errcode == 0)
+                {
+                  /* If it is a delayed branch, we need to look at the
+                     instruction before the delayed branch.  This handles
+                     sequences such as:
+
+                     sethi %o1, %hi(_foo), %o1
+                     call _printf
+                     or %o1, %lo(_foo), %o1  */
+
+                  if (is_delayed_branch (prev_insn))
+                    {
+                      if (memaddr >= 8)
+                        errcode = (*info->read_memory_func)
+                          (memaddr - 8, buffer, sizeof (buffer), info);
+                      else
+                        errcode = 1;
+
+                      prev_insn = getword (buffer);
+                    }
+                }
+
+              /* If there was a problem reading memory, then assume
+                 the previous instruction was not sethi.  */
+              if (errcode == 0)
+                {
+                  /* Is it sethi to the same register?  */
+                  if ((prev_insn & 0xc1c00000) == 0x01000000
+                      && X_RD (prev_insn) == X_RS1 (insn))
+                    {
+                      (*info->fprintf_func) (stream, "\t! ");
+                      info->target =
+                        ((unsigned) 0xFFFFFFFF
+                         & ((int) X_IMM22 (prev_insn) << 10));
+                      if (imm_added_to_rs1)
+                        info->target += X_SIMM (insn, 13);
+                      else
+                        info->target |= X_SIMM (insn, 13);
+                      (*info->print_address_func) (info->target, info);
+                      info->insn_type = dis_dref;
+                      info->data_size = 4;  /* FIXME!!! */
+                    }
+                }
+            }
+
+          if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
+            {
+                /* FIXME -- check is_annulled flag.  */
+              if (opcode->flags & F_UNBR)
+                info->insn_type = dis_branch;
+              if (opcode->flags & F_CONDBR)
+                info->insn_type = dis_condbranch;
+              if (opcode->flags & F_JSR)
+                info->insn_type = dis_jsr;
+              if (opcode->flags & F_DELAYED)
+                info->branch_delay_insns = 1;
+            }
+
+          return sizeof (buffer);
+        }
+    }
+
+  info->insn_type = dis_noninsn;        /* Mark as non-valid instruction.  */
+  (*info->fprintf_func) (stream, _("unknown"));
+  return sizeof (buffer);
+}
diff --git a/qemu-0.15.x/sparc.ld b/qemu-0.15.x/sparc.ld
new file mode 100644
index 0000000..56efe34
--- /dev/null
+++ b/qemu-0.15.x/sparc.ld
@@ -0,0 +1,150 @@
+OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
+              "elf32-sparc")
+OUTPUT_ARCH(sparc)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp)    }
+  .hash          : { *(.hash)           }
+  .dynsym        : { *(.dynsym)         }
+  .dynstr        : { *(.dynstr)         }
+  .gnu.version   : { *(.gnu.version)    }
+  .gnu.version_d   : { *(.gnu.version_d)        }
+  .gnu.version_r   : { *(.gnu.version_r)        }
+  .rel.text      :
+    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+  .rela.text     :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rel.data      :
+    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+  .rela.data     :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rel.rodata    :
+    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+  .rela.rodata   :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rel.got       : { *(.rel.got)                }
+  .rela.got      : { *(.rela.got)               }
+  .rel.ctors     : { *(.rel.ctors)      }
+  .rela.ctors    : { *(.rela.ctors)     }
+  .rel.dtors     : { *(.rel.dtors)      }
+  .rela.dtors    : { *(.rela.dtors)     }
+  .rel.init      : { *(.rel.init)       }
+  .rela.init     : { *(.rela.init)      }
+  .rel.fini      : { *(.rel.fini)       }
+  .rela.fini     : { *(.rela.fini)      }
+  .rel.bss       : { *(.rel.bss)                }
+  .rela.bss      : { *(.rela.bss)               }
+  .rel.plt       : { *(.rel.plt)                }
+  .rela.plt      : { *(.rela.plt)               }
+  .init          : { *(.init)   } =0x47ff041f
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  } =0x47ff041f
+  _etext = .;
+  PROVIDE (etext = .);
+  .fini      : { *(.fini)    } =0x47ff041f
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x100000) + (. & (0x100000 - 1));
+  .data    :
+  {
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .tdata    : { *(.tdata) }
+  .tbss    : { *(.tbss) }
+  .preinit_array     :
+  {
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+  }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+  .plt      : { *(.plt) }
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+  /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) }
+}
diff --git a/qemu-0.15.x/sparc64.ld b/qemu-0.15.x/sparc64.ld
new file mode 100644
index 0000000..9ea4143
--- /dev/null
+++ b/qemu-0.15.x/sparc64.ld
@@ -0,0 +1,138 @@
+OUTPUT_FORMAT("elf64-sparc", "elf64-sparc",
+              "elf64-sparc")
+OUTPUT_ARCH(sparc:v9)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp     : { *(.interp)    }
+  .hash          : { *(.hash)           }
+  .dynsym        : { *(.dynsym)         }
+  .dynstr        : { *(.dynstr)         }
+  .gnu.version   : { *(.gnu.version)    }
+  .gnu.version_d   : { *(.gnu.version_d)        }
+  .gnu.version_r   : { *(.gnu.version_r)        }
+  .rel.text      :
+    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+  .rela.text     :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rel.data      :
+    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+  .rela.data     :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rel.rodata    :
+    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+  .rela.rodata   :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rel.got       : { *(.rel.got)                }
+  .rela.got      : { *(.rela.got)               }
+  .rel.ctors     : { *(.rel.ctors)      }
+  .rela.ctors    : { *(.rela.ctors)     }
+  .rel.dtors     : { *(.rel.dtors)      }
+  .rela.dtors    : { *(.rela.dtors)     }
+  .rel.init      : { *(.rel.init)       }
+  .rela.init     : { *(.rela.init)      }
+  .rel.fini      : { *(.rel.fini)       }
+  .rela.fini     : { *(.rela.fini)      }
+  .rel.bss       : { *(.rel.bss)                }
+  .rela.bss      : { *(.rela.bss)               }
+  .rel.plt       : { *(.rel.plt)                }
+  .rela.plt      : { *(.rela.plt)               }
+  .init          : { *(.init)   } =0x47ff041f
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  } =0x47ff041f
+  _etext = .;
+  PROVIDE (etext = .);
+  .fini      : { *(.fini)    } =0x47ff041f
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  . = ALIGN(64 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .reginfo : { *(.reginfo) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(0x100000) + (. & (0x100000 - 1));
+  .data    :
+  {
+    *(.gen_code)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+  .plt      : { *(.plt) }
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff --git a/qemu-0.15.x/spice-qemu-char.c b/qemu-0.15.x/spice-qemu-char.c
new file mode 100644
index 0000000..95bf6b6
--- /dev/null
+++ b/qemu-0.15.x/spice-qemu-char.c
@@ -0,0 +1,204 @@
+#include "config-host.h"
+#include "trace.h"
+#include "ui/qemu-spice.h"
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "osdep.h"
+
+#define dprintf(_scd, _level, _fmt, ...)                                \
+    do {                                                                \
+        static unsigned __dprintf_counter = 0;                          \
+        if (_scd->debug >= _level) {                                    \
+            fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
+        }                                                               \
+    } while (0)
+
+#define VMC_MAX_HOST_WRITE    2048
+
+typedef struct SpiceCharDriver {
+    CharDriverState*      chr;
+    SpiceCharDeviceInstance     sin;
+    char                  *subtype;
+    bool                  active;
+    uint8_t               *buffer;
+    uint8_t               *datapos;
+    ssize_t               bufsize, datalen;
+    uint32_t              debug;
+} SpiceCharDriver;
+
+static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
+{
+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    ssize_t out = 0;
+    ssize_t last_out;
+    uint8_t* p = (uint8_t*)buf;
+
+    while (len > 0) {
+        last_out = MIN(len, VMC_MAX_HOST_WRITE);
+        if (qemu_chr_can_read(scd->chr) < last_out) {
+            break;
+        }
+        qemu_chr_read(scd->chr, p, last_out);
+        out += last_out;
+        len -= last_out;
+        p += last_out;
+    }
+
+    dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+    trace_spice_vmc_write(out, len + out);
+    return out;
+}
+
+static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+{
+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+    int bytes = MIN(len, scd->datalen);
+
+    dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
+    if (bytes > 0) {
+        memcpy(buf, scd->datapos, bytes);
+        scd->datapos += bytes;
+        scd->datalen -= bytes;
+        assert(scd->datalen >= 0);
+        if (scd->datalen == 0) {
+            scd->datapos = 0;
+        }
+    }
+    trace_spice_vmc_read(bytes, len);
+    return bytes;
+}
+
+static SpiceCharDeviceInterface vmc_interface = {
+    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
+    .base.description   = "spice virtual channel char device",
+    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+    .write              = vmc_write,
+    .read               = vmc_read,
+};
+
+
+static void vmc_register_interface(SpiceCharDriver *scd)
+{
+    if (scd->active) {
+        return;
+    }
+    dprintf(scd, 1, "%s\n", __func__);
+    scd->sin.base.sif = &vmc_interface.base;
+    qemu_spice_add_interface(&scd->sin.base);
+    scd->active = true;
+    trace_spice_vmc_register_interface(scd);
+}
+
+static void vmc_unregister_interface(SpiceCharDriver *scd)
+{
+    if (!scd->active) {
+        return;
+    }
+    dprintf(scd, 1, "%s\n", __func__);
+    spice_server_remove_interface(&scd->sin.base);
+    scd->active = false;
+    trace_spice_vmc_unregister_interface(scd);
+}
+
+
+static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    SpiceCharDriver *s = chr->opaque;
+
+    dprintf(s, 2, "%s: %d\n", __func__, len);
+    vmc_register_interface(s);
+    assert(s->datalen == 0);
+    if (s->bufsize < len) {
+        s->bufsize = len;
+        s->buffer = qemu_realloc(s->buffer, s->bufsize);
+    }
+    memcpy(s->buffer, buf, len);
+    s->datapos = s->buffer;
+    s->datalen = len;
+    spice_server_char_device_wakeup(&s->sin);
+    return len;
+}
+
+static void spice_chr_close(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+
+    printf("%s\n", __func__);
+    vmc_unregister_interface(s);
+    qemu_free(s);
+}
+
+static void spice_chr_guest_open(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+    vmc_register_interface(s);
+}
+
+static void spice_chr_guest_close(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+    vmc_unregister_interface(s);
+}
+
+static void print_allowed_subtypes(void)
+{
+    const char** psubtype;
+    int i;
+
+    fprintf(stderr, "allowed names: ");
+    for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
+        *psubtype != NULL; ++psubtype, ++i) {
+        if (i == 0) {
+            fprintf(stderr, "%s", *psubtype);
+        } else {
+            fprintf(stderr, ", %s", *psubtype);
+        }
+    }
+    fprintf(stderr, "\n");
+}
+
+int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
+{
+    CharDriverState *chr;
+    SpiceCharDriver *s;
+    const char* name = qemu_opt_get(opts, "name");
+    uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
+    const char** psubtype = spice_server_char_device_recognized_subtypes();
+    const char *subtype = NULL;
+
+    if (name == NULL) {
+        fprintf(stderr, "spice-qemu-char: missing name parameter\n");
+        print_allowed_subtypes();
+        return -EINVAL;
+    }
+    for(;*psubtype != NULL; ++psubtype) {
+        if (strcmp(name, *psubtype) == 0) {
+            subtype = *psubtype;
+            break;
+        }
+    }
+    if (subtype == NULL) {
+        fprintf(stderr, "spice-qemu-char: unsupported name\n");
+        print_allowed_subtypes();
+        return -EINVAL;
+    }
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(SpiceCharDriver));
+    s->chr = chr;
+    s->debug = debug;
+    s->active = false;
+    s->sin.subtype = subtype;
+    chr->opaque = s;
+    chr->chr_write = spice_chr_write;
+    chr->chr_close = spice_chr_close;
+    chr->chr_guest_open = spice_chr_guest_open;
+    chr->chr_guest_close = spice_chr_guest_close;
+
+    qemu_chr_generic_open(chr);
+
+    *_chr = chr;
+    return 0;
+}
diff --git a/qemu-0.15.x/sysconfigs/target/target-x86_64.conf b/qemu-0.15.x/sysconfigs/target/target-x86_64.conf
new file mode 100644
index 0000000..43ad282
--- /dev/null
+++ b/qemu-0.15.x/sysconfigs/target/target-x86_64.conf
@@ -0,0 +1,86 @@
+# x86 CPU MODELS
+
+[cpudef]
+   name = "Conroe"
+   level = "2"
+   vendor = "GenuineIntel"
+   family = "6"
+   model = "2"
+   stepping = "3"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3 ssse3"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)"
+
+[cpudef]
+   name = "Penryn"
+   level = "2"
+   vendor = "GenuineIntel"
+   family = "6"
+   model = "2"
+   stepping = "3"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3 cx16 ssse3 sse4.1"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)"
+
+[cpudef]
+   name = "Nehalem"
+   level = "2"
+   vendor = "GenuineIntel"
+   family = "6"
+   model = "2"
+   stepping = "3"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3 cx16 ssse3 sse4.1 sse4.2 popcnt"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+   extfeature_ecx = "lahf_lm"
+   xlevel = "0x8000000A"
+   model_id = "Intel Core i7 9xx (Nehalem Class Core i7)"
+
+[cpudef]
+   name = "Opteron_G1"
+   level = "5"
+   vendor = "AuthenticAMD"
+   family = "15"
+   model = "6"
+   stepping = "1"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx"
+#   extfeature_ecx = ""
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 240 (Gen 1 Class Opteron)"
+
+[cpudef]
+   name = "Opteron_G2"
+   level = "5"
+   vendor = "AuthenticAMD"
+   family = "15"
+   model = "6"
+   stepping = "1"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3 cx16"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx rdtscp"
+   extfeature_ecx = "svm lahf_lm"
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)"
+
+[cpudef]
+   name = "Opteron_G3"
+   level = "5"
+   vendor = "AuthenticAMD"
+   family = "15"
+   model = "6"
+   stepping = "1"
+   feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu    mtrr clflush mca pse36"
+   feature_ecx = "sse3 cx16 monitor popcnt"
+   extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu    lm syscall nx rdtscp"
+   extfeature_ecx = "svm sse4a  abm misalignsse lahf_lm"
+   xlevel = "0x80000008"
+   model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)"
+
diff --git a/qemu-0.15.x/sysemu.h b/qemu-0.15.x/sysemu.h
new file mode 100644
index 0000000..d3013f5
--- /dev/null
+++ b/qemu-0.15.x/sysemu.h
@@ -0,0 +1,178 @@
+#ifndef SYSEMU_H
+#define SYSEMU_H
+/* Misc. things related to the system emulator.  */
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+#include "qemu-queue.h"
+#include "qemu-timer.h"
+#include "notify.h"
+
+/* vl.c */
+extern const char *bios_name;
+
+extern int vm_running;
+extern const char *qemu_name;
+extern uint8_t qemu_uuid[];
+int qemu_uuid_parse(const char *str, uint8_t *uuid);
+#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+
+typedef struct vm_change_state_entry VMChangeStateEntry;
+typedef void VMChangeStateHandler(void *opaque, int running, int reason);
+
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque);
+void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
+
+#define VMSTOP_USER      0
+#define VMSTOP_DEBUG     1
+#define VMSTOP_SHUTDOWN  2
+#define VMSTOP_DISKFULL  3
+#define VMSTOP_WATCHDOG  4
+#define VMSTOP_PANIC     5
+#define VMSTOP_SAVEVM    6
+#define VMSTOP_LOADVM    7
+#define VMSTOP_MIGRATE   8
+
+#define VMRESET_SILENT   false
+#define VMRESET_REPORT   true
+
+void vm_start(void);
+void vm_stop(int reason);
+
+void qemu_system_reset_request(void);
+void qemu_system_shutdown_request(void);
+void qemu_system_powerdown_request(void);
+void qemu_system_debug_request(void);
+void qemu_system_vmstop_request(int reason);
+int qemu_shutdown_requested_get(void);
+int qemu_reset_requested_get(void);
+int qemu_shutdown_requested(void);
+int qemu_reset_requested(void);
+int qemu_powerdown_requested(void);
+void qemu_system_killed(int signal, pid_t pid);
+void qemu_kill_report(void);
+extern qemu_irq qemu_system_powerdown;
+void qemu_system_reset(bool report);
+
+void qemu_add_exit_notifier(Notifier *notify);
+void qemu_remove_exit_notifier(Notifier *notify);
+
+void qemu_add_machine_init_done_notifier(Notifier *notify);
+
+void do_savevm(Monitor *mon, const QDict *qdict);
+int load_vmstate(const char *name);
+void do_delvm(Monitor *mon, const QDict *qdict);
+void do_info_snapshots(Monitor *mon);
+
+void qemu_announce_self(void);
+
+void main_loop_wait(int nonblocking);
+
+bool qemu_savevm_state_blocked(Monitor *mon);
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
+                            int shared);
+int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f);
+int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f);
+void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f);
+int qemu_loadvm_state(QEMUFile *f);
+
+/* SLIRP */
+void do_info_slirp(Monitor *mon);
+
+typedef enum DisplayType
+{
+    DT_DEFAULT,
+    DT_CURSES,
+    DT_SDL,
+    DT_NOGRAPHIC,
+    DT_NONE,
+} DisplayType;
+
+extern int autostart;
+extern int bios_size;
+
+typedef enum {
+    VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
+} VGAInterfaceType;
+
+extern int vga_interface_type;
+#define cirrus_vga_enabled (vga_interface_type == VGA_CIRRUS)
+#define std_vga_enabled (vga_interface_type == VGA_STD)
+#define xenfb_enabled (vga_interface_type == VGA_XENFB)
+#define vmsvga_enabled (vga_interface_type == VGA_VMWARE)
+#define qxl_enabled (vga_interface_type == VGA_QXL)
+
+extern int graphic_width;
+extern int graphic_height;
+extern int graphic_depth;
+extern uint8_t irq0override;
+extern DisplayType display_type;
+extern const char *keyboard_layout;
+extern int win2k_install_hack;
+extern int rtc_td_hack;
+extern int alt_grab;
+extern int ctrl_grab;
+extern int usb_enabled;
+extern int smp_cpus;
+extern int max_cpus;
+extern int cursor_hide;
+extern int graphic_rotate;
+extern int no_quit;
+extern int no_shutdown;
+extern int semihosting_enabled;
+extern int old_param;
+extern int boot_menu;
+extern QEMUClock *rtc_clock;
+
+#define MAX_NODES 64
+extern int nb_numa_nodes;
+extern uint64_t node_mem[MAX_NODES];
+extern uint64_t node_cpumask[MAX_NODES];
+
+#define MAX_OPTION_ROMS 16
+typedef struct QEMUOptionRom {
+    const char *name;
+    int32_t bootindex;
+} QEMUOptionRom;
+extern QEMUOptionRom option_rom[MAX_OPTION_ROMS];
+extern int nb_option_roms;
+
+#define MAX_PROM_ENVS 128
+extern const char *prom_envs[MAX_PROM_ENVS];
+extern unsigned int nb_prom_envs;
+
+/* pci-hotplug */
+void pci_device_hot_add(Monitor *mon, const QDict *qdict);
+void drive_hot_add(Monitor *mon, const QDict *qdict);
+void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict);
+
+/* pcie aer error injection */
+void pcie_aer_inject_error_print(Monitor *mon, const QObject *data);
+int do_pcie_aer_inejct_error(Monitor *mon,
+                             const QDict *qdict, QObject **ret_data);
+
+/* serial ports */
+
+#define MAX_SERIAL_PORTS 4
+
+extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+
+/* parallel ports */
+
+#define MAX_PARALLEL_PORTS 3
+
+extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+
+void do_usb_add(Monitor *mon, const QDict *qdict);
+void do_usb_del(Monitor *mon, const QDict *qdict);
+void usb_info(Monitor *mon);
+
+void rtc_change_mon_event(struct tm *tm);
+
+void register_devices(void);
+
+void add_boot_device_path(int32_t bootindex, DeviceState *dev,
+                          const char *suffix);
+char *get_boot_devices_list(uint32_t *size);
+#endif
diff --git a/qemu-0.15.x/target-alpha/STATUS b/qemu-0.15.x/target-alpha/STATUS
new file mode 100644
index 0000000..353d543
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/STATUS
@@ -0,0 +1,28 @@
+(to be completed)
+
+Alpha emulation structure:
+cpu.h           : CPU definitions globally exported
+exec.h          : CPU definitions used only for translated code execution
+helper.c        : helpers that can be called either by the translated code
+                  or the Qemu core, including the exception handler.
+op_helper.c     : helpers that can be called only from TCG
+helper.h        : TCG helpers prototypes
+translate.c     : Alpha instructions to micro-operations translator
+
+Code translator status:
+The Alpha CPU instruction emulation should be quite complete with the
+limitation that the VAX floating-point load and stores are not tested.
+The 4 MMU modes are implemented.
+
+Linux user mode emulation status:
+a few programs start to run. Most crash at a certain point, dereferencing a
+NULL pointer. It seems that the UNIQUE register is not initialized properly.
+It may appear that old executables, not relying on TLS support, run but
+this is to be prooved...
+
+Full system emulation status:
+* Alpha PALCode emulation is in a very early stage and is not sufficient
+  to run any real OS. The alpha-softmmu target is not enabled for now.
+* no hardware platform description is implemented
+* there might be problems in the Alpha PALCode dedicated instructions
+  that would prevent to use a native PALCode image.
diff --git a/qemu-0.15.x/target-alpha/cpu.h b/qemu-0.15.x/target-alpha/cpu.h
new file mode 100644
index 0000000..919be12
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/cpu.h
@@ -0,0 +1,516 @@
+/*
+ *  Alpha emulation cpu definitions for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__CPU_ALPHA_H__)
+#define __CPU_ALPHA_H__
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#define CPUState struct CPUAlphaState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE     EM_ALPHA
+
+#define ICACHE_LINE_SIZE 32
+#define DCACHE_LINE_SIZE 32
+
+#define TARGET_PAGE_BITS 13
+
+/* ??? EV4 has 34 phys addr bits, EV5 has 40, EV6 has 44.  */
+#define TARGET_PHYS_ADDR_SPACE_BITS	44
+#define TARGET_VIRT_ADDR_SPACE_BITS	(30 + TARGET_PAGE_BITS)
+
+/* Alpha major type */
+enum {
+    ALPHA_EV3  = 1,
+    ALPHA_EV4  = 2,
+    ALPHA_SIM  = 3,
+    ALPHA_LCA  = 4,
+    ALPHA_EV5  = 5, /* 21164 */
+    ALPHA_EV45 = 6, /* 21064A */
+    ALPHA_EV56 = 7, /* 21164A */
+};
+
+/* EV4 minor type */
+enum {
+    ALPHA_EV4_2 = 0,
+    ALPHA_EV4_3 = 1,
+};
+
+/* LCA minor type */
+enum {
+    ALPHA_LCA_1 = 1, /* 21066 */
+    ALPHA_LCA_2 = 2, /* 20166 */
+    ALPHA_LCA_3 = 3, /* 21068 */
+    ALPHA_LCA_4 = 4, /* 21068 */
+    ALPHA_LCA_5 = 5, /* 21066A */
+    ALPHA_LCA_6 = 6, /* 21068A */
+};
+
+/* EV5 minor type */
+enum {
+    ALPHA_EV5_1 = 1, /* Rev BA, CA */
+    ALPHA_EV5_2 = 2, /* Rev DA, EA */
+    ALPHA_EV5_3 = 3, /* Pass 3 */
+    ALPHA_EV5_4 = 4, /* Pass 3.2 */
+    ALPHA_EV5_5 = 5, /* Pass 4 */
+};
+
+/* EV45 minor type */
+enum {
+    ALPHA_EV45_1 = 1, /* Pass 1 */
+    ALPHA_EV45_2 = 2, /* Pass 1.1 */
+    ALPHA_EV45_3 = 3, /* Pass 2 */
+};
+
+/* EV56 minor type */
+enum {
+    ALPHA_EV56_1 = 1, /* Pass 1 */
+    ALPHA_EV56_2 = 2, /* Pass 2 */
+};
+
+enum {
+    IMPLVER_2106x = 0, /* EV4, EV45 & LCA45 */
+    IMPLVER_21164 = 1, /* EV5, EV56 & PCA45 */
+    IMPLVER_21264 = 2, /* EV6, EV67 & EV68x */
+    IMPLVER_21364 = 3, /* EV7 & EV79 */
+};
+
+enum {
+    AMASK_BWX      = 0x00000001,
+    AMASK_FIX      = 0x00000002,
+    AMASK_CIX      = 0x00000004,
+    AMASK_MVI      = 0x00000100,
+    AMASK_TRAP     = 0x00000200,
+    AMASK_PREFETCH = 0x00001000,
+};
+
+enum {
+    VAX_ROUND_NORMAL = 0,
+    VAX_ROUND_CHOPPED,
+};
+
+enum {
+    IEEE_ROUND_NORMAL = 0,
+    IEEE_ROUND_DYNAMIC,
+    IEEE_ROUND_PLUS,
+    IEEE_ROUND_MINUS,
+    IEEE_ROUND_CHOPPED,
+};
+
+/* IEEE floating-point operations encoding */
+/* Trap mode */
+enum {
+    FP_TRAP_I   = 0x0,
+    FP_TRAP_U   = 0x1,
+    FP_TRAP_S  = 0x4,
+    FP_TRAP_SU  = 0x5,
+    FP_TRAP_SUI = 0x7,
+};
+
+/* Rounding mode */
+enum {
+    FP_ROUND_CHOPPED = 0x0,
+    FP_ROUND_MINUS   = 0x1,
+    FP_ROUND_NORMAL  = 0x2,
+    FP_ROUND_DYNAMIC = 0x3,
+};
+
+/* FPCR bits */
+#define FPCR_SUM		(1ULL << 63)
+#define FPCR_INED		(1ULL << 62)
+#define FPCR_UNFD		(1ULL << 61)
+#define FPCR_UNDZ		(1ULL << 60)
+#define FPCR_DYN_SHIFT		58
+#define FPCR_DYN_CHOPPED	(0ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_MINUS		(1ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_NORMAL		(2ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_PLUS		(3ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_MASK		(3ULL << FPCR_DYN_SHIFT)
+#define FPCR_IOV		(1ULL << 57)
+#define FPCR_INE		(1ULL << 56)
+#define FPCR_UNF		(1ULL << 55)
+#define FPCR_OVF		(1ULL << 54)
+#define FPCR_DZE		(1ULL << 53)
+#define FPCR_INV		(1ULL << 52)
+#define FPCR_OVFD		(1ULL << 51)
+#define FPCR_DZED		(1ULL << 50)
+#define FPCR_INVD		(1ULL << 49)
+#define FPCR_DNZ		(1ULL << 48)
+#define FPCR_DNOD		(1ULL << 47)
+#define FPCR_STATUS_MASK	(FPCR_IOV | FPCR_INE | FPCR_UNF \
+				 | FPCR_OVF | FPCR_DZE | FPCR_INV)
+
+/* The silly software trap enables implemented by the kernel emulation.
+   These are more or less architecturally required, since the real hardware
+   has read-as-zero bits in the FPCR when the features aren't implemented.
+   For the purposes of QEMU, we pretend the FPCR can hold everything.  */
+#define SWCR_TRAP_ENABLE_INV	(1ULL << 1)
+#define SWCR_TRAP_ENABLE_DZE	(1ULL << 2)
+#define SWCR_TRAP_ENABLE_OVF	(1ULL << 3)
+#define SWCR_TRAP_ENABLE_UNF	(1ULL << 4)
+#define SWCR_TRAP_ENABLE_INE	(1ULL << 5)
+#define SWCR_TRAP_ENABLE_DNO	(1ULL << 6)
+#define SWCR_TRAP_ENABLE_MASK	((1ULL << 7) - (1ULL << 1))
+
+#define SWCR_MAP_DMZ		(1ULL << 12)
+#define SWCR_MAP_UMZ		(1ULL << 13)
+#define SWCR_MAP_MASK		(SWCR_MAP_DMZ | SWCR_MAP_UMZ)
+
+#define SWCR_STATUS_INV		(1ULL << 17)
+#define SWCR_STATUS_DZE		(1ULL << 18)
+#define SWCR_STATUS_OVF		(1ULL << 19)
+#define SWCR_STATUS_UNF		(1ULL << 20)
+#define SWCR_STATUS_INE		(1ULL << 21)
+#define SWCR_STATUS_DNO		(1ULL << 22)
+#define SWCR_STATUS_MASK	((1ULL << 23) - (1ULL << 17))
+
+#define SWCR_MASK  (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
+
+/* MMU modes definitions */
+
+/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
+   The Unix PALcode only exposes the kernel and user modes; presumably
+   executive and supervisor are used by VMS.
+
+   PALcode itself uses physical mode for code and kernel mode for data;
+   there are PALmode instructions that can access data via physical mode
+   or via an os-installed "alternate mode", which is one of the 4 above.
+
+   QEMU does not currently properly distinguish between code/data when
+   looking up addresses.  To avoid having to address this issue, our
+   emulated PALcode will cheat and use the KSEG mapping for its code+data
+   rather than physical addresses.
+
+   Moreover, we're only emulating Unix PALcode, and not attempting VMS.
+
+   All of which allows us to drop all but kernel and user modes.
+   Elide the unused MMU modes to save space.  */
+
+#define NB_MMU_MODES 2
+
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX   0
+#define MMU_USER_IDX     1
+
+typedef struct CPUAlphaState CPUAlphaState;
+
+struct CPUAlphaState {
+    uint64_t ir[31];
+    float64 fir[31];
+    uint64_t pc;
+    uint64_t unique;
+    uint64_t lock_addr;
+    uint64_t lock_st_addr;
+    uint64_t lock_value;
+    float_status fp_status;
+    /* The following fields make up the FPCR, but in FP_STATUS format.  */
+    uint8_t fpcr_exc_status;
+    uint8_t fpcr_exc_mask;
+    uint8_t fpcr_dyn_round;
+    uint8_t fpcr_flush_to_zero;
+    uint8_t fpcr_dnz;
+    uint8_t fpcr_dnod;
+    uint8_t fpcr_undz;
+
+    /* The Internal Processor Registers.  Some of these we assume always
+       exist for use in user-mode.  */
+    uint8_t ps;
+    uint8_t intr_flag;
+    uint8_t pal_mode;
+    uint8_t fen;
+
+    uint32_t pcc_ofs;
+
+    /* These pass data from the exception logic in the translator and
+       helpers to the OS entry point.  This is used for both system
+       emulation and user-mode.  */
+    uint64_t trap_arg0;
+    uint64_t trap_arg1;
+    uint64_t trap_arg2;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* The internal data required by our emulation of the Unix PALcode.  */
+    uint64_t exc_addr;
+    uint64_t palbr;
+    uint64_t ptbr;
+    uint64_t vptptr;
+    uint64_t sysval;
+    uint64_t usp;
+    uint64_t shadow[8];
+    uint64_t scratch[24];
+#endif
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    /* temporary fixed-point registers
+     * used to emulate 64 bits target on 32 bits hosts
+     */
+    target_ulong t0, t1;
+#endif
+
+    /* Those resources are used only in Qemu core */
+    CPU_COMMON
+
+    int error_code;
+
+    uint32_t features;
+    uint32_t amask;
+    int implver;
+};
+
+#define cpu_init cpu_alpha_init
+#define cpu_exec cpu_alpha_exec
+#define cpu_gen_code cpu_alpha_gen_code
+#define cpu_signal_handler cpu_alpha_signal_handler
+
+#include "cpu-all.h"
+
+enum {
+    FEATURE_ASN    = 0x00000001,
+    FEATURE_SPS    = 0x00000002,
+    FEATURE_VIRBND = 0x00000004,
+    FEATURE_TBCHK  = 0x00000008,
+};
+
+enum {
+    EXCP_RESET,
+    EXCP_MCHK,
+    EXCP_SMP_INTERRUPT,
+    EXCP_CLK_INTERRUPT,
+    EXCP_DEV_INTERRUPT,
+    EXCP_MMFAULT,
+    EXCP_UNALIGN,
+    EXCP_OPCDEC,
+    EXCP_ARITH,
+    EXCP_FEN,
+    EXCP_CALL_PAL,
+    /* For Usermode emulation.  */
+    EXCP_STL_C,
+    EXCP_STQ_C,
+};
+
+/* Alpha-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_TIMER	CPU_INTERRUPT_TGT_EXT_0
+#define CPU_INTERRUPT_SMP	CPU_INTERRUPT_TGT_EXT_1
+#define CPU_INTERRUPT_MCHK	CPU_INTERRUPT_TGT_EXT_2
+
+/* OSF/1 Page table bits.  */
+enum {
+    PTE_VALID = 0x0001,
+    PTE_FOR   = 0x0002,  /* used for page protection (fault on read) */
+    PTE_FOW   = 0x0004,  /* used for page protection (fault on write) */
+    PTE_FOE   = 0x0008,  /* used for page protection (fault on exec) */
+    PTE_ASM   = 0x0010,
+    PTE_KRE   = 0x0100,
+    PTE_URE   = 0x0200,
+    PTE_KWE   = 0x1000,
+    PTE_UWE   = 0x2000
+};
+
+/* Hardware interrupt (entInt) constants.  */
+enum {
+    INT_K_IP,
+    INT_K_CLK,
+    INT_K_MCHK,
+    INT_K_DEV,
+    INT_K_PERF,
+};
+
+/* Memory management (entMM) constants.  */
+enum {
+    MM_K_TNV,
+    MM_K_ACV,
+    MM_K_FOR,
+    MM_K_FOE,
+    MM_K_FOW
+};
+
+/* Arithmetic exception (entArith) constants.  */
+enum {
+    EXC_M_SWC = 1,      /* Software completion */
+    EXC_M_INV = 2,      /* Invalid operation */
+    EXC_M_DZE = 4,      /* Division by zero */
+    EXC_M_FOV = 8,      /* Overflow */
+    EXC_M_UNF = 16,     /* Underflow */
+    EXC_M_INE = 32,     /* Inexact result */
+    EXC_M_IOV = 64      /* Integer Overflow */
+};
+
+/* Processor status constants.  */
+enum {
+    /* Low 3 bits are interrupt mask level.  */
+    PS_INT_MASK = 7,
+
+    /* Bits 4 and 5 are the mmu mode.  The VMS PALcode uses all 4 modes;
+       The Unix PALcode only uses bit 4.  */
+    PS_USER_MODE = 8
+};
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    if (env->pal_mode) {
+        return MMU_KERNEL_IDX;
+    } else if (env->ps & PS_USER_MODE) {
+        return MMU_USER_IDX;
+    } else {
+        return MMU_KERNEL_IDX;
+    }
+}
+
+enum {
+    IR_V0   = 0,
+    IR_T0   = 1,
+    IR_T1   = 2,
+    IR_T2   = 3,
+    IR_T3   = 4,
+    IR_T4   = 5,
+    IR_T5   = 6,
+    IR_T6   = 7,
+    IR_T7   = 8,
+    IR_S0   = 9,
+    IR_S1   = 10,
+    IR_S2   = 11,
+    IR_S3   = 12,
+    IR_S4   = 13,
+    IR_S5   = 14,
+    IR_S6   = 15,
+    IR_FP   = IR_S6,
+    IR_A0   = 16,
+    IR_A1   = 17,
+    IR_A2   = 18,
+    IR_A3   = 19,
+    IR_A4   = 20,
+    IR_A5   = 21,
+    IR_T8   = 22,
+    IR_T9   = 23,
+    IR_T10  = 24,
+    IR_T11  = 25,
+    IR_RA   = 26,
+    IR_T12  = 27,
+    IR_PV   = IR_T12,
+    IR_AT   = 28,
+    IR_GP   = 29,
+    IR_SP   = 30,
+    IR_ZERO = 31,
+};
+
+CPUAlphaState * cpu_alpha_init (const char *cpu_model);
+int cpu_alpha_exec(CPUAlphaState *s);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_alpha_signal_handler(int host_signum, void *pinfo,
+                             void *puc);
+int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
+                                int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
+void do_interrupt (CPUState *env);
+
+uint64_t cpu_alpha_load_fpcr (CPUState *env);
+void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
+#ifndef CONFIG_USER_ONLY
+void swap_shadow_regs(CPUState *env);
+QEMU_NORETURN void cpu_unassigned_access(CPUState *env1,
+                                         target_phys_addr_t addr, int is_write,
+                                         int is_exec, int unused, int size);
+#endif
+
+/* Bits in TB->FLAGS that control how translation is processed.  */
+enum {
+    TB_FLAGS_PAL_MODE = 1,
+    TB_FLAGS_FEN = 2,
+    TB_FLAGS_USER_MODE = 8,
+
+    TB_FLAGS_AMASK_SHIFT = 4,
+    TB_FLAGS_AMASK_BWX = AMASK_BWX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_FIX = AMASK_FIX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_CIX = AMASK_CIX << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_MVI = AMASK_MVI << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_TRAP = AMASK_TRAP << TB_FLAGS_AMASK_SHIFT,
+    TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT,
+};
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *pflags)
+{
+    int flags = 0;
+
+    *pc = env->pc;
+    *cs_base = 0;
+
+    if (env->pal_mode) {
+        flags = TB_FLAGS_PAL_MODE;
+    } else {
+        flags = env->ps & PS_USER_MODE;
+    }
+    if (env->fen) {
+        flags |= TB_FLAGS_FEN;
+    }
+    flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
+
+    *pflags = flags;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->ir[IR_SP] = newsp;
+    }
+    env->ir[IR_V0] = 0;
+    env->ir[IR_A3] = 0;
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+    env->unique = newtls;
+}
+#endif
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    /* Here we are checking to see if the CPU should wake up from HALT.
+       We will have gotten into this state only for WTINT from PALmode.  */
+    /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
+       asleep even if (some) interrupts have been asserted.  For now,
+       assume that if a CPU really wants to stay asleep, it will mask
+       interrupts at the chipset level, which will prevent these bits
+       from being set in the first place.  */
+    return env->interrupt_request & (CPU_INTERRUPT_HARD
+                                     | CPU_INTERRUPT_TIMER
+                                     | CPU_INTERRUPT_SMP
+                                     | CPU_INTERRUPT_MCHK);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/qemu-0.15.x/target-alpha/exec.h b/qemu-0.15.x/target-alpha/exec.h
new file mode 100644
index 0000000..afb01d3
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/exec.h
@@ -0,0 +1,39 @@
+/*
+ *  Alpha emulation cpu run-time definitions for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__ALPHA_EXEC_H__)
+#define __ALPHA_EXEC_H__
+
+#include "config.h"
+
+#include "dyngen-exec.h"
+
+#define TARGET_LONG_BITS 64
+
+register struct CPUAlphaState *env asm(AREG0);
+
+#define FP_STATUS (env->fp_status)
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#endif /* !defined (__ALPHA_EXEC_H__) */
diff --git a/qemu-0.15.x/target-alpha/helper.c b/qemu-0.15.x/target-alpha/helper.c
new file mode 100644
index 0000000..7049c80
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/helper.c
@@ -0,0 +1,486 @@
+/*
+ *  Alpha emulation cpu helpers for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "softfloat.h"
+
+uint64_t cpu_alpha_load_fpcr (CPUState *env)
+{
+    uint64_t r = 0;
+    uint8_t t;
+
+    t = env->fpcr_exc_status;
+    if (t) {
+        r = FPCR_SUM;
+        if (t & float_flag_invalid) {
+            r |= FPCR_INV;
+        }
+        if (t & float_flag_divbyzero) {
+            r |= FPCR_DZE;
+        }
+        if (t & float_flag_overflow) {
+            r |= FPCR_OVF;
+        }
+        if (t & float_flag_underflow) {
+            r |= FPCR_UNF;
+        }
+        if (t & float_flag_inexact) {
+            r |= FPCR_INE;
+        }
+    }
+
+    t = env->fpcr_exc_mask;
+    if (t & float_flag_invalid) {
+        r |= FPCR_INVD;
+    }
+    if (t & float_flag_divbyzero) {
+        r |= FPCR_DZED;
+    }
+    if (t & float_flag_overflow) {
+        r |= FPCR_OVFD;
+    }
+    if (t & float_flag_underflow) {
+        r |= FPCR_UNFD;
+    }
+    if (t & float_flag_inexact) {
+        r |= FPCR_INED;
+    }
+
+    switch (env->fpcr_dyn_round) {
+    case float_round_nearest_even:
+        r |= FPCR_DYN_NORMAL;
+        break;
+    case float_round_down:
+        r |= FPCR_DYN_MINUS;
+        break;
+    case float_round_up:
+        r |= FPCR_DYN_PLUS;
+        break;
+    case float_round_to_zero:
+        r |= FPCR_DYN_CHOPPED;
+        break;
+    }
+
+    if (env->fpcr_dnz) {
+        r |= FPCR_DNZ;
+    }
+    if (env->fpcr_dnod) {
+        r |= FPCR_DNOD;
+    }
+    if (env->fpcr_undz) {
+        r |= FPCR_UNDZ;
+    }
+
+    return r;
+}
+
+void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
+{
+    uint8_t t;
+
+    t = 0;
+    if (val & FPCR_INV) {
+        t |= float_flag_invalid;
+    }
+    if (val & FPCR_DZE) {
+        t |= float_flag_divbyzero;
+    }
+    if (val & FPCR_OVF) {
+        t |= float_flag_overflow;
+    }
+    if (val & FPCR_UNF) {
+        t |= float_flag_underflow;
+    }
+    if (val & FPCR_INE) {
+        t |= float_flag_inexact;
+    }
+    env->fpcr_exc_status = t;
+
+    t = 0;
+    if (val & FPCR_INVD) {
+        t |= float_flag_invalid;
+    }
+    if (val & FPCR_DZED) {
+        t |= float_flag_divbyzero;
+    }
+    if (val & FPCR_OVFD) {
+        t |= float_flag_overflow;
+    }
+    if (val & FPCR_UNFD) {
+        t |= float_flag_underflow;
+    }
+    if (val & FPCR_INED) {
+        t |= float_flag_inexact;
+    }
+    env->fpcr_exc_mask = t;
+
+    switch (val & FPCR_DYN_MASK) {
+    case FPCR_DYN_CHOPPED:
+        t = float_round_to_zero;
+        break;
+    case FPCR_DYN_MINUS:
+        t = float_round_down;
+        break;
+    case FPCR_DYN_NORMAL:
+        t = float_round_nearest_even;
+        break;
+    case FPCR_DYN_PLUS:
+        t = float_round_up;
+        break;
+    }
+    env->fpcr_dyn_round = t;
+
+    env->fpcr_flush_to_zero
+      = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
+
+    env->fpcr_dnz = (val & FPCR_DNZ) != 0;
+    env->fpcr_dnod = (val & FPCR_DNOD) != 0;
+    env->fpcr_undz = (val & FPCR_UNDZ) != 0;
+}
+
+#if defined(CONFIG_USER_ONLY)
+int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                                int mmu_idx, int is_softmmu)
+{
+    env->exception_index = EXCP_MMFAULT;
+    env->trap_arg0 = address;
+    return 1;
+}
+#else
+void swap_shadow_regs(CPUState *env)
+{
+    uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
+
+    i0 = env->ir[8];
+    i1 = env->ir[9];
+    i2 = env->ir[10];
+    i3 = env->ir[11];
+    i4 = env->ir[12];
+    i5 = env->ir[13];
+    i6 = env->ir[14];
+    i7 = env->ir[25];
+
+    env->ir[8]  = env->shadow[0];
+    env->ir[9]  = env->shadow[1];
+    env->ir[10] = env->shadow[2];
+    env->ir[11] = env->shadow[3];
+    env->ir[12] = env->shadow[4];
+    env->ir[13] = env->shadow[5];
+    env->ir[14] = env->shadow[6];
+    env->ir[25] = env->shadow[7];
+
+    env->shadow[0] = i0;
+    env->shadow[1] = i1;
+    env->shadow[2] = i2;
+    env->shadow[3] = i3;
+    env->shadow[4] = i4;
+    env->shadow[5] = i5;
+    env->shadow[6] = i6;
+    env->shadow[7] = i7;
+}
+
+/* Returns the OSF/1 entMM failure indication, or -1 on success.  */
+static int get_physical_address(CPUState *env, target_ulong addr,
+                                int prot_need, int mmu_idx,
+                                target_ulong *pphys, int *pprot)
+{
+    target_long saddr = addr;
+    target_ulong phys = 0;
+    target_ulong L1pte, L2pte, L3pte;
+    target_ulong pt, index;
+    int prot = 0;
+    int ret = MM_K_ACV;
+
+    /* Ensure that the virtual address is properly sign-extended from
+       the last implemented virtual address bit.  */
+    if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
+        goto exit;
+    }
+
+    /* Translate the superpage.  */
+    /* ??? When we do more than emulate Unix PALcode, we'll need to
+       determine which KSEG is actually active.  */
+    if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
+        /* User-space cannot access KSEG addresses.  */
+        if (mmu_idx != MMU_KERNEL_IDX) {
+            goto exit;
+        }
+
+        /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
+           We would not do this if the 48-bit KSEG is enabled.  */
+        phys = saddr & ((1ull << 40) - 1);
+        phys |= (saddr & (1ull << 40)) << 3;
+
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        ret = -1;
+        goto exit;
+    }
+
+    /* Interpret the page table exactly like PALcode does.  */
+
+    pt = env->ptbr;
+
+    /* L1 page table read.  */
+    index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
+    L1pte = ldq_phys(pt + index*8);
+
+    if (unlikely((L1pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+    if (unlikely((L1pte & PTE_KRE) == 0)) {
+        goto exit;
+    }
+    pt = L1pte >> 32 << TARGET_PAGE_BITS;
+
+    /* L2 page table read.  */
+    index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
+    L2pte = ldq_phys(pt + index*8);
+
+    if (unlikely((L2pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+    if (unlikely((L2pte & PTE_KRE) == 0)) {
+        goto exit;
+    }
+    pt = L2pte >> 32 << TARGET_PAGE_BITS;
+
+    /* L3 page table read.  */
+    index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
+    L3pte = ldq_phys(pt + index*8);
+
+    phys = L3pte >> 32 << TARGET_PAGE_BITS;
+    if (unlikely((L3pte & PTE_VALID) == 0)) {
+        ret = MM_K_TNV;
+        goto exit;
+    }
+
+#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
+# error page bits out of date
+#endif
+
+    /* Check access violations.  */
+    if (L3pte & (PTE_KRE << mmu_idx)) {
+        prot |= PAGE_READ | PAGE_EXEC;
+    }
+    if (L3pte & (PTE_KWE << mmu_idx)) {
+        prot |= PAGE_WRITE;
+    }
+    if (unlikely((prot & prot_need) == 0 && prot_need)) {
+        goto exit;
+    }
+
+    /* Check fault-on-operation violations.  */
+    prot &= ~(L3pte >> 1);
+    ret = -1;
+    if (unlikely((prot & prot_need) == 0)) {
+        ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
+               prot_need & PAGE_WRITE ? MM_K_FOW :
+               prot_need & PAGE_READ ? MM_K_FOR : -1);
+    }
+
+ exit:
+    *pphys = phys;
+    *pprot = prot;
+    return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_ulong phys;
+    int prot, fail;
+
+    fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+    return (fail >= 0 ? -1 : phys);
+}
+
+int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    target_ulong phys;
+    int prot, fail;
+
+    fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
+    if (unlikely(fail >= 0)) {
+        env->exception_index = EXCP_MMFAULT;
+        env->trap_arg0 = addr;
+        env->trap_arg1 = fail;
+        env->trap_arg2 = (rw == 2 ? -1 : rw);
+        return 1;
+    }
+
+    tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+                 prot, mmu_idx, TARGET_PAGE_SIZE);
+    return 0;
+}
+#endif /* USER_ONLY */
+
+void do_interrupt (CPUState *env)
+{
+    int i = env->exception_index;
+
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name = "<unknown>";
+
+        switch (i) {
+        case EXCP_RESET:
+            name = "reset";
+            break;
+        case EXCP_MCHK:
+            name = "mchk";
+            break;
+        case EXCP_SMP_INTERRUPT:
+            name = "smp_interrupt";
+            break;
+        case EXCP_CLK_INTERRUPT:
+            name = "clk_interrupt";
+            break;
+        case EXCP_DEV_INTERRUPT:
+            name = "dev_interrupt";
+            break;
+        case EXCP_MMFAULT:
+            name = "mmfault";
+            break;
+        case EXCP_UNALIGN:
+            name = "unalign";
+            break;
+        case EXCP_OPCDEC:
+            name = "opcdec";
+            break;
+        case EXCP_ARITH:
+            name = "arith";
+            break;
+        case EXCP_FEN:
+            name = "fen";
+            break;
+        case EXCP_CALL_PAL:
+            name = "call_pal";
+            break;
+        case EXCP_STL_C:
+            name = "stl_c";
+            break;
+        case EXCP_STQ_C:
+            name = "stq_c";
+            break;
+        }
+        qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
+                 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
+    }
+
+    env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    switch (i) {
+    case EXCP_RESET:
+        i = 0x0000;
+        break;
+    case EXCP_MCHK:
+        i = 0x0080;
+        break;
+    case EXCP_SMP_INTERRUPT:
+        i = 0x0100;
+        break;
+    case EXCP_CLK_INTERRUPT:
+        i = 0x0180;
+        break;
+    case EXCP_DEV_INTERRUPT:
+        i = 0x0200;
+        break;
+    case EXCP_MMFAULT:
+        i = 0x0280;
+        break;
+    case EXCP_UNALIGN:
+        i = 0x0300;
+        break;
+    case EXCP_OPCDEC:
+        i = 0x0380;
+        break;
+    case EXCP_ARITH:
+        i = 0x0400;
+        break;
+    case EXCP_FEN:
+        i = 0x0480;
+        break;
+    case EXCP_CALL_PAL:
+        i = env->error_code;
+        /* There are 64 entry points for both privileged and unprivileged,
+           with bit 0x80 indicating unprivileged.  Each entry point gets
+           64 bytes to do its job.  */
+        if (i & 0x80) {
+            i = 0x2000 + (i - 0x80) * 64;
+        } else {
+            i = 0x1000 + i * 64;
+        }
+        break;
+    default:
+        cpu_abort(env, "Unhandled CPU exception");
+    }
+
+    /* Remember where the exception happened.  Emulate real hardware in
+       that the low bit of the PC indicates PALmode.  */
+    env->exc_addr = env->pc | env->pal_mode;
+
+    /* Continue execution at the PALcode entry point.  */
+    env->pc = env->palbr + i;
+
+    /* Switch to PALmode.  */
+    if (!env->pal_mode) {
+        env->pal_mode = 1;
+        swap_shadow_regs(env);
+    }
+#endif /* !USER_ONLY */
+}
+
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    static const char *linux_reg_names[] = {
+        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
+        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
+        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
+        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
+    };
+    int i;
+
+    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
+                env->pc, env->ps);
+    for (i = 0; i < 31; i++) {
+        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
+                    linux_reg_names[i], env->ir[i]);
+        if ((i % 3) == 2)
+            cpu_fprintf(f, "\n");
+    }
+
+    cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
+                env->lock_addr, env->lock_value);
+
+    for (i = 0; i < 31; i++) {
+        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
+                    *((uint64_t *)(&env->fir[i])));
+        if ((i % 3) == 2)
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "\n");
+}
diff --git a/qemu-0.15.x/target-alpha/helper.h b/qemu-0.15.x/target-alpha/helper.h
new file mode 100644
index 0000000..2dec57e
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/helper.h
@@ -0,0 +1,118 @@
+#include "def-helper.h"
+
+DEF_HELPER_2(excp, void, int, int)
+DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64)
+
+DEF_HELPER_2(addqv, i64, i64, i64)
+DEF_HELPER_2(addlv, i64, i64, i64)
+DEF_HELPER_2(subqv, i64, i64, i64)
+DEF_HELPER_2(sublv, i64, i64, i64)
+DEF_HELPER_2(mullv, i64, i64, i64)
+DEF_HELPER_2(mulqv, i64, i64, i64)
+DEF_HELPER_FLAGS_2(umulh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+
+DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(cttz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+
+DEF_HELPER_FLAGS_2(zap, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+
+DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+
+DEF_HELPER_FLAGS_2(minub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(minsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(minuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(minsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(maxub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(maxsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(maxuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(maxsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(perr, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_1(pklb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+
+DEF_HELPER_FLAGS_0(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64)
+DEF_HELPER_FLAGS_1(store_fpcr, TCG_CALL_CONST, void, i64)
+
+DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
+DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
+DEF_HELPER_FLAGS_2(addf, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(subf, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(mulf, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(divf, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_1(sqrtf, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
+DEF_HELPER_FLAGS_2(addg, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(subg, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(mulg, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(divg, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_1(sqrtg, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
+DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
+DEF_HELPER_FLAGS_2(adds, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(subs, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(muls, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(divs, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_1(sqrts, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_2(addt, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(subt, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(mult, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_2(divt, TCG_CALL_CONST, i64, i64, i64)
+DEF_HELPER_FLAGS_1(sqrtt, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_2(cmptun, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmpteq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmptle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmptlt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmpgeq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmpgle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(cmpglt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+
+DEF_HELPER_FLAGS_1(cvtts, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtst, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtqs, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtqt, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtqf, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtgf, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtgq, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvtqg, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_1(cvttq, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvttq_c, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_1(cvttq_svic, TCG_CALL_CONST, i64, i64)
+
+DEF_HELPER_FLAGS_1(setroundmode, TCG_CALL_CONST, void, i32)
+DEF_HELPER_FLAGS_1(setflushzero, TCG_CALL_CONST, void, i32)
+DEF_HELPER_FLAGS_0(fp_exc_clear, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_0(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32)
+DEF_HELPER_2(fp_exc_raise, void, i32, i32)
+DEF_HELPER_2(fp_exc_raise_s, void, i32, i32)
+
+DEF_HELPER_1(ieee_input, i64, i64)
+DEF_HELPER_1(ieee_input_cmp, i64, i64)
+DEF_HELPER_1(ieee_input_s, i64, i64)
+
+#if !defined (CONFIG_USER_ONLY)
+DEF_HELPER_1(hw_ret, void, i64)
+
+DEF_HELPER_1(ldl_phys, i64, i64)
+DEF_HELPER_1(ldq_phys, i64, i64)
+DEF_HELPER_1(ldl_l_phys, i64, i64)
+DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(stl_phys, void, i64, i64)
+DEF_HELPER_2(stq_phys, void, i64, i64)
+DEF_HELPER_2(stl_c_phys, i64, i64, i64)
+DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+
+DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+#endif
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-alpha/machine.c b/qemu-0.15.x/target-alpha/machine.c
new file mode 100644
index 0000000..76d70d9
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/machine.c
@@ -0,0 +1,87 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static int get_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAlphaState *env = opaque;
+    cpu_alpha_store_fpcr(env, qemu_get_be64(f));
+    return 0;
+}
+
+static void put_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAlphaState *env = opaque;
+    qemu_put_be64(f, cpu_alpha_load_fpcr(env));
+}
+
+static const VMStateInfo vmstate_fpcr = {
+    .name = "fpcr",
+    .get = get_fpcr,
+    .put = put_fpcr,
+};
+
+static VMStateField vmstate_cpu_fields[] = {
+    VMSTATE_UINTTL_ARRAY(ir, CPUState, 31),
+    VMSTATE_UINTTL_ARRAY(fir, CPUState, 31),
+    /* Save the architecture value of the fpcr, not the internally
+       expanded version.  Since this architecture value does not
+       exist in memory to be stored, this requires a but of hoop
+       jumping.  We want OFFSET=0 so that we effectively pass ENV
+       to the helper functions, and we need to fill in the name by
+       hand since there's no field of that name.  */
+    {
+        .name = "fpcr",
+        .version_id = 0,
+        .size = sizeof(uint64_t),
+        .info = &vmstate_fpcr,
+        .flags = VMS_SINGLE,
+        .offset = 0
+    },
+    VMSTATE_UINTTL(pc, CPUState),
+    VMSTATE_UINTTL(unique, CPUState),
+    VMSTATE_UINTTL(lock_addr, CPUState),
+    VMSTATE_UINTTL(lock_value, CPUState),
+    /* Note that lock_st_addr is not saved; it is a temporary
+       used during the execution of the st[lq]_c insns.  */
+
+    VMSTATE_UINT8(ps, CPUState),
+    VMSTATE_UINT8(intr_flag, CPUState),
+    VMSTATE_UINT8(pal_mode, CPUState),
+    VMSTATE_UINT8(fen, CPUState),
+
+    VMSTATE_UINT32(pcc_ofs, CPUState),
+
+    VMSTATE_UINTTL(trap_arg0, CPUState),
+    VMSTATE_UINTTL(trap_arg1, CPUState),
+    VMSTATE_UINTTL(trap_arg2, CPUState),
+
+    VMSTATE_UINTTL(exc_addr, CPUState),
+    VMSTATE_UINTTL(palbr, CPUState),
+    VMSTATE_UINTTL(ptbr, CPUState),
+    VMSTATE_UINTTL(vptptr, CPUState),
+    VMSTATE_UINTTL(sysval, CPUState),
+    VMSTATE_UINTTL(usp, CPUState),
+
+    VMSTATE_UINTTL_ARRAY(shadow, CPUState, 8),
+    VMSTATE_UINTTL_ARRAY(scratch, CPUState, 24),
+
+    VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = vmstate_cpu_fields,
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
diff --git a/qemu-0.15.x/target-alpha/op_helper.c b/qemu-0.15.x/target-alpha/op_helper.c
new file mode 100644
index 0000000..8f39154
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/op_helper.c
@@ -0,0 +1,1350 @@
+/*
+ *  Alpha emulation cpu micro-operations helpers for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "exec.h"
+#include "host-utils.h"
+#include "softfloat.h"
+#include "helper.h"
+#include "qemu-timer.h"
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+
+/* This should only be called from translate, via gen_excp.
+   We expect that ENV->PC has already been updated.  */
+void QEMU_NORETURN helper_excp(int excp, int error)
+{
+    env->exception_index = excp;
+    env->error_code = error;
+    cpu_loop_exit(env);
+}
+
+static void do_restore_state(void *retaddr)
+{
+    unsigned long pc = (unsigned long)retaddr;
+
+    if (pc) {
+        TranslationBlock *tb = tb_find_pc(pc);
+        if (tb) {
+            cpu_restore_state(tb, env, pc);
+        }
+    }
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX.  */
+static void QEMU_NORETURN dynamic_excp(int excp, int error)
+{
+    env->exception_index = excp;
+    env->error_code = error;
+    do_restore_state(GETPC());
+    cpu_loop_exit(env);
+}
+
+static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
+{
+    env->trap_arg0 = exc;
+    env->trap_arg1 = mask;
+    dynamic_excp(EXCP_ARITH, 0);
+}
+
+uint64_t helper_load_pcc (void)
+{
+#ifndef CONFIG_USER_ONLY
+    /* In system mode we have access to a decent high-resolution clock.
+       In order to make OS-level time accounting work with the RPCC,
+       present it with a well-timed clock fixed at 250MHz.  */
+    return (((uint64_t)env->pcc_ofs << 32)
+            | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+    /* In user-mode, vm_clock doesn't exist.  Just pass through the host cpu
+       clock ticks.  Also, don't bother taking PCC_OFS into account.  */
+    return (uint32_t)cpu_get_real_ticks();
+#endif
+}
+
+uint64_t helper_load_fpcr (void)
+{
+    return cpu_alpha_load_fpcr (env);
+}
+
+void helper_store_fpcr (uint64_t val)
+{
+    cpu_alpha_store_fpcr (env, val);
+}
+
+uint64_t helper_addqv (uint64_t op1, uint64_t op2)
+{
+    uint64_t tmp = op1;
+    op1 += op2;
+    if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return op1;
+}
+
+uint64_t helper_addlv (uint64_t op1, uint64_t op2)
+{
+    uint64_t tmp = op1;
+    op1 = (uint32_t)(op1 + op2);
+    if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return op1;
+}
+
+uint64_t helper_subqv (uint64_t op1, uint64_t op2)
+{
+    uint64_t res;
+    res = op1 - op2;
+    if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return res;
+}
+
+uint64_t helper_sublv (uint64_t op1, uint64_t op2)
+{
+    uint32_t res;
+    res = op1 - op2;
+    if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return res;
+}
+
+uint64_t helper_mullv (uint64_t op1, uint64_t op2)
+{
+    int64_t res = (int64_t)op1 * (int64_t)op2;
+
+    if (unlikely((int32_t)res != res)) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return (int64_t)((int32_t)res);
+}
+
+uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
+{
+    uint64_t tl, th;
+
+    muls64(&tl, &th, op1, op2);
+    /* If th != 0 && th != -1, then we had an overflow */
+    if (unlikely((th + 1) > 1)) {
+        arith_excp(EXC_M_IOV, 0);
+    }
+    return tl;
+}
+
+uint64_t helper_umulh (uint64_t op1, uint64_t op2)
+{
+    uint64_t tl, th;
+
+    mulu64(&tl, &th, op1, op2);
+    return th;
+}
+
+uint64_t helper_ctpop (uint64_t arg)
+{
+    return ctpop64(arg);
+}
+
+uint64_t helper_ctlz (uint64_t arg)
+{
+    return clz64(arg);
+}
+
+uint64_t helper_cttz (uint64_t arg)
+{
+    return ctz64(arg);
+}
+
+static inline uint64_t byte_zap(uint64_t op, uint8_t mskb)
+{
+    uint64_t mask;
+
+    mask = 0;
+    mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
+    mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
+    mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
+    mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
+    mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
+    mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
+    mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
+    mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
+
+    return op & ~mask;
+}
+
+uint64_t helper_zap(uint64_t val, uint64_t mask)
+{
+    return byte_zap(val, mask);
+}
+
+uint64_t helper_zapnot(uint64_t val, uint64_t mask)
+{
+    return byte_zap(val, ~mask);
+}
+
+uint64_t helper_cmpbge (uint64_t op1, uint64_t op2)
+{
+    uint8_t opa, opb, res;
+    int i;
+
+    res = 0;
+    for (i = 0; i < 8; i++) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        if (opa >= opb)
+            res |= 1 << i;
+    }
+    return res;
+}
+
+uint64_t helper_minub8 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    uint8_t opa, opb, opr;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        opr = opa < opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 8);
+    }
+    return res;
+}
+
+uint64_t helper_minsb8 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    int8_t opa, opb;
+    uint8_t opr;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        opr = opa < opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 8);
+    }
+    return res;
+}
+
+uint64_t helper_minuw4 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    uint16_t opa, opb, opr;
+    int i;
+
+    for (i = 0; i < 4; ++i) {
+        opa = op1 >> (i * 16);
+        opb = op2 >> (i * 16);
+        opr = opa < opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 16);
+    }
+    return res;
+}
+
+uint64_t helper_minsw4 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    int16_t opa, opb;
+    uint16_t opr;
+    int i;
+
+    for (i = 0; i < 4; ++i) {
+        opa = op1 >> (i * 16);
+        opb = op2 >> (i * 16);
+        opr = opa < opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 16);
+    }
+    return res;
+}
+
+uint64_t helper_maxub8 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    uint8_t opa, opb, opr;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        opr = opa > opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 8);
+    }
+    return res;
+}
+
+uint64_t helper_maxsb8 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    int8_t opa, opb;
+    uint8_t opr;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        opr = opa > opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 8);
+    }
+    return res;
+}
+
+uint64_t helper_maxuw4 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    uint16_t opa, opb, opr;
+    int i;
+
+    for (i = 0; i < 4; ++i) {
+        opa = op1 >> (i * 16);
+        opb = op2 >> (i * 16);
+        opr = opa > opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 16);
+    }
+    return res;
+}
+
+uint64_t helper_maxsw4 (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    int16_t opa, opb;
+    uint16_t opr;
+    int i;
+
+    for (i = 0; i < 4; ++i) {
+        opa = op1 >> (i * 16);
+        opb = op2 >> (i * 16);
+        opr = opa > opb ? opa : opb;
+        res |= (uint64_t)opr << (i * 16);
+    }
+    return res;
+}
+
+uint64_t helper_perr (uint64_t op1, uint64_t op2)
+{
+    uint64_t res = 0;
+    uint8_t opa, opb, opr;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        opa = op1 >> (i * 8);
+        opb = op2 >> (i * 8);
+        if (opa >= opb)
+            opr = opa - opb;
+        else
+            opr = opb - opa;
+        res += opr;
+    }
+    return res;
+}
+
+uint64_t helper_pklb (uint64_t op1)
+{
+    return (op1 & 0xff) | ((op1 >> 24) & 0xff00);
+}
+
+uint64_t helper_pkwb (uint64_t op1)
+{
+    return ((op1 & 0xff)
+            | ((op1 >> 8) & 0xff00)
+            | ((op1 >> 16) & 0xff0000)
+            | ((op1 >> 24) & 0xff000000));
+}
+
+uint64_t helper_unpkbl (uint64_t op1)
+{
+    return (op1 & 0xff) | ((op1 & 0xff00) << 24);
+}
+
+uint64_t helper_unpkbw (uint64_t op1)
+{
+    return ((op1 & 0xff)
+            | ((op1 & 0xff00) << 8)
+            | ((op1 & 0xff0000) << 16)
+            | ((op1 & 0xff000000) << 24));
+}
+
+/* Floating point helpers */
+
+void helper_setroundmode (uint32_t val)
+{
+    set_float_rounding_mode(val, &FP_STATUS);
+}
+
+void helper_setflushzero (uint32_t val)
+{
+    set_flush_to_zero(val, &FP_STATUS);
+}
+
+void helper_fp_exc_clear (void)
+{
+    set_float_exception_flags(0, &FP_STATUS);
+}
+
+uint32_t helper_fp_exc_get (void)
+{
+    return get_float_exception_flags(&FP_STATUS);
+}
+
+/* Raise exceptions for ieee fp insns without software completion.
+   In that case there are no exceptions that don't trap; the mask
+   doesn't apply.  */
+void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
+{
+    if (exc) {
+        uint32_t hw_exc = 0;
+
+        if (exc & float_flag_invalid) {
+            hw_exc |= EXC_M_INV;
+        }
+        if (exc & float_flag_divbyzero) {
+            hw_exc |= EXC_M_DZE;
+        }
+        if (exc & float_flag_overflow) {
+            hw_exc |= EXC_M_FOV;
+        }
+        if (exc & float_flag_underflow) {
+            hw_exc |= EXC_M_UNF;
+        }
+        if (exc & float_flag_inexact) {
+            hw_exc |= EXC_M_INE;
+        }
+
+        arith_excp(hw_exc, 1ull << regno);
+    }
+}
+
+/* Raise exceptions for ieee fp insns with software completion.  */
+void helper_fp_exc_raise_s(uint32_t exc, uint32_t regno)
+{
+    if (exc) {
+        env->fpcr_exc_status |= exc;
+
+        exc &= ~env->fpcr_exc_mask;
+        if (exc) {
+            helper_fp_exc_raise(exc, regno);
+        }
+    }
+}
+
+/* Input remapping without software completion.  Handle denormal-map-to-zero
+   and trap for all other non-finite numbers.  */
+uint64_t helper_ieee_input(uint64_t val)
+{
+    uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+    uint64_t frac = val & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (frac != 0) {
+            /* If DNZ is set flush denormals to zero on input.  */
+            if (env->fpcr_dnz) {
+                val &= 1ull << 63;
+            } else {
+                arith_excp(EXC_M_UNF, 0);
+            }
+        }
+    } else if (exp == 0x7ff) {
+        /* Infinity or NaN.  */
+        /* ??? I'm not sure these exception bit flags are correct.  I do
+           know that the Linux kernel, at least, doesn't rely on them and
+           just emulates the insn to figure out what exception to use.  */
+        arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
+    }
+    return val;
+}
+
+/* Similar, but does not trap for infinities.  Used for comparisons.  */
+uint64_t helper_ieee_input_cmp(uint64_t val)
+{
+    uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+    uint64_t frac = val & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (frac != 0) {
+            /* If DNZ is set flush denormals to zero on input.  */
+            if (env->fpcr_dnz) {
+                val &= 1ull << 63;
+            } else {
+                arith_excp(EXC_M_UNF, 0);
+            }
+        }
+    } else if (exp == 0x7ff && frac) {
+        /* NaN.  */
+        arith_excp(EXC_M_INV, 0);
+    }
+    return val;
+}
+
+/* Input remapping with software completion enabled.  All we have to do
+   is handle denormal-map-to-zero; all other inputs get exceptions as
+   needed from the actual operation.  */
+uint64_t helper_ieee_input_s(uint64_t val)
+{
+    if (env->fpcr_dnz) {
+        uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+        if (exp == 0) {
+            val &= 1ull << 63;
+        }
+    }
+    return val;
+}
+
+/* F floating (VAX) */
+static inline uint64_t float32_to_f(float32 fa)
+{
+    uint64_t r, exp, mant, sig;
+    CPU_FloatU a;
+
+    a.f = fa;
+    sig = ((uint64_t)a.l & 0x80000000) << 32;
+    exp = (a.l >> 23) & 0xff;
+    mant = ((uint64_t)a.l & 0x007fffff) << 29;
+
+    if (exp == 255) {
+        /* NaN or infinity */
+        r = 1; /* VAX dirty zero */
+    } else if (exp == 0) {
+        if (mant == 0) {
+            /* Zero */
+            r = 0;
+        } else {
+            /* Denormalized */
+            r = sig | ((exp + 1) << 52) | mant;
+        }
+    } else {
+        if (exp >= 253) {
+            /* Overflow */
+            r = 1; /* VAX dirty zero */
+        } else {
+            r = sig | ((exp + 2) << 52);
+        }
+    }
+
+    return r;
+}
+
+static inline float32 f_to_float32(uint64_t a)
+{
+    uint32_t exp, mant_sig;
+    CPU_FloatU r;
+
+    exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
+    mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
+
+    if (unlikely(!exp && mant_sig)) {
+        /* Reserved operands / Dirty zero */
+        dynamic_excp(EXCP_OPCDEC, 0);
+    }
+
+    if (exp < 3) {
+        /* Underflow */
+        r.l = 0;
+    } else {
+        r.l = ((exp - 2) << 23) | mant_sig;
+    }
+
+    return r.f;
+}
+
+uint32_t helper_f_to_memory (uint64_t a)
+{
+    uint32_t r;
+    r =  (a & 0x00001fffe0000000ull) >> 13;
+    r |= (a & 0x07ffe00000000000ull) >> 45;
+    r |= (a & 0xc000000000000000ull) >> 48;
+    return r;
+}
+
+uint64_t helper_memory_to_f (uint32_t a)
+{
+    uint64_t r;
+    r =  ((uint64_t)(a & 0x0000c000)) << 48;
+    r |= ((uint64_t)(a & 0x003fffff)) << 45;
+    r |= ((uint64_t)(a & 0xffff0000)) << 13;
+    if (!(a & 0x00004000))
+        r |= 0x7ll << 59;
+    return r;
+}
+
+/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong.  We should
+   either implement VAX arithmetic properly or just signal invalid opcode.  */
+
+uint64_t helper_addf (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = f_to_float32(a);
+    fb = f_to_float32(b);
+    fr = float32_add(fa, fb, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_subf (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = f_to_float32(a);
+    fb = f_to_float32(b);
+    fr = float32_sub(fa, fb, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_mulf (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = f_to_float32(a);
+    fb = f_to_float32(b);
+    fr = float32_mul(fa, fb, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_divf (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = f_to_float32(a);
+    fb = f_to_float32(b);
+    fr = float32_div(fa, fb, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_sqrtf (uint64_t t)
+{
+    float32 ft, fr;
+
+    ft = f_to_float32(t);
+    fr = float32_sqrt(ft, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+
+/* G floating (VAX) */
+static inline uint64_t float64_to_g(float64 fa)
+{
+    uint64_t r, exp, mant, sig;
+    CPU_DoubleU a;
+
+    a.d = fa;
+    sig = a.ll & 0x8000000000000000ull;
+    exp = (a.ll >> 52) & 0x7ff;
+    mant = a.ll & 0x000fffffffffffffull;
+
+    if (exp == 2047) {
+        /* NaN or infinity */
+        r = 1; /* VAX dirty zero */
+    } else if (exp == 0) {
+        if (mant == 0) {
+            /* Zero */
+            r = 0;
+        } else {
+            /* Denormalized */
+            r = sig | ((exp + 1) << 52) | mant;
+        }
+    } else {
+        if (exp >= 2045) {
+            /* Overflow */
+            r = 1; /* VAX dirty zero */
+        } else {
+            r = sig | ((exp + 2) << 52);
+        }
+    }
+
+    return r;
+}
+
+static inline float64 g_to_float64(uint64_t a)
+{
+    uint64_t exp, mant_sig;
+    CPU_DoubleU r;
+
+    exp = (a >> 52) & 0x7ff;
+    mant_sig = a & 0x800fffffffffffffull;
+
+    if (!exp && mant_sig) {
+        /* Reserved operands / Dirty zero */
+        dynamic_excp(EXCP_OPCDEC, 0);
+    }
+
+    if (exp < 3) {
+        /* Underflow */
+        r.ll = 0;
+    } else {
+        r.ll = ((exp - 2) << 52) | mant_sig;
+    }
+
+    return r.d;
+}
+
+uint64_t helper_g_to_memory (uint64_t a)
+{
+    uint64_t r;
+    r =  (a & 0x000000000000ffffull) << 48;
+    r |= (a & 0x00000000ffff0000ull) << 16;
+    r |= (a & 0x0000ffff00000000ull) >> 16;
+    r |= (a & 0xffff000000000000ull) >> 48;
+    return r;
+}
+
+uint64_t helper_memory_to_g (uint64_t a)
+{
+    uint64_t r;
+    r =  (a & 0x000000000000ffffull) << 48;
+    r |= (a & 0x00000000ffff0000ull) << 16;
+    r |= (a & 0x0000ffff00000000ull) >> 16;
+    r |= (a & 0xffff000000000000ull) >> 48;
+    return r;
+}
+
+uint64_t helper_addg (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+    fr = float64_add(fa, fb, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+uint64_t helper_subg (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+    fr = float64_sub(fa, fb, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+uint64_t helper_mulg (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+    fr = float64_mul(fa, fb, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+uint64_t helper_divg (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+    fr = float64_div(fa, fb, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+uint64_t helper_sqrtg (uint64_t a)
+{
+    float64 fa, fr;
+
+    fa = g_to_float64(a);
+    fr = float64_sqrt(fa, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+
+/* S floating (single) */
+
+/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
+static inline uint64_t float32_to_s_int(uint32_t fi)
+{
+    uint32_t frac = fi & 0x7fffff;
+    uint32_t sign = fi >> 31;
+    uint32_t exp_msb = (fi >> 30) & 1;
+    uint32_t exp_low = (fi >> 23) & 0x7f;
+    uint32_t exp;
+
+    exp = (exp_msb << 10) | exp_low;
+    if (exp_msb) {
+        if (exp_low == 0x7f)
+            exp = 0x7ff;
+    } else {
+        if (exp_low != 0x00)
+            exp |= 0x380;
+    }
+
+    return (((uint64_t)sign << 63)
+            | ((uint64_t)exp << 52)
+            | ((uint64_t)frac << 29));
+}
+
+static inline uint64_t float32_to_s(float32 fa)
+{
+    CPU_FloatU a;
+    a.f = fa;
+    return float32_to_s_int(a.l);
+}
+
+static inline uint32_t s_to_float32_int(uint64_t a)
+{
+    return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
+}
+
+static inline float32 s_to_float32(uint64_t a)
+{
+    CPU_FloatU r;
+    r.l = s_to_float32_int(a);
+    return r.f;
+}
+
+uint32_t helper_s_to_memory (uint64_t a)
+{
+    return s_to_float32_int(a);
+}
+
+uint64_t helper_memory_to_s (uint32_t a)
+{
+    return float32_to_s_int(a);
+}
+
+uint64_t helper_adds (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = s_to_float32(a);
+    fb = s_to_float32(b);
+    fr = float32_add(fa, fb, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+uint64_t helper_subs (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = s_to_float32(a);
+    fb = s_to_float32(b);
+    fr = float32_sub(fa, fb, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+uint64_t helper_muls (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = s_to_float32(a);
+    fb = s_to_float32(b);
+    fr = float32_mul(fa, fb, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+uint64_t helper_divs (uint64_t a, uint64_t b)
+{
+    float32 fa, fb, fr;
+
+    fa = s_to_float32(a);
+    fb = s_to_float32(b);
+    fr = float32_div(fa, fb, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+uint64_t helper_sqrts (uint64_t a)
+{
+    float32 fa, fr;
+
+    fa = s_to_float32(a);
+    fr = float32_sqrt(fa, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+
+/* T floating (double) */
+static inline float64 t_to_float64(uint64_t a)
+{
+    /* Memory format is the same as float64 */
+    CPU_DoubleU r;
+    r.ll = a;
+    return r.d;
+}
+
+static inline uint64_t float64_to_t(float64 fa)
+{
+    /* Memory format is the same as float64 */
+    CPU_DoubleU r;
+    r.d = fa;
+    return r.ll;
+}
+
+uint64_t helper_addt (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+    fr = float64_add(fa, fb, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_subt (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+    fr = float64_sub(fa, fb, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_mult (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+    fr = float64_mul(fa, fb, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_divt (uint64_t a, uint64_t b)
+{
+    float64 fa, fb, fr;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+    fr = float64_div(fa, fb, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_sqrtt (uint64_t a)
+{
+    float64 fa, fr;
+
+    fa = t_to_float64(a);
+    fr = float64_sqrt(fa, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+/* Comparisons */
+uint64_t helper_cmptun (uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+
+    if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
+        return 0x4000000000000000ULL;
+    } else {
+        return 0;
+    }
+}
+
+uint64_t helper_cmpteq(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+
+    if (float64_eq_quiet(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+uint64_t helper_cmptle(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+
+    if (float64_le(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+uint64_t helper_cmptlt(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = t_to_float64(a);
+    fb = t_to_float64(b);
+
+    if (float64_lt(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+uint64_t helper_cmpgeq(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+
+    if (float64_eq_quiet(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+uint64_t helper_cmpgle(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+
+    if (float64_le(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+uint64_t helper_cmpglt(uint64_t a, uint64_t b)
+{
+    float64 fa, fb;
+
+    fa = g_to_float64(a);
+    fb = g_to_float64(b);
+
+    if (float64_lt(fa, fb, &FP_STATUS))
+        return 0x4000000000000000ULL;
+    else
+        return 0;
+}
+
+/* Floating point format conversion */
+uint64_t helper_cvtts (uint64_t a)
+{
+    float64 fa;
+    float32 fr;
+
+    fa = t_to_float64(a);
+    fr = float64_to_float32(fa, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+uint64_t helper_cvtst (uint64_t a)
+{
+    float32 fa;
+    float64 fr;
+
+    fa = s_to_float32(a);
+    fr = float32_to_float64(fa, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqs (uint64_t a)
+{
+    float32 fr = int64_to_float32(a, &FP_STATUS);
+    return float32_to_s(fr);
+}
+
+/* Implement float64 to uint64 conversion without saturation -- we must
+   supply the truncated result.  This behaviour is used by the compiler
+   to get unsigned conversion for free with the same instruction.
+
+   The VI flag is set when overflow or inexact exceptions should be raised.  */
+
+static inline uint64_t helper_cvttq_internal(uint64_t a, int roundmode, int VI)
+{
+    uint64_t frac, ret = 0;
+    uint32_t exp, sign, exc = 0;
+    int shift;
+
+    sign = (a >> 63);
+    exp = (uint32_t)(a >> 52) & 0x7ff;
+    frac = a & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (unlikely(frac != 0)) {
+            goto do_underflow;
+        }
+    } else if (exp == 0x7ff) {
+        exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
+    } else {
+        /* Restore implicit bit.  */
+        frac |= 0x10000000000000ull;
+
+        shift = exp - 1023 - 52;
+        if (shift >= 0) {
+            /* In this case the number is so large that we must shift
+               the fraction left.  There is no rounding to do.  */
+            if (shift < 63) {
+                ret = frac << shift;
+                if (VI && (ret >> shift) != frac) {
+                    exc = float_flag_overflow;
+                }
+            }
+        } else {
+            uint64_t round;
+
+            /* In this case the number is smaller than the fraction as
+               represented by the 52 bit number.  Here we must think
+               about rounding the result.  Handle this by shifting the
+               fractional part of the number into the high bits of ROUND.
+               This will let us efficiently handle round-to-nearest.  */
+            shift = -shift;
+            if (shift < 63) {
+                ret = frac >> shift;
+                round = frac << (64 - shift);
+            } else {
+                /* The exponent is so small we shift out everything.
+                   Leave a sticky bit for proper rounding below.  */
+            do_underflow:
+                round = 1;
+            }
+
+            if (round) {
+                exc = (VI ? float_flag_inexact : 0);
+                switch (roundmode) {
+                case float_round_nearest_even:
+                    if (round == (1ull << 63)) {
+                        /* Fraction is exactly 0.5; round to even.  */
+                        ret += (ret & 1);
+                    } else if (round > (1ull << 63)) {
+                        ret += 1;
+                    }
+                    break;
+                case float_round_to_zero:
+                    break;
+                case float_round_up:
+                    ret += 1 - sign;
+                    break;
+                case float_round_down:
+                    ret += sign;
+                    break;
+                }
+            }
+        }
+        if (sign) {
+            ret = -ret;
+        }
+    }
+    if (unlikely(exc)) {
+        float_raise(exc, &FP_STATUS);
+    }
+
+    return ret;
+}
+
+uint64_t helper_cvttq(uint64_t a)
+{
+    return helper_cvttq_internal(a, FP_STATUS.float_rounding_mode, 1);
+}
+
+uint64_t helper_cvttq_c(uint64_t a)
+{
+    return helper_cvttq_internal(a, float_round_to_zero, 0);
+}
+
+uint64_t helper_cvttq_svic(uint64_t a)
+{
+    return helper_cvttq_internal(a, float_round_to_zero, 1);
+}
+
+uint64_t helper_cvtqt (uint64_t a)
+{
+    float64 fr = int64_to_float64(a, &FP_STATUS);
+    return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqf (uint64_t a)
+{
+    float32 fr = int64_to_float32(a, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgf (uint64_t a)
+{
+    float64 fa;
+    float32 fr;
+
+    fa = g_to_float64(a);
+    fr = float64_to_float32(fa, &FP_STATUS);
+    return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgq (uint64_t a)
+{
+    float64 fa = g_to_float64(a);
+    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+}
+
+uint64_t helper_cvtqg (uint64_t a)
+{
+    float64 fr;
+    fr = int64_to_float64(a, &FP_STATUS);
+    return float64_to_g(fr);
+}
+
+/* PALcode support special instructions */
+#if !defined (CONFIG_USER_ONLY)
+void helper_hw_ret (uint64_t a)
+{
+    env->pc = a & ~3;
+    env->intr_flag = 0;
+    env->lock_addr = -1;
+    if ((a & 1) == 0) {
+        env->pal_mode = 0;
+        swap_shadow_regs(env);
+    }
+}
+
+void helper_tbia(void)
+{
+    tlb_flush(env, 1);
+}
+
+void helper_tbis(uint64_t p)
+{
+    tlb_flush_page(env, p);
+}
+#endif
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+uint64_t helper_ldl_phys(uint64_t p)
+{
+    return (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_phys(uint64_t p)
+{
+    return ldq_phys(p);
+}
+
+uint64_t helper_ldl_l_phys(uint64_t p)
+{
+    env->lock_addr = p;
+    return env->lock_value = (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_l_phys(uint64_t p)
+{
+    env->lock_addr = p;
+    return env->lock_value = ldl_phys(p);
+}
+
+void helper_stl_phys(uint64_t p, uint64_t v)
+{
+    stl_phys(p, v);
+}
+
+void helper_stq_phys(uint64_t p, uint64_t v)
+{
+    stq_phys(p, v);
+}
+
+uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
+{
+    uint64_t ret = 0;
+
+    if (p == env->lock_addr) {
+        int32_t old = ldl_phys(p);
+        if (old == (int32_t)env->lock_value) {
+            stl_phys(p, v);
+            ret = 1;
+        }
+    }
+    env->lock_addr = -1;
+
+    return ret;
+}
+
+uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
+{
+    uint64_t ret = 0;
+
+    if (p == env->lock_addr) {
+        uint64_t old = ldq_phys(p);
+        if (old == env->lock_value) {
+            stq_phys(p, v);
+            ret = 1;
+        }
+    }
+    env->lock_addr = -1;
+
+    return ret;
+}
+
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+                                              int is_user, void *retaddr)
+{
+    uint64_t pc;
+    uint32_t insn;
+
+    do_restore_state(retaddr);
+
+    pc = env->pc;
+    insn = ldl_code(pc);
+
+    env->trap_arg0 = addr;
+    env->trap_arg1 = insn >> 26;                /* opcode */
+    env->trap_arg2 = (insn >> 21) & 31;         /* dest regno */
+    helper_excp(EXCP_UNALIGN, 0);
+}
+
+void QEMU_NORETURN cpu_unassigned_access(CPUState *env1,
+                                         target_phys_addr_t addr, int is_write,
+                                         int is_exec, int unused, int size)
+{
+    env = env1;
+    env->trap_arg0 = addr;
+    env->trap_arg1 = is_write;
+    dynamic_excp(EXCP_MCHK, 0);
+}
+
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    CPUState *saved_env;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret != 0)) {
+        do_restore_state(retaddr);
+        /* Exception index and error code are already set */
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+#endif
diff --git a/qemu-0.15.x/target-alpha/translate.c b/qemu-0.15.x/target-alpha/translate.c
new file mode 100644
index 0000000..c61906a
--- /dev/null
+++ b/qemu-0.15.x/target-alpha/translate.c
@@ -0,0 +1,3488 @@
+/*
+ *  Alpha emulation cpu translation for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "host-utils.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#undef ALPHA_DEBUG_DISAS
+#define CONFIG_SOFTFLOAT_INLINE
+
+#ifdef ALPHA_DEBUG_DISAS
+#  define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DISAS(...) do { } while (0)
+#endif
+
+typedef struct DisasContext DisasContext;
+struct DisasContext {
+    struct TranslationBlock *tb;
+    CPUAlphaState *env;
+    uint64_t pc;
+    int mem_idx;
+
+    /* Current rounding mode for this TB.  */
+    int tb_rm;
+    /* Current flush-to-zero setting for this TB.  */
+    int tb_ftz;
+};
+
+/* Return values from translate_one, indicating the state of the TB.
+   Note that zero indicates that we are not exiting the TB.  */
+
+typedef enum {
+    NO_EXIT,
+
+    /* We have emitted one or more goto_tb.  No fixup required.  */
+    EXIT_GOTO_TB,
+
+    /* We are not using a goto_tb (for whatever reason), but have updated
+       the PC (for whatever reason), so there's no need to do it again on
+       exiting the TB.  */
+    EXIT_PC_UPDATED,
+
+    /* We are exiting the TB, but have neither emitted a goto_tb, nor
+       updated the PC for the next instruction to be executed.  */
+    EXIT_PC_STALE,
+
+    /* We are ending the TB with a noreturn function call, e.g. longjmp.
+       No following code will be executed.  */
+    EXIT_NORETURN,
+} ExitStatus;
+
+/* global register indexes */
+static TCGv_ptr cpu_env;
+static TCGv cpu_ir[31];
+static TCGv cpu_fir[31];
+static TCGv cpu_pc;
+static TCGv cpu_lock_addr;
+static TCGv cpu_lock_st_addr;
+static TCGv cpu_lock_value;
+static TCGv cpu_unique;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_sysval;
+static TCGv cpu_usp;
+#endif
+
+/* register names */
+static char cpu_reg_names[10*4+21*5 + 10*5+21*6];
+
+#include "gen-icount.h"
+
+static void alpha_translate_init(void)
+{
+    int i;
+    char *p;
+    static int done_init = 0;
+
+    if (done_init)
+        return;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    p = cpu_reg_names;
+    for (i = 0; i < 31; i++) {
+        sprintf(p, "ir%d", i);
+        cpu_ir[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                           offsetof(CPUState, ir[i]), p);
+        p += (i < 10) ? 4 : 5;
+
+        sprintf(p, "fir%d", i);
+        cpu_fir[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                            offsetof(CPUState, fir[i]), p);
+        p += (i < 10) ? 5 : 6;
+    }
+
+    cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
+                                    offsetof(CPUState, pc), "pc");
+
+    cpu_lock_addr = tcg_global_mem_new_i64(TCG_AREG0,
+					   offsetof(CPUState, lock_addr),
+					   "lock_addr");
+    cpu_lock_st_addr = tcg_global_mem_new_i64(TCG_AREG0,
+					      offsetof(CPUState, lock_st_addr),
+					      "lock_st_addr");
+    cpu_lock_value = tcg_global_mem_new_i64(TCG_AREG0,
+					    offsetof(CPUState, lock_value),
+					    "lock_value");
+
+    cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
+                                        offsetof(CPUState, unique), "unique");
+#ifndef CONFIG_USER_ONLY
+    cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
+                                        offsetof(CPUState, sysval), "sysval");
+    cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
+                                     offsetof(CPUState, usp), "usp");
+#endif
+
+    /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+
+    done_init = 1;
+}
+
+static void gen_excp_1(int exception, int error_code)
+{
+    TCGv_i32 tmp1, tmp2;
+
+    tmp1 = tcg_const_i32(exception);
+    tmp2 = tcg_const_i32(error_code);
+    gen_helper_excp(tmp1, tmp2);
+    tcg_temp_free_i32(tmp2);
+    tcg_temp_free_i32(tmp1);
+}
+
+static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+{
+    tcg_gen_movi_i64(cpu_pc, ctx->pc);
+    gen_excp_1(exception, error_code);
+    return EXIT_NORETURN;
+}
+
+static inline ExitStatus gen_invalid(DisasContext *ctx)
+{
+    return gen_excp(ctx, EXCP_OPCDEC, 0);
+}
+
+static inline void gen_qemu_ldf(TCGv t0, TCGv t1, int flags)
+{
+    TCGv tmp = tcg_temp_new();
+    TCGv_i32 tmp32 = tcg_temp_new_i32();
+    tcg_gen_qemu_ld32u(tmp, t1, flags);
+    tcg_gen_trunc_i64_i32(tmp32, tmp);
+    gen_helper_memory_to_f(t0, tmp32);
+    tcg_temp_free_i32(tmp32);
+    tcg_temp_free(tmp);
+}
+
+static inline void gen_qemu_ldg(TCGv t0, TCGv t1, int flags)
+{
+    TCGv tmp = tcg_temp_new();
+    tcg_gen_qemu_ld64(tmp, t1, flags);
+    gen_helper_memory_to_g(t0, tmp);
+    tcg_temp_free(tmp);
+}
+
+static inline void gen_qemu_lds(TCGv t0, TCGv t1, int flags)
+{
+    TCGv tmp = tcg_temp_new();
+    TCGv_i32 tmp32 = tcg_temp_new_i32();
+    tcg_gen_qemu_ld32u(tmp, t1, flags);
+    tcg_gen_trunc_i64_i32(tmp32, tmp);
+    gen_helper_memory_to_s(t0, tmp32);
+    tcg_temp_free_i32(tmp32);
+    tcg_temp_free(tmp);
+}
+
+static inline void gen_qemu_ldl_l(TCGv t0, TCGv t1, int flags)
+{
+    tcg_gen_qemu_ld32s(t0, t1, flags);
+    tcg_gen_mov_i64(cpu_lock_addr, t1);
+    tcg_gen_mov_i64(cpu_lock_value, t0);
+}
+
+static inline void gen_qemu_ldq_l(TCGv t0, TCGv t1, int flags)
+{
+    tcg_gen_qemu_ld64(t0, t1, flags);
+    tcg_gen_mov_i64(cpu_lock_addr, t1);
+    tcg_gen_mov_i64(cpu_lock_value, t0);
+}
+
+static inline void gen_load_mem(DisasContext *ctx,
+                                void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1,
+                                                          int flags),
+                                int ra, int rb, int32_t disp16, int fp,
+                                int clear)
+{
+    TCGv addr, va;
+
+    /* LDQ_U with ra $31 is UNOP.  Other various loads are forms of
+       prefetches, which we can treat as nops.  No worries about
+       missed exceptions here.  */
+    if (unlikely(ra == 31)) {
+        return;
+    }
+
+    addr = tcg_temp_new();
+    if (rb != 31) {
+        tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
+        if (clear) {
+            tcg_gen_andi_i64(addr, addr, ~0x7);
+        }
+    } else {
+        if (clear) {
+            disp16 &= ~0x7;
+        }
+        tcg_gen_movi_i64(addr, disp16);
+    }
+
+    va = (fp ? cpu_fir[ra] : cpu_ir[ra]);
+    tcg_gen_qemu_load(va, addr, ctx->mem_idx);
+
+    tcg_temp_free(addr);
+}
+
+static inline void gen_qemu_stf(TCGv t0, TCGv t1, int flags)
+{
+    TCGv_i32 tmp32 = tcg_temp_new_i32();
+    TCGv tmp = tcg_temp_new();
+    gen_helper_f_to_memory(tmp32, t0);
+    tcg_gen_extu_i32_i64(tmp, tmp32);
+    tcg_gen_qemu_st32(tmp, t1, flags);
+    tcg_temp_free(tmp);
+    tcg_temp_free_i32(tmp32);
+}
+
+static inline void gen_qemu_stg(TCGv t0, TCGv t1, int flags)
+{
+    TCGv tmp = tcg_temp_new();
+    gen_helper_g_to_memory(tmp, t0);
+    tcg_gen_qemu_st64(tmp, t1, flags);
+    tcg_temp_free(tmp);
+}
+
+static inline void gen_qemu_sts(TCGv t0, TCGv t1, int flags)
+{
+    TCGv_i32 tmp32 = tcg_temp_new_i32();
+    TCGv tmp = tcg_temp_new();
+    gen_helper_s_to_memory(tmp32, t0);
+    tcg_gen_extu_i32_i64(tmp, tmp32);
+    tcg_gen_qemu_st32(tmp, t1, flags);
+    tcg_temp_free(tmp);
+    tcg_temp_free_i32(tmp32);
+}
+
+static inline void gen_store_mem(DisasContext *ctx,
+                                 void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1,
+                                                            int flags),
+                                 int ra, int rb, int32_t disp16, int fp,
+                                 int clear)
+{
+    TCGv addr, va;
+
+    addr = tcg_temp_new();
+    if (rb != 31) {
+        tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
+        if (clear) {
+            tcg_gen_andi_i64(addr, addr, ~0x7);
+        }
+    } else {
+        if (clear) {
+            disp16 &= ~0x7;
+        }
+        tcg_gen_movi_i64(addr, disp16);
+    }
+
+    if (ra == 31) {
+        va = tcg_const_i64(0);
+    } else {
+        va = (fp ? cpu_fir[ra] : cpu_ir[ra]);
+    }
+    tcg_gen_qemu_store(va, addr, ctx->mem_idx);
+
+    tcg_temp_free(addr);
+    if (ra == 31) {
+        tcg_temp_free(va);
+    }
+}
+
+static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
+                                        int32_t disp16, int quad)
+{
+    TCGv addr;
+
+    if (ra == 31) {
+        /* ??? Don't bother storing anything.  The user can't tell
+           the difference, since the zero register always reads zero.  */
+        return NO_EXIT;
+    }
+
+#if defined(CONFIG_USER_ONLY)
+    addr = cpu_lock_st_addr;
+#else
+    addr = tcg_temp_local_new();
+#endif
+
+    if (rb != 31) {
+        tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
+    } else {
+        tcg_gen_movi_i64(addr, disp16);
+    }
+
+#if defined(CONFIG_USER_ONLY)
+    /* ??? This is handled via a complicated version of compare-and-swap
+       in the cpu_loop.  Hopefully one day we'll have a real CAS opcode
+       in TCG so that this isn't necessary.  */
+    return gen_excp(ctx, quad ? EXCP_STQ_C : EXCP_STL_C, ra);
+#else
+    /* ??? In system mode we are never multi-threaded, so CAS can be
+       implemented via a non-atomic load-compare-store sequence.  */
+    {
+        int lab_fail, lab_done;
+        TCGv val;
+
+        lab_fail = gen_new_label();
+        lab_done = gen_new_label();
+        tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
+
+        val = tcg_temp_new();
+        if (quad) {
+            tcg_gen_qemu_ld64(val, addr, ctx->mem_idx);
+        } else {
+            tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx);
+        }
+        tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
+
+        if (quad) {
+            tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx);
+        } else {
+            tcg_gen_qemu_st32(cpu_ir[ra], addr, ctx->mem_idx);
+        }
+        tcg_gen_movi_i64(cpu_ir[ra], 1);
+        tcg_gen_br(lab_done);
+
+        gen_set_label(lab_fail);
+        tcg_gen_movi_i64(cpu_ir[ra], 0);
+
+        gen_set_label(lab_done);
+        tcg_gen_movi_i64(cpu_lock_addr, -1);
+
+        tcg_temp_free(addr);
+        return NO_EXIT;
+    }
+#endif
+}
+
+static int use_goto_tb(DisasContext *ctx, uint64_t dest)
+{
+    /* Check for the dest on the same page as the start of the TB.  We
+       also want to suppress goto_tb in the case of single-steping and IO.  */
+    return (((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0
+            && !ctx->env->singlestep_enabled
+            && !(ctx->tb->cflags & CF_LAST_IO));
+}
+
+static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
+{
+    uint64_t dest = ctx->pc + (disp << 2);
+
+    if (ra != 31) {
+        tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
+    }
+
+    /* Notice branch-to-next; used to initialize RA with the PC.  */
+    if (disp == 0) {
+        return 0;
+    } else if (use_goto_tb(ctx, dest)) {
+        tcg_gen_goto_tb(0);
+        tcg_gen_movi_i64(cpu_pc, dest);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb);
+        return EXIT_GOTO_TB;
+    } else {
+        tcg_gen_movi_i64(cpu_pc, dest);
+        return EXIT_PC_UPDATED;
+    }
+}
+
+static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond,
+                                     TCGv cmp, int32_t disp)
+{
+    uint64_t dest = ctx->pc + (disp << 2);
+    int lab_true = gen_new_label();
+
+    if (use_goto_tb(ctx, dest)) {
+        tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
+
+        tcg_gen_goto_tb(0);
+        tcg_gen_movi_i64(cpu_pc, ctx->pc);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb);
+
+        gen_set_label(lab_true);
+        tcg_gen_goto_tb(1);
+        tcg_gen_movi_i64(cpu_pc, dest);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb + 1);
+
+        return EXIT_GOTO_TB;
+    } else {
+        int lab_over = gen_new_label();
+
+        /* ??? Consider using either
+             movi pc, next
+             addi tmp, pc, disp
+             movcond pc, cond, 0, tmp, pc
+           or
+             setcond tmp, cond, 0
+             movi pc, next
+             neg tmp, tmp
+             andi tmp, tmp, disp
+             add pc, pc, tmp
+           The current diamond subgraph surely isn't efficient.  */
+
+        tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
+        tcg_gen_movi_i64(cpu_pc, ctx->pc);
+        tcg_gen_br(lab_over);
+        gen_set_label(lab_true);
+        tcg_gen_movi_i64(cpu_pc, dest);
+        gen_set_label(lab_over);
+
+        return EXIT_PC_UPDATED;
+    }
+}
+
+static ExitStatus gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
+                            int32_t disp, int mask)
+{
+    TCGv cmp_tmp;
+
+    if (unlikely(ra == 31)) {
+        cmp_tmp = tcg_const_i64(0);
+    } else {
+        cmp_tmp = tcg_temp_new();
+        if (mask) {
+            tcg_gen_andi_i64(cmp_tmp, cpu_ir[ra], 1);
+        } else {
+            tcg_gen_mov_i64(cmp_tmp, cpu_ir[ra]);
+        }
+    }
+
+    return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
+}
+
+/* Fold -0.0 for comparison with COND.  */
+
+static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src)
+{
+    uint64_t mzero = 1ull << 63;
+
+    switch (cond) {
+    case TCG_COND_LE:
+    case TCG_COND_GT:
+        /* For <= or >, the -0.0 value directly compares the way we want.  */
+        tcg_gen_mov_i64(dest, src);
+        break;
+
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        /* For == or !=, we can simply mask off the sign bit and compare.  */
+        tcg_gen_andi_i64(dest, src, mzero - 1);
+        break;
+
+    case TCG_COND_GE:
+    case TCG_COND_LT:
+        /* For >= or <, map -0.0 to +0.0 via comparison and mask.  */
+        tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero);
+        tcg_gen_neg_i64(dest, dest);
+        tcg_gen_and_i64(dest, dest, src);
+        break;
+
+    default:
+        abort();
+    }
+}
+
+static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
+                             int32_t disp)
+{
+    TCGv cmp_tmp;
+
+    if (unlikely(ra == 31)) {
+        /* Very uncommon case, but easier to optimize it to an integer
+           comparison than continuing with the floating point comparison.  */
+        return gen_bcond(ctx, cond, ra, disp, 0);
+    }
+
+    cmp_tmp = tcg_temp_new();
+    gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]);
+    return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
+}
+
+static void gen_cmov(TCGCond cond, int ra, int rb, int rc,
+                     int islit, uint8_t lit, int mask)
+{
+    TCGCond inv_cond = tcg_invert_cond(cond);
+    int l1;
+
+    if (unlikely(rc == 31))
+        return;
+
+    l1 = gen_new_label();
+
+    if (ra != 31) {
+        if (mask) {
+            TCGv tmp = tcg_temp_new();
+            tcg_gen_andi_i64(tmp, cpu_ir[ra], 1);
+            tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1);
+            tcg_temp_free(tmp);
+        } else
+            tcg_gen_brcondi_i64(inv_cond, cpu_ir[ra], 0, l1);
+    } else {
+        /* Very uncommon case - Do not bother to optimize.  */
+        TCGv tmp = tcg_const_i64(0);
+        tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1);
+        tcg_temp_free(tmp);
+    }
+
+    if (islit)
+        tcg_gen_movi_i64(cpu_ir[rc], lit);
+    else
+        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+    gen_set_label(l1);
+}
+
+static void gen_fcmov(TCGCond cond, int ra, int rb, int rc)
+{
+    TCGv cmp_tmp;
+    int l1;
+
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    cmp_tmp = tcg_temp_new();
+    if (unlikely(ra == 31)) {
+        tcg_gen_movi_i64(cmp_tmp, 0);
+    } else {
+        gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]);
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_i64(tcg_invert_cond(cond), cmp_tmp, 0, l1);
+    tcg_temp_free(cmp_tmp);
+
+    if (rb != 31)
+        tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]);
+    else
+        tcg_gen_movi_i64(cpu_fir[rc], 0);
+    gen_set_label(l1);
+}
+
+#define QUAL_RM_N       0x080   /* Round mode nearest even */
+#define QUAL_RM_C       0x000   /* Round mode chopped */
+#define QUAL_RM_M       0x040   /* Round mode minus infinity */
+#define QUAL_RM_D       0x0c0   /* Round mode dynamic */
+#define QUAL_RM_MASK    0x0c0
+
+#define QUAL_U          0x100   /* Underflow enable (fp output) */
+#define QUAL_V          0x100   /* Overflow enable (int output) */
+#define QUAL_S          0x400   /* Software completion enable */
+#define QUAL_I          0x200   /* Inexact detection enable */
+
+static void gen_qual_roundmode(DisasContext *ctx, int fn11)
+{
+    TCGv_i32 tmp;
+
+    fn11 &= QUAL_RM_MASK;
+    if (fn11 == ctx->tb_rm) {
+        return;
+    }
+    ctx->tb_rm = fn11;
+
+    tmp = tcg_temp_new_i32();
+    switch (fn11) {
+    case QUAL_RM_N:
+        tcg_gen_movi_i32(tmp, float_round_nearest_even);
+        break;
+    case QUAL_RM_C:
+        tcg_gen_movi_i32(tmp, float_round_to_zero);
+        break;
+    case QUAL_RM_M:
+        tcg_gen_movi_i32(tmp, float_round_down);
+        break;
+    case QUAL_RM_D:
+        tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUState, fpcr_dyn_round));
+        break;
+    }
+
+#if defined(CONFIG_SOFTFLOAT_INLINE)
+    /* ??? The "softfloat.h" interface is to call set_float_rounding_mode.
+       With CONFIG_SOFTFLOAT that expands to an out-of-line call that just
+       sets the one field.  */
+    tcg_gen_st8_i32(tmp, cpu_env,
+                    offsetof(CPUState, fp_status.float_rounding_mode));
+#else
+    gen_helper_setroundmode(tmp);
+#endif
+
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_qual_flushzero(DisasContext *ctx, int fn11)
+{
+    TCGv_i32 tmp;
+
+    fn11 &= QUAL_U;
+    if (fn11 == ctx->tb_ftz) {
+        return;
+    }
+    ctx->tb_ftz = fn11;
+
+    tmp = tcg_temp_new_i32();
+    if (fn11) {
+        /* Underflow is enabled, use the FPCR setting.  */
+        tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUState, fpcr_flush_to_zero));
+    } else {
+        /* Underflow is disabled, force flush-to-zero.  */
+        tcg_gen_movi_i32(tmp, 1);
+    }
+
+#if defined(CONFIG_SOFTFLOAT_INLINE)
+    tcg_gen_st8_i32(tmp, cpu_env,
+                    offsetof(CPUState, fp_status.flush_to_zero));
+#else
+    gen_helper_setflushzero(tmp);
+#endif
+
+    tcg_temp_free_i32(tmp);
+}
+
+static TCGv gen_ieee_input(int reg, int fn11, int is_cmp)
+{
+    TCGv val = tcg_temp_new();
+    if (reg == 31) {
+        tcg_gen_movi_i64(val, 0);
+    } else if (fn11 & QUAL_S) {
+        gen_helper_ieee_input_s(val, cpu_fir[reg]);
+    } else if (is_cmp) {
+        gen_helper_ieee_input_cmp(val, cpu_fir[reg]);
+    } else {
+        gen_helper_ieee_input(val, cpu_fir[reg]);
+    }
+    return val;
+}
+
+static void gen_fp_exc_clear(void)
+{
+#if defined(CONFIG_SOFTFLOAT_INLINE)
+    TCGv_i32 zero = tcg_const_i32(0);
+    tcg_gen_st8_i32(zero, cpu_env,
+                    offsetof(CPUState, fp_status.float_exception_flags));
+    tcg_temp_free_i32(zero);
+#else
+    gen_helper_fp_exc_clear();
+#endif
+}
+
+static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
+{
+    /* ??? We ought to be able to do something with imprecise exceptions.
+       E.g. notice we're still in the trap shadow of something within the
+       TB and do not generate the code to signal the exception; end the TB
+       when an exception is forced to arrive, either by consumption of a
+       register value or TRAPB or EXCB.  */
+    TCGv_i32 exc = tcg_temp_new_i32();
+    TCGv_i32 reg;
+
+#if defined(CONFIG_SOFTFLOAT_INLINE)
+    tcg_gen_ld8u_i32(exc, cpu_env,
+                     offsetof(CPUState, fp_status.float_exception_flags));
+#else
+    gen_helper_fp_exc_get(exc);
+#endif
+
+    if (ignore) {
+        tcg_gen_andi_i32(exc, exc, ~ignore);
+    }
+
+    /* ??? Pass in the regno of the destination so that the helper can
+       set EXC_MASK, which contains a bitmask of destination registers
+       that have caused arithmetic traps.  A simple userspace emulation
+       does not require this.  We do need it for a guest kernel's entArith,
+       or if we were to do something clever with imprecise exceptions.  */
+    reg = tcg_const_i32(rc + 32);
+
+    if (fn11 & QUAL_S) {
+        gen_helper_fp_exc_raise_s(exc, reg);
+    } else {
+        gen_helper_fp_exc_raise(exc, reg);
+    }
+
+    tcg_temp_free_i32(reg);
+    tcg_temp_free_i32(exc);
+}
+
+static inline void gen_fp_exc_raise(int rc, int fn11)
+{
+    gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : float_flag_inexact);
+}
+
+static void gen_fcvtlq(int rb, int rc)
+{
+    if (unlikely(rc == 31)) {
+        return;
+    }
+    if (unlikely(rb == 31)) {
+        tcg_gen_movi_i64(cpu_fir[rc], 0);
+    } else {
+        TCGv tmp = tcg_temp_new();
+
+        /* The arithmetic right shift here, plus the sign-extended mask below
+           yields a sign-extended result without an explicit ext32s_i64.  */
+        tcg_gen_sari_i64(tmp, cpu_fir[rb], 32);
+        tcg_gen_shri_i64(cpu_fir[rc], cpu_fir[rb], 29);
+        tcg_gen_andi_i64(tmp, tmp, (int32_t)0xc0000000);
+        tcg_gen_andi_i64(cpu_fir[rc], cpu_fir[rc], 0x3fffffff);
+        tcg_gen_or_i64(cpu_fir[rc], cpu_fir[rc], tmp);
+
+        tcg_temp_free(tmp);
+    }
+}
+
+static void gen_fcvtql(int rb, int rc)
+{
+    if (unlikely(rc == 31)) {
+        return;
+    }
+    if (unlikely(rb == 31)) {
+        tcg_gen_movi_i64(cpu_fir[rc], 0);
+    } else {
+        TCGv tmp = tcg_temp_new();
+
+        tcg_gen_andi_i64(tmp, cpu_fir[rb], 0xC0000000);
+        tcg_gen_andi_i64(cpu_fir[rc], cpu_fir[rb], 0x3FFFFFFF);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_shli_i64(cpu_fir[rc], cpu_fir[rc], 29);
+        tcg_gen_or_i64(cpu_fir[rc], cpu_fir[rc], tmp);
+
+        tcg_temp_free(tmp);
+    }
+}
+
+static void gen_fcvtql_v(DisasContext *ctx, int rb, int rc)
+{
+    if (rb != 31) {
+        int lab = gen_new_label();
+        TCGv tmp = tcg_temp_new();
+
+        tcg_gen_ext32s_i64(tmp, cpu_fir[rb]);
+        tcg_gen_brcond_i64(TCG_COND_EQ, tmp, cpu_fir[rb], lab);
+        gen_excp(ctx, EXCP_ARITH, EXC_M_IOV);
+
+        gen_set_label(lab);
+    }
+    gen_fcvtql(rb, rc);
+}
+
+#define FARITH2(name)                                   \
+static inline void glue(gen_f, name)(int rb, int rc)    \
+{                                                       \
+    if (unlikely(rc == 31)) {                           \
+        return;                                         \
+    }                                                   \
+    if (rb != 31) {                                     \
+        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \
+    } else {						\
+        TCGv tmp = tcg_const_i64(0);                    \
+        gen_helper_ ## name (cpu_fir[rc], tmp);         \
+        tcg_temp_free(tmp);                             \
+    }                                                   \
+}
+
+/* ??? VAX instruction qualifiers ignored.  */
+FARITH2(sqrtf)
+FARITH2(sqrtg)
+FARITH2(cvtgf)
+FARITH2(cvtgq)
+FARITH2(cvtqf)
+FARITH2(cvtqg)
+
+static void gen_ieee_arith2(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+                            int rb, int rc, int fn11)
+{
+    TCGv vb;
+
+    /* ??? This is wrong: the instruction is not a nop, it still may
+       raise exceptions.  */
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    gen_qual_roundmode(ctx, fn11);
+    gen_qual_flushzero(ctx, fn11);
+    gen_fp_exc_clear();
+
+    vb = gen_ieee_input(rb, fn11, 0);
+    helper(cpu_fir[rc], vb);
+    tcg_temp_free(vb);
+
+    gen_fp_exc_raise(rc, fn11);
+}
+
+#define IEEE_ARITH2(name)                                       \
+static inline void glue(gen_f, name)(DisasContext *ctx,         \
+                                     int rb, int rc, int fn11)  \
+{                                                               \
+    gen_ieee_arith2(ctx, gen_helper_##name, rb, rc, fn11);      \
+}
+IEEE_ARITH2(sqrts)
+IEEE_ARITH2(sqrtt)
+IEEE_ARITH2(cvtst)
+IEEE_ARITH2(cvtts)
+
+static void gen_fcvttq(DisasContext *ctx, int rb, int rc, int fn11)
+{
+    TCGv vb;
+    int ignore = 0;
+
+    /* ??? This is wrong: the instruction is not a nop, it still may
+       raise exceptions.  */
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    /* No need to set flushzero, since we have an integer output.  */
+    gen_fp_exc_clear();
+    vb = gen_ieee_input(rb, fn11, 0);
+
+    /* Almost all integer conversions use cropped rounding, and most
+       also do not have integer overflow enabled.  Special case that.  */
+    switch (fn11) {
+    case QUAL_RM_C:
+        gen_helper_cvttq_c(cpu_fir[rc], vb);
+        break;
+    case QUAL_V | QUAL_RM_C:
+    case QUAL_S | QUAL_V | QUAL_RM_C:
+        ignore = float_flag_inexact;
+        /* FALLTHRU */
+    case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
+        gen_helper_cvttq_svic(cpu_fir[rc], vb);
+        break;
+    default:
+        gen_qual_roundmode(ctx, fn11);
+        gen_helper_cvttq(cpu_fir[rc], vb);
+        ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow);
+        ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact);
+        break;
+    }
+    tcg_temp_free(vb);
+
+    gen_fp_exc_raise_ignore(rc, fn11, ignore);
+}
+
+static void gen_ieee_intcvt(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+			    int rb, int rc, int fn11)
+{
+    TCGv vb;
+
+    /* ??? This is wrong: the instruction is not a nop, it still may
+       raise exceptions.  */
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    gen_qual_roundmode(ctx, fn11);
+
+    if (rb == 31) {
+        vb = tcg_const_i64(0);
+    } else {
+        vb = cpu_fir[rb];
+    }
+
+    /* The only exception that can be raised by integer conversion
+       is inexact.  Thus we only need to worry about exceptions when
+       inexact handling is requested.  */
+    if (fn11 & QUAL_I) {
+        gen_fp_exc_clear();
+        helper(cpu_fir[rc], vb);
+        gen_fp_exc_raise(rc, fn11);
+    } else {
+        helper(cpu_fir[rc], vb);
+    }
+
+    if (rb == 31) {
+        tcg_temp_free(vb);
+    }
+}
+
+#define IEEE_INTCVT(name)                                       \
+static inline void glue(gen_f, name)(DisasContext *ctx,         \
+                                     int rb, int rc, int fn11)  \
+{                                                               \
+    gen_ieee_intcvt(ctx, gen_helper_##name, rb, rc, fn11);      \
+}
+IEEE_INTCVT(cvtqs)
+IEEE_INTCVT(cvtqt)
+
+static void gen_cpys_internal(int ra, int rb, int rc, int inv_a, uint64_t mask)
+{
+    TCGv va, vb, vmask;
+    int za = 0, zb = 0;
+
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    vmask = tcg_const_i64(mask);
+
+    TCGV_UNUSED_I64(va);
+    if (ra == 31) {
+        if (inv_a) {
+            va = vmask;
+        } else {
+            za = 1;
+        }
+    } else {
+        va = tcg_temp_new_i64();
+        tcg_gen_mov_i64(va, cpu_fir[ra]);
+        if (inv_a) {
+            tcg_gen_andc_i64(va, vmask, va);
+        } else {
+            tcg_gen_and_i64(va, va, vmask);
+        }
+    }
+
+    TCGV_UNUSED_I64(vb);
+    if (rb == 31) {
+        zb = 1;
+    } else {
+        vb = tcg_temp_new_i64();
+        tcg_gen_andc_i64(vb, cpu_fir[rb], vmask);
+    }
+
+    switch (za << 1 | zb) {
+    case 0 | 0:
+        tcg_gen_or_i64(cpu_fir[rc], va, vb);
+        break;
+    case 0 | 1:
+        tcg_gen_mov_i64(cpu_fir[rc], va);
+        break;
+    case 2 | 0:
+        tcg_gen_mov_i64(cpu_fir[rc], vb);
+        break;
+    case 2 | 1:
+        tcg_gen_movi_i64(cpu_fir[rc], 0);
+        break;
+    }
+
+    tcg_temp_free(vmask);
+    if (ra != 31) {
+        tcg_temp_free(va);
+    }
+    if (rb != 31) {
+        tcg_temp_free(vb);
+    }
+}
+
+static inline void gen_fcpys(int ra, int rb, int rc)
+{
+    gen_cpys_internal(ra, rb, rc, 0, 0x8000000000000000ULL);
+}
+
+static inline void gen_fcpysn(int ra, int rb, int rc)
+{
+    gen_cpys_internal(ra, rb, rc, 1, 0x8000000000000000ULL);
+}
+
+static inline void gen_fcpyse(int ra, int rb, int rc)
+{
+    gen_cpys_internal(ra, rb, rc, 0, 0xFFF0000000000000ULL);
+}
+
+#define FARITH3(name)                                           \
+static inline void glue(gen_f, name)(int ra, int rb, int rc)    \
+{                                                               \
+    TCGv va, vb;                                                \
+                                                                \
+    if (unlikely(rc == 31)) {                                   \
+        return;                                                 \
+    }                                                           \
+    if (ra == 31) {                                             \
+        va = tcg_const_i64(0);                                  \
+    } else {                                                    \
+        va = cpu_fir[ra];                                       \
+    }                                                           \
+    if (rb == 31) {                                             \
+        vb = tcg_const_i64(0);                                  \
+    } else {                                                    \
+        vb = cpu_fir[rb];                                       \
+    }                                                           \
+                                                                \
+    gen_helper_ ## name (cpu_fir[rc], va, vb);                  \
+                                                                \
+    if (ra == 31) {                                             \
+        tcg_temp_free(va);                                      \
+    }                                                           \
+    if (rb == 31) {                                             \
+        tcg_temp_free(vb);                                      \
+    }                                                           \
+}
+
+/* ??? VAX instruction qualifiers ignored.  */
+FARITH3(addf)
+FARITH3(subf)
+FARITH3(mulf)
+FARITH3(divf)
+FARITH3(addg)
+FARITH3(subg)
+FARITH3(mulg)
+FARITH3(divg)
+FARITH3(cmpgeq)
+FARITH3(cmpglt)
+FARITH3(cmpgle)
+
+static void gen_ieee_arith3(DisasContext *ctx,
+                            void (*helper)(TCGv, TCGv, TCGv),
+                            int ra, int rb, int rc, int fn11)
+{
+    TCGv va, vb;
+
+    /* ??? This is wrong: the instruction is not a nop, it still may
+       raise exceptions.  */
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    gen_qual_roundmode(ctx, fn11);
+    gen_qual_flushzero(ctx, fn11);
+    gen_fp_exc_clear();
+
+    va = gen_ieee_input(ra, fn11, 0);
+    vb = gen_ieee_input(rb, fn11, 0);
+    helper(cpu_fir[rc], va, vb);
+    tcg_temp_free(va);
+    tcg_temp_free(vb);
+
+    gen_fp_exc_raise(rc, fn11);
+}
+
+#define IEEE_ARITH3(name)                                               \
+static inline void glue(gen_f, name)(DisasContext *ctx,                 \
+                                     int ra, int rb, int rc, int fn11)  \
+{                                                                       \
+    gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc, fn11);          \
+}
+IEEE_ARITH3(adds)
+IEEE_ARITH3(subs)
+IEEE_ARITH3(muls)
+IEEE_ARITH3(divs)
+IEEE_ARITH3(addt)
+IEEE_ARITH3(subt)
+IEEE_ARITH3(mult)
+IEEE_ARITH3(divt)
+
+static void gen_ieee_compare(DisasContext *ctx,
+                             void (*helper)(TCGv, TCGv, TCGv),
+                             int ra, int rb, int rc, int fn11)
+{
+    TCGv va, vb;
+
+    /* ??? This is wrong: the instruction is not a nop, it still may
+       raise exceptions.  */
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    gen_fp_exc_clear();
+
+    va = gen_ieee_input(ra, fn11, 1);
+    vb = gen_ieee_input(rb, fn11, 1);
+    helper(cpu_fir[rc], va, vb);
+    tcg_temp_free(va);
+    tcg_temp_free(vb);
+
+    gen_fp_exc_raise(rc, fn11);
+}
+
+#define IEEE_CMP3(name)                                                 \
+static inline void glue(gen_f, name)(DisasContext *ctx,                 \
+                                     int ra, int rb, int rc, int fn11)  \
+{                                                                       \
+    gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc, fn11);         \
+}
+IEEE_CMP3(cmptun)
+IEEE_CMP3(cmpteq)
+IEEE_CMP3(cmptlt)
+IEEE_CMP3(cmptle)
+
+static inline uint64_t zapnot_mask(uint8_t lit)
+{
+    uint64_t mask = 0;
+    int i;
+
+    for (i = 0; i < 8; ++i) {
+        if ((lit >> i) & 1)
+            mask |= 0xffull << (i * 8);
+    }
+    return mask;
+}
+
+/* Implement zapnot with an immediate operand, which expands to some
+   form of immediate AND.  This is a basic building block in the
+   definition of many of the other byte manipulation instructions.  */
+static void gen_zapnoti(TCGv dest, TCGv src, uint8_t lit)
+{
+    switch (lit) {
+    case 0x00:
+        tcg_gen_movi_i64(dest, 0);
+        break;
+    case 0x01:
+        tcg_gen_ext8u_i64(dest, src);
+        break;
+    case 0x03:
+        tcg_gen_ext16u_i64(dest, src);
+        break;
+    case 0x0f:
+        tcg_gen_ext32u_i64(dest, src);
+        break;
+    case 0xff:
+        tcg_gen_mov_i64(dest, src);
+        break;
+    default:
+        tcg_gen_andi_i64 (dest, src, zapnot_mask (lit));
+        break;
+    }
+}
+
+static inline void gen_zapnot(int ra, int rb, int rc, int islit, uint8_t lit)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else if (islit)
+        gen_zapnoti(cpu_ir[rc], cpu_ir[ra], lit);
+    else
+        gen_helper_zapnot (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+}
+
+static inline void gen_zap(int ra, int rb, int rc, int islit, uint8_t lit)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else if (islit)
+        gen_zapnoti(cpu_ir[rc], cpu_ir[ra], ~lit);
+    else
+        gen_helper_zap (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+}
+
+
+/* EXTWH, EXTLH, EXTQH */
+static void gen_ext_h(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else {
+        if (islit) {
+            lit = (64 - (lit & 7) * 8) & 0x3f;
+            tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], lit);
+        } else {
+            TCGv tmp1 = tcg_temp_new();
+            tcg_gen_andi_i64(tmp1, cpu_ir[rb], 7);
+            tcg_gen_shli_i64(tmp1, tmp1, 3);
+            tcg_gen_neg_i64(tmp1, tmp1);
+            tcg_gen_andi_i64(tmp1, tmp1, 0x3f);
+            tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], tmp1);
+            tcg_temp_free(tmp1);
+        }
+        gen_zapnoti(cpu_ir[rc], cpu_ir[rc], byte_mask);
+    }
+}
+
+/* EXTBL, EXTWL, EXTLL, EXTQL */
+static void gen_ext_l(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else {
+        if (islit) {
+            tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], (lit & 7) * 8);
+        } else {
+            TCGv tmp = tcg_temp_new();
+            tcg_gen_andi_i64(tmp, cpu_ir[rb], 7);
+            tcg_gen_shli_i64(tmp, tmp, 3);
+            tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], tmp);
+            tcg_temp_free(tmp);
+        }
+        gen_zapnoti(cpu_ir[rc], cpu_ir[rc], byte_mask);
+    }
+}
+
+/* INSWH, INSLH, INSQH */
+static void gen_ins_h(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31) || (islit && (lit & 7) == 0))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else {
+        TCGv tmp = tcg_temp_new();
+
+        /* The instruction description has us left-shift the byte mask
+           and extract bits <15:8> and apply that zap at the end.  This
+           is equivalent to simply performing the zap first and shifting
+           afterward.  */
+        gen_zapnoti (tmp, cpu_ir[ra], byte_mask);
+
+        if (islit) {
+            /* Note that we have handled the lit==0 case above.  */
+            tcg_gen_shri_i64 (cpu_ir[rc], tmp, 64 - (lit & 7) * 8);
+        } else {
+            TCGv shift = tcg_temp_new();
+
+            /* If (B & 7) == 0, we need to shift by 64 and leave a zero.
+               Do this portably by splitting the shift into two parts:
+               shift_count-1 and 1.  Arrange for the -1 by using
+               ones-complement instead of twos-complement in the negation:
+               ~((B & 7) * 8) & 63.  */
+
+            tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
+            tcg_gen_shli_i64(shift, shift, 3);
+            tcg_gen_not_i64(shift, shift);
+            tcg_gen_andi_i64(shift, shift, 0x3f);
+
+            tcg_gen_shr_i64(cpu_ir[rc], tmp, shift);
+            tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[rc], 1);
+            tcg_temp_free(shift);
+        }
+        tcg_temp_free(tmp);
+    }
+}
+
+/* INSBL, INSWL, INSLL, INSQL */
+static void gen_ins_l(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else {
+        TCGv tmp = tcg_temp_new();
+
+        /* The instruction description has us left-shift the byte mask
+           the same number of byte slots as the data and apply the zap
+           at the end.  This is equivalent to simply performing the zap
+           first and shifting afterward.  */
+        gen_zapnoti (tmp, cpu_ir[ra], byte_mask);
+
+        if (islit) {
+            tcg_gen_shli_i64(cpu_ir[rc], tmp, (lit & 7) * 8);
+        } else {
+            TCGv shift = tcg_temp_new();
+            tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
+            tcg_gen_shli_i64(shift, shift, 3);
+            tcg_gen_shl_i64(cpu_ir[rc], tmp, shift);
+            tcg_temp_free(shift);
+        }
+        tcg_temp_free(tmp);
+    }
+}
+
+/* MSKWH, MSKLH, MSKQH */
+static void gen_msk_h(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else if (islit) {
+        gen_zapnoti (cpu_ir[rc], cpu_ir[ra], ~((byte_mask << (lit & 7)) >> 8));
+    } else {
+        TCGv shift = tcg_temp_new();
+        TCGv mask = tcg_temp_new();
+
+        /* The instruction description is as above, where the byte_mask
+           is shifted left, and then we extract bits <15:8>.  This can be
+           emulated with a right-shift on the expanded byte mask.  This
+           requires extra care because for an input <2:0> == 0 we need a
+           shift of 64 bits in order to generate a zero.  This is done by
+           splitting the shift into two parts, the variable shift - 1
+           followed by a constant 1 shift.  The code we expand below is
+           equivalent to ~((B & 7) * 8) & 63.  */
+
+        tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
+        tcg_gen_shli_i64(shift, shift, 3);
+        tcg_gen_not_i64(shift, shift);
+        tcg_gen_andi_i64(shift, shift, 0x3f);
+        tcg_gen_movi_i64(mask, zapnot_mask (byte_mask));
+        tcg_gen_shr_i64(mask, mask, shift);
+        tcg_gen_shri_i64(mask, mask, 1);
+
+        tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], mask);
+
+        tcg_temp_free(mask);
+        tcg_temp_free(shift);
+    }
+}
+
+/* MSKBL, MSKWL, MSKLL, MSKQL */
+static void gen_msk_l(int ra, int rb, int rc, int islit,
+                      uint8_t lit, uint8_t byte_mask)
+{
+    if (unlikely(rc == 31))
+        return;
+    else if (unlikely(ra == 31))
+        tcg_gen_movi_i64(cpu_ir[rc], 0);
+    else if (islit) {
+        gen_zapnoti (cpu_ir[rc], cpu_ir[ra], ~(byte_mask << (lit & 7)));
+    } else {
+        TCGv shift = tcg_temp_new();
+        TCGv mask = tcg_temp_new();
+
+        tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
+        tcg_gen_shli_i64(shift, shift, 3);
+        tcg_gen_movi_i64(mask, zapnot_mask (byte_mask));
+        tcg_gen_shl_i64(mask, mask, shift);
+
+        tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], mask);
+
+        tcg_temp_free(mask);
+        tcg_temp_free(shift);
+    }
+}
+
+/* Code to call arith3 helpers */
+#define ARITH3(name)                                                  \
+static inline void glue(gen_, name)(int ra, int rb, int rc, int islit,\
+                                    uint8_t lit)                      \
+{                                                                     \
+    if (unlikely(rc == 31))                                           \
+        return;                                                       \
+                                                                      \
+    if (ra != 31) {                                                   \
+        if (islit) {                                                  \
+            TCGv tmp = tcg_const_i64(lit);                            \
+            gen_helper_ ## name(cpu_ir[rc], cpu_ir[ra], tmp);         \
+            tcg_temp_free(tmp);                                       \
+        } else                                                        \
+            gen_helper_ ## name (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); \
+    } else {                                                          \
+        TCGv tmp1 = tcg_const_i64(0);                                 \
+        if (islit) {                                                  \
+            TCGv tmp2 = tcg_const_i64(lit);                           \
+            gen_helper_ ## name (cpu_ir[rc], tmp1, tmp2);             \
+            tcg_temp_free(tmp2);                                      \
+        } else                                                        \
+            gen_helper_ ## name (cpu_ir[rc], tmp1, cpu_ir[rb]);       \
+        tcg_temp_free(tmp1);                                          \
+    }                                                                 \
+}
+ARITH3(cmpbge)
+ARITH3(addlv)
+ARITH3(sublv)
+ARITH3(addqv)
+ARITH3(subqv)
+ARITH3(umulh)
+ARITH3(mullv)
+ARITH3(mulqv)
+ARITH3(minub8)
+ARITH3(minsb8)
+ARITH3(minuw4)
+ARITH3(minsw4)
+ARITH3(maxub8)
+ARITH3(maxsb8)
+ARITH3(maxuw4)
+ARITH3(maxsw4)
+ARITH3(perr)
+
+#define MVIOP2(name)                                    \
+static inline void glue(gen_, name)(int rb, int rc)     \
+{                                                       \
+    if (unlikely(rc == 31))                             \
+        return;                                         \
+    if (unlikely(rb == 31))                             \
+        tcg_gen_movi_i64(cpu_ir[rc], 0);                \
+    else                                                \
+        gen_helper_ ## name (cpu_ir[rc], cpu_ir[rb]);   \
+}
+MVIOP2(pklb)
+MVIOP2(pkwb)
+MVIOP2(unpkbl)
+MVIOP2(unpkbw)
+
+static void gen_cmp(TCGCond cond, int ra, int rb, int rc,
+                    int islit, uint8_t lit)
+{
+    TCGv va, vb;
+
+    if (unlikely(rc == 31)) {
+        return;
+    }
+
+    if (ra == 31) {
+        va = tcg_const_i64(0);
+    } else {
+        va = cpu_ir[ra];
+    }
+    if (islit) {
+        vb = tcg_const_i64(lit);
+    } else {
+        vb = cpu_ir[rb];
+    }
+
+    tcg_gen_setcond_i64(cond, cpu_ir[rc], va, vb);
+
+    if (ra == 31) {
+        tcg_temp_free(va);
+    }
+    if (islit) {
+        tcg_temp_free(vb);
+    }
+}
+
+static void gen_rx(int ra, int set)
+{
+    TCGv_i32 tmp;
+
+    if (ra != 31) {
+        tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, offsetof(CPUState, intr_flag));
+    }
+
+    tmp = tcg_const_i32(set);
+    tcg_gen_st8_i32(tmp, cpu_env, offsetof(CPUState, intr_flag));
+    tcg_temp_free_i32(tmp);
+}
+
+static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
+{
+    /* We're emulating OSF/1 PALcode.  Many of these are trivial access
+       to internal cpu registers.  */
+
+    /* Unprivileged PAL call */
+    if (palcode >= 0x80 && palcode < 0xC0) {
+        switch (palcode) {
+        case 0x86:
+            /* IMB */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x9E:
+            /* RDUNIQUE */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
+            break;
+        case 0x9F:
+            /* WRUNIQUE */
+            tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
+            break;
+        default:
+            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+        }
+        return NO_EXIT;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    /* Privileged PAL code */
+    if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
+        switch (palcode) {
+        case 0x01:
+            /* CFLUSH */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x02:
+            /* DRAINA */
+            /* No-op inside QEMU.  */
+            break;
+        case 0x2D:
+            /* WRVPTPTR */
+            tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUState, vptptr));
+            break;
+        case 0x31:
+            /* WRVAL */
+            tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
+            break;
+        case 0x32:
+            /* RDVAL */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
+            break;
+
+        case 0x35: {
+            /* SWPIPL */
+            TCGv tmp;
+
+            /* Note that we already know we're in kernel mode, so we know
+               that PS only contains the 3 IPL bits.  */
+            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+
+            /* But make sure and store only the 3 IPL bits from the user.  */
+            tmp = tcg_temp_new();
+            tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
+            tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUState, ps));
+            tcg_temp_free(tmp);
+            break;
+        }
+
+        case 0x36:
+            /* RDPS */
+            tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+            break;
+        case 0x38:
+            /* WRUSP */
+            tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
+            break;
+        case 0x3A:
+            /* RDUSP */
+            tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
+            break;
+        case 0x3C:
+            /* WHAMI */
+            tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
+                              offsetof(CPUState, cpu_index));
+            break;
+
+        default:
+            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+        }
+        return NO_EXIT;
+    }
+#endif
+
+    return gen_invalid(ctx);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+#define PR_BYTE         0x100000
+#define PR_LONG         0x200000
+
+static int cpu_pr_data(int pr)
+{
+    switch (pr) {
+    case  0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
+    case  1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
+    case  2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
+    case  3: return offsetof(CPUAlphaState, trap_arg0);
+    case  4: return offsetof(CPUAlphaState, trap_arg1);
+    case  5: return offsetof(CPUAlphaState, trap_arg2);
+    case  6: return offsetof(CPUAlphaState, exc_addr);
+    case  7: return offsetof(CPUAlphaState, palbr);
+    case  8: return offsetof(CPUAlphaState, ptbr);
+    case  9: return offsetof(CPUAlphaState, vptptr);
+    case 10: return offsetof(CPUAlphaState, unique);
+    case 11: return offsetof(CPUAlphaState, sysval);
+    case 12: return offsetof(CPUAlphaState, usp);
+
+    case 32 ... 39:
+        return offsetof(CPUAlphaState, shadow[pr - 32]);
+    case 40 ... 63:
+        return offsetof(CPUAlphaState, scratch[pr - 40]);
+    }
+    return 0;
+}
+
+static void gen_mfpr(int ra, int regno)
+{
+    int data = cpu_pr_data(regno);
+
+    /* In our emulated PALcode, these processor registers have no
+       side effects from reading.  */
+    if (ra == 31) {
+        return;
+    }
+
+    /* The basic registers are data only, and unknown registers
+       are read-zero, write-ignore.  */
+    if (data == 0) {
+        tcg_gen_movi_i64(cpu_ir[ra], 0);
+    } else if (data & PR_BYTE) {
+        tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
+    } else if (data & PR_LONG) {
+        tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
+    } else {
+        tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
+    }
+}
+
+static void gen_mtpr(int rb, int regno)
+{
+    TCGv tmp;
+
+    if (rb == 31) {
+        tmp = tcg_const_i64(0);
+    } else {
+        tmp = cpu_ir[rb];
+    }
+
+    /* These two register numbers perform a TLB cache flush.  Thankfully we
+       can only do this inside PALmode, which means that the current basic
+       block cannot be affected by the change in mappings.  */
+    if (regno == 255) {
+        /* TBIA */
+        gen_helper_tbia();
+    } else if (regno == 254) {
+        /* TBIS */
+        gen_helper_tbis(tmp);
+    } else {
+        /* The basic registers are data only, and unknown registers
+           are read-zero, write-ignore.  */
+        int data = cpu_pr_data(regno);
+        if (data != 0) {
+            if (data & PR_BYTE) {
+                tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+            } else if (data & PR_LONG) {
+                tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+            } else {
+                tcg_gen_st_i64(tmp, cpu_env, data);
+            }
+        }
+    }
+
+    if (rb == 31) {
+        tcg_temp_free(tmp);
+    }
+}
+#endif /* !USER_ONLY*/
+
+static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
+{
+    uint32_t palcode;
+    int32_t disp21, disp16;
+#ifndef CONFIG_USER_ONLY
+    int32_t disp12;
+#endif
+    uint16_t fn11;
+    uint8_t opc, ra, rb, rc, fpfn, fn7, islit, real_islit;
+    uint8_t lit;
+    ExitStatus ret;
+
+    /* Decode all instruction fields */
+    opc = insn >> 26;
+    ra = (insn >> 21) & 0x1F;
+    rb = (insn >> 16) & 0x1F;
+    rc = insn & 0x1F;
+    real_islit = islit = (insn >> 12) & 1;
+    if (rb == 31 && !islit) {
+        islit = 1;
+        lit = 0;
+    } else
+        lit = (insn >> 13) & 0xFF;
+    palcode = insn & 0x03FFFFFF;
+    disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
+    disp16 = (int16_t)(insn & 0x0000FFFF);
+#ifndef CONFIG_USER_ONLY
+    disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
+#endif
+    fn11 = (insn >> 5) & 0x000007FF;
+    fpfn = fn11 & 0x3F;
+    fn7 = (insn >> 5) & 0x0000007F;
+    LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
+              opc, ra, rb, rc, disp16);
+
+    ret = NO_EXIT;
+    switch (opc) {
+    case 0x00:
+        /* CALL_PAL */
+        ret = gen_call_pal(ctx, palcode);
+        break;
+    case 0x01:
+        /* OPC01 */
+        goto invalid_opc;
+    case 0x02:
+        /* OPC02 */
+        goto invalid_opc;
+    case 0x03:
+        /* OPC03 */
+        goto invalid_opc;
+    case 0x04:
+        /* OPC04 */
+        goto invalid_opc;
+    case 0x05:
+        /* OPC05 */
+        goto invalid_opc;
+    case 0x06:
+        /* OPC06 */
+        goto invalid_opc;
+    case 0x07:
+        /* OPC07 */
+        goto invalid_opc;
+    case 0x08:
+        /* LDA */
+        if (likely(ra != 31)) {
+            if (rb != 31)
+                tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16);
+            else
+                tcg_gen_movi_i64(cpu_ir[ra], disp16);
+        }
+        break;
+    case 0x09:
+        /* LDAH */
+        if (likely(ra != 31)) {
+            if (rb != 31)
+                tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16 << 16);
+            else
+                tcg_gen_movi_i64(cpu_ir[ra], disp16 << 16);
+        }
+        break;
+    case 0x0A:
+        /* LDBU */
+        if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+            gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
+            break;
+        }
+        goto invalid_opc;
+    case 0x0B:
+        /* LDQ_U */
+        gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1);
+        break;
+    case 0x0C:
+        /* LDWU */
+        if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+            gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
+            break;
+        }
+        goto invalid_opc;
+    case 0x0D:
+        /* STW */
+        gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0);
+        break;
+    case 0x0E:
+        /* STB */
+        gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0);
+        break;
+    case 0x0F:
+        /* STQ_U */
+        gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1);
+        break;
+    case 0x10:
+        switch (fn7) {
+        case 0x00:
+            /* ADDL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit) {
+                        tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                    } else {
+                        tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                    }
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x02:
+            /* S4ADDL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
+                    if (islit)
+                        tcg_gen_addi_i64(tmp, tmp, lit);
+                    else
+                        tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x09:
+            /* SUBL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else {
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                }
+            }
+            break;
+        case 0x0B:
+            /* S4SUBL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
+                    if (islit)
+                        tcg_gen_subi_i64(tmp, tmp, lit);
+                    else
+                        tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else {
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                    }
+                }
+            }
+            break;
+        case 0x0F:
+            /* CMPBGE */
+            gen_cmpbge(ra, rb, rc, islit, lit);
+            break;
+        case 0x12:
+            /* S8ADDL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
+                    if (islit)
+                        tcg_gen_addi_i64(tmp, tmp, lit);
+                    else
+                        tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x1B:
+            /* S8SUBL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
+                    if (islit)
+                        tcg_gen_subi_i64(tmp, tmp, lit);
+                    else
+                       tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                        tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                    }
+                }
+            }
+            break;
+        case 0x1D:
+            /* CMPULT */
+            gen_cmp(TCG_COND_LTU, ra, rb, rc, islit, lit);
+            break;
+        case 0x20:
+            /* ADDQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x22:
+            /* S4ADDQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
+                    if (islit)
+                        tcg_gen_addi_i64(cpu_ir[rc], tmp, lit);
+                    else
+                        tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x29:
+            /* SUBQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x2B:
+            /* S4SUBQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
+                    if (islit)
+                        tcg_gen_subi_i64(cpu_ir[rc], tmp, lit);
+                    else
+                        tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x2D:
+            /* CMPEQ */
+            gen_cmp(TCG_COND_EQ, ra, rb, rc, islit, lit);
+            break;
+        case 0x32:
+            /* S8ADDQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
+                    if (islit)
+                        tcg_gen_addi_i64(cpu_ir[rc], tmp, lit);
+                    else
+                        tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x3B:
+            /* S8SUBQ */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv tmp = tcg_temp_new();
+                    tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
+                    if (islit)
+                        tcg_gen_subi_i64(cpu_ir[rc], tmp, lit);
+                    else
+                        tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
+                    tcg_temp_free(tmp);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], -lit);
+                    else
+                        tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x3D:
+            /* CMPULE */
+            gen_cmp(TCG_COND_LEU, ra, rb, rc, islit, lit);
+            break;
+        case 0x40:
+            /* ADDL/V */
+            gen_addlv(ra, rb, rc, islit, lit);
+            break;
+        case 0x49:
+            /* SUBL/V */
+            gen_sublv(ra, rb, rc, islit, lit);
+            break;
+        case 0x4D:
+            /* CMPLT */
+            gen_cmp(TCG_COND_LT, ra, rb, rc, islit, lit);
+            break;
+        case 0x60:
+            /* ADDQ/V */
+            gen_addqv(ra, rb, rc, islit, lit);
+            break;
+        case 0x69:
+            /* SUBQ/V */
+            gen_subqv(ra, rb, rc, islit, lit);
+            break;
+        case 0x6D:
+            /* CMPLE */
+            gen_cmp(TCG_COND_LE, ra, rb, rc, islit, lit);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x11:
+        switch (fn7) {
+        case 0x00:
+            /* AND */
+            if (likely(rc != 31)) {
+                if (ra == 31)
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+                else if (islit)
+                    tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                else
+                    tcg_gen_and_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+            }
+            break;
+        case 0x08:
+            /* BIC */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
+                    else
+                        tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+            }
+            break;
+        case 0x14:
+            /* CMOVLBS */
+            gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 1);
+            break;
+        case 0x16:
+            /* CMOVLBC */
+            gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 1);
+            break;
+        case 0x20:
+            /* BIS */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_or_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x24:
+            /* CMOVEQ */
+            gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x26:
+            /* CMOVNE */
+            gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x28:
+            /* ORNOT */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
+                    else
+                        tcg_gen_orc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], ~lit);
+                    else
+                        tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x40:
+            /* XOR */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_xor_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], lit);
+                    else
+                        tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x44:
+            /* CMOVLT */
+            gen_cmov(TCG_COND_LT, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x46:
+            /* CMOVGE */
+            gen_cmov(TCG_COND_GE, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x48:
+            /* EQV */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
+                    else
+                        tcg_gen_eqv_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                } else {
+                    if (islit)
+                        tcg_gen_movi_i64(cpu_ir[rc], ~lit);
+                    else
+                        tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]);
+                }
+            }
+            break;
+        case 0x61:
+            /* AMASK */
+            if (likely(rc != 31)) {
+                uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT;
+
+                if (islit) {
+                    tcg_gen_movi_i64(cpu_ir[rc], lit & ~amask);
+                } else {
+                    tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rb], ~amask);
+                }
+            }
+            break;
+        case 0x64:
+            /* CMOVLE */
+            gen_cmov(TCG_COND_LE, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x66:
+            /* CMOVGT */
+            gen_cmov(TCG_COND_GT, ra, rb, rc, islit, lit, 0);
+            break;
+        case 0x6C:
+            /* IMPLVER */
+            if (rc != 31)
+                tcg_gen_movi_i64(cpu_ir[rc], ctx->env->implver);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x12:
+        switch (fn7) {
+        case 0x02:
+            /* MSKBL */
+            gen_msk_l(ra, rb, rc, islit, lit, 0x01);
+            break;
+        case 0x06:
+            /* EXTBL */
+            gen_ext_l(ra, rb, rc, islit, lit, 0x01);
+            break;
+        case 0x0B:
+            /* INSBL */
+            gen_ins_l(ra, rb, rc, islit, lit, 0x01);
+            break;
+        case 0x12:
+            /* MSKWL */
+            gen_msk_l(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x16:
+            /* EXTWL */
+            gen_ext_l(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x1B:
+            /* INSWL */
+            gen_ins_l(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x22:
+            /* MSKLL */
+            gen_msk_l(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x26:
+            /* EXTLL */
+            gen_ext_l(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x2B:
+            /* INSLL */
+            gen_ins_l(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x30:
+            /* ZAP */
+            gen_zap(ra, rb, rc, islit, lit);
+            break;
+        case 0x31:
+            /* ZAPNOT */
+            gen_zapnot(ra, rb, rc, islit, lit);
+            break;
+        case 0x32:
+            /* MSKQL */
+            gen_msk_l(ra, rb, rc, islit, lit, 0xff);
+            break;
+        case 0x34:
+            /* SRL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
+                    else {
+                        TCGv shift = tcg_temp_new();
+                        tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
+                        tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], shift);
+                        tcg_temp_free(shift);
+                    }
+                } else
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+            }
+            break;
+        case 0x36:
+            /* EXTQL */
+            gen_ext_l(ra, rb, rc, islit, lit, 0xff);
+            break;
+        case 0x39:
+            /* SLL */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
+                    else {
+                        TCGv shift = tcg_temp_new();
+                        tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
+                        tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], shift);
+                        tcg_temp_free(shift);
+                    }
+                } else
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+            }
+            break;
+        case 0x3B:
+            /* INSQL */
+            gen_ins_l(ra, rb, rc, islit, lit, 0xff);
+            break;
+        case 0x3C:
+            /* SRA */
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    if (islit)
+                        tcg_gen_sari_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
+                    else {
+                        TCGv shift = tcg_temp_new();
+                        tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
+                        tcg_gen_sar_i64(cpu_ir[rc], cpu_ir[ra], shift);
+                        tcg_temp_free(shift);
+                    }
+                } else
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+            }
+            break;
+        case 0x52:
+            /* MSKWH */
+            gen_msk_h(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x57:
+            /* INSWH */
+            gen_ins_h(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x5A:
+            /* EXTWH */
+            gen_ext_h(ra, rb, rc, islit, lit, 0x03);
+            break;
+        case 0x62:
+            /* MSKLH */
+            gen_msk_h(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x67:
+            /* INSLH */
+            gen_ins_h(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x6A:
+            /* EXTLH */
+            gen_ext_h(ra, rb, rc, islit, lit, 0x0f);
+            break;
+        case 0x72:
+            /* MSKQH */
+            gen_msk_h(ra, rb, rc, islit, lit, 0xff);
+            break;
+        case 0x77:
+            /* INSQH */
+            gen_ins_h(ra, rb, rc, islit, lit, 0xff);
+            break;
+        case 0x7A:
+            /* EXTQH */
+            gen_ext_h(ra, rb, rc, islit, lit, 0xff);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x13:
+        switch (fn7) {
+        case 0x00:
+            /* MULL */
+            if (likely(rc != 31)) {
+                if (ra == 31)
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+                else {
+                    if (islit)
+                        tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                    else
+                        tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+                    tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
+                }
+            }
+            break;
+        case 0x20:
+            /* MULQ */
+            if (likely(rc != 31)) {
+                if (ra == 31)
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+                else if (islit)
+                    tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit);
+                else
+                    tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
+            }
+            break;
+        case 0x30:
+            /* UMULH */
+            gen_umulh(ra, rb, rc, islit, lit);
+            break;
+        case 0x40:
+            /* MULL/V */
+            gen_mullv(ra, rb, rc, islit, lit);
+            break;
+        case 0x60:
+            /* MULQ/V */
+            gen_mulqv(ra, rb, rc, islit, lit);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x14:
+        switch (fpfn) { /* fn11 & 0x3F */
+        case 0x04:
+            /* ITOFS */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
+                goto invalid_opc;
+            }
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]);
+                    gen_helper_memory_to_s(cpu_fir[rc], tmp);
+                    tcg_temp_free_i32(tmp);
+                } else
+                    tcg_gen_movi_i64(cpu_fir[rc], 0);
+            }
+            break;
+        case 0x0A:
+            /* SQRTF */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtf(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x0B:
+            /* SQRTS */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrts(ctx, rb, rc, fn11);
+                break;
+            }
+            goto invalid_opc;
+        case 0x14:
+            /* ITOFF */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
+                goto invalid_opc;
+            }
+            if (likely(rc != 31)) {
+                if (ra != 31) {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]);
+                    gen_helper_memory_to_f(cpu_fir[rc], tmp);
+                    tcg_temp_free_i32(tmp);
+                } else
+                    tcg_gen_movi_i64(cpu_fir[rc], 0);
+            }
+            break;
+        case 0x24:
+            /* ITOFT */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
+                goto invalid_opc;
+            }
+            if (likely(rc != 31)) {
+                if (ra != 31)
+                    tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]);
+                else
+                    tcg_gen_movi_i64(cpu_fir[rc], 0);
+            }
+            break;
+        case 0x2A:
+            /* SQRTG */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtg(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x02B:
+            /* SQRTT */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+                gen_fsqrtt(ctx, rb, rc, fn11);
+                break;
+            }
+            goto invalid_opc;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x15:
+        /* VAX floating point */
+        /* XXX: rounding mode and trap are ignored (!) */
+        switch (fpfn) { /* fn11 & 0x3F */
+        case 0x00:
+            /* ADDF */
+            gen_faddf(ra, rb, rc);
+            break;
+        case 0x01:
+            /* SUBF */
+            gen_fsubf(ra, rb, rc);
+            break;
+        case 0x02:
+            /* MULF */
+            gen_fmulf(ra, rb, rc);
+            break;
+        case 0x03:
+            /* DIVF */
+            gen_fdivf(ra, rb, rc);
+            break;
+        case 0x1E:
+            /* CVTDG */
+#if 0 // TODO
+            gen_fcvtdg(rb, rc);
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0x20:
+            /* ADDG */
+            gen_faddg(ra, rb, rc);
+            break;
+        case 0x21:
+            /* SUBG */
+            gen_fsubg(ra, rb, rc);
+            break;
+        case 0x22:
+            /* MULG */
+            gen_fmulg(ra, rb, rc);
+            break;
+        case 0x23:
+            /* DIVG */
+            gen_fdivg(ra, rb, rc);
+            break;
+        case 0x25:
+            /* CMPGEQ */
+            gen_fcmpgeq(ra, rb, rc);
+            break;
+        case 0x26:
+            /* CMPGLT */
+            gen_fcmpglt(ra, rb, rc);
+            break;
+        case 0x27:
+            /* CMPGLE */
+            gen_fcmpgle(ra, rb, rc);
+            break;
+        case 0x2C:
+            /* CVTGF */
+            gen_fcvtgf(rb, rc);
+            break;
+        case 0x2D:
+            /* CVTGD */
+#if 0 // TODO
+            gen_fcvtgd(rb, rc);
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0x2F:
+            /* CVTGQ */
+            gen_fcvtgq(rb, rc);
+            break;
+        case 0x3C:
+            /* CVTQF */
+            gen_fcvtqf(rb, rc);
+            break;
+        case 0x3E:
+            /* CVTQG */
+            gen_fcvtqg(rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x16:
+        /* IEEE floating-point */
+        switch (fpfn) { /* fn11 & 0x3F */
+        case 0x00:
+            /* ADDS */
+            gen_fadds(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x01:
+            /* SUBS */
+            gen_fsubs(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x02:
+            /* MULS */
+            gen_fmuls(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x03:
+            /* DIVS */
+            gen_fdivs(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x20:
+            /* ADDT */
+            gen_faddt(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x21:
+            /* SUBT */
+            gen_fsubt(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x22:
+            /* MULT */
+            gen_fmult(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x23:
+            /* DIVT */
+            gen_fdivt(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x24:
+            /* CMPTUN */
+            gen_fcmptun(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x25:
+            /* CMPTEQ */
+            gen_fcmpteq(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x26:
+            /* CMPTLT */
+            gen_fcmptlt(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x27:
+            /* CMPTLE */
+            gen_fcmptle(ctx, ra, rb, rc, fn11);
+            break;
+        case 0x2C:
+            if (fn11 == 0x2AC || fn11 == 0x6AC) {
+                /* CVTST */
+                gen_fcvtst(ctx, rb, rc, fn11);
+            } else {
+                /* CVTTS */
+                gen_fcvtts(ctx, rb, rc, fn11);
+            }
+            break;
+        case 0x2F:
+            /* CVTTQ */
+            gen_fcvttq(ctx, rb, rc, fn11);
+            break;
+        case 0x3C:
+            /* CVTQS */
+            gen_fcvtqs(ctx, rb, rc, fn11);
+            break;
+        case 0x3E:
+            /* CVTQT */
+            gen_fcvtqt(ctx, rb, rc, fn11);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x17:
+        switch (fn11) {
+        case 0x010:
+            /* CVTLQ */
+            gen_fcvtlq(rb, rc);
+            break;
+        case 0x020:
+            if (likely(rc != 31)) {
+                if (ra == rb) {
+                    /* FMOV */
+                    if (ra == 31)
+                        tcg_gen_movi_i64(cpu_fir[rc], 0);
+                    else
+                        tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]);
+                } else {
+                    /* CPYS */
+                    gen_fcpys(ra, rb, rc);
+                }
+            }
+            break;
+        case 0x021:
+            /* CPYSN */
+            gen_fcpysn(ra, rb, rc);
+            break;
+        case 0x022:
+            /* CPYSE */
+            gen_fcpyse(ra, rb, rc);
+            break;
+        case 0x024:
+            /* MT_FPCR */
+            if (likely(ra != 31))
+                gen_helper_store_fpcr(cpu_fir[ra]);
+            else {
+                TCGv tmp = tcg_const_i64(0);
+                gen_helper_store_fpcr(tmp);
+                tcg_temp_free(tmp);
+            }
+            break;
+        case 0x025:
+            /* MF_FPCR */
+            if (likely(ra != 31))
+                gen_helper_load_fpcr(cpu_fir[ra]);
+            break;
+        case 0x02A:
+            /* FCMOVEQ */
+            gen_fcmov(TCG_COND_EQ, ra, rb, rc);
+            break;
+        case 0x02B:
+            /* FCMOVNE */
+            gen_fcmov(TCG_COND_NE, ra, rb, rc);
+            break;
+        case 0x02C:
+            /* FCMOVLT */
+            gen_fcmov(TCG_COND_LT, ra, rb, rc);
+            break;
+        case 0x02D:
+            /* FCMOVGE */
+            gen_fcmov(TCG_COND_GE, ra, rb, rc);
+            break;
+        case 0x02E:
+            /* FCMOVLE */
+            gen_fcmov(TCG_COND_LE, ra, rb, rc);
+            break;
+        case 0x02F:
+            /* FCMOVGT */
+            gen_fcmov(TCG_COND_GT, ra, rb, rc);
+            break;
+        case 0x030:
+            /* CVTQL */
+            gen_fcvtql(rb, rc);
+            break;
+        case 0x130:
+            /* CVTQL/V */
+        case 0x530:
+            /* CVTQL/SV */
+            /* ??? I'm pretty sure there's nothing that /sv needs to do that
+               /v doesn't do.  The only thing I can think is that /sv is a
+               valid instruction merely for completeness in the ISA.  */
+            gen_fcvtql_v(ctx, rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x18:
+        switch ((uint16_t)disp16) {
+        case 0x0000:
+            /* TRAPB */
+            /* No-op.  */
+            break;
+        case 0x0400:
+            /* EXCB */
+            /* No-op.  */
+            break;
+        case 0x4000:
+            /* MB */
+            /* No-op */
+            break;
+        case 0x4400:
+            /* WMB */
+            /* No-op */
+            break;
+        case 0x8000:
+            /* FETCH */
+            /* No-op */
+            break;
+        case 0xA000:
+            /* FETCH_M */
+            /* No-op */
+            break;
+        case 0xC000:
+            /* RPCC */
+            if (ra != 31)
+                gen_helper_load_pcc(cpu_ir[ra]);
+            break;
+        case 0xE000:
+            /* RC */
+            gen_rx(ra, 0);
+            break;
+        case 0xE800:
+            /* ECB */
+            break;
+        case 0xF000:
+            /* RS */
+            gen_rx(ra, 1);
+            break;
+        case 0xF800:
+            /* WH64 */
+            /* No-op */
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x19:
+        /* HW_MFPR (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            gen_mfpr(ra, insn & 0xffff);
+            break;
+        }
+#endif
+        goto invalid_opc;
+    case 0x1A:
+        /* JMP, JSR, RET, JSR_COROUTINE.  These only differ by the branch
+           prediction stack action, which of course we don't implement.  */
+        if (rb != 31) {
+            tcg_gen_andi_i64(cpu_pc, cpu_ir[rb], ~3);
+        } else {
+            tcg_gen_movi_i64(cpu_pc, 0);
+        }
+        if (ra != 31) {
+            tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
+        }
+        ret = EXIT_PC_UPDATED;
+        break;
+    case 0x1B:
+        /* HW_LD (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            TCGv addr;
+
+            if (ra == 31) {
+                break;
+            }
+
+            addr = tcg_temp_new();
+            if (rb != 31)
+                tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
+            else
+                tcg_gen_movi_i64(addr, disp12);
+            switch ((insn >> 12) & 0xF) {
+            case 0x0:
+                /* Longword physical access (hw_ldl/p) */
+                gen_helper_ldl_phys(cpu_ir[ra], addr);
+                break;
+            case 0x1:
+                /* Quadword physical access (hw_ldq/p) */
+                gen_helper_ldq_phys(cpu_ir[ra], addr);
+                break;
+            case 0x2:
+                /* Longword physical access with lock (hw_ldl_l/p) */
+                gen_helper_ldl_l_phys(cpu_ir[ra], addr);
+                break;
+            case 0x3:
+                /* Quadword physical access with lock (hw_ldq_l/p) */
+                gen_helper_ldq_l_phys(cpu_ir[ra], addr);
+                break;
+            case 0x4:
+                /* Longword virtual PTE fetch (hw_ldl/v) */
+                goto invalid_opc;
+            case 0x5:
+                /* Quadword virtual PTE fetch (hw_ldq/v) */
+                goto invalid_opc;
+                break;
+            case 0x6:
+                /* Incpu_ir[ra]id */
+                goto invalid_opc;
+            case 0x7:
+                /* Incpu_ir[ra]id */
+                goto invalid_opc;
+            case 0x8:
+                /* Longword virtual access (hw_ldl) */
+                goto invalid_opc;
+            case 0x9:
+                /* Quadword virtual access (hw_ldq) */
+                goto invalid_opc;
+            case 0xA:
+                /* Longword virtual access with protection check (hw_ldl/w) */
+                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_KERNEL_IDX);
+                break;
+            case 0xB:
+                /* Quadword virtual access with protection check (hw_ldq/w) */
+                tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_KERNEL_IDX);
+                break;
+            case 0xC:
+                /* Longword virtual access with alt access mode (hw_ldl/a)*/
+                goto invalid_opc;
+            case 0xD:
+                /* Quadword virtual access with alt access mode (hw_ldq/a) */
+                goto invalid_opc;
+            case 0xE:
+                /* Longword virtual access with alternate access mode and
+                   protection checks (hw_ldl/wa) */
+                tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_USER_IDX);
+                break;
+            case 0xF:
+                /* Quadword virtual access with alternate access mode and
+                   protection checks (hw_ldq/wa) */
+                tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_USER_IDX);
+                break;
+            }
+            tcg_temp_free(addr);
+            break;
+        }
+#endif
+        goto invalid_opc;
+    case 0x1C:
+        switch (fn7) {
+        case 0x00:
+            /* SEXTB */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_BWX) == 0) {
+                goto invalid_opc;
+            }
+            if (likely(rc != 31)) {
+                if (islit)
+                    tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit));
+                else
+                    tcg_gen_ext8s_i64(cpu_ir[rc], cpu_ir[rb]);
+            }
+            break;
+        case 0x01:
+            /* SEXTW */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
+                    } else {
+                        tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
+            }
+            goto invalid_opc;
+        case 0x30:
+            /* CTPOP */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
+                    } else {
+                        gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
+            }
+            goto invalid_opc;
+        case 0x31:
+            /* PERR */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_perr(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x32:
+            /* CTLZ */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
+                    } else {
+                        gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
+            }
+            goto invalid_opc;
+        case 0x33:
+            /* CTTZ */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+                if (likely(rc != 31)) {
+                    if (islit) {
+                        tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
+                    } else {
+                        gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+                    }
+                }
+                break;
+            }
+            goto invalid_opc;
+        case 0x34:
+            /* UNPKBW */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_unpkbw(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x35:
+            /* UNPKBL */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_unpkbl(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x36:
+            /* PKWB */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_pkwb(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x37:
+            /* PKLB */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                if (real_islit || ra != 31) {
+                    goto invalid_opc;
+                }
+                gen_pklb(rb, rc);
+                break;
+            }
+            goto invalid_opc;
+        case 0x38:
+            /* MINSB8 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minsb8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x39:
+            /* MINSW4 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minsw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3A:
+            /* MINUB8 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minub8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3B:
+            /* MINUW4 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_minuw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3C:
+            /* MAXUB8 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxub8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3D:
+            /* MAXUW4 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxuw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3E:
+            /* MAXSB8 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxsb8(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x3F:
+            /* MAXSW4 */
+            if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+                gen_maxsw4(ra, rb, rc, islit, lit);
+                break;
+            }
+            goto invalid_opc;
+        case 0x70:
+            /* FTOIT */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
+                goto invalid_opc;
+            }
+            if (likely(rc != 31)) {
+                if (ra != 31)
+                    tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]);
+                else
+                    tcg_gen_movi_i64(cpu_ir[rc], 0);
+            }
+            break;
+        case 0x78:
+            /* FTOIS */
+            if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
+                goto invalid_opc;
+            }
+            if (rc != 31) {
+                TCGv_i32 tmp1 = tcg_temp_new_i32();
+                if (ra != 31)
+                    gen_helper_s_to_memory(tmp1, cpu_fir[ra]);
+                else {
+                    TCGv tmp2 = tcg_const_i64(0);
+                    gen_helper_s_to_memory(tmp1, tmp2);
+                    tcg_temp_free(tmp2);
+                }
+                tcg_gen_ext_i32_i64(cpu_ir[rc], tmp1);
+                tcg_temp_free_i32(tmp1);
+            }
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x1D:
+        /* HW_MTPR (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            gen_mtpr(rb, insn & 0xffff);
+            break;
+        }
+#endif
+        goto invalid_opc;
+    case 0x1E:
+        /* HW_RET (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            if (rb == 31) {
+                /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
+                   address from EXC_ADDR.  This turns out to be useful for our
+                   emulation PALcode, so continue to accept it.  */
+                TCGv tmp = tcg_temp_new();
+                tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, exc_addr));
+                gen_helper_hw_ret(tmp);
+                tcg_temp_free(tmp);
+            } else {
+                gen_helper_hw_ret(cpu_ir[rb]);
+            }
+            ret = EXIT_PC_UPDATED;
+            break;
+        }
+#endif
+        goto invalid_opc;
+    case 0x1F:
+        /* HW_ST (PALcode) */
+#ifndef CONFIG_USER_ONLY
+        if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+            TCGv addr, val;
+            addr = tcg_temp_new();
+            if (rb != 31)
+                tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
+            else
+                tcg_gen_movi_i64(addr, disp12);
+            if (ra != 31)
+                val = cpu_ir[ra];
+            else {
+                val = tcg_temp_new();
+                tcg_gen_movi_i64(val, 0);
+            }
+            switch ((insn >> 12) & 0xF) {
+            case 0x0:
+                /* Longword physical access */
+                gen_helper_stl_phys(addr, val);
+                break;
+            case 0x1:
+                /* Quadword physical access */
+                gen_helper_stq_phys(addr, val);
+                break;
+            case 0x2:
+                /* Longword physical access with lock */
+                gen_helper_stl_c_phys(val, addr, val);
+                break;
+            case 0x3:
+                /* Quadword physical access with lock */
+                gen_helper_stq_c_phys(val, addr, val);
+                break;
+            case 0x4:
+                /* Longword virtual access */
+                goto invalid_opc;
+            case 0x5:
+                /* Quadword virtual access */
+                goto invalid_opc;
+            case 0x6:
+                /* Invalid */
+                goto invalid_opc;
+            case 0x7:
+                /* Invalid */
+                goto invalid_opc;
+            case 0x8:
+                /* Invalid */
+                goto invalid_opc;
+            case 0x9:
+                /* Invalid */
+                goto invalid_opc;
+            case 0xA:
+                /* Invalid */
+                goto invalid_opc;
+            case 0xB:
+                /* Invalid */
+                goto invalid_opc;
+            case 0xC:
+                /* Longword virtual access with alternate access mode */
+                goto invalid_opc;
+            case 0xD:
+                /* Quadword virtual access with alternate access mode */
+                goto invalid_opc;
+            case 0xE:
+                /* Invalid */
+                goto invalid_opc;
+            case 0xF:
+                /* Invalid */
+                goto invalid_opc;
+            }
+            if (ra == 31)
+                tcg_temp_free(val);
+            tcg_temp_free(addr);
+            break;
+        }
+#endif
+        goto invalid_opc;
+    case 0x20:
+        /* LDF */
+        gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0);
+        break;
+    case 0x21:
+        /* LDG */
+        gen_load_mem(ctx, &gen_qemu_ldg, ra, rb, disp16, 1, 0);
+        break;
+    case 0x22:
+        /* LDS */
+        gen_load_mem(ctx, &gen_qemu_lds, ra, rb, disp16, 1, 0);
+        break;
+    case 0x23:
+        /* LDT */
+        gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0);
+        break;
+    case 0x24:
+        /* STF */
+        gen_store_mem(ctx, &gen_qemu_stf, ra, rb, disp16, 1, 0);
+        break;
+    case 0x25:
+        /* STG */
+        gen_store_mem(ctx, &gen_qemu_stg, ra, rb, disp16, 1, 0);
+        break;
+    case 0x26:
+        /* STS */
+        gen_store_mem(ctx, &gen_qemu_sts, ra, rb, disp16, 1, 0);
+        break;
+    case 0x27:
+        /* STT */
+        gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0);
+        break;
+    case 0x28:
+        /* LDL */
+        gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0);
+        break;
+    case 0x29:
+        /* LDQ */
+        gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0);
+        break;
+    case 0x2A:
+        /* LDL_L */
+        gen_load_mem(ctx, &gen_qemu_ldl_l, ra, rb, disp16, 0, 0);
+        break;
+    case 0x2B:
+        /* LDQ_L */
+        gen_load_mem(ctx, &gen_qemu_ldq_l, ra, rb, disp16, 0, 0);
+        break;
+    case 0x2C:
+        /* STL */
+        gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0);
+        break;
+    case 0x2D:
+        /* STQ */
+        gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0);
+        break;
+    case 0x2E:
+        /* STL_C */
+        ret = gen_store_conditional(ctx, ra, rb, disp16, 0);
+        break;
+    case 0x2F:
+        /* STQ_C */
+        ret = gen_store_conditional(ctx, ra, rb, disp16, 1);
+        break;
+    case 0x30:
+        /* BR */
+        ret = gen_bdirect(ctx, ra, disp21);
+        break;
+    case 0x31: /* FBEQ */
+        ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21);
+        break;
+    case 0x32: /* FBLT */
+        ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21);
+        break;
+    case 0x33: /* FBLE */
+        ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21);
+        break;
+    case 0x34:
+        /* BSR */
+        ret = gen_bdirect(ctx, ra, disp21);
+        break;
+    case 0x35: /* FBNE */
+        ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21);
+        break;
+    case 0x36: /* FBGE */
+        ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21);
+        break;
+    case 0x37: /* FBGT */
+        ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21);
+        break;
+    case 0x38:
+        /* BLBC */
+        ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1);
+        break;
+    case 0x39:
+        /* BEQ */
+        ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0);
+        break;
+    case 0x3A:
+        /* BLT */
+        ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0);
+        break;
+    case 0x3B:
+        /* BLE */
+        ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0);
+        break;
+    case 0x3C:
+        /* BLBS */
+        ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1);
+        break;
+    case 0x3D:
+        /* BNE */
+        ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0);
+        break;
+    case 0x3E:
+        /* BGE */
+        ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0);
+        break;
+    case 0x3F:
+        /* BGT */
+        ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0);
+        break;
+    invalid_opc:
+        ret = gen_invalid(ctx);
+        break;
+    }
+
+    return ret;
+}
+
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext ctx, *ctxp = &ctx;
+    target_ulong pc_start;
+    uint32_t insn;
+    uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int j, lj = -1;
+    ExitStatus ret;
+    int num_insns;
+    int max_insns;
+
+    pc_start = tb->pc;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    ctx.tb = tb;
+    ctx.env = env;
+    ctx.pc = pc_start;
+    ctx.mem_idx = cpu_mmu_index(env);
+
+    /* ??? Every TB begins with unset rounding mode, to be initialized on
+       the first fp insn of the TB.  Alternately we could define a proper
+       default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure
+       to reset the FP_STATUS to that default at the end of any TB that
+       changes the default.  We could even (gasp) dynamiclly figure out
+       what default would be most efficient given the running program.  */
+    ctx.tb_rm = -1;
+    /* Similarly for flush-to-zero.  */
+    ctx.tb_ftz = -1;
+
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+    do {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == ctx.pc) {
+                    gen_excp(&ctx, EXCP_DEBUG, 0);
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = ctx.pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+        insn = ldl_code(ctx.pc);
+        num_insns++;
+
+	if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(ctx.pc);
+        }
+
+        ctx.pc += 4;
+        ret = translate_one(ctxp, insn);
+
+        /* If we reach a page boundary, are single stepping,
+           or exhaust instruction count, stop generation.  */
+        if (ret == NO_EXIT
+            && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
+                || gen_opc_ptr >= gen_opc_end
+                || num_insns >= max_insns
+                || singlestep
+                || env->singlestep_enabled)) {
+            ret = EXIT_PC_STALE;
+        }
+    } while (ret == NO_EXIT);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    switch (ret) {
+    case EXIT_GOTO_TB:
+    case EXIT_NORETURN:
+        break;
+    case EXIT_PC_STALE:
+        tcg_gen_movi_i64(cpu_pc, ctx.pc);
+        /* FALLTHRU */
+    case EXIT_PC_UPDATED:
+        if (env->singlestep_enabled) {
+            gen_excp_1(EXCP_DEBUG, 0);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+        break;
+    default:
+        abort();
+    }
+
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = ctx.pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, ctx.pc - pc_start, 1);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+struct cpu_def_t {
+    const char *name;
+    int implver, amask;
+};
+
+static const struct cpu_def_t cpu_defs[] = {
+    { "ev4",   IMPLVER_2106x, 0 },
+    { "ev5",   IMPLVER_21164, 0 },
+    { "ev56",  IMPLVER_21164, AMASK_BWX },
+    { "pca56", IMPLVER_21164, AMASK_BWX | AMASK_MVI },
+    { "ev6",   IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP },
+    { "ev67",  IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX
+			       | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), },
+    { "ev68",  IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX
+			       | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), },
+    { "21064", IMPLVER_2106x, 0 },
+    { "21164", IMPLVER_21164, 0 },
+    { "21164a", IMPLVER_21164, AMASK_BWX },
+    { "21164pc", IMPLVER_21164, AMASK_BWX | AMASK_MVI },
+    { "21264", IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP },
+    { "21264a", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX
+				| AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), }
+};
+
+CPUAlphaState * cpu_alpha_init (const char *cpu_model)
+{
+    CPUAlphaState *env;
+    int implver, amask, i, max;
+
+    env = qemu_mallocz(sizeof(CPUAlphaState));
+    cpu_exec_init(env);
+    alpha_translate_init();
+    tlb_flush(env, 1);
+
+    /* Default to ev67; no reason not to emulate insns by default.  */
+    implver = IMPLVER_21264;
+    amask = (AMASK_BWX | AMASK_FIX | AMASK_CIX | AMASK_MVI
+	     | AMASK_TRAP | AMASK_PREFETCH);
+
+    max = ARRAY_SIZE(cpu_defs);
+    for (i = 0; i < max; i++) {
+        if (strcmp (cpu_model, cpu_defs[i].name) == 0) {
+            implver = cpu_defs[i].implver;
+            amask = cpu_defs[i].amask;
+            break;
+        }
+    }
+    env->implver = implver;
+    env->amask = amask;
+
+#if defined (CONFIG_USER_ONLY)
+    env->ps = PS_USER_MODE;
+    cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
+                               | FPCR_UNFD | FPCR_INED | FPCR_DNOD));
+#endif
+    env->lock_addr = -1;
+    env->fen = 1;
+
+    qemu_init_vcpu(env);
+    return env;
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/target-arm/cpu.h b/qemu-0.15.x/target-arm/cpu.h
new file mode 100644
index 0000000..1974d82
--- /dev/null
+++ b/qemu-0.15.x/target-arm/cpu.h
@@ -0,0 +1,535 @@
+/*
+ * ARM virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_ARM_H
+#define CPU_ARM_H
+
+#define TARGET_LONG_BITS 32
+
+#define ELF_MACHINE	EM_ARM
+
+#define CPUState struct CPUARMState
+
+#include "config.h"
+#include "qemu-common.h"
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define TARGET_HAS_ICE 1
+
+#define EXCP_UDEF            1   /* undefined instruction */
+#define EXCP_SWI             2   /* software interrupt */
+#define EXCP_PREFETCH_ABORT  3
+#define EXCP_DATA_ABORT      4
+#define EXCP_IRQ             5
+#define EXCP_FIQ             6
+#define EXCP_BKPT            7
+#define EXCP_EXCEPTION_EXIT  8   /* Return from v7M exception.  */
+#define EXCP_KERNEL_TRAP     9   /* Jumped to kernel code page.  */
+#define EXCP_STREX          10
+
+#define ARMV7M_EXCP_RESET   1
+#define ARMV7M_EXCP_NMI     2
+#define ARMV7M_EXCP_HARD    3
+#define ARMV7M_EXCP_MEM     4
+#define ARMV7M_EXCP_BUS     5
+#define ARMV7M_EXCP_USAGE   6
+#define ARMV7M_EXCP_SVC     11
+#define ARMV7M_EXCP_DEBUG   12
+#define ARMV7M_EXCP_PENDSV  14
+#define ARMV7M_EXCP_SYSTICK 15
+
+/* ARM-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_FIQ   CPU_INTERRUPT_TGT_EXT_1
+
+
+typedef void ARMWriteCPFunc(void *opaque, int cp_info,
+                            int srcreg, int operand, uint32_t value);
+typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
+                               int dstreg, int operand);
+
+struct arm_boot_info;
+
+#define NB_MMU_MODES 2
+
+/* We currently assume float and double are IEEE single and double
+   precision respectively.
+   Doing runtime conversions is tricky because VFP registers may contain
+   integer values (eg. as the result of a FTOSI instruction).
+   s<2n> maps to the least significant half of d<n>
+   s<2n+1> maps to the most significant half of d<n>
+ */
+
+typedef struct CPUARMState {
+    /* Regs for current mode.  */
+    uint32_t regs[16];
+    /* Frequently accessed CPSR bits are stored separately for efficiently.
+       This contains all the other bits.  Use cpsr_{read,write} to access
+       the whole CPSR.  */
+    uint32_t uncached_cpsr;
+    uint32_t spsr;
+
+    /* Banked registers.  */
+    uint32_t banked_spsr[6];
+    uint32_t banked_r13[6];
+    uint32_t banked_r14[6];
+
+    /* These hold r8-r12.  */
+    uint32_t usr_regs[5];
+    uint32_t fiq_regs[5];
+
+    /* cpsr flag cache for faster execution */
+    uint32_t CF; /* 0 or 1 */
+    uint32_t VF; /* V is the bit 31. All other bits are undefined */
+    uint32_t NF; /* N is bit 31. All other bits are undefined.  */
+    uint32_t ZF; /* Z set if zero.  */
+    uint32_t QF; /* 0 or 1 */
+    uint32_t GE; /* cpsr[19:16] */
+    uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
+    uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
+
+    /* System control coprocessor (cp15) */
+    struct {
+        uint32_t c0_cpuid;
+        uint32_t c0_cachetype;
+        uint32_t c0_ccsid[16]; /* Cache size.  */
+        uint32_t c0_clid; /* Cache level.  */
+        uint32_t c0_cssel; /* Cache size selection.  */
+        uint32_t c0_c1[8]; /* Feature registers.  */
+        uint32_t c0_c2[8]; /* Instruction set registers.  */
+        uint32_t c1_sys; /* System control register.  */
+        uint32_t c1_coproc; /* Coprocessor access register.  */
+        uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
+        uint32_t c2_base0; /* MMU translation table base 0.  */
+        uint32_t c2_base1; /* MMU translation table base 1.  */
+        uint32_t c2_control; /* MMU translation table base control.  */
+        uint32_t c2_mask; /* MMU translation table base selection mask.  */
+        uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
+        uint32_t c2_data; /* MPU data cachable bits.  */
+        uint32_t c2_insn; /* MPU instruction cachable bits.  */
+        uint32_t c3; /* MMU domain access control register
+                        MPU write buffer control.  */
+        uint32_t c5_insn; /* Fault status registers.  */
+        uint32_t c5_data;
+        uint32_t c6_region[8]; /* MPU base/size registers.  */
+        uint32_t c6_insn; /* Fault address registers.  */
+        uint32_t c6_data;
+        uint32_t c7_par;  /* Translation result. */
+        uint32_t c9_insn; /* Cache lockdown registers.  */
+        uint32_t c9_data;
+        uint32_t c9_pmcr; /* performance monitor control register */
+        uint32_t c9_pmcnten; /* perf monitor counter enables */
+        uint32_t c9_pmovsr; /* perf monitor overflow status */
+        uint32_t c9_pmxevtyper; /* perf monitor event type */
+        uint32_t c9_pmuserenr; /* perf monitor user enable */
+        uint32_t c9_pminten; /* perf monitor interrupt enables */
+        uint32_t c13_fcse; /* FCSE PID.  */
+        uint32_t c13_context; /* Context ID.  */
+        uint32_t c13_tls1; /* User RW Thread register.  */
+        uint32_t c13_tls2; /* User RO Thread register.  */
+        uint32_t c13_tls3; /* Privileged Thread register.  */
+        uint32_t c15_cpar; /* XScale Coprocessor Access Register */
+        uint32_t c15_ticonfig; /* TI925T configuration byte.  */
+        uint32_t c15_i_max; /* Maximum D-cache dirty line index.  */
+        uint32_t c15_i_min; /* Minimum D-cache dirty line index.  */
+        uint32_t c15_threadid; /* TI debugger thread-ID.  */
+    } cp15;
+
+    struct {
+        uint32_t other_sp;
+        uint32_t vecbase;
+        uint32_t basepri;
+        uint32_t control;
+        int current_sp;
+        int exception;
+        int pending_exception;
+    } v7m;
+
+    /* Thumb-2 EE state.  */
+    uint32_t teecr;
+    uint32_t teehbr;
+
+    /* Internal CPU feature flags.  */
+    uint32_t features;
+
+    /* VFP coprocessor state.  */
+    struct {
+        float64 regs[32];
+
+        uint32_t xregs[16];
+        /* We store these fpcsr fields separately for convenience.  */
+        int vec_len;
+        int vec_stride;
+
+        /* scratch space when Tn are not sufficient.  */
+        uint32_t scratch[8];
+
+        /* fp_status is the "normal" fp status. standard_fp_status retains
+         * values corresponding to the ARM "Standard FPSCR Value", ie
+         * default-NaN, flush-to-zero, round-to-nearest and is used by
+         * any operations (generally Neon) which the architecture defines
+         * as controlled by the standard FPSCR value rather than the FPSCR.
+         *
+         * To avoid having to transfer exception bits around, we simply
+         * say that the FPSCR cumulative exception flags are the logical
+         * OR of the flags in the two fp statuses. This relies on the
+         * only thing which needs to read the exception flags being
+         * an explicit FPSCR read.
+         */
+        float_status fp_status;
+        float_status standard_fp_status;
+    } vfp;
+    uint32_t exclusive_addr;
+    uint32_t exclusive_val;
+    uint32_t exclusive_high;
+#if defined(CONFIG_USER_ONLY)
+    uint32_t exclusive_test;
+    uint32_t exclusive_info;
+#endif
+
+    /* iwMMXt coprocessor state.  */
+    struct {
+        uint64_t regs[16];
+        uint64_t val;
+
+        uint32_t cregs[16];
+    } iwmmxt;
+
+#if defined(CONFIG_USER_ONLY)
+    /* For usermode syscall translation.  */
+    int eabi;
+#endif
+
+    CPU_COMMON
+
+    /* These fields after the common ones so they are preserved on reset.  */
+
+    /* Coprocessor IO used by peripherals */
+    struct {
+        ARMReadCPFunc *cp_read;
+        ARMWriteCPFunc *cp_write;
+        void *opaque;
+    } cp[15];
+    void *nvic;
+    const struct arm_boot_info *boot_info;
+} CPUARMState;
+
+CPUARMState *cpu_arm_init(const char *cpu_model);
+void arm_translate_init(void);
+int cpu_arm_exec(CPUARMState *s);
+void cpu_arm_close(CPUARMState *s);
+void do_interrupt(CPUARMState *);
+void switch_mode(CPUARMState *, int);
+uint32_t do_arm_semihosting(CPUARMState *env);
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_arm_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
+#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
+
+static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+  env->cp15.c13_tls2 = newtls;
+}
+
+#define CPSR_M (0x1f)
+#define CPSR_T (1 << 5)
+#define CPSR_F (1 << 6)
+#define CPSR_I (1 << 7)
+#define CPSR_A (1 << 8)
+#define CPSR_E (1 << 9)
+#define CPSR_IT_2_7 (0xfc00)
+#define CPSR_GE (0xf << 16)
+#define CPSR_RESERVED (0xf << 20)
+#define CPSR_J (1 << 24)
+#define CPSR_IT_0_1 (3 << 25)
+#define CPSR_Q (1 << 27)
+#define CPSR_V (1 << 28)
+#define CPSR_C (1 << 29)
+#define CPSR_Z (1 << 30)
+#define CPSR_N (1 << 31)
+#define CPSR_NZCV (CPSR_N | CPSR_Z | CPSR_C | CPSR_V)
+
+#define CPSR_IT (CPSR_IT_0_1 | CPSR_IT_2_7)
+#define CACHED_CPSR_BITS (CPSR_T | CPSR_GE | CPSR_IT | CPSR_Q | CPSR_NZCV)
+/* Bits writable in user mode.  */
+#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE)
+/* Execution state bits.  MRS read as zero, MSR writes ignored.  */
+#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J)
+
+/* Return the current CPSR value.  */
+uint32_t cpsr_read(CPUARMState *env);
+/* Set the CPSR.  Note that some bits of mask must be all-set or all-clear.  */
+void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask);
+
+/* Return the current xPSR value.  */
+static inline uint32_t xpsr_read(CPUARMState *env)
+{
+    int ZF;
+    ZF = (env->ZF == 0);
+    return (env->NF & 0x80000000) | (ZF << 30)
+        | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
+        | (env->thumb << 24) | ((env->condexec_bits & 3) << 25)
+        | ((env->condexec_bits & 0xfc) << 8)
+        | env->v7m.exception;
+}
+
+/* Set the xPSR.  Note that some bits of mask must be all-set or all-clear.  */
+static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
+{
+    if (mask & CPSR_NZCV) {
+        env->ZF = (~val) & CPSR_Z;
+        env->NF = val;
+        env->CF = (val >> 29) & 1;
+        env->VF = (val << 3) & 0x80000000;
+    }
+    if (mask & CPSR_Q)
+        env->QF = ((val & CPSR_Q) != 0);
+    if (mask & (1 << 24))
+        env->thumb = ((val & (1 << 24)) != 0);
+    if (mask & CPSR_IT_0_1) {
+        env->condexec_bits &= ~3;
+        env->condexec_bits |= (val >> 25) & 3;
+    }
+    if (mask & CPSR_IT_2_7) {
+        env->condexec_bits &= 3;
+        env->condexec_bits |= (val >> 8) & 0xfc;
+    }
+    if (mask & 0x1ff) {
+        env->v7m.exception = val & 0x1ff;
+    }
+}
+
+/* Return the current FPSCR value.  */
+uint32_t vfp_get_fpscr(CPUARMState *env);
+void vfp_set_fpscr(CPUARMState *env, uint32_t val);
+
+enum arm_cpu_mode {
+  ARM_CPU_MODE_USR = 0x10,
+  ARM_CPU_MODE_FIQ = 0x11,
+  ARM_CPU_MODE_IRQ = 0x12,
+  ARM_CPU_MODE_SVC = 0x13,
+  ARM_CPU_MODE_ABT = 0x17,
+  ARM_CPU_MODE_UND = 0x1b,
+  ARM_CPU_MODE_SYS = 0x1f
+};
+
+/* VFP system registers.  */
+#define ARM_VFP_FPSID   0
+#define ARM_VFP_FPSCR   1
+#define ARM_VFP_MVFR1   6
+#define ARM_VFP_MVFR0   7
+#define ARM_VFP_FPEXC   8
+#define ARM_VFP_FPINST  9
+#define ARM_VFP_FPINST2 10
+
+/* iwMMXt coprocessor control registers.  */
+#define ARM_IWMMXT_wCID		0
+#define ARM_IWMMXT_wCon		1
+#define ARM_IWMMXT_wCSSF	2
+#define ARM_IWMMXT_wCASF	3
+#define ARM_IWMMXT_wCGR0	8
+#define ARM_IWMMXT_wCGR1	9
+#define ARM_IWMMXT_wCGR2	10
+#define ARM_IWMMXT_wCGR3	11
+
+enum arm_features {
+    ARM_FEATURE_VFP,
+    ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
+    ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
+    ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
+    ARM_FEATURE_V6,
+    ARM_FEATURE_V6K,
+    ARM_FEATURE_V7,
+    ARM_FEATURE_THUMB2,
+    ARM_FEATURE_MPU,    /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_VFP3,
+    ARM_FEATURE_VFP_FP16,
+    ARM_FEATURE_NEON,
+    ARM_FEATURE_DIV,
+    ARM_FEATURE_M, /* Microcontroller profile.  */
+    ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
+    ARM_FEATURE_THUMB2EE,
+    ARM_FEATURE_V7MP,    /* v7 Multiprocessing Extensions */
+    ARM_FEATURE_V4T,
+    ARM_FEATURE_V5,
+    ARM_FEATURE_STRONGARM,
+    ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
+};
+
+static inline int arm_feature(CPUARMState *env, int feature)
+{
+    return (env->features & (1u << feature)) != 0;
+}
+
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+/* Interface between CPU and Interrupt controller.  */
+void armv7m_nvic_set_pending(void *opaque, int irq);
+int armv7m_nvic_acknowledge_irq(void *opaque);
+void armv7m_nvic_complete_irq(void *opaque, int irq);
+
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                       ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                       void *opaque);
+
+/* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3.
+   Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are
+   conventional cores (ie. Application or Realtime profile).  */
+
+#define IS_M(env) arm_feature(env, ARM_FEATURE_M)
+#define ARM_CPUID(env) (env->cp15.c0_cpuid)
+
+#define ARM_CPUID_ARM1026     0x4106a262
+#define ARM_CPUID_ARM926      0x41069265
+#define ARM_CPUID_ARM946      0x41059461
+#define ARM_CPUID_TI915T      0x54029152
+#define ARM_CPUID_TI925T      0x54029252
+#define ARM_CPUID_SA1100      0x4401A11B
+#define ARM_CPUID_SA1110      0x6901B119
+#define ARM_CPUID_PXA250      0x69052100
+#define ARM_CPUID_PXA255      0x69052d00
+#define ARM_CPUID_PXA260      0x69052903
+#define ARM_CPUID_PXA261      0x69052d05
+#define ARM_CPUID_PXA262      0x69052d06
+#define ARM_CPUID_PXA270      0x69054110
+#define ARM_CPUID_PXA270_A0   0x69054110
+#define ARM_CPUID_PXA270_A1   0x69054111
+#define ARM_CPUID_PXA270_B0   0x69054112
+#define ARM_CPUID_PXA270_B1   0x69054113
+#define ARM_CPUID_PXA270_C0   0x69054114
+#define ARM_CPUID_PXA270_C5   0x69054117
+#define ARM_CPUID_ARM1136     0x4117b363
+#define ARM_CPUID_ARM1136_R2  0x4107b362
+#define ARM_CPUID_ARM11MPCORE 0x410fb022
+#define ARM_CPUID_CORTEXA8    0x410fc080
+#define ARM_CPUID_CORTEXA9    0x410fc090
+#define ARM_CPUID_CORTEXM3    0x410fc231
+#define ARM_CPUID_ANY         0xffffffff
+
+#if defined(CONFIG_USER_ONLY)
+#define TARGET_PAGE_BITS 12
+#else
+/* The ARM MMU allows 1k pages.  */
+/* ??? Linux doesn't actually use these, and they're deprecated in recent
+   architecture revisions.  Maybe a configure option to disable them.  */
+#define TARGET_PAGE_BITS 10
+#endif
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define cpu_init cpu_arm_init
+#define cpu_exec cpu_arm_exec
+#define cpu_gen_code cpu_arm_gen_code
+#define cpu_signal_handler cpu_arm_signal_handler
+#define cpu_list arm_cpu_list
+
+#define CPU_SAVE_VERSION 4
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[13] = newsp;
+    env->regs[0] = 0;
+}
+#endif
+
+#include "cpu-all.h"
+
+/* Bit usage in the TB flags field: */
+#define ARM_TBFLAG_THUMB_SHIFT      0
+#define ARM_TBFLAG_THUMB_MASK       (1 << ARM_TBFLAG_THUMB_SHIFT)
+#define ARM_TBFLAG_VECLEN_SHIFT     1
+#define ARM_TBFLAG_VECLEN_MASK      (0x7 << ARM_TBFLAG_VECLEN_SHIFT)
+#define ARM_TBFLAG_VECSTRIDE_SHIFT  4
+#define ARM_TBFLAG_VECSTRIDE_MASK   (0x3 << ARM_TBFLAG_VECSTRIDE_SHIFT)
+#define ARM_TBFLAG_PRIV_SHIFT       6
+#define ARM_TBFLAG_PRIV_MASK        (1 << ARM_TBFLAG_PRIV_SHIFT)
+#define ARM_TBFLAG_VFPEN_SHIFT      7
+#define ARM_TBFLAG_VFPEN_MASK       (1 << ARM_TBFLAG_VFPEN_SHIFT)
+#define ARM_TBFLAG_CONDEXEC_SHIFT   8
+#define ARM_TBFLAG_CONDEXEC_MASK    (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
+/* Bits 31..16 are currently unused. */
+
+/* some convenience accessor macros */
+#define ARM_TBFLAG_THUMB(F) \
+    (((F) & ARM_TBFLAG_THUMB_MASK) >> ARM_TBFLAG_THUMB_SHIFT)
+#define ARM_TBFLAG_VECLEN(F) \
+    (((F) & ARM_TBFLAG_VECLEN_MASK) >> ARM_TBFLAG_VECLEN_SHIFT)
+#define ARM_TBFLAG_VECSTRIDE(F) \
+    (((F) & ARM_TBFLAG_VECSTRIDE_MASK) >> ARM_TBFLAG_VECSTRIDE_SHIFT)
+#define ARM_TBFLAG_PRIV(F) \
+    (((F) & ARM_TBFLAG_PRIV_MASK) >> ARM_TBFLAG_PRIV_SHIFT)
+#define ARM_TBFLAG_VFPEN(F) \
+    (((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
+#define ARM_TBFLAG_CONDEXEC(F) \
+    (((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    int privmode;
+    *pc = env->regs[15];
+    *cs_base = 0;
+    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
+        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
+        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
+        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT);
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
+    } else {
+        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
+    }
+    if (privmode) {
+        *flags |= ARM_TBFLAG_PRIV_MASK;
+    }
+    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
+        *flags |= ARM_TBFLAG_VFPEN_MASK;
+    }
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request &
+        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->regs[15] = tb->pc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-arm/exec.h b/qemu-0.15.x/target-arm/exec.h
new file mode 100644
index 0000000..6793288
--- /dev/null
+++ b/qemu-0.15.x/target-arm/exec.h
@@ -0,0 +1,30 @@
+/*
+ *  ARM execution defines
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "dyngen-exec.h"
+
+register struct CPUARMState *env asm(AREG0);
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+void raise_exception(int);
diff --git a/qemu-0.15.x/target-arm/helper.c b/qemu-0.15.x/target-arm/helper.c
new file mode 100644
index 0000000..5b0b492
--- /dev/null
+++ b/qemu-0.15.x/target-arm/helper.c
@@ -0,0 +1,3068 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "gdbstub.h"
+#include "helper.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
+
+static uint32_t cortexa9_cp15_c0_c1[8] =
+{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
+
+static uint32_t cortexa9_cp15_c0_c2[8] =
+{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 };
+
+static uint32_t cortexa8_cp15_c0_c1[8] =
+{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
+
+static uint32_t cortexa8_cp15_c0_c2[8] =
+{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
+
+static uint32_t mpcore_cp15_c0_c1[8] =
+{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
+
+static uint32_t mpcore_cp15_c0_c2[8] =
+{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 };
+
+static uint32_t arm1136_cp15_c0_c1[8] =
+{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 };
+
+static uint32_t arm1136_cp15_c0_c2[8] =
+{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
+
+static uint32_t cpu_arm_find_by_name(const char *name);
+
+static inline void set_feature(CPUARMState *env, int feature)
+{
+    env->features |= 1u << feature;
+}
+
+static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
+{
+    env->cp15.c0_cpuid = id;
+    switch (id) {
+    case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_VFP);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00090078;
+        break;
+    case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_MPU);
+        env->cp15.c0_cachetype = 0x0f004006;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00090078;
+        break;
+    case ARM_CPUID_ARM1136:
+        /* This is the 1136 r1, which is a v6K core */
+        set_feature(env, ARM_FEATURE_V6K);
+        /* Fall through */
+    case ARM_CPUID_ARM1136_R2:
+        /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+         * older core than plain "arm1136". In particular this does not
+         * have the v6K features.
+         */
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        /* These ID register values are correct for 1136 but may be wrong
+         * for 1136_r2 (in particular r0p2 does not actually implement most
+         * of the ID registers).
+         */
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
+        memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00050078;
+        break;
+    case ARM_CPUID_ARM11MPCORE:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_VAPA);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
+        memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        break;
+    case ARM_CPUID_CORTEXA8:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_VFP3);
+        set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
+        memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x82048004;
+        env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
+        env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+        env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+        env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
+        env->cp15.c1_sys = 0x00c50078;
+        break;
+    case ARM_CPUID_CORTEXA9:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_VFP3);
+        set_feature(env, ARM_FEATURE_VFP_FP16);
+        set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
+        /* Note that A9 supports the MP extensions even for
+         * A9UP and single-core A9MP (which are both different
+         * and valid configurations; we don't model A9UP).
+         */
+        set_feature(env, ARM_FEATURE_V7MP);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
+        memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x80038003;
+        env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
+        env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
+        env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
+        env->cp15.c1_sys = 0x00c50078;
+        break;
+    case ARM_CPUID_CORTEXM3:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_M);
+        set_feature(env, ARM_FEATURE_DIV);
+        break;
+    case ARM_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_VFP3);
+        set_feature(env, ARM_FEATURE_VFP_FP16);
+        set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
+        set_feature(env, ARM_FEATURE_DIV);
+        set_feature(env, ARM_FEATURE_V7MP);
+        break;
+    case ARM_CPUID_TI915T:
+    case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_OMAPCP);
+        env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
+        env->cp15.c0_cachetype = 0x5109149;
+        env->cp15.c1_sys = 0x00000070;
+        env->cp15.c15_i_max = 0x000;
+        env->cp15.c15_i_min = 0xff0;
+        break;
+    case ARM_CPUID_PXA250:
+    case ARM_CPUID_PXA255:
+    case ARM_CPUID_PXA260:
+    case ARM_CPUID_PXA261:
+    case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        env->cp15.c0_cachetype = 0xd172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    case ARM_CPUID_PXA270_A0:
+    case ARM_CPUID_PXA270_A1:
+    case ARM_CPUID_PXA270_B0:
+    case ARM_CPUID_PXA270_B1:
+    case ARM_CPUID_PXA270_C0:
+    case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        set_feature(env, ARM_FEATURE_IWMMXT);
+        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+        env->cp15.c0_cachetype = 0xd172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    case ARM_CPUID_SA1100:
+    case ARM_CPUID_SA1110:
+        set_feature(env, ARM_FEATURE_STRONGARM);
+        env->cp15.c1_sys = 0x00000070;
+        break;
+    default:
+        cpu_abort(env, "Bad CPU ID: %x\n", id);
+        break;
+    }
+
+    /* Some features automatically imply others: */
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        set_feature(env, ARM_FEATURE_VAPA);
+    }
+}
+
+void cpu_reset(CPUARMState *env)
+{
+    uint32_t id;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    id = env->cp15.c0_cpuid;
+    memset(env, 0, offsetof(CPUARMState, breakpoints));
+    if (id)
+        cpu_reset_model_id(env, id);
+#if defined (CONFIG_USER_ONLY)
+    env->uncached_cpsr = ARM_CPU_MODE_USR;
+    /* For user mode we must enable access to coprocessors */
+    env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        env->cp15.c15_cpar = 3;
+    } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+        env->cp15.c15_cpar = 1;
+    }
+#else
+    /* SVC mode with interrupts disabled.  */
+    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+    /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
+       clear at reset.  Initial SP and PC are loaded from ROM.  */
+    if (IS_M(env)) {
+        uint32_t pc;
+        uint8_t *rom;
+        env->uncached_cpsr &= ~CPSR_I;
+        rom = rom_ptr(0);
+        if (rom) {
+            /* We should really use ldl_phys here, in case the guest
+               modified flash and reset itself.  However images
+               loaded via -kenrel have not been copied yet, so load the
+               values directly from there.  */
+            env->regs[13] = ldl_p(rom);
+            pc = ldl_p(rom + 4);
+            env->thumb = pc & 1;
+            env->regs[15] = pc & ~1;
+        }
+    }
+    env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+    env->cp15.c2_base_mask = 0xffffc000u;
+    /* v7 performance monitor control register: same implementor
+     * field as main ID register, and we implement no event counters.
+     */
+    env->cp15.c9_pmcr = (id & 0xff000000);
+#endif
+    set_flush_to_zero(1, &env->vfp.standard_fp_status);
+    set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
+    set_default_nan_mode(1, &env->vfp.standard_fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.standard_fp_status);
+    tlb_flush(env, 1);
+}
+
+static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    /* VFP data registers are always little-endian.  */
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        stfq_le_p(buf, env->vfp.regs[reg]);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        /* Aliases for Q regs.  */
+        nregs += 16;
+        if (reg < nregs) {
+            stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]);
+            stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
+    case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4;
+    case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+    }
+    return 0;
+}
+
+static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        env->vfp.regs[reg] = ldfq_le_p(buf);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        nregs += 16;
+        if (reg < nregs) {
+            env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf);
+            env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4;
+    case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4;
+    case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30); return 4;
+    }
+    return 0;
+}
+
+CPUARMState *cpu_arm_init(const char *cpu_model)
+{
+    CPUARMState *env;
+    uint32_t id;
+    static int inited = 0;
+
+    id = cpu_arm_find_by_name(cpu_model);
+    if (id == 0)
+        return NULL;
+    env = qemu_mallocz(sizeof(CPUARMState));
+    cpu_exec_init(env);
+    if (!inited) {
+        inited = 1;
+        arm_translate_init();
+    }
+
+    env->cpu_model_str = cpu_model;
+    env->cp15.c0_cpuid = id;
+    cpu_reset(env);
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 51, "arm-neon.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP3)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 35, "arm-vfp3.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 19, "arm-vfp.xml", 0);
+    }
+    qemu_init_vcpu(env);
+    return env;
+}
+
+struct arm_cpu_t {
+    uint32_t id;
+    const char *name;
+};
+
+static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM926, "arm926"},
+    { ARM_CPUID_ARM946, "arm946"},
+    { ARM_CPUID_ARM1026, "arm1026"},
+    { ARM_CPUID_ARM1136, "arm1136"},
+    { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
+    { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
+    { ARM_CPUID_CORTEXM3, "cortex-m3"},
+    { ARM_CPUID_CORTEXA8, "cortex-a8"},
+    { ARM_CPUID_CORTEXA9, "cortex-a9"},
+    { ARM_CPUID_TI925T, "ti925t" },
+    { ARM_CPUID_PXA250, "pxa250" },
+    { ARM_CPUID_SA1100,    "sa1100" },
+    { ARM_CPUID_SA1110,    "sa1110" },
+    { ARM_CPUID_PXA255, "pxa255" },
+    { ARM_CPUID_PXA260, "pxa260" },
+    { ARM_CPUID_PXA261, "pxa261" },
+    { ARM_CPUID_PXA262, "pxa262" },
+    { ARM_CPUID_PXA270, "pxa270" },
+    { ARM_CPUID_PXA270_A0, "pxa270-a0" },
+    { ARM_CPUID_PXA270_A1, "pxa270-a1" },
+    { ARM_CPUID_PXA270_B0, "pxa270-b0" },
+    { ARM_CPUID_PXA270_B1, "pxa270-b1" },
+    { ARM_CPUID_PXA270_C0, "pxa270-c0" },
+    { ARM_CPUID_PXA270_C5, "pxa270-c5" },
+    { ARM_CPUID_ANY, "any"},
+    { 0, NULL}
+};
+
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    for (i = 0; arm_cpu_names[i].name; i++) {
+        (*cpu_fprintf)(f, "  %s\n", arm_cpu_names[i].name);
+    }
+}
+
+/* return 0 if not found */
+static uint32_t cpu_arm_find_by_name(const char *name)
+{
+    int i;
+    uint32_t id;
+
+    id = 0;
+    for (i = 0; arm_cpu_names[i].name; i++) {
+        if (strcmp(name, arm_cpu_names[i].name) == 0) {
+            id = arm_cpu_names[i].id;
+            break;
+        }
+    }
+    return id;
+}
+
+void cpu_arm_close(CPUARMState *env)
+{
+    free(env);
+}
+
+uint32_t cpsr_read(CPUARMState *env)
+{
+    int ZF;
+    ZF = (env->ZF == 0);
+    return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) |
+        (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
+        | (env->thumb << 5) | ((env->condexec_bits & 3) << 25)
+        | ((env->condexec_bits & 0xfc) << 8)
+        | (env->GE << 16);
+}
+
+void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
+{
+    if (mask & CPSR_NZCV) {
+        env->ZF = (~val) & CPSR_Z;
+        env->NF = val;
+        env->CF = (val >> 29) & 1;
+        env->VF = (val << 3) & 0x80000000;
+    }
+    if (mask & CPSR_Q)
+        env->QF = ((val & CPSR_Q) != 0);
+    if (mask & CPSR_T)
+        env->thumb = ((val & CPSR_T) != 0);
+    if (mask & CPSR_IT_0_1) {
+        env->condexec_bits &= ~3;
+        env->condexec_bits |= (val >> 25) & 3;
+    }
+    if (mask & CPSR_IT_2_7) {
+        env->condexec_bits &= 3;
+        env->condexec_bits |= (val >> 8) & 0xfc;
+    }
+    if (mask & CPSR_GE) {
+        env->GE = (val >> 16) & 0xf;
+    }
+
+    if ((env->uncached_cpsr ^ val) & mask & CPSR_M) {
+        switch_mode(env, val & CPSR_M);
+    }
+    mask &= ~CACHED_CPSR_BITS;
+    env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
+}
+
+/* Sign/zero extend */
+uint32_t HELPER(sxtb16)(uint32_t x)
+{
+    uint32_t res;
+    res = (uint16_t)(int8_t)x;
+    res |= (uint32_t)(int8_t)(x >> 16) << 16;
+    return res;
+}
+
+uint32_t HELPER(uxtb16)(uint32_t x)
+{
+    uint32_t res;
+    res = (uint16_t)(uint8_t)x;
+    res |= (uint32_t)(uint8_t)(x >> 16) << 16;
+    return res;
+}
+
+uint32_t HELPER(clz)(uint32_t x)
+{
+    return clz32(x);
+}
+
+int32_t HELPER(sdiv)(int32_t num, int32_t den)
+{
+    if (den == 0)
+      return 0;
+    if (num == INT_MIN && den == -1)
+      return INT_MIN;
+    return num / den;
+}
+
+uint32_t HELPER(udiv)(uint32_t num, uint32_t den)
+{
+    if (den == 0)
+      return 0;
+    return num / den;
+}
+
+uint32_t HELPER(rbit)(uint32_t x)
+{
+    x =  ((x & 0xff000000) >> 24)
+       | ((x & 0x00ff0000) >> 8)
+       | ((x & 0x0000ff00) << 8)
+       | ((x & 0x000000ff) << 24);
+    x =  ((x & 0xf0f0f0f0) >> 4)
+       | ((x & 0x0f0f0f0f) << 4);
+    x =  ((x & 0x88888888) >> 3)
+       | ((x & 0x44444444) >> 1)
+       | ((x & 0x22222222) << 1)
+       | ((x & 0x11111111) << 3);
+    return x;
+}
+
+uint32_t HELPER(abs)(uint32_t x)
+{
+    return ((int32_t)x < 0) ? -x : x;
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    if (rw == 2) {
+        env->exception_index = EXCP_PREFETCH_ABORT;
+        env->cp15.c6_insn = address;
+    } else {
+        env->exception_index = EXCP_DATA_ABORT;
+        env->cp15.c6_data = address;
+    }
+    return 1;
+}
+
+/* These should probably raise undefined insn exceptions.  */
+void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return;
+}
+
+uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return 0;
+}
+
+void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    cpu_abort(env, "cp15 insn %08x\n", insn);
+}
+
+uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
+{
+    cpu_abort(env, "cp15 insn %08x\n", insn);
+}
+
+/* These should probably raise undefined insn exceptions.  */
+void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val)
+{
+    cpu_abort(env, "v7m_mrs %d\n", reg);
+}
+
+uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg)
+{
+    cpu_abort(env, "v7m_mrs %d\n", reg);
+    return 0;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    if (mode != ARM_CPU_MODE_USR)
+        cpu_abort(env, "Tried to switch out of user mode\n");
+}
+
+void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val)
+{
+    cpu_abort(env, "banked r13 write\n");
+}
+
+uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
+{
+    cpu_abort(env, "banked r13 read\n");
+    return 0;
+}
+
+#else
+
+extern int semihosting_enabled;
+
+/* Map CPU modes onto saved register banks.  */
+static inline int bank_number (int mode)
+{
+    switch (mode) {
+    case ARM_CPU_MODE_USR:
+    case ARM_CPU_MODE_SYS:
+        return 0;
+    case ARM_CPU_MODE_SVC:
+        return 1;
+    case ARM_CPU_MODE_ABT:
+        return 2;
+    case ARM_CPU_MODE_UND:
+        return 3;
+    case ARM_CPU_MODE_IRQ:
+        return 4;
+    case ARM_CPU_MODE_FIQ:
+        return 5;
+    }
+    cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
+    return -1;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    int old_mode;
+    int i;
+
+    old_mode = env->uncached_cpsr & CPSR_M;
+    if (mode == old_mode)
+        return;
+
+    if (old_mode == ARM_CPU_MODE_FIQ) {
+        memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+        memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
+    } else if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+        memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
+    }
+
+    i = bank_number(old_mode);
+    env->banked_r13[i] = env->regs[13];
+    env->banked_r14[i] = env->regs[14];
+    env->banked_spsr[i] = env->spsr;
+
+    i = bank_number(mode);
+    env->regs[13] = env->banked_r13[i];
+    env->regs[14] = env->banked_r14[i];
+    env->spsr = env->banked_spsr[i];
+}
+
+static void v7m_push(CPUARMState *env, uint32_t val)
+{
+    env->regs[13] -= 4;
+    stl_phys(env->regs[13], val);
+}
+
+static uint32_t v7m_pop(CPUARMState *env)
+{
+    uint32_t val;
+    val = ldl_phys(env->regs[13]);
+    env->regs[13] += 4;
+    return val;
+}
+
+/* Switch to V7M main or process stack pointer.  */
+static void switch_v7m_sp(CPUARMState *env, int process)
+{
+    uint32_t tmp;
+    if (env->v7m.current_sp != process) {
+        tmp = env->v7m.other_sp;
+        env->v7m.other_sp = env->regs[13];
+        env->regs[13] = tmp;
+        env->v7m.current_sp = process;
+    }
+}
+
+static void do_v7m_exception_exit(CPUARMState *env)
+{
+    uint32_t type;
+    uint32_t xpsr;
+
+    type = env->regs[15];
+    if (env->v7m.exception != 0)
+        armv7m_nvic_complete_irq(env->nvic, env->v7m.exception);
+
+    /* Switch to the target stack.  */
+    switch_v7m_sp(env, (type & 4) != 0);
+    /* Pop registers.  */
+    env->regs[0] = v7m_pop(env);
+    env->regs[1] = v7m_pop(env);
+    env->regs[2] = v7m_pop(env);
+    env->regs[3] = v7m_pop(env);
+    env->regs[12] = v7m_pop(env);
+    env->regs[14] = v7m_pop(env);
+    env->regs[15] = v7m_pop(env);
+    xpsr = v7m_pop(env);
+    xpsr_write(env, xpsr, 0xfffffdff);
+    /* Undo stack alignment.  */
+    if (xpsr & 0x200)
+        env->regs[13] |= 4;
+    /* ??? The exception return type specifies Thread/Handler mode.  However
+       this is also implied by the xPSR value. Not sure what to do
+       if there is a mismatch.  */
+    /* ??? Likewise for mismatches between the CONTROL register and the stack
+       pointer.  */
+}
+
+static void do_interrupt_v7m(CPUARMState *env)
+{
+    uint32_t xpsr = xpsr_read(env);
+    uint32_t lr;
+    uint32_t addr;
+
+    lr = 0xfffffff1;
+    if (env->v7m.current_sp)
+        lr |= 4;
+    if (env->v7m.exception == 0)
+        lr |= 8;
+
+    /* For exceptions we just mark as pending on the NVIC, and let that
+       handle it.  */
+    /* TODO: Need to escalate if the current priority is higher than the
+       one we're raising.  */
+    switch (env->exception_index) {
+    case EXCP_UDEF:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
+        return;
+    case EXCP_SWI:
+        env->regs[15] += 2;
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
+        return;
+    case EXCP_PREFETCH_ABORT:
+    case EXCP_DATA_ABORT:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
+        return;
+    case EXCP_BKPT:
+        if (semihosting_enabled) {
+            int nr;
+            nr = lduw_code(env->regs[15]) & 0xff;
+            if (nr == 0xab) {
+                env->regs[15] += 2;
+                env->regs[0] = do_arm_semihosting(env);
+                return;
+            }
+        }
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
+        return;
+    case EXCP_IRQ:
+        env->v7m.exception = armv7m_nvic_acknowledge_irq(env->nvic);
+        break;
+    case EXCP_EXCEPTION_EXIT:
+        do_v7m_exception_exit(env);
+        return;
+    default:
+        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        return; /* Never happens.  Keep compiler happy.  */
+    }
+
+    /* Align stack pointer.  */
+    /* ??? Should only do this if Configuration Control Register
+       STACKALIGN bit is set.  */
+    if (env->regs[13] & 4) {
+        env->regs[13] -= 4;
+        xpsr |= 0x200;
+    }
+    /* Switch to the handler mode.  */
+    v7m_push(env, xpsr);
+    v7m_push(env, env->regs[15]);
+    v7m_push(env, env->regs[14]);
+    v7m_push(env, env->regs[12]);
+    v7m_push(env, env->regs[3]);
+    v7m_push(env, env->regs[2]);
+    v7m_push(env, env->regs[1]);
+    v7m_push(env, env->regs[0]);
+    switch_v7m_sp(env, 0);
+    env->uncached_cpsr &= ~CPSR_IT;
+    env->regs[14] = lr;
+    addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4);
+    env->regs[15] = addr & 0xfffffffe;
+    env->thumb = addr & 1;
+}
+
+/* Handle a CPU exception.  */
+void do_interrupt(CPUARMState *env)
+{
+    uint32_t addr;
+    uint32_t mask;
+    int new_mode;
+    uint32_t offset;
+
+    if (IS_M(env)) {
+        do_interrupt_v7m(env);
+        return;
+    }
+    /* TODO: Vectored interrupt controller.  */
+    switch (env->exception_index) {
+    case EXCP_UDEF:
+        new_mode = ARM_CPU_MODE_UND;
+        addr = 0x04;
+        mask = CPSR_I;
+        if (env->thumb)
+            offset = 2;
+        else
+            offset = 4;
+        break;
+    case EXCP_SWI:
+        if (semihosting_enabled) {
+            /* Check for semihosting interrupt.  */
+            if (env->thumb) {
+                mask = lduw_code(env->regs[15] - 2) & 0xff;
+            } else {
+                mask = ldl_code(env->regs[15] - 4) & 0xffffff;
+            }
+            /* Only intercept calls from privileged modes, to provide some
+               semblance of security.  */
+            if (((mask == 0x123456 && !env->thumb)
+                    || (mask == 0xab && env->thumb))
+                  && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
+                env->regs[0] = do_arm_semihosting(env);
+                return;
+            }
+        }
+        new_mode = ARM_CPU_MODE_SVC;
+        addr = 0x08;
+        mask = CPSR_I;
+        /* The PC already points to the next instruction.  */
+        offset = 0;
+        break;
+    case EXCP_BKPT:
+        /* See if this is a semihosting syscall.  */
+        if (env->thumb && semihosting_enabled) {
+            mask = lduw_code(env->regs[15]) & 0xff;
+            if (mask == 0xab
+                  && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
+                env->regs[15] += 2;
+                env->regs[0] = do_arm_semihosting(env);
+                return;
+            }
+        }
+        env->cp15.c5_insn = 2;
+        /* Fall through to prefetch abort.  */
+    case EXCP_PREFETCH_ABORT:
+        new_mode = ARM_CPU_MODE_ABT;
+        addr = 0x0c;
+        mask = CPSR_A | CPSR_I;
+        offset = 4;
+        break;
+    case EXCP_DATA_ABORT:
+        new_mode = ARM_CPU_MODE_ABT;
+        addr = 0x10;
+        mask = CPSR_A | CPSR_I;
+        offset = 8;
+        break;
+    case EXCP_IRQ:
+        new_mode = ARM_CPU_MODE_IRQ;
+        addr = 0x18;
+        /* Disable IRQ and imprecise data aborts.  */
+        mask = CPSR_A | CPSR_I;
+        offset = 4;
+        break;
+    case EXCP_FIQ:
+        new_mode = ARM_CPU_MODE_FIQ;
+        addr = 0x1c;
+        /* Disable FIQ, IRQ and imprecise data aborts.  */
+        mask = CPSR_A | CPSR_I | CPSR_F;
+        offset = 4;
+        break;
+    default:
+        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        return; /* Never happens.  Keep compiler happy.  */
+    }
+    /* High vectors.  */
+    if (env->cp15.c1_sys & (1 << 13)) {
+        addr += 0xffff0000;
+    }
+    switch_mode (env, new_mode);
+    env->spsr = cpsr_read(env);
+    /* Clear IT bits.  */
+    env->condexec_bits = 0;
+    /* Switch to the new mode, and to the correct instruction set.  */
+    env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
+    env->uncached_cpsr |= mask;
+    /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
+     * and we should just guard the thumb mode on V4 */
+    if (arm_feature(env, ARM_FEATURE_V4T)) {
+        env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
+    }
+    env->regs[14] = env->regs[15] + offset;
+    env->regs[15] = addr;
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+/* Check section/page access permissions.
+   Returns the page protection flags, or zero if the access is not
+   permitted.  */
+static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
+                           int is_user)
+{
+  int prot_ro;
+
+  if (domain == 3)
+    return PAGE_READ | PAGE_WRITE;
+
+  if (access_type == 1)
+      prot_ro = 0;
+  else
+      prot_ro = PAGE_READ;
+
+  switch (ap) {
+  case 0:
+      if (access_type == 1)
+          return 0;
+      switch ((env->cp15.c1_sys >> 8) & 3) {
+      case 1:
+          return is_user ? 0 : PAGE_READ;
+      case 2:
+          return PAGE_READ;
+      default:
+          return 0;
+      }
+  case 1:
+      return is_user ? 0 : PAGE_READ | PAGE_WRITE;
+  case 2:
+      if (is_user)
+          return prot_ro;
+      else
+          return PAGE_READ | PAGE_WRITE;
+  case 3:
+      return PAGE_READ | PAGE_WRITE;
+  case 4: /* Reserved.  */
+      return 0;
+  case 5:
+      return is_user ? 0 : prot_ro;
+  case 6:
+      return prot_ro;
+  case 7:
+      if (!arm_feature (env, ARM_FEATURE_V7))
+          return 0;
+      return prot_ro;
+  default:
+      abort();
+  }
+}
+
+static uint32_t get_level1_table_address(CPUState *env, uint32_t address)
+{
+    uint32_t table;
+
+    if (address & env->cp15.c2_mask)
+        table = env->cp15.c2_base1 & 0xffffc000;
+    else
+        table = env->cp15.c2_base0 & env->cp15.c2_base_mask;
+
+    table |= (address >> 18) & 0x3ffc;
+    return table;
+}
+
+static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type,
+			    int is_user, uint32_t *phys_ptr, int *prot,
+                            target_ulong *page_size)
+{
+    int code;
+    uint32_t table;
+    uint32_t desc;
+    int type;
+    int ap;
+    int domain;
+    uint32_t phys_addr;
+
+    /* Pagetable walk.  */
+    /* Lookup l1 descriptor.  */
+    table = get_level1_table_address(env, address);
+    desc = ldl_phys(table);
+    type = (desc & 3);
+    domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
+    if (type == 0) {
+        /* Section translation fault.  */
+        code = 5;
+        goto do_fault;
+    }
+    if (domain == 0 || domain == 2) {
+        if (type == 2)
+            code = 9; /* Section domain fault.  */
+        else
+            code = 11; /* Page domain fault.  */
+        goto do_fault;
+    }
+    if (type == 2) {
+        /* 1Mb section.  */
+        phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
+        ap = (desc >> 10) & 3;
+        code = 13;
+        *page_size = 1024 * 1024;
+    } else {
+        /* Lookup l2 entry.  */
+	if (type == 1) {
+	    /* Coarse pagetable.  */
+	    table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+	} else {
+	    /* Fine pagetable.  */
+	    table = (desc & 0xfffff000) | ((address >> 8) & 0xffc);
+	}
+        desc = ldl_phys(table);
+        switch (desc & 3) {
+        case 0: /* Page translation fault.  */
+            code = 7;
+            goto do_fault;
+        case 1: /* 64k page.  */
+            phys_addr = (desc & 0xffff0000) | (address & 0xffff);
+            ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
+            *page_size = 0x10000;
+            break;
+        case 2: /* 4k page.  */
+            phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+            ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
+            *page_size = 0x1000;
+            break;
+        case 3: /* 1k page.  */
+	    if (type == 1) {
+		if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+		    phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+		} else {
+		    /* Page translation fault.  */
+		    code = 7;
+		    goto do_fault;
+		}
+	    } else {
+		phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
+	    }
+            ap = (desc >> 4) & 3;
+            *page_size = 0x400;
+            break;
+        default:
+            /* Never happens, but compiler isn't smart enough to tell.  */
+            abort();
+        }
+        code = 15;
+    }
+    *prot = check_ap(env, ap, domain, access_type, is_user);
+    if (!*prot) {
+        /* Access permission fault.  */
+        goto do_fault;
+    }
+    *prot |= PAGE_EXEC;
+    *phys_ptr = phys_addr;
+    return 0;
+do_fault:
+    return code | (domain << 4);
+}
+
+static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
+			    int is_user, uint32_t *phys_ptr, int *prot,
+                            target_ulong *page_size)
+{
+    int code;
+    uint32_t table;
+    uint32_t desc;
+    uint32_t xn;
+    int type;
+    int ap;
+    int domain;
+    uint32_t phys_addr;
+
+    /* Pagetable walk.  */
+    /* Lookup l1 descriptor.  */
+    table = get_level1_table_address(env, address);
+    desc = ldl_phys(table);
+    type = (desc & 3);
+    if (type == 0) {
+        /* Section translation fault.  */
+        code = 5;
+        domain = 0;
+        goto do_fault;
+    } else if (type == 2 && (desc & (1 << 18))) {
+        /* Supersection.  */
+        domain = 0;
+    } else {
+        /* Section or page.  */
+        domain = (desc >> 4) & 0x1e;
+    }
+    domain = (env->cp15.c3 >> domain) & 3;
+    if (domain == 0 || domain == 2) {
+        if (type == 2)
+            code = 9; /* Section domain fault.  */
+        else
+            code = 11; /* Page domain fault.  */
+        goto do_fault;
+    }
+    if (type == 2) {
+        if (desc & (1 << 18)) {
+            /* Supersection.  */
+            phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
+            *page_size = 0x1000000;
+        } else {
+            /* Section.  */
+            phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
+            *page_size = 0x100000;
+        }
+        ap = ((desc >> 10) & 3) | ((desc >> 13) & 4);
+        xn = desc & (1 << 4);
+        code = 13;
+    } else {
+        /* Lookup l2 entry.  */
+        table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+        desc = ldl_phys(table);
+        ap = ((desc >> 4) & 3) | ((desc >> 7) & 4);
+        switch (desc & 3) {
+        case 0: /* Page translation fault.  */
+            code = 7;
+            goto do_fault;
+        case 1: /* 64k page.  */
+            phys_addr = (desc & 0xffff0000) | (address & 0xffff);
+            xn = desc & (1 << 15);
+            *page_size = 0x10000;
+            break;
+        case 2: case 3: /* 4k page.  */
+            phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+            xn = desc & 1;
+            *page_size = 0x1000;
+            break;
+        default:
+            /* Never happens, but compiler isn't smart enough to tell.  */
+            abort();
+        }
+        code = 15;
+    }
+    if (domain == 3) {
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    } else {
+        if (xn && access_type == 2)
+            goto do_fault;
+
+        /* The simplified model uses AP[0] as an access control bit.  */
+        if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
+            /* Access flag fault.  */
+            code = (code == 15) ? 6 : 3;
+            goto do_fault;
+        }
+        *prot = check_ap(env, ap, domain, access_type, is_user);
+        if (!*prot) {
+            /* Access permission fault.  */
+            goto do_fault;
+        }
+        if (!xn) {
+            *prot |= PAGE_EXEC;
+        }
+    }
+    *phys_ptr = phys_addr;
+    return 0;
+do_fault:
+    return code | (domain << 4);
+}
+
+static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type,
+			     int is_user, uint32_t *phys_ptr, int *prot)
+{
+    int n;
+    uint32_t mask;
+    uint32_t base;
+
+    *phys_ptr = address;
+    for (n = 7; n >= 0; n--) {
+	base = env->cp15.c6_region[n];
+	if ((base & 1) == 0)
+	    continue;
+	mask = 1 << ((base >> 1) & 0x1f);
+	/* Keep this shift separate from the above to avoid an
+	   (undefined) << 32.  */
+	mask = (mask << 1) - 1;
+	if (((base ^ address) & ~mask) == 0)
+	    break;
+    }
+    if (n < 0)
+	return 2;
+
+    if (access_type == 2) {
+	mask = env->cp15.c5_insn;
+    } else {
+	mask = env->cp15.c5_data;
+    }
+    mask = (mask >> (n * 4)) & 0xf;
+    switch (mask) {
+    case 0:
+	return 1;
+    case 1:
+	if (is_user)
+	  return 1;
+	*prot = PAGE_READ | PAGE_WRITE;
+	break;
+    case 2:
+	*prot = PAGE_READ;
+	if (!is_user)
+	    *prot |= PAGE_WRITE;
+	break;
+    case 3:
+	*prot = PAGE_READ | PAGE_WRITE;
+	break;
+    case 5:
+	if (is_user)
+	    return 1;
+	*prot = PAGE_READ;
+	break;
+    case 6:
+	*prot = PAGE_READ;
+	break;
+    default:
+	/* Bad permission.  */
+	return 1;
+    }
+    *prot |= PAGE_EXEC;
+    return 0;
+}
+
+static inline int get_phys_addr(CPUState *env, uint32_t address,
+                                int access_type, int is_user,
+                                uint32_t *phys_ptr, int *prot,
+                                target_ulong *page_size)
+{
+    /* Fast Context Switch Extension.  */
+    if (address < 0x02000000)
+        address += env->cp15.c13_fcse;
+
+    if ((env->cp15.c1_sys & 1) == 0) {
+        /* MMU/MPU disabled.  */
+        *phys_ptr = address;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        *page_size = TARGET_PAGE_SIZE;
+        return 0;
+    } else if (arm_feature(env, ARM_FEATURE_MPU)) {
+        *page_size = TARGET_PAGE_SIZE;
+	return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr,
+				 prot);
+    } else if (env->cp15.c1_sys & (1 << 23)) {
+        return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
+                                prot, page_size);
+    } else {
+        return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr,
+                                prot, page_size);
+    }
+}
+
+int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
+                              int access_type, int mmu_idx, int is_softmmu)
+{
+    uint32_t phys_addr;
+    target_ulong page_size;
+    int prot;
+    int ret, is_user;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+    ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,
+                        &page_size);
+    if (ret == 0) {
+        /* Map a single [sub]page.  */
+        phys_addr &= ~(uint32_t)0x3ff;
+        address &= ~(uint32_t)0x3ff;
+        tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    if (access_type == 2) {
+        env->cp15.c5_insn = ret;
+        env->cp15.c6_insn = address;
+        env->exception_index = EXCP_PREFETCH_ABORT;
+    } else {
+        env->cp15.c5_data = ret;
+        if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6))
+            env->cp15.c5_data |= (1 << 11);
+        env->cp15.c6_data = address;
+        env->exception_index = EXCP_DATA_ABORT;
+    }
+    return 1;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    uint32_t phys_addr;
+    target_ulong page_size;
+    int prot;
+    int ret;
+
+    ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot, &page_size);
+
+    if (ret != 0)
+        return -1;
+
+    return phys_addr;
+}
+
+void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int src = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_write)
+        env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
+                                 cp_info, src, operand, val);
+}
+
+uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int dest = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_read)
+        return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
+                                       cp_info, dest, operand);
+    return 0;
+}
+
+/* Return basic MPU access permission bits.  */
+static uint32_t simple_mpu_ap_bits(uint32_t val)
+{
+    uint32_t ret;
+    uint32_t mask;
+    int i;
+    ret = 0;
+    mask = 3;
+    for (i = 0; i < 16; i += 2) {
+        ret |= (val >> i) & mask;
+        mask <<= 2;
+    }
+    return ret;
+}
+
+/* Pad basic MPU access permission bits to extended format.  */
+static uint32_t extended_mpu_ap_bits(uint32_t val)
+{
+    uint32_t ret;
+    uint32_t mask;
+    int i;
+    ret = 0;
+    mask = 3;
+    for (i = 0; i < 16; i += 2) {
+        ret |= (val & mask) << i;
+        mask <<= 2;
+    }
+    return ret;
+}
+
+void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1;
+    int op2;
+    int crm;
+
+    op1 = (insn >> 21) & 7;
+    op2 = (insn >> 5) & 7;
+    crm = insn & 0xf;
+    switch ((insn >> 16) & 0xf) {
+    case 0:
+        /* ID codes.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE))
+            break;
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            break;
+        if (arm_feature(env, ARM_FEATURE_V7)
+                && op1 == 2 && crm == 0 && op2 == 0) {
+            env->cp15.c0_cssel = val & 0xf;
+            break;
+        }
+        goto bad_reg;
+    case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
+        switch (op2) {
+        case 0:
+            if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
+                env->cp15.c1_sys = val;
+            /* ??? Lots of these bits are not implemented.  */
+            /* This may enable/disable the MMU, so do a TLB flush.  */
+            tlb_flush(env, 1);
+            break;
+        case 1: /* Auxiliary control register.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+                env->cp15.c1_xscaleauxcr = val;
+                break;
+            }
+            /* Not implemented.  */
+            break;
+        case 2:
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                goto bad_reg;
+            if (env->cp15.c1_coproc != val) {
+                env->cp15.c1_coproc = val;
+                /* ??? Is this safe when called from within a TB?  */
+                tb_flush(env);
+            }
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 2: /* MMU Page table control / MPU cache control.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            switch (op2) {
+            case 0:
+                env->cp15.c2_data = val;
+                break;
+            case 1:
+                env->cp15.c2_insn = val;
+                break;
+            default:
+                goto bad_reg;
+            }
+        } else {
+	    switch (op2) {
+	    case 0:
+		env->cp15.c2_base0 = val;
+		break;
+	    case 1:
+		env->cp15.c2_base1 = val;
+		break;
+	    case 2:
+                val &= 7;
+                env->cp15.c2_control = val;
+		env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+                env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
+		break;
+	    default:
+		goto bad_reg;
+	    }
+        }
+        break;
+    case 3: /* MMU Domain access control / MPU write buffer control.  */
+        env->cp15.c3 = val;
+        tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */
+        break;
+    case 4: /* Reserved.  */
+        goto bad_reg;
+    case 5: /* MMU Fault status / MPU access permission.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
+        switch (op2) {
+        case 0:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                val = extended_mpu_ap_bits(val);
+            env->cp15.c5_data = val;
+            break;
+        case 1:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                val = extended_mpu_ap_bits(val);
+            env->cp15.c5_insn = val;
+            break;
+        case 2:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            env->cp15.c5_data = val;
+            break;
+        case 3:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            env->cp15.c5_insn = val;
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 6: /* MMU Fault address / MPU base/size.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            if (crm >= 8)
+                goto bad_reg;
+            env->cp15.c6_region[crm] = val;
+        } else {
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+            switch (op2) {
+            case 0:
+                env->cp15.c6_data = val;
+                break;
+            case 1: /* ??? This is WFAR on armv6 */
+            case 2:
+                env->cp15.c6_insn = val;
+                break;
+            default:
+                goto bad_reg;
+            }
+        }
+        break;
+    case 7: /* Cache control.  */
+        env->cp15.c15_i_max = 0x000;
+        env->cp15.c15_i_min = 0xff0;
+        if (op1 != 0) {
+            goto bad_reg;
+        }
+        /* No cache, so nothing to do except VA->PA translations. */
+        if (arm_feature(env, ARM_FEATURE_VAPA)) {
+            switch (crm) {
+            case 4:
+                if (arm_feature(env, ARM_FEATURE_V7)) {
+                    env->cp15.c7_par = val & 0xfffff6ff;
+                } else {
+                    env->cp15.c7_par = val & 0xfffff1ff;
+                }
+                break;
+            case 8: {
+                uint32_t phys_addr;
+                target_ulong page_size;
+                int prot;
+                int ret, is_user = op2 & 2;
+                int access_type = op2 & 1;
+
+                if (op2 & 4) {
+                    /* Other states are only available with TrustZone */
+                    goto bad_reg;
+                }
+                ret = get_phys_addr(env, val, access_type, is_user,
+                                    &phys_addr, &prot, &page_size);
+                if (ret == 0) {
+                    /* We do not set any attribute bits in the PAR */
+                    if (page_size == (1 << 24)
+                        && arm_feature(env, ARM_FEATURE_V7)) {
+                        env->cp15.c7_par = (phys_addr & 0xff000000) | 1 << 1;
+                    } else {
+                        env->cp15.c7_par = phys_addr & 0xfffff000;
+                    }
+                } else {
+                    env->cp15.c7_par = ((ret & (10 << 1)) >> 5) |
+                                       ((ret & (12 << 1)) >> 6) |
+                                       ((ret & 0xf) << 1) | 1;
+                }
+                break;
+            }
+            }
+        }
+        break;
+    case 8: /* MMU TLB control.  */
+        switch (op2) {
+        case 0: /* Invalidate all.  */
+            tlb_flush(env, 0);
+            break;
+        case 1: /* Invalidate single TLB entry.  */
+            tlb_flush_page(env, val & TARGET_PAGE_MASK);
+            break;
+        case 2: /* Invalidate on ASID.  */
+            tlb_flush(env, val == 0);
+            break;
+        case 3: /* Invalidate single entry on MVA.  */
+            /* ??? This is like case 1, but ignores ASID.  */
+            tlb_flush(env, 1);
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 9:
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            break;
+        if (arm_feature(env, ARM_FEATURE_STRONGARM))
+            break; /* Ignore ReadBuffer access */
+        switch (crm) {
+        case 0: /* Cache lockdown.  */
+	    switch (op1) {
+	    case 0: /* L1 cache.  */
+		switch (op2) {
+		case 0:
+		    env->cp15.c9_data = val;
+		    break;
+		case 1:
+		    env->cp15.c9_insn = val;
+		    break;
+		default:
+		    goto bad_reg;
+		}
+		break;
+	    case 1: /* L2 cache.  */
+		/* Ignore writes to L2 lockdown/auxiliary registers.  */
+		break;
+	    default:
+		goto bad_reg;
+	    }
+	    break;
+        case 1: /* TCM memory region registers.  */
+            /* Not implemented.  */
+            goto bad_reg;
+        case 12: /* Performance monitor control */
+            /* Performance monitors are implementation defined in v7,
+             * but with an ARM recommended set of registers, which we
+             * follow (although we don't actually implement any counters)
+             */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* performance monitor control register */
+                /* only the DP, X, D and E bits are writable */
+                env->cp15.c9_pmcr &= ~0x39;
+                env->cp15.c9_pmcr |= (val & 0x39);
+                break;
+            case 1: /* Count enable set register */
+                val &= (1 << 31);
+                env->cp15.c9_pmcnten |= val;
+                break;
+            case 2: /* Count enable clear */
+                val &= (1 << 31);
+                env->cp15.c9_pmcnten &= ~val;
+                break;
+            case 3: /* Overflow flag status */
+                env->cp15.c9_pmovsr &= ~val;
+                break;
+            case 4: /* Software increment */
+                /* RAZ/WI since we don't implement the software-count event */
+                break;
+            case 5: /* Event counter selection register */
+                /* Since we don't implement any events, writing to this register
+                 * is actually UNPREDICTABLE. So we choose to RAZ/WI.
+                 */
+                break;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 13: /* Performance counters */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* Cycle count register: not implemented, so RAZ/WI */
+                break;
+            case 1: /* Event type select */
+                env->cp15.c9_pmxevtyper = val & 0xff;
+                break;
+            case 2: /* Event count register */
+                /* Unimplemented (we have no events), RAZ/WI */
+                break;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 14: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* user enable */
+                env->cp15.c9_pmuserenr = val & 1;
+                /* changes access rights for cp registers, so flush tbs */
+                tb_flush(env);
+                break;
+            case 1: /* interrupt enable set */
+                /* We have no event counters so only the C bit can be changed */
+                val &= (1 << 31);
+                env->cp15.c9_pminten |= val;
+                break;
+            case 2: /* interrupt enable clear */
+                val &= (1 << 31);
+                env->cp15.c9_pminten &= ~val;
+                break;
+            }
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 10: /* MMU TLB lockdown.  */
+        /* ??? TLB lockdown not implemented.  */
+        break;
+    case 12: /* Reserved.  */
+        goto bad_reg;
+    case 13: /* Process ID.  */
+        switch (op2) {
+        case 0:
+            /* Unlike real hardware the qemu TLB uses virtual addresses,
+               not modified virtual addresses, so this causes a TLB flush.
+             */
+            if (env->cp15.c13_fcse != val)
+              tlb_flush(env, 1);
+            env->cp15.c13_fcse = val;
+            break;
+        case 1:
+            /* This changes the ASID, so do a TLB flush.  */
+            if (env->cp15.c13_context != val
+                && !arm_feature(env, ARM_FEATURE_MPU))
+              tlb_flush(env, 0);
+            env->cp15.c13_context = val;
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 14: /* Reserved.  */
+        goto bad_reg;
+    case 15: /* Implementation specific.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && crm == 1) {
+                if (env->cp15.c15_cpar != (val & 0x3fff)) {
+                    /* Changes cp0 to cp13 behavior, so needs a TB flush.  */
+                    tb_flush(env);
+                    env->cp15.c15_cpar = val & 0x3fff;
+                }
+                break;
+            }
+            goto bad_reg;
+        }
+        if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+            switch (crm) {
+            case 0:
+                break;
+            case 1: /* Set TI925T configuration.  */
+                env->cp15.c15_ticonfig = val & 0xe7;
+                env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */
+                        ARM_CPUID_TI915T : ARM_CPUID_TI925T;
+                break;
+            case 2: /* Set I_max.  */
+                env->cp15.c15_i_max = val;
+                break;
+            case 3: /* Set I_min.  */
+                env->cp15.c15_i_min = val;
+                break;
+            case 4: /* Set thread-ID.  */
+                env->cp15.c15_threadid = val & 0xffff;
+                break;
+            case 8: /* Wait-for-interrupt (deprecated).  */
+                cpu_interrupt(env, CPU_INTERRUPT_HALT);
+                break;
+            default:
+                goto bad_reg;
+            }
+        }
+        break;
+    }
+    return;
+bad_reg:
+    /* ??? For debugging only.  Should raise illegal instruction exception.  */
+    cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n",
+              (insn >> 16) & 0xf, crm, op1, op2);
+}
+
+uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
+{
+    int op1;
+    int op2;
+    int crm;
+
+    op1 = (insn >> 21) & 7;
+    op2 = (insn >> 5) & 7;
+    crm = insn & 0xf;
+    switch ((insn >> 16) & 0xf) {
+    case 0: /* ID codes.  */
+        switch (op1) {
+        case 0:
+            switch (crm) {
+            case 0:
+                switch (op2) {
+                case 0: /* Device ID.  */
+                    return env->cp15.c0_cpuid;
+                case 1: /* Cache Type.  */
+		    return env->cp15.c0_cachetype;
+                case 2: /* TCM status.  */
+                    return 0;
+                case 3: /* TLB type register.  */
+                    return 0; /* No lockable TLB entries.  */
+                case 5: /* MPIDR */
+                    /* The MPIDR was standardised in v7; prior to
+                     * this it was implemented only in the 11MPCore.
+                     * For all other pre-v7 cores it does not exist.
+                     */
+                    if (arm_feature(env, ARM_FEATURE_V7) ||
+                        ARM_CPUID(env) == ARM_CPUID_ARM11MPCORE) {
+                        int mpidr = env->cpu_index;
+                        /* We don't support setting cluster ID ([8..11])
+                         * so these bits always RAZ.
+                         */
+                        if (arm_feature(env, ARM_FEATURE_V7MP)) {
+                            mpidr |= (1 << 31);
+                            /* Cores which are uniprocessor (non-coherent)
+                             * but still implement the MP extensions set
+                             * bit 30. (For instance, A9UP.) However we do
+                             * not currently model any of those cores.
+                             */
+                        }
+                        return mpidr;
+                    }
+                    /* otherwise fall through to the unimplemented-reg case */
+                default:
+                    goto bad_reg;
+                }
+            case 1:
+                if (!arm_feature(env, ARM_FEATURE_V6))
+                    goto bad_reg;
+                return env->cp15.c0_c1[op2];
+            case 2:
+                if (!arm_feature(env, ARM_FEATURE_V6))
+                    goto bad_reg;
+                return env->cp15.c0_c2[op2];
+            case 3: case 4: case 5: case 6: case 7:
+                return 0;
+            default:
+                goto bad_reg;
+            }
+        case 1:
+            /* These registers aren't documented on arm11 cores.  However
+               Linux looks at them anyway.  */
+            if (!arm_feature(env, ARM_FEATURE_V6))
+                goto bad_reg;
+            if (crm != 0)
+                goto bad_reg;
+            if (!arm_feature(env, ARM_FEATURE_V7))
+                return 0;
+
+            switch (op2) {
+            case 0:
+                return env->cp15.c0_ccsid[env->cp15.c0_cssel];
+            case 1:
+                return env->cp15.c0_clid;
+            case 7:
+                return 0;
+            }
+            goto bad_reg;
+        case 2:
+            if (op2 != 0 || crm != 0)
+                goto bad_reg;
+            return env->cp15.c0_cssel;
+        default:
+            goto bad_reg;
+        }
+    case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
+        switch (op2) {
+        case 0: /* Control register.  */
+            return env->cp15.c1_sys;
+        case 1: /* Auxiliary control register.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                return env->cp15.c1_xscaleauxcr;
+            if (!arm_feature(env, ARM_FEATURE_AUXCR))
+                goto bad_reg;
+            switch (ARM_CPUID(env)) {
+            case ARM_CPUID_ARM1026:
+                return 1;
+            case ARM_CPUID_ARM1136:
+            case ARM_CPUID_ARM1136_R2:
+                return 7;
+            case ARM_CPUID_ARM11MPCORE:
+                return 1;
+            case ARM_CPUID_CORTEXA8:
+                return 2;
+            case ARM_CPUID_CORTEXA9:
+                return 0;
+            default:
+                goto bad_reg;
+            }
+        case 2: /* Coprocessor access register.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                goto bad_reg;
+            return env->cp15.c1_coproc;
+        default:
+            goto bad_reg;
+        }
+    case 2: /* MMU Page table control / MPU cache control.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            switch (op2) {
+            case 0:
+                return env->cp15.c2_data;
+                break;
+            case 1:
+                return env->cp15.c2_insn;
+                break;
+            default:
+                goto bad_reg;
+            }
+        } else {
+	    switch (op2) {
+	    case 0:
+		return env->cp15.c2_base0;
+	    case 1:
+		return env->cp15.c2_base1;
+	    case 2:
+                return env->cp15.c2_control;
+	    default:
+		goto bad_reg;
+	    }
+	}
+    case 3: /* MMU Domain access control / MPU write buffer control.  */
+        return env->cp15.c3;
+    case 4: /* Reserved.  */
+        goto bad_reg;
+    case 5: /* MMU Fault status / MPU access permission.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
+        switch (op2) {
+        case 0:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                return simple_mpu_ap_bits(env->cp15.c5_data);
+            return env->cp15.c5_data;
+        case 1:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                return simple_mpu_ap_bits(env->cp15.c5_data);
+            return env->cp15.c5_insn;
+        case 2:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            return env->cp15.c5_data;
+        case 3:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            return env->cp15.c5_insn;
+        default:
+            goto bad_reg;
+        }
+    case 6: /* MMU Fault address.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            if (crm >= 8)
+                goto bad_reg;
+            return env->cp15.c6_region[crm];
+        } else {
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+	    switch (op2) {
+	    case 0:
+		return env->cp15.c6_data;
+	    case 1:
+		if (arm_feature(env, ARM_FEATURE_V6)) {
+		    /* Watchpoint Fault Adrress.  */
+		    return 0; /* Not implemented.  */
+		} else {
+		    /* Instruction Fault Adrress.  */
+		    /* Arm9 doesn't have an IFAR, but implementing it anyway
+		       shouldn't do any harm.  */
+		    return env->cp15.c6_insn;
+		}
+	    case 2:
+		if (arm_feature(env, ARM_FEATURE_V6)) {
+		    /* Instruction Fault Adrress.  */
+		    return env->cp15.c6_insn;
+		} else {
+		    goto bad_reg;
+		}
+	    default:
+		goto bad_reg;
+	    }
+        }
+    case 7: /* Cache control.  */
+        if (crm == 4 && op1 == 0 && op2 == 0) {
+            return env->cp15.c7_par;
+        }
+        /* FIXME: Should only clear Z flag if destination is r15.  */
+        env->ZF = 0;
+        return 0;
+    case 8: /* MMU TLB control.  */
+        goto bad_reg;
+    case 9:
+        switch (crm) {
+        case 0: /* Cache lockdown */
+            switch (op1) {
+            case 0: /* L1 cache.  */
+                if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+                    return 0;
+                }
+                switch (op2) {
+                case 0:
+                    return env->cp15.c9_data;
+                case 1:
+                    return env->cp15.c9_insn;
+                default:
+                    goto bad_reg;
+                }
+            case 1: /* L2 cache */
+                if (crm != 0) {
+                    goto bad_reg;
+                }
+                /* L2 Lockdown and Auxiliary control.  */
+                return 0;
+            default:
+                goto bad_reg;
+            }
+            break;
+        case 12: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* performance monitor control register */
+                return env->cp15.c9_pmcr;
+            case 1: /* count enable set */
+            case 2: /* count enable clear */
+                return env->cp15.c9_pmcnten;
+            case 3: /* overflow flag status */
+                return env->cp15.c9_pmovsr;
+            case 4: /* software increment */
+            case 5: /* event counter selection register */
+                return 0; /* Unimplemented, RAZ/WI */
+            default:
+                goto bad_reg;
+            }
+        case 13: /* Performance counters */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 1: /* Event type select */
+                return env->cp15.c9_pmxevtyper;
+            case 0: /* Cycle count register */
+            case 2: /* Event count register */
+                /* Unimplemented, so RAZ/WI */
+                return 0;
+            default:
+                goto bad_reg;
+            }
+        case 14: /* Performance monitor control */
+            if (!arm_feature(env, ARM_FEATURE_V7)) {
+                goto bad_reg;
+            }
+            switch (op2) {
+            case 0: /* user enable */
+                return env->cp15.c9_pmuserenr;
+            case 1: /* interrupt enable set */
+            case 2: /* interrupt enable clear */
+                return env->cp15.c9_pminten;
+            default:
+                goto bad_reg;
+            }
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 10: /* MMU TLB lockdown.  */
+        /* ??? TLB lockdown not implemented.  */
+        return 0;
+    case 11: /* TCM DMA control.  */
+    case 12: /* Reserved.  */
+        goto bad_reg;
+    case 13: /* Process ID.  */
+        switch (op2) {
+        case 0:
+            return env->cp15.c13_fcse;
+        case 1:
+            return env->cp15.c13_context;
+        default:
+            goto bad_reg;
+        }
+    case 14: /* Reserved.  */
+        goto bad_reg;
+    case 15: /* Implementation specific.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && crm == 1)
+                return env->cp15.c15_cpar;
+
+            goto bad_reg;
+        }
+        if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+            switch (crm) {
+            case 0:
+                return 0;
+            case 1: /* Read TI925T configuration.  */
+                return env->cp15.c15_ticonfig;
+            case 2: /* Read I_max.  */
+                return env->cp15.c15_i_max;
+            case 3: /* Read I_min.  */
+                return env->cp15.c15_i_min;
+            case 4: /* Read thread-ID.  */
+                return env->cp15.c15_threadid;
+            case 8: /* TI925T_status */
+                return 0;
+            }
+            /* TODO: Peripheral port remap register:
+             * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt
+             * controller base address at $rn & ~0xfff and map size of
+             * 0x200 << ($rn & 0xfff), when MMU is off.  */
+            goto bad_reg;
+        }
+        return 0;
+    }
+bad_reg:
+    /* ??? For debugging only.  Should raise illegal instruction exception.  */
+    cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n",
+              (insn >> 16) & 0xf, crm, op1, op2);
+    return 0;
+}
+
+void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val)
+{
+    if ((env->uncached_cpsr & CPSR_M) == mode) {
+        env->regs[13] = val;
+    } else {
+        env->banked_r13[bank_number(mode)] = val;
+    }
+}
+
+uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
+{
+    if ((env->uncached_cpsr & CPSR_M) == mode) {
+        return env->regs[13];
+    } else {
+        return env->banked_r13[bank_number(mode)];
+    }
+}
+
+uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg)
+{
+    switch (reg) {
+    case 0: /* APSR */
+        return xpsr_read(env) & 0xf8000000;
+    case 1: /* IAPSR */
+        return xpsr_read(env) & 0xf80001ff;
+    case 2: /* EAPSR */
+        return xpsr_read(env) & 0xff00fc00;
+    case 3: /* xPSR */
+        return xpsr_read(env) & 0xff00fdff;
+    case 5: /* IPSR */
+        return xpsr_read(env) & 0x000001ff;
+    case 6: /* EPSR */
+        return xpsr_read(env) & 0x0700fc00;
+    case 7: /* IEPSR */
+        return xpsr_read(env) & 0x0700edff;
+    case 8: /* MSP */
+        return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13];
+    case 9: /* PSP */
+        return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp;
+    case 16: /* PRIMASK */
+        return (env->uncached_cpsr & CPSR_I) != 0;
+    case 17: /* BASEPRI */
+    case 18: /* BASEPRI_MAX */
+        return env->v7m.basepri;
+    case 19: /* FAULTMASK */
+        return (env->uncached_cpsr & CPSR_F) != 0;
+    case 20: /* CONTROL */
+        return env->v7m.control;
+    default:
+        /* ??? For debugging only.  */
+        cpu_abort(env, "Unimplemented system register read (%d)\n", reg);
+        return 0;
+    }
+}
+
+void HELPER(v7m_msr)(CPUState *env, uint32_t reg, uint32_t val)
+{
+    switch (reg) {
+    case 0: /* APSR */
+        xpsr_write(env, val, 0xf8000000);
+        break;
+    case 1: /* IAPSR */
+        xpsr_write(env, val, 0xf8000000);
+        break;
+    case 2: /* EAPSR */
+        xpsr_write(env, val, 0xfe00fc00);
+        break;
+    case 3: /* xPSR */
+        xpsr_write(env, val, 0xfe00fc00);
+        break;
+    case 5: /* IPSR */
+        /* IPSR bits are readonly.  */
+        break;
+    case 6: /* EPSR */
+        xpsr_write(env, val, 0x0600fc00);
+        break;
+    case 7: /* IEPSR */
+        xpsr_write(env, val, 0x0600fc00);
+        break;
+    case 8: /* MSP */
+        if (env->v7m.current_sp)
+            env->v7m.other_sp = val;
+        else
+            env->regs[13] = val;
+        break;
+    case 9: /* PSP */
+        if (env->v7m.current_sp)
+            env->regs[13] = val;
+        else
+            env->v7m.other_sp = val;
+        break;
+    case 16: /* PRIMASK */
+        if (val & 1)
+            env->uncached_cpsr |= CPSR_I;
+        else
+            env->uncached_cpsr &= ~CPSR_I;
+        break;
+    case 17: /* BASEPRI */
+        env->v7m.basepri = val & 0xff;
+        break;
+    case 18: /* BASEPRI_MAX */
+        val &= 0xff;
+        if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0))
+            env->v7m.basepri = val;
+        break;
+    case 19: /* FAULTMASK */
+        if (val & 1)
+            env->uncached_cpsr |= CPSR_F;
+        else
+            env->uncached_cpsr &= ~CPSR_F;
+        break;
+    case 20: /* CONTROL */
+        env->v7m.control = val & 3;
+        switch_v7m_sp(env, (val & 2) != 0);
+        break;
+    default:
+        /* ??? For debugging only.  */
+        cpu_abort(env, "Unimplemented system register write (%d)\n", reg);
+        return;
+    }
+}
+
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                void *opaque)
+{
+    if (cpnum < 0 || cpnum > 14) {
+        cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
+        return;
+    }
+
+    env->cp[cpnum].cp_read = cp_read;
+    env->cp[cpnum].cp_write = cp_write;
+    env->cp[cpnum].opaque = opaque;
+}
+
+#endif
+
+/* Note that signed overflow is undefined in C.  The following routines are
+   careful to use unsigned types where modulo arithmetic is required.
+   Failure to do so _will_ break on newer gcc.  */
+
+/* Signed saturating arithmetic.  */
+
+/* Perform 16-bit signed saturating addition.  */
+static inline uint16_t add16_sat(uint16_t a, uint16_t b)
+{
+    uint16_t res;
+
+    res = a + b;
+    if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
+        if (a & 0x8000)
+            res = 0x8000;
+        else
+            res = 0x7fff;
+    }
+    return res;
+}
+
+/* Perform 8-bit signed saturating addition.  */
+static inline uint8_t add8_sat(uint8_t a, uint8_t b)
+{
+    uint8_t res;
+
+    res = a + b;
+    if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
+        if (a & 0x80)
+            res = 0x80;
+        else
+            res = 0x7f;
+    }
+    return res;
+}
+
+/* Perform 16-bit signed saturating subtraction.  */
+static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
+{
+    uint16_t res;
+
+    res = a - b;
+    if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
+        if (a & 0x8000)
+            res = 0x8000;
+        else
+            res = 0x7fff;
+    }
+    return res;
+}
+
+/* Perform 8-bit signed saturating subtraction.  */
+static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
+{
+    uint8_t res;
+
+    res = a - b;
+    if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
+        if (a & 0x80)
+            res = 0x80;
+        else
+            res = 0x7f;
+    }
+    return res;
+}
+
+#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
+#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
+#define ADD8(a, b, n)  RESULT(add8_sat(a, b), n, 8);
+#define SUB8(a, b, n)  RESULT(sub8_sat(a, b), n, 8);
+#define PFX q
+
+#include "op_addsub.h"
+
+/* Unsigned saturating arithmetic.  */
+static inline uint16_t add16_usat(uint16_t a, uint16_t b)
+{
+    uint16_t res;
+    res = a + b;
+    if (res < a)
+        res = 0xffff;
+    return res;
+}
+
+static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
+{
+    if (a > b)
+        return a - b;
+    else
+        return 0;
+}
+
+static inline uint8_t add8_usat(uint8_t a, uint8_t b)
+{
+    uint8_t res;
+    res = a + b;
+    if (res < a)
+        res = 0xff;
+    return res;
+}
+
+static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
+{
+    if (a > b)
+        return a - b;
+    else
+        return 0;
+}
+
+#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
+#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
+#define ADD8(a, b, n)  RESULT(add8_usat(a, b), n, 8);
+#define SUB8(a, b, n)  RESULT(sub8_usat(a, b), n, 8);
+#define PFX uq
+
+#include "op_addsub.h"
+
+/* Signed modulo arithmetic.  */
+#define SARITH16(a, b, n, op) do { \
+    int32_t sum; \
+    sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
+    RESULT(sum, n, 16); \
+    if (sum >= 0) \
+        ge |= 3 << (n * 2); \
+    } while(0)
+
+#define SARITH8(a, b, n, op) do { \
+    int32_t sum; \
+    sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
+    RESULT(sum, n, 8); \
+    if (sum >= 0) \
+        ge |= 1 << n; \
+    } while(0)
+
+
+#define ADD16(a, b, n) SARITH16(a, b, n, +)
+#define SUB16(a, b, n) SARITH16(a, b, n, -)
+#define ADD8(a, b, n)  SARITH8(a, b, n, +)
+#define SUB8(a, b, n)  SARITH8(a, b, n, -)
+#define PFX s
+#define ARITH_GE
+
+#include "op_addsub.h"
+
+/* Unsigned modulo arithmetic.  */
+#define ADD16(a, b, n) do { \
+    uint32_t sum; \
+    sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
+    RESULT(sum, n, 16); \
+    if ((sum >> 16) == 1) \
+        ge |= 3 << (n * 2); \
+    } while(0)
+
+#define ADD8(a, b, n) do { \
+    uint32_t sum; \
+    sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
+    RESULT(sum, n, 8); \
+    if ((sum >> 8) == 1) \
+        ge |= 1 << n; \
+    } while(0)
+
+#define SUB16(a, b, n) do { \
+    uint32_t sum; \
+    sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
+    RESULT(sum, n, 16); \
+    if ((sum >> 16) == 0) \
+        ge |= 3 << (n * 2); \
+    } while(0)
+
+#define SUB8(a, b, n) do { \
+    uint32_t sum; \
+    sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
+    RESULT(sum, n, 8); \
+    if ((sum >> 8) == 0) \
+        ge |= 1 << n; \
+    } while(0)
+
+#define PFX u
+#define ARITH_GE
+
+#include "op_addsub.h"
+
+/* Halved signed arithmetic.  */
+#define ADD16(a, b, n) \
+  RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
+#define SUB16(a, b, n) \
+  RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
+#define ADD8(a, b, n) \
+  RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
+#define SUB8(a, b, n) \
+  RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
+#define PFX sh
+
+#include "op_addsub.h"
+
+/* Halved unsigned arithmetic.  */
+#define ADD16(a, b, n) \
+  RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
+#define SUB16(a, b, n) \
+  RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
+#define ADD8(a, b, n) \
+  RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
+#define SUB8(a, b, n) \
+  RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
+#define PFX uh
+
+#include "op_addsub.h"
+
+static inline uint8_t do_usad(uint8_t a, uint8_t b)
+{
+    if (a > b)
+        return a - b;
+    else
+        return b - a;
+}
+
+/* Unsigned sum of absolute byte differences.  */
+uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
+{
+    uint32_t sum;
+    sum = do_usad(a, b);
+    sum += do_usad(a >> 8, b >> 8);
+    sum += do_usad(a >> 16, b >>16);
+    sum += do_usad(a >> 24, b >> 24);
+    return sum;
+}
+
+/* For ARMv6 SEL instruction.  */
+uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
+{
+    uint32_t mask;
+
+    mask = 0;
+    if (flags & 1)
+        mask |= 0xff;
+    if (flags & 2)
+        mask |= 0xff00;
+    if (flags & 4)
+        mask |= 0xff0000;
+    if (flags & 8)
+        mask |= 0xff000000;
+    return (a & mask) | (b & ~mask);
+}
+
+uint32_t HELPER(logicq_cc)(uint64_t val)
+{
+    return (val >> 32) | (val != 0);
+}
+
+/* VFP support.  We follow the convention used for VFP instrunctions:
+   Single precition routines have a "s" suffix, double precision a
+   "d" suffix.  */
+
+/* Convert host exception flags to vfp form.  */
+static inline int vfp_exceptbits_from_host(int host_bits)
+{
+    int target_bits = 0;
+
+    if (host_bits & float_flag_invalid)
+        target_bits |= 1;
+    if (host_bits & float_flag_divbyzero)
+        target_bits |= 2;
+    if (host_bits & float_flag_overflow)
+        target_bits |= 4;
+    if (host_bits & (float_flag_underflow | float_flag_output_denormal))
+        target_bits |= 8;
+    if (host_bits & float_flag_inexact)
+        target_bits |= 0x10;
+    if (host_bits & float_flag_input_denormal)
+        target_bits |= 0x80;
+    return target_bits;
+}
+
+uint32_t HELPER(vfp_get_fpscr)(CPUState *env)
+{
+    int i;
+    uint32_t fpscr;
+
+    fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff)
+            | (env->vfp.vec_len << 16)
+            | (env->vfp.vec_stride << 20);
+    i = get_float_exception_flags(&env->vfp.fp_status);
+    i |= get_float_exception_flags(&env->vfp.standard_fp_status);
+    fpscr |= vfp_exceptbits_from_host(i);
+    return fpscr;
+}
+
+uint32_t vfp_get_fpscr(CPUState *env)
+{
+    return HELPER(vfp_get_fpscr)(env);
+}
+
+/* Convert vfp exception flags to target form.  */
+static inline int vfp_exceptbits_to_host(int target_bits)
+{
+    int host_bits = 0;
+
+    if (target_bits & 1)
+        host_bits |= float_flag_invalid;
+    if (target_bits & 2)
+        host_bits |= float_flag_divbyzero;
+    if (target_bits & 4)
+        host_bits |= float_flag_overflow;
+    if (target_bits & 8)
+        host_bits |= float_flag_underflow;
+    if (target_bits & 0x10)
+        host_bits |= float_flag_inexact;
+    if (target_bits & 0x80)
+        host_bits |= float_flag_input_denormal;
+    return host_bits;
+}
+
+void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
+{
+    int i;
+    uint32_t changed;
+
+    changed = env->vfp.xregs[ARM_VFP_FPSCR];
+    env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff);
+    env->vfp.vec_len = (val >> 16) & 7;
+    env->vfp.vec_stride = (val >> 20) & 3;
+
+    changed ^= val;
+    if (changed & (3 << 22)) {
+        i = (val >> 22) & 3;
+        switch (i) {
+        case 0:
+            i = float_round_nearest_even;
+            break;
+        case 1:
+            i = float_round_up;
+            break;
+        case 2:
+            i = float_round_down;
+            break;
+        case 3:
+            i = float_round_to_zero;
+            break;
+        }
+        set_float_rounding_mode(i, &env->vfp.fp_status);
+    }
+    if (changed & (1 << 24)) {
+        set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+        set_flush_inputs_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+    }
+    if (changed & (1 << 25))
+        set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
+
+    i = vfp_exceptbits_to_host(val);
+    set_float_exception_flags(i, &env->vfp.fp_status);
+    set_float_exception_flags(0, &env->vfp.standard_fp_status);
+}
+
+void vfp_set_fpscr(CPUState *env, uint32_t val)
+{
+    HELPER(vfp_set_fpscr)(env, val);
+}
+
+#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
+
+#define VFP_BINOP(name) \
+float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    return float32_ ## name(a, b, fpst); \
+} \
+float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    return float64_ ## name(a, b, fpst); \
+}
+VFP_BINOP(add)
+VFP_BINOP(sub)
+VFP_BINOP(mul)
+VFP_BINOP(div)
+#undef VFP_BINOP
+
+float32 VFP_HELPER(neg, s)(float32 a)
+{
+    return float32_chs(a);
+}
+
+float64 VFP_HELPER(neg, d)(float64 a)
+{
+    return float64_chs(a);
+}
+
+float32 VFP_HELPER(abs, s)(float32 a)
+{
+    return float32_abs(a);
+}
+
+float64 VFP_HELPER(abs, d)(float64 a)
+{
+    return float64_abs(a);
+}
+
+float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env)
+{
+    return float32_sqrt(a, &env->vfp.fp_status);
+}
+
+float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env)
+{
+    return float64_sqrt(a, &env->vfp.fp_status);
+}
+
+/* XXX: check quiet/signaling case */
+#define DO_VFP_cmp(p, type) \
+void VFP_HELPER(cmp, p)(type a, type b, CPUState *env)  \
+{ \
+    uint32_t flags; \
+    switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \
+    case 0: flags = 0x6; break; \
+    case -1: flags = 0x8; break; \
+    case 1: flags = 0x2; break; \
+    default: case 2: flags = 0x3; break; \
+    } \
+    env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \
+        | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
+} \
+void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \
+{ \
+    uint32_t flags; \
+    switch(type ## _compare(a, b, &env->vfp.fp_status)) { \
+    case 0: flags = 0x6; break; \
+    case -1: flags = 0x8; break; \
+    case 1: flags = 0x2; break; \
+    default: case 2: flags = 0x3; break; \
+    } \
+    env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \
+        | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
+}
+DO_VFP_cmp(s, float32)
+DO_VFP_cmp(d, float64)
+#undef DO_VFP_cmp
+
+/* Integer to float and float to integer conversions */
+
+#define CONV_ITOF(name, fsz, sign) \
+    float##fsz HELPER(name)(uint32_t x, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    return sign##int32_to_##float##fsz(x, fpst); \
+}
+
+#define CONV_FTOI(name, fsz, sign, round) \
+uint32_t HELPER(name)(float##fsz x, void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    if (float##fsz##_is_any_nan(x)) { \
+        float_raise(float_flag_invalid, fpst); \
+        return 0; \
+    } \
+    return float##fsz##_to_##sign##int32##round(x, fpst); \
+}
+
+#define FLOAT_CONVS(name, p, fsz, sign) \
+CONV_ITOF(vfp_##name##to##p, fsz, sign) \
+CONV_FTOI(vfp_to##name##p, fsz, sign, ) \
+CONV_FTOI(vfp_to##name##z##p, fsz, sign, _round_to_zero)
+
+FLOAT_CONVS(si, s, 32, )
+FLOAT_CONVS(si, d, 64, )
+FLOAT_CONVS(ui, s, 32, u)
+FLOAT_CONVS(ui, d, 64, u)
+
+#undef CONV_ITOF
+#undef CONV_FTOI
+#undef FLOAT_CONVS
+
+/* floating point conversion */
+float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
+{
+    float64 r = float32_to_float64(x, &env->vfp.fp_status);
+    /* ARM requires that S<->D conversion of any kind of NaN generates
+     * a quiet NaN by forcing the most significant frac bit to 1.
+     */
+    return float64_maybe_silence_nan(r);
+}
+
+float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
+{
+    float32 r =  float64_to_float32(x, &env->vfp.fp_status);
+    /* ARM requires that S<->D conversion of any kind of NaN generates
+     * a quiet NaN by forcing the most significant frac bit to 1.
+     */
+    return float32_maybe_silence_nan(r);
+}
+
+/* VFP3 fixed point conversion.  */
+#define VFP_CONV_FIX(name, p, fsz, itype, sign) \
+float##fsz HELPER(vfp_##name##to##p)(uint##fsz##_t  x, uint32_t shift, \
+                                    void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    float##fsz tmp; \
+    tmp = sign##int32_to_##float##fsz((itype##_t)x, fpst); \
+    return float##fsz##_scalbn(tmp, -(int)shift, fpst); \
+} \
+uint##fsz##_t HELPER(vfp_to##name##p)(float##fsz x, uint32_t shift, \
+                                       void *fpstp) \
+{ \
+    float_status *fpst = fpstp; \
+    float##fsz tmp; \
+    if (float##fsz##_is_any_nan(x)) { \
+        float_raise(float_flag_invalid, fpst); \
+        return 0; \
+    } \
+    tmp = float##fsz##_scalbn(x, shift, fpst); \
+    return float##fsz##_to_##itype##_round_to_zero(tmp, fpst); \
+}
+
+VFP_CONV_FIX(sh, d, 64, int16, )
+VFP_CONV_FIX(sl, d, 64, int32, )
+VFP_CONV_FIX(uh, d, 64, uint16, u)
+VFP_CONV_FIX(ul, d, 64, uint32, u)
+VFP_CONV_FIX(sh, s, 32, int16, )
+VFP_CONV_FIX(sl, s, 32, int32, )
+VFP_CONV_FIX(uh, s, 32, uint16, u)
+VFP_CONV_FIX(ul, s, 32, uint32, u)
+#undef VFP_CONV_FIX
+
+/* Half precision conversions.  */
+static float32 do_fcvt_f16_to_f32(uint32_t a, CPUState *env, float_status *s)
+{
+    int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
+    float32 r = float16_to_float32(make_float16(a), ieee, s);
+    if (ieee) {
+        return float32_maybe_silence_nan(r);
+    }
+    return r;
+}
+
+static uint32_t do_fcvt_f32_to_f16(float32 a, CPUState *env, float_status *s)
+{
+    int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
+    float16 r = float32_to_float16(a, ieee, s);
+    if (ieee) {
+        r = float16_maybe_silence_nan(r);
+    }
+    return float16_val(r);
+}
+
+float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status);
+}
+
+uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status);
+}
+
+float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
+}
+
+uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status);
+}
+
+#define float32_two make_float32(0x40000000)
+#define float32_three make_float32(0x40400000)
+#define float32_one_point_five make_float32(0x3fc00000)
+
+float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
+{
+    float_status *s = &env->vfp.standard_fp_status;
+    if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
+        (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
+        if (!(float32_is_zero(a) || float32_is_zero(b))) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        return float32_two;
+    }
+    return float32_sub(float32_two, float32_mul(a, b, s), s);
+}
+
+float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env)
+{
+    float_status *s = &env->vfp.standard_fp_status;
+    float32 product;
+    if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
+        (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
+        if (!(float32_is_zero(a) || float32_is_zero(b))) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        return float32_one_point_five;
+    }
+    product = float32_mul(a, b, s);
+    return float32_div(float32_sub(float32_three, product, s), float32_two, s);
+}
+
+/* NEON helpers.  */
+
+/* Constants 256 and 512 are used in some helpers; we avoid relying on
+ * int->float conversions at run-time.  */
+#define float64_256 make_float64(0x4070000000000000LL)
+#define float64_512 make_float64(0x4080000000000000LL)
+
+/* The algorithm that must be used to calculate the estimate
+ * is specified by the ARM ARM.
+ */
+static float64 recip_estimate(float64 a, CPUState *env)
+{
+    /* These calculations mustn't set any fp exception flags,
+     * so we use a local copy of the fp_status.
+     */
+    float_status dummy_status = env->vfp.standard_fp_status;
+    float_status *s = &dummy_status;
+    /* q = (int)(a * 512.0) */
+    float64 q = float64_mul(float64_512, a, s);
+    int64_t q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* r = 1.0 / (((double)q + 0.5) / 512.0) */
+    q = int64_to_float64(q_int, s);
+    q = float64_add(q, float64_half, s);
+    q = float64_div(q, float64_512, s);
+    q = float64_div(float64_one, q, s);
+
+    /* s = (int)(256.0 * r + 0.5) */
+    q = float64_mul(q, float64_256, s);
+    q = float64_add(q, float64_half, s);
+    q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* return (double)s / 256.0 */
+    return float64_div(int64_to_float64(q_int, s), float64_256, s);
+}
+
+float32 HELPER(recpe_f32)(float32 a, CPUState *env)
+{
+    float_status *s = &env->vfp.standard_fp_status;
+    float64 f64;
+    uint32_t val32 = float32_val(a);
+
+    int result_exp;
+    int a_exp = (val32  & 0x7f800000) >> 23;
+    int sign = val32 & 0x80000000;
+
+    if (float32_is_any_nan(a)) {
+        if (float32_is_signaling_nan(a)) {
+            float_raise(float_flag_invalid, s);
+        }
+        return float32_default_nan;
+    } else if (float32_is_infinity(a)) {
+        return float32_set_sign(float32_zero, float32_is_neg(a));
+    } else if (float32_is_zero_or_denormal(a)) {
+        if (!float32_is_zero(a)) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        float_raise(float_flag_divbyzero, s);
+        return float32_set_sign(float32_infinity, float32_is_neg(a));
+    } else if (a_exp >= 253) {
+        float_raise(float_flag_underflow, s);
+        return float32_set_sign(float32_zero, float32_is_neg(a));
+    }
+
+    f64 = make_float64((0x3feULL << 52)
+                       | ((int64_t)(val32 & 0x7fffff) << 29));
+
+    result_exp = 253 - a_exp;
+
+    f64 = recip_estimate(f64, env);
+
+    val32 = sign
+        | ((result_exp & 0xff) << 23)
+        | ((float64_val(f64) >> 29) & 0x7fffff);
+    return make_float32(val32);
+}
+
+/* The algorithm that must be used to calculate the estimate
+ * is specified by the ARM ARM.
+ */
+static float64 recip_sqrt_estimate(float64 a, CPUState *env)
+{
+    /* These calculations mustn't set any fp exception flags,
+     * so we use a local copy of the fp_status.
+     */
+    float_status dummy_status = env->vfp.standard_fp_status;
+    float_status *s = &dummy_status;
+    float64 q;
+    int64_t q_int;
+
+    if (float64_lt(a, float64_half, s)) {
+        /* range 0.25 <= a < 0.5 */
+
+        /* a in units of 1/512 rounded down */
+        /* q0 = (int)(a * 512.0);  */
+        q = float64_mul(float64_512, a, s);
+        q_int = float64_to_int64_round_to_zero(q, s);
+
+        /* reciprocal root r */
+        /* r = 1.0 / sqrt(((double)q0 + 0.5) / 512.0);  */
+        q = int64_to_float64(q_int, s);
+        q = float64_add(q, float64_half, s);
+        q = float64_div(q, float64_512, s);
+        q = float64_sqrt(q, s);
+        q = float64_div(float64_one, q, s);
+    } else {
+        /* range 0.5 <= a < 1.0 */
+
+        /* a in units of 1/256 rounded down */
+        /* q1 = (int)(a * 256.0); */
+        q = float64_mul(float64_256, a, s);
+        int64_t q_int = float64_to_int64_round_to_zero(q, s);
+
+        /* reciprocal root r */
+        /* r = 1.0 /sqrt(((double)q1 + 0.5) / 256); */
+        q = int64_to_float64(q_int, s);
+        q = float64_add(q, float64_half, s);
+        q = float64_div(q, float64_256, s);
+        q = float64_sqrt(q, s);
+        q = float64_div(float64_one, q, s);
+    }
+    /* r in units of 1/256 rounded to nearest */
+    /* s = (int)(256.0 * r + 0.5); */
+
+    q = float64_mul(q, float64_256,s );
+    q = float64_add(q, float64_half, s);
+    q_int = float64_to_int64_round_to_zero(q, s);
+
+    /* return (double)s / 256.0;*/
+    return float64_div(int64_to_float64(q_int, s), float64_256, s);
+}
+
+float32 HELPER(rsqrte_f32)(float32 a, CPUState *env)
+{
+    float_status *s = &env->vfp.standard_fp_status;
+    int result_exp;
+    float64 f64;
+    uint32_t val;
+    uint64_t val64;
+
+    val = float32_val(a);
+
+    if (float32_is_any_nan(a)) {
+        if (float32_is_signaling_nan(a)) {
+            float_raise(float_flag_invalid, s);
+        }
+        return float32_default_nan;
+    } else if (float32_is_zero_or_denormal(a)) {
+        if (!float32_is_zero(a)) {
+            float_raise(float_flag_input_denormal, s);
+        }
+        float_raise(float_flag_divbyzero, s);
+        return float32_set_sign(float32_infinity, float32_is_neg(a));
+    } else if (float32_is_neg(a)) {
+        float_raise(float_flag_invalid, s);
+        return float32_default_nan;
+    } else if (float32_is_infinity(a)) {
+        return float32_zero;
+    }
+
+    /* Normalize to a double-precision value between 0.25 and 1.0,
+     * preserving the parity of the exponent.  */
+    if ((val & 0x800000) == 0) {
+        f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
+                           | (0x3feULL << 52)
+                           | ((uint64_t)(val & 0x7fffff) << 29));
+    } else {
+        f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
+                           | (0x3fdULL << 52)
+                           | ((uint64_t)(val & 0x7fffff) << 29));
+    }
+
+    result_exp = (380 - ((val & 0x7f800000) >> 23)) / 2;
+
+    f64 = recip_sqrt_estimate(f64, env);
+
+    val64 = float64_val(f64);
+
+    val = ((val64 >> 63)  & 0x80000000)
+        | ((result_exp & 0xff) << 23)
+        | ((val64 >> 29)  & 0x7fffff);
+    return make_float32(val);
+}
+
+uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env)
+{
+    float64 f64;
+
+    if ((a & 0x80000000) == 0) {
+        return 0xffffffff;
+    }
+
+    f64 = make_float64((0x3feULL << 52)
+                       | ((int64_t)(a & 0x7fffffff) << 21));
+
+    f64 = recip_estimate (f64, env);
+
+    return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
+}
+
+uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env)
+{
+    float64 f64;
+
+    if ((a & 0xc0000000) == 0) {
+        return 0xffffffff;
+    }
+
+    if (a & 0x80000000) {
+        f64 = make_float64((0x3feULL << 52)
+                           | ((uint64_t)(a & 0x7fffffff) << 21));
+    } else { /* bits 31-30 == '01' */
+        f64 = make_float64((0x3fdULL << 52)
+                           | ((uint64_t)(a & 0x3fffffff) << 22));
+    }
+
+    f64 = recip_sqrt_estimate(f64, env);
+
+    return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
+}
+
+void HELPER(set_teecr)(CPUState *env, uint32_t val)
+{
+    val &= 1;
+    if (env->teecr != val) {
+        env->teecr = val;
+        tb_flush(env);
+    }
+}
diff --git a/qemu-0.15.x/target-arm/helper.h b/qemu-0.15.x/target-arm/helper.h
new file mode 100644
index 0000000..3ad1cb0
--- /dev/null
+++ b/qemu-0.15.x/target-arm/helper.h
@@ -0,0 +1,472 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(clz, i32, i32)
+DEF_HELPER_1(sxtb16, i32, i32)
+DEF_HELPER_1(uxtb16, i32, i32)
+
+DEF_HELPER_2(add_setq, i32, i32, i32)
+DEF_HELPER_2(add_saturate, i32, i32, i32)
+DEF_HELPER_2(sub_saturate, i32, i32, i32)
+DEF_HELPER_2(add_usaturate, i32, i32, i32)
+DEF_HELPER_2(sub_usaturate, i32, i32, i32)
+DEF_HELPER_1(double_saturate, i32, s32)
+DEF_HELPER_2(sdiv, s32, s32, s32)
+DEF_HELPER_2(udiv, i32, i32, i32)
+DEF_HELPER_1(rbit, i32, i32)
+DEF_HELPER_1(abs, i32, i32)
+
+#define PAS_OP(pfx)  \
+    DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr)
+
+PAS_OP(s)
+PAS_OP(u)
+#undef PAS_OP
+
+#define PAS_OP(pfx)  \
+    DEF_HELPER_2(pfx ## add8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## add16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## subaddx, i32, i32, i32)
+PAS_OP(q)
+PAS_OP(sh)
+PAS_OP(uq)
+PAS_OP(uh)
+#undef PAS_OP
+
+DEF_HELPER_2(ssat, i32, i32, i32)
+DEF_HELPER_2(usat, i32, i32, i32)
+DEF_HELPER_2(ssat16, i32, i32, i32)
+DEF_HELPER_2(usat16, i32, i32, i32)
+
+DEF_HELPER_2(usad8, i32, i32, i32)
+
+DEF_HELPER_1(logicq_cc, i32, i64)
+
+DEF_HELPER_3(sel_flags, i32, i32, i32, i32)
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_0(wfi, void)
+
+DEF_HELPER_2(cpsr_write, void, i32, i32)
+DEF_HELPER_0(cpsr_read, i32)
+
+DEF_HELPER_3(v7m_msr, void, env, i32, i32)
+DEF_HELPER_2(v7m_mrs, i32, env, i32)
+
+DEF_HELPER_3(set_cp15, void, env, i32, i32)
+DEF_HELPER_2(get_cp15, i32, env, i32)
+
+DEF_HELPER_3(set_cp, void, env, i32, i32)
+DEF_HELPER_2(get_cp, i32, env, i32)
+
+DEF_HELPER_2(get_r13_banked, i32, env, i32)
+DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
+
+DEF_HELPER_1(get_user_reg, i32, i32)
+DEF_HELPER_2(set_user_reg, void, i32, i32)
+
+DEF_HELPER_1(vfp_get_fpscr, i32, env)
+DEF_HELPER_2(vfp_set_fpscr, void, env, i32)
+
+DEF_HELPER_3(vfp_adds, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_addd, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_subs, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_subd, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_muls, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_muld, f64, f64, f64, ptr)
+DEF_HELPER_3(vfp_divs, f32, f32, f32, ptr)
+DEF_HELPER_3(vfp_divd, f64, f64, f64, ptr)
+DEF_HELPER_1(vfp_negs, f32, f32)
+DEF_HELPER_1(vfp_negd, f64, f64)
+DEF_HELPER_1(vfp_abss, f32, f32)
+DEF_HELPER_1(vfp_absd, f64, f64)
+DEF_HELPER_2(vfp_sqrts, f32, f32, env)
+DEF_HELPER_2(vfp_sqrtd, f64, f64, env)
+DEF_HELPER_3(vfp_cmps, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmpd, void, f64, f64, env)
+DEF_HELPER_3(vfp_cmpes, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmped, void, f64, f64, env)
+
+DEF_HELPER_2(vfp_fcvtds, f64, f32, env)
+DEF_HELPER_2(vfp_fcvtsd, f32, f64, env)
+
+DEF_HELPER_2(vfp_uitos, f32, i32, ptr)
+DEF_HELPER_2(vfp_uitod, f64, i32, ptr)
+DEF_HELPER_2(vfp_sitos, f32, i32, ptr)
+DEF_HELPER_2(vfp_sitod, f64, i32, ptr)
+
+DEF_HELPER_2(vfp_touis, i32, f32, ptr)
+DEF_HELPER_2(vfp_touid, i32, f64, ptr)
+DEF_HELPER_2(vfp_touizs, i32, f32, ptr)
+DEF_HELPER_2(vfp_touizd, i32, f64, ptr)
+DEF_HELPER_2(vfp_tosis, i32, f32, ptr)
+DEF_HELPER_2(vfp_tosid, i32, f64, ptr)
+DEF_HELPER_2(vfp_tosizs, i32, f32, ptr)
+DEF_HELPER_2(vfp_tosizd, i32, f64, ptr)
+
+DEF_HELPER_3(vfp_toshs, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_tosls, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_touhs, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_touls, i32, f32, i32, ptr)
+DEF_HELPER_3(vfp_toshd, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_tosld, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_touhd, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_tould, i64, f64, i32, ptr)
+DEF_HELPER_3(vfp_shtos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_sltos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_uhtos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_ultos, f32, i32, i32, ptr)
+DEF_HELPER_3(vfp_shtod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_sltod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_uhtod, f64, i64, i32, ptr)
+DEF_HELPER_3(vfp_ultod, f64, i64, i32, ptr)
+
+DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
+DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
+DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
+DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
+
+DEF_HELPER_3(recps_f32, f32, f32, f32, env)
+DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
+DEF_HELPER_2(recpe_f32, f32, f32, env)
+DEF_HELPER_2(rsqrte_f32, f32, f32, env)
+DEF_HELPER_2(recpe_u32, i32, i32, env)
+DEF_HELPER_2(rsqrte_u32, i32, i32, env)
+DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32)
+
+DEF_HELPER_2(add_cc, i32, i32, i32)
+DEF_HELPER_2(adc_cc, i32, i32, i32)
+DEF_HELPER_2(sub_cc, i32, i32, i32)
+DEF_HELPER_2(sbc_cc, i32, i32, i32)
+
+DEF_HELPER_2(shl, i32, i32, i32)
+DEF_HELPER_2(shr, i32, i32, i32)
+DEF_HELPER_2(sar, i32, i32, i32)
+DEF_HELPER_2(shl_cc, i32, i32, i32)
+DEF_HELPER_2(shr_cc, i32, i32, i32)
+DEF_HELPER_2(sar_cc, i32, i32, i32)
+DEF_HELPER_2(ror_cc, i32, i32, i32)
+
+/* neon_helper.c */
+DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qadd_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qsub_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qsub_s64, i64, env, i64, i64)
+
+DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
+
+DEF_HELPER_2(neon_cgt_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s32, i32, i32, i32)
+
+DEF_HELPER_2(neon_min_u8, i32, i32, i32)
+DEF_HELPER_2(neon_min_s8, i32, i32, i32)
+DEF_HELPER_2(neon_min_u16, i32, i32, i32)
+DEF_HELPER_2(neon_min_s16, i32, i32, i32)
+DEF_HELPER_2(neon_min_u32, i32, i32, i32)
+DEF_HELPER_2(neon_min_s32, i32, i32, i32)
+DEF_HELPER_2(neon_max_u8, i32, i32, i32)
+DEF_HELPER_2(neon_max_s8, i32, i32, i32)
+DEF_HELPER_2(neon_max_u16, i32, i32, i32)
+DEF_HELPER_2(neon_max_s16, i32, i32, i32)
+DEF_HELPER_2(neon_max_u32, i32, i32, i32)
+DEF_HELPER_2(neon_max_s32, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s16, i32, i32, i32)
+
+DEF_HELPER_2(neon_abd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s32, i32, i32, i32)
+
+DEF_HELPER_2(neon_shl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_shl_s64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_s64, i64, i64, i64)
+DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64);
+DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64)
+
+DEF_HELPER_2(neon_add_u8, i32, i32, i32)
+DEF_HELPER_2(neon_add_u16, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u8, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_p8, i32, i32, i32)
+DEF_HELPER_2(neon_mull_p8, i64, i32, i32)
+
+DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u8, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u16, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u32, i32, i32, i32)
+
+DEF_HELPER_1(neon_abs_s8, i32, i32)
+DEF_HELPER_1(neon_abs_s16, i32, i32)
+DEF_HELPER_1(neon_clz_u8, i32, i32)
+DEF_HELPER_1(neon_clz_u16, i32, i32)
+DEF_HELPER_1(neon_cls_s8, i32, i32)
+DEF_HELPER_1(neon_cls_s16, i32, i32)
+DEF_HELPER_1(neon_cls_s32, i32, i32)
+DEF_HELPER_1(neon_cnt_u8, i32, i32)
+
+DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32)
+
+DEF_HELPER_1(neon_narrow_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_u16, i32, i64)
+DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
+DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_high_u16, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64)
+DEF_HELPER_1(neon_widen_u8, i64, i32)
+DEF_HELPER_1(neon_widen_s8, i64, i32)
+DEF_HELPER_1(neon_widen_u16, i64, i32)
+DEF_HELPER_1(neon_widen_s16, i64, i32)
+
+DEF_HELPER_2(neon_addl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_addl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u32, i64, i64, i64)
+DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64)
+DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64)
+DEF_HELPER_2(neon_abdl_u16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u64, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s64, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u16, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s16, i64, i32, i32)
+
+DEF_HELPER_1(neon_negl_u16, i64, i64)
+DEF_HELPER_1(neon_negl_u32, i64, i64)
+DEF_HELPER_1(neon_negl_u64, i64, i64)
+
+DEF_HELPER_2(neon_qabs_s8, i32, env, i32)
+DEF_HELPER_2(neon_qabs_s16, i32, env, i32)
+DEF_HELPER_2(neon_qabs_s32, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s8, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s16, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s32, i32, env, i32)
+
+DEF_HELPER_3(neon_min_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_max_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_abd_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
+DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
+
+/* iwmmxt_helper.c */
+DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64)
+DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64)
+
+#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \
+DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \
+DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \
+DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \
+
+DEF_IWMMXT_HELPER_SIZE_ENV(unpackl)
+DEF_IWMMXT_HELPER_SIZE_ENV(unpackh)
+
+DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64)
+
+DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq)
+DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu)
+DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts)
+
+DEF_IWMMXT_HELPER_SIZE_ENV(mins)
+DEF_IWMMXT_HELPER_SIZE_ENV(minu)
+DEF_IWMMXT_HELPER_SIZE_ENV(maxs)
+DEF_IWMMXT_HELPER_SIZE_ENV(maxu)
+
+DEF_IWMMXT_HELPER_SIZE_ENV(subn)
+DEF_IWMMXT_HELPER_SIZE_ENV(addn)
+DEF_IWMMXT_HELPER_SIZE_ENV(subu)
+DEF_IWMMXT_HELPER_SIZE_ENV(addu)
+DEF_IWMMXT_HELPER_SIZE_ENV(subs)
+DEF_IWMMXT_HELPER_SIZE_ENV(adds)
+
+DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64)
+
+DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64)
+
+DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32)
+DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32)
+
+DEF_HELPER_1(iwmmxt_bcstb, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstw, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstl, i64, i32)
+
+DEF_HELPER_1(iwmmxt_addcb, i64, i64)
+DEF_HELPER_1(iwmmxt_addcw, i64, i64)
+DEF_HELPER_1(iwmmxt_addcl, i64, i64)
+
+DEF_HELPER_1(iwmmxt_msbb, i32, i64)
+DEF_HELPER_1(iwmmxt_msbw, i32, i64)
+DEF_HELPER_1(iwmmxt_msbl, i32, i64)
+
+DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32)
+
+DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64)
+
+DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
+
+DEF_HELPER_2(set_teecr, void, env, i32)
+
+DEF_HELPER_3(neon_unzip8, void, env, i32, i32)
+DEF_HELPER_3(neon_unzip16, void, env, i32, i32)
+DEF_HELPER_3(neon_qunzip8, void, env, i32, i32)
+DEF_HELPER_3(neon_qunzip16, void, env, i32, i32)
+DEF_HELPER_3(neon_qunzip32, void, env, i32, i32)
+DEF_HELPER_3(neon_zip8, void, env, i32, i32)
+DEF_HELPER_3(neon_zip16, void, env, i32, i32)
+DEF_HELPER_3(neon_qzip8, void, env, i32, i32)
+DEF_HELPER_3(neon_qzip16, void, env, i32, i32)
+DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-arm/iwmmxt_helper.c b/qemu-0.15.x/target-arm/iwmmxt_helper.c
new file mode 100644
index 0000000..843994d
--- /dev/null
+++ b/qemu-0.15.x/target-arm/iwmmxt_helper.c
@@ -0,0 +1,681 @@
+/*
+ * iwMMXt micro operations for XScale.
+ *
+ * Copyright (c) 2007 OpenedHand, Ltd.
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ * Copyright (c) 2008 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "helper.h"
+
+/* iwMMXt macros extracted from GNU gdb.  */
+
+/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations.  */
+#define SIMD8_SET( v, n, b)	((v != 0) << ((((b) + 1) * 4) + (n)))
+#define SIMD16_SET(v, n, h)	((v != 0) << ((((h) + 1) * 8) + (n)))
+#define SIMD32_SET(v, n, w)	((v != 0) << ((((w) + 1) * 16) + (n)))
+#define SIMD64_SET(v, n)	((v != 0) << (32 + (n)))
+/* Flags to pass as "n" above.  */
+#define SIMD_NBIT	-1
+#define SIMD_ZBIT	-2
+#define SIMD_CBIT	-3
+#define SIMD_VBIT	-4
+/* Various status bit macros.  */
+#define NBIT8(x)	((x) & 0x80)
+#define NBIT16(x)	((x) & 0x8000)
+#define NBIT32(x)	((x) & 0x80000000)
+#define NBIT64(x)	((x) & 0x8000000000000000ULL)
+#define ZBIT8(x)	(((x) & 0xff) == 0)
+#define ZBIT16(x)	(((x) & 0xffff) == 0)
+#define ZBIT32(x)	(((x) & 0xffffffff) == 0)
+#define ZBIT64(x)	(x == 0)
+/* Sign extension macros.  */
+#define EXTEND8H(a)	((uint16_t) (int8_t) (a))
+#define EXTEND8(a)	((uint32_t) (int8_t) (a))
+#define EXTEND16(a)	((uint32_t) (int16_t) (a))
+#define EXTEND16S(a)	((int32_t) (int16_t) (a))
+#define EXTEND32(a)	((uint64_t) (int32_t) (a))
+
+uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b)
+{
+    a = ((
+            EXTEND16S((a >> 0) & 0xffff) * EXTEND16S((b >> 0) & 0xffff) +
+            EXTEND16S((a >> 16) & 0xffff) * EXTEND16S((b >> 16) & 0xffff)
+        ) & 0xffffffff) | ((uint64_t) (
+            EXTEND16S((a >> 32) & 0xffff) * EXTEND16S((b >> 32) & 0xffff) +
+            EXTEND16S((a >> 48) & 0xffff) * EXTEND16S((b >> 48) & 0xffff)
+        ) << 32);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_madduq)(uint64_t a, uint64_t b)
+{
+    a = ((
+            ((a >> 0) & 0xffff) * ((b >> 0) & 0xffff) +
+            ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)
+        ) & 0xffffffff) | ((
+            ((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) +
+            ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)
+        ) << 32);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_sadb)(uint64_t a, uint64_t b)
+{
+#define abs(x) (((x) >= 0) ? x : -x)
+#define SADB(SHR) abs((int) ((a >> SHR) & 0xff) - (int) ((b >> SHR) & 0xff))
+    return
+        SADB(0) + SADB(8) + SADB(16) + SADB(24) +
+        SADB(32) + SADB(40) + SADB(48) + SADB(56);
+#undef SADB
+}
+
+uint64_t HELPER(iwmmxt_sadw)(uint64_t a, uint64_t b)
+{
+#define SADW(SHR) \
+    abs((int) ((a >> SHR) & 0xffff) - (int) ((b >> SHR) & 0xffff))
+    return SADW(0) + SADW(16) + SADW(32) + SADW(48);
+#undef SADW
+}
+
+uint64_t HELPER(iwmmxt_mulslw)(uint64_t a, uint64_t b)
+{
+#define MULS(SHR) ((uint64_t) ((( \
+        EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \
+    ) >> 0) & 0xffff) << SHR)
+    return MULS(0) | MULS(16) | MULS(32) | MULS(48);
+#undef MULS
+}
+
+uint64_t HELPER(iwmmxt_mulshw)(uint64_t a, uint64_t b)
+{
+#define MULS(SHR) ((uint64_t) ((( \
+        EXTEND16S((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff) \
+    ) >> 16) & 0xffff) << SHR)
+    return MULS(0) | MULS(16) | MULS(32) | MULS(48);
+#undef MULS
+}
+
+uint64_t HELPER(iwmmxt_mululw)(uint64_t a, uint64_t b)
+{
+#define MULU(SHR) ((uint64_t) ((( \
+        ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \
+    ) >> 0) & 0xffff) << SHR)
+    return MULU(0) | MULU(16) | MULU(32) | MULU(48);
+#undef MULU
+}
+
+uint64_t HELPER(iwmmxt_muluhw)(uint64_t a, uint64_t b)
+{
+#define MULU(SHR) ((uint64_t) ((( \
+        ((a >> SHR) & 0xffff) * ((b >> SHR) & 0xffff) \
+    ) >> 16) & 0xffff) << SHR)
+    return MULU(0) | MULU(16) | MULU(32) | MULU(48);
+#undef MULU
+}
+
+uint64_t HELPER(iwmmxt_macsw)(uint64_t a, uint64_t b)
+{
+#define MACS(SHR) ( \
+        EXTEND16((a >> SHR) & 0xffff) * EXTEND16S((b >> SHR) & 0xffff))
+    return (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48));
+#undef MACS
+}
+
+uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b)
+{
+#define MACU(SHR) ( \
+        (uint32_t) ((a >> SHR) & 0xffff) * \
+        (uint32_t) ((b >> SHR) & 0xffff))
+    return MACU(0) + MACU(16) + MACU(32) + MACU(48);
+#undef MACU
+}
+
+#define NZBIT8(x, i) \
+    SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \
+    SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i)
+#define NZBIT16(x, i) \
+    SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \
+    SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i)
+#define NZBIT32(x, i) \
+    SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \
+    SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i)
+#define NZBIT64(x) \
+    SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
+    SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
+#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3)			\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \
+                                                 uint64_t a, uint64_t b) \
+{								\
+    a =							        \
+        (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) |	\
+        (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) |	\
+        (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) |	\
+        (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |		        \
+        NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |		\
+        NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |		\
+        NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);		\
+    return a;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \
+                                        uint64_t a, uint64_t b) \
+{								\
+    a =							        \
+        (((a >> SH0) & 0xffff) << 0) |				\
+        (((b >> SH0) & 0xffff) << 16) |			        \
+        (((a >> SH2) & 0xffff) << 32) |			        \
+        (((b >> SH2) & 0xffff) << 48);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) |		\
+        NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3);		\
+    return a;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \
+                                        uint64_t a, uint64_t b) \
+{								\
+    a =							        \
+        (((a >> SH0) & 0xffffffff) << 0) |			\
+        (((b >> SH0) & 0xffffffff) << 32);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);		\
+    return a;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x =							        \
+        (((x >> SH0) & 0xff) << 0) |				\
+        (((x >> SH1) & 0xff) << 16) |				\
+        (((x >> SH2) & 0xff) << 32) |				\
+        (((x >> SH3) & 0xff) << 48);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |		\
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);		\
+    return x;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x =							        \
+        (((x >> SH0) & 0xffff) << 0) |				\
+        (((x >> SH2) & 0xffff) << 32);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);		\
+    return x;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x = (((x >> SH0) & 0xffffffff) << 0);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);	\
+    return x;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x =							        \
+        ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) |	        \
+        ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) |	\
+        ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) |	\
+        ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48);	        \
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |		\
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);		\
+    return x;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x =							        \
+        ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) |	\
+        ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);		\
+    return x;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \
+                                                  uint64_t x)   \
+{								\
+    x = EXTEND32((x >> SH0) & 0xffffffff);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);	\
+    return x;                                                   \
+}
+IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
+IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
+
+#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O)			\
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env,    \
+                                        uint64_t a, uint64_t b) \
+{								\
+    a =							        \
+        CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) |		\
+        CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) |		\
+        CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) |		\
+        CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff);		\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |		        \
+        NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |		\
+        NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |		\
+        NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);		\
+    return a;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env,    \
+                                        uint64_t a, uint64_t b) \
+{								\
+    a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) |	\
+        CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |		\
+        NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);		\
+    return a;                                                   \
+}								\
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env,    \
+                                        uint64_t a, uint64_t b) \
+{								\
+    a = CMP(0, Tl, O, 0xffffffff) |				\
+        CMP(32, Tl, O, 0xffffffff);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);		\
+    return a;                                                   \
+}
+#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
+            (TYPE) ((b >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR)
+IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==)
+IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >)
+IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >)
+#undef CMP
+#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
+            (TYPE) ((b >> SHR) & MASK)) ? a : b) & ((uint64_t) MASK << SHR))
+IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <)
+IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <)
+IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >)
+IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >)
+#undef CMP
+#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \
+            OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR)
+IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -)
+IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +)
+#undef CMP
+/* TODO Signed- and Unsigned-Saturation */
+#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((a >> SHR) & MASK) \
+            OPER (TYPE) ((b >> SHR) & MASK)) & MASK) << SHR)
+IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -)
+IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +)
+IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -)
+IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +)
+#undef CMP
+#undef IWMMXT_OP_CMP
+
+#define AVGB(SHR) ((( \
+        ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR)
+#define IWMMXT_OP_AVGB(r)                                                 \
+uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b)    \
+{                                                                         \
+    const int round = r;                                                  \
+    a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) |                         \
+        AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56);                        \
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =                                 \
+        SIMD8_SET(ZBIT8((a >> 0) & 0xff), SIMD_ZBIT, 0) |                 \
+        SIMD8_SET(ZBIT8((a >> 8) & 0xff), SIMD_ZBIT, 1) |                 \
+        SIMD8_SET(ZBIT8((a >> 16) & 0xff), SIMD_ZBIT, 2) |                \
+        SIMD8_SET(ZBIT8((a >> 24) & 0xff), SIMD_ZBIT, 3) |                \
+        SIMD8_SET(ZBIT8((a >> 32) & 0xff), SIMD_ZBIT, 4) |                \
+        SIMD8_SET(ZBIT8((a >> 40) & 0xff), SIMD_ZBIT, 5) |                \
+        SIMD8_SET(ZBIT8((a >> 48) & 0xff), SIMD_ZBIT, 6) |                \
+        SIMD8_SET(ZBIT8((a >> 56) & 0xff), SIMD_ZBIT, 7);                 \
+    return a;                                                             \
+}
+IWMMXT_OP_AVGB(0)
+IWMMXT_OP_AVGB(1)
+#undef IWMMXT_OP_AVGB
+#undef AVGB
+
+#define AVGW(SHR) ((( \
+        ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR)
+#define IWMMXT_OP_AVGW(r)                                               \
+uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b)  \
+{                                                                       \
+    const int round = r;                                                \
+    a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48);                       \
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =                               \
+        SIMD16_SET(ZBIT16((a >> 0) & 0xffff), SIMD_ZBIT, 0) |           \
+        SIMD16_SET(ZBIT16((a >> 16) & 0xffff), SIMD_ZBIT, 1) |          \
+        SIMD16_SET(ZBIT16((a >> 32) & 0xffff), SIMD_ZBIT, 2) |          \
+        SIMD16_SET(ZBIT16((a >> 48) & 0xffff), SIMD_ZBIT, 3);           \
+    return a;                                                           \
+}
+IWMMXT_OP_AVGW(0)
+IWMMXT_OP_AVGW(1)
+#undef IWMMXT_OP_AVGW
+#undef AVGW
+
+uint64_t HELPER(iwmmxt_msadb)(uint64_t a, uint64_t b)
+{
+    a =  ((((a >> 0 ) & 0xffff) * ((b >> 0) & 0xffff) +
+           ((a >> 16) & 0xffff) * ((b >> 16) & 0xffff)) & 0xffffffff) |
+         ((((a >> 32) & 0xffff) * ((b >> 32) & 0xffff) +
+           ((a >> 48) & 0xffff) * ((b >> 48) & 0xffff)) << 32);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_align)(uint64_t a, uint64_t b, uint32_t n)
+{
+    a >>= n << 3;
+    a |= b << (64 - (n << 3));
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_insr)(uint64_t x, uint32_t a, uint32_t b, uint32_t n)
+{
+    x &= ~((uint64_t) b << n);
+    x |= (uint64_t) (a & b) << n;
+    return x;
+}
+
+uint32_t HELPER(iwmmxt_setpsr_nz)(uint64_t x)
+{
+    return SIMD64_SET((x == 0), SIMD_ZBIT) |
+           SIMD64_SET((x & (1ULL << 63)), SIMD_NBIT);
+}
+
+uint64_t HELPER(iwmmxt_bcstb)(uint32_t arg)
+{
+    arg &= 0xff;
+    return
+        ((uint64_t) arg << 0 ) | ((uint64_t) arg << 8 ) |
+        ((uint64_t) arg << 16) | ((uint64_t) arg << 24) |
+        ((uint64_t) arg << 32) | ((uint64_t) arg << 40) |
+        ((uint64_t) arg << 48) | ((uint64_t) arg << 56);
+}
+
+uint64_t HELPER(iwmmxt_bcstw)(uint32_t arg)
+{
+    arg &= 0xffff;
+    return
+        ((uint64_t) arg << 0 ) | ((uint64_t) arg << 16) |
+        ((uint64_t) arg << 32) | ((uint64_t) arg << 48);
+}
+
+uint64_t HELPER(iwmmxt_bcstl)(uint32_t arg)
+{
+    return arg | ((uint64_t) arg << 32);
+}
+
+uint64_t HELPER(iwmmxt_addcb)(uint64_t x)
+{
+    return
+        ((x >> 0) & 0xff) + ((x >> 8) & 0xff) +
+        ((x >> 16) & 0xff) + ((x >> 24) & 0xff) +
+        ((x >> 32) & 0xff) + ((x >> 40) & 0xff) +
+        ((x >> 48) & 0xff) + ((x >> 56) & 0xff);
+}
+
+uint64_t HELPER(iwmmxt_addcw)(uint64_t x)
+{
+    return
+        ((x >> 0) & 0xffff) + ((x >> 16) & 0xffff) +
+        ((x >> 32) & 0xffff) + ((x >> 48) & 0xffff);
+}
+
+uint64_t HELPER(iwmmxt_addcl)(uint64_t x)
+{
+    return (x & 0xffffffff) + (x >> 32);
+}
+
+uint32_t HELPER(iwmmxt_msbb)(uint64_t x)
+{
+    return
+        ((x >> 7) & 0x01) | ((x >> 14) & 0x02) |
+        ((x >> 21) & 0x04) | ((x >> 28) & 0x08) |
+        ((x >> 35) & 0x10) | ((x >> 42) & 0x20) |
+        ((x >> 49) & 0x40) | ((x >> 56) & 0x80);
+}
+
+uint32_t HELPER(iwmmxt_msbw)(uint64_t x)
+{
+    return
+        ((x >> 15) & 0x01) | ((x >> 30) & 0x02) |
+        ((x >> 45) & 0x04) | ((x >> 52) & 0x08);
+}
+
+uint32_t HELPER(iwmmxt_msbl)(uint64_t x)
+{
+    return ((x >> 31) & 0x01) | ((x >> 62) & 0x02);
+}
+
+/* FIXME: Split wCASF setting into a separate op to avoid env use.  */
+uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) |
+        (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) |
+        (((x & (0xffffll << 32)) >> n) & (0xffffll << 32)) |
+        (((x & (0xffffll << 48)) >> n) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = ((x & (0xffffffffll << 0)) >> n) |
+        ((x >> n) & (0xffffffffll << 32));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x >>= n;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) |
+        (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) |
+        (((x & (0xffffll << 32)) << n) & (0xffffll << 32)) |
+        (((x & (0xffffll << 48)) << n) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = ((x << n) & (0xffffffffll << 0)) |
+        ((x & (0xffffffffll << 32)) << n);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x <<= n;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) |
+        ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) |
+        ((uint64_t) ((EXTEND16(x >> 32) >> n) & 0xffff) << 32) |
+        ((uint64_t) ((EXTEND16(x >> 48) >> n) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) |
+        (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (int64_t) x >> n;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = ((((x & (0xffffll << 0)) >> n) |
+          ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) |
+        ((((x & (0xffffll << 16)) >> n) |
+          ((x & (0xffffll << 16)) << (16 - n))) & (0xffffll << 16)) |
+        ((((x & (0xffffll << 32)) >> n) |
+          ((x & (0xffffll << 32)) << (16 - n))) & (0xffffll << 32)) |
+        ((((x & (0xffffll << 48)) >> n) |
+          ((x & (0xffffll << 48)) << (16 - n))) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = ((x & (0xffffffffll << 0)) >> n) |
+        ((x >> n) & (0xffffffffll << 32)) |
+        ((x << (32 - n)) & (0xffffffffll << 0)) |
+        ((x & (0xffffffffll << 32)) << (32 - n));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (x >> n) | (x << (64 - n));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
+    return x;
+}
+
+uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n)
+{
+    x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) |
+        (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) |
+        (((x >> ((n << 0) & 0x30)) & 0xffff) << 32) |
+        (((x >> ((n >> 2) & 0x30)) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |
+        NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);
+    return x;
+}
+
+/* TODO: Unsigned-Saturation */
+uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
+        (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
+        (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) |
+        (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |
+        NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |
+        NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |
+        NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
+        (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |
+        NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);
+    return a;
+}
+
+/* TODO: Signed-Saturation */
+uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
+        (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
+        (((b >> 0) & 0xff) << 32) | (((b >> 16) & 0xff) << 40) |
+        (((b >> 32) & 0xff) << 48) | (((b >> 48) & 0xff) << 56);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |
+        NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |
+        NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |
+        NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
+        (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |
+        NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b)
+{
+    a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);
+    return a;
+}
+
+uint64_t HELPER(iwmmxt_muladdsl)(uint64_t c, uint32_t a, uint32_t b)
+{
+    return c + ((int32_t) EXTEND32(a) * (int32_t) EXTEND32(b));
+}
+
+uint64_t HELPER(iwmmxt_muladdsw)(uint64_t c, uint32_t a, uint32_t b)
+{
+    c += EXTEND32(EXTEND16S((a >> 0) & 0xffff) *
+                  EXTEND16S((b >> 0) & 0xffff));
+    c += EXTEND32(EXTEND16S((a >> 16) & 0xffff) *
+                  EXTEND16S((b >> 16) & 0xffff));
+    return c;
+}
+
+uint64_t HELPER(iwmmxt_muladdswl)(uint64_t c, uint32_t a, uint32_t b)
+{
+    return c + (EXTEND32(EXTEND16S(a & 0xffff) *
+                         EXTEND16S(b & 0xffff)));
+}
diff --git a/qemu-0.15.x/target-arm/machine.c b/qemu-0.15.x/target-arm/machine.c
new file mode 100644
index 0000000..7d4fc54
--- /dev/null
+++ b/qemu-0.15.x/target-arm/machine.c
@@ -0,0 +1,225 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    int i;
+    CPUARMState *env = (CPUARMState *)opaque;
+
+    for (i = 0; i < 16; i++) {
+        qemu_put_be32(f, env->regs[i]);
+    }
+    qemu_put_be32(f, cpsr_read(env));
+    qemu_put_be32(f, env->spsr);
+    for (i = 0; i < 6; i++) {
+        qemu_put_be32(f, env->banked_spsr[i]);
+        qemu_put_be32(f, env->banked_r13[i]);
+        qemu_put_be32(f, env->banked_r14[i]);
+    }
+    for (i = 0; i < 5; i++) {
+        qemu_put_be32(f, env->usr_regs[i]);
+        qemu_put_be32(f, env->fiq_regs[i]);
+    }
+    qemu_put_be32(f, env->cp15.c0_cpuid);
+    qemu_put_be32(f, env->cp15.c0_cachetype);
+    qemu_put_be32(f, env->cp15.c0_cssel);
+    qemu_put_be32(f, env->cp15.c1_sys);
+    qemu_put_be32(f, env->cp15.c1_coproc);
+    qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+    qemu_put_be32(f, env->cp15.c2_base0);
+    qemu_put_be32(f, env->cp15.c2_base1);
+    qemu_put_be32(f, env->cp15.c2_control);
+    qemu_put_be32(f, env->cp15.c2_mask);
+    qemu_put_be32(f, env->cp15.c2_base_mask);
+    qemu_put_be32(f, env->cp15.c2_data);
+    qemu_put_be32(f, env->cp15.c2_insn);
+    qemu_put_be32(f, env->cp15.c3);
+    qemu_put_be32(f, env->cp15.c5_insn);
+    qemu_put_be32(f, env->cp15.c5_data);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be32(f, env->cp15.c6_region[i]);
+    }
+    qemu_put_be32(f, env->cp15.c6_insn);
+    qemu_put_be32(f, env->cp15.c6_data);
+    qemu_put_be32(f, env->cp15.c7_par);
+    qemu_put_be32(f, env->cp15.c9_insn);
+    qemu_put_be32(f, env->cp15.c9_data);
+    qemu_put_be32(f, env->cp15.c9_pmcr);
+    qemu_put_be32(f, env->cp15.c9_pmcnten);
+    qemu_put_be32(f, env->cp15.c9_pmovsr);
+    qemu_put_be32(f, env->cp15.c9_pmxevtyper);
+    qemu_put_be32(f, env->cp15.c9_pmuserenr);
+    qemu_put_be32(f, env->cp15.c9_pminten);
+    qemu_put_be32(f, env->cp15.c13_fcse);
+    qemu_put_be32(f, env->cp15.c13_context);
+    qemu_put_be32(f, env->cp15.c13_tls1);
+    qemu_put_be32(f, env->cp15.c13_tls2);
+    qemu_put_be32(f, env->cp15.c13_tls3);
+    qemu_put_be32(f, env->cp15.c15_cpar);
+
+    qemu_put_be32(f, env->features);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.d = env->vfp.regs[i];
+            qemu_put_be32(f, u.l.upper);
+            qemu_put_be32(f, u.l.lower);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->vfp.xregs[i]);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        qemu_put_be32(f, env->vfp.vec_len);
+        qemu_put_be32(f, env->vfp.vec_stride);
+
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            for (i = 16;  i < 32; i++) {
+                CPU_DoubleU u;
+                u.d = env->vfp.regs[i];
+                qemu_put_be32(f, u.l.upper);
+                qemu_put_be32(f, u.l.lower);
+            }
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            qemu_put_be64(f, env->iwmmxt.regs[i]);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->iwmmxt.cregs[i]);
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        qemu_put_be32(f, env->v7m.other_sp);
+        qemu_put_be32(f, env->v7m.vecbase);
+        qemu_put_be32(f, env->v7m.basepri);
+        qemu_put_be32(f, env->v7m.control);
+        qemu_put_be32(f, env->v7m.current_sp);
+        qemu_put_be32(f, env->v7m.exception);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        qemu_put_be32(f, env->teecr);
+        qemu_put_be32(f, env->teehbr);
+    }
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    CPUARMState *env = (CPUARMState *)opaque;
+    int i;
+    uint32_t val;
+
+    if (version_id != CPU_SAVE_VERSION)
+        return -EINVAL;
+
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = qemu_get_be32(f);
+    }
+    val = qemu_get_be32(f);
+    /* Avoid mode switch when restoring CPSR.  */
+    env->uncached_cpsr = val & CPSR_M;
+    cpsr_write(env, val, 0xffffffff);
+    env->spsr = qemu_get_be32(f);
+    for (i = 0; i < 6; i++) {
+        env->banked_spsr[i] = qemu_get_be32(f);
+        env->banked_r13[i] = qemu_get_be32(f);
+        env->banked_r14[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < 5; i++) {
+        env->usr_regs[i] = qemu_get_be32(f);
+        env->fiq_regs[i] = qemu_get_be32(f);
+    }
+    env->cp15.c0_cpuid = qemu_get_be32(f);
+    env->cp15.c0_cachetype = qemu_get_be32(f);
+    env->cp15.c0_cssel = qemu_get_be32(f);
+    env->cp15.c1_sys = qemu_get_be32(f);
+    env->cp15.c1_coproc = qemu_get_be32(f);
+    env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+    env->cp15.c2_base0 = qemu_get_be32(f);
+    env->cp15.c2_base1 = qemu_get_be32(f);
+    env->cp15.c2_control = qemu_get_be32(f);
+    env->cp15.c2_mask = qemu_get_be32(f);
+    env->cp15.c2_base_mask = qemu_get_be32(f);
+    env->cp15.c2_data = qemu_get_be32(f);
+    env->cp15.c2_insn = qemu_get_be32(f);
+    env->cp15.c3 = qemu_get_be32(f);
+    env->cp15.c5_insn = qemu_get_be32(f);
+    env->cp15.c5_data = qemu_get_be32(f);
+    for (i = 0; i < 8; i++) {
+        env->cp15.c6_region[i] = qemu_get_be32(f);
+    }
+    env->cp15.c6_insn = qemu_get_be32(f);
+    env->cp15.c6_data = qemu_get_be32(f);
+    env->cp15.c7_par = qemu_get_be32(f);
+    env->cp15.c9_insn = qemu_get_be32(f);
+    env->cp15.c9_data = qemu_get_be32(f);
+    env->cp15.c9_pmcr = qemu_get_be32(f);
+    env->cp15.c9_pmcnten = qemu_get_be32(f);
+    env->cp15.c9_pmovsr = qemu_get_be32(f);
+    env->cp15.c9_pmxevtyper = qemu_get_be32(f);
+    env->cp15.c9_pmuserenr = qemu_get_be32(f);
+    env->cp15.c9_pminten = qemu_get_be32(f);
+    env->cp15.c13_fcse = qemu_get_be32(f);
+    env->cp15.c13_context = qemu_get_be32(f);
+    env->cp15.c13_tls1 = qemu_get_be32(f);
+    env->cp15.c13_tls2 = qemu_get_be32(f);
+    env->cp15.c13_tls3 = qemu_get_be32(f);
+    env->cp15.c15_cpar = qemu_get_be32(f);
+
+    env->features = qemu_get_be32(f);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.l.upper = qemu_get_be32(f);
+            u.l.lower = qemu_get_be32(f);
+            env->vfp.regs[i] = u.d;
+        }
+        for (i = 0; i < 16; i++) {
+            env->vfp.xregs[i] = qemu_get_be32(f);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        env->vfp.vec_len = qemu_get_be32(f);
+        env->vfp.vec_stride = qemu_get_be32(f);
+
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            for (i = 0;  i < 16; i++) {
+                CPU_DoubleU u;
+                u.l.upper = qemu_get_be32(f);
+                u.l.lower = qemu_get_be32(f);
+                env->vfp.regs[i] = u.d;
+            }
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.regs[i] = qemu_get_be64(f);
+        }
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.cregs[i] = qemu_get_be32(f);
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        env->v7m.other_sp = qemu_get_be32(f);
+        env->v7m.vecbase = qemu_get_be32(f);
+        env->v7m.basepri = qemu_get_be32(f);
+        env->v7m.control = qemu_get_be32(f);
+        env->v7m.current_sp = qemu_get_be32(f);
+        env->v7m.exception = qemu_get_be32(f);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        env->teecr = qemu_get_be32(f);
+        env->teehbr = qemu_get_be32(f);
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/target-arm/neon_helper.c b/qemu-0.15.x/target-arm/neon_helper.c
new file mode 100644
index 0000000..b51e35a
--- /dev/null
+++ b/qemu-0.15.x/target-arm/neon_helper.c
@@ -0,0 +1,2017 @@
+/*
+ * ARM NEON vector operations.
+ *
+ * Copyright (c) 2007, 2008 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "helper.h"
+
+#define SIGNBIT (uint32_t)0x80000000
+#define SIGNBIT64 ((uint64_t)1 << 63)
+
+#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q
+
+#define NEON_TYPE1(name, type) \
+typedef struct \
+{ \
+    type v1; \
+} neon_##name;
+#ifdef HOST_WORDS_BIGENDIAN
+#define NEON_TYPE2(name, type) \
+typedef struct \
+{ \
+    type v2; \
+    type v1; \
+} neon_##name;
+#define NEON_TYPE4(name, type) \
+typedef struct \
+{ \
+    type v4; \
+    type v3; \
+    type v2; \
+    type v1; \
+} neon_##name;
+#else
+#define NEON_TYPE2(name, type) \
+typedef struct \
+{ \
+    type v1; \
+    type v2; \
+} neon_##name;
+#define NEON_TYPE4(name, type) \
+typedef struct \
+{ \
+    type v1; \
+    type v2; \
+    type v3; \
+    type v4; \
+} neon_##name;
+#endif
+
+NEON_TYPE4(s8, int8_t)
+NEON_TYPE4(u8, uint8_t)
+NEON_TYPE2(s16, int16_t)
+NEON_TYPE2(u16, uint16_t)
+NEON_TYPE1(s32, int32_t)
+NEON_TYPE1(u32, uint32_t)
+#undef NEON_TYPE4
+#undef NEON_TYPE2
+#undef NEON_TYPE1
+
+/* Copy from a uint32_t to a vector structure type.  */
+#define NEON_UNPACK(vtype, dest, val) do { \
+    union { \
+        vtype v; \
+        uint32_t i; \
+    } conv_u; \
+    conv_u.i = (val); \
+    dest = conv_u.v; \
+    } while(0)
+
+/* Copy from a vector structure type to a uint32_t.  */
+#define NEON_PACK(vtype, dest, val) do { \
+    union { \
+        vtype v; \
+        uint32_t i; \
+    } conv_u; \
+    conv_u.v = (val); \
+    dest = conv_u.i; \
+    } while(0)
+
+#define NEON_DO1 \
+    NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1);
+#define NEON_DO2 \
+    NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \
+    NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2);
+#define NEON_DO4 \
+    NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \
+    NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \
+    NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \
+    NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4);
+
+#define NEON_VOP_BODY(vtype, n) \
+{ \
+    uint32_t res; \
+    vtype vsrc1; \
+    vtype vsrc2; \
+    vtype vdest; \
+    NEON_UNPACK(vtype, vsrc1, arg1); \
+    NEON_UNPACK(vtype, vsrc2, arg2); \
+    NEON_DO##n; \
+    NEON_PACK(vtype, res, vdest); \
+    return res; \
+}
+
+#define NEON_VOP(name, vtype, n) \
+uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \
+NEON_VOP_BODY(vtype, n)
+
+#define NEON_VOP_ENV(name, vtype, n) \
+uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \
+NEON_VOP_BODY(vtype, n)
+
+/* Pairwise operations.  */
+/* For 32-bit elements each segment only contains a single element, so
+   the elementwise and pairwise operations are the same.  */
+#define NEON_PDO2 \
+    NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \
+    NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2);
+#define NEON_PDO4 \
+    NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \
+    NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \
+    NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \
+    NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \
+
+#define NEON_POP(name, vtype, n) \
+uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \
+{ \
+    uint32_t res; \
+    vtype vsrc1; \
+    vtype vsrc2; \
+    vtype vdest; \
+    NEON_UNPACK(vtype, vsrc1, arg1); \
+    NEON_UNPACK(vtype, vsrc2, arg2); \
+    NEON_PDO##n; \
+    NEON_PACK(vtype, res, vdest); \
+    return res; \
+}
+
+/* Unary operators.  */
+#define NEON_VOP1(name, vtype, n) \
+uint32_t HELPER(glue(neon_,name))(uint32_t arg) \
+{ \
+    vtype vsrc1; \
+    vtype vdest; \
+    NEON_UNPACK(vtype, vsrc1, arg); \
+    NEON_DO##n; \
+    NEON_PACK(vtype, arg, vdest); \
+    return arg; \
+}
+
+
+#define NEON_USAT(dest, src1, src2, type) do { \
+    uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
+    if (tmp != (type)tmp) { \
+        SET_QC(); \
+        dest = ~0; \
+    } else { \
+        dest = tmp; \
+    }} while(0)
+#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
+NEON_VOP_ENV(qadd_u8, neon_u8, 4)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
+NEON_VOP_ENV(qadd_u16, neon_u16, 2)
+#undef NEON_FN
+#undef NEON_USAT
+
+uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b)
+{
+    uint32_t res = a + b;
+    if (res < a) {
+        SET_QC();
+        res = ~0;
+    }
+    return res;
+}
+
+uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2)
+{
+    uint64_t res;
+
+    res = src1 + src2;
+    if (res < src1) {
+        SET_QC();
+        res = ~(uint64_t)0;
+    }
+    return res;
+}
+
+#define NEON_SSAT(dest, src1, src2, type) do { \
+    int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
+    if (tmp != (type)tmp) { \
+        SET_QC(); \
+        if (src2 > 0) { \
+            tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \
+        } else { \
+            tmp = 1 << (sizeof(type) * 8 - 1); \
+        } \
+    } \
+    dest = tmp; \
+    } while(0)
+#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
+NEON_VOP_ENV(qadd_s8, neon_s8, 4)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
+NEON_VOP_ENV(qadd_s16, neon_s16, 2)
+#undef NEON_FN
+#undef NEON_SSAT
+
+uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b)
+{
+    uint32_t res = a + b;
+    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
+        SET_QC();
+        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+    }
+    return res;
+}
+
+uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2)
+{
+    uint64_t res;
+
+    res = src1 + src2;
+    if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
+        SET_QC();
+        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
+    }
+    return res;
+}
+
+#define NEON_USAT(dest, src1, src2, type) do { \
+    uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
+    if (tmp != (type)tmp) { \
+        SET_QC(); \
+        dest = 0; \
+    } else { \
+        dest = tmp; \
+    }} while(0)
+#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
+NEON_VOP_ENV(qsub_u8, neon_u8, 4)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
+NEON_VOP_ENV(qsub_u16, neon_u16, 2)
+#undef NEON_FN
+#undef NEON_USAT
+
+uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b)
+{
+    uint32_t res = a - b;
+    if (res > a) {
+        SET_QC();
+        res = 0;
+    }
+    return res;
+}
+
+uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2)
+{
+    uint64_t res;
+
+    if (src1 < src2) {
+        SET_QC();
+        res = 0;
+    } else {
+        res = src1 - src2;
+    }
+    return res;
+}
+
+#define NEON_SSAT(dest, src1, src2, type) do { \
+    int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
+    if (tmp != (type)tmp) { \
+        SET_QC(); \
+        if (src2 < 0) { \
+            tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \
+        } else { \
+            tmp = 1 << (sizeof(type) * 8 - 1); \
+        } \
+    } \
+    dest = tmp; \
+    } while(0)
+#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
+NEON_VOP_ENV(qsub_s8, neon_s8, 4)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
+NEON_VOP_ENV(qsub_s16, neon_s16, 2)
+#undef NEON_FN
+#undef NEON_SSAT
+
+uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b)
+{
+    uint32_t res = a - b;
+    if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
+        SET_QC();
+        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+    }
+    return res;
+}
+
+uint64_t HELPER(neon_qsub_s64)(CPUState *env, uint64_t src1, uint64_t src2)
+{
+    uint64_t res;
+
+    res = src1 - src2;
+    if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
+        SET_QC();
+        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
+    }
+    return res;
+}
+
+#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1
+NEON_VOP(hadd_s8, neon_s8, 4)
+NEON_VOP(hadd_u8, neon_u8, 4)
+NEON_VOP(hadd_s16, neon_s16, 2)
+NEON_VOP(hadd_u16, neon_u16, 2)
+#undef NEON_FN
+
+int32_t HELPER(neon_hadd_s32)(int32_t src1, int32_t src2)
+{
+    int32_t dest;
+
+    dest = (src1 >> 1) + (src2 >> 1);
+    if (src1 & src2 & 1)
+        dest++;
+    return dest;
+}
+
+uint32_t HELPER(neon_hadd_u32)(uint32_t src1, uint32_t src2)
+{
+    uint32_t dest;
+
+    dest = (src1 >> 1) + (src2 >> 1);
+    if (src1 & src2 & 1)
+        dest++;
+    return dest;
+}
+
+#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1
+NEON_VOP(rhadd_s8, neon_s8, 4)
+NEON_VOP(rhadd_u8, neon_u8, 4)
+NEON_VOP(rhadd_s16, neon_s16, 2)
+NEON_VOP(rhadd_u16, neon_u16, 2)
+#undef NEON_FN
+
+int32_t HELPER(neon_rhadd_s32)(int32_t src1, int32_t src2)
+{
+    int32_t dest;
+
+    dest = (src1 >> 1) + (src2 >> 1);
+    if ((src1 | src2) & 1)
+        dest++;
+    return dest;
+}
+
+uint32_t HELPER(neon_rhadd_u32)(uint32_t src1, uint32_t src2)
+{
+    uint32_t dest;
+
+    dest = (src1 >> 1) + (src2 >> 1);
+    if ((src1 | src2) & 1)
+        dest++;
+    return dest;
+}
+
+#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1
+NEON_VOP(hsub_s8, neon_s8, 4)
+NEON_VOP(hsub_u8, neon_u8, 4)
+NEON_VOP(hsub_s16, neon_s16, 2)
+NEON_VOP(hsub_u16, neon_u16, 2)
+#undef NEON_FN
+
+int32_t HELPER(neon_hsub_s32)(int32_t src1, int32_t src2)
+{
+    int32_t dest;
+
+    dest = (src1 >> 1) - (src2 >> 1);
+    if ((~src1) & src2 & 1)
+        dest--;
+    return dest;
+}
+
+uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2)
+{
+    uint32_t dest;
+
+    dest = (src1 >> 1) - (src2 >> 1);
+    if ((~src1) & src2 & 1)
+        dest--;
+    return dest;
+}
+
+#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0
+NEON_VOP(cgt_s8, neon_s8, 4)
+NEON_VOP(cgt_u8, neon_u8, 4)
+NEON_VOP(cgt_s16, neon_s16, 2)
+NEON_VOP(cgt_u16, neon_u16, 2)
+NEON_VOP(cgt_s32, neon_s32, 1)
+NEON_VOP(cgt_u32, neon_u32, 1)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0
+NEON_VOP(cge_s8, neon_s8, 4)
+NEON_VOP(cge_u8, neon_u8, 4)
+NEON_VOP(cge_s16, neon_s16, 2)
+NEON_VOP(cge_u16, neon_u16, 2)
+NEON_VOP(cge_s32, neon_s32, 1)
+NEON_VOP(cge_u32, neon_u32, 1)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2
+NEON_VOP(min_s8, neon_s8, 4)
+NEON_VOP(min_u8, neon_u8, 4)
+NEON_VOP(min_s16, neon_s16, 2)
+NEON_VOP(min_u16, neon_u16, 2)
+NEON_VOP(min_s32, neon_s32, 1)
+NEON_VOP(min_u32, neon_u32, 1)
+NEON_POP(pmin_s8, neon_s8, 4)
+NEON_POP(pmin_u8, neon_u8, 4)
+NEON_POP(pmin_s16, neon_s16, 2)
+NEON_POP(pmin_u16, neon_u16, 2)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2
+NEON_VOP(max_s8, neon_s8, 4)
+NEON_VOP(max_u8, neon_u8, 4)
+NEON_VOP(max_s16, neon_s16, 2)
+NEON_VOP(max_u16, neon_u16, 2)
+NEON_VOP(max_s32, neon_s32, 1)
+NEON_VOP(max_u32, neon_u32, 1)
+NEON_POP(pmax_s8, neon_s8, 4)
+NEON_POP(pmax_u8, neon_u8, 4)
+NEON_POP(pmax_s16, neon_s16, 2)
+NEON_POP(pmax_u16, neon_u16, 2)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) \
+    dest = (src1 > src2) ? (src1 - src2) : (src2 - src1)
+NEON_VOP(abd_s8, neon_s8, 4)
+NEON_VOP(abd_u8, neon_u8, 4)
+NEON_VOP(abd_s16, neon_s16, 2)
+NEON_VOP(abd_u16, neon_u16, 2)
+NEON_VOP(abd_s32, neon_s32, 1)
+NEON_VOP(abd_u32, neon_u32, 1)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8 || \
+        tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp < 0) { \
+        dest = src1 >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+    }} while (0)
+NEON_VOP(shl_u8, neon_u8, 4)
+NEON_VOP(shl_u16, neon_u16, 2)
+NEON_VOP(shl_u32, neon_u32, 1)
+#undef NEON_FN
+
+uint64_t HELPER(neon_shl_u64)(uint64_t val, uint64_t shiftop)
+{
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 64 || shift <= -64) {
+        val = 0;
+    } else if (shift < 0) {
+        val >>= -shift;
+    } else {
+        val <<= shift;
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = src1 >> (sizeof(src1) * 8 - 1); \
+    } else if (tmp < 0) { \
+        dest = src1 >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+    }} while (0)
+NEON_VOP(shl_s8, neon_s8, 4)
+NEON_VOP(shl_s16, neon_s16, 2)
+NEON_VOP(shl_s32, neon_s32, 1)
+#undef NEON_FN
+
+uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop)
+{
+    int8_t shift = (int8_t)shiftop;
+    int64_t val = valop;
+    if (shift >= 64) {
+        val = 0;
+    } else if (shift <= -64) {
+        val >>= 63;
+    } else if (shift < 0) {
+        val >>= -shift;
+    } else {
+        val <<= shift;
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if ((tmp >= (ssize_t)sizeof(src1) * 8) \
+        || (tmp <= -(ssize_t)sizeof(src1) * 8)) { \
+        dest = 0; \
+    } else if (tmp < 0) { \
+        dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+    }} while (0)
+NEON_VOP(rshl_s8, neon_s8, 4)
+NEON_VOP(rshl_s16, neon_s16, 2)
+#undef NEON_FN
+
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
+{
+    int32_t dest;
+    int32_t val = (int32_t)valop;
+    int8_t shift = (int8_t)shiftop;
+    if ((shift >= 32) || (shift <= -32)) {
+        dest = 0;
+    } else if (shift < 0) {
+        int64_t big_dest = ((int64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
+uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
+{
+    int8_t shift = (int8_t)shiftop;
+    int64_t val = valop;
+    if ((shift >= 64) || (shift <= -64)) {
+        val = 0;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == INT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x4000000000000000LL;
+        } else {
+            val++;
+            val >>= 1;
+        }
+    } else {
+        val <<= shift;
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8 || \
+        tmp < -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \
+        dest = src1 >> (-tmp - 1); \
+    } else if (tmp < 0) { \
+        dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+    }} while (0)
+NEON_VOP(rshl_u8, neon_u8, 4)
+NEON_VOP(rshl_u16, neon_u16, 2)
+#undef NEON_FN
+
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
+{
+    uint32_t dest;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32 || shift < -32) {
+        dest = 0;
+    } else if (shift == -32) {
+        dest = val >> 31;
+    } else if (shift < 0) {
+        uint64_t big_dest = ((uint64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
+uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
+{
+    int8_t shift = (uint8_t)shiftop;
+    if (shift >= 64 || shift < -64) {
+        val = 0;
+    } else if (shift == -64) {
+        /* Rounding a 1-bit result just preserves that bit.  */
+        val >>= 63;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == UINT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x8000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
+    } else {
+        val <<= shift;
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = ~0; \
+        } else { \
+            dest = 0; \
+        } \
+    } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp < 0) { \
+        dest = src1 >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+        if ((dest >> tmp) != src1) { \
+            SET_QC(); \
+            dest = ~0; \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qshl_u8, neon_u8, 4)
+NEON_VOP_ENV(qshl_u16, neon_u16, 2)
+NEON_VOP_ENV(qshl_u32, neon_u32, 1)
+#undef NEON_FN
+
+uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
+{
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 64) {
+        if (val) {
+            val = ~(uint64_t)0;
+            SET_QC();
+        }
+    } else if (shift <= -64) {
+        val = 0;
+    } else if (shift < 0) {
+        val >>= -shift;
+    } else {
+        uint64_t tmp = val;
+        val <<= shift;
+        if ((val >> shift) != tmp) {
+            SET_QC();
+            val = ~(uint64_t)0;
+        }
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } else { \
+            dest = src1; \
+        } \
+    } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = src1 >> 31; \
+    } else if (tmp < 0) { \
+        dest = src1 >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+        if ((dest >> tmp) != src1) { \
+            SET_QC(); \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qshl_s8, neon_s8, 4)
+NEON_VOP_ENV(qshl_s16, neon_s16, 2)
+NEON_VOP_ENV(qshl_s32, neon_s32, 1)
+#undef NEON_FN
+
+uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+    int8_t shift = (uint8_t)shiftop;
+    int64_t val = valop;
+    if (shift >= 64) {
+        if (val) {
+            SET_QC();
+            val = (val >> 63) ^ ~SIGNBIT64;
+        }
+    } else if (shift <= -64) {
+        val >>= 63;
+    } else if (shift < 0) {
+        val >>= -shift;
+    } else {
+        int64_t tmp = val;
+        val <<= shift;
+        if ((val >> shift) != tmp) {
+            SET_QC();
+            val = (tmp >> 63) ^ ~SIGNBIT64;
+        }
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    if (src1 & (1 << (sizeof(src1) * 8 - 1))) { \
+        SET_QC(); \
+        dest = 0; \
+    } else { \
+        int8_t tmp; \
+        tmp = (int8_t)src2; \
+        if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+            if (src1) { \
+                SET_QC(); \
+                dest = ~0; \
+            } else { \
+                dest = 0; \
+            } \
+        } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+            dest = 0; \
+        } else if (tmp < 0) { \
+            dest = src1 >> -tmp; \
+        } else { \
+            dest = src1 << tmp; \
+            if ((dest >> tmp) != src1) { \
+                SET_QC(); \
+                dest = ~0; \
+            } \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qshlu_s8, neon_u8, 4)
+NEON_VOP_ENV(qshlu_s16, neon_u16, 2)
+#undef NEON_FN
+
+uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+{
+    if ((int32_t)valop < 0) {
+        SET_QC();
+        return 0;
+    }
+    return helper_neon_qshl_u32(env, valop, shiftop);
+}
+
+uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+    if ((int64_t)valop < 0) {
+        SET_QC();
+        return 0;
+    }
+    return helper_neon_qshl_u64(env, valop, shiftop);
+}
+
+/* FIXME: This is wrong.  */
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = ~0; \
+        } else { \
+            dest = 0; \
+        } \
+    } else if (tmp < -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp == -(ssize_t)sizeof(src1) * 8) { \
+        dest = src1 >> (sizeof(src1) * 8 - 1); \
+    } else if (tmp < 0) { \
+        dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+        if ((dest >> tmp) != src1) { \
+            SET_QC(); \
+            dest = ~0; \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qrshl_u8, neon_u8, 4)
+NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
+#undef NEON_FN
+
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop)
+{
+    uint32_t dest;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32) {
+        if (val) {
+            SET_QC();
+            dest = ~0;
+        } else {
+            dest = 0;
+        }
+    } else if (shift < -32) {
+        dest = 0;
+    } else if (shift == -32) {
+        dest = val >> 31;
+    } else if (shift < 0) {
+        uint64_t big_dest = ((uint64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+        if ((dest >> shift) != val) {
+            SET_QC();
+            dest = ~0;
+        }
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
+uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
+{
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 64) {
+        if (val) {
+            SET_QC();
+            val = ~0;
+        }
+    } else if (shift < -64) {
+        val = 0;
+    } else if (shift == -64) {
+        val >>= 63;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == UINT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x8000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
+    } else { \
+        uint64_t tmp = val;
+        val <<= shift;
+        if ((val >> shift) != tmp) {
+            SET_QC();
+            val = ~0;
+        }
+    }
+    return val;
+}
+
+#define NEON_FN(dest, src1, src2) do { \
+    int8_t tmp; \
+    tmp = (int8_t)src2; \
+    if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+        if (src1) { \
+            SET_QC(); \
+            dest = (1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } else { \
+            dest = 0; \
+        } \
+    } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+        dest = 0; \
+    } else if (tmp < 0) { \
+        dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
+    } else { \
+        dest = src1 << tmp; \
+        if ((dest >> tmp) != src1) { \
+            SET_QC(); \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qrshl_s8, neon_s8, 4)
+NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
+#undef NEON_FN
+
+/* The addition of the rounding constant may overflow, so we use an
+ * intermediate 64 bits accumulator.  */
+uint32_t HELPER(neon_qrshl_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+{
+    int32_t dest;
+    int32_t val = (int32_t)valop;
+    int8_t shift = (int8_t)shiftop;
+    if (shift >= 32) {
+        if (val) {
+            SET_QC();
+            dest = (val >> 31) ^ ~SIGNBIT;
+        } else {
+            dest = 0;
+        }
+    } else if (shift <= -32) {
+        dest = 0;
+    } else if (shift < 0) {
+        int64_t big_dest = ((int64_t)val + (1 << (-1 - shift)));
+        dest = big_dest >> -shift;
+    } else {
+        dest = val << shift;
+        if ((dest >> shift) != val) {
+            SET_QC();
+            dest = (val >> 31) ^ ~SIGNBIT;
+        }
+    }
+    return dest;
+}
+
+/* Handling addition overflow with 64 bits inputs values is more
+ * tricky than with 32 bits values.  */
+uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+    int8_t shift = (uint8_t)shiftop;
+    int64_t val = valop;
+
+    if (shift >= 64) {
+        if (val) {
+            SET_QC();
+            val = (val >> 63) ^ ~SIGNBIT64;
+        }
+    } else if (shift <= -64) {
+        val = 0;
+    } else if (shift < 0) {
+        val >>= (-shift - 1);
+        if (val == INT64_MAX) {
+            /* In this case, it means that the rounding constant is 1,
+             * and the addition would overflow. Return the actual
+             * result directly.  */
+            val = 0x4000000000000000ULL;
+        } else {
+            val++;
+            val >>= 1;
+        }
+    } else {
+        int64_t tmp = val;
+        val <<= shift;
+        if ((val >> shift) != tmp) {
+            SET_QC();
+            val = (tmp >> 63) ^ ~SIGNBIT64;
+        }
+    }
+    return val;
+}
+
+uint32_t HELPER(neon_add_u8)(uint32_t a, uint32_t b)
+{
+    uint32_t mask;
+    mask = (a ^ b) & 0x80808080u;
+    a &= ~0x80808080u;
+    b &= ~0x80808080u;
+    return (a + b) ^ mask;
+}
+
+uint32_t HELPER(neon_add_u16)(uint32_t a, uint32_t b)
+{
+    uint32_t mask;
+    mask = (a ^ b) & 0x80008000u;
+    a &= ~0x80008000u;
+    b &= ~0x80008000u;
+    return (a + b) ^ mask;
+}
+
+#define NEON_FN(dest, src1, src2) dest = src1 + src2
+NEON_POP(padd_u8, neon_u8, 4)
+NEON_POP(padd_u16, neon_u16, 2)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = src1 - src2
+NEON_VOP(sub_u8, neon_u8, 4)
+NEON_VOP(sub_u16, neon_u16, 2)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = src1 * src2
+NEON_VOP(mul_u8, neon_u8, 4)
+NEON_VOP(mul_u16, neon_u16, 2)
+#undef NEON_FN
+
+/* Polynomial multiplication is like integer multiplication except the
+   partial products are XORed, not added.  */
+uint32_t HELPER(neon_mul_p8)(uint32_t op1, uint32_t op2)
+{
+    uint32_t mask;
+    uint32_t result;
+    result = 0;
+    while (op1) {
+        mask = 0;
+        if (op1 & 1)
+            mask |= 0xff;
+        if (op1 & (1 << 8))
+            mask |= (0xff << 8);
+        if (op1 & (1 << 16))
+            mask |= (0xff << 16);
+        if (op1 & (1 << 24))
+            mask |= (0xff << 24);
+        result ^= op2 & mask;
+        op1 = (op1 >> 1) & 0x7f7f7f7f;
+        op2 = (op2 << 1) & 0xfefefefe;
+    }
+    return result;
+}
+
+uint64_t HELPER(neon_mull_p8)(uint32_t op1, uint32_t op2)
+{
+    uint64_t result = 0;
+    uint64_t mask;
+    uint64_t op2ex = op2;
+    op2ex = (op2ex & 0xff) |
+        ((op2ex & 0xff00) << 8) |
+        ((op2ex & 0xff0000) << 16) |
+        ((op2ex & 0xff000000) << 24);
+    while (op1) {
+        mask = 0;
+        if (op1 & 1) {
+            mask |= 0xffff;
+        }
+        if (op1 & (1 << 8)) {
+            mask |= (0xffffU << 16);
+        }
+        if (op1 & (1 << 16)) {
+            mask |= (0xffffULL << 32);
+        }
+        if (op1 & (1 << 24)) {
+            mask |= (0xffffULL << 48);
+        }
+        result ^= op2ex & mask;
+        op1 = (op1 >> 1) & 0x7f7f7f7f;
+        op2ex <<= 1;
+    }
+    return result;
+}
+
+#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0
+NEON_VOP(tst_u8, neon_u8, 4)
+NEON_VOP(tst_u16, neon_u16, 2)
+NEON_VOP(tst_u32, neon_u32, 1)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0
+NEON_VOP(ceq_u8, neon_u8, 4)
+NEON_VOP(ceq_u16, neon_u16, 2)
+NEON_VOP(ceq_u32, neon_u32, 1)
+#undef NEON_FN
+
+#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src
+NEON_VOP1(abs_s8, neon_s8, 4)
+NEON_VOP1(abs_s16, neon_s16, 2)
+#undef NEON_FN
+
+/* Count Leading Sign/Zero Bits.  */
+static inline int do_clz8(uint8_t x)
+{
+    int n;
+    for (n = 8; x; n--)
+        x >>= 1;
+    return n;
+}
+
+static inline int do_clz16(uint16_t x)
+{
+    int n;
+    for (n = 16; x; n--)
+        x >>= 1;
+    return n;
+}
+
+#define NEON_FN(dest, src, dummy) dest = do_clz8(src)
+NEON_VOP1(clz_u8, neon_u8, 4)
+#undef NEON_FN
+
+#define NEON_FN(dest, src, dummy) dest = do_clz16(src)
+NEON_VOP1(clz_u16, neon_u16, 2)
+#undef NEON_FN
+
+#define NEON_FN(dest, src, dummy) dest = do_clz8((src < 0) ? ~src : src) - 1
+NEON_VOP1(cls_s8, neon_s8, 4)
+#undef NEON_FN
+
+#define NEON_FN(dest, src, dummy) dest = do_clz16((src < 0) ? ~src : src) - 1
+NEON_VOP1(cls_s16, neon_s16, 2)
+#undef NEON_FN
+
+uint32_t HELPER(neon_cls_s32)(uint32_t x)
+{
+    int count;
+    if ((int32_t)x < 0)
+        x = ~x;
+    for (count = 32; x; count--)
+        x = x >> 1;
+    return count - 1;
+}
+
+/* Bit count.  */
+uint32_t HELPER(neon_cnt_u8)(uint32_t x)
+{
+    x = (x & 0x55555555) + ((x >>  1) & 0x55555555);
+    x = (x & 0x33333333) + ((x >>  2) & 0x33333333);
+    x = (x & 0x0f0f0f0f) + ((x >>  4) & 0x0f0f0f0f);
+    return x;
+}
+
+#define NEON_QDMULH16(dest, src1, src2, round) do { \
+    uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \
+    if ((tmp ^ (tmp << 1)) & SIGNBIT) { \
+        SET_QC(); \
+        tmp = (tmp >> 31) ^ ~SIGNBIT; \
+    } else { \
+        tmp <<= 1; \
+    } \
+    if (round) { \
+        int32_t old = tmp; \
+        tmp += 1 << 15; \
+        if ((int32_t)tmp < old) { \
+            SET_QC(); \
+            tmp = SIGNBIT - 1; \
+        } \
+    } \
+    dest = tmp >> 16; \
+    } while(0)
+#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0)
+NEON_VOP_ENV(qdmulh_s16, neon_s16, 2)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1)
+NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2)
+#undef NEON_FN
+#undef NEON_QDMULH16
+
+#define NEON_QDMULH32(dest, src1, src2, round) do { \
+    uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \
+    if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \
+        SET_QC(); \
+        tmp = (tmp >> 63) ^ ~SIGNBIT64; \
+    } else { \
+        tmp <<= 1; \
+    } \
+    if (round) { \
+        int64_t old = tmp; \
+        tmp += (int64_t)1 << 31; \
+        if ((int64_t)tmp < old) { \
+            SET_QC(); \
+            tmp = SIGNBIT64 - 1; \
+        } \
+    } \
+    dest = tmp >> 32; \
+    } while(0)
+#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0)
+NEON_VOP_ENV(qdmulh_s32, neon_s32, 1)
+#undef NEON_FN
+#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1)
+NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1)
+#undef NEON_FN
+#undef NEON_QDMULH32
+
+uint32_t HELPER(neon_narrow_u8)(uint64_t x)
+{
+    return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u)
+           | ((x >> 24) & 0xff000000u);
+}
+
+uint32_t HELPER(neon_narrow_u16)(uint64_t x)
+{
+    return (x & 0xffffu) | ((x >> 16) & 0xffff0000u);
+}
+
+uint32_t HELPER(neon_narrow_high_u8)(uint64_t x)
+{
+    return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00)
+            | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000);
+}
+
+uint32_t HELPER(neon_narrow_high_u16)(uint64_t x)
+{
+    return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
+}
+
+uint32_t HELPER(neon_narrow_round_high_u8)(uint64_t x)
+{
+    x &= 0xff80ff80ff80ff80ull;
+    x += 0x0080008000800080ull;
+    return ((x >> 8) & 0xff) | ((x >> 16) & 0xff00)
+            | ((x >> 24) & 0xff0000) | ((x >> 32) & 0xff000000);
+}
+
+uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x)
+{
+    x &= 0xffff8000ffff8000ull;
+    x += 0x0000800000008000ull;
+    return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
+}
+
+uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x)
+{
+    uint16_t s;
+    uint8_t d;
+    uint32_t res = 0;
+#define SAT8(n) \
+    s = x >> n; \
+    if (s & 0x8000) { \
+        SET_QC(); \
+    } else { \
+        if (s > 0xff) { \
+            d = 0xff; \
+            SET_QC(); \
+        } else  { \
+            d = s; \
+        } \
+        res |= (uint32_t)d << (n / 2); \
+    }
+
+    SAT8(0);
+    SAT8(16);
+    SAT8(32);
+    SAT8(48);
+#undef SAT8
+    return res;
+}
+
+uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
+{
+    uint16_t s;
+    uint8_t d;
+    uint32_t res = 0;
+#define SAT8(n) \
+    s = x >> n; \
+    if (s > 0xff) { \
+        d = 0xff; \
+        SET_QC(); \
+    } else  { \
+        d = s; \
+    } \
+    res |= (uint32_t)d << (n / 2);
+
+    SAT8(0);
+    SAT8(16);
+    SAT8(32);
+    SAT8(48);
+#undef SAT8
+    return res;
+}
+
+uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x)
+{
+    int16_t s;
+    uint8_t d;
+    uint32_t res = 0;
+#define SAT8(n) \
+    s = x >> n; \
+    if (s != (int8_t)s) { \
+        d = (s >> 15) ^ 0x7f; \
+        SET_QC(); \
+    } else  { \
+        d = s; \
+    } \
+    res |= (uint32_t)d << (n / 2);
+
+    SAT8(0);
+    SAT8(16);
+    SAT8(32);
+    SAT8(48);
+#undef SAT8
+    return res;
+}
+
+uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x)
+{
+    uint32_t high;
+    uint32_t low;
+    low = x;
+    if (low & 0x80000000) {
+        low = 0;
+        SET_QC();
+    } else if (low > 0xffff) {
+        low = 0xffff;
+        SET_QC();
+    }
+    high = x >> 32;
+    if (high & 0x80000000) {
+        high = 0;
+        SET_QC();
+    } else if (high > 0xffff) {
+        high = 0xffff;
+        SET_QC();
+    }
+    return low | (high << 16);
+}
+
+uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
+{
+    uint32_t high;
+    uint32_t low;
+    low = x;
+    if (low > 0xffff) {
+        low = 0xffff;
+        SET_QC();
+    }
+    high = x >> 32;
+    if (high > 0xffff) {
+        high = 0xffff;
+        SET_QC();
+    }
+    return low | (high << 16);
+}
+
+uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x)
+{
+    int32_t low;
+    int32_t high;
+    low = x;
+    if (low != (int16_t)low) {
+        low = (low >> 31) ^ 0x7fff;
+        SET_QC();
+    }
+    high = x >> 32;
+    if (high != (int16_t)high) {
+        high = (high >> 31) ^ 0x7fff;
+        SET_QC();
+    }
+    return (uint16_t)low | (high << 16);
+}
+
+uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x)
+{
+    if (x & 0x8000000000000000ull) {
+        SET_QC();
+        return 0;
+    }
+    if (x > 0xffffffffu) {
+        SET_QC();
+        return 0xffffffffu;
+    }
+    return x;
+}
+
+uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
+{
+    if (x > 0xffffffffu) {
+        SET_QC();
+        return 0xffffffffu;
+    }
+    return x;
+}
+
+uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x)
+{
+    if ((int64_t)x != (int32_t)x) {
+        SET_QC();
+        return ((int64_t)x >> 63) ^ 0x7fffffff;
+    }
+    return x;
+}
+
+uint64_t HELPER(neon_widen_u8)(uint32_t x)
+{
+    uint64_t tmp;
+    uint64_t ret;
+    ret = (uint8_t)x;
+    tmp = (uint8_t)(x >> 8);
+    ret |= tmp << 16;
+    tmp = (uint8_t)(x >> 16);
+    ret |= tmp << 32;
+    tmp = (uint8_t)(x >> 24);
+    ret |= tmp << 48;
+    return ret;
+}
+
+uint64_t HELPER(neon_widen_s8)(uint32_t x)
+{
+    uint64_t tmp;
+    uint64_t ret;
+    ret = (uint16_t)(int8_t)x;
+    tmp = (uint16_t)(int8_t)(x >> 8);
+    ret |= tmp << 16;
+    tmp = (uint16_t)(int8_t)(x >> 16);
+    ret |= tmp << 32;
+    tmp = (uint16_t)(int8_t)(x >> 24);
+    ret |= tmp << 48;
+    return ret;
+}
+
+uint64_t HELPER(neon_widen_u16)(uint32_t x)
+{
+    uint64_t high = (uint16_t)(x >> 16);
+    return ((uint16_t)x) | (high << 32);
+}
+
+uint64_t HELPER(neon_widen_s16)(uint32_t x)
+{
+    uint64_t high = (int16_t)(x >> 16);
+    return ((uint32_t)(int16_t)x) | (high << 32);
+}
+
+uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b)
+{
+    uint64_t mask;
+    mask = (a ^ b) & 0x8000800080008000ull;
+    a &= ~0x8000800080008000ull;
+    b &= ~0x8000800080008000ull;
+    return (a + b) ^ mask;
+}
+
+uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b)
+{
+    uint64_t mask;
+    mask = (a ^ b) & 0x8000000080000000ull;
+    a &= ~0x8000000080000000ull;
+    b &= ~0x8000000080000000ull;
+    return (a + b) ^ mask;
+}
+
+uint64_t HELPER(neon_paddl_u16)(uint64_t a, uint64_t b)
+{
+    uint64_t tmp;
+    uint64_t tmp2;
+
+    tmp = a & 0x0000ffff0000ffffull;
+    tmp += (a >> 16) & 0x0000ffff0000ffffull;
+    tmp2 = b & 0xffff0000ffff0000ull;
+    tmp2 += (b << 16) & 0xffff0000ffff0000ull;
+    return    ( tmp         & 0xffff)
+            | ((tmp  >> 16) & 0xffff0000ull)
+            | ((tmp2 << 16) & 0xffff00000000ull)
+            | ( tmp2        & 0xffff000000000000ull);
+}
+
+uint64_t HELPER(neon_paddl_u32)(uint64_t a, uint64_t b)
+{
+    uint32_t low = a + (a >> 32);
+    uint32_t high = b + (b >> 32);
+    return low + ((uint64_t)high << 32);
+}
+
+uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b)
+{
+    uint64_t mask;
+    mask = (a ^ ~b) & 0x8000800080008000ull;
+    a |= 0x8000800080008000ull;
+    b &= ~0x8000800080008000ull;
+    return (a - b) ^ mask;
+}
+
+uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b)
+{
+    uint64_t mask;
+    mask = (a ^ ~b) & 0x8000000080000000ull;
+    a |= 0x8000000080000000ull;
+    b &= ~0x8000000080000000ull;
+    return (a - b) ^ mask;
+}
+
+uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b)
+{
+    uint32_t x, y;
+    uint32_t low, high;
+
+    x = a;
+    y = b;
+    low = x + y;
+    if (((low ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) {
+        SET_QC();
+        low = ((int32_t)x >> 31) ^ ~SIGNBIT;
+    }
+    x = a >> 32;
+    y = b >> 32;
+    high = x + y;
+    if (((high ^ x) & SIGNBIT) && !((x ^ y) & SIGNBIT)) {
+        SET_QC();
+        high = ((int32_t)x >> 31) ^ ~SIGNBIT;
+    }
+    return low | ((uint64_t)high << 32);
+}
+
+uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b)
+{
+    uint64_t result;
+
+    result = a + b;
+    if (((result ^ a) & SIGNBIT64) && !((a ^ b) & SIGNBIT64)) {
+        SET_QC();
+        result = ((int64_t)a >> 63) ^ ~SIGNBIT64;
+    }
+    return result;
+}
+
+/* We have to do the arithmetic in a larger type than
+ * the input type, because for example with a signed 32 bit
+ * op the absolute difference can overflow a signed 32 bit value.
+ */
+#define DO_ABD(dest, x, y, intype, arithtype) do {            \
+    arithtype tmp_x = (intype)(x);                            \
+    arithtype tmp_y = (intype)(y);                            \
+    dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \
+    } while(0)
+
+uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+    DO_ABD(result, a, b, uint8_t, uint32_t);
+    DO_ABD(tmp, a >> 8, b >> 8, uint8_t, uint32_t);
+    result |= tmp << 16;
+    DO_ABD(tmp, a >> 16, b >> 16, uint8_t, uint32_t);
+    result |= tmp << 32;
+    DO_ABD(tmp, a >> 24, b >> 24, uint8_t, uint32_t);
+    result |= tmp << 48;
+    return result;
+}
+
+uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+    DO_ABD(result, a, b, int8_t, int32_t);
+    DO_ABD(tmp, a >> 8, b >> 8, int8_t, int32_t);
+    result |= tmp << 16;
+    DO_ABD(tmp, a >> 16, b >> 16, int8_t, int32_t);
+    result |= tmp << 32;
+    DO_ABD(tmp, a >> 24, b >> 24, int8_t, int32_t);
+    result |= tmp << 48;
+    return result;
+}
+
+uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+    DO_ABD(result, a, b, uint16_t, uint32_t);
+    DO_ABD(tmp, a >> 16, b >> 16, uint16_t, uint32_t);
+    return result | (tmp << 32);
+}
+
+uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+    DO_ABD(result, a, b, int16_t, int32_t);
+    DO_ABD(tmp, a >> 16, b >> 16, int16_t, int32_t);
+    return result | (tmp << 32);
+}
+
+uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b)
+{
+    uint64_t result;
+    DO_ABD(result, a, b, uint32_t, uint64_t);
+    return result;
+}
+
+uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b)
+{
+    uint64_t result;
+    DO_ABD(result, a, b, int32_t, int64_t);
+    return result;
+}
+#undef DO_ABD
+
+/* Widening multiply. Named type is the source type.  */
+#define DO_MULL(dest, x, y, type1, type2) do { \
+    type1 tmp_x = x; \
+    type1 tmp_y = y; \
+    dest = (type2)((type2)tmp_x * (type2)tmp_y); \
+    } while(0)
+
+uint64_t HELPER(neon_mull_u8)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+
+    DO_MULL(result, a, b, uint8_t, uint16_t);
+    DO_MULL(tmp, a >> 8, b >> 8, uint8_t, uint16_t);
+    result |= tmp << 16;
+    DO_MULL(tmp, a >> 16, b >> 16, uint8_t, uint16_t);
+    result |= tmp << 32;
+    DO_MULL(tmp, a >> 24, b >> 24, uint8_t, uint16_t);
+    result |= tmp << 48;
+    return result;
+}
+
+uint64_t HELPER(neon_mull_s8)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+
+    DO_MULL(result, a, b, int8_t, uint16_t);
+    DO_MULL(tmp, a >> 8, b >> 8, int8_t, uint16_t);
+    result |= tmp << 16;
+    DO_MULL(tmp, a >> 16, b >> 16, int8_t, uint16_t);
+    result |= tmp << 32;
+    DO_MULL(tmp, a >> 24, b >> 24, int8_t, uint16_t);
+    result |= tmp << 48;
+    return result;
+}
+
+uint64_t HELPER(neon_mull_u16)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+
+    DO_MULL(result, a, b, uint16_t, uint32_t);
+    DO_MULL(tmp, a >> 16, b >> 16, uint16_t, uint32_t);
+    return result | (tmp << 32);
+}
+
+uint64_t HELPER(neon_mull_s16)(uint32_t a, uint32_t b)
+{
+    uint64_t tmp;
+    uint64_t result;
+
+    DO_MULL(result, a, b, int16_t, uint32_t);
+    DO_MULL(tmp, a >> 16, b >> 16, int16_t, uint32_t);
+    return result | (tmp << 32);
+}
+
+uint64_t HELPER(neon_negl_u16)(uint64_t x)
+{
+    uint16_t tmp;
+    uint64_t result;
+    result = (uint16_t)-x;
+    tmp = -(x >> 16);
+    result |= (uint64_t)tmp << 16;
+    tmp = -(x >> 32);
+    result |= (uint64_t)tmp << 32;
+    tmp = -(x >> 48);
+    result |= (uint64_t)tmp << 48;
+    return result;
+}
+
+uint64_t HELPER(neon_negl_u32)(uint64_t x)
+{
+    uint32_t low = -x;
+    uint32_t high = -(x >> 32);
+    return low | ((uint64_t)high << 32);
+}
+
+/* FIXME:  There should be a native op for this.  */
+uint64_t HELPER(neon_negl_u64)(uint64_t x)
+{
+    return -x;
+}
+
+/* Saturnating sign manuipulation.  */
+/* ??? Make these use NEON_VOP1 */
+#define DO_QABS8(x) do { \
+    if (x == (int8_t)0x80) { \
+        x = 0x7f; \
+        SET_QC(); \
+    } else if (x < 0) { \
+        x = -x; \
+    }} while (0)
+uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x)
+{
+    neon_s8 vec;
+    NEON_UNPACK(neon_s8, vec, x);
+    DO_QABS8(vec.v1);
+    DO_QABS8(vec.v2);
+    DO_QABS8(vec.v3);
+    DO_QABS8(vec.v4);
+    NEON_PACK(neon_s8, x, vec);
+    return x;
+}
+#undef DO_QABS8
+
+#define DO_QNEG8(x) do { \
+    if (x == (int8_t)0x80) { \
+        x = 0x7f; \
+        SET_QC(); \
+    } else { \
+        x = -x; \
+    }} while (0)
+uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x)
+{
+    neon_s8 vec;
+    NEON_UNPACK(neon_s8, vec, x);
+    DO_QNEG8(vec.v1);
+    DO_QNEG8(vec.v2);
+    DO_QNEG8(vec.v3);
+    DO_QNEG8(vec.v4);
+    NEON_PACK(neon_s8, x, vec);
+    return x;
+}
+#undef DO_QNEG8
+
+#define DO_QABS16(x) do { \
+    if (x == (int16_t)0x8000) { \
+        x = 0x7fff; \
+        SET_QC(); \
+    } else if (x < 0) { \
+        x = -x; \
+    }} while (0)
+uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x)
+{
+    neon_s16 vec;
+    NEON_UNPACK(neon_s16, vec, x);
+    DO_QABS16(vec.v1);
+    DO_QABS16(vec.v2);
+    NEON_PACK(neon_s16, x, vec);
+    return x;
+}
+#undef DO_QABS16
+
+#define DO_QNEG16(x) do { \
+    if (x == (int16_t)0x8000) { \
+        x = 0x7fff; \
+        SET_QC(); \
+    } else { \
+        x = -x; \
+    }} while (0)
+uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x)
+{
+    neon_s16 vec;
+    NEON_UNPACK(neon_s16, vec, x);
+    DO_QNEG16(vec.v1);
+    DO_QNEG16(vec.v2);
+    NEON_PACK(neon_s16, x, vec);
+    return x;
+}
+#undef DO_QNEG16
+
+uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x)
+{
+    if (x == SIGNBIT) {
+        SET_QC();
+        x = ~SIGNBIT;
+    } else if ((int32_t)x < 0) {
+        x = -x;
+    }
+    return x;
+}
+
+uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x)
+{
+    if (x == SIGNBIT) {
+        SET_QC();
+        x = ~SIGNBIT;
+    } else {
+        x = -x;
+    }
+    return x;
+}
+
+/* NEON Float helpers.  */
+uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float32_val(float32_min(make_float32(a), make_float32(b), fpst));
+}
+
+uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float32_val(float32_max(make_float32(a), make_float32(b), fpst));
+}
+
+uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    float32 f0 = make_float32(a);
+    float32 f1 = make_float32(b);
+    return float32_val(float32_abs(float32_sub(f0, f1, fpst)));
+}
+
+/* Floating point comparisons produce an integer result.
+ * Note that EQ doesn't signal InvalidOp for QNaNs but GE and GT do.
+ * Softfloat routines return 0/1, which we convert to the 0/-1 Neon requires.
+ */
+uint32_t HELPER(neon_ceq_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return -float32_eq_quiet(make_float32(a), make_float32(b), fpst);
+}
+
+uint32_t HELPER(neon_cge_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return -float32_le(make_float32(b), make_float32(a), fpst);
+}
+
+uint32_t HELPER(neon_cgt_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return -float32_lt(make_float32(b), make_float32(a), fpst);
+}
+
+uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    return -float32_le(f1, f0, fpst);
+}
+
+uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    return -float32_lt(f1, f0, fpst);
+}
+
+#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
+
+void HELPER(neon_qunzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zd0, 2, 8) << 8)
+        | (ELEM(zd0, 4, 8) << 16) | (ELEM(zd0, 6, 8) << 24)
+        | (ELEM(zd1, 0, 8) << 32) | (ELEM(zd1, 2, 8) << 40)
+        | (ELEM(zd1, 4, 8) << 48) | (ELEM(zd1, 6, 8) << 56);
+    uint64_t d1 = ELEM(zm0, 0, 8) | (ELEM(zm0, 2, 8) << 8)
+        | (ELEM(zm0, 4, 8) << 16) | (ELEM(zm0, 6, 8) << 24)
+        | (ELEM(zm1, 0, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+        | (ELEM(zm1, 4, 8) << 48) | (ELEM(zm1, 6, 8) << 56);
+    uint64_t m0 = ELEM(zd0, 1, 8) | (ELEM(zd0, 3, 8) << 8)
+        | (ELEM(zd0, 5, 8) << 16) | (ELEM(zd0, 7, 8) << 24)
+        | (ELEM(zd1, 1, 8) << 32) | (ELEM(zd1, 3, 8) << 40)
+        | (ELEM(zd1, 5, 8) << 48) | (ELEM(zd1, 7, 8) << 56);
+    uint64_t m1 = ELEM(zm0, 1, 8) | (ELEM(zm0, 3, 8) << 8)
+        | (ELEM(zm0, 5, 8) << 16) | (ELEM(zm0, 7, 8) << 24)
+        | (ELEM(zm1, 1, 8) << 32) | (ELEM(zm1, 3, 8) << 40)
+        | (ELEM(zm1, 5, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qunzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zd0, 2, 16) << 16)
+        | (ELEM(zd1, 0, 16) << 32) | (ELEM(zd1, 2, 16) << 48);
+    uint64_t d1 = ELEM(zm0, 0, 16) | (ELEM(zm0, 2, 16) << 16)
+        | (ELEM(zm1, 0, 16) << 32) | (ELEM(zm1, 2, 16) << 48);
+    uint64_t m0 = ELEM(zd0, 1, 16) | (ELEM(zd0, 3, 16) << 16)
+        | (ELEM(zd1, 1, 16) << 32) | (ELEM(zd1, 3, 16) << 48);
+    uint64_t m1 = ELEM(zm0, 1, 16) | (ELEM(zm0, 3, 16) << 16)
+        | (ELEM(zm1, 1, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qunzip32)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zd1, 0, 32) << 32);
+    uint64_t d1 = ELEM(zm0, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+    uint64_t m0 = ELEM(zd0, 1, 32) | (ELEM(zd1, 1, 32) << 32);
+    uint64_t m1 = ELEM(zm0, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zd, 2, 8) << 8)
+        | (ELEM(zd, 4, 8) << 16) | (ELEM(zd, 6, 8) << 24)
+        | (ELEM(zm, 0, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+        | (ELEM(zm, 4, 8) << 48) | (ELEM(zm, 6, 8) << 56);
+    uint64_t m0 = ELEM(zd, 1, 8) | (ELEM(zd, 3, 8) << 8)
+        | (ELEM(zd, 5, 8) << 16) | (ELEM(zd, 7, 8) << 24)
+        | (ELEM(zm, 1, 8) << 32) | (ELEM(zm, 3, 8) << 40)
+        | (ELEM(zm, 5, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zd, 2, 16) << 16)
+        | (ELEM(zm, 0, 16) << 32) | (ELEM(zm, 2, 16) << 48);
+    uint64_t m0 = ELEM(zd, 1, 16) | (ELEM(zd, 3, 16) << 16)
+        | (ELEM(zm, 1, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_qzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zm0, 0, 8) << 8)
+        | (ELEM(zd0, 1, 8) << 16) | (ELEM(zm0, 1, 8) << 24)
+        | (ELEM(zd0, 2, 8) << 32) | (ELEM(zm0, 2, 8) << 40)
+        | (ELEM(zd0, 3, 8) << 48) | (ELEM(zm0, 3, 8) << 56);
+    uint64_t d1 = ELEM(zd0, 4, 8) | (ELEM(zm0, 4, 8) << 8)
+        | (ELEM(zd0, 5, 8) << 16) | (ELEM(zm0, 5, 8) << 24)
+        | (ELEM(zd0, 6, 8) << 32) | (ELEM(zm0, 6, 8) << 40)
+        | (ELEM(zd0, 7, 8) << 48) | (ELEM(zm0, 7, 8) << 56);
+    uint64_t m0 = ELEM(zd1, 0, 8) | (ELEM(zm1, 0, 8) << 8)
+        | (ELEM(zd1, 1, 8) << 16) | (ELEM(zm1, 1, 8) << 24)
+        | (ELEM(zd1, 2, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+        | (ELEM(zd1, 3, 8) << 48) | (ELEM(zm1, 3, 8) << 56);
+    uint64_t m1 = ELEM(zd1, 4, 8) | (ELEM(zm1, 4, 8) << 8)
+        | (ELEM(zd1, 5, 8) << 16) | (ELEM(zm1, 5, 8) << 24)
+        | (ELEM(zd1, 6, 8) << 32) | (ELEM(zm1, 6, 8) << 40)
+        | (ELEM(zd1, 7, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zm0, 0, 16) << 16)
+        | (ELEM(zd0, 1, 16) << 32) | (ELEM(zm0, 1, 16) << 48);
+    uint64_t d1 = ELEM(zd0, 2, 16) | (ELEM(zm0, 2, 16) << 16)
+        | (ELEM(zd0, 3, 16) << 32) | (ELEM(zm0, 3, 16) << 48);
+    uint64_t m0 = ELEM(zd1, 0, 16) | (ELEM(zm1, 0, 16) << 16)
+        | (ELEM(zd1, 1, 16) << 32) | (ELEM(zm1, 1, 16) << 48);
+    uint64_t m1 = ELEM(zd1, 2, 16) | (ELEM(zm1, 2, 16) << 16)
+        | (ELEM(zd1, 3, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_qzip32)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zm0, 0, 32) << 32);
+    uint64_t d1 = ELEM(zd0, 1, 32) | (ELEM(zm0, 1, 32) << 32);
+    uint64_t m0 = ELEM(zd1, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+    uint64_t m1 = ELEM(zd1, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rm + 1] = make_float64(m1);
+    env->vfp.regs[rd] = make_float64(d0);
+    env->vfp.regs[rd + 1] = make_float64(d1);
+}
+
+void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zm, 0, 8) << 8)
+        | (ELEM(zd, 1, 8) << 16) | (ELEM(zm, 1, 8) << 24)
+        | (ELEM(zd, 2, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+        | (ELEM(zd, 3, 8) << 48) | (ELEM(zm, 3, 8) << 56);
+    uint64_t m0 = ELEM(zd, 4, 8) | (ELEM(zm, 4, 8) << 8)
+        | (ELEM(zd, 5, 8) << 16) | (ELEM(zm, 5, 8) << 24)
+        | (ELEM(zd, 6, 8) << 32) | (ELEM(zm, 6, 8) << 40)
+        | (ELEM(zd, 7, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
+
+void HELPER(neon_zip16)(CPUState *env, uint32_t rd, uint32_t rm)
+{
+    uint64_t zm = float64_val(env->vfp.regs[rm]);
+    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zm, 0, 16) << 16)
+        | (ELEM(zd, 1, 16) << 32) | (ELEM(zm, 1, 16) << 48);
+    uint64_t m0 = ELEM(zd, 2, 16) | (ELEM(zm, 2, 16) << 16)
+        | (ELEM(zd, 3, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+    env->vfp.regs[rm] = make_float64(m0);
+    env->vfp.regs[rd] = make_float64(d0);
+}
diff --git a/qemu-0.15.x/target-arm/op_addsub.h b/qemu-0.15.x/target-arm/op_addsub.h
new file mode 100644
index 0000000..ca4a189
--- /dev/null
+++ b/qemu-0.15.x/target-arm/op_addsub.h
@@ -0,0 +1,103 @@
+/*
+ * ARMv6 integer SIMD operations.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#ifdef ARITH_GE
+#define GE_ARG , void *gep
+#define DECLARE_GE uint32_t ge = 0
+#define SET_GE *(uint32_t *)gep = ge
+#else
+#define GE_ARG
+#define DECLARE_GE do{}while(0)
+#define SET_GE do{}while(0)
+#endif
+
+#define RESULT(val, n, width) \
+    res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width)
+
+uint32_t HELPER(glue(PFX,add16))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    ADD16(a, b, 0);
+    ADD16(a >> 16, b >> 16, 1);
+    SET_GE;
+    return res;
+}
+
+uint32_t HELPER(glue(PFX,add8))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    ADD8(a, b, 0);
+    ADD8(a >> 8, b >> 8, 1);
+    ADD8(a >> 16, b >> 16, 2);
+    ADD8(a >> 24, b >> 24, 3);
+    SET_GE;
+    return res;
+}
+
+uint32_t HELPER(glue(PFX,sub16))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    SUB16(a, b, 0);
+    SUB16(a >> 16, b >> 16, 1);
+    SET_GE;
+    return res;
+}
+
+uint32_t HELPER(glue(PFX,sub8))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    SUB8(a, b, 0);
+    SUB8(a >> 8, b >> 8, 1);
+    SUB8(a >> 16, b >> 16, 2);
+    SUB8(a >> 24, b >> 24, 3);
+    SET_GE;
+    return res;
+}
+
+uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    ADD16(a, b >> 16, 0);
+    SUB16(a >> 16, b, 1);
+    SET_GE;
+    return res;
+}
+
+uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG)
+{
+    uint32_t res = 0;
+    DECLARE_GE;
+
+    SUB16(a, b >> 16, 0);
+    ADD16(a >> 16, b, 1);
+    SET_GE;
+    return res;
+}
+
+#undef GE_ARG
+#undef DECLARE_GE
+#undef SET_GE
+#undef RESULT
+
+#undef ARITH_GE
+#undef PFX
+#undef ADD16
+#undef SUB16
+#undef ADD8
+#undef SUB8
diff --git a/qemu-0.15.x/target-arm/op_helper.c b/qemu-0.15.x/target-arm/op_helper.c
new file mode 100644
index 0000000..4635884
--- /dev/null
+++ b/qemu-0.15.x/target-arm/op_helper.c
@@ -0,0 +1,426 @@
+/*
+ *  ARM helper routines
+ *
+ *  Copyright (c) 2005-2007 CodeSourcery, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "exec.h"
+#include "helper.h"
+
+#define SIGNBIT (uint32_t)0x80000000
+#define SIGNBIT64 ((uint64_t)1 << 63)
+
+void raise_exception(int tt)
+{
+    env->exception_index = tt;
+    cpu_loop_exit(env);
+}
+
+uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
+                          uint32_t rn, uint32_t maxindex)
+{
+    uint32_t val;
+    uint32_t tmp;
+    int index;
+    int shift;
+    uint64_t *table;
+    table = (uint64_t *)&env->vfp.regs[rn];
+    val = 0;
+    for (shift = 0; shift < 32; shift += 8) {
+        index = (ireg >> shift) & 0xff;
+        if (index < maxindex) {
+            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
+            val |= tmp << shift;
+        } else {
+            val |= def & (0xff << shift);
+        }
+    }
+    return val;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        raise_exception(env->exception_index);
+    }
+    env = saved_env;
+}
+#endif
+
+/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating
+   instructions into helper.c  */
+uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
+{
+    uint32_t res = a + b;
+    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
+        env->QF = 1;
+    return res;
+}
+
+uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
+{
+    uint32_t res = a + b;
+    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
+        env->QF = 1;
+        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+    }
+    return res;
+}
+
+uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
+{
+    uint32_t res = a - b;
+    if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
+        env->QF = 1;
+        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+    }
+    return res;
+}
+
+uint32_t HELPER(double_saturate)(int32_t val)
+{
+    uint32_t res;
+    if (val >= 0x40000000) {
+        res = ~SIGNBIT;
+        env->QF = 1;
+    } else if (val <= (int32_t)0xc0000000) {
+        res = SIGNBIT;
+        env->QF = 1;
+    } else {
+        res = val << 1;
+    }
+    return res;
+}
+
+uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
+{
+    uint32_t res = a + b;
+    if (res < a) {
+        env->QF = 1;
+        res = ~0;
+    }
+    return res;
+}
+
+uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
+{
+    uint32_t res = a - b;
+    if (res > a) {
+        env->QF = 1;
+        res = 0;
+    }
+    return res;
+}
+
+/* Signed saturation.  */
+static inline uint32_t do_ssat(int32_t val, int shift)
+{
+    int32_t top;
+    uint32_t mask;
+
+    top = val >> shift;
+    mask = (1u << shift) - 1;
+    if (top > 0) {
+        env->QF = 1;
+        return mask;
+    } else if (top < -1) {
+        env->QF = 1;
+        return ~mask;
+    }
+    return val;
+}
+
+/* Unsigned saturation.  */
+static inline uint32_t do_usat(int32_t val, int shift)
+{
+    uint32_t max;
+
+    max = (1u << shift) - 1;
+    if (val < 0) {
+        env->QF = 1;
+        return 0;
+    } else if (val > max) {
+        env->QF = 1;
+        return max;
+    }
+    return val;
+}
+
+/* Signed saturate.  */
+uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
+{
+    return do_ssat(x, shift);
+}
+
+/* Dual halfword signed saturate.  */
+uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
+{
+    uint32_t res;
+
+    res = (uint16_t)do_ssat((int16_t)x, shift);
+    res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
+    return res;
+}
+
+/* Unsigned saturate.  */
+uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
+{
+    return do_usat(x, shift);
+}
+
+/* Dual halfword unsigned saturate.  */
+uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
+{
+    uint32_t res;
+
+    res = (uint16_t)do_usat((int16_t)x, shift);
+    res |= do_usat(((int32_t)x) >> 16, shift) << 16;
+    return res;
+}
+
+void HELPER(wfi)(void)
+{
+    env->exception_index = EXCP_HLT;
+    env->halted = 1;
+    cpu_loop_exit(env);
+}
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+uint32_t HELPER(cpsr_read)(void)
+{
+    return cpsr_read(env) & ~CPSR_EXEC;
+}
+
+void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
+{
+    cpsr_write(env, val, mask);
+}
+
+/* Access to user mode registers from privileged modes.  */
+uint32_t HELPER(get_user_reg)(uint32_t regno)
+{
+    uint32_t val;
+
+    if (regno == 13) {
+        val = env->banked_r13[0];
+    } else if (regno == 14) {
+        val = env->banked_r14[0];
+    } else if (regno >= 8
+               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
+        val = env->usr_regs[regno - 8];
+    } else {
+        val = env->regs[regno];
+    }
+    return val;
+}
+
+void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
+{
+    if (regno == 13) {
+        env->banked_r13[0] = val;
+    } else if (regno == 14) {
+        env->banked_r14[0] = val;
+    } else if (regno >= 8
+               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
+        env->usr_regs[regno - 8] = val;
+    } else {
+        env->regs[regno] = val;
+    }
+}
+
+/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
+   The only way to do that in TCG is a conditional branch, which clobbers
+   all our temporaries.  For now implement these as helper functions.  */
+
+uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a + b;
+    env->NF = env->ZF = result;
+    env->CF = result < a;
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a + b;
+        env->CF = result < a;
+    } else {
+        result = a + b + 1;
+        env->CF = result <= a;
+    }
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a - b;
+    env->NF = env->ZF = result;
+    env->CF = a >= b;
+    env->VF = (a ^ b) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a - b - 1;
+        env->CF = a > b;
+    } else {
+        result = a - b;
+        env->CF = a >= b;
+    }
+    env->VF = (a ^ b) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+/* Similarly for variable shift instructions.  */
+
+uint32_t HELPER(shl)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32)
+        return 0;
+    return x << shift;
+}
+
+uint32_t HELPER(shr)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32)
+        return 0;
+    return (uint32_t)x >> shift;
+}
+
+uint32_t HELPER(sar)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32)
+        shift = 31;
+    return (int32_t)x >> shift;
+}
+
+uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32)
+            env->CF = x & 1;
+        else
+            env->CF = 0;
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (32 - shift)) & 1;
+        return x << shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32)
+            env->CF = (x >> 31) & 1;
+        else
+            env->CF = 0;
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        env->CF = (x >> 31) & 1;
+        return (int32_t)x >> 31;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return (int32_t)x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
+{
+    int shift1, shift;
+    shift1 = i & 0xff;
+    shift = shift1 & 0x1f;
+    if (shift == 0) {
+        if (shift1 != 0)
+            env->CF = (x >> 31) & 1;
+        return x;
+    } else {
+        env->CF = (x >> (shift - 1)) & 1;
+        return ((uint32_t)x >> shift) | (x << (32 - shift));
+    }
+}
diff --git a/qemu-0.15.x/target-arm/translate.c b/qemu-0.15.x/target-arm/translate.c
new file mode 100644
index 0000000..fcb41d1
--- /dev/null
+++ b/qemu-0.15.x/target-arm/translate.c
@@ -0,0 +1,10073 @@
+/*
+ *  ARM translation
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *  Copyright (c) 2005-2007 CodeSourcery
+ *  Copyright (c) 2007 OpenedHand, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
+#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
+/* currently all emulated v5 cores are also v5TE, so don't bother */
+#define ENABLE_ARCH_5TE   arm_feature(env, ARM_FEATURE_V5)
+#define ENABLE_ARCH_5J    0
+#define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
+#define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
+#define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
+#define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
+
+#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0)
+
+/* internal defines */
+typedef struct DisasContext {
+    target_ulong pc;
+    int is_jmp;
+    /* Nonzero if this instruction has been conditionally skipped.  */
+    int condjmp;
+    /* The label that will be jumped to when the instruction is skipped.  */
+    int condlabel;
+    /* Thumb-2 condtional execution bits.  */
+    int condexec_mask;
+    int condexec_cond;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+    int thumb;
+#if !defined(CONFIG_USER_ONLY)
+    int user;
+#endif
+    int vfp_enabled;
+    int vec_len;
+    int vec_stride;
+} DisasContext;
+
+static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
+
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(s) 1
+#else
+#define IS_USER(s) (s->user)
+#endif
+
+/* These instructions trap after executing, so defer them until after the
+   conditional executions state has been updated.  */
+#define DISAS_WFI 4
+#define DISAS_SWI 5
+
+static TCGv_ptr cpu_env;
+/* We reuse the same 64-bit temporaries for efficiency.  */
+static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
+static TCGv_i32 cpu_R[16];
+static TCGv_i32 cpu_exclusive_addr;
+static TCGv_i32 cpu_exclusive_val;
+static TCGv_i32 cpu_exclusive_high;
+#ifdef CONFIG_USER_ONLY
+static TCGv_i32 cpu_exclusive_test;
+static TCGv_i32 cpu_exclusive_info;
+#endif
+
+/* FIXME:  These should be removed.  */
+static TCGv cpu_F0s, cpu_F1s;
+static TCGv_i64 cpu_F0d, cpu_F1d;
+
+#include "gen-icount.h"
+
+static const char *regnames[] =
+    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
+
+/* initialize TCG globals.  */
+void arm_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < 16; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                          offsetof(CPUState, regs[i]),
+                                          regnames[i]);
+    }
+    cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUState, exclusive_addr), "exclusive_addr");
+    cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUState, exclusive_val), "exclusive_val");
+    cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUState, exclusive_high), "exclusive_high");
+#ifdef CONFIG_USER_ONLY
+    cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUState, exclusive_test), "exclusive_test");
+    cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUState, exclusive_info), "exclusive_info");
+#endif
+
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+static inline TCGv load_cpu_offset(int offset)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_ld_i32(tmp, cpu_env, offset);
+    return tmp;
+}
+
+#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))
+
+static inline void store_cpu_offset(TCGv var, int offset)
+{
+    tcg_gen_st_i32(var, cpu_env, offset);
+    tcg_temp_free_i32(var);
+}
+
+#define store_cpu_field(var, name) \
+    store_cpu_offset(var, offsetof(CPUState, name))
+
+/* Set a variable to the value of a CPU register.  */
+static void load_reg_var(DisasContext *s, TCGv var, int reg)
+{
+    if (reg == 15) {
+        uint32_t addr;
+        /* normaly, since we updated PC, we need only to add one insn */
+        if (s->thumb)
+            addr = (long)s->pc + 2;
+        else
+            addr = (long)s->pc + 4;
+        tcg_gen_movi_i32(var, addr);
+    } else {
+        tcg_gen_mov_i32(var, cpu_R[reg]);
+    }
+}
+
+/* Create a new temporary and set it to the value of a CPU register.  */
+static inline TCGv load_reg(DisasContext *s, int reg)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    load_reg_var(s, tmp, reg);
+    return tmp;
+}
+
+/* Set a CPU register.  The source must be a temporary and will be
+   marked as dead.  */
+static void store_reg(DisasContext *s, int reg, TCGv var)
+{
+    if (reg == 15) {
+        tcg_gen_andi_i32(var, var, ~1);
+        s->is_jmp = DISAS_JUMP;
+    }
+    tcg_gen_mov_i32(cpu_R[reg], var);
+    tcg_temp_free_i32(var);
+}
+
+/* Value extensions.  */
+#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
+#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
+#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
+#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
+
+#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
+#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
+
+
+static inline void gen_set_cpsr(TCGv var, uint32_t mask)
+{
+    TCGv tmp_mask = tcg_const_i32(mask);
+    gen_helper_cpsr_write(var, tmp_mask);
+    tcg_temp_free_i32(tmp_mask);
+}
+/* Set NZCV flags from the high 4 bits of var.  */
+#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
+
+static void gen_exception(int excp)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_movi_i32(tmp, excp);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_smul_dual(TCGv a, TCGv b)
+{
+    TCGv tmp1 = tcg_temp_new_i32();
+    TCGv tmp2 = tcg_temp_new_i32();
+    tcg_gen_ext16s_i32(tmp1, a);
+    tcg_gen_ext16s_i32(tmp2, b);
+    tcg_gen_mul_i32(tmp1, tmp1, tmp2);
+    tcg_temp_free_i32(tmp2);
+    tcg_gen_sari_i32(a, a, 16);
+    tcg_gen_sari_i32(b, b, 16);
+    tcg_gen_mul_i32(b, b, a);
+    tcg_gen_mov_i32(a, tmp1);
+    tcg_temp_free_i32(tmp1);
+}
+
+/* Byteswap each halfword.  */
+static void gen_rev16(TCGv var)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_shri_i32(tmp, var, 8);
+    tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
+    tcg_gen_shli_i32(var, var, 8);
+    tcg_gen_andi_i32(var, var, 0xff00ff00);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* Byteswap low halfword and sign extend.  */
+static void gen_revsh(TCGv var)
+{
+    tcg_gen_ext16u_i32(var, var);
+    tcg_gen_bswap16_i32(var, var);
+    tcg_gen_ext16s_i32(var, var);
+}
+
+/* Unsigned bitfield extract.  */
+static void gen_ubfx(TCGv var, int shift, uint32_t mask)
+{
+    if (shift)
+        tcg_gen_shri_i32(var, var, shift);
+    tcg_gen_andi_i32(var, var, mask);
+}
+
+/* Signed bitfield extract.  */
+static void gen_sbfx(TCGv var, int shift, int width)
+{
+    uint32_t signbit;
+
+    if (shift)
+        tcg_gen_sari_i32(var, var, shift);
+    if (shift + width < 32) {
+        signbit = 1u << (width - 1);
+        tcg_gen_andi_i32(var, var, (1u << width) - 1);
+        tcg_gen_xori_i32(var, var, signbit);
+        tcg_gen_subi_i32(var, var, signbit);
+    }
+}
+
+/* Bitfield insertion.  Insert val into base.  Clobbers base and val.  */
+static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
+{
+    tcg_gen_andi_i32(val, val, mask);
+    tcg_gen_shli_i32(val, val, shift);
+    tcg_gen_andi_i32(base, base, ~(mask << shift));
+    tcg_gen_or_i32(dest, base, val);
+}
+
+/* Return (b << 32) + a. Mark inputs as dead */
+static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
+{
+    TCGv_i64 tmp64 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp64, b);
+    tcg_temp_free_i32(b);
+    tcg_gen_shli_i64(tmp64, tmp64, 32);
+    tcg_gen_add_i64(a, tmp64, a);
+
+    tcg_temp_free_i64(tmp64);
+    return a;
+}
+
+/* Return (b << 32) - a. Mark inputs as dead. */
+static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
+{
+    TCGv_i64 tmp64 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp64, b);
+    tcg_temp_free_i32(b);
+    tcg_gen_shli_i64(tmp64, tmp64, 32);
+    tcg_gen_sub_i64(a, tmp64, a);
+
+    tcg_temp_free_i64(tmp64);
+    return a;
+}
+
+/* FIXME: Most targets have native widening multiplication.
+   It would be good to use that instead of a full wide multiply.  */
+/* 32x32->64 multiply.  Marks inputs as dead.  */
+static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp1, a);
+    tcg_temp_free_i32(a);
+    tcg_gen_extu_i32_i64(tmp2, b);
+    tcg_temp_free_i32(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(tmp1, a);
+    tcg_temp_free_i32(a);
+    tcg_gen_ext_i32_i64(tmp2, b);
+    tcg_temp_free_i32(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+/* Swap low and high halfwords.  */
+static void gen_swap_half(TCGv var)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_shri_i32(tmp, var, 16);
+    tcg_gen_shli_i32(var, var, 16);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* Dual 16-bit add.  Result placed in t0 and t1 is marked as dead.
+    tmp = (t0 ^ t1) & 0x8000;
+    t0 &= ~0x8000;
+    t1 &= ~0x8000;
+    t0 = (t0 + t1) ^ tmp;
+ */
+
+static void gen_add16(TCGv t0, TCGv t1)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_xor_i32(tmp, t0, t1);
+    tcg_gen_andi_i32(tmp, tmp, 0x8000);
+    tcg_gen_andi_i32(t0, t0, ~0x8000);
+    tcg_gen_andi_i32(t1, t1, ~0x8000);
+    tcg_gen_add_i32(t0, t0, t1);
+    tcg_gen_xor_i32(t0, t0, tmp);
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(t1);
+}
+
+#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
+
+/* Set CF to the top bit of var.  */
+static void gen_set_CF_bit31(TCGv var)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_shri_i32(tmp, var, 31);
+    gen_set_CF(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* Set N and Z flags from var.  */
+static inline void gen_logic_CC(TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
+}
+
+/* T0 += T1 + CF.  */
+static void gen_adc(TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(t0, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(t0, t0, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* dest = T0 - T1 + CF - 1.  */
+static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_sub_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    tcg_gen_subi_i32(dest, dest, 1);
+    tcg_temp_free_i32(tmp);
+}
+
+/* FIXME:  Implement this natively.  */
+#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)
+
+static void shifter_out_im(TCGv var, int shift)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    if (shift == 0) {
+        tcg_gen_andi_i32(tmp, var, 1);
+    } else {
+        tcg_gen_shri_i32(tmp, var, shift);
+        if (shift != 31)
+            tcg_gen_andi_i32(tmp, tmp, 1);
+    }
+    gen_set_CF(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* Shift by immediate.  Includes special handling for shift == 0.  */
+static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
+{
+    switch (shiftop) {
+    case 0: /* LSL */
+        if (shift != 0) {
+            if (flags)
+                shifter_out_im(var, 32 - shift);
+            tcg_gen_shli_i32(var, var, shift);
+        }
+        break;
+    case 1: /* LSR */
+        if (shift == 0) {
+            if (flags) {
+                tcg_gen_shri_i32(var, var, 31);
+                gen_set_CF(var);
+            }
+            tcg_gen_movi_i32(var, 0);
+        } else {
+            if (flags)
+                shifter_out_im(var, shift - 1);
+            tcg_gen_shri_i32(var, var, shift);
+        }
+        break;
+    case 2: /* ASR */
+        if (shift == 0)
+            shift = 32;
+        if (flags)
+            shifter_out_im(var, shift - 1);
+        if (shift == 32)
+          shift = 31;
+        tcg_gen_sari_i32(var, var, shift);
+        break;
+    case 3: /* ROR/RRX */
+        if (shift != 0) {
+            if (flags)
+                shifter_out_im(var, shift - 1);
+            tcg_gen_rotri_i32(var, var, shift); break;
+        } else {
+            TCGv tmp = load_cpu_field(CF);
+            if (flags)
+                shifter_out_im(var, 0);
+            tcg_gen_shri_i32(var, var, 1);
+            tcg_gen_shli_i32(tmp, tmp, 31);
+            tcg_gen_or_i32(var, var, tmp);
+            tcg_temp_free_i32(tmp);
+        }
+    }
+};
+
+static inline void gen_arm_shift_reg(TCGv var, int shiftop,
+                                     TCGv shift, int flags)
+{
+    if (flags) {
+        switch (shiftop) {
+        case 0: gen_helper_shl_cc(var, var, shift); break;
+        case 1: gen_helper_shr_cc(var, var, shift); break;
+        case 2: gen_helper_sar_cc(var, var, shift); break;
+        case 3: gen_helper_ror_cc(var, var, shift); break;
+        }
+    } else {
+        switch (shiftop) {
+        case 0: gen_helper_shl(var, var, shift); break;
+        case 1: gen_helper_shr(var, var, shift); break;
+        case 2: gen_helper_sar(var, var, shift); break;
+        case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
+                tcg_gen_rotr_i32(var, var, shift); break;
+        }
+    }
+    tcg_temp_free_i32(shift);
+}
+
+#define PAS_OP(pfx) \
+    switch (op2) {  \
+    case 0: gen_pas_helper(glue(pfx,add16)); break; \
+    case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
+    case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
+    case 3: gen_pas_helper(glue(pfx,sub16)); break; \
+    case 4: gen_pas_helper(glue(pfx,add8)); break; \
+    case 7: gen_pas_helper(glue(pfx,sub8)); break; \
+    }
+static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
+{
+    TCGv_ptr tmp;
+
+    switch (op1) {
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
+    case 1:
+        tmp = tcg_temp_new_ptr();
+        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+        PAS_OP(s)
+        tcg_temp_free_ptr(tmp);
+        break;
+    case 5:
+        tmp = tcg_temp_new_ptr();
+        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+        PAS_OP(u)
+        tcg_temp_free_ptr(tmp);
+        break;
+#undef gen_pas_helper
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
+    case 2:
+        PAS_OP(q);
+        break;
+    case 3:
+        PAS_OP(sh);
+        break;
+    case 6:
+        PAS_OP(uq);
+        break;
+    case 7:
+        PAS_OP(uh);
+        break;
+#undef gen_pas_helper
+    }
+}
+#undef PAS_OP
+
+/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings.  */
+#define PAS_OP(pfx) \
+    switch (op1) {  \
+    case 0: gen_pas_helper(glue(pfx,add8)); break; \
+    case 1: gen_pas_helper(glue(pfx,add16)); break; \
+    case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
+    case 4: gen_pas_helper(glue(pfx,sub8)); break; \
+    case 5: gen_pas_helper(glue(pfx,sub16)); break; \
+    case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
+    }
+static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
+{
+    TCGv_ptr tmp;
+
+    switch (op2) {
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
+    case 0:
+        tmp = tcg_temp_new_ptr();
+        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+        PAS_OP(s)
+        tcg_temp_free_ptr(tmp);
+        break;
+    case 4:
+        tmp = tcg_temp_new_ptr();
+        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+        PAS_OP(u)
+        tcg_temp_free_ptr(tmp);
+        break;
+#undef gen_pas_helper
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
+    case 1:
+        PAS_OP(q);
+        break;
+    case 2:
+        PAS_OP(sh);
+        break;
+    case 5:
+        PAS_OP(uq);
+        break;
+    case 6:
+        PAS_OP(uh);
+        break;
+#undef gen_pas_helper
+    }
+}
+#undef PAS_OP
+
+static void gen_test_cc(int cc, int label)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    int inv;
+
+    switch (cc) {
+    case 0: /* eq: Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 1: /* ne: !Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 2: /* cs: C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 3: /* cc: !C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 4: /* mi: N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 5: /* pl: !N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 6: /* vs: V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 7: /* vc: !V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 8: /* hi: C && !Z */
+        inv = gen_new_label();
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        tcg_temp_free_i32(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 9: /* ls: !C || Z */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        tcg_temp_free_i32(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 10: /* ge: N == V -> N ^ V == 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 11: /* lt: N != V -> N ^ V != 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 12: /* gt: !Z && N == V */
+        inv = gen_new_label();
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        tcg_temp_free_i32(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 13: /* le: Z || N != V */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        tcg_temp_free_i32(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    default:
+        fprintf(stderr, "Bad condition code 0x%x\n", cc);
+        abort();
+    }
+    tcg_temp_free_i32(tmp);
+}
+
+static const uint8_t table_logic_cc[16] = {
+    1, /* and */
+    1, /* xor */
+    0, /* sub */
+    0, /* rsb */
+    0, /* add */
+    0, /* adc */
+    0, /* sbc */
+    0, /* rsc */
+    1, /* andl */
+    1, /* xorl */
+    0, /* cmp */
+    0, /* cmn */
+    1, /* orr */
+    1, /* mov */
+    1, /* bic */
+    1, /* mvn */
+};
+
+/* Set PC and Thumb state from an immediate address.  */
+static inline void gen_bx_im(DisasContext *s, uint32_t addr)
+{
+    TCGv tmp;
+
+    s->is_jmp = DISAS_UPDATE;
+    if (s->thumb != (addr & 1)) {
+        tmp = tcg_temp_new_i32();
+        tcg_gen_movi_i32(tmp, addr & 1);
+        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
+        tcg_temp_free_i32(tmp);
+    }
+    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
+}
+
+/* Set PC and Thumb state from var.  var is marked as dead.  */
+static inline void gen_bx(DisasContext *s, TCGv var)
+{
+    s->is_jmp = DISAS_UPDATE;
+    tcg_gen_andi_i32(cpu_R[15], var, ~1);
+    tcg_gen_andi_i32(var, var, 1);
+    store_cpu_field(var, thumb);
+}
+
+/* Variant of store_reg which uses branch&exchange logic when storing
+   to r15 in ARM architecture v7 and above. The source must be a temporary
+   and will be marked as dead. */
+static inline void store_reg_bx(CPUState *env, DisasContext *s,
+                                int reg, TCGv var)
+{
+    if (reg == 15 && ENABLE_ARCH_7) {
+        gen_bx(s, var);
+    } else {
+        store_reg(s, reg, var);
+    }
+}
+
+/* Variant of store_reg which uses branch&exchange logic when storing
+ * to r15 in ARM architecture v5T and above. This is used for storing
+ * the results of a LDR/LDM/POP into r15, and corresponds to the cases
+ * in the ARM ARM which use the LoadWritePC() pseudocode function. */
+static inline void store_reg_from_load(CPUState *env, DisasContext *s,
+                                int reg, TCGv var)
+{
+    if (reg == 15 && ENABLE_ARCH_5) {
+        gen_bx(s, var);
+    } else {
+        store_reg(s, reg, var);
+    }
+}
+
+static inline TCGv gen_ld8s(TCGv addr, int index)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_qemu_ld8s(tmp, addr, index);
+    return tmp;
+}
+static inline TCGv gen_ld8u(TCGv addr, int index)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_qemu_ld8u(tmp, addr, index);
+    return tmp;
+}
+static inline TCGv gen_ld16s(TCGv addr, int index)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_qemu_ld16s(tmp, addr, index);
+    return tmp;
+}
+static inline TCGv gen_ld16u(TCGv addr, int index)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_qemu_ld16u(tmp, addr, index);
+    return tmp;
+}
+static inline TCGv gen_ld32(TCGv addr, int index)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_qemu_ld32u(tmp, addr, index);
+    return tmp;
+}
+static inline TCGv_i64 gen_ld64(TCGv addr, int index)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(tmp, addr, index);
+    return tmp;
+}
+static inline void gen_st8(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st8(val, addr, index);
+    tcg_temp_free_i32(val);
+}
+static inline void gen_st16(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st16(val, addr, index);
+    tcg_temp_free_i32(val);
+}
+static inline void gen_st32(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st32(val, addr, index);
+    tcg_temp_free_i32(val);
+}
+static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st64(val, addr, index);
+    tcg_temp_free_i64(val);
+}
+
+static inline void gen_set_pc_im(uint32_t val)
+{
+    tcg_gen_movi_i32(cpu_R[15], val);
+}
+
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static inline void gen_lookup_tb(DisasContext *s)
+{
+    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
+                                       TCGv var)
+{
+    int val, rm, shift, shiftop;
+    TCGv offset;
+
+    if (!(insn & (1 << 25))) {
+        /* immediate */
+        val = insn & 0xfff;
+        if (!(insn & (1 << 23)))
+            val = -val;
+        if (val != 0)
+            tcg_gen_addi_i32(var, var, val);
+    } else {
+        /* shift/register */
+        rm = (insn) & 0xf;
+        shift = (insn >> 7) & 0x1f;
+        shiftop = (insn >> 5) & 3;
+        offset = load_reg(s, rm);
+        gen_arm_shift_im(offset, shiftop, shift, 0);
+        if (!(insn & (1 << 23)))
+            tcg_gen_sub_i32(var, var, offset);
+        else
+            tcg_gen_add_i32(var, var, offset);
+        tcg_temp_free_i32(offset);
+    }
+}
+
+static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
+                                        int extra, TCGv var)
+{
+    int val, rm;
+    TCGv offset;
+
+    if (insn & (1 << 22)) {
+        /* immediate */
+        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
+        if (!(insn & (1 << 23)))
+            val = -val;
+        val += extra;
+        if (val != 0)
+            tcg_gen_addi_i32(var, var, val);
+    } else {
+        /* register */
+        if (extra)
+            tcg_gen_addi_i32(var, var, extra);
+        rm = (insn) & 0xf;
+        offset = load_reg(s, rm);
+        if (!(insn & (1 << 23)))
+            tcg_gen_sub_i32(var, var, offset);
+        else
+            tcg_gen_add_i32(var, var, offset);
+        tcg_temp_free_i32(offset);
+    }
+}
+
+static TCGv_ptr get_fpstatus_ptr(int neon)
+{
+    TCGv_ptr statusptr = tcg_temp_new_ptr();
+    int offset;
+    if (neon) {
+        offset = offsetof(CPUState, vfp.standard_fp_status);
+    } else {
+        offset = offsetof(CPUState, vfp.fp_status);
+    }
+    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
+    return statusptr;
+}
+
+#define VFP_OP2(name)                                                 \
+static inline void gen_vfp_##name(int dp)                             \
+{                                                                     \
+    TCGv_ptr fpst = get_fpstatus_ptr(0);                              \
+    if (dp) {                                                         \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, fpst);    \
+    } else {                                                          \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, fpst);    \
+    }                                                                 \
+    tcg_temp_free_ptr(fpst);                                          \
+}
+
+VFP_OP2(add)
+VFP_OP2(sub)
+VFP_OP2(mul)
+VFP_OP2(div)
+
+#undef VFP_OP2
+
+static inline void gen_vfp_F1_mul(int dp)
+{
+    /* Like gen_vfp_mul() but put result in F1 */
+    TCGv_ptr fpst = get_fpstatus_ptr(0);
+    if (dp) {
+        gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
+    } else {
+        gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
+    }
+    tcg_temp_free_ptr(fpst);
+}
+
+static inline void gen_vfp_F1_neg(int dp)
+{
+    /* Like gen_vfp_neg() but put result in F1 */
+    if (dp) {
+        gen_helper_vfp_negd(cpu_F1d, cpu_F0d);
+    } else {
+        gen_helper_vfp_negs(cpu_F1s, cpu_F0s);
+    }
+}
+
+static inline void gen_vfp_abs(int dp)
+{
+    if (dp)
+        gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
+    else
+        gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
+}
+
+static inline void gen_vfp_neg(int dp)
+{
+    if (dp)
+        gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
+    else
+        gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
+}
+
+static inline void gen_vfp_sqrt(int dp)
+{
+    if (dp)
+        gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env);
+    else
+        gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env);
+}
+
+static inline void gen_vfp_cmp(int dp)
+{
+    if (dp)
+        gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env);
+    else
+        gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env);
+}
+
+static inline void gen_vfp_cmpe(int dp)
+{
+    if (dp)
+        gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env);
+    else
+        gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env);
+}
+
+static inline void gen_vfp_F1_ld0(int dp)
+{
+    if (dp)
+        tcg_gen_movi_i64(cpu_F1d, 0);
+    else
+        tcg_gen_movi_i32(cpu_F1s, 0);
+}
+
+#define VFP_GEN_ITOF(name) \
+static inline void gen_vfp_##name(int dp, int neon) \
+{ \
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
+    } \
+    tcg_temp_free_ptr(statusptr); \
+}
+
+VFP_GEN_ITOF(uito)
+VFP_GEN_ITOF(sito)
+#undef VFP_GEN_ITOF
+
+#define VFP_GEN_FTOI(name) \
+static inline void gen_vfp_##name(int dp, int neon) \
+{ \
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
+    } \
+    tcg_temp_free_ptr(statusptr); \
+}
+
+VFP_GEN_FTOI(toui)
+VFP_GEN_FTOI(touiz)
+VFP_GEN_FTOI(tosi)
+VFP_GEN_FTOI(tosiz)
+#undef VFP_GEN_FTOI
+
+#define VFP_GEN_FIX(name) \
+static inline void gen_vfp_##name(int dp, int shift, int neon) \
+{ \
+    TCGv tmp_shift = tcg_const_i32(shift); \
+    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
+    if (dp) { \
+        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
+    } else { \
+        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
+    } \
+    tcg_temp_free_i32(tmp_shift); \
+    tcg_temp_free_ptr(statusptr); \
+}
+VFP_GEN_FIX(tosh)
+VFP_GEN_FIX(tosl)
+VFP_GEN_FIX(touh)
+VFP_GEN_FIX(toul)
+VFP_GEN_FIX(shto)
+VFP_GEN_FIX(slto)
+VFP_GEN_FIX(uhto)
+VFP_GEN_FIX(ulto)
+#undef VFP_GEN_FIX
+
+static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr)
+{
+    if (dp)
+        tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s));
+    else
+        tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s));
+}
+
+static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr)
+{
+    if (dp)
+        tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s));
+    else
+        tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s));
+}
+
+static inline long
+vfp_reg_offset (int dp, int reg)
+{
+    if (dp)
+        return offsetof(CPUARMState, vfp.regs[reg]);
+    else if (reg & 1) {
+        return offsetof(CPUARMState, vfp.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.upper);
+    } else {
+        return offsetof(CPUARMState, vfp.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.lower);
+    }
+}
+
+/* Return the offset of a 32-bit piece of a NEON register.
+   zero is the least significant end of the register.  */
+static inline long
+neon_reg_offset (int reg, int n)
+{
+    int sreg;
+    sreg = reg * 2 + n;
+    return vfp_reg_offset(0, sreg);
+}
+
+static TCGv neon_load_reg(int reg, int pass)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
+    return tmp;
+}
+
+static void neon_store_reg(int reg, int pass, TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
+    tcg_temp_free_i32(var);
+}
+
+static inline void neon_load_reg64(TCGv_i64 var, int reg)
+{
+    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
+}
+
+static inline void neon_store_reg64(TCGv_i64 var, int reg)
+{
+    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
+}
+
+#define tcg_gen_ld_f32 tcg_gen_ld_i32
+#define tcg_gen_ld_f64 tcg_gen_ld_i64
+#define tcg_gen_st_f32 tcg_gen_st_i32
+#define tcg_gen_st_f64 tcg_gen_st_i64
+
+static inline void gen_mov_F0_vreg(int dp, int reg)
+{
+    if (dp)
+        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
+    else
+        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
+}
+
+static inline void gen_mov_F1_vreg(int dp, int reg)
+{
+    if (dp)
+        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
+    else
+        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
+}
+
+static inline void gen_mov_vreg_F0(int dp, int reg)
+{
+    if (dp)
+        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
+    else
+        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
+}
+
+#define ARM_CP_RW_BIT	(1 << 20)
+
+static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
+{
+    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
+}
+
+static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
+{
+    tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
+}
+
+static inline TCGv iwmmxt_load_creg(int reg)
+{
+    TCGv var = tcg_temp_new_i32();
+    tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
+    return var;
+}
+
+static inline void iwmmxt_store_creg(int reg, TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
+    tcg_temp_free_i32(var);
+}
+
+static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
+{
+    iwmmxt_store_reg(cpu_M0, rn);
+}
+
+static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
+{
+    iwmmxt_load_reg(cpu_M0, rn);
+}
+
+static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
+{
+    iwmmxt_load_reg(cpu_V1, rn);
+    tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
+}
+
+static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
+{
+    iwmmxt_load_reg(cpu_V1, rn);
+    tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
+}
+
+static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
+{
+    iwmmxt_load_reg(cpu_V1, rn);
+    tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
+}
+
+#define IWMMXT_OP(name) \
+static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
+{ \
+    iwmmxt_load_reg(cpu_V1, rn); \
+    gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
+}
+
+#define IWMMXT_OP_ENV(name) \
+static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
+{ \
+    iwmmxt_load_reg(cpu_V1, rn); \
+    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
+}
+
+#define IWMMXT_OP_ENV_SIZE(name) \
+IWMMXT_OP_ENV(name##b) \
+IWMMXT_OP_ENV(name##w) \
+IWMMXT_OP_ENV(name##l)
+
+#define IWMMXT_OP_ENV1(name) \
+static inline void gen_op_iwmmxt_##name##_M0(void) \
+{ \
+    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
+}
+
+IWMMXT_OP(maddsq)
+IWMMXT_OP(madduq)
+IWMMXT_OP(sadb)
+IWMMXT_OP(sadw)
+IWMMXT_OP(mulslw)
+IWMMXT_OP(mulshw)
+IWMMXT_OP(mululw)
+IWMMXT_OP(muluhw)
+IWMMXT_OP(macsw)
+IWMMXT_OP(macuw)
+
+IWMMXT_OP_ENV_SIZE(unpackl)
+IWMMXT_OP_ENV_SIZE(unpackh)
+
+IWMMXT_OP_ENV1(unpacklub)
+IWMMXT_OP_ENV1(unpackluw)
+IWMMXT_OP_ENV1(unpacklul)
+IWMMXT_OP_ENV1(unpackhub)
+IWMMXT_OP_ENV1(unpackhuw)
+IWMMXT_OP_ENV1(unpackhul)
+IWMMXT_OP_ENV1(unpacklsb)
+IWMMXT_OP_ENV1(unpacklsw)
+IWMMXT_OP_ENV1(unpacklsl)
+IWMMXT_OP_ENV1(unpackhsb)
+IWMMXT_OP_ENV1(unpackhsw)
+IWMMXT_OP_ENV1(unpackhsl)
+
+IWMMXT_OP_ENV_SIZE(cmpeq)
+IWMMXT_OP_ENV_SIZE(cmpgtu)
+IWMMXT_OP_ENV_SIZE(cmpgts)
+
+IWMMXT_OP_ENV_SIZE(mins)
+IWMMXT_OP_ENV_SIZE(minu)
+IWMMXT_OP_ENV_SIZE(maxs)
+IWMMXT_OP_ENV_SIZE(maxu)
+
+IWMMXT_OP_ENV_SIZE(subn)
+IWMMXT_OP_ENV_SIZE(addn)
+IWMMXT_OP_ENV_SIZE(subu)
+IWMMXT_OP_ENV_SIZE(addu)
+IWMMXT_OP_ENV_SIZE(subs)
+IWMMXT_OP_ENV_SIZE(adds)
+
+IWMMXT_OP_ENV(avgb0)
+IWMMXT_OP_ENV(avgb1)
+IWMMXT_OP_ENV(avgw0)
+IWMMXT_OP_ENV(avgw1)
+
+IWMMXT_OP(msadb)
+
+IWMMXT_OP_ENV(packuw)
+IWMMXT_OP_ENV(packul)
+IWMMXT_OP_ENV(packuq)
+IWMMXT_OP_ENV(packsw)
+IWMMXT_OP_ENV(packsl)
+IWMMXT_OP_ENV(packsq)
+
+static void gen_op_iwmmxt_set_mup(void)
+{
+    TCGv tmp;
+    tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
+    tcg_gen_ori_i32(tmp, tmp, 2);
+    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
+}
+
+static void gen_op_iwmmxt_set_cup(void)
+{
+    TCGv tmp;
+    tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
+    tcg_gen_ori_i32(tmp, tmp, 1);
+    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
+}
+
+static void gen_op_iwmmxt_setpsr_nz(void)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
+    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
+}
+
+static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
+{
+    iwmmxt_load_reg(cpu_V1, rn);
+    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
+    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
+}
+
+static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest)
+{
+    int rd;
+    uint32_t offset;
+    TCGv tmp;
+
+    rd = (insn >> 16) & 0xf;
+    tmp = load_reg(s, rd);
+
+    offset = (insn & 0xff) << ((insn >> 7) & 2);
+    if (insn & (1 << 24)) {
+        /* Pre indexed */
+        if (insn & (1 << 23))
+            tcg_gen_addi_i32(tmp, tmp, offset);
+        else
+            tcg_gen_addi_i32(tmp, tmp, -offset);
+        tcg_gen_mov_i32(dest, tmp);
+        if (insn & (1 << 21))
+            store_reg(s, rd, tmp);
+        else
+            tcg_temp_free_i32(tmp);
+    } else if (insn & (1 << 21)) {
+        /* Post indexed */
+        tcg_gen_mov_i32(dest, tmp);
+        if (insn & (1 << 23))
+            tcg_gen_addi_i32(tmp, tmp, offset);
+        else
+            tcg_gen_addi_i32(tmp, tmp, -offset);
+        store_reg(s, rd, tmp);
+    } else if (!(insn & (1 << 23)))
+        return 1;
+    return 0;
+}
+
+static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest)
+{
+    int rd = (insn >> 0) & 0xf;
+    TCGv tmp;
+
+    if (insn & (1 << 8)) {
+        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
+            return 1;
+        } else {
+            tmp = iwmmxt_load_creg(rd);
+        }
+    } else {
+        tmp = tcg_temp_new_i32();
+        iwmmxt_load_reg(cpu_V0, rd);
+        tcg_gen_trunc_i64_i32(tmp, cpu_V0);
+    }
+    tcg_gen_andi_i32(tmp, tmp, mask);
+    tcg_gen_mov_i32(dest, tmp);
+    tcg_temp_free_i32(tmp);
+    return 0;
+}
+
+/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
+   (ie. an undefined instruction).  */
+static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int rd, wrd;
+    int rdhi, rdlo, rd0, rd1, i;
+    TCGv addr;
+    TCGv tmp, tmp2, tmp3;
+
+    if ((insn & 0x0e000e00) == 0x0c000000) {
+        if ((insn & 0x0fe00ff0) == 0x0c400000) {
+            wrd = insn & 0xf;
+            rdlo = (insn >> 12) & 0xf;
+            rdhi = (insn >> 16) & 0xf;
+            if (insn & ARM_CP_RW_BIT) {			/* TMRRC */
+                iwmmxt_load_reg(cpu_V0, wrd);
+                tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
+                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
+                tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
+            } else {					/* TMCRR */
+                tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
+                iwmmxt_store_reg(cpu_V0, wrd);
+                gen_op_iwmmxt_set_mup();
+            }
+            return 0;
+        }
+
+        wrd = (insn >> 12) & 0xf;
+        addr = tcg_temp_new_i32();
+        if (gen_iwmmxt_address(s, insn, addr)) {
+            tcg_temp_free_i32(addr);
+            return 1;
+        }
+        if (insn & ARM_CP_RW_BIT) {
+            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
+                tmp = tcg_temp_new_i32();
+                tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
+                iwmmxt_store_creg(wrd, tmp);
+            } else {
+                i = 1;
+                if (insn & (1 << 8)) {
+                    if (insn & (1 << 22)) {		/* WLDRD */
+                        tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s));
+                        i = 0;
+                    } else {				/* WLDRW wRd */
+                        tmp = gen_ld32(addr, IS_USER(s));
+                    }
+                } else {
+                    if (insn & (1 << 22)) {		/* WLDRH */
+                        tmp = gen_ld16u(addr, IS_USER(s));
+                    } else {				/* WLDRB */
+                        tmp = gen_ld8u(addr, IS_USER(s));
+                    }
+                }
+                if (i) {
+                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
+                    tcg_temp_free_i32(tmp);
+                }
+                gen_op_iwmmxt_movq_wRn_M0(wrd);
+            }
+        } else {
+            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
+                tmp = iwmmxt_load_creg(wrd);
+                gen_st32(tmp, addr, IS_USER(s));
+            } else {
+                gen_op_iwmmxt_movq_M0_wRn(wrd);
+                tmp = tcg_temp_new_i32();
+                if (insn & (1 << 8)) {
+                    if (insn & (1 << 22)) {		/* WSTRD */
+                        tcg_temp_free_i32(tmp);
+                        tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
+                    } else {				/* WSTRW wRd */
+                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+                        gen_st32(tmp, addr, IS_USER(s));
+                    }
+                } else {
+                    if (insn & (1 << 22)) {		/* WSTRH */
+                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+                        gen_st16(tmp, addr, IS_USER(s));
+                    } else {				/* WSTRB */
+                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+                        gen_st8(tmp, addr, IS_USER(s));
+                    }
+                }
+            }
+        }
+        tcg_temp_free_i32(addr);
+        return 0;
+    }
+
+    if ((insn & 0x0f000000) != 0x0e000000)
+        return 1;
+
+    switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
+    case 0x000:						/* WOR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_orq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x011:						/* TMCR */
+        if (insn & 0xf)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        switch (wrd) {
+        case ARM_IWMMXT_wCID:
+        case ARM_IWMMXT_wCASF:
+            break;
+        case ARM_IWMMXT_wCon:
+            gen_op_iwmmxt_set_cup();
+            /* Fall through.  */
+        case ARM_IWMMXT_wCSSF:
+            tmp = iwmmxt_load_creg(wrd);
+            tmp2 = load_reg(s, rd);
+            tcg_gen_andc_i32(tmp, tmp, tmp2);
+            tcg_temp_free_i32(tmp2);
+            iwmmxt_store_creg(wrd, tmp);
+            break;
+        case ARM_IWMMXT_wCGR0:
+        case ARM_IWMMXT_wCGR1:
+        case ARM_IWMMXT_wCGR2:
+        case ARM_IWMMXT_wCGR3:
+            gen_op_iwmmxt_set_cup();
+            tmp = load_reg(s, rd);
+            iwmmxt_store_creg(wrd, tmp);
+            break;
+        default:
+            return 1;
+        }
+        break;
+    case 0x100:						/* WXOR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_xorq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x111:						/* TMRC */
+        if (insn & 0xf)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        tmp = iwmmxt_load_creg(wrd);
+        store_reg(s, rd, tmp);
+        break;
+    case 0x300:						/* WANDN */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tcg_gen_neg_i64(cpu_M0, cpu_M0);
+        gen_op_iwmmxt_andq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x200:						/* WAND */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_andq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x810: case 0xa10:				/* WMADD */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21))
+            gen_op_iwmmxt_maddsq_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_madduq_M0_wRn(rd1);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x10e: case 0x50e: case 0x90e: case 0xd0e:	/* WUNPCKIL */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_unpackll_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x10c: case 0x50c: case 0x90c: case 0xd0c:	/* WUNPCKIH */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x012: case 0x112: case 0x412: case 0x512:	/* WSAD */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 22))
+            gen_op_iwmmxt_sadw_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_sadb_M0_wRn(rd1);
+        if (!(insn & (1 << 20)))
+            gen_op_iwmmxt_addl_M0_wRn(wrd);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x010: case 0x110: case 0x210: case 0x310:	/* WMUL */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21)) {
+            if (insn & (1 << 20))
+                gen_op_iwmmxt_mulshw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_mulslw_M0_wRn(rd1);
+        } else {
+            if (insn & (1 << 20))
+                gen_op_iwmmxt_muluhw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_mululw_M0_wRn(rd1);
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x410: case 0x510: case 0x610: case 0x710:	/* WMAC */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21))
+            gen_op_iwmmxt_macsw_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_macuw_M0_wRn(rd1);
+        if (!(insn & (1 << 20))) {
+            iwmmxt_load_reg(cpu_V1, wrd);
+            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x006: case 0x406: case 0x806: case 0xc06:	/* WCMPEQ */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x800: case 0x900: case 0xc00: case 0xd00:	/* WAVG2 */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 22)) {
+            if (insn & (1 << 20))
+                gen_op_iwmmxt_avgw1_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_avgw0_M0_wRn(rd1);
+        } else {
+            if (insn & (1 << 20))
+                gen_op_iwmmxt_avgb1_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_avgb0_M0_wRn(rd1);
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x802: case 0x902: case 0xa02: case 0xb02:	/* WALIGNR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
+        tcg_gen_andi_i32(tmp, tmp, 7);
+        iwmmxt_load_reg(cpu_V1, rd1);
+        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
+        if (((insn >> 6) & 3) == 3)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        tmp = load_reg(s, rd);
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        switch ((insn >> 6) & 3) {
+        case 0:
+            tmp2 = tcg_const_i32(0xff);
+            tmp3 = tcg_const_i32((insn & 7) << 3);
+            break;
+        case 1:
+            tmp2 = tcg_const_i32(0xffff);
+            tmp3 = tcg_const_i32((insn & 3) << 4);
+            break;
+        case 2:
+            tmp2 = tcg_const_i32(0xffffffff);
+            tmp3 = tcg_const_i32((insn & 1) << 5);
+            break;
+        default:
+            TCGV_UNUSED(tmp2);
+            TCGV_UNUSED(tmp3);
+        }
+        gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
+        tcg_temp_free(tmp3);
+        tcg_temp_free(tmp2);
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x107: case 0x507: case 0x907: case 0xd07:	/* TEXTRM */
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        if (rd == 15 || ((insn >> 22) & 3) == 3)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        tmp = tcg_temp_new_i32();
+        switch ((insn >> 22) & 3) {
+        case 0:
+            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
+            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+            if (insn & 8) {
+                tcg_gen_ext8s_i32(tmp, tmp);
+            } else {
+                tcg_gen_andi_i32(tmp, tmp, 0xff);
+            }
+            break;
+        case 1:
+            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
+            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+            if (insn & 8) {
+                tcg_gen_ext16s_i32(tmp, tmp);
+            } else {
+                tcg_gen_andi_i32(tmp, tmp, 0xffff);
+            }
+            break;
+        case 2:
+            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
+            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
+            break;
+        }
+        store_reg(s, rd, tmp);
+        break;
+    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
+        if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
+            return 1;
+        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
+            break;
+        case 1:
+            tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
+            break;
+        case 2:
+            tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
+            break;
+        }
+        tcg_gen_shli_i32(tmp, tmp, 28);
+        gen_set_nzcv(tmp);
+        tcg_temp_free_i32(tmp);
+        break;
+    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
+        if (((insn >> 6) & 3) == 3)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        tmp = load_reg(s, rd);
+        switch ((insn >> 6) & 3) {
+        case 0:
+            gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
+            break;
+        case 1:
+            gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
+            break;
+        case 2:
+            gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
+            break;
+        }
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
+        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
+            return 1;
+        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_mov_i32(tmp2, tmp);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            for (i = 0; i < 7; i ++) {
+                tcg_gen_shli_i32(tmp2, tmp2, 4);
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+            }
+            break;
+        case 1:
+            for (i = 0; i < 3; i ++) {
+                tcg_gen_shli_i32(tmp2, tmp2, 8);
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+            }
+            break;
+        case 2:
+            tcg_gen_shli_i32(tmp2, tmp2, 16);
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            break;
+        }
+        gen_set_nzcv(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
+        break;
+    case 0x01c: case 0x41c: case 0x81c: case 0xc1c:	/* WACC */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
+            break;
+        case 1:
+            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
+            break;
+        case 2:
+            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x115: case 0x515: case 0x915: case 0xd15:	/* TORC */
+        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
+            return 1;
+        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_mov_i32(tmp2, tmp);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            for (i = 0; i < 7; i ++) {
+                tcg_gen_shli_i32(tmp2, tmp2, 4);
+                tcg_gen_or_i32(tmp, tmp, tmp2);
+            }
+            break;
+        case 1:
+            for (i = 0; i < 3; i ++) {
+                tcg_gen_shli_i32(tmp2, tmp2, 8);
+                tcg_gen_or_i32(tmp, tmp, tmp2);
+            }
+            break;
+        case 2:
+            tcg_gen_shli_i32(tmp2, tmp2, 16);
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            break;
+        }
+        gen_set_nzcv(tmp);
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
+        break;
+    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
+        rd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_temp_new_i32();
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_helper_iwmmxt_msbb(tmp, cpu_M0);
+            break;
+        case 1:
+            gen_helper_iwmmxt_msbw(tmp, cpu_M0);
+            break;
+        case 2:
+            gen_helper_iwmmxt_msbl(tmp, cpu_M0);
+            break;
+        }
+        store_reg(s, rd, tmp);
+        break;
+    case 0x106: case 0x306: case 0x506: case 0x706:	/* WCMPGT */
+    case 0x906: case 0xb06: case 0xd06: case 0xf06:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x00e: case 0x20e: case 0x40e: case 0x60e:	/* WUNPCKEL */
+    case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsb_M0();
+            else
+                gen_op_iwmmxt_unpacklub_M0();
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsw_M0();
+            else
+                gen_op_iwmmxt_unpackluw_M0();
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsl_M0();
+            else
+                gen_op_iwmmxt_unpacklul_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x00c: case 0x20c: case 0x40c: case 0x60c:	/* WUNPCKEH */
+    case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsb_M0();
+            else
+                gen_op_iwmmxt_unpackhub_M0();
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsw_M0();
+            else
+                gen_op_iwmmxt_unpackhuw_M0();
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsl_M0();
+            else
+                gen_op_iwmmxt_unpackhul_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x204: case 0x604: case 0xa04: case 0xe04:	/* WSRL */
+    case 0x214: case 0x614: case 0xa14: case 0xe14:
+        if (((insn >> 22) & 3) == 0)
+            return 1;
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_temp_new_i32();
+        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
+            tcg_temp_free_i32(tmp);
+            return 1;
+        }
+        switch ((insn >> 22) & 3) {
+        case 1:
+            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 2:
+            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 3:
+            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        }
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x004: case 0x404: case 0x804: case 0xc04:	/* WSRA */
+    case 0x014: case 0x414: case 0x814: case 0xc14:
+        if (((insn >> 22) & 3) == 0)
+            return 1;
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_temp_new_i32();
+        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
+            tcg_temp_free_i32(tmp);
+            return 1;
+        }
+        switch ((insn >> 22) & 3) {
+        case 1:
+            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 2:
+            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 3:
+            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        }
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x104: case 0x504: case 0x904: case 0xd04:	/* WSLL */
+    case 0x114: case 0x514: case 0x914: case 0xd14:
+        if (((insn >> 22) & 3) == 0)
+            return 1;
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_temp_new_i32();
+        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
+            tcg_temp_free_i32(tmp);
+            return 1;
+        }
+        switch ((insn >> 22) & 3) {
+        case 1:
+            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 2:
+            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 3:
+            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        }
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x304: case 0x704: case 0xb04: case 0xf04:	/* WROR */
+    case 0x314: case 0x714: case 0xb14: case 0xf14:
+        if (((insn >> 22) & 3) == 0)
+            return 1;
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_temp_new_i32();
+        switch ((insn >> 22) & 3) {
+        case 1:
+            if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
+                tcg_temp_free_i32(tmp);
+                return 1;
+            }
+            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 2:
+            if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
+                tcg_temp_free_i32(tmp);
+                return 1;
+            }
+            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        case 3:
+            if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
+                tcg_temp_free_i32(tmp);
+                return 1;
+            }
+            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
+            break;
+        }
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x116: case 0x316: case 0x516: case 0x716:	/* WMIN */
+    case 0x916: case 0xb16: case 0xd16: case 0xf16:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x016: case 0x216: case 0x416: case 0x616:	/* WMAX */
+    case 0x816: case 0xa16: case 0xc16: case 0xe16:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x002: case 0x102: case 0x202: case 0x302:	/* WALIGNI */
+    case 0x402: case 0x502: case 0x602: case 0x702:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_const_i32((insn >> 20) & 3);
+        iwmmxt_load_reg(cpu_V1, rd1);
+        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
+        tcg_temp_free(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x01a: case 0x11a: case 0x21a: case 0x31a:	/* WSUB */
+    case 0x41a: case 0x51a: case 0x61a: case 0x71a:
+    case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
+    case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 20) & 0xf) {
+        case 0x0:
+            gen_op_iwmmxt_subnb_M0_wRn(rd1);
+            break;
+        case 0x1:
+            gen_op_iwmmxt_subub_M0_wRn(rd1);
+            break;
+        case 0x3:
+            gen_op_iwmmxt_subsb_M0_wRn(rd1);
+            break;
+        case 0x4:
+            gen_op_iwmmxt_subnw_M0_wRn(rd1);
+            break;
+        case 0x5:
+            gen_op_iwmmxt_subuw_M0_wRn(rd1);
+            break;
+        case 0x7:
+            gen_op_iwmmxt_subsw_M0_wRn(rd1);
+            break;
+        case 0x8:
+            gen_op_iwmmxt_subnl_M0_wRn(rd1);
+            break;
+        case 0x9:
+            gen_op_iwmmxt_subul_M0_wRn(rd1);
+            break;
+        case 0xb:
+            gen_op_iwmmxt_subsl_M0_wRn(rd1);
+            break;
+        default:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x01e: case 0x11e: case 0x21e: case 0x31e:	/* WSHUFH */
+    case 0x41e: case 0x51e: case 0x61e: case 0x71e:
+    case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
+    case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
+        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
+        tcg_temp_free(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x018: case 0x118: case 0x218: case 0x318:	/* WADD */
+    case 0x418: case 0x518: case 0x618: case 0x718:
+    case 0x818: case 0x918: case 0xa18: case 0xb18:
+    case 0xc18: case 0xd18: case 0xe18: case 0xf18:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 20) & 0xf) {
+        case 0x0:
+            gen_op_iwmmxt_addnb_M0_wRn(rd1);
+            break;
+        case 0x1:
+            gen_op_iwmmxt_addub_M0_wRn(rd1);
+            break;
+        case 0x3:
+            gen_op_iwmmxt_addsb_M0_wRn(rd1);
+            break;
+        case 0x4:
+            gen_op_iwmmxt_addnw_M0_wRn(rd1);
+            break;
+        case 0x5:
+            gen_op_iwmmxt_adduw_M0_wRn(rd1);
+            break;
+        case 0x7:
+            gen_op_iwmmxt_addsw_M0_wRn(rd1);
+            break;
+        case 0x8:
+            gen_op_iwmmxt_addnl_M0_wRn(rd1);
+            break;
+        case 0x9:
+            gen_op_iwmmxt_addul_M0_wRn(rd1);
+            break;
+        case 0xb:
+            gen_op_iwmmxt_addsl_M0_wRn(rd1);
+            break;
+        default:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x008: case 0x108: case 0x208: case 0x308:	/* WPACK */
+    case 0x408: case 0x508: case 0x608: case 0x708:
+    case 0x808: case 0x908: case 0xa08: case 0xb08:
+    case 0xc08: case 0xd08: case 0xe08: case 0xf08:
+        if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
+            return 1;
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packul_M0_wRn(rd1);
+            break;
+        case 3:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsq_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packuq_M0_wRn(rd1);
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x201: case 0x203: case 0x205: case 0x207:
+    case 0x209: case 0x20b: case 0x20d: case 0x20f:
+    case 0x211: case 0x213: case 0x215: case 0x217:
+    case 0x219: case 0x21b: case 0x21d: case 0x21f:
+        wrd = (insn >> 5) & 0xf;
+        rd0 = (insn >> 12) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        if (rd0 == 0xf || rd1 == 0xf)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        tmp = load_reg(s, rd0);
+        tmp2 = load_reg(s, rd1);
+        switch ((insn >> 16) & 0xf) {
+        case 0x0:					/* TMIA */
+            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        case 0x8:					/* TMIAPH */
+            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
+            if (insn & (1 << 16))
+                tcg_gen_shri_i32(tmp, tmp, 16);
+            if (insn & (1 << 17))
+                tcg_gen_shri_i32(tmp2, tmp2, 16);
+            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        default:
+            tcg_temp_free_i32(tmp2);
+            tcg_temp_free_i32(tmp);
+            return 1;
+        }
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    default:
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
+   (ie. an undefined instruction).  */
+static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int acc, rd0, rd1, rdhi, rdlo;
+    TCGv tmp, tmp2;
+
+    if ((insn & 0x0ff00f10) == 0x0e200010) {
+        /* Multiply with Internal Accumulate Format */
+        rd0 = (insn >> 12) & 0xf;
+        rd1 = insn & 0xf;
+        acc = (insn >> 5) & 7;
+
+        if (acc != 0)
+            return 1;
+
+        tmp = load_reg(s, rd0);
+        tmp2 = load_reg(s, rd1);
+        switch ((insn >> 16) & 0xf) {
+        case 0x0:					/* MIA */
+            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        case 0x8:					/* MIAPH */
+            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        case 0xc:					/* MIABB */
+        case 0xd:					/* MIABT */
+        case 0xe:					/* MIATB */
+        case 0xf:					/* MIATT */
+            if (insn & (1 << 16))
+                tcg_gen_shri_i32(tmp, tmp, 16);
+            if (insn & (1 << 17))
+                tcg_gen_shri_i32(tmp2, tmp2, 16);
+            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
+            break;
+        default:
+            return 1;
+        }
+        tcg_temp_free_i32(tmp2);
+        tcg_temp_free_i32(tmp);
+
+        gen_op_iwmmxt_movq_wRn_M0(acc);
+        return 0;
+    }
+
+    if ((insn & 0x0fe00ff8) == 0x0c400000) {
+        /* Internal Accumulator Access Format */
+        rdhi = (insn >> 16) & 0xf;
+        rdlo = (insn >> 12) & 0xf;
+        acc = insn & 7;
+
+        if (acc != 0)
+            return 1;
+
+        if (insn & ARM_CP_RW_BIT) {			/* MRA */
+            iwmmxt_load_reg(cpu_V0, acc);
+            tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
+            tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
+            tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
+            tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
+        } else {					/* MAR */
+            tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
+            iwmmxt_store_reg(cpu_V0, acc);
+        }
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Disassemble system coprocessor instruction.  Return nonzero if
+   instruction is not defined.  */
+static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp, tmp2;
+    uint32_t rd = (insn >> 12) & 0xf;
+    uint32_t cp = (insn >> 8) & 0xf;
+    if (IS_USER(s)) {
+        return 1;
+    }
+
+    if (insn & ARM_CP_RW_BIT) {
+        if (!env->cp[cp].cp_read)
+            return 1;
+        gen_set_pc_im(s->pc);
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_const_i32(insn);
+        gen_helper_get_cp(tmp, cpu_env, tmp2);
+        tcg_temp_free(tmp2);
+        store_reg(s, rd, tmp);
+    } else {
+        if (!env->cp[cp].cp_write)
+            return 1;
+        gen_set_pc_im(s->pc);
+        tmp = load_reg(s, rd);
+        tmp2 = tcg_const_i32(insn);
+        gen_helper_set_cp(cpu_env, tmp2, tmp);
+        tcg_temp_free(tmp2);
+        tcg_temp_free_i32(tmp);
+    }
+    return 0;
+}
+
+static int cp15_user_ok(CPUState *env, uint32_t insn)
+{
+    int cpn = (insn >> 16) & 0xf;
+    int cpm = insn & 0xf;
+    int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
+
+    if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) {
+        /* Performance monitor registers fall into three categories:
+         *  (a) always UNDEF in usermode
+         *  (b) UNDEF only if PMUSERENR.EN is 0
+         *  (c) always read OK and UNDEF on write (PMUSERENR only)
+         */
+        if ((cpm == 12 && (op < 6)) ||
+            (cpm == 13 && (op < 3))) {
+            return env->cp15.c9_pmuserenr;
+        } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) {
+            /* PMUSERENR, read only */
+            return 1;
+        }
+        return 0;
+    }
+
+    if (cpn == 13 && cpm == 0) {
+        /* TLS register.  */
+        if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
+            return 1;
+    }
+    return 0;
+}
+
+static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, uint32_t rd)
+{
+    TCGv tmp;
+    int cpn = (insn >> 16) & 0xf;
+    int cpm = insn & 0xf;
+    int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
+
+    if (!arm_feature(env, ARM_FEATURE_V6K))
+        return 0;
+
+    if (!(cpn == 13 && cpm == 0))
+        return 0;
+
+    if (insn & ARM_CP_RW_BIT) {
+        switch (op) {
+        case 2:
+            tmp = load_cpu_field(cp15.c13_tls1);
+            break;
+        case 3:
+            tmp = load_cpu_field(cp15.c13_tls2);
+            break;
+        case 4:
+            tmp = load_cpu_field(cp15.c13_tls3);
+            break;
+        default:
+            return 0;
+        }
+        store_reg(s, rd, tmp);
+
+    } else {
+        tmp = load_reg(s, rd);
+        switch (op) {
+        case 2:
+            store_cpu_field(tmp, cp15.c13_tls1);
+            break;
+        case 3:
+            store_cpu_field(tmp, cp15.c13_tls2);
+            break;
+        case 4:
+            store_cpu_field(tmp, cp15.c13_tls3);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
+   instruction is not defined.  */
+static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    uint32_t rd;
+    TCGv tmp, tmp2;
+
+    /* M profile cores use memory mapped registers instead of cp15.  */
+    if (arm_feature(env, ARM_FEATURE_M))
+	return 1;
+
+    if ((insn & (1 << 25)) == 0) {
+        if (insn & (1 << 20)) {
+            /* mrrc */
+            return 1;
+        }
+        /* mcrr.  Used for block cache operations, so implement as no-op.  */
+        return 0;
+    }
+    if ((insn & (1 << 4)) == 0) {
+        /* cdp */
+        return 1;
+    }
+    /* We special case a number of cp15 instructions which were used
+     * for things which are real instructions in ARMv7. This allows
+     * them to work in linux-user mode which doesn't provide functional
+     * get_cp15/set_cp15 helpers, and is more efficient anyway.
+     */
+    switch ((insn & 0x0fff0fff)) {
+    case 0x0e070f90:
+        /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
+         * In v7, this must NOP.
+         */
+        if (IS_USER(s)) {
+            return 1;
+        }
+        if (!arm_feature(env, ARM_FEATURE_V7)) {
+            /* Wait for interrupt.  */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_WFI;
+        }
+        return 0;
+    case 0x0e070f58:
+        /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
+         * so this is slightly over-broad.
+         */
+        if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
+            /* Wait for interrupt.  */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_WFI;
+            return 0;
+        }
+        /* Otherwise continue to handle via helper function.
+         * In particular, on v7 and some v6 cores this is one of
+         * the VA-PA registers.
+         */
+        break;
+    case 0x0e070f3d:
+        /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return IS_USER(s) ? 1 : 0;
+        }
+        break;
+    case 0x0e070f95: /* 0,c7,c5,4 : ISB */
+    case 0x0e070f9a: /* 0,c7,c10,4: DSB */
+    case 0x0e070fba: /* 0,c7,c10,5: DMB */
+        /* Barriers in both v6 and v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return 0;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (IS_USER(s) && !cp15_user_ok(env, insn)) {
+        return 1;
+    }
+
+    rd = (insn >> 12) & 0xf;
+
+    if (cp15_tls_load_store(env, s, insn, rd))
+        return 0;
+
+    tmp2 = tcg_const_i32(insn);
+    if (insn & ARM_CP_RW_BIT) {
+        tmp = tcg_temp_new_i32();
+        gen_helper_get_cp15(tmp, cpu_env, tmp2);
+        /* If the destination register is r15 then sets condition codes.  */
+        if (rd != 15)
+            store_reg(s, rd, tmp);
+        else
+            tcg_temp_free_i32(tmp);
+    } else {
+        tmp = load_reg(s, rd);
+        gen_helper_set_cp15(cpu_env, tmp2, tmp);
+        tcg_temp_free_i32(tmp);
+        /* Normally we would always end the TB here, but Linux
+         * arch/arm/mach-pxa/sleep.S expects two instructions following
+         * an MMU enable to execute from cache.  Imitate this behaviour.  */
+        if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
+                (insn & 0x0fff0fff) != 0x0e010f10)
+            gen_lookup_tb(s);
+    }
+    tcg_temp_free_i32(tmp2);
+    return 0;
+}
+
+#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
+#define VFP_SREG(insn, bigbit, smallbit) \
+  ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
+#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
+    if (arm_feature(env, ARM_FEATURE_VFP3)) { \
+        reg = (((insn) >> (bigbit)) & 0x0f) \
+              | (((insn) >> ((smallbit) - 4)) & 0x10); \
+    } else { \
+        if (insn & (1 << (smallbit))) \
+            return 1; \
+        reg = ((insn) >> (bigbit)) & 0x0f; \
+    }} while (0)
+
+#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
+#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
+#define VFP_SREG_N(insn) VFP_SREG(insn, 16,  7)
+#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16,  7)
+#define VFP_SREG_M(insn) VFP_SREG(insn,  0,  5)
+#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn,  0,  5)
+
+/* Move between integer and VFP cores.  */
+static TCGv gen_vfp_mrs(void)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_mov_i32(tmp, cpu_F0s);
+    return tmp;
+}
+
+static void gen_vfp_msr(TCGv tmp)
+{
+    tcg_gen_mov_i32(cpu_F0s, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_neon_dup_u8(TCGv var, int shift)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    if (shift)
+        tcg_gen_shri_i32(var, var, shift);
+    tcg_gen_ext8u_i32(var, var);
+    tcg_gen_shli_i32(tmp, var, 8);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_gen_shli_i32(tmp, var, 16);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_neon_dup_low16(TCGv var)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_ext16u_i32(var, var);
+    tcg_gen_shli_i32(tmp, var, 16);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_neon_dup_high16(TCGv var)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_andi_i32(var, var, 0xffff0000);
+    tcg_gen_shri_i32(tmp, var, 16);
+    tcg_gen_or_i32(var, var, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size)
+{
+    /* Load a single Neon element and replicate into a 32 bit TCG reg */
+    TCGv tmp;
+    switch (size) {
+    case 0:
+        tmp = gen_ld8u(addr, IS_USER(s));
+        gen_neon_dup_u8(tmp, 0);
+        break;
+    case 1:
+        tmp = gen_ld16u(addr, IS_USER(s));
+        gen_neon_dup_low16(tmp);
+        break;
+    case 2:
+        tmp = gen_ld32(addr, IS_USER(s));
+        break;
+    default: /* Avoid compiler warnings.  */
+        abort();
+    }
+    return tmp;
+}
+
+/* Disassemble a VFP instruction.  Returns nonzero if an error occurred
+   (ie. an undefined instruction).  */
+static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
+    int dp, veclen;
+    TCGv addr;
+    TCGv tmp;
+    TCGv tmp2;
+
+    if (!arm_feature(env, ARM_FEATURE_VFP))
+        return 1;
+
+    if (!s->vfp_enabled) {
+        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
+        if ((insn & 0x0fe00fff) != 0x0ee00a10)
+            return 1;
+        rn = (insn >> 16) & 0xf;
+        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
+            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
+            return 1;
+    }
+    dp = ((insn & 0xf00) == 0xb00);
+    switch ((insn >> 24) & 0xf) {
+    case 0xe:
+        if (insn & (1 << 4)) {
+            /* single register transfer */
+            rd = (insn >> 12) & 0xf;
+            if (dp) {
+                int size;
+                int pass;
+
+                VFP_DREG_N(rn, insn);
+                if (insn & 0xf)
+                    return 1;
+                if (insn & 0x00c00060
+                    && !arm_feature(env, ARM_FEATURE_NEON))
+                    return 1;
+
+                pass = (insn >> 21) & 1;
+                if (insn & (1 << 22)) {
+                    size = 0;
+                    offset = ((insn >> 5) & 3) * 8;
+                } else if (insn & (1 << 5)) {
+                    size = 1;
+                    offset = (insn & (1 << 6)) ? 16 : 0;
+                } else {
+                    size = 2;
+                    offset = 0;
+                }
+                if (insn & ARM_CP_RW_BIT) {
+                    /* vfp->arm */
+                    tmp = neon_load_reg(rn, pass);
+                    switch (size) {
+                    case 0:
+                        if (offset)
+                            tcg_gen_shri_i32(tmp, tmp, offset);
+                        if (insn & (1 << 23))
+                            gen_uxtb(tmp);
+                        else
+                            gen_sxtb(tmp);
+                        break;
+                    case 1:
+                        if (insn & (1 << 23)) {
+                            if (offset) {
+                                tcg_gen_shri_i32(tmp, tmp, 16);
+                            } else {
+                                gen_uxth(tmp);
+                            }
+                        } else {
+                            if (offset) {
+                                tcg_gen_sari_i32(tmp, tmp, 16);
+                            } else {
+                                gen_sxth(tmp);
+                            }
+                        }
+                        break;
+                    case 2:
+                        break;
+                    }
+                    store_reg(s, rd, tmp);
+                } else {
+                    /* arm->vfp */
+                    tmp = load_reg(s, rd);
+                    if (insn & (1 << 23)) {
+                        /* VDUP */
+                        if (size == 0) {
+                            gen_neon_dup_u8(tmp, 0);
+                        } else if (size == 1) {
+                            gen_neon_dup_low16(tmp);
+                        }
+                        for (n = 0; n <= pass * 2; n++) {
+                            tmp2 = tcg_temp_new_i32();
+                            tcg_gen_mov_i32(tmp2, tmp);
+                            neon_store_reg(rn, n, tmp2);
+                        }
+                        neon_store_reg(rn, n, tmp);
+                    } else {
+                        /* VMOV */
+                        switch (size) {
+                        case 0:
+                            tmp2 = neon_load_reg(rn, pass);
+                            gen_bfi(tmp, tmp2, tmp, offset, 0xff);
+                            tcg_temp_free_i32(tmp2);
+                            break;
+                        case 1:
+                            tmp2 = neon_load_reg(rn, pass);
+                            gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
+                            tcg_temp_free_i32(tmp2);
+                            break;
+                        case 2:
+                            break;
+                        }
+                        neon_store_reg(rn, pass, tmp);
+                    }
+                }
+            } else { /* !dp */
+                if ((insn & 0x6f) != 0x00)
+                    return 1;
+                rn = VFP_SREG_N(insn);
+                if (insn & ARM_CP_RW_BIT) {
+                    /* vfp->arm */
+                    if (insn & (1 << 21)) {
+                        /* system register */
+                        rn >>= 1;
+
+                        switch (rn) {
+                        case ARM_VFP_FPSID:
+                            /* VFP2 allows access to FSID from userspace.
+                               VFP3 restricts all id registers to privileged
+                               accesses.  */
+                            if (IS_USER(s)
+                                && arm_feature(env, ARM_FEATURE_VFP3))
+                                return 1;
+                            tmp = load_cpu_field(vfp.xregs[rn]);
+                            break;
+                        case ARM_VFP_FPEXC:
+                            if (IS_USER(s))
+                                return 1;
+                            tmp = load_cpu_field(vfp.xregs[rn]);
+                            break;
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            /* Not present in VFP3.  */
+                            if (IS_USER(s)
+                                || arm_feature(env, ARM_FEATURE_VFP3))
+                                return 1;
+                            tmp = load_cpu_field(vfp.xregs[rn]);
+                            break;
+                        case ARM_VFP_FPSCR:
+                            if (rd == 15) {
+                                tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
+                                tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
+                            } else {
+                                tmp = tcg_temp_new_i32();
+                                gen_helper_vfp_get_fpscr(tmp, cpu_env);
+                            }
+                            break;
+                        case ARM_VFP_MVFR0:
+                        case ARM_VFP_MVFR1:
+                            if (IS_USER(s)
+                                || !arm_feature(env, ARM_FEATURE_VFP3))
+                                return 1;
+                            tmp = load_cpu_field(vfp.xregs[rn]);
+                            break;
+                        default:
+                            return 1;
+                        }
+                    } else {
+                        gen_mov_F0_vreg(0, rn);
+                        tmp = gen_vfp_mrs();
+                    }
+                    if (rd == 15) {
+                        /* Set the 4 flag bits in the CPSR.  */
+                        gen_set_nzcv(tmp);
+                        tcg_temp_free_i32(tmp);
+                    } else {
+                        store_reg(s, rd, tmp);
+                    }
+                } else {
+                    /* arm->vfp */
+                    tmp = load_reg(s, rd);
+                    if (insn & (1 << 21)) {
+                        rn >>= 1;
+                        /* system register */
+                        switch (rn) {
+                        case ARM_VFP_FPSID:
+                        case ARM_VFP_MVFR0:
+                        case ARM_VFP_MVFR1:
+                            /* Writes are ignored.  */
+                            break;
+                        case ARM_VFP_FPSCR:
+                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
+                            tcg_temp_free_i32(tmp);
+                            gen_lookup_tb(s);
+                            break;
+                        case ARM_VFP_FPEXC:
+                            if (IS_USER(s))
+                                return 1;
+                            /* TODO: VFP subarchitecture support.
+                             * For now, keep the EN bit only */
+                            tcg_gen_andi_i32(tmp, tmp, 1 << 30);
+                            store_cpu_field(tmp, vfp.xregs[rn]);
+                            gen_lookup_tb(s);
+                            break;
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            store_cpu_field(tmp, vfp.xregs[rn]);
+                            break;
+                        default:
+                            return 1;
+                        }
+                    } else {
+                        gen_vfp_msr(tmp);
+                        gen_mov_vreg_F0(0, rn);
+                    }
+                }
+            }
+        } else {
+            /* data processing */
+            /* The opcode is in bits 23, 21, 20 and 6.  */
+            op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
+            if (dp) {
+                if (op == 15) {
+                    /* rn is opcode */
+                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
+                } else {
+                    /* rn is register number */
+                    VFP_DREG_N(rn, insn);
+                }
+
+                if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
+                    /* Integer or single precision destination.  */
+                    rd = VFP_SREG_D(insn);
+                } else {
+                    VFP_DREG_D(rd, insn);
+                }
+                if (op == 15 &&
+                    (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
+                    /* VCVT from int is always from S reg regardless of dp bit.
+                     * VCVT with immediate frac_bits has same format as SREG_M
+                     */
+                    rm = VFP_SREG_M(insn);
+                } else {
+                    VFP_DREG_M(rm, insn);
+                }
+            } else {
+                rn = VFP_SREG_N(insn);
+                if (op == 15 && rn == 15) {
+                    /* Double precision destination.  */
+                    VFP_DREG_D(rd, insn);
+                } else {
+                    rd = VFP_SREG_D(insn);
+                }
+                /* NB that we implicitly rely on the encoding for the frac_bits
+                 * in VCVT of fixed to float being the same as that of an SREG_M
+                 */
+                rm = VFP_SREG_M(insn);
+            }
+
+            veclen = s->vec_len;
+            if (op == 15 && rn > 3)
+                veclen = 0;
+
+            /* Shut up compiler warnings.  */
+            delta_m = 0;
+            delta_d = 0;
+            bank_mask = 0;
+
+            if (veclen > 0) {
+                if (dp)
+                    bank_mask = 0xc;
+                else
+                    bank_mask = 0x18;
+
+                /* Figure out what type of vector operation this is.  */
+                if ((rd & bank_mask) == 0) {
+                    /* scalar */
+                    veclen = 0;
+                } else {
+                    if (dp)
+                        delta_d = (s->vec_stride >> 1) + 1;
+                    else
+                        delta_d = s->vec_stride + 1;
+
+                    if ((rm & bank_mask) == 0) {
+                        /* mixed scalar/vector */
+                        delta_m = 0;
+                    } else {
+                        /* vector */
+                        delta_m = delta_d;
+                    }
+                }
+            }
+
+            /* Load the initial operands.  */
+            if (op == 15) {
+                switch (rn) {
+                case 16:
+                case 17:
+                    /* Integer source */
+                    gen_mov_F0_vreg(0, rm);
+                    break;
+                case 8:
+                case 9:
+                    /* Compare */
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_mov_F1_vreg(dp, rm);
+                    break;
+                case 10:
+                case 11:
+                    /* Compare with zero */
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_F1_ld0(dp);
+                    break;
+                case 20:
+                case 21:
+                case 22:
+                case 23:
+                case 28:
+                case 29:
+                case 30:
+                case 31:
+                    /* Source and destination the same.  */
+                    gen_mov_F0_vreg(dp, rd);
+                    break;
+                case 4:
+                case 5:
+                case 6:
+                case 7:
+                    /* VCVTB, VCVTT: only present with the halfprec extension,
+                     * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
+                     */
+                    if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
+                        return 1;
+                    }
+                    /* Otherwise fall through */
+                default:
+                    /* One source operand.  */
+                    gen_mov_F0_vreg(dp, rm);
+                    break;
+                }
+            } else {
+                /* Two source operands.  */
+                gen_mov_F0_vreg(dp, rn);
+                gen_mov_F1_vreg(dp, rm);
+            }
+
+            for (;;) {
+                /* Perform the calculation.  */
+                switch (op) {
+                case 0: /* VMLA: fd + (fn * fm) */
+                    /* Note that order of inputs to the add matters for NaNs */
+                    gen_vfp_F1_mul(dp);
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_add(dp);
+                    break;
+                case 1: /* VMLS: fd + -(fn * fm) */
+                    gen_vfp_mul(dp);
+                    gen_vfp_F1_neg(dp);
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_add(dp);
+                    break;
+                case 2: /* VNMLS: -fd + (fn * fm) */
+                    /* Note that it isn't valid to replace (-A + B) with (B - A)
+                     * or similar plausible looking simplifications
+                     * because this will give wrong results for NaNs.
+                     */
+                    gen_vfp_F1_mul(dp);
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_neg(dp);
+                    gen_vfp_add(dp);
+                    break;
+                case 3: /* VNMLA: -fd + -(fn * fm) */
+                    gen_vfp_mul(dp);
+                    gen_vfp_F1_neg(dp);
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_neg(dp);
+                    gen_vfp_add(dp);
+                    break;
+                case 4: /* mul: fn * fm */
+                    gen_vfp_mul(dp);
+                    break;
+                case 5: /* nmul: -(fn * fm) */
+                    gen_vfp_mul(dp);
+                    gen_vfp_neg(dp);
+                    break;
+                case 6: /* add: fn + fm */
+                    gen_vfp_add(dp);
+                    break;
+                case 7: /* sub: fn - fm */
+                    gen_vfp_sub(dp);
+                    break;
+                case 8: /* div: fn / fm */
+                    gen_vfp_div(dp);
+                    break;
+                case 14: /* fconst */
+                    if (!arm_feature(env, ARM_FEATURE_VFP3))
+                      return 1;
+
+                    n = (insn << 12) & 0x80000000;
+                    i = ((insn >> 12) & 0x70) | (insn & 0xf);
+                    if (dp) {
+                        if (i & 0x40)
+                            i |= 0x3f80;
+                        else
+                            i |= 0x4000;
+                        n |= i << 16;
+                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
+                    } else {
+                        if (i & 0x40)
+                            i |= 0x780;
+                        else
+                            i |= 0x800;
+                        n |= i << 19;
+                        tcg_gen_movi_i32(cpu_F0s, n);
+                    }
+                    break;
+                case 15: /* extension space */
+                    switch (rn) {
+                    case 0: /* cpy */
+                        /* no-op */
+                        break;
+                    case 1: /* abs */
+                        gen_vfp_abs(dp);
+                        break;
+                    case 2: /* neg */
+                        gen_vfp_neg(dp);
+                        break;
+                    case 3: /* sqrt */
+                        gen_vfp_sqrt(dp);
+                        break;
+                    case 4: /* vcvtb.f32.f16 */
+                        tmp = gen_vfp_mrs();
+                        tcg_gen_ext16u_i32(tmp, tmp);
+                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
+                        tcg_temp_free_i32(tmp);
+                        break;
+                    case 5: /* vcvtt.f32.f16 */
+                        tmp = gen_vfp_mrs();
+                        tcg_gen_shri_i32(tmp, tmp, 16);
+                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
+                        tcg_temp_free_i32(tmp);
+                        break;
+                    case 6: /* vcvtb.f16.f32 */
+                        tmp = tcg_temp_new_i32();
+                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                        gen_mov_F0_vreg(0, rd);
+                        tmp2 = gen_vfp_mrs();
+                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
+                        tcg_gen_or_i32(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        gen_vfp_msr(tmp);
+                        break;
+                    case 7: /* vcvtt.f16.f32 */
+                        tmp = tcg_temp_new_i32();
+                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                        tcg_gen_shli_i32(tmp, tmp, 16);
+                        gen_mov_F0_vreg(0, rd);
+                        tmp2 = gen_vfp_mrs();
+                        tcg_gen_ext16u_i32(tmp2, tmp2);
+                        tcg_gen_or_i32(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        gen_vfp_msr(tmp);
+                        break;
+                    case 8: /* cmp */
+                        gen_vfp_cmp(dp);
+                        break;
+                    case 9: /* cmpe */
+                        gen_vfp_cmpe(dp);
+                        break;
+                    case 10: /* cmpz */
+                        gen_vfp_cmp(dp);
+                        break;
+                    case 11: /* cmpez */
+                        gen_vfp_F1_ld0(dp);
+                        gen_vfp_cmpe(dp);
+                        break;
+                    case 15: /* single<->double conversion */
+                        if (dp)
+                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
+                        else
+                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
+                        break;
+                    case 16: /* fuito */
+                        gen_vfp_uito(dp, 0);
+                        break;
+                    case 17: /* fsito */
+                        gen_vfp_sito(dp, 0);
+                        break;
+                    case 20: /* fshto */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_shto(dp, 16 - rm, 0);
+                        break;
+                    case 21: /* fslto */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_slto(dp, 32 - rm, 0);
+                        break;
+                    case 22: /* fuhto */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_uhto(dp, 16 - rm, 0);
+                        break;
+                    case 23: /* fulto */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_ulto(dp, 32 - rm, 0);
+                        break;
+                    case 24: /* ftoui */
+                        gen_vfp_toui(dp, 0);
+                        break;
+                    case 25: /* ftouiz */
+                        gen_vfp_touiz(dp, 0);
+                        break;
+                    case 26: /* ftosi */
+                        gen_vfp_tosi(dp, 0);
+                        break;
+                    case 27: /* ftosiz */
+                        gen_vfp_tosiz(dp, 0);
+                        break;
+                    case 28: /* ftosh */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_tosh(dp, 16 - rm, 0);
+                        break;
+                    case 29: /* ftosl */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_tosl(dp, 32 - rm, 0);
+                        break;
+                    case 30: /* ftouh */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_touh(dp, 16 - rm, 0);
+                        break;
+                    case 31: /* ftoul */
+                        if (!arm_feature(env, ARM_FEATURE_VFP3))
+                          return 1;
+                        gen_vfp_toul(dp, 32 - rm, 0);
+                        break;
+                    default: /* undefined */
+                        printf ("rn:%d\n", rn);
+                        return 1;
+                    }
+                    break;
+                default: /* undefined */
+                    printf ("op:%d\n", op);
+                    return 1;
+                }
+
+                /* Write back the result.  */
+                if (op == 15 && (rn >= 8 && rn <= 11))
+                    ; /* Comparison, do nothing.  */
+                else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
+                    /* VCVT double to int: always integer result. */
+                    gen_mov_vreg_F0(0, rd);
+                else if (op == 15 && rn == 15)
+                    /* conversion */
+                    gen_mov_vreg_F0(!dp, rd);
+                else
+                    gen_mov_vreg_F0(dp, rd);
+
+                /* break out of the loop if we have finished  */
+                if (veclen == 0)
+                    break;
+
+                if (op == 15 && delta_m == 0) {
+                    /* single source one-many */
+                    while (veclen--) {
+                        rd = ((rd + delta_d) & (bank_mask - 1))
+                             | (rd & bank_mask);
+                        gen_mov_vreg_F0(dp, rd);
+                    }
+                    break;
+                }
+                /* Setup the next operands.  */
+                veclen--;
+                rd = ((rd + delta_d) & (bank_mask - 1))
+                     | (rd & bank_mask);
+
+                if (op == 15) {
+                    /* One source operand.  */
+                    rm = ((rm + delta_m) & (bank_mask - 1))
+                         | (rm & bank_mask);
+                    gen_mov_F0_vreg(dp, rm);
+                } else {
+                    /* Two source operands.  */
+                    rn = ((rn + delta_d) & (bank_mask - 1))
+                         | (rn & bank_mask);
+                    gen_mov_F0_vreg(dp, rn);
+                    if (delta_m) {
+                        rm = ((rm + delta_m) & (bank_mask - 1))
+                             | (rm & bank_mask);
+                        gen_mov_F1_vreg(dp, rm);
+                    }
+                }
+            }
+        }
+        break;
+    case 0xc:
+    case 0xd:
+        if ((insn & 0x03e00000) == 0x00400000) {
+            /* two-register transfer */
+            rn = (insn >> 16) & 0xf;
+            rd = (insn >> 12) & 0xf;
+            if (dp) {
+                VFP_DREG_M(rm, insn);
+            } else {
+                rm = VFP_SREG_M(insn);
+            }
+
+            if (insn & ARM_CP_RW_BIT) {
+                /* vfp->arm */
+                if (dp) {
+                    gen_mov_F0_vreg(0, rm * 2);
+                    tmp = gen_vfp_mrs();
+                    store_reg(s, rd, tmp);
+                    gen_mov_F0_vreg(0, rm * 2 + 1);
+                    tmp = gen_vfp_mrs();
+                    store_reg(s, rn, tmp);
+                } else {
+                    gen_mov_F0_vreg(0, rm);
+                    tmp = gen_vfp_mrs();
+                    store_reg(s, rd, tmp);
+                    gen_mov_F0_vreg(0, rm + 1);
+                    tmp = gen_vfp_mrs();
+                    store_reg(s, rn, tmp);
+                }
+            } else {
+                /* arm->vfp */
+                if (dp) {
+                    tmp = load_reg(s, rd);
+                    gen_vfp_msr(tmp);
+                    gen_mov_vreg_F0(0, rm * 2);
+                    tmp = load_reg(s, rn);
+                    gen_vfp_msr(tmp);
+                    gen_mov_vreg_F0(0, rm * 2 + 1);
+                } else {
+                    tmp = load_reg(s, rd);
+                    gen_vfp_msr(tmp);
+                    gen_mov_vreg_F0(0, rm);
+                    tmp = load_reg(s, rn);
+                    gen_vfp_msr(tmp);
+                    gen_mov_vreg_F0(0, rm + 1);
+                }
+            }
+        } else {
+            /* Load/store */
+            rn = (insn >> 16) & 0xf;
+            if (dp)
+                VFP_DREG_D(rd, insn);
+            else
+                rd = VFP_SREG_D(insn);
+            if ((insn & 0x01200000) == 0x01000000) {
+                /* Single load/store */
+                offset = (insn & 0xff) << 2;
+                if ((insn & (1 << 23)) == 0)
+                    offset = -offset;
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
+                tcg_gen_addi_i32(addr, addr, offset);
+                if (insn & (1 << 20)) {
+                    gen_vfp_ld(s, dp, addr);
+                    gen_mov_vreg_F0(dp, rd);
+                } else {
+                    gen_mov_F0_vreg(dp, rd);
+                    gen_vfp_st(s, dp, addr);
+                }
+                tcg_temp_free_i32(addr);
+            } else {
+                /* load/store multiple */
+                int w = insn & (1 << 21);
+                if (dp)
+                    n = (insn >> 1) & 0x7f;
+                else
+                    n = insn & 0xff;
+
+                if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
+                    /* P == U , W == 1  => UNDEF */
+                    return 1;
+                }
+                if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
+                    /* UNPREDICTABLE cases for bad immediates: we choose to
+                     * UNDEF to avoid generating huge numbers of TCG ops
+                     */
+                    return 1;
+                }
+                if (rn == 15 && w) {
+                    /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
+                    return 1;
+                }
+
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
+                if (insn & (1 << 24)) /* pre-decrement */
+                    tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
+
+                if (dp)
+                    offset = 8;
+                else
+                    offset = 4;
+                for (i = 0; i < n; i++) {
+                    if (insn & ARM_CP_RW_BIT) {
+                        /* load */
+                        gen_vfp_ld(s, dp, addr);
+                        gen_mov_vreg_F0(dp, rd + i);
+                    } else {
+                        /* store */
+                        gen_mov_F0_vreg(dp, rd + i);
+                        gen_vfp_st(s, dp, addr);
+                    }
+                    tcg_gen_addi_i32(addr, addr, offset);
+                }
+                if (w) {
+                    /* writeback */
+                    if (insn & (1 << 24))
+                        offset = -offset * n;
+                    else if (dp && (insn & 1))
+                        offset = 4;
+                    else
+                        offset = 0;
+
+                    if (offset != 0)
+                        tcg_gen_addi_i32(addr, addr, offset);
+                    store_reg(s, rn, addr);
+                } else {
+                    tcg_temp_free_i32(addr);
+                }
+            }
+        }
+        break;
+    default:
+        /* Should never happen.  */
+        return 1;
+    }
+    return 0;
+}
+
+static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        tcg_gen_goto_tb(n);
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void gen_jmp (DisasContext *s, uint32_t dest)
+{
+    if (unlikely(s->singlestep_enabled)) {
+        /* An indirect jump so that we still trigger the debug exception.  */
+        if (s->thumb)
+            dest |= 1;
+        gen_bx_im(s, dest);
+    } else {
+        gen_goto_tb(s, 0, dest);
+        s->is_jmp = DISAS_TB_JUMP;
+    }
+}
+
+static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
+{
+    if (x)
+        tcg_gen_sari_i32(t0, t0, 16);
+    else
+        gen_sxth(t0);
+    if (y)
+        tcg_gen_sari_i32(t1, t1, 16);
+    else
+        gen_sxth(t1);
+    tcg_gen_mul_i32(t0, t0, t1);
+}
+
+/* Return the mask of PSR bits set by a MSR instruction.  */
+static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
+    uint32_t mask;
+
+    mask = 0;
+    if (flags & (1 << 0))
+        mask |= 0xff;
+    if (flags & (1 << 1))
+        mask |= 0xff00;
+    if (flags & (1 << 2))
+        mask |= 0xff0000;
+    if (flags & (1 << 3))
+        mask |= 0xff000000;
+
+    /* Mask out undefined bits.  */
+    mask &= ~CPSR_RESERVED;
+    if (!arm_feature(env, ARM_FEATURE_V4T))
+        mask &= ~CPSR_T;
+    if (!arm_feature(env, ARM_FEATURE_V5))
+        mask &= ~CPSR_Q; /* V5TE in reality*/
+    if (!arm_feature(env, ARM_FEATURE_V6))
+        mask &= ~(CPSR_E | CPSR_GE);
+    if (!arm_feature(env, ARM_FEATURE_THUMB2))
+        mask &= ~CPSR_IT;
+    /* Mask out execution state bits.  */
+    if (!spsr)
+        mask &= ~CPSR_EXEC;
+    /* Mask out privileged bits.  */
+    if (IS_USER(s))
+        mask &= CPSR_USER;
+    return mask;
+}
+
+/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
+static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
+{
+    TCGv tmp;
+    if (spsr) {
+        /* ??? This is also undefined in system mode.  */
+        if (IS_USER(s))
+            return 1;
+
+        tmp = load_cpu_field(spsr);
+        tcg_gen_andi_i32(tmp, tmp, ~mask);
+        tcg_gen_andi_i32(t0, t0, mask);
+        tcg_gen_or_i32(tmp, tmp, t0);
+        store_cpu_field(tmp, spsr);
+    } else {
+        gen_set_cpsr(t0, mask);
+    }
+    tcg_temp_free_i32(t0);
+    gen_lookup_tb(s);
+    return 0;
+}
+
+/* Returns nonzero if access to the PSR is not permitted.  */
+static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
+{
+    TCGv tmp;
+    tmp = tcg_temp_new_i32();
+    tcg_gen_movi_i32(tmp, val);
+    return gen_set_psr(s, mask, spsr, tmp);
+}
+
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
+{
+    TCGv tmp;
+    store_reg(s, 15, pc);
+    tmp = load_cpu_field(spsr);
+    gen_set_cpsr(tmp, 0xffffffff);
+    tcg_temp_free_i32(tmp);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+/* Generate a v6 exception return.  Marks both values as dead.  */
+static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
+{
+    gen_set_cpsr(cpsr, 0xffffffff);
+    tcg_temp_free_i32(cpsr);
+    store_reg(s, 15, pc);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static inline void
+gen_set_condexec (DisasContext *s)
+{
+    if (s->condexec_mask) {
+        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
+        TCGv tmp = tcg_temp_new_i32();
+        tcg_gen_movi_i32(tmp, val);
+        store_cpu_field(tmp, condexec_bits);
+    }
+}
+
+static void gen_exception_insn(DisasContext *s, int offset, int excp)
+{
+    gen_set_condexec(s);
+    gen_set_pc_im(s->pc - offset);
+    gen_exception(excp);
+    s->is_jmp = DISAS_JUMP;
+}
+
+static void gen_nop_hint(DisasContext *s, int val)
+{
+    switch (val) {
+    case 3: /* wfi */
+        gen_set_pc_im(s->pc);
+        s->is_jmp = DISAS_WFI;
+        break;
+    case 2: /* wfe */
+    case 4: /* sev */
+        /* TODO: Implement SEV and WFE.  May help SMP performance.  */
+    default: /* nop */
+        break;
+    }
+}
+
+#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
+
+static inline void gen_neon_add(int size, TCGv t0, TCGv t1)
+{
+    switch (size) {
+    case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
+    case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
+    case 2: tcg_gen_add_i32(t0, t0, t1); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
+{
+    switch (size) {
+    case 0: gen_helper_neon_sub_u8(t0, t1, t0); break;
+    case 1: gen_helper_neon_sub_u16(t0, t1, t0); break;
+    case 2: tcg_gen_sub_i32(t0, t1, t0); break;
+    default: return;
+    }
+}
+
+/* 32-bit pairwise ops end up the same as the elementwise versions.  */
+#define gen_helper_neon_pmax_s32  gen_helper_neon_max_s32
+#define gen_helper_neon_pmax_u32  gen_helper_neon_max_u32
+#define gen_helper_neon_pmin_s32  gen_helper_neon_min_s32
+#define gen_helper_neon_pmin_u32  gen_helper_neon_min_u32
+
+#define GEN_NEON_INTEGER_OP_ENV(name) do { \
+    switch ((size << 1) | u) { \
+    case 0: \
+        gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    case 1: \
+        gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    case 2: \
+        gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    case 3: \
+        gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    case 4: \
+        gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    case 5: \
+        gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
+        break; \
+    default: return 1; \
+    }} while (0)
+
+#define GEN_NEON_INTEGER_OP(name) do { \
+    switch ((size << 1) | u) { \
+    case 0: \
+        gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
+        break; \
+    case 1: \
+        gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
+        break; \
+    case 2: \
+        gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
+        break; \
+    case 3: \
+        gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
+        break; \
+    case 4: \
+        gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
+        break; \
+    case 5: \
+        gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
+        break; \
+    default: return 1; \
+    }} while (0)
+
+static TCGv neon_load_scratch(int scratch)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
+    return tmp;
+}
+
+static void neon_store_scratch(int scratch, TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
+    tcg_temp_free_i32(var);
+}
+
+static inline TCGv neon_get_scalar(int size, int reg)
+{
+    TCGv tmp;
+    if (size == 1) {
+        tmp = neon_load_reg(reg & 7, reg >> 4);
+        if (reg & 8) {
+            gen_neon_dup_high16(tmp);
+        } else {
+            gen_neon_dup_low16(tmp);
+        }
+    } else {
+        tmp = neon_load_reg(reg & 15, reg >> 4);
+    }
+    return tmp;
+}
+
+static int gen_neon_unzip(int rd, int rm, int size, int q)
+{
+    TCGv tmp, tmp2;
+    if (!q && size == 2) {
+        return 1;
+    }
+    tmp = tcg_const_i32(rd);
+    tmp2 = tcg_const_i32(rm);
+    if (q) {
+        switch (size) {
+        case 0:
+            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
+            break;
+        case 2:
+            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    } else {
+        switch (size) {
+        case 0:
+            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    }
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(tmp2);
+    return 0;
+}
+
+static int gen_neon_zip(int rd, int rm, int size, int q)
+{
+    TCGv tmp, tmp2;
+    if (!q && size == 2) {
+        return 1;
+    }
+    tmp = tcg_const_i32(rd);
+    tmp2 = tcg_const_i32(rm);
+    if (q) {
+        switch (size) {
+        case 0:
+            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
+            break;
+        case 2:
+            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    } else {
+        switch (size) {
+        case 0:
+            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
+            break;
+        case 1:
+            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
+            break;
+        default:
+            abort();
+        }
+    }
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(tmp2);
+    return 0;
+}
+
+static void gen_neon_trn_u8(TCGv t0, TCGv t1)
+{
+    TCGv rd, tmp;
+
+    rd = tcg_temp_new_i32();
+    tmp = tcg_temp_new_i32();
+
+    tcg_gen_shli_i32(rd, t0, 8);
+    tcg_gen_andi_i32(rd, rd, 0xff00ff00);
+    tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
+    tcg_gen_or_i32(rd, rd, tmp);
+
+    tcg_gen_shri_i32(t1, t1, 8);
+    tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
+    tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
+    tcg_gen_or_i32(t1, t1, tmp);
+    tcg_gen_mov_i32(t0, rd);
+
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(rd);
+}
+
+static void gen_neon_trn_u16(TCGv t0, TCGv t1)
+{
+    TCGv rd, tmp;
+
+    rd = tcg_temp_new_i32();
+    tmp = tcg_temp_new_i32();
+
+    tcg_gen_shli_i32(rd, t0, 16);
+    tcg_gen_andi_i32(tmp, t1, 0xffff);
+    tcg_gen_or_i32(rd, rd, tmp);
+    tcg_gen_shri_i32(t1, t1, 16);
+    tcg_gen_andi_i32(tmp, t0, 0xffff0000);
+    tcg_gen_or_i32(t1, t1, tmp);
+    tcg_gen_mov_i32(t0, rd);
+
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(rd);
+}
+
+
+static struct {
+    int nregs;
+    int interleave;
+    int spacing;
+} neon_ls_element_type[11] = {
+    {4, 4, 1},
+    {4, 4, 2},
+    {4, 1, 1},
+    {4, 2, 1},
+    {3, 3, 1},
+    {3, 3, 2},
+    {3, 1, 1},
+    {1, 1, 1},
+    {2, 2, 1},
+    {2, 2, 2},
+    {2, 1, 1}
+};
+
+/* Translate a NEON load/store element instruction.  Return nonzero if the
+   instruction is invalid.  */
+static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int rd, rn, rm;
+    int op;
+    int nregs;
+    int interleave;
+    int spacing;
+    int stride;
+    int size;
+    int reg;
+    int pass;
+    int load;
+    int shift;
+    int n;
+    TCGv addr;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv_i64 tmp64;
+
+    if (!s->vfp_enabled)
+      return 1;
+    VFP_DREG_D(rd, insn);
+    rn = (insn >> 16) & 0xf;
+    rm = insn & 0xf;
+    load = (insn & (1 << 21)) != 0;
+    if ((insn & (1 << 23)) == 0) {
+        /* Load store all elements.  */
+        op = (insn >> 8) & 0xf;
+        size = (insn >> 6) & 3;
+        if (op > 10)
+            return 1;
+        /* Catch UNDEF cases for bad values of align field */
+        switch (op & 0xc) {
+        case 4:
+            if (((insn >> 5) & 1) == 1) {
+                return 1;
+            }
+            break;
+        case 8:
+            if (((insn >> 4) & 3) == 3) {
+                return 1;
+            }
+            break;
+        default:
+            break;
+        }
+        nregs = neon_ls_element_type[op].nregs;
+        interleave = neon_ls_element_type[op].interleave;
+        spacing = neon_ls_element_type[op].spacing;
+        if (size == 3 && (interleave | spacing) != 1)
+            return 1;
+        addr = tcg_temp_new_i32();
+        load_reg_var(s, addr, rn);
+        stride = (1 << size) * interleave;
+        for (reg = 0; reg < nregs; reg++) {
+            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
+                load_reg_var(s, addr, rn);
+                tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
+            } else if (interleave == 2 && nregs == 4 && reg == 2) {
+                load_reg_var(s, addr, rn);
+                tcg_gen_addi_i32(addr, addr, 1 << size);
+            }
+            if (size == 3) {
+                if (load) {
+                    tmp64 = gen_ld64(addr, IS_USER(s));
+                    neon_store_reg64(tmp64, rd);
+                    tcg_temp_free_i64(tmp64);
+                } else {
+                    tmp64 = tcg_temp_new_i64();
+                    neon_load_reg64(tmp64, rd);
+                    gen_st64(tmp64, addr, IS_USER(s));
+                }
+                tcg_gen_addi_i32(addr, addr, stride);
+            } else {
+                for (pass = 0; pass < 2; pass++) {
+                    if (size == 2) {
+                        if (load) {
+                            tmp = gen_ld32(addr, IS_USER(s));
+                            neon_store_reg(rd, pass, tmp);
+                        } else {
+                            tmp = neon_load_reg(rd, pass);
+                            gen_st32(tmp, addr, IS_USER(s));
+                        }
+                        tcg_gen_addi_i32(addr, addr, stride);
+                    } else if (size == 1) {
+                        if (load) {
+                            tmp = gen_ld16u(addr, IS_USER(s));
+                            tcg_gen_addi_i32(addr, addr, stride);
+                            tmp2 = gen_ld16u(addr, IS_USER(s));
+                            tcg_gen_addi_i32(addr, addr, stride);
+                            tcg_gen_shli_i32(tmp2, tmp2, 16);
+                            tcg_gen_or_i32(tmp, tmp, tmp2);
+                            tcg_temp_free_i32(tmp2);
+                            neon_store_reg(rd, pass, tmp);
+                        } else {
+                            tmp = neon_load_reg(rd, pass);
+                            tmp2 = tcg_temp_new_i32();
+                            tcg_gen_shri_i32(tmp2, tmp, 16);
+                            gen_st16(tmp, addr, IS_USER(s));
+                            tcg_gen_addi_i32(addr, addr, stride);
+                            gen_st16(tmp2, addr, IS_USER(s));
+                            tcg_gen_addi_i32(addr, addr, stride);
+                        }
+                    } else /* size == 0 */ {
+                        if (load) {
+                            TCGV_UNUSED(tmp2);
+                            for (n = 0; n < 4; n++) {
+                                tmp = gen_ld8u(addr, IS_USER(s));
+                                tcg_gen_addi_i32(addr, addr, stride);
+                                if (n == 0) {
+                                    tmp2 = tmp;
+                                } else {
+                                    tcg_gen_shli_i32(tmp, tmp, n * 8);
+                                    tcg_gen_or_i32(tmp2, tmp2, tmp);
+                                    tcg_temp_free_i32(tmp);
+                                }
+                            }
+                            neon_store_reg(rd, pass, tmp2);
+                        } else {
+                            tmp2 = neon_load_reg(rd, pass);
+                            for (n = 0; n < 4; n++) {
+                                tmp = tcg_temp_new_i32();
+                                if (n == 0) {
+                                    tcg_gen_mov_i32(tmp, tmp2);
+                                } else {
+                                    tcg_gen_shri_i32(tmp, tmp2, n * 8);
+                                }
+                                gen_st8(tmp, addr, IS_USER(s));
+                                tcg_gen_addi_i32(addr, addr, stride);
+                            }
+                            tcg_temp_free_i32(tmp2);
+                        }
+                    }
+                }
+            }
+            rd += spacing;
+        }
+        tcg_temp_free_i32(addr);
+        stride = nregs * 8;
+    } else {
+        size = (insn >> 10) & 3;
+        if (size == 3) {
+            /* Load single element to all lanes.  */
+            int a = (insn >> 4) & 1;
+            if (!load) {
+                return 1;
+            }
+            size = (insn >> 6) & 3;
+            nregs = ((insn >> 8) & 3) + 1;
+
+            if (size == 3) {
+                if (nregs != 4 || a == 0) {
+                    return 1;
+                }
+                /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
+                size = 2;
+            }
+            if (nregs == 1 && a == 1 && size == 0) {
+                return 1;
+            }
+            if (nregs == 3 && a == 1) {
+                return 1;
+            }
+            addr = tcg_temp_new_i32();
+            load_reg_var(s, addr, rn);
+            if (nregs == 1) {
+                /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */
+                tmp = gen_load_and_replicate(s, addr, size);
+                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
+                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
+                if (insn & (1 << 5)) {
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
+                }
+                tcg_temp_free_i32(tmp);
+            } else {
+                /* VLD2/3/4 to all lanes: bit 5 indicates register stride */
+                stride = (insn & (1 << 5)) ? 2 : 1;
+                for (reg = 0; reg < nregs; reg++) {
+                    tmp = gen_load_and_replicate(s, addr, size);
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
+                    tcg_temp_free_i32(tmp);
+                    tcg_gen_addi_i32(addr, addr, 1 << size);
+                    rd += stride;
+                }
+            }
+            tcg_temp_free_i32(addr);
+            stride = (1 << size) * nregs;
+        } else {
+            /* Single element.  */
+            int idx = (insn >> 4) & 0xf;
+            pass = (insn >> 7) & 1;
+            switch (size) {
+            case 0:
+                shift = ((insn >> 5) & 3) * 8;
+                stride = 1;
+                break;
+            case 1:
+                shift = ((insn >> 6) & 1) * 16;
+                stride = (insn & (1 << 5)) ? 2 : 1;
+                break;
+            case 2:
+                shift = 0;
+                stride = (insn & (1 << 6)) ? 2 : 1;
+                break;
+            default:
+                abort();
+            }
+            nregs = ((insn >> 8) & 3) + 1;
+            /* Catch the UNDEF cases. This is unavoidably a bit messy. */
+            switch (nregs) {
+            case 1:
+                if (((idx & (1 << size)) != 0) ||
+                    (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
+                    return 1;
+                }
+                break;
+            case 3:
+                if ((idx & 1) != 0) {
+                    return 1;
+                }
+                /* fall through */
+            case 2:
+                if (size == 2 && (idx & 2) != 0) {
+                    return 1;
+                }
+                break;
+            case 4:
+                if ((size == 2) && ((idx & 3) == 3)) {
+                    return 1;
+                }
+                break;
+            default:
+                abort();
+            }
+            if ((rd + stride * (nregs - 1)) > 31) {
+                /* Attempts to write off the end of the register file
+                 * are UNPREDICTABLE; we choose to UNDEF because otherwise
+                 * the neon_load_reg() would write off the end of the array.
+                 */
+                return 1;
+            }
+            addr = tcg_temp_new_i32();
+            load_reg_var(s, addr, rn);
+            for (reg = 0; reg < nregs; reg++) {
+                if (load) {
+                    switch (size) {
+                    case 0:
+                        tmp = gen_ld8u(addr, IS_USER(s));
+                        break;
+                    case 1:
+                        tmp = gen_ld16u(addr, IS_USER(s));
+                        break;
+                    case 2:
+                        tmp = gen_ld32(addr, IS_USER(s));
+                        break;
+                    default: /* Avoid compiler warnings.  */
+                        abort();
+                    }
+                    if (size != 2) {
+                        tmp2 = neon_load_reg(rd, pass);
+                        gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
+                        tcg_temp_free_i32(tmp2);
+                    }
+                    neon_store_reg(rd, pass, tmp);
+                } else { /* Store */
+                    tmp = neon_load_reg(rd, pass);
+                    if (shift)
+                        tcg_gen_shri_i32(tmp, tmp, shift);
+                    switch (size) {
+                    case 0:
+                        gen_st8(tmp, addr, IS_USER(s));
+                        break;
+                    case 1:
+                        gen_st16(tmp, addr, IS_USER(s));
+                        break;
+                    case 2:
+                        gen_st32(tmp, addr, IS_USER(s));
+                        break;
+                    }
+                }
+                rd += stride;
+                tcg_gen_addi_i32(addr, addr, 1 << size);
+            }
+            tcg_temp_free_i32(addr);
+            stride = nregs * (1 << size);
+        }
+    }
+    if (rm != 15) {
+        TCGv base;
+
+        base = load_reg(s, rn);
+        if (rm == 13) {
+            tcg_gen_addi_i32(base, base, stride);
+        } else {
+            TCGv index;
+            index = load_reg(s, rm);
+            tcg_gen_add_i32(base, base, index);
+            tcg_temp_free_i32(index);
+        }
+        store_reg(s, rn, base);
+    }
+    return 0;
+}
+
+/* Bitwise select.  dest = c ? t : f.  Clobbers T and F.  */
+static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c)
+{
+    tcg_gen_and_i32(t, t, c);
+    tcg_gen_andc_i32(f, f, c);
+    tcg_gen_or_i32(dest, t, f);
+}
+
+static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
+{
+    switch (size) {
+    case 0: gen_helper_neon_narrow_u8(dest, src); break;
+    case 1: gen_helper_neon_narrow_u16(dest, src); break;
+    case 2: tcg_gen_trunc_i64_i32(dest, src); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
+{
+    switch (size) {
+    case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
+    case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
+    case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
+{
+    switch (size) {
+    case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
+    case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
+    case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
+{
+    switch (size) {
+    case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
+    case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
+    case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
+                                         int q, int u)
+{
+    if (q) {
+        if (u) {
+            switch (size) {
+            case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
+            case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
+            default: abort();
+            }
+        } else {
+            switch (size) {
+            case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
+            case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
+            default: abort();
+            }
+        }
+    } else {
+        if (u) {
+            switch (size) {
+            case 1: gen_helper_neon_shl_u16(var, var, shift); break;
+            case 2: gen_helper_neon_shl_u32(var, var, shift); break;
+            default: abort();
+            }
+        } else {
+            switch (size) {
+            case 1: gen_helper_neon_shl_s16(var, var, shift); break;
+            case 2: gen_helper_neon_shl_s32(var, var, shift); break;
+            default: abort();
+            }
+        }
+    }
+}
+
+static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
+{
+    if (u) {
+        switch (size) {
+        case 0: gen_helper_neon_widen_u8(dest, src); break;
+        case 1: gen_helper_neon_widen_u16(dest, src); break;
+        case 2: tcg_gen_extu_i32_i64(dest, src); break;
+        default: abort();
+        }
+    } else {
+        switch (size) {
+        case 0: gen_helper_neon_widen_s8(dest, src); break;
+        case 1: gen_helper_neon_widen_s16(dest, src); break;
+        case 2: tcg_gen_ext_i32_i64(dest, src); break;
+        default: abort();
+        }
+    }
+    tcg_temp_free_i32(src);
+}
+
+static inline void gen_neon_addl(int size)
+{
+    switch (size) {
+    case 0: gen_helper_neon_addl_u16(CPU_V001); break;
+    case 1: gen_helper_neon_addl_u32(CPU_V001); break;
+    case 2: tcg_gen_add_i64(CPU_V001); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_subl(int size)
+{
+    switch (size) {
+    case 0: gen_helper_neon_subl_u16(CPU_V001); break;
+    case 1: gen_helper_neon_subl_u32(CPU_V001); break;
+    case 2: tcg_gen_sub_i64(CPU_V001); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_negl(TCGv_i64 var, int size)
+{
+    switch (size) {
+    case 0: gen_helper_neon_negl_u16(var, var); break;
+    case 1: gen_helper_neon_negl_u32(var, var); break;
+    case 2: gen_helper_neon_negl_u64(var, var); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
+{
+    switch (size) {
+    case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
+    case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
+    default: abort();
+    }
+}
+
+static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
+{
+    TCGv_i64 tmp;
+
+    switch ((size << 1) | u) {
+    case 0: gen_helper_neon_mull_s8(dest, a, b); break;
+    case 1: gen_helper_neon_mull_u8(dest, a, b); break;
+    case 2: gen_helper_neon_mull_s16(dest, a, b); break;
+    case 3: gen_helper_neon_mull_u16(dest, a, b); break;
+    case 4:
+        tmp = gen_muls_i64_i32(a, b);
+        tcg_gen_mov_i64(dest, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 5:
+        tmp = gen_mulu_i64_i32(a, b);
+        tcg_gen_mov_i64(dest, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    default: abort();
+    }
+
+    /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
+       Don't forget to clean them now.  */
+    if (size < 2) {
+        tcg_temp_free_i32(a);
+        tcg_temp_free_i32(b);
+    }
+}
+
+static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
+{
+    if (op) {
+        if (u) {
+            gen_neon_unarrow_sats(size, dest, src);
+        } else {
+            gen_neon_narrow(size, dest, src);
+        }
+    } else {
+        if (u) {
+            gen_neon_narrow_satu(size, dest, src);
+        } else {
+            gen_neon_narrow_sats(size, dest, src);
+        }
+    }
+}
+
+/* Symbolic constants for op fields for Neon 3-register same-length.
+ * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
+ * table A7-9.
+ */
+#define NEON_3R_VHADD 0
+#define NEON_3R_VQADD 1
+#define NEON_3R_VRHADD 2
+#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
+#define NEON_3R_VHSUB 4
+#define NEON_3R_VQSUB 5
+#define NEON_3R_VCGT 6
+#define NEON_3R_VCGE 7
+#define NEON_3R_VSHL 8
+#define NEON_3R_VQSHL 9
+#define NEON_3R_VRSHL 10
+#define NEON_3R_VQRSHL 11
+#define NEON_3R_VMAX 12
+#define NEON_3R_VMIN 13
+#define NEON_3R_VABD 14
+#define NEON_3R_VABA 15
+#define NEON_3R_VADD_VSUB 16
+#define NEON_3R_VTST_VCEQ 17
+#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
+#define NEON_3R_VMUL 19
+#define NEON_3R_VPMAX 20
+#define NEON_3R_VPMIN 21
+#define NEON_3R_VQDMULH_VQRDMULH 22
+#define NEON_3R_VPADD 23
+#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
+#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
+#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
+#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
+#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
+#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */
+
+static const uint8_t neon_3r_sizes[] = {
+    [NEON_3R_VHADD] = 0x7,
+    [NEON_3R_VQADD] = 0xf,
+    [NEON_3R_VRHADD] = 0x7,
+    [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
+    [NEON_3R_VHSUB] = 0x7,
+    [NEON_3R_VQSUB] = 0xf,
+    [NEON_3R_VCGT] = 0x7,
+    [NEON_3R_VCGE] = 0x7,
+    [NEON_3R_VSHL] = 0xf,
+    [NEON_3R_VQSHL] = 0xf,
+    [NEON_3R_VRSHL] = 0xf,
+    [NEON_3R_VQRSHL] = 0xf,
+    [NEON_3R_VMAX] = 0x7,
+    [NEON_3R_VMIN] = 0x7,
+    [NEON_3R_VABD] = 0x7,
+    [NEON_3R_VABA] = 0x7,
+    [NEON_3R_VADD_VSUB] = 0xf,
+    [NEON_3R_VTST_VCEQ] = 0x7,
+    [NEON_3R_VML] = 0x7,
+    [NEON_3R_VMUL] = 0x7,
+    [NEON_3R_VPMAX] = 0x7,
+    [NEON_3R_VPMIN] = 0x7,
+    [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
+    [NEON_3R_VPADD] = 0x7,
+    [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
+};
+
+/* Symbolic constants for op fields for Neon 2-register miscellaneous.
+ * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
+ * table A7-13.
+ */
+#define NEON_2RM_VREV64 0
+#define NEON_2RM_VREV32 1
+#define NEON_2RM_VREV16 2
+#define NEON_2RM_VPADDL 4
+#define NEON_2RM_VPADDL_U 5
+#define NEON_2RM_VCLS 8
+#define NEON_2RM_VCLZ 9
+#define NEON_2RM_VCNT 10
+#define NEON_2RM_VMVN 11
+#define NEON_2RM_VPADAL 12
+#define NEON_2RM_VPADAL_U 13
+#define NEON_2RM_VQABS 14
+#define NEON_2RM_VQNEG 15
+#define NEON_2RM_VCGT0 16
+#define NEON_2RM_VCGE0 17
+#define NEON_2RM_VCEQ0 18
+#define NEON_2RM_VCLE0 19
+#define NEON_2RM_VCLT0 20
+#define NEON_2RM_VABS 22
+#define NEON_2RM_VNEG 23
+#define NEON_2RM_VCGT0_F 24
+#define NEON_2RM_VCGE0_F 25
+#define NEON_2RM_VCEQ0_F 26
+#define NEON_2RM_VCLE0_F 27
+#define NEON_2RM_VCLT0_F 28
+#define NEON_2RM_VABS_F 30
+#define NEON_2RM_VNEG_F 31
+#define NEON_2RM_VSWP 32
+#define NEON_2RM_VTRN 33
+#define NEON_2RM_VUZP 34
+#define NEON_2RM_VZIP 35
+#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
+#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
+#define NEON_2RM_VSHLL 38
+#define NEON_2RM_VCVT_F16_F32 44
+#define NEON_2RM_VCVT_F32_F16 46
+#define NEON_2RM_VRECPE 56
+#define NEON_2RM_VRSQRTE 57
+#define NEON_2RM_VRECPE_F 58
+#define NEON_2RM_VRSQRTE_F 59
+#define NEON_2RM_VCVT_FS 60
+#define NEON_2RM_VCVT_FU 61
+#define NEON_2RM_VCVT_SF 62
+#define NEON_2RM_VCVT_UF 63
+
+static int neon_2rm_is_float_op(int op)
+{
+    /* Return true if this neon 2reg-misc op is float-to-float */
+    return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
+            op >= NEON_2RM_VRECPE_F);
+}
+
+/* Each entry in this array has bit n set if the insn allows
+ * size value n (otherwise it will UNDEF). Since unallocated
+ * op values will have no bits set they always UNDEF.
+ */
+static const uint8_t neon_2rm_sizes[] = {
+    [NEON_2RM_VREV64] = 0x7,
+    [NEON_2RM_VREV32] = 0x3,
+    [NEON_2RM_VREV16] = 0x1,
+    [NEON_2RM_VPADDL] = 0x7,
+    [NEON_2RM_VPADDL_U] = 0x7,
+    [NEON_2RM_VCLS] = 0x7,
+    [NEON_2RM_VCLZ] = 0x7,
+    [NEON_2RM_VCNT] = 0x1,
+    [NEON_2RM_VMVN] = 0x1,
+    [NEON_2RM_VPADAL] = 0x7,
+    [NEON_2RM_VPADAL_U] = 0x7,
+    [NEON_2RM_VQABS] = 0x7,
+    [NEON_2RM_VQNEG] = 0x7,
+    [NEON_2RM_VCGT0] = 0x7,
+    [NEON_2RM_VCGE0] = 0x7,
+    [NEON_2RM_VCEQ0] = 0x7,
+    [NEON_2RM_VCLE0] = 0x7,
+    [NEON_2RM_VCLT0] = 0x7,
+    [NEON_2RM_VABS] = 0x7,
+    [NEON_2RM_VNEG] = 0x7,
+    [NEON_2RM_VCGT0_F] = 0x4,
+    [NEON_2RM_VCGE0_F] = 0x4,
+    [NEON_2RM_VCEQ0_F] = 0x4,
+    [NEON_2RM_VCLE0_F] = 0x4,
+    [NEON_2RM_VCLT0_F] = 0x4,
+    [NEON_2RM_VABS_F] = 0x4,
+    [NEON_2RM_VNEG_F] = 0x4,
+    [NEON_2RM_VSWP] = 0x1,
+    [NEON_2RM_VTRN] = 0x7,
+    [NEON_2RM_VUZP] = 0x7,
+    [NEON_2RM_VZIP] = 0x7,
+    [NEON_2RM_VMOVN] = 0x7,
+    [NEON_2RM_VQMOVN] = 0x7,
+    [NEON_2RM_VSHLL] = 0x7,
+    [NEON_2RM_VCVT_F16_F32] = 0x2,
+    [NEON_2RM_VCVT_F32_F16] = 0x2,
+    [NEON_2RM_VRECPE] = 0x4,
+    [NEON_2RM_VRSQRTE] = 0x4,
+    [NEON_2RM_VRECPE_F] = 0x4,
+    [NEON_2RM_VRSQRTE_F] = 0x4,
+    [NEON_2RM_VCVT_FS] = 0x4,
+    [NEON_2RM_VCVT_FU] = 0x4,
+    [NEON_2RM_VCVT_SF] = 0x4,
+    [NEON_2RM_VCVT_UF] = 0x4,
+};
+
+/* Translate a NEON data processing instruction.  Return nonzero if the
+   instruction is invalid.
+   We process data in a mixture of 32-bit and 64-bit chunks.
+   Mostly we use 32-bit chunks so we can use normal scalar instructions.  */
+
+static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int op;
+    int q;
+    int rd, rn, rm;
+    int size;
+    int shift;
+    int pass;
+    int count;
+    int pairwise;
+    int u;
+    uint32_t imm, mask;
+    TCGv tmp, tmp2, tmp3, tmp4, tmp5;
+    TCGv_i64 tmp64;
+
+    if (!s->vfp_enabled)
+      return 1;
+    q = (insn & (1 << 6)) != 0;
+    u = (insn >> 24) & 1;
+    VFP_DREG_D(rd, insn);
+    VFP_DREG_N(rn, insn);
+    VFP_DREG_M(rm, insn);
+    size = (insn >> 20) & 3;
+    if ((insn & (1 << 23)) == 0) {
+        /* Three register same length.  */
+        op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
+        /* Catch invalid op and bad size combinations: UNDEF */
+        if ((neon_3r_sizes[op] & (1 << size)) == 0) {
+            return 1;
+        }
+        /* All insns of this form UNDEF for either this condition or the
+         * superset of cases "Q==1"; we catch the latter later.
+         */
+        if (q && ((rd | rn | rm) & 1)) {
+            return 1;
+        }
+        if (size == 3 && op != NEON_3R_LOGIC) {
+            /* 64-bit element instructions. */
+            for (pass = 0; pass < (q ? 2 : 1); pass++) {
+                neon_load_reg64(cpu_V0, rn + pass);
+                neon_load_reg64(cpu_V1, rm + pass);
+                switch (op) {
+                case NEON_3R_VQADD:
+                    if (u) {
+                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
+                                                 cpu_V0, cpu_V1);
+                    } else {
+                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
+                                                 cpu_V0, cpu_V1);
+                    }
+                    break;
+                case NEON_3R_VQSUB:
+                    if (u) {
+                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
+                                                 cpu_V0, cpu_V1);
+                    } else {
+                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
+                                                 cpu_V0, cpu_V1);
+                    }
+                    break;
+                case NEON_3R_VSHL:
+                    if (u) {
+                        gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
+                    } else {
+                        gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
+                    }
+                    break;
+                case NEON_3R_VQSHL:
+                    if (u) {
+                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+                                                 cpu_V1, cpu_V0);
+                    } else {
+                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
+                                                 cpu_V1, cpu_V0);
+                    }
+                    break;
+                case NEON_3R_VRSHL:
+                    if (u) {
+                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
+                    } else {
+                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
+                    }
+                    break;
+                case NEON_3R_VQRSHL:
+                    if (u) {
+                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
+                                                  cpu_V1, cpu_V0);
+                    } else {
+                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
+                                                  cpu_V1, cpu_V0);
+                    }
+                    break;
+                case NEON_3R_VADD_VSUB:
+                    if (u) {
+                        tcg_gen_sub_i64(CPU_V001);
+                    } else {
+                        tcg_gen_add_i64(CPU_V001);
+                    }
+                    break;
+                default:
+                    abort();
+                }
+                neon_store_reg64(cpu_V0, rd + pass);
+            }
+            return 0;
+        }
+        pairwise = 0;
+        switch (op) {
+        case NEON_3R_VSHL:
+        case NEON_3R_VQSHL:
+        case NEON_3R_VRSHL:
+        case NEON_3R_VQRSHL:
+            {
+                int rtmp;
+                /* Shift instruction operands are reversed.  */
+                rtmp = rn;
+                rn = rm;
+                rm = rtmp;
+            }
+            break;
+        case NEON_3R_VPADD:
+            if (u) {
+                return 1;
+            }
+            /* Fall through */
+        case NEON_3R_VPMAX:
+        case NEON_3R_VPMIN:
+            pairwise = 1;
+            break;
+        case NEON_3R_FLOAT_ARITH:
+            pairwise = (u && size < 2); /* if VPADD (float) */
+            break;
+        case NEON_3R_FLOAT_MINMAX:
+            pairwise = u; /* if VPMIN/VPMAX (float) */
+            break;
+        case NEON_3R_FLOAT_CMP:
+            if (!u && size) {
+                /* no encoding for U=0 C=1x */
+                return 1;
+            }
+            break;
+        case NEON_3R_FLOAT_ACMP:
+            if (!u) {
+                return 1;
+            }
+            break;
+        case NEON_3R_VRECPS_VRSQRTS:
+            if (u) {
+                return 1;
+            }
+            break;
+        case NEON_3R_VMUL:
+            if (u && (size != 0)) {
+                /* UNDEF on invalid size for polynomial subcase */
+                return 1;
+            }
+            break;
+        default:
+            break;
+        }
+
+        if (pairwise && q) {
+            /* All the pairwise insns UNDEF if Q is set */
+            return 1;
+        }
+
+        for (pass = 0; pass < (q ? 4 : 2); pass++) {
+
+        if (pairwise) {
+            /* Pairwise.  */
+            if (pass < 1) {
+                tmp = neon_load_reg(rn, 0);
+                tmp2 = neon_load_reg(rn, 1);
+            } else {
+                tmp = neon_load_reg(rm, 0);
+                tmp2 = neon_load_reg(rm, 1);
+            }
+        } else {
+            /* Elementwise.  */
+            tmp = neon_load_reg(rn, pass);
+            tmp2 = neon_load_reg(rm, pass);
+        }
+        switch (op) {
+        case NEON_3R_VHADD:
+            GEN_NEON_INTEGER_OP(hadd);
+            break;
+        case NEON_3R_VQADD:
+            GEN_NEON_INTEGER_OP_ENV(qadd);
+            break;
+        case NEON_3R_VRHADD:
+            GEN_NEON_INTEGER_OP(rhadd);
+            break;
+        case NEON_3R_LOGIC: /* Logic ops.  */
+            switch ((u << 2) | size) {
+            case 0: /* VAND */
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+                break;
+            case 1: /* BIC */
+                tcg_gen_andc_i32(tmp, tmp, tmp2);
+                break;
+            case 2: /* VORR */
+                tcg_gen_or_i32(tmp, tmp, tmp2);
+                break;
+            case 3: /* VORN */
+                tcg_gen_orc_i32(tmp, tmp, tmp2);
+                break;
+            case 4: /* VEOR */
+                tcg_gen_xor_i32(tmp, tmp, tmp2);
+                break;
+            case 5: /* VBSL */
+                tmp3 = neon_load_reg(rd, pass);
+                gen_neon_bsl(tmp, tmp, tmp2, tmp3);
+                tcg_temp_free_i32(tmp3);
+                break;
+            case 6: /* VBIT */
+                tmp3 = neon_load_reg(rd, pass);
+                gen_neon_bsl(tmp, tmp, tmp3, tmp2);
+                tcg_temp_free_i32(tmp3);
+                break;
+            case 7: /* VBIF */
+                tmp3 = neon_load_reg(rd, pass);
+                gen_neon_bsl(tmp, tmp3, tmp, tmp2);
+                tcg_temp_free_i32(tmp3);
+                break;
+            }
+            break;
+        case NEON_3R_VHSUB:
+            GEN_NEON_INTEGER_OP(hsub);
+            break;
+        case NEON_3R_VQSUB:
+            GEN_NEON_INTEGER_OP_ENV(qsub);
+            break;
+        case NEON_3R_VCGT:
+            GEN_NEON_INTEGER_OP(cgt);
+            break;
+        case NEON_3R_VCGE:
+            GEN_NEON_INTEGER_OP(cge);
+            break;
+        case NEON_3R_VSHL:
+            GEN_NEON_INTEGER_OP(shl);
+            break;
+        case NEON_3R_VQSHL:
+            GEN_NEON_INTEGER_OP_ENV(qshl);
+            break;
+        case NEON_3R_VRSHL:
+            GEN_NEON_INTEGER_OP(rshl);
+            break;
+        case NEON_3R_VQRSHL:
+            GEN_NEON_INTEGER_OP_ENV(qrshl);
+            break;
+        case NEON_3R_VMAX:
+            GEN_NEON_INTEGER_OP(max);
+            break;
+        case NEON_3R_VMIN:
+            GEN_NEON_INTEGER_OP(min);
+            break;
+        case NEON_3R_VABD:
+            GEN_NEON_INTEGER_OP(abd);
+            break;
+        case NEON_3R_VABA:
+            GEN_NEON_INTEGER_OP(abd);
+            tcg_temp_free_i32(tmp2);
+            tmp2 = neon_load_reg(rd, pass);
+            gen_neon_add(size, tmp, tmp2);
+            break;
+        case NEON_3R_VADD_VSUB:
+            if (!u) { /* VADD */
+                gen_neon_add(size, tmp, tmp2);
+            } else { /* VSUB */
+                switch (size) {
+                case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
+                case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
+                case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
+                default: abort();
+                }
+            }
+            break;
+        case NEON_3R_VTST_VCEQ:
+            if (!u) { /* VTST */
+                switch (size) {
+                case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
+                case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
+                case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
+                default: abort();
+                }
+            } else { /* VCEQ */
+                switch (size) {
+                case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
+                case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
+                case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
+                default: abort();
+                }
+            }
+            break;
+        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
+            switch (size) {
+            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
+            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
+            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
+            default: abort();
+            }
+            tcg_temp_free_i32(tmp2);
+            tmp2 = neon_load_reg(rd, pass);
+            if (u) { /* VMLS */
+                gen_neon_rsb(size, tmp, tmp2);
+            } else { /* VMLA */
+                gen_neon_add(size, tmp, tmp2);
+            }
+            break;
+        case NEON_3R_VMUL:
+            if (u) { /* polynomial */
+                gen_helper_neon_mul_p8(tmp, tmp, tmp2);
+            } else { /* Integer */
+                switch (size) {
+                case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
+                case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
+                case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
+                default: abort();
+                }
+            }
+            break;
+        case NEON_3R_VPMAX:
+            GEN_NEON_INTEGER_OP(pmax);
+            break;
+        case NEON_3R_VPMIN:
+            GEN_NEON_INTEGER_OP(pmin);
+            break;
+        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */
+            if (!u) { /* VQDMULH */
+                switch (size) {
+                case 1:
+                    gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                    break;
+                case 2:
+                    gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                    break;
+                default: abort();
+                }
+            } else { /* VQRDMULH */
+                switch (size) {
+                case 1:
+                    gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                    break;
+                case 2:
+                    gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                    break;
+                default: abort();
+                }
+            }
+            break;
+        case NEON_3R_VPADD:
+            switch (size) {
+            case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
+            case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
+            case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
+            default: abort();
+            }
+            break;
+        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            switch ((u << 2) | size) {
+            case 0: /* VADD */
+            case 4: /* VPADD */
+                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
+                break;
+            case 2: /* VSUB */
+                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
+                break;
+            case 6: /* VABD */
+                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
+                break;
+            default:
+                abort();
+            }
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
+        case NEON_3R_FLOAT_MULTIPLY:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
+            if (!u) {
+                tcg_temp_free_i32(tmp2);
+                tmp2 = neon_load_reg(rd, pass);
+                if (size == 0) {
+                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
+                } else {
+                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
+                }
+            }
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
+        case NEON_3R_FLOAT_CMP:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            if (!u) {
+                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
+            } else {
+                if (size == 0) {
+                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
+                } else {
+                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
+                }
+            }
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
+        case NEON_3R_FLOAT_ACMP:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            if (size == 0) {
+                gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
+            } else {
+                gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
+            }
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
+        case NEON_3R_FLOAT_MINMAX:
+        {
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            if (size == 0) {
+                gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
+            } else {
+                gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
+            }
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
+        case NEON_3R_VRECPS_VRSQRTS:
+            if (size == 0)
+                gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
+            else
+                gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
+            break;
+        default:
+            abort();
+        }
+        tcg_temp_free_i32(tmp2);
+
+        /* Save the result.  For elementwise operations we can put it
+           straight into the destination register.  For pairwise operations
+           we have to be careful to avoid clobbering the source operands.  */
+        if (pairwise && rd == rm) {
+            neon_store_scratch(pass, tmp);
+        } else {
+            neon_store_reg(rd, pass, tmp);
+        }
+
+        } /* for pass */
+        if (pairwise && rd == rm) {
+            for (pass = 0; pass < (q ? 4 : 2); pass++) {
+                tmp = neon_load_scratch(pass);
+                neon_store_reg(rd, pass, tmp);
+            }
+        }
+        /* End of 3 register same size operations.  */
+    } else if (insn & (1 << 4)) {
+        if ((insn & 0x00380080) != 0) {
+            /* Two registers and shift.  */
+            op = (insn >> 8) & 0xf;
+            if (insn & (1 << 7)) {
+                /* 64-bit shift. */
+                if (op > 7) {
+                    return 1;
+                }
+                size = 3;
+            } else {
+                size = 2;
+                while ((insn & (1 << (size + 19))) == 0)
+                    size--;
+            }
+            shift = (insn >> 16) & ((1 << (3 + size)) - 1);
+            /* To avoid excessive dumplication of ops we implement shift
+               by immediate using the variable shift operations.  */
+            if (op < 8) {
+                /* Shift by immediate:
+                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
+                if (q && ((rd | rm) & 1)) {
+                    return 1;
+                }
+                if (!u && (op == 4 || op == 6)) {
+                    return 1;
+                }
+                /* Right shifts are encoded as N - shift, where N is the
+                   element size in bits.  */
+                if (op <= 4)
+                    shift = shift - (1 << (size + 3));
+                if (size == 3) {
+                    count = q + 1;
+                } else {
+                    count = q ? 4: 2;
+                }
+                switch (size) {
+                case 0:
+                    imm = (uint8_t) shift;
+                    imm |= imm << 8;
+                    imm |= imm << 16;
+                    break;
+                case 1:
+                    imm = (uint16_t) shift;
+                    imm |= imm << 16;
+                    break;
+                case 2:
+                case 3:
+                    imm = shift;
+                    break;
+                default:
+                    abort();
+                }
+
+                for (pass = 0; pass < count; pass++) {
+                    if (size == 3) {
+                        neon_load_reg64(cpu_V0, rm + pass);
+                        tcg_gen_movi_i64(cpu_V1, imm);
+                        switch (op) {
+                        case 0:  /* VSHR */
+                        case 1:  /* VSRA */
+                            if (u)
+                                gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
+                            else
+                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
+                            break;
+                        case 2: /* VRSHR */
+                        case 3: /* VRSRA */
+                            if (u)
+                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
+                            else
+                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
+                            break;
+                        case 4: /* VSRI */
+                        case 5: /* VSHL, VSLI */
+                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
+                            break;
+                        case 6: /* VQSHLU */
+                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
+                                                      cpu_V0, cpu_V1);
+                            break;
+                        case 7: /* VQSHL */
+                            if (u) {
+                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+                                                         cpu_V0, cpu_V1);
+                            } else {
+                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
+                                                         cpu_V0, cpu_V1);
+                            }
+                            break;
+                        }
+                        if (op == 1 || op == 3) {
+                            /* Accumulate.  */
+                            neon_load_reg64(cpu_V1, rd + pass);
+                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
+                        } else if (op == 4 || (op == 5 && u)) {
+                            /* Insert */
+                            neon_load_reg64(cpu_V1, rd + pass);
+                            uint64_t mask;
+                            if (shift < -63 || shift > 63) {
+                                mask = 0;
+                            } else {
+                                if (op == 4) {
+                                    mask = 0xffffffffffffffffull >> -shift;
+                                } else {
+                                    mask = 0xffffffffffffffffull << shift;
+                                }
+                            }
+                            tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
+                            tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
+                        }
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    } else { /* size < 3 */
+                        /* Operands in T0 and T1.  */
+                        tmp = neon_load_reg(rm, pass);
+                        tmp2 = tcg_temp_new_i32();
+                        tcg_gen_movi_i32(tmp2, imm);
+                        switch (op) {
+                        case 0:  /* VSHR */
+                        case 1:  /* VSRA */
+                            GEN_NEON_INTEGER_OP(shl);
+                            break;
+                        case 2: /* VRSHR */
+                        case 3: /* VRSRA */
+                            GEN_NEON_INTEGER_OP(rshl);
+                            break;
+                        case 4: /* VSRI */
+                        case 5: /* VSHL, VSLI */
+                            switch (size) {
+                            case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
+                            case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
+                            case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
+                            default: abort();
+                            }
+                            break;
+                        case 6: /* VQSHLU */
+                            switch (size) {
+                            case 0:
+                                gen_helper_neon_qshlu_s8(tmp, cpu_env,
+                                                         tmp, tmp2);
+                                break;
+                            case 1:
+                                gen_helper_neon_qshlu_s16(tmp, cpu_env,
+                                                          tmp, tmp2);
+                                break;
+                            case 2:
+                                gen_helper_neon_qshlu_s32(tmp, cpu_env,
+                                                          tmp, tmp2);
+                                break;
+                            default:
+                                abort();
+                            }
+                            break;
+                        case 7: /* VQSHL */
+                            GEN_NEON_INTEGER_OP_ENV(qshl);
+                            break;
+                        }
+                        tcg_temp_free_i32(tmp2);
+
+                        if (op == 1 || op == 3) {
+                            /* Accumulate.  */
+                            tmp2 = neon_load_reg(rd, pass);
+                            gen_neon_add(size, tmp, tmp2);
+                            tcg_temp_free_i32(tmp2);
+                        } else if (op == 4 || (op == 5 && u)) {
+                            /* Insert */
+                            switch (size) {
+                            case 0:
+                                if (op == 4)
+                                    mask = 0xff >> -shift;
+                                else
+                                    mask = (uint8_t)(0xff << shift);
+                                mask |= mask << 8;
+                                mask |= mask << 16;
+                                break;
+                            case 1:
+                                if (op == 4)
+                                    mask = 0xffff >> -shift;
+                                else
+                                    mask = (uint16_t)(0xffff << shift);
+                                mask |= mask << 16;
+                                break;
+                            case 2:
+                                if (shift < -31 || shift > 31) {
+                                    mask = 0;
+                                } else {
+                                    if (op == 4)
+                                        mask = 0xffffffffu >> -shift;
+                                    else
+                                        mask = 0xffffffffu << shift;
+                                }
+                                break;
+                            default:
+                                abort();
+                            }
+                            tmp2 = neon_load_reg(rd, pass);
+                            tcg_gen_andi_i32(tmp, tmp, mask);
+                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);
+                            tcg_gen_or_i32(tmp, tmp, tmp2);
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        neon_store_reg(rd, pass, tmp);
+                    }
+                } /* for pass */
+            } else if (op < 10) {
+                /* Shift by immediate and narrow:
+                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
+                int input_unsigned = (op == 8) ? !u : u;
+                if (rm & 1) {
+                    return 1;
+                }
+                shift = shift - (1 << (size + 3));
+                size++;
+                if (size == 3) {
+                    tmp64 = tcg_const_i64(shift);
+                    neon_load_reg64(cpu_V0, rm);
+                    neon_load_reg64(cpu_V1, rm + 1);
+                    for (pass = 0; pass < 2; pass++) {
+                        TCGv_i64 in;
+                        if (pass == 0) {
+                            in = cpu_V0;
+                        } else {
+                            in = cpu_V1;
+                        }
+                        if (q) {
+                            if (input_unsigned) {
+                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
+                            } else {
+                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
+                            }
+                        } else {
+                            if (input_unsigned) {
+                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
+                            } else {
+                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
+                            }
+                        }
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
+                        neon_store_reg(rd, pass, tmp);
+                    } /* for pass */
+                    tcg_temp_free_i64(tmp64);
+                } else {
+                    if (size == 1) {
+                        imm = (uint16_t)shift;
+                        imm |= imm << 16;
+                    } else {
+                        /* size == 2 */
+                        imm = (uint32_t)shift;
+                    }
+                    tmp2 = tcg_const_i32(imm);
+                    tmp4 = neon_load_reg(rm + 1, 0);
+                    tmp5 = neon_load_reg(rm + 1, 1);
+                    for (pass = 0; pass < 2; pass++) {
+                        if (pass == 0) {
+                            tmp = neon_load_reg(rm, 0);
+                        } else {
+                            tmp = tmp4;
+                        }
+                        gen_neon_shift_narrow(size, tmp, tmp2, q,
+                                              input_unsigned);
+                        if (pass == 0) {
+                            tmp3 = neon_load_reg(rm, 1);
+                        } else {
+                            tmp3 = tmp5;
+                        }
+                        gen_neon_shift_narrow(size, tmp3, tmp2, q,
+                                              input_unsigned);
+                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
+                        tcg_temp_free_i32(tmp);
+                        tcg_temp_free_i32(tmp3);
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
+                        neon_store_reg(rd, pass, tmp);
+                    } /* for pass */
+                    tcg_temp_free_i32(tmp2);
+                }
+            } else if (op == 10) {
+                /* VSHLL, VMOVL */
+                if (q || (rd & 1)) {
+                    return 1;
+                }
+                tmp = neon_load_reg(rm, 0);
+                tmp2 = neon_load_reg(rm, 1);
+                for (pass = 0; pass < 2; pass++) {
+                    if (pass == 1)
+                        tmp = tmp2;
+
+                    gen_neon_widen(cpu_V0, tmp, size, u);
+
+                    if (shift != 0) {
+                        /* The shift is less than the width of the source
+                           type, so we can just shift the whole register.  */
+                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
+                        /* Widen the result of shift: we need to clear
+                         * the potential overflow bits resulting from
+                         * left bits of the narrow input appearing as
+                         * right bits of left the neighbour narrow
+                         * input.  */
+                        if (size < 2 || !u) {
+                            uint64_t imm64;
+                            if (size == 0) {
+                                imm = (0xffu >> (8 - shift));
+                                imm |= imm << 16;
+                            } else if (size == 1) {
+                                imm = 0xffff >> (16 - shift);
+                            } else {
+                                /* size == 2 */
+                                imm = 0xffffffff >> (32 - shift);
+                            }
+                            if (size < 2) {
+                                imm64 = imm | (((uint64_t)imm) << 32);
+                            } else {
+                                imm64 = imm;
+                            }
+                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
+                        }
+                    }
+                    neon_store_reg64(cpu_V0, rd + pass);
+                }
+            } else if (op >= 14) {
+                /* VCVT fixed-point.  */
+                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
+                    return 1;
+                }
+                /* We have already masked out the must-be-1 top bit of imm6,
+                 * hence this 32-shift where the ARM ARM has 64-imm6.
+                 */
+                shift = 32 - shift;
+                for (pass = 0; pass < (q ? 4 : 2); pass++) {
+                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
+                    if (!(op & 1)) {
+                        if (u)
+                            gen_vfp_ulto(0, shift, 1);
+                        else
+                            gen_vfp_slto(0, shift, 1);
+                    } else {
+                        if (u)
+                            gen_vfp_toul(0, shift, 1);
+                        else
+                            gen_vfp_tosl(0, shift, 1);
+                    }
+                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
+                }
+            } else {
+                return 1;
+            }
+        } else { /* (insn & 0x00380080) == 0 */
+            int invert;
+            if (q && (rd & 1)) {
+                return 1;
+            }
+
+            op = (insn >> 8) & 0xf;
+            /* One register and immediate.  */
+            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
+            invert = (insn & (1 << 5)) != 0;
+            /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
+             * We choose to not special-case this and will behave as if a
+             * valid constant encoding of 0 had been given.
+             */
+            switch (op) {
+            case 0: case 1:
+                /* no-op */
+                break;
+            case 2: case 3:
+                imm <<= 8;
+                break;
+            case 4: case 5:
+                imm <<= 16;
+                break;
+            case 6: case 7:
+                imm <<= 24;
+                break;
+            case 8: case 9:
+                imm |= imm << 16;
+                break;
+            case 10: case 11:
+                imm = (imm << 8) | (imm << 24);
+                break;
+            case 12:
+                imm = (imm << 8) | 0xff;
+                break;
+            case 13:
+                imm = (imm << 16) | 0xffff;
+                break;
+            case 14:
+                imm |= (imm << 8) | (imm << 16) | (imm << 24);
+                if (invert)
+                    imm = ~imm;
+                break;
+            case 15:
+                if (invert) {
+                    return 1;
+                }
+                imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
+                      | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
+                break;
+            }
+            if (invert)
+                imm = ~imm;
+
+            for (pass = 0; pass < (q ? 4 : 2); pass++) {
+                if (op & 1 && op < 12) {
+                    tmp = neon_load_reg(rd, pass);
+                    if (invert) {
+                        /* The immediate value has already been inverted, so
+                           BIC becomes AND.  */
+                        tcg_gen_andi_i32(tmp, tmp, imm);
+                    } else {
+                        tcg_gen_ori_i32(tmp, tmp, imm);
+                    }
+                } else {
+                    /* VMOV, VMVN.  */
+                    tmp = tcg_temp_new_i32();
+                    if (op == 14 && invert) {
+                        int n;
+                        uint32_t val;
+                        val = 0;
+                        for (n = 0; n < 4; n++) {
+                            if (imm & (1 << (n + (pass & 1) * 4)))
+                                val |= 0xff << (n * 8);
+                        }
+                        tcg_gen_movi_i32(tmp, val);
+                    } else {
+                        tcg_gen_movi_i32(tmp, imm);
+                    }
+                }
+                neon_store_reg(rd, pass, tmp);
+            }
+        }
+    } else { /* (insn & 0x00800010 == 0x00800000) */
+        if (size != 3) {
+            op = (insn >> 8) & 0xf;
+            if ((insn & (1 << 6)) == 0) {
+                /* Three registers of different lengths.  */
+                int src1_wide;
+                int src2_wide;
+                int prewiden;
+                /* undefreq: bit 0 : UNDEF if size != 0
+                 *           bit 1 : UNDEF if size == 0
+                 *           bit 2 : UNDEF if U == 1
+                 * Note that [1:0] set implies 'always UNDEF'
+                 */
+                int undefreq;
+                /* prewiden, src1_wide, src2_wide, undefreq */
+                static const int neon_3reg_wide[16][4] = {
+                    {1, 0, 0, 0}, /* VADDL */
+                    {1, 1, 0, 0}, /* VADDW */
+                    {1, 0, 0, 0}, /* VSUBL */
+                    {1, 1, 0, 0}, /* VSUBW */
+                    {0, 1, 1, 0}, /* VADDHN */
+                    {0, 0, 0, 0}, /* VABAL */
+                    {0, 1, 1, 0}, /* VSUBHN */
+                    {0, 0, 0, 0}, /* VABDL */
+                    {0, 0, 0, 0}, /* VMLAL */
+                    {0, 0, 0, 6}, /* VQDMLAL */
+                    {0, 0, 0, 0}, /* VMLSL */
+                    {0, 0, 0, 6}, /* VQDMLSL */
+                    {0, 0, 0, 0}, /* Integer VMULL */
+                    {0, 0, 0, 2}, /* VQDMULL */
+                    {0, 0, 0, 5}, /* Polynomial VMULL */
+                    {0, 0, 0, 3}, /* Reserved: always UNDEF */
+                };
+
+                prewiden = neon_3reg_wide[op][0];
+                src1_wide = neon_3reg_wide[op][1];
+                src2_wide = neon_3reg_wide[op][2];
+                undefreq = neon_3reg_wide[op][3];
+
+                if (((undefreq & 1) && (size != 0)) ||
+                    ((undefreq & 2) && (size == 0)) ||
+                    ((undefreq & 4) && u)) {
+                    return 1;
+                }
+                if ((src1_wide && (rn & 1)) ||
+                    (src2_wide && (rm & 1)) ||
+                    (!src2_wide && (rd & 1))) {
+                    return 1;
+                }
+
+                /* Avoid overlapping operands.  Wide source operands are
+                   always aligned so will never overlap with wide
+                   destinations in problematic ways.  */
+                if (rd == rm && !src2_wide) {
+                    tmp = neon_load_reg(rm, 1);
+                    neon_store_scratch(2, tmp);
+                } else if (rd == rn && !src1_wide) {
+                    tmp = neon_load_reg(rn, 1);
+                    neon_store_scratch(2, tmp);
+                }
+                TCGV_UNUSED(tmp3);
+                for (pass = 0; pass < 2; pass++) {
+                    if (src1_wide) {
+                        neon_load_reg64(cpu_V0, rn + pass);
+                        TCGV_UNUSED(tmp);
+                    } else {
+                        if (pass == 1 && rd == rn) {
+                            tmp = neon_load_scratch(2);
+                        } else {
+                            tmp = neon_load_reg(rn, pass);
+                        }
+                        if (prewiden) {
+                            gen_neon_widen(cpu_V0, tmp, size, u);
+                        }
+                    }
+                    if (src2_wide) {
+                        neon_load_reg64(cpu_V1, rm + pass);
+                        TCGV_UNUSED(tmp2);
+                    } else {
+                        if (pass == 1 && rd == rm) {
+                            tmp2 = neon_load_scratch(2);
+                        } else {
+                            tmp2 = neon_load_reg(rm, pass);
+                        }
+                        if (prewiden) {
+                            gen_neon_widen(cpu_V1, tmp2, size, u);
+                        }
+                    }
+                    switch (op) {
+                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
+                        gen_neon_addl(size);
+                        break;
+                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
+                        gen_neon_subl(size);
+                        break;
+                    case 5: case 7: /* VABAL, VABDL */
+                        switch ((size << 1) | u) {
+                        case 0:
+                            gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);
+                            break;
+                        case 1:
+                            gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);
+                            break;
+                        case 2:
+                            gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);
+                            break;
+                        case 3:
+                            gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);
+                            break;
+                        case 4:
+                            gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);
+                            break;
+                        case 5:
+                            gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
+                            break;
+                        default: abort();
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        tcg_temp_free_i32(tmp);
+                        break;
+                    case 8: case 9: case 10: case 11: case 12: case 13:
+                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
+                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
+                        break;
+                    case 14: /* Polynomial VMULL */
+                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        tcg_temp_free_i32(tmp);
+                        break;
+                    default: /* 15 is RESERVED: caught earlier  */
+                        abort();
+                    }
+                    if (op == 13) {
+                        /* VQDMULL */
+                        gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    } else if (op == 5 || (op >= 8 && op <= 11)) {
+                        /* Accumulate.  */
+                        neon_load_reg64(cpu_V1, rd + pass);
+                        switch (op) {
+                        case 10: /* VMLSL */
+                            gen_neon_negl(cpu_V0, size);
+                            /* Fall through */
+                        case 5: case 8: /* VABAL, VMLAL */
+                            gen_neon_addl(size);
+                            break;
+                        case 9: case 11: /* VQDMLAL, VQDMLSL */
+                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                            if (op == 11) {
+                                gen_neon_negl(cpu_V0, size);
+                            }
+                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
+                            break;
+                        default:
+                            abort();
+                        }
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    } else if (op == 4 || op == 6) {
+                        /* Narrowing operation.  */
+                        tmp = tcg_temp_new_i32();
+                        if (!u) {
+                            switch (size) {
+                            case 0:
+                                gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
+                                break;
+                            case 1:
+                                gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
+                                break;
+                            case 2:
+                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
+                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
+                                break;
+                            default: abort();
+                            }
+                        } else {
+                            switch (size) {
+                            case 0:
+                                gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
+                                break;
+                            case 1:
+                                gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
+                                break;
+                            case 2:
+                                tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
+                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
+                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
+                                break;
+                            default: abort();
+                            }
+                        }
+                        if (pass == 0) {
+                            tmp3 = tmp;
+                        } else {
+                            neon_store_reg(rd, 0, tmp3);
+                            neon_store_reg(rd, 1, tmp);
+                        }
+                    } else {
+                        /* Write back the result.  */
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    }
+                }
+            } else {
+                /* Two registers and a scalar. NB that for ops of this form
+                 * the ARM ARM labels bit 24 as Q, but it is in our variable
+                 * 'u', not 'q'.
+                 */
+                if (size == 0) {
+                    return 1;
+                }
+                switch (op) {
+                case 1: /* Float VMLA scalar */
+                case 5: /* Floating point VMLS scalar */
+                case 9: /* Floating point VMUL scalar */
+                    if (size == 1) {
+                        return 1;
+                    }
+                    /* fall through */
+                case 0: /* Integer VMLA scalar */
+                case 4: /* Integer VMLS scalar */
+                case 8: /* Integer VMUL scalar */
+                case 12: /* VQDMULH scalar */
+                case 13: /* VQRDMULH scalar */
+                    if (u && ((rd | rn) & 1)) {
+                        return 1;
+                    }
+                    tmp = neon_get_scalar(size, rm);
+                    neon_store_scratch(0, tmp);
+                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
+                        tmp = neon_load_scratch(0);
+                        tmp2 = neon_load_reg(rn, pass);
+                        if (op == 12) {
+                            if (size == 1) {
+                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                            } else {
+                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                            }
+                        } else if (op == 13) {
+                            if (size == 1) {
+                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                            } else {
+                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                            }
+                        } else if (op & 1) {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free_ptr(fpstatus);
+                        } else {
+                            switch (size) {
+                            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
+                            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
+                            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
+                            default: abort();
+                            }
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        if (op < 8) {
+                            /* Accumulate.  */
+                            tmp2 = neon_load_reg(rd, pass);
+                            switch (op) {
+                            case 0:
+                                gen_neon_add(size, tmp, tmp2);
+                                break;
+                            case 1:
+                            {
+                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
+                                tcg_temp_free_ptr(fpstatus);
+                                break;
+                            }
+                            case 4:
+                                gen_neon_rsb(size, tmp, tmp2);
+                                break;
+                            case 5:
+                            {
+                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
+                                tcg_temp_free_ptr(fpstatus);
+                                break;
+                            }
+                            default:
+                                abort();
+                            }
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        neon_store_reg(rd, pass, tmp);
+                    }
+                    break;
+                case 3: /* VQDMLAL scalar */
+                case 7: /* VQDMLSL scalar */
+                case 11: /* VQDMULL scalar */
+                    if (u == 1) {
+                        return 1;
+                    }
+                    /* fall through */
+                case 2: /* VMLAL sclar */
+                case 6: /* VMLSL scalar */
+                case 10: /* VMULL scalar */
+                    if (rd & 1) {
+                        return 1;
+                    }
+                    tmp2 = neon_get_scalar(size, rm);
+                    /* We need a copy of tmp2 because gen_neon_mull
+                     * deletes it during pass 0.  */
+                    tmp4 = tcg_temp_new_i32();
+                    tcg_gen_mov_i32(tmp4, tmp2);
+                    tmp3 = neon_load_reg(rn, 1);
+
+                    for (pass = 0; pass < 2; pass++) {
+                        if (pass == 0) {
+                            tmp = neon_load_reg(rn, 0);
+                        } else {
+                            tmp = tmp3;
+                            tmp2 = tmp4;
+                        }
+                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
+                        if (op != 11) {
+                            neon_load_reg64(cpu_V1, rd + pass);
+                        }
+                        switch (op) {
+                        case 6:
+                            gen_neon_negl(cpu_V0, size);
+                            /* Fall through */
+                        case 2:
+                            gen_neon_addl(size);
+                            break;
+                        case 3: case 7:
+                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                            if (op == 7) {
+                                gen_neon_negl(cpu_V0, size);
+                            }
+                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
+                            break;
+                        case 10:
+                            /* no-op */
+                            break;
+                        case 11:
+                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
+                            break;
+                        default:
+                            abort();
+                        }
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    }
+
+
+                    break;
+                default: /* 14 and 15 are RESERVED */
+                    return 1;
+                }
+            }
+        } else { /* size == 3 */
+            if (!u) {
+                /* Extract.  */
+                imm = (insn >> 8) & 0xf;
+
+                if (imm > 7 && !q)
+                    return 1;
+
+                if (q && ((rd | rn | rm) & 1)) {
+                    return 1;
+                }
+
+                if (imm == 0) {
+                    neon_load_reg64(cpu_V0, rn);
+                    if (q) {
+                        neon_load_reg64(cpu_V1, rn + 1);
+                    }
+                } else if (imm == 8) {
+                    neon_load_reg64(cpu_V0, rn + 1);
+                    if (q) {
+                        neon_load_reg64(cpu_V1, rm);
+                    }
+                } else if (q) {
+                    tmp64 = tcg_temp_new_i64();
+                    if (imm < 8) {
+                        neon_load_reg64(cpu_V0, rn);
+                        neon_load_reg64(tmp64, rn + 1);
+                    } else {
+                        neon_load_reg64(cpu_V0, rn + 1);
+                        neon_load_reg64(tmp64, rm);
+                    }
+                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
+                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
+                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
+                    if (imm < 8) {
+                        neon_load_reg64(cpu_V1, rm);
+                    } else {
+                        neon_load_reg64(cpu_V1, rm + 1);
+                        imm -= 8;
+                    }
+                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
+                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
+                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
+                    tcg_temp_free_i64(tmp64);
+                } else {
+                    /* BUGFIX */
+                    neon_load_reg64(cpu_V0, rn);
+                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
+                    neon_load_reg64(cpu_V1, rm);
+                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
+                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
+                }
+                neon_store_reg64(cpu_V0, rd);
+                if (q) {
+                    neon_store_reg64(cpu_V1, rd + 1);
+                }
+            } else if ((insn & (1 << 11)) == 0) {
+                /* Two register misc.  */
+                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
+                size = (insn >> 18) & 3;
+                /* UNDEF for unknown op values and bad op-size combinations */
+                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
+                    return 1;
+                }
+                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
+                    q && ((rm | rd) & 1)) {
+                    return 1;
+                }
+                switch (op) {
+                case NEON_2RM_VREV64:
+                    for (pass = 0; pass < (q ? 2 : 1); pass++) {
+                        tmp = neon_load_reg(rm, pass * 2);
+                        tmp2 = neon_load_reg(rm, pass * 2 + 1);
+                        switch (size) {
+                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
+                        case 1: gen_swap_half(tmp); break;
+                        case 2: /* no-op */ break;
+                        default: abort();
+                        }
+                        neon_store_reg(rd, pass * 2 + 1, tmp);
+                        if (size == 2) {
+                            neon_store_reg(rd, pass * 2, tmp2);
+                        } else {
+                            switch (size) {
+                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
+                            case 1: gen_swap_half(tmp2); break;
+                            default: abort();
+                            }
+                            neon_store_reg(rd, pass * 2, tmp2);
+                        }
+                    }
+                    break;
+                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
+                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
+                    for (pass = 0; pass < q + 1; pass++) {
+                        tmp = neon_load_reg(rm, pass * 2);
+                        gen_neon_widen(cpu_V0, tmp, size, op & 1);
+                        tmp = neon_load_reg(rm, pass * 2 + 1);
+                        gen_neon_widen(cpu_V1, tmp, size, op & 1);
+                        switch (size) {
+                        case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
+                        case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
+                        case 2: tcg_gen_add_i64(CPU_V001); break;
+                        default: abort();
+                        }
+                        if (op >= NEON_2RM_VPADAL) {
+                            /* Accumulate.  */
+                            neon_load_reg64(cpu_V1, rd + pass);
+                            gen_neon_addl(size);
+                        }
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    }
+                    break;
+                case NEON_2RM_VTRN:
+                    if (size == 2) {
+                        int n;
+                        for (n = 0; n < (q ? 4 : 2); n += 2) {
+                            tmp = neon_load_reg(rm, n);
+                            tmp2 = neon_load_reg(rd, n + 1);
+                            neon_store_reg(rm, n, tmp2);
+                            neon_store_reg(rd, n + 1, tmp);
+                        }
+                    } else {
+                        goto elementwise;
+                    }
+                    break;
+                case NEON_2RM_VUZP:
+                    if (gen_neon_unzip(rd, rm, size, q)) {
+                        return 1;
+                    }
+                    break;
+                case NEON_2RM_VZIP:
+                    if (gen_neon_zip(rd, rm, size, q)) {
+                        return 1;
+                    }
+                    break;
+                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
+                    /* also VQMOVUN; op field and mnemonics don't line up */
+                    if (rm & 1) {
+                        return 1;
+                    }
+                    TCGV_UNUSED(tmp2);
+                    for (pass = 0; pass < 2; pass++) {
+                        neon_load_reg64(cpu_V0, rm + pass);
+                        tmp = tcg_temp_new_i32();
+                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
+                                           tmp, cpu_V0);
+                        if (pass == 0) {
+                            tmp2 = tmp;
+                        } else {
+                            neon_store_reg(rd, 0, tmp2);
+                            neon_store_reg(rd, 1, tmp);
+                        }
+                    }
+                    break;
+                case NEON_2RM_VSHLL:
+                    if (q || (rd & 1)) {
+                        return 1;
+                    }
+                    tmp = neon_load_reg(rm, 0);
+                    tmp2 = neon_load_reg(rm, 1);
+                    for (pass = 0; pass < 2; pass++) {
+                        if (pass == 1)
+                            tmp = tmp2;
+                        gen_neon_widen(cpu_V0, tmp, size, 1);
+                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
+                        neon_store_reg64(cpu_V0, rd + pass);
+                    }
+                    break;
+                case NEON_2RM_VCVT_F16_F32:
+                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
+                        q || (rm & 1)) {
+                        return 1;
+                    }
+                    tmp = tcg_temp_new_i32();
+                    tmp2 = tcg_temp_new_i32();
+                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    tcg_gen_shli_i32(tmp2, tmp2, 16);
+                    tcg_gen_or_i32(tmp2, tmp2, tmp);
+                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
+                    neon_store_reg(rd, 0, tmp2);
+                    tmp2 = tcg_temp_new_i32();
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    tcg_gen_shli_i32(tmp2, tmp2, 16);
+                    tcg_gen_or_i32(tmp2, tmp2, tmp);
+                    neon_store_reg(rd, 1, tmp2);
+                    tcg_temp_free_i32(tmp);
+                    break;
+                case NEON_2RM_VCVT_F32_F16:
+                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
+                        q || (rd & 1)) {
+                        return 1;
+                    }
+                    tmp3 = tcg_temp_new_i32();
+                    tmp = neon_load_reg(rm, 0);
+                    tmp2 = neon_load_reg(rm, 1);
+                    tcg_gen_ext16u_i32(tmp3, tmp);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
+                    tcg_gen_shri_i32(tmp3, tmp, 16);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
+                    tcg_temp_free_i32(tmp);
+                    tcg_gen_ext16u_i32(tmp3, tmp2);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
+                    tcg_gen_shri_i32(tmp3, tmp2, 16);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
+                    tcg_temp_free_i32(tmp2);
+                    tcg_temp_free_i32(tmp3);
+                    break;
+                default:
+                elementwise:
+                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
+                        if (neon_2rm_is_float_op(op)) {
+                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
+                                           neon_reg_offset(rm, pass));
+                            TCGV_UNUSED(tmp);
+                        } else {
+                            tmp = neon_load_reg(rm, pass);
+                        }
+                        switch (op) {
+                        case NEON_2RM_VREV32:
+                            switch (size) {
+                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
+                            case 1: gen_swap_half(tmp); break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VREV16:
+                            gen_rev16(tmp);
+                            break;
+                        case NEON_2RM_VCLS:
+                            switch (size) {
+                            case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
+                            case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
+                            case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VCLZ:
+                            switch (size) {
+                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
+                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
+                            case 2: gen_helper_clz(tmp, tmp); break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VCNT:
+                            gen_helper_neon_cnt_u8(tmp, tmp);
+                            break;
+                        case NEON_2RM_VMVN:
+                            tcg_gen_not_i32(tmp, tmp);
+                            break;
+                        case NEON_2RM_VQABS:
+                            switch (size) {
+                            case 0:
+                                gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);
+                                break;
+                            case 1:
+                                gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);
+                                break;
+                            case 2:
+                                gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);
+                                break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VQNEG:
+                            switch (size) {
+                            case 0:
+                                gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);
+                                break;
+                            case 1:
+                                gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);
+                                break;
+                            case 2:
+                                gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);
+                                break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
+                            tmp2 = tcg_const_i32(0);
+                            switch(size) {
+                            case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
+                            case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
+                            case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
+                            default: abort();
+                            }
+                            tcg_temp_free(tmp2);
+                            if (op == NEON_2RM_VCLE0) {
+                                tcg_gen_not_i32(tmp, tmp);
+                            }
+                            break;
+                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
+                            tmp2 = tcg_const_i32(0);
+                            switch(size) {
+                            case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
+                            case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
+                            case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
+                            default: abort();
+                            }
+                            tcg_temp_free(tmp2);
+                            if (op == NEON_2RM_VCLT0) {
+                                tcg_gen_not_i32(tmp, tmp);
+                            }
+                            break;
+                        case NEON_2RM_VCEQ0:
+                            tmp2 = tcg_const_i32(0);
+                            switch(size) {
+                            case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
+                            case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
+                            case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
+                            default: abort();
+                            }
+                            tcg_temp_free(tmp2);
+                            break;
+                        case NEON_2RM_VABS:
+                            switch(size) {
+                            case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
+                            case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
+                            case 2: tcg_gen_abs_i32(tmp, tmp); break;
+                            default: abort();
+                            }
+                            break;
+                        case NEON_2RM_VNEG:
+                            tmp2 = tcg_const_i32(0);
+                            gen_neon_rsb(size, tmp, tmp2);
+                            tcg_temp_free(tmp2);
+                            break;
+                        case NEON_2RM_VCGT0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCGE0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCEQ0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCLE0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VCLT0_F:
+                        {
+                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
+                            tcg_temp_free(tmp2);
+                            tcg_temp_free_ptr(fpstatus);
+                            break;
+                        }
+                        case NEON_2RM_VABS_F:
+                            gen_vfp_abs(0);
+                            break;
+                        case NEON_2RM_VNEG_F:
+                            gen_vfp_neg(0);
+                            break;
+                        case NEON_2RM_VSWP:
+                            tmp2 = neon_load_reg(rd, pass);
+                            neon_store_reg(rm, pass, tmp2);
+                            break;
+                        case NEON_2RM_VTRN:
+                            tmp2 = neon_load_reg(rd, pass);
+                            switch (size) {
+                            case 0: gen_neon_trn_u8(tmp, tmp2); break;
+                            case 1: gen_neon_trn_u16(tmp, tmp2); break;
+                            default: abort();
+                            }
+                            neon_store_reg(rm, pass, tmp2);
+                            break;
+                        case NEON_2RM_VRECPE:
+                            gen_helper_recpe_u32(tmp, tmp, cpu_env);
+                            break;
+                        case NEON_2RM_VRSQRTE:
+                            gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
+                            break;
+                        case NEON_2RM_VRECPE_F:
+                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
+                            break;
+                        case NEON_2RM_VRSQRTE_F:
+                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
+                            break;
+                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
+                            gen_vfp_sito(0, 1);
+                            break;
+                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
+                            gen_vfp_uito(0, 1);
+                            break;
+                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
+                            gen_vfp_tosiz(0, 1);
+                            break;
+                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
+                            gen_vfp_touiz(0, 1);
+                            break;
+                        default:
+                            /* Reserved op values were caught by the
+                             * neon_2rm_sizes[] check earlier.
+                             */
+                            abort();
+                        }
+                        if (neon_2rm_is_float_op(op)) {
+                            tcg_gen_st_f32(cpu_F0s, cpu_env,
+                                           neon_reg_offset(rd, pass));
+                        } else {
+                            neon_store_reg(rd, pass, tmp);
+                        }
+                    }
+                    break;
+                }
+            } else if ((insn & (1 << 10)) == 0) {
+                /* VTBL, VTBX.  */
+                int n = ((insn >> 8) & 3) + 1;
+                if ((rn + n) > 32) {
+                    /* This is UNPREDICTABLE; we choose to UNDEF to avoid the
+                     * helper function running off the end of the register file.
+                     */
+                    return 1;
+                }
+                n <<= 3;
+                if (insn & (1 << 6)) {
+                    tmp = neon_load_reg(rd, 0);
+                } else {
+                    tmp = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(tmp, 0);
+                }
+                tmp2 = neon_load_reg(rm, 0);
+                tmp4 = tcg_const_i32(rn);
+                tmp5 = tcg_const_i32(n);
+                gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5);
+                tcg_temp_free_i32(tmp);
+                if (insn & (1 << 6)) {
+                    tmp = neon_load_reg(rd, 1);
+                } else {
+                    tmp = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(tmp, 0);
+                }
+                tmp3 = neon_load_reg(rm, 1);
+                gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5);
+                tcg_temp_free_i32(tmp5);
+                tcg_temp_free_i32(tmp4);
+                neon_store_reg(rd, 0, tmp2);
+                neon_store_reg(rd, 1, tmp3);
+                tcg_temp_free_i32(tmp);
+            } else if ((insn & 0x380) == 0) {
+                /* VDUP */
+                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
+                    return 1;
+                }
+                if (insn & (1 << 19)) {
+                    tmp = neon_load_reg(rm, 1);
+                } else {
+                    tmp = neon_load_reg(rm, 0);
+                }
+                if (insn & (1 << 16)) {
+                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
+                } else if (insn & (1 << 17)) {
+                    if ((insn >> 18) & 1)
+                        gen_neon_dup_high16(tmp);
+                    else
+                        gen_neon_dup_low16(tmp);
+                }
+                for (pass = 0; pass < (q ? 4 : 2); pass++) {
+                    tmp2 = tcg_temp_new_i32();
+                    tcg_gen_mov_i32(tmp2, tmp);
+                    neon_store_reg(rd, pass, tmp2);
+                }
+                tcg_temp_free_i32(tmp);
+            } else {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int crn = (insn >> 16) & 0xf;
+    int crm = insn & 0xf;
+    int op1 = (insn >> 21) & 7;
+    int op2 = (insn >> 5) & 7;
+    int rt = (insn >> 12) & 0xf;
+    TCGv tmp;
+
+    /* Minimal set of debug registers, since we don't support debug */
+    if (op1 == 0 && crn == 0 && op2 == 0) {
+        switch (crm) {
+        case 0:
+            /* DBGDIDR: just RAZ. In particular this means the
+             * "debug architecture version" bits will read as
+             * a reserved value, which should cause Linux to
+             * not try to use the debug hardware.
+             */
+            tmp = tcg_const_i32(0);
+            store_reg(s, rt, tmp);
+            return 0;
+        case 1:
+        case 2:
+            /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we
+             * don't implement memory mapped debug components
+             */
+            if (ENABLE_ARCH_7) {
+                tmp = tcg_const_i32(0);
+                store_reg(s, rt, tmp);
+                return 0;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+            /* TEECR */
+            if (IS_USER(s))
+                return 1;
+            tmp = load_cpu_field(teecr);
+            store_reg(s, rt, tmp);
+            return 0;
+        }
+        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+            /* TEEHBR */
+            if (IS_USER(s) && (env->teecr & 1))
+                return 1;
+            tmp = load_cpu_field(teehbr);
+            store_reg(s, rt, tmp);
+            return 0;
+        }
+    }
+    fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
+            op1, crn, crm, op2);
+    return 1;
+}
+
+static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int crn = (insn >> 16) & 0xf;
+    int crm = insn & 0xf;
+    int op1 = (insn >> 21) & 7;
+    int op2 = (insn >> 5) & 7;
+    int rt = (insn >> 12) & 0xf;
+    TCGv tmp;
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+            /* TEECR */
+            if (IS_USER(s))
+                return 1;
+            tmp = load_reg(s, rt);
+            gen_helper_set_teecr(cpu_env, tmp);
+            tcg_temp_free_i32(tmp);
+            return 0;
+        }
+        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+            /* TEEHBR */
+            if (IS_USER(s) && (env->teecr & 1))
+                return 1;
+            tmp = load_reg(s, rt);
+            store_cpu_field(tmp, teehbr);
+            return 0;
+        }
+    }
+    fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
+            op1, crn, crm, op2);
+    return 1;
+}
+
+static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int cpnum;
+
+    cpnum = (insn >> 8) & 0xf;
+    if (arm_feature(env, ARM_FEATURE_XSCALE)
+	    && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
+	return 1;
+
+    switch (cpnum) {
+      case 0:
+      case 1:
+	if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+	    return disas_iwmmxt_insn(env, s, insn);
+	} else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+	    return disas_dsp_insn(env, s, insn);
+	}
+	return 1;
+    case 10:
+    case 11:
+	return disas_vfp_insn (env, s, insn);
+    case 14:
+        /* Coprocessors 7-15 are architecturally reserved by ARM.
+           Unfortunately Intel decided to ignore this.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE))
+            goto board;
+        if (insn & (1 << 20))
+            return disas_cp14_read(env, s, insn);
+        else
+            return disas_cp14_write(env, s, insn);
+    case 15:
+	return disas_cp15_insn (env, s, insn);
+    default:
+    board:
+	/* Unknown coprocessor.  See if the board has hooked it.  */
+	return disas_cp_insn (env, s, insn);
+    }
+}
+
+
+/* Store a 64-bit value to a register pair.  Clobbers val.  */
+static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
+{
+    TCGv tmp;
+    tmp = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rlow, tmp);
+    tmp = tcg_temp_new_i32();
+    tcg_gen_shri_i64(val, val, 32);
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rhigh, tmp);
+}
+
+/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
+static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
+{
+    TCGv_i64 tmp;
+    TCGv tmp2;
+
+    /* Load value and extend to 64 bits.  */
+    tmp = tcg_temp_new_i64();
+    tmp2 = load_reg(s, rlow);
+    tcg_gen_extu_i32_i64(tmp, tmp2);
+    tcg_temp_free_i32(tmp2);
+    tcg_gen_add_i64(val, val, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+/* load and add a 64-bit value from a register pair.  */
+static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
+{
+    TCGv_i64 tmp;
+    TCGv tmpl;
+    TCGv tmph;
+
+    /* Load 64-bit value rd:rn.  */
+    tmpl = load_reg(s, rlow);
+    tmph = load_reg(s, rhigh);
+    tmp = tcg_temp_new_i64();
+    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
+    tcg_temp_free_i32(tmpl);
+    tcg_temp_free_i32(tmph);
+    tcg_gen_add_i64(val, val, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+/* Set N and Z flags from a 64-bit value.  */
+static void gen_logicq_cc(TCGv_i64 val)
+{
+    TCGv tmp = tcg_temp_new_i32();
+    gen_helper_logicq_cc(tmp, val);
+    gen_logic_CC(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+/* Load/Store exclusive instructions are implemented by remembering
+   the value/address loaded, and seeing if these are the same
+   when the store is performed. This should be is sufficient to implement
+   the architecturally mandated semantics, and avoids having to monitor
+   regular stores.
+
+   In system emulation mode only one CPU will be running at once, so
+   this sequence is effectively atomic.  In user emulation mode we
+   throw an exception and handle the atomic operation elsewhere.  */
+static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
+                               TCGv addr, int size)
+{
+    TCGv tmp;
+
+    switch (size) {
+    case 0:
+        tmp = gen_ld8u(addr, IS_USER(s));
+        break;
+    case 1:
+        tmp = gen_ld16u(addr, IS_USER(s));
+        break;
+    case 2:
+    case 3:
+        tmp = gen_ld32(addr, IS_USER(s));
+        break;
+    default:
+        abort();
+    }
+    tcg_gen_mov_i32(cpu_exclusive_val, tmp);
+    store_reg(s, rt, tmp);
+    if (size == 3) {
+        TCGv tmp2 = tcg_temp_new_i32();
+        tcg_gen_addi_i32(tmp2, addr, 4);
+        tmp = gen_ld32(tmp2, IS_USER(s));
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_mov_i32(cpu_exclusive_high, tmp);
+        store_reg(s, rt2, tmp);
+    }
+    tcg_gen_mov_i32(cpu_exclusive_addr, addr);
+}
+
+static void gen_clrex(DisasContext *s)
+{
+    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+}
+
+#ifdef CONFIG_USER_ONLY
+static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
+                                TCGv addr, int size)
+{
+    tcg_gen_mov_i32(cpu_exclusive_test, addr);
+    tcg_gen_movi_i32(cpu_exclusive_info,
+                     size | (rd << 4) | (rt << 8) | (rt2 << 12));
+    gen_exception_insn(s, 4, EXCP_STREX);
+}
+#else
+static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
+                                TCGv addr, int size)
+{
+    TCGv tmp;
+    int done_label;
+    int fail_label;
+
+    /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
+         [addr] = {Rt};
+         {Rd} = 0;
+       } else {
+         {Rd} = 1;
+       } */
+    fail_label = gen_new_label();
+    done_label = gen_new_label();
+    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
+    switch (size) {
+    case 0:
+        tmp = gen_ld8u(addr, IS_USER(s));
+        break;
+    case 1:
+        tmp = gen_ld16u(addr, IS_USER(s));
+        break;
+    case 2:
+    case 3:
+        tmp = gen_ld32(addr, IS_USER(s));
+        break;
+    default:
+        abort();
+    }
+    tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
+    tcg_temp_free_i32(tmp);
+    if (size == 3) {
+        TCGv tmp2 = tcg_temp_new_i32();
+        tcg_gen_addi_i32(tmp2, addr, 4);
+        tmp = gen_ld32(tmp2, IS_USER(s));
+        tcg_temp_free_i32(tmp2);
+        tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
+        tcg_temp_free_i32(tmp);
+    }
+    tmp = load_reg(s, rt);
+    switch (size) {
+    case 0:
+        gen_st8(tmp, addr, IS_USER(s));
+        break;
+    case 1:
+        gen_st16(tmp, addr, IS_USER(s));
+        break;
+    case 2:
+    case 3:
+        gen_st32(tmp, addr, IS_USER(s));
+        break;
+    default:
+        abort();
+    }
+    if (size == 3) {
+        tcg_gen_addi_i32(addr, addr, 4);
+        tmp = load_reg(s, rt2);
+        gen_st32(tmp, addr, IS_USER(s));
+    }
+    tcg_gen_movi_i32(cpu_R[rd], 0);
+    tcg_gen_br(done_label);
+    gen_set_label(fail_label);
+    tcg_gen_movi_i32(cpu_R[rd], 1);
+    gen_set_label(done_label);
+    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+}
+#endif
+
+static void disas_arm_insn(CPUState * env, DisasContext *s)
+{
+    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv tmp3;
+    TCGv addr;
+    TCGv_i64 tmp64;
+
+    insn = ldl_code(s->pc);
+    s->pc += 4;
+
+    /* M variants do not implement ARM mode.  */
+    if (IS_M(env))
+        goto illegal_op;
+    cond = insn >> 28;
+    if (cond == 0xf){
+        /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
+         * choose to UNDEF. In ARMv5 and above the space is used
+         * for miscellaneous unconditional instructions.
+         */
+        ARCH(5);
+
+        /* Unconditional instructions.  */
+        if (((insn >> 25) & 7) == 1) {
+            /* NEON Data processing.  */
+            if (!arm_feature(env, ARM_FEATURE_NEON))
+                goto illegal_op;
+
+            if (disas_neon_data_insn(env, s, insn))
+                goto illegal_op;
+            return;
+        }
+        if ((insn & 0x0f100000) == 0x04000000) {
+            /* NEON load/store.  */
+            if (!arm_feature(env, ARM_FEATURE_NEON))
+                goto illegal_op;
+
+            if (disas_neon_ls_insn(env, s, insn))
+                goto illegal_op;
+            return;
+        }
+        if (((insn & 0x0f30f000) == 0x0510f000) ||
+            ((insn & 0x0f30f010) == 0x0710f000)) {
+            if ((insn & (1 << 22)) == 0) {
+                /* PLDW; v7MP */
+                if (!arm_feature(env, ARM_FEATURE_V7MP)) {
+                    goto illegal_op;
+                }
+            }
+            /* Otherwise PLD; v5TE+ */
+            ARCH(5TE);
+            return;
+        }
+        if (((insn & 0x0f70f000) == 0x0450f000) ||
+            ((insn & 0x0f70f010) == 0x0650f000)) {
+            ARCH(7);
+            return; /* PLI; V7 */
+        }
+        if (((insn & 0x0f700000) == 0x04100000) ||
+            ((insn & 0x0f700010) == 0x06100000)) {
+            if (!arm_feature(env, ARM_FEATURE_V7MP)) {
+                goto illegal_op;
+            }
+            return; /* v7MP: Unallocated memory hint: must NOP */
+        }
+
+        if ((insn & 0x0ffffdff) == 0x01010000) {
+            ARCH(6);
+            /* setend */
+            if (insn & (1 << 9)) {
+                /* BE8 mode not implemented.  */
+                goto illegal_op;
+            }
+            return;
+        } else if ((insn & 0x0fffff00) == 0x057ff000) {
+            switch ((insn >> 4) & 0xf) {
+            case 1: /* clrex */
+                ARCH(6K);
+                gen_clrex(s);
+                return;
+            case 4: /* dsb */
+            case 5: /* dmb */
+            case 6: /* isb */
+                ARCH(7);
+                /* We don't emulate caches so these are a no-op.  */
+                return;
+            default:
+                goto illegal_op;
+            }
+        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
+            /* srs */
+            int32_t offset;
+            if (IS_USER(s))
+                goto illegal_op;
+            ARCH(6);
+            op1 = (insn & 0x1f);
+            addr = tcg_temp_new_i32();
+            tmp = tcg_const_i32(op1);
+            gen_helper_get_r13_banked(addr, cpu_env, tmp);
+            tcg_temp_free_i32(tmp);
+            i = (insn >> 23) & 3;
+            switch (i) {
+            case 0: offset = -4; break; /* DA */
+            case 1: offset = 0; break; /* IA */
+            case 2: offset = -8; break; /* DB */
+            case 3: offset = 4; break; /* IB */
+            default: abort();
+            }
+            if (offset)
+                tcg_gen_addi_i32(addr, addr, offset);
+            tmp = load_reg(s, 14);
+            gen_st32(tmp, addr, 0);
+            tmp = load_cpu_field(spsr);
+            tcg_gen_addi_i32(addr, addr, 4);
+            gen_st32(tmp, addr, 0);
+            if (insn & (1 << 21)) {
+                /* Base writeback.  */
+                switch (i) {
+                case 0: offset = -8; break;
+                case 1: offset = 4; break;
+                case 2: offset = -4; break;
+                case 3: offset = 0; break;
+                default: abort();
+                }
+                if (offset)
+                    tcg_gen_addi_i32(addr, addr, offset);
+                tmp = tcg_const_i32(op1);
+                gen_helper_set_r13_banked(cpu_env, tmp, addr);
+                tcg_temp_free_i32(tmp);
+                tcg_temp_free_i32(addr);
+            } else {
+                tcg_temp_free_i32(addr);
+            }
+            return;
+        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
+            /* rfe */
+            int32_t offset;
+            if (IS_USER(s))
+                goto illegal_op;
+            ARCH(6);
+            rn = (insn >> 16) & 0xf;
+            addr = load_reg(s, rn);
+            i = (insn >> 23) & 3;
+            switch (i) {
+            case 0: offset = -4; break; /* DA */
+            case 1: offset = 0; break; /* IA */
+            case 2: offset = -8; break; /* DB */
+            case 3: offset = 4; break; /* IB */
+            default: abort();
+            }
+            if (offset)
+                tcg_gen_addi_i32(addr, addr, offset);
+            /* Load PC into tmp and CPSR into tmp2.  */
+            tmp = gen_ld32(addr, 0);
+            tcg_gen_addi_i32(addr, addr, 4);
+            tmp2 = gen_ld32(addr, 0);
+            if (insn & (1 << 21)) {
+                /* Base writeback.  */
+                switch (i) {
+                case 0: offset = -8; break;
+                case 1: offset = 4; break;
+                case 2: offset = -4; break;
+                case 3: offset = 0; break;
+                default: abort();
+                }
+                if (offset)
+                    tcg_gen_addi_i32(addr, addr, offset);
+                store_reg(s, rn, addr);
+            } else {
+                tcg_temp_free_i32(addr);
+            }
+            gen_rfe(s, tmp, tmp2);
+            return;
+        } else if ((insn & 0x0e000000) == 0x0a000000) {
+            /* branch link and change to thumb (blx <offset>) */
+            int32_t offset;
+
+            val = (uint32_t)s->pc;
+            tmp = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp, val);
+            store_reg(s, 14, tmp);
+            /* Sign-extend the 24-bit offset */
+            offset = (((int32_t)insn) << 8) >> 8;
+            /* offset * 4 + bit24 * 2 + (thumb bit) */
+            val += (offset << 2) | ((insn >> 23) & 2) | 1;
+            /* pipeline offset */
+            val += 4;
+            /* protected by ARCH(5); above, near the start of uncond block */
+            gen_bx_im(s, val);
+            return;
+        } else if ((insn & 0x0e000f00) == 0x0c000100) {
+            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+                /* iWMMXt register transfer.  */
+                if (env->cp15.c15_cpar & (1 << 1))
+                    if (!disas_iwmmxt_insn(env, s, insn))
+                        return;
+            }
+        } else if ((insn & 0x0fe00000) == 0x0c400000) {
+            /* Coprocessor double register transfer.  */
+            ARCH(5TE);
+        } else if ((insn & 0x0f000010) == 0x0e000010) {
+            /* Additional coprocessor register transfer.  */
+        } else if ((insn & 0x0ff10020) == 0x01000000) {
+            uint32_t mask;
+            uint32_t val;
+            /* cps (privileged) */
+            if (IS_USER(s))
+                return;
+            mask = val = 0;
+            if (insn & (1 << 19)) {
+                if (insn & (1 << 8))
+                    mask |= CPSR_A;
+                if (insn & (1 << 7))
+                    mask |= CPSR_I;
+                if (insn & (1 << 6))
+                    mask |= CPSR_F;
+                if (insn & (1 << 18))
+                    val |= mask;
+            }
+            if (insn & (1 << 17)) {
+                mask |= CPSR_M;
+                val |= (insn & 0x1f);
+            }
+            if (mask) {
+                gen_set_psr_im(s, mask, 0, val);
+            }
+            return;
+        }
+        goto illegal_op;
+    }
+    if (cond != 0xe) {
+        /* if not always execute, we generate a conditional jump to
+           next instruction */
+        s->condlabel = gen_new_label();
+        gen_test_cc(cond ^ 1, s->condlabel);
+        s->condjmp = 1;
+    }
+    if ((insn & 0x0f900000) == 0x03000000) {
+        if ((insn & (1 << 21)) == 0) {
+            ARCH(6T2);
+            rd = (insn >> 12) & 0xf;
+            val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
+            if ((insn & (1 << 22)) == 0) {
+                /* MOVW */
+                tmp = tcg_temp_new_i32();
+                tcg_gen_movi_i32(tmp, val);
+            } else {
+                /* MOVT */
+                tmp = load_reg(s, rd);
+                tcg_gen_ext16u_i32(tmp, tmp);
+                tcg_gen_ori_i32(tmp, tmp, val << 16);
+            }
+            store_reg(s, rd, tmp);
+        } else {
+            if (((insn >> 12) & 0xf) != 0xf)
+                goto illegal_op;
+            if (((insn >> 16) & 0xf) == 0) {
+                gen_nop_hint(s, insn & 0xff);
+            } else {
+                /* CPSR = immediate */
+                val = insn & 0xff;
+                shift = ((insn >> 8) & 0xf) * 2;
+                if (shift)
+                    val = (val >> shift) | (val << (32 - shift));
+                i = ((insn & (1 << 22)) != 0);
+                if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))
+                    goto illegal_op;
+            }
+        }
+    } else if ((insn & 0x0f900000) == 0x01000000
+               && (insn & 0x00000090) != 0x00000090) {
+        /* miscellaneous instructions */
+        op1 = (insn >> 21) & 3;
+        sh = (insn >> 4) & 0xf;
+        rm = insn & 0xf;
+        switch (sh) {
+        case 0x0: /* move program status register */
+            if (op1 & 1) {
+                /* PSR = reg */
+                tmp = load_reg(s, rm);
+                i = ((op1 & 2) != 0);
+                if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))
+                    goto illegal_op;
+            } else {
+                /* reg = PSR */
+                rd = (insn >> 12) & 0xf;
+                if (op1 & 2) {
+                    if (IS_USER(s))
+                        goto illegal_op;
+                    tmp = load_cpu_field(spsr);
+                } else {
+                    tmp = tcg_temp_new_i32();
+                    gen_helper_cpsr_read(tmp);
+                }
+                store_reg(s, rd, tmp);
+            }
+            break;
+        case 0x1:
+            if (op1 == 1) {
+                /* branch/exchange thumb (bx).  */
+                ARCH(4T);
+                tmp = load_reg(s, rm);
+                gen_bx(s, tmp);
+            } else if (op1 == 3) {
+                /* clz */
+                ARCH(5);
+                rd = (insn >> 12) & 0xf;
+                tmp = load_reg(s, rm);
+                gen_helper_clz(tmp, tmp);
+                store_reg(s, rd, tmp);
+            } else {
+                goto illegal_op;
+            }
+            break;
+        case 0x2:
+            if (op1 == 1) {
+                ARCH(5J); /* bxj */
+                /* Trivial implementation equivalent to bx.  */
+                tmp = load_reg(s, rm);
+                gen_bx(s, tmp);
+            } else {
+                goto illegal_op;
+            }
+            break;
+        case 0x3:
+            if (op1 != 1)
+              goto illegal_op;
+
+            ARCH(5);
+            /* branch link/exchange thumb (blx) */
+            tmp = load_reg(s, rm);
+            tmp2 = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp2, s->pc);
+            store_reg(s, 14, tmp2);
+            gen_bx(s, tmp);
+            break;
+        case 0x5: /* saturating add/subtract */
+            ARCH(5TE);
+            rd = (insn >> 12) & 0xf;
+            rn = (insn >> 16) & 0xf;
+            tmp = load_reg(s, rm);
+            tmp2 = load_reg(s, rn);
+            if (op1 & 2)
+                gen_helper_double_saturate(tmp2, tmp2);
+            if (op1 & 1)
+                gen_helper_sub_saturate(tmp, tmp, tmp2);
+            else
+                gen_helper_add_saturate(tmp, tmp, tmp2);
+            tcg_temp_free_i32(tmp2);
+            store_reg(s, rd, tmp);
+            break;
+        case 7:
+            /* SMC instruction (op1 == 3)
+               and undefined instructions (op1 == 0 || op1 == 2)
+               will trap */
+            if (op1 != 1) {
+                goto illegal_op;
+            }
+            /* bkpt */
+            ARCH(5);
+            gen_exception_insn(s, 4, EXCP_BKPT);
+            break;
+        case 0x8: /* signed multiply */
+        case 0xa:
+        case 0xc:
+        case 0xe:
+            ARCH(5TE);
+            rs = (insn >> 8) & 0xf;
+            rn = (insn >> 12) & 0xf;
+            rd = (insn >> 16) & 0xf;
+            if (op1 == 1) {
+                /* (32 * 16) >> 16 */
+                tmp = load_reg(s, rm);
+                tmp2 = load_reg(s, rs);
+                if (sh & 4)
+                    tcg_gen_sari_i32(tmp2, tmp2, 16);
+                else
+                    gen_sxth(tmp2);
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                tcg_gen_shri_i64(tmp64, tmp64, 16);
+                tmp = tcg_temp_new_i32();
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
+                tcg_temp_free_i64(tmp64);
+                if ((sh & 2) == 0) {
+                    tmp2 = load_reg(s, rn);
+                    gen_helper_add_setq(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                }
+                store_reg(s, rd, tmp);
+            } else {
+                /* 16 * 16 */
+                tmp = load_reg(s, rm);
+                tmp2 = load_reg(s, rs);
+                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
+                tcg_temp_free_i32(tmp2);
+                if (op1 == 2) {
+                    tmp64 = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(tmp64, tmp);
+                    tcg_temp_free_i32(tmp);
+                    gen_addq(s, tmp64, rn, rd);
+                    gen_storeq_reg(s, rn, rd, tmp64);
+                    tcg_temp_free_i64(tmp64);
+                } else {
+                    if (op1 == 0) {
+                        tmp2 = load_reg(s, rn);
+                        gen_helper_add_setq(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                    }
+                    store_reg(s, rd, tmp);
+                }
+            }
+            break;
+        default:
+            goto illegal_op;
+        }
+    } else if (((insn & 0x0e000000) == 0 &&
+                (insn & 0x00000090) != 0x90) ||
+               ((insn & 0x0e000000) == (1 << 25))) {
+        int set_cc, logic_cc, shiftop;
+
+        op1 = (insn >> 21) & 0xf;
+        set_cc = (insn >> 20) & 1;
+        logic_cc = table_logic_cc[op1] & set_cc;
+
+        /* data processing instruction */
+        if (insn & (1 << 25)) {
+            /* immediate operand */
+            val = insn & 0xff;
+            shift = ((insn >> 8) & 0xf) * 2;
+            if (shift) {
+                val = (val >> shift) | (val << (32 - shift));
+            }
+            tmp2 = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp2, val);
+            if (logic_cc && shift) {
+                gen_set_CF_bit31(tmp2);
+            }
+        } else {
+            /* register */
+            rm = (insn) & 0xf;
+            tmp2 = load_reg(s, rm);
+            shiftop = (insn >> 5) & 3;
+            if (!(insn & (1 << 4))) {
+                shift = (insn >> 7) & 0x1f;
+                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
+            } else {
+                rs = (insn >> 8) & 0xf;
+                tmp = load_reg(s, rs);
+                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
+            }
+        }
+        if (op1 != 0x0f && op1 != 0x0d) {
+            rn = (insn >> 16) & 0xf;
+            tmp = load_reg(s, rn);
+        } else {
+            TCGV_UNUSED(tmp);
+        }
+        rd = (insn >> 12) & 0xf;
+        switch(op1) {
+        case 0x00:
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x01:
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x02:
+            if (set_cc && rd == 15) {
+                /* SUBS r15, ... is used for exception return.  */
+                if (IS_USER(s)) {
+                    goto illegal_op;
+                }
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+                gen_exception_return(s, tmp);
+            } else {
+                if (set_cc) {
+                    gen_helper_sub_cc(tmp, tmp, tmp2);
+                } else {
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                }
+                store_reg_bx(env, s, rd, tmp);
+            }
+            break;
+        case 0x03:
+            if (set_cc) {
+                gen_helper_sub_cc(tmp, tmp2, tmp);
+            } else {
+                tcg_gen_sub_i32(tmp, tmp2, tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x04:
+            if (set_cc) {
+                gen_helper_add_cc(tmp, tmp, tmp2);
+            } else {
+                tcg_gen_add_i32(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x05:
+            if (set_cc) {
+                gen_helper_adc_cc(tmp, tmp, tmp2);
+            } else {
+                gen_add_carry(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x06:
+            if (set_cc) {
+                gen_helper_sbc_cc(tmp, tmp, tmp2);
+            } else {
+                gen_sub_carry(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x07:
+            if (set_cc) {
+                gen_helper_sbc_cc(tmp, tmp2, tmp);
+            } else {
+                gen_sub_carry(tmp, tmp2, tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x08:
+            if (set_cc) {
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
+            }
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x09:
+            if (set_cc) {
+                tcg_gen_xor_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
+            }
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x0a:
+            if (set_cc) {
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+            }
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x0b:
+            if (set_cc) {
+                gen_helper_add_cc(tmp, tmp, tmp2);
+            }
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x0c:
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 0x0d:
+            if (logic_cc && rd == 15) {
+                /* MOVS r15, ... is used for exception return.  */
+                if (IS_USER(s)) {
+                    goto illegal_op;
+                }
+                gen_exception_return(s, tmp2);
+            } else {
+                if (logic_cc) {
+                    gen_logic_CC(tmp2);
+                }
+                store_reg_bx(env, s, rd, tmp2);
+            }
+            break;
+        case 0x0e:
+            tcg_gen_andc_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        default:
+        case 0x0f:
+            tcg_gen_not_i32(tmp2, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp2);
+            break;
+        }
+        if (op1 != 0x0f && op1 != 0x0d) {
+            tcg_temp_free_i32(tmp2);
+        }
+    } else {
+        /* other instructions */
+        op1 = (insn >> 24) & 0xf;
+        switch(op1) {
+        case 0x0:
+        case 0x1:
+            /* multiplies, extra load/stores */
+            sh = (insn >> 5) & 3;
+            if (sh == 0) {
+                if (op1 == 0x0) {
+                    rd = (insn >> 16) & 0xf;
+                    rn = (insn >> 12) & 0xf;
+                    rs = (insn >> 8) & 0xf;
+                    rm = (insn) & 0xf;
+                    op1 = (insn >> 20) & 0xf;
+                    switch (op1) {
+                    case 0: case 1: case 2: case 3: case 6:
+                        /* 32 bit mul */
+                        tmp = load_reg(s, rs);
+                        tmp2 = load_reg(s, rm);
+                        tcg_gen_mul_i32(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        if (insn & (1 << 22)) {
+                            /* Subtract (mls) */
+                            ARCH(6T2);
+                            tmp2 = load_reg(s, rn);
+                            tcg_gen_sub_i32(tmp, tmp2, tmp);
+                            tcg_temp_free_i32(tmp2);
+                        } else if (insn & (1 << 21)) {
+                            /* Add */
+                            tmp2 = load_reg(s, rn);
+                            tcg_gen_add_i32(tmp, tmp, tmp2);
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        if (insn & (1 << 20))
+                            gen_logic_CC(tmp);
+                        store_reg(s, rd, tmp);
+                        break;
+                    case 4:
+                        /* 64 bit mul double accumulate (UMAAL) */
+                        ARCH(6);
+                        tmp = load_reg(s, rs);
+                        tmp2 = load_reg(s, rm);
+                        tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+                        gen_addq_lo(s, tmp64, rn);
+                        gen_addq_lo(s, tmp64, rd);
+                        gen_storeq_reg(s, rn, rd, tmp64);
+                        tcg_temp_free_i64(tmp64);
+                        break;
+                    case 8: case 9: case 10: case 11:
+                    case 12: case 13: case 14: case 15:
+                        /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
+                        tmp = load_reg(s, rs);
+                        tmp2 = load_reg(s, rm);
+                        if (insn & (1 << 22)) {
+                            tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                        } else {
+                            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+                        }
+                        if (insn & (1 << 21)) { /* mult accumulate */
+                            gen_addq(s, tmp64, rn, rd);
+                        }
+                        if (insn & (1 << 20)) {
+                            gen_logicq_cc(tmp64);
+                        }
+                        gen_storeq_reg(s, rn, rd, tmp64);
+                        tcg_temp_free_i64(tmp64);
+                        break;
+                    default:
+                        goto illegal_op;
+                    }
+                } else {
+                    rn = (insn >> 16) & 0xf;
+                    rd = (insn >> 12) & 0xf;
+                    if (insn & (1 << 23)) {
+                        /* load/store exclusive */
+                        op1 = (insn >> 21) & 0x3;
+                        if (op1)
+                            ARCH(6K);
+                        else
+                            ARCH(6);
+                        addr = tcg_temp_local_new_i32();
+                        load_reg_var(s, addr, rn);
+                        if (insn & (1 << 20)) {
+                            switch (op1) {
+                            case 0: /* ldrex */
+                                gen_load_exclusive(s, rd, 15, addr, 2);
+                                break;
+                            case 1: /* ldrexd */
+                                gen_load_exclusive(s, rd, rd + 1, addr, 3);
+                                break;
+                            case 2: /* ldrexb */
+                                gen_load_exclusive(s, rd, 15, addr, 0);
+                                break;
+                            case 3: /* ldrexh */
+                                gen_load_exclusive(s, rd, 15, addr, 1);
+                                break;
+                            default:
+                                abort();
+                            }
+                        } else {
+                            rm = insn & 0xf;
+                            switch (op1) {
+                            case 0:  /*  strex */
+                                gen_store_exclusive(s, rd, rm, 15, addr, 2);
+                                break;
+                            case 1: /*  strexd */
+                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
+                                break;
+                            case 2: /*  strexb */
+                                gen_store_exclusive(s, rd, rm, 15, addr, 0);
+                                break;
+                            case 3: /* strexh */
+                                gen_store_exclusive(s, rd, rm, 15, addr, 1);
+                                break;
+                            default:
+                                abort();
+                            }
+                        }
+                        tcg_temp_free(addr);
+                    } else {
+                        /* SWP instruction */
+                        rm = (insn) & 0xf;
+
+                        /* ??? This is not really atomic.  However we know
+                           we never have multiple CPUs running in parallel,
+                           so it is good enough.  */
+                        addr = load_reg(s, rn);
+                        tmp = load_reg(s, rm);
+                        if (insn & (1 << 22)) {
+                            tmp2 = gen_ld8u(addr, IS_USER(s));
+                            gen_st8(tmp, addr, IS_USER(s));
+                        } else {
+                            tmp2 = gen_ld32(addr, IS_USER(s));
+                            gen_st32(tmp, addr, IS_USER(s));
+                        }
+                        tcg_temp_free_i32(addr);
+                        store_reg(s, rd, tmp2);
+                    }
+                }
+            } else {
+                int address_offset;
+                int load;
+                /* Misc load/store */
+                rn = (insn >> 16) & 0xf;
+                rd = (insn >> 12) & 0xf;
+                addr = load_reg(s, rn);
+                if (insn & (1 << 24))
+                    gen_add_datah_offset(s, insn, 0, addr);
+                address_offset = 0;
+                if (insn & (1 << 20)) {
+                    /* load */
+                    switch(sh) {
+                    case 1:
+                        tmp = gen_ld16u(addr, IS_USER(s));
+                        break;
+                    case 2:
+                        tmp = gen_ld8s(addr, IS_USER(s));
+                        break;
+                    default:
+                    case 3:
+                        tmp = gen_ld16s(addr, IS_USER(s));
+                        break;
+                    }
+                    load = 1;
+                } else if (sh & 2) {
+                    ARCH(5TE);
+                    /* doubleword */
+                    if (sh & 1) {
+                        /* store */
+                        tmp = load_reg(s, rd);
+                        gen_st32(tmp, addr, IS_USER(s));
+                        tcg_gen_addi_i32(addr, addr, 4);
+                        tmp = load_reg(s, rd + 1);
+                        gen_st32(tmp, addr, IS_USER(s));
+                        load = 0;
+                    } else {
+                        /* load */
+                        tmp = gen_ld32(addr, IS_USER(s));
+                        store_reg(s, rd, tmp);
+                        tcg_gen_addi_i32(addr, addr, 4);
+                        tmp = gen_ld32(addr, IS_USER(s));
+                        rd++;
+                        load = 1;
+                    }
+                    address_offset = -4;
+                } else {
+                    /* store */
+                    tmp = load_reg(s, rd);
+                    gen_st16(tmp, addr, IS_USER(s));
+                    load = 0;
+                }
+                /* Perform base writeback before the loaded value to
+                   ensure correct behavior with overlapping index registers.
+                   ldrd with base writeback is is undefined if the
+                   destination and index registers overlap.  */
+                if (!(insn & (1 << 24))) {
+                    gen_add_datah_offset(s, insn, address_offset, addr);
+                    store_reg(s, rn, addr);
+                } else if (insn & (1 << 21)) {
+                    if (address_offset)
+                        tcg_gen_addi_i32(addr, addr, address_offset);
+                    store_reg(s, rn, addr);
+                } else {
+                    tcg_temp_free_i32(addr);
+                }
+                if (load) {
+                    /* Complete the load.  */
+                    store_reg(s, rd, tmp);
+                }
+            }
+            break;
+        case 0x4:
+        case 0x5:
+            goto do_ldst;
+        case 0x6:
+        case 0x7:
+            if (insn & (1 << 4)) {
+                ARCH(6);
+                /* Armv6 Media instructions.  */
+                rm = insn & 0xf;
+                rn = (insn >> 16) & 0xf;
+                rd = (insn >> 12) & 0xf;
+                rs = (insn >> 8) & 0xf;
+                switch ((insn >> 23) & 3) {
+                case 0: /* Parallel add/subtract.  */
+                    op1 = (insn >> 20) & 7;
+                    tmp = load_reg(s, rn);
+                    tmp2 = load_reg(s, rm);
+                    sh = (insn >> 5) & 7;
+                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
+                        goto illegal_op;
+                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                    store_reg(s, rd, tmp);
+                    break;
+                case 1:
+                    if ((insn & 0x00700020) == 0) {
+                        /* Halfword pack.  */
+                        tmp = load_reg(s, rn);
+                        tmp2 = load_reg(s, rm);
+                        shift = (insn >> 7) & 0x1f;
+                        if (insn & (1 << 6)) {
+                            /* pkhtb */
+                            if (shift == 0)
+                                shift = 31;
+                            tcg_gen_sari_i32(tmp2, tmp2, shift);
+                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
+                            tcg_gen_ext16u_i32(tmp2, tmp2);
+                        } else {
+                            /* pkhbt */
+                            if (shift)
+                                tcg_gen_shli_i32(tmp2, tmp2, shift);
+                            tcg_gen_ext16u_i32(tmp, tmp);
+                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
+                        }
+                        tcg_gen_or_i32(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rd, tmp);
+                    } else if ((insn & 0x00200020) == 0x00200000) {
+                        /* [us]sat */
+                        tmp = load_reg(s, rm);
+                        shift = (insn >> 7) & 0x1f;
+                        if (insn & (1 << 6)) {
+                            if (shift == 0)
+                                shift = 31;
+                            tcg_gen_sari_i32(tmp, tmp, shift);
+                        } else {
+                            tcg_gen_shli_i32(tmp, tmp, shift);
+                        }
+                        sh = (insn >> 16) & 0x1f;
+                        tmp2 = tcg_const_i32(sh);
+                        if (insn & (1 << 22))
+                          gen_helper_usat(tmp, tmp, tmp2);
+                        else
+                          gen_helper_ssat(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rd, tmp);
+                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
+                        /* [us]sat16 */
+                        tmp = load_reg(s, rm);
+                        sh = (insn >> 16) & 0x1f;
+                        tmp2 = tcg_const_i32(sh);
+                        if (insn & (1 << 22))
+                          gen_helper_usat16(tmp, tmp, tmp2);
+                        else
+                          gen_helper_ssat16(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rd, tmp);
+                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
+                        /* Select bytes.  */
+                        tmp = load_reg(s, rn);
+                        tmp2 = load_reg(s, rm);
+                        tmp3 = tcg_temp_new_i32();
+                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
+                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
+                        tcg_temp_free_i32(tmp3);
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rd, tmp);
+                    } else if ((insn & 0x000003e0) == 0x00000060) {
+                        tmp = load_reg(s, rm);
+                        shift = (insn >> 10) & 3;
+                        /* ??? In many cases it's not necessary to do a
+                           rotate, a shift is sufficient.  */
+                        if (shift != 0)
+                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);
+                        op1 = (insn >> 20) & 7;
+                        switch (op1) {
+                        case 0: gen_sxtb16(tmp);  break;
+                        case 2: gen_sxtb(tmp);    break;
+                        case 3: gen_sxth(tmp);    break;
+                        case 4: gen_uxtb16(tmp);  break;
+                        case 6: gen_uxtb(tmp);    break;
+                        case 7: gen_uxth(tmp);    break;
+                        default: goto illegal_op;
+                        }
+                        if (rn != 15) {
+                            tmp2 = load_reg(s, rn);
+                            if ((op1 & 3) == 0) {
+                                gen_add16(tmp, tmp2);
+                            } else {
+                                tcg_gen_add_i32(tmp, tmp, tmp2);
+                                tcg_temp_free_i32(tmp2);
+                            }
+                        }
+                        store_reg(s, rd, tmp);
+                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
+                        /* rev */
+                        tmp = load_reg(s, rm);
+                        if (insn & (1 << 22)) {
+                            if (insn & (1 << 7)) {
+                                gen_revsh(tmp);
+                            } else {
+                                ARCH(6T2);
+                                gen_helper_rbit(tmp, tmp);
+                            }
+                        } else {
+                            if (insn & (1 << 7))
+                                gen_rev16(tmp);
+                            else
+                                tcg_gen_bswap32_i32(tmp, tmp);
+                        }
+                        store_reg(s, rd, tmp);
+                    } else {
+                        goto illegal_op;
+                    }
+                    break;
+                case 2: /* Multiplies (Type 3).  */
+                    tmp = load_reg(s, rm);
+                    tmp2 = load_reg(s, rs);
+                    if (insn & (1 << 20)) {
+                        /* Signed multiply most significant [accumulate].
+                           (SMMUL, SMMLA, SMMLS) */
+                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
+
+                        if (rd != 15) {
+                            tmp = load_reg(s, rd);
+                            if (insn & (1 << 6)) {
+                                tmp64 = gen_subq_msw(tmp64, tmp);
+                            } else {
+                                tmp64 = gen_addq_msw(tmp64, tmp);
+                            }
+                        }
+                        if (insn & (1 << 5)) {
+                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
+                        }
+                        tcg_gen_shri_i64(tmp64, tmp64, 32);
+                        tmp = tcg_temp_new_i32();
+                        tcg_gen_trunc_i64_i32(tmp, tmp64);
+                        tcg_temp_free_i64(tmp64);
+                        store_reg(s, rn, tmp);
+                    } else {
+                        if (insn & (1 << 5))
+                            gen_swap_half(tmp2);
+                        gen_smul_dual(tmp, tmp2);
+                        if (insn & (1 << 6)) {
+                            /* This subtraction cannot overflow. */
+                            tcg_gen_sub_i32(tmp, tmp, tmp2);
+                        } else {
+                            /* This addition cannot overflow 32 bits;
+                             * however it may overflow considered as a signed
+                             * operation, in which case we must set the Q flag.
+                             */
+                            gen_helper_add_setq(tmp, tmp, tmp2);
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        if (insn & (1 << 22)) {
+                            /* smlald, smlsld */
+                            tmp64 = tcg_temp_new_i64();
+                            tcg_gen_ext_i32_i64(tmp64, tmp);
+                            tcg_temp_free_i32(tmp);
+                            gen_addq(s, tmp64, rd, rn);
+                            gen_storeq_reg(s, rd, rn, tmp64);
+                            tcg_temp_free_i64(tmp64);
+                        } else {
+                            /* smuad, smusd, smlad, smlsd */
+                            if (rd != 15)
+                              {
+                                tmp2 = load_reg(s, rd);
+                                gen_helper_add_setq(tmp, tmp, tmp2);
+                                tcg_temp_free_i32(tmp2);
+                              }
+                            store_reg(s, rn, tmp);
+                        }
+                    }
+                    break;
+                case 3:
+                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
+                    switch (op1) {
+                    case 0: /* Unsigned sum of absolute differences.  */
+                        ARCH(6);
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
+                        gen_helper_usad8(tmp, tmp, tmp2);
+                        tcg_temp_free_i32(tmp2);
+                        if (rd != 15) {
+                            tmp2 = load_reg(s, rd);
+                            tcg_gen_add_i32(tmp, tmp, tmp2);
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        store_reg(s, rn, tmp);
+                        break;
+                    case 0x20: case 0x24: case 0x28: case 0x2c:
+                        /* Bitfield insert/clear.  */
+                        ARCH(6T2);
+                        shift = (insn >> 7) & 0x1f;
+                        i = (insn >> 16) & 0x1f;
+                        i = i + 1 - shift;
+                        if (rm == 15) {
+                            tmp = tcg_temp_new_i32();
+                            tcg_gen_movi_i32(tmp, 0);
+                        } else {
+                            tmp = load_reg(s, rm);
+                        }
+                        if (i != 32) {
+                            tmp2 = load_reg(s, rd);
+                            gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        store_reg(s, rd, tmp);
+                        break;
+                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
+                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
+                        ARCH(6T2);
+                        tmp = load_reg(s, rm);
+                        shift = (insn >> 7) & 0x1f;
+                        i = ((insn >> 16) & 0x1f) + 1;
+                        if (shift + i > 32)
+                            goto illegal_op;
+                        if (i < 32) {
+                            if (op1 & 0x20) {
+                                gen_ubfx(tmp, shift, (1u << i) - 1);
+                            } else {
+                                gen_sbfx(tmp, shift, i);
+                            }
+                        }
+                        store_reg(s, rd, tmp);
+                        break;
+                    default:
+                        goto illegal_op;
+                    }
+                    break;
+                }
+                break;
+            }
+        do_ldst:
+            /* Check for undefined extension instructions
+             * per the ARM Bible IE:
+             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx
+             */
+            sh = (0xf << 20) | (0xf << 4);
+            if (op1 == 0x7 && ((insn & sh) == sh))
+            {
+                goto illegal_op;
+            }
+            /* load/store byte/word */
+            rn = (insn >> 16) & 0xf;
+            rd = (insn >> 12) & 0xf;
+            tmp2 = load_reg(s, rn);
+            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
+            if (insn & (1 << 24))
+                gen_add_data_offset(s, insn, tmp2);
+            if (insn & (1 << 20)) {
+                /* load */
+                if (insn & (1 << 22)) {
+                    tmp = gen_ld8u(tmp2, i);
+                } else {
+                    tmp = gen_ld32(tmp2, i);
+                }
+            } else {
+                /* store */
+                tmp = load_reg(s, rd);
+                if (insn & (1 << 22))
+                    gen_st8(tmp, tmp2, i);
+                else
+                    gen_st32(tmp, tmp2, i);
+            }
+            if (!(insn & (1 << 24))) {
+                gen_add_data_offset(s, insn, tmp2);
+                store_reg(s, rn, tmp2);
+            } else if (insn & (1 << 21)) {
+                store_reg(s, rn, tmp2);
+            } else {
+                tcg_temp_free_i32(tmp2);
+            }
+            if (insn & (1 << 20)) {
+                /* Complete the load.  */
+                store_reg_from_load(env, s, rd, tmp);
+            }
+            break;
+        case 0x08:
+        case 0x09:
+            {
+                int j, n, user, loaded_base;
+                TCGv loaded_var;
+                /* load/store multiple words */
+                /* XXX: store correct base if write back */
+                user = 0;
+                if (insn & (1 << 22)) {
+                    if (IS_USER(s))
+                        goto illegal_op; /* only usable in supervisor mode */
+
+                    if ((insn & (1 << 15)) == 0)
+                        user = 1;
+                }
+                rn = (insn >> 16) & 0xf;
+                addr = load_reg(s, rn);
+
+                /* compute total size */
+                loaded_base = 0;
+                TCGV_UNUSED(loaded_var);
+                n = 0;
+                for(i=0;i<16;i++) {
+                    if (insn & (1 << i))
+                        n++;
+                }
+                /* XXX: test invalid n == 0 case ? */
+                if (insn & (1 << 23)) {
+                    if (insn & (1 << 24)) {
+                        /* pre increment */
+                        tcg_gen_addi_i32(addr, addr, 4);
+                    } else {
+                        /* post increment */
+                    }
+                } else {
+                    if (insn & (1 << 24)) {
+                        /* pre decrement */
+                        tcg_gen_addi_i32(addr, addr, -(n * 4));
+                    } else {
+                        /* post decrement */
+                        if (n != 1)
+                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                    }
+                }
+                j = 0;
+                for(i=0;i<16;i++) {
+                    if (insn & (1 << i)) {
+                        if (insn & (1 << 20)) {
+                            /* load */
+                            tmp = gen_ld32(addr, IS_USER(s));
+                            if (user) {
+                                tmp2 = tcg_const_i32(i);
+                                gen_helper_set_user_reg(tmp2, tmp);
+                                tcg_temp_free_i32(tmp2);
+                                tcg_temp_free_i32(tmp);
+                            } else if (i == rn) {
+                                loaded_var = tmp;
+                                loaded_base = 1;
+                            } else {
+                                store_reg_from_load(env, s, i, tmp);
+                            }
+                        } else {
+                            /* store */
+                            if (i == 15) {
+                                /* special case: r15 = PC + 8 */
+                                val = (long)s->pc + 4;
+                                tmp = tcg_temp_new_i32();
+                                tcg_gen_movi_i32(tmp, val);
+                            } else if (user) {
+                                tmp = tcg_temp_new_i32();
+                                tmp2 = tcg_const_i32(i);
+                                gen_helper_get_user_reg(tmp, tmp2);
+                                tcg_temp_free_i32(tmp2);
+                            } else {
+                                tmp = load_reg(s, i);
+                            }
+                            gen_st32(tmp, addr, IS_USER(s));
+                        }
+                        j++;
+                        /* no need to add after the last transfer */
+                        if (j != n)
+                            tcg_gen_addi_i32(addr, addr, 4);
+                    }
+                }
+                if (insn & (1 << 21)) {
+                    /* write back */
+                    if (insn & (1 << 23)) {
+                        if (insn & (1 << 24)) {
+                            /* pre increment */
+                        } else {
+                            /* post increment */
+                            tcg_gen_addi_i32(addr, addr, 4);
+                        }
+                    } else {
+                        if (insn & (1 << 24)) {
+                            /* pre decrement */
+                            if (n != 1)
+                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                        } else {
+                            /* post decrement */
+                            tcg_gen_addi_i32(addr, addr, -(n * 4));
+                        }
+                    }
+                    store_reg(s, rn, addr);
+                } else {
+                    tcg_temp_free_i32(addr);
+                }
+                if (loaded_base) {
+                    store_reg(s, rn, loaded_var);
+                }
+                if ((insn & (1 << 22)) && !user) {
+                    /* Restore CPSR from SPSR.  */
+                    tmp = load_cpu_field(spsr);
+                    gen_set_cpsr(tmp, 0xffffffff);
+                    tcg_temp_free_i32(tmp);
+                    s->is_jmp = DISAS_UPDATE;
+                }
+            }
+            break;
+        case 0xa:
+        case 0xb:
+            {
+                int32_t offset;
+
+                /* branch (and link) */
+                val = (int32_t)s->pc;
+                if (insn & (1 << 24)) {
+                    tmp = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(tmp, val);
+                    store_reg(s, 14, tmp);
+                }
+                offset = (((int32_t)insn << 8) >> 8);
+                val += (offset << 2) + 4;
+                gen_jmp(s, val);
+            }
+            break;
+        case 0xc:
+        case 0xd:
+        case 0xe:
+            /* Coprocessor.  */
+            if (disas_coproc_insn(env, s, insn))
+                goto illegal_op;
+            break;
+        case 0xf:
+            /* swi */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_SWI;
+            break;
+        default:
+        illegal_op:
+            gen_exception_insn(s, 4, EXCP_UDEF);
+            break;
+        }
+    }
+}
+
+/* Return true if this is a Thumb-2 logical op.  */
+static int
+thumb2_logic_op(int op)
+{
+    return (op < 8);
+}
+
+/* Generate code for a Thumb-2 data processing operation.  If CONDS is nonzero
+   then set condition code flags based on the result of the operation.
+   If SHIFTER_OUT is nonzero then set the carry flag for logical operations
+   to the high bit of T1.
+   Returns zero if the opcode is valid.  */
+
+static int
+gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1)
+{
+    int logic_cc;
+
+    logic_cc = 0;
+    switch (op) {
+    case 0: /* and */
+        tcg_gen_and_i32(t0, t0, t1);
+        logic_cc = conds;
+        break;
+    case 1: /* bic */
+        tcg_gen_andc_i32(t0, t0, t1);
+        logic_cc = conds;
+        break;
+    case 2: /* orr */
+        tcg_gen_or_i32(t0, t0, t1);
+        logic_cc = conds;
+        break;
+    case 3: /* orn */
+        tcg_gen_orc_i32(t0, t0, t1);
+        logic_cc = conds;
+        break;
+    case 4: /* eor */
+        tcg_gen_xor_i32(t0, t0, t1);
+        logic_cc = conds;
+        break;
+    case 8: /* add */
+        if (conds)
+            gen_helper_add_cc(t0, t0, t1);
+        else
+            tcg_gen_add_i32(t0, t0, t1);
+        break;
+    case 10: /* adc */
+        if (conds)
+            gen_helper_adc_cc(t0, t0, t1);
+        else
+            gen_adc(t0, t1);
+        break;
+    case 11: /* sbc */
+        if (conds)
+            gen_helper_sbc_cc(t0, t0, t1);
+        else
+            gen_sub_carry(t0, t0, t1);
+        break;
+    case 13: /* sub */
+        if (conds)
+            gen_helper_sub_cc(t0, t0, t1);
+        else
+            tcg_gen_sub_i32(t0, t0, t1);
+        break;
+    case 14: /* rsb */
+        if (conds)
+            gen_helper_sub_cc(t0, t1, t0);
+        else
+            tcg_gen_sub_i32(t0, t1, t0);
+        break;
+    default: /* 5, 6, 7, 9, 12, 15. */
+        return 1;
+    }
+    if (logic_cc) {
+        gen_logic_CC(t0);
+        if (shifter_out)
+            gen_set_CF_bit31(t1);
+    }
+    return 0;
+}
+
+/* Translate a 32-bit thumb instruction.  Returns nonzero if the instruction
+   is not legal.  */
+static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
+{
+    uint32_t insn, imm, shift, offset;
+    uint32_t rd, rn, rm, rs;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv tmp3;
+    TCGv addr;
+    TCGv_i64 tmp64;
+    int op;
+    int shiftop;
+    int conds;
+    int logic_cc;
+
+    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
+          || arm_feature (env, ARM_FEATURE_M))) {
+        /* Thumb-1 cores may need to treat bl and blx as a pair of
+           16-bit instructions to get correct prefetch abort behavior.  */
+        insn = insn_hw1;
+        if ((insn & (1 << 12)) == 0) {
+            ARCH(5);
+            /* Second half of blx.  */
+            offset = ((insn & 0x7ff) << 1);
+            tmp = load_reg(s, 14);
+            tcg_gen_addi_i32(tmp, tmp, offset);
+            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
+
+            tmp2 = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp2, s->pc | 1);
+            store_reg(s, 14, tmp2);
+            gen_bx(s, tmp);
+            return 0;
+        }
+        if (insn & (1 << 11)) {
+            /* Second half of bl.  */
+            offset = ((insn & 0x7ff) << 1) | 1;
+            tmp = load_reg(s, 14);
+            tcg_gen_addi_i32(tmp, tmp, offset);
+
+            tmp2 = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp2, s->pc | 1);
+            store_reg(s, 14, tmp2);
+            gen_bx(s, tmp);
+            return 0;
+        }
+        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
+            /* Instruction spans a page boundary.  Implement it as two
+               16-bit instructions in case the second half causes an
+               prefetch abort.  */
+            offset = ((int32_t)insn << 21) >> 9;
+            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
+            return 0;
+        }
+        /* Fall through to 32-bit decode.  */
+    }
+
+    insn = lduw_code(s->pc);
+    s->pc += 2;
+    insn |= (uint32_t)insn_hw1 << 16;
+
+    if ((insn & 0xf800e800) != 0xf000e800) {
+        ARCH(6T2);
+    }
+
+    rn = (insn >> 16) & 0xf;
+    rs = (insn >> 12) & 0xf;
+    rd = (insn >> 8) & 0xf;
+    rm = insn & 0xf;
+    switch ((insn >> 25) & 0xf) {
+    case 0: case 1: case 2: case 3:
+        /* 16-bit instructions.  Should never happen.  */
+        abort();
+    case 4:
+        if (insn & (1 << 22)) {
+            /* Other load/store, table branch.  */
+            if (insn & 0x01200000) {
+                /* Load/store doubleword.  */
+                if (rn == 15) {
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~3);
+                } else {
+                    addr = load_reg(s, rn);
+                }
+                offset = (insn & 0xff) * 4;
+                if ((insn & (1 << 23)) == 0)
+                    offset = -offset;
+                if (insn & (1 << 24)) {
+                    tcg_gen_addi_i32(addr, addr, offset);
+                    offset = 0;
+                }
+                if (insn & (1 << 20)) {
+                    /* ldrd */
+                    tmp = gen_ld32(addr, IS_USER(s));
+                    store_reg(s, rs, tmp);
+                    tcg_gen_addi_i32(addr, addr, 4);
+                    tmp = gen_ld32(addr, IS_USER(s));
+                    store_reg(s, rd, tmp);
+                } else {
+                    /* strd */
+                    tmp = load_reg(s, rs);
+                    gen_st32(tmp, addr, IS_USER(s));
+                    tcg_gen_addi_i32(addr, addr, 4);
+                    tmp = load_reg(s, rd);
+                    gen_st32(tmp, addr, IS_USER(s));
+                }
+                if (insn & (1 << 21)) {
+                    /* Base writeback.  */
+                    if (rn == 15)
+                        goto illegal_op;
+                    tcg_gen_addi_i32(addr, addr, offset - 4);
+                    store_reg(s, rn, addr);
+                } else {
+                    tcg_temp_free_i32(addr);
+                }
+            } else if ((insn & (1 << 23)) == 0) {
+                /* Load/store exclusive word.  */
+                addr = tcg_temp_local_new();
+                load_reg_var(s, addr, rn);
+                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
+                if (insn & (1 << 20)) {
+                    gen_load_exclusive(s, rs, 15, addr, 2);
+                } else {
+                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
+                }
+                tcg_temp_free(addr);
+            } else if ((insn & (1 << 6)) == 0) {
+                /* Table Branch.  */
+                if (rn == 15) {
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc);
+                } else {
+                    addr = load_reg(s, rn);
+                }
+                tmp = load_reg(s, rm);
+                tcg_gen_add_i32(addr, addr, tmp);
+                if (insn & (1 << 4)) {
+                    /* tbh */
+                    tcg_gen_add_i32(addr, addr, tmp);
+                    tcg_temp_free_i32(tmp);
+                    tmp = gen_ld16u(addr, IS_USER(s));
+                } else { /* tbb */
+                    tcg_temp_free_i32(tmp);
+                    tmp = gen_ld8u(addr, IS_USER(s));
+                }
+                tcg_temp_free_i32(addr);
+                tcg_gen_shli_i32(tmp, tmp, 1);
+                tcg_gen_addi_i32(tmp, tmp, s->pc);
+                store_reg(s, 15, tmp);
+            } else {
+                /* Load/store exclusive byte/halfword/doubleword.  */
+                ARCH(7);
+                op = (insn >> 4) & 0x3;
+                if (op == 2) {
+                    goto illegal_op;
+                }
+                addr = tcg_temp_local_new();
+                load_reg_var(s, addr, rn);
+                if (insn & (1 << 20)) {
+                    gen_load_exclusive(s, rs, rd, addr, op);
+                } else {
+                    gen_store_exclusive(s, rm, rs, rd, addr, op);
+                }
+                tcg_temp_free(addr);
+            }
+        } else {
+            /* Load/store multiple, RFE, SRS.  */
+            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
+                /* Not available in user mode.  */
+                if (IS_USER(s))
+                    goto illegal_op;
+                if (insn & (1 << 20)) {
+                    /* rfe */
+                    addr = load_reg(s, rn);
+                    if ((insn & (1 << 24)) == 0)
+                        tcg_gen_addi_i32(addr, addr, -8);
+                    /* Load PC into tmp and CPSR into tmp2.  */
+                    tmp = gen_ld32(addr, 0);
+                    tcg_gen_addi_i32(addr, addr, 4);
+                    tmp2 = gen_ld32(addr, 0);
+                    if (insn & (1 << 21)) {
+                        /* Base writeback.  */
+                        if (insn & (1 << 24)) {
+                            tcg_gen_addi_i32(addr, addr, 4);
+                        } else {
+                            tcg_gen_addi_i32(addr, addr, -4);
+                        }
+                        store_reg(s, rn, addr);
+                    } else {
+                        tcg_temp_free_i32(addr);
+                    }
+                    gen_rfe(s, tmp, tmp2);
+                } else {
+                    /* srs */
+                    op = (insn & 0x1f);
+                    addr = tcg_temp_new_i32();
+                    tmp = tcg_const_i32(op);
+                    gen_helper_get_r13_banked(addr, cpu_env, tmp);
+                    tcg_temp_free_i32(tmp);
+                    if ((insn & (1 << 24)) == 0) {
+                        tcg_gen_addi_i32(addr, addr, -8);
+                    }
+                    tmp = load_reg(s, 14);
+                    gen_st32(tmp, addr, 0);
+                    tcg_gen_addi_i32(addr, addr, 4);
+                    tmp = tcg_temp_new_i32();
+                    gen_helper_cpsr_read(tmp);
+                    gen_st32(tmp, addr, 0);
+                    if (insn & (1 << 21)) {
+                        if ((insn & (1 << 24)) == 0) {
+                            tcg_gen_addi_i32(addr, addr, -4);
+                        } else {
+                            tcg_gen_addi_i32(addr, addr, 4);
+                        }
+                        tmp = tcg_const_i32(op);
+                        gen_helper_set_r13_banked(cpu_env, tmp, addr);
+                        tcg_temp_free_i32(tmp);
+                    } else {
+                        tcg_temp_free_i32(addr);
+                    }
+                }
+            } else {
+                int i, loaded_base = 0;
+                TCGv loaded_var;
+                /* Load/store multiple.  */
+                addr = load_reg(s, rn);
+                offset = 0;
+                for (i = 0; i < 16; i++) {
+                    if (insn & (1 << i))
+                        offset += 4;
+                }
+                if (insn & (1 << 24)) {
+                    tcg_gen_addi_i32(addr, addr, -offset);
+                }
+
+                TCGV_UNUSED(loaded_var);
+                for (i = 0; i < 16; i++) {
+                    if ((insn & (1 << i)) == 0)
+                        continue;
+                    if (insn & (1 << 20)) {
+                        /* Load.  */
+                        tmp = gen_ld32(addr, IS_USER(s));
+                        if (i == 15) {
+                            gen_bx(s, tmp);
+                        } else if (i == rn) {
+                            loaded_var = tmp;
+                            loaded_base = 1;
+                        } else {
+                            store_reg(s, i, tmp);
+                        }
+                    } else {
+                        /* Store.  */
+                        tmp = load_reg(s, i);
+                        gen_st32(tmp, addr, IS_USER(s));
+                    }
+                    tcg_gen_addi_i32(addr, addr, 4);
+                }
+                if (loaded_base) {
+                    store_reg(s, rn, loaded_var);
+                }
+                if (insn & (1 << 21)) {
+                    /* Base register writeback.  */
+                    if (insn & (1 << 24)) {
+                        tcg_gen_addi_i32(addr, addr, -offset);
+                    }
+                    /* Fault if writeback register is in register list.  */
+                    if (insn & (1 << rn))
+                        goto illegal_op;
+                    store_reg(s, rn, addr);
+                } else {
+                    tcg_temp_free_i32(addr);
+                }
+            }
+        }
+        break;
+    case 5:
+
+        op = (insn >> 21) & 0xf;
+        if (op == 6) {
+            /* Halfword pack.  */
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
+            if (insn & (1 << 5)) {
+                /* pkhtb */
+                if (shift == 0)
+                    shift = 31;
+                tcg_gen_sari_i32(tmp2, tmp2, shift);
+                tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
+                tcg_gen_ext16u_i32(tmp2, tmp2);
+            } else {
+                /* pkhbt */
+                if (shift)
+                    tcg_gen_shli_i32(tmp2, tmp2, shift);
+                tcg_gen_ext16u_i32(tmp, tmp);
+                tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
+            }
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            tcg_temp_free_i32(tmp2);
+            store_reg(s, rd, tmp);
+        } else {
+            /* Data processing register constant shift.  */
+            if (rn == 15) {
+                tmp = tcg_temp_new_i32();
+                tcg_gen_movi_i32(tmp, 0);
+            } else {
+                tmp = load_reg(s, rn);
+            }
+            tmp2 = load_reg(s, rm);
+
+            shiftop = (insn >> 4) & 3;
+            shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
+            conds = (insn & (1 << 20)) != 0;
+            logic_cc = (conds && thumb2_logic_op(op));
+            gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
+            if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
+                goto illegal_op;
+            tcg_temp_free_i32(tmp2);
+            if (rd != 15) {
+                store_reg(s, rd, tmp);
+            } else {
+                tcg_temp_free_i32(tmp);
+            }
+        }
+        break;
+    case 13: /* Misc data processing.  */
+        op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
+        if (op < 4 && (insn & 0xf000) != 0xf000)
+            goto illegal_op;
+        switch (op) {
+        case 0: /* Register controlled shift.  */
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            if ((insn & 0x70) != 0)
+                goto illegal_op;
+            op = (insn >> 21) & 3;
+            logic_cc = (insn & (1 << 20)) != 0;
+            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
+            if (logic_cc)
+                gen_logic_CC(tmp);
+            store_reg_bx(env, s, rd, tmp);
+            break;
+        case 1: /* Sign/zero extend.  */
+            tmp = load_reg(s, rm);
+            shift = (insn >> 4) & 3;
+            /* ??? In many cases it's not necessary to do a
+               rotate, a shift is sufficient.  */
+            if (shift != 0)
+                tcg_gen_rotri_i32(tmp, tmp, shift * 8);
+            op = (insn >> 20) & 7;
+            switch (op) {
+            case 0: gen_sxth(tmp);   break;
+            case 1: gen_uxth(tmp);   break;
+            case 2: gen_sxtb16(tmp); break;
+            case 3: gen_uxtb16(tmp); break;
+            case 4: gen_sxtb(tmp);   break;
+            case 5: gen_uxtb(tmp);   break;
+            default: goto illegal_op;
+            }
+            if (rn != 15) {
+                tmp2 = load_reg(s, rn);
+                if ((op >> 1) == 1) {
+                    gen_add16(tmp, tmp2);
+                } else {
+                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                }
+            }
+            store_reg(s, rd, tmp);
+            break;
+        case 2: /* SIMD add/subtract.  */
+            op = (insn >> 20) & 7;
+            shift = (insn >> 4) & 7;
+            if ((op & 3) == 3 || (shift & 3) == 3)
+                goto illegal_op;
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
+            tcg_temp_free_i32(tmp2);
+            store_reg(s, rd, tmp);
+            break;
+        case 3: /* Other data processing.  */
+            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
+            if (op < 4) {
+                /* Saturating add/subtract.  */
+                tmp = load_reg(s, rn);
+                tmp2 = load_reg(s, rm);
+                if (op & 1)
+                    gen_helper_double_saturate(tmp, tmp);
+                if (op & 2)
+                    gen_helper_sub_saturate(tmp, tmp2, tmp);
+                else
+                    gen_helper_add_saturate(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+            } else {
+                tmp = load_reg(s, rn);
+                switch (op) {
+                case 0x0a: /* rbit */
+                    gen_helper_rbit(tmp, tmp);
+                    break;
+                case 0x08: /* rev */
+                    tcg_gen_bswap32_i32(tmp, tmp);
+                    break;
+                case 0x09: /* rev16 */
+                    gen_rev16(tmp);
+                    break;
+                case 0x0b: /* revsh */
+                    gen_revsh(tmp);
+                    break;
+                case 0x10: /* sel */
+                    tmp2 = load_reg(s, rm);
+                    tmp3 = tcg_temp_new_i32();
+                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
+                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
+                    tcg_temp_free_i32(tmp3);
+                    tcg_temp_free_i32(tmp2);
+                    break;
+                case 0x18: /* clz */
+                    gen_helper_clz(tmp, tmp);
+                    break;
+                default:
+                    goto illegal_op;
+                }
+            }
+            store_reg(s, rd, tmp);
+            break;
+        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
+            op = (insn >> 4) & 0xf;
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            switch ((insn >> 20) & 7) {
+            case 0: /* 32 x 32 -> 32 */
+                tcg_gen_mul_i32(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                if (rs != 15) {
+                    tmp2 = load_reg(s, rs);
+                    if (op)
+                        tcg_gen_sub_i32(tmp, tmp2, tmp);
+                    else
+                        tcg_gen_add_i32(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                }
+                break;
+            case 1: /* 16 x 16 -> 32 */
+                gen_mulxy(tmp, tmp2, op & 2, op & 1);
+                tcg_temp_free_i32(tmp2);
+                if (rs != 15) {
+                    tmp2 = load_reg(s, rs);
+                    gen_helper_add_setq(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                }
+                break;
+            case 2: /* Dual multiply add.  */
+            case 4: /* Dual multiply subtract.  */
+                if (op)
+                    gen_swap_half(tmp2);
+                gen_smul_dual(tmp, tmp2);
+                if (insn & (1 << 22)) {
+                    /* This subtraction cannot overflow. */
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                } else {
+                    /* This addition cannot overflow 32 bits;
+                     * however it may overflow considered as a signed
+                     * operation, in which case we must set the Q flag.
+                     */
+                    gen_helper_add_setq(tmp, tmp, tmp2);
+                }
+                tcg_temp_free_i32(tmp2);
+                if (rs != 15)
+                  {
+                    tmp2 = load_reg(s, rs);
+                    gen_helper_add_setq(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                  }
+                break;
+            case 3: /* 32 * 16 -> 32msb */
+                if (op)
+                    tcg_gen_sari_i32(tmp2, tmp2, 16);
+                else
+                    gen_sxth(tmp2);
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                tcg_gen_shri_i64(tmp64, tmp64, 16);
+                tmp = tcg_temp_new_i32();
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
+                tcg_temp_free_i64(tmp64);
+                if (rs != 15)
+                  {
+                    tmp2 = load_reg(s, rs);
+                    gen_helper_add_setq(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                  }
+                break;
+            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                if (rs != 15) {
+                    tmp = load_reg(s, rs);
+                    if (insn & (1 << 20)) {
+                        tmp64 = gen_addq_msw(tmp64, tmp);
+                    } else {
+                        tmp64 = gen_subq_msw(tmp64, tmp);
+                    }
+                }
+                if (insn & (1 << 4)) {
+                    tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
+                }
+                tcg_gen_shri_i64(tmp64, tmp64, 32);
+                tmp = tcg_temp_new_i32();
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
+                tcg_temp_free_i64(tmp64);
+                break;
+            case 7: /* Unsigned sum of absolute differences.  */
+                gen_helper_usad8(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                if (rs != 15) {
+                    tmp2 = load_reg(s, rs);
+                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                }
+                break;
+            }
+            store_reg(s, rd, tmp);
+            break;
+        case 6: case 7: /* 64-bit multiply, Divide.  */
+            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            if ((op & 0x50) == 0x10) {
+                /* sdiv, udiv */
+                if (!arm_feature(env, ARM_FEATURE_DIV))
+                    goto illegal_op;
+                if (op & 0x20)
+                    gen_helper_udiv(tmp, tmp, tmp2);
+                else
+                    gen_helper_sdiv(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                store_reg(s, rd, tmp);
+            } else if ((op & 0xe) == 0xc) {
+                /* Dual multiply accumulate long.  */
+                if (op & 1)
+                    gen_swap_half(tmp2);
+                gen_smul_dual(tmp, tmp2);
+                if (op & 0x10) {
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                } else {
+                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                }
+                tcg_temp_free_i32(tmp2);
+                /* BUGFIX */
+                tmp64 = tcg_temp_new_i64();
+                tcg_gen_ext_i32_i64(tmp64, tmp);
+                tcg_temp_free_i32(tmp);
+                gen_addq(s, tmp64, rs, rd);
+                gen_storeq_reg(s, rs, rd, tmp64);
+                tcg_temp_free_i64(tmp64);
+            } else {
+                if (op & 0x20) {
+                    /* Unsigned 64-bit multiply  */
+                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+                } else {
+                    if (op & 8) {
+                        /* smlalxy */
+                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
+                        tcg_temp_free_i32(tmp2);
+                        tmp64 = tcg_temp_new_i64();
+                        tcg_gen_ext_i32_i64(tmp64, tmp);
+                        tcg_temp_free_i32(tmp);
+                    } else {
+                        /* Signed 64-bit multiply  */
+                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                    }
+                }
+                if (op & 4) {
+                    /* umaal */
+                    gen_addq_lo(s, tmp64, rs);
+                    gen_addq_lo(s, tmp64, rd);
+                } else if (op & 0x40) {
+                    /* 64-bit accumulate.  */
+                    gen_addq(s, tmp64, rs, rd);
+                }
+                gen_storeq_reg(s, rs, rd, tmp64);
+                tcg_temp_free_i64(tmp64);
+            }
+            break;
+        }
+        break;
+    case 6: case 7: case 14: case 15:
+        /* Coprocessor.  */
+        if (((insn >> 24) & 3) == 3) {
+            /* Translate into the equivalent ARM encoding.  */
+            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
+            if (disas_neon_data_insn(env, s, insn))
+                goto illegal_op;
+        } else {
+            if (insn & (1 << 28))
+                goto illegal_op;
+            if (disas_coproc_insn (env, s, insn))
+                goto illegal_op;
+        }
+        break;
+    case 8: case 9: case 10: case 11:
+        if (insn & (1 << 15)) {
+            /* Branches, misc control.  */
+            if (insn & 0x5000) {
+                /* Unconditional branch.  */
+                /* signextend(hw1[10:0]) -> offset[:12].  */
+                offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
+                /* hw1[10:0] -> offset[11:1].  */
+                offset |= (insn & 0x7ff) << 1;
+                /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
+                   offset[24:22] already have the same value because of the
+                   sign extension above.  */
+                offset ^= ((~insn) & (1 << 13)) << 10;
+                offset ^= ((~insn) & (1 << 11)) << 11;
+
+                if (insn & (1 << 14)) {
+                    /* Branch and link.  */
+                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
+                }
+
+                offset += s->pc;
+                if (insn & (1 << 12)) {
+                    /* b/bl */
+                    gen_jmp(s, offset);
+                } else {
+                    /* blx */
+                    offset &= ~(uint32_t)2;
+                    /* thumb2 bx, no need to check */
+                    gen_bx_im(s, offset);
+                }
+            } else if (((insn >> 23) & 7) == 7) {
+                /* Misc control */
+                if (insn & (1 << 13))
+                    goto illegal_op;
+
+                if (insn & (1 << 26)) {
+                    /* Secure monitor call (v6Z) */
+                    goto illegal_op; /* not implemented.  */
+                } else {
+                    op = (insn >> 20) & 7;
+                    switch (op) {
+                    case 0: /* msr cpsr.  */
+                        if (IS_M(env)) {
+                            tmp = load_reg(s, rn);
+                            addr = tcg_const_i32(insn & 0xff);
+                            gen_helper_v7m_msr(cpu_env, addr, tmp);
+                            tcg_temp_free_i32(addr);
+                            tcg_temp_free_i32(tmp);
+                            gen_lookup_tb(s);
+                            break;
+                        }
+                        /* fall through */
+                    case 1: /* msr spsr.  */
+                        if (IS_M(env))
+                            goto illegal_op;
+                        tmp = load_reg(s, rn);
+                        if (gen_set_psr(s,
+                              msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
+                              op == 1, tmp))
+                            goto illegal_op;
+                        break;
+                    case 2: /* cps, nop-hint.  */
+                        if (((insn >> 8) & 7) == 0) {
+                            gen_nop_hint(s, insn & 0xff);
+                        }
+                        /* Implemented as NOP in user mode.  */
+                        if (IS_USER(s))
+                            break;
+                        offset = 0;
+                        imm = 0;
+                        if (insn & (1 << 10)) {
+                            if (insn & (1 << 7))
+                                offset |= CPSR_A;
+                            if (insn & (1 << 6))
+                                offset |= CPSR_I;
+                            if (insn & (1 << 5))
+                                offset |= CPSR_F;
+                            if (insn & (1 << 9))
+                                imm = CPSR_A | CPSR_I | CPSR_F;
+                        }
+                        if (insn & (1 << 8)) {
+                            offset |= 0x1f;
+                            imm |= (insn & 0x1f);
+                        }
+                        if (offset) {
+                            gen_set_psr_im(s, offset, 0, imm);
+                        }
+                        break;
+                    case 3: /* Special control operations.  */
+                        ARCH(7);
+                        op = (insn >> 4) & 0xf;
+                        switch (op) {
+                        case 2: /* clrex */
+                            gen_clrex(s);
+                            break;
+                        case 4: /* dsb */
+                        case 5: /* dmb */
+                        case 6: /* isb */
+                            /* These execute as NOPs.  */
+                            break;
+                        default:
+                            goto illegal_op;
+                        }
+                        break;
+                    case 4: /* bxj */
+                        /* Trivial implementation equivalent to bx.  */
+                        tmp = load_reg(s, rn);
+                        gen_bx(s, tmp);
+                        break;
+                    case 5: /* Exception return.  */
+                        if (IS_USER(s)) {
+                            goto illegal_op;
+                        }
+                        if (rn != 14 || rd != 15) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rn);
+                        tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
+                        gen_exception_return(s, tmp);
+                        break;
+                    case 6: /* mrs cpsr.  */
+                        tmp = tcg_temp_new_i32();
+                        if (IS_M(env)) {
+                            addr = tcg_const_i32(insn & 0xff);
+                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
+                            tcg_temp_free_i32(addr);
+                        } else {
+                            gen_helper_cpsr_read(tmp);
+                        }
+                        store_reg(s, rd, tmp);
+                        break;
+                    case 7: /* mrs spsr.  */
+                        /* Not accessible in user mode.  */
+                        if (IS_USER(s) || IS_M(env))
+                            goto illegal_op;
+                        tmp = load_cpu_field(spsr);
+                        store_reg(s, rd, tmp);
+                        break;
+                    }
+                }
+            } else {
+                /* Conditional branch.  */
+                op = (insn >> 22) & 0xf;
+                /* Generate a conditional jump to next instruction.  */
+                s->condlabel = gen_new_label();
+                gen_test_cc(op ^ 1, s->condlabel);
+                s->condjmp = 1;
+
+                /* offset[11:1] = insn[10:0] */
+                offset = (insn & 0x7ff) << 1;
+                /* offset[17:12] = insn[21:16].  */
+                offset |= (insn & 0x003f0000) >> 4;
+                /* offset[31:20] = insn[26].  */
+                offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
+                /* offset[18] = insn[13].  */
+                offset |= (insn & (1 << 13)) << 5;
+                /* offset[19] = insn[11].  */
+                offset |= (insn & (1 << 11)) << 8;
+
+                /* jump to the offset */
+                gen_jmp(s, s->pc + offset);
+            }
+        } else {
+            /* Data processing immediate.  */
+            if (insn & (1 << 25)) {
+                if (insn & (1 << 24)) {
+                    if (insn & (1 << 20))
+                        goto illegal_op;
+                    /* Bitfield/Saturate.  */
+                    op = (insn >> 21) & 7;
+                    imm = insn & 0x1f;
+                    shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
+                    if (rn == 15) {
+                        tmp = tcg_temp_new_i32();
+                        tcg_gen_movi_i32(tmp, 0);
+                    } else {
+                        tmp = load_reg(s, rn);
+                    }
+                    switch (op) {
+                    case 2: /* Signed bitfield extract.  */
+                        imm++;
+                        if (shift + imm > 32)
+                            goto illegal_op;
+                        if (imm < 32)
+                            gen_sbfx(tmp, shift, imm);
+                        break;
+                    case 6: /* Unsigned bitfield extract.  */
+                        imm++;
+                        if (shift + imm > 32)
+                            goto illegal_op;
+                        if (imm < 32)
+                            gen_ubfx(tmp, shift, (1u << imm) - 1);
+                        break;
+                    case 3: /* Bitfield insert/clear.  */
+                        if (imm < shift)
+                            goto illegal_op;
+                        imm = imm + 1 - shift;
+                        if (imm != 32) {
+                            tmp2 = load_reg(s, rd);
+                            gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
+                            tcg_temp_free_i32(tmp2);
+                        }
+                        break;
+                    case 7:
+                        goto illegal_op;
+                    default: /* Saturate.  */
+                        if (shift) {
+                            if (op & 1)
+                                tcg_gen_sari_i32(tmp, tmp, shift);
+                            else
+                                tcg_gen_shli_i32(tmp, tmp, shift);
+                        }
+                        tmp2 = tcg_const_i32(imm);
+                        if (op & 4) {
+                            /* Unsigned.  */
+                            if ((op & 1) && shift == 0)
+                                gen_helper_usat16(tmp, tmp, tmp2);
+                            else
+                                gen_helper_usat(tmp, tmp, tmp2);
+                        } else {
+                            /* Signed.  */
+                            if ((op & 1) && shift == 0)
+                                gen_helper_ssat16(tmp, tmp, tmp2);
+                            else
+                                gen_helper_ssat(tmp, tmp, tmp2);
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        break;
+                    }
+                    store_reg(s, rd, tmp);
+                } else {
+                    imm = ((insn & 0x04000000) >> 15)
+                          | ((insn & 0x7000) >> 4) | (insn & 0xff);
+                    if (insn & (1 << 22)) {
+                        /* 16-bit immediate.  */
+                        imm |= (insn >> 4) & 0xf000;
+                        if (insn & (1 << 23)) {
+                            /* movt */
+                            tmp = load_reg(s, rd);
+                            tcg_gen_ext16u_i32(tmp, tmp);
+                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
+                        } else {
+                            /* movw */
+                            tmp = tcg_temp_new_i32();
+                            tcg_gen_movi_i32(tmp, imm);
+                        }
+                    } else {
+                        /* Add/sub 12-bit immediate.  */
+                        if (rn == 15) {
+                            offset = s->pc & ~(uint32_t)3;
+                            if (insn & (1 << 23))
+                                offset -= imm;
+                            else
+                                offset += imm;
+                            tmp = tcg_temp_new_i32();
+                            tcg_gen_movi_i32(tmp, offset);
+                        } else {
+                            tmp = load_reg(s, rn);
+                            if (insn & (1 << 23))
+                                tcg_gen_subi_i32(tmp, tmp, imm);
+                            else
+                                tcg_gen_addi_i32(tmp, tmp, imm);
+                        }
+                    }
+                    store_reg(s, rd, tmp);
+                }
+            } else {
+                int shifter_out = 0;
+                /* modified 12-bit immediate.  */
+                shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
+                imm = (insn & 0xff);
+                switch (shift) {
+                case 0: /* XY */
+                    /* Nothing to do.  */
+                    break;
+                case 1: /* 00XY00XY */
+                    imm |= imm << 16;
+                    break;
+                case 2: /* XY00XY00 */
+                    imm |= imm << 16;
+                    imm <<= 8;
+                    break;
+                case 3: /* XYXYXYXY */
+                    imm |= imm << 16;
+                    imm |= imm << 8;
+                    break;
+                default: /* Rotated constant.  */
+                    shift = (shift << 1) | (imm >> 7);
+                    imm |= 0x80;
+                    imm = imm << (32 - shift);
+                    shifter_out = 1;
+                    break;
+                }
+                tmp2 = tcg_temp_new_i32();
+                tcg_gen_movi_i32(tmp2, imm);
+                rn = (insn >> 16) & 0xf;
+                if (rn == 15) {
+                    tmp = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(tmp, 0);
+                } else {
+                    tmp = load_reg(s, rn);
+                }
+                op = (insn >> 21) & 0xf;
+                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
+                                       shifter_out, tmp, tmp2))
+                    goto illegal_op;
+                tcg_temp_free_i32(tmp2);
+                rd = (insn >> 8) & 0xf;
+                if (rd != 15) {
+                    store_reg(s, rd, tmp);
+                } else {
+                    tcg_temp_free_i32(tmp);
+                }
+            }
+        }
+        break;
+    case 12: /* Load/store single data item.  */
+        {
+        int postinc = 0;
+        int writeback = 0;
+        int user;
+        if ((insn & 0x01100000) == 0x01000000) {
+            if (disas_neon_ls_insn(env, s, insn))
+                goto illegal_op;
+            break;
+        }
+        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
+        if (rs == 15) {
+            if (!(insn & (1 << 20))) {
+                goto illegal_op;
+            }
+            if (op != 2) {
+                /* Byte or halfword load space with dest == r15 : memory hints.
+                 * Catch them early so we don't emit pointless addressing code.
+                 * This space is a mix of:
+                 *  PLD/PLDW/PLI,  which we implement as NOPs (note that unlike
+                 *     the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
+                 *     cores)
+                 *  unallocated hints, which must be treated as NOPs
+                 *  UNPREDICTABLE space, which we NOP or UNDEF depending on
+                 *     which is easiest for the decoding logic
+                 *  Some space which must UNDEF
+                 */
+                int op1 = (insn >> 23) & 3;
+                int op2 = (insn >> 6) & 0x3f;
+                if (op & 2) {
+                    goto illegal_op;
+                }
+                if (rn == 15) {
+                    /* UNPREDICTABLE or unallocated hint */
+                    return 0;
+                }
+                if (op1 & 1) {
+                    return 0; /* PLD* or unallocated hint */
+                }
+                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
+                    return 0; /* PLD* or unallocated hint */
+                }
+                /* UNDEF space, or an UNPREDICTABLE */
+                return 1;
+            }
+        }
+        user = IS_USER(s);
+        if (rn == 15) {
+            addr = tcg_temp_new_i32();
+            /* PC relative.  */
+            /* s->pc has already been incremented by 4.  */
+            imm = s->pc & 0xfffffffc;
+            if (insn & (1 << 23))
+                imm += insn & 0xfff;
+            else
+                imm -= insn & 0xfff;
+            tcg_gen_movi_i32(addr, imm);
+        } else {
+            addr = load_reg(s, rn);
+            if (insn & (1 << 23)) {
+                /* Positive offset.  */
+                imm = insn & 0xfff;
+                tcg_gen_addi_i32(addr, addr, imm);
+            } else {
+                imm = insn & 0xff;
+                switch ((insn >> 8) & 0xf) {
+                case 0x0: /* Shifted Register.  */
+                    shift = (insn >> 4) & 0xf;
+                    if (shift > 3) {
+                        tcg_temp_free_i32(addr);
+                        goto illegal_op;
+                    }
+                    tmp = load_reg(s, rm);
+                    if (shift)
+                        tcg_gen_shli_i32(tmp, tmp, shift);
+                    tcg_gen_add_i32(addr, addr, tmp);
+                    tcg_temp_free_i32(tmp);
+                    break;
+                case 0xc: /* Negative offset.  */
+                    tcg_gen_addi_i32(addr, addr, -imm);
+                    break;
+                case 0xe: /* User privilege.  */
+                    tcg_gen_addi_i32(addr, addr, imm);
+                    user = 1;
+                    break;
+                case 0x9: /* Post-decrement.  */
+                    imm = -imm;
+                    /* Fall through.  */
+                case 0xb: /* Post-increment.  */
+                    postinc = 1;
+                    writeback = 1;
+                    break;
+                case 0xd: /* Pre-decrement.  */
+                    imm = -imm;
+                    /* Fall through.  */
+                case 0xf: /* Pre-increment.  */
+                    tcg_gen_addi_i32(addr, addr, imm);
+                    writeback = 1;
+                    break;
+                default:
+                    tcg_temp_free_i32(addr);
+                    goto illegal_op;
+                }
+            }
+        }
+        if (insn & (1 << 20)) {
+            /* Load.  */
+            switch (op) {
+            case 0: tmp = gen_ld8u(addr, user); break;
+            case 4: tmp = gen_ld8s(addr, user); break;
+            case 1: tmp = gen_ld16u(addr, user); break;
+            case 5: tmp = gen_ld16s(addr, user); break;
+            case 2: tmp = gen_ld32(addr, user); break;
+            default:
+                tcg_temp_free_i32(addr);
+                goto illegal_op;
+            }
+            if (rs == 15) {
+                gen_bx(s, tmp);
+            } else {
+                store_reg(s, rs, tmp);
+            }
+        } else {
+            /* Store.  */
+            tmp = load_reg(s, rs);
+            switch (op) {
+            case 0: gen_st8(tmp, addr, user); break;
+            case 1: gen_st16(tmp, addr, user); break;
+            case 2: gen_st32(tmp, addr, user); break;
+            default:
+                tcg_temp_free_i32(addr);
+                goto illegal_op;
+            }
+        }
+        if (postinc)
+            tcg_gen_addi_i32(addr, addr, imm);
+        if (writeback) {
+            store_reg(s, rn, addr);
+        } else {
+            tcg_temp_free_i32(addr);
+        }
+        }
+        break;
+    default:
+        goto illegal_op;
+    }
+    return 0;
+illegal_op:
+    return 1;
+}
+
+static void disas_thumb_insn(CPUState *env, DisasContext *s)
+{
+    uint32_t val, insn, op, rm, rn, rd, shift, cond;
+    int32_t offset;
+    int i;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv addr;
+
+    if (s->condexec_mask) {
+        cond = s->condexec_cond;
+        if (cond != 0x0e) {     /* Skip conditional when condition is AL. */
+          s->condlabel = gen_new_label();
+          gen_test_cc(cond ^ 1, s->condlabel);
+          s->condjmp = 1;
+        }
+    }
+
+    insn = lduw_code(s->pc);
+    s->pc += 2;
+
+    switch (insn >> 12) {
+    case 0: case 1:
+
+        rd = insn & 7;
+        op = (insn >> 11) & 3;
+        if (op == 3) {
+            /* add/subtract */
+            rn = (insn >> 3) & 7;
+            tmp = load_reg(s, rn);
+            if (insn & (1 << 10)) {
+                /* immediate */
+                tmp2 = tcg_temp_new_i32();
+                tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
+            } else {
+                /* reg */
+                rm = (insn >> 6) & 7;
+                tmp2 = load_reg(s, rm);
+            }
+            if (insn & (1 << 9)) {
+                if (s->condexec_mask)
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                else
+                    gen_helper_sub_cc(tmp, tmp, tmp2);
+            } else {
+                if (s->condexec_mask)
+                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                else
+                    gen_helper_add_cc(tmp, tmp, tmp2);
+            }
+            tcg_temp_free_i32(tmp2);
+            store_reg(s, rd, tmp);
+        } else {
+            /* shift immediate */
+            rm = (insn >> 3) & 7;
+            shift = (insn >> 6) & 0x1f;
+            tmp = load_reg(s, rm);
+            gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            store_reg(s, rd, tmp);
+        }
+        break;
+    case 2: case 3:
+        /* arithmetic large immediate */
+        op = (insn >> 11) & 3;
+        rd = (insn >> 8) & 0x7;
+        if (op == 0) { /* mov */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp, insn & 0xff);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            store_reg(s, rd, tmp);
+        } else {
+            tmp = load_reg(s, rd);
+            tmp2 = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp2, insn & 0xff);
+            switch (op) {
+            case 1: /* cmp */
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp);
+                tcg_temp_free_i32(tmp2);
+                break;
+            case 2: /* add */
+                if (s->condexec_mask)
+                    tcg_gen_add_i32(tmp, tmp, tmp2);
+                else
+                    gen_helper_add_cc(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                store_reg(s, rd, tmp);
+                break;
+            case 3: /* sub */
+                if (s->condexec_mask)
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                else
+                    gen_helper_sub_cc(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                store_reg(s, rd, tmp);
+                break;
+            }
+        }
+        break;
+    case 4:
+        if (insn & (1 << 11)) {
+            rd = (insn >> 8) & 7;
+            /* load pc-relative.  Bit 1 of PC is ignored.  */
+            val = s->pc + 2 + ((insn & 0xff) * 4);
+            val &= ~(uint32_t)2;
+            addr = tcg_temp_new_i32();
+            tcg_gen_movi_i32(addr, val);
+            tmp = gen_ld32(addr, IS_USER(s));
+            tcg_temp_free_i32(addr);
+            store_reg(s, rd, tmp);
+            break;
+        }
+        if (insn & (1 << 10)) {
+            /* data processing extended or blx */
+            rd = (insn & 7) | ((insn >> 4) & 8);
+            rm = (insn >> 3) & 0xf;
+            op = (insn >> 8) & 3;
+            switch (op) {
+            case 0: /* add */
+                tmp = load_reg(s, rd);
+                tmp2 = load_reg(s, rm);
+                tcg_gen_add_i32(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                store_reg(s, rd, tmp);
+                break;
+            case 1: /* cmp */
+                tmp = load_reg(s, rd);
+                tmp2 = load_reg(s, rm);
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+                tcg_temp_free_i32(tmp2);
+                tcg_temp_free_i32(tmp);
+                break;
+            case 2: /* mov/cpy */
+                tmp = load_reg(s, rm);
+                store_reg(s, rd, tmp);
+                break;
+            case 3:/* branch [and link] exchange thumb register */
+                tmp = load_reg(s, rm);
+                if (insn & (1 << 7)) {
+                    ARCH(5);
+                    val = (uint32_t)s->pc | 1;
+                    tmp2 = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(tmp2, val);
+                    store_reg(s, 14, tmp2);
+                }
+                /* already thumb, no need to check */
+                gen_bx(s, tmp);
+                break;
+            }
+            break;
+        }
+
+        /* data processing register */
+        rd = insn & 7;
+        rm = (insn >> 3) & 7;
+        op = (insn >> 6) & 0xf;
+        if (op == 2 || op == 3 || op == 4 || op == 7) {
+            /* the shift/rotate ops want the operands backwards */
+            val = rm;
+            rm = rd;
+            rd = val;
+            val = 1;
+        } else {
+            val = 0;
+        }
+
+        if (op == 9) { /* neg */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp, 0);
+        } else if (op != 0xf) { /* mvn doesn't read its first operand */
+            tmp = load_reg(s, rd);
+        } else {
+            TCGV_UNUSED(tmp);
+        }
+
+        tmp2 = load_reg(s, rm);
+        switch (op) {
+        case 0x0: /* and */
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            break;
+        case 0x1: /* eor */
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            break;
+        case 0x2: /* lsl */
+            if (s->condexec_mask) {
+                gen_helper_shl(tmp2, tmp2, tmp);
+            } else {
+                gen_helper_shl_cc(tmp2, tmp2, tmp);
+                gen_logic_CC(tmp2);
+            }
+            break;
+        case 0x3: /* lsr */
+            if (s->condexec_mask) {
+                gen_helper_shr(tmp2, tmp2, tmp);
+            } else {
+                gen_helper_shr_cc(tmp2, tmp2, tmp);
+                gen_logic_CC(tmp2);
+            }
+            break;
+        case 0x4: /* asr */
+            if (s->condexec_mask) {
+                gen_helper_sar(tmp2, tmp2, tmp);
+            } else {
+                gen_helper_sar_cc(tmp2, tmp2, tmp);
+                gen_logic_CC(tmp2);
+            }
+            break;
+        case 0x5: /* adc */
+            if (s->condexec_mask)
+                gen_adc(tmp, tmp2);
+            else
+                gen_helper_adc_cc(tmp, tmp, tmp2);
+            break;
+        case 0x6: /* sbc */
+            if (s->condexec_mask)
+                gen_sub_carry(tmp, tmp, tmp2);
+            else
+                gen_helper_sbc_cc(tmp, tmp, tmp2);
+            break;
+        case 0x7: /* ror */
+            if (s->condexec_mask) {
+                tcg_gen_andi_i32(tmp, tmp, 0x1f);
+                tcg_gen_rotr_i32(tmp2, tmp2, tmp);
+            } else {
+                gen_helper_ror_cc(tmp2, tmp2, tmp);
+                gen_logic_CC(tmp2);
+            }
+            break;
+        case 0x8: /* tst */
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            gen_logic_CC(tmp);
+            rd = 16;
+            break;
+        case 0x9: /* neg */
+            if (s->condexec_mask)
+                tcg_gen_neg_i32(tmp, tmp2);
+            else
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+            break;
+        case 0xa: /* cmp */
+            gen_helper_sub_cc(tmp, tmp, tmp2);
+            rd = 16;
+            break;
+        case 0xb: /* cmn */
+            gen_helper_add_cc(tmp, tmp, tmp2);
+            rd = 16;
+            break;
+        case 0xc: /* orr */
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            break;
+        case 0xd: /* mul */
+            tcg_gen_mul_i32(tmp, tmp, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            break;
+        case 0xe: /* bic */
+            tcg_gen_andc_i32(tmp, tmp, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp);
+            break;
+        case 0xf: /* mvn */
+            tcg_gen_not_i32(tmp2, tmp2);
+            if (!s->condexec_mask)
+                gen_logic_CC(tmp2);
+            val = 1;
+            rm = rd;
+            break;
+        }
+        if (rd != 16) {
+            if (val) {
+                store_reg(s, rm, tmp2);
+                if (op != 0xf)
+                    tcg_temp_free_i32(tmp);
+            } else {
+                store_reg(s, rd, tmp);
+                tcg_temp_free_i32(tmp2);
+            }
+        } else {
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+        }
+        break;
+
+    case 5:
+        /* load/store register offset.  */
+        rd = insn & 7;
+        rn = (insn >> 3) & 7;
+        rm = (insn >> 6) & 7;
+        op = (insn >> 9) & 7;
+        addr = load_reg(s, rn);
+        tmp = load_reg(s, rm);
+        tcg_gen_add_i32(addr, addr, tmp);
+        tcg_temp_free_i32(tmp);
+
+        if (op < 3) /* store */
+            tmp = load_reg(s, rd);
+
+        switch (op) {
+        case 0: /* str */
+            gen_st32(tmp, addr, IS_USER(s));
+            break;
+        case 1: /* strh */
+            gen_st16(tmp, addr, IS_USER(s));
+            break;
+        case 2: /* strb */
+            gen_st8(tmp, addr, IS_USER(s));
+            break;
+        case 3: /* ldrsb */
+            tmp = gen_ld8s(addr, IS_USER(s));
+            break;
+        case 4: /* ldr */
+            tmp = gen_ld32(addr, IS_USER(s));
+            break;
+        case 5: /* ldrh */
+            tmp = gen_ld16u(addr, IS_USER(s));
+            break;
+        case 6: /* ldrb */
+            tmp = gen_ld8u(addr, IS_USER(s));
+            break;
+        case 7: /* ldrsh */
+            tmp = gen_ld16s(addr, IS_USER(s));
+            break;
+        }
+        if (op >= 3) /* load */
+            store_reg(s, rd, tmp);
+        tcg_temp_free_i32(addr);
+        break;
+
+    case 6:
+        /* load/store word immediate offset */
+        rd = insn & 7;
+        rn = (insn >> 3) & 7;
+        addr = load_reg(s, rn);
+        val = (insn >> 4) & 0x7c;
+        tcg_gen_addi_i32(addr, addr, val);
+
+        if (insn & (1 << 11)) {
+            /* load */
+            tmp = gen_ld32(addr, IS_USER(s));
+            store_reg(s, rd, tmp);
+        } else {
+            /* store */
+            tmp = load_reg(s, rd);
+            gen_st32(tmp, addr, IS_USER(s));
+        }
+        tcg_temp_free_i32(addr);
+        break;
+
+    case 7:
+        /* load/store byte immediate offset */
+        rd = insn & 7;
+        rn = (insn >> 3) & 7;
+        addr = load_reg(s, rn);
+        val = (insn >> 6) & 0x1f;
+        tcg_gen_addi_i32(addr, addr, val);
+
+        if (insn & (1 << 11)) {
+            /* load */
+            tmp = gen_ld8u(addr, IS_USER(s));
+            store_reg(s, rd, tmp);
+        } else {
+            /* store */
+            tmp = load_reg(s, rd);
+            gen_st8(tmp, addr, IS_USER(s));
+        }
+        tcg_temp_free_i32(addr);
+        break;
+
+    case 8:
+        /* load/store halfword immediate offset */
+        rd = insn & 7;
+        rn = (insn >> 3) & 7;
+        addr = load_reg(s, rn);
+        val = (insn >> 5) & 0x3e;
+        tcg_gen_addi_i32(addr, addr, val);
+
+        if (insn & (1 << 11)) {
+            /* load */
+            tmp = gen_ld16u(addr, IS_USER(s));
+            store_reg(s, rd, tmp);
+        } else {
+            /* store */
+            tmp = load_reg(s, rd);
+            gen_st16(tmp, addr, IS_USER(s));
+        }
+        tcg_temp_free_i32(addr);
+        break;
+
+    case 9:
+        /* load/store from stack */
+        rd = (insn >> 8) & 7;
+        addr = load_reg(s, 13);
+        val = (insn & 0xff) * 4;
+        tcg_gen_addi_i32(addr, addr, val);
+
+        if (insn & (1 << 11)) {
+            /* load */
+            tmp = gen_ld32(addr, IS_USER(s));
+            store_reg(s, rd, tmp);
+        } else {
+            /* store */
+            tmp = load_reg(s, rd);
+            gen_st32(tmp, addr, IS_USER(s));
+        }
+        tcg_temp_free_i32(addr);
+        break;
+
+    case 10:
+        /* add to high reg */
+        rd = (insn >> 8) & 7;
+        if (insn & (1 << 11)) {
+            /* SP */
+            tmp = load_reg(s, 13);
+        } else {
+            /* PC. bit 1 is ignored.  */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
+        }
+        val = (insn & 0xff) * 4;
+        tcg_gen_addi_i32(tmp, tmp, val);
+        store_reg(s, rd, tmp);
+        break;
+
+    case 11:
+        /* misc */
+        op = (insn >> 8) & 0xf;
+        switch (op) {
+        case 0:
+            /* adjust stack pointer */
+            tmp = load_reg(s, 13);
+            val = (insn & 0x7f) * 4;
+            if (insn & (1 << 7))
+                val = -(int32_t)val;
+            tcg_gen_addi_i32(tmp, tmp, val);
+            store_reg(s, 13, tmp);
+            break;
+
+        case 2: /* sign/zero extend.  */
+            ARCH(6);
+            rd = insn & 7;
+            rm = (insn >> 3) & 7;
+            tmp = load_reg(s, rm);
+            switch ((insn >> 6) & 3) {
+            case 0: gen_sxth(tmp); break;
+            case 1: gen_sxtb(tmp); break;
+            case 2: gen_uxth(tmp); break;
+            case 3: gen_uxtb(tmp); break;
+            }
+            store_reg(s, rd, tmp);
+            break;
+        case 4: case 5: case 0xc: case 0xd:
+            /* push/pop */
+            addr = load_reg(s, 13);
+            if (insn & (1 << 8))
+                offset = 4;
+            else
+                offset = 0;
+            for (i = 0; i < 8; i++) {
+                if (insn & (1 << i))
+                    offset += 4;
+            }
+            if ((insn & (1 << 11)) == 0) {
+                tcg_gen_addi_i32(addr, addr, -offset);
+            }
+            for (i = 0; i < 8; i++) {
+                if (insn & (1 << i)) {
+                    if (insn & (1 << 11)) {
+                        /* pop */
+                        tmp = gen_ld32(addr, IS_USER(s));
+                        store_reg(s, i, tmp);
+                    } else {
+                        /* push */
+                        tmp = load_reg(s, i);
+                        gen_st32(tmp, addr, IS_USER(s));
+                    }
+                    /* advance to the next address.  */
+                    tcg_gen_addi_i32(addr, addr, 4);
+                }
+            }
+            TCGV_UNUSED(tmp);
+            if (insn & (1 << 8)) {
+                if (insn & (1 << 11)) {
+                    /* pop pc */
+                    tmp = gen_ld32(addr, IS_USER(s));
+                    /* don't set the pc until the rest of the instruction
+                       has completed */
+                } else {
+                    /* push lr */
+                    tmp = load_reg(s, 14);
+                    gen_st32(tmp, addr, IS_USER(s));
+                }
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+            if ((insn & (1 << 11)) == 0) {
+                tcg_gen_addi_i32(addr, addr, -offset);
+            }
+            /* write back the new stack pointer */
+            store_reg(s, 13, addr);
+            /* set the new PC value */
+            if ((insn & 0x0900) == 0x0900) {
+                store_reg_from_load(env, s, 15, tmp);
+            }
+            break;
+
+        case 1: case 3: case 9: case 11: /* czb */
+            rm = insn & 7;
+            tmp = load_reg(s, rm);
+            s->condlabel = gen_new_label();
+            s->condjmp = 1;
+            if (insn & (1 << 11))
+                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
+            else
+                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
+            tcg_temp_free_i32(tmp);
+            offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
+            val = (uint32_t)s->pc + 2;
+            val += offset;
+            gen_jmp(s, val);
+            break;
+
+        case 15: /* IT, nop-hint.  */
+            if ((insn & 0xf) == 0) {
+                gen_nop_hint(s, (insn >> 4) & 0xf);
+                break;
+            }
+            /* If Then.  */
+            s->condexec_cond = (insn >> 4) & 0xe;
+            s->condexec_mask = insn & 0x1f;
+            /* No actual code generated for this insn, just setup state.  */
+            break;
+
+        case 0xe: /* bkpt */
+            ARCH(5);
+            gen_exception_insn(s, 2, EXCP_BKPT);
+            break;
+
+        case 0xa: /* rev */
+            ARCH(6);
+            rn = (insn >> 3) & 0x7;
+            rd = insn & 0x7;
+            tmp = load_reg(s, rn);
+            switch ((insn >> 6) & 3) {
+            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
+            case 1: gen_rev16(tmp); break;
+            case 3: gen_revsh(tmp); break;
+            default: goto illegal_op;
+            }
+            store_reg(s, rd, tmp);
+            break;
+
+        case 6: /* cps */
+            ARCH(6);
+            if (IS_USER(s))
+                break;
+            if (IS_M(env)) {
+                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
+                /* PRIMASK */
+                if (insn & 1) {
+                    addr = tcg_const_i32(16);
+                    gen_helper_v7m_msr(cpu_env, addr, tmp);
+                    tcg_temp_free_i32(addr);
+                }
+                /* FAULTMASK */
+                if (insn & 2) {
+                    addr = tcg_const_i32(17);
+                    gen_helper_v7m_msr(cpu_env, addr, tmp);
+                    tcg_temp_free_i32(addr);
+                }
+                tcg_temp_free_i32(tmp);
+                gen_lookup_tb(s);
+            } else {
+                if (insn & (1 << 4))
+                    shift = CPSR_A | CPSR_I | CPSR_F;
+                else
+                    shift = 0;
+                gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
+            }
+            break;
+
+        default:
+            goto undef;
+        }
+        break;
+
+    case 12:
+    {
+        /* load/store multiple */
+        TCGv loaded_var;
+        TCGV_UNUSED(loaded_var);
+        rn = (insn >> 8) & 0x7;
+        addr = load_reg(s, rn);
+        for (i = 0; i < 8; i++) {
+            if (insn & (1 << i)) {
+                if (insn & (1 << 11)) {
+                    /* load */
+                    tmp = gen_ld32(addr, IS_USER(s));
+                    if (i == rn) {
+                        loaded_var = tmp;
+                    } else {
+                        store_reg(s, i, tmp);
+                    }
+                } else {
+                    /* store */
+                    tmp = load_reg(s, i);
+                    gen_st32(tmp, addr, IS_USER(s));
+                }
+                /* advance to the next address */
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+        }
+        if ((insn & (1 << rn)) == 0) {
+            /* base reg not in list: base register writeback */
+            store_reg(s, rn, addr);
+        } else {
+            /* base reg in list: if load, complete it now */
+            if (insn & (1 << 11)) {
+                store_reg(s, rn, loaded_var);
+            }
+            tcg_temp_free_i32(addr);
+        }
+        break;
+    }
+    case 13:
+        /* conditional branch or swi */
+        cond = (insn >> 8) & 0xf;
+        if (cond == 0xe)
+            goto undef;
+
+        if (cond == 0xf) {
+            /* swi */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_SWI;
+            break;
+        }
+        /* generate a conditional jump to next instruction */
+        s->condlabel = gen_new_label();
+        gen_test_cc(cond ^ 1, s->condlabel);
+        s->condjmp = 1;
+
+        /* jump to the offset */
+        val = (uint32_t)s->pc + 2;
+        offset = ((int32_t)insn << 24) >> 24;
+        val += offset << 1;
+        gen_jmp(s, val);
+        break;
+
+    case 14:
+        if (insn & (1 << 11)) {
+            if (disas_thumb2_insn(env, s, insn))
+              goto undef32;
+            break;
+        }
+        /* unconditional branch */
+        val = (uint32_t)s->pc;
+        offset = ((int32_t)insn << 21) >> 21;
+        val += (offset << 1) + 2;
+        gen_jmp(s, val);
+        break;
+
+    case 15:
+        if (disas_thumb2_insn(env, s, insn))
+            goto undef32;
+        break;
+    }
+    return;
+undef32:
+    gen_exception_insn(s, 4, EXCP_UDEF);
+    return;
+illegal_op:
+undef:
+    gen_exception_insn(s, 2, EXCP_UDEF);
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+   basic block 'tb'. If search_pc is TRUE, also generate PC
+   information for each intermediate instruction. */
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
+    uint16_t *gen_opc_end;
+    int j, lj;
+    target_ulong pc_start;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    pc_start = tb->pc;
+
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->condjmp = 0;
+    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
+    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
+    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
+#if !defined(CONFIG_USER_ONLY)
+    dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
+#endif
+    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
+    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
+    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
+    cpu_F0s = tcg_temp_new_i32();
+    cpu_F1s = tcg_temp_new_i32();
+    cpu_F0d = tcg_temp_new_i64();
+    cpu_F1d = tcg_temp_new_i64();
+    cpu_V0 = cpu_F0d;
+    cpu_V1 = cpu_F1d;
+    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
+    cpu_M0 = tcg_temp_new_i64();
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+
+    tcg_clear_temp_count();
+
+    /* A note on handling of the condexec (IT) bits:
+     *
+     * We want to avoid the overhead of having to write the updated condexec
+     * bits back to the CPUState for every instruction in an IT block. So:
+     * (1) if the condexec bits are not already zero then we write
+     * zero back into the CPUState now. This avoids complications trying
+     * to do it at the end of the block. (For example if we don't do this
+     * it's hard to identify whether we can safely skip writing condexec
+     * at the end of the TB, which we definitely want to do for the case
+     * where a TB doesn't do anything with the IT state at all.)
+     * (2) if we are going to leave the TB then we call gen_set_condexec()
+     * which will write the correct value into CPUState if zero is wrong.
+     * This is done both for leaving the TB at the end, and for leaving
+     * it because of an exception we know will happen, which is done in
+     * gen_exception_insn(). The latter is necessary because we need to
+     * leave the TB with the PC/IT state just prior to execution of the
+     * instruction which caused the exception.
+     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
+     * then the CPUState will be wrong and we need to reset it.
+     * This is handled in the same way as restoration of the
+     * PC in these situations: we will be called again with search_pc=1
+     * and generate a mapping of the condexec bits for each PC in
+     * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
+     * this to restore the condexec bits.
+     *
+     * Note that there are no instructions which can read the condexec
+     * bits, and none which can write non-static values to them, so
+     * we don't need to care about whether CPUState is correct in the
+     * middle of a TB.
+     */
+
+    /* Reset the conditional execution bits immediately. This avoids
+       complications trying to do it at the end of the block.  */
+    if (dc->condexec_mask || dc->condexec_cond)
+      {
+        TCGv tmp = tcg_temp_new_i32();
+        tcg_gen_movi_i32(tmp, 0);
+        store_cpu_field(tmp, condexec_bits);
+      }
+    do {
+#ifdef CONFIG_USER_ONLY
+        /* Intercept jump to the magic kernel page.  */
+        if (dc->pc >= 0xffff0000) {
+            /* We always get here via a jump, so know we are not in a
+               conditional execution block.  */
+            gen_exception(EXCP_KERNEL_TRAP);
+            dc->is_jmp = DISAS_UPDATE;
+            break;
+        }
+#else
+        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
+            /* We always get here via a jump, so know we are not in a
+               conditional execution block.  */
+            gen_exception(EXCP_EXCEPTION_EXIT);
+            dc->is_jmp = DISAS_UPDATE;
+            break;
+        }
+#endif
+
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
+                    gen_exception_insn(dc, 0, EXCP_DEBUG);
+                    /* Advance PC so that clearing the breakpoint will
+                       invalidate this TB.  */
+                    dc->pc += 2;
+                    goto done_generating;
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc->pc);
+        }
+
+        if (dc->thumb) {
+            disas_thumb_insn(env, dc);
+            if (dc->condexec_mask) {
+                dc->condexec_cond = (dc->condexec_cond & 0xe)
+                                   | ((dc->condexec_mask >> 4) & 1);
+                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
+                if (dc->condexec_mask == 0) {
+                    dc->condexec_cond = 0;
+                }
+            }
+        } else {
+            disas_arm_insn(env, dc);
+        }
+
+        if (dc->condjmp && !dc->is_jmp) {
+            gen_set_label(dc->condlabel);
+            dc->condjmp = 0;
+        }
+
+        if (tcg_check_temp_count()) {
+            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
+        }
+
+        /* Translation stops when a conditional branch is encountered.
+         * Otherwise the subsequent code could get translated several times.
+         * Also stop translation when a page boundary is reached.  This
+         * ensures prefetch aborts occur at the right place.  */
+        num_insns ++;
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+             !env->singlestep_enabled &&
+             !singlestep &&
+             dc->pc < next_page_start &&
+             num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        if (dc->condjmp) {
+            /* FIXME:  This can theoretically happen with self-modifying
+               code.  */
+            cpu_abort(env, "IO on conditional branch instruction");
+        }
+        gen_io_end();
+    }
+
+    /* At this stage dc->condjmp will only be set when the skipped
+       instruction was a conditional branch or trap, and the PC has
+       already been written.  */
+    if (unlikely(env->singlestep_enabled)) {
+        /* Make sure the pc is updated, and raise a debug exception.  */
+        if (dc->condjmp) {
+            gen_set_condexec(dc);
+            if (dc->is_jmp == DISAS_SWI) {
+                gen_exception(EXCP_SWI);
+            } else {
+                gen_exception(EXCP_DEBUG);
+            }
+            gen_set_label(dc->condlabel);
+        }
+        if (dc->condjmp || !dc->is_jmp) {
+            gen_set_pc_im(dc->pc);
+            dc->condjmp = 0;
+        }
+        gen_set_condexec(dc);
+        if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
+            gen_exception(EXCP_SWI);
+        } else {
+            /* FIXME: Single stepping a WFI insn will not halt
+               the CPU.  */
+            gen_exception(EXCP_DEBUG);
+        }
+    } else {
+        /* While branches must always occur at the end of an IT block,
+           there are a few other things that can cause us to terminate
+           the TB in the middel of an IT block:
+            - Exception generating instructions (bkpt, swi, undefined).
+            - Page boundaries.
+            - Hardware watchpoints.
+           Hardware breakpoints have already been handled and skip this code.
+         */
+        gen_set_condexec(dc);
+        switch(dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 1, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+        case DISAS_UPDATE:
+            /* indicate that the hash table must be used to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        case DISAS_WFI:
+            gen_helper_wfi();
+            break;
+        case DISAS_SWI:
+            gen_exception(EXCP_SWI);
+            break;
+        }
+        if (dc->condjmp) {
+            gen_set_label(dc->condlabel);
+            gen_set_condexec(dc);
+            gen_goto_tb(dc, 1, dc->pc);
+            dc->condjmp = 0;
+        }
+    }
+
+done_generating:
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc->pc - pc_start, dc->thumb);
+        qemu_log("\n");
+    }
+#endif
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+static const char *cpu_mode_names[16] = {
+  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
+  "???", "???", "???", "und", "???", "???", "???", "sys"
+};
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i;
+#if 0
+    union {
+        uint32_t i;
+        float s;
+    } s0, s1;
+    CPU_DoubleU d;
+    /* ??? This assumes float64 and double have the same layout.
+       Oh well, it's only debug dumps.  */
+    union {
+        float64 f64;
+        double d;
+    } d0;
+#endif
+    uint32_t psr;
+
+    for(i=0;i<16;i++) {
+        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3)
+            cpu_fprintf(f, "\n");
+        else
+            cpu_fprintf(f, " ");
+    }
+    psr = cpsr_read(env);
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
+                psr,
+                psr & (1 << 31) ? 'N' : '-',
+                psr & (1 << 30) ? 'Z' : '-',
+                psr & (1 << 29) ? 'C' : '-',
+                psr & (1 << 28) ? 'V' : '-',
+                psr & CPSR_T ? 'T' : 'A',
+                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
+
+#if 0
+    for (i = 0; i < 16; i++) {
+        d.d = env->vfp.regs[i];
+        s0.i = d.l.lower;
+        s1.i = d.l.upper;
+        d0.f64 = d.d;
+        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
+                    i * 2, (int)s0.i, s0.s,
+                    i * 2 + 1, (int)s1.i, s1.s,
+                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
+                    d0.d);
+    }
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
+#endif
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->regs[15] = gen_opc_pc[pc_pos];
+    env->condexec_bits = gen_opc_condexec_bits[pc_pos];
+}
diff --git a/qemu-0.15.x/target-cris/cpu.h b/qemu-0.15.x/target-cris/cpu.h
new file mode 100644
index 0000000..ecb0df1
--- /dev/null
+++ b/qemu-0.15.x/target-cris/cpu.h
@@ -0,0 +1,282 @@
+/*
+ *  CRIS virtual CPU header
+ *
+ *  Copyright (c) 2007 AXIS Communications AB
+ *  Written by Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_CRIS_H
+#define CPU_CRIS_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPUCRISState
+
+#include "cpu-defs.h"
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_CRIS
+
+#define EXCP_NMI        1
+#define EXCP_GURU       2
+#define EXCP_BUSFAULT   3
+#define EXCP_IRQ        4
+#define EXCP_BREAK      5
+
+/* CRIS-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+
+/* Register aliases. R0 - R15 */
+#define R_FP  8
+#define R_SP  14
+#define R_ACR 15
+
+/* Support regs, P0 - P15  */
+#define PR_BZ  0
+#define PR_VR  1
+#define PR_PID 2
+#define PR_SRS 3
+#define PR_WZ  4
+#define PR_EXS 5
+#define PR_EDA 6
+#define PR_PREFIX 6    /* On CRISv10 P6 is reserved, we use it as prefix.  */
+#define PR_MOF 7
+#define PR_DZ  8
+#define PR_EBP 9
+#define PR_ERP 10
+#define PR_SRP 11
+#define PR_NRP 12
+#define PR_CCS 13
+#define PR_USP 14
+#define PR_SPC 15
+
+/* CPU flags.  */
+#define Q_FLAG 0x80000000
+#define M_FLAG 0x40000000
+#define PFIX_FLAG 0x800      /* CRISv10 Only.  */
+#define S_FLAG 0x200
+#define R_FLAG 0x100
+#define P_FLAG 0x80
+#define U_FLAG 0x40
+#define I_FLAG 0x20
+#define X_FLAG 0x10
+#define N_FLAG 0x08
+#define Z_FLAG 0x04
+#define V_FLAG 0x02
+#define C_FLAG 0x01
+#define ALU_FLAGS 0x1F
+
+/* Condition codes.  */
+#define CC_CC   0
+#define CC_CS   1
+#define CC_NE   2
+#define CC_EQ   3
+#define CC_VC   4
+#define CC_VS   5
+#define CC_PL   6
+#define CC_MI   7
+#define CC_LS   8
+#define CC_HI   9
+#define CC_GE  10
+#define CC_LT  11
+#define CC_GT  12
+#define CC_LE  13
+#define CC_A   14
+#define CC_P   15
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUCRISState {
+	uint32_t regs[16];
+	/* P0 - P15 are referred to as special registers in the docs.  */
+	uint32_t pregs[16];
+
+	/* Pseudo register for the PC. Not directly accessible on CRIS.  */
+	uint32_t pc;
+
+	/* Pseudo register for the kernel stack.  */
+	uint32_t ksp;
+
+	/* Branch.  */
+	int dslot;
+	int btaken;
+	uint32_t btarget;
+
+	/* Condition flag tracking.  */
+	uint32_t cc_op;
+	uint32_t cc_mask;
+	uint32_t cc_dest;
+	uint32_t cc_src;
+	uint32_t cc_result;
+	/* size of the operation, 1 = byte, 2 = word, 4 = dword.  */
+	int cc_size;
+	/* X flag at the time of cc snapshot.  */
+	int cc_x;
+
+	/* CRIS has certain insns that lockout interrupts.  */
+	int locked_irq;
+	int interrupt_vector;
+	int fault_vector;
+	int trap_vector;
+
+	/* FIXME: add a check in the translator to avoid writing to support
+	   register sets beyond the 4th. The ISA allows up to 256! but in
+	   practice there is no core that implements more than 4.
+
+	   Support function registers are used to control units close to the
+	   core. Accesses do not pass down the normal hierarchy.
+	*/
+	uint32_t sregs[4][16];
+
+	/* Linear feedback shift reg in the mmu. Used to provide pseudo
+	   randomness for the 'hint' the mmu gives to sw for chosing valid
+	   sets on TLB refills.  */
+	uint32_t mmu_rand_lfsr;
+
+	/*
+	 * We just store the stores to the tlbset here for later evaluation
+	 * when the hw needs access to them.
+	 *
+	 * One for I and another for D.
+	 */
+	struct
+	{
+		uint32_t hi;
+		uint32_t lo;
+	} tlbsets[2][4][16];
+
+	CPU_COMMON
+
+	/* Members after CPU_COMMON are preserved across resets.  */
+	void *load_info;
+} CPUCRISState;
+
+CPUCRISState *cpu_cris_init(const char *cpu_model);
+int cpu_cris_exec(CPUCRISState *s);
+void cpu_cris_close(CPUCRISState *s);
+void do_interrupt(CPUCRISState *env);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_cris_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+
+enum {
+    CC_OP_DYNAMIC, /* Use env->cc_op  */
+    CC_OP_FLAGS,
+    CC_OP_CMP,
+    CC_OP_MOVE,
+    CC_OP_ADD,
+    CC_OP_ADDC,
+    CC_OP_MCP,
+    CC_OP_ADDU,
+    CC_OP_SUB,
+    CC_OP_SUBU,
+    CC_OP_NEG,
+    CC_OP_BTST,
+    CC_OP_MULS,
+    CC_OP_MULU,
+    CC_OP_DSTEP,
+    CC_OP_MSTEP,
+    CC_OP_BOUND,
+
+    CC_OP_OR,
+    CC_OP_AND,
+    CC_OP_XOR,
+    CC_OP_LSL,
+    CC_OP_LSR,
+    CC_OP_ASR,
+    CC_OP_LZ
+};
+
+/* CRIS uses 8k pages.  */
+#define TARGET_PAGE_BITS 13
+#define MMAP_SHIFT TARGET_PAGE_BITS
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define cpu_init cpu_cris_init
+#define cpu_exec cpu_cris_exec
+#define cpu_gen_code cpu_cris_gen_code
+#define cpu_signal_handler cpu_cris_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+	return !!(env->pregs[PR_CCS] & U_FLAG);
+}
+
+int cpu_cris_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_cris_handle_mmu_fault
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[14] = newsp;
+    env->regs[10] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUCRISState *env, target_ulong newtls)
+{
+	env->pregs[PR_PID] = (env->pregs[PR_PID] & 0xff) | newtls;
+}
+
+/* Support function regs.  */
+#define SFR_RW_GC_CFG      0][0
+#define SFR_RW_MM_CFG      env->pregs[PR_SRS]][0
+#define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1
+#define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2
+#define SFR_R_MM_CAUSE     env->pregs[PR_SRS]][3
+#define SFR_RW_MM_TLB_SEL  env->pregs[PR_SRS]][4
+#define SFR_RW_MM_TLB_LO   env->pregs[PR_SRS]][5
+#define SFR_RW_MM_TLB_HI   env->pregs[PR_SRS]][6
+
+#include "cpu-all.h"
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = env->dslot |
+            (env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG
+				     | X_FLAG | PFIX_FLAG));
+}
+
+#define cpu_list cris_cpu_list
+void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+#endif
diff --git a/qemu-0.15.x/target-cris/crisv10-decode.h b/qemu-0.15.x/target-cris/crisv10-decode.h
new file mode 100644
index 0000000..587fbdd
--- /dev/null
+++ b/qemu-0.15.x/target-cris/crisv10-decode.h
@@ -0,0 +1,107 @@
+/*
+ *  CRISv10 insn decoding macros.
+ *
+ *  Copyright (c) 2010 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define CRISV10_MODE_QIMMEDIATE  0
+#define CRISV10_MODE_REG         1
+#define CRISV10_MODE_INDIRECT    2
+#define CRISV10_MODE_AUTOINC     3
+
+/* Quick Immediate.  */
+#define CRISV10_QIMM_BCC_R0      0
+#define CRISV10_QIMM_BCC_R1      1
+#define CRISV10_QIMM_BCC_R2      2
+#define CRISV10_QIMM_BCC_R3      3
+
+#define CRISV10_QIMM_BDAP_R0     4
+#define CRISV10_QIMM_BDAP_R1     5
+#define CRISV10_QIMM_BDAP_R2     6
+#define CRISV10_QIMM_BDAP_R3     7
+
+#define CRISV10_QIMM_ADDQ        8
+#define CRISV10_QIMM_MOVEQ       9
+#define CRISV10_QIMM_SUBQ       10
+#define CRISV10_QIMM_CMPQ       11
+#define CRISV10_QIMM_ANDQ       12
+#define CRISV10_QIMM_ORQ        13
+#define CRISV10_QIMM_ASHQ       14
+#define CRISV10_QIMM_LSHQ       15
+
+
+#define CRISV10_REG_ADDX         0
+#define CRISV10_REG_MOVX         1
+#define CRISV10_REG_SUBX         2
+#define CRISV10_REG_LSL          3
+#define CRISV10_REG_ADDI         4
+#define CRISV10_REG_BIAP         5
+#define CRISV10_REG_NEG          6
+#define CRISV10_REG_BOUND        7
+#define CRISV10_REG_ADD          8
+#define CRISV10_REG_MOVE_R       9
+#define CRISV10_REG_MOVE_SPR_R   9
+#define CRISV10_REG_MOVE_R_SPR   8
+#define CRISV10_REG_SUB         10
+#define CRISV10_REG_CMP         11
+#define CRISV10_REG_AND         12
+#define CRISV10_REG_OR          13
+#define CRISV10_REG_ASR         14
+#define CRISV10_REG_LSR         15
+
+#define CRISV10_REG_BTST         3
+#define CRISV10_REG_SCC          4
+#define CRISV10_REG_SETF         6
+#define CRISV10_REG_CLEARF       7
+#define CRISV10_REG_BIAP         5
+#define CRISV10_REG_ABS         10
+#define CRISV10_REG_DSTEP       11
+#define CRISV10_REG_LZ          12
+#define CRISV10_REG_NOT         13
+#define CRISV10_REG_SWAP        13
+#define CRISV10_REG_XOR         14
+#define CRISV10_REG_MSTEP       15
+
+/* Indirect, var size.  */
+#define CRISV10_IND_TEST        14
+#define CRISV10_IND_MUL          4
+#define CRISV10_IND_BDAP_M       5
+#define CRISV10_IND_ADD          8
+#define CRISV10_IND_MOVE_M_R     9
+
+
+/* indirect fixed size.  */
+#define CRISV10_IND_ADDX         0
+#define CRISV10_IND_MOVX         1
+#define CRISV10_IND_SUBX         2
+#define CRISV10_IND_CMPX         3
+#define CRISV10_IND_JUMP_M       4
+#define CRISV10_IND_DIP          5
+#define CRISV10_IND_JUMP_R       6
+#define CRISV10_IND_BOUND        7
+#define CRISV10_IND_BCC_M        7
+#define CRISV10_IND_MOVE_M_SPR   8
+#define CRISV10_IND_MOVE_SPR_M   9
+#define CRISV10_IND_SUB         10
+#define CRISV10_IND_CMP         11
+#define CRISV10_IND_AND         12
+#define CRISV10_IND_OR          13
+#define CRISV10_IND_MOVE_R_M    15
+
+#define CRISV10_IND_MOVEM_M_R    14
+#define CRISV10_IND_MOVEM_R_M    15
+
diff --git a/qemu-0.15.x/target-cris/crisv32-decode.h b/qemu-0.15.x/target-cris/crisv32-decode.h
new file mode 100644
index 0000000..ed141de
--- /dev/null
+++ b/qemu-0.15.x/target-cris/crisv32-decode.h
@@ -0,0 +1,128 @@
+/*
+ *  CRIS insn decoding macros.
+ *
+ *  Copyright (c) 2007 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Convenient binary macros.  */
+#define HEX__(n) 0x##n##LU
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
+                 + ((x&0x000000F0LU)?2:0) \
+                 + ((x&0x00000F00LU)?4:0) \
+                 + ((x&0x0000F000LU)?8:0) \
+                 + ((x&0x000F0000LU)?16:0) \
+                 + ((x&0x00F00000LU)?32:0) \
+                 + ((x&0x0F000000LU)?64:0) \
+                 + ((x&0xF0000000LU)?128:0)
+#define B8(d) ((unsigned char)B8__(HEX__(d)))
+
+/* Quick imm.  */
+#define DEC_BCCQ     {B8(00000000), B8(11110000)}
+#define DEC_ADDOQ    {B8(00010000), B8(11110000)}
+#define DEC_ADDQ     {B8(00100000), B8(11111100)}
+#define DEC_MOVEQ    {B8(00100100), B8(11111100)}
+#define DEC_SUBQ     {B8(00101000), B8(11111100)}
+#define DEC_CMPQ     {B8(00101100), B8(11111100)}
+#define DEC_ANDQ     {B8(00110000), B8(11111100)}
+#define DEC_ORQ      {B8(00110100), B8(11111100)}
+#define DEC_BTSTQ    {B8(00111000), B8(11111110)}
+#define DEC_ASRQ     {B8(00111010), B8(11111110)}
+#define DEC_LSLQ     {B8(00111100), B8(11111110)}
+#define DEC_LSRQ     {B8(00111110), B8(11111110)}
+
+/* Register.  */
+#define DEC_MOVU_R   {B8(01000100), B8(11111110)}
+#define DEC_MOVU_R   {B8(01000100), B8(11111110)}
+#define DEC_MOVS_R   {B8(01000110), B8(11111110)}
+#define DEC_MOVE_R   {B8(01100100), B8(11111100)}
+#define DEC_MOVE_RP  {B8(01100011), B8(11111111)}
+#define DEC_MOVE_PR  {B8(01100111), B8(11111111)}
+#define DEC_DSTEP_R  {B8(01101111), B8(11111111)}
+#define DEC_MOVE_RS  {B8(10110111), B8(11111111)}
+#define DEC_MOVE_SR  {B8(11110111), B8(11111111)}
+#define DEC_ADDU_R   {B8(01000000), B8(11111110)}
+#define DEC_ADDS_R   {B8(01000010), B8(11111110)}
+#define DEC_ADD_R    {B8(01100000), B8(11111100)}
+#define DEC_ADDI_R   {B8(01010000), B8(11111100)}
+#define DEC_MULS_R   {B8(11010000), B8(11111100)}
+#define DEC_MULU_R   {B8(10010000), B8(11111100)}
+#define DEC_ADDI_ACR {B8(01010100), B8(11111100)}
+#define DEC_NEG_R    {B8(01011000), B8(11111100)}
+#define DEC_BOUND_R  {B8(01011100), B8(11111100)}
+#define DEC_SUBU_R   {B8(01001000), B8(11111110)}
+#define DEC_SUBS_R   {B8(01001010), B8(11111110)}
+#define DEC_SUB_R    {B8(01101000), B8(11111100)}
+#define DEC_CMP_R    {B8(01101100), B8(11111100)}
+#define DEC_AND_R    {B8(01110000), B8(11111100)}
+#define DEC_ABS_R    {B8(01101011), B8(11111111)}
+#define DEC_LZ_R     {B8(01110011), B8(11111111)}
+#define DEC_MCP_R    {B8(01111111), B8(11111111)}
+#define DEC_SWAP_R   {B8(01110111), B8(11111111)}
+#define DEC_XOR_R    {B8(01111011), B8(11111111)}
+#define DEC_LSL_R    {B8(01001100), B8(11111100)}
+#define DEC_LSR_R    {B8(01111100), B8(11111100)}
+#define DEC_ASR_R    {B8(01111000), B8(11111100)}
+#define DEC_OR_R     {B8(01110100), B8(11111100)}
+#define DEC_BTST_R   {B8(01001111), B8(11111111)}
+
+/* Fixed.  */
+#define DEC_SETF     {B8(01011011), B8(11111111)}
+#define DEC_CLEARF   {B8(01011111), B8(11111111)}
+
+/* Memory.  */
+#define DEC_ADDU_M   {B8(10000000), B8(10111110)}
+#define DEC_ADDS_M   {B8(10000010), B8(10111110)}
+#define DEC_MOVU_M   {B8(10000100), B8(10111110)}
+#define DEC_MOVS_M   {B8(10000110), B8(10111110)}
+#define DEC_SUBU_M   {B8(10001000), B8(10111110)}
+#define DEC_SUBS_M   {B8(10001010), B8(10111110)}
+#define DEC_CMPU_M   {B8(10001100), B8(10111110)}
+#define DEC_CMPS_M   {B8(10001110), B8(10111110)}
+#define DEC_ADDO_M   {B8(10010100), B8(10111100)}
+#define DEC_BOUND_M  {B8(10011100), B8(10111100)}
+#define DEC_ADD_M    {B8(10100000), B8(10111100)}
+#define DEC_MOVE_MR  {B8(10100100), B8(10111100)}
+#define DEC_SUB_M    {B8(10101000), B8(10111100)}
+#define DEC_CMP_M    {B8(10101100), B8(10111100)}
+#define DEC_AND_M    {B8(10110000), B8(10111100)}
+#define DEC_OR_M     {B8(10110100), B8(10111100)}
+#define DEC_TEST_M   {B8(10111000), B8(10111100)}
+#define DEC_MOVE_RM  {B8(10111100), B8(10111100)}
+
+#define DEC_ADDC_R   {B8(01010111), B8(11111111)}
+#define DEC_ADDC_MR  {B8(10011010), B8(10111111)}
+#define DEC_LAPCQ    {B8(10010111), B8(11111111)}
+#define DEC_LAPC_IM  {B8(11010111), B8(11111111)}
+
+#define DEC_MOVE_MP  {B8(10100011), B8(10111111)}
+#define DEC_MOVE_PM  {B8(10100111), B8(10111111)}
+
+#define DEC_SCC_R    {B8(01010011), B8(11111111)}
+#define DEC_RFE_ETC  {B8(10010011), B8(11111111)}
+#define DEC_JUMP_P   {B8(10011111), B8(11111111)}
+#define DEC_BCC_IM   {B8(11011111), B8(11111111)}
+#define DEC_JAS_R    {B8(10011011), B8(11111111)}
+#define DEC_JASC_R   {B8(10110011), B8(11111111)}
+#define DEC_JAS_IM   {B8(11011011), B8(11111111)}
+#define DEC_JASC_IM  {B8(11110011), B8(11111111)}
+#define DEC_BAS_IM   {B8(11101011), B8(11111111)}
+#define DEC_BASC_IM  {B8(11101111), B8(11111111)}
+#define DEC_MOVEM_MR {B8(10111011), B8(10111111)}
+#define DEC_MOVEM_RM {B8(10111111), B8(10111111)}
+
+#define DEC_FTAG_FIDX_D_M {B8(10101011), B8(11111111)}
+#define DEC_FTAG_FIDX_I_M {B8(11010011), B8(11111111)}
diff --git a/qemu-0.15.x/target-cris/exec.h b/qemu-0.15.x/target-cris/exec.h
new file mode 100644
index 0000000..3294abe
--- /dev/null
+++ b/qemu-0.15.x/target-cris/exec.h
@@ -0,0 +1,28 @@
+/*
+ *  CRIS execution defines
+ *
+ *  Copyright (c) 2007 AXIS Communications AB
+ *  Written by Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dyngen-exec.h"
+
+register struct CPUCRISState *env asm(AREG0);
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
diff --git a/qemu-0.15.x/target-cris/helper.c b/qemu-0.15.x/target-cris/helper.c
new file mode 100644
index 0000000..962d214
--- /dev/null
+++ b/qemu-0.15.x/target-cris/helper.c
@@ -0,0 +1,270 @@
+/*
+ *  CRIS helper routines.
+ *
+ *  Copyright (c) 2007 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "mmu.h"
+#include "host-utils.h"
+
+
+//#define CRIS_HELPER_DEBUG
+
+
+#ifdef CRIS_HELPER_DEBUG
+#define D(x) x
+#define D_LOG(...) qemu_log(__VA__ARGS__)
+#else
+#define D(x)
+#define D_LOG(...) do { } while (0)
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+	env->exception_index = -1;
+	env->pregs[PR_ERP] = env->pc;
+}
+
+int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
+                             int mmu_idx, int is_softmmu)
+{
+	env->exception_index = 0xaa;
+	env->pregs[PR_EDA] = address;
+	cpu_dump_state(env, stderr, fprintf, 0);
+	return 1;
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+
+static void cris_shift_ccs(CPUState *env)
+{
+	uint32_t ccs;
+	/* Apply the ccs shift.  */
+	ccs = env->pregs[PR_CCS];
+	ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
+	env->pregs[PR_CCS] = ccs;
+}
+
+int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+	struct cris_mmu_result res;
+	int prot, miss;
+	int r = -1;
+	target_ulong phy;
+
+	D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
+	miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
+				  rw, mmu_idx, 0);
+	if (miss)
+	{
+		if (env->exception_index == EXCP_BUSFAULT)
+			cpu_abort(env,
+				  "CRIS: Illegal recursive bus fault."
+				 "addr=%x rw=%d\n",
+				 address, rw);
+
+		env->pregs[PR_EDA] = address;
+		env->exception_index = EXCP_BUSFAULT;
+		env->fault_vector = res.bf_vec;
+		r = 1;
+	}
+	else
+	{
+		/*
+		 * Mask off the cache selection bit. The ETRAX busses do not
+		 * see the top bit.
+		 */
+		phy = res.phy & ~0x80000000;
+		prot = res.prot;
+		tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
+                             prot, mmu_idx, TARGET_PAGE_SIZE);
+                r = 0;
+	}
+	if (r > 0)
+		D_LOG("%s returns %d irqreq=%x addr=%x"
+			  " phy=%x ismmu=%d vec=%x pc=%x\n", 
+			  __func__, r, env->interrupt_request, 
+			  address, res.phy, is_softmmu, res.bf_vec, env->pc);
+	return r;
+}
+
+static void do_interruptv10(CPUState *env)
+{
+	int ex_vec = -1;
+
+	D_LOG( "exception index=%d interrupt_req=%d\n",
+		   env->exception_index,
+		   env->interrupt_request);
+
+	assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
+	switch (env->exception_index)
+	{
+		case EXCP_BREAK:
+			/* These exceptions are genereated by the core itself.
+			   ERP should point to the insn following the brk.  */
+			ex_vec = env->trap_vector;
+			env->pregs[PR_ERP] = env->pc;
+			break;
+
+		case EXCP_NMI:
+			/* NMI is hardwired to vector zero.  */
+			ex_vec = 0;
+			env->pregs[PR_CCS] &= ~M_FLAG;
+			env->pregs[PR_NRP] = env->pc;
+			break;
+
+		case EXCP_BUSFAULT:
+                        cpu_abort(env, "Unhandled busfault");
+			break;
+
+		default:
+			/* The interrupt controller gives us the vector.  */
+			ex_vec = env->interrupt_vector;
+			/* Normal interrupts are taken between
+			   TB's.  env->pc is valid here.  */
+			env->pregs[PR_ERP] = env->pc;
+			break;
+	}
+
+	if (env->pregs[PR_CCS] & U_FLAG) {
+		/* Swap stack pointers.  */
+		env->pregs[PR_USP] = env->regs[R_SP];
+		env->regs[R_SP] = env->ksp;
+	}
+
+	/* Now that we are in kernel mode, load the handlers address.  */
+	env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
+	env->locked_irq = 1;
+
+	qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 
+		      __func__, env->pc, ex_vec, 
+		      env->pregs[PR_CCS],
+		      env->pregs[PR_PID], 
+		      env->pregs[PR_ERP]);
+}
+
+void do_interrupt(CPUState *env)
+{
+	int ex_vec = -1;
+
+	if (env->pregs[PR_VR] < 32)
+		return do_interruptv10(env);
+
+	D_LOG( "exception index=%d interrupt_req=%d\n",
+		   env->exception_index,
+		   env->interrupt_request);
+
+	switch (env->exception_index)
+	{
+		case EXCP_BREAK:
+			/* These exceptions are genereated by the core itself.
+			   ERP should point to the insn following the brk.  */
+			ex_vec = env->trap_vector;
+			env->pregs[PR_ERP] = env->pc;
+			break;
+
+		case EXCP_NMI:
+			/* NMI is hardwired to vector zero.  */
+			ex_vec = 0;
+			env->pregs[PR_CCS] &= ~M_FLAG;
+			env->pregs[PR_NRP] = env->pc;
+			break;
+
+		case EXCP_BUSFAULT:
+			ex_vec = env->fault_vector;
+			env->pregs[PR_ERP] = env->pc;
+			break;
+
+		default:
+			/* The interrupt controller gives us the vector.  */
+			ex_vec = env->interrupt_vector;
+			/* Normal interrupts are taken between
+			   TB's.  env->pc is valid here.  */
+			env->pregs[PR_ERP] = env->pc;
+			break;
+	}
+
+	/* Fill in the IDX field.  */
+	env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
+
+	if (env->dslot) {
+		D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
+			  " ERP=%x pid=%x ccs=%x cc=%d %x\n",
+			  ex_vec, env->pc, env->dslot,
+			  env->regs[R_SP],
+			  env->pregs[PR_ERP], env->pregs[PR_PID],
+			  env->pregs[PR_CCS],
+			  env->cc_op, env->cc_mask);
+		/* We loose the btarget, btaken state here so rexec the
+		   branch.  */
+		env->pregs[PR_ERP] -= env->dslot;
+		/* Exception starts with dslot cleared.  */
+		env->dslot = 0;
+	}
+	
+	if (env->pregs[PR_CCS] & U_FLAG) {
+		/* Swap stack pointers.  */
+		env->pregs[PR_USP] = env->regs[R_SP];
+		env->regs[R_SP] = env->ksp;
+	}
+
+	/* Apply the CRIS CCS shift. Clears U if set.  */
+	cris_shift_ccs(env);
+
+	/* Now that we are in kernel mode, load the handlers address.
+	   This load may not fault, real hw leaves that behaviour as
+	   undefined.  */
+	env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
+
+	/* Clear the excption_index to avoid spurios hw_aborts for recursive
+	   bus faults.  */
+	env->exception_index = -1;
+
+	D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
+		   __func__, env->pc, ex_vec,
+		   env->pregs[PR_CCS],
+		   env->pregs[PR_PID], 
+		   env->pregs[PR_ERP]);
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+{
+	uint32_t phy = addr;
+	struct cris_mmu_result res;
+	int miss;
+
+	miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
+	/* If D TLB misses, try I TLB.  */
+	if (miss) {
+		miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
+	}
+
+	if (!miss)
+		phy = res.phy;
+	D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
+	return phy;
+}
+#endif
diff --git a/qemu-0.15.x/target-cris/helper.h b/qemu-0.15.x/target-cris/helper.h
new file mode 100644
index 0000000..093063a
--- /dev/null
+++ b/qemu-0.15.x/target-cris/helper.h
@@ -0,0 +1,26 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_1(tlb_flush_pid, void, i32)
+DEF_HELPER_1(spc_write, void, i32)
+DEF_HELPER_3(dump, void, i32, i32, i32)
+DEF_HELPER_0(rfe, void);
+DEF_HELPER_0(rfn, void);
+
+DEF_HELPER_2(movl_sreg_reg, void, i32, i32)
+DEF_HELPER_2(movl_reg_sreg, void, i32, i32)
+
+DEF_HELPER_FLAGS_1(lz, TCG_CALL_PURE, i32, i32);
+DEF_HELPER_FLAGS_3(btst, TCG_CALL_PURE, i32, i32, i32, i32);
+
+DEF_HELPER_FLAGS_3(evaluate_flags_muls, TCG_CALL_PURE, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(evaluate_flags_mulu, TCG_CALL_PURE, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_4(evaluate_flags_mcp, TCG_CALL_PURE, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_4(evaluate_flags_alu_4, TCG_CALL_PURE, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_4(evaluate_flags_sub_4, TCG_CALL_PURE, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_2(evaluate_flags_move_4, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(evaluate_flags_move_2, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_0(evaluate_flags, void)
+DEF_HELPER_0(top_evaluate_flags, void)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-cris/machine.c b/qemu-0.15.x/target-cris/machine.c
new file mode 100644
index 0000000..8f9c0dd
--- /dev/null
+++ b/qemu-0.15.x/target-cris/machine.c
@@ -0,0 +1,90 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    CPUCRISState *env = opaque;
+    int i;
+    int s;
+    int mmu;
+
+    for (i = 0; i < 16; i++)
+        qemu_put_be32(f, env->regs[i]);
+    for (i = 0; i < 16; i++)
+        qemu_put_be32(f, env->pregs[i]);
+
+    qemu_put_be32(f, env->pc);
+    qemu_put_be32(f, env->ksp);
+
+    qemu_put_be32(f, env->dslot);
+    qemu_put_be32(f, env->btaken);
+    qemu_put_be32(f, env->btarget);
+
+    qemu_put_be32(f, env->cc_op);
+    qemu_put_be32(f, env->cc_mask);
+    qemu_put_be32(f, env->cc_dest);
+    qemu_put_be32(f, env->cc_src);
+    qemu_put_be32(f, env->cc_result);
+    qemu_put_be32(f, env->cc_size);
+    qemu_put_be32(f, env->cc_x);
+
+    for (s = 0; s < 4; s++) {
+        for (i = 0; i < 16; i++)
+            qemu_put_be32(f, env->sregs[s][i]);
+    }
+
+    qemu_put_be32(f, env->mmu_rand_lfsr);
+    for (mmu = 0; mmu < 2; mmu++) {
+        for (s = 0; s < 4; s++) {
+            for (i = 0; i < 16; i++) {
+                qemu_put_be32(f, env->tlbsets[mmu][s][i].lo);
+                qemu_put_be32(f, env->tlbsets[mmu][s][i].hi);
+            }
+        }
+    }
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+	CPUCRISState *env = opaque;
+    int i;
+    int s;
+    int mmu;
+
+    for (i = 0; i < 16; i++)
+        env->regs[i] = qemu_get_be32(f);
+    for (i = 0; i < 16; i++)
+        env->pregs[i] = qemu_get_be32(f);
+
+    env->pc = qemu_get_be32(f);
+    env->ksp = qemu_get_be32(f);
+
+    env->dslot = qemu_get_be32(f);
+    env->btaken = qemu_get_be32(f);
+    env->btarget = qemu_get_be32(f);
+
+    env->cc_op = qemu_get_be32(f);
+    env->cc_mask = qemu_get_be32(f);
+    env->cc_dest = qemu_get_be32(f);
+    env->cc_src = qemu_get_be32(f);
+    env->cc_result = qemu_get_be32(f);
+    env->cc_size = qemu_get_be32(f);
+    env->cc_x = qemu_get_be32(f);
+
+    for (s = 0; s < 4; s++) {
+        for (i = 0; i < 16; i++)
+            env->sregs[s][i] = qemu_get_be32(f);
+    }
+
+    env->mmu_rand_lfsr = qemu_get_be32(f);
+    for (mmu = 0; mmu < 2; mmu++) {
+        for (s = 0; s < 4; s++) {
+            for (i = 0; i < 16; i++) {
+                env->tlbsets[mmu][s][i].lo = qemu_get_be32(f);
+                env->tlbsets[mmu][s][i].hi = qemu_get_be32(f);
+            }
+        }
+    }
+
+    return 0;
+}
diff --git a/qemu-0.15.x/target-cris/mmu.c b/qemu-0.15.x/target-cris/mmu.c
new file mode 100644
index 0000000..d481e39
--- /dev/null
+++ b/qemu-0.15.x/target-cris/mmu.c
@@ -0,0 +1,367 @@
+/*
+ *  CRIS mmu emulation.
+ *
+ *  Copyright (c) 2007 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CONFIG_USER_ONLY
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "mmu.h"
+
+#ifdef DEBUG
+#define D(x) x
+#define D_LOG(...) qemu_log(__VA_ARGS__)
+#else
+#define D(x) do { } while (0)
+#define D_LOG(...) do { } while (0)
+#endif
+
+void cris_mmu_init(CPUState *env)
+{
+	env->mmu_rand_lfsr = 0xcccc;
+}
+
+#define SR_POLYNOM 0x8805
+static inline unsigned int compute_polynom(unsigned int sr)
+{
+	unsigned int i;
+	unsigned int f;
+
+	f = 0;
+	for (i = 0; i < 16; i++)
+		f += ((SR_POLYNOM >> i) & 1) & ((sr >> i) & 1);
+
+	return f;
+}
+
+static void cris_mmu_update_rand_lfsr(CPUState *env)
+{
+	unsigned int f;
+
+	/* Update lfsr at every fault.  */
+	f = compute_polynom(env->mmu_rand_lfsr);
+	env->mmu_rand_lfsr >>= 1;
+	env->mmu_rand_lfsr |= (f << 15);
+	env->mmu_rand_lfsr &= 0xffff;
+}
+
+static inline int cris_mmu_enabled(uint32_t rw_gc_cfg)
+{
+	return (rw_gc_cfg & 12) != 0;
+}
+
+static inline int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg)
+{
+	return (1 << seg) & rw_mm_cfg;
+}
+
+static uint32_t cris_mmu_translate_seg(CPUState *env, int seg)
+{
+	uint32_t base;
+	int i;
+
+	if (seg < 8)
+		base = env->sregs[SFR_RW_MM_KBASE_LO];
+	else
+		base = env->sregs[SFR_RW_MM_KBASE_HI];
+
+	i = seg & 7;
+	base >>= i * 4;
+	base &= 15;
+
+	base <<= 28;
+	return base;
+}
+/* Used by the tlb decoder.  */
+#define EXTRACT_FIELD(src, start, end) \
+	    (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+static inline void set_field(uint32_t *dst, unsigned int val, 
+			     unsigned int offset, unsigned int width)
+{
+	uint32_t mask;
+
+	mask = (1 << width) - 1;
+	mask <<= offset;
+	val <<= offset;
+
+	val &= mask;
+	*dst &= ~(mask);
+	*dst |= val;
+}
+
+#ifdef DEBUG
+static void dump_tlb(CPUState *env, int mmu)
+{
+	int set;
+	int idx;
+	uint32_t hi, lo, tlb_vpn, tlb_pfn;
+
+	for (set = 0; set < 4; set++) {
+		for (idx = 0; idx < 16; idx++) {
+			lo = env->tlbsets[mmu][set][idx].lo;
+			hi = env->tlbsets[mmu][set][idx].hi;
+			tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
+			tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
+
+			printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", 
+					set, idx, hi, lo, tlb_vpn, tlb_pfn);
+		}
+	}
+}
+#endif
+
+/* rw 0 = read, 1 = write, 2 = exec.  */
+static int cris_mmu_translate_page(struct cris_mmu_result *res,
+				   CPUState *env, uint32_t vaddr,
+				   int rw, int usermode, int debug)
+{
+	unsigned int vpage;
+	unsigned int idx;
+	uint32_t pid, lo, hi;
+	uint32_t tlb_vpn, tlb_pfn = 0;
+	int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x;
+	int cfg_v, cfg_k, cfg_w, cfg_x;	
+	int set, match = 0;
+	uint32_t r_cause;
+	uint32_t r_cfg;
+	int rwcause;
+	int mmu = 1; /* Data mmu is default.  */
+	int vect_base;
+
+	r_cause = env->sregs[SFR_R_MM_CAUSE];
+	r_cfg = env->sregs[SFR_RW_MM_CFG];
+	pid = env->pregs[PR_PID] & 0xff;
+
+	switch (rw) {
+		case 2: rwcause = CRIS_MMU_ERR_EXEC; mmu = 0; break;
+		case 1: rwcause = CRIS_MMU_ERR_WRITE; break;
+		default:
+		case 0: rwcause = CRIS_MMU_ERR_READ; break;
+	}
+
+	/* I exception vectors 4 - 7, D 8 - 11.  */
+	vect_base = (mmu + 1) * 4;
+
+	vpage = vaddr >> 13;
+
+	/* We know the index which to check on each set.
+	   Scan both I and D.  */
+#if 0
+	for (set = 0; set < 4; set++) {
+		for (idx = 0; idx < 16; idx++) {
+			lo = env->tlbsets[mmu][set][idx].lo;
+			hi = env->tlbsets[mmu][set][idx].hi;
+			tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
+			tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
+
+			printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", 
+					set, idx, hi, lo, tlb_vpn, tlb_pfn);
+		}
+	}
+#endif
+
+	idx = vpage & 15;
+	for (set = 0; set < 4; set++)
+	{
+		lo = env->tlbsets[mmu][set][idx].lo;
+		hi = env->tlbsets[mmu][set][idx].hi;
+
+		tlb_vpn = hi >> 13;
+		tlb_pid = EXTRACT_FIELD(hi, 0, 7);
+		tlb_g  = EXTRACT_FIELD(lo, 4, 4);
+
+		D_LOG("TLB[%d][%d][%d] v=%x vpage=%x lo=%x hi=%x\n", 
+			 mmu, set, idx, tlb_vpn, vpage, lo, hi);
+		if ((tlb_g || (tlb_pid == pid))
+		    && tlb_vpn == vpage) {
+			match = 1;
+			break;
+		}
+	}
+
+	res->bf_vec = vect_base;
+	if (match) {
+		cfg_w  = EXTRACT_FIELD(r_cfg, 19, 19);
+		cfg_k  = EXTRACT_FIELD(r_cfg, 18, 18);
+		cfg_x  = EXTRACT_FIELD(r_cfg, 17, 17);
+		cfg_v  = EXTRACT_FIELD(r_cfg, 16, 16);
+
+		tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
+		tlb_v = EXTRACT_FIELD(lo, 3, 3);
+		tlb_k = EXTRACT_FIELD(lo, 2, 2);
+		tlb_w = EXTRACT_FIELD(lo, 1, 1);
+		tlb_x = EXTRACT_FIELD(lo, 0, 0);
+
+		/*
+		set_exception_vector(0x04, i_mmu_refill);
+		set_exception_vector(0x05, i_mmu_invalid);
+		set_exception_vector(0x06, i_mmu_access);
+		set_exception_vector(0x07, i_mmu_execute);
+		set_exception_vector(0x08, d_mmu_refill);
+		set_exception_vector(0x09, d_mmu_invalid);
+		set_exception_vector(0x0a, d_mmu_access);
+		set_exception_vector(0x0b, d_mmu_write);
+		*/
+		if (cfg_k && tlb_k && usermode) {
+			D(printf ("tlb: kernel protected %x lo=%x pc=%x\n", 
+				  vaddr, lo, env->pc));
+			match = 0;
+			res->bf_vec = vect_base + 2;
+		} else if (rw == 1 && cfg_w && !tlb_w) {
+			D(printf ("tlb: write protected %x lo=%x pc=%x\n", 
+				  vaddr, lo, env->pc));
+			match = 0;
+			/* write accesses never go through the I mmu.  */
+			res->bf_vec = vect_base + 3;
+		} else if (rw == 2 && cfg_x && !tlb_x) {
+			D(printf ("tlb: exec protected %x lo=%x pc=%x\n", 
+				 vaddr, lo, env->pc));
+			match = 0;
+			res->bf_vec = vect_base + 3;
+		} else if (cfg_v && !tlb_v) {
+			D(printf ("tlb: invalid %x\n", vaddr));
+			match = 0;
+			res->bf_vec = vect_base + 1;
+		}
+
+		res->prot = 0;
+		if (match) {
+			res->prot |= PAGE_READ;
+			if (tlb_w)
+				res->prot |= PAGE_WRITE;
+			if (mmu == 0 && (cfg_x || tlb_x))
+				res->prot |= PAGE_EXEC;
+		}
+		else
+			D(dump_tlb(env, mmu));
+	} else {
+		/* If refill, provide a randomized set.  */
+		set = env->mmu_rand_lfsr & 3;
+	}
+
+	if (!match && !debug) {
+		cris_mmu_update_rand_lfsr(env);
+
+		/* Compute index.  */
+		idx = vpage & 15;
+
+		/* Update RW_MM_TLB_SEL.  */
+		env->sregs[SFR_RW_MM_TLB_SEL] = 0;
+		set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4);
+		set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 2);
+
+		/* Update RW_MM_CAUSE.  */
+		set_field(&r_cause, rwcause, 8, 2);
+		set_field(&r_cause, vpage, 13, 19);
+		set_field(&r_cause, pid, 0, 8);
+		env->sregs[SFR_R_MM_CAUSE] = r_cause;
+		D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc));
+	}
+
+	D(printf ("%s rw=%d mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x"
+		  " %x cause=%x sel=%x sp=%x %x %x\n",
+		  __func__, rw, match, env->pc,
+		  vaddr, vpage,
+		  tlb_vpn, tlb_pfn, tlb_pid, 
+		  pid,
+		  r_cause,
+		  env->sregs[SFR_RW_MM_TLB_SEL],
+		  env->regs[R_SP], env->pregs[PR_USP], env->ksp));
+
+	res->phy = tlb_pfn << TARGET_PAGE_BITS;
+	return !match;
+}
+
+void cris_mmu_flush_pid(CPUState *env, uint32_t pid)
+{
+	target_ulong vaddr;
+	unsigned int idx;
+	uint32_t lo, hi;
+	uint32_t tlb_vpn;
+	int tlb_pid, tlb_g, tlb_v;
+	unsigned int set;
+	unsigned int mmu;
+
+	pid &= 0xff;
+	for (mmu = 0; mmu < 2; mmu++) {
+		for (set = 0; set < 4; set++)
+		{
+			for (idx = 0; idx < 16; idx++) {
+				lo = env->tlbsets[mmu][set][idx].lo;
+				hi = env->tlbsets[mmu][set][idx].hi;
+				
+				tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
+				tlb_pid = EXTRACT_FIELD(hi, 0, 7);
+				tlb_g  = EXTRACT_FIELD(lo, 4, 4);
+				tlb_v = EXTRACT_FIELD(lo, 3, 3);
+
+				if (tlb_v && !tlb_g && (tlb_pid == pid)) {
+					vaddr = tlb_vpn << TARGET_PAGE_BITS;
+					D_LOG("flush pid=%x vaddr=%x\n", 
+						  pid, vaddr);
+					tlb_flush_page(env, vaddr);
+				}
+			}
+		}
+	}
+}
+
+int cris_mmu_translate(struct cris_mmu_result *res,
+		       CPUState *env, uint32_t vaddr,
+		       int rw, int mmu_idx, int debug)
+{
+	int seg;
+	int miss = 0;
+	int is_user = mmu_idx == MMU_USER_IDX;
+	uint32_t old_srs;
+
+	old_srs= env->pregs[PR_SRS];
+
+	/* rw == 2 means exec, map the access to the insn mmu.  */
+	env->pregs[PR_SRS] = rw == 2 ? 1 : 2;
+
+	if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) {
+		res->phy = vaddr;
+		res->prot = PAGE_BITS;
+		goto done;
+	}
+
+	seg = vaddr >> 28;
+	if (!is_user && cris_mmu_segmented_addr(seg, env->sregs[SFR_RW_MM_CFG]))
+	{
+		uint32_t base;
+
+		miss = 0;
+		base = cris_mmu_translate_seg(env, seg);
+                res->phy = base | (0x0fffffff & vaddr);
+		res->prot = PAGE_BITS;
+	} else {
+		miss = cris_mmu_translate_page(res, env, vaddr, rw,
+					       is_user, debug);
+	}
+  done:
+	env->pregs[PR_SRS] = old_srs;
+	return miss;
+}
+#endif
diff --git a/qemu-0.15.x/target-cris/mmu.h b/qemu-0.15.x/target-cris/mmu.h
new file mode 100644
index 0000000..459d809
--- /dev/null
+++ b/qemu-0.15.x/target-cris/mmu.h
@@ -0,0 +1,17 @@
+#define CRIS_MMU_ERR_EXEC  0
+#define CRIS_MMU_ERR_READ  1
+#define CRIS_MMU_ERR_WRITE 2
+#define CRIS_MMU_ERR_FLUSH 3
+
+struct cris_mmu_result
+{
+	uint32_t phy;
+	int prot;
+	int bf_vec;
+};
+
+void cris_mmu_init(CPUState *env);
+void cris_mmu_flush_pid(CPUState *env, uint32_t pid);
+int cris_mmu_translate(struct cris_mmu_result *res,
+		       CPUState *env, uint32_t vaddr,
+		       int rw, int mmu_idx, int debug);
diff --git a/qemu-0.15.x/target-cris/op_helper.c b/qemu-0.15.x/target-cris/op_helper.c
new file mode 100644
index 0000000..b3ddd33
--- /dev/null
+++ b/qemu-0.15.x/target-cris/op_helper.c
@@ -0,0 +1,655 @@
+/*
+ *  CRIS helper routines
+ *
+ *  Copyright (c) 2007 AXIS Communications
+ *  Written by Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "exec.h"
+#include "mmu.h"
+#include "helper.h"
+#include "host-utils.h"
+
+//#define CRIS_OP_HELPER_DEBUG
+
+
+#ifdef CRIS_OP_HELPER_DEBUG
+#define D(x) x
+#define D_LOG(...) qemu_log(__VA__ARGS__)
+#else
+#define D(x)
+#define D_LOG(...) do { } while (0)
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__, 
+	     env->pc, env->debug1, retaddr);
+    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+
+		/* Evaluate flags after retranslation.  */
+                helper_top_evaluate_flags();
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+
+#endif
+
+void helper_raise_exception(uint32_t index)
+{
+	env->exception_index = index;
+        cpu_loop_exit(env);
+}
+
+void helper_tlb_flush_pid(uint32_t pid)
+{
+#if !defined(CONFIG_USER_ONLY)
+	pid &= 0xff;
+	if (pid != (env->pregs[PR_PID] & 0xff))
+		cris_mmu_flush_pid(env, env->pregs[PR_PID]);
+#endif
+}
+
+void helper_spc_write(uint32_t new_spc)
+{
+#if !defined(CONFIG_USER_ONLY)
+	tlb_flush_page(env, env->pregs[PR_SPC]);
+	tlb_flush_page(env, new_spc);
+#endif
+}
+
+void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
+{
+	qemu_log("%s: a0=%x a1=%x\n", __func__, a0, a1);
+}
+
+/* Used by the tlb decoder.  */
+#define EXTRACT_FIELD(src, start, end) \
+	    (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
+{
+	uint32_t srs;
+	srs = env->pregs[PR_SRS];
+	srs &= 3;
+	env->sregs[srs][sreg] = env->regs[reg];
+
+#if !defined(CONFIG_USER_ONLY)
+	if (srs == 1 || srs == 2) {
+		if (sreg == 6) {
+			/* Writes to tlb-hi write to mm_cause as a side 
+			   effect.  */
+			env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
+			env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
+		}
+		else if (sreg == 5) {
+			uint32_t set;
+			uint32_t idx;
+			uint32_t lo, hi;
+			uint32_t vaddr;
+			int tlb_v;
+
+			idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
+			set >>= 4;
+			set &= 3;
+
+			idx &= 15;
+			/* We've just made a write to tlb_lo.  */
+			lo = env->sregs[SFR_RW_MM_TLB_LO];
+			/* Writes are done via r_mm_cause.  */
+			hi = env->sregs[SFR_R_MM_CAUSE];
+
+			vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
+					      13, 31);
+			vaddr <<= TARGET_PAGE_BITS;
+			tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
+					    3, 3);
+			env->tlbsets[srs - 1][set][idx].lo = lo;
+			env->tlbsets[srs - 1][set][idx].hi = hi;
+
+			D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", 
+				  vaddr, tlb_v, env->pc);
+			if (tlb_v) {
+				tlb_flush_page(env, vaddr);
+			}
+		}
+	}
+#endif
+}
+
+void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg)
+{
+	uint32_t srs;
+	env->pregs[PR_SRS] &= 3;
+	srs = env->pregs[PR_SRS];
+	
+#if !defined(CONFIG_USER_ONLY)
+	if (srs == 1 || srs == 2)
+	{
+		uint32_t set;
+		uint32_t idx;
+		uint32_t lo, hi;
+
+		idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
+		set >>= 4;
+		set &= 3;
+		idx &= 15;
+
+		/* Update the mirror regs.  */
+		hi = env->tlbsets[srs - 1][set][idx].hi;
+		lo = env->tlbsets[srs - 1][set][idx].lo;
+		env->sregs[SFR_RW_MM_TLB_HI] = hi;
+		env->sregs[SFR_RW_MM_TLB_LO] = lo;
+	}
+#endif
+	env->regs[reg] = env->sregs[srs][sreg];
+}
+
+static void cris_ccs_rshift(CPUState *env)
+{
+	uint32_t ccs;
+
+	/* Apply the ccs shift.  */
+	ccs = env->pregs[PR_CCS];
+	ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
+	if (ccs & U_FLAG)
+	{
+		/* Enter user mode.  */
+		env->ksp = env->regs[R_SP];
+		env->regs[R_SP] = env->pregs[PR_USP];
+	}
+
+	env->pregs[PR_CCS] = ccs;
+}
+
+void helper_rfe(void)
+{
+	int rflag = env->pregs[PR_CCS] & R_FLAG;
+
+	D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
+		 env->pregs[PR_ERP], env->pregs[PR_PID],
+		 env->pregs[PR_CCS],
+		 env->btarget);
+
+	cris_ccs_rshift(env);
+
+	/* RFE sets the P_FLAG only if the R_FLAG is not set.  */
+	if (!rflag)
+		env->pregs[PR_CCS] |= P_FLAG;
+}
+
+void helper_rfn(void)
+{
+	int rflag = env->pregs[PR_CCS] & R_FLAG;
+
+	D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n", 
+		 env->pregs[PR_ERP], env->pregs[PR_PID],
+		 env->pregs[PR_CCS],
+		 env->btarget);
+
+	cris_ccs_rshift(env);
+
+	/* Set the P_FLAG only if the R_FLAG is not set.  */
+	if (!rflag)
+		env->pregs[PR_CCS] |= P_FLAG;
+
+    /* Always set the M flag.  */
+    env->pregs[PR_CCS] |= M_FLAG;
+}
+
+uint32_t helper_lz(uint32_t t0)
+{
+	return clz32(t0);
+}
+
+uint32_t helper_btst(uint32_t t0, uint32_t t1, uint32_t ccs)
+{
+	/* FIXME: clean this up.  */
+
+	/* des ref:
+	   The N flag is set according to the selected bit in the dest reg.
+	   The Z flag is set if the selected bit and all bits to the right are
+	   zero.
+	   The X flag is cleared.
+	   Other flags are left untouched.
+	   The destination reg is not affected.*/
+	unsigned int fz, sbit, bset, mask, masked_t0;
+
+	sbit = t1 & 31;
+	bset = !!(t0 & (1 << sbit));
+	mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
+	masked_t0 = t0 & mask;
+	fz = !(masked_t0 | bset);
+
+	/* Clear the X, N and Z flags.  */
+	ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
+	if (env->pregs[PR_VR] < 32)
+		ccs &= ~(V_FLAG | C_FLAG);
+	/* Set the N and Z flags accordingly.  */
+	ccs |= (bset << 3) | (fz << 2);
+	return ccs;
+}
+
+static inline uint32_t evaluate_flags_writeback(uint32_t flags, uint32_t ccs)
+{
+	unsigned int x, z, mask;
+
+	/* Extended arithmetics, leave the z flag alone.  */
+	x = env->cc_x;
+	mask = env->cc_mask | X_FLAG;
+        if (x) {
+		z = flags & Z_FLAG;
+		mask = mask & ~z;
+	}
+	flags &= mask;
+
+	/* all insn clear the x-flag except setf or clrf.  */
+	ccs &= ~mask;
+	ccs |= flags;
+	return ccs;
+}
+
+uint32_t helper_evaluate_flags_muls(uint32_t ccs, uint32_t res, uint32_t mof)
+{
+	uint32_t flags = 0;
+	int64_t tmp;
+	int dneg;
+
+	dneg = ((int32_t)res) < 0;
+
+	tmp = mof;
+	tmp <<= 32;
+	tmp |= res;
+	if (tmp == 0)
+		flags |= Z_FLAG;
+	else if (tmp < 0)
+		flags |= N_FLAG;
+	if ((dneg && mof != -1)
+	    || (!dneg && mof != 0))
+		flags |= V_FLAG;
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+uint32_t helper_evaluate_flags_mulu(uint32_t ccs, uint32_t res, uint32_t mof)
+{
+	uint32_t flags = 0;
+	uint64_t tmp;
+
+	tmp = mof;
+	tmp <<= 32;
+	tmp |= res;
+	if (tmp == 0)
+		flags |= Z_FLAG;
+	else if (tmp >> 63)
+		flags |= N_FLAG;
+	if (mof)
+		flags |= V_FLAG;
+
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+uint32_t helper_evaluate_flags_mcp(uint32_t ccs,
+				   uint32_t src, uint32_t dst, uint32_t res)
+{
+	uint32_t flags = 0;
+
+	src = src & 0x80000000;
+	dst = dst & 0x80000000;
+
+	if ((res & 0x80000000L) != 0L)
+	{
+		flags |= N_FLAG;
+		if (!src && !dst)
+			flags |= V_FLAG;
+		else if (src & dst)
+			flags |= R_FLAG;
+	}
+	else
+	{
+		if (res == 0L)
+			flags |= Z_FLAG;
+		if (src & dst) 
+			flags |= V_FLAG;
+		if (dst | src) 
+			flags |= R_FLAG;
+	}
+
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+uint32_t helper_evaluate_flags_alu_4(uint32_t ccs,
+				     uint32_t src, uint32_t dst, uint32_t res)
+{
+	uint32_t flags = 0;
+
+	src = src & 0x80000000;
+	dst = dst & 0x80000000;
+
+	if ((res & 0x80000000L) != 0L)
+	{
+		flags |= N_FLAG;
+		if (!src && !dst)
+			flags |= V_FLAG;
+		else if (src & dst)
+			flags |= C_FLAG;
+	}
+	else
+	{
+		if (res == 0L)
+			flags |= Z_FLAG;
+		if (src & dst) 
+			flags |= V_FLAG;
+		if (dst | src) 
+			flags |= C_FLAG;
+	}
+
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+uint32_t helper_evaluate_flags_sub_4(uint32_t ccs,
+				     uint32_t src, uint32_t dst, uint32_t res)
+{
+	uint32_t flags = 0;
+
+	src = (~src) & 0x80000000;
+	dst = dst & 0x80000000;
+
+	if ((res & 0x80000000L) != 0L)
+	{
+		flags |= N_FLAG;
+		if (!src && !dst)
+			flags |= V_FLAG;
+		else if (src & dst)
+			flags |= C_FLAG;
+	}
+	else
+	{
+		if (res == 0L)
+			flags |= Z_FLAG;
+		if (src & dst) 
+			flags |= V_FLAG;
+		if (dst | src) 
+			flags |= C_FLAG;
+	}
+
+	flags ^= C_FLAG;
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+uint32_t helper_evaluate_flags_move_4(uint32_t ccs, uint32_t res)
+{
+	uint32_t flags = 0;
+
+	if ((int32_t)res < 0)
+		flags |= N_FLAG;
+	else if (res == 0L)
+		flags |= Z_FLAG;
+
+	return evaluate_flags_writeback(flags, ccs);
+}
+uint32_t helper_evaluate_flags_move_2(uint32_t ccs, uint32_t res)
+{
+	uint32_t flags = 0;
+
+	if ((int16_t)res < 0L)
+		flags |= N_FLAG;
+	else if (res == 0)
+		flags |= Z_FLAG;
+
+	return evaluate_flags_writeback(flags, ccs);
+}
+
+/* TODO: This is expensive. We could split things up and only evaluate part of
+   CCR on a need to know basis. For now, we simply re-evaluate everything.  */
+void  helper_evaluate_flags(void)
+{
+	uint32_t src, dst, res;
+	uint32_t flags = 0;
+
+	src = env->cc_src;
+	dst = env->cc_dest;
+	res = env->cc_result;
+
+	if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
+		src = ~src;
+
+	/* Now, evaluate the flags. This stuff is based on
+	   Per Zander's CRISv10 simulator.  */
+	switch (env->cc_size)
+	{
+		case 1:
+			if ((res & 0x80L) != 0L)
+			{
+				flags |= N_FLAG;
+				if (((src & 0x80L) == 0L)
+				    && ((dst & 0x80L) == 0L))
+				{
+					flags |= V_FLAG;
+				}
+				else if (((src & 0x80L) != 0L)
+					 && ((dst & 0x80L) != 0L))
+				{
+					flags |= C_FLAG;
+				}
+			}
+			else
+			{
+				if ((res & 0xFFL) == 0L)
+				{
+					flags |= Z_FLAG;
+				}
+				if (((src & 0x80L) != 0L)
+				    && ((dst & 0x80L) != 0L))
+				{
+					flags |= V_FLAG;
+				}
+				if ((dst & 0x80L) != 0L
+				    || (src & 0x80L) != 0L)
+				{
+					flags |= C_FLAG;
+				}
+			}
+			break;
+		case 2:
+			if ((res & 0x8000L) != 0L)
+			{
+				flags |= N_FLAG;
+				if (((src & 0x8000L) == 0L)
+				    && ((dst & 0x8000L) == 0L))
+				{
+					flags |= V_FLAG;
+				}
+				else if (((src & 0x8000L) != 0L)
+					 && ((dst & 0x8000L) != 0L))
+				{
+					flags |= C_FLAG;
+				}
+			}
+			else
+			{
+				if ((res & 0xFFFFL) == 0L)
+				{
+					flags |= Z_FLAG;
+				}
+				if (((src & 0x8000L) != 0L)
+				    && ((dst & 0x8000L) != 0L))
+				{
+					flags |= V_FLAG;
+				}
+				if ((dst & 0x8000L) != 0L
+				    || (src & 0x8000L) != 0L)
+				{
+					flags |= C_FLAG;
+				}
+			}
+			break;
+		case 4:
+			if ((res & 0x80000000L) != 0L)
+			{
+				flags |= N_FLAG;
+				if (((src & 0x80000000L) == 0L)
+				    && ((dst & 0x80000000L) == 0L))
+				{
+					flags |= V_FLAG;
+				}
+				else if (((src & 0x80000000L) != 0L) &&
+					 ((dst & 0x80000000L) != 0L))
+				{
+					flags |= C_FLAG;
+				}
+			}
+			else
+			{
+				if (res == 0L)
+					flags |= Z_FLAG;
+				if (((src & 0x80000000L) != 0L)
+				    && ((dst & 0x80000000L) != 0L))
+					flags |= V_FLAG;
+				if ((dst & 0x80000000L) != 0L
+				    || (src & 0x80000000L) != 0L)
+					flags |= C_FLAG;
+			}
+			break;
+		default:
+			break;
+	}
+
+	if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
+		flags ^= C_FLAG;
+
+	env->pregs[PR_CCS] = evaluate_flags_writeback(flags, env->pregs[PR_CCS]);
+}
+
+void helper_top_evaluate_flags(void)
+{
+	switch (env->cc_op)
+	{
+		case CC_OP_MCP:
+			env->pregs[PR_CCS] = helper_evaluate_flags_mcp(
+					env->pregs[PR_CCS], env->cc_src,
+					env->cc_dest, env->cc_result);
+			break;
+		case CC_OP_MULS:
+			env->pregs[PR_CCS] = helper_evaluate_flags_muls(
+					env->pregs[PR_CCS], env->cc_result,
+					env->pregs[PR_MOF]);
+			break;
+		case CC_OP_MULU:
+			env->pregs[PR_CCS] = helper_evaluate_flags_mulu(
+					env->pregs[PR_CCS], env->cc_result,
+					env->pregs[PR_MOF]);
+			break;
+		case CC_OP_MOVE:
+		case CC_OP_AND:
+		case CC_OP_OR:
+		case CC_OP_XOR:
+		case CC_OP_ASR:
+		case CC_OP_LSR:
+		case CC_OP_LSL:
+		switch (env->cc_size)
+		{
+			case 4:
+				env->pregs[PR_CCS] =
+					helper_evaluate_flags_move_4(
+							env->pregs[PR_CCS],
+							env->cc_result);
+				break;
+			case 2:
+				env->pregs[PR_CCS] =
+					helper_evaluate_flags_move_2(
+							env->pregs[PR_CCS],
+							env->cc_result);
+				break;
+			default:
+				helper_evaluate_flags();
+				break;
+		}
+		break;
+		case CC_OP_FLAGS:
+			/* live.  */
+			break;
+		case CC_OP_SUB:
+		case CC_OP_CMP:
+			if (env->cc_size == 4)
+				env->pregs[PR_CCS] =
+					helper_evaluate_flags_sub_4(
+						env->pregs[PR_CCS],
+						env->cc_src, env->cc_dest,
+						env->cc_result);
+			else
+				helper_evaluate_flags();
+			break;
+		default:
+		{
+			switch (env->cc_size)
+			{
+			case 4:
+				env->pregs[PR_CCS] =
+					helper_evaluate_flags_alu_4(
+						env->pregs[PR_CCS],
+						env->cc_src, env->cc_dest,
+						env->cc_result);
+				break;
+			default:
+				helper_evaluate_flags();
+				break;
+			}
+		}
+		break;
+	}
+}
diff --git a/qemu-0.15.x/target-cris/opcode-cris.h b/qemu-0.15.x/target-cris/opcode-cris.h
new file mode 100644
index 0000000..8d4749d
--- /dev/null
+++ b/qemu-0.15.x/target-cris/opcode-cris.h
@@ -0,0 +1,365 @@
+/* cris.h -- Header file for CRIS opcode and register tables.
+   Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
+   Contributed by Axis Communications AB, Lund, Sweden.
+   Originally written for GAS 1.38.1 by Mikael Asker.
+   Updated, BFDized and GNUified by Hans-Peter Nilsson.
+
+This file is part of GAS, GDB and the GNU binutils.
+
+GAS, GDB, and GNU binutils is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GAS, GDB, and GNU binutils are distributed in the hope that they will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef __CRIS_H_INCLUDED_
+#define __CRIS_H_INCLUDED_
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+
+/* Registers.  */
+#define MAX_REG (15)
+#define REG_SP (14)
+#define REG_PC (15)
+
+/* CPU version control of disassembly and assembly of instructions.
+   May affect how the instruction is assembled, at least the size of
+   immediate operands.  */
+enum cris_insn_version_usage
+{
+  /* Any version.  */
+  cris_ver_version_all=0,
+
+  /* Indeterminate (intended for disassembly only, or obsolete).  */
+  cris_ver_warning,
+
+  /* Only for v0..3 (Etrax 1..4).  */
+  cris_ver_v0_3,
+
+  /* Only for v3 or higher (ETRAX 4 and beyond).  */
+  cris_ver_v3p,
+
+  /* Only for v8 (Etrax 100).  */
+  cris_ver_v8,
+
+  /* Only for v8 or higher (ETRAX 100, ETRAX 100 LX).  */
+  cris_ver_v8p,
+
+  /* Only for v0..10.  FIXME: Not sure what to do with this.  */
+  cris_ver_sim_v0_10,
+
+  /* Only for v0..10.  */
+  cris_ver_v0_10,
+
+  /* Only for v3..10.  (ETRAX 4, ETRAX 100 and ETRAX 100 LX).  */
+  cris_ver_v3_10,
+
+  /* Only for v8..10 (ETRAX 100 and ETRAX 100 LX).  */
+  cris_ver_v8_10,
+
+  /* Only for v10 (ETRAX 100 LX) and same series.  */
+  cris_ver_v10,
+
+  /* Only for v10 (ETRAX 100 LX) and same series.  */
+  cris_ver_v10p,
+
+  /* Only for v32 or higher (codename GUINNESS).
+     Of course some or all these of may change to cris_ver_v32p if/when
+     there's a new revision. */
+  cris_ver_v32p
+};
+
+
+/* Special registers.  */
+struct cris_spec_reg
+{
+  const char *const name;
+  unsigned int number;
+
+  /* The size of the register.  */
+  unsigned int reg_size;
+
+  /* What CPU version the special register of that name is implemented
+     in.  If cris_ver_warning, emit an unimplemented-warning.  */
+  enum cris_insn_version_usage applicable_version;
+
+  /* There might be a specific warning for using a special register
+     here.  */
+  const char *const warning;
+};
+extern const struct cris_spec_reg cris_spec_regs[];
+
+
+/* Support registers (kind of special too, but not named as such).  */
+struct cris_support_reg
+{
+  const char *const name;
+  unsigned int number;
+};
+extern const struct cris_support_reg cris_support_regs[];
+
+struct cris_cond15
+{
+  /* The name of the condition.  */
+  const char *const name;
+
+  /* What CPU version this condition name applies to.  */
+  enum cris_insn_version_usage applicable_version;
+};
+extern const struct cris_cond15 cris_conds15[];
+
+/* Opcode-dependent constants.  */
+#define AUTOINCR_BIT (0x04)
+
+/* Prefixes.  */
+#define BDAP_QUICK_OPCODE (0x0100)
+#define BDAP_QUICK_Z_BITS (0x0e00)
+
+#define BIAP_OPCODE	  (0x0540)
+#define BIAP_Z_BITS	  (0x0a80)
+
+#define DIP_OPCODE	  (0x0970)
+#define DIP_Z_BITS	  (0xf280)
+
+#define BDAP_INDIR_LOW	  (0x40)
+#define BDAP_INDIR_LOW_Z  (0x80)
+#define BDAP_INDIR_HIGH	  (0x09)
+#define BDAP_INDIR_HIGH_Z (0x02)
+
+#define BDAP_INDIR_OPCODE (BDAP_INDIR_HIGH * 0x0100 + BDAP_INDIR_LOW)
+#define BDAP_INDIR_Z_BITS (BDAP_INDIR_HIGH_Z * 0x100 + BDAP_INDIR_LOW_Z)
+#define BDAP_PC_LOW	  (BDAP_INDIR_LOW + REG_PC)
+#define BDAP_INCR_HIGH	  (BDAP_INDIR_HIGH + AUTOINCR_BIT)
+
+/* No prefix must have this code for its "match" bits in the
+   opcode-table.  "BCC .+2" will do nicely.  */
+#define NO_CRIS_PREFIX 0
+
+/* Definitions for condition codes.  */
+#define CC_CC  0x0
+#define CC_HS  0x0
+#define CC_CS  0x1
+#define CC_LO  0x1
+#define CC_NE  0x2
+#define CC_EQ  0x3
+#define CC_VC  0x4
+#define CC_VS  0x5
+#define CC_PL  0x6
+#define CC_MI  0x7
+#define CC_LS  0x8
+#define CC_HI  0x9
+#define CC_GE  0xA
+#define CC_LT  0xB
+#define CC_GT  0xC
+#define CC_LE  0xD
+#define CC_A   0xE
+#define CC_EXT 0xF
+
+/* A table of strings "cc", "cs"... indexed with condition code
+   values as above.  */
+extern const char *const cris_cc_strings[];
+
+/* Bcc quick.  */
+#define BRANCH_QUICK_LOW  (0)
+#define BRANCH_QUICK_HIGH (0)
+#define BRANCH_QUICK_OPCODE (BRANCH_QUICK_HIGH * 0x0100 + BRANCH_QUICK_LOW)
+#define BRANCH_QUICK_Z_BITS (0x0F00)
+
+/* BA quick.  */
+#define BA_QUICK_HIGH (BRANCH_QUICK_HIGH + CC_A * 0x10)
+#define BA_QUICK_OPCODE (BA_QUICK_HIGH * 0x100 + BRANCH_QUICK_LOW)
+
+/* Bcc [PC+].  */
+#define BRANCH_PC_LOW	 (0xFF)
+#define BRANCH_INCR_HIGH (0x0D)
+#define BA_PC_INCR_OPCODE \
+ ((BRANCH_INCR_HIGH + CC_A * 0x10) * 0x0100 + BRANCH_PC_LOW)
+
+/* Jump.  */
+/* Note that old versions generated special register 8 (in high bits)
+   and not-that-old versions recognized it as a jump-instruction.
+   That opcode now belongs to JUMPU.  */
+#define JUMP_INDIR_OPCODE (0x0930)
+#define JUMP_INDIR_Z_BITS (0xf2c0)
+#define JUMP_PC_INCR_OPCODE \
+ (JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + REG_PC)
+
+#define MOVE_M_TO_PREG_OPCODE 0x0a30
+#define MOVE_M_TO_PREG_ZBITS 0x01c0
+
+/* BDAP.D N,PC.  */
+#define MOVE_PC_INCR_OPCODE_PREFIX \
+ (((BDAP_INCR_HIGH | (REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4))
+#define MOVE_PC_INCR_OPCODE_SUFFIX \
+ (MOVE_M_TO_PREG_OPCODE | REG_PC | (AUTOINCR_BIT << 8))
+
+#define JUMP_PC_INCR_OPCODE_V32 (0x0DBF)
+
+/* BA DWORD (V32).  */
+#define BA_DWORD_OPCODE (0x0EBF)
+
+/* Nop.  */
+#define NOP_OPCODE (0x050F)
+#define NOP_Z_BITS (0xFFFF ^ NOP_OPCODE)
+
+#define NOP_OPCODE_V32 (0x05B0)
+#define NOP_Z_BITS_V32 (0xFFFF ^ NOP_OPCODE_V32)
+
+/* For the compatibility mode, let's use "MOVE R0,P0".  Doesn't affect
+   registers or flags.  Unfortunately shuts off interrupts for one cycle
+   for < v32, but there doesn't seem to be any alternative without that
+   effect.  */
+#define NOP_OPCODE_COMMON (0x630)
+#define NOP_OPCODE_ZBITS_COMMON (0xffff & ~NOP_OPCODE_COMMON)
+
+/* LAPC.D  */
+#define LAPC_DWORD_OPCODE (0x0D7F)
+#define LAPC_DWORD_Z_BITS (0x0fff & ~LAPC_DWORD_OPCODE)
+
+/* Structure of an opcode table entry.  */
+enum cris_imm_oprnd_size_type
+{
+  /* No size is applicable.  */
+  SIZE_NONE,
+
+  /* Always 32 bits.  */
+  SIZE_FIX_32,
+
+  /* Indicated by size of special register.  */
+  SIZE_SPEC_REG,
+
+  /* Indicated by size field, signed.  */
+  SIZE_FIELD_SIGNED,
+
+  /* Indicated by size field, unsigned.  */
+  SIZE_FIELD_UNSIGNED,
+
+  /* Indicated by size field, no sign implied.  */
+  SIZE_FIELD
+};
+
+/* For GDB.  FIXME: Is this the best way to handle opcode
+   interpretation?  */
+enum cris_op_type
+{
+  cris_not_implemented_op = 0,
+  cris_abs_op,
+  cris_addi_op,
+  cris_asr_op,
+  cris_asrq_op,
+  cris_ax_ei_setf_op,
+  cris_bdap_prefix,
+  cris_biap_prefix,
+  cris_break_op,
+  cris_btst_nop_op,
+  cris_clearf_di_op,
+  cris_dip_prefix,
+  cris_dstep_logshift_mstep_neg_not_op,
+  cris_eight_bit_offset_branch_op,
+  cris_move_mem_to_reg_movem_op,
+  cris_move_reg_to_mem_movem_op,
+  cris_move_to_preg_op,
+  cris_muls_op,
+  cris_mulu_op,
+  cris_none_reg_mode_add_sub_cmp_and_or_move_op,
+  cris_none_reg_mode_clear_test_op,
+  cris_none_reg_mode_jump_op,
+  cris_none_reg_mode_move_from_preg_op,
+  cris_quick_mode_add_sub_op,
+  cris_quick_mode_and_cmp_move_or_op,
+  cris_quick_mode_bdap_prefix,
+  cris_reg_mode_add_sub_cmp_and_or_move_op,
+  cris_reg_mode_clear_op,
+  cris_reg_mode_jump_op,
+  cris_reg_mode_move_from_preg_op,
+  cris_reg_mode_test_op,
+  cris_scc_op,
+  cris_sixteen_bit_offset_branch_op,
+  cris_three_operand_add_sub_cmp_and_or_op,
+  cris_three_operand_bound_op,
+  cris_two_operand_bound_op,
+  cris_xor_op
+};
+
+struct cris_opcode
+{
+  /* The name of the insn.  */
+  const char *name;
+
+  /* Bits that must be 1 for a match.  */
+  unsigned int match;
+
+  /* Bits that must be 0 for a match.  */
+  unsigned int lose;
+
+  /* See the table in "opcodes/cris-opc.c".  */
+  const char *args;
+
+  /* Nonzero if this is a delayed branch instruction.  */
+  char delayed;
+
+  /* Size of immediate operands.  */
+  enum cris_imm_oprnd_size_type imm_oprnd_size;
+
+  /* Indicates which version this insn was first implemented in.  */
+  enum cris_insn_version_usage applicable_version;
+
+  /* What kind of operation this is.  */
+  enum cris_op_type op;
+};
+extern const struct cris_opcode cris_opcodes[];
+
+
+/* These macros are for the target-specific flags in disassemble_info
+   used at disassembly.  */
+
+/* This insn accesses memory.  This flag is more trustworthy than
+   checking insn_type for "dis_dref" which does not work for
+   e.g. "JSR [foo]".  */
+#define CRIS_DIS_FLAG_MEMREF (1 << 0)
+
+/* The "target" field holds a register number.  */
+#define CRIS_DIS_FLAG_MEM_TARGET_IS_REG (1 << 1)
+
+/* The "target2" field holds a register number; add it to "target".  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_IS_REG (1 << 2)
+
+/* Yet another add-on: the register in "target2" must be multiplied
+   by 2 before adding to "target".  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_MULT2 (1 << 3)
+
+/* Yet another add-on: the register in "target2" must be multiplied
+   by 4 (mutually exclusive with .._MULT2).  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_MULT4 (1 << 4)
+
+/* The register in "target2" is an indirect memory reference (of the
+   register there), add to "target".  Assumed size is dword (mutually
+   exclusive with .._MULT[24]).  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_MEM (1 << 5)
+
+/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "byte";
+   sign-extended before adding to "target".  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE (1 << 6)
+
+/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "word";
+   sign-extended before adding to "target".  */
+#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD (1 << 7)
+
+#endif /* __CRIS_H_INCLUDED_ */
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/qemu-0.15.x/target-cris/translate.c b/qemu-0.15.x/target-cris/translate.c
new file mode 100644
index 0000000..dd85859
--- /dev/null
+++ b/qemu-0.15.x/target-cris/translate.c
@@ -0,0 +1,3609 @@
+/*
+ *  CRIS emulation for qemu: main translation routines.
+ *
+ *  Copyright (c) 2008 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * FIXME:
+ * The condition code translation is in need of attention.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "helper.h"
+#include "mmu.h"
+#include "crisv32-decode.h"
+#include "qemu-common.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define DISAS_CRIS 0
+#if DISAS_CRIS
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+#define D(x)
+#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
+#define BUG_ON(x) ({if (x) BUG();})
+
+#define DISAS_SWI 5
+
+/* Used by the decoder.  */
+#define EXTRACT_FIELD(src, start, end) \
+            (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+#define CC_MASK_NZ 0xc
+#define CC_MASK_NZV 0xe
+#define CC_MASK_NZVC 0xf
+#define CC_MASK_RNZV 0x10e
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[16];
+static TCGv cpu_PR[16];
+static TCGv cc_x;
+static TCGv cc_src;
+static TCGv cc_dest;
+static TCGv cc_result;
+static TCGv cc_op;
+static TCGv cc_size;
+static TCGv cc_mask;
+
+static TCGv env_btaken;
+static TCGv env_btarget;
+static TCGv env_pc;
+
+#include "gen-icount.h"
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+	CPUState *env;
+	target_ulong pc, ppc;
+
+	/* Decoder.  */
+	unsigned int (*decoder)(struct DisasContext *dc);
+	uint32_t ir;
+	uint32_t opcode;
+	unsigned int op1;
+	unsigned int op2;
+	unsigned int zsize, zzsize;
+	unsigned int mode;
+	unsigned int postinc;
+
+	unsigned int size;
+	unsigned int src;
+	unsigned int dst;
+	unsigned int cond;
+
+	int update_cc;
+	int cc_op;
+	int cc_size;
+	uint32_t cc_mask;
+
+	int cc_size_uptodate; /* -1 invalid or last written value.  */
+
+	int cc_x_uptodate;  /* 1 - ccs, 2 - known | X_FLAG. 0 not uptodate.  */
+	int flags_uptodate; /* Wether or not $ccs is uptodate.  */
+	int flagx_known; /* Wether or not flags_x has the x flag known at
+			    translation time.  */
+	int flags_x;
+
+	int clear_x; /* Clear x after this insn?  */
+	int clear_prefix; /* Clear prefix after this insn?  */
+	int clear_locked_irq; /* Clear the irq lockout.  */
+	int cpustate_changed;
+	unsigned int tb_flags; /* tb dependent flags.  */
+	int is_jmp;
+
+#define JMP_NOJMP     0
+#define JMP_DIRECT    1
+#define JMP_DIRECT_CC 2
+#define JMP_INDIRECT  3
+	int jmp; /* 0=nojmp, 1=direct, 2=indirect.  */ 
+	uint32_t jmp_pc;
+
+	int delayed_branch;
+
+	struct TranslationBlock *tb;
+	int singlestep_enabled;
+} DisasContext;
+
+static void gen_BUG(DisasContext *dc, const char *file, int line)
+{
+	printf ("BUG: pc=%x %s %d\n", dc->pc, file, line);
+	qemu_log("BUG: pc=%x %s %d\n", dc->pc, file, line);
+	cpu_abort(dc->env, "%s:%d\n", file, line);
+}
+
+static const char *regnames[] =
+{
+	"$r0", "$r1", "$r2", "$r3",
+	"$r4", "$r5", "$r6", "$r7",
+	"$r8", "$r9", "$r10", "$r11",
+	"$r12", "$r13", "$sp", "$acr",
+};
+static const char *pregnames[] =
+{
+	"$bz", "$vr", "$pid", "$srs",
+	"$wz", "$exs", "$eda", "$mof",
+	"$dz", "$ebp", "$erp", "$srp",
+	"$nrp", "$ccs", "$usp", "$spc",
+};
+
+/* We need this table to handle preg-moves with implicit width.  */
+static int preg_sizes[] = {
+	1, /* bz.  */
+	1, /* vr.  */
+	4, /* pid.  */
+	1, /* srs.  */
+	2, /* wz.  */
+	4, 4, 4,
+	4, 4, 4, 4,
+	4, 4, 4, 4,
+};
+
+#define t_gen_mov_TN_env(tn, member) \
+ _t_gen_mov_TN_env((tn), offsetof(CPUState, member))
+#define t_gen_mov_env_TN(member, tn) \
+ _t_gen_mov_env_TN(offsetof(CPUState, member), (tn))
+
+static inline void t_gen_mov_TN_reg(TCGv tn, int r)
+{
+	if (r < 0 || r > 15)
+		fprintf(stderr, "wrong register read $r%d\n", r);
+	tcg_gen_mov_tl(tn, cpu_R[r]);
+}
+static inline void t_gen_mov_reg_TN(int r, TCGv tn)
+{
+	if (r < 0 || r > 15)
+		fprintf(stderr, "wrong register write $r%d\n", r);
+	tcg_gen_mov_tl(cpu_R[r], tn);
+}
+
+static inline void _t_gen_mov_TN_env(TCGv tn, int offset)
+{
+	if (offset > sizeof (CPUState))
+		fprintf(stderr, "wrong load from env from off=%d\n", offset);
+	tcg_gen_ld_tl(tn, cpu_env, offset);
+}
+static inline void _t_gen_mov_env_TN(int offset, TCGv tn)
+{
+	if (offset > sizeof (CPUState))
+		fprintf(stderr, "wrong store to env at off=%d\n", offset);
+	tcg_gen_st_tl(tn, cpu_env, offset);
+}
+
+static inline void t_gen_mov_TN_preg(TCGv tn, int r)
+{
+	if (r < 0 || r > 15)
+		fprintf(stderr, "wrong register read $p%d\n", r);
+	if (r == PR_BZ || r == PR_WZ || r == PR_DZ)
+		tcg_gen_mov_tl(tn, tcg_const_tl(0));
+	else if (r == PR_VR)
+		tcg_gen_mov_tl(tn, tcg_const_tl(32));
+	else
+		tcg_gen_mov_tl(tn, cpu_PR[r]);
+}
+static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
+{
+	if (r < 0 || r > 15)
+		fprintf(stderr, "wrong register write $p%d\n", r);
+	if (r == PR_BZ || r == PR_WZ || r == PR_DZ)
+		return;
+	else if (r == PR_SRS)
+		tcg_gen_andi_tl(cpu_PR[r], tn, 3);
+	else {
+		if (r == PR_PID) 
+			gen_helper_tlb_flush_pid(tn);
+		if (dc->tb_flags & S_FLAG && r == PR_SPC) 
+			gen_helper_spc_write(tn);
+		else if (r == PR_CCS)
+			dc->cpustate_changed = 1;
+		tcg_gen_mov_tl(cpu_PR[r], tn);
+	}
+}
+
+/* Sign extend at translation time.  */
+static int sign_extend(unsigned int val, unsigned int width)
+{
+	int sval;
+
+	/* LSL.  */
+	val <<= 31 - width;
+	sval = val;
+	/* ASR.  */
+	sval >>= 31 - width;
+	return sval;
+}
+
+static int cris_fetch(DisasContext *dc, uint32_t addr,
+		      unsigned int size, unsigned int sign)
+{
+	int r;
+
+	switch (size) {
+		case 4:
+		{
+			r = ldl_code(addr);
+			break;
+		}
+		case 2:
+		{
+			if (sign) {
+				r = ldsw_code(addr);
+			} else {
+				r = lduw_code(addr);
+			}
+			break;
+		}
+		case 1:
+		{
+			if (sign) {
+				r = ldsb_code(addr);
+			} else {
+				r = ldub_code(addr);
+			}
+			break;
+		}
+		default:
+			cpu_abort(dc->env, "Invalid fetch size %d\n", size);
+			break;
+	}
+	return r;
+}
+
+static void cris_lock_irq(DisasContext *dc)
+{
+	dc->clear_locked_irq = 0;
+	t_gen_mov_env_TN(locked_irq, tcg_const_tl(1));
+}
+
+static inline void t_gen_raise_exception(uint32_t index)
+{
+        TCGv_i32 tmp = tcg_const_i32(index);
+	gen_helper_raise_exception(tmp);
+        tcg_temp_free_i32(tmp);
+}
+
+static void t_gen_lsl(TCGv d, TCGv a, TCGv b)
+{
+	TCGv t0, t_31;
+
+	t0 = tcg_temp_new();
+	t_31 = tcg_const_tl(31);
+	tcg_gen_shl_tl(d, a, b);
+
+	tcg_gen_sub_tl(t0, t_31, b);
+	tcg_gen_sar_tl(t0, t0, t_31);
+	tcg_gen_and_tl(t0, t0, d);
+	tcg_gen_xor_tl(d, d, t0);
+	tcg_temp_free(t0);
+	tcg_temp_free(t_31);
+}
+
+static void t_gen_lsr(TCGv d, TCGv a, TCGv b)
+{
+	TCGv t0, t_31;
+
+	t0 = tcg_temp_new();
+	t_31 = tcg_temp_new();
+	tcg_gen_shr_tl(d, a, b);
+
+	tcg_gen_movi_tl(t_31, 31);
+	tcg_gen_sub_tl(t0, t_31, b);
+	tcg_gen_sar_tl(t0, t0, t_31);
+	tcg_gen_and_tl(t0, t0, d);
+	tcg_gen_xor_tl(d, d, t0);
+	tcg_temp_free(t0);
+	tcg_temp_free(t_31);
+}
+
+static void t_gen_asr(TCGv d, TCGv a, TCGv b)
+{
+	TCGv t0, t_31;
+
+	t0 = tcg_temp_new();
+	t_31 = tcg_temp_new();
+	tcg_gen_sar_tl(d, a, b);
+
+	tcg_gen_movi_tl(t_31, 31);
+	tcg_gen_sub_tl(t0, t_31, b);
+	tcg_gen_sar_tl(t0, t0, t_31);
+	tcg_gen_or_tl(d, d, t0);
+	tcg_temp_free(t0);
+	tcg_temp_free(t_31);
+}
+
+/* 64-bit signed mul, lower result in d and upper in d2.  */
+static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b)
+{
+	TCGv_i64 t0, t1;
+
+	t0 = tcg_temp_new_i64();
+	t1 = tcg_temp_new_i64();
+
+	tcg_gen_ext_i32_i64(t0, a);
+	tcg_gen_ext_i32_i64(t1, b);
+	tcg_gen_mul_i64(t0, t0, t1);
+
+	tcg_gen_trunc_i64_i32(d, t0);
+	tcg_gen_shri_i64(t0, t0, 32);
+	tcg_gen_trunc_i64_i32(d2, t0);
+
+	tcg_temp_free_i64(t0);
+	tcg_temp_free_i64(t1);
+}
+
+/* 64-bit unsigned muls, lower result in d and upper in d2.  */
+static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b)
+{
+	TCGv_i64 t0, t1;
+
+	t0 = tcg_temp_new_i64();
+	t1 = tcg_temp_new_i64();
+
+	tcg_gen_extu_i32_i64(t0, a);
+	tcg_gen_extu_i32_i64(t1, b);
+	tcg_gen_mul_i64(t0, t0, t1);
+
+	tcg_gen_trunc_i64_i32(d, t0);
+	tcg_gen_shri_i64(t0, t0, 32);
+	tcg_gen_trunc_i64_i32(d2, t0);
+
+	tcg_temp_free_i64(t0);
+	tcg_temp_free_i64(t1);
+}
+
+static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
+{
+	int l1;
+
+	l1 = gen_new_label();
+
+	/* 
+	 * d <<= 1
+	 * if (d >= s)
+	 *    d -= s;
+	 */
+	tcg_gen_shli_tl(d, a, 1);
+	tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1);
+	tcg_gen_sub_tl(d, d, b);
+	gen_set_label(l1);
+}
+
+static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs)
+{
+	TCGv t;
+
+	/* 
+	 * d <<= 1
+	 * if (n)
+	 *    d += s;
+	 */
+	t = tcg_temp_new();
+	tcg_gen_shli_tl(d, a, 1);
+	tcg_gen_shli_tl(t, ccs, 31 - 3);
+	tcg_gen_sari_tl(t, t, 31);
+	tcg_gen_and_tl(t, t, b);
+	tcg_gen_add_tl(d, d, t);
+	tcg_temp_free(t);
+}
+
+/* Extended arithmetics on CRIS.  */
+static inline void t_gen_add_flag(TCGv d, int flag)
+{
+	TCGv c;
+
+	c = tcg_temp_new();
+	t_gen_mov_TN_preg(c, PR_CCS);
+	/* Propagate carry into d.  */
+	tcg_gen_andi_tl(c, c, 1 << flag);
+	if (flag)
+		tcg_gen_shri_tl(c, c, flag);
+	tcg_gen_add_tl(d, d, c);
+	tcg_temp_free(c);
+}
+
+static inline void t_gen_addx_carry(DisasContext *dc, TCGv d)
+{
+	if (dc->flagx_known) {
+		if (dc->flags_x) {
+			TCGv c;
+            
+			c = tcg_temp_new();
+			t_gen_mov_TN_preg(c, PR_CCS);
+			/* C flag is already at bit 0.  */
+			tcg_gen_andi_tl(c, c, C_FLAG);
+			tcg_gen_add_tl(d, d, c);
+			tcg_temp_free(c);
+		}
+	} else {
+		TCGv x, c;
+
+		x = tcg_temp_new();
+		c = tcg_temp_new();
+		t_gen_mov_TN_preg(x, PR_CCS);
+		tcg_gen_mov_tl(c, x);
+
+		/* Propagate carry into d if X is set. Branch free.  */
+		tcg_gen_andi_tl(c, c, C_FLAG);
+		tcg_gen_andi_tl(x, x, X_FLAG);
+		tcg_gen_shri_tl(x, x, 4);
+
+		tcg_gen_and_tl(x, x, c);
+		tcg_gen_add_tl(d, d, x);        
+		tcg_temp_free(x);
+		tcg_temp_free(c);
+	}
+}
+
+static inline void t_gen_subx_carry(DisasContext *dc, TCGv d)
+{
+	if (dc->flagx_known) {
+		if (dc->flags_x) {
+			TCGv c;
+            
+			c = tcg_temp_new();
+			t_gen_mov_TN_preg(c, PR_CCS);
+			/* C flag is already at bit 0.  */
+			tcg_gen_andi_tl(c, c, C_FLAG);
+			tcg_gen_sub_tl(d, d, c);
+			tcg_temp_free(c);
+		}
+	} else {
+		TCGv x, c;
+
+		x = tcg_temp_new();
+		c = tcg_temp_new();
+		t_gen_mov_TN_preg(x, PR_CCS);
+		tcg_gen_mov_tl(c, x);
+
+		/* Propagate carry into d if X is set. Branch free.  */
+		tcg_gen_andi_tl(c, c, C_FLAG);
+		tcg_gen_andi_tl(x, x, X_FLAG);
+		tcg_gen_shri_tl(x, x, 4);
+
+		tcg_gen_and_tl(x, x, c);
+		tcg_gen_sub_tl(d, d, x);
+		tcg_temp_free(x);
+		tcg_temp_free(c);
+	}
+}
+
+/* Swap the two bytes within each half word of the s operand.
+   T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff)  */
+static inline void t_gen_swapb(TCGv d, TCGv s)
+{
+	TCGv t, org_s;
+
+	t = tcg_temp_new();
+	org_s = tcg_temp_new();
+
+	/* d and s may refer to the same object.  */
+	tcg_gen_mov_tl(org_s, s);
+	tcg_gen_shli_tl(t, org_s, 8);
+	tcg_gen_andi_tl(d, t, 0xff00ff00);
+	tcg_gen_shri_tl(t, org_s, 8);
+	tcg_gen_andi_tl(t, t, 0x00ff00ff);
+	tcg_gen_or_tl(d, d, t);
+	tcg_temp_free(t);
+	tcg_temp_free(org_s);
+}
+
+/* Swap the halfwords of the s operand.  */
+static inline void t_gen_swapw(TCGv d, TCGv s)
+{
+	TCGv t;
+	/* d and s refer the same object.  */
+	t = tcg_temp_new();
+	tcg_gen_mov_tl(t, s);
+	tcg_gen_shli_tl(d, t, 16);
+	tcg_gen_shri_tl(t, t, 16);
+	tcg_gen_or_tl(d, d, t);
+	tcg_temp_free(t);
+}
+
+/* Reverse the within each byte.
+   T0 = (((T0 << 7) & 0x80808080) |
+   ((T0 << 5) & 0x40404040) |
+   ((T0 << 3) & 0x20202020) |
+   ((T0 << 1) & 0x10101010) |
+   ((T0 >> 1) & 0x08080808) |
+   ((T0 >> 3) & 0x04040404) |
+   ((T0 >> 5) & 0x02020202) |
+   ((T0 >> 7) & 0x01010101));
+ */
+static inline void t_gen_swapr(TCGv d, TCGv s)
+{
+	struct {
+		int shift; /* LSL when positive, LSR when negative.  */
+		uint32_t mask;
+	} bitrev [] = {
+		{7, 0x80808080},
+		{5, 0x40404040},
+		{3, 0x20202020},
+		{1, 0x10101010},
+		{-1, 0x08080808},
+		{-3, 0x04040404},
+		{-5, 0x02020202},
+		{-7, 0x01010101}
+	};
+	int i;
+	TCGv t, org_s;
+
+	/* d and s refer the same object.  */
+	t = tcg_temp_new();
+	org_s = tcg_temp_new();
+	tcg_gen_mov_tl(org_s, s);
+
+	tcg_gen_shli_tl(t, org_s,  bitrev[0].shift);
+	tcg_gen_andi_tl(d, t,  bitrev[0].mask);
+	for (i = 1; i < ARRAY_SIZE(bitrev); i++) {
+		if (bitrev[i].shift >= 0) {
+			tcg_gen_shli_tl(t, org_s,  bitrev[i].shift);
+		} else {
+			tcg_gen_shri_tl(t, org_s,  -bitrev[i].shift);
+		}
+		tcg_gen_andi_tl(t, t,  bitrev[i].mask);
+		tcg_gen_or_tl(d, d, t);
+	}
+	tcg_temp_free(t);
+	tcg_temp_free(org_s);
+}
+
+static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
+{
+	int l1;
+
+	l1 = gen_new_label();
+
+	/* Conditional jmp.  */
+	tcg_gen_mov_tl(env_pc, pc_false);
+	tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
+	tcg_gen_mov_tl(env_pc, pc_true);
+	gen_set_label(l1);
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+	TranslationBlock *tb;
+	tb = dc->tb;
+	if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+		tcg_gen_goto_tb(n);
+		tcg_gen_movi_tl(env_pc, dest);
+                tcg_gen_exit_tb((tcg_target_long)tb + n);
+	} else {
+		tcg_gen_movi_tl(env_pc, dest);
+		tcg_gen_exit_tb(0);
+	}
+}
+
+static inline void cris_clear_x_flag(DisasContext *dc)
+{
+	if (dc->flagx_known && dc->flags_x)
+		dc->flags_uptodate = 0;
+
+	dc->flagx_known = 1;
+	dc->flags_x = 0;
+}
+
+static void cris_flush_cc_state(DisasContext *dc)
+{
+	if (dc->cc_size_uptodate != dc->cc_size) {
+		tcg_gen_movi_tl(cc_size, dc->cc_size);
+		dc->cc_size_uptodate = dc->cc_size;
+	}
+	tcg_gen_movi_tl(cc_op, dc->cc_op);
+	tcg_gen_movi_tl(cc_mask, dc->cc_mask);
+}
+
+static void cris_evaluate_flags(DisasContext *dc)
+{
+	if (dc->flags_uptodate)
+		return;
+
+	cris_flush_cc_state(dc);
+
+	switch (dc->cc_op)
+	{
+	case CC_OP_MCP:
+		gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS],
+					cpu_PR[PR_CCS], cc_src,
+					cc_dest, cc_result);
+		break;
+	case CC_OP_MULS:
+		gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS],
+					cpu_PR[PR_CCS], cc_result,
+					cpu_PR[PR_MOF]);
+		break;
+	case CC_OP_MULU:
+		gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS],
+					cpu_PR[PR_CCS], cc_result,
+					cpu_PR[PR_MOF]);
+		break;
+	case CC_OP_MOVE:
+	case CC_OP_AND:
+	case CC_OP_OR:
+	case CC_OP_XOR:
+	case CC_OP_ASR:
+	case CC_OP_LSR:
+	case CC_OP_LSL:
+		switch (dc->cc_size)
+		{
+		case 4:
+			gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS],
+						cpu_PR[PR_CCS], cc_result);
+			break;
+		case 2:
+			gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS],
+						cpu_PR[PR_CCS], cc_result);
+			break;
+		default:
+			gen_helper_evaluate_flags();
+			break;
+		}
+		break;
+	case CC_OP_FLAGS:
+		/* live.  */
+		break;
+	case CC_OP_SUB:
+	case CC_OP_CMP:
+		if (dc->cc_size == 4)
+			gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS],
+				cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
+		else
+			gen_helper_evaluate_flags();
+
+		break;
+	default:
+		switch (dc->cc_size)
+		{
+			case 4:
+			gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS],
+				cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
+				break;
+			default:
+				gen_helper_evaluate_flags();
+				break;
+		}
+		break;
+	}
+
+	if (dc->flagx_known) {
+		if (dc->flags_x)
+			tcg_gen_ori_tl(cpu_PR[PR_CCS], 
+				       cpu_PR[PR_CCS], X_FLAG);
+		else if (dc->cc_op == CC_OP_FLAGS)
+			tcg_gen_andi_tl(cpu_PR[PR_CCS], 
+					cpu_PR[PR_CCS], ~X_FLAG);
+        }
+	dc->flags_uptodate = 1;
+}
+
+static void cris_cc_mask(DisasContext *dc, unsigned int mask)
+{
+	uint32_t ovl;
+
+	if (!mask) {
+		dc->update_cc = 0;
+		return;
+	}	
+
+	/* Check if we need to evaluate the condition codes due to 
+	   CC overlaying.  */
+	ovl = (dc->cc_mask ^ mask) & ~mask;
+	if (ovl) {
+		/* TODO: optimize this case. It trigs all the time.  */
+		cris_evaluate_flags (dc);
+	}
+	dc->cc_mask = mask;
+	dc->update_cc = 1;
+}
+
+static void cris_update_cc_op(DisasContext *dc, int op, int size)
+{
+	dc->cc_op = op;
+	dc->cc_size = size;
+	dc->flags_uptodate = 0;
+}
+
+static inline void cris_update_cc_x(DisasContext *dc)
+{
+	/* Save the x flag state at the time of the cc snapshot.  */
+	if (dc->flagx_known) {
+		if (dc->cc_x_uptodate == (2 | dc->flags_x))
+			return;
+		tcg_gen_movi_tl(cc_x, dc->flags_x);
+		dc->cc_x_uptodate = 2 | dc->flags_x;
+	}
+	else {
+		tcg_gen_andi_tl(cc_x, cpu_PR[PR_CCS], X_FLAG);
+		dc->cc_x_uptodate = 1;
+	}
+}
+
+/* Update cc prior to executing ALU op. Needs source operands untouched.  */
+static void cris_pre_alu_update_cc(DisasContext *dc, int op, 
+				   TCGv dst, TCGv src, int size)
+{
+	if (dc->update_cc) {
+		cris_update_cc_op(dc, op, size);
+		tcg_gen_mov_tl(cc_src, src);
+
+		if (op != CC_OP_MOVE
+		    && op != CC_OP_AND
+		    && op != CC_OP_OR
+		    && op != CC_OP_XOR
+		    && op != CC_OP_ASR
+		    && op != CC_OP_LSR
+		    && op != CC_OP_LSL)
+			tcg_gen_mov_tl(cc_dest, dst);
+
+		cris_update_cc_x(dc);
+	}
+}
+
+/* Update cc after executing ALU op. needs the result.  */
+static inline void cris_update_result(DisasContext *dc, TCGv res)
+{
+	if (dc->update_cc)
+		tcg_gen_mov_tl(cc_result, res);
+}
+
+/* Returns one if the write back stage should execute.  */
+static void cris_alu_op_exec(DisasContext *dc, int op, 
+			       TCGv dst, TCGv a, TCGv b, int size)
+{
+	/* Emit the ALU insns.  */
+	switch (op)
+	{
+		case CC_OP_ADD:
+			tcg_gen_add_tl(dst, a, b);
+			/* Extended arithmetics.  */
+			t_gen_addx_carry(dc, dst);
+			break;
+		case CC_OP_ADDC:
+			tcg_gen_add_tl(dst, a, b);
+			t_gen_add_flag(dst, 0); /* C_FLAG.  */
+			break;
+		case CC_OP_MCP:
+			tcg_gen_add_tl(dst, a, b);
+			t_gen_add_flag(dst, 8); /* R_FLAG.  */
+			break;
+		case CC_OP_SUB:
+			tcg_gen_sub_tl(dst, a, b);
+			/* Extended arithmetics.  */
+			t_gen_subx_carry(dc, dst);
+			break;
+		case CC_OP_MOVE:
+			tcg_gen_mov_tl(dst, b);
+			break;
+		case CC_OP_OR:
+			tcg_gen_or_tl(dst, a, b);
+			break;
+		case CC_OP_AND:
+			tcg_gen_and_tl(dst, a, b);
+			break;
+		case CC_OP_XOR:
+			tcg_gen_xor_tl(dst, a, b);
+			break;
+		case CC_OP_LSL:
+			t_gen_lsl(dst, a, b);
+			break;
+		case CC_OP_LSR:
+			t_gen_lsr(dst, a, b);
+			break;
+		case CC_OP_ASR:
+			t_gen_asr(dst, a, b);
+			break;
+		case CC_OP_NEG:
+			tcg_gen_neg_tl(dst, b);
+			/* Extended arithmetics.  */
+			t_gen_subx_carry(dc, dst);
+			break;
+		case CC_OP_LZ:
+			gen_helper_lz(dst, b);
+			break;
+		case CC_OP_MULS:
+			t_gen_muls(dst, cpu_PR[PR_MOF], a, b);
+			break;
+		case CC_OP_MULU:
+			t_gen_mulu(dst, cpu_PR[PR_MOF], a, b);
+			break;
+		case CC_OP_DSTEP:
+			t_gen_cris_dstep(dst, a, b);
+			break;
+		case CC_OP_MSTEP:
+			t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]);
+			break;
+		case CC_OP_BOUND:
+		{
+			int l1;
+			l1 = gen_new_label();
+			tcg_gen_mov_tl(dst, a);
+			tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1);
+			tcg_gen_mov_tl(dst, b);
+			gen_set_label(l1);
+		}
+		break;
+		case CC_OP_CMP:
+			tcg_gen_sub_tl(dst, a, b);
+			/* Extended arithmetics.  */
+			t_gen_subx_carry(dc, dst);
+			break;
+		default:
+			qemu_log("illegal ALU op.\n");
+			BUG();
+			break;
+	}
+
+	if (size == 1)
+		tcg_gen_andi_tl(dst, dst, 0xff);
+	else if (size == 2)
+		tcg_gen_andi_tl(dst, dst, 0xffff);
+}
+
+static void cris_alu(DisasContext *dc, int op,
+			       TCGv d, TCGv op_a, TCGv op_b, int size)
+{
+	TCGv tmp;
+	int writeback;
+
+	writeback = 1;
+
+	if (op == CC_OP_CMP) {
+		tmp = tcg_temp_new();
+		writeback = 0;
+	} else if (size == 4) {
+		tmp = d;
+		writeback = 0;
+	} else
+		tmp = tcg_temp_new();
+
+
+	cris_pre_alu_update_cc(dc, op, op_a, op_b, size);
+	cris_alu_op_exec(dc, op, tmp, op_a, op_b, size);
+	cris_update_result(dc, tmp);
+
+	/* Writeback.  */
+	if (writeback) {
+		if (size == 1)
+			tcg_gen_andi_tl(d, d, ~0xff);
+		else
+			tcg_gen_andi_tl(d, d, ~0xffff);
+		tcg_gen_or_tl(d, d, tmp);
+	}
+	if (!TCGV_EQUAL(tmp, d))
+		tcg_temp_free(tmp);
+}
+
+static int arith_cc(DisasContext *dc)
+{
+	if (dc->update_cc) {
+		switch (dc->cc_op) {
+			case CC_OP_ADDC: return 1;
+			case CC_OP_ADD: return 1;
+			case CC_OP_SUB: return 1;
+			case CC_OP_DSTEP: return 1;
+			case CC_OP_LSL: return 1;
+			case CC_OP_LSR: return 1;
+			case CC_OP_ASR: return 1;
+			case CC_OP_CMP: return 1;
+			case CC_OP_NEG: return 1;
+			case CC_OP_OR: return 1;
+			case CC_OP_AND: return 1;
+			case CC_OP_XOR: return 1;
+			case CC_OP_MULU: return 1;
+			case CC_OP_MULS: return 1;
+			default:
+				return 0;
+		}
+	}
+	return 0;
+}
+
+static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
+{
+	int arith_opt, move_opt;
+
+	/* TODO: optimize more condition codes.  */
+
+	/*
+	 * If the flags are live, we've gotta look into the bits of CCS.
+	 * Otherwise, if we just did an arithmetic operation we try to
+	 * evaluate the condition code faster.
+	 *
+	 * When this function is done, T0 should be non-zero if the condition
+	 * code is true.
+	 */
+	arith_opt = arith_cc(dc) && !dc->flags_uptodate;
+	move_opt = (dc->cc_op == CC_OP_MOVE);
+	switch (cond) {
+		case CC_EQ:
+			if ((arith_opt || move_opt)
+			    && dc->cc_x_uptodate != (2 | X_FLAG)) {
+				tcg_gen_setcond_tl(TCG_COND_EQ, cc,
+						   cc_result, tcg_const_tl(0));
+			}
+			else {
+				cris_evaluate_flags(dc);
+				tcg_gen_andi_tl(cc, 
+						cpu_PR[PR_CCS], Z_FLAG);
+			}
+			break;
+		case CC_NE:
+			if ((arith_opt || move_opt)
+			    && dc->cc_x_uptodate != (2 | X_FLAG)) {
+				tcg_gen_mov_tl(cc, cc_result);
+	 		} else {
+				cris_evaluate_flags(dc);
+				tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
+						Z_FLAG);
+				tcg_gen_andi_tl(cc, cc, Z_FLAG);
+			}
+			break;
+		case CC_CS:
+			cris_evaluate_flags(dc);
+			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG);
+			break;
+		case CC_CC:
+			cris_evaluate_flags(dc);
+			tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG);
+			tcg_gen_andi_tl(cc, cc, C_FLAG);
+			break;
+		case CC_VS:
+			cris_evaluate_flags(dc);
+			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG);
+			break;
+		case CC_VC:
+			cris_evaluate_flags(dc);
+			tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
+					V_FLAG);
+			tcg_gen_andi_tl(cc, cc, V_FLAG);
+			break;
+		case CC_PL:
+			if (arith_opt || move_opt) {
+				int bits = 31;
+
+				if (dc->cc_size == 1)
+					bits = 7;
+				else if (dc->cc_size == 2)
+					bits = 15;	
+
+				tcg_gen_shri_tl(cc, cc_result, bits);
+				tcg_gen_xori_tl(cc, cc, 1);
+			} else {
+				cris_evaluate_flags(dc);
+				tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
+						N_FLAG);
+				tcg_gen_andi_tl(cc, cc, N_FLAG);
+			}
+			break;
+		case CC_MI:
+			if (arith_opt || move_opt) {
+				int bits = 31;
+
+				if (dc->cc_size == 1)
+					bits = 7;
+				else if (dc->cc_size == 2)
+					bits = 15;	
+
+				tcg_gen_shri_tl(cc, cc_result, bits);
+				tcg_gen_andi_tl(cc, cc, 1);
+			}
+			else {
+				cris_evaluate_flags(dc);
+				tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
+						N_FLAG);
+			}
+			break;
+		case CC_LS:
+			cris_evaluate_flags(dc);
+			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
+					C_FLAG | Z_FLAG);
+			break;
+		case CC_HI:
+			cris_evaluate_flags(dc);
+			{
+				TCGv tmp;
+
+				tmp = tcg_temp_new();
+				tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS],
+						C_FLAG | Z_FLAG);
+				/* Overlay the C flag on top of the Z.  */
+				tcg_gen_shli_tl(cc, tmp, 2);
+				tcg_gen_and_tl(cc, tmp, cc);
+				tcg_gen_andi_tl(cc, cc, Z_FLAG);
+
+				tcg_temp_free(tmp);
+			}
+			break;
+		case CC_GE:
+			cris_evaluate_flags(dc);
+			/* Overlay the V flag on top of the N.  */
+			tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
+			tcg_gen_xor_tl(cc,
+				       cpu_PR[PR_CCS], cc);
+			tcg_gen_andi_tl(cc, cc, N_FLAG);
+			tcg_gen_xori_tl(cc, cc, N_FLAG);
+			break;
+		case CC_LT:
+			cris_evaluate_flags(dc);
+			/* Overlay the V flag on top of the N.  */
+			tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
+			tcg_gen_xor_tl(cc,
+				       cpu_PR[PR_CCS], cc);
+			tcg_gen_andi_tl(cc, cc, N_FLAG);
+			break;
+		case CC_GT:
+			cris_evaluate_flags(dc);
+			{
+				TCGv n, z;
+
+				n = tcg_temp_new();
+				z = tcg_temp_new();
+
+				/* To avoid a shift we overlay everything on
+				   the V flag.  */
+				tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
+				tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);
+				/* invert Z.  */
+				tcg_gen_xori_tl(z, z, 2);
+
+				tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
+				tcg_gen_xori_tl(n, n, 2);
+				tcg_gen_and_tl(cc, z, n);
+				tcg_gen_andi_tl(cc, cc, 2);
+
+				tcg_temp_free(n);
+				tcg_temp_free(z);
+			}
+			break;
+		case CC_LE:
+			cris_evaluate_flags(dc);
+			{
+				TCGv n, z;
+
+				n = tcg_temp_new();
+				z = tcg_temp_new();
+
+				/* To avoid a shift we overlay everything on
+				   the V flag.  */
+				tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
+				tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);
+
+				tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
+				tcg_gen_or_tl(cc, z, n);
+				tcg_gen_andi_tl(cc, cc, 2);
+
+				tcg_temp_free(n);
+				tcg_temp_free(z);
+			}
+			break;
+		case CC_P:
+			cris_evaluate_flags(dc);
+			tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG);
+			break;
+		case CC_A:
+			tcg_gen_movi_tl(cc, 1);
+			break;
+		default:
+			BUG();
+			break;
+	};
+}
+
+static void cris_store_direct_jmp(DisasContext *dc)
+{
+	/* Store the direct jmp state into the cpu-state.  */
+	if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+		if (dc->jmp == JMP_DIRECT) {
+			tcg_gen_movi_tl(env_btaken, 1);
+		}
+		tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+		dc->jmp = JMP_INDIRECT;
+	}
+}
+
+static void cris_prepare_cc_branch (DisasContext *dc, 
+				    int offset, int cond)
+{
+	/* This helps us re-schedule the micro-code to insns in delay-slots
+	   before the actual jump.  */
+	dc->delayed_branch = 2;
+	dc->jmp = JMP_DIRECT_CC;
+	dc->jmp_pc = dc->pc + offset;
+
+	gen_tst_cc (dc, env_btaken, cond);
+	tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+}
+
+
+/* jumps, when the dest is in a live reg for example. Direct should be set
+   when the dest addr is constant to allow tb chaining.  */
+static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
+{
+	/* This helps us re-schedule the micro-code to insns in delay-slots
+	   before the actual jump.  */
+	dc->delayed_branch = 2;
+	dc->jmp = type;
+	if (type == JMP_INDIRECT) {
+		tcg_gen_movi_tl(env_btaken, 1);
+	}
+}
+
+static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
+{
+	int mem_index = cpu_mmu_index(dc->env);
+
+	/* If we get a fault on a delayslot we must keep the jmp state in
+	   the cpu-state to be able to re-execute the jmp.  */
+	if (dc->delayed_branch == 1)
+		cris_store_direct_jmp(dc);
+
+        tcg_gen_qemu_ld64(dst, addr, mem_index);
+}
+
+static void gen_load(DisasContext *dc, TCGv dst, TCGv addr, 
+		     unsigned int size, int sign)
+{
+	int mem_index = cpu_mmu_index(dc->env);
+
+	/* If we get a fault on a delayslot we must keep the jmp state in
+	   the cpu-state to be able to re-execute the jmp.  */
+	if (dc->delayed_branch == 1)
+		cris_store_direct_jmp(dc);
+
+	if (size == 1) {
+		if (sign)
+			tcg_gen_qemu_ld8s(dst, addr, mem_index);
+		else
+			tcg_gen_qemu_ld8u(dst, addr, mem_index);
+	}
+	else if (size == 2) {
+		if (sign)
+			tcg_gen_qemu_ld16s(dst, addr, mem_index);
+		else
+			tcg_gen_qemu_ld16u(dst, addr, mem_index);
+	}
+	else if (size == 4) {
+		tcg_gen_qemu_ld32u(dst, addr, mem_index);
+	}
+	else {
+		abort();
+	}
+}
+
+static void gen_store (DisasContext *dc, TCGv addr, TCGv val,
+		       unsigned int size)
+{
+	int mem_index = cpu_mmu_index(dc->env);
+
+	/* If we get a fault on a delayslot we must keep the jmp state in
+	   the cpu-state to be able to re-execute the jmp.  */
+	if (dc->delayed_branch == 1)
+ 		cris_store_direct_jmp(dc);
+
+
+	/* Conditional writes. We only support the kind were X and P are known
+	   at translation time.  */
+	if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) {
+		dc->postinc = 0;
+		cris_evaluate_flags(dc);
+		tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG);
+		return;
+	}
+
+	if (size == 1)
+		tcg_gen_qemu_st8(val, addr, mem_index);
+	else if (size == 2)
+		tcg_gen_qemu_st16(val, addr, mem_index);
+	else
+		tcg_gen_qemu_st32(val, addr, mem_index);
+
+	if (dc->flagx_known && dc->flags_x) {
+		cris_evaluate_flags(dc);
+		tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG);
+	}
+}
+
+static inline void t_gen_sext(TCGv d, TCGv s, int size)
+{
+	if (size == 1)
+		tcg_gen_ext8s_i32(d, s);
+	else if (size == 2)
+		tcg_gen_ext16s_i32(d, s);
+	else if(!TCGV_EQUAL(d, s))
+		tcg_gen_mov_tl(d, s);
+}
+
+static inline void t_gen_zext(TCGv d, TCGv s, int size)
+{
+	if (size == 1)
+		tcg_gen_ext8u_i32(d, s);
+	else if (size == 2)
+		tcg_gen_ext16u_i32(d, s);
+	else if (!TCGV_EQUAL(d, s))
+		tcg_gen_mov_tl(d, s);
+}
+
+#if DISAS_CRIS
+static char memsize_char(int size)
+{
+	switch (size)
+	{
+		case 1: return 'b';  break;
+		case 2: return 'w';  break;
+		case 4: return 'd';  break;
+		default:
+			return 'x';
+			break;
+	}
+}
+#endif
+
+static inline unsigned int memsize_z(DisasContext *dc)
+{
+	return dc->zsize + 1;
+}
+
+static inline unsigned int memsize_zz(DisasContext *dc)
+{
+	switch (dc->zzsize)
+	{
+		case 0: return 1;
+		case 1: return 2;
+		default:
+			return 4;
+	}
+}
+
+static inline void do_postinc (DisasContext *dc, int size)
+{
+	if (dc->postinc)
+		tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size);
+}
+
+static inline void dec_prep_move_r(DisasContext *dc, int rs, int rd,
+				   int size, int s_ext, TCGv dst)
+{
+	if (s_ext)
+		t_gen_sext(dst, cpu_R[rs], size);
+	else
+		t_gen_zext(dst, cpu_R[rs], size);
+}
+
+/* Prepare T0 and T1 for a register alu operation.
+   s_ext decides if the operand1 should be sign-extended or zero-extended when
+   needed.  */
+static void dec_prep_alu_r(DisasContext *dc, int rs, int rd,
+			  int size, int s_ext, TCGv dst, TCGv src)
+{
+	dec_prep_move_r(dc, rs, rd, size, s_ext, src);
+
+	if (s_ext)
+		t_gen_sext(dst, cpu_R[rd], size);
+	else
+		t_gen_zext(dst, cpu_R[rd], size);
+}
+
+static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize,
+			   TCGv dst)
+{
+	unsigned int rs;
+	uint32_t imm;
+	int is_imm;
+	int insn_len = 2;
+
+	rs = dc->op1;
+	is_imm = rs == 15 && dc->postinc;
+
+	/* Load [$rs] onto T1.  */
+	if (is_imm) {
+		insn_len = 2 + memsize;
+		if (memsize == 1)
+			insn_len++;
+
+		imm = cris_fetch(dc, dc->pc + 2, memsize, s_ext);
+		tcg_gen_movi_tl(dst, imm);
+		dc->postinc = 0;
+	} else {
+		cris_flush_cc_state(dc);
+		gen_load(dc, dst, cpu_R[rs], memsize, 0);
+		if (s_ext)
+			t_gen_sext(dst, dst, memsize);
+		else
+			t_gen_zext(dst, dst, memsize);
+	}
+	return insn_len;
+}
+
+/* Prepare T0 and T1 for a memory + alu operation.
+   s_ext decides if the operand1 should be sign-extended or zero-extended when
+   needed.  */
+static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize,
+			  TCGv dst, TCGv src)
+{
+	int insn_len;
+
+	insn_len = dec_prep_move_m(dc, s_ext, memsize, src);
+	tcg_gen_mov_tl(dst, cpu_R[dc->op2]);
+	return insn_len;
+}
+
+#if DISAS_CRIS
+static const char *cc_name(int cc)
+{
+	static const char *cc_names[16] = {
+		"cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi",
+		"ls", "hi", "ge", "lt", "gt", "le", "a", "p"
+	};
+	assert(cc < 16);
+	return cc_names[cc];
+}
+#endif
+
+/* Start of insn decoders.  */
+
+static int dec_bccq(DisasContext *dc)
+{
+	int32_t offset;
+	int sign;
+	uint32_t cond = dc->op2;
+
+	offset = EXTRACT_FIELD (dc->ir, 1, 7);
+	sign = EXTRACT_FIELD(dc->ir, 0, 0);
+
+	offset *= 2;
+	offset |= sign << 8;
+	offset = sign_extend(offset, 8);
+
+	LOG_DIS("b%s %x\n", cc_name(cond), dc->pc + offset);
+
+	/* op2 holds the condition-code.  */
+	cris_cc_mask(dc, 0);
+	cris_prepare_cc_branch (dc, offset, cond);
+	return 2;
+}
+static int dec_addoq(DisasContext *dc)
+{
+	int32_t imm;
+
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7);
+	imm = sign_extend(dc->op1, 7);
+
+	LOG_DIS("addoq %d, $r%u\n", imm, dc->op2);
+	cris_cc_mask(dc, 0);
+	/* Fetch register operand,  */
+	tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm);
+
+	return 2;
+}
+static int dec_addq(DisasContext *dc)
+{
+	LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2);
+
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+
+	cris_alu(dc, CC_OP_ADD,
+		    cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
+	return 2;
+}
+static int dec_moveq(DisasContext *dc)
+{
+	uint32_t imm;
+
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+	imm = sign_extend(dc->op1, 5);
+	LOG_DIS("moveq %d, $r%u\n", imm, dc->op2);
+
+	tcg_gen_movi_tl(cpu_R[dc->op2], imm);
+	return 2;
+}
+static int dec_subq(DisasContext *dc)
+{
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+
+	LOG_DIS("subq %u, $r%u\n", dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_SUB,
+		    cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
+	return 2;
+}
+static int dec_cmpq(DisasContext *dc)
+{
+	uint32_t imm;
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+	imm = sign_extend(dc->op1, 5);
+
+	LOG_DIS("cmpq %d, $r%d\n", imm, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+
+	cris_alu(dc, CC_OP_CMP,
+		    cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4);
+	return 2;
+}
+static int dec_andq(DisasContext *dc)
+{
+	uint32_t imm;
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+	imm = sign_extend(dc->op1, 5);
+
+	LOG_DIS("andq %d, $r%d\n", imm, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	cris_alu(dc, CC_OP_AND,
+		    cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4);
+	return 2;
+}
+static int dec_orq(DisasContext *dc)
+{
+	uint32_t imm;
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
+	imm = sign_extend(dc->op1, 5);
+	LOG_DIS("orq %d, $r%d\n", imm, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	cris_alu(dc, CC_OP_OR,
+		    cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4);
+	return 2;
+}
+static int dec_btstq(DisasContext *dc)
+{
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
+	LOG_DIS("btstq %u, $r%d\n", dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_evaluate_flags(dc);
+	gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->op2],
+			tcg_const_tl(dc->op1), cpu_PR[PR_CCS]);
+	cris_alu(dc, CC_OP_MOVE,
+		 cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+	dc->flags_uptodate = 1;
+	return 2;
+}
+static int dec_asrq(DisasContext *dc)
+{
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
+	LOG_DIS("asrq %u, $r%d\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2],
+		    cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	return 2;
+}
+static int dec_lslq(DisasContext *dc)
+{
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
+	LOG_DIS("lslq %u, $r%d\n", dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
+
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2],
+		    cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	return 2;
+}
+static int dec_lsrq(DisasContext *dc)
+{
+	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
+	LOG_DIS("lsrq %u, $r%d\n", dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2],
+		    cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	return 2;
+}
+
+static int dec_move_r(DisasContext *dc)
+{
+	int size = memsize_zz(dc);
+
+	LOG_DIS("move.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	if (size == 4) {
+		dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, cpu_R[dc->op2]);
+		cris_cc_mask(dc, CC_MASK_NZ);
+		cris_update_cc_op(dc, CC_OP_MOVE, 4);
+		cris_update_cc_x(dc);
+		cris_update_result(dc, cpu_R[dc->op2]);
+	}
+	else {
+		TCGv t0;
+
+		t0 = tcg_temp_new();
+		dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0);
+		cris_alu(dc, CC_OP_MOVE,
+			 cpu_R[dc->op2],
+			 cpu_R[dc->op2], t0, size);
+		tcg_temp_free(t0);
+	}
+	return 2;
+}
+
+static int dec_scc_r(DisasContext *dc)
+{
+	int cond = dc->op2;
+
+	LOG_DIS("s%s $r%u\n",
+		    cc_name(cond), dc->op1);
+
+	if (cond != CC_A)
+	{
+		int l1;
+
+		gen_tst_cc (dc, cpu_R[dc->op1], cond);
+		l1 = gen_new_label();
+		tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[dc->op1], 0, l1);
+		tcg_gen_movi_tl(cpu_R[dc->op1], 1);
+		gen_set_label(l1);
+	}
+	else
+		tcg_gen_movi_tl(cpu_R[dc->op1], 1);
+
+	cris_cc_mask(dc, 0);
+	return 2;
+}
+
+static inline void cris_alu_alloc_temps(DisasContext *dc, int size, TCGv *t)
+{
+	if (size == 4) {
+		t[0] = cpu_R[dc->op2];
+		t[1] = cpu_R[dc->op1];
+	} else {
+		t[0] = tcg_temp_new();
+		t[1] = tcg_temp_new();
+	}
+}
+
+static inline void cris_alu_free_temps(DisasContext *dc, int size, TCGv *t)
+{
+	if (size != 4) {
+		tcg_temp_free(t[0]);
+		tcg_temp_free(t[1]);
+	}
+}
+
+static int dec_and_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("and.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+	cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_lz_r(DisasContext *dc)
+{
+	TCGv t0;
+	LOG_DIS("lz $r%u, $r%u\n",
+		    dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	t0 = tcg_temp_new();
+	dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0, cpu_R[dc->op2], t0);
+	cris_alu(dc, CC_OP_LZ, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+static int dec_lsl_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("lsl.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+	tcg_gen_andi_tl(t[1], t[1], 63);
+	cris_alu(dc, CC_OP_LSL, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_alloc_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_lsr_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("lsr.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+	tcg_gen_andi_tl(t[1], t[1], 63);
+	cris_alu(dc, CC_OP_LSR, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_asr_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("asr.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]);
+	tcg_gen_andi_tl(t[1], t[1], 63);
+	cris_alu(dc, CC_OP_ASR, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_muls_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("muls.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZV);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_MULS, cpu_R[dc->op2], t[0], t[1], 4);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_mulu_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+
+	LOG_DIS("mulu.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZV);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_MULU, cpu_R[dc->op2], t[0], t[1], 4);
+	cris_alu_alloc_temps(dc, size, t);
+	return 2;
+}
+
+
+static int dec_dstep_r(DisasContext *dc)
+{
+	LOG_DIS("dstep $r%u, $r%u\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_DSTEP,
+		    cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4);
+	return 2;
+}
+
+static int dec_xor_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("xor.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	BUG_ON(size != 4); /* xor is dword.  */
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_XOR, cpu_R[dc->op2], t[0], t[1], 4);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_bound_r(DisasContext *dc)
+{
+	TCGv l0;
+	int size = memsize_zz(dc);
+	LOG_DIS("bound.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	l0 = tcg_temp_local_new();
+	dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, l0);
+	cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], cpu_R[dc->op2], l0, 4);
+	tcg_temp_free(l0);
+	return 2;
+}
+
+static int dec_cmp_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("cmp.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_abs_r(DisasContext *dc)
+{
+	TCGv t0;
+
+	LOG_DIS("abs $r%u, $r%u\n",
+		    dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+
+	t0 = tcg_temp_new();
+	tcg_gen_sari_tl(t0, cpu_R[dc->op1], 31);
+	tcg_gen_xor_tl(cpu_R[dc->op2], cpu_R[dc->op1], t0);
+	tcg_gen_sub_tl(cpu_R[dc->op2], cpu_R[dc->op2], t0);
+	tcg_temp_free(t0);
+
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	return 2;
+}
+
+static int dec_add_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("add.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_addc_r(DisasContext *dc)
+{
+	LOG_DIS("addc $r%u, $r%u\n",
+		    dc->op1, dc->op2);
+	cris_evaluate_flags(dc);
+	/* Set for this insn.  */
+	dc->flagx_known = 1;
+	dc->flags_x = X_FLAG;
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_ADDC,
+		 cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4);
+	return 2;
+}
+
+static int dec_mcp_r(DisasContext *dc)
+{
+	LOG_DIS("mcp $p%u, $r%u\n",
+		     dc->op2, dc->op1);
+	cris_evaluate_flags(dc);
+	cris_cc_mask(dc, CC_MASK_RNZV);
+	cris_alu(dc, CC_OP_MCP,
+		    cpu_R[dc->op1], cpu_R[dc->op1], cpu_PR[dc->op2], 4);
+	return 2;
+}
+
+#if DISAS_CRIS
+static char * swapmode_name(int mode, char *modename) {
+	int i = 0;
+	if (mode & 8)
+		modename[i++] = 'n';
+	if (mode & 4)
+		modename[i++] = 'w';
+	if (mode & 2)
+		modename[i++] = 'b';
+	if (mode & 1)
+		modename[i++] = 'r';
+	modename[i++] = 0;
+	return modename;
+}
+#endif
+
+static int dec_swap_r(DisasContext *dc)
+{
+	TCGv t0;
+#if DISAS_CRIS
+	char modename[4];
+#endif
+	LOG_DIS("swap%s $r%u\n",
+		     swapmode_name(dc->op2, modename), dc->op1);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	t0 = tcg_temp_new();
+	t_gen_mov_TN_reg(t0, dc->op1);
+	if (dc->op2 & 8)
+		tcg_gen_not_tl(t0, t0);
+	if (dc->op2 & 4)
+		t_gen_swapw(t0, t0);
+	if (dc->op2 & 2)
+		t_gen_swapb(t0, t0);
+	if (dc->op2 & 1)
+		t_gen_swapr(t0, t0);
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op1], cpu_R[dc->op1], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+static int dec_or_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("or.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+	cris_alu(dc, CC_OP_OR, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_addi_r(DisasContext *dc)
+{
+	TCGv t0;
+	LOG_DIS("addi.%c $r%u, $r%u\n",
+		    memsize_char(memsize_zz(dc)), dc->op2, dc->op1);
+	cris_cc_mask(dc, 0);
+	t0 = tcg_temp_new();
+	tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize));
+	tcg_gen_add_tl(cpu_R[dc->op1], cpu_R[dc->op1], t0);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+static int dec_addi_acr(DisasContext *dc)
+{
+	TCGv t0;
+	LOG_DIS("addi.%c $r%u, $r%u, $acr\n",
+		  memsize_char(memsize_zz(dc)), dc->op2, dc->op1);
+	cris_cc_mask(dc, 0);
+	t0 = tcg_temp_new();
+	tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize));
+	tcg_gen_add_tl(cpu_R[R_ACR], cpu_R[dc->op1], t0);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+static int dec_neg_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("neg.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+
+	cris_alu(dc, CC_OP_NEG, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+static int dec_btst_r(DisasContext *dc)
+{
+	LOG_DIS("btst $r%u, $r%u\n",
+		    dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_evaluate_flags(dc);
+	gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->op2],
+			cpu_R[dc->op1], cpu_PR[PR_CCS]);
+	cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2],
+		 cpu_R[dc->op2], cpu_R[dc->op2], 4);
+	cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+	dc->flags_uptodate = 1;
+	return 2;
+}
+
+static int dec_sub_r(DisasContext *dc)
+{
+	TCGv t[2];
+	int size = memsize_zz(dc);
+	LOG_DIS("sub.%c $r%u, $r%u\n",
+		    memsize_char(size), dc->op1, dc->op2);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu_alloc_temps(dc, size, t);
+	dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
+	cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], size);
+	cris_alu_free_temps(dc, size, t);
+	return 2;
+}
+
+/* Zero extension. From size to dword.  */
+static int dec_movu_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("movu.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	t0 = tcg_temp_new();
+	dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0);
+	cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+/* Sign extension. From size to dword.  */
+static int dec_movs_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("movs.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZ);
+	t0 = tcg_temp_new();
+	/* Size can only be qi or hi.  */
+	t_gen_sext(t0, cpu_R[dc->op1], size);
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2], cpu_R[dc->op1], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+/* zero extension. From size to dword.  */
+static int dec_addu_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("addu.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	t0 = tcg_temp_new();
+	/* Size can only be qi or hi.  */
+	t_gen_zext(t0, cpu_R[dc->op1], size);
+	cris_alu(dc, CC_OP_ADD,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+/* Sign extension. From size to dword.  */
+static int dec_adds_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("adds.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	t0 = tcg_temp_new();
+	/* Size can only be qi or hi.  */
+	t_gen_sext(t0, cpu_R[dc->op1], size);
+	cris_alu(dc, CC_OP_ADD,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+/* Zero extension. From size to dword.  */
+static int dec_subu_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("subu.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	t0 = tcg_temp_new();
+	/* Size can only be qi or hi.  */
+	t_gen_zext(t0, cpu_R[dc->op1], size);
+	cris_alu(dc, CC_OP_SUB,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+/* Sign extension. From size to dword.  */
+static int dec_subs_r(DisasContext *dc)
+{
+	TCGv t0;
+	int size = memsize_z(dc);
+	LOG_DIS("subs.%c $r%u, $r%u\n",
+		    memsize_char(size),
+		    dc->op1, dc->op2);
+
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	t0 = tcg_temp_new();
+	/* Size can only be qi or hi.  */
+	t_gen_sext(t0, cpu_R[dc->op1], size);
+	cris_alu(dc, CC_OP_SUB,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
+	tcg_temp_free(t0);
+	return 2;
+}
+
+static int dec_setclrf(DisasContext *dc)
+{
+	uint32_t flags;
+	int set = (~dc->opcode >> 2) & 1;
+
+
+	flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4)
+		| EXTRACT_FIELD(dc->ir, 0, 3);
+	if (set && flags == 0) {
+		LOG_DIS("nop\n");
+		return 2;
+	} else if (!set && (flags & 0x20)) {
+		LOG_DIS("di\n");
+	}
+	else {
+		LOG_DIS("%sf %x\n",
+			     set ? "set" : "clr",
+			    flags);
+	}
+
+	/* User space is not allowed to touch these. Silently ignore.  */
+	if (dc->tb_flags & U_FLAG) {
+		flags &= ~(S_FLAG | I_FLAG | U_FLAG);
+	}
+
+	if (flags & X_FLAG) {
+		dc->flagx_known = 1;
+		if (set)
+			dc->flags_x = X_FLAG;
+		else
+			dc->flags_x = 0;
+	}
+
+	/* Break the TB if any of the SPI flag changes.  */
+	if (flags & (P_FLAG | S_FLAG)) {
+		tcg_gen_movi_tl(env_pc, dc->pc + 2);
+		dc->is_jmp = DISAS_UPDATE;
+		dc->cpustate_changed = 1;
+	}
+
+	/* For the I flag, only act on posedge.  */
+	if ((flags & I_FLAG)) {
+		tcg_gen_movi_tl(env_pc, dc->pc + 2);
+		dc->is_jmp = DISAS_UPDATE;
+		dc->cpustate_changed = 1;
+	}
+
+
+	/* Simply decode the flags.  */
+	cris_evaluate_flags (dc);
+	cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+	cris_update_cc_x(dc);
+	tcg_gen_movi_tl(cc_op, dc->cc_op);
+
+	if (set) {
+		if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) {
+			/* Enter user mode.  */
+			t_gen_mov_env_TN(ksp, cpu_R[R_SP]);
+			tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]);
+			dc->cpustate_changed = 1;
+		}
+		tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
+	}
+	else
+		tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
+
+	dc->flags_uptodate = 1;
+	dc->clear_x = 0;
+	return 2;
+}
+
+static int dec_move_rs(DisasContext *dc)
+{
+	LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, 0);
+	gen_helper_movl_sreg_reg(tcg_const_tl(dc->op2), tcg_const_tl(dc->op1));
+	return 2;
+}
+static int dec_move_sr(DisasContext *dc)
+{
+	LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1);
+	cris_cc_mask(dc, 0);
+	gen_helper_movl_reg_sreg(tcg_const_tl(dc->op1), tcg_const_tl(dc->op2));
+	return 2;
+}
+
+static int dec_move_rp(DisasContext *dc)
+{
+	TCGv t[2];
+	LOG_DIS("move $r%u, $p%u\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, 0);
+
+	t[0] = tcg_temp_new();
+	if (dc->op2 == PR_CCS) {
+		cris_evaluate_flags(dc);
+		t_gen_mov_TN_reg(t[0], dc->op1);
+		if (dc->tb_flags & U_FLAG) {
+			t[1] = tcg_temp_new();
+			/* User space is not allowed to touch all flags.  */
+			tcg_gen_andi_tl(t[0], t[0], 0x39f);
+			tcg_gen_andi_tl(t[1], cpu_PR[PR_CCS], ~0x39f);
+			tcg_gen_or_tl(t[0], t[1], t[0]);
+			tcg_temp_free(t[1]);
+		}
+	}
+	else
+		t_gen_mov_TN_reg(t[0], dc->op1);
+
+	t_gen_mov_preg_TN(dc, dc->op2, t[0]);
+	if (dc->op2 == PR_CCS) {
+		cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+		dc->flags_uptodate = 1;
+	}
+	tcg_temp_free(t[0]);
+	return 2;
+}
+static int dec_move_pr(DisasContext *dc)
+{
+	TCGv t0;
+	LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1);
+	cris_cc_mask(dc, 0);
+
+	if (dc->op2 == PR_CCS)
+		cris_evaluate_flags(dc);
+
+        if (dc->op2 == PR_DZ) {
+		tcg_gen_movi_tl(cpu_R[dc->op1], 0);
+        } else {
+		t0 = tcg_temp_new();
+		t_gen_mov_TN_preg(t0, dc->op2);
+		cris_alu(dc, CC_OP_MOVE,
+			 cpu_R[dc->op1], cpu_R[dc->op1], t0,
+			 preg_sizes[dc->op2]);
+		tcg_temp_free(t0);
+	}
+	return 2;
+}
+
+static int dec_move_mr(DisasContext *dc)
+{
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("move.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	if (memsize == 4) {
+		insn_len = dec_prep_move_m(dc, 0, 4, cpu_R[dc->op2]);
+		cris_cc_mask(dc, CC_MASK_NZ);
+		cris_update_cc_op(dc, CC_OP_MOVE, 4);
+		cris_update_cc_x(dc);
+		cris_update_result(dc, cpu_R[dc->op2]);
+	}
+	else {
+		TCGv t0;
+
+		t0 = tcg_temp_new();
+		insn_len = dec_prep_move_m(dc, 0, memsize, t0);
+		cris_cc_mask(dc, CC_MASK_NZ);
+		cris_alu(dc, CC_OP_MOVE,
+			    cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize);
+		tcg_temp_free(t0);
+	}
+	do_postinc(dc, memsize);
+	return insn_len;
+}
+
+static inline void cris_alu_m_alloc_temps(TCGv *t)
+{
+	t[0] = tcg_temp_new();
+	t[1] = tcg_temp_new();
+}
+
+static inline void cris_alu_m_free_temps(TCGv *t)
+{
+	tcg_temp_free(t[0]);
+	tcg_temp_free(t[1]);
+}
+
+static int dec_movs_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("movs.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	/* sign extend.  */
+	insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_MOVE,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_addu_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("addu.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	/* sign extend.  */
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_ADD,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_adds_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("adds.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	/* sign extend.  */
+	insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_subu_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("subu.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	/* sign extend.  */
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_subs_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("subs.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	/* sign extend.  */
+	insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_movu_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+
+	LOG_DIS("movu.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_cmpu_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("cmpu.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_cmps_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_z(dc);
+	int insn_len;
+	LOG_DIS("cmps.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_CMP,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t[1],
+		    memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_cmp_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("cmp.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_CMP,
+		    cpu_R[dc->op2], cpu_R[dc->op2], t[1],
+		    memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_test_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("test.%c [$r%u%s] op2=%x\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_evaluate_flags(dc);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3);
+
+	cris_alu(dc, CC_OP_CMP,
+		 cpu_R[dc->op2], t[1], tcg_const_tl(0), memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_and_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("and.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_add_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("add.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_ADD,
+		 cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_addo_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("add.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]);
+	cris_cc_mask(dc, 0);
+	cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_bound_m(DisasContext *dc)
+{
+	TCGv l[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("bound.%c [$r%u%s, $r%u\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	l[0] = tcg_temp_local_new();
+	l[1] = tcg_temp_local_new();
+	insn_len = dec_prep_alu_m(dc, 0, memsize, l[0], l[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4);
+	do_postinc(dc, memsize);
+	tcg_temp_free(l[0]);
+	tcg_temp_free(l[1]);
+	return insn_len;
+}
+
+static int dec_addc_mr(DisasContext *dc)
+{
+	TCGv t[2];
+	int insn_len = 2;
+	LOG_DIS("addc [$r%u%s, $r%u\n",
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_evaluate_flags(dc);
+
+	/* Set for this insn.  */
+	dc->flagx_known = 1;
+	dc->flags_x = X_FLAG;
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, 4, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4);
+	do_postinc(dc, 4);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_sub_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("sub.%c [$r%u%s, $r%u ir=%x zz=%x\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2, dc->ir, dc->zzsize);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZVC);
+	cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize);
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_or_m(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len;
+	LOG_DIS("or.%c [$r%u%s, $r%u pc=%x\n",
+		    memsize_char(memsize),
+		    dc->op1, dc->postinc ? "+]" : "]",
+		    dc->op2, dc->pc);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, CC_MASK_NZ);
+	cris_alu(dc, CC_OP_OR,
+		    cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_move_mp(DisasContext *dc)
+{
+	TCGv t[2];
+	int memsize = memsize_zz(dc);
+	int insn_len = 2;
+
+	LOG_DIS("move.%c [$r%u%s, $p%u\n",
+		    memsize_char(memsize),
+		    dc->op1,
+		    dc->postinc ? "+]" : "]",
+		    dc->op2);
+
+	cris_alu_m_alloc_temps(t);
+	insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]);
+	cris_cc_mask(dc, 0);
+	if (dc->op2 == PR_CCS) {
+		cris_evaluate_flags(dc);
+		if (dc->tb_flags & U_FLAG) {
+			/* User space is not allowed to touch all flags.  */
+			tcg_gen_andi_tl(t[1], t[1], 0x39f);
+			tcg_gen_andi_tl(t[0], cpu_PR[PR_CCS], ~0x39f);
+			tcg_gen_or_tl(t[1], t[0], t[1]);
+		}
+	}
+
+	t_gen_mov_preg_TN(dc, dc->op2, t[1]);
+
+	do_postinc(dc, memsize);
+	cris_alu_m_free_temps(t);
+	return insn_len;
+}
+
+static int dec_move_pm(DisasContext *dc)
+{
+	TCGv t0;
+	int memsize;
+
+	memsize = preg_sizes[dc->op2];
+
+	LOG_DIS("move.%c $p%u, [$r%u%s\n",
+		     memsize_char(memsize), 
+		     dc->op2, dc->op1, dc->postinc ? "+]" : "]");
+
+	/* prepare store. Address in T0, value in T1.  */
+	if (dc->op2 == PR_CCS)
+		cris_evaluate_flags(dc);
+	t0 = tcg_temp_new();
+	t_gen_mov_TN_preg(t0, dc->op2);
+	cris_flush_cc_state(dc);
+	gen_store(dc, cpu_R[dc->op1], t0, memsize);
+	tcg_temp_free(t0);
+
+	cris_cc_mask(dc, 0);
+	if (dc->postinc)
+		tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize);
+	return 2;
+}
+
+static int dec_movem_mr(DisasContext *dc)
+{
+	TCGv_i64 tmp[16];
+        TCGv tmp32;
+	TCGv addr;
+	int i;
+	int nr = dc->op2 + 1;
+
+	LOG_DIS("movem [$r%u%s, $r%u\n", dc->op1,
+		    dc->postinc ? "+]" : "]", dc->op2);
+
+	addr = tcg_temp_new();
+	/* There are probably better ways of doing this.  */
+	cris_flush_cc_state(dc);
+	for (i = 0; i < (nr >> 1); i++) {
+		tmp[i] = tcg_temp_new_i64();
+		tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8);
+		gen_load64(dc, tmp[i], addr);
+	}
+	if (nr & 1) {
+		tmp32 = tcg_temp_new_i32();
+		tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8);
+		gen_load(dc, tmp32, addr, 4, 0);
+	} else
+		TCGV_UNUSED(tmp32);
+	tcg_temp_free(addr);
+
+	for (i = 0; i < (nr >> 1); i++) {
+		tcg_gen_trunc_i64_i32(cpu_R[i * 2], tmp[i]);
+		tcg_gen_shri_i64(tmp[i], tmp[i], 32);
+		tcg_gen_trunc_i64_i32(cpu_R[i * 2 + 1], tmp[i]);
+		tcg_temp_free_i64(tmp[i]);
+	}
+	if (nr & 1) {
+		tcg_gen_mov_tl(cpu_R[dc->op2], tmp32);
+		tcg_temp_free(tmp32);
+	}
+
+	/* writeback the updated pointer value.  */
+	if (dc->postinc)
+		tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], nr * 4);
+
+	/* gen_load might want to evaluate the previous insns flags.  */
+	cris_cc_mask(dc, 0);
+	return 2;
+}
+
+static int dec_movem_rm(DisasContext *dc)
+{
+	TCGv tmp;
+	TCGv addr;
+	int i;
+
+	LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1,
+		     dc->postinc ? "+]" : "]");
+
+	cris_flush_cc_state(dc);
+
+	tmp = tcg_temp_new();
+	addr = tcg_temp_new();
+	tcg_gen_movi_tl(tmp, 4);
+	tcg_gen_mov_tl(addr, cpu_R[dc->op1]);
+	for (i = 0; i <= dc->op2; i++) {
+		/* Displace addr.  */
+		/* Perform the store.  */
+		gen_store(dc, addr, cpu_R[i], 4);
+		tcg_gen_add_tl(addr, addr, tmp);
+	}
+	if (dc->postinc)
+		tcg_gen_mov_tl(cpu_R[dc->op1], addr);
+	cris_cc_mask(dc, 0);
+	tcg_temp_free(tmp);
+	tcg_temp_free(addr);
+	return 2;
+}
+
+static int dec_move_rm(DisasContext *dc)
+{
+	int memsize;
+
+	memsize = memsize_zz(dc);
+
+	LOG_DIS("move.%c $r%u, [$r%u]\n",
+		     memsize_char(memsize), dc->op2, dc->op1);
+
+	/* prepare store.  */
+	cris_flush_cc_state(dc);
+	gen_store(dc, cpu_R[dc->op1], cpu_R[dc->op2], memsize);
+
+	if (dc->postinc)
+		tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize);
+	cris_cc_mask(dc, 0);
+	return 2;
+}
+
+static int dec_lapcq(DisasContext *dc)
+{
+	LOG_DIS("lapcq %x, $r%u\n",
+		    dc->pc + dc->op1*2, dc->op2);
+	cris_cc_mask(dc, 0);
+	tcg_gen_movi_tl(cpu_R[dc->op2], dc->pc + dc->op1 * 2);
+	return 2;
+}
+
+static int dec_lapc_im(DisasContext *dc)
+{
+	unsigned int rd;
+	int32_t imm;
+	int32_t pc;
+
+	rd = dc->op2;
+
+	cris_cc_mask(dc, 0);
+	imm = cris_fetch(dc, dc->pc + 2, 4, 0);
+	LOG_DIS("lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2);
+
+	pc = dc->pc;
+	pc += imm;
+	tcg_gen_movi_tl(cpu_R[rd], pc);
+	return 6;
+}
+
+/* Jump to special reg.  */
+static int dec_jump_p(DisasContext *dc)
+{
+	LOG_DIS("jump $p%u\n", dc->op2);
+
+	if (dc->op2 == PR_CCS)
+		cris_evaluate_flags(dc);
+	t_gen_mov_TN_preg(env_btarget, dc->op2);
+	/* rete will often have low bit set to indicate delayslot.  */
+	tcg_gen_andi_tl(env_btarget, env_btarget, ~1);
+	cris_cc_mask(dc, 0);
+	cris_prepare_jmp(dc, JMP_INDIRECT);
+	return 2;
+}
+
+/* Jump and save.  */
+static int dec_jas_r(DisasContext *dc)
+{
+	LOG_DIS("jas $r%u, $p%u\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]);
+	if (dc->op2 > 15)
+		abort();
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4));
+
+	cris_prepare_jmp(dc, JMP_INDIRECT);
+	return 2;
+}
+
+static int dec_jas_im(DisasContext *dc)
+{
+	uint32_t imm;
+
+	imm = cris_fetch(dc, dc->pc + 2, 4, 0);
+
+	LOG_DIS("jas 0x%x\n", imm);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8));
+
+	dc->jmp_pc = imm;
+	cris_prepare_jmp(dc, JMP_DIRECT);
+	return 6;
+}
+
+static int dec_jasc_im(DisasContext *dc)
+{
+	uint32_t imm;
+
+	imm = cris_fetch(dc, dc->pc + 2, 4, 0);
+
+	LOG_DIS("jasc 0x%x\n", imm);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8 + 4));
+
+	dc->jmp_pc = imm;
+	cris_prepare_jmp(dc, JMP_DIRECT);
+	return 6;
+}
+
+static int dec_jasc_r(DisasContext *dc)
+{
+	LOG_DIS("jasc_r $r%u, $p%u\n", dc->op1, dc->op2);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]);
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4 + 4));
+	cris_prepare_jmp(dc, JMP_INDIRECT);
+	return 2;
+}
+
+static int dec_bcc_im(DisasContext *dc)
+{
+	int32_t offset;
+	uint32_t cond = dc->op2;
+
+	offset = cris_fetch(dc, dc->pc + 2, 2, 1);
+
+	LOG_DIS("b%s %d pc=%x dst=%x\n",
+		    cc_name(cond), offset,
+		    dc->pc, dc->pc + offset);
+
+	cris_cc_mask(dc, 0);
+	/* op2 holds the condition-code.  */
+	cris_prepare_cc_branch (dc, offset, cond);
+	return 4;
+}
+
+static int dec_bas_im(DisasContext *dc)
+{
+	int32_t simm;
+
+
+	simm = cris_fetch(dc, dc->pc + 2, 4, 0);
+
+	LOG_DIS("bas 0x%x, $p%u\n", dc->pc + simm, dc->op2);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8));
+
+	dc->jmp_pc = dc->pc + simm;
+	cris_prepare_jmp(dc, JMP_DIRECT);
+	return 6;
+}
+
+static int dec_basc_im(DisasContext *dc)
+{
+	int32_t simm;
+	simm = cris_fetch(dc, dc->pc + 2, 4, 0);
+
+	LOG_DIS("basc 0x%x, $p%u\n", dc->pc + simm, dc->op2);
+	cris_cc_mask(dc, 0);
+	/* Store the return address in Pd.  */
+	t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 12));
+
+	dc->jmp_pc = dc->pc + simm;
+	cris_prepare_jmp(dc, JMP_DIRECT);
+	return 6;
+}
+
+static int dec_rfe_etc(DisasContext *dc)
+{
+	cris_cc_mask(dc, 0);
+
+	if (dc->op2 == 15) {
+		t_gen_mov_env_TN(halted, tcg_const_tl(1));
+		tcg_gen_movi_tl(env_pc, dc->pc + 2);
+		t_gen_raise_exception(EXCP_HLT);
+		return 2;
+	}
+
+	switch (dc->op2 & 7) {
+		case 2:
+			/* rfe.  */
+			LOG_DIS("rfe\n");
+			cris_evaluate_flags(dc);
+			gen_helper_rfe();
+			dc->is_jmp = DISAS_UPDATE;
+			break;
+		case 5:
+			/* rfn.  */
+			LOG_DIS("rfn\n");
+			cris_evaluate_flags(dc);
+			gen_helper_rfn();
+			dc->is_jmp = DISAS_UPDATE;
+			break;
+		case 6:
+			LOG_DIS("break %d\n", dc->op1);
+			cris_evaluate_flags (dc);
+			/* break.  */
+			tcg_gen_movi_tl(env_pc, dc->pc + 2);
+
+			/* Breaks start at 16 in the exception vector.  */
+			t_gen_mov_env_TN(trap_vector, 
+					 tcg_const_tl(dc->op1 + 16));
+			t_gen_raise_exception(EXCP_BREAK);
+			dc->is_jmp = DISAS_UPDATE;
+			break;
+		default:
+			printf ("op2=%x\n", dc->op2);
+			BUG();
+			break;
+
+	}
+	return 2;
+}
+
+static int dec_ftag_fidx_d_m(DisasContext *dc)
+{
+	return 2;
+}
+
+static int dec_ftag_fidx_i_m(DisasContext *dc)
+{
+	return 2;
+}
+
+static int dec_null(DisasContext *dc)
+{
+	printf ("unknown insn pc=%x opc=%x op1=%x op2=%x\n",
+		dc->pc, dc->opcode, dc->op1, dc->op2);
+	fflush(NULL);
+	BUG();
+	return 2;
+}
+
+static struct decoder_info {
+	struct {
+		uint32_t bits;
+		uint32_t mask;
+	};
+	int (*dec)(DisasContext *dc);
+} decinfo[] = {
+	/* Order matters here.  */
+	{DEC_MOVEQ, dec_moveq},
+	{DEC_BTSTQ, dec_btstq},
+	{DEC_CMPQ, dec_cmpq},
+	{DEC_ADDOQ, dec_addoq},
+	{DEC_ADDQ, dec_addq},
+	{DEC_SUBQ, dec_subq},
+	{DEC_ANDQ, dec_andq},
+	{DEC_ORQ, dec_orq},
+	{DEC_ASRQ, dec_asrq},
+	{DEC_LSLQ, dec_lslq},
+	{DEC_LSRQ, dec_lsrq},
+	{DEC_BCCQ, dec_bccq},
+
+	{DEC_BCC_IM, dec_bcc_im},
+	{DEC_JAS_IM, dec_jas_im},
+	{DEC_JAS_R, dec_jas_r},
+	{DEC_JASC_IM, dec_jasc_im},
+	{DEC_JASC_R, dec_jasc_r},
+	{DEC_BAS_IM, dec_bas_im},
+	{DEC_BASC_IM, dec_basc_im},
+	{DEC_JUMP_P, dec_jump_p},
+	{DEC_LAPC_IM, dec_lapc_im},
+	{DEC_LAPCQ, dec_lapcq},
+
+	{DEC_RFE_ETC, dec_rfe_etc},
+	{DEC_ADDC_MR, dec_addc_mr},
+
+	{DEC_MOVE_MP, dec_move_mp},
+	{DEC_MOVE_PM, dec_move_pm},
+	{DEC_MOVEM_MR, dec_movem_mr},
+	{DEC_MOVEM_RM, dec_movem_rm},
+	{DEC_MOVE_PR, dec_move_pr},
+	{DEC_SCC_R, dec_scc_r},
+	{DEC_SETF, dec_setclrf},
+	{DEC_CLEARF, dec_setclrf},
+
+	{DEC_MOVE_SR, dec_move_sr},
+	{DEC_MOVE_RP, dec_move_rp},
+	{DEC_SWAP_R, dec_swap_r},
+	{DEC_ABS_R, dec_abs_r},
+	{DEC_LZ_R, dec_lz_r},
+	{DEC_MOVE_RS, dec_move_rs},
+	{DEC_BTST_R, dec_btst_r},
+	{DEC_ADDC_R, dec_addc_r},
+
+	{DEC_DSTEP_R, dec_dstep_r},
+	{DEC_XOR_R, dec_xor_r},
+	{DEC_MCP_R, dec_mcp_r},
+	{DEC_CMP_R, dec_cmp_r},
+
+	{DEC_ADDI_R, dec_addi_r},
+	{DEC_ADDI_ACR, dec_addi_acr},
+
+	{DEC_ADD_R, dec_add_r},
+	{DEC_SUB_R, dec_sub_r},
+
+	{DEC_ADDU_R, dec_addu_r},
+	{DEC_ADDS_R, dec_adds_r},
+	{DEC_SUBU_R, dec_subu_r},
+	{DEC_SUBS_R, dec_subs_r},
+	{DEC_LSL_R, dec_lsl_r},
+
+	{DEC_AND_R, dec_and_r},
+	{DEC_OR_R, dec_or_r},
+	{DEC_BOUND_R, dec_bound_r},
+	{DEC_ASR_R, dec_asr_r},
+	{DEC_LSR_R, dec_lsr_r},
+
+	{DEC_MOVU_R, dec_movu_r},
+	{DEC_MOVS_R, dec_movs_r},
+	{DEC_NEG_R, dec_neg_r},
+	{DEC_MOVE_R, dec_move_r},
+
+	{DEC_FTAG_FIDX_I_M, dec_ftag_fidx_i_m},
+	{DEC_FTAG_FIDX_D_M, dec_ftag_fidx_d_m},
+
+	{DEC_MULS_R, dec_muls_r},
+	{DEC_MULU_R, dec_mulu_r},
+
+	{DEC_ADDU_M, dec_addu_m},
+	{DEC_ADDS_M, dec_adds_m},
+	{DEC_SUBU_M, dec_subu_m},
+	{DEC_SUBS_M, dec_subs_m},
+
+	{DEC_CMPU_M, dec_cmpu_m},
+	{DEC_CMPS_M, dec_cmps_m},
+	{DEC_MOVU_M, dec_movu_m},
+	{DEC_MOVS_M, dec_movs_m},
+
+	{DEC_CMP_M, dec_cmp_m},
+	{DEC_ADDO_M, dec_addo_m},
+	{DEC_BOUND_M, dec_bound_m},
+	{DEC_ADD_M, dec_add_m},
+	{DEC_SUB_M, dec_sub_m},
+	{DEC_AND_M, dec_and_m},
+	{DEC_OR_M, dec_or_m},
+	{DEC_MOVE_RM, dec_move_rm},
+	{DEC_TEST_M, dec_test_m},
+	{DEC_MOVE_MR, dec_move_mr},
+
+	{{0, 0}, dec_null}
+};
+
+static unsigned int crisv32_decoder(DisasContext *dc)
+{
+	int insn_len = 2;
+	int i;
+
+	if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+		tcg_gen_debug_insn_start(dc->pc);
+
+	/* Load a halfword onto the instruction register.  */
+	dc->ir = cris_fetch(dc, dc->pc, 2, 0);
+
+	/* Now decode it.  */
+	dc->opcode   = EXTRACT_FIELD(dc->ir, 4, 11);
+	dc->op1      = EXTRACT_FIELD(dc->ir, 0, 3);
+	dc->op2      = EXTRACT_FIELD(dc->ir, 12, 15);
+	dc->zsize    = EXTRACT_FIELD(dc->ir, 4, 4);
+	dc->zzsize   = EXTRACT_FIELD(dc->ir, 4, 5);
+	dc->postinc  = EXTRACT_FIELD(dc->ir, 10, 10);
+
+	/* Large switch for all insns.  */
+	for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
+		if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits)
+		{
+			insn_len = decinfo[i].dec(dc);
+			break;
+		}
+	}
+
+#if !defined(CONFIG_USER_ONLY)
+	/* Single-stepping ?  */
+	if (dc->tb_flags & S_FLAG) {
+		int l1;
+
+		l1 = gen_new_label();
+		tcg_gen_brcondi_tl(TCG_COND_NE, cpu_PR[PR_SPC], dc->pc, l1);
+		/* We treat SPC as a break with an odd trap vector.  */
+		cris_evaluate_flags (dc);
+		t_gen_mov_env_TN(trap_vector, tcg_const_tl(3));
+		tcg_gen_movi_tl(env_pc, dc->pc + insn_len);
+		tcg_gen_movi_tl(cpu_PR[PR_SPC], dc->pc + insn_len);
+		t_gen_raise_exception(EXCP_BREAK);
+		gen_set_label(l1);
+	}
+#endif
+	return insn_len;
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+	CPUBreakpoint *bp;
+
+	if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+		QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+			if (bp->pc == dc->pc) {
+				cris_evaluate_flags (dc);
+				tcg_gen_movi_tl(env_pc, dc->pc);
+				t_gen_raise_exception(EXCP_DEBUG);
+				dc->is_jmp = DISAS_UPDATE;
+			}
+		}
+	}
+}
+
+#include "translate_v10.c"
+
+/*
+ * Delay slots on QEMU/CRIS.
+ *
+ * If an exception hits on a delayslot, the core will let ERP (the Exception
+ * Return Pointer) point to the branch (the previous) insn and set the lsb to
+ * to give SW a hint that the exception actually hit on the dslot.
+ *
+ * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by
+ * the core and any jmp to an odd addresses will mask off that lsb. It is 
+ * simply there to let sw know there was an exception on a dslot.
+ *
+ * When the software returns from an exception, the branch will re-execute.
+ * On QEMU care needs to be taken when a branch+delayslot sequence is broken
+ * and the branch and delayslot dont share pages.
+ *
+ * The TB contaning the branch insn will set up env->btarget and evaluate 
+ * env->btaken. When the translation loop exits we will note that the branch 
+ * sequence is broken and let env->dslot be the size of the branch insn (those
+ * vary in length).
+ *
+ * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb
+ * set). It will also expect to have env->dslot setup with the size of the 
+ * delay slot so that env->pc - env->dslot point to the branch insn. This TB 
+ * will execute the dslot and take the branch, either to btarget or just one 
+ * insn ahead.
+ *
+ * When exceptions occur, we check for env->dslot in do_interrupt to detect 
+ * broken branch sequences and setup $erp accordingly (i.e let it point to the
+ * branch and set lsb). Then env->dslot gets cleared so that the exception 
+ * handler can enter. When returning from exceptions (jump $erp) the lsb gets
+ * masked off and we will reexecute the branch insn.
+ *
+ */
+
+/* generate intermediate code for basic block 'tb'.  */
+static void
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+                               int search_pc)
+{
+	uint16_t *gen_opc_end;
+   	uint32_t pc_start;
+	unsigned int insn_len;
+	int j, lj;
+	struct DisasContext ctx;
+	struct DisasContext *dc = &ctx;
+	uint32_t next_page_start;
+	target_ulong npc;
+        int num_insns;
+        int max_insns;
+
+	qemu_log_try_set_file(stderr);
+
+	if (env->pregs[PR_VR] == 32) {
+		dc->decoder = crisv32_decoder;
+		dc->clear_locked_irq = 0;
+	} else {
+		dc->decoder = crisv10_decoder;
+		dc->clear_locked_irq = 1;
+	}
+
+	/* Odd PC indicates that branch is rexecuting due to exception in the
+	 * delayslot, like in real hw.
+	 */
+	pc_start = tb->pc & ~1;
+	dc->env = env;
+	dc->tb = tb;
+
+	gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+	dc->is_jmp = DISAS_NEXT;
+	dc->ppc = pc_start;
+	dc->pc = pc_start;
+	dc->singlestep_enabled = env->singlestep_enabled;
+	dc->flags_uptodate = 1;
+	dc->flagx_known = 1;
+	dc->flags_x = tb->flags & X_FLAG;
+	dc->cc_x_uptodate = 0;
+	dc->cc_mask = 0;
+	dc->update_cc = 0;
+	dc->clear_prefix = 0;
+
+	cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+	dc->cc_size_uptodate = -1;
+
+	/* Decode TB flags.  */
+	dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG \
+					| X_FLAG | PFIX_FLAG);
+	dc->delayed_branch = !!(tb->flags & 7);
+	if (dc->delayed_branch)
+		dc->jmp = JMP_INDIRECT;
+	else
+		dc->jmp = JMP_NOJMP;
+
+	dc->cpustate_changed = 0;
+
+	if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+		qemu_log(
+                        "srch=%d pc=%x %x flg=%" PRIx64 " bt=%x ds=%u ccs=%x\n"
+			"pid=%x usp=%x\n"
+			"%x.%x.%x.%x\n"
+			"%x.%x.%x.%x\n"
+			"%x.%x.%x.%x\n"
+			"%x.%x.%x.%x\n",
+			search_pc, dc->pc, dc->ppc,
+                        (uint64_t)tb->flags,
+			env->btarget, (unsigned)tb->flags & 7,
+			env->pregs[PR_CCS], 
+			env->pregs[PR_PID], env->pregs[PR_USP],
+			env->regs[0], env->regs[1], env->regs[2], env->regs[3],
+			env->regs[4], env->regs[5], env->regs[6], env->regs[7],
+			env->regs[8], env->regs[9],
+			env->regs[10], env->regs[11],
+			env->regs[12], env->regs[13],
+			env->regs[14], env->regs[15]);
+		qemu_log("--------------\n");
+		qemu_log("IN: %s\n", lookup_symbol(pc_start));
+	}
+
+	next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+	lj = -1;
+        num_insns = 0;
+        max_insns = tb->cflags & CF_COUNT_MASK;
+        if (max_insns == 0)
+            max_insns = CF_COUNT_MASK;
+
+        gen_icount_start();
+	do
+	{
+		check_breakpoint(env, dc);
+
+		if (search_pc) {
+			j = gen_opc_ptr - gen_opc_buf;
+			if (lj < j) {
+				lj++;
+				while (lj < j)
+					gen_opc_instr_start[lj++] = 0;
+			}
+			if (dc->delayed_branch == 1)
+				gen_opc_pc[lj] = dc->ppc | 1;
+			else
+				gen_opc_pc[lj] = dc->pc;
+			gen_opc_instr_start[lj] = 1;
+                        gen_opc_icount[lj] = num_insns;
+		}
+
+		/* Pretty disas.  */
+		LOG_DIS("%8.8x:\t", dc->pc);
+
+                if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+                    gen_io_start();
+		dc->clear_x = 1;
+
+		insn_len = dc->decoder(dc);
+		dc->ppc = dc->pc;
+		dc->pc += insn_len;
+		if (dc->clear_x)
+			cris_clear_x_flag(dc);
+
+                num_insns++;
+		/* Check for delayed branches here. If we do it before
+		   actually generating any host code, the simulator will just
+		   loop doing nothing for on this program location.  */
+		if (dc->delayed_branch) {
+			dc->delayed_branch--;
+			if (dc->delayed_branch == 0)
+			{
+				if (tb->flags & 7)
+					t_gen_mov_env_TN(dslot, 
+						tcg_const_tl(0));
+				if (dc->cpustate_changed || !dc->flagx_known
+				    || (dc->flags_x != (tb->flags & X_FLAG))) {
+					cris_store_direct_jmp(dc);
+				}
+
+				if (dc->clear_locked_irq) {
+					dc->clear_locked_irq = 0;
+					t_gen_mov_env_TN(locked_irq,
+							 tcg_const_tl(0));
+				}
+
+				if (dc->jmp == JMP_DIRECT_CC) {
+					int l1;
+
+					l1 = gen_new_label();
+					cris_evaluate_flags(dc);
+
+					/* Conditional jmp.  */
+					tcg_gen_brcondi_tl(TCG_COND_EQ,
+							   env_btaken, 0, l1);
+					gen_goto_tb(dc, 1, dc->jmp_pc);
+					gen_set_label(l1);
+					gen_goto_tb(dc, 0, dc->pc);
+					dc->is_jmp = DISAS_TB_JUMP;
+					dc->jmp = JMP_NOJMP;
+				} else if (dc->jmp == JMP_DIRECT) {
+					cris_evaluate_flags(dc);
+					gen_goto_tb(dc, 0, dc->jmp_pc);
+					dc->is_jmp = DISAS_TB_JUMP;
+					dc->jmp = JMP_NOJMP;
+				} else {
+					t_gen_cc_jmp(env_btarget, 
+						     tcg_const_tl(dc->pc));
+					dc->is_jmp = DISAS_JUMP;
+				}
+				break;
+			}
+		}
+
+		/* If we are rexecuting a branch due to exceptions on
+		   delay slots dont break.  */
+		if (!(tb->pc & 1) && env->singlestep_enabled)
+			break;
+	} while (!dc->is_jmp && !dc->cpustate_changed
+		 && gen_opc_ptr < gen_opc_end
+                 && !singlestep
+		 && (dc->pc < next_page_start)
+                 && num_insns < max_insns);
+
+	if (dc->clear_locked_irq)
+		t_gen_mov_env_TN(locked_irq, tcg_const_tl(0));
+
+	npc = dc->pc;
+
+        if (tb->cflags & CF_LAST_IO)
+            gen_io_end();
+	/* Force an update if the per-tb cpu state has changed.  */
+	if (dc->is_jmp == DISAS_NEXT
+	    && (dc->cpustate_changed || !dc->flagx_known 
+	    || (dc->flags_x != (tb->flags & X_FLAG)))) {
+		dc->is_jmp = DISAS_UPDATE;
+		tcg_gen_movi_tl(env_pc, npc);
+	}
+	/* Broken branch+delayslot sequence.  */
+	if (dc->delayed_branch == 1) {
+		/* Set env->dslot to the size of the branch insn.  */
+		t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc));
+		cris_store_direct_jmp(dc);
+	}
+
+	cris_evaluate_flags (dc);
+
+	if (unlikely(env->singlestep_enabled)) {
+		if (dc->is_jmp == DISAS_NEXT)
+			tcg_gen_movi_tl(env_pc, npc);
+		t_gen_raise_exception(EXCP_DEBUG);
+	} else {
+		switch(dc->is_jmp) {
+			case DISAS_NEXT:
+				gen_goto_tb(dc, 1, npc);
+				break;
+			default:
+			case DISAS_JUMP:
+			case DISAS_UPDATE:
+				/* indicate that the hash table must be used
+				   to find the next TB */
+				tcg_gen_exit_tb(0);
+				break;
+			case DISAS_SWI:
+			case DISAS_TB_JUMP:
+				/* nothing more to generate */
+				break;
+		}
+	}
+        gen_icount_end(tb, num_insns);
+	*gen_opc_ptr = INDEX_op_end;
+	if (search_pc) {
+		j = gen_opc_ptr - gen_opc_buf;
+		lj++;
+		while (lj <= j)
+			gen_opc_instr_start[lj++] = 0;
+	} else {
+		tb->size = dc->pc - pc_start;
+                tb->icount = num_insns;
+	}
+
+#ifdef DEBUG_DISAS
+#if !DISAS_CRIS
+	if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+		log_target_disas(pc_start, dc->pc - pc_start,
+                                 dc->env->pregs[PR_VR]);
+		qemu_log("\nisize=%d osize=%td\n",
+			dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+	}
+#endif
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+	int i;
+	uint32_t srs;
+
+	if (!env || !f)
+		return;
+
+	cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n"
+		    "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n",
+		    env->pc, env->pregs[PR_CCS], env->btaken, env->btarget,
+		    env->cc_op,
+		    env->cc_src, env->cc_dest, env->cc_result, env->cc_mask);
+
+
+	for (i = 0; i < 16; i++) {
+		cpu_fprintf(f, "%s=%8.8x ",regnames[i], env->regs[i]);
+		if ((i + 1) % 4 == 0)
+			cpu_fprintf(f, "\n");
+	}
+	cpu_fprintf(f, "\nspecial regs:\n");
+	for (i = 0; i < 16; i++) {
+		cpu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]);
+		if ((i + 1) % 4 == 0)
+			cpu_fprintf(f, "\n");
+	}
+	srs = env->pregs[PR_SRS];
+	cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs);
+	if (srs < 256) {
+		for (i = 0; i < 16; i++) {
+			cpu_fprintf(f, "s%2.2d=%8.8x ",
+				    i, env->sregs[srs][i]);
+			if ((i + 1) % 4 == 0)
+				cpu_fprintf(f, "\n");
+		}
+	}
+	cpu_fprintf(f, "\n\n");
+
+}
+
+struct
+{
+    uint32_t vr;
+    const char *name;
+} cris_cores[] = {
+	{8, "crisv8"},
+	{9, "crisv9"},
+	{10, "crisv10"},
+	{11, "crisv11"},
+	{32, "crisv32"},
+};
+
+void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    unsigned int i;
+
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+        (*cpu_fprintf)(f, "  %s\n", cris_cores[i].name);
+    }
+}
+
+static uint32_t vr_by_name(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+        if (strcmp(name, cris_cores[i].name) == 0) {
+            return cris_cores[i].vr;
+        }
+    }
+    return 32;
+}
+
+CPUCRISState *cpu_cris_init (const char *cpu_model)
+{
+	CPUCRISState *env;
+	static int tcg_initialized = 0;
+	int i;
+
+	env = qemu_mallocz(sizeof(CPUCRISState));
+
+	env->pregs[PR_VR] = vr_by_name(cpu_model);
+	cpu_exec_init(env);
+	cpu_reset(env);
+	qemu_init_vcpu(env);
+
+	if (tcg_initialized)
+		return env;
+
+	tcg_initialized = 1;
+
+#define GEN_HELPER 2
+#include "helper.h"
+
+	if (env->pregs[PR_VR] < 32) {
+		cpu_crisv10_init(env);
+		return env; 
+	}
+
+
+	cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+	cc_x = tcg_global_mem_new(TCG_AREG0,
+				  offsetof(CPUState, cc_x), "cc_x");
+	cc_src = tcg_global_mem_new(TCG_AREG0,
+				    offsetof(CPUState, cc_src), "cc_src");
+	cc_dest = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_dest),
+				     "cc_dest");
+	cc_result = tcg_global_mem_new(TCG_AREG0,
+				       offsetof(CPUState, cc_result),
+				       "cc_result");
+	cc_op = tcg_global_mem_new(TCG_AREG0,
+				   offsetof(CPUState, cc_op), "cc_op");
+	cc_size = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_size),
+				     "cc_size");
+	cc_mask = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_mask),
+				     "cc_mask");
+
+	env_pc = tcg_global_mem_new(TCG_AREG0, 
+				    offsetof(CPUState, pc),
+				    "pc");
+	env_btarget = tcg_global_mem_new(TCG_AREG0,
+					 offsetof(CPUState, btarget),
+					 "btarget");
+	env_btaken = tcg_global_mem_new(TCG_AREG0,
+					 offsetof(CPUState, btaken),
+					 "btaken");
+	for (i = 0; i < 16; i++) {
+		cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+					      offsetof(CPUState, regs[i]),
+					      regnames[i]);
+	}
+	for (i = 0; i < 16; i++) {
+		cpu_PR[i] = tcg_global_mem_new(TCG_AREG0,
+					       offsetof(CPUState, pregs[i]),
+					       pregnames[i]);
+	}
+
+	return env;
+}
+
+void cpu_reset (CPUCRISState *env)
+{
+	uint32_t vr;
+
+	if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+		qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+		log_cpu_state(env, 0);
+	}
+
+	vr = env->pregs[PR_VR];
+	memset(env, 0, offsetof(CPUCRISState, breakpoints));
+	env->pregs[PR_VR] = vr;
+	tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+	/* start in user mode with interrupts enabled.  */
+	env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
+#else
+	cris_mmu_init(env);
+	env->pregs[PR_CCS] = 0;
+#endif
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+	env->pc = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/target-cris/translate_v10.c b/qemu-0.15.x/target-cris/translate_v10.c
new file mode 100644
index 0000000..637ac20
--- /dev/null
+++ b/qemu-0.15.x/target-cris/translate_v10.c
@@ -0,0 +1,1242 @@
+/*
+ *  CRISv10 emulation for qemu: main translation routines.
+ *
+ *  Copyright (c) 2010 AXIS Communications AB
+ *  Written by Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "crisv10-decode.h"
+
+static const char *regnames_v10[] =
+{
+    "$r0", "$r1", "$r2", "$r3",
+    "$r4", "$r5", "$r6", "$r7",
+    "$r8", "$r9", "$r10", "$r11",
+    "$r12", "$r13", "$sp", "$pc",
+};
+
+static const char *pregnames_v10[] =
+{
+    "$bz", "$vr", "$p2", "$p3",
+    "$wz", "$ccr", "$p6-prefix", "$mof",
+    "$dz", "$ibr", "$irp", "$srp",
+    "$bar", "$dccr", "$brp", "$usp",
+};
+
+/* We need this table to handle preg-moves with implicit width.  */
+static int preg_sizes_v10[] = {
+    1, /* bz.  */
+    1, /* vr.  */
+    1, /* pid. */
+    1, /* srs. */
+    2, /* wz.  */
+    2, 2, 4,
+    4, 4, 4, 4,
+    4, 4, 4, 4,
+};
+
+static inline int dec10_size(unsigned int size)
+{
+    size++;
+    if (size == 3)
+        size++;
+    return size;
+}
+
+static inline void cris_illegal_insn(DisasContext *dc)
+{
+    qemu_log("illegal insn at pc=%x\n", dc->pc);
+    t_gen_raise_exception(EXCP_BREAK);
+}
+
+/* Prefix flag and register are used to handle the more complex
+   addressing modes.  */
+static void cris_set_prefix(DisasContext *dc)
+{
+    dc->clear_prefix = 0;
+    dc->tb_flags |= PFIX_FLAG;
+    tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], PFIX_FLAG);
+
+    /* prefix insns dont clear the x flag.  */
+    dc->clear_x = 0;
+    cris_lock_irq(dc);
+}
+
+static void crisv10_prepare_memaddr(DisasContext *dc,
+                                    TCGv addr, unsigned int size)
+{
+    if (dc->tb_flags & PFIX_FLAG) {
+        tcg_gen_mov_tl(addr, cpu_PR[PR_PREFIX]);
+    } else {
+        tcg_gen_mov_tl(addr, cpu_R[dc->src]);
+    }
+}
+
+static unsigned int crisv10_post_memaddr(DisasContext *dc, unsigned int size)
+{
+    unsigned int insn_len = 0;
+
+    if (dc->tb_flags & PFIX_FLAG) {
+        if (dc->mode == CRISV10_MODE_AUTOINC) {
+            tcg_gen_mov_tl(cpu_R[dc->src], cpu_PR[PR_PREFIX]);
+        }
+    } else {
+        if (dc->mode == CRISV10_MODE_AUTOINC) {
+            if (dc->src == 15) {
+                insn_len += size & ~1;
+            } else {
+                tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], size);
+            }
+        }
+    }
+    return insn_len;
+}
+
+static int dec10_prep_move_m(DisasContext *dc, int s_ext, int memsize,
+                           TCGv dst)
+{
+    unsigned int rs;
+    uint32_t imm;
+    int is_imm;
+    int insn_len = 0;
+
+    rs = dc->src;
+    is_imm = rs == 15 && !(dc->tb_flags & PFIX_FLAG);
+    LOG_DIS("rs=%d rd=%d is_imm=%d mode=%d pfix=%d\n",
+             rs, dc->dst, is_imm, dc->mode, dc->tb_flags & PFIX_FLAG);
+
+    /* Load [$rs] onto T1.  */
+    if (is_imm) {
+        if (memsize != 4) {
+            if (s_ext) {
+                if (memsize == 1)
+                    imm = ldsb_code(dc->pc + 2);
+                else
+                    imm = ldsw_code(dc->pc + 2);
+            } else {
+                if (memsize == 1)
+                    imm = ldub_code(dc->pc + 2);
+                else
+                    imm = lduw_code(dc->pc + 2);
+            }
+        } else
+            imm = ldl_code(dc->pc + 2);
+
+        tcg_gen_movi_tl(dst, imm);
+
+        if (dc->mode == CRISV10_MODE_AUTOINC) {
+            insn_len += memsize;
+            if (memsize == 1)
+                insn_len++;
+            tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len);
+        }
+    } else {
+        TCGv addr;
+
+        addr = tcg_temp_new();
+        cris_flush_cc_state(dc);
+        crisv10_prepare_memaddr(dc, addr, memsize);
+        gen_load(dc, dst, addr, memsize, 0);
+        if (s_ext)
+            t_gen_sext(dst, dst, memsize);
+        else
+            t_gen_zext(dst, dst, memsize);
+        insn_len += crisv10_post_memaddr(dc, memsize);
+        tcg_temp_free(addr);
+    }
+
+    if (dc->mode == CRISV10_MODE_INDIRECT && (dc->tb_flags & PFIX_FLAG)) {
+        dc->dst = dc->src;
+    }
+    return insn_len;
+}
+
+static unsigned int dec10_quick_imm(DisasContext *dc)
+{
+    int32_t imm, simm;
+    int op;
+
+    /* sign extend.  */
+    imm = dc->ir & ((1 << 6) - 1);
+    simm = (int8_t) (imm << 2);
+    simm >>= 2;
+    switch (dc->opcode) {
+        case CRISV10_QIMM_BDAP_R0:
+        case CRISV10_QIMM_BDAP_R1:
+        case CRISV10_QIMM_BDAP_R2:
+        case CRISV10_QIMM_BDAP_R3:
+            simm = (int8_t)dc->ir;
+            LOG_DIS("bdap %d $r%d\n", simm, dc->dst);
+            LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n",
+                     dc->pc, dc->mode, dc->opcode, dc->src, dc->dst);
+            cris_set_prefix(dc);
+            if (dc->dst == 15) {
+                tcg_gen_movi_tl(cpu_PR[PR_PREFIX], dc->pc + 2 + simm);
+            } else {
+                tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm);
+            }
+            break;
+
+        case CRISV10_QIMM_MOVEQ:
+            LOG_DIS("moveq %d, $r%d\n", simm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(simm), 4);
+            break;
+        case CRISV10_QIMM_CMPQ:
+            LOG_DIS("cmpq %d, $r%d\n", simm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(simm), 4);
+            break;
+        case CRISV10_QIMM_ADDQ:
+            LOG_DIS("addq %d, $r%d\n", imm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_ADD, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(imm), 4);
+            break;
+        case CRISV10_QIMM_ANDQ:
+            LOG_DIS("andq %d, $r%d\n", simm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_AND, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(simm), 4);
+            break;
+        case CRISV10_QIMM_ASHQ:
+            LOG_DIS("ashq %d, $r%d\n", simm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            op = imm & (1 << 5);
+            imm &= 0x1f;
+            if (op) {
+                cris_alu(dc, CC_OP_ASR, cpu_R[dc->dst],
+                          cpu_R[dc->dst], tcg_const_tl(imm), 4);
+            } else {
+                /* BTST */
+                cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+                gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst],
+                           tcg_const_tl(imm), cpu_PR[PR_CCS]);
+            }
+            break;
+        case CRISV10_QIMM_LSHQ:
+            LOG_DIS("lshq %d, $r%d\n", simm, dc->dst);
+
+            op = CC_OP_LSL;
+            if (imm & (1 << 5)) {
+                op = CC_OP_LSR; 
+            }
+            imm &= 0x1f;
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, op, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(imm), 4);
+            break;
+        case CRISV10_QIMM_SUBQ:
+            LOG_DIS("subq %d, $r%d\n", imm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_SUB, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(imm), 4);
+            break;
+        case CRISV10_QIMM_ORQ:
+            LOG_DIS("andq %d, $r%d\n", simm, dc->dst);
+
+            cris_cc_mask(dc, CC_MASK_NZVC);
+            cris_alu(dc, CC_OP_OR, cpu_R[dc->dst],
+                     cpu_R[dc->dst], tcg_const_tl(simm), 4);
+            break;
+
+        case CRISV10_QIMM_BCC_R0:
+        case CRISV10_QIMM_BCC_R1:
+        case CRISV10_QIMM_BCC_R2:
+        case CRISV10_QIMM_BCC_R3:
+            imm = dc->ir & 0xff;
+            /* bit 0 is a sign bit.  */
+            if (imm & 1) {
+                imm |= 0xffffff00;   /* sign extend.  */
+                imm &= ~1;           /* get rid of the sign bit.  */
+            }
+            imm += 2;
+            LOG_DIS("b%s %d\n", cc_name(dc->cond), imm);
+
+            cris_cc_mask(dc, 0);
+            cris_prepare_cc_branch(dc, imm, dc->cond); 
+            break;
+
+        default:
+            LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n",
+                     dc->pc, dc->mode, dc->opcode, dc->src, dc->dst);
+            cpu_abort(dc->env, "Unhandled quickimm\n");
+            break;
+    }
+    return 2;
+}
+
+static unsigned int dec10_setclrf(DisasContext *dc)
+{
+    uint32_t flags;
+    unsigned int set = ~dc->opcode & 1;
+
+    flags = EXTRACT_FIELD(dc->ir, 0, 3)
+            | (EXTRACT_FIELD(dc->ir, 12, 15) << 4);
+    LOG_DIS("%s set=%d flags=%x\n", __func__, set, flags);
+
+
+    if (flags & X_FLAG) {
+        dc->flagx_known = 1;
+        if (set)
+            dc->flags_x = X_FLAG;
+        else
+            dc->flags_x = 0;
+    }
+
+    cris_evaluate_flags (dc);
+    cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+    cris_update_cc_x(dc);
+    tcg_gen_movi_tl(cc_op, dc->cc_op);
+
+    if (set) {
+        tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
+    } else {
+        tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
+    }
+
+    dc->flags_uptodate = 1;
+    dc->clear_x = 0;
+    cris_lock_irq(dc);
+    return 2;
+}
+
+static inline void dec10_reg_prep_sext(DisasContext *dc, int size, int sext,
+				       TCGv dd, TCGv ds, TCGv sd, TCGv ss)
+{
+    if (sext) {
+        t_gen_sext(dd, sd, size);
+        t_gen_sext(ds, ss, size);
+    } else {
+        t_gen_zext(dd, sd, size);
+        t_gen_zext(ds, ss, size);
+    }
+}
+
+static void dec10_reg_alu(DisasContext *dc, int op, int size, int sext)
+{
+    TCGv t[2];
+
+    t[0] = tcg_temp_new();
+    t[1] = tcg_temp_new();
+    dec10_reg_prep_sext(dc, size, sext,
+                        t[0], t[1], cpu_R[dc->dst], cpu_R[dc->src]);
+
+    if (op == CC_OP_LSL || op == CC_OP_LSR || op == CC_OP_ASR) {
+        tcg_gen_andi_tl(t[1], t[1], 63);
+    }
+
+    assert(dc->dst != 15);
+    cris_alu(dc, op, cpu_R[dc->dst], t[0], t[1], size);
+    tcg_temp_free(t[0]);
+    tcg_temp_free(t[1]);
+}
+
+static void dec10_reg_bound(DisasContext *dc, int size)
+{
+    TCGv t;
+
+    t = tcg_temp_local_new();
+    t_gen_zext(t, cpu_R[dc->src], size);
+    cris_alu(dc, CC_OP_BOUND, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
+    tcg_temp_free(t);
+}
+
+static void dec10_reg_mul(DisasContext *dc, int size, int sext)
+{
+    int op = sext ? CC_OP_MULS : CC_OP_MULU;
+    TCGv t[2];
+
+    t[0] = tcg_temp_new();
+    t[1] = tcg_temp_new();
+    dec10_reg_prep_sext(dc, size, sext,
+                        t[0], t[1], cpu_R[dc->dst], cpu_R[dc->src]);
+
+    cris_alu(dc, op, cpu_R[dc->dst], t[0], t[1], 4);
+
+    tcg_temp_free(t[0]);
+    tcg_temp_free(t[1]);
+}
+
+
+static void dec10_reg_movs(DisasContext *dc)
+{
+    int size = (dc->size & 1) + 1;
+    TCGv t;
+
+    LOG_DIS("movx.%d $r%d, $r%d\n", size, dc->src, dc->dst);
+    cris_cc_mask(dc, CC_MASK_NZVC);
+
+    t = tcg_temp_new();
+    if (dc->ir & 32)
+        t_gen_sext(t, cpu_R[dc->src], size);
+    else
+        t_gen_zext(t, cpu_R[dc->src], size);
+
+    cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
+    tcg_temp_free(t);
+}
+
+static void dec10_reg_alux(DisasContext *dc, int op)
+{
+    int size = (dc->size & 1) + 1;
+    TCGv t;
+
+    LOG_DIS("movx.%d $r%d, $r%d\n", size, dc->src, dc->dst);
+    cris_cc_mask(dc, CC_MASK_NZVC);
+
+    t = tcg_temp_new();
+    if (dc->ir & 32)
+        t_gen_sext(t, cpu_R[dc->src], size);
+    else
+        t_gen_zext(t, cpu_R[dc->src], size);
+
+    cris_alu(dc, op, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
+    tcg_temp_free(t);
+}
+
+static void dec10_reg_mov_pr(DisasContext *dc)
+{
+    LOG_DIS("move p%d r%d sz=%d\n", dc->dst, dc->src, preg_sizes_v10[dc->dst]);
+    cris_lock_irq(dc);
+    if (dc->src == 15) {
+        tcg_gen_mov_tl(env_btarget, cpu_PR[dc->dst]);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        return;
+    }
+    if (dc->dst == PR_CCS) {
+        cris_evaluate_flags(dc); 
+    }
+    cris_alu(dc, CC_OP_MOVE, cpu_R[dc->src],
+                 cpu_R[dc->src], cpu_PR[dc->dst], preg_sizes_v10[dc->dst]);
+}
+
+static void dec10_reg_abs(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("abs $r%u, $r%u\n", dc->src, dc->dst);
+
+    assert(dc->dst != 15);
+    t0 = tcg_temp_new();
+    tcg_gen_sari_tl(t0, cpu_R[dc->src], 31);
+    tcg_gen_xor_tl(cpu_R[dc->dst], cpu_R[dc->src], t0);
+    tcg_gen_sub_tl(t0, cpu_R[dc->dst], t0);
+
+    cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t0, 4);
+    tcg_temp_free(t0);
+}
+
+static void dec10_reg_swap(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("not $r%d, $r%d\n", dc->src, dc->dst);
+
+    cris_cc_mask(dc, CC_MASK_NZVC);
+    t0 = tcg_temp_new();
+    t_gen_mov_TN_reg(t0, dc->src);
+    if (dc->dst & 8)
+        tcg_gen_not_tl(t0, t0);
+    if (dc->dst & 4)
+        t_gen_swapw(t0, t0);
+    if (dc->dst & 2)
+        t_gen_swapb(t0, t0);
+    if (dc->dst & 1)
+        t_gen_swapr(t0, t0);
+    cris_alu(dc, CC_OP_MOVE, cpu_R[dc->src], cpu_R[dc->src], t0, 4);
+    tcg_temp_free(t0);
+}
+
+static void dec10_reg_scc(DisasContext *dc)
+{
+    int cond = dc->dst;
+
+    LOG_DIS("s%s $r%u\n", cc_name(cond), dc->src);
+
+    if (cond != CC_A)
+    {
+        int l1;
+
+        gen_tst_cc (dc, cpu_R[dc->src], cond);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[dc->src], 0, l1);
+        tcg_gen_movi_tl(cpu_R[dc->src], 1);
+        gen_set_label(l1);
+    } else {
+        tcg_gen_movi_tl(cpu_R[dc->src], 1);
+    }
+
+    cris_cc_mask(dc, 0);
+}
+
+static unsigned int dec10_reg(DisasContext *dc)
+{
+    TCGv t;
+    unsigned int insn_len = 2;
+    unsigned int size = dec10_size(dc->size);
+    unsigned int tmp;
+
+    if (dc->size != 3) {
+        switch (dc->opcode) {
+            case CRISV10_REG_MOVE_R:
+                LOG_DIS("move.%d $r%d, $r%d\n", dc->size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_MOVE, size, 0);
+                if (dc->dst == 15) {
+                    tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
+                    cris_prepare_jmp(dc, JMP_INDIRECT);
+                    dc->delayed_branch = 1;
+                }
+                break;
+            case CRISV10_REG_MOVX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_movs(dc);
+                break;
+            case CRISV10_REG_ADDX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alux(dc, CC_OP_ADD);
+                break;
+            case CRISV10_REG_SUBX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alux(dc, CC_OP_SUB);
+                break;
+            case CRISV10_REG_ADD:
+                LOG_DIS("add $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_ADD, size, 0);
+                break;
+            case CRISV10_REG_SUB:
+                LOG_DIS("sub $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_SUB, size, 0);
+                break;
+            case CRISV10_REG_CMP:
+                LOG_DIS("cmp $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_CMP, size, 0);
+                break;
+            case CRISV10_REG_BOUND:
+                LOG_DIS("bound $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_bound(dc, size);
+                break;
+            case CRISV10_REG_AND:
+                LOG_DIS("and $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_AND, size, 0);
+                break;
+            case CRISV10_REG_ADDI:
+                if (dc->src == 15) {
+                    /* nop.  */
+                    return 2;
+                }
+                t = tcg_temp_new();
+                LOG_DIS("addi r%d r%d size=%d\n", dc->src, dc->dst, dc->size);
+                tcg_gen_shli_tl(t, cpu_R[dc->dst], dc->size & 3);
+                tcg_gen_add_tl(cpu_R[dc->src], cpu_R[dc->src], t);
+                tcg_temp_free(t);
+                break;
+            case CRISV10_REG_LSL:
+                LOG_DIS("lsl $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_LSL, size, 0);
+                break;
+            case CRISV10_REG_LSR:
+                LOG_DIS("lsr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_LSR, size, 0);
+                break;
+            case CRISV10_REG_ASR:
+                LOG_DIS("asr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_ASR, size, 1);
+                break;
+            case CRISV10_REG_OR:
+                LOG_DIS("or $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_OR, size, 0);
+                break;
+            case CRISV10_REG_NEG:
+                LOG_DIS("neg $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_NEG, size, 0);
+                break;
+            case CRISV10_REG_BIAP:
+                LOG_DIS("BIAP pc=%x reg %d r%d r%d size=%d\n", dc->pc,
+                         dc->opcode, dc->src, dc->dst, size);
+                switch (size) {
+                    case 4: tmp = 2; break;
+                    case 2: tmp = 1; break;
+                    case 1: tmp = 0; break;
+                    default:
+                        cpu_abort(dc->env, "Unhandled BIAP");
+                        break;
+                }
+
+                t = tcg_temp_new();
+                tcg_gen_shli_tl(t, cpu_R[dc->dst], tmp);
+                if (dc->src == 15) {
+                    tcg_gen_addi_tl(cpu_PR[PR_PREFIX], t, ((dc->pc +2)| 1) + 1);
+                } else {
+                    tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_R[dc->src], t);
+                }
+                tcg_temp_free(t);
+                cris_set_prefix(dc);
+                break;
+
+            default:
+                LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
+                         dc->opcode, dc->src, dc->dst);
+                cpu_abort(dc->env, "Unhandled opcode");
+                break;
+        }
+    } else {
+        switch (dc->opcode) {
+            case CRISV10_REG_MOVX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_movs(dc);
+                break;
+            case CRISV10_REG_ADDX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alux(dc, CC_OP_ADD);
+                break;
+            case CRISV10_REG_SUBX:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alux(dc, CC_OP_SUB);
+                break;
+            case CRISV10_REG_MOVE_SPR_R:
+                cris_evaluate_flags(dc);
+                cris_cc_mask(dc, 0);
+                dec10_reg_mov_pr(dc);
+                break;
+            case CRISV10_REG_MOVE_R_SPR:
+                LOG_DIS("move r%d p%d\n", dc->src, dc->dst);
+                cris_evaluate_flags(dc);
+                if (dc->src != 11) /* fast for srp.  */
+                    dc->cpustate_changed = 1;
+                t_gen_mov_preg_TN(dc, dc->dst, cpu_R[dc->src]);
+                break;
+            case CRISV10_REG_SETF:
+            case CRISV10_REG_CLEARF:
+                dec10_setclrf(dc);
+                break;
+            case CRISV10_REG_SWAP:
+                dec10_reg_swap(dc);
+                break;
+            case CRISV10_REG_ABS:
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_abs(dc);
+                break;
+            case CRISV10_REG_LZ:
+                LOG_DIS("lz $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_LZ, 4, 0);
+                break;
+            case CRISV10_REG_XOR:
+                LOG_DIS("xor $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_alu(dc, CC_OP_XOR, 4, 0);
+                break;
+            case CRISV10_REG_BTST:
+                LOG_DIS("btst $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                cris_update_cc_op(dc, CC_OP_FLAGS, 4);
+                gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst],
+                           cpu_R[dc->src], cpu_PR[PR_CCS]);
+                break;
+            case CRISV10_REG_DSTEP:
+                LOG_DIS("dstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                cris_alu(dc, CC_OP_DSTEP, cpu_R[dc->dst],
+                            cpu_R[dc->dst], cpu_R[dc->src], 4);
+                break;
+            case CRISV10_REG_MSTEP:
+                LOG_DIS("mstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
+                cris_evaluate_flags(dc);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                cris_alu(dc, CC_OP_MSTEP, cpu_R[dc->dst],
+                            cpu_R[dc->dst], cpu_R[dc->src], 4);
+                break;
+            case CRISV10_REG_SCC:
+                dec10_reg_scc(dc);
+                break;
+            default:
+                LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
+                         dc->opcode, dc->src, dc->dst);
+                cpu_abort(dc->env, "Unhandled opcode");
+                break;
+        }
+    }
+    return insn_len;
+}
+
+static unsigned int dec10_ind_move_m_r(DisasContext *dc, unsigned int size)
+{
+    unsigned int insn_len = 2;
+    TCGv t;
+
+    LOG_DIS("%s: move.%d [$r%d], $r%d\n", __func__,
+             size, dc->src, dc->dst);
+
+    cris_cc_mask(dc, CC_MASK_NZVC);
+    t = tcg_temp_new();
+    insn_len += dec10_prep_move_m(dc, 0, size, t);
+    cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t, size);
+    if (dc->dst == 15) {
+        tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        dc->delayed_branch = 1;
+        return insn_len;
+    }
+
+    tcg_temp_free(t);
+    return insn_len;
+}
+
+static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size)
+{
+    unsigned int insn_len = 2;
+    TCGv addr;
+
+    LOG_DIS("move.%d $r%d, [$r%d]\n", dc->size, dc->src, dc->dst);
+    addr = tcg_temp_new();
+    crisv10_prepare_memaddr(dc, addr, size);
+    gen_store(dc, addr, cpu_R[dc->dst], size);
+    insn_len += crisv10_post_memaddr(dc, size);
+
+    return insn_len;
+}
+
+static unsigned int dec10_ind_move_m_pr(DisasContext *dc)
+{
+    unsigned int insn_len = 2, rd = dc->dst;
+    TCGv t, addr;
+
+    LOG_DIS("move.%d $p%d, [$r%d]\n", dc->size, dc->dst, dc->src);
+    cris_lock_irq(dc);
+
+    addr = tcg_temp_new();
+    t = tcg_temp_new();
+    insn_len += dec10_prep_move_m(dc, 0, 4, t);
+    if (rd == 15) {
+        tcg_gen_mov_tl(env_btarget, t);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        dc->delayed_branch = 1;
+        return insn_len;
+    }
+
+    tcg_gen_mov_tl(cpu_PR[rd], t);
+    dc->cpustate_changed = 1;
+    tcg_temp_free(addr);
+    tcg_temp_free(t);
+    return insn_len;
+}
+
+static unsigned int dec10_ind_move_pr_m(DisasContext *dc)
+{
+    unsigned int insn_len = 2, size = preg_sizes_v10[dc->dst];
+    TCGv addr, t0;
+
+    LOG_DIS("move.%d $p%d, [$r%d]\n", dc->size, dc->dst, dc->src);
+
+    addr = tcg_temp_new();
+    crisv10_prepare_memaddr(dc, addr, size);
+    if (dc->dst == PR_CCS) {
+        t0 = tcg_temp_new();
+        cris_evaluate_flags(dc);
+        tcg_gen_andi_tl(t0, cpu_PR[PR_CCS], ~PFIX_FLAG);
+        gen_store(dc, addr, t0, size);
+        tcg_temp_free(t0);
+    } else {
+        gen_store(dc, addr, cpu_PR[dc->dst], size);
+    }
+    t0 = tcg_temp_new();
+    insn_len += crisv10_post_memaddr(dc, size);
+    cris_lock_irq(dc);
+
+    return insn_len;
+}
+
+static void dec10_movem_r_m(DisasContext *dc)
+{
+    int i, pfix = dc->tb_flags & PFIX_FLAG;
+    TCGv addr, t0;
+
+    LOG_DIS("%s r%d, [r%d] pi=%d ir=%x\n", __func__,
+              dc->dst, dc->src, dc->postinc, dc->ir);
+
+    addr = tcg_temp_new();
+    t0 = tcg_temp_new();
+    crisv10_prepare_memaddr(dc, addr, 4);
+    tcg_gen_mov_tl(t0, addr);
+    for (i = dc->dst; i >= 0; i--) {
+        if ((pfix && dc->mode == CRISV10_MODE_AUTOINC) && dc->src == i) {
+            gen_store(dc, addr, t0, 4);
+        } else {
+            gen_store(dc, addr, cpu_R[i], 4);
+        }
+        tcg_gen_addi_tl(addr, addr, 4);
+    }
+
+    if (pfix && dc->mode == CRISV10_MODE_AUTOINC) {
+        tcg_gen_mov_tl(cpu_R[dc->src], t0);
+    }
+
+    if (!pfix && dc->mode == CRISV10_MODE_AUTOINC) {
+        tcg_gen_mov_tl(cpu_R[dc->src], addr);
+    }
+    tcg_temp_free(addr);
+    tcg_temp_free(t0);
+}
+
+static void dec10_movem_m_r(DisasContext *dc)
+{
+    int i, pfix = dc->tb_flags & PFIX_FLAG;
+    TCGv addr, t0;
+
+    LOG_DIS("%s [r%d], r%d pi=%d ir=%x\n", __func__,
+              dc->src, dc->dst, dc->postinc, dc->ir);
+
+    addr = tcg_temp_new();
+    t0 = tcg_temp_new();
+    crisv10_prepare_memaddr(dc, addr, 4);
+    tcg_gen_mov_tl(t0, addr);
+    for (i = dc->dst; i >= 0; i--) {
+        gen_load(dc, cpu_R[i], addr, 4, 0);
+        tcg_gen_addi_tl(addr, addr, 4);
+    }
+
+    if (pfix && dc->mode == CRISV10_MODE_AUTOINC) {
+        tcg_gen_mov_tl(cpu_R[dc->src], t0);
+    }
+
+    if (!pfix && dc->mode == CRISV10_MODE_AUTOINC) {
+        tcg_gen_mov_tl(cpu_R[dc->src], addr);
+    }
+    tcg_temp_free(addr);
+    tcg_temp_free(t0);
+}
+
+static int dec10_ind_alu(DisasContext *dc, int op, unsigned int size)
+{
+    int insn_len = 0;
+    int rd = dc->dst;
+    TCGv t[2];
+
+    cris_alu_m_alloc_temps(t);
+    insn_len += dec10_prep_move_m(dc, 0, size, t[0]);
+    cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t[0], size);
+    if (dc->dst == 15) {
+        tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        dc->delayed_branch = 1;
+        return insn_len;
+    }
+
+    cris_alu_m_free_temps(t);
+
+    return insn_len;
+}
+
+static int dec10_ind_bound(DisasContext *dc, unsigned int size)
+{
+    int insn_len = 0;
+    int rd = dc->dst;
+    TCGv t;
+
+    t = tcg_temp_local_new();
+    insn_len += dec10_prep_move_m(dc, 0, size, t);
+    cris_alu(dc, CC_OP_BOUND, cpu_R[dc->dst], cpu_R[rd], t, 4);
+    if (dc->dst == 15) {
+        tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        dc->delayed_branch = 1;
+        return insn_len;
+    }
+
+    tcg_temp_free(t);
+    return insn_len;
+}
+
+static int dec10_alux_m(DisasContext *dc, int op)
+{
+    unsigned int size = (dc->size & 1) ? 2 : 1;
+    unsigned int sx = !!(dc->size & 2);
+    int insn_len = 2;
+    int rd = dc->dst;
+    TCGv t;
+
+    LOG_DIS("addx size=%d sx=%d op=%d %d\n", size, sx, dc->src, dc->dst);
+
+    t = tcg_temp_new();
+
+    cris_cc_mask(dc, CC_MASK_NZVC);
+    insn_len += dec10_prep_move_m(dc, sx, size, t);
+    cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t, 4);
+    if (dc->dst == 15) {
+        tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
+        cris_prepare_jmp(dc, JMP_INDIRECT);
+        dc->delayed_branch = 1;
+        return insn_len;
+    }
+
+    tcg_temp_free(t);
+    return insn_len;
+}
+
+static int dec10_dip(DisasContext *dc)
+{
+    int insn_len = 2;
+    uint32_t imm;
+
+    LOG_DIS("dip pc=%x opcode=%d r%d r%d\n",
+              dc->pc, dc->opcode, dc->src, dc->dst);
+    if (dc->src == 15) {
+        imm = ldl_code(dc->pc + 2);
+        tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm);
+        if (dc->postinc)
+            insn_len += 4;
+        tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
+    } else {
+        gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0);
+        if (dc->postinc)
+            tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], 4);
+    }
+
+    cris_set_prefix(dc);
+    return insn_len;
+}
+
+static int dec10_bdap_m(DisasContext *dc, int size)
+{
+    int insn_len = 2;
+    int rd = dc->dst;
+
+    LOG_DIS("bdap_m pc=%x opcode=%d r%d r%d sz=%d\n",
+              dc->pc, dc->opcode, dc->src, dc->dst, size);
+
+    assert(dc->dst != 15);
+#if 0
+    /* 8bit embedded offset?  */
+    if (!dc->postinc && (dc->ir & (1 << 11))) {
+        int simm = dc->ir & 0xff;
+
+        /* cpu_abort(dc->env, "Unhandled opcode"); */
+        /* sign extended.  */
+        simm = (int8_t)simm;
+
+        tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm);
+
+        cris_set_prefix(dc);
+        return insn_len;
+    }
+#endif
+    /* Now the rest of the modes are truly indirect.  */
+    insn_len += dec10_prep_move_m(dc, 1, size, cpu_PR[PR_PREFIX]);
+    tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_PR[PR_PREFIX], cpu_R[rd]);
+    cris_set_prefix(dc);
+    return insn_len;
+}
+
+static unsigned int dec10_ind(DisasContext *dc)
+{
+    unsigned int insn_len = 2;
+    unsigned int size = dec10_size(dc->size);
+    uint32_t imm;
+    int32_t simm;
+    TCGv t[2];
+
+    if (dc->size != 3) {
+        switch (dc->opcode) {
+            case CRISV10_IND_MOVE_M_R:
+                return dec10_ind_move_m_r(dc, size);
+                break;
+            case CRISV10_IND_MOVE_R_M:
+                return dec10_ind_move_r_m(dc, size);
+                break;
+            case CRISV10_IND_CMP:
+                LOG_DIS("cmp size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_alu(dc, CC_OP_CMP, size);
+                break;
+            case CRISV10_IND_TEST:
+                LOG_DIS("test size=%d op=%d %d\n",  size, dc->src, dc->dst);
+
+                cris_evaluate_flags(dc);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                cris_alu_m_alloc_temps(t);
+                insn_len += dec10_prep_move_m(dc, 0, size, t[0]);
+                tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3);
+                cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst],
+                         t[0], tcg_const_tl(0), size);
+                cris_alu_m_free_temps(t);
+                break;
+            case CRISV10_IND_ADD:
+                LOG_DIS("add size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_alu(dc, CC_OP_ADD, size);
+                break;
+            case CRISV10_IND_SUB:
+                LOG_DIS("sub size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_alu(dc, CC_OP_SUB, size);
+                break;
+            case CRISV10_IND_BOUND:
+                LOG_DIS("bound size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_bound(dc, size);
+                break;
+            case CRISV10_IND_AND:
+                LOG_DIS("and size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_alu(dc, CC_OP_AND, size);
+                break;
+            case CRISV10_IND_OR:
+                LOG_DIS("or size=%d op=%d %d\n",  size, dc->src, dc->dst);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                insn_len += dec10_ind_alu(dc, CC_OP_OR, size);
+                break;
+            case CRISV10_IND_MOVX:
+                insn_len = dec10_alux_m(dc, CC_OP_MOVE);
+                break;
+            case CRISV10_IND_ADDX:
+                insn_len = dec10_alux_m(dc, CC_OP_ADD);
+                break;
+            case CRISV10_IND_SUBX:
+                insn_len = dec10_alux_m(dc, CC_OP_SUB);
+                break;
+            case CRISV10_IND_CMPX:
+                insn_len = dec10_alux_m(dc, CC_OP_CMP);
+                break;
+            case CRISV10_IND_MUL:
+                /* This is a reg insn coded in the mem indir space.  */
+                LOG_DIS("mul pc=%x opcode=%d\n", dc->pc, dc->opcode);
+                cris_cc_mask(dc, CC_MASK_NZVC);
+                dec10_reg_mul(dc, size, dc->ir & (1 << 10));
+                break;
+            case CRISV10_IND_BDAP_M:
+                insn_len = dec10_bdap_m(dc, size);
+                break;
+            default:
+                LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n",
+                          dc->pc, size, dc->opcode, dc->src, dc->dst);
+                cpu_abort(dc->env, "Unhandled opcode");
+                break;
+        }
+        return insn_len;
+    }
+
+    switch (dc->opcode) {
+        case CRISV10_IND_MOVE_M_SPR:
+            insn_len = dec10_ind_move_m_pr(dc);
+            break;
+        case CRISV10_IND_MOVE_SPR_M:
+            insn_len = dec10_ind_move_pr_m(dc);
+            break;
+        case CRISV10_IND_JUMP_M:
+            if (dc->src == 15) {
+                LOG_DIS("jump.%d %d r%d r%d direct\n", size,
+                         dc->opcode, dc->src, dc->dst);
+                imm = ldl_code(dc->pc + 2);
+                if (dc->mode == CRISV10_MODE_AUTOINC)
+                    insn_len += size;
+
+                t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len));
+                dc->jmp_pc = imm;
+                cris_prepare_jmp(dc, JMP_DIRECT);
+                dc->delayed_branch--; /* v10 has no dslot here.  */
+            } else {
+                if (dc->dst == 14) {
+                    LOG_DIS("break %d\n", dc->src);
+                    cris_evaluate_flags(dc);
+                    tcg_gen_movi_tl(env_pc, dc->pc + 2);
+                    t_gen_raise_exception(EXCP_BREAK);
+                    dc->is_jmp = DISAS_UPDATE;
+                    return insn_len;
+                }
+                LOG_DIS("%d: jump.%d %d r%d r%d\n", __LINE__, size,
+                         dc->opcode, dc->src, dc->dst);
+                t[0] = tcg_temp_new();
+                t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len));
+                crisv10_prepare_memaddr(dc, t[0], size);
+                gen_load(dc, env_btarget, t[0], 4, 0);
+                insn_len += crisv10_post_memaddr(dc, size);
+                cris_prepare_jmp(dc, JMP_INDIRECT);
+                dc->delayed_branch--; /* v10 has no dslot here.  */
+                tcg_temp_free(t[0]);
+            }
+            break;
+
+        case CRISV10_IND_MOVEM_R_M:
+            LOG_DIS("movem_r_m pc=%x opcode=%d r%d r%d\n",
+                        dc->pc, dc->opcode, dc->dst, dc->src);
+            dec10_movem_r_m(dc);
+            break;
+        case CRISV10_IND_MOVEM_M_R:
+            LOG_DIS("movem_m_r pc=%x opcode=%d\n", dc->pc, dc->opcode);
+            dec10_movem_m_r(dc);
+            break;
+        case CRISV10_IND_JUMP_R:
+            LOG_DIS("jmp pc=%x opcode=%d r%d r%d\n",
+                        dc->pc, dc->opcode, dc->dst, dc->src);
+            tcg_gen_mov_tl(env_btarget, cpu_R[dc->src]);
+            t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len));
+            cris_prepare_jmp(dc, JMP_INDIRECT);
+            dc->delayed_branch--; /* v10 has no dslot here.  */
+            break;
+        case CRISV10_IND_MOVX:
+            insn_len = dec10_alux_m(dc, CC_OP_MOVE);
+            break;
+        case CRISV10_IND_ADDX:
+            insn_len = dec10_alux_m(dc, CC_OP_ADD);
+            break;
+        case CRISV10_IND_SUBX:
+            insn_len = dec10_alux_m(dc, CC_OP_SUB);
+            break;
+        case CRISV10_IND_CMPX:
+            insn_len = dec10_alux_m(dc, CC_OP_CMP);
+            break;
+        case CRISV10_IND_DIP:
+            insn_len = dec10_dip(dc);
+            break;
+        case CRISV10_IND_BCC_M:
+
+            cris_cc_mask(dc, 0);
+            imm = ldsw_code(dc->pc + 2);
+            simm = (int16_t)imm;
+            simm += 4;
+
+            LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm);
+            cris_prepare_cc_branch(dc, simm, dc->cond);
+            insn_len = 4;
+            break;
+        default:
+            LOG_DIS("ERROR pc=%x opcode=%d\n", dc->pc, dc->opcode);
+            cpu_abort(dc->env, "Unhandled opcode");
+            break;
+    }
+
+    return insn_len;
+}
+
+static unsigned int crisv10_decoder(DisasContext *dc)
+{
+    unsigned int insn_len = 2;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+        tcg_gen_debug_insn_start(dc->pc);
+
+    /* Load a halfword onto the instruction register.  */
+    dc->ir = lduw_code(dc->pc);
+
+    /* Now decode it.  */
+    dc->opcode   = EXTRACT_FIELD(dc->ir, 6, 9);
+    dc->mode     = EXTRACT_FIELD(dc->ir, 10, 11);
+    dc->src      = EXTRACT_FIELD(dc->ir, 0, 3);
+    dc->size     = EXTRACT_FIELD(dc->ir, 4, 5);
+    dc->cond = dc->dst = EXTRACT_FIELD(dc->ir, 12, 15);
+    dc->postinc  = EXTRACT_FIELD(dc->ir, 10, 10);
+
+    dc->clear_prefix = 1;
+
+    /* FIXME: What if this insn insn't 2 in length??  */
+    if (dc->src == 15 || dc->dst == 15)
+        tcg_gen_movi_tl(cpu_R[15], dc->pc + 2);
+
+    switch (dc->mode) {
+        case CRISV10_MODE_QIMMEDIATE:
+            insn_len = dec10_quick_imm(dc);
+            break;
+        case CRISV10_MODE_REG:
+            insn_len = dec10_reg(dc);
+            break;
+        case CRISV10_MODE_AUTOINC:
+        case CRISV10_MODE_INDIRECT:
+            insn_len = dec10_ind(dc);
+            break;
+    }
+
+    if (dc->clear_prefix && dc->tb_flags & PFIX_FLAG) {
+        dc->tb_flags &= ~PFIX_FLAG;
+        tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~PFIX_FLAG);
+        if (dc->tb_flags != dc->tb->flags) {
+            dc->cpustate_changed = 1;
+        }
+    }
+
+    /* CRISv10 locks out interrupts on dslots.  */
+    if (dc->delayed_branch == 2) {
+        cris_lock_irq(dc);
+    }
+    return insn_len;
+}
+
+static CPUCRISState *cpu_crisv10_init (CPUState *env)
+{
+	int i;
+
+	cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+	cc_x = tcg_global_mem_new(TCG_AREG0,
+				  offsetof(CPUState, cc_x), "cc_x");
+	cc_src = tcg_global_mem_new(TCG_AREG0,
+				    offsetof(CPUState, cc_src), "cc_src");
+	cc_dest = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_dest),
+				     "cc_dest");
+	cc_result = tcg_global_mem_new(TCG_AREG0,
+				       offsetof(CPUState, cc_result),
+				       "cc_result");
+	cc_op = tcg_global_mem_new(TCG_AREG0,
+				   offsetof(CPUState, cc_op), "cc_op");
+	cc_size = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_size),
+				     "cc_size");
+	cc_mask = tcg_global_mem_new(TCG_AREG0,
+				     offsetof(CPUState, cc_mask),
+				     "cc_mask");
+
+	env_pc = tcg_global_mem_new(TCG_AREG0, 
+				    offsetof(CPUState, pc),
+				    "pc");
+	env_btarget = tcg_global_mem_new(TCG_AREG0,
+					 offsetof(CPUState, btarget),
+					 "btarget");
+	env_btaken = tcg_global_mem_new(TCG_AREG0,
+					 offsetof(CPUState, btaken),
+					 "btaken");
+	for (i = 0; i < 16; i++) {
+		cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+					      offsetof(CPUState, regs[i]),
+					      regnames_v10[i]);
+	}
+	for (i = 0; i < 16; i++) {
+		cpu_PR[i] = tcg_global_mem_new(TCG_AREG0,
+					       offsetof(CPUState, pregs[i]),
+					       pregnames_v10[i]);
+	}
+
+	return env;
+}
+
diff --git a/qemu-0.15.x/target-i386/TODO b/qemu-0.15.x/target-i386/TODO
new file mode 100644
index 0000000..c8ada07
--- /dev/null
+++ b/qemu-0.15.x/target-i386/TODO
@@ -0,0 +1,32 @@
+Correctness issues:
+
+- some eflags manipulation incorrectly reset the bit 0x2.
+- SVM: test, cpu save/restore, SMM save/restore. 
+- x86_64: lcall/ljmp intel/amd differences ?
+- better code fetch (different exception handling + CS.limit support)
+- user/kernel PUSHL/POPL in helper.c
+- add missing cpuid tests
+- return UD exception if LOCK prefix incorrectly used
+- test ldt limit < 7 ?
+- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
+- full support of segment limit/rights 
+- full x87 exception support
+- improve x87 bit exactness (use bochs code ?)
+- DRx register support
+- CR0.AC emulation
+- SSE alignment checks
+- fix SSE min/max with nans
+
+Optimizations/Features:
+
+- add SVM nested paging support
+- add VMX support
+- add AVX support
+- add SSE5 support
+- fxsave/fxrstor AMD extensions
+- improve monitor/mwait support
+- faster EFLAGS update: consider SZAP, C, O can be updated separately
+  with a bit field in CC_OP and more state variables.
+- evaluate x87 stack pointer statically
+- find a way to avoid translating several time the same TB if CR0.TS
+  is set or not.
diff --git a/qemu-0.15.x/target-i386/cpu.h b/qemu-0.15.x/target-i386/cpu.h
new file mode 100644
index 0000000..9819b5f
--- /dev/null
+++ b/qemu-0.15.x/target-i386/cpu.h
@@ -0,0 +1,1060 @@
+/*
+ * i386 virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_I386_H
+#define CPU_I386_H
+
+#include "config.h"
+#include "qemu-common.h"
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#endif
+
+/* target supports implicit self modifying code */
+#define TARGET_HAS_SMC
+/* support for self modifying code even if the modified instruction is
+   close to the modifying instruction */
+#define TARGET_HAS_PRECISE_SMC
+
+#define TARGET_HAS_ICE 1
+
+#ifdef TARGET_X86_64
+#define ELF_MACHINE	EM_X86_64
+#else
+#define ELF_MACHINE	EM_386
+#endif
+
+#define CPUState struct CPUX86State
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define R_EAX 0
+#define R_ECX 1
+#define R_EDX 2
+#define R_EBX 3
+#define R_ESP 4
+#define R_EBP 5
+#define R_ESI 6
+#define R_EDI 7
+
+#define R_AL 0
+#define R_CL 1
+#define R_DL 2
+#define R_BL 3
+#define R_AH 4
+#define R_CH 5
+#define R_DH 6
+#define R_BH 7
+
+#define R_ES 0
+#define R_CS 1
+#define R_SS 2
+#define R_DS 3
+#define R_FS 4
+#define R_GS 5
+
+/* segment descriptor fields */
+#define DESC_G_MASK     (1 << 23)
+#define DESC_B_SHIFT    22
+#define DESC_B_MASK     (1 << DESC_B_SHIFT)
+#define DESC_L_SHIFT    21 /* x86_64 only : 64 bit code segment */
+#define DESC_L_MASK     (1 << DESC_L_SHIFT)
+#define DESC_AVL_MASK   (1 << 20)
+#define DESC_P_MASK     (1 << 15)
+#define DESC_DPL_SHIFT  13
+#define DESC_DPL_MASK   (3 << DESC_DPL_SHIFT)
+#define DESC_S_MASK     (1 << 12)
+#define DESC_TYPE_SHIFT 8
+#define DESC_TYPE_MASK  (15 << DESC_TYPE_SHIFT)
+#define DESC_A_MASK     (1 << 8)
+
+#define DESC_CS_MASK    (1 << 11) /* 1=code segment 0=data segment */
+#define DESC_C_MASK     (1 << 10) /* code: conforming */
+#define DESC_R_MASK     (1 << 9)  /* code: readable */
+
+#define DESC_E_MASK     (1 << 10) /* data: expansion direction */
+#define DESC_W_MASK     (1 << 9)  /* data: writable */
+
+#define DESC_TSS_BUSY_MASK (1 << 9)
+
+/* eflags masks */
+#define CC_C   	0x0001
+#define CC_P 	0x0004
+#define CC_A	0x0010
+#define CC_Z	0x0040
+#define CC_S    0x0080
+#define CC_O    0x0800
+
+#define TF_SHIFT   8
+#define IOPL_SHIFT 12
+#define VM_SHIFT   17
+
+#define TF_MASK 		0x00000100
+#define IF_MASK 		0x00000200
+#define DF_MASK 		0x00000400
+#define IOPL_MASK		0x00003000
+#define NT_MASK	         	0x00004000
+#define RF_MASK			0x00010000
+#define VM_MASK			0x00020000
+#define AC_MASK			0x00040000
+#define VIF_MASK                0x00080000
+#define VIP_MASK                0x00100000
+#define ID_MASK                 0x00200000
+
+/* hidden flags - used internally by qemu to represent additional cpu
+   states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
+   redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
+   position to ease oring with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT         0
+/* true if soft mmu is being used */
+#define HF_SOFTMMU_SHIFT     2
+/* true if hardware interrupts must be disabled for next instruction */
+#define HF_INHIBIT_IRQ_SHIFT 3
+/* 16 or 32 segments */
+#define HF_CS32_SHIFT        4
+#define HF_SS32_SHIFT        5
+/* zero base for DS, ES and SS : can be '0' only in 32 bit CS segment */
+#define HF_ADDSEG_SHIFT      6
+/* copy of CR0.PE (protected mode) */
+#define HF_PE_SHIFT          7
+#define HF_TF_SHIFT          8 /* must be same as eflags */
+#define HF_MP_SHIFT          9 /* the order must be MP, EM, TS */
+#define HF_EM_SHIFT         10
+#define HF_TS_SHIFT         11
+#define HF_IOPL_SHIFT       12 /* must be same as eflags */
+#define HF_LMA_SHIFT        14 /* only used on x86_64: long mode active */
+#define HF_CS64_SHIFT       15 /* only used on x86_64: 64 bit code segment  */
+#define HF_RF_SHIFT         16 /* must be same as eflags */
+#define HF_VM_SHIFT         17 /* must be same as eflags */
+#define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+#define HF_SVME_SHIFT       20 /* SVME enabled (copy of EFER.SVME) */
+#define HF_SVMI_SHIFT       21 /* SVM intercepts are active */
+#define HF_OSFXSR_SHIFT     22 /* CR4.OSFXSR */
+
+#define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
+#define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
+#define HF_INHIBIT_IRQ_MASK  (1 << HF_INHIBIT_IRQ_SHIFT)
+#define HF_CS32_MASK         (1 << HF_CS32_SHIFT)
+#define HF_SS32_MASK         (1 << HF_SS32_SHIFT)
+#define HF_ADDSEG_MASK       (1 << HF_ADDSEG_SHIFT)
+#define HF_PE_MASK           (1 << HF_PE_SHIFT)
+#define HF_TF_MASK           (1 << HF_TF_SHIFT)
+#define HF_MP_MASK           (1 << HF_MP_SHIFT)
+#define HF_EM_MASK           (1 << HF_EM_SHIFT)
+#define HF_TS_MASK           (1 << HF_TS_SHIFT)
+#define HF_IOPL_MASK         (3 << HF_IOPL_SHIFT)
+#define HF_LMA_MASK          (1 << HF_LMA_SHIFT)
+#define HF_CS64_MASK         (1 << HF_CS64_SHIFT)
+#define HF_RF_MASK           (1 << HF_RF_SHIFT)
+#define HF_VM_MASK           (1 << HF_VM_SHIFT)
+#define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+#define HF_SVME_MASK         (1 << HF_SVME_SHIFT)
+#define HF_SVMI_MASK         (1 << HF_SVMI_SHIFT)
+#define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
+
+/* hflags2 */
+
+#define HF2_GIF_SHIFT        0 /* if set CPU takes interrupts */
+#define HF2_HIF_SHIFT        1 /* value of IF_MASK when entering SVM */
+#define HF2_NMI_SHIFT        2 /* CPU serving NMI */
+#define HF2_VINTR_SHIFT      3 /* value of V_INTR_MASKING bit */
+
+#define HF2_GIF_MASK          (1 << HF2_GIF_SHIFT)
+#define HF2_HIF_MASK          (1 << HF2_HIF_SHIFT) 
+#define HF2_NMI_MASK          (1 << HF2_NMI_SHIFT)
+#define HF2_VINTR_MASK        (1 << HF2_VINTR_SHIFT)
+
+#define CR0_PE_SHIFT 0
+#define CR0_MP_SHIFT 1
+
+#define CR0_PE_MASK  (1 << 0)
+#define CR0_MP_MASK  (1 << 1)
+#define CR0_EM_MASK  (1 << 2)
+#define CR0_TS_MASK  (1 << 3)
+#define CR0_ET_MASK  (1 << 4)
+#define CR0_NE_MASK  (1 << 5)
+#define CR0_WP_MASK  (1 << 16)
+#define CR0_AM_MASK  (1 << 18)
+#define CR0_PG_MASK  (1 << 31)
+
+#define CR4_VME_MASK  (1 << 0)
+#define CR4_PVI_MASK  (1 << 1)
+#define CR4_TSD_MASK  (1 << 2)
+#define CR4_DE_MASK   (1 << 3)
+#define CR4_PSE_MASK  (1 << 4)
+#define CR4_PAE_MASK  (1 << 5)
+#define CR4_MCE_MASK  (1 << 6)
+#define CR4_PGE_MASK  (1 << 7)
+#define CR4_PCE_MASK  (1 << 8)
+#define CR4_OSFXSR_SHIFT 9
+#define CR4_OSFXSR_MASK (1 << CR4_OSFXSR_SHIFT)
+#define CR4_OSXMMEXCPT_MASK  (1 << 10)
+
+#define DR6_BD          (1 << 13)
+#define DR6_BS          (1 << 14)
+#define DR6_BT          (1 << 15)
+#define DR6_FIXED_1     0xffff0ff0
+
+#define DR7_GD          (1 << 13)
+#define DR7_TYPE_SHIFT  16
+#define DR7_LEN_SHIFT   18
+#define DR7_FIXED_1     0x00000400
+
+#define PG_PRESENT_BIT	0
+#define PG_RW_BIT	1
+#define PG_USER_BIT	2
+#define PG_PWT_BIT	3
+#define PG_PCD_BIT	4
+#define PG_ACCESSED_BIT	5
+#define PG_DIRTY_BIT	6
+#define PG_PSE_BIT	7
+#define PG_GLOBAL_BIT	8
+#define PG_NX_BIT	63
+
+#define PG_PRESENT_MASK  (1 << PG_PRESENT_BIT)
+#define PG_RW_MASK	 (1 << PG_RW_BIT)
+#define PG_USER_MASK	 (1 << PG_USER_BIT)
+#define PG_PWT_MASK	 (1 << PG_PWT_BIT)
+#define PG_PCD_MASK	 (1 << PG_PCD_BIT)
+#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
+#define PG_DIRTY_MASK	 (1 << PG_DIRTY_BIT)
+#define PG_PSE_MASK	 (1 << PG_PSE_BIT)
+#define PG_GLOBAL_MASK	 (1 << PG_GLOBAL_BIT)
+#define PG_NX_MASK	 (1LL << PG_NX_BIT)
+
+#define PG_ERROR_W_BIT     1
+
+#define PG_ERROR_P_MASK    0x01
+#define PG_ERROR_W_MASK    (1 << PG_ERROR_W_BIT)
+#define PG_ERROR_U_MASK    0x04
+#define PG_ERROR_RSVD_MASK 0x08
+#define PG_ERROR_I_D_MASK  0x10
+
+#define MCG_CTL_P	(1ULL<<8)   /* MCG_CAP register available */
+#define MCG_SER_P	(1ULL<<24) /* MCA recovery/new status bits */
+
+#define MCE_CAP_DEF	(MCG_CTL_P|MCG_SER_P)
+#define MCE_BANKS_DEF	10
+
+#define MCG_STATUS_RIPV	(1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV	(1ULL<<1)   /* ip points to correct instruction */
+#define MCG_STATUS_MCIP	(1ULL<<2)   /* machine check in progress */
+
+#define MCI_STATUS_VAL	(1ULL<<63)  /* valid error */
+#define MCI_STATUS_OVER	(1ULL<<62)  /* previous errors lost */
+#define MCI_STATUS_UC	(1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN	(1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC	(1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S	(1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR	(1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF	0	/* segment offset */
+#define MCM_ADDR_LINEAR	1	/* linear address */
+#define MCM_ADDR_PHYS	2	/* physical address */
+#define MCM_ADDR_MEM	3	/* memory address */
+#define MCM_ADDR_GENERIC 7	/* generic */
+
+#define MSR_IA32_TSC                    0x10
+#define MSR_IA32_APICBASE               0x1b
+#define MSR_IA32_APICBASE_BSP           (1<<8)
+#define MSR_IA32_APICBASE_ENABLE        (1<<11)
+#define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+
+#define MSR_MTRRcap			0xfe
+#define MSR_MTRRcap_VCNT		8
+#define MSR_MTRRcap_FIXRANGE_SUPPORT	(1 << 8)
+#define MSR_MTRRcap_WC_SUPPORTED	(1 << 10)
+
+#define MSR_IA32_SYSENTER_CS            0x174
+#define MSR_IA32_SYSENTER_ESP           0x175
+#define MSR_IA32_SYSENTER_EIP           0x176
+
+#define MSR_MCG_CAP                     0x179
+#define MSR_MCG_STATUS                  0x17a
+#define MSR_MCG_CTL                     0x17b
+
+#define MSR_IA32_PERF_STATUS            0x198
+
+#define MSR_MTRRphysBase(reg)		(0x200 + 2 * (reg))
+#define MSR_MTRRphysMask(reg)		(0x200 + 2 * (reg) + 1)
+
+#define MSR_MTRRfix64K_00000		0x250
+#define MSR_MTRRfix16K_80000		0x258
+#define MSR_MTRRfix16K_A0000		0x259
+#define MSR_MTRRfix4K_C0000		0x268
+#define MSR_MTRRfix4K_C8000		0x269
+#define MSR_MTRRfix4K_D0000		0x26a
+#define MSR_MTRRfix4K_D8000		0x26b
+#define MSR_MTRRfix4K_E0000		0x26c
+#define MSR_MTRRfix4K_E8000		0x26d
+#define MSR_MTRRfix4K_F0000		0x26e
+#define MSR_MTRRfix4K_F8000		0x26f
+
+#define MSR_PAT                         0x277
+
+#define MSR_MTRRdefType			0x2ff
+
+#define MSR_MC0_CTL			0x400
+#define MSR_MC0_STATUS			0x401
+#define MSR_MC0_ADDR			0x402
+#define MSR_MC0_MISC			0x403
+
+#define MSR_EFER                        0xc0000080
+
+#define MSR_EFER_SCE   (1 << 0)
+#define MSR_EFER_LME   (1 << 8)
+#define MSR_EFER_LMA   (1 << 10)
+#define MSR_EFER_NXE   (1 << 11)
+#define MSR_EFER_SVME  (1 << 12)
+#define MSR_EFER_FFXSR (1 << 14)
+
+#define MSR_STAR                        0xc0000081
+#define MSR_LSTAR                       0xc0000082
+#define MSR_CSTAR                       0xc0000083
+#define MSR_FMASK                       0xc0000084
+#define MSR_FSBASE                      0xc0000100
+#define MSR_GSBASE                      0xc0000101
+#define MSR_KERNELGSBASE                0xc0000102
+#define MSR_TSC_AUX                     0xc0000103
+
+#define MSR_VM_HSAVE_PA                 0xc0010117
+
+/* cpuid_features bits */
+#define CPUID_FP87 (1 << 0)
+#define CPUID_VME  (1 << 1)
+#define CPUID_DE   (1 << 2)
+#define CPUID_PSE  (1 << 3)
+#define CPUID_TSC  (1 << 4)
+#define CPUID_MSR  (1 << 5)
+#define CPUID_PAE  (1 << 6)
+#define CPUID_MCE  (1 << 7)
+#define CPUID_CX8  (1 << 8)
+#define CPUID_APIC (1 << 9)
+#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
+#define CPUID_MTRR (1 << 12)
+#define CPUID_PGE  (1 << 13)
+#define CPUID_MCA  (1 << 14)
+#define CPUID_CMOV (1 << 15)
+#define CPUID_PAT  (1 << 16)
+#define CPUID_PSE36   (1 << 17)
+#define CPUID_PN   (1 << 18)
+#define CPUID_CLFLUSH (1 << 19)
+#define CPUID_DTS (1 << 21)
+#define CPUID_ACPI (1 << 22)
+#define CPUID_MMX  (1 << 23)
+#define CPUID_FXSR (1 << 24)
+#define CPUID_SSE  (1 << 25)
+#define CPUID_SSE2 (1 << 26)
+#define CPUID_SS (1 << 27)
+#define CPUID_HT (1 << 28)
+#define CPUID_TM (1 << 29)
+#define CPUID_IA64 (1 << 30)
+#define CPUID_PBE (1 << 31)
+
+#define CPUID_EXT_SSE3     (1 << 0)
+#define CPUID_EXT_DTES64   (1 << 2)
+#define CPUID_EXT_MONITOR  (1 << 3)
+#define CPUID_EXT_DSCPL    (1 << 4)
+#define CPUID_EXT_VMX      (1 << 5)
+#define CPUID_EXT_SMX      (1 << 6)
+#define CPUID_EXT_EST      (1 << 7)
+#define CPUID_EXT_TM2      (1 << 8)
+#define CPUID_EXT_SSSE3    (1 << 9)
+#define CPUID_EXT_CID      (1 << 10)
+#define CPUID_EXT_CX16     (1 << 13)
+#define CPUID_EXT_XTPR     (1 << 14)
+#define CPUID_EXT_PDCM     (1 << 15)
+#define CPUID_EXT_DCA      (1 << 18)
+#define CPUID_EXT_SSE41    (1 << 19)
+#define CPUID_EXT_SSE42    (1 << 20)
+#define CPUID_EXT_X2APIC   (1 << 21)
+#define CPUID_EXT_MOVBE    (1 << 22)
+#define CPUID_EXT_POPCNT   (1 << 23)
+#define CPUID_EXT_XSAVE    (1 << 26)
+#define CPUID_EXT_OSXSAVE  (1 << 27)
+#define CPUID_EXT_HYPERVISOR  (1 << 31)
+
+#define CPUID_EXT2_SYSCALL (1 << 11)
+#define CPUID_EXT2_MP      (1 << 19)
+#define CPUID_EXT2_NX      (1 << 20)
+#define CPUID_EXT2_MMXEXT  (1 << 22)
+#define CPUID_EXT2_FFXSR   (1 << 25)
+#define CPUID_EXT2_PDPE1GB (1 << 26)
+#define CPUID_EXT2_RDTSCP  (1 << 27)
+#define CPUID_EXT2_LM      (1 << 29)
+#define CPUID_EXT2_3DNOWEXT (1 << 30)
+#define CPUID_EXT2_3DNOW   (1 << 31)
+
+#define CPUID_EXT3_LAHF_LM (1 << 0)
+#define CPUID_EXT3_CMP_LEG (1 << 1)
+#define CPUID_EXT3_SVM     (1 << 2)
+#define CPUID_EXT3_EXTAPIC (1 << 3)
+#define CPUID_EXT3_CR8LEG  (1 << 4)
+#define CPUID_EXT3_ABM     (1 << 5)
+#define CPUID_EXT3_SSE4A   (1 << 6)
+#define CPUID_EXT3_MISALIGNSSE (1 << 7)
+#define CPUID_EXT3_3DNOWPREFETCH (1 << 8)
+#define CPUID_EXT3_OSVW    (1 << 9)
+#define CPUID_EXT3_IBS     (1 << 10)
+#define CPUID_EXT3_SKINIT  (1 << 12)
+
+#define CPUID_SVM_NPT          (1 << 0)
+#define CPUID_SVM_LBRV         (1 << 1)
+#define CPUID_SVM_SVMLOCK      (1 << 2)
+#define CPUID_SVM_NRIPSAVE     (1 << 3)
+#define CPUID_SVM_TSCSCALE     (1 << 4)
+#define CPUID_SVM_VMCBCLEAN    (1 << 5)
+#define CPUID_SVM_FLUSHASID    (1 << 6)
+#define CPUID_SVM_DECODEASSIST (1 << 7)
+#define CPUID_SVM_PAUSEFILTER  (1 << 10)
+#define CPUID_SVM_PFTHRESHOLD  (1 << 12)
+
+#define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
+#define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
+#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
+
+#define CPUID_VENDOR_AMD_1   0x68747541 /* "Auth" */
+#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_3   0x444d4163 /* "cAMD" */
+
+#define CPUID_VENDOR_VIA_1   0x746e6543 /* "Cent" */
+#define CPUID_VENDOR_VIA_2   0x48727561 /* "aurH" */
+#define CPUID_VENDOR_VIA_3   0x736c7561 /* "auls" */
+
+#define CPUID_MWAIT_IBE     (1 << 1) /* Interrupts can exit capability */
+#define CPUID_MWAIT_EMX     (1 << 0) /* enumeration supported */
+
+#define EXCP00_DIVZ	0
+#define EXCP01_DB	1
+#define EXCP02_NMI	2
+#define EXCP03_INT3	3
+#define EXCP04_INTO	4
+#define EXCP05_BOUND	5
+#define EXCP06_ILLOP	6
+#define EXCP07_PREX	7
+#define EXCP08_DBLE	8
+#define EXCP09_XERR	9
+#define EXCP0A_TSS	10
+#define EXCP0B_NOSEG	11
+#define EXCP0C_STACK	12
+#define EXCP0D_GPF	13
+#define EXCP0E_PAGE	14
+#define EXCP10_COPR	16
+#define EXCP11_ALGN	17
+#define EXCP12_MCHK	18
+
+#define EXCP_SYSCALL    0x100 /* only happens in user only emulation
+                                 for syscall instruction */
+
+/* i386-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_SMI       CPU_INTERRUPT_TGT_EXT_2
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+#define CPU_INTERRUPT_MCE       CPU_INTERRUPT_TGT_EXT_4
+#define CPU_INTERRUPT_VIRQ      CPU_INTERRUPT_TGT_INT_0
+#define CPU_INTERRUPT_INIT      CPU_INTERRUPT_TGT_INT_1
+#define CPU_INTERRUPT_SIPI      CPU_INTERRUPT_TGT_INT_2
+
+
+enum {
+    CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
+    CC_OP_EFLAGS,  /* all cc are explicitly computed, CC_SRC = flags */
+
+    CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
+    CC_OP_MULW,
+    CC_OP_MULL,
+    CC_OP_MULQ,
+
+    CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_ADDW,
+    CC_OP_ADDL,
+    CC_OP_ADDQ,
+
+    CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_ADCW,
+    CC_OP_ADCL,
+    CC_OP_ADCQ,
+
+    CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_SUBW,
+    CC_OP_SUBL,
+    CC_OP_SUBQ,
+
+    CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_SBBW,
+    CC_OP_SBBL,
+    CC_OP_SBBQ,
+
+    CC_OP_LOGICB, /* modify all flags, CC_DST = res */
+    CC_OP_LOGICW,
+    CC_OP_LOGICL,
+    CC_OP_LOGICQ,
+
+    CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
+    CC_OP_INCW,
+    CC_OP_INCL,
+    CC_OP_INCQ,
+
+    CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C  */
+    CC_OP_DECW,
+    CC_OP_DECL,
+    CC_OP_DECQ,
+
+    CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.msb = C */
+    CC_OP_SHLW,
+    CC_OP_SHLL,
+    CC_OP_SHLQ,
+
+    CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
+    CC_OP_SARW,
+    CC_OP_SARL,
+    CC_OP_SARQ,
+
+    CC_OP_NB,
+};
+
+typedef struct SegmentCache {
+    uint32_t selector;
+    target_ulong base;
+    uint32_t limit;
+    uint32_t flags;
+} SegmentCache;
+
+typedef union {
+    uint8_t _b[16];
+    uint16_t _w[8];
+    uint32_t _l[4];
+    uint64_t _q[2];
+    float32 _s[4];
+    float64 _d[2];
+} XMMReg;
+
+typedef union {
+    uint8_t _b[8];
+    uint16_t _w[4];
+    uint32_t _l[2];
+    float32 _s[2];
+    uint64_t q;
+} MMXReg;
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define XMM_B(n) _b[15 - (n)]
+#define XMM_W(n) _w[7 - (n)]
+#define XMM_L(n) _l[3 - (n)]
+#define XMM_S(n) _s[3 - (n)]
+#define XMM_Q(n) _q[1 - (n)]
+#define XMM_D(n) _d[1 - (n)]
+
+#define MMX_B(n) _b[7 - (n)]
+#define MMX_W(n) _w[3 - (n)]
+#define MMX_L(n) _l[1 - (n)]
+#define MMX_S(n) _s[1 - (n)]
+#else
+#define XMM_B(n) _b[n]
+#define XMM_W(n) _w[n]
+#define XMM_L(n) _l[n]
+#define XMM_S(n) _s[n]
+#define XMM_Q(n) _q[n]
+#define XMM_D(n) _d[n]
+
+#define MMX_B(n) _b[n]
+#define MMX_W(n) _w[n]
+#define MMX_L(n) _l[n]
+#define MMX_S(n) _s[n]
+#endif
+#define MMX_Q(n) q
+
+typedef union {
+    floatx80 d __attribute__((aligned(16)));
+    MMXReg mmx;
+} FPReg;
+
+typedef struct {
+    uint64_t base;
+    uint64_t mask;
+} MTRRVar;
+
+#define CPU_NB_REGS64 16
+#define CPU_NB_REGS32 8
+
+#ifdef TARGET_X86_64
+#define CPU_NB_REGS CPU_NB_REGS64
+#else
+#define CPU_NB_REGS CPU_NB_REGS32
+#endif
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUX86State {
+    /* standard registers */
+    target_ulong regs[CPU_NB_REGS];
+    target_ulong eip;
+    target_ulong eflags; /* eflags register. During CPU emulation, CC
+                        flags and DF are set to zero because they are
+                        stored elsewhere */
+
+    /* emulator internal eflags handling */
+    target_ulong cc_src;
+    target_ulong cc_dst;
+    uint32_t cc_op;
+    int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
+    uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
+                        are known at translation time. */
+    uint32_t hflags2; /* various other flags, see HF2_xxx constants. */
+
+    /* segments */
+    SegmentCache segs[6]; /* selector values */
+    SegmentCache ldt;
+    SegmentCache tr;
+    SegmentCache gdt; /* only base and limit are used */
+    SegmentCache idt; /* only base and limit are used */
+
+    target_ulong cr[5]; /* NOTE: cr1 is unused */
+    int32_t a20_mask;
+
+    /* FPU state */
+    unsigned int fpstt; /* top of stack index */
+    uint16_t fpus;
+    uint16_t fpuc;
+    uint8_t fptags[8];   /* 0 = valid, 1 = empty */
+    FPReg fpregs[8];
+    /* KVM-only so far */
+    uint16_t fpop;
+    uint64_t fpip;
+    uint64_t fpdp;
+
+    /* emulator internal variables */
+    float_status fp_status;
+    floatx80 ft0;
+
+    float_status mmx_status; /* for 3DNow! float ops */
+    float_status sse_status;
+    uint32_t mxcsr;
+    XMMReg xmm_regs[CPU_NB_REGS];
+    XMMReg xmm_t0;
+    MMXReg mmx_t0;
+    target_ulong cc_tmp; /* temporary for rcr/rcl */
+
+    /* sysenter registers */
+    uint32_t sysenter_cs;
+    target_ulong sysenter_esp;
+    target_ulong sysenter_eip;
+    uint64_t efer;
+    uint64_t star;
+
+    uint64_t vm_hsave;
+    uint64_t vm_vmcb;
+    uint64_t tsc_offset;
+    uint64_t intercept;
+    uint16_t intercept_cr_read;
+    uint16_t intercept_cr_write;
+    uint16_t intercept_dr_read;
+    uint16_t intercept_dr_write;
+    uint32_t intercept_exceptions;
+    uint8_t v_tpr;
+
+#ifdef TARGET_X86_64
+    target_ulong lstar;
+    target_ulong cstar;
+    target_ulong fmask;
+    target_ulong kernelgsbase;
+#endif
+    uint64_t system_time_msr;
+    uint64_t wall_clock_msr;
+    uint64_t async_pf_en_msr;
+
+    uint64_t tsc;
+
+    uint64_t mcg_status;
+
+    /* exception/interrupt handling */
+    int error_code;
+    int exception_is_int;
+    target_ulong exception_next_eip;
+    target_ulong dr[8]; /* debug registers */
+    union {
+        CPUBreakpoint *cpu_breakpoint[4];
+        CPUWatchpoint *cpu_watchpoint[4];
+    }; /* break/watchpoints for dr[0..3] */
+    uint32_t smbase;
+    int old_exception;  /* exception in flight */
+
+    /* KVM states, automatically cleared on reset */
+    uint8_t nmi_injected;
+    uint8_t nmi_pending;
+
+    CPU_COMMON
+
+    uint64_t pat;
+
+    /* processor features (e.g. for CPUID insn) */
+    uint32_t cpuid_level;
+    uint32_t cpuid_vendor1;
+    uint32_t cpuid_vendor2;
+    uint32_t cpuid_vendor3;
+    uint32_t cpuid_version;
+    uint32_t cpuid_features;
+    uint32_t cpuid_ext_features;
+    uint32_t cpuid_xlevel;
+    uint32_t cpuid_model[12];
+    uint32_t cpuid_ext2_features;
+    uint32_t cpuid_ext3_features;
+    uint32_t cpuid_apic_id;
+    int cpuid_vendor_override;
+    /* Store the results of Centaur's CPUID instructions */
+    uint32_t cpuid_xlevel2;
+    uint32_t cpuid_ext4_features;
+
+    /* MTRRs */
+    uint64_t mtrr_fixed[11];
+    uint64_t mtrr_deftype;
+    MTRRVar mtrr_var[8];
+
+    /* For KVM */
+    uint32_t mp_state;
+    int32_t exception_injected;
+    int32_t interrupt_injected;
+    uint8_t soft_interrupt;
+    uint8_t has_error_code;
+    uint32_t sipi_vector;
+    uint32_t cpuid_kvm_features;
+    uint32_t cpuid_svm_features;
+    bool tsc_valid;
+    
+    /* in order to simplify APIC support, we leave this pointer to the
+       user */
+    struct DeviceState *apic_state;
+
+    uint64_t mcg_cap;
+    uint64_t mcg_ctl;
+    uint64_t mce_banks[MCE_BANKS_DEF*4];
+
+    uint64_t tsc_aux;
+
+    /* vmstate */
+    uint16_t fpus_vmstate;
+    uint16_t fptag_vmstate;
+    uint16_t fpregs_format_vmstate;
+
+    uint64_t xstate_bv;
+    XMMReg ymmh_regs[CPU_NB_REGS];
+
+    uint64_t xcr0;
+} CPUX86State;
+
+CPUX86State *cpu_x86_init(const char *cpu_model);
+int cpu_x86_exec(CPUX86State *s);
+void cpu_x86_close(CPUX86State *s);
+void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg);
+void x86_cpudef_setup(void);
+int cpu_x86_support_mca_broadcast(CPUState *env);
+
+int cpu_get_pic_interrupt(CPUX86State *s);
+/* MSDOS compatibility mode FPU exception support */
+void cpu_set_ferr(CPUX86State *s);
+
+/* this function must always be used to load data in the segment
+   cache: it synchronizes the hflags with the segment cache values */
+static inline void cpu_x86_load_seg_cache(CPUX86State *env,
+                                          int seg_reg, unsigned int selector,
+                                          target_ulong base,
+                                          unsigned int limit,
+                                          unsigned int flags)
+{
+    SegmentCache *sc;
+    unsigned int new_hflags;
+
+    sc = &env->segs[seg_reg];
+    sc->selector = selector;
+    sc->base = base;
+    sc->limit = limit;
+    sc->flags = flags;
+
+    /* update the hidden flags */
+    {
+        if (seg_reg == R_CS) {
+#ifdef TARGET_X86_64
+            if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) {
+                /* long mode */
+                env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+                env->hflags &= ~(HF_ADDSEG_MASK);
+            } else
+#endif
+            {
+                /* legacy / compatibility case */
+                new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
+                    >> (DESC_B_SHIFT - HF_CS32_SHIFT);
+                env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) |
+                    new_hflags;
+            }
+        }
+        new_hflags = (env->segs[R_SS].flags & DESC_B_MASK)
+            >> (DESC_B_SHIFT - HF_SS32_SHIFT);
+        if (env->hflags & HF_CS64_MASK) {
+            /* zero base assumed for DS, ES and SS in long mode */
+        } else if (!(env->cr[0] & CR0_PE_MASK) ||
+                   (env->eflags & VM_MASK) ||
+                   !(env->hflags & HF_CS32_MASK)) {
+            /* XXX: try to avoid this test. The problem comes from the
+               fact that is real mode or vm86 mode we only modify the
+               'base' and 'selector' fields of the segment cache to go
+               faster. A solution may be to force addseg to one in
+               translate-i386.c. */
+            new_hflags |= HF_ADDSEG_MASK;
+        } else {
+            new_hflags |= ((env->segs[R_DS].base |
+                            env->segs[R_ES].base |
+                            env->segs[R_SS].base) != 0) <<
+                HF_ADDSEG_SHIFT;
+        }
+        env->hflags = (env->hflags &
+                       ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
+    }
+}
+
+static inline void cpu_x86_load_seg_cache_sipi(CPUX86State *env,
+                                               int sipi_vector)
+{
+    env->eip = 0;
+    cpu_x86_load_seg_cache(env, R_CS, sipi_vector << 8,
+                           sipi_vector << 12,
+                           env->segs[R_CS].limit,
+                           env->segs[R_CS].flags);
+    env->halted = 0;
+}
+
+int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
+                            target_ulong *base, unsigned int *limit,
+                            unsigned int *flags);
+
+/* wrapper, just in case memory mappings must be changed */
+static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
+{
+#if HF_CPL_MASK == 3
+    s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
+#else
+#error HF_CPL_MASK is hardcoded
+#endif
+}
+
+/* op_helper.c */
+/* used for debug or cpu save/restore */
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
+
+/* cpu-exec.c */
+/* the following helpers are only usable in user mode simulation as
+   they can trigger unexpected exceptions */
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
+void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32);
+void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_x86_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+
+/* cpuid.c */
+void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
+                   uint32_t *eax, uint32_t *ebx,
+                   uint32_t *ecx, uint32_t *edx);
+int cpu_x86_register (CPUX86State *env, const char *cpu_model);
+void cpu_clear_apic_feature(CPUX86State *env);
+void host_cpuid(uint32_t function, uint32_t count,
+                uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
+
+/* helper.c */
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+                             int is_write, int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
+void cpu_x86_set_a20(CPUX86State *env, int a20_state);
+
+static inline int hw_breakpoint_enabled(unsigned long dr7, int index)
+{
+    return (dr7 >> (index * 2)) & 3;
+}
+
+static inline int hw_breakpoint_type(unsigned long dr7, int index)
+{
+    return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3;
+}
+
+static inline int hw_breakpoint_len(unsigned long dr7, int index)
+{
+    int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3);
+    return (len == 2) ? 8 : len + 1;
+}
+
+void hw_breakpoint_insert(CPUX86State *env, int index);
+void hw_breakpoint_remove(CPUX86State *env, int index);
+int check_hw_breakpoints(CPUX86State *env, int force_dr6_update);
+
+/* will be suppressed */
+void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
+void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
+void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
+
+/* hw/pc.c */
+void cpu_smm_update(CPUX86State *env);
+uint64_t cpu_get_tsc(CPUX86State *env);
+
+/* used to debug */
+#define X86_DUMP_FPU  0x0001 /* dump FPU state too */
+#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
+
+#define TARGET_PAGE_BITS 12
+
+#ifdef TARGET_X86_64
+#define TARGET_PHYS_ADDR_SPACE_BITS 52
+/* ??? This is really 48 bits, sign-extended, but the only thing
+   accessible to userland with bit 48 set is the VSYSCALL, and that
+   is handled via other mechanisms.  */
+#define TARGET_VIRT_ADDR_SPACE_BITS 47
+#else
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#define cpu_init cpu_x86_init
+#define cpu_exec cpu_x86_exec
+#define cpu_gen_code cpu_x86_gen_code
+#define cpu_signal_handler cpu_x86_signal_handler
+#define cpu_list_id x86_cpu_list
+#define cpudef_setup	x86_cpudef_setup
+
+#define CPU_SAVE_VERSION 12
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
+}
+
+#undef EAX
+#define EAX (env->regs[R_EAX])
+#undef ECX
+#define ECX (env->regs[R_ECX])
+#undef EDX
+#define EDX (env->regs[R_EDX])
+#undef EBX
+#define EBX (env->regs[R_EBX])
+#undef ESP
+#define ESP (env->regs[R_ESP])
+#undef EBP
+#define EBP (env->regs[R_EBP])
+#undef ESI
+#define ESI (env->regs[R_ESI])
+#undef EDI
+#define EDI (env->regs[R_EDI])
+#undef EIP
+#define EIP (env->eip)
+#define DF  (env->df)
+
+#define CC_SRC (env->cc_src)
+#define CC_DST (env->cc_dst)
+#define CC_OP  (env->cc_op)
+
+/* float macros */
+#define FT0    (env->ft0)
+#define ST0    (env->fpregs[env->fpstt].d)
+#define ST(n)  (env->fpregs[(env->fpstt + (n)) & 7].d)
+#define ST1    ST(1)
+
+/* translate.c */
+void optimize_flags_init(void);
+
+typedef struct CCTable {
+    int (*compute_all)(void); /* return all the flags */
+    int (*compute_c)(void);  /* return the C flag */
+} CCTable;
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_ESP] = newsp;
+    env->regs[R_EAX] = 0;
+}
+#endif
+
+#include "cpu-all.h"
+#include "svm.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/apic.h"
+#endif
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->eflags & IF_MASK)) ||
+           (env->interrupt_request & (CPU_INTERRUPT_NMI |
+                                      CPU_INTERRUPT_INIT |
+                                      CPU_INTERRUPT_SIPI |
+                                      CPU_INTERRUPT_MCE));
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->eip = tb->pc - tb->cs_base;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *cs_base = env->segs[R_CS].base;
+    *pc = *cs_base + env->eip;
+    *flags = env->hflags |
+        (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK));
+}
+
+void do_cpu_init(CPUState *env);
+void do_cpu_sipi(CPUState *env);
+
+#define MCE_INJECT_BROADCAST    1
+#define MCE_INJECT_UNCOND_AO    2
+
+void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
+                        uint64_t status, uint64_t mcg_status, uint64_t addr,
+                        uint64_t misc, int flags);
+
+/* op_helper.c */
+void do_interrupt(CPUState *env);
+void do_interrupt_x86_hardirq(CPUState *env, int intno, int is_hw);
+
+void do_smm_enter(CPUState *env1);
+
+void svm_check_intercept(CPUState *env1, uint32_t type);
+
+uint32_t cpu_cc_compute_all(CPUState *env1, int op);
+
+#endif /* CPU_I386_H */
diff --git a/qemu-0.15.x/target-i386/cpuid.c b/qemu-0.15.x/target-i386/cpuid.c
new file mode 100644
index 0000000..e1ae3af
--- /dev/null
+++ b/qemu-0.15.x/target-i386/cpuid.c
@@ -0,0 +1,1308 @@
+/*
+ *  i386 CPUID helper functions
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "kvm.h"
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+
+/* feature flags taken from "Intel Processor Identification and the CPUID
+ * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
+ * between feature naming conventions, aliases may be added.
+ */
+static const char *feature_name[] = {
+    "fpu", "vme", "de", "pse",
+    "tsc", "msr", "pae", "mce",
+    "cx8", "apic", NULL, "sep",
+    "mtrr", "pge", "mca", "cmov",
+    "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
+    NULL, "ds" /* Intel dts */, "acpi", "mmx",
+    "fxsr", "sse", "sse2", "ss",
+    "ht" /* Intel htt */, "tm", "ia64", "pbe",
+};
+static const char *ext_feature_name[] = {
+    "pni|sse3" /* Intel,AMD sse3 */, "pclmuldq", "dtes64", "monitor",
+    "ds_cpl", "vmx", "smx", "est",
+    "tm2", "ssse3", "cid", NULL,
+    "fma", "cx16", "xtpr", "pdcm",
+    NULL, NULL, "dca", "sse4.1|sse4_1",
+    "sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
+    NULL, "aes", "xsave", "osxsave",
+    "avx", NULL, NULL, "hypervisor",
+};
+static const char *ext2_feature_name[] = {
+    "fpu", "vme", "de", "pse",
+    "tsc", "msr", "pae", "mce",
+    "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
+    "mtrr", "pge", "mca", "cmov",
+    "pat", "pse36", NULL, NULL /* Linux mp */,
+    "nx" /* Intel xd */, NULL, "mmxext", "mmx",
+    "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
+    NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
+};
+static const char *ext3_feature_name[] = {
+    "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
+    "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+    "3dnowprefetch", "osvw", "ibs", "xop",
+    "skinit", "wdt", NULL, NULL,
+    "fma4", NULL, "cvt16", "nodeid_msr",
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+};
+
+static const char *kvm_feature_name[] = {
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static const char *svm_feature_name[] = {
+    "npt", "lbrv", "svm_lock", "nrip_save",
+    "tsc_scale", "vmcb_clean",  "flushbyasid", "decodeassists",
+    NULL, NULL, "pause_filter", NULL,
+    "pfthreshold", NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+};
+
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+    uint32_t *guest_feat;
+    uint32_t *host_feat;
+    uint32_t check_feat;
+    const char **flag_names;
+    uint32_t cpuid;
+    } model_features_t;
+
+int check_cpuid = 0;
+int enforce_cpuid = 0;
+
+void host_cpuid(uint32_t function, uint32_t count,
+                uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
+{
+#if defined(CONFIG_KVM)
+    uint32_t vec[4];
+
+#ifdef __x86_64__
+    asm volatile("cpuid"
+                 : "=a"(vec[0]), "=b"(vec[1]),
+                   "=c"(vec[2]), "=d"(vec[3])
+                 : "0"(function), "c"(count) : "cc");
+#else
+    asm volatile("pusha \n\t"
+                 "cpuid \n\t"
+                 "mov %%eax, 0(%2) \n\t"
+                 "mov %%ebx, 4(%2) \n\t"
+                 "mov %%ecx, 8(%2) \n\t"
+                 "mov %%edx, 12(%2) \n\t"
+                 "popa"
+                 : : "a"(function), "c"(count), "S"(vec)
+                 : "memory", "cc");
+#endif
+
+    if (eax)
+        *eax = vec[0];
+    if (ebx)
+        *ebx = vec[1];
+    if (ecx)
+        *ecx = vec[2];
+    if (edx)
+        *edx = vec[3];
+#endif
+}
+
+#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
+
+/* general substring compare of *[s1..e1) and *[s2..e2).  sx is start of
+ * a substring.  ex if !NULL points to the first char after a substring,
+ * otherwise the string is assumed to sized by a terminating nul.
+ * Return lexical ordering of *s1:*s2.
+ */
+static int sstrcmp(const char *s1, const char *e1, const char *s2,
+    const char *e2)
+{
+    for (;;) {
+        if (!*s1 || !*s2 || *s1 != *s2)
+            return (*s1 - *s2);
+        ++s1, ++s2;
+        if (s1 == e1 && s2 == e2)
+            return (0);
+        else if (s1 == e1)
+            return (*s2);
+        else if (s2 == e2)
+            return (*s1);
+    }
+}
+
+/* compare *[s..e) to *altstr.  *altstr may be a simple string or multiple
+ * '|' delimited (possibly empty) strings in which case search for a match
+ * within the alternatives proceeds left to right.  Return 0 for success,
+ * non-zero otherwise.
+ */
+static int altcmp(const char *s, const char *e, const char *altstr)
+{
+    const char *p, *q;
+
+    for (q = p = altstr; ; ) {
+        while (*p && *p != '|')
+            ++p;
+        if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
+            return (0);
+        if (!*p)
+            return (1);
+        else
+            q = ++p;
+    }
+}
+
+/* search featureset for flag *[s..e), if found set corresponding bit in
+ * *pval and return true, otherwise return false
+ */
+static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
+                           const char **featureset)
+{
+    uint32_t mask;
+    const char **ppc;
+    bool found = false;
+
+    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
+        if (*ppc && !altcmp(s, e, *ppc)) {
+            *pval |= mask;
+            found = true;
+        }
+    }
+    return found;
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
+                                    uint32_t *ext_features,
+                                    uint32_t *ext2_features,
+                                    uint32_t *ext3_features,
+                                    uint32_t *kvm_features,
+                                    uint32_t *svm_features)
+{
+    if (!lookup_feature(features, flagname, NULL, feature_name) &&
+        !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
+        !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
+        !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
+        !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
+        !lookup_feature(svm_features, flagname, NULL, svm_feature_name))
+            fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+typedef struct x86_def_t {
+    struct x86_def_t *next;
+    const char *name;
+    uint32_t level;
+    uint32_t vendor1, vendor2, vendor3;
+    int family;
+    int model;
+    int stepping;
+    uint32_t features, ext_features, ext2_features, ext3_features;
+    uint32_t kvm_features, svm_features;
+    uint32_t xlevel;
+    char model_id[48];
+    int vendor_override;
+    uint32_t flags;
+    /* Store the results of Centaur's CPUID instructions */
+    uint32_t ext4_features;
+    uint32_t xlevel2;
+} x86_def_t;
+
+#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
+#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
+          CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
+#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \
+          CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
+          CPUID_PSE36 | CPUID_FXSR)
+#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
+#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
+          CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
+          CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
+          CPUID_PAE | CPUID_SEP | CPUID_APIC)
+#define EXT2_FEATURE_MASK 0x0183F3FF
+
+#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
+          CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
+          CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
+          CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
+          CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS)
+          /* partly implemented:
+          CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64)
+          CPUID_PSE36 (needed for Solaris) */
+          /* missing:
+          CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
+#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \
+          CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \
+          CPUID_EXT_HYPERVISOR)
+          /* missing:
+          CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
+          CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */
+#define TCG_EXT2_FEATURES ((TCG_FEATURES & EXT2_FEATURE_MASK) | \
+          CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
+          CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT)
+          /* missing:
+          CPUID_EXT2_PDPE1GB */
+#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
+          CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
+#define TCG_SVM_FEATURES 0
+
+/* maintains list of cpu model definitions
+ */
+static x86_def_t *x86_defs = {NULL};
+
+/* built-in cpu model definitions (deprecated)
+ */
+static x86_def_t builtin_x86_defs[] = {
+    {
+        .name = "qemu64",
+        .level = 4,
+        .vendor1 = CPUID_VENDOR_AMD_1,
+        .vendor2 = CPUID_VENDOR_AMD_2,
+        .vendor3 = CPUID_VENDOR_AMD_3,
+        .family = 6,
+        .model = 2,
+        .stepping = 3,
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+            CPUID_PSE36,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
+        .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
+        .xlevel = 0x8000000A,
+        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+    },
+    {
+        .name = "phenom",
+        .level = 5,
+        .vendor1 = CPUID_VENDOR_AMD_1,
+        .vendor2 = CPUID_VENDOR_AMD_2,
+        .vendor3 = CPUID_VENDOR_AMD_3,
+        .family = 16,
+        .model = 2,
+        .stepping = 3,
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+            CPUID_PSE36 | CPUID_VME | CPUID_HT,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
+            CPUID_EXT_POPCNT,
+        .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
+            CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
+            CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
+        /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
+                    CPUID_EXT3_CR8LEG,
+                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+                    CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
+        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
+        .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
+        .xlevel = 0x8000001A,
+        .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
+    },
+    {
+        .name = "core2duo",
+        .level = 10,
+        .family = 6,
+        .model = 15,
+        .stepping = 11,
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+            CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
+            CPUID_HT | CPUID_TM | CPUID_PBE,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+            CPUID_EXT_DTES64 | CPUID_EXT_DSCPL | CPUID_EXT_VMX | CPUID_EXT_EST |
+            CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
+        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .xlevel = 0x80000008,
+        .model_id = "Intel(R) Core(TM)2 Duo CPU     T7700  @ 2.40GHz",
+    },
+    {
+        .name = "kvm64",
+        .level = 5,
+        .vendor1 = CPUID_VENDOR_INTEL_1,
+        .vendor2 = CPUID_VENDOR_INTEL_2,
+        .vendor3 = CPUID_VENDOR_INTEL_3,
+        .family = 15,
+        .model = 6,
+        .stepping = 1,
+        /* Missing: CPUID_VME, CPUID_HT */
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+            CPUID_PSE36,
+        /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+        /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
+        .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+        /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
+                    CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
+                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+                    CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
+        .ext3_features = 0,
+        .xlevel = 0x80000008,
+        .model_id = "Common KVM processor"
+    },
+    {
+        .name = "qemu32",
+        .level = 4,
+        .family = 6,
+        .model = 3,
+        .stepping = 3,
+        .features = PPRO_FEATURES,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
+        .xlevel = 0x80000004,
+        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+    },
+    {
+        .name = "kvm32",
+        .level = 5,
+        .family = 15,
+        .model = 6,
+        .stepping = 1,
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
+        .ext_features = CPUID_EXT_SSE3,
+        .ext2_features = PPRO_FEATURES & EXT2_FEATURE_MASK,
+        .ext3_features = 0,
+        .xlevel = 0x80000008,
+        .model_id = "Common 32-bit KVM processor"
+    },
+    {
+        .name = "coreduo",
+        .level = 10,
+        .family = 6,
+        .model = 14,
+        .stepping = 8,
+        .features = PPRO_FEATURES | CPUID_VME |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI |
+            CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
+            CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
+        .ext2_features = CPUID_EXT2_NX,
+        .xlevel = 0x80000008,
+        .model_id = "Genuine Intel(R) CPU           T2600  @ 2.16GHz",
+    },
+    {
+        .name = "486",
+        .level = 1,
+        .family = 4,
+        .model = 0,
+        .stepping = 0,
+        .features = I486_FEATURES,
+        .xlevel = 0,
+    },
+    {
+        .name = "pentium",
+        .level = 1,
+        .family = 5,
+        .model = 4,
+        .stepping = 3,
+        .features = PENTIUM_FEATURES,
+        .xlevel = 0,
+    },
+    {
+        .name = "pentium2",
+        .level = 2,
+        .family = 6,
+        .model = 5,
+        .stepping = 2,
+        .features = PENTIUM2_FEATURES,
+        .xlevel = 0,
+    },
+    {
+        .name = "pentium3",
+        .level = 2,
+        .family = 6,
+        .model = 7,
+        .stepping = 3,
+        .features = PENTIUM3_FEATURES,
+        .xlevel = 0,
+    },
+    {
+        .name = "athlon",
+        .level = 2,
+        .vendor1 = CPUID_VENDOR_AMD_1,
+        .vendor2 = CPUID_VENDOR_AMD_2,
+        .vendor3 = CPUID_VENDOR_AMD_3,
+        .family = 6,
+        .model = 2,
+        .stepping = 3,
+        .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
+        .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
+        .xlevel = 0x80000008,
+        /* XXX: put another string ? */
+        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+    },
+    {
+        .name = "n270",
+        /* original is on level 10 */
+        .level = 5,
+        .family = 6,
+        .model = 28,
+        .stepping = 2,
+        .features = PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME | CPUID_DTS |
+            CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+            /* Some CPUs got no CPUID_SEP */
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+            CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
+        .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_NX,
+        .ext3_features = CPUID_EXT3_LAHF_LM,
+        .xlevel = 0x8000000A,
+        .model_id = "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
+    },
+};
+
+static int cpu_x86_fill_model_id(char *str)
+{
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
+        memcpy(str + i * 16 +  0, &eax, 4);
+        memcpy(str + i * 16 +  4, &ebx, 4);
+        memcpy(str + i * 16 +  8, &ecx, 4);
+        memcpy(str + i * 16 + 12, &edx, 4);
+    }
+    return 0;
+}
+
+static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
+{
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+
+    x86_cpu_def->name = "host";
+    host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+    x86_cpu_def->level = eax;
+    x86_cpu_def->vendor1 = ebx;
+    x86_cpu_def->vendor2 = edx;
+    x86_cpu_def->vendor3 = ecx;
+
+    host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+    x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+    x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+    x86_cpu_def->stepping = eax & 0x0F;
+    x86_cpu_def->ext_features = ecx;
+    x86_cpu_def->features = edx;
+
+    host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
+    x86_cpu_def->xlevel = eax;
+
+    host_cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
+    x86_cpu_def->ext2_features = edx;
+    x86_cpu_def->ext3_features = ecx;
+    cpu_x86_fill_model_id(x86_cpu_def->model_id);
+    x86_cpu_def->vendor_override = 0;
+
+    /* Call Centaur's CPUID instruction. */
+    if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+        x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+        x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+        host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+        if (eax >= 0xC0000001) {
+            /* Support VIA max extended level */
+            x86_cpu_def->xlevel2 = eax;
+            host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+            x86_cpu_def->ext4_features = edx;
+        }
+    }
+
+    /*
+     * Every SVM feature requires emulation support in KVM - so we can't just
+     * read the host features here. KVM might even support SVM features not
+     * available on the host hardware. Just set all bits and mask out the
+     * unsupported ones later.
+     */
+    x86_cpu_def->svm_features = -1;
+
+    return 0;
+}
+
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+    int i;
+
+    for (i = 0; i < 32; ++i)
+        if (1 << i & mask) {
+            fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+                " flag '%s' [0x%08x]\n",
+                f->cpuid >> 16, f->cpuid & 0xffff,
+                f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+            break;
+        }
+    return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest.  Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+    x86_def_t host_def;
+    uint32_t mask;
+    int rv, i;
+    struct model_features_t ft[] = {
+        {&guest_def->features, &host_def.features,
+            ~0, feature_name, 0x00000000},
+        {&guest_def->ext_features, &host_def.ext_features,
+            ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+        {&guest_def->ext2_features, &host_def.ext2_features,
+            ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+        {&guest_def->ext3_features, &host_def.ext3_features,
+            ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+    cpu_x86_fill_host(&host_def);
+    for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
+        for (mask = 1; mask; mask <<= 1)
+            if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+                !(*ft[i].host_feat & mask)) {
+                    unavailable_host_feature(&ft[i], mask);
+                    rv = 1;
+                }
+    return rv;
+}
+
+static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
+{
+    unsigned int i;
+    x86_def_t *def;
+
+    char *s = strdup(cpu_model);
+    char *featurestr, *name = strtok(s, ",");
+    /* Features to be added*/
+    uint32_t plus_features = 0, plus_ext_features = 0;
+    uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
+    uint32_t plus_kvm_features = 0, plus_svm_features = 0;
+    /* Features to be removed */
+    uint32_t minus_features = 0, minus_ext_features = 0;
+    uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
+    uint32_t minus_kvm_features = 0, minus_svm_features = 0;
+    uint32_t numvalue;
+
+    for (def = x86_defs; def; def = def->next)
+        if (!strcmp(name, def->name))
+            break;
+    if (kvm_enabled() && strcmp(name, "host") == 0) {
+        cpu_x86_fill_host(x86_cpu_def);
+    } else if (!def) {
+        goto error;
+    } else {
+        memcpy(x86_cpu_def, def, sizeof(*def));
+    }
+
+    plus_kvm_features = ~0; /* not supported bits will be filtered out later */
+
+    add_flagname_to_bitmaps("hypervisor", &plus_features,
+        &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
+        &plus_kvm_features, &plus_svm_features);
+
+    featurestr = strtok(NULL, ",");
+
+    while (featurestr) {
+        char *val;
+        if (featurestr[0] == '+') {
+            add_flagname_to_bitmaps(featurestr + 1, &plus_features,
+                            &plus_ext_features, &plus_ext2_features,
+                            &plus_ext3_features, &plus_kvm_features,
+                            &plus_svm_features);
+        } else if (featurestr[0] == '-') {
+            add_flagname_to_bitmaps(featurestr + 1, &minus_features,
+                            &minus_ext_features, &minus_ext2_features,
+                            &minus_ext3_features, &minus_kvm_features,
+                            &minus_svm_features);
+        } else if ((val = strchr(featurestr, '='))) {
+            *val = 0; val++;
+            if (!strcmp(featurestr, "family")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->family = numvalue;
+            } else if (!strcmp(featurestr, "model")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err || numvalue > 0xff) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->model = numvalue;
+            } else if (!strcmp(featurestr, "stepping")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err || numvalue > 0xf) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->stepping = numvalue ;
+            } else if (!strcmp(featurestr, "level")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->level = numvalue;
+            } else if (!strcmp(featurestr, "xlevel")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                if (numvalue < 0x80000000) {
+                    numvalue += 0x80000000;
+                }
+                x86_cpu_def->xlevel = numvalue;
+            } else if (!strcmp(featurestr, "vendor")) {
+                if (strlen(val) != 12) {
+                    fprintf(stderr, "vendor string must be 12 chars long\n");
+                    goto error;
+                }
+                x86_cpu_def->vendor1 = 0;
+                x86_cpu_def->vendor2 = 0;
+                x86_cpu_def->vendor3 = 0;
+                for(i = 0; i < 4; i++) {
+                    x86_cpu_def->vendor1 |= ((uint8_t)val[i    ]) << (8 * i);
+                    x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
+                    x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
+                }
+                x86_cpu_def->vendor_override = 1;
+            } else if (!strcmp(featurestr, "model_id")) {
+                pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
+                        val);
+            } else {
+                fprintf(stderr, "unrecognized feature %s\n", featurestr);
+                goto error;
+            }
+        } else if (!strcmp(featurestr, "check")) {
+            check_cpuid = 1;
+        } else if (!strcmp(featurestr, "enforce")) {
+            check_cpuid = enforce_cpuid = 1;
+        } else {
+            fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
+            goto error;
+        }
+        featurestr = strtok(NULL, ",");
+    }
+    x86_cpu_def->features |= plus_features;
+    x86_cpu_def->ext_features |= plus_ext_features;
+    x86_cpu_def->ext2_features |= plus_ext2_features;
+    x86_cpu_def->ext3_features |= plus_ext3_features;
+    x86_cpu_def->kvm_features |= plus_kvm_features;
+    x86_cpu_def->svm_features |= plus_svm_features;
+    x86_cpu_def->features &= ~minus_features;
+    x86_cpu_def->ext_features &= ~minus_ext_features;
+    x86_cpu_def->ext2_features &= ~minus_ext2_features;
+    x86_cpu_def->ext3_features &= ~minus_ext3_features;
+    x86_cpu_def->kvm_features &= ~minus_kvm_features;
+    x86_cpu_def->svm_features &= ~minus_svm_features;
+    if (check_cpuid) {
+        if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
+            goto error;
+    }
+    free(s);
+    return 0;
+
+error:
+    free(s);
+    return -1;
+}
+
+/* generate a composite string into buf of all cpuid names in featureset
+ * selected by fbits.  indicate truncation at bufsize in the event of overflow.
+ * if flags, suppress names undefined in featureset.
+ */
+static void listflags(char *buf, int bufsize, uint32_t fbits,
+    const char **featureset, uint32_t flags)
+{
+    const char **p = &featureset[31];
+    char *q, *b, bit;
+    int nc;
+
+    b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
+    *buf = '\0';
+    for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
+        if (fbits & 1 << bit && (*p || !flags)) {
+            if (*p)
+                nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
+            else
+                nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
+            if (bufsize <= nc) {
+                if (b) {
+                    memcpy(b, "...", sizeof("..."));
+                }
+                return;
+            }
+            q += nc;
+            bufsize -= nc;
+        }
+}
+
+/* generate CPU information:
+ * -?        list model names
+ * -?model   list model names/IDs
+ * -?dump    output all model (x86_def_t) data
+ * -?cpuid   list all recognized cpuid flag names
+ */
+void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
+{
+    unsigned char model = !strcmp("?model", optarg);
+    unsigned char dump = !strcmp("?dump", optarg);
+    unsigned char cpuid = !strcmp("?cpuid", optarg);
+    x86_def_t *def;
+    char buf[256];
+
+    if (cpuid) {
+        (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
+        listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
+        (*cpu_fprintf)(f, "  f_edx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
+        (*cpu_fprintf)(f, "  f_ecx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
+        (*cpu_fprintf)(f, "  extf_edx: %s\n", buf);
+        listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
+        (*cpu_fprintf)(f, "  extf_ecx: %s\n", buf);
+        return;
+    }
+    for (def = x86_defs; def; def = def->next) {
+        snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
+        if (model || dump) {
+            (*cpu_fprintf)(f, "x86 %16s  %-48s\n", buf, def->model_id);
+        } else {
+            (*cpu_fprintf)(f, "x86 %16s\n", buf);
+        }
+        if (dump) {
+            memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+            memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+            memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+            buf[12] = '\0';
+            (*cpu_fprintf)(f,
+                "  family %d model %d stepping %d level %d xlevel 0x%x"
+                " vendor \"%s\"\n",
+                def->family, def->model, def->stepping, def->level,
+                def->xlevel, buf);
+            listflags(buf, sizeof (buf), def->features, feature_name, 0);
+            (*cpu_fprintf)(f, "  feature_edx %08x (%s)\n", def->features,
+                buf);
+            listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  feature_ecx %08x (%s)\n", def->ext_features,
+                buf);
+            listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  extfeature_edx %08x (%s)\n",
+                def->ext2_features, buf);
+            listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
+                0);
+            (*cpu_fprintf)(f, "  extfeature_ecx %08x (%s)\n",
+                def->ext3_features, buf);
+            (*cpu_fprintf)(f, "\n");
+        }
+    }
+    if (kvm_enabled()) {
+        (*cpu_fprintf)(f, "x86 %16s\n", "[host]");
+    }
+}
+
+int cpu_x86_register (CPUX86State *env, const char *cpu_model)
+{
+    x86_def_t def1, *def = &def1;
+
+    memset(def, 0, sizeof(*def));
+
+    if (cpu_x86_find_by_name(def, cpu_model) < 0)
+        return -1;
+    if (def->vendor1) {
+        env->cpuid_vendor1 = def->vendor1;
+        env->cpuid_vendor2 = def->vendor2;
+        env->cpuid_vendor3 = def->vendor3;
+    } else {
+        env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1;
+        env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
+        env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
+    }
+    env->cpuid_vendor_override = def->vendor_override;
+    env->cpuid_level = def->level;
+    if (def->family > 0x0f)
+        env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20);
+    else
+        env->cpuid_version = def->family << 8;
+    env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16);
+    env->cpuid_version |= def->stepping;
+    env->cpuid_features = def->features;
+    env->cpuid_ext_features = def->ext_features;
+    env->cpuid_ext2_features = def->ext2_features;
+    env->cpuid_ext3_features = def->ext3_features;
+    env->cpuid_xlevel = def->xlevel;
+    env->cpuid_kvm_features = def->kvm_features;
+    env->cpuid_svm_features = def->svm_features;
+    env->cpuid_ext4_features = def->ext4_features;
+    env->cpuid_xlevel2 = def->xlevel2;
+    if (!kvm_enabled()) {
+        env->cpuid_features &= TCG_FEATURES;
+        env->cpuid_ext_features &= TCG_EXT_FEATURES;
+        env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
+#ifdef TARGET_X86_64
+            | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
+#endif
+            );
+        env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
+        env->cpuid_svm_features &= TCG_SVM_FEATURES;
+    }
+    {
+        const char *model_id = def->model_id;
+        int c, len, i;
+        if (!model_id)
+            model_id = "";
+        len = strlen(model_id);
+        for(i = 0; i < 48; i++) {
+            if (i >= len)
+                c = '\0';
+            else
+                c = (uint8_t)model_id[i];
+            env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
+        }
+    }
+    return 0;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* copy vendor id string to 32 bit register, nul pad as needed
+ */
+static void cpyid(const char *s, uint32_t *id)
+{
+    char *d = (char *)id;
+    char i;
+
+    for (i = sizeof (*id); i--; )
+        *d++ = *s ? *s++ : '\0';
+}
+
+/* interpret radix and convert from string to arbitrary scalar,
+ * otherwise flag failure
+ */
+#define setscalar(pval, str, perr)                      \
+{                                                       \
+    char *pend;                                         \
+    unsigned long ul;                                   \
+                                                        \
+    ul = strtoul(str, &pend, 0);                        \
+    *str && !*pend ? (*pval = ul) : (*perr = 1);        \
+}
+
+/* map cpuid options to feature bits, otherwise return failure
+ * (option tags in *str are delimited by whitespace)
+ */
+static void setfeatures(uint32_t *pval, const char *str,
+    const char **featureset, int *perr)
+{
+    const char *p, *q;
+
+    for (q = p = str; *p || *q; q = p) {
+        while (iswhite(*p))
+            q = ++p;
+        while (*p && !iswhite(*p))
+            ++p;
+        if (!*q && !*p)
+            return;
+        if (!lookup_feature(pval, q, p, featureset)) {
+            fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
+                (int)(p - q), q);
+            *perr = 1;
+            return;
+        }
+    }
+}
+
+/* map config file options to x86_def_t form
+ */
+static int cpudef_setfield(const char *name, const char *str, void *opaque)
+{
+    x86_def_t *def = opaque;
+    int err = 0;
+
+    if (!strcmp(name, "name")) {
+        def->name = strdup(str);
+    } else if (!strcmp(name, "model_id")) {
+        strncpy(def->model_id, str, sizeof (def->model_id));
+    } else if (!strcmp(name, "level")) {
+        setscalar(&def->level, str, &err)
+    } else if (!strcmp(name, "vendor")) {
+        cpyid(&str[0], &def->vendor1);
+        cpyid(&str[4], &def->vendor2);
+        cpyid(&str[8], &def->vendor3);
+    } else if (!strcmp(name, "family")) {
+        setscalar(&def->family, str, &err)
+    } else if (!strcmp(name, "model")) {
+        setscalar(&def->model, str, &err)
+    } else if (!strcmp(name, "stepping")) {
+        setscalar(&def->stepping, str, &err)
+    } else if (!strcmp(name, "feature_edx")) {
+        setfeatures(&def->features, str, feature_name, &err);
+    } else if (!strcmp(name, "feature_ecx")) {
+        setfeatures(&def->ext_features, str, ext_feature_name, &err);
+    } else if (!strcmp(name, "extfeature_edx")) {
+        setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
+    } else if (!strcmp(name, "extfeature_ecx")) {
+        setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
+    } else if (!strcmp(name, "xlevel")) {
+        setscalar(&def->xlevel, str, &err)
+    } else {
+        fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
+        return (1);
+    }
+    if (err) {
+        fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
+        return (1);
+    }
+    return (0);
+}
+
+/* register config file entry as x86_def_t
+ */
+static int cpudef_register(QemuOpts *opts, void *opaque)
+{
+    x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
+
+    qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+    def->next = x86_defs;
+    x86_defs = def;
+    return (0);
+}
+
+void cpu_clear_apic_feature(CPUX86State *env)
+{
+    env->cpuid_features &= ~CPUID_APIC;
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+/* register "cpudef" models defined in configuration file.  Here we first
+ * preload any built-in definitions
+ */
+void x86_cpudef_setup(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
+        builtin_x86_defs[i].next = x86_defs;
+        builtin_x86_defs[i].flags = 1;
+        x86_defs = &builtin_x86_defs[i];
+    }
+#if !defined(CONFIG_USER_ONLY)
+    qemu_opts_foreach(qemu_find_opts("cpudef"), cpudef_register, NULL, 0);
+#endif
+}
+
+static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
+                             uint32_t *ecx, uint32_t *edx)
+{
+    *ebx = env->cpuid_vendor1;
+    *edx = env->cpuid_vendor2;
+    *ecx = env->cpuid_vendor3;
+
+    /* sysenter isn't supported on compatibility mode on AMD, syscall
+     * isn't supported in compatibility mode on Intel.
+     * Normally we advertise the actual cpu vendor, but you can override
+     * this if you want to use KVM's sysenter/syscall emulation
+     * in compatibility mode and when doing cross vendor migration
+     */
+    if (kvm_enabled() && ! env->cpuid_vendor_override) {
+        host_cpuid(0, 0, NULL, ebx, ecx, edx);
+    }
+}
+
+void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
+                   uint32_t *eax, uint32_t *ebx,
+                   uint32_t *ecx, uint32_t *edx)
+{
+    /* test if maximum index reached */
+    if (index & 0x80000000) {
+        if (index > env->cpuid_xlevel) {
+            if (env->cpuid_xlevel2 > 0) {
+                /* Handle the Centaur's CPUID instruction. */
+                if (index > env->cpuid_xlevel2) {
+                    index = env->cpuid_xlevel2;
+                } else if (index < 0xC0000000) {
+                    index = env->cpuid_xlevel;
+                }
+            } else {
+                index =  env->cpuid_xlevel;
+            }
+        }
+    } else {
+        if (index > env->cpuid_level)
+            index = env->cpuid_level;
+    }
+
+    switch(index) {
+    case 0:
+        *eax = env->cpuid_level;
+        get_cpuid_vendor(env, ebx, ecx, edx);
+        break;
+    case 1:
+        *eax = env->cpuid_version;
+        *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
+        *ecx = env->cpuid_ext_features;
+        *edx = env->cpuid_features;
+        if (env->nr_cores * env->nr_threads > 1) {
+            *ebx |= (env->nr_cores * env->nr_threads) << 16;
+            *edx |= 1 << 28;    /* HTT bit */
+        }
+        break;
+    case 2:
+        /* cache info: needed for Pentium Pro compatibility */
+        *eax = 1;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0x2c307d;
+        break;
+    case 4:
+        /* cache info: needed for Core compatibility */
+        if (env->nr_cores > 1) {
+            *eax = (env->nr_cores - 1) << 26;
+        } else {
+            *eax = 0;
+        }
+        switch (count) {
+            case 0: /* L1 dcache info */
+                *eax |= 0x0000121;
+                *ebx = 0x1c0003f;
+                *ecx = 0x000003f;
+                *edx = 0x0000001;
+                break;
+            case 1: /* L1 icache info */
+                *eax |= 0x0000122;
+                *ebx = 0x1c0003f;
+                *ecx = 0x000003f;
+                *edx = 0x0000001;
+                break;
+            case 2: /* L2 cache info */
+                *eax |= 0x0000143;
+                if (env->nr_threads > 1) {
+                    *eax |= (env->nr_threads - 1) << 14;
+                }
+                *ebx = 0x3c0003f;
+                *ecx = 0x0000fff;
+                *edx = 0x0000001;
+                break;
+            default: /* end of info */
+                *eax = 0;
+                *ebx = 0;
+                *ecx = 0;
+                *edx = 0;
+                break;
+        }
+        break;
+    case 5:
+        /* mwait info: needed for Core compatibility */
+        *eax = 0; /* Smallest monitor-line size in bytes */
+        *ebx = 0; /* Largest monitor-line size in bytes */
+        *ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
+        *edx = 0;
+        break;
+    case 6:
+        /* Thermal and Power Leaf */
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 7:
+        if (kvm_enabled()) {
+            KVMState *s = env->kvm_state;
+
+            *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
+            *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
+            *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
+            *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
+        } else {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+        }
+        break;
+    case 9:
+        /* Direct Cache Access Information Leaf */
+        *eax = 0; /* Bits 0-31 in DCA_CAP MSR */
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0xA:
+        /* Architectural Performance Monitoring Leaf */
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0xD:
+        /* Processor Extended State */
+        if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE)) {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+            break;
+        }
+        if (kvm_enabled()) {
+            KVMState *s = env->kvm_state;
+
+            *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX);
+            *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX);
+            *ecx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_ECX);
+            *edx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EDX);
+        } else {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+        }
+        break;
+    case 0x80000000:
+        *eax = env->cpuid_xlevel;
+        *ebx = env->cpuid_vendor1;
+        *edx = env->cpuid_vendor2;
+        *ecx = env->cpuid_vendor3;
+        break;
+    case 0x80000001:
+        *eax = env->cpuid_version;
+        *ebx = 0;
+        *ecx = env->cpuid_ext3_features;
+        *edx = env->cpuid_ext2_features;
+
+        /* The Linux kernel checks for the CMPLegacy bit and
+         * discards multiple thread information if it is set.
+         * So dont set it here for Intel to make Linux guests happy.
+         */
+        if (env->nr_cores * env->nr_threads > 1) {
+            uint32_t tebx, tecx, tedx;
+            get_cpuid_vendor(env, &tebx, &tecx, &tedx);
+            if (tebx != CPUID_VENDOR_INTEL_1 ||
+                tedx != CPUID_VENDOR_INTEL_2 ||
+                tecx != CPUID_VENDOR_INTEL_3) {
+                *ecx |= 1 << 1;    /* CmpLegacy bit */
+            }
+        }
+        break;
+    case 0x80000002:
+    case 0x80000003:
+    case 0x80000004:
+        *eax = env->cpuid_model[(index - 0x80000002) * 4 + 0];
+        *ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1];
+        *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
+        *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
+        break;
+    case 0x80000005:
+        /* cache info (L1 cache) */
+        *eax = 0x01ff01ff;
+        *ebx = 0x01ff01ff;
+        *ecx = 0x40020140;
+        *edx = 0x40020140;
+        break;
+    case 0x80000006:
+        /* cache info (L2 cache) */
+        *eax = 0;
+        *ebx = 0x42004200;
+        *ecx = 0x02008140;
+        *edx = 0;
+        break;
+    case 0x80000008:
+        /* virtual & phys address size in low 2 bytes. */
+/* XXX: This value must match the one used in the MMU code. */
+        if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
+            /* 64 bit processor */
+/* XXX: The physical address space is limited to 42 bits in exec.c. */
+            *eax = 0x00003028;	/* 48 bits virtual, 40 bits physical */
+        } else {
+            if (env->cpuid_features & CPUID_PSE36)
+                *eax = 0x00000024; /* 36 bits physical */
+            else
+                *eax = 0x00000020; /* 32 bits physical */
+        }
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        if (env->nr_cores * env->nr_threads > 1) {
+            *ecx |= (env->nr_cores * env->nr_threads) - 1;
+        }
+        break;
+    case 0x8000000A:
+	if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
+		*eax = 0x00000001; /* SVM Revision */
+		*ebx = 0x00000010; /* nr of ASIDs */
+		*ecx = 0;
+		*edx = env->cpuid_svm_features; /* optional features */
+	} else {
+		*eax = 0;
+		*ebx = 0;
+		*ecx = 0;
+		*edx = 0;
+	}
+        break;
+    case 0xC0000000:
+        *eax = env->cpuid_xlevel2;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0xC0000001:
+        /* Support for VIA CPU's CPUID instruction */
+        *eax = env->cpuid_version;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = env->cpuid_ext4_features;
+        break;
+    case 0xC0000002:
+    case 0xC0000003:
+    case 0xC0000004:
+        /* Reserved for the future, and now filled with zero */
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    default:
+        /* reserved values: zero */
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    }
+}
diff --git a/qemu-0.15.x/target-i386/exec.h b/qemu-0.15.x/target-i386/exec.h
new file mode 100644
index 0000000..dd9bce4
--- /dev/null
+++ b/qemu-0.15.x/target-i386/exec.h
@@ -0,0 +1,142 @@
+/*
+ *  i386 execution defines
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "dyngen-exec.h"
+
+/* XXX: factorize this mess */
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#endif
+
+#include "cpu-defs.h"
+
+register struct CPUX86State *env asm(AREG0);
+
+#include "qemu-common.h"
+#include "qemu-log.h"
+
+#include "cpu.h"
+
+/* op_helper.c */
+void QEMU_NORETURN raise_exception_err(int exception_index, int error_code);
+void QEMU_NORETURN raise_exception(int exception_index);
+void QEMU_NORETURN raise_exception_env(int exception_index, CPUState *nenv);
+
+/* n must be a constant to be efficient */
+static inline target_long lshift(target_long x, int n)
+{
+    if (n >= 0)
+        return x << n;
+    else
+        return x >> (-n);
+}
+
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+
+#include "softmmu_exec.h"
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#define RC_MASK         0xc00
+#define RC_NEAR		0x000
+#define RC_DOWN		0x400
+#define RC_UP		0x800
+#define RC_CHOP		0xc00
+
+#define MAXTAN 9223372036854775808.0
+
+/* the following deal with x86 long double-precision numbers */
+#define MAXEXPD 0x7fff
+#define EXPBIAS 16383
+#define EXPD(fp)	(fp.l.upper & 0x7fff)
+#define SIGND(fp)	((fp.l.upper) & 0x8000)
+#define MANTD(fp)       (fp.l.lower)
+#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
+
+static inline void fpush(void)
+{
+    env->fpstt = (env->fpstt - 1) & 7;
+    env->fptags[env->fpstt] = 0; /* validate stack entry */
+}
+
+static inline void fpop(void)
+{
+    env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
+    env->fpstt = (env->fpstt + 1) & 7;
+}
+
+static inline floatx80 helper_fldt(target_ulong ptr)
+{
+    CPU_LDoubleU temp;
+
+    temp.l.lower = ldq(ptr);
+    temp.l.upper = lduw(ptr + 8);
+    return temp.d;
+}
+
+static inline void helper_fstt(floatx80 f, target_ulong ptr)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = f;
+    stq(ptr, temp.l.lower);
+    stw(ptr + 8, temp.l.upper);
+}
+
+#define FPUS_IE (1 << 0)
+#define FPUS_DE (1 << 1)
+#define FPUS_ZE (1 << 2)
+#define FPUS_OE (1 << 3)
+#define FPUS_UE (1 << 4)
+#define FPUS_PE (1 << 5)
+#define FPUS_SF (1 << 6)
+#define FPUS_SE (1 << 7)
+#define FPUS_B  (1 << 15)
+
+#define FPUC_EM 0x3f
+
+static inline uint32_t compute_eflags(void)
+{
+    return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+}
+
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
+static inline void load_eflags(int eflags, int update_mask)
+{
+    CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+    DF = 1 - (2 * ((eflags >> 10) & 1));
+    env->eflags = (env->eflags & ~update_mask) |
+        (eflags & update_mask) | 0x2;
+}
+
+/* load efer and update the corresponding hflags. XXX: do consistency
+   checks with cpuid bits ? */
+static inline void cpu_load_efer(CPUState *env, uint64_t val)
+{
+    env->efer = val;
+    env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
+    if (env->efer & MSR_EFER_LMA)
+        env->hflags |= HF_LMA_MASK;
+    if (env->efer & MSR_EFER_SVME)
+        env->hflags |= HF_SVME_MASK;
+}
diff --git a/qemu-0.15.x/target-i386/helper.c b/qemu-0.15.x/target-i386/helper.c
new file mode 100644
index 0000000..e9be104
--- /dev/null
+++ b/qemu-0.15.x/target-i386/helper.c
@@ -0,0 +1,1292 @@
+/*
+ *  i386 helpers (without register variable usage)
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "qemu-common.h"
+#include "kvm.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu.h"
+#include "monitor.h"
+#endif
+
+//#define DEBUG_MMU
+
+/* NOTE: must be called outside the CPU execute loop */
+void cpu_reset(CPUX86State *env)
+{
+    int i;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
+    }
+
+    memset(env, 0, offsetof(CPUX86State, breakpoints));
+
+    tlb_flush(env, 1);
+
+    env->old_exception = -1;
+
+    /* init to reset state */
+
+#ifdef CONFIG_SOFTMMU
+    env->hflags |= HF_SOFTMMU_MASK;
+#endif
+    env->hflags2 |= HF2_GIF_MASK;
+
+    cpu_x86_update_cr0(env, 0x60000010);
+    env->a20_mask = ~0x0;
+    env->smbase = 0x30000;
+
+    env->idt.limit = 0xffff;
+    env->gdt.limit = 0xffff;
+    env->ldt.limit = 0xffff;
+    env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
+    env->tr.limit = 0xffff;
+    env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
+
+    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+                           DESC_R_MASK | DESC_A_MASK);
+    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+                           DESC_A_MASK);
+    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+                           DESC_A_MASK);
+    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+                           DESC_A_MASK);
+    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+                           DESC_A_MASK);
+    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
+                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+                           DESC_A_MASK);
+
+    env->eip = 0xfff0;
+    env->regs[R_EDX] = env->cpuid_version;
+
+    env->eflags = 0x2;
+
+    /* FPU init */
+    for(i = 0;i < 8; i++)
+        env->fptags[i] = 1;
+    env->fpuc = 0x37f;
+
+    env->mxcsr = 0x1f80;
+
+    env->pat = 0x0007040600070406ULL;
+
+    memset(env->dr, 0, sizeof(env->dr));
+    env->dr[6] = DR6_FIXED_1;
+    env->dr[7] = DR7_FIXED_1;
+    cpu_breakpoint_remove_all(env, BP_CPU);
+    cpu_watchpoint_remove_all(env, BP_CPU);
+}
+
+void cpu_x86_close(CPUX86State *env)
+{
+    qemu_free(env);
+}
+
+static void cpu_x86_version(CPUState *env, int *family, int *model)
+{
+    int cpuver = env->cpuid_version;
+
+    if (family == NULL || model == NULL) {
+        return;
+    }
+
+    *family = (cpuver >> 8) & 0x0f;
+    *model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
+}
+
+/* Broadcast MCA signal for processor version 06H_EH and above */
+int cpu_x86_support_mca_broadcast(CPUState *env)
+{
+    int family = 0;
+    int model = 0;
+
+    cpu_x86_version(env, &family, &model);
+    if ((family == 6 && model >= 14) || family > 6) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/***********************************************************/
+/* x86 debug */
+
+static const char *cc_op_str[] = {
+    "DYNAMIC",
+    "EFLAGS",
+
+    "MULB",
+    "MULW",
+    "MULL",
+    "MULQ",
+
+    "ADDB",
+    "ADDW",
+    "ADDL",
+    "ADDQ",
+
+    "ADCB",
+    "ADCW",
+    "ADCL",
+    "ADCQ",
+
+    "SUBB",
+    "SUBW",
+    "SUBL",
+    "SUBQ",
+
+    "SBBB",
+    "SBBW",
+    "SBBL",
+    "SBBQ",
+
+    "LOGICB",
+    "LOGICW",
+    "LOGICL",
+    "LOGICQ",
+
+    "INCB",
+    "INCW",
+    "INCL",
+    "INCQ",
+
+    "DECB",
+    "DECW",
+    "DECL",
+    "DECQ",
+
+    "SHLB",
+    "SHLW",
+    "SHLL",
+    "SHLQ",
+
+    "SARB",
+    "SARW",
+    "SARL",
+    "SARQ",
+};
+
+static void
+cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                       const char *name, struct SegmentCache *sc)
+{
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_CS64_MASK) {
+        cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
+                    sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00);
+    } else
+#endif
+    {
+        cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
+                    (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00);
+    }
+
+    if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
+        goto done;
+
+    cpu_fprintf(f, " DPL=%d ", (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
+    if (sc->flags & DESC_S_MASK) {
+        if (sc->flags & DESC_CS_MASK) {
+            cpu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
+                           ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
+            cpu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
+                        (sc->flags & DESC_R_MASK) ? 'R' : '-');
+        } else {
+            cpu_fprintf(f, (sc->flags & DESC_B_MASK) ? "DS  " : "DS16");
+            cpu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
+                        (sc->flags & DESC_W_MASK) ? 'W' : '-');
+        }
+        cpu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
+    } else {
+        static const char *sys_type_name[2][16] = {
+            { /* 32 bit mode */
+                "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
+                "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
+                "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
+                "CallGate32", "Reserved", "IntGate32", "TrapGate32"
+            },
+            { /* 64 bit mode */
+                "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
+                "Reserved", "Reserved", "Reserved", "Reserved",
+                "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
+                "Reserved", "IntGate64", "TrapGate64"
+            }
+        };
+        cpu_fprintf(f, "%s",
+                    sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
+                                 [(sc->flags & DESC_TYPE_MASK)
+                                  >> DESC_TYPE_SHIFT]);
+    }
+done:
+    cpu_fprintf(f, "\n");
+}
+
+#define DUMP_CODE_BYTES_TOTAL    50
+#define DUMP_CODE_BYTES_BACKWARD 20
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int eflags, i, nb;
+    char cc_op_name[32];
+    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+    cpu_synchronize_state(env);
+
+    eflags = env->eflags;
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_CS64_MASK) {
+        cpu_fprintf(f,
+                    "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
+                    "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
+                    "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
+                    "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
+                    "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
+                    env->regs[R_EAX],
+                    env->regs[R_EBX],
+                    env->regs[R_ECX],
+                    env->regs[R_EDX],
+                    env->regs[R_ESI],
+                    env->regs[R_EDI],
+                    env->regs[R_EBP],
+                    env->regs[R_ESP],
+                    env->regs[8],
+                    env->regs[9],
+                    env->regs[10],
+                    env->regs[11],
+                    env->regs[12],
+                    env->regs[13],
+                    env->regs[14],
+                    env->regs[15],
+                    env->eip, eflags,
+                    eflags & DF_MASK ? 'D' : '-',
+                    eflags & CC_O ? 'O' : '-',
+                    eflags & CC_S ? 'S' : '-',
+                    eflags & CC_Z ? 'Z' : '-',
+                    eflags & CC_A ? 'A' : '-',
+                    eflags & CC_P ? 'P' : '-',
+                    eflags & CC_C ? 'C' : '-',
+                    env->hflags & HF_CPL_MASK,
+                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
+                    (env->a20_mask >> 20) & 1,
+                    (env->hflags >> HF_SMM_SHIFT) & 1,
+                    env->halted);
+    } else
+#endif
+    {
+        cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
+                    "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
+                    "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
+                    (uint32_t)env->regs[R_EAX],
+                    (uint32_t)env->regs[R_EBX],
+                    (uint32_t)env->regs[R_ECX],
+                    (uint32_t)env->regs[R_EDX],
+                    (uint32_t)env->regs[R_ESI],
+                    (uint32_t)env->regs[R_EDI],
+                    (uint32_t)env->regs[R_EBP],
+                    (uint32_t)env->regs[R_ESP],
+                    (uint32_t)env->eip, eflags,
+                    eflags & DF_MASK ? 'D' : '-',
+                    eflags & CC_O ? 'O' : '-',
+                    eflags & CC_S ? 'S' : '-',
+                    eflags & CC_Z ? 'Z' : '-',
+                    eflags & CC_A ? 'A' : '-',
+                    eflags & CC_P ? 'P' : '-',
+                    eflags & CC_C ? 'C' : '-',
+                    env->hflags & HF_CPL_MASK,
+                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
+                    (env->a20_mask >> 20) & 1,
+                    (env->hflags >> HF_SMM_SHIFT) & 1,
+                    env->halted);
+    }
+
+    for(i = 0; i < 6; i++) {
+        cpu_x86_dump_seg_cache(env, f, cpu_fprintf, seg_name[i],
+                               &env->segs[i]);
+    }
+    cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "LDT", &env->ldt);
+    cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "TR", &env->tr);
+
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_LMA_MASK) {
+        cpu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
+                    env->gdt.base, env->gdt.limit);
+        cpu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
+                    env->idt.base, env->idt.limit);
+        cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
+                    (uint32_t)env->cr[0],
+                    env->cr[2],
+                    env->cr[3],
+                    (uint32_t)env->cr[4]);
+        for(i = 0; i < 4; i++)
+            cpu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
+        cpu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
+                    env->dr[6], env->dr[7]);
+    } else
+#endif
+    {
+        cpu_fprintf(f, "GDT=     %08x %08x\n",
+                    (uint32_t)env->gdt.base, env->gdt.limit);
+        cpu_fprintf(f, "IDT=     %08x %08x\n",
+                    (uint32_t)env->idt.base, env->idt.limit);
+        cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
+                    (uint32_t)env->cr[0],
+                    (uint32_t)env->cr[2],
+                    (uint32_t)env->cr[3],
+                    (uint32_t)env->cr[4]);
+        for(i = 0; i < 4; i++) {
+            cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
+        }
+        cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
+                    env->dr[6], env->dr[7]);
+    }
+    if (flags & X86_DUMP_CCOP) {
+        if ((unsigned)env->cc_op < CC_OP_NB)
+            snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
+        else
+            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_CS64_MASK) {
+            cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
+                        env->cc_src, env->cc_dst,
+                        cc_op_name);
+        } else
+#endif
+        {
+            cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
+                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
+                        cc_op_name);
+        }
+    }
+    cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
+    if (flags & X86_DUMP_FPU) {
+        int fptag;
+        fptag = 0;
+        for(i = 0; i < 8; i++) {
+            fptag |= ((!env->fptags[i]) << i);
+        }
+        cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
+                    env->fpuc,
+                    (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
+                    env->fpstt,
+                    fptag,
+                    env->mxcsr);
+        for(i=0;i<8;i++) {
+            CPU_LDoubleU u;
+            u.d = env->fpregs[i].d;
+            cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
+                        i, u.l.lower, u.l.upper);
+            if ((i & 1) == 1)
+                cpu_fprintf(f, "\n");
+            else
+                cpu_fprintf(f, " ");
+        }
+        if (env->hflags & HF_CS64_MASK)
+            nb = 16;
+        else
+            nb = 8;
+        for(i=0;i<nb;i++) {
+            cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
+                        i,
+                        env->xmm_regs[i].XMM_L(3),
+                        env->xmm_regs[i].XMM_L(2),
+                        env->xmm_regs[i].XMM_L(1),
+                        env->xmm_regs[i].XMM_L(0));
+            if ((i & 1) == 1)
+                cpu_fprintf(f, "\n");
+            else
+                cpu_fprintf(f, " ");
+        }
+    }
+    if (flags & CPU_DUMP_CODE) {
+        target_ulong base = env->segs[R_CS].base + env->eip;
+        target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
+        uint8_t code;
+        char codestr[3];
+
+        cpu_fprintf(f, "Code=");
+        for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
+            if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
+                snprintf(codestr, sizeof(codestr), "%02x", code);
+            } else {
+                snprintf(codestr, sizeof(codestr), "??");
+            }
+            cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
+                        i == offs ? "<" : "", codestr, i == offs ? ">" : "");
+        }
+        cpu_fprintf(f, "\n");
+    }
+}
+
+/***********************************************************/
+/* x86 mmu */
+/* XXX: add PGE support */
+
+void cpu_x86_set_a20(CPUX86State *env, int a20_state)
+{
+    a20_state = (a20_state != 0);
+    if (a20_state != ((env->a20_mask >> 20) & 1)) {
+#if defined(DEBUG_MMU)
+        printf("A20 update: a20=%d\n", a20_state);
+#endif
+        /* if the cpu is currently executing code, we must unlink it and
+           all the potentially executing TB */
+        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
+
+        /* when a20 is changed, all the MMU mappings are invalid, so
+           we must flush everything */
+        tlb_flush(env, 1);
+        env->a20_mask = ~(1 << 20) | (a20_state << 20);
+    }
+}
+
+void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
+{
+    int pe_state;
+
+#if defined(DEBUG_MMU)
+    printf("CR0 update: CR0=0x%08x\n", new_cr0);
+#endif
+    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
+        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
+        tlb_flush(env, 1);
+    }
+
+#ifdef TARGET_X86_64
+    if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
+        (env->efer & MSR_EFER_LME)) {
+        /* enter in long mode */
+        /* XXX: generate an exception */
+        if (!(env->cr[4] & CR4_PAE_MASK))
+            return;
+        env->efer |= MSR_EFER_LMA;
+        env->hflags |= HF_LMA_MASK;
+    } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
+               (env->efer & MSR_EFER_LMA)) {
+        /* exit long mode */
+        env->efer &= ~MSR_EFER_LMA;
+        env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
+        env->eip &= 0xffffffff;
+    }
+#endif
+    env->cr[0] = new_cr0 | CR0_ET_MASK;
+
+    /* update PE flag in hidden flags */
+    pe_state = (env->cr[0] & CR0_PE_MASK);
+    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
+    /* ensure that ADDSEG is always set in real mode */
+    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
+    /* update FPU flags */
+    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
+        ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
+}
+
+/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
+   the PDPT */
+void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
+{
+    env->cr[3] = new_cr3;
+    if (env->cr[0] & CR0_PG_MASK) {
+#if defined(DEBUG_MMU)
+        printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
+#endif
+        tlb_flush(env, 0);
+    }
+}
+
+void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
+{
+#if defined(DEBUG_MMU)
+    printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
+#endif
+    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
+        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
+        tlb_flush(env, 1);
+    }
+    /* SSE handling */
+    if (!(env->cpuid_features & CPUID_SSE))
+        new_cr4 &= ~CR4_OSFXSR_MASK;
+    if (new_cr4 & CR4_OSFXSR_MASK)
+        env->hflags |= HF_OSFXSR_MASK;
+    else
+        env->hflags &= ~HF_OSFXSR_MASK;
+
+    env->cr[4] = new_cr4;
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+                             int is_write, int mmu_idx, int is_softmmu)
+{
+    /* user mode only emulation */
+    is_write &= 1;
+    env->cr[2] = addr;
+    env->error_code = (is_write << PG_ERROR_W_BIT);
+    env->error_code |= PG_ERROR_U_MASK;
+    env->exception_index = EXCP0E_PAGE;
+    return 1;
+}
+
+#else
+
+/* XXX: This value should match the one returned by CPUID
+ * and in exec.c */
+# if defined(TARGET_X86_64)
+# define PHYS_ADDR_MASK 0xfffffff000LL
+# else
+# define PHYS_ADDR_MASK 0xffffff000LL
+# endif
+
+/* return value:
+   -1 = cannot handle fault
+   0  = nothing more to do
+   1  = generate PF fault
+*/
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+                             int is_write1, int mmu_idx, int is_softmmu)
+{
+    uint64_t ptep, pte;
+    target_ulong pde_addr, pte_addr;
+    int error_code, is_dirty, prot, page_size, is_write, is_user;
+    target_phys_addr_t paddr;
+    uint32_t page_offset;
+    target_ulong vaddr, virt_addr;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+#if defined(DEBUG_MMU)
+    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
+           addr, is_write1, is_user, env->eip);
+#endif
+    is_write = is_write1 & 1;
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        pte = addr;
+        virt_addr = addr & TARGET_PAGE_MASK;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        page_size = 4096;
+        goto do_mapping;
+    }
+
+    if (env->cr[4] & CR4_PAE_MASK) {
+        uint64_t pde, pdpe;
+        target_ulong pdpe_addr;
+
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint64_t pml4e_addr, pml4e;
+            int32_t sext;
+
+            /* test virtual address sign extension */
+            sext = (int64_t)addr >> 47;
+            if (sext != 0 && sext != -1) {
+                env->error_code = 0;
+                env->exception_index = EXCP0D_GPF;
+                return 1;
+            }
+
+            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
+                env->a20_mask;
+            pml4e = ldq_phys(pml4e_addr);
+            if (!(pml4e & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
+            if (!(pml4e & PG_ACCESSED_MASK)) {
+                pml4e |= PG_ACCESSED_MASK;
+                stl_phys_notdirty(pml4e_addr, pml4e);
+            }
+            ptep = pml4e ^ PG_NX_MASK;
+            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
+                env->a20_mask;
+            pdpe = ldq_phys(pdpe_addr);
+            if (!(pdpe & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
+            ptep &= pdpe ^ PG_NX_MASK;
+            if (!(pdpe & PG_ACCESSED_MASK)) {
+                pdpe |= PG_ACCESSED_MASK;
+                stl_phys_notdirty(pdpe_addr, pdpe);
+            }
+        } else
+#endif
+        {
+            /* XXX: load them when cr3 is loaded ? */
+            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
+                env->a20_mask;
+            pdpe = ldq_phys(pdpe_addr);
+            if (!(pdpe & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
+        }
+
+        pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
+            env->a20_mask;
+        pde = ldq_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            error_code = 0;
+            goto do_fault;
+        }
+        if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
+            error_code = PG_ERROR_RSVD_MASK;
+            goto do_fault;
+        }
+        ptep &= pde ^ PG_NX_MASK;
+        if (pde & PG_PSE_MASK) {
+            /* 2 MB page */
+            page_size = 2048 * 1024;
+            ptep ^= PG_NX_MASK;
+            if ((ptep & PG_NX_MASK) && is_write1 == 2)
+                goto do_fault_protect;
+            if (is_user) {
+                if (!(ptep & PG_USER_MASK))
+                    goto do_fault_protect;
+                if (is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            } else {
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pde & PG_DIRTY_MASK);
+            if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+                pde |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pde |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pde_addr, pde);
+            }
+            /* align to page_size */
+            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
+            virt_addr = addr & ~(page_size - 1);
+        } else {
+            /* 4 KB page */
+            if (!(pde & PG_ACCESSED_MASK)) {
+                pde |= PG_ACCESSED_MASK;
+                stl_phys_notdirty(pde_addr, pde);
+            }
+            pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
+                env->a20_mask;
+            pte = ldq_phys(pte_addr);
+            if (!(pte & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
+            /* combine pde and pte nx, user and rw protections */
+            ptep &= pte ^ PG_NX_MASK;
+            ptep ^= PG_NX_MASK;
+            if ((ptep & PG_NX_MASK) && is_write1 == 2)
+                goto do_fault_protect;
+            if (is_user) {
+                if (!(ptep & PG_USER_MASK))
+                    goto do_fault_protect;
+                if (is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            } else {
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pte & PG_DIRTY_MASK);
+            if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
+                pte |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pte |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pte_addr, pte);
+            }
+            page_size = 4096;
+            virt_addr = addr & ~0xfff;
+            pte = pte & (PHYS_ADDR_MASK | 0xfff);
+        }
+    } else {
+        uint32_t pde;
+
+        /* page directory entry */
+        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
+            env->a20_mask;
+        pde = ldl_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            error_code = 0;
+            goto do_fault;
+        }
+        /* if PSE bit is set, then we use a 4MB page */
+        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+            page_size = 4096 * 1024;
+            if (is_user) {
+                if (!(pde & PG_USER_MASK))
+                    goto do_fault_protect;
+                if (is_write && !(pde & PG_RW_MASK))
+                    goto do_fault_protect;
+            } else {
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(pde & PG_RW_MASK))
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pde & PG_DIRTY_MASK);
+            if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+                pde |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pde |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pde_addr, pde);
+            }
+
+            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
+            ptep = pte;
+            virt_addr = addr & ~(page_size - 1);
+        } else {
+            if (!(pde & PG_ACCESSED_MASK)) {
+                pde |= PG_ACCESSED_MASK;
+                stl_phys_notdirty(pde_addr, pde);
+            }
+
+            /* page directory entry */
+            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
+                env->a20_mask;
+            pte = ldl_phys(pte_addr);
+            if (!(pte & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            /* combine pde and pte user and rw protections */
+            ptep = pte & pde;
+            if (is_user) {
+                if (!(ptep & PG_USER_MASK))
+                    goto do_fault_protect;
+                if (is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            } else {
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(ptep & PG_RW_MASK))
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pte & PG_DIRTY_MASK);
+            if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
+                pte |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pte |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pte_addr, pte);
+            }
+            page_size = 4096;
+            virt_addr = addr & ~0xfff;
+        }
+    }
+    /* the page can be put in the TLB */
+    prot = PAGE_READ;
+    if (!(ptep & PG_NX_MASK))
+        prot |= PAGE_EXEC;
+    if (pte & PG_DIRTY_MASK) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        if (is_user) {
+            if (ptep & PG_RW_MASK)
+                prot |= PAGE_WRITE;
+        } else {
+            if (!(env->cr[0] & CR0_WP_MASK) ||
+                (ptep & PG_RW_MASK))
+                prot |= PAGE_WRITE;
+        }
+    }
+ do_mapping:
+    pte = pte & env->a20_mask;
+
+    /* Even if 4MB pages, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
+    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+    vaddr = virt_addr + page_offset;
+
+    tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+    return 0;
+ do_fault_protect:
+    error_code = PG_ERROR_P_MASK;
+ do_fault:
+    error_code |= (is_write << PG_ERROR_W_BIT);
+    if (is_user)
+        error_code |= PG_ERROR_U_MASK;
+    if (is_write1 == 2 &&
+        (env->efer & MSR_EFER_NXE) &&
+        (env->cr[4] & CR4_PAE_MASK))
+        error_code |= PG_ERROR_I_D_MASK;
+    if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
+        /* cr2 is not modified in case of exceptions */
+        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 
+                 addr);
+    } else {
+        env->cr[2] = addr;
+    }
+    env->error_code = error_code;
+    env->exception_index = EXCP0E_PAGE;
+    return 1;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_ulong pde_addr, pte_addr;
+    uint64_t pte;
+    target_phys_addr_t paddr;
+    uint32_t page_offset;
+    int page_size;
+
+    if (env->cr[4] & CR4_PAE_MASK) {
+        target_ulong pdpe_addr;
+        uint64_t pde, pdpe;
+
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint64_t pml4e_addr, pml4e;
+            int32_t sext;
+
+            /* test virtual address sign extension */
+            sext = (int64_t)addr >> 47;
+            if (sext != 0 && sext != -1)
+                return -1;
+
+            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
+                env->a20_mask;
+            pml4e = ldq_phys(pml4e_addr);
+            if (!(pml4e & PG_PRESENT_MASK))
+                return -1;
+
+            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
+                env->a20_mask;
+            pdpe = ldq_phys(pdpe_addr);
+            if (!(pdpe & PG_PRESENT_MASK))
+                return -1;
+        } else
+#endif
+        {
+            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
+                env->a20_mask;
+            pdpe = ldq_phys(pdpe_addr);
+            if (!(pdpe & PG_PRESENT_MASK))
+                return -1;
+        }
+
+        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
+            env->a20_mask;
+        pde = ldq_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            return -1;
+        }
+        if (pde & PG_PSE_MASK) {
+            /* 2 MB page */
+            page_size = 2048 * 1024;
+            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
+        } else {
+            /* 4 KB page */
+            pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
+                env->a20_mask;
+            page_size = 4096;
+            pte = ldq_phys(pte_addr);
+        }
+        if (!(pte & PG_PRESENT_MASK))
+            return -1;
+    } else {
+        uint32_t pde;
+
+        if (!(env->cr[0] & CR0_PG_MASK)) {
+            pte = addr;
+            page_size = 4096;
+        } else {
+            /* page directory entry */
+            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
+            pde = ldl_phys(pde_addr);
+            if (!(pde & PG_PRESENT_MASK))
+                return -1;
+            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+                pte = pde & ~0x003ff000; /* align to 4MB */
+                page_size = 4096 * 1024;
+            } else {
+                /* page directory entry */
+                pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
+                pte = ldl_phys(pte_addr);
+                if (!(pte & PG_PRESENT_MASK))
+                    return -1;
+                page_size = 4096;
+            }
+        }
+        pte = pte & env->a20_mask;
+    }
+
+    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
+    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+    return paddr;
+}
+
+void hw_breakpoint_insert(CPUState *env, int index)
+{
+    int type, err = 0;
+
+    switch (hw_breakpoint_type(env->dr[7], index)) {
+    case 0:
+        if (hw_breakpoint_enabled(env->dr[7], index))
+            err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
+                                        &env->cpu_breakpoint[index]);
+        break;
+    case 1:
+        type = BP_CPU | BP_MEM_WRITE;
+        goto insert_wp;
+    case 2:
+         /* No support for I/O watchpoints yet */
+        break;
+    case 3:
+        type = BP_CPU | BP_MEM_ACCESS;
+    insert_wp:
+        err = cpu_watchpoint_insert(env, env->dr[index],
+                                    hw_breakpoint_len(env->dr[7], index),
+                                    type, &env->cpu_watchpoint[index]);
+        break;
+    }
+    if (err)
+        env->cpu_breakpoint[index] = NULL;
+}
+
+void hw_breakpoint_remove(CPUState *env, int index)
+{
+    if (!env->cpu_breakpoint[index])
+        return;
+    switch (hw_breakpoint_type(env->dr[7], index)) {
+    case 0:
+        if (hw_breakpoint_enabled(env->dr[7], index))
+            cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
+        break;
+    case 1:
+    case 3:
+        cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
+        break;
+    case 2:
+        /* No support for I/O watchpoints yet */
+        break;
+    }
+}
+
+int check_hw_breakpoints(CPUState *env, int force_dr6_update)
+{
+    target_ulong dr6;
+    int reg, type;
+    int hit_enabled = 0;
+
+    dr6 = env->dr[6] & ~0xf;
+    for (reg = 0; reg < 4; reg++) {
+        type = hw_breakpoint_type(env->dr[7], reg);
+        if ((type == 0 && env->dr[reg] == env->eip) ||
+            ((type & 1) && env->cpu_watchpoint[reg] &&
+             (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) {
+            dr6 |= 1 << reg;
+            if (hw_breakpoint_enabled(env->dr[7], reg))
+                hit_enabled = 1;
+        }
+    }
+    if (hit_enabled || force_dr6_update)
+        env->dr[6] = dr6;
+    return hit_enabled;
+}
+
+static CPUDebugExcpHandler *prev_debug_excp_handler;
+
+void raise_exception_env(int exception_index, CPUState *env);
+
+static void breakpoint_handler(CPUState *env)
+{
+    CPUBreakpoint *bp;
+
+    if (env->watchpoint_hit) {
+        if (env->watchpoint_hit->flags & BP_CPU) {
+            env->watchpoint_hit = NULL;
+            if (check_hw_breakpoints(env, 0))
+                raise_exception_env(EXCP01_DB, env);
+            else
+                cpu_resume_from_signal(env, NULL);
+        }
+    } else {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry)
+            if (bp->pc == env->eip) {
+                if (bp->flags & BP_CPU) {
+                    check_hw_breakpoints(env, 1);
+                    raise_exception_env(EXCP01_DB, env);
+                }
+                break;
+            }
+    }
+    if (prev_debug_excp_handler)
+        prev_debug_excp_handler(env);
+}
+
+typedef struct MCEInjectionParams {
+    Monitor *mon;
+    CPUState *env;
+    int bank;
+    uint64_t status;
+    uint64_t mcg_status;
+    uint64_t addr;
+    uint64_t misc;
+    int flags;
+} MCEInjectionParams;
+
+static void do_inject_x86_mce(void *data)
+{
+    MCEInjectionParams *params = data;
+    CPUState *cenv = params->env;
+    uint64_t *banks = cenv->mce_banks + 4 * params->bank;
+
+    cpu_synchronize_state(cenv);
+
+    /*
+     * If there is an MCE exception being processed, ignore this SRAO MCE
+     * unless unconditional injection was requested.
+     */
+    if (!(params->flags & MCE_INJECT_UNCOND_AO)
+        && !(params->status & MCI_STATUS_AR)
+        && (cenv->mcg_status & MCG_STATUS_MCIP)) {
+        return;
+    }
+
+    if (params->status & MCI_STATUS_UC) {
+        /*
+         * if MSR_MCG_CTL is not all 1s, the uncorrected error
+         * reporting is disabled
+         */
+        if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
+            monitor_printf(params->mon,
+                           "CPU %d: Uncorrected error reporting disabled\n",
+                           cenv->cpu_index);
+            return;
+        }
+
+        /*
+         * if MSR_MCi_CTL is not all 1s, the uncorrected error
+         * reporting is disabled for the bank
+         */
+        if (banks[0] != ~(uint64_t)0) {
+            monitor_printf(params->mon,
+                           "CPU %d: Uncorrected error reporting disabled for"
+                           " bank %d\n",
+                           cenv->cpu_index, params->bank);
+            return;
+        }
+
+        if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
+            !(cenv->cr[4] & CR4_MCE_MASK)) {
+            monitor_printf(params->mon,
+                           "CPU %d: Previous MCE still in progress, raising"
+                           " triple fault\n",
+                           cenv->cpu_index);
+            qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
+            qemu_system_reset_request();
+            return;
+        }
+        if (banks[1] & MCI_STATUS_VAL) {
+            params->status |= MCI_STATUS_OVER;
+        }
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        cenv->mcg_status = params->mcg_status;
+        banks[1] = params->status;
+        cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
+    } else if (!(banks[1] & MCI_STATUS_VAL)
+               || !(banks[1] & MCI_STATUS_UC)) {
+        if (banks[1] & MCI_STATUS_VAL) {
+            params->status |= MCI_STATUS_OVER;
+        }
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        banks[1] = params->status;
+    } else {
+        banks[1] |= MCI_STATUS_OVER;
+    }
+}
+
+void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
+                        uint64_t status, uint64_t mcg_status, uint64_t addr,
+                        uint64_t misc, int flags)
+{
+    MCEInjectionParams params = {
+        .mon = mon,
+        .env = cenv,
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+        .flags = flags,
+    };
+    unsigned bank_num = cenv->mcg_cap & 0xff;
+    CPUState *env;
+
+    if (!cenv->mcg_cap) {
+        monitor_printf(mon, "MCE injection not supported\n");
+        return;
+    }
+    if (bank >= bank_num) {
+        monitor_printf(mon, "Invalid MCE bank number\n");
+        return;
+    }
+    if (!(status & MCI_STATUS_VAL)) {
+        monitor_printf(mon, "Invalid MCE status code\n");
+        return;
+    }
+    if ((flags & MCE_INJECT_BROADCAST)
+        && !cpu_x86_support_mca_broadcast(cenv)) {
+        monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
+        return;
+    }
+
+    run_on_cpu(cenv, do_inject_x86_mce, &params);
+    if (flags & MCE_INJECT_BROADCAST) {
+        params.bank = 1;
+        params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
+        params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        params.addr = 0;
+        params.misc = 0;
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (cenv == env) {
+                continue;
+            }
+            params.env = env;
+            run_on_cpu(cenv, do_inject_x86_mce, &params);
+        }
+    }
+}
+#endif /* !CONFIG_USER_ONLY */
+
+static void mce_init(CPUX86State *cenv)
+{
+    unsigned int bank;
+
+    if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+        && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
+            (CPUID_MCE | CPUID_MCA)) {
+        cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
+        cenv->mcg_ctl = ~(uint64_t)0;
+        for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
+            cenv->mce_banks[bank * 4] = ~(uint64_t)0;
+        }
+    }
+}
+
+int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
+                            target_ulong *base, unsigned int *limit,
+                            unsigned int *flags)
+{
+    SegmentCache *dt;
+    target_ulong ptr;
+    uint32_t e1, e2;
+    int index;
+
+    if (selector & 0x4)
+        dt = &env->ldt;
+    else
+        dt = &env->gdt;
+    index = selector & ~7;
+    ptr = dt->base + index;
+    if ((index + 7) > dt->limit
+        || cpu_memory_rw_debug(env, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
+        || cpu_memory_rw_debug(env, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
+        return 0;
+
+    *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+    *limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+    if (e2 & DESC_G_MASK)
+        *limit = (*limit << 12) | 0xfff;
+    *flags = e2;
+
+    return 1;
+}
+
+CPUX86State *cpu_x86_init(const char *cpu_model)
+{
+    CPUX86State *env;
+    static int inited;
+
+    env = qemu_mallocz(sizeof(CPUX86State));
+    cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+        optimize_flags_init();
+#ifndef CONFIG_USER_ONLY
+        prev_debug_excp_handler =
+            cpu_set_debug_excp_handler(breakpoint_handler);
+#endif
+    }
+    if (cpu_x86_register(env, cpu_model) < 0) {
+        cpu_x86_close(env);
+        return NULL;
+    }
+    mce_init(env);
+
+    qemu_init_vcpu(env);
+
+    return env;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void do_cpu_init(CPUState *env)
+{
+    int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
+    uint64_t pat = env->pat;
+
+    cpu_reset(env);
+    env->interrupt_request = sipi;
+    env->pat = pat;
+    apic_init_reset(env->apic_state);
+    env->halted = !cpu_is_bsp(env);
+}
+
+void do_cpu_sipi(CPUState *env)
+{
+    apic_sipi(env->apic_state);
+}
+#else
+void do_cpu_init(CPUState *env)
+{
+}
+void do_cpu_sipi(CPUState *env)
+{
+}
+#endif
diff --git a/qemu-0.15.x/target-i386/helper.h b/qemu-0.15.x/target-i386/helper.h
new file mode 100644
index 0000000..6b518ad
--- /dev/null
+++ b/qemu-0.15.x/target-i386/helper.h
@@ -0,0 +1,220 @@
+#include "def-helper.h"
+
+DEF_HELPER_FLAGS_1(cc_compute_all, TCG_CALL_PURE, i32, int)
+DEF_HELPER_FLAGS_1(cc_compute_c, TCG_CALL_PURE, i32, int)
+
+DEF_HELPER_0(lock, void)
+DEF_HELPER_0(unlock, void)
+DEF_HELPER_2(write_eflags, void, tl, i32)
+DEF_HELPER_0(read_eflags, tl)
+DEF_HELPER_1(divb_AL, void, tl)
+DEF_HELPER_1(idivb_AL, void, tl)
+DEF_HELPER_1(divw_AX, void, tl)
+DEF_HELPER_1(idivw_AX, void, tl)
+DEF_HELPER_1(divl_EAX, void, tl)
+DEF_HELPER_1(idivl_EAX, void, tl)
+#ifdef TARGET_X86_64
+DEF_HELPER_1(mulq_EAX_T0, void, tl)
+DEF_HELPER_1(imulq_EAX_T0, void, tl)
+DEF_HELPER_2(imulq_T0_T1, tl, tl, tl)
+DEF_HELPER_1(divq_EAX, void, tl)
+DEF_HELPER_1(idivq_EAX, void, tl)
+#endif
+
+DEF_HELPER_1(aam, void, int)
+DEF_HELPER_1(aad, void, int)
+DEF_HELPER_0(aaa, void)
+DEF_HELPER_0(aas, void)
+DEF_HELPER_0(daa, void)
+DEF_HELPER_0(das, void)
+
+DEF_HELPER_1(lsl, tl, tl)
+DEF_HELPER_1(lar, tl, tl)
+DEF_HELPER_1(verr, void, tl)
+DEF_HELPER_1(verw, void, tl)
+DEF_HELPER_1(lldt, void, int)
+DEF_HELPER_1(ltr, void, int)
+DEF_HELPER_2(load_seg, void, int, int)
+DEF_HELPER_3(ljmp_protected, void, int, tl, int)
+DEF_HELPER_4(lcall_real, void, int, tl, int, int)
+DEF_HELPER_4(lcall_protected, void, int, tl, int, int)
+DEF_HELPER_1(iret_real, void, int)
+DEF_HELPER_2(iret_protected, void, int, int)
+DEF_HELPER_2(lret_protected, void, int, int)
+DEF_HELPER_1(read_crN, tl, int)
+DEF_HELPER_2(write_crN, void, int, tl)
+DEF_HELPER_1(lmsw, void, tl)
+DEF_HELPER_0(clts, void)
+DEF_HELPER_2(movl_drN_T0, void, int, tl)
+DEF_HELPER_1(invlpg, void, tl)
+
+DEF_HELPER_3(enter_level, void, int, int, tl)
+#ifdef TARGET_X86_64
+DEF_HELPER_3(enter64_level, void, int, int, tl)
+#endif
+DEF_HELPER_0(sysenter, void)
+DEF_HELPER_1(sysexit, void, int)
+#ifdef TARGET_X86_64
+DEF_HELPER_1(syscall, void, int)
+DEF_HELPER_1(sysret, void, int)
+#endif
+DEF_HELPER_1(hlt, void, int)
+DEF_HELPER_1(monitor, void, tl)
+DEF_HELPER_1(mwait, void, int)
+DEF_HELPER_0(debug, void)
+DEF_HELPER_0(reset_rf, void)
+DEF_HELPER_2(raise_interrupt, void, int, int)
+DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_0(cli, void)
+DEF_HELPER_0(sti, void)
+DEF_HELPER_0(set_inhibit_irq, void)
+DEF_HELPER_0(reset_inhibit_irq, void)
+DEF_HELPER_2(boundw, void, tl, int)
+DEF_HELPER_2(boundl, void, tl, int)
+DEF_HELPER_0(rsm, void)
+DEF_HELPER_1(into, void, int)
+DEF_HELPER_1(cmpxchg8b, void, tl)
+#ifdef TARGET_X86_64
+DEF_HELPER_1(cmpxchg16b, void, tl)
+#endif
+DEF_HELPER_0(single_step, void)
+DEF_HELPER_0(cpuid, void)
+DEF_HELPER_0(rdtsc, void)
+DEF_HELPER_0(rdtscp, void)
+DEF_HELPER_0(rdpmc, void)
+DEF_HELPER_0(rdmsr, void)
+DEF_HELPER_0(wrmsr, void)
+
+DEF_HELPER_1(check_iob, void, i32)
+DEF_HELPER_1(check_iow, void, i32)
+DEF_HELPER_1(check_iol, void, i32)
+DEF_HELPER_2(outb, void, i32, i32)
+DEF_HELPER_1(inb, tl, i32)
+DEF_HELPER_2(outw, void, i32, i32)
+DEF_HELPER_1(inw, tl, i32)
+DEF_HELPER_2(outl, void, i32, i32)
+DEF_HELPER_1(inl, tl, i32)
+
+DEF_HELPER_2(svm_check_intercept_param, void, i32, i64)
+DEF_HELPER_2(vmexit, void, i32, i64)
+DEF_HELPER_3(svm_check_io, void, i32, i32, i32)
+DEF_HELPER_2(vmrun, void, int, int)
+DEF_HELPER_0(vmmcall, void)
+DEF_HELPER_1(vmload, void, int)
+DEF_HELPER_1(vmsave, void, int)
+DEF_HELPER_0(stgi, void)
+DEF_HELPER_0(clgi, void)
+DEF_HELPER_0(skinit, void)
+DEF_HELPER_1(invlpga, void, int)
+
+/* x86 FPU */
+
+DEF_HELPER_1(flds_FT0, void, i32)
+DEF_HELPER_1(fldl_FT0, void, i64)
+DEF_HELPER_1(fildl_FT0, void, s32)
+DEF_HELPER_1(flds_ST0, void, i32)
+DEF_HELPER_1(fldl_ST0, void, i64)
+DEF_HELPER_1(fildl_ST0, void, s32)
+DEF_HELPER_1(fildll_ST0, void, s64)
+DEF_HELPER_0(fsts_ST0, i32)
+DEF_HELPER_0(fstl_ST0, i64)
+DEF_HELPER_0(fist_ST0, s32)
+DEF_HELPER_0(fistl_ST0, s32)
+DEF_HELPER_0(fistll_ST0, s64)
+DEF_HELPER_0(fistt_ST0, s32)
+DEF_HELPER_0(fisttl_ST0, s32)
+DEF_HELPER_0(fisttll_ST0, s64)
+DEF_HELPER_1(fldt_ST0, void, tl)
+DEF_HELPER_1(fstt_ST0, void, tl)
+DEF_HELPER_0(fpush, void)
+DEF_HELPER_0(fpop, void)
+DEF_HELPER_0(fdecstp, void)
+DEF_HELPER_0(fincstp, void)
+DEF_HELPER_1(ffree_STN, void, int)
+DEF_HELPER_0(fmov_ST0_FT0, void)
+DEF_HELPER_1(fmov_FT0_STN, void, int)
+DEF_HELPER_1(fmov_ST0_STN, void, int)
+DEF_HELPER_1(fmov_STN_ST0, void, int)
+DEF_HELPER_1(fxchg_ST0_STN, void, int)
+DEF_HELPER_0(fcom_ST0_FT0, void)
+DEF_HELPER_0(fucom_ST0_FT0, void)
+DEF_HELPER_0(fcomi_ST0_FT0, void)
+DEF_HELPER_0(fucomi_ST0_FT0, void)
+DEF_HELPER_0(fadd_ST0_FT0, void)
+DEF_HELPER_0(fmul_ST0_FT0, void)
+DEF_HELPER_0(fsub_ST0_FT0, void)
+DEF_HELPER_0(fsubr_ST0_FT0, void)
+DEF_HELPER_0(fdiv_ST0_FT0, void)
+DEF_HELPER_0(fdivr_ST0_FT0, void)
+DEF_HELPER_1(fadd_STN_ST0, void, int)
+DEF_HELPER_1(fmul_STN_ST0, void, int)
+DEF_HELPER_1(fsub_STN_ST0, void, int)
+DEF_HELPER_1(fsubr_STN_ST0, void, int)
+DEF_HELPER_1(fdiv_STN_ST0, void, int)
+DEF_HELPER_1(fdivr_STN_ST0, void, int)
+DEF_HELPER_0(fchs_ST0, void)
+DEF_HELPER_0(fabs_ST0, void)
+DEF_HELPER_0(fxam_ST0, void)
+DEF_HELPER_0(fld1_ST0, void)
+DEF_HELPER_0(fldl2t_ST0, void)
+DEF_HELPER_0(fldl2e_ST0, void)
+DEF_HELPER_0(fldpi_ST0, void)
+DEF_HELPER_0(fldlg2_ST0, void)
+DEF_HELPER_0(fldln2_ST0, void)
+DEF_HELPER_0(fldz_ST0, void)
+DEF_HELPER_0(fldz_FT0, void)
+DEF_HELPER_0(fnstsw, i32)
+DEF_HELPER_0(fnstcw, i32)
+DEF_HELPER_1(fldcw, void, i32)
+DEF_HELPER_0(fclex, void)
+DEF_HELPER_0(fwait, void)
+DEF_HELPER_0(fninit, void)
+DEF_HELPER_1(fbld_ST0, void, tl)
+DEF_HELPER_1(fbst_ST0, void, tl)
+DEF_HELPER_0(f2xm1, void)
+DEF_HELPER_0(fyl2x, void)
+DEF_HELPER_0(fptan, void)
+DEF_HELPER_0(fpatan, void)
+DEF_HELPER_0(fxtract, void)
+DEF_HELPER_0(fprem1, void)
+DEF_HELPER_0(fprem, void)
+DEF_HELPER_0(fyl2xp1, void)
+DEF_HELPER_0(fsqrt, void)
+DEF_HELPER_0(fsincos, void)
+DEF_HELPER_0(frndint, void)
+DEF_HELPER_0(fscale, void)
+DEF_HELPER_0(fsin, void)
+DEF_HELPER_0(fcos, void)
+DEF_HELPER_2(fstenv, void, tl, int)
+DEF_HELPER_2(fldenv, void, tl, int)
+DEF_HELPER_2(fsave, void, tl, int)
+DEF_HELPER_2(frstor, void, tl, int)
+DEF_HELPER_2(fxsave, void, tl, int)
+DEF_HELPER_2(fxrstor, void, tl, int)
+DEF_HELPER_1(bsf, tl, tl)
+DEF_HELPER_1(bsr, tl, tl)
+DEF_HELPER_2(lzcnt, tl, tl, int)
+
+/* MMX/SSE */
+
+DEF_HELPER_0(enter_mmx, void)
+DEF_HELPER_0(emms, void)
+DEF_HELPER_2(movq, void, ptr, ptr)
+
+#define SHIFT 0
+#include "ops_sse_header.h"
+#define SHIFT 1
+#include "ops_sse_header.h"
+
+DEF_HELPER_2(rclb, tl, tl, tl)
+DEF_HELPER_2(rclw, tl, tl, tl)
+DEF_HELPER_2(rcll, tl, tl, tl)
+DEF_HELPER_2(rcrb, tl, tl, tl)
+DEF_HELPER_2(rcrw, tl, tl, tl)
+DEF_HELPER_2(rcrl, tl, tl, tl)
+#ifdef TARGET_X86_64
+DEF_HELPER_2(rclq, tl, tl, tl)
+DEF_HELPER_2(rcrq, tl, tl, tl)
+#endif
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-i386/helper_template.h b/qemu-0.15.x/target-i386/helper_template.h
new file mode 100644
index 0000000..afc41fb
--- /dev/null
+++ b/qemu-0.15.x/target-i386/helper_template.h
@@ -0,0 +1,334 @@
+/*
+ *  i386 helpers
+ *
+ *  Copyright (c) 2008 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define DATA_BITS (1 << (3 + SHIFT))
+#define SHIFT_MASK (DATA_BITS - 1)
+#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1))
+#if DATA_BITS <= 32
+#define SHIFT1_MASK 0x1f
+#else
+#define SHIFT1_MASK 0x3f
+#endif
+
+#if DATA_BITS == 8
+#define SUFFIX b
+#define DATA_TYPE uint8_t
+#define DATA_STYPE int8_t
+#define DATA_MASK 0xff
+#elif DATA_BITS == 16
+#define SUFFIX w
+#define DATA_TYPE uint16_t
+#define DATA_STYPE int16_t
+#define DATA_MASK 0xffff
+#elif DATA_BITS == 32
+#define SUFFIX l
+#define DATA_TYPE uint32_t
+#define DATA_STYPE int32_t
+#define DATA_MASK 0xffffffff
+#elif DATA_BITS == 64
+#define SUFFIX q
+#define DATA_TYPE uint64_t
+#define DATA_STYPE int64_t
+#define DATA_MASK 0xffffffffffffffffULL
+#else
+#error unhandled operand size
+#endif
+
+/* dynamic flags computation */
+
+static int glue(compute_all_add, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_SRC;
+    src2 = CC_DST - CC_SRC;
+    cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_add, SUFFIX)(void)
+{
+    int cf;
+    target_long src1;
+    src1 = CC_SRC;
+    cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
+    return cf;
+}
+
+static int glue(compute_all_adc, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_SRC;
+    src2 = CC_DST - CC_SRC - 1;
+    cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_adc, SUFFIX)(void)
+{
+    int cf;
+    target_long src1;
+    src1 = CC_SRC;
+    cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+    return cf;
+}
+
+static int glue(compute_all_sub, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_DST + CC_SRC;
+    src2 = CC_SRC;
+    cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_sub, SUFFIX)(void)
+{
+    int cf;
+    target_long src1, src2;
+    src1 = CC_DST + CC_SRC;
+    src2 = CC_SRC;
+    cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
+    return cf;
+}
+
+static int glue(compute_all_sbb, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_DST + CC_SRC + 1;
+    src2 = CC_SRC;
+    cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_sbb, SUFFIX)(void)
+{
+    int cf;
+    target_long src1, src2;
+    src1 = CC_DST + CC_SRC + 1;
+    src2 = CC_SRC;
+    cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
+    return cf;
+}
+
+static int glue(compute_all_logic, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    cf = 0;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = 0;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = 0;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_logic, SUFFIX)(void)
+{
+    return 0;
+}
+
+static int glue(compute_all_inc, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_DST - 1;
+    src2 = 1;
+    cf = CC_SRC;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
+    return cf | pf | af | zf | sf | of;
+}
+
+#if DATA_BITS == 32
+static int glue(compute_c_inc, SUFFIX)(void)
+{
+    return CC_SRC;
+}
+#endif
+
+static int glue(compute_all_dec, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    target_long src1, src2;
+    src1 = CC_DST + 1;
+    src2 = 1;
+    cf = CC_SRC;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_all_shl, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = 0; /* undefined */
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    /* of is defined if shift count == 1 */
+    of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_shl, SUFFIX)(void)
+{
+    return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
+}
+
+#if DATA_BITS == 32
+static int glue(compute_c_sar, SUFFIX)(void)
+{
+    return CC_SRC & 1;
+}
+#endif
+
+static int glue(compute_all_sar, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    cf = CC_SRC & 1;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = 0; /* undefined */
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    /* of is defined if shift count == 1 */
+    of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+#if DATA_BITS == 32
+static int glue(compute_c_mul, SUFFIX)(void)
+{
+    int cf;
+    cf = (CC_SRC != 0);
+    return cf;
+}
+#endif
+
+/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
+   CF are modified and it is slower to do that. */
+static int glue(compute_all_mul, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    cf = (CC_SRC != 0);
+    pf = parity_table[(uint8_t)CC_DST];
+    af = 0; /* undefined */
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = cf << 11;
+    return cf | pf | af | zf | sf | of;
+}
+
+/* shifts */
+
+target_ulong glue(helper_rcl, SUFFIX)(target_ulong t0, target_ulong t1)
+{
+    int count, eflags;
+    target_ulong src;
+    target_long res;
+
+    count = t1 & SHIFT1_MASK;
+#if DATA_BITS == 16
+    count = rclw_table[count];
+#elif DATA_BITS == 8
+    count = rclb_table[count];
+#endif
+    if (count) {
+        eflags = helper_cc_compute_all(CC_OP);
+        t0 &= DATA_MASK;
+        src = t0;
+        res = (t0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1));
+        if (count > 1)
+            res |= t0 >> (DATA_BITS + 1 - count);
+        t0 = res;
+        env->cc_tmp = (eflags & ~(CC_C | CC_O)) |
+            (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
+            ((src >> (DATA_BITS - count)) & CC_C);
+    } else {
+        env->cc_tmp = -1;
+    }
+    return t0;
+}
+
+target_ulong glue(helper_rcr, SUFFIX)(target_ulong t0, target_ulong t1)
+{
+    int count, eflags;
+    target_ulong src;
+    target_long res;
+
+    count = t1 & SHIFT1_MASK;
+#if DATA_BITS == 16
+    count = rclw_table[count];
+#elif DATA_BITS == 8
+    count = rclb_table[count];
+#endif
+    if (count) {
+        eflags = helper_cc_compute_all(CC_OP);
+        t0 &= DATA_MASK;
+        src = t0;
+        res = (t0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count));
+        if (count > 1)
+            res |= t0 << (DATA_BITS + 1 - count);
+        t0 = res;
+        env->cc_tmp = (eflags & ~(CC_C | CC_O)) |
+            (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
+            ((src >> (count - 1)) & CC_C);
+    } else {
+        env->cc_tmp = -1;
+    }
+    return t0;
+}
+
+#undef DATA_BITS
+#undef SHIFT_MASK
+#undef SHIFT1_MASK
+#undef SIGN_MASK
+#undef DATA_TYPE
+#undef DATA_STYPE
+#undef DATA_MASK
+#undef SUFFIX
diff --git a/qemu-0.15.x/target-i386/kvm.c b/qemu-0.15.x/target-i386/kvm.c
new file mode 100644
index 0000000..10fb2c4
--- /dev/null
+++ b/qemu-0.15.x/target-i386/kvm.c
@@ -0,0 +1,1837 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright (C) 2006-2008 Qumranet Technologies
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "cpu.h"
+#include "gdbstub.h"
+#include "host-utils.h"
+#include "hw/pc.h"
+#include "hw/apic.h"
+#include "ioport.h"
+
+//#define DEBUG_KVM
+
+#ifdef DEBUG_KVM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define MSR_KVM_WALL_CLOCK  0x11
+#define MSR_KVM_SYSTEM_TIME 0x12
+
+#ifndef BUS_MCEERR_AR
+#define BUS_MCEERR_AR 4
+#endif
+#ifndef BUS_MCEERR_AO
+#define BUS_MCEERR_AO 5
+#endif
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_INFO(SET_TSS_ADDR),
+    KVM_CAP_INFO(EXT_CPUID),
+    KVM_CAP_INFO(MP_STATE),
+    KVM_CAP_LAST_INFO
+};
+
+static bool has_msr_star;
+static bool has_msr_hsave_pa;
+static bool has_msr_async_pf_en;
+static int lm_capable_kernel;
+
+static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
+{
+    struct kvm_cpuid2 *cpuid;
+    int r, size;
+
+    size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
+    cpuid = (struct kvm_cpuid2 *)qemu_mallocz(size);
+    cpuid->nent = max;
+    r = kvm_ioctl(s, KVM_GET_SUPPORTED_CPUID, cpuid);
+    if (r == 0 && cpuid->nent >= max) {
+        r = -E2BIG;
+    }
+    if (r < 0) {
+        if (r == -E2BIG) {
+            qemu_free(cpuid);
+            return NULL;
+        } else {
+            fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
+                    strerror(-r));
+            exit(1);
+        }
+    }
+    return cpuid;
+}
+
+struct kvm_para_features {
+    int cap;
+    int feature;
+} para_features[] = {
+    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
+    { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
+    { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
+    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+    { -1, -1 }
+};
+
+static int get_para_features(KVMState *s)
+{
+    int i, features = 0;
+
+    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
+        if (kvm_check_extension(s, para_features[i].cap)) {
+            features |= (1 << para_features[i].feature);
+        }
+    }
+
+    return features;
+}
+
+
+uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
+                                      uint32_t index, int reg)
+{
+    struct kvm_cpuid2 *cpuid;
+    int i, max;
+    uint32_t ret = 0;
+    uint32_t cpuid_1_edx;
+    int has_kvm_features = 0;
+
+    max = 1;
+    while ((cpuid = try_get_cpuid(s, max)) == NULL) {
+        max *= 2;
+    }
+
+    for (i = 0; i < cpuid->nent; ++i) {
+        if (cpuid->entries[i].function == function &&
+            cpuid->entries[i].index == index) {
+            if (cpuid->entries[i].function == KVM_CPUID_FEATURES) {
+                has_kvm_features = 1;
+            }
+            switch (reg) {
+            case R_EAX:
+                ret = cpuid->entries[i].eax;
+                break;
+            case R_EBX:
+                ret = cpuid->entries[i].ebx;
+                break;
+            case R_ECX:
+                ret = cpuid->entries[i].ecx;
+                break;
+            case R_EDX:
+                ret = cpuid->entries[i].edx;
+                switch (function) {
+                case 1:
+                    /* KVM before 2.6.30 misreports the following features */
+                    ret |= CPUID_MTRR | CPUID_PAT | CPUID_MCE | CPUID_MCA;
+                    break;
+                case 0x80000001:
+                    /* On Intel, kvm returns cpuid according to the Intel spec,
+                     * so add missing bits according to the AMD spec:
+                     */
+                    cpuid_1_edx = kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
+                    ret |= cpuid_1_edx & 0x183f7ff;
+                    break;
+                }
+                break;
+            }
+        }
+    }
+
+    qemu_free(cpuid);
+
+    /* fallback for older kernels */
+    if (!has_kvm_features && (function == KVM_CPUID_FEATURES)) {
+        ret = get_para_features(s);
+    }
+
+    return ret;
+}
+
+typedef struct HWPoisonPage {
+    ram_addr_t ram_addr;
+    QLIST_ENTRY(HWPoisonPage) list;
+} HWPoisonPage;
+
+static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
+    QLIST_HEAD_INITIALIZER(hwpoison_page_list);
+
+static void kvm_unpoison_all(void *param)
+{
+    HWPoisonPage *page, *next_page;
+
+    QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
+        QLIST_REMOVE(page, list);
+        qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
+        qemu_free(page);
+    }
+}
+
+static void kvm_hwpoison_page_add(ram_addr_t ram_addr)
+{
+    HWPoisonPage *page;
+
+    QLIST_FOREACH(page, &hwpoison_page_list, list) {
+        if (page->ram_addr == ram_addr) {
+            return;
+        }
+    }
+    page = qemu_malloc(sizeof(HWPoisonPage));
+    page->ram_addr = ram_addr;
+    QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
+}
+
+static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
+                                     int *max_banks)
+{
+    int r;
+
+    r = kvm_check_extension(s, KVM_CAP_MCE);
+    if (r > 0) {
+        *max_banks = r;
+        return kvm_ioctl(s, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+    }
+    return -ENOSYS;
+}
+
+static void kvm_mce_inject(CPUState *env, target_phys_addr_t paddr, int code)
+{
+    uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
+                      MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S;
+    uint64_t mcg_status = MCG_STATUS_MCIP;
+
+    if (code == BUS_MCEERR_AR) {
+        status |= MCI_STATUS_AR | 0x134;
+        mcg_status |= MCG_STATUS_EIPV;
+    } else {
+        status |= 0xc0;
+        mcg_status |= MCG_STATUS_RIPV;
+    }
+    cpu_x86_inject_mce(NULL, env, 9, status, mcg_status, paddr,
+                       (MCM_ADDR_PHYS << 6) | 0xc,
+                       cpu_x86_support_mca_broadcast(env) ?
+                       MCE_INJECT_BROADCAST : 0);
+}
+
+static void hardware_memory_error(void)
+{
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    ram_addr_t ram_addr;
+    target_phys_addr_t paddr;
+
+    if ((env->mcg_cap & MCG_SER_P) && addr
+        && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) {
+        if (qemu_ram_addr_from_host(addr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr,
+                                               &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!\n");
+            /* Hope we are lucky for AO MCE */
+            if (code == BUS_MCEERR_AO) {
+                return 0;
+            } else {
+                hardware_memory_error();
+            }
+        }
+        kvm_hwpoison_page_add(ram_addr);
+        kvm_mce_inject(env, paddr, code);
+    } else {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
+        ram_addr_t ram_addr;
+        target_phys_addr_t paddr;
+
+        /* Hope we are lucky for AO MCE */
+        if (qemu_ram_addr_from_host(addr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr,
+                                               &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!: %p\n", addr);
+            return 0;
+        }
+        kvm_hwpoison_page_add(ram_addr);
+        kvm_mce_inject(first_cpu, paddr, code);
+    } else {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int kvm_inject_mce_oldstyle(CPUState *env)
+{
+    if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) {
+        unsigned int bank, bank_num = env->mcg_cap & 0xff;
+        struct kvm_x86_mce mce;
+
+        env->exception_injected = -1;
+
+        /*
+         * There must be at least one bank in use if an MCE is pending.
+         * Find it and use its values for the event injection.
+         */
+        for (bank = 0; bank < bank_num; bank++) {
+            if (env->mce_banks[bank * 4 + 1] & MCI_STATUS_VAL) {
+                break;
+            }
+        }
+        assert(bank < bank_num);
+
+        mce.bank = bank;
+        mce.status = env->mce_banks[bank * 4 + 1];
+        mce.mcg_status = env->mcg_status;
+        mce.addr = env->mce_banks[bank * 4 + 2];
+        mce.misc = env->mce_banks[bank * 4 + 3];
+
+        return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce);
+    }
+    return 0;
+}
+
+static void cpu_update_state(void *opaque, int running, int reason)
+{
+    CPUState *env = opaque;
+
+    if (running) {
+        env->tsc_valid = false;
+    }
+}
+
+int kvm_arch_init_vcpu(CPUState *env)
+{
+    struct {
+        struct kvm_cpuid2 cpuid;
+        struct kvm_cpuid_entry2 entries[100];
+    } __attribute__((packed)) cpuid_data;
+    KVMState *s = env->kvm_state;
+    uint32_t limit, i, j, cpuid_i;
+    uint32_t unused;
+    struct kvm_cpuid_entry2 *c;
+    uint32_t signature[3];
+
+    env->cpuid_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
+
+    i = env->cpuid_ext_features & CPUID_EXT_HYPERVISOR;
+    env->cpuid_ext_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX);
+    env->cpuid_ext_features |= i;
+
+    env->cpuid_ext2_features &= kvm_arch_get_supported_cpuid(s, 0x80000001,
+                                                             0, R_EDX);
+    env->cpuid_ext3_features &= kvm_arch_get_supported_cpuid(s, 0x80000001,
+                                                             0, R_ECX);
+    env->cpuid_svm_features  &= kvm_arch_get_supported_cpuid(s, 0x8000000A,
+                                                             0, R_EDX);
+
+    cpuid_i = 0;
+
+    /* Paravirtualization CPUIDs */
+    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+    c = &cpuid_data.entries[cpuid_i++];
+    memset(c, 0, sizeof(*c));
+    c->function = KVM_CPUID_SIGNATURE;
+    c->eax = 0;
+    c->ebx = signature[0];
+    c->ecx = signature[1];
+    c->edx = signature[2];
+
+    c = &cpuid_data.entries[cpuid_i++];
+    memset(c, 0, sizeof(*c));
+    c->function = KVM_CPUID_FEATURES;
+    c->eax = env->cpuid_kvm_features &
+        kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+
+    has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
+
+    cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
+
+    for (i = 0; i <= limit; i++) {
+        c = &cpuid_data.entries[cpuid_i++];
+
+        switch (i) {
+        case 2: {
+            /* Keep reading function 2 till all the input is received */
+            int times;
+
+            c->function = i;
+            c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC |
+                       KVM_CPUID_FLAG_STATE_READ_NEXT;
+            cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+            times = c->eax & 0xff;
+
+            for (j = 1; j < times; ++j) {
+                c = &cpuid_data.entries[cpuid_i++];
+                c->function = i;
+                c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC;
+                cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+            }
+            break;
+        }
+        case 4:
+        case 0xb:
+        case 0xd:
+            for (j = 0; ; j++) {
+                if (i == 0xd && j == 64) {
+                    break;
+                }
+                c->function = i;
+                c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                c->index = j;
+                cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+
+                if (i == 4 && c->eax == 0) {
+                    break;
+                }
+                if (i == 0xb && !(c->ecx & 0xff00)) {
+                    break;
+                }
+                if (i == 0xd && c->eax == 0) {
+                    continue;
+                }
+                c = &cpuid_data.entries[cpuid_i++];
+            }
+            break;
+        default:
+            c->function = i;
+            c->flags = 0;
+            cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+            break;
+        }
+    }
+    cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused);
+
+    for (i = 0x80000000; i <= limit; i++) {
+        c = &cpuid_data.entries[cpuid_i++];
+
+        c->function = i;
+        c->flags = 0;
+        cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+    }
+
+    /* Call Centaur's CPUID instructions they are supported. */
+    if (env->cpuid_xlevel2 > 0) {
+        env->cpuid_ext4_features &=
+            kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
+        cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+        for (i = 0xC0000000; i <= limit; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+
+            c->function = i;
+            c->flags = 0;
+            cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+        }
+    }
+
+    cpuid_data.cpuid.nent = cpuid_i;
+
+    if (((env->cpuid_version >> 8)&0xF) >= 6
+        && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+        && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {
+        uint64_t mcg_cap;
+        int banks;
+        int ret;
+
+        ret = kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks);
+        if (ret < 0) {
+            fprintf(stderr, "kvm_get_mce_cap_supported: %s", strerror(-ret));
+            return ret;
+        }
+
+        if (banks > MCE_BANKS_DEF) {
+            banks = MCE_BANKS_DEF;
+        }
+        mcg_cap &= MCE_CAP_DEF;
+        mcg_cap |= banks;
+        ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
+            return ret;
+        }
+
+        env->mcg_cap = mcg_cap;
+    }
+
+    qemu_add_vm_change_state_handler(cpu_update_state, env);
+
+    return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
+}
+
+void kvm_arch_reset_vcpu(CPUState *env)
+{
+    env->exception_injected = -1;
+    env->interrupt_injected = -1;
+    env->xcr0 = 1;
+    if (kvm_irqchip_in_kernel()) {
+        env->mp_state = cpu_is_bsp(env) ? KVM_MP_STATE_RUNNABLE :
+                                          KVM_MP_STATE_UNINITIALIZED;
+    } else {
+        env->mp_state = KVM_MP_STATE_RUNNABLE;
+    }
+}
+
+static int kvm_get_supported_msrs(KVMState *s)
+{
+    static int kvm_supported_msrs;
+    int ret = 0;
+
+    /* first time */
+    if (kvm_supported_msrs == 0) {
+        struct kvm_msr_list msr_list, *kvm_msr_list;
+
+        kvm_supported_msrs = -1;
+
+        /* Obtain MSR list from KVM.  These are the MSRs that we must
+         * save/restore */
+        msr_list.nmsrs = 0;
+        ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, &msr_list);
+        if (ret < 0 && ret != -E2BIG) {
+            return ret;
+        }
+        /* Old kernel modules had a bug and could write beyond the provided
+           memory. Allocate at least a safe amount of 1K. */
+        kvm_msr_list = qemu_mallocz(MAX(1024, sizeof(msr_list) +
+                                              msr_list.nmsrs *
+                                              sizeof(msr_list.indices[0])));
+
+        kvm_msr_list->nmsrs = msr_list.nmsrs;
+        ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, kvm_msr_list);
+        if (ret >= 0) {
+            int i;
+
+            for (i = 0; i < kvm_msr_list->nmsrs; i++) {
+                if (kvm_msr_list->indices[i] == MSR_STAR) {
+                    has_msr_star = true;
+                    continue;
+                }
+                if (kvm_msr_list->indices[i] == MSR_VM_HSAVE_PA) {
+                    has_msr_hsave_pa = true;
+                    continue;
+                }
+            }
+        }
+
+        qemu_free(kvm_msr_list);
+    }
+
+    return ret;
+}
+
+int kvm_arch_init(KVMState *s)
+{
+    uint64_t identity_base = 0xfffbc000;
+    int ret;
+    struct utsname utsname;
+
+    ret = kvm_get_supported_msrs(s);
+    if (ret < 0) {
+        return ret;
+    }
+
+    uname(&utsname);
+    lm_capable_kernel = strcmp(utsname.machine, "x86_64") == 0;
+
+    /*
+     * On older Intel CPUs, KVM uses vm86 mode to emulate 16-bit code directly.
+     * In order to use vm86 mode, an EPT identity map and a TSS  are needed.
+     * Since these must be part of guest physical memory, we need to allocate
+     * them, both by setting their start addresses in the kernel and by
+     * creating a corresponding e820 entry. We need 4 pages before the BIOS.
+     *
+     * Older KVM versions may not support setting the identity map base. In
+     * that case we need to stick with the default, i.e. a 256K maximum BIOS
+     * size.
+     */
+    if (kvm_check_extension(s, KVM_CAP_SET_IDENTITY_MAP_ADDR)) {
+        /* Allows up to 16M BIOSes. */
+        identity_base = 0xfeffc000;
+
+        ret = kvm_vm_ioctl(s, KVM_SET_IDENTITY_MAP_ADDR, &identity_base);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    /* Set TSS base one page after EPT identity map. */
+    ret = kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, identity_base + 0x1000);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Tell fw_cfg to notify the BIOS to reserve the range. */
+    ret = e820_add_entry(identity_base, 0x4000, E820_RESERVED);
+    if (ret < 0) {
+        fprintf(stderr, "e820_add_entry() table is full\n");
+        return ret;
+    }
+    qemu_register_reset(kvm_unpoison_all, NULL);
+
+    return 0;
+}
+
+static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = 3;
+    lhs->present = 1;
+    lhs->dpl = 3;
+    lhs->db = 0;
+    lhs->s = 1;
+    lhs->l = 0;
+    lhs->g = 0;
+    lhs->avl = 0;
+    lhs->unusable = 0;
+}
+
+static void set_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+    unsigned flags = rhs->flags;
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
+    lhs->present = (flags & DESC_P_MASK) != 0;
+    lhs->dpl = (flags >> DESC_DPL_SHIFT) & 3;
+    lhs->db = (flags >> DESC_B_SHIFT) & 1;
+    lhs->s = (flags & DESC_S_MASK) != 0;
+    lhs->l = (flags >> DESC_L_SHIFT) & 1;
+    lhs->g = (flags & DESC_G_MASK) != 0;
+    lhs->avl = (flags & DESC_AVL_MASK) != 0;
+    lhs->unusable = 0;
+}
+
+static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs)
+{
+    lhs->selector = rhs->selector;
+    lhs->base = rhs->base;
+    lhs->limit = rhs->limit;
+    lhs->flags = (rhs->type << DESC_TYPE_SHIFT) |
+                 (rhs->present * DESC_P_MASK) |
+                 (rhs->dpl << DESC_DPL_SHIFT) |
+                 (rhs->db << DESC_B_SHIFT) |
+                 (rhs->s * DESC_S_MASK) |
+                 (rhs->l << DESC_L_SHIFT) |
+                 (rhs->g * DESC_G_MASK) |
+                 (rhs->avl * DESC_AVL_MASK);
+}
+
+static void kvm_getput_reg(__u64 *kvm_reg, target_ulong *qemu_reg, int set)
+{
+    if (set) {
+        *kvm_reg = *qemu_reg;
+    } else {
+        *qemu_reg = *kvm_reg;
+    }
+}
+
+static int kvm_getput_regs(CPUState *env, int set)
+{
+    struct kvm_regs regs;
+    int ret = 0;
+
+    if (!set) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    kvm_getput_reg(&regs.rax, &env->regs[R_EAX], set);
+    kvm_getput_reg(&regs.rbx, &env->regs[R_EBX], set);
+    kvm_getput_reg(&regs.rcx, &env->regs[R_ECX], set);
+    kvm_getput_reg(&regs.rdx, &env->regs[R_EDX], set);
+    kvm_getput_reg(&regs.rsi, &env->regs[R_ESI], set);
+    kvm_getput_reg(&regs.rdi, &env->regs[R_EDI], set);
+    kvm_getput_reg(&regs.rsp, &env->regs[R_ESP], set);
+    kvm_getput_reg(&regs.rbp, &env->regs[R_EBP], set);
+#ifdef TARGET_X86_64
+    kvm_getput_reg(&regs.r8, &env->regs[8], set);
+    kvm_getput_reg(&regs.r9, &env->regs[9], set);
+    kvm_getput_reg(&regs.r10, &env->regs[10], set);
+    kvm_getput_reg(&regs.r11, &env->regs[11], set);
+    kvm_getput_reg(&regs.r12, &env->regs[12], set);
+    kvm_getput_reg(&regs.r13, &env->regs[13], set);
+    kvm_getput_reg(&regs.r14, &env->regs[14], set);
+    kvm_getput_reg(&regs.r15, &env->regs[15], set);
+#endif
+
+    kvm_getput_reg(&regs.rflags, &env->eflags, set);
+    kvm_getput_reg(&regs.rip, &env->eip, set);
+
+    if (set) {
+        ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+    }
+
+    return ret;
+}
+
+static int kvm_put_fpu(CPUState *env)
+{
+    struct kvm_fpu fpu;
+    int i;
+
+    memset(&fpu, 0, sizeof fpu);
+    fpu.fsw = env->fpus & ~(7 << 11);
+    fpu.fsw |= (env->fpstt & 7) << 11;
+    fpu.fcw = env->fpuc;
+    fpu.last_opcode = env->fpop;
+    fpu.last_ip = env->fpip;
+    fpu.last_dp = env->fpdp;
+    for (i = 0; i < 8; ++i) {
+        fpu.ftwx |= (!env->fptags[i]) << i;
+    }
+    memcpy(fpu.fpr, env->fpregs, sizeof env->fpregs);
+    memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs);
+    fpu.mxcsr = env->mxcsr;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu);
+}
+
+#define XSAVE_CWD_RIP     2
+#define XSAVE_CWD_RDP     4
+#define XSAVE_MXCSR       6
+#define XSAVE_ST_SPACE    8
+#define XSAVE_XMM_SPACE   40
+#define XSAVE_XSTATE_BV   128
+#define XSAVE_YMMH_SPACE  144
+
+static int kvm_put_xsave(CPUState *env)
+{
+    int i, r;
+    struct kvm_xsave* xsave;
+    uint16_t cwd, swd, twd;
+
+    if (!kvm_has_xsave()) {
+        return kvm_put_fpu(env);
+    }
+
+    xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
+    memset(xsave, 0, sizeof(struct kvm_xsave));
+    cwd = swd = twd = 0;
+    swd = env->fpus & ~(7 << 11);
+    swd |= (env->fpstt & 7) << 11;
+    cwd = env->fpuc;
+    for (i = 0; i < 8; ++i) {
+        twd |= (!env->fptags[i]) << i;
+    }
+    xsave->region[0] = (uint32_t)(swd << 16) + cwd;
+    xsave->region[1] = (uint32_t)(env->fpop << 16) + twd;
+    memcpy(&xsave->region[XSAVE_CWD_RIP], &env->fpip, sizeof(env->fpip));
+    memcpy(&xsave->region[XSAVE_CWD_RDP], &env->fpdp, sizeof(env->fpdp));
+    memcpy(&xsave->region[XSAVE_ST_SPACE], env->fpregs,
+            sizeof env->fpregs);
+    memcpy(&xsave->region[XSAVE_XMM_SPACE], env->xmm_regs,
+            sizeof env->xmm_regs);
+    xsave->region[XSAVE_MXCSR] = env->mxcsr;
+    *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv;
+    memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs,
+            sizeof env->ymmh_regs);
+    r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
+    qemu_free(xsave);
+    return r;
+}
+
+static int kvm_put_xcrs(CPUState *env)
+{
+    struct kvm_xcrs xcrs;
+
+    if (!kvm_has_xcrs()) {
+        return 0;
+    }
+
+    xcrs.nr_xcrs = 1;
+    xcrs.flags = 0;
+    xcrs.xcrs[0].xcr = 0;
+    xcrs.xcrs[0].value = env->xcr0;
+    return kvm_vcpu_ioctl(env, KVM_SET_XCRS, &xcrs);
+}
+
+static int kvm_put_sregs(CPUState *env)
+{
+    struct kvm_sregs sregs;
+
+    memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
+    if (env->interrupt_injected >= 0) {
+        sregs.interrupt_bitmap[env->interrupt_injected / 64] |=
+                (uint64_t)1 << (env->interrupt_injected % 64);
+    }
+
+    if ((env->eflags & VM_MASK)) {
+        set_v8086_seg(&sregs.cs, &env->segs[R_CS]);
+        set_v8086_seg(&sregs.ds, &env->segs[R_DS]);
+        set_v8086_seg(&sregs.es, &env->segs[R_ES]);
+        set_v8086_seg(&sregs.fs, &env->segs[R_FS]);
+        set_v8086_seg(&sregs.gs, &env->segs[R_GS]);
+        set_v8086_seg(&sregs.ss, &env->segs[R_SS]);
+    } else {
+        set_seg(&sregs.cs, &env->segs[R_CS]);
+        set_seg(&sregs.ds, &env->segs[R_DS]);
+        set_seg(&sregs.es, &env->segs[R_ES]);
+        set_seg(&sregs.fs, &env->segs[R_FS]);
+        set_seg(&sregs.gs, &env->segs[R_GS]);
+        set_seg(&sregs.ss, &env->segs[R_SS]);
+    }
+
+    set_seg(&sregs.tr, &env->tr);
+    set_seg(&sregs.ldt, &env->ldt);
+
+    sregs.idt.limit = env->idt.limit;
+    sregs.idt.base = env->idt.base;
+    sregs.gdt.limit = env->gdt.limit;
+    sregs.gdt.base = env->gdt.base;
+
+    sregs.cr0 = env->cr[0];
+    sregs.cr2 = env->cr[2];
+    sregs.cr3 = env->cr[3];
+    sregs.cr4 = env->cr[4];
+
+    sregs.cr8 = cpu_get_apic_tpr(env->apic_state);
+    sregs.apic_base = cpu_get_apic_base(env->apic_state);
+
+    sregs.efer = env->efer;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
+}
+
+static void kvm_msr_entry_set(struct kvm_msr_entry *entry,
+                              uint32_t index, uint64_t value)
+{
+    entry->index = index;
+    entry->data = value;
+}
+
+static int kvm_put_msrs(CPUState *env, int level)
+{
+    struct {
+        struct kvm_msrs info;
+        struct kvm_msr_entry entries[100];
+    } msr_data;
+    struct kvm_msr_entry *msrs = msr_data.entries;
+    int n = 0;
+
+    kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
+    kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
+    kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+    kvm_msr_entry_set(&msrs[n++], MSR_PAT, env->pat);
+    if (has_msr_star) {
+        kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
+    }
+    if (has_msr_hsave_pa) {
+        kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
+    }
+#ifdef TARGET_X86_64
+    if (lm_capable_kernel) {
+        kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
+        kvm_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase);
+        kvm_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask);
+        kvm_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar);
+    }
+#endif
+    if (level == KVM_PUT_FULL_STATE) {
+        /*
+         * KVM is yet unable to synchronize TSC values of multiple VCPUs on
+         * writeback. Until this is fixed, we only write the offset to SMP
+         * guests after migration, desynchronizing the VCPUs, but avoiding
+         * huge jump-backs that would occur without any writeback at all.
+         */
+        if (smp_cpus == 1 || env->tsc != 0) {
+            kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+        }
+    }
+    /*
+     * The following paravirtual MSRs have side effects on the guest or are
+     * too heavy for normal writeback. Limit them to reset or full state
+     * updates.
+     */
+    if (level >= KVM_PUT_RESET_STATE) {
+        kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
+                          env->system_time_msr);
+        kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
+        if (has_msr_async_pf_en) {
+            kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
+                              env->async_pf_en_msr);
+        }
+    }
+    if (env->mcg_cap) {
+        int i;
+
+        kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+        kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
+        for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) {
+            kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
+        }
+    }
+
+    msr_data.info.nmsrs = n;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_MSRS, &msr_data);
+
+}
+
+
+static int kvm_get_fpu(CPUState *env)
+{
+    struct kvm_fpu fpu;
+    int i, ret;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_FPU, &fpu);
+    if (ret < 0) {
+        return ret;
+    }
+
+    env->fpstt = (fpu.fsw >> 11) & 7;
+    env->fpus = fpu.fsw;
+    env->fpuc = fpu.fcw;
+    env->fpop = fpu.last_opcode;
+    env->fpip = fpu.last_ip;
+    env->fpdp = fpu.last_dp;
+    for (i = 0; i < 8; ++i) {
+        env->fptags[i] = !((fpu.ftwx >> i) & 1);
+    }
+    memcpy(env->fpregs, fpu.fpr, sizeof env->fpregs);
+    memcpy(env->xmm_regs, fpu.xmm, sizeof env->xmm_regs);
+    env->mxcsr = fpu.mxcsr;
+
+    return 0;
+}
+
+static int kvm_get_xsave(CPUState *env)
+{
+    struct kvm_xsave* xsave;
+    int ret, i;
+    uint16_t cwd, swd, twd;
+
+    if (!kvm_has_xsave()) {
+        return kvm_get_fpu(env);
+    }
+
+    xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
+    ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave);
+    if (ret < 0) {
+        qemu_free(xsave);
+        return ret;
+    }
+
+    cwd = (uint16_t)xsave->region[0];
+    swd = (uint16_t)(xsave->region[0] >> 16);
+    twd = (uint16_t)xsave->region[1];
+    env->fpop = (uint16_t)(xsave->region[1] >> 16);
+    env->fpstt = (swd >> 11) & 7;
+    env->fpus = swd;
+    env->fpuc = cwd;
+    for (i = 0; i < 8; ++i) {
+        env->fptags[i] = !((twd >> i) & 1);
+    }
+    memcpy(&env->fpip, &xsave->region[XSAVE_CWD_RIP], sizeof(env->fpip));
+    memcpy(&env->fpdp, &xsave->region[XSAVE_CWD_RDP], sizeof(env->fpdp));
+    env->mxcsr = xsave->region[XSAVE_MXCSR];
+    memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE],
+            sizeof env->fpregs);
+    memcpy(env->xmm_regs, &xsave->region[XSAVE_XMM_SPACE],
+            sizeof env->xmm_regs);
+    env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV];
+    memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE],
+            sizeof env->ymmh_regs);
+    qemu_free(xsave);
+    return 0;
+}
+
+static int kvm_get_xcrs(CPUState *env)
+{
+    int i, ret;
+    struct kvm_xcrs xcrs;
+
+    if (!kvm_has_xcrs()) {
+        return 0;
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_XCRS, &xcrs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (i = 0; i < xcrs.nr_xcrs; i++) {
+        /* Only support xcr0 now */
+        if (xcrs.xcrs[0].xcr == 0) {
+            env->xcr0 = xcrs.xcrs[0].value;
+            break;
+        }
+    }
+    return 0;
+}
+
+static int kvm_get_sregs(CPUState *env)
+{
+    struct kvm_sregs sregs;
+    uint32_t hflags;
+    int bit, i, ret;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* There can only be one pending IRQ set in the bitmap at a time, so try
+       to find it and save its number instead (-1 for none). */
+    env->interrupt_injected = -1;
+    for (i = 0; i < ARRAY_SIZE(sregs.interrupt_bitmap); i++) {
+        if (sregs.interrupt_bitmap[i]) {
+            bit = ctz64(sregs.interrupt_bitmap[i]);
+            env->interrupt_injected = i * 64 + bit;
+            break;
+        }
+    }
+
+    get_seg(&env->segs[R_CS], &sregs.cs);
+    get_seg(&env->segs[R_DS], &sregs.ds);
+    get_seg(&env->segs[R_ES], &sregs.es);
+    get_seg(&env->segs[R_FS], &sregs.fs);
+    get_seg(&env->segs[R_GS], &sregs.gs);
+    get_seg(&env->segs[R_SS], &sregs.ss);
+
+    get_seg(&env->tr, &sregs.tr);
+    get_seg(&env->ldt, &sregs.ldt);
+
+    env->idt.limit = sregs.idt.limit;
+    env->idt.base = sregs.idt.base;
+    env->gdt.limit = sregs.gdt.limit;
+    env->gdt.base = sregs.gdt.base;
+
+    env->cr[0] = sregs.cr0;
+    env->cr[2] = sregs.cr2;
+    env->cr[3] = sregs.cr3;
+    env->cr[4] = sregs.cr4;
+
+    cpu_set_apic_base(env->apic_state, sregs.apic_base);
+
+    env->efer = sregs.efer;
+    //cpu_set_apic_tpr(env->apic_state, sregs.cr8);
+
+#define HFLAG_COPY_MASK \
+    ~( HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
+       HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
+       HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
+       HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
+
+    hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+    hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
+    hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
+                (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
+    hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
+    hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
+                (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+    if (env->efer & MSR_EFER_LMA) {
+        hflags |= HF_LMA_MASK;
+    }
+
+    if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) {
+        hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+    } else {
+        hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >>
+                    (DESC_B_SHIFT - HF_CS32_SHIFT);
+        hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >>
+                    (DESC_B_SHIFT - HF_SS32_SHIFT);
+        if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK) ||
+            !(hflags & HF_CS32_MASK)) {
+            hflags |= HF_ADDSEG_MASK;
+        } else {
+            hflags |= ((env->segs[R_DS].base | env->segs[R_ES].base |
+                        env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT;
+        }
+    }
+    env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+
+    return 0;
+}
+
+static int kvm_get_msrs(CPUState *env)
+{
+    struct {
+        struct kvm_msrs info;
+        struct kvm_msr_entry entries[100];
+    } msr_data;
+    struct kvm_msr_entry *msrs = msr_data.entries;
+    int ret, i, n;
+
+    n = 0;
+    msrs[n++].index = MSR_IA32_SYSENTER_CS;
+    msrs[n++].index = MSR_IA32_SYSENTER_ESP;
+    msrs[n++].index = MSR_IA32_SYSENTER_EIP;
+    msrs[n++].index = MSR_PAT;
+    if (has_msr_star) {
+        msrs[n++].index = MSR_STAR;
+    }
+    if (has_msr_hsave_pa) {
+        msrs[n++].index = MSR_VM_HSAVE_PA;
+    }
+
+    if (!env->tsc_valid) {
+        msrs[n++].index = MSR_IA32_TSC;
+        env->tsc_valid = !vm_running;
+    }
+
+#ifdef TARGET_X86_64
+    if (lm_capable_kernel) {
+        msrs[n++].index = MSR_CSTAR;
+        msrs[n++].index = MSR_KERNELGSBASE;
+        msrs[n++].index = MSR_FMASK;
+        msrs[n++].index = MSR_LSTAR;
+    }
+#endif
+    msrs[n++].index = MSR_KVM_SYSTEM_TIME;
+    msrs[n++].index = MSR_KVM_WALL_CLOCK;
+    if (has_msr_async_pf_en) {
+        msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
+    }
+
+    if (env->mcg_cap) {
+        msrs[n++].index = MSR_MCG_STATUS;
+        msrs[n++].index = MSR_MCG_CTL;
+        for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) {
+            msrs[n++].index = MSR_MC0_CTL + i;
+        }
+    }
+
+    msr_data.info.nmsrs = n;
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (i = 0; i < ret; i++) {
+        switch (msrs[i].index) {
+        case MSR_IA32_SYSENTER_CS:
+            env->sysenter_cs = msrs[i].data;
+            break;
+        case MSR_IA32_SYSENTER_ESP:
+            env->sysenter_esp = msrs[i].data;
+            break;
+        case MSR_IA32_SYSENTER_EIP:
+            env->sysenter_eip = msrs[i].data;
+            break;
+        case MSR_PAT:
+            env->pat = msrs[i].data;
+            break;
+        case MSR_STAR:
+            env->star = msrs[i].data;
+            break;
+#ifdef TARGET_X86_64
+        case MSR_CSTAR:
+            env->cstar = msrs[i].data;
+            break;
+        case MSR_KERNELGSBASE:
+            env->kernelgsbase = msrs[i].data;
+            break;
+        case MSR_FMASK:
+            env->fmask = msrs[i].data;
+            break;
+        case MSR_LSTAR:
+            env->lstar = msrs[i].data;
+            break;
+#endif
+        case MSR_IA32_TSC:
+            env->tsc = msrs[i].data;
+            break;
+        case MSR_VM_HSAVE_PA:
+            env->vm_hsave = msrs[i].data;
+            break;
+        case MSR_KVM_SYSTEM_TIME:
+            env->system_time_msr = msrs[i].data;
+            break;
+        case MSR_KVM_WALL_CLOCK:
+            env->wall_clock_msr = msrs[i].data;
+            break;
+        case MSR_MCG_STATUS:
+            env->mcg_status = msrs[i].data;
+            break;
+        case MSR_MCG_CTL:
+            env->mcg_ctl = msrs[i].data;
+            break;
+        default:
+            if (msrs[i].index >= MSR_MC0_CTL &&
+                msrs[i].index < MSR_MC0_CTL + (env->mcg_cap & 0xff) * 4) {
+                env->mce_banks[msrs[i].index - MSR_MC0_CTL] = msrs[i].data;
+            }
+            break;
+        case MSR_KVM_ASYNC_PF_EN:
+            env->async_pf_en_msr = msrs[i].data;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int kvm_put_mp_state(CPUState *env)
+{
+    struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
+
+    return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state);
+}
+
+static int kvm_get_mp_state(CPUState *env)
+{
+    struct kvm_mp_state mp_state;
+    int ret;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state);
+    if (ret < 0) {
+        return ret;
+    }
+    env->mp_state = mp_state.mp_state;
+    if (kvm_irqchip_in_kernel()) {
+        env->halted = (mp_state.mp_state == KVM_MP_STATE_HALTED);
+    }
+    return 0;
+}
+
+static int kvm_put_vcpu_events(CPUState *env, int level)
+{
+    struct kvm_vcpu_events events;
+
+    if (!kvm_has_vcpu_events()) {
+        return 0;
+    }
+
+    events.exception.injected = (env->exception_injected >= 0);
+    events.exception.nr = env->exception_injected;
+    events.exception.has_error_code = env->has_error_code;
+    events.exception.error_code = env->error_code;
+
+    events.interrupt.injected = (env->interrupt_injected >= 0);
+    events.interrupt.nr = env->interrupt_injected;
+    events.interrupt.soft = env->soft_interrupt;
+
+    events.nmi.injected = env->nmi_injected;
+    events.nmi.pending = env->nmi_pending;
+    events.nmi.masked = !!(env->hflags2 & HF2_NMI_MASK);
+
+    events.sipi_vector = env->sipi_vector;
+
+    events.flags = 0;
+    if (level >= KVM_PUT_RESET_STATE) {
+        events.flags |=
+            KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR;
+    }
+
+    return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events);
+}
+
+static int kvm_get_vcpu_events(CPUState *env)
+{
+    struct kvm_vcpu_events events;
+    int ret;
+
+    if (!kvm_has_vcpu_events()) {
+        return 0;
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_VCPU_EVENTS, &events);
+    if (ret < 0) {
+       return ret;
+    }
+    env->exception_injected =
+       events.exception.injected ? events.exception.nr : -1;
+    env->has_error_code = events.exception.has_error_code;
+    env->error_code = events.exception.error_code;
+
+    env->interrupt_injected =
+        events.interrupt.injected ? events.interrupt.nr : -1;
+    env->soft_interrupt = events.interrupt.soft;
+
+    env->nmi_injected = events.nmi.injected;
+    env->nmi_pending = events.nmi.pending;
+    if (events.nmi.masked) {
+        env->hflags2 |= HF2_NMI_MASK;
+    } else {
+        env->hflags2 &= ~HF2_NMI_MASK;
+    }
+
+    env->sipi_vector = events.sipi_vector;
+
+    return 0;
+}
+
+static int kvm_guest_debug_workarounds(CPUState *env)
+{
+    int ret = 0;
+    unsigned long reinject_trap = 0;
+
+    if (!kvm_has_vcpu_events()) {
+        if (env->exception_injected == 1) {
+            reinject_trap = KVM_GUESTDBG_INJECT_DB;
+        } else if (env->exception_injected == 3) {
+            reinject_trap = KVM_GUESTDBG_INJECT_BP;
+        }
+        env->exception_injected = -1;
+    }
+
+    /*
+     * Kernels before KVM_CAP_X86_ROBUST_SINGLESTEP overwrote flags.TF
+     * injected via SET_GUEST_DEBUG while updating GP regs. Work around this
+     * by updating the debug state once again if single-stepping is on.
+     * Another reason to call kvm_update_guest_debug here is a pending debug
+     * trap raise by the guest. On kernels without SET_VCPU_EVENTS we have to
+     * reinject them via SET_GUEST_DEBUG.
+     */
+    if (reinject_trap ||
+        (!kvm_has_robust_singlestep() && env->singlestep_enabled)) {
+        ret = kvm_update_guest_debug(env, reinject_trap);
+    }
+    return ret;
+}
+
+static int kvm_put_debugregs(CPUState *env)
+{
+    struct kvm_debugregs dbgregs;
+    int i;
+
+    if (!kvm_has_debugregs()) {
+        return 0;
+    }
+
+    for (i = 0; i < 4; i++) {
+        dbgregs.db[i] = env->dr[i];
+    }
+    dbgregs.dr6 = env->dr[6];
+    dbgregs.dr7 = env->dr[7];
+    dbgregs.flags = 0;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_DEBUGREGS, &dbgregs);
+}
+
+static int kvm_get_debugregs(CPUState *env)
+{
+    struct kvm_debugregs dbgregs;
+    int i, ret;
+
+    if (!kvm_has_debugregs()) {
+        return 0;
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_DEBUGREGS, &dbgregs);
+    if (ret < 0) {
+        return ret;
+    }
+    for (i = 0; i < 4; i++) {
+        env->dr[i] = dbgregs.db[i];
+    }
+    env->dr[4] = env->dr[6] = dbgregs.dr6;
+    env->dr[5] = env->dr[7] = dbgregs.dr7;
+
+    return 0;
+}
+
+int kvm_arch_put_registers(CPUState *env, int level)
+{
+    int ret;
+
+    assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
+
+    ret = kvm_getput_regs(env, 1);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_put_xsave(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_put_xcrs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_put_sregs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    /* must be before kvm_put_msrs */
+    ret = kvm_inject_mce_oldstyle(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_put_msrs(env, level);
+    if (ret < 0) {
+        return ret;
+    }
+    if (level >= KVM_PUT_RESET_STATE) {
+        ret = kvm_put_mp_state(env);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+    ret = kvm_put_vcpu_events(env, level);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_put_debugregs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    /* must be last */
+    ret = kvm_guest_debug_workarounds(env);
+    if (ret < 0) {
+        return ret;
+    }
+    return 0;
+}
+
+int kvm_arch_get_registers(CPUState *env)
+{
+    int ret;
+
+    assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
+
+    ret = kvm_getput_regs(env, 0);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_xsave(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_xcrs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_sregs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_msrs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_mp_state(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_vcpu_events(env);
+    if (ret < 0) {
+        return ret;
+    }
+    ret = kvm_get_debugregs(env);
+    if (ret < 0) {
+        return ret;
+    }
+    return 0;
+}
+
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+{
+    int ret;
+
+    /* Inject NMI */
+    if (env->interrupt_request & CPU_INTERRUPT_NMI) {
+        env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+        DPRINTF("injected NMI\n");
+        ret = kvm_vcpu_ioctl(env, KVM_NMI);
+        if (ret < 0) {
+            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+                    strerror(-ret));
+        }
+    }
+
+    if (!kvm_irqchip_in_kernel()) {
+        /* Force the VCPU out of its inner loop to process the INIT request */
+        if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+            env->exit_request = 1;
+        }
+
+        /* Try to inject an interrupt if the guest can accept it */
+        if (run->ready_for_interrupt_injection &&
+            (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->eflags & IF_MASK)) {
+            int irq;
+
+            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+            irq = cpu_get_pic_interrupt(env);
+            if (irq >= 0) {
+                struct kvm_interrupt intr;
+
+                intr.irq = irq;
+                DPRINTF("injected interrupt %d\n", irq);
+                ret = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr);
+                if (ret < 0) {
+                    fprintf(stderr,
+                            "KVM: injection failed, interrupt lost (%s)\n",
+                            strerror(-ret));
+                }
+            }
+        }
+
+        /* If we have an interrupt but the guest is not ready to receive an
+         * interrupt, request an interrupt window exit.  This will
+         * cause a return to userspace as soon as the guest is ready to
+         * receive interrupts. */
+        if ((env->interrupt_request & CPU_INTERRUPT_HARD)) {
+            run->request_interrupt_window = 1;
+        } else {
+            run->request_interrupt_window = 0;
+        }
+
+        DPRINTF("setting tpr\n");
+        run->cr8 = cpu_get_apic_tpr(env->apic_state);
+    }
+}
+
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+{
+    if (run->if_flag) {
+        env->eflags |= IF_MASK;
+    } else {
+        env->eflags &= ~IF_MASK;
+    }
+    cpu_set_apic_tpr(env->apic_state, run->cr8);
+    cpu_set_apic_base(env->apic_state, run->apic_base);
+}
+
+int kvm_arch_process_async_events(CPUState *env)
+{
+    if (env->interrupt_request & CPU_INTERRUPT_MCE) {
+        /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */
+        assert(env->mcg_cap);
+
+        env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+
+        kvm_cpu_synchronize_state(env);
+
+        if (env->exception_injected == EXCP08_DBLE) {
+            /* this means triple fault */
+            qemu_system_reset_request();
+            env->exit_request = 1;
+            return 0;
+        }
+        env->exception_injected = EXCP12_MCHK;
+        env->has_error_code = 0;
+
+        env->halted = 0;
+        if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) {
+            env->mp_state = KVM_MP_STATE_RUNNABLE;
+        }
+    }
+
+    if (kvm_irqchip_in_kernel()) {
+        return 0;
+    }
+
+    if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+         (env->eflags & IF_MASK)) ||
+        (env->interrupt_request & CPU_INTERRUPT_NMI)) {
+        env->halted = 0;
+    }
+    if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+        kvm_cpu_synchronize_state(env);
+        do_cpu_init(env);
+    }
+    if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
+        kvm_cpu_synchronize_state(env);
+        do_cpu_sipi(env);
+    }
+
+    return env->halted;
+}
+
+static int kvm_handle_halt(CPUState *env)
+{
+    if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+          (env->eflags & IF_MASK)) &&
+        !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
+        env->halted = 1;
+        return EXCP_HLT;
+    }
+
+    return 0;
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    static const uint8_t int3 = 0xcc;
+
+    if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) ||
+        cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&int3, 1, 1)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    uint8_t int3;
+
+    if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
+        cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static struct {
+    target_ulong addr;
+    int len;
+    int type;
+} hw_breakpoint[4];
+
+static int nb_hw_breakpoint;
+
+static int find_hw_breakpoint(target_ulong addr, int len, int type)
+{
+    int n;
+
+    for (n = 0; n < nb_hw_breakpoint; n++) {
+        if (hw_breakpoint[n].addr == addr && hw_breakpoint[n].type == type &&
+            (hw_breakpoint[n].len == len || len == -1)) {
+            return n;
+        }
+    }
+    return -1;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        len = 1;
+        break;
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+        switch (len) {
+        case 1:
+            break;
+        case 2:
+        case 4:
+        case 8:
+            if (addr & (len - 1)) {
+                return -EINVAL;
+            }
+            break;
+        default:
+            return -EINVAL;
+        }
+        break;
+    default:
+        return -ENOSYS;
+    }
+
+    if (nb_hw_breakpoint == 4) {
+        return -ENOBUFS;
+    }
+    if (find_hw_breakpoint(addr, len, type) >= 0) {
+        return -EEXIST;
+    }
+    hw_breakpoint[nb_hw_breakpoint].addr = addr;
+    hw_breakpoint[nb_hw_breakpoint].len = len;
+    hw_breakpoint[nb_hw_breakpoint].type = type;
+    nb_hw_breakpoint++;
+
+    return 0;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    int n;
+
+    n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type);
+    if (n < 0) {
+        return -ENOENT;
+    }
+    nb_hw_breakpoint--;
+    hw_breakpoint[n] = hw_breakpoint[nb_hw_breakpoint];
+
+    return 0;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    nb_hw_breakpoint = 0;
+}
+
+static CPUWatchpoint hw_watchpoint;
+
+static int kvm_handle_debug(struct kvm_debug_exit_arch *arch_info)
+{
+    int ret = 0;
+    int n;
+
+    if (arch_info->exception == 1) {
+        if (arch_info->dr6 & (1 << 14)) {
+            if (cpu_single_env->singlestep_enabled) {
+                ret = EXCP_DEBUG;
+            }
+        } else {
+            for (n = 0; n < 4; n++) {
+                if (arch_info->dr6 & (1 << n)) {
+                    switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) {
+                    case 0x0:
+                        ret = EXCP_DEBUG;
+                        break;
+                    case 0x1:
+                        ret = EXCP_DEBUG;
+                        cpu_single_env->watchpoint_hit = &hw_watchpoint;
+                        hw_watchpoint.vaddr = hw_breakpoint[n].addr;
+                        hw_watchpoint.flags = BP_MEM_WRITE;
+                        break;
+                    case 0x3:
+                        ret = EXCP_DEBUG;
+                        cpu_single_env->watchpoint_hit = &hw_watchpoint;
+                        hw_watchpoint.vaddr = hw_breakpoint[n].addr;
+                        hw_watchpoint.flags = BP_MEM_ACCESS;
+                        break;
+                    }
+                }
+            }
+        }
+    } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) {
+        ret = EXCP_DEBUG;
+    }
+    if (ret == 0) {
+        cpu_synchronize_state(cpu_single_env);
+        assert(cpu_single_env->exception_injected == -1);
+
+        /* pass to guest */
+        cpu_single_env->exception_injected = arch_info->exception;
+        cpu_single_env->has_error_code = 0;
+    }
+
+    return ret;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
+{
+    const uint8_t type_code[] = {
+        [GDB_BREAKPOINT_HW] = 0x0,
+        [GDB_WATCHPOINT_WRITE] = 0x1,
+        [GDB_WATCHPOINT_ACCESS] = 0x3
+    };
+    const uint8_t len_code[] = {
+        [1] = 0x0, [2] = 0x1, [4] = 0x3, [8] = 0x2
+    };
+    int n;
+
+    if (kvm_sw_breakpoints_active(env)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+    }
+    if (nb_hw_breakpoint > 0) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+        dbg->arch.debugreg[7] = 0x0600;
+        for (n = 0; n < nb_hw_breakpoint; n++) {
+            dbg->arch.debugreg[n] = hw_breakpoint[n].addr;
+            dbg->arch.debugreg[7] |= (2 << (n * 2)) |
+                (type_code[hw_breakpoint[n].type] << (16 + n*4)) |
+                ((uint32_t)len_code[hw_breakpoint[n].len] << (18 + n*4));
+        }
+    }
+}
+
+static bool host_supports_vmx(void)
+{
+    uint32_t ecx, unused;
+
+    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
+    return ecx & CPUID_EXT_VMX;
+}
+
+#define VMX_INVALID_GUEST_STATE 0x80000021
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
+{
+    uint64_t code;
+    int ret;
+
+    switch (run->exit_reason) {
+    case KVM_EXIT_HLT:
+        DPRINTF("handle_hlt\n");
+        ret = kvm_handle_halt(env);
+        break;
+    case KVM_EXIT_SET_TPR:
+        ret = 0;
+        break;
+    case KVM_EXIT_FAIL_ENTRY:
+        code = run->fail_entry.hardware_entry_failure_reason;
+        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
+                code);
+        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
+            fprintf(stderr,
+                    "\nIf you're runnning a guest on an Intel machine without "
+                        "unrestricted mode\n"
+                    "support, the failure can be most likely due to the guest "
+                        "entering an invalid\n"
+                    "state for Intel VT. For example, the guest maybe running "
+                        "in big real mode\n"
+                    "which is not supported on less recent Intel processors."
+                        "\n\n");
+        }
+        ret = -1;
+        break;
+    case KVM_EXIT_EXCEPTION:
+        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
+                run->ex.exception, run->ex.error_code);
+        ret = -1;
+        break;
+    case KVM_EXIT_DEBUG:
+        DPRINTF("kvm_exit_debug\n");
+        ret = kvm_handle_debug(&run->debug.arch);
+        break;
+    default:
+        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+    return !(env->cr[0] & CR0_PE_MASK) ||
+           ((env->segs[R_CS].selector  & 3) != 3);
+}
diff --git a/qemu-0.15.x/target-i386/machine.c b/qemu-0.15.x/target-i386/machine.c
new file mode 100644
index 0000000..9aca8e0
--- /dev/null
+++ b/qemu-0.15.x/target-i386/machine.c
@@ -0,0 +1,437 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/pc.h"
+#include "hw/isa.h"
+
+#include "cpu.h"
+#include "kvm.h"
+
+static const VMStateDescription vmstate_segment = {
+    .name = "segment",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(selector, SegmentCache),
+        VMSTATE_UINTTL(base, SegmentCache),
+        VMSTATE_UINT32(limit, SegmentCache),
+        VMSTATE_UINT32(flags, SegmentCache),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_SEGMENT(_field, _state) {                            \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(SegmentCache),                              \
+    .vmsd       = &vmstate_segment,                                  \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = offsetof(_state, _field)                           \
+            + type_check(SegmentCache,typeof_field(_state, _field))  \
+}
+
+#define VMSTATE_SEGMENT_ARRAY(_field, _state, _n)                    \
+    VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_segment, SegmentCache)
+
+static const VMStateDescription vmstate_xmm_reg = {
+    .name = "xmm_reg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(XMM_Q(0), XMMReg),
+        VMSTATE_UINT64(XMM_Q(1), XMMReg),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_XMM_REGS(_field, _state, _n)                         \
+    VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg)
+
+/* YMMH format is the same as XMM */
+static const VMStateDescription vmstate_ymmh_reg = {
+    .name = "ymmh_reg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(XMM_Q(0), XMMReg),
+        VMSTATE_UINT64(XMM_Q(1), XMMReg),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v)                         \
+    VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg)
+
+static const VMStateDescription vmstate_mtrr_var = {
+    .name = "mtrr_var",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(base, MTRRVar),
+        VMSTATE_UINT64(mask, MTRRVar),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_MTRR_VARS(_field, _state, _n, _v)                    \
+    VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar)
+
+static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size)
+{
+    fprintf(stderr, "call put_fpreg() with invalid arguments\n");
+    exit(0);
+}
+
+/* XXX: add that in a FPU generic layer */
+union x86_longdouble {
+    uint64_t mant;
+    uint16_t exp;
+};
+
+#define MANTD1(fp)	(fp & ((1LL << 52) - 1))
+#define EXPBIAS1 1023
+#define EXPD1(fp)	((fp >> 52) & 0x7FF)
+#define SIGND1(fp)	((fp >> 32) & 0x80000000)
+
+static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)
+{
+    int e;
+    /* mantissa */
+    p->mant = (MANTD1(temp) << 11) | (1LL << 63);
+    /* exponent + sign */
+    e = EXPD1(temp) - EXPBIAS1 + 16383;
+    e |= SIGND1(temp) >> 16;
+    p->exp = e;
+}
+
+static int get_fpreg(QEMUFile *f, void *opaque, size_t size)
+{
+    FPReg *fp_reg = opaque;
+    uint64_t mant;
+    uint16_t exp;
+
+    qemu_get_be64s(f, &mant);
+    qemu_get_be16s(f, &exp);
+    fp_reg->d = cpu_set_fp80(mant, exp);
+    return 0;
+}
+
+static void put_fpreg(QEMUFile *f, void *opaque, size_t size)
+{
+    FPReg *fp_reg = opaque;
+    uint64_t mant;
+    uint16_t exp;
+    /* we save the real CPU data (in case of MMX usage only 'mant'
+       contains the MMX register */
+    cpu_get_fp80(&mant, &exp, fp_reg->d);
+    qemu_put_be64s(f, &mant);
+    qemu_put_be16s(f, &exp);
+}
+
+static const VMStateInfo vmstate_fpreg = {
+    .name = "fpreg",
+    .get  = get_fpreg,
+    .put  = put_fpreg,
+};
+
+static int get_fpreg_1_mmx(QEMUFile *f, void *opaque, size_t size)
+{
+    union x86_longdouble *p = opaque;
+    uint64_t mant;
+
+    qemu_get_be64s(f, &mant);
+    p->mant = mant;
+    p->exp = 0xffff;
+    return 0;
+}
+
+static const VMStateInfo vmstate_fpreg_1_mmx = {
+    .name = "fpreg_1_mmx",
+    .get  = get_fpreg_1_mmx,
+    .put  = put_fpreg_error,
+};
+
+static int get_fpreg_1_no_mmx(QEMUFile *f, void *opaque, size_t size)
+{
+    union x86_longdouble *p = opaque;
+    uint64_t mant;
+
+    qemu_get_be64s(f, &mant);
+    fp64_to_fp80(p, mant);
+    return 0;
+}
+
+static const VMStateInfo vmstate_fpreg_1_no_mmx = {
+    .name = "fpreg_1_no_mmx",
+    .get  = get_fpreg_1_no_mmx,
+    .put  = put_fpreg_error,
+};
+
+static bool fpregs_is_0(void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+
+    return (env->fpregs_format_vmstate == 0);
+}
+
+static bool fpregs_is_1_mmx(void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+    int guess_mmx;
+
+    guess_mmx = ((env->fptag_vmstate == 0xff) &&
+                 (env->fpus_vmstate & 0x3800) == 0);
+    return (guess_mmx && (env->fpregs_format_vmstate == 1));
+}
+
+static bool fpregs_is_1_no_mmx(void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+    int guess_mmx;
+
+    guess_mmx = ((env->fptag_vmstate == 0xff) &&
+                 (env->fpus_vmstate & 0x3800) == 0);
+    return (!guess_mmx && (env->fpregs_format_vmstate == 1));
+}
+
+#define VMSTATE_FP_REGS(_field, _state, _n)                               \
+    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0, vmstate_fpreg, FPReg), \
+    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_mmx, vmstate_fpreg_1_mmx, FPReg), \
+    VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_no_mmx, vmstate_fpreg_1_no_mmx, FPReg)
+
+static bool version_is_5(void *opaque, int version_id)
+{
+    return version_id == 5;
+}
+
+#ifdef TARGET_X86_64
+static bool less_than_7(void *opaque, int version_id)
+{
+    return version_id < 7;
+}
+
+static int get_uint64_as_uint32(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    *v = qemu_get_be32(f);
+    return 0;
+}
+
+static void put_uint64_as_uint32(QEMUFile *f, void *pv, size_t size)
+{
+    uint64_t *v = pv;
+    qemu_put_be32(f, *v);
+}
+
+static const VMStateInfo vmstate_hack_uint64_as_uint32 = {
+    .name = "uint64_as_uint32",
+    .get  = get_uint64_as_uint32,
+    .put  = put_uint64_as_uint32,
+};
+
+#define VMSTATE_HACK_UINT32(_f, _s, _t)                                  \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint64_as_uint32, uint64_t)
+#endif
+
+static void cpu_pre_save(void *opaque)
+{
+    CPUState *env = opaque;
+    int i;
+
+    /* FPU */
+    env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    env->fptag_vmstate = 0;
+    for(i = 0; i < 8; i++) {
+        env->fptag_vmstate |= ((!env->fptags[i]) << i);
+    }
+
+    env->fpregs_format_vmstate = 0;
+}
+
+static int cpu_post_load(void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+    int i;
+
+    /* XXX: restore FPU round state */
+    env->fpstt = (env->fpus_vmstate >> 11) & 7;
+    env->fpus = env->fpus_vmstate & ~0x3800;
+    env->fptag_vmstate ^= 0xff;
+    for(i = 0; i < 8; i++) {
+        env->fptags[i] = (env->fptag_vmstate >> i) & 1;
+    }
+
+    cpu_breakpoint_remove_all(env, BP_CPU);
+    cpu_watchpoint_remove_all(env, BP_CPU);
+    for (i = 0; i < 4; i++)
+        hw_breakpoint_insert(env, i);
+
+    tlb_flush(env, 1);
+    return 0;
+}
+
+static bool async_pf_msr_needed(void *opaque)
+{
+    CPUState *cpu = opaque;
+
+    return cpu->async_pf_en_msr != 0;
+}
+
+static const VMStateDescription vmstate_async_pf_msr = {
+    .name = "cpu/async_pf_msr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(async_pf_en_msr, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool fpop_ip_dp_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0;
+}
+
+static const VMStateDescription vmstate_fpop_ip_dp = {
+    .name = "cpu/fpop_ip_dp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(fpop, CPUState),
+        VMSTATE_UINT64(fpip, CPUState),
+        VMSTATE_UINT64(fpdp, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = CPU_SAVE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .pre_save = cpu_pre_save,
+    .post_load = cpu_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINTTL_ARRAY(regs, CPUState, CPU_NB_REGS),
+        VMSTATE_UINTTL(eip, CPUState),
+        VMSTATE_UINTTL(eflags, CPUState),
+        VMSTATE_UINT32(hflags, CPUState),
+        /* FPU */
+        VMSTATE_UINT16(fpuc, CPUState),
+        VMSTATE_UINT16(fpus_vmstate, CPUState),
+        VMSTATE_UINT16(fptag_vmstate, CPUState),
+        VMSTATE_UINT16(fpregs_format_vmstate, CPUState),
+        VMSTATE_FP_REGS(fpregs, CPUState, 8),
+
+        VMSTATE_SEGMENT_ARRAY(segs, CPUState, 6),
+        VMSTATE_SEGMENT(ldt, CPUState),
+        VMSTATE_SEGMENT(tr, CPUState),
+        VMSTATE_SEGMENT(gdt, CPUState),
+        VMSTATE_SEGMENT(idt, CPUState),
+
+        VMSTATE_UINT32(sysenter_cs, CPUState),
+#ifdef TARGET_X86_64
+        /* Hack: In v7 size changed from 32 to 64 bits on x86_64 */
+        VMSTATE_HACK_UINT32(sysenter_esp, CPUState, less_than_7),
+        VMSTATE_HACK_UINT32(sysenter_eip, CPUState, less_than_7),
+        VMSTATE_UINTTL_V(sysenter_esp, CPUState, 7),
+        VMSTATE_UINTTL_V(sysenter_eip, CPUState, 7),
+#else
+        VMSTATE_UINTTL(sysenter_esp, CPUState),
+        VMSTATE_UINTTL(sysenter_eip, CPUState),
+#endif
+
+        VMSTATE_UINTTL(cr[0], CPUState),
+        VMSTATE_UINTTL(cr[2], CPUState),
+        VMSTATE_UINTTL(cr[3], CPUState),
+        VMSTATE_UINTTL(cr[4], CPUState),
+        VMSTATE_UINTTL_ARRAY(dr, CPUState, 8),
+        /* MMU */
+        VMSTATE_INT32(a20_mask, CPUState),
+        /* XMM */
+        VMSTATE_UINT32(mxcsr, CPUState),
+        VMSTATE_XMM_REGS(xmm_regs, CPUState, CPU_NB_REGS),
+
+#ifdef TARGET_X86_64
+        VMSTATE_UINT64(efer, CPUState),
+        VMSTATE_UINT64(star, CPUState),
+        VMSTATE_UINT64(lstar, CPUState),
+        VMSTATE_UINT64(cstar, CPUState),
+        VMSTATE_UINT64(fmask, CPUState),
+        VMSTATE_UINT64(kernelgsbase, CPUState),
+#endif
+        VMSTATE_UINT32_V(smbase, CPUState, 4),
+
+        VMSTATE_UINT64_V(pat, CPUState, 5),
+        VMSTATE_UINT32_V(hflags2, CPUState, 5),
+
+        VMSTATE_UINT32_TEST(halted, CPUState, version_is_5),
+        VMSTATE_UINT64_V(vm_hsave, CPUState, 5),
+        VMSTATE_UINT64_V(vm_vmcb, CPUState, 5),
+        VMSTATE_UINT64_V(tsc_offset, CPUState, 5),
+        VMSTATE_UINT64_V(intercept, CPUState, 5),
+        VMSTATE_UINT16_V(intercept_cr_read, CPUState, 5),
+        VMSTATE_UINT16_V(intercept_cr_write, CPUState, 5),
+        VMSTATE_UINT16_V(intercept_dr_read, CPUState, 5),
+        VMSTATE_UINT16_V(intercept_dr_write, CPUState, 5),
+        VMSTATE_UINT32_V(intercept_exceptions, CPUState, 5),
+        VMSTATE_UINT8_V(v_tpr, CPUState, 5),
+        /* MTRRs */
+        VMSTATE_UINT64_ARRAY_V(mtrr_fixed, CPUState, 11, 8),
+        VMSTATE_UINT64_V(mtrr_deftype, CPUState, 8),
+        VMSTATE_MTRR_VARS(mtrr_var, CPUState, 8, 8),
+        /* KVM-related states */
+        VMSTATE_INT32_V(interrupt_injected, CPUState, 9),
+        VMSTATE_UINT32_V(mp_state, CPUState, 9),
+        VMSTATE_UINT64_V(tsc, CPUState, 9),
+        VMSTATE_INT32_V(exception_injected, CPUState, 11),
+        VMSTATE_UINT8_V(soft_interrupt, CPUState, 11),
+        VMSTATE_UINT8_V(nmi_injected, CPUState, 11),
+        VMSTATE_UINT8_V(nmi_pending, CPUState, 11),
+        VMSTATE_UINT8_V(has_error_code, CPUState, 11),
+        VMSTATE_UINT32_V(sipi_vector, CPUState, 11),
+        /* MCE */
+        VMSTATE_UINT64_V(mcg_cap, CPUState, 10),
+        VMSTATE_UINT64_V(mcg_status, CPUState, 10),
+        VMSTATE_UINT64_V(mcg_ctl, CPUState, 10),
+        VMSTATE_UINT64_ARRAY_V(mce_banks, CPUState, MCE_BANKS_DEF *4, 10),
+        /* rdtscp */
+        VMSTATE_UINT64_V(tsc_aux, CPUState, 11),
+        /* KVM pvclock msr */
+        VMSTATE_UINT64_V(system_time_msr, CPUState, 11),
+        VMSTATE_UINT64_V(wall_clock_msr, CPUState, 11),
+        /* XSAVE related fields */
+        VMSTATE_UINT64_V(xcr0, CPUState, 12),
+        VMSTATE_UINT64_V(xstate_bv, CPUState, 12),
+        VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
+        VMSTATE_END_OF_LIST()
+        /* The above list is not sorted /wrt version numbers, watch out! */
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_async_pf_msr,
+            .needed = async_pf_msr_needed,
+        } , {
+            .vmsd = &vmstate_fpop_ip_dp,
+            .needed = fpop_ip_dp_needed,
+        } , {
+            /* empty */
+        }
+    }
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
diff --git a/qemu-0.15.x/target-i386/op_helper.c b/qemu-0.15.x/target-i386/op_helper.c
new file mode 100644
index 0000000..315e18b
--- /dev/null
+++ b/qemu-0.15.x/target-i386/op_helper.c
@@ -0,0 +1,5719 @@
+/*
+ *  i386 helpers
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <math.h>
+#include "exec.h"
+#include "host-utils.h"
+#include "ioport.h"
+
+//#define DEBUG_PCALL
+
+
+#ifdef DEBUG_PCALL
+#  define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
+#  define LOG_PCALL_STATE(env) \
+          log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
+#else
+#  define LOG_PCALL(...) do { } while (0)
+#  define LOG_PCALL_STATE(env) do { } while (0)
+#endif
+
+
+#if 0
+#define raise_exception_err(a, b)\
+do {\
+    qemu_log("raise_exception line=%d\n", __LINE__);\
+    (raise_exception_err)(a, b);\
+} while (0)
+#endif
+
+static const uint8_t parity_table[256] = {
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+};
+
+/* modulo 17 table */
+static const uint8_t rclw_table[32] = {
+    0, 1, 2, 3, 4, 5, 6, 7,
+    8, 9,10,11,12,13,14,15,
+   16, 0, 1, 2, 3, 4, 5, 6,
+    7, 8, 9,10,11,12,13,14,
+};
+
+/* modulo 9 table */
+static const uint8_t rclb_table[32] = {
+    0, 1, 2, 3, 4, 5, 6, 7,
+    8, 0, 1, 2, 3, 4, 5, 6,
+    7, 8, 0, 1, 2, 3, 4, 5,
+    6, 7, 8, 0, 1, 2, 3, 4,
+};
+
+#define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
+#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
+#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
+
+/* broken thread support */
+
+static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void helper_lock(void)
+{
+    spin_lock(&global_cpu_lock);
+}
+
+void helper_unlock(void)
+{
+    spin_unlock(&global_cpu_lock);
+}
+
+void helper_write_eflags(target_ulong t0, uint32_t update_mask)
+{
+    load_eflags(t0, update_mask);
+}
+
+target_ulong helper_read_eflags(void)
+{
+    uint32_t eflags;
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags |= (DF & DF_MASK);
+    eflags |= env->eflags & ~(VM_MASK | RF_MASK);
+    return eflags;
+}
+
+/* return non zero if error */
+static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
+                               int selector)
+{
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    if (selector & 0x4)
+        dt = &env->ldt;
+    else
+        dt = &env->gdt;
+    index = selector & ~7;
+    if ((index + 7) > dt->limit)
+        return -1;
+    ptr = dt->base + index;
+    *e1_ptr = ldl_kernel(ptr);
+    *e2_ptr = ldl_kernel(ptr + 4);
+    return 0;
+}
+
+static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
+{
+    unsigned int limit;
+    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+    if (e2 & DESC_G_MASK)
+        limit = (limit << 12) | 0xfff;
+    return limit;
+}
+
+static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
+{
+    return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+}
+
+static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
+{
+    sc->base = get_seg_base(e1, e2);
+    sc->limit = get_seg_limit(e1, e2);
+    sc->flags = e2;
+}
+
+/* init the segment cache in vm86 mode. */
+static inline void load_seg_vm(int seg, int selector)
+{
+    selector &= 0xffff;
+    cpu_x86_load_seg_cache(env, seg, selector,
+                           (selector << 4), 0xffff, 0);
+}
+
+static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
+                                       uint32_t *esp_ptr, int dpl)
+{
+    int type, index, shift;
+
+#if 0
+    {
+        int i;
+        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
+        for(i=0;i<env->tr.limit;i++) {
+            printf("%02x ", env->tr.base[i]);
+            if ((i & 7) == 7) printf("\n");
+        }
+        printf("\n");
+    }
+#endif
+
+    if (!(env->tr.flags & DESC_P_MASK))
+        cpu_abort(env, "invalid tss");
+    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+    if ((type & 7) != 1)
+        cpu_abort(env, "invalid tss type");
+    shift = type >> 3;
+    index = (dpl * 4 + 2) << shift;
+    if (index + (4 << shift) - 1 > env->tr.limit)
+        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
+    if (shift == 0) {
+        *esp_ptr = lduw_kernel(env->tr.base + index);
+        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
+    } else {
+        *esp_ptr = ldl_kernel(env->tr.base + index);
+        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
+    }
+}
+
+/* XXX: merge with load_seg() */
+static void tss_load_seg(int seg_reg, int selector)
+{
+    uint32_t e1, e2;
+    int rpl, dpl, cpl;
+
+    if ((selector & 0xfffc) != 0) {
+        if (load_segment(&e1, &e2, selector) != 0)
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        if (!(e2 & DESC_S_MASK))
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        rpl = selector & 3;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        cpl = env->hflags & HF_CPL_MASK;
+        if (seg_reg == R_CS) {
+            if (!(e2 & DESC_CS_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            /* XXX: is it correct ? */
+            if (dpl != rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            if ((e2 & DESC_C_MASK) && dpl > rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        } else if (seg_reg == R_SS) {
+            /* SS must be writable data */
+            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            if (dpl != cpl || dpl != rpl)
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+        } else {
+            /* not readable code */
+            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
+                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            /* if data or non conforming code, checks the rights */
+            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
+                if (dpl < cpl || dpl < rpl)
+                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+            }
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+    } else {
+        if (seg_reg == R_SS || seg_reg == R_CS)
+            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
+    }
+}
+
+#define SWITCH_TSS_JMP  0
+#define SWITCH_TSS_IRET 1
+#define SWITCH_TSS_CALL 2
+
+/* XXX: restore CPU state in registers (PowerPC case) */
+static void switch_tss(int tss_selector,
+                       uint32_t e1, uint32_t e2, int source,
+                       uint32_t next_eip)
+{
+    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
+    target_ulong tss_base;
+    uint32_t new_regs[8], new_segs[6];
+    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
+    uint32_t old_eflags, eflags_mask;
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+    LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
+
+    /* if task gate, we read the TSS segment and we load it */
+    if (type == 5) {
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
+        tss_selector = e1 >> 16;
+        if (tss_selector & 4)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        if (load_segment(&e1, &e2, tss_selector) != 0)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+        if (e2 & DESC_S_MASK)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        if ((type & 7) != 1)
+            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
+    }
+
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
+
+    if (type & 8)
+        tss_limit_max = 103;
+    else
+        tss_limit_max = 43;
+    tss_limit = get_seg_limit(e1, e2);
+    tss_base = get_seg_base(e1, e2);
+    if ((tss_selector & 4) != 0 ||
+        tss_limit < tss_limit_max)
+        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+    if (old_type & 8)
+        old_tss_limit_max = 103;
+    else
+        old_tss_limit_max = 43;
+
+    /* read all the registers from the new TSS */
+    if (type & 8) {
+        /* 32 bit */
+        new_cr3 = ldl_kernel(tss_base + 0x1c);
+        new_eip = ldl_kernel(tss_base + 0x20);
+        new_eflags = ldl_kernel(tss_base + 0x24);
+        for(i = 0; i < 8; i++)
+            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
+        for(i = 0; i < 6; i++)
+            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
+        new_ldt = lduw_kernel(tss_base + 0x60);
+        new_trap = ldl_kernel(tss_base + 0x64);
+    } else {
+        /* 16 bit */
+        new_cr3 = 0;
+        new_eip = lduw_kernel(tss_base + 0x0e);
+        new_eflags = lduw_kernel(tss_base + 0x10);
+        for(i = 0; i < 8; i++)
+            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
+        for(i = 0; i < 4; i++)
+            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
+        new_ldt = lduw_kernel(tss_base + 0x2a);
+        new_segs[R_FS] = 0;
+        new_segs[R_GS] = 0;
+        new_trap = 0;
+    }
+    /* XXX: avoid a compiler warning, see
+     http://support.amd.com/us/Processor_TechDocs/24593.pdf
+     chapters 12.2.5 and 13.2.4 on how to implement TSS Trap bit */
+    (void)new_trap;
+
+    /* NOTE: we must avoid memory exceptions during the task switch,
+       so we make dummy accesses before */
+    /* XXX: it can still fail in some cases, so a bigger hack is
+       necessary to valid the TLB after having done the accesses */
+
+    v1 = ldub_kernel(env->tr.base);
+    v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
+    stb_kernel(env->tr.base, v1);
+    stb_kernel(env->tr.base + old_tss_limit_max, v2);
+
+    /* clear busy bit (it is restartable) */
+    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
+        target_ulong ptr;
+        uint32_t e2;
+        ptr = env->gdt.base + (env->tr.selector & ~7);
+        e2 = ldl_kernel(ptr + 4);
+        e2 &= ~DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+    old_eflags = compute_eflags();
+    if (source == SWITCH_TSS_IRET)
+        old_eflags &= ~NT_MASK;
+
+    /* save the current state in the old TSS */
+    if (type & 8) {
+        /* 32 bit */
+        stl_kernel(env->tr.base + 0x20, next_eip);
+        stl_kernel(env->tr.base + 0x24, old_eflags);
+        stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
+        stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
+        stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
+        stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
+        stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
+        stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
+        stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
+        stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
+        for(i = 0; i < 6; i++)
+            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
+    } else {
+        /* 16 bit */
+        stw_kernel(env->tr.base + 0x0e, next_eip);
+        stw_kernel(env->tr.base + 0x10, old_eflags);
+        stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
+        stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
+        stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
+        stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
+        stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
+        stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
+        stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
+        stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
+        for(i = 0; i < 4; i++)
+            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
+    }
+
+    /* now if an exception occurs, it will occurs in the next task
+       context */
+
+    if (source == SWITCH_TSS_CALL) {
+        stw_kernel(tss_base, env->tr.selector);
+        new_eflags |= NT_MASK;
+    }
+
+    /* set busy bit */
+    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
+        target_ulong ptr;
+        uint32_t e2;
+        ptr = env->gdt.base + (tss_selector & ~7);
+        e2 = ldl_kernel(ptr + 4);
+        e2 |= DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+
+    /* set the new CPU state */
+    /* from this point, any exception which occurs can give problems */
+    env->cr[0] |= CR0_TS_MASK;
+    env->hflags |= HF_TS_MASK;
+    env->tr.selector = tss_selector;
+    env->tr.base = tss_base;
+    env->tr.limit = tss_limit;
+    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
+
+    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
+        cpu_x86_update_cr3(env, new_cr3);
+    }
+
+    /* load all registers without an exception, then reload them with
+       possible exception */
+    env->eip = new_eip;
+    eflags_mask = TF_MASK | AC_MASK | ID_MASK |
+        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
+    if (!(type & 8))
+        eflags_mask &= 0xffff;
+    load_eflags(new_eflags, eflags_mask);
+    /* XXX: what to do in 16 bit case ? */
+    EAX = new_regs[0];
+    ECX = new_regs[1];
+    EDX = new_regs[2];
+    EBX = new_regs[3];
+    ESP = new_regs[4];
+    EBP = new_regs[5];
+    ESI = new_regs[6];
+    EDI = new_regs[7];
+    if (new_eflags & VM_MASK) {
+        for(i = 0; i < 6; i++)
+            load_seg_vm(i, new_segs[i]);
+        /* in vm86, CPL is always 3 */
+        cpu_x86_set_cpl(env, 3);
+    } else {
+        /* CPL is set the RPL of CS */
+        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
+        /* first just selectors as the rest may trigger exceptions */
+        for(i = 0; i < 6; i++)
+            cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
+    }
+
+    env->ldt.selector = new_ldt & ~4;
+    env->ldt.base = 0;
+    env->ldt.limit = 0;
+    env->ldt.flags = 0;
+
+    /* load the LDT */
+    if (new_ldt & 4)
+        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+
+    if ((new_ldt & 0xfffc) != 0) {
+        dt = &env->gdt;
+        index = new_ldt & ~7;
+        if ((index + 7) > dt->limit)
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
+        load_seg_cache_raw_dt(&env->ldt, e1, e2);
+    }
+
+    /* load the segments */
+    if (!(new_eflags & VM_MASK)) {
+        tss_load_seg(R_CS, new_segs[R_CS]);
+        tss_load_seg(R_SS, new_segs[R_SS]);
+        tss_load_seg(R_ES, new_segs[R_ES]);
+        tss_load_seg(R_DS, new_segs[R_DS]);
+        tss_load_seg(R_FS, new_segs[R_FS]);
+        tss_load_seg(R_GS, new_segs[R_GS]);
+    }
+
+    /* check that EIP is in the CS segment limits */
+    if (new_eip > env->segs[R_CS].limit) {
+        /* XXX: different exception if CALL ? */
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+
+#ifndef CONFIG_USER_ONLY
+    /* reset local breakpoints */
+    if (env->dr[7] & 0x55) {
+        for (i = 0; i < 4; i++) {
+            if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
+                hw_breakpoint_remove(env, i);
+        }
+        env->dr[7] &= ~0x55;
+    }
+#endif
+}
+
+/* check if Port I/O is allowed in TSS */
+static inline void check_io(int addr, int size)
+{
+    int io_offset, val, mask;
+
+    /* TSS must be a valid 32 bit one */
+    if (!(env->tr.flags & DESC_P_MASK) ||
+        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+        env->tr.limit < 103)
+        goto fail;
+    io_offset = lduw_kernel(env->tr.base + 0x66);
+    io_offset += (addr >> 3);
+    /* Note: the check needs two bytes */
+    if ((io_offset + 1) > env->tr.limit)
+        goto fail;
+    val = lduw_kernel(env->tr.base + io_offset);
+    val >>= (addr & 7);
+    mask = (1 << size) - 1;
+    /* all bits must be zero to allow the I/O */
+    if ((val & mask) != 0) {
+    fail:
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+}
+
+void helper_check_iob(uint32_t t0)
+{
+    check_io(t0, 1);
+}
+
+void helper_check_iow(uint32_t t0)
+{
+    check_io(t0, 2);
+}
+
+void helper_check_iol(uint32_t t0)
+{
+    check_io(t0, 4);
+}
+
+void helper_outb(uint32_t port, uint32_t data)
+{
+    cpu_outb(port, data & 0xff);
+}
+
+target_ulong helper_inb(uint32_t port)
+{
+    return cpu_inb(port);
+}
+
+void helper_outw(uint32_t port, uint32_t data)
+{
+    cpu_outw(port, data & 0xffff);
+}
+
+target_ulong helper_inw(uint32_t port)
+{
+    return cpu_inw(port);
+}
+
+void helper_outl(uint32_t port, uint32_t data)
+{
+    cpu_outl(port, data);
+}
+
+target_ulong helper_inl(uint32_t port)
+{
+    return cpu_inl(port);
+}
+
+static inline unsigned int get_sp_mask(unsigned int e2)
+{
+    if (e2 & DESC_B_MASK)
+        return 0xffffffff;
+    else
+        return 0xffff;
+}
+
+static int exeption_has_error_code(int intno)
+{
+        switch(intno) {
+        case 8:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 17:
+            return 1;
+        }
+	return 0;
+}
+
+#ifdef TARGET_X86_64
+#define SET_ESP(val, sp_mask)\
+do {\
+    if ((sp_mask) == 0xffff)\
+        ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
+    else if ((sp_mask) == 0xffffffffLL)\
+        ESP = (uint32_t)(val);\
+    else\
+        ESP = (val);\
+} while (0)
+#else
+#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
+#endif
+
+/* in 64-bit machines, this can overflow. So this segment addition macro
+ * can be used to trim the value to 32-bit whenever needed */
+#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
+
+/* XXX: add a is_user flag to have proper security support */
+#define PUSHW(ssp, sp, sp_mask, val)\
+{\
+    sp -= 2;\
+    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
+}
+
+#define PUSHL(ssp, sp, sp_mask, val)\
+{\
+    sp -= 4;\
+    stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
+}
+
+#define POPW(ssp, sp, sp_mask, val)\
+{\
+    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
+    sp += 2;\
+}
+
+#define POPL(ssp, sp, sp_mask, val)\
+{\
+    val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
+    sp += 4;\
+}
+
+/* protected mode interrupt */
+static void do_interrupt_protected(int intno, int is_int, int error_code,
+                                   unsigned int next_eip, int is_hw)
+{
+    SegmentCache *dt;
+    target_ulong ptr, ssp;
+    int type, dpl, selector, ss_dpl, cpl;
+    int has_error_code, new_stack, shift;
+    uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
+    uint32_t old_eip, sp_mask;
+
+    has_error_code = 0;
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+
+    dt = &env->idt;
+    if (intno * 8 + 7 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    ptr = dt->base + intno * 8;
+    e1 = ldl_kernel(ptr);
+    e2 = ldl_kernel(ptr + 4);
+    /* check gate type */
+    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+    switch(type) {
+    case 5: /* task gate */
+        /* must do that check here to return the correct error code */
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
+        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
+        if (has_error_code) {
+            int type;
+            uint32_t mask;
+            /* push the error code */
+            type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+            shift = type >> 3;
+            if (env->segs[R_SS].flags & DESC_B_MASK)
+                mask = 0xffffffff;
+            else
+                mask = 0xffff;
+            esp = (ESP - (2 << shift)) & mask;
+            ssp = env->segs[R_SS].base + esp;
+            if (shift)
+                stl_kernel(ssp, error_code);
+            else
+                stw_kernel(ssp, error_code);
+            SET_ESP(esp, mask);
+        }
+        return;
+    case 6: /* 286 interrupt gate */
+    case 7: /* 286 trap gate */
+    case 14: /* 386 interrupt gate */
+    case 15: /* 386 trap gate */
+        break;
+    default:
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+        break;
+    }
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    /* check valid bit */
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
+    selector = e1 >> 16;
+    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+    if ((selector & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+
+    if (load_segment(&e1, &e2, selector) != 0)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (dpl > cpl)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+        /* to inner privilege */
+        get_ss_esp_from_tss(&ss, &esp, dpl);
+        if ((ss & 0xfffc) == 0)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if ((ss & 3) != dpl)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+        if (ss_dpl != dpl)
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (!(ss_e2 & DESC_S_MASK) ||
+            (ss_e2 & DESC_CS_MASK) ||
+            !(ss_e2 & DESC_W_MASK))
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        if (!(ss_e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+        new_stack = 1;
+        sp_mask = get_sp_mask(ss_e2);
+        ssp = get_seg_base(ss_e1, ss_e2);
+    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
+        /* to same privilege */
+        if (env->eflags & VM_MASK)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0;
+        sp_mask = get_sp_mask(env->segs[R_SS].flags);
+        ssp = env->segs[R_SS].base;
+        esp = ESP;
+        dpl = cpl;
+    } else {
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0; /* avoid warning */
+        sp_mask = 0; /* avoid warning */
+        ssp = 0; /* avoid warning */
+        esp = 0; /* avoid warning */
+    }
+
+    shift = type >> 3;
+
+#if 0
+    /* XXX: check that enough room is available */
+    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
+    if (env->eflags & VM_MASK)
+        push_size += 8;
+    push_size <<= shift;
+#endif
+    if (shift == 1) {
+        if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
+            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
+            PUSHL(ssp, esp, sp_mask, ESP);
+        }
+        PUSHL(ssp, esp, sp_mask, compute_eflags());
+        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
+        PUSHL(ssp, esp, sp_mask, old_eip);
+        if (has_error_code) {
+            PUSHL(ssp, esp, sp_mask, error_code);
+        }
+    } else {
+        if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
+            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
+            PUSHW(ssp, esp, sp_mask, ESP);
+        }
+        PUSHW(ssp, esp, sp_mask, compute_eflags());
+        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
+        PUSHW(ssp, esp, sp_mask, old_eip);
+        if (has_error_code) {
+            PUSHW(ssp, esp, sp_mask, error_code);
+        }
+    }
+
+    if (new_stack) {
+        if (env->eflags & VM_MASK) {
+            cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
+            cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
+        }
+        ss = (ss & ~3) | dpl;
+        cpu_x86_load_seg_cache(env, R_SS, ss,
+                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
+    }
+    SET_ESP(esp, sp_mask);
+
+    selector = (selector & ~3) | dpl;
+    cpu_x86_load_seg_cache(env, R_CS, selector,
+                   get_seg_base(e1, e2),
+                   get_seg_limit(e1, e2),
+                   e2);
+    cpu_x86_set_cpl(env, dpl);
+    env->eip = offset;
+
+    /* interrupt gate clear IF mask */
+    if ((type & 1) == 0) {
+        env->eflags &= ~IF_MASK;
+    }
+    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+}
+
+#ifdef TARGET_X86_64
+
+#define PUSHQ(sp, val)\
+{\
+    sp -= 8;\
+    stq_kernel(sp, (val));\
+}
+
+#define POPQ(sp, val)\
+{\
+    val = ldq_kernel(sp);\
+    sp += 8;\
+}
+
+static inline target_ulong get_rsp_from_tss(int level)
+{
+    int index;
+
+#if 0
+    printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
+           env->tr.base, env->tr.limit);
+#endif
+
+    if (!(env->tr.flags & DESC_P_MASK))
+        cpu_abort(env, "invalid tss");
+    index = 8 * level + 4;
+    if ((index + 7) > env->tr.limit)
+        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
+    return ldq_kernel(env->tr.base + index);
+}
+
+/* 64 bit interrupt */
+static void do_interrupt64(int intno, int is_int, int error_code,
+                           target_ulong next_eip, int is_hw)
+{
+    SegmentCache *dt;
+    target_ulong ptr;
+    int type, dpl, selector, cpl, ist;
+    int has_error_code, new_stack;
+    uint32_t e1, e2, e3, ss;
+    target_ulong old_eip, esp, offset;
+
+    has_error_code = 0;
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+
+    dt = &env->idt;
+    if (intno * 16 + 15 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+    ptr = dt->base + intno * 16;
+    e1 = ldl_kernel(ptr);
+    e2 = ldl_kernel(ptr + 4);
+    e3 = ldl_kernel(ptr + 8);
+    /* check gate type */
+    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+    switch(type) {
+    case 14: /* 386 interrupt gate */
+    case 15: /* 386 trap gate */
+        break;
+    default:
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+        break;
+    }
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+    /* check valid bit */
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
+    selector = e1 >> 16;
+    offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+    ist = e2 & 7;
+    if ((selector & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+
+    if (load_segment(&e1, &e2, selector) != 0)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (dpl > cpl)
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+    if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+    if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
+        /* to inner privilege */
+        if (ist != 0)
+            esp = get_rsp_from_tss(ist + 3);
+        else
+            esp = get_rsp_from_tss(dpl);
+        esp &= ~0xfLL; /* align stack */
+        ss = 0;
+        new_stack = 1;
+    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
+        /* to same privilege */
+        if (env->eflags & VM_MASK)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0;
+        if (ist != 0)
+            esp = get_rsp_from_tss(ist + 3);
+        else
+            esp = ESP;
+        esp &= ~0xfLL; /* align stack */
+        dpl = cpl;
+    } else {
+        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        new_stack = 0; /* avoid warning */
+        esp = 0; /* avoid warning */
+    }
+
+    PUSHQ(esp, env->segs[R_SS].selector);
+    PUSHQ(esp, ESP);
+    PUSHQ(esp, compute_eflags());
+    PUSHQ(esp, env->segs[R_CS].selector);
+    PUSHQ(esp, old_eip);
+    if (has_error_code) {
+        PUSHQ(esp, error_code);
+    }
+
+    if (new_stack) {
+        ss = 0 | dpl;
+        cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
+    }
+    ESP = esp;
+
+    selector = (selector & ~3) | dpl;
+    cpu_x86_load_seg_cache(env, R_CS, selector,
+                   get_seg_base(e1, e2),
+                   get_seg_limit(e1, e2),
+                   e2);
+    cpu_x86_set_cpl(env, dpl);
+    env->eip = offset;
+
+    /* interrupt gate clear IF mask */
+    if ((type & 1) == 0) {
+        env->eflags &= ~IF_MASK;
+    }
+    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+}
+#endif
+
+#ifdef TARGET_X86_64
+#if defined(CONFIG_USER_ONLY)
+void helper_syscall(int next_eip_addend)
+{
+    env->exception_index = EXCP_SYSCALL;
+    env->exception_next_eip = env->eip + next_eip_addend;
+    cpu_loop_exit(env);
+}
+#else
+void helper_syscall(int next_eip_addend)
+{
+    int selector;
+
+    if (!(env->efer & MSR_EFER_SCE)) {
+        raise_exception_err(EXCP06_ILLOP, 0);
+    }
+    selector = (env->star >> 32) & 0xffff;
+    if (env->hflags & HF_LMA_MASK) {
+        int code64;
+
+        ECX = env->eip + next_eip_addend;
+        env->regs[11] = compute_eflags();
+
+        code64 = env->hflags & HF_CS64_MASK;
+
+        cpu_x86_set_cpl(env, 0);
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
+                               DESC_G_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags &= ~env->fmask;
+        load_eflags(env->eflags, 0);
+        if (code64)
+            env->eip = env->lstar;
+        else
+            env->eip = env->cstar;
+    } else {
+        ECX = (uint32_t)(env->eip + next_eip_addend);
+
+        cpu_x86_set_cpl(env, 0);
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
+        env->eip = (uint32_t)env->star;
+    }
+}
+#endif
+#endif
+
+#ifdef TARGET_X86_64
+void helper_sysret(int dflag)
+{
+    int cpl, selector;
+
+    if (!(env->efer & MSR_EFER_SCE)) {
+        raise_exception_err(EXCP06_ILLOP, 0);
+    }
+    cpl = env->hflags & HF_CPL_MASK;
+    if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    selector = (env->star >> 48) & 0xffff;
+    if (env->hflags & HF_LMA_MASK) {
+        if (dflag == 2) {
+            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
+                                   0, 0xffffffff,
+                                   DESC_G_MASK | DESC_P_MASK |
+                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
+                                   DESC_L_MASK);
+            env->eip = ECX;
+        } else {
+            cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                                   0, 0xffffffff,
+                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+            env->eip = (uint32_t)ECX;
+        }
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
+                    IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
+        cpu_x86_set_cpl(env, 3);
+    } else {
+        cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        env->eip = (uint32_t)ECX;
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+        env->eflags |= IF_MASK;
+        cpu_x86_set_cpl(env, 3);
+    }
+}
+#endif
+
+/* real mode interrupt */
+static void do_interrupt_real(int intno, int is_int, int error_code,
+                              unsigned int next_eip)
+{
+    SegmentCache *dt;
+    target_ulong ptr, ssp;
+    int selector;
+    uint32_t offset, esp;
+    uint32_t old_cs, old_eip;
+
+    /* real mode (simpler !) */
+    dt = &env->idt;
+    if (intno * 4 + 3 > dt->limit)
+        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+    ptr = dt->base + intno * 4;
+    offset = lduw_kernel(ptr);
+    selector = lduw_kernel(ptr + 2);
+    esp = ESP;
+    ssp = env->segs[R_SS].base;
+    if (is_int)
+        old_eip = next_eip;
+    else
+        old_eip = env->eip;
+    old_cs = env->segs[R_CS].selector;
+    /* XXX: use SS segment size ? */
+    PUSHW(ssp, esp, 0xffff, compute_eflags());
+    PUSHW(ssp, esp, 0xffff, old_cs);
+    PUSHW(ssp, esp, 0xffff, old_eip);
+
+    /* update processor state */
+    ESP = (ESP & ~0xffff) | (esp & 0xffff);
+    env->eip = offset;
+    env->segs[R_CS].selector = selector;
+    env->segs[R_CS].base = (selector << 4);
+    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
+}
+
+#if defined(CONFIG_USER_ONLY)
+/* fake user mode interrupt */
+static void do_interrupt_user(int intno, int is_int, int error_code,
+                              target_ulong next_eip)
+{
+    SegmentCache *dt;
+    target_ulong ptr;
+    int dpl, cpl, shift;
+    uint32_t e2;
+
+    dt = &env->idt;
+    if (env->hflags & HF_LMA_MASK) {
+        shift = 4;
+    } else {
+        shift = 3;
+    }
+    ptr = dt->base + (intno << shift);
+    e2 = ldl_kernel(ptr + 4);
+
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    /* check privilege if software int */
+    if (is_int && dpl < cpl)
+        raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
+
+    /* Since we emulate only user space, we cannot do more than
+       exiting the emulation with the suitable exception and error
+       code */
+    if (is_int)
+        EIP = next_eip;
+}
+
+#else
+
+static void handle_even_inj(int intno, int is_int, int error_code,
+		int is_hw, int rm)
+{
+    uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (!(event_inj & SVM_EVTINJ_VALID)) {
+	    int type;
+	    if (is_int)
+		    type = SVM_EVTINJ_TYPE_SOFT;
+	    else
+		    type = SVM_EVTINJ_TYPE_EXEPT;
+	    event_inj = intno | type | SVM_EVTINJ_VALID;
+	    if (!rm && exeption_has_error_code(intno)) {
+		    event_inj |= SVM_EVTINJ_VALID_ERR;
+		    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
+	    }
+	    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
+    }
+}
+#endif
+
+/*
+ * Begin execution of an interruption. is_int is TRUE if coming from
+ * the int instruction. next_eip is the EIP value AFTER the interrupt
+ * instruction. It is only relevant if is_int is TRUE.
+ */
+static void do_interrupt_all(int intno, int is_int, int error_code,
+                             target_ulong next_eip, int is_hw)
+{
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        if ((env->cr[0] & CR0_PE_MASK)) {
+            static int count;
+            qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
+                    count, intno, error_code, is_int,
+                    env->hflags & HF_CPL_MASK,
+                    env->segs[R_CS].selector, EIP,
+                    (int)env->segs[R_CS].base + EIP,
+                    env->segs[R_SS].selector, ESP);
+            if (intno == 0x0e) {
+                qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
+            } else {
+                qemu_log(" EAX=" TARGET_FMT_lx, EAX);
+            }
+            qemu_log("\n");
+            log_cpu_state(env, X86_DUMP_CCOP);
+#if 0
+            {
+                int i;
+                target_ulong ptr;
+                qemu_log("       code=");
+                ptr = env->segs[R_CS].base + env->eip;
+                for(i = 0; i < 16; i++) {
+                    qemu_log(" %02x", ldub(ptr + i));
+                }
+                qemu_log("\n");
+            }
+#endif
+            count++;
+        }
+    }
+    if (env->cr[0] & CR0_PE_MASK) {
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 0);
+#endif
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
+        } else
+#endif
+        {
+            do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
+        }
+    } else {
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 1);
+#endif
+        do_interrupt_real(intno, is_int, error_code, next_eip);
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    if (env->hflags & HF_SVMI_MASK) {
+	    uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+	    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
+    }
+#endif
+}
+
+void do_interrupt(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+#if defined(CONFIG_USER_ONLY)
+    /* if user mode only, we simulate a fake exception
+       which will be handled outside the cpu execution
+       loop */
+    do_interrupt_user(env->exception_index,
+                      env->exception_is_int,
+                      env->error_code,
+                      env->exception_next_eip);
+    /* successfully delivered */
+    env->old_exception = -1;
+#else
+    /* simulate a real cpu exception. On i386, it can
+       trigger new exceptions, but we do not handle
+       double or triple faults yet. */
+    do_interrupt_all(env->exception_index,
+                     env->exception_is_int,
+                     env->error_code,
+                     env->exception_next_eip, 0);
+    /* successfully delivered */
+    env->old_exception = -1;
+#endif
+    env = saved_env;
+}
+
+void do_interrupt_x86_hardirq(CPUState *env1, int intno, int is_hw)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(intno, 0, 0, 0, is_hw);
+    env = saved_env;
+}
+
+/* This should come from sysemu.h - if we could include it here... */
+void qemu_system_reset_request(void);
+
+/*
+ * Check nested exceptions and change to double or triple fault if
+ * needed. It should only be called, if this is not an interrupt.
+ * Returns the new exception number.
+ */
+static int check_exception(int intno, int *error_code)
+{
+    int first_contributory = env->old_exception == 0 ||
+                              (env->old_exception >= 10 &&
+                               env->old_exception <= 13);
+    int second_contributory = intno == 0 ||
+                               (intno >= 10 && intno <= 13);
+
+    qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
+                env->old_exception, intno);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (env->old_exception == EXCP08_DBLE) {
+        if (env->hflags & HF_SVMI_MASK)
+            helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
+
+        qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
+
+        qemu_system_reset_request();
+        return EXCP_HLT;
+    }
+#endif
+
+    if ((first_contributory && second_contributory)
+        || (env->old_exception == EXCP0E_PAGE &&
+            (second_contributory || (intno == EXCP0E_PAGE)))) {
+        intno = EXCP08_DBLE;
+        *error_code = 0;
+    }
+
+    if (second_contributory || (intno == EXCP0E_PAGE) ||
+        (intno == EXCP08_DBLE))
+        env->old_exception = intno;
+
+    return intno;
+}
+
+/*
+ * Signal an interruption. It is executed in the main CPU loop.
+ * is_int is TRUE if coming from the int instruction. next_eip is the
+ * EIP value AFTER the interrupt instruction. It is only relevant if
+ * is_int is TRUE.
+ */
+static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
+                                          int next_eip_addend)
+{
+    if (!is_int) {
+        helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
+        intno = check_exception(intno, &error_code);
+    } else {
+        helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
+    }
+
+    env->exception_index = intno;
+    env->error_code = error_code;
+    env->exception_is_int = is_int;
+    env->exception_next_eip = env->eip + next_eip_addend;
+    cpu_loop_exit(env);
+}
+
+/* shortcuts to generate exceptions */
+
+void raise_exception_err(int exception_index, int error_code)
+{
+    raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+void raise_exception(int exception_index)
+{
+    raise_interrupt(exception_index, 0, 0, 0);
+}
+
+void raise_exception_env(int exception_index, CPUState *nenv)
+{
+    env = nenv;
+    raise_exception(exception_index);
+}
+/* SMM support */
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_smm_enter(CPUState *env1)
+{
+}
+
+void helper_rsm(void)
+{
+}
+
+#else
+
+#ifdef TARGET_X86_64
+#define SMM_REVISION_ID 0x00020064
+#else
+#define SMM_REVISION_ID 0x00020000
+#endif
+
+void do_smm_enter(CPUState *env1)
+{
+    target_ulong sm_state;
+    SegmentCache *dt;
+    int i, offset;
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+
+    qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
+
+    env->hflags |= HF_SMM_MASK;
+    cpu_smm_update(env);
+
+    sm_state = env->smbase + 0x8000;
+
+#ifdef TARGET_X86_64
+    for(i = 0; i < 6; i++) {
+        dt = &env->segs[i];
+        offset = 0x7e00 + i * 16;
+        stw_phys(sm_state + offset, dt->selector);
+        stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
+        stl_phys(sm_state + offset + 4, dt->limit);
+        stq_phys(sm_state + offset + 8, dt->base);
+    }
+
+    stq_phys(sm_state + 0x7e68, env->gdt.base);
+    stl_phys(sm_state + 0x7e64, env->gdt.limit);
+
+    stw_phys(sm_state + 0x7e70, env->ldt.selector);
+    stq_phys(sm_state + 0x7e78, env->ldt.base);
+    stl_phys(sm_state + 0x7e74, env->ldt.limit);
+    stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
+
+    stq_phys(sm_state + 0x7e88, env->idt.base);
+    stl_phys(sm_state + 0x7e84, env->idt.limit);
+
+    stw_phys(sm_state + 0x7e90, env->tr.selector);
+    stq_phys(sm_state + 0x7e98, env->tr.base);
+    stl_phys(sm_state + 0x7e94, env->tr.limit);
+    stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
+
+    stq_phys(sm_state + 0x7ed0, env->efer);
+
+    stq_phys(sm_state + 0x7ff8, EAX);
+    stq_phys(sm_state + 0x7ff0, ECX);
+    stq_phys(sm_state + 0x7fe8, EDX);
+    stq_phys(sm_state + 0x7fe0, EBX);
+    stq_phys(sm_state + 0x7fd8, ESP);
+    stq_phys(sm_state + 0x7fd0, EBP);
+    stq_phys(sm_state + 0x7fc8, ESI);
+    stq_phys(sm_state + 0x7fc0, EDI);
+    for(i = 8; i < 16; i++)
+        stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
+    stq_phys(sm_state + 0x7f78, env->eip);
+    stl_phys(sm_state + 0x7f70, compute_eflags());
+    stl_phys(sm_state + 0x7f68, env->dr[6]);
+    stl_phys(sm_state + 0x7f60, env->dr[7]);
+
+    stl_phys(sm_state + 0x7f48, env->cr[4]);
+    stl_phys(sm_state + 0x7f50, env->cr[3]);
+    stl_phys(sm_state + 0x7f58, env->cr[0]);
+
+    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
+    stl_phys(sm_state + 0x7f00, env->smbase);
+#else
+    stl_phys(sm_state + 0x7ffc, env->cr[0]);
+    stl_phys(sm_state + 0x7ff8, env->cr[3]);
+    stl_phys(sm_state + 0x7ff4, compute_eflags());
+    stl_phys(sm_state + 0x7ff0, env->eip);
+    stl_phys(sm_state + 0x7fec, EDI);
+    stl_phys(sm_state + 0x7fe8, ESI);
+    stl_phys(sm_state + 0x7fe4, EBP);
+    stl_phys(sm_state + 0x7fe0, ESP);
+    stl_phys(sm_state + 0x7fdc, EBX);
+    stl_phys(sm_state + 0x7fd8, EDX);
+    stl_phys(sm_state + 0x7fd4, ECX);
+    stl_phys(sm_state + 0x7fd0, EAX);
+    stl_phys(sm_state + 0x7fcc, env->dr[6]);
+    stl_phys(sm_state + 0x7fc8, env->dr[7]);
+
+    stl_phys(sm_state + 0x7fc4, env->tr.selector);
+    stl_phys(sm_state + 0x7f64, env->tr.base);
+    stl_phys(sm_state + 0x7f60, env->tr.limit);
+    stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
+
+    stl_phys(sm_state + 0x7fc0, env->ldt.selector);
+    stl_phys(sm_state + 0x7f80, env->ldt.base);
+    stl_phys(sm_state + 0x7f7c, env->ldt.limit);
+    stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
+
+    stl_phys(sm_state + 0x7f74, env->gdt.base);
+    stl_phys(sm_state + 0x7f70, env->gdt.limit);
+
+    stl_phys(sm_state + 0x7f58, env->idt.base);
+    stl_phys(sm_state + 0x7f54, env->idt.limit);
+
+    for(i = 0; i < 6; i++) {
+        dt = &env->segs[i];
+        if (i < 3)
+            offset = 0x7f84 + i * 12;
+        else
+            offset = 0x7f2c + (i - 3) * 12;
+        stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
+        stl_phys(sm_state + offset + 8, dt->base);
+        stl_phys(sm_state + offset + 4, dt->limit);
+        stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
+    }
+    stl_phys(sm_state + 0x7f14, env->cr[4]);
+
+    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
+    stl_phys(sm_state + 0x7ef8, env->smbase);
+#endif
+    /* init SMM cpu state */
+
+#ifdef TARGET_X86_64
+    cpu_load_efer(env, 0);
+#endif
+    load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->eip = 0x00008000;
+    cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
+                           0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
+    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
+
+    cpu_x86_update_cr0(env,
+                       env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
+    cpu_x86_update_cr4(env, 0);
+    env->dr[7] = 0x00000400;
+    CC_OP = CC_OP_EFLAGS;
+    env = saved_env;
+}
+
+void helper_rsm(void)
+{
+    target_ulong sm_state;
+    int i, offset;
+    uint32_t val;
+
+    sm_state = env->smbase + 0x8000;
+#ifdef TARGET_X86_64
+    cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
+
+    for(i = 0; i < 6; i++) {
+        offset = 0x7e00 + i * 16;
+        cpu_x86_load_seg_cache(env, i,
+                               lduw_phys(sm_state + offset),
+                               ldq_phys(sm_state + offset + 8),
+                               ldl_phys(sm_state + offset + 4),
+                               (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
+    }
+
+    env->gdt.base = ldq_phys(sm_state + 0x7e68);
+    env->gdt.limit = ldl_phys(sm_state + 0x7e64);
+
+    env->ldt.selector = lduw_phys(sm_state + 0x7e70);
+    env->ldt.base = ldq_phys(sm_state + 0x7e78);
+    env->ldt.limit = ldl_phys(sm_state + 0x7e74);
+    env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
+
+    env->idt.base = ldq_phys(sm_state + 0x7e88);
+    env->idt.limit = ldl_phys(sm_state + 0x7e84);
+
+    env->tr.selector = lduw_phys(sm_state + 0x7e90);
+    env->tr.base = ldq_phys(sm_state + 0x7e98);
+    env->tr.limit = ldl_phys(sm_state + 0x7e94);
+    env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
+
+    EAX = ldq_phys(sm_state + 0x7ff8);
+    ECX = ldq_phys(sm_state + 0x7ff0);
+    EDX = ldq_phys(sm_state + 0x7fe8);
+    EBX = ldq_phys(sm_state + 0x7fe0);
+    ESP = ldq_phys(sm_state + 0x7fd8);
+    EBP = ldq_phys(sm_state + 0x7fd0);
+    ESI = ldq_phys(sm_state + 0x7fc8);
+    EDI = ldq_phys(sm_state + 0x7fc0);
+    for(i = 8; i < 16; i++)
+        env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
+    env->eip = ldq_phys(sm_state + 0x7f78);
+    load_eflags(ldl_phys(sm_state + 0x7f70),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->dr[6] = ldl_phys(sm_state + 0x7f68);
+    env->dr[7] = ldl_phys(sm_state + 0x7f60);
+
+    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
+    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
+    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
+
+    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
+    if (val & 0x20000) {
+        env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
+    }
+#else
+    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
+    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
+    load_eflags(ldl_phys(sm_state + 0x7ff4),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    env->eip = ldl_phys(sm_state + 0x7ff0);
+    EDI = ldl_phys(sm_state + 0x7fec);
+    ESI = ldl_phys(sm_state + 0x7fe8);
+    EBP = ldl_phys(sm_state + 0x7fe4);
+    ESP = ldl_phys(sm_state + 0x7fe0);
+    EBX = ldl_phys(sm_state + 0x7fdc);
+    EDX = ldl_phys(sm_state + 0x7fd8);
+    ECX = ldl_phys(sm_state + 0x7fd4);
+    EAX = ldl_phys(sm_state + 0x7fd0);
+    env->dr[6] = ldl_phys(sm_state + 0x7fcc);
+    env->dr[7] = ldl_phys(sm_state + 0x7fc8);
+
+    env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
+    env->tr.base = ldl_phys(sm_state + 0x7f64);
+    env->tr.limit = ldl_phys(sm_state + 0x7f60);
+    env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
+
+    env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
+    env->ldt.base = ldl_phys(sm_state + 0x7f80);
+    env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
+    env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
+
+    env->gdt.base = ldl_phys(sm_state + 0x7f74);
+    env->gdt.limit = ldl_phys(sm_state + 0x7f70);
+
+    env->idt.base = ldl_phys(sm_state + 0x7f58);
+    env->idt.limit = ldl_phys(sm_state + 0x7f54);
+
+    for(i = 0; i < 6; i++) {
+        if (i < 3)
+            offset = 0x7f84 + i * 12;
+        else
+            offset = 0x7f2c + (i - 3) * 12;
+        cpu_x86_load_seg_cache(env, i,
+                               ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
+                               ldl_phys(sm_state + offset + 8),
+                               ldl_phys(sm_state + offset + 4),
+                               (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
+    }
+    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
+
+    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
+    if (val & 0x20000) {
+        env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
+    }
+#endif
+    CC_OP = CC_OP_EFLAGS;
+    env->hflags &= ~HF_SMM_MASK;
+    cpu_smm_update(env);
+
+    qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+
+/* division, flags are undefined */
+
+void helper_divb_AL(target_ulong t0)
+{
+    unsigned int num, den, q, r;
+
+    num = (EAX & 0xffff);
+    den = (t0 & 0xff);
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q > 0xff)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xff;
+    r = (num % den) & 0xff;
+    EAX = (EAX & ~0xffff) | (r << 8) | q;
+}
+
+void helper_idivb_AL(target_ulong t0)
+{
+    int num, den, q, r;
+
+    num = (int16_t)EAX;
+    den = (int8_t)t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q != (int8_t)q)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xff;
+    r = (num % den) & 0xff;
+    EAX = (EAX & ~0xffff) | (r << 8) | q;
+}
+
+void helper_divw_AX(target_ulong t0)
+{
+    unsigned int num, den, q, r;
+
+    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+    den = (t0 & 0xffff);
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q > 0xffff)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xffff;
+    r = (num % den) & 0xffff;
+    EAX = (EAX & ~0xffff) | q;
+    EDX = (EDX & ~0xffff) | r;
+}
+
+void helper_idivw_AX(target_ulong t0)
+{
+    int num, den, q, r;
+
+    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+    den = (int16_t)t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    if (q != (int16_t)q)
+        raise_exception(EXCP00_DIVZ);
+    q &= 0xffff;
+    r = (num % den) & 0xffff;
+    EAX = (EAX & ~0xffff) | q;
+    EDX = (EDX & ~0xffff) | r;
+}
+
+void helper_divl_EAX(target_ulong t0)
+{
+    unsigned int den, r;
+    uint64_t num, q;
+
+    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+    den = t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    r = (num % den);
+    if (q > 0xffffffff)
+        raise_exception(EXCP00_DIVZ);
+    EAX = (uint32_t)q;
+    EDX = (uint32_t)r;
+}
+
+void helper_idivl_EAX(target_ulong t0)
+{
+    int den, r;
+    int64_t num, q;
+
+    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+    den = t0;
+    if (den == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    q = (num / den);
+    r = (num % den);
+    if (q != (int32_t)q)
+        raise_exception(EXCP00_DIVZ);
+    EAX = (uint32_t)q;
+    EDX = (uint32_t)r;
+}
+
+/* bcd */
+
+/* XXX: exception */
+void helper_aam(int base)
+{
+    int al, ah;
+    al = EAX & 0xff;
+    ah = al / base;
+    al = al % base;
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_DST = al;
+}
+
+void helper_aad(int base)
+{
+    int al, ah;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+    al = ((ah * base) + al) & 0xff;
+    EAX = (EAX & ~0xffff) | al;
+    CC_DST = al;
+}
+
+void helper_aaa(void)
+{
+    int icarry;
+    int al, ah, af;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+
+    icarry = (al > 0xf9);
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al + 6) & 0x0f;
+        ah = (ah + 1 + icarry) & 0xff;
+        eflags |= CC_C | CC_A;
+    } else {
+        eflags &= ~(CC_C | CC_A);
+        al &= 0x0f;
+    }
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_SRC = eflags;
+}
+
+void helper_aas(void)
+{
+    int icarry;
+    int al, ah, af;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+    ah = (EAX >> 8) & 0xff;
+
+    icarry = (al < 6);
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al - 6) & 0x0f;
+        ah = (ah - 1 - icarry) & 0xff;
+        eflags |= CC_C | CC_A;
+    } else {
+        eflags &= ~(CC_C | CC_A);
+        al &= 0x0f;
+    }
+    EAX = (EAX & ~0xffff) | al | (ah << 8);
+    CC_SRC = eflags;
+}
+
+void helper_daa(void)
+{
+    int al, af, cf;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    cf = eflags & CC_C;
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+
+    eflags = 0;
+    if (((al & 0x0f) > 9 ) || af) {
+        al = (al + 6) & 0xff;
+        eflags |= CC_A;
+    }
+    if ((al > 0x9f) || cf) {
+        al = (al + 0x60) & 0xff;
+        eflags |= CC_C;
+    }
+    EAX = (EAX & ~0xff) | al;
+    /* well, speed is not an issue here, so we compute the flags by hand */
+    eflags |= (al == 0) << 6; /* zf */
+    eflags |= parity_table[al]; /* pf */
+    eflags |= (al & 0x80); /* sf */
+    CC_SRC = eflags;
+}
+
+void helper_das(void)
+{
+    int al, al1, af, cf;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    cf = eflags & CC_C;
+    af = eflags & CC_A;
+    al = EAX & 0xff;
+
+    eflags = 0;
+    al1 = al;
+    if (((al & 0x0f) > 9 ) || af) {
+        eflags |= CC_A;
+        if (al < 6 || cf)
+            eflags |= CC_C;
+        al = (al - 6) & 0xff;
+    }
+    if ((al1 > 0x99) || cf) {
+        al = (al - 0x60) & 0xff;
+        eflags |= CC_C;
+    }
+    EAX = (EAX & ~0xff) | al;
+    /* well, speed is not an issue here, so we compute the flags by hand */
+    eflags |= (al == 0) << 6; /* zf */
+    eflags |= parity_table[al]; /* pf */
+    eflags |= (al & 0x80); /* sf */
+    CC_SRC = eflags;
+}
+
+void helper_into(int next_eip_addend)
+{
+    int eflags;
+    eflags = helper_cc_compute_all(CC_OP);
+    if (eflags & CC_O) {
+        raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
+    }
+}
+
+void helper_cmpxchg8b(target_ulong a0)
+{
+    uint64_t d;
+    int eflags;
+
+    eflags = helper_cc_compute_all(CC_OP);
+    d = ldq(a0);
+    if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
+        stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
+        eflags |= CC_Z;
+    } else {
+        /* always do the store */
+        stq(a0, d); 
+        EDX = (uint32_t)(d >> 32);
+        EAX = (uint32_t)d;
+        eflags &= ~CC_Z;
+    }
+    CC_SRC = eflags;
+}
+
+#ifdef TARGET_X86_64
+void helper_cmpxchg16b(target_ulong a0)
+{
+    uint64_t d0, d1;
+    int eflags;
+
+    if ((a0 & 0xf) != 0)
+        raise_exception(EXCP0D_GPF);
+    eflags = helper_cc_compute_all(CC_OP);
+    d0 = ldq(a0);
+    d1 = ldq(a0 + 8);
+    if (d0 == EAX && d1 == EDX) {
+        stq(a0, EBX);
+        stq(a0 + 8, ECX);
+        eflags |= CC_Z;
+    } else {
+        /* always do the store */
+        stq(a0, d0); 
+        stq(a0 + 8, d1); 
+        EDX = d1;
+        EAX = d0;
+        eflags &= ~CC_Z;
+    }
+    CC_SRC = eflags;
+}
+#endif
+
+void helper_single_step(void)
+{
+#ifndef CONFIG_USER_ONLY
+    check_hw_breakpoints(env, 1);
+    env->dr[6] |= DR6_BS;
+#endif
+    raise_exception(EXCP01_DB);
+}
+
+void helper_cpuid(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+
+    helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
+
+    cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
+    EAX = eax;
+    EBX = ebx;
+    ECX = ecx;
+    EDX = edx;
+}
+
+void helper_enter_level(int level, int data32, target_ulong t1)
+{
+    target_ulong ssp;
+    uint32_t esp_mask, esp, ebp;
+
+    esp_mask = get_sp_mask(env->segs[R_SS].flags);
+    ssp = env->segs[R_SS].base;
+    ebp = EBP;
+    esp = ESP;
+    if (data32) {
+        /* 32 bit */
+        esp -= 4;
+        while (--level) {
+            esp -= 4;
+            ebp -= 4;
+            stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
+        }
+        esp -= 4;
+        stl(ssp + (esp & esp_mask), t1);
+    } else {
+        /* 16 bit */
+        esp -= 2;
+        while (--level) {
+            esp -= 2;
+            ebp -= 2;
+            stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
+        }
+        esp -= 2;
+        stw(ssp + (esp & esp_mask), t1);
+    }
+}
+
+#ifdef TARGET_X86_64
+void helper_enter64_level(int level, int data64, target_ulong t1)
+{
+    target_ulong esp, ebp;
+    ebp = EBP;
+    esp = ESP;
+
+    if (data64) {
+        /* 64 bit */
+        esp -= 8;
+        while (--level) {
+            esp -= 8;
+            ebp -= 8;
+            stq(esp, ldq(ebp));
+        }
+        esp -= 8;
+        stq(esp, t1);
+    } else {
+        /* 16 bit */
+        esp -= 2;
+        while (--level) {
+            esp -= 2;
+            ebp -= 2;
+            stw(esp, lduw(ebp));
+        }
+        esp -= 2;
+        stw(esp, t1);
+    }
+}
+#endif
+
+void helper_lldt(int selector)
+{
+    SegmentCache *dt;
+    uint32_t e1, e2;
+    int index, entry_limit;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    if ((selector & 0xfffc) == 0) {
+        /* XXX: NULL selector case: invalid LDT */
+        env->ldt.base = 0;
+        env->ldt.limit = 0;
+    } else {
+        if (selector & 0x4)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dt = &env->gdt;
+        index = selector & ~7;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            entry_limit = 15;
+        else
+#endif
+            entry_limit = 7;
+        if ((index + entry_limit) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint32_t e3;
+            e3 = ldl_kernel(ptr + 8);
+            load_seg_cache_raw_dt(&env->ldt, e1, e2);
+            env->ldt.base |= (target_ulong)e3 << 32;
+        } else
+#endif
+        {
+            load_seg_cache_raw_dt(&env->ldt, e1, e2);
+        }
+    }
+    env->ldt.selector = selector;
+}
+
+void helper_ltr(int selector)
+{
+    SegmentCache *dt;
+    uint32_t e1, e2;
+    int index, type, entry_limit;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    if ((selector & 0xfffc) == 0) {
+        /* NULL selector case: invalid TR */
+        env->tr.base = 0;
+        env->tr.limit = 0;
+        env->tr.flags = 0;
+    } else {
+        if (selector & 0x4)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dt = &env->gdt;
+        index = selector & ~7;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            entry_limit = 15;
+        else
+#endif
+            entry_limit = 7;
+        if ((index + entry_limit) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        if ((e2 & DESC_S_MASK) ||
+            (type != 1 && type != 9))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            uint32_t e3, e4;
+            e3 = ldl_kernel(ptr + 8);
+            e4 = ldl_kernel(ptr + 12);
+            if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            load_seg_cache_raw_dt(&env->tr, e1, e2);
+            env->tr.base |= (target_ulong)e3 << 32;
+        } else
+#endif
+        {
+            load_seg_cache_raw_dt(&env->tr, e1, e2);
+        }
+        e2 |= DESC_TSS_BUSY_MASK;
+        stl_kernel(ptr + 4, e2);
+    }
+    env->tr.selector = selector;
+}
+
+/* only works if protected mode and not VM86. seg_reg must be != R_CS */
+void helper_load_seg(int seg_reg, int selector)
+{
+    uint32_t e1, e2;
+    int cpl, dpl, rpl;
+    SegmentCache *dt;
+    int index;
+    target_ulong ptr;
+
+    selector &= 0xffff;
+    cpl = env->hflags & HF_CPL_MASK;
+    if ((selector & 0xfffc) == 0) {
+        /* null selector case */
+        if (seg_reg == R_SS
+#ifdef TARGET_X86_64
+            && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
+#endif
+            )
+            raise_exception_err(EXCP0D_GPF, 0);
+        cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
+    } else {
+
+        if (selector & 0x4)
+            dt = &env->ldt;
+        else
+            dt = &env->gdt;
+        index = selector & ~7;
+        if ((index + 7) > dt->limit)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        ptr = dt->base + index;
+        e1 = ldl_kernel(ptr);
+        e2 = ldl_kernel(ptr + 4);
+
+        if (!(e2 & DESC_S_MASK))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        rpl = selector & 3;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (seg_reg == R_SS) {
+            /* must be writable segment */
+            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            if (rpl != cpl || dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        } else {
+            /* must be readable segment */
+            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+
+            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+                /* if not conforming code, test rights */
+                if (dpl < cpl || dpl < rpl)
+                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+            }
+        }
+
+        if (!(e2 & DESC_P_MASK)) {
+            if (seg_reg == R_SS)
+                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
+            else
+                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+        }
+
+        /* set the access bit if not already set */
+        if (!(e2 & DESC_A_MASK)) {
+            e2 |= DESC_A_MASK;
+            stl_kernel(ptr + 4, e2);
+        }
+
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+#if 0
+        qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
+                selector, (unsigned long)sc->base, sc->limit, sc->flags);
+#endif
+    }
+}
+
+/* protected mode jump */
+void helper_ljmp_protected(int new_cs, target_ulong new_eip,
+                           int next_eip_addend)
+{
+    int gate_cs, type;
+    uint32_t e1, e2, cpl, dpl, rpl, limit;
+    target_ulong next_eip;
+
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if (!(e2 & DESC_CS_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (e2 & DESC_C_MASK) {
+            /* conforming code segment */
+            if (dpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        } else {
+            /* non conforming code segment */
+            rpl = new_cs & 3;
+            if (rpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+        limit = get_seg_limit(e1, e2);
+        if (new_eip > limit &&
+            !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                       get_seg_base(e1, e2), limit, e2);
+        EIP = new_eip;
+    } else {
+        /* jump to call or task gate */
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        rpl = new_cs & 3;
+        cpl = env->hflags & HF_CPL_MASK;
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1: /* 286 TSS */
+        case 9: /* 386 TSS */
+        case 5: /* task gate */
+            if (dpl < cpl || dpl < rpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            next_eip = env->eip + next_eip_addend;
+            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
+            CC_OP = CC_OP_EFLAGS;
+            break;
+        case 4: /* 286 call gate */
+        case 12: /* 386 call gate */
+            if ((dpl < cpl) || (dpl < rpl))
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (!(e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+            gate_cs = e1 >> 16;
+            new_eip = (e1 & 0xffff);
+            if (type == 12)
+                new_eip |= (e2 & 0xffff0000);
+            if (load_segment(&e1, &e2, gate_cs) != 0)
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+            /* must be code segment */
+            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
+                 (DESC_S_MASK | DESC_CS_MASK)))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
+                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            if (!(e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
+            limit = get_seg_limit(e1, e2);
+            if (new_eip > limit)
+                raise_exception_err(EXCP0D_GPF, 0);
+            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2), limit, e2);
+            EIP = new_eip;
+            break;
+        default:
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            break;
+        }
+    }
+}
+
+/* real mode call */
+void helper_lcall_real(int new_cs, target_ulong new_eip1,
+                       int shift, int next_eip)
+{
+    int new_eip;
+    uint32_t esp, esp_mask;
+    target_ulong ssp;
+
+    new_eip = new_eip1;
+    esp = ESP;
+    esp_mask = get_sp_mask(env->segs[R_SS].flags);
+    ssp = env->segs[R_SS].base;
+    if (shift) {
+        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
+        PUSHL(ssp, esp, esp_mask, next_eip);
+    } else {
+        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
+        PUSHW(ssp, esp, esp_mask, next_eip);
+    }
+
+    SET_ESP(esp, esp_mask);
+    env->eip = new_eip;
+    env->segs[R_CS].selector = new_cs;
+    env->segs[R_CS].base = (new_cs << 4);
+}
+
+/* protected mode call */
+void helper_lcall_protected(int new_cs, target_ulong new_eip, 
+                            int shift, int next_eip_addend)
+{
+    int new_stack, i;
+    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
+    uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
+    uint32_t val, limit, old_sp_mask;
+    target_ulong ssp, old_ssp, next_eip;
+
+    next_eip = env->eip + next_eip_addend;
+    LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
+    LOG_PCALL_STATE(env);
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, 0);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    LOG_PCALL("desc=%08x:%08x\n", e1, e2);
+    if (e2 & DESC_S_MASK) {
+        if (!(e2 & DESC_CS_MASK))
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (e2 & DESC_C_MASK) {
+            /* conforming code segment */
+            if (dpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        } else {
+            /* non conforming code segment */
+            rpl = new_cs & 3;
+            if (rpl > cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            if (dpl != cpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        }
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+#ifdef TARGET_X86_64
+        /* XXX: check 16/32 bit cases in long mode */
+        if (shift == 2) {
+            target_ulong rsp;
+            /* 64 bit case */
+            rsp = ESP;
+            PUSHQ(rsp, env->segs[R_CS].selector);
+            PUSHQ(rsp, next_eip);
+            /* from this point, not restartable */
+            ESP = rsp;
+            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2),
+                                   get_seg_limit(e1, e2), e2);
+            EIP = new_eip;
+        } else
+#endif
+        {
+            sp = ESP;
+            sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            ssp = env->segs[R_SS].base;
+            if (shift) {
+                PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
+                PUSHL(ssp, sp, sp_mask, next_eip);
+            } else {
+                PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
+                PUSHW(ssp, sp, sp_mask, next_eip);
+            }
+
+            limit = get_seg_limit(e1, e2);
+            if (new_eip > limit)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            /* from this point, not restartable */
+            SET_ESP(sp, sp_mask);
+            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+                                   get_seg_base(e1, e2), limit, e2);
+            EIP = new_eip;
+        }
+    } else {
+        /* check gate type */
+        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        rpl = new_cs & 3;
+        switch(type) {
+        case 1: /* available 286 TSS */
+        case 9: /* available 386 TSS */
+        case 5: /* task gate */
+            if (dpl < cpl || dpl < rpl)
+                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
+            CC_OP = CC_OP_EFLAGS;
+            return;
+        case 4: /* 286 call gate */
+        case 12: /* 386 call gate */
+            break;
+        default:
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+            break;
+        }
+        shift = type >> 3;
+
+        if (dpl < cpl || dpl < rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+        /* check valid bit */
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
+        selector = e1 >> 16;
+        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+        param_count = e2 & 0x1f;
+        if ((selector & 0xfffc) == 0)
+            raise_exception_err(EXCP0D_GPF, 0);
+
+        if (load_segment(&e1, &e2, selector) != 0)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+        if (dpl > cpl)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        if (!(e2 & DESC_P_MASK))
+            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+
+        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+            /* to inner privilege */
+            get_ss_esp_from_tss(&ss, &sp, dpl);
+            LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
+                        ss, sp, param_count, ESP);
+            if ((ss & 0xfffc) == 0)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if ((ss & 3) != dpl)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+            if (ss_dpl != dpl)
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (!(ss_e2 & DESC_S_MASK) ||
+                (ss_e2 & DESC_CS_MASK) ||
+                !(ss_e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+            if (!(ss_e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+
+            //            push_size = ((param_count * 2) + 8) << shift;
+
+            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            old_ssp = env->segs[R_SS].base;
+
+            sp_mask = get_sp_mask(ss_e2);
+            ssp = get_seg_base(ss_e1, ss_e2);
+            if (shift) {
+                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
+                PUSHL(ssp, sp, sp_mask, ESP);
+                for(i = param_count - 1; i >= 0; i--) {
+                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
+                    PUSHL(ssp, sp, sp_mask, val);
+                }
+            } else {
+                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
+                PUSHW(ssp, sp, sp_mask, ESP);
+                for(i = param_count - 1; i >= 0; i--) {
+                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
+                    PUSHW(ssp, sp, sp_mask, val);
+                }
+            }
+            new_stack = 1;
+        } else {
+            /* to same privilege */
+            sp = ESP;
+            sp_mask = get_sp_mask(env->segs[R_SS].flags);
+            ssp = env->segs[R_SS].base;
+            //            push_size = (4 << shift);
+            new_stack = 0;
+        }
+
+        if (shift) {
+            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
+            PUSHL(ssp, sp, sp_mask, next_eip);
+        } else {
+            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
+            PUSHW(ssp, sp, sp_mask, next_eip);
+        }
+
+        /* from this point, not restartable */
+
+        if (new_stack) {
+            ss = (ss & ~3) | dpl;
+            cpu_x86_load_seg_cache(env, R_SS, ss,
+                                   ssp,
+                                   get_seg_limit(ss_e1, ss_e2),
+                                   ss_e2);
+        }
+
+        selector = (selector & ~3) | dpl;
+        cpu_x86_load_seg_cache(env, R_CS, selector,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+        cpu_x86_set_cpl(env, dpl);
+        SET_ESP(sp, sp_mask);
+        EIP = offset;
+    }
+}
+
+/* real and vm86 mode iret */
+void helper_iret_real(int shift)
+{
+    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
+    target_ulong ssp;
+    int eflags_mask;
+
+    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
+    sp = ESP;
+    ssp = env->segs[R_SS].base;
+    if (shift == 1) {
+        /* 32 bits */
+        POPL(ssp, sp, sp_mask, new_eip);
+        POPL(ssp, sp, sp_mask, new_cs);
+        new_cs &= 0xffff;
+        POPL(ssp, sp, sp_mask, new_eflags);
+    } else {
+        /* 16 bits */
+        POPW(ssp, sp, sp_mask, new_eip);
+        POPW(ssp, sp, sp_mask, new_cs);
+        POPW(ssp, sp, sp_mask, new_eflags);
+    }
+    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
+    env->segs[R_CS].selector = new_cs;
+    env->segs[R_CS].base = (new_cs << 4);
+    env->eip = new_eip;
+    if (env->eflags & VM_MASK)
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
+    else
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
+    if (shift == 0)
+        eflags_mask &= 0xffff;
+    load_eflags(new_eflags, eflags_mask);
+    env->hflags2 &= ~HF2_NMI_MASK;
+}
+
+static inline void validate_seg(int seg_reg, int cpl)
+{
+    int dpl;
+    uint32_t e2;
+
+    /* XXX: on x86_64, we do not want to nullify FS and GS because
+       they may still contain a valid base. I would be interested to
+       know how a real x86_64 CPU behaves */
+    if ((seg_reg == R_FS || seg_reg == R_GS) &&
+        (env->segs[seg_reg].selector & 0xfffc) == 0)
+        return;
+
+    e2 = env->segs[seg_reg].flags;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+        /* data or non conforming code segment */
+        if (dpl < cpl) {
+            cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
+        }
+    }
+}
+
+/* protected mode iret */
+static inline void helper_ret_protected(int shift, int is_iret, int addend)
+{
+    uint32_t new_cs, new_eflags, new_ss;
+    uint32_t new_es, new_ds, new_fs, new_gs;
+    uint32_t e1, e2, ss_e1, ss_e2;
+    int cpl, dpl, rpl, eflags_mask, iopl;
+    target_ulong ssp, sp, new_eip, new_esp, sp_mask;
+
+#ifdef TARGET_X86_64
+    if (shift == 2)
+        sp_mask = -1;
+    else
+#endif
+        sp_mask = get_sp_mask(env->segs[R_SS].flags);
+    sp = ESP;
+    ssp = env->segs[R_SS].base;
+    new_eflags = 0; /* avoid warning */
+#ifdef TARGET_X86_64
+    if (shift == 2) {
+        POPQ(sp, new_eip);
+        POPQ(sp, new_cs);
+        new_cs &= 0xffff;
+        if (is_iret) {
+            POPQ(sp, new_eflags);
+        }
+    } else
+#endif
+    if (shift == 1) {
+        /* 32 bits */
+        POPL(ssp, sp, sp_mask, new_eip);
+        POPL(ssp, sp, sp_mask, new_cs);
+        new_cs &= 0xffff;
+        if (is_iret) {
+            POPL(ssp, sp, sp_mask, new_eflags);
+            if (new_eflags & VM_MASK)
+                goto return_to_vm86;
+        }
+    } else {
+        /* 16 bits */
+        POPW(ssp, sp, sp_mask, new_eip);
+        POPW(ssp, sp, sp_mask, new_cs);
+        if (is_iret)
+            POPW(ssp, sp, sp_mask, new_eflags);
+    }
+    LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
+              new_cs, new_eip, shift, addend);
+    LOG_PCALL_STATE(env);
+    if ((new_cs & 0xfffc) == 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    if (load_segment(&e1, &e2, new_cs) != 0)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    if (!(e2 & DESC_S_MASK) ||
+        !(e2 & DESC_CS_MASK))
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    cpl = env->hflags & HF_CPL_MASK;
+    rpl = new_cs & 3;
+    if (rpl < cpl)
+        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (e2 & DESC_C_MASK) {
+        if (dpl > rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    } else {
+        if (dpl != rpl)
+            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+    }
+    if (!(e2 & DESC_P_MASK))
+        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+    sp += addend;
+    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
+                       ((env->hflags & HF_CS64_MASK) && !is_iret))) {
+        /* return to same privilege level */
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+    } else {
+        /* return to different privilege level */
+#ifdef TARGET_X86_64
+        if (shift == 2) {
+            POPQ(sp, new_esp);
+            POPQ(sp, new_ss);
+            new_ss &= 0xffff;
+        } else
+#endif
+        if (shift == 1) {
+            /* 32 bits */
+            POPL(ssp, sp, sp_mask, new_esp);
+            POPL(ssp, sp, sp_mask, new_ss);
+            new_ss &= 0xffff;
+        } else {
+            /* 16 bits */
+            POPW(ssp, sp, sp_mask, new_esp);
+            POPW(ssp, sp, sp_mask, new_ss);
+        }
+        LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
+                    new_ss, new_esp);
+        if ((new_ss & 0xfffc) == 0) {
+#ifdef TARGET_X86_64
+            /* NULL ss is allowed in long mode if cpl != 3*/
+            /* XXX: test CS64 ? */
+            if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
+                cpu_x86_load_seg_cache(env, R_SS, new_ss,
+                                       0, 0xffffffff,
+                                       DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                                       DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
+                                       DESC_W_MASK | DESC_A_MASK);
+                ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
+            } else
+#endif
+            {
+                raise_exception_err(EXCP0D_GPF, 0);
+            }
+        } else {
+            if ((new_ss & 3) != rpl)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (!(ss_e2 & DESC_S_MASK) ||
+                (ss_e2 & DESC_CS_MASK) ||
+                !(ss_e2 & DESC_W_MASK))
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+            if (dpl != rpl)
+                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+            if (!(ss_e2 & DESC_P_MASK))
+                raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
+            cpu_x86_load_seg_cache(env, R_SS, new_ss,
+                                   get_seg_base(ss_e1, ss_e2),
+                                   get_seg_limit(ss_e1, ss_e2),
+                                   ss_e2);
+        }
+
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
+                       get_seg_base(e1, e2),
+                       get_seg_limit(e1, e2),
+                       e2);
+        cpu_x86_set_cpl(env, rpl);
+        sp = new_esp;
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_CS64_MASK)
+            sp_mask = -1;
+        else
+#endif
+            sp_mask = get_sp_mask(ss_e2);
+
+        /* validate data segments */
+        validate_seg(R_ES, rpl);
+        validate_seg(R_DS, rpl);
+        validate_seg(R_FS, rpl);
+        validate_seg(R_GS, rpl);
+
+        sp += addend;
+    }
+    SET_ESP(sp, sp_mask);
+    env->eip = new_eip;
+    if (is_iret) {
+        /* NOTE: 'cpl' is the _old_ CPL */
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
+        if (cpl == 0)
+            eflags_mask |= IOPL_MASK;
+        iopl = (env->eflags >> IOPL_SHIFT) & 3;
+        if (cpl <= iopl)
+            eflags_mask |= IF_MASK;
+        if (shift == 0)
+            eflags_mask &= 0xffff;
+        load_eflags(new_eflags, eflags_mask);
+    }
+    return;
+
+ return_to_vm86:
+    POPL(ssp, sp, sp_mask, new_esp);
+    POPL(ssp, sp, sp_mask, new_ss);
+    POPL(ssp, sp, sp_mask, new_es);
+    POPL(ssp, sp, sp_mask, new_ds);
+    POPL(ssp, sp, sp_mask, new_fs);
+    POPL(ssp, sp, sp_mask, new_gs);
+
+    /* modify processor state */
+    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
+                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
+    load_seg_vm(R_CS, new_cs & 0xffff);
+    cpu_x86_set_cpl(env, 3);
+    load_seg_vm(R_SS, new_ss & 0xffff);
+    load_seg_vm(R_ES, new_es & 0xffff);
+    load_seg_vm(R_DS, new_ds & 0xffff);
+    load_seg_vm(R_FS, new_fs & 0xffff);
+    load_seg_vm(R_GS, new_gs & 0xffff);
+
+    env->eip = new_eip & 0xffff;
+    ESP = new_esp;
+}
+
+void helper_iret_protected(int shift, int next_eip)
+{
+    int tss_selector, type;
+    uint32_t e1, e2;
+
+    /* specific case for TSS */
+    if (env->eflags & NT_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK)
+            raise_exception_err(EXCP0D_GPF, 0);
+#endif
+        tss_selector = lduw_kernel(env->tr.base + 0);
+        if (tss_selector & 4)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        if (load_segment(&e1, &e2, tss_selector) != 0)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
+        /* NOTE: we check both segment and busy TSS */
+        if (type != 3)
+            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
+        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
+    } else {
+        helper_ret_protected(shift, 1, 0);
+    }
+    env->hflags2 &= ~HF2_NMI_MASK;
+}
+
+void helper_lret_protected(int shift, int addend)
+{
+    helper_ret_protected(shift, 0, addend);
+}
+
+void helper_sysenter(void)
+{
+    if (env->sysenter_cs == 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
+    cpu_x86_set_cpl(env, 0);
+
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_LMA_MASK) {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+    }
+    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
+                           0, 0xffffffff,
+                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                           DESC_S_MASK |
+                           DESC_W_MASK | DESC_A_MASK);
+    ESP = env->sysenter_esp;
+    EIP = env->sysenter_eip;
+}
+
+void helper_sysexit(int dflag)
+{
+    int cpl;
+
+    cpl = env->hflags & HF_CPL_MASK;
+    if (env->sysenter_cs == 0 || cpl != 0) {
+        raise_exception_err(EXCP0D_GPF, 0);
+    }
+    cpu_x86_set_cpl(env, 3);
+#ifdef TARGET_X86_64
+    if (dflag == 2) {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    }
+    ESP = ECX;
+    EIP = EDX;
+}
+
+#if defined(CONFIG_USER_ONLY)
+target_ulong helper_read_crN(int reg)
+{
+    return 0;
+}
+
+void helper_write_crN(int reg, target_ulong t0)
+{
+}
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+}
+#else
+target_ulong helper_read_crN(int reg)
+{
+    target_ulong val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
+    switch(reg) {
+    default:
+        val = env->cr[reg];
+        break;
+    case 8:
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            val = cpu_get_apic_tpr(env->apic_state);
+        } else {
+            val = env->v_tpr;
+        }
+        break;
+    }
+    return val;
+}
+
+void helper_write_crN(int reg, target_ulong t0)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
+    switch(reg) {
+    case 0:
+        cpu_x86_update_cr0(env, t0);
+        break;
+    case 3:
+        cpu_x86_update_cr3(env, t0);
+        break;
+    case 4:
+        cpu_x86_update_cr4(env, t0);
+        break;
+    case 8:
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            cpu_set_apic_tpr(env->apic_state, t0);
+        }
+        env->v_tpr = t0 & 0x0f;
+        break;
+    default:
+        env->cr[reg] = t0;
+        break;
+    }
+}
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+    int i;
+
+    if (reg < 4) {
+        hw_breakpoint_remove(env, reg);
+        env->dr[reg] = t0;
+        hw_breakpoint_insert(env, reg);
+    } else if (reg == 7) {
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_remove(env, i);
+        env->dr[7] = t0;
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_insert(env, i);
+    } else
+        env->dr[reg] = t0;
+}
+#endif
+
+void helper_lmsw(target_ulong t0)
+{
+    /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
+       if already set to one. */
+    t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
+    helper_write_crN(0, t0);
+}
+
+void helper_clts(void)
+{
+    env->cr[0] &= ~CR0_TS_MASK;
+    env->hflags &= ~HF_TS_MASK;
+}
+
+void helper_invlpg(target_ulong addr)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
+    tlb_flush_page(env, addr);
+}
+
+void helper_rdtsc(void)
+{
+    uint64_t val;
+
+    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
+        raise_exception(EXCP0D_GPF);
+    }
+    helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
+
+    val = cpu_get_tsc(env) + env->tsc_offset;
+    EAX = (uint32_t)(val);
+    EDX = (uint32_t)(val >> 32);
+}
+
+void helper_rdtscp(void)
+{
+    helper_rdtsc();
+    ECX = (uint32_t)(env->tsc_aux);
+}
+
+void helper_rdpmc(void)
+{
+    if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
+        raise_exception(EXCP0D_GPF);
+    }
+    helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
+    
+    /* currently unimplemented */
+    raise_exception_err(EXCP06_ILLOP, 0);
+}
+
+#if defined(CONFIG_USER_ONLY)
+void helper_wrmsr(void)
+{
+}
+
+void helper_rdmsr(void)
+{
+}
+#else
+void helper_wrmsr(void)
+{
+    uint64_t val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
+
+    val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
+
+    switch((uint32_t)ECX) {
+    case MSR_IA32_SYSENTER_CS:
+        env->sysenter_cs = val & 0xffff;
+        break;
+    case MSR_IA32_SYSENTER_ESP:
+        env->sysenter_esp = val;
+        break;
+    case MSR_IA32_SYSENTER_EIP:
+        env->sysenter_eip = val;
+        break;
+    case MSR_IA32_APICBASE:
+        cpu_set_apic_base(env->apic_state, val);
+        break;
+    case MSR_EFER:
+        {
+            uint64_t update_mask;
+            update_mask = 0;
+            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
+                update_mask |= MSR_EFER_SCE;
+            if (env->cpuid_ext2_features & CPUID_EXT2_LM)
+                update_mask |= MSR_EFER_LME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
+            if (env->cpuid_ext2_features & CPUID_EXT2_NX)
+                update_mask |= MSR_EFER_NXE;
+            if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
+                update_mask |= MSR_EFER_SVME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
+            cpu_load_efer(env, (env->efer & ~update_mask) |
+                          (val & update_mask));
+        }
+        break;
+    case MSR_STAR:
+        env->star = val;
+        break;
+    case MSR_PAT:
+        env->pat = val;
+        break;
+    case MSR_VM_HSAVE_PA:
+        env->vm_hsave = val;
+        break;
+#ifdef TARGET_X86_64
+    case MSR_LSTAR:
+        env->lstar = val;
+        break;
+    case MSR_CSTAR:
+        env->cstar = val;
+        break;
+    case MSR_FMASK:
+        env->fmask = val;
+        break;
+    case MSR_FSBASE:
+        env->segs[R_FS].base = val;
+        break;
+    case MSR_GSBASE:
+        env->segs[R_GS].base = val;
+        break;
+    case MSR_KERNELGSBASE:
+        env->kernelgsbase = val;
+        break;
+#endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
+        break;
+    case MSR_MTRRfix64K_00000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
+        break;
+    case MSR_MTRRdefType:
+        env->mtrr_deftype = val;
+        break;
+    case MSR_MCG_STATUS:
+        env->mcg_status = val;
+        break;
+    case MSR_MCG_CTL:
+        if ((env->mcg_cap & MCG_CTL_P)
+            && (val == 0 || val == ~(uint64_t)0))
+            env->mcg_ctl = val;
+        break;
+    case MSR_TSC_AUX:
+        env->tsc_aux = val;
+        break;
+    default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            if ((offset & 0x3) != 0
+                || (val == 0 || val == ~(uint64_t)0))
+                env->mce_banks[offset] = val;
+            break;
+        }
+        /* XXX: exception ? */
+        break;
+    }
+}
+
+void helper_rdmsr(void)
+{
+    uint64_t val;
+
+    helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
+
+    switch((uint32_t)ECX) {
+    case MSR_IA32_SYSENTER_CS:
+        val = env->sysenter_cs;
+        break;
+    case MSR_IA32_SYSENTER_ESP:
+        val = env->sysenter_esp;
+        break;
+    case MSR_IA32_SYSENTER_EIP:
+        val = env->sysenter_eip;
+        break;
+    case MSR_IA32_APICBASE:
+        val = cpu_get_apic_base(env->apic_state);
+        break;
+    case MSR_EFER:
+        val = env->efer;
+        break;
+    case MSR_STAR:
+        val = env->star;
+        break;
+    case MSR_PAT:
+        val = env->pat;
+        break;
+    case MSR_VM_HSAVE_PA:
+        val = env->vm_hsave;
+        break;
+    case MSR_IA32_PERF_STATUS:
+        /* tsc_increment_by_tick */
+        val = 1000ULL;
+        /* CPU multiplier */
+        val |= (((uint64_t)4ULL) << 40);
+        break;
+#ifdef TARGET_X86_64
+    case MSR_LSTAR:
+        val = env->lstar;
+        break;
+    case MSR_CSTAR:
+        val = env->cstar;
+        break;
+    case MSR_FMASK:
+        val = env->fmask;
+        break;
+    case MSR_FSBASE:
+        val = env->segs[R_FS].base;
+        break;
+    case MSR_GSBASE:
+        val = env->segs[R_GS].base;
+        break;
+    case MSR_KERNELGSBASE:
+        val = env->kernelgsbase;
+        break;
+    case MSR_TSC_AUX:
+        val = env->tsc_aux;
+        break;
+#endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
+        break;
+    case MSR_MTRRfix64K_00000:
+        val = env->mtrr_fixed[0];
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
+        break;
+    case MSR_MTRRdefType:
+        val = env->mtrr_deftype;
+        break;
+    case MSR_MTRRcap:
+        if (env->cpuid_features & CPUID_MTRR)
+            val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
+        else
+            /* XXX: exception ? */
+            val = 0;
+        break;
+    case MSR_MCG_CAP:
+        val = env->mcg_cap;
+        break;
+    case MSR_MCG_CTL:
+        if (env->mcg_cap & MCG_CTL_P)
+            val = env->mcg_ctl;
+        else
+            val = 0;
+        break;
+    case MSR_MCG_STATUS:
+        val = env->mcg_status;
+        break;
+    default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            val = env->mce_banks[offset];
+            break;
+        }
+        /* XXX: exception ? */
+        val = 0;
+        break;
+    }
+    EAX = (uint32_t)(val);
+    EDX = (uint32_t)(val >> 32);
+}
+#endif
+
+target_ulong helper_lsl(target_ulong selector1)
+{
+    unsigned int limit;
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl, type;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
+            /* conforming */
+        } else {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1:
+        case 2:
+        case 3:
+        case 9:
+        case 11:
+            break;
+        default:
+            goto fail;
+        }
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return 0;
+        }
+    }
+    limit = get_seg_limit(e1, e2);
+    CC_SRC = eflags | CC_Z;
+    return limit;
+}
+
+target_ulong helper_lar(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl, type;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_S_MASK) {
+        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
+            /* conforming */
+        } else {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+        switch(type) {
+        case 1:
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+        case 11:
+        case 12:
+            break;
+        default:
+            goto fail;
+        }
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return 0;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+    return e2 & 0x00f0ff00;
+}
+
+void helper_verr(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    if (!(e2 & DESC_S_MASK))
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_CS_MASK) {
+        if (!(e2 & DESC_R_MASK))
+            goto fail;
+        if (!(e2 & DESC_C_MASK)) {
+            if (dpl < cpl || dpl < rpl)
+                goto fail;
+        }
+    } else {
+        if (dpl < cpl || dpl < rpl) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+}
+
+void helper_verw(target_ulong selector1)
+{
+    uint32_t e1, e2, eflags, selector;
+    int rpl, dpl, cpl;
+
+    selector = selector1 & 0xffff;
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
+    if (load_segment(&e1, &e2, selector) != 0)
+        goto fail;
+    if (!(e2 & DESC_S_MASK))
+        goto fail;
+    rpl = selector & 3;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
+    if (e2 & DESC_CS_MASK) {
+        goto fail;
+    } else {
+        if (dpl < cpl || dpl < rpl)
+            goto fail;
+        if (!(e2 & DESC_W_MASK)) {
+        fail:
+            CC_SRC = eflags & ~CC_Z;
+            return;
+        }
+    }
+    CC_SRC = eflags | CC_Z;
+}
+
+/* x87 FPU helpers */
+
+static inline double floatx80_to_double(floatx80 a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.f64 = floatx80_to_float64(a, &env->fp_status);
+    return u.d;
+}
+
+static inline floatx80 double_to_floatx80(double a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.d = a;
+    return float64_to_floatx80(u.f64, &env->fp_status);
+}
+
+static void fpu_set_exception(int mask)
+{
+    env->fpus |= mask;
+    if (env->fpus & (~env->fpuc & FPUC_EM))
+        env->fpus |= FPUS_SE | FPUS_B;
+}
+
+static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
+{
+    if (floatx80_is_zero(b)) {
+        fpu_set_exception(FPUS_ZE);
+    }
+    return floatx80_div(a, b, &env->fp_status);
+}
+
+static void fpu_raise_exception(void)
+{
+    if (env->cr[0] & CR0_NE_MASK) {
+        raise_exception(EXCP10_COPR);
+    }
+#if !defined(CONFIG_USER_ONLY)
+    else {
+        cpu_set_ferr(env);
+    }
+#endif
+}
+
+void helper_flds_FT0(uint32_t val)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.i = val;
+    FT0 = float32_to_floatx80(u.f, &env->fp_status);
+}
+
+void helper_fldl_FT0(uint64_t val)
+{
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    u.i = val;
+    FT0 = float64_to_floatx80(u.f, &env->fp_status);
+}
+
+void helper_fildl_FT0(int32_t val)
+{
+    FT0 = int32_to_floatx80(val, &env->fp_status);
+}
+
+void helper_flds_ST0(uint32_t val)
+{
+    int new_fpstt;
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    new_fpstt = (env->fpstt - 1) & 7;
+    u.i = val;
+    env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fldl_ST0(uint64_t val)
+{
+    int new_fpstt;
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    new_fpstt = (env->fpstt - 1) & 7;
+    u.i = val;
+    env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildl_ST0(int32_t val)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildll_ST0(int64_t val)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+uint32_t helper_fsts_ST0(void)
+{
+    union {
+        float32 f;
+        uint32_t i;
+    } u;
+    u.f = floatx80_to_float32(ST0, &env->fp_status);
+    return u.i;
+}
+
+uint64_t helper_fstl_ST0(void)
+{
+    union {
+        float64 f;
+        uint64_t i;
+    } u;
+    u.f = floatx80_to_float64(ST0, &env->fp_status);
+    return u.i;
+}
+
+int32_t helper_fist_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32(ST0, &env->fp_status);
+    if (val != (int16_t)val)
+        val = -32768;
+    return val;
+}
+
+int32_t helper_fistl_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32(ST0, &env->fp_status);
+    return val;
+}
+
+int64_t helper_fistll_ST0(void)
+{
+    int64_t val;
+    val = floatx80_to_int64(ST0, &env->fp_status);
+    return val;
+}
+
+int32_t helper_fistt_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
+    if (val != (int16_t)val)
+        val = -32768;
+    return val;
+}
+
+int32_t helper_fisttl_ST0(void)
+{
+    int32_t val;
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
+    return val;
+}
+
+int64_t helper_fisttll_ST0(void)
+{
+    int64_t val;
+    val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
+    return val;
+}
+
+void helper_fldt_ST0(target_ulong ptr)
+{
+    int new_fpstt;
+    new_fpstt = (env->fpstt - 1) & 7;
+    env->fpregs[new_fpstt].d = helper_fldt(ptr);
+    env->fpstt = new_fpstt;
+    env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fstt_ST0(target_ulong ptr)
+{
+    helper_fstt(ST0, ptr);
+}
+
+void helper_fpush(void)
+{
+    fpush();
+}
+
+void helper_fpop(void)
+{
+    fpop();
+}
+
+void helper_fdecstp(void)
+{
+    env->fpstt = (env->fpstt - 1) & 7;
+    env->fpus &= (~0x4700);
+}
+
+void helper_fincstp(void)
+{
+    env->fpstt = (env->fpstt + 1) & 7;
+    env->fpus &= (~0x4700);
+}
+
+/* FPU move */
+
+void helper_ffree_STN(int st_index)
+{
+    env->fptags[(env->fpstt + st_index) & 7] = 1;
+}
+
+void helper_fmov_ST0_FT0(void)
+{
+    ST0 = FT0;
+}
+
+void helper_fmov_FT0_STN(int st_index)
+{
+    FT0 = ST(st_index);
+}
+
+void helper_fmov_ST0_STN(int st_index)
+{
+    ST0 = ST(st_index);
+}
+
+void helper_fmov_STN_ST0(int st_index)
+{
+    ST(st_index) = ST0;
+}
+
+void helper_fxchg_ST0_STN(int st_index)
+{
+    floatx80 tmp;
+    tmp = ST(st_index);
+    ST(st_index) = ST0;
+    ST0 = tmp;
+}
+
+/* FPU operations */
+
+static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
+
+void helper_fcom_ST0_FT0(void)
+{
+    int ret;
+
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
+    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+}
+
+void helper_fucom_ST0_FT0(void)
+{
+    int ret;
+
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
+}
+
+static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
+
+void helper_fcomi_ST0_FT0(void)
+{
+    int eflags;
+    int ret;
+
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
+    CC_SRC = eflags;
+}
+
+void helper_fucomi_ST0_FT0(void)
+{
+    int eflags;
+    int ret;
+
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
+    CC_SRC = eflags;
+}
+
+void helper_fadd_ST0_FT0(void)
+{
+    ST0 = floatx80_add(ST0, FT0, &env->fp_status);
+}
+
+void helper_fmul_ST0_FT0(void)
+{
+    ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
+}
+
+void helper_fsub_ST0_FT0(void)
+{
+    ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
+}
+
+void helper_fsubr_ST0_FT0(void)
+{
+    ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
+}
+
+void helper_fdiv_ST0_FT0(void)
+{
+    ST0 = helper_fdiv(ST0, FT0);
+}
+
+void helper_fdivr_ST0_FT0(void)
+{
+    ST0 = helper_fdiv(FT0, ST0);
+}
+
+/* fp operations between STN and ST0 */
+
+void helper_fadd_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fmul_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fsub_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
+}
+
+void helper_fsubr_STN_ST0(int st_index)
+{
+    ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
+}
+
+void helper_fdiv_STN_ST0(int st_index)
+{
+    floatx80 *p;
+    p = &ST(st_index);
+    *p = helper_fdiv(*p, ST0);
+}
+
+void helper_fdivr_STN_ST0(int st_index)
+{
+    floatx80 *p;
+    p = &ST(st_index);
+    *p = helper_fdiv(ST0, *p);
+}
+
+/* misc FPU operations */
+void helper_fchs_ST0(void)
+{
+    ST0 = floatx80_chs(ST0);
+}
+
+void helper_fabs_ST0(void)
+{
+    ST0 = floatx80_abs(ST0);
+}
+
+void helper_fld1_ST0(void)
+{
+    ST0 = floatx80_one;
+}
+
+void helper_fldl2t_ST0(void)
+{
+    ST0 = floatx80_l2t;
+}
+
+void helper_fldl2e_ST0(void)
+{
+    ST0 = floatx80_l2e;
+}
+
+void helper_fldpi_ST0(void)
+{
+    ST0 = floatx80_pi;
+}
+
+void helper_fldlg2_ST0(void)
+{
+    ST0 = floatx80_lg2;
+}
+
+void helper_fldln2_ST0(void)
+{
+    ST0 = floatx80_ln2;
+}
+
+void helper_fldz_ST0(void)
+{
+    ST0 = floatx80_zero;
+}
+
+void helper_fldz_FT0(void)
+{
+    FT0 = floatx80_zero;
+}
+
+uint32_t helper_fnstsw(void)
+{
+    return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+}
+
+uint32_t helper_fnstcw(void)
+{
+    return env->fpuc;
+}
+
+static void update_fp_status(void)
+{
+    int rnd_type;
+
+    /* set rounding mode */
+    switch(env->fpuc & RC_MASK) {
+    default:
+    case RC_NEAR:
+        rnd_type = float_round_nearest_even;
+        break;
+    case RC_DOWN:
+        rnd_type = float_round_down;
+        break;
+    case RC_UP:
+        rnd_type = float_round_up;
+        break;
+    case RC_CHOP:
+        rnd_type = float_round_to_zero;
+        break;
+    }
+    set_float_rounding_mode(rnd_type, &env->fp_status);
+    switch((env->fpuc >> 8) & 3) {
+    case 0:
+        rnd_type = 32;
+        break;
+    case 2:
+        rnd_type = 64;
+        break;
+    case 3:
+    default:
+        rnd_type = 80;
+        break;
+    }
+    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
+}
+
+void helper_fldcw(uint32_t val)
+{
+    env->fpuc = val;
+    update_fp_status();
+}
+
+void helper_fclex(void)
+{
+    env->fpus &= 0x7f00;
+}
+
+void helper_fwait(void)
+{
+    if (env->fpus & FPUS_SE)
+        fpu_raise_exception();
+}
+
+void helper_fninit(void)
+{
+    env->fpus = 0;
+    env->fpstt = 0;
+    env->fpuc = 0x37f;
+    env->fptags[0] = 1;
+    env->fptags[1] = 1;
+    env->fptags[2] = 1;
+    env->fptags[3] = 1;
+    env->fptags[4] = 1;
+    env->fptags[5] = 1;
+    env->fptags[6] = 1;
+    env->fptags[7] = 1;
+}
+
+/* BCD ops */
+
+void helper_fbld_ST0(target_ulong ptr)
+{
+    floatx80 tmp;
+    uint64_t val;
+    unsigned int v;
+    int i;
+
+    val = 0;
+    for(i = 8; i >= 0; i--) {
+        v = ldub(ptr + i);
+        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
+    }
+    tmp = int64_to_floatx80(val, &env->fp_status);
+    if (ldub(ptr + 9) & 0x80) {
+        floatx80_chs(tmp);
+    }
+    fpush();
+    ST0 = tmp;
+}
+
+void helper_fbst_ST0(target_ulong ptr)
+{
+    int v;
+    target_ulong mem_ref, mem_end;
+    int64_t val;
+
+    val = floatx80_to_int64(ST0, &env->fp_status);
+    mem_ref = ptr;
+    mem_end = mem_ref + 9;
+    if (val < 0) {
+        stb(mem_end, 0x80);
+        val = -val;
+    } else {
+        stb(mem_end, 0x00);
+    }
+    while (mem_ref < mem_end) {
+        if (val == 0)
+            break;
+        v = val % 100;
+        val = val / 100;
+        v = ((v / 10) << 4) | (v % 10);
+        stb(mem_ref++, v);
+    }
+    while (mem_ref < mem_end) {
+        stb(mem_ref++, 0);
+    }
+}
+
+void helper_f2xm1(void)
+{
+    double val = floatx80_to_double(ST0);
+    val = pow(2.0, val) - 1.0;
+    ST0 = double_to_floatx80(val);
+}
+
+void helper_fyl2x(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if (fptemp>0.0){
+        fptemp = log(fptemp)/log(2.0);    /* log2(ST) */
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
+        fpop();
+    } else {
+        env->fpus &= (~0x4700);
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fptan(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        fptemp = tan(fptemp);
+        ST0 = double_to_floatx80(fptemp);
+        fpush();
+        ST0 = floatx80_one;
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**52 only */
+    }
+}
+
+void helper_fpatan(void)
+{
+    double fptemp, fpsrcop;
+
+    fpsrcop = floatx80_to_double(ST1);
+    fptemp = floatx80_to_double(ST0);
+    ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
+    fpop();
+}
+
+void helper_fxtract(void)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = ST0;
+
+    if (floatx80_is_zero(ST0)) {
+        /* Easy way to generate -inf and raising division by 0 exception */
+        ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status);
+        fpush();
+        ST0 = temp.d;
+    } else {
+        int expdif;
+
+        expdif = EXPD(temp) - EXPBIAS;
+        /*DP exponent bias*/
+        ST0 = int32_to_floatx80(expdif, &env->fp_status);
+        fpush();
+        BIASEXPONENT(temp);
+        ST0 = temp.d;
+    }
+}
+
+void helper_fprem1(void)
+{
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
+    int expdif;
+    signed long long int q;
+
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+        ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        return;
+    }
+
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
+    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        /* ST0 is unchanged */
+        return;
+    }
+
+    if (expdif < 53) {
+        dblq = fpsrcop / fptemp;
+        /* round dblq towards nearest integer */
+        dblq = rint(dblq);
+        st0 = fpsrcop - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
+    } else {
+        env->fpus |= 0x400;  /* C2 <-- 1 */
+        fptemp = pow(2.0, expdif - 50);
+        fpsrcop = (st0 / st1) / fptemp;
+        /* fpsrcop = integer obtained by chopping */
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
+        st0 -= (st1 * fpsrcop * fptemp);
+    }
+    ST0 = double_to_floatx80(st0);
+}
+
+void helper_fprem(void)
+{
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
+    int expdif;
+    signed long long int q;
+
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+       ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+       env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+       return;
+    }
+
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
+    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        /* ST0 is unchanged */
+        return;
+    }
+
+    if ( expdif < 53 ) {
+        dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
+        /* round dblq towards zero */
+        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
+        st0 = fpsrcop/*ST0*/ - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
+    } else {
+        int N = 32 + (expdif % 32); /* as per AMD docs */
+        env->fpus |= 0x400;  /* C2 <-- 1 */
+        fptemp = pow(2.0, (double)(expdif - N));
+        fpsrcop = (st0 / st1) / fptemp;
+        /* fpsrcop = integer obtained by chopping */
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
+        st0 -= (st1 * fpsrcop * fptemp);
+    }
+    ST0 = double_to_floatx80(st0);
+}
+
+void helper_fyl2xp1(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp+1.0)>0.0) {
+        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
+        fpop();
+    } else {
+        env->fpus &= (~0x4700);
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fsqrt(void)
+{
+    if (floatx80_is_neg(ST0)) {
+        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
+        env->fpus |= 0x400;
+    }
+    ST0 = floatx80_sqrt(ST0, &env->fp_status);
+}
+
+void helper_fsincos(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(sin(fptemp));
+        fpush();
+        ST0 = double_to_floatx80(cos(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**63 only */
+    }
+}
+
+void helper_frndint(void)
+{
+    ST0 = floatx80_round_to_int(ST0, &env->fp_status);
+}
+
+void helper_fscale(void)
+{
+    if (floatx80_is_any_nan(ST1)) {
+        ST0 = ST1;
+    } else {
+        int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
+        ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
+    }
+}
+
+void helper_fsin(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(sin(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg| < 2**53 only */
+    }
+}
+
+void helper_fcos(void)
+{
+    double fptemp = floatx80_to_double(ST0);
+
+    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+        env->fpus |= 0x400;
+    } else {
+        ST0 = double_to_floatx80(cos(fptemp));
+        env->fpus &= (~0x400);  /* C2 <-- 0 */
+        /* the above code is for  |arg5 < 2**63 only */
+    }
+}
+
+void helper_fxam_ST0(void)
+{
+    CPU_LDoubleU temp;
+    int expdif;
+
+    temp.d = ST0;
+
+    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
+    if (SIGND(temp))
+        env->fpus |= 0x200; /* C1 <-- 1 */
+
+    /* XXX: test fptags too */
+    expdif = EXPD(temp);
+    if (expdif == MAXEXPD) {
+        if (MANTD(temp) == 0x8000000000000000ULL)
+            env->fpus |=  0x500 /*Infinity*/;
+        else
+            env->fpus |=  0x100 /*NaN*/;
+    } else if (expdif == 0) {
+        if (MANTD(temp) == 0)
+            env->fpus |=  0x4000 /*Zero*/;
+        else
+            env->fpus |= 0x4400 /*Denormal*/;
+    } else {
+        env->fpus |= 0x400;
+    }
+}
+
+void helper_fstenv(target_ulong ptr, int data32)
+{
+    int fpus, fptag, exp, i;
+    uint64_t mant;
+    CPU_LDoubleU tmp;
+
+    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    fptag = 0;
+    for (i=7; i>=0; i--) {
+	fptag <<= 2;
+	if (env->fptags[i]) {
+            fptag |= 3;
+	} else {
+            tmp.d = env->fpregs[i].d;
+            exp = EXPD(tmp);
+            mant = MANTD(tmp);
+            if (exp == 0 && mant == 0) {
+                /* zero */
+	        fptag |= 1;
+	    } else if (exp == 0 || exp == MAXEXPD
+                       || (mant & (1LL << 63)) == 0
+                       ) {
+                /* NaNs, infinity, denormal */
+                fptag |= 2;
+            }
+        }
+    }
+    if (data32) {
+        /* 32 bit */
+        stl(ptr, env->fpuc);
+        stl(ptr + 4, fpus);
+        stl(ptr + 8, fptag);
+        stl(ptr + 12, 0); /* fpip */
+        stl(ptr + 16, 0); /* fpcs */
+        stl(ptr + 20, 0); /* fpoo */
+        stl(ptr + 24, 0); /* fpos */
+    } else {
+        /* 16 bit */
+        stw(ptr, env->fpuc);
+        stw(ptr + 2, fpus);
+        stw(ptr + 4, fptag);
+        stw(ptr + 6, 0);
+        stw(ptr + 8, 0);
+        stw(ptr + 10, 0);
+        stw(ptr + 12, 0);
+    }
+}
+
+void helper_fldenv(target_ulong ptr, int data32)
+{
+    int i, fpus, fptag;
+
+    if (data32) {
+	env->fpuc = lduw(ptr);
+        fpus = lduw(ptr + 4);
+        fptag = lduw(ptr + 8);
+    }
+    else {
+	env->fpuc = lduw(ptr);
+        fpus = lduw(ptr + 2);
+        fptag = lduw(ptr + 4);
+    }
+    env->fpstt = (fpus >> 11) & 7;
+    env->fpus = fpus & ~0x3800;
+    for(i = 0;i < 8; i++) {
+        env->fptags[i] = ((fptag & 3) == 3);
+        fptag >>= 2;
+    }
+}
+
+void helper_fsave(target_ulong ptr, int data32)
+{
+    floatx80 tmp;
+    int i;
+
+    helper_fstenv(ptr, data32);
+
+    ptr += (14 << data32);
+    for(i = 0;i < 8; i++) {
+        tmp = ST(i);
+        helper_fstt(tmp, ptr);
+        ptr += 10;
+    }
+
+    /* fninit */
+    env->fpus = 0;
+    env->fpstt = 0;
+    env->fpuc = 0x37f;
+    env->fptags[0] = 1;
+    env->fptags[1] = 1;
+    env->fptags[2] = 1;
+    env->fptags[3] = 1;
+    env->fptags[4] = 1;
+    env->fptags[5] = 1;
+    env->fptags[6] = 1;
+    env->fptags[7] = 1;
+}
+
+void helper_frstor(target_ulong ptr, int data32)
+{
+    floatx80 tmp;
+    int i;
+
+    helper_fldenv(ptr, data32);
+    ptr += (14 << data32);
+
+    for(i = 0;i < 8; i++) {
+        tmp = helper_fldt(ptr);
+        ST(i) = tmp;
+        ptr += 10;
+    }
+}
+
+void helper_fxsave(target_ulong ptr, int data64)
+{
+    int fpus, fptag, i, nb_xmm_regs;
+    floatx80 tmp;
+    target_ulong addr;
+
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
+    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    fptag = 0;
+    for(i = 0; i < 8; i++) {
+        fptag |= (env->fptags[i] << i);
+    }
+    stw(ptr, env->fpuc);
+    stw(ptr + 2, fpus);
+    stw(ptr + 4, fptag ^ 0xff);
+#ifdef TARGET_X86_64
+    if (data64) {
+        stq(ptr + 0x08, 0); /* rip */
+        stq(ptr + 0x10, 0); /* rdp */
+    } else 
+#endif
+    {
+        stl(ptr + 0x08, 0); /* eip */
+        stl(ptr + 0x0c, 0); /* sel  */
+        stl(ptr + 0x10, 0); /* dp */
+        stl(ptr + 0x14, 0); /* sel  */
+    }
+
+    addr = ptr + 0x20;
+    for(i = 0;i < 8; i++) {
+        tmp = ST(i);
+        helper_fstt(tmp, addr);
+        addr += 16;
+    }
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        /* XXX: finish it */
+        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
+        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
+        if (env->hflags & HF_CS64_MASK)
+            nb_xmm_regs = 16;
+        else
+            nb_xmm_regs = 8;
+        addr = ptr + 0xa0;
+        /* Fast FXSAVE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                stq(addr, env->xmm_regs[i].XMM_Q(0));
+                stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
+                addr += 16;
+            }
+        }
+    }
+}
+
+void helper_fxrstor(target_ulong ptr, int data64)
+{
+    int i, fpus, fptag, nb_xmm_regs;
+    floatx80 tmp;
+    target_ulong addr;
+
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
+    env->fpuc = lduw(ptr);
+    fpus = lduw(ptr + 2);
+    fptag = lduw(ptr + 4);
+    env->fpstt = (fpus >> 11) & 7;
+    env->fpus = fpus & ~0x3800;
+    fptag ^= 0xff;
+    for(i = 0;i < 8; i++) {
+        env->fptags[i] = ((fptag >> i) & 1);
+    }
+
+    addr = ptr + 0x20;
+    for(i = 0;i < 8; i++) {
+        tmp = helper_fldt(addr);
+        ST(i) = tmp;
+        addr += 16;
+    }
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        /* XXX: finish it */
+        env->mxcsr = ldl(ptr + 0x18);
+        //ldl(ptr + 0x1c);
+        if (env->hflags & HF_CS64_MASK)
+            nb_xmm_regs = 16;
+        else
+            nb_xmm_regs = 8;
+        addr = ptr + 0xa0;
+        /* Fast FXRESTORE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                env->xmm_regs[i].XMM_Q(0) = ldq(addr);
+                env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+                addr += 16;
+            }
+        }
+    }
+}
+
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
+{
+    CPU_LDoubleU temp;
+
+    temp.d = f;
+    *pmant = temp.l.lower;
+    *pexp = temp.l.upper;
+}
+
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
+{
+    CPU_LDoubleU temp;
+
+    temp.l.upper = upper;
+    temp.l.lower = mant;
+    return temp.d;
+}
+
+#ifdef TARGET_X86_64
+
+//#define DEBUG_MULDIV
+
+static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    *plow += a;
+    /* carry test */
+    if (*plow < a)
+        (*phigh)++;
+    *phigh += b;
+}
+
+static void neg128(uint64_t *plow, uint64_t *phigh)
+{
+    *plow = ~ *plow;
+    *phigh = ~ *phigh;
+    add128(plow, phigh, 1, 0);
+}
+
+/* return TRUE if overflow */
+static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
+{
+    uint64_t q, r, a1, a0;
+    int i, qb, ab;
+
+    a0 = *plow;
+    a1 = *phigh;
+    if (a1 == 0) {
+        q = a0 / b;
+        r = a0 % b;
+        *plow = q;
+        *phigh = r;
+    } else {
+        if (a1 >= b)
+            return 1;
+        /* XXX: use a better algorithm */
+        for(i = 0; i < 64; i++) {
+            ab = a1 >> 63;
+            a1 = (a1 << 1) | (a0 >> 63);
+            if (ab || a1 >= b) {
+                a1 -= b;
+                qb = 1;
+            } else {
+                qb = 0;
+            }
+            a0 = (a0 << 1) | qb;
+        }
+#if defined(DEBUG_MULDIV)
+        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
+               *phigh, *plow, b, a0, a1);
+#endif
+        *plow = a0;
+        *phigh = a1;
+    }
+    return 0;
+}
+
+/* return TRUE if overflow */
+static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
+{
+    int sa, sb;
+    sa = ((int64_t)*phigh < 0);
+    if (sa)
+        neg128(plow, phigh);
+    sb = (b < 0);
+    if (sb)
+        b = -b;
+    if (div64(plow, phigh, b) != 0)
+        return 1;
+    if (sa ^ sb) {
+        if (*plow > (1ULL << 63))
+            return 1;
+        *plow = - *plow;
+    } else {
+        if (*plow >= (1ULL << 63))
+            return 1;
+    }
+    if (sa)
+        *phigh = - *phigh;
+    return 0;
+}
+
+void helper_mulq_EAX_T0(target_ulong t0)
+{
+    uint64_t r0, r1;
+
+    mulu64(&r0, &r1, EAX, t0);
+    EAX = r0;
+    EDX = r1;
+    CC_DST = r0;
+    CC_SRC = r1;
+}
+
+void helper_imulq_EAX_T0(target_ulong t0)
+{
+    uint64_t r0, r1;
+
+    muls64(&r0, &r1, EAX, t0);
+    EAX = r0;
+    EDX = r1;
+    CC_DST = r0;
+    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
+}
+
+target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
+{
+    uint64_t r0, r1;
+
+    muls64(&r0, &r1, t0, t1);
+    CC_DST = r0;
+    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
+    return r0;
+}
+
+void helper_divq_EAX(target_ulong t0)
+{
+    uint64_t r0, r1;
+    if (t0 == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    r0 = EAX;
+    r1 = EDX;
+    if (div64(&r0, &r1, t0))
+        raise_exception(EXCP00_DIVZ);
+    EAX = r0;
+    EDX = r1;
+}
+
+void helper_idivq_EAX(target_ulong t0)
+{
+    uint64_t r0, r1;
+    if (t0 == 0) {
+        raise_exception(EXCP00_DIVZ);
+    }
+    r0 = EAX;
+    r1 = EDX;
+    if (idiv64(&r0, &r1, t0))
+        raise_exception(EXCP00_DIVZ);
+    EAX = r0;
+    EDX = r1;
+}
+#endif
+
+static void do_hlt(void)
+{
+    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit(env);
+}
+
+void helper_hlt(int next_eip_addend)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
+    EIP += next_eip_addend;
+    
+    do_hlt();
+}
+
+void helper_monitor(target_ulong ptr)
+{
+    if ((uint32_t)ECX != 0)
+        raise_exception(EXCP0D_GPF);
+    /* XXX: store address ? */
+    helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
+}
+
+void helper_mwait(int next_eip_addend)
+{
+    if ((uint32_t)ECX != 0)
+        raise_exception(EXCP0D_GPF);
+    helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
+    EIP += next_eip_addend;
+
+    /* XXX: not complete but not completely erroneous */
+    if (env->cpu_index != 0 || env->next_cpu != NULL) {
+        /* more than one CPU: do not sleep because another CPU may
+           wake this one */
+    } else {
+        do_hlt();
+    }
+}
+
+void helper_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
+
+void helper_reset_rf(void)
+{
+    env->eflags &= ~RF_MASK;
+}
+
+void helper_raise_interrupt(int intno, int next_eip_addend)
+{
+    raise_interrupt(intno, 1, 0, next_eip_addend);
+}
+
+void helper_raise_exception(int exception_index)
+{
+    raise_exception(exception_index);
+}
+
+void helper_cli(void)
+{
+    env->eflags &= ~IF_MASK;
+}
+
+void helper_sti(void)
+{
+    env->eflags |= IF_MASK;
+}
+
+#if 0
+/* vm86plus instructions */
+void helper_cli_vm(void)
+{
+    env->eflags &= ~VIF_MASK;
+}
+
+void helper_sti_vm(void)
+{
+    env->eflags |= VIF_MASK;
+    if (env->eflags & VIP_MASK) {
+        raise_exception(EXCP0D_GPF);
+    }
+}
+#endif
+
+void helper_set_inhibit_irq(void)
+{
+    env->hflags |= HF_INHIBIT_IRQ_MASK;
+}
+
+void helper_reset_inhibit_irq(void)
+{
+    env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+}
+
+void helper_boundw(target_ulong a0, int v)
+{
+    int low, high;
+    low = ldsw(a0);
+    high = ldsw(a0 + 2);
+    v = (int16_t)v;
+    if (v < low || v > high) {
+        raise_exception(EXCP05_BOUND);
+    }
+}
+
+void helper_boundl(target_ulong a0, int v)
+{
+    int low, high;
+    low = ldl(a0);
+    high = ldl(a0 + 4);
+    if (v < low || v > high) {
+        raise_exception(EXCP05_BOUND);
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    int ret;
+    unsigned long pc;
+    CPUX86State *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (ret) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        raise_exception_err(env->exception_index, env->error_code);
+    }
+    env = saved_env;
+}
+#endif
+
+/* Secure Virtual Machine helpers */
+
+#if defined(CONFIG_USER_ONLY)
+
+void helper_vmrun(int aflag, int next_eip_addend)
+{ 
+}
+void helper_vmmcall(void) 
+{ 
+}
+void helper_vmload(int aflag)
+{ 
+}
+void helper_vmsave(int aflag)
+{ 
+}
+void helper_stgi(void)
+{
+}
+void helper_clgi(void)
+{
+}
+void helper_skinit(void) 
+{ 
+}
+void helper_invlpga(int aflag)
+{ 
+}
+void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 
+{ 
+}
+void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+}
+
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+}
+
+void helper_svm_check_io(uint32_t port, uint32_t param, 
+                         uint32_t next_eip_addend)
+{
+}
+#else
+
+static inline void svm_save_seg(target_phys_addr_t addr,
+                                const SegmentCache *sc)
+{
+    stw_phys(addr + offsetof(struct vmcb_seg, selector), 
+             sc->selector);
+    stq_phys(addr + offsetof(struct vmcb_seg, base), 
+             sc->base);
+    stl_phys(addr + offsetof(struct vmcb_seg, limit), 
+             sc->limit);
+    stw_phys(addr + offsetof(struct vmcb_seg, attrib), 
+             ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
+}
+                                
+static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
+{
+    unsigned int flags;
+
+    sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
+    sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
+    sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
+    flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
+    sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
+}
+
+static inline void svm_load_seg_cache(target_phys_addr_t addr, 
+                                      CPUState *env, int seg_reg)
+{
+    SegmentCache sc1, *sc = &sc1;
+    svm_load_seg(addr, sc);
+    cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
+                           sc->base, sc->limit, sc->flags);
+}
+
+void helper_vmrun(int aflag, int next_eip_addend)
+{
+    target_ulong addr;
+    uint32_t event_inj;
+    uint32_t int_ctl;
+
+    helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
+
+    env->vm_vmcb = addr;
+
+    /* save the current CPU state in the hsave page */
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
+
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es), 
+                  &env->segs[R_ES]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs), 
+                 &env->segs[R_CS]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss), 
+                 &env->segs[R_SS]);
+    svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), 
+                 &env->segs[R_DS]);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
+             EIP + next_eip_addend);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
+
+    /* load the interception bitmaps so we do not need to access the
+       vmcb in svm mode */
+    env->intercept            = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
+    env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
+    env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
+    env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
+    env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
+    env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
+
+    /* enable intercepts */
+    env->hflags |= HF_SVMI_MASK;
+
+    env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
+
+    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
+
+    /* clear exit_info_2 so we behave like the real hardware */
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
+    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
+    if (int_ctl & V_INTR_MASKING_MASK) {
+        env->v_tpr = int_ctl & V_TPR_MASK;
+        env->hflags2 |= HF2_VINTR_MASK;
+        if (env->eflags & IF_MASK)
+            env->hflags2 |= HF2_HIF_MASK;
+    }
+
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
+                       env, R_ES);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
+                       env, R_CS);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
+                       env, R_SS);
+    svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
+                       env, R_DS);
+
+    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
+    env->eip = EIP;
+    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
+    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
+    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
+    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
+
+    /* FIXME: guest state consistency checks */
+
+    switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
+        case TLB_CONTROL_DO_NOTHING:
+            break;
+        case TLB_CONTROL_FLUSH_ALL_ASID:
+            /* FIXME: this is not 100% correct but should work for now */
+            tlb_flush(env, 1);
+        break;
+    }
+
+    env->hflags2 |= HF2_GIF_MASK;
+
+    if (int_ctl & V_IRQ_MASK) {
+        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
+    }
+
+    /* maybe we need to inject an event */
+    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (event_inj & SVM_EVTINJ_VALID) {
+        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
+        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
+        uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
+
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
+        /* FIXME: need to implement valid_err */
+        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
+        case SVM_EVTINJ_TYPE_INTR:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = -1;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
+                /* XXX: is it always correct ? */
+                do_interrupt_all(vector, 0, 0, 0, 1);
+                break;
+        case SVM_EVTINJ_TYPE_NMI:
+                env->exception_index = EXCP02_NMI;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = EIP;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
+                cpu_loop_exit(env);
+                break;
+        case SVM_EVTINJ_TYPE_EXEPT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = -1;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
+                cpu_loop_exit(env);
+                break;
+        case SVM_EVTINJ_TYPE_SOFT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 1;
+                env->exception_next_eip = EIP;
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
+                cpu_loop_exit(env);
+                break;
+        }
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
+    }
+}
+
+void helper_vmmcall(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
+    raise_exception(EXCP06_ILLOP);
+}
+
+void helper_vmload(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
+                       env, R_FS);
+    svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
+                       env, R_GS);
+    svm_load_seg(addr + offsetof(struct vmcb, save.tr),
+                 &env->tr);
+    svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
+                 &env->ldt);
+
+#ifdef TARGET_X86_64
+    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
+    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
+    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
+    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
+#endif
+    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
+    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
+    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
+    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
+}
+
+void helper_vmsave(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    svm_save_seg(addr + offsetof(struct vmcb, save.fs), 
+                 &env->segs[R_FS]);
+    svm_save_seg(addr + offsetof(struct vmcb, save.gs), 
+                 &env->segs[R_GS]);
+    svm_save_seg(addr + offsetof(struct vmcb, save.tr), 
+                 &env->tr);
+    svm_save_seg(addr + offsetof(struct vmcb, save.ldtr), 
+                 &env->ldt);
+
+#ifdef TARGET_X86_64
+    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
+    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
+    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
+    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
+#endif
+    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
+}
+
+void helper_stgi(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
+    env->hflags2 |= HF2_GIF_MASK;
+}
+
+void helper_clgi(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
+    env->hflags2 &= ~HF2_GIF_MASK;
+}
+
+void helper_skinit(void)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
+    /* XXX: not implemented */
+    raise_exception(EXCP06_ILLOP);
+}
+
+void helper_invlpga(int aflag)
+{
+    target_ulong addr;
+    helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
+    
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    /* XXX: could use the ASID to see if it is needed to do the
+       flush */
+    tlb_flush_page(env, addr);
+}
+
+void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+    if (likely(!(env->hflags & HF_SVMI_MASK)))
+        return;
+    switch(type) {
+    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
+        if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
+        if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
+        if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
+        if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
+        if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    case SVM_EXIT_MSR:
+        if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
+            /* FIXME: this should be read in at vmrun (faster this way?) */
+            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
+            uint32_t t0, t1;
+            switch((uint32_t)ECX) {
+            case 0 ... 0x1fff:
+                t0 = (ECX * 2) % 8;
+                t1 = (ECX * 2) / 8;
+                break;
+            case 0xc0000000 ... 0xc0001fff:
+                t0 = (8192 + ECX - 0xc0000000) * 2;
+                t1 = (t0 / 8);
+                t0 %= 8;
+                break;
+            case 0xc0010000 ... 0xc0011fff:
+                t0 = (16384 + ECX - 0xc0010000) * 2;
+                t1 = (t0 / 8);
+                t0 %= 8;
+                break;
+            default:
+                helper_vmexit(type, param);
+                t0 = 0;
+                t1 = 0;
+                break;
+            }
+            if (ldub_phys(addr + t1) & ((1 << param) << t0))
+                helper_vmexit(type, param);
+        }
+        break;
+    default:
+        if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
+            helper_vmexit(type, param);
+        }
+        break;
+    }
+}
+
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    helper_svm_check_intercept_param(type, 0);
+    env = saved_env;
+}
+
+void helper_svm_check_io(uint32_t port, uint32_t param, 
+                         uint32_t next_eip_addend)
+{
+    if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
+        /* FIXME: this should be read in at vmrun (faster this way?) */
+        uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
+        uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
+        if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
+            /* next EIP */
+            stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 
+                     env->eip + next_eip_addend);
+            helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
+        }
+    }
+}
+
+/* Note: currently only 32 bits of exit_code are used */
+void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
+{
+    uint32_t int_ctl;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
+                exit_code, exit_info_1,
+                ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
+                EIP);
+
+    if(env->hflags & HF_INHIBIT_IRQ_MASK) {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
+        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+    } else {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
+    }
+
+    /* Save the VM state in the vmcb */
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es), 
+                 &env->segs[R_ES]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs), 
+                 &env->segs[R_CS]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss), 
+                 &env->segs[R_SS]);
+    svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds), 
+                 &env->segs[R_DS]);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
+
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
+    int_ctl |= env->v_tpr & V_TPR_MASK;
+    if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
+        int_ctl |= V_IRQ_MASK;
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
+
+    /* Reload the host state from vm_hsave */
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
+    env->hflags &= ~HF_SVMI_MASK;
+    env->intercept = 0;
+    env->intercept_exceptions = 0;
+    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+    env->tsc_offset = 0;
+
+    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
+    /* we need to set the efer after the crs so the hidden flags get
+       set properly */
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
+                       env, R_ES);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
+                       env, R_CS);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
+                       env, R_SS);
+    svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
+                       env, R_DS);
+
+    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
+    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
+
+    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
+    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
+
+    /* other setups */
+    cpu_x86_set_cpl(env, 0);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
+
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
+
+    env->hflags2 &= ~HF2_GIF_MASK;
+    /* FIXME: Resets the current ASID register to zero (host ASID). */
+
+    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
+
+    /* Clears the TSC_OFFSET inside the processor. */
+
+    /* If the host is in PAE mode, the processor reloads the host's PDPEs
+       from the page table indicated the host's CR3. If the PDPEs contain
+       illegal state, the processor causes a shutdown. */
+
+    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
+    env->cr[0] |= CR0_PE_MASK;
+    env->eflags &= ~VM_MASK;
+
+    /* Disables all breakpoints in the host DR7 register. */
+
+    /* Checks the reloaded host state for consistency. */
+
+    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
+       host's code segment or non-canonical (in the case of long mode), a
+       #GP fault is delivered inside the host.) */
+
+    /* remove any pending exception */
+    env->exception_index = -1;
+    env->error_code = 0;
+    env->old_exception = -1;
+
+    cpu_loop_exit(env);
+}
+
+#endif
+
+/* MMX/SSE */
+/* XXX: optimize by storing fptt and fptags in the static cpu state */
+void helper_enter_mmx(void)
+{
+    env->fpstt = 0;
+    *(uint32_t *)(env->fptags) = 0;
+    *(uint32_t *)(env->fptags + 4) = 0;
+}
+
+void helper_emms(void)
+{
+    /* set to empty state */
+    *(uint32_t *)(env->fptags) = 0x01010101;
+    *(uint32_t *)(env->fptags + 4) = 0x01010101;
+}
+
+/* XXX: suppress */
+void helper_movq(void *d, void *s)
+{
+    *(uint64_t *)d = *(uint64_t *)s;
+}
+
+#define SHIFT 0
+#include "ops_sse.h"
+
+#define SHIFT 1
+#include "ops_sse.h"
+
+#define SHIFT 0
+#include "helper_template.h"
+#undef SHIFT
+
+#define SHIFT 1
+#include "helper_template.h"
+#undef SHIFT
+
+#define SHIFT 2
+#include "helper_template.h"
+#undef SHIFT
+
+#ifdef TARGET_X86_64
+
+#define SHIFT 3
+#include "helper_template.h"
+#undef SHIFT
+
+#endif
+
+/* bit operations */
+target_ulong helper_bsf(target_ulong t0)
+{
+    int count;
+    target_ulong res;
+
+    res = t0;
+    count = 0;
+    while ((res & 1) == 0) {
+        count++;
+        res >>= 1;
+    }
+    return count;
+}
+
+target_ulong helper_lzcnt(target_ulong t0, int wordsize)
+{
+    int count;
+    target_ulong res, mask;
+
+    if (wordsize > 0 && t0 == 0) {
+        return wordsize;
+    }
+    res = t0;
+    count = TARGET_LONG_BITS - 1;
+    mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
+    while ((res & mask) == 0) {
+        count--;
+        res <<= 1;
+    }
+    if (wordsize > 0) {
+        return wordsize - 1 - count;
+    }
+    return count;
+}
+
+target_ulong helper_bsr(target_ulong t0)
+{
+	return helper_lzcnt(t0, 0);
+}
+
+static int compute_all_eflags(void)
+{
+    return CC_SRC;
+}
+
+static int compute_c_eflags(void)
+{
+    return CC_SRC & CC_C;
+}
+
+uint32_t helper_cc_compute_all(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
+
+    case CC_OP_EFLAGS: return compute_all_eflags();
+
+    case CC_OP_MULB: return compute_all_mulb();
+    case CC_OP_MULW: return compute_all_mulw();
+    case CC_OP_MULL: return compute_all_mull();
+
+    case CC_OP_ADDB: return compute_all_addb();
+    case CC_OP_ADDW: return compute_all_addw();
+    case CC_OP_ADDL: return compute_all_addl();
+
+    case CC_OP_ADCB: return compute_all_adcb();
+    case CC_OP_ADCW: return compute_all_adcw();
+    case CC_OP_ADCL: return compute_all_adcl();
+
+    case CC_OP_SUBB: return compute_all_subb();
+    case CC_OP_SUBW: return compute_all_subw();
+    case CC_OP_SUBL: return compute_all_subl();
+
+    case CC_OP_SBBB: return compute_all_sbbb();
+    case CC_OP_SBBW: return compute_all_sbbw();
+    case CC_OP_SBBL: return compute_all_sbbl();
+
+    case CC_OP_LOGICB: return compute_all_logicb();
+    case CC_OP_LOGICW: return compute_all_logicw();
+    case CC_OP_LOGICL: return compute_all_logicl();
+
+    case CC_OP_INCB: return compute_all_incb();
+    case CC_OP_INCW: return compute_all_incw();
+    case CC_OP_INCL: return compute_all_incl();
+
+    case CC_OP_DECB: return compute_all_decb();
+    case CC_OP_DECW: return compute_all_decw();
+    case CC_OP_DECL: return compute_all_decl();
+
+    case CC_OP_SHLB: return compute_all_shlb();
+    case CC_OP_SHLW: return compute_all_shlw();
+    case CC_OP_SHLL: return compute_all_shll();
+
+    case CC_OP_SARB: return compute_all_sarb();
+    case CC_OP_SARW: return compute_all_sarw();
+    case CC_OP_SARL: return compute_all_sarl();
+
+#ifdef TARGET_X86_64
+    case CC_OP_MULQ: return compute_all_mulq();
+
+    case CC_OP_ADDQ: return compute_all_addq();
+
+    case CC_OP_ADCQ: return compute_all_adcq();
+
+    case CC_OP_SUBQ: return compute_all_subq();
+
+    case CC_OP_SBBQ: return compute_all_sbbq();
+
+    case CC_OP_LOGICQ: return compute_all_logicq();
+
+    case CC_OP_INCQ: return compute_all_incq();
+
+    case CC_OP_DECQ: return compute_all_decq();
+
+    case CC_OP_SHLQ: return compute_all_shlq();
+
+    case CC_OP_SARQ: return compute_all_sarq();
+#endif
+    }
+}
+
+uint32_t cpu_cc_compute_all(CPUState *env1, int op)
+{
+    CPUState *saved_env;
+    uint32_t ret;
+
+    saved_env = env;
+    env = env1;
+    ret = helper_cc_compute_all(op);
+    env = saved_env;
+    return ret;
+}
+
+uint32_t helper_cc_compute_c(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
+
+    case CC_OP_EFLAGS: return compute_c_eflags();
+
+    case CC_OP_MULB: return compute_c_mull();
+    case CC_OP_MULW: return compute_c_mull();
+    case CC_OP_MULL: return compute_c_mull();
+
+    case CC_OP_ADDB: return compute_c_addb();
+    case CC_OP_ADDW: return compute_c_addw();
+    case CC_OP_ADDL: return compute_c_addl();
+
+    case CC_OP_ADCB: return compute_c_adcb();
+    case CC_OP_ADCW: return compute_c_adcw();
+    case CC_OP_ADCL: return compute_c_adcl();
+
+    case CC_OP_SUBB: return compute_c_subb();
+    case CC_OP_SUBW: return compute_c_subw();
+    case CC_OP_SUBL: return compute_c_subl();
+
+    case CC_OP_SBBB: return compute_c_sbbb();
+    case CC_OP_SBBW: return compute_c_sbbw();
+    case CC_OP_SBBL: return compute_c_sbbl();
+
+    case CC_OP_LOGICB: return compute_c_logicb();
+    case CC_OP_LOGICW: return compute_c_logicw();
+    case CC_OP_LOGICL: return compute_c_logicl();
+
+    case CC_OP_INCB: return compute_c_incl();
+    case CC_OP_INCW: return compute_c_incl();
+    case CC_OP_INCL: return compute_c_incl();
+
+    case CC_OP_DECB: return compute_c_incl();
+    case CC_OP_DECW: return compute_c_incl();
+    case CC_OP_DECL: return compute_c_incl();
+
+    case CC_OP_SHLB: return compute_c_shlb();
+    case CC_OP_SHLW: return compute_c_shlw();
+    case CC_OP_SHLL: return compute_c_shll();
+
+    case CC_OP_SARB: return compute_c_sarl();
+    case CC_OP_SARW: return compute_c_sarl();
+    case CC_OP_SARL: return compute_c_sarl();
+
+#ifdef TARGET_X86_64
+    case CC_OP_MULQ: return compute_c_mull();
+
+    case CC_OP_ADDQ: return compute_c_addq();
+
+    case CC_OP_ADCQ: return compute_c_adcq();
+
+    case CC_OP_SUBQ: return compute_c_subq();
+
+    case CC_OP_SBBQ: return compute_c_sbbq();
+
+    case CC_OP_LOGICQ: return compute_c_logicq();
+
+    case CC_OP_INCQ: return compute_c_incl();
+
+    case CC_OP_DECQ: return compute_c_incl();
+
+    case CC_OP_SHLQ: return compute_c_shlq();
+
+    case CC_OP_SARQ: return compute_c_sarl();
+#endif
+    }
+}
diff --git a/qemu-0.15.x/target-i386/ops_sse.h b/qemu-0.15.x/target-i386/ops_sse.h
new file mode 100644
index 0000000..703be99
--- /dev/null
+++ b/qemu-0.15.x/target-i386/ops_sse.h
@@ -0,0 +1,2087 @@
+/*
+ *  MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI support
+ *
+ *  Copyright (c) 2005 Fabrice Bellard
+ *  Copyright (c) 2008 Intel Corporation  <andrew.zaborowski at intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if SHIFT == 0
+#define Reg MMXReg
+#define XMM_ONLY(...)
+#define B(n) MMX_B(n)
+#define W(n) MMX_W(n)
+#define L(n) MMX_L(n)
+#define Q(n) q
+#define SUFFIX _mmx
+#else
+#define Reg XMMReg
+#define XMM_ONLY(...) __VA_ARGS__
+#define B(n) XMM_B(n)
+#define W(n) XMM_W(n)
+#define L(n) XMM_L(n)
+#define Q(n) XMM_Q(n)
+#define SUFFIX _xmm
+#endif
+
+void glue(helper_psrlw, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 15) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->W(0) >>= shift;
+        d->W(1) >>= shift;
+        d->W(2) >>= shift;
+        d->W(3) >>= shift;
+#if SHIFT == 1
+        d->W(4) >>= shift;
+        d->W(5) >>= shift;
+        d->W(6) >>= shift;
+        d->W(7) >>= shift;
+#endif
+    }
+}
+
+void glue(helper_psraw, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 15) {
+        shift = 15;
+    } else {
+        shift = s->B(0);
+    }
+    d->W(0) = (int16_t)d->W(0) >> shift;
+    d->W(1) = (int16_t)d->W(1) >> shift;
+    d->W(2) = (int16_t)d->W(2) >> shift;
+    d->W(3) = (int16_t)d->W(3) >> shift;
+#if SHIFT == 1
+    d->W(4) = (int16_t)d->W(4) >> shift;
+    d->W(5) = (int16_t)d->W(5) >> shift;
+    d->W(6) = (int16_t)d->W(6) >> shift;
+    d->W(7) = (int16_t)d->W(7) >> shift;
+#endif
+}
+
+void glue(helper_psllw, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 15) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->W(0) <<= shift;
+        d->W(1) <<= shift;
+        d->W(2) <<= shift;
+        d->W(3) <<= shift;
+#if SHIFT == 1
+        d->W(4) <<= shift;
+        d->W(5) <<= shift;
+        d->W(6) <<= shift;
+        d->W(7) <<= shift;
+#endif
+    }
+}
+
+void glue(helper_psrld, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 31) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->L(0) >>= shift;
+        d->L(1) >>= shift;
+#if SHIFT == 1
+        d->L(2) >>= shift;
+        d->L(3) >>= shift;
+#endif
+    }
+}
+
+void glue(helper_psrad, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 31) {
+        shift = 31;
+    } else {
+        shift = s->B(0);
+    }
+    d->L(0) = (int32_t)d->L(0) >> shift;
+    d->L(1) = (int32_t)d->L(1) >> shift;
+#if SHIFT == 1
+    d->L(2) = (int32_t)d->L(2) >> shift;
+    d->L(3) = (int32_t)d->L(3) >> shift;
+#endif
+}
+
+void glue(helper_pslld, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 31) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->L(0) <<= shift;
+        d->L(1) <<= shift;
+#if SHIFT == 1
+        d->L(2) <<= shift;
+        d->L(3) <<= shift;
+#endif
+    }
+}
+
+void glue(helper_psrlq, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 63) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->Q(0) >>= shift;
+#if SHIFT == 1
+        d->Q(1) >>= shift;
+#endif
+    }
+}
+
+void glue(helper_psllq, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift;
+
+    if (s->Q(0) > 63) {
+        d->Q(0) = 0;
+#if SHIFT == 1
+        d->Q(1) = 0;
+#endif
+    } else {
+        shift = s->B(0);
+        d->Q(0) <<= shift;
+#if SHIFT == 1
+        d->Q(1) <<= shift;
+#endif
+    }
+}
+
+#if SHIFT == 1
+void glue(helper_psrldq, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift, i;
+
+    shift = s->L(0);
+    if (shift > 16)
+        shift = 16;
+    for(i = 0; i < 16 - shift; i++)
+        d->B(i) = d->B(i + shift);
+    for(i = 16 - shift; i < 16; i++)
+        d->B(i) = 0;
+}
+
+void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
+{
+    int shift, i;
+
+    shift = s->L(0);
+    if (shift > 16)
+        shift = 16;
+    for(i = 15; i >= shift; i--)
+        d->B(i) = d->B(i - shift);
+    for(i = 0; i < shift; i++)
+        d->B(i) = 0;
+}
+#endif
+
+#define SSE_HELPER_B(name, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->B(0) = F(d->B(0), s->B(0));\
+    d->B(1) = F(d->B(1), s->B(1));\
+    d->B(2) = F(d->B(2), s->B(2));\
+    d->B(3) = F(d->B(3), s->B(3));\
+    d->B(4) = F(d->B(4), s->B(4));\
+    d->B(5) = F(d->B(5), s->B(5));\
+    d->B(6) = F(d->B(6), s->B(6));\
+    d->B(7) = F(d->B(7), s->B(7));\
+    XMM_ONLY(\
+    d->B(8) = F(d->B(8), s->B(8));\
+    d->B(9) = F(d->B(9), s->B(9));\
+    d->B(10) = F(d->B(10), s->B(10));\
+    d->B(11) = F(d->B(11), s->B(11));\
+    d->B(12) = F(d->B(12), s->B(12));\
+    d->B(13) = F(d->B(13), s->B(13));\
+    d->B(14) = F(d->B(14), s->B(14));\
+    d->B(15) = F(d->B(15), s->B(15));\
+    )\
+}
+
+#define SSE_HELPER_W(name, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->W(0) = F(d->W(0), s->W(0));\
+    d->W(1) = F(d->W(1), s->W(1));\
+    d->W(2) = F(d->W(2), s->W(2));\
+    d->W(3) = F(d->W(3), s->W(3));\
+    XMM_ONLY(\
+    d->W(4) = F(d->W(4), s->W(4));\
+    d->W(5) = F(d->W(5), s->W(5));\
+    d->W(6) = F(d->W(6), s->W(6));\
+    d->W(7) = F(d->W(7), s->W(7));\
+    )\
+}
+
+#define SSE_HELPER_L(name, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->L(0) = F(d->L(0), s->L(0));\
+    d->L(1) = F(d->L(1), s->L(1));\
+    XMM_ONLY(\
+    d->L(2) = F(d->L(2), s->L(2));\
+    d->L(3) = F(d->L(3), s->L(3));\
+    )\
+}
+
+#define SSE_HELPER_Q(name, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->Q(0) = F(d->Q(0), s->Q(0));\
+    XMM_ONLY(\
+    d->Q(1) = F(d->Q(1), s->Q(1));\
+    )\
+}
+
+#if SHIFT == 0
+static inline int satub(int x)
+{
+    if (x < 0)
+        return 0;
+    else if (x > 255)
+        return 255;
+    else
+        return x;
+}
+
+static inline int satuw(int x)
+{
+    if (x < 0)
+        return 0;
+    else if (x > 65535)
+        return 65535;
+    else
+        return x;
+}
+
+static inline int satsb(int x)
+{
+    if (x < -128)
+        return -128;
+    else if (x > 127)
+        return 127;
+    else
+        return x;
+}
+
+static inline int satsw(int x)
+{
+    if (x < -32768)
+        return -32768;
+    else if (x > 32767)
+        return 32767;
+    else
+        return x;
+}
+
+#define FADD(a, b) ((a) + (b))
+#define FADDUB(a, b) satub((a) + (b))
+#define FADDUW(a, b) satuw((a) + (b))
+#define FADDSB(a, b) satsb((int8_t)(a) + (int8_t)(b))
+#define FADDSW(a, b) satsw((int16_t)(a) + (int16_t)(b))
+
+#define FSUB(a, b) ((a) - (b))
+#define FSUBUB(a, b) satub((a) - (b))
+#define FSUBUW(a, b) satuw((a) - (b))
+#define FSUBSB(a, b) satsb((int8_t)(a) - (int8_t)(b))
+#define FSUBSW(a, b) satsw((int16_t)(a) - (int16_t)(b))
+#define FMINUB(a, b) ((a) < (b)) ? (a) : (b)
+#define FMINSW(a, b) ((int16_t)(a) < (int16_t)(b)) ? (a) : (b)
+#define FMAXUB(a, b) ((a) > (b)) ? (a) : (b)
+#define FMAXSW(a, b) ((int16_t)(a) > (int16_t)(b)) ? (a) : (b)
+
+#define FAND(a, b) (a) & (b)
+#define FANDN(a, b) ((~(a)) & (b))
+#define FOR(a, b) (a) | (b)
+#define FXOR(a, b) (a) ^ (b)
+
+#define FCMPGTB(a, b) (int8_t)(a) > (int8_t)(b) ? -1 : 0
+#define FCMPGTW(a, b) (int16_t)(a) > (int16_t)(b) ? -1 : 0
+#define FCMPGTL(a, b) (int32_t)(a) > (int32_t)(b) ? -1 : 0
+#define FCMPEQ(a, b) (a) == (b) ? -1 : 0
+
+#define FMULLW(a, b) (a) * (b)
+#define FMULHRW(a, b) ((int16_t)(a) * (int16_t)(b) + 0x8000) >> 16
+#define FMULHUW(a, b) (a) * (b) >> 16
+#define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16
+
+#define FAVG(a, b) ((a) + (b) + 1) >> 1
+#endif
+
+SSE_HELPER_B(helper_paddb, FADD)
+SSE_HELPER_W(helper_paddw, FADD)
+SSE_HELPER_L(helper_paddl, FADD)
+SSE_HELPER_Q(helper_paddq, FADD)
+
+SSE_HELPER_B(helper_psubb, FSUB)
+SSE_HELPER_W(helper_psubw, FSUB)
+SSE_HELPER_L(helper_psubl, FSUB)
+SSE_HELPER_Q(helper_psubq, FSUB)
+
+SSE_HELPER_B(helper_paddusb, FADDUB)
+SSE_HELPER_B(helper_paddsb, FADDSB)
+SSE_HELPER_B(helper_psubusb, FSUBUB)
+SSE_HELPER_B(helper_psubsb, FSUBSB)
+
+SSE_HELPER_W(helper_paddusw, FADDUW)
+SSE_HELPER_W(helper_paddsw, FADDSW)
+SSE_HELPER_W(helper_psubusw, FSUBUW)
+SSE_HELPER_W(helper_psubsw, FSUBSW)
+
+SSE_HELPER_B(helper_pminub, FMINUB)
+SSE_HELPER_B(helper_pmaxub, FMAXUB)
+
+SSE_HELPER_W(helper_pminsw, FMINSW)
+SSE_HELPER_W(helper_pmaxsw, FMAXSW)
+
+SSE_HELPER_Q(helper_pand, FAND)
+SSE_HELPER_Q(helper_pandn, FANDN)
+SSE_HELPER_Q(helper_por, FOR)
+SSE_HELPER_Q(helper_pxor, FXOR)
+
+SSE_HELPER_B(helper_pcmpgtb, FCMPGTB)
+SSE_HELPER_W(helper_pcmpgtw, FCMPGTW)
+SSE_HELPER_L(helper_pcmpgtl, FCMPGTL)
+
+SSE_HELPER_B(helper_pcmpeqb, FCMPEQ)
+SSE_HELPER_W(helper_pcmpeqw, FCMPEQ)
+SSE_HELPER_L(helper_pcmpeql, FCMPEQ)
+
+SSE_HELPER_W(helper_pmullw, FMULLW)
+#if SHIFT == 0
+SSE_HELPER_W(helper_pmulhrw, FMULHRW)
+#endif
+SSE_HELPER_W(helper_pmulhuw, FMULHUW)
+SSE_HELPER_W(helper_pmulhw, FMULHW)
+
+SSE_HELPER_B(helper_pavgb, FAVG)
+SSE_HELPER_W(helper_pavgw, FAVG)
+
+void glue(helper_pmuludq, SUFFIX) (Reg *d, Reg *s)
+{
+    d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0);
+#if SHIFT == 1
+    d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2);
+#endif
+}
+
+void glue(helper_pmaddwd, SUFFIX) (Reg *d, Reg *s)
+{
+    int i;
+
+    for(i = 0; i < (2 << SHIFT); i++) {
+        d->L(i) = (int16_t)s->W(2*i) * (int16_t)d->W(2*i) +
+            (int16_t)s->W(2*i+1) * (int16_t)d->W(2*i+1);
+    }
+}
+
+#if SHIFT == 0
+static inline int abs1(int a)
+{
+    if (a < 0)
+        return -a;
+    else
+        return a;
+}
+#endif
+void glue(helper_psadbw, SUFFIX) (Reg *d, Reg *s)
+{
+    unsigned int val;
+
+    val = 0;
+    val += abs1(d->B(0) - s->B(0));
+    val += abs1(d->B(1) - s->B(1));
+    val += abs1(d->B(2) - s->B(2));
+    val += abs1(d->B(3) - s->B(3));
+    val += abs1(d->B(4) - s->B(4));
+    val += abs1(d->B(5) - s->B(5));
+    val += abs1(d->B(6) - s->B(6));
+    val += abs1(d->B(7) - s->B(7));
+    d->Q(0) = val;
+#if SHIFT == 1
+    val = 0;
+    val += abs1(d->B(8) - s->B(8));
+    val += abs1(d->B(9) - s->B(9));
+    val += abs1(d->B(10) - s->B(10));
+    val += abs1(d->B(11) - s->B(11));
+    val += abs1(d->B(12) - s->B(12));
+    val += abs1(d->B(13) - s->B(13));
+    val += abs1(d->B(14) - s->B(14));
+    val += abs1(d->B(15) - s->B(15));
+    d->Q(1) = val;
+#endif
+}
+
+void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s, target_ulong a0)
+{
+    int i;
+    for(i = 0; i < (8 << SHIFT); i++) {
+        if (s->B(i) & 0x80)
+            stb(a0 + i, d->B(i));
+    }
+}
+
+void glue(helper_movl_mm_T0, SUFFIX) (Reg *d, uint32_t val)
+{
+    d->L(0) = val;
+    d->L(1) = 0;
+#if SHIFT == 1
+    d->Q(1) = 0;
+#endif
+}
+
+#ifdef TARGET_X86_64
+void glue(helper_movq_mm_T0, SUFFIX) (Reg *d, uint64_t val)
+{
+    d->Q(0) = val;
+#if SHIFT == 1
+    d->Q(1) = 0;
+#endif
+}
+#endif
+
+#if SHIFT == 0
+void glue(helper_pshufw, SUFFIX) (Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.W(0) = s->W(order & 3);
+    r.W(1) = s->W((order >> 2) & 3);
+    r.W(2) = s->W((order >> 4) & 3);
+    r.W(3) = s->W((order >> 6) & 3);
+    *d = r;
+}
+#else
+void helper_shufps(Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.L(0) = d->L(order & 3);
+    r.L(1) = d->L((order >> 2) & 3);
+    r.L(2) = s->L((order >> 4) & 3);
+    r.L(3) = s->L((order >> 6) & 3);
+    *d = r;
+}
+
+void helper_shufpd(Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.Q(0) = d->Q(order & 1);
+    r.Q(1) = s->Q((order >> 1) & 1);
+    *d = r;
+}
+
+void glue(helper_pshufd, SUFFIX) (Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.L(0) = s->L(order & 3);
+    r.L(1) = s->L((order >> 2) & 3);
+    r.L(2) = s->L((order >> 4) & 3);
+    r.L(3) = s->L((order >> 6) & 3);
+    *d = r;
+}
+
+void glue(helper_pshuflw, SUFFIX) (Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.W(0) = s->W(order & 3);
+    r.W(1) = s->W((order >> 2) & 3);
+    r.W(2) = s->W((order >> 4) & 3);
+    r.W(3) = s->W((order >> 6) & 3);
+    r.Q(1) = s->Q(1);
+    *d = r;
+}
+
+void glue(helper_pshufhw, SUFFIX) (Reg *d, Reg *s, int order)
+{
+    Reg r;
+    r.Q(0) = s->Q(0);
+    r.W(4) = s->W(4 + (order & 3));
+    r.W(5) = s->W(4 + ((order >> 2) & 3));
+    r.W(6) = s->W(4 + ((order >> 4) & 3));
+    r.W(7) = s->W(4 + ((order >> 6) & 3));
+    *d = r;
+}
+#endif
+
+#if SHIFT == 1
+/* FPU ops */
+/* XXX: not accurate */
+
+#define SSE_HELPER_S(name, F)\
+void helper_ ## name ## ps (Reg *d, Reg *s)\
+{\
+    d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
+    d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1));\
+    d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2));\
+    d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3));\
+}\
+\
+void helper_ ## name ## ss (Reg *d, Reg *s)\
+{\
+    d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
+}\
+void helper_ ## name ## pd (Reg *d, Reg *s)\
+{\
+    d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
+    d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1));\
+}\
+\
+void helper_ ## name ## sd (Reg *d, Reg *s)\
+{\
+    d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
+}
+
+#define FPU_ADD(size, a, b) float ## size ## _add(a, b, &env->sse_status)
+#define FPU_SUB(size, a, b) float ## size ## _sub(a, b, &env->sse_status)
+#define FPU_MUL(size, a, b) float ## size ## _mul(a, b, &env->sse_status)
+#define FPU_DIV(size, a, b) float ## size ## _div(a, b, &env->sse_status)
+#define FPU_MIN(size, a, b) (a) < (b) ? (a) : (b)
+#define FPU_MAX(size, a, b) (a) > (b) ? (a) : (b)
+#define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, &env->sse_status)
+
+SSE_HELPER_S(add, FPU_ADD)
+SSE_HELPER_S(sub, FPU_SUB)
+SSE_HELPER_S(mul, FPU_MUL)
+SSE_HELPER_S(div, FPU_DIV)
+SSE_HELPER_S(min, FPU_MIN)
+SSE_HELPER_S(max, FPU_MAX)
+SSE_HELPER_S(sqrt, FPU_SQRT)
+
+
+/* float to float conversions */
+void helper_cvtps2pd(Reg *d, Reg *s)
+{
+    float32 s0, s1;
+    s0 = s->XMM_S(0);
+    s1 = s->XMM_S(1);
+    d->XMM_D(0) = float32_to_float64(s0, &env->sse_status);
+    d->XMM_D(1) = float32_to_float64(s1, &env->sse_status);
+}
+
+void helper_cvtpd2ps(Reg *d, Reg *s)
+{
+    d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
+    d->XMM_S(1) = float64_to_float32(s->XMM_D(1), &env->sse_status);
+    d->Q(1) = 0;
+}
+
+void helper_cvtss2sd(Reg *d, Reg *s)
+{
+    d->XMM_D(0) = float32_to_float64(s->XMM_S(0), &env->sse_status);
+}
+
+void helper_cvtsd2ss(Reg *d, Reg *s)
+{
+    d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
+}
+
+/* integer to float */
+void helper_cvtdq2ps(Reg *d, Reg *s)
+{
+    d->XMM_S(0) = int32_to_float32(s->XMM_L(0), &env->sse_status);
+    d->XMM_S(1) = int32_to_float32(s->XMM_L(1), &env->sse_status);
+    d->XMM_S(2) = int32_to_float32(s->XMM_L(2), &env->sse_status);
+    d->XMM_S(3) = int32_to_float32(s->XMM_L(3), &env->sse_status);
+}
+
+void helper_cvtdq2pd(Reg *d, Reg *s)
+{
+    int32_t l0, l1;
+    l0 = (int32_t)s->XMM_L(0);
+    l1 = (int32_t)s->XMM_L(1);
+    d->XMM_D(0) = int32_to_float64(l0, &env->sse_status);
+    d->XMM_D(1) = int32_to_float64(l1, &env->sse_status);
+}
+
+void helper_cvtpi2ps(XMMReg *d, MMXReg *s)
+{
+    d->XMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status);
+    d->XMM_S(1) = int32_to_float32(s->MMX_L(1), &env->sse_status);
+}
+
+void helper_cvtpi2pd(XMMReg *d, MMXReg *s)
+{
+    d->XMM_D(0) = int32_to_float64(s->MMX_L(0), &env->sse_status);
+    d->XMM_D(1) = int32_to_float64(s->MMX_L(1), &env->sse_status);
+}
+
+void helper_cvtsi2ss(XMMReg *d, uint32_t val)
+{
+    d->XMM_S(0) = int32_to_float32(val, &env->sse_status);
+}
+
+void helper_cvtsi2sd(XMMReg *d, uint32_t val)
+{
+    d->XMM_D(0) = int32_to_float64(val, &env->sse_status);
+}
+
+#ifdef TARGET_X86_64
+void helper_cvtsq2ss(XMMReg *d, uint64_t val)
+{
+    d->XMM_S(0) = int64_to_float32(val, &env->sse_status);
+}
+
+void helper_cvtsq2sd(XMMReg *d, uint64_t val)
+{
+    d->XMM_D(0) = int64_to_float64(val, &env->sse_status);
+}
+#endif
+
+/* float to integer */
+void helper_cvtps2dq(XMMReg *d, XMMReg *s)
+{
+    d->XMM_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
+    d->XMM_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
+    d->XMM_L(2) = float32_to_int32(s->XMM_S(2), &env->sse_status);
+    d->XMM_L(3) = float32_to_int32(s->XMM_S(3), &env->sse_status);
+}
+
+void helper_cvtpd2dq(XMMReg *d, XMMReg *s)
+{
+    d->XMM_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
+    d->XMM_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
+    d->XMM_Q(1) = 0;
+}
+
+void helper_cvtps2pi(MMXReg *d, XMMReg *s)
+{
+    d->MMX_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
+    d->MMX_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
+}
+
+void helper_cvtpd2pi(MMXReg *d, XMMReg *s)
+{
+    d->MMX_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
+    d->MMX_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
+}
+
+int32_t helper_cvtss2si(XMMReg *s)
+{
+    return float32_to_int32(s->XMM_S(0), &env->sse_status);
+}
+
+int32_t helper_cvtsd2si(XMMReg *s)
+{
+    return float64_to_int32(s->XMM_D(0), &env->sse_status);
+}
+
+#ifdef TARGET_X86_64
+int64_t helper_cvtss2sq(XMMReg *s)
+{
+    return float32_to_int64(s->XMM_S(0), &env->sse_status);
+}
+
+int64_t helper_cvtsd2sq(XMMReg *s)
+{
+    return float64_to_int64(s->XMM_D(0), &env->sse_status);
+}
+#endif
+
+/* float to integer truncated */
+void helper_cvttps2dq(XMMReg *d, XMMReg *s)
+{
+    d->XMM_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
+    d->XMM_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
+    d->XMM_L(2) = float32_to_int32_round_to_zero(s->XMM_S(2), &env->sse_status);
+    d->XMM_L(3) = float32_to_int32_round_to_zero(s->XMM_S(3), &env->sse_status);
+}
+
+void helper_cvttpd2dq(XMMReg *d, XMMReg *s)
+{
+    d->XMM_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
+    d->XMM_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
+    d->XMM_Q(1) = 0;
+}
+
+void helper_cvttps2pi(MMXReg *d, XMMReg *s)
+{
+    d->MMX_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
+    d->MMX_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
+}
+
+void helper_cvttpd2pi(MMXReg *d, XMMReg *s)
+{
+    d->MMX_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
+    d->MMX_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
+}
+
+int32_t helper_cvttss2si(XMMReg *s)
+{
+    return float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
+}
+
+int32_t helper_cvttsd2si(XMMReg *s)
+{
+    return float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
+}
+
+#ifdef TARGET_X86_64
+int64_t helper_cvttss2sq(XMMReg *s)
+{
+    return float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status);
+}
+
+int64_t helper_cvttsd2sq(XMMReg *s)
+{
+    return float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status);
+}
+#endif
+
+void helper_rsqrtps(XMMReg *d, XMMReg *s)
+{
+    d->XMM_S(0) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(0), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(1) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(1), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(2) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(2), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(3) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(3), &env->sse_status),
+                              &env->sse_status);
+}
+
+void helper_rsqrtss(XMMReg *d, XMMReg *s)
+{
+    d->XMM_S(0) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(0), &env->sse_status),
+                              &env->sse_status);
+}
+
+void helper_rcpps(XMMReg *d, XMMReg *s)
+{
+    d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
+    d->XMM_S(1) = float32_div(float32_one, s->XMM_S(1), &env->sse_status);
+    d->XMM_S(2) = float32_div(float32_one, s->XMM_S(2), &env->sse_status);
+    d->XMM_S(3) = float32_div(float32_one, s->XMM_S(3), &env->sse_status);
+}
+
+void helper_rcpss(XMMReg *d, XMMReg *s)
+{
+    d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
+}
+
+static inline uint64_t helper_extrq(uint64_t src, int shift, int len)
+{
+    uint64_t mask;
+
+    if (len == 0) {
+        mask = ~0LL;
+    } else {
+        mask = (1ULL << len) - 1;
+    }
+    return (src >> shift) & mask;
+}
+
+void helper_extrq_r(XMMReg *d, XMMReg *s)
+{
+    d->XMM_Q(0) = helper_extrq(d->XMM_Q(0), s->XMM_B(1), s->XMM_B(0));
+}
+
+void helper_extrq_i(XMMReg *d, int index, int length)
+{
+    d->XMM_Q(0) = helper_extrq(d->XMM_Q(0), index, length);
+}
+
+static inline uint64_t helper_insertq(uint64_t src, int shift, int len)
+{
+    uint64_t mask;
+
+    if (len == 0) {
+        mask = ~0ULL;
+    } else {
+        mask = (1ULL << len) - 1;
+    }
+    return (src & ~(mask << shift)) | ((src & mask) << shift);
+}
+
+void helper_insertq_r(XMMReg *d, XMMReg *s)
+{
+    d->XMM_Q(0) = helper_insertq(s->XMM_Q(0), s->XMM_B(9), s->XMM_B(8));
+}
+
+void helper_insertq_i(XMMReg *d, int index, int length)
+{
+    d->XMM_Q(0) = helper_insertq(d->XMM_Q(0), index, length);
+}
+
+void helper_haddps(XMMReg *d, XMMReg *s)
+{
+    XMMReg r;
+    r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1);
+    r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3);
+    r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1);
+    r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3);
+    *d = r;
+}
+
+void helper_haddpd(XMMReg *d, XMMReg *s)
+{
+    XMMReg r;
+    r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1);
+    r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1);
+    *d = r;
+}
+
+void helper_hsubps(XMMReg *d, XMMReg *s)
+{
+    XMMReg r;
+    r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1);
+    r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3);
+    r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1);
+    r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3);
+    *d = r;
+}
+
+void helper_hsubpd(XMMReg *d, XMMReg *s)
+{
+    XMMReg r;
+    r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1);
+    r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1);
+    *d = r;
+}
+
+void helper_addsubps(XMMReg *d, XMMReg *s)
+{
+    d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0);
+    d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1);
+    d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2);
+    d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3);
+}
+
+void helper_addsubpd(XMMReg *d, XMMReg *s)
+{
+    d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0);
+    d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1);
+}
+
+/* XXX: unordered */
+#define SSE_HELPER_CMP(name, F)\
+void helper_ ## name ## ps (Reg *d, Reg *s)\
+{\
+    d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
+    d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1));\
+    d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2));\
+    d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3));\
+}\
+\
+void helper_ ## name ## ss (Reg *d, Reg *s)\
+{\
+    d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
+}\
+void helper_ ## name ## pd (Reg *d, Reg *s)\
+{\
+    d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
+    d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1));\
+}\
+\
+void helper_ ## name ## sd (Reg *d, Reg *s)\
+{\
+    d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
+}
+
+#define FPU_CMPEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? -1 : 0
+#define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0
+#define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0
+#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? - 1 : 0
+#define FPU_CMPNEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? 0 : -1
+#define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1
+#define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1
+#define FPU_CMPORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1
+
+SSE_HELPER_CMP(cmpeq, FPU_CMPEQ)
+SSE_HELPER_CMP(cmplt, FPU_CMPLT)
+SSE_HELPER_CMP(cmple, FPU_CMPLE)
+SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD)
+SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ)
+SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT)
+SSE_HELPER_CMP(cmpnle, FPU_CMPNLE)
+SSE_HELPER_CMP(cmpord, FPU_CMPORD)
+
+static const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
+
+void helper_ucomiss(Reg *d, Reg *s)
+{
+    int ret;
+    float32 s0, s1;
+
+    s0 = d->XMM_S(0);
+    s1 = s->XMM_S(0);
+    ret = float32_compare_quiet(s0, s1, &env->sse_status);
+    CC_SRC = comis_eflags[ret + 1];
+}
+
+void helper_comiss(Reg *d, Reg *s)
+{
+    int ret;
+    float32 s0, s1;
+
+    s0 = d->XMM_S(0);
+    s1 = s->XMM_S(0);
+    ret = float32_compare(s0, s1, &env->sse_status);
+    CC_SRC = comis_eflags[ret + 1];
+}
+
+void helper_ucomisd(Reg *d, Reg *s)
+{
+    int ret;
+    float64 d0, d1;
+
+    d0 = d->XMM_D(0);
+    d1 = s->XMM_D(0);
+    ret = float64_compare_quiet(d0, d1, &env->sse_status);
+    CC_SRC = comis_eflags[ret + 1];
+}
+
+void helper_comisd(Reg *d, Reg *s)
+{
+    int ret;
+    float64 d0, d1;
+
+    d0 = d->XMM_D(0);
+    d1 = s->XMM_D(0);
+    ret = float64_compare(d0, d1, &env->sse_status);
+    CC_SRC = comis_eflags[ret + 1];
+}
+
+uint32_t helper_movmskps(Reg *s)
+{
+    int b0, b1, b2, b3;
+    b0 = s->XMM_L(0) >> 31;
+    b1 = s->XMM_L(1) >> 31;
+    b2 = s->XMM_L(2) >> 31;
+    b3 = s->XMM_L(3) >> 31;
+    return b0 | (b1 << 1) | (b2 << 2) | (b3 << 3);
+}
+
+uint32_t helper_movmskpd(Reg *s)
+{
+    int b0, b1;
+    b0 = s->XMM_L(1) >> 31;
+    b1 = s->XMM_L(3) >> 31;
+    return b0 | (b1 << 1);
+}
+
+#endif
+
+uint32_t glue(helper_pmovmskb, SUFFIX)(Reg *s)
+{
+    uint32_t val;
+    val = 0;
+    val |= (s->B(0) >> 7);
+    val |= (s->B(1) >> 6) & 0x02;
+    val |= (s->B(2) >> 5) & 0x04;
+    val |= (s->B(3) >> 4) & 0x08;
+    val |= (s->B(4) >> 3) & 0x10;
+    val |= (s->B(5) >> 2) & 0x20;
+    val |= (s->B(6) >> 1) & 0x40;
+    val |= (s->B(7)) & 0x80;
+#if SHIFT == 1
+    val |= (s->B(8) << 1) & 0x0100;
+    val |= (s->B(9) << 2) & 0x0200;
+    val |= (s->B(10) << 3) & 0x0400;
+    val |= (s->B(11) << 4) & 0x0800;
+    val |= (s->B(12) << 5) & 0x1000;
+    val |= (s->B(13) << 6) & 0x2000;
+    val |= (s->B(14) << 7) & 0x4000;
+    val |= (s->B(15) << 8) & 0x8000;
+#endif
+    return val;
+}
+
+void glue(helper_packsswb, SUFFIX) (Reg *d, Reg *s)
+{
+    Reg r;
+
+    r.B(0) = satsb((int16_t)d->W(0));
+    r.B(1) = satsb((int16_t)d->W(1));
+    r.B(2) = satsb((int16_t)d->W(2));
+    r.B(3) = satsb((int16_t)d->W(3));
+#if SHIFT == 1
+    r.B(4) = satsb((int16_t)d->W(4));
+    r.B(5) = satsb((int16_t)d->W(5));
+    r.B(6) = satsb((int16_t)d->W(6));
+    r.B(7) = satsb((int16_t)d->W(7));
+#endif
+    r.B((4 << SHIFT) + 0) = satsb((int16_t)s->W(0));
+    r.B((4 << SHIFT) + 1) = satsb((int16_t)s->W(1));
+    r.B((4 << SHIFT) + 2) = satsb((int16_t)s->W(2));
+    r.B((4 << SHIFT) + 3) = satsb((int16_t)s->W(3));
+#if SHIFT == 1
+    r.B(12) = satsb((int16_t)s->W(4));
+    r.B(13) = satsb((int16_t)s->W(5));
+    r.B(14) = satsb((int16_t)s->W(6));
+    r.B(15) = satsb((int16_t)s->W(7));
+#endif
+    *d = r;
+}
+
+void glue(helper_packuswb, SUFFIX) (Reg *d, Reg *s)
+{
+    Reg r;
+
+    r.B(0) = satub((int16_t)d->W(0));
+    r.B(1) = satub((int16_t)d->W(1));
+    r.B(2) = satub((int16_t)d->W(2));
+    r.B(3) = satub((int16_t)d->W(3));
+#if SHIFT == 1
+    r.B(4) = satub((int16_t)d->W(4));
+    r.B(5) = satub((int16_t)d->W(5));
+    r.B(6) = satub((int16_t)d->W(6));
+    r.B(7) = satub((int16_t)d->W(7));
+#endif
+    r.B((4 << SHIFT) + 0) = satub((int16_t)s->W(0));
+    r.B((4 << SHIFT) + 1) = satub((int16_t)s->W(1));
+    r.B((4 << SHIFT) + 2) = satub((int16_t)s->W(2));
+    r.B((4 << SHIFT) + 3) = satub((int16_t)s->W(3));
+#if SHIFT == 1
+    r.B(12) = satub((int16_t)s->W(4));
+    r.B(13) = satub((int16_t)s->W(5));
+    r.B(14) = satub((int16_t)s->W(6));
+    r.B(15) = satub((int16_t)s->W(7));
+#endif
+    *d = r;
+}
+
+void glue(helper_packssdw, SUFFIX) (Reg *d, Reg *s)
+{
+    Reg r;
+
+    r.W(0) = satsw(d->L(0));
+    r.W(1) = satsw(d->L(1));
+#if SHIFT == 1
+    r.W(2) = satsw(d->L(2));
+    r.W(3) = satsw(d->L(3));
+#endif
+    r.W((2 << SHIFT) + 0) = satsw(s->L(0));
+    r.W((2 << SHIFT) + 1) = satsw(s->L(1));
+#if SHIFT == 1
+    r.W(6) = satsw(s->L(2));
+    r.W(7) = satsw(s->L(3));
+#endif
+    *d = r;
+}
+
+#define UNPCK_OP(base_name, base)                               \
+                                                                \
+void glue(helper_punpck ## base_name ## bw, SUFFIX) (Reg *d, Reg *s)   \
+{                                                               \
+    Reg r;                                              \
+                                                                \
+    r.B(0) = d->B((base << (SHIFT + 2)) + 0);                   \
+    r.B(1) = s->B((base << (SHIFT + 2)) + 0);                   \
+    r.B(2) = d->B((base << (SHIFT + 2)) + 1);                   \
+    r.B(3) = s->B((base << (SHIFT + 2)) + 1);                   \
+    r.B(4) = d->B((base << (SHIFT + 2)) + 2);                   \
+    r.B(5) = s->B((base << (SHIFT + 2)) + 2);                   \
+    r.B(6) = d->B((base << (SHIFT + 2)) + 3);                   \
+    r.B(7) = s->B((base << (SHIFT + 2)) + 3);                   \
+XMM_ONLY(                                                       \
+    r.B(8) = d->B((base << (SHIFT + 2)) + 4);                   \
+    r.B(9) = s->B((base << (SHIFT + 2)) + 4);                   \
+    r.B(10) = d->B((base << (SHIFT + 2)) + 5);                  \
+    r.B(11) = s->B((base << (SHIFT + 2)) + 5);                  \
+    r.B(12) = d->B((base << (SHIFT + 2)) + 6);                  \
+    r.B(13) = s->B((base << (SHIFT + 2)) + 6);                  \
+    r.B(14) = d->B((base << (SHIFT + 2)) + 7);                  \
+    r.B(15) = s->B((base << (SHIFT + 2)) + 7);                  \
+)                                                               \
+    *d = r;                                                     \
+}                                                               \
+                                                                \
+void glue(helper_punpck ## base_name ## wd, SUFFIX) (Reg *d, Reg *s)   \
+{                                                               \
+    Reg r;                                              \
+                                                                \
+    r.W(0) = d->W((base << (SHIFT + 1)) + 0);                   \
+    r.W(1) = s->W((base << (SHIFT + 1)) + 0);                   \
+    r.W(2) = d->W((base << (SHIFT + 1)) + 1);                   \
+    r.W(3) = s->W((base << (SHIFT + 1)) + 1);                   \
+XMM_ONLY(                                                       \
+    r.W(4) = d->W((base << (SHIFT + 1)) + 2);                   \
+    r.W(5) = s->W((base << (SHIFT + 1)) + 2);                   \
+    r.W(6) = d->W((base << (SHIFT + 1)) + 3);                   \
+    r.W(7) = s->W((base << (SHIFT + 1)) + 3);                   \
+)                                                               \
+    *d = r;                                                     \
+}                                                               \
+                                                                \
+void glue(helper_punpck ## base_name ## dq, SUFFIX) (Reg *d, Reg *s)   \
+{                                                               \
+    Reg r;                                              \
+                                                                \
+    r.L(0) = d->L((base << SHIFT) + 0);                         \
+    r.L(1) = s->L((base << SHIFT) + 0);                         \
+XMM_ONLY(                                                       \
+    r.L(2) = d->L((base << SHIFT) + 1);                         \
+    r.L(3) = s->L((base << SHIFT) + 1);                         \
+)                                                               \
+    *d = r;                                                     \
+}                                                               \
+                                                                \
+XMM_ONLY(                                                       \
+void glue(helper_punpck ## base_name ## qdq, SUFFIX) (Reg *d, Reg *s)  \
+{                                                               \
+    Reg r;                                              \
+                                                                \
+    r.Q(0) = d->Q(base);                                        \
+    r.Q(1) = s->Q(base);                                        \
+    *d = r;                                                     \
+}                                                               \
+)
+
+UNPCK_OP(l, 0)
+UNPCK_OP(h, 1)
+
+/* 3DNow! float ops */
+#if SHIFT == 0
+void helper_pi2fd(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = int32_to_float32(s->MMX_L(0), &env->mmx_status);
+    d->MMX_S(1) = int32_to_float32(s->MMX_L(1), &env->mmx_status);
+}
+
+void helper_pi2fw(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = int32_to_float32((int16_t)s->MMX_W(0), &env->mmx_status);
+    d->MMX_S(1) = int32_to_float32((int16_t)s->MMX_W(2), &env->mmx_status);
+}
+
+void helper_pf2id(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(0) = float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status);
+    d->MMX_L(1) = float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status);
+}
+
+void helper_pf2iw(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(0) = satsw(float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status));
+    d->MMX_L(1) = satsw(float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status));
+}
+
+void helper_pfacc(MMXReg *d, MMXReg *s)
+{
+    MMXReg r;
+    r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
+    r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
+    *d = r;
+}
+
+void helper_pfadd(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = float32_add(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
+    d->MMX_S(1) = float32_add(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
+}
+
+void helper_pfcmpeq(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(0) = float32_eq_quiet(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0;
+    d->MMX_L(1) = float32_eq_quiet(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0;
+}
+
+void helper_pfcmpge(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(0) = float32_le(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0;
+    d->MMX_L(1) = float32_le(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0;
+}
+
+void helper_pfcmpgt(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(0) = float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0;
+    d->MMX_L(1) = float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0;
+}
+
+void helper_pfmax(MMXReg *d, MMXReg *s)
+{
+    if (float32_lt(d->MMX_S(0), s->MMX_S(0), &env->mmx_status))
+        d->MMX_S(0) = s->MMX_S(0);
+    if (float32_lt(d->MMX_S(1), s->MMX_S(1), &env->mmx_status))
+        d->MMX_S(1) = s->MMX_S(1);
+}
+
+void helper_pfmin(MMXReg *d, MMXReg *s)
+{
+    if (float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status))
+        d->MMX_S(0) = s->MMX_S(0);
+    if (float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status))
+        d->MMX_S(1) = s->MMX_S(1);
+}
+
+void helper_pfmul(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = float32_mul(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
+    d->MMX_S(1) = float32_mul(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
+}
+
+void helper_pfnacc(MMXReg *d, MMXReg *s)
+{
+    MMXReg r;
+    r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
+    r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
+    *d = r;
+}
+
+void helper_pfpnacc(MMXReg *d, MMXReg *s)
+{
+    MMXReg r;
+    r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
+    r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
+    *d = r;
+}
+
+void helper_pfrcp(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = float32_div(float32_one, s->MMX_S(0), &env->mmx_status);
+    d->MMX_S(1) = d->MMX_S(0);
+}
+
+void helper_pfrsqrt(MMXReg *d, MMXReg *s)
+{
+    d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff;
+    d->MMX_S(1) = float32_div(float32_one,
+                              float32_sqrt(d->MMX_S(1), &env->mmx_status),
+                              &env->mmx_status);
+    d->MMX_L(1) |= s->MMX_L(0) & 0x80000000;
+    d->MMX_L(0) = d->MMX_L(1);
+}
+
+void helper_pfsub(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = float32_sub(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
+    d->MMX_S(1) = float32_sub(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
+}
+
+void helper_pfsubr(MMXReg *d, MMXReg *s)
+{
+    d->MMX_S(0) = float32_sub(s->MMX_S(0), d->MMX_S(0), &env->mmx_status);
+    d->MMX_S(1) = float32_sub(s->MMX_S(1), d->MMX_S(1), &env->mmx_status);
+}
+
+void helper_pswapd(MMXReg *d, MMXReg *s)
+{
+    MMXReg r;
+    r.MMX_L(0) = s->MMX_L(1);
+    r.MMX_L(1) = s->MMX_L(0);
+    *d = r;
+}
+#endif
+
+/* SSSE3 op helpers */
+void glue(helper_pshufb, SUFFIX) (Reg *d, Reg *s)
+{
+    int i;
+    Reg r;
+
+    for (i = 0; i < (8 << SHIFT); i++)
+        r.B(i) = (s->B(i) & 0x80) ? 0 : (d->B(s->B(i) & ((8 << SHIFT) - 1)));
+
+    *d = r;
+}
+
+void glue(helper_phaddw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = (int16_t)d->W(0) + (int16_t)d->W(1);
+    d->W(1) = (int16_t)d->W(2) + (int16_t)d->W(3);
+    XMM_ONLY(d->W(2) = (int16_t)d->W(4) + (int16_t)d->W(5));
+    XMM_ONLY(d->W(3) = (int16_t)d->W(6) + (int16_t)d->W(7));
+    d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) + (int16_t)s->W(1);
+    d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) + (int16_t)s->W(3);
+    XMM_ONLY(d->W(6) = (int16_t)s->W(4) + (int16_t)s->W(5));
+    XMM_ONLY(d->W(7) = (int16_t)s->W(6) + (int16_t)s->W(7));
+}
+
+void glue(helper_phaddd, SUFFIX) (Reg *d, Reg *s)
+{
+    d->L(0) = (int32_t)d->L(0) + (int32_t)d->L(1);
+    XMM_ONLY(d->L(1) = (int32_t)d->L(2) + (int32_t)d->L(3));
+    d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) + (int32_t)s->L(1);
+    XMM_ONLY(d->L(3) = (int32_t)s->L(2) + (int32_t)s->L(3));
+}
+
+void glue(helper_phaddsw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1));
+    d->W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3));
+    XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) + (int16_t)d->W(5)));
+    XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) + (int16_t)d->W(7)));
+    d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) + (int16_t)s->W(1));
+    d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) + (int16_t)s->W(3));
+    XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) + (int16_t)s->W(5)));
+    XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7)));
+}
+
+void glue(helper_pmaddubsw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = satsw((int8_t)s->B( 0) * (uint8_t)d->B( 0) +
+                    (int8_t)s->B( 1) * (uint8_t)d->B( 1));
+    d->W(1) = satsw((int8_t)s->B( 2) * (uint8_t)d->B( 2) +
+                    (int8_t)s->B( 3) * (uint8_t)d->B( 3));
+    d->W(2) = satsw((int8_t)s->B( 4) * (uint8_t)d->B( 4) +
+                    (int8_t)s->B( 5) * (uint8_t)d->B( 5));
+    d->W(3) = satsw((int8_t)s->B( 6) * (uint8_t)d->B( 6) +
+                    (int8_t)s->B( 7) * (uint8_t)d->B( 7));
+#if SHIFT == 1
+    d->W(4) = satsw((int8_t)s->B( 8) * (uint8_t)d->B( 8) +
+                    (int8_t)s->B( 9) * (uint8_t)d->B( 9));
+    d->W(5) = satsw((int8_t)s->B(10) * (uint8_t)d->B(10) +
+                    (int8_t)s->B(11) * (uint8_t)d->B(11));
+    d->W(6) = satsw((int8_t)s->B(12) * (uint8_t)d->B(12) +
+                    (int8_t)s->B(13) * (uint8_t)d->B(13));
+    d->W(7) = satsw((int8_t)s->B(14) * (uint8_t)d->B(14) +
+                    (int8_t)s->B(15) * (uint8_t)d->B(15));
+#endif
+}
+
+void glue(helper_phsubw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = (int16_t)d->W(0) - (int16_t)d->W(1);
+    d->W(1) = (int16_t)d->W(2) - (int16_t)d->W(3);
+    XMM_ONLY(d->W(2) = (int16_t)d->W(4) - (int16_t)d->W(5));
+    XMM_ONLY(d->W(3) = (int16_t)d->W(6) - (int16_t)d->W(7));
+    d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) - (int16_t)s->W(1);
+    d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) - (int16_t)s->W(3);
+    XMM_ONLY(d->W(6) = (int16_t)s->W(4) - (int16_t)s->W(5));
+    XMM_ONLY(d->W(7) = (int16_t)s->W(6) - (int16_t)s->W(7));
+}
+
+void glue(helper_phsubd, SUFFIX) (Reg *d, Reg *s)
+{
+    d->L(0) = (int32_t)d->L(0) - (int32_t)d->L(1);
+    XMM_ONLY(d->L(1) = (int32_t)d->L(2) - (int32_t)d->L(3));
+    d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) - (int32_t)s->L(1);
+    XMM_ONLY(d->L(3) = (int32_t)s->L(2) - (int32_t)s->L(3));
+}
+
+void glue(helper_phsubsw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1));
+    d->W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3));
+    XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) - (int16_t)d->W(5)));
+    XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) - (int16_t)d->W(7)));
+    d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) - (int16_t)s->W(1));
+    d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) - (int16_t)s->W(3));
+    XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) - (int16_t)s->W(5)));
+    XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) - (int16_t)s->W(7)));
+}
+
+#define FABSB(_, x) x > INT8_MAX  ? -(int8_t ) x : x
+#define FABSW(_, x) x > INT16_MAX ? -(int16_t) x : x
+#define FABSL(_, x) x > INT32_MAX ? -(int32_t) x : x
+SSE_HELPER_B(helper_pabsb, FABSB)
+SSE_HELPER_W(helper_pabsw, FABSW)
+SSE_HELPER_L(helper_pabsd, FABSL)
+
+#define FMULHRSW(d, s) ((int16_t) d * (int16_t) s + 0x4000) >> 15
+SSE_HELPER_W(helper_pmulhrsw, FMULHRSW)
+
+#define FSIGNB(d, s) s <= INT8_MAX  ? s ? d : 0 : -(int8_t ) d
+#define FSIGNW(d, s) s <= INT16_MAX ? s ? d : 0 : -(int16_t) d
+#define FSIGNL(d, s) s <= INT32_MAX ? s ? d : 0 : -(int32_t) d
+SSE_HELPER_B(helper_psignb, FSIGNB)
+SSE_HELPER_W(helper_psignw, FSIGNW)
+SSE_HELPER_L(helper_psignd, FSIGNL)
+
+void glue(helper_palignr, SUFFIX) (Reg *d, Reg *s, int32_t shift)
+{
+    Reg r;
+
+    /* XXX could be checked during translation */
+    if (shift >= (16 << SHIFT)) {
+        r.Q(0) = 0;
+        XMM_ONLY(r.Q(1) = 0);
+    } else {
+        shift <<= 3;
+#define SHR(v, i) (i < 64 && i > -64 ? i > 0 ? v >> (i) : (v << -(i)) : 0)
+#if SHIFT == 0
+        r.Q(0) = SHR(s->Q(0), shift -   0) |
+                 SHR(d->Q(0), shift -  64);
+#else
+        r.Q(0) = SHR(s->Q(0), shift -   0) |
+                 SHR(s->Q(1), shift -  64) |
+                 SHR(d->Q(0), shift - 128) |
+                 SHR(d->Q(1), shift - 192);
+        r.Q(1) = SHR(s->Q(0), shift +  64) |
+                 SHR(s->Q(1), shift -   0) |
+                 SHR(d->Q(0), shift -  64) |
+                 SHR(d->Q(1), shift - 128);
+#endif
+#undef SHR
+    }
+
+    *d = r;
+}
+
+#define XMM0 env->xmm_regs[0]
+
+#if SHIFT == 1
+#define SSE_HELPER_V(name, elem, num, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->elem(0) = F(d->elem(0), s->elem(0), XMM0.elem(0));\
+    d->elem(1) = F(d->elem(1), s->elem(1), XMM0.elem(1));\
+    if (num > 2) {\
+        d->elem(2) = F(d->elem(2), s->elem(2), XMM0.elem(2));\
+        d->elem(3) = F(d->elem(3), s->elem(3), XMM0.elem(3));\
+        if (num > 4) {\
+            d->elem(4) = F(d->elem(4), s->elem(4), XMM0.elem(4));\
+            d->elem(5) = F(d->elem(5), s->elem(5), XMM0.elem(5));\
+            d->elem(6) = F(d->elem(6), s->elem(6), XMM0.elem(6));\
+            d->elem(7) = F(d->elem(7), s->elem(7), XMM0.elem(7));\
+            if (num > 8) {\
+                d->elem(8) = F(d->elem(8), s->elem(8), XMM0.elem(8));\
+                d->elem(9) = F(d->elem(9), s->elem(9), XMM0.elem(9));\
+                d->elem(10) = F(d->elem(10), s->elem(10), XMM0.elem(10));\
+                d->elem(11) = F(d->elem(11), s->elem(11), XMM0.elem(11));\
+                d->elem(12) = F(d->elem(12), s->elem(12), XMM0.elem(12));\
+                d->elem(13) = F(d->elem(13), s->elem(13), XMM0.elem(13));\
+                d->elem(14) = F(d->elem(14), s->elem(14), XMM0.elem(14));\
+                d->elem(15) = F(d->elem(15), s->elem(15), XMM0.elem(15));\
+            }\
+        }\
+    }\
+}
+
+#define SSE_HELPER_I(name, elem, num, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s, uint32_t imm)\
+{\
+    d->elem(0) = F(d->elem(0), s->elem(0), ((imm >> 0) & 1));\
+    d->elem(1) = F(d->elem(1), s->elem(1), ((imm >> 1) & 1));\
+    if (num > 2) {\
+        d->elem(2) = F(d->elem(2), s->elem(2), ((imm >> 2) & 1));\
+        d->elem(3) = F(d->elem(3), s->elem(3), ((imm >> 3) & 1));\
+        if (num > 4) {\
+            d->elem(4) = F(d->elem(4), s->elem(4), ((imm >> 4) & 1));\
+            d->elem(5) = F(d->elem(5), s->elem(5), ((imm >> 5) & 1));\
+            d->elem(6) = F(d->elem(6), s->elem(6), ((imm >> 6) & 1));\
+            d->elem(7) = F(d->elem(7), s->elem(7), ((imm >> 7) & 1));\
+            if (num > 8) {\
+                d->elem(8) = F(d->elem(8), s->elem(8), ((imm >> 8) & 1));\
+                d->elem(9) = F(d->elem(9), s->elem(9), ((imm >> 9) & 1));\
+                d->elem(10) = F(d->elem(10), s->elem(10), ((imm >> 10) & 1));\
+                d->elem(11) = F(d->elem(11), s->elem(11), ((imm >> 11) & 1));\
+                d->elem(12) = F(d->elem(12), s->elem(12), ((imm >> 12) & 1));\
+                d->elem(13) = F(d->elem(13), s->elem(13), ((imm >> 13) & 1));\
+                d->elem(14) = F(d->elem(14), s->elem(14), ((imm >> 14) & 1));\
+                d->elem(15) = F(d->elem(15), s->elem(15), ((imm >> 15) & 1));\
+            }\
+        }\
+    }\
+}
+
+/* SSE4.1 op helpers */
+#define FBLENDVB(d, s, m) (m & 0x80) ? s : d
+#define FBLENDVPS(d, s, m) (m & 0x80000000) ? s : d
+#define FBLENDVPD(d, s, m) (m & 0x8000000000000000LL) ? s : d
+SSE_HELPER_V(helper_pblendvb, B, 16, FBLENDVB)
+SSE_HELPER_V(helper_blendvps, L, 4, FBLENDVPS)
+SSE_HELPER_V(helper_blendvpd, Q, 2, FBLENDVPD)
+
+void glue(helper_ptest, SUFFIX) (Reg *d, Reg *s)
+{
+    uint64_t zf = (s->Q(0) &  d->Q(0)) | (s->Q(1) &  d->Q(1));
+    uint64_t cf = (s->Q(0) & ~d->Q(0)) | (s->Q(1) & ~d->Q(1));
+
+    CC_SRC = (zf ? 0 : CC_Z) | (cf ? 0 : CC_C);
+}
+
+#define SSE_HELPER_F(name, elem, num, F)\
+void glue(name, SUFFIX) (Reg *d, Reg *s)\
+{\
+    d->elem(0) = F(0);\
+    d->elem(1) = F(1);\
+    if (num > 2) {\
+        d->elem(2) = F(2);\
+        d->elem(3) = F(3);\
+        if (num > 4) {\
+            d->elem(4) = F(4);\
+            d->elem(5) = F(5);\
+            d->elem(6) = F(6);\
+            d->elem(7) = F(7);\
+        }\
+    }\
+}
+
+SSE_HELPER_F(helper_pmovsxbw, W, 8, (int8_t) s->B)
+SSE_HELPER_F(helper_pmovsxbd, L, 4, (int8_t) s->B)
+SSE_HELPER_F(helper_pmovsxbq, Q, 2, (int8_t) s->B)
+SSE_HELPER_F(helper_pmovsxwd, L, 4, (int16_t) s->W)
+SSE_HELPER_F(helper_pmovsxwq, Q, 2, (int16_t) s->W)
+SSE_HELPER_F(helper_pmovsxdq, Q, 2, (int32_t) s->L)
+SSE_HELPER_F(helper_pmovzxbw, W, 8, s->B)
+SSE_HELPER_F(helper_pmovzxbd, L, 4, s->B)
+SSE_HELPER_F(helper_pmovzxbq, Q, 2, s->B)
+SSE_HELPER_F(helper_pmovzxwd, L, 4, s->W)
+SSE_HELPER_F(helper_pmovzxwq, Q, 2, s->W)
+SSE_HELPER_F(helper_pmovzxdq, Q, 2, s->L)
+
+void glue(helper_pmuldq, SUFFIX) (Reg *d, Reg *s)
+{
+    d->Q(0) = (int64_t) (int32_t) d->L(0) * (int32_t) s->L(0);
+    d->Q(1) = (int64_t) (int32_t) d->L(2) * (int32_t) s->L(2);
+}
+
+#define FCMPEQQ(d, s) d == s ? -1 : 0
+SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ)
+
+void glue(helper_packusdw, SUFFIX) (Reg *d, Reg *s)
+{
+    d->W(0) = satuw((int32_t) d->L(0));
+    d->W(1) = satuw((int32_t) d->L(1));
+    d->W(2) = satuw((int32_t) d->L(2));
+    d->W(3) = satuw((int32_t) d->L(3));
+    d->W(4) = satuw((int32_t) s->L(0));
+    d->W(5) = satuw((int32_t) s->L(1));
+    d->W(6) = satuw((int32_t) s->L(2));
+    d->W(7) = satuw((int32_t) s->L(3));
+}
+
+#define FMINSB(d, s) MIN((int8_t) d, (int8_t) s)
+#define FMINSD(d, s) MIN((int32_t) d, (int32_t) s)
+#define FMAXSB(d, s) MAX((int8_t) d, (int8_t) s)
+#define FMAXSD(d, s) MAX((int32_t) d, (int32_t) s)
+SSE_HELPER_B(helper_pminsb, FMINSB)
+SSE_HELPER_L(helper_pminsd, FMINSD)
+SSE_HELPER_W(helper_pminuw, MIN)
+SSE_HELPER_L(helper_pminud, MIN)
+SSE_HELPER_B(helper_pmaxsb, FMAXSB)
+SSE_HELPER_L(helper_pmaxsd, FMAXSD)
+SSE_HELPER_W(helper_pmaxuw, MAX)
+SSE_HELPER_L(helper_pmaxud, MAX)
+
+#define FMULLD(d, s) (int32_t) d * (int32_t) s
+SSE_HELPER_L(helper_pmulld, FMULLD)
+
+void glue(helper_phminposuw, SUFFIX) (Reg *d, Reg *s)
+{
+    int idx = 0;
+
+    if (s->W(1) < s->W(idx))
+        idx = 1;
+    if (s->W(2) < s->W(idx))
+        idx = 2;
+    if (s->W(3) < s->W(idx))
+        idx = 3;
+    if (s->W(4) < s->W(idx))
+        idx = 4;
+    if (s->W(5) < s->W(idx))
+        idx = 5;
+    if (s->W(6) < s->W(idx))
+        idx = 6;
+    if (s->W(7) < s->W(idx))
+        idx = 7;
+
+    d->Q(1) = 0;
+    d->L(1) = 0;
+    d->W(1) = idx;
+    d->W(0) = s->W(idx);
+}
+
+void glue(helper_roundps, SUFFIX) (Reg *d, Reg *s, uint32_t mode)
+{
+    signed char prev_rounding_mode;
+
+    prev_rounding_mode = env->sse_status.float_rounding_mode;
+    if (!(mode & (1 << 2)))
+        switch (mode & 3) {
+        case 0:
+            set_float_rounding_mode(float_round_nearest_even, &env->sse_status);
+            break;
+        case 1:
+            set_float_rounding_mode(float_round_down, &env->sse_status);
+            break;
+        case 2:
+            set_float_rounding_mode(float_round_up, &env->sse_status);
+            break;
+        case 3:
+            set_float_rounding_mode(float_round_to_zero, &env->sse_status);
+            break;
+        }
+
+    d->L(0) = float64_round_to_int(s->L(0), &env->sse_status);
+    d->L(1) = float64_round_to_int(s->L(1), &env->sse_status);
+    d->L(2) = float64_round_to_int(s->L(2), &env->sse_status);
+    d->L(3) = float64_round_to_int(s->L(3), &env->sse_status);
+
+#if 0 /* TODO */
+    if (mode & (1 << 3))
+        set_float_exception_flags(
+                        get_float_exception_flags(&env->sse_status) &
+                        ~float_flag_inexact,
+                        &env->sse_status);
+#endif
+    env->sse_status.float_rounding_mode = prev_rounding_mode;
+}
+
+void glue(helper_roundpd, SUFFIX) (Reg *d, Reg *s, uint32_t mode)
+{
+    signed char prev_rounding_mode;
+
+    prev_rounding_mode = env->sse_status.float_rounding_mode;
+    if (!(mode & (1 << 2)))
+        switch (mode & 3) {
+        case 0:
+            set_float_rounding_mode(float_round_nearest_even, &env->sse_status);
+            break;
+        case 1:
+            set_float_rounding_mode(float_round_down, &env->sse_status);
+            break;
+        case 2:
+            set_float_rounding_mode(float_round_up, &env->sse_status);
+            break;
+        case 3:
+            set_float_rounding_mode(float_round_to_zero, &env->sse_status);
+            break;
+        }
+
+    d->Q(0) = float64_round_to_int(s->Q(0), &env->sse_status);
+    d->Q(1) = float64_round_to_int(s->Q(1), &env->sse_status);
+
+#if 0 /* TODO */
+    if (mode & (1 << 3))
+        set_float_exception_flags(
+                        get_float_exception_flags(&env->sse_status) &
+                        ~float_flag_inexact,
+                        &env->sse_status);
+#endif
+    env->sse_status.float_rounding_mode = prev_rounding_mode;
+}
+
+void glue(helper_roundss, SUFFIX) (Reg *d, Reg *s, uint32_t mode)
+{
+    signed char prev_rounding_mode;
+
+    prev_rounding_mode = env->sse_status.float_rounding_mode;
+    if (!(mode & (1 << 2)))
+        switch (mode & 3) {
+        case 0:
+            set_float_rounding_mode(float_round_nearest_even, &env->sse_status);
+            break;
+        case 1:
+            set_float_rounding_mode(float_round_down, &env->sse_status);
+            break;
+        case 2:
+            set_float_rounding_mode(float_round_up, &env->sse_status);
+            break;
+        case 3:
+            set_float_rounding_mode(float_round_to_zero, &env->sse_status);
+            break;
+        }
+
+    d->L(0) = float64_round_to_int(s->L(0), &env->sse_status);
+
+#if 0 /* TODO */
+    if (mode & (1 << 3))
+        set_float_exception_flags(
+                        get_float_exception_flags(&env->sse_status) &
+                        ~float_flag_inexact,
+                        &env->sse_status);
+#endif
+    env->sse_status.float_rounding_mode = prev_rounding_mode;
+}
+
+void glue(helper_roundsd, SUFFIX) (Reg *d, Reg *s, uint32_t mode)
+{
+    signed char prev_rounding_mode;
+
+    prev_rounding_mode = env->sse_status.float_rounding_mode;
+    if (!(mode & (1 << 2)))
+        switch (mode & 3) {
+        case 0:
+            set_float_rounding_mode(float_round_nearest_even, &env->sse_status);
+            break;
+        case 1:
+            set_float_rounding_mode(float_round_down, &env->sse_status);
+            break;
+        case 2:
+            set_float_rounding_mode(float_round_up, &env->sse_status);
+            break;
+        case 3:
+            set_float_rounding_mode(float_round_to_zero, &env->sse_status);
+            break;
+        }
+
+    d->Q(0) = float64_round_to_int(s->Q(0), &env->sse_status);
+
+#if 0 /* TODO */
+    if (mode & (1 << 3))
+        set_float_exception_flags(
+                        get_float_exception_flags(&env->sse_status) &
+                        ~float_flag_inexact,
+                        &env->sse_status);
+#endif
+    env->sse_status.float_rounding_mode = prev_rounding_mode;
+}
+
+#define FBLENDP(d, s, m) m ? s : d
+SSE_HELPER_I(helper_blendps, L, 4, FBLENDP)
+SSE_HELPER_I(helper_blendpd, Q, 2, FBLENDP)
+SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP)
+
+void glue(helper_dpps, SUFFIX) (Reg *d, Reg *s, uint32_t mask)
+{
+    float32 iresult = 0 /*float32_zero*/;
+
+    if (mask & (1 << 4))
+        iresult = float32_add(iresult,
+                        float32_mul(d->L(0), s->L(0), &env->sse_status),
+                        &env->sse_status);
+    if (mask & (1 << 5))
+        iresult = float32_add(iresult,
+                        float32_mul(d->L(1), s->L(1), &env->sse_status),
+                        &env->sse_status);
+    if (mask & (1 << 6))
+        iresult = float32_add(iresult,
+                        float32_mul(d->L(2), s->L(2), &env->sse_status),
+                        &env->sse_status);
+    if (mask & (1 << 7))
+        iresult = float32_add(iresult,
+                        float32_mul(d->L(3), s->L(3), &env->sse_status),
+                        &env->sse_status);
+    d->L(0) = (mask & (1 << 0)) ? iresult : 0 /*float32_zero*/;
+    d->L(1) = (mask & (1 << 1)) ? iresult : 0 /*float32_zero*/;
+    d->L(2) = (mask & (1 << 2)) ? iresult : 0 /*float32_zero*/;
+    d->L(3) = (mask & (1 << 3)) ? iresult : 0 /*float32_zero*/;
+}
+
+void glue(helper_dppd, SUFFIX) (Reg *d, Reg *s, uint32_t mask)
+{
+    float64 iresult = 0 /*float64_zero*/;
+
+    if (mask & (1 << 4))
+        iresult = float64_add(iresult,
+                        float64_mul(d->Q(0), s->Q(0), &env->sse_status),
+                        &env->sse_status);
+    if (mask & (1 << 5))
+        iresult = float64_add(iresult,
+                        float64_mul(d->Q(1), s->Q(1), &env->sse_status),
+                        &env->sse_status);
+    d->Q(0) = (mask & (1 << 0)) ? iresult : 0 /*float64_zero*/;
+    d->Q(1) = (mask & (1 << 1)) ? iresult : 0 /*float64_zero*/;
+}
+
+void glue(helper_mpsadbw, SUFFIX) (Reg *d, Reg *s, uint32_t offset)
+{
+    int s0 = (offset & 3) << 2;
+    int d0 = (offset & 4) << 0;
+    int i;
+    Reg r;
+
+    for (i = 0; i < 8; i++, d0++) {
+        r.W(i) = 0;
+        r.W(i) += abs1(d->B(d0 + 0) - s->B(s0 + 0));
+        r.W(i) += abs1(d->B(d0 + 1) - s->B(s0 + 1));
+        r.W(i) += abs1(d->B(d0 + 2) - s->B(s0 + 2));
+        r.W(i) += abs1(d->B(d0 + 3) - s->B(s0 + 3));
+    }
+
+    *d = r;
+}
+
+/* SSE4.2 op helpers */
+/* it's unclear whether signed or unsigned */
+#define FCMPGTQ(d, s) d > s ? -1 : 0
+SSE_HELPER_Q(helper_pcmpgtq, FCMPGTQ)
+
+static inline int pcmp_elen(int reg, uint32_t ctrl)
+{
+    int val;
+
+    /* Presence of REX.W is indicated by a bit higher than 7 set */
+    if (ctrl >> 8)
+        val = abs1((int64_t) env->regs[reg]);
+    else
+        val = abs1((int32_t) env->regs[reg]);
+
+    if (ctrl & 1) {
+        if (val > 8)
+            return 8;
+    } else
+        if (val > 16)
+            return 16;
+
+    return val;
+}
+
+static inline int pcmp_ilen(Reg *r, uint8_t ctrl)
+{
+    int val = 0;
+
+    if (ctrl & 1) {
+        while (val < 8 && r->W(val))
+            val++;
+    } else
+        while (val < 16 && r->B(val))
+            val++;
+
+    return val;
+}
+
+static inline int pcmp_val(Reg *r, uint8_t ctrl, int i)
+{
+    switch ((ctrl >> 0) & 3) {
+    case 0:
+        return r->B(i);
+    case 1:
+        return r->W(i);
+    case 2:
+        return (int8_t) r->B(i);
+    case 3:
+    default:
+        return (int16_t) r->W(i);
+    }
+}
+
+static inline unsigned pcmpxstrx(Reg *d, Reg *s,
+                int8_t ctrl, int valids, int validd)
+{
+    unsigned int res = 0;
+    int v;
+    int j, i;
+    int upper = (ctrl & 1) ? 7 : 15;
+
+    valids--;
+    validd--;
+
+    CC_SRC = (valids < upper ? CC_Z : 0) | (validd < upper ? CC_S : 0);
+
+    switch ((ctrl >> 2) & 3) {
+    case 0:
+        for (j = valids; j >= 0; j--) {
+            res <<= 1;
+            v = pcmp_val(s, ctrl, j);
+            for (i = validd; i >= 0; i--)
+                res |= (v == pcmp_val(d, ctrl, i));
+        }
+        break;
+    case 1:
+        for (j = valids; j >= 0; j--) {
+            res <<= 1;
+            v = pcmp_val(s, ctrl, j);
+            for (i = ((validd - 1) | 1); i >= 0; i -= 2)
+                res |= (pcmp_val(d, ctrl, i - 0) <= v &&
+                        pcmp_val(d, ctrl, i - 1) >= v);
+        }
+        break;
+    case 2:
+        res = (2 << (upper - MAX(valids, validd))) - 1;
+        res <<= MAX(valids, validd) - MIN(valids, validd);
+        for (i = MIN(valids, validd); i >= 0; i--) {
+            res <<= 1;
+            v = pcmp_val(s, ctrl, i);
+            res |= (v == pcmp_val(d, ctrl, i));
+        }
+        break;
+    case 3:
+        for (j = valids - validd; j >= 0; j--) {
+            res <<= 1;
+            res |= 1;
+            for (i = MIN(upper - j, validd); i >= 0; i--)
+                res &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i));
+        }
+        break;
+    }
+
+    switch ((ctrl >> 4) & 3) {
+    case 1:
+        res ^= (2 << upper) - 1;
+        break;
+    case 3:
+        res ^= (2 << valids) - 1;
+        break;
+    }
+
+    if (res)
+       CC_SRC |= CC_C;
+    if (res & 1)
+       CC_SRC |= CC_O;
+
+    return res;
+}
+
+static inline int rffs1(unsigned int val)
+{
+    int ret = 1, hi;
+
+    for (hi = sizeof(val) * 4; hi; hi /= 2)
+        if (val >> hi) {
+            val >>= hi;
+            ret += hi;
+        }
+
+    return ret;
+}
+
+static inline int ffs1(unsigned int val)
+{
+    int ret = 1, hi;
+
+    for (hi = sizeof(val) * 4; hi; hi /= 2)
+        if (val << hi) {
+            val <<= hi;
+            ret += hi;
+        }
+
+    return ret;
+}
+
+void glue(helper_pcmpestri, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
+{
+    unsigned int res = pcmpxstrx(d, s, ctrl,
+                    pcmp_elen(R_EDX, ctrl),
+                    pcmp_elen(R_EAX, ctrl));
+
+    if (res)
+        env->regs[R_ECX] = ((ctrl & (1 << 6)) ? rffs1 : ffs1)(res) - 1;
+    else
+        env->regs[R_ECX] = 16 >> (ctrl & (1 << 0));
+}
+
+void glue(helper_pcmpestrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
+{
+    int i;
+    unsigned int res = pcmpxstrx(d, s, ctrl,
+                    pcmp_elen(R_EDX, ctrl),
+                    pcmp_elen(R_EAX, ctrl));
+
+    if ((ctrl >> 6) & 1) {
+        if (ctrl & 1)
+            for (i = 0; i <= 8; i--, res >>= 1)
+                d->W(i) = (res & 1) ? ~0 : 0;
+        else
+            for (i = 0; i <= 16; i--, res >>= 1)
+                d->B(i) = (res & 1) ? ~0 : 0;
+    } else {
+        d->Q(1) = 0;
+        d->Q(0) = res;
+    }
+}
+
+void glue(helper_pcmpistri, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
+{
+    unsigned int res = pcmpxstrx(d, s, ctrl,
+                    pcmp_ilen(s, ctrl),
+                    pcmp_ilen(d, ctrl));
+
+    if (res)
+        env->regs[R_ECX] = ((ctrl & (1 << 6)) ? rffs1 : ffs1)(res) - 1;
+    else
+        env->regs[R_ECX] = 16 >> (ctrl & (1 << 0));
+}
+
+void glue(helper_pcmpistrm, SUFFIX) (Reg *d, Reg *s, uint32_t ctrl)
+{
+    int i;
+    unsigned int res = pcmpxstrx(d, s, ctrl,
+                    pcmp_ilen(s, ctrl),
+                    pcmp_ilen(d, ctrl));
+
+    if ((ctrl >> 6) & 1) {
+        if (ctrl & 1)
+            for (i = 0; i <= 8; i--, res >>= 1)
+                d->W(i) = (res & 1) ? ~0 : 0;
+        else
+            for (i = 0; i <= 16; i--, res >>= 1)
+                d->B(i) = (res & 1) ? ~0 : 0;
+    } else {
+        d->Q(1) = 0;
+        d->Q(0) = res;
+    }
+}
+
+#define CRCPOLY        0x1edc6f41
+#define CRCPOLY_BITREV 0x82f63b78
+target_ulong helper_crc32(uint32_t crc1, target_ulong msg, uint32_t len)
+{
+    target_ulong crc = (msg & ((target_ulong) -1 >>
+                            (TARGET_LONG_BITS - len))) ^ crc1;
+
+    while (len--)
+        crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_BITREV : 0);
+
+    return crc;
+}
+
+#define POPMASK(i)     ((target_ulong) -1 / ((1LL << (1 << i)) + 1))
+#define POPCOUNT(n, i) (n & POPMASK(i)) + ((n >> (1 << i)) & POPMASK(i))
+target_ulong helper_popcnt(target_ulong n, uint32_t type)
+{
+    CC_SRC = n ? 0 : CC_Z;
+
+    n = POPCOUNT(n, 0);
+    n = POPCOUNT(n, 1);
+    n = POPCOUNT(n, 2);
+    n = POPCOUNT(n, 3);
+    if (type == 1)
+        return n & 0xff;
+
+    n = POPCOUNT(n, 4);
+#ifndef TARGET_X86_64
+    return n;
+#else
+    if (type == 2)
+        return n & 0xff;
+
+    return POPCOUNT(n, 5);
+#endif
+}
+#endif
+
+#undef SHIFT
+#undef XMM_ONLY
+#undef Reg
+#undef B
+#undef W
+#undef L
+#undef Q
+#undef SUFFIX
diff --git a/qemu-0.15.x/target-i386/ops_sse_header.h b/qemu-0.15.x/target-i386/ops_sse_header.h
new file mode 100644
index 0000000..8d4b2b7
--- /dev/null
+++ b/qemu-0.15.x/target-i386/ops_sse_header.h
@@ -0,0 +1,349 @@
+/*
+ *  MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI support
+ *
+ *  Copyright (c) 2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if SHIFT == 0
+#define Reg MMXReg
+#define SUFFIX _mmx
+#else
+#define Reg XMMReg
+#define SUFFIX _xmm
+#endif
+
+#define dh_alias_Reg ptr
+#define dh_alias_XMMReg ptr
+#define dh_alias_MMXReg ptr
+#define dh_ctype_Reg Reg *
+#define dh_ctype_XMMReg XMMReg *
+#define dh_ctype_MMXReg MMXReg *
+#define dh_is_signed_Reg dh_is_signed_ptr
+#define dh_is_signed_XMMReg dh_is_signed_ptr
+#define dh_is_signed_MMXReg dh_is_signed_ptr
+
+DEF_HELPER_2(glue(psrlw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psraw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psllw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psrld, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psrad, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pslld, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psrlq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psllq, SUFFIX), void, Reg, Reg)
+
+#if SHIFT == 1
+DEF_HELPER_2(glue(psrldq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pslldq, SUFFIX), void, Reg, Reg)
+#endif
+
+#define SSE_HELPER_B(name, F)\
+    DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+
+#define SSE_HELPER_W(name, F)\
+    DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+
+#define SSE_HELPER_L(name, F)\
+    DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+
+#define SSE_HELPER_Q(name, F)\
+    DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+
+SSE_HELPER_B(paddb, FADD)
+SSE_HELPER_W(paddw, FADD)
+SSE_HELPER_L(paddl, FADD)
+SSE_HELPER_Q(paddq, FADD)
+
+SSE_HELPER_B(psubb, FSUB)
+SSE_HELPER_W(psubw, FSUB)
+SSE_HELPER_L(psubl, FSUB)
+SSE_HELPER_Q(psubq, FSUB)
+
+SSE_HELPER_B(paddusb, FADDUB)
+SSE_HELPER_B(paddsb, FADDSB)
+SSE_HELPER_B(psubusb, FSUBUB)
+SSE_HELPER_B(psubsb, FSUBSB)
+
+SSE_HELPER_W(paddusw, FADDUW)
+SSE_HELPER_W(paddsw, FADDSW)
+SSE_HELPER_W(psubusw, FSUBUW)
+SSE_HELPER_W(psubsw, FSUBSW)
+
+SSE_HELPER_B(pminub, FMINUB)
+SSE_HELPER_B(pmaxub, FMAXUB)
+
+SSE_HELPER_W(pminsw, FMINSW)
+SSE_HELPER_W(pmaxsw, FMAXSW)
+
+SSE_HELPER_Q(pand, FAND)
+SSE_HELPER_Q(pandn, FANDN)
+SSE_HELPER_Q(por, FOR)
+SSE_HELPER_Q(pxor, FXOR)
+
+SSE_HELPER_B(pcmpgtb, FCMPGTB)
+SSE_HELPER_W(pcmpgtw, FCMPGTW)
+SSE_HELPER_L(pcmpgtl, FCMPGTL)
+
+SSE_HELPER_B(pcmpeqb, FCMPEQ)
+SSE_HELPER_W(pcmpeqw, FCMPEQ)
+SSE_HELPER_L(pcmpeql, FCMPEQ)
+
+SSE_HELPER_W(pmullw, FMULLW)
+#if SHIFT == 0
+SSE_HELPER_W(pmulhrw, FMULHRW)
+#endif
+SSE_HELPER_W(pmulhuw, FMULHUW)
+SSE_HELPER_W(pmulhw, FMULHW)
+
+SSE_HELPER_B(pavgb, FAVG)
+SSE_HELPER_W(pavgw, FAVG)
+
+DEF_HELPER_2(glue(pmuludq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaddwd, SUFFIX), void, Reg, Reg)
+
+DEF_HELPER_2(glue(psadbw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(maskmov, SUFFIX), void, Reg, Reg, tl)
+DEF_HELPER_2(glue(movl_mm_T0, SUFFIX), void, Reg, i32)
+#ifdef TARGET_X86_64
+DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64)
+#endif
+
+#if SHIFT == 0
+DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int)
+#else
+DEF_HELPER_3(shufps, void, Reg, Reg, int)
+DEF_HELPER_3(shufpd, void, Reg, Reg, int)
+DEF_HELPER_3(glue(pshufd, SUFFIX), void, Reg, Reg, int)
+DEF_HELPER_3(glue(pshuflw, SUFFIX), void, Reg, Reg, int)
+DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int)
+#endif
+
+#if SHIFT == 1
+/* FPU ops */
+/* XXX: not accurate */
+
+#define SSE_HELPER_S(name, F)\
+    DEF_HELPER_2(name ## ps , void, Reg, Reg)        \
+    DEF_HELPER_2(name ## ss , void, Reg, Reg)        \
+    DEF_HELPER_2(name ## pd , void, Reg, Reg)        \
+    DEF_HELPER_2(name ## sd , void, Reg, Reg)
+
+SSE_HELPER_S(add, FPU_ADD)
+SSE_HELPER_S(sub, FPU_SUB)
+SSE_HELPER_S(mul, FPU_MUL)
+SSE_HELPER_S(div, FPU_DIV)
+SSE_HELPER_S(min, FPU_MIN)
+SSE_HELPER_S(max, FPU_MAX)
+SSE_HELPER_S(sqrt, FPU_SQRT)
+
+
+DEF_HELPER_2(cvtps2pd, void, Reg, Reg)
+DEF_HELPER_2(cvtpd2ps, void, Reg, Reg)
+DEF_HELPER_2(cvtss2sd, void, Reg, Reg)
+DEF_HELPER_2(cvtsd2ss, void, Reg, Reg)
+DEF_HELPER_2(cvtdq2ps, void, Reg, Reg)
+DEF_HELPER_2(cvtdq2pd, void, Reg, Reg)
+DEF_HELPER_2(cvtpi2ps, void, XMMReg, MMXReg)
+DEF_HELPER_2(cvtpi2pd, void, XMMReg, MMXReg)
+DEF_HELPER_2(cvtsi2ss, void, XMMReg, i32)
+DEF_HELPER_2(cvtsi2sd, void, XMMReg, i32)
+
+#ifdef TARGET_X86_64
+DEF_HELPER_2(cvtsq2ss, void, XMMReg, i64)
+DEF_HELPER_2(cvtsq2sd, void, XMMReg, i64)
+#endif
+
+DEF_HELPER_2(cvtps2dq, void, XMMReg, XMMReg)
+DEF_HELPER_2(cvtpd2dq, void, XMMReg, XMMReg)
+DEF_HELPER_2(cvtps2pi, void, MMXReg, XMMReg)
+DEF_HELPER_2(cvtpd2pi, void, MMXReg, XMMReg)
+DEF_HELPER_1(cvtss2si, s32, XMMReg)
+DEF_HELPER_1(cvtsd2si, s32, XMMReg)
+#ifdef TARGET_X86_64
+DEF_HELPER_1(cvtss2sq, s64, XMMReg)
+DEF_HELPER_1(cvtsd2sq, s64, XMMReg)
+#endif
+
+DEF_HELPER_2(cvttps2dq, void, XMMReg, XMMReg)
+DEF_HELPER_2(cvttpd2dq, void, XMMReg, XMMReg)
+DEF_HELPER_2(cvttps2pi, void, MMXReg, XMMReg)
+DEF_HELPER_2(cvttpd2pi, void, MMXReg, XMMReg)
+DEF_HELPER_1(cvttss2si, s32, XMMReg)
+DEF_HELPER_1(cvttsd2si, s32, XMMReg)
+#ifdef TARGET_X86_64
+DEF_HELPER_1(cvttss2sq, s64, XMMReg)
+DEF_HELPER_1(cvttsd2sq, s64, XMMReg)
+#endif
+
+DEF_HELPER_2(rsqrtps, void, XMMReg, XMMReg)
+DEF_HELPER_2(rsqrtss, void, XMMReg, XMMReg)
+DEF_HELPER_2(rcpps, void, XMMReg, XMMReg)
+DEF_HELPER_2(rcpss, void, XMMReg, XMMReg)
+DEF_HELPER_2(extrq_r, void, XMMReg, XMMReg)
+DEF_HELPER_3(extrq_i, void, XMMReg, int, int)
+DEF_HELPER_2(insertq_r, void, XMMReg, XMMReg)
+DEF_HELPER_3(insertq_i, void, XMMReg, int, int)
+DEF_HELPER_2(haddps, void, XMMReg, XMMReg)
+DEF_HELPER_2(haddpd, void, XMMReg, XMMReg)
+DEF_HELPER_2(hsubps, void, XMMReg, XMMReg)
+DEF_HELPER_2(hsubpd, void, XMMReg, XMMReg)
+DEF_HELPER_2(addsubps, void, XMMReg, XMMReg)
+DEF_HELPER_2(addsubpd, void, XMMReg, XMMReg)
+
+#define SSE_HELPER_CMP(name, F)\
+    DEF_HELPER_2( name ## ps , void, Reg, Reg)        \
+    DEF_HELPER_2( name ## ss , void, Reg, Reg)        \
+    DEF_HELPER_2( name ## pd , void, Reg, Reg)        \
+    DEF_HELPER_2( name ## sd , void, Reg, Reg)
+
+SSE_HELPER_CMP(cmpeq, FPU_CMPEQ)
+SSE_HELPER_CMP(cmplt, FPU_CMPLT)
+SSE_HELPER_CMP(cmple, FPU_CMPLE)
+SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD)
+SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ)
+SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT)
+SSE_HELPER_CMP(cmpnle, FPU_CMPNLE)
+SSE_HELPER_CMP(cmpord, FPU_CMPORD)
+
+DEF_HELPER_2(ucomiss, void, Reg, Reg)
+DEF_HELPER_2(comiss, void, Reg, Reg)
+DEF_HELPER_2(ucomisd, void, Reg, Reg)
+DEF_HELPER_2(comisd, void, Reg, Reg)
+DEF_HELPER_1(movmskps, i32, Reg)
+DEF_HELPER_1(movmskpd, i32, Reg)
+#endif
+
+DEF_HELPER_1(glue(pmovmskb, SUFFIX), i32, Reg)
+DEF_HELPER_2(glue(packsswb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(packuswb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(packssdw, SUFFIX), void, Reg, Reg)
+#define UNPCK_OP(base_name, base)                               \
+    DEF_HELPER_2(glue(punpck ## base_name ## bw, SUFFIX) , void, Reg, Reg) \
+    DEF_HELPER_2(glue(punpck ## base_name ## wd, SUFFIX) , void, Reg, Reg) \
+    DEF_HELPER_2(glue(punpck ## base_name ## dq, SUFFIX) , void, Reg, Reg)
+
+UNPCK_OP(l, 0)
+UNPCK_OP(h, 1)
+
+#if SHIFT == 1
+DEF_HELPER_2(glue(punpcklqdq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(punpckhqdq, SUFFIX), void, Reg, Reg)
+#endif
+
+/* 3DNow! float ops */
+#if SHIFT == 0
+DEF_HELPER_2(pi2fd, void, MMXReg, MMXReg)
+DEF_HELPER_2(pi2fw, void, MMXReg, MMXReg)
+DEF_HELPER_2(pf2id, void, MMXReg, MMXReg)
+DEF_HELPER_2(pf2iw, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfacc, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfadd, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfcmpeq, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfcmpge, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfcmpgt, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfmax, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfmin, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfmul, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfnacc, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfpnacc, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfrcp, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfrsqrt, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfsub, void, MMXReg, MMXReg)
+DEF_HELPER_2(pfsubr, void, MMXReg, MMXReg)
+DEF_HELPER_2(pswapd, void, MMXReg, MMXReg)
+#endif
+
+/* SSSE3 op helpers */
+DEF_HELPER_2(glue(phaddw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phaddd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phaddsw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phsubw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phsubd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phsubsw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pabsb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pabsw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pabsd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaddubsw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmulhrsw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pshufb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psignb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psignw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(psignd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(palignr, SUFFIX), void, Reg, Reg, s32)
+
+/* SSE4.1 op helpers */
+#if SHIFT == 1
+DEF_HELPER_2(glue(pblendvb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(blendvps, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(blendvpd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(ptest, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxbw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxbd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxbq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxwd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxwq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovsxdq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxbw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxbd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxbq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxwd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxwq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmovzxdq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmuldq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pcmpeqq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(packusdw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pminsb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pminsd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pminuw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pminud, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaxsb, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaxsd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaxuw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmaxud, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(pmulld, SUFFIX), void, Reg, Reg)
+DEF_HELPER_2(glue(phminposuw, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(roundps, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(roundpd, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(roundss, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(roundsd, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(blendps, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(blendpd, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pblendw, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(dpps, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(dppd, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(mpsadbw, SUFFIX), void, Reg, Reg, i32)
+#endif
+
+/* SSE4.2 op helpers */
+#if SHIFT == 1
+DEF_HELPER_2(glue(pcmpgtq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(pcmpestri, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pcmpestrm, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pcmpistri, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pcmpistrm, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(crc32, tl, i32, tl, i32)
+DEF_HELPER_2(popcnt, tl, tl, i32)
+#endif
+
+#undef SHIFT
+#undef Reg
+#undef SUFFIX
+
+#undef SSE_HELPER_B
+#undef SSE_HELPER_W
+#undef SSE_HELPER_L
+#undef SSE_HELPER_Q
+#undef SSE_HELPER_S
+#undef SSE_HELPER_CMP
+#undef UNPCK_OP
diff --git a/qemu-0.15.x/target-i386/svm.h b/qemu-0.15.x/target-i386/svm.h
new file mode 100644
index 0000000..a224aea
--- /dev/null
+++ b/qemu-0.15.x/target-i386/svm.h
@@ -0,0 +1,222 @@
+#ifndef __SVM_H
+#define __SVM_H
+
+#define TLB_CONTROL_DO_NOTHING 0
+#define TLB_CONTROL_FLUSH_ALL_ASID 1
+
+#define V_TPR_MASK 0x0f
+
+#define V_IRQ_SHIFT 8
+#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
+
+#define V_INTR_PRIO_SHIFT 16
+#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
+
+#define V_IGN_TPR_SHIFT 20
+#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
+
+#define V_INTR_MASKING_SHIFT 24
+#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
+
+#define SVM_INTERRUPT_SHADOW_MASK 1
+
+#define SVM_IOIO_STR_SHIFT 2
+#define SVM_IOIO_REP_SHIFT 3
+#define SVM_IOIO_SIZE_SHIFT 4
+#define SVM_IOIO_ASIZE_SHIFT 7
+
+#define SVM_IOIO_TYPE_MASK 1
+#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
+#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
+#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
+#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
+
+#define SVM_EVTINJ_VEC_MASK 0xff
+
+#define SVM_EVTINJ_TYPE_SHIFT 8
+#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_VALID (1 << 31)
+#define SVM_EVTINJ_VALID_ERR (1 << 11)
+
+#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+
+#define	SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
+#define	SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
+#define	SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
+#define	SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
+
+#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
+#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+
+#define	SVM_EXIT_READ_CR0 	0x000
+#define	SVM_EXIT_READ_CR3 	0x003
+#define	SVM_EXIT_READ_CR4 	0x004
+#define	SVM_EXIT_READ_CR8 	0x008
+#define	SVM_EXIT_WRITE_CR0 	0x010
+#define	SVM_EXIT_WRITE_CR3 	0x013
+#define	SVM_EXIT_WRITE_CR4 	0x014
+#define	SVM_EXIT_WRITE_CR8 	0x018
+#define	SVM_EXIT_READ_DR0 	0x020
+#define	SVM_EXIT_READ_DR1 	0x021
+#define	SVM_EXIT_READ_DR2 	0x022
+#define	SVM_EXIT_READ_DR3 	0x023
+#define	SVM_EXIT_READ_DR4 	0x024
+#define	SVM_EXIT_READ_DR5 	0x025
+#define	SVM_EXIT_READ_DR6 	0x026
+#define	SVM_EXIT_READ_DR7 	0x027
+#define	SVM_EXIT_WRITE_DR0 	0x030
+#define	SVM_EXIT_WRITE_DR1 	0x031
+#define	SVM_EXIT_WRITE_DR2 	0x032
+#define	SVM_EXIT_WRITE_DR3 	0x033
+#define	SVM_EXIT_WRITE_DR4 	0x034
+#define	SVM_EXIT_WRITE_DR5 	0x035
+#define	SVM_EXIT_WRITE_DR6 	0x036
+#define	SVM_EXIT_WRITE_DR7 	0x037
+#define SVM_EXIT_EXCP_BASE      0x040
+#define SVM_EXIT_INTR		0x060
+#define SVM_EXIT_NMI		0x061
+#define SVM_EXIT_SMI		0x062
+#define SVM_EXIT_INIT		0x063
+#define SVM_EXIT_VINTR		0x064
+#define SVM_EXIT_CR0_SEL_WRITE	0x065
+#define SVM_EXIT_IDTR_READ	0x066
+#define SVM_EXIT_GDTR_READ	0x067
+#define SVM_EXIT_LDTR_READ	0x068
+#define SVM_EXIT_TR_READ	0x069
+#define SVM_EXIT_IDTR_WRITE	0x06a
+#define SVM_EXIT_GDTR_WRITE	0x06b
+#define SVM_EXIT_LDTR_WRITE	0x06c
+#define SVM_EXIT_TR_WRITE	0x06d
+#define SVM_EXIT_RDTSC		0x06e
+#define SVM_EXIT_RDPMC		0x06f
+#define SVM_EXIT_PUSHF		0x070
+#define SVM_EXIT_POPF		0x071
+#define SVM_EXIT_CPUID		0x072
+#define SVM_EXIT_RSM		0x073
+#define SVM_EXIT_IRET		0x074
+#define SVM_EXIT_SWINT		0x075
+#define SVM_EXIT_INVD		0x076
+#define SVM_EXIT_PAUSE		0x077
+#define SVM_EXIT_HLT		0x078
+#define SVM_EXIT_INVLPG		0x079
+#define SVM_EXIT_INVLPGA	0x07a
+#define SVM_EXIT_IOIO		0x07b
+#define SVM_EXIT_MSR		0x07c
+#define SVM_EXIT_TASK_SWITCH	0x07d
+#define SVM_EXIT_FERR_FREEZE	0x07e
+#define SVM_EXIT_SHUTDOWN	0x07f
+#define SVM_EXIT_VMRUN		0x080
+#define SVM_EXIT_VMMCALL	0x081
+#define SVM_EXIT_VMLOAD		0x082
+#define SVM_EXIT_VMSAVE		0x083
+#define SVM_EXIT_STGI		0x084
+#define SVM_EXIT_CLGI		0x085
+#define SVM_EXIT_SKINIT		0x086
+#define SVM_EXIT_RDTSCP		0x087
+#define SVM_EXIT_ICEBP		0x088
+#define SVM_EXIT_WBINVD		0x089
+/* only included in documentation, maybe wrong */
+#define SVM_EXIT_MONITOR	0x08a
+#define SVM_EXIT_MWAIT		0x08b
+#define SVM_EXIT_NPF  		0x400
+
+#define SVM_EXIT_ERR		-1
+
+#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
+
+struct __attribute__ ((__packed__)) vmcb_control_area {
+	uint16_t intercept_cr_read;
+	uint16_t intercept_cr_write;
+	uint16_t intercept_dr_read;
+	uint16_t intercept_dr_write;
+	uint32_t intercept_exceptions;
+	uint64_t intercept;
+	uint8_t reserved_1[44];
+	uint64_t iopm_base_pa;
+	uint64_t msrpm_base_pa;
+	uint64_t tsc_offset;
+	uint32_t asid;
+	uint8_t tlb_ctl;
+	uint8_t reserved_2[3];
+	uint32_t int_ctl;
+	uint32_t int_vector;
+	uint32_t int_state;
+	uint8_t reserved_3[4];
+	uint64_t exit_code;
+	uint64_t exit_info_1;
+	uint64_t exit_info_2;
+	uint32_t exit_int_info;
+	uint32_t exit_int_info_err;
+	uint64_t nested_ctl;
+	uint8_t reserved_4[16];
+	uint32_t event_inj;
+	uint32_t event_inj_err;
+	uint64_t nested_cr3;
+	uint64_t lbr_ctl;
+	uint8_t reserved_5[832];
+};
+
+struct __attribute__ ((__packed__)) vmcb_seg {
+	uint16_t selector;
+	uint16_t attrib;
+	uint32_t limit;
+	uint64_t base;
+};
+
+struct __attribute__ ((__packed__)) vmcb_save_area {
+	struct vmcb_seg es;
+	struct vmcb_seg cs;
+	struct vmcb_seg ss;
+	struct vmcb_seg ds;
+	struct vmcb_seg fs;
+	struct vmcb_seg gs;
+	struct vmcb_seg gdtr;
+	struct vmcb_seg ldtr;
+	struct vmcb_seg idtr;
+	struct vmcb_seg tr;
+	uint8_t reserved_1[43];
+	uint8_t cpl;
+	uint8_t reserved_2[4];
+	uint64_t efer;
+	uint8_t reserved_3[112];
+	uint64_t cr4;
+	uint64_t cr3;
+	uint64_t cr0;
+	uint64_t dr7;
+	uint64_t dr6;
+	uint64_t rflags;
+	uint64_t rip;
+	uint8_t reserved_4[88];
+	uint64_t rsp;
+	uint8_t reserved_5[24];
+	uint64_t rax;
+	uint64_t star;
+	uint64_t lstar;
+	uint64_t cstar;
+	uint64_t sfmask;
+	uint64_t kernel_gs_base;
+	uint64_t sysenter_cs;
+	uint64_t sysenter_esp;
+	uint64_t sysenter_eip;
+	uint64_t cr2;
+	uint8_t reserved_6[32];
+	uint64_t g_pat;
+	uint64_t dbgctl;
+	uint64_t br_from;
+	uint64_t br_to;
+	uint64_t last_excp_from;
+	uint64_t last_excp_to;
+};
+
+struct __attribute__ ((__packed__)) vmcb {
+	struct vmcb_control_area control;
+	struct vmcb_save_area save;
+};
+
+#endif
diff --git a/qemu-0.15.x/target-i386/translate.c b/qemu-0.15.x/target-i386/translate.c
new file mode 100644
index 0000000..ccef381
--- /dev/null
+++ b/qemu-0.15.x/target-i386/translate.c
@@ -0,0 +1,7913 @@
+/*
+ *  i386 translation
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define PREFIX_REPZ   0x01
+#define PREFIX_REPNZ  0x02
+#define PREFIX_LOCK   0x04
+#define PREFIX_DATA   0x08
+#define PREFIX_ADR    0x10
+
+#ifdef TARGET_X86_64
+#define X86_64_ONLY(x) x
+#define X86_64_DEF(...)  __VA_ARGS__
+#define CODE64(s) ((s)->code64)
+#define REX_X(s) ((s)->rex_x)
+#define REX_B(s) ((s)->rex_b)
+/* XXX: gcc generates push/pop in some opcodes, so we cannot use them */
+#if 1
+#define BUGGY_64(x) NULL
+#endif
+#else
+#define X86_64_ONLY(x) NULL
+#define X86_64_DEF(...)
+#define CODE64(s) 0
+#define REX_X(s) 0
+#define REX_B(s) 0
+#endif
+
+//#define MACRO_TEST   1
+
+/* global register indexes */
+static TCGv_ptr cpu_env;
+static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp;
+static TCGv_i32 cpu_cc_op;
+static TCGv cpu_regs[CPU_NB_REGS];
+/* local temps */
+static TCGv cpu_T[2], cpu_T3;
+/* local register indexes (only used inside old micro ops) */
+static TCGv cpu_tmp0, cpu_tmp4;
+static TCGv_ptr cpu_ptr0, cpu_ptr1;
+static TCGv_i32 cpu_tmp2_i32, cpu_tmp3_i32;
+static TCGv_i64 cpu_tmp1_i64;
+static TCGv cpu_tmp5;
+
+static uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
+
+#include "gen-icount.h"
+
+#ifdef TARGET_X86_64
+static int x86_64_hregs;
+#endif
+
+typedef struct DisasContext {
+    /* current insn context */
+    int override; /* -1 if no override */
+    int prefix;
+    int aflag, dflag;
+    target_ulong pc; /* pc = eip + cs_base */
+    int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
+                   static state change (stop translation) */
+    /* current block context */
+    target_ulong cs_base; /* base of CS segment */
+    int pe;     /* protected mode */
+    int code32; /* 32 bit code segment */
+#ifdef TARGET_X86_64
+    int lma;    /* long mode active */
+    int code64; /* 64 bit code segment */
+    int rex_x, rex_b;
+#endif
+    int ss32;   /* 32 bit stack segment */
+    int cc_op;  /* current CC operation */
+    int addseg; /* non zero if either DS/ES/SS have a non zero base */
+    int f_st;   /* currently unused */
+    int vm86;   /* vm86 mode */
+    int cpl;
+    int iopl;
+    int tf;     /* TF cpu flag */
+    int singlestep_enabled; /* "hardware" single step enabled */
+    int jmp_opt; /* use direct block chaining for direct jumps */
+    int mem_index; /* select memory access functions */
+    uint64_t flags; /* all execution flags */
+    struct TranslationBlock *tb;
+    int popl_esp_hack; /* for correct popl with esp base handling */
+    int rip_offset; /* only used in x86_64, but left for simplicity */
+    int cpuid_features;
+    int cpuid_ext_features;
+    int cpuid_ext2_features;
+    int cpuid_ext3_features;
+} DisasContext;
+
+static void gen_eob(DisasContext *s);
+static void gen_jmp(DisasContext *s, target_ulong eip);
+static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
+
+/* i386 arith/logic operations */
+enum {
+    OP_ADDL,
+    OP_ORL,
+    OP_ADCL,
+    OP_SBBL,
+    OP_ANDL,
+    OP_SUBL,
+    OP_XORL,
+    OP_CMPL,
+};
+
+/* i386 shift ops */
+enum {
+    OP_ROL,
+    OP_ROR,
+    OP_RCL,
+    OP_RCR,
+    OP_SHL,
+    OP_SHR,
+    OP_SHL1, /* undocumented */
+    OP_SAR = 7,
+};
+
+enum {
+    JCC_O,
+    JCC_B,
+    JCC_Z,
+    JCC_BE,
+    JCC_S,
+    JCC_P,
+    JCC_L,
+    JCC_LE,
+};
+
+/* operand size */
+enum {
+    OT_BYTE = 0,
+    OT_WORD,
+    OT_LONG,
+    OT_QUAD,
+};
+
+enum {
+    /* I386 int registers */
+    OR_EAX,   /* MUST be even numbered */
+    OR_ECX,
+    OR_EDX,
+    OR_EBX,
+    OR_ESP,
+    OR_EBP,
+    OR_ESI,
+    OR_EDI,
+
+    OR_TMP0 = 16,    /* temporary operand register */
+    OR_TMP1,
+    OR_A0, /* temporary register used when doing address evaluation */
+};
+
+static inline void gen_op_movl_T0_0(void)
+{
+    tcg_gen_movi_tl(cpu_T[0], 0);
+}
+
+static inline void gen_op_movl_T0_im(int32_t val)
+{
+    tcg_gen_movi_tl(cpu_T[0], val);
+}
+
+static inline void gen_op_movl_T0_imu(uint32_t val)
+{
+    tcg_gen_movi_tl(cpu_T[0], val);
+}
+
+static inline void gen_op_movl_T1_im(int32_t val)
+{
+    tcg_gen_movi_tl(cpu_T[1], val);
+}
+
+static inline void gen_op_movl_T1_imu(uint32_t val)
+{
+    tcg_gen_movi_tl(cpu_T[1], val);
+}
+
+static inline void gen_op_movl_A0_im(uint32_t val)
+{
+    tcg_gen_movi_tl(cpu_A0, val);
+}
+
+#ifdef TARGET_X86_64
+static inline void gen_op_movq_A0_im(int64_t val)
+{
+    tcg_gen_movi_tl(cpu_A0, val);
+}
+#endif
+
+static inline void gen_movtl_T0_im(target_ulong val)
+{
+    tcg_gen_movi_tl(cpu_T[0], val);
+}
+
+static inline void gen_movtl_T1_im(target_ulong val)
+{
+    tcg_gen_movi_tl(cpu_T[1], val);
+}
+
+static inline void gen_op_andl_T0_ffff(void)
+{
+    tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff);
+}
+
+static inline void gen_op_andl_T0_im(uint32_t val)
+{
+    tcg_gen_andi_tl(cpu_T[0], cpu_T[0], val);
+}
+
+static inline void gen_op_movl_T0_T1(void)
+{
+    tcg_gen_mov_tl(cpu_T[0], cpu_T[1]);
+}
+
+static inline void gen_op_andl_A0_ffff(void)
+{
+    tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffff);
+}
+
+#ifdef TARGET_X86_64
+
+#define NB_OP_SIZES 4
+
+#else /* !TARGET_X86_64 */
+
+#define NB_OP_SIZES 3
+
+#endif /* !TARGET_X86_64 */
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define REG_B_OFFSET (sizeof(target_ulong) - 1)
+#define REG_H_OFFSET (sizeof(target_ulong) - 2)
+#define REG_W_OFFSET (sizeof(target_ulong) - 2)
+#define REG_L_OFFSET (sizeof(target_ulong) - 4)
+#define REG_LH_OFFSET (sizeof(target_ulong) - 8)
+#else
+#define REG_B_OFFSET 0
+#define REG_H_OFFSET 1
+#define REG_W_OFFSET 0
+#define REG_L_OFFSET 0
+#define REG_LH_OFFSET 4
+#endif
+
+static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
+{
+    switch(ot) {
+    case OT_BYTE:
+        if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
+            tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 8);
+        } else {
+            tcg_gen_deposit_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], t0, 8, 8);
+        }
+        break;
+    case OT_WORD:
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 16);
+        break;
+    default: /* XXX this shouldn't be reached;  abort? */
+    case OT_LONG:
+        /* For x86_64, this sets the higher half of register to zero.
+           For i386, this is equivalent to a mov. */
+        tcg_gen_ext32u_tl(cpu_regs[reg], t0);
+        break;
+#ifdef TARGET_X86_64
+    case OT_QUAD:
+        tcg_gen_mov_tl(cpu_regs[reg], t0);
+        break;
+#endif
+    }
+}
+
+static inline void gen_op_mov_reg_T0(int ot, int reg)
+{
+    gen_op_mov_reg_v(ot, reg, cpu_T[0]);
+}
+
+static inline void gen_op_mov_reg_T1(int ot, int reg)
+{
+    gen_op_mov_reg_v(ot, reg, cpu_T[1]);
+}
+
+static inline void gen_op_mov_reg_A0(int size, int reg)
+{
+    switch(size) {
+    case 0:
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_A0, 0, 16);
+        break;
+    default: /* XXX this shouldn't be reached;  abort? */
+    case 1:
+        /* For x86_64, this sets the higher half of register to zero.
+           For i386, this is equivalent to a mov. */
+        tcg_gen_ext32u_tl(cpu_regs[reg], cpu_A0);
+        break;
+#ifdef TARGET_X86_64
+    case 2:
+        tcg_gen_mov_tl(cpu_regs[reg], cpu_A0);
+        break;
+#endif
+    }
+}
+
+static inline void gen_op_mov_v_reg(int ot, TCGv t0, int reg)
+{
+    switch(ot) {
+    case OT_BYTE:
+        if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
+            goto std_case;
+        } else {
+            tcg_gen_shri_tl(t0, cpu_regs[reg - 4], 8);
+            tcg_gen_ext8u_tl(t0, t0);
+        }
+        break;
+    default:
+    std_case:
+        tcg_gen_mov_tl(t0, cpu_regs[reg]);
+        break;
+    }
+}
+
+static inline void gen_op_mov_TN_reg(int ot, int t_index, int reg)
+{
+    gen_op_mov_v_reg(ot, cpu_T[t_index], reg);
+}
+
+static inline void gen_op_movl_A0_reg(int reg)
+{
+    tcg_gen_mov_tl(cpu_A0, cpu_regs[reg]);
+}
+
+static inline void gen_op_addl_A0_im(int32_t val)
+{
+    tcg_gen_addi_tl(cpu_A0, cpu_A0, val);
+#ifdef TARGET_X86_64
+    tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
+#endif
+}
+
+#ifdef TARGET_X86_64
+static inline void gen_op_addq_A0_im(int64_t val)
+{
+    tcg_gen_addi_tl(cpu_A0, cpu_A0, val);
+}
+#endif
+    
+static void gen_add_A0_im(DisasContext *s, int val)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s))
+        gen_op_addq_A0_im(val);
+    else
+#endif
+        gen_op_addl_A0_im(val);
+}
+
+static inline void gen_op_addl_T0_T1(void)
+{
+    tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+}
+
+static inline void gen_op_jmp_T0(void)
+{
+    tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUState, eip));
+}
+
+static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
+{
+    switch(size) {
+    case 0:
+        tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
+        break;
+    case 1:
+        tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
+        /* For x86_64, this sets the higher half of register to zero.
+           For i386, this is equivalent to a nop. */
+        tcg_gen_ext32u_tl(cpu_tmp0, cpu_tmp0);
+        tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0);
+        break;
+#ifdef TARGET_X86_64
+    case 2:
+        tcg_gen_addi_tl(cpu_regs[reg], cpu_regs[reg], val);
+        break;
+#endif
+    }
+}
+
+static inline void gen_op_add_reg_T0(int size, int reg)
+{
+    switch(size) {
+    case 0:
+        tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
+        tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
+        break;
+    case 1:
+        tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
+        /* For x86_64, this sets the higher half of register to zero.
+           For i386, this is equivalent to a nop. */
+        tcg_gen_ext32u_tl(cpu_tmp0, cpu_tmp0);
+        tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0);
+        break;
+#ifdef TARGET_X86_64
+    case 2:
+        tcg_gen_add_tl(cpu_regs[reg], cpu_regs[reg], cpu_T[0]);
+        break;
+#endif
+    }
+}
+
+static inline void gen_op_set_cc_op(int32_t val)
+{
+    tcg_gen_movi_i32(cpu_cc_op, val);
+}
+
+static inline void gen_op_addl_A0_reg_sN(int shift, int reg)
+{
+    tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]);
+    if (shift != 0)
+        tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
+    tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+    /* For x86_64, this sets the higher half of register to zero.
+       For i386, this is equivalent to a nop. */
+    tcg_gen_ext32u_tl(cpu_A0, cpu_A0);
+}
+
+static inline void gen_op_movl_A0_seg(int reg)
+{
+    tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base) + REG_L_OFFSET);
+}
+
+static inline void gen_op_addl_A0_seg(int reg)
+{
+    tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base));
+    tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+#ifdef TARGET_X86_64
+    tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
+#endif
+}
+
+#ifdef TARGET_X86_64
+static inline void gen_op_movq_A0_seg(int reg)
+{
+    tcg_gen_ld_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base));
+}
+
+static inline void gen_op_addq_A0_seg(int reg)
+{
+    tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base));
+    tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+}
+
+static inline void gen_op_movq_A0_reg(int reg)
+{
+    tcg_gen_mov_tl(cpu_A0, cpu_regs[reg]);
+}
+
+static inline void gen_op_addq_A0_reg_sN(int shift, int reg)
+{
+    tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]);
+    if (shift != 0)
+        tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
+    tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+}
+#endif
+
+static inline void gen_op_lds_T0_A0(int idx)
+{
+    int mem_index = (idx >> 2) - 1;
+    switch(idx & 3) {
+    case 0:
+        tcg_gen_qemu_ld8s(cpu_T[0], cpu_A0, mem_index);
+        break;
+    case 1:
+        tcg_gen_qemu_ld16s(cpu_T[0], cpu_A0, mem_index);
+        break;
+    default:
+    case 2:
+        tcg_gen_qemu_ld32s(cpu_T[0], cpu_A0, mem_index);
+        break;
+    }
+}
+
+static inline void gen_op_ld_v(int idx, TCGv t0, TCGv a0)
+{
+    int mem_index = (idx >> 2) - 1;
+    switch(idx & 3) {
+    case 0:
+        tcg_gen_qemu_ld8u(t0, a0, mem_index);
+        break;
+    case 1:
+        tcg_gen_qemu_ld16u(t0, a0, mem_index);
+        break;
+    case 2:
+        tcg_gen_qemu_ld32u(t0, a0, mem_index);
+        break;
+    default:
+    case 3:
+        /* Should never happen on 32-bit targets.  */
+#ifdef TARGET_X86_64
+        tcg_gen_qemu_ld64(t0, a0, mem_index);
+#endif
+        break;
+    }
+}
+
+/* XXX: always use ldu or lds */
+static inline void gen_op_ld_T0_A0(int idx)
+{
+    gen_op_ld_v(idx, cpu_T[0], cpu_A0);
+}
+
+static inline void gen_op_ldu_T0_A0(int idx)
+{
+    gen_op_ld_v(idx, cpu_T[0], cpu_A0);
+}
+
+static inline void gen_op_ld_T1_A0(int idx)
+{
+    gen_op_ld_v(idx, cpu_T[1], cpu_A0);
+}
+
+static inline void gen_op_st_v(int idx, TCGv t0, TCGv a0)
+{
+    int mem_index = (idx >> 2) - 1;
+    switch(idx & 3) {
+    case 0:
+        tcg_gen_qemu_st8(t0, a0, mem_index);
+        break;
+    case 1:
+        tcg_gen_qemu_st16(t0, a0, mem_index);
+        break;
+    case 2:
+        tcg_gen_qemu_st32(t0, a0, mem_index);
+        break;
+    default:
+    case 3:
+        /* Should never happen on 32-bit targets.  */
+#ifdef TARGET_X86_64
+        tcg_gen_qemu_st64(t0, a0, mem_index);
+#endif
+        break;
+    }
+}
+
+static inline void gen_op_st_T0_A0(int idx)
+{
+    gen_op_st_v(idx, cpu_T[0], cpu_A0);
+}
+
+static inline void gen_op_st_T1_A0(int idx)
+{
+    gen_op_st_v(idx, cpu_T[1], cpu_A0);
+}
+
+static inline void gen_jmp_im(target_ulong pc)
+{
+    tcg_gen_movi_tl(cpu_tmp0, pc);
+    tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, eip));
+}
+
+static inline void gen_string_movl_A0_ESI(DisasContext *s)
+{
+    int override;
+
+    override = s->override;
+#ifdef TARGET_X86_64
+    if (s->aflag == 2) {
+        if (override >= 0) {
+            gen_op_movq_A0_seg(override);
+            gen_op_addq_A0_reg_sN(0, R_ESI);
+        } else {
+            gen_op_movq_A0_reg(R_ESI);
+        }
+    } else
+#endif
+    if (s->aflag) {
+        /* 32 bit address */
+        if (s->addseg && override < 0)
+            override = R_DS;
+        if (override >= 0) {
+            gen_op_movl_A0_seg(override);
+            gen_op_addl_A0_reg_sN(0, R_ESI);
+        } else {
+            gen_op_movl_A0_reg(R_ESI);
+        }
+    } else {
+        /* 16 address, always override */
+        if (override < 0)
+            override = R_DS;
+        gen_op_movl_A0_reg(R_ESI);
+        gen_op_andl_A0_ffff();
+        gen_op_addl_A0_seg(override);
+    }
+}
+
+static inline void gen_string_movl_A0_EDI(DisasContext *s)
+{
+#ifdef TARGET_X86_64
+    if (s->aflag == 2) {
+        gen_op_movq_A0_reg(R_EDI);
+    } else
+#endif
+    if (s->aflag) {
+        if (s->addseg) {
+            gen_op_movl_A0_seg(R_ES);
+            gen_op_addl_A0_reg_sN(0, R_EDI);
+        } else {
+            gen_op_movl_A0_reg(R_EDI);
+        }
+    } else {
+        gen_op_movl_A0_reg(R_EDI);
+        gen_op_andl_A0_ffff();
+        gen_op_addl_A0_seg(R_ES);
+    }
+}
+
+static inline void gen_op_movl_T0_Dshift(int ot) 
+{
+    tcg_gen_ld32s_tl(cpu_T[0], cpu_env, offsetof(CPUState, df));
+    tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot);
+};
+
+static void gen_extu(int ot, TCGv reg)
+{
+    switch(ot) {
+    case OT_BYTE:
+        tcg_gen_ext8u_tl(reg, reg);
+        break;
+    case OT_WORD:
+        tcg_gen_ext16u_tl(reg, reg);
+        break;
+    case OT_LONG:
+        tcg_gen_ext32u_tl(reg, reg);
+        break;
+    default:
+        break;
+    }
+}
+
+static void gen_exts(int ot, TCGv reg)
+{
+    switch(ot) {
+    case OT_BYTE:
+        tcg_gen_ext8s_tl(reg, reg);
+        break;
+    case OT_WORD:
+        tcg_gen_ext16s_tl(reg, reg);
+        break;
+    case OT_LONG:
+        tcg_gen_ext32s_tl(reg, reg);
+        break;
+    default:
+        break;
+    }
+}
+
+static inline void gen_op_jnz_ecx(int size, int label1)
+{
+    tcg_gen_mov_tl(cpu_tmp0, cpu_regs[R_ECX]);
+    gen_extu(size + 1, cpu_tmp0);
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, label1);
+}
+
+static inline void gen_op_jz_ecx(int size, int label1)
+{
+    tcg_gen_mov_tl(cpu_tmp0, cpu_regs[R_ECX]);
+    gen_extu(size + 1, cpu_tmp0);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
+}
+
+static void gen_helper_in_func(int ot, TCGv v, TCGv_i32 n)
+{
+    switch (ot) {
+    case 0: gen_helper_inb(v, n); break;
+    case 1: gen_helper_inw(v, n); break;
+    case 2: gen_helper_inl(v, n); break;
+    }
+
+}
+
+static void gen_helper_out_func(int ot, TCGv_i32 v, TCGv_i32 n)
+{
+    switch (ot) {
+    case 0: gen_helper_outb(v, n); break;
+    case 1: gen_helper_outw(v, n); break;
+    case 2: gen_helper_outl(v, n); break;
+    }
+
+}
+
+static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
+                         uint32_t svm_flags)
+{
+    int state_saved;
+    target_ulong next_eip;
+
+    state_saved = 0;
+    if (s->pe && (s->cpl > s->iopl || s->vm86)) {
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(cur_eip);
+        state_saved = 1;
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        switch (ot) {
+        case 0: gen_helper_check_iob(cpu_tmp2_i32); break;
+        case 1: gen_helper_check_iow(cpu_tmp2_i32); break;
+        case 2: gen_helper_check_iol(cpu_tmp2_i32); break;
+        }
+    }
+    if(s->flags & HF_SVMI_MASK) {
+        if (!state_saved) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(cur_eip);
+        }
+        svm_flags |= (1 << (4 + ot));
+        next_eip = s->pc - s->cs_base;
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        gen_helper_svm_check_io(cpu_tmp2_i32, tcg_const_i32(svm_flags),
+                                tcg_const_i32(next_eip - cur_eip));
+    }
+}
+
+static inline void gen_movs(DisasContext *s, int ot)
+{
+    gen_string_movl_A0_ESI(s);
+    gen_op_ld_T0_A0(ot + s->mem_index);
+    gen_string_movl_A0_EDI(s);
+    gen_op_st_T0_A0(ot + s->mem_index);
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_ESI);
+    gen_op_add_reg_T0(s->aflag, R_EDI);
+}
+
+static inline void gen_update_cc_op(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC) {
+        gen_op_set_cc_op(s->cc_op);
+        s->cc_op = CC_OP_DYNAMIC;
+    }
+}
+
+static void gen_op_update1_cc(void)
+{
+    tcg_gen_discard_tl(cpu_cc_src);
+    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+}
+
+static void gen_op_update2_cc(void)
+{
+    tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
+    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+}
+
+static inline void gen_op_cmpl_T0_T1_cc(void)
+{
+    tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
+    tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
+}
+
+static inline void gen_op_testl_T0_T1_cc(void)
+{
+    tcg_gen_discard_tl(cpu_cc_src);
+    tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
+}
+
+static void gen_op_update_neg_cc(void)
+{
+    tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]);
+    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+}
+
+/* compute eflags.C to reg */
+static void gen_compute_eflags_c(TCGv reg)
+{
+    gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_cc_op);
+    tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
+}
+
+/* compute all eflags to cc_src */
+static void gen_compute_eflags(TCGv reg)
+{
+    gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_cc_op);
+    tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
+}
+
+static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    switch(jcc_op) {
+    case JCC_O:
+        gen_compute_eflags(cpu_T[0]);
+        tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    case JCC_B:
+        gen_compute_eflags_c(cpu_T[0]);
+        break;
+    case JCC_Z:
+        gen_compute_eflags(cpu_T[0]);
+        tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    case JCC_BE:
+        gen_compute_eflags(cpu_tmp0);
+        tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6);
+        tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    case JCC_S:
+        gen_compute_eflags(cpu_T[0]);
+        tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    case JCC_P:
+        gen_compute_eflags(cpu_T[0]);
+        tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    case JCC_L:
+        gen_compute_eflags(cpu_tmp0);
+        tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
+        tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */
+        tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    default:
+    case JCC_LE:
+        gen_compute_eflags(cpu_tmp0);
+        tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
+        tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */
+        tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */
+        tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
+        tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
+        break;
+    }
+}
+
+/* return true if setcc_slow is not needed (WARNING: must be kept in
+   sync with gen_jcc1) */
+static int is_fast_jcc_case(DisasContext *s, int b)
+{
+    int jcc_op;
+    jcc_op = (b >> 1) & 7;
+    switch(s->cc_op) {
+        /* we optimize the cmp/jcc case */
+    case CC_OP_SUBB:
+    case CC_OP_SUBW:
+    case CC_OP_SUBL:
+    case CC_OP_SUBQ:
+        if (jcc_op == JCC_O || jcc_op == JCC_P)
+            goto slow_jcc;
+        break;
+
+        /* some jumps are easy to compute */
+    case CC_OP_ADDB:
+    case CC_OP_ADDW:
+    case CC_OP_ADDL:
+    case CC_OP_ADDQ:
+
+    case CC_OP_LOGICB:
+    case CC_OP_LOGICW:
+    case CC_OP_LOGICL:
+    case CC_OP_LOGICQ:
+
+    case CC_OP_INCB:
+    case CC_OP_INCW:
+    case CC_OP_INCL:
+    case CC_OP_INCQ:
+
+    case CC_OP_DECB:
+    case CC_OP_DECW:
+    case CC_OP_DECL:
+    case CC_OP_DECQ:
+
+    case CC_OP_SHLB:
+    case CC_OP_SHLW:
+    case CC_OP_SHLL:
+    case CC_OP_SHLQ:
+        if (jcc_op != JCC_Z && jcc_op != JCC_S)
+            goto slow_jcc;
+        break;
+    default:
+    slow_jcc:
+        return 0;
+    }
+    return 1;
+}
+
+/* generate a conditional jump to label 'l1' according to jump opcode
+   value 'b'. In the fast case, T0 is guaranted not to be used. */
+static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
+{
+    int inv, jcc_op, size, cond;
+    TCGv t0;
+
+    inv = b & 1;
+    jcc_op = (b >> 1) & 7;
+
+    switch(cc_op) {
+        /* we optimize the cmp/jcc case */
+    case CC_OP_SUBB:
+    case CC_OP_SUBW:
+    case CC_OP_SUBL:
+    case CC_OP_SUBQ:
+        
+        size = cc_op - CC_OP_SUBB;
+        switch(jcc_op) {
+        case JCC_Z:
+        fast_jcc_z:
+            switch(size) {
+            case 0:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xff);
+                t0 = cpu_tmp0;
+                break;
+            case 1:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffff);
+                t0 = cpu_tmp0;
+                break;
+#ifdef TARGET_X86_64
+            case 2:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffffffff);
+                t0 = cpu_tmp0;
+                break;
+#endif
+            default:
+                t0 = cpu_cc_dst;
+                break;
+            }
+            tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1);
+            break;
+        case JCC_S:
+        fast_jcc_s:
+            switch(size) {
+            case 0:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80);
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
+                                   0, l1);
+                break;
+            case 1:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000);
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
+                                   0, l1);
+                break;
+#ifdef TARGET_X86_64
+            case 2:
+                tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000);
+                tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, 
+                                   0, l1);
+                break;
+#endif
+            default:
+                tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst, 
+                                   0, l1);
+                break;
+            }
+            break;
+            
+        case JCC_B:
+            cond = inv ? TCG_COND_GEU : TCG_COND_LTU;
+            goto fast_jcc_b;
+        case JCC_BE:
+            cond = inv ? TCG_COND_GTU : TCG_COND_LEU;
+        fast_jcc_b:
+            tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
+            switch(size) {
+            case 0:
+                t0 = cpu_tmp0;
+                tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xff);
+                tcg_gen_andi_tl(t0, cpu_cc_src, 0xff);
+                break;
+            case 1:
+                t0 = cpu_tmp0;
+                tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffff);
+                tcg_gen_andi_tl(t0, cpu_cc_src, 0xffff);
+                break;
+#ifdef TARGET_X86_64
+            case 2:
+                t0 = cpu_tmp0;
+                tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffffffff);
+                tcg_gen_andi_tl(t0, cpu_cc_src, 0xffffffff);
+                break;
+#endif
+            default:
+                t0 = cpu_cc_src;
+                break;
+            }
+            tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
+            break;
+            
+        case JCC_L:
+            cond = inv ? TCG_COND_GE : TCG_COND_LT;
+            goto fast_jcc_l;
+        case JCC_LE:
+            cond = inv ? TCG_COND_GT : TCG_COND_LE;
+        fast_jcc_l:
+            tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
+            switch(size) {
+            case 0:
+                t0 = cpu_tmp0;
+                tcg_gen_ext8s_tl(cpu_tmp4, cpu_tmp4);
+                tcg_gen_ext8s_tl(t0, cpu_cc_src);
+                break;
+            case 1:
+                t0 = cpu_tmp0;
+                tcg_gen_ext16s_tl(cpu_tmp4, cpu_tmp4);
+                tcg_gen_ext16s_tl(t0, cpu_cc_src);
+                break;
+#ifdef TARGET_X86_64
+            case 2:
+                t0 = cpu_tmp0;
+                tcg_gen_ext32s_tl(cpu_tmp4, cpu_tmp4);
+                tcg_gen_ext32s_tl(t0, cpu_cc_src);
+                break;
+#endif
+            default:
+                t0 = cpu_cc_src;
+                break;
+            }
+            tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
+            break;
+            
+        default:
+            goto slow_jcc;
+        }
+        break;
+        
+        /* some jumps are easy to compute */
+    case CC_OP_ADDB:
+    case CC_OP_ADDW:
+    case CC_OP_ADDL:
+    case CC_OP_ADDQ:
+        
+    case CC_OP_ADCB:
+    case CC_OP_ADCW:
+    case CC_OP_ADCL:
+    case CC_OP_ADCQ:
+        
+    case CC_OP_SBBB:
+    case CC_OP_SBBW:
+    case CC_OP_SBBL:
+    case CC_OP_SBBQ:
+        
+    case CC_OP_LOGICB:
+    case CC_OP_LOGICW:
+    case CC_OP_LOGICL:
+    case CC_OP_LOGICQ:
+        
+    case CC_OP_INCB:
+    case CC_OP_INCW:
+    case CC_OP_INCL:
+    case CC_OP_INCQ:
+        
+    case CC_OP_DECB:
+    case CC_OP_DECW:
+    case CC_OP_DECL:
+    case CC_OP_DECQ:
+        
+    case CC_OP_SHLB:
+    case CC_OP_SHLW:
+    case CC_OP_SHLL:
+    case CC_OP_SHLQ:
+        
+    case CC_OP_SARB:
+    case CC_OP_SARW:
+    case CC_OP_SARL:
+    case CC_OP_SARQ:
+        switch(jcc_op) {
+        case JCC_Z:
+            size = (cc_op - CC_OP_ADDB) & 3;
+            goto fast_jcc_z;
+        case JCC_S:
+            size = (cc_op - CC_OP_ADDB) & 3;
+            goto fast_jcc_s;
+        default:
+            goto slow_jcc;
+        }
+        break;
+    default:
+    slow_jcc:
+        gen_setcc_slow_T0(s, jcc_op);
+        tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, 
+                           cpu_T[0], 0, l1);
+        break;
+    }
+}
+
+/* XXX: does not work with gdbstub "ice" single step - not a
+   serious problem */
+static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
+{
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    gen_op_jnz_ecx(s->aflag, l1);
+    gen_set_label(l2);
+    gen_jmp_tb(s, next_eip, 1);
+    gen_set_label(l1);
+    return l2;
+}
+
+static inline void gen_stos(DisasContext *s, int ot)
+{
+    gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
+    gen_string_movl_A0_EDI(s);
+    gen_op_st_T0_A0(ot + s->mem_index);
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_EDI);
+}
+
+static inline void gen_lods(DisasContext *s, int ot)
+{
+    gen_string_movl_A0_ESI(s);
+    gen_op_ld_T0_A0(ot + s->mem_index);
+    gen_op_mov_reg_T0(ot, R_EAX);
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_ESI);
+}
+
+static inline void gen_scas(DisasContext *s, int ot)
+{
+    gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
+    gen_string_movl_A0_EDI(s);
+    gen_op_ld_T1_A0(ot + s->mem_index);
+    gen_op_cmpl_T0_T1_cc();
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_EDI);
+}
+
+static inline void gen_cmps(DisasContext *s, int ot)
+{
+    gen_string_movl_A0_ESI(s);
+    gen_op_ld_T0_A0(ot + s->mem_index);
+    gen_string_movl_A0_EDI(s);
+    gen_op_ld_T1_A0(ot + s->mem_index);
+    gen_op_cmpl_T0_T1_cc();
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_ESI);
+    gen_op_add_reg_T0(s->aflag, R_EDI);
+}
+
+static inline void gen_ins(DisasContext *s, int ot)
+{
+    if (use_icount)
+        gen_io_start();
+    gen_string_movl_A0_EDI(s);
+    /* Note: we must do this dummy write first to be restartable in
+       case of page fault. */
+    gen_op_movl_T0_0();
+    gen_op_st_T0_A0(ot + s->mem_index);
+    gen_op_mov_TN_reg(OT_WORD, 1, R_EDX);
+    tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]);
+    tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
+    gen_helper_in_func(ot, cpu_T[0], cpu_tmp2_i32);
+    gen_op_st_T0_A0(ot + s->mem_index);
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_EDI);
+    if (use_icount)
+        gen_io_end();
+}
+
+static inline void gen_outs(DisasContext *s, int ot)
+{
+    if (use_icount)
+        gen_io_start();
+    gen_string_movl_A0_ESI(s);
+    gen_op_ld_T0_A0(ot + s->mem_index);
+
+    gen_op_mov_TN_reg(OT_WORD, 1, R_EDX);
+    tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]);
+    tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
+    tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[0]);
+    gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
+
+    gen_op_movl_T0_Dshift(ot);
+    gen_op_add_reg_T0(s->aflag, R_ESI);
+    if (use_icount)
+        gen_io_end();
+}
+
+/* same method as Valgrind : we generate jumps to current or next
+   instruction */
+#define GEN_REPZ(op)                                                          \
+static inline void gen_repz_ ## op(DisasContext *s, int ot,                   \
+                                 target_ulong cur_eip, target_ulong next_eip) \
+{                                                                             \
+    int l2;\
+    gen_update_cc_op(s);                                                      \
+    l2 = gen_jz_ecx_string(s, next_eip);                                      \
+    gen_ ## op(s, ot);                                                        \
+    gen_op_add_reg_im(s->aflag, R_ECX, -1);                                   \
+    /* a loop would cause two single step exceptions if ECX = 1               \
+       before rep string_insn */                                              \
+    if (!s->jmp_opt)                                                          \
+        gen_op_jz_ecx(s->aflag, l2);                                          \
+    gen_jmp(s, cur_eip);                                                      \
+}
+
+#define GEN_REPZ2(op)                                                         \
+static inline void gen_repz_ ## op(DisasContext *s, int ot,                   \
+                                   target_ulong cur_eip,                      \
+                                   target_ulong next_eip,                     \
+                                   int nz)                                    \
+{                                                                             \
+    int l2;\
+    gen_update_cc_op(s);                                                      \
+    l2 = gen_jz_ecx_string(s, next_eip);                                      \
+    gen_ ## op(s, ot);                                                        \
+    gen_op_add_reg_im(s->aflag, R_ECX, -1);                                   \
+    gen_op_set_cc_op(CC_OP_SUBB + ot);                                        \
+    gen_jcc1(s, CC_OP_SUBB + ot, (JCC_Z << 1) | (nz ^ 1), l2);                \
+    if (!s->jmp_opt)                                                          \
+        gen_op_jz_ecx(s->aflag, l2);                                          \
+    gen_jmp(s, cur_eip);                                                      \
+}
+
+GEN_REPZ(movs)
+GEN_REPZ(stos)
+GEN_REPZ(lods)
+GEN_REPZ(ins)
+GEN_REPZ(outs)
+GEN_REPZ2(scas)
+GEN_REPZ2(cmps)
+
+static void gen_helper_fp_arith_ST0_FT0(int op)
+{
+    switch (op) {
+    case 0: gen_helper_fadd_ST0_FT0(); break;
+    case 1: gen_helper_fmul_ST0_FT0(); break;
+    case 2: gen_helper_fcom_ST0_FT0(); break;
+    case 3: gen_helper_fcom_ST0_FT0(); break;
+    case 4: gen_helper_fsub_ST0_FT0(); break;
+    case 5: gen_helper_fsubr_ST0_FT0(); break;
+    case 6: gen_helper_fdiv_ST0_FT0(); break;
+    case 7: gen_helper_fdivr_ST0_FT0(); break;
+    }
+}
+
+/* NOTE the exception in "r" op ordering */
+static void gen_helper_fp_arith_STN_ST0(int op, int opreg)
+{
+    TCGv_i32 tmp = tcg_const_i32(opreg);
+    switch (op) {
+    case 0: gen_helper_fadd_STN_ST0(tmp); break;
+    case 1: gen_helper_fmul_STN_ST0(tmp); break;
+    case 4: gen_helper_fsubr_STN_ST0(tmp); break;
+    case 5: gen_helper_fsub_STN_ST0(tmp); break;
+    case 6: gen_helper_fdivr_STN_ST0(tmp); break;
+    case 7: gen_helper_fdiv_STN_ST0(tmp); break;
+    }
+}
+
+/* if d == OR_TMP0, it means memory operand (address in A0) */
+static void gen_op(DisasContext *s1, int op, int ot, int d)
+{
+    if (d != OR_TMP0) {
+        gen_op_mov_TN_reg(ot, 0, d);
+    } else {
+        gen_op_ld_T0_A0(ot + s1->mem_index);
+    }
+    switch(op) {
+    case OP_ADCL:
+        if (s1->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s1->cc_op);
+        gen_compute_eflags_c(cpu_tmp4);
+        tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
+        tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
+        tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
+        tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot);
+        s1->cc_op = CC_OP_DYNAMIC;
+        break;
+    case OP_SBBL:
+        if (s1->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s1->cc_op);
+        gen_compute_eflags_c(cpu_tmp4);
+        tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
+        tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
+        tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
+        tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot);
+        s1->cc_op = CC_OP_DYNAMIC;
+        break;
+    case OP_ADDL:
+        gen_op_addl_T0_T1();
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        gen_op_update2_cc();
+        s1->cc_op = CC_OP_ADDB + ot;
+        break;
+    case OP_SUBL:
+        tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        gen_op_update2_cc();
+        s1->cc_op = CC_OP_SUBB + ot;
+        break;
+    default:
+    case OP_ANDL:
+        tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        gen_op_update1_cc();
+        s1->cc_op = CC_OP_LOGICB + ot;
+        break;
+    case OP_ORL:
+        tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        gen_op_update1_cc();
+        s1->cc_op = CC_OP_LOGICB + ot;
+        break;
+    case OP_XORL:
+        tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        if (d != OR_TMP0)
+            gen_op_mov_reg_T0(ot, d);
+        else
+            gen_op_st_T0_A0(ot + s1->mem_index);
+        gen_op_update1_cc();
+        s1->cc_op = CC_OP_LOGICB + ot;
+        break;
+    case OP_CMPL:
+        gen_op_cmpl_T0_T1_cc();
+        s1->cc_op = CC_OP_SUBB + ot;
+        break;
+    }
+}
+
+/* if d == OR_TMP0, it means memory operand (address in A0) */
+static void gen_inc(DisasContext *s1, int ot, int d, int c)
+{
+    if (d != OR_TMP0)
+        gen_op_mov_TN_reg(ot, 0, d);
+    else
+        gen_op_ld_T0_A0(ot + s1->mem_index);
+    if (s1->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s1->cc_op);
+    if (c > 0) {
+        tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1);
+        s1->cc_op = CC_OP_INCB + ot;
+    } else {
+        tcg_gen_addi_tl(cpu_T[0], cpu_T[0], -1);
+        s1->cc_op = CC_OP_DECB + ot;
+    }
+    if (d != OR_TMP0)
+        gen_op_mov_reg_T0(ot, d);
+    else
+        gen_op_st_T0_A0(ot + s1->mem_index);
+    gen_compute_eflags_c(cpu_cc_src);
+    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+}
+
+static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, 
+                            int is_right, int is_arith)
+{
+    target_ulong mask;
+    int shift_label;
+    TCGv t0, t1;
+
+    if (ot == OT_QUAD)
+        mask = 0x3f;
+    else
+        mask = 0x1f;
+
+    /* load */
+    if (op1 == OR_TMP0)
+        gen_op_ld_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_TN_reg(ot, 0, op1);
+
+    tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
+
+    tcg_gen_addi_tl(cpu_tmp5, cpu_T[1], -1);
+
+    if (is_right) {
+        if (is_arith) {
+            gen_exts(ot, cpu_T[0]);
+            tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5);
+            tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        } else {
+            gen_extu(ot, cpu_T[0]);
+            tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5);
+            tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        }
+    } else {
+        tcg_gen_shl_tl(cpu_T3, cpu_T[0], cpu_tmp5);
+        tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+    }
+
+    /* store */
+    if (op1 == OR_TMP0)
+        gen_op_st_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_reg_T0(ot, op1);
+        
+    /* update eflags if non zero shift */
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+
+    /* XXX: inefficient */
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+
+    tcg_gen_mov_tl(t0, cpu_T[0]);
+    tcg_gen_mov_tl(t1, cpu_T3);
+
+    shift_label = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_T[1], 0, shift_label);
+
+    tcg_gen_mov_tl(cpu_cc_src, t1);
+    tcg_gen_mov_tl(cpu_cc_dst, t0);
+    if (is_right)
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
+    else
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
+        
+    gen_set_label(shift_label);
+    s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
+                            int is_right, int is_arith)
+{
+    int mask;
+    
+    if (ot == OT_QUAD)
+        mask = 0x3f;
+    else
+        mask = 0x1f;
+
+    /* load */
+    if (op1 == OR_TMP0)
+        gen_op_ld_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_TN_reg(ot, 0, op1);
+
+    op2 &= mask;
+    if (op2 != 0) {
+        if (is_right) {
+            if (is_arith) {
+                gen_exts(ot, cpu_T[0]);
+                tcg_gen_sari_tl(cpu_tmp4, cpu_T[0], op2 - 1);
+                tcg_gen_sari_tl(cpu_T[0], cpu_T[0], op2);
+            } else {
+                gen_extu(ot, cpu_T[0]);
+                tcg_gen_shri_tl(cpu_tmp4, cpu_T[0], op2 - 1);
+                tcg_gen_shri_tl(cpu_T[0], cpu_T[0], op2);
+            }
+        } else {
+            tcg_gen_shli_tl(cpu_tmp4, cpu_T[0], op2 - 1);
+            tcg_gen_shli_tl(cpu_T[0], cpu_T[0], op2);
+        }
+    }
+
+    /* store */
+    if (op1 == OR_TMP0)
+        gen_op_st_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_reg_T0(ot, op1);
+        
+    /* update eflags if non zero shift */
+    if (op2 != 0) {
+        tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
+        tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+        if (is_right)
+            s->cc_op = CC_OP_SARB + ot;
+        else
+            s->cc_op = CC_OP_SHLB + ot;
+    }
+}
+
+static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2)
+{
+    if (arg2 >= 0)
+        tcg_gen_shli_tl(ret, arg1, arg2);
+    else
+        tcg_gen_shri_tl(ret, arg1, -arg2);
+}
+
+static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, 
+                          int is_right)
+{
+    target_ulong mask;
+    int label1, label2, data_bits;
+    TCGv t0, t1, t2, a0;
+
+    /* XXX: inefficient, but we must use local temps */
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
+    a0 = tcg_temp_local_new();
+
+    if (ot == OT_QUAD)
+        mask = 0x3f;
+    else
+        mask = 0x1f;
+
+    /* load */
+    if (op1 == OR_TMP0) {
+        tcg_gen_mov_tl(a0, cpu_A0);
+        gen_op_ld_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_v_reg(ot, t0, op1);
+    }
+
+    tcg_gen_mov_tl(t1, cpu_T[1]);
+
+    tcg_gen_andi_tl(t1, t1, mask);
+
+    /* Must test zero case to avoid using undefined behaviour in TCG
+       shifts. */
+    label1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1);
+    
+    if (ot <= OT_WORD)
+        tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1);
+    else
+        tcg_gen_mov_tl(cpu_tmp0, t1);
+    
+    gen_extu(ot, t0);
+    tcg_gen_mov_tl(t2, t0);
+
+    data_bits = 8 << ot;
+    /* XXX: rely on behaviour of shifts when operand 2 overflows (XXX:
+       fix TCG definition) */
+    if (is_right) {
+        tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp0);
+        tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0);
+        tcg_gen_shl_tl(t0, t0, cpu_tmp0);
+    } else {
+        tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp0);
+        tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0);
+        tcg_gen_shr_tl(t0, t0, cpu_tmp0);
+    }
+    tcg_gen_or_tl(t0, t0, cpu_tmp4);
+
+    gen_set_label(label1);
+    /* store */
+    if (op1 == OR_TMP0) {
+        gen_op_st_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_reg_v(ot, op1, t0);
+    }
+    
+    /* update eflags */
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+
+    label2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2);
+
+    gen_compute_eflags(cpu_cc_src);
+    tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
+    tcg_gen_xor_tl(cpu_tmp0, t2, t0);
+    tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
+    tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
+    tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+    if (is_right) {
+        tcg_gen_shri_tl(t0, t0, data_bits - 1);
+    }
+    tcg_gen_andi_tl(t0, t0, CC_C);
+    tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
+    
+    tcg_gen_discard_tl(cpu_cc_dst);
+    tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
+        
+    gen_set_label(label2);
+    s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(a0);
+}
+
+static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2,
+                          int is_right)
+{
+    int mask;
+    int data_bits;
+    TCGv t0, t1, a0;
+
+    /* XXX: inefficient, but we must use local temps */
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    a0 = tcg_temp_local_new();
+
+    if (ot == OT_QUAD)
+        mask = 0x3f;
+    else
+        mask = 0x1f;
+
+    /* load */
+    if (op1 == OR_TMP0) {
+        tcg_gen_mov_tl(a0, cpu_A0);
+        gen_op_ld_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_v_reg(ot, t0, op1);
+    }
+
+    gen_extu(ot, t0);
+    tcg_gen_mov_tl(t1, t0);
+
+    op2 &= mask;
+    data_bits = 8 << ot;
+    if (op2 != 0) {
+        int shift = op2 & ((1 << (3 + ot)) - 1);
+        if (is_right) {
+            tcg_gen_shri_tl(cpu_tmp4, t0, shift);
+            tcg_gen_shli_tl(t0, t0, data_bits - shift);
+        }
+        else {
+            tcg_gen_shli_tl(cpu_tmp4, t0, shift);
+            tcg_gen_shri_tl(t0, t0, data_bits - shift);
+        }
+        tcg_gen_or_tl(t0, t0, cpu_tmp4);
+    }
+
+    /* store */
+    if (op1 == OR_TMP0) {
+        gen_op_st_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_reg_v(ot, op1, t0);
+    }
+
+    if (op2 != 0) {
+        /* update eflags */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+
+        gen_compute_eflags(cpu_cc_src);
+        tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
+        tcg_gen_xor_tl(cpu_tmp0, t1, t0);
+        tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
+        tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
+        tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+        if (is_right) {
+            tcg_gen_shri_tl(t0, t0, data_bits - 1);
+        }
+        tcg_gen_andi_tl(t0, t0, CC_C);
+        tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
+
+        tcg_gen_discard_tl(cpu_cc_dst);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
+        s->cc_op = CC_OP_EFLAGS;
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(a0);
+}
+
+/* XXX: add faster immediate = 1 case */
+static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, 
+                           int is_right)
+{
+    int label1;
+
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+
+    /* load */
+    if (op1 == OR_TMP0)
+        gen_op_ld_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_TN_reg(ot, 0, op1);
+    
+    if (is_right) {
+        switch (ot) {
+        case 0: gen_helper_rcrb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+        case 1: gen_helper_rcrw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+        case 2: gen_helper_rcrl(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+#ifdef TARGET_X86_64
+        case 3: gen_helper_rcrq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+#endif
+        }
+    } else {
+        switch (ot) {
+        case 0: gen_helper_rclb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+        case 1: gen_helper_rclw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+        case 2: gen_helper_rcll(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+#ifdef TARGET_X86_64
+        case 3: gen_helper_rclq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+#endif
+        }
+    }
+    /* store */
+    if (op1 == OR_TMP0)
+        gen_op_st_T0_A0(ot + s->mem_index);
+    else
+        gen_op_mov_reg_T0(ot, op1);
+
+    /* update eflags */
+    label1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_tmp, -1, label1);
+
+    tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp);
+    tcg_gen_discard_tl(cpu_cc_dst);
+    tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
+        
+    gen_set_label(label1);
+    s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
+}
+
+/* XXX: add faster immediate case */
+static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, 
+                                int is_right)
+{
+    int label1, label2, data_bits;
+    target_ulong mask;
+    TCGv t0, t1, t2, a0;
+
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
+    a0 = tcg_temp_local_new();
+
+    if (ot == OT_QUAD)
+        mask = 0x3f;
+    else
+        mask = 0x1f;
+
+    /* load */
+    if (op1 == OR_TMP0) {
+        tcg_gen_mov_tl(a0, cpu_A0);
+        gen_op_ld_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_v_reg(ot, t0, op1);
+    }
+
+    tcg_gen_andi_tl(cpu_T3, cpu_T3, mask);
+
+    tcg_gen_mov_tl(t1, cpu_T[1]);
+    tcg_gen_mov_tl(t2, cpu_T3);
+
+    /* Must test zero case to avoid using undefined behaviour in TCG
+       shifts. */
+    label1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
+    
+    tcg_gen_addi_tl(cpu_tmp5, t2, -1);
+    if (ot == OT_WORD) {
+        /* Note: we implement the Intel behaviour for shift count > 16 */
+        if (is_right) {
+            tcg_gen_andi_tl(t0, t0, 0xffff);
+            tcg_gen_shli_tl(cpu_tmp0, t1, 16);
+            tcg_gen_or_tl(t0, t0, cpu_tmp0);
+            tcg_gen_ext32u_tl(t0, t0);
+
+            tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
+            
+            /* only needed if count > 16, but a test would complicate */
+            tcg_gen_subfi_tl(cpu_tmp5, 32, t2);
+            tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5);
+
+            tcg_gen_shr_tl(t0, t0, t2);
+
+            tcg_gen_or_tl(t0, t0, cpu_tmp0);
+        } else {
+            /* XXX: not optimal */
+            tcg_gen_andi_tl(t0, t0, 0xffff);
+            tcg_gen_shli_tl(t1, t1, 16);
+            tcg_gen_or_tl(t1, t1, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            
+            tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
+            tcg_gen_subfi_tl(cpu_tmp0, 32, cpu_tmp5);
+            tcg_gen_shr_tl(cpu_tmp5, t1, cpu_tmp0);
+            tcg_gen_or_tl(cpu_tmp4, cpu_tmp4, cpu_tmp5);
+
+            tcg_gen_shl_tl(t0, t0, t2);
+            tcg_gen_subfi_tl(cpu_tmp5, 32, t2);
+            tcg_gen_shr_tl(t1, t1, cpu_tmp5);
+            tcg_gen_or_tl(t0, t0, t1);
+        }
+    } else {
+        data_bits = 8 << ot;
+        if (is_right) {
+            if (ot == OT_LONG)
+                tcg_gen_ext32u_tl(t0, t0);
+
+            tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
+
+            tcg_gen_shr_tl(t0, t0, t2);
+            tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
+            tcg_gen_shl_tl(t1, t1, cpu_tmp5);
+            tcg_gen_or_tl(t0, t0, t1);
+            
+        } else {
+            if (ot == OT_LONG)
+                tcg_gen_ext32u_tl(t1, t1);
+
+            tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
+            
+            tcg_gen_shl_tl(t0, t0, t2);
+            tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2);
+            tcg_gen_shr_tl(t1, t1, cpu_tmp5);
+            tcg_gen_or_tl(t0, t0, t1);
+        }
+    }
+    tcg_gen_mov_tl(t1, cpu_tmp4);
+
+    gen_set_label(label1);
+    /* store */
+    if (op1 == OR_TMP0) {
+        gen_op_st_v(ot + s->mem_index, t0, a0);
+    } else {
+        gen_op_mov_reg_v(ot, op1, t0);
+    }
+    
+    /* update eflags */
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+
+    label2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2);
+
+    tcg_gen_mov_tl(cpu_cc_src, t1);
+    tcg_gen_mov_tl(cpu_cc_dst, t0);
+    if (is_right) {
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
+    } else {
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
+    }
+    gen_set_label(label2);
+    s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(a0);
+}
+
+static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
+{
+    if (s != OR_TMP1)
+        gen_op_mov_TN_reg(ot, 1, s);
+    switch(op) {
+    case OP_ROL:
+        gen_rot_rm_T1(s1, ot, d, 0);
+        break;
+    case OP_ROR:
+        gen_rot_rm_T1(s1, ot, d, 1);
+        break;
+    case OP_SHL:
+    case OP_SHL1:
+        gen_shift_rm_T1(s1, ot, d, 0, 0);
+        break;
+    case OP_SHR:
+        gen_shift_rm_T1(s1, ot, d, 1, 0);
+        break;
+    case OP_SAR:
+        gen_shift_rm_T1(s1, ot, d, 1, 1);
+        break;
+    case OP_RCL:
+        gen_rotc_rm_T1(s1, ot, d, 0);
+        break;
+    case OP_RCR:
+        gen_rotc_rm_T1(s1, ot, d, 1);
+        break;
+    }
+}
+
+static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
+{
+    switch(op) {
+    case OP_ROL:
+        gen_rot_rm_im(s1, ot, d, c, 0);
+        break;
+    case OP_ROR:
+        gen_rot_rm_im(s1, ot, d, c, 1);
+        break;
+    case OP_SHL:
+    case OP_SHL1:
+        gen_shift_rm_im(s1, ot, d, c, 0, 0);
+        break;
+    case OP_SHR:
+        gen_shift_rm_im(s1, ot, d, c, 1, 0);
+        break;
+    case OP_SAR:
+        gen_shift_rm_im(s1, ot, d, c, 1, 1);
+        break;
+    default:
+        /* currently not optimized */
+        gen_op_movl_T1_im(c);
+        gen_shift(s1, op, ot, d, OR_TMP1);
+        break;
+    }
+}
+
+static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
+{
+    target_long disp;
+    int havesib;
+    int base;
+    int index;
+    int scale;
+    int opreg;
+    int mod, rm, code, override, must_add_seg;
+
+    override = s->override;
+    must_add_seg = s->addseg;
+    if (override >= 0)
+        must_add_seg = 1;
+    mod = (modrm >> 6) & 3;
+    rm = modrm & 7;
+
+    if (s->aflag) {
+
+        havesib = 0;
+        base = rm;
+        index = 0;
+        scale = 0;
+
+        if (base == 4) {
+            havesib = 1;
+            code = ldub_code(s->pc++);
+            scale = (code >> 6) & 3;
+            index = ((code >> 3) & 7) | REX_X(s);
+            base = (code & 7);
+        }
+        base |= REX_B(s);
+
+        switch (mod) {
+        case 0:
+            if ((base & 7) == 5) {
+                base = -1;
+                disp = (int32_t)ldl_code(s->pc);
+                s->pc += 4;
+                if (CODE64(s) && !havesib) {
+                    disp += s->pc + s->rip_offset;
+                }
+            } else {
+                disp = 0;
+            }
+            break;
+        case 1:
+            disp = (int8_t)ldub_code(s->pc++);
+            break;
+        default:
+        case 2:
+            disp = (int32_t)ldl_code(s->pc);
+            s->pc += 4;
+            break;
+        }
+
+        if (base >= 0) {
+            /* for correct popl handling with esp */
+            if (base == 4 && s->popl_esp_hack)
+                disp += s->popl_esp_hack;
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                gen_op_movq_A0_reg(base);
+                if (disp != 0) {
+                    gen_op_addq_A0_im(disp);
+                }
+            } else
+#endif
+            {
+                gen_op_movl_A0_reg(base);
+                if (disp != 0)
+                    gen_op_addl_A0_im(disp);
+            }
+        } else {
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                gen_op_movq_A0_im(disp);
+            } else
+#endif
+            {
+                gen_op_movl_A0_im(disp);
+            }
+        }
+        /* index == 4 means no index */
+        if (havesib && (index != 4)) {
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                gen_op_addq_A0_reg_sN(scale, index);
+            } else
+#endif
+            {
+                gen_op_addl_A0_reg_sN(scale, index);
+            }
+        }
+        if (must_add_seg) {
+            if (override < 0) {
+                if (base == R_EBP || base == R_ESP)
+                    override = R_SS;
+                else
+                    override = R_DS;
+            }
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                gen_op_addq_A0_seg(override);
+            } else
+#endif
+            {
+                gen_op_addl_A0_seg(override);
+            }
+        }
+    } else {
+        switch (mod) {
+        case 0:
+            if (rm == 6) {
+                disp = lduw_code(s->pc);
+                s->pc += 2;
+                gen_op_movl_A0_im(disp);
+                rm = 0; /* avoid SS override */
+                goto no_rm;
+            } else {
+                disp = 0;
+            }
+            break;
+        case 1:
+            disp = (int8_t)ldub_code(s->pc++);
+            break;
+        default:
+        case 2:
+            disp = lduw_code(s->pc);
+            s->pc += 2;
+            break;
+        }
+        switch(rm) {
+        case 0:
+            gen_op_movl_A0_reg(R_EBX);
+            gen_op_addl_A0_reg_sN(0, R_ESI);
+            break;
+        case 1:
+            gen_op_movl_A0_reg(R_EBX);
+            gen_op_addl_A0_reg_sN(0, R_EDI);
+            break;
+        case 2:
+            gen_op_movl_A0_reg(R_EBP);
+            gen_op_addl_A0_reg_sN(0, R_ESI);
+            break;
+        case 3:
+            gen_op_movl_A0_reg(R_EBP);
+            gen_op_addl_A0_reg_sN(0, R_EDI);
+            break;
+        case 4:
+            gen_op_movl_A0_reg(R_ESI);
+            break;
+        case 5:
+            gen_op_movl_A0_reg(R_EDI);
+            break;
+        case 6:
+            gen_op_movl_A0_reg(R_EBP);
+            break;
+        default:
+        case 7:
+            gen_op_movl_A0_reg(R_EBX);
+            break;
+        }
+        if (disp != 0)
+            gen_op_addl_A0_im(disp);
+        gen_op_andl_A0_ffff();
+    no_rm:
+        if (must_add_seg) {
+            if (override < 0) {
+                if (rm == 2 || rm == 3 || rm == 6)
+                    override = R_SS;
+                else
+                    override = R_DS;
+            }
+            gen_op_addl_A0_seg(override);
+        }
+    }
+
+    opreg = OR_A0;
+    disp = 0;
+    *reg_ptr = opreg;
+    *offset_ptr = disp;
+}
+
+static void gen_nop_modrm(DisasContext *s, int modrm)
+{
+    int mod, rm, base, code;
+
+    mod = (modrm >> 6) & 3;
+    if (mod == 3)
+        return;
+    rm = modrm & 7;
+
+    if (s->aflag) {
+
+        base = rm;
+
+        if (base == 4) {
+            code = ldub_code(s->pc++);
+            base = (code & 7);
+        }
+
+        switch (mod) {
+        case 0:
+            if (base == 5) {
+                s->pc += 4;
+            }
+            break;
+        case 1:
+            s->pc++;
+            break;
+        default:
+        case 2:
+            s->pc += 4;
+            break;
+        }
+    } else {
+        switch (mod) {
+        case 0:
+            if (rm == 6) {
+                s->pc += 2;
+            }
+            break;
+        case 1:
+            s->pc++;
+            break;
+        default:
+        case 2:
+            s->pc += 2;
+            break;
+        }
+    }
+}
+
+/* used for LEA and MOV AX, mem */
+static void gen_add_A0_ds_seg(DisasContext *s)
+{
+    int override, must_add_seg;
+    must_add_seg = s->addseg;
+    override = R_DS;
+    if (s->override >= 0) {
+        override = s->override;
+        must_add_seg = 1;
+    }
+    if (must_add_seg) {
+#ifdef TARGET_X86_64
+        if (CODE64(s)) {
+            gen_op_addq_A0_seg(override);
+        } else
+#endif
+        {
+            gen_op_addl_A0_seg(override);
+        }
+    }
+}
+
+/* generate modrm memory load or store of 'reg'. TMP0 is used if reg ==
+   OR_TMP0 */
+static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
+{
+    int mod, rm, opreg, disp;
+
+    mod = (modrm >> 6) & 3;
+    rm = (modrm & 7) | REX_B(s);
+    if (mod == 3) {
+        if (is_store) {
+            if (reg != OR_TMP0)
+                gen_op_mov_TN_reg(ot, 0, reg);
+            gen_op_mov_reg_T0(ot, rm);
+        } else {
+            gen_op_mov_TN_reg(ot, 0, rm);
+            if (reg != OR_TMP0)
+                gen_op_mov_reg_T0(ot, reg);
+        }
+    } else {
+        gen_lea_modrm(s, modrm, &opreg, &disp);
+        if (is_store) {
+            if (reg != OR_TMP0)
+                gen_op_mov_TN_reg(ot, 0, reg);
+            gen_op_st_T0_A0(ot + s->mem_index);
+        } else {
+            gen_op_ld_T0_A0(ot + s->mem_index);
+            if (reg != OR_TMP0)
+                gen_op_mov_reg_T0(ot, reg);
+        }
+    }
+}
+
+static inline uint32_t insn_get(DisasContext *s, int ot)
+{
+    uint32_t ret;
+
+    switch(ot) {
+    case OT_BYTE:
+        ret = ldub_code(s->pc);
+        s->pc++;
+        break;
+    case OT_WORD:
+        ret = lduw_code(s->pc);
+        s->pc += 2;
+        break;
+    default:
+    case OT_LONG:
+        ret = ldl_code(s->pc);
+        s->pc += 4;
+        break;
+    }
+    return ret;
+}
+
+static inline int insn_const_size(unsigned int ot)
+{
+    if (ot <= OT_LONG)
+        return 1 << ot;
+    else
+        return 4;
+}
+
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
+{
+    TranslationBlock *tb;
+    target_ulong pc;
+
+    pc = s->cs_base + eip;
+    tb = s->tb;
+    /* NOTE: we handle the case where the TB spans two pages here */
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
+        (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
+        /* jump to same page: we can use a direct jump */
+        tcg_gen_goto_tb(tb_num);
+        gen_jmp_im(eip);
+        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
+    } else {
+        /* jump to another page: currently not optimized */
+        gen_jmp_im(eip);
+        gen_eob(s);
+    }
+}
+
+static inline void gen_jcc(DisasContext *s, int b,
+                           target_ulong val, target_ulong next_eip)
+{
+    int l1, l2, cc_op;
+
+    cc_op = s->cc_op;
+    gen_update_cc_op(s);
+    if (s->jmp_opt) {
+        l1 = gen_new_label();
+        gen_jcc1(s, cc_op, b, l1);
+        
+        gen_goto_tb(s, 0, next_eip);
+
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, val);
+        s->is_jmp = DISAS_TB_JUMP;
+    } else {
+
+        l1 = gen_new_label();
+        l2 = gen_new_label();
+        gen_jcc1(s, cc_op, b, l1);
+
+        gen_jmp_im(next_eip);
+        tcg_gen_br(l2);
+
+        gen_set_label(l1);
+        gen_jmp_im(val);
+        gen_set_label(l2);
+        gen_eob(s);
+    }
+}
+
+static void gen_setcc(DisasContext *s, int b)
+{
+    int inv, jcc_op, l1;
+    TCGv t0;
+
+    if (is_fast_jcc_case(s, b)) {
+        /* nominal case: we use a jump */
+        /* XXX: make it faster by adding new instructions in TCG */
+        t0 = tcg_temp_local_new();
+        tcg_gen_movi_tl(t0, 0);
+        l1 = gen_new_label();
+        gen_jcc1(s, s->cc_op, b ^ 1, l1);
+        tcg_gen_movi_tl(t0, 1);
+        gen_set_label(l1);
+        tcg_gen_mov_tl(cpu_T[0], t0);
+        tcg_temp_free(t0);
+    } else {
+        /* slow case: it is more efficient not to generate a jump,
+           although it is questionnable whether this optimization is
+           worth to */
+        inv = b & 1;
+        jcc_op = (b >> 1) & 7;
+        gen_setcc_slow_T0(s, jcc_op);
+        if (inv) {
+            tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1);
+        }
+    }
+}
+
+static inline void gen_op_movl_T0_seg(int seg_reg)
+{
+    tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
+                     offsetof(CPUX86State,segs[seg_reg].selector));
+}
+
+static inline void gen_op_movl_seg_T0_vm(int seg_reg)
+{
+    tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff);
+    tcg_gen_st32_tl(cpu_T[0], cpu_env, 
+                    offsetof(CPUX86State,segs[seg_reg].selector));
+    tcg_gen_shli_tl(cpu_T[0], cpu_T[0], 4);
+    tcg_gen_st_tl(cpu_T[0], cpu_env, 
+                  offsetof(CPUX86State,segs[seg_reg].base));
+}
+
+/* move T0 to seg_reg and compute if the CPU state may change. Never
+   call this function with seg_reg == R_CS */
+static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip)
+{
+    if (s->pe && !s->vm86) {
+        /* XXX: optimize by finding processor state dynamically */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(cur_eip);
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        gen_helper_load_seg(tcg_const_i32(seg_reg), cpu_tmp2_i32);
+        /* abort translation because the addseg value may change or
+           because ss32 may change. For R_SS, translation must always
+           stop as a special handling must be done to disable hardware
+           interrupts for the next instruction */
+        if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
+            s->is_jmp = DISAS_TB_JUMP;
+    } else {
+        gen_op_movl_seg_T0_vm(seg_reg);
+        if (seg_reg == R_SS)
+            s->is_jmp = DISAS_TB_JUMP;
+    }
+}
+
+static inline int svm_is_rep(int prefixes)
+{
+    return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
+}
+
+static inline void
+gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
+                              uint32_t type, uint64_t param)
+{
+    /* no SVM activated; fast case */
+    if (likely(!(s->flags & HF_SVMI_MASK)))
+        return;
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_jmp_im(pc_start - s->cs_base);
+    gen_helper_svm_check_intercept_param(tcg_const_i32(type),
+                                         tcg_const_i64(param));
+}
+
+static inline void
+gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type)
+{
+    gen_svm_check_intercept_param(s, pc_start, type, 0);
+}
+
+static inline void gen_stack_update(DisasContext *s, int addend)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        gen_op_add_reg_im(2, R_ESP, addend);
+    } else
+#endif
+    if (s->ss32) {
+        gen_op_add_reg_im(1, R_ESP, addend);
+    } else {
+        gen_op_add_reg_im(0, R_ESP, addend);
+    }
+}
+
+/* generate a push. It depends on ss32, addseg and dflag */
+static void gen_push_T0(DisasContext *s)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        gen_op_movq_A0_reg(R_ESP);
+        if (s->dflag) {
+            gen_op_addq_A0_im(-8);
+            gen_op_st_T0_A0(OT_QUAD + s->mem_index);
+        } else {
+            gen_op_addq_A0_im(-2);
+            gen_op_st_T0_A0(OT_WORD + s->mem_index);
+        }
+        gen_op_mov_reg_A0(2, R_ESP);
+    } else
+#endif
+    {
+        gen_op_movl_A0_reg(R_ESP);
+        if (!s->dflag)
+            gen_op_addl_A0_im(-2);
+        else
+            gen_op_addl_A0_im(-4);
+        if (s->ss32) {
+            if (s->addseg) {
+                tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+                gen_op_addl_A0_seg(R_SS);
+            }
+        } else {
+            gen_op_andl_A0_ffff();
+            tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+            gen_op_addl_A0_seg(R_SS);
+        }
+        gen_op_st_T0_A0(s->dflag + 1 + s->mem_index);
+        if (s->ss32 && !s->addseg)
+            gen_op_mov_reg_A0(1, R_ESP);
+        else
+            gen_op_mov_reg_T1(s->ss32 + 1, R_ESP);
+    }
+}
+
+/* generate a push. It depends on ss32, addseg and dflag */
+/* slower version for T1, only used for call Ev */
+static void gen_push_T1(DisasContext *s)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        gen_op_movq_A0_reg(R_ESP);
+        if (s->dflag) {
+            gen_op_addq_A0_im(-8);
+            gen_op_st_T1_A0(OT_QUAD + s->mem_index);
+        } else {
+            gen_op_addq_A0_im(-2);
+            gen_op_st_T0_A0(OT_WORD + s->mem_index);
+        }
+        gen_op_mov_reg_A0(2, R_ESP);
+    } else
+#endif
+    {
+        gen_op_movl_A0_reg(R_ESP);
+        if (!s->dflag)
+            gen_op_addl_A0_im(-2);
+        else
+            gen_op_addl_A0_im(-4);
+        if (s->ss32) {
+            if (s->addseg) {
+                gen_op_addl_A0_seg(R_SS);
+            }
+        } else {
+            gen_op_andl_A0_ffff();
+            gen_op_addl_A0_seg(R_SS);
+        }
+        gen_op_st_T1_A0(s->dflag + 1 + s->mem_index);
+
+        if (s->ss32 && !s->addseg)
+            gen_op_mov_reg_A0(1, R_ESP);
+        else
+            gen_stack_update(s, (-2) << s->dflag);
+    }
+}
+
+/* two step pop is necessary for precise exceptions */
+static void gen_pop_T0(DisasContext *s)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        gen_op_movq_A0_reg(R_ESP);
+        gen_op_ld_T0_A0((s->dflag ? OT_QUAD : OT_WORD) + s->mem_index);
+    } else
+#endif
+    {
+        gen_op_movl_A0_reg(R_ESP);
+        if (s->ss32) {
+            if (s->addseg)
+                gen_op_addl_A0_seg(R_SS);
+        } else {
+            gen_op_andl_A0_ffff();
+            gen_op_addl_A0_seg(R_SS);
+        }
+        gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index);
+    }
+}
+
+static void gen_pop_update(DisasContext *s)
+{
+#ifdef TARGET_X86_64
+    if (CODE64(s) && s->dflag) {
+        gen_stack_update(s, 8);
+    } else
+#endif
+    {
+        gen_stack_update(s, 2 << s->dflag);
+    }
+}
+
+static void gen_stack_A0(DisasContext *s)
+{
+    gen_op_movl_A0_reg(R_ESP);
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+    if (s->addseg)
+        gen_op_addl_A0_seg(R_SS);
+}
+
+/* NOTE: wrap around in 16 bit not fully handled */
+static void gen_pusha(DisasContext *s)
+{
+    int i;
+    gen_op_movl_A0_reg(R_ESP);
+    gen_op_addl_A0_im(-16 <<  s->dflag);
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+    if (s->addseg)
+        gen_op_addl_A0_seg(R_SS);
+    for(i = 0;i < 8; i++) {
+        gen_op_mov_TN_reg(OT_LONG, 0, 7 - i);
+        gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index);
+        gen_op_addl_A0_im(2 <<  s->dflag);
+    }
+    gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
+}
+
+/* NOTE: wrap around in 16 bit not fully handled */
+static void gen_popa(DisasContext *s)
+{
+    int i;
+    gen_op_movl_A0_reg(R_ESP);
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+    tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 <<  s->dflag);
+    if (s->addseg)
+        gen_op_addl_A0_seg(R_SS);
+    for(i = 0;i < 8; i++) {
+        /* ESP is not reloaded */
+        if (i != 3) {
+            gen_op_ld_T0_A0(OT_WORD + s->dflag + s->mem_index);
+            gen_op_mov_reg_T0(OT_WORD + s->dflag, 7 - i);
+        }
+        gen_op_addl_A0_im(2 <<  s->dflag);
+    }
+    gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
+}
+
+static void gen_enter(DisasContext *s, int esp_addend, int level)
+{
+    int ot, opsize;
+
+    level &= 0x1f;
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        ot = s->dflag ? OT_QUAD : OT_WORD;
+        opsize = 1 << ot;
+
+        gen_op_movl_A0_reg(R_ESP);
+        gen_op_addq_A0_im(-opsize);
+        tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+
+        /* push bp */
+        gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
+        gen_op_st_T0_A0(ot + s->mem_index);
+        if (level) {
+            /* XXX: must save state */
+            gen_helper_enter64_level(tcg_const_i32(level),
+                                     tcg_const_i32((ot == OT_QUAD)),
+                                     cpu_T[1]);
+        }
+        gen_op_mov_reg_T1(ot, R_EBP);
+        tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level));
+        gen_op_mov_reg_T1(OT_QUAD, R_ESP);
+    } else
+#endif
+    {
+        ot = s->dflag + OT_WORD;
+        opsize = 2 << s->dflag;
+
+        gen_op_movl_A0_reg(R_ESP);
+        gen_op_addl_A0_im(-opsize);
+        if (!s->ss32)
+            gen_op_andl_A0_ffff();
+        tcg_gen_mov_tl(cpu_T[1], cpu_A0);
+        if (s->addseg)
+            gen_op_addl_A0_seg(R_SS);
+        /* push bp */
+        gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
+        gen_op_st_T0_A0(ot + s->mem_index);
+        if (level) {
+            /* XXX: must save state */
+            gen_helper_enter_level(tcg_const_i32(level),
+                                   tcg_const_i32(s->dflag),
+                                   cpu_T[1]);
+        }
+        gen_op_mov_reg_T1(ot, R_EBP);
+        tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level));
+        gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
+    }
+}
+
+static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_jmp_im(cur_eip);
+    gen_helper_raise_exception(tcg_const_i32(trapno));
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+/* an interrupt is different from an exception because of the
+   privilege checks */
+static void gen_interrupt(DisasContext *s, int intno,
+                          target_ulong cur_eip, target_ulong next_eip)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_jmp_im(cur_eip);
+    gen_helper_raise_interrupt(tcg_const_i32(intno), 
+                               tcg_const_i32(next_eip - cur_eip));
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+static void gen_debug(DisasContext *s, target_ulong cur_eip)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_jmp_im(cur_eip);
+    gen_helper_debug();
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+/* generate a generic end of block. Trace exception is also generated
+   if needed */
+static void gen_eob(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
+        gen_helper_reset_inhibit_irq();
+    }
+    if (s->tb->flags & HF_RF_MASK) {
+        gen_helper_reset_rf();
+    }
+    if (s->singlestep_enabled) {
+        gen_helper_debug();
+    } else if (s->tf) {
+	gen_helper_single_step();
+    } else {
+        tcg_gen_exit_tb(0);
+    }
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+/* generate a jump to eip. No segment change must happen before as a
+   direct call to the next block may occur */
+static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
+{
+    if (s->jmp_opt) {
+        gen_update_cc_op(s);
+        gen_goto_tb(s, tb_num, eip);
+        s->is_jmp = DISAS_TB_JUMP;
+    } else {
+        gen_jmp_im(eip);
+        gen_eob(s);
+    }
+}
+
+static void gen_jmp(DisasContext *s, target_ulong eip)
+{
+    gen_jmp_tb(s, eip, 0);
+}
+
+static inline void gen_ldq_env_A0(int idx, int offset)
+{
+    int mem_index = (idx >> 2) - 1;
+    tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset);
+}
+
+static inline void gen_stq_env_A0(int idx, int offset)
+{
+    int mem_index = (idx >> 2) - 1;
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset);
+    tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index);
+}
+
+static inline void gen_ldo_env_A0(int idx, int offset)
+{
+    int mem_index = (idx >> 2) - 1;
+    tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0)));
+    tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8);
+    tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_tmp0, mem_index);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1)));
+}
+
+static inline void gen_sto_env_A0(int idx, int offset)
+{
+    int mem_index = (idx >> 2) - 1;
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0)));
+    tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index);
+    tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8);
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1)));
+    tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_tmp0, mem_index);
+}
+
+static inline void gen_op_movo(int d_offset, int s_offset)
+{
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset + 8);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset + 8);
+}
+
+static inline void gen_op_movq(int d_offset, int s_offset)
+{
+    tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
+}
+
+static inline void gen_op_movl(int d_offset, int s_offset)
+{
+    tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, s_offset);
+    tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, d_offset);
+}
+
+static inline void gen_op_movq_env_0(int d_offset)
+{
+    tcg_gen_movi_i64(cpu_tmp1_i64, 0);
+    tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
+}
+
+#define SSE_SPECIAL ((void *)1)
+#define SSE_DUMMY ((void *)2)
+
+#define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm }
+#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
+                     gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
+
+static void *sse_op_table1[256][4] = {
+    /* 3DNow! extensions */
+    [0x0e] = { SSE_DUMMY }, /* femms */
+    [0x0f] = { SSE_DUMMY }, /* pf... */
+    /* pure SSE operations */
+    [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
+    [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
+    [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */
+    [0x13] = { SSE_SPECIAL, SSE_SPECIAL },  /* movlps, movlpd */
+    [0x14] = { gen_helper_punpckldq_xmm, gen_helper_punpcklqdq_xmm },
+    [0x15] = { gen_helper_punpckhdq_xmm, gen_helper_punpckhqdq_xmm },
+    [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },  /* movhps, movhpd, movshdup */
+    [0x17] = { SSE_SPECIAL, SSE_SPECIAL },  /* movhps, movhpd */
+
+    [0x28] = { SSE_SPECIAL, SSE_SPECIAL },  /* movaps, movapd */
+    [0x29] = { SSE_SPECIAL, SSE_SPECIAL },  /* movaps, movapd */
+    [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */
+    [0x2b] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd, movntss, movntsd */
+    [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */
+    [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */
+    [0x2e] = { gen_helper_ucomiss, gen_helper_ucomisd },
+    [0x2f] = { gen_helper_comiss, gen_helper_comisd },
+    [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */
+    [0x51] = SSE_FOP(sqrt),
+    [0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL },
+    [0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL },
+    [0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */
+    [0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd */
+    [0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */
+    [0x57] = { gen_helper_pxor_xmm, gen_helper_pxor_xmm }, /* xorps, xorpd */
+    [0x58] = SSE_FOP(add),
+    [0x59] = SSE_FOP(mul),
+    [0x5a] = { gen_helper_cvtps2pd, gen_helper_cvtpd2ps,
+               gen_helper_cvtss2sd, gen_helper_cvtsd2ss },
+    [0x5b] = { gen_helper_cvtdq2ps, gen_helper_cvtps2dq, gen_helper_cvttps2dq },
+    [0x5c] = SSE_FOP(sub),
+    [0x5d] = SSE_FOP(min),
+    [0x5e] = SSE_FOP(div),
+    [0x5f] = SSE_FOP(max),
+
+    [0xc2] = SSE_FOP(cmpeq),
+    [0xc6] = { gen_helper_shufps, gen_helper_shufpd },
+
+    [0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */
+    [0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */
+
+    /* MMX ops and their SSE extensions */
+    [0x60] = MMX_OP2(punpcklbw),
+    [0x61] = MMX_OP2(punpcklwd),
+    [0x62] = MMX_OP2(punpckldq),
+    [0x63] = MMX_OP2(packsswb),
+    [0x64] = MMX_OP2(pcmpgtb),
+    [0x65] = MMX_OP2(pcmpgtw),
+    [0x66] = MMX_OP2(pcmpgtl),
+    [0x67] = MMX_OP2(packuswb),
+    [0x68] = MMX_OP2(punpckhbw),
+    [0x69] = MMX_OP2(punpckhwd),
+    [0x6a] = MMX_OP2(punpckhdq),
+    [0x6b] = MMX_OP2(packssdw),
+    [0x6c] = { NULL, gen_helper_punpcklqdq_xmm },
+    [0x6d] = { NULL, gen_helper_punpckhqdq_xmm },
+    [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
+    [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
+    [0x70] = { gen_helper_pshufw_mmx,
+               gen_helper_pshufd_xmm,
+               gen_helper_pshufhw_xmm,
+               gen_helper_pshuflw_xmm },
+    [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
+    [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
+    [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
+    [0x74] = MMX_OP2(pcmpeqb),
+    [0x75] = MMX_OP2(pcmpeqw),
+    [0x76] = MMX_OP2(pcmpeql),
+    [0x77] = { SSE_DUMMY }, /* emms */
+    [0x78] = { NULL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* extrq_i, insertq_i */
+    [0x79] = { NULL, gen_helper_extrq_r, NULL, gen_helper_insertq_r },
+    [0x7c] = { NULL, gen_helper_haddpd, NULL, gen_helper_haddps },
+    [0x7d] = { NULL, gen_helper_hsubpd, NULL, gen_helper_hsubps },
+    [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */
+    [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */
+    [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */
+    [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */
+    [0xd0] = { NULL, gen_helper_addsubpd, NULL, gen_helper_addsubps },
+    [0xd1] = MMX_OP2(psrlw),
+    [0xd2] = MMX_OP2(psrld),
+    [0xd3] = MMX_OP2(psrlq),
+    [0xd4] = MMX_OP2(paddq),
+    [0xd5] = MMX_OP2(pmullw),
+    [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
+    [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */
+    [0xd8] = MMX_OP2(psubusb),
+    [0xd9] = MMX_OP2(psubusw),
+    [0xda] = MMX_OP2(pminub),
+    [0xdb] = MMX_OP2(pand),
+    [0xdc] = MMX_OP2(paddusb),
+    [0xdd] = MMX_OP2(paddusw),
+    [0xde] = MMX_OP2(pmaxub),
+    [0xdf] = MMX_OP2(pandn),
+    [0xe0] = MMX_OP2(pavgb),
+    [0xe1] = MMX_OP2(psraw),
+    [0xe2] = MMX_OP2(psrad),
+    [0xe3] = MMX_OP2(pavgw),
+    [0xe4] = MMX_OP2(pmulhuw),
+    [0xe5] = MMX_OP2(pmulhw),
+    [0xe6] = { NULL, gen_helper_cvttpd2dq, gen_helper_cvtdq2pd, gen_helper_cvtpd2dq },
+    [0xe7] = { SSE_SPECIAL , SSE_SPECIAL },  /* movntq, movntq */
+    [0xe8] = MMX_OP2(psubsb),
+    [0xe9] = MMX_OP2(psubsw),
+    [0xea] = MMX_OP2(pminsw),
+    [0xeb] = MMX_OP2(por),
+    [0xec] = MMX_OP2(paddsb),
+    [0xed] = MMX_OP2(paddsw),
+    [0xee] = MMX_OP2(pmaxsw),
+    [0xef] = MMX_OP2(pxor),
+    [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */
+    [0xf1] = MMX_OP2(psllw),
+    [0xf2] = MMX_OP2(pslld),
+    [0xf3] = MMX_OP2(psllq),
+    [0xf4] = MMX_OP2(pmuludq),
+    [0xf5] = MMX_OP2(pmaddwd),
+    [0xf6] = MMX_OP2(psadbw),
+    [0xf7] = MMX_OP2(maskmov),
+    [0xf8] = MMX_OP2(psubb),
+    [0xf9] = MMX_OP2(psubw),
+    [0xfa] = MMX_OP2(psubl),
+    [0xfb] = MMX_OP2(psubq),
+    [0xfc] = MMX_OP2(paddb),
+    [0xfd] = MMX_OP2(paddw),
+    [0xfe] = MMX_OP2(paddl),
+};
+
+static void *sse_op_table2[3 * 8][2] = {
+    [0 + 2] = MMX_OP2(psrlw),
+    [0 + 4] = MMX_OP2(psraw),
+    [0 + 6] = MMX_OP2(psllw),
+    [8 + 2] = MMX_OP2(psrld),
+    [8 + 4] = MMX_OP2(psrad),
+    [8 + 6] = MMX_OP2(pslld),
+    [16 + 2] = MMX_OP2(psrlq),
+    [16 + 3] = { NULL, gen_helper_psrldq_xmm },
+    [16 + 6] = MMX_OP2(psllq),
+    [16 + 7] = { NULL, gen_helper_pslldq_xmm },
+};
+
+static void *sse_op_table3[4 * 3] = {
+    gen_helper_cvtsi2ss,
+    gen_helper_cvtsi2sd,
+    X86_64_ONLY(gen_helper_cvtsq2ss),
+    X86_64_ONLY(gen_helper_cvtsq2sd),
+
+    gen_helper_cvttss2si,
+    gen_helper_cvttsd2si,
+    X86_64_ONLY(gen_helper_cvttss2sq),
+    X86_64_ONLY(gen_helper_cvttsd2sq),
+
+    gen_helper_cvtss2si,
+    gen_helper_cvtsd2si,
+    X86_64_ONLY(gen_helper_cvtss2sq),
+    X86_64_ONLY(gen_helper_cvtsd2sq),
+};
+
+static void *sse_op_table4[8][4] = {
+    SSE_FOP(cmpeq),
+    SSE_FOP(cmplt),
+    SSE_FOP(cmple),
+    SSE_FOP(cmpunord),
+    SSE_FOP(cmpneq),
+    SSE_FOP(cmpnlt),
+    SSE_FOP(cmpnle),
+    SSE_FOP(cmpord),
+};
+
+static void *sse_op_table5[256] = {
+    [0x0c] = gen_helper_pi2fw,
+    [0x0d] = gen_helper_pi2fd,
+    [0x1c] = gen_helper_pf2iw,
+    [0x1d] = gen_helper_pf2id,
+    [0x8a] = gen_helper_pfnacc,
+    [0x8e] = gen_helper_pfpnacc,
+    [0x90] = gen_helper_pfcmpge,
+    [0x94] = gen_helper_pfmin,
+    [0x96] = gen_helper_pfrcp,
+    [0x97] = gen_helper_pfrsqrt,
+    [0x9a] = gen_helper_pfsub,
+    [0x9e] = gen_helper_pfadd,
+    [0xa0] = gen_helper_pfcmpgt,
+    [0xa4] = gen_helper_pfmax,
+    [0xa6] = gen_helper_movq, /* pfrcpit1; no need to actually increase precision */
+    [0xa7] = gen_helper_movq, /* pfrsqit1 */
+    [0xaa] = gen_helper_pfsubr,
+    [0xae] = gen_helper_pfacc,
+    [0xb0] = gen_helper_pfcmpeq,
+    [0xb4] = gen_helper_pfmul,
+    [0xb6] = gen_helper_movq, /* pfrcpit2 */
+    [0xb7] = gen_helper_pmulhrw_mmx,
+    [0xbb] = gen_helper_pswapd,
+    [0xbf] = gen_helper_pavgb_mmx /* pavgusb */
+};
+
+struct sse_op_helper_s {
+    void *op[2]; uint32_t ext_mask;
+};
+#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 }
+#define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 }
+#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
+#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 }
+static struct sse_op_helper_s sse_op_table6[256] = {
+    [0x00] = SSSE3_OP(pshufb),
+    [0x01] = SSSE3_OP(phaddw),
+    [0x02] = SSSE3_OP(phaddd),
+    [0x03] = SSSE3_OP(phaddsw),
+    [0x04] = SSSE3_OP(pmaddubsw),
+    [0x05] = SSSE3_OP(phsubw),
+    [0x06] = SSSE3_OP(phsubd),
+    [0x07] = SSSE3_OP(phsubsw),
+    [0x08] = SSSE3_OP(psignb),
+    [0x09] = SSSE3_OP(psignw),
+    [0x0a] = SSSE3_OP(psignd),
+    [0x0b] = SSSE3_OP(pmulhrsw),
+    [0x10] = SSE41_OP(pblendvb),
+    [0x14] = SSE41_OP(blendvps),
+    [0x15] = SSE41_OP(blendvpd),
+    [0x17] = SSE41_OP(ptest),
+    [0x1c] = SSSE3_OP(pabsb),
+    [0x1d] = SSSE3_OP(pabsw),
+    [0x1e] = SSSE3_OP(pabsd),
+    [0x20] = SSE41_OP(pmovsxbw),
+    [0x21] = SSE41_OP(pmovsxbd),
+    [0x22] = SSE41_OP(pmovsxbq),
+    [0x23] = SSE41_OP(pmovsxwd),
+    [0x24] = SSE41_OP(pmovsxwq),
+    [0x25] = SSE41_OP(pmovsxdq),
+    [0x28] = SSE41_OP(pmuldq),
+    [0x29] = SSE41_OP(pcmpeqq),
+    [0x2a] = SSE41_SPECIAL, /* movntqda */
+    [0x2b] = SSE41_OP(packusdw),
+    [0x30] = SSE41_OP(pmovzxbw),
+    [0x31] = SSE41_OP(pmovzxbd),
+    [0x32] = SSE41_OP(pmovzxbq),
+    [0x33] = SSE41_OP(pmovzxwd),
+    [0x34] = SSE41_OP(pmovzxwq),
+    [0x35] = SSE41_OP(pmovzxdq),
+    [0x37] = SSE42_OP(pcmpgtq),
+    [0x38] = SSE41_OP(pminsb),
+    [0x39] = SSE41_OP(pminsd),
+    [0x3a] = SSE41_OP(pminuw),
+    [0x3b] = SSE41_OP(pminud),
+    [0x3c] = SSE41_OP(pmaxsb),
+    [0x3d] = SSE41_OP(pmaxsd),
+    [0x3e] = SSE41_OP(pmaxuw),
+    [0x3f] = SSE41_OP(pmaxud),
+    [0x40] = SSE41_OP(pmulld),
+    [0x41] = SSE41_OP(phminposuw),
+};
+
+static struct sse_op_helper_s sse_op_table7[256] = {
+    [0x08] = SSE41_OP(roundps),
+    [0x09] = SSE41_OP(roundpd),
+    [0x0a] = SSE41_OP(roundss),
+    [0x0b] = SSE41_OP(roundsd),
+    [0x0c] = SSE41_OP(blendps),
+    [0x0d] = SSE41_OP(blendpd),
+    [0x0e] = SSE41_OP(pblendw),
+    [0x0f] = SSSE3_OP(palignr),
+    [0x14] = SSE41_SPECIAL, /* pextrb */
+    [0x15] = SSE41_SPECIAL, /* pextrw */
+    [0x16] = SSE41_SPECIAL, /* pextrd/pextrq */
+    [0x17] = SSE41_SPECIAL, /* extractps */
+    [0x20] = SSE41_SPECIAL, /* pinsrb */
+    [0x21] = SSE41_SPECIAL, /* insertps */
+    [0x22] = SSE41_SPECIAL, /* pinsrd/pinsrq */
+    [0x40] = SSE41_OP(dpps),
+    [0x41] = SSE41_OP(dppd),
+    [0x42] = SSE41_OP(mpsadbw),
+    [0x60] = SSE42_OP(pcmpestrm),
+    [0x61] = SSE42_OP(pcmpestri),
+    [0x62] = SSE42_OP(pcmpistrm),
+    [0x63] = SSE42_OP(pcmpistri),
+};
+
+static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
+{
+    int b1, op1_offset, op2_offset, is_xmm, val, ot;
+    int modrm, mod, rm, reg, reg_addr, offset_addr;
+    void *sse_op2;
+
+    b &= 0xff;
+    if (s->prefix & PREFIX_DATA)
+        b1 = 1;
+    else if (s->prefix & PREFIX_REPZ)
+        b1 = 2;
+    else if (s->prefix & PREFIX_REPNZ)
+        b1 = 3;
+    else
+        b1 = 0;
+    sse_op2 = sse_op_table1[b][b1];
+    if (!sse_op2)
+        goto illegal_op;
+    if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
+        is_xmm = 1;
+    } else {
+        if (b1 == 0) {
+            /* MMX case */
+            is_xmm = 0;
+        } else {
+            is_xmm = 1;
+        }
+    }
+    /* simple MMX/SSE operation */
+    if (s->flags & HF_TS_MASK) {
+        gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+        return;
+    }
+    if (s->flags & HF_EM_MASK) {
+    illegal_op:
+        gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
+        return;
+    }
+    if (is_xmm && !(s->flags & HF_OSFXSR_MASK))
+        if ((b != 0x38 && b != 0x3a) || (s->prefix & PREFIX_DATA))
+            goto illegal_op;
+    if (b == 0x0e) {
+        if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
+            goto illegal_op;
+        /* femms */
+        gen_helper_emms();
+        return;
+    }
+    if (b == 0x77) {
+        /* emms */
+        gen_helper_emms();
+        return;
+    }
+    /* prepare MMX state (XXX: optimize by storing fptt and fptags in
+       the static cpu state) */
+    if (!is_xmm) {
+        gen_helper_enter_mmx();
+    }
+
+    modrm = ldub_code(s->pc++);
+    reg = ((modrm >> 3) & 7);
+    if (is_xmm)
+        reg |= rex_r;
+    mod = (modrm >> 6) & 3;
+    if (sse_op2 == SSE_SPECIAL) {
+        b |= (b1 << 8);
+        switch(b) {
+        case 0x0e7: /* movntq */
+            if (mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
+            break;
+        case 0x1e7: /* movntdq */
+        case 0x02b: /* movntps */
+        case 0x12b: /* movntps */
+            if (mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            break;
+        case 0x3f0: /* lddqu */
+            if (mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            break;
+        case 0x22b: /* movntss */
+        case 0x32b: /* movntsd */
+            if (mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            if (b1 & 1) {
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,
+                    xmm_regs[reg]));
+            } else {
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
+                    xmm_regs[reg].XMM_L(0)));
+                gen_op_st_T0_A0(OT_LONG + s->mem_index);
+            }
+            break;
+        case 0x6e: /* movd mm, ea */
+#ifdef TARGET_X86_64
+            if (s->dflag == 2) {
+                gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+                tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,fpregs[reg].mmx));
+            } else
+#endif
+            {
+                gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
+                                 offsetof(CPUX86State,fpregs[reg].mmx));
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_movl_mm_T0_mmx(cpu_ptr0, cpu_tmp2_i32);
+            }
+            break;
+        case 0x16e: /* movd xmm, ea */
+#ifdef TARGET_X86_64
+            if (s->dflag == 2) {
+                gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
+                                 offsetof(CPUX86State,xmm_regs[reg]));
+                gen_helper_movq_mm_T0_xmm(cpu_ptr0, cpu_T[0]);
+            } else
+#endif
+            {
+                gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
+                                 offsetof(CPUX86State,xmm_regs[reg]));
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_movl_mm_T0_xmm(cpu_ptr0, cpu_tmp2_i32);
+            }
+            break;
+        case 0x6f: /* movq mm, ea */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
+            } else {
+                rm = (modrm & 7);
+                tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env,
+                               offsetof(CPUX86State,fpregs[rm].mmx));
+                tcg_gen_st_i64(cpu_tmp1_i64, cpu_env,
+                               offsetof(CPUX86State,fpregs[reg].mmx));
+            }
+            break;
+        case 0x010: /* movups */
+        case 0x110: /* movupd */
+        case 0x028: /* movaps */
+        case 0x128: /* movapd */
+        case 0x16f: /* movdqa xmm, ea */
+        case 0x26f: /* movdqu xmm, ea */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]),
+                            offsetof(CPUX86State,xmm_regs[rm]));
+            }
+            break;
+        case 0x210: /* movss xmm, ea */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
+                gen_op_movl_T0_0();
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
+            }
+            break;
+        case 0x310: /* movsd xmm, ea */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+                gen_op_movl_T0_0();
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
+            }
+            break;
+        case 0x012: /* movlps */
+        case 0x112: /* movlpd */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                /* movhlps */
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
+            }
+            break;
+        case 0x212: /* movsldup */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_L(2)));
+            }
+            gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
+                        offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
+            gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
+                        offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
+            break;
+        case 0x312: /* movddup */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
+            }
+            gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
+                        offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            break;
+        case 0x016: /* movhps */
+        case 0x116: /* movhpd */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
+            } else {
+                /* movlhps */
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
+            }
+            break;
+        case 0x216: /* movshdup */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_L(1)));
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_L(3)));
+            }
+            gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
+                        offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
+            gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
+                        offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
+            break;
+        case 0x178:
+        case 0x378:
+            {
+                int bit_index, field_length;
+
+                if (b1 == 1 && reg != 0)
+                    goto illegal_op;
+                field_length = ldub_code(s->pc++) & 0x3F;
+                bit_index = ldub_code(s->pc++) & 0x3F;
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
+                    offsetof(CPUX86State,xmm_regs[reg]));
+                if (b1 == 1)
+                    gen_helper_extrq_i(cpu_ptr0, tcg_const_i32(bit_index),
+                        tcg_const_i32(field_length));
+                else
+                    gen_helper_insertq_i(cpu_ptr0, tcg_const_i32(bit_index),
+                        tcg_const_i32(field_length));
+            }
+            break;
+        case 0x7e: /* movd ea, mm */
+#ifdef TARGET_X86_64
+            if (s->dflag == 2) {
+                tcg_gen_ld_i64(cpu_T[0], cpu_env, 
+                               offsetof(CPUX86State,fpregs[reg].mmx));
+                gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+            } else
+#endif
+            {
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
+                                 offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0)));
+                gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+            }
+            break;
+        case 0x17e: /* movd ea, xmm */
+#ifdef TARGET_X86_64
+            if (s->dflag == 2) {
+                tcg_gen_ld_i64(cpu_T[0], cpu_env, 
+                               offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+                gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+            } else
+#endif
+            {
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, 
+                                 offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
+                gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+            }
+            break;
+        case 0x27e: /* movq xmm, ea */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
+            }
+            gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
+            break;
+        case 0x7f: /* movq ea, mm */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
+            } else {
+                rm = (modrm & 7);
+                gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx),
+                            offsetof(CPUX86State,fpregs[reg].mmx));
+            }
+            break;
+        case 0x011: /* movups */
+        case 0x111: /* movupd */
+        case 0x029: /* movaps */
+        case 0x129: /* movapd */
+        case 0x17f: /* movdqa ea, xmm */
+        case 0x27f: /* movdqu ea, xmm */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]),
+                            offsetof(CPUX86State,xmm_regs[reg]));
+            }
+            break;
+        case 0x211: /* movss ea, xmm */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
+                gen_op_st_T0_A0(OT_LONG + s->mem_index);
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movl(offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)),
+                            offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
+            }
+            break;
+        case 0x311: /* movsd ea, xmm */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            }
+            break;
+        case 0x013: /* movlps */
+        case 0x113: /* movlpd */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                goto illegal_op;
+            }
+            break;
+        case 0x017: /* movhps */
+        case 0x117: /* movhpd */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
+            } else {
+                goto illegal_op;
+            }
+            break;
+        case 0x71: /* shift mm, im */
+        case 0x72:
+        case 0x73:
+        case 0x171: /* shift xmm, im */
+        case 0x172:
+        case 0x173:
+            if (b1 >= 2) {
+	        goto illegal_op;
+            }
+            val = ldub_code(s->pc++);
+            if (is_xmm) {
+                gen_op_movl_T0_im(val);
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+                gen_op_movl_T0_0();
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(1)));
+                op1_offset = offsetof(CPUX86State,xmm_t0);
+            } else {
+                gen_op_movl_T0_im(val);
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(0)));
+                gen_op_movl_T0_0();
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(1)));
+                op1_offset = offsetof(CPUX86State,mmx_t0);
+            }
+            sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
+            if (!sse_op2)
+                goto illegal_op;
+            if (is_xmm) {
+                rm = (modrm & 7) | REX_B(s);
+                op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
+            } else {
+                rm = (modrm & 7);
+                op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
+            }
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op1_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+            break;
+        case 0x050: /* movmskps */
+            rm = (modrm & 7) | REX_B(s);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
+                             offsetof(CPUX86State,xmm_regs[rm]));
+            gen_helper_movmskps(cpu_tmp2_i32, cpu_ptr0);
+            tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+            gen_op_mov_reg_T0(OT_LONG, reg);
+            break;
+        case 0x150: /* movmskpd */
+            rm = (modrm & 7) | REX_B(s);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, 
+                             offsetof(CPUX86State,xmm_regs[rm]));
+            gen_helper_movmskpd(cpu_tmp2_i32, cpu_ptr0);
+            tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+            gen_op_mov_reg_T0(OT_LONG, reg);
+            break;
+        case 0x02a: /* cvtpi2ps */
+        case 0x12a: /* cvtpi2pd */
+            gen_helper_enter_mmx();
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                op2_offset = offsetof(CPUX86State,mmx_t0);
+                gen_ldq_env_A0(s->mem_index, op2_offset);
+            } else {
+                rm = (modrm & 7);
+                op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
+            }
+            op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            switch(b >> 8) {
+            case 0x0:
+                gen_helper_cvtpi2ps(cpu_ptr0, cpu_ptr1);
+                break;
+            default:
+            case 0x1:
+                gen_helper_cvtpi2pd(cpu_ptr0, cpu_ptr1);
+                break;
+            }
+            break;
+        case 0x22a: /* cvtsi2ss */
+        case 0x32a: /* cvtsi2sd */
+            ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+            op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)];
+            if (ot == OT_LONG) {
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                ((void (*)(TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_tmp2_i32);
+            } else {
+                ((void (*)(TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_T[0]);
+            }
+            break;
+        case 0x02c: /* cvttps2pi */
+        case 0x12c: /* cvttpd2pi */
+        case 0x02d: /* cvtps2pi */
+        case 0x12d: /* cvtpd2pi */
+            gen_helper_enter_mmx();
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                op2_offset = offsetof(CPUX86State,xmm_t0);
+                gen_ldo_env_A0(s->mem_index, op2_offset);
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
+            }
+            op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            switch(b) {
+            case 0x02c:
+                gen_helper_cvttps2pi(cpu_ptr0, cpu_ptr1);
+                break;
+            case 0x12c:
+                gen_helper_cvttpd2pi(cpu_ptr0, cpu_ptr1);
+                break;
+            case 0x02d:
+                gen_helper_cvtps2pi(cpu_ptr0, cpu_ptr1);
+                break;
+            case 0x12d:
+                gen_helper_cvtpd2pi(cpu_ptr0, cpu_ptr1);
+                break;
+            }
+            break;
+        case 0x22c: /* cvttss2si */
+        case 0x32c: /* cvttsd2si */
+        case 0x22d: /* cvtss2si */
+        case 0x32d: /* cvtsd2si */
+            ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                if ((b >> 8) & 1) {
+                    gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_Q(0)));
+                } else {
+                    gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                    tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+                }
+                op2_offset = offsetof(CPUX86State,xmm_t0);
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
+            }
+            sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 +
+                                    (b & 1) * 4];
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
+            if (ot == OT_LONG) {
+                ((void (*)(TCGv_i32, TCGv_ptr))sse_op2)(cpu_tmp2_i32, cpu_ptr0);
+                tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+            } else {
+                ((void (*)(TCGv, TCGv_ptr))sse_op2)(cpu_T[0], cpu_ptr0);
+            }
+            gen_op_mov_reg_T0(ot, reg);
+            break;
+        case 0xc4: /* pinsrw */
+        case 0x1c4:
+            s->rip_offset = 1;
+            gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+            val = ldub_code(s->pc++);
+            if (b1) {
+                val &= 7;
+                tcg_gen_st16_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,xmm_regs[reg].XMM_W(val)));
+            } else {
+                val &= 3;
+                tcg_gen_st16_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val)));
+            }
+            break;
+        case 0xc5: /* pextrw */
+        case 0x1c5:
+            if (mod != 3)
+                goto illegal_op;
+            ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+            val = ldub_code(s->pc++);
+            if (b1) {
+                val &= 7;
+                rm = (modrm & 7) | REX_B(s);
+                tcg_gen_ld16u_tl(cpu_T[0], cpu_env,
+                                 offsetof(CPUX86State,xmm_regs[rm].XMM_W(val)));
+            } else {
+                val &= 3;
+                rm = (modrm & 7);
+                tcg_gen_ld16u_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val)));
+            }
+            reg = ((modrm >> 3) & 7) | rex_r;
+            gen_op_mov_reg_T0(ot, reg);
+            break;
+        case 0x1d6: /* movq ea, xmm */
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
+                            offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+                gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
+            }
+            break;
+        case 0x2d6: /* movq2dq */
+            gen_helper_enter_mmx();
+            rm = (modrm & 7);
+            gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+                        offsetof(CPUX86State,fpregs[rm].mmx));
+            gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
+            break;
+        case 0x3d6: /* movdq2q */
+            gen_helper_enter_mmx();
+            rm = (modrm & 7) | REX_B(s);
+            gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx),
+                        offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
+            break;
+        case 0xd7: /* pmovmskb */
+        case 0x1d7:
+            if (mod != 3)
+                goto illegal_op;
+            if (b1) {
+                rm = (modrm & 7) | REX_B(s);
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,xmm_regs[rm]));
+                gen_helper_pmovmskb_xmm(cpu_tmp2_i32, cpu_ptr0);
+            } else {
+                rm = (modrm & 7);
+                tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,fpregs[rm].mmx));
+                gen_helper_pmovmskb_mmx(cpu_tmp2_i32, cpu_ptr0);
+            }
+            tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            gen_op_mov_reg_T0(OT_LONG, reg);
+            break;
+        case 0x138:
+            if (s->prefix & PREFIX_REPNZ)
+                goto crc32;
+        case 0x038:
+            b = modrm;
+            modrm = ldub_code(s->pc++);
+            rm = modrm & 7;
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            if (b1 >= 2) {
+                goto illegal_op;
+            }
+
+            sse_op2 = sse_op_table6[b].op[b1];
+            if (!sse_op2)
+                goto illegal_op;
+            if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
+                goto illegal_op;
+
+            if (b1) {
+                op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+                if (mod == 3) {
+                    op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
+                } else {
+                    op2_offset = offsetof(CPUX86State,xmm_t0);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    switch (b) {
+                    case 0x20: case 0x30: /* pmovsxbw, pmovzxbw */
+                    case 0x23: case 0x33: /* pmovsxwd, pmovzxwd */
+                    case 0x25: case 0x35: /* pmovsxdq, pmovzxdq */
+                        gen_ldq_env_A0(s->mem_index, op2_offset +
+                                        offsetof(XMMReg, XMM_Q(0)));
+                        break;
+                    case 0x21: case 0x31: /* pmovsxbd, pmovzxbd */
+                    case 0x24: case 0x34: /* pmovsxwq, pmovzxwq */
+                        tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
+                                          (s->mem_index >> 2) - 1);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
+                        tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, op2_offset +
+                                        offsetof(XMMReg, XMM_L(0)));
+                        break;
+                    case 0x22: case 0x32: /* pmovsxbq, pmovzxbq */
+                        tcg_gen_qemu_ld16u(cpu_tmp0, cpu_A0,
+                                          (s->mem_index >> 2) - 1);
+                        tcg_gen_st16_tl(cpu_tmp0, cpu_env, op2_offset +
+                                        offsetof(XMMReg, XMM_W(0)));
+                        break;
+                    case 0x2a:            /* movntqda */
+                        gen_ldo_env_A0(s->mem_index, op1_offset);
+                        return;
+                    default:
+                        gen_ldo_env_A0(s->mem_index, op2_offset);
+                    }
+                }
+            } else {
+                op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
+                if (mod == 3) {
+                    op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
+                } else {
+                    op2_offset = offsetof(CPUX86State,mmx_t0);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_ldq_env_A0(s->mem_index, op2_offset);
+                }
+            }
+            if (sse_op2 == SSE_SPECIAL)
+                goto illegal_op;
+
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+
+            if (b == 0x17)
+                s->cc_op = CC_OP_EFLAGS;
+            break;
+        case 0x338: /* crc32 */
+        crc32:
+            b = modrm;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+
+            if (b != 0xf0 && b != 0xf1)
+                goto illegal_op;
+            if (!(s->cpuid_ext_features & CPUID_EXT_SSE42))
+                goto illegal_op;
+
+            if (b == 0xf0)
+                ot = OT_BYTE;
+            else if (b == 0xf1 && s->dflag != 2)
+                if (s->prefix & PREFIX_DATA)
+                    ot = OT_WORD;
+                else
+                    ot = OT_LONG;
+            else
+                ot = OT_QUAD;
+
+            gen_op_mov_TN_reg(OT_LONG, 0, reg);
+            tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+            gen_helper_crc32(cpu_T[0], cpu_tmp2_i32,
+                             cpu_T[0], tcg_const_i32(8 << ot));
+
+            ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+            gen_op_mov_reg_T0(ot, reg);
+            break;
+        case 0x03a:
+        case 0x13a:
+            b = modrm;
+            modrm = ldub_code(s->pc++);
+            rm = modrm & 7;
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            if (b1 >= 2) {
+                goto illegal_op;
+            }
+
+            sse_op2 = sse_op_table7[b].op[b1];
+            if (!sse_op2)
+                goto illegal_op;
+            if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
+                goto illegal_op;
+
+            if (sse_op2 == SSE_SPECIAL) {
+                ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
+                rm = (modrm & 7) | REX_B(s);
+                if (mod != 3)
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                reg = ((modrm >> 3) & 7) | rex_r;
+                val = ldub_code(s->pc++);
+                switch (b) {
+                case 0x14: /* pextrb */
+                    tcg_gen_ld8u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
+                                            xmm_regs[reg].XMM_B(val & 15)));
+                    if (mod == 3)
+                        gen_op_mov_reg_T0(ot, rm);
+                    else
+                        tcg_gen_qemu_st8(cpu_T[0], cpu_A0,
+                                        (s->mem_index >> 2) - 1);
+                    break;
+                case 0x15: /* pextrw */
+                    tcg_gen_ld16u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
+                                            xmm_regs[reg].XMM_W(val & 7)));
+                    if (mod == 3)
+                        gen_op_mov_reg_T0(ot, rm);
+                    else
+                        tcg_gen_qemu_st16(cpu_T[0], cpu_A0,
+                                        (s->mem_index >> 2) - 1);
+                    break;
+                case 0x16:
+                    if (ot == OT_LONG) { /* pextrd */
+                        tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env,
+                                        offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(val & 3)));
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        if (mod == 3)
+                            gen_op_mov_reg_v(ot, rm, cpu_T[0]);
+                        else
+                            tcg_gen_qemu_st32(cpu_T[0], cpu_A0,
+                                            (s->mem_index >> 2) - 1);
+                    } else { /* pextrq */
+#ifdef TARGET_X86_64
+                        tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env,
+                                        offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_Q(val & 1)));
+                        if (mod == 3)
+                            gen_op_mov_reg_v(ot, rm, cpu_tmp1_i64);
+                        else
+                            tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
+                                            (s->mem_index >> 2) - 1);
+#else
+                        goto illegal_op;
+#endif
+                    }
+                    break;
+                case 0x17: /* extractps */
+                    tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
+                                            xmm_regs[reg].XMM_L(val & 3)));
+                    if (mod == 3)
+                        gen_op_mov_reg_T0(ot, rm);
+                    else
+                        tcg_gen_qemu_st32(cpu_T[0], cpu_A0,
+                                        (s->mem_index >> 2) - 1);
+                    break;
+                case 0x20: /* pinsrb */
+                    if (mod == 3)
+                        gen_op_mov_TN_reg(OT_LONG, 0, rm);
+                    else
+                        tcg_gen_qemu_ld8u(cpu_tmp0, cpu_A0,
+                                        (s->mem_index >> 2) - 1);
+                    tcg_gen_st8_tl(cpu_tmp0, cpu_env, offsetof(CPUX86State,
+                                            xmm_regs[reg].XMM_B(val & 15)));
+                    break;
+                case 0x21: /* insertps */
+                    if (mod == 3) {
+                        tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env,
+                                        offsetof(CPUX86State,xmm_regs[rm]
+                                                .XMM_L((val >> 6) & 3)));
+                    } else {
+                        tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
+                                        (s->mem_index >> 2) - 1);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
+                    }
+                    tcg_gen_st_i32(cpu_tmp2_i32, cpu_env,
+                                    offsetof(CPUX86State,xmm_regs[reg]
+                                            .XMM_L((val >> 4) & 3)));
+                    if ((val >> 0) & 1)
+                        tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
+                                        cpu_env, offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(0)));
+                    if ((val >> 1) & 1)
+                        tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
+                                        cpu_env, offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(1)));
+                    if ((val >> 2) & 1)
+                        tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
+                                        cpu_env, offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(2)));
+                    if ((val >> 3) & 1)
+                        tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
+                                        cpu_env, offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(3)));
+                    break;
+                case 0x22:
+                    if (ot == OT_LONG) { /* pinsrd */
+                        if (mod == 3)
+                            gen_op_mov_v_reg(ot, cpu_tmp0, rm);
+                        else
+                            tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
+                                            (s->mem_index >> 2) - 1);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
+                        tcg_gen_st_i32(cpu_tmp2_i32, cpu_env,
+                                        offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_L(val & 3)));
+                    } else { /* pinsrq */
+#ifdef TARGET_X86_64
+                        if (mod == 3)
+                            gen_op_mov_v_reg(ot, cpu_tmp1_i64, rm);
+                        else
+                            tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
+                                            (s->mem_index >> 2) - 1);
+                        tcg_gen_st_i64(cpu_tmp1_i64, cpu_env,
+                                        offsetof(CPUX86State,
+                                                xmm_regs[reg].XMM_Q(val & 1)));
+#else
+                        goto illegal_op;
+#endif
+                    }
+                    break;
+                }
+                return;
+            }
+
+            if (b1) {
+                op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+                if (mod == 3) {
+                    op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
+                } else {
+                    op2_offset = offsetof(CPUX86State,xmm_t0);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_ldo_env_A0(s->mem_index, op2_offset);
+                }
+            } else {
+                op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
+                if (mod == 3) {
+                    op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
+                } else {
+                    op2_offset = offsetof(CPUX86State,mmx_t0);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_ldq_env_A0(s->mem_index, op2_offset);
+                }
+            }
+            val = ldub_code(s->pc++);
+
+            if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
+                s->cc_op = CC_OP_EFLAGS;
+
+                if (s->dflag == 2)
+                    /* The helper must use entire 64-bit gp registers */
+                    val |= 1 << 8;
+            }
+
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
+            break;
+        default:
+            goto illegal_op;
+        }
+    } else {
+        /* generic MMX or SSE operation */
+        switch(b) {
+        case 0x70: /* pshufx insn */
+        case 0xc6: /* pshufx insn */
+        case 0xc2: /* compare insns */
+            s->rip_offset = 1;
+            break;
+        default:
+            break;
+        }
+        if (is_xmm) {
+            op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                op2_offset = offsetof(CPUX86State,xmm_t0);
+                if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
+                                b == 0xc2)) {
+                    /* specific case for SSE single instructions */
+                    if (b1 == 2) {
+                        /* 32 bit access */
+                        gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                        tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+                    } else {
+                        /* 64 bit access */
+                        gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_D(0)));
+                    }
+                } else {
+                    gen_ldo_env_A0(s->mem_index, op2_offset);
+                }
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
+            }
+        } else {
+            op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                op2_offset = offsetof(CPUX86State,mmx_t0);
+                gen_ldq_env_A0(s->mem_index, op2_offset);
+            } else {
+                rm = (modrm & 7);
+                op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
+            }
+        }
+        switch(b) {
+        case 0x0f: /* 3DNow! data insns */
+            if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
+                goto illegal_op;
+            val = ldub_code(s->pc++);
+            sse_op2 = sse_op_table5[val];
+            if (!sse_op2)
+                goto illegal_op;
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+            break;
+        case 0x70: /* pshufx insn */
+        case 0xc6: /* pshufx insn */
+            val = ldub_code(s->pc++);
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
+            break;
+        case 0xc2:
+            /* compare insns */
+            val = ldub_code(s->pc++);
+            if (val >= 8)
+                goto illegal_op;
+            sse_op2 = sse_op_table4[val][b1];
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+            break;
+        case 0xf7:
+            /* maskmov : we must prepare A0 */
+            if (mod != 3)
+                goto illegal_op;
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                gen_op_movq_A0_reg(R_EDI);
+            } else
+#endif
+            {
+                gen_op_movl_A0_reg(R_EDI);
+                if (s->aflag == 0)
+                    gen_op_andl_A0_ffff();
+            }
+            gen_add_A0_ds_seg(s);
+
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_ptr1, cpu_A0);
+            break;
+        default:
+            tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
+            tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
+            ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+            break;
+        }
+        if (b == 0x2e || b == 0x2f) {
+            s->cc_op = CC_OP_EFLAGS;
+        }
+    }
+}
+
+/* convert one instruction. s->is_jmp is set if the translation must
+   be stopped. Return the next pc value */
+static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
+{
+    int b, prefixes, aflag, dflag;
+    int shift, ot;
+    int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
+    target_ulong next_eip, tval;
+    int rex_w, rex_r;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+        tcg_gen_debug_insn_start(pc_start);
+    s->pc = pc_start;
+    prefixes = 0;
+    aflag = s->code32;
+    dflag = s->code32;
+    s->override = -1;
+    rex_w = -1;
+    rex_r = 0;
+#ifdef TARGET_X86_64
+    s->rex_x = 0;
+    s->rex_b = 0;
+    x86_64_hregs = 0;
+#endif
+    s->rip_offset = 0; /* for relative ip address */
+ next_byte:
+    b = ldub_code(s->pc);
+    s->pc++;
+    /* check prefixes */
+#ifdef TARGET_X86_64
+    if (CODE64(s)) {
+        switch (b) {
+        case 0xf3:
+            prefixes |= PREFIX_REPZ;
+            goto next_byte;
+        case 0xf2:
+            prefixes |= PREFIX_REPNZ;
+            goto next_byte;
+        case 0xf0:
+            prefixes |= PREFIX_LOCK;
+            goto next_byte;
+        case 0x2e:
+            s->override = R_CS;
+            goto next_byte;
+        case 0x36:
+            s->override = R_SS;
+            goto next_byte;
+        case 0x3e:
+            s->override = R_DS;
+            goto next_byte;
+        case 0x26:
+            s->override = R_ES;
+            goto next_byte;
+        case 0x64:
+            s->override = R_FS;
+            goto next_byte;
+        case 0x65:
+            s->override = R_GS;
+            goto next_byte;
+        case 0x66:
+            prefixes |= PREFIX_DATA;
+            goto next_byte;
+        case 0x67:
+            prefixes |= PREFIX_ADR;
+            goto next_byte;
+        case 0x40 ... 0x4f:
+            /* REX prefix */
+            rex_w = (b >> 3) & 1;
+            rex_r = (b & 0x4) << 1;
+            s->rex_x = (b & 0x2) << 2;
+            REX_B(s) = (b & 0x1) << 3;
+            x86_64_hregs = 1; /* select uniform byte register addressing */
+            goto next_byte;
+        }
+        if (rex_w == 1) {
+            /* 0x66 is ignored if rex.w is set */
+            dflag = 2;
+        } else {
+            if (prefixes & PREFIX_DATA)
+                dflag ^= 1;
+        }
+        if (!(prefixes & PREFIX_ADR))
+            aflag = 2;
+    } else
+#endif
+    {
+        switch (b) {
+        case 0xf3:
+            prefixes |= PREFIX_REPZ;
+            goto next_byte;
+        case 0xf2:
+            prefixes |= PREFIX_REPNZ;
+            goto next_byte;
+        case 0xf0:
+            prefixes |= PREFIX_LOCK;
+            goto next_byte;
+        case 0x2e:
+            s->override = R_CS;
+            goto next_byte;
+        case 0x36:
+            s->override = R_SS;
+            goto next_byte;
+        case 0x3e:
+            s->override = R_DS;
+            goto next_byte;
+        case 0x26:
+            s->override = R_ES;
+            goto next_byte;
+        case 0x64:
+            s->override = R_FS;
+            goto next_byte;
+        case 0x65:
+            s->override = R_GS;
+            goto next_byte;
+        case 0x66:
+            prefixes |= PREFIX_DATA;
+            goto next_byte;
+        case 0x67:
+            prefixes |= PREFIX_ADR;
+            goto next_byte;
+        }
+        if (prefixes & PREFIX_DATA)
+            dflag ^= 1;
+        if (prefixes & PREFIX_ADR)
+            aflag ^= 1;
+    }
+
+    s->prefix = prefixes;
+    s->aflag = aflag;
+    s->dflag = dflag;
+
+    /* lock generation */
+    if (prefixes & PREFIX_LOCK)
+        gen_helper_lock();
+
+    /* now check op code */
+ reswitch:
+    switch(b) {
+    case 0x0f:
+        /**************************/
+        /* extended op code */
+        b = ldub_code(s->pc++) | 0x100;
+        goto reswitch;
+
+        /**************************/
+        /* arith & logic */
+    case 0x00 ... 0x05:
+    case 0x08 ... 0x0d:
+    case 0x10 ... 0x15:
+    case 0x18 ... 0x1d:
+    case 0x20 ... 0x25:
+    case 0x28 ... 0x2d:
+    case 0x30 ... 0x35:
+    case 0x38 ... 0x3d:
+        {
+            int op, f, val;
+            op = (b >> 3) & 7;
+            f = (b >> 1) & 3;
+
+            if ((b & 1) == 0)
+                ot = OT_BYTE;
+            else
+                ot = dflag + OT_WORD;
+
+            switch(f) {
+            case 0: /* OP Ev, Gv */
+                modrm = ldub_code(s->pc++);
+                reg = ((modrm >> 3) & 7) | rex_r;
+                mod = (modrm >> 6) & 3;
+                rm = (modrm & 7) | REX_B(s);
+                if (mod != 3) {
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    opreg = OR_TMP0;
+                } else if (op == OP_XORL && rm == reg) {
+                xor_zero:
+                    /* xor reg, reg optimisation */
+                    gen_op_movl_T0_0();
+                    s->cc_op = CC_OP_LOGICB + ot;
+                    gen_op_mov_reg_T0(ot, reg);
+                    gen_op_update1_cc();
+                    break;
+                } else {
+                    opreg = rm;
+                }
+                gen_op_mov_TN_reg(ot, 1, reg);
+                gen_op(s, op, ot, opreg);
+                break;
+            case 1: /* OP Gv, Ev */
+                modrm = ldub_code(s->pc++);
+                mod = (modrm >> 6) & 3;
+                reg = ((modrm >> 3) & 7) | rex_r;
+                rm = (modrm & 7) | REX_B(s);
+                if (mod != 3) {
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_op_ld_T1_A0(ot + s->mem_index);
+                } else if (op == OP_XORL && rm == reg) {
+                    goto xor_zero;
+                } else {
+                    gen_op_mov_TN_reg(ot, 1, rm);
+                }
+                gen_op(s, op, ot, reg);
+                break;
+            case 2: /* OP A, Iv */
+                val = insn_get(s, ot);
+                gen_op_movl_T1_im(val);
+                gen_op(s, op, ot, OR_EAX);
+                break;
+            }
+        }
+        break;
+
+    case 0x82:
+        if (CODE64(s))
+            goto illegal_op;
+    case 0x80: /* GRP1 */
+    case 0x81:
+    case 0x83:
+        {
+            int val;
+
+            if ((b & 1) == 0)
+                ot = OT_BYTE;
+            else
+                ot = dflag + OT_WORD;
+
+            modrm = ldub_code(s->pc++);
+            mod = (modrm >> 6) & 3;
+            rm = (modrm & 7) | REX_B(s);
+            op = (modrm >> 3) & 7;
+
+            if (mod != 3) {
+                if (b == 0x83)
+                    s->rip_offset = 1;
+                else
+                    s->rip_offset = insn_const_size(ot);
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                opreg = OR_TMP0;
+            } else {
+                opreg = rm;
+            }
+
+            switch(b) {
+            default:
+            case 0x80:
+            case 0x81:
+            case 0x82:
+                val = insn_get(s, ot);
+                break;
+            case 0x83:
+                val = (int8_t)insn_get(s, OT_BYTE);
+                break;
+            }
+            gen_op_movl_T1_im(val);
+            gen_op(s, op, ot, opreg);
+        }
+        break;
+
+        /**************************/
+        /* inc, dec, and other misc arith */
+    case 0x40 ... 0x47: /* inc Gv */
+        ot = dflag ? OT_LONG : OT_WORD;
+        gen_inc(s, ot, OR_EAX + (b & 7), 1);
+        break;
+    case 0x48 ... 0x4f: /* dec Gv */
+        ot = dflag ? OT_LONG : OT_WORD;
+        gen_inc(s, ot, OR_EAX + (b & 7), -1);
+        break;
+    case 0xf6: /* GRP3 */
+    case 0xf7:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        rm = (modrm & 7) | REX_B(s);
+        op = (modrm >> 3) & 7;
+        if (mod != 3) {
+            if (op == 0)
+                s->rip_offset = insn_const_size(ot);
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_ld_T0_A0(ot + s->mem_index);
+        } else {
+            gen_op_mov_TN_reg(ot, 0, rm);
+        }
+
+        switch(op) {
+        case 0: /* test */
+            val = insn_get(s, ot);
+            gen_op_movl_T1_im(val);
+            gen_op_testl_T0_T1_cc();
+            s->cc_op = CC_OP_LOGICB + ot;
+            break;
+        case 2: /* not */
+            tcg_gen_not_tl(cpu_T[0], cpu_T[0]);
+            if (mod != 3) {
+                gen_op_st_T0_A0(ot + s->mem_index);
+            } else {
+                gen_op_mov_reg_T0(ot, rm);
+            }
+            break;
+        case 3: /* neg */
+            tcg_gen_neg_tl(cpu_T[0], cpu_T[0]);
+            if (mod != 3) {
+                gen_op_st_T0_A0(ot + s->mem_index);
+            } else {
+                gen_op_mov_reg_T0(ot, rm);
+            }
+            gen_op_update_neg_cc();
+            s->cc_op = CC_OP_SUBB + ot;
+            break;
+        case 4: /* mul */
+            switch(ot) {
+            case OT_BYTE:
+                gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX);
+                tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext8u_tl(cpu_T[1], cpu_T[1]);
+                /* XXX: use 32 bit mul which could be faster */
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_WORD, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00);
+                s->cc_op = CC_OP_MULB;
+                break;
+            case OT_WORD:
+                gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
+                tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext16u_tl(cpu_T[1], cpu_T[1]);
+                /* XXX: use 32 bit mul which could be faster */
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_WORD, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
+                gen_op_mov_reg_T0(OT_WORD, R_EDX);
+                tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+                s->cc_op = CC_OP_MULW;
+                break;
+            default:
+            case OT_LONG:
+#ifdef TARGET_X86_64
+                gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
+                tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]);
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_LONG, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
+                gen_op_mov_reg_T0(OT_LONG, R_EDX);
+                tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+#else
+                {
+                    TCGv_i64 t0, t1;
+                    t0 = tcg_temp_new_i64();
+                    t1 = tcg_temp_new_i64();
+                    gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
+                    tcg_gen_extu_i32_i64(t0, cpu_T[0]);
+                    tcg_gen_extu_i32_i64(t1, cpu_T[1]);
+                    tcg_gen_mul_i64(t0, t0, t1);
+                    tcg_gen_trunc_i64_i32(cpu_T[0], t0);
+                    gen_op_mov_reg_T0(OT_LONG, R_EAX);
+                    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                    tcg_gen_shri_i64(t0, t0, 32);
+                    tcg_gen_trunc_i64_i32(cpu_T[0], t0);
+                    gen_op_mov_reg_T0(OT_LONG, R_EDX);
+                    tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
+                }
+#endif
+                s->cc_op = CC_OP_MULL;
+                break;
+#ifdef TARGET_X86_64
+            case OT_QUAD:
+                gen_helper_mulq_EAX_T0(cpu_T[0]);
+                s->cc_op = CC_OP_MULQ;
+                break;
+#endif
+            }
+            break;
+        case 5: /* imul */
+            switch(ot) {
+            case OT_BYTE:
+                gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX);
+                tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext8s_tl(cpu_T[1], cpu_T[1]);
+                /* XXX: use 32 bit mul which could be faster */
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_WORD, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]);
+                tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+                s->cc_op = CC_OP_MULB;
+                break;
+            case OT_WORD:
+                gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
+                tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]);
+                /* XXX: use 32 bit mul which could be faster */
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_WORD, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]);
+                tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+                tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
+                gen_op_mov_reg_T0(OT_WORD, R_EDX);
+                s->cc_op = CC_OP_MULW;
+                break;
+            default:
+            case OT_LONG:
+#ifdef TARGET_X86_64
+                gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
+                tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                gen_op_mov_reg_T0(OT_LONG, R_EAX);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
+                tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+                tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
+                gen_op_mov_reg_T0(OT_LONG, R_EDX);
+#else
+                {
+                    TCGv_i64 t0, t1;
+                    t0 = tcg_temp_new_i64();
+                    t1 = tcg_temp_new_i64();
+                    gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
+                    tcg_gen_ext_i32_i64(t0, cpu_T[0]);
+                    tcg_gen_ext_i32_i64(t1, cpu_T[1]);
+                    tcg_gen_mul_i64(t0, t0, t1);
+                    tcg_gen_trunc_i64_i32(cpu_T[0], t0);
+                    gen_op_mov_reg_T0(OT_LONG, R_EAX);
+                    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                    tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
+                    tcg_gen_shri_i64(t0, t0, 32);
+                    tcg_gen_trunc_i64_i32(cpu_T[0], t0);
+                    gen_op_mov_reg_T0(OT_LONG, R_EDX);
+                    tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+                }
+#endif
+                s->cc_op = CC_OP_MULL;
+                break;
+#ifdef TARGET_X86_64
+            case OT_QUAD:
+                gen_helper_imulq_EAX_T0(cpu_T[0]);
+                s->cc_op = CC_OP_MULQ;
+                break;
+#endif
+            }
+            break;
+        case 6: /* div */
+            switch(ot) {
+            case OT_BYTE:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_divb_AL(cpu_T[0]);
+                break;
+            case OT_WORD:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_divw_AX(cpu_T[0]);
+                break;
+            default:
+            case OT_LONG:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_divl_EAX(cpu_T[0]);
+                break;
+#ifdef TARGET_X86_64
+            case OT_QUAD:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_divq_EAX(cpu_T[0]);
+                break;
+#endif
+            }
+            break;
+        case 7: /* idiv */
+            switch(ot) {
+            case OT_BYTE:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_idivb_AL(cpu_T[0]);
+                break;
+            case OT_WORD:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_idivw_AX(cpu_T[0]);
+                break;
+            default:
+            case OT_LONG:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_idivl_EAX(cpu_T[0]);
+                break;
+#ifdef TARGET_X86_64
+            case OT_QUAD:
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_idivq_EAX(cpu_T[0]);
+                break;
+#endif
+            }
+            break;
+        default:
+            goto illegal_op;
+        }
+        break;
+
+    case 0xfe: /* GRP4 */
+    case 0xff: /* GRP5 */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        rm = (modrm & 7) | REX_B(s);
+        op = (modrm >> 3) & 7;
+        if (op >= 2 && b == 0xfe) {
+            goto illegal_op;
+        }
+        if (CODE64(s)) {
+            if (op == 2 || op == 4) {
+                /* operand size for jumps is 64 bit */
+                ot = OT_QUAD;
+            } else if (op == 3 || op == 5) {
+                ot = dflag ? OT_LONG + (rex_w == 1) : OT_WORD;
+            } else if (op == 6) {
+                /* default push size is 64 bit */
+                ot = dflag ? OT_QUAD : OT_WORD;
+            }
+        }
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            if (op >= 2 && op != 3 && op != 5)
+                gen_op_ld_T0_A0(ot + s->mem_index);
+        } else {
+            gen_op_mov_TN_reg(ot, 0, rm);
+        }
+
+        switch(op) {
+        case 0: /* inc Ev */
+            if (mod != 3)
+                opreg = OR_TMP0;
+            else
+                opreg = rm;
+            gen_inc(s, ot, opreg, 1);
+            break;
+        case 1: /* dec Ev */
+            if (mod != 3)
+                opreg = OR_TMP0;
+            else
+                opreg = rm;
+            gen_inc(s, ot, opreg, -1);
+            break;
+        case 2: /* call Ev */
+            /* XXX: optimize if memory (no 'and' is necessary) */
+            if (s->dflag == 0)
+                gen_op_andl_T0_ffff();
+            next_eip = s->pc - s->cs_base;
+            gen_movtl_T1_im(next_eip);
+            gen_push_T1(s);
+            gen_op_jmp_T0();
+            gen_eob(s);
+            break;
+        case 3: /* lcall Ev */
+            gen_op_ld_T1_A0(ot + s->mem_index);
+            gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
+            gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
+        do_lcall:
+            if (s->pe && !s->vm86) {
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_lcall_protected(cpu_tmp2_i32, cpu_T[1],
+                                           tcg_const_i32(dflag), 
+                                           tcg_const_i32(s->pc - pc_start));
+            } else {
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_lcall_real(cpu_tmp2_i32, cpu_T[1],
+                                      tcg_const_i32(dflag), 
+                                      tcg_const_i32(s->pc - s->cs_base));
+            }
+            gen_eob(s);
+            break;
+        case 4: /* jmp Ev */
+            if (s->dflag == 0)
+                gen_op_andl_T0_ffff();
+            gen_op_jmp_T0();
+            gen_eob(s);
+            break;
+        case 5: /* ljmp Ev */
+            gen_op_ld_T1_A0(ot + s->mem_index);
+            gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
+            gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
+        do_ljmp:
+            if (s->pe && !s->vm86) {
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_ljmp_protected(cpu_tmp2_i32, cpu_T[1],
+                                          tcg_const_i32(s->pc - pc_start));
+            } else {
+                gen_op_movl_seg_T0_vm(R_CS);
+                gen_op_movl_T0_T1();
+                gen_op_jmp_T0();
+            }
+            gen_eob(s);
+            break;
+        case 6: /* push Ev */
+            gen_push_T0(s);
+            break;
+        default:
+            goto illegal_op;
+        }
+        break;
+
+    case 0x84: /* test Ev, Gv */
+    case 0x85:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        gen_op_mov_TN_reg(ot, 1, reg);
+        gen_op_testl_T0_T1_cc();
+        s->cc_op = CC_OP_LOGICB + ot;
+        break;
+
+    case 0xa8: /* test eAX, Iv */
+    case 0xa9:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        val = insn_get(s, ot);
+
+        gen_op_mov_TN_reg(ot, 0, OR_EAX);
+        gen_op_movl_T1_im(val);
+        gen_op_testl_T0_T1_cc();
+        s->cc_op = CC_OP_LOGICB + ot;
+        break;
+
+    case 0x98: /* CWDE/CBW */
+#ifdef TARGET_X86_64
+        if (dflag == 2) {
+            gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
+            tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+            gen_op_mov_reg_T0(OT_QUAD, R_EAX);
+        } else
+#endif
+        if (dflag == 1) {
+            gen_op_mov_TN_reg(OT_WORD, 0, R_EAX);
+            tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
+            gen_op_mov_reg_T0(OT_LONG, R_EAX);
+        } else {
+            gen_op_mov_TN_reg(OT_BYTE, 0, R_EAX);
+            tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
+            gen_op_mov_reg_T0(OT_WORD, R_EAX);
+        }
+        break;
+    case 0x99: /* CDQ/CWD */
+#ifdef TARGET_X86_64
+        if (dflag == 2) {
+            gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX);
+            tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 63);
+            gen_op_mov_reg_T0(OT_QUAD, R_EDX);
+        } else
+#endif
+        if (dflag == 1) {
+            gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
+            tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+            tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 31);
+            gen_op_mov_reg_T0(OT_LONG, R_EDX);
+        } else {
+            gen_op_mov_TN_reg(OT_WORD, 0, R_EAX);
+            tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
+            tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 15);
+            gen_op_mov_reg_T0(OT_WORD, R_EDX);
+        }
+        break;
+    case 0x1af: /* imul Gv, Ev */
+    case 0x69: /* imul Gv, Ev, I */
+    case 0x6b:
+        ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        if (b == 0x69)
+            s->rip_offset = insn_const_size(ot);
+        else if (b == 0x6b)
+            s->rip_offset = 1;
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        if (b == 0x69) {
+            val = insn_get(s, ot);
+            gen_op_movl_T1_im(val);
+        } else if (b == 0x6b) {
+            val = (int8_t)insn_get(s, OT_BYTE);
+            gen_op_movl_T1_im(val);
+        } else {
+            gen_op_mov_TN_reg(ot, 1, reg);
+        }
+
+#ifdef TARGET_X86_64
+        if (ot == OT_QUAD) {
+            gen_helper_imulq_T0_T1(cpu_T[0], cpu_T[0], cpu_T[1]);
+        } else
+#endif
+        if (ot == OT_LONG) {
+#ifdef TARGET_X86_64
+                tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+                tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
+                tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+                tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
+                tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+#else
+                {
+                    TCGv_i64 t0, t1;
+                    t0 = tcg_temp_new_i64();
+                    t1 = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(t0, cpu_T[0]);
+                    tcg_gen_ext_i32_i64(t1, cpu_T[1]);
+                    tcg_gen_mul_i64(t0, t0, t1);
+                    tcg_gen_trunc_i64_i32(cpu_T[0], t0);
+                    tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+                    tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
+                    tcg_gen_shri_i64(t0, t0, 32);
+                    tcg_gen_trunc_i64_i32(cpu_T[1], t0);
+                    tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0);
+                }
+#endif
+        } else {
+            tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
+            tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]);
+            /* XXX: use 32 bit mul which could be faster */
+            tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+            tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
+            tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]);
+            tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
+        }
+        gen_op_mov_reg_T0(ot, reg);
+        s->cc_op = CC_OP_MULB + ot;
+        break;
+    case 0x1c0:
+    case 0x1c1: /* xadd Ev, Gv */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        mod = (modrm >> 6) & 3;
+        if (mod == 3) {
+            rm = (modrm & 7) | REX_B(s);
+            gen_op_mov_TN_reg(ot, 0, reg);
+            gen_op_mov_TN_reg(ot, 1, rm);
+            gen_op_addl_T0_T1();
+            gen_op_mov_reg_T1(ot, reg);
+            gen_op_mov_reg_T0(ot, rm);
+        } else {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_mov_TN_reg(ot, 0, reg);
+            gen_op_ld_T1_A0(ot + s->mem_index);
+            gen_op_addl_T0_T1();
+            gen_op_st_T0_A0(ot + s->mem_index);
+            gen_op_mov_reg_T1(ot, reg);
+        }
+        gen_op_update2_cc();
+        s->cc_op = CC_OP_ADDB + ot;
+        break;
+    case 0x1b0:
+    case 0x1b1: /* cmpxchg Ev, Gv */
+        {
+            int label1, label2;
+            TCGv t0, t1, t2, a0;
+
+            if ((b & 1) == 0)
+                ot = OT_BYTE;
+            else
+                ot = dflag + OT_WORD;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            t0 = tcg_temp_local_new();
+            t1 = tcg_temp_local_new();
+            t2 = tcg_temp_local_new();
+            a0 = tcg_temp_local_new();
+            gen_op_mov_v_reg(ot, t1, reg);
+            if (mod == 3) {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_mov_v_reg(ot, t0, rm);
+            } else {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                tcg_gen_mov_tl(a0, cpu_A0);
+                gen_op_ld_v(ot + s->mem_index, t0, a0);
+                rm = 0; /* avoid warning */
+            }
+            label1 = gen_new_label();
+            tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
+            gen_extu(ot, t2);
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
+            if (mod == 3) {
+                label2 = gen_new_label();
+                gen_op_mov_reg_v(ot, R_EAX, t0);
+                tcg_gen_br(label2);
+                gen_set_label(label1);
+                gen_op_mov_reg_v(ot, rm, t1);
+                gen_set_label(label2);
+            } else {
+                tcg_gen_mov_tl(t1, t0);
+                gen_op_mov_reg_v(ot, R_EAX, t0);
+                gen_set_label(label1);
+                /* always store */
+                gen_op_st_v(ot + s->mem_index, t1, a0);
+            }
+            tcg_gen_mov_tl(cpu_cc_src, t0);
+            tcg_gen_mov_tl(cpu_cc_dst, t2);
+            s->cc_op = CC_OP_SUBB + ot;
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t2);
+            tcg_temp_free(a0);
+        }
+        break;
+    case 0x1c7: /* cmpxchg8b */
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if ((mod == 3) || ((modrm & 0x38) != 0x8))
+            goto illegal_op;
+#ifdef TARGET_X86_64
+        if (dflag == 2) {
+            if (!(s->cpuid_ext_features & CPUID_EXT_CX16))
+                goto illegal_op;
+            gen_jmp_im(pc_start - s->cs_base);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_helper_cmpxchg16b(cpu_A0);
+        } else
+#endif        
+        {
+            if (!(s->cpuid_features & CPUID_CX8))
+                goto illegal_op;
+            gen_jmp_im(pc_start - s->cs_base);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_helper_cmpxchg8b(cpu_A0);
+        }
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+
+        /**************************/
+        /* push/pop */
+    case 0x50 ... 0x57: /* push */
+        gen_op_mov_TN_reg(OT_LONG, 0, (b & 7) | REX_B(s));
+        gen_push_T0(s);
+        break;
+    case 0x58 ... 0x5f: /* pop */
+        if (CODE64(s)) {
+            ot = dflag ? OT_QUAD : OT_WORD;
+        } else {
+            ot = dflag + OT_WORD;
+        }
+        gen_pop_T0(s);
+        /* NOTE: order is important for pop %sp */
+        gen_pop_update(s);
+        gen_op_mov_reg_T0(ot, (b & 7) | REX_B(s));
+        break;
+    case 0x60: /* pusha */
+        if (CODE64(s))
+            goto illegal_op;
+        gen_pusha(s);
+        break;
+    case 0x61: /* popa */
+        if (CODE64(s))
+            goto illegal_op;
+        gen_popa(s);
+        break;
+    case 0x68: /* push Iv */
+    case 0x6a:
+        if (CODE64(s)) {
+            ot = dflag ? OT_QUAD : OT_WORD;
+        } else {
+            ot = dflag + OT_WORD;
+        }
+        if (b == 0x68)
+            val = insn_get(s, ot);
+        else
+            val = (int8_t)insn_get(s, OT_BYTE);
+        gen_op_movl_T0_im(val);
+        gen_push_T0(s);
+        break;
+    case 0x8f: /* pop Ev */
+        if (CODE64(s)) {
+            ot = dflag ? OT_QUAD : OT_WORD;
+        } else {
+            ot = dflag + OT_WORD;
+        }
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        gen_pop_T0(s);
+        if (mod == 3) {
+            /* NOTE: order is important for pop %sp */
+            gen_pop_update(s);
+            rm = (modrm & 7) | REX_B(s);
+            gen_op_mov_reg_T0(ot, rm);
+        } else {
+            /* NOTE: order is important too for MMU exceptions */
+            s->popl_esp_hack = 1 << ot;
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+            s->popl_esp_hack = 0;
+            gen_pop_update(s);
+        }
+        break;
+    case 0xc8: /* enter */
+        {
+            int level;
+            val = lduw_code(s->pc);
+            s->pc += 2;
+            level = ldub_code(s->pc++);
+            gen_enter(s, val, level);
+        }
+        break;
+    case 0xc9: /* leave */
+        /* XXX: exception not precise (ESP is updated before potential exception) */
+        if (CODE64(s)) {
+            gen_op_mov_TN_reg(OT_QUAD, 0, R_EBP);
+            gen_op_mov_reg_T0(OT_QUAD, R_ESP);
+        } else if (s->ss32) {
+            gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
+            gen_op_mov_reg_T0(OT_LONG, R_ESP);
+        } else {
+            gen_op_mov_TN_reg(OT_WORD, 0, R_EBP);
+            gen_op_mov_reg_T0(OT_WORD, R_ESP);
+        }
+        gen_pop_T0(s);
+        if (CODE64(s)) {
+            ot = dflag ? OT_QUAD : OT_WORD;
+        } else {
+            ot = dflag + OT_WORD;
+        }
+        gen_op_mov_reg_T0(ot, R_EBP);
+        gen_pop_update(s);
+        break;
+    case 0x06: /* push es */
+    case 0x0e: /* push cs */
+    case 0x16: /* push ss */
+    case 0x1e: /* push ds */
+        if (CODE64(s))
+            goto illegal_op;
+        gen_op_movl_T0_seg(b >> 3);
+        gen_push_T0(s);
+        break;
+    case 0x1a0: /* push fs */
+    case 0x1a8: /* push gs */
+        gen_op_movl_T0_seg((b >> 3) & 7);
+        gen_push_T0(s);
+        break;
+    case 0x07: /* pop es */
+    case 0x17: /* pop ss */
+    case 0x1f: /* pop ds */
+        if (CODE64(s))
+            goto illegal_op;
+        reg = b >> 3;
+        gen_pop_T0(s);
+        gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
+        gen_pop_update(s);
+        if (reg == R_SS) {
+            /* if reg == SS, inhibit interrupts/trace. */
+            /* If several instructions disable interrupts, only the
+               _first_ does it */
+            if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                gen_helper_set_inhibit_irq();
+            s->tf = 0;
+        }
+        if (s->is_jmp) {
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+    case 0x1a1: /* pop fs */
+    case 0x1a9: /* pop gs */
+        gen_pop_T0(s);
+        gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
+        gen_pop_update(s);
+        if (s->is_jmp) {
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+
+        /**************************/
+        /* mov */
+    case 0x88:
+    case 0x89: /* mov Gv, Ev */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+
+        /* generate a generic store */
+        gen_ldst_modrm(s, modrm, ot, reg, 1);
+        break;
+    case 0xc6:
+    case 0xc7: /* mov Ev, Iv */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if (mod != 3) {
+            s->rip_offset = insn_const_size(ot);
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+        }
+        val = insn_get(s, ot);
+        gen_op_movl_T0_im(val);
+        if (mod != 3)
+            gen_op_st_T0_A0(ot + s->mem_index);
+        else
+            gen_op_mov_reg_T0(ot, (modrm & 7) | REX_B(s));
+        break;
+    case 0x8a:
+    case 0x8b: /* mov Ev, Gv */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = OT_WORD + dflag;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        gen_op_mov_reg_T0(ot, reg);
+        break;
+    case 0x8e: /* mov seg, Gv */
+        modrm = ldub_code(s->pc++);
+        reg = (modrm >> 3) & 7;
+        if (reg >= 6 || reg == R_CS)
+            goto illegal_op;
+        gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+        gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
+        if (reg == R_SS) {
+            /* if reg == SS, inhibit interrupts/trace */
+            /* If several instructions disable interrupts, only the
+               _first_ does it */
+            if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                gen_helper_set_inhibit_irq();
+            s->tf = 0;
+        }
+        if (s->is_jmp) {
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+    case 0x8c: /* mov Gv, seg */
+        modrm = ldub_code(s->pc++);
+        reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        if (reg >= 6)
+            goto illegal_op;
+        gen_op_movl_T0_seg(reg);
+        if (mod == 3)
+            ot = OT_WORD + dflag;
+        else
+            ot = OT_WORD;
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+        break;
+
+    case 0x1b6: /* movzbS Gv, Eb */
+    case 0x1b7: /* movzwS Gv, Eb */
+    case 0x1be: /* movsbS Gv, Eb */
+    case 0x1bf: /* movswS Gv, Eb */
+        {
+            int d_ot;
+            /* d_ot is the size of destination */
+            d_ot = dflag + OT_WORD;
+            /* ot is the size of source */
+            ot = (b & 1) + OT_BYTE;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            rm = (modrm & 7) | REX_B(s);
+
+            if (mod == 3) {
+                gen_op_mov_TN_reg(ot, 0, rm);
+                switch(ot | (b & 8)) {
+                case OT_BYTE:
+                    tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]);
+                    break;
+                case OT_BYTE | 8:
+                    tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
+                    break;
+                case OT_WORD:
+                    tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]);
+                    break;
+                default:
+                case OT_WORD | 8:
+                    tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
+                    break;
+                }
+                gen_op_mov_reg_T0(d_ot, reg);
+            } else {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                if (b & 8) {
+                    gen_op_lds_T0_A0(ot + s->mem_index);
+                } else {
+                    gen_op_ldu_T0_A0(ot + s->mem_index);
+                }
+                gen_op_mov_reg_T0(d_ot, reg);
+            }
+        }
+        break;
+
+    case 0x8d: /* lea */
+        ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
+        reg = ((modrm >> 3) & 7) | rex_r;
+        /* we must ensure that no segment is added */
+        s->override = -1;
+        val = s->addseg;
+        s->addseg = 0;
+        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+        s->addseg = val;
+        gen_op_mov_reg_A0(ot - OT_WORD, reg);
+        break;
+
+    case 0xa0: /* mov EAX, Ov */
+    case 0xa1:
+    case 0xa2: /* mov Ov, EAX */
+    case 0xa3:
+        {
+            target_ulong offset_addr;
+
+            if ((b & 1) == 0)
+                ot = OT_BYTE;
+            else
+                ot = dflag + OT_WORD;
+#ifdef TARGET_X86_64
+            if (s->aflag == 2) {
+                offset_addr = ldq_code(s->pc);
+                s->pc += 8;
+                gen_op_movq_A0_im(offset_addr);
+            } else
+#endif
+            {
+                if (s->aflag) {
+                    offset_addr = insn_get(s, OT_LONG);
+                } else {
+                    offset_addr = insn_get(s, OT_WORD);
+                }
+                gen_op_movl_A0_im(offset_addr);
+            }
+            gen_add_A0_ds_seg(s);
+            if ((b & 2) == 0) {
+                gen_op_ld_T0_A0(ot + s->mem_index);
+                gen_op_mov_reg_T0(ot, R_EAX);
+            } else {
+                gen_op_mov_TN_reg(ot, 0, R_EAX);
+                gen_op_st_T0_A0(ot + s->mem_index);
+            }
+        }
+        break;
+    case 0xd7: /* xlat */
+#ifdef TARGET_X86_64
+        if (s->aflag == 2) {
+            gen_op_movq_A0_reg(R_EBX);
+            gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX);
+            tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff);
+            tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]);
+        } else
+#endif
+        {
+            gen_op_movl_A0_reg(R_EBX);
+            gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
+            tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff);
+            tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]);
+            if (s->aflag == 0)
+                gen_op_andl_A0_ffff();
+            else
+                tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
+        }
+        gen_add_A0_ds_seg(s);
+        gen_op_ldu_T0_A0(OT_BYTE + s->mem_index);
+        gen_op_mov_reg_T0(OT_BYTE, R_EAX);
+        break;
+    case 0xb0 ... 0xb7: /* mov R, Ib */
+        val = insn_get(s, OT_BYTE);
+        gen_op_movl_T0_im(val);
+        gen_op_mov_reg_T0(OT_BYTE, (b & 7) | REX_B(s));
+        break;
+    case 0xb8 ... 0xbf: /* mov R, Iv */
+#ifdef TARGET_X86_64
+        if (dflag == 2) {
+            uint64_t tmp;
+            /* 64 bit case */
+            tmp = ldq_code(s->pc);
+            s->pc += 8;
+            reg = (b & 7) | REX_B(s);
+            gen_movtl_T0_im(tmp);
+            gen_op_mov_reg_T0(OT_QUAD, reg);
+        } else
+#endif
+        {
+            ot = dflag ? OT_LONG : OT_WORD;
+            val = insn_get(s, ot);
+            reg = (b & 7) | REX_B(s);
+            gen_op_movl_T0_im(val);
+            gen_op_mov_reg_T0(ot, reg);
+        }
+        break;
+
+    case 0x91 ... 0x97: /* xchg R, EAX */
+    do_xchg_reg_eax:
+        ot = dflag + OT_WORD;
+        reg = (b & 7) | REX_B(s);
+        rm = R_EAX;
+        goto do_xchg_reg;
+    case 0x86:
+    case 0x87: /* xchg Ev, Gv */
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        mod = (modrm >> 6) & 3;
+        if (mod == 3) {
+            rm = (modrm & 7) | REX_B(s);
+        do_xchg_reg:
+            gen_op_mov_TN_reg(ot, 0, reg);
+            gen_op_mov_TN_reg(ot, 1, rm);
+            gen_op_mov_reg_T0(ot, rm);
+            gen_op_mov_reg_T1(ot, reg);
+        } else {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_mov_TN_reg(ot, 0, reg);
+            /* for xchg, lock is implicit */
+            if (!(prefixes & PREFIX_LOCK))
+                gen_helper_lock();
+            gen_op_ld_T1_A0(ot + s->mem_index);
+            gen_op_st_T0_A0(ot + s->mem_index);
+            if (!(prefixes & PREFIX_LOCK))
+                gen_helper_unlock();
+            gen_op_mov_reg_T1(ot, reg);
+        }
+        break;
+    case 0xc4: /* les Gv */
+        if (CODE64(s))
+            goto illegal_op;
+        op = R_ES;
+        goto do_lxx;
+    case 0xc5: /* lds Gv */
+        if (CODE64(s))
+            goto illegal_op;
+        op = R_DS;
+        goto do_lxx;
+    case 0x1b2: /* lss Gv */
+        op = R_SS;
+        goto do_lxx;
+    case 0x1b4: /* lfs Gv */
+        op = R_FS;
+        goto do_lxx;
+    case 0x1b5: /* lgs Gv */
+        op = R_GS;
+    do_lxx:
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
+        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+        gen_op_ld_T1_A0(ot + s->mem_index);
+        gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
+        /* load the segment first to handle exceptions properly */
+        gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
+        gen_movl_seg_T0(s, op, pc_start - s->cs_base);
+        /* then put the data */
+        gen_op_mov_reg_T1(ot, reg);
+        if (s->is_jmp) {
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+
+        /************************/
+        /* shifts */
+    case 0xc0:
+    case 0xc1:
+        /* shift Ev,Ib */
+        shift = 2;
+    grp2:
+        {
+            if ((b & 1) == 0)
+                ot = OT_BYTE;
+            else
+                ot = dflag + OT_WORD;
+
+            modrm = ldub_code(s->pc++);
+            mod = (modrm >> 6) & 3;
+            op = (modrm >> 3) & 7;
+
+            if (mod != 3) {
+                if (shift == 2) {
+                    s->rip_offset = 1;
+                }
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                opreg = OR_TMP0;
+            } else {
+                opreg = (modrm & 7) | REX_B(s);
+            }
+
+            /* simpler op */
+            if (shift == 0) {
+                gen_shift(s, op, ot, opreg, OR_ECX);
+            } else {
+                if (shift == 2) {
+                    shift = ldub_code(s->pc++);
+                }
+                gen_shifti(s, op, ot, opreg, shift);
+            }
+        }
+        break;
+    case 0xd0:
+    case 0xd1:
+        /* shift Ev,1 */
+        shift = 1;
+        goto grp2;
+    case 0xd2:
+    case 0xd3:
+        /* shift Ev,cl */
+        shift = 0;
+        goto grp2;
+
+    case 0x1a4: /* shld imm */
+        op = 0;
+        shift = 1;
+        goto do_shiftd;
+    case 0x1a5: /* shld cl */
+        op = 0;
+        shift = 0;
+        goto do_shiftd;
+    case 0x1ac: /* shrd imm */
+        op = 1;
+        shift = 1;
+        goto do_shiftd;
+    case 0x1ad: /* shrd cl */
+        op = 1;
+        shift = 0;
+    do_shiftd:
+        ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        rm = (modrm & 7) | REX_B(s);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            opreg = OR_TMP0;
+        } else {
+            opreg = rm;
+        }
+        gen_op_mov_TN_reg(ot, 1, reg);
+
+        if (shift) {
+            val = ldub_code(s->pc++);
+            tcg_gen_movi_tl(cpu_T3, val);
+        } else {
+            tcg_gen_mov_tl(cpu_T3, cpu_regs[R_ECX]);
+        }
+        gen_shiftd_rm_T1_T3(s, ot, opreg, op);
+        break;
+
+        /************************/
+        /* floats */
+    case 0xd8 ... 0xdf:
+        if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
+            /* if CR0.EM or CR0.TS are set, generate an FPU exception */
+            /* XXX: what to do if illegal op ? */
+            gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+            break;
+        }
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        rm = modrm & 7;
+        op = ((b & 7) << 3) | ((modrm >> 3) & 7);
+        if (mod != 3) {
+            /* memory op */
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            switch(op) {
+            case 0x00 ... 0x07: /* fxxxs */
+            case 0x10 ... 0x17: /* fixxxl */
+            case 0x20 ... 0x27: /* fxxxl */
+            case 0x30 ... 0x37: /* fixxx */
+                {
+                    int op1;
+                    op1 = op & 7;
+
+                    switch(op >> 4) {
+                    case 0:
+                        gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_flds_FT0(cpu_tmp2_i32);
+                        break;
+                    case 1:
+                        gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_fildl_FT0(cpu_tmp2_i32);
+                        break;
+                    case 2:
+                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
+                                          (s->mem_index >> 2) - 1);
+                        gen_helper_fldl_FT0(cpu_tmp1_i64);
+                        break;
+                    case 3:
+                    default:
+                        gen_op_lds_T0_A0(OT_WORD + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_fildl_FT0(cpu_tmp2_i32);
+                        break;
+                    }
+
+                    gen_helper_fp_arith_ST0_FT0(op1);
+                    if (op1 == 3) {
+                        /* fcomp needs pop */
+                        gen_helper_fpop();
+                    }
+                }
+                break;
+            case 0x08: /* flds */
+            case 0x0a: /* fsts */
+            case 0x0b: /* fstps */
+            case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */
+            case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */
+            case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */
+                switch(op & 7) {
+                case 0:
+                    switch(op >> 4) {
+                    case 0:
+                        gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_flds_ST0(cpu_tmp2_i32);
+                        break;
+                    case 1:
+                        gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_fildl_ST0(cpu_tmp2_i32);
+                        break;
+                    case 2:
+                        tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
+                                          (s->mem_index >> 2) - 1);
+                        gen_helper_fldl_ST0(cpu_tmp1_i64);
+                        break;
+                    case 3:
+                    default:
+                        gen_op_lds_T0_A0(OT_WORD + s->mem_index);
+                        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                        gen_helper_fildl_ST0(cpu_tmp2_i32);
+                        break;
+                    }
+                    break;
+                case 1:
+                    /* XXX: the corresponding CPUID bit must be tested ! */
+                    switch(op >> 4) {
+                    case 1:
+                        gen_helper_fisttl_ST0(cpu_tmp2_i32);
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        gen_op_st_T0_A0(OT_LONG + s->mem_index);
+                        break;
+                    case 2:
+                        gen_helper_fisttll_ST0(cpu_tmp1_i64);
+                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
+                                          (s->mem_index >> 2) - 1);
+                        break;
+                    case 3:
+                    default:
+                        gen_helper_fistt_ST0(cpu_tmp2_i32);
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        gen_op_st_T0_A0(OT_WORD + s->mem_index);
+                        break;
+                    }
+                    gen_helper_fpop();
+                    break;
+                default:
+                    switch(op >> 4) {
+                    case 0:
+                        gen_helper_fsts_ST0(cpu_tmp2_i32);
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        gen_op_st_T0_A0(OT_LONG + s->mem_index);
+                        break;
+                    case 1:
+                        gen_helper_fistl_ST0(cpu_tmp2_i32);
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        gen_op_st_T0_A0(OT_LONG + s->mem_index);
+                        break;
+                    case 2:
+                        gen_helper_fstl_ST0(cpu_tmp1_i64);
+                        tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
+                                          (s->mem_index >> 2) - 1);
+                        break;
+                    case 3:
+                    default:
+                        gen_helper_fist_ST0(cpu_tmp2_i32);
+                        tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                        gen_op_st_T0_A0(OT_WORD + s->mem_index);
+                        break;
+                    }
+                    if ((op & 7) == 3)
+                        gen_helper_fpop();
+                    break;
+                }
+                break;
+            case 0x0c: /* fldenv mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fldenv(
+                                   cpu_A0, tcg_const_i32(s->dflag));
+                break;
+            case 0x0d: /* fldcw mem */
+                gen_op_ld_T0_A0(OT_WORD + s->mem_index);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_fldcw(cpu_tmp2_i32);
+                break;
+            case 0x0e: /* fnstenv mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fstenv(cpu_A0, tcg_const_i32(s->dflag));
+                break;
+            case 0x0f: /* fnstcw mem */
+                gen_helper_fnstcw(cpu_tmp2_i32);
+                tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                gen_op_st_T0_A0(OT_WORD + s->mem_index);
+                break;
+            case 0x1d: /* fldt mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fldt_ST0(cpu_A0);
+                break;
+            case 0x1f: /* fstpt mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fstt_ST0(cpu_A0);
+                gen_helper_fpop();
+                break;
+            case 0x2c: /* frstor mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_frstor(cpu_A0, tcg_const_i32(s->dflag));
+                break;
+            case 0x2e: /* fnsave mem */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fsave(cpu_A0, tcg_const_i32(s->dflag));
+                break;
+            case 0x2f: /* fnstsw mem */
+                gen_helper_fnstsw(cpu_tmp2_i32);
+                tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                gen_op_st_T0_A0(OT_WORD + s->mem_index);
+                break;
+            case 0x3c: /* fbld */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fbld_ST0(cpu_A0);
+                break;
+            case 0x3e: /* fbstp */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                gen_helper_fbst_ST0(cpu_A0);
+                gen_helper_fpop();
+                break;
+            case 0x3d: /* fildll */
+                tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, 
+                                  (s->mem_index >> 2) - 1);
+                gen_helper_fildll_ST0(cpu_tmp1_i64);
+                break;
+            case 0x3f: /* fistpll */
+                gen_helper_fistll_ST0(cpu_tmp1_i64);
+                tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, 
+                                  (s->mem_index >> 2) - 1);
+                gen_helper_fpop();
+                break;
+            default:
+                goto illegal_op;
+            }
+        } else {
+            /* register float ops */
+            opreg = rm;
+
+            switch(op) {
+            case 0x08: /* fld sti */
+                gen_helper_fpush();
+                gen_helper_fmov_ST0_STN(tcg_const_i32((opreg + 1) & 7));
+                break;
+            case 0x09: /* fxchg sti */
+            case 0x29: /* fxchg4 sti, undocumented op */
+            case 0x39: /* fxchg7 sti, undocumented op */
+                gen_helper_fxchg_ST0_STN(tcg_const_i32(opreg));
+                break;
+            case 0x0a: /* grp d9/2 */
+                switch(rm) {
+                case 0: /* fnop */
+                    /* check exceptions (FreeBSD FPU probe) */
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(pc_start - s->cs_base);
+                    gen_helper_fwait();
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x0c: /* grp d9/4 */
+                switch(rm) {
+                case 0: /* fchs */
+                    gen_helper_fchs_ST0();
+                    break;
+                case 1: /* fabs */
+                    gen_helper_fabs_ST0();
+                    break;
+                case 4: /* ftst */
+                    gen_helper_fldz_FT0();
+                    gen_helper_fcom_ST0_FT0();
+                    break;
+                case 5: /* fxam */
+                    gen_helper_fxam_ST0();
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x0d: /* grp d9/5 */
+                {
+                    switch(rm) {
+                    case 0:
+                        gen_helper_fpush();
+                        gen_helper_fld1_ST0();
+                        break;
+                    case 1:
+                        gen_helper_fpush();
+                        gen_helper_fldl2t_ST0();
+                        break;
+                    case 2:
+                        gen_helper_fpush();
+                        gen_helper_fldl2e_ST0();
+                        break;
+                    case 3:
+                        gen_helper_fpush();
+                        gen_helper_fldpi_ST0();
+                        break;
+                    case 4:
+                        gen_helper_fpush();
+                        gen_helper_fldlg2_ST0();
+                        break;
+                    case 5:
+                        gen_helper_fpush();
+                        gen_helper_fldln2_ST0();
+                        break;
+                    case 6:
+                        gen_helper_fpush();
+                        gen_helper_fldz_ST0();
+                        break;
+                    default:
+                        goto illegal_op;
+                    }
+                }
+                break;
+            case 0x0e: /* grp d9/6 */
+                switch(rm) {
+                case 0: /* f2xm1 */
+                    gen_helper_f2xm1();
+                    break;
+                case 1: /* fyl2x */
+                    gen_helper_fyl2x();
+                    break;
+                case 2: /* fptan */
+                    gen_helper_fptan();
+                    break;
+                case 3: /* fpatan */
+                    gen_helper_fpatan();
+                    break;
+                case 4: /* fxtract */
+                    gen_helper_fxtract();
+                    break;
+                case 5: /* fprem1 */
+                    gen_helper_fprem1();
+                    break;
+                case 6: /* fdecstp */
+                    gen_helper_fdecstp();
+                    break;
+                default:
+                case 7: /* fincstp */
+                    gen_helper_fincstp();
+                    break;
+                }
+                break;
+            case 0x0f: /* grp d9/7 */
+                switch(rm) {
+                case 0: /* fprem */
+                    gen_helper_fprem();
+                    break;
+                case 1: /* fyl2xp1 */
+                    gen_helper_fyl2xp1();
+                    break;
+                case 2: /* fsqrt */
+                    gen_helper_fsqrt();
+                    break;
+                case 3: /* fsincos */
+                    gen_helper_fsincos();
+                    break;
+                case 5: /* fscale */
+                    gen_helper_fscale();
+                    break;
+                case 4: /* frndint */
+                    gen_helper_frndint();
+                    break;
+                case 6: /* fsin */
+                    gen_helper_fsin();
+                    break;
+                default:
+                case 7: /* fcos */
+                    gen_helper_fcos();
+                    break;
+                }
+                break;
+            case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
+            case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
+            case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
+                {
+                    int op1;
+
+                    op1 = op & 7;
+                    if (op >= 0x20) {
+                        gen_helper_fp_arith_STN_ST0(op1, opreg);
+                        if (op >= 0x30)
+                            gen_helper_fpop();
+                    } else {
+                        gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                        gen_helper_fp_arith_ST0_FT0(op1);
+                    }
+                }
+                break;
+            case 0x02: /* fcom */
+            case 0x22: /* fcom2, undocumented op */
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fcom_ST0_FT0();
+                break;
+            case 0x03: /* fcomp */
+            case 0x23: /* fcomp3, undocumented op */
+            case 0x32: /* fcomp5, undocumented op */
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fcom_ST0_FT0();
+                gen_helper_fpop();
+                break;
+            case 0x15: /* da/5 */
+                switch(rm) {
+                case 1: /* fucompp */
+                    gen_helper_fmov_FT0_STN(tcg_const_i32(1));
+                    gen_helper_fucom_ST0_FT0();
+                    gen_helper_fpop();
+                    gen_helper_fpop();
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x1c:
+                switch(rm) {
+                case 0: /* feni (287 only, just do nop here) */
+                    break;
+                case 1: /* fdisi (287 only, just do nop here) */
+                    break;
+                case 2: /* fclex */
+                    gen_helper_fclex();
+                    break;
+                case 3: /* fninit */
+                    gen_helper_fninit();
+                    break;
+                case 4: /* fsetpm (287 only, just do nop here) */
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x1d: /* fucomi */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fucomi_ST0_FT0();
+                s->cc_op = CC_OP_EFLAGS;
+                break;
+            case 0x1e: /* fcomi */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fcomi_ST0_FT0();
+                s->cc_op = CC_OP_EFLAGS;
+                break;
+            case 0x28: /* ffree sti */
+                gen_helper_ffree_STN(tcg_const_i32(opreg));
+                break;
+            case 0x2a: /* fst sti */
+                gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
+                break;
+            case 0x2b: /* fstp sti */
+            case 0x0b: /* fstp1 sti, undocumented op */
+            case 0x3a: /* fstp8 sti, undocumented op */
+            case 0x3b: /* fstp9 sti, undocumented op */
+                gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
+                gen_helper_fpop();
+                break;
+            case 0x2c: /* fucom st(i) */
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fucom_ST0_FT0();
+                break;
+            case 0x2d: /* fucomp st(i) */
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fucom_ST0_FT0();
+                gen_helper_fpop();
+                break;
+            case 0x33: /* de/3 */
+                switch(rm) {
+                case 1: /* fcompp */
+                    gen_helper_fmov_FT0_STN(tcg_const_i32(1));
+                    gen_helper_fcom_ST0_FT0();
+                    gen_helper_fpop();
+                    gen_helper_fpop();
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x38: /* ffreep sti, undocumented op */
+                gen_helper_ffree_STN(tcg_const_i32(opreg));
+                gen_helper_fpop();
+                break;
+            case 0x3c: /* df/4 */
+                switch(rm) {
+                case 0:
+                    gen_helper_fnstsw(cpu_tmp2_i32);
+                    tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
+                    gen_op_mov_reg_T0(OT_WORD, R_EAX);
+                    break;
+                default:
+                    goto illegal_op;
+                }
+                break;
+            case 0x3d: /* fucomip */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fucomi_ST0_FT0();
+                gen_helper_fpop();
+                s->cc_op = CC_OP_EFLAGS;
+                break;
+            case 0x3e: /* fcomip */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+                gen_helper_fcomi_ST0_FT0();
+                gen_helper_fpop();
+                s->cc_op = CC_OP_EFLAGS;
+                break;
+            case 0x10 ... 0x13: /* fcmovxx */
+            case 0x18 ... 0x1b:
+                {
+                    int op1, l1;
+                    static const uint8_t fcmov_cc[8] = {
+                        (JCC_B << 1),
+                        (JCC_Z << 1),
+                        (JCC_BE << 1),
+                        (JCC_P << 1),
+                    };
+                    op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
+                    l1 = gen_new_label();
+                    gen_jcc1(s, s->cc_op, op1, l1);
+                    gen_helper_fmov_ST0_STN(tcg_const_i32(opreg));
+                    gen_set_label(l1);
+                }
+                break;
+            default:
+                goto illegal_op;
+            }
+        }
+        break;
+        /************************/
+        /* string ops */
+
+    case 0xa4: /* movsS */
+    case 0xa5:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
+        } else {
+            gen_movs(s, ot);
+        }
+        break;
+
+    case 0xaa: /* stosS */
+    case 0xab:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
+        } else {
+            gen_stos(s, ot);
+        }
+        break;
+    case 0xac: /* lodsS */
+    case 0xad:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
+        } else {
+            gen_lods(s, ot);
+        }
+        break;
+    case 0xae: /* scasS */
+    case 0xaf:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        if (prefixes & PREFIX_REPNZ) {
+            gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
+        } else if (prefixes & PREFIX_REPZ) {
+            gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
+        } else {
+            gen_scas(s, ot);
+            s->cc_op = CC_OP_SUBB + ot;
+        }
+        break;
+
+    case 0xa6: /* cmpsS */
+    case 0xa7:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag + OT_WORD;
+        if (prefixes & PREFIX_REPNZ) {
+            gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
+        } else if (prefixes & PREFIX_REPZ) {
+            gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
+        } else {
+            gen_cmps(s, ot);
+            s->cc_op = CC_OP_SUBB + ot;
+        }
+        break;
+    case 0x6c: /* insS */
+    case 0x6d:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
+        gen_op_andl_T0_ffff();
+        gen_check_io(s, ot, pc_start - s->cs_base, 
+                     SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
+        } else {
+            gen_ins(s, ot);
+            if (use_icount) {
+                gen_jmp(s, s->pc - s->cs_base);
+            }
+        }
+        break;
+    case 0x6e: /* outsS */
+    case 0x6f:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
+        gen_op_andl_T0_ffff();
+        gen_check_io(s, ot, pc_start - s->cs_base,
+                     svm_is_rep(prefixes) | 4);
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
+        } else {
+            gen_outs(s, ot);
+            if (use_icount) {
+                gen_jmp(s, s->pc - s->cs_base);
+            }
+        }
+        break;
+
+        /************************/
+        /* port I/O */
+
+    case 0xe4:
+    case 0xe5:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        val = ldub_code(s->pc++);
+        gen_op_movl_T0_im(val);
+        gen_check_io(s, ot, pc_start - s->cs_base,
+                     SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+        if (use_icount)
+            gen_io_start();
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32);
+        gen_op_mov_reg_T1(ot, R_EAX);
+        if (use_icount) {
+            gen_io_end();
+            gen_jmp(s, s->pc - s->cs_base);
+        }
+        break;
+    case 0xe6:
+    case 0xe7:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        val = ldub_code(s->pc++);
+        gen_op_movl_T0_im(val);
+        gen_check_io(s, ot, pc_start - s->cs_base,
+                     svm_is_rep(prefixes));
+        gen_op_mov_TN_reg(ot, 1, R_EAX);
+
+        if (use_icount)
+            gen_io_start();
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
+        tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
+        gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
+        if (use_icount) {
+            gen_io_end();
+            gen_jmp(s, s->pc - s->cs_base);
+        }
+        break;
+    case 0xec:
+    case 0xed:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
+        gen_op_andl_T0_ffff();
+        gen_check_io(s, ot, pc_start - s->cs_base,
+                     SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+        if (use_icount)
+            gen_io_start();
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32);
+        gen_op_mov_reg_T1(ot, R_EAX);
+        if (use_icount) {
+            gen_io_end();
+            gen_jmp(s, s->pc - s->cs_base);
+        }
+        break;
+    case 0xee:
+    case 0xef:
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
+        gen_op_andl_T0_ffff();
+        gen_check_io(s, ot, pc_start - s->cs_base,
+                     svm_is_rep(prefixes));
+        gen_op_mov_TN_reg(ot, 1, R_EAX);
+
+        if (use_icount)
+            gen_io_start();
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
+        tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
+        gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
+        if (use_icount) {
+            gen_io_end();
+            gen_jmp(s, s->pc - s->cs_base);
+        }
+        break;
+
+        /************************/
+        /* control */
+    case 0xc2: /* ret im */
+        val = ldsw_code(s->pc);
+        s->pc += 2;
+        gen_pop_T0(s);
+        if (CODE64(s) && s->dflag)
+            s->dflag = 2;
+        gen_stack_update(s, val + (2 << s->dflag));
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
+        gen_op_jmp_T0();
+        gen_eob(s);
+        break;
+    case 0xc3: /* ret */
+        gen_pop_T0(s);
+        gen_pop_update(s);
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
+        gen_op_jmp_T0();
+        gen_eob(s);
+        break;
+    case 0xca: /* lret im */
+        val = ldsw_code(s->pc);
+        s->pc += 2;
+    do_lret:
+        if (s->pe && !s->vm86) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_lret_protected(tcg_const_i32(s->dflag),
+                                      tcg_const_i32(val));
+        } else {
+            gen_stack_A0(s);
+            /* pop offset */
+            gen_op_ld_T0_A0(1 + s->dflag + s->mem_index);
+            if (s->dflag == 0)
+                gen_op_andl_T0_ffff();
+            /* NOTE: keeping EIP updated is not a problem in case of
+               exception */
+            gen_op_jmp_T0();
+            /* pop selector */
+            gen_op_addl_A0_im(2 << s->dflag);
+            gen_op_ld_T0_A0(1 + s->dflag + s->mem_index);
+            gen_op_movl_seg_T0_vm(R_CS);
+            /* add stack offset */
+            gen_stack_update(s, val + (4 << s->dflag));
+        }
+        gen_eob(s);
+        break;
+    case 0xcb: /* lret */
+        val = 0;
+        goto do_lret;
+    case 0xcf: /* iret */
+        gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
+        if (!s->pe) {
+            /* real mode */
+            gen_helper_iret_real(tcg_const_i32(s->dflag));
+            s->cc_op = CC_OP_EFLAGS;
+        } else if (s->vm86) {
+            if (s->iopl != 3) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_helper_iret_real(tcg_const_i32(s->dflag));
+                s->cc_op = CC_OP_EFLAGS;
+            }
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_iret_protected(tcg_const_i32(s->dflag), 
+                                      tcg_const_i32(s->pc - s->cs_base));
+            s->cc_op = CC_OP_EFLAGS;
+        }
+        gen_eob(s);
+        break;
+    case 0xe8: /* call im */
+        {
+            if (dflag)
+                tval = (int32_t)insn_get(s, OT_LONG);
+            else
+                tval = (int16_t)insn_get(s, OT_WORD);
+            next_eip = s->pc - s->cs_base;
+            tval += next_eip;
+            if (s->dflag == 0)
+                tval &= 0xffff;
+            else if(!CODE64(s))
+                tval &= 0xffffffff;
+            gen_movtl_T0_im(next_eip);
+            gen_push_T0(s);
+            gen_jmp(s, tval);
+        }
+        break;
+    case 0x9a: /* lcall im */
+        {
+            unsigned int selector, offset;
+
+            if (CODE64(s))
+                goto illegal_op;
+            ot = dflag ? OT_LONG : OT_WORD;
+            offset = insn_get(s, ot);
+            selector = insn_get(s, OT_WORD);
+
+            gen_op_movl_T0_im(selector);
+            gen_op_movl_T1_imu(offset);
+        }
+        goto do_lcall;
+    case 0xe9: /* jmp im */
+        if (dflag)
+            tval = (int32_t)insn_get(s, OT_LONG);
+        else
+            tval = (int16_t)insn_get(s, OT_WORD);
+        tval += s->pc - s->cs_base;
+        if (s->dflag == 0)
+            tval &= 0xffff;
+        else if(!CODE64(s))
+            tval &= 0xffffffff;
+        gen_jmp(s, tval);
+        break;
+    case 0xea: /* ljmp im */
+        {
+            unsigned int selector, offset;
+
+            if (CODE64(s))
+                goto illegal_op;
+            ot = dflag ? OT_LONG : OT_WORD;
+            offset = insn_get(s, ot);
+            selector = insn_get(s, OT_WORD);
+
+            gen_op_movl_T0_im(selector);
+            gen_op_movl_T1_imu(offset);
+        }
+        goto do_ljmp;
+    case 0xeb: /* jmp Jb */
+        tval = (int8_t)insn_get(s, OT_BYTE);
+        tval += s->pc - s->cs_base;
+        if (s->dflag == 0)
+            tval &= 0xffff;
+        gen_jmp(s, tval);
+        break;
+    case 0x70 ... 0x7f: /* jcc Jb */
+        tval = (int8_t)insn_get(s, OT_BYTE);
+        goto do_jcc;
+    case 0x180 ... 0x18f: /* jcc Jv */
+        if (dflag) {
+            tval = (int32_t)insn_get(s, OT_LONG);
+        } else {
+            tval = (int16_t)insn_get(s, OT_WORD);
+        }
+    do_jcc:
+        next_eip = s->pc - s->cs_base;
+        tval += next_eip;
+        if (s->dflag == 0)
+            tval &= 0xffff;
+        gen_jcc(s, b, tval, next_eip);
+        break;
+
+    case 0x190 ... 0x19f: /* setcc Gv */
+        modrm = ldub_code(s->pc++);
+        gen_setcc(s, b);
+        gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
+        break;
+    case 0x140 ... 0x14f: /* cmov Gv, Ev */
+        {
+            int l1;
+            TCGv t0;
+
+            ot = dflag + OT_WORD;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            t0 = tcg_temp_local_new();
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_op_ld_v(ot + s->mem_index, t0, cpu_A0);
+            } else {
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_mov_v_reg(ot, t0, rm);
+            }
+#ifdef TARGET_X86_64
+            if (ot == OT_LONG) {
+                /* XXX: specific Intel behaviour ? */
+                l1 = gen_new_label();
+                gen_jcc1(s, s->cc_op, b ^ 1, l1);
+                tcg_gen_mov_tl(cpu_regs[reg], t0);
+                gen_set_label(l1);
+                tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]);
+            } else
+#endif
+            {
+                l1 = gen_new_label();
+                gen_jcc1(s, s->cc_op, b ^ 1, l1);
+                gen_op_mov_reg_v(ot, reg, t0);
+                gen_set_label(l1);
+            }
+            tcg_temp_free(t0);
+        }
+        break;
+
+        /************************/
+        /* flags */
+    case 0x9c: /* pushf */
+        gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
+        if (s->vm86 && s->iopl != 3) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_helper_read_eflags(cpu_T[0]);
+            gen_push_T0(s);
+        }
+        break;
+    case 0x9d: /* popf */
+        gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
+        if (s->vm86 && s->iopl != 3) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_pop_T0(s);
+            if (s->cpl == 0) {
+                if (s->dflag) {
+                    gen_helper_write_eflags(cpu_T[0],
+                                       tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK)));
+                } else {
+                    gen_helper_write_eflags(cpu_T[0],
+                                       tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff));
+                }
+            } else {
+                if (s->cpl <= s->iopl) {
+                    if (s->dflag) {
+                        gen_helper_write_eflags(cpu_T[0],
+                                           tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK)));
+                    } else {
+                        gen_helper_write_eflags(cpu_T[0],
+                                           tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff));
+                    }
+                } else {
+                    if (s->dflag) {
+                        gen_helper_write_eflags(cpu_T[0],
+                                           tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK)));
+                    } else {
+                        gen_helper_write_eflags(cpu_T[0],
+                                           tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff));
+                    }
+                }
+            }
+            gen_pop_update(s);
+            s->cc_op = CC_OP_EFLAGS;
+            /* abort translation because TF flag may change */
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+    case 0x9e: /* sahf */
+        if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
+            goto illegal_op;
+        gen_op_mov_TN_reg(OT_BYTE, 0, R_AH);
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags(cpu_cc_src);
+        tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O);
+        tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C);
+        tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]);
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0x9f: /* lahf */
+        if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags(cpu_T[0]);
+        /* Note: gen_compute_eflags() only gives the condition codes */
+        tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02);
+        gen_op_mov_reg_T0(OT_BYTE, R_AH);
+        break;
+    case 0xf5: /* cmc */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags(cpu_cc_src);
+        tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C);
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0xf8: /* clc */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags(cpu_cc_src);
+        tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C);
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0xf9: /* stc */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags(cpu_cc_src);
+        tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C);
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0xfc: /* cld */
+        tcg_gen_movi_i32(cpu_tmp2_i32, 1);
+        tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df));
+        break;
+    case 0xfd: /* std */
+        tcg_gen_movi_i32(cpu_tmp2_i32, -1);
+        tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df));
+        break;
+
+        /************************/
+        /* bit operations */
+    case 0x1ba: /* bt/bts/btr/btc Gv, im */
+        ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        op = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        rm = (modrm & 7) | REX_B(s);
+        if (mod != 3) {
+            s->rip_offset = 1;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_ld_T0_A0(ot + s->mem_index);
+        } else {
+            gen_op_mov_TN_reg(ot, 0, rm);
+        }
+        /* load shift */
+        val = ldub_code(s->pc++);
+        gen_op_movl_T1_im(val);
+        if (op < 4)
+            goto illegal_op;
+        op -= 4;
+        goto bt_op;
+    case 0x1a3: /* bt Gv, Ev */
+        op = 0;
+        goto do_btx;
+    case 0x1ab: /* bts */
+        op = 1;
+        goto do_btx;
+    case 0x1b3: /* btr */
+        op = 2;
+        goto do_btx;
+    case 0x1bb: /* btc */
+        op = 3;
+    do_btx:
+        ot = dflag + OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7) | rex_r;
+        mod = (modrm >> 6) & 3;
+        rm = (modrm & 7) | REX_B(s);
+        gen_op_mov_TN_reg(OT_LONG, 1, reg);
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            /* specific case: we need to add a displacement */
+            gen_exts(ot, cpu_T[1]);
+            tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot);
+            tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, ot);
+            tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+            gen_op_ld_T0_A0(ot + s->mem_index);
+        } else {
+            gen_op_mov_TN_reg(ot, 0, rm);
+        }
+    bt_op:
+        tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1);
+        switch(op) {
+        case 0:
+            tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]);
+            tcg_gen_movi_tl(cpu_cc_dst, 0);
+            break;
+        case 1:
+            tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
+            tcg_gen_movi_tl(cpu_tmp0, 1);
+            tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
+            tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+            break;
+        case 2:
+            tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
+            tcg_gen_movi_tl(cpu_tmp0, 1);
+            tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
+            tcg_gen_not_tl(cpu_tmp0, cpu_tmp0);
+            tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+            break;
+        default:
+        case 3:
+            tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
+            tcg_gen_movi_tl(cpu_tmp0, 1);
+            tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
+            tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
+            break;
+        }
+        s->cc_op = CC_OP_SARB + ot;
+        if (op != 0) {
+            if (mod != 3)
+                gen_op_st_T0_A0(ot + s->mem_index);
+            else
+                gen_op_mov_reg_T0(ot, rm);
+            tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
+            tcg_gen_movi_tl(cpu_cc_dst, 0);
+        }
+        break;
+    case 0x1bc: /* bsf */
+    case 0x1bd: /* bsr */
+        {
+            int label1;
+            TCGv t0;
+
+            ot = dflag + OT_WORD;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            gen_ldst_modrm(s,modrm, ot, OR_TMP0, 0);
+            gen_extu(ot, cpu_T[0]);
+            t0 = tcg_temp_local_new();
+            tcg_gen_mov_tl(t0, cpu_T[0]);
+            if ((b & 1) && (prefixes & PREFIX_REPZ) &&
+                (s->cpuid_ext3_features & CPUID_EXT3_ABM)) {
+                switch(ot) {
+                case OT_WORD: gen_helper_lzcnt(cpu_T[0], t0,
+                    tcg_const_i32(16)); break;
+                case OT_LONG: gen_helper_lzcnt(cpu_T[0], t0,
+                    tcg_const_i32(32)); break;
+                case OT_QUAD: gen_helper_lzcnt(cpu_T[0], t0,
+                    tcg_const_i32(64)); break;
+                }
+                gen_op_mov_reg_T0(ot, reg);
+            } else {
+                label1 = gen_new_label();
+                tcg_gen_movi_tl(cpu_cc_dst, 0);
+                tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1);
+                if (b & 1) {
+                    gen_helper_bsr(cpu_T[0], t0);
+                } else {
+                    gen_helper_bsf(cpu_T[0], t0);
+                }
+                gen_op_mov_reg_T0(ot, reg);
+                tcg_gen_movi_tl(cpu_cc_dst, 1);
+                gen_set_label(label1);
+                tcg_gen_discard_tl(cpu_cc_src);
+                s->cc_op = CC_OP_LOGICB + ot;
+            }
+            tcg_temp_free(t0);
+        }
+        break;
+        /************************/
+        /* bcd */
+    case 0x27: /* daa */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_helper_daa();
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0x2f: /* das */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_helper_das();
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0x37: /* aaa */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_helper_aaa();
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0x3f: /* aas */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_helper_aas();
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0xd4: /* aam */
+        if (CODE64(s))
+            goto illegal_op;
+        val = ldub_code(s->pc++);
+        if (val == 0) {
+            gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
+        } else {
+            gen_helper_aam(tcg_const_i32(val));
+            s->cc_op = CC_OP_LOGICB;
+        }
+        break;
+    case 0xd5: /* aad */
+        if (CODE64(s))
+            goto illegal_op;
+        val = ldub_code(s->pc++);
+        gen_helper_aad(tcg_const_i32(val));
+        s->cc_op = CC_OP_LOGICB;
+        break;
+        /************************/
+        /* misc */
+    case 0x90: /* nop */
+        /* XXX: correct lock test for all insn */
+        if (prefixes & PREFIX_LOCK) {
+            goto illegal_op;
+        }
+        /* If REX_B is set, then this is xchg eax, r8d, not a nop.  */
+        if (REX_B(s)) {
+            goto do_xchg_reg_eax;
+        }
+        if (prefixes & PREFIX_REPZ) {
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE);
+        }
+        break;
+    case 0x9b: /* fwait */
+        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
+            (HF_MP_MASK | HF_TS_MASK)) {
+            gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_fwait();
+        }
+        break;
+    case 0xcc: /* int3 */
+        gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
+        break;
+    case 0xcd: /* int N */
+        val = ldub_code(s->pc++);
+        if (s->vm86 && s->iopl != 3) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
+        }
+        break;
+    case 0xce: /* into */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_helper_into(tcg_const_i32(s->pc - pc_start));
+        break;
+#ifdef WANT_ICEBP
+    case 0xf1: /* icebp (undocumented, exits to external debugger) */
+        gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP);
+#if 1
+        gen_debug(s, pc_start - s->cs_base);
+#else
+        /* start debug */
+        tb_flush(cpu_single_env);
+        cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM);
+#endif
+        break;
+#endif
+    case 0xfa: /* cli */
+        if (!s->vm86) {
+            if (s->cpl <= s->iopl) {
+                gen_helper_cli();
+            } else {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            }
+        } else {
+            if (s->iopl == 3) {
+                gen_helper_cli();
+            } else {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            }
+        }
+        break;
+    case 0xfb: /* sti */
+        if (!s->vm86) {
+            if (s->cpl <= s->iopl) {
+            gen_sti:
+                gen_helper_sti();
+                /* interruptions are enabled only the first insn after sti */
+                /* If several instructions disable interrupts, only the
+                   _first_ does it */
+                if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                    gen_helper_set_inhibit_irq();
+                /* give a chance to handle pending irqs */
+                gen_jmp_im(s->pc - s->cs_base);
+                gen_eob(s);
+            } else {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            }
+        } else {
+            if (s->iopl == 3) {
+                goto gen_sti;
+            } else {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            }
+        }
+        break;
+    case 0x62: /* bound */
+        if (CODE64(s))
+            goto illegal_op;
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
+        gen_op_mov_TN_reg(ot, 0, reg);
+        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+        gen_jmp_im(pc_start - s->cs_base);
+        tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+        if (ot == OT_WORD)
+            gen_helper_boundw(cpu_A0, cpu_tmp2_i32);
+        else
+            gen_helper_boundl(cpu_A0, cpu_tmp2_i32);
+        break;
+    case 0x1c8 ... 0x1cf: /* bswap reg */
+        reg = (b & 7) | REX_B(s);
+#ifdef TARGET_X86_64
+        if (dflag == 2) {
+            gen_op_mov_TN_reg(OT_QUAD, 0, reg);
+            tcg_gen_bswap64_i64(cpu_T[0], cpu_T[0]);
+            gen_op_mov_reg_T0(OT_QUAD, reg);
+        } else
+#endif
+        {
+            gen_op_mov_TN_reg(OT_LONG, 0, reg);
+            tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]);
+            tcg_gen_bswap32_tl(cpu_T[0], cpu_T[0]);
+            gen_op_mov_reg_T0(OT_LONG, reg);
+        }
+        break;
+    case 0xd6: /* salc */
+        if (CODE64(s))
+            goto illegal_op;
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_compute_eflags_c(cpu_T[0]);
+        tcg_gen_neg_tl(cpu_T[0], cpu_T[0]);
+        gen_op_mov_reg_T0(OT_BYTE, R_EAX);
+        break;
+    case 0xe0: /* loopnz */
+    case 0xe1: /* loopz */
+    case 0xe2: /* loop */
+    case 0xe3: /* jecxz */
+        {
+            int l1, l2, l3;
+
+            tval = (int8_t)insn_get(s, OT_BYTE);
+            next_eip = s->pc - s->cs_base;
+            tval += next_eip;
+            if (s->dflag == 0)
+                tval &= 0xffff;
+
+            l1 = gen_new_label();
+            l2 = gen_new_label();
+            l3 = gen_new_label();
+            b &= 3;
+            switch(b) {
+            case 0: /* loopnz */
+            case 1: /* loopz */
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_op_add_reg_im(s->aflag, R_ECX, -1);
+                gen_op_jz_ecx(s->aflag, l3);
+                gen_compute_eflags(cpu_tmp0);
+                tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z);
+                if (b == 0) {
+                    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
+                } else {
+                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1);
+                }
+                break;
+            case 2: /* loop */
+                gen_op_add_reg_im(s->aflag, R_ECX, -1);
+                gen_op_jnz_ecx(s->aflag, l1);
+                break;
+            default:
+            case 3: /* jcxz */
+                gen_op_jz_ecx(s->aflag, l1);
+                break;
+            }
+
+            gen_set_label(l3);
+            gen_jmp_im(next_eip);
+            tcg_gen_br(l2);
+
+            gen_set_label(l1);
+            gen_jmp_im(tval);
+            gen_set_label(l2);
+            gen_eob(s);
+        }
+        break;
+    case 0x130: /* wrmsr */
+    case 0x132: /* rdmsr */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            if (b & 2) {
+                gen_helper_rdmsr();
+            } else {
+                gen_helper_wrmsr();
+            }
+        }
+        break;
+    case 0x131: /* rdtsc */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(pc_start - s->cs_base);
+        if (use_icount)
+            gen_io_start();
+        gen_helper_rdtsc();
+        if (use_icount) {
+            gen_io_end();
+            gen_jmp(s, s->pc - s->cs_base);
+        }
+        break;
+    case 0x133: /* rdpmc */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_helper_rdpmc();
+        break;
+    case 0x134: /* sysenter */
+        /* For Intel SYSENTER is valid on 64-bit */
+        if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
+            goto illegal_op;
+        if (!s->pe) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_sysenter();
+            gen_eob(s);
+        }
+        break;
+    case 0x135: /* sysexit */
+        /* For Intel SYSEXIT is valid on 64-bit */
+        if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
+            goto illegal_op;
+        if (!s->pe) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_sysexit(tcg_const_i32(dflag));
+            gen_eob(s);
+        }
+        break;
+#ifdef TARGET_X86_64
+    case 0x105: /* syscall */
+        /* XXX: is it usable in real mode ? */
+        gen_update_cc_op(s);
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_helper_syscall(tcg_const_i32(s->pc - pc_start));
+        gen_eob(s);
+        break;
+    case 0x107: /* sysret */
+        if (!s->pe) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_sysret(tcg_const_i32(s->dflag));
+            /* condition codes are modified only in long mode */
+            if (s->lma)
+                s->cc_op = CC_OP_EFLAGS;
+            gen_eob(s);
+        }
+        break;
+#endif
+    case 0x1a2: /* cpuid */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_helper_cpuid();
+        break;
+    case 0xf4: /* hlt */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_hlt(tcg_const_i32(s->pc - pc_start));
+            s->is_jmp = DISAS_TB_JUMP;
+        }
+        break;
+    case 0x100:
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        op = (modrm >> 3) & 7;
+        switch(op) {
+        case 0: /* sldt */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ);
+            tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,ldt.selector));
+            ot = OT_WORD;
+            if (mod == 3)
+                ot += s->dflag;
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+            break;
+        case 2: /* lldt */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
+                gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+                gen_jmp_im(pc_start - s->cs_base);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_lldt(cpu_tmp2_i32);
+            }
+            break;
+        case 1: /* str */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ);
+            tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,tr.selector));
+            ot = OT_WORD;
+            if (mod == 3)
+                ot += s->dflag;
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+            break;
+        case 3: /* ltr */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
+                gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+                gen_jmp_im(pc_start - s->cs_base);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_ltr(cpu_tmp2_i32);
+            }
+            break;
+        case 4: /* verr */
+        case 5: /* verw */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            if (op == 4)
+                gen_helper_verr(cpu_T[0]);
+            else
+                gen_helper_verw(cpu_T[0]);
+            s->cc_op = CC_OP_EFLAGS;
+            break;
+        default:
+            goto illegal_op;
+        }
+        break;
+    case 0x101:
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        op = (modrm >> 3) & 7;
+        rm = modrm & 7;
+        switch(op) {
+        case 0: /* sgdt */
+            if (mod == 3)
+                goto illegal_op;
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit));
+            gen_op_st_T0_A0(OT_WORD + s->mem_index);
+            gen_add_A0_im(s, 2);
+            tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.base));
+            if (!s->dflag)
+                gen_op_andl_T0_im(0xffffff);
+            gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
+            break;
+        case 1:
+            if (mod == 3) {
+                switch (rm) {
+                case 0: /* monitor */
+                    if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
+                        s->cpl != 0)
+                        goto illegal_op;
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(pc_start - s->cs_base);
+#ifdef TARGET_X86_64
+                    if (s->aflag == 2) {
+                        gen_op_movq_A0_reg(R_EAX);
+                    } else
+#endif
+                    {
+                        gen_op_movl_A0_reg(R_EAX);
+                        if (s->aflag == 0)
+                            gen_op_andl_A0_ffff();
+                    }
+                    gen_add_A0_ds_seg(s);
+                    gen_helper_monitor(cpu_A0);
+                    break;
+                case 1: /* mwait */
+                    if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
+                        s->cpl != 0)
+                        goto illegal_op;
+                    gen_update_cc_op(s);
+                    gen_jmp_im(pc_start - s->cs_base);
+                    gen_helper_mwait(tcg_const_i32(s->pc - pc_start));
+                    gen_eob(s);
+                    break;
+                default:
+                    goto illegal_op;
+                }
+            } else { /* sidt */
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit));
+                gen_op_st_T0_A0(OT_WORD + s->mem_index);
+                gen_add_A0_im(s, 2);
+                tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.base));
+                if (!s->dflag)
+                    gen_op_andl_T0_im(0xffffff);
+                gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
+            }
+            break;
+        case 2: /* lgdt */
+        case 3: /* lidt */
+            if (mod == 3) {
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                switch(rm) {
+                case 0: /* VMRUN */
+                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_vmrun(tcg_const_i32(s->aflag),
+                                         tcg_const_i32(s->pc - pc_start));
+                        tcg_gen_exit_tb(0);
+                        s->is_jmp = DISAS_TB_JUMP;
+                    }
+                    break;
+                case 1: /* VMMCALL */
+                    if (!(s->flags & HF_SVME_MASK))
+                        goto illegal_op;
+                    gen_helper_vmmcall();
+                    break;
+                case 2: /* VMLOAD */
+                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_vmload(tcg_const_i32(s->aflag));
+                    }
+                    break;
+                case 3: /* VMSAVE */
+                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_vmsave(tcg_const_i32(s->aflag));
+                    }
+                    break;
+                case 4: /* STGI */
+                    if ((!(s->flags & HF_SVME_MASK) &&
+                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
+                        !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_stgi();
+                    }
+                    break;
+                case 5: /* CLGI */
+                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_clgi();
+                    }
+                    break;
+                case 6: /* SKINIT */
+                    if ((!(s->flags & HF_SVME_MASK) && 
+                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
+                        !s->pe)
+                        goto illegal_op;
+                    gen_helper_skinit();
+                    break;
+                case 7: /* INVLPGA */
+                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
+                        goto illegal_op;
+                    if (s->cpl != 0) {
+                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        break;
+                    } else {
+                        gen_helper_invlpga(tcg_const_i32(s->aflag));
+                    }
+                    break;
+                default:
+                    goto illegal_op;
+                }
+            } else if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_svm_check_intercept(s, pc_start,
+                                        op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE);
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_op_ld_T1_A0(OT_WORD + s->mem_index);
+                gen_add_A0_im(s, 2);
+                gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
+                if (!s->dflag)
+                    gen_op_andl_T0_im(0xffffff);
+                if (op == 2) {
+                    tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,gdt.base));
+                    tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,gdt.limit));
+                } else {
+                    tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,idt.base));
+                    tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,idt.limit));
+                }
+            }
+            break;
+        case 4: /* smsw */
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
+#if defined TARGET_X86_64 && defined HOST_WORDS_BIGENDIAN
+            tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0]) + 4);
+#else
+            tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0]));
+#endif
+            gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
+            break;
+        case 6: /* lmsw */
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+                gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+                gen_helper_lmsw(cpu_T[0]);
+                gen_jmp_im(s->pc - s->cs_base);
+                gen_eob(s);
+            }
+            break;
+        case 7:
+            if (mod != 3) { /* invlpg */
+                if (s->cpl != 0) {
+                    gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                } else {
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(pc_start - s->cs_base);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_helper_invlpg(cpu_A0);
+                    gen_jmp_im(s->pc - s->cs_base);
+                    gen_eob(s);
+                }
+            } else {
+                switch (rm) {
+                case 0: /* swapgs */
+#ifdef TARGET_X86_64
+                    if (CODE64(s)) {
+                        if (s->cpl != 0) {
+                            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                        } else {
+                            tcg_gen_ld_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,segs[R_GS].base));
+                            tcg_gen_ld_tl(cpu_T[1], cpu_env,
+                                offsetof(CPUX86State,kernelgsbase));
+                            tcg_gen_st_tl(cpu_T[1], cpu_env,
+                                offsetof(CPUX86State,segs[R_GS].base));
+                            tcg_gen_st_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,kernelgsbase));
+                        }
+                    } else
+#endif
+                    {
+                        goto illegal_op;
+                    }
+                    break;
+                case 1: /* rdtscp */
+                    if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP))
+                        goto illegal_op;
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(pc_start - s->cs_base);
+                    if (use_icount)
+                        gen_io_start();
+                    gen_helper_rdtscp();
+                    if (use_icount) {
+                        gen_io_end();
+                        gen_jmp(s, s->pc - s->cs_base);
+                    }
+                    break;
+                default:
+                    goto illegal_op;
+                }
+            }
+            break;
+        default:
+            goto illegal_op;
+        }
+        break;
+    case 0x108: /* invd */
+    case 0x109: /* wbinvd */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
+            /* nothing to do */
+        }
+        break;
+    case 0x63: /* arpl or movslS (x86_64) */
+#ifdef TARGET_X86_64
+        if (CODE64(s)) {
+            int d_ot;
+            /* d_ot is the size of destination */
+            d_ot = dflag + OT_WORD;
+
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            mod = (modrm >> 6) & 3;
+            rm = (modrm & 7) | REX_B(s);
+
+            if (mod == 3) {
+                gen_op_mov_TN_reg(OT_LONG, 0, rm);
+                /* sign extend */
+                if (d_ot == OT_QUAD)
+                    tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
+                gen_op_mov_reg_T0(d_ot, reg);
+            } else {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                if (d_ot == OT_QUAD) {
+                    gen_op_lds_T0_A0(OT_LONG + s->mem_index);
+                } else {
+                    gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                }
+                gen_op_mov_reg_T0(d_ot, reg);
+            }
+        } else
+#endif
+        {
+            int label1;
+            TCGv t0, t1, t2, a0;
+
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            t0 = tcg_temp_local_new();
+            t1 = tcg_temp_local_new();
+            t2 = tcg_temp_local_new();
+            ot = OT_WORD;
+            modrm = ldub_code(s->pc++);
+            reg = (modrm >> 3) & 7;
+            mod = (modrm >> 6) & 3;
+            rm = modrm & 7;
+            if (mod != 3) {
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                gen_op_ld_v(ot + s->mem_index, t0, cpu_A0);
+                a0 = tcg_temp_local_new();
+                tcg_gen_mov_tl(a0, cpu_A0);
+            } else {
+                gen_op_mov_v_reg(ot, t0, rm);
+                TCGV_UNUSED(a0);
+            }
+            gen_op_mov_v_reg(ot, t1, reg);
+            tcg_gen_andi_tl(cpu_tmp0, t0, 3);
+            tcg_gen_andi_tl(t1, t1, 3);
+            tcg_gen_movi_tl(t2, 0);
+            label1 = gen_new_label();
+            tcg_gen_brcond_tl(TCG_COND_GE, cpu_tmp0, t1, label1);
+            tcg_gen_andi_tl(t0, t0, ~3);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_gen_movi_tl(t2, CC_Z);
+            gen_set_label(label1);
+            if (mod != 3) {
+                gen_op_st_v(ot + s->mem_index, t0, a0);
+                tcg_temp_free(a0);
+           } else {
+                gen_op_mov_reg_v(ot, rm, t0);
+            }
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_compute_eflags(cpu_cc_src);
+            tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z);
+            tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2);
+            s->cc_op = CC_OP_EFLAGS;
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t2);
+        }
+        break;
+    case 0x102: /* lar */
+    case 0x103: /* lsl */
+        {
+            int label1;
+            TCGv t0;
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            ot = dflag ? OT_LONG : OT_WORD;
+            modrm = ldub_code(s->pc++);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+            t0 = tcg_temp_local_new();
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            if (b == 0x102)
+                gen_helper_lar(t0, cpu_T[0]);
+            else
+                gen_helper_lsl(t0, cpu_T[0]);
+            tcg_gen_andi_tl(cpu_tmp0, cpu_cc_src, CC_Z);
+            label1 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
+            gen_op_mov_reg_v(ot, reg, t0);
+            gen_set_label(label1);
+            s->cc_op = CC_OP_EFLAGS;
+            tcg_temp_free(t0);
+        }
+        break;
+    case 0x118:
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        op = (modrm >> 3) & 7;
+        switch(op) {
+        case 0: /* prefetchnta */
+        case 1: /* prefetchnt0 */
+        case 2: /* prefetchnt0 */
+        case 3: /* prefetchnt0 */
+            if (mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            /* nothing more to do */
+            break;
+        default: /* nop (multi byte) */
+            gen_nop_modrm(s, modrm);
+            break;
+        }
+        break;
+    case 0x119 ... 0x11f: /* nop (multi byte) */
+        modrm = ldub_code(s->pc++);
+        gen_nop_modrm(s, modrm);
+        break;
+    case 0x120: /* mov reg, crN */
+    case 0x122: /* mov crN, reg */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            modrm = ldub_code(s->pc++);
+            if ((modrm & 0xc0) != 0xc0)
+                goto illegal_op;
+            rm = (modrm & 7) | REX_B(s);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            if (CODE64(s))
+                ot = OT_QUAD;
+            else
+                ot = OT_LONG;
+            if ((prefixes & PREFIX_LOCK) && (reg == 0) &&
+                (s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) {
+                reg = 8;
+            }
+            switch(reg) {
+            case 0:
+            case 2:
+            case 3:
+            case 4:
+            case 8:
+                if (s->cc_op != CC_OP_DYNAMIC)
+                    gen_op_set_cc_op(s->cc_op);
+                gen_jmp_im(pc_start - s->cs_base);
+                if (b & 2) {
+                    gen_op_mov_TN_reg(ot, 0, rm);
+                    gen_helper_write_crN(tcg_const_i32(reg), cpu_T[0]);
+                    gen_jmp_im(s->pc - s->cs_base);
+                    gen_eob(s);
+                } else {
+                    gen_helper_read_crN(cpu_T[0], tcg_const_i32(reg));
+                    gen_op_mov_reg_T0(ot, rm);
+                }
+                break;
+            default:
+                goto illegal_op;
+            }
+        }
+        break;
+    case 0x121: /* mov reg, drN */
+    case 0x123: /* mov drN, reg */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            modrm = ldub_code(s->pc++);
+            if ((modrm & 0xc0) != 0xc0)
+                goto illegal_op;
+            rm = (modrm & 7) | REX_B(s);
+            reg = ((modrm >> 3) & 7) | rex_r;
+            if (CODE64(s))
+                ot = OT_QUAD;
+            else
+                ot = OT_LONG;
+            /* XXX: do it dynamically with CR4.DE bit */
+            if (reg == 4 || reg == 5 || reg >= 8)
+                goto illegal_op;
+            if (b & 2) {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
+                gen_op_mov_TN_reg(ot, 0, rm);
+                gen_helper_movl_drN_T0(tcg_const_i32(reg), cpu_T[0]);
+                gen_jmp_im(s->pc - s->cs_base);
+                gen_eob(s);
+            } else {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg);
+                tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,dr[reg]));
+                gen_op_mov_reg_T0(ot, rm);
+            }
+        }
+        break;
+    case 0x106: /* clts */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+            gen_helper_clts();
+            /* abort block because static cpu state changed */
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+        }
+        break;
+    /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */
+    case 0x1c3: /* MOVNTI reg, mem */
+        if (!(s->cpuid_features & CPUID_SSE2))
+            goto illegal_op;
+        ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
+        reg = ((modrm >> 3) & 7) | rex_r;
+        /* generate a generic store */
+        gen_ldst_modrm(s, modrm, ot, reg, 1);
+        break;
+    case 0x1ae:
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        op = (modrm >> 3) & 7;
+        switch(op) {
+        case 0: /* fxsave */
+            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
+                (s->prefix & PREFIX_LOCK))
+                goto illegal_op;
+            if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
+                gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+                break;
+            }
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_fxsave(cpu_A0, tcg_const_i32((s->dflag == 2)));
+            break;
+        case 1: /* fxrstor */
+            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
+                (s->prefix & PREFIX_LOCK))
+                goto illegal_op;
+            if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
+                gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+                break;
+            }
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_fxrstor(cpu_A0, tcg_const_i32((s->dflag == 2)));
+            break;
+        case 2: /* ldmxcsr */
+        case 3: /* stmxcsr */
+            if (s->flags & HF_TS_MASK) {
+                gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+                break;
+            }
+            if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) ||
+                mod == 3)
+                goto illegal_op;
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            if (op == 2) {
+                gen_op_ld_T0_A0(OT_LONG + s->mem_index);
+                tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
+            } else {
+                tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
+                gen_op_st_T0_A0(OT_LONG + s->mem_index);
+            }
+            break;
+        case 5: /* lfence */
+        case 6: /* mfence */
+            if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
+                goto illegal_op;
+            break;
+        case 7: /* sfence / clflush */
+            if ((modrm & 0xc7) == 0xc0) {
+                /* sfence */
+                /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */
+                if (!(s->cpuid_features & CPUID_SSE))
+                    goto illegal_op;
+            } else {
+                /* clflush */
+                if (!(s->cpuid_features & CPUID_CLFLUSH))
+                    goto illegal_op;
+                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            }
+            break;
+        default:
+            goto illegal_op;
+        }
+        break;
+    case 0x10d: /* 3DNow! prefetch(w) */
+        modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
+        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+        /* ignore for now */
+        break;
+    case 0x1aa: /* rsm */
+        gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM);
+        if (!(s->flags & HF_SMM_MASK))
+            goto illegal_op;
+        gen_update_cc_op(s);
+        gen_jmp_im(s->pc - s->cs_base);
+        gen_helper_rsm();
+        gen_eob(s);
+        break;
+    case 0x1b8: /* SSE4.2 popcnt */
+        if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) !=
+             PREFIX_REPZ)
+            goto illegal_op;
+        if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT))
+            goto illegal_op;
+
+        modrm = ldub_code(s->pc++);
+        reg = ((modrm >> 3) & 7);
+
+        if (s->prefix & PREFIX_DATA)
+            ot = OT_WORD;
+        else if (s->dflag != 2)
+            ot = OT_LONG;
+        else
+            ot = OT_QUAD;
+
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        gen_helper_popcnt(cpu_T[0], cpu_T[0], tcg_const_i32(ot));
+        gen_op_mov_reg_T0(ot, reg);
+
+        s->cc_op = CC_OP_EFLAGS;
+        break;
+    case 0x10e ... 0x10f:
+        /* 3DNow! instructions, ignore prefixes */
+        s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA);
+    case 0x110 ... 0x117:
+    case 0x128 ... 0x12f:
+    case 0x138 ... 0x13a:
+    case 0x150 ... 0x179:
+    case 0x17c ... 0x17f:
+    case 0x1c2:
+    case 0x1c4 ... 0x1c6:
+    case 0x1d0 ... 0x1fe:
+        gen_sse(s, b, pc_start, rex_r);
+        break;
+    default:
+        goto illegal_op;
+    }
+    /* lock generation */
+    if (s->prefix & PREFIX_LOCK)
+        gen_helper_unlock();
+    return s->pc;
+ illegal_op:
+    if (s->prefix & PREFIX_LOCK)
+        gen_helper_unlock();
+    /* XXX: ensure that no lock was generated */
+    gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
+    return s->pc;
+}
+
+void optimize_flags_init(void)
+{
+#if TCG_TARGET_REG_BITS == 32
+    assert(sizeof(CCTable) == (1 << 3));
+#else
+    assert(sizeof(CCTable) == (1 << 4));
+#endif
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0,
+                                       offsetof(CPUState, cc_op), "cc_op");
+    cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_src),
+                                    "cc_src");
+    cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_dst),
+                                    "cc_dst");
+    cpu_cc_tmp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_tmp),
+                                    "cc_tmp");
+
+#ifdef TARGET_X86_64
+    cpu_regs[R_EAX] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EAX]), "rax");
+    cpu_regs[R_ECX] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ECX]), "rcx");
+    cpu_regs[R_EDX] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EDX]), "rdx");
+    cpu_regs[R_EBX] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EBX]), "rbx");
+    cpu_regs[R_ESP] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ESP]), "rsp");
+    cpu_regs[R_EBP] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EBP]), "rbp");
+    cpu_regs[R_ESI] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ESI]), "rsi");
+    cpu_regs[R_EDI] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EDI]), "rdi");
+    cpu_regs[8] = tcg_global_mem_new_i64(TCG_AREG0,
+                                         offsetof(CPUState, regs[8]), "r8");
+    cpu_regs[9] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[9]), "r9");
+    cpu_regs[10] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[10]), "r10");
+    cpu_regs[11] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[11]), "r11");
+    cpu_regs[12] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[12]), "r12");
+    cpu_regs[13] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[13]), "r13");
+    cpu_regs[14] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[14]), "r14");
+    cpu_regs[15] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUState, regs[15]), "r15");
+#else
+    cpu_regs[R_EAX] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EAX]), "eax");
+    cpu_regs[R_ECX] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ECX]), "ecx");
+    cpu_regs[R_EDX] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EDX]), "edx");
+    cpu_regs[R_EBX] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EBX]), "ebx");
+    cpu_regs[R_ESP] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ESP]), "esp");
+    cpu_regs[R_EBP] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EBP]), "ebp");
+    cpu_regs[R_ESI] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_ESI]), "esi");
+    cpu_regs[R_EDI] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, regs[R_EDI]), "edi");
+#endif
+
+    /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+   basic block 'tb'. If search_pc is TRUE, also generate PC
+   information for each intermediate instruction. */
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    target_ulong pc_ptr;
+    uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int j, lj;
+    uint64_t flags;
+    target_ulong pc_start;
+    target_ulong cs_base;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    pc_start = tb->pc;
+    cs_base = tb->cs_base;
+    flags = tb->flags;
+
+    dc->pe = (flags >> HF_PE_SHIFT) & 1;
+    dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
+    dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
+    dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
+    dc->f_st = 0;
+    dc->vm86 = (flags >> VM_SHIFT) & 1;
+    dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
+    dc->iopl = (flags >> IOPL_SHIFT) & 3;
+    dc->tf = (flags >> TF_SHIFT) & 1;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->cc_op = CC_OP_DYNAMIC;
+    dc->cs_base = cs_base;
+    dc->tb = tb;
+    dc->popl_esp_hack = 0;
+    /* select memory access functions */
+    dc->mem_index = 0;
+    if (flags & HF_SOFTMMU_MASK) {
+        if (dc->cpl == 3)
+            dc->mem_index = 2 * 4;
+        else
+            dc->mem_index = 1 * 4;
+    }
+    dc->cpuid_features = env->cpuid_features;
+    dc->cpuid_ext_features = env->cpuid_ext_features;
+    dc->cpuid_ext2_features = env->cpuid_ext2_features;
+    dc->cpuid_ext3_features = env->cpuid_ext3_features;
+#ifdef TARGET_X86_64
+    dc->lma = (flags >> HF_LMA_SHIFT) & 1;
+    dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
+#endif
+    dc->flags = flags;
+    dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
+                    (flags & HF_INHIBIT_IRQ_MASK)
+#ifndef CONFIG_SOFTMMU
+                    || (flags & HF_SOFTMMU_MASK)
+#endif
+                    );
+#if 0
+    /* check addseg logic */
+    if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
+        printf("ERROR addseg\n");
+#endif
+
+    cpu_T[0] = tcg_temp_new();
+    cpu_T[1] = tcg_temp_new();
+    cpu_A0 = tcg_temp_new();
+    cpu_T3 = tcg_temp_new();
+
+    cpu_tmp0 = tcg_temp_new();
+    cpu_tmp1_i64 = tcg_temp_new_i64();
+    cpu_tmp2_i32 = tcg_temp_new_i32();
+    cpu_tmp3_i32 = tcg_temp_new_i32();
+    cpu_tmp4 = tcg_temp_new();
+    cpu_tmp5 = tcg_temp_new();
+    cpu_ptr0 = tcg_temp_new_ptr();
+    cpu_ptr1 = tcg_temp_new_ptr();
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    pc_ptr = pc_start;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+    for(;;) {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == pc_ptr &&
+                    !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
+                    gen_debug(dc, pc_ptr - dc->cs_base);
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = pc_ptr;
+            gen_opc_cc_op[lj] = dc->cc_op;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+
+        pc_ptr = disas_insn(dc, pc_ptr);
+        num_insns++;
+        /* stop translation if indicated */
+        if (dc->is_jmp)
+            break;
+        /* if single step mode, we generate only one instruction and
+           generate an exception */
+        /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
+           the flag and abort the translation to give the irqs a
+           change to be happen */
+        if (dc->tf || dc->singlestep_enabled ||
+            (flags & HF_INHIBIT_IRQ_MASK)) {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
+        /* if too long translation, stop generation too */
+        if (gen_opc_ptr >= gen_opc_end ||
+            (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
+            num_insns >= max_insns) {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
+        if (singlestep) {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
+    }
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    /* we don't forget to fill the last values */
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    }
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        int disas_flags;
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+#ifdef TARGET_X86_64
+        if (dc->code64)
+            disas_flags = 2;
+        else
+#endif
+            disas_flags = !dc->code32;
+        log_target_disas(pc_start, pc_ptr - pc_start, disas_flags);
+        qemu_log("\n");
+    }
+#endif
+
+    if (!search_pc) {
+        tb->size = pc_ptr - pc_start;
+        tb->icount = num_insns;
+    }
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    int cc_op;
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_OP)) {
+        int i;
+        qemu_log("RESTORE:\n");
+        for(i = 0;i <= pc_pos; i++) {
+            if (gen_opc_instr_start[i]) {
+                qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
+            }
+        }
+        qemu_log("pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
+                pc_pos, gen_opc_pc[pc_pos] - tb->cs_base,
+                (uint32_t)tb->cs_base);
+    }
+#endif
+    env->eip = gen_opc_pc[pc_pos] - tb->cs_base;
+    cc_op = gen_opc_cc_op[pc_pos];
+    if (cc_op != CC_OP_DYNAMIC)
+        env->cc_op = cc_op;
+}
diff --git a/qemu-0.15.x/target-lm32/README b/qemu-0.15.x/target-lm32/README
new file mode 100644
index 0000000..a1c2c7e
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/README
@@ -0,0 +1,46 @@
+LatticeMico32 target
+--------------------
+
+General
+-------
+All opcodes including the JUART CSRs are supported.
+
+
+JTAG UART
+---------
+JTAG UART is routed to a serial console device. For the current boards it
+is the second one. Ie to enable it in the qemu virtual console window use
+the following command line parameters:
+  -serial vc -serial vc
+This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
+available as virtual consoles.
+
+
+Programmatically terminate the emulator
+----------------------------------------
+Originally neither the LatticeMico32 nor its peripherals support a
+mechanism to shut down the machine. Emulation aware programs can write to a
+to a special register within the system control block to shut down the
+virtual machine.  For more details see hw/lm32_sys.c. The lm32-evr is the
+first BSP which instantiate this model. A (32 bit) write to 0xfff0000
+causes a vm shutdown.
+
+
+Special instructions
+--------------------
+The translation recognizes one special instruction to halt the cpu:
+  and r0, r0, r0
+On real hardware this instruction is a nop. It is not used by GCC and
+should (hopefully) not be used within hand-crafted assembly.
+Insert this instruction in your idle loop to reduce the cpu load on the
+host.
+
+
+Ignoring the MSB of the address bus
+-----------------------------------
+Some SoC ignores the MSB on the address bus. Thus creating a shadow memory
+area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+0x80000000-0xffffffff is not cached and used to access IO devices. This
+behaviour can be enabled with:
+  cpu_lm32_set_phys_msb_ignore(env, 1);
+
diff --git a/qemu-0.15.x/target-lm32/TODO b/qemu-0.15.x/target-lm32/TODO
new file mode 100644
index 0000000..b9ea0c8
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/TODO
@@ -0,0 +1,3 @@
+* disassembler (lm32-dis.c)
+* linux-user emulation
+* native bp/wp emulation (?)
diff --git a/qemu-0.15.x/target-lm32/cpu.h b/qemu-0.15.x/target-lm32/cpu.h
new file mode 100644
index 0000000..876b5be
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/cpu.h
@@ -0,0 +1,257 @@
+/*
+ *  LatticeMico32 virtual CPU header.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CPU_LM32_H
+#define CPU_LM32_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPULM32State
+
+#include "qemu-common.h"
+#include "cpu-defs.h"
+struct CPULM32State;
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_LATTICEMICO32
+
+#define NB_MMU_MODES 1
+#define TARGET_PAGE_BITS 12
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return 0;
+}
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+/* Exceptions indices */
+enum {
+    EXCP_RESET = 0,
+    EXCP_BREAKPOINT,
+    EXCP_INSN_BUS_ERROR,
+    EXCP_WATCHPOINT,
+    EXCP_DATA_BUS_ERROR,
+    EXCP_DIVIDE_BY_ZERO,
+    EXCP_IRQ,
+    EXCP_SYSTEMCALL
+};
+
+/* Registers */
+enum {
+    R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10,
+    R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20,
+    R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30,
+    R_R31
+};
+
+/* Register aliases */
+enum {
+    R_GP = R_R26,
+    R_FP = R_R27,
+    R_SP = R_R28,
+    R_RA = R_R29,
+    R_EA = R_R30,
+    R_BA = R_R31
+};
+
+/* IE flags */
+enum {
+    IE_IE  = (1<<0),
+    IE_EIE = (1<<1),
+    IE_BIE = (1<<2),
+};
+
+/* DC flags */
+enum {
+    DC_SS  = (1<<0),
+    DC_RE  = (1<<1),
+    DC_C0  = (1<<2),
+    DC_C1  = (1<<3),
+    DC_C2  = (1<<4),
+    DC_C3  = (1<<5),
+};
+
+/* CFG mask */
+enum {
+    CFG_M         = (1<<0),
+    CFG_D         = (1<<1),
+    CFG_S         = (1<<2),
+    CFG_U         = (1<<3),
+    CFG_X         = (1<<4),
+    CFG_CC        = (1<<5),
+    CFG_IC        = (1<<6),
+    CFG_DC        = (1<<7),
+    CFG_G         = (1<<8),
+    CFG_H         = (1<<9),
+    CFG_R         = (1<<10),
+    CFG_J         = (1<<11),
+    CFG_INT_SHIFT = 12,
+    CFG_BP_SHIFT  = 18,
+    CFG_WP_SHIFT  = 22,
+    CFG_REV_SHIFT = 26,
+};
+
+/* CSRs */
+enum {
+    CSR_IE   = 0x00,
+    CSR_IM   = 0x01,
+    CSR_IP   = 0x02,
+    CSR_ICC  = 0x03,
+    CSR_DCC  = 0x04,
+    CSR_CC   = 0x05,
+    CSR_CFG  = 0x06,
+    CSR_EBA  = 0x07,
+    CSR_DC   = 0x08,
+    CSR_DEBA = 0x09,
+    CSR_JTX  = 0x0e,
+    CSR_JRX  = 0x0f,
+    CSR_BP0  = 0x10,
+    CSR_BP1  = 0x11,
+    CSR_BP2  = 0x12,
+    CSR_BP3  = 0x13,
+    CSR_WP0  = 0x18,
+    CSR_WP1  = 0x19,
+    CSR_WP2  = 0x1a,
+    CSR_WP3  = 0x1b,
+};
+
+enum {
+    LM32_FEATURE_MULTIPLY     =  1,
+    LM32_FEATURE_DIVIDE       =  2,
+    LM32_FEATURE_SHIFT        =  4,
+    LM32_FEATURE_SIGN_EXTEND  =  8,
+    LM32_FEATURE_I_CACHE      = 16,
+    LM32_FEATURE_D_CACHE      = 32,
+    LM32_FEATURE_CYCLE_COUNT  = 64,
+};
+
+enum {
+    LM32_FLAG_IGNORE_MSB = 1,
+};
+
+typedef struct CPULM32State {
+    /* general registers */
+    uint32_t regs[32];
+
+    /* special registers */
+    uint32_t pc;        /* program counter */
+    uint32_t ie;        /* interrupt enable */
+    uint32_t icc;       /* instruction cache control */
+    uint32_t dcc;       /* data cache control */
+    uint32_t cc;        /* cycle counter */
+    uint32_t cfg;       /* configuration */
+
+    /* debug registers */
+    uint32_t dc;        /* debug control */
+    uint32_t bp[4];     /* breakpoint addresses */
+    uint32_t wp[4];     /* watchpoint addresses */
+
+    CPU_COMMON
+
+    uint32_t eba;       /* exception base address */
+    uint32_t deba;      /* debug exception base address */
+
+    /* interrupt controller handle for callbacks */
+    DeviceState *pic_state;
+    /* JTAG UART handle for callbacks */
+    DeviceState *juart_state;
+
+    /* processor core features */
+    uint32_t features;
+    uint32_t flags;
+    uint8_t num_bps;
+    uint8_t num_wps;
+
+} CPULM32State;
+
+
+CPUState *cpu_lm32_init(const char *cpu_model);
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_lm32_exec(CPUState *s);
+void cpu_lm32_close(CPUState *s);
+void do_interrupt(CPUState *env);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_lm32_signal_handler(int host_signum, void *pinfo,
+                          void *puc);
+void lm32_translate_init(void);
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value);
+
+#define cpu_list cpu_lm32_list
+#define cpu_init cpu_lm32_init
+#define cpu_exec cpu_lm32_exec
+#define cpu_gen_code cpu_lm32_gen_code
+#define cpu_signal_handler cpu_lm32_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                            int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->regs[R_SP] = newsp;
+    }
+    env->regs[R_R1] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env)
+{
+    return env->ie & IE_IE;
+}
+
+#include "cpu-all.h"
+
+static inline target_ulong cpu_get_pc(CPUState *env)
+{
+    return env->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-lm32/exec.h b/qemu-0.15.x/target-lm32/exec.h
new file mode 100644
index 0000000..2a227b2
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/exec.h
@@ -0,0 +1,38 @@
+/*
+ *  LatticeMico32 execution defines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dyngen-exec.h"
+
+register struct CPULM32State *env asm(AREG0);
+
+#include "cpu.h"
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted) {
+        return 0;
+    }
+
+    /* IRQ execeptions wakes us up.  */
+    if (cpu_has_work(env)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
diff --git a/qemu-0.15.x/target-lm32/helper.c b/qemu-0.15.x/target-lm32/helper.c
new file mode 100644
index 0000000..e79428d
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/helper.c
@@ -0,0 +1,254 @@
+/*
+ *  LatticeMico32 helper routines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "host-utils.h"
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    int prot;
+
+    address &= TARGET_PAGE_MASK;
+    prot = PAGE_BITS;
+    if (env->flags & LM32_FLAG_IGNORE_MSB) {
+        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
+                TARGET_PAGE_SIZE);
+    } else {
+        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+    }
+
+    return 0;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr & TARGET_PAGE_MASK;
+}
+
+void do_interrupt(CPUState *env)
+{
+    qemu_log_mask(CPU_LOG_INT,
+            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
+
+    switch (env->exception_index) {
+    case EXCP_INSN_BUS_ERROR:
+    case EXCP_DATA_BUS_ERROR:
+    case EXCP_DIVIDE_BY_ZERO:
+    case EXCP_IRQ:
+    case EXCP_SYSTEMCALL:
+        /* non-debug exceptions */
+        env->regs[R_EA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
+        env->ie &= ~IE_IE;
+        if (env->dc & DC_RE) {
+            env->pc = env->deba + (env->exception_index * 32);
+        } else {
+            env->pc = env->eba + (env->exception_index * 32);
+        }
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    case EXCP_BREAKPOINT:
+    case EXCP_WATCHPOINT:
+        /* debug exceptions */
+        env->regs[R_BA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
+        env->ie &= ~IE_IE;
+        env->pc = env->deba + (env->exception_index * 32);
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    default:
+        cpu_abort(env, "unhandled exception type=%d\n",
+                  env->exception_index);
+        break;
+    }
+}
+
+typedef struct {
+    const char *name;
+    uint32_t revision;
+    uint8_t num_interrupts;
+    uint8_t num_breakpoints;
+    uint8_t num_watchpoints;
+    uint32_t features;
+} LM32Def;
+
+static const LM32Def lm32_defs[] = {
+    {
+        .name = "lm32-basic",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-standard",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-full",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_D_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    }
+};
+
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        cpu_fprintf(f, "  %s\n", lm32_defs[i].name);
+    }
+}
+
+static const LM32Def *cpu_lm32_find_by_name(const char *name)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        if (strcasecmp(name, lm32_defs[i].name) == 0) {
+            return &lm32_defs[i];
+        }
+    }
+
+    return NULL;
+}
+
+static uint32_t cfg_by_def(const LM32Def *def)
+{
+    uint32_t cfg = 0;
+
+    if (def->features & LM32_FEATURE_MULTIPLY) {
+        cfg |= CFG_M;
+    }
+
+    if (def->features & LM32_FEATURE_DIVIDE) {
+        cfg |= CFG_D;
+    }
+
+    if (def->features & LM32_FEATURE_SHIFT) {
+        cfg |= CFG_S;
+    }
+
+    if (def->features & LM32_FEATURE_SIGN_EXTEND) {
+        cfg |= CFG_X;
+    }
+
+    if (def->features & LM32_FEATURE_I_CACHE) {
+        cfg |= CFG_IC;
+    }
+
+    if (def->features & LM32_FEATURE_D_CACHE) {
+        cfg |= CFG_DC;
+    }
+
+    if (def->features & LM32_FEATURE_CYCLE_COUNT) {
+        cfg |= CFG_CC;
+    }
+
+    cfg |= (def->num_interrupts << CFG_INT_SHIFT);
+    cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
+    cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
+    cfg |= (def->revision << CFG_REV_SHIFT);
+
+    return cfg;
+}
+
+CPUState *cpu_lm32_init(const char *cpu_model)
+{
+    CPUState *env;
+    const LM32Def *def;
+    static int tcg_initialized;
+
+    def = cpu_lm32_find_by_name(cpu_model);
+    if (!def) {
+        return NULL;
+    }
+
+    env = qemu_mallocz(sizeof(CPUState));
+
+    env->features = def->features;
+    env->num_bps = def->num_breakpoints;
+    env->num_wps = def->num_watchpoints;
+    env->cfg = cfg_by_def(def);
+    env->flags = 0;
+
+    cpu_exec_init(env);
+    cpu_reset(env);
+
+    if (!tcg_initialized) {
+        tcg_initialized = 1;
+        lm32_translate_init();
+    }
+
+    return env;
+}
+
+/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
+ * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+ * 0x80000000-0xffffffff is not cached and used to access IO devices. */
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value)
+{
+    if (value) {
+        env->flags |= LM32_FLAG_IGNORE_MSB;
+    } else {
+        env->flags &= ~LM32_FLAG_IGNORE_MSB;
+    }
+}
+
+void cpu_reset(CPUState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    tlb_flush(env, 1);
+
+    /* reset cpu state */
+    memset(env, 0, offsetof(CPULM32State, breakpoints));
+}
+
diff --git a/qemu-0.15.x/target-lm32/helper.h b/qemu-0.15.x/target-lm32/helper.h
new file mode 100644
index 0000000..9d335ef
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/helper.h
@@ -0,0 +1,14 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(hlt, void)
+DEF_HELPER_1(wcsr_im, void, i32)
+DEF_HELPER_1(wcsr_ip, void, i32)
+DEF_HELPER_1(wcsr_jtx, void, i32)
+DEF_HELPER_1(wcsr_jrx, void, i32)
+DEF_HELPER_0(rcsr_im, i32)
+DEF_HELPER_0(rcsr_ip, i32)
+DEF_HELPER_0(rcsr_jtx, i32)
+DEF_HELPER_0(rcsr_jrx, i32)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-lm32/machine.c b/qemu-0.15.x/target-lm32/machine.c
new file mode 100644
index 0000000..70ca52a
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/machine.c
@@ -0,0 +1,33 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = CPU_SAVE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, CPUState, 32),
+        VMSTATE_UINT32(pc, CPUState),
+        VMSTATE_UINT32(ie, CPUState),
+        VMSTATE_UINT32(icc, CPUState),
+        VMSTATE_UINT32(dcc, CPUState),
+        VMSTATE_UINT32(cc, CPUState),
+        VMSTATE_UINT32(eba, CPUState),
+        VMSTATE_UINT32(dc, CPUState),
+        VMSTATE_UINT32(deba, CPUState),
+        VMSTATE_UINT32_ARRAY(bp, CPUState, 4),
+        VMSTATE_UINT32_ARRAY(wp, CPUState, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
diff --git a/qemu-0.15.x/target-lm32/op_helper.c b/qemu-0.15.x/target-lm32/op_helper.c
new file mode 100644
index 0000000..a34cecd
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/op_helper.c
@@ -0,0 +1,106 @@
+#include <assert.h>
+#include "exec.h"
+#include "helper.h"
+#include "host-utils.h"
+
+#include "hw/lm32_pic.h"
+#include "hw/lm32_juart.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#define MMUSUFFIX _mmu
+#define SHIFT 0
+#include "softmmu_template.h"
+#define SHIFT 1
+#include "softmmu_template.h"
+#define SHIFT 2
+#include "softmmu_template.h"
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void helper_raise_exception(uint32_t index)
+{
+    env->exception_index = index;
+    cpu_loop_exit(env);
+}
+
+void helper_hlt(void)
+{
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit(env);
+}
+
+void helper_wcsr_im(uint32_t im)
+{
+    lm32_pic_set_im(env->pic_state, im);
+}
+
+void helper_wcsr_ip(uint32_t im)
+{
+    lm32_pic_set_ip(env->pic_state, im);
+}
+
+void helper_wcsr_jtx(uint32_t jtx)
+{
+    lm32_juart_set_jtx(env->juart_state, jtx);
+}
+
+void helper_wcsr_jrx(uint32_t jrx)
+{
+    lm32_juart_set_jrx(env->juart_state, jrx);
+}
+
+uint32_t helper_rcsr_im(void)
+{
+    return lm32_pic_get_im(env->pic_state);
+}
+
+uint32_t helper_rcsr_ip(void)
+{
+    return lm32_pic_get_ip(env->pic_state);
+}
+
+uint32_t helper_rcsr_jtx(void)
+{
+    return lm32_juart_get_jtx(env->juart_state);
+}
+
+uint32_t helper_rcsr_jrx(void)
+{
+    return lm32_juart_get_jrx(env->juart_state);
+}
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+#endif
+
diff --git a/qemu-0.15.x/target-lm32/translate.c b/qemu-0.15.x/target-lm32/translate.c
new file mode 100644
index 0000000..0be105d
--- /dev/null
+++ b/qemu-0.15.x/target-lm32/translate.c
@@ -0,0 +1,1239 @@
+/*
+ *  LatticeMico32 main translation routines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "helper.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#include "hw/lm32_pic.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define DISAS_LM32 1
+#if DISAS_LM32
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+#define EXTRACT_FIELD(src, start, end) \
+            (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+#define MEM_INDEX 0
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[32];
+static TCGv cpu_pc;
+static TCGv cpu_ie;
+static TCGv cpu_icc;
+static TCGv cpu_dcc;
+static TCGv cpu_cc;
+static TCGv cpu_cfg;
+static TCGv cpu_eba;
+static TCGv cpu_dc;
+static TCGv cpu_deba;
+static TCGv cpu_bp[4];
+static TCGv cpu_wp[4];
+
+#include "gen-icount.h"
+
+enum {
+    OP_FMT_RI,
+    OP_FMT_RR,
+    OP_FMT_CR,
+    OP_FMT_I
+};
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+    CPUState *env;
+    target_ulong pc;
+
+    /* Decoder.  */
+    int format;
+    uint32_t ir;
+    uint8_t opcode;
+    uint8_t r0, r1, r2, csr;
+    uint16_t imm5;
+    uint16_t imm16;
+    uint32_t imm26;
+
+    unsigned int delayed_branch;
+    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
+    int is_jmp;
+
+    int nr_nops;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+static const char *regnames[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26/gp", "r27/fp", "r28/sp", "r29/ra",
+    "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0",
+    "wp1", "wp2", "wp3"
+};
+
+static inline int zero_extend(unsigned int val, int width)
+{
+    return val & ((1 << width) - 1);
+}
+
+static inline int sign_extend(unsigned int val, int width)
+{
+    int sval;
+
+    /* LSL.  */
+    val <<= 32 - width;
+    sval = val;
+    /* ASR.  */
+    sval >>= 32 - width;
+
+    return sval;
+}
+
+static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
+{
+    TCGv_i32 tmp = tcg_const_i32(index);
+
+    gen_helper_raise_exception(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+
+    tb = dc->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+            likely(!dc->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_pc, dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dest);
+        if (dc->singlestep_enabled) {
+            t_gen_raise_exception(dc, EXCP_DEBUG);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void dec_add(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        if (dc->r0 == R_R0) {
+            if (dc->r1 == R_R0 && dc->imm16 == 0) {
+                LOG_DIS("nop\n");
+            } else {
+                LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16));
+            }
+        } else {
+            LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0,
+                    sign_extend(dc->imm16, 16));
+        }
+    } else {
+        LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_and(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else  {
+        if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+            gen_helper_hlt();
+        } else {
+            tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+        }
+    }
+}
+
+static void dec_andhi(DisasContext *dc)
+{
+    LOG_DIS("andhi r%d, r%d, %d\n", dc->r2, dc->r0, dc->imm16);
+
+    tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_b(DisasContext *dc)
+{
+    if (dc->r0 == R_RA) {
+        LOG_DIS("ret\n");
+    } else if (dc->r0 == R_EA) {
+        LOG_DIS("eret\n");
+    } else if (dc->r0 == R_BA) {
+        LOG_DIS("bret\n");
+    } else {
+        LOG_DIS("b r%d\n", dc->r0);
+    }
+
+    /* restore IE.IE in case of an eret */
+    if (dc->r0 == R_EA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_EIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    } else if (dc->r0 == R_BA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_BIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    }
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_bi(DisasContext *dc)
+{
+    LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26));
+
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_cond_branch(DisasContext *dc, int cond)
+{
+    int l1;
+
+    l1 = gen_new_label();
+    tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1);
+    gen_goto_tb(dc, 0, dc->pc + 4);
+    gen_set_label(l1);
+    gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16)));
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static void dec_be(DisasContext *dc)
+{
+    LOG_DIS("be r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_EQ);
+}
+
+static void dec_bg(DisasContext *dc)
+{
+    LOG_DIS("bg r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16 * 4));
+
+    gen_cond_branch(dc, TCG_COND_GT);
+}
+
+static void dec_bge(DisasContext *dc)
+{
+    LOG_DIS("bge r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GE);
+}
+
+static void dec_bgeu(DisasContext *dc)
+{
+    LOG_DIS("bgeu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GEU);
+}
+
+static void dec_bgu(DisasContext *dc)
+{
+    LOG_DIS("bgu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GTU);
+}
+
+static void dec_bne(DisasContext *dc)
+{
+    LOG_DIS("bne r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_NE);
+}
+
+static void dec_call(DisasContext *dc)
+{
+    LOG_DIS("call r%d\n", dc->r0);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_calli(DisasContext *dc)
+{
+    LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_compare(DisasContext *dc, int cond)
+{
+    int rX = (dc->format == OP_FMT_RR) ? dc->r2 : dc->r1;
+    int rY = (dc->format == OP_FMT_RR) ? dc->r0 : dc->r0;
+    int rZ = (dc->format == OP_FMT_RR) ? dc->r1 : -1;
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_setcondi_tl(cond, cpu_R[rX], cpu_R[rY],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_setcond_tl(cond, cpu_R[rX], cpu_R[rY], cpu_R[rZ]);
+    }
+}
+
+static void dec_cmpe(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_EQ);
+}
+
+static void dec_cmpg(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GT);
+}
+
+static void dec_cmpge(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GE);
+}
+
+static void dec_cmpgeu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GEU);
+}
+
+static void dec_cmpgu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GTU);
+}
+
+static void dec_cmpne(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_NE);
+}
+
+static void dec_divu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_lb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lbu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lhu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16));
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_modu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_mul(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("muli r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
+        cpu_abort(dc->env, "hardware multiplier is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_nor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("nori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16));
+        tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_or(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_orhi(DisasContext *dc)
+{
+    if (dc->r0 == R_R0) {
+        LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16);
+    } else {
+        LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
+    }
+
+    tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_scall(DisasContext *dc)
+{
+    if (dc->imm5 == 7) {
+        LOG_DIS("scall\n");
+    } else if (dc->imm5 == 2) {
+        LOG_DIS("break\n");
+    } else {
+        cpu_abort(dc->env, "invalid opcode\n");
+    }
+
+    if (dc->imm5 == 7) {
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_BREAKPOINT);
+    }
+}
+
+static void dec_rcsr(DisasContext *dc)
+{
+    LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie);
+        break;
+    case CSR_IM:
+        gen_helper_rcsr_im(cpu_R[dc->r2]);
+        break;
+    case CSR_IP:
+        gen_helper_rcsr_ip(cpu_R[dc->r2]);
+        break;
+    case CSR_CC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc);
+        break;
+    case CSR_CFG:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg);
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba);
+        break;
+    case CSR_JTX:
+        gen_helper_rcsr_jtx(cpu_R[dc->r2]);
+        break;
+    case CSR_JRX:
+        gen_helper_rcsr_jrx(cpu_R[dc->r2]);
+        break;
+    case CSR_ICC:
+    case CSR_DCC:
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_sb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sextb(DisasContext *dc)
+{
+    LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sexth(DisasContext *dc)
+{
+    LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sl(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        cpu_abort(dc->env, "hardware shifter is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sr(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sru(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sub(DisasContext *dc)
+{
+    LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_sw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_user(DisasContext *dc)
+{
+    LOG_DIS("user");
+
+    cpu_abort(dc->env, "user insn undefined\n");
+}
+
+static void dec_wcsr(DisasContext *dc)
+{
+    int no;
+
+    LOG_DIS("wcsr r%d, %d\n", dc->r1, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IM:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_im(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IP:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_ip(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_ICC:
+        /* TODO */
+        break;
+    case CSR_DCC:
+        /* TODO */
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]);
+        break;
+    case CSR_JTX:
+        gen_helper_wcsr_jtx(cpu_R[dc->r1]);
+        break;
+    case CSR_JRX:
+        gen_helper_wcsr_jrx(cpu_R[dc->r1]);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
+        break;
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+        no = dc->csr - CSR_BP0;
+        if (dc->env->num_bps <= no) {
+            cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        no = dc->csr - CSR_WP0;
+        if (dc->env->num_wps <= no) {
+            cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_CC:
+    case CSR_CFG:
+        cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_xnor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xnori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+        tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]);
+    } else {
+        tcg_gen_eqv_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_xor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_ill(DisasContext *dc)
+{
+    cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode);
+}
+
+typedef void (*DecoderInfo)(DisasContext *dc);
+static const DecoderInfo decinfo[] = {
+    dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh,
+    dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl,
+    dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne,
+    dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi,
+    dec_cmpne,
+    dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill,
+    dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl,
+    dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth,
+    dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli,
+    dec_cmpne
+};
+
+static inline void decode(DisasContext *dc)
+{
+    uint32_t ir;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+        tcg_gen_debug_insn_start(dc->pc);
+    }
+
+    dc->ir = ir = ldl_code(dc->pc);
+    LOG_DIS("%8.8x\t", dc->ir);
+
+    /* try guessing 'empty' instruction memory, although it may be a valid
+     * instruction sequence (eg. srui r0, r0, 0) */
+    if (dc->ir) {
+        dc->nr_nops = 0;
+    } else {
+        LOG_DIS("nr_nops=%d\t", dc->nr_nops);
+        dc->nr_nops++;
+        if (dc->nr_nops > 4) {
+            cpu_abort(dc->env, "fetching nop sequence\n");
+        }
+    }
+
+    dc->opcode = EXTRACT_FIELD(ir, 26, 31);
+
+    dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
+    dc->imm16 = EXTRACT_FIELD(ir, 0, 15);
+    dc->imm26 = EXTRACT_FIELD(ir, 0, 25);
+
+    dc->csr = EXTRACT_FIELD(ir, 21, 25);
+    dc->r0 = EXTRACT_FIELD(ir, 21, 25);
+    dc->r1 = EXTRACT_FIELD(ir, 16, 20);
+    dc->r2 = EXTRACT_FIELD(ir, 11, 15);
+
+    /* bit 31 seems to indicate insn type.  */
+    if (ir & (1 << 31)) {
+        dc->format = OP_FMT_RR;
+    } else {
+        dc->format = OP_FMT_RI;
+    }
+
+    assert(ARRAY_SIZE(decinfo) == 64);
+    assert(dc->opcode < 64);
+
+    decinfo[dc->opcode](dc);
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_tl(cpu_pc, dc->pc);
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+static void gen_intermediate_code_internal(CPUState *env,
+        TranslationBlock *tb, int search_pc)
+{
+    struct DisasContext ctx, *dc = &ctx;
+    uint16_t *gen_opc_end;
+    uint32_t pc_start;
+    int j, lj;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    qemu_log_try_set_file(stderr);
+
+    pc_start = tb->pc;
+    dc->env = env;
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->nr_nops = 0;
+
+    if (pc_start & 3) {
+        cpu_abort(env, "LM32: unaligned PC=%x\n", pc_start);
+    }
+
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("-----------------------------------------\n");
+        log_cpu_state(env, 0);
+    }
+
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    gen_icount_start();
+    do {
+        check_breakpoint(env, dc);
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+
+        /* Pretty disas.  */
+        LOG_DIS("%8.8x:\t", dc->pc);
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        decode(dc);
+        dc->pc += 4;
+        num_insns++;
+
+    } while (!dc->is_jmp
+         && gen_opc_ptr < gen_opc_end
+         && !env->singlestep_enabled
+         && !singlestep
+         && (dc->pc < next_page_start)
+         && num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    if (unlikely(env->singlestep_enabled)) {
+        if (dc->is_jmp == DISAS_NEXT) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc);
+        }
+        t_gen_raise_exception(dc, EXCP_DEBUG);
+    } else {
+        switch (dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 1, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+        case DISAS_UPDATE:
+            /* indicate that the hash table must be used
+               to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        }
+    }
+
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j) {
+            gen_opc_instr_start[lj++] = 0;
+        }
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("\n");
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\nisize=%d osize=%td\n",
+            dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+    }
+#endif
+}
+
+void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    int i;
+
+    if (!env || !f) {
+        return;
+    }
+
+    cpu_fprintf(f, "IN: PC=%x %s\n",
+                env->pc, lookup_symbol(env->pc));
+
+    cpu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n",
+             env->ie,
+             (env->ie & IE_IE) ? 1 : 0,
+             (env->ie & IE_EIE) ? 1 : 0,
+             (env->ie & IE_BIE) ? 1 : 0,
+             lm32_pic_get_im(env->pic_state),
+             lm32_pic_get_ip(env->pic_state));
+    cpu_fprintf(f, "eba=%8.8x deba=%8.8x\n",
+             env->eba,
+             env->deba);
+
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
+        if ((i + 1) % 4 == 0) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+    cpu_fprintf(f, "\n\n");
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
+
+void lm32_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
+        cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, regs[i]),
+                          regnames[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpu_bp); i++) {
+        cpu_bp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, bp[i]),
+                          regnames[32+i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) {
+        cpu_wp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, wp[i]),
+                          regnames[36+i]);
+    }
+
+    cpu_pc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, pc),
+                    "pc");
+    cpu_ie = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, ie),
+                    "ie");
+    cpu_icc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, icc),
+                    "icc");
+    cpu_dcc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dcc),
+                    "dcc");
+    cpu_cc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cc),
+                    "cc");
+    cpu_cfg = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cfg),
+                    "cfg");
+    cpu_eba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, eba),
+                    "eba");
+    cpu_dc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dc),
+                    "dc");
+    cpu_deba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, deba),
+                    "deba");
+}
+
diff --git a/qemu-0.15.x/target-m68k/cpu.h b/qemu-0.15.x/target-m68k/cpu.h
new file mode 100644
index 0000000..e0f9b32
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/cpu.h
@@ -0,0 +1,270 @@
+/*
+ * m68k virtual CPU header
+ *
+ *  Copyright (c) 2005-2007 CodeSourcery
+ *  Written by Paul Brook
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_M68K_H
+#define CPU_M68K_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPUM68KState
+
+#include "qemu-common.h"
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define MAX_QREGS 32
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_68K
+
+#define EXCP_ACCESS         2   /* Access (MMU) error.  */
+#define EXCP_ADDRESS        3   /* Address error.  */
+#define EXCP_ILLEGAL        4   /* Illegal instruction.  */
+#define EXCP_DIV0           5   /* Divide by zero */
+#define EXCP_PRIVILEGE      8   /* Privilege violation.  */
+#define EXCP_TRACE          9
+#define EXCP_LINEA          10  /* Unimplemented line-A (MAC) opcode.  */
+#define EXCP_LINEF          11  /* Unimplemented line-F (FPU) opcode.  */
+#define EXCP_DEBUGNBP       12  /* Non-breakpoint debug interrupt.  */
+#define EXCP_DEBEGBP        13  /* Breakpoint debug interrupt.  */
+#define EXCP_FORMAT         14  /* RTE format error.  */
+#define EXCP_UNINITIALIZED  15
+#define EXCP_TRAP0          32   /* User trap #0.  */
+#define EXCP_TRAP15         47   /* User trap #15.  */
+#define EXCP_UNSUPPORTED    61
+#define EXCP_ICE            13
+
+#define EXCP_RTE            0x100
+#define EXCP_HALT_INSN      0x101
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUM68KState {
+    uint32_t dregs[8];
+    uint32_t aregs[8];
+    uint32_t pc;
+    uint32_t sr;
+
+    /* SSP and USP.  The current_sp is stored in aregs[7], the other here.  */
+    int current_sp;
+    uint32_t sp[2];
+
+    /* Condition flags.  */
+    uint32_t cc_op;
+    uint32_t cc_dest;
+    uint32_t cc_src;
+    uint32_t cc_x;
+
+    float64 fregs[8];
+    float64 fp_result;
+    uint32_t fpcr;
+    uint32_t fpsr;
+    float_status fp_status;
+
+    uint64_t mactmp;
+    /* EMAC Hardware deals with 48-bit values composed of one 32-bit and
+       two 8-bit parts.  We store a single 64-bit value and
+       rearrange/extend this when changing modes.  */
+    uint64_t macc[4];
+    uint32_t macsr;
+    uint32_t mac_mask;
+
+    /* Temporary storage for DIV helpers.  */
+    uint32_t div1;
+    uint32_t div2;
+
+    /* MMU status.  */
+    struct {
+        uint32_t ar;
+    } mmu;
+
+    /* Control registers.  */
+    uint32_t vbr;
+    uint32_t mbar;
+    uint32_t rambar0;
+    uint32_t cacr;
+
+    /* ??? remove this.  */
+    uint32_t t1;
+
+    int pending_vector;
+    int pending_level;
+
+    uint32_t qregs[MAX_QREGS];
+
+    CPU_COMMON
+
+    uint32_t features;
+} CPUM68KState;
+
+void m68k_tcg_init(void);
+CPUM68KState *cpu_m68k_init(const char *cpu_model);
+int cpu_m68k_exec(CPUM68KState *s);
+void cpu_m68k_close(CPUM68KState *s);
+void do_interrupt(CPUState *env1);
+void do_interrupt_m68k_hardirq(CPUState *env1);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_m68k_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+void cpu_m68k_flush_flags(CPUM68KState *, int);
+
+enum {
+    CC_OP_DYNAMIC, /* Use env->cc_op  */
+    CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */
+    CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */
+    CC_OP_ADD,   /* CC_DEST = result, CC_SRC = source */
+    CC_OP_SUB,   /* CC_DEST = result, CC_SRC = source */
+    CC_OP_CMPB,  /* CC_DEST = result, CC_SRC = source */
+    CC_OP_CMPW,  /* CC_DEST = result, CC_SRC = source */
+    CC_OP_ADDX,  /* CC_DEST = result, CC_SRC = source */
+    CC_OP_SUBX,  /* CC_DEST = result, CC_SRC = source */
+    CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */
+};
+
+#define CCF_C 0x01
+#define CCF_V 0x02
+#define CCF_Z 0x04
+#define CCF_N 0x08
+#define CCF_X 0x10
+
+#define SR_I_SHIFT 8
+#define SR_I  0x0700
+#define SR_M  0x1000
+#define SR_S  0x2000
+#define SR_T  0x8000
+
+#define M68K_SSP    0
+#define M68K_USP    1
+
+/* CACR fields are implementation defined, but some bits are common.  */
+#define M68K_CACR_EUSP  0x10
+
+#define MACSR_PAV0  0x100
+#define MACSR_OMC   0x080
+#define MACSR_SU    0x040
+#define MACSR_FI    0x020
+#define MACSR_RT    0x010
+#define MACSR_N     0x008
+#define MACSR_Z     0x004
+#define MACSR_V     0x002
+#define MACSR_EV    0x001
+
+void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
+void m68k_set_macsr(CPUM68KState *env, uint32_t val);
+void m68k_switch_sp(CPUM68KState *env);
+
+#define M68K_FPCR_PREC (1 << 6)
+
+void do_m68k_semihosting(CPUM68KState *env, int nr);
+
+/* There are 4 ColdFire core ISA revisions: A, A+, B and C.
+   Each feature covers the subset of instructions common to the
+   ISA revisions mentioned.  */
+
+enum m68k_features {
+    M68K_FEATURE_CF_ISA_A,
+    M68K_FEATURE_CF_ISA_B, /* (ISA B or C).  */
+    M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C).  */
+    M68K_FEATURE_BRAL, /* Long unconditional branch.  (ISA A+ or B).  */
+    M68K_FEATURE_CF_FPU,
+    M68K_FEATURE_CF_MAC,
+    M68K_FEATURE_CF_EMAC,
+    M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate).  */
+    M68K_FEATURE_USP, /* User Stack Pointer.  (ISA A+, B or C).  */
+    M68K_FEATURE_EXT_FULL, /* 68020+ full extension word.  */
+    M68K_FEATURE_WORD_INDEX /* word sized address index registers.  */
+};
+
+static inline int m68k_feature(CPUM68KState *env, int feature)
+{
+    return (env->features & (1u << feature)) != 0;
+}
+
+void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+void register_m68k_insns (CPUM68KState *env);
+
+#ifdef CONFIG_USER_ONLY
+/* Linux uses 8k pages.  */
+#define TARGET_PAGE_BITS 13
+#else
+/* Smallest TLB entry size is 1k.  */
+#define TARGET_PAGE_BITS 10
+#endif
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define cpu_init cpu_m68k_init
+#define cpu_exec cpu_m68k_exec
+#define cpu_gen_code cpu_m68k_gen_code
+#define cpu_signal_handler cpu_m68k_signal_handler
+#define cpu_list m68k_cpu_list
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->sr & SR_S) == 0 ? 1 : 0;
+}
+
+int cpu_m68k_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_m68k_handle_mmu_fault
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->aregs[7] = newsp;
+    env->dregs[0] = 0;
+}
+#endif
+
+#include "cpu-all.h"
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = (env->fpcr & M68K_FPCR_PREC)       /* Bit  6 */
+            | (env->sr & SR_S)                  /* Bit  13 */
+            | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-m68k/exec.h b/qemu-0.15.x/target-m68k/exec.h
new file mode 100644
index 0000000..93e7912
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/exec.h
@@ -0,0 +1,28 @@
+/*
+ *  m68k execution defines
+ *
+ *  Copyright (c) 2005-2006 CodeSourcery
+ *  Written by Paul Brook
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dyngen-exec.h"
+
+register struct CPUM68KState *env asm(AREG0);
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
diff --git a/qemu-0.15.x/target-m68k/helper.c b/qemu-0.15.x/target-m68k/helper.c
new file mode 100644
index 0000000..a936fe7
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/helper.c
@@ -0,0 +1,923 @@
+/*
+ *  m68k op helpers
+ *
+ *  Copyright (c) 2006-2007 CodeSourcery
+ *  Written by Paul Brook
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "gdbstub.h"
+
+#include "helpers.h"
+
+#define SIGNBIT (1u << 31)
+
+enum m68k_cpuid {
+    M68K_CPUID_M5206,
+    M68K_CPUID_M5208,
+    M68K_CPUID_CFV4E,
+    M68K_CPUID_ANY,
+};
+
+typedef struct m68k_def_t m68k_def_t;
+
+struct m68k_def_t {
+    const char * name;
+    enum m68k_cpuid id;
+};
+
+static m68k_def_t m68k_cpu_defs[] = {
+    {"m5206", M68K_CPUID_M5206},
+    {"m5208", M68K_CPUID_M5208},
+    {"cfv4e", M68K_CPUID_CFV4E},
+    {"any", M68K_CPUID_ANY},
+    {NULL, 0},
+};
+
+void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    unsigned int i;
+
+    for (i = 0; m68k_cpu_defs[i].name; i++) {
+        (*cpu_fprintf)(f, "%s\n", m68k_cpu_defs[i].name);
+    }
+}
+
+static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        stfq_p(mem_buf, env->fregs[n]);
+        return 8;
+    }
+    if (n < 11) {
+        /* FP control registers (not implemented)  */
+        memset(mem_buf, 0, 4);
+        return 4;
+    }
+    return 0;
+}
+
+static int fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        env->fregs[n] = ldfq_p(mem_buf);
+        return 8;
+    }
+    if (n < 11) {
+        /* FP control registers (not implemented)  */
+        return 4;
+    }
+    return 0;
+}
+
+static void m68k_set_feature(CPUM68KState *env, int feature)
+{
+    env->features |= (1u << feature);
+}
+
+static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
+{
+    m68k_def_t *def;
+
+    for (def = m68k_cpu_defs; def->name; def++) {
+        if (strcmp(def->name, name) == 0)
+            break;
+    }
+    if (!def->name)
+        return -1;
+
+    switch (def->id) {
+    case M68K_CPUID_M5206:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        break;
+    case M68K_CPUID_M5208:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        break;
+    case M68K_CPUID_CFV4E:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        break;
+    case M68K_CPUID_ANY:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
+        /* MAC and EMAC are mututally exclusive, so pick EMAC.
+           It's mostly backwards compatible.  */
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
+        m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
+        break;
+    }
+
+    register_m68k_insns(env);
+    if (m68k_feature (env, M68K_FEATURE_CF_FPU)) {
+        gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
+                                 11, "cf-fp.xml", 18);
+    }
+    /* TODO: Add [E]MAC registers.  */
+    return 0;
+}
+
+void cpu_reset(CPUM68KState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    memset(env, 0, offsetof(CPUM68KState, breakpoints));
+#if !defined (CONFIG_USER_ONLY)
+    env->sr = 0x2700;
+#endif
+    m68k_switch_sp(env);
+    /* ??? FP regs should be initialized to NaN.  */
+    env->cc_op = CC_OP_FLAGS;
+    /* TODO: We should set PC from the interrupt vector.  */
+    env->pc = 0;
+    tlb_flush(env, 1);
+}
+
+CPUM68KState *cpu_m68k_init(const char *cpu_model)
+{
+    CPUM68KState *env;
+    static int inited;
+
+    env = qemu_mallocz(sizeof(CPUM68KState));
+    cpu_exec_init(env);
+    if (!inited) {
+        inited = 1;
+        m68k_tcg_init();
+    }
+
+    env->cpu_model_str = cpu_model;
+
+    if (cpu_m68k_set_model(env, cpu_model) < 0) {
+        cpu_m68k_close(env);
+        return NULL;
+    }
+
+    cpu_reset(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+void cpu_m68k_close(CPUM68KState *env)
+{
+    qemu_free(env);
+}
+
+void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
+{
+    int flags;
+    uint32_t src;
+    uint32_t dest;
+    uint32_t tmp;
+
+#define HIGHBIT 0x80000000u
+
+#define SET_NZ(x) do { \
+    if ((x) == 0) \
+        flags |= CCF_Z; \
+    else if ((int32_t)(x) < 0) \
+        flags |= CCF_N; \
+    } while (0)
+
+#define SET_FLAGS_SUB(type, utype) do { \
+    SET_NZ((type)dest); \
+    tmp = dest + src; \
+    if ((utype) tmp < (utype) src) \
+        flags |= CCF_C; \
+    if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
+        flags |= CCF_V; \
+    } while (0)
+
+    flags = 0;
+    src = env->cc_src;
+    dest = env->cc_dest;
+    switch (cc_op) {
+    case CC_OP_FLAGS:
+        flags = dest;
+        break;
+    case CC_OP_LOGIC:
+        SET_NZ(dest);
+        break;
+    case CC_OP_ADD:
+        SET_NZ(dest);
+        if (dest < src)
+            flags |= CCF_C;
+        tmp = dest - src;
+        if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
+            flags |= CCF_V;
+        break;
+    case CC_OP_SUB:
+        SET_FLAGS_SUB(int32_t, uint32_t);
+        break;
+    case CC_OP_CMPB:
+        SET_FLAGS_SUB(int8_t, uint8_t);
+        break;
+    case CC_OP_CMPW:
+        SET_FLAGS_SUB(int16_t, uint16_t);
+        break;
+    case CC_OP_ADDX:
+        SET_NZ(dest);
+        if (dest <= src)
+            flags |= CCF_C;
+        tmp = dest - src - 1;
+        if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
+            flags |= CCF_V;
+        break;
+    case CC_OP_SUBX:
+        SET_NZ(dest);
+        tmp = dest + src + 1;
+        if (tmp <= src)
+            flags |= CCF_C;
+        if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
+            flags |= CCF_V;
+        break;
+    case CC_OP_SHIFT:
+        SET_NZ(dest);
+        if (src)
+            flags |= CCF_C;
+        break;
+    default:
+        cpu_abort(env, "Bad CC_OP %d", cc_op);
+    }
+    env->cc_op = CC_OP_FLAGS;
+    env->cc_dest = flags;
+}
+
+void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
+{
+    switch (reg) {
+    case 0x02: /* CACR */
+        env->cacr = val;
+        m68k_switch_sp(env);
+        break;
+    case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
+        /* TODO: Implement Access Control Registers.  */
+        break;
+    case 0x801: /* VBR */
+        env->vbr = val;
+        break;
+    /* TODO: Implement control registers.  */
+    default:
+        cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
+                  reg, val);
+    }
+}
+
+void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
+{
+    uint32_t acc;
+    int8_t exthigh;
+    uint8_t extlow;
+    uint64_t regval;
+    int i;
+    if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
+        for (i = 0; i < 4; i++) {
+            regval = env->macc[i];
+            exthigh = regval >> 40;
+            if (env->macsr & MACSR_FI) {
+                acc = regval >> 8;
+                extlow = regval;
+            } else {
+                acc = regval;
+                extlow = regval >> 32;
+            }
+            if (env->macsr & MACSR_FI) {
+                regval = (((uint64_t)acc) << 8) | extlow;
+                regval |= ((int64_t)exthigh) << 40;
+            } else if (env->macsr & MACSR_SU) {
+                regval = acc | (((int64_t)extlow) << 32);
+                regval |= ((int64_t)exthigh) << 40;
+            } else {
+                regval = acc | (((uint64_t)extlow) << 32);
+                regval |= ((uint64_t)(uint8_t)exthigh) << 40;
+            }
+            env->macc[i] = regval;
+        }
+    }
+    env->macsr = val;
+}
+
+void m68k_switch_sp(CPUM68KState *env)
+{
+    int new_sp;
+
+    env->sp[env->current_sp] = env->aregs[7];
+    new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
+             ? M68K_SSP : M68K_USP;
+    env->aregs[7] = env->sp[new_sp];
+    env->current_sp = new_sp;
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    env->exception_index = EXCP_ACCESS;
+    env->mmu.ar = address;
+    return 1;
+}
+
+#else
+
+/* MMU */
+
+/* TODO: This will need fixing once the MMU is implemented.  */
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
+
+int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    int prot;
+
+    address &= TARGET_PAGE_MASK;
+    prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+    return 0;
+}
+
+/* Notify CPU of a pending interrupt.  Prioritization and vectoring should
+   be handled by the interrupt controller.  Real hardware only requests
+   the vector when the interrupt is acknowledged by the CPU.  For
+   simplicitly we calculate it when the interrupt is signalled.  */
+void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
+{
+    env->pending_level = level;
+    env->pending_vector = vector;
+    if (level)
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    else
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+#endif
+
+uint32_t HELPER(bitrev)(uint32_t x)
+{
+    x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
+    x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
+    x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
+    return bswap32(x);
+}
+
+uint32_t HELPER(ff1)(uint32_t x)
+{
+    int n;
+    for (n = 32; x; n--)
+        x >>= 1;
+    return n;
+}
+
+uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
+{
+    /* The result has the opposite sign to the original value.  */
+    if (ccr & CCF_V)
+        val = (((int32_t)val) >> 31) ^ SIGNBIT;
+    return val;
+}
+
+uint32_t HELPER(subx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+    uint32_t res;
+    uint32_t old_flags;
+
+    old_flags = env->cc_dest;
+    if (env->cc_x) {
+        env->cc_x = (op1 <= op2);
+        env->cc_op = CC_OP_SUBX;
+        res = op1 - (op2 + 1);
+    } else {
+        env->cc_x = (op1 < op2);
+        env->cc_op = CC_OP_SUB;
+        res = op1 - op2;
+    }
+    env->cc_dest = res;
+    env->cc_src = op2;
+    cpu_m68k_flush_flags(env, env->cc_op);
+    /* !Z is sticky.  */
+    env->cc_dest &= (old_flags | ~CCF_Z);
+    return res;
+}
+
+uint32_t HELPER(addx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+    uint32_t res;
+    uint32_t old_flags;
+
+    old_flags = env->cc_dest;
+    if (env->cc_x) {
+        res = op1 + op2 + 1;
+        env->cc_x = (res <= op2);
+        env->cc_op = CC_OP_ADDX;
+    } else {
+        res = op1 + op2;
+        env->cc_x = (res < op2);
+        env->cc_op = CC_OP_ADD;
+    }
+    env->cc_dest = res;
+    env->cc_src = op2;
+    cpu_m68k_flush_flags(env, env->cc_op);
+    /* !Z is sticky.  */
+    env->cc_dest &= (old_flags | ~CCF_Z);
+    return res;
+}
+
+uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b)
+{
+    return a < b;
+}
+
+void HELPER(set_sr)(CPUState *env, uint32_t val)
+{
+    env->sr = val & 0xffff;
+    m68k_switch_sp(env);
+}
+
+uint32_t HELPER(shl_cc)(CPUState *env, uint32_t val, uint32_t shift)
+{
+    uint32_t result;
+    uint32_t cf;
+
+    shift &= 63;
+    if (shift == 0) {
+        result = val;
+        cf = env->cc_src & CCF_C;
+    } else if (shift < 32) {
+        result = val << shift;
+        cf = (val >> (32 - shift)) & 1;
+    } else if (shift == 32) {
+        result = 0;
+        cf = val & 1;
+    } else /* shift > 32 */ {
+        result = 0;
+        cf = 0;
+    }
+    env->cc_src = cf;
+    env->cc_x = (cf != 0);
+    env->cc_dest = result;
+    return result;
+}
+
+uint32_t HELPER(shr_cc)(CPUState *env, uint32_t val, uint32_t shift)
+{
+    uint32_t result;
+    uint32_t cf;
+
+    shift &= 63;
+    if (shift == 0) {
+        result = val;
+        cf = env->cc_src & CCF_C;
+    } else if (shift < 32) {
+        result = val >> shift;
+        cf = (val >> (shift - 1)) & 1;
+    } else if (shift == 32) {
+        result = 0;
+        cf = val >> 31;
+    } else /* shift > 32 */ {
+        result = 0;
+        cf = 0;
+    }
+    env->cc_src = cf;
+    env->cc_x = (cf != 0);
+    env->cc_dest = result;
+    return result;
+}
+
+uint32_t HELPER(sar_cc)(CPUState *env, uint32_t val, uint32_t shift)
+{
+    uint32_t result;
+    uint32_t cf;
+
+    shift &= 63;
+    if (shift == 0) {
+        result = val;
+        cf = (env->cc_src & CCF_C) != 0;
+    } else if (shift < 32) {
+        result = (int32_t)val >> shift;
+        cf = (val >> (shift - 1)) & 1;
+    } else /* shift >= 32 */ {
+        result = (int32_t)val >> 31;
+        cf = val >> 31;
+    }
+    env->cc_src = cf;
+    env->cc_x = cf;
+    env->cc_dest = result;
+    return result;
+}
+
+/* FPU helpers.  */
+uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
+{
+    return float64_to_int32(val, &env->fp_status);
+}
+
+float32 HELPER(f64_to_f32)(CPUState *env, float64 val)
+{
+    return float64_to_float32(val, &env->fp_status);
+}
+
+float64 HELPER(i32_to_f64)(CPUState *env, uint32_t val)
+{
+    return int32_to_float64(val, &env->fp_status);
+}
+
+float64 HELPER(f32_to_f64)(CPUState *env, float32 val)
+{
+    return float32_to_float64(val, &env->fp_status);
+}
+
+float64 HELPER(iround_f64)(CPUState *env, float64 val)
+{
+    return float64_round_to_int(val, &env->fp_status);
+}
+
+float64 HELPER(itrunc_f64)(CPUState *env, float64 val)
+{
+    return float64_trunc_to_int(val, &env->fp_status);
+}
+
+float64 HELPER(sqrt_f64)(CPUState *env, float64 val)
+{
+    return float64_sqrt(val, &env->fp_status);
+}
+
+float64 HELPER(abs_f64)(float64 val)
+{
+    return float64_abs(val);
+}
+
+float64 HELPER(chs_f64)(float64 val)
+{
+    return float64_chs(val);
+}
+
+float64 HELPER(add_f64)(CPUState *env, float64 a, float64 b)
+{
+    return float64_add(a, b, &env->fp_status);
+}
+
+float64 HELPER(sub_f64)(CPUState *env, float64 a, float64 b)
+{
+    return float64_sub(a, b, &env->fp_status);
+}
+
+float64 HELPER(mul_f64)(CPUState *env, float64 a, float64 b)
+{
+    return float64_mul(a, b, &env->fp_status);
+}
+
+float64 HELPER(div_f64)(CPUState *env, float64 a, float64 b)
+{
+    return float64_div(a, b, &env->fp_status);
+}
+
+float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
+{
+    /* ??? This may incorrectly raise exceptions.  */
+    /* ??? Should flush denormals to zero.  */
+    float64 res;
+    res = float64_sub(a, b, &env->fp_status);
+    if (float64_is_quiet_nan(res)) {
+        /* +/-inf compares equal against itself, but sub returns nan.  */
+        if (!float64_is_quiet_nan(a)
+            && !float64_is_quiet_nan(b)) {
+            res = float64_zero;
+            if (float64_lt_quiet(a, res, &env->fp_status))
+                res = float64_chs(res);
+        }
+    }
+    return res;
+}
+
+uint32_t HELPER(compare_f64)(CPUState *env, float64 val)
+{
+    return float64_compare_quiet(val, float64_zero, &env->fp_status);
+}
+
+/* MAC unit.  */
+/* FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
+   take values,  others take register numbers and manipulate the contents
+   in-place.  */
+void HELPER(mac_move)(CPUState *env, uint32_t dest, uint32_t src)
+{
+    uint32_t mask;
+    env->macc[dest] = env->macc[src];
+    mask = MACSR_PAV0 << dest;
+    if (env->macsr & (MACSR_PAV0 << src))
+        env->macsr |= mask;
+    else
+        env->macsr &= ~mask;
+}
+
+uint64_t HELPER(macmuls)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+    int64_t product;
+    int64_t res;
+
+    product = (uint64_t)op1 * op2;
+    res = (product << 24) >> 24;
+    if (res != product) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            if (product < 0)
+                res = ~(1ll << 50);
+            else
+                res = 1ll << 50;
+        }
+    }
+    return res;
+}
+
+uint64_t HELPER(macmulu)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+    uint64_t product;
+
+    product = (uint64_t)op1 * op2;
+    if (product & (0xffffffull << 40)) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            product = 1ll << 50;
+        } else {
+            product &= ((1ull << 40) - 1);
+        }
+    }
+    return product;
+}
+
+uint64_t HELPER(macmulf)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+    uint64_t product;
+    uint32_t remainder;
+
+    product = (uint64_t)op1 * op2;
+    if (env->macsr & MACSR_RT) {
+        remainder = product & 0xffffff;
+        product >>= 24;
+        if (remainder > 0x800000)
+            product++;
+        else if (remainder == 0x800000)
+            product += (product & 1);
+    } else {
+        product >>= 24;
+    }
+    return product;
+}
+
+void HELPER(macsats)(CPUState *env, uint32_t acc)
+{
+    int64_t tmp;
+    int64_t result;
+    tmp = env->macc[acc];
+    result = ((tmp << 16) >> 16);
+    if (result != tmp) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            /* The result is saturated to 32 bits, despite overflow occurring
+               at 48 bits.  Seems weird, but that's what the hardware docs
+               say.  */
+            result = (result >> 63) ^ 0x7fffffff;
+        }
+    }
+    env->macc[acc] = result;
+}
+
+void HELPER(macsatu)(CPUState *env, uint32_t acc)
+{
+    uint64_t val;
+
+    val = env->macc[acc];
+    if (val & (0xffffull << 48)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            if (val > (1ull << 53))
+                val = 0;
+            else
+                val = (1ull << 48) - 1;
+        } else {
+            val &= ((1ull << 48) - 1);
+        }
+    }
+    env->macc[acc] = val;
+}
+
+void HELPER(macsatf)(CPUState *env, uint32_t acc)
+{
+    int64_t sum;
+    int64_t result;
+
+    sum = env->macc[acc];
+    result = (sum << 16) >> 16;
+    if (result != sum) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            result = (result >> 63) ^ 0x7fffffffffffll;
+        }
+    }
+    env->macc[acc] = result;
+}
+
+void HELPER(mac_set_flags)(CPUState *env, uint32_t acc)
+{
+    uint64_t val;
+    val = env->macc[acc];
+    if (val == 0) {
+        env->macsr |= MACSR_Z;
+    } else if (val & (1ull << 47)) {
+        env->macsr |= MACSR_N;
+    }
+    if (env->macsr & (MACSR_PAV0 << acc)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_FI) {
+        val = ((int64_t)val) >> 40;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else if (env->macsr & MACSR_SU) {
+        val = ((int64_t)val) >> 32;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else {
+        if ((val >> 32) != 0)
+            env->macsr |= MACSR_EV;
+    }
+}
+
+void HELPER(flush_flags)(CPUState *env, uint32_t cc_op)
+{
+    cpu_m68k_flush_flags(env, cc_op);
+}
+
+uint32_t HELPER(get_macf)(CPUState *env, uint64_t val)
+{
+    int rem;
+    uint32_t result;
+
+    if (env->macsr & MACSR_SU) {
+        /* 16-bit rounding.  */
+        rem = val & 0xffffff;
+        val = (val >> 24) & 0xffffu;
+        if (rem > 0x800000)
+            val++;
+        else if (rem == 0x800000)
+            val += (val & 1);
+    } else if (env->macsr & MACSR_RT) {
+        /* 32-bit rounding.  */
+        rem = val & 0xff;
+        val >>= 8;
+        if (rem > 0x80)
+            val++;
+        else if (rem == 0x80)
+            val += (val & 1);
+    } else {
+        /* No rounding.  */
+        val >>= 8;
+    }
+    if (env->macsr & MACSR_OMC) {
+        /* Saturate.  */
+        if (env->macsr & MACSR_SU) {
+            if (val != (uint16_t) val) {
+                result = ((val >> 63) ^ 0x7fff) & 0xffff;
+            } else {
+                result = val & 0xffff;
+            }
+        } else {
+            if (val != (uint32_t)val) {
+                result = ((uint32_t)(val >> 63) & 0x7fffffff);
+            } else {
+                result = (uint32_t)val;
+            }
+        }
+    } else {
+        /* No saturation.  */
+        if (env->macsr & MACSR_SU) {
+            result = val & 0xffff;
+        } else {
+            result = (uint32_t)val;
+        }
+    }
+    return result;
+}
+
+uint32_t HELPER(get_macs)(uint64_t val)
+{
+    if (val == (int32_t)val) {
+        return (int32_t)val;
+    } else {
+        return (val >> 61) ^ ~SIGNBIT;
+    }
+}
+
+uint32_t HELPER(get_macu)(uint64_t val)
+{
+    if ((val >> 32) == 0) {
+        return (uint32_t)val;
+    } else {
+        return 0xffffffffu;
+    }
+}
+
+uint32_t HELPER(get_mac_extf)(CPUState *env, uint32_t acc)
+{
+    uint32_t val;
+    val = env->macc[acc] & 0x00ff;
+    val = (env->macc[acc] >> 32) & 0xff00;
+    val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
+    val |= (env->macc[acc + 1] >> 16) & 0xff000000;
+    return val;
+}
+
+uint32_t HELPER(get_mac_exti)(CPUState *env, uint32_t acc)
+{
+    uint32_t val;
+    val = (env->macc[acc] >> 32) & 0xffff;
+    val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
+    return val;
+}
+
+void HELPER(set_mac_extf)(CPUState *env, uint32_t val, uint32_t acc)
+{
+    int64_t res;
+    int32_t tmp;
+    res = env->macc[acc] & 0xffffffff00ull;
+    tmp = (int16_t)(val & 0xff00);
+    res |= ((int64_t)tmp) << 32;
+    res |= val & 0xff;
+    env->macc[acc] = res;
+    res = env->macc[acc + 1] & 0xffffffff00ull;
+    tmp = (val & 0xff000000);
+    res |= ((int64_t)tmp) << 16;
+    res |= (val >> 16) & 0xff;
+    env->macc[acc + 1] = res;
+}
+
+void HELPER(set_mac_exts)(CPUState *env, uint32_t val, uint32_t acc)
+{
+    int64_t res;
+    int32_t tmp;
+    res = (uint32_t)env->macc[acc];
+    tmp = (int16_t)val;
+    res |= ((int64_t)tmp) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    tmp = val & 0xffff0000;
+    res |= (int64_t)tmp << 16;
+    env->macc[acc + 1] = res;
+}
+
+void HELPER(set_mac_extu)(CPUState *env, uint32_t val, uint32_t acc)
+{
+    uint64_t res;
+    res = (uint32_t)env->macc[acc];
+    res |= ((uint64_t)(val & 0xffff)) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    res |= (uint64_t)(val & 0xffff0000) << 16;
+    env->macc[acc + 1] = res;
+}
diff --git a/qemu-0.15.x/target-m68k/helpers.h b/qemu-0.15.x/target-m68k/helpers.h
new file mode 100644
index 0000000..cb8a0c7
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/helpers.h
@@ -0,0 +1,54 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(bitrev, i32, i32)
+DEF_HELPER_1(ff1, i32, i32)
+DEF_HELPER_2(sats, i32, i32, i32)
+DEF_HELPER_2(divu, void, env, i32)
+DEF_HELPER_2(divs, void, env, i32)
+DEF_HELPER_3(addx_cc, i32, env, i32, i32)
+DEF_HELPER_3(subx_cc, i32, env, i32, i32)
+DEF_HELPER_3(shl_cc, i32, env, i32, i32)
+DEF_HELPER_3(shr_cc, i32, env, i32, i32)
+DEF_HELPER_3(sar_cc, i32, env, i32, i32)
+DEF_HELPER_2(xflag_lt, i32, i32, i32)
+DEF_HELPER_2(set_sr, void, env, i32)
+DEF_HELPER_3(movec, void, env, i32, i32)
+
+DEF_HELPER_2(f64_to_i32, f32, env, f64)
+DEF_HELPER_2(f64_to_f32, f32, env, f64)
+DEF_HELPER_2(i32_to_f64, f64, env, i32)
+DEF_HELPER_2(f32_to_f64, f64, env, f32)
+DEF_HELPER_2(iround_f64, f64, env, f64)
+DEF_HELPER_2(itrunc_f64, f64, env, f64)
+DEF_HELPER_2(sqrt_f64, f64, env, f64)
+DEF_HELPER_1(abs_f64, f64, f64)
+DEF_HELPER_1(chs_f64, f64, f64)
+DEF_HELPER_3(add_f64, f64, env, f64, f64)
+DEF_HELPER_3(sub_f64, f64, env, f64, f64)
+DEF_HELPER_3(mul_f64, f64, env, f64, f64)
+DEF_HELPER_3(div_f64, f64, env, f64, f64)
+DEF_HELPER_3(sub_cmp_f64, f64, env, f64, f64)
+DEF_HELPER_2(compare_f64, i32, env, f64)
+
+DEF_HELPER_3(mac_move, void, env, i32, i32)
+DEF_HELPER_3(macmulf, i64, env, i32, i32)
+DEF_HELPER_3(macmuls, i64, env, i32, i32)
+DEF_HELPER_3(macmulu, i64, env, i32, i32)
+DEF_HELPER_2(macsats, void, env, i32)
+DEF_HELPER_2(macsatu, void, env, i32)
+DEF_HELPER_2(macsatf, void, env, i32)
+DEF_HELPER_2(mac_set_flags, void, env, i32)
+DEF_HELPER_2(set_macsr, void, env, i32)
+DEF_HELPER_2(get_macf, i32, env, i64)
+DEF_HELPER_1(get_macs, i32, i64)
+DEF_HELPER_1(get_macu, i32, i64)
+DEF_HELPER_2(get_mac_extf, i32, env, i32)
+DEF_HELPER_2(get_mac_exti, i32, env, i32)
+DEF_HELPER_3(set_mac_extf, void, env, i32, i32)
+DEF_HELPER_3(set_mac_exts, void, env, i32, i32)
+DEF_HELPER_3(set_mac_extu, void, env, i32, i32)
+
+DEF_HELPER_2(flush_flags, void, env, i32)
+DEF_HELPER_1(raise_exception, void, i32)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-m68k/m68k-qreg.h b/qemu-0.15.x/target-m68k/m68k-qreg.h
new file mode 100644
index 0000000..c224d5e
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/m68k-qreg.h
@@ -0,0 +1,11 @@
+enum {
+#define DEFO32(name, offset) QREG_##name,
+#define DEFR(name, reg, mode) QREG_##name,
+#define DEFF64(name, offset) QREG_##name,
+    QREG_NULL,
+#include "qregs.def"
+    TARGET_NUM_QREGS = 0x100
+#undef DEFO32
+#undef DEFR
+#undef DEFF64
+};
diff --git a/qemu-0.15.x/target-m68k/machine.c b/qemu-0.15.x/target-m68k/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/qemu-0.15.x/target-m68k/op_helper.c b/qemu-0.15.x/target-m68k/op_helper.c
new file mode 100644
index 0000000..237fc4c
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/op_helper.c
@@ -0,0 +1,248 @@
+/*
+ *  M68K helper routines
+ *
+ *  Copyright (c) 2007 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "exec.h"
+#include "helpers.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt(CPUState *env1)
+{
+    env1->exception_index = -1;
+}
+
+void do_interrupt_m68k_hardirq(CPUState *env1)
+{
+}
+
+#else
+
+extern int semihosting_enabled;
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+
+static void do_rte(void)
+{
+    uint32_t sp;
+    uint32_t fmt;
+
+    sp = env->aregs[7];
+    fmt = ldl_kernel(sp);
+    env->pc = ldl_kernel(sp + 4);
+    sp |= (fmt >> 28) & 3;
+    env->sr = fmt & 0xffff;
+    m68k_switch_sp(env);
+    env->aregs[7] = sp + 8;
+}
+
+static void do_interrupt_all(int is_hw)
+{
+    uint32_t sp;
+    uint32_t fmt;
+    uint32_t retaddr;
+    uint32_t vector;
+
+    fmt = 0;
+    retaddr = env->pc;
+
+    if (!is_hw) {
+        switch (env->exception_index) {
+        case EXCP_RTE:
+            /* Return from an exception.  */
+            do_rte();
+            return;
+        case EXCP_HALT_INSN:
+            if (semihosting_enabled
+                    && (env->sr & SR_S) != 0
+                    && (env->pc & 3) == 0
+                    && lduw_code(env->pc - 4) == 0x4e71
+                    && ldl_code(env->pc) == 0x4e7bf000) {
+                env->pc += 4;
+                do_m68k_semihosting(env, env->dregs[0]);
+                return;
+            }
+            env->halted = 1;
+            env->exception_index = EXCP_HLT;
+            cpu_loop_exit(env);
+            return;
+        }
+        if (env->exception_index >= EXCP_TRAP0
+            && env->exception_index <= EXCP_TRAP15) {
+            /* Move the PC after the trap instruction.  */
+            retaddr += 2;
+        }
+    }
+
+    vector = env->exception_index << 2;
+
+    sp = env->aregs[7];
+
+    fmt |= 0x40000000;
+    fmt |= (sp & 3) << 28;
+    fmt |= vector << 16;
+    fmt |= env->sr;
+
+    env->sr |= SR_S;
+    if (is_hw) {
+        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
+        env->sr &= ~SR_M;
+    }
+    m68k_switch_sp(env);
+
+    /* ??? This could cause MMU faults.  */
+    sp &= ~3;
+    sp -= 4;
+    stl_kernel(sp, retaddr);
+    sp -= 4;
+    stl_kernel(sp, fmt);
+    env->aregs[7] = sp;
+    /* Jump to vector.  */
+    env->pc = ldl_kernel(env->vbr + vector);
+}
+
+void do_interrupt(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(0);
+    env = saved_env;
+}
+
+void do_interrupt_m68k_hardirq(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(1);
+    env = saved_env;
+}
+#endif
+
+static void raise_exception(int tt)
+{
+    env->exception_index = tt;
+    cpu_loop_exit(env);
+}
+
+void HELPER(raise_exception)(uint32_t tt)
+{
+    raise_exception(tt);
+}
+
+void HELPER(divu)(CPUState *env, uint32_t word)
+{
+    uint32_t num;
+    uint32_t den;
+    uint32_t quot;
+    uint32_t rem;
+    uint32_t flags;
+
+    num = env->div1;
+    den = env->div2;
+    /* ??? This needs to make sure the throwing location is accurate.  */
+    if (den == 0)
+        raise_exception(EXCP_DIV0);
+    quot = num / den;
+    rem = num % den;
+    flags = 0;
+    /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
+       the address of a symbol, and gcc knows symbols can't have address
+       zero.  */
+    if (word && quot > 0xffff)
+        flags |= CCF_V;
+    if (quot == 0)
+        flags |= CCF_Z;
+    else if ((int32_t)quot < 0)
+        flags |= CCF_N;
+    env->div1 = quot;
+    env->div2 = rem;
+    env->cc_dest = flags;
+}
+
+void HELPER(divs)(CPUState *env, uint32_t word)
+{
+    int32_t num;
+    int32_t den;
+    int32_t quot;
+    int32_t rem;
+    int32_t flags;
+
+    num = env->div1;
+    den = env->div2;
+    if (den == 0)
+        raise_exception(EXCP_DIV0);
+    quot = num / den;
+    rem = num % den;
+    flags = 0;
+    if (word && quot != (int16_t)quot)
+        flags |= CCF_V;
+    if (quot == 0)
+        flags |= CCF_Z;
+    else if (quot < 0)
+        flags |= CCF_N;
+    env->div1 = quot;
+    env->div2 = rem;
+    env->cc_dest = flags;
+}
diff --git a/qemu-0.15.x/target-m68k/qregs.def b/qemu-0.15.x/target-m68k/qregs.def
new file mode 100644
index 0000000..49400c4
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/qregs.def
@@ -0,0 +1,13 @@
+DEFF64(FP_RESULT, fp_result)
+DEFO32(PC, pc)
+DEFO32(SR, sr)
+DEFO32(CC_OP, cc_op)
+DEFO32(CC_DEST, cc_dest)
+DEFO32(CC_SRC, cc_src)
+DEFO32(CC_X, cc_x)
+DEFO32(DIV1, div1)
+DEFO32(DIV2, div2)
+DEFO32(EXCEPTION, exception_index)
+DEFO32(HALTED, halted)
+DEFO32(MACSR, macsr)
+DEFO32(MAC_MASK, mac_mask)
diff --git a/qemu-0.15.x/target-m68k/translate.c b/qemu-0.15.x/target-m68k/translate.c
new file mode 100644
index 0000000..0e7f1fe
--- /dev/null
+++ b/qemu-0.15.x/target-m68k/translate.c
@@ -0,0 +1,3115 @@
+/*
+ *  m68k translation
+ *
+ *  Copyright (c) 2005-2007 CodeSourcery
+ *  Written by Paul Brook
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+//#define DEBUG_DISPATCH 1
+
+/* Fake floating point.  */
+#define tcg_gen_mov_f64 tcg_gen_mov_i64
+#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
+#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
+
+#define DEFO32(name, offset) static TCGv QREG_##name;
+#define DEFO64(name, offset) static TCGv_i64 QREG_##name;
+#define DEFF64(name, offset) static TCGv_i64 QREG_##name;
+#include "qregs.def"
+#undef DEFO32
+#undef DEFO64
+#undef DEFF64
+
+static TCGv_ptr cpu_env;
+
+static char cpu_reg_names[3*8*3 + 5*4];
+static TCGv cpu_dregs[8];
+static TCGv cpu_aregs[8];
+static TCGv_i64 cpu_fregs[8];
+static TCGv_i64 cpu_macc[4];
+
+#define DREG(insn, pos) cpu_dregs[((insn) >> (pos)) & 7]
+#define AREG(insn, pos) cpu_aregs[((insn) >> (pos)) & 7]
+#define FREG(insn, pos) cpu_fregs[((insn) >> (pos)) & 7]
+#define MACREG(acc) cpu_macc[acc]
+#define QREG_SP cpu_aregs[7]
+
+static TCGv NULL_QREG;
+#define IS_NULL_QREG(t) (TCGV_EQUAL(t, NULL_QREG))
+/* Used to distinguish stores from bad addressing modes.  */
+static TCGv store_dummy;
+
+#include "gen-icount.h"
+
+void m68k_tcg_init(void)
+{
+    char *p;
+    int i;
+
+#define DEFO32(name,  offset) QREG_##name = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, offset), #name);
+#define DEFO64(name,  offset) QREG_##name = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, offset), #name);
+#define DEFF64(name,  offset) DEFO64(name, offset)
+#include "qregs.def"
+#undef DEFO32
+#undef DEFO64
+#undef DEFF64
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    p = cpu_reg_names;
+    for (i = 0; i < 8; i++) {
+        sprintf(p, "D%d", i);
+        cpu_dregs[i] = tcg_global_mem_new(TCG_AREG0,
+                                          offsetof(CPUM68KState, dregs[i]), p);
+        p += 3;
+        sprintf(p, "A%d", i);
+        cpu_aregs[i] = tcg_global_mem_new(TCG_AREG0,
+                                          offsetof(CPUM68KState, aregs[i]), p);
+        p += 3;
+        sprintf(p, "F%d", i);
+        cpu_fregs[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUM68KState, fregs[i]), p);
+        p += 3;
+    }
+    for (i = 0; i < 4; i++) {
+        sprintf(p, "ACC%d", i);
+        cpu_macc[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                         offsetof(CPUM68KState, macc[i]), p);
+        p += 5;
+    }
+
+    NULL_QREG = tcg_global_mem_new(TCG_AREG0, -4, "NULL");
+    store_dummy = tcg_global_mem_new(TCG_AREG0, -8, "NULL");
+
+#define GEN_HELPER 2
+#include "helpers.h"
+}
+
+static inline void qemu_assert(int cond, const char *msg)
+{
+    if (!cond) {
+        fprintf (stderr, "badness: %s\n", msg);
+        abort();
+    }
+}
+
+/* internal defines */
+typedef struct DisasContext {
+    CPUM68KState *env;
+    target_ulong insn_pc; /* Start of the current instruction.  */
+    target_ulong pc;
+    int is_jmp;
+    int cc_op;
+    int user;
+    uint32_t fpcr;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+    int is_mem;
+    TCGv_i64 mactmp;
+    int done_mac;
+} DisasContext;
+
+#define DISAS_JUMP_NEXT 4
+
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(s) 1
+#else
+#define IS_USER(s) s->user
+#endif
+
+/* XXX: move that elsewhere */
+/* ??? Fix exceptions.  */
+static void *gen_throws_exception;
+#define gen_last_qop NULL
+
+#define OS_BYTE 0
+#define OS_WORD 1
+#define OS_LONG 2
+#define OS_SINGLE 4
+#define OS_DOUBLE 5
+
+typedef void (*disas_proc)(DisasContext *, uint16_t);
+
+#ifdef DEBUG_DISPATCH
+#define DISAS_INSN(name) \
+  static void real_disas_##name (DisasContext *s, uint16_t insn); \
+  static void disas_##name (DisasContext *s, uint16_t insn) { \
+    qemu_log("Dispatch " #name "\n"); \
+    real_disas_##name(s, insn); } \
+  static void real_disas_##name (DisasContext *s, uint16_t insn)
+#else
+#define DISAS_INSN(name) \
+  static void disas_##name (DisasContext *s, uint16_t insn)
+#endif
+
+/* Generate a load from the specified address.  Narrow values are
+   sign extended to full register width.  */
+static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
+{
+    TCGv tmp;
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tmp = tcg_temp_new_i32();
+    switch(opsize) {
+    case OS_BYTE:
+        if (sign)
+            tcg_gen_qemu_ld8s(tmp, addr, index);
+        else
+            tcg_gen_qemu_ld8u(tmp, addr, index);
+        break;
+    case OS_WORD:
+        if (sign)
+            tcg_gen_qemu_ld16s(tmp, addr, index);
+        else
+            tcg_gen_qemu_ld16u(tmp, addr, index);
+        break;
+    case OS_LONG:
+    case OS_SINGLE:
+        tcg_gen_qemu_ld32u(tmp, addr, index);
+        break;
+    default:
+        qemu_assert(0, "bad load size");
+    }
+    gen_throws_exception = gen_last_qop;
+    return tmp;
+}
+
+static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr)
+{
+    TCGv_i64 tmp;
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ldf64(tmp, addr, index);
+    gen_throws_exception = gen_last_qop;
+    return tmp;
+}
+
+/* Generate a store.  */
+static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
+{
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    switch(opsize) {
+    case OS_BYTE:
+        tcg_gen_qemu_st8(val, addr, index);
+        break;
+    case OS_WORD:
+        tcg_gen_qemu_st16(val, addr, index);
+        break;
+    case OS_LONG:
+    case OS_SINGLE:
+        tcg_gen_qemu_st32(val, addr, index);
+        break;
+    default:
+        qemu_assert(0, "bad store size");
+    }
+    gen_throws_exception = gen_last_qop;
+}
+
+static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val)
+{
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tcg_gen_qemu_stf64(val, addr, index);
+    gen_throws_exception = gen_last_qop;
+}
+
+typedef enum {
+    EA_STORE,
+    EA_LOADU,
+    EA_LOADS
+} ea_what;
+
+/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
+   otherwise generate a store.  */
+static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
+                     ea_what what)
+{
+    if (what == EA_STORE) {
+        gen_store(s, opsize, addr, val);
+        return store_dummy;
+    } else {
+        return gen_load(s, opsize, addr, what == EA_LOADS);
+    }
+}
+
+/* Read a 32-bit immediate constant.  */
+static inline uint32_t read_im32(DisasContext *s)
+{
+    uint32_t im;
+    im = ((uint32_t)lduw_code(s->pc)) << 16;
+    s->pc += 2;
+    im |= lduw_code(s->pc);
+    s->pc += 2;
+    return im;
+}
+
+/* Calculate and address index.  */
+static TCGv gen_addr_index(uint16_t ext, TCGv tmp)
+{
+    TCGv add;
+    int scale;
+
+    add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
+    if ((ext & 0x800) == 0) {
+        tcg_gen_ext16s_i32(tmp, add);
+        add = tmp;
+    }
+    scale = (ext >> 9) & 3;
+    if (scale != 0) {
+        tcg_gen_shli_i32(tmp, add, scale);
+        add = tmp;
+    }
+    return add;
+}
+
+/* Handle a base + index + displacement effective addresss.
+   A NULL_QREG base means pc-relative.  */
+static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
+{
+    uint32_t offset;
+    uint16_t ext;
+    TCGv add;
+    TCGv tmp;
+    uint32_t bd, od;
+
+    offset = s->pc;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
+        return NULL_QREG;
+
+    if (ext & 0x100) {
+        /* full extension word format */
+        if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
+            return NULL_QREG;
+
+        if ((ext & 0x30) > 0x10) {
+            /* base displacement */
+            if ((ext & 0x30) == 0x20) {
+                bd = (int16_t)lduw_code(s->pc);
+                s->pc += 2;
+            } else {
+                bd = read_im32(s);
+            }
+        } else {
+            bd = 0;
+        }
+        tmp = tcg_temp_new();
+        if ((ext & 0x44) == 0) {
+            /* pre-index */
+            add = gen_addr_index(ext, tmp);
+        } else {
+            add = NULL_QREG;
+        }
+        if ((ext & 0x80) == 0) {
+            /* base not suppressed */
+            if (IS_NULL_QREG(base)) {
+                base = tcg_const_i32(offset + bd);
+                bd = 0;
+            }
+            if (!IS_NULL_QREG(add)) {
+                tcg_gen_add_i32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+        }
+        if (!IS_NULL_QREG(add)) {
+            if (bd != 0) {
+                tcg_gen_addi_i32(tmp, add, bd);
+                add = tmp;
+            }
+        } else {
+            add = tcg_const_i32(bd);
+        }
+        if ((ext & 3) != 0) {
+            /* memory indirect */
+            base = gen_load(s, OS_LONG, add, 0);
+            if ((ext & 0x44) == 4) {
+                add = gen_addr_index(ext, tmp);
+                tcg_gen_add_i32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+            if ((ext & 3) > 1) {
+                /* outer displacement */
+                if ((ext & 3) == 2) {
+                    od = (int16_t)lduw_code(s->pc);
+                    s->pc += 2;
+                } else {
+                    od = read_im32(s);
+                }
+            } else {
+                od = 0;
+            }
+            if (od != 0) {
+                tcg_gen_addi_i32(tmp, add, od);
+                add = tmp;
+            }
+        }
+    } else {
+        /* brief extension word format */
+        tmp = tcg_temp_new();
+        add = gen_addr_index(ext, tmp);
+        if (!IS_NULL_QREG(base)) {
+            tcg_gen_add_i32(tmp, add, base);
+            if ((int8_t)ext)
+                tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
+        } else {
+            tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
+        }
+        add = tmp;
+    }
+    return add;
+}
+
+/* Update the CPU env CC_OP state.  */
+static inline void gen_flush_cc_op(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
+}
+
+/* Evaluate all the CC flags.  */
+static inline void gen_flush_flags(DisasContext *s)
+{
+    if (s->cc_op == CC_OP_FLAGS)
+        return;
+    gen_flush_cc_op(s);
+    gen_helper_flush_flags(cpu_env, QREG_CC_OP);
+    s->cc_op = CC_OP_FLAGS;
+}
+
+static void gen_logic_cc(DisasContext *s, TCGv val)
+{
+    tcg_gen_mov_i32(QREG_CC_DEST, val);
+    s->cc_op = CC_OP_LOGIC;
+}
+
+static void gen_update_cc_add(TCGv dest, TCGv src)
+{
+    tcg_gen_mov_i32(QREG_CC_DEST, dest);
+    tcg_gen_mov_i32(QREG_CC_SRC, src);
+}
+
+static inline int opsize_bytes(int opsize)
+{
+    switch (opsize) {
+    case OS_BYTE: return 1;
+    case OS_WORD: return 2;
+    case OS_LONG: return 4;
+    case OS_SINGLE: return 4;
+    case OS_DOUBLE: return 8;
+    default:
+        qemu_assert(0, "bad operand size");
+        return 0;
+    }
+}
+
+/* Assign value to a register.  If the width is less than the register width
+   only the low part of the register is set.  */
+static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
+{
+    TCGv tmp;
+    switch (opsize) {
+    case OS_BYTE:
+        tcg_gen_andi_i32(reg, reg, 0xffffff00);
+        tmp = tcg_temp_new();
+        tcg_gen_ext8u_i32(tmp, val);
+        tcg_gen_or_i32(reg, reg, tmp);
+        break;
+    case OS_WORD:
+        tcg_gen_andi_i32(reg, reg, 0xffff0000);
+        tmp = tcg_temp_new();
+        tcg_gen_ext16u_i32(tmp, val);
+        tcg_gen_or_i32(reg, reg, tmp);
+        break;
+    case OS_LONG:
+    case OS_SINGLE:
+        tcg_gen_mov_i32(reg, val);
+        break;
+    default:
+        qemu_assert(0, "Bad operand size");
+        break;
+    }
+}
+
+/* Sign or zero extend a value.  */
+static inline TCGv gen_extend(TCGv val, int opsize, int sign)
+{
+    TCGv tmp;
+
+    switch (opsize) {
+    case OS_BYTE:
+        tmp = tcg_temp_new();
+        if (sign)
+            tcg_gen_ext8s_i32(tmp, val);
+        else
+            tcg_gen_ext8u_i32(tmp, val);
+        break;
+    case OS_WORD:
+        tmp = tcg_temp_new();
+        if (sign)
+            tcg_gen_ext16s_i32(tmp, val);
+        else
+            tcg_gen_ext16u_i32(tmp, val);
+        break;
+    case OS_LONG:
+    case OS_SINGLE:
+        tmp = val;
+        break;
+    default:
+        qemu_assert(0, "Bad operand size");
+    }
+    return tmp;
+}
+
+/* Generate code for an "effective address".  Does not adjust the base
+   register for autoincrement addressing modes.  */
+static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize)
+{
+    TCGv reg;
+    TCGv tmp;
+    uint16_t ext;
+    uint32_t offset;
+
+    switch ((insn >> 3) & 7) {
+    case 0: /* Data register direct.  */
+    case 1: /* Address register direct.  */
+        return NULL_QREG;
+    case 2: /* Indirect register */
+    case 3: /* Indirect postincrement.  */
+        return AREG(insn, 0);
+    case 4: /* Indirect predecrememnt.  */
+        reg = AREG(insn, 0);
+        tmp = tcg_temp_new();
+        tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
+        return tmp;
+    case 5: /* Indirect displacement.  */
+        reg = AREG(insn, 0);
+        tmp = tcg_temp_new();
+        ext = lduw_code(s->pc);
+        s->pc += 2;
+        tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
+        return tmp;
+    case 6: /* Indirect index + displacement.  */
+        reg = AREG(insn, 0);
+        return gen_lea_indexed(s, opsize, reg);
+    case 7: /* Other */
+        switch (insn & 7) {
+        case 0: /* Absolute short.  */
+            offset = ldsw_code(s->pc);
+            s->pc += 2;
+            return tcg_const_i32(offset);
+        case 1: /* Absolute long.  */
+            offset = read_im32(s);
+            return tcg_const_i32(offset);
+        case 2: /* pc displacement  */
+            offset = s->pc;
+            offset += ldsw_code(s->pc);
+            s->pc += 2;
+            return tcg_const_i32(offset);
+        case 3: /* pc index+displacement.  */
+            return gen_lea_indexed(s, opsize, NULL_QREG);
+        case 4: /* Immediate.  */
+        default:
+            return NULL_QREG;
+        }
+    }
+    /* Should never happen.  */
+    return NULL_QREG;
+}
+
+/* Helper function for gen_ea. Reuse the computed address between the
+   for read/write operands.  */
+static inline TCGv gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
+                              TCGv val, TCGv *addrp, ea_what what)
+{
+    TCGv tmp;
+
+    if (addrp && what == EA_STORE) {
+        tmp = *addrp;
+    } else {
+        tmp = gen_lea(s, insn, opsize);
+        if (IS_NULL_QREG(tmp))
+            return tmp;
+        if (addrp)
+            *addrp = tmp;
+    }
+    return gen_ldst(s, opsize, tmp, val, what);
+}
+
+/* Generate code to load/store a value ito/from an EA.  If VAL > 0 this is
+   a write otherwise it is a read (0 == sign extend, -1 == zero extend).
+   ADDRP is non-null for readwrite operands.  */
+static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val,
+                   TCGv *addrp, ea_what what)
+{
+    TCGv reg;
+    TCGv result;
+    uint32_t offset;
+
+    switch ((insn >> 3) & 7) {
+    case 0: /* Data register direct.  */
+        reg = DREG(insn, 0);
+        if (what == EA_STORE) {
+            gen_partset_reg(opsize, reg, val);
+            return store_dummy;
+        } else {
+            return gen_extend(reg, opsize, what == EA_LOADS);
+        }
+    case 1: /* Address register direct.  */
+        reg = AREG(insn, 0);
+        if (what == EA_STORE) {
+            tcg_gen_mov_i32(reg, val);
+            return store_dummy;
+        } else {
+            return gen_extend(reg, opsize, what == EA_LOADS);
+        }
+    case 2: /* Indirect register */
+        reg = AREG(insn, 0);
+        return gen_ldst(s, opsize, reg, val, what);
+    case 3: /* Indirect postincrement.  */
+        reg = AREG(insn, 0);
+        result = gen_ldst(s, opsize, reg, val, what);
+        /* ??? This is not exception safe.  The instruction may still
+           fault after this point.  */
+        if (what == EA_STORE || !addrp)
+            tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+        return result;
+    case 4: /* Indirect predecrememnt.  */
+        {
+            TCGv tmp;
+            if (addrp && what == EA_STORE) {
+                tmp = *addrp;
+            } else {
+                tmp = gen_lea(s, insn, opsize);
+                if (IS_NULL_QREG(tmp))
+                    return tmp;
+                if (addrp)
+                    *addrp = tmp;
+            }
+            result = gen_ldst(s, opsize, tmp, val, what);
+            /* ??? This is not exception safe.  The instruction may still
+               fault after this point.  */
+            if (what == EA_STORE || !addrp) {
+                reg = AREG(insn, 0);
+                tcg_gen_mov_i32(reg, tmp);
+            }
+        }
+        return result;
+    case 5: /* Indirect displacement.  */
+    case 6: /* Indirect index + displacement.  */
+        return gen_ea_once(s, insn, opsize, val, addrp, what);
+    case 7: /* Other */
+        switch (insn & 7) {
+        case 0: /* Absolute short.  */
+        case 1: /* Absolute long.  */
+        case 2: /* pc displacement  */
+        case 3: /* pc index+displacement.  */
+            return gen_ea_once(s, insn, opsize, val, addrp, what);
+        case 4: /* Immediate.  */
+            /* Sign extend values for consistency.  */
+            switch (opsize) {
+            case OS_BYTE:
+                if (what == EA_LOADS)
+                    offset = ldsb_code(s->pc + 1);
+                else
+                    offset = ldub_code(s->pc + 1);
+                s->pc += 2;
+                break;
+            case OS_WORD:
+                if (what == EA_LOADS)
+                    offset = ldsw_code(s->pc);
+                else
+                    offset = lduw_code(s->pc);
+                s->pc += 2;
+                break;
+            case OS_LONG:
+                offset = read_im32(s);
+                break;
+            default:
+                qemu_assert(0, "Bad immediate operand");
+            }
+            return tcg_const_i32(offset);
+        default:
+            return NULL_QREG;
+        }
+    }
+    /* Should never happen.  */
+    return NULL_QREG;
+}
+
+/* This generates a conditional branch, clobbering all temporaries.  */
+static void gen_jmpcc(DisasContext *s, int cond, int l1)
+{
+    TCGv tmp;
+
+    /* TODO: Optimize compare/branch pairs rather than always flushing
+       flag state to CC_OP_FLAGS.  */
+    gen_flush_flags(s);
+    switch (cond) {
+    case 0: /* T */
+        tcg_gen_br(l1);
+        break;
+    case 1: /* F */
+        break;
+    case 2: /* HI (!C && !Z) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 3: /* LS (C || Z) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 4: /* CC (!C) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 5: /* CS (C) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 6: /* NE (!Z) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 7: /* EQ (Z) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 8: /* VC (!V) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 9: /* VS (V) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 10: /* PL (!N) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 11: /* MI (N) */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 12: /* GE (!(N ^ V)) */
+        tmp = tcg_temp_new();
+        assert(CCF_V == (CCF_N >> 2));
+        tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2);
+        tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST);
+        tcg_gen_andi_i32(tmp, tmp, CCF_V);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 13: /* LT (N ^ V) */
+        tmp = tcg_temp_new();
+        assert(CCF_V == (CCF_N >> 2));
+        tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2);
+        tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST);
+        tcg_gen_andi_i32(tmp, tmp, CCF_V);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    case 14: /* GT (!(Z || (N ^ V))) */
+        tmp = tcg_temp_new();
+        assert(CCF_V == (CCF_N >> 2));
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N);
+        tcg_gen_shri_i32(tmp, tmp, 2);
+        tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST);
+        tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1);
+        break;
+    case 15: /* LE (Z || (N ^ V)) */
+        tmp = tcg_temp_new();
+        assert(CCF_V == (CCF_N >> 2));
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N);
+        tcg_gen_shri_i32(tmp, tmp, 2);
+        tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST);
+        tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
+        break;
+    default:
+        /* Should ever happen.  */
+        abort();
+    }
+}
+
+DISAS_INSN(scc)
+{
+    int l1;
+    int cond;
+    TCGv reg;
+
+    l1 = gen_new_label();
+    cond = (insn >> 8) & 0xf;
+    reg = DREG(insn, 0);
+    tcg_gen_andi_i32(reg, reg, 0xffffff00);
+    /* This is safe because we modify the reg directly, with no other values
+       live.  */
+    gen_jmpcc(s, cond ^ 1, l1);
+    tcg_gen_ori_i32(reg, reg, 0xff);
+    gen_set_label(l1);
+}
+
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static void gen_lookup_tb(DisasContext *s)
+{
+    gen_flush_cc_op(s);
+    tcg_gen_movi_i32(QREG_PC, s->pc);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+/* Generate a jump to an immediate address.  */
+static void gen_jmp_im(DisasContext *s, uint32_t dest)
+{
+    gen_flush_cc_op(s);
+    tcg_gen_movi_i32(QREG_PC, dest);
+    s->is_jmp = DISAS_JUMP;
+}
+
+/* Generate a jump to the address in qreg DEST.  */
+static void gen_jmp(DisasContext *s, TCGv dest)
+{
+    gen_flush_cc_op(s);
+    tcg_gen_mov_i32(QREG_PC, dest);
+    s->is_jmp = DISAS_JUMP;
+}
+
+static void gen_exception(DisasContext *s, uint32_t where, int nr)
+{
+    gen_flush_cc_op(s);
+    gen_jmp_im(s, where);
+    gen_helper_raise_exception(tcg_const_i32(nr));
+}
+
+static inline void gen_addr_fault(DisasContext *s)
+{
+    gen_exception(s, s->insn_pc, EXCP_ADDRESS);
+}
+
+#define SRC_EA(result, opsize, op_sign, addrp) do { \
+    result = gen_ea(s, insn, opsize, NULL_QREG, addrp, op_sign ? EA_LOADS : EA_LOADU); \
+    if (IS_NULL_QREG(result)) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
+#define DEST_EA(insn, opsize, val, addrp) do { \
+    TCGv ea_result = gen_ea(s, insn, opsize, val, addrp, EA_STORE); \
+    if (IS_NULL_QREG(ea_result)) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
+/* Generate a jump to an immediate address.  */
+static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if (unlikely(s->singlestep_enabled)) {
+        gen_exception(s, dest, EXCP_DEBUG);
+    } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
+               (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_i32(QREG_PC, dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        gen_jmp_im(s, dest);
+        tcg_gen_exit_tb(0);
+    }
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+DISAS_INSN(undef_mac)
+{
+    gen_exception(s, s->pc - 2, EXCP_LINEA);
+}
+
+DISAS_INSN(undef_fpu)
+{
+    gen_exception(s, s->pc - 2, EXCP_LINEF);
+}
+
+DISAS_INSN(undef)
+{
+    gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
+    cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x",
+              insn, s->pc - 2);
+}
+
+DISAS_INSN(mulw)
+{
+    TCGv reg;
+    TCGv tmp;
+    TCGv src;
+    int sign;
+
+    sign = (insn & 0x100) != 0;
+    reg = DREG(insn, 9);
+    tmp = tcg_temp_new();
+    if (sign)
+        tcg_gen_ext16s_i32(tmp, reg);
+    else
+        tcg_gen_ext16u_i32(tmp, reg);
+    SRC_EA(src, OS_WORD, sign, NULL);
+    tcg_gen_mul_i32(tmp, tmp, src);
+    tcg_gen_mov_i32(reg, tmp);
+    /* Unlike m68k, coldfire always clears the overflow bit.  */
+    gen_logic_cc(s, tmp);
+}
+
+DISAS_INSN(divw)
+{
+    TCGv reg;
+    TCGv tmp;
+    TCGv src;
+    int sign;
+
+    sign = (insn & 0x100) != 0;
+    reg = DREG(insn, 9);
+    if (sign) {
+        tcg_gen_ext16s_i32(QREG_DIV1, reg);
+    } else {
+        tcg_gen_ext16u_i32(QREG_DIV1, reg);
+    }
+    SRC_EA(src, OS_WORD, sign, NULL);
+    tcg_gen_mov_i32(QREG_DIV2, src);
+    if (sign) {
+        gen_helper_divs(cpu_env, tcg_const_i32(1));
+    } else {
+        gen_helper_divu(cpu_env, tcg_const_i32(1));
+    }
+
+    tmp = tcg_temp_new();
+    src = tcg_temp_new();
+    tcg_gen_ext16u_i32(tmp, QREG_DIV1);
+    tcg_gen_shli_i32(src, QREG_DIV2, 16);
+    tcg_gen_or_i32(reg, tmp, src);
+    s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(divl)
+{
+    TCGv num;
+    TCGv den;
+    TCGv reg;
+    uint16_t ext;
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if (ext & 0x87f8) {
+        gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+        return;
+    }
+    num = DREG(ext, 12);
+    reg = DREG(ext, 0);
+    tcg_gen_mov_i32(QREG_DIV1, num);
+    SRC_EA(den, OS_LONG, 0, NULL);
+    tcg_gen_mov_i32(QREG_DIV2, den);
+    if (ext & 0x0800) {
+        gen_helper_divs(cpu_env, tcg_const_i32(0));
+    } else {
+        gen_helper_divu(cpu_env, tcg_const_i32(0));
+    }
+    if ((ext & 7) == ((ext >> 12) & 7)) {
+        /* div */
+        tcg_gen_mov_i32 (reg, QREG_DIV1);
+    } else {
+        /* rem */
+        tcg_gen_mov_i32 (reg, QREG_DIV2);
+    }
+    s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(addsub)
+{
+    TCGv reg;
+    TCGv dest;
+    TCGv src;
+    TCGv tmp;
+    TCGv addr;
+    int add;
+
+    add = (insn & 0x4000) != 0;
+    reg = DREG(insn, 9);
+    dest = tcg_temp_new();
+    if (insn & 0x100) {
+        SRC_EA(tmp, OS_LONG, 0, &addr);
+        src = reg;
+    } else {
+        tmp = reg;
+        SRC_EA(src, OS_LONG, 0, NULL);
+    }
+    if (add) {
+        tcg_gen_add_i32(dest, tmp, src);
+        gen_helper_xflag_lt(QREG_CC_X, dest, src);
+        s->cc_op = CC_OP_ADD;
+    } else {
+        gen_helper_xflag_lt(QREG_CC_X, tmp, src);
+        tcg_gen_sub_i32(dest, tmp, src);
+        s->cc_op = CC_OP_SUB;
+    }
+    gen_update_cc_add(dest, src);
+    if (insn & 0x100) {
+        DEST_EA(insn, OS_LONG, dest, &addr);
+    } else {
+        tcg_gen_mov_i32(reg, dest);
+    }
+}
+
+
+/* Reverse the order of the bits in REG.  */
+DISAS_INSN(bitrev)
+{
+    TCGv reg;
+    reg = DREG(insn, 0);
+    gen_helper_bitrev(reg, reg);
+}
+
+DISAS_INSN(bitop_reg)
+{
+    int opsize;
+    int op;
+    TCGv src1;
+    TCGv src2;
+    TCGv tmp;
+    TCGv addr;
+    TCGv dest;
+
+    if ((insn & 0x38) != 0)
+        opsize = OS_BYTE;
+    else
+        opsize = OS_LONG;
+    op = (insn >> 6) & 3;
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
+    src2 = DREG(insn, 9);
+    dest = tcg_temp_new();
+
+    gen_flush_flags(s);
+    tmp = tcg_temp_new();
+    if (opsize == OS_BYTE)
+        tcg_gen_andi_i32(tmp, src2, 7);
+    else
+        tcg_gen_andi_i32(tmp, src2, 31);
+    src2 = tmp;
+    tmp = tcg_temp_new();
+    tcg_gen_shr_i32(tmp, src1, src2);
+    tcg_gen_andi_i32(tmp, tmp, 1);
+    tcg_gen_shli_i32(tmp, tmp, 2);
+    /* Clear CCF_Z if bit set.  */
+    tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z);
+    tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp);
+
+    tcg_gen_shl_i32(tmp, tcg_const_i32(1), src2);
+    switch (op) {
+    case 1: /* bchg */
+        tcg_gen_xor_i32(dest, src1, tmp);
+        break;
+    case 2: /* bclr */
+        tcg_gen_not_i32(tmp, tmp);
+        tcg_gen_and_i32(dest, src1, tmp);
+        break;
+    case 3: /* bset */
+        tcg_gen_or_i32(dest, src1, tmp);
+        break;
+    default: /* btst */
+        break;
+    }
+    if (op)
+        DEST_EA(insn, opsize, dest, &addr);
+}
+
+DISAS_INSN(sats)
+{
+    TCGv reg;
+    reg = DREG(insn, 0);
+    gen_flush_flags(s);
+    gen_helper_sats(reg, reg, QREG_CC_DEST);
+    gen_logic_cc(s, reg);
+}
+
+static void gen_push(DisasContext *s, TCGv val)
+{
+    TCGv tmp;
+
+    tmp = tcg_temp_new();
+    tcg_gen_subi_i32(tmp, QREG_SP, 4);
+    gen_store(s, OS_LONG, tmp, val);
+    tcg_gen_mov_i32(QREG_SP, tmp);
+}
+
+DISAS_INSN(movem)
+{
+    TCGv addr;
+    int i;
+    uint16_t mask;
+    TCGv reg;
+    TCGv tmp;
+    int is_load;
+
+    mask = lduw_code(s->pc);
+    s->pc += 2;
+    tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    addr = tcg_temp_new();
+    tcg_gen_mov_i32(addr, tmp);
+    is_load = ((insn & 0x0400) != 0);
+    for (i = 0; i < 16; i++, mask >>= 1) {
+        if (mask & 1) {
+            if (i < 8)
+                reg = DREG(i, 0);
+            else
+                reg = AREG(i, 0);
+            if (is_load) {
+                tmp = gen_load(s, OS_LONG, addr, 0);
+                tcg_gen_mov_i32(reg, tmp);
+            } else {
+                gen_store(s, OS_LONG, addr, reg);
+            }
+            if (mask != 1)
+                tcg_gen_addi_i32(addr, addr, 4);
+        }
+    }
+}
+
+DISAS_INSN(bitop_im)
+{
+    int opsize;
+    int op;
+    TCGv src1;
+    uint32_t mask;
+    int bitnum;
+    TCGv tmp;
+    TCGv addr;
+
+    if ((insn & 0x38) != 0)
+        opsize = OS_BYTE;
+    else
+        opsize = OS_LONG;
+    op = (insn >> 6) & 3;
+
+    bitnum = lduw_code(s->pc);
+    s->pc += 2;
+    if (bitnum & 0xff00) {
+        disas_undef(s, insn);
+        return;
+    }
+
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
+
+    gen_flush_flags(s);
+    if (opsize == OS_BYTE)
+        bitnum &= 7;
+    else
+        bitnum &= 31;
+    mask = 1 << bitnum;
+
+    tmp = tcg_temp_new();
+    assert (CCF_Z == (1 << 2));
+    if (bitnum > 2)
+        tcg_gen_shri_i32(tmp, src1, bitnum - 2);
+    else if (bitnum < 2)
+        tcg_gen_shli_i32(tmp, src1, 2 - bitnum);
+    else
+        tcg_gen_mov_i32(tmp, src1);
+    tcg_gen_andi_i32(tmp, tmp, CCF_Z);
+    /* Clear CCF_Z if bit set.  */
+    tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z);
+    tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp);
+    if (op) {
+        switch (op) {
+        case 1: /* bchg */
+            tcg_gen_xori_i32(tmp, src1, mask);
+            break;
+        case 2: /* bclr */
+            tcg_gen_andi_i32(tmp, src1, ~mask);
+            break;
+        case 3: /* bset */
+            tcg_gen_ori_i32(tmp, src1, mask);
+            break;
+        default: /* btst */
+            break;
+        }
+        DEST_EA(insn, opsize, tmp, &addr);
+    }
+}
+
+DISAS_INSN(arith_im)
+{
+    int op;
+    uint32_t im;
+    TCGv src1;
+    TCGv dest;
+    TCGv addr;
+
+    op = (insn >> 9) & 7;
+    SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
+    im = read_im32(s);
+    dest = tcg_temp_new();
+    switch (op) {
+    case 0: /* ori */
+        tcg_gen_ori_i32(dest, src1, im);
+        gen_logic_cc(s, dest);
+        break;
+    case 1: /* andi */
+        tcg_gen_andi_i32(dest, src1, im);
+        gen_logic_cc(s, dest);
+        break;
+    case 2: /* subi */
+        tcg_gen_mov_i32(dest, src1);
+        gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
+        tcg_gen_subi_i32(dest, dest, im);
+        gen_update_cc_add(dest, tcg_const_i32(im));
+        s->cc_op = CC_OP_SUB;
+        break;
+    case 3: /* addi */
+        tcg_gen_mov_i32(dest, src1);
+        tcg_gen_addi_i32(dest, dest, im);
+        gen_update_cc_add(dest, tcg_const_i32(im));
+        gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
+        s->cc_op = CC_OP_ADD;
+        break;
+    case 5: /* eori */
+        tcg_gen_xori_i32(dest, src1, im);
+        gen_logic_cc(s, dest);
+        break;
+    case 6: /* cmpi */
+        tcg_gen_mov_i32(dest, src1);
+        tcg_gen_subi_i32(dest, dest, im);
+        gen_update_cc_add(dest, tcg_const_i32(im));
+        s->cc_op = CC_OP_SUB;
+        break;
+    default:
+        abort();
+    }
+    if (op != 6) {
+        DEST_EA(insn, OS_LONG, dest, &addr);
+    }
+}
+
+DISAS_INSN(byterev)
+{
+    TCGv reg;
+
+    reg = DREG(insn, 0);
+    tcg_gen_bswap32_i32(reg, reg);
+}
+
+DISAS_INSN(move)
+{
+    TCGv src;
+    TCGv dest;
+    int op;
+    int opsize;
+
+    switch (insn >> 12) {
+    case 1: /* move.b */
+        opsize = OS_BYTE;
+        break;
+    case 2: /* move.l */
+        opsize = OS_LONG;
+        break;
+    case 3: /* move.w */
+        opsize = OS_WORD;
+        break;
+    default:
+        abort();
+    }
+    SRC_EA(src, opsize, 1, NULL);
+    op = (insn >> 6) & 7;
+    if (op == 1) {
+        /* movea */
+        /* The value will already have been sign extended.  */
+        dest = AREG(insn, 9);
+        tcg_gen_mov_i32(dest, src);
+    } else {
+        /* normal move */
+        uint16_t dest_ea;
+        dest_ea = ((insn >> 9) & 7) | (op << 3);
+        DEST_EA(dest_ea, opsize, src, NULL);
+        /* This will be correct because loads sign extend.  */
+        gen_logic_cc(s, src);
+    }
+}
+
+DISAS_INSN(negx)
+{
+    TCGv reg;
+
+    gen_flush_flags(s);
+    reg = DREG(insn, 0);
+    gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg);
+}
+
+DISAS_INSN(lea)
+{
+    TCGv reg;
+    TCGv tmp;
+
+    reg = AREG(insn, 9);
+    tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    tcg_gen_mov_i32(reg, tmp);
+}
+
+DISAS_INSN(clr)
+{
+    int opsize;
+
+    switch ((insn >> 6) & 3) {
+    case 0: /* clr.b */
+        opsize = OS_BYTE;
+        break;
+    case 1: /* clr.w */
+        opsize = OS_WORD;
+        break;
+    case 2: /* clr.l */
+        opsize = OS_LONG;
+        break;
+    default:
+        abort();
+    }
+    DEST_EA(insn, opsize, tcg_const_i32(0), NULL);
+    gen_logic_cc(s, tcg_const_i32(0));
+}
+
+static TCGv gen_get_ccr(DisasContext *s)
+{
+    TCGv dest;
+
+    gen_flush_flags(s);
+    dest = tcg_temp_new();
+    tcg_gen_shli_i32(dest, QREG_CC_X, 4);
+    tcg_gen_or_i32(dest, dest, QREG_CC_DEST);
+    return dest;
+}
+
+DISAS_INSN(move_from_ccr)
+{
+    TCGv reg;
+    TCGv ccr;
+
+    ccr = gen_get_ccr(s);
+    reg = DREG(insn, 0);
+    gen_partset_reg(OS_WORD, reg, ccr);
+}
+
+DISAS_INSN(neg)
+{
+    TCGv reg;
+    TCGv src1;
+
+    reg = DREG(insn, 0);
+    src1 = tcg_temp_new();
+    tcg_gen_mov_i32(src1, reg);
+    tcg_gen_neg_i32(reg, src1);
+    s->cc_op = CC_OP_SUB;
+    gen_update_cc_add(reg, src1);
+    gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1);
+    s->cc_op = CC_OP_SUB;
+}
+
+static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
+{
+    tcg_gen_movi_i32(QREG_CC_DEST, val & 0xf);
+    tcg_gen_movi_i32(QREG_CC_X, (val & 0x10) >> 4);
+    if (!ccr_only) {
+        gen_helper_set_sr(cpu_env, tcg_const_i32(val & 0xff00));
+    }
+}
+
+static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
+{
+    TCGv tmp;
+    TCGv reg;
+
+    s->cc_op = CC_OP_FLAGS;
+    if ((insn & 0x38) == 0)
+      {
+        tmp = tcg_temp_new();
+        reg = DREG(insn, 0);
+        tcg_gen_andi_i32(QREG_CC_DEST, reg, 0xf);
+        tcg_gen_shri_i32(tmp, reg, 4);
+        tcg_gen_andi_i32(QREG_CC_X, tmp, 1);
+        if (!ccr_only) {
+            gen_helper_set_sr(cpu_env, reg);
+        }
+      }
+    else if ((insn & 0x3f) == 0x3c)
+      {
+        uint16_t val;
+        val = lduw_code(s->pc);
+        s->pc += 2;
+        gen_set_sr_im(s, val, ccr_only);
+      }
+    else
+        disas_undef(s, insn);
+}
+
+DISAS_INSN(move_to_ccr)
+{
+    gen_set_sr(s, insn, 1);
+}
+
+DISAS_INSN(not)
+{
+    TCGv reg;
+
+    reg = DREG(insn, 0);
+    tcg_gen_not_i32(reg, reg);
+    gen_logic_cc(s, reg);
+}
+
+DISAS_INSN(swap)
+{
+    TCGv src1;
+    TCGv src2;
+    TCGv reg;
+
+    src1 = tcg_temp_new();
+    src2 = tcg_temp_new();
+    reg = DREG(insn, 0);
+    tcg_gen_shli_i32(src1, reg, 16);
+    tcg_gen_shri_i32(src2, reg, 16);
+    tcg_gen_or_i32(reg, src1, src2);
+    gen_logic_cc(s, reg);
+}
+
+DISAS_INSN(pea)
+{
+    TCGv tmp;
+
+    tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    gen_push(s, tmp);
+}
+
+DISAS_INSN(ext)
+{
+    int op;
+    TCGv reg;
+    TCGv tmp;
+
+    reg = DREG(insn, 0);
+    op = (insn >> 6) & 7;
+    tmp = tcg_temp_new();
+    if (op == 3)
+        tcg_gen_ext16s_i32(tmp, reg);
+    else
+        tcg_gen_ext8s_i32(tmp, reg);
+    if (op == 2)
+        gen_partset_reg(OS_WORD, reg, tmp);
+    else
+        tcg_gen_mov_i32(reg, tmp);
+    gen_logic_cc(s, tmp);
+}
+
+DISAS_INSN(tst)
+{
+    int opsize;
+    TCGv tmp;
+
+    switch ((insn >> 6) & 3) {
+    case 0: /* tst.b */
+        opsize = OS_BYTE;
+        break;
+    case 1: /* tst.w */
+        opsize = OS_WORD;
+        break;
+    case 2: /* tst.l */
+        opsize = OS_LONG;
+        break;
+    default:
+        abort();
+    }
+    SRC_EA(tmp, opsize, 1, NULL);
+    gen_logic_cc(s, tmp);
+}
+
+DISAS_INSN(pulse)
+{
+  /* Implemented as a NOP.  */
+}
+
+DISAS_INSN(illegal)
+{
+    gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
+}
+
+/* ??? This should be atomic.  */
+DISAS_INSN(tas)
+{
+    TCGv dest;
+    TCGv src1;
+    TCGv addr;
+
+    dest = tcg_temp_new();
+    SRC_EA(src1, OS_BYTE, 1, &addr);
+    gen_logic_cc(s, src1);
+    tcg_gen_ori_i32(dest, src1, 0x80);
+    DEST_EA(insn, OS_BYTE, dest, &addr);
+}
+
+DISAS_INSN(mull)
+{
+    uint16_t ext;
+    TCGv reg;
+    TCGv src1;
+    TCGv dest;
+
+    /* The upper 32 bits of the product are discarded, so
+       muls.l and mulu.l are functionally equivalent.  */
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if (ext & 0x87ff) {
+        gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+        return;
+    }
+    reg = DREG(ext, 12);
+    SRC_EA(src1, OS_LONG, 0, NULL);
+    dest = tcg_temp_new();
+    tcg_gen_mul_i32(dest, src1, reg);
+    tcg_gen_mov_i32(reg, dest);
+    /* Unlike m68k, coldfire always clears the overflow bit.  */
+    gen_logic_cc(s, dest);
+}
+
+DISAS_INSN(link)
+{
+    int16_t offset;
+    TCGv reg;
+    TCGv tmp;
+
+    offset = ldsw_code(s->pc);
+    s->pc += 2;
+    reg = AREG(insn, 0);
+    tmp = tcg_temp_new();
+    tcg_gen_subi_i32(tmp, QREG_SP, 4);
+    gen_store(s, OS_LONG, tmp, reg);
+    if ((insn & 7) != 7)
+        tcg_gen_mov_i32(reg, tmp);
+    tcg_gen_addi_i32(QREG_SP, tmp, offset);
+}
+
+DISAS_INSN(unlk)
+{
+    TCGv src;
+    TCGv reg;
+    TCGv tmp;
+
+    src = tcg_temp_new();
+    reg = AREG(insn, 0);
+    tcg_gen_mov_i32(src, reg);
+    tmp = gen_load(s, OS_LONG, src, 0);
+    tcg_gen_mov_i32(reg, tmp);
+    tcg_gen_addi_i32(QREG_SP, src, 4);
+}
+
+DISAS_INSN(nop)
+{
+}
+
+DISAS_INSN(rts)
+{
+    TCGv tmp;
+
+    tmp = gen_load(s, OS_LONG, QREG_SP, 0);
+    tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
+    gen_jmp(s, tmp);
+}
+
+DISAS_INSN(jump)
+{
+    TCGv tmp;
+
+    /* Load the target address first to ensure correct exception
+       behavior.  */
+    tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    if ((insn & 0x40) == 0) {
+        /* jsr */
+        gen_push(s, tcg_const_i32(s->pc));
+    }
+    gen_jmp(s, tmp);
+}
+
+DISAS_INSN(addsubq)
+{
+    TCGv src1;
+    TCGv src2;
+    TCGv dest;
+    int val;
+    TCGv addr;
+
+    SRC_EA(src1, OS_LONG, 0, &addr);
+    val = (insn >> 9) & 7;
+    if (val == 0)
+        val = 8;
+    dest = tcg_temp_new();
+    tcg_gen_mov_i32(dest, src1);
+    if ((insn & 0x38) == 0x08) {
+        /* Don't update condition codes if the destination is an
+           address register.  */
+        if (insn & 0x0100) {
+            tcg_gen_subi_i32(dest, dest, val);
+        } else {
+            tcg_gen_addi_i32(dest, dest, val);
+        }
+    } else {
+        src2 = tcg_const_i32(val);
+        if (insn & 0x0100) {
+            gen_helper_xflag_lt(QREG_CC_X, dest, src2);
+            tcg_gen_subi_i32(dest, dest, val);
+            s->cc_op = CC_OP_SUB;
+        } else {
+            tcg_gen_addi_i32(dest, dest, val);
+            gen_helper_xflag_lt(QREG_CC_X, dest, src2);
+            s->cc_op = CC_OP_ADD;
+        }
+        gen_update_cc_add(dest, src2);
+    }
+    DEST_EA(insn, OS_LONG, dest, &addr);
+}
+
+DISAS_INSN(tpf)
+{
+    switch (insn & 7) {
+    case 2: /* One extension word.  */
+        s->pc += 2;
+        break;
+    case 3: /* Two extension words.  */
+        s->pc += 4;
+        break;
+    case 4: /* No extension words.  */
+        break;
+    default:
+        disas_undef(s, insn);
+    }
+}
+
+DISAS_INSN(branch)
+{
+    int32_t offset;
+    uint32_t base;
+    int op;
+    int l1;
+
+    base = s->pc;
+    op = (insn >> 8) & 0xf;
+    offset = (int8_t)insn;
+    if (offset == 0) {
+        offset = ldsw_code(s->pc);
+        s->pc += 2;
+    } else if (offset == -1) {
+        offset = read_im32(s);
+    }
+    if (op == 1) {
+        /* bsr */
+        gen_push(s, tcg_const_i32(s->pc));
+    }
+    gen_flush_cc_op(s);
+    if (op > 1) {
+        /* Bcc */
+        l1 = gen_new_label();
+        gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
+        gen_jmp_tb(s, 1, base + offset);
+        gen_set_label(l1);
+        gen_jmp_tb(s, 0, s->pc);
+    } else {
+        /* Unconditional branch.  */
+        gen_jmp_tb(s, 0, base + offset);
+    }
+}
+
+DISAS_INSN(moveq)
+{
+    uint32_t val;
+
+    val = (int8_t)insn;
+    tcg_gen_movi_i32(DREG(insn, 9), val);
+    gen_logic_cc(s, tcg_const_i32(val));
+}
+
+DISAS_INSN(mvzs)
+{
+    int opsize;
+    TCGv src;
+    TCGv reg;
+
+    if (insn & 0x40)
+        opsize = OS_WORD;
+    else
+        opsize = OS_BYTE;
+    SRC_EA(src, opsize, (insn & 0x80) == 0, NULL);
+    reg = DREG(insn, 9);
+    tcg_gen_mov_i32(reg, src);
+    gen_logic_cc(s, src);
+}
+
+DISAS_INSN(or)
+{
+    TCGv reg;
+    TCGv dest;
+    TCGv src;
+    TCGv addr;
+
+    reg = DREG(insn, 9);
+    dest = tcg_temp_new();
+    if (insn & 0x100) {
+        SRC_EA(src, OS_LONG, 0, &addr);
+        tcg_gen_or_i32(dest, src, reg);
+        DEST_EA(insn, OS_LONG, dest, &addr);
+    } else {
+        SRC_EA(src, OS_LONG, 0, NULL);
+        tcg_gen_or_i32(dest, src, reg);
+        tcg_gen_mov_i32(reg, dest);
+    }
+    gen_logic_cc(s, dest);
+}
+
+DISAS_INSN(suba)
+{
+    TCGv src;
+    TCGv reg;
+
+    SRC_EA(src, OS_LONG, 0, NULL);
+    reg = AREG(insn, 9);
+    tcg_gen_sub_i32(reg, reg, src);
+}
+
+DISAS_INSN(subx)
+{
+    TCGv reg;
+    TCGv src;
+
+    gen_flush_flags(s);
+    reg = DREG(insn, 9);
+    src = DREG(insn, 0);
+    gen_helper_subx_cc(reg, cpu_env, reg, src);
+}
+
+DISAS_INSN(mov3q)
+{
+    TCGv src;
+    int val;
+
+    val = (insn >> 9) & 7;
+    if (val == 0)
+        val = -1;
+    src = tcg_const_i32(val);
+    gen_logic_cc(s, src);
+    DEST_EA(insn, OS_LONG, src, NULL);
+}
+
+DISAS_INSN(cmp)
+{
+    int op;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+    int opsize;
+
+    op = (insn >> 6) & 3;
+    switch (op) {
+    case 0: /* cmp.b */
+        opsize = OS_BYTE;
+        s->cc_op = CC_OP_CMPB;
+        break;
+    case 1: /* cmp.w */
+        opsize = OS_WORD;
+        s->cc_op = CC_OP_CMPW;
+        break;
+    case 2: /* cmp.l */
+        opsize = OS_LONG;
+        s->cc_op = CC_OP_SUB;
+        break;
+    default:
+        abort();
+    }
+    SRC_EA(src, opsize, 1, NULL);
+    reg = DREG(insn, 9);
+    dest = tcg_temp_new();
+    tcg_gen_sub_i32(dest, reg, src);
+    gen_update_cc_add(dest, src);
+}
+
+DISAS_INSN(cmpa)
+{
+    int opsize;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+
+    if (insn & 0x100) {
+        opsize = OS_LONG;
+    } else {
+        opsize = OS_WORD;
+    }
+    SRC_EA(src, opsize, 1, NULL);
+    reg = AREG(insn, 9);
+    dest = tcg_temp_new();
+    tcg_gen_sub_i32(dest, reg, src);
+    gen_update_cc_add(dest, src);
+    s->cc_op = CC_OP_SUB;
+}
+
+DISAS_INSN(eor)
+{
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+    TCGv addr;
+
+    SRC_EA(src, OS_LONG, 0, &addr);
+    reg = DREG(insn, 9);
+    dest = tcg_temp_new();
+    tcg_gen_xor_i32(dest, src, reg);
+    gen_logic_cc(s, dest);
+    DEST_EA(insn, OS_LONG, dest, &addr);
+}
+
+DISAS_INSN(and)
+{
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+    TCGv addr;
+
+    reg = DREG(insn, 9);
+    dest = tcg_temp_new();
+    if (insn & 0x100) {
+        SRC_EA(src, OS_LONG, 0, &addr);
+        tcg_gen_and_i32(dest, src, reg);
+        DEST_EA(insn, OS_LONG, dest, &addr);
+    } else {
+        SRC_EA(src, OS_LONG, 0, NULL);
+        tcg_gen_and_i32(dest, src, reg);
+        tcg_gen_mov_i32(reg, dest);
+    }
+    gen_logic_cc(s, dest);
+}
+
+DISAS_INSN(adda)
+{
+    TCGv src;
+    TCGv reg;
+
+    SRC_EA(src, OS_LONG, 0, NULL);
+    reg = AREG(insn, 9);
+    tcg_gen_add_i32(reg, reg, src);
+}
+
+DISAS_INSN(addx)
+{
+    TCGv reg;
+    TCGv src;
+
+    gen_flush_flags(s);
+    reg = DREG(insn, 9);
+    src = DREG(insn, 0);
+    gen_helper_addx_cc(reg, cpu_env, reg, src);
+    s->cc_op = CC_OP_FLAGS;
+}
+
+/* TODO: This could be implemented without helper functions.  */
+DISAS_INSN(shift_im)
+{
+    TCGv reg;
+    int tmp;
+    TCGv shift;
+
+    reg = DREG(insn, 0);
+    tmp = (insn >> 9) & 7;
+    if (tmp == 0)
+        tmp = 8;
+    shift = tcg_const_i32(tmp);
+    /* No need to flush flags becuse we know we will set C flag.  */
+    if (insn & 0x100) {
+        gen_helper_shl_cc(reg, cpu_env, reg, shift);
+    } else {
+        if (insn & 8) {
+            gen_helper_shr_cc(reg, cpu_env, reg, shift);
+        } else {
+            gen_helper_sar_cc(reg, cpu_env, reg, shift);
+        }
+    }
+    s->cc_op = CC_OP_SHIFT;
+}
+
+DISAS_INSN(shift_reg)
+{
+    TCGv reg;
+    TCGv shift;
+
+    reg = DREG(insn, 0);
+    shift = DREG(insn, 9);
+    /* Shift by zero leaves C flag unmodified.   */
+    gen_flush_flags(s);
+    if (insn & 0x100) {
+        gen_helper_shl_cc(reg, cpu_env, reg, shift);
+    } else {
+        if (insn & 8) {
+            gen_helper_shr_cc(reg, cpu_env, reg, shift);
+        } else {
+            gen_helper_sar_cc(reg, cpu_env, reg, shift);
+        }
+    }
+    s->cc_op = CC_OP_SHIFT;
+}
+
+DISAS_INSN(ff1)
+{
+    TCGv reg;
+    reg = DREG(insn, 0);
+    gen_logic_cc(s, reg);
+    gen_helper_ff1(reg, reg);
+}
+
+static TCGv gen_get_sr(DisasContext *s)
+{
+    TCGv ccr;
+    TCGv sr;
+
+    ccr = gen_get_ccr(s);
+    sr = tcg_temp_new();
+    tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
+    tcg_gen_or_i32(sr, sr, ccr);
+    return sr;
+}
+
+DISAS_INSN(strldsr)
+{
+    uint16_t ext;
+    uint32_t addr;
+
+    addr = s->pc - 2;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if (ext != 0x46FC) {
+        gen_exception(s, addr, EXCP_UNSUPPORTED);
+        return;
+    }
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if (IS_USER(s) || (ext & SR_S) == 0) {
+        gen_exception(s, addr, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_push(s, gen_get_sr(s));
+    gen_set_sr_im(s, ext, 0);
+}
+
+DISAS_INSN(move_from_sr)
+{
+    TCGv reg;
+    TCGv sr;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    sr = gen_get_sr(s);
+    reg = DREG(insn, 0);
+    gen_partset_reg(OS_WORD, reg, sr);
+}
+
+DISAS_INSN(move_to_sr)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_set_sr(s, insn, 0);
+    gen_lookup_tb(s);
+}
+
+DISAS_INSN(move_from_usp)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement USP.  */
+    gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
+}
+
+DISAS_INSN(move_to_usp)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement USP.  */
+    gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
+}
+
+DISAS_INSN(halt)
+{
+    gen_exception(s, s->pc, EXCP_HALT_INSN);
+}
+
+DISAS_INSN(stop)
+{
+    uint16_t ext;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    gen_set_sr_im(s, ext, 0);
+    tcg_gen_movi_i32(QREG_HALTED, 1);
+    gen_exception(s, s->pc, EXCP_HLT);
+}
+
+DISAS_INSN(rte)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_exception(s, s->pc - 2, EXCP_RTE);
+}
+
+DISAS_INSN(movec)
+{
+    uint16_t ext;
+    TCGv reg;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    if (ext & 0x8000) {
+        reg = AREG(ext, 12);
+    } else {
+        reg = DREG(ext, 12);
+    }
+    gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg);
+    gen_lookup_tb(s);
+}
+
+DISAS_INSN(intouch)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* ICache fetch.  Implement as no-op.  */
+}
+
+DISAS_INSN(cpushl)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* Cache push/invalidate.  Implement as no-op.  */
+}
+
+DISAS_INSN(wddata)
+{
+    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+}
+
+DISAS_INSN(wdebug)
+{
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement wdebug.  */
+    qemu_assert(0, "WDEBUG not implemented");
+}
+
+DISAS_INSN(trap)
+{
+    gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
+}
+
+/* ??? FP exceptions are not implemented.  Most exceptions are deferred until
+   immediately before the next FP instruction is executed.  */
+DISAS_INSN(fpu)
+{
+    uint16_t ext;
+    int32_t offset;
+    int opmode;
+    TCGv_i64 src;
+    TCGv_i64 dest;
+    TCGv_i64 res;
+    TCGv tmp32;
+    int round;
+    int set_dest;
+    int opsize;
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    opmode = ext & 0x7f;
+    switch ((ext >> 13) & 7) {
+    case 0: case 2:
+        break;
+    case 1:
+        goto undef;
+    case 3: /* fmove out */
+        src = FREG(ext, 7);
+        tmp32 = tcg_temp_new_i32();
+        /* fmove */
+        /* ??? TODO: Proper behavior on overflow.  */
+        switch ((ext >> 10) & 7) {
+        case 0:
+            opsize = OS_LONG;
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
+            break;
+        case 1:
+            opsize = OS_SINGLE;
+            gen_helper_f64_to_f32(tmp32, cpu_env, src);
+            break;
+        case 4:
+            opsize = OS_WORD;
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
+            break;
+        case 5: /* OS_DOUBLE */
+            tcg_gen_mov_i32(tmp32, AREG(insn, 0));
+            switch ((insn >> 3) & 7) {
+            case 2:
+            case 3:
+                break;
+            case 4:
+                tcg_gen_addi_i32(tmp32, tmp32, -8);
+                break;
+            case 5:
+                offset = ldsw_code(s->pc);
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            default:
+                goto undef;
+            }
+            gen_store64(s, tmp32, src);
+            switch ((insn >> 3) & 7) {
+            case 3:
+                tcg_gen_addi_i32(tmp32, tmp32, 8);
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            case 4:
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            }
+            tcg_temp_free_i32(tmp32);
+            return;
+        case 6:
+            opsize = OS_BYTE;
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
+            break;
+        default:
+            goto undef;
+        }
+        DEST_EA(insn, opsize, tmp32, NULL);
+        tcg_temp_free_i32(tmp32);
+        return;
+    case 4: /* fmove to control register.  */
+        switch ((ext >> 10) & 7) {
+        case 4: /* FPCR */
+            /* Not implemented.  Ignore writes.  */
+            break;
+        case 1: /* FPIAR */
+        case 2: /* FPSR */
+        default:
+            cpu_abort(NULL, "Unimplemented: fmove to control %d",
+                      (ext >> 10) & 7);
+        }
+        break;
+    case 5: /* fmove from control register.  */
+        switch ((ext >> 10) & 7) {
+        case 4: /* FPCR */
+            /* Not implemented.  Always return zero.  */
+            tmp32 = tcg_const_i32(0);
+            break;
+        case 1: /* FPIAR */
+        case 2: /* FPSR */
+        default:
+            cpu_abort(NULL, "Unimplemented: fmove from control %d",
+                      (ext >> 10) & 7);
+            goto undef;
+        }
+        DEST_EA(insn, OS_LONG, tmp32, NULL);
+        break;
+    case 6: /* fmovem */
+    case 7:
+        {
+            TCGv addr;
+            uint16_t mask;
+            int i;
+            if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
+                goto undef;
+            tmp32 = gen_lea(s, insn, OS_LONG);
+            if (IS_NULL_QREG(tmp32)) {
+                gen_addr_fault(s);
+                return;
+            }
+            addr = tcg_temp_new_i32();
+            tcg_gen_mov_i32(addr, tmp32);
+            mask = 0x80;
+            for (i = 0; i < 8; i++) {
+                if (ext & mask) {
+                    s->is_mem = 1;
+                    dest = FREG(i, 0);
+                    if (ext & (1 << 13)) {
+                        /* store */
+                        tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
+                    } else {
+                        /* load */
+                        tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
+                    }
+                    if (ext & (mask - 1))
+                        tcg_gen_addi_i32(addr, addr, 8);
+                }
+                mask >>= 1;
+            }
+            tcg_temp_free_i32(addr);
+        }
+        return;
+    }
+    if (ext & (1 << 14)) {
+        /* Source effective address.  */
+        switch ((ext >> 10) & 7) {
+        case 0: opsize = OS_LONG; break;
+        case 1: opsize = OS_SINGLE; break;
+        case 4: opsize = OS_WORD; break;
+        case 5: opsize = OS_DOUBLE; break;
+        case 6: opsize = OS_BYTE; break;
+        default:
+            goto undef;
+        }
+        if (opsize == OS_DOUBLE) {
+            tmp32 = tcg_temp_new_i32();
+            tcg_gen_mov_i32(tmp32, AREG(insn, 0));
+            switch ((insn >> 3) & 7) {
+            case 2:
+            case 3:
+                break;
+            case 4:
+                tcg_gen_addi_i32(tmp32, tmp32, -8);
+                break;
+            case 5:
+                offset = ldsw_code(s->pc);
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            case 7:
+                offset = ldsw_code(s->pc);
+                offset += s->pc - 2;
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            default:
+                goto undef;
+            }
+            src = gen_load64(s, tmp32);
+            switch ((insn >> 3) & 7) {
+            case 3:
+                tcg_gen_addi_i32(tmp32, tmp32, 8);
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            case 4:
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            }
+            tcg_temp_free_i32(tmp32);
+        } else {
+            SRC_EA(tmp32, opsize, 1, NULL);
+            src = tcg_temp_new_i64();
+            switch (opsize) {
+            case OS_LONG:
+            case OS_WORD:
+            case OS_BYTE:
+                gen_helper_i32_to_f64(src, cpu_env, tmp32);
+                break;
+            case OS_SINGLE:
+                gen_helper_f32_to_f64(src, cpu_env, tmp32);
+                break;
+            }
+        }
+    } else {
+        /* Source register.  */
+        src = FREG(ext, 10);
+    }
+    dest = FREG(ext, 7);
+    res = tcg_temp_new_i64();
+    if (opmode != 0x3a)
+        tcg_gen_mov_f64(res, dest);
+    round = 1;
+    set_dest = 1;
+    switch (opmode) {
+    case 0: case 0x40: case 0x44: /* fmove */
+        tcg_gen_mov_f64(res, src);
+        break;
+    case 1: /* fint */
+        gen_helper_iround_f64(res, cpu_env, src);
+        round = 0;
+        break;
+    case 3: /* fintrz */
+        gen_helper_itrunc_f64(res, cpu_env, src);
+        round = 0;
+        break;
+    case 4: case 0x41: case 0x45: /* fsqrt */
+        gen_helper_sqrt_f64(res, cpu_env, src);
+        break;
+    case 0x18: case 0x58: case 0x5c: /* fabs */
+        gen_helper_abs_f64(res, src);
+        break;
+    case 0x1a: case 0x5a: case 0x5e: /* fneg */
+        gen_helper_chs_f64(res, src);
+        break;
+    case 0x20: case 0x60: case 0x64: /* fdiv */
+        gen_helper_div_f64(res, cpu_env, res, src);
+        break;
+    case 0x22: case 0x62: case 0x66: /* fadd */
+        gen_helper_add_f64(res, cpu_env, res, src);
+        break;
+    case 0x23: case 0x63: case 0x67: /* fmul */
+        gen_helper_mul_f64(res, cpu_env, res, src);
+        break;
+    case 0x28: case 0x68: case 0x6c: /* fsub */
+        gen_helper_sub_f64(res, cpu_env, res, src);
+        break;
+    case 0x38: /* fcmp */
+        gen_helper_sub_cmp_f64(res, cpu_env, res, src);
+        set_dest = 0;
+        round = 0;
+        break;
+    case 0x3a: /* ftst */
+        tcg_gen_mov_f64(res, src);
+        set_dest = 0;
+        round = 0;
+        break;
+    default:
+        goto undef;
+    }
+    if (ext & (1 << 14)) {
+        tcg_temp_free_i64(src);
+    }
+    if (round) {
+        if (opmode & 0x40) {
+            if ((opmode & 0x4) != 0)
+                round = 0;
+        } else if ((s->fpcr & M68K_FPCR_PREC) == 0) {
+            round = 0;
+        }
+    }
+    if (round) {
+        TCGv tmp = tcg_temp_new_i32();
+        gen_helper_f64_to_f32(tmp, cpu_env, res);
+        gen_helper_f32_to_f64(res, cpu_env, tmp);
+        tcg_temp_free_i32(tmp);
+    }
+    tcg_gen_mov_f64(QREG_FP_RESULT, res);
+    if (set_dest) {
+        tcg_gen_mov_f64(dest, res);
+    }
+    tcg_temp_free_i64(res);
+    return;
+undef:
+    /* FIXME: Is this right for offset addressing modes?  */
+    s->pc -= 2;
+    disas_undef_fpu(s, insn);
+}
+
+DISAS_INSN(fbcc)
+{
+    uint32_t offset;
+    uint32_t addr;
+    TCGv flag;
+    int l1;
+
+    addr = s->pc;
+    offset = ldsw_code(s->pc);
+    s->pc += 2;
+    if (insn & (1 << 6)) {
+        offset = (offset << 16) | lduw_code(s->pc);
+        s->pc += 2;
+    }
+
+    l1 = gen_new_label();
+    /* TODO: Raise BSUN exception.  */
+    flag = tcg_temp_new();
+    gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT);
+    /* Jump to l1 if condition is true.  */
+    switch (insn & 0xf) {
+    case 0: /* f */
+        break;
+    case 1: /* eq (=0) */
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
+        break;
+    case 2: /* ogt (=1) */
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(1), l1);
+        break;
+    case 3: /* oge (=0 or =1) */
+        tcg_gen_brcond_i32(TCG_COND_LEU, flag, tcg_const_i32(1), l1);
+        break;
+    case 4: /* olt (=-1) */
+        tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(0), l1);
+        break;
+    case 5: /* ole (=-1 or =0) */
+        tcg_gen_brcond_i32(TCG_COND_LE, flag, tcg_const_i32(0), l1);
+        break;
+    case 6: /* ogl (=-1 or =1) */
+        tcg_gen_andi_i32(flag, flag, 1);
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
+        break;
+    case 7: /* or (=2) */
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
+        break;
+    case 8: /* un (<2) */
+        tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1);
+        break;
+    case 9: /* ueq (=0 or =2) */
+        tcg_gen_andi_i32(flag, flag, 1);
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
+        break;
+    case 10: /* ugt (>0) */
+        tcg_gen_brcond_i32(TCG_COND_GT, flag, tcg_const_i32(0), l1);
+        break;
+    case 11: /* uge (>=0) */
+        tcg_gen_brcond_i32(TCG_COND_GE, flag, tcg_const_i32(0), l1);
+        break;
+    case 12: /* ult (=-1 or =2) */
+        tcg_gen_brcond_i32(TCG_COND_GEU, flag, tcg_const_i32(2), l1);
+        break;
+    case 13: /* ule (!=1) */
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(1), l1);
+        break;
+    case 14: /* ne (!=0) */
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
+        break;
+    case 15: /* t */
+        tcg_gen_br(l1);
+        break;
+    }
+    gen_jmp_tb(s, 0, s->pc);
+    gen_set_label(l1);
+    gen_jmp_tb(s, 1, addr + offset);
+}
+
+DISAS_INSN(frestore)
+{
+    /* TODO: Implement frestore.  */
+    qemu_assert(0, "FRESTORE not implemented");
+}
+
+DISAS_INSN(fsave)
+{
+    /* TODO: Implement fsave.  */
+    qemu_assert(0, "FSAVE not implemented");
+}
+
+static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
+{
+    TCGv tmp = tcg_temp_new();
+    if (s->env->macsr & MACSR_FI) {
+        if (upper)
+            tcg_gen_andi_i32(tmp, val, 0xffff0000);
+        else
+            tcg_gen_shli_i32(tmp, val, 16);
+    } else if (s->env->macsr & MACSR_SU) {
+        if (upper)
+            tcg_gen_sari_i32(tmp, val, 16);
+        else
+            tcg_gen_ext16s_i32(tmp, val);
+    } else {
+        if (upper)
+            tcg_gen_shri_i32(tmp, val, 16);
+        else
+            tcg_gen_ext16u_i32(tmp, val);
+    }
+    return tmp;
+}
+
+static void gen_mac_clear_flags(void)
+{
+    tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
+                     ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
+}
+
+DISAS_INSN(mac)
+{
+    TCGv rx;
+    TCGv ry;
+    uint16_t ext;
+    int acc;
+    TCGv tmp;
+    TCGv addr;
+    TCGv loadval;
+    int dual;
+    TCGv saved_flags;
+
+    if (!s->done_mac) {
+        s->mactmp = tcg_temp_new_i64();
+        s->done_mac = 1;
+    }
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
+    dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
+    if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
+        disas_undef(s, insn);
+        return;
+    }
+    if (insn & 0x30) {
+        /* MAC with load.  */
+        tmp = gen_lea(s, insn, OS_LONG);
+        addr = tcg_temp_new();
+        tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
+        /* Load the value now to ensure correct exception behavior.
+           Perform writeback after reading the MAC inputs.  */
+        loadval = gen_load(s, OS_LONG, addr, 0);
+
+        acc ^= 1;
+        rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
+        ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
+    } else {
+        loadval = addr = NULL_QREG;
+        rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    }
+
+    gen_mac_clear_flags();
+#if 0
+    l1 = -1;
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
+        /* Skip the multiply if we know we will ignore it.  */
+        l1 = gen_new_label();
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+#endif
+
+    if ((ext & 0x0800) == 0) {
+        /* Word.  */
+        rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
+        ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
+    }
+    if (s->env->macsr & MACSR_FI) {
+        gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
+    } else {
+        if (s->env->macsr & MACSR_SU)
+            gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
+        else
+            gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
+        switch ((ext >> 9) & 3) {
+        case 1:
+            tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
+            break;
+        case 3:
+            tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
+            break;
+        }
+    }
+
+    if (dual) {
+        /* Save the overflow flag from the multiply.  */
+        saved_flags = tcg_temp_new();
+        tcg_gen_mov_i32(saved_flags, QREG_MACSR);
+    } else {
+        saved_flags = NULL_QREG;
+    }
+
+#if 0
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
+        /* Skip the accumulate if the value is already saturated.  */
+        l1 = gen_new_label();
+        tmp = tcg_temp_new();
+        gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+#endif
+
+    if (insn & 0x100)
+        tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
+    else
+        tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
+
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
+    else if (s->env->macsr & MACSR_SU)
+        gen_helper_macsats(cpu_env, tcg_const_i32(acc));
+    else
+        gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
+
+#if 0
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if (l1 != -1)
+        gen_set_label(l1);
+#endif
+
+    if (dual) {
+        /* Dual accumulate variant.  */
+        acc = (ext >> 2) & 3;
+        /* Restore the overflow flag from the multiplier.  */
+        tcg_gen_mov_i32(QREG_MACSR, saved_flags);
+#if 0
+        /* Disabled because conditional branches clobber temporary vars.  */
+        if ((s->env->macsr & MACSR_OMC) != 0) {
+            /* Skip the accumulate if the value is already saturated.  */
+            l1 = gen_new_label();
+            tmp = tcg_temp_new();
+            gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
+            gen_op_jmp_nz32(tmp, l1);
+        }
+#endif
+        if (ext & 2)
+            tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
+        else
+            tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
+        if (s->env->macsr & MACSR_FI)
+            gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
+        else if (s->env->macsr & MACSR_SU)
+            gen_helper_macsats(cpu_env, tcg_const_i32(acc));
+        else
+            gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
+#if 0
+        /* Disabled because conditional branches clobber temporary vars.  */
+        if (l1 != -1)
+            gen_set_label(l1);
+#endif
+    }
+    gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
+
+    if (insn & 0x30) {
+        TCGv rw;
+        rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        tcg_gen_mov_i32(rw, loadval);
+        /* FIXME: Should address writeback happen with the masked or
+           unmasked value?  */
+        switch ((insn >> 3) & 7) {
+        case 3: /* Post-increment.  */
+            tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
+            break;
+        case 4: /* Pre-decrement.  */
+            tcg_gen_mov_i32(AREG(insn, 0), addr);
+        }
+    }
+}
+
+DISAS_INSN(from_mac)
+{
+    TCGv rx;
+    TCGv_i64 acc;
+    int accnum;
+
+    rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    accnum = (insn >> 9) & 3;
+    acc = MACREG(accnum);
+    if (s->env->macsr & MACSR_FI) {
+        gen_helper_get_macf(rx, cpu_env, acc);
+    } else if ((s->env->macsr & MACSR_OMC) == 0) {
+        tcg_gen_trunc_i64_i32(rx, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_helper_get_macs(rx, acc);
+    } else {
+        gen_helper_get_macu(rx, acc);
+    }
+    if (insn & 0x40) {
+        tcg_gen_movi_i64(acc, 0);
+        tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
+    }
+}
+
+DISAS_INSN(move_mac)
+{
+    /* FIXME: This can be done without a helper.  */
+    int src;
+    TCGv dest;
+    src = insn & 3;
+    dest = tcg_const_i32((insn >> 9) & 3);
+    gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
+    gen_mac_clear_flags();
+    gen_helper_mac_set_flags(cpu_env, dest);
+}
+
+DISAS_INSN(from_macsr)
+{
+    TCGv reg;
+
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    tcg_gen_mov_i32(reg, QREG_MACSR);
+}
+
+DISAS_INSN(from_mask)
+{
+    TCGv reg;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    tcg_gen_mov_i32(reg, QREG_MAC_MASK);
+}
+
+DISAS_INSN(from_mext)
+{
+    TCGv reg;
+    TCGv acc;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_get_mac_extf(reg, cpu_env, acc);
+    else
+        gen_helper_get_mac_exti(reg, cpu_env, acc);
+}
+
+DISAS_INSN(macsr_to_ccr)
+{
+    tcg_gen_movi_i32(QREG_CC_X, 0);
+    tcg_gen_andi_i32(QREG_CC_DEST, QREG_MACSR, 0xf);
+    s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(to_mac)
+{
+    TCGv_i64 acc;
+    TCGv val;
+    int accnum;
+    accnum = (insn >> 9) & 3;
+    acc = MACREG(accnum);
+    SRC_EA(val, OS_LONG, 0, NULL);
+    if (s->env->macsr & MACSR_FI) {
+        tcg_gen_ext_i32_i64(acc, val);
+        tcg_gen_shli_i64(acc, acc, 8);
+    } else if (s->env->macsr & MACSR_SU) {
+        tcg_gen_ext_i32_i64(acc, val);
+    } else {
+        tcg_gen_extu_i32_i64(acc, val);
+    }
+    tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
+    gen_mac_clear_flags();
+    gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
+}
+
+DISAS_INSN(to_macsr)
+{
+    TCGv val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_helper_set_macsr(cpu_env, val);
+    gen_lookup_tb(s);
+}
+
+DISAS_INSN(to_mask)
+{
+    TCGv val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
+}
+
+DISAS_INSN(to_mext)
+{
+    TCGv val;
+    TCGv acc;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_set_mac_extf(cpu_env, val, acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_helper_set_mac_exts(cpu_env, val, acc);
+    else
+        gen_helper_set_mac_extu(cpu_env, val, acc);
+}
+
+static disas_proc opcode_table[65536];
+
+static void
+register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
+{
+  int i;
+  int from;
+  int to;
+
+  /* Sanity check.  All set bits must be included in the mask.  */
+  if (opcode & ~mask) {
+      fprintf(stderr,
+              "qemu internal error: bogus opcode definition %04x/%04x\n",
+              opcode, mask);
+      abort();
+  }
+  /* This could probably be cleverer.  For now just optimize the case where
+     the top bits are known.  */
+  /* Find the first zero bit in the mask.  */
+  i = 0x8000;
+  while ((i & mask) != 0)
+      i >>= 1;
+  /* Iterate over all combinations of this and lower bits.  */
+  if (i == 0)
+      i = 1;
+  else
+      i <<= 1;
+  from = opcode & ~(i - 1);
+  to = from + i;
+  for (i = from; i < to; i++) {
+      if ((i & mask) == opcode)
+          opcode_table[i] = proc;
+  }
+}
+
+/* Register m68k opcode handlers.  Order is important.
+   Later insn override earlier ones.  */
+void register_m68k_insns (CPUM68KState *env)
+{
+#define INSN(name, opcode, mask, feature) do { \
+    if (m68k_feature(env, M68K_FEATURE_##feature)) \
+        register_opcode(disas_##name, 0x##opcode, 0x##mask); \
+    } while(0)
+    INSN(undef,     0000, 0000, CF_ISA_A);
+    INSN(arith_im,  0080, fff8, CF_ISA_A);
+    INSN(bitrev,    00c0, fff8, CF_ISA_APLUSC);
+    INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
+    INSN(arith_im,  0280, fff8, CF_ISA_A);
+    INSN(byterev,   02c0, fff8, CF_ISA_APLUSC);
+    INSN(arith_im,  0480, fff8, CF_ISA_A);
+    INSN(ff1,       04c0, fff8, CF_ISA_APLUSC);
+    INSN(arith_im,  0680, fff8, CF_ISA_A);
+    INSN(bitop_im,  0800, ffc0, CF_ISA_A);
+    INSN(bitop_im,  0840, ffc0, CF_ISA_A);
+    INSN(bitop_im,  0880, ffc0, CF_ISA_A);
+    INSN(bitop_im,  08c0, ffc0, CF_ISA_A);
+    INSN(arith_im,  0a80, fff8, CF_ISA_A);
+    INSN(arith_im,  0c00, ff38, CF_ISA_A);
+    INSN(move,      1000, f000, CF_ISA_A);
+    INSN(move,      2000, f000, CF_ISA_A);
+    INSN(move,      3000, f000, CF_ISA_A);
+    INSN(strldsr,   40e7, ffff, CF_ISA_APLUSC);
+    INSN(negx,      4080, fff8, CF_ISA_A);
+    INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
+    INSN(lea,       41c0, f1c0, CF_ISA_A);
+    INSN(clr,       4200, ff00, CF_ISA_A);
+    INSN(undef,     42c0, ffc0, CF_ISA_A);
+    INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
+    INSN(neg,       4480, fff8, CF_ISA_A);
+    INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
+    INSN(not,       4680, fff8, CF_ISA_A);
+    INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
+    INSN(pea,       4840, ffc0, CF_ISA_A);
+    INSN(swap,      4840, fff8, CF_ISA_A);
+    INSN(movem,     48c0, fbc0, CF_ISA_A);
+    INSN(ext,       4880, fff8, CF_ISA_A);
+    INSN(ext,       48c0, fff8, CF_ISA_A);
+    INSN(ext,       49c0, fff8, CF_ISA_A);
+    INSN(tst,       4a00, ff00, CF_ISA_A);
+    INSN(tas,       4ac0, ffc0, CF_ISA_B);
+    INSN(halt,      4ac8, ffff, CF_ISA_A);
+    INSN(pulse,     4acc, ffff, CF_ISA_A);
+    INSN(illegal,   4afc, ffff, CF_ISA_A);
+    INSN(mull,      4c00, ffc0, CF_ISA_A);
+    INSN(divl,      4c40, ffc0, CF_ISA_A);
+    INSN(sats,      4c80, fff8, CF_ISA_B);
+    INSN(trap,      4e40, fff0, CF_ISA_A);
+    INSN(link,      4e50, fff8, CF_ISA_A);
+    INSN(unlk,      4e58, fff8, CF_ISA_A);
+    INSN(move_to_usp, 4e60, fff8, USP);
+    INSN(move_from_usp, 4e68, fff8, USP);
+    INSN(nop,       4e71, ffff, CF_ISA_A);
+    INSN(stop,      4e72, ffff, CF_ISA_A);
+    INSN(rte,       4e73, ffff, CF_ISA_A);
+    INSN(rts,       4e75, ffff, CF_ISA_A);
+    INSN(movec,     4e7b, ffff, CF_ISA_A);
+    INSN(jump,      4e80, ffc0, CF_ISA_A);
+    INSN(jump,      4ec0, ffc0, CF_ISA_A);
+    INSN(addsubq,   5180, f1c0, CF_ISA_A);
+    INSN(scc,       50c0, f0f8, CF_ISA_A);
+    INSN(addsubq,   5080, f1c0, CF_ISA_A);
+    INSN(tpf,       51f8, fff8, CF_ISA_A);
+
+    /* Branch instructions.  */
+    INSN(branch,    6000, f000, CF_ISA_A);
+    /* Disable long branch instructions, then add back the ones we want.  */
+    INSN(undef,     60ff, f0ff, CF_ISA_A); /* All long branches.  */
+    INSN(branch,    60ff, f0ff, CF_ISA_B);
+    INSN(undef,     60ff, ffff, CF_ISA_B); /* bra.l */
+    INSN(branch,    60ff, ffff, BRAL);
+
+    INSN(moveq,     7000, f100, CF_ISA_A);
+    INSN(mvzs,      7100, f100, CF_ISA_B);
+    INSN(or,        8000, f000, CF_ISA_A);
+    INSN(divw,      80c0, f0c0, CF_ISA_A);
+    INSN(addsub,    9000, f000, CF_ISA_A);
+    INSN(subx,      9180, f1f8, CF_ISA_A);
+    INSN(suba,      91c0, f1c0, CF_ISA_A);
+
+    INSN(undef_mac, a000, f000, CF_ISA_A);
+    INSN(mac,       a000, f100, CF_EMAC);
+    INSN(from_mac,  a180, f9b0, CF_EMAC);
+    INSN(move_mac,  a110, f9fc, CF_EMAC);
+    INSN(from_macsr,a980, f9f0, CF_EMAC);
+    INSN(from_mask, ad80, fff0, CF_EMAC);
+    INSN(from_mext, ab80, fbf0, CF_EMAC);
+    INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
+    INSN(to_mac,    a100, f9c0, CF_EMAC);
+    INSN(to_macsr,  a900, ffc0, CF_EMAC);
+    INSN(to_mext,   ab00, fbc0, CF_EMAC);
+    INSN(to_mask,   ad00, ffc0, CF_EMAC);
+
+    INSN(mov3q,     a140, f1c0, CF_ISA_B);
+    INSN(cmp,       b000, f1c0, CF_ISA_B); /* cmp.b */
+    INSN(cmp,       b040, f1c0, CF_ISA_B); /* cmp.w */
+    INSN(cmpa,      b0c0, f1c0, CF_ISA_B); /* cmpa.w */
+    INSN(cmp,       b080, f1c0, CF_ISA_A);
+    INSN(cmpa,      b1c0, f1c0, CF_ISA_A);
+    INSN(eor,       b180, f1c0, CF_ISA_A);
+    INSN(and,       c000, f000, CF_ISA_A);
+    INSN(mulw,      c0c0, f0c0, CF_ISA_A);
+    INSN(addsub,    d000, f000, CF_ISA_A);
+    INSN(addx,      d180, f1f8, CF_ISA_A);
+    INSN(adda,      d1c0, f1c0, CF_ISA_A);
+    INSN(shift_im,  e080, f0f0, CF_ISA_A);
+    INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
+    INSN(undef_fpu, f000, f000, CF_ISA_A);
+    INSN(fpu,       f200, ffc0, CF_FPU);
+    INSN(fbcc,      f280, ffc0, CF_FPU);
+    INSN(frestore,  f340, ffc0, CF_FPU);
+    INSN(fsave,     f340, ffc0, CF_FPU);
+    INSN(intouch,   f340, ffc0, CF_ISA_A);
+    INSN(cpushl,    f428, ff38, CF_ISA_A);
+    INSN(wddata,    fb00, ff00, CF_ISA_A);
+    INSN(wdebug,    fbc0, ffc0, CF_ISA_A);
+#undef INSN
+}
+
+/* ??? Some of this implementation is not exception safe.  We should always
+   write back the result to memory before setting the condition codes.  */
+static void disas_m68k_insn(CPUState * env, DisasContext *s)
+{
+    uint16_t insn;
+
+    insn = lduw_code(s->pc);
+    s->pc += 2;
+
+    opcode_table[insn](s, insn);
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+static inline void
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+                               int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int j, lj;
+    target_ulong pc_start;
+    int pc_offset;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    pc_start = tb->pc;
+
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->env = env;
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    dc->cc_op = CC_OP_DYNAMIC;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->fpcr = env->fpcr;
+    dc->user = (env->sr & SR_S) == 0;
+    dc->is_mem = 0;
+    dc->done_mac = 0;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+    do {
+        pc_offset = dc->pc - pc_start;
+        gen_throws_exception = NULL;
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
+                    gen_exception(dc, dc->pc, EXCP_DEBUG);
+                    dc->is_jmp = DISAS_JUMP;
+                    break;
+                }
+            }
+            if (dc->is_jmp)
+                break;
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+        dc->insn_pc = dc->pc;
+	disas_m68k_insn(env, dc);
+        num_insns++;
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+             !env->singlestep_enabled &&
+             !singlestep &&
+             (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
+             num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (unlikely(env->singlestep_enabled)) {
+        /* Make sure the pc is updated, and raise a debug exception.  */
+        if (!dc->is_jmp) {
+            gen_flush_cc_op(dc);
+            tcg_gen_movi_i32(QREG_PC, dc->pc);
+        }
+        gen_helper_raise_exception(tcg_const_i32(EXCP_DEBUG));
+    } else {
+        switch(dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_flush_cc_op(dc);
+            gen_jmp_tb(dc, 0, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+        case DISAS_UPDATE:
+            gen_flush_cc_op(dc);
+            /* indicate that the hash table must be used to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        }
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\n");
+    }
+#endif
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+    //optimize_flags();
+    //expand_target_qops();
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i;
+    uint16_t sr;
+    CPU_DoubleU u;
+    for (i = 0; i < 8; i++)
+      {
+        u.d = env->fregs[i];
+        cpu_fprintf (f, "D%d = %08x   A%d = %08x   F%d = %08x%08x (%12g)\n",
+                     i, env->dregs[i], i, env->aregs[i],
+                     i, u.l.upper, u.l.lower, *(double *)&u.d);
+      }
+    cpu_fprintf (f, "PC = %08x   ", env->pc);
+    sr = env->sr;
+    cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-',
+                 (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
+                 (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
+    cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/target-microblaze/cpu.h b/qemu-0.15.x/target-microblaze/cpu.h
new file mode 100644
index 0000000..76f4fc4
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/cpu.h
@@ -0,0 +1,366 @@
+/*
+ *  MicroBlaze virtual CPU header
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_MICROBLAZE_H
+#define CPU_MICROBLAZE_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPUMBState
+
+#include "cpu-defs.h"
+#include "softfloat.h"
+struct CPUMBState;
+#if !defined(CONFIG_USER_ONLY)
+#include "mmu.h"
+#endif
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_MICROBLAZE
+
+#define EXCP_NMI        1
+#define EXCP_MMU        2
+#define EXCP_IRQ        3
+#define EXCP_BREAK      4
+#define EXCP_HW_BREAK   5
+#define EXCP_HW_EXCP    6
+
+/* MicroBlaze-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
+
+/* Register aliases. R0 - R15 */
+#define R_SP     1
+#define SR_PC    0
+#define SR_MSR   1
+#define SR_EAR   3
+#define SR_ESR   5
+#define SR_FSR   7
+#define SR_BTR   0xb
+#define SR_EDR   0xd
+
+/* MSR flags.  */
+#define MSR_BE  (1<<0) /* 0x001 */
+#define MSR_IE  (1<<1) /* 0x002 */
+#define MSR_C   (1<<2) /* 0x004 */
+#define MSR_BIP (1<<3) /* 0x008 */
+#define MSR_FSL (1<<4) /* 0x010 */
+#define MSR_ICE (1<<5) /* 0x020 */
+#define MSR_DZ  (1<<6) /* 0x040 */
+#define MSR_DCE (1<<7) /* 0x080 */
+#define MSR_EE  (1<<8) /* 0x100 */
+#define MSR_EIP (1<<9) /* 0x200 */
+#define MSR_CC  (1<<31)
+
+/* Machine State Register (MSR) Fields */
+#define MSR_UM (1<<11) /* User Mode */
+#define MSR_UMS        (1<<12) /* User Mode Save */
+#define MSR_VM (1<<13) /* Virtual Mode */
+#define MSR_VMS        (1<<14) /* Virtual Mode Save */
+
+#define MSR_KERNEL      MSR_EE|MSR_VM
+//#define MSR_USER     MSR_KERNEL|MSR_UM|MSR_IE
+#define MSR_KERNEL_VMS  MSR_EE|MSR_VMS
+//#define MSR_USER_VMS MSR_KERNEL_VMS|MSR_UMS|MSR_IE
+
+/* Exception State Register (ESR) Fields */
+#define          ESR_DIZ       (1<<11) /* Zone Protection */
+#define          ESR_S         (1<<10) /* Store instruction */
+
+#define          ESR_ESS_FSL_OFFSET     5
+
+#define          ESR_EC_FSL             0
+#define          ESR_EC_UNALIGNED_DATA  1
+#define          ESR_EC_ILLEGAL_OP      2
+#define          ESR_EC_INSN_BUS        3
+#define          ESR_EC_DATA_BUS        4
+#define          ESR_EC_DIVZERO         5
+#define          ESR_EC_FPU             6
+#define          ESR_EC_PRIVINSN        7
+#define          ESR_EC_DATA_STORAGE    8
+#define          ESR_EC_INSN_STORAGE    9
+#define          ESR_EC_DATA_TLB        10
+#define          ESR_EC_INSN_TLB        11
+#define          ESR_EC_MASK            31
+
+/* Floating Point Status Register (FSR) Bits */
+#define FSR_IO          (1<<4) /* Invalid operation */
+#define FSR_DZ          (1<<3) /* Divide-by-zero */
+#define FSR_OF          (1<<2) /* Overflow */
+#define FSR_UF          (1<<1) /* Underflow */
+#define FSR_DO          (1<<0) /* Denormalized operand error */
+
+/* Version reg.  */
+/* Basic PVR mask */
+#define PVR0_PVR_FULL_MASK              0x80000000
+#define PVR0_USE_BARREL_MASK            0x40000000
+#define PVR0_USE_DIV_MASK               0x20000000
+#define PVR0_USE_HW_MUL_MASK            0x10000000
+#define PVR0_USE_FPU_MASK               0x08000000
+#define PVR0_USE_EXC_MASK               0x04000000
+#define PVR0_USE_ICACHE_MASK            0x02000000
+#define PVR0_USE_DCACHE_MASK            0x01000000
+#define PVR0_USE_MMU                    0x00800000      /* new */
+#define PVR0_USE_BTC			0x00400000
+#define PVR0_ENDI			0x00200000
+#define PVR0_FAULT			0x00100000
+#define PVR0_VERSION_MASK               0x0000FF00
+#define PVR0_USER1_MASK                 0x000000FF
+
+/* User 2 PVR mask */
+#define PVR1_USER2_MASK                 0xFFFFFFFF
+
+/* Configuration PVR masks */
+#define PVR2_D_OPB_MASK                 0x80000000
+#define PVR2_D_LMB_MASK                 0x40000000
+#define PVR2_I_OPB_MASK                 0x20000000
+#define PVR2_I_LMB_MASK                 0x10000000
+#define PVR2_INTERRUPT_IS_EDGE_MASK     0x08000000
+#define PVR2_EDGE_IS_POSITIVE_MASK      0x04000000
+#define PVR2_D_PLB_MASK                 0x02000000      /* new */
+#define PVR2_I_PLB_MASK                 0x01000000      /* new */
+#define PVR2_INTERCONNECT               0x00800000      /* new */
+#define PVR2_USE_EXTEND_FSL             0x00080000      /* new */
+#define PVR2_USE_FSL_EXC                0x00040000      /* new */
+#define PVR2_USE_MSR_INSTR              0x00020000
+#define PVR2_USE_PCMP_INSTR             0x00010000
+#define PVR2_AREA_OPTIMISED             0x00008000
+#define PVR2_USE_BARREL_MASK            0x00004000
+#define PVR2_USE_DIV_MASK               0x00002000
+#define PVR2_USE_HW_MUL_MASK            0x00001000
+#define PVR2_USE_FPU_MASK               0x00000800
+#define PVR2_USE_MUL64_MASK             0x00000400
+#define PVR2_USE_FPU2_MASK              0x00000200      /* new */
+#define PVR2_USE_IPLBEXC                0x00000100
+#define PVR2_USE_DPLBEXC                0x00000080
+#define PVR2_OPCODE_0x0_ILL_MASK        0x00000040
+#define PVR2_UNALIGNED_EXC_MASK         0x00000020
+#define PVR2_ILL_OPCODE_EXC_MASK        0x00000010
+#define PVR2_IOPB_BUS_EXC_MASK          0x00000008
+#define PVR2_DOPB_BUS_EXC_MASK          0x00000004
+#define PVR2_DIV_ZERO_EXC_MASK          0x00000002
+#define PVR2_FPU_EXC_MASK               0x00000001
+
+/* Debug and exception PVR masks */
+#define PVR3_DEBUG_ENABLED_MASK         0x80000000
+#define PVR3_NUMBER_OF_PC_BRK_MASK      0x1E000000
+#define PVR3_NUMBER_OF_RD_ADDR_BRK_MASK 0x00380000
+#define PVR3_NUMBER_OF_WR_ADDR_BRK_MASK 0x0000E000
+#define PVR3_FSL_LINKS_MASK             0x00000380
+
+/* ICache config PVR masks */
+#define PVR4_USE_ICACHE_MASK            0x80000000
+#define PVR4_ICACHE_ADDR_TAG_BITS_MASK  0x7C000000
+#define PVR4_ICACHE_USE_FSL_MASK        0x02000000
+#define PVR4_ICACHE_ALLOW_WR_MASK       0x01000000
+#define PVR4_ICACHE_LINE_LEN_MASK       0x00E00000
+#define PVR4_ICACHE_BYTE_SIZE_MASK      0x001F0000
+
+/* DCache config PVR masks */
+#define PVR5_USE_DCACHE_MASK            0x80000000
+#define PVR5_DCACHE_ADDR_TAG_BITS_MASK  0x7C000000
+#define PVR5_DCACHE_USE_FSL_MASK        0x02000000
+#define PVR5_DCACHE_ALLOW_WR_MASK       0x01000000
+#define PVR5_DCACHE_LINE_LEN_MASK       0x00E00000
+#define PVR5_DCACHE_BYTE_SIZE_MASK      0x001F0000
+#define PVR5_DCACHE_WRITEBACK_MASK      0x00004000
+
+/* ICache base address PVR mask */
+#define PVR6_ICACHE_BASEADDR_MASK       0xFFFFFFFF
+
+/* ICache high address PVR mask */
+#define PVR7_ICACHE_HIGHADDR_MASK       0xFFFFFFFF
+
+/* DCache base address PVR mask */
+#define PVR8_DCACHE_BASEADDR_MASK       0xFFFFFFFF
+
+/* DCache high address PVR mask */
+#define PVR9_DCACHE_HIGHADDR_MASK       0xFFFFFFFF
+
+/* Target family PVR mask */
+#define PVR10_TARGET_FAMILY_MASK        0xFF000000
+
+/* MMU descrtiption */
+#define PVR11_USE_MMU                   0xC0000000
+#define PVR11_MMU_ITLB_SIZE             0x38000000
+#define PVR11_MMU_DTLB_SIZE             0x07000000
+#define PVR11_MMU_TLB_ACCESS            0x00C00000
+#define PVR11_MMU_ZONES                 0x003E0000
+/* MSR Reset value PVR mask */
+#define PVR11_MSR_RESET_VALUE_MASK      0x000007FF
+
+
+
+/* CPU flags.  */
+
+/* Condition codes.  */
+#define CC_GE  5
+#define CC_GT  4
+#define CC_LE  3
+#define CC_LT  2
+#define CC_NE  1
+#define CC_EQ  0
+
+#define NB_MMU_MODES    3
+
+#define STREAM_EXCEPTION (1 << 0)
+#define STREAM_ATOMIC    (1 << 1)
+#define STREAM_TEST      (1 << 2)
+#define STREAM_CONTROL   (1 << 3)
+#define STREAM_NONBLOCK  (1 << 4)
+
+typedef struct CPUMBState {
+    uint32_t debug;
+    uint32_t btaken;
+    uint32_t btarget;
+    uint32_t bimm;
+
+    uint32_t imm;
+    uint32_t regs[33];
+    uint32_t sregs[24];
+    float_status fp_status;
+
+    /* Internal flags.  */
+#define IMM_FLAG	4
+#define MSR_EE_FLAG     (1 << 8)
+#define DRTI_FLAG	(1 << 16)
+#define DRTE_FLAG	(1 << 17)
+#define DRTB_FLAG	(1 << 18)
+#define D_FLAG		(1 << 19)  /* Bit in ESR.  */
+/* TB dependant CPUState.  */
+#define IFLAGS_TB_MASK  (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
+    uint32_t iflags;
+
+    struct {
+        uint32_t regs[16];
+    } pvr;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* Unified MMU.  */
+    struct microblaze_mmu mmu;
+#endif
+
+    CPU_COMMON
+} CPUMBState;
+
+CPUState *cpu_mb_init(const char *cpu_model);
+int cpu_mb_exec(CPUState *s);
+void cpu_mb_close(CPUState *s);
+void do_interrupt(CPUState *env);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_mb_signal_handler(int host_signum, void *pinfo,
+                          void *puc);
+
+enum {
+    CC_OP_DYNAMIC, /* Use env->cc_op  */
+    CC_OP_FLAGS,
+    CC_OP_CMP,
+};
+
+/* FIXME: MB uses variable pages down to 1K but linux only uses 4k.  */
+#define TARGET_PAGE_BITS 12
+#define MMAP_SHIFT TARGET_PAGE_BITS
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define cpu_init cpu_mb_init
+#define cpu_exec cpu_mb_exec
+#define cpu_gen_code cpu_mb_gen_code
+#define cpu_signal_handler cpu_mb_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _nommu
+#define MMU_MODE1_SUFFIX _kernel
+#define MMU_MODE2_SUFFIX _user
+#define MMU_NOMMU_IDX   0
+#define MMU_KERNEL_IDX  1
+#define MMU_USER_IDX    2
+/* See NB_MMU_MODES further up the file.  */
+
+static inline int cpu_mmu_index (CPUState *env)
+{
+        /* Are we in nommu mode?.  */
+        if (!(env->sregs[SR_MSR] & MSR_VM))
+            return MMU_NOMMU_IDX;
+
+	if (env->sregs[SR_MSR] & MSR_UM)
+            return MMU_USER_IDX;
+        return MMU_KERNEL_IDX;
+}
+
+int cpu_mb_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                            int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_mb_handle_mmu_fault
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regs[R_SP] = newsp;
+    env->regs[3] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env)
+{
+    return env->sregs[SR_MSR] & MSR_IE;
+}
+
+#include "cpu-all.h"
+
+static inline target_ulong cpu_get_pc(CPUState *env)
+{
+    return env->sregs[SR_PC];
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->sregs[SR_PC];
+    *cs_base = 0;
+    *flags = (env->iflags & IFLAGS_TB_MASK) |
+                 (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size);
+#endif
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->sregs[SR_PC] = tb->pc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-microblaze/exec.h b/qemu-0.15.x/target-microblaze/exec.h
new file mode 100644
index 0000000..71b4d39
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/exec.h
@@ -0,0 +1,27 @@
+/*
+ *  Microblaze execution defines
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dyngen-exec.h"
+
+register struct CPUMBState *env asm(AREG0);
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
diff --git a/qemu-0.15.x/target-microblaze/helper.c b/qemu-0.15.x/target-microblaze/helper.c
new file mode 100644
index 0000000..299259c
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/helper.c
@@ -0,0 +1,281 @@
+/*
+ *  MicroBlaze helper routines.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "host-utils.h"
+
+#define D(x)
+#define DMMU(x)
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+    env->regs[14] = env->sregs[SR_PC];
+}
+
+int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
+                             int mmu_idx, int is_softmmu)
+{
+    env->exception_index = 0xaa;
+    cpu_dump_state(env, stderr, fprintf, 0);
+    return 1;
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    unsigned int hit;
+    unsigned int mmu_available;
+    int r = 1;
+    int prot;
+
+    mmu_available = 0;
+    if (env->pvr.regs[0] & PVR0_USE_MMU) {
+        mmu_available = 1;
+        if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK)
+            && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
+            mmu_available = 0;
+        }
+    }
+
+    /* Translate if the MMU is available and enabled.  */
+    if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
+        target_ulong vaddr, paddr;
+        struct microblaze_mmu_lookup lu;
+
+        hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
+        if (hit) {
+            vaddr = address & TARGET_PAGE_MASK;
+            paddr = lu.paddr + vaddr - lu.vaddr;
+
+            DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n",
+                     mmu_idx, vaddr, paddr, lu.prot));
+            tlb_set_page(env, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE);
+            r = 0;
+        } else {
+            env->sregs[SR_EAR] = address;
+            DMMU(qemu_log("mmu=%d miss v=%x\n", mmu_idx, address));
+
+            switch (lu.err) {
+                case ERR_PROT:
+                    env->sregs[SR_ESR] = rw == 2 ? 17 : 16;
+                    env->sregs[SR_ESR] |= (rw == 1) << 10;
+                    break;
+                case ERR_MISS:
+                    env->sregs[SR_ESR] = rw == 2 ? 19 : 18;
+                    env->sregs[SR_ESR] |= (rw == 1) << 10;
+                    break;
+                default:
+                    abort();
+                    break;
+            }
+
+            if (env->exception_index == EXCP_MMU) {
+                cpu_abort(env, "recursive faults\n");
+            }
+
+            /* TLB miss.  */
+            env->exception_index = EXCP_MMU;
+        }
+    } else {
+        /* MMU disabled or not available.  */
+        address &= TARGET_PAGE_MASK;
+        prot = PAGE_BITS;
+        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+        r = 0;
+    }
+    return r;
+}
+
+void do_interrupt(CPUState *env)
+{
+    uint32_t t;
+
+    /* IMM flag cannot propagate across a branch and into the dslot.  */
+    assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
+    assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
+/*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
+    switch (env->exception_index) {
+        case EXCP_HW_EXCP:
+            if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
+                qemu_log("Exception raised on system without exceptions!\n");
+                return;
+            }
+
+            env->regs[17] = env->sregs[SR_PC] + 4;
+            env->sregs[SR_ESR] &= ~(1 << 12);
+
+            /* Exception breaks branch + dslot sequence?  */
+            if (env->iflags & D_FLAG) {
+                env->sregs[SR_ESR] |= 1 << 12 ;
+                env->sregs[SR_BTR] = env->btarget;
+            }
+
+            /* Disable the MMU.  */
+            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
+            env->sregs[SR_MSR] |= t;
+            /* Exception in progress.  */
+            env->sregs[SR_MSR] |= MSR_EIP;
+
+            qemu_log_mask(CPU_LOG_INT,
+                          "hw exception at pc=%x ear=%x esr=%x iflags=%x\n",
+                          env->sregs[SR_PC], env->sregs[SR_EAR],
+                          env->sregs[SR_ESR], env->iflags);
+            log_cpu_state_mask(CPU_LOG_INT, env, 0);
+            env->iflags &= ~(IMM_FLAG | D_FLAG);
+            env->sregs[SR_PC] = 0x20;
+            break;
+
+        case EXCP_MMU:
+            env->regs[17] = env->sregs[SR_PC];
+
+            env->sregs[SR_ESR] &= ~(1 << 12);
+            /* Exception breaks branch + dslot sequence?  */
+            if (env->iflags & D_FLAG) {
+                D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm));
+                env->sregs[SR_ESR] |= 1 << 12 ;
+                env->sregs[SR_BTR] = env->btarget;
+
+                /* Reexecute the branch.  */
+                env->regs[17] -= 4;
+                /* was the branch immprefixed?.  */
+                if (env->bimm) {
+                    qemu_log_mask(CPU_LOG_INT,
+                                  "bimm exception at pc=%x iflags=%x\n",
+                                  env->sregs[SR_PC], env->iflags);
+                    env->regs[17] -= 4;
+                    log_cpu_state_mask(CPU_LOG_INT, env, 0);
+                }
+            } else if (env->iflags & IMM_FLAG) {
+                D(qemu_log("IMM_FLAG set at exception\n"));
+                env->regs[17] -= 4;
+            }
+
+            /* Disable the MMU.  */
+            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
+            env->sregs[SR_MSR] |= t;
+            /* Exception in progress.  */
+            env->sregs[SR_MSR] |= MSR_EIP;
+
+            qemu_log_mask(CPU_LOG_INT,
+                          "exception at pc=%x ear=%x iflags=%x\n",
+                          env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
+            log_cpu_state_mask(CPU_LOG_INT, env, 0);
+            env->iflags &= ~(IMM_FLAG | D_FLAG);
+            env->sregs[SR_PC] = 0x20;
+            break;
+
+        case EXCP_IRQ:
+            assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)));
+            assert(env->sregs[SR_MSR] & MSR_IE);
+            assert(!(env->iflags & D_FLAG));
+
+            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+
+#if 0
+#include "disas.h"
+
+/* Useful instrumentation when debugging interrupt issues in either
+   the models or in sw.  */
+            {
+                const char *sym;
+
+                sym = lookup_symbol(env->sregs[SR_PC]);
+                if (sym
+                    && (!strcmp("netif_rx", sym)
+                        || !strcmp("process_backlog", sym))) {
+
+                    qemu_log(
+                         "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
+                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
+                         sym);
+
+                    log_cpu_state(env, 0);
+                }
+            }
+#endif
+            qemu_log_mask(CPU_LOG_INT,
+                         "interrupt at pc=%x msr=%x %x iflags=%x\n",
+                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
+
+            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
+                                    | MSR_UM | MSR_IE);
+            env->sregs[SR_MSR] |= t;
+
+            env->regs[14] = env->sregs[SR_PC];
+            env->sregs[SR_PC] = 0x10;
+            //log_cpu_state_mask(CPU_LOG_INT, env, 0);
+            break;
+
+        case EXCP_BREAK:
+        case EXCP_HW_BREAK:
+            assert(!(env->iflags & IMM_FLAG));
+            assert(!(env->iflags & D_FLAG));
+            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
+            qemu_log_mask(CPU_LOG_INT,
+                        "break at pc=%x msr=%x %x iflags=%x\n",
+                        env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
+            log_cpu_state_mask(CPU_LOG_INT, env, 0);
+            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
+            env->sregs[SR_MSR] |= t;
+            env->sregs[SR_MSR] |= MSR_BIP;
+            if (env->exception_index == EXCP_HW_BREAK) {
+                env->regs[16] = env->sregs[SR_PC];
+                env->sregs[SR_MSR] |= MSR_BIP;
+                env->sregs[SR_PC] = 0x18;
+            } else
+                env->sregs[SR_PC] = env->btarget;
+            break;
+        default:
+            cpu_abort(env, "unhandled exception type=%d\n",
+                      env->exception_index);
+            break;
+    }
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+{
+    target_ulong vaddr, paddr = 0;
+    struct microblaze_mmu_lookup lu;
+    unsigned int hit;
+
+    if (env->sregs[SR_MSR] & MSR_VM) {
+        hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
+        if (hit) {
+            vaddr = addr & TARGET_PAGE_MASK;
+            paddr = lu.paddr + vaddr - lu.vaddr;
+        } else
+            paddr = 0; /* ???.  */
+    } else
+        paddr = addr & TARGET_PAGE_MASK;
+
+    return paddr;
+}
+#endif
diff --git a/qemu-0.15.x/target-microblaze/helper.h b/qemu-0.15.x/target-microblaze/helper.h
new file mode 100644
index 0000000..b92aa34
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/helper.h
@@ -0,0 +1,39 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(debug, void)
+DEF_HELPER_FLAGS_3(carry, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_2(cmp, i32, i32, i32)
+DEF_HELPER_2(cmpu, i32, i32, i32)
+
+DEF_HELPER_2(divs, i32, i32, i32)
+DEF_HELPER_2(divu, i32, i32, i32)
+
+DEF_HELPER_2(fadd, i32, i32, i32)
+DEF_HELPER_2(frsub, i32, i32, i32)
+DEF_HELPER_2(fmul, i32, i32, i32)
+DEF_HELPER_2(fdiv, i32, i32, i32)
+DEF_HELPER_1(flt, i32, i32)
+DEF_HELPER_1(fint, i32, i32)
+DEF_HELPER_1(fsqrt, i32, i32)
+
+DEF_HELPER_2(fcmp_un, i32, i32, i32)
+DEF_HELPER_2(fcmp_lt, i32, i32, i32)
+DEF_HELPER_2(fcmp_eq, i32, i32, i32)
+DEF_HELPER_2(fcmp_le, i32, i32, i32)
+DEF_HELPER_2(fcmp_gt, i32, i32, i32)
+DEF_HELPER_2(fcmp_ne, i32, i32, i32)
+DEF_HELPER_2(fcmp_ge, i32, i32, i32)
+
+DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32)
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_1(mmu_read, i32, i32)
+DEF_HELPER_2(mmu_write, void, i32, i32)
+#endif
+
+DEF_HELPER_4(memalign, void, i32, i32, i32, i32)
+
+DEF_HELPER_2(get, i32, i32, i32)
+DEF_HELPER_3(put, void, i32, i32, i32)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-microblaze/machine.c b/qemu-0.15.x/target-microblaze/machine.c
new file mode 100644
index 0000000..1be1c35
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/machine.c
@@ -0,0 +1,11 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
diff --git a/qemu-0.15.x/target-microblaze/microblaze-decode.h b/qemu-0.15.x/target-microblaze/microblaze-decode.h
new file mode 100644
index 0000000..401319e
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/microblaze-decode.h
@@ -0,0 +1,55 @@
+/*
+ *  MicroBlaze insn decoding macros.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Convenient binary macros.  */
+#define HEX__(n) 0x##n##LU
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
+                 + ((x&0x000000F0LU)?2:0) \
+                 + ((x&0x00000F00LU)?4:0) \
+                 + ((x&0x0000F000LU)?8:0) \
+                 + ((x&0x000F0000LU)?16:0) \
+                 + ((x&0x00F00000LU)?32:0) \
+                 + ((x&0x0F000000LU)?64:0) \
+                 + ((x&0xF0000000LU)?128:0)
+#define B8(d) ((unsigned char)B8__(HEX__(d)))
+
+/* Decode logic, value and mask.  */
+#define DEC_ADD     {B8(00000000), B8(00110001)}
+#define DEC_SUB     {B8(00000001), B8(00110001)}
+#define DEC_AND     {B8(00100001), B8(00110101)}
+#define DEC_XOR     {B8(00100010), B8(00110111)}
+#define DEC_OR      {B8(00100000), B8(00110111)}
+#define DEC_BIT     {B8(00100100), B8(00111111)}
+#define DEC_MSR     {B8(00100101), B8(00111111)}
+
+#define DEC_BARREL  {B8(00010001), B8(00110111)}
+#define DEC_MUL     {B8(00010000), B8(00110111)}
+#define DEC_DIV     {B8(00010010), B8(00110111)}
+#define DEC_FPU     {B8(00010110), B8(00111111)}
+
+#define DEC_LD      {B8(00110000), B8(00110100)}
+#define DEC_ST      {B8(00110100), B8(00110100)}
+#define DEC_IMM     {B8(00101100), B8(00111111)}
+
+#define DEC_BR      {B8(00100110), B8(00110111)}
+#define DEC_BCC     {B8(00100111), B8(00110111)}
+#define DEC_RTS     {B8(00101101), B8(00111111)}
+
+#define DEC_STREAM  {B8(00010011), B8(00110111)}
+
diff --git a/qemu-0.15.x/target-microblaze/mmu.c b/qemu-0.15.x/target-microblaze/mmu.c
new file mode 100644
index 0000000..281fc8d
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/mmu.c
@@ -0,0 +1,302 @@
+/*
+ *  Microblaze MMU emulation for qemu.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+
+#define D(x)
+
+static unsigned int tlb_decode_size(unsigned int f)
+{
+    static const unsigned int sizes[] = {
+        1 * 1024, 4 * 1024, 16 * 1024, 64 * 1024, 256 * 1024,
+        1 * 1024 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024
+    };
+    assert(f < ARRAY_SIZE(sizes));
+    return sizes[f];
+}
+
+static void mmu_flush_idx(CPUState *env, unsigned int idx)
+{
+    struct microblaze_mmu *mmu = &env->mmu;
+    unsigned int tlb_size;
+    uint32_t tlb_tag, end, t;
+
+    t = mmu->rams[RAM_TAG][idx];
+    if (!(t & TLB_VALID))
+        return;
+
+    tlb_tag = t & TLB_EPN_MASK;
+    tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
+    end = tlb_tag + tlb_size;
+
+    while (tlb_tag < end) {
+        tlb_flush_page(env, tlb_tag);
+        tlb_tag += TARGET_PAGE_SIZE;
+    }
+}
+
+static void mmu_change_pid(CPUState *env, unsigned int newpid) 
+{
+    struct microblaze_mmu *mmu = &env->mmu;
+    unsigned int i;
+    uint32_t t;
+
+    if (newpid & ~0xff)
+        qemu_log("Illegal rpid=%x\n", newpid);
+
+    for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
+        /* Lookup and decode.  */
+        t = mmu->rams[RAM_TAG][i];
+        if (t & TLB_VALID) {
+            if (mmu->tids[i] && ((mmu->regs[MMU_R_PID] & 0xff) == mmu->tids[i]))
+                mmu_flush_idx(env, i);
+        }
+    }
+}
+
+/* rw - 0 = read, 1 = write, 2 = fetch.  */
+unsigned int mmu_translate(struct microblaze_mmu *mmu,
+                           struct microblaze_mmu_lookup *lu,
+                           target_ulong vaddr, int rw, int mmu_idx)
+{
+    unsigned int i, hit = 0;
+    unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel;
+    unsigned int tlb_size;
+    uint32_t tlb_tag, tlb_rpn, mask, t0;
+
+    lu->err = ERR_MISS;
+    for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
+        uint32_t t, d;
+
+        /* Lookup and decode.  */
+        t = mmu->rams[RAM_TAG][i];
+        D(qemu_log("TLB %d valid=%d\n", i, t & TLB_VALID));
+        if (t & TLB_VALID) {
+            tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
+            if (tlb_size < TARGET_PAGE_SIZE) {
+                qemu_log("%d pages not supported\n", tlb_size);
+                abort();
+            }
+
+            mask = ~(tlb_size - 1);
+            tlb_tag = t & TLB_EPN_MASK;
+            if ((vaddr & mask) != (tlb_tag & mask)) {
+                D(qemu_log("TLB %d vaddr=%x != tag=%x\n",
+                           i, vaddr & mask, tlb_tag & mask));
+                continue;
+            }
+            if (mmu->tids[i]
+                && ((mmu->regs[MMU_R_PID] & 0xff) != mmu->tids[i])) {
+                D(qemu_log("TLB %d pid=%x != tid=%x\n",
+                           i, mmu->regs[MMU_R_PID], mmu->tids[i]));
+                continue;
+            }
+
+            /* Bring in the data part.  */
+            d = mmu->rams[RAM_DATA][i];
+            tlb_ex = d & TLB_EX;
+            tlb_wr = d & TLB_WR;
+
+            /* Now lets see if there is a zone that overrides the protbits.  */
+            tlb_zsel = (d >> 4) & 0xf;
+            t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2));
+            t0 &= 0x3;
+
+            if (tlb_zsel > mmu->c_mmu_zones) {
+                qemu_log("tlb zone select out of range! %d\n", tlb_zsel);
+                t0 = 1; /* Ignore.  */
+            }
+
+            if (mmu->c_mmu == 1) {
+                t0 = 1; /* Zones are disabled.  */
+            }
+
+            switch (t0) {
+                case 0:
+                    if (mmu_idx == MMU_USER_IDX)
+                        continue;
+                    break;
+                case 2:
+                    if (mmu_idx != MMU_USER_IDX) {
+                        tlb_ex = 1;
+                        tlb_wr = 1;
+                    }
+                    break;
+                case 3:
+                    tlb_ex = 1;
+                    tlb_wr = 1;
+                    break;
+                default: break;
+            }
+
+            lu->err = ERR_PROT;
+            lu->prot = PAGE_READ;
+            if (tlb_wr)
+                lu->prot |= PAGE_WRITE;
+            else if (rw == 1)
+                goto done;
+            if (tlb_ex)
+                lu->prot |=PAGE_EXEC;
+            else if (rw == 2) {
+                goto done;
+            }
+
+            tlb_rpn = d & TLB_RPN_MASK;
+
+            lu->vaddr = tlb_tag;
+            lu->paddr = tlb_rpn;
+            lu->size = tlb_size;
+            lu->err = ERR_HIT;
+            lu->idx = i;
+            hit = 1;
+            goto done;
+        }
+    }
+done:
+    D(qemu_log("MMU vaddr=%x rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
+              vaddr, rw, tlb_wr, tlb_ex, hit));
+    return hit;
+}
+
+/* Writes/reads to the MMU's special regs end up here.  */
+uint32_t mmu_read(CPUState *env, uint32_t rn)
+{
+    unsigned int i;
+    uint32_t r;
+
+    if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
+        qemu_log("MMU access on MMU-less system\n");
+        return 0;
+    }
+
+    switch (rn) {
+        /* Reads to HI/LO trig reads from the mmu rams.  */
+        case MMU_R_TLBLO:
+        case MMU_R_TLBHI:
+            if (!(env->mmu.c_mmu_tlb_access & 1)) {
+                qemu_log("Invalid access to MMU reg %d\n", rn);
+                return 0;
+            }
+
+            i = env->mmu.regs[MMU_R_TLBX] & 0xff;
+            r = env->mmu.rams[rn & 1][i];
+            if (rn == MMU_R_TLBHI)
+                env->mmu.regs[MMU_R_PID] = env->mmu.tids[i];
+            break;
+        case MMU_R_PID:
+        case MMU_R_ZPR:
+            if (!(env->mmu.c_mmu_tlb_access & 1)) {
+                qemu_log("Invalid access to MMU reg %d\n", rn);
+                return 0;
+            }
+            r = env->mmu.regs[rn];
+            break;
+        default:
+            r = env->mmu.regs[rn];
+            break;
+    }
+    D(qemu_log("%s rn=%d=%x\n", __func__, rn, r));
+    return r;
+}
+
+void mmu_write(CPUState *env, uint32_t rn, uint32_t v)
+{
+    unsigned int i;
+    D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]));
+
+    if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
+        qemu_log("MMU access on MMU-less system\n");
+        return;
+    }
+
+    switch (rn) {
+        /* Writes to HI/LO trig writes to the mmu rams.  */
+        case MMU_R_TLBLO:
+        case MMU_R_TLBHI:
+            i = env->mmu.regs[MMU_R_TLBX] & 0xff;
+            if (rn == MMU_R_TLBHI) {
+                if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
+                    qemu_log("invalidating index %x at pc=%x\n",
+                             i, env->sregs[SR_PC]);
+                env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
+                mmu_flush_idx(env, i);
+            }
+            env->mmu.rams[rn & 1][i] = v;
+
+            D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v));
+            break;
+        case MMU_R_ZPR:
+            if (env->mmu.c_mmu_tlb_access <= 1) {
+                qemu_log("Invalid access to MMU reg %d\n", rn);
+                return;
+            }
+
+            /* Changes to the zone protection reg flush the QEMU TLB.
+               Fortunately, these are very uncommon.  */
+            if (v != env->mmu.regs[rn]) {
+                tlb_flush(env, 1);
+            }
+            env->mmu.regs[rn] = v;
+            break;
+        case MMU_R_PID:
+            if (env->mmu.c_mmu_tlb_access <= 1) {
+                qemu_log("Invalid access to MMU reg %d\n", rn);
+                return;
+            }
+
+            if (v != env->mmu.regs[rn]) {
+                mmu_change_pid(env, v);
+                env->mmu.regs[rn] = v;
+            }
+            break;
+        case MMU_R_TLBSX:
+        {
+            struct microblaze_mmu_lookup lu;
+            int hit;
+
+            if (env->mmu.c_mmu_tlb_access <= 1) {
+                qemu_log("Invalid access to MMU reg %d\n", rn);
+                return;
+            }
+
+            hit = mmu_translate(&env->mmu, &lu,
+                                v & TLB_EPN_MASK, 0, cpu_mmu_index(env));
+            if (hit) {
+                env->mmu.regs[MMU_R_TLBX] = lu.idx;
+            } else
+                env->mmu.regs[MMU_R_TLBX] |= 0x80000000;
+            break;
+        }
+        default:
+            env->mmu.regs[rn] = v;
+            break;
+   }
+}
+
+void mmu_init(struct microblaze_mmu *mmu)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(mmu->regs); i++) {
+        mmu->regs[i] = 0;
+    }
+}
diff --git a/qemu-0.15.x/target-microblaze/mmu.h b/qemu-0.15.x/target-microblaze/mmu.h
new file mode 100644
index 0000000..56149a5
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/mmu.h
@@ -0,0 +1,91 @@
+/*
+ *  Microblaze MMU emulation for qemu.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define MMU_R_PID    0
+#define MMU_R_ZPR    1
+#define MMU_R_TLBX   2
+#define MMU_R_TLBLO  3
+#define MMU_R_TLBHI  4
+#define MMU_R_TLBSX  5
+
+#define RAM_DATA     1
+#define RAM_TAG      0
+
+/* Tag portion */
+#define TLB_EPN_MASK          0xFFFFFC00 /* Effective Page Number */
+#define TLB_PAGESZ_MASK       0x00000380
+#define TLB_PAGESZ(x)         (((x) & 0x7) << 7)
+#define PAGESZ_1K             0
+#define PAGESZ_4K             1
+#define PAGESZ_16K            2
+#define PAGESZ_64K            3
+#define PAGESZ_256K           4
+#define PAGESZ_1M             5
+#define PAGESZ_4M             6
+#define PAGESZ_16M            7
+#define TLB_VALID             0x00000040 /* Entry is valid */
+
+/* Data portion */
+#define TLB_RPN_MASK          0xFFFFFC00 /* Real Page Number */
+#define TLB_PERM_MASK         0x00000300
+#define TLB_EX                0x00000200 /* Instruction execution allowed */
+#define TLB_WR                0x00000100 /* Writes permitted */
+#define TLB_ZSEL_MASK         0x000000F0
+#define TLB_ZSEL(x)           (((x) & 0xF) << 4)
+#define TLB_ATTR_MASK         0x0000000F
+#define TLB_W                 0x00000008 /* Caching is write-through */
+#define TLB_I                 0x00000004 /* Caching is inhibited */
+#define TLB_M                 0x00000002 /* Memory is coherent */
+#define TLB_G                 0x00000001 /* Memory is guarded from prefetch */
+
+#define TLB_ENTRIES    64
+
+struct microblaze_mmu
+{
+    /* Data and tag brams.  */
+    uint32_t rams[2][TLB_ENTRIES];
+    /* We keep a separate ram for the tids to avoid the 48 bit tag width.  */
+    uint8_t tids[TLB_ENTRIES];
+    /* Control flops.  */
+    uint32_t regs[8];
+
+    int c_mmu;
+    int c_mmu_tlb_access;
+    int c_mmu_zones;
+};
+
+struct microblaze_mmu_lookup
+{
+    uint32_t paddr;
+    uint32_t vaddr;
+    unsigned int size;
+    unsigned int idx;
+    int prot;
+    enum {
+        ERR_PROT, ERR_MISS, ERR_HIT
+    } err;
+};
+
+void mmu_flip_um(CPUState *env, unsigned int um);
+unsigned int mmu_translate(struct microblaze_mmu *mmu,
+                           struct microblaze_mmu_lookup *lu,
+                           target_ulong vaddr, int rw, int mmu_idx);
+uint32_t mmu_read(CPUState *env, uint32_t rn);
+void mmu_write(CPUState *env, uint32_t rn, uint32_t v);
+void mmu_init(struct microblaze_mmu *mmu);
diff --git a/qemu-0.15.x/target-microblaze/op_helper.c b/qemu-0.15.x/target-microblaze/op_helper.c
new file mode 100644
index 0000000..664ffe5
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/op_helper.c
@@ -0,0 +1,520 @@
+/*
+ *  Microblaze helper routines.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias at gmail.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include "exec.h"
+#include "helper.h"
+#include "host-utils.h"
+
+#define D(x)
+
+#if !defined(CONFIG_USER_ONLY)
+#define MMUSUFFIX _mmu
+#define SHIFT 0
+#include "softmmu_template.h"
+#define SHIFT 1
+#include "softmmu_template.h"
+#define SHIFT 2
+#include "softmmu_template.h"
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+#endif
+
+void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
+{
+    int test = ctrl & STREAM_TEST;
+    int atomic = ctrl & STREAM_ATOMIC;
+    int control = ctrl & STREAM_CONTROL;
+    int nonblock = ctrl & STREAM_NONBLOCK;
+    int exception = ctrl & STREAM_EXCEPTION;
+
+    qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
+             id, data,
+             test ? "t" : "",
+             nonblock ? "n" : "",
+             exception ? "e" : "",
+             control ? "c" : "",
+             atomic ? "a" : "");
+}
+
+uint32_t helper_get(uint32_t id, uint32_t ctrl)
+{
+    int test = ctrl & STREAM_TEST;
+    int atomic = ctrl & STREAM_ATOMIC;
+    int control = ctrl & STREAM_CONTROL;
+    int nonblock = ctrl & STREAM_NONBLOCK;
+    int exception = ctrl & STREAM_EXCEPTION;
+
+    qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
+             id,
+             test ? "t" : "",
+             nonblock ? "n" : "",
+             exception ? "e" : "",
+             control ? "c" : "",
+             atomic ? "a" : "");
+    return 0xdead0000 | id;
+}
+
+void helper_raise_exception(uint32_t index)
+{
+    env->exception_index = index;
+    cpu_loop_exit(env);
+}
+
+void helper_debug(void)
+{
+    int i;
+
+    qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
+    qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
+             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
+             env->debug, env->imm, env->iflags);
+    qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
+             env->btaken, env->btarget,
+             (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
+             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
+             (env->sregs[SR_MSR] & MSR_EIP),
+             (env->sregs[SR_MSR] & MSR_IE));
+    for (i = 0; i < 32; i++) {
+        qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
+        if ((i + 1) % 4 == 0)
+            qemu_log("\n");
+    }
+    qemu_log("\n\n");
+}
+
+static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
+{
+    uint32_t cout = 0;
+
+    if ((b == ~0) && cin)
+        cout = 1;
+    else if ((~0 - a) < (b + cin))
+        cout = 1;
+    return cout;
+}
+
+uint32_t helper_cmp(uint32_t a, uint32_t b)
+{
+    uint32_t t;
+
+    t = b + ~a + 1;
+    if ((b & 0x80000000) ^ (a & 0x80000000))
+        t = (t & 0x7fffffff) | (b & 0x80000000);
+    return t;
+}
+
+uint32_t helper_cmpu(uint32_t a, uint32_t b)
+{
+    uint32_t t;
+
+    t = b + ~a + 1;
+    if ((b & 0x80000000) ^ (a & 0x80000000))
+        t = (t & 0x7fffffff) | (a & 0x80000000);
+    return t;
+}
+
+uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
+{
+    uint32_t ncf;
+    ncf = compute_carry(a, b, cf);
+    return ncf;
+}
+
+static inline int div_prepare(uint32_t a, uint32_t b)
+{
+    if (b == 0) {
+        env->sregs[SR_MSR] |= MSR_DZ;
+
+        if ((env->sregs[SR_MSR] & MSR_EE)
+            && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) {
+            env->sregs[SR_ESR] = ESR_EC_DIVZERO;
+            helper_raise_exception(EXCP_HW_EXCP);
+        }
+        return 0;
+    }
+    env->sregs[SR_MSR] &= ~MSR_DZ;
+    return 1;
+}
+
+uint32_t helper_divs(uint32_t a, uint32_t b)
+{
+    if (!div_prepare(a, b))
+        return 0;
+    return (int32_t)a / (int32_t)b;
+}
+
+uint32_t helper_divu(uint32_t a, uint32_t b)
+{
+    if (!div_prepare(a, b))
+        return 0;
+    return a / b;
+}
+
+/* raise FPU exception.  */
+static void raise_fpu_exception(void)
+{
+    env->sregs[SR_ESR] = ESR_EC_FPU;
+    helper_raise_exception(EXCP_HW_EXCP);
+}
+
+static void update_fpu_flags(int flags)
+{
+    int raise = 0;
+
+    if (flags & float_flag_invalid) {
+        env->sregs[SR_FSR] |= FSR_IO;
+        raise = 1;
+    }
+    if (flags & float_flag_divbyzero) {
+        env->sregs[SR_FSR] |= FSR_DZ;
+        raise = 1;
+    }
+    if (flags & float_flag_overflow) {
+        env->sregs[SR_FSR] |= FSR_OF;
+        raise = 1;
+    }
+    if (flags & float_flag_underflow) {
+        env->sregs[SR_FSR] |= FSR_UF;
+        raise = 1;
+    }
+    if (raise
+        && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
+        && (env->sregs[SR_MSR] & MSR_EE)) {
+        raise_fpu_exception();
+    }
+}
+
+uint32_t helper_fadd(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fd, fa, fb;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    fd.f = float32_add(fa.f, fb.f, &env->fp_status);
+
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+    return fd.l;
+}
+
+uint32_t helper_frsub(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fd, fa, fb;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+    return fd.l;
+}
+
+uint32_t helper_fmul(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fd, fa, fb;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+
+    return fd.l;
+}
+
+uint32_t helper_fdiv(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fd, fa, fb;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    fd.f = float32_div(fb.f, fa.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+
+    return fd.l;
+}
+
+uint32_t helper_fcmp_un(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    uint32_t r = 0;
+
+    fa.l = a;
+    fb.l = b;
+
+    if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) {
+        update_fpu_flags(float_flag_invalid);
+        r = 1;
+    }
+
+    if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
+        r = 1;
+    }
+
+    return r;
+}
+
+uint32_t helper_fcmp_lt(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int r;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    r = float32_lt(fb.f, fa.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+
+    return r;
+}
+
+uint32_t helper_fcmp_eq(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int flags;
+    int r;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fb.l = b;
+    r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+
+    return r;
+}
+
+uint32_t helper_fcmp_le(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int flags;
+    int r;
+
+    fa.l = a;
+    fb.l = b;
+    set_float_exception_flags(0, &env->fp_status);
+    r = float32_le(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+
+
+    return r;
+}
+
+uint32_t helper_fcmp_gt(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int flags, r;
+
+    fa.l = a;
+    fb.l = b;
+    set_float_exception_flags(0, &env->fp_status);
+    r = float32_lt(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+    return r;
+}
+
+uint32_t helper_fcmp_ne(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int flags, r;
+
+    fa.l = a;
+    fb.l = b;
+    set_float_exception_flags(0, &env->fp_status);
+    r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+
+    return r;
+}
+
+uint32_t helper_fcmp_ge(uint32_t a, uint32_t b)
+{
+    CPU_FloatU fa, fb;
+    int flags, r;
+
+    fa.l = a;
+    fb.l = b;
+    set_float_exception_flags(0, &env->fp_status);
+    r = !float32_lt(fa.f, fb.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags & float_flag_invalid);
+
+    return r;
+}
+
+uint32_t helper_flt(uint32_t a)
+{
+    CPU_FloatU fd, fa;
+
+    fa.l = a;
+    fd.f = int32_to_float32(fa.l, &env->fp_status);
+    return fd.l;
+}
+
+uint32_t helper_fint(uint32_t a)
+{
+    CPU_FloatU fa;
+    uint32_t r;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    r = float32_to_int32(fa.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+
+    return r;
+}
+
+uint32_t helper_fsqrt(uint32_t a)
+{
+    CPU_FloatU fd, fa;
+    int flags;
+
+    set_float_exception_flags(0, &env->fp_status);
+    fa.l = a;
+    fd.l = float32_sqrt(fa.f, &env->fp_status);
+    flags = get_float_exception_flags(&env->fp_status);
+    update_fpu_flags(flags);
+
+    return fd.l;
+}
+
+uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
+{
+    unsigned int i;
+    uint32_t mask = 0xff000000;
+
+    for (i = 0; i < 4; i++) {
+        if ((a & mask) == (b & mask))
+            return i + 1;
+        mask >>= 8;
+    }
+    return 0;
+}
+
+void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask)
+{
+    if (addr & mask) {
+            qemu_log_mask(CPU_LOG_INT,
+                          "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
+                          addr, mask, wr, dr);
+            env->sregs[SR_EAR] = addr;
+            env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
+                                 | (dr & 31) << 5;
+            if (mask == 3) {
+                env->sregs[SR_ESR] |= 1 << 11;
+            }
+            if (!(env->sregs[SR_MSR] & MSR_EE)) {
+                return;
+            }
+            helper_raise_exception(EXCP_HW_EXCP);
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Writes/reads to the MMU's special regs end up here.  */
+uint32_t helper_mmu_read(uint32_t rn)
+{
+    return mmu_read(env, rn);
+}
+
+void helper_mmu_write(uint32_t rn, uint32_t v)
+{
+    mmu_write(env, rn, v);
+}
+
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+
+    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
+             addr, is_write, is_exec);
+    if (!(env->sregs[SR_MSR] & MSR_EE)) {
+        env = saved_env;
+        return;
+    }
+
+    env->sregs[SR_EAR] = addr;
+    if (is_exec) {
+        if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
+            env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
+            helper_raise_exception(EXCP_HW_EXCP);
+        }
+    } else {
+        if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
+            env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
+            helper_raise_exception(EXCP_HW_EXCP);
+        }
+    }
+    env = saved_env;
+}
+#endif
diff --git a/qemu-0.15.x/target-microblaze/translate.c b/qemu-0.15.x/target-microblaze/translate.c
new file mode 100644
index 0000000..31e8306
--- /dev/null
+++ b/qemu-0.15.x/target-microblaze/translate.c
@@ -0,0 +1,1945 @@
+/*
+ *  Xilinx MicroBlaze emulation for qemu: main translation routines.
+ *
+ *  Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "helper.h"
+#include "microblaze-decode.h"
+#include "qemu-common.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define SIM_COMPAT 0
+#define DISAS_GNU 1
+#define DISAS_MB 1
+#if DISAS_MB && !SIM_COMPAT
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+#define D(x)
+
+#define EXTRACT_FIELD(src, start, end) \
+            (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+static TCGv env_debug;
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[32];
+static TCGv cpu_SR[18];
+static TCGv env_imm;
+static TCGv env_btaken;
+static TCGv env_btarget;
+static TCGv env_iflags;
+
+#include "gen-icount.h"
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+    CPUState *env;
+    target_ulong pc;
+
+    /* Decoder.  */
+    int type_b;
+    uint32_t ir;
+    uint8_t opcode;
+    uint8_t rd, ra, rb;
+    uint16_t imm;
+
+    unsigned int cpustate_changed;
+    unsigned int delayed_branch;
+    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
+    unsigned int clear_imm;
+    int is_jmp;
+
+#define JMP_NOJMP     0
+#define JMP_DIRECT    1
+#define JMP_DIRECT_CC 2
+#define JMP_INDIRECT  3
+    unsigned int jmp;
+    uint32_t jmp_pc;
+
+    int abort_at_next_insn;
+    int nr_nops;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+static const char *regnames[] =
+{
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+};
+
+static const char *special_regnames[] =
+{
+    "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
+    "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
+    "sr16", "sr17", "sr18"
+};
+
+/* Sign extend at translation time.  */
+static inline int sign_extend(unsigned int val, unsigned int width)
+{
+        int sval;
+
+        /* LSL.  */
+        val <<= 31 - width;
+        sval = val;
+        /* ASR.  */
+        sval >>= 31 - width;
+        return sval;
+}
+
+static inline void t_sync_flags(DisasContext *dc)
+{
+    /* Synch the tb dependant flags between translator and runtime.  */
+    if (dc->tb_flags != dc->synced_flags) {
+        tcg_gen_movi_tl(env_iflags, dc->tb_flags);
+        dc->synced_flags = dc->tb_flags;
+    }
+}
+
+static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
+{
+    TCGv_i32 tmp = tcg_const_i32(index);
+
+    t_sync_flags(dc);
+    tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+    gen_helper_raise_exception(tmp);
+    tcg_temp_free_i32(tmp);
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = dc->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void read_carry(DisasContext *dc, TCGv d)
+{
+    tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
+}
+
+static void write_carry(DisasContext *dc, TCGv v)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shli_tl(t0, v, 31);
+    tcg_gen_sari_tl(t0, t0, 31);
+    tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
+    tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
+                    ~(MSR_C | MSR_CC));
+    tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
+    tcg_temp_free(t0);
+}
+
+/* True if ALU operand b is a small immediate that may deserve
+   faster treatment.  */
+static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
+{
+    /* Immediate insn without the imm prefix ?  */
+    return dc->type_b && !(dc->tb_flags & IMM_FLAG);
+}
+
+static inline TCGv *dec_alu_op_b(DisasContext *dc)
+{
+    if (dc->type_b) {
+        if (dc->tb_flags & IMM_FLAG)
+            tcg_gen_ori_tl(env_imm, env_imm, dc->imm);
+        else
+            tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm));
+        return &env_imm;
+    } else
+        return &cpu_R[dc->rb];
+}
+
+static void dec_add(DisasContext *dc)
+{
+    unsigned int k, c;
+    TCGv cf;
+
+    k = dc->opcode & 4;
+    c = dc->opcode & 2;
+
+    LOG_DIS("add%s%s%s r%d r%d r%d\n",
+            dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
+            dc->rd, dc->ra, dc->rb);
+
+    /* Take care of the easy cases first.  */
+    if (k) {
+        /* k - keep carry, no need to update MSR.  */
+        /* If rd == r0, it's a nop.  */
+        if (dc->rd) {
+            tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+
+            if (c) {
+                /* c - Add carry into the result.  */
+                cf = tcg_temp_new();
+
+                read_carry(dc, cf);
+                tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+                tcg_temp_free(cf);
+            }
+        }
+        return;
+    }
+
+    /* From now on, we can assume k is zero.  So we need to update MSR.  */
+    /* Extract carry.  */
+    cf = tcg_temp_new();
+    if (c) {
+        read_carry(dc, cf);
+    } else {
+        tcg_gen_movi_tl(cf, 0);
+    }
+
+    if (dc->rd) {
+        TCGv ncf = tcg_temp_new();
+        gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
+        tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+        tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+        write_carry(dc, ncf);
+        tcg_temp_free(ncf);
+    } else {
+        gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
+        write_carry(dc, cf);
+    }
+    tcg_temp_free(cf);
+}
+
+static void dec_sub(DisasContext *dc)
+{
+    unsigned int u, cmp, k, c;
+    TCGv cf, na;
+
+    u = dc->imm & 2;
+    k = dc->opcode & 4;
+    c = dc->opcode & 2;
+    cmp = (dc->imm & 1) && (!dc->type_b) && k;
+
+    if (cmp) {
+        LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
+        if (dc->rd) {
+            if (u)
+                gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            else
+                gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+        }
+        return;
+    }
+
+    LOG_DIS("sub%s%s r%d, r%d r%d\n",
+             k ? "k" : "",  c ? "c" : "", dc->rd, dc->ra, dc->rb);
+
+    /* Take care of the easy cases first.  */
+    if (k) {
+        /* k - keep carry, no need to update MSR.  */
+        /* If rd == r0, it's a nop.  */
+        if (dc->rd) {
+            tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+
+            if (c) {
+                /* c - Add carry into the result.  */
+                cf = tcg_temp_new();
+
+                read_carry(dc, cf);
+                tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+                tcg_temp_free(cf);
+            }
+        }
+        return;
+    }
+
+    /* From now on, we can assume k is zero.  So we need to update MSR.  */
+    /* Extract carry. And complement a into na.  */
+    cf = tcg_temp_new();
+    na = tcg_temp_new();
+    if (c) {
+        read_carry(dc, cf);
+    } else {
+        tcg_gen_movi_tl(cf, 1);
+    }
+
+    /* d = b + ~a + c. carry defaults to 1.  */
+    tcg_gen_not_tl(na, cpu_R[dc->ra]);
+
+    if (dc->rd) {
+        TCGv ncf = tcg_temp_new();
+        gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
+        tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
+        tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+        write_carry(dc, ncf);
+        tcg_temp_free(ncf);
+    } else {
+        gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
+        write_carry(dc, cf);
+    }
+    tcg_temp_free(cf);
+    tcg_temp_free(na);
+}
+
+static void dec_pattern(DisasContext *dc)
+{
+    unsigned int mode;
+    int l1;
+
+    if ((dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+    }
+
+    mode = dc->opcode & 3;
+    switch (mode) {
+        case 0:
+            /* pcmpbf.  */
+            LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            if (dc->rd)
+                gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+        case 2:
+            LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            if (dc->rd) {
+                TCGv t0 = tcg_temp_local_new();
+                l1 = gen_new_label();
+                tcg_gen_movi_tl(t0, 1);
+                tcg_gen_brcond_tl(TCG_COND_EQ,
+                                  cpu_R[dc->ra], cpu_R[dc->rb], l1);
+                tcg_gen_movi_tl(t0, 0);
+                gen_set_label(l1);
+                tcg_gen_mov_tl(cpu_R[dc->rd], t0);
+                tcg_temp_free(t0);
+            }
+            break;
+        case 3:
+            LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            l1 = gen_new_label();
+            if (dc->rd) {
+                TCGv t0 = tcg_temp_local_new();
+                tcg_gen_movi_tl(t0, 1);
+                tcg_gen_brcond_tl(TCG_COND_NE,
+                                  cpu_R[dc->ra], cpu_R[dc->rb], l1);
+                tcg_gen_movi_tl(t0, 0);
+                gen_set_label(l1);
+                tcg_gen_mov_tl(cpu_R[dc->rd], t0);
+                tcg_temp_free(t0);
+            }
+            break;
+        default:
+            cpu_abort(dc->env,
+                      "unsupported pattern insn opcode=%x\n", dc->opcode);
+            break;
+    }
+}
+
+static void dec_and(DisasContext *dc)
+{
+    unsigned int not;
+
+    if (!dc->type_b && (dc->imm & (1 << 10))) {
+        dec_pattern(dc);
+        return;
+    }
+
+    not = dc->opcode & (1 << 1);
+    LOG_DIS("and%s\n", not ? "n" : "");
+
+    if (!dc->rd)
+        return;
+
+    if (not) {
+        TCGv t = tcg_temp_new();
+        tcg_gen_not_tl(t, *(dec_alu_op_b(dc)));
+        tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], t);
+        tcg_temp_free(t);
+    } else
+        tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void dec_or(DisasContext *dc)
+{
+    if (!dc->type_b && (dc->imm & (1 << 10))) {
+        dec_pattern(dc);
+        return;
+    }
+
+    LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
+    if (dc->rd)
+        tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static void dec_xor(DisasContext *dc)
+{
+    if (!dc->type_b && (dc->imm & (1 << 10))) {
+        dec_pattern(dc);
+        return;
+    }
+
+    LOG_DIS("xor r%d\n", dc->rd);
+    if (dc->rd)
+        tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static inline void msr_read(DisasContext *dc, TCGv d)
+{
+    tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
+}
+
+static inline void msr_write(DisasContext *dc, TCGv v)
+{
+    dc->cpustate_changed = 1;
+    tcg_gen_mov_tl(cpu_SR[SR_MSR], v);
+    /* PVR, we have a processor version register.  */
+    tcg_gen_ori_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], (1 << 10));
+}
+
+static void dec_msr(DisasContext *dc)
+{
+    TCGv t0, t1;
+    unsigned int sr, to, rn;
+    int mem_index = cpu_mmu_index(dc->env);
+
+    sr = dc->imm & ((1 << 14) - 1);
+    to = dc->imm & (1 << 14);
+    dc->type_b = 1;
+    if (to)
+        dc->cpustate_changed = 1;
+
+    /* msrclr and msrset.  */
+    if (!(dc->imm & (1 << 15))) {
+        unsigned int clr = dc->ir & (1 << 16);
+
+        LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
+                dc->rd, dc->imm);
+
+        if (!(dc->env->pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
+            /* nop??? */
+            return;
+        }
+
+        if ((dc->tb_flags & MSR_EE_FLAG)
+            && mem_index == MMU_USER_IDX && (dc->imm != 4 && dc->imm != 0)) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+            return;
+        }
+
+        if (dc->rd)
+            msr_read(dc, cpu_R[dc->rd]);
+
+        t0 = tcg_temp_new();
+        t1 = tcg_temp_new();
+        msr_read(dc, t0);
+        tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc)));
+
+        if (clr) {
+            tcg_gen_not_tl(t1, t1);
+            tcg_gen_and_tl(t0, t0, t1);
+        } else
+            tcg_gen_or_tl(t0, t0, t1);
+        msr_write(dc, t0);
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+	tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
+        dc->is_jmp = DISAS_UPDATE;
+        return;
+    }
+
+    if (to) {
+        if ((dc->tb_flags & MSR_EE_FLAG)
+             && mem_index == MMU_USER_IDX) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+            return;
+        }
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    /* Catch read/writes to the mmu block.  */
+    if ((sr & ~0xff) == 0x1000) {
+        sr &= 7;
+        LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
+        if (to)
+            gen_helper_mmu_write(tcg_const_tl(sr), cpu_R[dc->ra]);
+        else
+            gen_helper_mmu_read(cpu_R[dc->rd], tcg_const_tl(sr));
+        return;
+    }
+#endif
+
+    if (to) {
+        LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
+        switch (sr) {
+            case 0:
+                break;
+            case 1:
+                msr_write(dc, cpu_R[dc->ra]);
+                break;
+            case 0x3:
+                tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]);
+                break;
+            case 0x5:
+                tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
+                break;
+            case 0x7:
+                tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
+                break;
+            default:
+                cpu_abort(dc->env, "unknown mts reg %x\n", sr);
+                break;
+        }
+    } else {
+        LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
+
+        switch (sr) {
+            case 0:
+                tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+                break;
+            case 1:
+                msr_read(dc, cpu_R[dc->rd]);
+                break;
+            case 0x3:
+                tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]);
+                break;
+            case 0x5:
+                tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
+                break;
+             case 0x7:
+                tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
+                break;
+            case 0xb:
+                tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
+                break;
+            case 0x2000:
+            case 0x2001:
+            case 0x2002:
+            case 0x2003:
+            case 0x2004:
+            case 0x2005:
+            case 0x2006:
+            case 0x2007:
+            case 0x2008:
+            case 0x2009:
+            case 0x200a:
+            case 0x200b:
+            case 0x200c:
+                rn = sr & 0xf;
+                tcg_gen_ld_tl(cpu_R[dc->rd],
+                              cpu_env, offsetof(CPUState, pvr.regs[rn]));
+                break;
+            default:
+                cpu_abort(dc->env, "unknown mfs reg %x\n", sr);
+                break;
+        }
+    }
+
+    if (dc->rd == 0) {
+        tcg_gen_movi_tl(cpu_R[0], 0);
+    }
+}
+
+/* 64-bit signed mul, lower result in d and upper in d2.  */
+static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b)
+{
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(t0, a);
+    tcg_gen_ext_i32_i64(t1, b);
+    tcg_gen_mul_i64(t0, t0, t1);
+
+    tcg_gen_trunc_i64_i32(d, t0);
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_trunc_i64_i32(d2, t0);
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+/* 64-bit unsigned muls, lower result in d and upper in d2.  */
+static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b)
+{
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(t0, a);
+    tcg_gen_extu_i32_i64(t1, b);
+    tcg_gen_mul_i64(t0, t0, t1);
+
+    tcg_gen_trunc_i64_i32(d, t0);
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_trunc_i64_i32(d2, t0);
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+/* Multiplier unit.  */
+static void dec_mul(DisasContext *dc)
+{
+    TCGv d[2];
+    unsigned int subcode;
+
+    if ((dc->tb_flags & MSR_EE_FLAG)
+         && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+         && !(dc->env->pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    subcode = dc->imm & 3;
+    d[0] = tcg_temp_new();
+    d[1] = tcg_temp_new();
+
+    if (dc->type_b) {
+        LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
+        t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+        goto done;
+    }
+
+    /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2.  */
+    if (subcode >= 1 && subcode <= 3
+        && !((dc->env->pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
+        /* nop??? */
+    }
+
+    switch (subcode) {
+        case 0:
+            LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+        case 1:
+            LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+        case 2:
+            LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+        case 3:
+            LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
+            t_gen_mulu(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+        default:
+            cpu_abort(dc->env, "unknown MUL insn %x\n", subcode);
+            break;
+    }
+done:
+    tcg_temp_free(d[0]);
+    tcg_temp_free(d[1]);
+}
+
+/* Div unit.  */
+static void dec_div(DisasContext *dc)
+{
+    unsigned int u;
+
+    u = dc->imm & 2; 
+    LOG_DIS("div\n");
+
+    if ((dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->env->pvr.regs[0] & PVR0_USE_DIV_MASK))) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+    }
+
+    if (u)
+        gen_helper_divu(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+    else
+        gen_helper_divs(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+    if (!dc->rd)
+        tcg_gen_movi_tl(cpu_R[dc->rd], 0);
+}
+
+static void dec_barrel(DisasContext *dc)
+{
+    TCGv t0;
+    unsigned int s, t;
+
+    if ((dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !(dc->env->pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    s = dc->imm & (1 << 10);
+    t = dc->imm & (1 << 9);
+
+    LOG_DIS("bs%s%s r%d r%d r%d\n",
+            s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
+
+    t0 = tcg_temp_new();
+
+    tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc)));
+    tcg_gen_andi_tl(t0, t0, 31);
+
+    if (s)
+        tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+    else {
+        if (t)
+            tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+        else
+            tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+    }
+}
+
+static void dec_bit(DisasContext *dc)
+{
+    TCGv t0, t1;
+    unsigned int op;
+    int mem_index = cpu_mmu_index(dc->env);
+
+    op = dc->ir & ((1 << 8) - 1);
+    switch (op) {
+        case 0x21:
+            /* src.  */
+            t0 = tcg_temp_new();
+
+            LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
+            tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1);
+            if (dc->rd) {
+                t1 = tcg_temp_new();
+                read_carry(dc, t1);
+                tcg_gen_shli_tl(t1, t1, 31);
+
+                tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+                tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t1);
+                tcg_temp_free(t1);
+            }
+
+            /* Update carry.  */
+            write_carry(dc, t0);
+            tcg_temp_free(t0);
+            break;
+
+        case 0x1:
+        case 0x41:
+            /* srl.  */
+            t0 = tcg_temp_new();
+            LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
+
+            /* Update carry.  */
+            tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1);
+            write_carry(dc, t0);
+            tcg_temp_free(t0);
+            if (dc->rd) {
+                if (op == 0x41)
+                    tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+                else
+                    tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+            }
+            break;
+        case 0x60:
+            LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
+            tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+        case 0x61:
+            LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
+            tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+        case 0x64:
+        case 0x66:
+        case 0x74:
+        case 0x76:
+            /* wdc.  */
+            LOG_DIS("wdc r%d\n", dc->ra);
+            if ((dc->tb_flags & MSR_EE_FLAG)
+                 && mem_index == MMU_USER_IDX) {
+                tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+                t_gen_raise_exception(dc, EXCP_HW_EXCP);
+                return;
+            }
+            break;
+        case 0x68:
+            /* wic.  */
+            LOG_DIS("wic r%d\n", dc->ra);
+            if ((dc->tb_flags & MSR_EE_FLAG)
+                 && mem_index == MMU_USER_IDX) {
+                tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+                t_gen_raise_exception(dc, EXCP_HW_EXCP);
+                return;
+            }
+            break;
+        default:
+            cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
+                     dc->pc, op, dc->rd, dc->ra, dc->rb);
+            break;
+    }
+}
+
+static inline void sync_jmpstate(DisasContext *dc)
+{
+    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+        if (dc->jmp == JMP_DIRECT) {
+            tcg_gen_movi_tl(env_btaken, 1);
+        }
+        dc->jmp = JMP_INDIRECT;
+        tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+    }
+}
+
+static void dec_imm(DisasContext *dc)
+{
+    LOG_DIS("imm %x\n", dc->imm << 16);
+    tcg_gen_movi_tl(env_imm, (dc->imm << 16));
+    dc->tb_flags |= IMM_FLAG;
+    dc->clear_imm = 0;
+}
+
+static inline void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
+                            unsigned int size)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+
+    if (size == 1) {
+        tcg_gen_qemu_ld8u(dst, addr, mem_index);
+    } else if (size == 2) {
+        tcg_gen_qemu_ld16u(dst, addr, mem_index);
+    } else if (size == 4) {
+        tcg_gen_qemu_ld32u(dst, addr, mem_index);
+    } else
+        cpu_abort(dc->env, "Incorrect load size %d\n", size);
+}
+
+static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
+{
+    unsigned int extimm = dc->tb_flags & IMM_FLAG;
+
+    /* Treat the common cases first.  */
+    if (!dc->type_b) {
+        /* If any of the regs is r0, return a ptr to the other.  */
+        if (dc->ra == 0) {
+            return &cpu_R[dc->rb];
+        } else if (dc->rb == 0) {
+            return &cpu_R[dc->ra];
+        }
+
+        *t = tcg_temp_new();
+        tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
+        return t;
+    }
+    /* Immediate.  */
+    if (!extimm) {
+        if (dc->imm == 0) {
+            return &cpu_R[dc->ra];
+        }
+        *t = tcg_temp_new();
+        tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm));
+        tcg_gen_add_tl(*t, cpu_R[dc->ra], *t);
+    } else {
+        *t = tcg_temp_new();
+        tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+    }
+
+    return t;
+}
+
+static inline void dec_byteswap(DisasContext *dc, TCGv dst, TCGv src, int size)
+{
+    if (size == 4) {
+        tcg_gen_bswap32_tl(dst, src);
+    } else if (size == 2) {
+        TCGv t = tcg_temp_new();
+
+        /* bswap16 assumes the high bits are zero.  */
+        tcg_gen_andi_tl(t, src, 0xffff);
+        tcg_gen_bswap16_tl(dst, t);
+        tcg_temp_free(t);
+    } else {
+        /* Ignore.
+        cpu_abort(dc->env, "Invalid ldst byteswap size %d\n", size);
+        */
+    }
+}
+
+static void dec_load(DisasContext *dc)
+{
+    TCGv t, *addr;
+    unsigned int size, rev = 0;
+
+    size = 1 << (dc->opcode & 3);
+
+    if (!dc->type_b) {
+        rev = (dc->ir >> 9) & 1;
+    }
+
+    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    LOG_DIS("l%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
+
+    t_sync_flags(dc);
+    addr = compute_ldst_addr(dc, &t);
+
+    /*
+     * When doing reverse accesses we need to do two things.
+     *
+     * 1. Reverse the address wrt endianness.
+     * 2. Byteswap the data lanes on the way back into the CPU core.
+     */
+    if (rev && size != 4) {
+        /* Endian reverse the address. t is addr.  */
+        switch (size) {
+            case 1:
+            {
+                /* 00 -> 11
+                   01 -> 10
+                   10 -> 10
+                   11 -> 00 */
+                TCGv low = tcg_temp_new();
+
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_mov_tl(t, *addr);
+                    addr = &t;
+                }
+
+                tcg_gen_andi_tl(low, t, 3);
+                tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+                tcg_gen_andi_tl(t, t, ~3);
+                tcg_gen_or_tl(t, t, low);
+                tcg_gen_mov_tl(env_imm, t);
+                tcg_temp_free(low);
+                break;
+            }
+
+            case 2:
+                /* 00 -> 10
+                   10 -> 00.  */
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_xori_tl(t, *addr, 2);
+                    addr = &t;
+                } else {
+                    tcg_gen_xori_tl(t, t, 2);
+                }
+                break;
+            default:
+                cpu_abort(dc->env, "Invalid reverse size\n");
+                break;
+        }
+    }
+
+    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
+    sync_jmpstate(dc);
+
+    /* Verify alignment if needed.  */
+    if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+        TCGv v = tcg_temp_new();
+
+        /*
+         * Microblaze gives MMU faults priority over faults due to
+         * unaligned addresses. That's why we speculatively do the load
+         * into v. If the load succeeds, we verify alignment of the
+         * address and if that succeeds we write into the destination reg.
+         */
+        gen_load(dc, v, *addr, size);
+
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+        gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
+                            tcg_const_tl(0), tcg_const_tl(size - 1));
+        if (dc->rd) {
+            if (rev) {
+                dec_byteswap(dc, cpu_R[dc->rd], v, size);
+            } else {
+                tcg_gen_mov_tl(cpu_R[dc->rd], v);
+            }
+        }
+        tcg_temp_free(v);
+    } else {
+        if (dc->rd) {
+            gen_load(dc, cpu_R[dc->rd], *addr, size);
+            if (rev) {
+                dec_byteswap(dc, cpu_R[dc->rd], cpu_R[dc->rd], size);
+            }
+        } else {
+            /* We are loading into r0, no need to reverse.  */
+            gen_load(dc, env_imm, *addr, size);
+        }
+    }
+
+    if (addr == &t)
+        tcg_temp_free(t);
+}
+
+static void gen_store(DisasContext *dc, TCGv addr, TCGv val,
+                      unsigned int size)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+
+    if (size == 1)
+        tcg_gen_qemu_st8(val, addr, mem_index);
+    else if (size == 2) {
+        tcg_gen_qemu_st16(val, addr, mem_index);
+    } else if (size == 4) {
+        tcg_gen_qemu_st32(val, addr, mem_index);
+    } else
+        cpu_abort(dc->env, "Incorrect store size %d\n", size);
+}
+
+static void dec_store(DisasContext *dc)
+{
+    TCGv t, *addr;
+    unsigned int size, rev = 0;
+
+    size = 1 << (dc->opcode & 3);
+    if (!dc->type_b) {
+        rev = (dc->ir >> 9) & 1;
+    }
+
+    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    LOG_DIS("s%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
+    t_sync_flags(dc);
+    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
+    sync_jmpstate(dc);
+    addr = compute_ldst_addr(dc, &t);
+
+    if (rev && size != 4) {
+        /* Endian reverse the address. t is addr.  */
+        switch (size) {
+            case 1:
+            {
+                /* 00 -> 11
+                   01 -> 10
+                   10 -> 10
+                   11 -> 00 */
+                TCGv low = tcg_temp_new();
+
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_mov_tl(t, *addr);
+                    addr = &t;
+                }
+
+                tcg_gen_andi_tl(low, t, 3);
+                tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+                tcg_gen_andi_tl(t, t, ~3);
+                tcg_gen_or_tl(t, t, low);
+                tcg_gen_mov_tl(env_imm, t);
+                tcg_temp_free(low);
+                break;
+            }
+
+            case 2:
+                /* 00 -> 10
+                   10 -> 00.  */
+                /* Force addr into the temp.  */
+                if (addr != &t) {
+                    t = tcg_temp_new();
+                    tcg_gen_xori_tl(t, *addr, 2);
+                    addr = &t;
+                } else {
+                    tcg_gen_xori_tl(t, t, 2);
+                }
+                break;
+            default:
+                cpu_abort(dc->env, "Invalid reverse size\n");
+                break;
+        }
+
+        if (size != 1) {
+            TCGv bs_data = tcg_temp_new();
+            dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+            gen_store(dc, *addr, bs_data, size);
+            tcg_temp_free(bs_data);
+        } else {
+            gen_store(dc, *addr, cpu_R[dc->rd], size);
+        }
+    } else {
+        if (rev) {
+            TCGv bs_data = tcg_temp_new();
+            dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+            gen_store(dc, *addr, bs_data, size);
+            tcg_temp_free(bs_data);
+        } else {
+            gen_store(dc, *addr, cpu_R[dc->rd], size);
+        }
+    }
+
+    /* Verify alignment if needed.  */
+    if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+        tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+        /* FIXME: if the alignment is wrong, we should restore the value
+         *        in memory. One possible way to acheive this is to probe
+         *        the MMU prior to the memaccess, thay way we could put
+         *        the alignment checks in between the probe and the mem
+         *        access.
+         */
+        gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
+                            tcg_const_tl(1), tcg_const_tl(size - 1));
+    }
+
+    if (addr == &t)
+        tcg_temp_free(t);
+}
+
+static inline void eval_cc(DisasContext *dc, unsigned int cc,
+                           TCGv d, TCGv a, TCGv b)
+{
+    switch (cc) {
+        case CC_EQ:
+            tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
+            break;
+        case CC_NE:
+            tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
+            break;
+        case CC_LT:
+            tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
+            break;
+        case CC_LE:
+            tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
+            break;
+        case CC_GE:
+            tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
+            break;
+        case CC_GT:
+            tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
+            break;
+        default:
+            cpu_abort(dc->env, "Unknown condition code %x.\n", cc);
+            break;
+    }
+}
+
+static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
+{
+    int l1;
+
+    l1 = gen_new_label();
+    /* Conditional jmp.  */
+    tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
+    tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true);
+    gen_set_label(l1);
+}
+
+static void dec_bcc(DisasContext *dc)
+{
+    unsigned int cc;
+    unsigned int dslot;
+
+    cc = EXTRACT_FIELD(dc->ir, 21, 23);
+    dslot = dc->ir & (1 << 25);
+    LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
+
+    dc->delayed_branch = 1;
+    if (dslot) {
+        dc->delayed_branch = 2;
+        dc->tb_flags |= D_FLAG;
+        tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+                      cpu_env, offsetof(CPUState, bimm));
+    }
+
+    if (dec_alu_op_b_is_small_imm(dc)) {
+        int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend.  */
+
+        tcg_gen_movi_tl(env_btarget, dc->pc + offset);
+        dc->jmp = JMP_DIRECT_CC;
+        dc->jmp_pc = dc->pc + offset;
+    } else {
+        dc->jmp = JMP_INDIRECT;
+        tcg_gen_movi_tl(env_btarget, dc->pc);
+        tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+    }
+    eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
+}
+
+static void dec_br(DisasContext *dc)
+{
+    unsigned int dslot, link, abs;
+    int mem_index = cpu_mmu_index(dc->env);
+
+    dslot = dc->ir & (1 << 20);
+    abs = dc->ir & (1 << 19);
+    link = dc->ir & (1 << 18);
+    LOG_DIS("br%s%s%s%s imm=%x\n",
+             abs ? "a" : "", link ? "l" : "",
+             dc->type_b ? "i" : "", dslot ? "d" : "",
+             dc->imm);
+
+    dc->delayed_branch = 1;
+    if (dslot) {
+        dc->delayed_branch = 2;
+        dc->tb_flags |= D_FLAG;
+        tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+                      cpu_env, offsetof(CPUState, bimm));
+    }
+    if (link && dc->rd)
+        tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+
+    dc->jmp = JMP_INDIRECT;
+    if (abs) {
+        tcg_gen_movi_tl(env_btaken, 1);
+        tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
+        if (link && !dslot) {
+            if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
+                t_gen_raise_exception(dc, EXCP_BREAK);
+            if (dc->imm == 0) {
+                if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
+                    tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+                    t_gen_raise_exception(dc, EXCP_HW_EXCP);
+                    return;
+                }
+
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+            }
+        }
+    } else {
+        if (dec_alu_op_b_is_small_imm(dc)) {
+            dc->jmp = JMP_DIRECT;
+            dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
+        } else {
+            tcg_gen_movi_tl(env_btaken, 1);
+            tcg_gen_movi_tl(env_btarget, dc->pc);
+            tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+        }
+    }
+}
+
+static inline void do_rti(DisasContext *dc)
+{
+    TCGv t0, t1;
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1);
+    tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE);
+    tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+    tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+    tcg_gen_or_tl(t1, t1, t0);
+    msr_write(dc, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    dc->tb_flags &= ~DRTI_FLAG;
+}
+
+static inline void do_rtb(DisasContext *dc)
+{
+    TCGv t0, t1;
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP);
+    tcg_gen_shri_tl(t0, t1, 1);
+    tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+    tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+    tcg_gen_or_tl(t1, t1, t0);
+    msr_write(dc, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    dc->tb_flags &= ~DRTB_FLAG;
+}
+
+static inline void do_rte(DisasContext *dc)
+{
+    TCGv t0, t1;
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+
+    tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE);
+    tcg_gen_andi_tl(t1, t1, ~MSR_EIP);
+    tcg_gen_shri_tl(t0, t1, 1);
+    tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
+
+    tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
+    tcg_gen_or_tl(t1, t1, t0);
+    msr_write(dc, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    dc->tb_flags &= ~DRTE_FLAG;
+}
+
+static void dec_rts(DisasContext *dc)
+{
+    unsigned int b_bit, i_bit, e_bit;
+    int mem_index = cpu_mmu_index(dc->env);
+
+    i_bit = dc->ir & (1 << 21);
+    b_bit = dc->ir & (1 << 22);
+    e_bit = dc->ir & (1 << 23);
+
+    dc->delayed_branch = 2;
+    dc->tb_flags |= D_FLAG;
+    tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+                  cpu_env, offsetof(CPUState, bimm));
+
+    if (i_bit) {
+        LOG_DIS("rtid ir=%x\n", dc->ir);
+        if ((dc->tb_flags & MSR_EE_FLAG)
+             && mem_index == MMU_USER_IDX) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        }
+        dc->tb_flags |= DRTI_FLAG;
+    } else if (b_bit) {
+        LOG_DIS("rtbd ir=%x\n", dc->ir);
+        if ((dc->tb_flags & MSR_EE_FLAG)
+             && mem_index == MMU_USER_IDX) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        }
+        dc->tb_flags |= DRTB_FLAG;
+    } else if (e_bit) {
+        LOG_DIS("rted ir=%x\n", dc->ir);
+        if ((dc->tb_flags & MSR_EE_FLAG)
+             && mem_index == MMU_USER_IDX) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        }
+        dc->tb_flags |= DRTE_FLAG;
+    } else
+        LOG_DIS("rts ir=%x\n", dc->ir);
+
+    dc->jmp = JMP_INDIRECT;
+    tcg_gen_movi_tl(env_btaken, 1);
+    tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+}
+
+static int dec_check_fpuv2(DisasContext *dc)
+{
+    int r;
+
+    r = dc->env->pvr.regs[2] & PVR2_USE_FPU2_MASK;
+
+    if (!r && (dc->tb_flags & MSR_EE_FLAG)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+    }
+    return r;
+}
+
+static void dec_fpu(DisasContext *dc)
+{
+    unsigned int fpu_insn;
+
+    if ((dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+          && !((dc->env->pvr.regs[2] & PVR2_USE_FPU_MASK))) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    fpu_insn = (dc->ir >> 7) & 7;
+
+    switch (fpu_insn) {
+        case 0:
+            gen_helper_fadd(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 1:
+            gen_helper_frsub(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 2:
+            gen_helper_fmul(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 3:
+            gen_helper_fdiv(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+            break;
+
+        case 4:
+            switch ((dc->ir >> 4) & 7) {
+                case 0:
+                    gen_helper_fcmp_un(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 1:
+                    gen_helper_fcmp_lt(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 2:
+                    gen_helper_fcmp_eq(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 3:
+                    gen_helper_fcmp_le(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 4:
+                    gen_helper_fcmp_gt(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 5:
+                    gen_helper_fcmp_ne(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                case 6:
+                    gen_helper_fcmp_ge(cpu_R[dc->rd],
+                                       cpu_R[dc->ra], cpu_R[dc->rb]);
+                    break;
+                default:
+                    qemu_log ("unimplemented fcmp fpu_insn=%x pc=%x opc=%x\n",
+                              fpu_insn, dc->pc, dc->opcode);
+                    dc->abort_at_next_insn = 1;
+                    break;
+            }
+            break;
+
+        case 5:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_flt(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        case 6:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_fint(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        case 7:
+            if (!dec_check_fpuv2(dc)) {
+                return;
+            }
+            gen_helper_fsqrt(cpu_R[dc->rd], cpu_R[dc->ra]);
+            break;
+
+        default:
+            qemu_log ("unimplemented FPU insn fpu_insn=%x pc=%x opc=%x\n",
+                      fpu_insn, dc->pc, dc->opcode);
+            dc->abort_at_next_insn = 1;
+            break;
+    }
+}
+
+static void dec_null(DisasContext *dc)
+{
+    if ((dc->tb_flags & MSR_EE_FLAG)
+          && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+    qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
+    dc->abort_at_next_insn = 1;
+}
+
+/* Insns connected to FSL or AXI stream attached devices.  */
+static void dec_stream(DisasContext *dc)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+    TCGv_i32 t_id, t_ctrl;
+    int ctrl;
+
+    LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
+            dc->type_b ? "" : "d", dc->imm);
+
+    if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    t_id = tcg_temp_new();
+    if (dc->type_b) {
+        tcg_gen_movi_tl(t_id, dc->imm & 0xf);
+        ctrl = dc->imm >> 10;
+    } else {
+        tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
+        ctrl = dc->imm >> 5;
+    }
+
+    t_ctrl = tcg_const_tl(ctrl);
+
+    if (dc->rd == 0) {
+        gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
+    } else {
+        gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
+    }
+    tcg_temp_free(t_id);
+    tcg_temp_free(t_ctrl);
+}
+
+static struct decoder_info {
+    struct {
+        uint32_t bits;
+        uint32_t mask;
+    };
+    void (*dec)(DisasContext *dc);
+} decinfo[] = {
+    {DEC_ADD, dec_add},
+    {DEC_SUB, dec_sub},
+    {DEC_AND, dec_and},
+    {DEC_XOR, dec_xor},
+    {DEC_OR, dec_or},
+    {DEC_BIT, dec_bit},
+    {DEC_BARREL, dec_barrel},
+    {DEC_LD, dec_load},
+    {DEC_ST, dec_store},
+    {DEC_IMM, dec_imm},
+    {DEC_BR, dec_br},
+    {DEC_BCC, dec_bcc},
+    {DEC_RTS, dec_rts},
+    {DEC_FPU, dec_fpu},
+    {DEC_MUL, dec_mul},
+    {DEC_DIV, dec_div},
+    {DEC_MSR, dec_msr},
+    {DEC_STREAM, dec_stream},
+    {{0, 0}, dec_null}
+};
+
+static inline void decode(DisasContext *dc)
+{
+    uint32_t ir;
+    int i;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+        tcg_gen_debug_insn_start(dc->pc);
+
+    dc->ir = ir = ldl_code(dc->pc);
+    LOG_DIS("%8.8x\t", dc->ir);
+
+    if (dc->ir)
+        dc->nr_nops = 0;
+    else {
+        if ((dc->tb_flags & MSR_EE_FLAG)
+              && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+              && (dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
+            tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+            t_gen_raise_exception(dc, EXCP_HW_EXCP);
+            return;
+        }
+
+        LOG_DIS("nr_nops=%d\t", dc->nr_nops);
+        dc->nr_nops++;
+        if (dc->nr_nops > 4)
+            cpu_abort(dc->env, "fetching nop sequence\n");
+    }
+    /* bit 2 seems to indicate insn type.  */
+    dc->type_b = ir & (1 << 29);
+
+    dc->opcode = EXTRACT_FIELD(ir, 26, 31);
+    dc->rd = EXTRACT_FIELD(ir, 21, 25);
+    dc->ra = EXTRACT_FIELD(ir, 16, 20);
+    dc->rb = EXTRACT_FIELD(ir, 11, 15);
+    dc->imm = EXTRACT_FIELD(ir, 0, 15);
+
+    /* Large switch for all insns.  */
+    for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
+        if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
+            decinfo[i].dec(dc);
+            break;
+        }
+    }
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                t_gen_raise_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+static void
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+                               int search_pc)
+{
+    uint16_t *gen_opc_end;
+    uint32_t pc_start;
+    int j, lj;
+    struct DisasContext ctx;
+    struct DisasContext *dc = &ctx;
+    uint32_t next_page_start, org_flags;
+    target_ulong npc;
+    int num_insns;
+    int max_insns;
+
+    qemu_log_try_set_file(stderr);
+
+    pc_start = tb->pc;
+    dc->env = env;
+    dc->tb = tb;
+    org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->jmp = 0;
+    dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
+    if (dc->delayed_branch) {
+        dc->jmp = JMP_INDIRECT;
+    }
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->cpustate_changed = 0;
+    dc->abort_at_next_insn = 0;
+    dc->nr_nops = 0;
+
+    if (pc_start & 3)
+        cpu_abort(env, "Microblaze: unaligned PC=%x\n", pc_start);
+
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+#if !SIM_COMPAT
+        qemu_log("--------------\n");
+        log_cpu_state(env, 0);
+#endif
+    }
+
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+    do
+    {
+#if SIM_COMPAT
+        if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+            tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+            gen_helper_debug();
+        }
+#endif
+        check_breakpoint(env, dc);
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_instr_start[lj] = 1;
+                        gen_opc_icount[lj] = num_insns;
+        }
+
+        /* Pretty disas.  */
+        LOG_DIS("%8.8x:\t", dc->pc);
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+
+        dc->clear_imm = 1;
+	decode(dc);
+        if (dc->clear_imm)
+            dc->tb_flags &= ~IMM_FLAG;
+        dc->pc += 4;
+        num_insns++;
+
+        if (dc->delayed_branch) {
+            dc->delayed_branch--;
+            if (!dc->delayed_branch) {
+                if (dc->tb_flags & DRTI_FLAG)
+                    do_rti(dc);
+                 if (dc->tb_flags & DRTB_FLAG)
+                    do_rtb(dc);
+                if (dc->tb_flags & DRTE_FLAG)
+                    do_rte(dc);
+                /* Clear the delay slot flag.  */
+                dc->tb_flags &= ~D_FLAG;
+                /* If it is a direct jump, try direct chaining.  */
+                if (dc->jmp == JMP_INDIRECT) {
+                    eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
+                    dc->is_jmp = DISAS_JUMP;
+                } else if (dc->jmp == JMP_DIRECT) {
+                    t_sync_flags(dc);
+                    gen_goto_tb(dc, 0, dc->jmp_pc);
+                    dc->is_jmp = DISAS_TB_JUMP;
+                } else if (dc->jmp == JMP_DIRECT_CC) {
+                    int l1;
+
+                    t_sync_flags(dc);
+                    l1 = gen_new_label();
+                    /* Conditional jmp.  */
+                    tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
+                    gen_goto_tb(dc, 1, dc->pc);
+                    gen_set_label(l1);
+                    gen_goto_tb(dc, 0, dc->jmp_pc);
+
+                    dc->is_jmp = DISAS_TB_JUMP;
+                }
+                break;
+            }
+        }
+        if (env->singlestep_enabled)
+            break;
+    } while (!dc->is_jmp && !dc->cpustate_changed
+         && gen_opc_ptr < gen_opc_end
+                 && !singlestep
+         && (dc->pc < next_page_start)
+                 && num_insns < max_insns);
+
+    npc = dc->pc;
+    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+        if (dc->tb_flags & D_FLAG) {
+            dc->is_jmp = DISAS_UPDATE;
+            tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+            sync_jmpstate(dc);
+        } else
+            npc = dc->jmp_pc;
+    }
+
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    /* Force an update if the per-tb cpu state has changed.  */
+    if (dc->is_jmp == DISAS_NEXT
+        && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
+        dc->is_jmp = DISAS_UPDATE;
+        tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+    }
+    t_sync_flags(dc);
+
+    if (unlikely(env->singlestep_enabled)) {
+        TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
+
+        if (dc->is_jmp != DISAS_JUMP) {
+            tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+        }
+        gen_helper_raise_exception(tmp);
+        tcg_temp_free_i32(tmp);
+    } else {
+        switch(dc->is_jmp) {
+            case DISAS_NEXT:
+                gen_goto_tb(dc, 1, npc);
+                break;
+            default:
+            case DISAS_JUMP:
+            case DISAS_UPDATE:
+                /* indicate that the hash table must be used
+                   to find the next TB */
+                tcg_gen_exit_tb(0);
+                break;
+            case DISAS_TB_JUMP:
+                /* nothing more to generate */
+                break;
+        }
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = dc->pc - pc_start;
+                tb->icount = num_insns;
+    }
+
+#ifdef DEBUG_DISAS
+#if !SIM_COMPAT
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("\n");
+#if DISAS_GNU
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+#endif
+        qemu_log("\nisize=%d osize=%td\n",
+            dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+    }
+#endif
+#endif
+    assert(!dc->abort_at_next_insn);
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    int i;
+
+    if (!env || !f)
+        return;
+
+    cpu_fprintf(f, "IN: PC=%x %s\n",
+                env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
+    cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
+             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
+             env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
+    cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
+             env->btaken, env->btarget,
+             (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
+             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
+             (env->sregs[SR_MSR] & MSR_EIP),
+             (env->sregs[SR_MSR] & MSR_IE));
+
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
+        if ((i + 1) % 4 == 0)
+            cpu_fprintf(f, "\n");
+        }
+    cpu_fprintf(f, "\n\n");
+}
+
+CPUState *cpu_mb_init (const char *cpu_model)
+{
+    CPUState *env;
+    static int tcg_initialized = 0;
+    int i;
+
+    env = qemu_mallocz(sizeof(CPUState));
+
+    cpu_exec_init(env);
+    cpu_reset(env);
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+
+    if (tcg_initialized)
+        return env;
+
+    tcg_initialized = 1;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    env_debug = tcg_global_mem_new(TCG_AREG0, 
+                    offsetof(CPUState, debug),
+                    "debug0");
+    env_iflags = tcg_global_mem_new(TCG_AREG0, 
+                    offsetof(CPUState, iflags),
+                    "iflags");
+    env_imm = tcg_global_mem_new(TCG_AREG0, 
+                    offsetof(CPUState, imm),
+                    "imm");
+    env_btarget = tcg_global_mem_new(TCG_AREG0,
+                     offsetof(CPUState, btarget),
+                     "btarget");
+    env_btaken = tcg_global_mem_new(TCG_AREG0,
+                     offsetof(CPUState, btaken),
+                     "btaken");
+    for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
+        cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, regs[i]),
+                          regnames[i]);
+    }
+    for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
+        cpu_SR[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, sregs[i]),
+                          special_regnames[i]);
+    }
+#define GEN_HELPER 2
+#include "helper.h"
+
+    return env;
+}
+
+void cpu_reset (CPUState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    memset(env, 0, offsetof(CPUMBState, breakpoints));
+    tlb_flush(env, 1);
+
+    env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+                       | PVR0_USE_BARREL_MASK \
+                       | PVR0_USE_DIV_MASK \
+                       | PVR0_USE_HW_MUL_MASK \
+                       | PVR0_USE_EXC_MASK \
+                       | PVR0_USE_ICACHE_MASK \
+                       | PVR0_USE_DCACHE_MASK \
+                       | PVR0_USE_MMU \
+                       | (0xb << 8);
+    env->pvr.regs[2] = PVR2_D_OPB_MASK \
+                        | PVR2_D_LMB_MASK \
+                        | PVR2_I_OPB_MASK \
+                        | PVR2_I_LMB_MASK \
+                        | PVR2_USE_MSR_INSTR \
+                        | PVR2_USE_PCMP_INSTR \
+                        | PVR2_USE_BARREL_MASK \
+                        | PVR2_USE_DIV_MASK \
+                        | PVR2_USE_HW_MUL_MASK \
+                        | PVR2_USE_MUL64_MASK \
+                        | PVR2_USE_FPU_MASK \
+                        | PVR2_USE_FPU2_MASK \
+                        | PVR2_FPU_EXC_MASK \
+                        | 0;
+    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
+    env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+
+#if defined(CONFIG_USER_ONLY)
+    /* start in user mode with interrupts enabled.  */
+    env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
+    env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp.  */
+#else
+    env->sregs[SR_MSR] = 0;
+    mmu_init(&env->mmu);
+    env->mmu.c_mmu = 3;
+    env->mmu.c_mmu_tlb_access = 3;
+    env->mmu.c_mmu_zones = 16;
+#endif
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->sregs[SR_PC] = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/target-mips/TODO b/qemu-0.15.x/target-mips/TODO
new file mode 100644
index 0000000..9101881
--- /dev/null
+++ b/qemu-0.15.x/target-mips/TODO
@@ -0,0 +1,52 @@
+Unsolved issues/bugs in the mips/mipsel backend
+-----------------------------------------------
+
+General
+-------
+- Unimplemented ASEs:
+  - MDMX
+  - SmartMIPS
+  - DSP r1
+  - DSP r2
+- MT ASE only partially implemented and not functional
+- Shadow register support only partially implemented,
+  lacks set switching on interrupt/exception.
+- 34K ITC not implemented.
+- A general lack of documentation, especially for technical internals.
+  Existing documentation is x86-centric.
+- Reverse endianness bit not implemented
+- The TLB emulation is very inefficient:
+  Qemu's softmmu implements a x86-style MMU, with separate entries
+  for read/write/execute, a TLB index which is just a modulo of the
+  virtual address, and a set of TLBs for each user/kernel/supervisor
+  MMU mode.
+  MIPS has a single entry for read/write/execute and only one MMU mode.
+  But it is fully associative with randomized entry indices, and uses
+  up to 256 ASID tags as additional matching criterion (which roughly
+  equates to 256 MMU modes). It also has a global flag which causes
+  entries to match regardless of ASID.
+  To cope with these differences, Qemu currently flushes the TLB at
+  each ASID change. Using the MMU modes to implement ASIDs hinges on
+  implementing the global bit efficiently.
+- save/restore of the CPU state is not implemented (see machine.c).
+
+MIPS64
+------
+- Userland emulation (both n32 and n64) not functional.
+
+"Generic" 4Kc system emulation
+------------------------------
+- Doesn't correspond to any real hardware. Should be removed some day,
+  U-Boot is the last remaining user.
+
+PICA 61 system emulation
+------------------------
+- No framebuffer support yet.
+
+MALTA system emulation
+----------------------
+- We fake firmware support instead of doing the real thing
+- Real firmware (YAMON) falls over when trying to init RAM, presumably
+  due to lacking system controller emulation.
+- Bonito system controller not implemented
+- MSC1 system controller not implemented
diff --git a/qemu-0.15.x/target-mips/cpu.h b/qemu-0.15.x/target-mips/cpu.h
new file mode 100644
index 0000000..33be296
--- /dev/null
+++ b/qemu-0.15.x/target-mips/cpu.h
@@ -0,0 +1,683 @@
+#if !defined (__MIPS_CPU_H__)
+#define __MIPS_CPU_H__
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_MIPS
+
+#define CPUState struct CPUMIPSState
+
+#include "config.h"
+#include "qemu-common.h"
+#include "mips-defs.h"
+#include "cpu-defs.h"
+#include "softfloat.h"
+
+// uint_fast8_t and uint_fast16_t not in <sys/int_types.h>
+// XXX: move that elsewhere
+#if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10
+typedef unsigned char           uint_fast8_t;
+typedef unsigned int            uint_fast16_t;
+#endif
+
+struct CPUMIPSState;
+
+typedef struct r4k_tlb_t r4k_tlb_t;
+struct r4k_tlb_t {
+    target_ulong VPN;
+    uint32_t PageMask;
+    uint_fast8_t ASID;
+    uint_fast16_t G:1;
+    uint_fast16_t C0:3;
+    uint_fast16_t C1:3;
+    uint_fast16_t V0:1;
+    uint_fast16_t V1:1;
+    uint_fast16_t D0:1;
+    uint_fast16_t D1:1;
+    target_ulong PFN[2];
+};
+
+#if !defined(CONFIG_USER_ONLY)
+typedef struct CPUMIPSTLBContext CPUMIPSTLBContext;
+struct CPUMIPSTLBContext {
+    uint32_t nb_tlb;
+    uint32_t tlb_in_use;
+    int (*map_address) (struct CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type);
+    void (*helper_tlbwi) (void);
+    void (*helper_tlbwr) (void);
+    void (*helper_tlbp) (void);
+    void (*helper_tlbr) (void);
+    union {
+        struct {
+            r4k_tlb_t tlb[MIPS_TLB_MAX];
+        } r4k;
+    } mmu;
+};
+#endif
+
+typedef union fpr_t fpr_t;
+union fpr_t {
+    float64  fd;   /* ieee double precision */
+    float32  fs[2];/* ieee single precision */
+    uint64_t d;    /* binary double fixed-point */
+    uint32_t w[2]; /* binary single fixed-point */
+};
+/* define FP_ENDIAN_IDX to access the same location
+ * in the fpr_t union regardless of the host endianness
+ */
+#if defined(HOST_WORDS_BIGENDIAN)
+#  define FP_ENDIAN_IDX 1
+#else
+#  define FP_ENDIAN_IDX 0
+#endif
+
+typedef struct CPUMIPSFPUContext CPUMIPSFPUContext;
+struct CPUMIPSFPUContext {
+    /* Floating point registers */
+    fpr_t fpr[32];
+    float_status fp_status;
+    /* fpu implementation/revision register (fir) */
+    uint32_t fcr0;
+#define FCR0_F64 22
+#define FCR0_L 21
+#define FCR0_W 20
+#define FCR0_3D 19
+#define FCR0_PS 18
+#define FCR0_D 17
+#define FCR0_S 16
+#define FCR0_PRID 8
+#define FCR0_REV 0
+    /* fcsr */
+    uint32_t fcr31;
+#define SET_FP_COND(num,env)     do { ((env).fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
+#define CLEAR_FP_COND(num,env)   do { ((env).fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
+#define GET_FP_COND(env)         ((((env).fcr31 >> 24) & 0xfe) | (((env).fcr31 >> 23) & 0x1))
+#define GET_FP_CAUSE(reg)        (((reg) >> 12) & 0x3f)
+#define GET_FP_ENABLE(reg)       (((reg) >>  7) & 0x1f)
+#define GET_FP_FLAGS(reg)        (((reg) >>  2) & 0x1f)
+#define SET_FP_CAUSE(reg,v)      do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0)
+#define SET_FP_ENABLE(reg,v)     do { (reg) = ((reg) & ~(0x1f <<  7)) | ((v & 0x1f) << 7); } while(0)
+#define SET_FP_FLAGS(reg,v)      do { (reg) = ((reg) & ~(0x1f <<  2)) | ((v & 0x1f) << 2); } while(0)
+#define UPDATE_FP_FLAGS(reg,v)   do { (reg) |= ((v & 0x1f) << 2); } while(0)
+#define FP_INEXACT        1
+#define FP_UNDERFLOW      2
+#define FP_OVERFLOW       4
+#define FP_DIV0           8
+#define FP_INVALID        16
+#define FP_UNIMPLEMENTED  32
+};
+
+#define NB_MMU_MODES 3
+
+typedef struct CPUMIPSMVPContext CPUMIPSMVPContext;
+struct CPUMIPSMVPContext {
+    int32_t CP0_MVPControl;
+#define CP0MVPCo_CPA	3
+#define CP0MVPCo_STLB	2
+#define CP0MVPCo_VPC	1
+#define CP0MVPCo_EVP	0
+    int32_t CP0_MVPConf0;
+#define CP0MVPC0_M	31
+#define CP0MVPC0_TLBS	29
+#define CP0MVPC0_GS	28
+#define CP0MVPC0_PCP	27
+#define CP0MVPC0_PTLBE	16
+#define CP0MVPC0_TCA	15
+#define CP0MVPC0_PVPE	10
+#define CP0MVPC0_PTC	0
+    int32_t CP0_MVPConf1;
+#define CP0MVPC1_CIM	31
+#define CP0MVPC1_CIF	30
+#define CP0MVPC1_PCX	20
+#define CP0MVPC1_PCP2	10
+#define CP0MVPC1_PCP1	0
+};
+
+typedef struct mips_def_t mips_def_t;
+
+#define MIPS_SHADOW_SET_MAX 16
+#define MIPS_TC_MAX 5
+#define MIPS_FPU_MAX 1
+#define MIPS_DSP_ACC 4
+
+typedef struct TCState TCState;
+struct TCState {
+    target_ulong gpr[32];
+    target_ulong PC;
+    target_ulong HI[MIPS_DSP_ACC];
+    target_ulong LO[MIPS_DSP_ACC];
+    target_ulong ACX[MIPS_DSP_ACC];
+    target_ulong DSPControl;
+    int32_t CP0_TCStatus;
+#define CP0TCSt_TCU3	31
+#define CP0TCSt_TCU2	30
+#define CP0TCSt_TCU1	29
+#define CP0TCSt_TCU0	28
+#define CP0TCSt_TMX	27
+#define CP0TCSt_RNST	23
+#define CP0TCSt_TDS	21
+#define CP0TCSt_DT	20
+#define CP0TCSt_DA	15
+#define CP0TCSt_A	13
+#define CP0TCSt_TKSU	11
+#define CP0TCSt_IXMT	10
+#define CP0TCSt_TASID	0
+    int32_t CP0_TCBind;
+#define CP0TCBd_CurTC	21
+#define CP0TCBd_TBE	17
+#define CP0TCBd_CurVPE	0
+    target_ulong CP0_TCHalt;
+    target_ulong CP0_TCContext;
+    target_ulong CP0_TCSchedule;
+    target_ulong CP0_TCScheFBack;
+    int32_t CP0_Debug_tcstatus;
+};
+
+typedef struct CPUMIPSState CPUMIPSState;
+struct CPUMIPSState {
+    TCState active_tc;
+    CPUMIPSFPUContext active_fpu;
+
+    uint32_t current_tc;
+    uint32_t current_fpu;
+
+    uint32_t SEGBITS;
+    uint32_t PABITS;
+    target_ulong SEGMask;
+    target_ulong PAMask;
+
+    int32_t CP0_Index;
+    /* CP0_MVP* are per MVP registers. */
+    int32_t CP0_Random;
+    int32_t CP0_VPEControl;
+#define CP0VPECo_YSI	21
+#define CP0VPECo_GSI	20
+#define CP0VPECo_EXCPT	16
+#define CP0VPECo_TE	15
+#define CP0VPECo_TargTC	0
+    int32_t CP0_VPEConf0;
+#define CP0VPEC0_M	31
+#define CP0VPEC0_XTC	21
+#define CP0VPEC0_TCS	19
+#define CP0VPEC0_SCS	18
+#define CP0VPEC0_DSC	17
+#define CP0VPEC0_ICS	16
+#define CP0VPEC0_MVP	1
+#define CP0VPEC0_VPA	0
+    int32_t CP0_VPEConf1;
+#define CP0VPEC1_NCX	20
+#define CP0VPEC1_NCP2	10
+#define CP0VPEC1_NCP1	0
+    target_ulong CP0_YQMask;
+    target_ulong CP0_VPESchedule;
+    target_ulong CP0_VPEScheFBack;
+    int32_t CP0_VPEOpt;
+#define CP0VPEOpt_IWX7	15
+#define CP0VPEOpt_IWX6	14
+#define CP0VPEOpt_IWX5	13
+#define CP0VPEOpt_IWX4	12
+#define CP0VPEOpt_IWX3	11
+#define CP0VPEOpt_IWX2	10
+#define CP0VPEOpt_IWX1	9
+#define CP0VPEOpt_IWX0	8
+#define CP0VPEOpt_DWX7	7
+#define CP0VPEOpt_DWX6	6
+#define CP0VPEOpt_DWX5	5
+#define CP0VPEOpt_DWX4	4
+#define CP0VPEOpt_DWX3	3
+#define CP0VPEOpt_DWX2	2
+#define CP0VPEOpt_DWX1	1
+#define CP0VPEOpt_DWX0	0
+    target_ulong CP0_EntryLo0;
+    target_ulong CP0_EntryLo1;
+    target_ulong CP0_Context;
+    int32_t CP0_PageMask;
+    int32_t CP0_PageGrain;
+    int32_t CP0_Wired;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+#define CP0SRSC0_M	31
+#define CP0SRSC0_SRS3	20
+#define CP0SRSC0_SRS2	10
+#define CP0SRSC0_SRS1	0
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+#define CP0SRSC1_M	31
+#define CP0SRSC1_SRS6	20
+#define CP0SRSC1_SRS5	10
+#define CP0SRSC1_SRS4	0
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+#define CP0SRSC2_M	31
+#define CP0SRSC2_SRS9	20
+#define CP0SRSC2_SRS8	10
+#define CP0SRSC2_SRS7	0
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+#define CP0SRSC3_M	31
+#define CP0SRSC3_SRS12	20
+#define CP0SRSC3_SRS11	10
+#define CP0SRSC3_SRS10	0
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
+#define CP0SRSC4_SRS15	20
+#define CP0SRSC4_SRS14	10
+#define CP0SRSC4_SRS13	0
+    int32_t CP0_HWREna;
+    target_ulong CP0_BadVAddr;
+    int32_t CP0_Count;
+    target_ulong CP0_EntryHi;
+    int32_t CP0_Compare;
+    int32_t CP0_Status;
+#define CP0St_CU3   31
+#define CP0St_CU2   30
+#define CP0St_CU1   29
+#define CP0St_CU0   28
+#define CP0St_RP    27
+#define CP0St_FR    26
+#define CP0St_RE    25
+#define CP0St_MX    24
+#define CP0St_PX    23
+#define CP0St_BEV   22
+#define CP0St_TS    21
+#define CP0St_SR    20
+#define CP0St_NMI   19
+#define CP0St_IM    8
+#define CP0St_KX    7
+#define CP0St_SX    6
+#define CP0St_UX    5
+#define CP0St_KSU   3
+#define CP0St_ERL   2
+#define CP0St_EXL   1
+#define CP0St_IE    0
+    int32_t CP0_IntCtl;
+#define CP0IntCtl_IPTI 29
+#define CP0IntCtl_IPPC1 26
+#define CP0IntCtl_VS 5
+    int32_t CP0_SRSCtl;
+#define CP0SRSCtl_HSS 26
+#define CP0SRSCtl_EICSS 18
+#define CP0SRSCtl_ESS 12
+#define CP0SRSCtl_PSS 6
+#define CP0SRSCtl_CSS 0
+    int32_t CP0_SRSMap;
+#define CP0SRSMap_SSV7 28
+#define CP0SRSMap_SSV6 24
+#define CP0SRSMap_SSV5 20
+#define CP0SRSMap_SSV4 16
+#define CP0SRSMap_SSV3 12
+#define CP0SRSMap_SSV2 8
+#define CP0SRSMap_SSV1 4
+#define CP0SRSMap_SSV0 0
+    int32_t CP0_Cause;
+#define CP0Ca_BD   31
+#define CP0Ca_TI   30
+#define CP0Ca_CE   28
+#define CP0Ca_DC   27
+#define CP0Ca_PCI  26
+#define CP0Ca_IV   23
+#define CP0Ca_WP   22
+#define CP0Ca_IP    8
+#define CP0Ca_IP_mask 0x0000FF00
+#define CP0Ca_EC    2
+    target_ulong CP0_EPC;
+    int32_t CP0_PRid;
+    int32_t CP0_EBase;
+    int32_t CP0_Config0;
+#define CP0C0_M    31
+#define CP0C0_K23  28
+#define CP0C0_KU   25
+#define CP0C0_MDU  20
+#define CP0C0_MM   17
+#define CP0C0_BM   16
+#define CP0C0_BE   15
+#define CP0C0_AT   13
+#define CP0C0_AR   10
+#define CP0C0_MT   7
+#define CP0C0_VI   3
+#define CP0C0_K0   0
+    int32_t CP0_Config1;
+#define CP0C1_M    31
+#define CP0C1_MMU  25
+#define CP0C1_IS   22
+#define CP0C1_IL   19
+#define CP0C1_IA   16
+#define CP0C1_DS   13
+#define CP0C1_DL   10
+#define CP0C1_DA   7
+#define CP0C1_C2   6
+#define CP0C1_MD   5
+#define CP0C1_PC   4
+#define CP0C1_WR   3
+#define CP0C1_CA   2
+#define CP0C1_EP   1
+#define CP0C1_FP   0
+    int32_t CP0_Config2;
+#define CP0C2_M    31
+#define CP0C2_TU   28
+#define CP0C2_TS   24
+#define CP0C2_TL   20
+#define CP0C2_TA   16
+#define CP0C2_SU   12
+#define CP0C2_SS   8
+#define CP0C2_SL   4
+#define CP0C2_SA   0
+    int32_t CP0_Config3;
+#define CP0C3_M    31
+#define CP0C3_ISA_ON_EXC 16
+#define CP0C3_DSPP 10
+#define CP0C3_LPA  7
+#define CP0C3_VEIC 6
+#define CP0C3_VInt 5
+#define CP0C3_SP   4
+#define CP0C3_MT   2
+#define CP0C3_SM   1
+#define CP0C3_TL   0
+    int32_t CP0_Config6;
+    int32_t CP0_Config7;
+    /* XXX: Maybe make LLAddr per-TC? */
+    target_ulong lladdr;
+    target_ulong llval;
+    target_ulong llnewval;
+    target_ulong llreg;
+    target_ulong CP0_LLAddr_rw_bitmask;
+    int CP0_LLAddr_shift;
+    target_ulong CP0_WatchLo[8];
+    int32_t CP0_WatchHi[8];
+    target_ulong CP0_XContext;
+    int32_t CP0_Framemask;
+    int32_t CP0_Debug;
+#define CP0DB_DBD  31
+#define CP0DB_DM   30
+#define CP0DB_LSNM 28
+#define CP0DB_Doze 27
+#define CP0DB_Halt 26
+#define CP0DB_CNT  25
+#define CP0DB_IBEP 24
+#define CP0DB_DBEP 21
+#define CP0DB_IEXI 20
+#define CP0DB_VER  15
+#define CP0DB_DEC  10
+#define CP0DB_SSt  8
+#define CP0DB_DINT 5
+#define CP0DB_DIB  4
+#define CP0DB_DDBS 3
+#define CP0DB_DDBL 2
+#define CP0DB_DBp  1
+#define CP0DB_DSS  0
+    target_ulong CP0_DEPC;
+    int32_t CP0_Performance0;
+    int32_t CP0_TagLo;
+    int32_t CP0_DataLo;
+    int32_t CP0_TagHi;
+    int32_t CP0_DataHi;
+    target_ulong CP0_ErrorEPC;
+    int32_t CP0_DESAVE;
+    /* We waste some space so we can handle shadow registers like TCs. */
+    TCState tcs[MIPS_SHADOW_SET_MAX];
+    CPUMIPSFPUContext fpus[MIPS_FPU_MAX];
+    /* Qemu */
+    int error_code;
+    uint32_t hflags;    /* CPU State */
+    /* TMASK defines different execution modes */
+#define MIPS_HFLAG_TMASK  0x007FF
+#define MIPS_HFLAG_MODE   0x00007 /* execution modes                    */
+    /* The KSU flags must be the lowest bits in hflags. The flag order
+       must be the same as defined for CP0 Status. This allows to use
+       the bits as the value of mmu_idx. */
+#define MIPS_HFLAG_KSU    0x00003 /* kernel/supervisor/user mode mask   */
+#define MIPS_HFLAG_UM     0x00002 /* user mode flag                     */
+#define MIPS_HFLAG_SM     0x00001 /* supervisor mode flag               */
+#define MIPS_HFLAG_KM     0x00000 /* kernel mode flag                   */
+#define MIPS_HFLAG_DM     0x00004 /* Debug mode                         */
+#define MIPS_HFLAG_64     0x00008 /* 64-bit instructions enabled        */
+#define MIPS_HFLAG_CP0    0x00010 /* CP0 enabled                        */
+#define MIPS_HFLAG_FPU    0x00020 /* FPU enabled                        */
+#define MIPS_HFLAG_F64    0x00040 /* 64-bit FPU enabled                 */
+    /* True if the MIPS IV COP1X instructions can be used.  This also
+       controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S
+       and RSQRT.D.  */
+#define MIPS_HFLAG_COP1X  0x00080 /* COP1X instructions enabled         */
+#define MIPS_HFLAG_RE     0x00100 /* Reversed endianness                */
+#define MIPS_HFLAG_UX     0x00200 /* 64-bit user mode                   */
+#define MIPS_HFLAG_M16    0x00400 /* MIPS16 mode flag                   */
+#define MIPS_HFLAG_M16_SHIFT 10
+    /* If translation is interrupted between the branch instruction and
+     * the delay slot, record what type of branch it is so that we can
+     * resume translation properly.  It might be possible to reduce
+     * this from three bits to two.  */
+#define MIPS_HFLAG_BMASK_BASE  0x03800
+#define MIPS_HFLAG_B      0x00800 /* Unconditional branch               */
+#define MIPS_HFLAG_BC     0x01000 /* Conditional branch                 */
+#define MIPS_HFLAG_BL     0x01800 /* Likely branch                      */
+#define MIPS_HFLAG_BR     0x02000 /* branch to register (can't link TB) */
+    /* Extra flags about the current pending branch.  */
+#define MIPS_HFLAG_BMASK_EXT 0x3C000
+#define MIPS_HFLAG_B16    0x04000 /* branch instruction was 16 bits     */
+#define MIPS_HFLAG_BDS16  0x08000 /* branch requires 16-bit delay slot  */
+#define MIPS_HFLAG_BDS32  0x10000 /* branch requires 32-bit delay slot  */
+#define MIPS_HFLAG_BX     0x20000 /* branch exchanges execution mode    */
+#define MIPS_HFLAG_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
+    target_ulong btarget;        /* Jump / branch target               */
+    target_ulong bcond;          /* Branch condition (if needed)       */
+
+    int SYNCI_Step; /* Address step size for SYNCI */
+    int CCRes; /* Cycle count resolution/divisor */
+    uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
+    uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
+    int insn_flags; /* Supported instruction set */
+
+    target_ulong tls_value; /* For usermode emulation */
+
+    CPU_COMMON
+
+    CPUMIPSMVPContext *mvp;
+#if !defined(CONFIG_USER_ONLY)
+    CPUMIPSTLBContext *tlb;
+#endif
+
+    const mips_def_t *cpu_model;
+    void *irq[8];
+    struct QEMUTimer *timer; /* Internal timer */
+};
+
+#if !defined(CONFIG_USER_ONLY)
+int no_mmu_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot,
+                        target_ulong address, int rw, int access_type);
+int fixed_mmu_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot,
+                           target_ulong address, int rw, int access_type);
+int r4k_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot,
+                     target_ulong address, int rw, int access_type);
+void r4k_helper_tlbwi (void);
+void r4k_helper_tlbwr (void);
+void r4k_helper_tlbp (void);
+void r4k_helper_tlbr (void);
+
+void cpu_unassigned_access(CPUState *env, target_phys_addr_t addr,
+                           int is_write, int is_exec, int unused, int size);
+#endif
+
+void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
+
+#define cpu_init cpu_mips_init
+#define cpu_exec cpu_mips_exec
+#define cpu_gen_code cpu_mips_gen_code
+#define cpu_signal_handler cpu_mips_signal_handler
+#define cpu_list mips_cpu_list
+
+#define CPU_SAVE_VERSION 3
+
+/* MMU modes definitions. We carefully match the indices with our
+   hflags layout. */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _super
+#define MMU_MODE2_SUFFIX _user
+#define MMU_USER_IDX 2
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return env->hflags & MIPS_HFLAG_KSU;
+}
+
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
+}
+
+static inline int cpu_mips_hw_interrupts_pending(CPUState *env)
+{
+    int32_t pending;
+    int32_t status;
+    int r;
+
+    if (!(env->CP0_Status & (1 << CP0St_IE)) ||
+        (env->CP0_Status & (1 << CP0St_EXL)) ||
+        (env->CP0_Status & (1 << CP0St_ERL)) ||
+        (env->hflags & MIPS_HFLAG_DM)) {
+        /* Interrupts are disabled */
+        return 0;
+    }
+
+    pending = env->CP0_Cause & CP0Ca_IP_mask;
+    status = env->CP0_Status & CP0Ca_IP_mask;
+
+    if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
+        /* A MIPS configured with a vectorizing external interrupt controller
+           will feed a vector into the Cause pending lines. The core treats
+           the status lines as a vector level, not as indiviual masks.  */
+        r = pending > status;
+    } else {
+        /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
+           treats the pending lines as individual interrupt lines, the status
+           lines are individual masks.  */
+        r = pending & status;
+    }
+    return r;
+}
+
+#include "cpu-all.h"
+
+/* Memory access type :
+ * may be needed for precise access rights control and precise exceptions.
+ */
+enum {
+    /* 1 bit to define user level / supervisor access */
+    ACCESS_USER  = 0x00,
+    ACCESS_SUPER = 0x01,
+    /* 1 bit to indicate direction */
+    ACCESS_STORE = 0x02,
+    /* Type of instruction that generated the access */
+    ACCESS_CODE  = 0x10, /* Code fetch access                */
+    ACCESS_INT   = 0x20, /* Integer load/store access        */
+    ACCESS_FLOAT = 0x30, /* floating point load/store access */
+};
+
+/* Exceptions */
+enum {
+    EXCP_NONE          = -1,
+    EXCP_RESET         = 0,
+    EXCP_SRESET,
+    EXCP_DSS,
+    EXCP_DINT,
+    EXCP_DDBL,
+    EXCP_DDBS,
+    EXCP_NMI,
+    EXCP_MCHECK,
+    EXCP_EXT_INTERRUPT, /* 8 */
+    EXCP_DFWATCH,
+    EXCP_DIB,
+    EXCP_IWATCH,
+    EXCP_AdEL,
+    EXCP_AdES,
+    EXCP_TLBF,
+    EXCP_IBE,
+    EXCP_DBp, /* 16 */
+    EXCP_SYSCALL,
+    EXCP_BREAK,
+    EXCP_CpU,
+    EXCP_RI,
+    EXCP_OVERFLOW,
+    EXCP_TRAP,
+    EXCP_FPE,
+    EXCP_DWATCH, /* 24 */
+    EXCP_LTLBL,
+    EXCP_TLBL,
+    EXCP_TLBS,
+    EXCP_DBE,
+    EXCP_THREAD,
+    EXCP_MDMX,
+    EXCP_C2E,
+    EXCP_CACHE, /* 32 */
+
+    EXCP_LAST = EXCP_CACHE,
+};
+/* Dummy exception for conditional stores.  */
+#define EXCP_SC 0x100
+
+int cpu_mips_exec(CPUMIPSState *s);
+CPUMIPSState *cpu_mips_init(const char *cpu_model);
+//~ uint32_t cpu_mips_get_clock (void);
+int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
+
+/* mips_timer.c */
+uint32_t cpu_mips_get_random (CPUState *env);
+uint32_t cpu_mips_get_count (CPUState *env);
+void cpu_mips_store_count (CPUState *env, uint32_t value);
+void cpu_mips_store_compare (CPUState *env, uint32_t value);
+void cpu_mips_start_count(CPUState *env);
+void cpu_mips_stop_count(CPUState *env);
+
+/* mips_int.c */
+void cpu_mips_soft_irq(CPUState *env, int irq, int level);
+
+/* helper.c */
+int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
+void do_interrupt (CPUState *env);
+#if !defined(CONFIG_USER_ONLY)
+void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
+target_phys_addr_t cpu_mips_translate_address (CPUState *env, target_ulong address,
+		                               int rw);
+#endif
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->active_tc.PC;
+    *cs_base = 0;
+    *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+    env->tls_value = newtls;
+}
+
+static inline int cpu_has_work(CPUState *env)
+{
+    int has_work = 0;
+
+    /* It is implementation dependent if non-enabled interrupts
+       wake-up the CPU, however most of the implementations only
+       check for interrupts that can be taken. */
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        cpu_mips_hw_interrupts_pending(env)) {
+        has_work = 1;
+    }
+
+    return has_work;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->active_tc.PC = tb->pc;
+    env->hflags &= ~MIPS_HFLAG_BMASK;
+    env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
+}
+
+#endif /* !defined (__MIPS_CPU_H__) */
diff --git a/qemu-0.15.x/target-mips/exec.h b/qemu-0.15.x/target-mips/exec.h
new file mode 100644
index 0000000..e787e9a
--- /dev/null
+++ b/qemu-0.15.x/target-mips/exec.h
@@ -0,0 +1,60 @@
+#if !defined(__QEMU_MIPS_EXEC_H__)
+#define __QEMU_MIPS_EXEC_H__
+
+//#define DEBUG_OP
+
+#include "config.h"
+#include "mips-defs.h"
+#include "dyngen-exec.h"
+#include "cpu-defs.h"
+
+register struct CPUMIPSState *env asm(AREG0);
+
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+static inline void compute_hflags(CPUState *env)
+{
+    env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
+                     MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
+                     MIPS_HFLAG_UX);
+    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+        !(env->CP0_Status & (1 << CP0St_ERL)) &&
+        !(env->hflags & MIPS_HFLAG_DM)) {
+        env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
+    }
+#if defined(TARGET_MIPS64)
+    if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
+        (env->CP0_Status & (1 << CP0St_PX)) ||
+        (env->CP0_Status & (1 << CP0St_UX)))
+        env->hflags |= MIPS_HFLAG_64;
+    if (env->CP0_Status & (1 << CP0St_UX))
+        env->hflags |= MIPS_HFLAG_UX;
+#endif
+    if ((env->CP0_Status & (1 << CP0St_CU0)) ||
+        !(env->hflags & MIPS_HFLAG_KSU))
+        env->hflags |= MIPS_HFLAG_CP0;
+    if (env->CP0_Status & (1 << CP0St_CU1))
+        env->hflags |= MIPS_HFLAG_FPU;
+    if (env->CP0_Status & (1 << CP0St_FR))
+        env->hflags |= MIPS_HFLAG_F64;
+    if (env->insn_flags & ISA_MIPS32R2) {
+        if (env->active_fpu.fcr0 & (1 << FCR0_F64))
+            env->hflags |= MIPS_HFLAG_COP1X;
+    } else if (env->insn_flags & ISA_MIPS32) {
+        if (env->hflags & MIPS_HFLAG_64)
+            env->hflags |= MIPS_HFLAG_COP1X;
+    } else if (env->insn_flags & ISA_MIPS4) {
+        /* All supported MIPS IV CPUs use the XX (CU3) to enable
+           and disable the MIPS IV extensions to the MIPS III ISA.
+           Some other MIPS IV CPUs ignore the bit, so the check here
+           would be too restrictive for them.  */
+        if (env->CP0_Status & (1 << CP0St_CU3))
+            env->hflags |= MIPS_HFLAG_COP1X;
+    }
+}
+
+#endif /* !defined(__QEMU_MIPS_EXEC_H__) */
diff --git a/qemu-0.15.x/target-mips/helper.c b/qemu-0.15.x/target-mips/helper.c
new file mode 100644
index 0000000..ecf6182
--- /dev/null
+++ b/qemu-0.15.x/target-mips/helper.c
@@ -0,0 +1,693 @@
+/*
+ *  MIPS emulation helpers for qemu.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "cpu.h"
+
+enum {
+    TLBRET_DIRTY = -4,
+    TLBRET_INVALID = -3,
+    TLBRET_NOMATCH = -2,
+    TLBRET_BADADDR = -1,
+    TLBRET_MATCH = 0
+};
+
+#if !defined(CONFIG_USER_ONLY)
+
+/* no MMU emulation */
+int no_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot,
+                        target_ulong address, int rw, int access_type)
+{
+    *physical = address;
+    *prot = PAGE_READ | PAGE_WRITE;
+    return TLBRET_MATCH;
+}
+
+/* fixed mapping MMU emulation */
+int fixed_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot,
+                           target_ulong address, int rw, int access_type)
+{
+    if (address <= (int32_t)0x7FFFFFFFUL) {
+        if (!(env->CP0_Status & (1 << CP0St_ERL)))
+            *physical = address + 0x40000000UL;
+        else
+            *physical = address;
+    } else if (address <= (int32_t)0xBFFFFFFFUL)
+        *physical = address & 0x1FFFFFFF;
+    else
+        *physical = address;
+
+    *prot = PAGE_READ | PAGE_WRITE;
+    return TLBRET_MATCH;
+}
+
+/* MIPS32/MIPS64 R4000-style MMU emulation */
+int r4k_map_address (CPUState *env, target_phys_addr_t *physical, int *prot,
+                     target_ulong address, int rw, int access_type)
+{
+    uint8_t ASID = env->CP0_EntryHi & 0xFF;
+    int i;
+
+    for (i = 0; i < env->tlb->tlb_in_use; i++) {
+        r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
+        /* 1k pages are not supported. */
+        target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+        target_ulong tag = address & ~mask;
+        target_ulong VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+        tag &= env->SEGMask;
+#endif
+
+        /* Check ASID, virtual page number & size */
+        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+            /* TLB match */
+            int n = !!(address & mask & ~(mask >> 1));
+            /* Check access rights */
+            if (!(n ? tlb->V1 : tlb->V0))
+                return TLBRET_INVALID;
+            if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
+                *physical = tlb->PFN[n] | (address & (mask >> 1));
+                *prot = PAGE_READ;
+                if (n ? tlb->D1 : tlb->D0)
+                    *prot |= PAGE_WRITE;
+                return TLBRET_MATCH;
+            }
+            return TLBRET_DIRTY;
+        }
+    }
+    return TLBRET_NOMATCH;
+}
+
+static int get_physical_address (CPUState *env, target_phys_addr_t *physical,
+                                int *prot, target_ulong address,
+                                int rw, int access_type)
+{
+    /* User mode can only access useg/xuseg */
+    int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
+    int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
+    int kernel_mode = !user_mode && !supervisor_mode;
+#if defined(TARGET_MIPS64)
+    int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+    int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+    int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+#endif
+    int ret = TLBRET_MATCH;
+
+#if 0
+    qemu_log("user mode %d h %08x\n", user_mode, env->hflags);
+#endif
+
+    if (address <= (int32_t)0x7FFFFFFFUL) {
+        /* useg */
+        if (env->CP0_Status & (1 << CP0St_ERL)) {
+            *physical = address & 0xFFFFFFFF;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        }
+#if defined(TARGET_MIPS64)
+    } else if (address < 0x4000000000000000ULL) {
+        /* xuseg */
+        if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else if (address < 0x8000000000000000ULL) {
+        /* xsseg */
+        if ((supervisor_mode || kernel_mode) &&
+            SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else if (address < 0xC000000000000000ULL) {
+        /* xkphys */
+        if (kernel_mode && KX &&
+            (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
+            *physical = address & env->PAMask;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else if (address < 0xFFFFFFFF80000000ULL) {
+        /* xkseg */
+        if (kernel_mode && KX &&
+            address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+#endif
+    } else if (address < (int32_t)0xA0000000UL) {
+        /* kseg0 */
+        if (kernel_mode) {
+            *physical = address - (int32_t)0x80000000UL;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else if (address < (int32_t)0xC0000000UL) {
+        /* kseg1 */
+        if (kernel_mode) {
+            *physical = address - (int32_t)0xA0000000UL;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else if (address < (int32_t)0xE0000000UL) {
+        /* sseg (kseg2) */
+        if (supervisor_mode || kernel_mode) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    } else {
+        /* kseg3 */
+        /* XXX: debug segment is not emulated */
+        if (kernel_mode) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
+    }
+#if 0
+    qemu_log(TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
+            address, rw, access_type, *physical, *prot, ret);
+#endif
+
+    return ret;
+}
+#endif
+
+static void raise_mmu_exception(CPUState *env, target_ulong address,
+                                int rw, int tlb_error)
+{
+    int exception = 0, error_code = 0;
+
+    switch (tlb_error) {
+    default:
+    case TLBRET_BADADDR:
+        /* Reference to kernel address from user mode or supervisor mode */
+        /* Reference to supervisor address from user mode */
+        if (rw)
+            exception = EXCP_AdES;
+        else
+            exception = EXCP_AdEL;
+        break;
+    case TLBRET_NOMATCH:
+        /* No TLB match for a mapped address */
+        if (rw)
+            exception = EXCP_TLBS;
+        else
+            exception = EXCP_TLBL;
+        error_code = 1;
+        break;
+    case TLBRET_INVALID:
+        /* TLB match with no valid bit */
+        if (rw)
+            exception = EXCP_TLBS;
+        else
+            exception = EXCP_TLBL;
+        break;
+    case TLBRET_DIRTY:
+        /* TLB match but 'D' bit is cleared */
+        exception = EXCP_LTLBL;
+        break;
+
+    }
+    /* Raise exception */
+    env->CP0_BadVAddr = address;
+    env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
+                       ((address >> 9) & 0x007ffff0);
+    env->CP0_EntryHi =
+        (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
+#if defined(TARGET_MIPS64)
+    env->CP0_EntryHi &= env->SEGMask;
+    env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
+                        ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
+                        ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
+#endif
+    env->exception_index = exception;
+    env->error_code = error_code;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_phys_addr_t phys_addr;
+    int prot;
+
+    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+        return -1;
+    return phys_addr;
+}
+#endif
+
+int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+#if !defined(CONFIG_USER_ONLY)
+    target_phys_addr_t physical;
+    int prot;
+    int access_type;
+#endif
+    int ret = 0;
+
+#if 0
+    log_cpu_state(env, 0);
+#endif
+    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
+              __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
+
+    rw &= 1;
+
+    /* data access */
+#if !defined(CONFIG_USER_ONLY)
+    /* XXX: put correct access by using cpu_restore_state()
+       correctly */
+    access_type = ACCESS_INT;
+    ret = get_physical_address(env, &physical, &prot,
+                               address, rw, access_type);
+    qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n",
+              __func__, address, ret, physical, prot);
+    if (ret == TLBRET_MATCH) {
+        tlb_set_page(env, address & TARGET_PAGE_MASK,
+                     physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
+                     mmu_idx, TARGET_PAGE_SIZE);
+        ret = 0;
+    } else if (ret < 0)
+#endif
+    {
+        raise_mmu_exception(env, address, rw, ret);
+        ret = 1;
+    }
+
+    return ret;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+target_phys_addr_t cpu_mips_translate_address(CPUState *env, target_ulong address, int rw)
+{
+    target_phys_addr_t physical;
+    int prot;
+    int access_type;
+    int ret = 0;
+
+    rw &= 1;
+
+    /* data access */
+    access_type = ACCESS_INT;
+    ret = get_physical_address(env, &physical, &prot,
+                               address, rw, access_type);
+    if (ret != TLBRET_MATCH) {
+        raise_mmu_exception(env, address, rw, ret);
+        return -1LL;
+    } else {
+        return physical;
+    }
+}
+#endif
+
+static const char * const excp_names[EXCP_LAST + 1] = {
+    [EXCP_RESET] = "reset",
+    [EXCP_SRESET] = "soft reset",
+    [EXCP_DSS] = "debug single step",
+    [EXCP_DINT] = "debug interrupt",
+    [EXCP_NMI] = "non-maskable interrupt",
+    [EXCP_MCHECK] = "machine check",
+    [EXCP_EXT_INTERRUPT] = "interrupt",
+    [EXCP_DFWATCH] = "deferred watchpoint",
+    [EXCP_DIB] = "debug instruction breakpoint",
+    [EXCP_IWATCH] = "instruction fetch watchpoint",
+    [EXCP_AdEL] = "address error load",
+    [EXCP_AdES] = "address error store",
+    [EXCP_TLBF] = "TLB refill",
+    [EXCP_IBE] = "instruction bus error",
+    [EXCP_DBp] = "debug breakpoint",
+    [EXCP_SYSCALL] = "syscall",
+    [EXCP_BREAK] = "break",
+    [EXCP_CpU] = "coprocessor unusable",
+    [EXCP_RI] = "reserved instruction",
+    [EXCP_OVERFLOW] = "arithmetic overflow",
+    [EXCP_TRAP] = "trap",
+    [EXCP_FPE] = "floating point",
+    [EXCP_DDBS] = "debug data break store",
+    [EXCP_DWATCH] = "data watchpoint",
+    [EXCP_LTLBL] = "TLB modify",
+    [EXCP_TLBL] = "TLB load",
+    [EXCP_TLBS] = "TLB store",
+    [EXCP_DBE] = "data bus error",
+    [EXCP_DDBL] = "debug data break load",
+    [EXCP_THREAD] = "thread",
+    [EXCP_MDMX] = "MDMX",
+    [EXCP_C2E] = "precise coprocessor 2",
+    [EXCP_CACHE] = "cache error",
+};
+
+#if !defined(CONFIG_USER_ONLY)
+static target_ulong exception_resume_pc (CPUState *env)
+{
+    target_ulong bad_pc;
+    target_ulong isa_mode;
+
+    isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
+    bad_pc = env->active_tc.PC | isa_mode;
+    if (env->hflags & MIPS_HFLAG_BMASK) {
+        /* If the exception was raised from a delay slot, come back to
+           the jump.  */
+        bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
+    }
+
+    return bad_pc;
+}
+
+static void set_hflags_for_handler (CPUState *env)
+{
+    /* Exception handlers are entered in 32-bit mode.  */
+    env->hflags &= ~(MIPS_HFLAG_M16);
+    /* ...except that microMIPS lets you choose.  */
+    if (env->insn_flags & ASE_MICROMIPS) {
+        env->hflags |= (!!(env->CP0_Config3
+                           & (1 << CP0C3_ISA_ON_EXC))
+                        << MIPS_HFLAG_M16_SHIFT);
+    }
+}
+#endif
+
+void do_interrupt (CPUState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    target_ulong offset;
+    int cause = -1;
+    const char *name;
+
+    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
+        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
+            name = "unknown";
+        else
+            name = excp_names[env->exception_index];
+
+        qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
+                 __func__, env->active_tc.PC, env->CP0_EPC, name);
+    }
+    if (env->exception_index == EXCP_EXT_INTERRUPT &&
+        (env->hflags & MIPS_HFLAG_DM))
+        env->exception_index = EXCP_DINT;
+    offset = 0x180;
+    switch (env->exception_index) {
+    case EXCP_DSS:
+        env->CP0_Debug |= 1 << CP0DB_DSS;
+        /* Debug single step cannot be raised inside a delay slot and
+           resume will always occur on the next instruction
+           (but we assume the pc has always been updated during
+           code translation). */
+        env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
+        goto enter_debug_mode;
+    case EXCP_DINT:
+        env->CP0_Debug |= 1 << CP0DB_DINT;
+        goto set_DEPC;
+    case EXCP_DIB:
+        env->CP0_Debug |= 1 << CP0DB_DIB;
+        goto set_DEPC;
+    case EXCP_DBp:
+        env->CP0_Debug |= 1 << CP0DB_DBp;
+        goto set_DEPC;
+    case EXCP_DDBS:
+        env->CP0_Debug |= 1 << CP0DB_DDBS;
+        goto set_DEPC;
+    case EXCP_DDBL:
+        env->CP0_Debug |= 1 << CP0DB_DDBL;
+    set_DEPC:
+        env->CP0_DEPC = exception_resume_pc(env);
+        env->hflags &= ~MIPS_HFLAG_BMASK;
+ enter_debug_mode:
+        env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+        env->hflags &= ~(MIPS_HFLAG_KSU);
+        /* EJTAG probe trap enable is not implemented... */
+        if (!(env->CP0_Status & (1 << CP0St_EXL)))
+            env->CP0_Cause &= ~(1 << CP0Ca_BD);
+        env->active_tc.PC = (int32_t)0xBFC00480;
+        set_hflags_for_handler(env);
+        break;
+    case EXCP_RESET:
+        cpu_reset(env);
+        break;
+    case EXCP_SRESET:
+        env->CP0_Status |= (1 << CP0St_SR);
+        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
+        goto set_error_EPC;
+    case EXCP_NMI:
+        env->CP0_Status |= (1 << CP0St_NMI);
+ set_error_EPC:
+        env->CP0_ErrorEPC = exception_resume_pc(env);
+        env->hflags &= ~MIPS_HFLAG_BMASK;
+        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
+        env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+        env->hflags &= ~(MIPS_HFLAG_KSU);
+        if (!(env->CP0_Status & (1 << CP0St_EXL)))
+            env->CP0_Cause &= ~(1 << CP0Ca_BD);
+        env->active_tc.PC = (int32_t)0xBFC00000;
+        set_hflags_for_handler(env);
+        break;
+    case EXCP_EXT_INTERRUPT:
+        cause = 0;
+        if (env->CP0_Cause & (1 << CP0Ca_IV))
+            offset = 0x200;
+
+        if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) {
+            /* Vectored Interrupts.  */
+            unsigned int spacing;
+            unsigned int vector;
+            unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
+
+            /* Compute the Vector Spacing.  */
+            spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
+            spacing <<= 5;
+
+            if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
+                /* For VInt mode, the MIPS computes the vector internally.  */
+                for (vector = 0; vector < 8; vector++) {
+                    if (pending & 1) {
+                        /* Found it.  */
+                        break;
+                    }
+                    pending >>= 1;
+                }
+            } else {
+                /* For VEIC mode, the external interrupt controller feeds the
+                   vector throught the CP0Cause IP lines.  */
+                vector = pending;
+            }
+            offset = 0x200 + vector * spacing;
+        }
+        goto set_EPC;
+    case EXCP_LTLBL:
+        cause = 1;
+        goto set_EPC;
+    case EXCP_TLBL:
+        cause = 2;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#if defined(TARGET_MIPS64)
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+
+            if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
+                (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
+        goto set_EPC;
+    case EXCP_TLBS:
+        cause = 3;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#if defined(TARGET_MIPS64)
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+
+            if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
+                (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
+        goto set_EPC;
+    case EXCP_AdEL:
+        cause = 4;
+        goto set_EPC;
+    case EXCP_AdES:
+        cause = 5;
+        goto set_EPC;
+    case EXCP_IBE:
+        cause = 6;
+        goto set_EPC;
+    case EXCP_DBE:
+        cause = 7;
+        goto set_EPC;
+    case EXCP_SYSCALL:
+        cause = 8;
+        goto set_EPC;
+    case EXCP_BREAK:
+        cause = 9;
+        goto set_EPC;
+    case EXCP_RI:
+        cause = 10;
+        goto set_EPC;
+    case EXCP_CpU:
+        cause = 11;
+        env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
+                         (env->error_code << CP0Ca_CE);
+        goto set_EPC;
+    case EXCP_OVERFLOW:
+        cause = 12;
+        goto set_EPC;
+    case EXCP_TRAP:
+        cause = 13;
+        goto set_EPC;
+    case EXCP_FPE:
+        cause = 15;
+        goto set_EPC;
+    case EXCP_C2E:
+        cause = 18;
+        goto set_EPC;
+    case EXCP_MDMX:
+        cause = 22;
+        goto set_EPC;
+    case EXCP_DWATCH:
+        cause = 23;
+        /* XXX: TODO: manage defered watch exceptions */
+        goto set_EPC;
+    case EXCP_MCHECK:
+        cause = 24;
+        goto set_EPC;
+    case EXCP_THREAD:
+        cause = 25;
+        goto set_EPC;
+    case EXCP_CACHE:
+        cause = 30;
+        if (env->CP0_Status & (1 << CP0St_BEV)) {
+            offset = 0x100;
+        } else {
+            offset = 0x20000100;
+        }
+ set_EPC:
+        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
+            env->CP0_EPC = exception_resume_pc(env);
+            if (env->hflags & MIPS_HFLAG_BMASK) {
+                env->CP0_Cause |= (1 << CP0Ca_BD);
+            } else {
+                env->CP0_Cause &= ~(1 << CP0Ca_BD);
+            }
+            env->CP0_Status |= (1 << CP0St_EXL);
+            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+            env->hflags &= ~(MIPS_HFLAG_KSU);
+        }
+        env->hflags &= ~MIPS_HFLAG_BMASK;
+        if (env->CP0_Status & (1 << CP0St_BEV)) {
+            env->active_tc.PC = (int32_t)0xBFC00200;
+        } else {
+            env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
+        }
+        env->active_tc.PC += offset;
+        set_hflags_for_handler(env);
+        env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
+        break;
+    default:
+        qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
+        printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
+        exit(1);
+    }
+    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
+        qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
+                "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
+                __func__, env->active_tc.PC, env->CP0_EPC, cause,
+                env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
+                env->CP0_DEPC);
+    }
+#endif
+    env->exception_index = EXCP_NONE;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
+{
+    r4k_tlb_t *tlb;
+    target_ulong addr;
+    target_ulong end;
+    uint8_t ASID = env->CP0_EntryHi & 0xFF;
+    target_ulong mask;
+
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
+    /* The qemu TLB is flushed when the ASID changes, so no need to
+       flush these entries again.  */
+    if (tlb->G == 0 && tlb->ASID != ASID) {
+        return;
+    }
+
+    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
+        /* For tlbwr, we can shadow the discarded entry into
+           a new (fake) TLB entry, as long as the guest can not
+           tell that it's there.  */
+        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
+        env->tlb->tlb_in_use++;
+        return;
+    }
+
+    /* 1k pages are not supported. */
+    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+    if (tlb->V0) {
+        addr = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
+        end = addr | (mask >> 1);
+        while (addr < end) {
+            tlb_flush_page (env, addr);
+            addr += TARGET_PAGE_SIZE;
+        }
+    }
+    if (tlb->V1) {
+        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
+#if defined(TARGET_MIPS64)
+        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
+        end = addr | mask;
+        while (addr - 1 < end) {
+            tlb_flush_page (env, addr);
+            addr += TARGET_PAGE_SIZE;
+        }
+    }
+}
+#endif
diff --git a/qemu-0.15.x/target-mips/helper.h b/qemu-0.15.x/target-mips/helper.h
new file mode 100644
index 0000000..297ab64
--- /dev/null
+++ b/qemu-0.15.x/target-mips/helper.h
@@ -0,0 +1,290 @@
+#include "def-helper.h"
+
+DEF_HELPER_2(raise_exception_err, void, i32, int)
+DEF_HELPER_1(raise_exception, void, i32)
+
+#ifdef TARGET_MIPS64
+DEF_HELPER_3(ldl, tl, tl, tl, int)
+DEF_HELPER_3(ldr, tl, tl, tl, int)
+DEF_HELPER_3(sdl, void, tl, tl, int)
+DEF_HELPER_3(sdr, void, tl, tl, int)
+#endif
+DEF_HELPER_3(lwl, tl, tl, tl, int)
+DEF_HELPER_3(lwr, tl, tl, tl, int)
+DEF_HELPER_3(swl, void, tl, tl, int)
+DEF_HELPER_3(swr, void, tl, tl, int)
+
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(ll, tl, tl, int)
+DEF_HELPER_3(sc, tl, tl, tl, int)
+#ifdef TARGET_MIPS64
+DEF_HELPER_2(lld, tl, tl, int)
+DEF_HELPER_3(scd, tl, tl, tl, int)
+#endif
+#endif
+
+DEF_HELPER_FLAGS_1(clo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+#ifdef TARGET_MIPS64
+DEF_HELPER_FLAGS_1(dclo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(dclz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_2(dmult, void, tl, tl)
+DEF_HELPER_2(dmultu, void, tl, tl)
+#endif
+
+DEF_HELPER_2(muls, tl, tl, tl)
+DEF_HELPER_2(mulsu, tl, tl, tl)
+DEF_HELPER_2(macc, tl, tl, tl)
+DEF_HELPER_2(maccu, tl, tl, tl)
+DEF_HELPER_2(msac, tl, tl, tl)
+DEF_HELPER_2(msacu, tl, tl, tl)
+DEF_HELPER_2(mulhi, tl, tl, tl)
+DEF_HELPER_2(mulhiu, tl, tl, tl)
+DEF_HELPER_2(mulshi, tl, tl, tl)
+DEF_HELPER_2(mulshiu, tl, tl, tl)
+DEF_HELPER_2(macchi, tl, tl, tl)
+DEF_HELPER_2(macchiu, tl, tl, tl)
+DEF_HELPER_2(msachi, tl, tl, tl)
+DEF_HELPER_2(msachiu, tl, tl, tl)
+
+#ifndef CONFIG_USER_ONLY
+/* CP0 helpers */
+DEF_HELPER_0(mfc0_mvpcontrol, tl)
+DEF_HELPER_0(mfc0_mvpconf0, tl)
+DEF_HELPER_0(mfc0_mvpconf1, tl)
+DEF_HELPER_0(mfc0_random, tl)
+DEF_HELPER_0(mfc0_tcstatus, tl)
+DEF_HELPER_0(mftc0_tcstatus, tl)
+DEF_HELPER_0(mfc0_tcbind, tl)
+DEF_HELPER_0(mftc0_tcbind, tl)
+DEF_HELPER_0(mfc0_tcrestart, tl)
+DEF_HELPER_0(mftc0_tcrestart, tl)
+DEF_HELPER_0(mfc0_tchalt, tl)
+DEF_HELPER_0(mftc0_tchalt, tl)
+DEF_HELPER_0(mfc0_tccontext, tl)
+DEF_HELPER_0(mftc0_tccontext, tl)
+DEF_HELPER_0(mfc0_tcschedule, tl)
+DEF_HELPER_0(mftc0_tcschedule, tl)
+DEF_HELPER_0(mfc0_tcschefback, tl)
+DEF_HELPER_0(mftc0_tcschefback, tl)
+DEF_HELPER_0(mfc0_count, tl)
+DEF_HELPER_0(mftc0_entryhi, tl)
+DEF_HELPER_0(mftc0_status, tl)
+DEF_HELPER_0(mfc0_lladdr, tl)
+DEF_HELPER_1(mfc0_watchlo, tl, i32)
+DEF_HELPER_1(mfc0_watchhi, tl, i32)
+DEF_HELPER_0(mfc0_debug, tl)
+DEF_HELPER_0(mftc0_debug, tl)
+#ifdef TARGET_MIPS64
+DEF_HELPER_0(dmfc0_tcrestart, tl)
+DEF_HELPER_0(dmfc0_tchalt, tl)
+DEF_HELPER_0(dmfc0_tccontext, tl)
+DEF_HELPER_0(dmfc0_tcschedule, tl)
+DEF_HELPER_0(dmfc0_tcschefback, tl)
+DEF_HELPER_0(dmfc0_lladdr, tl)
+DEF_HELPER_1(dmfc0_watchlo, tl, i32)
+#endif /* TARGET_MIPS64 */
+
+DEF_HELPER_1(mtc0_index, void, tl)
+DEF_HELPER_1(mtc0_mvpcontrol, void, tl)
+DEF_HELPER_1(mtc0_vpecontrol, void, tl)
+DEF_HELPER_1(mtc0_vpeconf0, void, tl)
+DEF_HELPER_1(mtc0_vpeconf1, void, tl)
+DEF_HELPER_1(mtc0_yqmask, void, tl)
+DEF_HELPER_1(mtc0_vpeopt, void, tl)
+DEF_HELPER_1(mtc0_entrylo0, void, tl)
+DEF_HELPER_1(mtc0_tcstatus, void, tl)
+DEF_HELPER_1(mttc0_tcstatus, void, tl)
+DEF_HELPER_1(mtc0_tcbind, void, tl)
+DEF_HELPER_1(mttc0_tcbind, void, tl)
+DEF_HELPER_1(mtc0_tcrestart, void, tl)
+DEF_HELPER_1(mttc0_tcrestart, void, tl)
+DEF_HELPER_1(mtc0_tchalt, void, tl)
+DEF_HELPER_1(mttc0_tchalt, void, tl)
+DEF_HELPER_1(mtc0_tccontext, void, tl)
+DEF_HELPER_1(mttc0_tccontext, void, tl)
+DEF_HELPER_1(mtc0_tcschedule, void, tl)
+DEF_HELPER_1(mttc0_tcschedule, void, tl)
+DEF_HELPER_1(mtc0_tcschefback, void, tl)
+DEF_HELPER_1(mttc0_tcschefback, void, tl)
+DEF_HELPER_1(mtc0_entrylo1, void, tl)
+DEF_HELPER_1(mtc0_context, void, tl)
+DEF_HELPER_1(mtc0_pagemask, void, tl)
+DEF_HELPER_1(mtc0_pagegrain, void, tl)
+DEF_HELPER_1(mtc0_wired, void, tl)
+DEF_HELPER_1(mtc0_srsconf0, void, tl)
+DEF_HELPER_1(mtc0_srsconf1, void, tl)
+DEF_HELPER_1(mtc0_srsconf2, void, tl)
+DEF_HELPER_1(mtc0_srsconf3, void, tl)
+DEF_HELPER_1(mtc0_srsconf4, void, tl)
+DEF_HELPER_1(mtc0_hwrena, void, tl)
+DEF_HELPER_1(mtc0_count, void, tl)
+DEF_HELPER_1(mtc0_entryhi, void, tl)
+DEF_HELPER_1(mttc0_entryhi, void, tl)
+DEF_HELPER_1(mtc0_compare, void, tl)
+DEF_HELPER_1(mtc0_status, void, tl)
+DEF_HELPER_1(mttc0_status, void, tl)
+DEF_HELPER_1(mtc0_intctl, void, tl)
+DEF_HELPER_1(mtc0_srsctl, void, tl)
+DEF_HELPER_1(mtc0_cause, void, tl)
+DEF_HELPER_1(mtc0_ebase, void, tl)
+DEF_HELPER_1(mtc0_config0, void, tl)
+DEF_HELPER_1(mtc0_config2, void, tl)
+DEF_HELPER_1(mtc0_lladdr, void, tl)
+DEF_HELPER_2(mtc0_watchlo, void, tl, i32)
+DEF_HELPER_2(mtc0_watchhi, void, tl, i32)
+DEF_HELPER_1(mtc0_xcontext, void, tl)
+DEF_HELPER_1(mtc0_framemask, void, tl)
+DEF_HELPER_1(mtc0_debug, void, tl)
+DEF_HELPER_1(mttc0_debug, void, tl)
+DEF_HELPER_1(mtc0_performance0, void, tl)
+DEF_HELPER_1(mtc0_taglo, void, tl)
+DEF_HELPER_1(mtc0_datalo, void, tl)
+DEF_HELPER_1(mtc0_taghi, void, tl)
+DEF_HELPER_1(mtc0_datahi, void, tl)
+
+/* MIPS MT functions */
+DEF_HELPER_1(mftgpr, tl, i32);
+DEF_HELPER_1(mftlo, tl, i32)
+DEF_HELPER_1(mfthi, tl, i32)
+DEF_HELPER_1(mftacx, tl, i32)
+DEF_HELPER_0(mftdsp, tl)
+DEF_HELPER_2(mttgpr, void, tl, i32)
+DEF_HELPER_2(mttlo, void, tl, i32)
+DEF_HELPER_2(mtthi, void, tl, i32)
+DEF_HELPER_2(mttacx, void, tl, i32)
+DEF_HELPER_1(mttdsp, void, tl)
+DEF_HELPER_0(dmt, tl)
+DEF_HELPER_0(emt, tl)
+DEF_HELPER_0(dvpe, tl)
+DEF_HELPER_0(evpe, tl)
+#endif /* !CONFIG_USER_ONLY */
+
+/* microMIPS functions */
+DEF_HELPER_3(lwm, void, tl, tl, i32);
+DEF_HELPER_3(swm, void, tl, tl, i32);
+#ifdef TARGET_MIPS64
+DEF_HELPER_3(ldm, void, tl, tl, i32);
+DEF_HELPER_3(sdm, void, tl, tl, i32);
+#endif
+
+DEF_HELPER_2(fork, void, tl, tl)
+DEF_HELPER_1(yield, tl, tl)
+
+/* CP1 functions */
+DEF_HELPER_1(cfc1, tl, i32)
+DEF_HELPER_2(ctc1, void, tl, i32)
+
+DEF_HELPER_1(float_cvtd_s, i64, i32)
+DEF_HELPER_1(float_cvtd_w, i64, i32)
+DEF_HELPER_1(float_cvtd_l, i64, i64)
+DEF_HELPER_1(float_cvtl_d, i64, i64)
+DEF_HELPER_1(float_cvtl_s, i64, i32)
+DEF_HELPER_1(float_cvtps_pw, i64, i64)
+DEF_HELPER_1(float_cvtpw_ps, i64, i64)
+DEF_HELPER_1(float_cvts_d, i32, i64)
+DEF_HELPER_1(float_cvts_w, i32, i32)
+DEF_HELPER_1(float_cvts_l, i32, i64)
+DEF_HELPER_1(float_cvts_pl, i32, i32)
+DEF_HELPER_1(float_cvts_pu, i32, i32)
+DEF_HELPER_1(float_cvtw_s, i32, i32)
+DEF_HELPER_1(float_cvtw_d, i32, i64)
+
+DEF_HELPER_2(float_addr_ps, i64, i64, i64)
+DEF_HELPER_2(float_mulr_ps, i64, i64, i64)
+
+#define FOP_PROTO(op)                       \
+DEF_HELPER_1(float_ ## op ## l_s, i64, i32) \
+DEF_HELPER_1(float_ ## op ## l_d, i64, i64) \
+DEF_HELPER_1(float_ ## op ## w_s, i32, i32) \
+DEF_HELPER_1(float_ ## op ## w_d, i32, i64)
+FOP_PROTO(round)
+FOP_PROTO(trunc)
+FOP_PROTO(ceil)
+FOP_PROTO(floor)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                       \
+DEF_HELPER_1(float_ ## op ## _s, i32, i32)  \
+DEF_HELPER_1(float_ ## op ## _d, i64, i64)
+FOP_PROTO(sqrt)
+FOP_PROTO(rsqrt)
+FOP_PROTO(recip)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                       \
+DEF_HELPER_1(float_ ## op ## _s, i32, i32)  \
+DEF_HELPER_1(float_ ## op ## _d, i64, i64)  \
+DEF_HELPER_1(float_ ## op ## _ps, i64, i64)
+FOP_PROTO(abs)
+FOP_PROTO(chs)
+FOP_PROTO(recip1)
+FOP_PROTO(rsqrt1)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                             \
+DEF_HELPER_2(float_ ## op ## _s, i32, i32, i32)   \
+DEF_HELPER_2(float_ ## op ## _d, i64, i64, i64)   \
+DEF_HELPER_2(float_ ## op ## _ps, i64, i64, i64)
+FOP_PROTO(add)
+FOP_PROTO(sub)
+FOP_PROTO(mul)
+FOP_PROTO(div)
+FOP_PROTO(recip2)
+FOP_PROTO(rsqrt2)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                                 \
+DEF_HELPER_3(float_ ## op ## _s, i32, i32, i32, i32)  \
+DEF_HELPER_3(float_ ## op ## _d, i64, i64, i64, i64)  \
+DEF_HELPER_3(float_ ## op ## _ps, i64, i64, i64, i64)
+FOP_PROTO(muladd)
+FOP_PROTO(mulsub)
+FOP_PROTO(nmuladd)
+FOP_PROTO(nmulsub)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                               \
+DEF_HELPER_3(cmp_d_ ## op, void, i64, i64, int)     \
+DEF_HELPER_3(cmpabs_d_ ## op, void, i64, i64, int)  \
+DEF_HELPER_3(cmp_s_ ## op, void, i32, i32, int)     \
+DEF_HELPER_3(cmpabs_s_ ## op, void, i32, i32, int)  \
+DEF_HELPER_3(cmp_ps_ ## op, void, i64, i64, int)    \
+DEF_HELPER_3(cmpabs_ps_ ## op, void, i64, i64, int)
+FOP_PROTO(f)
+FOP_PROTO(un)
+FOP_PROTO(eq)
+FOP_PROTO(ueq)
+FOP_PROTO(olt)
+FOP_PROTO(ult)
+FOP_PROTO(ole)
+FOP_PROTO(ule)
+FOP_PROTO(sf)
+FOP_PROTO(ngle)
+FOP_PROTO(seq)
+FOP_PROTO(ngl)
+FOP_PROTO(lt)
+FOP_PROTO(nge)
+FOP_PROTO(le)
+FOP_PROTO(ngt)
+#undef FOP_PROTO
+
+/* Special functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_0(tlbwi, void)
+DEF_HELPER_0(tlbwr, void)
+DEF_HELPER_0(tlbp, void)
+DEF_HELPER_0(tlbr, void)
+DEF_HELPER_0(di, tl)
+DEF_HELPER_0(ei, tl)
+DEF_HELPER_0(eret, void)
+DEF_HELPER_0(deret, void)
+#endif /* !CONFIG_USER_ONLY */
+DEF_HELPER_0(rdhwr_cpunum, tl)
+DEF_HELPER_0(rdhwr_synci_step, tl)
+DEF_HELPER_0(rdhwr_cc, tl)
+DEF_HELPER_0(rdhwr_ccres, tl)
+DEF_HELPER_1(pmon, void, int)
+DEF_HELPER_0(wait, void)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-mips/machine.c b/qemu-0.15.x/target-mips/machine.c
new file mode 100644
index 0000000..be72b36
--- /dev/null
+++ b/qemu-0.15.x/target-mips/machine.c
@@ -0,0 +1,308 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+#include "cpu.h"
+
+static void save_tc(QEMUFile *f, TCState *tc)
+{
+    int i;
+
+    /* Save active TC */
+    for(i = 0; i < 32; i++)
+        qemu_put_betls(f, &tc->gpr[i]);
+    qemu_put_betls(f, &tc->PC);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_put_betls(f, &tc->HI[i]);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_put_betls(f, &tc->LO[i]);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_put_betls(f, &tc->ACX[i]);
+    qemu_put_betls(f, &tc->DSPControl);
+    qemu_put_sbe32s(f, &tc->CP0_TCStatus);
+    qemu_put_sbe32s(f, &tc->CP0_TCBind);
+    qemu_put_betls(f, &tc->CP0_TCHalt);
+    qemu_put_betls(f, &tc->CP0_TCContext);
+    qemu_put_betls(f, &tc->CP0_TCSchedule);
+    qemu_put_betls(f, &tc->CP0_TCScheFBack);
+    qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
+}
+
+static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+{
+    int i;
+
+    for(i = 0; i < 32; i++)
+        qemu_put_be64s(f, &fpu->fpr[i].d);
+    qemu_put_s8s(f, &fpu->fp_status.float_detect_tininess);
+    qemu_put_s8s(f, &fpu->fp_status.float_rounding_mode);
+    qemu_put_s8s(f, &fpu->fp_status.float_exception_flags);
+    qemu_put_be32s(f, &fpu->fcr0);
+    qemu_put_be32s(f, &fpu->fcr31);
+}
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    CPUState *env = opaque;
+    int i;
+
+    /* Save active TC */
+    save_tc(f, &env->active_tc);
+
+    /* Save active FPU */
+    save_fpu(f, &env->active_fpu);
+
+    /* Save MVP */
+    qemu_put_sbe32s(f, &env->mvp->CP0_MVPControl);
+    qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf0);
+    qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf1);
+
+    /* Save TLB */
+    qemu_put_be32s(f, &env->tlb->nb_tlb);
+    qemu_put_be32s(f, &env->tlb->tlb_in_use);
+    for(i = 0; i < MIPS_TLB_MAX; i++) {
+        uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].G << 10) |
+                          (env->tlb->mmu.r4k.tlb[i].C0 << 7) |
+                          (env->tlb->mmu.r4k.tlb[i].C1 << 4) |
+                          (env->tlb->mmu.r4k.tlb[i].V0 << 3) |
+                          (env->tlb->mmu.r4k.tlb[i].V1 << 2) |
+                          (env->tlb->mmu.r4k.tlb[i].D0 << 1) |
+                          (env->tlb->mmu.r4k.tlb[i].D1 << 0));
+        uint8_t asid;
+
+        qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
+        qemu_put_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
+        asid = env->tlb->mmu.r4k.tlb[i].ASID;
+        qemu_put_8s(f, &asid);
+        qemu_put_be16s(f, &flags);
+        qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
+        qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
+    }
+
+    /* Save CPU metastate */
+    qemu_put_be32s(f, &env->current_tc);
+    qemu_put_be32s(f, &env->current_fpu);
+    qemu_put_sbe32s(f, &env->error_code);
+    qemu_put_be32s(f, &env->hflags);
+    qemu_put_betls(f, &env->btarget);
+    i = env->bcond;
+    qemu_put_sbe32s(f, &i);
+
+    /* Save remaining CP1 registers */
+    qemu_put_sbe32s(f, &env->CP0_Index);
+    qemu_put_sbe32s(f, &env->CP0_Random);
+    qemu_put_sbe32s(f, &env->CP0_VPEControl);
+    qemu_put_sbe32s(f, &env->CP0_VPEConf0);
+    qemu_put_sbe32s(f, &env->CP0_VPEConf1);
+    qemu_put_betls(f, &env->CP0_YQMask);
+    qemu_put_betls(f, &env->CP0_VPESchedule);
+    qemu_put_betls(f, &env->CP0_VPEScheFBack);
+    qemu_put_sbe32s(f, &env->CP0_VPEOpt);
+    qemu_put_betls(f, &env->CP0_EntryLo0);
+    qemu_put_betls(f, &env->CP0_EntryLo1);
+    qemu_put_betls(f, &env->CP0_Context);
+    qemu_put_sbe32s(f, &env->CP0_PageMask);
+    qemu_put_sbe32s(f, &env->CP0_PageGrain);
+    qemu_put_sbe32s(f, &env->CP0_Wired);
+    qemu_put_sbe32s(f, &env->CP0_SRSConf0);
+    qemu_put_sbe32s(f, &env->CP0_SRSConf1);
+    qemu_put_sbe32s(f, &env->CP0_SRSConf2);
+    qemu_put_sbe32s(f, &env->CP0_SRSConf3);
+    qemu_put_sbe32s(f, &env->CP0_SRSConf4);
+    qemu_put_sbe32s(f, &env->CP0_HWREna);
+    qemu_put_betls(f, &env->CP0_BadVAddr);
+    qemu_put_sbe32s(f, &env->CP0_Count);
+    qemu_put_betls(f, &env->CP0_EntryHi);
+    qemu_put_sbe32s(f, &env->CP0_Compare);
+    qemu_put_sbe32s(f, &env->CP0_Status);
+    qemu_put_sbe32s(f, &env->CP0_IntCtl);
+    qemu_put_sbe32s(f, &env->CP0_SRSCtl);
+    qemu_put_sbe32s(f, &env->CP0_SRSMap);
+    qemu_put_sbe32s(f, &env->CP0_Cause);
+    qemu_put_betls(f, &env->CP0_EPC);
+    qemu_put_sbe32s(f, &env->CP0_PRid);
+    qemu_put_sbe32s(f, &env->CP0_EBase);
+    qemu_put_sbe32s(f, &env->CP0_Config0);
+    qemu_put_sbe32s(f, &env->CP0_Config1);
+    qemu_put_sbe32s(f, &env->CP0_Config2);
+    qemu_put_sbe32s(f, &env->CP0_Config3);
+    qemu_put_sbe32s(f, &env->CP0_Config6);
+    qemu_put_sbe32s(f, &env->CP0_Config7);
+    qemu_put_betls(f, &env->lladdr);
+    for(i = 0; i < 8; i++)
+        qemu_put_betls(f, &env->CP0_WatchLo[i]);
+    for(i = 0; i < 8; i++)
+        qemu_put_sbe32s(f, &env->CP0_WatchHi[i]);
+    qemu_put_betls(f, &env->CP0_XContext);
+    qemu_put_sbe32s(f, &env->CP0_Framemask);
+    qemu_put_sbe32s(f, &env->CP0_Debug);
+    qemu_put_betls(f, &env->CP0_DEPC);
+    qemu_put_sbe32s(f, &env->CP0_Performance0);
+    qemu_put_sbe32s(f, &env->CP0_TagLo);
+    qemu_put_sbe32s(f, &env->CP0_DataLo);
+    qemu_put_sbe32s(f, &env->CP0_TagHi);
+    qemu_put_sbe32s(f, &env->CP0_DataHi);
+    qemu_put_betls(f, &env->CP0_ErrorEPC);
+    qemu_put_sbe32s(f, &env->CP0_DESAVE);
+
+    /* Save inactive TC state */
+    for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
+        save_tc(f, &env->tcs[i]);
+    for (i = 0; i < MIPS_FPU_MAX; i++)
+        save_fpu(f, &env->fpus[i]);
+}
+
+static void load_tc(QEMUFile *f, TCState *tc)
+{
+    int i;
+
+    /* Save active TC */
+    for(i = 0; i < 32; i++)
+        qemu_get_betls(f, &tc->gpr[i]);
+    qemu_get_betls(f, &tc->PC);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_get_betls(f, &tc->HI[i]);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_get_betls(f, &tc->LO[i]);
+    for(i = 0; i < MIPS_DSP_ACC; i++)
+        qemu_get_betls(f, &tc->ACX[i]);
+    qemu_get_betls(f, &tc->DSPControl);
+    qemu_get_sbe32s(f, &tc->CP0_TCStatus);
+    qemu_get_sbe32s(f, &tc->CP0_TCBind);
+    qemu_get_betls(f, &tc->CP0_TCHalt);
+    qemu_get_betls(f, &tc->CP0_TCContext);
+    qemu_get_betls(f, &tc->CP0_TCSchedule);
+    qemu_get_betls(f, &tc->CP0_TCScheFBack);
+    qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
+}
+
+static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+{
+    int i;
+
+    for(i = 0; i < 32; i++)
+        qemu_get_be64s(f, &fpu->fpr[i].d);
+    qemu_get_s8s(f, &fpu->fp_status.float_detect_tininess);
+    qemu_get_s8s(f, &fpu->fp_status.float_rounding_mode);
+    qemu_get_s8s(f, &fpu->fp_status.float_exception_flags);
+    qemu_get_be32s(f, &fpu->fcr0);
+    qemu_get_be32s(f, &fpu->fcr31);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+    int i;
+
+    if (version_id != 3)
+        return -EINVAL;
+
+    /* Load active TC */
+    load_tc(f, &env->active_tc);
+
+    /* Load active FPU */
+    load_fpu(f, &env->active_fpu);
+
+    /* Load MVP */
+    qemu_get_sbe32s(f, &env->mvp->CP0_MVPControl);
+    qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf0);
+    qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf1);
+
+    /* Load TLB */
+    qemu_get_be32s(f, &env->tlb->nb_tlb);
+    qemu_get_be32s(f, &env->tlb->tlb_in_use);
+    for(i = 0; i < MIPS_TLB_MAX; i++) {
+        uint16_t flags;
+        uint8_t asid;
+
+        qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
+        qemu_get_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
+        qemu_get_8s(f, &asid);
+        env->tlb->mmu.r4k.tlb[i].ASID = asid;
+        qemu_get_be16s(f, &flags);
+        env->tlb->mmu.r4k.tlb[i].G = (flags >> 10) & 1;
+        env->tlb->mmu.r4k.tlb[i].C0 = (flags >> 7) & 3;
+        env->tlb->mmu.r4k.tlb[i].C1 = (flags >> 4) & 3;
+        env->tlb->mmu.r4k.tlb[i].V0 = (flags >> 3) & 1;
+        env->tlb->mmu.r4k.tlb[i].V1 = (flags >> 2) & 1;
+        env->tlb->mmu.r4k.tlb[i].D0 = (flags >> 1) & 1;
+        env->tlb->mmu.r4k.tlb[i].D1 = (flags >> 0) & 1;
+        qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
+        qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
+    }
+
+    /* Load CPU metastate */
+    qemu_get_be32s(f, &env->current_tc);
+    qemu_get_be32s(f, &env->current_fpu);
+    qemu_get_sbe32s(f, &env->error_code);
+    qemu_get_be32s(f, &env->hflags);
+    qemu_get_betls(f, &env->btarget);
+    qemu_get_sbe32s(f, &i);
+    env->bcond = i;
+
+    /* Load remaining CP1 registers */
+    qemu_get_sbe32s(f, &env->CP0_Index);
+    qemu_get_sbe32s(f, &env->CP0_Random);
+    qemu_get_sbe32s(f, &env->CP0_VPEControl);
+    qemu_get_sbe32s(f, &env->CP0_VPEConf0);
+    qemu_get_sbe32s(f, &env->CP0_VPEConf1);
+    qemu_get_betls(f, &env->CP0_YQMask);
+    qemu_get_betls(f, &env->CP0_VPESchedule);
+    qemu_get_betls(f, &env->CP0_VPEScheFBack);
+    qemu_get_sbe32s(f, &env->CP0_VPEOpt);
+    qemu_get_betls(f, &env->CP0_EntryLo0);
+    qemu_get_betls(f, &env->CP0_EntryLo1);
+    qemu_get_betls(f, &env->CP0_Context);
+    qemu_get_sbe32s(f, &env->CP0_PageMask);
+    qemu_get_sbe32s(f, &env->CP0_PageGrain);
+    qemu_get_sbe32s(f, &env->CP0_Wired);
+    qemu_get_sbe32s(f, &env->CP0_SRSConf0);
+    qemu_get_sbe32s(f, &env->CP0_SRSConf1);
+    qemu_get_sbe32s(f, &env->CP0_SRSConf2);
+    qemu_get_sbe32s(f, &env->CP0_SRSConf3);
+    qemu_get_sbe32s(f, &env->CP0_SRSConf4);
+    qemu_get_sbe32s(f, &env->CP0_HWREna);
+    qemu_get_betls(f, &env->CP0_BadVAddr);
+    qemu_get_sbe32s(f, &env->CP0_Count);
+    qemu_get_betls(f, &env->CP0_EntryHi);
+    qemu_get_sbe32s(f, &env->CP0_Compare);
+    qemu_get_sbe32s(f, &env->CP0_Status);
+    qemu_get_sbe32s(f, &env->CP0_IntCtl);
+    qemu_get_sbe32s(f, &env->CP0_SRSCtl);
+    qemu_get_sbe32s(f, &env->CP0_SRSMap);
+    qemu_get_sbe32s(f, &env->CP0_Cause);
+    qemu_get_betls(f, &env->CP0_EPC);
+    qemu_get_sbe32s(f, &env->CP0_PRid);
+    qemu_get_sbe32s(f, &env->CP0_EBase);
+    qemu_get_sbe32s(f, &env->CP0_Config0);
+    qemu_get_sbe32s(f, &env->CP0_Config1);
+    qemu_get_sbe32s(f, &env->CP0_Config2);
+    qemu_get_sbe32s(f, &env->CP0_Config3);
+    qemu_get_sbe32s(f, &env->CP0_Config6);
+    qemu_get_sbe32s(f, &env->CP0_Config7);
+    qemu_get_betls(f, &env->lladdr);
+    for(i = 0; i < 8; i++)
+        qemu_get_betls(f, &env->CP0_WatchLo[i]);
+    for(i = 0; i < 8; i++)
+        qemu_get_sbe32s(f, &env->CP0_WatchHi[i]);
+    qemu_get_betls(f, &env->CP0_XContext);
+    qemu_get_sbe32s(f, &env->CP0_Framemask);
+    qemu_get_sbe32s(f, &env->CP0_Debug);
+    qemu_get_betls(f, &env->CP0_DEPC);
+    qemu_get_sbe32s(f, &env->CP0_Performance0);
+    qemu_get_sbe32s(f, &env->CP0_TagLo);
+    qemu_get_sbe32s(f, &env->CP0_DataLo);
+    qemu_get_sbe32s(f, &env->CP0_TagHi);
+    qemu_get_sbe32s(f, &env->CP0_DataHi);
+    qemu_get_betls(f, &env->CP0_ErrorEPC);
+    qemu_get_sbe32s(f, &env->CP0_DESAVE);
+
+    /* Load inactive TC state */
+    for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
+        load_tc(f, &env->tcs[i]);
+    for (i = 0; i < MIPS_FPU_MAX; i++)
+        load_fpu(f, &env->fpus[i]);
+
+    /* XXX: ensure compatiblity for halted bit ? */
+    tlb_flush(env, 1);
+    return 0;
+}
diff --git a/qemu-0.15.x/target-mips/mips-defs.h b/qemu-0.15.x/target-mips/mips-defs.h
new file mode 100644
index 0000000..bf094a3
--- /dev/null
+++ b/qemu-0.15.x/target-mips/mips-defs.h
@@ -0,0 +1,72 @@
+#if !defined (__QEMU_MIPS_DEFS_H__)
+#define __QEMU_MIPS_DEFS_H__
+
+/* If we want to use host float regs... */
+//#define USE_HOST_FLOAT_REGS
+
+/* Real pages are variable size... */
+#define TARGET_PAGE_BITS 12
+#define MIPS_TLB_MAX 128
+
+#if defined(TARGET_MIPS64)
+#define TARGET_LONG_BITS 64
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 42
+#else
+#define TARGET_LONG_BITS 32
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+/* Masks used to mark instructions to indicate which ISA level they
+   were introduced in. */
+#define		ISA_MIPS1	0x00000001
+#define		ISA_MIPS2	0x00000002
+#define		ISA_MIPS3	0x00000004
+#define		ISA_MIPS4	0x00000008
+#define		ISA_MIPS5	0x00000010
+#define		ISA_MIPS32	0x00000020
+#define		ISA_MIPS32R2	0x00000040
+#define		ISA_MIPS64	0x00000080
+#define		ISA_MIPS64R2	0x00000100
+
+/* MIPS ASEs. */
+#define		ASE_MIPS16	0x00001000
+#define		ASE_MIPS3D	0x00002000
+#define		ASE_MDMX	0x00004000
+#define		ASE_DSP		0x00008000
+#define		ASE_DSPR2	0x00010000
+#define		ASE_MT		0x00020000
+#define		ASE_SMARTMIPS	0x00040000
+#define 	ASE_MICROMIPS	0x00080000
+
+/* Chip specific instructions. */
+#define		INSN_LOONGSON2E  0x20000000
+#define		INSN_LOONGSON2F  0x40000000
+#define		INSN_VR54XX	0x80000000
+
+/* MIPS CPU defines. */
+#define		CPU_MIPS1	(ISA_MIPS1)
+#define		CPU_MIPS2	(CPU_MIPS1 | ISA_MIPS2)
+#define		CPU_MIPS3	(CPU_MIPS2 | ISA_MIPS3)
+#define		CPU_MIPS4	(CPU_MIPS3 | ISA_MIPS4)
+#define		CPU_VR54XX	(CPU_MIPS4 | INSN_VR54XX)
+#define		CPU_LOONGSON2E  (CPU_MIPS3 | INSN_LOONGSON2E)
+#define		CPU_LOONGSON2F  (CPU_MIPS3 | INSN_LOONGSON2F)
+
+#define		CPU_MIPS5	(CPU_MIPS4 | ISA_MIPS5)
+
+/* MIPS Technologies "Release 1" */
+#define		CPU_MIPS32	(CPU_MIPS2 | ISA_MIPS32)
+#define		CPU_MIPS64	(CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+
+/* MIPS Technologies "Release 2" */
+#define		CPU_MIPS32R2	(CPU_MIPS32 | ISA_MIPS32R2)
+#define		CPU_MIPS64R2	(CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
+
+/* Strictly follow the architecture standard:
+   - Disallow "special" instruction handling for PMON/SPIM.
+   Note that we still maintain Count/Compare to match the host clock. */
+//#define MIPS_STRICT_STANDARD 1
+
+#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
diff --git a/qemu-0.15.x/target-mips/op_helper.c b/qemu-0.15.x/target-mips/op_helper.c
new file mode 100644
index 0000000..01315ef
--- /dev/null
+++ b/qemu-0.15.x/target-mips/op_helper.c
@@ -0,0 +1,3048 @@
+/*
+ *  MIPS emulation helpers for qemu.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include "exec.h"
+
+#include "host-utils.h"
+
+#include "helper.h"
+
+#ifndef CONFIG_USER_ONLY
+static inline void cpu_mips_tlb_flush (CPUState *env, int flush_global);
+#endif
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+
+void helper_raise_exception_err (uint32_t exception, int error_code)
+{
+#if 1
+    if (exception < 0x100)
+        qemu_log("%s: %d %d\n", __func__, exception, error_code);
+#endif
+    env->exception_index = exception;
+    env->error_code = error_code;
+    cpu_loop_exit(env);
+}
+
+void helper_raise_exception (uint32_t exception)
+{
+    helper_raise_exception_err(exception, 0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_restore_state (void *pc_ptr)
+{
+    TranslationBlock *tb;
+    unsigned long pc = (unsigned long) pc_ptr;
+    
+    tb = tb_find_pc (pc);
+    if (tb) {
+        cpu_restore_state(tb, env, pc);
+    }
+}
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    return (type) insn##_raw(addr);                                     \
+}
+#else
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: return (type) insn##_kernel(addr); break;                   \
+    case 1: return (type) insn##_super(addr); break;                    \
+    default:                                                            \
+    case 2: return (type) insn##_user(addr); break;                     \
+    }                                                                   \
+}
+#endif
+HELPER_LD(lbu, ldub, uint8_t)
+HELPER_LD(lw, ldl, int32_t)
+#ifdef TARGET_MIPS64
+HELPER_LD(ld, ldq, int64_t)
+#endif
+#undef HELPER_LD
+
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    insn##_raw(addr, val);                                              \
+}
+#else
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: insn##_kernel(addr, val); break;                            \
+    case 1: insn##_super(addr, val); break;                             \
+    default:                                                            \
+    case 2: insn##_user(addr, val); break;                              \
+    }                                                                   \
+}
+#endif
+HELPER_ST(sb, stb, uint8_t)
+HELPER_ST(sw, stl, uint32_t)
+#ifdef TARGET_MIPS64
+HELPER_ST(sd, stq, uint64_t)
+#endif
+#undef HELPER_ST
+
+target_ulong helper_clo (target_ulong arg1)
+{
+    return clo32(arg1);
+}
+
+target_ulong helper_clz (target_ulong arg1)
+{
+    return clz32(arg1);
+}
+
+#if defined(TARGET_MIPS64)
+target_ulong helper_dclo (target_ulong arg1)
+{
+    return clo64(arg1);
+}
+
+target_ulong helper_dclz (target_ulong arg1)
+{
+    return clz64(arg1);
+}
+#endif /* TARGET_MIPS64 */
+
+/* 64 bits arithmetic for 32 bits hosts */
+static inline uint64_t get_HILO (void)
+{
+    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
+}
+
+static inline void set_HILO (uint64_t HILO)
+{
+    env->active_tc.LO[0] = (int32_t)HILO;
+    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+}
+
+static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
+{
+    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+    arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+}
+
+static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
+{
+    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+}
+
+/* Multiplication variants of the vr54xx. */
+target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
+{
+    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
+
+    return arg1;
+}
+
+target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
+
+    return arg1;
+}
+
+target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
+
+    return arg1;
+}
+
+target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
+{
+    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
+
+    return arg1;
+}
+
+#ifdef TARGET_MIPS64
+void helper_dmult (target_ulong arg1, target_ulong arg2)
+{
+    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
+}
+
+void helper_dmultu (target_ulong arg1, target_ulong arg2)
+{
+    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
+
+static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
+{
+    target_phys_addr_t lladdr;
+
+    lladdr = cpu_mips_translate_address(env, address, rw);
+
+    if (lladdr == -1LL) {
+        cpu_loop_exit(env);
+    } else {
+        return lladdr;
+    }
+}
+
+#define HELPER_LD_ATOMIC(name, insn)                                          \
+target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
+{                                                                             \
+    env->lladdr = do_translate_address(arg, 0);                               \
+    env->llval = do_##insn(arg, mem_idx);                                     \
+    return env->llval;                                                        \
+}
+HELPER_LD_ATOMIC(ll, lw)
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ld)
+#endif
+#undef HELPER_LD_ATOMIC
+
+#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
+target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
+{                                                                             \
+    target_long tmp;                                                          \
+                                                                              \
+    if (arg2 & almask) {                                                      \
+        env->CP0_BadVAddr = arg2;                                             \
+        helper_raise_exception(EXCP_AdES);                                    \
+    }                                                                         \
+    if (do_translate_address(arg2, 1) == env->lladdr) {                       \
+        tmp = do_##ld_insn(arg2, mem_idx);                                    \
+        if (tmp == env->llval) {                                              \
+            do_##st_insn(arg2, arg1, mem_idx);                                \
+            return 1;                                                         \
+        }                                                                     \
+    }                                                                         \
+    return 0;                                                                 \
+}
+HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
+#ifdef TARGET_MIPS64
+HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
+#endif
+#undef HELPER_ST_ATOMIC
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK(v) ((v) & 3)
+#define GET_OFFSET(addr, offset) (addr + (offset))
+#else
+#define GET_LMASK(v) (((v) & 3) ^ 3)
+#define GET_OFFSET(addr, offset) (addr - (offset))
+#endif
+
+target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    target_ulong tmp;
+
+    tmp = do_lbu(arg2, mem_idx);
+    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
+
+    if (GET_LMASK(arg2) <= 2) {
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
+        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
+    }
+
+    if (GET_LMASK(arg2) <= 1) {
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
+        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
+    }
+
+    if (GET_LMASK(arg2) == 0) {
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
+        arg1 = (arg1 & 0xFFFFFF00) | tmp;
+    }
+    return (int32_t)arg1;
+}
+
+target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    target_ulong tmp;
+
+    tmp = do_lbu(arg2, mem_idx);
+    arg1 = (arg1 & 0xFFFFFF00) | tmp;
+
+    if (GET_LMASK(arg2) >= 1) {
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
+        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
+    }
+
+    if (GET_LMASK(arg2) >= 2) {
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
+        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
+    }
+
+    if (GET_LMASK(arg2) == 3) {
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
+        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
+    }
+    return (int32_t)arg1;
+}
+
+void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
+
+    if (GET_LMASK(arg2) <= 2)
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
+
+    if (GET_LMASK(arg2) <= 1)
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
+
+    if (GET_LMASK(arg2) == 0)
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
+}
+
+void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
+
+    if (GET_LMASK(arg2) >= 1)
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
+
+    if (GET_LMASK(arg2) >= 2)
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
+
+    if (GET_LMASK(arg2) == 3)
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
+}
+
+#if defined(TARGET_MIPS64)
+/* "half" load and stores.  We must do the memory access inline,
+   or fault handling won't work.  */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 7)
+#else
+#define GET_LMASK64(v) (((v) & 7) ^ 7)
+#endif
+
+target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    uint64_t tmp;
+
+    tmp = do_lbu(arg2, mem_idx);
+    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
+
+    if (GET_LMASK64(arg2) <= 6) {
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
+        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
+    }
+
+    if (GET_LMASK64(arg2) <= 5) {
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
+        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
+    }
+
+    if (GET_LMASK64(arg2) <= 4) {
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
+        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
+    }
+
+    if (GET_LMASK64(arg2) <= 3) {
+        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
+    }
+
+    if (GET_LMASK64(arg2) <= 2) {
+        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
+    }
+
+    if (GET_LMASK64(arg2) <= 1) {
+        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
+    }
+
+    if (GET_LMASK64(arg2) == 0) {
+        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
+    }
+
+    return arg1;
+}
+
+target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    uint64_t tmp;
+
+    tmp = do_lbu(arg2, mem_idx);
+    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
+
+    if (GET_LMASK64(arg2) >= 1) {
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
+    }
+
+    if (GET_LMASK64(arg2) >= 2) {
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
+    }
+
+    if (GET_LMASK64(arg2) >= 3) {
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
+        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
+    }
+
+    if (GET_LMASK64(arg2) >= 4) {
+        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
+        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
+    }
+
+    if (GET_LMASK64(arg2) >= 5) {
+        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
+        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
+    }
+
+    if (GET_LMASK64(arg2) >= 6) {
+        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
+        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
+    }
+
+    if (GET_LMASK64(arg2) == 7) {
+        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
+        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
+    }
+
+    return arg1;
+}
+
+void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 6)
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 5)
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 4)
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 3)
+        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 2)
+        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 1)
+        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
+
+    if (GET_LMASK64(arg2) <= 0)
+        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
+}
+
+void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
+{
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
+
+    if (GET_LMASK64(arg2) >= 1)
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
+
+    if (GET_LMASK64(arg2) >= 2)
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
+
+    if (GET_LMASK64(arg2) >= 3)
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
+
+    if (GET_LMASK64(arg2) >= 4)
+        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
+
+    if (GET_LMASK64(arg2) >= 5)
+        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
+
+    if (GET_LMASK64(arg2) >= 6)
+        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
+
+    if (GET_LMASK64(arg2) == 7)
+        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
+}
+#endif /* TARGET_MIPS64 */
+
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldl_raw
+#else
+    uint32_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldl_kernel; break;
+    case 1: ldfun = ldl_super; break;
+    default:
+    case 2: ldfun = ldl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = (target_long) ldfun(addr);
+    }
+}
+
+void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stl_raw
+#else
+    void (*stfun)(target_ulong, uint32_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stl_kernel; break;
+    case 1: stfun = stl_super; break;
+     default:
+    case 2: stfun = stl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldq_raw
+#else
+    uint64_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldq_kernel; break;
+    case 1: ldfun = ldq_super; break;
+    default:
+    case 2: ldfun = ldq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = ldfun(addr);
+    }
+}
+
+void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stq_raw
+#else
+    void (*stfun)(target_ulong, uint64_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stq_kernel; break;
+    case 1: stfun = stq_super; break;
+     default:
+    case 2: stfun = stq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
+/* CP0 helpers */
+target_ulong helper_mfc0_mvpcontrol (void)
+{
+    return env->mvp->CP0_MVPControl;
+}
+
+target_ulong helper_mfc0_mvpconf0 (void)
+{
+    return env->mvp->CP0_MVPConf0;
+}
+
+target_ulong helper_mfc0_mvpconf1 (void)
+{
+    return env->mvp->CP0_MVPConf1;
+}
+
+target_ulong helper_mfc0_random (void)
+{
+    return (int32_t)cpu_mips_get_random(env);
+}
+
+target_ulong helper_mfc0_tcstatus (void)
+{
+    return env->active_tc.CP0_TCStatus;
+}
+
+target_ulong helper_mftc0_tcstatus(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCStatus;
+    else
+        return env->tcs[other_tc].CP0_TCStatus;
+}
+
+target_ulong helper_mfc0_tcbind (void)
+{
+    return env->active_tc.CP0_TCBind;
+}
+
+target_ulong helper_mftc0_tcbind(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCBind;
+    else
+        return env->tcs[other_tc].CP0_TCBind;
+}
+
+target_ulong helper_mfc0_tcrestart (void)
+{
+    return env->active_tc.PC;
+}
+
+target_ulong helper_mftc0_tcrestart(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.PC;
+    else
+        return env->tcs[other_tc].PC;
+}
+
+target_ulong helper_mfc0_tchalt (void)
+{
+    return env->active_tc.CP0_TCHalt;
+}
+
+target_ulong helper_mftc0_tchalt(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCHalt;
+    else
+        return env->tcs[other_tc].CP0_TCHalt;
+}
+
+target_ulong helper_mfc0_tccontext (void)
+{
+    return env->active_tc.CP0_TCContext;
+}
+
+target_ulong helper_mftc0_tccontext(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCContext;
+    else
+        return env->tcs[other_tc].CP0_TCContext;
+}
+
+target_ulong helper_mfc0_tcschedule (void)
+{
+    return env->active_tc.CP0_TCSchedule;
+}
+
+target_ulong helper_mftc0_tcschedule(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCSchedule;
+    else
+        return env->tcs[other_tc].CP0_TCSchedule;
+}
+
+target_ulong helper_mfc0_tcschefback (void)
+{
+    return env->active_tc.CP0_TCScheFBack;
+}
+
+target_ulong helper_mftc0_tcschefback(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCScheFBack;
+    else
+        return env->tcs[other_tc].CP0_TCScheFBack;
+}
+
+target_ulong helper_mfc0_count (void)
+{
+    return (int32_t)cpu_mips_get_count(env);
+}
+
+target_ulong helper_mftc0_entryhi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
+
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_TCStatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_TCStatus;
+
+    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
+}
+
+target_ulong helper_mftc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    target_ulong t0;
+    int32_t tcstatus;
+
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_TCStatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_TCStatus;
+
+    t0 = env->CP0_Status & ~0xf1000018;
+    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
+    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
+    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
+
+    return t0;
+}
+
+target_ulong helper_mfc0_lladdr (void)
+{
+    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
+}
+
+target_ulong helper_mfc0_watchlo (uint32_t sel)
+{
+    return (int32_t)env->CP0_WatchLo[sel];
+}
+
+target_ulong helper_mfc0_watchhi (uint32_t sel)
+{
+    return env->CP0_WatchHi[sel];
+}
+
+target_ulong helper_mfc0_debug (void)
+{
+    target_ulong t0 = env->CP0_Debug;
+    if (env->hflags & MIPS_HFLAG_DM)
+        t0 |= 1 << CP0DB_DM;
+
+    return t0;
+}
+
+target_ulong helper_mftc0_debug(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
+
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_Debug_tcstatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+}
+
+#if defined(TARGET_MIPS64)
+target_ulong helper_dmfc0_tcrestart (void)
+{
+    return env->active_tc.PC;
+}
+
+target_ulong helper_dmfc0_tchalt (void)
+{
+    return env->active_tc.CP0_TCHalt;
+}
+
+target_ulong helper_dmfc0_tccontext (void)
+{
+    return env->active_tc.CP0_TCContext;
+}
+
+target_ulong helper_dmfc0_tcschedule (void)
+{
+    return env->active_tc.CP0_TCSchedule;
+}
+
+target_ulong helper_dmfc0_tcschefback (void)
+{
+    return env->active_tc.CP0_TCScheFBack;
+}
+
+target_ulong helper_dmfc0_lladdr (void)
+{
+    return env->lladdr >> env->CP0_LLAddr_shift;
+}
+
+target_ulong helper_dmfc0_watchlo (uint32_t sel)
+{
+    return env->CP0_WatchLo[sel];
+}
+#endif /* TARGET_MIPS64 */
+
+void helper_mtc0_index (target_ulong arg1)
+{
+    int num = 1;
+    unsigned int tmp = env->tlb->nb_tlb;
+
+    do {
+        tmp >>= 1;
+        num <<= 1;
+    } while (tmp);
+    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
+}
+
+void helper_mtc0_mvpcontrol (target_ulong arg1)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
+        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
+                (1 << CP0MVPCo_EVP);
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0MVPCo_STLB);
+    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
+
+    // TODO: Enable/disable shared TLB, enable/disable VPEs.
+
+    env->mvp->CP0_MVPControl = newval;
+}
+
+void helper_mtc0_vpecontrol (target_ulong arg1)
+{
+    uint32_t mask;
+    uint32_t newval;
+
+    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
+           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
+    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
+
+    /* Yield scheduler intercept not implemented. */
+    /* Gating storage scheduler intercept not implemented. */
+
+    // TODO: Enable/disable TCs.
+
+    env->CP0_VPEControl = newval;
+}
+
+void helper_mtc0_vpeconf0 (target_ulong arg1)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
+        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
+            mask |= (0xff << CP0VPEC0_XTC);
+        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+    }
+    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
+
+    // TODO: TC exclusive handling due to ERL/EXL.
+
+    env->CP0_VPEConf0 = newval;
+}
+
+void helper_mtc0_vpeconf1 (target_ulong arg1)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
+                (0xff << CP0VPEC1_NCP1);
+    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
+
+    /* UDI not implemented. */
+    /* CP2 not implemented. */
+
+    // TODO: Handle FPU (CP1) binding.
+
+    env->CP0_VPEConf1 = newval;
+}
+
+void helper_mtc0_yqmask (target_ulong arg1)
+{
+    /* Yield qualifier inputs not implemented. */
+    env->CP0_YQMask = 0x00000000;
+}
+
+void helper_mtc0_vpeopt (target_ulong arg1)
+{
+    env->CP0_VPEOpt = arg1 & 0x0000ffff;
+}
+
+void helper_mtc0_entrylo0 (target_ulong arg1)
+{
+    /* Large physaddr (PABITS) not implemented */
+    /* 1k pages not implemented */
+    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
+}
+
+void helper_mtc0_tcstatus (target_ulong arg1)
+{
+    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
+    uint32_t newval;
+
+    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
+
+    // TODO: Sync with CP0_Status.
+
+    env->active_tc.CP0_TCStatus = newval;
+}
+
+void helper_mttc0_tcstatus (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Sync with CP0_Status.
+
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCStatus = arg1;
+    else
+        env->tcs[other_tc].CP0_TCStatus = arg1;
+}
+
+void helper_mtc0_tcbind (target_ulong arg1)
+{
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0TCBd_CurVPE);
+    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
+    env->active_tc.CP0_TCBind = newval;
+}
+
+void helper_mttc0_tcbind (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0TCBd_CurVPE);
+    if (other_tc == env->current_tc) {
+        newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
+        env->active_tc.CP0_TCBind = newval;
+    } else {
+        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
+        env->tcs[other_tc].CP0_TCBind = newval;
+    }
+}
+
+void helper_mtc0_tcrestart (target_ulong arg1)
+{
+    env->active_tc.PC = arg1;
+    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+    env->lladdr = 0ULL;
+    /* MIPS16 not implemented. */
+}
+
+void helper_mttc0_tcrestart (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc) {
+        env->active_tc.PC = arg1;
+        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        env->lladdr = 0ULL;
+        /* MIPS16 not implemented. */
+    } else {
+        env->tcs[other_tc].PC = arg1;
+        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        env->lladdr = 0ULL;
+        /* MIPS16 not implemented. */
+    }
+}
+
+void helper_mtc0_tchalt (target_ulong arg1)
+{
+    env->active_tc.CP0_TCHalt = arg1 & 0x1;
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+}
+
+void helper_mttc0_tchalt (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCHalt = arg1;
+    else
+        env->tcs[other_tc].CP0_TCHalt = arg1;
+}
+
+void helper_mtc0_tccontext (target_ulong arg1)
+{
+    env->active_tc.CP0_TCContext = arg1;
+}
+
+void helper_mttc0_tccontext (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCContext = arg1;
+    else
+        env->tcs[other_tc].CP0_TCContext = arg1;
+}
+
+void helper_mtc0_tcschedule (target_ulong arg1)
+{
+    env->active_tc.CP0_TCSchedule = arg1;
+}
+
+void helper_mttc0_tcschedule (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCSchedule = arg1;
+    else
+        env->tcs[other_tc].CP0_TCSchedule = arg1;
+}
+
+void helper_mtc0_tcschefback (target_ulong arg1)
+{
+    env->active_tc.CP0_TCScheFBack = arg1;
+}
+
+void helper_mttc0_tcschefback (target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCScheFBack = arg1;
+    else
+        env->tcs[other_tc].CP0_TCScheFBack = arg1;
+}
+
+void helper_mtc0_entrylo1 (target_ulong arg1)
+{
+    /* Large physaddr (PABITS) not implemented */
+    /* 1k pages not implemented */
+    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
+}
+
+void helper_mtc0_context (target_ulong arg1)
+{
+    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
+}
+
+void helper_mtc0_pagemask (target_ulong arg1)
+{
+    /* 1k pages not implemented */
+    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
+}
+
+void helper_mtc0_pagegrain (target_ulong arg1)
+{
+    /* SmartMIPS not implemented */
+    /* Large physaddr (PABITS) not implemented */
+    /* 1k pages not implemented */
+    env->CP0_PageGrain = 0;
+}
+
+void helper_mtc0_wired (target_ulong arg1)
+{
+    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
+}
+
+void helper_mtc0_srsconf0 (target_ulong arg1)
+{
+    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
+}
+
+void helper_mtc0_srsconf1 (target_ulong arg1)
+{
+    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
+}
+
+void helper_mtc0_srsconf2 (target_ulong arg1)
+{
+    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
+}
+
+void helper_mtc0_srsconf3 (target_ulong arg1)
+{
+    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
+}
+
+void helper_mtc0_srsconf4 (target_ulong arg1)
+{
+    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
+}
+
+void helper_mtc0_hwrena (target_ulong arg1)
+{
+    env->CP0_HWREna = arg1 & 0x0000000F;
+}
+
+void helper_mtc0_count (target_ulong arg1)
+{
+    cpu_mips_store_count(env, arg1);
+}
+
+void helper_mtc0_entryhi (target_ulong arg1)
+{
+    target_ulong old, val;
+
+    /* 1k pages not implemented */
+    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
+#if defined(TARGET_MIPS64)
+    val &= env->SEGMask;
+#endif
+    old = env->CP0_EntryHi;
+    env->CP0_EntryHi = val;
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
+        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
+    }
+    /* If the ASID changes, flush qemu's TLB.  */
+    if ((old & 0xFF) != (val & 0xFF))
+        cpu_mips_tlb_flush(env, 1);
+}
+
+void helper_mttc0_entryhi(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
+
+    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
+    if (other_tc == env->current_tc) {
+        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
+        env->active_tc.CP0_TCStatus = tcstatus;
+    } else {
+        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
+        env->tcs[other_tc].CP0_TCStatus = tcstatus;
+    }
+}
+
+void helper_mtc0_compare (target_ulong arg1)
+{
+    cpu_mips_store_compare(env, arg1);
+}
+
+void helper_mtc0_status (target_ulong arg1)
+{
+    uint32_t val, old;
+    uint32_t mask = env->CP0_Status_rw_bitmask;
+
+    val = arg1 & mask;
+    old = env->CP0_Status;
+    env->CP0_Status = (env->CP0_Status & ~mask) | val;
+    compute_hflags(env);
+    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
+        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
+                old, old & env->CP0_Cause & CP0Ca_IP_mask,
+                val, val & env->CP0_Cause & CP0Ca_IP_mask,
+                env->CP0_Cause);
+        switch (env->hflags & MIPS_HFLAG_KSU) {
+        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
+        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
+        case MIPS_HFLAG_KM: qemu_log("\n"); break;
+        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
+        }
+    }
+}
+
+void helper_mttc0_status(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
+
+    env->CP0_Status = arg1 & ~0xf1000018;
+    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
+    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
+    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCStatus = tcstatus;
+    else
+        env->tcs[other_tc].CP0_TCStatus = tcstatus;
+}
+
+void helper_mtc0_intctl (target_ulong arg1)
+{
+    /* vectored interrupts not implemented, no performance counters. */
+    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
+}
+
+void helper_mtc0_srsctl (target_ulong arg1)
+{
+    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
+    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
+}
+
+void helper_mtc0_cause (target_ulong arg1)
+{
+    uint32_t mask = 0x00C00300;
+    uint32_t old = env->CP0_Cause;
+    int i;
+
+    if (env->insn_flags & ISA_MIPS32R2)
+        mask |= 1 << CP0Ca_DC;
+
+    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
+
+    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
+        if (env->CP0_Cause & (1 << CP0Ca_DC))
+            cpu_mips_stop_count(env);
+        else
+            cpu_mips_start_count(env);
+    }
+
+    /* Set/reset software interrupts */
+    for (i = 0 ; i < 2 ; i++) {
+        if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+            cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+        }
+    }
+}
+
+void helper_mtc0_ebase (target_ulong arg1)
+{
+    /* vectored interrupts not implemented */
+    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
+}
+
+void helper_mtc0_config0 (target_ulong arg1)
+{
+    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
+}
+
+void helper_mtc0_config2 (target_ulong arg1)
+{
+    /* tertiary/secondary caches not implemented */
+    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
+}
+
+void helper_mtc0_lladdr (target_ulong arg1)
+{
+    target_long mask = env->CP0_LLAddr_rw_bitmask;
+    arg1 = arg1 << env->CP0_LLAddr_shift;
+    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
+}
+
+void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
+{
+    /* Watch exceptions for instructions, data loads, data stores
+       not implemented. */
+    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
+}
+
+void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
+{
+    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
+    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
+}
+
+void helper_mtc0_xcontext (target_ulong arg1)
+{
+    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
+    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
+}
+
+void helper_mtc0_framemask (target_ulong arg1)
+{
+    env->CP0_Framemask = arg1; /* XXX */
+}
+
+void helper_mtc0_debug (target_ulong arg1)
+{
+    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
+    if (arg1 & (1 << CP0DB_DM))
+        env->hflags |= MIPS_HFLAG_DM;
+    else
+        env->hflags &= ~MIPS_HFLAG_DM;
+}
+
+void helper_mttc0_debug(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_Debug_tcstatus = val;
+    else
+        env->tcs[other_tc].CP0_Debug_tcstatus = val;
+    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+}
+
+void helper_mtc0_performance0 (target_ulong arg1)
+{
+    env->CP0_Performance0 = arg1 & 0x000007ff;
+}
+
+void helper_mtc0_taglo (target_ulong arg1)
+{
+    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
+}
+
+void helper_mtc0_datalo (target_ulong arg1)
+{
+    env->CP0_DataLo = arg1; /* XXX */
+}
+
+void helper_mtc0_taghi (target_ulong arg1)
+{
+    env->CP0_TagHi = arg1; /* XXX */
+}
+
+void helper_mtc0_datahi (target_ulong arg1)
+{
+    env->CP0_DataHi = arg1; /* XXX */
+}
+
+/* MIPS MT functions */
+target_ulong helper_mftgpr(uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.gpr[sel];
+    else
+        return env->tcs[other_tc].gpr[sel];
+}
+
+target_ulong helper_mftlo(uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.LO[sel];
+    else
+        return env->tcs[other_tc].LO[sel];
+}
+
+target_ulong helper_mfthi(uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.HI[sel];
+    else
+        return env->tcs[other_tc].HI[sel];
+}
+
+target_ulong helper_mftacx(uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.ACX[sel];
+    else
+        return env->tcs[other_tc].ACX[sel];
+}
+
+target_ulong helper_mftdsp(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        return env->active_tc.DSPControl;
+    else
+        return env->tcs[other_tc].DSPControl;
+}
+
+void helper_mttgpr(target_ulong arg1, uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.gpr[sel] = arg1;
+    else
+        env->tcs[other_tc].gpr[sel] = arg1;
+}
+
+void helper_mttlo(target_ulong arg1, uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.LO[sel] = arg1;
+    else
+        env->tcs[other_tc].LO[sel] = arg1;
+}
+
+void helper_mtthi(target_ulong arg1, uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.HI[sel] = arg1;
+    else
+        env->tcs[other_tc].HI[sel] = arg1;
+}
+
+void helper_mttacx(target_ulong arg1, uint32_t sel)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.ACX[sel] = arg1;
+    else
+        env->tcs[other_tc].ACX[sel] = arg1;
+}
+
+void helper_mttdsp(target_ulong arg1)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if (other_tc == env->current_tc)
+        env->active_tc.DSPControl = arg1;
+    else
+        env->tcs[other_tc].DSPControl = arg1;
+}
+
+/* MIPS MT functions */
+target_ulong helper_dmt(void)
+{
+    // TODO
+     return 0;
+}
+
+target_ulong helper_emt(void)
+{
+    // TODO
+    return 0;
+}
+
+target_ulong helper_dvpe(void)
+{
+    // TODO
+    return 0;
+}
+
+target_ulong helper_evpe(void)
+{
+    // TODO
+    return 0;
+}
+#endif /* !CONFIG_USER_ONLY */
+
+void helper_fork(target_ulong arg1, target_ulong arg2)
+{
+    // arg1 = rt, arg2 = rs
+    arg1 = 0;
+    // TODO: store to TC register
+}
+
+target_ulong helper_yield(target_ulong arg)
+{
+    target_long arg1 = arg;
+
+    if (arg1 < 0) {
+        /* No scheduling policy implemented. */
+        if (arg1 != -2) {
+            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
+                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
+                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
+                helper_raise_exception(EXCP_THREAD);
+            }
+        }
+    } else if (arg1 == 0) {
+        if (0 /* TODO: TC underflow */) {
+            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+            helper_raise_exception(EXCP_THREAD);
+        } else {
+            // TODO: Deallocate TC
+        }
+    } else if (arg1 > 0) {
+        /* Yield qualifier inputs not implemented. */
+        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
+        helper_raise_exception(EXCP_THREAD);
+    }
+    return env->CP0_YQMask;
+}
+
+#ifndef CONFIG_USER_ONLY
+/* TLB management */
+static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
+{
+    /* Flush qemu's TLB and discard all shadowed entries.  */
+    tlb_flush (env, flush_global);
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
+}
+
+static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
+{
+    /* Discard entries from env->tlb[first] onwards.  */
+    while (env->tlb->tlb_in_use > first) {
+        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
+    }
+}
+
+static void r4k_fill_tlb (int idx)
+{
+    r4k_tlb_t *tlb;
+
+    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
+    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#if defined(TARGET_MIPS64)
+    tlb->VPN &= env->SEGMask;
+#endif
+    tlb->ASID = env->CP0_EntryHi & 0xFF;
+    tlb->PageMask = env->CP0_PageMask;
+    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
+    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
+    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
+    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
+    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
+    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
+    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
+    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
+    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
+}
+
+void r4k_helper_tlbwi (void)
+{
+    int idx;
+
+    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
+
+    /* Discard cached TLB entries.  We could avoid doing this if the
+       tlbwi is just upgrading access permissions on the current entry;
+       that might be a further win.  */
+    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
+
+    r4k_invalidate_tlb(env, idx, 0);
+    r4k_fill_tlb(idx);
+}
+
+void r4k_helper_tlbwr (void)
+{
+    int r = cpu_mips_get_random(env);
+
+    r4k_invalidate_tlb(env, r, 1);
+    r4k_fill_tlb(r);
+}
+
+void r4k_helper_tlbp (void)
+{
+    r4k_tlb_t *tlb;
+    target_ulong mask;
+    target_ulong tag;
+    target_ulong VPN;
+    uint8_t ASID;
+    int i;
+
+    ASID = env->CP0_EntryHi & 0xFF;
+    for (i = 0; i < env->tlb->nb_tlb; i++) {
+        tlb = &env->tlb->mmu.r4k.tlb[i];
+        /* 1k pages are not supported. */
+        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+        tag = env->CP0_EntryHi & ~mask;
+        VPN = tlb->VPN & ~mask;
+        /* Check ASID, virtual page number & size */
+        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+            /* TLB match */
+            env->CP0_Index = i;
+            break;
+        }
+    }
+    if (i == env->tlb->nb_tlb) {
+        /* No match.  Discard any shadow entries, if any of them match.  */
+        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
+            tlb = &env->tlb->mmu.r4k.tlb[i];
+            /* 1k pages are not supported. */
+            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+            tag = env->CP0_EntryHi & ~mask;
+            VPN = tlb->VPN & ~mask;
+            /* Check ASID, virtual page number & size */
+            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+                r4k_mips_tlb_flush_extra (env, i);
+                break;
+            }
+        }
+
+        env->CP0_Index |= 0x80000000;
+    }
+}
+
+void r4k_helper_tlbr (void)
+{
+    r4k_tlb_t *tlb;
+    uint8_t ASID;
+    int idx;
+
+    ASID = env->CP0_EntryHi & 0xFF;
+    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
+
+    /* If this will change the current ASID, flush qemu's TLB.  */
+    if (ASID != tlb->ASID)
+        cpu_mips_tlb_flush (env, 1);
+
+    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
+
+    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
+    env->CP0_PageMask = tlb->PageMask;
+    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
+                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
+    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
+                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
+}
+
+void helper_tlbwi(void)
+{
+    env->tlb->helper_tlbwi();
+}
+
+void helper_tlbwr(void)
+{
+    env->tlb->helper_tlbwr();
+}
+
+void helper_tlbp(void)
+{
+    env->tlb->helper_tlbp();
+}
+
+void helper_tlbr(void)
+{
+    env->tlb->helper_tlbr();
+}
+
+/* Specials */
+target_ulong helper_di (void)
+{
+    target_ulong t0 = env->CP0_Status;
+
+    env->CP0_Status = t0 & ~(1 << CP0St_IE);
+    return t0;
+}
+
+target_ulong helper_ei (void)
+{
+    target_ulong t0 = env->CP0_Status;
+
+    env->CP0_Status = t0 | (1 << CP0St_IE);
+    return t0;
+}
+
+static void debug_pre_eret (void)
+{
+    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
+        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+                env->active_tc.PC, env->CP0_EPC);
+        if (env->CP0_Status & (1 << CP0St_ERL))
+            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+        if (env->hflags & MIPS_HFLAG_DM)
+            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+        qemu_log("\n");
+    }
+}
+
+static void debug_post_eret (void)
+{
+    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
+        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+                env->active_tc.PC, env->CP0_EPC);
+        if (env->CP0_Status & (1 << CP0St_ERL))
+            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+        if (env->hflags & MIPS_HFLAG_DM)
+            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+        switch (env->hflags & MIPS_HFLAG_KSU) {
+        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
+        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
+        case MIPS_HFLAG_KM: qemu_log("\n"); break;
+        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
+        }
+    }
+}
+
+static void set_pc (target_ulong error_pc)
+{
+    env->active_tc.PC = error_pc & ~(target_ulong)1;
+    if (error_pc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    } else {
+        env->hflags &= ~(MIPS_HFLAG_M16);
+    }
+}
+
+void helper_eret (void)
+{
+    debug_pre_eret();
+    if (env->CP0_Status & (1 << CP0St_ERL)) {
+        set_pc(env->CP0_ErrorEPC);
+        env->CP0_Status &= ~(1 << CP0St_ERL);
+    } else {
+        set_pc(env->CP0_EPC);
+        env->CP0_Status &= ~(1 << CP0St_EXL);
+    }
+    compute_hflags(env);
+    debug_post_eret();
+    env->lladdr = 1;
+}
+
+void helper_deret (void)
+{
+    debug_pre_eret();
+    set_pc(env->CP0_DEPC);
+
+    env->hflags &= MIPS_HFLAG_DM;
+    compute_hflags(env);
+    debug_post_eret();
+    env->lladdr = 1;
+}
+#endif /* !CONFIG_USER_ONLY */
+
+target_ulong helper_rdhwr_cpunum(void)
+{
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 0)))
+        return env->CP0_EBase & 0x3ff;
+    else
+        helper_raise_exception(EXCP_RI);
+
+    return 0;
+}
+
+target_ulong helper_rdhwr_synci_step(void)
+{
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 1)))
+        return env->SYNCI_Step;
+    else
+        helper_raise_exception(EXCP_RI);
+
+    return 0;
+}
+
+target_ulong helper_rdhwr_cc(void)
+{
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 2)))
+        return env->CP0_Count;
+    else
+        helper_raise_exception(EXCP_RI);
+
+    return 0;
+}
+
+target_ulong helper_rdhwr_ccres(void)
+{
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 3)))
+        return env->CCRes;
+    else
+        helper_raise_exception(EXCP_RI);
+
+    return 0;
+}
+
+void helper_pmon (int function)
+{
+    function /= 2;
+    switch (function) {
+    case 2: /* TODO: char inbyte(int waitflag); */
+        if (env->active_tc.gpr[4] == 0)
+            env->active_tc.gpr[2] = -1;
+        /* Fall through */
+    case 11: /* TODO: char inbyte (void); */
+        env->active_tc.gpr[2] = -1;
+        break;
+    case 3:
+    case 12:
+        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
+        break;
+    case 17:
+        break;
+    case 158:
+        {
+            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
+            printf("%s", fmt);
+        }
+        break;
+    }
+}
+
+void helper_wait (void)
+{
+    env->halted = 1;
+    helper_raise_exception(EXCP_HLT);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
+
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+    env->CP0_BadVAddr = addr;
+    do_restore_state (retaddr);
+    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
+}
+
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (ret) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        helper_raise_exception_err(env->exception_index, env->error_code);
+    }
+    env = saved_env;
+}
+
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int unused, int size)
+{
+    env = env1;
+
+    if (is_exec)
+        helper_raise_exception(EXCP_IBE);
+    else
+        helper_raise_exception(EXCP_DBE);
+}
+#endif /* !CONFIG_USER_ONLY */
+
+/* Complex FPU operations which may need stack space. */
+
+#define FLOAT_ONE32 make_float32(0x3f8 << 20)
+#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
+#define FLOAT_TWO32 make_float32(1 << 30)
+#define FLOAT_TWO64 make_float64(1ULL << 62)
+#define FLOAT_QNAN32 0x7fbfffff
+#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
+#define FLOAT_SNAN32 0x7fffffff
+#define FLOAT_SNAN64 0x7fffffffffffffffULL
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+static unsigned int ieee_rm[] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+};
+
+#define RESTORE_ROUNDING_MODE \
+    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
+
+#define RESTORE_FLUSH_MODE \
+    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
+
+target_ulong helper_cfc1 (uint32_t reg)
+{
+    target_ulong arg1;
+
+    switch (reg) {
+    case 0:
+        arg1 = (int32_t)env->active_fpu.fcr0;
+        break;
+    case 25:
+        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
+        break;
+    case 26:
+        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
+        break;
+    case 28:
+        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
+        break;
+    default:
+        arg1 = (int32_t)env->active_fpu.fcr31;
+        break;
+    }
+
+    return arg1;
+}
+
+void helper_ctc1 (target_ulong arg1, uint32_t reg)
+{
+    switch(reg) {
+    case 25:
+        if (arg1 & 0xffffff00)
+            return;
+        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
+                     ((arg1 & 0x1) << 23);
+        break;
+    case 26:
+        if (arg1 & 0x007c0000)
+            return;
+        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
+        break;
+    case 28:
+        if (arg1 & 0x007c0000)
+            return;
+        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
+                     ((arg1 & 0x4) << 22);
+        break;
+    case 31:
+        if (arg1 & 0x007c0000)
+            return;
+        env->active_fpu.fcr31 = arg1;
+        break;
+    default:
+        return;
+    }
+    /* set rounding mode */
+    RESTORE_ROUNDING_MODE;
+    /* set flush-to-zero mode */
+    RESTORE_FLUSH_MODE;
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
+        helper_raise_exception(EXCP_FPE);
+}
+
+static inline int ieee_ex_to_mips(int xcpt)
+{
+    int ret = 0;
+    if (xcpt) {
+        if (xcpt & float_flag_invalid) {
+            ret |= FP_INVALID;
+        }
+        if (xcpt & float_flag_overflow) {
+            ret |= FP_OVERFLOW;
+        }
+        if (xcpt & float_flag_underflow) {
+            ret |= FP_UNDERFLOW;
+        }
+        if (xcpt & float_flag_divbyzero) {
+            ret |= FP_DIV0;
+        }
+        if (xcpt & float_flag_inexact) {
+            ret |= FP_INEXACT;
+        }
+    }
+    return ret;
+}
+
+static inline void update_fcr31(void)
+{
+    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
+
+    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
+    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
+        helper_raise_exception(EXCP_FPE);
+    else
+        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
+}
+
+/* Float support.
+   Single precition routines have a "s" suffix, double precision a
+   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
+   paired single lower "pl", paired single upper "pu".  */
+
+/* unary operations, modifying fp status  */
+uint64_t helper_float_sqrt_d(uint64_t fdt0)
+{
+    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
+}
+
+uint32_t helper_float_sqrt_s(uint32_t fst0)
+{
+    return float32_sqrt(fst0, &env->active_fpu.fp_status);
+}
+
+uint64_t helper_float_cvtd_s(uint32_t fst0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint64_t helper_float_cvtd_w(uint32_t wt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint64_t helper_float_cvtd_l(uint64_t dt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint64_t helper_float_cvtl_d(uint64_t fdt0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_cvtl_s(uint32_t fst0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_cvtps_pw(uint64_t dt0)
+{
+    uint32_t fst2;
+    uint32_t fsth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
+{
+    uint32_t wt2;
+    uint32_t wth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
+        wt2 = FLOAT_SNAN32;
+        wth2 = FLOAT_SNAN32;
+    }
+    return ((uint64_t)wth2 << 32) | wt2;
+}
+
+uint32_t helper_float_cvts_d(uint64_t fdt0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint32_t helper_float_cvts_w(uint32_t wt0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint32_t helper_float_cvts_l(uint64_t dt0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint32_t helper_float_cvts_pl(uint32_t wt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = wt0;
+    update_fcr31();
+    return wt2;
+}
+
+uint32_t helper_float_cvts_pu(uint32_t wth0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = wth0;
+    update_fcr31();
+    return wt2;
+}
+
+uint32_t helper_float_cvtw_s(uint32_t fst0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint32_t helper_float_cvtw_d(uint64_t fdt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint64_t helper_float_roundl_d(uint64_t fdt0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
+    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_roundl_s(uint32_t fst0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
+    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint32_t helper_float_roundw_d(uint64_t fdt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
+    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint32_t helper_float_roundw_s(uint32_t fst0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint64_t helper_float_truncl_d(uint64_t fdt0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_truncl_s(uint32_t fst0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint32_t helper_float_truncw_d(uint64_t fdt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint32_t helper_float_truncw_s(uint32_t fst0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint64_t helper_float_ceill_d(uint64_t fdt0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
+    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_ceill_s(uint32_t fst0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
+    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint32_t helper_float_ceilw_d(uint64_t fdt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
+    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint32_t helper_float_ceilw_s(uint32_t fst0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint64_t helper_float_floorl_d(uint64_t fdt0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
+    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint64_t helper_float_floorl_s(uint32_t fst0)
+{
+    uint64_t dt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
+    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        dt2 = FLOAT_SNAN64;
+    return dt2;
+}
+
+uint32_t helper_float_floorw_d(uint64_t fdt0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
+    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+uint32_t helper_float_floorw_s(uint32_t fst0)
+{
+    uint32_t wt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
+    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
+        wt2 = FLOAT_SNAN32;
+    return wt2;
+}
+
+/* unary operations, not modifying fp status  */
+#define FLOAT_UNOP(name)                                       \
+uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
+{                                                              \
+    return float64_ ## name(fdt0);                             \
+}                                                              \
+uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
+{                                                              \
+    return float32_ ## name(fst0);                             \
+}                                                              \
+uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
+{                                                              \
+    uint32_t wt0;                                              \
+    uint32_t wth0;                                             \
+                                                               \
+    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
+    wth0 = float32_ ## name(fdt0 >> 32);                       \
+    return ((uint64_t)wth0 << 32) | wt0;                       \
+}
+FLOAT_UNOP(abs)
+FLOAT_UNOP(chs)
+#undef FLOAT_UNOP
+
+/* MIPS specific unary operations */
+uint64_t helper_float_recip_d(uint64_t fdt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_recip_s(uint32_t fst0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_rsqrt_d(uint64_t fdt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
+    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_rsqrt_s(uint32_t fst0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_recip1_d(uint64_t fdt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_recip1_s(uint32_t fst0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_recip1_ps(uint64_t fdt0)
+{
+    uint32_t fst2;
+    uint32_t fsth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
+{
+    uint64_t fdt2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
+    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_rsqrt1_s(uint32_t fst0)
+{
+    uint32_t fst2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
+{
+    uint32_t fst2;
+    uint32_t fsth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
+    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
+    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
+
+/* binary operations */
+#define FLOAT_BINOP(name)                                          \
+uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
+{                                                                  \
+    uint64_t dt2;                                                  \
+                                                                   \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
+    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
+        dt2 = FLOAT_QNAN64;                                        \
+    return dt2;                                                    \
+}                                                                  \
+                                                                   \
+uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
+{                                                                  \
+    uint32_t wt2;                                                  \
+                                                                   \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
+    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
+        wt2 = FLOAT_QNAN32;                                        \
+    return wt2;                                                    \
+}                                                                  \
+                                                                   \
+uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
+{                                                                  \
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
+    uint32_t fsth0 = fdt0 >> 32;                                   \
+    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
+    uint32_t fsth1 = fdt1 >> 32;                                   \
+    uint32_t wt2;                                                  \
+    uint32_t wth2;                                                 \
+                                                                   \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
+    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
+    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
+        wt2 = FLOAT_QNAN32;                                        \
+        wth2 = FLOAT_QNAN32;                                       \
+    }                                                              \
+    return ((uint64_t)wth2 << 32) | wt2;                           \
+}
+
+FLOAT_BINOP(add)
+FLOAT_BINOP(sub)
+FLOAT_BINOP(mul)
+FLOAT_BINOP(div)
+#undef FLOAT_BINOP
+
+/* ternary operations */
+#define FLOAT_TERNOP(name1, name2)                                        \
+uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
+                                           uint64_t fdt2)                 \
+{                                                                         \
+    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
+    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
+}                                                                         \
+                                                                          \
+uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
+                                           uint32_t fst2)                 \
+{                                                                         \
+    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
+    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
+}                                                                         \
+                                                                          \
+uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
+                                            uint64_t fdt2)                \
+{                                                                         \
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
+    uint32_t fsth0 = fdt0 >> 32;                                          \
+    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
+    uint32_t fsth1 = fdt1 >> 32;                                          \
+    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
+    uint32_t fsth2 = fdt2 >> 32;                                          \
+                                                                          \
+    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
+    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
+    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
+    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
+    return ((uint64_t)fsth2 << 32) | fst2;                                \
+}
+
+FLOAT_TERNOP(mul, add)
+FLOAT_TERNOP(mul, sub)
+#undef FLOAT_TERNOP
+
+/* negated ternary operations */
+#define FLOAT_NTERNOP(name1, name2)                                       \
+uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
+                                           uint64_t fdt2)                 \
+{                                                                         \
+    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
+    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
+    return float64_chs(fdt2);                                             \
+}                                                                         \
+                                                                          \
+uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
+                                           uint32_t fst2)                 \
+{                                                                         \
+    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
+    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
+    return float32_chs(fst2);                                             \
+}                                                                         \
+                                                                          \
+uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
+                                           uint64_t fdt2)                 \
+{                                                                         \
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
+    uint32_t fsth0 = fdt0 >> 32;                                          \
+    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
+    uint32_t fsth1 = fdt1 >> 32;                                          \
+    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
+    uint32_t fsth2 = fdt2 >> 32;                                          \
+                                                                          \
+    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
+    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
+    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
+    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
+    fst2 = float32_chs(fst2);                                             \
+    fsth2 = float32_chs(fsth2);                                           \
+    return ((uint64_t)fsth2 << 32) | fst2;                                \
+}
+
+FLOAT_NTERNOP(mul, add)
+FLOAT_NTERNOP(mul, sub)
+#undef FLOAT_NTERNOP
+
+/* MIPS specific binary operations */
+uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
+{
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
+    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
+{
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
+{
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fdt0 >> 32;
+    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+    uint32_t fsth2 = fdt2 >> 32;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
+    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
+    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
+{
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
+    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
+    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
+    update_fcr31();
+    return fdt2;
+}
+
+uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
+{
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
+    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
+    update_fcr31();
+    return fst2;
+}
+
+uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
+{
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fdt0 >> 32;
+    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+    uint32_t fsth2 = fdt2 >> 32;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
+    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
+    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
+    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
+    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
+    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
+{
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fdt0 >> 32;
+    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+    uint32_t fsth1 = fdt1 >> 32;
+    uint32_t fst2;
+    uint32_t fsth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
+    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
+{
+    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fdt0 >> 32;
+    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+    uint32_t fsth1 = fdt1 >> 32;
+    uint32_t fst2;
+    uint32_t fsth2;
+
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
+    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
+    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
+    update_fcr31();
+    return ((uint64_t)fsth2 << 32) | fst2;
+}
+
+/* compare operations */
+#define FOP_COND_D(op, cond)                                   \
+void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
+{                                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
+    update_fcr31();                                            \
+    if (c)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                      \
+    else                                                       \
+        CLEAR_FP_COND(cc, env->active_fpu);                    \
+}                                                              \
+void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{                                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    fdt0 = float64_abs(fdt0);                                  \
+    fdt1 = float64_abs(fdt1);                                  \
+    c = cond;                                                  \
+    update_fcr31();                                            \
+    if (c)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                      \
+    else                                                       \
+        CLEAR_FP_COND(cc, env->active_fpu);                    \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered_quiet() is still called. */
+FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered() is still called. */
+FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+
+#define FOP_COND_S(op, cond)                                   \
+void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
+{                                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
+    update_fcr31();                                            \
+    if (c)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                      \
+    else                                                       \
+        CLEAR_FP_COND(cc, env->active_fpu);                    \
+}                                                              \
+void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
+{                                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    fst0 = float32_abs(fst0);                                  \
+    fst1 = float32_abs(fst1);                                  \
+    c = cond;                                                  \
+    update_fcr31();                                            \
+    if (c)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                      \
+    else                                                       \
+        CLEAR_FP_COND(cc, env->active_fpu);                    \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered() is still called. */
+FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
+
+#define FOP_COND_PS(op, condl, condh)                           \
+void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
+{                                                               \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);   \
+    fst0 = fdt0 & 0XFFFFFFFF;                                   \
+    fsth0 = fdt0 >> 32;                                         \
+    fst1 = fdt1 & 0XFFFFFFFF;                                   \
+    fsth1 = fdt1 >> 32;                                         \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
+    update_fcr31();                                             \
+    if (cl)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                       \
+    else                                                        \
+        CLEAR_FP_COND(cc, env->active_fpu);                     \
+    if (ch)                                                     \
+        SET_FP_COND(cc + 1, env->active_fpu);                   \
+    else                                                        \
+        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
+}                                                               \
+void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{                                                               \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
+    fsth0 = float32_abs(fdt0 >> 32);                            \
+    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
+    fsth1 = float32_abs(fdt1 >> 32);                            \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
+    update_fcr31();                                             \
+    if (cl)                                                     \
+        SET_FP_COND(cc, env->active_fpu);                       \
+    else                                                        \
+        CLEAR_FP_COND(cc, env->active_fpu);                     \
+    if (ch)                                                     \
+        SET_FP_COND(cc + 1, env->active_fpu);                   \
+    else                                                        \
+        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered() is still called. */
+FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
diff --git a/qemu-0.15.x/target-mips/translate.c b/qemu-0.15.x/target-mips/translate.c
new file mode 100644
index 0000000..2848c6a
--- /dev/null
+++ b/qemu-0.15.x/target-mips/translate.c
@@ -0,0 +1,12744 @@
+/*
+ *  MIPS32 emulation for qemu: main translation routines.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+//#define MIPS_DEBUG_DISAS
+//#define MIPS_DEBUG_SIGN_EXTENSIONS
+
+/* MIPS major opcodes */
+#define MASK_OP_MAJOR(op)  (op & (0x3F << 26))
+
+enum {
+    /* indirect opcode tables */
+    OPC_SPECIAL  = (0x00 << 26),
+    OPC_REGIMM   = (0x01 << 26),
+    OPC_CP0      = (0x10 << 26),
+    OPC_CP1      = (0x11 << 26),
+    OPC_CP2      = (0x12 << 26),
+    OPC_CP3      = (0x13 << 26),
+    OPC_SPECIAL2 = (0x1C << 26),
+    OPC_SPECIAL3 = (0x1F << 26),
+    /* arithmetic with immediate */
+    OPC_ADDI     = (0x08 << 26),
+    OPC_ADDIU    = (0x09 << 26),
+    OPC_SLTI     = (0x0A << 26),
+    OPC_SLTIU    = (0x0B << 26),
+    /* logic with immediate */
+    OPC_ANDI     = (0x0C << 26),
+    OPC_ORI      = (0x0D << 26),
+    OPC_XORI     = (0x0E << 26),
+    OPC_LUI      = (0x0F << 26),
+    /* arithmetic with immediate */
+    OPC_DADDI    = (0x18 << 26),
+    OPC_DADDIU   = (0x19 << 26),
+    /* Jump and branches */
+    OPC_J        = (0x02 << 26),
+    OPC_JAL      = (0x03 << 26),
+    OPC_JALS     = OPC_JAL | 0x5,
+    OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
+    OPC_BEQL     = (0x14 << 26),
+    OPC_BNE      = (0x05 << 26),
+    OPC_BNEL     = (0x15 << 26),
+    OPC_BLEZ     = (0x06 << 26),
+    OPC_BLEZL    = (0x16 << 26),
+    OPC_BGTZ     = (0x07 << 26),
+    OPC_BGTZL    = (0x17 << 26),
+    OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
+    OPC_JALXS    = OPC_JALX | 0x5,
+    /* Load and stores */
+    OPC_LDL      = (0x1A << 26),
+    OPC_LDR      = (0x1B << 26),
+    OPC_LB       = (0x20 << 26),
+    OPC_LH       = (0x21 << 26),
+    OPC_LWL      = (0x22 << 26),
+    OPC_LW       = (0x23 << 26),
+    OPC_LWPC     = OPC_LW | 0x5,
+    OPC_LBU      = (0x24 << 26),
+    OPC_LHU      = (0x25 << 26),
+    OPC_LWR      = (0x26 << 26),
+    OPC_LWU      = (0x27 << 26),
+    OPC_SB       = (0x28 << 26),
+    OPC_SH       = (0x29 << 26),
+    OPC_SWL      = (0x2A << 26),
+    OPC_SW       = (0x2B << 26),
+    OPC_SDL      = (0x2C << 26),
+    OPC_SDR      = (0x2D << 26),
+    OPC_SWR      = (0x2E << 26),
+    OPC_LL       = (0x30 << 26),
+    OPC_LLD      = (0x34 << 26),
+    OPC_LD       = (0x37 << 26),
+    OPC_LDPC     = OPC_LD | 0x5,
+    OPC_SC       = (0x38 << 26),
+    OPC_SCD      = (0x3C << 26),
+    OPC_SD       = (0x3F << 26),
+    /* Floating point load/store */
+    OPC_LWC1     = (0x31 << 26),
+    OPC_LWC2     = (0x32 << 26),
+    OPC_LDC1     = (0x35 << 26),
+    OPC_LDC2     = (0x36 << 26),
+    OPC_SWC1     = (0x39 << 26),
+    OPC_SWC2     = (0x3A << 26),
+    OPC_SDC1     = (0x3D << 26),
+    OPC_SDC2     = (0x3E << 26),
+    /* MDMX ASE specific */
+    OPC_MDMX     = (0x1E << 26),
+    /* Cache and prefetch */
+    OPC_CACHE    = (0x2F << 26),
+    OPC_PREF     = (0x33 << 26),
+    /* Reserved major opcode */
+    OPC_MAJOR3B_RESERVED = (0x3B << 26),
+};
+
+/* MIPS special opcodes */
+#define MASK_SPECIAL(op)   MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    /* Shifts */
+    OPC_SLL      = 0x00 | OPC_SPECIAL,
+    /* NOP is SLL r0, r0, 0   */
+    /* SSNOP is SLL r0, r0, 1 */
+    /* EHB is SLL r0, r0, 3 */
+    OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
+    OPC_ROTR     = OPC_SRL | (1 << 21),
+    OPC_SRA      = 0x03 | OPC_SPECIAL,
+    OPC_SLLV     = 0x04 | OPC_SPECIAL,
+    OPC_SRLV     = 0x06 | OPC_SPECIAL, /* also ROTRV */
+    OPC_ROTRV    = OPC_SRLV | (1 << 6),
+    OPC_SRAV     = 0x07 | OPC_SPECIAL,
+    OPC_DSLLV    = 0x14 | OPC_SPECIAL,
+    OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
+    OPC_DROTRV   = OPC_DSRLV | (1 << 6),
+    OPC_DSRAV    = 0x17 | OPC_SPECIAL,
+    OPC_DSLL     = 0x38 | OPC_SPECIAL,
+    OPC_DSRL     = 0x3A | OPC_SPECIAL, /* also DROTR */
+    OPC_DROTR    = OPC_DSRL | (1 << 21),
+    OPC_DSRA     = 0x3B | OPC_SPECIAL,
+    OPC_DSLL32   = 0x3C | OPC_SPECIAL,
+    OPC_DSRL32   = 0x3E | OPC_SPECIAL, /* also DROTR32 */
+    OPC_DROTR32  = OPC_DSRL32 | (1 << 21),
+    OPC_DSRA32   = 0x3F | OPC_SPECIAL,
+    /* Multiplication / division */
+    OPC_MULT     = 0x18 | OPC_SPECIAL,
+    OPC_MULTU    = 0x19 | OPC_SPECIAL,
+    OPC_DIV      = 0x1A | OPC_SPECIAL,
+    OPC_DIVU     = 0x1B | OPC_SPECIAL,
+    OPC_DMULT    = 0x1C | OPC_SPECIAL,
+    OPC_DMULTU   = 0x1D | OPC_SPECIAL,
+    OPC_DDIV     = 0x1E | OPC_SPECIAL,
+    OPC_DDIVU    = 0x1F | OPC_SPECIAL,
+    /* 2 registers arithmetic / logic */
+    OPC_ADD      = 0x20 | OPC_SPECIAL,
+    OPC_ADDU     = 0x21 | OPC_SPECIAL,
+    OPC_SUB      = 0x22 | OPC_SPECIAL,
+    OPC_SUBU     = 0x23 | OPC_SPECIAL,
+    OPC_AND      = 0x24 | OPC_SPECIAL,
+    OPC_OR       = 0x25 | OPC_SPECIAL,
+    OPC_XOR      = 0x26 | OPC_SPECIAL,
+    OPC_NOR      = 0x27 | OPC_SPECIAL,
+    OPC_SLT      = 0x2A | OPC_SPECIAL,
+    OPC_SLTU     = 0x2B | OPC_SPECIAL,
+    OPC_DADD     = 0x2C | OPC_SPECIAL,
+    OPC_DADDU    = 0x2D | OPC_SPECIAL,
+    OPC_DSUB     = 0x2E | OPC_SPECIAL,
+    OPC_DSUBU    = 0x2F | OPC_SPECIAL,
+    /* Jumps */
+    OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
+    OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
+    OPC_JALRC    = OPC_JALR | (0x5 << 6),
+    OPC_JALRS    = 0x10 | OPC_SPECIAL | (0x5 << 6),
+    /* Traps */
+    OPC_TGE      = 0x30 | OPC_SPECIAL,
+    OPC_TGEU     = 0x31 | OPC_SPECIAL,
+    OPC_TLT      = 0x32 | OPC_SPECIAL,
+    OPC_TLTU     = 0x33 | OPC_SPECIAL,
+    OPC_TEQ      = 0x34 | OPC_SPECIAL,
+    OPC_TNE      = 0x36 | OPC_SPECIAL,
+    /* HI / LO registers load & stores */
+    OPC_MFHI     = 0x10 | OPC_SPECIAL,
+    OPC_MTHI     = 0x11 | OPC_SPECIAL,
+    OPC_MFLO     = 0x12 | OPC_SPECIAL,
+    OPC_MTLO     = 0x13 | OPC_SPECIAL,
+    /* Conditional moves */
+    OPC_MOVZ     = 0x0A | OPC_SPECIAL,
+    OPC_MOVN     = 0x0B | OPC_SPECIAL,
+
+    OPC_MOVCI    = 0x01 | OPC_SPECIAL,
+
+    /* Special */
+    OPC_PMON     = 0x05 | OPC_SPECIAL, /* unofficial */
+    OPC_SYSCALL  = 0x0C | OPC_SPECIAL,
+    OPC_BREAK    = 0x0D | OPC_SPECIAL,
+    OPC_SPIM     = 0x0E | OPC_SPECIAL, /* unofficial */
+    OPC_SYNC     = 0x0F | OPC_SPECIAL,
+
+    OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
+    OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
+    OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
+    OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
+    OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
+    OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
+    OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
+};
+
+/* Multiplication variants of the vr54xx. */
+#define MASK_MUL_VR54XX(op)   MASK_SPECIAL(op) | (op & (0x1F << 6))
+
+enum {
+    OPC_VR54XX_MULS    = (0x03 << 6) | OPC_MULT,
+    OPC_VR54XX_MULSU   = (0x03 << 6) | OPC_MULTU,
+    OPC_VR54XX_MACC    = (0x05 << 6) | OPC_MULT,
+    OPC_VR54XX_MACCU   = (0x05 << 6) | OPC_MULTU,
+    OPC_VR54XX_MSAC    = (0x07 << 6) | OPC_MULT,
+    OPC_VR54XX_MSACU   = (0x07 << 6) | OPC_MULTU,
+    OPC_VR54XX_MULHI   = (0x09 << 6) | OPC_MULT,
+    OPC_VR54XX_MULHIU  = (0x09 << 6) | OPC_MULTU,
+    OPC_VR54XX_MULSHI  = (0x0B << 6) | OPC_MULT,
+    OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
+    OPC_VR54XX_MACCHI  = (0x0D << 6) | OPC_MULT,
+    OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU,
+    OPC_VR54XX_MSACHI  = (0x0F << 6) | OPC_MULT,
+    OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU,
+};
+
+/* REGIMM (rt field) opcodes */
+#define MASK_REGIMM(op)    MASK_OP_MAJOR(op) | (op & (0x1F << 16))
+
+enum {
+    OPC_BLTZ     = (0x00 << 16) | OPC_REGIMM,
+    OPC_BLTZL    = (0x02 << 16) | OPC_REGIMM,
+    OPC_BGEZ     = (0x01 << 16) | OPC_REGIMM,
+    OPC_BGEZL    = (0x03 << 16) | OPC_REGIMM,
+    OPC_BLTZAL   = (0x10 << 16) | OPC_REGIMM,
+    OPC_BLTZALS  = OPC_BLTZAL | 0x5, /* microMIPS */
+    OPC_BLTZALL  = (0x12 << 16) | OPC_REGIMM,
+    OPC_BGEZAL   = (0x11 << 16) | OPC_REGIMM,
+    OPC_BGEZALS  = OPC_BGEZAL | 0x5, /* microMIPS */
+    OPC_BGEZALL  = (0x13 << 16) | OPC_REGIMM,
+    OPC_TGEI     = (0x08 << 16) | OPC_REGIMM,
+    OPC_TGEIU    = (0x09 << 16) | OPC_REGIMM,
+    OPC_TLTI     = (0x0A << 16) | OPC_REGIMM,
+    OPC_TLTIU    = (0x0B << 16) | OPC_REGIMM,
+    OPC_TEQI     = (0x0C << 16) | OPC_REGIMM,
+    OPC_TNEI     = (0x0E << 16) | OPC_REGIMM,
+    OPC_SYNCI    = (0x1F << 16) | OPC_REGIMM,
+};
+
+/* Special2 opcodes */
+#define MASK_SPECIAL2(op)  MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    /* Multiply & xxx operations */
+    OPC_MADD     = 0x00 | OPC_SPECIAL2,
+    OPC_MADDU    = 0x01 | OPC_SPECIAL2,
+    OPC_MUL      = 0x02 | OPC_SPECIAL2,
+    OPC_MSUB     = 0x04 | OPC_SPECIAL2,
+    OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
+    /* Loongson 2F */
+    OPC_MULT_G_2F   = 0x10 | OPC_SPECIAL2,
+    OPC_DMULT_G_2F  = 0x11 | OPC_SPECIAL2,
+    OPC_MULTU_G_2F  = 0x12 | OPC_SPECIAL2,
+    OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
+    OPC_DIV_G_2F    = 0x14 | OPC_SPECIAL2,
+    OPC_DDIV_G_2F   = 0x15 | OPC_SPECIAL2,
+    OPC_DIVU_G_2F   = 0x16 | OPC_SPECIAL2,
+    OPC_DDIVU_G_2F  = 0x17 | OPC_SPECIAL2,
+    OPC_MOD_G_2F    = 0x1c | OPC_SPECIAL2,
+    OPC_DMOD_G_2F   = 0x1d | OPC_SPECIAL2,
+    OPC_MODU_G_2F   = 0x1e | OPC_SPECIAL2,
+    OPC_DMODU_G_2F  = 0x1f | OPC_SPECIAL2,
+    /* Misc */
+    OPC_CLZ      = 0x20 | OPC_SPECIAL2,
+    OPC_CLO      = 0x21 | OPC_SPECIAL2,
+    OPC_DCLZ     = 0x24 | OPC_SPECIAL2,
+    OPC_DCLO     = 0x25 | OPC_SPECIAL2,
+    /* Special */
+    OPC_SDBBP    = 0x3F | OPC_SPECIAL2,
+};
+
+/* Special3 opcodes */
+#define MASK_SPECIAL3(op)  MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    OPC_EXT      = 0x00 | OPC_SPECIAL3,
+    OPC_DEXTM    = 0x01 | OPC_SPECIAL3,
+    OPC_DEXTU    = 0x02 | OPC_SPECIAL3,
+    OPC_DEXT     = 0x03 | OPC_SPECIAL3,
+    OPC_INS      = 0x04 | OPC_SPECIAL3,
+    OPC_DINSM    = 0x05 | OPC_SPECIAL3,
+    OPC_DINSU    = 0x06 | OPC_SPECIAL3,
+    OPC_DINS     = 0x07 | OPC_SPECIAL3,
+    OPC_FORK     = 0x08 | OPC_SPECIAL3,
+    OPC_YIELD    = 0x09 | OPC_SPECIAL3,
+    OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
+    OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
+    OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
+
+    /* Loongson 2E */
+    OPC_MULT_G_2E   = 0x18 | OPC_SPECIAL3,
+    OPC_MULTU_G_2E  = 0x19 | OPC_SPECIAL3,
+    OPC_DIV_G_2E    = 0x1A | OPC_SPECIAL3,
+    OPC_DIVU_G_2E   = 0x1B | OPC_SPECIAL3,
+    OPC_DMULT_G_2E  = 0x1C | OPC_SPECIAL3,
+    OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3,
+    OPC_DDIV_G_2E   = 0x1E | OPC_SPECIAL3,
+    OPC_DDIVU_G_2E  = 0x1F | OPC_SPECIAL3,
+    OPC_MOD_G_2E    = 0x22 | OPC_SPECIAL3,
+    OPC_MODU_G_2E   = 0x23 | OPC_SPECIAL3,
+    OPC_DMOD_G_2E   = 0x26 | OPC_SPECIAL3,
+    OPC_DMODU_G_2E  = 0x27 | OPC_SPECIAL3,
+};
+
+/* BSHFL opcodes */
+#define MASK_BSHFL(op)     MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
+enum {
+    OPC_WSBH     = (0x02 << 6) | OPC_BSHFL,
+    OPC_SEB      = (0x10 << 6) | OPC_BSHFL,
+    OPC_SEH      = (0x18 << 6) | OPC_BSHFL,
+};
+
+/* DBSHFL opcodes */
+#define MASK_DBSHFL(op)    MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
+enum {
+    OPC_DSBH     = (0x02 << 6) | OPC_DBSHFL,
+    OPC_DSHD     = (0x05 << 6) | OPC_DBSHFL,
+};
+
+/* Coprocessor 0 (rs field) */
+#define MASK_CP0(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC0     = (0x00 << 21) | OPC_CP0,
+    OPC_DMFC0    = (0x01 << 21) | OPC_CP0,
+    OPC_MTC0     = (0x04 << 21) | OPC_CP0,
+    OPC_DMTC0    = (0x05 << 21) | OPC_CP0,
+    OPC_MFTR     = (0x08 << 21) | OPC_CP0,
+    OPC_RDPGPR   = (0x0A << 21) | OPC_CP0,
+    OPC_MFMC0    = (0x0B << 21) | OPC_CP0,
+    OPC_MTTR     = (0x0C << 21) | OPC_CP0,
+    OPC_WRPGPR   = (0x0E << 21) | OPC_CP0,
+    OPC_C0       = (0x10 << 21) | OPC_CP0,
+    OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
+    OPC_C0_LAST  = (0x1F << 21) | OPC_CP0,
+};
+
+/* MFMC0 opcodes */
+#define MASK_MFMC0(op)     MASK_CP0(op) | (op & 0xFFFF)
+
+enum {
+    OPC_DMT      = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_EMT      = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_DVPE     = 0x01 | (0 << 5) | OPC_MFMC0,
+    OPC_EVPE     = 0x01 | (1 << 5) | OPC_MFMC0,
+    OPC_DI       = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
+    OPC_EI       = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
+};
+
+/* Coprocessor 0 (with rs == C0) */
+#define MASK_C0(op)        MASK_CP0(op) | (op & 0x3F)
+
+enum {
+    OPC_TLBR     = 0x01 | OPC_C0,
+    OPC_TLBWI    = 0x02 | OPC_C0,
+    OPC_TLBWR    = 0x06 | OPC_C0,
+    OPC_TLBP     = 0x08 | OPC_C0,
+    OPC_RFE      = 0x10 | OPC_C0,
+    OPC_ERET     = 0x18 | OPC_C0,
+    OPC_DERET    = 0x1F | OPC_C0,
+    OPC_WAIT     = 0x20 | OPC_C0,
+};
+
+/* Coprocessor 1 (rs field) */
+#define MASK_CP1(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+/* Values for the fmt field in FP instructions */
+enum {
+    /* 0 - 15 are reserved */
+    FMT_S = 16,          /* single fp */
+    FMT_D = 17,          /* double fp */
+    FMT_E = 18,          /* extended fp */
+    FMT_Q = 19,          /* quad fp */
+    FMT_W = 20,          /* 32-bit fixed */
+    FMT_L = 21,          /* 64-bit fixed */
+    FMT_PS = 22,         /* paired single fp */
+    /* 23 - 31 are reserved */
+};
+
+enum {
+    OPC_MFC1     = (0x00 << 21) | OPC_CP1,
+    OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
+    OPC_CFC1     = (0x02 << 21) | OPC_CP1,
+    OPC_MFHC1    = (0x03 << 21) | OPC_CP1,
+    OPC_MTC1     = (0x04 << 21) | OPC_CP1,
+    OPC_DMTC1    = (0x05 << 21) | OPC_CP1,
+    OPC_CTC1     = (0x06 << 21) | OPC_CP1,
+    OPC_MTHC1    = (0x07 << 21) | OPC_CP1,
+    OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
+    OPC_BC1ANY2  = (0x09 << 21) | OPC_CP1,
+    OPC_BC1ANY4  = (0x0A << 21) | OPC_CP1,
+    OPC_S_FMT    = (FMT_S << 21) | OPC_CP1,
+    OPC_D_FMT    = (FMT_D << 21) | OPC_CP1,
+    OPC_E_FMT    = (FMT_E << 21) | OPC_CP1,
+    OPC_Q_FMT    = (FMT_Q << 21) | OPC_CP1,
+    OPC_W_FMT    = (FMT_W << 21) | OPC_CP1,
+    OPC_L_FMT    = (FMT_L << 21) | OPC_CP1,
+    OPC_PS_FMT   = (FMT_PS << 21) | OPC_CP1,
+};
+
+#define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
+#define MASK_BC1(op)            MASK_CP1(op) | (op & (0x3 << 16))
+
+enum {
+    OPC_BC1F     = (0x00 << 16) | OPC_BC1,
+    OPC_BC1T     = (0x01 << 16) | OPC_BC1,
+    OPC_BC1FL    = (0x02 << 16) | OPC_BC1,
+    OPC_BC1TL    = (0x03 << 16) | OPC_BC1,
+};
+
+enum {
+    OPC_BC1FANY2     = (0x00 << 16) | OPC_BC1ANY2,
+    OPC_BC1TANY2     = (0x01 << 16) | OPC_BC1ANY2,
+};
+
+enum {
+    OPC_BC1FANY4     = (0x00 << 16) | OPC_BC1ANY4,
+    OPC_BC1TANY4     = (0x01 << 16) | OPC_BC1ANY4,
+};
+
+#define MASK_CP2(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC2    = (0x00 << 21) | OPC_CP2,
+    OPC_DMFC2   = (0x01 << 21) | OPC_CP2,
+    OPC_CFC2    = (0x02 << 21) | OPC_CP2,
+    OPC_MFHC2   = (0x03 << 21) | OPC_CP2,
+    OPC_MTC2    = (0x04 << 21) | OPC_CP2,
+    OPC_DMTC2   = (0x05 << 21) | OPC_CP2,
+    OPC_CTC2    = (0x06 << 21) | OPC_CP2,
+    OPC_MTHC2   = (0x07 << 21) | OPC_CP2,
+    OPC_BC2     = (0x08 << 21) | OPC_CP2,
+};
+
+#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    OPC_LWXC1   = 0x00 | OPC_CP3,
+    OPC_LDXC1   = 0x01 | OPC_CP3,
+    OPC_LUXC1   = 0x05 | OPC_CP3,
+    OPC_SWXC1   = 0x08 | OPC_CP3,
+    OPC_SDXC1   = 0x09 | OPC_CP3,
+    OPC_SUXC1   = 0x0D | OPC_CP3,
+    OPC_PREFX   = 0x0F | OPC_CP3,
+    OPC_ALNV_PS = 0x1E | OPC_CP3,
+    OPC_MADD_S  = 0x20 | OPC_CP3,
+    OPC_MADD_D  = 0x21 | OPC_CP3,
+    OPC_MADD_PS = 0x26 | OPC_CP3,
+    OPC_MSUB_S  = 0x28 | OPC_CP3,
+    OPC_MSUB_D  = 0x29 | OPC_CP3,
+    OPC_MSUB_PS = 0x2E | OPC_CP3,
+    OPC_NMADD_S = 0x30 | OPC_CP3,
+    OPC_NMADD_D = 0x31 | OPC_CP3,
+    OPC_NMADD_PS= 0x36 | OPC_CP3,
+    OPC_NMSUB_S = 0x38 | OPC_CP3,
+    OPC_NMSUB_D = 0x39 | OPC_CP3,
+    OPC_NMSUB_PS= 0x3E | OPC_CP3,
+};
+
+/* global register indices */
+static TCGv_ptr cpu_env;
+static TCGv cpu_gpr[32], cpu_PC;
+static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC];
+static TCGv cpu_dspctrl, btarget, bcond;
+static TCGv_i32 hflags;
+static TCGv_i32 fpu_fcr0, fpu_fcr31;
+
+static uint32_t gen_opc_hflags[OPC_BUF_SIZE];
+
+#include "gen-icount.h"
+
+#define gen_helper_0i(name, arg) do {                             \
+    TCGv_i32 helper_tmp = tcg_const_i32(arg);                     \
+    gen_helper_##name(helper_tmp);                                \
+    tcg_temp_free_i32(helper_tmp);                                \
+    } while(0)
+
+#define gen_helper_1i(name, arg1, arg2) do {                      \
+    TCGv_i32 helper_tmp = tcg_const_i32(arg2);                    \
+    gen_helper_##name(arg1, helper_tmp);                          \
+    tcg_temp_free_i32(helper_tmp);                                \
+    } while(0)
+
+#define gen_helper_2i(name, arg1, arg2, arg3) do {                \
+    TCGv_i32 helper_tmp = tcg_const_i32(arg3);                    \
+    gen_helper_##name(arg1, arg2, helper_tmp);                    \
+    tcg_temp_free_i32(helper_tmp);                                \
+    } while(0)
+
+#define gen_helper_3i(name, arg1, arg2, arg3, arg4) do {          \
+    TCGv_i32 helper_tmp = tcg_const_i32(arg4);                    \
+    gen_helper_##name(arg1, arg2, arg3, helper_tmp);              \
+    tcg_temp_free_i32(helper_tmp);                                \
+    } while(0)
+
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    target_ulong pc, saved_pc;
+    uint32_t opcode;
+    int singlestep_enabled;
+    /* Routine used to access memory */
+    int mem_idx;
+    uint32_t hflags, saved_hflags;
+    int bstate;
+    target_ulong btarget;
+} DisasContext;
+
+enum {
+    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
+                      * exception condition */
+    BS_STOP     = 1, /* We want to stop translation for any reason */
+    BS_BRANCH   = 2, /* We reached a branch condition     */
+    BS_EXCP     = 3, /* We reached an exception condition */
+};
+
+static const char *regnames[] =
+    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
+
+static const char *regnames_HI[] =
+    { "HI0", "HI1", "HI2", "HI3", };
+
+static const char *regnames_LO[] =
+    { "LO0", "LO1", "LO2", "LO3", };
+
+static const char *regnames_ACX[] =
+    { "ACX0", "ACX1", "ACX2", "ACX3", };
+
+static const char *fregnames[] =
+    { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+      "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+      "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+      "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
+
+#ifdef MIPS_DEBUG_DISAS
+#define MIPS_DEBUG(fmt, ...)                         \
+        qemu_log_mask(CPU_LOG_TB_IN_ASM,                \
+                       TARGET_FMT_lx ": %08x " fmt "\n", \
+                       ctx->pc, ctx->opcode , ## __VA_ARGS__)
+#define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#define MIPS_DEBUG(fmt, ...) do { } while(0)
+#define LOG_DISAS(...) do { } while (0)
+#endif
+
+#define MIPS_INVAL(op)                                                        \
+do {                                                                          \
+    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
+               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
+} while (0)
+
+/* General purpose registers moves. */
+static inline void gen_load_gpr (TCGv t, int reg)
+{
+    if (reg == 0)
+        tcg_gen_movi_tl(t, 0);
+    else
+        tcg_gen_mov_tl(t, cpu_gpr[reg]);
+}
+
+static inline void gen_store_gpr (TCGv t, int reg)
+{
+    if (reg != 0)
+        tcg_gen_mov_tl(cpu_gpr[reg], t);
+}
+
+/* Moves to/from ACX register.  */
+static inline void gen_load_ACX (TCGv t, int reg)
+{
+    tcg_gen_mov_tl(t, cpu_ACX[reg]);
+}
+
+static inline void gen_store_ACX (TCGv t, int reg)
+{
+    tcg_gen_mov_tl(cpu_ACX[reg], t);
+}
+
+/* Moves to/from shadow registers. */
+static inline void gen_load_srsgpr (int from, int to)
+{
+    TCGv t0 = tcg_temp_new();
+
+    if (from == 0)
+        tcg_gen_movi_tl(t0, 0);
+    else {
+        TCGv_i32 t2 = tcg_temp_new_i32();
+        TCGv_ptr addr = tcg_temp_new_ptr();
+
+        tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUState, CP0_SRSCtl));
+        tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS);
+        tcg_gen_andi_i32(t2, t2, 0xf);
+        tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32);
+        tcg_gen_ext_i32_ptr(addr, t2);
+        tcg_gen_add_ptr(addr, cpu_env, addr);
+
+        tcg_gen_ld_tl(t0, addr, sizeof(target_ulong) * from);
+        tcg_temp_free_ptr(addr);
+        tcg_temp_free_i32(t2);
+    }
+    gen_store_gpr(t0, to);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_store_srsgpr (int from, int to)
+{
+    if (to != 0) {
+        TCGv t0 = tcg_temp_new();
+        TCGv_i32 t2 = tcg_temp_new_i32();
+        TCGv_ptr addr = tcg_temp_new_ptr();
+
+        gen_load_gpr(t0, from);
+        tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUState, CP0_SRSCtl));
+        tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS);
+        tcg_gen_andi_i32(t2, t2, 0xf);
+        tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32);
+        tcg_gen_ext_i32_ptr(addr, t2);
+        tcg_gen_add_ptr(addr, cpu_env, addr);
+
+        tcg_gen_st_tl(t0, addr, sizeof(target_ulong) * to);
+        tcg_temp_free_ptr(addr);
+        tcg_temp_free_i32(t2);
+        tcg_temp_free(t0);
+    }
+}
+
+/* Floating point register moves. */
+static inline void gen_load_fpr32 (TCGv_i32 t, int reg)
+{
+    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX]));
+}
+
+static inline void gen_store_fpr32 (TCGv_i32 t, int reg)
+{
+    tcg_gen_st_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX]));
+}
+
+static inline void gen_load_fpr32h (TCGv_i32 t, int reg)
+{
+    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX]));
+}
+
+static inline void gen_store_fpr32h (TCGv_i32 t, int reg)
+{
+    tcg_gen_st_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX]));
+}
+
+static inline void gen_load_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg)
+{
+    if (ctx->hflags & MIPS_HFLAG_F64) {
+        tcg_gen_ld_i64(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].d));
+    } else {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        TCGv_i32 t1 = tcg_temp_new_i32();
+        gen_load_fpr32(t0, reg & ~1);
+        gen_load_fpr32(t1, reg | 1);
+        tcg_gen_concat_i32_i64(t, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+    }
+}
+
+static inline void gen_store_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg)
+{
+    if (ctx->hflags & MIPS_HFLAG_F64) {
+        tcg_gen_st_i64(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].d));
+    } else {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        TCGv_i32 t1 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(t1, t);
+        gen_store_fpr32(t1, reg & ~1);
+        tcg_gen_shri_i64(t0, t, 32);
+        tcg_gen_trunc_i64_i32(t1, t0);
+        gen_store_fpr32(t1, reg | 1);
+        tcg_temp_free_i32(t1);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline int get_fp_bit (int cc)
+{
+    if (cc)
+        return 24 + cc;
+    else
+        return 23;
+}
+
+/* Tests */
+static inline void gen_save_pc(target_ulong pc)
+{
+    tcg_gen_movi_tl(cpu_PC, pc);
+}
+
+static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
+{
+    LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags);
+    if (do_save_pc && ctx->pc != ctx->saved_pc) {
+        gen_save_pc(ctx->pc);
+        ctx->saved_pc = ctx->pc;
+    }
+    if (ctx->hflags != ctx->saved_hflags) {
+        tcg_gen_movi_i32(hflags, ctx->hflags);
+        ctx->saved_hflags = ctx->hflags;
+        switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) {
+        case MIPS_HFLAG_BR:
+            break;
+        case MIPS_HFLAG_BC:
+        case MIPS_HFLAG_BL:
+        case MIPS_HFLAG_B:
+            tcg_gen_movi_tl(btarget, ctx->btarget);
+            break;
+        }
+    }
+}
+
+static inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
+{
+    ctx->saved_hflags = ctx->hflags;
+    switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) {
+    case MIPS_HFLAG_BR:
+        break;
+    case MIPS_HFLAG_BC:
+    case MIPS_HFLAG_BL:
+    case MIPS_HFLAG_B:
+        ctx->btarget = env->btarget;
+        break;
+    }
+}
+
+static inline void
+generate_exception_err (DisasContext *ctx, int excp, int err)
+{
+    TCGv_i32 texcp = tcg_const_i32(excp);
+    TCGv_i32 terr = tcg_const_i32(err);
+    save_cpu_state(ctx, 1);
+    gen_helper_raise_exception_err(texcp, terr);
+    tcg_temp_free_i32(terr);
+    tcg_temp_free_i32(texcp);
+}
+
+static inline void
+generate_exception (DisasContext *ctx, int excp)
+{
+    save_cpu_state(ctx, 1);
+    gen_helper_0i(raise_exception, excp);
+}
+
+/* Addresses computation */
+static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1)
+{
+    tcg_gen_add_tl(ret, arg0, arg1);
+
+#if defined(TARGET_MIPS64)
+    /* For compatibility with 32-bit code, data reference in user mode
+       with Status_UX = 0 should be casted to 32-bit and sign extended.
+       See the MIPS64 PRA manual, section 4.10. */
+    if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
+        !(ctx->hflags & MIPS_HFLAG_UX)) {
+        tcg_gen_ext32s_i64(ret, ret);
+    }
+#endif
+}
+
+static inline void check_cp0_enabled(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
+        generate_exception_err(ctx, EXCP_CpU, 0);
+}
+
+static inline void check_cp1_enabled(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU)))
+        generate_exception_err(ctx, EXCP_CpU, 1);
+}
+
+/* Verify that the processor is running with COP1X instructions enabled.
+   This is associated with the nabla symbol in the MIPS32 and MIPS64
+   opcode tables.  */
+
+static inline void check_cop1x(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* Verify that the processor is running with 64-bit floating-point
+   operations enabled.  */
+
+static inline void check_cp1_64bitmode(DisasContext *ctx)
+{
+    if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/*
+ * Verify if floating point register is valid; an operation is not defined
+ * if bit 0 of any register specification is set and the FR bit in the
+ * Status register equals zero, since the register numbers specify an
+ * even-odd pair of adjacent coprocessor general registers. When the FR bit
+ * in the Status register equals one, both even and odd register numbers
+ * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers.
+ *
+ * Multiple 64 bit wide registers can be checked by calling
+ * gen_op_cp1_registers(freg1 | freg2 | ... | fregN);
+ */
+static inline void check_cp1_registers(DisasContext *ctx, int regs)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* This code generates a "reserved instruction" exception if the
+   CPU does not support the instruction set corresponding to flags. */
+static inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
+{
+    if (unlikely(!(env->insn_flags & flags)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* This code generates a "reserved instruction" exception if 64-bit
+   instructions are not enabled. */
+static inline void check_mips_64(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_64)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* Define small wrappers for gen_load_fpr* so that we have a uniform
+   calling interface for 32 and 64-bit FPRs.  No sense in changing
+   all callers for gen_load_fpr32 when we need the CTX parameter for
+   this one use.  */
+#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y)
+#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y)
+#define FOP_CONDS(type, abs, fmt, ifmt, bits)                                 \
+static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n,      \
+                                               int ft, int fs, int cc)        \
+{                                                                             \
+    TCGv_i##bits fp0 = tcg_temp_new_i##bits ();                               \
+    TCGv_i##bits fp1 = tcg_temp_new_i##bits ();                               \
+    switch (ifmt) {                                                           \
+    case FMT_PS:                                                              \
+        check_cp1_64bitmode(ctx);                                             \
+        break;                                                                \
+    case FMT_D:                                                               \
+        if (abs) {                                                            \
+            check_cop1x(ctx);                                                 \
+        }                                                                     \
+        check_cp1_registers(ctx, fs | ft);                                    \
+        break;                                                                \
+    case FMT_S:                                                               \
+        if (abs) {                                                            \
+            check_cop1x(ctx);                                                 \
+        }                                                                     \
+        break;                                                                \
+    }                                                                         \
+    gen_ldcmp_fpr##bits (ctx, fp0, fs);                                       \
+    gen_ldcmp_fpr##bits (ctx, fp1, ft);                                       \
+    switch (n) {                                                              \
+    case  0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc);    break;\
+    case  1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc);   break;\
+    case  2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc);   break;\
+    case  3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc);  break;\
+    case  4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc);  break;\
+    case  5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc);  break;\
+    case  6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc);  break;\
+    case  7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc);  break;\
+    case  8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc);   break;\
+    case  9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\
+    case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc);  break;\
+    case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc);  break;\
+    case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc);   break;\
+    case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc);  break;\
+    case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc);   break;\
+    case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc);  break;\
+    default: abort();                                                         \
+    }                                                                         \
+    tcg_temp_free_i##bits (fp0);                                              \
+    tcg_temp_free_i##bits (fp1);                                              \
+}
+
+FOP_CONDS(, 0, d, FMT_D, 64)
+FOP_CONDS(abs, 1, d, FMT_D, 64)
+FOP_CONDS(, 0, s, FMT_S, 32)
+FOP_CONDS(abs, 1, s, FMT_S, 32)
+FOP_CONDS(, 0, ps, FMT_PS, 64)
+FOP_CONDS(abs, 1, ps, FMT_PS, 64)
+#undef FOP_CONDS
+#undef gen_ldcmp_fpr32
+#undef gen_ldcmp_fpr64
+
+/* load/store instructions. */
+#define OP_LD(insn,fname)                                                 \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)   \
+{                                                                         \
+    tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                        \
+}
+OP_LD(lb,ld8s);
+OP_LD(lbu,ld8u);
+OP_LD(lh,ld16s);
+OP_LD(lhu,ld16u);
+OP_LD(lw,ld32s);
+#if defined(TARGET_MIPS64)
+OP_LD(lwu,ld32u);
+OP_LD(ld,ld64);
+#endif
+#undef OP_LD
+
+#define OP_ST(insn,fname)                                                  \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx)   \
+{                                                                          \
+    tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx);                        \
+}
+OP_ST(sb,st8);
+OP_ST(sh,st16);
+OP_ST(sw,st32);
+#if defined(TARGET_MIPS64)
+OP_ST(sd,st64);
+#endif
+#undef OP_ST
+
+#ifdef CONFIG_USER_ONLY
+#define OP_LD_ATOMIC(insn,fname)                                           \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
+{                                                                          \
+    TCGv t0 = tcg_temp_new();                                              \
+    tcg_gen_mov_tl(t0, arg1);                                              \
+    tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                         \
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, lladdr));                \
+    tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval));                \
+    tcg_temp_free(t0);                                                     \
+}
+#else
+#define OP_LD_ATOMIC(insn,fname)                                           \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
+{                                                                          \
+    gen_helper_2i(insn, ret, arg1, ctx->mem_idx);                          \
+}
+#endif
+OP_LD_ATOMIC(ll,ld32s);
+#if defined(TARGET_MIPS64)
+OP_LD_ATOMIC(lld,ld64);
+#endif
+#undef OP_LD_ATOMIC
+
+#ifdef CONFIG_USER_ONLY
+#define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
+{                                                                            \
+    TCGv t0 = tcg_temp_new();                                                \
+    int l1 = gen_new_label();                                                \
+    int l2 = gen_new_label();                                                \
+                                                                             \
+    tcg_gen_andi_tl(t0, arg2, almask);                                       \
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);                              \
+    tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr));          \
+    generate_exception(ctx, EXCP_AdES);                                      \
+    gen_set_label(l1);                                                       \
+    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr));                  \
+    tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2);                            \
+    tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20));                        \
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg));                   \
+    tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUState, llnewval));              \
+    gen_helper_0i(raise_exception, EXCP_SC);                                 \
+    gen_set_label(l2);                                                       \
+    tcg_gen_movi_tl(t0, 0);                                                  \
+    gen_store_gpr(t0, rt);                                                   \
+    tcg_temp_free(t0);                                                       \
+}
+#else
+#define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
+{                                                                            \
+    TCGv t0 = tcg_temp_new();                                                \
+    gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx);                       \
+    gen_store_gpr(t0, rt);                                                   \
+    tcg_temp_free(t0);                                                       \
+}
+#endif
+OP_ST_ATOMIC(sc,st32,ld32s,0x3);
+#if defined(TARGET_MIPS64)
+OP_ST_ATOMIC(scd,st64,ld64,0x7);
+#endif
+#undef OP_ST_ATOMIC
+
+static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
+                                  int base, int16_t offset)
+{
+    if (base == 0) {
+        tcg_gen_movi_tl(addr, offset);
+    } else if (offset == 0) {
+        gen_load_gpr(addr, base);
+    } else {
+        tcg_gen_movi_tl(addr, offset);
+        gen_op_addr_add(ctx, addr, cpu_gpr[base], addr);
+    }
+}
+
+static target_ulong pc_relative_pc (DisasContext *ctx)
+{
+    target_ulong pc = ctx->pc;
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;
+
+        pc -= branch_bytes;
+    }
+
+    pc &= ~(target_ulong)3;
+    return pc;
+}
+
+/* Load */
+static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
+                    int rt, int base, int16_t offset)
+{
+    const char *opn = "ld";
+    TCGv t0, t1;
+
+    if (rt == 0 && env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) {
+        /* Loongson CPU uses a load to zero register for prefetch.
+           We emulate it as a NOP. On other CPU we must perform the
+           actual memory access. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    gen_base_offset_addr(ctx, t0, base, offset);
+
+    switch (opc) {
+#if defined(TARGET_MIPS64)
+    case OPC_LWU:
+        save_cpu_state(ctx, 0);
+        op_ld_lwu(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lwu";
+        break;
+    case OPC_LD:
+        save_cpu_state(ctx, 0);
+        op_ld_ld(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "ld";
+        break;
+    case OPC_LLD:
+        save_cpu_state(ctx, 1);
+        op_ld_lld(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lld";
+        break;
+    case OPC_LDL:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rt);
+        gen_helper_3i(ldl, t1, t1, t0, ctx->mem_idx);
+        gen_store_gpr(t1, rt);
+        opn = "ldl";
+        break;
+    case OPC_LDR:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rt);
+        gen_helper_3i(ldr, t1, t1, t0, ctx->mem_idx);
+        gen_store_gpr(t1, rt);
+        opn = "ldr";
+        break;
+    case OPC_LDPC:
+        save_cpu_state(ctx, 0);
+        tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
+        gen_op_addr_add(ctx, t0, t0, t1);
+        op_ld_ld(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "ldpc";
+        break;
+#endif
+    case OPC_LWPC:
+        save_cpu_state(ctx, 0);
+        tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
+        gen_op_addr_add(ctx, t0, t0, t1);
+        op_ld_lw(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lwpc";
+        break;
+    case OPC_LW:
+        save_cpu_state(ctx, 0);
+        op_ld_lw(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lw";
+        break;
+    case OPC_LH:
+        save_cpu_state(ctx, 0);
+        op_ld_lh(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lh";
+        break;
+    case OPC_LHU:
+        save_cpu_state(ctx, 0);
+        op_ld_lhu(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lhu";
+        break;
+    case OPC_LB:
+        save_cpu_state(ctx, 0);
+        op_ld_lb(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lb";
+        break;
+    case OPC_LBU:
+        save_cpu_state(ctx, 0);
+        op_ld_lbu(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "lbu";
+        break;
+    case OPC_LWL:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rt);
+        gen_helper_3i(lwl, t1, t1, t0, ctx->mem_idx);
+        gen_store_gpr(t1, rt);
+        opn = "lwl";
+        break;
+    case OPC_LWR:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rt);
+        gen_helper_3i(lwr, t1, t1, t0, ctx->mem_idx);
+        gen_store_gpr(t1, rt);
+        opn = "lwr";
+        break;
+    case OPC_LL:
+        save_cpu_state(ctx, 1);
+        op_ld_ll(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        opn = "ll";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* Store */
+static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
+                    int base, int16_t offset)
+{
+    const char *opn = "st";
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+#if defined(TARGET_MIPS64)
+    case OPC_SD:
+        save_cpu_state(ctx, 0);
+        op_st_sd(t1, t0, ctx);
+        opn = "sd";
+        break;
+    case OPC_SDL:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(sdl, t1, t0, ctx->mem_idx);
+        opn = "sdl";
+        break;
+    case OPC_SDR:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(sdr, t1, t0, ctx->mem_idx);
+        opn = "sdr";
+        break;
+#endif
+    case OPC_SW:
+        save_cpu_state(ctx, 0);
+        op_st_sw(t1, t0, ctx);
+        opn = "sw";
+        break;
+    case OPC_SH:
+        save_cpu_state(ctx, 0);
+        op_st_sh(t1, t0, ctx);
+        opn = "sh";
+        break;
+    case OPC_SB:
+        save_cpu_state(ctx, 0);
+        op_st_sb(t1, t0, ctx);
+        opn = "sb";
+        break;
+    case OPC_SWL:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(swl, t1, t0, ctx->mem_idx);
+        opn = "swl";
+        break;
+    case OPC_SWR:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(swr, t1, t0, ctx->mem_idx);
+        opn = "swr";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+
+/* Store conditional */
+static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
+                         int base, int16_t offset)
+{
+    const char *opn = "st_cond";
+    TCGv t0, t1;
+
+    t0 = tcg_temp_local_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+    /* Don't do NOP if destination is zero: we must perform the actual
+       memory access. */
+
+    t1 = tcg_temp_local_new();
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+#if defined(TARGET_MIPS64)
+    case OPC_SCD:
+        save_cpu_state(ctx, 1);
+        op_st_scd(t1, t0, rt, ctx);
+        opn = "scd";
+        break;
+#endif
+    case OPC_SC:
+        save_cpu_state(ctx, 1);
+        op_st_sc(t1, t0, rt, ctx);
+        opn = "sc";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+}
+
+/* Load and store */
+static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
+                          int base, int16_t offset)
+{
+    const char *opn = "flt_ldst";
+    TCGv t0 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+    /* Don't do NOP if destination is zero: we must perform the actual
+       memory access. */
+    switch (opc) {
+    case OPC_LWC1:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx);
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32(fp0, ft);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "lwc1";
+        break;
+    case OPC_SWC1:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv t1 = tcg_temp_new();
+
+            gen_load_fpr32(fp0, ft);
+            tcg_gen_extu_i32_tl(t1, fp0);
+            tcg_gen_qemu_st32(t1, t0, ctx->mem_idx);
+            tcg_temp_free(t1);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "swc1";
+        break;
+    case OPC_LDC1:
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+            gen_store_fpr64(ctx, fp0, ft);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "ldc1";
+        break;
+    case OPC_SDC1:
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, ft);
+            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "sdc1";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
+ out:
+    tcg_temp_free(t0);
+}
+
+static void gen_cop1_ldst(CPUState *env, DisasContext *ctx,
+                          uint32_t op, int rt, int rs, int16_t imm)
+{
+    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+        check_cp1_enabled(ctx);
+        gen_flt_ldst(ctx, op, rt, rs, imm);
+    } else {
+        generate_exception_err(ctx, EXCP_CpU, 1);
+    }
+}
+
+/* Arithmetic with immediate operand */
+static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
+                           int rt, int rs, int16_t imm)
+{
+    target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */
+    const char *opn = "imm arith";
+
+    if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
+        /* If no destination, treat it as a NOP.
+           For addi, we must generate the overflow exception when needed. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+    switch (opc) {
+    case OPC_ADDI:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            tcg_gen_addi_tl(t0, t1, uimm);
+            tcg_gen_ext32s_tl(t0, t0);
+
+            tcg_gen_xori_tl(t1, t1, ~uimm);
+            tcg_gen_xori_tl(t2, t0, uimm);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of same sign, result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            tcg_gen_ext32s_tl(t0, t0);
+            gen_store_gpr(t0, rt);
+            tcg_temp_free(t0);
+        }
+        opn = "addi";
+        break;
+    case OPC_ADDIU:
+        if (rs != 0) {
+            tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+            tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
+        }
+        opn = "addiu";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DADDI:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            tcg_gen_addi_tl(t0, t1, uimm);
+
+            tcg_gen_xori_tl(t1, t1, ~uimm);
+            tcg_gen_xori_tl(t2, t0, uimm);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of same sign, result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            gen_store_gpr(t0, rt);
+            tcg_temp_free(t0);
+        }
+        opn = "daddi";
+        break;
+    case OPC_DADDIU:
+        if (rs != 0) {
+            tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
+        }
+        opn = "daddiu";
+        break;
+#endif
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
+}
+
+/* Logic with immediate operand */
+static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm)
+{
+    target_ulong uimm;
+    const char *opn = "imm logic";
+
+    if (rt == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+    uimm = (uint16_t)imm;
+    switch (opc) {
+    case OPC_ANDI:
+        if (likely(rs != 0))
+            tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        else
+            tcg_gen_movi_tl(cpu_gpr[rt], 0);
+        opn = "andi";
+        break;
+    case OPC_ORI:
+        if (rs != 0)
+            tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        else
+            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
+        opn = "ori";
+        break;
+    case OPC_XORI:
+        if (likely(rs != 0))
+            tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
+        else
+            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
+        opn = "xori";
+        break;
+    case OPC_LUI:
+        tcg_gen_movi_tl(cpu_gpr[rt], imm << 16);
+        opn = "lui";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
+}
+
+/* Set on less than with immediate operand */
+static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm)
+{
+    target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */
+    const char *opn = "imm arith";
+    TCGv t0;
+
+    if (rt == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_load_gpr(t0, rs);
+    switch (opc) {
+    case OPC_SLTI:
+        tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm);
+        opn = "slti";
+        break;
+    case OPC_SLTIU:
+        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm);
+        opn = "sltiu";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
+    tcg_temp_free(t0);
+}
+
+/* Shifts with immediate operand */
+static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
+                          int rt, int rs, int16_t imm)
+{
+    target_ulong uimm = ((uint16_t)imm) & 0x1f;
+    const char *opn = "imm shift";
+    TCGv t0;
+
+    if (rt == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_load_gpr(t0, rs);
+    switch (opc) {
+    case OPC_SLL:
+        tcg_gen_shli_tl(t0, t0, uimm);
+        tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
+        opn = "sll";
+        break;
+    case OPC_SRA:
+        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm);
+        opn = "sra";
+        break;
+    case OPC_SRL:
+        if (uimm != 0) {
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+        } else {
+            tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
+        }
+        opn = "srl";
+        break;
+    case OPC_ROTR:
+        if (uimm != 0) {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(t1, t0);
+            tcg_gen_rotri_i32(t1, t1, uimm);
+            tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
+            tcg_temp_free_i32(t1);
+        } else {
+            tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
+        }
+        opn = "rotr";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DSLL:
+        tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm);
+        opn = "dsll";
+        break;
+    case OPC_DSRA:
+        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm);
+        opn = "dsra";
+        break;
+    case OPC_DSRL:
+        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+        opn = "dsrl";
+        break;
+    case OPC_DROTR:
+        if (uimm != 0) {
+            tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
+        } else {
+            tcg_gen_mov_tl(cpu_gpr[rt], t0);
+        }
+        opn = "drotr";
+        break;
+    case OPC_DSLL32:
+        tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "dsll32";
+        break;
+    case OPC_DSRA32:
+        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "dsra32";
+        break;
+    case OPC_DSRL32:
+        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "dsrl32";
+        break;
+    case OPC_DROTR32:
+        tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "drotr32";
+        break;
+#endif
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
+    tcg_temp_free(t0);
+}
+
+/* Arithmetic */
+static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
+                       int rd, int rs, int rt)
+{
+    const char *opn = "arith";
+
+    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
+       && opc != OPC_DADD && opc != OPC_DSUB) {
+        /* If no destination, treat it as a NOP.
+           For add & sub, we must generate the overflow exception when needed. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    switch (opc) {
+    case OPC_ADD:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            gen_load_gpr(t2, rt);
+            tcg_gen_add_tl(t0, t1, t2);
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_xor_tl(t1, t1, t2);
+            tcg_gen_xor_tl(t2, t0, t2);
+            tcg_gen_andc_tl(t1, t2, t1);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of same sign, result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        opn = "add";
+        break;
+    case OPC_ADDU:
+        if (rs != 0 && rt != 0) {
+            tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "addu";
+        break;
+    case OPC_SUB:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            gen_load_gpr(t2, rt);
+            tcg_gen_sub_tl(t0, t1, t2);
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_xor_tl(t2, t1, t2);
+            tcg_gen_xor_tl(t1, t0, t1);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of different sign, first operand and result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        opn = "sub";
+        break;
+    case OPC_SUBU:
+        if (rs != 0 && rt != 0) {
+            tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "subu";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DADD:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            gen_load_gpr(t2, rt);
+            tcg_gen_add_tl(t0, t1, t2);
+            tcg_gen_xor_tl(t1, t1, t2);
+            tcg_gen_xor_tl(t2, t0, t2);
+            tcg_gen_andc_tl(t1, t2, t1);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of same sign, result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        opn = "dadd";
+        break;
+    case OPC_DADDU:
+        if (rs != 0 && rt != 0) {
+            tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "daddu";
+        break;
+    case OPC_DSUB:
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            int l1 = gen_new_label();
+
+            gen_load_gpr(t1, rs);
+            gen_load_gpr(t2, rt);
+            tcg_gen_sub_tl(t0, t1, t2);
+            tcg_gen_xor_tl(t2, t1, t2);
+            tcg_gen_xor_tl(t1, t0, t1);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            tcg_temp_free(t1);
+            /* operands of different sign, first operand and result different sign */
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(l1);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        opn = "dsub";
+        break;
+    case OPC_DSUBU:
+        if (rs != 0 && rt != 0) {
+            tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "dsubu";
+        break;
+#endif
+    case OPC_MUL:
+        if (likely(rs != 0 && rt != 0)) {
+            tcg_gen_mul_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "mul";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
+/* Conditional move */
+static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt)
+{
+    const char *opn = "cond move";
+    int l1;
+
+    if (rd == 0) {
+        /* If no destination, treat it as a NOP.
+           For add & sub, we must generate the overflow exception when needed. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    l1 = gen_new_label();
+    switch (opc) {
+    case OPC_MOVN:
+        if (likely(rt != 0))
+            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rt], 0, l1);
+        else
+            tcg_gen_br(l1);
+        opn = "movn";
+        break;
+    case OPC_MOVZ:
+        if (likely(rt != 0))
+            tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rt], 0, l1);
+        opn = "movz";
+        break;
+    }
+    if (rs != 0)
+        tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+    else
+        tcg_gen_movi_tl(cpu_gpr[rd], 0);
+    gen_set_label(l1);
+
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
+/* Logic */
+static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt)
+{
+    const char *opn = "logic";
+
+    if (rd == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    switch (opc) {
+    case OPC_AND:
+        if (likely(rs != 0 && rt != 0)) {
+            tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "and";
+        break;
+    case OPC_NOR:
+        if (rs != 0 && rt != 0) {
+            tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0));
+        }
+        opn = "nor";
+        break;
+    case OPC_OR:
+        if (likely(rs != 0 && rt != 0)) {
+            tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "or";
+        break;
+    case OPC_XOR:
+        if (likely(rs != 0 && rt != 0)) {
+            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
+        } else if (rs == 0 && rt != 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
+        } else if (rs != 0 && rt == 0) {
+            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+        }
+        opn = "xor";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
+/* Set on lower than */
+static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt)
+{
+    const char *opn = "slt";
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+    case OPC_SLT:
+        tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1);
+        opn = "slt";
+        break;
+    case OPC_SLTU:
+        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1);
+        opn = "sltu";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* Shifts */
+static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
+                       int rd, int rs, int rt)
+{
+    const char *opn = "shifts";
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* If no destination, treat it as a NOP.
+           For add & sub, we must generate the overflow exception when needed. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+    case OPC_SLLV:
+        tcg_gen_andi_tl(t0, t0, 0x1f);
+        tcg_gen_shl_tl(t0, t1, t0);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+        opn = "sllv";
+        break;
+    case OPC_SRAV:
+        tcg_gen_andi_tl(t0, t0, 0x1f);
+        tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
+        opn = "srav";
+        break;
+    case OPC_SRLV:
+        tcg_gen_ext32u_tl(t1, t1);
+        tcg_gen_andi_tl(t0, t0, 0x1f);
+        tcg_gen_shr_tl(t0, t1, t0);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+        opn = "srlv";
+        break;
+    case OPC_ROTRV:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_andi_i32(t2, t2, 0x1f);
+            tcg_gen_rotr_i32(t2, t3, t2);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+            opn = "rotrv";
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DSLLV:
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_shl_tl(cpu_gpr[rd], t1, t0);
+        opn = "dsllv";
+        break;
+    case OPC_DSRAV:
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
+        opn = "dsrav";
+        break;
+    case OPC_DSRLV:
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
+        opn = "dsrlv";
+        break;
+    case OPC_DROTRV:
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
+        opn = "drotrv";
+        break;
+#endif
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* Arithmetic on HI/LO registers */
+static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
+{
+    const char *opn = "hilo";
+
+    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+    switch (opc) {
+    case OPC_MFHI:
+        tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[0]);
+        opn = "mfhi";
+        break;
+    case OPC_MFLO:
+        tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[0]);
+        opn = "mflo";
+        break;
+    case OPC_MTHI:
+        if (reg != 0)
+            tcg_gen_mov_tl(cpu_HI[0], cpu_gpr[reg]);
+        else
+            tcg_gen_movi_tl(cpu_HI[0], 0);
+        opn = "mthi";
+        break;
+    case OPC_MTLO:
+        if (reg != 0)
+            tcg_gen_mov_tl(cpu_LO[0], cpu_gpr[reg]);
+        else
+            tcg_gen_movi_tl(cpu_LO[0], 0);
+        opn = "mtlo";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s", opn, regnames[reg]);
+}
+
+static void gen_muldiv (DisasContext *ctx, uint32_t opc,
+                        int rs, int rt)
+{
+    const char *opn = "mul/div";
+    TCGv t0, t1;
+
+    switch (opc) {
+    case OPC_DIV:
+    case OPC_DIVU:
+#if defined(TARGET_MIPS64)
+    case OPC_DDIV:
+    case OPC_DDIVU:
+#endif
+        t0 = tcg_temp_local_new();
+        t1 = tcg_temp_local_new();
+        break;
+    default:
+        t0 = tcg_temp_new();
+        t1 = tcg_temp_new();
+        break;
+    }
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+    case OPC_DIV:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_ext32s_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
+
+            tcg_gen_mov_tl(cpu_LO[0], t0);
+            tcg_gen_movi_tl(cpu_HI[0], 0);
+            tcg_gen_br(l1);
+            gen_set_label(l2);
+            tcg_gen_div_tl(cpu_LO[0], t0, t1);
+            tcg_gen_rem_tl(cpu_HI[0], t0, t1);
+            tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
+            tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
+            gen_set_label(l1);
+        }
+        opn = "div";
+        break;
+    case OPC_DIVU:
+        {
+            int l1 = gen_new_label();
+
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_divu_tl(cpu_LO[0], t0, t1);
+            tcg_gen_remu_tl(cpu_HI[0], t0, t1);
+            tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
+            tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
+            gen_set_label(l1);
+        }
+        opn = "divu";
+        break;
+    case OPC_MULT:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext_tl_i64(t2, t0);
+            tcg_gen_ext_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "mult";
+        break;
+    case OPC_MULTU:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_extu_tl_i64(t2, t0);
+            tcg_gen_extu_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "multu";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DDIV:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+            tcg_gen_mov_tl(cpu_LO[0], t0);
+            tcg_gen_movi_tl(cpu_HI[0], 0);
+            tcg_gen_br(l1);
+            gen_set_label(l2);
+            tcg_gen_div_i64(cpu_LO[0], t0, t1);
+            tcg_gen_rem_i64(cpu_HI[0], t0, t1);
+            gen_set_label(l1);
+        }
+        opn = "ddiv";
+        break;
+    case OPC_DDIVU:
+        {
+            int l1 = gen_new_label();
+
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_divu_i64(cpu_LO[0], t0, t1);
+            tcg_gen_remu_i64(cpu_HI[0], t0, t1);
+            gen_set_label(l1);
+        }
+        opn = "ddivu";
+        break;
+    case OPC_DMULT:
+        gen_helper_dmult(t0, t1);
+        opn = "dmult";
+        break;
+    case OPC_DMULTU:
+        gen_helper_dmultu(t0, t1);
+        opn = "dmultu";
+        break;
+#endif
+    case OPC_MADD:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext_tl_i64(t2, t0);
+            tcg_gen_ext_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
+            tcg_gen_add_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "madd";
+        break;
+    case OPC_MADDU:
+       {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_extu_tl_i64(t2, t0);
+            tcg_gen_extu_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
+            tcg_gen_add_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "maddu";
+        break;
+    case OPC_MSUB:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext_tl_i64(t2, t0);
+            tcg_gen_ext_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
+            tcg_gen_sub_i64(t2, t3, t2);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "msub";
+        break;
+    case OPC_MSUBU:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_extu_tl_i64(t2, t0);
+            tcg_gen_extu_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
+            tcg_gen_sub_i64(t2, t3, t2);
+            tcg_temp_free_i64(t3);
+            tcg_gen_trunc_i64_tl(t0, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_tl(t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_ext32s_tl(cpu_LO[0], t0);
+            tcg_gen_ext32s_tl(cpu_HI[0], t1);
+        }
+        opn = "msubu";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
+ out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
+                            int rd, int rs, int rt)
+{
+    const char *opn = "mul vr54xx";
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+
+    switch (opc) {
+    case OPC_VR54XX_MULS:
+        gen_helper_muls(t0, t0, t1);
+        opn = "muls";
+        break;
+    case OPC_VR54XX_MULSU:
+        gen_helper_mulsu(t0, t0, t1);
+        opn = "mulsu";
+        break;
+    case OPC_VR54XX_MACC:
+        gen_helper_macc(t0, t0, t1);
+        opn = "macc";
+        break;
+    case OPC_VR54XX_MACCU:
+        gen_helper_maccu(t0, t0, t1);
+        opn = "maccu";
+        break;
+    case OPC_VR54XX_MSAC:
+        gen_helper_msac(t0, t0, t1);
+        opn = "msac";
+        break;
+    case OPC_VR54XX_MSACU:
+        gen_helper_msacu(t0, t0, t1);
+        opn = "msacu";
+        break;
+    case OPC_VR54XX_MULHI:
+        gen_helper_mulhi(t0, t0, t1);
+        opn = "mulhi";
+        break;
+    case OPC_VR54XX_MULHIU:
+        gen_helper_mulhiu(t0, t0, t1);
+        opn = "mulhiu";
+        break;
+    case OPC_VR54XX_MULSHI:
+        gen_helper_mulshi(t0, t0, t1);
+        opn = "mulshi";
+        break;
+    case OPC_VR54XX_MULSHIU:
+        gen_helper_mulshiu(t0, t0, t1);
+        opn = "mulshiu";
+        break;
+    case OPC_VR54XX_MACCHI:
+        gen_helper_macchi(t0, t0, t1);
+        opn = "macchi";
+        break;
+    case OPC_VR54XX_MACCHIU:
+        gen_helper_macchiu(t0, t0, t1);
+        opn = "macchiu";
+        break;
+    case OPC_VR54XX_MSACHI:
+        gen_helper_msachi(t0, t0, t1);
+        opn = "msachi";
+        break;
+    case OPC_VR54XX_MSACHIU:
+        gen_helper_msachiu(t0, t0, t1);
+        opn = "msachiu";
+        break;
+    default:
+        MIPS_INVAL("mul vr54xx");
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+    gen_store_gpr(t0, rd);
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+
+ out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_cl (DisasContext *ctx, uint32_t opc,
+                    int rd, int rs)
+{
+    const char *opn = "CLx";
+    TCGv t0;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_load_gpr(t0, rs);
+    switch (opc) {
+    case OPC_CLO:
+        gen_helper_clo(cpu_gpr[rd], t0);
+        opn = "clo";
+        break;
+    case OPC_CLZ:
+        gen_helper_clz(cpu_gpr[rd], t0);
+        opn = "clz";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DCLO:
+        gen_helper_dclo(cpu_gpr[rd], t0);
+        opn = "dclo";
+        break;
+    case OPC_DCLZ:
+        gen_helper_dclz(cpu_gpr[rd], t0);
+        opn = "dclz";
+        break;
+#endif
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
+    tcg_temp_free(t0);
+}
+
+/* Godson integer instructions */
+static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
+                                int rd, int rs, int rt)
+{
+    const char *opn = "loongson";
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    switch (opc) {
+    case OPC_MULT_G_2E:
+    case OPC_MULT_G_2F:
+    case OPC_MULTU_G_2E:
+    case OPC_MULTU_G_2F:
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2E:
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2E:
+    case OPC_DMULTU_G_2F:
+#endif
+        t0 = tcg_temp_new();
+        t1 = tcg_temp_new();
+        break;
+    default:
+        t0 = tcg_temp_local_new();
+        t1 = tcg_temp_local_new();
+        break;
+    }
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+
+    switch (opc) {
+    case OPC_MULT_G_2E:
+    case OPC_MULT_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        opn = "mult.g";
+        break;
+    case OPC_MULTU_G_2E:
+    case OPC_MULTU_G_2F:
+        tcg_gen_ext32u_tl(t0, t0);
+        tcg_gen_ext32u_tl(t1, t1);
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        opn = "multu.g";
+        break;
+    case OPC_DIV_G_2E:
+    case OPC_DIV_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int l3 = gen_new_label();
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_ext32s_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
+            tcg_gen_mov_tl(cpu_gpr[rd], t0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l3);
+        }
+        opn = "div.g";
+        break;
+    case OPC_DIVU_G_2E:
+    case OPC_DIVU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l2);
+        }
+        opn = "divu.g";
+        break;
+    case OPC_MOD_G_2E:
+    case OPC_MOD_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int l3 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
+            gen_set_label(l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l3);
+        }
+        opn = "mod.g";
+        break;
+    case OPC_MODU_G_2E:
+    case OPC_MODU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l2);
+        }
+        opn = "modu.g";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2E:
+    case OPC_DMULT_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        opn = "dmult.g";
+        break;
+    case OPC_DMULTU_G_2E:
+    case OPC_DMULTU_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        opn = "dmultu.g";
+        break;
+    case OPC_DDIV_G_2E:
+    case OPC_DDIV_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int l3 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+            tcg_gen_mov_tl(cpu_gpr[rd], t0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l3);
+        }
+        opn = "ddiv.g";
+        break;
+    case OPC_DDIVU_G_2E:
+    case OPC_DDIVU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l2);
+        }
+        opn = "ddivu.g";
+        break;
+    case OPC_DMOD_G_2E:
+    case OPC_DMOD_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int l3 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+            gen_set_label(l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l3);
+        }
+        opn = "dmod.g";
+        break;
+    case OPC_DMODU_G_2E:
+    case OPC_DMODU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l2);
+        }
+        opn = "dmodu.g";
+        break;
+#endif
+    }
+
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* Traps */
+static void gen_trap (DisasContext *ctx, uint32_t opc,
+                      int rs, int rt, int16_t imm)
+{
+    int cond;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    cond = 0;
+    /* Load needed operands */
+    switch (opc) {
+    case OPC_TEQ:
+    case OPC_TGE:
+    case OPC_TGEU:
+    case OPC_TLT:
+    case OPC_TLTU:
+    case OPC_TNE:
+        /* Compare two registers */
+        if (rs != rt) {
+            gen_load_gpr(t0, rs);
+            gen_load_gpr(t1, rt);
+            cond = 1;
+        }
+        break;
+    case OPC_TEQI:
+    case OPC_TGEI:
+    case OPC_TGEIU:
+    case OPC_TLTI:
+    case OPC_TLTIU:
+    case OPC_TNEI:
+        /* Compare register to immediate */
+        if (rs != 0 || imm != 0) {
+            gen_load_gpr(t0, rs);
+            tcg_gen_movi_tl(t1, (int32_t)imm);
+            cond = 1;
+        }
+        break;
+    }
+    if (cond == 0) {
+        switch (opc) {
+        case OPC_TEQ:   /* rs == rs */
+        case OPC_TEQI:  /* r0 == 0  */
+        case OPC_TGE:   /* rs >= rs */
+        case OPC_TGEI:  /* r0 >= 0  */
+        case OPC_TGEU:  /* rs >= rs unsigned */
+        case OPC_TGEIU: /* r0 >= 0  unsigned */
+            /* Always trap */
+            generate_exception(ctx, EXCP_TRAP);
+            break;
+        case OPC_TLT:   /* rs < rs           */
+        case OPC_TLTI:  /* r0 < 0            */
+        case OPC_TLTU:  /* rs < rs unsigned  */
+        case OPC_TLTIU: /* r0 < 0  unsigned  */
+        case OPC_TNE:   /* rs != rs          */
+        case OPC_TNEI:  /* r0 != 0           */
+            /* Never trap: treat as NOP. */
+            break;
+        }
+    } else {
+        int l1 = gen_new_label();
+
+        switch (opc) {
+        case OPC_TEQ:
+        case OPC_TEQI:
+            tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1);
+            break;
+        case OPC_TGE:
+        case OPC_TGEI:
+            tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1);
+            break;
+        case OPC_TGEU:
+        case OPC_TGEIU:
+            tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1);
+            break;
+        case OPC_TLT:
+        case OPC_TLTI:
+            tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
+            break;
+        case OPC_TLTU:
+        case OPC_TLTIU:
+            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
+            break;
+        case OPC_TNE:
+        case OPC_TNEI:
+            tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1);
+            break;
+        }
+        generate_exception(ctx, EXCP_TRAP);
+        gen_set_label(l1);
+    }
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+        likely(!ctx->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
+        gen_save_pc(dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        gen_save_pc(dest);
+        if (ctx->singlestep_enabled) {
+            save_cpu_state(ctx, 0);
+            gen_helper_0i(raise_exception, EXCP_DEBUG);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+/* Branches (before delay slot) */
+static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
+                                int insn_bytes,
+                                int rs, int rt, int32_t offset)
+{
+    target_ulong btgt = -1;
+    int blink = 0;
+    int bcond_compute = 0;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+#ifdef MIPS_DEBUG_DISAS
+        LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc);
+#endif
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    /* Load needed operands */
+    switch (opc) {
+    case OPC_BEQ:
+    case OPC_BEQL:
+    case OPC_BNE:
+    case OPC_BNEL:
+        /* Compare two registers */
+        if (rs != rt) {
+            gen_load_gpr(t0, rs);
+            gen_load_gpr(t1, rt);
+            bcond_compute = 1;
+        }
+        btgt = ctx->pc + insn_bytes + offset;
+        break;
+    case OPC_BGEZ:
+    case OPC_BGEZAL:
+    case OPC_BGEZALS:
+    case OPC_BGEZALL:
+    case OPC_BGEZL:
+    case OPC_BGTZ:
+    case OPC_BGTZL:
+    case OPC_BLEZ:
+    case OPC_BLEZL:
+    case OPC_BLTZ:
+    case OPC_BLTZAL:
+    case OPC_BLTZALS:
+    case OPC_BLTZALL:
+    case OPC_BLTZL:
+        /* Compare to zero */
+        if (rs != 0) {
+            gen_load_gpr(t0, rs);
+            bcond_compute = 1;
+        }
+        btgt = ctx->pc + insn_bytes + offset;
+        break;
+    case OPC_J:
+    case OPC_JAL:
+    case OPC_JALX:
+    case OPC_JALS:
+    case OPC_JALXS:
+        /* Jump to immediate */
+        btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
+        break;
+    case OPC_JR:
+    case OPC_JALR:
+    case OPC_JALRC:
+    case OPC_JALRS:
+        /* Jump to register */
+        if (offset != 0 && offset != 16) {
+            /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
+               others are reserved. */
+            MIPS_INVAL("jump hint");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+        gen_load_gpr(btarget, rs);
+        break;
+    default:
+        MIPS_INVAL("branch/jump");
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+    if (bcond_compute == 0) {
+        /* No condition to be computed */
+        switch (opc) {
+        case OPC_BEQ:     /* rx == rx        */
+        case OPC_BEQL:    /* rx == rx likely */
+        case OPC_BGEZ:    /* 0 >= 0          */
+        case OPC_BGEZL:   /* 0 >= 0 likely   */
+        case OPC_BLEZ:    /* 0 <= 0          */
+        case OPC_BLEZL:   /* 0 <= 0 likely   */
+            /* Always take */
+            ctx->hflags |= MIPS_HFLAG_B;
+            MIPS_DEBUG("balways");
+            break;
+        case OPC_BGEZALS:
+        case OPC_BGEZAL:  /* 0 >= 0          */
+        case OPC_BGEZALL: /* 0 >= 0 likely   */
+            ctx->hflags |= (opc == OPC_BGEZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            /* Always take and link */
+            blink = 31;
+            ctx->hflags |= MIPS_HFLAG_B;
+            MIPS_DEBUG("balways and link");
+            break;
+        case OPC_BNE:     /* rx != rx        */
+        case OPC_BGTZ:    /* 0 > 0           */
+        case OPC_BLTZ:    /* 0 < 0           */
+            /* Treat as NOP. */
+            MIPS_DEBUG("bnever (NOP)");
+            goto out;
+        case OPC_BLTZALS:
+        case OPC_BLTZAL:  /* 0 < 0           */
+            ctx->hflags |= (opc == OPC_BLTZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            /* Handle as an unconditional branch to get correct delay
+               slot checking.  */
+            blink = 31;
+            btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8);
+            ctx->hflags |= MIPS_HFLAG_B;
+            MIPS_DEBUG("bnever and link");
+            break;
+        case OPC_BLTZALL: /* 0 < 0 likely */
+            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
+            /* Skip the instruction in the delay slot */
+            MIPS_DEBUG("bnever, link and skip");
+            ctx->pc += 4;
+            goto out;
+        case OPC_BNEL:    /* rx != rx likely */
+        case OPC_BGTZL:   /* 0 > 0 likely */
+        case OPC_BLTZL:   /* 0 < 0 likely */
+            /* Skip the instruction in the delay slot */
+            MIPS_DEBUG("bnever and skip");
+            ctx->pc += 4;
+            goto out;
+        case OPC_J:
+            ctx->hflags |= MIPS_HFLAG_B;
+            MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
+            break;
+        case OPC_JALXS:
+        case OPC_JALX:
+            ctx->hflags |= MIPS_HFLAG_BX;
+            /* Fallthrough */
+        case OPC_JALS:
+        case OPC_JAL:
+            blink = 31;
+            ctx->hflags |= MIPS_HFLAG_B;
+            ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS)
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
+            break;
+        case OPC_JR:
+            ctx->hflags |= MIPS_HFLAG_BR;
+            if (insn_bytes == 4)
+                ctx->hflags |= MIPS_HFLAG_BDS32;
+            MIPS_DEBUG("jr %s", regnames[rs]);
+            break;
+        case OPC_JALRS:
+        case OPC_JALR:
+        case OPC_JALRC:
+            blink = rt;
+            ctx->hflags |= MIPS_HFLAG_BR;
+            ctx->hflags |= (opc == OPC_JALRS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
+            break;
+        default:
+            MIPS_INVAL("branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+    } else {
+        switch (opc) {
+        case OPC_BEQ:
+            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
+            MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx,
+                       regnames[rs], regnames[rt], btgt);
+            goto not_likely;
+        case OPC_BEQL:
+            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
+            MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx,
+                       regnames[rs], regnames[rt], btgt);
+            goto likely;
+        case OPC_BNE:
+            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
+            MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx,
+                       regnames[rs], regnames[rt], btgt);
+            goto not_likely;
+        case OPC_BNEL:
+            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
+            MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
+                       regnames[rs], regnames[rt], btgt);
+            goto likely;
+        case OPC_BGEZ:
+            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
+            MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto not_likely;
+        case OPC_BGEZL:
+            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
+            MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto likely;
+        case OPC_BGEZALS:
+        case OPC_BGEZAL:
+            ctx->hflags |= (opc == OPC_BGEZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
+            MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            blink = 31;
+            goto not_likely;
+        case OPC_BGEZALL:
+            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
+            blink = 31;
+            MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto likely;
+        case OPC_BGTZ:
+            tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0);
+            MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto not_likely;
+        case OPC_BGTZL:
+            tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0);
+            MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto likely;
+        case OPC_BLEZ:
+            tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0);
+            MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto not_likely;
+        case OPC_BLEZL:
+            tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0);
+            MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto likely;
+        case OPC_BLTZ:
+            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
+            MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto not_likely;
+        case OPC_BLTZL:
+            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
+            MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
+            goto likely;
+        case OPC_BLTZALS:
+        case OPC_BLTZAL:
+            ctx->hflags |= (opc == OPC_BLTZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
+            blink = 31;
+            MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
+        not_likely:
+            ctx->hflags |= MIPS_HFLAG_BC;
+            break;
+        case OPC_BLTZALL:
+            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
+            blink = 31;
+            MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btgt);
+        likely:
+            ctx->hflags |= MIPS_HFLAG_BL;
+            break;
+        default:
+            MIPS_INVAL("conditional branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+    }
+    MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
+               blink, ctx->hflags, btgt);
+
+    ctx->btarget = btgt;
+    if (blink > 0) {
+        int post_delay = insn_bytes;
+        int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);
+
+        if (opc != OPC_JALRC)
+            post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
+
+        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
+    }
+
+ out:
+    if (insn_bytes == 2)
+        ctx->hflags |= MIPS_HFLAG_B16;
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* special3 bitfield operations */
+static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
+                        int rs, int lsb, int msb)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    target_ulong mask;
+
+    gen_load_gpr(t1, rs);
+    switch (opc) {
+    case OPC_EXT:
+        if (lsb + msb > 31)
+            goto fail;
+        tcg_gen_shri_tl(t0, t1, lsb);
+        if (msb != 31) {
+            tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1);
+        } else {
+            tcg_gen_ext32s_tl(t0, t0);
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DEXTM:
+        tcg_gen_shri_tl(t0, t1, lsb);
+        if (msb != 31) {
+            tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1);
+        }
+        break;
+    case OPC_DEXTU:
+        tcg_gen_shri_tl(t0, t1, lsb + 32);
+        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
+        break;
+    case OPC_DEXT:
+        tcg_gen_shri_tl(t0, t1, lsb);
+        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
+        break;
+#endif
+    case OPC_INS:
+        if (lsb > msb)
+            goto fail;
+        mask = ((msb - lsb + 1 < 32) ? ((1 << (msb - lsb + 1)) - 1) : ~0) << lsb;
+        gen_load_gpr(t0, rt);
+        tcg_gen_andi_tl(t0, t0, ~mask);
+        tcg_gen_shli_tl(t1, t1, lsb);
+        tcg_gen_andi_tl(t1, t1, mask);
+        tcg_gen_or_tl(t0, t0, t1);
+        tcg_gen_ext32s_tl(t0, t0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DINSM:
+        if (lsb > msb)
+            goto fail;
+        mask = ((msb - lsb + 1 + 32 < 64) ? ((1ULL << (msb - lsb + 1 + 32)) - 1) : ~0ULL) << lsb;
+        gen_load_gpr(t0, rt);
+        tcg_gen_andi_tl(t0, t0, ~mask);
+        tcg_gen_shli_tl(t1, t1, lsb);
+        tcg_gen_andi_tl(t1, t1, mask);
+        tcg_gen_or_tl(t0, t0, t1);
+        break;
+    case OPC_DINSU:
+        if (lsb > msb)
+            goto fail;
+        mask = ((1ULL << (msb - lsb + 1)) - 1) << (lsb + 32);
+        gen_load_gpr(t0, rt);
+        tcg_gen_andi_tl(t0, t0, ~mask);
+        tcg_gen_shli_tl(t1, t1, lsb + 32);
+        tcg_gen_andi_tl(t1, t1, mask);
+        tcg_gen_or_tl(t0, t0, t1);
+        break;
+    case OPC_DINS:
+        if (lsb > msb)
+            goto fail;
+        gen_load_gpr(t0, rt);
+        mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb;
+        gen_load_gpr(t0, rt);
+        tcg_gen_andi_tl(t0, t0, ~mask);
+        tcg_gen_shli_tl(t1, t1, lsb);
+        tcg_gen_andi_tl(t1, t1, mask);
+        tcg_gen_or_tl(t0, t0, t1);
+        break;
+#endif
+    default:
+fail:
+        MIPS_INVAL("bitops");
+        generate_exception(ctx, EXCP_RI);
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+        return;
+    }
+    gen_store_gpr(t0, rt);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd)
+{
+    TCGv t0;
+
+    if (rd == 0) {
+        /* If no destination, treat it as a NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_load_gpr(t0, rt);
+    switch (op2) {
+    case OPC_WSBH:
+        {
+            TCGv t1 = tcg_temp_new();
+
+            tcg_gen_shri_tl(t1, t0, 8);
+            tcg_gen_andi_tl(t1, t1, 0x00FF00FF);
+            tcg_gen_shli_tl(t0, t0, 8);
+            tcg_gen_andi_tl(t0, t0, ~0x00FF00FF);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+        }
+        break;
+    case OPC_SEB:
+        tcg_gen_ext8s_tl(cpu_gpr[rd], t0);
+        break;
+    case OPC_SEH:
+        tcg_gen_ext16s_tl(cpu_gpr[rd], t0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DSBH:
+        {
+            TCGv t1 = tcg_temp_new();
+
+            tcg_gen_shri_tl(t1, t0, 8);
+            tcg_gen_andi_tl(t1, t1, 0x00FF00FF00FF00FFULL);
+            tcg_gen_shli_tl(t0, t0, 8);
+            tcg_gen_andi_tl(t0, t0, ~0x00FF00FF00FF00FFULL);
+            tcg_gen_or_tl(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t1);
+        }
+        break;
+    case OPC_DSHD:
+        {
+            TCGv t1 = tcg_temp_new();
+
+            tcg_gen_shri_tl(t1, t0, 16);
+            tcg_gen_andi_tl(t1, t1, 0x0000FFFF0000FFFFULL);
+            tcg_gen_shli_tl(t0, t0, 16);
+            tcg_gen_andi_tl(t0, t0, ~0x0000FFFF0000FFFFULL);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_gen_shri_tl(t1, t0, 32);
+            tcg_gen_shli_tl(t0, t0, 32);
+            tcg_gen_or_tl(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t1);
+        }
+        break;
+#endif
+    default:
+        MIPS_INVAL("bsfhl");
+        generate_exception(ctx, EXCP_RI);
+        tcg_temp_free(t0);
+        return;
+    }
+    tcg_temp_free(t0);
+}
+
+#ifndef CONFIG_USER_ONLY
+/* CP0 (MMU and control) */
+static inline void gen_mfc0_load32 (TCGv arg, target_ulong off)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+
+    tcg_gen_ld_i32(t0, cpu_env, off);
+    tcg_gen_ext_i32_tl(arg, t0);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void gen_mfc0_load64 (TCGv arg, target_ulong off)
+{
+    tcg_gen_ld_tl(arg, cpu_env, off);
+    tcg_gen_ext32s_tl(arg, arg);
+}
+
+static inline void gen_mtc0_store32 (TCGv arg, target_ulong off)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+
+    tcg_gen_trunc_tl_i32(t0, arg);
+    tcg_gen_st_i32(t0, cpu_env, off);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void gen_mtc0_store64 (TCGv arg, target_ulong off)
+{
+    tcg_gen_ext32s_tl(arg, arg);
+    tcg_gen_st_tl(arg, cpu_env, off);
+}
+
+static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
+{
+    const char *rn = "invalid";
+
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
+    switch (reg) {
+    case 0:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Index));
+            rn = "Index";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpcontrol(arg);
+            rn = "MVPControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpconf0(arg);
+            rn = "MVPConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpconf1(arg);
+            rn = "MVPConf1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 1:
+        switch (sel) {
+        case 0:
+            gen_helper_mfc0_random(arg);
+            rn = "Random";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEControl));
+            rn = "VPEControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf0));
+            rn = "VPEConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf1));
+            rn = "VPEConf1";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load64(arg, offsetof(CPUState, CP0_YQMask));
+            rn = "YQMask";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load64(arg, offsetof(CPUState, CP0_VPESchedule));
+            rn = "VPESchedule";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load64(arg, offsetof(CPUState, CP0_VPEScheFBack));
+            rn = "VPEScheFBack";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEOpt));
+            rn = "VPEOpt";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 2:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo0));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "EntryLo0";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcstatus(arg);
+            rn = "TCStatus";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcbind(arg);
+            rn = "TCBind";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcrestart(arg);
+            rn = "TCRestart";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tchalt(arg);
+            rn = "TCHalt";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tccontext(arg);
+            rn = "TCContext";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcschedule(arg);
+            rn = "TCSchedule";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcschefback(arg);
+            rn = "TCScheFBack";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 3:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo1));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "EntryLo1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 4:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_Context));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "Context";
+            break;
+        case 1:
+//            gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 5:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageMask));
+            rn = "PageMask";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageGrain));
+            rn = "PageGrain";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 6:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Wired));
+            rn = "Wired";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf0));
+            rn = "SRSConf0";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf1));
+            rn = "SRSConf1";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf2));
+            rn = "SRSConf2";
+            break;
+        case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf3));
+            rn = "SRSConf3";
+            break;
+        case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf4));
+            rn = "SRSConf4";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 7:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_HWREna));
+            rn = "HWREna";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 8:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_BadVAddr));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "BadVAddr";
+            break;
+        default:
+            goto die;
+       }
+        break;
+    case 9:
+        switch (sel) {
+        case 0:
+            /* Mark as an IO operation because we read the time.  */
+            if (use_icount)
+                gen_io_start();
+            gen_helper_mfc0_count(arg);
+            if (use_icount) {
+                gen_io_end();
+            }
+            /* Break the TB to be able to take timer interrupts immediately
+               after reading count.  */
+            ctx->bstate = BS_STOP;
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 10:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryHi));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "EntryHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 11:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Compare));
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 12:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Status));
+            rn = "Status";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_IntCtl));
+            rn = "IntCtl";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSCtl));
+            rn = "SRSCtl";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSMap));
+            rn = "SRSMap";
+            break;
+        default:
+            goto die;
+       }
+        break;
+    case 13:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Cause));
+            rn = "Cause";
+            break;
+        default:
+            goto die;
+       }
+        break;
+    case 14:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "EPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 15:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PRid));
+            rn = "PRid";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_EBase));
+            rn = "EBase";
+            break;
+        default:
+            goto die;
+       }
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config0));
+            rn = "Config";
+            break;
+        case 1:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config1));
+            rn = "Config1";
+            break;
+        case 2:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config2));
+            rn = "Config2";
+            break;
+        case 3:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config3));
+            rn = "Config3";
+            break;
+        /* 4,5 are reserved */
+        /* 6,7 are implementation dependent */
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config6));
+            rn = "Config6";
+            break;
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config7));
+            rn = "Config7";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 17:
+        switch (sel) {
+        case 0:
+            gen_helper_mfc0_lladdr(arg);
+            rn = "LLAddr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 18:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mfc0_watchlo, arg, sel);
+            rn = "WatchLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 19:
+        switch (sel) {
+        case 0 ...7:
+            gen_helper_1i(mfc0_watchhi, arg, sel);
+            rn = "WatchHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 20:
+        switch (sel) {
+        case 0:
+#if defined(TARGET_MIPS64)
+            check_insn(env, ctx, ISA_MIPS3);
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_XContext));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "XContext";
+            break;
+#endif
+        default:
+            goto die;
+        }
+        break;
+    case 21:
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Framemask));
+            rn = "Framemask";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 22:
+        tcg_gen_movi_tl(arg, 0); /* unimplemented */
+        rn = "'Diagnostic"; /* implementation dependent */
+        break;
+    case 23:
+        switch (sel) {
+        case 0:
+            gen_helper_mfc0_debug(arg); /* EJTAG support */
+            rn = "Debug";
+            break;
+        case 1:
+//            gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */
+            rn = "TraceControl";
+//            break;
+        case 2:
+//            gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */
+            rn = "TraceControl2";
+//            break;
+        case 3:
+//            gen_helper_mfc0_usertracedata(arg); /* PDtrace support */
+            rn = "UserTraceData";
+//            break;
+        case 4:
+//            gen_helper_mfc0_tracebpc(arg); /* PDtrace support */
+            rn = "TraceBPC";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 24:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "DEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 25:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Performance0));
+            rn = "Performance0";
+            break;
+        case 1:
+//            gen_helper_mfc0_performance1(arg);
+            rn = "Performance1";
+//            break;
+        case 2:
+//            gen_helper_mfc0_performance2(arg);
+            rn = "Performance2";
+//            break;
+        case 3:
+//            gen_helper_mfc0_performance3(arg);
+            rn = "Performance3";
+//            break;
+        case 4:
+//            gen_helper_mfc0_performance4(arg);
+            rn = "Performance4";
+//            break;
+        case 5:
+//            gen_helper_mfc0_performance5(arg);
+            rn = "Performance5";
+//            break;
+        case 6:
+//            gen_helper_mfc0_performance6(arg);
+            rn = "Performance6";
+//            break;
+        case 7:
+//            gen_helper_mfc0_performance7(arg);
+            rn = "Performance7";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 26:
+        tcg_gen_movi_tl(arg, 0); /* unimplemented */
+        rn = "ECC";
+        break;
+    case 27:
+        switch (sel) {
+        case 0 ... 3:
+            tcg_gen_movi_tl(arg, 0); /* unimplemented */
+            rn = "CacheErr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 28:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagLo));
+            rn = "TagLo";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataLo));
+            rn = "DataLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 29:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagHi));
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataHi));
+            rn = "DataHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 30:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC));
+            tcg_gen_ext32s_tl(arg, arg);
+            rn = "ErrorEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 31:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DESAVE));
+            rn = "DESAVE";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    default:
+       goto die;
+    }
+    (void)rn; /* avoid a compiler warning */
+    LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    return;
+
+die:
+    LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
+{
+    const char *rn = "invalid";
+
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
+    if (use_icount)
+        gen_io_start();
+
+    switch (reg) {
+    case 0:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_index(arg);
+            rn = "Index";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_mvpcontrol(arg);
+            rn = "MVPControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            /* ignored */
+            rn = "MVPConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            /* ignored */
+            rn = "MVPConf1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 1:
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "Random";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpecontrol(arg);
+            rn = "VPEControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeconf0(arg);
+            rn = "VPEConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeconf1(arg);
+            rn = "VPEConf1";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_yqmask(arg);
+            rn = "YQMask";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_mtc0_store64(arg, offsetof(CPUState, CP0_VPESchedule));
+            rn = "VPESchedule";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_mtc0_store64(arg, offsetof(CPUState, CP0_VPEScheFBack));
+            rn = "VPEScheFBack";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeopt(arg);
+            rn = "VPEOpt";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 2:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entrylo0(arg);
+            rn = "EntryLo0";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcstatus(arg);
+            rn = "TCStatus";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcbind(arg);
+            rn = "TCBind";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcrestart(arg);
+            rn = "TCRestart";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tchalt(arg);
+            rn = "TCHalt";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tccontext(arg);
+            rn = "TCContext";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcschedule(arg);
+            rn = "TCSchedule";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcschefback(arg);
+            rn = "TCScheFBack";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 3:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entrylo1(arg);
+            rn = "EntryLo1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 4:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_context(arg);
+            rn = "Context";
+            break;
+        case 1:
+//            gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 5:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_pagemask(arg);
+            rn = "PageMask";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_pagegrain(arg);
+            rn = "PageGrain";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 6:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_wired(arg);
+            rn = "Wired";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf0(arg);
+            rn = "SRSConf0";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf1(arg);
+            rn = "SRSConf1";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf2(arg);
+            rn = "SRSConf2";
+            break;
+        case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf3(arg);
+            rn = "SRSConf3";
+            break;
+        case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf4(arg);
+            rn = "SRSConf4";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 7:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_hwrena(arg);
+            rn = "HWREna";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 8:
+        /* ignored */
+        rn = "BadVAddr";
+        break;
+    case 9:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_count(arg);
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 10:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entryhi(arg);
+            rn = "EntryHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 11:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_compare(arg);
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 12:
+        switch (sel) {
+        case 0:
+            save_cpu_state(ctx, 1);
+            gen_helper_mtc0_status(arg);
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Status";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_intctl(arg);
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "IntCtl";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsctl(arg);
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSCtl";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mtc0_store32(arg, offsetof(CPUState, CP0_SRSMap));
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSMap";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 13:
+        switch (sel) {
+        case 0:
+            save_cpu_state(ctx, 1);
+            gen_helper_mtc0_cause(arg);
+            rn = "Cause";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 14:
+        switch (sel) {
+        case 0:
+            gen_mtc0_store64(arg, offsetof(CPUState, CP0_EPC));
+            rn = "EPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 15:
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "PRid";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_ebase(arg);
+            rn = "EBase";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_config0(arg);
+            rn = "Config";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            break;
+        case 1:
+            /* ignored, read only */
+            rn = "Config1";
+            break;
+        case 2:
+            gen_helper_mtc0_config2(arg);
+            rn = "Config2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            break;
+        case 3:
+            /* ignored, read only */
+            rn = "Config3";
+            break;
+        /* 4,5 are reserved */
+        /* 6,7 are implementation dependent */
+        case 6:
+            /* ignored */
+            rn = "Config6";
+            break;
+        case 7:
+            /* ignored */
+            rn = "Config7";
+            break;
+        default:
+            rn = "Invalid config selector";
+            goto die;
+        }
+        break;
+    case 17:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_lladdr(arg);
+            rn = "LLAddr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 18:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mtc0_watchlo, arg, sel);
+            rn = "WatchLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 19:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mtc0_watchhi, arg, sel);
+            rn = "WatchHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 20:
+        switch (sel) {
+        case 0:
+#if defined(TARGET_MIPS64)
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_helper_mtc0_xcontext(arg);
+            rn = "XContext";
+            break;
+#endif
+        default:
+            goto die;
+        }
+        break;
+    case 21:
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_framemask(arg);
+            rn = "Framemask";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 22:
+        /* ignored */
+        rn = "Diagnostic"; /* implementation dependent */
+        break;
+    case 23:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_debug(arg); /* EJTAG support */
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Debug";
+            break;
+        case 1:
+//            gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */
+            rn = "TraceControl";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
+        case 2:
+//            gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */
+            rn = "TraceControl2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
+        case 3:
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            gen_helper_mtc0_usertracedata(arg); /* PDtrace support */
+            rn = "UserTraceData";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
+        case 4:
+//            gen_helper_mtc0_tracebpc(arg); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceBPC";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 24:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            gen_mtc0_store64(arg, offsetof(CPUState, CP0_DEPC));
+            rn = "DEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 25:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_performance0(arg);
+            rn = "Performance0";
+            break;
+        case 1:
+//            gen_helper_mtc0_performance1(arg);
+            rn = "Performance1";
+//            break;
+        case 2:
+//            gen_helper_mtc0_performance2(arg);
+            rn = "Performance2";
+//            break;
+        case 3:
+//            gen_helper_mtc0_performance3(arg);
+            rn = "Performance3";
+//            break;
+        case 4:
+//            gen_helper_mtc0_performance4(arg);
+            rn = "Performance4";
+//            break;
+        case 5:
+//            gen_helper_mtc0_performance5(arg);
+            rn = "Performance5";
+//            break;
+        case 6:
+//            gen_helper_mtc0_performance6(arg);
+            rn = "Performance6";
+//            break;
+        case 7:
+//            gen_helper_mtc0_performance7(arg);
+            rn = "Performance7";
+//            break;
+        default:
+            goto die;
+        }
+       break;
+    case 26:
+        /* ignored */
+        rn = "ECC";
+        break;
+    case 27:
+        switch (sel) {
+        case 0 ... 3:
+            /* ignored */
+            rn = "CacheErr";
+            break;
+        default:
+            goto die;
+        }
+       break;
+    case 28:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_helper_mtc0_taglo(arg);
+            rn = "TagLo";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_helper_mtc0_datalo(arg);
+            rn = "DataLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 29:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_helper_mtc0_taghi(arg);
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_helper_mtc0_datahi(arg);
+            rn = "DataHi";
+            break;
+        default:
+            rn = "invalid sel";
+            goto die;
+        }
+       break;
+    case 30:
+        switch (sel) {
+        case 0:
+            gen_mtc0_store64(arg, offsetof(CPUState, CP0_ErrorEPC));
+            rn = "ErrorEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 31:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            gen_mtc0_store32(arg, offsetof(CPUState, CP0_DESAVE));
+            rn = "DESAVE";
+            break;
+        default:
+            goto die;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
+        break;
+    default:
+       goto die;
+    }
+    (void)rn; /* avoid a compiler warning */
+    LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    /* For simplicity assume that all writes can cause interrupts.  */
+    if (use_icount) {
+        gen_io_end();
+        ctx->bstate = BS_STOP;
+    }
+    return;
+
+die:
+    LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    generate_exception(ctx, EXCP_RI);
+}
+
+#if defined(TARGET_MIPS64)
+static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
+{
+    const char *rn = "invalid";
+
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
+    switch (reg) {
+    case 0:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Index));
+            rn = "Index";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpcontrol(arg);
+            rn = "MVPControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpconf0(arg);
+            rn = "MVPConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_mvpconf1(arg);
+            rn = "MVPConf1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 1:
+        switch (sel) {
+        case 0:
+            gen_helper_mfc0_random(arg);
+            rn = "Random";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEControl));
+            rn = "VPEControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf0));
+            rn = "VPEConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf1));
+            rn = "VPEConf1";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_YQMask));
+            rn = "YQMask";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_VPESchedule));
+            rn = "VPESchedule";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_VPEScheFBack));
+            rn = "VPEScheFBack";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEOpt));
+            rn = "VPEOpt";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 2:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo0));
+            rn = "EntryLo0";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcstatus(arg);
+            rn = "TCStatus";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mfc0_tcbind(arg);
+            rn = "TCBind";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_dmfc0_tcrestart(arg);
+            rn = "TCRestart";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_dmfc0_tchalt(arg);
+            rn = "TCHalt";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_dmfc0_tccontext(arg);
+            rn = "TCContext";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_dmfc0_tcschedule(arg);
+            rn = "TCSchedule";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_dmfc0_tcschefback(arg);
+            rn = "TCScheFBack";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 3:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo1));
+            rn = "EntryLo1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 4:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_Context));
+            rn = "Context";
+            break;
+        case 1:
+//            gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 5:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageMask));
+            rn = "PageMask";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageGrain));
+            rn = "PageGrain";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 6:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Wired));
+            rn = "Wired";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf0));
+            rn = "SRSConf0";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf1));
+            rn = "SRSConf1";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf2));
+            rn = "SRSConf2";
+            break;
+        case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf3));
+            rn = "SRSConf3";
+            break;
+        case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf4));
+            rn = "SRSConf4";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 7:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_HWREna));
+            rn = "HWREna";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 8:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_BadVAddr));
+            rn = "BadVAddr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 9:
+        switch (sel) {
+        case 0:
+            /* Mark as an IO operation because we read the time.  */
+            if (use_icount)
+                gen_io_start();
+            gen_helper_mfc0_count(arg);
+            if (use_icount) {
+                gen_io_end();
+            }
+            /* Break the TB to be able to take timer interrupts immediately
+               after reading count.  */
+            ctx->bstate = BS_STOP;
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 10:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryHi));
+            rn = "EntryHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 11:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Compare));
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        break;
+    case 12:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Status));
+            rn = "Status";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_IntCtl));
+            rn = "IntCtl";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSCtl));
+            rn = "SRSCtl";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSMap));
+            rn = "SRSMap";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 13:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Cause));
+            rn = "Cause";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 14:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC));
+            rn = "EPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 15:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_PRid));
+            rn = "PRid";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_EBase));
+            rn = "EBase";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config0));
+            rn = "Config";
+            break;
+        case 1:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config1));
+            rn = "Config1";
+            break;
+        case 2:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config2));
+            rn = "Config2";
+            break;
+        case 3:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config3));
+            rn = "Config3";
+            break;
+       /* 6,7 are implementation dependent */
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config6));
+            rn = "Config6";
+            break;
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config7));
+            rn = "Config7";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 17:
+        switch (sel) {
+        case 0:
+            gen_helper_dmfc0_lladdr(arg);
+            rn = "LLAddr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 18:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(dmfc0_watchlo, arg, sel);
+            rn = "WatchLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 19:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mfc0_watchhi, arg, sel);
+            rn = "WatchHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 20:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS3);
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_XContext));
+            rn = "XContext";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 21:
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Framemask));
+            rn = "Framemask";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 22:
+        tcg_gen_movi_tl(arg, 0); /* unimplemented */
+        rn = "'Diagnostic"; /* implementation dependent */
+        break;
+    case 23:
+        switch (sel) {
+        case 0:
+            gen_helper_mfc0_debug(arg); /* EJTAG support */
+            rn = "Debug";
+            break;
+        case 1:
+//            gen_helper_dmfc0_tracecontrol(arg); /* PDtrace support */
+            rn = "TraceControl";
+//            break;
+        case 2:
+//            gen_helper_dmfc0_tracecontrol2(arg); /* PDtrace support */
+            rn = "TraceControl2";
+//            break;
+        case 3:
+//            gen_helper_dmfc0_usertracedata(arg); /* PDtrace support */
+            rn = "UserTraceData";
+//            break;
+        case 4:
+//            gen_helper_dmfc0_tracebpc(arg); /* PDtrace support */
+            rn = "TraceBPC";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 24:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC));
+            rn = "DEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 25:
+        switch (sel) {
+        case 0:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_Performance0));
+            rn = "Performance0";
+            break;
+        case 1:
+//            gen_helper_dmfc0_performance1(arg);
+            rn = "Performance1";
+//            break;
+        case 2:
+//            gen_helper_dmfc0_performance2(arg);
+            rn = "Performance2";
+//            break;
+        case 3:
+//            gen_helper_dmfc0_performance3(arg);
+            rn = "Performance3";
+//            break;
+        case 4:
+//            gen_helper_dmfc0_performance4(arg);
+            rn = "Performance4";
+//            break;
+        case 5:
+//            gen_helper_dmfc0_performance5(arg);
+            rn = "Performance5";
+//            break;
+        case 6:
+//            gen_helper_dmfc0_performance6(arg);
+            rn = "Performance6";
+//            break;
+        case 7:
+//            gen_helper_dmfc0_performance7(arg);
+            rn = "Performance7";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 26:
+        tcg_gen_movi_tl(arg, 0); /* unimplemented */
+        rn = "ECC";
+        break;
+    case 27:
+        switch (sel) {
+        /* ignored */
+        case 0 ... 3:
+            tcg_gen_movi_tl(arg, 0); /* unimplemented */
+            rn = "CacheErr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 28:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagLo));
+            rn = "TagLo";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataLo));
+            rn = "DataLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 29:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagHi));
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataHi));
+            rn = "DataHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 30:
+        switch (sel) {
+        case 0:
+            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC));
+            rn = "ErrorEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 31:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            gen_mfc0_load32(arg, offsetof(CPUState, CP0_DESAVE));
+            rn = "DESAVE";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    default:
+        goto die;
+    }
+    (void)rn; /* avoid a compiler warning */
+    LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    return;
+
+die:
+    LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
+{
+    const char *rn = "invalid";
+
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
+    if (use_icount)
+        gen_io_start();
+
+    switch (reg) {
+    case 0:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_index(arg);
+            rn = "Index";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_mvpcontrol(arg);
+            rn = "MVPControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            /* ignored */
+            rn = "MVPConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            /* ignored */
+            rn = "MVPConf1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 1:
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "Random";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpecontrol(arg);
+            rn = "VPEControl";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeconf0(arg);
+            rn = "VPEConf0";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeconf1(arg);
+            rn = "VPEConf1";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_yqmask(arg);
+            rn = "YQMask";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_VPESchedule));
+            rn = "VPESchedule";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_VPEScheFBack));
+            rn = "VPEScheFBack";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_vpeopt(arg);
+            rn = "VPEOpt";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 2:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entrylo0(arg);
+            rn = "EntryLo0";
+            break;
+        case 1:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcstatus(arg);
+            rn = "TCStatus";
+            break;
+        case 2:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcbind(arg);
+            rn = "TCBind";
+            break;
+        case 3:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcrestart(arg);
+            rn = "TCRestart";
+            break;
+        case 4:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tchalt(arg);
+            rn = "TCHalt";
+            break;
+        case 5:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tccontext(arg);
+            rn = "TCContext";
+            break;
+        case 6:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcschedule(arg);
+            rn = "TCSchedule";
+            break;
+        case 7:
+            check_insn(env, ctx, ASE_MT);
+            gen_helper_mtc0_tcschefback(arg);
+            rn = "TCScheFBack";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 3:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entrylo1(arg);
+            rn = "EntryLo1";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 4:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_context(arg);
+            rn = "Context";
+            break;
+        case 1:
+//           gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//           break;
+        default:
+            goto die;
+        }
+        break;
+    case 5:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_pagemask(arg);
+            rn = "PageMask";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_pagegrain(arg);
+            rn = "PageGrain";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 6:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_wired(arg);
+            rn = "Wired";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf0(arg);
+            rn = "SRSConf0";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf1(arg);
+            rn = "SRSConf1";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf2(arg);
+            rn = "SRSConf2";
+            break;
+        case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf3(arg);
+            rn = "SRSConf3";
+            break;
+        case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsconf4(arg);
+            rn = "SRSConf4";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 7:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_hwrena(arg);
+            rn = "HWREna";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 8:
+        /* ignored */
+        rn = "BadVAddr";
+        break;
+    case 9:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_count(arg);
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
+        break;
+    case 10:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_entryhi(arg);
+            rn = "EntryHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 11:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_compare(arg);
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            goto die;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
+        break;
+    case 12:
+        switch (sel) {
+        case 0:
+            save_cpu_state(ctx, 1);
+            gen_helper_mtc0_status(arg);
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Status";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_intctl(arg);
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "IntCtl";
+            break;
+        case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_srsctl(arg);
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSCtl";
+            break;
+        case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_mtc0_store32(arg, offsetof(CPUState, CP0_SRSMap));
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSMap";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 13:
+        switch (sel) {
+        case 0:
+            save_cpu_state(ctx, 1);
+            /* Mark as an IO operation because we may trigger a software
+               interrupt.  */
+            if (use_icount) {
+                gen_io_start();
+            }
+            gen_helper_mtc0_cause(arg);
+            if (use_icount) {
+                gen_io_end();
+            }
+            /* Stop translation as we may have triggered an intetrupt */
+            ctx->bstate = BS_STOP;
+            rn = "Cause";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 14:
+        switch (sel) {
+        case 0:
+            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC));
+            rn = "EPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 15:
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "PRid";
+            break;
+        case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_helper_mtc0_ebase(arg);
+            rn = "EBase";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_config0(arg);
+            rn = "Config";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            break;
+        case 1:
+            /* ignored, read only */
+            rn = "Config1";
+            break;
+        case 2:
+            gen_helper_mtc0_config2(arg);
+            rn = "Config2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            break;
+        case 3:
+            /* ignored */
+            rn = "Config3";
+            break;
+        /* 6,7 are implementation dependent */
+        default:
+            rn = "Invalid config selector";
+            goto die;
+        }
+        break;
+    case 17:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_lladdr(arg);
+            rn = "LLAddr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 18:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mtc0_watchlo, arg, sel);
+            rn = "WatchLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 19:
+        switch (sel) {
+        case 0 ... 7:
+            gen_helper_1i(mtc0_watchhi, arg, sel);
+            rn = "WatchHi";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 20:
+        switch (sel) {
+        case 0:
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_helper_mtc0_xcontext(arg);
+            rn = "XContext";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 21:
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_framemask(arg);
+            rn = "Framemask";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 22:
+        /* ignored */
+        rn = "Diagnostic"; /* implementation dependent */
+        break;
+    case 23:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_debug(arg); /* EJTAG support */
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Debug";
+            break;
+        case 1:
+//            gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceControl";
+//            break;
+        case 2:
+//            gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceControl2";
+//            break;
+        case 3:
+//            gen_helper_mtc0_usertracedata(arg); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "UserTraceData";
+//            break;
+        case 4:
+//            gen_helper_mtc0_tracebpc(arg); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceBPC";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 24:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC));
+            rn = "DEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 25:
+        switch (sel) {
+        case 0:
+            gen_helper_mtc0_performance0(arg);
+            rn = "Performance0";
+            break;
+        case 1:
+//            gen_helper_mtc0_performance1(arg);
+            rn = "Performance1";
+//            break;
+        case 2:
+//            gen_helper_mtc0_performance2(arg);
+            rn = "Performance2";
+//            break;
+        case 3:
+//            gen_helper_mtc0_performance3(arg);
+            rn = "Performance3";
+//            break;
+        case 4:
+//            gen_helper_mtc0_performance4(arg);
+            rn = "Performance4";
+//            break;
+        case 5:
+//            gen_helper_mtc0_performance5(arg);
+            rn = "Performance5";
+//            break;
+        case 6:
+//            gen_helper_mtc0_performance6(arg);
+            rn = "Performance6";
+//            break;
+        case 7:
+//            gen_helper_mtc0_performance7(arg);
+            rn = "Performance7";
+//            break;
+        default:
+            goto die;
+        }
+        break;
+    case 26:
+        /* ignored */
+        rn = "ECC";
+        break;
+    case 27:
+        switch (sel) {
+        case 0 ... 3:
+            /* ignored */
+            rn = "CacheErr";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 28:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_helper_mtc0_taglo(arg);
+            rn = "TagLo";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_helper_mtc0_datalo(arg);
+            rn = "DataLo";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 29:
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_helper_mtc0_taghi(arg);
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_helper_mtc0_datahi(arg);
+            rn = "DataHi";
+            break;
+        default:
+            rn = "invalid sel";
+            goto die;
+        }
+        break;
+    case 30:
+        switch (sel) {
+        case 0:
+            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC));
+            rn = "ErrorEPC";
+            break;
+        default:
+            goto die;
+        }
+        break;
+    case 31:
+        switch (sel) {
+        case 0:
+            /* EJTAG support */
+            gen_mtc0_store32(arg, offsetof(CPUState, CP0_DESAVE));
+            rn = "DESAVE";
+            break;
+        default:
+            goto die;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
+        break;
+    default:
+        goto die;
+    }
+    (void)rn; /* avoid a compiler warning */
+    LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    /* For simplicity assume that all writes can cause interrupts.  */
+    if (use_icount) {
+        gen_io_end();
+        ctx->bstate = BS_STOP;
+    }
+    return;
+
+die:
+    LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+    generate_exception(ctx, EXCP_RI);
+}
+#endif /* TARGET_MIPS64 */
+
+static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd,
+                     int u, int sel, int h)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    TCGv t0 = tcg_temp_local_new();
+
+    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
+        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
+        tcg_gen_movi_tl(t0, -1);
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        tcg_gen_movi_tl(t0, -1);
+    else if (u == 0) {
+        switch (rt) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_helper_mftc0_tcstatus(t0);
+                break;
+            case 2:
+                gen_helper_mftc0_tcbind(t0);
+                break;
+            case 3:
+                gen_helper_mftc0_tcrestart(t0);
+                break;
+            case 4:
+                gen_helper_mftc0_tchalt(t0);
+                break;
+            case 5:
+                gen_helper_mftc0_tccontext(t0);
+                break;
+            case 6:
+                gen_helper_mftc0_tcschedule(t0);
+                break;
+            case 7:
+                gen_helper_mftc0_tcschefback(t0);
+                break;
+            default:
+                gen_mfc0(env, ctx, t0, rt, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_helper_mftc0_entryhi(t0);
+                break;
+            default:
+                gen_mfc0(env, ctx, t0, rt, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_helper_mftc0_status(t0);
+                break;
+            default:
+                gen_mfc0(env, ctx, t0, rt, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_helper_mftc0_debug(t0);
+                break;
+            default:
+                gen_mfc0(env, ctx, t0, rt, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mfc0(env, ctx, t0, rt, sel);
+        }
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_helper_1i(mftgpr, t0, rt);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rt) {
+        case 0:
+            gen_helper_1i(mftlo, t0, 0);
+            break;
+        case 1:
+            gen_helper_1i(mfthi, t0, 0);
+            break;
+        case 2:
+            gen_helper_1i(mftacx, t0, 0);
+            break;
+        case 4:
+            gen_helper_1i(mftlo, t0, 1);
+            break;
+        case 5:
+            gen_helper_1i(mfthi, t0, 1);
+            break;
+        case 6:
+            gen_helper_1i(mftacx, t0, 1);
+            break;
+        case 8:
+            gen_helper_1i(mftlo, t0, 2);
+            break;
+        case 9:
+            gen_helper_1i(mfthi, t0, 2);
+            break;
+        case 10:
+            gen_helper_1i(mftacx, t0, 2);
+            break;
+        case 12:
+            gen_helper_1i(mftlo, t0, 3);
+            break;
+        case 13:
+            gen_helper_1i(mfthi, t0, 3);
+            break;
+        case 14:
+            gen_helper_1i(mftacx, t0, 3);
+            break;
+        case 16:
+            gen_helper_mftdsp(t0);
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, rt);
+            tcg_gen_ext_i32_tl(t0, fp0);
+            tcg_temp_free_i32(fp0);
+        } else {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32h(fp0, rt);
+            tcg_gen_ext_i32_tl(t0, fp0);
+            tcg_temp_free_i32(fp0);
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_helper_1i(cfc1, t0, rt);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
+    }
+    LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h);
+    gen_store_gpr(t0, rd);
+    tcg_temp_free(t0);
+    return;
+
+die:
+    tcg_temp_free(t0);
+    LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h);
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt,
+                     int u, int sel, int h)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    TCGv t0 = tcg_temp_local_new();
+
+    gen_load_gpr(t0, rt);
+    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
+        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
+        /* NOP */ ;
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        /* NOP */ ;
+    else if (u == 0) {
+        switch (rd) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_helper_mttc0_tcstatus(t0);
+                break;
+            case 2:
+                gen_helper_mttc0_tcbind(t0);
+                break;
+            case 3:
+                gen_helper_mttc0_tcrestart(t0);
+                break;
+            case 4:
+                gen_helper_mttc0_tchalt(t0);
+                break;
+            case 5:
+                gen_helper_mttc0_tccontext(t0);
+                break;
+            case 6:
+                gen_helper_mttc0_tcschedule(t0);
+                break;
+            case 7:
+                gen_helper_mttc0_tcschefback(t0);
+                break;
+            default:
+                gen_mtc0(env, ctx, t0, rd, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_helper_mttc0_entryhi(t0);
+                break;
+            default:
+                gen_mtc0(env, ctx, t0, rd, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_helper_mttc0_status(t0);
+                break;
+            default:
+                gen_mtc0(env, ctx, t0, rd, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_helper_mttc0_debug(t0);
+                break;
+            default:
+                gen_mtc0(env, ctx, t0, rd, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mtc0(env, ctx, t0, rd, sel);
+        }
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_helper_1i(mttgpr, t0, rd);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rd) {
+        case 0:
+            gen_helper_1i(mttlo, t0, 0);
+            break;
+        case 1:
+            gen_helper_1i(mtthi, t0, 0);
+            break;
+        case 2:
+            gen_helper_1i(mttacx, t0, 0);
+            break;
+        case 4:
+            gen_helper_1i(mttlo, t0, 1);
+            break;
+        case 5:
+            gen_helper_1i(mtthi, t0, 1);
+            break;
+        case 6:
+            gen_helper_1i(mttacx, t0, 1);
+            break;
+        case 8:
+            gen_helper_1i(mttlo, t0, 2);
+            break;
+        case 9:
+            gen_helper_1i(mtthi, t0, 2);
+            break;
+        case 10:
+            gen_helper_1i(mttacx, t0, 2);
+            break;
+        case 12:
+            gen_helper_1i(mttlo, t0, 3);
+            break;
+        case 13:
+            gen_helper_1i(mtthi, t0, 3);
+            break;
+        case 14:
+            gen_helper_1i(mttacx, t0, 3);
+            break;
+        case 16:
+            gen_helper_mttdsp(t0);
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32(fp0, rd);
+            tcg_temp_free_i32(fp0);
+        } else {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32h(fp0, rd);
+            tcg_temp_free_i32(fp0);
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_helper_1i(ctc1, t0, rd);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
+    }
+    LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h);
+    tcg_temp_free(t0);
+    return;
+
+die:
+    tcg_temp_free(t0);
+    LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h);
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd)
+{
+    const char *opn = "ldst";
+
+    switch (opc) {
+    case OPC_MFC0:
+        if (rt == 0) {
+            /* Treat as NOP. */
+            return;
+        }
+        gen_mfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7);
+        opn = "mfc0";
+        break;
+    case OPC_MTC0:
+        {
+            TCGv t0 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_mtc0(env, ctx, t0, rd, ctx->opcode & 0x7);
+            tcg_temp_free(t0);
+        }
+        opn = "mtc0";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMFC0:
+        check_insn(env, ctx, ISA_MIPS3);
+        if (rt == 0) {
+            /* Treat as NOP. */
+            return;
+        }
+        gen_dmfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7);
+        opn = "dmfc0";
+        break;
+    case OPC_DMTC0:
+        check_insn(env, ctx, ISA_MIPS3);
+        {
+            TCGv t0 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_dmtc0(env, ctx, t0, rd, ctx->opcode & 0x7);
+            tcg_temp_free(t0);
+        }
+        opn = "dmtc0";
+        break;
+#endif
+    case OPC_MFTR:
+        check_insn(env, ctx, ASE_MT);
+        if (rd == 0) {
+            /* Treat as NOP. */
+            return;
+        }
+        gen_mftr(env, ctx, rt, rd, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        opn = "mftr";
+        break;
+    case OPC_MTTR:
+        check_insn(env, ctx, ASE_MT);
+        gen_mttr(env, ctx, rd, rt, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        opn = "mttr";
+        break;
+    case OPC_TLBWI:
+        opn = "tlbwi";
+        if (!env->tlb->helper_tlbwi)
+            goto die;
+        gen_helper_tlbwi();
+        break;
+    case OPC_TLBWR:
+        opn = "tlbwr";
+        if (!env->tlb->helper_tlbwr)
+            goto die;
+        gen_helper_tlbwr();
+        break;
+    case OPC_TLBP:
+        opn = "tlbp";
+        if (!env->tlb->helper_tlbp)
+            goto die;
+        gen_helper_tlbp();
+        break;
+    case OPC_TLBR:
+        opn = "tlbr";
+        if (!env->tlb->helper_tlbr)
+            goto die;
+        gen_helper_tlbr();
+        break;
+    case OPC_ERET:
+        opn = "eret";
+        check_insn(env, ctx, ISA_MIPS2);
+        gen_helper_eret();
+        ctx->bstate = BS_EXCP;
+        break;
+    case OPC_DERET:
+        opn = "deret";
+        check_insn(env, ctx, ISA_MIPS32);
+        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+            MIPS_INVAL(opn);
+            generate_exception(ctx, EXCP_RI);
+        } else {
+            gen_helper_deret();
+            ctx->bstate = BS_EXCP;
+        }
+        break;
+    case OPC_WAIT:
+        opn = "wait";
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
+        /* If we get an exception, we want to restart at next instruction */
+        ctx->pc += 4;
+        save_cpu_state(ctx, 1);
+        ctx->pc -= 4;
+        gen_helper_wait();
+        ctx->bstate = BS_EXCP;
+        break;
+    default:
+ die:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
+}
+#endif /* !CONFIG_USER_ONLY */
+
+/* CP1 Branches (before delay slot) */
+static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
+                                 int32_t cc, int32_t offset)
+{
+    target_ulong btarget;
+    const char *opn = "cp1 cond branch";
+    TCGv_i32 t0 = tcg_temp_new_i32();
+
+    if (cc != 0)
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+
+    btarget = ctx->pc + 4 + offset;
+
+    switch (op) {
+    case OPC_BC1F:
+        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+        tcg_gen_not_i32(t0, t0);
+        tcg_gen_andi_i32(t0, t0, 1);
+        tcg_gen_extu_i32_tl(bcond, t0);
+        opn = "bc1f";
+        goto not_likely;
+    case OPC_BC1FL:
+        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+        tcg_gen_not_i32(t0, t0);
+        tcg_gen_andi_i32(t0, t0, 1);
+        tcg_gen_extu_i32_tl(bcond, t0);
+        opn = "bc1fl";
+        goto likely;
+    case OPC_BC1T:
+        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+        tcg_gen_andi_i32(t0, t0, 1);
+        tcg_gen_extu_i32_tl(bcond, t0);
+        opn = "bc1t";
+        goto not_likely;
+    case OPC_BC1TL:
+        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+        tcg_gen_andi_i32(t0, t0, 1);
+        tcg_gen_extu_i32_tl(bcond, t0);
+        opn = "bc1tl";
+    likely:
+        ctx->hflags |= MIPS_HFLAG_BL;
+        break;
+    case OPC_BC1FANY2:
+        {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
+            tcg_gen_nor_i32(t0, t0, t1);
+            tcg_temp_free_i32(t1);
+            tcg_gen_andi_i32(t0, t0, 1);
+            tcg_gen_extu_i32_tl(bcond, t0);
+        }
+        opn = "bc1any2f";
+        goto not_likely;
+    case OPC_BC1TANY2:
+        {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_temp_free_i32(t1);
+            tcg_gen_andi_i32(t0, t0, 1);
+            tcg_gen_extu_i32_tl(bcond, t0);
+        }
+        opn = "bc1any2t";
+        goto not_likely;
+    case OPC_BC1FANY4:
+        {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3));
+            tcg_gen_nor_i32(t0, t0, t1);
+            tcg_temp_free_i32(t1);
+            tcg_gen_andi_i32(t0, t0, 1);
+            tcg_gen_extu_i32_tl(bcond, t0);
+        }
+        opn = "bc1any4f";
+        goto not_likely;
+    case OPC_BC1TANY4:
+        {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3));
+            tcg_gen_or_i32(t0, t0, t1);
+            tcg_temp_free_i32(t1);
+            tcg_gen_andi_i32(t0, t0, 1);
+            tcg_gen_extu_i32_tl(bcond, t0);
+        }
+        opn = "bc1any4t";
+    not_likely:
+        ctx->hflags |= MIPS_HFLAG_BC;
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
+        goto out;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
+               ctx->hflags, btarget);
+    ctx->btarget = btarget;
+
+ out:
+    tcg_temp_free_i32(t0);
+}
+
+/* Coprocessor 1 (FPU) */
+
+#define FOP(func, fmt) (((fmt) << 21) | (func))
+
+enum fopcode {
+    OPC_ADD_S = FOP(0, FMT_S),
+    OPC_SUB_S = FOP(1, FMT_S),
+    OPC_MUL_S = FOP(2, FMT_S),
+    OPC_DIV_S = FOP(3, FMT_S),
+    OPC_SQRT_S = FOP(4, FMT_S),
+    OPC_ABS_S = FOP(5, FMT_S),
+    OPC_MOV_S = FOP(6, FMT_S),
+    OPC_NEG_S = FOP(7, FMT_S),
+    OPC_ROUND_L_S = FOP(8, FMT_S),
+    OPC_TRUNC_L_S = FOP(9, FMT_S),
+    OPC_CEIL_L_S = FOP(10, FMT_S),
+    OPC_FLOOR_L_S = FOP(11, FMT_S),
+    OPC_ROUND_W_S = FOP(12, FMT_S),
+    OPC_TRUNC_W_S = FOP(13, FMT_S),
+    OPC_CEIL_W_S = FOP(14, FMT_S),
+    OPC_FLOOR_W_S = FOP(15, FMT_S),
+    OPC_MOVCF_S = FOP(17, FMT_S),
+    OPC_MOVZ_S = FOP(18, FMT_S),
+    OPC_MOVN_S = FOP(19, FMT_S),
+    OPC_RECIP_S = FOP(21, FMT_S),
+    OPC_RSQRT_S = FOP(22, FMT_S),
+    OPC_RECIP2_S = FOP(28, FMT_S),
+    OPC_RECIP1_S = FOP(29, FMT_S),
+    OPC_RSQRT1_S = FOP(30, FMT_S),
+    OPC_RSQRT2_S = FOP(31, FMT_S),
+    OPC_CVT_D_S = FOP(33, FMT_S),
+    OPC_CVT_W_S = FOP(36, FMT_S),
+    OPC_CVT_L_S = FOP(37, FMT_S),
+    OPC_CVT_PS_S = FOP(38, FMT_S),
+    OPC_CMP_F_S = FOP (48, FMT_S),
+    OPC_CMP_UN_S = FOP (49, FMT_S),
+    OPC_CMP_EQ_S = FOP (50, FMT_S),
+    OPC_CMP_UEQ_S = FOP (51, FMT_S),
+    OPC_CMP_OLT_S = FOP (52, FMT_S),
+    OPC_CMP_ULT_S = FOP (53, FMT_S),
+    OPC_CMP_OLE_S = FOP (54, FMT_S),
+    OPC_CMP_ULE_S = FOP (55, FMT_S),
+    OPC_CMP_SF_S = FOP (56, FMT_S),
+    OPC_CMP_NGLE_S = FOP (57, FMT_S),
+    OPC_CMP_SEQ_S = FOP (58, FMT_S),
+    OPC_CMP_NGL_S = FOP (59, FMT_S),
+    OPC_CMP_LT_S = FOP (60, FMT_S),
+    OPC_CMP_NGE_S = FOP (61, FMT_S),
+    OPC_CMP_LE_S = FOP (62, FMT_S),
+    OPC_CMP_NGT_S = FOP (63, FMT_S),
+
+    OPC_ADD_D = FOP(0, FMT_D),
+    OPC_SUB_D = FOP(1, FMT_D),
+    OPC_MUL_D = FOP(2, FMT_D),
+    OPC_DIV_D = FOP(3, FMT_D),
+    OPC_SQRT_D = FOP(4, FMT_D),
+    OPC_ABS_D = FOP(5, FMT_D),
+    OPC_MOV_D = FOP(6, FMT_D),
+    OPC_NEG_D = FOP(7, FMT_D),
+    OPC_ROUND_L_D = FOP(8, FMT_D),
+    OPC_TRUNC_L_D = FOP(9, FMT_D),
+    OPC_CEIL_L_D = FOP(10, FMT_D),
+    OPC_FLOOR_L_D = FOP(11, FMT_D),
+    OPC_ROUND_W_D = FOP(12, FMT_D),
+    OPC_TRUNC_W_D = FOP(13, FMT_D),
+    OPC_CEIL_W_D = FOP(14, FMT_D),
+    OPC_FLOOR_W_D = FOP(15, FMT_D),
+    OPC_MOVCF_D = FOP(17, FMT_D),
+    OPC_MOVZ_D = FOP(18, FMT_D),
+    OPC_MOVN_D = FOP(19, FMT_D),
+    OPC_RECIP_D = FOP(21, FMT_D),
+    OPC_RSQRT_D = FOP(22, FMT_D),
+    OPC_RECIP2_D = FOP(28, FMT_D),
+    OPC_RECIP1_D = FOP(29, FMT_D),
+    OPC_RSQRT1_D = FOP(30, FMT_D),
+    OPC_RSQRT2_D = FOP(31, FMT_D),
+    OPC_CVT_S_D = FOP(32, FMT_D),
+    OPC_CVT_W_D = FOP(36, FMT_D),
+    OPC_CVT_L_D = FOP(37, FMT_D),
+    OPC_CMP_F_D = FOP (48, FMT_D),
+    OPC_CMP_UN_D = FOP (49, FMT_D),
+    OPC_CMP_EQ_D = FOP (50, FMT_D),
+    OPC_CMP_UEQ_D = FOP (51, FMT_D),
+    OPC_CMP_OLT_D = FOP (52, FMT_D),
+    OPC_CMP_ULT_D = FOP (53, FMT_D),
+    OPC_CMP_OLE_D = FOP (54, FMT_D),
+    OPC_CMP_ULE_D = FOP (55, FMT_D),
+    OPC_CMP_SF_D = FOP (56, FMT_D),
+    OPC_CMP_NGLE_D = FOP (57, FMT_D),
+    OPC_CMP_SEQ_D = FOP (58, FMT_D),
+    OPC_CMP_NGL_D = FOP (59, FMT_D),
+    OPC_CMP_LT_D = FOP (60, FMT_D),
+    OPC_CMP_NGE_D = FOP (61, FMT_D),
+    OPC_CMP_LE_D = FOP (62, FMT_D),
+    OPC_CMP_NGT_D = FOP (63, FMT_D),
+
+    OPC_CVT_S_W = FOP(32, FMT_W),
+    OPC_CVT_D_W = FOP(33, FMT_W),
+    OPC_CVT_S_L = FOP(32, FMT_L),
+    OPC_CVT_D_L = FOP(33, FMT_L),
+    OPC_CVT_PS_PW = FOP(38, FMT_W),
+
+    OPC_ADD_PS = FOP(0, FMT_PS),
+    OPC_SUB_PS = FOP(1, FMT_PS),
+    OPC_MUL_PS = FOP(2, FMT_PS),
+    OPC_DIV_PS = FOP(3, FMT_PS),
+    OPC_ABS_PS = FOP(5, FMT_PS),
+    OPC_MOV_PS = FOP(6, FMT_PS),
+    OPC_NEG_PS = FOP(7, FMT_PS),
+    OPC_MOVCF_PS = FOP(17, FMT_PS),
+    OPC_MOVZ_PS = FOP(18, FMT_PS),
+    OPC_MOVN_PS = FOP(19, FMT_PS),
+    OPC_ADDR_PS = FOP(24, FMT_PS),
+    OPC_MULR_PS = FOP(26, FMT_PS),
+    OPC_RECIP2_PS = FOP(28, FMT_PS),
+    OPC_RECIP1_PS = FOP(29, FMT_PS),
+    OPC_RSQRT1_PS = FOP(30, FMT_PS),
+    OPC_RSQRT2_PS = FOP(31, FMT_PS),
+
+    OPC_CVT_S_PU = FOP(32, FMT_PS),
+    OPC_CVT_PW_PS = FOP(36, FMT_PS),
+    OPC_CVT_S_PL = FOP(40, FMT_PS),
+    OPC_PLL_PS = FOP(44, FMT_PS),
+    OPC_PLU_PS = FOP(45, FMT_PS),
+    OPC_PUL_PS = FOP(46, FMT_PS),
+    OPC_PUU_PS = FOP(47, FMT_PS),
+    OPC_CMP_F_PS = FOP (48, FMT_PS),
+    OPC_CMP_UN_PS = FOP (49, FMT_PS),
+    OPC_CMP_EQ_PS = FOP (50, FMT_PS),
+    OPC_CMP_UEQ_PS = FOP (51, FMT_PS),
+    OPC_CMP_OLT_PS = FOP (52, FMT_PS),
+    OPC_CMP_ULT_PS = FOP (53, FMT_PS),
+    OPC_CMP_OLE_PS = FOP (54, FMT_PS),
+    OPC_CMP_ULE_PS = FOP (55, FMT_PS),
+    OPC_CMP_SF_PS = FOP (56, FMT_PS),
+    OPC_CMP_NGLE_PS = FOP (57, FMT_PS),
+    OPC_CMP_SEQ_PS = FOP (58, FMT_PS),
+    OPC_CMP_NGL_PS = FOP (59, FMT_PS),
+    OPC_CMP_LT_PS = FOP (60, FMT_PS),
+    OPC_CMP_NGE_PS = FOP (61, FMT_PS),
+    OPC_CMP_LE_PS = FOP (62, FMT_PS),
+    OPC_CMP_NGT_PS = FOP (63, FMT_PS),
+};
+
+static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
+{
+    const char *opn = "cp1 move";
+    TCGv t0 = tcg_temp_new();
+
+    switch (opc) {
+    case OPC_MFC1:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            tcg_gen_ext_i32_tl(t0, fp0);
+            tcg_temp_free_i32(fp0);
+        }
+        gen_store_gpr(t0, rt);
+        opn = "mfc1";
+        break;
+    case OPC_MTC1:
+        gen_load_gpr(t0, rt);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32(fp0, fs);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "mtc1";
+        break;
+    case OPC_CFC1:
+        gen_helper_1i(cfc1, t0, fs);
+        gen_store_gpr(t0, rt);
+        opn = "cfc1";
+        break;
+    case OPC_CTC1:
+        gen_load_gpr(t0, rt);
+        gen_helper_1i(ctc1, t0, fs);
+        opn = "ctc1";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMFC1:
+        gen_load_fpr64(ctx, t0, fs);
+        gen_store_gpr(t0, rt);
+        opn = "dmfc1";
+        break;
+    case OPC_DMTC1:
+        gen_load_gpr(t0, rt);
+        gen_store_fpr64(ctx, t0, fs);
+        opn = "dmtc1";
+        break;
+#endif
+    case OPC_MFHC1:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32h(fp0, fs);
+            tcg_gen_ext_i32_tl(t0, fp0);
+            tcg_temp_free_i32(fp0);
+        }
+        gen_store_gpr(t0, rt);
+        opn = "mfhc1";
+        break;
+    case OPC_MTHC1:
+        gen_load_gpr(t0, rt);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32h(fp0, fs);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "mthc1";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
+        goto out;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
+
+ out:
+    tcg_temp_free(t0);
+}
+
+static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+{
+    int l1;
+    TCGCond cond;
+    TCGv_i32 t0;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        return;
+    }
+
+    if (tf)
+        cond = TCG_COND_EQ;
+    else
+        cond = TCG_COND_NE;
+
+    l1 = gen_new_label();
+    t0 = tcg_temp_new_i32();
+    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
+    tcg_gen_brcondi_i32(cond, t0, 0, l1);
+    tcg_temp_free_i32(t0);
+    if (rs == 0) {
+        tcg_gen_movi_tl(cpu_gpr[rd], 0);
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
+    }
+    gen_set_label(l1);
+}
+
+static inline void gen_movcf_s (int fs, int fd, int cc, int tf)
+{
+    int cond;
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    int l1 = gen_new_label();
+
+    if (tf)
+        cond = TCG_COND_EQ;
+    else
+        cond = TCG_COND_NE;
+
+    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
+    tcg_gen_brcondi_i32(cond, t0, 0, l1);
+    gen_load_fpr32(t0, fs);
+    gen_store_fpr32(t0, fd);
+    gen_set_label(l1);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf)
+{
+    int cond;
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    TCGv_i64 fp0;
+    int l1 = gen_new_label();
+
+    if (tf)
+        cond = TCG_COND_EQ;
+    else
+        cond = TCG_COND_NE;
+
+    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
+    tcg_gen_brcondi_i32(cond, t0, 0, l1);
+    tcg_temp_free_i32(t0);
+    fp0 = tcg_temp_new_i64();
+    gen_load_fpr64(ctx, fp0, fs);
+    gen_store_fpr64(ctx, fp0, fd);
+    tcg_temp_free_i64(fp0);
+    gen_set_label(l1);
+}
+
+static inline void gen_movcf_ps (int fs, int fd, int cc, int tf)
+{
+    int cond;
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+
+    if (tf)
+        cond = TCG_COND_EQ;
+    else
+        cond = TCG_COND_NE;
+
+    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
+    tcg_gen_brcondi_i32(cond, t0, 0, l1);
+    gen_load_fpr32(t0, fs);
+    gen_store_fpr32(t0, fd);
+    gen_set_label(l1);
+
+    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc+1));
+    tcg_gen_brcondi_i32(cond, t0, 0, l2);
+    gen_load_fpr32h(t0, fs);
+    gen_store_fpr32h(t0, fd);
+    tcg_temp_free_i32(t0);
+    gen_set_label(l2);
+}
+
+
+static void gen_farith (DisasContext *ctx, enum fopcode op1,
+                        int ft, int fs, int fd, int cc)
+{
+    const char *opn = "farith";
+    const char *condnames[] = {
+            "c.f",
+            "c.un",
+            "c.eq",
+            "c.ueq",
+            "c.olt",
+            "c.ult",
+            "c.ole",
+            "c.ule",
+            "c.sf",
+            "c.ngle",
+            "c.seq",
+            "c.ngl",
+            "c.lt",
+            "c.nge",
+            "c.le",
+            "c.ngt",
+    };
+    const char *condnames_abs[] = {
+            "cabs.f",
+            "cabs.un",
+            "cabs.eq",
+            "cabs.ueq",
+            "cabs.olt",
+            "cabs.ult",
+            "cabs.ole",
+            "cabs.ule",
+            "cabs.sf",
+            "cabs.ngle",
+            "cabs.seq",
+            "cabs.ngl",
+            "cabs.lt",
+            "cabs.nge",
+            "cabs.le",
+            "cabs.ngt",
+    };
+    enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
+    uint32_t func = ctx->opcode & 0x3f;
+
+    switch (op1) {
+    case OPC_ADD_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_add_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "add.s";
+        optype = BINOP;
+        break;
+    case OPC_SUB_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_sub_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "sub.s";
+        optype = BINOP;
+        break;
+    case OPC_MUL_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_mul_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "mul.s";
+        optype = BINOP;
+        break;
+    case OPC_DIV_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_div_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "div.s";
+        optype = BINOP;
+        break;
+    case OPC_SQRT_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_sqrt_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "sqrt.s";
+        break;
+    case OPC_ABS_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_abs_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "abs.s";
+        break;
+    case OPC_MOV_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "mov.s";
+        break;
+    case OPC_NEG_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_chs_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "neg.s";
+        break;
+    case OPC_ROUND_L_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_roundl_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "round.l.s";
+        break;
+    case OPC_TRUNC_L_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_truncl_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "trunc.l.s";
+        break;
+    case OPC_CEIL_L_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_ceill_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "ceil.l.s";
+        break;
+    case OPC_FLOOR_L_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_floorl_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "floor.l.s";
+        break;
+    case OPC_ROUND_W_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_roundw_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "round.w.s";
+        break;
+    case OPC_TRUNC_W_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_truncw_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "trunc.w.s";
+        break;
+    case OPC_CEIL_W_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_ceilw_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "ceil.w.s";
+        break;
+    case OPC_FLOOR_W_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_floorw_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "floor.w.s";
+        break;
+    case OPC_MOVCF_S:
+        gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
+        opn = "movcf.s";
+        break;
+    case OPC_MOVZ_S:
+        {
+            int l1 = gen_new_label();
+            TCGv_i32 fp0;
+
+            if (ft != 0) {
+                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
+            }
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(fp0, fs);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+            gen_set_label(l1);
+        }
+        opn = "movz.s";
+        break;
+    case OPC_MOVN_S:
+        {
+            int l1 = gen_new_label();
+            TCGv_i32 fp0;
+
+            if (ft != 0) {
+                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
+                fp0 = tcg_temp_new_i32();
+                gen_load_fpr32(fp0, fs);
+                gen_store_fpr32(fp0, fd);
+                tcg_temp_free_i32(fp0);
+                gen_set_label(l1);
+            }
+        }
+        opn = "movn.s";
+        break;
+    case OPC_RECIP_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_recip_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "recip.s";
+        break;
+    case OPC_RSQRT_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_rsqrt_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "rsqrt.s";
+        break;
+    case OPC_RECIP2_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, fd);
+            gen_helper_float_recip2_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "recip2.s";
+        break;
+    case OPC_RECIP1_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_recip1_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "recip1.s";
+        break;
+    case OPC_RSQRT1_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_rsqrt1_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "rsqrt1.s";
+        break;
+    case OPC_RSQRT2_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_rsqrt2_s(fp0, fp0, fp1);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "rsqrt2.s";
+        break;
+    case OPC_CVT_D_S:
+        check_cp1_registers(ctx, fd);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_cvtd_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "cvt.d.s";
+        break;
+    case OPC_CVT_W_S:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_cvtw_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "cvt.w.s";
+        break;
+    case OPC_CVT_L_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_cvtl_s(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "cvt.l.s";
+        break;
+    case OPC_CVT_PS_S:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+            TCGv_i32 fp32_0 = tcg_temp_new_i32();
+            TCGv_i32 fp32_1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp32_0, fs);
+            gen_load_fpr32(fp32_1, ft);
+            tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1);
+            tcg_temp_free_i32(fp32_1);
+            tcg_temp_free_i32(fp32_0);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "cvt.ps.s";
+        break;
+    case OPC_CMP_F_S:
+    case OPC_CMP_UN_S:
+    case OPC_CMP_EQ_S:
+    case OPC_CMP_UEQ_S:
+    case OPC_CMP_OLT_S:
+    case OPC_CMP_ULT_S:
+    case OPC_CMP_OLE_S:
+    case OPC_CMP_ULE_S:
+    case OPC_CMP_SF_S:
+    case OPC_CMP_NGLE_S:
+    case OPC_CMP_SEQ_S:
+    case OPC_CMP_NGL_S:
+    case OPC_CMP_LT_S:
+    case OPC_CMP_NGE_S:
+    case OPC_CMP_LE_S:
+    case OPC_CMP_NGT_S:
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_s(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_s(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
+        }
+        break;
+    case OPC_ADD_D:
+        check_cp1_registers(ctx, fs | ft | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_add_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "add.d";
+        optype = BINOP;
+        break;
+    case OPC_SUB_D:
+        check_cp1_registers(ctx, fs | ft | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_sub_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "sub.d";
+        optype = BINOP;
+        break;
+    case OPC_MUL_D:
+        check_cp1_registers(ctx, fs | ft | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_mul_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "mul.d";
+        optype = BINOP;
+        break;
+    case OPC_DIV_D:
+        check_cp1_registers(ctx, fs | ft | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_div_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "div.d";
+        optype = BINOP;
+        break;
+    case OPC_SQRT_D:
+        check_cp1_registers(ctx, fs | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_sqrt_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "sqrt.d";
+        break;
+    case OPC_ABS_D:
+        check_cp1_registers(ctx, fs | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_abs_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "abs.d";
+        break;
+    case OPC_MOV_D:
+        check_cp1_registers(ctx, fs | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "mov.d";
+        break;
+    case OPC_NEG_D:
+        check_cp1_registers(ctx, fs | fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_chs_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "neg.d";
+        break;
+    case OPC_ROUND_L_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_roundl_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "round.l.d";
+        break;
+    case OPC_TRUNC_L_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_truncl_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "trunc.l.d";
+        break;
+    case OPC_CEIL_L_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_ceill_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "ceil.l.d";
+        break;
+    case OPC_FLOOR_L_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_floorl_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "floor.l.d";
+        break;
+    case OPC_ROUND_W_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_roundw_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "round.w.d";
+        break;
+    case OPC_TRUNC_W_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_truncw_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "trunc.w.d";
+        break;
+    case OPC_CEIL_W_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_ceilw_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "ceil.w.d";
+        break;
+    case OPC_FLOOR_W_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_floorw_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "floor.w.d";
+        break;
+    case OPC_MOVCF_D:
+        gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
+        opn = "movcf.d";
+        break;
+    case OPC_MOVZ_D:
+        {
+            int l1 = gen_new_label();
+            TCGv_i64 fp0;
+
+            if (ft != 0) {
+                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
+            }
+            fp0 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+            gen_set_label(l1);
+        }
+        opn = "movz.d";
+        break;
+    case OPC_MOVN_D:
+        {
+            int l1 = gen_new_label();
+            TCGv_i64 fp0;
+
+            if (ft != 0) {
+                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
+                fp0 = tcg_temp_new_i64();
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+                gen_set_label(l1);
+            }
+        }
+        opn = "movn.d";
+        break;
+    case OPC_RECIP_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_recip_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "recip.d";
+        break;
+    case OPC_RSQRT_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_rsqrt_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "rsqrt.d";
+        break;
+    case OPC_RECIP2_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_recip2_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "recip2.d";
+        break;
+    case OPC_RECIP1_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_recip1_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "recip1.d";
+        break;
+    case OPC_RSQRT1_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_rsqrt1_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "rsqrt1.d";
+        break;
+    case OPC_RSQRT2_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_rsqrt2_d(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "rsqrt2.d";
+        break;
+    case OPC_CMP_F_D:
+    case OPC_CMP_UN_D:
+    case OPC_CMP_EQ_D:
+    case OPC_CMP_UEQ_D:
+    case OPC_CMP_OLT_D:
+    case OPC_CMP_ULT_D:
+    case OPC_CMP_OLE_D:
+    case OPC_CMP_ULE_D:
+    case OPC_CMP_SF_D:
+    case OPC_CMP_NGLE_D:
+    case OPC_CMP_SEQ_D:
+    case OPC_CMP_NGL_D:
+    case OPC_CMP_LT_D:
+    case OPC_CMP_NGE_D:
+    case OPC_CMP_LE_D:
+    case OPC_CMP_NGT_D:
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_d(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_d(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
+        }
+        break;
+    case OPC_CVT_S_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_cvts_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "cvt.s.d";
+        break;
+    case OPC_CVT_W_D:
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_cvtw_d(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "cvt.w.d";
+        break;
+    case OPC_CVT_L_D:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_cvtl_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "cvt.l.d";
+        break;
+    case OPC_CVT_S_W:
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_cvts_w(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "cvt.s.w";
+        break;
+    case OPC_CVT_D_W:
+        check_cp1_registers(ctx, fd);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr32(fp32, fs);
+            gen_helper_float_cvtd_w(fp64, fp32);
+            tcg_temp_free_i32(fp32);
+            gen_store_fpr64(ctx, fp64, fd);
+            tcg_temp_free_i64(fp64);
+        }
+        opn = "cvt.d.w";
+        break;
+    case OPC_CVT_S_L:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp32 = tcg_temp_new_i32();
+            TCGv_i64 fp64 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp64, fs);
+            gen_helper_float_cvts_l(fp32, fp64);
+            tcg_temp_free_i64(fp64);
+            gen_store_fpr32(fp32, fd);
+            tcg_temp_free_i32(fp32);
+        }
+        opn = "cvt.s.l";
+        break;
+    case OPC_CVT_D_L:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_cvtd_l(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "cvt.d.l";
+        break;
+    case OPC_CVT_PS_PW:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_cvtps_pw(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "cvt.ps.pw";
+        break;
+    case OPC_ADD_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_add_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "add.ps";
+        break;
+    case OPC_SUB_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_sub_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "sub.ps";
+        break;
+    case OPC_MUL_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_mul_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "mul.ps";
+        break;
+    case OPC_ABS_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_abs_ps(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "abs.ps";
+        break;
+    case OPC_MOV_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "mov.ps";
+        break;
+    case OPC_NEG_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_chs_ps(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "neg.ps";
+        break;
+    case OPC_MOVCF_PS:
+        check_cp1_64bitmode(ctx);
+        gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
+        opn = "movcf.ps";
+        break;
+    case OPC_MOVZ_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            int l1 = gen_new_label();
+            TCGv_i64 fp0;
+
+            if (ft != 0)
+                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
+            fp0 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+            gen_set_label(l1);
+        }
+        opn = "movz.ps";
+        break;
+    case OPC_MOVN_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            int l1 = gen_new_label();
+            TCGv_i64 fp0;
+
+            if (ft != 0) {
+                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
+                fp0 = tcg_temp_new_i64();
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+                gen_set_label(l1);
+            }
+        }
+        opn = "movn.ps";
+        break;
+    case OPC_ADDR_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, ft);
+            gen_load_fpr64(ctx, fp1, fs);
+            gen_helper_float_addr_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "addr.ps";
+        break;
+    case OPC_MULR_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, ft);
+            gen_load_fpr64(ctx, fp1, fs);
+            gen_helper_float_mulr_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "mulr.ps";
+        break;
+    case OPC_RECIP2_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, fd);
+            gen_helper_float_recip2_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "recip2.ps";
+        break;
+    case OPC_RECIP1_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_recip1_ps(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "recip1.ps";
+        break;
+    case OPC_RSQRT1_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_rsqrt1_ps(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "rsqrt1.ps";
+        break;
+    case OPC_RSQRT2_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_rsqrt2_ps(fp0, fp0, fp1);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "rsqrt2.ps";
+        break;
+    case OPC_CVT_S_PU:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32h(fp0, fs);
+            gen_helper_float_cvts_pu(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "cvt.s.pu";
+        break;
+    case OPC_CVT_PW_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_cvtpw_ps(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "cvt.pw.ps";
+        break;
+    case OPC_CVT_S_PL:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_cvts_pl(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "cvt.s.pl";
+        break;
+    case OPC_PLL_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_store_fpr32h(fp0, fd);
+            gen_store_fpr32(fp1, fd);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+        }
+        opn = "pll.ps";
+        break;
+    case OPC_PLU_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32h(fp1, ft);
+            gen_store_fpr32(fp1, fd);
+            gen_store_fpr32h(fp0, fd);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+        }
+        opn = "plu.ps";
+        break;
+    case OPC_PUL_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32h(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_store_fpr32(fp1, fd);
+            gen_store_fpr32h(fp0, fd);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+        }
+        opn = "pul.ps";
+        break;
+    case OPC_PUU_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+
+            gen_load_fpr32h(fp0, fs);
+            gen_load_fpr32h(fp1, ft);
+            gen_store_fpr32(fp1, fd);
+            gen_store_fpr32h(fp0, fd);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+        }
+        opn = "puu.ps";
+        break;
+    case OPC_CMP_F_PS:
+    case OPC_CMP_UN_PS:
+    case OPC_CMP_EQ_PS:
+    case OPC_CMP_UEQ_PS:
+    case OPC_CMP_OLT_PS:
+    case OPC_CMP_ULT_PS:
+    case OPC_CMP_OLE_PS:
+    case OPC_CMP_ULE_PS:
+    case OPC_CMP_SF_PS:
+    case OPC_CMP_NGLE_PS:
+    case OPC_CMP_SEQ_PS:
+    case OPC_CMP_NGL_PS:
+    case OPC_CMP_LT_PS:
+    case OPC_CMP_NGE_PS:
+    case OPC_CMP_LE_PS:
+    case OPC_CMP_NGT_PS:
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_ps(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_ps(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
+        }
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
+        return;
+    }
+    (void)opn; /* avoid a compiler warning */
+    switch (optype) {
+    case BINOP:
+        MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
+        break;
+    case CMPOP:
+        MIPS_DEBUG("%s %s,%s", opn, fregnames[fs], fregnames[ft]);
+        break;
+    default:
+        MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
+        break;
+    }
+}
+
+/* Coprocessor 3 (FPU) */
+static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
+                           int fd, int fs, int base, int index)
+{
+    const char *opn = "extended float load/store";
+    int store = 0;
+    TCGv t0 = tcg_temp_new();
+
+    if (base == 0) {
+        gen_load_gpr(t0, index);
+    } else if (index == 0) {
+        gen_load_gpr(t0, base);
+    } else {
+        gen_load_gpr(t0, index);
+        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
+    }
+    /* Don't do NOP if destination is zero: we must perform the actual
+       memory access. */
+    save_cpu_state(ctx, 0);
+    switch (opc) {
+    case OPC_LWXC1:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+
+            tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx);
+            tcg_gen_trunc_tl_i32(fp0, t0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+        }
+        opn = "lwxc1";
+        break;
+    case OPC_LDXC1:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "ldxc1";
+        break;
+    case OPC_LUXC1:
+        check_cp1_64bitmode(ctx);
+        tcg_gen_andi_tl(t0, t0, ~0x7);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "luxc1";
+        break;
+    case OPC_SWXC1:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv t1 = tcg_temp_new();
+
+            gen_load_fpr32(fp0, fs);
+            tcg_gen_extu_i32_tl(t1, fp0);
+            tcg_gen_qemu_st32(t1, t0, ctx->mem_idx);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free(t1);
+        }
+        opn = "swxc1";
+        store = 1;
+        break;
+    case OPC_SDXC1:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fs);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "sdxc1";
+        store = 1;
+        break;
+    case OPC_SUXC1:
+        check_cp1_64bitmode(ctx);
+        tcg_gen_andi_tl(t0, t0, ~0x7);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+            tcg_temp_free_i64(fp0);
+        }
+        opn = "suxc1";
+        store = 1;
+        break;
+    }
+    tcg_temp_free(t0);
+    (void)opn; (void)store; /* avoid compiler warnings */
+    MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
+               regnames[index], regnames[base]);
+}
+
+static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
+                            int fd, int fr, int fs, int ft)
+{
+    const char *opn = "flt3_arith";
+
+    switch (opc) {
+    case OPC_ALNV_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv t0 = tcg_temp_local_new();
+            TCGv_i32 fp = tcg_temp_new_i32();
+            TCGv_i32 fph = tcg_temp_new_i32();
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+
+            gen_load_gpr(t0, fr);
+            tcg_gen_andi_tl(t0, t0, 0x7);
+
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
+            gen_load_fpr32(fp, fs);
+            gen_load_fpr32h(fph, fs);
+            gen_store_fpr32(fp, fd);
+            gen_store_fpr32h(fph, fd);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2);
+            tcg_temp_free(t0);
+#ifdef TARGET_WORDS_BIGENDIAN
+            gen_load_fpr32(fp, fs);
+            gen_load_fpr32h(fph, ft);
+            gen_store_fpr32h(fp, fd);
+            gen_store_fpr32(fph, fd);
+#else
+            gen_load_fpr32h(fph, fs);
+            gen_load_fpr32(fp, ft);
+            gen_store_fpr32(fph, fd);
+            gen_store_fpr32h(fp, fd);
+#endif
+            gen_set_label(l2);
+            tcg_temp_free_i32(fp);
+            tcg_temp_free_i32(fph);
+        }
+        opn = "alnv.ps";
+        break;
+    case OPC_MADD_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_load_fpr32(fp2, fr);
+            gen_helper_float_muladd_s(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+        }
+        opn = "madd.s";
+        break;
+    case OPC_MADD_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_muladd_d(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "madd.d";
+        break;
+    case OPC_MADD_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_muladd_ps(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "madd.ps";
+        break;
+    case OPC_MSUB_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_load_fpr32(fp2, fr);
+            gen_helper_float_mulsub_s(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+        }
+        opn = "msub.s";
+        break;
+    case OPC_MSUB_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_mulsub_d(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "msub.d";
+        break;
+    case OPC_MSUB_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_mulsub_ps(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "msub.ps";
+        break;
+    case OPC_NMADD_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_load_fpr32(fp2, fr);
+            gen_helper_float_nmuladd_s(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+        }
+        opn = "nmadd.s";
+        break;
+    case OPC_NMADD_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_nmuladd_d(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "nmadd.d";
+        break;
+    case OPC_NMADD_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_nmuladd_ps(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "nmadd.ps";
+        break;
+    case OPC_NMSUB_S:
+        check_cop1x(ctx);
+        {
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_load_fpr32(fp2, fr);
+            gen_helper_float_nmulsub_s(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free_i32(fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+        }
+        opn = "nmsub.s";
+        break;
+    case OPC_NMSUB_D:
+        check_cop1x(ctx);
+        check_cp1_registers(ctx, fd | fs | ft | fr);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_nmulsub_d(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "nmsub.d";
+        break;
+    case OPC_NMSUB_PS:
+        check_cp1_64bitmode(ctx);
+        {
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
+
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fr);
+            gen_helper_float_nmulsub_ps(fp2, fp0, fp1, fp2);
+            tcg_temp_free_i64(fp0);
+            tcg_temp_free_i64(fp1);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+        }
+        opn = "nmsub.ps";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
+        return;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
+               fregnames[fs], fregnames[ft]);
+}
+
+static void
+gen_rdhwr (CPUState *env, DisasContext *ctx, int rt, int rd)
+{
+    TCGv t0;
+
+    check_insn(env, ctx, ISA_MIPS32R2);
+    t0 = tcg_temp_new();
+
+    switch (rd) {
+    case 0:
+        save_cpu_state(ctx, 1);
+        gen_helper_rdhwr_cpunum(t0);
+        gen_store_gpr(t0, rt);
+        break;
+    case 1:
+        save_cpu_state(ctx, 1);
+        gen_helper_rdhwr_synci_step(t0);
+        gen_store_gpr(t0, rt);
+        break;
+    case 2:
+        save_cpu_state(ctx, 1);
+        gen_helper_rdhwr_cc(t0);
+        gen_store_gpr(t0, rt);
+        break;
+    case 3:
+        save_cpu_state(ctx, 1);
+        gen_helper_rdhwr_ccres(t0);
+        gen_store_gpr(t0, rt);
+        break;
+    case 29:
+#if defined(CONFIG_USER_ONLY)
+        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value));
+        gen_store_gpr(t0, rt);
+        break;
+#else
+        /* XXX: Some CPUs implement this in hardware.
+           Not supported yet. */
+#endif
+    default:            /* Invalid */
+        MIPS_INVAL("rdhwr");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+    tcg_temp_free(t0);
+}
+
+static void handle_delay_slot (CPUState *env, DisasContext *ctx,
+                               int insn_bytes)
+{
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
+        /* Branches completion */
+        ctx->hflags &= ~MIPS_HFLAG_BMASK;
+        ctx->bstate = BS_BRANCH;
+        save_cpu_state(ctx, 0);
+        /* FIXME: Need to clear can_do_io.  */
+        switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) {
+        case MIPS_HFLAG_B:
+            /* unconditional branch */
+            MIPS_DEBUG("unconditional branch");
+            if (proc_hflags & MIPS_HFLAG_BX) {
+                tcg_gen_xori_i32(hflags, hflags, MIPS_HFLAG_M16);
+            }
+            gen_goto_tb(ctx, 0, ctx->btarget);
+            break;
+        case MIPS_HFLAG_BL:
+            /* blikely taken case */
+            MIPS_DEBUG("blikely branch taken");
+            gen_goto_tb(ctx, 0, ctx->btarget);
+            break;
+        case MIPS_HFLAG_BC:
+            /* Conditional branch */
+            MIPS_DEBUG("conditional branch");
+            {
+                int l1 = gen_new_label();
+
+                tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+                gen_goto_tb(ctx, 1, ctx->pc + insn_bytes);
+                gen_set_label(l1);
+                gen_goto_tb(ctx, 0, ctx->btarget);
+            }
+            break;
+        case MIPS_HFLAG_BR:
+            /* unconditional branch to register */
+            MIPS_DEBUG("branch to register");
+            if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
+                TCGv t0 = tcg_temp_new();
+                TCGv_i32 t1 = tcg_temp_new_i32();
+
+                tcg_gen_andi_tl(t0, btarget, 0x1);
+                tcg_gen_trunc_tl_i32(t1, t0);
+                tcg_temp_free(t0);
+                tcg_gen_andi_i32(hflags, hflags, ~(uint32_t)MIPS_HFLAG_M16);
+                tcg_gen_shli_i32(t1, t1, MIPS_HFLAG_M16_SHIFT);
+                tcg_gen_or_i32(hflags, hflags, t1);
+                tcg_temp_free_i32(t1);
+
+                tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
+            } else {
+                tcg_gen_mov_tl(cpu_PC, btarget);
+            }
+            if (ctx->singlestep_enabled) {
+                save_cpu_state(ctx, 0);
+                gen_helper_0i(raise_exception, EXCP_DEBUG);
+            }
+            tcg_gen_exit_tb(0);
+            break;
+        default:
+            MIPS_DEBUG("unknown branch");
+            break;
+        }
+    }
+}
+
+/* ISA extensions (ASEs) */
+/* MIPS16 extension to MIPS32 */
+
+/* MIPS16 major opcodes */
+enum {
+  M16_OPC_ADDIUSP = 0x00,
+  M16_OPC_ADDIUPC = 0x01,
+  M16_OPC_B = 0x02,
+  M16_OPC_JAL = 0x03,
+  M16_OPC_BEQZ = 0x04,
+  M16_OPC_BNEQZ = 0x05,
+  M16_OPC_SHIFT = 0x06,
+  M16_OPC_LD = 0x07,
+  M16_OPC_RRIA = 0x08,
+  M16_OPC_ADDIU8 = 0x09,
+  M16_OPC_SLTI = 0x0a,
+  M16_OPC_SLTIU = 0x0b,
+  M16_OPC_I8 = 0x0c,
+  M16_OPC_LI = 0x0d,
+  M16_OPC_CMPI = 0x0e,
+  M16_OPC_SD = 0x0f,
+  M16_OPC_LB = 0x10,
+  M16_OPC_LH = 0x11,
+  M16_OPC_LWSP = 0x12,
+  M16_OPC_LW = 0x13,
+  M16_OPC_LBU = 0x14,
+  M16_OPC_LHU = 0x15,
+  M16_OPC_LWPC = 0x16,
+  M16_OPC_LWU = 0x17,
+  M16_OPC_SB = 0x18,
+  M16_OPC_SH = 0x19,
+  M16_OPC_SWSP = 0x1a,
+  M16_OPC_SW = 0x1b,
+  M16_OPC_RRR = 0x1c,
+  M16_OPC_RR = 0x1d,
+  M16_OPC_EXTEND = 0x1e,
+  M16_OPC_I64 = 0x1f
+};
+
+/* I8 funct field */
+enum {
+  I8_BTEQZ = 0x0,
+  I8_BTNEZ = 0x1,
+  I8_SWRASP = 0x2,
+  I8_ADJSP = 0x3,
+  I8_SVRS = 0x4,
+  I8_MOV32R = 0x5,
+  I8_MOVR32 = 0x7
+};
+
+/* RRR f field */
+enum {
+  RRR_DADDU = 0x0,
+  RRR_ADDU = 0x1,
+  RRR_DSUBU = 0x2,
+  RRR_SUBU = 0x3
+};
+
+/* RR funct field */
+enum {
+  RR_JR = 0x00,
+  RR_SDBBP = 0x01,
+  RR_SLT = 0x02,
+  RR_SLTU = 0x03,
+  RR_SLLV = 0x04,
+  RR_BREAK = 0x05,
+  RR_SRLV = 0x06,
+  RR_SRAV = 0x07,
+  RR_DSRL = 0x08,
+  RR_CMP = 0x0a,
+  RR_NEG = 0x0b,
+  RR_AND = 0x0c,
+  RR_OR = 0x0d,
+  RR_XOR = 0x0e,
+  RR_NOT = 0x0f,
+  RR_MFHI = 0x10,
+  RR_CNVT = 0x11,
+  RR_MFLO = 0x12,
+  RR_DSRA = 0x13,
+  RR_DSLLV = 0x14,
+  RR_DSRLV = 0x16,
+  RR_DSRAV = 0x17,
+  RR_MULT = 0x18,
+  RR_MULTU = 0x19,
+  RR_DIV = 0x1a,
+  RR_DIVU = 0x1b,
+  RR_DMULT = 0x1c,
+  RR_DMULTU = 0x1d,
+  RR_DDIV = 0x1e,
+  RR_DDIVU = 0x1f
+};
+
+/* I64 funct field */
+enum {
+  I64_LDSP = 0x0,
+  I64_SDSP = 0x1,
+  I64_SDRASP = 0x2,
+  I64_DADJSP = 0x3,
+  I64_LDPC = 0x4,
+  I64_DADDIU5 = 0x5,
+  I64_DADDIUPC = 0x6,
+  I64_DADDIUSP = 0x7
+};
+
+/* RR ry field for CNVT */
+enum {
+  RR_RY_CNVT_ZEB = 0x0,
+  RR_RY_CNVT_ZEH = 0x1,
+  RR_RY_CNVT_ZEW = 0x2,
+  RR_RY_CNVT_SEB = 0x4,
+  RR_RY_CNVT_SEH = 0x5,
+  RR_RY_CNVT_SEW = 0x6,
+};
+
+static int xlat (int r)
+{
+  static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+  return map[r];
+}
+
+static void gen_mips16_save (DisasContext *ctx,
+                             int xsregs, int aregs,
+                             int do_ra, int do_s0, int do_s1,
+                             int framesize)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    int args, astatic;
+
+    switch (aregs) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 11:
+        args = 0;
+        break;
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+        args = 1;
+        break;
+    case 8:
+    case 9:
+    case 10:
+        args = 2;
+        break;
+    case 12:
+    case 13:
+        args = 3;
+        break;
+    case 14:
+        args = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    switch (args) {
+    case 4:
+        gen_base_offset_addr(ctx, t0, 29, 12);
+        gen_load_gpr(t1, 7);
+        op_st_sw(t1, t0, ctx);
+        /* Fall through */
+    case 3:
+        gen_base_offset_addr(ctx, t0, 29, 8);
+        gen_load_gpr(t1, 6);
+        op_st_sw(t1, t0, ctx);
+        /* Fall through */
+    case 2:
+        gen_base_offset_addr(ctx, t0, 29, 4);
+        gen_load_gpr(t1, 5);
+        op_st_sw(t1, t0, ctx);
+        /* Fall through */
+    case 1:
+        gen_base_offset_addr(ctx, t0, 29, 0);
+        gen_load_gpr(t1, 4);
+        op_st_sw(t1, t0, ctx);
+    }
+
+    gen_load_gpr(t0, 29);
+
+#define DECR_AND_STORE(reg) do {                \
+        tcg_gen_subi_tl(t0, t0, 4);             \
+        gen_load_gpr(t1, reg);                  \
+        op_st_sw(t1, t0, ctx);                  \
+    } while (0)
+
+    if (do_ra) {
+        DECR_AND_STORE(31);
+    }
+
+    switch (xsregs) {
+    case 7:
+        DECR_AND_STORE(30);
+        /* Fall through */
+    case 6:
+        DECR_AND_STORE(23);
+        /* Fall through */
+    case 5:
+        DECR_AND_STORE(22);
+        /* Fall through */
+    case 4:
+        DECR_AND_STORE(21);
+        /* Fall through */
+    case 3:
+        DECR_AND_STORE(20);
+        /* Fall through */
+    case 2:
+        DECR_AND_STORE(19);
+        /* Fall through */
+    case 1:
+        DECR_AND_STORE(18);
+    }
+
+    if (do_s1) {
+        DECR_AND_STORE(17);
+    }
+    if (do_s0) {
+        DECR_AND_STORE(16);
+    }
+
+    switch (aregs) {
+    case 0:
+    case 4:
+    case 8:
+    case 12:
+    case 14:
+        astatic = 0;
+        break;
+    case 1:
+    case 5:
+    case 9:
+    case 13:
+        astatic = 1;
+        break;
+    case 2:
+    case 6:
+    case 10:
+        astatic = 2;
+        break;
+    case 3:
+    case 7:
+        astatic = 3;
+        break;
+    case 11:
+        astatic = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    if (astatic > 0) {
+        DECR_AND_STORE(7);
+        if (astatic > 1) {
+            DECR_AND_STORE(6);
+            if (astatic > 2) {
+                DECR_AND_STORE(5);
+                if (astatic > 3) {
+                    DECR_AND_STORE(4);
+                }
+            }
+        }
+    }
+#undef DECR_AND_STORE
+
+    tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_mips16_restore (DisasContext *ctx,
+                                int xsregs, int aregs,
+                                int do_ra, int do_s0, int do_s1,
+                                int framesize)
+{
+    int astatic;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);
+
+#define DECR_AND_LOAD(reg) do {                 \
+        tcg_gen_subi_tl(t0, t0, 4);             \
+        op_ld_lw(t1, t0, ctx);                  \
+        gen_store_gpr(t1, reg);                 \
+    } while (0)
+
+    if (do_ra) {
+        DECR_AND_LOAD(31);
+    }
+
+    switch (xsregs) {
+    case 7:
+        DECR_AND_LOAD(30);
+        /* Fall through */
+    case 6:
+        DECR_AND_LOAD(23);
+        /* Fall through */
+    case 5:
+        DECR_AND_LOAD(22);
+        /* Fall through */
+    case 4:
+        DECR_AND_LOAD(21);
+        /* Fall through */
+    case 3:
+        DECR_AND_LOAD(20);
+        /* Fall through */
+    case 2:
+        DECR_AND_LOAD(19);
+        /* Fall through */
+    case 1:
+        DECR_AND_LOAD(18);
+    }
+
+    if (do_s1) {
+        DECR_AND_LOAD(17);
+    }
+    if (do_s0) {
+        DECR_AND_LOAD(16);
+    }
+
+    switch (aregs) {
+    case 0:
+    case 4:
+    case 8:
+    case 12:
+    case 14:
+        astatic = 0;
+        break;
+    case 1:
+    case 5:
+    case 9:
+    case 13:
+        astatic = 1;
+        break;
+    case 2:
+    case 6:
+    case 10:
+        astatic = 2;
+        break;
+    case 3:
+    case 7:
+        astatic = 3;
+        break;
+    case 11:
+        astatic = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    if (astatic > 0) {
+        DECR_AND_LOAD(7);
+        if (astatic > 1) {
+            DECR_AND_LOAD(6);
+            if (astatic > 2) {
+                DECR_AND_LOAD(5);
+                if (astatic > 3) {
+                    DECR_AND_LOAD(4);
+                }
+            }
+        }
+    }
+#undef DECR_AND_LOAD
+
+    tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_addiupc (DisasContext *ctx, int rx, int imm,
+                         int is_64_bit, int extended)
+{
+    TCGv t0;
+
+    if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) {
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+
+    tcg_gen_movi_tl(t0, pc_relative_pc(ctx));
+    tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
+    if (!is_64_bit) {
+        tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+    }
+
+    tcg_temp_free(t0);
+}
+
+#if defined(TARGET_MIPS64)
+static void decode_i64_mips16 (CPUState *env, DisasContext *ctx,
+                               int ry, int funct, int16_t offset,
+                               int extended)
+{
+    switch (funct) {
+    case I64_LDSP:
+        check_mips_64(ctx);
+        offset = extended ? offset : offset << 3;
+        gen_ld(env, ctx, OPC_LD, ry, 29, offset);
+        break;
+    case I64_SDSP:
+        check_mips_64(ctx);
+        offset = extended ? offset : offset << 3;
+        gen_st(ctx, OPC_SD, ry, 29, offset);
+        break;
+    case I64_SDRASP:
+        check_mips_64(ctx);
+        offset = extended ? offset : (ctx->opcode & 0xff) << 3;
+        gen_st(ctx, OPC_SD, 31, 29, offset);
+        break;
+    case I64_DADJSP:
+        check_mips_64(ctx);
+        offset = extended ? offset : ((int8_t)ctx->opcode) << 3;
+        gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29, offset);
+        break;
+    case I64_LDPC:
+        if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) {
+            generate_exception(ctx, EXCP_RI);
+        } else {
+            offset = extended ? offset : offset << 3;
+            gen_ld(env, ctx, OPC_LDPC, ry, 0, offset);
+        }
+        break;
+    case I64_DADDIU5:
+        check_mips_64(ctx);
+        offset = extended ? offset : ((int8_t)(offset << 3)) >> 3;
+        gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry, offset);
+        break;
+    case I64_DADDIUPC:
+        check_mips_64(ctx);
+        offset = extended ? offset : offset << 2;
+        gen_addiupc(ctx, ry, offset, 1, extended);
+        break;
+    case I64_DADDIUSP:
+        check_mips_64(ctx);
+        offset = extended ? offset : offset << 2;
+        gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29, offset);
+        break;
+    }
+}
+#endif
+
+static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
+                                       int *is_branch)
+{
+    int extend = lduw_code(ctx->pc + 2);
+    int op, rx, ry, funct, sa;
+    int16_t imm, offset;
+
+    ctx->opcode = (ctx->opcode << 16) | extend;
+    op = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 22) & 0x1f;
+    funct = (ctx->opcode >> 8) & 0x7;
+    rx = xlat((ctx->opcode >> 8) & 0x7);
+    ry = xlat((ctx->opcode >> 5) & 0x7);
+    offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
+                              | ((ctx->opcode >> 21) & 0x3f) << 5
+                              | (ctx->opcode & 0x1f));
+
+    /* The extended opcodes cleverly reuse the opcodes from their 16-bit
+       counterparts.  */
+    switch (op) {
+    case M16_OPC_ADDIUSP:
+        gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+        break;
+    case M16_OPC_ADDIUPC:
+        gen_addiupc(ctx, rx, imm, 0, 1);
+        break;
+    case M16_OPC_B:
+        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BEQZ:
+        gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BNEQZ:
+        gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_SHIFT:
+        switch (ctx->opcode & 0x3) {
+        case 0x0:
+            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+            break;
+        case 0x1:
+#if defined(TARGET_MIPS64)
+            check_mips_64(ctx);
+            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+            break;
+        case 0x2:
+            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+            break;
+        case 0x3:
+            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+            break;
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LD:
+            check_mips_64(ctx);
+        gen_ld(env, ctx, OPC_LD, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_RRIA:
+        imm = ctx->opcode & 0xf;
+        imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
+        imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
+        imm = (int16_t) (imm << 1) >> 1;
+        if ((ctx->opcode >> 4) & 0x1) {
+#if defined(TARGET_MIPS64)
+            check_mips_64(ctx);
+            gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+        } else {
+            gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+        }
+        break;
+    case M16_OPC_ADDIU8:
+        gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+        break;
+    case M16_OPC_SLTI:
+        gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+        break;
+    case M16_OPC_SLTIU:
+        gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+        break;
+    case M16_OPC_I8:
+        switch (funct) {
+        case I8_BTEQZ:
+            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
+            break;
+        case I8_BTNEZ:
+            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
+            break;
+        case I8_SWRASP:
+            gen_st(ctx, OPC_SW, 31, 29, imm);
+            break;
+        case I8_ADJSP:
+            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
+            break;
+        case I8_SVRS:
+            {
+                int xsregs = (ctx->opcode >> 24) & 0x7;
+                int aregs = (ctx->opcode >> 16) & 0xf;
+                int do_ra = (ctx->opcode >> 6) & 0x1;
+                int do_s0 = (ctx->opcode >> 5) & 0x1;
+                int do_s1 = (ctx->opcode >> 4) & 0x1;
+                int framesize = (((ctx->opcode >> 20) & 0xf) << 4
+                                 | (ctx->opcode & 0xf)) << 3;
+
+                if (ctx->opcode & (1 << 7)) {
+                    gen_mips16_save(ctx, xsregs, aregs,
+                                    do_ra, do_s0, do_s1,
+                                    framesize);
+                } else {
+                    gen_mips16_restore(ctx, xsregs, aregs,
+                                       do_ra, do_s0, do_s1,
+                                       framesize);
+                }
+            }
+            break;
+        default:
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case M16_OPC_LI:
+        tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
+        break;
+    case M16_OPC_CMPI:
+        tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_SD:
+        gen_st(ctx, OPC_SD, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_LB:
+        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
+        break;
+    case M16_OPC_LH:
+        gen_ld(env, ctx, OPC_LH, ry, rx, offset);
+        break;
+    case M16_OPC_LWSP:
+        gen_ld(env, ctx, OPC_LW, rx, 29, offset);
+        break;
+    case M16_OPC_LW:
+        gen_ld(env, ctx, OPC_LW, ry, rx, offset);
+        break;
+    case M16_OPC_LBU:
+        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
+        break;
+    case M16_OPC_LHU:
+        gen_ld(env, ctx, OPC_LHU, ry, rx, offset);
+        break;
+    case M16_OPC_LWPC:
+        gen_ld(env, ctx, OPC_LWPC, rx, 0, offset);
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LWU:
+        gen_ld(env, ctx, OPC_LWU, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_SB:
+        gen_st(ctx, OPC_SB, ry, rx, offset);
+        break;
+    case M16_OPC_SH:
+        gen_st(ctx, OPC_SH, ry, rx, offset);
+        break;
+    case M16_OPC_SWSP:
+        gen_st(ctx, OPC_SW, rx, 29, offset);
+        break;
+    case M16_OPC_SW:
+        gen_st(ctx, OPC_SW, ry, rx, offset);
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_I64:
+        decode_i64_mips16(env, ctx, ry, funct, offset, 1);
+        break;
+#endif
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+
+    return 4;
+}
+
+static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
+                              int *is_branch)
+{
+    int rx, ry;
+    int sa;
+    int op, cnvt_op, op1, offset;
+    int funct;
+    int n_bytes;
+
+    op = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 2) & 0x7;
+    sa = sa == 0 ? 8 : sa;
+    rx = xlat((ctx->opcode >> 8) & 0x7);
+    cnvt_op = (ctx->opcode >> 5) & 0x7;
+    ry = xlat((ctx->opcode >> 5) & 0x7);
+    op1 = offset = ctx->opcode & 0x1f;
+
+    n_bytes = 2;
+
+    switch (op) {
+    case M16_OPC_ADDIUSP:
+        {
+            int16_t imm = ((uint8_t) ctx->opcode) << 2;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+        }
+        break;
+    case M16_OPC_ADDIUPC:
+        gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2, 0, 0);
+        break;
+    case M16_OPC_B:
+        offset = (ctx->opcode & 0x7ff) << 1;
+        offset = (int16_t)(offset << 4) >> 4;
+        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_JAL:
+        offset = lduw_code(ctx->pc + 2);
+        offset = (((ctx->opcode & 0x1f) << 21)
+                  | ((ctx->opcode >> 5) & 0x1f) << 16
+                  | offset) << 2;
+        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS;
+        gen_compute_branch(ctx, op, 4, rx, ry, offset);
+        n_bytes = 4;
+        *is_branch = 1;
+        break;
+    case M16_OPC_BEQZ:
+        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BNEQZ:
+        gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_SHIFT:
+        switch (ctx->opcode & 0x3) {
+        case 0x0:
+            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+            break;
+        case 0x1:
+#if defined(TARGET_MIPS64)
+            check_mips_64(ctx);
+            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+            break;
+        case 0x2:
+            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+            break;
+        case 0x3:
+            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+            break;
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LD:
+        check_mips_64(ctx);
+        gen_ld(env, ctx, OPC_LD, ry, rx, offset << 3);
+        break;
+#endif
+    case M16_OPC_RRIA:
+        {
+            int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;
+
+            if ((ctx->opcode >> 4) & 1) {
+#if defined(TARGET_MIPS64)
+                check_mips_64(ctx);
+                gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+                generate_exception(ctx, EXCP_RI);
+#endif
+            } else {
+                gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+            }
+        }
+        break;
+    case M16_OPC_ADDIU8:
+        {
+            int16_t imm = (int8_t) ctx->opcode;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+        }
+        break;
+    case M16_OPC_SLTI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+        }
+        break;
+    case M16_OPC_SLTIU:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+        }
+        break;
+    case M16_OPC_I8:
+        {
+            int reg32;
+
+            funct = (ctx->opcode >> 8) & 0x7;
+            switch (funct) {
+            case I8_BTEQZ:
+                gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
+                                   ((int8_t)ctx->opcode) << 1);
+                break;
+            case I8_BTNEZ:
+                gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
+                                   ((int8_t)ctx->opcode) << 1);
+                break;
+            case I8_SWRASP:
+                gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
+                break;
+            case I8_ADJSP:
+                gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
+                              ((int8_t)ctx->opcode) << 3);
+                break;
+            case I8_SVRS:
+                {
+                    int do_ra = ctx->opcode & (1 << 6);
+                    int do_s0 = ctx->opcode & (1 << 5);
+                    int do_s1 = ctx->opcode & (1 << 4);
+                    int framesize = ctx->opcode & 0xf;
+
+                    if (framesize == 0) {
+                        framesize = 128;
+                    } else {
+                        framesize = framesize << 3;
+                    }
+
+                    if (ctx->opcode & (1 << 7)) {
+                        gen_mips16_save(ctx, 0, 0,
+                                        do_ra, do_s0, do_s1, framesize);
+                    } else {
+                        gen_mips16_restore(ctx, 0, 0,
+                                           do_ra, do_s0, do_s1, framesize);
+                    }
+                }
+                break;
+            case I8_MOV32R:
+                {
+                    int rz = xlat(ctx->opcode & 0x7);
+
+                    reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
+                        ((ctx->opcode >> 5) & 0x7);
+                    gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
+                }
+                break;
+            case I8_MOVR32:
+                reg32 = ctx->opcode & 0x1f;
+                gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+        }
+        break;
+    case M16_OPC_LI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
+        }
+        break;
+    case M16_OPC_CMPI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_logic_imm(env, OPC_XORI, 24, rx, imm);
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_SD:
+        check_mips_64(ctx);
+        gen_st(ctx, OPC_SD, ry, rx, offset << 3);
+        break;
+#endif
+    case M16_OPC_LB:
+        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
+        break;
+    case M16_OPC_LH:
+        gen_ld(env, ctx, OPC_LH, ry, rx, offset << 1);
+        break;
+    case M16_OPC_LWSP:
+        gen_ld(env, ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        break;
+    case M16_OPC_LW:
+        gen_ld(env, ctx, OPC_LW, ry, rx, offset << 2);
+        break;
+    case M16_OPC_LBU:
+        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
+        break;
+    case M16_OPC_LHU:
+        gen_ld(env, ctx, OPC_LHU, ry, rx, offset << 1);
+        break;
+    case M16_OPC_LWPC:
+        gen_ld(env, ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
+        break;
+#if defined (TARGET_MIPS64)
+    case M16_OPC_LWU:
+        check_mips_64(ctx);
+        gen_ld(env, ctx, OPC_LWU, ry, rx, offset << 2);
+        break;
+#endif
+    case M16_OPC_SB:
+        gen_st(ctx, OPC_SB, ry, rx, offset);
+        break;
+    case M16_OPC_SH:
+        gen_st(ctx, OPC_SH, ry, rx, offset << 1);
+        break;
+    case M16_OPC_SWSP:
+        gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        break;
+    case M16_OPC_SW:
+        gen_st(ctx, OPC_SW, ry, rx, offset << 2);
+        break;
+    case M16_OPC_RRR:
+        {
+            int rz = xlat((ctx->opcode >> 2) & 0x7);
+            int mips32_op;
+
+            switch (ctx->opcode & 0x3) {
+            case RRR_ADDU:
+                mips32_op = OPC_ADDU;
+                break;
+            case RRR_SUBU:
+                mips32_op = OPC_SUBU;
+                break;
+#if defined(TARGET_MIPS64)
+            case RRR_DADDU:
+                mips32_op = OPC_DADDU;
+                check_mips_64(ctx);
+                break;
+            case RRR_DSUBU:
+                mips32_op = OPC_DSUBU;
+                check_mips_64(ctx);
+                break;
+#endif
+            default:
+                generate_exception(ctx, EXCP_RI);
+                goto done;
+            }
+
+            gen_arith(env, ctx, mips32_op, rz, rx, ry);
+        done:
+            ;
+        }
+        break;
+    case M16_OPC_RR:
+        switch (op1) {
+        case RR_JR:
+            {
+                int nd = (ctx->opcode >> 7) & 0x1;
+                int link = (ctx->opcode >> 6) & 0x1;
+                int ra = (ctx->opcode >> 5) & 0x1;
+
+                if (link) {
+                    op = nd ? OPC_JALRC : OPC_JALRS;
+                } else {
+                    op = OPC_JR;
+                }
+
+                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
+                if (!nd) {
+                    *is_branch = 1;
+                }
+            }
+            break;
+        case RR_SDBBP:
+            /* XXX: not clear which exception should be raised
+             *      when in debug mode...
+             */
+            check_insn(env, ctx, ISA_MIPS32);
+            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+                generate_exception(ctx, EXCP_DBp);
+            } else {
+                generate_exception(ctx, EXCP_DBp);
+            }
+            break;
+        case RR_SLT:
+            gen_slt(env, OPC_SLT, 24, rx, ry);
+            break;
+        case RR_SLTU:
+            gen_slt(env, OPC_SLTU, 24, rx, ry);
+            break;
+        case RR_BREAK:
+            generate_exception(ctx, EXCP_BREAK);
+            break;
+        case RR_SLLV:
+            gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
+            break;
+        case RR_SRLV:
+            gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
+            break;
+        case RR_SRAV:
+            gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DSRL:
+            check_mips_64(ctx);
+            gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
+            break;
+#endif
+        case RR_CMP:
+            gen_logic(env, OPC_XOR, 24, rx, ry);
+            break;
+        case RR_NEG:
+            gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
+            break;
+        case RR_AND:
+            gen_logic(env, OPC_AND, rx, rx, ry);
+            break;
+        case RR_OR:
+            gen_logic(env, OPC_OR, rx, rx, ry);
+            break;
+        case RR_XOR:
+            gen_logic(env, OPC_XOR, rx, rx, ry);
+            break;
+        case RR_NOT:
+            gen_logic(env, OPC_NOR, rx, ry, 0);
+            break;
+        case RR_MFHI:
+            gen_HILO(ctx, OPC_MFHI, rx);
+            break;
+        case RR_CNVT:
+            switch (cnvt_op) {
+            case RR_RY_CNVT_ZEB:
+                tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_ZEH:
+                tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEB:
+                tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEH:
+                tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+#if defined (TARGET_MIPS64)
+            case RR_RY_CNVT_ZEW:
+                check_mips_64(ctx);
+                tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEW:
+                check_mips_64(ctx);
+                tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+#endif
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case RR_MFLO:
+            gen_HILO(ctx, OPC_MFLO, rx);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DSRA:
+            check_mips_64(ctx);
+            gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
+            break;
+        case RR_DSLLV:
+            check_mips_64(ctx);
+            gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
+            break;
+        case RR_DSRLV:
+            check_mips_64(ctx);
+            gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
+            break;
+        case RR_DSRAV:
+            check_mips_64(ctx);
+            gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
+            break;
+#endif
+        case RR_MULT:
+            gen_muldiv(ctx, OPC_MULT, rx, ry);
+            break;
+        case RR_MULTU:
+            gen_muldiv(ctx, OPC_MULTU, rx, ry);
+            break;
+        case RR_DIV:
+            gen_muldiv(ctx, OPC_DIV, rx, ry);
+            break;
+        case RR_DIVU:
+            gen_muldiv(ctx, OPC_DIVU, rx, ry);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DMULT:
+            check_mips_64(ctx);
+            gen_muldiv(ctx, OPC_DMULT, rx, ry);
+            break;
+        case RR_DMULTU:
+            check_mips_64(ctx);
+            gen_muldiv(ctx, OPC_DMULTU, rx, ry);
+            break;
+        case RR_DDIV:
+            check_mips_64(ctx);
+            gen_muldiv(ctx, OPC_DDIV, rx, ry);
+            break;
+        case RR_DDIVU:
+            check_mips_64(ctx);
+            gen_muldiv(ctx, OPC_DDIVU, rx, ry);
+            break;
+#endif
+        default:
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case M16_OPC_EXTEND:
+        decode_extended_mips16_opc(env, ctx, is_branch);
+        n_bytes = 4;
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_I64:
+        funct = (ctx->opcode >> 8) & 0x7;
+        decode_i64_mips16(env, ctx, ry, funct, offset, 0);
+        break;
+#endif
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+
+    return n_bytes;
+}
+
+/* microMIPS extension to MIPS32 */
+
+/* microMIPS32 major opcodes */
+
+enum {
+    POOL32A = 0x00,
+    POOL16A = 0x01,
+    LBU16 = 0x02,
+    MOVE16 = 0x03,
+    ADDI32 = 0x04,
+    LBU32 = 0x05,
+    SB32 = 0x06,
+    LB32 = 0x07,
+
+    POOL32B = 0x08,
+    POOL16B = 0x09,
+    LHU16 = 0x0a,
+    ANDI16 = 0x0b,
+    ADDIU32 = 0x0c,
+    LHU32 = 0x0d,
+    SH32 = 0x0e,
+    LH32 = 0x0f,
+
+    POOL32I = 0x10,
+    POOL16C = 0x11,
+    LWSP16 = 0x12,
+    POOL16D = 0x13,
+    ORI32 = 0x14,
+    POOL32F = 0x15,
+    POOL32S = 0x16,
+    DADDIU32 = 0x17,
+
+    POOL32C = 0x18,
+    LWGP16 = 0x19,
+    LW16 = 0x1a,
+    POOL16E = 0x1b,
+    XORI32 = 0x1c,
+    JALS32 = 0x1d,
+    ADDIUPC = 0x1e,
+    POOL48A = 0x1f,
+
+    /* 0x20 is reserved */
+    RES_20 = 0x20,
+    POOL16F = 0x21,
+    SB16 = 0x22,
+    BEQZ16 = 0x23,
+    SLTI32 = 0x24,
+    BEQ32 = 0x25,
+    SWC132 = 0x26,
+    LWC132 = 0x27,
+
+    /* 0x28 and 0x29 are reserved */
+    RES_28 = 0x28,
+    RES_29 = 0x29,
+    SH16 = 0x2a,
+    BNEZ16 = 0x2b,
+    SLTIU32 = 0x2c,
+    BNE32 = 0x2d,
+    SDC132 = 0x2e,
+    LDC132 = 0x2f,
+
+    /* 0x30 and 0x31 are reserved */
+    RES_30 = 0x30,
+    RES_31 = 0x31,
+    SWSP16 = 0x32,
+    B16 = 0x33,
+    ANDI32 = 0x34,
+    J32 = 0x35,
+    SD32 = 0x36,
+    LD32 = 0x37,
+
+    /* 0x38 and 0x39 are reserved */
+    RES_38 = 0x38,
+    RES_39 = 0x39,
+    SW16 = 0x3a,
+    LI16 = 0x3b,
+    JALX32 = 0x3c,
+    JAL32 = 0x3d,
+    SW32 = 0x3e,
+    LW32 = 0x3f
+};
+
+/* POOL32A encoding of minor opcode field */
+
+enum {
+    /* These opcodes are distinguished only by bits 9..6; those bits are
+     * what are recorded below. */
+    SLL32 = 0x0,
+    SRL32 = 0x1,
+    SRA = 0x2,
+    ROTR = 0x3,
+
+    SLLV = 0x0,
+    SRLV = 0x1,
+    SRAV = 0x2,
+    ROTRV = 0x3,
+    ADD = 0x4,
+    ADDU32 = 0x5,
+    SUB = 0x6,
+    SUBU32 = 0x7,
+    MUL = 0x8,
+    AND = 0x9,
+    OR32 = 0xa,
+    NOR = 0xb,
+    XOR32 = 0xc,
+    SLT = 0xd,
+    SLTU = 0xe,
+
+    MOVN = 0x0,
+    MOVZ = 0x1,
+    LWXS = 0x4,
+
+    /* The following can be distinguished by their lower 6 bits. */
+    INS = 0x0c,
+    EXT = 0x2c,
+    POOL32AXF = 0x3c
+};
+
+/* POOL32AXF encoding of minor opcode field extension */
+
+enum {
+    /* bits 11..6 */
+    TEQ = 0x00,
+    TGE = 0x08,
+    TGEU = 0x10,
+    TLT = 0x20,
+    TLTU = 0x28,
+    TNE = 0x30,
+
+    MFC0 = 0x03,
+    MTC0 = 0x0b,
+
+    /* bits 13..12 for 0x01 */
+    MFHI_ACC = 0x0,
+    MFLO_ACC = 0x1,
+    MTHI_ACC = 0x2,
+    MTLO_ACC = 0x3,
+
+    /* bits 13..12 for 0x2a */
+    MADD_ACC = 0x0,
+    MADDU_ACC = 0x1,
+    MSUB_ACC = 0x2,
+    MSUBU_ACC = 0x3,
+
+    /* bits 13..12 for 0x32 */
+    MULT_ACC = 0x0,
+    MULTU_ACC = 0x0,
+
+    /* bits 15..12 for 0x2c */
+    SEB = 0x2,
+    SEH = 0x3,
+    CLO = 0x4,
+    CLZ = 0x5,
+    RDHWR = 0x6,
+    WSBH = 0x7,
+    MULT = 0x8,
+    MULTU = 0x9,
+    DIV = 0xa,
+    DIVU = 0xb,
+    MADD = 0xc,
+    MADDU = 0xd,
+    MSUB = 0xe,
+    MSUBU = 0xf,
+
+    /* bits 15..12 for 0x34 */
+    MFC2 = 0x4,
+    MTC2 = 0x5,
+    MFHC2 = 0x8,
+    MTHC2 = 0x9,
+    CFC2 = 0xc,
+    CTC2 = 0xd,
+
+    /* bits 15..12 for 0x3c */
+    JALR = 0x0,
+    JR = 0x0,                   /* alias */
+    JALR_HB = 0x1,
+    JALRS = 0x4,
+    JALRS_HB = 0x5,
+
+    /* bits 15..12 for 0x05 */
+    RDPGPR = 0xe,
+    WRPGPR = 0xf,
+
+    /* bits 15..12 for 0x0d */
+    TLBP = 0x0,
+    TLBR = 0x1,
+    TLBWI = 0x2,
+    TLBWR = 0x3,
+    WAIT = 0x9,
+    IRET = 0xd,
+    DERET = 0xe,
+    ERET = 0xf,
+
+    /* bits 15..12 for 0x15 */
+    DMT = 0x0,
+    DVPE = 0x1,
+    EMT = 0x2,
+    EVPE = 0x3,
+
+    /* bits 15..12 for 0x1d */
+    DI = 0x4,
+    EI = 0x5,
+
+    /* bits 15..12 for 0x2d */
+    SYNC = 0x6,
+    SYSCALL = 0x8,
+    SDBBP = 0xd,
+
+    /* bits 15..12 for 0x35 */
+    MFHI32 = 0x0,
+    MFLO32 = 0x1,
+    MTHI32 = 0x2,
+    MTLO32 = 0x3,
+};
+
+/* POOL32B encoding of minor opcode field (bits 15..12) */
+
+enum {
+    LWC2 = 0x0,
+    LWP = 0x1,
+    LDP = 0x4,
+    LWM32 = 0x5,
+    CACHE = 0x6,
+    LDM = 0x7,
+    SWC2 = 0x8,
+    SWP = 0x9,
+    SDP = 0xc,
+    SWM32 = 0xd,
+    SDM = 0xf
+};
+
+/* POOL32C encoding of minor opcode field (bits 15..12) */
+
+enum {
+    LWL = 0x0,
+    SWL = 0x8,
+    LWR = 0x1,
+    SWR = 0x9,
+    PREF = 0x2,
+    /* 0xa is reserved */
+    LL = 0x3,
+    SC = 0xb,
+    LDL = 0x4,
+    SDL = 0xc,
+    LDR = 0x5,
+    SDR = 0xd,
+    /* 0x6 is reserved */
+    LWU = 0xe,
+    LLD = 0x7,
+    SCD = 0xf
+};
+
+/* POOL32F encoding of minor opcode field (bits 5..0) */
+
+enum {
+    /* These are the bit 7..6 values */
+    ADD_FMT = 0x0,
+    MOVN_FMT = 0x0,
+
+    SUB_FMT = 0x1,
+    MOVZ_FMT = 0x1,
+
+    MUL_FMT = 0x2,
+
+    DIV_FMT = 0x3,
+
+    /* These are the bit 8..6 values */
+    RSQRT2_FMT = 0x0,
+    MOVF_FMT = 0x0,
+
+    LWXC1 = 0x1,
+    MOVT_FMT = 0x1,
+
+    PLL_PS = 0x2,
+    SWXC1 = 0x2,
+
+    PLU_PS = 0x3,
+    LDXC1 = 0x3,
+
+    PUL_PS = 0x4,
+    SDXC1 = 0x4,
+    RECIP2_FMT = 0x4,
+
+    PUU_PS = 0x5,
+    LUXC1 = 0x5,
+
+    CVT_PS_S = 0x6,
+    SUXC1 = 0x6,
+    ADDR_PS = 0x6,
+    PREFX = 0x6,
+
+    MULR_PS = 0x7,
+
+    MADD_S = 0x01,
+    MADD_D = 0x09,
+    MADD_PS = 0x11,
+    ALNV_PS = 0x19,
+    MSUB_S = 0x21,
+    MSUB_D = 0x29,
+    MSUB_PS = 0x31,
+
+    NMADD_S = 0x02,
+    NMADD_D = 0x0a,
+    NMADD_PS = 0x12,
+    NMSUB_S = 0x22,
+    NMSUB_D = 0x2a,
+    NMSUB_PS = 0x32,
+
+    POOL32FXF = 0x3b,
+
+    CABS_COND_FMT = 0x1c,              /* MIPS3D */
+    C_COND_FMT = 0x3c
+};
+
+/* POOL32Fxf encoding of minor opcode extension field */
+
+enum {
+    CVT_L = 0x04,
+    RSQRT_FMT = 0x08,
+    FLOOR_L = 0x0c,
+    CVT_PW_PS = 0x1c,
+    CVT_W = 0x24,
+    SQRT_FMT = 0x28,
+    FLOOR_W = 0x2c,
+    CVT_PS_PW = 0x3c,
+    CFC1 = 0x40,
+    RECIP_FMT = 0x48,
+    CEIL_L = 0x4c,
+    CTC1 = 0x60,
+    CEIL_W = 0x6c,
+    MFC1 = 0x80,
+    CVT_S_PL = 0x84,
+    TRUNC_L = 0x8c,
+    MTC1 = 0xa0,
+    CVT_S_PU = 0xa4,
+    TRUNC_W = 0xac,
+    MFHC1 = 0xc0,
+    ROUND_L = 0xcc,
+    MTHC1 = 0xe0,
+    ROUND_W = 0xec,
+
+    MOV_FMT = 0x01,
+    MOVF = 0x05,
+    ABS_FMT = 0x0d,
+    RSQRT1_FMT = 0x1d,
+    MOVT = 0x25,
+    NEG_FMT = 0x2d,
+    CVT_D = 0x4d,
+    RECIP1_FMT = 0x5d,
+    CVT_S = 0x6d
+};
+
+/* POOL32I encoding of minor opcode field (bits 25..21) */
+
+enum {
+    BLTZ = 0x00,
+    BLTZAL = 0x01,
+    BGEZ = 0x02,
+    BGEZAL = 0x03,
+    BLEZ = 0x04,
+    BNEZC = 0x05,
+    BGTZ = 0x06,
+    BEQZC = 0x07,
+    TLTI = 0x08,
+    TGEI = 0x09,
+    TLTIU = 0x0a,
+    TGEIU = 0x0b,
+    TNEI = 0x0c,
+    LUI = 0x0d,
+    TEQI = 0x0e,
+    SYNCI = 0x10,
+    BLTZALS = 0x11,
+    BGEZALS = 0x13,
+    BC2F = 0x14,
+    BC2T = 0x15,
+    BPOSGE64 = 0x1a,
+    BPOSGE32 = 0x1b,
+    /* These overlap and are distinguished by bit16 of the instruction */
+    BC1F = 0x1c,
+    BC1T = 0x1d,
+    BC1ANY2F = 0x1c,
+    BC1ANY2T = 0x1d,
+    BC1ANY4F = 0x1e,
+    BC1ANY4T = 0x1f
+};
+
+/* POOL16A encoding of minor opcode field */
+
+enum {
+    ADDU16 = 0x0,
+    SUBU16 = 0x1
+};
+
+/* POOL16B encoding of minor opcode field */
+
+enum {
+    SLL16 = 0x0,
+    SRL16 = 0x1
+};
+
+/* POOL16C encoding of minor opcode field */
+
+enum {
+    NOT16 = 0x00,
+    XOR16 = 0x04,
+    AND16 = 0x08,
+    OR16 = 0x0c,
+    LWM16 = 0x10,
+    SWM16 = 0x14,
+    JR16 = 0x18,
+    JRC16 = 0x1a,
+    JALR16 = 0x1c,
+    JALR16S = 0x1e,
+    MFHI16 = 0x20,
+    MFLO16 = 0x24,
+    BREAK16 = 0x28,
+    SDBBP16 = 0x2c,
+    JRADDIUSP = 0x30
+};
+
+/* POOL16D encoding of minor opcode field */
+
+enum {
+    ADDIUS5 = 0x0,
+    ADDIUSP = 0x1
+};
+
+/* POOL16E encoding of minor opcode field */
+
+enum {
+    ADDIUR2 = 0x0,
+    ADDIUR1SP = 0x1
+};
+
+static int mmreg (int r)
+{
+    static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+    return map[r];
+}
+
+/* Used for 16-bit store instructions.  */
+static int mmreg2 (int r)
+{
+    static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
+
+    return map[r];
+}
+
+#define uMIPS_RD(op) ((op >> 7) & 0x7)
+#define uMIPS_RS(op) ((op >> 4) & 0x7)
+#define uMIPS_RS2(op) uMIPS_RS(op)
+#define uMIPS_RS1(op) ((op >> 1) & 0x7)
+#define uMIPS_RD5(op) ((op >> 5) & 0x1f)
+#define uMIPS_RS5(op) (op & 0x1f)
+
+/* Signed immediate */
+#define SIMM(op, start, width)                                          \
+    ((int32_t)(((op >> start) & ((~0U) >> (32-width)))                 \
+               << (32-width))                                           \
+     >> (32-width))
+/* Zero-extended immediate */
+#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width)))
+
+static void gen_addiur1sp (CPUState *env, DisasContext *ctx)
+{
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2);
+}
+
+static void gen_addiur2 (CPUState *env, DisasContext *ctx)
+{
+    static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 };
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+    int rs = mmreg(uMIPS_RS(ctx->opcode));
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]);
+}
+
+static void gen_addiusp (CPUState *env, DisasContext *ctx)
+{
+    int encoded = ZIMM(ctx->opcode, 1, 9);
+    int decoded;
+
+    if (encoded <= 1) {
+        decoded = 256 + encoded;
+    } else if (encoded <= 255) {
+        decoded = encoded;
+    } else if (encoded <= 509) {
+        decoded = encoded - 512;
+    } else {
+        decoded = encoded - 768;
+    }
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2);
+}
+
+static void gen_addius5 (CPUState *env, DisasContext *ctx)
+{
+    int imm = SIMM(ctx->opcode, 1, 4);
+    int rd = (ctx->opcode >> 5) & 0x1f;
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm);
+}
+
+static void gen_andi16 (CPUState *env, DisasContext *ctx)
+{
+    static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16,
+                                 31, 32, 63, 64, 255, 32768, 65535 };
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+    int rs = mmreg(uMIPS_RS(ctx->opcode));
+    int encoded = ZIMM(ctx->opcode, 0, 4);
+
+    gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]);
+}
+
+static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist,
+                               int base, int16_t offset)
+{
+    TCGv t0, t1;
+    TCGv_i32 t2;
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+
+    t1 = tcg_const_tl(reglist);
+    t2 = tcg_const_i32(ctx->mem_idx);
+
+    save_cpu_state(ctx, 1);
+    switch (opc) {
+    case LWM32:
+        gen_helper_lwm(t0, t1, t2);
+        break;
+    case SWM32:
+        gen_helper_swm(t0, t1, t2);
+        break;
+#ifdef TARGET_MIPS64
+    case LDM:
+        gen_helper_ldm(t0, t1, t2);
+        break;
+    case SDM:
+        gen_helper_sdm(t0, t1, t2);
+        break;
+#endif
+    }
+    MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free_i32(t2);
+}
+
+
+static void gen_pool16c_insn (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+    int rd = mmreg((ctx->opcode >> 3) & 0x7);
+    int rs = mmreg(ctx->opcode & 0x7);
+    int opc;
+
+    switch (((ctx->opcode) >> 4) & 0x3f) {
+    case NOT16 + 0:
+    case NOT16 + 1:
+    case NOT16 + 2:
+    case NOT16 + 3:
+        gen_logic(env, OPC_NOR, rd, rs, 0);
+        break;
+    case XOR16 + 0:
+    case XOR16 + 1:
+    case XOR16 + 2:
+    case XOR16 + 3:
+        gen_logic(env, OPC_XOR, rd, rd, rs);
+        break;
+    case AND16 + 0:
+    case AND16 + 1:
+    case AND16 + 2:
+    case AND16 + 3:
+        gen_logic(env, OPC_AND, rd, rd, rs);
+        break;
+    case OR16 + 0:
+    case OR16 + 1:
+    case OR16 + 2:
+    case OR16 + 3:
+        gen_logic(env, OPC_OR, rd, rd, rs);
+        break;
+    case LWM16 + 0:
+    case LWM16 + 1:
+    case LWM16 + 2:
+    case LWM16 + 3:
+        {
+            static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+            int offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3],
+                              29, offset << 2);
+        }
+        break;
+    case SWM16 + 0:
+    case SWM16 + 1:
+    case SWM16 + 2:
+    case SWM16 + 3:
+        {
+            static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+            int offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3],
+                              29, offset << 2);
+        }
+        break;
+    case JR16 + 0:
+    case JR16 + 1:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+        }
+        *is_branch = 1;
+        break;
+    case JRC16 + 0:
+    case JRC16 + 1:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+            /* Let normal delay slot handling in our caller take us
+               to the branch target.  */
+        }
+        break;
+    case JALR16 + 0:
+    case JALR16 + 1:
+        opc = OPC_JALR;
+        goto do_jalr;
+    case JALR16S + 0:
+    case JALR16S + 1:
+        opc = OPC_JALRS;
+    do_jalr:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, opc, 2, reg, 31, 0);
+        }
+        *is_branch = 1;
+        break;
+    case MFHI16 + 0:
+    case MFHI16 + 1:
+        gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode));
+        break;
+    case MFLO16 + 0:
+    case MFLO16 + 1:
+        gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode));
+        break;
+    case BREAK16:
+        generate_exception(ctx, EXCP_BREAK);
+        break;
+    case SDBBP16:
+        /* XXX: not clear which exception should be raised
+         *      when in debug mode...
+         */
+        check_insn(env, ctx, ISA_MIPS32);
+        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+            generate_exception(ctx, EXCP_DBp);
+        } else {
+            generate_exception(ctx, EXCP_DBp);
+        }
+        break;
+    case JRADDIUSP + 0:
+    case JRADDIUSP + 1:
+        {
+            int imm = ZIMM(ctx->opcode, 0, 5);
+
+            gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
+            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2);
+            /* Let normal delay slot handling in our caller take us
+               to the branch target.  */
+        }
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void gen_ldxs (DisasContext *ctx, int base, int index, int rd)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    gen_load_gpr(t0, base);
+
+    if (index != 0) {
+        gen_load_gpr(t1, index);
+        tcg_gen_shli_tl(t1, t1, 2);
+        gen_op_addr_add(ctx, t0, t1, t0);
+    }
+
+    save_cpu_state(ctx, 0);
+    op_ld_lw(t1, t0, ctx);
+    gen_store_gpr(t1, rd);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
+                           int base, int16_t offset)
+{
+    const char *opn = "ldst_pair";
+    TCGv t0, t1;
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+
+    switch (opc) {
+    case LWP:
+        save_cpu_state(ctx, 0);
+        op_ld_lw(t1, t0, ctx);
+        gen_store_gpr(t1, rd);
+        tcg_gen_movi_tl(t1, 4);
+        gen_op_addr_add(ctx, t0, t0, t1);
+        op_ld_lw(t1, t0, ctx);
+        gen_store_gpr(t1, rd+1);
+        opn = "lwp";
+        break;
+    case SWP:
+        save_cpu_state(ctx, 0);
+        gen_load_gpr(t1, rd);
+        op_st_sw(t1, t0, ctx);
+        tcg_gen_movi_tl(t1, 4);
+        gen_op_addr_add(ctx, t0, t0, t1);
+        gen_load_gpr(t1, rd+1);
+        op_st_sw(t1, t0, ctx);
+        opn = "swp";
+        break;
+#ifdef TARGET_MIPS64
+    case LDP:
+        save_cpu_state(ctx, 0);
+        op_ld_ld(t1, t0, ctx);
+        gen_store_gpr(t1, rd);
+        tcg_gen_movi_tl(t1, 8);
+        gen_op_addr_add(ctx, t0, t0, t1);
+        op_ld_ld(t1, t0, ctx);
+        gen_store_gpr(t1, rd+1);
+        opn = "ldp";
+        break;
+    case SDP:
+        save_cpu_state(ctx, 0);
+        gen_load_gpr(t1, rd);
+        op_st_sd(t1, t0, ctx);
+        tcg_gen_movi_tl(t1, 8);
+        gen_op_addr_add(ctx, t0, t0, t1);
+        gen_load_gpr(t1, rd+1);
+        op_st_sd(t1, t0, ctx);
+        opn = "sdp";
+        break;
+#endif
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_pool32axf (CPUState *env, DisasContext *ctx, int rt, int rs,
+                           int *is_branch)
+{
+    int extension = (ctx->opcode >> 6) & 0x3f;
+    int minor = (ctx->opcode >> 12) & 0xf;
+    uint32_t mips32_op;
+
+    switch (extension) {
+    case TEQ:
+        mips32_op = OPC_TEQ;
+        goto do_trap;
+    case TGE:
+        mips32_op = OPC_TGE;
+        goto do_trap;
+    case TGEU:
+        mips32_op = OPC_TGEU;
+        goto do_trap;
+    case TLT:
+        mips32_op = OPC_TLT;
+        goto do_trap;
+    case TLTU:
+        mips32_op = OPC_TLTU;
+        goto do_trap;
+    case TNE:
+        mips32_op = OPC_TNE;
+    do_trap:
+        gen_trap(ctx, mips32_op, rs, rt, -1);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case MFC0:
+    case MFC0 + 32:
+        if (rt == 0) {
+            /* Treat as NOP. */
+            break;
+        }
+        gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
+        break;
+    case MTC0:
+    case MTC0 + 32:
+        {
+            TCGv t0 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
+            tcg_temp_free(t0);
+        }
+        break;
+#endif
+    case 0x2c:
+        switch (minor) {
+        case SEB:
+            gen_bshfl(ctx, OPC_SEB, rs, rt);
+            break;
+        case SEH:
+            gen_bshfl(ctx, OPC_SEH, rs, rt);
+            break;
+        case CLO:
+            mips32_op = OPC_CLO;
+            goto do_cl;
+        case CLZ:
+            mips32_op = OPC_CLZ;
+        do_cl:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_cl(ctx, mips32_op, rt, rs);
+            break;
+        case RDHWR:
+            gen_rdhwr(env, ctx, rt, rs);
+            break;
+        case WSBH:
+            gen_bshfl(ctx, OPC_WSBH, rs, rt);
+            break;
+        case MULT:
+            mips32_op = OPC_MULT;
+            goto do_muldiv;
+        case MULTU:
+            mips32_op = OPC_MULTU;
+            goto do_muldiv;
+        case DIV:
+            mips32_op = OPC_DIV;
+            goto do_muldiv;
+        case DIVU:
+            mips32_op = OPC_DIVU;
+            goto do_muldiv;
+        case MADD:
+            mips32_op = OPC_MADD;
+            goto do_muldiv;
+        case MADDU:
+            mips32_op = OPC_MADDU;
+            goto do_muldiv;
+        case MSUB:
+            mips32_op = OPC_MSUB;
+            goto do_muldiv;
+        case MSUBU:
+            mips32_op = OPC_MSUBU;
+        do_muldiv:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_muldiv(ctx, mips32_op, rs, rt);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x34:
+        switch (minor) {
+        case MFC2:
+        case MTC2:
+        case MFHC2:
+        case MTHC2:
+        case CFC2:
+        case CTC2:
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x3c:
+        switch (minor) {
+        case JALR:
+        case JALR_HB:
+            gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0);
+            *is_branch = 1;
+            break;
+        case JALRS:
+        case JALRS_HB:
+            gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0);
+            *is_branch = 1;
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x05:
+        switch (minor) {
+        case RDPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_load_srsgpr(rt, rs);
+            break;
+        case WRPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_store_srsgpr(rt, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x0d:
+        switch (minor) {
+        case TLBP:
+            mips32_op = OPC_TLBP;
+            goto do_cp0;
+        case TLBR:
+            mips32_op = OPC_TLBR;
+            goto do_cp0;
+        case TLBWI:
+            mips32_op = OPC_TLBWI;
+            goto do_cp0;
+        case TLBWR:
+            mips32_op = OPC_TLBWR;
+            goto do_cp0;
+        case WAIT:
+            mips32_op = OPC_WAIT;
+            goto do_cp0;
+        case DERET:
+            mips32_op = OPC_DERET;
+            goto do_cp0;
+        case ERET:
+            mips32_op = OPC_ERET;
+        do_cp0:
+            gen_cp0(env, ctx, mips32_op, rt, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x1d:
+        switch (minor) {
+        case DI:
+            {
+                TCGv t0 = tcg_temp_new();
+
+                save_cpu_state(ctx, 1);
+                gen_helper_di(t0);
+                gen_store_gpr(t0, rs);
+                /* Stop translation as we may have switched the execution mode */
+                ctx->bstate = BS_STOP;
+                tcg_temp_free(t0);
+            }
+            break;
+        case EI:
+            {
+                TCGv t0 = tcg_temp_new();
+
+                save_cpu_state(ctx, 1);
+                gen_helper_ei(t0);
+                gen_store_gpr(t0, rs);
+                /* Stop translation as we may have switched the execution mode */
+                ctx->bstate = BS_STOP;
+                tcg_temp_free(t0);
+            }
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+#endif
+    case 0x2d:
+        switch (minor) {
+        case SYNC:
+            /* NOP */
+            break;
+        case SYSCALL:
+            generate_exception(ctx, EXCP_SYSCALL);
+            ctx->bstate = BS_STOP;
+            break;
+        case SDBBP:
+            check_insn(env, ctx, ISA_MIPS32);
+            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+                generate_exception(ctx, EXCP_DBp);
+            } else {
+                generate_exception(ctx, EXCP_DBp);
+            }
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x35:
+        switch (minor) {
+        case MFHI32:
+            gen_HILO(ctx, OPC_MFHI, rs);
+            break;
+        case MFLO32:
+            gen_HILO(ctx, OPC_MFLO, rs);
+            break;
+        case MTHI32:
+            gen_HILO(ctx, OPC_MTHI, rs);
+            break;
+        case MTLO32:
+            gen_HILO(ctx, OPC_MTLO, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    default:
+    pool32axf_invalid:
+        MIPS_INVAL("pool32axf");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+/* Values for microMIPS fmt field.  Variable-width, depending on which
+   formats the instruction supports.  */
+
+enum {
+    FMT_SD_S = 0,
+    FMT_SD_D = 1,
+
+    FMT_SDPS_S = 0,
+    FMT_SDPS_D = 1,
+    FMT_SDPS_PS = 2,
+
+    FMT_SWL_S = 0,
+    FMT_SWL_W = 1,
+    FMT_SWL_L = 2,
+
+    FMT_DWL_D = 0,
+    FMT_DWL_W = 1,
+    FMT_DWL_L = 2
+};
+
+static void gen_pool32fxf (CPUState *env, DisasContext *ctx, int rt, int rs)
+{
+    int extension = (ctx->opcode >> 6) & 0x3ff;
+    uint32_t mips32_op;
+
+#define FLOAT_1BIT_FMT(opc, fmt) (fmt << 8) | opc
+#define FLOAT_2BIT_FMT(opc, fmt) (fmt << 7) | opc
+#define COND_FLOAT_MOV(opc, cond) (cond << 7) | opc
+
+    switch (extension) {
+    case FLOAT_1BIT_FMT(CFC1, 0):
+        mips32_op = OPC_CFC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(CTC1, 0):
+        mips32_op = OPC_CTC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MFC1, 0):
+        mips32_op = OPC_MFC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MTC1, 0):
+        mips32_op = OPC_MTC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MFHC1, 0):
+        mips32_op = OPC_MFHC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MTHC1, 0):
+        mips32_op = OPC_MTHC1;
+    do_cp1:
+        gen_cp1(ctx, mips32_op, rt, rs);
+        break;
+
+        /* Reciprocal square root */
+    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S):
+        mips32_op = OPC_RSQRT_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D):
+        mips32_op = OPC_RSQRT_D;
+        goto do_unaryfp;
+
+        /* Square root */
+    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S):
+        mips32_op = OPC_SQRT_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D):
+        mips32_op = OPC_SQRT_D;
+        goto do_unaryfp;
+
+        /* Reciprocal */
+    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S):
+        mips32_op = OPC_RECIP_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D):
+        mips32_op = OPC_RECIP_D;
+        goto do_unaryfp;
+
+        /* Floor */
+    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S):
+        mips32_op = OPC_FLOOR_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D):
+        mips32_op = OPC_FLOOR_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S):
+        mips32_op = OPC_FLOOR_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D):
+        mips32_op = OPC_FLOOR_W_D;
+        goto do_unaryfp;
+
+        /* Ceiling */
+    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S):
+        mips32_op = OPC_CEIL_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D):
+        mips32_op = OPC_CEIL_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S):
+        mips32_op = OPC_CEIL_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D):
+        mips32_op = OPC_CEIL_W_D;
+        goto do_unaryfp;
+
+        /* Truncation */
+    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S):
+        mips32_op = OPC_TRUNC_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D):
+        mips32_op = OPC_TRUNC_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S):
+        mips32_op = OPC_TRUNC_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D):
+        mips32_op = OPC_TRUNC_W_D;
+        goto do_unaryfp;
+
+        /* Round */
+    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S):
+        mips32_op = OPC_ROUND_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D):
+        mips32_op = OPC_ROUND_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S):
+        mips32_op = OPC_ROUND_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D):
+        mips32_op = OPC_ROUND_W_D;
+        goto do_unaryfp;
+
+        /* Integer to floating-point conversion */
+    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S):
+        mips32_op = OPC_CVT_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D):
+        mips32_op = OPC_CVT_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S):
+        mips32_op = OPC_CVT_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D):
+        mips32_op = OPC_CVT_W_D;
+        goto do_unaryfp;
+
+        /* Paired-foo conversions */
+    case FLOAT_1BIT_FMT(CVT_S_PL, 0):
+        mips32_op = OPC_CVT_S_PL;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_S_PU, 0):
+        mips32_op = OPC_CVT_S_PU;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_PW_PS, 0):
+        mips32_op = OPC_CVT_PW_PS;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_PS_PW, 0):
+        mips32_op = OPC_CVT_PS_PW;
+        goto do_unaryfp;
+
+        /* Floating-point moves */
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S):
+        mips32_op = OPC_MOV_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D):
+        mips32_op = OPC_MOV_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_MOV_PS;
+        goto do_unaryfp;
+
+        /* Absolute value */
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S):
+        mips32_op = OPC_ABS_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D):
+        mips32_op = OPC_ABS_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_ABS_PS;
+        goto do_unaryfp;
+
+        /* Negation */
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S):
+        mips32_op = OPC_NEG_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D):
+        mips32_op = OPC_NEG_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_NEG_PS;
+        goto do_unaryfp;
+
+        /* Reciprocal square root step */
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S):
+        mips32_op = OPC_RSQRT1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D):
+        mips32_op = OPC_RSQRT1_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_RSQRT1_PS;
+        goto do_unaryfp;
+
+        /* Reciprocal step */
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S):
+        mips32_op = OPC_RECIP1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D):
+        mips32_op = OPC_RECIP1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_RECIP1_PS;
+        goto do_unaryfp;
+
+        /* Conversions from double */
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S):
+        mips32_op = OPC_CVT_D_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W):
+        mips32_op = OPC_CVT_D_W;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L):
+        mips32_op = OPC_CVT_D_L;
+        goto do_unaryfp;
+
+        /* Conversions from single */
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D):
+        mips32_op = OPC_CVT_S_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W):
+        mips32_op = OPC_CVT_S_W;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L):
+        mips32_op = OPC_CVT_S_L;
+    do_unaryfp:
+        gen_farith(ctx, mips32_op, -1, rs, rt, 0);
+        break;
+
+        /* Conditional moves on floating-point codes */
+    case COND_FLOAT_MOV(MOVT, 0):
+    case COND_FLOAT_MOV(MOVT, 1):
+    case COND_FLOAT_MOV(MOVT, 2):
+    case COND_FLOAT_MOV(MOVT, 3):
+    case COND_FLOAT_MOV(MOVT, 4):
+    case COND_FLOAT_MOV(MOVT, 5):
+    case COND_FLOAT_MOV(MOVT, 6):
+    case COND_FLOAT_MOV(MOVT, 7):
+        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1);
+        break;
+    case COND_FLOAT_MOV(MOVF, 0):
+    case COND_FLOAT_MOV(MOVF, 1):
+    case COND_FLOAT_MOV(MOVF, 2):
+    case COND_FLOAT_MOV(MOVF, 3):
+    case COND_FLOAT_MOV(MOVF, 4):
+    case COND_FLOAT_MOV(MOVF, 5):
+    case COND_FLOAT_MOV(MOVF, 6):
+    case COND_FLOAT_MOV(MOVF, 7):
+        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0);
+        break;
+    default:
+        MIPS_INVAL("pool32fxf");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_micromips32_opc (CPUState *env, DisasContext *ctx,
+                                    uint16_t insn_hw1, int *is_branch)
+{
+    int32_t offset;
+    uint16_t insn;
+    int rt, rs, rd, rr;
+    int16_t imm;
+    uint32_t op, minor, mips32_op;
+    uint32_t cond, fmt, cc;
+
+    insn = lduw_code(ctx->pc + 2);
+    ctx->opcode = (ctx->opcode << 16) | insn;
+
+    rt = (ctx->opcode >> 21) & 0x1f;
+    rs = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    rr = (ctx->opcode >> 6) & 0x1f;
+    imm = (int16_t) ctx->opcode;
+
+    op = (ctx->opcode >> 26) & 0x3f;
+    switch (op) {
+    case POOL32A:
+        minor = ctx->opcode & 0x3f;
+        switch (minor) {
+        case 0x00:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+            case SLL32:
+                mips32_op = OPC_SLL;
+                goto do_shifti;
+            case SRA:
+                mips32_op = OPC_SRA;
+                goto do_shifti;
+            case SRL32:
+                mips32_op = OPC_SRL;
+                goto do_shifti;
+            case ROTR:
+                mips32_op = OPC_ROTR;
+            do_shifti:
+                gen_shift_imm(env, ctx, mips32_op, rt, rs, rd);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case 0x10:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+                /* Arithmetic */
+            case ADD:
+                mips32_op = OPC_ADD;
+                goto do_arith;
+            case ADDU32:
+                mips32_op = OPC_ADDU;
+                goto do_arith;
+            case SUB:
+                mips32_op = OPC_SUB;
+                goto do_arith;
+            case SUBU32:
+                mips32_op = OPC_SUBU;
+                goto do_arith;
+            case MUL:
+                mips32_op = OPC_MUL;
+            do_arith:
+                gen_arith(env, ctx, mips32_op, rd, rs, rt);
+                break;
+                /* Shifts */
+            case SLLV:
+                mips32_op = OPC_SLLV;
+                goto do_shift;
+            case SRLV:
+                mips32_op = OPC_SRLV;
+                goto do_shift;
+            case SRAV:
+                mips32_op = OPC_SRAV;
+                goto do_shift;
+            case ROTRV:
+                mips32_op = OPC_ROTRV;
+            do_shift:
+                gen_shift(env, ctx, mips32_op, rd, rs, rt);
+                break;
+                /* Logical operations */
+            case AND:
+                mips32_op = OPC_AND;
+                goto do_logic;
+            case OR32:
+                mips32_op = OPC_OR;
+                goto do_logic;
+            case NOR:
+                mips32_op = OPC_NOR;
+                goto do_logic;
+            case XOR32:
+                mips32_op = OPC_XOR;
+            do_logic:
+                gen_logic(env, mips32_op, rd, rs, rt);
+                break;
+                /* Set less than */
+            case SLT:
+                mips32_op = OPC_SLT;
+                goto do_slt;
+            case SLTU:
+                mips32_op = OPC_SLTU;
+            do_slt:
+                gen_slt(env, mips32_op, rd, rs, rt);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case 0x18:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+                /* Conditional moves */
+            case MOVN:
+                mips32_op = OPC_MOVN;
+                goto do_cmov;
+            case MOVZ:
+                mips32_op = OPC_MOVZ;
+            do_cmov:
+                gen_cond_move(env, mips32_op, rd, rs, rt);
+                break;
+            case LWXS:
+                gen_ldxs(ctx, rs, rt, rd);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case INS:
+            gen_bitops(ctx, OPC_INS, rt, rs, rr, rd);
+            return;
+        case EXT:
+            gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);
+            return;
+        case POOL32AXF:
+            gen_pool32axf(env, ctx, rt, rs, is_branch);
+            break;
+        case 0x07:
+            generate_exception(ctx, EXCP_BREAK);
+            break;
+        default:
+        pool32a_invalid:
+                MIPS_INVAL("pool32a");
+                generate_exception(ctx, EXCP_RI);
+                break;
+        }
+        break;
+    case POOL32B:
+        minor = (ctx->opcode >> 12) & 0xf;
+        switch (minor) {
+        case CACHE:
+            /* Treat as no-op. */
+            break;
+        case LWC2:
+        case SWC2:
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        case LWP:
+        case SWP:
+#ifdef TARGET_MIPS64
+        case LDP:
+        case SDP:
+#endif
+            gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        case LWM32:
+        case SWM32:
+#ifdef TARGET_MIPS64
+        case LDM:
+        case SDM:
+#endif
+            gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        default:
+            MIPS_INVAL("pool32b");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case POOL32F:
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            minor = ctx->opcode & 0x3f;
+            check_cp1_enabled(ctx);
+            switch (minor) {
+            case ALNV_PS:
+                mips32_op = OPC_ALNV_PS;
+                goto do_madd;
+            case MADD_S:
+                mips32_op = OPC_MADD_S;
+                goto do_madd;
+            case MADD_D:
+                mips32_op = OPC_MADD_D;
+                goto do_madd;
+            case MADD_PS:
+                mips32_op = OPC_MADD_PS;
+                goto do_madd;
+            case MSUB_S:
+                mips32_op = OPC_MSUB_S;
+                goto do_madd;
+            case MSUB_D:
+                mips32_op = OPC_MSUB_D;
+                goto do_madd;
+            case MSUB_PS:
+                mips32_op = OPC_MSUB_PS;
+                goto do_madd;
+            case NMADD_S:
+                mips32_op = OPC_NMADD_S;
+                goto do_madd;
+            case NMADD_D:
+                mips32_op = OPC_NMADD_D;
+                goto do_madd;
+            case NMADD_PS:
+                mips32_op = OPC_NMADD_PS;
+                goto do_madd;
+            case NMSUB_S:
+                mips32_op = OPC_NMSUB_S;
+                goto do_madd;
+            case NMSUB_D:
+                mips32_op = OPC_NMSUB_D;
+                goto do_madd;
+            case NMSUB_PS:
+                mips32_op = OPC_NMSUB_PS;
+            do_madd:
+                gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt);
+                break;
+            case CABS_COND_FMT:
+                cond = (ctx->opcode >> 6) & 0xf;
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 10) & 0x3;
+                switch (fmt) {
+                case 0x0:
+                    gen_cmpabs_s(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x1:
+                    gen_cmpabs_d(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x2:
+                    gen_cmpabs_ps(ctx, cond, rt, rs, cc);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case C_COND_FMT:
+                cond = (ctx->opcode >> 6) & 0xf;
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 10) & 0x3;
+                switch (fmt) {
+                case 0x0:
+                    gen_cmp_s(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x1:
+                    gen_cmp_d(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x2:
+                    gen_cmp_ps(ctx, cond, rt, rs, cc);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case POOL32FXF:
+                gen_pool32fxf(env, ctx, rt, rs);
+                break;
+            case 0x00:
+                /* PLL foo */
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case PLL_PS:
+                    mips32_op = OPC_PLL_PS;
+                    goto do_ps;
+                case PLU_PS:
+                    mips32_op = OPC_PLU_PS;
+                    goto do_ps;
+                case PUL_PS:
+                    mips32_op = OPC_PUL_PS;
+                    goto do_ps;
+                case PUU_PS:
+                    mips32_op = OPC_PUU_PS;
+                    goto do_ps;
+                case CVT_PS_S:
+                    mips32_op = OPC_CVT_PS_S;
+                do_ps:
+                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x08:
+                /* [LS][WDU]XC1 */
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case LWXC1:
+                    mips32_op = OPC_LWXC1;
+                    goto do_ldst_cp1;
+                case SWXC1:
+                    mips32_op = OPC_SWXC1;
+                    goto do_ldst_cp1;
+                case LDXC1:
+                    mips32_op = OPC_LDXC1;
+                    goto do_ldst_cp1;
+                case SDXC1:
+                    mips32_op = OPC_SDXC1;
+                    goto do_ldst_cp1;
+                case LUXC1:
+                    mips32_op = OPC_LUXC1;
+                    goto do_ldst_cp1;
+                case SUXC1:
+                    mips32_op = OPC_SUXC1;
+                do_ldst_cp1:
+                    gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x18:
+                /* 3D insns */
+                fmt = (ctx->opcode >> 9) & 0x3;
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case RSQRT2_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        mips32_op = OPC_RSQRT2_S;
+                        goto do_3d;
+                    case FMT_SDPS_D:
+                        mips32_op = OPC_RSQRT2_D;
+                        goto do_3d;
+                    case FMT_SDPS_PS:
+                        mips32_op = OPC_RSQRT2_PS;
+                        goto do_3d;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case RECIP2_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        mips32_op = OPC_RECIP2_S;
+                        goto do_3d;
+                    case FMT_SDPS_D:
+                        mips32_op = OPC_RECIP2_D;
+                        goto do_3d;
+                    case FMT_SDPS_PS:
+                        mips32_op = OPC_RECIP2_PS;
+                        goto do_3d;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case ADDR_PS:
+                    mips32_op = OPC_ADDR_PS;
+                    goto do_3d;
+                case MULR_PS:
+                    mips32_op = OPC_MULR_PS;
+                do_3d:
+                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x20:
+                /* MOV[FT].fmt and PREFX */
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 9) & 0x3;
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case MOVF_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        gen_movcf_s(rs, rt, cc, 0);
+                        break;
+                    case FMT_SDPS_D:
+                        gen_movcf_d(ctx, rs, rt, cc, 0);
+                        break;
+                    case FMT_SDPS_PS:
+                        gen_movcf_ps(rs, rt, cc, 0);
+                        break;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case MOVT_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        gen_movcf_s(rs, rt, cc, 1);
+                        break;
+                    case FMT_SDPS_D:
+                        gen_movcf_d(ctx, rs, rt, cc, 1);
+                        break;
+                    case FMT_SDPS_PS:
+                        gen_movcf_ps(rs, rt, cc, 1);
+                        break;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case PREFX:
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+#define FINSN_3ARG_SDPS(prfx)                           \
+                switch ((ctx->opcode >> 8) & 0x3) {     \
+                case FMT_SDPS_S:                        \
+                    mips32_op = OPC_##prfx##_S;         \
+                    goto do_fpop;                       \
+                case FMT_SDPS_D:                        \
+                    mips32_op = OPC_##prfx##_D;         \
+                    goto do_fpop;                       \
+                case FMT_SDPS_PS:                       \
+                    mips32_op = OPC_##prfx##_PS;        \
+                    goto do_fpop;                       \
+                default:                                \
+                    goto pool32f_invalid;               \
+                }
+            case 0x30:
+                /* regular FP ops */
+                switch ((ctx->opcode >> 6) & 0x3) {
+                case ADD_FMT:
+                    FINSN_3ARG_SDPS(ADD);
+                    break;
+                case SUB_FMT:
+                    FINSN_3ARG_SDPS(SUB);
+                    break;
+                case MUL_FMT:
+                    FINSN_3ARG_SDPS(MUL);
+                    break;
+                case DIV_FMT:
+                    fmt = (ctx->opcode >> 8) & 0x3;
+                    if (fmt == 1) {
+                        mips32_op = OPC_DIV_D;
+                    } else if (fmt == 0) {
+                        mips32_op = OPC_DIV_S;
+                    } else {
+                        goto pool32f_invalid;
+                    }
+                    goto do_fpop;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x38:
+                /* cmovs */
+                switch ((ctx->opcode >> 6) & 0x3) {
+                case MOVN_FMT:
+                    FINSN_3ARG_SDPS(MOVN);
+                    break;
+                case MOVZ_FMT:
+                    FINSN_3ARG_SDPS(MOVZ);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            do_fpop:
+                gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                break;
+            default:
+            pool32f_invalid:
+                MIPS_INVAL("pool32f");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
+    case POOL32I:
+        minor = (ctx->opcode >> 21) & 0x1f;
+        switch (minor) {
+        case BLTZ:
+            mips32_op = OPC_BLTZ;
+            goto do_branch;
+        case BLTZAL:
+            mips32_op = OPC_BLTZAL;
+            goto do_branch;
+        case BLTZALS:
+            mips32_op = OPC_BLTZALS;
+            goto do_branch;
+        case BGEZ:
+            mips32_op = OPC_BGEZ;
+            goto do_branch;
+        case BGEZAL:
+            mips32_op = OPC_BGEZAL;
+            goto do_branch;
+        case BGEZALS:
+            mips32_op = OPC_BGEZALS;
+            goto do_branch;
+        case BLEZ:
+            mips32_op = OPC_BLEZ;
+            goto do_branch;
+        case BGTZ:
+            mips32_op = OPC_BGTZ;
+        do_branch:
+            gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
+            *is_branch = 1;
+            break;
+
+            /* Traps */
+        case TLTI:
+            mips32_op = OPC_TLTI;
+            goto do_trapi;
+        case TGEI:
+            mips32_op = OPC_TGEI;
+            goto do_trapi;
+        case TLTIU:
+            mips32_op = OPC_TLTIU;
+            goto do_trapi;
+        case TGEIU:
+            mips32_op = OPC_TGEIU;
+            goto do_trapi;
+        case TNEI:
+            mips32_op = OPC_TNEI;
+            goto do_trapi;
+        case TEQI:
+            mips32_op = OPC_TEQI;
+        do_trapi:
+            gen_trap(ctx, mips32_op, rs, -1, imm);
+            break;
+
+        case BNEZC:
+        case BEQZC:
+            gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
+                               4, rs, 0, imm << 1);
+            /* Compact branches don't have a delay slot, so just let
+               the normal delay slot handling take us to the branch
+               target. */
+            break;
+        case LUI:
+            gen_logic_imm(env, OPC_LUI, rs, -1, imm);
+            break;
+        case SYNCI:
+            break;
+        case BC2F:
+        case BC2T:
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        case BC1F:
+            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F;
+            goto do_cp1branch;
+        case BC1T:
+            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T;
+            goto do_cp1branch;
+        case BC1ANY4F:
+            mips32_op = OPC_BC1FANY4;
+            goto do_cp1mips3d;
+        case BC1ANY4T:
+            mips32_op = OPC_BC1TANY4;
+        do_cp1mips3d:
+            check_cop1x(ctx);
+            check_insn(env, ctx, ASE_MIPS3D);
+            /* Fall through */
+        do_cp1branch:
+            gen_compute_branch1(env, ctx, mips32_op,
+                                (ctx->opcode >> 18) & 0x7, imm << 1);
+            *is_branch = 1;
+            break;
+        case BPOSGE64:
+        case BPOSGE32:
+            /* MIPS DSP: not implemented */
+            /* Fall through */
+        default:
+            MIPS_INVAL("pool32i");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case POOL32C:
+        minor = (ctx->opcode >> 12) & 0xf;
+        switch (minor) {
+        case LWL:
+            mips32_op = OPC_LWL;
+            goto do_ld_lr;
+        case SWL:
+            mips32_op = OPC_SWL;
+            goto do_st_lr;
+        case LWR:
+            mips32_op = OPC_LWR;
+            goto do_ld_lr;
+        case SWR:
+            mips32_op = OPC_SWR;
+            goto do_st_lr;
+#if defined(TARGET_MIPS64)
+        case LDL:
+            mips32_op = OPC_LDL;
+            goto do_ld_lr;
+        case SDL:
+            mips32_op = OPC_SDL;
+            goto do_st_lr;
+        case LDR:
+            mips32_op = OPC_LDR;
+            goto do_ld_lr;
+        case SDR:
+            mips32_op = OPC_SDR;
+            goto do_st_lr;
+        case LWU:
+            mips32_op = OPC_LWU;
+            goto do_ld_lr;
+        case LLD:
+            mips32_op = OPC_LLD;
+            goto do_ld_lr;
+#endif
+        case LL:
+            mips32_op = OPC_LL;
+            goto do_ld_lr;
+        do_ld_lr:
+            gen_ld(env, ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        do_st_lr:
+            gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        case SC:
+            gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+#if defined(TARGET_MIPS64)
+        case SCD:
+            gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+#endif
+        case PREF:
+            /* Treat as no-op */
+            break;
+        default:
+            MIPS_INVAL("pool32c");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case ADDI32:
+        mips32_op = OPC_ADDI;
+        goto do_addi;
+    case ADDIU32:
+        mips32_op = OPC_ADDIU;
+    do_addi:
+        gen_arith_imm(env, ctx, mips32_op, rt, rs, imm);
+        break;
+
+        /* Logical operations */
+    case ORI32:
+        mips32_op = OPC_ORI;
+        goto do_logici;
+    case XORI32:
+        mips32_op = OPC_XORI;
+        goto do_logici;
+    case ANDI32:
+        mips32_op = OPC_ANDI;
+    do_logici:
+        gen_logic_imm(env, mips32_op, rt, rs, imm);
+        break;
+
+        /* Set less than immediate */
+    case SLTI32:
+        mips32_op = OPC_SLTI;
+        goto do_slti;
+    case SLTIU32:
+        mips32_op = OPC_SLTIU;
+    do_slti:
+        gen_slt_imm(env, mips32_op, rt, rs, imm);
+        break;
+    case JALX32:
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+        gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset);
+        *is_branch = 1;
+        break;
+    case JALS32:
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1;
+        gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset);
+        *is_branch = 1;
+        break;
+    case BEQ32:
+        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);
+        *is_branch = 1;
+        break;
+    case BNE32:
+        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);
+        *is_branch = 1;
+        break;
+    case J32:
+        gen_compute_branch(ctx, OPC_J, 4, rt, rs,
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+        *is_branch = 1;
+        break;
+    case JAL32:
+        gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+        *is_branch = 1;
+        break;
+        /* Floating point (COP1) */
+    case LWC132:
+        mips32_op = OPC_LWC1;
+        goto do_cop1;
+    case LDC132:
+        mips32_op = OPC_LDC1;
+        goto do_cop1;
+    case SWC132:
+        mips32_op = OPC_SWC1;
+        goto do_cop1;
+    case SDC132:
+        mips32_op = OPC_SDC1;
+    do_cop1:
+        gen_cop1_ldst(env, ctx, mips32_op, rt, rs, imm);
+        break;
+    case ADDIUPC:
+        {
+            int reg = mmreg(ZIMM(ctx->opcode, 23, 3));
+            int offset = SIMM(ctx->opcode, 0, 23) << 2;
+
+            gen_addiupc(ctx, reg, offset, 0, 0);
+        }
+        break;
+        /* Loads and stores */
+    case LB32:
+        mips32_op = OPC_LB;
+        goto do_ld;
+    case LBU32:
+        mips32_op = OPC_LBU;
+        goto do_ld;
+    case LH32:
+        mips32_op = OPC_LH;
+        goto do_ld;
+    case LHU32:
+        mips32_op = OPC_LHU;
+        goto do_ld;
+    case LW32:
+        mips32_op = OPC_LW;
+        goto do_ld;
+#ifdef TARGET_MIPS64
+    case LD32:
+        mips32_op = OPC_LD;
+        goto do_ld;
+    case SD32:
+        mips32_op = OPC_SD;
+        goto do_st;
+#endif
+    case SB32:
+        mips32_op = OPC_SB;
+        goto do_st;
+    case SH32:
+        mips32_op = OPC_SH;
+        goto do_st;
+    case SW32:
+        mips32_op = OPC_SW;
+        goto do_st;
+    do_ld:
+        gen_ld(env, ctx, mips32_op, rt, rs, imm);
+        break;
+    do_st:
+        gen_st(ctx, mips32_op, rt, rs, imm);
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+    uint32_t op;
+
+    /* make sure instructions are on a halfword boundary */
+    if (ctx->pc & 0x1) {
+        env->CP0_BadVAddr = ctx->pc;
+        generate_exception(ctx, EXCP_AdEL);
+        ctx->bstate = BS_STOP;
+        return 2;
+    }
+
+    op = (ctx->opcode >> 10) & 0x3f;
+    /* Enforce properly-sized instructions in a delay slot */
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT;
+
+        switch (op) {
+        case POOL32A:
+        case POOL32B:
+        case POOL32I:
+        case POOL32C:
+        case ADDI32:
+        case ADDIU32:
+        case ORI32:
+        case XORI32:
+        case SLTI32:
+        case SLTIU32:
+        case ANDI32:
+        case JALX32:
+        case LBU32:
+        case LHU32:
+        case POOL32F:
+        case JALS32:
+        case BEQ32:
+        case BNE32:
+        case J32:
+        case JAL32:
+        case SB32:
+        case SH32:
+        case POOL32S:
+        case ADDIUPC:
+        case SWC132:
+        case SDC132:
+        case SD32:
+        case SW32:
+        case LB32:
+        case LH32:
+        case DADDIU32:
+        case POOL48A:           /* ??? */
+        case LWC132:
+        case LDC132:
+        case LD32:
+        case LW32:
+            if (bits & MIPS_HFLAG_BDS16) {
+                generate_exception(ctx, EXCP_RI);
+                /* Just stop translation; the user is confused.  */
+                ctx->bstate = BS_STOP;
+                return 2;
+            }
+            break;
+        case POOL16A:
+        case POOL16B:
+        case POOL16C:
+        case LWGP16:
+        case POOL16F:
+        case LBU16:
+        case LHU16:
+        case LWSP16:
+        case LW16:
+        case SB16:
+        case SH16:
+        case SWSP16:
+        case SW16:
+        case MOVE16:
+        case ANDI16:
+        case POOL16D:
+        case POOL16E:
+        case BEQZ16:
+        case BNEZ16:
+        case B16:
+        case LI16:
+            if (bits & MIPS_HFLAG_BDS32) {
+                generate_exception(ctx, EXCP_RI);
+                /* Just stop translation; the user is confused.  */
+                ctx->bstate = BS_STOP;
+                return 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    switch (op) {
+    case POOL16A:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rs1 = mmreg(uMIPS_RS1(ctx->opcode));
+            int rs2 = mmreg(uMIPS_RS2(ctx->opcode));
+            uint32_t opc = 0;
+
+            switch (ctx->opcode & 0x1) {
+            case ADDU16:
+                opc = OPC_ADDU;
+                break;
+            case SUBU16:
+                opc = OPC_SUBU;
+                break;
+            }
+
+            gen_arith(env, ctx, opc, rd, rs1, rs2);
+        }
+        break;
+    case POOL16B:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rs = mmreg(uMIPS_RS(ctx->opcode));
+            int amount = (ctx->opcode >> 1) & 0x7;
+            uint32_t opc = 0;
+            amount = amount == 0 ? 8 : amount;
+
+            switch (ctx->opcode & 0x1) {
+            case SLL16:
+                opc = OPC_SLL;
+                break;
+            case SRL16:
+                opc = OPC_SRL;
+                break;
+            }
+
+            gen_shift_imm(env, ctx, opc, rd, rs, amount);
+        }
+        break;
+    case POOL16C:
+        gen_pool16c_insn(env, ctx, is_branch);
+        break;
+    case LWGP16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = 28;            /* GP */
+            int16_t offset = SIMM(ctx->opcode, 0, 7) << 2;
+
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case POOL16F:
+        if (ctx->opcode & 1) {
+            generate_exception(ctx, EXCP_RI);
+        } else {
+            /* MOVEP */
+            int enc_dest = uMIPS_RD(ctx->opcode);
+            int enc_rt = uMIPS_RS2(ctx->opcode);
+            int enc_rs = uMIPS_RS1(ctx->opcode);
+            int rd, rs, re, rt;
+            static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
+            static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
+            static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 };
+
+            rd = rd_enc[enc_dest];
+            re = re_enc[enc_dest];
+            rs = rs_rt_enc[enc_rs];
+            rt = rs_rt_enc[enc_rt];
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+            gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0);
+        }
+        break;
+    case LBU16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4);
+            offset = (offset == 0xf ? -1 : offset);
+
+            gen_ld(env, ctx, OPC_LBU, rd, rb, offset);
+        }
+        break;
+    case LHU16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+            gen_ld(env, ctx, OPC_LHU, rd, rb, offset);
+        }
+        break;
+    case LWSP16:
+        {
+            int rd = (ctx->opcode >> 5) & 0x1f;
+            int rb = 29;            /* SP */
+            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case LW16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case SB16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_st(ctx, OPC_SB, rd, rb, offset);
+        }
+        break;
+    case SH16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+            gen_st(ctx, OPC_SH, rd, rb, offset);
+        }
+        break;
+    case SWSP16:
+        {
+            int rd = (ctx->opcode >> 5) & 0x1f;
+            int rb = 29;            /* SP */
+            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+            gen_st(ctx, OPC_SW, rd, rb, offset);
+        }
+        break;
+    case SW16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+            gen_st(ctx, OPC_SW, rd, rb, offset);
+        }
+        break;
+    case MOVE16:
+        {
+            int rd = uMIPS_RD5(ctx->opcode);
+            int rs = uMIPS_RS5(ctx->opcode);
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+        }
+        break;
+    case ANDI16:
+        gen_andi16(env, ctx);
+        break;
+    case POOL16D:
+        switch (ctx->opcode & 0x1) {
+        case ADDIUS5:
+            gen_addius5(env, ctx);
+            break;
+        case ADDIUSP:
+            gen_addiusp(env, ctx);
+            break;
+        }
+        break;
+    case POOL16E:
+        switch (ctx->opcode & 0x1) {
+        case ADDIUR2:
+            gen_addiur2(env, ctx);
+            break;
+        case ADDIUR1SP:
+            gen_addiur1sp(env, ctx);
+            break;
+        }
+        break;
+    case B16:
+        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
+                           SIMM(ctx->opcode, 0, 10) << 1);
+        *is_branch = 1;
+        break;
+    case BNEZ16:
+    case BEQZ16:
+        gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
+                           mmreg(uMIPS_RD(ctx->opcode)),
+                           0, SIMM(ctx->opcode, 0, 7) << 1);
+        *is_branch = 1;
+        break;
+    case LI16:
+        {
+            int reg = mmreg(uMIPS_RD(ctx->opcode));
+            int imm = ZIMM(ctx->opcode, 0, 7);
+
+            imm = (imm == 0x7f ? -1 : imm);
+            tcg_gen_movi_tl(cpu_gpr[reg], imm);
+        }
+        break;
+    case RES_20:
+    case RES_28:
+    case RES_29:
+    case RES_30:
+    case RES_31:
+    case RES_38:
+    case RES_39:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    default:
+        decode_micromips32_opc (env, ctx, op, is_branch);
+        return 4;
+    }
+
+    return 2;
+}
+
+/* SmartMIPS extension to MIPS32 */
+
+#if defined(TARGET_MIPS64)
+
+/* MDMX extension to MIPS64 */
+
+#endif
+
+static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+    int32_t offset;
+    int rs, rt, rd, sa;
+    uint32_t op, op1, op2;
+    int16_t imm;
+
+    /* make sure instructions are on a word boundary */
+    if (ctx->pc & 0x3) {
+        env->CP0_BadVAddr = ctx->pc;
+        generate_exception(ctx, EXCP_AdEL);
+        return;
+    }
+
+    /* Handle blikely not taken case */
+    if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
+        int l1 = gen_new_label();
+
+        MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
+        tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+        tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
+        gen_goto_tb(ctx, 1, ctx->pc + 4);
+        gen_set_label(l1);
+    }
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+        tcg_gen_debug_insn_start(ctx->pc);
+
+    op = MASK_OP_MAJOR(ctx->opcode);
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
+    imm = (int16_t)ctx->opcode;
+    switch (op) {
+    case OPC_SPECIAL:
+        op1 = MASK_SPECIAL(ctx->opcode);
+        switch (op1) {
+        case OPC_SLL:          /* Shift with immediate */
+        case OPC_SRA:
+            gen_shift_imm(env, ctx, op1, rd, rt, sa);
+            break;
+        case OPC_SRL:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* rotr is decoded as srl on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_ROTR;
+                }
+                /* Fallthrough */
+            case 0:
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_MOVN:         /* Conditional move */
+        case OPC_MOVZ:
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 |
+                                 INSN_LOONGSON2E | INSN_LOONGSON2F);
+            gen_cond_move(env, op1, rd, rs, rt);
+            break;
+        case OPC_ADD ... OPC_SUBU:
+            gen_arith(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_SLLV:         /* Shifts */
+        case OPC_SRAV:
+            gen_shift(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_SRLV:
+            switch ((ctx->opcode >> 6) & 0x1f) {
+            case 1:
+                /* rotrv is decoded as srlv on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_ROTRV;
+                }
+                /* Fallthrough */
+            case 0:
+                gen_shift(env, ctx, op1, rd, rs, rt);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_SLT:          /* Set on less than */
+        case OPC_SLTU:
+            gen_slt(env, op1, rd, rs, rt);
+            break;
+        case OPC_AND:          /* Logic*/
+        case OPC_OR:
+        case OPC_NOR:
+        case OPC_XOR:
+            gen_logic(env, op1, rd, rs, rt);
+            break;
+        case OPC_MULT ... OPC_DIVU:
+            if (sa) {
+                check_insn(env, ctx, INSN_VR54XX);
+                op1 = MASK_MUL_VR54XX(ctx->opcode);
+                gen_mul_vr54xx(ctx, op1, rd, rs, rt);
+            } else
+                gen_muldiv(ctx, op1, rs, rt);
+            break;
+        case OPC_JR ... OPC_JALR:
+            gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+            *is_branch = 1;
+            break;
+        case OPC_TGE ... OPC_TEQ: /* Traps */
+        case OPC_TNE:
+            gen_trap(ctx, op1, rs, rt, -1);
+            break;
+        case OPC_MFHI:          /* Move from HI/LO */
+        case OPC_MFLO:
+            gen_HILO(ctx, op1, rd);
+            break;
+        case OPC_MTHI:
+        case OPC_MTLO:          /* Move to HI/LO */
+            gen_HILO(ctx, op1, rs);
+            break;
+        case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
+#ifdef MIPS_STRICT_STANDARD
+            MIPS_INVAL("PMON / selsl");
+            generate_exception(ctx, EXCP_RI);
+#else
+            gen_helper_0i(pmon, sa);
+#endif
+            break;
+        case OPC_SYSCALL:
+            generate_exception(ctx, EXCP_SYSCALL);
+            ctx->bstate = BS_STOP;
+            break;
+        case OPC_BREAK:
+            generate_exception(ctx, EXCP_BREAK);
+            break;
+        case OPC_SPIM:
+#ifdef MIPS_STRICT_STANDARD
+            MIPS_INVAL("SPIM");
+            generate_exception(ctx, EXCP_RI);
+#else
+           /* Implemented as RI exception for now. */
+            MIPS_INVAL("spim (unofficial)");
+            generate_exception(ctx, EXCP_RI);
+#endif
+            break;
+        case OPC_SYNC:
+            /* Treat as NOP. */
+            break;
+
+        case OPC_MOVCI:
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+            if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+                check_cp1_enabled(ctx);
+                gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                          (ctx->opcode >> 16) & 1);
+            } else {
+                generate_exception_err(ctx, EXCP_CpU, 1);
+            }
+            break;
+
+#if defined(TARGET_MIPS64)
+       /* MIPS64 specific opcodes */
+        case OPC_DSLL:
+        case OPC_DSRA:
+        case OPC_DSLL32:
+        case OPC_DSRA32:
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_shift_imm(env, ctx, op1, rd, rt, sa);
+            break;
+        case OPC_DSRL:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* drotr is decoded as dsrl on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTR;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_DSRL32:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTR32;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_DADD ... OPC_DSUBU:
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_DSLLV:
+        case OPC_DSRAV:
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_shift(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_DSRLV:
+            switch ((ctx->opcode >> 6) & 0x1f) {
+            case 1:
+                /* drotrv is decoded as dsrlv on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTRV;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift(env, ctx, op1, rd, rs, rt);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_DMULT ... OPC_DDIVU:
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_muldiv(ctx, op1, rs, rt);
+            break;
+#endif
+        default:            /* Invalid */
+            MIPS_INVAL("special");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_SPECIAL2:
+        op1 = MASK_SPECIAL2(ctx->opcode);
+        switch (op1) {
+        case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
+        case OPC_MSUB ... OPC_MSUBU:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_muldiv(ctx, op1, rs, rt);
+            break;
+        case OPC_MUL:
+            gen_arith(env, ctx, op1, rd, rs, rt);
+            break;
+        case OPC_CLO:
+        case OPC_CLZ:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_cl(ctx, op1, rd, rs);
+            break;
+        case OPC_SDBBP:
+            /* XXX: not clear which exception should be raised
+             *      when in debug mode...
+             */
+            check_insn(env, ctx, ISA_MIPS32);
+            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+                generate_exception(ctx, EXCP_DBp);
+            } else {
+                generate_exception(ctx, EXCP_DBp);
+            }
+            /* Treat as NOP. */
+            break;
+        case OPC_DIV_G_2F:
+        case OPC_DIVU_G_2F:
+        case OPC_MULT_G_2F:
+        case OPC_MULTU_G_2F:
+        case OPC_MOD_G_2F:
+        case OPC_MODU_G_2F:
+            check_insn(env, ctx, INSN_LOONGSON2F);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_DCLO:
+        case OPC_DCLZ:
+            check_insn(env, ctx, ISA_MIPS64);
+            check_mips_64(ctx);
+            gen_cl(ctx, op1, rd, rs);
+            break;
+        case OPC_DMULT_G_2F:
+        case OPC_DMULTU_G_2F:
+        case OPC_DDIV_G_2F:
+        case OPC_DDIVU_G_2F:
+        case OPC_DMOD_G_2F:
+        case OPC_DMODU_G_2F:
+            check_insn(env, ctx, INSN_LOONGSON2F);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
+#endif
+        default:            /* Invalid */
+            MIPS_INVAL("special2");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_SPECIAL3:
+        op1 = MASK_SPECIAL3(ctx->opcode);
+        switch (op1) {
+        case OPC_EXT:
+        case OPC_INS:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_BSHFL:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            op2 = MASK_BSHFL(ctx->opcode);
+            gen_bshfl(ctx, op2, rt, rd);
+            break;
+        case OPC_RDHWR:
+            gen_rdhwr(env, ctx, rt, rd);
+            break;
+        case OPC_FORK:
+            check_insn(env, ctx, ASE_MT);
+            {
+                TCGv t0 = tcg_temp_new();
+                TCGv t1 = tcg_temp_new();
+
+                gen_load_gpr(t0, rt);
+                gen_load_gpr(t1, rs);
+                gen_helper_fork(t0, t1);
+                tcg_temp_free(t0);
+                tcg_temp_free(t1);
+            }
+            break;
+        case OPC_YIELD:
+            check_insn(env, ctx, ASE_MT);
+            {
+                TCGv t0 = tcg_temp_new();
+
+                save_cpu_state(ctx, 1);
+                gen_load_gpr(t0, rs);
+                gen_helper_yield(t0, t0);
+                gen_store_gpr(t0, rd);
+                tcg_temp_free(t0);
+            }
+            break;
+        case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
+        case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
+        case OPC_MOD_G_2E ... OPC_MODU_G_2E:
+            check_insn(env, ctx, INSN_LOONGSON2E);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_DEXTM ... OPC_DEXT:
+        case OPC_DINSM ... OPC_DINS:
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_DBSHFL:
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            op2 = MASK_DBSHFL(ctx->opcode);
+            gen_bshfl(ctx, op2, rt, rd);
+            break;
+        case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+        case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+        case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
+            check_insn(env, ctx, INSN_LOONGSON2E);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
+#endif
+        default:            /* Invalid */
+            MIPS_INVAL("special3");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_REGIMM:
+        op1 = MASK_REGIMM(ctx->opcode);
+        switch (op1) {
+        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
+        case OPC_BLTZAL ... OPC_BGEZALL:
+            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+            *is_branch = 1;
+            break;
+        case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
+        case OPC_TNEI:
+            gen_trap(ctx, op1, rs, -1, imm);
+            break;
+        case OPC_SYNCI:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            /* Treat as NOP. */
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("regimm");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_CP0:
+        check_cp0_enabled(ctx);
+        op1 = MASK_CP0(ctx->opcode);
+        switch (op1) {
+        case OPC_MFC0:
+        case OPC_MTC0:
+        case OPC_MFTR:
+        case OPC_MTTR:
+#if defined(TARGET_MIPS64)
+        case OPC_DMFC0:
+        case OPC_DMTC0:
+#endif
+#ifndef CONFIG_USER_ONLY
+            gen_cp0(env, ctx, op1, rt, rd);
+#endif /* !CONFIG_USER_ONLY */
+            break;
+        case OPC_C0_FIRST ... OPC_C0_LAST:
+#ifndef CONFIG_USER_ONLY
+            gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);
+#endif /* !CONFIG_USER_ONLY */
+            break;
+        case OPC_MFMC0:
+#ifndef CONFIG_USER_ONLY
+            {
+                TCGv t0 = tcg_temp_new();
+
+                op2 = MASK_MFMC0(ctx->opcode);
+                switch (op2) {
+                case OPC_DMT:
+                    check_insn(env, ctx, ASE_MT);
+                    gen_helper_dmt(t0);
+                    gen_store_gpr(t0, rt);
+                    break;
+                case OPC_EMT:
+                    check_insn(env, ctx, ASE_MT);
+                    gen_helper_emt(t0);
+                    gen_store_gpr(t0, rt);
+                    break;
+                case OPC_DVPE:
+                    check_insn(env, ctx, ASE_MT);
+                    gen_helper_dvpe(t0);
+                    gen_store_gpr(t0, rt);
+                    break;
+                case OPC_EVPE:
+                    check_insn(env, ctx, ASE_MT);
+                    gen_helper_evpe(t0);
+                    gen_store_gpr(t0, rt);
+                    break;
+                case OPC_DI:
+                    check_insn(env, ctx, ISA_MIPS32R2);
+                    save_cpu_state(ctx, 1);
+                    gen_helper_di(t0);
+                    gen_store_gpr(t0, rt);
+                    /* Stop translation as we may have switched the execution mode */
+                    ctx->bstate = BS_STOP;
+                    break;
+                case OPC_EI:
+                    check_insn(env, ctx, ISA_MIPS32R2);
+                    save_cpu_state(ctx, 1);
+                    gen_helper_ei(t0);
+                    gen_store_gpr(t0, rt);
+                    /* Stop translation as we may have switched the execution mode */
+                    ctx->bstate = BS_STOP;
+                    break;
+                default:            /* Invalid */
+                    MIPS_INVAL("mfmc0");
+                    generate_exception(ctx, EXCP_RI);
+                    break;
+                }
+                tcg_temp_free(t0);
+            }
+#endif /* !CONFIG_USER_ONLY */
+            break;
+        case OPC_RDPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_load_srsgpr(rt, rd);
+            break;
+        case OPC_WRPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_store_srsgpr(rt, rd);
+            break;
+        default:
+            MIPS_INVAL("cp0");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_ADDI: /* Arithmetic with immediate opcode */
+    case OPC_ADDIU:
+         gen_arith_imm(env, ctx, op, rt, rs, imm);
+         break;
+    case OPC_SLTI: /* Set on less than with immediate opcode */
+    case OPC_SLTIU:
+         gen_slt_imm(env, op, rt, rs, imm);
+         break;
+    case OPC_ANDI: /* Arithmetic with immediate opcode */
+    case OPC_LUI:
+    case OPC_ORI:
+    case OPC_XORI:
+         gen_logic_imm(env, op, rt, rs, imm);
+         break;
+    case OPC_J ... OPC_JAL: /* Jump */
+         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+         gen_compute_branch(ctx, op, 4, rs, rt, offset);
+         *is_branch = 1;
+         break;
+    case OPC_BEQ ... OPC_BGTZ: /* Branch */
+    case OPC_BEQL ... OPC_BGTZL:
+         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+         *is_branch = 1;
+         break;
+    case OPC_LB ... OPC_LWR: /* Load and stores */
+    case OPC_LL:
+         gen_ld(env, ctx, op, rt, rs, imm);
+         break;
+    case OPC_SB ... OPC_SW:
+    case OPC_SWR:
+         gen_st(ctx, op, rt, rs, imm);
+         break;
+    case OPC_SC:
+         gen_st_cond(ctx, op, rt, rs, imm);
+         break;
+    case OPC_CACHE:
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
+        /* Treat as NOP. */
+        break;
+    case OPC_PREF:
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+        /* Treat as NOP. */
+        break;
+
+    /* Floating point (COP1). */
+    case OPC_LWC1:
+    case OPC_LDC1:
+    case OPC_SWC1:
+    case OPC_SDC1:
+        gen_cop1_ldst(env, ctx, op, rt, rs, imm);
+        break;
+
+    case OPC_CP1:
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            check_cp1_enabled(ctx);
+            op1 = MASK_CP1(ctx->opcode);
+            switch (op1) {
+            case OPC_MFHC1:
+            case OPC_MTHC1:
+                check_insn(env, ctx, ISA_MIPS32R2);
+            case OPC_MFC1:
+            case OPC_CFC1:
+            case OPC_MTC1:
+            case OPC_CTC1:
+                gen_cp1(ctx, op1, rt, rd);
+                break;
+#if defined(TARGET_MIPS64)
+            case OPC_DMFC1:
+            case OPC_DMTC1:
+                check_insn(env, ctx, ISA_MIPS3);
+                gen_cp1(ctx, op1, rt, rd);
+                break;
+#endif
+            case OPC_BC1ANY2:
+            case OPC_BC1ANY4:
+                check_cop1x(ctx);
+                check_insn(env, ctx, ASE_MIPS3D);
+                /* fall through */
+            case OPC_BC1:
+                gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
+                                    (rt >> 2) & 0x7, imm << 2);
+                *is_branch = 1;
+                break;
+            case OPC_S_FMT:
+            case OPC_D_FMT:
+            case OPC_W_FMT:
+            case OPC_L_FMT:
+            case OPC_PS_FMT:
+                gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
+                           (imm >> 8) & 0x7);
+                break;
+            default:
+                MIPS_INVAL("cp1");
+                generate_exception (ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
+
+    /* COP2.  */
+    case OPC_LWC2:
+    case OPC_LDC2:
+    case OPC_SWC2:
+    case OPC_SDC2:
+    case OPC_CP2:
+        /* COP2: Not implemented. */
+        generate_exception_err(ctx, EXCP_CpU, 2);
+        break;
+
+    case OPC_CP3:
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            check_cp1_enabled(ctx);
+            op1 = MASK_CP3(ctx->opcode);
+            switch (op1) {
+            case OPC_LWXC1:
+            case OPC_LDXC1:
+            case OPC_LUXC1:
+            case OPC_SWXC1:
+            case OPC_SDXC1:
+            case OPC_SUXC1:
+                gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);
+                break;
+            case OPC_PREFX:
+                /* Treat as NOP. */
+                break;
+            case OPC_ALNV_PS:
+            case OPC_MADD_S:
+            case OPC_MADD_D:
+            case OPC_MADD_PS:
+            case OPC_MSUB_S:
+            case OPC_MSUB_D:
+            case OPC_MSUB_PS:
+            case OPC_NMADD_S:
+            case OPC_NMADD_D:
+            case OPC_NMADD_PS:
+            case OPC_NMSUB_S:
+            case OPC_NMSUB_D:
+            case OPC_NMSUB_PS:
+                gen_flt3_arith(ctx, op1, sa, rs, rd, rt);
+                break;
+            default:
+                MIPS_INVAL("cp3");
+                generate_exception (ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
+
+#if defined(TARGET_MIPS64)
+    /* MIPS64 opcodes */
+    case OPC_LWU:
+    case OPC_LDL ... OPC_LDR:
+    case OPC_LLD:
+    case OPC_LD:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_ld(env, ctx, op, rt, rs, imm);
+        break;
+    case OPC_SDL ... OPC_SDR:
+    case OPC_SD:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_st(ctx, op, rt, rs, imm);
+        break;
+    case OPC_SCD:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_st_cond(ctx, op, rt, rs, imm);
+        break;
+    case OPC_DADDI:
+    case OPC_DADDIU:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_arith_imm(env, ctx, op, rt, rs, imm);
+        break;
+#endif
+    case OPC_JALX:
+        check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS);
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+        gen_compute_branch(ctx, op, 4, rs, rt, offset);
+        *is_branch = 1;
+        break;
+    case OPC_MDMX:
+        check_insn(env, ctx, ASE_MDMX);
+        /* MDMX: Not implemented. */
+    default:            /* Invalid */
+        MIPS_INVAL("major opcode");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static inline void
+gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+                                int search_pc)
+{
+    DisasContext ctx;
+    target_ulong pc_start;
+    uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int j, lj = -1;
+    int num_insns;
+    int max_insns;
+    int insn_bytes;
+    int is_branch;
+
+    if (search_pc)
+        qemu_log("search pc %d\n", search_pc);
+
+    pc_start = tb->pc;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    ctx.pc = pc_start;
+    ctx.saved_pc = -1;
+    ctx.singlestep_enabled = env->singlestep_enabled;
+    ctx.tb = tb;
+    ctx.bstate = BS_NONE;
+    /* Restore delay slot state from the tb context.  */
+    ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
+    restore_cpu_state(env, &ctx);
+#ifdef CONFIG_USER_ONLY
+        ctx.mem_idx = MIPS_HFLAG_UM;
+#else
+        ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU;
+#endif
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+    LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
+    gen_icount_start();
+    while (ctx.bstate == BS_NONE) {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == ctx.pc) {
+                    save_cpu_state(&ctx, 1);
+                    ctx.bstate = BS_BRANCH;
+                    gen_helper_0i(raise_exception, EXCP_DEBUG);
+                    /* Include the breakpoint location or the tb won't
+                     * be flushed when it must be.  */
+                    ctx.pc += 4;
+                    goto done_generating;
+                }
+            }
+        }
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = ctx.pc;
+            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+
+        is_branch = 0;
+        if (!(ctx.hflags & MIPS_HFLAG_M16)) {
+            ctx.opcode = ldl_code(ctx.pc);
+            insn_bytes = 4;
+            decode_opc(env, &ctx, &is_branch);
+        } else if (env->insn_flags & ASE_MICROMIPS) {
+            ctx.opcode = lduw_code(ctx.pc);
+            insn_bytes = decode_micromips_opc(env, &ctx, &is_branch);
+        } else if (env->insn_flags & ASE_MIPS16) {
+            ctx.opcode = lduw_code(ctx.pc);
+            insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
+        } else {
+            generate_exception(&ctx, EXCP_RI);
+            ctx.bstate = BS_STOP;
+            break;
+        }
+        if (!is_branch) {
+            handle_delay_slot(env, &ctx, insn_bytes);
+        }
+        ctx.pc += insn_bytes;
+
+        num_insns++;
+
+        /* Execute a branch and its delay slot as a single instruction.
+           This is what GDB expects and is consistent with what the
+           hardware does (e.g. if a delay slot instruction faults, the
+           reported PC is the PC of the branch).  */
+        if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0)
+            break;
+
+        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
+            break;
+
+        if (gen_opc_ptr >= gen_opc_end)
+            break;
+
+        if (num_insns >= max_insns)
+            break;
+
+        if (singlestep)
+            break;
+    }
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) {
+        save_cpu_state(&ctx, ctx.bstate == BS_NONE);
+        gen_helper_0i(raise_exception, EXCP_DEBUG);
+    } else {
+        switch (ctx.bstate) {
+        case BS_STOP:
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_NONE:
+            save_cpu_state(&ctx, 0);
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_EXCP:
+            tcg_gen_exit_tb(0);
+            break;
+        case BS_BRANCH:
+        default:
+            break;
+        }
+    }
+done_generating:
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = ctx.pc - pc_start;
+        tb->icount = num_insns;
+    }
+#ifdef DEBUG_DISAS
+    LOG_DISAS("\n");
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, ctx.pc - pc_start, 0);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+static void fpu_dump_state(CPUState *env, FILE *f, fprintf_function fpu_fprintf,
+                           int flags)
+{
+    int i;
+    int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
+
+#define printfpr(fp)                                                    \
+    do {                                                                \
+        if (is_fpu64)                                                   \
+            fpu_fprintf(f, "w:%08x d:%016" PRIx64                       \
+                        " fd:%13g fs:%13g psu: %13g\n",                 \
+                        (fp)->w[FP_ENDIAN_IDX], (fp)->d,                \
+                        (double)(fp)->fd,                               \
+                        (double)(fp)->fs[FP_ENDIAN_IDX],                \
+                        (double)(fp)->fs[!FP_ENDIAN_IDX]);              \
+        else {                                                          \
+            fpr_t tmp;                                                  \
+            tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX];              \
+            tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX];       \
+            fpu_fprintf(f, "w:%08x d:%016" PRIx64                       \
+                        " fd:%13g fs:%13g psu:%13g\n",                  \
+                        tmp.w[FP_ENDIAN_IDX], tmp.d,                    \
+                        (double)tmp.fd,                                 \
+                        (double)tmp.fs[FP_ENDIAN_IDX],                  \
+                        (double)tmp.fs[!FP_ENDIAN_IDX]);                \
+        }                                                               \
+    } while(0)
+
+
+    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%02x\n",
+                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
+                get_float_exception_flags(&env->active_fpu.fp_status));
+    for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
+        fpu_fprintf(f, "%3s: ", fregnames[i]);
+        printfpr(&env->active_fpu.fpr[i]);
+    }
+
+#undef printfpr
+}
+
+#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+/* Debug help: The architecture requires 32bit code to maintain proper
+   sign-extended values on 64bit machines.  */
+
+#define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff))
+
+static void
+cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
+                                fprintf_function cpu_fprintf,
+                                int flags)
+{
+    int i;
+
+    if (!SIGN_EXT_P(env->active_tc.PC))
+        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC);
+    if (!SIGN_EXT_P(env->active_tc.HI[0]))
+        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]);
+    if (!SIGN_EXT_P(env->active_tc.LO[0]))
+        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]);
+    if (!SIGN_EXT_P(env->btarget))
+        cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
+
+    for (i = 0; i < 32; i++) {
+        if (!SIGN_EXT_P(env->active_tc.gpr[i]))
+            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]);
+    }
+
+    if (!SIGN_EXT_P(env->CP0_EPC))
+        cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC);
+    if (!SIGN_EXT_P(env->lladdr))
+        cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->lladdr);
+}
+#endif
+
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    int i;
+
+    cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
+                " LO=0x" TARGET_FMT_lx " ds %04x "
+                TARGET_FMT_lx " " TARGET_FMT_ld "\n",
+                env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
+                env->hflags, env->btarget, env->bcond);
+    for (i = 0; i < 32; i++) {
+        if ((i & 3) == 0)
+            cpu_fprintf(f, "GPR%02d:", i);
+        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]);
+        if ((i & 3) == 3)
+            cpu_fprintf(f, "\n");
+    }
+
+    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x" TARGET_FMT_lx "\n",
+                env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
+    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n",
+                env->CP0_Config0, env->CP0_Config1, env->lladdr);
+    if (env->hflags & MIPS_HFLAG_FPU)
+        fpu_dump_state(env, f, cpu_fprintf, flags);
+#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+    cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags);
+#endif
+}
+
+static void mips_tcg_init(void)
+{
+    int i;
+    static int inited;
+
+    /* Initialize various static tables. */
+    if (inited)
+        return;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    TCGV_UNUSED(cpu_gpr[0]);
+    for (i = 1; i < 32; i++)
+        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
+                                        offsetof(CPUState, active_tc.gpr[i]),
+                                        regnames[i]);
+    cpu_PC = tcg_global_mem_new(TCG_AREG0,
+                                offsetof(CPUState, active_tc.PC), "PC");
+    for (i = 0; i < MIPS_DSP_ACC; i++) {
+        cpu_HI[i] = tcg_global_mem_new(TCG_AREG0,
+                                       offsetof(CPUState, active_tc.HI[i]),
+                                       regnames_HI[i]);
+        cpu_LO[i] = tcg_global_mem_new(TCG_AREG0,
+                                       offsetof(CPUState, active_tc.LO[i]),
+                                       regnames_LO[i]);
+        cpu_ACX[i] = tcg_global_mem_new(TCG_AREG0,
+                                        offsetof(CPUState, active_tc.ACX[i]),
+                                        regnames_ACX[i]);
+    }
+    cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, active_tc.DSPControl),
+                                     "DSPControl");
+    bcond = tcg_global_mem_new(TCG_AREG0,
+                               offsetof(CPUState, bcond), "bcond");
+    btarget = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUState, btarget), "btarget");
+    hflags = tcg_global_mem_new_i32(TCG_AREG0,
+                                    offsetof(CPUState, hflags), "hflags");
+
+    fpu_fcr0 = tcg_global_mem_new_i32(TCG_AREG0,
+                                      offsetof(CPUState, active_fpu.fcr0),
+                                      "fcr0");
+    fpu_fcr31 = tcg_global_mem_new_i32(TCG_AREG0,
+                                       offsetof(CPUState, active_fpu.fcr31),
+                                       "fcr31");
+
+    /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+
+    inited = 1;
+}
+
+#include "translate_init.c"
+
+CPUMIPSState *cpu_mips_init (const char *cpu_model)
+{
+    CPUMIPSState *env;
+    const mips_def_t *def;
+
+    def = cpu_mips_find_by_name(cpu_model);
+    if (!def)
+        return NULL;
+    env = qemu_mallocz(sizeof(CPUMIPSState));
+    env->cpu_model = def;
+    env->cpu_model_str = cpu_model;
+
+    cpu_exec_init(env);
+#ifndef CONFIG_USER_ONLY
+    mmu_init(env, def);
+#endif
+    fpu_init(env, def);
+    mvp_init(env, def);
+    mips_tcg_init();
+    cpu_reset(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+void cpu_reset (CPUMIPSState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    memset(env, 0, offsetof(CPUMIPSState, breakpoints));
+    tlb_flush(env, 1);
+
+    /* Reset registers to their default values */
+    env->CP0_PRid = env->cpu_model->CP0_PRid;
+    env->CP0_Config0 = env->cpu_model->CP0_Config0;
+#ifdef TARGET_WORDS_BIGENDIAN
+    env->CP0_Config0 |= (1 << CP0C0_BE);
+#endif
+    env->CP0_Config1 = env->cpu_model->CP0_Config1;
+    env->CP0_Config2 = env->cpu_model->CP0_Config2;
+    env->CP0_Config3 = env->cpu_model->CP0_Config3;
+    env->CP0_Config6 = env->cpu_model->CP0_Config6;
+    env->CP0_Config7 = env->cpu_model->CP0_Config7;
+    env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
+                                 << env->cpu_model->CP0_LLAddr_shift;
+    env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
+    env->SYNCI_Step = env->cpu_model->SYNCI_Step;
+    env->CCRes = env->cpu_model->CCRes;
+    env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
+    env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
+    env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
+    env->current_tc = 0;
+    env->SEGBITS = env->cpu_model->SEGBITS;
+    env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
+#if defined(TARGET_MIPS64)
+    if (env->cpu_model->insn_flags & ISA_MIPS3) {
+        env->SEGMask |= 3ULL << 62;
+    }
+#endif
+    env->PABITS = env->cpu_model->PABITS;
+    env->PAMask = (target_ulong)((1ULL << env->cpu_model->PABITS) - 1);
+    env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
+    env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
+    env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
+    env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
+    env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
+    env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
+    env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
+    env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
+    env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
+    env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
+    env->insn_flags = env->cpu_model->insn_flags;
+
+#if defined(CONFIG_USER_ONLY)
+    env->hflags = MIPS_HFLAG_UM;
+    /* Enable access to the SYNCI_Step register.  */
+    env->CP0_HWREna |= (1 << 1);
+    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+        env->hflags |= MIPS_HFLAG_FPU;
+    }
+#ifdef TARGET_MIPS64
+    if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
+        env->hflags |= MIPS_HFLAG_F64;
+    }
+#endif
+#else
+    if (env->hflags & MIPS_HFLAG_BMASK) {
+        /* If the exception was raised from a delay slot,
+           come back to the jump.  */
+        env->CP0_ErrorEPC = env->active_tc.PC - 4;
+    } else {
+        env->CP0_ErrorEPC = env->active_tc.PC;
+    }
+    env->active_tc.PC = (int32_t)0xBFC00000;
+    env->CP0_Random = env->tlb->nb_tlb - 1;
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
+    env->CP0_Wired = 0;
+    env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF);
+    env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
+    /* vectored interrupts not implemented, timer on int 7,
+       no performance counters. */
+    env->CP0_IntCtl = 0xe0000000;
+    {
+        int i;
+
+        for (i = 0; i < 7; i++) {
+            env->CP0_WatchLo[i] = 0;
+            env->CP0_WatchHi[i] = 0x80000000;
+        }
+        env->CP0_WatchLo[7] = 0;
+        env->CP0_WatchHi[7] = 0;
+    }
+    /* Count register increments in debug mode, EJTAG version 1 */
+    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
+    env->hflags = MIPS_HFLAG_CP0;
+#endif
+#if defined(TARGET_MIPS64)
+    if (env->cpu_model->insn_flags & ISA_MIPS3) {
+        env->hflags |= MIPS_HFLAG_64;
+    }
+#endif
+    env->exception_index = EXCP_NONE;
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->active_tc.PC = gen_opc_pc[pc_pos];
+    env->hflags &= ~MIPS_HFLAG_BMASK;
+    env->hflags |= gen_opc_hflags[pc_pos];
+}
diff --git a/qemu-0.15.x/target-mips/translate_init.c b/qemu-0.15.x/target-mips/translate_init.c
new file mode 100644
index 0000000..d55c522
--- /dev/null
+++ b/qemu-0.15.x/target-mips/translate_init.c
@@ -0,0 +1,594 @@
+/*
+ *  MIPS emulation for qemu: CPU initialisation routines.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2007 Herve Poussineau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* CPU / CPU family specific config register values. */
+
+/* Have config1, uncached coherency */
+#define MIPS_CONFIG0                                              \
+  ((1 << CP0C0_M) | (0x2 << CP0C0_K0))
+
+/* Have config2, no coprocessor2 attached, no MDMX support attached,
+   no performance counters, watch registers present,
+   no code compression, EJTAG present, no FPU */
+#define MIPS_CONFIG1                                              \
+((1 << CP0C1_M) |                                                 \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) |            \
+ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) |            \
+ (0 << CP0C1_FP))
+
+/* Have config3, no tertiary/secondary caches implemented */
+#define MIPS_CONFIG2                                              \
+((1 << CP0C2_M))
+
+/* No config4, no DSP ASE, no large physaddr (PABITS),
+   no external interrupt controller, no vectored interrupts,
+   no 1kb pages, no SmartMIPS ASE, no trace logic */
+#define MIPS_CONFIG3                                              \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) |          \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) |        \
+ (0 << CP0C3_SM) | (0 << CP0C3_TL))
+
+/* MMU types, the first four entries have the same layout as the
+   CP0C0_MT field.  */
+enum mips_mmu_types {
+    MMU_TYPE_NONE,
+    MMU_TYPE_R4000,
+    MMU_TYPE_RESERVED,
+    MMU_TYPE_FMT,
+    MMU_TYPE_R3000,
+    MMU_TYPE_R6000,
+    MMU_TYPE_R8000
+};
+
+struct mips_def_t {
+    const char *name;
+    int32_t CP0_PRid;
+    int32_t CP0_Config0;
+    int32_t CP0_Config1;
+    int32_t CP0_Config2;
+    int32_t CP0_Config3;
+    int32_t CP0_Config6;
+    int32_t CP0_Config7;
+    target_ulong CP0_LLAddr_rw_bitmask;
+    int CP0_LLAddr_shift;
+    int32_t SYNCI_Step;
+    int32_t CCRes;
+    int32_t CP0_Status_rw_bitmask;
+    int32_t CP0_TCStatus_rw_bitmask;
+    int32_t CP0_SRSCtl;
+    int32_t CP1_fcr0;
+    int32_t SEGBITS;
+    int32_t PABITS;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
+    int insn_flags;
+    enum mips_mmu_types mmu_type;
+};
+
+/*****************************************************************************/
+/* MIPS CPU definitions */
+static const mips_def_t mips_defs[] =
+{
+    {
+        .name = "4Kc",
+        .CP0_PRid = 0x00018000,
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (0 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "4Km",
+        .CP0_PRid = 0x00018300,
+        /* Config1 implemented, fixed mapping MMU,
+           no virtual icache, uncached coherency. */
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
+    },
+    {
+        .name = "4KEcR1",
+        .CP0_PRid = 0x00018400,
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (0 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "4KEmR1",
+        .CP0_PRid = 0x00018500,
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
+    },
+    {
+        .name = "4KEc",
+        .CP0_PRid = 0x00019000,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (0 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "4KEm",
+        .CP0_PRid = 0x00019100,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                       (MMU_TYPE_FMT << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_FMT,
+    },
+    {
+        .name = "24Kc",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x1278FF1F,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "24Kf",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF1F,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "34Kf",
+        .CP0_PRid = 0x00019500,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_CA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 0,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF1F,
+        /* No DSP implemented. */
+        .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) |
+                    (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) |
+                    (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) |
+                    (1 << CP0TCSt_DA) | (1 << CP0TCSt_A) |
+                    (0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) |
+                    (0xff << CP0TCSt_TASID),
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
+        .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
+        .CP0_SRSConf0_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf0 = (1 << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
+                    (0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1),
+        .CP0_SRSConf1_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf1 = (1 << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) |
+                    (0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4),
+        .CP0_SRSConf2_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf2 = (1 << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) |
+                    (0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7),
+        .CP0_SRSConf3_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf3 = (1 << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) |
+                    (0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10),
+        .CP0_SRSConf4_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
+                    (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+#if defined(TARGET_MIPS64)
+    {
+        .name = "R4000",
+        .CP0_PRid = 0x00000400,
+        /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
+        .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
+        /* Note: Config1 is only used internally, the R4000 has only Config0. */
+        .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+        .CP0_LLAddr_rw_bitmask = 0xFFFFFFFF,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x3678FFFF,
+        /* The R4000 has a full 64bit FPU but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS3,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "VR5432",
+        .CP0_PRid = 0x00005400,
+        /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
+        .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
+        .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+        .CP0_LLAddr_rw_bitmask = 0xFFFFFFFFL,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x3678FFFF,
+        /* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .PABITS = 32,
+        .insn_flags = CPU_VR54XX,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "5Kc",
+        .CP0_PRid = 0x00018100,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) |
+                       (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x32F8FFFF,
+        .SEGBITS = 42,
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS64,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "5Kf",
+        .CP0_PRid = 0x00018100,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
+                       (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x36F8FFFF,
+        /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
+                    (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 42,
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS64,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "20Kc",
+        /* We emulate a later version of the 20Kc, earlier ones had a broken
+           WAIT instruction. */
+        .CP0_PRid = 0x000182a0,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
+                    (MMU_TYPE_R4000 << CP0C0_MT) | (1 << CP0C0_VI),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
+                       (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+                       (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 0,
+        .SYNCI_Step = 32,
+        .CCRes = 1,
+        .CP0_Status_rw_bitmask = 0x36FBFFFF,
+        /* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
+                    (1 << FCR0_D) | (1 << FCR0_S) |
+                    (0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        /* A generic CPU providing MIPS64 Release 2 features.
+           FIXME: Eventually this should be replaced by a real CPU model. */
+        .name = "MIPS64R2-generic",
+        .CP0_PRid = 0x00010000,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+                       (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+                       (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 0,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x36FBFFFF,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
+                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
+                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 42,
+        /* The architectural limit is 59, but we have hardcoded 36 bit
+           in some places...
+        .PABITS = 59, */ /* the architectural limit */
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "Loongson-2E",
+        .CP0_PRid = 0x6302,
+        /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/
+        .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) |
+                       (0x1<<4) | (0x1<<1),
+        /* Note: Config1 is only used internally, Loongson-2E has only Config0. */
+        .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x35D0FFFF,
+        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+        .SEGBITS = 40,
+        .PABITS = 40,
+        .insn_flags = CPU_LOONGSON2E,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+      .name = "Loongson-2F",
+      .CP0_PRid = 0x6303,
+      /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/
+      .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) |
+                     (0x1<<4) | (0x1<<1),
+      /* Note: Config1 is only used internally, Loongson-2F has only Config0. */
+      .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+      .SYNCI_Step = 16,
+      .CCRes = 2,
+      .CP0_Status_rw_bitmask = 0xF5D0FF1F,   /*bit5:7 not writable*/
+      .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+      .SEGBITS = 40,
+      .PABITS = 40,
+      .insn_flags = CPU_LOONGSON2F,
+      .mmu_type = MMU_TYPE_R4000,
+    },
+
+#endif
+};
+
+static const mips_def_t *cpu_mips_find_by_name (const char *name)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
+        if (strcasecmp(name, mips_defs[i].name) == 0) {
+            return &mips_defs[i];
+        }
+    }
+    return NULL;
+}
+
+void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
+        (*cpu_fprintf)(f, "MIPS '%s'\n",
+                       mips_defs[i].name);
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+static void no_mmu_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &no_mmu_map_address;
+}
+
+static void fixed_mmu_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &fixed_mmu_map_address;
+}
+
+static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
+    env->tlb->map_address = &r4k_map_address;
+    env->tlb->helper_tlbwi = r4k_helper_tlbwi;
+    env->tlb->helper_tlbwr = r4k_helper_tlbwr;
+    env->tlb->helper_tlbp = r4k_helper_tlbp;
+    env->tlb->helper_tlbr = r4k_helper_tlbr;
+}
+
+static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext));
+
+    switch (def->mmu_type) {
+        case MMU_TYPE_NONE:
+            no_mmu_init(env, def);
+            break;
+        case MMU_TYPE_R4000:
+            r4k_mmu_init(env, def);
+            break;
+        case MMU_TYPE_FMT:
+            fixed_mmu_init(env, def);
+            break;
+        case MMU_TYPE_R3000:
+        case MMU_TYPE_R6000:
+        case MMU_TYPE_R8000:
+        default:
+            cpu_abort(env, "MMU type not supported\n");
+    }
+}
+#endif /* CONFIG_USER_ONLY */
+
+static void fpu_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    int i;
+
+    for (i = 0; i < MIPS_FPU_MAX; i++)
+        env->fpus[i].fcr0 = def->CP1_fcr0;
+
+    memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu));
+}
+
+static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
+{
+    env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext));
+
+    /* MVPConf1 implemented, TLB sharable, no gating storage support,
+       programmable cache partitioning implemented, number of allocatable
+       and sharable TLB entries, MVP has allocatable TCs, 2 VPEs
+       implemented, 5 TCs implemented. */
+    env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) |
+                             (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) |
+// TODO: actually do 2 VPEs.
+//                             (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) |
+//                             (0x04 << CP0MVPC0_PTC);
+                             (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) |
+                             (0x04 << CP0MVPC0_PTC);
+#if !defined(CONFIG_USER_ONLY)
+    /* Usermode has no TLB support */
+    env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE);
+#endif
+
+    /* Allocatable CP1 have media extensions, allocatable CP1 have FP support,
+       no UDI implemented, no CP2 implemented, 1 CP1 implemented. */
+    env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) |
+                             (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) |
+                             (0x1 << CP0MVPC1_PCP1);
+}
diff --git a/qemu-0.15.x/target-ppc/STATUS b/qemu-0.15.x/target-ppc/STATUS
new file mode 100644
index 0000000..c8e9018
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/STATUS
@@ -0,0 +1,559 @@
+PowerPC emulation status.
+The goal of this file is to provide a reference status to avoid regressions.
+
+===============================================================================
+PowerPC core emulation status
+
+INSN: instruction set.
+      OK => all instructions are emulated
+      KO => some insns are missing or some should be removed
+      ?  => unchecked
+SPR:  special purpose registers set
+      OK => all SPR registered (but some may be fake)
+      KO => some SPR are missing or should be removed
+      ?  => unchecked
+MSR:  MSR bits definitions
+      OK => all MSR bits properly defined
+      KO => MSR definition is incorrect
+      ?  => unchecked
+IRQ:  input signals definitions (mostly interrupts)
+      OK => input signals are properly defined
+      KO => input signals are not implemented (system emulation does not work)
+      ?  => input signals definitions may be incorrect
+MMU:  MMU model implementation
+      OK => MMU model is implemented and Linux is able to boot
+      KO => MMU model not implemented or bugged
+      ?  => MMU model not tested
+EXCP: exceptions model implementation
+      OK => exception model is implemented and Linux is able to boot
+      KO => exception model not implemented or known to be buggy
+      ?  => exception model may be incorrect or is untested
+
+Embedded PowerPC cores
+***
+PowerPC 401:
+INSN  OK
+SPR   OK 401A1
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+PowerPC 401x2:
+INSN  OK
+SPR   OK 401B2 401C2 401D2 401E2 401F2
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+PowerPC IOP480:
+INSN  OK
+SPR   OK IOP480
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+To be checked: 401G2 401B3 Cobra
+
+***
+PowerPC 403:
+INSN  OK
+SPR   OK 403GA 403GB
+MMU   OK
+MSR   OK
+IRQ   KO not implemented
+EXCP  ?
+
+PowerPC 403GCX:
+INSN  OK
+SPR   OK 403GCX
+MMU   OK
+MSR   OK
+IRQ   KO not implemented
+EXCP  ?
+
+To be checked: 403GC
+
+***
+PowerPC 405:
+Checked: 405CRa 405CRb 405CRc 405EP 405GPa 405GPb 405GPc 405GPd 405GPe 405GPR
+         Npe405H Npe405H2 Npe405L
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots (at least 1 proprietary firmware).
+         uboot seems to freeze at boot time.
+To be checked: 405D2 405D4 405EZ 405LP Npe4GS3 STB03 STB04 STB25
+               x2vp4 x2vp7 x2vp20 x2vp50
+
+XXX: find what is IBM e407b4
+
+***
+PowerPC 440:
+Checked: 440EPa 440EPb 440GXa 440GXb 440GXc 440GXf 440SP 440SP2
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440GP:
+Checked: 440GPb 440GPc
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440x4:
+Checked: 440A4 440B4 440G4 440H4
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440x5:
+Checked: 440A5 440F5 440G5 440H6 440GRa
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+To be checked: 440EPx 440GRx 440SPE
+
+***
+PowerPC 460: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+PowerPC 460F: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e200: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e300: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e500: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e600: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+32 bits PowerPC
+PowerPC 601: (601 601v2)
+INSN  OK
+SPR   OK is HID15 only on 601v2 ?
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+Remarks: some instructions should have a specific behavior (not implemented)
+
+PowerPC 602: 602
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   ?
+EXCP  ? at least timer and external interrupt are OK
+Remarks: Linux 2.4 crashes when entering user-mode.
+         Linux 2.6.22 boots on this CPU but does not recognize it.
+
+PowerPC 603: (603)
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU
+         Linux 2.6.22 idem.
+
+PowerPC 603e: (603e11)
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU
+         Linux 2.6.22 idem.
+
+PowerPC G2:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots, recognizes the CPU as a 82xx.
+         Linux 2.6.22 idem.
+
+PowerPC G2le:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 does not boots. Same symptoms as 602.
+         Linux 2.6.22 boots and properly recognizes the CPU.
+
+PowerPC 604:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU.
+         Linux 2.6.22 idem.
+
+PowerPC 7x0:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU.
+         Linux 2.6.22 idem.
+
+PowerPC 750fx:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots but does not properly recognizes the CPU.
+         Linux 2.6.22 boots and properly recognizes the CPU.
+
+PowerPC 7x5:
+INSN  ?
+SPR   ?
+MSR   ?
+IRQ   OK
+MMU   ?
+EXCP  OK
+Remarks: Linux 2.4 does not boot.
+         Linux 2.6.22 idem.
+
+PowerPC 7400:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux 2.4 boots and properly recognize the CPU.
+         Linux 2.6.22 idem.
+
+PowerPC 7410:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux 2.4 boots and properly recognize the CPU.
+         Linux 2.6.22 idem.
+   Note that UM says tlbld & tlbli are implemented but this may be a mistake
+   as TLB loads are managed by the hardware and the CPU does not implement the
+   needed registers.
+
+PowerPC 7441:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux does not have the code to handle TLB miss on this CPU
+         Linux 2.6.22 idem.
+
+PowerPC 7450/7451:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux does not have the code to handle TLB miss on this CPU
+         Linux 2.6.22 idem.
+
+PowerPC 7445/7447:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux does not have the code to handle TLB miss on this CPU
+         Linux 2.6.22 idem.
+
+PowerPC 7455/7457:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+Remarks: Linux does not have the code to handle TLB miss on this CPU
+         Linux 2.6.22 idem.
+
+64 bits PowerPC
+PowerPC 620: (disabled)
+INSN  KO
+SPR   KO
+MSR   ?
+IRQ   KO
+MMU   KO
+EXCP  KO
+Remarks: not much documentation for this implementation...
+
+PowerPC 970:
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   OK
+MMU   OK
+EXCP  KO partially implemented
+Remarks: Should be able to boot but there is no hw platform currently emulated.
+
+PowerPC 970FX:
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   OK
+MMU   OK
+EXCP  KO partially implemented
+Remarks: Should be able to boot but there is no hw platform currently emulated.
+
+PowerPC 970GX:
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   OK
+MMU   OK
+EXCP  KO partially implemented
+Remarks: Should be able to boot but there is no hw platform currently emulated.
+
+PowerPC Cell:
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   ?
+MMU   ?
+EXCP  ? partially implemented
+Remarks: As the core is mostly a 970, should be able to boot.
+         SPE are not implemented.
+
+PowerPC 630: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+PowerPC 631: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER4: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER4+: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER5: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER5+: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER6: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-II: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-III: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-IV: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+Original POWER
+POWER: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER2: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+===============================================================================
+PowerPC microcontrollers emulation status
+
+Implemementation should be sufficient to boot Linux:
+(there seem to be problems with uboot freezing at some point)
+- PowerPC 405CR
+- PowerPC 405EP
+
+TODO:
+- PowerPC 401 microcontrollers emulation
+- PowerPC 403 microcontrollers emulation
+- more PowerPC 405 microcontrollers emulation
+- Fixes / more features for implemented PowerPC 405 microcontrollers emulation
+- PowerPC 440 microcontrollers emulation
+- e200 microcontrollers emulation
+- e300 microcontrollers emulation
+- e500 microcontrollers emulation
+- e600 microcontrollers emulation
+
+===============================================================================
+PowerPC based platforms emulation status
+
+* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* mac99 platform (white and blue PowerMac, ...)
+- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
+- Debian Linux woody - boots from CDROM and HDD
+- Mandrake Linux 9 - boots from CDROM, freezes during install
+- Knoppix 2003-07-13_4 boots from CDROM, pb with X configuration
+  distribution bug: X runs with a properly hand-coded configuration.
+- rock Linux 2.0 runs from CDROM
+
+* Linux 2.6 support seems deadly broken (used to boot...).
+
+* PowerPC 405EP reference boards:
+- can boot Linux 2.4 & 2.6.
+  Need to provide a flash image ready to boot for reproductible tests.
+
+TODO:
+- URGENT: fix PreP and heathrow platforms
+- PowerPC 64 reference platform
+- MCA based RS/6000 emulation
+- CHRP emulation (not PowerMac)
+- PPAR emulation
+- ePPAR emulation
+- misc PowerPC reference boards emulation
+
+===============================================================================
diff --git a/qemu-0.15.x/target-ppc/cpu.h b/qemu-0.15.x/target-ppc/cpu.h
new file mode 100644
index 0000000..d903366
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/cpu.h
@@ -0,0 +1,2031 @@
+/*
+ *  PowerPC emulation cpu definitions for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined (__CPU_PPC_H__)
+#define __CPU_PPC_H__
+
+#include "config.h"
+#include "qemu-common.h"
+
+//#define PPC_EMULATE_32BITS_HYPV
+
+#if defined (TARGET_PPC64)
+/* PowerPC 64 definitions */
+#define TARGET_LONG_BITS 64
+#define TARGET_PAGE_BITS 12
+
+/* Note that the official physical address space bits is 62-M where M
+   is implementation dependent.  I've not looked up M for the set of
+   cpus we emulate at the system level.  */
+#define TARGET_PHYS_ADDR_SPACE_BITS 62
+
+/* Note that the PPC environment architecture talks about 80 bit virtual
+   addresses, with segmentation.  Obviously that's not all visible to a
+   single process, which is all we're concerned with here.  */
+#ifdef TARGET_ABI32
+# define TARGET_VIRT_ADDR_SPACE_BITS 32
+#else
+# define TARGET_VIRT_ADDR_SPACE_BITS 64
+#endif
+
+#define TARGET_PAGE_BITS_16M 24
+
+#else /* defined (TARGET_PPC64) */
+/* PowerPC 32 definitions */
+#define TARGET_LONG_BITS 32
+
+#if defined(TARGET_PPCEMB)
+/* Specific definitions for PowerPC embedded */
+/* BookE have 36 bits physical address space */
+#if defined(CONFIG_USER_ONLY)
+/* It looks like a lot of Linux programs assume page size
+ * is 4kB long. This is evil, but we have to deal with it...
+ */
+#define TARGET_PAGE_BITS 12
+#else /* defined(CONFIG_USER_ONLY) */
+/* Pages can be 1 kB small */
+#define TARGET_PAGE_BITS 10
+#endif /* defined(CONFIG_USER_ONLY) */
+#else /* defined(TARGET_PPCEMB) */
+/* "standard" PowerPC 32 definitions */
+#define TARGET_PAGE_BITS 12
+#endif /* defined(TARGET_PPCEMB) */
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#endif /* defined (TARGET_PPC64) */
+
+#define CPUState struct CPUPPCState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define TARGET_HAS_ICE 1
+
+#if defined (TARGET_PPC64)
+#define ELF_MACHINE     EM_PPC64
+#else
+#define ELF_MACHINE     EM_PPC
+#endif
+
+/*****************************************************************************/
+/* MMU model                                                                 */
+typedef enum powerpc_mmu_t powerpc_mmu_t;
+enum powerpc_mmu_t {
+    POWERPC_MMU_UNKNOWN    = 0x00000000,
+    /* Standard 32 bits PowerPC MMU                            */
+    POWERPC_MMU_32B        = 0x00000001,
+    /* PowerPC 6xx MMU with software TLB                       */
+    POWERPC_MMU_SOFT_6xx   = 0x00000002,
+    /* PowerPC 74xx MMU with software TLB                      */
+    POWERPC_MMU_SOFT_74xx  = 0x00000003,
+    /* PowerPC 4xx MMU with software TLB                       */
+    POWERPC_MMU_SOFT_4xx   = 0x00000004,
+    /* PowerPC 4xx MMU with software TLB and zones protections */
+    POWERPC_MMU_SOFT_4xx_Z = 0x00000005,
+    /* PowerPC MMU in real mode only                           */
+    POWERPC_MMU_REAL       = 0x00000006,
+    /* Freescale MPC8xx MMU model                              */
+    POWERPC_MMU_MPC8xx     = 0x00000007,
+    /* BookE MMU model                                         */
+    POWERPC_MMU_BOOKE      = 0x00000008,
+    /* BookE 2.06 MMU model                                    */
+    POWERPC_MMU_BOOKE206   = 0x00000009,
+    /* PowerPC 601 MMU model (specific BATs format)            */
+    POWERPC_MMU_601        = 0x0000000A,
+#if defined(TARGET_PPC64)
+#define POWERPC_MMU_64       0x00010000
+#define POWERPC_MMU_1TSEG    0x00020000
+    /* 64 bits PowerPC MMU                                     */
+    POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
+    /* 620 variant (no segment exceptions)                     */
+    POWERPC_MMU_620        = POWERPC_MMU_64 | 0x00000002,
+    /* Architecture 2.06 variant                               */
+    POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
+#endif /* defined(TARGET_PPC64) */
+};
+
+/*****************************************************************************/
+/* Exception model                                                           */
+typedef enum powerpc_excp_t powerpc_excp_t;
+enum powerpc_excp_t {
+    POWERPC_EXCP_UNKNOWN   = 0,
+    /* Standard PowerPC exception model */
+    POWERPC_EXCP_STD,
+    /* PowerPC 40x exception model      */
+    POWERPC_EXCP_40x,
+    /* PowerPC 601 exception model      */
+    POWERPC_EXCP_601,
+    /* PowerPC 602 exception model      */
+    POWERPC_EXCP_602,
+    /* PowerPC 603 exception model      */
+    POWERPC_EXCP_603,
+    /* PowerPC 603e exception model     */
+    POWERPC_EXCP_603E,
+    /* PowerPC G2 exception model       */
+    POWERPC_EXCP_G2,
+    /* PowerPC 604 exception model      */
+    POWERPC_EXCP_604,
+    /* PowerPC 7x0 exception model      */
+    POWERPC_EXCP_7x0,
+    /* PowerPC 7x5 exception model      */
+    POWERPC_EXCP_7x5,
+    /* PowerPC 74xx exception model     */
+    POWERPC_EXCP_74xx,
+    /* BookE exception model            */
+    POWERPC_EXCP_BOOKE,
+#if defined(TARGET_PPC64)
+    /* PowerPC 970 exception model      */
+    POWERPC_EXCP_970,
+    /* POWER7 exception model           */
+    POWERPC_EXCP_POWER7,
+#endif /* defined(TARGET_PPC64) */
+};
+
+/*****************************************************************************/
+/* Exception vectors definitions                                             */
+enum {
+    POWERPC_EXCP_NONE    = -1,
+    /* The 64 first entries are used by the PowerPC embedded specification   */
+    POWERPC_EXCP_CRITICAL = 0,  /* Critical input                            */
+    POWERPC_EXCP_MCHECK   = 1,  /* Machine check exception                   */
+    POWERPC_EXCP_DSI      = 2,  /* Data storage exception                    */
+    POWERPC_EXCP_ISI      = 3,  /* Instruction storage exception             */
+    POWERPC_EXCP_EXTERNAL = 4,  /* External input                            */
+    POWERPC_EXCP_ALIGN    = 5,  /* Alignment exception                       */
+    POWERPC_EXCP_PROGRAM  = 6,  /* Program exception                         */
+    POWERPC_EXCP_FPU      = 7,  /* Floating-point unavailable exception      */
+    POWERPC_EXCP_SYSCALL  = 8,  /* System call exception                     */
+    POWERPC_EXCP_APU      = 9,  /* Auxiliary processor unavailable           */
+    POWERPC_EXCP_DECR     = 10, /* Decrementer exception                     */
+    POWERPC_EXCP_FIT      = 11, /* Fixed-interval timer interrupt            */
+    POWERPC_EXCP_WDT      = 12, /* Watchdog timer interrupt                  */
+    POWERPC_EXCP_DTLB     = 13, /* Data TLB miss                             */
+    POWERPC_EXCP_ITLB     = 14, /* Instruction TLB miss                      */
+    POWERPC_EXCP_DEBUG    = 15, /* Debug interrupt                           */
+    /* Vectors 16 to 31 are reserved                                         */
+    POWERPC_EXCP_SPEU     = 32, /* SPE/embedded floating-point unavailable   */
+    POWERPC_EXCP_EFPDI    = 33, /* Embedded floating-point data interrupt    */
+    POWERPC_EXCP_EFPRI    = 34, /* Embedded floating-point round interrupt   */
+    POWERPC_EXCP_EPERFM   = 35, /* Embedded performance monitor interrupt    */
+    POWERPC_EXCP_DOORI    = 36, /* Embedded doorbell interrupt               */
+    POWERPC_EXCP_DOORCI   = 37, /* Embedded doorbell critical interrupt      */
+    /* Vectors 38 to 63 are reserved                                         */
+    /* Exceptions defined in the PowerPC server specification                */
+    POWERPC_EXCP_RESET    = 64, /* System reset exception                    */
+    POWERPC_EXCP_DSEG     = 65, /* Data segment exception                    */
+    POWERPC_EXCP_ISEG     = 66, /* Instruction segment exception             */
+    POWERPC_EXCP_HDECR    = 67, /* Hypervisor decrementer exception          */
+    POWERPC_EXCP_TRACE    = 68, /* Trace exception                           */
+    POWERPC_EXCP_HDSI     = 69, /* Hypervisor data storage exception         */
+    POWERPC_EXCP_HISI     = 70, /* Hypervisor instruction storage exception  */
+    POWERPC_EXCP_HDSEG    = 71, /* Hypervisor data segment exception         */
+    POWERPC_EXCP_HISEG    = 72, /* Hypervisor instruction segment exception  */
+    POWERPC_EXCP_VPU      = 73, /* Vector unavailable exception              */
+    /* 40x specific exceptions                                               */
+    POWERPC_EXCP_PIT      = 74, /* Programmable interval timer interrupt     */
+    /* 601 specific exceptions                                               */
+    POWERPC_EXCP_IO       = 75, /* IO error exception                        */
+    POWERPC_EXCP_RUNM     = 76, /* Run mode exception                        */
+    /* 602 specific exceptions                                               */
+    POWERPC_EXCP_EMUL     = 77, /* Emulation trap exception                  */
+    /* 602/603 specific exceptions                                           */
+    POWERPC_EXCP_IFTLB    = 78, /* Instruction fetch TLB miss                */
+    POWERPC_EXCP_DLTLB    = 79, /* Data load TLB miss                        */
+    POWERPC_EXCP_DSTLB    = 80, /* Data store TLB miss                       */
+    /* Exceptions available on most PowerPC                                  */
+    POWERPC_EXCP_FPA      = 81, /* Floating-point assist exception           */
+    POWERPC_EXCP_DABR     = 82, /* Data address breakpoint                   */
+    POWERPC_EXCP_IABR     = 83, /* Instruction address breakpoint            */
+    POWERPC_EXCP_SMI      = 84, /* System management interrupt               */
+    POWERPC_EXCP_PERFM    = 85, /* Embedded performance monitor interrupt    */
+    /* 7xx/74xx specific exceptions                                          */
+    POWERPC_EXCP_THERM    = 86, /* Thermal interrupt                         */
+    /* 74xx specific exceptions                                              */
+    POWERPC_EXCP_VPUA     = 87, /* Vector assist exception                   */
+    /* 970FX specific exceptions                                             */
+    POWERPC_EXCP_SOFTP    = 88, /* Soft patch exception                      */
+    POWERPC_EXCP_MAINT    = 89, /* Maintenance exception                     */
+    /* Freescale embedded cores specific exceptions                          */
+    POWERPC_EXCP_MEXTBR   = 90, /* Maskable external breakpoint              */
+    POWERPC_EXCP_NMEXTBR  = 91, /* Non maskable external breakpoint          */
+    POWERPC_EXCP_ITLBE    = 92, /* Instruction TLB error                     */
+    POWERPC_EXCP_DTLBE    = 93, /* Data TLB error                            */
+    /* EOL                                                                   */
+    POWERPC_EXCP_NB       = 96,
+    /* Qemu exceptions: used internally during code translation              */
+    POWERPC_EXCP_STOP         = 0x200, /* stop translation                   */
+    POWERPC_EXCP_BRANCH       = 0x201, /* branch instruction                 */
+    /* Qemu exceptions: special cases we want to stop translation            */
+    POWERPC_EXCP_SYNC         = 0x202, /* context synchronizing instruction  */
+    POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
+    POWERPC_EXCP_STCX         = 0x204 /* Conditional stores in user mode     */
+};
+
+/* Exceptions error codes                                                    */
+enum {
+    /* Exception subtypes for POWERPC_EXCP_ALIGN                             */
+    POWERPC_EXCP_ALIGN_FP      = 0x01,  /* FP alignment exception            */
+    POWERPC_EXCP_ALIGN_LST     = 0x02,  /* Unaligned mult/extern load/store  */
+    POWERPC_EXCP_ALIGN_LE      = 0x03,  /* Multiple little-endian access     */
+    POWERPC_EXCP_ALIGN_PROT    = 0x04,  /* Access cross protection boundary  */
+    POWERPC_EXCP_ALIGN_BAT     = 0x05,  /* Access cross a BAT/seg boundary   */
+    POWERPC_EXCP_ALIGN_CACHE   = 0x06,  /* Impossible dcbz access            */
+    /* Exception subtypes for POWERPC_EXCP_PROGRAM                           */
+    /* FP exceptions                                                         */
+    POWERPC_EXCP_FP            = 0x10,
+    POWERPC_EXCP_FP_OX         = 0x01,  /* FP overflow                       */
+    POWERPC_EXCP_FP_UX         = 0x02,  /* FP underflow                      */
+    POWERPC_EXCP_FP_ZX         = 0x03,  /* FP divide by zero                 */
+    POWERPC_EXCP_FP_XX         = 0x04,  /* FP inexact                        */
+    POWERPC_EXCP_FP_VXSNAN     = 0x05,  /* FP invalid SNaN op                */
+    POWERPC_EXCP_FP_VXISI      = 0x06,  /* FP invalid infinite subtraction   */
+    POWERPC_EXCP_FP_VXIDI      = 0x07,  /* FP invalid infinite divide        */
+    POWERPC_EXCP_FP_VXZDZ      = 0x08,  /* FP invalid zero divide            */
+    POWERPC_EXCP_FP_VXIMZ      = 0x09,  /* FP invalid infinite * zero        */
+    POWERPC_EXCP_FP_VXVC       = 0x0A,  /* FP invalid compare                */
+    POWERPC_EXCP_FP_VXSOFT     = 0x0B,  /* FP invalid operation              */
+    POWERPC_EXCP_FP_VXSQRT     = 0x0C,  /* FP invalid square root            */
+    POWERPC_EXCP_FP_VXCVI      = 0x0D,  /* FP invalid integer conversion     */
+    /* Invalid instruction                                                   */
+    POWERPC_EXCP_INVAL         = 0x20,
+    POWERPC_EXCP_INVAL_INVAL   = 0x01,  /* Invalid instruction               */
+    POWERPC_EXCP_INVAL_LSWX    = 0x02,  /* Invalid lswx instruction          */
+    POWERPC_EXCP_INVAL_SPR     = 0x03,  /* Invalid SPR access                */
+    POWERPC_EXCP_INVAL_FP      = 0x04,  /* Unimplemented mandatory fp instr  */
+    /* Privileged instruction                                                */
+    POWERPC_EXCP_PRIV          = 0x30,
+    POWERPC_EXCP_PRIV_OPC      = 0x01,  /* Privileged operation exception    */
+    POWERPC_EXCP_PRIV_REG      = 0x02,  /* Privileged register exception     */
+    /* Trap                                                                  */
+    POWERPC_EXCP_TRAP          = 0x40,
+};
+
+/*****************************************************************************/
+/* Input pins model                                                          */
+typedef enum powerpc_input_t powerpc_input_t;
+enum powerpc_input_t {
+    PPC_FLAGS_INPUT_UNKNOWN = 0,
+    /* PowerPC 6xx bus                  */
+    PPC_FLAGS_INPUT_6xx,
+    /* BookE bus                        */
+    PPC_FLAGS_INPUT_BookE,
+    /* PowerPC 405 bus                  */
+    PPC_FLAGS_INPUT_405,
+    /* PowerPC 970 bus                  */
+    PPC_FLAGS_INPUT_970,
+    /* PowerPC POWER7 bus               */
+    PPC_FLAGS_INPUT_POWER7,
+    /* PowerPC 401 bus                  */
+    PPC_FLAGS_INPUT_401,
+    /* Freescale RCPU bus               */
+    PPC_FLAGS_INPUT_RCPU,
+};
+
+#define PPC_INPUT(env) (env->bus_model)
+
+/*****************************************************************************/
+typedef struct ppc_def_t ppc_def_t;
+typedef struct opc_handler_t opc_handler_t;
+
+/*****************************************************************************/
+/* Types used to describe some PowerPC registers */
+typedef struct CPUPPCState CPUPPCState;
+typedef struct ppc_tb_t ppc_tb_t;
+typedef struct ppc_spr_t ppc_spr_t;
+typedef struct ppc_dcr_t ppc_dcr_t;
+typedef union ppc_avr_t ppc_avr_t;
+typedef union ppc_tlb_t ppc_tlb_t;
+
+/* SPR access micro-ops generations callbacks */
+struct ppc_spr_t {
+    void (*uea_read)(void *opaque, int gpr_num, int spr_num);
+    void (*uea_write)(void *opaque, int spr_num, int gpr_num);
+#if !defined(CONFIG_USER_ONLY)
+    void (*oea_read)(void *opaque, int gpr_num, int spr_num);
+    void (*oea_write)(void *opaque, int spr_num, int gpr_num);
+    void (*hea_read)(void *opaque, int gpr_num, int spr_num);
+    void (*hea_write)(void *opaque, int spr_num, int gpr_num);
+#endif
+    const char *name;
+};
+
+/* Altivec registers (128 bits) */
+union ppc_avr_t {
+    float32 f[4];
+    uint8_t u8[16];
+    uint16_t u16[8];
+    uint32_t u32[4];
+    int8_t s8[16];
+    int16_t s16[8];
+    int32_t s32[4];
+    uint64_t u64[2];
+};
+
+#if !defined(CONFIG_USER_ONLY)
+/* Software TLB cache */
+typedef struct ppc6xx_tlb_t ppc6xx_tlb_t;
+struct ppc6xx_tlb_t {
+    target_ulong pte0;
+    target_ulong pte1;
+    target_ulong EPN;
+};
+
+typedef struct ppcemb_tlb_t ppcemb_tlb_t;
+struct ppcemb_tlb_t {
+    target_phys_addr_t RPN;
+    target_ulong EPN;
+    target_ulong PID;
+    target_ulong size;
+    uint32_t prot;
+    uint32_t attr; /* Storage attributes */
+};
+
+typedef struct ppcmas_tlb_t {
+     uint32_t mas8;
+     uint32_t mas1;
+     uint64_t mas2;
+     uint64_t mas7_3;
+} ppcmas_tlb_t;
+
+union ppc_tlb_t {
+    ppc6xx_tlb_t *tlb6;
+    ppcemb_tlb_t *tlbe;
+    ppcmas_tlb_t *tlbm;
+};
+
+/* possible TLB variants */
+#define TLB_NONE               0
+#define TLB_6XX                1
+#define TLB_EMB                2
+#define TLB_MAS                3
+#endif
+
+#define SDR_32_HTABORG         0xFFFF0000UL
+#define SDR_32_HTABMASK        0x000001FFUL
+
+#if defined(TARGET_PPC64)
+#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
+#define SDR_64_HTABSIZE        0x000000000000001FULL
+#endif /* defined(TARGET_PPC64 */
+
+#define HASH_PTE_SIZE_32       8
+#define HASH_PTE_SIZE_64       16
+
+typedef struct ppc_slb_t ppc_slb_t;
+struct ppc_slb_t {
+    uint64_t esid;
+    uint64_t vsid;
+};
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_ESID           0xFFFFFFFFF0000000ULL
+#define SLB_ESID_V              0x0000000008000000ULL /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT          12
+#define SLB_VSID_SHIFT_1T       24
+#define SLB_VSID_SSIZE_SHIFT    62
+#define SLB_VSID_B              0xc000000000000000ULL
+#define SLB_VSID_B_256M         0x0000000000000000ULL
+#define SLB_VSID_B_1T           0x4000000000000000ULL
+#define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
+#define SLB_VSID_KS             0x0000000000000800ULL
+#define SLB_VSID_KP             0x0000000000000400ULL
+#define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
+#define SLB_VSID_L              0x0000000000000100ULL
+#define SLB_VSID_C              0x0000000000000080ULL /* class */
+#define SLB_VSID_LP             0x0000000000000030ULL
+#define SLB_VSID_ATTR           0x0000000000000FFFULL
+
+#define SEGMENT_SHIFT_256M      28
+#define SEGMENT_MASK_256M       (~((1ULL << SEGMENT_SHIFT_256M) - 1))
+
+#define SEGMENT_SHIFT_1T        40
+#define SEGMENT_MASK_1T         (~((1ULL << SEGMENT_SHIFT_1T) - 1))
+
+
+/*****************************************************************************/
+/* Machine state register bits definition                                    */
+#define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
+#define MSR_TAG  62 /* Tag-active mode (POWERx ?)                            */
+#define MSR_ISF  61 /* Sixty-four-bit interrupt mode on 630                  */
+#define MSR_SHV  60 /* hypervisor state                               hflags */
+#define MSR_CM   31 /* Computation mode for BookE                     hflags */
+#define MSR_ICM  30 /* Interrupt computation mode for BookE                  */
+#define MSR_THV  29 /* hypervisor state for 32 bits PowerPC           hflags */
+#define MSR_GS   28 /* guest state for BookE                                 */
+#define MSR_UCLE 26 /* User-mode cache lock enable for BookE                 */
+#define MSR_VR   25 /* altivec available                            x hflags */
+#define MSR_SPE  25 /* SPE enable for BookE                         x hflags */
+#define MSR_AP   23 /* Access privilege state on 602                  hflags */
+#define MSR_SA   22 /* Supervisor access mode on 602                  hflags */
+#define MSR_KEY  19 /* key bit on 603e                                       */
+#define MSR_POW  18 /* Power management                                      */
+#define MSR_TGPR 17 /* TGPR usage on 602/603                        x        */
+#define MSR_CE   17 /* Critical interrupt enable on embedded PowerPC x       */
+#define MSR_ILE  16 /* Interrupt little-endian mode                          */
+#define MSR_EE   15 /* External interrupt enable                             */
+#define MSR_PR   14 /* Problem state                                  hflags */
+#define MSR_FP   13 /* Floating point available                       hflags */
+#define MSR_ME   12 /* Machine check interrupt enable                        */
+#define MSR_FE0  11 /* Floating point exception mode 0                hflags */
+#define MSR_SE   10 /* Single-step trace enable                     x hflags */
+#define MSR_DWE  10 /* Debug wait enable on 405                     x        */
+#define MSR_UBLE 10 /* User BTB lock enable on e500                 x        */
+#define MSR_BE   9  /* Branch trace enable                          x hflags */
+#define MSR_DE   9  /* Debug interrupts enable on embedded PowerPC  x        */
+#define MSR_FE1  8  /* Floating point exception mode 1                hflags */
+#define MSR_AL   7  /* AL bit on POWER                                       */
+#define MSR_EP   6  /* Exception prefix on 601                               */
+#define MSR_IR   5  /* Instruction relocate                                  */
+#define MSR_DR   4  /* Data relocate                                         */
+#define MSR_PE   3  /* Protection enable on 403                              */
+#define MSR_PX   2  /* Protection exclusive on 403                  x        */
+#define MSR_PMM  2  /* Performance monitor mark on POWER            x        */
+#define MSR_RI   1  /* Recoverable interrupt                        1        */
+#define MSR_LE   0  /* Little-endian mode                           1 hflags */
+
+#define msr_sf   ((env->msr >> MSR_SF)   & 1)
+#define msr_isf  ((env->msr >> MSR_ISF)  & 1)
+#define msr_shv  ((env->msr >> MSR_SHV)  & 1)
+#define msr_cm   ((env->msr >> MSR_CM)   & 1)
+#define msr_icm  ((env->msr >> MSR_ICM)  & 1)
+#define msr_thv  ((env->msr >> MSR_THV)  & 1)
+#define msr_gs   ((env->msr >> MSR_GS)   & 1)
+#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
+#define msr_vr   ((env->msr >> MSR_VR)   & 1)
+#define msr_spe  ((env->msr >> MSR_SPE)  & 1)
+#define msr_ap   ((env->msr >> MSR_AP)   & 1)
+#define msr_sa   ((env->msr >> MSR_SA)   & 1)
+#define msr_key  ((env->msr >> MSR_KEY)  & 1)
+#define msr_pow  ((env->msr >> MSR_POW)  & 1)
+#define msr_tgpr ((env->msr >> MSR_TGPR) & 1)
+#define msr_ce   ((env->msr >> MSR_CE)   & 1)
+#define msr_ile  ((env->msr >> MSR_ILE)  & 1)
+#define msr_ee   ((env->msr >> MSR_EE)   & 1)
+#define msr_pr   ((env->msr >> MSR_PR)   & 1)
+#define msr_fp   ((env->msr >> MSR_FP)   & 1)
+#define msr_me   ((env->msr >> MSR_ME)   & 1)
+#define msr_fe0  ((env->msr >> MSR_FE0)  & 1)
+#define msr_se   ((env->msr >> MSR_SE)   & 1)
+#define msr_dwe  ((env->msr >> MSR_DWE)  & 1)
+#define msr_uble ((env->msr >> MSR_UBLE) & 1)
+#define msr_be   ((env->msr >> MSR_BE)   & 1)
+#define msr_de   ((env->msr >> MSR_DE)   & 1)
+#define msr_fe1  ((env->msr >> MSR_FE1)  & 1)
+#define msr_al   ((env->msr >> MSR_AL)   & 1)
+#define msr_ep   ((env->msr >> MSR_EP)   & 1)
+#define msr_ir   ((env->msr >> MSR_IR)   & 1)
+#define msr_dr   ((env->msr >> MSR_DR)   & 1)
+#define msr_pe   ((env->msr >> MSR_PE)   & 1)
+#define msr_px   ((env->msr >> MSR_PX)   & 1)
+#define msr_pmm  ((env->msr >> MSR_PMM)  & 1)
+#define msr_ri   ((env->msr >> MSR_RI)   & 1)
+#define msr_le   ((env->msr >> MSR_LE)   & 1)
+/* Hypervisor bit is more specific */
+#if defined(TARGET_PPC64)
+#define MSR_HVB (1ULL << MSR_SHV)
+#define msr_hv  msr_shv
+#else
+#if defined(PPC_EMULATE_32BITS_HYPV)
+#define MSR_HVB (1ULL << MSR_THV)
+#define msr_hv  msr_thv
+#else
+#define MSR_HVB (0ULL)
+#define msr_hv  (0)
+#endif
+#endif
+
+/* Exception state register bits definition                                  */
+#define ESR_ST    23    /* Exception was caused by a store type access.      */
+
+enum {
+    POWERPC_FLAG_NONE     = 0x00000000,
+    /* Flag for MSR bit 25 signification (VRE/SPE)                           */
+    POWERPC_FLAG_SPE      = 0x00000001,
+    POWERPC_FLAG_VRE      = 0x00000002,
+    /* Flag for MSR bit 17 signification (TGPR/CE)                           */
+    POWERPC_FLAG_TGPR     = 0x00000004,
+    POWERPC_FLAG_CE       = 0x00000008,
+    /* Flag for MSR bit 10 signification (SE/DWE/UBLE)                       */
+    POWERPC_FLAG_SE       = 0x00000010,
+    POWERPC_FLAG_DWE      = 0x00000020,
+    POWERPC_FLAG_UBLE     = 0x00000040,
+    /* Flag for MSR bit 9 signification (BE/DE)                              */
+    POWERPC_FLAG_BE       = 0x00000080,
+    POWERPC_FLAG_DE       = 0x00000100,
+    /* Flag for MSR bit 2 signification (PX/PMM)                             */
+    POWERPC_FLAG_PX       = 0x00000200,
+    POWERPC_FLAG_PMM      = 0x00000400,
+    /* Flag for special features                                             */
+    /* Decrementer clock: RTC clock (POWER, 601) or bus clock                */
+    POWERPC_FLAG_RTC_CLK  = 0x00010000,
+    POWERPC_FLAG_BUS_CLK  = 0x00020000,
+};
+
+/*****************************************************************************/
+/* Floating point status and control register                                */
+#define FPSCR_FX     31 /* Floating-point exception summary                  */
+#define FPSCR_FEX    30 /* Floating-point enabled exception summary          */
+#define FPSCR_VX     29 /* Floating-point invalid operation exception summ.  */
+#define FPSCR_OX     28 /* Floating-point overflow exception                 */
+#define FPSCR_UX     27 /* Floating-point underflow exception                */
+#define FPSCR_ZX     26 /* Floating-point zero divide exception              */
+#define FPSCR_XX     25 /* Floating-point inexact exception                  */
+#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */
+#define FPSCR_VXISI  23 /* Floating-point invalid operation exception (inf)  */
+#define FPSCR_VXIDI  22 /* Floating-point invalid operation exception (inf)  */
+#define FPSCR_VXZDZ  21 /* Floating-point invalid operation exception (zero) */
+#define FPSCR_VXIMZ  20 /* Floating-point invalid operation exception (inf)  */
+#define FPSCR_VXVC   19 /* Floating-point invalid operation exception (comp) */
+#define FPSCR_FR     18 /* Floating-point fraction rounded                   */
+#define FPSCR_FI     17 /* Floating-point fraction inexact                   */
+#define FPSCR_C      16 /* Floating-point result class descriptor            */
+#define FPSCR_FL     15 /* Floating-point less than or negative              */
+#define FPSCR_FG     14 /* Floating-point greater than or negative           */
+#define FPSCR_FE     13 /* Floating-point equal or zero                      */
+#define FPSCR_FU     12 /* Floating-point unordered or NaN                   */
+#define FPSCR_FPCC   12 /* Floating-point condition code                     */
+#define FPSCR_FPRF   12 /* Floating-point result flags                       */
+#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
+#define FPSCR_VXSQRT 9  /* Floating-point invalid operation exception (sqrt) */
+#define FPSCR_VXCVI  8  /* Floating-point invalid operation exception (int)  */
+#define FPSCR_VE     7  /* Floating-point invalid operation exception enable */
+#define FPSCR_OE     6  /* Floating-point overflow exception enable          */
+#define FPSCR_UE     5  /* Floating-point undeflow exception enable          */
+#define FPSCR_ZE     4  /* Floating-point zero divide exception enable       */
+#define FPSCR_XE     3  /* Floating-point inexact exception enable           */
+#define FPSCR_NI     2  /* Floating-point non-IEEE mode                      */
+#define FPSCR_RN1    1
+#define FPSCR_RN     0  /* Floating-point rounding control                   */
+#define fpscr_fex    (((env->fpscr) >> FPSCR_FEX)    & 0x1)
+#define fpscr_vx     (((env->fpscr) >> FPSCR_VX)     & 0x1)
+#define fpscr_ox     (((env->fpscr) >> FPSCR_OX)     & 0x1)
+#define fpscr_ux     (((env->fpscr) >> FPSCR_UX)     & 0x1)
+#define fpscr_zx     (((env->fpscr) >> FPSCR_ZX)     & 0x1)
+#define fpscr_xx     (((env->fpscr) >> FPSCR_XX)     & 0x1)
+#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1)
+#define fpscr_vxisi  (((env->fpscr) >> FPSCR_VXISI)  & 0x1)
+#define fpscr_vxidi  (((env->fpscr) >> FPSCR_VXIDI)  & 0x1)
+#define fpscr_vxzdz  (((env->fpscr) >> FPSCR_VXZDZ)  & 0x1)
+#define fpscr_vximz  (((env->fpscr) >> FPSCR_VXIMZ)  & 0x1)
+#define fpscr_vxvc   (((env->fpscr) >> FPSCR_VXVC)   & 0x1)
+#define fpscr_fpcc   (((env->fpscr) >> FPSCR_FPCC)   & 0xF)
+#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1)
+#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1)
+#define fpscr_vxcvi  (((env->fpscr) >> FPSCR_VXCVI)  & 0x1)
+#define fpscr_ve     (((env->fpscr) >> FPSCR_VE)     & 0x1)
+#define fpscr_oe     (((env->fpscr) >> FPSCR_OE)     & 0x1)
+#define fpscr_ue     (((env->fpscr) >> FPSCR_UE)     & 0x1)
+#define fpscr_ze     (((env->fpscr) >> FPSCR_ZE)     & 0x1)
+#define fpscr_xe     (((env->fpscr) >> FPSCR_XE)     & 0x1)
+#define fpscr_ni     (((env->fpscr) >> FPSCR_NI)     & 0x1)
+#define fpscr_rn     (((env->fpscr) >> FPSCR_RN)     & 0x3)
+/* Invalid operation exception summary */
+#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI)  | \
+                                  (1 << FPSCR_VXIDI)  | (1 << FPSCR_VXZDZ)  | \
+                                  (1 << FPSCR_VXIMZ)  | (1 << FPSCR_VXVC)   | \
+                                  (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \
+                                  (1 << FPSCR_VXCVI)))
+/* exception summary */
+#define fpscr_ex  (((env->fpscr) >> FPSCR_XX) & 0x1F)
+/* enabled exception summary */
+#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) &  \
+                   0x1F)
+
+/*****************************************************************************/
+/* Vector status and control register */
+#define VSCR_NJ		16 /* Vector non-java */
+#define VSCR_SAT	0 /* Vector saturation */
+#define vscr_nj		(((env->vscr) >> VSCR_NJ)	& 0x1)
+#define vscr_sat	(((env->vscr) >> VSCR_SAT)	& 0x1)
+
+/*****************************************************************************/
+/* BookE e500 MMU registers */
+
+#define MAS0_NV_SHIFT      0
+#define MAS0_NV_MASK       (0xfff << MAS0_NV_SHIFT)
+
+#define MAS0_WQ_SHIFT      12
+#define MAS0_WQ_MASK       (3 << MAS0_WQ_SHIFT)
+/* Write TLB entry regardless of reservation */
+#define MAS0_WQ_ALWAYS     (0 << MAS0_WQ_SHIFT)
+/* Write TLB entry only already in use */
+#define MAS0_WQ_COND       (1 << MAS0_WQ_SHIFT)
+/* Clear TLB entry */
+#define MAS0_WQ_CLR_RSRV   (2 << MAS0_WQ_SHIFT)
+
+#define MAS0_HES_SHIFT     14
+#define MAS0_HES           (1 << MAS0_HES_SHIFT)
+
+#define MAS0_ESEL_SHIFT    16
+#define MAS0_ESEL_MASK     (0xfff << MAS0_ESEL_SHIFT)
+
+#define MAS0_TLBSEL_SHIFT  28
+#define MAS0_TLBSEL_MASK   (3 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB0   (0 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB1   (1 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB2   (2 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB3   (3 << MAS0_TLBSEL_SHIFT)
+
+#define MAS0_ATSEL_SHIFT   31
+#define MAS0_ATSEL         (1 << MAS0_ATSEL_SHIFT)
+#define MAS0_ATSEL_TLB     0
+#define MAS0_ATSEL_LRAT    MAS0_ATSEL
+
+#define MAS1_TSIZE_SHIFT   8
+#define MAS1_TSIZE_MASK    (0xf << MAS1_TSIZE_SHIFT)
+
+#define MAS1_TS_SHIFT      12
+#define MAS1_TS            (1 << MAS1_TS_SHIFT)
+
+#define MAS1_IND_SHIFT     13
+#define MAS1_IND           (1 << MAS1_IND_SHIFT)
+
+#define MAS1_TID_SHIFT     16
+#define MAS1_TID_MASK      (0x3fff << MAS1_TID_SHIFT)
+
+#define MAS1_IPROT_SHIFT   30
+#define MAS1_IPROT         (1 << MAS1_IPROT_SHIFT)
+
+#define MAS1_VALID_SHIFT   31
+#define MAS1_VALID         0x80000000
+
+#define MAS2_EPN_SHIFT     12
+#define MAS2_EPN_MASK      (0xfffff << MAS2_EPN_SHIFT)
+
+#define MAS2_ACM_SHIFT     6
+#define MAS2_ACM           (1 << MAS2_ACM_SHIFT)
+
+#define MAS2_VLE_SHIFT     5
+#define MAS2_VLE           (1 << MAS2_VLE_SHIFT)
+
+#define MAS2_W_SHIFT       4
+#define MAS2_W             (1 << MAS2_W_SHIFT)
+
+#define MAS2_I_SHIFT       3
+#define MAS2_I             (1 << MAS2_I_SHIFT)
+
+#define MAS2_M_SHIFT       2
+#define MAS2_M             (1 << MAS2_M_SHIFT)
+
+#define MAS2_G_SHIFT       1
+#define MAS2_G             (1 << MAS2_G_SHIFT)
+
+#define MAS2_E_SHIFT       0
+#define MAS2_E             (1 << MAS2_E_SHIFT)
+
+#define MAS3_RPN_SHIFT     12
+#define MAS3_RPN_MASK      (0xfffff << MAS3_RPN_SHIFT)
+
+#define MAS3_U0                 0x00000200
+#define MAS3_U1                 0x00000100
+#define MAS3_U2                 0x00000080
+#define MAS3_U3                 0x00000040
+#define MAS3_UX                 0x00000020
+#define MAS3_SX                 0x00000010
+#define MAS3_UW                 0x00000008
+#define MAS3_SW                 0x00000004
+#define MAS3_UR                 0x00000002
+#define MAS3_SR                 0x00000001
+#define MAS3_SPSIZE_SHIFT       1
+#define MAS3_SPSIZE_MASK        (0x3e << MAS3_SPSIZE_SHIFT)
+
+#define MAS4_TLBSELD_SHIFT      MAS0_TLBSEL_SHIFT
+#define MAS4_TLBSELD_MASK       MAS0_TLBSEL_MASK
+#define MAS4_TIDSELD_MASK       0x00030000
+#define MAS4_TIDSELD_PID0       0x00000000
+#define MAS4_TIDSELD_PID1       0x00010000
+#define MAS4_TIDSELD_PID2       0x00020000
+#define MAS4_TIDSELD_PIDZ       0x00030000
+#define MAS4_INDD               0x00008000      /* Default IND */
+#define MAS4_TSIZED_SHIFT       MAS1_TSIZE_SHIFT
+#define MAS4_TSIZED_MASK        MAS1_TSIZE_MASK
+#define MAS4_ACMD               0x00000040
+#define MAS4_VLED               0x00000020
+#define MAS4_WD                 0x00000010
+#define MAS4_ID                 0x00000008
+#define MAS4_MD                 0x00000004
+#define MAS4_GD                 0x00000002
+#define MAS4_ED                 0x00000001
+#define MAS4_WIMGED_MASK        0x0000001f      /* Default WIMGE */
+#define MAS4_WIMGED_SHIFT       0
+
+#define MAS5_SGS                0x80000000
+#define MAS5_SLPID_MASK         0x00000fff
+
+#define MAS6_SPID0              0x3fff0000
+#define MAS6_SPID1              0x00007ffe
+#define MAS6_ISIZE(x)           MAS1_TSIZE(x)
+#define MAS6_SAS                0x00000001
+#define MAS6_SPID               MAS6_SPID0
+#define MAS6_SIND               0x00000002      /* Indirect page */
+#define MAS6_SIND_SHIFT         1
+#define MAS6_SPID_MASK          0x3fff0000
+#define MAS6_SPID_SHIFT         16
+#define MAS6_ISIZE_MASK         0x00000f80
+#define MAS6_ISIZE_SHIFT        7
+
+#define MAS7_RPN                0xffffffff
+
+#define MAS8_TGS                0x80000000
+#define MAS8_VF                 0x40000000
+#define MAS8_TLBPID             0x00000fff
+
+/* Bit definitions for MMUCFG */
+#define MMUCFG_MAVN     0x00000003      /* MMU Architecture Version Number */
+#define MMUCFG_MAVN_V1  0x00000000      /* v1.0 */
+#define MMUCFG_MAVN_V2  0x00000001      /* v2.0 */
+#define MMUCFG_NTLBS    0x0000000c      /* Number of TLBs */
+#define MMUCFG_PIDSIZE  0x000007c0      /* PID Reg Size */
+#define MMUCFG_TWC      0x00008000      /* TLB Write Conditional (v2.0) */
+#define MMUCFG_LRAT     0x00010000      /* LRAT Supported (v2.0) */
+#define MMUCFG_RASIZE   0x00fe0000      /* Real Addr Size */
+#define MMUCFG_LPIDSIZE 0x0f000000      /* LPID Reg Size */
+
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI  0x00000002      /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI  0x00000004      /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI  0x00000040      /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI  0x00000020      /* TLB3 Flash invalidate */
+#define MMUCSR0_TLBFI   (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+                         MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+#define MMUCSR0_TLB0PS  0x00000780      /* TLB0 Page Size */
+#define MMUCSR0_TLB1PS  0x00007800      /* TLB1 Page Size */
+#define MMUCSR0_TLB2PS  0x00078000      /* TLB2 Page Size */
+#define MMUCSR0_TLB3PS  0x00780000      /* TLB3 Page Size */
+
+/* TLBnCFG encoding */
+#define TLBnCFG_N_ENTRY         0x00000fff      /* number of entries */
+#define TLBnCFG_HES             0x00002000      /* HW select supported */
+#define TLBnCFG_AVAIL           0x00004000      /* variable page size */
+#define TLBnCFG_IPROT           0x00008000      /* IPROT supported */
+#define TLBnCFG_GTWE            0x00010000      /* Guest can write */
+#define TLBnCFG_IND             0x00020000      /* IND entries supported */
+#define TLBnCFG_PT              0x00040000      /* Can load from page table */
+#define TLBnCFG_MINSIZE         0x00f00000      /* Minimum Page Size (v1.0) */
+#define TLBnCFG_MINSIZE_SHIFT   20
+#define TLBnCFG_MAXSIZE         0x000f0000      /* Maximum Page Size (v1.0) */
+#define TLBnCFG_MAXSIZE_SHIFT   16
+#define TLBnCFG_ASSOC           0xff000000      /* Associativity */
+#define TLBnCFG_ASSOC_SHIFT     24
+
+/* TLBnPS encoding */
+#define TLBnPS_4K               0x00000004
+#define TLBnPS_8K               0x00000008
+#define TLBnPS_16K              0x00000010
+#define TLBnPS_32K              0x00000020
+#define TLBnPS_64K              0x00000040
+#define TLBnPS_128K             0x00000080
+#define TLBnPS_256K             0x00000100
+#define TLBnPS_512K             0x00000200
+#define TLBnPS_1M               0x00000400
+#define TLBnPS_2M               0x00000800
+#define TLBnPS_4M               0x00001000
+#define TLBnPS_8M               0x00002000
+#define TLBnPS_16M              0x00004000
+#define TLBnPS_32M              0x00008000
+#define TLBnPS_64M              0x00010000
+#define TLBnPS_128M             0x00020000
+#define TLBnPS_256M             0x00040000
+#define TLBnPS_512M             0x00080000
+#define TLBnPS_1G               0x00100000
+#define TLBnPS_2G               0x00200000
+#define TLBnPS_4G               0x00400000
+#define TLBnPS_8G               0x00800000
+#define TLBnPS_16G              0x01000000
+#define TLBnPS_32G              0x02000000
+#define TLBnPS_64G              0x04000000
+#define TLBnPS_128G             0x08000000
+#define TLBnPS_256G             0x10000000
+
+/* tlbilx action encoding */
+#define TLBILX_T_ALL                    0
+#define TLBILX_T_TID                    1
+#define TLBILX_T_FULLMATCH              3
+#define TLBILX_T_CLASS0                 4
+#define TLBILX_T_CLASS1                 5
+#define TLBILX_T_CLASS2                 6
+#define TLBILX_T_CLASS3                 7
+
+/* BookE 2.06 helper defines */
+
+#define BOOKE206_FLUSH_TLB0    (1 << 0)
+#define BOOKE206_FLUSH_TLB1    (1 << 1)
+#define BOOKE206_FLUSH_TLB2    (1 << 2)
+#define BOOKE206_FLUSH_TLB3    (1 << 3)
+
+/* number of possible TLBs */
+#define BOOKE206_MAX_TLBN      4
+
+/*****************************************************************************/
+/* The whole PowerPC CPU context */
+#define NB_MMU_MODES 3
+
+struct CPUPPCState {
+    /* First are the most commonly used resources
+     * during translated code execution
+     */
+    /* general purpose registers */
+    target_ulong gpr[32];
+#if !defined(TARGET_PPC64)
+    /* Storage for GPR MSB, used by the SPE extension */
+    target_ulong gprh[32];
+#endif
+    /* LR */
+    target_ulong lr;
+    /* CTR */
+    target_ulong ctr;
+    /* condition register */
+    uint32_t crf[8];
+    /* XER */
+    target_ulong xer;
+    /* Reservation address */
+    target_ulong reserve_addr;
+    /* Reservation value */
+    target_ulong reserve_val;
+    /* Reservation store address */
+    target_ulong reserve_ea;
+    /* Reserved store source register and size */
+    target_ulong reserve_info;
+
+    /* Those ones are used in supervisor mode only */
+    /* machine state register */
+    target_ulong msr;
+    /* temporary general purpose registers */
+    target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+
+    /* Floating point execution context */
+    float_status fp_status;
+    /* floating point registers */
+    float64 fpr[32];
+    /* floating point status and control register */
+    uint32_t fpscr;
+
+    /* Next instruction pointer */
+    target_ulong nip;
+
+    int access_type; /* when a memory exception occurs, the access
+                        type is stored here */
+
+    CPU_COMMON
+
+    /* MMU context - only relevant for full system emulation */
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+    /* Address space register */
+    target_ulong asr;
+    /* PowerPC 64 SLB area */
+    ppc_slb_t slb[64];
+    int slb_nr;
+#endif
+    /* segment registers */
+    target_phys_addr_t htab_base;
+    target_phys_addr_t htab_mask;
+    target_ulong sr[32];
+    /* externally stored hash table */
+    uint8_t *external_htab;
+    /* BATs */
+    int nb_BATs;
+    target_ulong DBAT[2][8];
+    target_ulong IBAT[2][8];
+    /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
+    int nb_tlb;      /* Total number of TLB                                  */
+    int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
+    int nb_ways;     /* Number of ways in the TLB set                        */
+    int last_way;    /* Last used way used to allocate TLB in a LRU way      */
+    int id_tlbs;     /* If 1, MMU has separated TLBs for instructions & data */
+    int nb_pids;     /* Number of available PID registers                    */
+    int tlb_type;    /* Type of TLB we're dealing with                       */
+    ppc_tlb_t tlb;   /* TLB is optional. Allocate them only if needed        */
+    /* 403 dedicated access protection registers */
+    target_ulong pb[4];
+#endif
+
+    /* Other registers */
+    /* Special purpose registers */
+    target_ulong spr[1024];
+    ppc_spr_t spr_cb[1024];
+    /* Altivec registers */
+    ppc_avr_t avr[32];
+    uint32_t vscr;
+    /* SPE registers */
+    uint64_t spe_acc;
+    uint32_t spe_fscr;
+    /* SPE and Altivec can share a status since they will never be used
+     * simultaneously */
+    float_status vec_status;
+
+    /* Internal devices resources */
+    /* Time base and decrementer */
+    ppc_tb_t *tb_env;
+    /* Device control registers */
+    ppc_dcr_t *dcr_env;
+
+    int dcache_line_size;
+    int icache_line_size;
+
+    /* Those resources are used during exception processing */
+    /* CPU model definition */
+    target_ulong msr_mask;
+    powerpc_mmu_t mmu_model;
+    powerpc_excp_t excp_model;
+    powerpc_input_t bus_model;
+    int bfd_mach;
+    uint32_t flags;
+    uint64_t insns_flags;
+    uint64_t insns_flags2;
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+    target_phys_addr_t vpa;
+    target_phys_addr_t slb_shadow;
+    target_phys_addr_t dispatch_trace_log;
+    uint32_t dtl_size;
+#endif /* TARGET_PPC64 */
+
+    int error_code;
+    uint32_t pending_interrupts;
+#if !defined(CONFIG_USER_ONLY)
+    /* This is the IRQ controller, which is implementation dependant
+     * and only relevant when emulating a complete machine.
+     */
+    uint32_t irq_input_state;
+    void **irq_inputs;
+    /* Exception vectors */
+    target_ulong excp_vectors[POWERPC_EXCP_NB];
+    target_ulong excp_prefix;
+    target_ulong hreset_excp_prefix;
+    target_ulong ivor_mask;
+    target_ulong ivpr_mask;
+    target_ulong hreset_vector;
+#endif
+
+    /* Those resources are used only during code translation */
+    /* opcode handlers */
+    opc_handler_t *opcodes[0x40];
+
+    /* Those resources are used only in Qemu core */
+    target_ulong hflags;      /* hflags is a MSR & HFLAGS_MASK         */
+    target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */
+    int mmu_idx;         /* precomputed MMU index to speed up mem accesses */
+
+    /* Power management */
+    int power_mode;
+    int (*check_pow)(CPUPPCState *env);
+
+#if !defined(CONFIG_USER_ONLY)
+    void *load_info;    /* Holds boot loading state.  */
+#endif
+};
+
+#if !defined(CONFIG_USER_ONLY)
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+    target_phys_addr_t raddr;      /* Real address              */
+    target_phys_addr_t eaddr;      /* Effective address         */
+    int prot;                      /* Protection bits           */
+    target_phys_addr_t hash[2];    /* Pagetable hash values     */
+    target_ulong ptem;             /* Virtual segment ID | API  */
+    int key;                       /* Access key                */
+    int nx;                        /* Non-execute area          */
+};
+#endif
+
+/*****************************************************************************/
+CPUPPCState *cpu_ppc_init (const char *cpu_model);
+void ppc_translate_init(void);
+int cpu_ppc_exec (CPUPPCState *s);
+void cpu_ppc_close (CPUPPCState *s);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_ppc_signal_handler (int host_signum, void *pinfo,
+                            void *puc);
+int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
+#if !defined(CONFIG_USER_ONLY)
+int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong vaddr,
+                          int rw, int access_type);
+#endif
+void do_interrupt (CPUPPCState *env);
+void ppc_hw_interrupt (CPUPPCState *env);
+
+void cpu_dump_rfi (target_ulong RA, target_ulong msr);
+
+#if !defined(CONFIG_USER_ONLY)
+void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1);
+void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value);
+void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
+#if defined(TARGET_PPC64)
+void ppc_store_asr (CPUPPCState *env, target_ulong value);
+target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
+target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr);
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
+#endif /* defined(TARGET_PPC64) */
+void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
+#endif /* !defined(CONFIG_USER_ONLY) */
+void ppc_store_msr (CPUPPCState *env, target_ulong value);
+
+void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
+
+const ppc_def_t *cpu_ppc_find_by_name (const char *name);
+int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
+
+/* Time-base and decrementer management */
+#ifndef NO_CPU_IO_DEFS
+uint64_t cpu_ppc_load_tbl (CPUPPCState *env);
+uint32_t cpu_ppc_load_tbu (CPUPPCState *env);
+void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value);
+void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value);
+uint64_t cpu_ppc_load_atbl (CPUPPCState *env);
+uint32_t cpu_ppc_load_atbu (CPUPPCState *env);
+void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value);
+void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value);
+uint32_t cpu_ppc_load_decr (CPUPPCState *env);
+void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
+uint32_t cpu_ppc_load_hdecr (CPUPPCState *env);
+void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value);
+uint64_t cpu_ppc_load_purr (CPUPPCState *env);
+void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value);
+uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env);
+uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env);
+#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value);
+void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
+target_ulong load_40x_pit (CPUPPCState *env);
+void store_40x_pit (CPUPPCState *env, target_ulong val);
+void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
+void store_40x_sler (CPUPPCState *env, uint32_t val);
+void store_booke_tcr (CPUPPCState *env, target_ulong val);
+void store_booke_tsr (CPUPPCState *env, target_ulong val);
+void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot);
+target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb);
+int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
+                     target_phys_addr_t *raddrp, target_ulong address,
+                     uint32_t pid, int ext, int i);
+int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                     target_phys_addr_t *raddrp, target_ulong address,
+                     uint32_t pid);
+void ppc_tlb_invalidate_all (CPUPPCState *env);
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
+#if defined(TARGET_PPC64)
+void ppc_slb_invalidate_all (CPUPPCState *env);
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0);
+#endif
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid);
+#endif
+#endif
+
+static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
+{
+    uint64_t gprv;
+
+    gprv = env->gpr[gprn];
+#if !defined(TARGET_PPC64)
+    if (env->flags & POWERPC_FLAG_SPE) {
+        /* If the CPU implements the SPE extension, we have to get the
+         * high bits of the GPR from the gprh storage area
+         */
+        gprv &= 0xFFFFFFFFULL;
+        gprv |= (uint64_t)env->gprh[gprn] << 32;
+    }
+#endif
+
+    return gprv;
+}
+
+/* Device control registers */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
+
+#define cpu_init cpu_ppc_init
+#define cpu_exec cpu_ppc_exec
+#define cpu_gen_code cpu_ppc_gen_code
+#define cpu_signal_handler cpu_ppc_signal_handler
+#define cpu_list ppc_cpu_list
+
+#define CPU_SAVE_VERSION 4
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _user
+#define MMU_MODE1_SUFFIX _kernel
+#define MMU_MODE2_SUFFIX _hypv
+#define MMU_USER_IDX 0
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return env->mmu_idx;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->gpr[1] = newsp;
+    env->gpr[3] = 0;
+}
+#endif
+
+#include "cpu-all.h"
+
+/*****************************************************************************/
+/* CRF definitions */
+#define CRF_LT        3
+#define CRF_GT        2
+#define CRF_EQ        1
+#define CRF_SO        0
+#define CRF_CH        (1 << CRF_LT)
+#define CRF_CL        (1 << CRF_GT)
+#define CRF_CH_OR_CL  (1 << CRF_EQ)
+#define CRF_CH_AND_CL (1 << CRF_SO)
+
+/* XER definitions */
+#define XER_SO  31
+#define XER_OV  30
+#define XER_CA  29
+#define XER_CMP  8
+#define XER_BC   0
+#define xer_so  ((env->xer >> XER_SO)  &    1)
+#define xer_ov  ((env->xer >> XER_OV)  &    1)
+#define xer_ca  ((env->xer >> XER_CA)  &    1)
+#define xer_cmp ((env->xer >> XER_CMP) & 0xFF)
+#define xer_bc  ((env->xer >> XER_BC)  & 0x7F)
+
+/* SPR definitions */
+#define SPR_MQ                (0x000)
+#define SPR_XER               (0x001)
+#define SPR_601_VRTCU         (0x004)
+#define SPR_601_VRTCL         (0x005)
+#define SPR_601_UDECR         (0x006)
+#define SPR_LR                (0x008)
+#define SPR_CTR               (0x009)
+#define SPR_DSISR             (0x012)
+#define SPR_DAR               (0x013) /* DAE for PowerPC 601 */
+#define SPR_601_RTCU          (0x014)
+#define SPR_601_RTCL          (0x015)
+#define SPR_DECR              (0x016)
+#define SPR_SDR1              (0x019)
+#define SPR_SRR0              (0x01A)
+#define SPR_SRR1              (0x01B)
+#define SPR_AMR               (0x01D)
+#define SPR_BOOKE_PID         (0x030)
+#define SPR_BOOKE_DECAR       (0x036)
+#define SPR_BOOKE_CSRR0       (0x03A)
+#define SPR_BOOKE_CSRR1       (0x03B)
+#define SPR_BOOKE_DEAR        (0x03D)
+#define SPR_BOOKE_ESR         (0x03E)
+#define SPR_BOOKE_IVPR        (0x03F)
+#define SPR_MPC_EIE           (0x050)
+#define SPR_MPC_EID           (0x051)
+#define SPR_MPC_NRI           (0x052)
+#define SPR_CTRL              (0x088)
+#define SPR_MPC_CMPA          (0x090)
+#define SPR_MPC_CMPB          (0x091)
+#define SPR_MPC_CMPC          (0x092)
+#define SPR_MPC_CMPD          (0x093)
+#define SPR_MPC_ECR           (0x094)
+#define SPR_MPC_DER           (0x095)
+#define SPR_MPC_COUNTA        (0x096)
+#define SPR_MPC_COUNTB        (0x097)
+#define SPR_UCTRL             (0x098)
+#define SPR_MPC_CMPE          (0x098)
+#define SPR_MPC_CMPF          (0x099)
+#define SPR_MPC_CMPG          (0x09A)
+#define SPR_MPC_CMPH          (0x09B)
+#define SPR_MPC_LCTRL1        (0x09C)
+#define SPR_MPC_LCTRL2        (0x09D)
+#define SPR_MPC_ICTRL         (0x09E)
+#define SPR_MPC_BAR           (0x09F)
+#define SPR_VRSAVE            (0x100)
+#define SPR_USPRG0            (0x100)
+#define SPR_USPRG1            (0x101)
+#define SPR_USPRG2            (0x102)
+#define SPR_USPRG3            (0x103)
+#define SPR_USPRG4            (0x104)
+#define SPR_USPRG5            (0x105)
+#define SPR_USPRG6            (0x106)
+#define SPR_USPRG7            (0x107)
+#define SPR_VTBL              (0x10C)
+#define SPR_VTBU              (0x10D)
+#define SPR_SPRG0             (0x110)
+#define SPR_SPRG1             (0x111)
+#define SPR_SPRG2             (0x112)
+#define SPR_SPRG3             (0x113)
+#define SPR_SPRG4             (0x114)
+#define SPR_SCOMC             (0x114)
+#define SPR_SPRG5             (0x115)
+#define SPR_SCOMD             (0x115)
+#define SPR_SPRG6             (0x116)
+#define SPR_SPRG7             (0x117)
+#define SPR_ASR               (0x118)
+#define SPR_EAR               (0x11A)
+#define SPR_TBL               (0x11C)
+#define SPR_TBU               (0x11D)
+#define SPR_TBU40             (0x11E)
+#define SPR_SVR               (0x11E)
+#define SPR_BOOKE_PIR         (0x11E)
+#define SPR_PVR               (0x11F)
+#define SPR_HSPRG0            (0x130)
+#define SPR_BOOKE_DBSR        (0x130)
+#define SPR_HSPRG1            (0x131)
+#define SPR_HDSISR            (0x132)
+#define SPR_HDAR              (0x133)
+#define SPR_BOOKE_EPCR        (0x133)
+#define SPR_SPURR             (0x134)
+#define SPR_BOOKE_DBCR0       (0x134)
+#define SPR_IBCR              (0x135)
+#define SPR_PURR              (0x135)
+#define SPR_BOOKE_DBCR1       (0x135)
+#define SPR_DBCR              (0x136)
+#define SPR_HDEC              (0x136)
+#define SPR_BOOKE_DBCR2       (0x136)
+#define SPR_HIOR              (0x137)
+#define SPR_MBAR              (0x137)
+#define SPR_RMOR              (0x138)
+#define SPR_BOOKE_IAC1        (0x138)
+#define SPR_HRMOR             (0x139)
+#define SPR_BOOKE_IAC2        (0x139)
+#define SPR_HSRR0             (0x13A)
+#define SPR_BOOKE_IAC3        (0x13A)
+#define SPR_HSRR1             (0x13B)
+#define SPR_BOOKE_IAC4        (0x13B)
+#define SPR_LPCR              (0x13C)
+#define SPR_BOOKE_DAC1        (0x13C)
+#define SPR_LPIDR             (0x13D)
+#define SPR_DABR2             (0x13D)
+#define SPR_BOOKE_DAC2        (0x13D)
+#define SPR_BOOKE_DVC1        (0x13E)
+#define SPR_BOOKE_DVC2        (0x13F)
+#define SPR_BOOKE_TSR         (0x150)
+#define SPR_BOOKE_TCR         (0x154)
+#define SPR_BOOKE_IVOR0       (0x190)
+#define SPR_BOOKE_IVOR1       (0x191)
+#define SPR_BOOKE_IVOR2       (0x192)
+#define SPR_BOOKE_IVOR3       (0x193)
+#define SPR_BOOKE_IVOR4       (0x194)
+#define SPR_BOOKE_IVOR5       (0x195)
+#define SPR_BOOKE_IVOR6       (0x196)
+#define SPR_BOOKE_IVOR7       (0x197)
+#define SPR_BOOKE_IVOR8       (0x198)
+#define SPR_BOOKE_IVOR9       (0x199)
+#define SPR_BOOKE_IVOR10      (0x19A)
+#define SPR_BOOKE_IVOR11      (0x19B)
+#define SPR_BOOKE_IVOR12      (0x19C)
+#define SPR_BOOKE_IVOR13      (0x19D)
+#define SPR_BOOKE_IVOR14      (0x19E)
+#define SPR_BOOKE_IVOR15      (0x19F)
+#define SPR_BOOKE_SPEFSCR     (0x200)
+#define SPR_Exxx_BBEAR        (0x201)
+#define SPR_Exxx_BBTAR        (0x202)
+#define SPR_Exxx_L1CFG0       (0x203)
+#define SPR_Exxx_NPIDR        (0x205)
+#define SPR_ATBL              (0x20E)
+#define SPR_ATBU              (0x20F)
+#define SPR_IBAT0U            (0x210)
+#define SPR_BOOKE_IVOR32      (0x210)
+#define SPR_RCPU_MI_GRA       (0x210)
+#define SPR_IBAT0L            (0x211)
+#define SPR_BOOKE_IVOR33      (0x211)
+#define SPR_IBAT1U            (0x212)
+#define SPR_BOOKE_IVOR34      (0x212)
+#define SPR_IBAT1L            (0x213)
+#define SPR_BOOKE_IVOR35      (0x213)
+#define SPR_IBAT2U            (0x214)
+#define SPR_BOOKE_IVOR36      (0x214)
+#define SPR_IBAT2L            (0x215)
+#define SPR_BOOKE_IVOR37      (0x215)
+#define SPR_IBAT3U            (0x216)
+#define SPR_IBAT3L            (0x217)
+#define SPR_DBAT0U            (0x218)
+#define SPR_RCPU_L2U_GRA      (0x218)
+#define SPR_DBAT0L            (0x219)
+#define SPR_DBAT1U            (0x21A)
+#define SPR_DBAT1L            (0x21B)
+#define SPR_DBAT2U            (0x21C)
+#define SPR_DBAT2L            (0x21D)
+#define SPR_DBAT3U            (0x21E)
+#define SPR_DBAT3L            (0x21F)
+#define SPR_IBAT4U            (0x230)
+#define SPR_RPCU_BBCMCR       (0x230)
+#define SPR_MPC_IC_CST        (0x230)
+#define SPR_Exxx_CTXCR        (0x230)
+#define SPR_IBAT4L            (0x231)
+#define SPR_MPC_IC_ADR        (0x231)
+#define SPR_Exxx_DBCR3        (0x231)
+#define SPR_IBAT5U            (0x232)
+#define SPR_MPC_IC_DAT        (0x232)
+#define SPR_Exxx_DBCNT        (0x232)
+#define SPR_IBAT5L            (0x233)
+#define SPR_IBAT6U            (0x234)
+#define SPR_IBAT6L            (0x235)
+#define SPR_IBAT7U            (0x236)
+#define SPR_IBAT7L            (0x237)
+#define SPR_DBAT4U            (0x238)
+#define SPR_RCPU_L2U_MCR      (0x238)
+#define SPR_MPC_DC_CST        (0x238)
+#define SPR_Exxx_ALTCTXCR     (0x238)
+#define SPR_DBAT4L            (0x239)
+#define SPR_MPC_DC_ADR        (0x239)
+#define SPR_DBAT5U            (0x23A)
+#define SPR_BOOKE_MCSRR0      (0x23A)
+#define SPR_MPC_DC_DAT        (0x23A)
+#define SPR_DBAT5L            (0x23B)
+#define SPR_BOOKE_MCSRR1      (0x23B)
+#define SPR_DBAT6U            (0x23C)
+#define SPR_BOOKE_MCSR        (0x23C)
+#define SPR_DBAT6L            (0x23D)
+#define SPR_Exxx_MCAR         (0x23D)
+#define SPR_DBAT7U            (0x23E)
+#define SPR_BOOKE_DSRR0       (0x23E)
+#define SPR_DBAT7L            (0x23F)
+#define SPR_BOOKE_DSRR1       (0x23F)
+#define SPR_BOOKE_SPRG8       (0x25C)
+#define SPR_BOOKE_SPRG9       (0x25D)
+#define SPR_BOOKE_MAS0        (0x270)
+#define SPR_BOOKE_MAS1        (0x271)
+#define SPR_BOOKE_MAS2        (0x272)
+#define SPR_BOOKE_MAS3        (0x273)
+#define SPR_BOOKE_MAS4        (0x274)
+#define SPR_BOOKE_MAS5        (0x275)
+#define SPR_BOOKE_MAS6        (0x276)
+#define SPR_BOOKE_PID1        (0x279)
+#define SPR_BOOKE_PID2        (0x27A)
+#define SPR_MPC_DPDR          (0x280)
+#define SPR_MPC_IMMR          (0x288)
+#define SPR_BOOKE_TLB0CFG     (0x2B0)
+#define SPR_BOOKE_TLB1CFG     (0x2B1)
+#define SPR_BOOKE_TLB2CFG     (0x2B2)
+#define SPR_BOOKE_TLB3CFG     (0x2B3)
+#define SPR_BOOKE_EPR         (0x2BE)
+#define SPR_PERF0             (0x300)
+#define SPR_RCPU_MI_RBA0      (0x300)
+#define SPR_MPC_MI_CTR        (0x300)
+#define SPR_PERF1             (0x301)
+#define SPR_RCPU_MI_RBA1      (0x301)
+#define SPR_PERF2             (0x302)
+#define SPR_RCPU_MI_RBA2      (0x302)
+#define SPR_MPC_MI_AP         (0x302)
+#define SPR_PERF3             (0x303)
+#define SPR_620_PMC1R         (0x303)
+#define SPR_RCPU_MI_RBA3      (0x303)
+#define SPR_MPC_MI_EPN        (0x303)
+#define SPR_PERF4             (0x304)
+#define SPR_620_PMC2R         (0x304)
+#define SPR_PERF5             (0x305)
+#define SPR_MPC_MI_TWC        (0x305)
+#define SPR_PERF6             (0x306)
+#define SPR_MPC_MI_RPN        (0x306)
+#define SPR_PERF7             (0x307)
+#define SPR_PERF8             (0x308)
+#define SPR_RCPU_L2U_RBA0     (0x308)
+#define SPR_MPC_MD_CTR        (0x308)
+#define SPR_PERF9             (0x309)
+#define SPR_RCPU_L2U_RBA1     (0x309)
+#define SPR_MPC_MD_CASID      (0x309)
+#define SPR_PERFA             (0x30A)
+#define SPR_RCPU_L2U_RBA2     (0x30A)
+#define SPR_MPC_MD_AP         (0x30A)
+#define SPR_PERFB             (0x30B)
+#define SPR_620_MMCR0R        (0x30B)
+#define SPR_RCPU_L2U_RBA3     (0x30B)
+#define SPR_MPC_MD_EPN        (0x30B)
+#define SPR_PERFC             (0x30C)
+#define SPR_MPC_MD_TWB        (0x30C)
+#define SPR_PERFD             (0x30D)
+#define SPR_MPC_MD_TWC        (0x30D)
+#define SPR_PERFE             (0x30E)
+#define SPR_MPC_MD_RPN        (0x30E)
+#define SPR_PERFF             (0x30F)
+#define SPR_MPC_MD_TW         (0x30F)
+#define SPR_UPERF0            (0x310)
+#define SPR_UPERF1            (0x311)
+#define SPR_UPERF2            (0x312)
+#define SPR_UPERF3            (0x313)
+#define SPR_620_PMC1W         (0x313)
+#define SPR_UPERF4            (0x314)
+#define SPR_620_PMC2W         (0x314)
+#define SPR_UPERF5            (0x315)
+#define SPR_UPERF6            (0x316)
+#define SPR_UPERF7            (0x317)
+#define SPR_UPERF8            (0x318)
+#define SPR_UPERF9            (0x319)
+#define SPR_UPERFA            (0x31A)
+#define SPR_UPERFB            (0x31B)
+#define SPR_620_MMCR0W        (0x31B)
+#define SPR_UPERFC            (0x31C)
+#define SPR_UPERFD            (0x31D)
+#define SPR_UPERFE            (0x31E)
+#define SPR_UPERFF            (0x31F)
+#define SPR_RCPU_MI_RA0       (0x320)
+#define SPR_MPC_MI_DBCAM      (0x320)
+#define SPR_RCPU_MI_RA1       (0x321)
+#define SPR_MPC_MI_DBRAM0     (0x321)
+#define SPR_RCPU_MI_RA2       (0x322)
+#define SPR_MPC_MI_DBRAM1     (0x322)
+#define SPR_RCPU_MI_RA3       (0x323)
+#define SPR_RCPU_L2U_RA0      (0x328)
+#define SPR_MPC_MD_DBCAM      (0x328)
+#define SPR_RCPU_L2U_RA1      (0x329)
+#define SPR_MPC_MD_DBRAM0     (0x329)
+#define SPR_RCPU_L2U_RA2      (0x32A)
+#define SPR_MPC_MD_DBRAM1     (0x32A)
+#define SPR_RCPU_L2U_RA3      (0x32B)
+#define SPR_440_INV0          (0x370)
+#define SPR_440_INV1          (0x371)
+#define SPR_440_INV2          (0x372)
+#define SPR_440_INV3          (0x373)
+#define SPR_440_ITV0          (0x374)
+#define SPR_440_ITV1          (0x375)
+#define SPR_440_ITV2          (0x376)
+#define SPR_440_ITV3          (0x377)
+#define SPR_440_CCR1          (0x378)
+#define SPR_DCRIPR            (0x37B)
+#define SPR_PPR               (0x380)
+#define SPR_750_GQR0          (0x390)
+#define SPR_440_DNV0          (0x390)
+#define SPR_750_GQR1          (0x391)
+#define SPR_440_DNV1          (0x391)
+#define SPR_750_GQR2          (0x392)
+#define SPR_440_DNV2          (0x392)
+#define SPR_750_GQR3          (0x393)
+#define SPR_440_DNV3          (0x393)
+#define SPR_750_GQR4          (0x394)
+#define SPR_440_DTV0          (0x394)
+#define SPR_750_GQR5          (0x395)
+#define SPR_440_DTV1          (0x395)
+#define SPR_750_GQR6          (0x396)
+#define SPR_440_DTV2          (0x396)
+#define SPR_750_GQR7          (0x397)
+#define SPR_440_DTV3          (0x397)
+#define SPR_750_THRM4         (0x398)
+#define SPR_750CL_HID2        (0x398)
+#define SPR_440_DVLIM         (0x398)
+#define SPR_750_WPAR          (0x399)
+#define SPR_440_IVLIM         (0x399)
+#define SPR_750_DMAU          (0x39A)
+#define SPR_750_DMAL          (0x39B)
+#define SPR_440_RSTCFG        (0x39B)
+#define SPR_BOOKE_DCDBTRL     (0x39C)
+#define SPR_BOOKE_DCDBTRH     (0x39D)
+#define SPR_BOOKE_ICDBTRL     (0x39E)
+#define SPR_BOOKE_ICDBTRH     (0x39F)
+#define SPR_UMMCR2            (0x3A0)
+#define SPR_UPMC5             (0x3A1)
+#define SPR_UPMC6             (0x3A2)
+#define SPR_UBAMR             (0x3A7)
+#define SPR_UMMCR0            (0x3A8)
+#define SPR_UPMC1             (0x3A9)
+#define SPR_UPMC2             (0x3AA)
+#define SPR_USIAR             (0x3AB)
+#define SPR_UMMCR1            (0x3AC)
+#define SPR_UPMC3             (0x3AD)
+#define SPR_UPMC4             (0x3AE)
+#define SPR_USDA              (0x3AF)
+#define SPR_40x_ZPR           (0x3B0)
+#define SPR_BOOKE_MAS7        (0x3B0)
+#define SPR_620_PMR0          (0x3B0)
+#define SPR_MMCR2             (0x3B0)
+#define SPR_PMC5              (0x3B1)
+#define SPR_40x_PID           (0x3B1)
+#define SPR_620_PMR1          (0x3B1)
+#define SPR_PMC6              (0x3B2)
+#define SPR_440_MMUCR         (0x3B2)
+#define SPR_620_PMR2          (0x3B2)
+#define SPR_4xx_CCR0          (0x3B3)
+#define SPR_BOOKE_EPLC        (0x3B3)
+#define SPR_620_PMR3          (0x3B3)
+#define SPR_405_IAC3          (0x3B4)
+#define SPR_BOOKE_EPSC        (0x3B4)
+#define SPR_620_PMR4          (0x3B4)
+#define SPR_405_IAC4          (0x3B5)
+#define SPR_620_PMR5          (0x3B5)
+#define SPR_405_DVC1          (0x3B6)
+#define SPR_620_PMR6          (0x3B6)
+#define SPR_405_DVC2          (0x3B7)
+#define SPR_620_PMR7          (0x3B7)
+#define SPR_BAMR              (0x3B7)
+#define SPR_MMCR0             (0x3B8)
+#define SPR_620_PMR8          (0x3B8)
+#define SPR_PMC1              (0x3B9)
+#define SPR_40x_SGR           (0x3B9)
+#define SPR_620_PMR9          (0x3B9)
+#define SPR_PMC2              (0x3BA)
+#define SPR_40x_DCWR          (0x3BA)
+#define SPR_620_PMRA          (0x3BA)
+#define SPR_SIAR              (0x3BB)
+#define SPR_405_SLER          (0x3BB)
+#define SPR_620_PMRB          (0x3BB)
+#define SPR_MMCR1             (0x3BC)
+#define SPR_405_SU0R          (0x3BC)
+#define SPR_620_PMRC          (0x3BC)
+#define SPR_401_SKR           (0x3BC)
+#define SPR_PMC3              (0x3BD)
+#define SPR_405_DBCR1         (0x3BD)
+#define SPR_620_PMRD          (0x3BD)
+#define SPR_PMC4              (0x3BE)
+#define SPR_620_PMRE          (0x3BE)
+#define SPR_SDA               (0x3BF)
+#define SPR_620_PMRF          (0x3BF)
+#define SPR_403_VTBL          (0x3CC)
+#define SPR_403_VTBU          (0x3CD)
+#define SPR_DMISS             (0x3D0)
+#define SPR_DCMP              (0x3D1)
+#define SPR_HASH1             (0x3D2)
+#define SPR_HASH2             (0x3D3)
+#define SPR_BOOKE_ICDBDR      (0x3D3)
+#define SPR_TLBMISS           (0x3D4)
+#define SPR_IMISS             (0x3D4)
+#define SPR_40x_ESR           (0x3D4)
+#define SPR_PTEHI             (0x3D5)
+#define SPR_ICMP              (0x3D5)
+#define SPR_40x_DEAR          (0x3D5)
+#define SPR_PTELO             (0x3D6)
+#define SPR_RPA               (0x3D6)
+#define SPR_40x_EVPR          (0x3D6)
+#define SPR_L3PM              (0x3D7)
+#define SPR_403_CDBCR         (0x3D7)
+#define SPR_L3ITCR0           (0x3D8)
+#define SPR_TCR               (0x3D8)
+#define SPR_40x_TSR           (0x3D8)
+#define SPR_IBR               (0x3DA)
+#define SPR_40x_TCR           (0x3DA)
+#define SPR_ESASRR            (0x3DB)
+#define SPR_40x_PIT           (0x3DB)
+#define SPR_403_TBL           (0x3DC)
+#define SPR_403_TBU           (0x3DD)
+#define SPR_SEBR              (0x3DE)
+#define SPR_40x_SRR2          (0x3DE)
+#define SPR_SER               (0x3DF)
+#define SPR_40x_SRR3          (0x3DF)
+#define SPR_L3OHCR            (0x3E8)
+#define SPR_L3ITCR1           (0x3E9)
+#define SPR_L3ITCR2           (0x3EA)
+#define SPR_L3ITCR3           (0x3EB)
+#define SPR_HID0              (0x3F0)
+#define SPR_40x_DBSR          (0x3F0)
+#define SPR_HID1              (0x3F1)
+#define SPR_IABR              (0x3F2)
+#define SPR_40x_DBCR0         (0x3F2)
+#define SPR_601_HID2          (0x3F2)
+#define SPR_Exxx_L1CSR0       (0x3F2)
+#define SPR_ICTRL             (0x3F3)
+#define SPR_HID2              (0x3F3)
+#define SPR_750CL_HID4        (0x3F3)
+#define SPR_Exxx_L1CSR1       (0x3F3)
+#define SPR_440_DBDR          (0x3F3)
+#define SPR_LDSTDB            (0x3F4)
+#define SPR_750_TDCL          (0x3F4)
+#define SPR_40x_IAC1          (0x3F4)
+#define SPR_MMUCSR0           (0x3F4)
+#define SPR_DABR              (0x3F5)
+#define DABR_MASK (~(target_ulong)0x7)
+#define SPR_Exxx_BUCSR        (0x3F5)
+#define SPR_40x_IAC2          (0x3F5)
+#define SPR_601_HID5          (0x3F5)
+#define SPR_40x_DAC1          (0x3F6)
+#define SPR_MSSCR0            (0x3F6)
+#define SPR_970_HID5          (0x3F6)
+#define SPR_MSSSR0            (0x3F7)
+#define SPR_MSSCR1            (0x3F7)
+#define SPR_DABRX             (0x3F7)
+#define SPR_40x_DAC2          (0x3F7)
+#define SPR_MMUCFG            (0x3F7)
+#define SPR_LDSTCR            (0x3F8)
+#define SPR_L2PMCR            (0x3F8)
+#define SPR_750FX_HID2        (0x3F8)
+#define SPR_620_BUSCSR        (0x3F8)
+#define SPR_Exxx_L1FINV0      (0x3F8)
+#define SPR_L2CR              (0x3F9)
+#define SPR_620_L2CR          (0x3F9)
+#define SPR_L3CR              (0x3FA)
+#define SPR_750_TDCH          (0x3FA)
+#define SPR_IABR2             (0x3FA)
+#define SPR_40x_DCCR          (0x3FA)
+#define SPR_620_L2SR          (0x3FA)
+#define SPR_ICTC              (0x3FB)
+#define SPR_40x_ICCR          (0x3FB)
+#define SPR_THRM1             (0x3FC)
+#define SPR_403_PBL1          (0x3FC)
+#define SPR_SP                (0x3FD)
+#define SPR_THRM2             (0x3FD)
+#define SPR_403_PBU1          (0x3FD)
+#define SPR_604_HID13         (0x3FD)
+#define SPR_LT                (0x3FE)
+#define SPR_THRM3             (0x3FE)
+#define SPR_RCPU_FPECR        (0x3FE)
+#define SPR_403_PBL2          (0x3FE)
+#define SPR_PIR               (0x3FF)
+#define SPR_403_PBU2          (0x3FF)
+#define SPR_601_HID15         (0x3FF)
+#define SPR_604_HID15         (0x3FF)
+#define SPR_E500_SVR          (0x3FF)
+
+/*****************************************************************************/
+/* PowerPC Instructions types definitions                                    */
+enum {
+    PPC_NONE           = 0x0000000000000000ULL,
+    /* PowerPC base instructions set                                         */
+    PPC_INSNS_BASE     = 0x0000000000000001ULL,
+    /*   integer operations instructions                                     */
+#define PPC_INTEGER PPC_INSNS_BASE
+    /*   flow control instructions                                           */
+#define PPC_FLOW    PPC_INSNS_BASE
+    /*   virtual memory instructions                                         */
+#define PPC_MEM     PPC_INSNS_BASE
+    /*   ld/st with reservation instructions                                 */
+#define PPC_RES     PPC_INSNS_BASE
+    /*   spr/msr access instructions                                         */
+#define PPC_MISC    PPC_INSNS_BASE
+    /* Deprecated instruction sets                                           */
+    /*   Original POWER instruction set                                      */
+    PPC_POWER          = 0x0000000000000002ULL,
+    /*   POWER2 instruction set extension                                    */
+    PPC_POWER2         = 0x0000000000000004ULL,
+    /*   Power RTC support                                                   */
+    PPC_POWER_RTC      = 0x0000000000000008ULL,
+    /*   Power-to-PowerPC bridge (601)                                       */
+    PPC_POWER_BR       = 0x0000000000000010ULL,
+    /* 64 bits PowerPC instruction set                                       */
+    PPC_64B            = 0x0000000000000020ULL,
+    /*   New 64 bits extensions (PowerPC 2.0x)                               */
+    PPC_64BX           = 0x0000000000000040ULL,
+    /*   64 bits hypervisor extensions                                       */
+    PPC_64H            = 0x0000000000000080ULL,
+    /*   New wait instruction (PowerPC 2.0x)                                 */
+    PPC_WAIT           = 0x0000000000000100ULL,
+    /*   Time base mftb instruction                                          */
+    PPC_MFTB           = 0x0000000000000200ULL,
+
+    /* Fixed-point unit extensions                                           */
+    /*   PowerPC 602 specific                                                */
+    PPC_602_SPEC       = 0x0000000000000400ULL,
+    /*   isel instruction                                                    */
+    PPC_ISEL           = 0x0000000000000800ULL,
+    /*   popcntb instruction                                                 */
+    PPC_POPCNTB        = 0x0000000000001000ULL,
+    /*   string load / store                                                 */
+    PPC_STRING         = 0x0000000000002000ULL,
+
+    /* Floating-point unit extensions                                        */
+    /*   Optional floating point instructions                                */
+    PPC_FLOAT          = 0x0000000000010000ULL,
+    /* New floating-point extensions (PowerPC 2.0x)                          */
+    PPC_FLOAT_EXT      = 0x0000000000020000ULL,
+    PPC_FLOAT_FSQRT    = 0x0000000000040000ULL,
+    PPC_FLOAT_FRES     = 0x0000000000080000ULL,
+    PPC_FLOAT_FRSQRTE  = 0x0000000000100000ULL,
+    PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL,
+    PPC_FLOAT_FSEL     = 0x0000000000400000ULL,
+    PPC_FLOAT_STFIWX   = 0x0000000000800000ULL,
+
+    /* Vector/SIMD extensions                                                */
+    /*   Altivec support                                                     */
+    PPC_ALTIVEC        = 0x0000000001000000ULL,
+    /*   PowerPC 2.03 SPE extension                                          */
+    PPC_SPE            = 0x0000000002000000ULL,
+    /*   PowerPC 2.03 SPE single-precision floating-point extension          */
+    PPC_SPE_SINGLE     = 0x0000000004000000ULL,
+    /*   PowerPC 2.03 SPE double-precision floating-point extension          */
+    PPC_SPE_DOUBLE     = 0x0000000008000000ULL,
+
+    /* Optional memory control instructions                                  */
+    PPC_MEM_TLBIA      = 0x0000000010000000ULL,
+    PPC_MEM_TLBIE      = 0x0000000020000000ULL,
+    PPC_MEM_TLBSYNC    = 0x0000000040000000ULL,
+    /*   sync instruction                                                    */
+    PPC_MEM_SYNC       = 0x0000000080000000ULL,
+    /*   eieio instruction                                                   */
+    PPC_MEM_EIEIO      = 0x0000000100000000ULL,
+
+    /* Cache control instructions                                            */
+    PPC_CACHE          = 0x0000000200000000ULL,
+    /*   icbi instruction                                                    */
+    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
+    /*   dcbz instruction with fixed cache line size                         */
+    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
+    /*   dcbz instruction with tunable cache line size                       */
+    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
+    /*   dcba instruction                                                    */
+    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
+    /*   Freescale cache locking instructions                                */
+    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
+
+    /* MMU related extensions                                                */
+    /*   external control instructions                                       */
+    PPC_EXTERN         = 0x0000010000000000ULL,
+    /*   segment register access instructions                                */
+    PPC_SEGMENT        = 0x0000020000000000ULL,
+    /*   PowerPC 6xx TLB management instructions                             */
+    PPC_6xx_TLB        = 0x0000040000000000ULL,
+    /* PowerPC 74xx TLB management instructions                              */
+    PPC_74xx_TLB       = 0x0000080000000000ULL,
+    /*   PowerPC 40x TLB management instructions                             */
+    PPC_40x_TLB        = 0x0000100000000000ULL,
+    /*   segment register access instructions for PowerPC 64 "bridge"        */
+    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
+    /*   SLB management                                                      */
+    PPC_SLBI           = 0x0000400000000000ULL,
+
+    /* Embedded PowerPC dedicated instructions                               */
+    PPC_WRTEE          = 0x0001000000000000ULL,
+    /* PowerPC 40x exception model                                           */
+    PPC_40x_EXCP       = 0x0002000000000000ULL,
+    /* PowerPC 405 Mac instructions                                          */
+    PPC_405_MAC        = 0x0004000000000000ULL,
+    /* PowerPC 440 specific instructions                                     */
+    PPC_440_SPEC       = 0x0008000000000000ULL,
+    /* BookE (embedded) PowerPC specification                                */
+    PPC_BOOKE          = 0x0010000000000000ULL,
+    /* mfapidi instruction                                                   */
+    PPC_MFAPIDI        = 0x0020000000000000ULL,
+    /* tlbiva instruction                                                    */
+    PPC_TLBIVA         = 0x0040000000000000ULL,
+    /* tlbivax instruction                                                   */
+    PPC_TLBIVAX        = 0x0080000000000000ULL,
+    /* PowerPC 4xx dedicated instructions                                    */
+    PPC_4xx_COMMON     = 0x0100000000000000ULL,
+    /* PowerPC 40x ibct instructions                                         */
+    PPC_40x_ICBT       = 0x0200000000000000ULL,
+    /* rfmci is not implemented in all BookE PowerPC                         */
+    PPC_RFMCI          = 0x0400000000000000ULL,
+    /* rfdi instruction                                                      */
+    PPC_RFDI           = 0x0800000000000000ULL,
+    /* DCR accesses                                                          */
+    PPC_DCR            = 0x1000000000000000ULL,
+    /* DCR extended accesse                                                  */
+    PPC_DCRX           = 0x2000000000000000ULL,
+    /* user-mode DCR access, implemented in PowerPC 460                      */
+    PPC_DCRUX          = 0x4000000000000000ULL,
+    /* popcntw and popcntd instructions                                      */
+    PPC_POPCNTWD       = 0x8000000000000000ULL,
+
+    /* extended type values */
+
+    /* BookE 2.06 PowerPC specification                                      */
+    PPC2_BOOKE206      = 0x0000000000000001ULL,
+};
+
+/*****************************************************************************/
+/* Memory access type :
+ * may be needed for precise access rights control and precise exceptions.
+ */
+enum {
+    /* 1 bit to define user level / supervisor access */
+    ACCESS_USER  = 0x00,
+    ACCESS_SUPER = 0x01,
+    /* Type of instruction that generated the access */
+    ACCESS_CODE  = 0x10, /* Code fetch access                */
+    ACCESS_INT   = 0x20, /* Integer load/store access        */
+    ACCESS_FLOAT = 0x30, /* floating point load/store access */
+    ACCESS_RES   = 0x40, /* load/store with reservation      */
+    ACCESS_EXT   = 0x50, /* external access                  */
+    ACCESS_CACHE = 0x60, /* Cache manipulation               */
+};
+
+/* Hardware interruption sources:
+ * all those exception can be raised simulteaneously
+ */
+/* Input pins definitions */
+enum {
+    /* 6xx bus input pins */
+    PPC6xx_INPUT_HRESET     = 0,
+    PPC6xx_INPUT_SRESET     = 1,
+    PPC6xx_INPUT_CKSTP_IN   = 2,
+    PPC6xx_INPUT_MCP        = 3,
+    PPC6xx_INPUT_SMI        = 4,
+    PPC6xx_INPUT_INT        = 5,
+    PPC6xx_INPUT_TBEN       = 6,
+    PPC6xx_INPUT_WAKEUP     = 7,
+    PPC6xx_INPUT_NB,
+};
+
+enum {
+    /* Embedded PowerPC input pins */
+    PPCBookE_INPUT_HRESET     = 0,
+    PPCBookE_INPUT_SRESET     = 1,
+    PPCBookE_INPUT_CKSTP_IN   = 2,
+    PPCBookE_INPUT_MCP        = 3,
+    PPCBookE_INPUT_SMI        = 4,
+    PPCBookE_INPUT_INT        = 5,
+    PPCBookE_INPUT_CINT       = 6,
+    PPCBookE_INPUT_NB,
+};
+
+enum {
+    /* PowerPC E500 input pins */
+    PPCE500_INPUT_RESET_CORE = 0,
+    PPCE500_INPUT_MCK        = 1,
+    PPCE500_INPUT_CINT       = 3,
+    PPCE500_INPUT_INT        = 4,
+    PPCE500_INPUT_DEBUG      = 6,
+    PPCE500_INPUT_NB,
+};
+
+enum {
+    /* PowerPC 40x input pins */
+    PPC40x_INPUT_RESET_CORE = 0,
+    PPC40x_INPUT_RESET_CHIP = 1,
+    PPC40x_INPUT_RESET_SYS  = 2,
+    PPC40x_INPUT_CINT       = 3,
+    PPC40x_INPUT_INT        = 4,
+    PPC40x_INPUT_HALT       = 5,
+    PPC40x_INPUT_DEBUG      = 6,
+    PPC40x_INPUT_NB,
+};
+
+enum {
+    /* RCPU input pins */
+    PPCRCPU_INPUT_PORESET   = 0,
+    PPCRCPU_INPUT_HRESET    = 1,
+    PPCRCPU_INPUT_SRESET    = 2,
+    PPCRCPU_INPUT_IRQ0      = 3,
+    PPCRCPU_INPUT_IRQ1      = 4,
+    PPCRCPU_INPUT_IRQ2      = 5,
+    PPCRCPU_INPUT_IRQ3      = 6,
+    PPCRCPU_INPUT_IRQ4      = 7,
+    PPCRCPU_INPUT_IRQ5      = 8,
+    PPCRCPU_INPUT_IRQ6      = 9,
+    PPCRCPU_INPUT_IRQ7      = 10,
+    PPCRCPU_INPUT_NB,
+};
+
+#if defined(TARGET_PPC64)
+enum {
+    /* PowerPC 970 input pins */
+    PPC970_INPUT_HRESET     = 0,
+    PPC970_INPUT_SRESET     = 1,
+    PPC970_INPUT_CKSTP      = 2,
+    PPC970_INPUT_TBEN       = 3,
+    PPC970_INPUT_MCP        = 4,
+    PPC970_INPUT_INT        = 5,
+    PPC970_INPUT_THINT      = 6,
+    PPC970_INPUT_NB,
+};
+
+enum {
+    /* POWER7 input pins */
+    POWER7_INPUT_INT        = 0,
+    /* POWER7 probably has other inputs, but we don't care about them
+     * for any existing machine.  We can wire these up when we need
+     * them */
+    POWER7_INPUT_NB,
+};
+#endif
+
+/* Hardware exceptions definitions */
+enum {
+    /* External hardware exception sources */
+    PPC_INTERRUPT_RESET     = 0,  /* Reset exception                      */
+    PPC_INTERRUPT_WAKEUP,         /* Wakeup exception                     */
+    PPC_INTERRUPT_MCK,            /* Machine check exception              */
+    PPC_INTERRUPT_EXT,            /* External interrupt                   */
+    PPC_INTERRUPT_SMI,            /* System management interrupt          */
+    PPC_INTERRUPT_CEXT,           /* Critical external interrupt          */
+    PPC_INTERRUPT_DEBUG,          /* External debug exception             */
+    PPC_INTERRUPT_THERM,          /* Thermal exception                    */
+    /* Internal hardware exception sources */
+    PPC_INTERRUPT_DECR,           /* Decrementer exception                */
+    PPC_INTERRUPT_HDECR,          /* Hypervisor decrementer exception     */
+    PPC_INTERRUPT_PIT,            /* Programmable inteval timer interrupt */
+    PPC_INTERRUPT_FIT,            /* Fixed interval timer interrupt       */
+    PPC_INTERRUPT_WDT,            /* Watchdog timer interrupt             */
+    PPC_INTERRUPT_CDOORBELL,      /* Critical doorbell interrupt          */
+    PPC_INTERRUPT_DOORBELL,       /* Doorbell interrupt                   */
+    PPC_INTERRUPT_PERFM,          /* Performance monitor interrupt        */
+};
+
+/*****************************************************************************/
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->nip;
+    *cs_base = 0;
+    *flags = env->hflags;
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+#if defined(TARGET_PPC64)
+    /* The kernel checks TIF_32BIT here; we don't support loading 32-bit
+       binaries on PPC64 yet. */
+    env->gpr[13] = newtls;
+#else
+    env->gpr[2] = newtls;
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm)
+{
+    uintptr_t tlbml = (uintptr_t)tlbm;
+    uintptr_t tlbl = (uintptr_t)env->tlb.tlbm;
+
+    return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]);
+}
+
+static inline int booke206_tlb_size(CPUState *env, int tlbn)
+{
+    uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+    int r = tlbncfg & TLBnCFG_N_ENTRY;
+    return r;
+}
+
+static inline int booke206_tlb_ways(CPUState *env, int tlbn)
+{
+    uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+    int r = tlbncfg >> TLBnCFG_ASSOC_SHIFT;
+    return r;
+}
+
+static inline int booke206_tlbm_to_tlbn(CPUState *env, ppcmas_tlb_t *tlbm)
+{
+    int id = booke206_tlbm_id(env, tlbm);
+    int end = 0;
+    int i;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        end += booke206_tlb_size(env, i);
+        if (id < end) {
+            return i;
+        }
+    }
+
+    cpu_abort(env, "Unknown TLBe: %d\n", id);
+    return 0;
+}
+
+static inline int booke206_tlbm_to_way(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    int tlbid = booke206_tlbm_id(env, tlb);
+    return tlbid & (booke206_tlb_ways(env, tlbn) - 1);
+}
+
+static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
+                                              target_ulong ea, int way)
+{
+    int r;
+    uint32_t ways = booke206_tlb_ways(env, tlbn);
+    int ways_bits = ffs(ways) - 1;
+    int tlb_bits = ffs(booke206_tlb_size(env, tlbn)) - 1;
+    int i;
+
+    way &= ways - 1;
+    ea >>= MAS2_EPN_SHIFT;
+    ea &= (1 << (tlb_bits - ways_bits)) - 1;
+    r = (ea << ways_bits) | way;
+
+    /* bump up to tlbn index */
+    for (i = 0; i < tlbn; i++) {
+        r += booke206_tlb_size(env, i);
+    }
+
+    return &env->tlb.tlbm[r];
+}
+
+#endif
+
+extern void (*cpu_ppc_hypercall)(CPUState *);
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->nip = tb->pc;
+}
+
+#endif /* !defined (__CPU_PPC_H__) */
diff --git a/qemu-0.15.x/target-ppc/exec.h b/qemu-0.15.x/target-ppc/exec.h
new file mode 100644
index 0000000..f4453e4
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/exec.h
@@ -0,0 +1,34 @@
+/*
+ *  PowerPC emulation definitions for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined (__PPC_H__)
+#define __PPC_H__
+
+#include "config.h"
+
+#include "dyngen-exec.h"
+
+#include "cpu.h"
+
+register struct CPUPPCState *env asm(AREG0);
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#endif /* !defined (__PPC_H__) */
diff --git a/qemu-0.15.x/target-ppc/helper.c b/qemu-0.15.x/target-ppc/helper.c
new file mode 100644
index 0000000..176128a
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/helper.c
@@ -0,0 +1,3107 @@
+/*
+ *  PowerPC emulation helpers for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "helper_regs.h"
+#include "qemu-common.h"
+#include "kvm.h"
+
+//#define DEBUG_MMU
+//#define DEBUG_BATS
+//#define DEBUG_SLB
+//#define DEBUG_SOFTWARE_TLB
+//#define DUMP_PAGE_TABLES
+//#define DEBUG_EXCEPTIONS
+//#define FLUSH_ALL_TLBS
+
+#ifdef DEBUG_MMU
+#  define LOG_MMU(...) qemu_log(__VA_ARGS__)
+#  define LOG_MMU_STATE(env) log_cpu_state((env), 0)
+#else
+#  define LOG_MMU(...) do { } while (0)
+#  define LOG_MMU_STATE(...) do { } while (0)
+#endif
+
+
+#ifdef DEBUG_SOFTWARE_TLB
+#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_SWTLB(...) do { } while (0)
+#endif
+
+#ifdef DEBUG_BATS
+#  define LOG_BATS(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_BATS(...) do { } while (0)
+#endif
+
+#ifdef DEBUG_SLB
+#  define LOG_SLB(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_SLB(...) do { } while (0)
+#endif
+
+#ifdef DEBUG_EXCEPTIONS
+#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_EXCP(...) do { } while (0)
+#endif
+
+/*****************************************************************************/
+/* PowerPC Hypercall emulation */
+
+void (*cpu_ppc_hypercall)(CPUState *);
+
+/*****************************************************************************/
+/* PowerPC MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    int exception, error_code;
+
+    if (rw == 2) {
+        exception = POWERPC_EXCP_ISI;
+        error_code = 0x40000000;
+    } else {
+        exception = POWERPC_EXCP_DSI;
+        error_code = 0x40000000;
+        if (rw)
+            error_code |= 0x02000000;
+        env->spr[SPR_DAR] = address;
+        env->spr[SPR_DSISR] = error_code;
+    }
+    env->exception_index = exception;
+    env->error_code = error_code;
+
+    return 1;
+}
+
+#else
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid(target_ulong pte0)
+{
+    return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate(target_ulong *pte0)
+{
+    *pte0 &= ~0x80000000;
+}
+
+#if defined(TARGET_PPC64)
+static inline int pte64_is_valid(target_ulong pte0)
+{
+    return pte0 & 0x0000000000000001ULL ? 1 : 0;
+}
+
+static inline void pte64_invalidate(target_ulong *pte0)
+{
+    *pte0 &= ~0x0000000000000001ULL;
+}
+#endif
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+#if defined(TARGET_PPC64)
+#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
+#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
+#endif
+
+static inline int pp_check(int key, int pp, int nx)
+{
+    int access;
+
+    /* Compute access rights */
+    /* When pp is 3/7, the result is undefined. Set it to noaccess */
+    access = 0;
+    if (key == 0) {
+        switch (pp) {
+        case 0x0:
+        case 0x1:
+        case 0x2:
+            access |= PAGE_WRITE;
+            /* No break here */
+        case 0x3:
+        case 0x6:
+            access |= PAGE_READ;
+            break;
+        }
+    } else {
+        switch (pp) {
+        case 0x0:
+        case 0x6:
+            access = 0;
+            break;
+        case 0x1:
+        case 0x3:
+            access = PAGE_READ;
+            break;
+        case 0x2:
+            access = PAGE_READ | PAGE_WRITE;
+            break;
+        }
+    }
+    if (nx == 0)
+        access |= PAGE_EXEC;
+
+    return access;
+}
+
+static inline int check_prot(int prot, int rw, int access_type)
+{
+    int ret;
+
+    if (access_type == ACCESS_CODE) {
+        if (prot & PAGE_EXEC)
+            ret = 0;
+        else
+            ret = -2;
+    } else if (rw) {
+        if (prot & PAGE_WRITE)
+            ret = 0;
+        else
+            ret = -2;
+    } else {
+        if (prot & PAGE_READ)
+            ret = 0;
+        else
+            ret = -2;
+    }
+
+    return ret;
+}
+
+static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
+                             target_ulong pte1, int h, int rw, int type)
+{
+    target_ulong ptem, mmask;
+    int access, ret, pteh, ptev, pp;
+
+    ret = -1;
+    /* Check validity and table match */
+#if defined(TARGET_PPC64)
+    if (is_64b) {
+        ptev = pte64_is_valid(pte0);
+        pteh = (pte0 >> 1) & 1;
+    } else
+#endif
+    {
+        ptev = pte_is_valid(pte0);
+        pteh = (pte0 >> 6) & 1;
+    }
+    if (ptev && h == pteh) {
+        /* Check vsid & api */
+#if defined(TARGET_PPC64)
+        if (is_64b) {
+            ptem = pte0 & PTE64_PTEM_MASK;
+            mmask = PTE64_CHECK_MASK;
+            pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
+            ctx->nx  = (pte1 >> 2) & 1; /* No execute bit */
+            ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit    */
+        } else
+#endif
+        {
+            ptem = pte0 & PTE_PTEM_MASK;
+            mmask = PTE_CHECK_MASK;
+            pp = pte1 & 0x00000003;
+        }
+        if (ptem == ctx->ptem) {
+            if (ctx->raddr != (target_phys_addr_t)-1ULL) {
+                /* all matches should have equal RPN, WIMG & PP */
+                if ((ctx->raddr & mmask) != (pte1 & mmask)) {
+                    qemu_log("Bad RPN/WIMG/PP\n");
+                    return -3;
+                }
+            }
+            /* Compute access rights */
+            access = pp_check(ctx->key, pp, ctx->nx);
+            /* Keep the matching PTE informations */
+            ctx->raddr = pte1;
+            ctx->prot = access;
+            ret = check_prot(ctx->prot, rw, type);
+            if (ret == 0) {
+                /* Access granted */
+                LOG_MMU("PTE access granted !\n");
+            } else {
+                /* Access right violation */
+                LOG_MMU("PTE access rejected\n");
+            }
+        }
+    }
+
+    return ret;
+}
+
+static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
+                              target_ulong pte1, int h, int rw, int type)
+{
+    return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
+}
+
+#if defined(TARGET_PPC64)
+static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+                              target_ulong pte1, int h, int rw, int type)
+{
+    return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
+}
+#endif
+
+static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+                                   int ret, int rw)
+{
+    int store = 0;
+
+    /* Update page flags */
+    if (!(*pte1p & 0x00000100)) {
+        /* Update accessed flag */
+        *pte1p |= 0x00000100;
+        store = 1;
+    }
+    if (!(*pte1p & 0x00000080)) {
+        if (rw == 1 && ret == 0) {
+            /* Update changed flag */
+            *pte1p |= 0x00000080;
+            store = 1;
+        } else {
+            /* Force page fault for first write access */
+            ctx->prot &= ~PAGE_WRITE;
+        }
+    }
+
+    return store;
+}
+
+/* Software driven TLB helpers */
+static inline int ppc6xx_tlb_getnum(CPUState *env, target_ulong eaddr, int way,
+                                    int is_code)
+{
+    int nr;
+
+    /* Select TLB num in a way from address */
+    nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+    /* Select TLB way */
+    nr += env->tlb_per_way * way;
+    /* 6xx have separate TLBs for instructions and data */
+    if (is_code && env->id_tlbs == 1)
+        nr += env->nb_tlb;
+
+    return nr;
+}
+
+static inline void ppc6xx_tlb_invalidate_all(CPUState *env)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr, max;
+
+    //LOG_SWTLB("Invalidate all TLBs\n");
+    /* Invalidate all defined software TLB */
+    max = env->nb_tlb;
+    if (env->id_tlbs == 1)
+        max *= 2;
+    for (nr = 0; nr < max; nr++) {
+        tlb = &env->tlb.tlb6[nr];
+        pte_invalidate(&tlb->pte0);
+    }
+    tlb_flush(env, 1);
+}
+
+static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env,
+                                                target_ulong eaddr,
+                                                int is_code, int match_epn)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    ppc6xx_tlb_t *tlb;
+    int way, nr;
+
+    /* Invalidate ITLB + DTLB, all ways */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+        tlb = &env->tlb.tlb6[nr];
+        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+            LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
+                      env->nb_tlb, eaddr);
+            pte_invalidate(&tlb->pte0);
+            tlb_flush_page(env, tlb->EPN);
+        }
+    }
+#else
+    /* XXX: PowerPC specification say this is valid as well */
+    ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+static inline void ppc6xx_tlb_invalidate_virt(CPUState *env,
+                                              target_ulong eaddr, int is_code)
+{
+    __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr;
+
+    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+    tlb = &env->tlb.tlb6[nr];
+    LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+              " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
+    /* Invalidate any pending reference in Qemu for this virtual address */
+    __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+    tlb->pte0 = pte0;
+    tlb->pte1 = pte1;
+    tlb->EPN = EPN;
+    /* Store last way for LRU mechanism */
+    env->last_way = way;
+}
+
+static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
+                                   target_ulong eaddr, int rw, int access_type)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr, best, way;
+    int ret;
+
+    best = -1;
+    ret = -1; /* No TLB found */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way,
+                               access_type == ACCESS_CODE ? 1 : 0);
+        tlb = &env->tlb.tlb6[nr];
+        /* This test "emulates" the PTE index match for hardware TLBs */
+        if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+            LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
+                      "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
+                      pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                      tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+            continue;
+        }
+        LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
+                  TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
+                  pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                  tlb->EPN, eaddr, tlb->pte1,
+                  rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+        switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
+        case -3:
+            /* TLB inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            best = nr;
+            break;
+        case -1:
+        default:
+            /* No match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all TLBs consistency
+             *      but we can speed-up the whole thing as the
+             *      result would be undefined if TLBs are not consistent.
+             */
+            ret = 0;
+            best = nr;
+            goto done;
+        }
+    }
+    if (best != -1) {
+    done:
+        LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
+                  ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+        /* Update page flags */
+        pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
+    }
+
+    return ret;
+}
+
+/* Perform BAT hit & translation */
+static inline void bat_size_prot(CPUState *env, target_ulong *blp, int *validp,
+                                 int *protp, target_ulong *BATu,
+                                 target_ulong *BATl)
+{
+    target_ulong bl;
+    int pp, valid, prot;
+
+    bl = (*BATu & 0x00001FFC) << 15;
+    valid = 0;
+    prot = 0;
+    if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
+        ((msr_pr != 0) && (*BATu & 0x00000001))) {
+        valid = 1;
+        pp = *BATl & 0x00000003;
+        if (pp != 0) {
+            prot = PAGE_READ | PAGE_EXEC;
+            if (pp == 0x2)
+                prot |= PAGE_WRITE;
+        }
+    }
+    *blp = bl;
+    *validp = valid;
+    *protp = prot;
+}
+
+static inline void bat_601_size_prot(CPUState *env, target_ulong *blp,
+                                     int *validp, int *protp,
+                                     target_ulong *BATu, target_ulong *BATl)
+{
+    target_ulong bl;
+    int key, pp, valid, prot;
+
+    bl = (*BATl & 0x0000003F) << 17;
+    LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
+             (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
+    prot = 0;
+    valid = (*BATl >> 6) & 1;
+    if (valid) {
+        pp = *BATu & 0x00000003;
+        if (msr_pr == 0)
+            key = (*BATu >> 3) & 1;
+        else
+            key = (*BATu >> 2) & 1;
+        prot = pp_check(key, pp, 0);
+    }
+    *blp = bl;
+    *validp = valid;
+    *protp = prot;
+}
+
+static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
+                          int rw, int type)
+{
+    target_ulong *BATlt, *BATut, *BATu, *BATl;
+    target_ulong BEPIl, BEPIu, bl;
+    int i, valid, prot;
+    int ret = -1;
+
+    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
+             type == ACCESS_CODE ? 'I' : 'D', virtual);
+    switch (type) {
+    case ACCESS_CODE:
+        BATlt = env->IBAT[1];
+        BATut = env->IBAT[0];
+        break;
+    default:
+        BATlt = env->DBAT[1];
+        BATut = env->DBAT[0];
+        break;
+    }
+    for (i = 0; i < env->nb_BATs; i++) {
+        BATu = &BATut[i];
+        BATl = &BATlt[i];
+        BEPIu = *BATu & 0xF0000000;
+        BEPIl = *BATu & 0x0FFE0000;
+        if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+            bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+        } else {
+            bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+        }
+        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+                 " BATl " TARGET_FMT_lx "\n", __func__,
+                 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
+        if ((virtual & 0xF0000000) == BEPIu &&
+            ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
+            /* BAT matches */
+            if (valid != 0) {
+                /* Get physical address */
+                ctx->raddr = (*BATl & 0xF0000000) |
+                    ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
+                    (virtual & 0x0001F000);
+                /* Compute access rights */
+                ctx->prot = prot;
+                ret = check_prot(ctx->prot, rw, type);
+                if (ret == 0)
+                    LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
+                             i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+                             ctx->prot & PAGE_WRITE ? 'W' : '-');
+                break;
+            }
+        }
+    }
+    if (ret < 0) {
+#if defined(DEBUG_BATS)
+        if (qemu_log_enabled()) {
+            LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
+            for (i = 0; i < 4; i++) {
+                BATu = &BATut[i];
+                BATl = &BATlt[i];
+                BEPIu = *BATu & 0xF0000000;
+                BEPIl = *BATu & 0x0FFE0000;
+                bl = (*BATu & 0x00001FFC) << 15;
+                LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+                         " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " "
+                         TARGET_FMT_lx " " TARGET_FMT_lx "\n",
+                         __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+                         *BATu, *BATl, BEPIu, BEPIl, bl);
+            }
+        }
+#endif
+    }
+    /* No hit */
+    return ret;
+}
+
+static inline target_phys_addr_t get_pteg_offset(CPUState *env,
+                                                 target_phys_addr_t hash,
+                                                 int pte_size)
+{
+    return (hash * pte_size * 8) & env->htab_mask;
+}
+
+/* PTE table lookup */
+static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
+                            int rw, int type, int target_page_bits)
+{
+    target_phys_addr_t pteg_off;
+    target_ulong pte0, pte1;
+    int i, good = -1;
+    int ret, r;
+
+    ret = -1; /* No entry found */
+    pteg_off = get_pteg_offset(env, ctx->hash[h],
+                               is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
+    for (i = 0; i < 8; i++) {
+#if defined(TARGET_PPC64)
+        if (is_64b) {
+            if (env->external_htab) {
+                pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
+                pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
+            } else {
+                pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+                pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+            }
+
+            /* We have a TLB that saves 4K pages, so let's
+             * split a huge page to 4k chunks */
+            if (target_page_bits != TARGET_PAGE_BITS)
+                pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
+                        & TARGET_PAGE_MASK;
+
+            r = pte64_check(ctx, pte0, pte1, h, rw, type);
+            LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
+                    TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+                    pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
+                    (int)((pte0 >> 1) & 1), ctx->ptem);
+        } else
+#endif
+        {
+            if (env->external_htab) {
+                pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
+                pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
+            } else {
+                pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+                pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+            }
+            r = pte32_check(ctx, pte0, pte1, h, rw, type);
+            LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
+                    TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+                    pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
+                    (int)((pte0 >> 6) & 1), ctx->ptem);
+        }
+        switch (r) {
+        case -3:
+            /* PTE inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            good = i;
+            break;
+        case -1:
+        default:
+            /* No PTE match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all PTEs consistency
+             *      but if we can speed-up the whole thing as the
+             *      result would be undefined if PTEs are not consistent.
+             */
+            ret = 0;
+            good = i;
+            goto done;
+        }
+    }
+    if (good != -1) {
+    done:
+        LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
+                ctx->raddr, ctx->prot, ret);
+        /* Update page flags */
+        pte1 = ctx->raddr;
+        if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+#if defined(TARGET_PPC64)
+            if (is_64b) {
+                if (env->external_htab) {
+                    stq_p(env->external_htab + pteg_off + (good * 16) + 8,
+                          pte1);
+                } else {
+                    stq_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 16) + 8, pte1);
+                }
+            } else
+#endif
+            {
+                if (env->external_htab) {
+                    stl_p(env->external_htab + pteg_off + (good * 8) + 4,
+                          pte1);
+                } else {
+                    stl_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 8) + 4, pte1);
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
+                           int type, int target_page_bits)
+{
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64)
+        return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
+#endif
+
+    return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
+}
+
+#if defined(TARGET_PPC64)
+static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
+{
+    uint64_t esid_256M, esid_1T;
+    int n;
+
+    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
+
+    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
+
+    for (n = 0; n < env->slb_nr; n++) {
+        ppc_slb_t *slb = &env->slb[n];
+
+        LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+                    PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+        /* We check for 1T matches on all MMUs here - if the MMU
+         * doesn't have 1T segment support, we will have prevented 1T
+         * entries from being inserted in the slbmte code. */
+        if (((slb->esid == esid_256M) &&
+             ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
+            || ((slb->esid == esid_1T) &&
+                ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
+            return slb;
+        }
+    }
+
+    return NULL;
+}
+
+void ppc_slb_invalidate_all (CPUPPCState *env)
+{
+    int n, do_invalidate;
+
+    do_invalidate = 0;
+    /* XXX: Warning: slbia never invalidates the first segment */
+    for (n = 1; n < env->slb_nr; n++) {
+        ppc_slb_t *slb = &env->slb[n];
+
+        if (slb->esid & SLB_ESID_V) {
+            slb->esid &= ~SLB_ESID_V;
+            /* XXX: given the fact that segment size is 256 MB or 1TB,
+             *      and we still don't have a tlb_flush_mask(env, n, mask)
+             *      in Qemu, we just invalidate all TLBs
+             */
+            do_invalidate = 1;
+        }
+    }
+    if (do_invalidate)
+        tlb_flush(env, 1);
+}
+
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
+{
+    ppc_slb_t *slb;
+
+    slb = slb_lookup(env, T0);
+    if (!slb) {
+        return;
+    }
+
+    if (slb->esid & SLB_ESID_V) {
+        slb->esid &= ~SLB_ESID_V;
+
+        /* XXX: given the fact that segment size is 256 MB or 1TB,
+         *      and we still don't have a tlb_flush_mask(env, n, mask)
+         *      in Qemu, we just invalidate all TLBs
+         */
+        tlb_flush(env, 1);
+    }
+}
+
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
+
+    if (rb & (0x1000 - env->slb_nr)) {
+        return -1; /* Reserved bits set or slot too high */
+    }
+    if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
+        return -1; /* Bad segment size */
+    }
+    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
+        return -1; /* 1T segment on MMU that doesn't support it */
+    }
+
+    /* Mask out the slot number as we store the entry */
+    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
+    slb->vsid = rs;
+
+    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
+            " %016" PRIx64 "\n", __func__, slot, rb, rs,
+            slb->esid, slb->vsid);
+
+    return 0;
+}
+
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
+
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
+
+    *rt = slb->esid;
+    return 0;
+}
+
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
+
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
+
+    *rt = slb->vsid;
+    return 0;
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* Perform segment based translation */
+static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
+                              target_ulong eaddr, int rw, int type)
+{
+    target_phys_addr_t hash;
+    target_ulong vsid;
+    int ds, pr, target_page_bits;
+    int ret, ret2;
+
+    pr = msr_pr;
+    ctx->eaddr = eaddr;
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64) {
+        ppc_slb_t *slb;
+        target_ulong pageaddr;
+        int segment_bits;
+
+        LOG_MMU("Check SLBs\n");
+        slb = slb_lookup(env, eaddr);
+        if (!slb) {
+            return -5;
+        }
+
+        if (slb->vsid & SLB_VSID_B) {
+            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+            segment_bits = 40;
+        } else {
+            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+            segment_bits = 28;
+        }
+
+        target_page_bits = (slb->vsid & SLB_VSID_L)
+            ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+        ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+                      : (slb->vsid & SLB_VSID_KS));
+        ds = 0;
+        ctx->nx = !!(slb->vsid & SLB_VSID_N);
+
+        pageaddr = eaddr & ((1ULL << segment_bits)
+                            - (1ULL << target_page_bits));
+        if (slb->vsid & SLB_VSID_B) {
+            hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+        } else {
+            hash = vsid ^ (pageaddr >> target_page_bits);
+        }
+        /* Only 5 bits of the page index are used in the AVPN */
+        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
+            ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+    } else
+#endif /* defined(TARGET_PPC64) */
+    {
+        target_ulong sr, pgidx;
+
+        sr = env->sr[eaddr >> 28];
+        ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
+                    ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
+        ds = sr & 0x80000000 ? 1 : 0;
+        ctx->nx = sr & 0x10000000 ? 1 : 0;
+        vsid = sr & 0x00FFFFFF;
+        target_page_bits = TARGET_PAGE_BITS;
+        LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+                TARGET_FMT_lx " lr=" TARGET_FMT_lx
+                " ir=%d dr=%d pr=%d %d t=%d\n",
+                eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+                (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+        pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+        hash = vsid ^ pgidx;
+        ctx->ptem = (vsid << 7) | (pgidx >> 10);
+    }
+    LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
+            ctx->key, ds, ctx->nx, vsid);
+    ret = -1;
+    if (!ds) {
+        /* Check if instruction fetch is allowed, if needed */
+        if (type != ACCESS_CODE || ctx->nx == 0) {
+            /* Page address translation */
+            LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+                    " hash " TARGET_FMT_plx "\n",
+                    env->htab_base, env->htab_mask, hash);
+            ctx->hash[0] = hash;
+            ctx->hash[1] = ~hash;
+
+            /* Initialize real address with an invalid value */
+            ctx->raddr = (target_phys_addr_t)-1ULL;
+            if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+                         env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
+                /* Software TLB search */
+                ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+            } else {
+                LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                        " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+                        " hash=" TARGET_FMT_plx "\n",
+                        env->htab_base, env->htab_mask, vsid, ctx->ptem,
+                        ctx->hash[0]);
+                /* Primary table lookup */
+                ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
+                if (ret < 0) {
+                    /* Secondary table lookup */
+                    if (eaddr != 0xEFFFFFFF)
+                        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                                " hash=" TARGET_FMT_plx "\n", env->htab_base,
+                                env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+                    ret2 = find_pte(env, ctx, 1, rw, type,
+                                    target_page_bits);
+                    if (ret2 != -1)
+                        ret = ret2;
+                }
+            }
+#if defined (DUMP_PAGE_TABLES)
+            if (qemu_log_enabled()) {
+                target_phys_addr_t curaddr;
+                uint32_t a0, a1, a2, a3;
+                qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+                         "\n", sdr, mask + 0x80);
+                for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+                     curaddr += 16) {
+                    a0 = ldl_phys(curaddr);
+                    a1 = ldl_phys(curaddr + 4);
+                    a2 = ldl_phys(curaddr + 8);
+                    a3 = ldl_phys(curaddr + 12);
+                    if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+                        qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+                                 curaddr, a0, a1, a2, a3);
+                    }
+                }
+            }
+#endif
+        } else {
+            LOG_MMU("No access allowed\n");
+            ret = -3;
+        }
+    } else {
+        target_ulong sr;
+        LOG_MMU("direct store...\n");
+        /* Direct-store segment : absolutely *BUGGY* for now */
+
+        /* Direct-store implies a 32-bit MMU.
+         * Check the Segment Register's bus unit ID (BUID).
+         */
+        sr = env->sr[eaddr >> 28];
+        if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+            /* Memory-forced I/O controller interface access */
+            /* If T=1 and BUID=x'07F', the 601 performs a memory access
+             * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+             */
+            ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+            return 0;
+        }
+
+        switch (type) {
+        case ACCESS_INT:
+            /* Integer load/store : only access allowed */
+            break;
+        case ACCESS_CODE:
+            /* No code fetch is allowed in direct-store areas */
+            return -4;
+        case ACCESS_FLOAT:
+            /* Floating point load/store */
+            return -4;
+        case ACCESS_RES:
+            /* lwarx, ldarx or srwcx. */
+            return -4;
+        case ACCESS_CACHE:
+            /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
+            /* Should make the instruction do no-op.
+             * As it already do no-op, it's quite easy :-)
+             */
+            ctx->raddr = eaddr;
+            return 0;
+        case ACCESS_EXT:
+            /* eciwx or ecowx */
+            return -4;
+        default:
+            qemu_log("ERROR: instruction should not need "
+                        "address translation\n");
+            return -4;
+        }
+        if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+            ctx->raddr = eaddr;
+            ret = 2;
+        } else {
+            ret = -2;
+        }
+    }
+
+    return ret;
+}
+
+/* Generic TLB check function for embedded PowerPC implementations */
+int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
+                     target_phys_addr_t *raddrp,
+                     target_ulong address, uint32_t pid, int ext,
+                     int i)
+{
+    target_ulong mask;
+
+    /* Check valid flag */
+    if (!(tlb->prot & PAGE_VALID)) {
+        return -1;
+    }
+    mask = ~(tlb->size - 1);
+    LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
+              " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
+              mask, (uint32_t)tlb->PID, tlb->prot);
+    /* Check PID */
+    if (tlb->PID != 0 && tlb->PID != pid)
+        return -1;
+    /* Check effective address */
+    if ((address & mask) != tlb->EPN)
+        return -1;
+    *raddrp = (tlb->RPN & mask) | (address & ~mask);
+#if (TARGET_PHYS_ADDR_BITS >= 36)
+    if (ext) {
+        /* Extend the physical address to 36 bits */
+        *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
+    }
+#endif
+
+    return 0;
+}
+
+/* Generic TLB search function for PowerPC embedded implementations */
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret;
+
+    /* Default return value is no match */
+    ret = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb.tlbe[i];
+        if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
+            ret = i;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/* Helpers specific to PowerPC 40x implementations */
+static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
+{
+    ppcemb_tlb_t *tlb;
+    int i;
+
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb.tlbe[i];
+        tlb->prot &= ~PAGE_VALID;
+    }
+    tlb_flush(env, 1);
+}
+
+static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
+                                              target_ulong eaddr, uint32_t pid)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    target_ulong page, end;
+    int i;
+
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb.tlbe[i];
+        if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
+            end = tlb->EPN + tlb->size;
+            for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+            tlb->prot &= ~PAGE_VALID;
+            break;
+        }
+    }
+#else
+    ppc4xx_tlb_invalidate_all(env);
+#endif
+}
+
+static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                 target_ulong address, int rw, int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret, zsel, zpr, pr;
+
+    ret = -1;
+    raddr = (target_phys_addr_t)-1ULL;
+    pr = msr_pr;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb.tlbe[i];
+        if (ppcemb_tlb_check(env, tlb, &raddr, address,
+                             env->spr[SPR_40x_PID], 0, i) < 0)
+            continue;
+        zsel = (tlb->attr >> 4) & 0xF;
+        zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
+        LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
+                    __func__, i, zsel, zpr, rw, tlb->attr);
+        /* Check execute enable bit */
+        switch (zpr) {
+        case 0x2:
+            if (pr != 0)
+                goto check_perms;
+            /* No break here */
+        case 0x3:
+            /* All accesses granted */
+            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+            ret = 0;
+            break;
+        case 0x0:
+            if (pr != 0) {
+                /* Raise Zone protection fault.  */
+                env->spr[SPR_40x_ESR] = 1 << 22;
+                ctx->prot = 0;
+                ret = -2;
+                break;
+            }
+            /* No break here */
+        case 0x1:
+        check_perms:
+            /* Check from TLB entry */
+            ctx->prot = tlb->prot;
+            ret = check_prot(ctx->prot, rw, access_type);
+            if (ret == -2)
+                env->spr[SPR_40x_ESR] = 0;
+            break;
+        }
+        if (ret >= 0) {
+            ctx->raddr = raddr;
+            LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                      " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                      ret);
+            return 0;
+        }
+    }
+    LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+              " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+
+    return ret;
+}
+
+void store_40x_sler (CPUPPCState *env, uint32_t val)
+{
+    /* XXX: TO BE FIXED */
+    if (val != 0x00000000) {
+        cpu_abort(env, "Little-endian regions are not supported by now\n");
+    }
+    env->spr[SPR_405_SLER] = val;
+}
+
+static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
+                                      target_phys_addr_t *raddr, int *prot,
+                                      target_ulong address, int rw,
+                                      int access_type, int i)
+{
+    int ret, _prot;
+
+    if (ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID],
+                         !env->nb_pids, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID1] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID2] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    LOG_SWTLB("%s: TLB entry not found\n", __func__);
+    return -1;
+
+found_tlb:
+
+    if (msr_pr != 0) {
+        _prot = tlb->prot & 0xF;
+    } else {
+        _prot = (tlb->prot >> 4) & 0xF;
+    }
+
+    /* Check the address space */
+    if (access_type == ACCESS_CODE) {
+        if (msr_ir != (tlb->attr & 1)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if (_prot & PAGE_EXEC) {
+            LOG_SWTLB("%s: good TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+        ret = -3;
+    } else {
+        if (msr_dr != (tlb->attr & 1)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+            LOG_SWTLB("%s: found TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+        ret = -2;
+    }
+
+    return ret;
+}
+
+static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                          target_ulong address, int rw,
+                                          int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret;
+
+    ret = -1;
+    raddr = (target_phys_addr_t)-1ULL;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb.tlbe[i];
+        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+                                 access_type, i);
+        if (!ret) {
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
+
+    return ret;
+}
+
+void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
+{
+    int tlb_size;
+    int i, j;
+    ppcmas_tlb_t *tlb = env->tlb.tlbm;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        if (flags & (1 << i)) {
+            tlb_size = booke206_tlb_size(env, i);
+            for (j = 0; j < tlb_size; j++) {
+                if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
+                    tlb[j].mas1 &= ~MAS1_VALID;
+                }
+            }
+        }
+        tlb += booke206_tlb_size(env, i);
+    }
+
+    tlb_flush(env, 1);
+}
+
+target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    uint32_t tlbncfg;
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    target_phys_addr_t tlbm_size;
+
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+
+    if (tlbncfg & TLBnCFG_AVAIL) {
+        tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+    } else {
+        tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+    }
+
+    return (1 << (tlbm_size << 1)) << 10;
+}
+
+/* TLB check function for MAS based SoftTLBs */
+int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                     target_phys_addr_t *raddrp,
+                     target_ulong address, uint32_t pid)
+{
+    target_ulong mask;
+    uint32_t tlb_pid;
+
+    /* Check valid flag */
+    if (!(tlb->mas1 & MAS1_VALID)) {
+        return -1;
+    }
+
+    mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+    LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
+              PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
+              __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
+              tlb->mas8);
+
+    /* Check PID */
+    tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
+    if (tlb_pid != 0 && tlb_pid != pid) {
+        return -1;
+    }
+
+    /* Check effective address */
+    if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
+        return -1;
+    }
+    *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+
+    return 0;
+}
+
+static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb,
+                                 target_phys_addr_t *raddr, int *prot,
+                                 target_ulong address, int rw,
+                                 int access_type)
+{
+    int ret;
+    int _prot = 0;
+
+    if (ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID]) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID1] &&
+        ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID1]) >= 0) {
+        goto found_tlb;
+    }
+
+    if (env->spr[SPR_BOOKE_PID2] &&
+        ppcmas_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID2]) >= 0) {
+        goto found_tlb;
+    }
+
+    LOG_SWTLB("%s: TLB entry not found\n", __func__);
+    return -1;
+
+found_tlb:
+
+    if (msr_pr != 0) {
+        if (tlb->mas7_3 & MAS3_UR) {
+            _prot |= PAGE_READ;
+        }
+        if (tlb->mas7_3 & MAS3_UW) {
+            _prot |= PAGE_WRITE;
+        }
+        if (tlb->mas7_3 & MAS3_UX) {
+            _prot |= PAGE_EXEC;
+        }
+    } else {
+        if (tlb->mas7_3 & MAS3_SR) {
+            _prot |= PAGE_READ;
+        }
+        if (tlb->mas7_3 & MAS3_SW) {
+            _prot |= PAGE_WRITE;
+        }
+        if (tlb->mas7_3 & MAS3_SX) {
+            _prot |= PAGE_EXEC;
+        }
+    }
+
+    /* Check the address space and permissions */
+    if (access_type == ACCESS_CODE) {
+        if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if (_prot & PAGE_EXEC) {
+            LOG_SWTLB("%s: good TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+        ret = -3;
+    } else {
+        if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+            LOG_SWTLB("%s: AS doesn't match\n", __func__);
+            return -1;
+        }
+
+        *prot = _prot;
+        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+            LOG_SWTLB("%s: found TLB!\n", __func__);
+            return 0;
+        }
+
+        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+        ret = -2;
+    }
+
+    return ret;
+}
+
+static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
+                                            target_ulong address, int rw,
+                                            int access_type)
+{
+    ppcmas_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, j, ret;
+
+    ret = -1;
+    raddr = (target_phys_addr_t)-1ULL;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int ways = booke206_tlb_ways(env, i);
+
+        for (j = 0; j < ways; j++) {
+            tlb = booke206_get_tlbm(env, i, address, j);
+            ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
+                                        rw, access_type);
+            if (ret != -1) {
+                goto found_tlb;
+            }
+        }
+    }
+
+found_tlb:
+
+    if (ret >= 0) {
+        ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
+
+    return ret;
+}
+
+static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
+                                 target_ulong eaddr, int rw)
+{
+    int in_plb, ret;
+
+    ctx->raddr = eaddr;
+    ctx->prot = PAGE_READ | PAGE_EXEC;
+    ret = 0;
+    switch (env->mmu_model) {
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_601:
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_REAL:
+    case POWERPC_MMU_BOOKE:
+        ctx->prot |= PAGE_WRITE;
+        break;
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_620:
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
+        /* Real address are 60 bits long */
+        ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
+        ctx->prot |= PAGE_WRITE;
+        break;
+#endif
+    case POWERPC_MMU_SOFT_4xx_Z:
+        if (unlikely(msr_pe != 0)) {
+            /* 403 family add some particular protections,
+             * using PBL/PBU registers for accesses with no translation.
+             */
+            in_plb =
+                /* Check PLB validity */
+                (env->pb[0] < env->pb[1] &&
+                 /* and address in plb area */
+                 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+                (env->pb[2] < env->pb[3] &&
+                 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+            if (in_plb ^ msr_px) {
+                /* Access in protected area */
+                if (rw == 1) {
+                    /* Access is not allowed */
+                    ret = -2;
+                }
+            } else {
+                /* Read-write access is allowed */
+                ctx->prot |= PAGE_WRITE;
+            }
+        }
+        break;
+    case POWERPC_MMU_MPC8xx:
+        /* XXX: TODO */
+        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE206:
+        cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
+        break;
+    default:
+        cpu_abort(env, "Unknown or invalid MMU model\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+                          int rw, int access_type)
+{
+    int ret;
+
+#if 0
+    qemu_log("%s\n", __func__);
+#endif
+    if ((access_type == ACCESS_CODE && msr_ir == 0) ||
+        (access_type != ACCESS_CODE && msr_dr == 0)) {
+        if (env->mmu_model == POWERPC_MMU_BOOKE) {
+            /* The BookE MMU always performs address translation. The
+               IS and DS bits only affect the address space.  */
+            ret = mmubooke_get_physical_address(env, ctx, eaddr,
+                                                rw, access_type);
+        } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+            ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+                                                   access_type);
+        } else {
+            /* No address translation.  */
+            ret = check_physical(env, ctx, eaddr, rw);
+        }
+    } else {
+        ret = -1;
+        switch (env->mmu_model) {
+        case POWERPC_MMU_32B:
+        case POWERPC_MMU_601:
+        case POWERPC_MMU_SOFT_6xx:
+        case POWERPC_MMU_SOFT_74xx:
+            /* Try to find a BAT */
+            if (env->nb_BATs != 0)
+                ret = get_bat(env, ctx, eaddr, rw, access_type);
+#if defined(TARGET_PPC64)
+        case POWERPC_MMU_620:
+        case POWERPC_MMU_64B:
+        case POWERPC_MMU_2_06:
+#endif
+            if (ret < 0) {
+                /* We didn't match any BAT entry or don't have BATs */
+                ret = get_segment(env, ctx, eaddr, rw, access_type);
+            }
+            break;
+        case POWERPC_MMU_SOFT_4xx:
+        case POWERPC_MMU_SOFT_4xx_Z:
+            ret = mmu40x_get_physical_address(env, ctx, eaddr,
+                                              rw, access_type);
+            break;
+        case POWERPC_MMU_BOOKE:
+            ret = mmubooke_get_physical_address(env, ctx, eaddr,
+                                                rw, access_type);
+            break;
+        case POWERPC_MMU_BOOKE206:
+            ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+                                               access_type);
+            break;
+        case POWERPC_MMU_MPC8xx:
+            /* XXX: TODO */
+            cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+            break;
+        case POWERPC_MMU_REAL:
+            cpu_abort(env, "PowerPC in real mode do not do any translation\n");
+            return -1;
+        default:
+            cpu_abort(env, "Unknown or invalid MMU model\n");
+            return -1;
+        }
+    }
+#if 0
+    qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
+             __func__, eaddr, ret, ctx->raddr);
+#endif
+
+    return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+    mmu_ctx_t ctx;
+
+    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
+        return -1;
+
+    return ctx.raddr & TARGET_PAGE_MASK;
+}
+
+static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
+                                     int rw)
+{
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+    env->spr[SPR_BOOKE_MAS3] = 0;
+    env->spr[SPR_BOOKE_MAS6] = 0;
+    env->spr[SPR_BOOKE_MAS7] = 0;
+
+    /* AS */
+    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
+    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
+
+    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
+    case MAS4_TIDSELD_PID0:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID1:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID2:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
+        break;
+    }
+
+    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= booke206_tlb_ways(env, 0) - 1;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+/* Perform address translation */
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    mmu_ctx_t ctx;
+    int access_type;
+    int ret = 0;
+
+    if (rw == 2) {
+        /* code access */
+        rw = 0;
+        access_type = ACCESS_CODE;
+    } else {
+        /* data access */
+        access_type = env->access_type;
+    }
+    ret = get_physical_address(env, &ctx, address, rw, access_type);
+    if (ret == 0) {
+        tlb_set_page(env, address & TARGET_PAGE_MASK,
+                     ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+                     mmu_idx, TARGET_PAGE_SIZE);
+        ret = 0;
+    } else if (ret < 0) {
+        LOG_MMU_STATE(env);
+        if (access_type == ACCESS_CODE) {
+            switch (ret) {
+            case -1:
+                /* No matches in page tables or TLB */
+                switch (env->mmu_model) {
+                case POWERPC_MMU_SOFT_6xx:
+                    env->exception_index = POWERPC_EXCP_IFTLB;
+                    env->error_code = 1 << 18;
+                    env->spr[SPR_IMISS] = address;
+                    env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+                    goto tlb_miss;
+                case POWERPC_MMU_SOFT_74xx:
+                    env->exception_index = POWERPC_EXCP_IFTLB;
+                    goto tlb_miss_74xx;
+                case POWERPC_MMU_SOFT_4xx:
+                case POWERPC_MMU_SOFT_4xx_Z:
+                    env->exception_index = POWERPC_EXCP_ITLB;
+                    env->error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case POWERPC_MMU_32B:
+                case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+                case POWERPC_MMU_620:
+                case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
+#endif
+                    env->exception_index = POWERPC_EXCP_ISI;
+                    env->error_code = 0x40000000;
+                    break;
+                case POWERPC_MMU_BOOKE206:
+                    booke206_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
+                case POWERPC_MMU_BOOKE:
+                    env->exception_index = POWERPC_EXCP_ITLB;
+                    env->error_code = 0;
+                    env->spr[SPR_BOOKE_DEAR] = address;
+                    return -1;
+                case POWERPC_MMU_MPC8xx:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+                    break;
+                case POWERPC_MMU_REAL:
+                    cpu_abort(env, "PowerPC in real mode should never raise "
+                              "any MMU exceptions\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
+                }
+                break;
+            case -2:
+                /* Access rights violation */
+                env->exception_index = POWERPC_EXCP_ISI;
+                env->error_code = 0x08000000;
+                break;
+            case -3:
+                /* No execute protection violation */
+                if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                    (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+                    env->spr[SPR_BOOKE_ESR] = 0x00000000;
+                }
+                env->exception_index = POWERPC_EXCP_ISI;
+                env->error_code = 0x10000000;
+                break;
+            case -4:
+                /* Direct store exception */
+                /* No code fetch is allowed in direct-store areas */
+                env->exception_index = POWERPC_EXCP_ISI;
+                env->error_code = 0x10000000;
+                break;
+#if defined(TARGET_PPC64)
+            case -5:
+                /* No match in segment table */
+                if (env->mmu_model == POWERPC_MMU_620) {
+                    env->exception_index = POWERPC_EXCP_ISI;
+                    /* XXX: this might be incorrect */
+                    env->error_code = 0x40000000;
+                } else {
+                    env->exception_index = POWERPC_EXCP_ISEG;
+                    env->error_code = 0;
+                }
+                break;
+#endif
+            }
+        } else {
+            switch (ret) {
+            case -1:
+                /* No matches in page tables or TLB */
+                switch (env->mmu_model) {
+                case POWERPC_MMU_SOFT_6xx:
+                    if (rw == 1) {
+                        env->exception_index = POWERPC_EXCP_DSTLB;
+                        env->error_code = 1 << 16;
+                    } else {
+                        env->exception_index = POWERPC_EXCP_DLTLB;
+                        env->error_code = 0;
+                    }
+                    env->spr[SPR_DMISS] = address;
+                    env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+                tlb_miss:
+                    env->error_code |= ctx.key << 19;
+                    env->spr[SPR_HASH1] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
+                    env->spr[SPR_HASH2] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
+                    break;
+                case POWERPC_MMU_SOFT_74xx:
+                    if (rw == 1) {
+                        env->exception_index = POWERPC_EXCP_DSTLB;
+                    } else {
+                        env->exception_index = POWERPC_EXCP_DLTLB;
+                    }
+                tlb_miss_74xx:
+                    /* Implement LRU algorithm */
+                    env->error_code = ctx.key << 19;
+                    env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
+                        ((env->last_way + 1) & (env->nb_ways - 1));
+                    env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
+                    break;
+                case POWERPC_MMU_SOFT_4xx:
+                case POWERPC_MMU_SOFT_4xx_Z:
+                    env->exception_index = POWERPC_EXCP_DTLB;
+                    env->error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    if (rw)
+                        env->spr[SPR_40x_ESR] = 0x00800000;
+                    else
+                        env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case POWERPC_MMU_32B:
+                case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+                case POWERPC_MMU_620:
+                case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
+#endif
+                    env->exception_index = POWERPC_EXCP_DSI;
+                    env->error_code = 0;
+                    env->spr[SPR_DAR] = address;
+                    if (rw == 1)
+                        env->spr[SPR_DSISR] = 0x42000000;
+                    else
+                        env->spr[SPR_DSISR] = 0x40000000;
+                    break;
+                case POWERPC_MMU_MPC8xx:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+                    break;
+                case POWERPC_MMU_BOOKE206:
+                    booke206_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
+                case POWERPC_MMU_BOOKE:
+                    env->exception_index = POWERPC_EXCP_DTLB;
+                    env->error_code = 0;
+                    env->spr[SPR_BOOKE_DEAR] = address;
+                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
+                    return -1;
+                case POWERPC_MMU_REAL:
+                    cpu_abort(env, "PowerPC in real mode should never raise "
+                              "any MMU exceptions\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
+                }
+                break;
+            case -2:
+                /* Access rights violation */
+                env->exception_index = POWERPC_EXCP_DSI;
+                env->error_code = 0;
+                if (env->mmu_model == POWERPC_MMU_SOFT_4xx
+                    || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
+                    env->spr[SPR_40x_DEAR] = address;
+                    if (rw) {
+                        env->spr[SPR_40x_ESR] |= 0x00800000;
+                    }
+                } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                           (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+                    env->spr[SPR_BOOKE_DEAR] = address;
+                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
+                } else {
+                    env->spr[SPR_DAR] = address;
+                    if (rw == 1) {
+                        env->spr[SPR_DSISR] = 0x0A000000;
+                    } else {
+                        env->spr[SPR_DSISR] = 0x08000000;
+                    }
+                }
+                break;
+            case -4:
+                /* Direct store exception */
+                switch (access_type) {
+                case ACCESS_FLOAT:
+                    /* Floating point load/store */
+                    env->exception_index = POWERPC_EXCP_ALIGN;
+                    env->error_code = POWERPC_EXCP_ALIGN_FP;
+                    env->spr[SPR_DAR] = address;
+                    break;
+                case ACCESS_RES:
+                    /* lwarx, ldarx or stwcx. */
+                    env->exception_index = POWERPC_EXCP_DSI;
+                    env->error_code = 0;
+                    env->spr[SPR_DAR] = address;
+                    if (rw == 1)
+                        env->spr[SPR_DSISR] = 0x06000000;
+                    else
+                        env->spr[SPR_DSISR] = 0x04000000;
+                    break;
+                case ACCESS_EXT:
+                    /* eciwx or ecowx */
+                    env->exception_index = POWERPC_EXCP_DSI;
+                    env->error_code = 0;
+                    env->spr[SPR_DAR] = address;
+                    if (rw == 1)
+                        env->spr[SPR_DSISR] = 0x06100000;
+                    else
+                        env->spr[SPR_DSISR] = 0x04100000;
+                    break;
+                default:
+                    printf("DSI: invalid exception (%d)\n", ret);
+                    env->exception_index = POWERPC_EXCP_PROGRAM;
+                    env->error_code =
+                        POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
+                    env->spr[SPR_DAR] = address;
+                    break;
+                }
+                break;
+#if defined(TARGET_PPC64)
+            case -5:
+                /* No match in segment table */
+                if (env->mmu_model == POWERPC_MMU_620) {
+                    env->exception_index = POWERPC_EXCP_DSI;
+                    env->error_code = 0;
+                    env->spr[SPR_DAR] = address;
+                    /* XXX: this might be incorrect */
+                    if (rw == 1)
+                        env->spr[SPR_DSISR] = 0x42000000;
+                    else
+                        env->spr[SPR_DSISR] = 0x40000000;
+                } else {
+                    env->exception_index = POWERPC_EXCP_DSEG;
+                    env->error_code = 0;
+                    env->spr[SPR_DAR] = address;
+                }
+                break;
+#endif
+            }
+        }
+#if 0
+        printf("%s: set exception to %d %02x\n", __func__,
+               env->exception, env->error_code);
+#endif
+        ret = 1;
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+/* BATs management */
+#if !defined(FLUSH_ALL_TLBS)
+static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
+                                     target_ulong mask)
+{
+    target_ulong base, end, page;
+
+    base = BATu & ~0x0001FFFF;
+    end = base + mask + 0x00020000;
+    LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
+             TARGET_FMT_lx ")\n", base, end, mask);
+    for (page = base; page != end; page += TARGET_PAGE_SIZE)
+        tlb_flush_page(env, page);
+    LOG_BATS("Flush done\n");
+}
+#endif
+
+static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
+                                  target_ulong value)
+{
+    LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
+             nr, ul == 0 ? 'u' : 'l', value, env->nip);
+}
+
+void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+
+    dump_store_bat(env, 'I', 0, nr, value);
+    if (env->IBAT[0][nr] != value) {
+        mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#endif
+        /* When storing valid upper BAT, mask BEPI and BRPN
+         * and invalidate all TLBs covered by this BAT
+         */
+        mask = (value << 15) & 0x0FFE0000UL;
+        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+            (value & ~0x0001FFFFUL & ~mask);
+        env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
+            (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+        tlb_flush(env, 1);
+#endif
+    }
+}
+
+void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
+{
+    dump_store_bat(env, 'I', 1, nr, value);
+    env->IBAT[1][nr] = value;
+}
+
+void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+
+    dump_store_bat(env, 'D', 0, nr, value);
+    if (env->DBAT[0][nr] != value) {
+        /* When storing valid upper BAT, mask BEPI and BRPN
+         * and invalidate all TLBs covered by this BAT
+         */
+        mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#endif
+        mask = (value << 15) & 0x0FFE0000UL;
+        env->DBAT[0][nr] = (value & 0x00001FFFUL) |
+            (value & ~0x0001FFFFUL & ~mask);
+        env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
+            (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#else
+        tlb_flush(env, 1);
+#endif
+    }
+}
+
+void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
+{
+    dump_store_bat(env, 'D', 1, nr, value);
+    env->DBAT[1][nr] = value;
+}
+
+void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+#if defined(FLUSH_ALL_TLBS)
+    int do_inval;
+#endif
+
+    dump_store_bat(env, 'I', 0, nr, value);
+    if (env->IBAT[0][nr] != value) {
+#if defined(FLUSH_ALL_TLBS)
+        do_inval = 0;
+#endif
+        mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+        if (env->IBAT[1][nr] & 0x40) {
+            /* Invalidate BAT only if it is valid */
+#if !defined(FLUSH_ALL_TLBS)
+            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+            do_inval = 1;
+#endif
+        }
+        /* When storing valid upper BAT, mask BEPI and BRPN
+         * and invalidate all TLBs covered by this BAT
+         */
+        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+            (value & ~0x0001FFFFUL & ~mask);
+        env->DBAT[0][nr] = env->IBAT[0][nr];
+        if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+            do_inval = 1;
+#endif
+        }
+#if defined(FLUSH_ALL_TLBS)
+        if (do_inval)
+            tlb_flush(env, 1);
+#endif
+    }
+}
+
+void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+#if defined(FLUSH_ALL_TLBS)
+    int do_inval;
+#endif
+
+    dump_store_bat(env, 'I', 1, nr, value);
+    if (env->IBAT[1][nr] != value) {
+#if defined(FLUSH_ALL_TLBS)
+        do_inval = 0;
+#endif
+        if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+            mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+            do_inval = 1;
+#endif
+        }
+        if (value & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+            mask = (value << 17) & 0x0FFE0000UL;
+            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+            do_inval = 1;
+#endif
+        }
+        env->IBAT[1][nr] = value;
+        env->DBAT[1][nr] = value;
+#if defined(FLUSH_ALL_TLBS)
+        if (do_inval)
+            tlb_flush(env, 1);
+#endif
+    }
+}
+
+/*****************************************************************************/
+/* TLB management */
+void ppc_tlb_invalidate_all (CPUPPCState *env)
+{
+    switch (env->mmu_model) {
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+        ppc6xx_tlb_invalidate_all(env);
+        break;
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_SOFT_4xx_Z:
+        ppc4xx_tlb_invalidate_all(env);
+        break;
+    case POWERPC_MMU_REAL:
+        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        break;
+    case POWERPC_MMU_MPC8xx:
+        /* XXX: TODO */
+        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE:
+        tlb_flush(env, 1);
+        break;
+    case POWERPC_MMU_BOOKE206:
+        booke206_flush_tlb(env, -1, 0);
+        break;
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_620:
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
+#endif /* defined(TARGET_PPC64) */
+        tlb_flush(env, 1);
+        break;
+    default:
+        /* XXX: TODO */
+        cpu_abort(env, "Unknown MMU model\n");
+        break;
+    }
+}
+
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    addr &= TARGET_PAGE_MASK;
+    switch (env->mmu_model) {
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+        ppc6xx_tlb_invalidate_virt(env, addr, 0);
+        if (env->id_tlbs == 1)
+            ppc6xx_tlb_invalidate_virt(env, addr, 1);
+        break;
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_SOFT_4xx_Z:
+        ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
+        break;
+    case POWERPC_MMU_REAL:
+        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        break;
+    case POWERPC_MMU_MPC8xx:
+        /* XXX: TODO */
+        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE:
+        /* XXX: TODO */
+        cpu_abort(env, "BookE MMU model is not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE206:
+        /* XXX: TODO */
+        cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
+        break;
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_601:
+        /* tlbie invalidate TLBs for all segments */
+        addr &= ~((target_ulong)-1ULL << 28);
+        /* XXX: this case should be optimized,
+         * giving a mask to tlb_flush_page
+         */
+        tlb_flush_page(env, addr | (0x0 << 28));
+        tlb_flush_page(env, addr | (0x1 << 28));
+        tlb_flush_page(env, addr | (0x2 << 28));
+        tlb_flush_page(env, addr | (0x3 << 28));
+        tlb_flush_page(env, addr | (0x4 << 28));
+        tlb_flush_page(env, addr | (0x5 << 28));
+        tlb_flush_page(env, addr | (0x6 << 28));
+        tlb_flush_page(env, addr | (0x7 << 28));
+        tlb_flush_page(env, addr | (0x8 << 28));
+        tlb_flush_page(env, addr | (0x9 << 28));
+        tlb_flush_page(env, addr | (0xA << 28));
+        tlb_flush_page(env, addr | (0xB << 28));
+        tlb_flush_page(env, addr | (0xC << 28));
+        tlb_flush_page(env, addr | (0xD << 28));
+        tlb_flush_page(env, addr | (0xE << 28));
+        tlb_flush_page(env, addr | (0xF << 28));
+        break;
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_620:
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
+        /* tlbie invalidate TLBs for all segments */
+        /* XXX: given the fact that there are too many segments to invalidate,
+         *      and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
+         *      we just invalidate all TLBs
+         */
+        tlb_flush(env, 1);
+        break;
+#endif /* defined(TARGET_PPC64) */
+    default:
+        /* XXX: TODO */
+        cpu_abort(env, "Unknown MMU model\n");
+        break;
+    }
+#else
+    ppc_tlb_invalidate_all(env);
+#endif
+}
+
+/*****************************************************************************/
+/* Special registers manipulation */
+#if defined(TARGET_PPC64)
+void ppc_store_asr (CPUPPCState *env, target_ulong value)
+{
+    if (env->asr != value) {
+        env->asr = value;
+        tlb_flush(env, 1);
+    }
+}
+#endif
+
+void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
+{
+    LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
+    if (env->spr[SPR_SDR1] != value) {
+        env->spr[SPR_SDR1] = value;
+#if defined(TARGET_PPC64)
+        if (env->mmu_model & POWERPC_MMU_64) {
+            target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+            if (htabsize > 28) {
+                fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
+                        " stored in SDR1\n", htabsize);
+                htabsize = 28;
+            }
+            env->htab_mask = (1ULL << (htabsize + 18)) - 1;
+            env->htab_base = value & SDR_64_HTABORG;
+        } else
+#endif /* defined(TARGET_PPC64) */
+        {
+            /* FIXME: Should check for valid HTABMASK values */
+            env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
+            env->htab_base = value & SDR_32_HTABORG;
+        }
+        tlb_flush(env, 1);
+    }
+}
+
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
+{
+    // XXX
+    return 0;
+}
+#endif
+
+void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
+{
+    LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
+            srnum, value, env->sr[srnum]);
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64) {
+        uint64_t rb = 0, rs = 0;
+
+        /* ESID = srnum */
+        rb |= ((uint32_t)srnum & 0xf) << 28;
+        /* Set the valid bit */
+        rb |= 1 << 27;
+        /* Index = ESID */
+        rb |= (uint32_t)srnum;
+
+        /* VSID = VSID */
+        rs |= (value & 0xfffffff) << 12;
+        /* flags = flags */
+        rs |= ((value >> 27) & 0xf) << 8;
+
+        ppc_store_slb(env, rb, rs);
+    } else
+#endif
+    if (env->sr[srnum] != value) {
+        env->sr[srnum] = value;
+/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
+   flusing the whole TLB. */
+#if !defined(FLUSH_ALL_TLBS) && 0
+        {
+            target_ulong page, end;
+            /* Invalidate 256 MB of virtual memory */
+            page = (16 << 20) * srnum;
+            end = page + (16 << 20);
+            for (; page != end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+        }
+#else
+        tlb_flush(env, 1);
+#endif
+    }
+}
+#endif /* !defined (CONFIG_USER_ONLY) */
+
+/* GDBstub can read and write MSR... */
+void ppc_store_msr (CPUPPCState *env, target_ulong value)
+{
+    hreg_store_msr(env, value, 0);
+}
+
+/*****************************************************************************/
+/* Exception processing */
+#if defined (CONFIG_USER_ONLY)
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+}
+
+void ppc_hw_interrupt (CPUState *env)
+{
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+}
+#else /* defined (CONFIG_USER_ONLY) */
+static inline void dump_syscall(CPUState *env)
+{
+    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
+                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+                  " nip=" TARGET_FMT_lx "\n",
+                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+                  ppc_dump_gpr(env, 6), env->nip);
+}
+
+/* Note that this function should be greatly optimized
+ * when called with a constant excp, from ppc_hw_interrupt
+ */
+static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
+{
+    target_ulong msr, new_msr, vector;
+    int srr0, srr1, asrr0, asrr1;
+    int lpes0, lpes1, lev;
+
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor mode */
+        lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
+        lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
+    } else {
+        /* Those values ensure we won't enter the hypervisor mode */
+        lpes0 = 0;
+        lpes1 = 1;
+    }
+
+    qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
+                  " => %08x (%02x)\n", env->nip, excp, env->error_code);
+
+    /* new srr1 value excluding must-be-zero bits */
+    msr = env->msr & ~0x783f0000ULL;
+
+    /* new interrupt handler msr */
+    new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+    /* target registers */
+    srr0 = SPR_SRR0;
+    srr1 = SPR_SRR1;
+    asrr0 = -1;
+    asrr1 = -1;
+
+    switch (excp) {
+    case POWERPC_EXCP_NONE:
+        /* Should never happen */
+        return;
+    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
+        switch (excp_model) {
+        case POWERPC_EXCP_40x:
+            srr0 = SPR_40x_SRR2;
+            srr1 = SPR_40x_SRR3;
+            break;
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        case POWERPC_EXCP_G2:
+            break;
+        default:
+            goto excp_invalid;
+        }
+        goto store_next;
+    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
+        if (msr_me == 0) {
+            /* Machine check exception is not enabled.
+             * Enter checkstop state.
+             */
+            if (qemu_log_enabled()) {
+                qemu_log("Machine check while not allowed. "
+                        "Entering checkstop state\n");
+            } else {
+                fprintf(stderr, "Machine check while not allowed. "
+                        "Entering checkstop state\n");
+            }
+            env->halted = 1;
+            env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+        }
+        if (0) {
+            /* XXX: find a suitable condition to enable the hypervisor mode */
+            new_msr |= (target_ulong)MSR_HVB;
+        }
+
+        /* machine check exceptions don't have ME set */
+        new_msr &= ~((target_ulong)1 << MSR_ME);
+
+        /* XXX: should also have something loaded in DAR / DSISR */
+        switch (excp_model) {
+        case POWERPC_EXCP_40x:
+            srr0 = SPR_40x_SRR2;
+            srr1 = SPR_40x_SRR3;
+            break;
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_MCSRR0;
+            srr1 = SPR_BOOKE_MCSRR1;
+            asrr0 = SPR_BOOKE_CSRR0;
+            asrr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        goto store_next;
+    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
+        LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
+                 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
+        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
+                 "\n", msr, env->nip);
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        msr |= env->error_code;
+        goto store_next;
+    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
+        if (lpes0 == 1)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        /* XXX: this is false */
+        /* Get rS/rD and rA from faulting opcode */
+        env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
+        goto store_current;
+    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
+        switch (env->error_code & ~0xF) {
+        case POWERPC_EXCP_FP:
+            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+                LOG_EXCP("Ignore floating point exception\n");
+                env->exception_index = POWERPC_EXCP_NONE;
+                env->error_code = 0;
+                return;
+            }
+            if (lpes1 == 0)
+                new_msr |= (target_ulong)MSR_HVB;
+            msr |= 0x00100000;
+            if (msr_fe0 == msr_fe1)
+                goto store_next;
+            msr |= 0x00010000;
+            break;
+        case POWERPC_EXCP_INVAL:
+            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
+            if (lpes1 == 0)
+                new_msr |= (target_ulong)MSR_HVB;
+            msr |= 0x00080000;
+            break;
+        case POWERPC_EXCP_PRIV:
+            if (lpes1 == 0)
+                new_msr |= (target_ulong)MSR_HVB;
+            msr |= 0x00040000;
+            break;
+        case POWERPC_EXCP_TRAP:
+            if (lpes1 == 0)
+                new_msr |= (target_ulong)MSR_HVB;
+            msr |= 0x00020000;
+            break;
+        default:
+            /* Should never occur */
+            cpu_abort(env, "Invalid program exception %d. Aborting\n",
+                      env->error_code);
+            break;
+        }
+        goto store_current;
+    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_current;
+    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
+        dump_syscall(env);
+        lev = env->error_code;
+        if ((lev == 1) && cpu_ppc_hypercall) {
+            cpu_ppc_hypercall(env);
+            return;
+        }
+        if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
+        goto store_current;
+    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
+        /* FIT on 4xx */
+        LOG_EXCP("FIT exception\n");
+        goto store_next;
+    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
+        LOG_EXCP("WDT exception\n");
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        goto store_next;
+    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
+        goto store_next;
+    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
+        goto store_next;
+    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_DSRR0;
+            srr1 = SPR_BOOKE_DSRR1;
+            asrr0 = SPR_BOOKE_CSRR0;
+            asrr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        /* XXX: TODO */
+        cpu_abort(env, "Debug exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
+        goto store_current;
+    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded floating point data exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded floating point round exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Performance counter exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Embedded doorbell interrupt is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded doorbell critical interrupt "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_RESET:     /* System reset exception                   */
+        if (msr_pow) {
+            /* indicate that we resumed from power save mode */
+            msr |= 0x10000;
+        } else {
+            new_msr &= ~((target_ulong)1 << MSR_ME);
+        }
+
+        if (0) {
+            /* XXX: find a suitable condition to enable the hypervisor mode */
+            new_msr |= (target_ulong)MSR_HVB;
+        }
+        goto store_next;
+    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSRR1;
+        new_msr |= (target_ulong)MSR_HVB;
+        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        goto store_next;
+    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_next;
+    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSRR1;
+        new_msr |= (target_ulong)MSR_HVB;
+        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        goto store_next;
+    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSRR1;
+        new_msr |= (target_ulong)MSR_HVB;
+        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        goto store_next;
+    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSRR1;
+        new_msr |= (target_ulong)MSR_HVB;
+        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        goto store_next;
+    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSRR1;
+        new_msr |= (target_ulong)MSR_HVB;
+        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        goto store_next;
+    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        goto store_current;
+    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
+        LOG_EXCP("PIT exception\n");
+        goto store_next;
+    case POWERPC_EXCP_IO:        /* IO error exception                       */
+        /* XXX: TODO */
+        cpu_abort(env, "601 IO error exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
+        /* XXX: TODO */
+        cpu_abort(env, "601 run mode exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
+        /* XXX: TODO */
+        cpu_abort(env, "602 emulation trap exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
+        if (lpes1 == 0) /* XXX: check this */
+            new_msr |= (target_ulong)MSR_HVB;
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+            goto tlb_miss_tgpr;
+        case POWERPC_EXCP_7x5:
+            goto tlb_miss;
+        case POWERPC_EXCP_74xx:
+            goto tlb_miss_74xx;
+        default:
+            cpu_abort(env, "Invalid instruction TLB miss exception\n");
+            break;
+        }
+        break;
+    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
+        if (lpes1 == 0) /* XXX: check this */
+            new_msr |= (target_ulong)MSR_HVB;
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+            goto tlb_miss_tgpr;
+        case POWERPC_EXCP_7x5:
+            goto tlb_miss;
+        case POWERPC_EXCP_74xx:
+            goto tlb_miss_74xx;
+        default:
+            cpu_abort(env, "Invalid data load TLB miss exception\n");
+            break;
+        }
+        break;
+    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
+        if (lpes1 == 0) /* XXX: check this */
+            new_msr |= (target_ulong)MSR_HVB;
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+        tlb_miss_tgpr:
+            /* Swap temporary saved registers with GPRs */
+            if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
+                new_msr |= (target_ulong)1 << MSR_TGPR;
+                hreg_swap_gpr_tgpr(env);
+            }
+            goto tlb_miss;
+        case POWERPC_EXCP_7x5:
+        tlb_miss:
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (qemu_log_enabled()) {
+                const char *es;
+                target_ulong *miss, *cmp;
+                int en;
+                if (excp == POWERPC_EXCP_IFTLB) {
+                    es = "I";
+                    en = 'I';
+                    miss = &env->spr[SPR_IMISS];
+                    cmp = &env->spr[SPR_ICMP];
+                } else {
+                    if (excp == POWERPC_EXCP_DLTLB)
+                        es = "DL";
+                    else
+                        es = "DS";
+                    en = 'D';
+                    miss = &env->spr[SPR_DMISS];
+                    cmp = &env->spr[SPR_DCMP];
+                }
+                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+                         env->error_code);
+            }
+#endif
+            msr |= env->crf[0] << 28;
+            msr |= env->error_code; /* key, D/I, S/L bits */
+            /* Set way using a LRU mechanism */
+            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+            break;
+        case POWERPC_EXCP_74xx:
+        tlb_miss_74xx:
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (qemu_log_enabled()) {
+                const char *es;
+                target_ulong *miss, *cmp;
+                int en;
+                if (excp == POWERPC_EXCP_IFTLB) {
+                    es = "I";
+                    en = 'I';
+                    miss = &env->spr[SPR_TLBMISS];
+                    cmp = &env->spr[SPR_PTEHI];
+                } else {
+                    if (excp == POWERPC_EXCP_DLTLB)
+                        es = "DL";
+                    else
+                        es = "DS";
+                    en = 'D';
+                    miss = &env->spr[SPR_TLBMISS];
+                    cmp = &env->spr[SPR_PTEHI];
+                }
+                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                         env->error_code);
+            }
+#endif
+            msr |= env->error_code; /* key bit */
+            break;
+        default:
+            cpu_abort(env, "Invalid data store TLB miss exception\n");
+            break;
+        }
+        goto store_next;
+    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
+        /* XXX: TODO */
+        cpu_abort(env, "Floating point assist exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
+        /* XXX: TODO */
+        cpu_abort(env, "DABR exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
+        /* XXX: TODO */
+        cpu_abort(env, "IABR exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_SMI:       /* System management interrupt              */
+        /* XXX: TODO */
+        cpu_abort(env, "SMI exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
+        /* XXX: TODO */
+        cpu_abort(env, "Thermal management exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
+        if (lpes1 == 0)
+            new_msr |= (target_ulong)MSR_HVB;
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Performance counter exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
+        /* XXX: TODO */
+        cpu_abort(env, "VPU assist exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "970 soft-patch exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "970 maintenance exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
+        /* XXX: TODO */
+        cpu_abort(env, "Maskable external exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
+        /* XXX: TODO */
+        cpu_abort(env, "Non maskable external exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    default:
+    excp_invalid:
+        cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
+        break;
+    store_current:
+        /* save current instruction location */
+        env->spr[srr0] = env->nip - 4;
+        break;
+    store_next:
+        /* save next instruction location */
+        env->spr[srr0] = env->nip;
+        break;
+    }
+    /* Save MSR */
+    env->spr[srr1] = msr;
+    /* If any alternate SRR register are defined, duplicate saved values */
+    if (asrr0 != -1)
+        env->spr[asrr0] = env->spr[srr0];
+    if (asrr1 != -1)
+        env->spr[asrr1] = env->spr[srr1];
+    /* If we disactivated any translation, flush TLBs */
+    if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
+        tlb_flush(env, 1);
+
+    if (msr_ile) {
+        new_msr |= (target_ulong)1 << MSR_LE;
+    }
+
+    /* Jump to handler */
+    vector = env->excp_vectors[excp];
+    if (vector == (target_ulong)-1ULL) {
+        cpu_abort(env, "Raised an exception without defined vector %d\n",
+                  excp);
+    }
+    vector |= env->excp_prefix;
+#if defined(TARGET_PPC64)
+    if (excp_model == POWERPC_EXCP_BOOKE) {
+        if (!msr_icm) {
+            vector = (uint32_t)vector;
+        } else {
+            new_msr |= (target_ulong)1 << MSR_CM;
+        }
+    } else {
+        if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
+            vector = (uint32_t)vector;
+        } else {
+            new_msr |= (target_ulong)1 << MSR_SF;
+        }
+    }
+#endif
+    /* XXX: we don't use hreg_store_msr here as already have treated
+     *      any special case that could occur. Just store MSR and update hflags
+     */
+    env->msr = new_msr & env->msr_mask;
+    hreg_compute_hflags(env);
+    env->nip = vector;
+    /* Reset exception state */
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+
+    if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+        (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+        /* XXX: The BookE changes address space when switching modes,
+                we should probably implement that as different MMU indexes,
+                but for the moment we do it the slow way and flush all.  */
+        tlb_flush(env, 1);
+    }
+}
+
+void do_interrupt (CPUState *env)
+{
+    powerpc_excp(env, env->excp_model, env->exception_index);
+}
+
+void ppc_hw_interrupt (CPUPPCState *env)
+{
+    int hdice;
+
+#if 0
+    qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
+                __func__, env, env->pending_interrupts,
+                env->interrupt_request, (int)msr_me, (int)msr_ee);
+#endif
+    /* External reset */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
+        return;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
+        return;
+    }
+#if 0 /* TODO */
+    /* External debug exception */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
+        return;
+    }
+#endif
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor mode */
+        hdice = env->spr[SPR_LPCR] & 1;
+    } else {
+        hdice = 0;
+    }
+    if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
+        /* Hypervisor decrementer exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
+            return;
+        }
+    }
+    if (msr_ce != 0) {
+        /* External critical interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
+            /* Taking a critical external interrupt does not clear the external
+             * critical interrupt status
+             */
+#if 0
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
+#endif
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
+            return;
+        }
+    }
+    if (msr_ee != 0) {
+        /* Watchdog timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
+            return;
+        }
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
+            return;
+        }
+        /* Fixed interval timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
+            return;
+        }
+        /* Programmable interval timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
+            return;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
+            return;
+        }
+        /* External interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+            /* Taking an external interrupt does not clear the external
+             * interrupt status
+             */
+#if 0
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
+            return;
+        }
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
+            return;
+        }
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
+            return;
+        }
+        /* Thermal interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
+            return;
+        }
+    }
+}
+#endif /* !CONFIG_USER_ONLY */
+
+void cpu_dump_rfi (target_ulong RA, target_ulong msr)
+{
+    qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
+             TARGET_FMT_lx "\n", RA, msr);
+}
+
+void cpu_reset(CPUPPCState *env)
+{
+    target_ulong msr;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    msr = (target_ulong)0;
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor mode */
+        msr |= (target_ulong)MSR_HVB;
+    }
+    msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
+    msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
+    msr |= (target_ulong)1 << MSR_EP;
+#if defined (DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr |= (target_ulong)1 << MSR_SE;
+    msr |= (target_ulong)1 << MSR_BE;
+#endif
+#if defined(CONFIG_USER_ONLY)
+    msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
+    msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
+    msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
+    msr |= (target_ulong)1 << MSR_PR;
+#else
+    env->excp_prefix = env->hreset_excp_prefix;
+    env->nip = env->hreset_vector | env->excp_prefix;
+    if (env->mmu_model != POWERPC_MMU_REAL)
+        ppc_tlb_invalidate_all(env);
+#endif
+    env->msr = msr & env->msr_mask;
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64)
+        env->msr |= (1ULL << MSR_SF);
+#endif
+    hreg_compute_hflags(env);
+    env->reserve_addr = (target_ulong)-1ULL;
+    /* Be sure no exception or interrupt is pending */
+    env->pending_interrupts = 0;
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+    /* Flush all TLBs */
+    tlb_flush(env, 1);
+}
+
+CPUPPCState *cpu_ppc_init (const char *cpu_model)
+{
+    CPUPPCState *env;
+    const ppc_def_t *def;
+
+    def = cpu_ppc_find_by_name(cpu_model);
+    if (!def)
+        return NULL;
+
+    env = qemu_mallocz(sizeof(CPUPPCState));
+    cpu_exec_init(env);
+    ppc_translate_init();
+    env->cpu_model_str = cpu_model;
+    cpu_ppc_register_internal(env, def);
+
+    qemu_init_vcpu(env);
+
+    return env;
+}
+
+void cpu_ppc_close (CPUPPCState *env)
+{
+    /* Should also remove all opcode tables... */
+    qemu_free(env);
+}
diff --git a/qemu-0.15.x/target-ppc/helper.h b/qemu-0.15.x/target-ppc/helper.h
new file mode 100644
index 0000000..470e42f
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/helper.h
@@ -0,0 +1,411 @@
+#include "def-helper.h"
+
+DEF_HELPER_2(raise_exception_err, void, i32, i32)
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_3(tw, void, tl, tl, i32)
+#if defined(TARGET_PPC64)
+DEF_HELPER_3(td, void, tl, tl, i32)
+#endif
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_1(store_msr, void, tl)
+DEF_HELPER_0(rfi, void)
+DEF_HELPER_0(rfsvc, void)
+DEF_HELPER_0(40x_rfci, void)
+DEF_HELPER_0(rfci, void)
+DEF_HELPER_0(rfdi, void)
+DEF_HELPER_0(rfmci, void)
+#if defined(TARGET_PPC64)
+DEF_HELPER_0(rfid, void)
+DEF_HELPER_0(hrfid, void)
+#endif
+#endif
+
+DEF_HELPER_2(lmw, void, tl, i32)
+DEF_HELPER_2(stmw, void, tl, i32)
+DEF_HELPER_3(lsw, void, tl, i32, i32)
+DEF_HELPER_4(lswx, void, tl, i32, i32, i32)
+DEF_HELPER_3(stsw, void, tl, i32, i32)
+DEF_HELPER_1(dcbz, void, tl)
+DEF_HELPER_1(dcbz_970, void, tl)
+DEF_HELPER_1(icbi, void, tl)
+DEF_HELPER_4(lscbx, tl, tl, i32, i32, i32)
+
+#if defined(TARGET_PPC64)
+DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_2(mulldo, i64, i64, i64)
+#endif
+
+DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_2(sraw, tl, tl, tl)
+#if defined(TARGET_PPC64)
+DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_2(srad, tl, tl, tl)
+#endif
+
+DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
+DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
+DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+
+DEF_HELPER_0(float_check_status, void)
+DEF_HELPER_0(reset_fpstatus, void)
+DEF_HELPER_2(compute_fprf, i32, i64, i32)
+DEF_HELPER_2(store_fpscr, void, i64, i32)
+DEF_HELPER_1(fpscr_clrbit, void, i32)
+DEF_HELPER_1(fpscr_setbit, void, i32)
+DEF_HELPER_1(float64_to_float32, i32, i64)
+DEF_HELPER_1(float32_to_float64, i64, i32)
+
+DEF_HELPER_3(fcmpo, void, i64, i64, i32)
+DEF_HELPER_3(fcmpu, void, i64, i64, i32)
+
+DEF_HELPER_1(fctiw, i64, i64)
+DEF_HELPER_1(fctiwz, i64, i64)
+#if defined(TARGET_PPC64)
+DEF_HELPER_1(fcfid, i64, i64)
+DEF_HELPER_1(fctid, i64, i64)
+DEF_HELPER_1(fctidz, i64, i64)
+#endif
+DEF_HELPER_1(frsp, i64, i64)
+DEF_HELPER_1(frin, i64, i64)
+DEF_HELPER_1(friz, i64, i64)
+DEF_HELPER_1(frip, i64, i64)
+DEF_HELPER_1(frim, i64, i64)
+
+DEF_HELPER_2(fadd, i64, i64, i64)
+DEF_HELPER_2(fsub, i64, i64, i64)
+DEF_HELPER_2(fmul, i64, i64, i64)
+DEF_HELPER_2(fdiv, i64, i64, i64)
+DEF_HELPER_3(fmadd, i64, i64, i64, i64)
+DEF_HELPER_3(fmsub, i64, i64, i64, i64)
+DEF_HELPER_3(fnmadd, i64, i64, i64, i64)
+DEF_HELPER_3(fnmsub, i64, i64, i64, i64)
+DEF_HELPER_1(fabs, i64, i64)
+DEF_HELPER_1(fnabs, i64, i64)
+DEF_HELPER_1(fneg, i64, i64)
+DEF_HELPER_1(fsqrt, i64, i64)
+DEF_HELPER_1(fre, i64, i64)
+DEF_HELPER_1(fres, i64, i64)
+DEF_HELPER_1(frsqrte, i64, i64)
+DEF_HELPER_3(fsel, i64, i64, i64, i64)
+
+#define dh_alias_avr ptr
+#define dh_ctype_avr ppc_avr_t *
+#define dh_is_signed_avr dh_is_signed_ptr
+
+DEF_HELPER_3(vaddubm, void, avr, avr, avr)
+DEF_HELPER_3(vadduhm, void, avr, avr, avr)
+DEF_HELPER_3(vadduwm, void, avr, avr, avr)
+DEF_HELPER_3(vsububm, void, avr, avr, avr)
+DEF_HELPER_3(vsubuhm, void, avr, avr, avr)
+DEF_HELPER_3(vsubuwm, void, avr, avr, avr)
+DEF_HELPER_3(vavgub, void, avr, avr, avr)
+DEF_HELPER_3(vavguh, void, avr, avr, avr)
+DEF_HELPER_3(vavguw, void, avr, avr, avr)
+DEF_HELPER_3(vavgsb, void, avr, avr, avr)
+DEF_HELPER_3(vavgsh, void, avr, avr, avr)
+DEF_HELPER_3(vavgsw, void, avr, avr, avr)
+DEF_HELPER_3(vminsb, void, avr, avr, avr)
+DEF_HELPER_3(vminsh, void, avr, avr, avr)
+DEF_HELPER_3(vminsw, void, avr, avr, avr)
+DEF_HELPER_3(vmaxsb, void, avr, avr, avr)
+DEF_HELPER_3(vmaxsh, void, avr, avr, avr)
+DEF_HELPER_3(vmaxsw, void, avr, avr, avr)
+DEF_HELPER_3(vminub, void, avr, avr, avr)
+DEF_HELPER_3(vminuh, void, avr, avr, avr)
+DEF_HELPER_3(vminuw, void, avr, avr, avr)
+DEF_HELPER_3(vmaxub, void, avr, avr, avr)
+DEF_HELPER_3(vmaxuh, void, avr, avr, avr)
+DEF_HELPER_3(vmaxuw, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequb, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequh, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequw, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtub, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtuh, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtuw, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsb, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsh, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsw, void, avr, avr, avr)
+DEF_HELPER_3(vcmpeqfp, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgefp, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtfp, void, avr, avr, avr)
+DEF_HELPER_3(vcmpbfp, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequb_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequh_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpequw_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtub_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtuh_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtuw_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsb_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsh_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtsw_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpeqfp_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgefp_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpgtfp_dot, void, avr, avr, avr)
+DEF_HELPER_3(vcmpbfp_dot, void, avr, avr, avr)
+DEF_HELPER_3(vmrglb, void, avr, avr, avr)
+DEF_HELPER_3(vmrglh, void, avr, avr, avr)
+DEF_HELPER_3(vmrglw, void, avr, avr, avr)
+DEF_HELPER_3(vmrghb, void, avr, avr, avr)
+DEF_HELPER_3(vmrghh, void, avr, avr, avr)
+DEF_HELPER_3(vmrghw, void, avr, avr, avr)
+DEF_HELPER_3(vmulesb, void, avr, avr, avr)
+DEF_HELPER_3(vmulesh, void, avr, avr, avr)
+DEF_HELPER_3(vmuleub, void, avr, avr, avr)
+DEF_HELPER_3(vmuleuh, void, avr, avr, avr)
+DEF_HELPER_3(vmulosb, void, avr, avr, avr)
+DEF_HELPER_3(vmulosh, void, avr, avr, avr)
+DEF_HELPER_3(vmuloub, void, avr, avr, avr)
+DEF_HELPER_3(vmulouh, void, avr, avr, avr)
+DEF_HELPER_3(vsrab, void, avr, avr, avr)
+DEF_HELPER_3(vsrah, void, avr, avr, avr)
+DEF_HELPER_3(vsraw, void, avr, avr, avr)
+DEF_HELPER_3(vsrb, void, avr, avr, avr)
+DEF_HELPER_3(vsrh, void, avr, avr, avr)
+DEF_HELPER_3(vsrw, void, avr, avr, avr)
+DEF_HELPER_3(vslb, void, avr, avr, avr)
+DEF_HELPER_3(vslh, void, avr, avr, avr)
+DEF_HELPER_3(vslw, void, avr, avr, avr)
+DEF_HELPER_3(vslo, void, avr, avr, avr)
+DEF_HELPER_3(vsro, void, avr, avr, avr)
+DEF_HELPER_3(vaddcuw, void, avr, avr, avr)
+DEF_HELPER_3(vsubcuw, void, avr, avr, avr)
+DEF_HELPER_2(lvsl, void, avr, tl);
+DEF_HELPER_2(lvsr, void, avr, tl);
+DEF_HELPER_3(vaddsbs, void, avr, avr, avr)
+DEF_HELPER_3(vaddshs, void, avr, avr, avr)
+DEF_HELPER_3(vaddsws, void, avr, avr, avr)
+DEF_HELPER_3(vsubsbs, void, avr, avr, avr)
+DEF_HELPER_3(vsubshs, void, avr, avr, avr)
+DEF_HELPER_3(vsubsws, void, avr, avr, avr)
+DEF_HELPER_3(vaddubs, void, avr, avr, avr)
+DEF_HELPER_3(vadduhs, void, avr, avr, avr)
+DEF_HELPER_3(vadduws, void, avr, avr, avr)
+DEF_HELPER_3(vsububs, void, avr, avr, avr)
+DEF_HELPER_3(vsubuhs, void, avr, avr, avr)
+DEF_HELPER_3(vsubuws, void, avr, avr, avr)
+DEF_HELPER_3(vrlb, void, avr, avr, avr)
+DEF_HELPER_3(vrlh, void, avr, avr, avr)
+DEF_HELPER_3(vrlw, void, avr, avr, avr)
+DEF_HELPER_3(vsl, void, avr, avr, avr)
+DEF_HELPER_3(vsr, void, avr, avr, avr)
+DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32)
+DEF_HELPER_2(vspltisb, void, avr, i32)
+DEF_HELPER_2(vspltish, void, avr, i32)
+DEF_HELPER_2(vspltisw, void, avr, i32)
+DEF_HELPER_3(vspltb, void, avr, avr, i32)
+DEF_HELPER_3(vsplth, void, avr, avr, i32)
+DEF_HELPER_3(vspltw, void, avr, avr, i32)
+DEF_HELPER_2(vupkhpx, void, avr, avr)
+DEF_HELPER_2(vupklpx, void, avr, avr)
+DEF_HELPER_2(vupkhsb, void, avr, avr)
+DEF_HELPER_2(vupkhsh, void, avr, avr)
+DEF_HELPER_2(vupklsb, void, avr, avr)
+DEF_HELPER_2(vupklsh, void, avr, avr)
+DEF_HELPER_4(vmsumubm, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmsummbm, void, avr, avr, avr, avr)
+DEF_HELPER_4(vsel, void, avr, avr, avr, avr)
+DEF_HELPER_4(vperm, void, avr, avr, avr, avr)
+DEF_HELPER_3(vpkshss, void, avr, avr, avr)
+DEF_HELPER_3(vpkshus, void, avr, avr, avr)
+DEF_HELPER_3(vpkswss, void, avr, avr, avr)
+DEF_HELPER_3(vpkswus, void, avr, avr, avr)
+DEF_HELPER_3(vpkuhus, void, avr, avr, avr)
+DEF_HELPER_3(vpkuwus, void, avr, avr, avr)
+DEF_HELPER_3(vpkuhum, void, avr, avr, avr)
+DEF_HELPER_3(vpkuwum, void, avr, avr, avr)
+DEF_HELPER_3(vpkpx, void, avr, avr, avr)
+DEF_HELPER_4(vmhaddshs, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmhraddshs, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmsumuhm, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmsumuhs, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmsumshm, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmsumshs, void, avr, avr, avr, avr)
+DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr)
+DEF_HELPER_1(mtvscr, void, avr);
+DEF_HELPER_2(lvebx, void, avr, tl)
+DEF_HELPER_2(lvehx, void, avr, tl)
+DEF_HELPER_2(lvewx, void, avr, tl)
+DEF_HELPER_2(stvebx, void, avr, tl)
+DEF_HELPER_2(stvehx, void, avr, tl)
+DEF_HELPER_2(stvewx, void, avr, tl)
+DEF_HELPER_3(vsumsws, void, avr, avr, avr)
+DEF_HELPER_3(vsum2sws, void, avr, avr, avr)
+DEF_HELPER_3(vsum4sbs, void, avr, avr, avr)
+DEF_HELPER_3(vsum4shs, void, avr, avr, avr)
+DEF_HELPER_3(vsum4ubs, void, avr, avr, avr)
+DEF_HELPER_3(vaddfp, void, avr, avr, avr)
+DEF_HELPER_3(vsubfp, void, avr, avr, avr)
+DEF_HELPER_3(vmaxfp, void, avr, avr, avr)
+DEF_HELPER_3(vminfp, void, avr, avr, avr)
+DEF_HELPER_2(vrefp, void, avr, avr)
+DEF_HELPER_2(vrsqrtefp, void, avr, avr)
+DEF_HELPER_4(vmaddfp, void, avr, avr, avr, avr)
+DEF_HELPER_4(vnmsubfp, void, avr, avr, avr, avr)
+DEF_HELPER_2(vexptefp, void, avr, avr)
+DEF_HELPER_2(vlogefp, void, avr, avr)
+DEF_HELPER_2(vrfim, void, avr, avr)
+DEF_HELPER_2(vrfin, void, avr, avr)
+DEF_HELPER_2(vrfip, void, avr, avr)
+DEF_HELPER_2(vrfiz, void, avr, avr)
+DEF_HELPER_3(vcfux, void, avr, avr, i32)
+DEF_HELPER_3(vcfsx, void, avr, avr, i32)
+DEF_HELPER_3(vctuxs, void, avr, avr, i32)
+DEF_HELPER_3(vctsxs, void, avr, avr, i32)
+
+DEF_HELPER_1(efscfsi, i32, i32)
+DEF_HELPER_1(efscfui, i32, i32)
+DEF_HELPER_1(efscfuf, i32, i32)
+DEF_HELPER_1(efscfsf, i32, i32)
+DEF_HELPER_1(efsctsi, i32, i32)
+DEF_HELPER_1(efsctui, i32, i32)
+DEF_HELPER_1(efsctsiz, i32, i32)
+DEF_HELPER_1(efsctuiz, i32, i32)
+DEF_HELPER_1(efsctsf, i32, i32)
+DEF_HELPER_1(efsctuf, i32, i32)
+DEF_HELPER_1(evfscfsi, i64, i64)
+DEF_HELPER_1(evfscfui, i64, i64)
+DEF_HELPER_1(evfscfuf, i64, i64)
+DEF_HELPER_1(evfscfsf, i64, i64)
+DEF_HELPER_1(evfsctsi, i64, i64)
+DEF_HELPER_1(evfsctui, i64, i64)
+DEF_HELPER_1(evfsctsiz, i64, i64)
+DEF_HELPER_1(evfsctuiz, i64, i64)
+DEF_HELPER_1(evfsctsf, i64, i64)
+DEF_HELPER_1(evfsctuf, i64, i64)
+DEF_HELPER_2(efsadd, i32, i32, i32)
+DEF_HELPER_2(efssub, i32, i32, i32)
+DEF_HELPER_2(efsmul, i32, i32, i32)
+DEF_HELPER_2(efsdiv, i32, i32, i32)
+DEF_HELPER_2(evfsadd, i64, i64, i64)
+DEF_HELPER_2(evfssub, i64, i64, i64)
+DEF_HELPER_2(evfsmul, i64, i64, i64)
+DEF_HELPER_2(evfsdiv, i64, i64, i64)
+DEF_HELPER_2(efststlt, i32, i32, i32)
+DEF_HELPER_2(efststgt, i32, i32, i32)
+DEF_HELPER_2(efststeq, i32, i32, i32)
+DEF_HELPER_2(efscmplt, i32, i32, i32)
+DEF_HELPER_2(efscmpgt, i32, i32, i32)
+DEF_HELPER_2(efscmpeq, i32, i32, i32)
+DEF_HELPER_2(evfststlt, i32, i64, i64)
+DEF_HELPER_2(evfststgt, i32, i64, i64)
+DEF_HELPER_2(evfststeq, i32, i64, i64)
+DEF_HELPER_2(evfscmplt, i32, i64, i64)
+DEF_HELPER_2(evfscmpgt, i32, i64, i64)
+DEF_HELPER_2(evfscmpeq, i32, i64, i64)
+DEF_HELPER_1(efdcfsi, i64, i32)
+DEF_HELPER_1(efdcfsid, i64, i64)
+DEF_HELPER_1(efdcfui, i64, i32)
+DEF_HELPER_1(efdcfuid, i64, i64)
+DEF_HELPER_1(efdctsi, i32, i64)
+DEF_HELPER_1(efdctui, i32, i64)
+DEF_HELPER_1(efdctsiz, i32, i64)
+DEF_HELPER_1(efdctsidz, i64, i64)
+DEF_HELPER_1(efdctuiz, i32, i64)
+DEF_HELPER_1(efdctuidz, i64, i64)
+DEF_HELPER_1(efdcfsf, i64, i32)
+DEF_HELPER_1(efdcfuf, i64, i32)
+DEF_HELPER_1(efdctsf, i32, i64)
+DEF_HELPER_1(efdctuf, i32, i64)
+DEF_HELPER_1(efscfd, i32, i64)
+DEF_HELPER_1(efdcfs, i64, i32)
+DEF_HELPER_2(efdadd, i64, i64, i64)
+DEF_HELPER_2(efdsub, i64, i64, i64)
+DEF_HELPER_2(efdmul, i64, i64, i64)
+DEF_HELPER_2(efddiv, i64, i64, i64)
+DEF_HELPER_2(efdtstlt, i32, i64, i64)
+DEF_HELPER_2(efdtstgt, i32, i64, i64)
+DEF_HELPER_2(efdtsteq, i32, i64, i64)
+DEF_HELPER_2(efdcmplt, i32, i64, i64)
+DEF_HELPER_2(efdcmpgt, i32, i64, i64)
+DEF_HELPER_2(efdcmpeq, i32, i64, i64)
+
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_1(4xx_tlbre_hi, tl, tl)
+DEF_HELPER_1(4xx_tlbre_lo, tl, tl)
+DEF_HELPER_2(4xx_tlbwe_hi, void, tl, tl)
+DEF_HELPER_2(4xx_tlbwe_lo, void, tl, tl)
+DEF_HELPER_1(4xx_tlbsx, tl, tl)
+DEF_HELPER_2(440_tlbre, tl, i32, tl)
+DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
+DEF_HELPER_1(440_tlbsx, tl, tl)
+DEF_HELPER_0(booke206_tlbre, void)
+DEF_HELPER_0(booke206_tlbwe, void)
+DEF_HELPER_1(booke206_tlbsx, void, tl)
+DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbflush, void, i32)
+DEF_HELPER_2(booke_setpid, void, i32, tl)
+DEF_HELPER_1(6xx_tlbd, void, tl)
+DEF_HELPER_1(6xx_tlbi, void, tl)
+DEF_HELPER_1(74xx_tlbd, void, tl)
+DEF_HELPER_1(74xx_tlbi, void, tl)
+DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl)
+#if defined(TARGET_PPC64)
+DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl)
+DEF_HELPER_1(load_slb_esid, tl, tl)
+DEF_HELPER_1(load_slb_vsid, tl, tl)
+DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl)
+#endif
+DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl);
+DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
+
+DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+#endif
+
+DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
+DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32)
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_1(rac, tl, tl)
+#endif
+DEF_HELPER_2(div, tl, tl, tl)
+DEF_HELPER_2(divo, tl, tl, tl)
+DEF_HELPER_2(divs, tl, tl, tl)
+DEF_HELPER_2(divso, tl, tl, tl)
+
+DEF_HELPER_1(load_dcr, tl, tl);
+DEF_HELPER_2(store_dcr, void, tl, tl)
+
+DEF_HELPER_1(load_dump_spr, void, i32)
+DEF_HELPER_1(store_dump_spr, void, i32)
+DEF_HELPER_0(load_tbl, tl)
+DEF_HELPER_0(load_tbu, tl)
+DEF_HELPER_0(load_atbl, tl)
+DEF_HELPER_0(load_atbu, tl)
+DEF_HELPER_0(load_601_rtcl, tl)
+DEF_HELPER_0(load_601_rtcu, tl)
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+DEF_HELPER_1(store_asr, void, tl)
+DEF_HELPER_0(load_purr, tl)
+#endif
+DEF_HELPER_1(store_sdr1, void, tl)
+DEF_HELPER_1(store_tbl, void, tl)
+DEF_HELPER_1(store_tbu, void, tl)
+DEF_HELPER_1(store_atbl, void, tl)
+DEF_HELPER_1(store_atbu, void, tl)
+DEF_HELPER_1(store_601_rtcl, void, tl)
+DEF_HELPER_1(store_601_rtcu, void, tl)
+DEF_HELPER_0(load_decr, tl)
+DEF_HELPER_1(store_decr, void, tl)
+DEF_HELPER_1(store_hid0_601, void, tl)
+DEF_HELPER_2(store_403_pbr, void, i32, tl)
+DEF_HELPER_0(load_40x_pit, tl)
+DEF_HELPER_1(store_40x_pit, void, tl)
+DEF_HELPER_1(store_40x_dbcr0, void, tl)
+DEF_HELPER_1(store_40x_sler, void, tl)
+DEF_HELPER_1(store_booke_tcr, void, tl)
+DEF_HELPER_1(store_booke_tsr, void, tl)
+DEF_HELPER_2(store_ibatl, void, i32, tl)
+DEF_HELPER_2(store_ibatu, void, i32, tl)
+DEF_HELPER_2(store_dbatl, void, i32, tl)
+DEF_HELPER_2(store_dbatu, void, i32, tl)
+DEF_HELPER_2(store_601_batl, void, i32, tl)
+DEF_HELPER_2(store_601_batu, void, i32, tl)
+#endif
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-ppc/helper_regs.h b/qemu-0.15.x/target-ppc/helper_regs.h
new file mode 100644
index 0000000..3c98850
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/helper_regs.h
@@ -0,0 +1,111 @@
+/*
+ *  PowerPC emulation special registers manipulation helpers for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined(__HELPER_REGS_H__)
+#define __HELPER_REGS_H__
+
+/* Swap temporary saved registers with GPRs */
+static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
+{
+    target_ulong tmp;
+
+    tmp = env->gpr[0];
+    env->gpr[0] = env->tgpr[0];
+    env->tgpr[0] = tmp;
+    tmp = env->gpr[1];
+    env->gpr[1] = env->tgpr[1];
+    env->tgpr[1] = tmp;
+    tmp = env->gpr[2];
+    env->gpr[2] = env->tgpr[2];
+    env->tgpr[2] = tmp;
+    tmp = env->gpr[3];
+    env->gpr[3] = env->tgpr[3];
+    env->tgpr[3] = tmp;
+}
+
+static inline void hreg_compute_mem_idx(CPUPPCState *env)
+{
+    /* Precompute MMU index */
+    if (msr_pr == 0 && msr_hv != 0) {
+        env->mmu_idx = 2;
+    } else {
+        env->mmu_idx = 1 - msr_pr;
+    }
+}
+
+static inline void hreg_compute_hflags(CPUPPCState *env)
+{
+    target_ulong hflags_mask;
+
+    /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */
+    hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) |
+        (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) |
+        (1 << MSR_LE);
+    hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB;
+    hreg_compute_mem_idx(env);
+    env->hflags = env->msr & hflags_mask;
+    /* Merge with hflags coming from other registers */
+    env->hflags |= env->hflags_nmsr;
+}
+
+static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
+                                 int alter_hv)
+{
+    int excp;
+
+    excp = 0;
+    value &= env->msr_mask;
+#if !defined (CONFIG_USER_ONLY)
+    if (!alter_hv) {
+        /* mtmsr cannot alter the hypervisor state */
+        value &= ~MSR_HVB;
+        value |= env->msr & MSR_HVB;
+    }
+    if (((value >> MSR_IR) & 1) != msr_ir ||
+        ((value >> MSR_DR) & 1) != msr_dr) {
+        /* Flush all tlb when changing translation mode */
+        tlb_flush(env, 1);
+        excp = POWERPC_EXCP_NONE;
+        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    }
+    if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&
+                 ((value ^ env->msr) & (1 << MSR_TGPR)))) {
+        /* Swap temporary saved registers with GPRs */
+        hreg_swap_gpr_tgpr(env);
+    }
+    if (unlikely((value >> MSR_EP) & 1) != msr_ep) {
+        /* Change the exception prefix on PowerPC 601 */
+        env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
+    }
+#endif
+    env->msr = value;
+    hreg_compute_hflags(env);
+#if !defined (CONFIG_USER_ONLY)
+    if (unlikely(msr_pow == 1)) {
+        if ((*env->check_pow)(env)) {
+            env->halted = 1;
+            excp = EXCP_HALTED;
+        }
+    }
+#endif
+
+    return excp;
+}
+
+#endif /* !defined(__HELPER_REGS_H__) */
diff --git a/qemu-0.15.x/target-ppc/kvm.c b/qemu-0.15.x/target-ppc/kvm.c
new file mode 100644
index 0000000..21f35af
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/kvm.c
@@ -0,0 +1,555 @@
+/*
+ * PowerPC implementation of KVM hooks
+ *
+ * Copyright IBM Corp. 2007
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * Authors:
+ *  Jerone Young <jyoung5 at us.ibm.com>
+ *  Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ *  Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "cpu.h"
+#include "device_tree.h"
+
+//#define DEBUG_KVM
+
+#ifdef DEBUG_KVM
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_LAST_INFO
+};
+
+static int cap_interrupt_unset = false;
+static int cap_interrupt_level = false;
+static int cap_segstate;
+static int cap_booke_sregs;
+
+/* XXX We have a race condition where we actually have a level triggered
+ *     interrupt, but the infrastructure can't expose that yet, so the guest
+ *     takes but ignores it, goes to sleep and never gets notified that there's
+ *     still an interrupt pending.
+ *
+ *     As a quick workaround, let's just wake up again 20 ms after we injected
+ *     an interrupt. That way we can assure that we're always reinjecting
+ *     interrupts in case the guest swallowed them.
+ */
+static QEMUTimer *idle_timer;
+
+static void kvm_kick_env(void *env)
+{
+    qemu_cpu_kick(env);
+}
+
+int kvm_arch_init(KVMState *s)
+{
+    cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
+    cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
+    cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
+    cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
+
+    if (!cap_interrupt_level) {
+        fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
+                        "VM to stall at times!\n");
+    }
+
+    return 0;
+}
+
+static int kvm_arch_sync_sregs(CPUState *cenv)
+{
+    struct kvm_sregs sregs;
+    int ret;
+
+    if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
+        /* What we're really trying to say is "if we're on BookE, we use
+           the native PVR for now". This is the only sane way to check
+           it though, so we potentially confuse users that they can run
+           BookE guests on BookS. Let's hope nobody dares enough :) */
+        return 0;
+    } else {
+        if (!cap_segstate) {
+            fprintf(stderr, "kvm error: missing PVR setting capability\n");
+            return -ENOSYS;
+        }
+    }
+
+    ret = kvm_vcpu_ioctl(cenv, KVM_GET_SREGS, &sregs);
+    if (ret) {
+        return ret;
+    }
+
+    sregs.pvr = cenv->spr[SPR_PVR];
+    return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
+}
+
+int kvm_arch_init_vcpu(CPUState *cenv)
+{
+    int ret;
+
+    ret = kvm_arch_sync_sregs(cenv);
+    if (ret) {
+        return ret;
+    }
+
+    idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_env, cenv);
+
+    return ret;
+}
+
+void kvm_arch_reset_vcpu(CPUState *env)
+{
+}
+
+int kvm_arch_put_registers(CPUState *env, int level)
+{
+    struct kvm_regs regs;
+    int ret;
+    int i;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+    if (ret < 0)
+        return ret;
+
+    regs.ctr = env->ctr;
+    regs.lr  = env->lr;
+    regs.xer = env->xer;
+    regs.msr = env->msr;
+    regs.pc = env->nip;
+
+    regs.srr0 = env->spr[SPR_SRR0];
+    regs.srr1 = env->spr[SPR_SRR1];
+
+    regs.sprg0 = env->spr[SPR_SPRG0];
+    regs.sprg1 = env->spr[SPR_SPRG1];
+    regs.sprg2 = env->spr[SPR_SPRG2];
+    regs.sprg3 = env->spr[SPR_SPRG3];
+    regs.sprg4 = env->spr[SPR_SPRG4];
+    regs.sprg5 = env->spr[SPR_SPRG5];
+    regs.sprg6 = env->spr[SPR_SPRG6];
+    regs.sprg7 = env->spr[SPR_SPRG7];
+
+    regs.pid = env->spr[SPR_BOOKE_PID];
+
+    for (i = 0;i < 32; i++)
+        regs.gpr[i] = env->gpr[i];
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+    if (ret < 0)
+        return ret;
+
+    return ret;
+}
+
+int kvm_arch_get_registers(CPUState *env)
+{
+    struct kvm_regs regs;
+    struct kvm_sregs sregs;
+    uint32_t cr;
+    int i, ret;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+    if (ret < 0)
+        return ret;
+
+    cr = regs.cr;
+    for (i = 7; i >= 0; i--) {
+        env->crf[i] = cr & 15;
+        cr >>= 4;
+    }
+
+    env->ctr = regs.ctr;
+    env->lr = regs.lr;
+    env->xer = regs.xer;
+    env->msr = regs.msr;
+    env->nip = regs.pc;
+
+    env->spr[SPR_SRR0] = regs.srr0;
+    env->spr[SPR_SRR1] = regs.srr1;
+
+    env->spr[SPR_SPRG0] = regs.sprg0;
+    env->spr[SPR_SPRG1] = regs.sprg1;
+    env->spr[SPR_SPRG2] = regs.sprg2;
+    env->spr[SPR_SPRG3] = regs.sprg3;
+    env->spr[SPR_SPRG4] = regs.sprg4;
+    env->spr[SPR_SPRG5] = regs.sprg5;
+    env->spr[SPR_SPRG6] = regs.sprg6;
+    env->spr[SPR_SPRG7] = regs.sprg7;
+
+    env->spr[SPR_BOOKE_PID] = regs.pid;
+
+    for (i = 0;i < 32; i++)
+        env->gpr[i] = regs.gpr[i];
+
+    if (cap_booke_sregs) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_BASE) {
+            env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
+            env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
+            env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
+            env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
+            env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
+            env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
+            env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
+            env->spr[SPR_DECR] = sregs.u.e.dec;
+            env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
+            env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
+            env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
+            env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
+            env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
+            env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
+            env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
+            env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_64) {
+            env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
+            env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
+            env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
+            env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
+            env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
+            env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
+            env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
+            env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
+            env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
+            env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
+            env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
+            env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
+            env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
+            env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
+            env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
+            env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
+            env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
+            env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
+
+            if (sregs.u.e.features & KVM_SREGS_E_SPE) {
+                env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
+                env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
+                env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
+            }
+
+            if (sregs.u.e.features & KVM_SREGS_E_PM) {
+                env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
+            }
+
+            if (sregs.u.e.features & KVM_SREGS_E_PC) {
+                env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
+                env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
+            }
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
+            env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
+            env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
+            env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
+            env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
+            env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
+            env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
+            env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
+            env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
+            env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
+            env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_EXP) {
+            env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
+        }
+
+        if (sregs.u.e.features & KVM_SREGS_E_PD) {
+            env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
+            env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
+        }
+
+        if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
+            env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
+            env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
+            env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
+
+            if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
+                env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
+                env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
+            }
+        }
+    }
+
+    if (cap_segstate) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ppc_store_sdr1(env, sregs.u.s.sdr1);
+
+        /* Sync SLB */
+#ifdef TARGET_PPC64
+        for (i = 0; i < 64; i++) {
+            ppc_store_slb(env, sregs.u.s.ppc64.slb[i].slbe,
+                               sregs.u.s.ppc64.slb[i].slbv);
+        }
+#endif
+
+        /* Sync SRs */
+        for (i = 0; i < 16; i++) {
+            env->sr[i] = sregs.u.s.ppc32.sr[i];
+        }
+
+        /* Sync BATs */
+        for (i = 0; i < 8; i++) {
+            env->DBAT[0][i] = sregs.u.s.ppc32.dbat[i] & 0xffffffff;
+            env->DBAT[1][i] = sregs.u.s.ppc32.dbat[i] >> 32;
+            env->IBAT[0][i] = sregs.u.s.ppc32.ibat[i] & 0xffffffff;
+            env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
+        }
+    }
+
+    return 0;
+}
+
+int kvmppc_set_interrupt(CPUState *env, int irq, int level)
+{
+    unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
+
+    if (irq != PPC_INTERRUPT_EXT) {
+        return 0;
+    }
+
+    if (!kvm_enabled() || !cap_interrupt_unset || !cap_interrupt_level) {
+        return 0;
+    }
+
+    kvm_vcpu_ioctl(env, KVM_INTERRUPT, &virq);
+
+    return 0;
+}
+
+#if defined(TARGET_PPCEMB)
+#define PPC_INPUT_INT PPC40x_INPUT_INT
+#elif defined(TARGET_PPC64)
+#define PPC_INPUT_INT PPC970_INPUT_INT
+#else
+#define PPC_INPUT_INT PPC6xx_INPUT_INT
+#endif
+
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+{
+    int r;
+    unsigned irq;
+
+    /* PowerPC Qemu tracks the various core input pins (interrupt, critical
+     * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
+    if (!cap_interrupt_level &&
+        run->ready_for_interrupt_injection &&
+        (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (env->irq_input_state & (1<<PPC_INPUT_INT)))
+    {
+        /* For now KVM disregards the 'irq' argument. However, in the
+         * future KVM could cache it in-kernel to avoid a heavyweight exit
+         * when reading the UIC.
+         */
+        irq = KVM_INTERRUPT_SET;
+
+        dprintf("injected interrupt %d\n", irq);
+        r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
+        if (r < 0)
+            printf("cpu %d fail inject %x\n", env->cpu_index, irq);
+
+        /* Always wake up soon in case the interrupt was level based */
+        qemu_mod_timer(idle_timer, qemu_get_clock_ns(vm_clock) +
+                       (get_ticks_per_sec() / 50));
+    }
+
+    /* We don't know if there are more interrupts pending after this. However,
+     * the guest will return to userspace in the course of handling this one
+     * anyways, so we will get a chance to deliver the rest. */
+}
+
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+{
+}
+
+int kvm_arch_process_async_events(CPUState *env)
+{
+    return 0;
+}
+
+static int kvmppc_handle_halt(CPUState *env)
+{
+    if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
+        env->halted = 1;
+        env->exception_index = EXCP_HLT;
+    }
+
+    return 0;
+}
+
+/* map dcr access to existing qemu dcr emulation */
+static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)
+{
+    if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
+        fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
+
+    return 0;
+}
+
+static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
+{
+    if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
+        fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
+
+    return 0;
+}
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
+{
+    int ret;
+
+    switch (run->exit_reason) {
+    case KVM_EXIT_DCR:
+        if (run->dcr.is_write) {
+            dprintf("handle dcr write\n");
+            ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data);
+        } else {
+            dprintf("handle dcr read\n");
+            ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data);
+        }
+        break;
+    case KVM_EXIT_HLT:
+        dprintf("handle halt\n");
+        ret = kvmppc_handle_halt(env);
+        break;
+    default:
+        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+static int read_cpuinfo(const char *field, char *value, int len)
+{
+    FILE *f;
+    int ret = -1;
+    int field_len = strlen(field);
+    char line[512];
+
+    f = fopen("/proc/cpuinfo", "r");
+    if (!f) {
+        return -1;
+    }
+
+    do {
+        if(!fgets(line, sizeof(line), f)) {
+            break;
+        }
+        if (!strncmp(line, field, field_len)) {
+            strncpy(value, line, len);
+            ret = 0;
+            break;
+        }
+    } while(*line);
+
+    fclose(f);
+
+    return ret;
+}
+
+uint32_t kvmppc_get_tbfreq(void)
+{
+    char line[512];
+    char *ns;
+    uint32_t retval = get_ticks_per_sec();
+
+    if (read_cpuinfo("timebase", line, sizeof(line))) {
+        return retval;
+    }
+
+    if (!(ns = strchr(line, ':'))) {
+        return retval;
+    }
+
+    ns++;
+
+    retval = atoi(ns);
+    return retval;
+}
+
+int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
+{
+    uint32_t *hc = (uint32_t*)buf;
+
+    struct kvm_ppc_pvinfo pvinfo;
+
+    if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
+        !kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) {
+        memcpy(buf, pvinfo.hcall, buf_len);
+
+        return 0;
+    }
+
+    /*
+     * Fallback to always fail hypercalls:
+     *
+     *     li r3, -1
+     *     nop
+     *     nop
+     *     nop
+     */
+
+    hc[0] = 0x3860ffff;
+    hc[1] = 0x60000000;
+    hc[2] = 0x60000000;
+    hc[3] = 0x60000000;
+
+    return 0;
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+    return true;
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
diff --git a/qemu-0.15.x/target-ppc/kvm_ppc.c b/qemu-0.15.x/target-ppc/kvm_ppc.c
new file mode 100644
index 0000000..536fcab
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/kvm_ppc.c
@@ -0,0 +1,105 @@
+/*
+ * PowerPC KVM support
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ *  Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+
+#define PROC_DEVTREE_PATH "/proc/device-tree"
+
+static QEMUTimer *kvmppc_timer;
+static unsigned int kvmppc_timer_rate;
+
+#ifdef CONFIG_FDT
+int kvmppc_read_host_property(const char *node_path, const char *prop,
+                                     void *val, size_t len)
+{
+    char *path;
+    FILE *f;
+    int ret = 0;
+    int pathlen;
+
+    pathlen = snprintf(NULL, 0, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop)
+              + 1;
+    path = qemu_malloc(pathlen);
+
+    snprintf(path, pathlen, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop);
+
+    f = fopen(path, "rb");
+    if (f == NULL) {
+        ret = errno;
+        goto free;
+    }
+
+    len = fread(val, len, 1, f);
+    if (len != 1) {
+        ret = ferror(f);
+        goto close;
+    }
+
+close:
+    fclose(f);
+free:
+    free(path);
+    return ret;
+}
+
+static int kvmppc_copy_host_cell(void *fdt, const char *node, const char *prop)
+{
+    uint32_t cell;
+    int ret;
+
+    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
+    if (ret < 0) {
+        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
+        goto out;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
+        goto out;
+    }
+
+out:
+    return ret;
+}
+
+void kvmppc_fdt_update(void *fdt)
+{
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
+    kvmppc_copy_host_cell(fdt, "/cpus/cpu at 0", "clock-frequency");
+    kvmppc_copy_host_cell(fdt, "/cpus/cpu at 0", "timebase-frequency");
+}
+#endif
+
+static void kvmppc_timer_hack(void *opaque)
+{
+    qemu_service_io();
+    qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
+}
+
+void kvmppc_init(void)
+{
+    /* XXX The only reason KVM yields control back to qemu is device IO. Since
+     * an idle guest does no IO, qemu's device model will never get a chance to
+     * run. So, until Qemu gains IO threads, we create this timer to ensure
+     * that the device model gets a chance to run. */
+    kvmppc_timer_rate = get_ticks_per_sec() / 10;
+    kvmppc_timer = qemu_new_timer_ns(vm_clock, &kvmppc_timer_hack, NULL);
+    qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
+}
+
diff --git a/qemu-0.15.x/target-ppc/kvm_ppc.h b/qemu-0.15.x/target-ppc/kvm_ppc.h
new file mode 100644
index 0000000..45a1373
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/kvm_ppc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 IBM Corporation.
+ * Authors: Hollis Blanchard <hollisb at us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef __KVM_PPC_H__
+#define __KVM_PPC_H__
+
+void kvmppc_init(void);
+void kvmppc_fdt_update(void *fdt);
+#ifndef CONFIG_KVM
+static inline int kvmppc_read_host_property(const char *node_path, const char *prop,
+                                            void *val, size_t len)
+{
+    assert(0);
+    return -ENOSYS;
+}
+#else
+int kvmppc_read_host_property(const char *node_path, const char *prop,
+                                     void *val, size_t len);
+#endif
+
+uint32_t kvmppc_get_tbfreq(void);
+int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
+int kvmppc_set_interrupt(CPUState *env, int irq, int level);
+
+#ifndef CONFIG_KVM
+#define kvmppc_eieio() do { } while (0)
+#else
+#define kvmppc_eieio() \
+    do {                                          \
+        if (kvm_enabled()) {                          \
+            asm volatile("eieio" : : : "memory"); \
+        } \
+    } while (0)
+#endif
+
+#ifndef KVM_INTERRUPT_SET
+#define KVM_INTERRUPT_SET -1
+#endif
+
+#ifndef KVM_INTERRUPT_UNSET
+#define KVM_INTERRUPT_UNSET -2
+#endif
+
+#ifndef KVM_INTERRUPT_SET_LEVEL
+#define KVM_INTERRUPT_SET_LEVEL -3
+#endif
+
+#endif /* __KVM_PPC_H__ */
diff --git a/qemu-0.15.x/target-ppc/machine.c b/qemu-0.15.x/target-ppc/machine.c
new file mode 100644
index 0000000..1c40d43
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/machine.c
@@ -0,0 +1,181 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "kvm.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    CPUState *env = (CPUState *)opaque;
+    unsigned int i, j;
+
+    for (i = 0; i < 32; i++)
+        qemu_put_betls(f, &env->gpr[i]);
+#if !defined(TARGET_PPC64)
+    for (i = 0; i < 32; i++)
+        qemu_put_betls(f, &env->gprh[i]);
+#endif
+    qemu_put_betls(f, &env->lr);
+    qemu_put_betls(f, &env->ctr);
+    for (i = 0; i < 8; i++)
+        qemu_put_be32s(f, &env->crf[i]);
+    qemu_put_betls(f, &env->xer);
+    qemu_put_betls(f, &env->reserve_addr);
+    qemu_put_betls(f, &env->msr);
+    for (i = 0; i < 4; i++)
+        qemu_put_betls(f, &env->tgpr[i]);
+    for (i = 0; i < 32; i++) {
+        union {
+            float64 d;
+            uint64_t l;
+        } u;
+        u.d = env->fpr[i];
+        qemu_put_be64(f, u.l);
+    }
+    qemu_put_be32s(f, &env->fpscr);
+    qemu_put_sbe32s(f, &env->access_type);
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+    qemu_put_betls(f, &env->asr);
+    qemu_put_sbe32s(f, &env->slb_nr);
+#endif
+    qemu_put_betls(f, &env->spr[SPR_SDR1]);
+    for (i = 0; i < 32; i++)
+        qemu_put_betls(f, &env->sr[i]);
+    for (i = 0; i < 2; i++)
+        for (j = 0; j < 8; j++)
+            qemu_put_betls(f, &env->DBAT[i][j]);
+    for (i = 0; i < 2; i++)
+        for (j = 0; j < 8; j++)
+            qemu_put_betls(f, &env->IBAT[i][j]);
+    qemu_put_sbe32s(f, &env->nb_tlb);
+    qemu_put_sbe32s(f, &env->tlb_per_way);
+    qemu_put_sbe32s(f, &env->nb_ways);
+    qemu_put_sbe32s(f, &env->last_way);
+    qemu_put_sbe32s(f, &env->id_tlbs);
+    qemu_put_sbe32s(f, &env->nb_pids);
+    if (env->tlb.tlb6) {
+        // XXX assumes 6xx
+        for (i = 0; i < env->nb_tlb; i++) {
+            qemu_put_betls(f, &env->tlb.tlb6[i].pte0);
+            qemu_put_betls(f, &env->tlb.tlb6[i].pte1);
+            qemu_put_betls(f, &env->tlb.tlb6[i].EPN);
+        }
+    }
+    for (i = 0; i < 4; i++)
+        qemu_put_betls(f, &env->pb[i]);
+#endif
+    for (i = 0; i < 1024; i++)
+        qemu_put_betls(f, &env->spr[i]);
+    qemu_put_be32s(f, &env->vscr);
+    qemu_put_be64s(f, &env->spe_acc);
+    qemu_put_be32s(f, &env->spe_fscr);
+    qemu_put_betls(f, &env->msr_mask);
+    qemu_put_be32s(f, &env->flags);
+    qemu_put_sbe32s(f, &env->error_code);
+    qemu_put_be32s(f, &env->pending_interrupts);
+#if !defined(CONFIG_USER_ONLY)
+    qemu_put_be32s(f, &env->irq_input_state);
+    for (i = 0; i < POWERPC_EXCP_NB; i++)
+        qemu_put_betls(f, &env->excp_vectors[i]);
+    qemu_put_betls(f, &env->excp_prefix);
+    qemu_put_betls(f, &env->hreset_excp_prefix);
+    qemu_put_betls(f, &env->ivor_mask);
+    qemu_put_betls(f, &env->ivpr_mask);
+    qemu_put_betls(f, &env->hreset_vector);
+#endif
+    qemu_put_betls(f, &env->nip);
+    qemu_put_betls(f, &env->hflags);
+    qemu_put_betls(f, &env->hflags_nmsr);
+    qemu_put_sbe32s(f, &env->mmu_idx);
+    qemu_put_sbe32s(f, &env->power_mode);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    CPUState *env = (CPUState *)opaque;
+    unsigned int i, j;
+    target_ulong sdr1;
+
+    for (i = 0; i < 32; i++)
+        qemu_get_betls(f, &env->gpr[i]);
+#if !defined(TARGET_PPC64)
+    for (i = 0; i < 32; i++)
+        qemu_get_betls(f, &env->gprh[i]);
+#endif
+    qemu_get_betls(f, &env->lr);
+    qemu_get_betls(f, &env->ctr);
+    for (i = 0; i < 8; i++)
+        qemu_get_be32s(f, &env->crf[i]);
+    qemu_get_betls(f, &env->xer);
+    qemu_get_betls(f, &env->reserve_addr);
+    qemu_get_betls(f, &env->msr);
+    for (i = 0; i < 4; i++)
+        qemu_get_betls(f, &env->tgpr[i]);
+    for (i = 0; i < 32; i++) {
+        union {
+            float64 d;
+            uint64_t l;
+        } u;
+        u.l = qemu_get_be64(f);
+        env->fpr[i] = u.d;
+    }
+    qemu_get_be32s(f, &env->fpscr);
+    qemu_get_sbe32s(f, &env->access_type);
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+    qemu_get_betls(f, &env->asr);
+    qemu_get_sbe32s(f, &env->slb_nr);
+#endif
+    qemu_get_betls(f, &sdr1);
+    for (i = 0; i < 32; i++)
+        qemu_get_betls(f, &env->sr[i]);
+    for (i = 0; i < 2; i++)
+        for (j = 0; j < 8; j++)
+            qemu_get_betls(f, &env->DBAT[i][j]);
+    for (i = 0; i < 2; i++)
+        for (j = 0; j < 8; j++)
+            qemu_get_betls(f, &env->IBAT[i][j]);
+    qemu_get_sbe32s(f, &env->nb_tlb);
+    qemu_get_sbe32s(f, &env->tlb_per_way);
+    qemu_get_sbe32s(f, &env->nb_ways);
+    qemu_get_sbe32s(f, &env->last_way);
+    qemu_get_sbe32s(f, &env->id_tlbs);
+    qemu_get_sbe32s(f, &env->nb_pids);
+    if (env->tlb.tlb6) {
+        // XXX assumes 6xx
+        for (i = 0; i < env->nb_tlb; i++) {
+            qemu_get_betls(f, &env->tlb.tlb6[i].pte0);
+            qemu_get_betls(f, &env->tlb.tlb6[i].pte1);
+            qemu_get_betls(f, &env->tlb.tlb6[i].EPN);
+        }
+    }
+    for (i = 0; i < 4; i++)
+        qemu_get_betls(f, &env->pb[i]);
+#endif
+    for (i = 0; i < 1024; i++)
+        qemu_get_betls(f, &env->spr[i]);
+    ppc_store_sdr1(env, sdr1);
+    qemu_get_be32s(f, &env->vscr);
+    qemu_get_be64s(f, &env->spe_acc);
+    qemu_get_be32s(f, &env->spe_fscr);
+    qemu_get_betls(f, &env->msr_mask);
+    qemu_get_be32s(f, &env->flags);
+    qemu_get_sbe32s(f, &env->error_code);
+    qemu_get_be32s(f, &env->pending_interrupts);
+#if !defined(CONFIG_USER_ONLY)
+    qemu_get_be32s(f, &env->irq_input_state);
+    for (i = 0; i < POWERPC_EXCP_NB; i++)
+        qemu_get_betls(f, &env->excp_vectors[i]);
+    qemu_get_betls(f, &env->excp_prefix);
+    qemu_get_betls(f, &env->hreset_excp_prefix);
+    qemu_get_betls(f, &env->ivor_mask);
+    qemu_get_betls(f, &env->ivpr_mask);
+    qemu_get_betls(f, &env->hreset_vector);
+#endif
+    qemu_get_betls(f, &env->nip);
+    qemu_get_betls(f, &env->hflags);
+    qemu_get_betls(f, &env->hflags_nmsr);
+    qemu_get_sbe32s(f, &env->mmu_idx);
+    qemu_get_sbe32s(f, &env->power_mode);
+
+    return 0;
+}
diff --git a/qemu-0.15.x/target-ppc/mfrom_table.c b/qemu-0.15.x/target-ppc/mfrom_table.c
new file mode 100644
index 0000000..6a1fa37
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/mfrom_table.c
@@ -0,0 +1,79 @@
+static const uint8_t mfrom_ROM_table[602] =
+{
+     77,  77,  76,  76,  75,  75,  74,  74,
+     73,  73,  72,  72,  71,  71,  70,  70,
+     69,  69,  68,  68,  68,  67,  67,  66,
+     66,  65,  65,  64,  64,  64,  63,  63,
+     62,  62,  61,  61,  61,  60,  60,  59,
+     59,  58,  58,  58,  57,  57,  56,  56,
+     56,  55,  55,  54,  54,  54,  53,  53,
+     53,  52,  52,  51,  51,  51,  50,  50,
+     50,  49,  49,  49,  48,  48,  47,  47,
+     47,  46,  46,  46,  45,  45,  45,  44,
+     44,  44,  43,  43,  43,  42,  42,  42,
+     42,  41,  41,  41,  40,  40,  40,  39,
+     39,  39,  39,  38,  38,  38,  37,  37,
+     37,  37,  36,  36,  36,  35,  35,  35,
+     35,  34,  34,  34,  34,  33,  33,  33,
+     33,  32,  32,  32,  32,  31,  31,  31,
+     31,  30,  30,  30,  30,  29,  29,  29,
+     29,  28,  28,  28,  28,  28,  27,  27,
+     27,  27,  26,  26,  26,  26,  26,  25,
+     25,  25,  25,  25,  24,  24,  24,  24,
+     24,  23,  23,  23,  23,  23,  23,  22,
+     22,  22,  22,  22,  21,  21,  21,  21,
+     21,  21,  20,  20,  20,  20,  20,  20,
+     19,  19,  19,  19,  19,  19,  19,  18,
+     18,  18,  18,  18,  18,  17,  17,  17,
+     17,  17,  17,  17,  16,  16,  16,  16,
+     16,  16,  16,  16,  15,  15,  15,  15,
+     15,  15,  15,  15,  14,  14,  14,  14,
+     14,  14,  14,  14,  13,  13,  13,  13,
+     13,  13,  13,  13,  13,  12,  12,  12,
+     12,  12,  12,  12,  12,  12,  12,  11,
+     11,  11,  11,  11,  11,  11,  11,  11,
+     11,  11,  10,  10,  10,  10,  10,  10,
+     10,  10,  10,  10,  10,   9,   9,   9,
+      9,   9,   9,   9,   9,   9,   9,   9,
+      9,   9,   8,   8,   8,   8,   8,   8,
+      8,   8,   8,   8,   8,   8,   8,   8,
+      7,   7,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,
+      7,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   0,
+};
diff --git a/qemu-0.15.x/target-ppc/mfrom_table_gen.c b/qemu-0.15.x/target-ppc/mfrom_table_gen.c
new file mode 100644
index 0000000..4c06aa4
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/mfrom_table_gen.c
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+
+int main (void)
+{
+    double d;
+    uint8_t n;
+    int i;
+
+    printf("static const uint8_t mfrom_ROM_table[602] =\n{\n    ");
+    for (i = 0; i < 602; i++) {
+        /* Extremly decomposed:
+         *                    -T0 / 256
+         * T0 = 256 * log10(10          + 1.0) + 0.5
+         */
+        d = -i;
+        d /= 256.0;
+        d = exp10(d);
+        d += 1.0;
+        d = log10(d);
+        d *= 256;
+        d += 0.5;
+        n = d;
+        printf("%3d, ", n);
+        if ((i & 7) == 7)
+            printf("\n    ");
+    }
+    printf("\n};\n");
+
+    return 0;
+}
diff --git a/qemu-0.15.x/target-ppc/op_helper.c b/qemu-0.15.x/target-ppc/op_helper.c
new file mode 100644
index 0000000..dde7595
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/op_helper.c
@@ -0,0 +1,4409 @@
+/*
+ *  PowerPC emulation helpers for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#include "exec.h"
+#include "host-utils.h"
+#include "helper.h"
+
+#include "helper_regs.h"
+
+//#define DEBUG_OP
+//#define DEBUG_EXCEPTIONS
+//#define DEBUG_SOFTWARE_TLB
+
+#ifdef DEBUG_SOFTWARE_TLB
+#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_SWTLB(...) do { } while (0)
+#endif
+
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+
+void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
+{
+#if 0
+    printf("Raise exception %3x code : %d\n", exception, error_code);
+#endif
+    env->exception_index = exception;
+    env->error_code = error_code;
+    cpu_loop_exit(env);
+}
+
+void helper_raise_exception (uint32_t exception)
+{
+    helper_raise_exception_err(exception, 0);
+}
+
+/*****************************************************************************/
+/* SPR accesses */
+void helper_load_dump_spr (uint32_t sprn)
+{
+    qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
+             env->spr[sprn]);
+}
+
+void helper_store_dump_spr (uint32_t sprn)
+{
+    qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
+             env->spr[sprn]);
+}
+
+target_ulong helper_load_tbl (void)
+{
+    return (target_ulong)cpu_ppc_load_tbl(env);
+}
+
+target_ulong helper_load_tbu (void)
+{
+    return cpu_ppc_load_tbu(env);
+}
+
+target_ulong helper_load_atbl (void)
+{
+    return (target_ulong)cpu_ppc_load_atbl(env);
+}
+
+target_ulong helper_load_atbu (void)
+{
+    return cpu_ppc_load_atbu(env);
+}
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+target_ulong helper_load_purr (void)
+{
+    return (target_ulong)cpu_ppc_load_purr(env);
+}
+#endif
+
+target_ulong helper_load_601_rtcl (void)
+{
+    return cpu_ppc601_load_rtcl(env);
+}
+
+target_ulong helper_load_601_rtcu (void)
+{
+    return cpu_ppc601_load_rtcu(env);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+#if defined (TARGET_PPC64)
+void helper_store_asr (target_ulong val)
+{
+    ppc_store_asr(env, val);
+}
+#endif
+
+void helper_store_sdr1 (target_ulong val)
+{
+    ppc_store_sdr1(env, val);
+}
+
+void helper_store_tbl (target_ulong val)
+{
+    cpu_ppc_store_tbl(env, val);
+}
+
+void helper_store_tbu (target_ulong val)
+{
+    cpu_ppc_store_tbu(env, val);
+}
+
+void helper_store_atbl (target_ulong val)
+{
+    cpu_ppc_store_atbl(env, val);
+}
+
+void helper_store_atbu (target_ulong val)
+{
+    cpu_ppc_store_atbu(env, val);
+}
+
+void helper_store_601_rtcl (target_ulong val)
+{
+    cpu_ppc601_store_rtcl(env, val);
+}
+
+void helper_store_601_rtcu (target_ulong val)
+{
+    cpu_ppc601_store_rtcu(env, val);
+}
+
+target_ulong helper_load_decr (void)
+{
+    return cpu_ppc_load_decr(env);
+}
+
+void helper_store_decr (target_ulong val)
+{
+    cpu_ppc_store_decr(env, val);
+}
+
+void helper_store_hid0_601 (target_ulong val)
+{
+    target_ulong hid0;
+
+    hid0 = env->spr[SPR_HID0];
+    if ((val ^ hid0) & 0x00000008) {
+        /* Change current endianness */
+        env->hflags &= ~(1 << MSR_LE);
+        env->hflags_nmsr &= ~(1 << MSR_LE);
+        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
+        env->hflags |= env->hflags_nmsr;
+        qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
+                 val & 0x8 ? 'l' : 'b', env->hflags);
+    }
+    env->spr[SPR_HID0] = (uint32_t)val;
+}
+
+void helper_store_403_pbr (uint32_t num, target_ulong value)
+{
+    if (likely(env->pb[num] != value)) {
+        env->pb[num] = value;
+        /* Should be optimized */
+        tlb_flush(env, 1);
+    }
+}
+
+target_ulong helper_load_40x_pit (void)
+{
+    return load_40x_pit(env);
+}
+
+void helper_store_40x_pit (target_ulong val)
+{
+    store_40x_pit(env, val);
+}
+
+void helper_store_40x_dbcr0 (target_ulong val)
+{
+    store_40x_dbcr0(env, val);
+}
+
+void helper_store_40x_sler (target_ulong val)
+{
+    store_40x_sler(env, val);
+}
+
+void helper_store_booke_tcr (target_ulong val)
+{
+    store_booke_tcr(env, val);
+}
+
+void helper_store_booke_tsr (target_ulong val)
+{
+    store_booke_tsr(env, val);
+}
+
+void helper_store_ibatu (uint32_t nr, target_ulong val)
+{
+    ppc_store_ibatu(env, nr, val);
+}
+
+void helper_store_ibatl (uint32_t nr, target_ulong val)
+{
+    ppc_store_ibatl(env, nr, val);
+}
+
+void helper_store_dbatu (uint32_t nr, target_ulong val)
+{
+    ppc_store_dbatu(env, nr, val);
+}
+
+void helper_store_dbatl (uint32_t nr, target_ulong val)
+{
+    ppc_store_dbatl(env, nr, val);
+}
+
+void helper_store_601_batl (uint32_t nr, target_ulong val)
+{
+    ppc_store_ibatl_601(env, nr, val);
+}
+
+void helper_store_601_batu (uint32_t nr, target_ulong val)
+{
+    ppc_store_ibatu_601(env, nr, val);
+}
+#endif
+
+/*****************************************************************************/
+/* Memory load and stores */
+
+static inline target_ulong addr_add(target_ulong addr, target_long arg)
+{
+#if defined(TARGET_PPC64)
+        if (!msr_sf)
+            return (uint32_t)(addr + arg);
+        else
+#endif
+            return addr + arg;
+}
+
+void helper_lmw (target_ulong addr, uint32_t reg)
+{
+    for (; reg < 32; reg++) {
+        if (msr_le)
+            env->gpr[reg] = bswap32(ldl(addr));
+        else
+            env->gpr[reg] = ldl(addr);
+	addr = addr_add(addr, 4);
+    }
+}
+
+void helper_stmw (target_ulong addr, uint32_t reg)
+{
+    for (; reg < 32; reg++) {
+        if (msr_le)
+            stl(addr, bswap32((uint32_t)env->gpr[reg]));
+        else
+            stl(addr, (uint32_t)env->gpr[reg]);
+	addr = addr_add(addr, 4);
+    }
+}
+
+void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
+{
+    int sh;
+    for (; nb > 3; nb -= 4) {
+        env->gpr[reg] = ldl(addr);
+        reg = (reg + 1) % 32;
+	addr = addr_add(addr, 4);
+    }
+    if (unlikely(nb > 0)) {
+        env->gpr[reg] = 0;
+        for (sh = 24; nb > 0; nb--, sh -= 8) {
+            env->gpr[reg] |= ldub(addr) << sh;
+	    addr = addr_add(addr, 1);
+        }
+    }
+}
+/* PPC32 specification says we must generate an exception if
+ * rA is in the range of registers to be loaded.
+ * In an other hand, IBM says this is valid, but rA won't be loaded.
+ * For now, I'll follow the spec...
+ */
+void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
+{
+    if (likely(xer_bc != 0)) {
+        if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
+                     (reg < rb && (reg + xer_bc) > rb))) {
+            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                       POWERPC_EXCP_INVAL |
+                                       POWERPC_EXCP_INVAL_LSWX);
+        } else {
+            helper_lsw(addr, xer_bc, reg);
+        }
+    }
+}
+
+void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
+{
+    int sh;
+    for (; nb > 3; nb -= 4) {
+        stl(addr, env->gpr[reg]);
+        reg = (reg + 1) % 32;
+	addr = addr_add(addr, 4);
+    }
+    if (unlikely(nb > 0)) {
+        for (sh = 24; nb > 0; nb--, sh -= 8) {
+            stb(addr, (env->gpr[reg] >> sh) & 0xFF);
+            addr = addr_add(addr, 1);
+        }
+    }
+}
+
+static void do_dcbz(target_ulong addr, int dcache_line_size)
+{
+    addr &= ~(dcache_line_size - 1);
+    int i;
+    for (i = 0 ; i < dcache_line_size ; i += 4) {
+        stl(addr + i , 0);
+    }
+    if (env->reserve_addr == addr)
+        env->reserve_addr = (target_ulong)-1ULL;
+}
+
+void helper_dcbz(target_ulong addr)
+{
+    do_dcbz(addr, env->dcache_line_size);
+}
+
+void helper_dcbz_970(target_ulong addr)
+{
+    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
+        do_dcbz(addr, 32);
+    else
+        do_dcbz(addr, env->dcache_line_size);
+}
+
+void helper_icbi(target_ulong addr)
+{
+    addr &= ~(env->dcache_line_size - 1);
+    /* Invalidate one cache line :
+     * PowerPC specification says this is to be treated like a load
+     * (not a fetch) by the MMU. To be sure it will be so,
+     * do the load "by hand".
+     */
+    ldl(addr);
+}
+
+// XXX: to be tested
+target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
+{
+    int i, c, d;
+    d = 24;
+    for (i = 0; i < xer_bc; i++) {
+        c = ldub(addr);
+	addr = addr_add(addr, 1);
+        /* ra (if not 0) and rb are never modified */
+        if (likely(reg != rb && (ra == 0 || reg != ra))) {
+            env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
+        }
+        if (unlikely(c == xer_cmp))
+            break;
+        if (likely(d != 0)) {
+            d -= 8;
+        } else {
+            d = 24;
+            reg++;
+            reg = reg & 0x1F;
+        }
+    }
+    return i;
+}
+
+/*****************************************************************************/
+/* Fixed point operations helpers */
+#if defined(TARGET_PPC64)
+
+/* multiply high word */
+uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
+{
+    uint64_t tl, th;
+
+    muls64(&tl, &th, arg1, arg2);
+    return th;
+}
+
+/* multiply high word unsigned */
+uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
+{
+    uint64_t tl, th;
+
+    mulu64(&tl, &th, arg1, arg2);
+    return th;
+}
+
+uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
+{
+    int64_t th;
+    uint64_t tl;
+
+    muls64(&tl, (uint64_t *)&th, arg1, arg2);
+    /* If th != 0 && th != -1, then we had an overflow */
+    if (likely((uint64_t)(th + 1) <= 1)) {
+        env->xer &= ~(1 << XER_OV);
+    } else {
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
+    }
+    return (int64_t)tl;
+}
+#endif
+
+target_ulong helper_cntlzw (target_ulong t)
+{
+    return clz32(t);
+}
+
+#if defined(TARGET_PPC64)
+target_ulong helper_cntlzd (target_ulong t)
+{
+    return clz64(t);
+}
+#endif
+
+/* shift right arithmetic helper */
+target_ulong helper_sraw (target_ulong value, target_ulong shift)
+{
+    int32_t ret;
+
+    if (likely(!(shift & 0x20))) {
+        if (likely((uint32_t)shift != 0)) {
+            shift &= 0x1f;
+            ret = (int32_t)value >> shift;
+            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
+                env->xer &= ~(1 << XER_CA);
+            } else {
+                env->xer |= (1 << XER_CA);
+            }
+        } else {
+            ret = (int32_t)value;
+            env->xer &= ~(1 << XER_CA);
+        }
+    } else {
+        ret = (int32_t)value >> 31;
+        if (ret) {
+            env->xer |= (1 << XER_CA);
+        } else {
+            env->xer &= ~(1 << XER_CA);
+        }
+    }
+    return (target_long)ret;
+}
+
+#if defined(TARGET_PPC64)
+target_ulong helper_srad (target_ulong value, target_ulong shift)
+{
+    int64_t ret;
+
+    if (likely(!(shift & 0x40))) {
+        if (likely((uint64_t)shift != 0)) {
+            shift &= 0x3f;
+            ret = (int64_t)value >> shift;
+            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
+                env->xer &= ~(1 << XER_CA);
+            } else {
+                env->xer |= (1 << XER_CA);
+            }
+        } else {
+            ret = (int64_t)value;
+            env->xer &= ~(1 << XER_CA);
+        }
+    } else {
+        ret = (int64_t)value >> 63;
+        if (ret) {
+            env->xer |= (1 << XER_CA);
+        } else {
+            env->xer &= ~(1 << XER_CA);
+        }
+    }
+    return ret;
+}
+#endif
+
+#if defined(TARGET_PPC64)
+target_ulong helper_popcntb (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    return val;
+}
+
+target_ulong helper_popcntw (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
+                                           0x00ff00ff00ff00ffULL);
+    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
+                                           0x0000ffff0000ffffULL);
+    return val;
+}
+
+target_ulong helper_popcntd (target_ulong val)
+{
+    return ctpop64(val);
+}
+#else
+target_ulong helper_popcntb (target_ulong val)
+{
+    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
+    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
+    return val;
+}
+
+target_ulong helper_popcntw (target_ulong val)
+{
+    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
+    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
+    val = (val & 0x00ff00ff) + ((val >>  8) & 0x00ff00ff);
+    val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
+    return val;
+}
+#endif
+
+/*****************************************************************************/
+/* Floating point operations helpers */
+uint64_t helper_float32_to_float64(uint32_t arg)
+{
+    CPU_FloatU f;
+    CPU_DoubleU d;
+    f.l = arg;
+    d.d = float32_to_float64(f.f, &env->fp_status);
+    return d.ll;
+}
+
+uint32_t helper_float64_to_float32(uint64_t arg)
+{
+    CPU_FloatU f;
+    CPU_DoubleU d;
+    d.ll = arg;
+    f.f = float64_to_float32(d.d, &env->fp_status);
+    return f.l;
+}
+
+static inline int isden(float64 d)
+{
+    CPU_DoubleU u;
+
+    u.d = d;
+
+    return ((u.ll >> 52) & 0x7FF) == 0;
+}
+
+uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
+{
+    CPU_DoubleU farg;
+    int isneg;
+    int ret;
+    farg.ll = arg;
+    isneg = float64_is_neg(farg.d);
+    if (unlikely(float64_is_any_nan(farg.d))) {
+        if (float64_is_signaling_nan(farg.d)) {
+            /* Signaling NaN: flags are undefined */
+            ret = 0x00;
+        } else {
+            /* Quiet NaN */
+            ret = 0x11;
+        }
+    } else if (unlikely(float64_is_infinity(farg.d))) {
+        /* +/- infinity */
+        if (isneg)
+            ret = 0x09;
+        else
+            ret = 0x05;
+    } else {
+        if (float64_is_zero(farg.d)) {
+            /* +/- zero */
+            if (isneg)
+                ret = 0x12;
+            else
+                ret = 0x02;
+        } else {
+            if (isden(farg.d)) {
+                /* Denormalized numbers */
+                ret = 0x10;
+            } else {
+                /* Normalized numbers */
+                ret = 0x00;
+            }
+            if (isneg) {
+                ret |= 0x08;
+            } else {
+                ret |= 0x04;
+            }
+        }
+    }
+    if (set_fprf) {
+        /* We update FPSCR_FPRF */
+        env->fpscr &= ~(0x1F << FPSCR_FPRF);
+        env->fpscr |= ret << FPSCR_FPRF;
+    }
+    /* We just need fpcc to update Rc1 */
+    return ret & 0xF;
+}
+
+/* Floating-point invalid operations exception */
+static inline uint64_t fload_invalid_op_excp(int op)
+{
+    uint64_t ret = 0;
+    int ve;
+
+    ve = fpscr_ve;
+    switch (op) {
+    case POWERPC_EXCP_FP_VXSNAN:
+        env->fpscr |= 1 << FPSCR_VXSNAN;
+	break;
+    case POWERPC_EXCP_FP_VXSOFT:
+        env->fpscr |= 1 << FPSCR_VXSOFT;
+	break;
+    case POWERPC_EXCP_FP_VXISI:
+        /* Magnitude subtraction of infinities */
+        env->fpscr |= 1 << FPSCR_VXISI;
+        goto update_arith;
+    case POWERPC_EXCP_FP_VXIDI:
+        /* Division of infinity by infinity */
+        env->fpscr |= 1 << FPSCR_VXIDI;
+        goto update_arith;
+    case POWERPC_EXCP_FP_VXZDZ:
+        /* Division of zero by zero */
+        env->fpscr |= 1 << FPSCR_VXZDZ;
+        goto update_arith;
+    case POWERPC_EXCP_FP_VXIMZ:
+        /* Multiplication of zero by infinity */
+        env->fpscr |= 1 << FPSCR_VXIMZ;
+        goto update_arith;
+    case POWERPC_EXCP_FP_VXVC:
+        /* Ordered comparison of NaN */
+        env->fpscr |= 1 << FPSCR_VXVC;
+        env->fpscr &= ~(0xF << FPSCR_FPCC);
+        env->fpscr |= 0x11 << FPSCR_FPCC;
+        /* We must update the target FPR before raising the exception */
+        if (ve != 0) {
+            env->exception_index = POWERPC_EXCP_PROGRAM;
+            env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
+            /* Update the floating-point enabled exception summary */
+            env->fpscr |= 1 << FPSCR_FEX;
+            /* Exception is differed */
+            ve = 0;
+        }
+        break;
+    case POWERPC_EXCP_FP_VXSQRT:
+        /* Square root of a negative number */
+        env->fpscr |= 1 << FPSCR_VXSQRT;
+    update_arith:
+        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+        if (ve == 0) {
+            /* Set the result to quiet NaN */
+            ret = 0x7FF8000000000000ULL;
+            env->fpscr &= ~(0xF << FPSCR_FPCC);
+            env->fpscr |= 0x11 << FPSCR_FPCC;
+        }
+        break;
+    case POWERPC_EXCP_FP_VXCVI:
+        /* Invalid conversion */
+        env->fpscr |= 1 << FPSCR_VXCVI;
+        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+        if (ve == 0) {
+            /* Set the result to quiet NaN */
+            ret = 0x7FF8000000000000ULL;
+            env->fpscr &= ~(0xF << FPSCR_FPCC);
+            env->fpscr |= 0x11 << FPSCR_FPCC;
+        }
+        break;
+    }
+    /* Update the floating-point invalid operation summary */
+    env->fpscr |= 1 << FPSCR_VX;
+    /* Update the floating-point exception summary */
+    env->fpscr |= 1 << FPSCR_FX;
+    if (ve != 0) {
+        /* Update the floating-point enabled exception summary */
+        env->fpscr |= 1 << FPSCR_FEX;
+        if (msr_fe0 != 0 || msr_fe1 != 0)
+            helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
+    }
+    return ret;
+}
+
+static inline void float_zero_divide_excp(void)
+{
+    env->fpscr |= 1 << FPSCR_ZX;
+    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+    /* Update the floating-point exception summary */
+    env->fpscr |= 1 << FPSCR_FX;
+    if (fpscr_ze != 0) {
+        /* Update the floating-point enabled exception summary */
+        env->fpscr |= 1 << FPSCR_FEX;
+        if (msr_fe0 != 0 || msr_fe1 != 0) {
+            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
+        }
+    }
+}
+
+static inline void float_overflow_excp(void)
+{
+    env->fpscr |= 1 << FPSCR_OX;
+    /* Update the floating-point exception summary */
+    env->fpscr |= 1 << FPSCR_FX;
+    if (fpscr_oe != 0) {
+        /* XXX: should adjust the result */
+        /* Update the floating-point enabled exception summary */
+        env->fpscr |= 1 << FPSCR_FEX;
+        /* We must update the target FPR before raising the exception */
+        env->exception_index = POWERPC_EXCP_PROGRAM;
+        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+    } else {
+        env->fpscr |= 1 << FPSCR_XX;
+        env->fpscr |= 1 << FPSCR_FI;
+    }
+}
+
+static inline void float_underflow_excp(void)
+{
+    env->fpscr |= 1 << FPSCR_UX;
+    /* Update the floating-point exception summary */
+    env->fpscr |= 1 << FPSCR_FX;
+    if (fpscr_ue != 0) {
+        /* XXX: should adjust the result */
+        /* Update the floating-point enabled exception summary */
+        env->fpscr |= 1 << FPSCR_FEX;
+        /* We must update the target FPR before raising the exception */
+        env->exception_index = POWERPC_EXCP_PROGRAM;
+        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+    }
+}
+
+static inline void float_inexact_excp(void)
+{
+    env->fpscr |= 1 << FPSCR_XX;
+    /* Update the floating-point exception summary */
+    env->fpscr |= 1 << FPSCR_FX;
+    if (fpscr_xe != 0) {
+        /* Update the floating-point enabled exception summary */
+        env->fpscr |= 1 << FPSCR_FEX;
+        /* We must update the target FPR before raising the exception */
+        env->exception_index = POWERPC_EXCP_PROGRAM;
+        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+    }
+}
+
+static inline void fpscr_set_rounding_mode(void)
+{
+    int rnd_type;
+
+    /* Set rounding mode */
+    switch (fpscr_rn) {
+    case 0:
+        /* Best approximation (round to nearest) */
+        rnd_type = float_round_nearest_even;
+        break;
+    case 1:
+        /* Smaller magnitude (round toward zero) */
+        rnd_type = float_round_to_zero;
+        break;
+    case 2:
+        /* Round toward +infinite */
+        rnd_type = float_round_up;
+        break;
+    default:
+    case 3:
+        /* Round toward -infinite */
+        rnd_type = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+void helper_fpscr_clrbit (uint32_t bit)
+{
+    int prev;
+
+    prev = (env->fpscr >> bit) & 1;
+    env->fpscr &= ~(1 << bit);
+    if (prev == 1) {
+        switch (bit) {
+        case FPSCR_RN1:
+        case FPSCR_RN:
+            fpscr_set_rounding_mode();
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void helper_fpscr_setbit (uint32_t bit)
+{
+    int prev;
+
+    prev = (env->fpscr >> bit) & 1;
+    env->fpscr |= 1 << bit;
+    if (prev == 0) {
+        switch (bit) {
+        case FPSCR_VX:
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_ve)
+                goto raise_ve;
+        case FPSCR_OX:
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_oe)
+                goto raise_oe;
+            break;
+        case FPSCR_UX:
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_ue)
+                goto raise_ue;
+            break;
+        case FPSCR_ZX:
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_ze)
+                goto raise_ze;
+            break;
+        case FPSCR_XX:
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_xe)
+                goto raise_xe;
+            break;
+        case FPSCR_VXSNAN:
+        case FPSCR_VXISI:
+        case FPSCR_VXIDI:
+        case FPSCR_VXZDZ:
+        case FPSCR_VXIMZ:
+        case FPSCR_VXVC:
+        case FPSCR_VXSOFT:
+        case FPSCR_VXSQRT:
+        case FPSCR_VXCVI:
+            env->fpscr |= 1 << FPSCR_VX;
+            env->fpscr |= 1 << FPSCR_FX;
+            if (fpscr_ve != 0)
+                goto raise_ve;
+            break;
+        case FPSCR_VE:
+            if (fpscr_vx != 0) {
+            raise_ve:
+                env->error_code = POWERPC_EXCP_FP;
+                if (fpscr_vxsnan)
+                    env->error_code |= POWERPC_EXCP_FP_VXSNAN;
+                if (fpscr_vxisi)
+                    env->error_code |= POWERPC_EXCP_FP_VXISI;
+                if (fpscr_vxidi)
+                    env->error_code |= POWERPC_EXCP_FP_VXIDI;
+                if (fpscr_vxzdz)
+                    env->error_code |= POWERPC_EXCP_FP_VXZDZ;
+                if (fpscr_vximz)
+                    env->error_code |= POWERPC_EXCP_FP_VXIMZ;
+                if (fpscr_vxvc)
+                    env->error_code |= POWERPC_EXCP_FP_VXVC;
+                if (fpscr_vxsoft)
+                    env->error_code |= POWERPC_EXCP_FP_VXSOFT;
+                if (fpscr_vxsqrt)
+                    env->error_code |= POWERPC_EXCP_FP_VXSQRT;
+                if (fpscr_vxcvi)
+                    env->error_code |= POWERPC_EXCP_FP_VXCVI;
+                goto raise_excp;
+            }
+            break;
+        case FPSCR_OE:
+            if (fpscr_ox != 0) {
+            raise_oe:
+                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+                goto raise_excp;
+            }
+            break;
+        case FPSCR_UE:
+            if (fpscr_ux != 0) {
+            raise_ue:
+                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+                goto raise_excp;
+            }
+            break;
+        case FPSCR_ZE:
+            if (fpscr_zx != 0) {
+            raise_ze:
+                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
+                goto raise_excp;
+            }
+            break;
+        case FPSCR_XE:
+            if (fpscr_xx != 0) {
+            raise_xe:
+                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+                goto raise_excp;
+            }
+            break;
+        case FPSCR_RN1:
+        case FPSCR_RN:
+            fpscr_set_rounding_mode();
+            break;
+        default:
+            break;
+        raise_excp:
+            /* Update the floating-point enabled exception summary */
+            env->fpscr |= 1 << FPSCR_FEX;
+                /* We have to update Rc1 before raising the exception */
+            env->exception_index = POWERPC_EXCP_PROGRAM;
+            break;
+        }
+    }
+}
+
+void helper_store_fpscr (uint64_t arg, uint32_t mask)
+{
+    /*
+     * We use only the 32 LSB of the incoming fpr
+     */
+    uint32_t prev, new;
+    int i;
+
+    prev = env->fpscr;
+    new = (uint32_t)arg;
+    new &= ~0x60000000;
+    new |= prev & 0x60000000;
+    for (i = 0; i < 8; i++) {
+        if (mask & (1 << i)) {
+            env->fpscr &= ~(0xF << (4 * i));
+            env->fpscr |= new & (0xF << (4 * i));
+        }
+    }
+    /* Update VX and FEX */
+    if (fpscr_ix != 0)
+        env->fpscr |= 1 << FPSCR_VX;
+    else
+        env->fpscr &= ~(1 << FPSCR_VX);
+    if ((fpscr_ex & fpscr_eex) != 0) {
+        env->fpscr |= 1 << FPSCR_FEX;
+        env->exception_index = POWERPC_EXCP_PROGRAM;
+        /* XXX: we should compute it properly */
+        env->error_code = POWERPC_EXCP_FP;
+    }
+    else
+        env->fpscr &= ~(1 << FPSCR_FEX);
+    fpscr_set_rounding_mode();
+}
+
+void helper_float_check_status (void)
+{
+    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
+        (env->error_code & POWERPC_EXCP_FP)) {
+        /* Differred floating-point exception after target FPR update */
+        if (msr_fe0 != 0 || msr_fe1 != 0)
+            helper_raise_exception_err(env->exception_index, env->error_code);
+    } else {
+        int status = get_float_exception_flags(&env->fp_status);
+        if (status & float_flag_divbyzero) {
+            float_zero_divide_excp();
+        } else if (status & float_flag_overflow) {
+            float_overflow_excp();
+        } else if (status & float_flag_underflow) {
+            float_underflow_excp();
+        } else if (status & float_flag_inexact) {
+            float_inexact_excp();
+        }
+    }
+}
+
+void helper_reset_fpstatus (void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
+/* fadd - fadd. */
+uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
+{
+    CPU_DoubleU farg1, farg2;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+                 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
+        /* Magnitude subtraction of infinities */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d))) {
+            /* sNaN addition */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fsub - fsub. */
+uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
+{
+    CPU_DoubleU farg1, farg2;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+                 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
+        /* Magnitude subtraction of infinities */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d))) {
+            /* sNaN subtraction */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fmul - fmul. */
+uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
+{
+    CPU_DoubleU farg1, farg2;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+        /* Multiplication of zero by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d))) {
+            /* sNaN multiplication */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fdiv - fdiv. */
+uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
+{
+    CPU_DoubleU farg1, farg2;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
+        /* Division of infinity by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
+    } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
+        /* Division of zero by zero */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d))) {
+            /* sNaN division */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fabs */
+uint64_t helper_fabs (uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+    farg.d = float64_abs(farg.d);
+    return farg.ll;
+}
+
+/* fnabs */
+uint64_t helper_fnabs (uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+    farg.d = float64_abs(farg.d);
+    farg.d = float64_chs(farg.d);
+    return farg.ll;
+}
+
+/* fneg */
+uint64_t helper_fneg (uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+    farg.d = float64_chs(farg.d);
+    return farg.ll;
+}
+
+/* fctiw - fctiw. */
+uint64_t helper_fctiw (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+        /* qNan / infinity conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+    } else {
+        farg.ll = float64_to_int32(farg.d, &env->fp_status);
+        /* XXX: higher bits are not supposed to be significant.
+         *     to make tests easier, return the same as a real PowerPC 750
+         */
+        farg.ll |= 0xFFF80000ULL << 32;
+    }
+    return farg.ll;
+}
+
+/* fctiwz - fctiwz. */
+uint64_t helper_fctiwz (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+        /* qNan / infinity conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+    } else {
+        farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
+        /* XXX: higher bits are not supposed to be significant.
+         *     to make tests easier, return the same as a real PowerPC 750
+         */
+        farg.ll |= 0xFFF80000ULL << 32;
+    }
+    return farg.ll;
+}
+
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+uint64_t helper_fcfid (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.d = int64_to_float64(arg, &env->fp_status);
+    return farg.ll;
+}
+
+/* fctid - fctid. */
+uint64_t helper_fctid (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+        /* qNan / infinity conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+    } else {
+        farg.ll = float64_to_int64(farg.d, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+/* fctidz - fctidz. */
+uint64_t helper_fctidz (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+        /* qNan / infinity conversion */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+    } else {
+        farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+#endif
+
+static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN round */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+        /* qNan / infinity round */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+    } else {
+        set_float_rounding_mode(rounding_mode, &env->fp_status);
+        farg.ll = float64_round_to_int(farg.d, &env->fp_status);
+        /* Restore rounding mode from FPSCR */
+        fpscr_set_rounding_mode();
+    }
+    return farg.ll;
+}
+
+uint64_t helper_frin (uint64_t arg)
+{
+    return do_fri(arg, float_round_nearest_even);
+}
+
+uint64_t helper_friz (uint64_t arg)
+{
+    return do_fri(arg, float_round_to_zero);
+}
+
+uint64_t helper_frip (uint64_t arg)
+{
+    return do_fri(arg, float_round_up);
+}
+
+uint64_t helper_frim (uint64_t arg)
+{
+    return do_fri(arg, float_round_down);
+}
+
+/* fmadd - fmadd. */
+uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+    CPU_DoubleU farg1, farg2, farg3;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+    farg3.ll = arg3;
+
+    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+        /* Multiplication of zero by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d) ||
+                     float64_is_signaling_nan(farg3.d))) {
+            /* sNaN operation */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        /* This is the way the PowerPC specification defines it */
+        float128 ft0_128, ft1_128;
+
+        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+            /* Magnitude subtraction of infinities */
+            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+        } else {
+            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+    }
+
+    return farg1.ll;
+}
+
+/* fmsub - fmsub. */
+uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+    CPU_DoubleU farg1, farg2, farg3;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+    farg3.ll = arg3;
+
+    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+        /* Multiplication of zero by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d) ||
+                     float64_is_signaling_nan(farg3.d))) {
+            /* sNaN operation */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        /* This is the way the PowerPC specification defines it */
+        float128 ft0_128, ft1_128;
+
+        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+            /* Magnitude subtraction of infinities */
+            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+        } else {
+            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+    }
+    return farg1.ll;
+}
+
+/* fnmadd - fnmadd. */
+uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+    CPU_DoubleU farg1, farg2, farg3;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+    farg3.ll = arg3;
+
+    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+        /* Multiplication of zero by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d) ||
+                     float64_is_signaling_nan(farg3.d))) {
+            /* sNaN operation */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        /* This is the way the PowerPC specification defines it */
+        float128 ft0_128, ft1_128;
+
+        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+            /* Magnitude subtraction of infinities */
+            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+        } else {
+            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+        if (likely(!float64_is_any_nan(farg1.d))) {
+            farg1.d = float64_chs(farg1.d);
+        }
+    }
+    return farg1.ll;
+}
+
+/* fnmsub - fnmsub. */
+uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+    CPU_DoubleU farg1, farg2, farg3;
+
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+    farg3.ll = arg3;
+
+    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+        /* Multiplication of zero by infinity */
+        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d) ||
+                     float64_is_signaling_nan(farg3.d))) {
+            /* sNaN operation */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        /* This is the way the PowerPC specification defines it */
+        float128 ft0_128, ft1_128;
+
+        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+            /* Magnitude subtraction of infinities */
+            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+        } else {
+            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+        if (likely(!float64_is_any_nan(farg1.d))) {
+            farg1.d = float64_chs(farg1.d);
+        }
+    }
+    return farg1.ll;
+}
+
+/* frsp - frsp. */
+uint64_t helper_frsp (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    float32 f32;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN square root */
+       fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+    }
+    f32 = float64_to_float32(farg.d, &env->fp_status);
+    farg.d = float32_to_float64(f32, &env->fp_status);
+
+    return farg.ll;
+}
+
+/* fsqrt - fsqrt. */
+uint64_t helper_fsqrt (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+        /* Square root of a negative nonzero number */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg.d))) {
+            /* sNaN square root */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg.d = float64_sqrt(farg.d, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+/* fre - fre. */
+uint64_t helper_fre (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN reciprocal */
+        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+    }
+    farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+    return farg.d;
+}
+
+/* fres - fres. */
+uint64_t helper_fres (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    float32 f32;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN reciprocal */
+        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+    }
+    farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+    f32 = float64_to_float32(farg.d, &env->fp_status);
+    farg.d = float32_to_float64(f32, &env->fp_status);
+
+    return farg.ll;
+}
+
+/* frsqrte  - frsqrte. */
+uint64_t helper_frsqrte (uint64_t arg)
+{
+    CPU_DoubleU farg;
+    float32 f32;
+    farg.ll = arg;
+
+    if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+        /* Reciprocal square root of a negative nonzero number */
+        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg.d))) {
+            /* sNaN reciprocal square root */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg.d = float64_sqrt(farg.d, &env->fp_status);
+        farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+        f32 = float64_to_float32(farg.d, &env->fp_status);
+        farg.d = float32_to_float64(f32, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+/* fsel - fsel. */
+uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+    CPU_DoubleU farg1;
+
+    farg1.ll = arg1;
+
+    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
+        return arg2;
+    } else {
+        return arg3;
+    }
+}
+
+void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+    CPU_DoubleU farg1, farg2;
+    uint32_t ret = 0;
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely(float64_is_any_nan(farg1.d) ||
+                 float64_is_any_nan(farg2.d))) {
+        ret = 0x01UL;
+    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+        ret = 0x08UL;
+    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+        ret = 0x04UL;
+    } else {
+        ret = 0x02UL;
+    }
+
+    env->fpscr &= ~(0x0F << FPSCR_FPRF);
+    env->fpscr |= ret << FPSCR_FPRF;
+    env->crf[crfD] = ret;
+    if (unlikely(ret == 0x01UL
+                 && (float64_is_signaling_nan(farg1.d) ||
+                     float64_is_signaling_nan(farg2.d)))) {
+        /* sNaN comparison */
+        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+    }
+}
+
+void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+    CPU_DoubleU farg1, farg2;
+    uint32_t ret = 0;
+    farg1.ll = arg1;
+    farg2.ll = arg2;
+
+    if (unlikely(float64_is_any_nan(farg1.d) ||
+                 float64_is_any_nan(farg2.d))) {
+        ret = 0x01UL;
+    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+        ret = 0x08UL;
+    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+        ret = 0x04UL;
+    } else {
+        ret = 0x02UL;
+    }
+
+    env->fpscr &= ~(0x0F << FPSCR_FPRF);
+    env->fpscr |= ret << FPSCR_FPRF;
+    env->crf[crfD] = ret;
+    if (unlikely (ret == 0x01UL)) {
+        if (float64_is_signaling_nan(farg1.d) ||
+            float64_is_signaling_nan(farg2.d)) {
+            /* sNaN comparison */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+                                  POWERPC_EXCP_FP_VXVC);
+        } else {
+            /* qNaN comparison */
+            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
+        }
+    }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void helper_store_msr (target_ulong val)
+{
+    val = hreg_store_msr(env, val, 0);
+    if (val != 0) {
+        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+        helper_raise_exception(val);
+    }
+}
+
+static inline void do_rfi(target_ulong nip, target_ulong msr,
+                          target_ulong msrm, int keep_msrh)
+{
+#if defined(TARGET_PPC64)
+    if (msr & (1ULL << MSR_SF)) {
+        nip = (uint64_t)nip;
+        msr &= (uint64_t)msrm;
+    } else {
+        nip = (uint32_t)nip;
+        msr = (uint32_t)(msr & msrm);
+        if (keep_msrh)
+            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
+    }
+#else
+    nip = (uint32_t)nip;
+    msr &= (uint32_t)msrm;
+#endif
+    /* XXX: beware: this is false if VLE is supported */
+    env->nip = nip & ~((target_ulong)0x00000003);
+    hreg_store_msr(env, msr, 1);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, env->msr);
+#endif
+    /* No need to raise an exception here,
+     * as rfi is always the last insn of a TB
+     */
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+void helper_rfi (void)
+{
+    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+           ~((target_ulong)0x783F0000), 1);
+}
+
+#if defined(TARGET_PPC64)
+void helper_rfid (void)
+{
+    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+           ~((target_ulong)0x783F0000), 0);
+}
+
+void helper_hrfid (void)
+{
+    do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
+           ~((target_ulong)0x783F0000), 0);
+}
+#endif
+#endif
+
+void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
+{
+    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
+                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
+                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
+                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
+                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+    }
+}
+
+#if defined(TARGET_PPC64)
+void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
+{
+    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
+                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
+                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
+                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
+                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+}
+#endif
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+target_ulong helper_clcs (uint32_t arg)
+{
+    switch (arg) {
+    case 0x0CUL:
+        /* Instruction cache line size */
+        return env->icache_line_size;
+        break;
+    case 0x0DUL:
+        /* Data cache line size */
+        return env->dcache_line_size;
+        break;
+    case 0x0EUL:
+        /* Minimum cache line size */
+        return (env->icache_line_size < env->dcache_line_size) ?
+                env->icache_line_size : env->dcache_line_size;
+        break;
+    case 0x0FUL:
+        /* Maximum cache line size */
+        return (env->icache_line_size > env->dcache_line_size) ?
+                env->icache_line_size : env->dcache_line_size;
+        break;
+    default:
+        /* Undefined */
+        return 0;
+        break;
+    }
+}
+
+target_ulong helper_div (target_ulong arg1, target_ulong arg2)
+{
+    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
+
+    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+        (int32_t)arg2 == 0) {
+        env->spr[SPR_MQ] = 0;
+        return INT32_MIN;
+    } else {
+        env->spr[SPR_MQ] = tmp % arg2;
+        return  tmp / (int32_t)arg2;
+    }
+}
+
+target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
+{
+    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
+
+    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+        (int32_t)arg2 == 0) {
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
+        env->spr[SPR_MQ] = 0;
+        return INT32_MIN;
+    } else {
+        env->spr[SPR_MQ] = tmp % arg2;
+        tmp /= (int32_t)arg2;
+	if ((int32_t)tmp != tmp) {
+            env->xer |= (1 << XER_OV) | (1 << XER_SO);
+        } else {
+            env->xer &= ~(1 << XER_OV);
+        }
+        return tmp;
+    }
+}
+
+target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
+{
+    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+        (int32_t)arg2 == 0) {
+        env->spr[SPR_MQ] = 0;
+        return INT32_MIN;
+    } else {
+        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+        return (int32_t)arg1 / (int32_t)arg2;
+    }
+}
+
+target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
+{
+    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+        (int32_t)arg2 == 0) {
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
+        env->spr[SPR_MQ] = 0;
+        return INT32_MIN;
+    } else {
+        env->xer &= ~(1 << XER_OV);
+        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+        return (int32_t)arg1 / (int32_t)arg2;
+    }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+target_ulong helper_rac (target_ulong addr)
+{
+    mmu_ctx_t ctx;
+    int nb_BATs;
+    target_ulong ret = 0;
+
+    /* We don't have to generate many instances of this instruction,
+     * as rac is supervisor only.
+     */
+    /* XXX: FIX THIS: Pretend we have no BAT */
+    nb_BATs = env->nb_BATs;
+    env->nb_BATs = 0;
+    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
+        ret = ctx.raddr;
+    env->nb_BATs = nb_BATs;
+    return ret;
+}
+
+void helper_rfsvc (void)
+{
+    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
+}
+#endif
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+/* Extremly decomposed:
+ *                      -arg / 256
+ * return 256 * log10(10           + 1.0) + 0.5
+ */
+#if !defined (CONFIG_USER_ONLY)
+target_ulong helper_602_mfrom (target_ulong arg)
+{
+    if (likely(arg < 602)) {
+#include "mfrom_table.c"
+        return mfrom_ROM_table[arg];
+    } else {
+        return 0;
+    }
+}
+#endif
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+
+/* XXX: to be improved to check access rights when in user-mode */
+target_ulong helper_load_dcr (target_ulong dcrn)
+{
+    uint32_t val = 0;
+
+    if (unlikely(env->dcr_env == NULL)) {
+        qemu_log("No DCR environment\n");
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
+        qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+    }
+    return val;
+}
+
+void helper_store_dcr (target_ulong dcrn, target_ulong val)
+{
+    if (unlikely(env->dcr_env == NULL)) {
+        qemu_log("No DCR environment\n");
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
+        qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void helper_40x_rfci (void)
+{
+    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
+           ~((target_ulong)0xFFFF0000), 0);
+}
+
+void helper_rfci (void)
+{
+    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfdi (void)
+{
+    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfmci (void)
+{
+    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+#endif
+
+/* 440 specific */
+target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
+{
+    target_ulong mask;
+    int i;
+
+    i = 1;
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((high & mask) == 0) {
+            if (update_Rc) {
+                env->crf[0] = 0x4;
+            }
+            goto done;
+        }
+        i++;
+    }
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((low & mask) == 0) {
+            if (update_Rc) {
+                env->crf[0] = 0x8;
+            }
+            goto done;
+        }
+        i++;
+    }
+    if (update_Rc) {
+        env->crf[0] = 0x2;
+    }
+ done:
+    env->xer = (env->xer & ~0x7F) | i;
+    if (update_Rc) {
+        env->crf[0] |= xer_so;
+    }
+    return i;
+}
+
+/*****************************************************************************/
+/* Altivec extension helpers */
+#if defined(HOST_WORDS_BIGENDIAN)
+#define HI_IDX 0
+#define LO_IDX 1
+#else
+#define HI_IDX 1
+#define LO_IDX 0
+#endif
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define VECTOR_FOR_INORDER_I(index, element)            \
+    for (index = 0; index < ARRAY_SIZE(r->element); index++)
+#else
+#define VECTOR_FOR_INORDER_I(index, element)            \
+  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
+#endif
+
+/* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
+ * execute the following block.  */
+#define DO_HANDLE_NAN(result, x)                \
+    if (float32_is_any_nan(x)) {                                \
+        CPU_FloatU __f;                                         \
+        __f.f = x;                                              \
+        __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
+        result = __f.f;                                         \
+    } else
+
+#define HANDLE_NAN1(result, x)                  \
+    DO_HANDLE_NAN(result, x)
+#define HANDLE_NAN2(result, x, y)               \
+    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
+#define HANDLE_NAN3(result, x, y, z)            \
+    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
+
+/* Saturating arithmetic helpers.  */
+#define SATCVT(from, to, from_type, to_type, min, max)                  \
+    static inline to_type cvt##from##to(from_type x, int *sat)          \
+    {                                                                   \
+        to_type r;                                                      \
+        if (x < (from_type)min) {                                       \
+            r = min;                                                    \
+            *sat = 1;                                                   \
+        } else if (x > (from_type)max) {                                \
+            r = max;                                                    \
+            *sat = 1;                                                   \
+        } else {                                                        \
+            r = x;                                                      \
+        }                                                               \
+        return r;                                                       \
+    }
+#define SATCVTU(from, to, from_type, to_type, min, max)                 \
+    static inline to_type cvt##from##to(from_type x, int *sat)          \
+    {                                                                   \
+        to_type r;                                                      \
+        if (x > (from_type)max) {                                       \
+            r = max;                                                    \
+            *sat = 1;                                                   \
+        } else {                                                        \
+            r = x;                                                      \
+        }                                                               \
+        return r;                                                       \
+    }
+SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
+SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
+SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
+
+SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
+SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
+SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
+SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
+SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
+SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
+#undef SATCVT
+#undef SATCVTU
+
+#define LVE(name, access, swap, element)                        \
+    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
+    {                                                           \
+        size_t n_elems = ARRAY_SIZE(r->element);                \
+        int adjust = HI_IDX*(n_elems-1);                        \
+        int sh = sizeof(r->element[0]) >> 1;                    \
+        int index = (addr & 0xf) >> sh;                         \
+        if(msr_le) {                                            \
+            r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
+        } else {                                                        \
+            r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
+        }                                                               \
+    }
+#define I(x) (x)
+LVE(lvebx, ldub, I, u8)
+LVE(lvehx, lduw, bswap16, u16)
+LVE(lvewx, ldl, bswap32, u32)
+#undef I
+#undef LVE
+
+void helper_lvsl (ppc_avr_t *r, target_ulong sh)
+{
+    int i, j = (sh & 0xf);
+
+    VECTOR_FOR_INORDER_I (i, u8) {
+        r->u8[i] = j++;
+    }
+}
+
+void helper_lvsr (ppc_avr_t *r, target_ulong sh)
+{
+    int i, j = 0x10 - (sh & 0xf);
+
+    VECTOR_FOR_INORDER_I (i, u8) {
+        r->u8[i] = j++;
+    }
+}
+
+#define STVE(name, access, swap, element)                       \
+    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
+    {                                                           \
+        size_t n_elems = ARRAY_SIZE(r->element);                \
+        int adjust = HI_IDX*(n_elems-1);                        \
+        int sh = sizeof(r->element[0]) >> 1;                    \
+        int index = (addr & 0xf) >> sh;                         \
+        if(msr_le) {                                            \
+            access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
+        } else {                                                        \
+            access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
+        }                                                               \
+    }
+#define I(x) (x)
+STVE(stvebx, stb, I, u8)
+STVE(stvehx, stw, bswap16, u16)
+STVE(stvewx, stl, bswap32, u32)
+#undef I
+#undef LVE
+
+void helper_mtvscr (ppc_avr_t *r)
+{
+#if defined(HOST_WORDS_BIGENDIAN)
+    env->vscr = r->u32[3];
+#else
+    env->vscr = r->u32[0];
+#endif
+    set_flush_to_zero(vscr_nj, &env->vec_status);
+}
+
+void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+        r->u32[i] = ~a->u32[i] < b->u32[i];
+    }
+}
+
+#define VARITH_DO(name, op, element)        \
+void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
+{                                                                       \
+    int i;                                                              \
+    for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
+        r->element[i] = a->element[i] op b->element[i];                 \
+    }                                                                   \
+}
+#define VARITH(suffix, element)                  \
+  VARITH_DO(add##suffix, +, element)             \
+  VARITH_DO(sub##suffix, -, element)
+VARITH(ubm, u8)
+VARITH(uhm, u16)
+VARITH(uwm, u32)
+#undef VARITH_DO
+#undef VARITH
+
+#define VARITHFP(suffix, func)                                          \
+    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
+                r->f[i] = func(a->f[i], b->f[i], &env->vec_status);     \
+            }                                                           \
+        }                                                               \
+    }
+VARITHFP(addfp, float32_add)
+VARITHFP(subfp, float32_sub)
+#undef VARITHFP
+
+#define VARITHSAT_CASE(type, op, cvt, element)                          \
+    {                                                                   \
+        type result = (type)a->element[i] op (type)b->element[i];       \
+        r->element[i] = cvt(result, &sat);                              \
+    }
+
+#define VARITHSAT_DO(name, op, optype, cvt, element)                    \
+    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
+    {                                                                   \
+        int sat = 0;                                                    \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            switch (sizeof(r->element[0])) {                            \
+            case 1: VARITHSAT_CASE(optype, op, cvt, element); break;    \
+            case 2: VARITHSAT_CASE(optype, op, cvt, element); break;    \
+            case 4: VARITHSAT_CASE(optype, op, cvt, element); break;    \
+            }                                                           \
+        }                                                               \
+        if (sat) {                                                      \
+            env->vscr |= (1 << VSCR_SAT);                               \
+        }                                                               \
+    }
+#define VARITHSAT_SIGNED(suffix, element, optype, cvt)        \
+    VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element)    \
+    VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
+#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt)       \
+    VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element)     \
+    VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
+VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
+VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
+VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
+VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
+VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
+VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
+#undef VARITHSAT_CASE
+#undef VARITHSAT_DO
+#undef VARITHSAT_SIGNED
+#undef VARITHSAT_UNSIGNED
+
+#define VAVG_DO(name, element, etype)                                   \
+    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
+            r->element[i] = x >> 1;                                     \
+        }                                                               \
+    }
+
+#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
+    VAVG_DO(avgs##type, signed_element, signed_type)                    \
+    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
+VAVG(b, s8, int16_t, u8, uint16_t)
+VAVG(h, s16, int32_t, u16, uint32_t)
+VAVG(w, s32, int64_t, u32, uint64_t)
+#undef VAVG_DO
+#undef VAVG
+
+#define VCF(suffix, cvt, element)                                       \
+    void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            float32 t = cvt(b->element[i], &env->vec_status);           \
+            r->f[i] = float32_scalbn (t, -uim, &env->vec_status);       \
+        }                                                               \
+    }
+VCF(ux, uint32_to_float32, u32)
+VCF(sx, int32_to_float32, s32)
+#undef VCF
+
+#define VCMP_DO(suffix, compare, element, record)                       \
+    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+    {                                                                   \
+        uint32_t ones = (uint32_t)-1;                                   \
+        uint32_t all = ones;                                            \
+        uint32_t none = 0;                                              \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
+            switch (sizeof (a->element[0])) {                           \
+            case 4: r->u32[i] = result; break;                          \
+            case 2: r->u16[i] = result; break;                          \
+            case 1: r->u8[i] = result; break;                           \
+            }                                                           \
+            all &= result;                                              \
+            none |= result;                                             \
+        }                                                               \
+        if (record) {                                                   \
+            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
+        }                                                               \
+    }
+#define VCMP(suffix, compare, element)          \
+    VCMP_DO(suffix, compare, element, 0)        \
+    VCMP_DO(suffix##_dot, compare, element, 1)
+VCMP(equb, ==, u8)
+VCMP(equh, ==, u16)
+VCMP(equw, ==, u32)
+VCMP(gtub, >, u8)
+VCMP(gtuh, >, u16)
+VCMP(gtuw, >, u32)
+VCMP(gtsb, >, s8)
+VCMP(gtsh, >, s16)
+VCMP(gtsw, >, s32)
+#undef VCMP_DO
+#undef VCMP
+
+#define VCMPFP_DO(suffix, compare, order, record)                       \
+    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+    {                                                                   \
+        uint32_t ones = (uint32_t)-1;                                   \
+        uint32_t all = ones;                                            \
+        uint32_t none = 0;                                              \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            uint32_t result;                                            \
+            int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
+            if (rel == float_relation_unordered) {                      \
+                result = 0;                                             \
+            } else if (rel compare order) {                             \
+                result = ones;                                          \
+            } else {                                                    \
+                result = 0;                                             \
+            }                                                           \
+            r->u32[i] = result;                                         \
+            all &= result;                                              \
+            none |= result;                                             \
+        }                                                               \
+        if (record) {                                                   \
+            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
+        }                                                               \
+    }
+#define VCMPFP(suffix, compare, order)           \
+    VCMPFP_DO(suffix, compare, order, 0)         \
+    VCMPFP_DO(suffix##_dot, compare, order, 1)
+VCMPFP(eqfp, ==, float_relation_equal)
+VCMPFP(gefp, !=, float_relation_less)
+VCMPFP(gtfp, ==, float_relation_greater)
+#undef VCMPFP_DO
+#undef VCMPFP
+
+static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
+                                    int record)
+{
+    int i;
+    int all_in = 0;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
+        if (le_rel == float_relation_unordered) {
+            r->u32[i] = 0xc0000000;
+            /* ALL_IN does not need to be updated here.  */
+        } else {
+            float32 bneg = float32_chs(b->f[i]);
+            int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
+            int le = le_rel != float_relation_greater;
+            int ge = ge_rel != float_relation_less;
+            r->u32[i] = ((!le) << 31) | ((!ge) << 30);
+            all_in |= (!le | !ge);
+        }
+    }
+    if (record) {
+        env->crf[6] = (all_in == 0) << 1;
+    }
+}
+
+void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    vcmpbfp_internal(r, a, b, 0);
+}
+
+void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    vcmpbfp_internal(r, a, b, 1);
+}
+
+#define VCT(suffix, satcvt, element)                                    \
+    void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
+    {                                                                   \
+        int i;                                                          \
+        int sat = 0;                                                    \
+        float_status s = env->vec_status;                               \
+        set_float_rounding_mode(float_round_to_zero, &s);               \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            if (float32_is_any_nan(b->f[i])) {                          \
+                r->element[i] = 0;                                      \
+            } else {                                                    \
+                float64 t = float32_to_float64(b->f[i], &s);            \
+                int64_t j;                                              \
+                t = float64_scalbn(t, uim, &s);                         \
+                j = float64_to_int64(t, &s);                            \
+                r->element[i] = satcvt(j, &sat);                        \
+            }                                                           \
+        }                                                               \
+        if (sat) {                                                      \
+            env->vscr |= (1 << VSCR_SAT);                               \
+        }                                                               \
+    }
+VCT(uxs, cvtsduw, u32)
+VCT(sxs, cvtsdsw, s32)
+#undef VCT
+
+void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
+            /* Need to do the computation in higher precision and round
+             * once at the end.  */
+            float64 af, bf, cf, t;
+            af = float32_to_float64(a->f[i], &env->vec_status);
+            bf = float32_to_float64(b->f[i], &env->vec_status);
+            cf = float32_to_float64(c->f[i], &env->vec_status);
+            t = float64_mul(af, cf, &env->vec_status);
+            t = float64_add(t, bf, &env->vec_status);
+            r->f[i] = float64_to_float32(t, &env->vec_status);
+        }
+    }
+}
+
+void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int sat = 0;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+        int32_t prod = a->s16[i] * b->s16[i];
+        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
+        r->s16[i] = cvtswsh (t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int sat = 0;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
+        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
+        r->s16[i] = cvtswsh (t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+#define VMINMAX_DO(name, compare, element)                              \
+    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            if (a->element[i] compare b->element[i]) {                  \
+                r->element[i] = b->element[i];                          \
+            } else {                                                    \
+                r->element[i] = a->element[i];                          \
+            }                                                           \
+        }                                                               \
+    }
+#define VMINMAX(suffix, element)                \
+  VMINMAX_DO(min##suffix, >, element)           \
+  VMINMAX_DO(max##suffix, <, element)
+VMINMAX(sb, s8)
+VMINMAX(sh, s16)
+VMINMAX(sw, s32)
+VMINMAX(ub, u8)
+VMINMAX(uh, u16)
+VMINMAX(uw, u32)
+#undef VMINMAX_DO
+#undef VMINMAX
+
+#define VMINMAXFP(suffix, rT, rF)                                       \
+    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
+                if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
+                    r->f[i] = rT->f[i];                                 \
+                } else {                                                \
+                    r->f[i] = rF->f[i];                                 \
+                }                                                       \
+            }                                                           \
+        }                                                               \
+    }
+VMINMAXFP(minfp, a, b)
+VMINMAXFP(maxfp, b, a)
+#undef VMINMAXFP
+
+void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+        int32_t prod = a->s16[i] * b->s16[i];
+        r->s16[i] = (int16_t) (prod + c->s16[i]);
+    }
+}
+
+#define VMRG_DO(name, element, highp)                                   \
+    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
+    {                                                                   \
+        ppc_avr_t result;                                               \
+        int i;                                                          \
+        size_t n_elems = ARRAY_SIZE(r->element);                        \
+        for (i = 0; i < n_elems/2; i++) {                               \
+            if (highp) {                                                \
+                result.element[i*2+HI_IDX] = a->element[i];             \
+                result.element[i*2+LO_IDX] = b->element[i];             \
+            } else {                                                    \
+                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
+                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
+            }                                                           \
+        }                                                               \
+        *r = result;                                                    \
+    }
+#if defined(HOST_WORDS_BIGENDIAN)
+#define MRGHI 0
+#define MRGLO 1
+#else
+#define MRGHI 1
+#define MRGLO 0
+#endif
+#define VMRG(suffix, element)                   \
+  VMRG_DO(mrgl##suffix, element, MRGHI)         \
+  VMRG_DO(mrgh##suffix, element, MRGLO)
+VMRG(b, u8)
+VMRG(h, u16)
+VMRG(w, u32)
+#undef VMRG_DO
+#undef VMRG
+#undef MRGHI
+#undef MRGLO
+
+void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int32_t prod[16];
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
+        prod[i] = (int32_t)a->s8[i] * b->u8[i];
+    }
+
+    VECTOR_FOR_INORDER_I(i, s32) {
+        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
+    }
+}
+
+void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int32_t prod[8];
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+        prod[i] = a->s16[i] * b->s16[i];
+    }
+
+    VECTOR_FOR_INORDER_I(i, s32) {
+        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
+    }
+}
+
+void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int32_t prod[8];
+    int i;
+    int sat = 0;
+
+    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+        prod[i] = (int32_t)a->s16[i] * b->s16[i];
+    }
+
+    VECTOR_FOR_INORDER_I (i, s32) {
+        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
+        r->u32[i] = cvtsdsw(t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    uint16_t prod[16];
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+        prod[i] = a->u8[i] * b->u8[i];
+    }
+
+    VECTOR_FOR_INORDER_I(i, u32) {
+        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
+    }
+}
+
+void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    uint32_t prod[8];
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
+        prod[i] = a->u16[i] * b->u16[i];
+    }
+
+    VECTOR_FOR_INORDER_I(i, u32) {
+        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
+    }
+}
+
+void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    uint32_t prod[8];
+    int i;
+    int sat = 0;
+
+    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
+        prod[i] = a->u16[i] * b->u16[i];
+    }
+
+    VECTOR_FOR_INORDER_I (i, s32) {
+        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
+        r->u32[i] = cvtuduw(t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
+    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
+    {                                                                   \
+        int i;                                                          \
+        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
+            if (evenp) {                                                \
+                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
+            } else {                                                    \
+                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
+            }                                                           \
+        }                                                               \
+    }
+#define VMUL(suffix, mul_element, prod_element) \
+  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
+  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
+VMUL(sb, s8, s16)
+VMUL(sh, s16, s32)
+VMUL(ub, u8, u16)
+VMUL(uh, u16, u32)
+#undef VMUL_DO
+#undef VMUL
+
+void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
+            /* Need to do the computation is higher precision and round
+             * once at the end.  */
+            float64 af, bf, cf, t;
+            af = float32_to_float64(a->f[i], &env->vec_status);
+            bf = float32_to_float64(b->f[i], &env->vec_status);
+            cf = float32_to_float64(c->f[i], &env->vec_status);
+            t = float64_mul(af, cf, &env->vec_status);
+            t = float64_sub(t, bf, &env->vec_status);
+            t = float64_chs(t);
+            r->f[i] = float64_to_float32(t, &env->vec_status);
+        }
+    }
+}
+
+void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    ppc_avr_t result;
+    int i;
+    VECTOR_FOR_INORDER_I (i, u8) {
+        int s = c->u8[i] & 0x1f;
+#if defined(HOST_WORDS_BIGENDIAN)
+        int index = s & 0xf;
+#else
+        int index = 15 - (s & 0xf);
+#endif
+        if (s & 0x10) {
+            result.u8[i] = b->u8[index];
+        } else {
+            result.u8[i] = a->u8[index];
+        }
+    }
+    *r = result;
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define PKBIG 1
+#else
+#define PKBIG 0
+#endif
+void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i, j;
+    ppc_avr_t result;
+#if defined(HOST_WORDS_BIGENDIAN)
+    const ppc_avr_t *x[2] = { a, b };
+#else
+    const ppc_avr_t *x[2] = { b, a };
+#endif
+
+    VECTOR_FOR_INORDER_I (i, u64) {
+        VECTOR_FOR_INORDER_I (j, u32){
+            uint32_t e = x[i]->u32[j];
+            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
+                                 ((e >> 6) & 0x3e0) |
+                                 ((e >> 3) & 0x1f));
+        }
+    }
+    *r = result;
+}
+
+#define VPK(suffix, from, to, cvt, dosat)       \
+    void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
+    {                                                                   \
+        int i;                                                          \
+        int sat = 0;                                                    \
+        ppc_avr_t result;                                               \
+        ppc_avr_t *a0 = PKBIG ? a : b;                                  \
+        ppc_avr_t *a1 = PKBIG ? b : a;                                  \
+        VECTOR_FOR_INORDER_I (i, from) {                                \
+            result.to[i] = cvt(a0->from[i], &sat);                      \
+            result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);  \
+        }                                                               \
+        *r = result;                                                    \
+        if (dosat && sat) {                                             \
+            env->vscr |= (1 << VSCR_SAT);                               \
+        }                                                               \
+    }
+#define I(x, y) (x)
+VPK(shss, s16, s8, cvtshsb, 1)
+VPK(shus, s16, u8, cvtshub, 1)
+VPK(swss, s32, s16, cvtswsh, 1)
+VPK(swus, s32, u16, cvtswuh, 1)
+VPK(uhus, u16, u8, cvtuhub, 1)
+VPK(uwus, u32, u16, cvtuwuh, 1)
+VPK(uhum, u16, u8, I, 0)
+VPK(uwum, u32, u16, I, 0)
+#undef I
+#undef VPK
+#undef PKBIG
+
+void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN1(r->f[i], b->f[i]) {
+            r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
+        }
+    }
+}
+
+#define VRFI(suffix, rounding)                                          \
+    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
+    {                                                                   \
+        int i;                                                          \
+        float_status s = env->vec_status;                               \
+        set_float_rounding_mode(rounding, &s);                          \
+        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
+            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
+                r->f[i] = float32_round_to_int (b->f[i], &s);           \
+            }                                                           \
+        }                                                               \
+    }
+VRFI(n, float_round_nearest_even)
+VRFI(m, float_round_down)
+VRFI(p, float_round_up)
+VRFI(z, float_round_to_zero)
+#undef VRFI
+
+#define VROTATE(suffix, element)                                        \
+    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+            unsigned int shift = b->element[i] & mask;                  \
+            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
+        }                                                               \
+    }
+VROTATE(b, u8)
+VROTATE(h, u16)
+VROTATE(w, u32)
+#undef VROTATE
+
+void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN1(r->f[i], b->f[i]) {
+            float32 t = float32_sqrt(b->f[i], &env->vec_status);
+            r->f[i] = float32_div(float32_one, t, &env->vec_status);
+        }
+    }
+}
+
+void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
+    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
+}
+
+void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN1(r->f[i], b->f[i]) {
+            r->f[i] = float32_exp2(b->f[i], &env->vec_status);
+        }
+    }
+}
+
+void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+        HANDLE_NAN1(r->f[i], b->f[i]) {
+            r->f[i] = float32_log2(b->f[i], &env->vec_status);
+        }
+    }
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define LEFT 0
+#define RIGHT 1
+#else
+#define LEFT 1
+#define RIGHT 0
+#endif
+/* The specification says that the results are undefined if all of the
+ * shift counts are not identical.  We check to make sure that they are
+ * to conform to what real hardware appears to do.  */
+#define VSHIFT(suffix, leftp)                                           \
+    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
+    {                                                                   \
+        int shift = b->u8[LO_IDX*15] & 0x7;                             \
+        int doit = 1;                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
+            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
+        }                                                               \
+        if (doit) {                                                     \
+            if (shift == 0) {                                           \
+                *r = *a;                                                \
+            } else if (leftp) {                                         \
+                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
+                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
+                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
+            } else {                                                    \
+                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
+                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
+                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
+            }                                                           \
+        }                                                               \
+    }
+VSHIFT(l, LEFT)
+VSHIFT(r, RIGHT)
+#undef VSHIFT
+#undef LEFT
+#undef RIGHT
+
+#define VSL(suffix, element)                                            \
+    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+            unsigned int shift = b->element[i] & mask;                  \
+            r->element[i] = a->element[i] << shift;                     \
+        }                                                               \
+    }
+VSL(b, u8)
+VSL(h, u16)
+VSL(w, u32)
+#undef VSL
+
+void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
+{
+    int sh = shift & 0xf;
+    int i;
+    ppc_avr_t result;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+        int index = sh + i;
+        if (index > 0xf) {
+            result.u8[i] = b->u8[index-0x10];
+        } else {
+            result.u8[i] = a->u8[index];
+        }
+    }
+#else
+    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+        int index = (16 - sh) + i;
+        if (index > 0xf) {
+            result.u8[i] = a->u8[index-0x10];
+        } else {
+            result.u8[i] = b->u8[index];
+        }
+    }
+#endif
+    *r = result;
+}
+
+void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
+
+#if defined (HOST_WORDS_BIGENDIAN)
+  memmove (&r->u8[0], &a->u8[sh], 16-sh);
+  memset (&r->u8[16-sh], 0, sh);
+#else
+  memmove (&r->u8[sh], &a->u8[0], 16-sh);
+  memset (&r->u8[0], 0, sh);
+#endif
+}
+
+/* Experimental testing shows that hardware masks the immediate.  */
+#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
+#if defined(HOST_WORDS_BIGENDIAN)
+#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
+#else
+#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
+#endif
+#define VSPLT(suffix, element)                                          \
+    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
+    {                                                                   \
+        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            r->element[i] = s;                                          \
+        }                                                               \
+    }
+VSPLT(b, u8)
+VSPLT(h, u16)
+VSPLT(w, u32)
+#undef VSPLT
+#undef SPLAT_ELEMENT
+#undef _SPLAT_MASKED
+
+#define VSPLTI(suffix, element, splat_type)                     \
+    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
+    {                                                           \
+        splat_type x = (int8_t)(splat << 3) >> 3;               \
+        int i;                                                  \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
+            r->element[i] = x;                                  \
+        }                                                       \
+    }
+VSPLTI(b, s8, int8_t)
+VSPLTI(h, s16, int16_t)
+VSPLTI(w, s32, int32_t)
+#undef VSPLTI
+
+#define VSR(suffix, element)                                            \
+    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
+    {                                                                   \
+        int i;                                                          \
+        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
+            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+            unsigned int shift = b->element[i] & mask;                  \
+            r->element[i] = a->element[i] >> shift;                     \
+        }                                                               \
+    }
+VSR(ab, s8)
+VSR(ah, s16)
+VSR(aw, s32)
+VSR(b, u8)
+VSR(h, u16)
+VSR(w, u32)
+#undef VSR
+
+void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
+
+#if defined (HOST_WORDS_BIGENDIAN)
+  memmove (&r->u8[sh], &a->u8[0], 16-sh);
+  memset (&r->u8[0], 0, sh);
+#else
+  memmove (&r->u8[0], &a->u8[sh], 16-sh);
+  memset (&r->u8[16-sh], 0, sh);
+#endif
+}
+
+void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+        r->u32[i] = a->u32[i] >= b->u32[i];
+    }
+}
+
+void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int64_t t;
+    int i, upper;
+    ppc_avr_t result;
+    int sat = 0;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+    upper = ARRAY_SIZE(r->s32)-1;
+#else
+    upper = 0;
+#endif
+    t = (int64_t)b->s32[upper];
+    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+        t += a->s32[i];
+        result.s32[i] = 0;
+    }
+    result.s32[upper] = cvtsdsw(t, &sat);
+    *r = result;
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i, j, upper;
+    ppc_avr_t result;
+    int sat = 0;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+    upper = 1;
+#else
+    upper = 0;
+#endif
+    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
+        int64_t t = (int64_t)b->s32[upper+i*2];
+        result.u64[i] = 0;
+        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
+            t += a->s32[2*i+j];
+        }
+        result.s32[upper+i*2] = cvtsdsw(t, &sat);
+    }
+
+    *r = result;
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i, j;
+    int sat = 0;
+
+    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+        int64_t t = (int64_t)b->s32[i];
+        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
+            t += a->s8[4*i+j];
+        }
+        r->s32[i] = cvtsdsw(t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int sat = 0;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+        int64_t t = (int64_t)b->s32[i];
+        t += a->s16[2*i] + a->s16[2*i+1];
+        r->s32[i] = cvtsdsw(t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i, j;
+    int sat = 0;
+
+    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+        uint64_t t = (uint64_t)b->u32[i];
+        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
+            t += a->u8[4*i+j];
+        }
+        r->u32[i] = cvtuduw(t, &sat);
+    }
+
+    if (sat) {
+        env->vscr |= (1 << VSCR_SAT);
+    }
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define UPKHI 1
+#define UPKLO 0
+#else
+#define UPKHI 0
+#define UPKLO 1
+#endif
+#define VUPKPX(suffix, hi)                                      \
+    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
+    {                                                           \
+        int i;                                                  \
+        ppc_avr_t result;                                       \
+        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
+            uint16_t e = b->u16[hi ? i : i+4];                  \
+            uint8_t a = (e >> 15) ? 0xff : 0;                   \
+            uint8_t r = (e >> 10) & 0x1f;                       \
+            uint8_t g = (e >> 5) & 0x1f;                        \
+            uint8_t b = e & 0x1f;                               \
+            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
+        }                                                               \
+        *r = result;                                                    \
+    }
+VUPKPX(lpx, UPKLO)
+VUPKPX(hpx, UPKHI)
+#undef VUPKPX
+
+#define VUPK(suffix, unpacked, packee, hi)                              \
+    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
+    {                                                                   \
+        int i;                                                          \
+        ppc_avr_t result;                                               \
+        if (hi) {                                                       \
+            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
+                result.unpacked[i] = b->packee[i];                      \
+            }                                                           \
+        } else {                                                        \
+            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
+                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
+            }                                                           \
+        }                                                               \
+        *r = result;                                                    \
+    }
+VUPK(hsb, s16, s8, UPKHI)
+VUPK(hsh, s32, s16, UPKHI)
+VUPK(lsb, s16, s8, UPKLO)
+VUPK(lsh, s32, s16, UPKLO)
+#undef VUPK
+#undef UPKHI
+#undef UPKLO
+
+#undef DO_HANDLE_NAN
+#undef HANDLE_NAN1
+#undef HANDLE_NAN2
+#undef HANDLE_NAN3
+#undef VECTOR_FOR_INORDER_I
+#undef HI_IDX
+#undef LO_IDX
+
+/*****************************************************************************/
+/* SPE extension helpers */
+/* Use a table to make this quicker */
+static uint8_t hbrev[16] = {
+    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
+    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
+};
+
+static inline uint8_t byte_reverse(uint8_t val)
+{
+    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
+}
+
+static inline uint32_t word_reverse(uint32_t val)
+{
+    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
+        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
+}
+
+#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
+target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
+{
+    uint32_t a, b, d, mask;
+
+    mask = UINT32_MAX >> (32 - MASKBITS);
+    a = arg1 & mask;
+    b = arg2 & mask;
+    d = word_reverse(1 + word_reverse(a | ~b));
+    return (arg1 & ~mask) | (d & b);
+}
+
+uint32_t helper_cntlsw32 (uint32_t val)
+{
+    if (val & 0x80000000)
+        return clz32(~val);
+    else
+        return clz32(val);
+}
+
+uint32_t helper_cntlzw32 (uint32_t val)
+{
+    return clz32(val);
+}
+
+/* Single-precision floating-point conversions */
+static inline uint32_t efscfsi(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.f = int32_to_float32(val, &env->vec_status);
+
+    return u.l;
+}
+
+static inline uint32_t efscfui(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.f = uint32_to_float32(val, &env->vec_status);
+
+    return u.l;
+}
+
+static inline int32_t efsctsi(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+
+    return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctui(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+
+    return float32_to_uint32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctsiz(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+
+    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuiz(uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+
+    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efscfsf(uint32_t val)
+{
+    CPU_FloatU u;
+    float32 tmp;
+
+    u.f = int32_to_float32(val, &env->vec_status);
+    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
+    u.f = float32_div(u.f, tmp, &env->vec_status);
+
+    return u.l;
+}
+
+static inline uint32_t efscfuf(uint32_t val)
+{
+    CPU_FloatU u;
+    float32 tmp;
+
+    u.f = uint32_to_float32(val, &env->vec_status);
+    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+    u.f = float32_div(u.f, tmp, &env->vec_status);
+
+    return u.l;
+}
+
+static inline uint32_t efsctsf(uint32_t val)
+{
+    CPU_FloatU u;
+    float32 tmp;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+    u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+    return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuf(uint32_t val)
+{
+    CPU_FloatU u;
+    float32 tmp;
+
+    u.l = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float32_is_quiet_nan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+    u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+    return float32_to_uint32(u.f, &env->vec_status);
+}
+
+#define HELPER_SPE_SINGLE_CONV(name)                                          \
+uint32_t helper_e##name (uint32_t val)                                        \
+{                                                                             \
+    return e##name(val);                                                      \
+}
+/* efscfsi */
+HELPER_SPE_SINGLE_CONV(fscfsi);
+/* efscfui */
+HELPER_SPE_SINGLE_CONV(fscfui);
+/* efscfuf */
+HELPER_SPE_SINGLE_CONV(fscfuf);
+/* efscfsf */
+HELPER_SPE_SINGLE_CONV(fscfsf);
+/* efsctsi */
+HELPER_SPE_SINGLE_CONV(fsctsi);
+/* efsctui */
+HELPER_SPE_SINGLE_CONV(fsctui);
+/* efsctsiz */
+HELPER_SPE_SINGLE_CONV(fsctsiz);
+/* efsctuiz */
+HELPER_SPE_SINGLE_CONV(fsctuiz);
+/* efsctsf */
+HELPER_SPE_SINGLE_CONV(fsctsf);
+/* efsctuf */
+HELPER_SPE_SINGLE_CONV(fsctuf);
+
+#define HELPER_SPE_VECTOR_CONV(name)                                          \
+uint64_t helper_ev##name (uint64_t val)                                       \
+{                                                                             \
+    return ((uint64_t)e##name(val >> 32) << 32) |                             \
+            (uint64_t)e##name(val);                                           \
+}
+/* evfscfsi */
+HELPER_SPE_VECTOR_CONV(fscfsi);
+/* evfscfui */
+HELPER_SPE_VECTOR_CONV(fscfui);
+/* evfscfuf */
+HELPER_SPE_VECTOR_CONV(fscfuf);
+/* evfscfsf */
+HELPER_SPE_VECTOR_CONV(fscfsf);
+/* evfsctsi */
+HELPER_SPE_VECTOR_CONV(fsctsi);
+/* evfsctui */
+HELPER_SPE_VECTOR_CONV(fsctui);
+/* evfsctsiz */
+HELPER_SPE_VECTOR_CONV(fsctsiz);
+/* evfsctuiz */
+HELPER_SPE_VECTOR_CONV(fsctuiz);
+/* evfsctsf */
+HELPER_SPE_VECTOR_CONV(fsctsf);
+/* evfsctuf */
+HELPER_SPE_VECTOR_CONV(fsctuf);
+
+/* Single-precision floating-point arithmetic */
+static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
+    return u1.l;
+}
+
+static inline uint32_t efssub(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
+    return u1.l;
+}
+
+static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
+    return u1.l;
+}
+
+static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
+    return u1.l;
+}
+
+#define HELPER_SPE_SINGLE_ARITH(name)                                         \
+uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
+{                                                                             \
+    return e##name(op1, op2);                                                 \
+}
+/* efsadd */
+HELPER_SPE_SINGLE_ARITH(fsadd);
+/* efssub */
+HELPER_SPE_SINGLE_ARITH(fssub);
+/* efsmul */
+HELPER_SPE_SINGLE_ARITH(fsmul);
+/* efsdiv */
+HELPER_SPE_SINGLE_ARITH(fsdiv);
+
+#define HELPER_SPE_VECTOR_ARITH(name)                                         \
+uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
+{                                                                             \
+    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
+            (uint64_t)e##name(op1, op2);                                      \
+}
+/* evfsadd */
+HELPER_SPE_VECTOR_ARITH(fsadd);
+/* evfssub */
+HELPER_SPE_VECTOR_ARITH(fssub);
+/* evfsmul */
+HELPER_SPE_VECTOR_ARITH(fsmul);
+/* evfsdiv */
+HELPER_SPE_VECTOR_ARITH(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
+}
+
+static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
+{
+    CPU_FloatU u1, u2;
+    u1.l = op1;
+    u2.l = op2;
+    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmplt(op1, op2);
+}
+
+static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpgt(op1, op2);
+}
+
+static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpeq(op1, op2);
+}
+
+#define HELPER_SINGLE_SPE_CMP(name)                                           \
+uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
+{                                                                             \
+    return e##name(op1, op2) << 2;                                            \
+}
+/* efststlt */
+HELPER_SINGLE_SPE_CMP(fststlt);
+/* efststgt */
+HELPER_SINGLE_SPE_CMP(fststgt);
+/* efststeq */
+HELPER_SINGLE_SPE_CMP(fststeq);
+/* efscmplt */
+HELPER_SINGLE_SPE_CMP(fscmplt);
+/* efscmpgt */
+HELPER_SINGLE_SPE_CMP(fscmpgt);
+/* efscmpeq */
+HELPER_SINGLE_SPE_CMP(fscmpeq);
+
+static inline uint32_t evcmp_merge(int t0, int t1)
+{
+    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+
+#define HELPER_VECTOR_SPE_CMP(name)                                           \
+uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
+{                                                                             \
+    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
+}
+/* evfststlt */
+HELPER_VECTOR_SPE_CMP(fststlt);
+/* evfststgt */
+HELPER_VECTOR_SPE_CMP(fststgt);
+/* evfststeq */
+HELPER_VECTOR_SPE_CMP(fststeq);
+/* evfscmplt */
+HELPER_VECTOR_SPE_CMP(fscmplt);
+/* evfscmpgt */
+HELPER_VECTOR_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+HELPER_VECTOR_SPE_CMP(fscmpeq);
+
+/* Double-precision floating-point conversion */
+uint64_t helper_efdcfsi (uint32_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = int32_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfsid (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = int64_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfui (uint32_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = uint32_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfuid (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = uint64_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint32_t helper_efdctsi (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctui (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctsiz (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctsidz (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuiz (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctuidz (uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+
+    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdcfsf (uint32_t val)
+{
+    CPU_DoubleU u;
+    float64 tmp;
+
+    u.d = int32_to_float64(val, &env->vec_status);
+    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+    u.d = float64_div(u.d, tmp, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfuf (uint32_t val)
+{
+    CPU_DoubleU u;
+    float64 tmp;
+
+    u.d = uint32_to_float64(val, &env->vec_status);
+    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+    u.d = float64_div(u.d, tmp, &env->vec_status);
+
+    return u.ll;
+}
+
+uint32_t helper_efdctsf (uint64_t val)
+{
+    CPU_DoubleU u;
+    float64 tmp;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+    u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+    return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuf (uint64_t val)
+{
+    CPU_DoubleU u;
+    float64 tmp;
+
+    u.ll = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(float64_is_any_nan(u.d))) {
+        return 0;
+    }
+    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+    u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+    return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efscfd (uint64_t val)
+{
+    CPU_DoubleU u1;
+    CPU_FloatU u2;
+
+    u1.ll = val;
+    u2.f = float64_to_float32(u1.d, &env->vec_status);
+
+    return u2.l;
+}
+
+uint64_t helper_efdcfs (uint32_t val)
+{
+    CPU_DoubleU u2;
+    CPU_FloatU u1;
+
+    u1.l = val;
+    u2.d = float32_to_float64(u1.f, &env->vec_status);
+
+    return u2.ll;
+}
+
+/* Double precision fixed-point arithmetic */
+uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
+    return u1.ll;
+}
+
+uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
+    return u1.ll;
+}
+
+uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
+    return u1.ll;
+}
+
+uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
+    return u1.ll;
+}
+
+/* Double precision floating point helpers */
+uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
+}
+
+uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
+{
+    CPU_DoubleU u1, u2;
+    u1.ll = op1;
+    u2.ll = op2;
+    return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtstlt(op1, op2);
+}
+
+uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtstgt(op1, op2);
+}
+
+uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtsteq(op1, op2);
+}
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret != 0)) {
+        if (likely(retaddr)) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (likely(tb)) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        helper_raise_exception_err(env->exception_index, env->error_code);
+    }
+    env = saved_env;
+}
+
+/* Segment registers load and store */
+target_ulong helper_load_sr (target_ulong sr_num)
+{
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64)
+        return ppc_load_sr(env, sr_num);
+#endif
+    return env->sr[sr_num];
+}
+
+void helper_store_sr (target_ulong sr_num, target_ulong val)
+{
+    ppc_store_sr(env, sr_num, val);
+}
+
+/* SLB management */
+#if defined(TARGET_PPC64)
+void helper_store_slb (target_ulong rb, target_ulong rs)
+{
+    if (ppc_store_slb(env, rb, rs) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+}
+
+target_ulong helper_load_slb_esid (target_ulong rb)
+{
+    target_ulong rt;
+
+    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+
+target_ulong helper_load_slb_vsid (target_ulong rb)
+{
+    target_ulong rt;
+
+    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+
+void helper_slbia (void)
+{
+    ppc_slb_invalidate_all(env);
+}
+
+void helper_slbie (target_ulong addr)
+{
+    ppc_slb_invalidate_one(env, addr);
+}
+
+#endif /* defined(TARGET_PPC64) */
+
+/* TLB management */
+void helper_tlbia (void)
+{
+    ppc_tlb_invalidate_all(env);
+}
+
+void helper_tlbie (target_ulong addr)
+{
+    ppc_tlb_invalidate_one(env, addr);
+}
+
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+static void do_6xx_tlb (target_ulong new_EPN, int is_code)
+{
+    target_ulong RPN, CMP, EPN;
+    int way;
+
+    RPN = env->spr[SPR_RPA];
+    if (is_code) {
+        CMP = env->spr[SPR_ICMP];
+        EPN = env->spr[SPR_IMISS];
+    } else {
+        CMP = env->spr[SPR_DCMP];
+        EPN = env->spr[SPR_DMISS];
+    }
+    way = (env->spr[SPR_SRR1] >> 17) & 1;
+    (void)EPN; /* avoid a compiler warning */
+    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
+              RPN, way);
+    /* Store this TLB */
+    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
+                     way, is_code, CMP, RPN);
+}
+
+void helper_6xx_tlbd (target_ulong EPN)
+{
+    do_6xx_tlb(EPN, 0);
+}
+
+void helper_6xx_tlbi (target_ulong EPN)
+{
+    do_6xx_tlb(EPN, 1);
+}
+
+/* PowerPC 74xx software TLB load instructions helpers */
+static void do_74xx_tlb (target_ulong new_EPN, int is_code)
+{
+    target_ulong RPN, CMP, EPN;
+    int way;
+
+    RPN = env->spr[SPR_PTELO];
+    CMP = env->spr[SPR_PTEHI];
+    EPN = env->spr[SPR_TLBMISS] & ~0x3;
+    way = env->spr[SPR_TLBMISS] & 0x3;
+    (void)EPN; /* avoid a compiler warning */
+    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
+              RPN, way);
+    /* Store this TLB */
+    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
+                     way, is_code, CMP, RPN);
+}
+
+void helper_74xx_tlbd (target_ulong EPN)
+{
+    do_74xx_tlb(EPN, 0);
+}
+
+void helper_74xx_tlbi (target_ulong EPN)
+{
+    do_74xx_tlb(EPN, 1);
+}
+
+static inline target_ulong booke_tlb_to_page_size(int size)
+{
+    return 1024 << (2 * size);
+}
+
+static inline int booke_page_size_to_tlb(target_ulong page_size)
+{
+    int size;
+
+    switch (page_size) {
+    case 0x00000400UL:
+        size = 0x0;
+        break;
+    case 0x00001000UL:
+        size = 0x1;
+        break;
+    case 0x00004000UL:
+        size = 0x2;
+        break;
+    case 0x00010000UL:
+        size = 0x3;
+        break;
+    case 0x00040000UL:
+        size = 0x4;
+        break;
+    case 0x00100000UL:
+        size = 0x5;
+        break;
+    case 0x00400000UL:
+        size = 0x6;
+        break;
+    case 0x01000000UL:
+        size = 0x7;
+        break;
+    case 0x04000000UL:
+        size = 0x8;
+        break;
+    case 0x10000000UL:
+        size = 0x9;
+        break;
+    case 0x40000000UL:
+        size = 0xA;
+        break;
+#if defined (TARGET_PPC64)
+    case 0x000100000000ULL:
+        size = 0xB;
+        break;
+    case 0x000400000000ULL:
+        size = 0xC;
+        break;
+    case 0x001000000000ULL:
+        size = 0xD;
+        break;
+    case 0x004000000000ULL:
+        size = 0xE;
+        break;
+    case 0x010000000000ULL:
+        size = 0xF;
+        break;
+#endif
+    default:
+        size = -1;
+        break;
+    }
+
+    return size;
+}
+
+/* Helpers for 4xx TLB management */
+#define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
+
+#define PPC4XX_TLBHI_V              0x00000040
+#define PPC4XX_TLBHI_E              0x00000020
+#define PPC4XX_TLBHI_SIZE_MIN       0
+#define PPC4XX_TLBHI_SIZE_MAX       7
+#define PPC4XX_TLBHI_SIZE_DEFAULT   1
+#define PPC4XX_TLBHI_SIZE_SHIFT     7
+#define PPC4XX_TLBHI_SIZE_MASK      0x00000007
+
+#define PPC4XX_TLBLO_EX             0x00000200
+#define PPC4XX_TLBLO_WR             0x00000100
+#define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
+#define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
+
+target_ulong helper_4xx_tlbre_hi (target_ulong entry)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong ret;
+    int size;
+
+    entry &= PPC4XX_TLB_ENTRY_MASK;
+    tlb = &env->tlb.tlbe[entry];
+    ret = tlb->EPN;
+    if (tlb->prot & PAGE_VALID) {
+        ret |= PPC4XX_TLBHI_V;
+    }
+    size = booke_page_size_to_tlb(tlb->size);
+    if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
+        size = PPC4XX_TLBHI_SIZE_DEFAULT;
+    }
+    ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
+    env->spr[SPR_40x_PID] = tlb->PID;
+    return ret;
+}
+
+target_ulong helper_4xx_tlbre_lo (target_ulong entry)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong ret;
+
+    entry &= PPC4XX_TLB_ENTRY_MASK;
+    tlb = &env->tlb.tlbe[entry];
+    ret = tlb->RPN;
+    if (tlb->prot & PAGE_EXEC) {
+        ret |= PPC4XX_TLBLO_EX;
+    }
+    if (tlb->prot & PAGE_WRITE) {
+        ret |= PPC4XX_TLBLO_WR;
+    }
+    return ret;
+}
+
+void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong page, end;
+
+    LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
+              val);
+    entry &= PPC4XX_TLB_ENTRY_MASK;
+    tlb = &env->tlb.tlbe[entry];
+    /* Invalidate previous TLB (if it's valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+        LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
+                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env, page);
+        }
+    }
+    tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
+                                       & PPC4XX_TLBHI_SIZE_MASK);
+    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
+     * If this ever occurs, one should use the ppcemb target instead
+     * of the ppc or ppc64 one
+     */
+    if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
+        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
+                  "are not supported (%d)\n",
+                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
+    }
+    tlb->EPN = val & ~(tlb->size - 1);
+    if (val & PPC4XX_TLBHI_V) {
+        tlb->prot |= PAGE_VALID;
+        if (val & PPC4XX_TLBHI_E) {
+            /* XXX: TO BE FIXED */
+            cpu_abort(env,
+                      "Little-endian TLB entries are not supported by now\n");
+        }
+    } else {
+        tlb->prot &= ~PAGE_VALID;
+    }
+    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
+    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
+              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
+              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+              tlb->prot & PAGE_READ ? 'r' : '-',
+              tlb->prot & PAGE_WRITE ? 'w' : '-',
+              tlb->prot & PAGE_EXEC ? 'x' : '-',
+              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+    /* Invalidate new TLB (if valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+        LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
+                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env, page);
+        }
+    }
+}
+
+void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
+{
+    ppcemb_tlb_t *tlb;
+
+    LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
+              val);
+    entry &= PPC4XX_TLB_ENTRY_MASK;
+    tlb = &env->tlb.tlbe[entry];
+    tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
+    tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
+    tlb->prot = PAGE_READ;
+    if (val & PPC4XX_TLBLO_EX) {
+        tlb->prot |= PAGE_EXEC;
+    }
+    if (val & PPC4XX_TLBLO_WR) {
+        tlb->prot |= PAGE_WRITE;
+    }
+    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
+              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
+              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+              tlb->prot & PAGE_READ ? 'r' : '-',
+              tlb->prot & PAGE_WRITE ? 'w' : '-',
+              tlb->prot & PAGE_EXEC ? 'x' : '-',
+              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+}
+
+target_ulong helper_4xx_tlbsx (target_ulong address)
+{
+    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
+}
+
+/* PowerPC 440 TLB management */
+void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong EPN, RPN, size;
+    int do_flush_tlbs;
+
+    LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
+              __func__, word, (int)entry, value);
+    do_flush_tlbs = 0;
+    entry &= 0x3F;
+    tlb = &env->tlb.tlbe[entry];
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        EPN = value & 0xFFFFFC00;
+        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
+            do_flush_tlbs = 1;
+        tlb->EPN = EPN;
+        size = booke_tlb_to_page_size((value >> 4) & 0xF);
+        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
+            do_flush_tlbs = 1;
+        tlb->size = size;
+        tlb->attr &= ~0x1;
+        tlb->attr |= (value >> 8) & 1;
+        if (value & 0x200) {
+            tlb->prot |= PAGE_VALID;
+        } else {
+            if (tlb->prot & PAGE_VALID) {
+                tlb->prot &= ~PAGE_VALID;
+                do_flush_tlbs = 1;
+            }
+        }
+        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
+        if (do_flush_tlbs)
+            tlb_flush(env, 1);
+        break;
+    case 1:
+        RPN = value & 0xFFFFFC0F;
+        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
+            tlb_flush(env, 1);
+        tlb->RPN = RPN;
+        break;
+    case 2:
+        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
+        tlb->prot = tlb->prot & PAGE_VALID;
+        if (value & 0x1)
+            tlb->prot |= PAGE_READ << 4;
+        if (value & 0x2)
+            tlb->prot |= PAGE_WRITE << 4;
+        if (value & 0x4)
+            tlb->prot |= PAGE_EXEC << 4;
+        if (value & 0x8)
+            tlb->prot |= PAGE_READ;
+        if (value & 0x10)
+            tlb->prot |= PAGE_WRITE;
+        if (value & 0x20)
+            tlb->prot |= PAGE_EXEC;
+        break;
+    }
+}
+
+target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong ret;
+    int size;
+
+    entry &= 0x3F;
+    tlb = &env->tlb.tlbe[entry];
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        ret = tlb->EPN;
+        size = booke_page_size_to_tlb(tlb->size);
+        if (size < 0 || size > 0xF)
+            size = 1;
+        ret |= size << 4;
+        if (tlb->attr & 0x1)
+            ret |= 0x100;
+        if (tlb->prot & PAGE_VALID)
+            ret |= 0x200;
+        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
+        env->spr[SPR_440_MMUCR] |= tlb->PID;
+        break;
+    case 1:
+        ret = tlb->RPN;
+        break;
+    case 2:
+        ret = tlb->attr & ~0x1;
+        if (tlb->prot & (PAGE_READ << 4))
+            ret |= 0x1;
+        if (tlb->prot & (PAGE_WRITE << 4))
+            ret |= 0x2;
+        if (tlb->prot & (PAGE_EXEC << 4))
+            ret |= 0x4;
+        if (tlb->prot & PAGE_READ)
+            ret |= 0x8;
+        if (tlb->prot & PAGE_WRITE)
+            ret |= 0x10;
+        if (tlb->prot & PAGE_EXEC)
+            ret |= 0x20;
+        break;
+    }
+    return ret;
+}
+
+target_ulong helper_440_tlbsx (target_ulong address)
+{
+    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
+}
+
+/* PowerPC BookE 2.06 TLB management */
+
+static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env)
+{
+    uint32_t tlbncfg = 0;
+    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
+    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
+    int tlb;
+
+    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
+
+    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
+        cpu_abort(env, "we don't support HES yet\n");
+    }
+
+    return booke206_get_tlbm(env, tlb, ea, esel);
+}
+
+void helper_booke_setpid(uint32_t pidn, target_ulong pid)
+{
+    env->spr[pidn] = pid;
+    /* changing PIDs mean we're in a different address space now */
+    tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbwe(void)
+{
+    uint32_t tlbncfg, tlbn;
+    ppcmas_tlb_t *tlb;
+
+    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
+    case MAS0_WQ_ALWAYS:
+        /* good to go, write that entry */
+        break;
+    case MAS0_WQ_COND:
+        /* XXX check if reserved */
+        if (0) {
+            return;
+        }
+        break;
+    case MAS0_WQ_CLR_RSRV:
+        /* XXX clear entry */
+        return;
+    default:
+        /* no idea what to do */
+        return;
+    }
+
+    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
+         !msr_gs) {
+        /* XXX we don't support direct LRAT setting yet */
+        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
+        return;
+    }
+
+    tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+
+    tlb = booke206_cur_tlb(env);
+
+    if (msr_gs) {
+        cpu_abort(env, "missing HV implementation\n");
+    }
+    tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
+                  env->spr[SPR_BOOKE_MAS3];
+    tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+    /* XXX needs to change when supporting 64-bit e500 */
+    tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
+
+    if (!(tlbncfg & TLBnCFG_IPROT)) {
+        /* no IPROT supported by TLB */
+        tlb->mas1 &= ~MAS1_IPROT;
+    }
+
+    if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
+        tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
+    } else {
+        tlb_flush(env, 1);
+    }
+}
+
+static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb)
+{
+    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+    int way = booke206_tlbm_to_way(env, tlb);
+
+    env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
+    env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+
+    env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
+    env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
+    env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
+    env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
+}
+
+void helper_booke206_tlbre(void)
+{
+    ppcmas_tlb_t *tlb = NULL;
+
+    tlb = booke206_cur_tlb(env);
+    booke206_tlb_to_mas(env, tlb);
+}
+
+void helper_booke206_tlbsx(target_ulong address)
+{
+    ppcmas_tlb_t *tlb = NULL;
+    int i, j;
+    target_phys_addr_t raddr;
+    uint32_t spid, sas;
+
+    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
+    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int ways = booke206_tlb_ways(env, i);
+
+        for (j = 0; j < ways; j++) {
+            tlb = booke206_get_tlbm(env, i, address, j);
+
+            if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
+                continue;
+            }
+
+            if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+                continue;
+            }
+
+            booke206_tlb_to_mas(env, tlb);
+            return;
+        }
+    }
+
+    /* no entry found, fill with defaults */
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+    env->spr[SPR_BOOKE_MAS3] = 0;
+    env->spr[SPR_BOOKE_MAS7] = 0;
+
+    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
+                                << MAS1_TID_SHIFT;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= booke206_tlb_ways(env, 0) - 1;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
+                                              uint32_t ea)
+{
+    int i;
+    int ways = booke206_tlb_ways(env, tlbn);
+    target_ulong mask;
+
+    for (i = 0; i < ways; i++) {
+        ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+        mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+        if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
+            !(tlb->mas1 & MAS1_IPROT)) {
+            tlb->mas1 &= ~MAS1_VALID;
+        }
+    }
+}
+
+void helper_booke206_tlbivax(target_ulong address)
+{
+    if (address & 0x4) {
+        /* flush all entries */
+        if (address & 0x8) {
+            /* flush all of TLB1 */
+            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
+        } else {
+            /* flush all of TLB0 */
+            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
+        }
+        return;
+    }
+
+    if (address & 0x8) {
+        /* flush TLB1 entries */
+        booke206_invalidate_ea_tlb(env, 1, address);
+        tlb_flush(env, 1);
+    } else {
+        /* flush TLB0 entries */
+        booke206_invalidate_ea_tlb(env, 0, address);
+        tlb_flush_page(env, address & MAS2_EPN_MASK);
+    }
+}
+
+void helper_booke206_tlbflush(uint32_t type)
+{
+    int flags = 0;
+
+    if (type & 2) {
+        flags |= BOOKE206_FLUSH_TLB1;
+    }
+
+    if (type & 4) {
+        flags |= BOOKE206_FLUSH_TLB0;
+    }
+
+    booke206_flush_tlb(env, flags, 1);
+}
+
+#endif /* !CONFIG_USER_ONLY */
diff --git a/qemu-0.15.x/target-ppc/translate.c b/qemu-0.15.x/target-ppc/translate.c
new file mode 100644
index 0000000..fd7c208
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/translate.c
@@ -0,0 +1,9539 @@
+/*
+ *  PowerPC emulation for qemu: main translation routines.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *  Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define CPU_SINGLE_STEP 0x1
+#define CPU_BRANCH_STEP 0x2
+#define GDBSTUB_SINGLE_STEP 0x4
+
+/* Include definitions for instructions classes and implementations flags */
+//#define PPC_DEBUG_DISAS
+//#define DO_PPC_STATISTICS
+
+#ifdef PPC_DEBUG_DISAS
+#  define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DISAS(...) do { } while (0)
+#endif
+/*****************************************************************************/
+/* Code translation helpers                                                  */
+
+/* global register indexes */
+static TCGv_ptr cpu_env;
+static char cpu_reg_names[10*3 + 22*4 /* GPR */
+#if !defined(TARGET_PPC64)
+    + 10*4 + 22*5 /* SPE GPRh */
+#endif
+    + 10*4 + 22*5 /* FPR */
+    + 2*(10*6 + 22*7) /* AVRh, AVRl */
+    + 8*5 /* CRF */];
+static TCGv cpu_gpr[32];
+#if !defined(TARGET_PPC64)
+static TCGv cpu_gprh[32];
+#endif
+static TCGv_i64 cpu_fpr[32];
+static TCGv_i64 cpu_avrh[32], cpu_avrl[32];
+static TCGv_i32 cpu_crf[8];
+static TCGv cpu_nip;
+static TCGv cpu_msr;
+static TCGv cpu_ctr;
+static TCGv cpu_lr;
+static TCGv cpu_xer;
+static TCGv cpu_reserve;
+static TCGv_i32 cpu_fpscr;
+static TCGv_i32 cpu_access_type;
+
+#include "gen-icount.h"
+
+void ppc_translate_init(void)
+{
+    int i;
+    char* p;
+    size_t cpu_reg_names_size;
+    static int done_init = 0;
+
+    if (done_init)
+        return;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    p = cpu_reg_names;
+    cpu_reg_names_size = sizeof(cpu_reg_names);
+
+    for (i = 0; i < 8; i++) {
+        snprintf(p, cpu_reg_names_size, "crf%d", i);
+        cpu_crf[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                            offsetof(CPUState, crf[i]), p);
+        p += 5;
+        cpu_reg_names_size -= 5;
+    }
+
+    for (i = 0; i < 32; i++) {
+        snprintf(p, cpu_reg_names_size, "r%d", i);
+        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
+                                        offsetof(CPUState, gpr[i]), p);
+        p += (i < 10) ? 3 : 4;
+        cpu_reg_names_size -= (i < 10) ? 3 : 4;
+#if !defined(TARGET_PPC64)
+        snprintf(p, cpu_reg_names_size, "r%dH", i);
+        cpu_gprh[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, gprh[i]), p);
+        p += (i < 10) ? 4 : 5;
+        cpu_reg_names_size -= (i < 10) ? 4 : 5;
+#endif
+
+        snprintf(p, cpu_reg_names_size, "fp%d", i);
+        cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                            offsetof(CPUState, fpr[i]), p);
+        p += (i < 10) ? 4 : 5;
+        cpu_reg_names_size -= (i < 10) ? 4 : 5;
+
+        snprintf(p, cpu_reg_names_size, "avr%dH", i);
+#ifdef HOST_WORDS_BIGENDIAN
+        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, avr[i].u64[0]), p);
+#else
+        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, avr[i].u64[1]), p);
+#endif
+        p += (i < 10) ? 6 : 7;
+        cpu_reg_names_size -= (i < 10) ? 6 : 7;
+
+        snprintf(p, cpu_reg_names_size, "avr%dL", i);
+#ifdef HOST_WORDS_BIGENDIAN
+        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, avr[i].u64[1]), p);
+#else
+        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUState, avr[i].u64[0]), p);
+#endif
+        p += (i < 10) ? 6 : 7;
+        cpu_reg_names_size -= (i < 10) ? 6 : 7;
+    }
+
+    cpu_nip = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUState, nip), "nip");
+
+    cpu_msr = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUState, msr), "msr");
+
+    cpu_ctr = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUState, ctr), "ctr");
+
+    cpu_lr = tcg_global_mem_new(TCG_AREG0,
+                                offsetof(CPUState, lr), "lr");
+
+    cpu_xer = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUState, xer), "xer");
+
+    cpu_reserve = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, reserve_addr),
+                                     "reserve_addr");
+
+    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
+                                       offsetof(CPUState, fpscr), "fpscr");
+
+    cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, access_type), "access_type");
+
+    /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+
+    done_init = 1;
+}
+
+/* internal defines */
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    target_ulong nip;
+    uint32_t opcode;
+    uint32_t exception;
+    /* Routine used to access memory */
+    int mem_idx;
+    int access_type;
+    /* Translation flags */
+    int le_mode;
+#if defined(TARGET_PPC64)
+    int sf_mode;
+#endif
+    int fpu_enabled;
+    int altivec_enabled;
+    int spe_enabled;
+    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
+    int singlestep_enabled;
+} DisasContext;
+
+struct opc_handler_t {
+    /* invalid bits */
+    uint32_t inval;
+    /* instruction type */
+    uint64_t type;
+    /* extended instruction type */
+    uint64_t type2;
+    /* handler */
+    void (*handler)(DisasContext *ctx);
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
+    const char *oname;
+#endif
+#if defined(DO_PPC_STATISTICS)
+    uint64_t count;
+#endif
+};
+
+static inline void gen_reset_fpstatus(void)
+{
+    gen_helper_reset_fpstatus();
+}
+
+static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+
+    if (set_fprf != 0) {
+        /* This case might be optimized later */
+        tcg_gen_movi_i32(t0, 1);
+        gen_helper_compute_fprf(t0, arg, t0);
+        if (unlikely(set_rc)) {
+            tcg_gen_mov_i32(cpu_crf[1], t0);
+        }
+        gen_helper_float_check_status();
+    } else if (unlikely(set_rc)) {
+        /* We always need to compute fpcc */
+        tcg_gen_movi_i32(t0, 0);
+        gen_helper_compute_fprf(t0, arg, t0);
+        tcg_gen_mov_i32(cpu_crf[1], t0);
+    }
+
+    tcg_temp_free_i32(t0);
+}
+
+static inline void gen_set_access_type(DisasContext *ctx, int access_type)
+{
+    if (ctx->access_type != access_type) {
+        tcg_gen_movi_i32(cpu_access_type, access_type);
+        ctx->access_type = access_type;
+    }
+}
+
+static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        tcg_gen_movi_tl(cpu_nip, nip);
+    else
+#endif
+        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
+}
+
+static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
+{
+    TCGv_i32 t0, t1;
+    if (ctx->exception == POWERPC_EXCP_NONE) {
+        gen_update_nip(ctx, ctx->nip);
+    }
+    t0 = tcg_const_i32(excp);
+    t1 = tcg_const_i32(error);
+    gen_helper_raise_exception_err(t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+    ctx->exception = (excp);
+}
+
+static inline void gen_exception(DisasContext *ctx, uint32_t excp)
+{
+    TCGv_i32 t0;
+    if (ctx->exception == POWERPC_EXCP_NONE) {
+        gen_update_nip(ctx, ctx->nip);
+    }
+    t0 = tcg_const_i32(excp);
+    gen_helper_raise_exception(t0);
+    tcg_temp_free_i32(t0);
+    ctx->exception = (excp);
+}
+
+static inline void gen_debug_exception(DisasContext *ctx)
+{
+    TCGv_i32 t0;
+
+    if (ctx->exception != POWERPC_EXCP_BRANCH)
+        gen_update_nip(ctx, ctx->nip);
+    t0 = tcg_const_i32(EXCP_DEBUG);
+    gen_helper_raise_exception(t0);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void gen_inval_exception(DisasContext *ctx, uint32_t error)
+{
+    gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | error);
+}
+
+/* Stop translation */
+static inline void gen_stop_exception(DisasContext *ctx)
+{
+    gen_update_nip(ctx, ctx->nip);
+    ctx->exception = POWERPC_EXCP_STOP;
+}
+
+/* No need to update nip here, as execution flow will change */
+static inline void gen_sync_exception(DisasContext *ctx)
+{
+    ctx->exception = POWERPC_EXCP_SYNC;
+}
+
+#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER_E(name, opc1, opc2, opc3, inval, type, type2)             \
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, type2)
+
+#define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type)               \
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2)      \
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
+
+typedef struct opcode_t {
+    unsigned char opc1, opc2, opc3;
+#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
+    unsigned char pad[5];
+#else
+    unsigned char pad[1];
+#endif
+    opc_handler_t handler;
+    const char *oname;
+} opcode_t;
+
+/*****************************************************************************/
+/***                           Instruction decoding                        ***/
+#define EXTRACT_HELPER(name, shift, nb)                                       \
+static inline uint32_t name(uint32_t opcode)                                  \
+{                                                                             \
+    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
+}
+
+#define EXTRACT_SHELPER(name, shift, nb)                                      \
+static inline int32_t name(uint32_t opcode)                                   \
+{                                                                             \
+    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
+}
+
+/* Opcode part 1 */
+EXTRACT_HELPER(opc1, 26, 6);
+/* Opcode part 2 */
+EXTRACT_HELPER(opc2, 1, 5);
+/* Opcode part 3 */
+EXTRACT_HELPER(opc3, 6, 5);
+/* Update Cr0 flags */
+EXTRACT_HELPER(Rc, 0, 1);
+/* Destination */
+EXTRACT_HELPER(rD, 21, 5);
+/* Source */
+EXTRACT_HELPER(rS, 21, 5);
+/* First operand */
+EXTRACT_HELPER(rA, 16, 5);
+/* Second operand */
+EXTRACT_HELPER(rB, 11, 5);
+/* Third operand */
+EXTRACT_HELPER(rC, 6, 5);
+/***                               Get CRn                                 ***/
+EXTRACT_HELPER(crfD, 23, 3);
+EXTRACT_HELPER(crfS, 18, 3);
+EXTRACT_HELPER(crbD, 21, 5);
+EXTRACT_HELPER(crbA, 16, 5);
+EXTRACT_HELPER(crbB, 11, 5);
+/* SPR / TBL */
+EXTRACT_HELPER(_SPR, 11, 10);
+static inline uint32_t SPR(uint32_t opcode)
+{
+    uint32_t sprn = _SPR(opcode);
+
+    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+}
+/***                              Get constants                            ***/
+EXTRACT_HELPER(IMM, 12, 8);
+/* 16 bits signed immediate value */
+EXTRACT_SHELPER(SIMM, 0, 16);
+/* 16 bits unsigned immediate value */
+EXTRACT_HELPER(UIMM, 0, 16);
+/* 5 bits signed immediate value */
+EXTRACT_HELPER(SIMM5, 16, 5);
+/* 5 bits signed immediate value */
+EXTRACT_HELPER(UIMM5, 16, 5);
+/* Bit count */
+EXTRACT_HELPER(NB, 11, 5);
+/* Shift count */
+EXTRACT_HELPER(SH, 11, 5);
+/* Vector shift count */
+EXTRACT_HELPER(VSH, 6, 4);
+/* Mask start */
+EXTRACT_HELPER(MB, 6, 5);
+/* Mask end */
+EXTRACT_HELPER(ME, 1, 5);
+/* Trap operand */
+EXTRACT_HELPER(TO, 21, 5);
+
+EXTRACT_HELPER(CRM, 12, 8);
+EXTRACT_HELPER(FM, 17, 8);
+EXTRACT_HELPER(SR, 16, 4);
+EXTRACT_HELPER(FPIMM, 12, 4);
+
+/***                            Jump target decoding                       ***/
+/* Displacement */
+EXTRACT_SHELPER(d, 0, 16);
+/* Immediate address */
+static inline target_ulong LI(uint32_t opcode)
+{
+    return (opcode >> 0) & 0x03FFFFFC;
+}
+
+static inline uint32_t BD(uint32_t opcode)
+{
+    return (opcode >> 0) & 0xFFFC;
+}
+
+EXTRACT_HELPER(BO, 21, 5);
+EXTRACT_HELPER(BI, 16, 5);
+/* Absolute/relative address */
+EXTRACT_HELPER(AA, 1, 1);
+/* Link */
+EXTRACT_HELPER(LK, 0, 1);
+
+/* Create a mask between <start> and <end> bits */
+static inline target_ulong MASK(uint32_t start, uint32_t end)
+{
+    target_ulong ret;
+
+#if defined(TARGET_PPC64)
+    if (likely(start == 0)) {
+        ret = UINT64_MAX << (63 - end);
+    } else if (likely(end == 63)) {
+        ret = UINT64_MAX >> start;
+    }
+#else
+    if (likely(start == 0)) {
+        ret = UINT32_MAX << (31  - end);
+    } else if (likely(end == 31)) {
+        ret = UINT32_MAX >> start;
+    }
+#endif
+    else {
+        ret = (((target_ulong)(-1ULL)) >> (start)) ^
+            (((target_ulong)(-1ULL) >> (end)) >> 1);
+        if (unlikely(start > end))
+            return ~ret;
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+/* PowerPC instructions table                                                */
+
+#if defined(DO_PPC_STATISTICS)
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+        .oname = stringify(name),                                             \
+    },                                                                        \
+    .oname = stringify(name),                                                 \
+}
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+        .oname = onam,                                                        \
+    },                                                                        \
+    .oname = onam,                                                            \
+}
+#else
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+    },                                                                        \
+    .oname = stringify(name),                                                 \
+}
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
+{                                                                             \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
+        .handler = &gen_##name,                                               \
+    },                                                                        \
+    .oname = onam,                                                            \
+}
+#endif
+
+/* SPR load/store helpers */
+static inline void gen_load_spr(TCGv t, int reg)
+{
+    tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, spr[reg]));
+}
+
+static inline void gen_store_spr(int reg, TCGv t)
+{
+    tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, spr[reg]));
+}
+
+/* Invalid instruction */
+static void gen_invalid(DisasContext *ctx)
+{
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+static opc_handler_t invalid_handler = {
+    .inval   = 0xFFFFFFFF,
+    .type    = PPC_NONE,
+    .type2   = PPC_NONE,
+    .handler = gen_invalid,
+};
+
+/***                           Integer comparison                          ***/
+
+static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
+{
+    int l1, l2, l3;
+
+    tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
+    tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
+    tcg_gen_andi_i32(cpu_crf[crf], cpu_crf[crf], 1);
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    l3 = gen_new_label();
+    if (s) {
+        tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
+        tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
+    } else {
+        tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
+        tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
+    }
+    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_EQ);
+    tcg_gen_br(l3);
+    gen_set_label(l1);
+    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_LT);
+    tcg_gen_br(l3);
+    gen_set_label(l2);
+    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_GT);
+    gen_set_label(l3);
+}
+
+static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
+{
+    TCGv t0 = tcg_const_local_tl(arg1);
+    gen_op_cmp(arg0, t0, s, crf);
+    tcg_temp_free(t0);
+}
+
+#if defined(TARGET_PPC64)
+static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
+{
+    TCGv t0, t1;
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    if (s) {
+        tcg_gen_ext32s_tl(t0, arg0);
+        tcg_gen_ext32s_tl(t1, arg1);
+    } else {
+        tcg_gen_ext32u_tl(t0, arg0);
+        tcg_gen_ext32u_tl(t1, arg1);
+    }
+    gen_op_cmp(t0, t1, s, crf);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
+{
+    TCGv t0 = tcg_const_local_tl(arg1);
+    gen_op_cmp32(arg0, t0, s, crf);
+    tcg_temp_free(t0);
+}
+#endif
+
+static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg)
+{
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode))
+        gen_op_cmpi32(reg, 0, 1, 0);
+    else
+#endif
+        gen_op_cmpi(reg, 0, 1, 0);
+}
+
+/* cmp */
+static void gen_cmp(DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
+        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+                     1, crfD(ctx->opcode));
+    else
+#endif
+        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+                   1, crfD(ctx->opcode));
+}
+
+/* cmpi */
+static void gen_cmpi(DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
+        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
+                      1, crfD(ctx->opcode));
+    else
+#endif
+        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
+                    1, crfD(ctx->opcode));
+}
+
+/* cmpl */
+static void gen_cmpl(DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
+        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+                     0, crfD(ctx->opcode));
+    else
+#endif
+        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+                   0, crfD(ctx->opcode));
+}
+
+/* cmpli */
+static void gen_cmpli(DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
+        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
+                      0, crfD(ctx->opcode));
+    else
+#endif
+        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
+                    0, crfD(ctx->opcode));
+}
+
+/* isel (PowerPC 2.03 specification) */
+static void gen_isel(DisasContext *ctx)
+{
+    int l1, l2;
+    uint32_t bi = rC(ctx->opcode);
+    uint32_t mask;
+    TCGv_i32 t0;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+
+    mask = 1 << (3 - (bi & 0x03));
+    t0 = tcg_temp_new_i32();
+    tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
+    if (rA(ctx->opcode) == 0)
+        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
+    else
+        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+
+/***                           Integer arithmetic                          ***/
+
+static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
+                                           TCGv arg1, TCGv arg2, int sub)
+{
+    int l1;
+    TCGv t0;
+
+    l1 = gen_new_label();
+    /* Start with XER OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    t0 = tcg_temp_local_new();
+    tcg_gen_xor_tl(t0, arg0, arg1);
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode)
+        tcg_gen_ext32s_tl(t0, t0);
+#endif
+    if (sub)
+        tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
+    else
+        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
+    tcg_gen_xor_tl(t0, arg1, arg2);
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode)
+        tcg_gen_ext32s_tl(t0, t0);
+#endif
+    if (sub)
+        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
+    else
+        tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1,
+                                           TCGv arg2, int sub)
+{
+    int l1 = gen_new_label();
+
+#if defined(TARGET_PPC64)
+    if (!(ctx->sf_mode)) {
+        TCGv t0, t1;
+        t0 = tcg_temp_new();
+        t1 = tcg_temp_new();
+
+        tcg_gen_ext32u_tl(t0, arg1);
+        tcg_gen_ext32u_tl(t1, arg2);
+        if (sub) {
+            tcg_gen_brcond_tl(TCG_COND_GTU, t0, t1, l1);
+        } else {
+            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
+        }
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+    } else
+#endif
+    {
+        if (sub) {
+            tcg_gen_brcond_tl(TCG_COND_GTU, arg1, arg2, l1);
+        } else {
+            tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1);
+        }
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
+        gen_set_label(l1);
+    }
+}
+
+/* Common add function */
+static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                    TCGv arg2, int add_ca, int compute_ca,
+                                    int compute_ov)
+{
+    TCGv t0, t1;
+
+    if ((!compute_ca && !compute_ov) ||
+        (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2)))  {
+        t0 = ret;
+    } else {
+        t0 = tcg_temp_local_new();
+    }
+
+    if (add_ca) {
+        t1 = tcg_temp_local_new();
+        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
+        tcg_gen_shri_tl(t1, t1, XER_CA);
+    } else {
+        TCGV_UNUSED(t1);
+    }
+
+    if (compute_ca && compute_ov) {
+        /* Start with XER CA and OV disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
+    } else if (compute_ca) {
+        /* Start with XER CA disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    } else if (compute_ov) {
+        /* Start with XER OV disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    }
+
+    tcg_gen_add_tl(t0, arg1, arg2);
+
+    if (compute_ca) {
+        gen_op_arith_compute_ca(ctx, t0, arg1, 0);
+    }
+    if (add_ca) {
+        tcg_gen_add_tl(t0, t0, t1);
+        gen_op_arith_compute_ca(ctx, t0, t1, 0);
+        tcg_temp_free(t1);
+    }
+    if (compute_ov) {
+        gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 0);
+    }
+
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, t0);
+
+    if (!TCGV_EQUAL(t0, ret)) {
+        tcg_gen_mov_tl(ret, t0);
+        tcg_temp_free(t0);
+    }
+}
+/* Add functions with two operands */
+#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov)         \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)],                           \
+                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],      \
+                     add_ca, compute_ca, compute_ov);                         \
+}
+/* Add functions with one operand and one immediate */
+#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val,                        \
+                                add_ca, compute_ca, compute_ov)               \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv t0 = tcg_const_local_tl(const_val);                                  \
+    gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)],                           \
+                     cpu_gpr[rA(ctx->opcode)], t0,                            \
+                     add_ca, compute_ca, compute_ov);                         \
+    tcg_temp_free(t0);                                                        \
+}
+
+/* add  add.  addo  addo. */
+GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
+GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
+/* addc  addc.  addco  addco. */
+GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
+GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
+/* adde  adde.  addeo  addeo. */
+GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
+GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
+/* addme  addme.  addmeo  addmeo.  */
+GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
+/* addze  addze.  addzeo  addzeo.*/
+GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
+/* addi */
+static void gen_addi(DisasContext *ctx)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        /* li case */
+        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm);
+    } else {
+        tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm);
+    }
+}
+/* addic  addic.*/
+static inline void gen_op_addic(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                int compute_Rc0)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    /* Start with XER CA and OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+
+    if (likely(simm != 0)) {
+        TCGv t0 = tcg_temp_local_new();
+        tcg_gen_addi_tl(t0, arg1, simm);
+        gen_op_arith_compute_ca(ctx, t0, arg1, 0);
+        tcg_gen_mov_tl(ret, t0);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_mov_tl(ret, arg1);
+    }
+    if (compute_Rc0) {
+        gen_set_Rc0(ctx, ret);
+    }
+}
+
+static void gen_addic(DisasContext *ctx)
+{
+    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
+}
+
+static void gen_addic_(DisasContext *ctx)
+{
+    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
+}
+
+/* addis */
+static void gen_addis(DisasContext *ctx)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        /* lis case */
+        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16);
+    } else {
+        tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm << 16);
+    }
+}
+
+static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                     TCGv arg2, int sign, int compute_ov)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+    TCGv_i32 t1 = tcg_temp_local_new_i32();
+
+    tcg_gen_trunc_tl_i32(t0, arg1);
+    tcg_gen_trunc_tl_i32(t1, arg2);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1);
+    if (sign) {
+        int l3 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_NE, t1, -1, l3);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, t0, INT32_MIN, l1);
+        gen_set_label(l3);
+        tcg_gen_div_i32(t0, t0, t1);
+    } else {
+        tcg_gen_divu_i32(t0, t0, t1);
+    }
+    if (compute_ov) {
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    }
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    if (sign) {
+        tcg_gen_sari_i32(t0, t0, 31);
+    } else {
+        tcg_gen_movi_i32(t0, 0);
+    }
+    if (compute_ov) {
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    }
+    gen_set_label(l2);
+    tcg_gen_extu_i32_tl(ret, t0);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, ret);
+}
+/* Div functions */
+#define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov)                      \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    gen_op_arith_divw(ctx, cpu_gpr[rD(ctx->opcode)],                          \
+                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],      \
+                     sign, compute_ov);                                       \
+}
+/* divwu  divwu.  divwuo  divwuo.   */
+GEN_INT_ARITH_DIVW(divwu, 0x0E, 0, 0);
+GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1);
+/* divw  divw.  divwo  divwo.   */
+GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0);
+GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1);
+#if defined(TARGET_PPC64)
+static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                     TCGv arg2, int sign, int compute_ov)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+
+    tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1);
+    if (sign) {
+        int l3 = gen_new_label();
+        tcg_gen_brcondi_i64(TCG_COND_NE, arg2, -1, l3);
+        tcg_gen_brcondi_i64(TCG_COND_EQ, arg1, INT64_MIN, l1);
+        gen_set_label(l3);
+        tcg_gen_div_i64(ret, arg1, arg2);
+    } else {
+        tcg_gen_divu_i64(ret, arg1, arg2);
+    }
+    if (compute_ov) {
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    }
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    if (sign) {
+        tcg_gen_sari_i64(ret, arg1, 63);
+    } else {
+        tcg_gen_movi_i64(ret, 0);
+    }
+    if (compute_ov) {
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    }
+    gen_set_label(l2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, ret);
+}
+#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)],                          \
+                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
+                      sign, compute_ov);                                      \
+}
+/* divwu  divwu.  divwuo  divwuo.   */
+GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0);
+GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1);
+/* divw  divw.  divwo  divwo.   */
+GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0);
+GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
+#endif
+
+/* mulhw  mulhw. */
+static void gen_mulhw(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
+#else
+    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* mulhwu  mulhwu.  */
+static void gen_mulhwu(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32u_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32u_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
+#else
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* mullw  mullw. */
+static void gen_mullw(DisasContext *ctx)
+{
+    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                   cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_ext32s_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* mullwo  mullwo. */
+static void gen_mullwo(DisasContext *ctx)
+{
+    int l1;
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    l1 = gen_new_label();
+    /* Start with XER OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#endif
+    tcg_gen_mul_i64(t0, t0, t1);
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32s_i64(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_gen_brcond_i64(TCG_COND_EQ, t0, cpu_gpr[rD(ctx->opcode)], l1);
+#else
+    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_gen_ext32s_i64(t1, t0);
+    tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
+#endif
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    gen_set_label(l1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* mulli */
+static void gen_mulli(DisasContext *ctx)
+{
+    tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                    SIMM(ctx->opcode));
+}
+#if defined(TARGET_PPC64)
+#define GEN_INT_ARITH_MUL_HELPER(name, opc3)                                  \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    gen_helper_##name (cpu_gpr[rD(ctx->opcode)],                              \
+                       cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);   \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);                           \
+}
+/* mulhd  mulhd. */
+GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00);
+/* mulhdu  mulhdu. */
+GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02);
+
+/* mulld  mulld. */
+static void gen_mulld(DisasContext *ctx)
+{
+    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                   cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+/* mulldo  mulldo. */
+GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17);
+#endif
+
+/* neg neg. nego nego. */
+static inline void gen_op_arith_neg(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                    int ov_check)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv t0 = tcg_temp_local_new();
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode) {
+        tcg_gen_mov_tl(t0, arg1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1);
+    } else
+#endif
+    {
+        tcg_gen_ext32s_tl(t0, arg1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT32_MIN, l1);
+    }
+    tcg_gen_neg_tl(ret, arg1);
+    if (ov_check) {
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    }
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_tl(ret, t0);
+    if (ov_check) {
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    }
+    gen_set_label(l2);
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, ret);
+}
+
+static void gen_neg(DisasContext *ctx)
+{
+    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
+}
+
+static void gen_nego(DisasContext *ctx)
+{
+    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
+}
+
+/* Common subf function */
+static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                     TCGv arg2, int add_ca, int compute_ca,
+                                     int compute_ov)
+{
+    TCGv t0, t1;
+
+    if ((!compute_ca && !compute_ov) ||
+        (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2)))  {
+        t0 = ret;
+    } else {
+        t0 = tcg_temp_local_new();
+    }
+
+    if (add_ca) {
+        t1 = tcg_temp_local_new();
+        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
+        tcg_gen_shri_tl(t1, t1, XER_CA);
+    } else {
+        TCGV_UNUSED(t1);
+    }
+
+    if (compute_ca && compute_ov) {
+        /* Start with XER CA and OV disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
+    } else if (compute_ca) {
+        /* Start with XER CA disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    } else if (compute_ov) {
+        /* Start with XER OV disabled, the most likely case */
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    }
+
+    if (add_ca) {
+        tcg_gen_not_tl(t0, arg1);
+        tcg_gen_add_tl(t0, t0, arg2);
+        gen_op_arith_compute_ca(ctx, t0, arg2, 0);
+        tcg_gen_add_tl(t0, t0, t1);
+        gen_op_arith_compute_ca(ctx, t0, t1, 0);
+        tcg_temp_free(t1);
+    } else {
+        tcg_gen_sub_tl(t0, arg2, arg1);
+        if (compute_ca) {
+            gen_op_arith_compute_ca(ctx, t0, arg2, 1);
+        }
+    }
+    if (compute_ov) {
+        gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 1);
+    }
+
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, t0);
+
+    if (!TCGV_EQUAL(t0, ret)) {
+        tcg_gen_mov_tl(ret, t0);
+        tcg_temp_free(t0);
+    }
+}
+/* Sub functions with Two operands functions */
+#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov)        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)],                          \
+                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
+                      add_ca, compute_ca, compute_ov);                        \
+}
+/* Sub functions with one operand and one immediate */
+#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val,                       \
+                                add_ca, compute_ca, compute_ov)               \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv t0 = tcg_const_local_tl(const_val);                                  \
+    gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)],                          \
+                      cpu_gpr[rA(ctx->opcode)], t0,                           \
+                      add_ca, compute_ca, compute_ov);                        \
+    tcg_temp_free(t0);                                                        \
+}
+/* subf  subf.  subfo  subfo. */
+GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0)
+GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1)
+/* subfc  subfc.  subfco  subfco. */
+GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0)
+GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1)
+/* subfe  subfe.  subfeo  subfo. */
+GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0)
+GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1)
+/* subfme  subfme.  subfmeo  subfmeo.  */
+GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0)
+GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1)
+/* subfze  subfze.  subfzeo  subfzeo.*/
+GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0)
+GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
+
+/* subfic */
+static void gen_subfic(DisasContext *ctx)
+{
+    /* Start with XER CA and OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode));
+    tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]);
+    gen_op_arith_compute_ca(ctx, t0, t1, 1);
+    tcg_temp_free(t1);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+/***                            Integer logical                            ***/
+#define GEN_LOGICAL2(name, tcg_op, opc, type)                                 \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],                \
+       cpu_gpr[rB(ctx->opcode)]);                                             \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
+}
+
+#define GEN_LOGICAL1(name, tcg_op, opc, type)                                 \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);               \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
+}
+
+/* and & and. */
+GEN_LOGICAL2(and, tcg_gen_and_tl, 0x00, PPC_INTEGER);
+/* andc & andc. */
+GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER);
+
+/* andi. */
+static void gen_andi_(DisasContext *ctx)
+{
+    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode));
+    gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* andis. */
+static void gen_andis_(DisasContext *ctx)
+{
+    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode) << 16);
+    gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* cntlzw */
+static void gen_cntlzw(DisasContext *ctx)
+{
+    gen_helper_cntlzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+/* eqv & eqv. */
+GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER);
+/* extsb & extsb. */
+GEN_LOGICAL1(extsb, tcg_gen_ext8s_tl, 0x1D, PPC_INTEGER);
+/* extsh & extsh. */
+GEN_LOGICAL1(extsh, tcg_gen_ext16s_tl, 0x1C, PPC_INTEGER);
+/* nand & nand. */
+GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);
+/* nor & nor. */
+GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER);
+
+/* or & or. */
+static void gen_or(DisasContext *ctx)
+{
+    int rs, ra, rb;
+
+    rs = rS(ctx->opcode);
+    ra = rA(ctx->opcode);
+    rb = rB(ctx->opcode);
+    /* Optimisation for mr. ri case */
+    if (rs != ra || rs != rb) {
+        if (rs != rb)
+            tcg_gen_or_tl(cpu_gpr[ra], cpu_gpr[rs], cpu_gpr[rb]);
+        else
+            tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rs]);
+        if (unlikely(Rc(ctx->opcode) != 0))
+            gen_set_Rc0(ctx, cpu_gpr[ra]);
+    } else if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_set_Rc0(ctx, cpu_gpr[rs]);
+#if defined(TARGET_PPC64)
+    } else {
+        int prio = 0;
+
+        switch (rs) {
+        case 1:
+            /* Set process priority to low */
+            prio = 2;
+            break;
+        case 6:
+            /* Set process priority to medium-low */
+            prio = 3;
+            break;
+        case 2:
+            /* Set process priority to normal */
+            prio = 4;
+            break;
+#if !defined(CONFIG_USER_ONLY)
+        case 31:
+            if (ctx->mem_idx > 0) {
+                /* Set process priority to very low */
+                prio = 1;
+            }
+            break;
+        case 5:
+            if (ctx->mem_idx > 0) {
+                /* Set process priority to medium-hight */
+                prio = 5;
+            }
+            break;
+        case 3:
+            if (ctx->mem_idx > 0) {
+                /* Set process priority to high */
+                prio = 6;
+            }
+            break;
+        case 7:
+            if (ctx->mem_idx > 1) {
+                /* Set process priority to very high */
+                prio = 7;
+            }
+            break;
+#endif
+        default:
+            /* nop */
+            break;
+        }
+        if (prio) {
+            TCGv t0 = tcg_temp_new();
+            gen_load_spr(t0, SPR_PPR);
+            tcg_gen_andi_tl(t0, t0, ~0x001C000000000000ULL);
+            tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50);
+            gen_store_spr(SPR_PPR, t0);
+            tcg_temp_free(t0);
+        }
+#endif
+    }
+}
+/* orc & orc. */
+GEN_LOGICAL2(orc, tcg_gen_orc_tl, 0x0C, PPC_INTEGER);
+
+/* xor & xor. */
+static void gen_xor(DisasContext *ctx)
+{
+    /* Optimisation for "set to zero" case */
+    if (rS(ctx->opcode) != rB(ctx->opcode))
+        tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    else
+        tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* ori */
+static void gen_ori(DisasContext *ctx)
+{
+    target_ulong uimm = UIMM(ctx->opcode);
+
+    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
+        /* NOP */
+        /* XXX: should handle special NOPs for POWER series */
+        return;
+    }
+    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
+}
+
+/* oris */
+static void gen_oris(DisasContext *ctx)
+{
+    target_ulong uimm = UIMM(ctx->opcode);
+
+    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
+        /* NOP */
+        return;
+    }
+    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
+}
+
+/* xori */
+static void gen_xori(DisasContext *ctx)
+{
+    target_ulong uimm = UIMM(ctx->opcode);
+
+    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
+        /* NOP */
+        return;
+    }
+    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
+}
+
+/* xoris */
+static void gen_xoris(DisasContext *ctx)
+{
+    target_ulong uimm = UIMM(ctx->opcode);
+
+    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
+        /* NOP */
+        return;
+    }
+    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
+}
+
+/* popcntb : PowerPC 2.03 specification */
+static void gen_popcntb(DisasContext *ctx)
+{
+    gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
+static void gen_popcntw(DisasContext *ctx)
+{
+    gen_helper_popcntw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
+#if defined(TARGET_PPC64)
+/* popcntd: PowerPC 2.06 specification */
+static void gen_popcntd(DisasContext *ctx)
+{
+    gen_helper_popcntd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+#endif
+
+#if defined(TARGET_PPC64)
+/* extsw & extsw. */
+GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
+
+/* cntlzd */
+static void gen_cntlzd(DisasContext *ctx)
+{
+    gen_helper_cntlzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+#endif
+
+/***                             Integer rotate                            ***/
+
+/* rlwimi & rlwimi. */
+static void gen_rlwimi(DisasContext *ctx)
+{
+    uint32_t mb, me, sh;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    sh = SH(ctx->opcode);
+    if (likely(sh == 0 && mb == 0 && me == 31)) {
+        tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    } else {
+        target_ulong mask;
+        TCGv t1;
+        TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+        TCGv_i32 t2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(t2, cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_rotli_i32(t2, t2, sh);
+        tcg_gen_extu_i32_i64(t0, t2);
+        tcg_temp_free_i32(t2);
+#else
+        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
+#endif
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        mask = MASK(mb, me);
+        t1 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, t0, mask);
+        tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask);
+        tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* rlwinm & rlwinm. */
+static void gen_rlwinm(DisasContext *ctx)
+{
+    uint32_t mb, me, sh;
+
+    sh = SH(ctx->opcode);
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+
+    if (likely(mb == 0 && me == (31 - sh))) {
+        if (likely(sh == 0)) {
+            tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+        } else {
+            TCGv t0 = tcg_temp_new();
+            tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]);
+            tcg_gen_shli_tl(t0, t0, sh);
+            tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0);
+            tcg_temp_free(t0);
+        }
+    } else if (likely(sh != 0 && me == 31 && sh == (32 - mb))) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_shri_tl(t0, t0, mb);
+        tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0);
+        tcg_temp_free(t0);
+    } else {
+        TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+        TCGv_i32 t1 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_rotli_i32(t1, t1, sh);
+        tcg_gen_extu_i32_i64(t0, t1);
+        tcg_temp_free_i32(t1);
+#else
+        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
+#endif
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
+        tcg_temp_free(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* rlwnm & rlwnm. */
+static void gen_rlwnm(DisasContext *ctx)
+{
+    uint32_t mb, me;
+    TCGv t0;
+#if defined(TARGET_PPC64)
+    TCGv_i32 t1, t2;
+#endif
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1f);
+#if defined(TARGET_PPC64)
+    t1 = tcg_temp_new_i32();
+    t2 = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]);
+    tcg_gen_trunc_i64_i32(t2, t0);
+    tcg_gen_rotl_i32(t1, t1, t2);
+    tcg_gen_extu_i32_i64(t0, t1);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+#else
+    tcg_gen_rotl_i32(t0, cpu_gpr[rS(ctx->opcode)], t0);
+#endif
+    if (unlikely(mb != 0 || me != 31)) {
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    }
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+#if defined(TARGET_PPC64)
+#define GEN_PPC64_R2(name, opc1, opc2)                                        \
+static void glue(gen_, name##0)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 0);                                                       \
+}                                                                             \
+                                                                              \
+static void glue(gen_, name##1)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 1);                                                       \
+}
+#define GEN_PPC64_R4(name, opc1, opc2)                                        \
+static void glue(gen_, name##0)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 0, 0);                                                    \
+}                                                                             \
+                                                                              \
+static void glue(gen_, name##1)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 0, 1);                                                    \
+}                                                                             \
+                                                                              \
+static void glue(gen_, name##2)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 1, 0);                                                    \
+}                                                                             \
+                                                                              \
+static void glue(gen_, name##3)(DisasContext *ctx)                            \
+{                                                                             \
+    gen_##name(ctx, 1, 1);                                                    \
+}
+
+static inline void gen_rldinm(DisasContext *ctx, uint32_t mb, uint32_t me,
+                              uint32_t sh)
+{
+    if (likely(sh != 0 && mb == 0 && me == (63 - sh))) {
+        tcg_gen_shli_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
+    } else if (likely(sh != 0 && me == 63 && sh == (64 - mb))) {
+        tcg_gen_shri_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], mb);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+        if (likely(mb == 0 && me == 63)) {
+            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+        } else {
+            tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
+        }
+        tcg_temp_free(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+/* rldicl - rldicl. */
+static inline void gen_rldicl(DisasContext *ctx, int mbn, int shn)
+{
+    uint32_t sh, mb;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldinm(ctx, mb, 63, sh);
+}
+GEN_PPC64_R4(rldicl, 0x1E, 0x00);
+/* rldicr - rldicr. */
+static inline void gen_rldicr(DisasContext *ctx, int men, int shn)
+{
+    uint32_t sh, me;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    me = MB(ctx->opcode) | (men << 5);
+    gen_rldinm(ctx, 0, me, sh);
+}
+GEN_PPC64_R4(rldicr, 0x1E, 0x02);
+/* rldic - rldic. */
+static inline void gen_rldic(DisasContext *ctx, int mbn, int shn)
+{
+    uint32_t sh, mb;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldinm(ctx, mb, 63 - sh, sh);
+}
+GEN_PPC64_R4(rldic, 0x1E, 0x04);
+
+static inline void gen_rldnm(DisasContext *ctx, uint32_t mb, uint32_t me)
+{
+    TCGv t0;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
+    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    if (unlikely(mb != 0 || me != 63)) {
+        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    }
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* rldcl - rldcl. */
+static inline void gen_rldcl(DisasContext *ctx, int mbn)
+{
+    uint32_t mb;
+
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldnm(ctx, mb, 63);
+}
+GEN_PPC64_R2(rldcl, 0x1E, 0x08);
+/* rldcr - rldcr. */
+static inline void gen_rldcr(DisasContext *ctx, int men)
+{
+    uint32_t me;
+
+    me = MB(ctx->opcode) | (men << 5);
+    gen_rldnm(ctx, 0, me);
+}
+GEN_PPC64_R2(rldcr, 0x1E, 0x09);
+/* rldimi - rldimi. */
+static inline void gen_rldimi(DisasContext *ctx, int mbn, int shn)
+{
+    uint32_t sh, mb, me;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    me = 63 - sh;
+    if (unlikely(sh == 0 && mb == 0)) {
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    } else {
+        TCGv t0, t1;
+        target_ulong mask;
+
+        t0 = tcg_temp_new();
+        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+        t1 = tcg_temp_new();
+        mask = MASK(mb, me);
+        tcg_gen_andi_tl(t0, t0, mask);
+        tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask);
+        tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+GEN_PPC64_R4(rldimi, 0x1E, 0x06);
+#endif
+
+/***                             Integer shift                             ***/
+
+/* slw & slw. */
+static void gen_slw(DisasContext *ctx)
+{
+    TCGv t0, t1;
+
+    t0 = tcg_temp_new();
+    /* AND rS with a mask that is 0 when rB >= 0x20 */
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3a);
+    tcg_gen_sari_tl(t0, t0, 0x3f);
+#else
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1a);
+    tcg_gen_sari_tl(t0, t0, 0x1f);
+#endif
+    tcg_gen_andc_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1f);
+    tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sraw & sraw. */
+static void gen_sraw(DisasContext *ctx)
+{
+    gen_helper_sraw(cpu_gpr[rA(ctx->opcode)],
+                    cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srawi & srawi. */
+static void gen_srawi(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    if (sh != 0) {
+        int l1, l2;
+        TCGv t0;
+        l1 = gen_new_label();
+        l2 = gen_new_label();
+        t0 = tcg_temp_local_new();
+        tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
+        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
+        tcg_gen_br(l2);
+        gen_set_label(l1);
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+        gen_set_label(l2);
+        tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srw & srw. */
+static void gen_srw(DisasContext *ctx)
+{
+    TCGv t0, t1;
+
+    t0 = tcg_temp_new();
+    /* AND rS with a mask that is 0 when rB >= 0x20 */
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3a);
+    tcg_gen_sari_tl(t0, t0, 0x3f);
+#else
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1a);
+    tcg_gen_sari_tl(t0, t0, 0x1f);
+#endif
+    tcg_gen_andc_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    tcg_gen_ext32u_tl(t0, t0);
+    t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1f);
+    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+#if defined(TARGET_PPC64)
+/* sld & sld. */
+static void gen_sld(DisasContext *ctx)
+{
+    TCGv t0, t1;
+
+    t0 = tcg_temp_new();
+    /* AND rS with a mask that is 0 when rB >= 0x40 */
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x39);
+    tcg_gen_sari_tl(t0, t0, 0x3f);
+    tcg_gen_andc_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x3f);
+    tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srad & srad. */
+static void gen_srad(DisasContext *ctx)
+{
+    gen_helper_srad(cpu_gpr[rA(ctx->opcode)],
+                    cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+/* sradi & sradi. */
+static inline void gen_sradi(DisasContext *ctx, int n)
+{
+    int sh = SH(ctx->opcode) + (n << 5);
+    if (sh != 0) {
+        int l1, l2;
+        TCGv t0;
+        l1 = gen_new_label();
+        l2 = gen_new_label();
+        t0 = tcg_temp_local_new();
+        tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
+        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
+        tcg_gen_br(l2);
+        gen_set_label(l1);
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+        gen_set_label(l2);
+        tcg_temp_free(t0);
+        tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    }
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+static void gen_sradi0(DisasContext *ctx)
+{
+    gen_sradi(ctx, 0);
+}
+
+static void gen_sradi1(DisasContext *ctx)
+{
+    gen_sradi(ctx, 1);
+}
+
+/* srd & srd. */
+static void gen_srd(DisasContext *ctx)
+{
+    TCGv t0, t1;
+
+    t0 = tcg_temp_new();
+    /* AND rS with a mask that is 0 when rB >= 0x40 */
+    tcg_gen_shli_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x39);
+    tcg_gen_sari_tl(t0, t0, 0x3f);
+    tcg_gen_andc_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x3f);
+    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+#endif
+
+/***                       Floating-Point arithmetic                       ***/
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
+                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
+    }                                                                         \
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf,                      \
+                     Rc(ctx->opcode) != 0);                                   \
+}
+
+#define GEN_FLOAT_ACB(name, op2, set_fprf, type)                              \
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type);                     \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
+
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
+                     cpu_fpr[rB(ctx->opcode)]);                               \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
+    }                                                                         \
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
+                     set_fprf, Rc(ctx->opcode) != 0);                         \
+}
+#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
+
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
+                       cpu_fpr[rC(ctx->opcode)]);                             \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
+    }                                                                         \
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
+                     set_fprf, Rc(ctx->opcode) != 0);                         \
+}
+#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
+
+#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);   \
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
+                     set_fprf, Rc(ctx->opcode) != 0);                         \
+}
+
+#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);   \
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
+                     set_fprf, Rc(ctx->opcode) != 0);                         \
+}
+
+/* fadd - fadds */
+GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
+/* fdiv - fdivs */
+GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
+/* fmul - fmuls */
+GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
+
+/* fre */
+GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
+
+/* fres */
+GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
+
+/* frsqrte */
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
+
+/* frsqrtes */
+static void gen_frsqrtes(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
+}
+
+/* fsel */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
+/* fsub - fsubs */
+GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
+/* Optional: */
+
+/* fsqrt */
+static void gen_fsqrt(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
+}
+
+static void gen_fsqrts(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
+}
+
+/***                     Floating-Point multiply-and-add                   ***/
+/* fmadd - fmadds */
+GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
+/* fmsub - fmsubs */
+GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
+/* fnmadd - fnmadds */
+GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
+/* fnmsub - fnmsubs */
+GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
+
+/***                     Floating-Point round & convert                    ***/
+/* fctiw */
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
+/* fctiwz */
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
+/* frsp */
+GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
+#if defined(TARGET_PPC64)
+/* fcfid */
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
+/* fctid */
+GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
+/* fctidz */
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
+#endif
+
+/* frin */
+GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
+/* friz */
+GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
+/* frip */
+GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
+/* frim */
+GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
+
+/***                         Floating-Point compare                        ***/
+
+/* fcmpo */
+static void gen_fcmpo(DisasContext *ctx)
+{
+    TCGv_i32 crf;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    crf = tcg_const_i32(crfD(ctx->opcode));
+    gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
+    tcg_temp_free_i32(crf);
+    gen_helper_float_check_status();
+}
+
+/* fcmpu */
+static void gen_fcmpu(DisasContext *ctx)
+{
+    TCGv_i32 crf;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    crf = tcg_const_i32(crfD(ctx->opcode));
+    gen_helper_fcmpu(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
+    tcg_temp_free_i32(crf);
+    gen_helper_float_check_status();
+}
+
+/***                         Floating-point move                           ***/
+/* fabs */
+/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
+
+/* fmr  - fmr. */
+/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
+static void gen_fmr(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
+
+/* fnabs */
+/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
+/* fneg */
+/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
+
+/***                  Floating-Point status & ctrl register                ***/
+
+/* mcrfs */
+static void gen_mcrfs(DisasContext *ctx)
+{
+    int bfa;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    bfa = 4 * (7 - crfS(ctx->opcode));
+    tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_fpscr, bfa);
+    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf);
+    tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
+}
+
+/* mffs */
+static void gen_mffs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_reset_fpstatus();
+    tcg_gen_extu_i32_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
+
+/* mtfsb0 */
+static void gen_mtfsb0(DisasContext *ctx)
+{
+    uint8_t crb;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    crb = 31 - crbD(ctx->opcode);
+    gen_reset_fpstatus();
+    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
+        TCGv_i32 t0;
+        /* NIP cannot be restored if the memory exception comes from an helper */
+        gen_update_nip(ctx, ctx->nip - 4);
+        t0 = tcg_const_i32(crb);
+        gen_helper_fpscr_clrbit(t0);
+        tcg_temp_free_i32(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
+    }
+}
+
+/* mtfsb1 */
+static void gen_mtfsb1(DisasContext *ctx)
+{
+    uint8_t crb;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    crb = 31 - crbD(ctx->opcode);
+    gen_reset_fpstatus();
+    /* XXX: we pretend we can only do IEEE floating-point computations */
+    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
+        TCGv_i32 t0;
+        /* NIP cannot be restored if the memory exception comes from an helper */
+        gen_update_nip(ctx, ctx->nip - 4);
+        t0 = tcg_const_i32(crb);
+        gen_helper_fpscr_setbit(t0);
+        tcg_temp_free_i32(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status();
+}
+
+/* mtfsf */
+static void gen_mtfsf(DisasContext *ctx)
+{
+    TCGv_i32 t0;
+    int L = ctx->opcode & 0x02000000;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    if (L)
+        t0 = tcg_const_i32(0xff);
+    else
+        t0 = tcg_const_i32(FM(ctx->opcode));
+    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status();
+}
+
+/* mtfsfi */
+static void gen_mtfsfi(DisasContext *ctx)
+{
+    int bf, sh;
+    TCGv_i64 t0;
+    TCGv_i32 t1;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    bf = crbD(ctx->opcode) >> 2;
+    sh = 7 - bf;
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
+    t1 = tcg_const_i32(1 << sh);
+    gen_helper_store_fpscr(t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i32(t1);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status();
+}
+
+/***                           Addressing modes                            ***/
+/* Register indirect with immediate index : EA = (rA|0) + SIMM */
+static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA,
+                                      target_long maskl)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    simm &= ~maskl;
+    if (rA(ctx->opcode) == 0) {
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_movi_tl(EA, (uint32_t)simm);
+        } else
+#endif
+        tcg_gen_movi_tl(EA, simm);
+    } else if (likely(simm != 0)) {
+        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, EA);
+        }
+#endif
+    } else {
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
+        } else
+#endif
+        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
+    }
+}
+
+static inline void gen_addr_reg_index(DisasContext *ctx, TCGv EA)
+{
+    if (rA(ctx->opcode) == 0) {
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]);
+        } else
+#endif
+        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
+    } else {
+        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, EA);
+        }
+#endif
+    }
+}
+
+static inline void gen_addr_register(DisasContext *ctx, TCGv EA)
+{
+    if (rA(ctx->opcode) == 0) {
+        tcg_gen_movi_tl(EA, 0);
+    } else {
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
+        } else
+#endif
+            tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
+    }
+}
+
+static inline void gen_addr_add(DisasContext *ctx, TCGv ret, TCGv arg1,
+                                target_long val)
+{
+    tcg_gen_addi_tl(ret, arg1, val);
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode) {
+        tcg_gen_ext32u_tl(ret, ret);
+    }
+#endif
+}
+
+static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
+{
+    int l1 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv_i32 t1, t2;
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    tcg_gen_andi_tl(t0, EA, mask);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+    t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
+    t2 = tcg_const_i32(0);
+    gen_helper_raise_exception_err(t1, t2);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+}
+
+/***                             Integer load                              ***/
+static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx);
+}
+
+static inline void gen_qemu_ld8s(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld8s(arg1, arg2, ctx->mem_idx);
+}
+
+static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
+    if (unlikely(ctx->le_mode)) {
+        tcg_gen_bswap16_tl(arg1, arg1);
+    }
+}
+
+static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (unlikely(ctx->le_mode)) {
+        tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
+        tcg_gen_bswap16_tl(arg1, arg1);
+        tcg_gen_ext16s_tl(arg1, arg1);
+    } else {
+        tcg_gen_qemu_ld16s(arg1, arg2, ctx->mem_idx);
+    }
+}
+
+static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
+    if (unlikely(ctx->le_mode)) {
+        tcg_gen_bswap32_tl(arg1, arg1);
+    }
+}
+
+#if defined(TARGET_PPC64)
+static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (unlikely(ctx->le_mode)) {
+        tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
+        tcg_gen_bswap32_tl(arg1, arg1);
+        tcg_gen_ext32s_tl(arg1, arg1);
+    } else
+        tcg_gen_qemu_ld32s(arg1, arg2, ctx->mem_idx);
+}
+#endif
+
+static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
+    if (unlikely(ctx->le_mode)) {
+        tcg_gen_bswap64_i64(arg1, arg1);
+    }
+}
+
+static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx);
+}
+
+static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (unlikely(ctx->le_mode)) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext16u_tl(t0, arg1);
+        tcg_gen_bswap16_tl(t0, t0);
+        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
+    }
+}
+
+static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (unlikely(ctx->le_mode)) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext32u_tl(t0, arg1);
+        tcg_gen_bswap32_tl(t0, t0);
+        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
+    }
+}
+
+static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    if (unlikely(ctx->le_mode)) {
+        TCGv_i64 t0 = tcg_temp_new_i64();
+        tcg_gen_bswap64_i64(t0, arg1);
+        tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
+        tcg_temp_free_i64(t0);
+    } else
+        tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx);
+}
+
+#define GEN_LD(name, ldop, opc, type)                                         \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDU(name, ldop, opc, type)                                        \
+static void glue(gen_, name##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    if (type == PPC_64B)                                                      \
+        gen_addr_imm_index(ctx, EA, 0x03);                                    \
+    else                                                                      \
+        gen_addr_imm_index(ctx, EA, 0);                                       \
+    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
+static void glue(gen_, name##x)(DisasContext *ctx)                            \
+{                                                                             \
+    TCGv EA;                                                                  \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDS(name, ldop, op, type)                                         \
+GEN_LD(name, ldop, op | 0x20, type);                                          \
+GEN_LDU(name, ldop, op | 0x21, type);                                         \
+GEN_LDUX(name, ldop, 0x17, op | 0x01, type);                                  \
+GEN_LDX(name, ldop, 0x17, op | 0x00, type)
+
+/* lbz lbzu lbzux lbzx */
+GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER);
+/* lha lhau lhaux lhax */
+GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER);
+/* lhz lhzu lhzux lhzx */
+GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER);
+/* lwz lwzu lwzux lwzx */
+GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+/* lwaux */
+GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B);
+/* lwax */
+GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B);
+/* ldux */
+GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B);
+/* ldx */
+GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B);
+
+static void gen_ld(DisasContext *ctx)
+{
+    TCGv EA;
+    if (Rc(ctx->opcode)) {
+        if (unlikely(rA(ctx->opcode) == 0 ||
+                     rA(ctx->opcode) == rD(ctx->opcode))) {
+            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+            return;
+        }
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_imm_index(ctx, EA, 0x03);
+    if (ctx->opcode & 0x02) {
+        /* lwa (lwau is undefined) */
+        gen_qemu_ld32s(ctx, cpu_gpr[rD(ctx->opcode)], EA);
+    } else {
+        /* ld - ldu */
+        gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], EA);
+    }
+    if (Rc(ctx->opcode))
+        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
+    tcg_temp_free(EA);
+}
+
+/* lq */
+static void gen_lq(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    int ra, rd;
+    TCGv EA;
+
+    /* Restore CPU state */
+    if (unlikely(ctx->mem_idx == 0)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    ra = rA(ctx->opcode);
+    rd = rD(ctx->opcode);
+    if (unlikely((rd & 1) || rd == ra)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        return;
+    }
+    if (unlikely(ctx->le_mode)) {
+        /* Little-endian mode is not handled */
+        gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_imm_index(ctx, EA, 0x0F);
+    gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
+    gen_addr_add(ctx, EA, EA, 8);
+    gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
+    tcg_temp_free(EA);
+#endif
+}
+#endif
+
+/***                              Integer store                            ***/
+#define GEN_ST(name, stop, opc, type)                                         \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STU(name, stop, opc, type)                                        \
+static void glue(gen_, stop##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    if (type == PPC_64B)                                                      \
+        gen_addr_imm_index(ctx, EA, 0x03);                                    \
+    else                                                                      \
+        gen_addr_imm_index(ctx, EA, 0);                                       \
+    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STUX(name, stop, opc2, opc3, type)                                \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STX(name, stop, opc2, opc3, type)                                 \
+static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STS(name, stop, op, type)                                         \
+GEN_ST(name, stop, op | 0x20, type);                                          \
+GEN_STU(name, stop, op | 0x21, type);                                         \
+GEN_STUX(name, stop, 0x17, op | 0x01, type);                                  \
+GEN_STX(name, stop, 0x17, op | 0x00, type)
+
+/* stb stbu stbux stbx */
+GEN_STS(stb, st8, 0x06, PPC_INTEGER);
+/* sth sthu sthux sthx */
+GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
+/* stw stwu stwux stwx */
+GEN_STS(stw, st32, 0x04, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
+GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
+
+static void gen_std(DisasContext *ctx)
+{
+    int rs;
+    TCGv EA;
+
+    rs = rS(ctx->opcode);
+    if ((ctx->opcode & 0x3) == 0x2) {
+#if defined(CONFIG_USER_ONLY)
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+        /* stq */
+        if (unlikely(ctx->mem_idx == 0)) {
+            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+            return;
+        }
+        if (unlikely(rs & 1)) {
+            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+            return;
+        }
+        if (unlikely(ctx->le_mode)) {
+            /* Little-endian mode is not handled */
+            gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+            return;
+        }
+        gen_set_access_type(ctx, ACCESS_INT);
+        EA = tcg_temp_new();
+        gen_addr_imm_index(ctx, EA, 0x03);
+        gen_qemu_st64(ctx, cpu_gpr[rs], EA);
+        gen_addr_add(ctx, EA, EA, 8);
+        gen_qemu_st64(ctx, cpu_gpr[rs+1], EA);
+        tcg_temp_free(EA);
+#endif
+    } else {
+        /* std / stdu */
+        if (Rc(ctx->opcode)) {
+            if (unlikely(rA(ctx->opcode) == 0)) {
+                gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+                return;
+            }
+        }
+        gen_set_access_type(ctx, ACCESS_INT);
+        EA = tcg_temp_new();
+        gen_addr_imm_index(ctx, EA, 0x03);
+        gen_qemu_st64(ctx, cpu_gpr[rs], EA);
+        if (Rc(ctx->opcode))
+            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
+        tcg_temp_free(EA);
+    }
+}
+#endif
+/***                Integer load and store with byte reverse               ***/
+/* lhbrx */
+static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
+    if (likely(!ctx->le_mode)) {
+        tcg_gen_bswap16_tl(arg1, arg1);
+    }
+}
+GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
+
+/* lwbrx */
+static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
+    if (likely(!ctx->le_mode)) {
+        tcg_gen_bswap32_tl(arg1, arg1);
+    }
+}
+GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
+
+/* sthbrx */
+static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (likely(!ctx->le_mode)) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext16u_tl(t0, arg1);
+        tcg_gen_bswap16_tl(t0, t0);
+        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
+    }
+}
+GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
+
+/* stwbrx */
+static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (likely(!ctx->le_mode)) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext32u_tl(t0, arg1);
+        tcg_gen_bswap32_tl(t0, t0);
+        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
+    }
+}
+GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
+
+/***                    Integer load and store multiple                    ***/
+
+/* lmw */
+static void gen_lmw(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1;
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    t1 = tcg_const_i32(rD(ctx->opcode));
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_helper_lmw(t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+}
+
+/* stmw */
+static void gen_stmw(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1;
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    t1 = tcg_const_i32(rS(ctx->opcode));
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_helper_stmw(t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+}
+
+/***                    Integer load and store strings                     ***/
+
+/* lswi */
+/* PowerPC32 specification says we must generate an exception if
+ * rA is in the range of registers to be loaded.
+ * In an other hand, IBM says this is valid, but rA won't be loaded.
+ * For now, I'll follow the spec...
+ */
+static void gen_lswi(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1, t2;
+    int nb = NB(ctx->opcode);
+    int start = rD(ctx->opcode);
+    int ra = rA(ctx->opcode);
+    int nr;
+
+    if (nb == 0)
+        nb = 32;
+    nr = nb / 4;
+    if (unlikely(((start + nr) > 32  &&
+                  start <= ra && (start + nr - 32) > ra) ||
+                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_register(ctx, t0);
+    t1 = tcg_const_i32(nb);
+    t2 = tcg_const_i32(start);
+    gen_helper_lsw(t0, t1, t2);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+}
+
+/* lswx */
+static void gen_lswx(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1, t2, t3;
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    t1 = tcg_const_i32(rD(ctx->opcode));
+    t2 = tcg_const_i32(rA(ctx->opcode));
+    t3 = tcg_const_i32(rB(ctx->opcode));
+    gen_helper_lswx(t0, t1, t2, t3);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    tcg_temp_free_i32(t3);
+}
+
+/* stswi */
+static void gen_stswi(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1, t2;
+    int nb = NB(ctx->opcode);
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_register(ctx, t0);
+    if (nb == 0)
+        nb = 32;
+    t1 = tcg_const_i32(nb);
+    t2 = tcg_const_i32(rS(ctx->opcode));
+    gen_helper_stsw(t0, t1, t2);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+}
+
+/* stswx */
+static void gen_stswx(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv_i32 t1, t2;
+    gen_set_access_type(ctx, ACCESS_INT);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    t1 = tcg_temp_new_i32();
+    tcg_gen_trunc_tl_i32(t1, cpu_xer);
+    tcg_gen_andi_i32(t1, t1, 0x7F);
+    t2 = tcg_const_i32(rS(ctx->opcode));
+    gen_helper_stsw(t0, t1, t2);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+}
+
+/***                        Memory synchronisation                         ***/
+/* eieio */
+static void gen_eieio(DisasContext *ctx)
+{
+}
+
+/* isync */
+static void gen_isync(DisasContext *ctx)
+{
+    gen_stop_exception(ctx);
+}
+
+/* lwarx */
+static void gen_lwarx(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv gpr = cpu_gpr[rD(ctx->opcode)];
+    gen_set_access_type(ctx, ACCESS_RES);
+    t0 = tcg_temp_local_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x03);
+    gen_qemu_ld32u(ctx, gpr, t0);
+    tcg_gen_mov_tl(cpu_reserve, t0);
+    tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUState, reserve_val));
+    tcg_temp_free(t0);
+}
+
+#if defined(CONFIG_USER_ONLY)
+static void gen_conditional_store (DisasContext *ctx, TCGv EA,
+                                   int reg, int size)
+{
+    TCGv t0 = tcg_temp_new();
+    uint32_t save_exception = ctx->exception;
+
+    tcg_gen_st_tl(EA, cpu_env, offsetof(CPUState, reserve_ea));
+    tcg_gen_movi_tl(t0, (size << 5) | reg);
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, reserve_info));
+    tcg_temp_free(t0);
+    gen_update_nip(ctx, ctx->nip-4);
+    ctx->exception = POWERPC_EXCP_BRANCH;
+    gen_exception(ctx, POWERPC_EXCP_STCX);
+    ctx->exception = save_exception;
+}
+#endif
+
+/* stwcx. */
+static void gen_stwcx_(DisasContext *ctx)
+{
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_RES);
+    t0 = tcg_temp_local_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x03);
+#if defined(CONFIG_USER_ONLY)
+    gen_conditional_store(ctx, t0, rS(ctx->opcode), 4);
+#else
+    {
+        int l1;
+
+        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
+        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
+        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+        l1 = gen_new_label();
+        tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
+        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+        gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], t0);
+        gen_set_label(l1);
+        tcg_gen_movi_tl(cpu_reserve, -1);
+    }
+#endif
+    tcg_temp_free(t0);
+}
+
+#if defined(TARGET_PPC64)
+/* ldarx */
+static void gen_ldarx(DisasContext *ctx)
+{
+    TCGv t0;
+    TCGv gpr = cpu_gpr[rD(ctx->opcode)];
+    gen_set_access_type(ctx, ACCESS_RES);
+    t0 = tcg_temp_local_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x07);
+    gen_qemu_ld64(ctx, gpr, t0);
+    tcg_gen_mov_tl(cpu_reserve, t0);
+    tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUState, reserve_val));
+    tcg_temp_free(t0);
+}
+
+/* stdcx. */
+static void gen_stdcx_(DisasContext *ctx)
+{
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_RES);
+    t0 = tcg_temp_local_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x07);
+#if defined(CONFIG_USER_ONLY)
+    gen_conditional_store(ctx, t0, rS(ctx->opcode), 8);
+#else
+    {
+        int l1;
+        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
+        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
+        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+        l1 = gen_new_label();
+        tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
+        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+        gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], t0);
+        gen_set_label(l1);
+        tcg_gen_movi_tl(cpu_reserve, -1);
+    }
+#endif
+    tcg_temp_free(t0);
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* sync */
+static void gen_sync(DisasContext *ctx)
+{
+}
+
+/* wait */
+static void gen_wait(DisasContext *ctx)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, halted));
+    tcg_temp_free_i32(t0);
+    /* Stop translation, as the CPU is supposed to sleep from now */
+    gen_exception_err(ctx, EXCP_HLT, 1);
+}
+
+/***                         Floating-point load                           ***/
+#define GEN_LDF(name, ldop, opc, type)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDUF(name, ldop, opc, type)                                       \
+static void glue(gen_, name##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDUXF(name, ldop, opc, type)                                      \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
+static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDFS(name, ldop, op, type)                                        \
+GEN_LDF(name, ldop, op | 0x20, type);                                         \
+GEN_LDUF(name, ldop, op | 0x21, type);                                        \
+GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
+GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
+
+static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    gen_qemu_ld32u(ctx, t0, arg2);
+    tcg_gen_trunc_tl_i32(t1, t0);
+    tcg_temp_free(t0);
+    gen_helper_float32_to_float64(arg1, t1);
+    tcg_temp_free_i32(t1);
+}
+
+ /* lfd lfdu lfdux lfdx */
+GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
+ /* lfs lfsu lfsux lfsx */
+GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
+
+/***                         Floating-point store                          ***/
+#define GEN_STF(name, stop, opc, type)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STUF(name, stop, opc, type)                                       \
+static void glue(gen_, name##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STUXF(name, stop, opc, type)                                      \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STXF(name, stop, opc2, opc3, type)                                \
+static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STFS(name, stop, op, type)                                        \
+GEN_STF(name, stop, op | 0x20, type);                                         \
+GEN_STUF(name, stop, op | 0x21, type);                                        \
+GEN_STUXF(name, stop, op | 0x01, type);                                       \
+GEN_STXF(name, stop, 0x17, op | 0x00, type)
+
+static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    TCGv t1 = tcg_temp_new();
+    gen_helper_float64_to_float32(t0, arg1);
+    tcg_gen_extu_i32_tl(t1, t0);
+    tcg_temp_free_i32(t0);
+    gen_qemu_st32(ctx, t1, arg2);
+    tcg_temp_free(t1);
+}
+
+/* stfd stfdu stfdux stfdx */
+GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
+/* stfs stfsu stfsux stfsx */
+GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
+
+/* Optional: */
+static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_trunc_i64_tl(t0, arg1),
+    gen_qemu_st32(ctx, t0, arg2);
+    tcg_temp_free(t0);
+}
+/* stfiwx */
+GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
+
+/***                                Branch                                 ***/
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode)
+        dest = (uint32_t) dest;
+#endif
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+        likely(!ctx->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_nip, dest & ~3);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_nip, dest & ~3);
+        if (unlikely(ctx->singlestep_enabled)) {
+            if ((ctx->singlestep_enabled &
+                (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
+                ctx->exception == POWERPC_EXCP_BRANCH) {
+                target_ulong tmp = ctx->nip;
+                ctx->nip = dest;
+                gen_exception(ctx, POWERPC_EXCP_TRACE);
+                ctx->nip = tmp;
+            }
+            if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
+                gen_debug_exception(ctx);
+            }
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void gen_setlr(DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode == 0)
+        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
+    else
+#endif
+        tcg_gen_movi_tl(cpu_lr, nip);
+}
+
+/* b ba bl bla */
+static void gen_b(DisasContext *ctx)
+{
+    target_ulong li, target;
+
+    ctx->exception = POWERPC_EXCP_BRANCH;
+    /* sign extend LI */
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
+    else
+#endif
+        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
+    if (likely(AA(ctx->opcode) == 0))
+        target = ctx->nip + li - 4;
+    else
+        target = li;
+    if (LK(ctx->opcode))
+        gen_setlr(ctx, ctx->nip);
+    gen_goto_tb(ctx, 0, target);
+}
+
+#define BCOND_IM  0
+#define BCOND_LR  1
+#define BCOND_CTR 2
+
+static inline void gen_bcond(DisasContext *ctx, int type)
+{
+    uint32_t bo = BO(ctx->opcode);
+    int l1;
+    TCGv target;
+
+    ctx->exception = POWERPC_EXCP_BRANCH;
+    if (type == BCOND_LR || type == BCOND_CTR) {
+        target = tcg_temp_local_new();
+        if (type == BCOND_CTR)
+            tcg_gen_mov_tl(target, cpu_ctr);
+        else
+            tcg_gen_mov_tl(target, cpu_lr);
+    } else {
+        TCGV_UNUSED(target);
+    }
+    if (LK(ctx->opcode))
+        gen_setlr(ctx, ctx->nip);
+    l1 = gen_new_label();
+    if ((bo & 0x4) == 0) {
+        /* Decrement and test CTR */
+        TCGv temp = tcg_temp_new();
+        if (unlikely(type == BCOND_CTR)) {
+            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+            return;
+        }
+        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode)
+            tcg_gen_ext32u_tl(temp, cpu_ctr);
+        else
+#endif
+            tcg_gen_mov_tl(temp, cpu_ctr);
+        if (bo & 0x2) {
+            tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
+        } else {
+            tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
+        }
+        tcg_temp_free(temp);
+    }
+    if ((bo & 0x10) == 0) {
+        /* Test CR */
+        uint32_t bi = BI(ctx->opcode);
+        uint32_t mask = 1 << (3 - (bi & 0x03));
+        TCGv_i32 temp = tcg_temp_new_i32();
+
+        if (bo & 0x8) {
+            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
+            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
+        } else {
+            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
+            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
+        }
+        tcg_temp_free_i32(temp);
+    }
+    if (type == BCOND_IM) {
+        target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
+        if (likely(AA(ctx->opcode) == 0)) {
+            gen_goto_tb(ctx, 0, ctx->nip + li - 4);
+        } else {
+            gen_goto_tb(ctx, 0, li);
+        }
+        gen_set_label(l1);
+        gen_goto_tb(ctx, 1, ctx->nip);
+    } else {
+#if defined(TARGET_PPC64)
+        if (!(ctx->sf_mode))
+            tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
+        else
+#endif
+            tcg_gen_andi_tl(cpu_nip, target, ~3);
+        tcg_gen_exit_tb(0);
+        gen_set_label(l1);
+#if defined(TARGET_PPC64)
+        if (!(ctx->sf_mode))
+            tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip);
+        else
+#endif
+            tcg_gen_movi_tl(cpu_nip, ctx->nip);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void gen_bc(DisasContext *ctx)
+{
+    gen_bcond(ctx, BCOND_IM);
+}
+
+static void gen_bcctr(DisasContext *ctx)
+{
+    gen_bcond(ctx, BCOND_CTR);
+}
+
+static void gen_bclr(DisasContext *ctx)
+{
+    gen_bcond(ctx, BCOND_LR);
+}
+
+/***                      Condition register logical                       ***/
+#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    uint8_t bitmask;                                                          \
+    int sh;                                                                   \
+    TCGv_i32 t0, t1;                                                          \
+    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
+    t0 = tcg_temp_new_i32();                                                  \
+    if (sh > 0)                                                               \
+        tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh);            \
+    else if (sh < 0)                                                          \
+        tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh);           \
+    else                                                                      \
+        tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]);                 \
+    t1 = tcg_temp_new_i32();                                                  \
+    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
+    if (sh > 0)                                                               \
+        tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh);            \
+    else if (sh < 0)                                                          \
+        tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh);           \
+    else                                                                      \
+        tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]);                 \
+    tcg_op(t0, t0, t1);                                                       \
+    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
+    tcg_gen_andi_i32(t0, t0, bitmask);                                        \
+    tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask);          \
+    tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1);                  \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+
+/* crand */
+GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08);
+/* crandc */
+GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04);
+/* creqv */
+GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09);
+/* crnand */
+GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07);
+/* crnor */
+GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01);
+/* cror */
+GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E);
+/* crorc */
+GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D);
+/* crxor */
+GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06);
+
+/* mcrf */
+static void gen_mcrf(DisasContext *ctx)
+{
+    tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]);
+}
+
+/***                           System linkage                              ***/
+
+/* rfi (mem_idx only) */
+static void gen_rfi(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    /* Restore CPU state */
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_rfi();
+    gen_sync_exception(ctx);
+#endif
+}
+
+#if defined(TARGET_PPC64)
+static void gen_rfid(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    /* Restore CPU state */
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_rfid();
+    gen_sync_exception(ctx);
+#endif
+}
+
+static void gen_hrfid(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    /* Restore CPU state */
+    if (unlikely(ctx->mem_idx <= 1)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_hrfid();
+    gen_sync_exception(ctx);
+#endif
+}
+#endif
+
+/* sc */
+#if defined(CONFIG_USER_ONLY)
+#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
+#else
+#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
+#endif
+static void gen_sc(DisasContext *ctx)
+{
+    uint32_t lev;
+
+    lev = (ctx->opcode >> 5) & 0x7F;
+    gen_exception_err(ctx, POWERPC_SYSCALL, lev);
+}
+
+/***                                Trap                                   ***/
+
+/* tw */
+static void gen_tw(DisasContext *ctx)
+{
+    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+}
+
+/* twi */
+static void gen_twi(DisasContext *ctx)
+{
+    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
+    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+}
+
+#if defined(TARGET_PPC64)
+/* td */
+static void gen_td(DisasContext *ctx)
+{
+    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+}
+
+/* tdi */
+static void gen_tdi(DisasContext *ctx)
+{
+    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
+    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+}
+#endif
+
+/***                          Processor control                            ***/
+
+/* mcrxr */
+static void gen_mcrxr(DisasContext *ctx)
+{
+    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], cpu_xer);
+    tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], XER_CA);
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
+}
+
+/* mfcr mfocrf */
+static void gen_mfcr(DisasContext *ctx)
+{
+    uint32_t crm, crn;
+
+    if (likely(ctx->opcode & 0x00100000)) {
+        crm = CRM(ctx->opcode);
+        if (likely(crm && ((crm & (crm - 1)) == 0))) {
+            crn = ctz32 (crm);
+            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
+            tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)],
+                            cpu_gpr[rD(ctx->opcode)], crn * 4);
+        }
+    } else {
+        TCGv_i32 t0 = tcg_temp_new_i32();
+        tcg_gen_mov_i32(t0, cpu_crf[0]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[1]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[2]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[3]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[4]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[5]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[6]);
+        tcg_gen_shli_i32(t0, t0, 4);
+        tcg_gen_or_i32(t0, t0, cpu_crf[7]);
+        tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+/* mfmsr */
+static void gen_mfmsr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr);
+#endif
+}
+
+static void spr_noaccess(void *opaque, int gprn, int sprn)
+{
+#if 0
+    sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+    printf("ERROR: try to access SPR %d !\n", sprn);
+#endif
+}
+#define SPR_NOACCESS (&spr_noaccess)
+
+/* mfspr */
+static inline void gen_op_mfspr(DisasContext *ctx)
+{
+    void (*read_cb)(void *opaque, int gprn, int sprn);
+    uint32_t sprn = SPR(ctx->opcode);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->mem_idx == 2)
+        read_cb = ctx->spr_cb[sprn].hea_read;
+    else if (ctx->mem_idx)
+        read_cb = ctx->spr_cb[sprn].oea_read;
+    else
+#endif
+        read_cb = ctx->spr_cb[sprn].uea_read;
+    if (likely(read_cb != NULL)) {
+        if (likely(read_cb != SPR_NOACCESS)) {
+            (*read_cb)(ctx, rD(ctx->opcode), sprn);
+        } else {
+            /* Privilege exception */
+            /* This is a hack to avoid warnings when running Linux:
+             * this OS breaks the PowerPC virtualisation model,
+             * allowing userland application to read the PVR
+             */
+            if (sprn != SPR_PVR) {
+                qemu_log("Trying to read privileged spr %d %03x at "
+                         TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+                printf("Trying to read privileged spr %d %03x at "
+                       TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+            }
+            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        }
+    } else {
+        /* Not defined */
+        qemu_log("Trying to read invalid spr %d %03x at "
+                    TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+        printf("Trying to read invalid spr %d %03x at " TARGET_FMT_lx "\n",
+               sprn, sprn, ctx->nip);
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+    }
+}
+
+static void gen_mfspr(DisasContext *ctx)
+{
+    gen_op_mfspr(ctx);
+}
+
+/* mftb */
+static void gen_mftb(DisasContext *ctx)
+{
+    gen_op_mfspr(ctx);
+}
+
+/* mtcrf mtocrf*/
+static void gen_mtcrf(DisasContext *ctx)
+{
+    uint32_t crm, crn;
+
+    crm = CRM(ctx->opcode);
+    if (likely((ctx->opcode & 0x00100000))) {
+        if (crm && ((crm & (crm - 1)) == 0)) {
+            TCGv_i32 temp = tcg_temp_new_i32();
+            crn = ctz32 (crm);
+            tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
+            tcg_gen_shri_i32(temp, temp, crn * 4);
+            tcg_gen_andi_i32(cpu_crf[7 - crn], temp, 0xf);
+            tcg_temp_free_i32(temp);
+        }
+    } else {
+        TCGv_i32 temp = tcg_temp_new_i32();
+        tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
+        for (crn = 0 ; crn < 8 ; crn++) {
+            if (crm & (1 << crn)) {
+                    tcg_gen_shri_i32(cpu_crf[7 - crn], temp, crn * 4);
+                    tcg_gen_andi_i32(cpu_crf[7 - crn], cpu_crf[7 - crn], 0xf);
+            }
+        }
+        tcg_temp_free_i32(temp);
+    }
+}
+
+/* mtmsr */
+#if defined(TARGET_PPC64)
+static void gen_mtmsrd(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
+        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
+        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
+        tcg_temp_free(t0);
+    } else {
+        /* XXX: we need to update nip before the store
+         *      if we enter power saving mode, we will exit the loop
+         *      directly from ppc_store_msr
+         */
+        gen_update_nip(ctx, ctx->nip);
+        gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsr is not always defined as context-synchronizing */
+        gen_stop_exception(ctx);
+    }
+#endif
+}
+#endif
+
+static void gen_mtmsr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
+        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
+        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
+        tcg_temp_free(t0);
+    } else {
+        TCGv msr = tcg_temp_new();
+
+        /* XXX: we need to update nip before the store
+         *      if we enter power saving mode, we will exit the loop
+         *      directly from ppc_store_msr
+         */
+        gen_update_nip(ctx, ctx->nip);
+#if defined(TARGET_PPC64)
+        tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32);
+#else
+        tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]);
+#endif
+        gen_helper_store_msr(msr);
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsr is not always defined as context-synchronizing */
+        gen_stop_exception(ctx);
+    }
+#endif
+}
+
+/* mtspr */
+static void gen_mtspr(DisasContext *ctx)
+{
+    void (*write_cb)(void *opaque, int sprn, int gprn);
+    uint32_t sprn = SPR(ctx->opcode);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->mem_idx == 2)
+        write_cb = ctx->spr_cb[sprn].hea_write;
+    else if (ctx->mem_idx)
+        write_cb = ctx->spr_cb[sprn].oea_write;
+    else
+#endif
+        write_cb = ctx->spr_cb[sprn].uea_write;
+    if (likely(write_cb != NULL)) {
+        if (likely(write_cb != SPR_NOACCESS)) {
+            (*write_cb)(ctx, sprn, rS(ctx->opcode));
+        } else {
+            /* Privilege exception */
+            qemu_log("Trying to write privileged spr %d %03x at "
+                     TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+            printf("Trying to write privileged spr %d %03x at " TARGET_FMT_lx
+                   "\n", sprn, sprn, ctx->nip);
+            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        }
+    } else {
+        /* Not defined */
+        qemu_log("Trying to write invalid spr %d %03x at "
+                 TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+        printf("Trying to write invalid spr %d %03x at " TARGET_FMT_lx "\n",
+               sprn, sprn, ctx->nip);
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+    }
+}
+
+/***                         Cache management                              ***/
+
+/* dcbf */
+static void gen_dcbf(DisasContext *ctx)
+{
+    /* XXX: specification says this is treated as a load by the MMU */
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld8u(ctx, t0, t0);
+    tcg_temp_free(t0);
+}
+
+/* dcbi (Supervisor only) */
+static void gen_dcbi(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv EA, val;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    EA = tcg_temp_new();
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    gen_addr_reg_index(ctx, EA);
+    val = tcg_temp_new();
+    /* XXX: specification says this should be treated as a store by the MMU */
+    gen_qemu_ld8u(ctx, val, EA);
+    gen_qemu_st8(ctx, val, EA);
+    tcg_temp_free(val);
+    tcg_temp_free(EA);
+#endif
+}
+
+/* dcdst */
+static void gen_dcbst(DisasContext *ctx)
+{
+    /* XXX: specification say this is treated as a load by the MMU */
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld8u(ctx, t0, t0);
+    tcg_temp_free(t0);
+}
+
+/* dcbt */
+static void gen_dcbt(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/* dcbtst */
+static void gen_dcbtst(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/* dcbz */
+static void gen_dcbz(DisasContext *ctx)
+{
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_dcbz(t0);
+    tcg_temp_free(t0);
+}
+
+static void gen_dcbz_970(DisasContext *ctx)
+{
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    if (ctx->opcode & 0x00200000)
+        gen_helper_dcbz(t0);
+    else
+        gen_helper_dcbz_970(t0);
+    tcg_temp_free(t0);
+}
+
+/* dst / dstt */
+static void gen_dst(DisasContext *ctx)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
+    } else {
+        /* interpreted as no-op */
+    }
+}
+
+/* dstst /dststt */
+static void gen_dstst(DisasContext *ctx)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
+    } else {
+        /* interpreted as no-op */
+    }
+
+}
+
+/* dss / dssall */
+static void gen_dss(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+}
+
+/* icbi */
+static void gen_icbi(DisasContext *ctx)
+{
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_icbi(t0);
+    tcg_temp_free(t0);
+}
+
+/* Optional: */
+/* dcba */
+static void gen_dcba(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a store by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/***                    Segment register manipulation                      ***/
+/* Supervisor only: */
+
+/* mfsr */
+static void gen_mfsr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_const_tl(SR(ctx->opcode));
+    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mfsrin */
+static void gen_mfsrin(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
+    tcg_gen_andi_tl(t0, t0, 0xF);
+    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mtsr */
+static void gen_mtsr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_const_tl(SR(ctx->opcode));
+    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mtsrin */
+static void gen_mtsrin(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
+    tcg_gen_andi_tl(t0, t0, 0xF);
+    gen_helper_store_sr(t0, cpu_gpr[rD(ctx->opcode)]);
+    tcg_temp_free(t0);
+#endif
+}
+
+#if defined(TARGET_PPC64)
+/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
+
+/* mfsr */
+static void gen_mfsr_64b(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_const_tl(SR(ctx->opcode));
+    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mfsrin */
+static void gen_mfsrin_64b(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
+    tcg_gen_andi_tl(t0, t0, 0xF);
+    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mtsr */
+static void gen_mtsr_64b(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_const_tl(SR(ctx->opcode));
+    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* mtsrin */
+static void gen_mtsrin_64b(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
+    tcg_gen_andi_tl(t0, t0, 0xF);
+    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* slbmte */
+static void gen_slbmte(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_store_slb(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+#endif
+}
+
+static void gen_slbmfee(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)],
+                             cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+static void gen_slbmfev(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)],
+                             cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+#endif /* defined(TARGET_PPC64) */
+
+/***                      Lookaside buffer management                      ***/
+/* Optional & mem_idx only: */
+
+/* tlbia */
+static void gen_tlbia(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_tlbia();
+#endif
+}
+
+/* tlbiel */
+static void gen_tlbiel(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* tlbie */
+static void gen_tlbie(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
+        gen_helper_tlbie(t0);
+        tcg_temp_free(t0);
+    } else
+#endif
+        gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* tlbsync */
+static void gen_tlbsync(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* This has no effect: it should ensure that all previous
+     * tlbie have completed
+     */
+    gen_stop_exception(ctx);
+#endif
+}
+
+#if defined(TARGET_PPC64)
+/* slbia */
+static void gen_slbia(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_slbia();
+#endif
+}
+
+/* slbie */
+static void gen_slbie(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+#endif
+
+/***                              External control                         ***/
+/* Optional: */
+
+/* eciwx */
+static void gen_eciwx(DisasContext *ctx)
+{
+    TCGv t0;
+    /* Should check EAR[E] ! */
+    gen_set_access_type(ctx, ACCESS_EXT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x03);
+    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+/* ecowx */
+static void gen_ecowx(DisasContext *ctx)
+{
+    TCGv t0;
+    /* Should check EAR[E] ! */
+    gen_set_access_type(ctx, ACCESS_EXT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_check_align(ctx, t0, 0x03);
+    gen_qemu_st32(ctx, cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+/* PowerPC 601 specific instructions */
+
+/* abs - abs. */
+static void gen_abs(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l1);
+    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    gen_set_label(l2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* abso - abso. */
+static void gen_abso(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    int l3 = gen_new_label();
+    /* Start with XER OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2);
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l3);
+    gen_set_label(l2);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    gen_set_label(l3);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* clcs */
+static void gen_clcs(DisasContext *ctx)
+{
+    TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
+    gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+    /* Rc=1 sets CR0 to an undefined state */
+}
+
+/* div - div. */
+static void gen_div(DisasContext *ctx)
+{
+    gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* divo - divo. */
+static void gen_divo(DisasContext *ctx)
+{
+    gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* divs - divs. */
+static void gen_divs(DisasContext *ctx)
+{
+    gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* divso - divso. */
+static void gen_divso(DisasContext *ctx)
+{
+    gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* doz - doz. */
+static void gen_doz(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
+    tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
+    gen_set_label(l2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* dozo - dozo. */
+static void gen_dozo(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+    /* Start with XER OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
+    tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
+    tcg_gen_andc_tl(t1, t1, t2);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
+    gen_set_label(l2);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* dozi */
+static void gen_dozi(DisasContext *ctx)
+{
+    target_long simm = SIMM(ctx->opcode);
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
+    tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
+    gen_set_label(l2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* lscbx - lscbx. */
+static void gen_lscbx(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
+    TCGv_i32 t2 = tcg_const_i32(rA(ctx->opcode));
+    TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
+
+    gen_addr_reg_index(ctx, t0);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_helper_lscbx(t0, t0, t1, t2, t3);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    tcg_temp_free_i32(t3);
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
+    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, t0);
+    tcg_temp_free(t0);
+}
+
+/* maskg - maskg. */
+static void gen_maskg(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+    TCGv t3 = tcg_temp_new();
+    tcg_gen_movi_tl(t3, 0xFFFFFFFF);
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
+    tcg_gen_addi_tl(t2, t0, 1);
+    tcg_gen_shr_tl(t2, t3, t2);
+    tcg_gen_shr_tl(t3, t3, t1);
+    tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
+    tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
+    tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(t3);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* maskir - maskir. */
+static void gen_maskir(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* mul - mul. */
+static void gen_mul(DisasContext *ctx)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv t2 = tcg_temp_new();
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_trunc_i64_tl(t2, t0);
+    gen_store_spr(SPR_MQ, t2);
+    tcg_gen_shri_i64(t1, t0, 32);
+    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* mulo - mulo. */
+static void gen_mulo(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv t2 = tcg_temp_new();
+    /* Start with XER OV disabled, the most likely case */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_trunc_i64_tl(t2, t0);
+    gen_store_spr(SPR_MQ, t2);
+    tcg_gen_shri_i64(t1, t0, 32);
+    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
+    tcg_gen_ext32s_i64(t1, t0);
+    tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+    gen_set_label(l1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* nabs - nabs. */
+static void gen_nabs(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    gen_set_label(l2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* nabso - nabso. */
+static void gen_nabso(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    gen_set_label(l2);
+    /* nabs never overflows */
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+}
+
+/* rlmi - rlmi. */
+static void gen_rlmi(DisasContext *ctx)
+{
+    uint32_t mb = MB(ctx->opcode);
+    uint32_t me = ME(ctx->opcode);
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    tcg_gen_andi_tl(t0, t0, MASK(mb, me));
+    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~MASK(mb, me));
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* rrib - rrib. */
+static void gen_rrib(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_movi_tl(t1, 0x80000000);
+    tcg_gen_shr_tl(t1, t1, t0);
+    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    tcg_gen_and_tl(t0, t0, t1);
+    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], t1);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sle - sle. */
+static void gen_sle(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_subfi_tl(t1, 32, t1);
+    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_or_tl(t1, t0, t1);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sleq - sleq. */
+static void gen_sleq(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_movi_tl(t2, 0xFFFFFFFF);
+    tcg_gen_shl_tl(t2, t2, t0);
+    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    gen_load_spr(t1, SPR_MQ);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_and_tl(t0, t0, t2);
+    tcg_gen_andc_tl(t1, t1, t2);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sliq - sliq. */
+static void gen_sliq(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_shli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+    tcg_gen_shri_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
+    tcg_gen_or_tl(t1, t0, t1);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* slliq - slliq. */
+static void gen_slliq(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+    gen_load_spr(t1, SPR_MQ);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU << sh));
+    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU << sh));
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sllq - sllq. */
+static void gen_sllq(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = tcg_temp_local_new();
+    TCGv t2 = tcg_temp_local_new();
+    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
+    tcg_gen_shl_tl(t1, t1, t2);
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+    gen_load_spr(t0, SPR_MQ);
+    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
+    gen_load_spr(t2, SPR_MQ);
+    tcg_gen_andc_tl(t1, t2, t1);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    gen_set_label(l2);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* slq - slq. */
+static void gen_slq(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_subfi_tl(t1, 32, t1);
+    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_or_tl(t1, t0, t1);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sraiq - sraiq. */
+static void gen_sraiq(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    int l1 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
+    tcg_gen_or_tl(t0, t0, t1);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
+    gen_set_label(l1);
+    tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sraq - sraq. */
+static void gen_sraq(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_local_new();
+    TCGv t2 = tcg_temp_local_new();
+    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
+    tcg_gen_sar_tl(t1, cpu_gpr[rS(ctx->opcode)], t2);
+    tcg_gen_subfi_tl(t2, 32, t2);
+    tcg_gen_shl_tl(t2, cpu_gpr[rS(ctx->opcode)], t2);
+    tcg_gen_or_tl(t0, t0, t2);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l1);
+    tcg_gen_mov_tl(t2, cpu_gpr[rS(ctx->opcode)]);
+    tcg_gen_sari_tl(t1, cpu_gpr[rS(ctx->opcode)], 31);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
+    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
+    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
+    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
+    gen_set_label(l2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sre - sre. */
+static void gen_sre(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_subfi_tl(t1, 32, t1);
+    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_or_tl(t1, t0, t1);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srea - srea. */
+static void gen_srea(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sreq */
+static void gen_sreq(DisasContext *ctx)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
+    tcg_gen_shr_tl(t1, t1, t0);
+    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
+    gen_load_spr(t2, SPR_MQ);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_and_tl(t0, t0, t1);
+    tcg_gen_andc_tl(t2, t2, t1);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* sriq */
+static void gen_sriq(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
+    tcg_gen_or_tl(t1, t0, t1);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srliq */
+static void gen_srliq(DisasContext *ctx)
+{
+    int sh = SH(ctx->opcode);
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_rotri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
+    gen_load_spr(t1, SPR_MQ);
+    gen_store_spr(SPR_MQ, t0);
+    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU >> sh));
+    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU >> sh));
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srlq */
+static void gen_srlq(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = tcg_temp_local_new();
+    TCGv t2 = tcg_temp_local_new();
+    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
+    tcg_gen_shr_tl(t2, t1, t2);
+    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+    gen_load_spr(t0, SPR_MQ);
+    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
+    tcg_gen_and_tl(t0, t0, t2);
+    gen_load_spr(t1, SPR_MQ);
+    tcg_gen_andc_tl(t1, t1, t2);
+    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
+    gen_set_label(l2);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* srq */
+static void gen_srq(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
+    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_subfi_tl(t1, 32, t1);
+    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
+    tcg_gen_or_tl(t1, t0, t1);
+    gen_store_spr(SPR_MQ, t1);
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
+    gen_set_label(l1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+}
+
+/* PowerPC 602 specific instructions */
+
+/* dsa  */
+static void gen_dsa(DisasContext *ctx)
+{
+    /* XXX: TODO */
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+/* esa */
+static void gen_esa(DisasContext *ctx)
+{
+    /* XXX: TODO */
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+/* mfrom */
+static void gen_mfrom(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+#endif
+}
+
+/* 602 - 603 - G2 TLB management */
+
+/* tlbld */
+static void gen_tlbld_6xx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* tlbli */
+static void gen_tlbli_6xx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* 74xx TLB management */
+
+/* tlbld */
+static void gen_tlbld_74xx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* tlbli */
+static void gen_tlbli_74xx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* POWER instructions not in PowerPC 601 */
+
+/* clf */
+static void gen_clf(DisasContext *ctx)
+{
+    /* Cache line flush: implemented as no-op */
+}
+
+/* cli */
+static void gen_cli(DisasContext *ctx)
+{
+    /* Cache line invalidate: privileged and treated as no-op */
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+#endif
+}
+
+/* dclst */
+static void gen_dclst(DisasContext *ctx)
+{
+    /* Data cache line store: treated as no-op */
+}
+
+static void gen_mfsri(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    tcg_gen_shri_tl(t0, t0, 28);
+    tcg_gen_andi_tl(t0, t0, 0xF);
+    gen_helper_load_sr(cpu_gpr[rd], t0);
+    tcg_temp_free(t0);
+    if (ra != 0 && ra != rd)
+        tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
+#endif
+}
+
+static void gen_rac(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#endif
+}
+
+static void gen_rfsvc(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_rfsvc();
+    gen_sync_exception(ctx);
+#endif
+}
+
+/* svc is not implemented for now */
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+
+/* lfq */
+static void gen_lfq(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* lfqu */
+static void gen_lfqu(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* lfqux */
+static void gen_lfqux(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    TCGv t0, t1;
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* lfqx */
+static void gen_lfqx(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfq */
+static void gen_stfq(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqu */
+static void gen_stfqu(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqux */
+static void gen_stfqux(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqx */
+static void gen_stfqx(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* BookE specific instructions */
+
+/* XXX: not implemented on 440 ? */
+static void gen_mfapidi(DisasContext *ctx)
+{
+    /* XXX: TODO */
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+/* XXX: not implemented on 440 ? */
+static void gen_tlbiva(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+    tcg_temp_free(t0);
+#endif
+}
+
+/* All 405 MAC instructions are translated here */
+static inline void gen_405_mulladd_insn(DisasContext *ctx, int opc2, int opc3,
+                                        int ra, int rb, int rt, int Rc)
+{
+    TCGv t0, t1;
+
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+
+    switch (opc3 & 0x0D) {
+    case 0x05:
+        /* macchw    - macchw.    - macchwo   - macchwo.   */
+        /* macchws   - macchws.   - macchwso  - macchwso.  */
+        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
+        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
+        /* mulchw - mulchw. */
+        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
+        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
+        tcg_gen_ext16s_tl(t1, t1);
+        break;
+    case 0x04:
+        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
+        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
+        /* mulchwu - mulchwu. */
+        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
+        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
+        tcg_gen_ext16u_tl(t1, t1);
+        break;
+    case 0x01:
+        /* machhw    - machhw.    - machhwo   - machhwo.   */
+        /* machhws   - machhws.   - machhwso  - machhwso.  */
+        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
+        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
+        /* mulhhw - mulhhw. */
+        tcg_gen_sari_tl(t0, cpu_gpr[ra], 16);
+        tcg_gen_ext16s_tl(t0, t0);
+        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
+        tcg_gen_ext16s_tl(t1, t1);
+        break;
+    case 0x00:
+        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
+        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
+        /* mulhhwu - mulhhwu. */
+        tcg_gen_shri_tl(t0, cpu_gpr[ra], 16);
+        tcg_gen_ext16u_tl(t0, t0);
+        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
+        tcg_gen_ext16u_tl(t1, t1);
+        break;
+    case 0x0D:
+        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
+        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
+        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
+        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
+        /* mullhw - mullhw. */
+        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
+        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
+        break;
+    case 0x0C:
+        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
+        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
+        /* mullhwu - mullhwu. */
+        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
+        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
+        break;
+    }
+    if (opc2 & 0x04) {
+        /* (n)multiply-and-accumulate (0x0C / 0x0E) */
+        tcg_gen_mul_tl(t1, t0, t1);
+        if (opc2 & 0x02) {
+            /* nmultiply-and-accumulate (0x0E) */
+            tcg_gen_sub_tl(t0, cpu_gpr[rt], t1);
+        } else {
+            /* multiply-and-accumulate (0x0C) */
+            tcg_gen_add_tl(t0, cpu_gpr[rt], t1);
+        }
+
+        if (opc3 & 0x12) {
+            /* Check overflow and/or saturate */
+            int l1 = gen_new_label();
+
+            if (opc3 & 0x10) {
+                /* Start with XER OV disabled, the most likely case */
+                tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
+            }
+            if (opc3 & 0x01) {
+                /* Signed */
+                tcg_gen_xor_tl(t1, cpu_gpr[rt], t1);
+                tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+                tcg_gen_xor_tl(t1, cpu_gpr[rt], t0);
+                tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1);
+                if (opc3 & 0x02) {
+                    /* Saturate */
+                    tcg_gen_sari_tl(t0, cpu_gpr[rt], 31);
+                    tcg_gen_xori_tl(t0, t0, 0x7fffffff);
+                }
+            } else {
+                /* Unsigned */
+                tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
+                if (opc3 & 0x02) {
+                    /* Saturate */
+                    tcg_gen_movi_tl(t0, UINT32_MAX);
+                }
+            }
+            if (opc3 & 0x10) {
+                /* Check overflow */
+                tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
+            }
+            gen_set_label(l1);
+            tcg_gen_mov_tl(cpu_gpr[rt], t0);
+        }
+    } else {
+        tcg_gen_mul_tl(cpu_gpr[rt], t0, t1);
+    }
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    if (unlikely(Rc) != 0) {
+        /* Update Rc0 */
+        gen_set_Rc0(ctx, cpu_gpr[rt]);
+    }
+}
+
+#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
+static void glue(gen_, name)(DisasContext *ctx)                               \
+{                                                                             \
+    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
+                         rD(ctx->opcode), Rc(ctx->opcode));                   \
+}
+
+/* macchw    - macchw.    */
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
+/* macchwo   - macchwo.   */
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
+/* macchws   - macchws.   */
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
+/* macchwso  - macchwso.  */
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
+/* macchwsu  - macchwsu.  */
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
+/* macchwsuo - macchwsuo. */
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
+/* macchwu   - macchwu.   */
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
+/* macchwuo  - macchwuo.  */
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
+/* machhw    - machhw.    */
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
+/* machhwo   - machhwo.   */
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
+/* machhws   - machhws.   */
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
+/* machhwso  - machhwso.  */
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
+/* machhwsu  - machhwsu.  */
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
+/* machhwsuo - machhwsuo. */
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
+/* machhwu   - machhwu.   */
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
+/* machhwuo  - machhwuo.  */
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
+/* maclhw    - maclhw.    */
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
+/* maclhwo   - maclhwo.   */
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
+/* maclhws   - maclhws.   */
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
+/* maclhwso  - maclhwso.  */
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
+/* maclhwu   - maclhwu.   */
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
+/* maclhwuo  - maclhwuo.  */
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
+/* maclhwsu  - maclhwsu.  */
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
+/* maclhwsuo - maclhwsuo. */
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
+/* nmacchw   - nmacchw.   */
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
+/* nmacchwo  - nmacchwo.  */
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
+/* nmacchws  - nmacchws.  */
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
+/* nmacchwso - nmacchwso. */
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
+/* nmachhw   - nmachhw.   */
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
+/* nmachhwo  - nmachhwo.  */
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
+/* nmachhws  - nmachhws.  */
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
+/* nmachhwso - nmachhwso. */
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
+/* nmaclhw   - nmaclhw.   */
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
+/* nmaclhwo  - nmaclhwo.  */
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
+/* nmaclhws  - nmaclhws.  */
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
+/* nmaclhwso - nmaclhwso. */
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
+
+/* mulchw  - mulchw.  */
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
+/* mulchwu - mulchwu. */
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
+/* mulhhw  - mulhhw.  */
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
+/* mulhhwu - mulhhwu. */
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
+/* mullhw  - mullhw.  */
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
+/* mullhwu - mullhwu. */
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
+
+/* mfdcr */
+static void gen_mfdcr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv dcrn;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    dcrn = tcg_const_tl(SPR(ctx->opcode));
+    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], dcrn);
+    tcg_temp_free(dcrn);
+#endif
+}
+
+/* mtdcr */
+static void gen_mtdcr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    TCGv dcrn;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    dcrn = tcg_const_tl(SPR(ctx->opcode));
+    gen_helper_store_dcr(dcrn, cpu_gpr[rS(ctx->opcode)]);
+    tcg_temp_free(dcrn);
+#endif
+}
+
+/* mfdcrx */
+/* XXX: not implemented on 440 ? */
+static void gen_mfdcrx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+#endif
+}
+
+/* mtdcrx */
+/* XXX: not implemented on 440 ? */
+static void gen_mtdcrx(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+#endif
+}
+
+/* mfdcrux (PPC 460) : user-mode access to DCR */
+static void gen_mfdcrux(DisasContext *ctx)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
+/* mtdcrux (PPC 460) : user-mode access to DCR */
+static void gen_mtdcrux(DisasContext *ctx)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
+/* dccci */
+static void gen_dccci(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* dcread */
+static void gen_dcread(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv EA, val;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_CACHE);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    val = tcg_temp_new();
+    gen_qemu_ld32u(ctx, val, EA);
+    tcg_temp_free(val);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
+    tcg_temp_free(EA);
+#endif
+}
+
+/* icbt */
+static void gen_icbt_40x(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/* iccci */
+static void gen_iccci(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* icread */
+static void gen_icread(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* rfci (mem_idx only) */
+static void gen_rfci_40x(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* Restore CPU state */
+    gen_helper_40x_rfci();
+    gen_sync_exception(ctx);
+#endif
+}
+
+static void gen_rfci(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* Restore CPU state */
+    gen_helper_rfci();
+    gen_sync_exception(ctx);
+#endif
+}
+
+/* BookE specific */
+
+/* XXX: not implemented on 440 ? */
+static void gen_rfdi(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* Restore CPU state */
+    gen_helper_rfdi();
+    gen_sync_exception(ctx);
+#endif
+}
+
+/* XXX: not implemented on 440 ? */
+static void gen_rfmci(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    /* Restore CPU state */
+    gen_helper_rfmci();
+    gen_sync_exception(ctx);
+#endif
+}
+
+/* TLB management - PowerPC 405 implementation */
+
+/* tlbre */
+static void gen_tlbre_40x(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+        break;
+    case 1:
+        gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+        break;
+    default:
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        break;
+    }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+static void gen_tlbsx_40x(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+    if (Rc(ctx->opcode)) {
+        int l1 = gen_new_label();
+        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
+        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
+        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
+        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
+        gen_set_label(l1);
+    }
+#endif
+}
+
+/* tlbwe */
+static void gen_tlbwe_40x(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+        break;
+    case 1:
+        gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+        break;
+    default:
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        break;
+    }
+#endif
+}
+
+/* TLB management - PowerPC 440 implementation */
+
+/* tlbre */
+static void gen_tlbre_440(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+    case 1:
+    case 2:
+        {
+            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
+            gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], t0, cpu_gpr[rA(ctx->opcode)]);
+            tcg_temp_free_i32(t0);
+        }
+        break;
+    default:
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        break;
+    }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+static void gen_tlbsx_440(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+    if (Rc(ctx->opcode)) {
+        int l1 = gen_new_label();
+        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
+        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
+        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
+        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
+        gen_set_label(l1);
+    }
+#endif
+}
+
+/* tlbwe */
+static void gen_tlbwe_440(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+    case 1:
+    case 2:
+        {
+            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
+            gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+            tcg_temp_free_i32(t0);
+        }
+        break;
+    default:
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        break;
+    }
+#endif
+}
+
+/* TLB management - PowerPC BookE 2.06 implementation */
+
+/* tlbre */
+static void gen_tlbre_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    gen_helper_booke206_tlbre();
+#endif
+}
+
+/* tlbsx - tlbsx. */
+static void gen_tlbsx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    if (rA(ctx->opcode)) {
+        t0 = tcg_temp_new();
+        tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]);
+    } else {
+        t0 = tcg_const_tl(0);
+    }
+
+    tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
+    gen_helper_booke206_tlbsx(t0);
+#endif
+}
+
+/* tlbwe */
+static void gen_tlbwe_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_booke206_tlbwe();
+#endif
+}
+
+static void gen_tlbivax_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+
+    gen_helper_booke206_tlbivax(t0);
+#endif
+}
+
+
+/* wrtee */
+static void gen_wrtee(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
+    tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
+    tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
+    tcg_temp_free(t0);
+    /* Stop translation to have a chance to raise an exception
+     * if we just set msr_ee to 1
+     */
+    gen_stop_exception(ctx);
+#endif
+}
+
+/* wrteei */
+static void gen_wrteei(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    if (ctx->opcode & 0x00008000) {
+        tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
+        /* Stop translation to have a chance to raise an exception */
+        gen_stop_exception(ctx);
+    } else {
+        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
+    }
+#endif
+}
+
+/* PowerPC 440 specific instructions */
+
+/* dlmzb */
+static void gen_dlmzb(DisasContext *ctx)
+{
+    TCGv_i32 t0 = tcg_const_i32(Rc(ctx->opcode));
+    gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
+                     cpu_gpr[rB(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+}
+
+/* mbar replaces eieio on 440 */
+static void gen_mbar(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+}
+
+/* msync replaces sync on 440 */
+static void gen_msync(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+}
+
+/* icbt */
+static void gen_icbt_440(DisasContext *ctx)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/***                      Altivec vector extension                         ***/
+/* Altivec registers moves */
+
+static inline TCGv_ptr gen_avr_ptr(int reg)
+{
+    TCGv_ptr r = tcg_temp_new_ptr();
+    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
+    return r;
+}
+
+#define GEN_VR_LDX(name, opc2, opc3)                                          \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->altivec_enabled)) {                                    \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
+    if (ctx->le_mode) {                                                       \
+        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+    } else {                                                                  \
+        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+    }                                                                         \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_VR_STX(name, opc2, opc3)                                          \
+static void gen_st##name(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->altivec_enabled)) {                                    \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
+    if (ctx->le_mode) {                                                       \
+        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+    } else {                                                                  \
+        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+    }                                                                         \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_VR_LVE(name, opc2, opc3)                                    \
+static void gen_lve##name(DisasContext *ctx)                            \
+    {                                                                   \
+        TCGv EA;                                                        \
+        TCGv_ptr rs;                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        gen_set_access_type(ctx, ACCESS_INT);                           \
+        EA = tcg_temp_new();                                            \
+        gen_addr_reg_index(ctx, EA);                                    \
+        rs = gen_avr_ptr(rS(ctx->opcode));                              \
+        gen_helper_lve##name (rs, EA);                                  \
+        tcg_temp_free(EA);                                              \
+        tcg_temp_free_ptr(rs);                                          \
+    }
+
+#define GEN_VR_STVE(name, opc2, opc3)                                   \
+static void gen_stve##name(DisasContext *ctx)                           \
+    {                                                                   \
+        TCGv EA;                                                        \
+        TCGv_ptr rs;                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        gen_set_access_type(ctx, ACCESS_INT);                           \
+        EA = tcg_temp_new();                                            \
+        gen_addr_reg_index(ctx, EA);                                    \
+        rs = gen_avr_ptr(rS(ctx->opcode));                              \
+        gen_helper_stve##name (rs, EA);                                 \
+        tcg_temp_free(EA);                                              \
+        tcg_temp_free_ptr(rs);                                          \
+    }
+
+GEN_VR_LDX(lvx, 0x07, 0x03);
+/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
+GEN_VR_LDX(lvxl, 0x07, 0x0B);
+
+GEN_VR_LVE(bx, 0x07, 0x00);
+GEN_VR_LVE(hx, 0x07, 0x01);
+GEN_VR_LVE(wx, 0x07, 0x02);
+
+GEN_VR_STX(svx, 0x07, 0x07);
+/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
+GEN_VR_STX(svxl, 0x07, 0x0F);
+
+GEN_VR_STVE(bx, 0x07, 0x04);
+GEN_VR_STVE(hx, 0x07, 0x05);
+GEN_VR_STVE(wx, 0x07, 0x06);
+
+static void gen_lvsl(DisasContext *ctx)
+{
+    TCGv_ptr rd;
+    TCGv EA;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_lvsl(rd, EA);
+    tcg_temp_free(EA);
+    tcg_temp_free_ptr(rd);
+}
+
+static void gen_lvsr(DisasContext *ctx)
+{
+    TCGv_ptr rd;
+    TCGv EA;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_lvsr(rd, EA);
+    tcg_temp_free(EA);
+    tcg_temp_free_ptr(rd);
+}
+
+static void gen_mfvscr(DisasContext *ctx)
+{
+    TCGv_i32 t;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0);
+    t = tcg_temp_new_i32();
+    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, vscr));
+    tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t);
+    tcg_temp_free_i32(t);
+}
+
+static void gen_mtvscr(DisasContext *ctx)
+{
+    TCGv_ptr p;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    p = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_mtvscr(p);
+    tcg_temp_free_ptr(p);
+}
+
+/* Logical operations */
+#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+{                                                                       \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
+    tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
+}
+
+GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
+GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
+GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
+GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
+GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);
+
+#define GEN_VXFORM(name, opc2, opc3)                                    \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+{                                                                       \
+    TCGv_ptr ra, rb, rd;                                                \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
+    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
+    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
+    gen_helper_##name (rd, ra, rb);                                     \
+    tcg_temp_free_ptr(ra);                                              \
+    tcg_temp_free_ptr(rb);                                              \
+    tcg_temp_free_ptr(rd);                                              \
+}
+
+GEN_VXFORM(vaddubm, 0, 0);
+GEN_VXFORM(vadduhm, 0, 1);
+GEN_VXFORM(vadduwm, 0, 2);
+GEN_VXFORM(vsububm, 0, 16);
+GEN_VXFORM(vsubuhm, 0, 17);
+GEN_VXFORM(vsubuwm, 0, 18);
+GEN_VXFORM(vmaxub, 1, 0);
+GEN_VXFORM(vmaxuh, 1, 1);
+GEN_VXFORM(vmaxuw, 1, 2);
+GEN_VXFORM(vmaxsb, 1, 4);
+GEN_VXFORM(vmaxsh, 1, 5);
+GEN_VXFORM(vmaxsw, 1, 6);
+GEN_VXFORM(vminub, 1, 8);
+GEN_VXFORM(vminuh, 1, 9);
+GEN_VXFORM(vminuw, 1, 10);
+GEN_VXFORM(vminsb, 1, 12);
+GEN_VXFORM(vminsh, 1, 13);
+GEN_VXFORM(vminsw, 1, 14);
+GEN_VXFORM(vavgub, 1, 16);
+GEN_VXFORM(vavguh, 1, 17);
+GEN_VXFORM(vavguw, 1, 18);
+GEN_VXFORM(vavgsb, 1, 20);
+GEN_VXFORM(vavgsh, 1, 21);
+GEN_VXFORM(vavgsw, 1, 22);
+GEN_VXFORM(vmrghb, 6, 0);
+GEN_VXFORM(vmrghh, 6, 1);
+GEN_VXFORM(vmrghw, 6, 2);
+GEN_VXFORM(vmrglb, 6, 4);
+GEN_VXFORM(vmrglh, 6, 5);
+GEN_VXFORM(vmrglw, 6, 6);
+GEN_VXFORM(vmuloub, 4, 0);
+GEN_VXFORM(vmulouh, 4, 1);
+GEN_VXFORM(vmulosb, 4, 4);
+GEN_VXFORM(vmulosh, 4, 5);
+GEN_VXFORM(vmuleub, 4, 8);
+GEN_VXFORM(vmuleuh, 4, 9);
+GEN_VXFORM(vmulesb, 4, 12);
+GEN_VXFORM(vmulesh, 4, 13);
+GEN_VXFORM(vslb, 2, 4);
+GEN_VXFORM(vslh, 2, 5);
+GEN_VXFORM(vslw, 2, 6);
+GEN_VXFORM(vsrb, 2, 8);
+GEN_VXFORM(vsrh, 2, 9);
+GEN_VXFORM(vsrw, 2, 10);
+GEN_VXFORM(vsrab, 2, 12);
+GEN_VXFORM(vsrah, 2, 13);
+GEN_VXFORM(vsraw, 2, 14);
+GEN_VXFORM(vslo, 6, 16);
+GEN_VXFORM(vsro, 6, 17);
+GEN_VXFORM(vaddcuw, 0, 6);
+GEN_VXFORM(vsubcuw, 0, 22);
+GEN_VXFORM(vaddubs, 0, 8);
+GEN_VXFORM(vadduhs, 0, 9);
+GEN_VXFORM(vadduws, 0, 10);
+GEN_VXFORM(vaddsbs, 0, 12);
+GEN_VXFORM(vaddshs, 0, 13);
+GEN_VXFORM(vaddsws, 0, 14);
+GEN_VXFORM(vsububs, 0, 24);
+GEN_VXFORM(vsubuhs, 0, 25);
+GEN_VXFORM(vsubuws, 0, 26);
+GEN_VXFORM(vsubsbs, 0, 28);
+GEN_VXFORM(vsubshs, 0, 29);
+GEN_VXFORM(vsubsws, 0, 30);
+GEN_VXFORM(vrlb, 2, 0);
+GEN_VXFORM(vrlh, 2, 1);
+GEN_VXFORM(vrlw, 2, 2);
+GEN_VXFORM(vsl, 2, 7);
+GEN_VXFORM(vsr, 2, 11);
+GEN_VXFORM(vpkuhum, 7, 0);
+GEN_VXFORM(vpkuwum, 7, 1);
+GEN_VXFORM(vpkuhus, 7, 2);
+GEN_VXFORM(vpkuwus, 7, 3);
+GEN_VXFORM(vpkshus, 7, 4);
+GEN_VXFORM(vpkswus, 7, 5);
+GEN_VXFORM(vpkshss, 7, 6);
+GEN_VXFORM(vpkswss, 7, 7);
+GEN_VXFORM(vpkpx, 7, 12);
+GEN_VXFORM(vsum4ubs, 4, 24);
+GEN_VXFORM(vsum4sbs, 4, 28);
+GEN_VXFORM(vsum4shs, 4, 25);
+GEN_VXFORM(vsum2sws, 4, 26);
+GEN_VXFORM(vsumsws, 4, 30);
+GEN_VXFORM(vaddfp, 5, 0);
+GEN_VXFORM(vsubfp, 5, 1);
+GEN_VXFORM(vmaxfp, 5, 16);
+GEN_VXFORM(vminfp, 5, 17);
+
+#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr ra, rb, rd;                                            \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        ra = gen_avr_ptr(rA(ctx->opcode));                              \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##opname (rd, ra, rb);                               \
+        tcg_temp_free_ptr(ra);                                          \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+#define GEN_VXRFORM(name, opc2, opc3)                                \
+    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
+    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
+
+GEN_VXRFORM(vcmpequb, 3, 0)
+GEN_VXRFORM(vcmpequh, 3, 1)
+GEN_VXRFORM(vcmpequw, 3, 2)
+GEN_VXRFORM(vcmpgtsb, 3, 12)
+GEN_VXRFORM(vcmpgtsh, 3, 13)
+GEN_VXRFORM(vcmpgtsw, 3, 14)
+GEN_VXRFORM(vcmpgtub, 3, 8)
+GEN_VXRFORM(vcmpgtuh, 3, 9)
+GEN_VXRFORM(vcmpgtuw, 3, 10)
+GEN_VXRFORM(vcmpeqfp, 3, 3)
+GEN_VXRFORM(vcmpgefp, 3, 7)
+GEN_VXRFORM(vcmpgtfp, 3, 11)
+GEN_VXRFORM(vcmpbfp, 3, 15)
+
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr rd;                                                    \
+        TCGv_i32 simm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, simm);                                   \
+        tcg_temp_free_i32(simm);                                        \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VXFORM_SIMM(vspltisb, 6, 12);
+GEN_VXFORM_SIMM(vspltish, 6, 13);
+GEN_VXFORM_SIMM(vspltisw, 6, 14);
+
+#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, rb);                                     \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                         \
+    }
+
+GEN_VXFORM_NOA(vupkhsb, 7, 8);
+GEN_VXFORM_NOA(vupkhsh, 7, 9);
+GEN_VXFORM_NOA(vupklsb, 7, 10);
+GEN_VXFORM_NOA(vupklsh, 7, 11);
+GEN_VXFORM_NOA(vupkhpx, 7, 13);
+GEN_VXFORM_NOA(vupklpx, 7, 15);
+GEN_VXFORM_NOA(vrefp, 5, 4);
+GEN_VXFORM_NOA(vrsqrtefp, 5, 5);
+GEN_VXFORM_NOA(vexptefp, 5, 6);
+GEN_VXFORM_NOA(vlogefp, 5, 7);
+GEN_VXFORM_NOA(vrfim, 5, 8);
+GEN_VXFORM_NOA(vrfin, 5, 9);
+GEN_VXFORM_NOA(vrfip, 5, 10);
+GEN_VXFORM_NOA(vrfiz, 5, 11);
+
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rd;                                                    \
+        TCGv_i32 simm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, simm);                                   \
+        tcg_temp_free_i32(simm);                                        \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+        TCGv_i32 uimm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, rb, uimm);                               \
+        tcg_temp_free_i32(uimm);                                        \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VXFORM_UIMM(vspltb, 6, 8);
+GEN_VXFORM_UIMM(vsplth, 6, 9);
+GEN_VXFORM_UIMM(vspltw, 6, 10);
+GEN_VXFORM_UIMM(vcfux, 5, 12);
+GEN_VXFORM_UIMM(vcfsx, 5, 13);
+GEN_VXFORM_UIMM(vctuxs, 5, 14);
+GEN_VXFORM_UIMM(vctsxs, 5, 15);
+
+static void gen_vsldoi(DisasContext *ctx)
+{
+    TCGv_ptr ra, rb, rd;
+    TCGv_i32 sh;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    ra = gen_avr_ptr(rA(ctx->opcode));
+    rb = gen_avr_ptr(rB(ctx->opcode));
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    sh = tcg_const_i32(VSH(ctx->opcode));
+    gen_helper_vsldoi (rd, ra, rb, sh);
+    tcg_temp_free_ptr(ra);
+    tcg_temp_free_ptr(rb);
+    tcg_temp_free_ptr(rd);
+    tcg_temp_free_i32(sh);
+}
+
+#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)                      \
+    {                                                                   \
+        TCGv_ptr ra, rb, rc, rd;                                        \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        ra = gen_avr_ptr(rA(ctx->opcode));                              \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rc = gen_avr_ptr(rC(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        if (Rc(ctx->opcode)) {                                          \
+            gen_helper_##name1 (rd, ra, rb, rc);                        \
+        } else {                                                        \
+            gen_helper_##name0 (rd, ra, rb, rc);                        \
+        }                                                               \
+        tcg_temp_free_ptr(ra);                                          \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rc);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)
+
+static void gen_vmladduhm(DisasContext *ctx)
+{
+    TCGv_ptr ra, rb, rc, rd;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    ra = gen_avr_ptr(rA(ctx->opcode));
+    rb = gen_avr_ptr(rB(ctx->opcode));
+    rc = gen_avr_ptr(rC(ctx->opcode));
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_vmladduhm(rd, ra, rb, rc);
+    tcg_temp_free_ptr(ra);
+    tcg_temp_free_ptr(rb);
+    tcg_temp_free_ptr(rc);
+    tcg_temp_free_ptr(rd);
+}
+
+GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
+GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
+GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
+GEN_VAFORM_PAIRED(vsel, vperm, 21)
+GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
+
+/***                           SPE extension                               ***/
+/* Register moves */
+
+
+static inline void gen_evmra(DisasContext *ctx)
+{
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+
+#if defined(TARGET_PPC64)
+    /* rD := rA */
+    tcg_gen_mov_i64(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+
+    /* spe_acc := rA */
+    tcg_gen_st_i64(cpu_gpr[rA(ctx->opcode)],
+                   cpu_env,
+                   offsetof(CPUState, spe_acc));
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* tmp := rA_lo + rA_hi << 32 */
+    tcg_gen_concat_i32_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+
+    /* spe_acc := tmp */
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+    tcg_temp_free_i64(tmp);
+
+    /* rD := rA */
+    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+#endif
+}
+
+static inline void gen_load_gpr64(TCGv_i64 t, int reg)
+{
+#if defined(TARGET_PPC64)
+    tcg_gen_mov_i64(t, cpu_gpr[reg]);
+#else
+    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
+#endif
+}
+
+static inline void gen_store_gpr64(int reg, TCGv_i64 t)
+{
+#if defined(TARGET_PPC64)
+    tcg_gen_mov_i64(cpu_gpr[reg], t);
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_trunc_i64_i32(cpu_gpr[reg], t);
+    tcg_gen_shri_i64(tmp, t, 32);
+    tcg_gen_trunc_i64_i32(cpu_gprh[reg], tmp);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)                    \
+{                                                                             \
+    if (Rc(ctx->opcode))                                                      \
+        gen_##name1(ctx);                                                     \
+    else                                                                      \
+        gen_##name0(ctx);                                                     \
+}
+
+/* Handler for undefined SPE opcodes */
+static inline void gen_speundef(DisasContext *ctx)
+{
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+/* SPE logic */
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
+           cpu_gpr[rB(ctx->opcode)]);                                         \
+}
+#else
+#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
+           cpu_gpr[rB(ctx->opcode)]);                                         \
+    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
+           cpu_gprh[rB(ctx->opcode)]);                                        \
+}
+#endif
+
+GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl);
+GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl);
+GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl);
+GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl);
+GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl);
+GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl);
+GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl);
+GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl);
+
+/* SPE logic immediate */
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
+    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
+    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
+    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
+    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t1, t2);                                            \
+    tcg_temp_free_i64(t2);                                                    \
+    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
+    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#else
+#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],               \
+            rB(ctx->opcode));                                                 \
+    tcg_opi(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],             \
+            rB(ctx->opcode));                                                 \
+}
+#endif
+GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32);
+
+/* SPE arithmetic */
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
+    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
+    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
+    tcg_op(t0, t0);                                                           \
+    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t1, t2);                                            \
+    tcg_temp_free_i64(t2);                                                    \
+    tcg_op(t1, t1);                                                           \
+    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#else
+#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);               \
+    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);             \
+}
+#endif
+
+static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+
+    tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1);
+    tcg_gen_neg_i32(ret, arg1);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_i32(ret, arg1);
+    gen_set_label(l2);
+}
+GEN_SPEOP_ARITH1(evabs, gen_op_evabs);
+GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32);
+GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32);
+GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32);
+static inline void gen_op_evrndw(TCGv_i32 ret, TCGv_i32 arg1)
+{
+    tcg_gen_addi_i32(ret, arg1, 0x8000);
+    tcg_gen_ext16u_i32(ret, ret);
+}
+GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
+GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
+GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
+
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
+    TCGv_i64 t3 = tcg_temp_local_new_i64();                                   \
+    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
+    tcg_gen_trunc_i64_i32(t2, cpu_gpr[rB(ctx->opcode)]);                      \
+    tcg_op(t0, t0, t2);                                                       \
+    tcg_gen_shri_i64(t3, cpu_gpr[rA(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t1, t3);                                            \
+    tcg_gen_shri_i64(t3, cpu_gpr[rB(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t2, t3);                                            \
+    tcg_temp_free_i64(t3);                                                    \
+    tcg_op(t1, t1, t2);                                                       \
+    tcg_temp_free_i32(t2);                                                    \
+    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#else
+#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
+           cpu_gpr[rB(ctx->opcode)]);                                         \
+    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
+           cpu_gprh[rB(ctx->opcode)]);                                        \
+}
+#endif
+
+static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new_i32();
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_shr_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
+static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new_i32();
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_sar_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
+static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    t0 = tcg_temp_local_new_i32();
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_shl_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
+static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    tcg_gen_andi_i32(t0, arg2, 0x1F);
+    tcg_gen_rotl_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
+static inline void gen_evmergehi(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32);
+    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+#else
+    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+#endif
+}
+GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32);
+static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_sub_i32(ret, arg2, arg1);
+}
+GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
+
+/* SPE arithmetic immediate */
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
+    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
+    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]);                      \
+    tcg_op(t0, t0, rA(ctx->opcode));                                          \
+    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t1, t2);                                            \
+    tcg_temp_free_i64(t2);                                                    \
+    tcg_op(t1, t1, rA(ctx->opcode));                                          \
+    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#else
+#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
+           rA(ctx->opcode));                                                  \
+    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)],              \
+           rA(ctx->opcode));                                                  \
+}
+#endif
+GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
+GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);
+
+/* SPE comparison */
+#if defined(TARGET_PPC64)
+#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    int l1 = gen_new_label();                                                 \
+    int l2 = gen_new_label();                                                 \
+    int l3 = gen_new_label();                                                 \
+    int l4 = gen_new_label();                                                 \
+    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
+    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
+    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
+    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
+    tcg_gen_trunc_i64_i32(t1, cpu_gpr[rB(ctx->opcode)]);                      \
+    tcg_gen_brcond_i32(tcg_cond, t0, t1, l1);                                 \
+    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
+    tcg_gen_br(l2);                                                           \
+    gen_set_label(l1);                                                        \
+    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
+                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
+    gen_set_label(l2);                                                        \
+    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t0, t2);                                            \
+    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
+    tcg_gen_trunc_i64_i32(t1, t2);                                            \
+    tcg_temp_free_i64(t2);                                                    \
+    tcg_gen_brcond_i32(tcg_cond, t0, t1, l3);                                 \
+    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
+                     ~(CRF_CH | CRF_CH_AND_CL));                              \
+    tcg_gen_br(l4);                                                           \
+    gen_set_label(l3);                                                        \
+    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
+                    CRF_CH | CRF_CH_OR_CL);                                   \
+    gen_set_label(l4);                                                        \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#else
+#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    int l1 = gen_new_label();                                                 \
+    int l2 = gen_new_label();                                                 \
+    int l3 = gen_new_label();                                                 \
+    int l4 = gen_new_label();                                                 \
+                                                                              \
+    tcg_gen_brcond_i32(tcg_cond, cpu_gpr[rA(ctx->opcode)],                    \
+                       cpu_gpr[rB(ctx->opcode)], l1);                         \
+    tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0);                           \
+    tcg_gen_br(l2);                                                           \
+    gen_set_label(l1);                                                        \
+    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
+                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
+    gen_set_label(l2);                                                        \
+    tcg_gen_brcond_i32(tcg_cond, cpu_gprh[rA(ctx->opcode)],                   \
+                       cpu_gprh[rB(ctx->opcode)], l3);                        \
+    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
+                     ~(CRF_CH | CRF_CH_AND_CL));                              \
+    tcg_gen_br(l4);                                                           \
+    gen_set_label(l3);                                                        \
+    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
+                    CRF_CH | CRF_CH_OR_CL);                                   \
+    gen_set_label(l4);                                                        \
+}
+#endif
+GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU);
+GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT);
+GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU);
+GEN_SPEOP_COMP(evcmplts, TCG_COND_LT);
+GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ);
+
+/* SPE misc */
+static inline void gen_brinc(DisasContext *ctx)
+{
+    /* Note: brinc is usable even if SPE is disabled */
+    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
+                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+}
+static inline void gen_evmergelo(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+#else
+    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+static inline void gen_evmergehilo(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+#else
+    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+#endif
+}
+static inline void gen_evmergelohi(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32);
+    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+#else
+    if (rD(ctx->opcode) == rA(ctx->opcode)) {
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_mov_i32(tmp, cpu_gpr[rA(ctx->opcode)]);
+        tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+        tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], tmp);
+        tcg_temp_free_i32(tmp);
+    } else {
+        tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+        tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    }
+#endif
+}
+static inline void gen_evsplati(DisasContext *ctx)
+{
+    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27;
+
+#if defined(TARGET_PPC64)
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
+#else
+    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
+    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
+#endif
+}
+static inline void gen_evsplatfi(DisasContext *ctx)
+{
+    uint64_t imm = rA(ctx->opcode) << 27;
+
+#if defined(TARGET_PPC64)
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
+#else
+    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
+    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
+#endif
+}
+
+static inline void gen_evsel(DisasContext *ctx)
+{
+    int l1 = gen_new_label();
+    int l2 = gen_new_label();
+    int l3 = gen_new_label();
+    int l4 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+#if defined(TARGET_PPC64)
+    TCGv t1 = tcg_temp_local_new();
+    TCGv t2 = tcg_temp_local_new();
+#endif
+    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
+#if defined(TARGET_PPC64)
+    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF00000000ULL);
+#else
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+#endif
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+#if defined(TARGET_PPC64)
+    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0xFFFFFFFF00000000ULL);
+#else
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+#endif
+    gen_set_label(l2);
+    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3);
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32u_tl(t2, cpu_gpr[rA(ctx->opcode)]);
+#else
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+#endif
+    tcg_gen_br(l4);
+    gen_set_label(l3);
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32u_tl(t2, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+#endif
+    gen_set_label(l4);
+    tcg_temp_free_i32(t0);
+#if defined(TARGET_PPC64)
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t1, t2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+#endif
+}
+
+static void gen_evsel0(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel1(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel2(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel3(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+/* Multiply */
+
+static inline void gen_evmwumi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32u_tl(t1, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#endif
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwumia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+
+    gen_evmwumi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwumiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc;
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+
+    gen_evmwumi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+#if defined(TARGET_PPC64)
+    tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]);
+#else
+    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+#endif
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwsmia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    gen_evmwsmi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));
+
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc = tcg_temp_new_i64();
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    gen_evmwsmi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(evmra,          speundef,      0x02, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE); ////
+
+/* SPE load and stores */
+static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
+{
+    target_ulong uimm = rB(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        tcg_gen_movi_tl(EA, uimm << sh);
+    } else {
+        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode) {
+            tcg_gen_ext32u_tl(EA, EA);
+        }
+#endif
+    }
+}
+
+static inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    gen_qemu_ld64(ctx, t0, addr);
+    tcg_gen_trunc_i64_i32(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_gen_shri_i64(t0, t0, 32);
+    tcg_gen_trunc_i64_i32(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld32u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
+    gen_addr_add(ctx, addr, addr, 4);
+    gen_qemu_ld32u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 4);
+    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+#endif
+}
+
+static inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16s(ctx, t0, addr);
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
+    tcg_gen_ext32u_tl(t0, t0);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+#endif
+}
+
+static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16s(ctx, t0, addr);
+    tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16s(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+#endif
+}
+
+static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld32u(ctx, t0, addr);
+#if defined(TARGET_PPC64)
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
+    tcg_gen_shli_tl(t0, t0, 32);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+#else
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+#endif
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    tcg_gen_concat_i32_i64(t0, cpu_gpr[rS(ctx->opcode)], cpu_gprh[rS(ctx->opcode)]);
+    gen_qemu_st64(ctx, t0, addr);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
+    gen_qemu_st32(ctx, t0, addr);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+#endif
+    gen_addr_add(ctx, addr, addr, 4);
+    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
+#else
+    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
+#endif
+    gen_qemu_st16(ctx, t0, addr);
+    gen_addr_add(ctx, addr, addr, 2);
+#if defined(TARGET_PPC64)
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
+    gen_qemu_st16(ctx, t0, addr);
+#else
+    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+#endif
+    gen_addr_add(ctx, addr, addr, 2);
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    tcg_temp_free(t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+#if defined(TARGET_PPC64)
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
+#else
+    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
+#endif
+    gen_qemu_st16(ctx, t0, addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
+    gen_qemu_st16(ctx, t0, addr);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+#endif
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr)
+{
+#if defined(TARGET_PPC64)
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
+    gen_qemu_st32(ctx, t0, addr);
+    tcg_temp_free(t0);
+#else
+    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+#endif
+}
+
+static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv t0;                                                                  \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    t0 = tcg_temp_new();                                                      \
+    if (Rc(ctx->opcode)) {                                                    \
+        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
+    } else {                                                                  \
+        gen_addr_reg_index(ctx, t0);                                          \
+    }                                                                         \
+    gen_op_##name(ctx, t0);                                                   \
+    tcg_temp_free(t0);                                                        \
+}
+
+GEN_SPEOP_LDST(evldd, 0x00, 3);
+GEN_SPEOP_LDST(evldw, 0x01, 3);
+GEN_SPEOP_LDST(evldh, 0x02, 3);
+GEN_SPEOP_LDST(evlhhesplat, 0x04, 1);
+GEN_SPEOP_LDST(evlhhousplat, 0x06, 1);
+GEN_SPEOP_LDST(evlhhossplat, 0x07, 1);
+GEN_SPEOP_LDST(evlwhe, 0x08, 2);
+GEN_SPEOP_LDST(evlwhou, 0x0A, 2);
+GEN_SPEOP_LDST(evlwhos, 0x0B, 2);
+GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2);
+GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2);
+
+GEN_SPEOP_LDST(evstdd, 0x10, 3);
+GEN_SPEOP_LDST(evstdw, 0x11, 3);
+GEN_SPEOP_LDST(evstdh, 0x12, 3);
+GEN_SPEOP_LDST(evstwhe, 0x18, 2);
+GEN_SPEOP_LDST(evstwho, 0x1A, 2);
+GEN_SPEOP_LDST(evstwwe, 0x1C, 2);
+GEN_SPEOP_LDST(evstwwo, 0x1E, 2);
+
+/* Multiply and add - TODO */
+#if 0
+GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0x00000000, PPC_SPE);
+#endif
+
+/***                      SPE floating-point extension                     ***/
+#if defined(TARGET_PPC64)
+#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0;                                                              \
+    TCGv t1;                                                                  \
+    t0 = tcg_temp_new_i32();                                                  \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(t0, t0);                                                \
+    t1 = tcg_temp_new();                                                      \
+    tcg_gen_extu_i32_tl(t1, t0);                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
+                    0xFFFFFFFF00000000ULL);                                   \
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1);    \
+    tcg_temp_free(t1);                                                        \
+}
+#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0;                                                              \
+    TCGv t1;                                                                  \
+    t0 = tcg_temp_new_i32();                                                  \
+    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
+    t1 = tcg_temp_new();                                                      \
+    tcg_gen_extu_i32_tl(t1, t0);                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
+                    0xFFFFFFFF00000000ULL);                                   \
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1);    \
+    tcg_temp_free(t1);                                                        \
+}
+#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0 = tcg_temp_new_i32();                                         \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
+    tcg_temp_free_i32(t0);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+}
+#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0, t1;                                                          \
+    TCGv_i64 t2;                                                              \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+    t1 = tcg_temp_new_i32();                                                  \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(t0, t0, t1);                                            \
+    tcg_temp_free_i32(t1);                                                    \
+    t2 = tcg_temp_new();                                                      \
+    tcg_gen_extu_i32_tl(t2, t0);                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
+                    0xFFFFFFFF00000000ULL);                                   \
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t2);    \
+    tcg_temp_free(t2);                                                        \
+}
+#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
+                      cpu_gpr[rB(ctx->opcode)]);                              \
+}
+#define GEN_SPEFPUOP_COMP_32(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+    t1 = tcg_temp_new_i32();                                                  \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#define GEN_SPEFPUOP_COMP_64(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
+                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+}
+#else
+#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+}
+#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
+    tcg_temp_free_i64(t0);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
+    gen_helper_##name(t0, t0);                                                \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+}
+#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
+                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+}
+#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i64();                                                  \
+    t1 = tcg_temp_new_i64();                                                  \
+    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
+    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
+    gen_helper_##name(t0, t0, t1);                                            \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i64(t1);                                                    \
+}
+#define GEN_SPEFPUOP_COMP_32(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
+                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+}
+#define GEN_SPEFPUOP_COMP_64(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i64();                                                  \
+    t1 = tcg_temp_new_i64();                                                  \
+    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
+    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i64(t1);                                                    \
+}
+#endif
+
+/* Single precision floating-point vectors operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
+GEN_SPEFPUOP_ARITH2_64_64(evfssub);
+GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
+GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
+static inline void gen_evfsabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
+#else
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
+#endif
+}
+static inline void gen_evfsnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
+#else
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+#endif
+}
+static inline void gen_evfsneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
+#else
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+#endif
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_64_64(evfscfui);
+GEN_SPEFPUOP_CONV_64_64(evfscfsi);
+GEN_SPEFPUOP_CONV_64_64(evfscfuf);
+GEN_SPEFPUOP_CONV_64_64(evfscfsf);
+GEN_SPEFPUOP_CONV_64_64(evfsctui);
+GEN_SPEFPUOP_CONV_64_64(evfsctsi);
+GEN_SPEFPUOP_CONV_64_64(evfsctuf);
+GEN_SPEFPUOP_CONV_64_64(evfsctsf);
+GEN_SPEFPUOP_CONV_64_64(evfsctuiz);
+GEN_SPEFPUOP_CONV_64_64(evfsctsiz);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_64(evfscmpgt);
+GEN_SPEFPUOP_COMP_64(evfscmplt);
+GEN_SPEFPUOP_COMP_64(evfscmpeq);
+GEN_SPEFPUOP_COMP_64(evfststgt);
+GEN_SPEFPUOP_COMP_64(evfststlt);
+GEN_SPEFPUOP_COMP_64(evfststeq);
+
+/* Opcodes definitions */
+GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
+
+/* Single precision floating-point operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_32_32(efsadd);
+GEN_SPEFPUOP_ARITH2_32_32(efssub);
+GEN_SPEFPUOP_ARITH2_32_32(efsmul);
+GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
+static inline void gen_efsabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
+}
+static inline void gen_efsnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+}
+static inline void gen_efsneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_32_32(efscfui);
+GEN_SPEFPUOP_CONV_32_32(efscfsi);
+GEN_SPEFPUOP_CONV_32_32(efscfuf);
+GEN_SPEFPUOP_CONV_32_32(efscfsf);
+GEN_SPEFPUOP_CONV_32_32(efsctui);
+GEN_SPEFPUOP_CONV_32_32(efsctsi);
+GEN_SPEFPUOP_CONV_32_32(efsctuf);
+GEN_SPEFPUOP_CONV_32_32(efsctsf);
+GEN_SPEFPUOP_CONV_32_32(efsctuiz);
+GEN_SPEFPUOP_CONV_32_32(efsctsiz);
+GEN_SPEFPUOP_CONV_32_64(efscfd);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_32(efscmpgt);
+GEN_SPEFPUOP_COMP_32(efscmplt);
+GEN_SPEFPUOP_COMP_32(efscmpeq);
+GEN_SPEFPUOP_COMP_32(efststgt);
+GEN_SPEFPUOP_COMP_32(efststlt);
+GEN_SPEFPUOP_COMP_32(efststeq);
+
+/* Opcodes definitions */
+GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
+
+/* Double precision floating-point operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_64_64(efdadd);
+GEN_SPEFPUOP_ARITH2_64_64(efdsub);
+GEN_SPEFPUOP_ARITH2_64_64(efdmul);
+GEN_SPEFPUOP_ARITH2_64_64(efddiv);
+static inline void gen_efdabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
+#else
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
+#endif
+}
+static inline void gen_efdnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
+#else
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+#endif
+}
+static inline void gen_efdneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_APU);
+        return;
+    }
+#if defined(TARGET_PPC64)
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
+#else
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+#endif
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_64_32(efdcfui);
+GEN_SPEFPUOP_CONV_64_32(efdcfsi);
+GEN_SPEFPUOP_CONV_64_32(efdcfuf);
+GEN_SPEFPUOP_CONV_64_32(efdcfsf);
+GEN_SPEFPUOP_CONV_32_64(efdctui);
+GEN_SPEFPUOP_CONV_32_64(efdctsi);
+GEN_SPEFPUOP_CONV_32_64(efdctuf);
+GEN_SPEFPUOP_CONV_32_64(efdctsf);
+GEN_SPEFPUOP_CONV_32_64(efdctuiz);
+GEN_SPEFPUOP_CONV_32_64(efdctsiz);
+GEN_SPEFPUOP_CONV_64_32(efdcfs);
+GEN_SPEFPUOP_CONV_64_64(efdcfuid);
+GEN_SPEFPUOP_CONV_64_64(efdcfsid);
+GEN_SPEFPUOP_CONV_64_64(efdctuidz);
+GEN_SPEFPUOP_CONV_64_64(efdctsidz);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_64(efdcmpgt);
+GEN_SPEFPUOP_COMP_64(efdcmplt);
+GEN_SPEFPUOP_COMP_64(efdcmpeq);
+GEN_SPEFPUOP_COMP_64(efdtstgt);
+GEN_SPEFPUOP_COMP_64(efdtstlt);
+GEN_SPEFPUOP_COMP_64(efdtsteq);
+
+/* Opcodes definitions */
+GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
+GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
+GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
+
+static opcode_t opcodes[] = {
+GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
+GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
+GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
+GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER),
+GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
+GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL),
+GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER),
+GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER),
+GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(mullwo, 0x1F, 0x0B, 0x17, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(mulld, 0x1F, 0x09, 0x07, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(neg, 0x1F, 0x08, 0x03, 0x0000F800, PPC_INTEGER),
+GEN_HANDLER(nego, 0x1F, 0x08, 0x13, 0x0000F800, PPC_INTEGER),
+GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB),
+GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
+GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(sraw, 0x1F, 0x18, 0x18, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(srw, 0x1F, 0x18, 0x10, 0x00000000, PPC_INTEGER),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(sld, 0x1F, 0x1B, 0x00, 0x00000000, PPC_64B),
+GEN_HANDLER(srad, 0x1F, 0x1A, 0x18, 0x00000000, PPC_64B),
+GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B),
+GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B),
+GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
+GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
+GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
+GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00010000, PPC_FLOAT),
+GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
+GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
+GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING),
+GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING),
+GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING),
+GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING),
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO),
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM),
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000000, PPC_RES),
+GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000000, PPC_64B),
+GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC),
+GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT),
+GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
+GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
+GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
+GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW),
+GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
+GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
+GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H),
+#endif
+GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW),
+GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW),
+GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B),
+GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B),
+#endif
+GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC),
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC),
+GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC),
+GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC),
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB),
+GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B),
+#endif
+GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC),
+GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC),
+GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE),
+GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE),
+GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE),
+GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE),
+GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE),
+GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ),
+GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT),
+GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC),
+GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC),
+GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC),
+GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI),
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA),
+GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT),
+GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT),
+GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT),
+GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT),
+#if defined(TARGET_PPC64)
+GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B),
+GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
+             PPC_SEGMENT_64B),
+GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B),
+GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
+             PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B),
+#endif
+GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA),
+GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE),
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE),
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC),
+#if defined(TARGET_PPC64)
+GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI),
+GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI),
+#endif
+GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN),
+GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN),
+GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR),
+GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR),
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR),
+GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
+GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC),
+GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC),
+GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC),
+GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
+GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
+GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB),
+GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB),
+GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
+GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER),
+GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER),
+GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER),
+GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER),
+GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER),
+GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
+GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
+GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2),
+GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2),
+GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
+GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
+GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2),
+GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2),
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI),
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA),
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR),
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR),
+GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX),
+GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX),
+GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX),
+GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX),
+GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON),
+GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON),
+GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
+GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
+GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
+GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
+GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI),
+GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI),
+GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB),
+GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB),
+GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB),
+GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE),
+GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE),
+GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE),
+GEN_HANDLER2_E(tlbre_booke206, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbsx_booke206, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
+               PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
+GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
+GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
+              PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
+              PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
+               PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
+GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
+GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
+GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC),
+GEN_HANDLER(vsldoi, 0x04, 0x16, 0xFF, 0x00000400, PPC_ALTIVEC),
+GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC),
+GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE),
+
+#undef GEN_INT_ARITH_ADD
+#undef GEN_INT_ARITH_ADD_CONST
+#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov)         \
+GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x00000000, PPC_INTEGER),
+#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val,                        \
+                                add_ca, compute_ca, compute_ov)               \
+GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x0000F800, PPC_INTEGER),
+GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
+GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
+GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
+GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
+GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
+GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
+GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
+GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
+
+#undef GEN_INT_ARITH_DIVW
+#define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov)                      \
+GEN_HANDLER(name, 0x1F, 0x0B, opc3, 0x00000000, PPC_INTEGER)
+GEN_INT_ARITH_DIVW(divwu, 0x0E, 0, 0),
+GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1),
+GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0),
+GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1),
+
+#if defined(TARGET_PPC64)
+#undef GEN_INT_ARITH_DIVD
+#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
+GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)
+GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0),
+GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1),
+GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0),
+GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1),
+
+#undef GEN_INT_ARITH_MUL_HELPER
+#define GEN_INT_ARITH_MUL_HELPER(name, opc3)                                  \
+GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)
+GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00),
+GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02),
+GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17),
+#endif
+
+#undef GEN_INT_ARITH_SUBF
+#undef GEN_INT_ARITH_SUBF_CONST
+#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov)        \
+GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x00000000, PPC_INTEGER),
+#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val,                       \
+                                add_ca, compute_ca, compute_ov)               \
+GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x0000F800, PPC_INTEGER),
+GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0)
+GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1)
+GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0)
+GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1)
+GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0)
+GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1)
+GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0)
+GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1)
+GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0)
+GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
+
+#undef GEN_LOGICAL1
+#undef GEN_LOGICAL2
+#define GEN_LOGICAL2(name, tcg_op, opc, type)                                 \
+GEN_HANDLER(name, 0x1F, 0x1C, opc, 0x00000000, type)
+#define GEN_LOGICAL1(name, tcg_op, opc, type)                                 \
+GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type)
+GEN_LOGICAL2(and, tcg_gen_and_tl, 0x00, PPC_INTEGER),
+GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER),
+GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER),
+GEN_LOGICAL1(extsb, tcg_gen_ext8s_tl, 0x1D, PPC_INTEGER),
+GEN_LOGICAL1(extsh, tcg_gen_ext16s_tl, 0x1C, PPC_INTEGER),
+GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER),
+GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER),
+GEN_LOGICAL2(orc, tcg_gen_orc_tl, 0x0C, PPC_INTEGER),
+#if defined(TARGET_PPC64)
+GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B),
+#endif
+
+#if defined(TARGET_PPC64)
+#undef GEN_PPC64_R2
+#undef GEN_PPC64_R4
+#define GEN_PPC64_R2(name, opc1, opc2)                                        \
+GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B),\
+GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
+             PPC_64B)
+#define GEN_PPC64_R4(name, opc1, opc2)                                        \
+GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B),\
+GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000,   \
+             PPC_64B),                                                        \
+GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
+             PPC_64B),                                                        \
+GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000,   \
+             PPC_64B)
+GEN_PPC64_R4(rldicl, 0x1E, 0x00),
+GEN_PPC64_R4(rldicr, 0x1E, 0x02),
+GEN_PPC64_R4(rldic, 0x1E, 0x04),
+GEN_PPC64_R2(rldcl, 0x1E, 0x08),
+GEN_PPC64_R2(rldcr, 0x1E, 0x09),
+GEN_PPC64_R4(rldimi, 0x1E, 0x06),
+#endif
+
+#undef _GEN_FLOAT_ACB
+#undef GEN_FLOAT_ACB
+#undef _GEN_FLOAT_AB
+#undef GEN_FLOAT_AB
+#undef _GEN_FLOAT_AC
+#undef GEN_FLOAT_AC
+#undef GEN_FLOAT_B
+#undef GEN_FLOAT_BS
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)
+#define GEN_FLOAT_ACB(name, op2, set_fprf, type)                              \
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type),                     \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type)
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
+#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type),               \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type)
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
+#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type),               \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type)
+#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
+GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)
+#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)
+
+GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT),
+GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES),
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE),
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL),
+GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT),
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
+GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
+#if defined(TARGET_PPC64)
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B),
+GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B),
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B),
+#endif
+GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT),
+GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT),
+GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT),
+
+#undef GEN_LD
+#undef GEN_LDU
+#undef GEN_LDUX
+#undef GEN_LDX
+#undef GEN_LDS
+#define GEN_LD(name, ldop, opc, type)                                         \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDU(name, ldop, opc, type)                                        \
+GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
+GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_LDS(name, ldop, op, type)                                         \
+GEN_LD(name, ldop, op | 0x20, type)                                           \
+GEN_LDU(name, ldop, op | 0x21, type)                                          \
+GEN_LDUX(name, ldop, 0x17, op | 0x01, type)                                   \
+GEN_LDX(name, ldop, 0x17, op | 0x00, type)
+
+GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER)
+GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER)
+GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER)
+GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER)
+#if defined(TARGET_PPC64)
+GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B)
+GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B)
+GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B)
+GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B)
+#endif
+GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
+GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
+
+#undef GEN_ST
+#undef GEN_STU
+#undef GEN_STUX
+#undef GEN_STX
+#undef GEN_STS
+#define GEN_ST(name, stop, opc, type)                                         \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STU(name, stop, opc, type)                                        \
+GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STUX(name, stop, opc2, opc3, type)                                \
+GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_STX(name, stop, opc2, opc3, type)                                 \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_STS(name, stop, op, type)                                         \
+GEN_ST(name, stop, op | 0x20, type)                                           \
+GEN_STU(name, stop, op | 0x21, type)                                          \
+GEN_STUX(name, stop, 0x17, op | 0x01, type)                                   \
+GEN_STX(name, stop, 0x17, op | 0x00, type)
+
+GEN_STS(stb, st8, 0x06, PPC_INTEGER)
+GEN_STS(sth, st16, 0x0C, PPC_INTEGER)
+GEN_STS(stw, st32, 0x04, PPC_INTEGER)
+#if defined(TARGET_PPC64)
+GEN_STUX(std, st64, 0x15, 0x05, PPC_64B)
+GEN_STX(std, st64, 0x15, 0x04, PPC_64B)
+#endif
+GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
+GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
+
+#undef GEN_LDF
+#undef GEN_LDUF
+#undef GEN_LDUXF
+#undef GEN_LDXF
+#undef GEN_LDFS
+#define GEN_LDF(name, ldop, opc, type)                                        \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDUF(name, ldop, opc, type)                                       \
+GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDUXF(name, ldop, opc, type)                                      \
+GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
+#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_LDFS(name, ldop, op, type)                                        \
+GEN_LDF(name, ldop, op | 0x20, type)                                          \
+GEN_LDUF(name, ldop, op | 0x21, type)                                         \
+GEN_LDUXF(name, ldop, op | 0x01, type)                                        \
+GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
+
+GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
+GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
+
+#undef GEN_STF
+#undef GEN_STUF
+#undef GEN_STUXF
+#undef GEN_STXF
+#undef GEN_STFS
+#define GEN_STF(name, stop, opc, type)                                        \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STUF(name, stop, opc, type)                                       \
+GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STUXF(name, stop, opc, type)                                      \
+GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
+#define GEN_STXF(name, stop, opc2, opc3, type)                                \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_STFS(name, stop, op, type)                                        \
+GEN_STF(name, stop, op | 0x20, type)                                          \
+GEN_STUF(name, stop, op | 0x21, type)                                         \
+GEN_STUXF(name, stop, op | 0x01, type)                                        \
+GEN_STXF(name, stop, 0x17, op | 0x00, type)
+
+GEN_STFS(stfd, st64, 0x16, PPC_FLOAT)
+GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT)
+GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
+
+#undef GEN_CRLOGIC
+#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
+GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)
+GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08),
+GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04),
+GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09),
+GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07),
+GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01),
+GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E),
+GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D),
+GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06),
+
+#undef GEN_MAC_HANDLER
+#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05),
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15),
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07),
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17),
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06),
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16),
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04),
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14),
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01),
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11),
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03),
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13),
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02),
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12),
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00),
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10),
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D),
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D),
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F),
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F),
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C),
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C),
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E),
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E),
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05),
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15),
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07),
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17),
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01),
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11),
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03),
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13),
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D),
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D),
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F),
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F),
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05),
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04),
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01),
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00),
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D),
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C),
+
+#undef GEN_VR_LDX
+#undef GEN_VR_STX
+#undef GEN_VR_LVE
+#undef GEN_VR_STVE
+#define GEN_VR_LDX(name, opc2, opc3)                                          \
+GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_STX(name, opc2, opc3)                                          \
+GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_LVE(name, opc2, opc3)                                    \
+    GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_STVE(name, opc2, opc3)                                   \
+    GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+GEN_VR_LDX(lvx, 0x07, 0x03),
+GEN_VR_LDX(lvxl, 0x07, 0x0B),
+GEN_VR_LVE(bx, 0x07, 0x00),
+GEN_VR_LVE(hx, 0x07, 0x01),
+GEN_VR_LVE(wx, 0x07, 0x02),
+GEN_VR_STX(svx, 0x07, 0x07),
+GEN_VR_STX(svxl, 0x07, 0x0F),
+GEN_VR_STVE(bx, 0x07, 0x04),
+GEN_VR_STVE(hx, 0x07, 0x05),
+GEN_VR_STVE(wx, 0x07, 0x06),
+
+#undef GEN_VX_LOGICAL
+#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
+GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
+GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
+GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
+GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
+
+#undef GEN_VXFORM
+#define GEN_VXFORM(name, opc2, opc3)                                    \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VXFORM(vaddubm, 0, 0),
+GEN_VXFORM(vadduhm, 0, 1),
+GEN_VXFORM(vadduwm, 0, 2),
+GEN_VXFORM(vsububm, 0, 16),
+GEN_VXFORM(vsubuhm, 0, 17),
+GEN_VXFORM(vsubuwm, 0, 18),
+GEN_VXFORM(vmaxub, 1, 0),
+GEN_VXFORM(vmaxuh, 1, 1),
+GEN_VXFORM(vmaxuw, 1, 2),
+GEN_VXFORM(vmaxsb, 1, 4),
+GEN_VXFORM(vmaxsh, 1, 5),
+GEN_VXFORM(vmaxsw, 1, 6),
+GEN_VXFORM(vminub, 1, 8),
+GEN_VXFORM(vminuh, 1, 9),
+GEN_VXFORM(vminuw, 1, 10),
+GEN_VXFORM(vminsb, 1, 12),
+GEN_VXFORM(vminsh, 1, 13),
+GEN_VXFORM(vminsw, 1, 14),
+GEN_VXFORM(vavgub, 1, 16),
+GEN_VXFORM(vavguh, 1, 17),
+GEN_VXFORM(vavguw, 1, 18),
+GEN_VXFORM(vavgsb, 1, 20),
+GEN_VXFORM(vavgsh, 1, 21),
+GEN_VXFORM(vavgsw, 1, 22),
+GEN_VXFORM(vmrghb, 6, 0),
+GEN_VXFORM(vmrghh, 6, 1),
+GEN_VXFORM(vmrghw, 6, 2),
+GEN_VXFORM(vmrglb, 6, 4),
+GEN_VXFORM(vmrglh, 6, 5),
+GEN_VXFORM(vmrglw, 6, 6),
+GEN_VXFORM(vmuloub, 4, 0),
+GEN_VXFORM(vmulouh, 4, 1),
+GEN_VXFORM(vmulosb, 4, 4),
+GEN_VXFORM(vmulosh, 4, 5),
+GEN_VXFORM(vmuleub, 4, 8),
+GEN_VXFORM(vmuleuh, 4, 9),
+GEN_VXFORM(vmulesb, 4, 12),
+GEN_VXFORM(vmulesh, 4, 13),
+GEN_VXFORM(vslb, 2, 4),
+GEN_VXFORM(vslh, 2, 5),
+GEN_VXFORM(vslw, 2, 6),
+GEN_VXFORM(vsrb, 2, 8),
+GEN_VXFORM(vsrh, 2, 9),
+GEN_VXFORM(vsrw, 2, 10),
+GEN_VXFORM(vsrab, 2, 12),
+GEN_VXFORM(vsrah, 2, 13),
+GEN_VXFORM(vsraw, 2, 14),
+GEN_VXFORM(vslo, 6, 16),
+GEN_VXFORM(vsro, 6, 17),
+GEN_VXFORM(vaddcuw, 0, 6),
+GEN_VXFORM(vsubcuw, 0, 22),
+GEN_VXFORM(vaddubs, 0, 8),
+GEN_VXFORM(vadduhs, 0, 9),
+GEN_VXFORM(vadduws, 0, 10),
+GEN_VXFORM(vaddsbs, 0, 12),
+GEN_VXFORM(vaddshs, 0, 13),
+GEN_VXFORM(vaddsws, 0, 14),
+GEN_VXFORM(vsububs, 0, 24),
+GEN_VXFORM(vsubuhs, 0, 25),
+GEN_VXFORM(vsubuws, 0, 26),
+GEN_VXFORM(vsubsbs, 0, 28),
+GEN_VXFORM(vsubshs, 0, 29),
+GEN_VXFORM(vsubsws, 0, 30),
+GEN_VXFORM(vrlb, 2, 0),
+GEN_VXFORM(vrlh, 2, 1),
+GEN_VXFORM(vrlw, 2, 2),
+GEN_VXFORM(vsl, 2, 7),
+GEN_VXFORM(vsr, 2, 11),
+GEN_VXFORM(vpkuhum, 7, 0),
+GEN_VXFORM(vpkuwum, 7, 1),
+GEN_VXFORM(vpkuhus, 7, 2),
+GEN_VXFORM(vpkuwus, 7, 3),
+GEN_VXFORM(vpkshus, 7, 4),
+GEN_VXFORM(vpkswus, 7, 5),
+GEN_VXFORM(vpkshss, 7, 6),
+GEN_VXFORM(vpkswss, 7, 7),
+GEN_VXFORM(vpkpx, 7, 12),
+GEN_VXFORM(vsum4ubs, 4, 24),
+GEN_VXFORM(vsum4sbs, 4, 28),
+GEN_VXFORM(vsum4shs, 4, 25),
+GEN_VXFORM(vsum2sws, 4, 26),
+GEN_VXFORM(vsumsws, 4, 30),
+GEN_VXFORM(vaddfp, 5, 0),
+GEN_VXFORM(vsubfp, 5, 1),
+GEN_VXFORM(vmaxfp, 5, 16),
+GEN_VXFORM(vminfp, 5, 17),
+
+#undef GEN_VXRFORM1
+#undef GEN_VXRFORM
+#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
+    GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC),
+#define GEN_VXRFORM(name, opc2, opc3)                                \
+    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
+    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
+GEN_VXRFORM(vcmpequb, 3, 0)
+GEN_VXRFORM(vcmpequh, 3, 1)
+GEN_VXRFORM(vcmpequw, 3, 2)
+GEN_VXRFORM(vcmpgtsb, 3, 12)
+GEN_VXRFORM(vcmpgtsh, 3, 13)
+GEN_VXRFORM(vcmpgtsw, 3, 14)
+GEN_VXRFORM(vcmpgtub, 3, 8)
+GEN_VXRFORM(vcmpgtuh, 3, 9)
+GEN_VXRFORM(vcmpgtuw, 3, 10)
+GEN_VXRFORM(vcmpeqfp, 3, 3)
+GEN_VXRFORM(vcmpgefp, 3, 7)
+GEN_VXRFORM(vcmpgtfp, 3, 11)
+GEN_VXRFORM(vcmpbfp, 3, 15)
+
+#undef GEN_VXFORM_SIMM
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VXFORM_SIMM(vspltisb, 6, 12),
+GEN_VXFORM_SIMM(vspltish, 6, 13),
+GEN_VXFORM_SIMM(vspltisw, 6, 14),
+
+#undef GEN_VXFORM_NOA
+#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)
+GEN_VXFORM_NOA(vupkhsb, 7, 8),
+GEN_VXFORM_NOA(vupkhsh, 7, 9),
+GEN_VXFORM_NOA(vupklsb, 7, 10),
+GEN_VXFORM_NOA(vupklsh, 7, 11),
+GEN_VXFORM_NOA(vupkhpx, 7, 13),
+GEN_VXFORM_NOA(vupklpx, 7, 15),
+GEN_VXFORM_NOA(vrefp, 5, 4),
+GEN_VXFORM_NOA(vrsqrtefp, 5, 5),
+GEN_VXFORM_NOA(vexptefp, 5, 6),
+GEN_VXFORM_NOA(vlogefp, 5, 7),
+GEN_VXFORM_NOA(vrfim, 5, 8),
+GEN_VXFORM_NOA(vrfin, 5, 9),
+GEN_VXFORM_NOA(vrfip, 5, 10),
+GEN_VXFORM_NOA(vrfiz, 5, 11),
+
+#undef GEN_VXFORM_UIMM
+#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VXFORM_UIMM(vspltb, 6, 8),
+GEN_VXFORM_UIMM(vsplth, 6, 9),
+GEN_VXFORM_UIMM(vspltw, 6, 10),
+GEN_VXFORM_UIMM(vcfux, 5, 12),
+GEN_VXFORM_UIMM(vcfsx, 5, 13),
+GEN_VXFORM_UIMM(vctuxs, 5, 14),
+GEN_VXFORM_UIMM(vctsxs, 5, 15),
+
+#undef GEN_VAFORM_PAIRED
+#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
+    GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC)
+GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16),
+GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18),
+GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19),
+GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20),
+GEN_VAFORM_PAIRED(vsel, vperm, 21),
+GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23),
+
+#undef GEN_SPE
+#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
+GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)
+GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE),
+GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE),
+GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE),
+GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evmra,          speundef,      0x02, 0x13, 0x0000F800, PPC_SPE),
+GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE),
+GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE),
+GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE),
+
+GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE),
+
+GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE),
+
+GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE),
+GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE),
+GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE),
+
+#undef GEN_SPEOP_LDST
+#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
+GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)
+GEN_SPEOP_LDST(evldd, 0x00, 3),
+GEN_SPEOP_LDST(evldw, 0x01, 3),
+GEN_SPEOP_LDST(evldh, 0x02, 3),
+GEN_SPEOP_LDST(evlhhesplat, 0x04, 1),
+GEN_SPEOP_LDST(evlhhousplat, 0x06, 1),
+GEN_SPEOP_LDST(evlhhossplat, 0x07, 1),
+GEN_SPEOP_LDST(evlwhe, 0x08, 2),
+GEN_SPEOP_LDST(evlwhou, 0x0A, 2),
+GEN_SPEOP_LDST(evlwhos, 0x0B, 2),
+GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2),
+GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2),
+
+GEN_SPEOP_LDST(evstdd, 0x10, 3),
+GEN_SPEOP_LDST(evstdw, 0x11, 3),
+GEN_SPEOP_LDST(evstdh, 0x12, 3),
+GEN_SPEOP_LDST(evstwhe, 0x18, 2),
+GEN_SPEOP_LDST(evstwho, 0x1A, 2),
+GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
+GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
+};
+
+#include "translate_init.c"
+#include "helper_regs.h"
+
+/*****************************************************************************/
+/* Misc PowerPC helpers */
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                     int flags)
+{
+#define RGPL  4
+#define RFPL  4
+
+    int i;
+
+    cpu_fprintf(f, "NIP " TARGET_FMT_lx "   LR " TARGET_FMT_lx " CTR "
+                TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
+                env->nip, env->lr, env->ctr, env->xer);
+    cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx "  HF "
+                TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0],
+                env->hflags, env->mmu_idx);
+#if !defined(NO_TIMER_DUMP)
+    cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
+#if !defined(CONFIG_USER_ONLY)
+                " DECR %08" PRIu32
+#endif
+                "\n",
+                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+                , cpu_ppc_load_decr(env)
+#endif
+                );
+#endif
+    for (i = 0; i < 32; i++) {
+        if ((i & (RGPL - 1)) == 0)
+            cpu_fprintf(f, "GPR%02d", i);
+        cpu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i));
+        if ((i & (RGPL - 1)) == (RGPL - 1))
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "CR ");
+    for (i = 0; i < 8; i++)
+        cpu_fprintf(f, "%01x", env->crf[i]);
+    cpu_fprintf(f, "  [");
+    for (i = 0; i < 8; i++) {
+        char a = '-';
+        if (env->crf[i] & 0x08)
+            a = 'L';
+        else if (env->crf[i] & 0x04)
+            a = 'G';
+        else if (env->crf[i] & 0x02)
+            a = 'E';
+        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
+    }
+    cpu_fprintf(f, " ]             RES " TARGET_FMT_lx "\n",
+                env->reserve_addr);
+    for (i = 0; i < 32; i++) {
+        if ((i & (RFPL - 1)) == 0)
+            cpu_fprintf(f, "FPR%02d", i);
+        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
+        if ((i & (RFPL - 1)) == (RFPL - 1))
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
+#if !defined(CONFIG_USER_ONLY)
+    cpu_fprintf(f, " SRR0 " TARGET_FMT_lx "  SRR1 " TARGET_FMT_lx
+                   "    PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
+                env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+                env->spr[SPR_PVR], env->spr[SPR_VRSAVE]);
+
+    cpu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx
+                   "  SPRG2 " TARGET_FMT_lx "  SPRG3 " TARGET_FMT_lx "\n",
+                env->spr[SPR_SPRG0], env->spr[SPR_SPRG1],
+                env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]);
+
+    cpu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx
+                   "  SPRG6 " TARGET_FMT_lx "  SPRG7 " TARGET_FMT_lx "\n",
+                env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
+                env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
+
+    if (env->excp_model == POWERPC_EXCP_BOOKE) {
+        cpu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
+                       " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
+                    env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
+
+        cpu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
+                       "    ESR " TARGET_FMT_lx "   DEAR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR],
+                    env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
+
+        cpu_fprintf(f, "  PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx
+                       "   IVPR " TARGET_FMT_lx "   EPCR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR],
+                    env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]);
+
+        cpu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx
+                       "    EPR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8],
+                    env->spr[SPR_BOOKE_EPR]);
+
+        /* FSL-specific */
+        cpu_fprintf(f, " MCAR " TARGET_FMT_lx "  PID1 " TARGET_FMT_lx
+                       "   PID2 " TARGET_FMT_lx "    SVR " TARGET_FMT_lx "\n",
+                    env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1],
+                    env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]);
+
+        /*
+         * IVORs are left out as they are large and do not change often --
+         * they can be read with "p $ivor0", "p $ivor1", etc.
+         */
+    }
+
+    switch (env->mmu_model) {
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_601:
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_620:
+    case POWERPC_MMU_64B:
+#endif
+        cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
+        break;
+    case POWERPC_MMU_BOOKE206:
+        cpu_fprintf(f, " MAS0 " TARGET_FMT_lx "  MAS1 " TARGET_FMT_lx
+                       "   MAS2 " TARGET_FMT_lx "   MAS3 " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],
+                    env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]);
+
+        cpu_fprintf(f, " MAS4 " TARGET_FMT_lx "  MAS6 " TARGET_FMT_lx
+                       "   MAS7 " TARGET_FMT_lx "    PID " TARGET_FMT_lx "\n",
+                    env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6],
+                    env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]);
+
+        cpu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx
+                       " TLB1CFG " TARGET_FMT_lx "\n",
+                    env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG],
+                    env->spr[SPR_BOOKE_TLB1CFG]);
+        break;
+    default:
+        break;
+    }
+#endif
+
+#undef RGPL
+#undef RFPL
+}
+
+void cpu_dump_statistics (CPUState *env, FILE*f, fprintf_function cpu_fprintf,
+                          int flags)
+{
+#if defined(DO_PPC_STATISTICS)
+    opc_handler_t **t1, **t2, **t3, *handler;
+    int op1, op2, op3;
+
+    t1 = env->opcodes;
+    for (op1 = 0; op1 < 64; op1++) {
+        handler = t1[op1];
+        if (is_indirect_opcode(handler)) {
+            t2 = ind_table(handler);
+            for (op2 = 0; op2 < 32; op2++) {
+                handler = t2[op2];
+                if (is_indirect_opcode(handler)) {
+                    t3 = ind_table(handler);
+                    for (op3 = 0; op3 < 32; op3++) {
+                        handler = t3[op3];
+                        if (handler->count == 0)
+                            continue;
+                        cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
+                                    "%016" PRIx64 " %" PRId64 "\n",
+                                    op1, op2, op3, op1, (op3 << 5) | op2,
+                                    handler->oname,
+                                    handler->count, handler->count);
+                    }
+                } else {
+                    if (handler->count == 0)
+                        continue;
+                    cpu_fprintf(f, "%02x %02x    (%02x %04d) %16s: "
+                                "%016" PRIx64 " %" PRId64 "\n",
+                                op1, op2, op1, op2, handler->oname,
+                                handler->count, handler->count);
+                }
+            }
+        } else {
+            if (handler->count == 0)
+                continue;
+            cpu_fprintf(f, "%02x       (%02x     ) %16s: %016" PRIx64
+                        " %" PRId64 "\n",
+                        op1, op1, handler->oname,
+                        handler->count, handler->count);
+        }
+    }
+#endif
+}
+
+/*****************************************************************************/
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext ctx, *ctxp = &ctx;
+    opc_handler_t **table, *handler;
+    target_ulong pc_start;
+    uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int j, lj = -1;
+    int num_insns;
+    int max_insns;
+
+    pc_start = tb->pc;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    ctx.nip = pc_start;
+    ctx.tb = tb;
+    ctx.exception = POWERPC_EXCP_NONE;
+    ctx.spr_cb = env->spr_cb;
+    ctx.mem_idx = env->mmu_idx;
+    ctx.access_type = -1;
+    ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
+#if defined(TARGET_PPC64)
+    ctx.sf_mode = msr_sf;
+#endif
+    ctx.fpu_enabled = msr_fp;
+    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
+        ctx.spe_enabled = msr_spe;
+    else
+        ctx.spe_enabled = 0;
+    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
+        ctx.altivec_enabled = msr_vr;
+    else
+        ctx.altivec_enabled = 0;
+    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
+        ctx.singlestep_enabled = CPU_SINGLE_STEP;
+    else
+        ctx.singlestep_enabled = 0;
+    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
+        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
+    if (unlikely(env->singlestep_enabled))
+        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
+#if defined (DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr_se = 1;
+#endif
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
+    /* Set env in case of segfault during code fetch */
+    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == ctx.nip) {
+                    gen_debug_exception(ctxp);
+                    break;
+                }
+            }
+        }
+        if (unlikely(search_pc)) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+            }
+            gen_opc_pc[lj] = ctx.nip;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        LOG_DISAS("----------------\n");
+        LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
+                  ctx.nip, ctx.mem_idx, (int)msr_ir);
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+        if (unlikely(ctx.le_mode)) {
+            ctx.opcode = bswap32(ldl_code(ctx.nip));
+        } else {
+            ctx.opcode = ldl_code(ctx.nip);
+        }
+        LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n",
+                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
+                    opc3(ctx.opcode), little_endian ? "little" : "big");
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+            tcg_gen_debug_insn_start(ctx.nip);
+        ctx.nip += 4;
+        table = env->opcodes;
+        num_insns++;
+        handler = table[opc1(ctx.opcode)];
+        if (is_indirect_opcode(handler)) {
+            table = ind_table(handler);
+            handler = table[opc2(ctx.opcode)];
+            if (is_indirect_opcode(handler)) {
+                table = ind_table(handler);
+                handler = table[opc3(ctx.opcode)];
+            }
+        }
+        /* Is opcode *REALLY* valid ? */
+        if (unlikely(handler->handler == &gen_invalid)) {
+            if (qemu_log_enabled()) {
+                qemu_log("invalid/unsupported opcode: "
+                         "%02x - %02x - %02x (%08x) " TARGET_FMT_lx " %d\n",
+                         opc1(ctx.opcode), opc2(ctx.opcode),
+                         opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
+            }
+        } else {
+            if (unlikely((ctx.opcode & handler->inval) != 0)) {
+                if (qemu_log_enabled()) {
+                    qemu_log("invalid bits: %08x for opcode: "
+                             "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n",
+                             ctx.opcode & handler->inval, opc1(ctx.opcode),
+                             opc2(ctx.opcode), opc3(ctx.opcode),
+                             ctx.opcode, ctx.nip - 4);
+                }
+                gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
+                break;
+            }
+        }
+        (*(handler->handler))(&ctx);
+#if defined(DO_PPC_STATISTICS)
+        handler->count++;
+#endif
+        /* Check trace mode exceptions */
+        if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP &&
+                     (ctx.nip <= 0x100 || ctx.nip > 0xF00) &&
+                     ctx.exception != POWERPC_SYSCALL &&
+                     ctx.exception != POWERPC_EXCP_TRAP &&
+                     ctx.exception != POWERPC_EXCP_BRANCH)) {
+            gen_exception(ctxp, POWERPC_EXCP_TRACE);
+        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+                            (env->singlestep_enabled) ||
+                            singlestep ||
+                            num_insns >= max_insns)) {
+            /* if we reach a page boundary or are single stepping, stop
+             * generation
+             */
+            break;
+        }
+    }
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (ctx.exception == POWERPC_EXCP_NONE) {
+        gen_goto_tb(&ctx, 0, ctx.nip);
+    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
+        if (unlikely(env->singlestep_enabled)) {
+            gen_debug_exception(ctxp);
+        }
+        /* Generate the return instruction */
+        tcg_gen_exit_tb(0);
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (unlikely(search_pc)) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = ctx.nip - pc_start;
+        tb->icount = num_insns;
+    }
+#if defined(DEBUG_DISAS)
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        int flags;
+        flags = env->bfd_mach;
+        flags |= ctx.le_mode << 16;
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, ctx.nip - pc_start, flags);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->nip = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/target-ppc/translate_init.c b/qemu-0.15.x/target-ppc/translate_init.c
new file mode 100644
index 0000000..f542b8e
--- /dev/null
+++ b/qemu-0.15.x/target-ppc/translate_init.c
@@ -0,0 +1,10067 @@
+/*
+ *  PowerPC CPU initialization for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A lot of PowerPC definition have been included here.
+ * Most of them are not usable for now but have been kept
+ * inside "#if defined(TODO) ... #endif" statements to make tests easier.
+ */
+
+#include "dis-asm.h"
+#include "gdbstub.h"
+
+//#define PPC_DUMP_CPU
+//#define PPC_DEBUG_SPR
+//#define PPC_DUMP_SPR_ACCESSES
+#if defined(CONFIG_USER_ONLY)
+#define TODO_USER_ONLY 1
+#endif
+
+struct ppc_def_t {
+    const char *name;
+    uint32_t pvr;
+    uint32_t svr;
+    uint64_t insns_flags;
+    uint64_t insns_flags2;
+    uint64_t msr_mask;
+    powerpc_mmu_t   mmu_model;
+    powerpc_excp_t  excp_model;
+    powerpc_input_t bus_model;
+    uint32_t flags;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
+    int  (*check_pow)(CPUPPCState *env);
+};
+
+/* For user-mode emulation, we don't emulate any IRQ controller */
+#if defined(CONFIG_USER_ONLY)
+#define PPC_IRQ_INIT_FN(name)                                                 \
+static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env)         \
+{                                                                             \
+}
+#else
+#define PPC_IRQ_INIT_FN(name)                                                 \
+void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
+#endif
+
+PPC_IRQ_INIT_FN(40x);
+PPC_IRQ_INIT_FN(6xx);
+PPC_IRQ_INIT_FN(970);
+PPC_IRQ_INIT_FN(POWER7);
+PPC_IRQ_INIT_FN(e500);
+
+/* Generic callbacks:
+ * do nothing but store/retrieve spr value
+ */
+static void spr_read_generic (void *opaque, int gprn, int sprn)
+{
+    gen_load_spr(cpu_gpr[gprn], sprn);
+#ifdef PPC_DUMP_SPR_ACCESSES
+    {
+        TCGv_i32 t0 = tcg_const_i32(sprn);
+        gen_helper_load_dump_spr(t0);
+        tcg_temp_free_i32(t0);
+    }
+#endif
+}
+
+static void spr_write_generic (void *opaque, int sprn, int gprn)
+{
+    gen_store_spr(sprn, cpu_gpr[gprn]);
+#ifdef PPC_DUMP_SPR_ACCESSES
+    {
+        TCGv_i32 t0 = tcg_const_i32(sprn);
+        gen_helper_store_dump_spr(t0);
+        tcg_temp_free_i32(t0);
+    }
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_clear (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    gen_load_spr(t0, sprn);
+    tcg_gen_neg_tl(t1, cpu_gpr[gprn]);
+    tcg_gen_and_tl(t0, t0, t1);
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+#endif
+
+/* SPR common to all PowerPC */
+/* XER */
+static void spr_read_xer (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_mov_tl(cpu_gpr[gprn], cpu_xer);
+}
+
+static void spr_write_xer (void *opaque, int sprn, int gprn)
+{
+    tcg_gen_mov_tl(cpu_xer, cpu_gpr[gprn]);
+}
+
+/* LR */
+static void spr_read_lr (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr);
+}
+
+static void spr_write_lr (void *opaque, int sprn, int gprn)
+{
+    tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
+}
+
+/* CTR */
+static void spr_read_ctr (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr);
+}
+
+static void spr_write_ctr (void *opaque, int sprn, int gprn)
+{
+    tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]);
+}
+
+/* User read access to SPR */
+/* USPRx */
+/* UMMCRx */
+/* UPMCx */
+/* USIA */
+/* UDECR */
+static void spr_read_ureg (void *opaque, int gprn, int sprn)
+{
+    gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
+}
+
+/* SPR common to all non-embedded PowerPC */
+/* DECR */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_decr (void *opaque, int gprn, int sprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_load_decr(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+
+static void spr_write_decr (void *opaque, int sprn, int gprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_store_decr(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+#endif
+
+/* SPR common to all non-embedded PowerPC, except 601 */
+/* Time base */
+static void spr_read_tbl (void *opaque, int gprn, int sprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_load_tbl(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+
+static void spr_read_tbu (void *opaque, int gprn, int sprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_load_tbu(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+
+__attribute__ (( unused ))
+static void spr_read_atbl (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_atbl(cpu_gpr[gprn]);
+}
+
+__attribute__ (( unused ))
+static void spr_read_atbu (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_atbu(cpu_gpr[gprn]);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_tbl (void *opaque, int sprn, int gprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_store_tbl(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+
+static void spr_write_tbu (void *opaque, int sprn, int gprn)
+{
+    if (use_icount) {
+        gen_io_start();
+    }
+    gen_helper_store_tbu(cpu_gpr[gprn]);
+    if (use_icount) {
+        gen_io_end();
+        gen_stop_exception(opaque);
+    }
+}
+
+__attribute__ (( unused ))
+static void spr_write_atbl (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_atbl(cpu_gpr[gprn]);
+}
+
+__attribute__ (( unused ))
+static void spr_write_atbu (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_atbu(cpu_gpr[gprn]);
+}
+
+#if defined(TARGET_PPC64)
+__attribute__ (( unused ))
+static void spr_read_purr (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_purr(cpu_gpr[gprn]);
+}
+#endif
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* IBAT0U...IBAT0U */
+/* IBAT0L...IBAT7L */
+static void spr_read_ibat (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
+}
+
+static void spr_read_ibat_h (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, IBAT[sprn & 1][(sprn - SPR_IBAT4U) / 2]));
+}
+
+static void spr_write_ibatu (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+    gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_ibatu_h (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4);
+    gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_ibatl (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
+    gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_ibatl_h (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4);
+    gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+/* DBAT0U...DBAT7U */
+/* DBAT0L...DBAT7L */
+static void spr_read_dbat (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2]));
+}
+
+static void spr_read_dbat_h (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4]));
+}
+
+static void spr_write_dbatu (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
+    gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_dbatu_h (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
+    gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_dbatl (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
+    gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
+    gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+/* SDR1 */
+static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_sdr1(cpu_gpr[gprn]);
+}
+
+/* 64 bits PowerPC specific SPRs */
+/* ASR */
+#if defined(TARGET_PPC64)
+static void spr_read_hior (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, excp_prefix));
+}
+
+static void spr_write_hior (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL);
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_prefix));
+    tcg_temp_free(t0);
+}
+
+static void spr_read_asr (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, asr));
+}
+
+static void spr_write_asr (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_asr(cpu_gpr[gprn]);
+}
+#endif
+#endif
+
+/* PowerPC 601 specific registers */
+/* RTC */
+static void spr_read_601_rtcl (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_601_rtcl(cpu_gpr[gprn]);
+}
+
+static void spr_read_601_rtcu (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_601_rtcu(cpu_gpr[gprn]);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_601_rtcu (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_601_rtcu(cpu_gpr[gprn]);
+}
+
+static void spr_write_601_rtcl (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_601_rtcl(cpu_gpr[gprn]);
+}
+
+static void spr_write_hid0_601 (void *opaque, int sprn, int gprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_helper_store_hid0_601(cpu_gpr[gprn]);
+    /* Must stop the translation as endianness may have changed */
+    gen_stop_exception(ctx);
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_601_ubat (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
+}
+
+static void spr_write_601_ubatu (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+    gen_helper_store_601_batl(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_601_ubatl (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+    gen_helper_store_601_batu(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_40x_pit (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_40x_pit(cpu_gpr[gprn]);
+}
+
+static void spr_write_40x_pit (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_40x_pit(cpu_gpr[gprn]);
+}
+
+static void spr_write_40x_dbcr0 (void *opaque, int sprn, int gprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_helper_store_40x_dbcr0(cpu_gpr[gprn]);
+    /* We must stop translation as we may have rebooted */
+    gen_stop_exception(ctx);
+}
+
+static void spr_write_40x_sler (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_40x_sler(cpu_gpr[gprn]);
+}
+
+static void spr_write_booke_tcr (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_booke_tcr(cpu_gpr[gprn]);
+}
+
+static void spr_write_booke_tsr (void *opaque, int sprn, int gprn)
+{
+    gen_helper_store_booke_tsr(cpu_gpr[gprn]);
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_403_pbr (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, pb[sprn - SPR_403_PBL1]));
+}
+
+static void spr_write_403_pbr (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1);
+    gen_helper_store_403_pbr(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_pir (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF);
+    gen_store_spr(SPR_PIR, t0);
+    tcg_temp_free(t0);
+}
+#endif
+
+/* SPE specific registers */
+static void spr_read_spefscr (void *opaque, int gprn, int sprn)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUState, spe_fscr));
+    tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_spefscr (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]);
+    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, spe_fscr));
+    tcg_temp_free_i32(t0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Callback used to write the exception vector base */
+static void spr_write_excp_prefix (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivpr_mask));
+    tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_prefix));
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
+}
+
+static void spr_write_excp_vector (void *opaque, int sprn, int gprn)
+{
+    DisasContext *ctx = opaque;
+
+    if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
+        tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+        tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR0]));
+        gen_store_spr(sprn, t0);
+        tcg_temp_free(t0);
+    } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
+        tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+        tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR32 + 32]));
+        gen_store_spr(sprn, t0);
+        tcg_temp_free(t0);
+    } else {
+        printf("Trying to write an unknown exception vector %d %03x\n",
+               sprn, sprn);
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+    }
+}
+#endif
+
+static inline void vscr_init (CPUPPCState *env, uint32_t val)
+{
+    env->vscr = val;
+    /* Altivec always uses round-to-nearest */
+    set_float_rounding_mode(float_round_nearest_even, &env->vec_status);
+    set_flush_to_zero(vscr_nj, &env->vec_status);
+}
+
+#if defined(CONFIG_USER_ONLY)
+#define spr_register(env, num, name, uea_read, uea_write,                     \
+                     oea_read, oea_write, initial_value)                      \
+do {                                                                          \
+     _spr_register(env, num, name, uea_read, uea_write, initial_value);       \
+} while (0)
+static inline void _spr_register (CPUPPCState *env, int num,
+                                  const char *name,
+                                  void (*uea_read)(void *opaque, int gprn, int sprn),
+                                  void (*uea_write)(void *opaque, int sprn, int gprn),
+                                  target_ulong initial_value)
+#else
+static inline void spr_register (CPUPPCState *env, int num,
+                                 const char *name,
+                                 void (*uea_read)(void *opaque, int gprn, int sprn),
+                                 void (*uea_write)(void *opaque, int sprn, int gprn),
+                                 void (*oea_read)(void *opaque, int gprn, int sprn),
+                                 void (*oea_write)(void *opaque, int sprn, int gprn),
+                                 target_ulong initial_value)
+#endif
+{
+    ppc_spr_t *spr;
+
+    spr = &env->spr_cb[num];
+    if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
+#if !defined(CONFIG_USER_ONLY)
+        spr->oea_read != NULL || spr->oea_write != NULL ||
+#endif
+        spr->uea_read != NULL || spr->uea_write != NULL) {
+        printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
+        exit(1);
+    }
+#if defined(PPC_DEBUG_SPR)
+    printf("*** register spr %d (%03x) %s val " TARGET_FMT_lx "\n", num, num,
+           name, initial_value);
+#endif
+    spr->name = name;
+    spr->uea_read = uea_read;
+    spr->uea_write = uea_write;
+#if !defined(CONFIG_USER_ONLY)
+    spr->oea_read = oea_read;
+    spr->oea_write = oea_write;
+#endif
+    env->spr[num] = initial_value;
+}
+
+/* Generic PowerPC SPRs */
+static void gen_spr_generic (CPUPPCState *env)
+{
+    /* Integer processing */
+    spr_register(env, SPR_XER, "XER",
+                 &spr_read_xer, &spr_write_xer,
+                 &spr_read_xer, &spr_write_xer,
+                 0x00000000);
+    /* Branch contol */
+    spr_register(env, SPR_LR, "LR",
+                 &spr_read_lr, &spr_write_lr,
+                 &spr_read_lr, &spr_write_lr,
+                 0x00000000);
+    spr_register(env, SPR_CTR, "CTR",
+                 &spr_read_ctr, &spr_write_ctr,
+                 &spr_read_ctr, &spr_write_ctr,
+                 0x00000000);
+    /* Interrupt processing */
+    spr_register(env, SPR_SRR0, "SRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SRR1, "SRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Processor control */
+    spr_register(env, SPR_SPRG0, "SPRG0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG1, "SPRG1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG2, "SPRG2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG3, "SPRG3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR common to all non-embedded PowerPC, including 601 */
+static void gen_spr_ne_601 (CPUPPCState *env)
+{
+    /* Exception processing */
+    spr_register(env, SPR_DSISR, "DSISR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_DAR, "DAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    /* Memory management */
+    spr_register(env, SPR_SDR1, "SDR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_sdr1,
+                 0x00000000);
+}
+
+/* BATs 0-3 */
+static void gen_low_BATs (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    spr_register(env, SPR_IBAT0U, "IBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT0L, "IBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1U, "IBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1L, "IBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2U, "IBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2L, "IBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3U, "IBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3L, "IBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT0U, "DBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT0L, "DBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT1U, "DBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT1L, "DBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT2U, "DBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT2L, "DBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT3U, "DBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT3L, "DBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    env->nb_BATs += 4;
+#endif
+}
+
+/* BATs 4-7 */
+static void gen_high_BATs (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    spr_register(env, SPR_IBAT4U, "IBAT4U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT4L, "IBAT4L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT5U, "IBAT5U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT5L, "IBAT5L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT6U, "IBAT6U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT6L, "IBAT6L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT7U, "IBAT7U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT7L, "IBAT7L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT4U, "DBAT4U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT4L, "DBAT4L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT5U, "DBAT5U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT5L, "DBAT5L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT6U, "DBAT6U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT6L, "DBAT6L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT7U, "DBAT7U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT7L, "DBAT7L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    env->nb_BATs += 4;
+#endif
+}
+
+/* Generic PowerPC time base */
+static void gen_tbl (CPUPPCState *env)
+{
+    spr_register(env, SPR_VTBL,  "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_TBL,   "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, &spr_write_tbl,
+                 0x00000000);
+    spr_register(env, SPR_VTBU,  "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_TBU,   "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, &spr_write_tbu,
+                 0x00000000);
+}
+
+/* Softare table search registers */
+static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = nb_tlbs;
+    env->nb_ways = nb_ways;
+    env->id_tlbs = 1;
+    env->tlb_type = TLB_6XX;
+    spr_register(env, SPR_DMISS, "DMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_DCMP, "DCMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH1, "HASH1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH2, "HASH2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_IMISS, "IMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_ICMP, "ICMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_RPA, "RPA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#endif
+}
+
+/* SPR common to MPC755 and G2 */
+static void gen_spr_G2_755 (CPUPPCState *env)
+{
+    /* SGPRs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR common to all 7xx PowerPC implementations */
+static void gen_spr_7xx (CPUPPCState *env)
+{
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Cache management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTC, "ICTC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Performance monitors */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR0, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR1, "MMCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC1, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC2, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC3, "PMC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC4, "PMC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SIAR, "SIAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UMMCR0, "UMMCR0",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UMMCR1, "UMMCR1",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC1, "UPMC1",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC2, "UPMC2",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC3, "UPMC3",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC4, "UPMC4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_USIAR, "USIAR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_thrm (CPUPPCState *env)
+{
+    /* Thermal management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM1, "THRM1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM2, "THRM2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM3, "THRM3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 604 implementation */
+static void gen_spr_604 (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Performance counters */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR0, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC1, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC2, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SIAR, "SIAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SDA, "SDA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 603 implementation */
+static void gen_spr_603 (CPUPPCState *env)
+{
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC G2 implementation */
+static void gen_spr_G2 (CPUPPCState *env)
+{
+    /* Memory base address */
+    /* MBAR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MBAR, "MBAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Exception processing */
+    spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR2, "DABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR2, "IABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IBCR, "IBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DBCR, "DBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 602 implementation */
+static void gen_spr_602 (CPUPPCState *env)
+{
+    /* ESA registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SER, "SER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SEBR, "SEBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_ESASRR, "ESASRR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Floating point status */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SP, "SP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_LT, "LT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Watchdog timer */
+    /* XXX : not implemented */
+    spr_register(env, SPR_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Interrupt base */
+    spr_register(env, SPR_IBR, "IBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 601 implementation */
+static void gen_spr_601 (CPUPPCState *env)
+{
+    /* Multiplication/division register */
+    /* MQ */
+    spr_register(env, SPR_MQ, "MQ",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* RTC registers */
+    spr_register(env, SPR_601_RTCU, "RTCU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcu,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCU, "RTCU",
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_601_RTCL, "RTCL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcl,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCL, "RTCL",
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 0x00000000);
+    /* Timer */
+#if 0 /* ? */
+    spr_register(env, SPR_601_UDECR, "UDECR",
+                 &spr_read_decr, SPR_NOACCESS,
+                 &spr_read_decr, SPR_NOACCESS,
+                 0x00000000);
+#endif
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    spr_register(env, SPR_IBAT0U, "IBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT0L, "IBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1U, "IBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1L, "IBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2U, "IBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2L, "IBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3U, "IBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3L, "IBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    env->nb_BATs = 4;
+#endif
+}
+
+static void gen_spr_74xx (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR2, "MMCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UMMCR2, "UMMCR2",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX: not implemented */
+    spr_register(env, SPR_BAMR, "BAMR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSCR0, "MSSCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Altivec */
+    spr_register(env, SPR_VRSAVE, "VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Not strictly an SPR */
+    vscr_init(env, 0x00010000);
+}
+
+static void gen_l3_ctrl (CPUPPCState *env)
+{
+    /* L3CR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3CR, "L3CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR0, "L3ITCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3PM */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3PM, "L3PM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = nb_tlbs;
+    env->nb_ways = nb_ways;
+    env->id_tlbs = 1;
+    env->tlb_type = TLB_6XX;
+    /* XXX : not implemented */
+    spr_register(env, SPR_PTEHI, "PTEHI",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PTELO, "PTELO",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_TLBMISS, "TLBMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256);
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
+}
+
+static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(sprn);
+    gen_helper_booke206_tlbflush(t0);
+    tcg_temp_free_i32(t0);
+}
+
+static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
+{
+    TCGv_i32 t0 = tcg_const_i32(sprn);
+    gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
+    tcg_temp_free_i32(t0);
+}
+#endif
+
+static void gen_spr_usprgh (CPUPPCState *env)
+{
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+}
+
+/* PowerPC BookE SPR */
+static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
+{
+    const char *ivor_names[64] = {
+        "IVOR0",  "IVOR1",  "IVOR2",  "IVOR3",
+        "IVOR4",  "IVOR5",  "IVOR6",  "IVOR7",
+        "IVOR8",  "IVOR9",  "IVOR10", "IVOR11",
+        "IVOR12", "IVOR13", "IVOR14", "IVOR15",
+        "IVOR16", "IVOR17", "IVOR18", "IVOR19",
+        "IVOR20", "IVOR21", "IVOR22", "IVOR23",
+        "IVOR24", "IVOR25", "IVOR26", "IVOR27",
+        "IVOR28", "IVOR29", "IVOR30", "IVOR31",
+        "IVOR32", "IVOR33", "IVOR34", "IVOR35",
+        "IVOR36", "IVOR37", "IVOR38", "IVOR39",
+        "IVOR40", "IVOR41", "IVOR42", "IVOR43",
+        "IVOR44", "IVOR45", "IVOR46", "IVOR47",
+        "IVOR48", "IVOR49", "IVOR50", "IVOR51",
+        "IVOR52", "IVOR53", "IVOR54", "IVOR55",
+        "IVOR56", "IVOR57", "IVOR58", "IVOR59",
+        "IVOR60", "IVOR61", "IVOR62", "IVOR63",
+    };
+#define SPR_BOOKE_IVORxx (-1)
+    int ivor_sprn[64] = {
+        SPR_BOOKE_IVOR0,  SPR_BOOKE_IVOR1,  SPR_BOOKE_IVOR2,  SPR_BOOKE_IVOR3,
+        SPR_BOOKE_IVOR4,  SPR_BOOKE_IVOR5,  SPR_BOOKE_IVOR6,  SPR_BOOKE_IVOR7,
+        SPR_BOOKE_IVOR8,  SPR_BOOKE_IVOR9,  SPR_BOOKE_IVOR10, SPR_BOOKE_IVOR11,
+        SPR_BOOKE_IVOR12, SPR_BOOKE_IVOR13, SPR_BOOKE_IVOR14, SPR_BOOKE_IVOR15,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35,
+        SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+    };
+    int i;
+
+    /* Interrupt processing */
+    spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR2, "DBCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVPR, "IVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_prefix,
+                 0x00000000);
+    /* Exception vectors */
+    for (i = 0; i < 64; i++) {
+        if (ivor_mask & (1ULL << i)) {
+            if (ivor_sprn[i] == SPR_BOOKE_IVORxx) {
+                fprintf(stderr, "ERROR: IVOR %d SPR is not defined\n", i);
+                exit(1);
+            }
+            spr_register(env, ivor_sprn[i], ivor_names[i],
+                         SPR_NOACCESS, SPR_NOACCESS,
+                         &spr_read_generic, &spr_write_excp_vector,
+                         0x00000000);
+        }
+    }
+    spr_register(env, SPR_BOOKE_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_pid,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DECAR, "DECAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
+                                   uint32_t maxsize, uint32_t flags,
+                                   uint32_t nentries)
+{
+    return (assoc << TLBnCFG_ASSOC_SHIFT) |
+           (minsize << TLBnCFG_MINSIZE_SHIFT) |
+           (maxsize << TLBnCFG_MAXSIZE_SHIFT) |
+           flags | nentries;
+}
+
+/* BookE 2.06 storage control registers */
+static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
+                              uint32_t *tlbncfg)
+{
+#if !defined(CONFIG_USER_ONLY)
+    const char *mas_names[8] = {
+        "MAS0", "MAS1", "MAS2", "MAS3", "MAS4", "MAS5", "MAS6", "MAS7",
+    };
+    int mas_sprn[8] = {
+        SPR_BOOKE_MAS0, SPR_BOOKE_MAS1, SPR_BOOKE_MAS2, SPR_BOOKE_MAS3,
+        SPR_BOOKE_MAS4, SPR_BOOKE_MAS5, SPR_BOOKE_MAS6, SPR_BOOKE_MAS7,
+    };
+    int i;
+
+    /* TLB assist registers */
+    /* XXX : not implemented */
+    for (i = 0; i < 8; i++) {
+        if (mas_mask & (1 << i)) {
+            spr_register(env, mas_sprn[i], mas_names[i],
+                         SPR_NOACCESS, SPR_NOACCESS,
+                         &spr_read_generic, &spr_write_generic,
+                         0x00000000);
+        }
+    }
+    if (env->nb_pids > 1) {
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_PID1, "PID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_booke_pid,
+                     0x00000000);
+    }
+    if (env->nb_pids > 2) {
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_PID2, "PID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_booke_pid,
+                     0x00000000);
+    }
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    switch (env->nb_ways) {
+    case 4:
+        spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     tlbncfg[3]);
+        /* Fallthru */
+    case 3:
+        spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     tlbncfg[2]);
+        /* Fallthru */
+    case 2:
+        spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     tlbncfg[1]);
+        /* Fallthru */
+    case 1:
+        spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     tlbncfg[0]);
+        /* Fallthru */
+    case 0:
+    default:
+        break;
+    }
+#endif
+
+    gen_spr_usprgh(env);
+}
+
+/* SPR specific to PowerPC 440 implementation */
+static void gen_spr_440 (CPUPPCState *env)
+{
+    /* Cache control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV0, "DNV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV1, "DNV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV2, "DNV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV3, "DNV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV0, "DTV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV1, "DTV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV2, "DTV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV3, "DTV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVLIM, "DVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV0, "INV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV1, "INV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV2, "INV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV3, "INV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV0, "ITV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV1, "ITV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV2, "ITV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV3, "ITV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVLIM, "IVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Cache debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DCDBTRH, "DCDBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DCDBTRL, "DCDBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBTRH, "ICDBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBTRL, "ICDBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DBDR, "DBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Processor control */
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_440_RSTCFG, "RSTCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Storage control */
+    spr_register(env, SPR_440_MMUCR, "MMUCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR shared between PowerPC 40x implementations */
+static void gen_spr_40x (CPUPPCState *env)
+{
+    /* Cache */
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCCR, "DCCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_ICCR, "ICCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Exception */
+    spr_register(env, SPR_40x_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_EVPR, "EVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_prefix,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR2, "SRR2",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR3, "SRR3",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timers */
+    spr_register(env, SPR_40x_PIT, "PIT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_40x_pit, &spr_write_40x_pit,
+                 0x00000000);
+    spr_register(env, SPR_40x_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_40x_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 405 implementation */
+static void gen_spr_405 (CPUPPCState *env)
+{
+    /* MMU */
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00700000);
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Storage control */
+    /* XXX: TODO: not implemented */
+    spr_register(env, SPR_405_SLER, "SLER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_sler,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_SU0R, "SU0R",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* SPRG */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    gen_spr_usprgh(env);
+}
+
+/* SPR shared between PowerPC 401 & 403 implementations */
+static void gen_spr_401_403 (CPUPPCState *env)
+{
+    /* Time base */
+    spr_register(env, SPR_403_VTBL,  "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBL,   "TBL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbl,
+                 0x00000000);
+    spr_register(env, SPR_403_VTBU,  "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBU,   "TBU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbu,
+                 0x00000000);
+    /* Debug */
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_403_CDBCR, "CDBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 401 implementation */
+static void gen_spr_401 (CPUPPCState *env)
+{
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Storage control */
+    /* XXX: TODO: not implemented */
+    spr_register(env, SPR_405_SLER, "SLER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_sler,
+                 0x00000000);
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_401x2 (CPUPPCState *env)
+{
+    gen_spr_401(env);
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 403 implementation */
+static void gen_spr_403 (CPUPPCState *env)
+{
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_403_real (CPUPPCState *env)
+{
+    spr_register(env, SPR_403_PBL1,  "PBL1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU1,  "PBU1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBL2,  "PBL2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU2,  "PBU2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+}
+
+static void gen_spr_403_mmu (CPUPPCState *env)
+{
+    /* MMU */
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC compression coprocessor extension */
+static void gen_spr_compress (CPUPPCState *env)
+{
+    /* XXX : not implemented */
+    spr_register(env, SPR_401_SKR, "SKR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+#if defined (TARGET_PPC64)
+/* SPR specific to PowerPC 620 */
+static void gen_spr_620 (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    spr_register(env, SPR_ASR, "ASR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_asr, &spr_write_asr,
+                 0x00000000);
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SIAR, "SIAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SDA, "SDA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMC1R, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_620_PMC1W, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                  SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMC2R, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_620_PMC2W, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                  SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_MMCR0R, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_620_MMCR0W, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                  SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if 0 // XXX: check this
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR0, "PMR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR1, "PMR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR2, "PMR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR3, "PMR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR4, "PMR4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR5, "PMR5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR6, "PMR6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR7, "PMR7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR8, "PMR8",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR9, "PMR9",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRA, "PMR10",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRB, "PMR11",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRC, "PMR12",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRD, "PMR13",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRE, "PMR14",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRF, "PMR15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#endif
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_BUSCSR, "BUSCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_L2SR, "L2SR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+#endif /* defined (TARGET_PPC64) */
+
+static void gen_spr_5xx_8xx (CPUPPCState *env)
+{
+    /* Exception processing */
+    spr_register(env, SPR_DSISR, "DSISR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_DAR, "DAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_EIE, "EIE",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_EID, "EID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_NRI, "NRI",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPA, "CMPA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPB, "CMPB",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPC, "CMPC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPD, "CMPD",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_ECR, "ECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_DER, "DER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_COUNTA, "COUNTA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_COUNTB, "COUNTB",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPE, "CMPE",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPF, "CMPF",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPG, "CMPG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_CMPH, "CMPH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_LCTRL1, "LCTRL1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_LCTRL2, "LCTRL2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_BAR, "BAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_DPDR, "DPDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_IMMR, "IMMR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_5xx (CPUPPCState *env)
+{
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_GRA, "MI_GRA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_GRA, "L2U_GRA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RPCU_BBCMCR, "L2U_BBCMCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_MCR, "L2U_MCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RBA0, "MI_RBA0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RBA1, "MI_RBA1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RBA2, "MI_RBA2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RBA3, "MI_RBA3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RBA0, "L2U_RBA0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RBA1, "L2U_RBA1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RBA2, "L2U_RBA2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RBA3, "L2U_RBA3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RA0, "MI_RA0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RA1, "MI_RA1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RA2, "MI_RA2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_MI_RA3, "MI_RA3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RA0, "L2U_RA0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RA1, "L2U_RA1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RA2, "L2U_RA2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_L2U_RA3, "L2U_RA3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_RCPU_FPECR, "FPECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_8xx (CPUPPCState *env)
+{
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_IC_CST, "IC_CST",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_IC_ADR, "IC_ADR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_IC_DAT, "IC_DAT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_DC_CST, "DC_CST",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_DC_ADR, "DC_ADR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_DC_DAT, "DC_DAT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_CTR, "MI_CTR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_AP, "MI_AP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_EPN, "MI_EPN",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_TWC, "MI_TWC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_RPN, "MI_RPN",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_DBCAM, "MI_DBCAM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_DBRAM0, "MI_DBRAM0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MI_DBRAM1, "MI_DBRAM1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_CTR, "MD_CTR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_CASID, "MD_CASID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_AP, "MD_AP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_EPN, "MD_EPN",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_TWB, "MD_TWB",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_TWC, "MD_TWC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_RPN, "MD_RPN",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_TW, "MD_TW",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_DBCAM, "MD_DBCAM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_DBRAM0, "MD_DBRAM0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MPC_MD_DBRAM1, "MD_DBRAM1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+// XXX: TODO
+/*
+ * AMR     => SPR 29 (Power 2.04)
+ * CTRL    => SPR 136 (Power 2.04)
+ * CTRL    => SPR 152 (Power 2.04)
+ * SCOMC   => SPR 276 (64 bits ?)
+ * SCOMD   => SPR 277 (64 bits ?)
+ * TBU40   => SPR 286 (Power 2.04 hypv)
+ * HSPRG0  => SPR 304 (Power 2.04 hypv)
+ * HSPRG1  => SPR 305 (Power 2.04 hypv)
+ * HDSISR  => SPR 306 (Power 2.04 hypv)
+ * HDAR    => SPR 307 (Power 2.04 hypv)
+ * PURR    => SPR 309 (Power 2.04 hypv)
+ * HDEC    => SPR 310 (Power 2.04 hypv)
+ * HIOR    => SPR 311 (hypv)
+ * RMOR    => SPR 312 (970)
+ * HRMOR   => SPR 313 (Power 2.04 hypv)
+ * HSRR0   => SPR 314 (Power 2.04 hypv)
+ * HSRR1   => SPR 315 (Power 2.04 hypv)
+ * LPCR    => SPR 316 (970)
+ * LPIDR   => SPR 317 (970)
+ * EPR     => SPR 702 (Power 2.04 emb)
+ * perf    => 768-783 (Power 2.04)
+ * perf    => 784-799 (Power 2.04)
+ * PPR     => SPR 896 (Power 2.04)
+ * EPLC    => SPR 947 (Power 2.04 emb)
+ * EPSC    => SPR 948 (Power 2.04 emb)
+ * DABRX   => 1015    (Power 2.04 hypv)
+ * FPECR   => SPR 1022 (?)
+ * ... and more (thermal management, performance counters, ...)
+ */
+
+/*****************************************************************************/
+/* Exception vectors models                                                  */
+static void init_excp_4xx_real (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFF0UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_4xx_softmmu (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFF0UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_MPC5xx (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
+    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
+    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
+    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFF0UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_MPC8xx (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
+    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_ITLBE]    = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_DTLBE]    = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
+    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
+    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFF0UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_G2 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_e200 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000FFC;
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_SPEU]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_EFPDI]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_EFPRI]    = 0x00000000;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFF7UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_BookE (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
+    env->hreset_excp_prefix = 0x00000000UL;
+    env->ivor_mask = 0x0000FFE0UL;
+    env->ivpr_mask = 0xFFFF0000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_601 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_IO]       = 0x00000A00;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_RUNM]     = 0x00002000;
+    env->hreset_excp_prefix = 0xFFF00000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x00000100UL;
+#endif
+}
+
+static void init_excp_602 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* XXX: exception prefix has a special behavior on 602 */
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001500;
+    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001600;
+    env->hreset_excp_prefix = 0xFFF00000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_603 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_604 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->hreset_excp_prefix = 0xFFF00000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x00000100UL;
+#endif
+}
+
+#if defined(TARGET_PPC64)
+static void init_excp_620 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->hreset_excp_prefix = 0xFFF00000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x0000000000000100ULL;
+#endif
+}
+#endif /* defined(TARGET_PPC64) */
+
+static void init_excp_7x0 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_750cl (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_750cx (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+/* XXX: Check if this is correct */
+static void init_excp_7x5 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_7400 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+static void init_excp_7450 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+    env->hreset_excp_prefix = 0x00000000UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0xFFFFFFFCUL;
+#endif
+}
+
+#if defined (TARGET_PPC64)
+static void init_excp_970 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    env->hreset_excp_prefix = 0x00000000FFF00000ULL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x0000000000000100ULL;
+#endif
+}
+
+static void init_excp_POWER7 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    env->hreset_excp_prefix = 0;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x0000000000000100ULL;
+#endif
+}
+#endif
+
+/*****************************************************************************/
+/* Power management enable checks                                            */
+static int check_pow_none (CPUPPCState *env)
+{
+    return 0;
+}
+
+static int check_pow_nocheck (CPUPPCState *env)
+{
+    return 1;
+}
+
+static int check_pow_hid0 (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00E00000)
+        return 1;
+
+    return 0;
+}
+
+static int check_pow_hid0_74xx (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00600000)
+        return 1;
+
+    return 0;
+}
+
+/*****************************************************************************/
+/* PowerPC implementations definitions                                       */
+
+/* PowerPC 401                                                               */
+#define POWERPC_INSNS_401    (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_WRTEE | PPC_DCR |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ |                                \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401   (PPC_NONE)
+#define POWERPC_MSRM_401     (0x00000000000FD201ULL)
+#define POWERPC_MMU_401      (POWERPC_MMU_REAL)
+#define POWERPC_EXCP_401     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401    (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401     (bfd_mach_ppc_403)
+#define POWERPC_FLAG_401     (POWERPC_FLAG_CE | POWERPC_FLAG_DE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_401        check_pow_nocheck
+
+static void init_proc_401 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401(env);
+    init_excp_4xx_real(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 401x2                                                             */
+#define POWERPC_INSNS_401x2  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x2 (PPC_NONE)
+#define POWERPC_MSRM_401x2   (0x00000000001FD231ULL)
+#define POWERPC_MMU_401x2    (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_401x2   (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401x2  (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401x2   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_401x2   (POWERPC_FLAG_CE | POWERPC_FLAG_DE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_401x2      check_pow_nocheck
+
+static void init_proc_401x2 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_4xx_softmmu(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 401x3                                                             */
+#define POWERPC_INSNS_401x3  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x3 (PPC_NONE)
+#define POWERPC_MSRM_401x3   (0x00000000001FD631ULL)
+#define POWERPC_MMU_401x3    (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_401x3   (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401x3  (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401x3   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_401x3   (POWERPC_FLAG_CE | POWERPC_FLAG_DE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_401x3      check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_401x3 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    init_excp_4xx_softmmu(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* IOP480                                                                    */
+#define POWERPC_INSNS_IOP480 (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI |  PPC_40x_ICBT |    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_IOP480 (PPC_NONE)
+#define POWERPC_MSRM_IOP480  (0x00000000001FD231ULL)
+#define POWERPC_MMU_IOP480   (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_IOP480  (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_IOP480  (bfd_mach_ppc_403)
+#define POWERPC_FLAG_IOP480  (POWERPC_FLAG_CE | POWERPC_FLAG_DE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_IOP480     check_pow_nocheck
+
+static void init_proc_IOP480 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_4xx_softmmu(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 403                                                               */
+#define POWERPC_INSNS_403    (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ |                                \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403   (PPC_NONE)
+#define POWERPC_MSRM_403     (0x000000000007D00DULL)
+#define POWERPC_MMU_403      (POWERPC_MMU_REAL)
+#define POWERPC_EXCP_403     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_403    (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_403     (bfd_mach_ppc_403)
+#define POWERPC_FLAG_403     (POWERPC_FLAG_CE | POWERPC_FLAG_PX |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_403        check_pow_nocheck
+
+static void init_proc_403 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_403(env);
+    gen_spr_403_real(env);
+    init_excp_4xx_real(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 403 GCX                                                           */
+#define POWERPC_INSNS_403GCX (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ |                                \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403GCX (PPC_NONE)
+#define POWERPC_MSRM_403GCX  (0x000000000007D00DULL)
+#define POWERPC_MMU_403GCX   (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_403GCX  (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_403GCX  (bfd_mach_ppc_403)
+#define POWERPC_FLAG_403GCX  (POWERPC_FLAG_CE | POWERPC_FLAG_PX |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_403GCX     check_pow_nocheck
+
+static void init_proc_403GCX (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_403(env);
+    gen_spr_403_real(env);
+    gen_spr_403_mmu(env);
+    /* Bus access control */
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_4xx_softmmu(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 405                                                               */
+#define POWERPC_INSNS_405    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |     \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP)
+#define POWERPC_INSNS2_405   (PPC_NONE)
+#define POWERPC_MSRM_405     (0x000000000006E630ULL)
+#define POWERPC_MMU_405      (POWERPC_MMU_SOFT_4xx)
+#define POWERPC_EXCP_405     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_405    (PPC_FLAGS_INPUT_405)
+#define POWERPC_BFDM_405     (bfd_mach_ppc_403)
+#define POWERPC_FLAG_405     (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_405        check_pow_nocheck
+
+static void init_proc_405 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_40x(env);
+    gen_spr_405(env);
+    /* Bus access control */
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_4xx_softmmu(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 440 EP                                                            */
+#define POWERPC_INSNS_440EP  (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE | PPC_RFMCI |               \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_MFTB |                    \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_440EP (PPC_NONE)
+#define POWERPC_MSRM_440EP   (0x000000000006D630ULL)
+#define POWERPC_MMU_440EP    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440EP   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440EP  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440EP   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_440EP   (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_440EP      check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_440EP (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440 GP                                                            */
+#define POWERPC_INSNS_440GP  (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI |  \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB |       \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_440GP (PPC_NONE)
+#define POWERPC_MSRM_440GP   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440GP    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440GP   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440GP  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440GP   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_440GP   (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_440GP      check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_440GP (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440x4                                                             */
+#define POWERPC_INSNS_440x4  (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE |                           \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_MFTB |                    \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_440x4 (PPC_NONE)
+#define POWERPC_MSRM_440x4   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440x4    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440x4   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440x4  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440x4   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_440x4   (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_440x4      check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_440x4 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440x5                                                             */
+#define POWERPC_INSNS_440x5  (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_WRTEE | PPC_RFMCI |               \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_MFTB |                    \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_440x5 (PPC_NONE)
+#define POWERPC_MSRM_440x5   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440x5    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440x5   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440x5  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440x5   (bfd_mach_ppc_403)
+#define POWERPC_FLAG_440x5   (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |           \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_440x5      check_pow_nocheck
+
+static void init_proc_440x5 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 460 (guessed)                                                     */
+#define POWERPC_INSNS_460    (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_DCR | PPC_DCRX  | PPC_DCRUX |               \
+                              PPC_WRTEE | PPC_MFAPIDI | PPC_MFTB |            \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_460   (PPC_NONE)
+#define POWERPC_MSRM_460     (0x000000000006FF30ULL)
+#define POWERPC_MMU_460      (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_460     (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_460    (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_460     (bfd_mach_ppc_403)
+#define POWERPC_FLAG_460     (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_460        check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_460 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DCRIPR, "SPR_DCRIPR",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 460F (guessed)                                                    */
+#define POWERPC_INSNS_460F   (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX | PPC_MFTB |                   \
+                              PPC_DCR | PPC_DCRX | PPC_DCRUX |                \
+                              PPC_WRTEE | PPC_MFAPIDI |                       \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_INSNS2_460F  (PPC_NONE)
+#define POWERPC_MSRM_460     (0x000000000006FF30ULL)
+#define POWERPC_MMU_460F     (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_460F    (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_460F   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_460F    (bfd_mach_ppc_403)
+#define POWERPC_FLAG_460F    (POWERPC_FLAG_CE | POWERPC_FLAG_DWE |            \
+                              POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_460F       check_pow_nocheck
+
+__attribute__ (( unused ))
+static void init_proc_460F (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000000000FFFFULL);
+    gen_spr_440(env);
+    gen_spr_usprgh(env);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DCRIPR, "SPR_DCRIPR",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_BookE(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* Freescale 5xx cores (aka RCPU) */
+#define POWERPC_INSNS_MPC5xx (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
+                              PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \
+                              PPC_MFTB)
+#define POWERPC_INSNS2_MPC5xx (PPC_NONE)
+#define POWERPC_MSRM_MPC5xx  (0x000000000001FF43ULL)
+#define POWERPC_MMU_MPC5xx   (POWERPC_MMU_REAL)
+#define POWERPC_EXCP_MPC5xx  (POWERPC_EXCP_603)
+#define POWERPC_INPUT_MPC5xx (PPC_FLAGS_INPUT_RCPU)
+#define POWERPC_BFDM_MPC5xx  (bfd_mach_ppc_505)
+#define POWERPC_FLAG_MPC5xx  (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_MPC5xx     check_pow_none
+
+__attribute__ (( unused ))
+static void init_proc_MPC5xx (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_5xx_8xx(env);
+    gen_spr_5xx(env);
+    init_excp_MPC5xx(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* Freescale 8xx cores (aka PowerQUICC) */
+#define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING  |                  \
+                              PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
+                              PPC_CACHE_ICBI | PPC_MFTB)
+#define POWERPC_INSNS2_MPC8xx (PPC_NONE)
+#define POWERPC_MSRM_MPC8xx  (0x000000000001F673ULL)
+#define POWERPC_MMU_MPC8xx   (POWERPC_MMU_MPC8xx)
+#define POWERPC_EXCP_MPC8xx  (POWERPC_EXCP_603)
+#define POWERPC_INPUT_MPC8xx (PPC_FLAGS_INPUT_RCPU)
+#define POWERPC_BFDM_MPC8xx  (bfd_mach_ppc_860)
+#define POWERPC_FLAG_MPC8xx  (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_MPC8xx     check_pow_none
+
+__attribute__ (( unused ))
+static void init_proc_MPC8xx (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_5xx_8xx(env);
+    gen_spr_8xx(env);
+    init_excp_MPC8xx(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* Freescale 82xx cores (aka PowerQUICC-II)                                  */
+/* PowerPC G2                                                                */
+#define POWERPC_INSNS_G2     (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2    (PPC_NONE)
+#define POWERPC_MSRM_G2      (0x000000000006FFF2ULL)
+#define POWERPC_MMU_G2       (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_G2      (POWERPC_EXCP_G2)
+#define POWERPC_INPUT_G2     (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_G2      (bfd_mach_ppc_ec603e)
+#define POWERPC_FLAG_G2      (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_G2         check_pow_hid0
+
+static void init_proc_G2 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_G2_755(env);
+    gen_spr_G2(env);
+    /* Time base */
+    gen_tbl(env);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation register */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_G2(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC G2LE                                                              */
+#define POWERPC_INSNS_G2LE   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2LE  (PPC_NONE)
+#define POWERPC_MSRM_G2LE    (0x000000000007FFF3ULL)
+#define POWERPC_MMU_G2LE     (POWERPC_MMU_SOFT_6xx)
+#define POWERPC_EXCP_G2LE    (POWERPC_EXCP_G2)
+#define POWERPC_INPUT_G2LE   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_G2LE    (bfd_mach_ppc_ec603e)
+#define POWERPC_FLAG_G2LE    (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_G2LE       check_pow_hid0
+
+static void init_proc_G2LE (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_G2_755(env);
+    gen_spr_G2(env);
+    /* Time base */
+    gen_tbl(env);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation register */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_G2(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* e200 core                                                                 */
+/* XXX: unimplemented instructions:
+ * dcblc
+ * dcbtlst
+ * dcbtstls
+ * icblc
+ * icbtls
+ * tlbivax
+ * all SPE multiply-accumulate instructions
+ */
+#define POWERPC_INSNS_e200   (PPC_INSNS_BASE | PPC_ISEL |                     \
+                              PPC_SPE | PPC_SPE_SINGLE |                      \
+                              PPC_WRTEE | PPC_RFDI |                          \
+                              PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |   \
+                              PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
+                              PPC_MEM_TLBSYNC | PPC_TLBIVAX |                 \
+                              PPC_BOOKE)
+#define POWERPC_INSNS2_e200  (PPC_NONE)
+#define POWERPC_MSRM_e200    (0x000000000606FF30ULL)
+#define POWERPC_MMU_e200     (POWERPC_MMU_BOOKE206)
+#define POWERPC_EXCP_e200    (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_e200   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_e200    (bfd_mach_ppc_860)
+#define POWERPC_FLAG_e200    (POWERPC_FLAG_SPE | POWERPC_FLAG_CE |            \
+                              POWERPC_FLAG_UBLE | POWERPC_FLAG_DE |           \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_e200       check_pow_hid0
+
+__attribute__ (( unused ))
+static void init_proc_e200 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env, 0x000000070000FFFFULL);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR",
+                 &spr_read_spefscr, &spr_write_spefscr,
+                 &spr_read_spefscr, &spr_write_spefscr,
+                 0x00000000);
+    /* Memory management */
+    gen_spr_BookE206(env, 0x0000005D, NULL);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_ALTCTXCR, "ALTCTXCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_BUCSR, "BUCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_CTXCR, "CTXCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_DBCNT, "DBCNT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_DBCR3, "DBCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1FINV0, "L1FINV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    env->tlb_type = TLB_EMB;
+#endif
+    init_excp_e200(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* e300 core                                                                 */
+#define POWERPC_INSNS_e300   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_e300  (PPC_NONE)
+#define POWERPC_MSRM_e300    (0x000000000007FFF3ULL)
+#define POWERPC_MMU_e300     (POWERPC_MMU_SOFT_6xx)
+#define POWERPC_EXCP_e300    (POWERPC_EXCP_603)
+#define POWERPC_INPUT_e300   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_e300    (bfd_mach_ppc_603)
+#define POWERPC_FLAG_e300    (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_e300       check_pow_hid0
+
+__attribute__ (( unused ))
+static void init_proc_e300 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_603(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_603(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* e500v1 core                                                               */
+#define POWERPC_INSNS_e500v1   (PPC_INSNS_BASE | PPC_ISEL |             \
+                                PPC_SPE | PPC_SPE_SINGLE |              \
+                                PPC_WRTEE | PPC_RFDI |                  \
+                                PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
+                                PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206)
+#define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
+#define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE206)
+#define POWERPC_EXCP_e500v1    (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_e500v1   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_e500v1    (bfd_mach_ppc_860)
+#define POWERPC_FLAG_e500v1    (POWERPC_FLAG_SPE | POWERPC_FLAG_CE |    \
+                                POWERPC_FLAG_UBLE | POWERPC_FLAG_DE |   \
+                                POWERPC_FLAG_BUS_CLK)
+#define check_pow_e500v1       check_pow_hid0
+#define init_proc_e500v1       init_proc_e500v1
+
+/* e500v2 core                                                               */
+#define POWERPC_INSNS_e500v2   (PPC_INSNS_BASE | PPC_ISEL |             \
+                                PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE |   \
+                                PPC_WRTEE | PPC_RFDI |                  \
+                                PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
+                                PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206)
+#define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
+#define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE206)
+#define POWERPC_EXCP_e500v2    (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_e500v2   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_e500v2    (bfd_mach_ppc_860)
+#define POWERPC_FLAG_e500v2    (POWERPC_FLAG_SPE | POWERPC_FLAG_CE |    \
+                                POWERPC_FLAG_UBLE | POWERPC_FLAG_DE |   \
+                                POWERPC_FLAG_BUS_CLK)
+#define check_pow_e500v2       check_pow_hid0
+#define init_proc_e500v2       init_proc_e500v2
+
+static void init_proc_e500 (CPUPPCState *env, int version)
+{
+    uint32_t tlbncfg[2];
+#if !defined(CONFIG_USER_ONLY)
+    int i;
+#endif
+
+    /* Time base */
+    gen_tbl(env);
+    /*
+     * XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
+     *     complain when accessing them.
+     * gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+     */
+    gen_spr_BookE(env, 0x0000000F0000FFFFULL);
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR",
+                 &spr_read_spefscr, &spr_write_spefscr,
+                 &spr_read_spefscr, &spr_write_spefscr,
+                 0x00000000);
+    /* Memory management */
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_pids = 3;
+    env->nb_ways = 2;
+    env->id_tlbs = 0;
+    switch (version) {
+    case 1:
+        /* e500v1 */
+        tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+        break;
+    case 2:
+        /* e500v2 */
+        tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+        break;
+    default:
+        cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
+    }
+#endif
+    gen_spr_BookE206(env, 0x000000DF, tlbncfg);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_BBEAR, "BBEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_BBTAR, "BBTAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_MCAR, "MCAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_NPIDR, "NPIDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_BUCSR, "BUCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_e500_l1csr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke206_mmucsr0,
+                 0x00000000);
+
+#if !defined(CONFIG_USER_ONLY)
+    env->nb_tlb = 0;
+    env->tlb_type = TLB_MAS;
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        env->nb_tlb += booke206_tlb_size(env, i);
+    }
+#endif
+
+    init_excp_e200(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppce500_irq_init(env);
+}
+
+static void init_proc_e500v1(CPUPPCState *env)
+{
+    init_proc_e500(env, 1);
+}
+
+static void init_proc_e500v2(CPUPPCState *env)
+{
+    init_proc_e500(env, 2);
+}
+
+/* Non-embedded PowerPC                                                      */
+
+/* POWER : same as 601, without mfmsr, mfsr                                  */
+#if defined(TODO)
+#define POWERPC_INSNS_POWER  (XXX_TODO)
+/* POWER RSC (from RAD6000) */
+#define POWERPC_MSRM_POWER   (0x00000000FEF0ULL)
+#endif /* TODO */
+
+/* PowerPC 601                                                               */
+#define POWERPC_INSNS_601    (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |    \
+                              PPC_FLOAT |                                     \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601   (PPC_NONE)
+#define POWERPC_MSRM_601     (0x000000000000FD70ULL)
+#define POWERPC_MSRR_601     (0x0000000000001040ULL)
+//#define POWERPC_MMU_601      (POWERPC_MMU_601)
+//#define POWERPC_EXCP_601     (POWERPC_EXCP_601)
+#define POWERPC_INPUT_601    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_601     (bfd_mach_ppc_601)
+#define POWERPC_FLAG_601     (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK)
+#define check_pow_601        check_pow_none
+
+static void init_proc_601 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_601(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_hid0_601,
+                 0x80010080);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    init_excp_601(env);
+    /* XXX: beware that dcache line size is 64 
+     *      but dcbz uses 32 bytes "sectors"
+     * XXX: this breaks clcs instruction !
+     */
+    env->dcache_line_size = 32;
+    env->icache_line_size = 64;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 601v                                                              */
+#define POWERPC_INSNS_601v   (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |    \
+                              PPC_FLOAT |                                     \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601v  (PPC_NONE)
+#define POWERPC_MSRM_601v    (0x000000000000FD70ULL)
+#define POWERPC_MSRR_601v    (0x0000000000001040ULL)
+#define POWERPC_MMU_601v     (POWERPC_MMU_601)
+#define POWERPC_EXCP_601v    (POWERPC_EXCP_601)
+#define POWERPC_INPUT_601v   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_601v    (bfd_mach_ppc_601)
+#define POWERPC_FLAG_601v    (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK)
+#define check_pow_601v       check_pow_none
+
+static void init_proc_601v (CPUPPCState *env)
+{
+    init_proc_601(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID15, "HID15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* PowerPC 602                                                               */
+#define POWERPC_INSNS_602    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \
+                              PPC_SEGMENT | PPC_602_SPEC)
+#define POWERPC_INSNS2_602   (PPC_NONE)
+#define POWERPC_MSRM_602     (0x0000000000C7FF73ULL)
+/* XXX: 602 MMU is quite specific. Should add a special case */
+#define POWERPC_MMU_602      (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_602     (POWERPC_EXCP_602)
+#define POWERPC_INPUT_602    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_602     (bfd_mach_ppc_602)
+#define POWERPC_FLAG_602     (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_602        check_pow_hid0
+
+static void init_proc_602 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_602(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_602(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 603                                                               */
+#define POWERPC_INSNS_603    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603   (PPC_NONE)
+#define POWERPC_MSRM_603     (0x000000000007FF73ULL)
+#define POWERPC_MMU_603      (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_603     (POWERPC_EXCP_603)
+#define POWERPC_INPUT_603    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_603     (bfd_mach_ppc_603)
+#define POWERPC_FLAG_603     (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_603        check_pow_hid0
+
+static void init_proc_603 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_603(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_603(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 603e                                                              */
+#define POWERPC_INSNS_603E   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603E  (PPC_NONE)
+#define POWERPC_MSRM_603E    (0x000000000007FF73ULL)
+#define POWERPC_MMU_603E     (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_603E    (POWERPC_EXCP_603E)
+#define POWERPC_INPUT_603E   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_603E    (bfd_mach_ppc_ec603e)
+#define POWERPC_FLAG_603E    (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |           \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK)
+#define check_pow_603E       check_pow_hid0
+
+static void init_proc_603E (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_603(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_603(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 604                                                               */
+#define POWERPC_INSNS_604    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604   (PPC_NONE)
+#define POWERPC_MSRM_604     (0x000000000005FF77ULL)
+#define POWERPC_MMU_604      (POWERPC_MMU_32B)
+//#define POWERPC_EXCP_604     (POWERPC_EXCP_604)
+#define POWERPC_INPUT_604    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_604     (bfd_mach_ppc_604)
+#define POWERPC_FLAG_604     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_604        check_pow_nocheck
+
+static void init_proc_604 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_604(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_604(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 604E                                                              */
+#define POWERPC_INSNS_604E   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604E  (PPC_NONE)
+#define POWERPC_MSRM_604E    (0x000000000005FF77ULL)
+#define POWERPC_MMU_604E     (POWERPC_MMU_32B)
+#define POWERPC_EXCP_604E    (POWERPC_EXCP_604)
+#define POWERPC_INPUT_604E   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_604E    (bfd_mach_ppc_604)
+#define POWERPC_FLAG_604E    (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_604E       check_pow_nocheck
+
+static void init_proc_604E (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_604(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR1, "MMCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC3, "PMC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC4, "PMC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_604(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 740                                                               */
+#define POWERPC_INSNS_740    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_740   (PPC_NONE)
+#define POWERPC_MSRM_740     (0x000000000005FF77ULL)
+#define POWERPC_MMU_740      (POWERPC_MMU_32B)
+#define POWERPC_EXCP_740     (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_740    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_740     (bfd_mach_ppc_750)
+#define POWERPC_FLAG_740     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_740        check_pow_hid0
+
+static void init_proc_740 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7x0(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750                                                               */
+#define POWERPC_INSNS_750    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750   (PPC_NONE)
+#define POWERPC_MSRM_750     (0x000000000005FF77ULL)
+#define POWERPC_MMU_750      (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750     (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750     (bfd_mach_ppc_750)
+#define POWERPC_FLAG_750     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_750        check_pow_hid0
+
+static void init_proc_750 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* XXX: high BATs are also present but are known to be bugged on
+     *      die version 1.x
+     */
+    init_excp_7x0(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750 CL                                                            */
+/* XXX: not implemented:
+ * cache lock instructions:
+ * dcbz_l
+ * floating point paired instructions
+ * psq_lux
+ * psq_lx
+ * psq_stux
+ * psq_stx
+ * ps_abs
+ * ps_add
+ * ps_cmpo0
+ * ps_cmpo1
+ * ps_cmpu0
+ * ps_cmpu1
+ * ps_div
+ * ps_madd
+ * ps_madds0
+ * ps_madds1
+ * ps_merge00
+ * ps_merge01
+ * ps_merge10
+ * ps_merge11
+ * ps_mr
+ * ps_msub
+ * ps_mul
+ * ps_muls0
+ * ps_muls1
+ * ps_nabs
+ * ps_neg
+ * ps_nmadd
+ * ps_nmsub
+ * ps_res
+ * ps_rsqrte
+ * ps_sel
+ * ps_sub
+ * ps_sum0
+ * ps_sum1
+ */
+#define POWERPC_INSNS_750cl  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cl (PPC_NONE)
+#define POWERPC_MSRM_750cl   (0x000000000005FF77ULL)
+#define POWERPC_MMU_750cl    (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750cl   (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750cl  (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750cl   (bfd_mach_ppc_750)
+#define POWERPC_FLAG_750cl   (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_750cl      check_pow_hid0
+
+static void init_proc_750cl (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    /* Those registers are fake on 750CL */
+    spr_register(env, SPR_THRM1, "THRM1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_THRM2, "THRM2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_THRM3, "THRM3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX: not implemented */
+    spr_register(env, SPR_750_TDCL, "TDCL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_750_TDCH, "TDCH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* DMA */
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_WPAR, "WPAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_750_DMAL, "DMAL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_750_DMAU, "DMAU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750CL_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750CL_HID4, "HID4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Quantization registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR0, "GQR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR1, "GQR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR2, "GQR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR3, "GQR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR4, "GQR4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR5, "GQR5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR6, "GQR6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_GQR7, "GQR7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* PowerPC 750cl has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
+    init_excp_750cl(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750CX                                                             */
+#define POWERPC_INSNS_750cx  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cx (PPC_NONE)
+#define POWERPC_MSRM_750cx   (0x000000000005FF77ULL)
+#define POWERPC_MMU_750cx    (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750cx   (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750cx  (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750cx   (bfd_mach_ppc_750)
+#define POWERPC_FLAG_750cx   (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_750cx      check_pow_hid0
+
+static void init_proc_750cx (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* This register is not implemented but is present for compatibility */
+    spr_register(env, SPR_SDA, "SDA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* PowerPC 750cx has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
+    init_excp_750cx(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750FX                                                             */
+#define POWERPC_INSNS_750fx  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750fx (PPC_NONE)
+#define POWERPC_MSRM_750fx   (0x000000000005FF77ULL)
+#define POWERPC_MMU_750fx    (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750fx   (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750fx  (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750fx   (bfd_mach_ppc_750)
+#define POWERPC_FLAG_750fx   (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_750fx      check_pow_hid0
+
+static void init_proc_750fx (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_THRM4, "THRM4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
+    init_excp_7x0(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750GX                                                             */
+#define POWERPC_INSNS_750gx  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750gx (PPC_NONE)
+#define POWERPC_MSRM_750gx   (0x000000000005FF77ULL)
+#define POWERPC_MMU_750gx    (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750gx   (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750gx  (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750gx   (bfd_mach_ppc_750)
+#define POWERPC_FLAG_750gx   (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_750gx      check_pow_hid0
+
+static void init_proc_750gx (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* XXX : not implemented (XXX: different from 750fx) */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_THRM4, "THRM4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented (XXX: different from 750fx) */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented (XXX: different from 750fx) */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
+    init_excp_7x0(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 745                                                               */
+#define POWERPC_INSNS_745    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_745   (PPC_NONE)
+#define POWERPC_MSRM_745     (0x000000000005FF77ULL)
+#define POWERPC_MMU_745      (POWERPC_MMU_SOFT_6xx)
+#define POWERPC_EXCP_745     (POWERPC_EXCP_7x5)
+#define POWERPC_INPUT_745    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_745     (bfd_mach_ppc_750)
+#define POWERPC_FLAG_745     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_745        check_pow_hid0
+
+static void init_proc_745 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    gen_spr_G2_755(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_7x5(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 755                                                               */
+#define POWERPC_INSNS_755    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
+                              PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_755   (PPC_NONE)
+#define POWERPC_MSRM_755     (0x000000000005FF77ULL)
+#define POWERPC_MMU_755      (POWERPC_MMU_SOFT_6xx)
+#define POWERPC_EXCP_755     (POWERPC_EXCP_7x5)
+#define POWERPC_INPUT_755    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_755     (bfd_mach_ppc_750)
+#define POWERPC_FLAG_755     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |             \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_755        check_pow_hid0
+
+static void init_proc_755 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    gen_spr_G2_755(env);
+    /* Time base */
+    gen_tbl(env);
+    /* L2 cache control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2PMCR, "L2PMCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_7x5(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7400 (aka G4)                                                     */
+#define POWERPC_INSNS_7400   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA |                                 \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7400  (PPC_NONE)
+#define POWERPC_MSRM_7400    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7400     (POWERPC_MMU_32B)
+#define POWERPC_EXCP_7400    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7400   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7400    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7400    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7400       check_pow_hid0
+
+static void init_proc_7400 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX: this seems not implemented on all revisions. */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSCR1, "MSSCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7400(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7410 (aka G4)                                                     */
+#define POWERPC_INSNS_7410   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA |                                 \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7410  (PPC_NONE)
+#define POWERPC_MSRM_7410    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7410     (POWERPC_MMU_32B)
+#define POWERPC_EXCP_7410    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7410   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7410    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7410    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7410       check_pow_hid0
+
+static void init_proc_7410 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* L2PMCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2PMCR, "L2PMCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* LDSTDB */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTDB, "LDSTDB",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7400(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7440 (aka G4)                                                     */
+#define POWERPC_INSNS_7440   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7440  (PPC_NONE)
+#define POWERPC_MSRM_7440    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7440     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7440    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7440   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7440    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7440    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7440       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7440 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7450 (aka G4)                                                     */
+#define POWERPC_INSNS_7450   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7450  (PPC_NONE)
+#define POWERPC_MSRM_7450    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7450     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7450    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7450   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7450    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7450    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7450       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7450 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* L3ITCR1 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR2 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR3 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3OHCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3OHCR, "L3OHCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7445 (aka G4)                                                     */
+#define POWERPC_INSNS_7445   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7445  (PPC_NONE)
+#define POWERPC_MSRM_7445    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7445     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7445    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7445   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7445    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7445    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7445       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7445 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7455 (aka G4)                                                     */
+#define POWERPC_INSNS_7455   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7455  (PPC_NONE)
+#define POWERPC_MSRM_7455    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7455     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7455    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7455   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7455    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7455    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7455       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7455 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7457 (aka G4)                                                     */
+#define POWERPC_INSNS_7457   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_INSNS2_7457  (PPC_NONE)
+#define POWERPC_MSRM_7457    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7457     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7457    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7457   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7457    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7457    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7457       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7457 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* L3ITCR1 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR2 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR3 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3OHCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3OHCR, "L3OHCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+#if defined (TARGET_PPC64)
+/* PowerPC 970                                                               */
+#define POWERPC_INSNS_970    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970   (PPC_NONE)
+#define POWERPC_MSRM_970     (0x900000000204FF36ULL)
+#define POWERPC_MMU_970      (POWERPC_MMU_64B)
+//#define POWERPC_EXCP_970     (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970    (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970     (bfd_mach_ppc64)
+#define POWERPC_FLAG_970     (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+
+#if defined(CONFIG_USER_ONLY)
+#define POWERPC970_HID5_INIT 0x00000080
+#else
+#define POWERPC970_HID5_INIT 0x00000000
+#endif
+
+static int check_pow_970 (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00600000)
+        return 1;
+
+    return 0;
+}
+
+static void init_proc_970 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x60000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_970_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 POWERPC970_HID5_INIT);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_hior, &spr_write_hior,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+
+/* PowerPC 970FX (aka G5)                                                    */
+#define POWERPC_INSNS_970FX  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970FX (PPC_NONE)
+#define POWERPC_MSRM_970FX   (0x800000000204FF36ULL)
+#define POWERPC_MMU_970FX    (POWERPC_MMU_64B)
+#define POWERPC_EXCP_970FX   (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970FX  (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970FX   (bfd_mach_ppc64)
+#define POWERPC_FLAG_970FX   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+
+static int check_pow_970FX (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00600000)
+        return 1;
+
+    return 0;
+}
+
+static void init_proc_970FX (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x60000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_970_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 POWERPC970_HID5_INIT);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_hior, &spr_write_hior,
+                 0x00000000);
+    spr_register(env, SPR_CTRL, "SPR_CTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_UCTRL, "SPR_UCTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 64;
+#endif
+    init_excp_970(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+
+/* PowerPC 970 GX                                                            */
+#define POWERPC_INSNS_970GX  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970GX (PPC_NONE)
+#define POWERPC_MSRM_970GX   (0x800000000204FF36ULL)
+#define POWERPC_MMU_970GX    (POWERPC_MMU_64B)
+#define POWERPC_EXCP_970GX   (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970GX  (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970GX   (bfd_mach_ppc64)
+#define POWERPC_FLAG_970GX   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+
+static int check_pow_970GX (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00600000)
+        return 1;
+
+    return 0;
+}
+
+static void init_proc_970GX (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x60000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_970_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 POWERPC970_HID5_INIT);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_hior, &spr_write_hior,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+
+/* PowerPC 970 MP                                                            */
+#define POWERPC_INSNS_970MP  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970MP (PPC_NONE)
+#define POWERPC_MSRM_970MP   (0x900000000204FF36ULL)
+#define POWERPC_MMU_970MP    (POWERPC_MMU_64B)
+#define POWERPC_EXCP_970MP   (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970MP  (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970MP   (bfd_mach_ppc64)
+#define POWERPC_FLAG_970MP   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+
+static int check_pow_970MP (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x01C00000)
+        return 1;
+
+    return 0;
+}
+
+static void init_proc_970MP (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x60000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750FX_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_970_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 POWERPC970_HID5_INIT);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_hior, &spr_write_hior,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+
+#if defined(TARGET_PPC64)
+/* POWER7 */
+#define POWERPC_INSNS_POWER7  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI |                    \
+                              PPC_POPCNTB | PPC_POPCNTWD)
+#define POWERPC_INSNS2_POWER7 (PPC_NONE)
+#define POWERPC_MSRM_POWER7   (0x800000000204FF36ULL)
+#define POWERPC_MMU_POWER7    (POWERPC_MMU_2_06)
+#define POWERPC_EXCP_POWER7   (POWERPC_EXCP_POWER7)
+#define POWERPC_INPUT_POWER7  (PPC_FLAGS_INPUT_POWER7)
+#define POWERPC_BFDM_POWER7   (bfd_mach_ppc64)
+#define POWERPC_FLAG_POWER7   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_POWER7    check_pow_nocheck
+
+static void init_proc_POWER7 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+#if !defined(CONFIG_USER_ONLY)
+    /* PURR & SPURR: Hack - treat these as aliases for the TB for now */
+    spr_register(env, SPR_PURR,   "PURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPURR,   "SPURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+#endif /* !CONFIG_USER_ONLY */
+    /* Memory management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_CTRL, "SPR_CTRLT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_UCTRL, "SPR_CTRLF",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_POWER7(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppcPOWER7_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+#endif /* TARGET_PPC64 */
+
+/* PowerPC 620                                                               */
+#define POWERPC_INSNS_620    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_64B | PPC_SLBI)
+#define POWERPC_INSNS2_620   (PPC_NONE)
+#define POWERPC_MSRM_620     (0x800000000005FF77ULL)
+//#define POWERPC_MMU_620      (POWERPC_MMU_620)
+#define POWERPC_EXCP_620     (POWERPC_EXCP_970)
+#define POWERPC_INPUT_620    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_620     (bfd_mach_ppc64)
+#define POWERPC_FLAG_620     (POWERPC_FLAG_SE | POWERPC_FLAG_BE |            \
+                              POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_620        check_pow_nocheck /* Check this */
+
+__attribute__ (( unused ))
+static void init_proc_620 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_620(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_620(env);
+    env->dcache_line_size = 64;
+    env->icache_line_size = 64;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+#endif /* defined (TARGET_PPC64) */
+
+/* Default 32 bits PowerPC target will be 604 */
+#define CPU_POWERPC_PPC32     CPU_POWERPC_604
+#define POWERPC_INSNS_PPC32   POWERPC_INSNS_604
+#define POWERPC_INSNS2_PPC32  POWERPC_INSNS2_604
+#define POWERPC_MSRM_PPC32    POWERPC_MSRM_604
+#define POWERPC_MMU_PPC32     POWERPC_MMU_604
+#define POWERPC_EXCP_PPC32    POWERPC_EXCP_604
+#define POWERPC_INPUT_PPC32   POWERPC_INPUT_604
+#define POWERPC_BFDM_PPC32    POWERPC_BFDM_604
+#define POWERPC_FLAG_PPC32    POWERPC_FLAG_604
+#define check_pow_PPC32       check_pow_604
+#define init_proc_PPC32       init_proc_604
+
+/* Default 64 bits PowerPC target will be 970 FX */
+#define CPU_POWERPC_PPC64     CPU_POWERPC_970FX
+#define POWERPC_INSNS_PPC64   POWERPC_INSNS_970FX
+#define POWERPC_INSNS2_PPC64  POWERPC_INSNS2_970FX
+#define POWERPC_MSRM_PPC64    POWERPC_MSRM_970FX
+#define POWERPC_MMU_PPC64     POWERPC_MMU_970FX
+#define POWERPC_EXCP_PPC64    POWERPC_EXCP_970FX
+#define POWERPC_INPUT_PPC64   POWERPC_INPUT_970FX
+#define POWERPC_BFDM_PPC64    POWERPC_BFDM_970FX
+#define POWERPC_FLAG_PPC64    POWERPC_FLAG_970FX
+#define check_pow_PPC64       check_pow_970FX
+#define init_proc_PPC64       init_proc_970FX
+
+/* Default PowerPC target will be PowerPC 32 */
+#if defined (TARGET_PPC64) && 0 // XXX: TODO
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC64
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC64
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC64
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC64
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC64
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC64
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC64
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC64
+#define check_pow_DEFAULT      check_pow_PPC64
+#define init_proc_DEFAULT      init_proc_PPC64
+#else
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC32
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC32
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC32
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC32
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC32
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC32
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC32
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC32
+#define check_pow_DEFAULT      check_pow_PPC32
+#define init_proc_DEFAULT      init_proc_PPC32
+#endif
+
+/*****************************************************************************/
+/* PVR definitions for most known PowerPC                                    */
+enum {
+    /* PowerPC 401 family */
+    /* Generic PowerPC 401 */
+#define CPU_POWERPC_401              CPU_POWERPC_401G2
+    /* PowerPC 401 cores */
+    CPU_POWERPC_401A1              = 0x00210000,
+    CPU_POWERPC_401B2              = 0x00220000,
+#if 0
+    CPU_POWERPC_401B3              = xxx,
+#endif
+    CPU_POWERPC_401C2              = 0x00230000,
+    CPU_POWERPC_401D2              = 0x00240000,
+    CPU_POWERPC_401E2              = 0x00250000,
+    CPU_POWERPC_401F2              = 0x00260000,
+    CPU_POWERPC_401G2              = 0x00270000,
+    /* PowerPC 401 microcontrolers */
+#if 0
+    CPU_POWERPC_401GF              = xxx,
+#endif
+#define CPU_POWERPC_IOP480           CPU_POWERPC_401B2
+    /* IBM Processor for Network Resources */
+    CPU_POWERPC_COBRA              = 0x10100000, /* XXX: 405 ? */
+#if 0
+    CPU_POWERPC_XIPCHIP            = xxx,
+#endif
+    /* PowerPC 403 family */
+    /* Generic PowerPC 403 */
+#define CPU_POWERPC_403              CPU_POWERPC_403GC
+    /* PowerPC 403 microcontrollers */
+    CPU_POWERPC_403GA              = 0x00200011,
+    CPU_POWERPC_403GB              = 0x00200100,
+    CPU_POWERPC_403GC              = 0x00200200,
+    CPU_POWERPC_403GCX             = 0x00201400,
+#if 0
+    CPU_POWERPC_403GP              = xxx,
+#endif
+    /* PowerPC 405 family */
+    /* Generic PowerPC 405 */
+#define CPU_POWERPC_405              CPU_POWERPC_405D4
+    /* PowerPC 405 cores */
+#if 0
+    CPU_POWERPC_405A3              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405A4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405B3              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405B4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405C3              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405C4              = xxx,
+#endif
+    CPU_POWERPC_405D2              = 0x20010000,
+#if 0
+    CPU_POWERPC_405D3              = xxx,
+#endif
+    CPU_POWERPC_405D4              = 0x41810000,
+#if 0
+    CPU_POWERPC_405D5              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405E4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F5              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F6              = xxx,
+#endif
+    /* PowerPC 405 microcontrolers */
+    /* XXX: missing 0x200108a0 */
+#define CPU_POWERPC_405CR            CPU_POWERPC_405CRc
+    CPU_POWERPC_405CRa             = 0x40110041,
+    CPU_POWERPC_405CRb             = 0x401100C5,
+    CPU_POWERPC_405CRc             = 0x40110145,
+    CPU_POWERPC_405EP              = 0x51210950,
+#if 0
+    CPU_POWERPC_405EXr             = xxx,
+#endif
+    CPU_POWERPC_405EZ              = 0x41511460, /* 0x51210950 ? */
+#if 0
+    CPU_POWERPC_405FX              = xxx,
+#endif
+#define CPU_POWERPC_405GP            CPU_POWERPC_405GPd
+    CPU_POWERPC_405GPa             = 0x40110000,
+    CPU_POWERPC_405GPb             = 0x40110040,
+    CPU_POWERPC_405GPc             = 0x40110082,
+    CPU_POWERPC_405GPd             = 0x401100C4,
+#define CPU_POWERPC_405GPe           CPU_POWERPC_405CRc
+    CPU_POWERPC_405GPR             = 0x50910951,
+#if 0
+    CPU_POWERPC_405H               = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405L               = xxx,
+#endif
+    CPU_POWERPC_405LP              = 0x41F10000,
+#if 0
+    CPU_POWERPC_405PM              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405PS              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405S               = xxx,
+#endif
+    /* IBM network processors */
+    CPU_POWERPC_NPE405H            = 0x414100C0,
+    CPU_POWERPC_NPE405H2           = 0x41410140,
+    CPU_POWERPC_NPE405L            = 0x416100C0,
+    CPU_POWERPC_NPE4GS3            = 0x40B10000,
+#if 0
+    CPU_POWERPC_NPCxx1             = xxx,
+#endif
+#if 0
+    CPU_POWERPC_NPR161             = xxx,
+#endif
+#if 0
+    CPU_POWERPC_LC77700            = xxx,
+#endif
+    /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */
+#if 0
+    CPU_POWERPC_STB01000           = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB01010           = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB0210            = xxx, /* 401B3 */
+#endif
+    CPU_POWERPC_STB03              = 0x40310000, /* 0x40130000 ? */
+#if 0
+    CPU_POWERPC_STB043             = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB045             = xxx,
+#endif
+    CPU_POWERPC_STB04              = 0x41810000,
+    CPU_POWERPC_STB25              = 0x51510950,
+#if 0
+    CPU_POWERPC_STB130             = xxx,
+#endif
+    /* Xilinx cores */
+    CPU_POWERPC_X2VP4              = 0x20010820,
+#define CPU_POWERPC_X2VP7            CPU_POWERPC_X2VP4
+    CPU_POWERPC_X2VP20             = 0x20010860,
+#define CPU_POWERPC_X2VP50           CPU_POWERPC_X2VP20
+#if 0
+    CPU_POWERPC_ZL10310            = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10311            = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10320            = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10321            = xxx,
+#endif
+    /* PowerPC 440 family */
+    /* Generic PowerPC 440 */
+#define CPU_POWERPC_440              CPU_POWERPC_440GXf
+    /* PowerPC 440 cores */
+#if 0
+    CPU_POWERPC_440A4              = xxx,
+#endif
+    CPU_POWERPC_440_XILINX         = 0x7ff21910,
+#if 0
+    CPU_POWERPC_440A5              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440B4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440F5              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440G5              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440H4              = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440H6              = xxx,
+#endif
+    /* PowerPC 440 microcontrolers */
+#define CPU_POWERPC_440EP            CPU_POWERPC_440EPb
+    CPU_POWERPC_440EPa             = 0x42221850,
+    CPU_POWERPC_440EPb             = 0x422218D3,
+#define CPU_POWERPC_440GP            CPU_POWERPC_440GPc
+    CPU_POWERPC_440GPb             = 0x40120440,
+    CPU_POWERPC_440GPc             = 0x40120481,
+#define CPU_POWERPC_440GR            CPU_POWERPC_440GRa
+#define CPU_POWERPC_440GRa           CPU_POWERPC_440EPb
+    CPU_POWERPC_440GRX             = 0x200008D0,
+#define CPU_POWERPC_440EPX           CPU_POWERPC_440GRX
+#define CPU_POWERPC_440GX            CPU_POWERPC_440GXf
+    CPU_POWERPC_440GXa             = 0x51B21850,
+    CPU_POWERPC_440GXb             = 0x51B21851,
+    CPU_POWERPC_440GXc             = 0x51B21892,
+    CPU_POWERPC_440GXf             = 0x51B21894,
+#if 0
+    CPU_POWERPC_440S               = xxx,
+#endif
+    CPU_POWERPC_440SP              = 0x53221850,
+    CPU_POWERPC_440SP2             = 0x53221891,
+    CPU_POWERPC_440SPE             = 0x53421890,
+    /* PowerPC 460 family */
+#if 0
+    /* Generic PowerPC 464 */
+#define CPU_POWERPC_464              CPU_POWERPC_464H90
+#endif
+    /* PowerPC 464 microcontrolers */
+#if 0
+    CPU_POWERPC_464H90             = xxx,
+#endif
+#if 0
+    CPU_POWERPC_464H90FP           = xxx,
+#endif
+    /* Freescale embedded PowerPC cores */
+    /* PowerPC MPC 5xx cores (aka RCPU) */
+    CPU_POWERPC_MPC5xx             = 0x00020020,
+#define CPU_POWERPC_MGT560           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC509           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC533           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC534           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC555           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC556           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC560           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC561           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC562           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC563           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC564           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC565           CPU_POWERPC_MPC5xx
+#define CPU_POWERPC_MPC566           CPU_POWERPC_MPC5xx
+    /* PowerPC MPC 8xx cores (aka PowerQUICC) */
+    CPU_POWERPC_MPC8xx             = 0x00500000,
+#define CPU_POWERPC_MGT823           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC821           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC823           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC850           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC852T          CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC855T          CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC857           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC859           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC860           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC862           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC866           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC870           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC875           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC880           CPU_POWERPC_MPC8xx
+#define CPU_POWERPC_MPC885           CPU_POWERPC_MPC8xx
+    /* G2 cores (aka PowerQUICC-II) */
+    CPU_POWERPC_G2                 = 0x00810011,
+    CPU_POWERPC_G2H4               = 0x80811010,
+    CPU_POWERPC_G2gp               = 0x80821010,
+    CPU_POWERPC_G2ls               = 0x90810010,
+    CPU_POWERPC_MPC603             = 0x00810100,
+    CPU_POWERPC_G2_HIP3            = 0x00810101,
+    CPU_POWERPC_G2_HIP4            = 0x80811014,
+    /*   G2_LE core (aka PowerQUICC-II) */
+    CPU_POWERPC_G2LE               = 0x80820010,
+    CPU_POWERPC_G2LEgp             = 0x80822010,
+    CPU_POWERPC_G2LEls             = 0xA0822010,
+    CPU_POWERPC_G2LEgp1            = 0x80822011,
+    CPU_POWERPC_G2LEgp3            = 0x80822013,
+    /* MPC52xx microcontrollers  */
+    /* XXX: MPC 5121 ? */
+#define CPU_POWERPC_MPC52xx          CPU_POWERPC_MPC5200
+#define CPU_POWERPC_MPC5200          CPU_POWERPC_MPC5200_v12
+#define CPU_POWERPC_MPC5200_v10      CPU_POWERPC_G2LEgp1
+#define CPU_POWERPC_MPC5200_v11      CPU_POWERPC_G2LEgp1
+#define CPU_POWERPC_MPC5200_v12      CPU_POWERPC_G2LEgp1
+#define CPU_POWERPC_MPC5200B         CPU_POWERPC_MPC5200B_v21
+#define CPU_POWERPC_MPC5200B_v20     CPU_POWERPC_G2LEgp1
+#define CPU_POWERPC_MPC5200B_v21     CPU_POWERPC_G2LEgp1
+    /* MPC82xx microcontrollers */
+#define CPU_POWERPC_MPC82xx          CPU_POWERPC_MPC8280
+#define CPU_POWERPC_MPC8240          CPU_POWERPC_MPC603
+#define CPU_POWERPC_MPC8241          CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8245          CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8247          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8248          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8250          CPU_POWERPC_MPC8250_HiP4
+#define CPU_POWERPC_MPC8250_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8250_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8255          CPU_POWERPC_MPC8255_HiP4
+#define CPU_POWERPC_MPC8255_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8255_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8260          CPU_POWERPC_MPC8260_HiP4
+#define CPU_POWERPC_MPC8260_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8260_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8264          CPU_POWERPC_MPC8264_HiP4
+#define CPU_POWERPC_MPC8264_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8264_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8265          CPU_POWERPC_MPC8265_HiP4
+#define CPU_POWERPC_MPC8265_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8265_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8266          CPU_POWERPC_MPC8266_HiP4
+#define CPU_POWERPC_MPC8266_HiP3     CPU_POWERPC_G2_HIP3
+#define CPU_POWERPC_MPC8266_HiP4     CPU_POWERPC_G2_HIP4
+#define CPU_POWERPC_MPC8270          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8271          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8272          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8275          CPU_POWERPC_G2LEgp3
+#define CPU_POWERPC_MPC8280          CPU_POWERPC_G2LEgp3
+    /* e200 family */
+    /* e200 cores */
+#define CPU_POWERPC_e200             CPU_POWERPC_e200z6
+#if 0
+    CPU_POWERPC_e200z0             = xxx,
+#endif
+#if 0
+    CPU_POWERPC_e200z1             = xxx,
+#endif
+#if 0 /* ? */
+    CPU_POWERPC_e200z3             = 0x81120000,
+#endif
+    CPU_POWERPC_e200z5             = 0x81000000,
+    CPU_POWERPC_e200z6             = 0x81120000,
+    /* MPC55xx microcontrollers */
+#define CPU_POWERPC_MPC55xx          CPU_POWERPC_MPC5567
+#if 0
+#define CPU_POWERPC_MPC5514E         CPU_POWERPC_MPC5514E_v1
+#define CPU_POWERPC_MPC5514E_v0      CPU_POWERPC_e200z0
+#define CPU_POWERPC_MPC5514E_v1      CPU_POWERPC_e200z1
+#define CPU_POWERPC_MPC5514G         CPU_POWERPC_MPC5514G_v1
+#define CPU_POWERPC_MPC5514G_v0      CPU_POWERPC_e200z0
+#define CPU_POWERPC_MPC5514G_v1      CPU_POWERPC_e200z1
+#define CPU_POWERPC_MPC5515S         CPU_POWERPC_e200z1
+#define CPU_POWERPC_MPC5516E         CPU_POWERPC_MPC5516E_v1
+#define CPU_POWERPC_MPC5516E_v0      CPU_POWERPC_e200z0
+#define CPU_POWERPC_MPC5516E_v1      CPU_POWERPC_e200z1
+#define CPU_POWERPC_MPC5516G         CPU_POWERPC_MPC5516G_v1
+#define CPU_POWERPC_MPC5516G_v0      CPU_POWERPC_e200z0
+#define CPU_POWERPC_MPC5516G_v1      CPU_POWERPC_e200z1
+#define CPU_POWERPC_MPC5516S         CPU_POWERPC_e200z1
+#endif
+#if 0
+#define CPU_POWERPC_MPC5533          CPU_POWERPC_e200z3
+#define CPU_POWERPC_MPC5534          CPU_POWERPC_e200z3
+#endif
+#define CPU_POWERPC_MPC5553          CPU_POWERPC_e200z6
+#define CPU_POWERPC_MPC5554          CPU_POWERPC_e200z6
+#define CPU_POWERPC_MPC5561          CPU_POWERPC_e200z6
+#define CPU_POWERPC_MPC5565          CPU_POWERPC_e200z6
+#define CPU_POWERPC_MPC5566          CPU_POWERPC_e200z6
+#define CPU_POWERPC_MPC5567          CPU_POWERPC_e200z6
+    /* e300 family */
+    /* e300 cores */
+#define CPU_POWERPC_e300             CPU_POWERPC_e300c3
+    CPU_POWERPC_e300c1             = 0x00830010,
+    CPU_POWERPC_e300c2             = 0x00840010,
+    CPU_POWERPC_e300c3             = 0x00850010,
+    CPU_POWERPC_e300c4             = 0x00860010,
+    /* MPC83xx microcontrollers */
+#define CPU_POWERPC_MPC831x          CPU_POWERPC_e300c3
+#define CPU_POWERPC_MPC832x          CPU_POWERPC_e300c2
+#define CPU_POWERPC_MPC834x          CPU_POWERPC_e300c1
+#define CPU_POWERPC_MPC835x          CPU_POWERPC_e300c1
+#define CPU_POWERPC_MPC836x          CPU_POWERPC_e300c1
+#define CPU_POWERPC_MPC837x          CPU_POWERPC_e300c4
+    /* e500 family */
+    /* e500 cores  */
+#define CPU_POWERPC_e500             CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_e500v1           CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_e500v2           CPU_POWERPC_e500v2_v22
+    CPU_POWERPC_e500v1_v10         = 0x80200010,
+    CPU_POWERPC_e500v1_v20         = 0x80200020,
+    CPU_POWERPC_e500v2_v10         = 0x80210010,
+    CPU_POWERPC_e500v2_v11         = 0x80210011,
+    CPU_POWERPC_e500v2_v20         = 0x80210020,
+    CPU_POWERPC_e500v2_v21         = 0x80210021,
+    CPU_POWERPC_e500v2_v22         = 0x80210022,
+    CPU_POWERPC_e500v2_v30         = 0x80210030,
+    /* MPC85xx microcontrollers */
+#define CPU_POWERPC_MPC8533          CPU_POWERPC_MPC8533_v11
+#define CPU_POWERPC_MPC8533_v10      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8533_v11      CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8533E         CPU_POWERPC_MPC8533E_v11
+#define CPU_POWERPC_MPC8533E_v10     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8533E_v11     CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8540          CPU_POWERPC_MPC8540_v21
+#define CPU_POWERPC_MPC8540_v10      CPU_POWERPC_e500v1_v10
+#define CPU_POWERPC_MPC8540_v20      CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8540_v21      CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8541          CPU_POWERPC_MPC8541_v11
+#define CPU_POWERPC_MPC8541_v10      CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8541_v11      CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8541E         CPU_POWERPC_MPC8541E_v11
+#define CPU_POWERPC_MPC8541E_v10     CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8541E_v11     CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8543          CPU_POWERPC_MPC8543_v21
+#define CPU_POWERPC_MPC8543_v10      CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8543_v11      CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8543_v20      CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8543_v21      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8543E         CPU_POWERPC_MPC8543E_v21
+#define CPU_POWERPC_MPC8543E_v10     CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8543E_v11     CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8543E_v20     CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8543E_v21     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8544          CPU_POWERPC_MPC8544_v11
+#define CPU_POWERPC_MPC8544_v10      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8544_v11      CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8544E_v11     CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8544E         CPU_POWERPC_MPC8544E_v11
+#define CPU_POWERPC_MPC8544E_v10     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8545          CPU_POWERPC_MPC8545_v21
+#define CPU_POWERPC_MPC8545_v10      CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8545_v20      CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8545_v21      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8545E         CPU_POWERPC_MPC8545E_v21
+#define CPU_POWERPC_MPC8545E_v10     CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8545E_v20     CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8545E_v21     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8547E         CPU_POWERPC_MPC8545E_v21
+#define CPU_POWERPC_MPC8547E_v10     CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8547E_v20     CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8547E_v21     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8548          CPU_POWERPC_MPC8548_v21
+#define CPU_POWERPC_MPC8548_v10      CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8548_v11      CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8548_v20      CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8548_v21      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8548E         CPU_POWERPC_MPC8548E_v21
+#define CPU_POWERPC_MPC8548E_v10     CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8548E_v11     CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8548E_v20     CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8548E_v21     CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8555          CPU_POWERPC_MPC8555_v11
+#define CPU_POWERPC_MPC8555_v10      CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8555_v11      CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8555E         CPU_POWERPC_MPC8555E_v11
+#define CPU_POWERPC_MPC8555E_v10     CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8555E_v11     CPU_POWERPC_e500v2_v11
+#define CPU_POWERPC_MPC8560          CPU_POWERPC_MPC8560_v21
+#define CPU_POWERPC_MPC8560_v10      CPU_POWERPC_e500v2_v10
+#define CPU_POWERPC_MPC8560_v20      CPU_POWERPC_e500v2_v20
+#define CPU_POWERPC_MPC8560_v21      CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8567          CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8567E         CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8568          CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8568E         CPU_POWERPC_e500v2_v22
+#define CPU_POWERPC_MPC8572          CPU_POWERPC_e500v2_v30
+#define CPU_POWERPC_MPC8572E         CPU_POWERPC_e500v2_v30
+    /* e600 family */
+    /* e600 cores */
+    CPU_POWERPC_e600               = 0x80040010,
+    /* MPC86xx microcontrollers */
+#define CPU_POWERPC_MPC8610          CPU_POWERPC_e600
+#define CPU_POWERPC_MPC8641          CPU_POWERPC_e600
+#define CPU_POWERPC_MPC8641D         CPU_POWERPC_e600
+    /* PowerPC 6xx cores */
+#define CPU_POWERPC_601              CPU_POWERPC_601_v2
+    CPU_POWERPC_601_v0             = 0x00010001,
+    CPU_POWERPC_601_v1             = 0x00010001,
+#define CPU_POWERPC_601v             CPU_POWERPC_601_v2
+    CPU_POWERPC_601_v2             = 0x00010002,
+    CPU_POWERPC_602                = 0x00050100,
+    CPU_POWERPC_603                = 0x00030100,
+#define CPU_POWERPC_603E             CPU_POWERPC_603E_v41
+    CPU_POWERPC_603E_v11           = 0x00060101,
+    CPU_POWERPC_603E_v12           = 0x00060102,
+    CPU_POWERPC_603E_v13           = 0x00060103,
+    CPU_POWERPC_603E_v14           = 0x00060104,
+    CPU_POWERPC_603E_v22           = 0x00060202,
+    CPU_POWERPC_603E_v3            = 0x00060300,
+    CPU_POWERPC_603E_v4            = 0x00060400,
+    CPU_POWERPC_603E_v41           = 0x00060401,
+    CPU_POWERPC_603E7t             = 0x00071201,
+    CPU_POWERPC_603E7v             = 0x00070100,
+    CPU_POWERPC_603E7v1            = 0x00070101,
+    CPU_POWERPC_603E7v2            = 0x00070201,
+    CPU_POWERPC_603E7              = 0x00070200,
+    CPU_POWERPC_603P               = 0x00070000,
+#define CPU_POWERPC_603R             CPU_POWERPC_603E7t
+    /* XXX: missing 0x00040303 (604) */
+    CPU_POWERPC_604                = 0x00040103,
+#define CPU_POWERPC_604E             CPU_POWERPC_604E_v24
+    /* XXX: missing 0x00091203 */
+    /* XXX: missing 0x00092110 */
+    /* XXX: missing 0x00092120 */
+    CPU_POWERPC_604E_v10           = 0x00090100,
+    CPU_POWERPC_604E_v22           = 0x00090202,
+    CPU_POWERPC_604E_v24           = 0x00090204,
+    /* XXX: missing 0x000a0100 */
+    /* XXX: missing 0x00093102 */
+    CPU_POWERPC_604R               = 0x000a0101,
+#if 0
+    CPU_POWERPC_604EV              = xxx, /* XXX: same as 604R ? */
+#endif
+    /* PowerPC 740/750 cores (aka G3) */
+    /* XXX: missing 0x00084202 */
+#define CPU_POWERPC_7x0              CPU_POWERPC_7x0_v31
+    CPU_POWERPC_7x0_v10            = 0x00080100,
+    CPU_POWERPC_7x0_v20            = 0x00080200,
+    CPU_POWERPC_7x0_v21            = 0x00080201,
+    CPU_POWERPC_7x0_v22            = 0x00080202,
+    CPU_POWERPC_7x0_v30            = 0x00080300,
+    CPU_POWERPC_7x0_v31            = 0x00080301,
+    CPU_POWERPC_740E               = 0x00080100,
+    CPU_POWERPC_750E               = 0x00080200,
+    CPU_POWERPC_7x0P               = 0x10080000,
+    /* XXX: missing 0x00087010 (CL ?) */
+#define CPU_POWERPC_750CL            CPU_POWERPC_750CL_v20
+    CPU_POWERPC_750CL_v10          = 0x00087200,
+    CPU_POWERPC_750CL_v20          = 0x00087210, /* aka rev E */
+#define CPU_POWERPC_750CX            CPU_POWERPC_750CX_v22
+    CPU_POWERPC_750CX_v10          = 0x00082100,
+    CPU_POWERPC_750CX_v20          = 0x00082200,
+    CPU_POWERPC_750CX_v21          = 0x00082201,
+    CPU_POWERPC_750CX_v22          = 0x00082202,
+#define CPU_POWERPC_750CXE           CPU_POWERPC_750CXE_v31b
+    CPU_POWERPC_750CXE_v21         = 0x00082211,
+    CPU_POWERPC_750CXE_v22         = 0x00082212,
+    CPU_POWERPC_750CXE_v23         = 0x00082213,
+    CPU_POWERPC_750CXE_v24         = 0x00082214,
+    CPU_POWERPC_750CXE_v24b        = 0x00083214,
+    CPU_POWERPC_750CXE_v30         = 0x00082310,
+    CPU_POWERPC_750CXE_v31         = 0x00082311,
+    CPU_POWERPC_750CXE_v31b        = 0x00083311,
+    CPU_POWERPC_750CXR             = 0x00083410,
+    CPU_POWERPC_750FL              = 0x70000203,
+#define CPU_POWERPC_750FX            CPU_POWERPC_750FX_v23
+    CPU_POWERPC_750FX_v10          = 0x70000100,
+    CPU_POWERPC_750FX_v20          = 0x70000200,
+    CPU_POWERPC_750FX_v21          = 0x70000201,
+    CPU_POWERPC_750FX_v22          = 0x70000202,
+    CPU_POWERPC_750FX_v23          = 0x70000203,
+    CPU_POWERPC_750GL              = 0x70020102,
+#define CPU_POWERPC_750GX            CPU_POWERPC_750GX_v12
+    CPU_POWERPC_750GX_v10          = 0x70020100,
+    CPU_POWERPC_750GX_v11          = 0x70020101,
+    CPU_POWERPC_750GX_v12          = 0x70020102,
+#define CPU_POWERPC_750L             CPU_POWERPC_750L_v32 /* Aka LoneStar */
+    CPU_POWERPC_750L_v20           = 0x00088200,
+    CPU_POWERPC_750L_v21           = 0x00088201,
+    CPU_POWERPC_750L_v22           = 0x00088202,
+    CPU_POWERPC_750L_v30           = 0x00088300,
+    CPU_POWERPC_750L_v32           = 0x00088302,
+    /* PowerPC 745/755 cores */
+#define CPU_POWERPC_7x5              CPU_POWERPC_7x5_v28
+    CPU_POWERPC_7x5_v10            = 0x00083100,
+    CPU_POWERPC_7x5_v11            = 0x00083101,
+    CPU_POWERPC_7x5_v20            = 0x00083200,
+    CPU_POWERPC_7x5_v21            = 0x00083201,
+    CPU_POWERPC_7x5_v22            = 0x00083202, /* aka D */
+    CPU_POWERPC_7x5_v23            = 0x00083203, /* aka E */
+    CPU_POWERPC_7x5_v24            = 0x00083204,
+    CPU_POWERPC_7x5_v25            = 0x00083205,
+    CPU_POWERPC_7x5_v26            = 0x00083206,
+    CPU_POWERPC_7x5_v27            = 0x00083207,
+    CPU_POWERPC_7x5_v28            = 0x00083208,
+#if 0
+    CPU_POWERPC_7x5P               = xxx,
+#endif
+    /* PowerPC 74xx cores (aka G4) */
+    /* XXX: missing 0x000C1101 */
+#define CPU_POWERPC_7400             CPU_POWERPC_7400_v29
+    CPU_POWERPC_7400_v10           = 0x000C0100,
+    CPU_POWERPC_7400_v11           = 0x000C0101,
+    CPU_POWERPC_7400_v20           = 0x000C0200,
+    CPU_POWERPC_7400_v21           = 0x000C0201,
+    CPU_POWERPC_7400_v22           = 0x000C0202,
+    CPU_POWERPC_7400_v26           = 0x000C0206,
+    CPU_POWERPC_7400_v27           = 0x000C0207,
+    CPU_POWERPC_7400_v28           = 0x000C0208,
+    CPU_POWERPC_7400_v29           = 0x000C0209,
+#define CPU_POWERPC_7410             CPU_POWERPC_7410_v14
+    CPU_POWERPC_7410_v10           = 0x800C1100,
+    CPU_POWERPC_7410_v11           = 0x800C1101,
+    CPU_POWERPC_7410_v12           = 0x800C1102, /* aka C */
+    CPU_POWERPC_7410_v13           = 0x800C1103, /* aka D */
+    CPU_POWERPC_7410_v14           = 0x800C1104, /* aka E */
+#define CPU_POWERPC_7448             CPU_POWERPC_7448_v21
+    CPU_POWERPC_7448_v10           = 0x80040100,
+    CPU_POWERPC_7448_v11           = 0x80040101,
+    CPU_POWERPC_7448_v20           = 0x80040200,
+    CPU_POWERPC_7448_v21           = 0x80040201,
+#define CPU_POWERPC_7450             CPU_POWERPC_7450_v21
+    CPU_POWERPC_7450_v10           = 0x80000100,
+    CPU_POWERPC_7450_v11           = 0x80000101,
+    CPU_POWERPC_7450_v12           = 0x80000102,
+    CPU_POWERPC_7450_v20           = 0x80000200, /* aka A, B, C, D: 2.04 */
+    CPU_POWERPC_7450_v21           = 0x80000201, /* aka E */
+#define CPU_POWERPC_74x1             CPU_POWERPC_74x1_v23
+    CPU_POWERPC_74x1_v23           = 0x80000203, /* aka G: 2.3 */
+    /* XXX: this entry might be a bug in some documentation */
+    CPU_POWERPC_74x1_v210          = 0x80000210, /* aka G: 2.3 ? */
+#define CPU_POWERPC_74x5             CPU_POWERPC_74x5_v32
+    CPU_POWERPC_74x5_v10           = 0x80010100,
+    /* XXX: missing 0x80010200 */
+    CPU_POWERPC_74x5_v21           = 0x80010201, /* aka C: 2.1 */
+    CPU_POWERPC_74x5_v32           = 0x80010302,
+    CPU_POWERPC_74x5_v33           = 0x80010303, /* aka F: 3.3 */
+    CPU_POWERPC_74x5_v34           = 0x80010304, /* aka G: 3.4 */
+#define CPU_POWERPC_74x7             CPU_POWERPC_74x7_v12
+    CPU_POWERPC_74x7_v10           = 0x80020100, /* aka A: 1.0 */
+    CPU_POWERPC_74x7_v11           = 0x80020101, /* aka B: 1.1 */
+    CPU_POWERPC_74x7_v12           = 0x80020102, /* aka C: 1.2 */
+#define CPU_POWERPC_74x7A            CPU_POWERPC_74x7A_v12
+    CPU_POWERPC_74x7A_v10          = 0x80030100, /* aka A: 1.0 */
+    CPU_POWERPC_74x7A_v11          = 0x80030101, /* aka B: 1.1 */
+    CPU_POWERPC_74x7A_v12          = 0x80030102, /* aka C: 1.2 */
+    /* 64 bits PowerPC */
+#if defined(TARGET_PPC64)
+    CPU_POWERPC_620                = 0x00140000,
+    CPU_POWERPC_630                = 0x00400000,
+    CPU_POWERPC_631                = 0x00410104,
+    CPU_POWERPC_POWER4             = 0x00350000,
+    CPU_POWERPC_POWER4P            = 0x00380000,
+     /* XXX: missing 0x003A0201 */
+    CPU_POWERPC_POWER5             = 0x003A0203,
+#define CPU_POWERPC_POWER5GR         CPU_POWERPC_POWER5
+    CPU_POWERPC_POWER5P            = 0x003B0000,
+#define CPU_POWERPC_POWER5GS         CPU_POWERPC_POWER5P
+    CPU_POWERPC_POWER6             = 0x003E0000,
+    CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
+    CPU_POWERPC_POWER6A            = 0x0F000002,
+#define CPU_POWERPC_POWER7           CPU_POWERPC_POWER7_v20
+    CPU_POWERPC_POWER7_v20         = 0x003F0200,
+    CPU_POWERPC_970                = 0x00390202,
+#define CPU_POWERPC_970FX            CPU_POWERPC_970FX_v31
+    CPU_POWERPC_970FX_v10          = 0x00391100,
+    CPU_POWERPC_970FX_v20          = 0x003C0200,
+    CPU_POWERPC_970FX_v21          = 0x003C0201,
+    CPU_POWERPC_970FX_v30          = 0x003C0300,
+    CPU_POWERPC_970FX_v31          = 0x003C0301,
+    CPU_POWERPC_970GX              = 0x00450000,
+#define CPU_POWERPC_970MP            CPU_POWERPC_970MP_v11
+    CPU_POWERPC_970MP_v10          = 0x00440100,
+    CPU_POWERPC_970MP_v11          = 0x00440101,
+#define CPU_POWERPC_CELL             CPU_POWERPC_CELL_v32
+    CPU_POWERPC_CELL_v10           = 0x00700100,
+    CPU_POWERPC_CELL_v20           = 0x00700400,
+    CPU_POWERPC_CELL_v30           = 0x00700500,
+    CPU_POWERPC_CELL_v31           = 0x00700501,
+#define CPU_POWERPC_CELL_v32         CPU_POWERPC_CELL_v31
+    CPU_POWERPC_RS64               = 0x00330000,
+    CPU_POWERPC_RS64II             = 0x00340000,
+    CPU_POWERPC_RS64III            = 0x00360000,
+    CPU_POWERPC_RS64IV             = 0x00370000,
+#endif /* defined(TARGET_PPC64) */
+    /* Original POWER */
+    /* XXX: should be POWER (RIOS), RSC3308, RSC4608,
+     * POWER2 (RIOS2) & RSC2 (P2SC) here
+     */
+#if 0
+    CPU_POWER                      = xxx, /* 0x20000 ? 0x30000 for RSC ? */
+#endif
+#if 0
+    CPU_POWER2                     = xxx, /* 0x40000 ? */
+#endif
+    /* PA Semi core */
+    CPU_POWERPC_PA6T               = 0x00900000,
+};
+
+/* System version register (used on MPC 8xxx)                                */
+enum {
+    POWERPC_SVR_NONE               = 0x00000000,
+#define POWERPC_SVR_52xx             POWERPC_SVR_5200
+#define POWERPC_SVR_5200             POWERPC_SVR_5200_v12
+    POWERPC_SVR_5200_v10           = 0x80110010,
+    POWERPC_SVR_5200_v11           = 0x80110011,
+    POWERPC_SVR_5200_v12           = 0x80110012,
+#define POWERPC_SVR_5200B            POWERPC_SVR_5200B_v21
+    POWERPC_SVR_5200B_v20          = 0x80110020,
+    POWERPC_SVR_5200B_v21          = 0x80110021,
+#define POWERPC_SVR_55xx             POWERPC_SVR_5567
+#if 0
+    POWERPC_SVR_5533               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5534               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5553               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5554               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5561               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5565               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5566               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_5567               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8313               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8313E              = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8314               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8314E              = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8315               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8315E              = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8321               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8321E              = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8323               = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8323E              = xxx,
+#endif
+    POWERPC_SVR_8343               = 0x80570010,
+    POWERPC_SVR_8343A              = 0x80570030,
+    POWERPC_SVR_8343E              = 0x80560010,
+    POWERPC_SVR_8343EA             = 0x80560030,
+#define POWERPC_SVR_8347             POWERPC_SVR_8347T
+    POWERPC_SVR_8347P              = 0x80550010, /* PBGA package */
+    POWERPC_SVR_8347T              = 0x80530010, /* TBGA package */
+#define POWERPC_SVR_8347A            POWERPC_SVR_8347AT
+    POWERPC_SVR_8347AP             = 0x80550030, /* PBGA package */
+    POWERPC_SVR_8347AT             = 0x80530030, /* TBGA package */
+#define POWERPC_SVR_8347E            POWERPC_SVR_8347ET
+    POWERPC_SVR_8347EP             = 0x80540010, /* PBGA package */
+    POWERPC_SVR_8347ET             = 0x80520010, /* TBGA package */
+#define POWERPC_SVR_8347EA            POWERPC_SVR_8347EAT
+    POWERPC_SVR_8347EAP            = 0x80540030, /* PBGA package */
+    POWERPC_SVR_8347EAT            = 0x80520030, /* TBGA package */
+    POWERPC_SVR_8349               = 0x80510010,
+    POWERPC_SVR_8349A              = 0x80510030,
+    POWERPC_SVR_8349E              = 0x80500010,
+    POWERPC_SVR_8349EA             = 0x80500030,
+#if 0
+    POWERPC_SVR_8358E              = xxx,
+#endif
+#if 0
+    POWERPC_SVR_8360E              = xxx,
+#endif
+#define POWERPC_SVR_E500             0x40000000
+    POWERPC_SVR_8377               = 0x80C70010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8377E              = 0x80C60010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8378               = 0x80C50010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8378E              = 0x80C40010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8379               = 0x80C30010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8379E              = 0x80C00010 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8533             POWERPC_SVR_8533_v11
+    POWERPC_SVR_8533_v10           = 0x80340010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8533_v11           = 0x80340011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8533E            POWERPC_SVR_8533E_v11
+    POWERPC_SVR_8533E_v10          = 0x803C0010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8533E_v11          = 0x803C0011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8540             POWERPC_SVR_8540_v21
+    POWERPC_SVR_8540_v10           = 0x80300010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8540_v20           = 0x80300020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8540_v21           = 0x80300021 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8541             POWERPC_SVR_8541_v11
+    POWERPC_SVR_8541_v10           = 0x80720010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8541_v11           = 0x80720011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8541E            POWERPC_SVR_8541E_v11
+    POWERPC_SVR_8541E_v10          = 0x807A0010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8541E_v11          = 0x807A0011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8543             POWERPC_SVR_8543_v21
+    POWERPC_SVR_8543_v10           = 0x80320010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543_v11           = 0x80320011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543_v20           = 0x80320020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543_v21           = 0x80320021 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8543E            POWERPC_SVR_8543E_v21
+    POWERPC_SVR_8543E_v10          = 0x803A0010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543E_v11          = 0x803A0011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543E_v20          = 0x803A0020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8543E_v21          = 0x803A0021 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8544             POWERPC_SVR_8544_v11
+    POWERPC_SVR_8544_v10           = 0x80340110 | POWERPC_SVR_E500,
+    POWERPC_SVR_8544_v11           = 0x80340111 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8544E            POWERPC_SVR_8544E_v11
+    POWERPC_SVR_8544E_v10          = 0x803C0110 | POWERPC_SVR_E500,
+    POWERPC_SVR_8544E_v11          = 0x803C0111 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8545             POWERPC_SVR_8545_v21
+    POWERPC_SVR_8545_v20           = 0x80310220 | POWERPC_SVR_E500,
+    POWERPC_SVR_8545_v21           = 0x80310221 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8545E            POWERPC_SVR_8545E_v21
+    POWERPC_SVR_8545E_v20          = 0x80390220 | POWERPC_SVR_E500,
+    POWERPC_SVR_8545E_v21          = 0x80390221 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8547E            POWERPC_SVR_8547E_v21
+    POWERPC_SVR_8547E_v20          = 0x80390120 | POWERPC_SVR_E500,
+    POWERPC_SVR_8547E_v21          = 0x80390121 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8548             POWERPC_SVR_8548_v21
+    POWERPC_SVR_8548_v10           = 0x80310010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548_v11           = 0x80310011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548_v20           = 0x80310020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548_v21           = 0x80310021 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8548E            POWERPC_SVR_8548E_v21
+    POWERPC_SVR_8548E_v10          = 0x80390010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548E_v11          = 0x80390011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548E_v20          = 0x80390020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8548E_v21          = 0x80390021 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8555             POWERPC_SVR_8555_v11
+    POWERPC_SVR_8555_v10           = 0x80710010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8555_v11           = 0x80710011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8555E            POWERPC_SVR_8555_v11
+    POWERPC_SVR_8555E_v10          = 0x80790010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8555E_v11          = 0x80790011 | POWERPC_SVR_E500,
+#define POWERPC_SVR_8560             POWERPC_SVR_8560_v21
+    POWERPC_SVR_8560_v10           = 0x80700010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8560_v20           = 0x80700020 | POWERPC_SVR_E500,
+    POWERPC_SVR_8560_v21           = 0x80700021 | POWERPC_SVR_E500,
+    POWERPC_SVR_8567               = 0x80750111 | POWERPC_SVR_E500,
+    POWERPC_SVR_8567E              = 0x807D0111 | POWERPC_SVR_E500,
+    POWERPC_SVR_8568               = 0x80750011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8568E              = 0x807D0011 | POWERPC_SVR_E500,
+    POWERPC_SVR_8572               = 0x80E00010 | POWERPC_SVR_E500,
+    POWERPC_SVR_8572E              = 0x80E80010 | POWERPC_SVR_E500,
+#if 0
+    POWERPC_SVR_8610               = xxx,
+#endif
+    POWERPC_SVR_8641               = 0x80900021,
+    POWERPC_SVR_8641D              = 0x80900121,
+};
+
+/*****************************************************************************/
+/* PowerPC CPU definitions                                                   */
+#define POWERPC_DEF_SVR(_name, _pvr, _svr, _type)                             \
+    {                                                                         \
+        .name         = _name,                                                \
+        .pvr          = _pvr,                                                 \
+        .svr          = _svr,                                                 \
+        .insns_flags  = glue(POWERPC_INSNS_,_type),                           \
+        .insns_flags2 = glue(POWERPC_INSNS2_,_type),                          \
+        .msr_mask     = glue(POWERPC_MSRM_,_type),                            \
+        .mmu_model    = glue(POWERPC_MMU_,_type),                             \
+        .excp_model   = glue(POWERPC_EXCP_,_type),                            \
+        .bus_model    = glue(POWERPC_INPUT_,_type),                           \
+        .bfd_mach     = glue(POWERPC_BFDM_,_type),                            \
+        .flags        = glue(POWERPC_FLAG_,_type),                            \
+        .init_proc    = &glue(init_proc_,_type),                              \
+        .check_pow    = &glue(check_pow_,_type),                              \
+    }
+#define POWERPC_DEF(_name, _pvr, _type)                                       \
+POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type)
+
+static const ppc_def_t ppc_defs[] = {
+    /* Embedded PowerPC                                                      */
+    /* PowerPC 401 family                                                    */
+    /* Generic PowerPC 401 */
+    POWERPC_DEF("401",           CPU_POWERPC_401,                    401),
+    /* PowerPC 401 cores                                                     */
+    /* PowerPC 401A1 */
+    POWERPC_DEF("401A1",         CPU_POWERPC_401A1,                  401),
+    /* PowerPC 401B2                                                         */
+    POWERPC_DEF("401B2",         CPU_POWERPC_401B2,                  401x2),
+#if defined (TODO)
+    /* PowerPC 401B3                                                         */
+    POWERPC_DEF("401B3",         CPU_POWERPC_401B3,                  401x3),
+#endif
+    /* PowerPC 401C2                                                         */
+    POWERPC_DEF("401C2",         CPU_POWERPC_401C2,                  401x2),
+    /* PowerPC 401D2                                                         */
+    POWERPC_DEF("401D2",         CPU_POWERPC_401D2,                  401x2),
+    /* PowerPC 401E2                                                         */
+    POWERPC_DEF("401E2",         CPU_POWERPC_401E2,                  401x2),
+    /* PowerPC 401F2                                                         */
+    POWERPC_DEF("401F2",         CPU_POWERPC_401F2,                  401x2),
+    /* PowerPC 401G2                                                         */
+    /* XXX: to be checked */
+    POWERPC_DEF("401G2",         CPU_POWERPC_401G2,                  401x2),
+    /* PowerPC 401 microcontrolers                                           */
+#if defined (TODO)
+    /* PowerPC 401GF                                                         */
+    POWERPC_DEF("401GF",         CPU_POWERPC_401GF,                  401),
+#endif
+    /* IOP480 (401 microcontroler)                                           */
+    POWERPC_DEF("IOP480",        CPU_POWERPC_IOP480,                 IOP480),
+    /* IBM Processor for Network Resources                                   */
+    POWERPC_DEF("Cobra",         CPU_POWERPC_COBRA,                  401),
+#if defined (TODO)
+    POWERPC_DEF("Xipchip",       CPU_POWERPC_XIPCHIP,                401),
+#endif
+    /* PowerPC 403 family                                                    */
+    /* Generic PowerPC 403                                                   */
+    POWERPC_DEF("403",           CPU_POWERPC_403,                    403),
+    /* PowerPC 403 microcontrolers                                           */
+    /* PowerPC 403 GA                                                        */
+    POWERPC_DEF("403GA",         CPU_POWERPC_403GA,                  403),
+    /* PowerPC 403 GB                                                        */
+    POWERPC_DEF("403GB",         CPU_POWERPC_403GB,                  403),
+    /* PowerPC 403 GC                                                        */
+    POWERPC_DEF("403GC",         CPU_POWERPC_403GC,                  403),
+    /* PowerPC 403 GCX                                                       */
+    POWERPC_DEF("403GCX",        CPU_POWERPC_403GCX,                 403GCX),
+#if defined (TODO)
+    /* PowerPC 403 GP                                                        */
+    POWERPC_DEF("403GP",         CPU_POWERPC_403GP,                  403),
+#endif
+    /* PowerPC 405 family                                                    */
+    /* Generic PowerPC 405                                                   */
+    POWERPC_DEF("405",           CPU_POWERPC_405,                    405),
+    /* PowerPC 405 cores                                                     */
+#if defined (TODO)
+    /* PowerPC 405 A3                                                        */
+    POWERPC_DEF("405A3",         CPU_POWERPC_405A3,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 A4                                                        */
+    POWERPC_DEF("405A4",         CPU_POWERPC_405A4,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 B3                                                        */
+    POWERPC_DEF("405B3",         CPU_POWERPC_405B3,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 B4                                                        */
+    POWERPC_DEF("405B4",         CPU_POWERPC_405B4,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 C3                                                        */
+    POWERPC_DEF("405C3",         CPU_POWERPC_405C3,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 C4                                                        */
+    POWERPC_DEF("405C4",         CPU_POWERPC_405C4,                  405),
+#endif
+    /* PowerPC 405 D2                                                        */
+    POWERPC_DEF("405D2",         CPU_POWERPC_405D2,                  405),
+#if defined (TODO)
+    /* PowerPC 405 D3                                                        */
+    POWERPC_DEF("405D3",         CPU_POWERPC_405D3,                  405),
+#endif
+    /* PowerPC 405 D4                                                        */
+    POWERPC_DEF("405D4",         CPU_POWERPC_405D4,                  405),
+#if defined (TODO)
+    /* PowerPC 405 D5                                                        */
+    POWERPC_DEF("405D5",         CPU_POWERPC_405D5,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 E4                                                        */
+    POWERPC_DEF("405E4",         CPU_POWERPC_405E4,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F4                                                        */
+    POWERPC_DEF("405F4",         CPU_POWERPC_405F4,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F5                                                        */
+    POWERPC_DEF("405F5",         CPU_POWERPC_405F5,                  405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F6                                                        */
+    POWERPC_DEF("405F6",         CPU_POWERPC_405F6,                  405),
+#endif
+    /* PowerPC 405 microcontrolers                                           */
+    /* PowerPC 405 CR                                                        */
+    POWERPC_DEF("405CR",         CPU_POWERPC_405CR,                  405),
+    /* PowerPC 405 CRa                                                       */
+    POWERPC_DEF("405CRa",        CPU_POWERPC_405CRa,                 405),
+    /* PowerPC 405 CRb                                                       */
+    POWERPC_DEF("405CRb",        CPU_POWERPC_405CRb,                 405),
+    /* PowerPC 405 CRc                                                       */
+    POWERPC_DEF("405CRc",        CPU_POWERPC_405CRc,                 405),
+    /* PowerPC 405 EP                                                        */
+    POWERPC_DEF("405EP",         CPU_POWERPC_405EP,                  405),
+#if defined(TODO)
+    /* PowerPC 405 EXr                                                       */
+    POWERPC_DEF("405EXr",        CPU_POWERPC_405EXr,                 405),
+#endif
+    /* PowerPC 405 EZ                                                        */
+    POWERPC_DEF("405EZ",         CPU_POWERPC_405EZ,                  405),
+#if defined(TODO)
+    /* PowerPC 405 FX                                                        */
+    POWERPC_DEF("405FX",         CPU_POWERPC_405FX,                  405),
+#endif
+    /* PowerPC 405 GP                                                        */
+    POWERPC_DEF("405GP",         CPU_POWERPC_405GP,                  405),
+    /* PowerPC 405 GPa                                                       */
+    POWERPC_DEF("405GPa",        CPU_POWERPC_405GPa,                 405),
+    /* PowerPC 405 GPb                                                       */
+    POWERPC_DEF("405GPb",        CPU_POWERPC_405GPb,                 405),
+    /* PowerPC 405 GPc                                                       */
+    POWERPC_DEF("405GPc",        CPU_POWERPC_405GPc,                 405),
+    /* PowerPC 405 GPd                                                       */
+    POWERPC_DEF("405GPd",        CPU_POWERPC_405GPd,                 405),
+    /* PowerPC 405 GPe                                                       */
+    POWERPC_DEF("405GPe",        CPU_POWERPC_405GPe,                 405),
+    /* PowerPC 405 GPR                                                       */
+    POWERPC_DEF("405GPR",        CPU_POWERPC_405GPR,                 405),
+#if defined(TODO)
+    /* PowerPC 405 H                                                         */
+    POWERPC_DEF("405H",          CPU_POWERPC_405H,                   405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 L                                                         */
+    POWERPC_DEF("405L",          CPU_POWERPC_405L,                   405),
+#endif
+    /* PowerPC 405 LP                                                        */
+    POWERPC_DEF("405LP",         CPU_POWERPC_405LP,                  405),
+#if defined(TODO)
+    /* PowerPC 405 PM                                                        */
+    POWERPC_DEF("405PM",         CPU_POWERPC_405PM,                  405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 PS                                                        */
+    POWERPC_DEF("405PS",         CPU_POWERPC_405PS,                  405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 S                                                         */
+    POWERPC_DEF("405S",          CPU_POWERPC_405S,                   405),
+#endif
+    /* Npe405 H                                                              */
+    POWERPC_DEF("Npe405H",       CPU_POWERPC_NPE405H,                405),
+    /* Npe405 H2                                                             */
+    POWERPC_DEF("Npe405H2",      CPU_POWERPC_NPE405H2,               405),
+    /* Npe405 L                                                              */
+    POWERPC_DEF("Npe405L",       CPU_POWERPC_NPE405L,                405),
+    /* Npe4GS3                                                               */
+    POWERPC_DEF("Npe4GS3",       CPU_POWERPC_NPE4GS3,                405),
+#if defined (TODO)
+    POWERPC_DEF("Npcxx1",        CPU_POWERPC_NPCxx1,                 405),
+#endif
+#if defined (TODO)
+    POWERPC_DEF("Npr161",        CPU_POWERPC_NPR161,                 405),
+#endif
+#if defined (TODO)
+    /* PowerPC LC77700 (Sanyo)                                               */
+    POWERPC_DEF("LC77700",       CPU_POWERPC_LC77700,                405),
+#endif
+    /* PowerPC 401/403/405 based set-top-box microcontrolers                 */
+#if defined (TODO)
+    /* STB010000                                                             */
+    POWERPC_DEF("STB01000",      CPU_POWERPC_STB01000,               401x2),
+#endif
+#if defined (TODO)
+    /* STB01010                                                              */
+    POWERPC_DEF("STB01010",      CPU_POWERPC_STB01010,               401x2),
+#endif
+#if defined (TODO)
+    /* STB0210                                                               */
+    POWERPC_DEF("STB0210",       CPU_POWERPC_STB0210,                401x3),
+#endif
+    /* STB03xx                                                               */
+    POWERPC_DEF("STB03",         CPU_POWERPC_STB03,                  405),
+#if defined (TODO)
+    /* STB043x                                                               */
+    POWERPC_DEF("STB043",        CPU_POWERPC_STB043,                 405),
+#endif
+#if defined (TODO)
+    /* STB045x                                                               */
+    POWERPC_DEF("STB045",        CPU_POWERPC_STB045,                 405),
+#endif
+    /* STB04xx                                                               */
+    POWERPC_DEF("STB04",         CPU_POWERPC_STB04,                  405),
+    /* STB25xx                                                               */
+    POWERPC_DEF("STB25",         CPU_POWERPC_STB25,                  405),
+#if defined (TODO)
+    /* STB130                                                                */
+    POWERPC_DEF("STB130",        CPU_POWERPC_STB130,                 405),
+#endif
+    /* Xilinx PowerPC 405 cores                                              */
+    POWERPC_DEF("x2vp4",         CPU_POWERPC_X2VP4,                  405),
+    POWERPC_DEF("x2vp7",         CPU_POWERPC_X2VP7,                  405),
+    POWERPC_DEF("x2vp20",        CPU_POWERPC_X2VP20,                 405),
+    POWERPC_DEF("x2vp50",        CPU_POWERPC_X2VP50,                 405),
+#if defined (TODO)
+    /* Zarlink ZL10310                                                       */
+    POWERPC_DEF("zl10310",       CPU_POWERPC_ZL10310,                405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10311                                                       */
+    POWERPC_DEF("zl10311",       CPU_POWERPC_ZL10311,                405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10320                                                       */
+    POWERPC_DEF("zl10320",       CPU_POWERPC_ZL10320,                405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10321                                                       */
+    POWERPC_DEF("zl10321",       CPU_POWERPC_ZL10321,                405),
+#endif
+    /* PowerPC 440 family                                                    */
+#if defined(TODO_USER_ONLY)
+    /* Generic PowerPC 440                                                   */
+    POWERPC_DEF("440",           CPU_POWERPC_440,                    440GP),
+#endif
+    /* PowerPC 440 cores                                                     */
+#if defined (TODO)
+    /* PowerPC 440 A4                                                        */
+    POWERPC_DEF("440A4",         CPU_POWERPC_440A4,                  440x4),
+#endif
+    /* PowerPC 440 Xilinx 5                                                  */
+    POWERPC_DEF("440-Xilinx",    CPU_POWERPC_440_XILINX,             440x5),
+#if defined (TODO)
+    /* PowerPC 440 A5                                                        */
+    POWERPC_DEF("440A5",         CPU_POWERPC_440A5,                  440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 B4                                                        */
+    POWERPC_DEF("440B4",         CPU_POWERPC_440B4,                  440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 G4                                                        */
+    POWERPC_DEF("440G4",         CPU_POWERPC_440G4,                  440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 F5                                                        */
+    POWERPC_DEF("440F5",         CPU_POWERPC_440F5,                  440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 G5                                                        */
+    POWERPC_DEF("440G5",         CPU_POWERPC_440G5,                  440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440H4                                                         */
+    POWERPC_DEF("440H4",         CPU_POWERPC_440H4,                  440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440H6                                                         */
+    POWERPC_DEF("440H6",         CPU_POWERPC_440H6,                  440Gx5),
+#endif
+    /* PowerPC 440 microcontrolers                                           */
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 EP                                                        */
+    POWERPC_DEF("440EP",         CPU_POWERPC_440EP,                  440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 EPa                                                       */
+    POWERPC_DEF("440EPa",        CPU_POWERPC_440EPa,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 EPb                                                       */
+    POWERPC_DEF("440EPb",        CPU_POWERPC_440EPb,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 EPX                                                       */
+    POWERPC_DEF("440EPX",        CPU_POWERPC_440EPX,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GP                                                        */
+    POWERPC_DEF("440GP",         CPU_POWERPC_440GP,                  440GP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GPb                                                       */
+    POWERPC_DEF("440GPb",        CPU_POWERPC_440GPb,                 440GP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GPc                                                       */
+    POWERPC_DEF("440GPc",        CPU_POWERPC_440GPc,                 440GP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GR                                                        */
+    POWERPC_DEF("440GR",         CPU_POWERPC_440GR,                  440x5),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GRa                                                       */
+    POWERPC_DEF("440GRa",        CPU_POWERPC_440GRa,                 440x5),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GRX                                                       */
+    POWERPC_DEF("440GRX",        CPU_POWERPC_440GRX,                 440x5),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GX                                                        */
+    POWERPC_DEF("440GX",         CPU_POWERPC_440GX,                  440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GXa                                                       */
+    POWERPC_DEF("440GXa",        CPU_POWERPC_440GXa,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GXb                                                       */
+    POWERPC_DEF("440GXb",        CPU_POWERPC_440GXb,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GXc                                                       */
+    POWERPC_DEF("440GXc",        CPU_POWERPC_440GXc,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 GXf                                                       */
+    POWERPC_DEF("440GXf",        CPU_POWERPC_440GXf,                 440EP),
+#endif
+#if defined(TODO)
+    /* PowerPC 440 S                                                         */
+    POWERPC_DEF("440S",          CPU_POWERPC_440S,                   440),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 SP                                                        */
+    POWERPC_DEF("440SP",         CPU_POWERPC_440SP,                  440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 SP2                                                       */
+    POWERPC_DEF("440SP2",        CPU_POWERPC_440SP2,                 440EP),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* PowerPC 440 SPE                                                       */
+    POWERPC_DEF("440SPE",        CPU_POWERPC_440SPE,                 440EP),
+#endif
+    /* PowerPC 460 family                                                    */
+#if defined (TODO)
+    /* Generic PowerPC 464                                                   */
+    POWERPC_DEF("464",           CPU_POWERPC_464,                    460),
+#endif
+    /* PowerPC 464 microcontrolers                                           */
+#if defined (TODO)
+    /* PowerPC 464H90                                                        */
+    POWERPC_DEF("464H90",        CPU_POWERPC_464H90,                 460),
+#endif
+#if defined (TODO)
+    /* PowerPC 464H90F                                                       */
+    POWERPC_DEF("464H90F",       CPU_POWERPC_464H90F,                460F),
+#endif
+    /* Freescale embedded PowerPC cores                                      */
+    /* MPC5xx family (aka RCPU)                                              */
+#if defined(TODO_USER_ONLY)
+    /* Generic MPC5xx core                                                   */
+    POWERPC_DEF("MPC5xx",        CPU_POWERPC_MPC5xx,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* Codename for MPC5xx core                                              */
+    POWERPC_DEF("RCPU",          CPU_POWERPC_MPC5xx,                 MPC5xx),
+#endif
+    /* MPC5xx microcontrollers                                               */
+#if defined(TODO_USER_ONLY)
+    /* MGT560                                                                */
+    POWERPC_DEF("MGT560",        CPU_POWERPC_MGT560,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC509                                                                */
+    POWERPC_DEF("MPC509",        CPU_POWERPC_MPC509,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC533                                                                */
+    POWERPC_DEF("MPC533",        CPU_POWERPC_MPC533,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC534                                                                */
+    POWERPC_DEF("MPC534",        CPU_POWERPC_MPC534,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC555                                                                */
+    POWERPC_DEF("MPC555",        CPU_POWERPC_MPC555,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC556                                                                */
+    POWERPC_DEF("MPC556",        CPU_POWERPC_MPC556,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC560                                                                */
+    POWERPC_DEF("MPC560",        CPU_POWERPC_MPC560,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC561                                                                */
+    POWERPC_DEF("MPC561",        CPU_POWERPC_MPC561,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC562                                                                */
+    POWERPC_DEF("MPC562",        CPU_POWERPC_MPC562,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC563                                                                */
+    POWERPC_DEF("MPC563",        CPU_POWERPC_MPC563,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC564                                                                */
+    POWERPC_DEF("MPC564",        CPU_POWERPC_MPC564,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC565                                                                */
+    POWERPC_DEF("MPC565",        CPU_POWERPC_MPC565,                 MPC5xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC566                                                                */
+    POWERPC_DEF("MPC566",        CPU_POWERPC_MPC566,                 MPC5xx),
+#endif
+    /* MPC8xx family (aka PowerQUICC)                                        */
+#if defined(TODO_USER_ONLY)
+    /* Generic MPC8xx core                                                   */
+    POWERPC_DEF("MPC8xx",        CPU_POWERPC_MPC8xx,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* Codename for MPC8xx core                                              */
+    POWERPC_DEF("PowerQUICC",    CPU_POWERPC_MPC8xx,                 MPC8xx),
+#endif
+    /* MPC8xx microcontrollers                                               */
+#if defined(TODO_USER_ONLY)
+    /* MGT823                                                                */
+    POWERPC_DEF("MGT823",        CPU_POWERPC_MGT823,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC821                                                                */
+    POWERPC_DEF("MPC821",        CPU_POWERPC_MPC821,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC823                                                                */
+    POWERPC_DEF("MPC823",        CPU_POWERPC_MPC823,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC850                                                                */
+    POWERPC_DEF("MPC850",        CPU_POWERPC_MPC850,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC852T                                                               */
+    POWERPC_DEF("MPC852T",       CPU_POWERPC_MPC852T,                MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC855T                                                               */
+    POWERPC_DEF("MPC855T",       CPU_POWERPC_MPC855T,                MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC857                                                                */
+    POWERPC_DEF("MPC857",        CPU_POWERPC_MPC857,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC859                                                                */
+    POWERPC_DEF("MPC859",        CPU_POWERPC_MPC859,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC860                                                                */
+    POWERPC_DEF("MPC860",        CPU_POWERPC_MPC860,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC862                                                                */
+    POWERPC_DEF("MPC862",        CPU_POWERPC_MPC862,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC866                                                                */
+    POWERPC_DEF("MPC866",        CPU_POWERPC_MPC866,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC870                                                                */
+    POWERPC_DEF("MPC870",        CPU_POWERPC_MPC870,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC875                                                                */
+    POWERPC_DEF("MPC875",        CPU_POWERPC_MPC875,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC880                                                                */
+    POWERPC_DEF("MPC880",        CPU_POWERPC_MPC880,                 MPC8xx),
+#endif
+#if defined(TODO_USER_ONLY)
+    /* MPC885                                                                */
+    POWERPC_DEF("MPC885",        CPU_POWERPC_MPC885,                 MPC8xx),
+#endif
+    /* MPC82xx family (aka PowerQUICC-II)                                    */
+    /* Generic MPC52xx core                                                  */
+    POWERPC_DEF_SVR("MPC52xx",
+                    CPU_POWERPC_MPC52xx,      POWERPC_SVR_52xx,      G2LE),
+    /* Generic MPC82xx core                                                  */
+    POWERPC_DEF("MPC82xx",       CPU_POWERPC_MPC82xx,                G2),
+    /* Codename for MPC82xx                                                  */
+    POWERPC_DEF("PowerQUICC-II", CPU_POWERPC_MPC82xx,                G2),
+    /* PowerPC G2 core                                                       */
+    POWERPC_DEF("G2",            CPU_POWERPC_G2,                     G2),
+    /* PowerPC G2 H4 core                                                    */
+    POWERPC_DEF("G2H4",          CPU_POWERPC_G2H4,                   G2),
+    /* PowerPC G2 GP core                                                    */
+    POWERPC_DEF("G2GP",          CPU_POWERPC_G2gp,                   G2),
+    /* PowerPC G2 LS core                                                    */
+    POWERPC_DEF("G2LS",          CPU_POWERPC_G2ls,                   G2),
+    /* PowerPC G2 HiP3 core                                                  */
+    POWERPC_DEF("G2HiP3",        CPU_POWERPC_G2_HIP3,                G2),
+    /* PowerPC G2 HiP4 core                                                  */
+    POWERPC_DEF("G2HiP4",        CPU_POWERPC_G2_HIP4,                G2),
+    /* PowerPC MPC603 core                                                   */
+    POWERPC_DEF("MPC603",        CPU_POWERPC_MPC603,                 603E),
+    /* PowerPC G2le core (same as G2 plus little-endian mode support)        */
+    POWERPC_DEF("G2le",          CPU_POWERPC_G2LE,                   G2LE),
+    /* PowerPC G2LE GP core                                                  */
+    POWERPC_DEF("G2leGP",        CPU_POWERPC_G2LEgp,                 G2LE),
+    /* PowerPC G2LE LS core                                                  */
+    POWERPC_DEF("G2leLS",        CPU_POWERPC_G2LEls,                 G2LE),
+    /* PowerPC G2LE GP1 core                                                 */
+    POWERPC_DEF("G2leGP1",       CPU_POWERPC_G2LEgp1,                G2LE),
+    /* PowerPC G2LE GP3 core                                                 */
+    POWERPC_DEF("G2leGP3",       CPU_POWERPC_G2LEgp1,                G2LE),
+    /* PowerPC MPC603 microcontrollers                                       */
+    /* MPC8240                                                               */
+    POWERPC_DEF("MPC8240",       CPU_POWERPC_MPC8240,                603E),
+    /* PowerPC G2 microcontrollers                                           */
+#if defined(TODO)
+    /* MPC5121                                                               */
+    POWERPC_DEF_SVR("MPC5121",
+                    CPU_POWERPC_MPC5121,      POWERPC_SVR_5121,      G2LE),
+#endif
+    /* MPC5200                                                               */
+    POWERPC_DEF_SVR("MPC5200",
+                    CPU_POWERPC_MPC5200,      POWERPC_SVR_5200,      G2LE),
+    /* MPC5200 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC5200_v10",
+                    CPU_POWERPC_MPC5200_v10,  POWERPC_SVR_5200_v10,  G2LE),
+    /* MPC5200 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC5200_v11",
+                    CPU_POWERPC_MPC5200_v11,  POWERPC_SVR_5200_v11,  G2LE),
+    /* MPC5200 v1.2                                                          */
+    POWERPC_DEF_SVR("MPC5200_v12",
+                    CPU_POWERPC_MPC5200_v12,  POWERPC_SVR_5200_v12,  G2LE),
+    /* MPC5200B                                                              */
+    POWERPC_DEF_SVR("MPC5200B",
+                    CPU_POWERPC_MPC5200B,     POWERPC_SVR_5200B,     G2LE),
+    /* MPC5200B v2.0                                                         */
+    POWERPC_DEF_SVR("MPC5200B_v20",
+                    CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE),
+    /* MPC5200B v2.1                                                         */
+    POWERPC_DEF_SVR("MPC5200B_v21",
+                    CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE),
+    /* MPC8241                                                               */
+    POWERPC_DEF("MPC8241",       CPU_POWERPC_MPC8241,                G2),
+    /* MPC8245                                                               */
+    POWERPC_DEF("MPC8245",       CPU_POWERPC_MPC8245,                G2),
+    /* MPC8247                                                               */
+    POWERPC_DEF("MPC8247",       CPU_POWERPC_MPC8247,                G2LE),
+    /* MPC8248                                                               */
+    POWERPC_DEF("MPC8248",       CPU_POWERPC_MPC8248,                G2LE),
+    /* MPC8250                                                               */
+    POWERPC_DEF("MPC8250",       CPU_POWERPC_MPC8250,                G2),
+    /* MPC8250 HiP3                                                          */
+    POWERPC_DEF("MPC8250_HiP3",  CPU_POWERPC_MPC8250_HiP3,           G2),
+    /* MPC8250 HiP4                                                          */
+    POWERPC_DEF("MPC8250_HiP4",  CPU_POWERPC_MPC8250_HiP4,           G2),
+    /* MPC8255                                                               */
+    POWERPC_DEF("MPC8255",       CPU_POWERPC_MPC8255,                G2),
+    /* MPC8255 HiP3                                                          */
+    POWERPC_DEF("MPC8255_HiP3",  CPU_POWERPC_MPC8255_HiP3,           G2),
+    /* MPC8255 HiP4                                                          */
+    POWERPC_DEF("MPC8255_HiP4",  CPU_POWERPC_MPC8255_HiP4,           G2),
+    /* MPC8260                                                               */
+    POWERPC_DEF("MPC8260",       CPU_POWERPC_MPC8260,                G2),
+    /* MPC8260 HiP3                                                          */
+    POWERPC_DEF("MPC8260_HiP3",  CPU_POWERPC_MPC8260_HiP3,           G2),
+    /* MPC8260 HiP4                                                          */
+    POWERPC_DEF("MPC8260_HiP4",  CPU_POWERPC_MPC8260_HiP4,           G2),
+    /* MPC8264                                                               */
+    POWERPC_DEF("MPC8264",       CPU_POWERPC_MPC8264,                G2),
+    /* MPC8264 HiP3                                                          */
+    POWERPC_DEF("MPC8264_HiP3",  CPU_POWERPC_MPC8264_HiP3,           G2),
+    /* MPC8264 HiP4                                                          */
+    POWERPC_DEF("MPC8264_HiP4",  CPU_POWERPC_MPC8264_HiP4,           G2),
+    /* MPC8265                                                               */
+    POWERPC_DEF("MPC8265",       CPU_POWERPC_MPC8265,                G2),
+    /* MPC8265 HiP3                                                          */
+    POWERPC_DEF("MPC8265_HiP3",  CPU_POWERPC_MPC8265_HiP3,           G2),
+    /* MPC8265 HiP4                                                          */
+    POWERPC_DEF("MPC8265_HiP4",  CPU_POWERPC_MPC8265_HiP4,           G2),
+    /* MPC8266                                                               */
+    POWERPC_DEF("MPC8266",       CPU_POWERPC_MPC8266,                G2),
+    /* MPC8266 HiP3                                                          */
+    POWERPC_DEF("MPC8266_HiP3",  CPU_POWERPC_MPC8266_HiP3,           G2),
+    /* MPC8266 HiP4                                                          */
+    POWERPC_DEF("MPC8266_HiP4",  CPU_POWERPC_MPC8266_HiP4,           G2),
+    /* MPC8270                                                               */
+    POWERPC_DEF("MPC8270",       CPU_POWERPC_MPC8270,                G2LE),
+    /* MPC8271                                                               */
+    POWERPC_DEF("MPC8271",       CPU_POWERPC_MPC8271,                G2LE),
+    /* MPC8272                                                               */
+    POWERPC_DEF("MPC8272",       CPU_POWERPC_MPC8272,                G2LE),
+    /* MPC8275                                                               */
+    POWERPC_DEF("MPC8275",       CPU_POWERPC_MPC8275,                G2LE),
+    /* MPC8280                                                               */
+    POWERPC_DEF("MPC8280",       CPU_POWERPC_MPC8280,                G2LE),
+    /* e200 family                                                           */
+    /* Generic PowerPC e200 core                                             */
+    POWERPC_DEF("e200",          CPU_POWERPC_e200,                   e200),
+    /* Generic MPC55xx core                                                  */
+#if defined (TODO)
+    POWERPC_DEF_SVR("MPC55xx",
+                    CPU_POWERPC_MPC55xx,      POWERPC_SVR_55xx,      e200),
+#endif
+#if defined (TODO)
+    /* PowerPC e200z0 core                                                   */
+    POWERPC_DEF("e200z0",        CPU_POWERPC_e200z0,                 e200),
+#endif
+#if defined (TODO)
+    /* PowerPC e200z1 core                                                   */
+    POWERPC_DEF("e200z1",        CPU_POWERPC_e200z1,                 e200),
+#endif
+#if defined (TODO)
+    /* PowerPC e200z3 core                                                   */
+    POWERPC_DEF("e200z3",        CPU_POWERPC_e200z3,                 e200),
+#endif
+    /* PowerPC e200z5 core                                                   */
+    POWERPC_DEF("e200z5",        CPU_POWERPC_e200z5,                 e200),
+    /* PowerPC e200z6 core                                                   */
+    POWERPC_DEF("e200z6",        CPU_POWERPC_e200z6,                 e200),
+    /* PowerPC e200 microcontrollers                                         */
+#if defined (TODO)
+    /* MPC5514E                                                              */
+    POWERPC_DEF_SVR("MPC5514E",
+                    CPU_POWERPC_MPC5514E,     POWERPC_SVR_5514E,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5514E v0                                                           */
+    POWERPC_DEF_SVR("MPC5514E_v0",
+                    CPU_POWERPC_MPC5514E_v0,  POWERPC_SVR_5514E_v0,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5514E v1                                                           */
+    POWERPC_DEF_SVR("MPC5514E_v1",
+                    CPU_POWERPC_MPC5514E_v1,  POWERPC_SVR_5514E_v1,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5514G                                                              */
+    POWERPC_DEF_SVR("MPC5514G",
+                    CPU_POWERPC_MPC5514G,     POWERPC_SVR_5514G,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5514G v0                                                           */
+    POWERPC_DEF_SVR("MPC5514G_v0",
+                    CPU_POWERPC_MPC5514G_v0,  POWERPC_SVR_5514G_v0,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5514G v1                                                           */
+    POWERPC_DEF_SVR("MPC5514G_v1",
+                    CPU_POWERPC_MPC5514G_v1,  POWERPC_SVR_5514G_v1,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5515S                                                              */
+    POWERPC_DEF_SVR("MPC5515S",
+                    CPU_POWERPC_MPC5515S,     POWERPC_SVR_5515S,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5516E                                                              */
+    POWERPC_DEF_SVR("MPC5516E",
+                    CPU_POWERPC_MPC5516E,     POWERPC_SVR_5516E,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5516E v0                                                           */
+    POWERPC_DEF_SVR("MPC5516E_v0",
+                    CPU_POWERPC_MPC5516E_v0,  POWERPC_SVR_5516E_v0,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5516E v1                                                           */
+    POWERPC_DEF_SVR("MPC5516E_v1",
+                    CPU_POWERPC_MPC5516E_v1,  POWERPC_SVR_5516E_v1,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5516G                                                              */
+    POWERPC_DEF_SVR("MPC5516G",
+                    CPU_POWERPC_MPC5516G,     POWERPC_SVR_5516G,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5516G v0                                                           */
+    POWERPC_DEF_SVR("MPC5516G_v0",
+                    CPU_POWERPC_MPC5516G_v0,  POWERPC_SVR_5516G_v0,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5516G v1                                                           */
+    POWERPC_DEF_SVR("MPC5516G_v1",
+                    CPU_POWERPC_MPC5516G_v1,  POWERPC_SVR_5516G_v1,  e200),
+#endif
+#if defined (TODO)
+    /* MPC5516S                                                              */
+    POWERPC_DEF_SVR("MPC5516S",
+                    CPU_POWERPC_MPC5516S,     POWERPC_SVR_5516S,     e200),
+#endif
+#if defined (TODO)
+    /* MPC5533                                                               */
+    POWERPC_DEF_SVR("MPC5533",
+                    CPU_POWERPC_MPC5533,      POWERPC_SVR_5533,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5534                                                               */
+    POWERPC_DEF_SVR("MPC5534",
+                    CPU_POWERPC_MPC5534,      POWERPC_SVR_5534,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5553                                                               */
+    POWERPC_DEF_SVR("MPC5553",
+                    CPU_POWERPC_MPC5553,      POWERPC_SVR_5553,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5554                                                               */
+    POWERPC_DEF_SVR("MPC5554",
+                    CPU_POWERPC_MPC5554,      POWERPC_SVR_5554,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5561                                                               */
+    POWERPC_DEF_SVR("MPC5561",
+                    CPU_POWERPC_MPC5561,      POWERPC_SVR_5561,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5565                                                               */
+    POWERPC_DEF_SVR("MPC5565",
+                    CPU_POWERPC_MPC5565,      POWERPC_SVR_5565,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5566                                                               */
+    POWERPC_DEF_SVR("MPC5566",
+                    CPU_POWERPC_MPC5566,      POWERPC_SVR_5566,      e200),
+#endif
+#if defined (TODO)
+    /* MPC5567                                                               */
+    POWERPC_DEF_SVR("MPC5567",
+                    CPU_POWERPC_MPC5567,      POWERPC_SVR_5567,      e200),
+#endif
+    /* e300 family                                                           */
+    /* Generic PowerPC e300 core                                             */
+    POWERPC_DEF("e300",          CPU_POWERPC_e300,                   e300),
+    /* PowerPC e300c1 core                                                   */
+    POWERPC_DEF("e300c1",        CPU_POWERPC_e300c1,                 e300),
+    /* PowerPC e300c2 core                                                   */
+    POWERPC_DEF("e300c2",        CPU_POWERPC_e300c2,                 e300),
+    /* PowerPC e300c3 core                                                   */
+    POWERPC_DEF("e300c3",        CPU_POWERPC_e300c3,                 e300),
+    /* PowerPC e300c4 core                                                   */
+    POWERPC_DEF("e300c4",        CPU_POWERPC_e300c4,                 e300),
+    /* PowerPC e300 microcontrollers                                         */
+#if defined (TODO)
+    /* MPC8313                                                               */
+    POWERPC_DEF_SVR("MPC8313",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8313,      e300),
+#endif
+#if defined (TODO)
+    /* MPC8313E                                                              */
+    POWERPC_DEF_SVR("MPC8313E",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8313E,     e300),
+#endif
+#if defined (TODO)
+    /* MPC8314                                                               */
+    POWERPC_DEF_SVR("MPC8314",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8314,      e300),
+#endif
+#if defined (TODO)
+    /* MPC8314E                                                              */
+    POWERPC_DEF_SVR("MPC8314E",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8314E,     e300),
+#endif
+#if defined (TODO)
+    /* MPC8315                                                               */
+    POWERPC_DEF_SVR("MPC8315",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8315,      e300),
+#endif
+#if defined (TODO)
+    /* MPC8315E                                                              */
+    POWERPC_DEF_SVR("MPC8315E",
+                    CPU_POWERPC_MPC831x,      POWERPC_SVR_8315E,     e300),
+#endif
+#if defined (TODO)
+    /* MPC8321                                                               */
+    POWERPC_DEF_SVR("MPC8321",
+                    CPU_POWERPC_MPC832x,      POWERPC_SVR_8321,      e300),
+#endif
+#if defined (TODO)
+    /* MPC8321E                                                              */
+    POWERPC_DEF_SVR("MPC8321E",
+                    CPU_POWERPC_MPC832x,      POWERPC_SVR_8321E,     e300),
+#endif
+#if defined (TODO)
+    /* MPC8323                                                               */
+    POWERPC_DEF_SVR("MPC8323",
+                    CPU_POWERPC_MPC832x,      POWERPC_SVR_8323,      e300),
+#endif
+#if defined (TODO)
+    /* MPC8323E                                                              */
+    POWERPC_DEF_SVR("MPC8323E",
+                    CPU_POWERPC_MPC832x,      POWERPC_SVR_8323E,     e300),
+#endif
+    /* MPC8343                                                               */
+    POWERPC_DEF_SVR("MPC8343",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8343,      e300),
+    /* MPC8343A                                                              */
+    POWERPC_DEF_SVR("MPC8343A",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8343A,     e300),
+    /* MPC8343E                                                              */
+    POWERPC_DEF_SVR("MPC8343E",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8343E,     e300),
+    /* MPC8343EA                                                             */
+    POWERPC_DEF_SVR("MPC8343EA",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8343EA,    e300),
+    /* MPC8347                                                               */
+    POWERPC_DEF_SVR("MPC8347",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347,      e300),
+    /* MPC8347T                                                              */
+    POWERPC_DEF_SVR("MPC8347T",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347T,     e300),
+    /* MPC8347P                                                              */
+    POWERPC_DEF_SVR("MPC8347P",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347P,     e300),
+    /* MPC8347A                                                              */
+    POWERPC_DEF_SVR("MPC8347A",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347A,     e300),
+    /* MPC8347AT                                                             */
+    POWERPC_DEF_SVR("MPC8347AT",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347AT,    e300),
+    /* MPC8347AP                                                             */
+    POWERPC_DEF_SVR("MPC8347AP",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347AP,    e300),
+    /* MPC8347E                                                              */
+    POWERPC_DEF_SVR("MPC8347E",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347E,     e300),
+    /* MPC8347ET                                                             */
+    POWERPC_DEF_SVR("MPC8347ET",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347ET,    e300),
+    /* MPC8343EP                                                             */
+    POWERPC_DEF_SVR("MPC8347EP",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347EP,    e300),
+    /* MPC8347EA                                                             */
+    POWERPC_DEF_SVR("MPC8347EA",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347EA,    e300),
+    /* MPC8347EAT                                                            */
+    POWERPC_DEF_SVR("MPC8347EAT",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347EAT,   e300),
+    /* MPC8343EAP                                                            */
+    POWERPC_DEF_SVR("MPC8347EAP",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8347EAP,   e300),
+    /* MPC8349                                                               */
+    POWERPC_DEF_SVR("MPC8349",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8349,      e300),
+    /* MPC8349A                                                              */
+    POWERPC_DEF_SVR("MPC8349A",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8349A,     e300),
+    /* MPC8349E                                                              */
+    POWERPC_DEF_SVR("MPC8349E",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8349E,     e300),
+    /* MPC8349EA                                                             */
+    POWERPC_DEF_SVR("MPC8349EA",
+                    CPU_POWERPC_MPC834x,      POWERPC_SVR_8349EA,    e300),
+#if defined (TODO)
+    /* MPC8358E                                                              */
+    POWERPC_DEF_SVR("MPC8358E",
+                    CPU_POWERPC_MPC835x,      POWERPC_SVR_8358E,     e300),
+#endif
+#if defined (TODO)
+    /* MPC8360E                                                              */
+    POWERPC_DEF_SVR("MPC8360E",
+                    CPU_POWERPC_MPC836x,      POWERPC_SVR_8360E,     e300),
+#endif
+    /* MPC8377                                                               */
+    POWERPC_DEF_SVR("MPC8377",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8377,      e300),
+    /* MPC8377E                                                              */
+    POWERPC_DEF_SVR("MPC8377E",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8377E,     e300),
+    /* MPC8378                                                               */
+    POWERPC_DEF_SVR("MPC8378",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8378,      e300),
+    /* MPC8378E                                                              */
+    POWERPC_DEF_SVR("MPC8378E",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8378E,     e300),
+    /* MPC8379                                                               */
+    POWERPC_DEF_SVR("MPC8379",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8379,      e300),
+    /* MPC8379E                                                              */
+    POWERPC_DEF_SVR("MPC8379E",
+                    CPU_POWERPC_MPC837x,      POWERPC_SVR_8379E,     e300),
+    /* e500 family                                                           */
+    /* PowerPC e500 core                                                     */
+    POWERPC_DEF("e500",          CPU_POWERPC_e500v2_v22,             e500v2),
+    /* PowerPC e500v1 core                                                   */
+    POWERPC_DEF("e500v1",        CPU_POWERPC_e500v1,                 e500v1),
+    /* PowerPC e500 v1.0 core                                                */
+    POWERPC_DEF("e500_v10",      CPU_POWERPC_e500v1_v10,             e500v1),
+    /* PowerPC e500 v2.0 core                                                */
+    POWERPC_DEF("e500_v20",      CPU_POWERPC_e500v1_v20,             e500v1),
+    /* PowerPC e500v2 core                                                   */
+    POWERPC_DEF("e500v2",        CPU_POWERPC_e500v2,                 e500v2),
+    /* PowerPC e500v2 v1.0 core                                              */
+    POWERPC_DEF("e500v2_v10",    CPU_POWERPC_e500v2_v10,             e500v2),
+    /* PowerPC e500v2 v2.0 core                                              */
+    POWERPC_DEF("e500v2_v20",    CPU_POWERPC_e500v2_v20,             e500v2),
+    /* PowerPC e500v2 v2.1 core                                              */
+    POWERPC_DEF("e500v2_v21",    CPU_POWERPC_e500v2_v21,             e500v2),
+    /* PowerPC e500v2 v2.2 core                                              */
+    POWERPC_DEF("e500v2_v22",    CPU_POWERPC_e500v2_v22,             e500v2),
+    /* PowerPC e500v2 v3.0 core                                              */
+    POWERPC_DEF("e500v2_v30",    CPU_POWERPC_e500v2_v30,             e500v2),
+    /* PowerPC e500 microcontrollers                                         */
+    /* MPC8533                                                               */
+    POWERPC_DEF_SVR("MPC8533",
+                    CPU_POWERPC_MPC8533,      POWERPC_SVR_8533,      e500v2),
+    /* MPC8533 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8533_v10",
+                    CPU_POWERPC_MPC8533_v10,  POWERPC_SVR_8533_v10,  e500v2),
+    /* MPC8533 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8533_v11",
+                    CPU_POWERPC_MPC8533_v11,  POWERPC_SVR_8533_v11,  e500v2),
+    /* MPC8533E                                                              */
+    POWERPC_DEF_SVR("MPC8533E",
+                    CPU_POWERPC_MPC8533E,     POWERPC_SVR_8533E,     e500v2),
+    /* MPC8533E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8533E_v10",
+                    CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2),
+    POWERPC_DEF_SVR("MPC8533E_v11",
+                    CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2),
+    /* MPC8540                                                               */
+    POWERPC_DEF_SVR("MPC8540",
+                    CPU_POWERPC_MPC8540,      POWERPC_SVR_8540,      e500v1),
+    /* MPC8540 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8540_v10",
+                    CPU_POWERPC_MPC8540_v10,  POWERPC_SVR_8540_v10,  e500v1),
+    /* MPC8540 v2.0                                                          */
+    POWERPC_DEF_SVR("MPC8540_v20",
+                    CPU_POWERPC_MPC8540_v20,  POWERPC_SVR_8540_v20,  e500v1),
+    /* MPC8540 v2.1                                                          */
+    POWERPC_DEF_SVR("MPC8540_v21",
+                    CPU_POWERPC_MPC8540_v21,  POWERPC_SVR_8540_v21,  e500v1),
+    /* MPC8541                                                               */
+    POWERPC_DEF_SVR("MPC8541",
+                    CPU_POWERPC_MPC8541,      POWERPC_SVR_8541,      e500v1),
+    /* MPC8541 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8541_v10",
+                    CPU_POWERPC_MPC8541_v10,  POWERPC_SVR_8541_v10,  e500v1),
+    /* MPC8541 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8541_v11",
+                    CPU_POWERPC_MPC8541_v11,  POWERPC_SVR_8541_v11,  e500v1),
+    /* MPC8541E                                                              */
+    POWERPC_DEF_SVR("MPC8541E",
+                    CPU_POWERPC_MPC8541E,     POWERPC_SVR_8541E,     e500v1),
+    /* MPC8541E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8541E_v10",
+                    CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1),
+    /* MPC8541E v1.1                                                         */
+    POWERPC_DEF_SVR("MPC8541E_v11",
+                    CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1),
+    /* MPC8543                                                               */
+    POWERPC_DEF_SVR("MPC8543",
+                    CPU_POWERPC_MPC8543,      POWERPC_SVR_8543,      e500v2),
+    /* MPC8543 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8543_v10",
+                    CPU_POWERPC_MPC8543_v10,  POWERPC_SVR_8543_v10,  e500v2),
+    /* MPC8543 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8543_v11",
+                    CPU_POWERPC_MPC8543_v11,  POWERPC_SVR_8543_v11,  e500v2),
+    /* MPC8543 v2.0                                                          */
+    POWERPC_DEF_SVR("MPC8543_v20",
+                    CPU_POWERPC_MPC8543_v20,  POWERPC_SVR_8543_v20,  e500v2),
+    /* MPC8543 v2.1                                                          */
+    POWERPC_DEF_SVR("MPC8543_v21",
+                    CPU_POWERPC_MPC8543_v21,  POWERPC_SVR_8543_v21,  e500v2),
+    /* MPC8543E                                                              */
+    POWERPC_DEF_SVR("MPC8543E",
+                    CPU_POWERPC_MPC8543E,     POWERPC_SVR_8543E,     e500v2),
+    /* MPC8543E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8543E_v10",
+                    CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2),
+    /* MPC8543E v1.1                                                         */
+    POWERPC_DEF_SVR("MPC8543E_v11",
+                    CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2),
+    /* MPC8543E v2.0                                                         */
+    POWERPC_DEF_SVR("MPC8543E_v20",
+                    CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2),
+    /* MPC8543E v2.1                                                         */
+    POWERPC_DEF_SVR("MPC8543E_v21",
+                    CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2),
+    /* MPC8544                                                               */
+    POWERPC_DEF_SVR("MPC8544",
+                    CPU_POWERPC_MPC8544,      POWERPC_SVR_8544,      e500v2),
+    /* MPC8544 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8544_v10",
+                    CPU_POWERPC_MPC8544_v10,  POWERPC_SVR_8544_v10,  e500v2),
+    /* MPC8544 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8544_v11",
+                    CPU_POWERPC_MPC8544_v11,  POWERPC_SVR_8544_v11,  e500v2),
+    /* MPC8544E                                                              */
+    POWERPC_DEF_SVR("MPC8544E",
+                    CPU_POWERPC_MPC8544E,     POWERPC_SVR_8544E,     e500v2),
+    /* MPC8544E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8544E_v10",
+                    CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2),
+    /* MPC8544E v1.1                                                         */
+    POWERPC_DEF_SVR("MPC8544E_v11",
+                    CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2),
+    /* MPC8545                                                               */
+    POWERPC_DEF_SVR("MPC8545",
+                    CPU_POWERPC_MPC8545,      POWERPC_SVR_8545,      e500v2),
+    /* MPC8545 v2.0                                                          */
+    POWERPC_DEF_SVR("MPC8545_v20",
+                    CPU_POWERPC_MPC8545_v20,  POWERPC_SVR_8545_v20,  e500v2),
+    /* MPC8545 v2.1                                                          */
+    POWERPC_DEF_SVR("MPC8545_v21",
+                    CPU_POWERPC_MPC8545_v21,  POWERPC_SVR_8545_v21,  e500v2),
+    /* MPC8545E                                                              */
+    POWERPC_DEF_SVR("MPC8545E",
+                    CPU_POWERPC_MPC8545E,     POWERPC_SVR_8545E,     e500v2),
+    /* MPC8545E v2.0                                                         */
+    POWERPC_DEF_SVR("MPC8545E_v20",
+                    CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2),
+    /* MPC8545E v2.1                                                         */
+    POWERPC_DEF_SVR("MPC8545E_v21",
+                    CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2),
+    /* MPC8547E                                                              */
+    POWERPC_DEF_SVR("MPC8547E",
+                    CPU_POWERPC_MPC8547E,     POWERPC_SVR_8547E,     e500v2),
+    /* MPC8547E v2.0                                                         */
+    POWERPC_DEF_SVR("MPC8547E_v20",
+                    CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2),
+    /* MPC8547E v2.1                                                         */
+    POWERPC_DEF_SVR("MPC8547E_v21",
+                    CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2),
+    /* MPC8548                                                               */
+    POWERPC_DEF_SVR("MPC8548",
+                    CPU_POWERPC_MPC8548,      POWERPC_SVR_8548,      e500v2),
+    /* MPC8548 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8548_v10",
+                    CPU_POWERPC_MPC8548_v10,  POWERPC_SVR_8548_v10,  e500v2),
+    /* MPC8548 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8548_v11",
+                    CPU_POWERPC_MPC8548_v11,  POWERPC_SVR_8548_v11,  e500v2),
+    /* MPC8548 v2.0                                                          */
+    POWERPC_DEF_SVR("MPC8548_v20",
+                    CPU_POWERPC_MPC8548_v20,  POWERPC_SVR_8548_v20,  e500v2),
+    /* MPC8548 v2.1                                                          */
+    POWERPC_DEF_SVR("MPC8548_v21",
+                    CPU_POWERPC_MPC8548_v21,  POWERPC_SVR_8548_v21,  e500v2),
+    /* MPC8548E                                                              */
+    POWERPC_DEF_SVR("MPC8548E",
+                    CPU_POWERPC_MPC8548E,     POWERPC_SVR_8548E,     e500v2),
+    /* MPC8548E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8548E_v10",
+                    CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2),
+    /* MPC8548E v1.1                                                         */
+    POWERPC_DEF_SVR("MPC8548E_v11",
+                    CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2),
+    /* MPC8548E v2.0                                                         */
+    POWERPC_DEF_SVR("MPC8548E_v20",
+                    CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2),
+    /* MPC8548E v2.1                                                         */
+    POWERPC_DEF_SVR("MPC8548E_v21",
+                    CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2),
+    /* MPC8555                                                               */
+    POWERPC_DEF_SVR("MPC8555",
+                    CPU_POWERPC_MPC8555,      POWERPC_SVR_8555,      e500v2),
+    /* MPC8555 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8555_v10",
+                    CPU_POWERPC_MPC8555_v10,  POWERPC_SVR_8555_v10,  e500v2),
+    /* MPC8555 v1.1                                                          */
+    POWERPC_DEF_SVR("MPC8555_v11",
+                    CPU_POWERPC_MPC8555_v11,  POWERPC_SVR_8555_v11,  e500v2),
+    /* MPC8555E                                                              */
+    POWERPC_DEF_SVR("MPC8555E",
+                    CPU_POWERPC_MPC8555E,     POWERPC_SVR_8555E,     e500v2),
+    /* MPC8555E v1.0                                                         */
+    POWERPC_DEF_SVR("MPC8555E_v10",
+                    CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2),
+    /* MPC8555E v1.1                                                         */
+    POWERPC_DEF_SVR("MPC8555E_v11",
+                    CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2),
+    /* MPC8560                                                               */
+    POWERPC_DEF_SVR("MPC8560",
+                    CPU_POWERPC_MPC8560,      POWERPC_SVR_8560,      e500v2),
+    /* MPC8560 v1.0                                                          */
+    POWERPC_DEF_SVR("MPC8560_v10",
+                    CPU_POWERPC_MPC8560_v10,  POWERPC_SVR_8560_v10,  e500v2),
+    /* MPC8560 v2.0                                                          */
+    POWERPC_DEF_SVR("MPC8560_v20",
+                    CPU_POWERPC_MPC8560_v20,  POWERPC_SVR_8560_v20,  e500v2),
+    /* MPC8560 v2.1                                                          */
+    POWERPC_DEF_SVR("MPC8560_v21",
+                    CPU_POWERPC_MPC8560_v21,  POWERPC_SVR_8560_v21,  e500v2),
+    /* MPC8567                                                               */
+    POWERPC_DEF_SVR("MPC8567",
+                    CPU_POWERPC_MPC8567,      POWERPC_SVR_8567,      e500v2),
+    /* MPC8567E                                                              */
+    POWERPC_DEF_SVR("MPC8567E",
+                    CPU_POWERPC_MPC8567E,     POWERPC_SVR_8567E,     e500v2),
+    /* MPC8568                                                               */
+    POWERPC_DEF_SVR("MPC8568",
+                    CPU_POWERPC_MPC8568,      POWERPC_SVR_8568,      e500v2),
+    /* MPC8568E                                                              */
+    POWERPC_DEF_SVR("MPC8568E",
+                    CPU_POWERPC_MPC8568E,     POWERPC_SVR_8568E,     e500v2),
+    /* MPC8572                                                               */
+    POWERPC_DEF_SVR("MPC8572",
+                    CPU_POWERPC_MPC8572,      POWERPC_SVR_8572,      e500v2),
+    /* MPC8572E                                                              */
+    POWERPC_DEF_SVR("MPC8572E",
+                    CPU_POWERPC_MPC8572E,     POWERPC_SVR_8572E,     e500v2),
+    /* e600 family                                                           */
+    /* PowerPC e600 core                                                     */
+    POWERPC_DEF("e600",          CPU_POWERPC_e600,                   7400),
+    /* PowerPC e600 microcontrollers                                         */
+#if defined (TODO)
+    /* MPC8610                                                               */
+    POWERPC_DEF_SVR("MPC8610",
+                    CPU_POWERPC_MPC8610,      POWERPC_SVR_8610,      7400),
+#endif
+    /* MPC8641                                                               */
+    POWERPC_DEF_SVR("MPC8641",
+                    CPU_POWERPC_MPC8641,      POWERPC_SVR_8641,      7400),
+    /* MPC8641D                                                              */
+    POWERPC_DEF_SVR("MPC8641D",
+                    CPU_POWERPC_MPC8641D,     POWERPC_SVR_8641D,     7400),
+    /* 32 bits "classic" PowerPC                                             */
+    /* PowerPC 6xx family                                                    */
+    /* PowerPC 601                                                           */
+    POWERPC_DEF("601",           CPU_POWERPC_601,                    601v),
+    /* PowerPC 601v0                                                         */
+    POWERPC_DEF("601_v0",        CPU_POWERPC_601_v0,                 601),
+    /* PowerPC 601v1                                                         */
+    POWERPC_DEF("601_v1",        CPU_POWERPC_601_v1,                 601),
+    /* PowerPC 601v                                                          */
+    POWERPC_DEF("601v",          CPU_POWERPC_601v,                   601v),
+    /* PowerPC 601v2                                                         */
+    POWERPC_DEF("601_v2",        CPU_POWERPC_601_v2,                 601v),
+    /* PowerPC 602                                                           */
+    POWERPC_DEF("602",           CPU_POWERPC_602,                    602),
+    /* PowerPC 603                                                           */
+    POWERPC_DEF("603",           CPU_POWERPC_603,                    603),
+    /* Code name for PowerPC 603                                             */
+    POWERPC_DEF("Vanilla",       CPU_POWERPC_603,                    603),
+    /* PowerPC 603e (aka PID6)                                               */
+    POWERPC_DEF("603e",          CPU_POWERPC_603E,                   603E),
+    /* Code name for PowerPC 603e                                            */
+    POWERPC_DEF("Stretch",       CPU_POWERPC_603E,                   603E),
+    /* PowerPC 603e v1.1                                                     */
+    POWERPC_DEF("603e_v1.1",     CPU_POWERPC_603E_v11,               603E),
+    /* PowerPC 603e v1.2                                                     */
+    POWERPC_DEF("603e_v1.2",     CPU_POWERPC_603E_v12,               603E),
+    /* PowerPC 603e v1.3                                                     */
+    POWERPC_DEF("603e_v1.3",     CPU_POWERPC_603E_v13,               603E),
+    /* PowerPC 603e v1.4                                                     */
+    POWERPC_DEF("603e_v1.4",     CPU_POWERPC_603E_v14,               603E),
+    /* PowerPC 603e v2.2                                                     */
+    POWERPC_DEF("603e_v2.2",     CPU_POWERPC_603E_v22,               603E),
+    /* PowerPC 603e v3                                                       */
+    POWERPC_DEF("603e_v3",       CPU_POWERPC_603E_v3,                603E),
+    /* PowerPC 603e v4                                                       */
+    POWERPC_DEF("603e_v4",       CPU_POWERPC_603E_v4,                603E),
+    /* PowerPC 603e v4.1                                                     */
+    POWERPC_DEF("603e_v4.1",     CPU_POWERPC_603E_v41,               603E),
+    /* PowerPC 603e (aka PID7)                                               */
+    POWERPC_DEF("603e7",         CPU_POWERPC_603E7,                  603E),
+    /* PowerPC 603e7t                                                        */
+    POWERPC_DEF("603e7t",        CPU_POWERPC_603E7t,                 603E),
+    /* PowerPC 603e7v                                                        */
+    POWERPC_DEF("603e7v",        CPU_POWERPC_603E7v,                 603E),
+    /* Code name for PowerPC 603ev                                           */
+    POWERPC_DEF("Vaillant",      CPU_POWERPC_603E7v,                 603E),
+    /* PowerPC 603e7v1                                                       */
+    POWERPC_DEF("603e7v1",       CPU_POWERPC_603E7v1,                603E),
+    /* PowerPC 603e7v2                                                       */
+    POWERPC_DEF("603e7v2",       CPU_POWERPC_603E7v2,                603E),
+    /* PowerPC 603p (aka PID7v)                                              */
+    POWERPC_DEF("603p",          CPU_POWERPC_603P,                   603E),
+    /* PowerPC 603r (aka PID7t)                                              */
+    POWERPC_DEF("603r",          CPU_POWERPC_603R,                   603E),
+    /* Code name for PowerPC 603r                                            */
+    POWERPC_DEF("Goldeneye",     CPU_POWERPC_603R,                   603E),
+    /* PowerPC 604                                                           */
+    POWERPC_DEF("604",           CPU_POWERPC_604,                    604),
+    /* PowerPC 604e (aka PID9)                                               */
+    POWERPC_DEF("604e",          CPU_POWERPC_604E,                   604E),
+    /* Code name for PowerPC 604e                                            */
+    POWERPC_DEF("Sirocco",       CPU_POWERPC_604E,                   604E),
+    /* PowerPC 604e v1.0                                                     */
+    POWERPC_DEF("604e_v1.0",     CPU_POWERPC_604E_v10,               604E),
+    /* PowerPC 604e v2.2                                                     */
+    POWERPC_DEF("604e_v2.2",     CPU_POWERPC_604E_v22,               604E),
+    /* PowerPC 604e v2.4                                                     */
+    POWERPC_DEF("604e_v2.4",     CPU_POWERPC_604E_v24,               604E),
+    /* PowerPC 604r (aka PIDA)                                               */
+    POWERPC_DEF("604r",          CPU_POWERPC_604R,                   604E),
+    /* Code name for PowerPC 604r                                            */
+    POWERPC_DEF("Mach5",         CPU_POWERPC_604R,                   604E),
+#if defined(TODO)
+    /* PowerPC 604ev                                                         */
+    POWERPC_DEF("604ev",         CPU_POWERPC_604EV,                  604E),
+#endif
+    /* PowerPC 7xx family                                                    */
+    /* Generic PowerPC 740 (G3)                                              */
+    POWERPC_DEF("740",           CPU_POWERPC_7x0,                    740),
+    /* Code name for PowerPC 740                                             */
+    POWERPC_DEF("Arthur",        CPU_POWERPC_7x0,                    740),
+    /* Generic PowerPC 750 (G3)                                              */
+    POWERPC_DEF("750",           CPU_POWERPC_7x0,                    750),
+    /* Code name for PowerPC 750                                             */
+    POWERPC_DEF("Typhoon",       CPU_POWERPC_7x0,                    750),
+    /* PowerPC 740/750 is also known as G3                                   */
+    POWERPC_DEF("G3",            CPU_POWERPC_7x0,                    750),
+    /* PowerPC 740 v1.0 (G3)                                                 */
+    POWERPC_DEF("740_v1.0",      CPU_POWERPC_7x0_v10,                740),
+    /* PowerPC 750 v1.0 (G3)                                                 */
+    POWERPC_DEF("750_v1.0",      CPU_POWERPC_7x0_v10,                750),
+    /* PowerPC 740 v2.0 (G3)                                                 */
+    POWERPC_DEF("740_v2.0",      CPU_POWERPC_7x0_v20,                740),
+    /* PowerPC 750 v2.0 (G3)                                                 */
+    POWERPC_DEF("750_v2.0",      CPU_POWERPC_7x0_v20,                750),
+    /* PowerPC 740 v2.1 (G3)                                                 */
+    POWERPC_DEF("740_v2.1",      CPU_POWERPC_7x0_v21,                740),
+    /* PowerPC 750 v2.1 (G3)                                                 */
+    POWERPC_DEF("750_v2.1",      CPU_POWERPC_7x0_v21,                750),
+    /* PowerPC 740 v2.2 (G3)                                                 */
+    POWERPC_DEF("740_v2.2",      CPU_POWERPC_7x0_v22,                740),
+    /* PowerPC 750 v2.2 (G3)                                                 */
+    POWERPC_DEF("750_v2.2",      CPU_POWERPC_7x0_v22,                750),
+    /* PowerPC 740 v3.0 (G3)                                                 */
+    POWERPC_DEF("740_v3.0",      CPU_POWERPC_7x0_v30,                740),
+    /* PowerPC 750 v3.0 (G3)                                                 */
+    POWERPC_DEF("750_v3.0",      CPU_POWERPC_7x0_v30,                750),
+    /* PowerPC 740 v3.1 (G3)                                                 */
+    POWERPC_DEF("740_v3.1",      CPU_POWERPC_7x0_v31,                740),
+    /* PowerPC 750 v3.1 (G3)                                                 */
+    POWERPC_DEF("750_v3.1",      CPU_POWERPC_7x0_v31,                750),
+    /* PowerPC 740E (G3)                                                     */
+    POWERPC_DEF("740e",          CPU_POWERPC_740E,                   740),
+    /* PowerPC 750E (G3)                                                     */
+    POWERPC_DEF("750e",          CPU_POWERPC_750E,                   750),
+    /* PowerPC 740P (G3)                                                     */
+    POWERPC_DEF("740p",          CPU_POWERPC_7x0P,                   740),
+    /* PowerPC 750P (G3)                                                     */
+    POWERPC_DEF("750p",          CPU_POWERPC_7x0P,                   750),
+    /* Code name for PowerPC 740P/750P (G3)                                  */
+    POWERPC_DEF("Conan/Doyle",   CPU_POWERPC_7x0P,                   750),
+    /* PowerPC 750CL (G3 embedded)                                           */
+    POWERPC_DEF("750cl",         CPU_POWERPC_750CL,                  750cl),
+    /* PowerPC 750CL v1.0                                                    */
+    POWERPC_DEF("750cl_v1.0",    CPU_POWERPC_750CL_v10,              750cl),
+    /* PowerPC 750CL v2.0                                                    */
+    POWERPC_DEF("750cl_v2.0",    CPU_POWERPC_750CL_v20,              750cl),
+    /* PowerPC 750CX (G3 embedded)                                           */
+    POWERPC_DEF("750cx",         CPU_POWERPC_750CX,                  750cx),
+    /* PowerPC 750CX v1.0 (G3 embedded)                                      */
+    POWERPC_DEF("750cx_v1.0",    CPU_POWERPC_750CX_v10,              750cx),
+    /* PowerPC 750CX v2.1 (G3 embedded)                                      */
+    POWERPC_DEF("750cx_v2.0",    CPU_POWERPC_750CX_v20,              750cx),
+    /* PowerPC 750CX v2.1 (G3 embedded)                                      */
+    POWERPC_DEF("750cx_v2.1",    CPU_POWERPC_750CX_v21,              750cx),
+    /* PowerPC 750CX v2.2 (G3 embedded)                                      */
+    POWERPC_DEF("750cx_v2.2",    CPU_POWERPC_750CX_v22,              750cx),
+    /* PowerPC 750CXe (G3 embedded)                                          */
+    POWERPC_DEF("750cxe",        CPU_POWERPC_750CXE,                 750cx),
+    /* PowerPC 750CXe v2.1 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v2.1",   CPU_POWERPC_750CXE_v21,             750cx),
+    /* PowerPC 750CXe v2.2 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v2.2",   CPU_POWERPC_750CXE_v22,             750cx),
+    /* PowerPC 750CXe v2.3 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v2.3",   CPU_POWERPC_750CXE_v23,             750cx),
+    /* PowerPC 750CXe v2.4 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v2.4",   CPU_POWERPC_750CXE_v24,             750cx),
+    /* PowerPC 750CXe v2.4b (G3 embedded)                                    */
+    POWERPC_DEF("750cxe_v2.4b",  CPU_POWERPC_750CXE_v24b,            750cx),
+    /* PowerPC 750CXe v3.0 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v3.0",   CPU_POWERPC_750CXE_v30,             750cx),
+    /* PowerPC 750CXe v3.1 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe_v3.1",   CPU_POWERPC_750CXE_v31,             750cx),
+    /* PowerPC 750CXe v3.1b (G3 embedded)                                    */
+    POWERPC_DEF("750cxe_v3.1b",  CPU_POWERPC_750CXE_v31b,            750cx),
+    /* PowerPC 750CXr (G3 embedded)                                          */
+    POWERPC_DEF("750cxr",        CPU_POWERPC_750CXR,                 750cx),
+    /* PowerPC 750FL (G3 embedded)                                           */
+    POWERPC_DEF("750fl",         CPU_POWERPC_750FL,                  750fx),
+    /* PowerPC 750FX (G3 embedded)                                           */
+    POWERPC_DEF("750fx",         CPU_POWERPC_750FX,                  750fx),
+    /* PowerPC 750FX v1.0 (G3 embedded)                                      */
+    POWERPC_DEF("750fx_v1.0",    CPU_POWERPC_750FX_v10,              750fx),
+    /* PowerPC 750FX v2.0 (G3 embedded)                                      */
+    POWERPC_DEF("750fx_v2.0",    CPU_POWERPC_750FX_v20,              750fx),
+    /* PowerPC 750FX v2.1 (G3 embedded)                                      */
+    POWERPC_DEF("750fx_v2.1",    CPU_POWERPC_750FX_v21,              750fx),
+    /* PowerPC 750FX v2.2 (G3 embedded)                                      */
+    POWERPC_DEF("750fx_v2.2",    CPU_POWERPC_750FX_v22,              750fx),
+    /* PowerPC 750FX v2.3 (G3 embedded)                                      */
+    POWERPC_DEF("750fx_v2.3",    CPU_POWERPC_750FX_v23,              750fx),
+    /* PowerPC 750GL (G3 embedded)                                           */
+    POWERPC_DEF("750gl",         CPU_POWERPC_750GL,                  750gx),
+    /* PowerPC 750GX (G3 embedded)                                           */
+    POWERPC_DEF("750gx",         CPU_POWERPC_750GX,                  750gx),
+    /* PowerPC 750GX v1.0 (G3 embedded)                                      */
+    POWERPC_DEF("750gx_v1.0",    CPU_POWERPC_750GX_v10,              750gx),
+    /* PowerPC 750GX v1.1 (G3 embedded)                                      */
+    POWERPC_DEF("750gx_v1.1",    CPU_POWERPC_750GX_v11,              750gx),
+    /* PowerPC 750GX v1.2 (G3 embedded)                                      */
+    POWERPC_DEF("750gx_v1.2",    CPU_POWERPC_750GX_v12,              750gx),
+    /* PowerPC 750L (G3 embedded)                                            */
+    POWERPC_DEF("750l",          CPU_POWERPC_750L,                   750),
+    /* Code name for PowerPC 750L (G3 embedded)                              */
+    POWERPC_DEF("LoneStar",      CPU_POWERPC_750L,                   750),
+    /* PowerPC 750L v2.0 (G3 embedded)                                       */
+    POWERPC_DEF("750l_v2.0",     CPU_POWERPC_750L_v20,               750),
+    /* PowerPC 750L v2.1 (G3 embedded)                                       */
+    POWERPC_DEF("750l_v2.1",     CPU_POWERPC_750L_v21,               750),
+    /* PowerPC 750L v2.2 (G3 embedded)                                       */
+    POWERPC_DEF("750l_v2.2",     CPU_POWERPC_750L_v22,               750),
+    /* PowerPC 750L v3.0 (G3 embedded)                                       */
+    POWERPC_DEF("750l_v3.0",     CPU_POWERPC_750L_v30,               750),
+    /* PowerPC 750L v3.2 (G3 embedded)                                       */
+    POWERPC_DEF("750l_v3.2",     CPU_POWERPC_750L_v32,               750),
+    /* Generic PowerPC 745                                                   */
+    POWERPC_DEF("745",           CPU_POWERPC_7x5,                    745),
+    /* Generic PowerPC 755                                                   */
+    POWERPC_DEF("755",           CPU_POWERPC_7x5,                    755),
+    /* Code name for PowerPC 745/755                                         */
+    POWERPC_DEF("Goldfinger",    CPU_POWERPC_7x5,                    755),
+    /* PowerPC 745 v1.0                                                      */
+    POWERPC_DEF("745_v1.0",      CPU_POWERPC_7x5_v10,                745),
+    /* PowerPC 755 v1.0                                                      */
+    POWERPC_DEF("755_v1.0",      CPU_POWERPC_7x5_v10,                755),
+    /* PowerPC 745 v1.1                                                      */
+    POWERPC_DEF("745_v1.1",      CPU_POWERPC_7x5_v11,                745),
+    /* PowerPC 755 v1.1                                                      */
+    POWERPC_DEF("755_v1.1",      CPU_POWERPC_7x5_v11,                755),
+    /* PowerPC 745 v2.0                                                      */
+    POWERPC_DEF("745_v2.0",      CPU_POWERPC_7x5_v20,                745),
+    /* PowerPC 755 v2.0                                                      */
+    POWERPC_DEF("755_v2.0",      CPU_POWERPC_7x5_v20,                755),
+    /* PowerPC 745 v2.1                                                      */
+    POWERPC_DEF("745_v2.1",      CPU_POWERPC_7x5_v21,                745),
+    /* PowerPC 755 v2.1                                                      */
+    POWERPC_DEF("755_v2.1",      CPU_POWERPC_7x5_v21,                755),
+    /* PowerPC 745 v2.2                                                      */
+    POWERPC_DEF("745_v2.2",      CPU_POWERPC_7x5_v22,                745),
+    /* PowerPC 755 v2.2                                                      */
+    POWERPC_DEF("755_v2.2",      CPU_POWERPC_7x5_v22,                755),
+    /* PowerPC 745 v2.3                                                      */
+    POWERPC_DEF("745_v2.3",      CPU_POWERPC_7x5_v23,                745),
+    /* PowerPC 755 v2.3                                                      */
+    POWERPC_DEF("755_v2.3",      CPU_POWERPC_7x5_v23,                755),
+    /* PowerPC 745 v2.4                                                      */
+    POWERPC_DEF("745_v2.4",      CPU_POWERPC_7x5_v24,                745),
+    /* PowerPC 755 v2.4                                                      */
+    POWERPC_DEF("755_v2.4",      CPU_POWERPC_7x5_v24,                755),
+    /* PowerPC 745 v2.5                                                      */
+    POWERPC_DEF("745_v2.5",      CPU_POWERPC_7x5_v25,                745),
+    /* PowerPC 755 v2.5                                                      */
+    POWERPC_DEF("755_v2.5",      CPU_POWERPC_7x5_v25,                755),
+    /* PowerPC 745 v2.6                                                      */
+    POWERPC_DEF("745_v2.6",      CPU_POWERPC_7x5_v26,                745),
+    /* PowerPC 755 v2.6                                                      */
+    POWERPC_DEF("755_v2.6",      CPU_POWERPC_7x5_v26,                755),
+    /* PowerPC 745 v2.7                                                      */
+    POWERPC_DEF("745_v2.7",      CPU_POWERPC_7x5_v27,                745),
+    /* PowerPC 755 v2.7                                                      */
+    POWERPC_DEF("755_v2.7",      CPU_POWERPC_7x5_v27,                755),
+    /* PowerPC 745 v2.8                                                      */
+    POWERPC_DEF("745_v2.8",      CPU_POWERPC_7x5_v28,                745),
+    /* PowerPC 755 v2.8                                                      */
+    POWERPC_DEF("755_v2.8",      CPU_POWERPC_7x5_v28,                755),
+#if defined (TODO)
+    /* PowerPC 745P (G3)                                                     */
+    POWERPC_DEF("745p",          CPU_POWERPC_7x5P,                   745),
+    /* PowerPC 755P (G3)                                                     */
+    POWERPC_DEF("755p",          CPU_POWERPC_7x5P,                   755),
+#endif
+    /* PowerPC 74xx family                                                   */
+    /* PowerPC 7400 (G4)                                                     */
+    POWERPC_DEF("7400",          CPU_POWERPC_7400,                   7400),
+    /* Code name for PowerPC 7400                                            */
+    POWERPC_DEF("Max",           CPU_POWERPC_7400,                   7400),
+    /* PowerPC 74xx is also well known as G4                                 */
+    POWERPC_DEF("G4",            CPU_POWERPC_7400,                   7400),
+    /* PowerPC 7400 v1.0 (G4)                                                */
+    POWERPC_DEF("7400_v1.0",     CPU_POWERPC_7400_v10,               7400),
+    /* PowerPC 7400 v1.1 (G4)                                                */
+    POWERPC_DEF("7400_v1.1",     CPU_POWERPC_7400_v11,               7400),
+    /* PowerPC 7400 v2.0 (G4)                                                */
+    POWERPC_DEF("7400_v2.0",     CPU_POWERPC_7400_v20,               7400),
+    /* PowerPC 7400 v2.1 (G4)                                                */
+    POWERPC_DEF("7400_v2.1",     CPU_POWERPC_7400_v21,               7400),
+    /* PowerPC 7400 v2.2 (G4)                                                */
+    POWERPC_DEF("7400_v2.2",     CPU_POWERPC_7400_v22,               7400),
+    /* PowerPC 7400 v2.6 (G4)                                                */
+    POWERPC_DEF("7400_v2.6",     CPU_POWERPC_7400_v26,               7400),
+    /* PowerPC 7400 v2.7 (G4)                                                */
+    POWERPC_DEF("7400_v2.7",     CPU_POWERPC_7400_v27,               7400),
+    /* PowerPC 7400 v2.8 (G4)                                                */
+    POWERPC_DEF("7400_v2.8",     CPU_POWERPC_7400_v28,               7400),
+    /* PowerPC 7400 v2.9 (G4)                                                */
+    POWERPC_DEF("7400_v2.9",     CPU_POWERPC_7400_v29,               7400),
+    /* PowerPC 7410 (G4)                                                     */
+    POWERPC_DEF("7410",          CPU_POWERPC_7410,                   7410),
+    /* Code name for PowerPC 7410                                            */
+    POWERPC_DEF("Nitro",         CPU_POWERPC_7410,                   7410),
+    /* PowerPC 7410 v1.0 (G4)                                                */
+    POWERPC_DEF("7410_v1.0",     CPU_POWERPC_7410_v10,               7410),
+    /* PowerPC 7410 v1.1 (G4)                                                */
+    POWERPC_DEF("7410_v1.1",     CPU_POWERPC_7410_v11,               7410),
+    /* PowerPC 7410 v1.2 (G4)                                                */
+    POWERPC_DEF("7410_v1.2",     CPU_POWERPC_7410_v12,               7410),
+    /* PowerPC 7410 v1.3 (G4)                                                */
+    POWERPC_DEF("7410_v1.3",     CPU_POWERPC_7410_v13,               7410),
+    /* PowerPC 7410 v1.4 (G4)                                                */
+    POWERPC_DEF("7410_v1.4",     CPU_POWERPC_7410_v14,               7410),
+    /* PowerPC 7448 (G4)                                                     */
+    POWERPC_DEF("7448",          CPU_POWERPC_7448,                   7400),
+    /* PowerPC 7448 v1.0 (G4)                                                */
+    POWERPC_DEF("7448_v1.0",     CPU_POWERPC_7448_v10,               7400),
+    /* PowerPC 7448 v1.1 (G4)                                                */
+    POWERPC_DEF("7448_v1.1",     CPU_POWERPC_7448_v11,               7400),
+    /* PowerPC 7448 v2.0 (G4)                                                */
+    POWERPC_DEF("7448_v2.0",     CPU_POWERPC_7448_v20,               7400),
+    /* PowerPC 7448 v2.1 (G4)                                                */
+    POWERPC_DEF("7448_v2.1",     CPU_POWERPC_7448_v21,               7400),
+    /* PowerPC 7450 (G4)                                                     */
+    POWERPC_DEF("7450",          CPU_POWERPC_7450,                   7450),
+    /* Code name for PowerPC 7450                                            */
+    POWERPC_DEF("Vger",          CPU_POWERPC_7450,                   7450),
+    /* PowerPC 7450 v1.0 (G4)                                                */
+    POWERPC_DEF("7450_v1.0",     CPU_POWERPC_7450_v10,               7450),
+    /* PowerPC 7450 v1.1 (G4)                                                */
+    POWERPC_DEF("7450_v1.1",     CPU_POWERPC_7450_v11,               7450),
+    /* PowerPC 7450 v1.2 (G4)                                                */
+    POWERPC_DEF("7450_v1.2",     CPU_POWERPC_7450_v12,               7450),
+    /* PowerPC 7450 v2.0 (G4)                                                */
+    POWERPC_DEF("7450_v2.0",     CPU_POWERPC_7450_v20,               7450),
+    /* PowerPC 7450 v2.1 (G4)                                                */
+    POWERPC_DEF("7450_v2.1",     CPU_POWERPC_7450_v21,               7450),
+    /* PowerPC 7441 (G4)                                                     */
+    POWERPC_DEF("7441",          CPU_POWERPC_74x1,                   7440),
+    /* PowerPC 7451 (G4)                                                     */
+    POWERPC_DEF("7451",          CPU_POWERPC_74x1,                   7450),
+    /* PowerPC 7441 v2.1 (G4)                                                */
+    POWERPC_DEF("7441_v2.1",     CPU_POWERPC_7450_v21,               7440),
+    /* PowerPC 7441 v2.3 (G4)                                                */
+    POWERPC_DEF("7441_v2.3",     CPU_POWERPC_74x1_v23,               7440),
+    /* PowerPC 7451 v2.3 (G4)                                                */
+    POWERPC_DEF("7451_v2.3",     CPU_POWERPC_74x1_v23,               7450),
+    /* PowerPC 7441 v2.10 (G4)                                                */
+    POWERPC_DEF("7441_v2.10",    CPU_POWERPC_74x1_v210,              7440),
+    /* PowerPC 7451 v2.10 (G4)                                               */
+    POWERPC_DEF("7451_v2.10",    CPU_POWERPC_74x1_v210,              7450),
+    /* PowerPC 7445 (G4)                                                     */
+    POWERPC_DEF("7445",          CPU_POWERPC_74x5,                   7445),
+    /* PowerPC 7455 (G4)                                                     */
+    POWERPC_DEF("7455",          CPU_POWERPC_74x5,                   7455),
+    /* Code name for PowerPC 7445/7455                                       */
+    POWERPC_DEF("Apollo6",       CPU_POWERPC_74x5,                   7455),
+    /* PowerPC 7445 v1.0 (G4)                                                */
+    POWERPC_DEF("7445_v1.0",     CPU_POWERPC_74x5_v10,               7445),
+    /* PowerPC 7455 v1.0 (G4)                                                */
+    POWERPC_DEF("7455_v1.0",     CPU_POWERPC_74x5_v10,               7455),
+    /* PowerPC 7445 v2.1 (G4)                                                */
+    POWERPC_DEF("7445_v2.1",     CPU_POWERPC_74x5_v21,               7445),
+    /* PowerPC 7455 v2.1 (G4)                                                */
+    POWERPC_DEF("7455_v2.1",     CPU_POWERPC_74x5_v21,               7455),
+    /* PowerPC 7445 v3.2 (G4)                                                */
+    POWERPC_DEF("7445_v3.2",     CPU_POWERPC_74x5_v32,               7445),
+    /* PowerPC 7455 v3.2 (G4)                                                */
+    POWERPC_DEF("7455_v3.2",     CPU_POWERPC_74x5_v32,               7455),
+    /* PowerPC 7445 v3.3 (G4)                                                */
+    POWERPC_DEF("7445_v3.3",     CPU_POWERPC_74x5_v33,               7445),
+    /* PowerPC 7455 v3.3 (G4)                                                */
+    POWERPC_DEF("7455_v3.3",     CPU_POWERPC_74x5_v33,               7455),
+    /* PowerPC 7445 v3.4 (G4)                                                */
+    POWERPC_DEF("7445_v3.4",     CPU_POWERPC_74x5_v34,               7445),
+    /* PowerPC 7455 v3.4 (G4)                                                */
+    POWERPC_DEF("7455_v3.4",     CPU_POWERPC_74x5_v34,               7455),
+    /* PowerPC 7447 (G4)                                                     */
+    POWERPC_DEF("7447",          CPU_POWERPC_74x7,                   7445),
+    /* PowerPC 7457 (G4)                                                     */
+    POWERPC_DEF("7457",          CPU_POWERPC_74x7,                   7455),
+    /* Code name for PowerPC 7447/7457                                       */
+    POWERPC_DEF("Apollo7",       CPU_POWERPC_74x7,                   7455),
+    /* PowerPC 7447 v1.0 (G4)                                                */
+    POWERPC_DEF("7447_v1.0",     CPU_POWERPC_74x7_v10,               7445),
+    /* PowerPC 7457 v1.0 (G4)                                                */
+    POWERPC_DEF("7457_v1.0",     CPU_POWERPC_74x7_v10,               7455),
+    /* PowerPC 7447 v1.1 (G4)                                                */
+    POWERPC_DEF("7447_v1.1",     CPU_POWERPC_74x7_v11,               7445),
+    /* PowerPC 7457 v1.1 (G4)                                                */
+    POWERPC_DEF("7457_v1.1",     CPU_POWERPC_74x7_v11,               7455),
+    /* PowerPC 7457 v1.2 (G4)                                                */
+    POWERPC_DEF("7457_v1.2",     CPU_POWERPC_74x7_v12,               7455),
+    /* PowerPC 7447A (G4)                                                    */
+    POWERPC_DEF("7447A",         CPU_POWERPC_74x7A,                  7445),
+    /* PowerPC 7457A (G4)                                                    */
+    POWERPC_DEF("7457A",         CPU_POWERPC_74x7A,                  7455),
+    /* PowerPC 7447A v1.0 (G4)                                               */
+    POWERPC_DEF("7447A_v1.0",    CPU_POWERPC_74x7A_v10,              7445),
+    /* PowerPC 7457A v1.0 (G4)                                               */
+    POWERPC_DEF("7457A_v1.0",    CPU_POWERPC_74x7A_v10,              7455),
+    /* Code name for PowerPC 7447A/7457A                                     */
+    POWERPC_DEF("Apollo7PM",     CPU_POWERPC_74x7A_v10,              7455),
+    /* PowerPC 7447A v1.1 (G4)                                               */
+    POWERPC_DEF("7447A_v1.1",    CPU_POWERPC_74x7A_v11,              7445),
+    /* PowerPC 7457A v1.1 (G4)                                               */
+    POWERPC_DEF("7457A_v1.1",    CPU_POWERPC_74x7A_v11,              7455),
+    /* PowerPC 7447A v1.2 (G4)                                               */
+    POWERPC_DEF("7447A_v1.2",    CPU_POWERPC_74x7A_v12,              7445),
+    /* PowerPC 7457A v1.2 (G4)                                               */
+    POWERPC_DEF("7457A_v1.2",    CPU_POWERPC_74x7A_v12,              7455),
+    /* 64 bits PowerPC                                                       */
+#if defined (TARGET_PPC64)
+    /* PowerPC 620                                                           */
+    POWERPC_DEF("620",           CPU_POWERPC_620,                    620),
+    /* Code name for PowerPC 620                                             */
+    POWERPC_DEF("Trident",       CPU_POWERPC_620,                    620),
+#if defined (TODO)
+    /* PowerPC 630 (POWER3)                                                  */
+    POWERPC_DEF("630",           CPU_POWERPC_630,                    630),
+    POWERPC_DEF("POWER3",        CPU_POWERPC_630,                    630),
+    /* Code names for POWER3                                                 */
+    POWERPC_DEF("Boxer",         CPU_POWERPC_630,                    630),
+    POWERPC_DEF("Dino",          CPU_POWERPC_630,                    630),
+#endif
+#if defined (TODO)
+    /* PowerPC 631 (Power 3+)                                                */
+    POWERPC_DEF("631",           CPU_POWERPC_631,                    631),
+    POWERPC_DEF("POWER3+",       CPU_POWERPC_631,                    631),
+#endif
+#if defined (TODO)
+    /* POWER4                                                                */
+    POWERPC_DEF("POWER4",        CPU_POWERPC_POWER4,                 POWER4),
+#endif
+#if defined (TODO)
+    /* POWER4p                                                               */
+    POWERPC_DEF("POWER4+",       CPU_POWERPC_POWER4P,                POWER4P),
+#endif
+#if defined (TODO)
+    /* POWER5                                                                */
+    POWERPC_DEF("POWER5",        CPU_POWERPC_POWER5,                 POWER5),
+    /* POWER5GR                                                              */
+    POWERPC_DEF("POWER5gr",      CPU_POWERPC_POWER5GR,               POWER5),
+#endif
+#if defined (TODO)
+    /* POWER5+                                                               */
+    POWERPC_DEF("POWER5+",       CPU_POWERPC_POWER5P,                POWER5P),
+    /* POWER5GS                                                              */
+    POWERPC_DEF("POWER5gs",      CPU_POWERPC_POWER5GS,               POWER5P),
+#endif
+#if defined (TODO)
+    /* POWER6                                                                */
+    POWERPC_DEF("POWER6",        CPU_POWERPC_POWER6,                 POWER6),
+    /* POWER6 running in POWER5 mode                                         */
+    POWERPC_DEF("POWER6_5",      CPU_POWERPC_POWER6_5,               POWER5),
+    /* POWER6A                                                               */
+    POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6),
+#endif
+    /* POWER7                                                                */
+    POWERPC_DEF("POWER7",        CPU_POWERPC_POWER7,                 POWER7),
+    POWERPC_DEF("POWER7_v2.0",   CPU_POWERPC_POWER7_v20,             POWER7),
+    /* PowerPC 970                                                           */
+    POWERPC_DEF("970",           CPU_POWERPC_970,                    970),
+    /* PowerPC 970FX (G5)                                                    */
+    POWERPC_DEF("970fx",         CPU_POWERPC_970FX,                  970FX),
+    /* PowerPC 970FX v1.0 (G5)                                               */
+    POWERPC_DEF("970fx_v1.0",    CPU_POWERPC_970FX_v10,              970FX),
+    /* PowerPC 970FX v2.0 (G5)                                               */
+    POWERPC_DEF("970fx_v2.0",    CPU_POWERPC_970FX_v20,              970FX),
+    /* PowerPC 970FX v2.1 (G5)                                               */
+    POWERPC_DEF("970fx_v2.1",    CPU_POWERPC_970FX_v21,              970FX),
+    /* PowerPC 970FX v3.0 (G5)                                               */
+    POWERPC_DEF("970fx_v3.0",    CPU_POWERPC_970FX_v30,              970FX),
+    /* PowerPC 970FX v3.1 (G5)                                               */
+    POWERPC_DEF("970fx_v3.1",    CPU_POWERPC_970FX_v31,              970FX),
+    /* PowerPC 970GX (G5)                                                    */
+    POWERPC_DEF("970gx",         CPU_POWERPC_970GX,                  970GX),
+    /* PowerPC 970MP                                                         */
+    POWERPC_DEF("970mp",         CPU_POWERPC_970MP,                  970MP),
+    /* PowerPC 970MP v1.0                                                    */
+    POWERPC_DEF("970mp_v1.0",    CPU_POWERPC_970MP_v10,              970MP),
+    /* PowerPC 970MP v1.1                                                    */
+    POWERPC_DEF("970mp_v1.1",    CPU_POWERPC_970MP_v11,              970MP),
+#if defined (TODO)
+    /* PowerPC Cell                                                          */
+    POWERPC_DEF("Cell",          CPU_POWERPC_CELL,                   970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v1.0                                                     */
+    POWERPC_DEF("Cell_v1.0",     CPU_POWERPC_CELL_v10,               970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v2.0                                                     */
+    POWERPC_DEF("Cell_v2.0",     CPU_POWERPC_CELL_v20,               970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.0                                                     */
+    POWERPC_DEF("Cell_v3.0",     CPU_POWERPC_CELL_v30,               970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.1                                                     */
+    POWERPC_DEF("Cell_v3.1",     CPU_POWERPC_CELL_v31,               970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.2                                                     */
+    POWERPC_DEF("Cell_v3.2",     CPU_POWERPC_CELL_v32,               970),
+#endif
+#if defined (TODO)
+    /* RS64 (Apache/A35)                                                     */
+    /* This one seems to support the whole POWER2 instruction set
+     * and the PowerPC 64 one.
+     */
+    /* What about A10 & A30 ? */
+    POWERPC_DEF("RS64",          CPU_POWERPC_RS64,                   RS64),
+    POWERPC_DEF("Apache",        CPU_POWERPC_RS64,                   RS64),
+    POWERPC_DEF("A35",           CPU_POWERPC_RS64,                   RS64),
+#endif
+#if defined (TODO)
+    /* RS64-II (NorthStar/A50)                                               */
+    POWERPC_DEF("RS64-II",       CPU_POWERPC_RS64II,                 RS64),
+    POWERPC_DEF("NorthStar",     CPU_POWERPC_RS64II,                 RS64),
+    POWERPC_DEF("A50",           CPU_POWERPC_RS64II,                 RS64),
+#endif
+#if defined (TODO)
+    /* RS64-III (Pulsar)                                                     */
+    POWERPC_DEF("RS64-III",      CPU_POWERPC_RS64III,                RS64),
+    POWERPC_DEF("Pulsar",        CPU_POWERPC_RS64III,                RS64),
+#endif
+#if defined (TODO)
+    /* RS64-IV (IceStar/IStar/SStar)                                         */
+    POWERPC_DEF("RS64-IV",       CPU_POWERPC_RS64IV,                 RS64),
+    POWERPC_DEF("IceStar",       CPU_POWERPC_RS64IV,                 RS64),
+    POWERPC_DEF("IStar",         CPU_POWERPC_RS64IV,                 RS64),
+    POWERPC_DEF("SStar",         CPU_POWERPC_RS64IV,                 RS64),
+#endif
+#endif /* defined (TARGET_PPC64) */
+    /* POWER                                                                 */
+#if defined (TODO)
+    /* Original POWER                                                        */
+    POWERPC_DEF("POWER",         CPU_POWERPC_POWER,                  POWER),
+    POWERPC_DEF("RIOS",          CPU_POWERPC_POWER,                  POWER),
+    POWERPC_DEF("RSC",           CPU_POWERPC_POWER,                  POWER),
+    POWERPC_DEF("RSC3308",       CPU_POWERPC_POWER,                  POWER),
+    POWERPC_DEF("RSC4608",       CPU_POWERPC_POWER,                  POWER),
+#endif
+#if defined (TODO)
+    /* POWER2                                                                */
+    POWERPC_DEF("POWER2",        CPU_POWERPC_POWER2,                 POWER),
+    POWERPC_DEF("RSC2",          CPU_POWERPC_POWER2,                 POWER),
+    POWERPC_DEF("P2SC",          CPU_POWERPC_POWER2,                 POWER),
+#endif
+    /* PA semi cores                                                         */
+#if defined (TODO)
+    /* PA PA6T */
+    POWERPC_DEF("PA6T",          CPU_POWERPC_PA6T,                   PA6T),
+#endif
+    /* Generic PowerPCs                                                      */
+#if defined (TARGET_PPC64)
+    POWERPC_DEF("ppc64",         CPU_POWERPC_PPC64,                  PPC64),
+#endif
+    POWERPC_DEF("ppc32",         CPU_POWERPC_PPC32,                  PPC32),
+    POWERPC_DEF("ppc",           CPU_POWERPC_DEFAULT,                DEFAULT),
+    /* Fallback                                                              */
+    POWERPC_DEF("default",       CPU_POWERPC_DEFAULT,                DEFAULT),
+};
+
+/*****************************************************************************/
+/* Generic CPU instantiation routine                                         */
+static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
+{
+#if !defined(CONFIG_USER_ONLY)
+    int i;
+
+    env->irq_inputs = NULL;
+    /* Set all exception vectors to an invalid address */
+    for (i = 0; i < POWERPC_EXCP_NB; i++)
+        env->excp_vectors[i] = (target_ulong)(-1ULL);
+    env->hreset_excp_prefix = 0x00000000;
+    env->ivor_mask = 0x00000000;
+    env->ivpr_mask = 0x00000000;
+    /* Default MMU definitions */
+    env->nb_BATs = 0;
+    env->nb_tlb = 0;
+    env->nb_ways = 0;
+    env->tlb_type = TLB_NONE;
+#endif
+    /* Register SPR common to all PowerPC implementations */
+    gen_spr_generic(env);
+    spr_register(env, SPR_PVR, "PVR",
+                 /* Linux permits userspace to read PVR */
+#if defined(CONFIG_LINUX_USER)
+                 &spr_read_generic,
+#else
+                 SPR_NOACCESS,
+#endif
+                 SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 def->pvr);
+    /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */
+    if (def->svr != POWERPC_SVR_NONE) {
+        if (def->svr & POWERPC_SVR_E500) {
+            spr_register(env, SPR_E500_SVR, "SVR",
+                         SPR_NOACCESS, SPR_NOACCESS,
+                         &spr_read_generic, SPR_NOACCESS,
+                         def->svr & ~POWERPC_SVR_E500);
+        } else {
+            spr_register(env, SPR_SVR, "SVR",
+                         SPR_NOACCESS, SPR_NOACCESS,
+                         &spr_read_generic, SPR_NOACCESS,
+                         def->svr);
+        }
+    }
+    /* PowerPC implementation specific initialisations (SPRs, timers, ...) */
+    (*def->init_proc)(env);
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_prefix = env->hreset_excp_prefix;
+#endif
+    /* MSR bits & flags consistency checks */
+    if (env->msr_mask & (1 << 25)) {
+        switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
+        case POWERPC_FLAG_SPE:
+        case POWERPC_FLAG_VRE:
+            break;
+        default:
+            fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                    "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n");
+            exit(1);
+        }
+    } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
+        fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n");
+        exit(1);
+    }
+    if (env->msr_mask & (1 << 17)) {
+        switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) {
+        case POWERPC_FLAG_TGPR:
+        case POWERPC_FLAG_CE:
+            break;
+        default:
+            fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                    "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n");
+            exit(1);
+        }
+    } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) {
+        fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n");
+        exit(1);
+    }
+    if (env->msr_mask & (1 << 10)) {
+        switch (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE |
+                              POWERPC_FLAG_UBLE)) {
+        case POWERPC_FLAG_SE:
+        case POWERPC_FLAG_DWE:
+        case POWERPC_FLAG_UBLE:
+            break;
+        default:
+            fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                    "Should define POWERPC_FLAG_SE or POWERPC_FLAG_DWE or "
+                    "POWERPC_FLAG_UBLE\n");
+            exit(1);
+        }
+    } else if (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE |
+                             POWERPC_FLAG_UBLE)) {
+        fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                "Should not define POWERPC_FLAG_SE nor POWERPC_FLAG_DWE nor "
+                "POWERPC_FLAG_UBLE\n");
+            exit(1);
+    }
+    if (env->msr_mask & (1 << 9)) {
+        switch (env->flags & (POWERPC_FLAG_BE | POWERPC_FLAG_DE)) {
+        case POWERPC_FLAG_BE:
+        case POWERPC_FLAG_DE:
+            break;
+        default:
+            fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                    "Should define POWERPC_FLAG_BE or POWERPC_FLAG_DE\n");
+            exit(1);
+        }
+    } else if (env->flags & (POWERPC_FLAG_BE | POWERPC_FLAG_DE)) {
+        fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                "Should not define POWERPC_FLAG_BE nor POWERPC_FLAG_DE\n");
+        exit(1);
+    }
+    if (env->msr_mask & (1 << 2)) {
+        switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) {
+        case POWERPC_FLAG_PX:
+        case POWERPC_FLAG_PMM:
+            break;
+        default:
+            fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                    "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n");
+            exit(1);
+        }
+    } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) {
+        fprintf(stderr, "PowerPC MSR definition inconsistency\n"
+                "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n");
+        exit(1);
+    }
+    if ((env->flags & (POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_BUS_CLK)) == 0) {
+        fprintf(stderr, "PowerPC flags inconsistency\n"
+                "Should define the time-base and decrementer clock source\n");
+        exit(1);
+    }
+    /* Allocate TLBs buffer when needed */
+#if !defined(CONFIG_USER_ONLY)
+    if (env->nb_tlb != 0) {
+        int nb_tlb = env->nb_tlb;
+        if (env->id_tlbs != 0)
+            nb_tlb *= 2;
+        switch (env->tlb_type) {
+        case TLB_6XX:
+            env->tlb.tlb6 = qemu_mallocz(nb_tlb * sizeof(ppc6xx_tlb_t));
+            break;
+        case TLB_EMB:
+            env->tlb.tlbe = qemu_mallocz(nb_tlb * sizeof(ppcemb_tlb_t));
+            break;
+        case TLB_MAS:
+            env->tlb.tlbm = qemu_mallocz(nb_tlb * sizeof(ppcmas_tlb_t));
+            break;
+        }
+        /* Pre-compute some useful values */
+        env->tlb_per_way = env->nb_tlb / env->nb_ways;
+    }
+    if (env->irq_inputs == NULL) {
+        fprintf(stderr, "WARNING: no internal IRQ controller registered.\n"
+                " Attempt Qemu to crash very soon !\n");
+    }
+#endif
+    if (env->check_pow == NULL) {
+        fprintf(stderr, "WARNING: no power management check handler "
+                "registered.\n"
+                " Attempt Qemu to crash very soon !\n");
+    }
+}
+
+#if defined(PPC_DUMP_CPU)
+static void dump_ppc_sprs (CPUPPCState *env)
+{
+    ppc_spr_t *spr;
+#if !defined(CONFIG_USER_ONLY)
+    uint32_t sr, sw;
+#endif
+    uint32_t ur, uw;
+    int i, j, n;
+
+    printf("Special purpose registers:\n");
+    for (i = 0; i < 32; i++) {
+        for (j = 0; j < 32; j++) {
+            n = (i << 5) | j;
+            spr = &env->spr_cb[n];
+            uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS;
+            ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS;
+#if !defined(CONFIG_USER_ONLY)
+            sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
+            sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
+            if (sw || sr || uw || ur) {
+                printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n",
+                       (i << 5) | j, (i << 5) | j, spr->name,
+                       sw ? 'w' : '-', sr ? 'r' : '-',
+                       uw ? 'w' : '-', ur ? 'r' : '-');
+            }
+#else
+            if (uw || ur) {
+                printf("SPR: %4d (%03x) %-8s u%c%c\n",
+                       (i << 5) | j, (i << 5) | j, spr->name,
+                       uw ? 'w' : '-', ur ? 'r' : '-');
+            }
+#endif
+        }
+    }
+    fflush(stdout);
+    fflush(stderr);
+}
+#endif
+
+/*****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+
+/* Opcode types */
+enum {
+    PPC_DIRECT   = 0, /* Opcode routine        */
+    PPC_INDIRECT = 1, /* Indirect opcode table */
+};
+
+static inline int is_indirect_opcode (void *handler)
+{
+    return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
+}
+
+static inline opc_handler_t **ind_table(void *handler)
+{
+    return (opc_handler_t **)((unsigned long)handler & ~3);
+}
+
+/* Instruction table creation */
+/* Opcodes tables creation */
+static void fill_new_table (opc_handler_t **table, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        table[i] = &invalid_handler;
+}
+
+static int create_new_table (opc_handler_t **table, unsigned char idx)
+{
+    opc_handler_t **tmp;
+
+    tmp = malloc(0x20 * sizeof(opc_handler_t));
+    fill_new_table(tmp, 0x20);
+    table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
+
+    return 0;
+}
+
+static int insert_in_table (opc_handler_t **table, unsigned char idx,
+                            opc_handler_t *handler)
+{
+    if (table[idx] != &invalid_handler)
+        return -1;
+    table[idx] = handler;
+
+    return 0;
+}
+
+static int register_direct_insn (opc_handler_t **ppc_opcodes,
+                                 unsigned char idx, opc_handler_t *handler)
+{
+    if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
+        printf("*** ERROR: opcode %02x already assigned in main "
+               "opcode table\n", idx);
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
+        printf("           Registered handler '%s' - new handler '%s'\n",
+               ppc_opcodes[idx]->oname, handler->oname);
+#endif
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_in_table (opc_handler_t **table,
+                                  unsigned char idx1, unsigned char idx2,
+                                  opc_handler_t *handler)
+{
+    if (table[idx1] == &invalid_handler) {
+        if (create_new_table(table, idx1) < 0) {
+            printf("*** ERROR: unable to create indirect table "
+                   "idx=%02x\n", idx1);
+            return -1;
+        }
+    } else {
+        if (!is_indirect_opcode(table[idx1])) {
+            printf("*** ERROR: idx %02x already assigned to a direct "
+                   "opcode\n", idx1);
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
+            printf("           Registered handler '%s' - new handler '%s'\n",
+                   ind_table(table[idx1])[idx2]->oname, handler->oname);
+#endif
+            return -1;
+        }
+    }
+    if (handler != NULL &&
+        insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
+        printf("*** ERROR: opcode %02x already assigned in "
+               "opcode table %02x\n", idx2, idx1);
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
+        printf("           Registered handler '%s' - new handler '%s'\n",
+               ind_table(table[idx1])[idx2]->oname, handler->oname);
+#endif
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_insn (opc_handler_t **ppc_opcodes,
+                              unsigned char idx1, unsigned char idx2,
+                              opc_handler_t *handler)
+{
+    int ret;
+
+    ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
+
+    return ret;
+}
+
+static int register_dblind_insn (opc_handler_t **ppc_opcodes,
+                                 unsigned char idx1, unsigned char idx2,
+                                 unsigned char idx3, opc_handler_t *handler)
+{
+    if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
+        printf("*** ERROR: unable to join indirect table idx "
+               "[%02x-%02x]\n", idx1, idx2);
+        return -1;
+    }
+    if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
+                              handler) < 0) {
+        printf("*** ERROR: unable to insert opcode "
+               "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
+{
+    if (insn->opc2 != 0xFF) {
+        if (insn->opc3 != 0xFF) {
+            if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
+                                     insn->opc3, &insn->handler) < 0)
+                return -1;
+        } else {
+            if (register_ind_insn(ppc_opcodes, insn->opc1,
+                                  insn->opc2, &insn->handler) < 0)
+                return -1;
+        }
+    } else {
+        if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static int test_opcode_table (opc_handler_t **table, int len)
+{
+    int i, count, tmp;
+
+    for (i = 0, count = 0; i < len; i++) {
+        /* Consistency fixup */
+        if (table[i] == NULL)
+            table[i] = &invalid_handler;
+        if (table[i] != &invalid_handler) {
+            if (is_indirect_opcode(table[i])) {
+                tmp = test_opcode_table(ind_table(table[i]), 0x20);
+                if (tmp == 0) {
+                    free(table[i]);
+                    table[i] = &invalid_handler;
+                } else {
+                    count++;
+                }
+            } else {
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
+
+static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
+{
+    if (test_opcode_table(ppc_opcodes, 0x40) == 0)
+        printf("*** WARNING: no opcode defined !\n");
+}
+
+/*****************************************************************************/
+static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
+{
+    opcode_t *opc;
+
+    fill_new_table(env->opcodes, 0x40);
+    for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
+        if (((opc->handler.type & def->insns_flags) != 0) ||
+            ((opc->handler.type2 & def->insns_flags2) != 0)) {
+            if (register_insn(env->opcodes, opc) < 0) {
+                printf("*** ERROR initializing PowerPC instruction "
+                       "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+                       opc->opc3);
+                return -1;
+            }
+        }
+    }
+    fix_opcode_tables(env->opcodes);
+    fflush(stdout);
+    fflush(stderr);
+
+    return 0;
+}
+
+#if defined(PPC_DUMP_CPU)
+static void dump_ppc_insns (CPUPPCState *env)
+{
+    opc_handler_t **table, *handler;
+    const char *p, *q;
+    uint8_t opc1, opc2, opc3;
+
+    printf("Instructions set:\n");
+    /* opc1 is 6 bits long */
+    for (opc1 = 0x00; opc1 < 0x40; opc1++) {
+        table = env->opcodes;
+        handler = table[opc1];
+        if (is_indirect_opcode(handler)) {
+            /* opc2 is 5 bits long */
+            for (opc2 = 0; opc2 < 0x20; opc2++) {
+                table = env->opcodes;
+                handler = env->opcodes[opc1];
+                table = ind_table(handler);
+                handler = table[opc2];
+                if (is_indirect_opcode(handler)) {
+                    table = ind_table(handler);
+                    /* opc3 is 5 bits long */
+                    for (opc3 = 0; opc3 < 0x20; opc3++) {
+                        handler = table[opc3];
+                        if (handler->handler != &gen_invalid) {
+                            /* Special hack to properly dump SPE insns */
+                            p = strchr(handler->oname, '_');
+                            if (p == NULL) {
+                                printf("INSN: %02x %02x %02x (%02d %04d) : "
+                                       "%s\n",
+                                       opc1, opc2, opc3, opc1,
+                                       (opc3 << 5) | opc2,
+                                       handler->oname);
+                            } else {
+                                q = "speundef";
+                                if ((p - handler->oname) != strlen(q) ||
+                                    memcmp(handler->oname, q, strlen(q)) != 0) {
+                                    /* First instruction */
+                                    printf("INSN: %02x %02x %02x (%02d %04d) : "
+                                           "%.*s\n",
+                                           opc1, opc2 << 1, opc3, opc1,
+                                           (opc3 << 6) | (opc2 << 1),
+                                           (int)(p - handler->oname),
+                                           handler->oname);
+                                }
+                                if (strcmp(p + 1, q) != 0) {
+                                    /* Second instruction */
+                                    printf("INSN: %02x %02x %02x (%02d %04d) : "
+                                           "%s\n",
+                                           opc1, (opc2 << 1) | 1, opc3, opc1,
+                                           (opc3 << 6) | (opc2 << 1) | 1,
+                                           p + 1);
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    if (handler->handler != &gen_invalid) {
+                        printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
+                               opc1, opc2, opc1, opc2, handler->oname);
+                    }
+                }
+            }
+        } else {
+            if (handler->handler != &gen_invalid) {
+                printf("INSN: %02x -- -- (%02d ----) : %s\n",
+                       opc1, opc1, handler->oname);
+            }
+        }
+    }
+}
+#endif
+
+static int gdb_get_float_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        stfq_p(mem_buf, env->fpr[n]);
+        return 8;
+    }
+    if (n == 32) {
+        /* FPSCR not implemented  */
+        memset(mem_buf, 0, 4);
+        return 4;
+    }
+    return 0;
+}
+
+static int gdb_set_float_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        env->fpr[n] = ldfq_p(mem_buf);
+        return 8;
+    }
+    if (n == 32) {
+        /* FPSCR not implemented  */
+        return 4;
+    }
+    return 0;
+}
+
+static int gdb_get_avr_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+#ifdef HOST_WORDS_BIGENDIAN
+        stq_p(mem_buf, env->avr[n].u64[0]);
+        stq_p(mem_buf+8, env->avr[n].u64[1]);
+#else
+        stq_p(mem_buf, env->avr[n].u64[1]);
+        stq_p(mem_buf+8, env->avr[n].u64[0]);
+#endif
+        return 16;
+    }
+    if (n == 32) {
+        stl_p(mem_buf, env->vscr);
+        return 4;
+    }
+    if (n == 33) {
+        stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+        return 4;
+    }
+    return 0;
+}
+
+static int gdb_set_avr_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+#ifdef HOST_WORDS_BIGENDIAN
+        env->avr[n].u64[0] = ldq_p(mem_buf);
+        env->avr[n].u64[1] = ldq_p(mem_buf+8);
+#else
+        env->avr[n].u64[1] = ldq_p(mem_buf);
+        env->avr[n].u64[0] = ldq_p(mem_buf+8);
+#endif
+        return 16;
+    }
+    if (n == 32) {
+        env->vscr = ldl_p(mem_buf);
+        return 4;
+    }
+    if (n == 33) {
+        env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf);
+        return 4;
+    }
+    return 0;
+}
+
+static int gdb_get_spe_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+#if defined(TARGET_PPC64)
+        stl_p(mem_buf, env->gpr[n] >> 32);
+#else
+        stl_p(mem_buf, env->gprh[n]);
+#endif
+        return 4;
+    }
+    if (n == 32) {
+        stq_p(mem_buf, env->spe_acc);
+        return 8;
+    }
+    if (n == 33) {
+        stl_p(mem_buf, env->spe_fscr);
+        return 4;
+    }
+    return 0;
+}
+
+static int gdb_set_spe_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+#if defined(TARGET_PPC64)
+        target_ulong lo = (uint32_t)env->gpr[n];
+        target_ulong hi = (target_ulong)ldl_p(mem_buf) << 32;
+        env->gpr[n] = lo | hi;
+#else
+        env->gprh[n] = ldl_p(mem_buf);
+#endif
+        return 4;
+    }
+    if (n == 32) {
+        env->spe_acc = ldq_p(mem_buf);
+        return 8;
+    }
+    if (n == 33) {
+        env->spe_fscr = ldl_p(mem_buf);
+        return 4;
+    }
+    return 0;
+}
+
+int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
+{
+    env->msr_mask = def->msr_mask;
+    env->mmu_model = def->mmu_model;
+    env->excp_model = def->excp_model;
+    env->bus_model = def->bus_model;
+    env->insns_flags = def->insns_flags;
+    env->insns_flags2 = def->insns_flags2;
+    env->flags = def->flags;
+    env->bfd_mach = def->bfd_mach;
+    env->check_pow = def->check_pow;
+    if (create_ppc_opcodes(env, def) < 0)
+        return -1;
+    init_ppc_proc(env, def);
+
+    if (def->insns_flags & PPC_FLOAT) {
+        gdb_register_coprocessor(env, gdb_get_float_reg, gdb_set_float_reg,
+                                 33, "power-fpu.xml", 0);
+    }
+    if (def->insns_flags & PPC_ALTIVEC) {
+        gdb_register_coprocessor(env, gdb_get_avr_reg, gdb_set_avr_reg,
+                                 34, "power-altivec.xml", 0);
+    }
+    if (def->insns_flags & PPC_SPE) {
+        gdb_register_coprocessor(env, gdb_get_spe_reg, gdb_set_spe_reg,
+                                 34, "power-spe.xml", 0);
+    }
+
+#if defined(PPC_DUMP_CPU)
+    {
+        const char *mmu_model, *excp_model, *bus_model;
+        switch (env->mmu_model) {
+        case POWERPC_MMU_32B:
+            mmu_model = "PowerPC 32";
+            break;
+        case POWERPC_MMU_SOFT_6xx:
+            mmu_model = "PowerPC 6xx/7xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_74xx:
+            mmu_model = "PowerPC 74xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_4xx:
+            mmu_model = "PowerPC 4xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_4xx_Z:
+            mmu_model = "PowerPC 4xx with software driven TLBs "
+                "and zones protections";
+            break;
+        case POWERPC_MMU_REAL:
+            mmu_model = "PowerPC real mode only";
+            break;
+        case POWERPC_MMU_MPC8xx:
+            mmu_model = "PowerPC MPC8xx";
+            break;
+        case POWERPC_MMU_BOOKE:
+            mmu_model = "PowerPC BookE";
+            break;
+        case POWERPC_MMU_BOOKE206:
+            mmu_model = "PowerPC BookE 2.06";
+            break;
+        case POWERPC_MMU_601:
+            mmu_model = "PowerPC 601";
+            break;
+#if defined (TARGET_PPC64)
+        case POWERPC_MMU_64B:
+            mmu_model = "PowerPC 64";
+            break;
+        case POWERPC_MMU_620:
+            mmu_model = "PowerPC 620";
+            break;
+#endif
+        default:
+            mmu_model = "Unknown or invalid";
+            break;
+        }
+        switch (env->excp_model) {
+        case POWERPC_EXCP_STD:
+            excp_model = "PowerPC";
+            break;
+        case POWERPC_EXCP_40x:
+            excp_model = "PowerPC 40x";
+            break;
+        case POWERPC_EXCP_601:
+            excp_model = "PowerPC 601";
+            break;
+        case POWERPC_EXCP_602:
+            excp_model = "PowerPC 602";
+            break;
+        case POWERPC_EXCP_603:
+            excp_model = "PowerPC 603";
+            break;
+        case POWERPC_EXCP_603E:
+            excp_model = "PowerPC 603e";
+            break;
+        case POWERPC_EXCP_604:
+            excp_model = "PowerPC 604";
+            break;
+        case POWERPC_EXCP_7x0:
+            excp_model = "PowerPC 740/750";
+            break;
+        case POWERPC_EXCP_7x5:
+            excp_model = "PowerPC 745/755";
+            break;
+        case POWERPC_EXCP_74xx:
+            excp_model = "PowerPC 74xx";
+            break;
+        case POWERPC_EXCP_BOOKE:
+            excp_model = "PowerPC BookE";
+            break;
+#if defined (TARGET_PPC64)
+        case POWERPC_EXCP_970:
+            excp_model = "PowerPC 970";
+            break;
+#endif
+        default:
+            excp_model = "Unknown or invalid";
+            break;
+        }
+        switch (env->bus_model) {
+        case PPC_FLAGS_INPUT_6xx:
+            bus_model = "PowerPC 6xx";
+            break;
+        case PPC_FLAGS_INPUT_BookE:
+            bus_model = "PowerPC BookE";
+            break;
+        case PPC_FLAGS_INPUT_405:
+            bus_model = "PowerPC 405";
+            break;
+        case PPC_FLAGS_INPUT_401:
+            bus_model = "PowerPC 401/403";
+            break;
+        case PPC_FLAGS_INPUT_RCPU:
+            bus_model = "RCPU / MPC8xx";
+            break;
+#if defined (TARGET_PPC64)
+        case PPC_FLAGS_INPUT_970:
+            bus_model = "PowerPC 970";
+            break;
+#endif
+        default:
+            bus_model = "Unknown or invalid";
+            break;
+        }
+        printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n"
+               "    MMU model        : %s\n",
+               def->name, def->pvr, def->msr_mask, mmu_model);
+#if !defined(CONFIG_USER_ONLY)
+        if (env->tlb != NULL) {
+            printf("                       %d %s TLB in %d ways\n",
+                   env->nb_tlb, env->id_tlbs ? "splitted" : "merged",
+                   env->nb_ways);
+        }
+#endif
+        printf("    Exceptions model : %s\n"
+               "    Bus model        : %s\n",
+               excp_model, bus_model);
+        printf("    MSR features     :\n");
+        if (env->flags & POWERPC_FLAG_SPE)
+            printf("                        signal processing engine enable"
+                   "\n");
+        else if (env->flags & POWERPC_FLAG_VRE)
+            printf("                        vector processor enable\n");
+        if (env->flags & POWERPC_FLAG_TGPR)
+            printf("                        temporary GPRs\n");
+        else if (env->flags & POWERPC_FLAG_CE)
+            printf("                        critical input enable\n");
+        if (env->flags & POWERPC_FLAG_SE)
+            printf("                        single-step trace mode\n");
+        else if (env->flags & POWERPC_FLAG_DWE)
+            printf("                        debug wait enable\n");
+        else if (env->flags & POWERPC_FLAG_UBLE)
+            printf("                        user BTB lock enable\n");
+        if (env->flags & POWERPC_FLAG_BE)
+            printf("                        branch-step trace mode\n");
+        else if (env->flags & POWERPC_FLAG_DE)
+            printf("                        debug interrupt enable\n");
+        if (env->flags & POWERPC_FLAG_PX)
+            printf("                        inclusive protection\n");
+        else if (env->flags & POWERPC_FLAG_PMM)
+            printf("                        performance monitor mark\n");
+        if (env->flags == POWERPC_FLAG_NONE)
+            printf("                        none\n");
+        printf("    Time-base/decrementer clock source: %s\n",
+               env->flags & POWERPC_FLAG_RTC_CLK ? "RTC clock" : "bus clock");
+    }
+    dump_ppc_insns(env);
+    dump_ppc_sprs(env);
+    fflush(stdout);
+#endif
+
+    return 0;
+}
+
+static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr)
+{
+    const ppc_def_t *ret;
+    uint32_t pvr_rev;
+    int i, best, match, best_match, max;
+
+    ret = NULL;
+    max = ARRAY_SIZE(ppc_defs);
+    best = -1;
+    pvr_rev = pvr & 0xFFFF;
+    /* We want all specified bits to match */
+    best_match = 32 - ctz32(pvr_rev);
+    for (i = 0; i < max; i++) {
+        /* We check that the 16 higher bits are the same to ensure the CPU
+         * model will be the choosen one.
+         */
+        if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) {
+            /* We want as much as possible of the low-level 16 bits
+             * to be the same but we allow inexact matches.
+             */
+            match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF));
+            /* We check '>=' instead of '>' because the PPC_defs table
+             * is ordered by increasing revision.
+             * Then, we will match the higher revision compatible
+             * with the requested PVR
+             */
+            if (match >= best_match) {
+                best = i;
+                best_match = match;
+            }
+        }
+    }
+    if (best != -1)
+        ret = &ppc_defs[best];
+
+    return ret;
+}
+
+#include <ctype.h>
+
+const ppc_def_t *cpu_ppc_find_by_name (const char *name)
+{
+    const ppc_def_t *ret;
+    const char *p;
+    int i, max, len;
+
+    /* Check if the given name is a PVR */
+    len = strlen(name);
+    if (len == 10 && name[0] == '0' && name[1] == 'x') {
+        p = name + 2;
+        goto check_pvr;
+    } else if (len == 8) {
+        p = name;
+    check_pvr:
+        for (i = 0; i < 8; i++) {
+            if (!qemu_isxdigit(*p++))
+                break;
+        }
+        if (i == 8)
+            return ppc_find_by_pvr(strtoul(name, NULL, 16));
+    }
+    ret = NULL;
+    max = ARRAY_SIZE(ppc_defs);
+    for (i = 0; i < max; i++) {
+        if (strcasecmp(name, ppc_defs[i].name) == 0) {
+            ret = &ppc_defs[i];
+            break;
+        }
+    }
+
+    return ret;
+}
+
+void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
+{
+    int i, max;
+
+    max = ARRAY_SIZE(ppc_defs);
+    for (i = 0; i < max; i++) {
+        (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
+                       ppc_defs[i].name, ppc_defs[i].pvr);
+    }
+}
diff --git a/qemu-0.15.x/target-s390x/cpu.h b/qemu-0.15.x/target-s390x/cpu.h
new file mode 100644
index 0000000..d48a9b7
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/cpu.h
@@ -0,0 +1,976 @@
+/*
+ * S/390 virtual CPU header
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_S390X_H
+#define CPU_S390X_H
+
+#define TARGET_LONG_BITS 64
+
+#define ELF_MACHINE	EM_S390
+
+#define CPUState struct CPUS390XState
+
+#include "cpu-defs.h"
+#define TARGET_PAGE_BITS 12
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 64
+#define TARGET_VIRT_ADDR_SPACE_BITS 64
+
+#include "cpu-all.h"
+
+#include "softfloat.h"
+
+#define NB_MMU_MODES 3
+
+#define MMU_MODE0_SUFFIX _primary
+#define MMU_MODE1_SUFFIX _secondary
+#define MMU_MODE2_SUFFIX _home
+
+#define MMU_USER_IDX 1
+
+#define MAX_EXT_QUEUE 16
+
+typedef struct PSW {
+    uint64_t mask;
+    uint64_t addr;
+} PSW;
+
+typedef struct ExtQueue {
+    uint32_t code;
+    uint32_t param;
+    uint32_t param64;
+} ExtQueue;
+
+typedef struct CPUS390XState {
+    uint64_t regs[16];	/* GP registers */
+
+    uint32_t aregs[16];	/* access registers */
+
+    uint32_t fpc;	/* floating-point control register */
+    CPU_DoubleU fregs[16]; /* FP registers */
+    float_status fpu_status; /* passed to softfloat lib */
+
+    PSW psw;
+
+    uint32_t cc_op;
+    uint64_t cc_src;
+    uint64_t cc_dst;
+    uint64_t cc_vr;
+
+    uint64_t __excp_addr;
+    uint64_t psa;
+
+    uint32_t int_pgm_code;
+    uint32_t int_pgm_ilc;
+
+    uint32_t int_svc_code;
+    uint32_t int_svc_ilc;
+
+    uint64_t cregs[16]; /* control registers */
+
+    int pending_int;
+    ExtQueue ext_queue[MAX_EXT_QUEUE];
+
+    int ext_index;
+
+    CPU_COMMON
+
+    /* reset does memset(0) up to here */
+
+    int cpu_num;
+    uint8_t *storage_keys;
+
+    uint64_t tod_offset;
+    uint64_t tod_basetime;
+    QEMUTimer *tod_timer;
+
+    QEMUTimer *cpu_timer;
+} CPUS390XState;
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->regs[15] = newsp;
+    }
+    env->regs[0] = 0;
+}
+#endif
+
+/* Interrupt Codes */
+/* Program Interrupts */
+#define PGM_OPERATION                   0x0001
+#define PGM_PRIVILEGED                  0x0002
+#define PGM_EXECUTE                     0x0003
+#define PGM_PROTECTION                  0x0004
+#define PGM_ADDRESSING                  0x0005
+#define PGM_SPECIFICATION               0x0006
+#define PGM_DATA                        0x0007
+#define PGM_FIXPT_OVERFLOW              0x0008
+#define PGM_FIXPT_DIVIDE                0x0009
+#define PGM_DEC_OVERFLOW                0x000a
+#define PGM_DEC_DIVIDE                  0x000b
+#define PGM_HFP_EXP_OVERFLOW            0x000c
+#define PGM_HFP_EXP_UNDERFLOW           0x000d
+#define PGM_HFP_SIGNIFICANCE            0x000e
+#define PGM_HFP_DIVIDE                  0x000f
+#define PGM_SEGMENT_TRANS               0x0010
+#define PGM_PAGE_TRANS                  0x0011
+#define PGM_TRANS_SPEC                  0x0012
+#define PGM_SPECIAL_OP                  0x0013
+#define PGM_OPERAND                     0x0015
+#define PGM_TRACE_TABLE                 0x0016
+#define PGM_SPACE_SWITCH                0x001c
+#define PGM_HFP_SQRT                    0x001d
+#define PGM_PC_TRANS_SPEC               0x001f
+#define PGM_AFX_TRANS                   0x0020
+#define PGM_ASX_TRANS                   0x0021
+#define PGM_LX_TRANS                    0x0022
+#define PGM_EX_TRANS                    0x0023
+#define PGM_PRIM_AUTH                   0x0024
+#define PGM_SEC_AUTH                    0x0025
+#define PGM_ALET_SPEC                   0x0028
+#define PGM_ALEN_SPEC                   0x0029
+#define PGM_ALE_SEQ                     0x002a
+#define PGM_ASTE_VALID                  0x002b
+#define PGM_ASTE_SEQ                    0x002c
+#define PGM_EXT_AUTH                    0x002d
+#define PGM_STACK_FULL                  0x0030
+#define PGM_STACK_EMPTY                 0x0031
+#define PGM_STACK_SPEC                  0x0032
+#define PGM_STACK_TYPE                  0x0033
+#define PGM_STACK_OP                    0x0034
+#define PGM_ASCE_TYPE                   0x0038
+#define PGM_REG_FIRST_TRANS             0x0039
+#define PGM_REG_SEC_TRANS               0x003a
+#define PGM_REG_THIRD_TRANS             0x003b
+#define PGM_MONITOR                     0x0040
+#define PGM_PER                         0x0080
+#define PGM_CRYPTO                      0x0119
+
+/* External Interrupts */
+#define EXT_INTERRUPT_KEY               0x0040
+#define EXT_CLOCK_COMP                  0x1004
+#define EXT_CPU_TIMER                   0x1005
+#define EXT_MALFUNCTION                 0x1200
+#define EXT_EMERGENCY                   0x1201
+#define EXT_EXTERNAL_CALL               0x1202
+#define EXT_ETR                         0x1406
+#define EXT_SERVICE                     0x2401
+#define EXT_VIRTIO                      0x2603
+
+/* PSW defines */
+#undef PSW_MASK_PER
+#undef PSW_MASK_DAT
+#undef PSW_MASK_IO
+#undef PSW_MASK_EXT
+#undef PSW_MASK_KEY
+#undef PSW_SHIFT_KEY
+#undef PSW_MASK_MCHECK
+#undef PSW_MASK_WAIT
+#undef PSW_MASK_PSTATE
+#undef PSW_MASK_ASC
+#undef PSW_MASK_CC
+#undef PSW_MASK_PM
+#undef PSW_MASK_64
+
+#define PSW_MASK_PER            0x4000000000000000ULL
+#define PSW_MASK_DAT            0x0400000000000000ULL
+#define PSW_MASK_IO             0x0200000000000000ULL
+#define PSW_MASK_EXT            0x0100000000000000ULL
+#define PSW_MASK_KEY            0x00F0000000000000ULL
+#define PSW_SHIFT_KEY           56
+#define PSW_MASK_MCHECK         0x0004000000000000ULL
+#define PSW_MASK_WAIT           0x0002000000000000ULL
+#define PSW_MASK_PSTATE         0x0001000000000000ULL
+#define PSW_MASK_ASC            0x0000C00000000000ULL
+#define PSW_MASK_CC             0x0000300000000000ULL
+#define PSW_MASK_PM             0x00000F0000000000ULL
+#define PSW_MASK_64             0x0000000100000000ULL
+#define PSW_MASK_32             0x0000000080000000ULL
+
+#undef PSW_ASC_PRIMARY
+#undef PSW_ASC_ACCREG
+#undef PSW_ASC_SECONDARY
+#undef PSW_ASC_HOME
+
+#define PSW_ASC_PRIMARY         0x0000000000000000ULL
+#define PSW_ASC_ACCREG          0x0000400000000000ULL
+#define PSW_ASC_SECONDARY       0x0000800000000000ULL
+#define PSW_ASC_HOME            0x0000C00000000000ULL
+
+/* tb flags */
+
+#define FLAG_MASK_PER           (PSW_MASK_PER    >> 32)
+#define FLAG_MASK_DAT           (PSW_MASK_DAT    >> 32)
+#define FLAG_MASK_IO            (PSW_MASK_IO     >> 32)
+#define FLAG_MASK_EXT           (PSW_MASK_EXT    >> 32)
+#define FLAG_MASK_KEY           (PSW_MASK_KEY    >> 32)
+#define FLAG_MASK_MCHECK        (PSW_MASK_MCHECK >> 32)
+#define FLAG_MASK_WAIT          (PSW_MASK_WAIT   >> 32)
+#define FLAG_MASK_PSTATE        (PSW_MASK_PSTATE >> 32)
+#define FLAG_MASK_ASC           (PSW_MASK_ASC    >> 32)
+#define FLAG_MASK_CC            (PSW_MASK_CC     >> 32)
+#define FLAG_MASK_PM            (PSW_MASK_PM     >> 32)
+#define FLAG_MASK_64            (PSW_MASK_64     >> 32)
+#define FLAG_MASK_32            0x00001000
+
+static inline int cpu_mmu_index (CPUState *env)
+{
+    if (env->psw.mask & PSW_MASK_PSTATE) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->psw.addr;
+    *cs_base = 0;
+    *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) |
+             ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0);
+}
+
+static inline int get_ilc(uint8_t opc)
+{
+    switch (opc >> 6) {
+    case 0:
+        return 1;
+    case 1:
+    case 2:
+        return 2;
+    case 3:
+        return 3;
+    }
+
+    return 0;
+}
+
+#define ILC_LATER       0x20
+#define ILC_LATER_INC   0x21
+#define ILC_LATER_INC_2 0x22
+
+
+CPUS390XState *cpu_s390x_init(const char *cpu_model);
+void s390x_translate_init(void);
+int cpu_s390x_exec(CPUS390XState *s);
+void cpu_s390x_close(CPUS390XState *s);
+void do_interrupt (CPUState *env);
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+int cpu_s390x_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
+#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
+
+
+#ifndef CONFIG_USER_ONLY
+int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall);
+
+#ifdef CONFIG_KVM
+void kvm_s390_interrupt(CPUState *env, int type, uint32_t code);
+void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token);
+void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
+                                 uint64_t parm64, int vm);
+#else
+static inline void kvm_s390_interrupt(CPUState *env, int type, uint32_t code)
+{
+}
+
+static inline void kvm_s390_virtio_irq(CPUState *env, int config_change,
+                                       uint64_t token)
+{
+}
+
+static inline void kvm_s390_interrupt_internal(CPUState *env, int type,
+                                               uint32_t parm, uint64_t parm64,
+                                               int vm)
+{
+}
+#endif
+CPUState *s390_cpu_addr2state(uint16_t cpu_addr);
+
+/* from s390-virtio-bus */
+extern const target_phys_addr_t virtio_size;
+
+#endif
+void cpu_lock(void);
+void cpu_unlock(void);
+
+static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls)
+{
+    env->aregs[0] = newtls >> 32;
+    env->aregs[1] = newtls & 0xffffffffULL;
+}
+
+#define cpu_init cpu_s390x_init
+#define cpu_exec cpu_s390x_exec
+#define cpu_gen_code cpu_s390x_gen_code
+#define cpu_signal_handler cpu_s390x_signal_handler
+
+#include "exec-all.h"
+
+#ifdef CONFIG_USER_ONLY
+
+#define EXCP_OPEX 1 /* operation exception (sigill) */
+#define EXCP_SVC 2 /* supervisor call (syscall) */
+#define EXCP_ADDR 5 /* addressing exception */
+#define EXCP_SPEC 6 /* specification exception */
+
+#else
+
+#define EXCP_EXT 1 /* external interrupt */
+#define EXCP_SVC 2 /* supervisor call (syscall) */
+#define EXCP_PGM 3 /* program interruption */
+
+#endif /* CONFIG_USER_ONLY */
+
+#define INTERRUPT_EXT        (1 << 0)
+#define INTERRUPT_TOD        (1 << 1)
+#define INTERRUPT_CPUTIMER   (1 << 2)
+
+/* Program Status Word.  */
+#define S390_PSWM_REGNUM 0
+#define S390_PSWA_REGNUM 1
+/* General Purpose Registers.  */
+#define S390_R0_REGNUM 2
+#define S390_R1_REGNUM 3
+#define S390_R2_REGNUM 4
+#define S390_R3_REGNUM 5
+#define S390_R4_REGNUM 6
+#define S390_R5_REGNUM 7
+#define S390_R6_REGNUM 8
+#define S390_R7_REGNUM 9
+#define S390_R8_REGNUM 10
+#define S390_R9_REGNUM 11
+#define S390_R10_REGNUM 12
+#define S390_R11_REGNUM 13
+#define S390_R12_REGNUM 14
+#define S390_R13_REGNUM 15
+#define S390_R14_REGNUM 16
+#define S390_R15_REGNUM 17
+/* Access Registers.  */
+#define S390_A0_REGNUM 18
+#define S390_A1_REGNUM 19
+#define S390_A2_REGNUM 20
+#define S390_A3_REGNUM 21
+#define S390_A4_REGNUM 22
+#define S390_A5_REGNUM 23
+#define S390_A6_REGNUM 24
+#define S390_A7_REGNUM 25
+#define S390_A8_REGNUM 26
+#define S390_A9_REGNUM 27
+#define S390_A10_REGNUM 28
+#define S390_A11_REGNUM 29
+#define S390_A12_REGNUM 30
+#define S390_A13_REGNUM 31
+#define S390_A14_REGNUM 32
+#define S390_A15_REGNUM 33
+/* Floating Point Control Word.  */
+#define S390_FPC_REGNUM 34
+/* Floating Point Registers.  */
+#define S390_F0_REGNUM 35
+#define S390_F1_REGNUM 36
+#define S390_F2_REGNUM 37
+#define S390_F3_REGNUM 38
+#define S390_F4_REGNUM 39
+#define S390_F5_REGNUM 40
+#define S390_F6_REGNUM 41
+#define S390_F7_REGNUM 42
+#define S390_F8_REGNUM 43
+#define S390_F9_REGNUM 44
+#define S390_F10_REGNUM 45
+#define S390_F11_REGNUM 46
+#define S390_F12_REGNUM 47
+#define S390_F13_REGNUM 48
+#define S390_F14_REGNUM 49
+#define S390_F15_REGNUM 50
+/* Total.  */
+#define S390_NUM_REGS 51
+
+/* Pseudo registers -- PC and condition code.  */
+#define S390_PC_REGNUM S390_NUM_REGS
+#define S390_CC_REGNUM (S390_NUM_REGS+1)
+#define S390_NUM_PSEUDO_REGS 2
+#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2)
+
+
+
+/* Program Status Word.  */
+#define S390_PSWM_REGNUM 0
+#define S390_PSWA_REGNUM 1
+/* General Purpose Registers.  */
+#define S390_R0_REGNUM 2
+#define S390_R1_REGNUM 3
+#define S390_R2_REGNUM 4
+#define S390_R3_REGNUM 5
+#define S390_R4_REGNUM 6
+#define S390_R5_REGNUM 7
+#define S390_R6_REGNUM 8
+#define S390_R7_REGNUM 9
+#define S390_R8_REGNUM 10
+#define S390_R9_REGNUM 11
+#define S390_R10_REGNUM 12
+#define S390_R11_REGNUM 13
+#define S390_R12_REGNUM 14
+#define S390_R13_REGNUM 15
+#define S390_R14_REGNUM 16
+#define S390_R15_REGNUM 17
+/* Access Registers.  */
+#define S390_A0_REGNUM 18
+#define S390_A1_REGNUM 19
+#define S390_A2_REGNUM 20
+#define S390_A3_REGNUM 21
+#define S390_A4_REGNUM 22
+#define S390_A5_REGNUM 23
+#define S390_A6_REGNUM 24
+#define S390_A7_REGNUM 25
+#define S390_A8_REGNUM 26
+#define S390_A9_REGNUM 27
+#define S390_A10_REGNUM 28
+#define S390_A11_REGNUM 29
+#define S390_A12_REGNUM 30
+#define S390_A13_REGNUM 31
+#define S390_A14_REGNUM 32
+#define S390_A15_REGNUM 33
+/* Floating Point Control Word.  */
+#define S390_FPC_REGNUM 34
+/* Floating Point Registers.  */
+#define S390_F0_REGNUM 35
+#define S390_F1_REGNUM 36
+#define S390_F2_REGNUM 37
+#define S390_F3_REGNUM 38
+#define S390_F4_REGNUM 39
+#define S390_F5_REGNUM 40
+#define S390_F6_REGNUM 41
+#define S390_F7_REGNUM 42
+#define S390_F8_REGNUM 43
+#define S390_F9_REGNUM 44
+#define S390_F10_REGNUM 45
+#define S390_F11_REGNUM 46
+#define S390_F12_REGNUM 47
+#define S390_F13_REGNUM 48
+#define S390_F14_REGNUM 49
+#define S390_F15_REGNUM 50
+/* Total.  */
+#define S390_NUM_REGS 51
+
+/* Pseudo registers -- PC and condition code.  */
+#define S390_PC_REGNUM S390_NUM_REGS
+#define S390_CC_REGNUM (S390_NUM_REGS+1)
+#define S390_NUM_PSEUDO_REGS 2
+#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2)
+
+/* CC optimization */
+
+enum cc_op {
+    CC_OP_CONST0 = 0,           /* CC is 0 */
+    CC_OP_CONST1,               /* CC is 1 */
+    CC_OP_CONST2,               /* CC is 2 */
+    CC_OP_CONST3,               /* CC is 3 */
+
+    CC_OP_DYNAMIC,              /* CC calculation defined by env->cc_op */
+    CC_OP_STATIC,               /* CC value is env->cc_op */
+
+    CC_OP_NZ,                   /* env->cc_dst != 0 */
+    CC_OP_LTGT_32,              /* signed less/greater than (32bit) */
+    CC_OP_LTGT_64,              /* signed less/greater than (64bit) */
+    CC_OP_LTUGTU_32,            /* unsigned less/greater than (32bit) */
+    CC_OP_LTUGTU_64,            /* unsigned less/greater than (64bit) */
+    CC_OP_LTGT0_32,             /* signed less/greater than 0 (32bit) */
+    CC_OP_LTGT0_64,             /* signed less/greater than 0 (64bit) */
+
+    CC_OP_ADD_64,               /* overflow on add (64bit) */
+    CC_OP_ADDU_64,              /* overflow on unsigned add (64bit) */
+    CC_OP_SUB_64,               /* overflow on substraction (64bit) */
+    CC_OP_SUBU_64,              /* overflow on unsigned substraction (64bit) */
+    CC_OP_ABS_64,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_64,              /* sign eval on nabs (64bit) */
+
+    CC_OP_ADD_32,               /* overflow on add (32bit) */
+    CC_OP_ADDU_32,              /* overflow on unsigned add (32bit) */
+    CC_OP_SUB_32,               /* overflow on substraction (32bit) */
+    CC_OP_SUBU_32,              /* overflow on unsigned substraction (32bit) */
+    CC_OP_ABS_32,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_32,              /* sign eval on nabs (64bit) */
+
+    CC_OP_COMP_32,              /* complement */
+    CC_OP_COMP_64,              /* complement */
+
+    CC_OP_TM_32,                /* test under mask (32bit) */
+    CC_OP_TM_64,                /* test under mask (64bit) */
+
+    CC_OP_LTGT_F32,             /* FP compare (32bit) */
+    CC_OP_LTGT_F64,             /* FP compare (64bit) */
+
+    CC_OP_NZ_F32,               /* FP dst != 0 (32bit) */
+    CC_OP_NZ_F64,               /* FP dst != 0 (64bit) */
+
+    CC_OP_ICM,                  /* insert characters under mask */
+    CC_OP_SLAG,                 /* Calculate shift left signed */
+    CC_OP_MAX
+};
+
+static const char *cc_names[] = {
+    [CC_OP_CONST0]    = "CC_OP_CONST0",
+    [CC_OP_CONST1]    = "CC_OP_CONST1",
+    [CC_OP_CONST2]    = "CC_OP_CONST2",
+    [CC_OP_CONST3]    = "CC_OP_CONST3",
+    [CC_OP_DYNAMIC]   = "CC_OP_DYNAMIC",
+    [CC_OP_STATIC]    = "CC_OP_STATIC",
+    [CC_OP_NZ]        = "CC_OP_NZ",
+    [CC_OP_LTGT_32]   = "CC_OP_LTGT_32",
+    [CC_OP_LTGT_64]   = "CC_OP_LTGT_64",
+    [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
+    [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
+    [CC_OP_LTGT0_32]  = "CC_OP_LTGT0_32",
+    [CC_OP_LTGT0_64]  = "CC_OP_LTGT0_64",
+    [CC_OP_ADD_64]    = "CC_OP_ADD_64",
+    [CC_OP_ADDU_64]   = "CC_OP_ADDU_64",
+    [CC_OP_SUB_64]    = "CC_OP_SUB_64",
+    [CC_OP_SUBU_64]   = "CC_OP_SUBU_64",
+    [CC_OP_ABS_64]    = "CC_OP_ABS_64",
+    [CC_OP_NABS_64]   = "CC_OP_NABS_64",
+    [CC_OP_ADD_32]    = "CC_OP_ADD_32",
+    [CC_OP_ADDU_32]   = "CC_OP_ADDU_32",
+    [CC_OP_SUB_32]    = "CC_OP_SUB_32",
+    [CC_OP_SUBU_32]   = "CC_OP_SUBU_32",
+    [CC_OP_ABS_32]    = "CC_OP_ABS_32",
+    [CC_OP_NABS_32]   = "CC_OP_NABS_32",
+    [CC_OP_COMP_32]   = "CC_OP_COMP_32",
+    [CC_OP_COMP_64]   = "CC_OP_COMP_64",
+    [CC_OP_TM_32]     = "CC_OP_TM_32",
+    [CC_OP_TM_64]     = "CC_OP_TM_64",
+    [CC_OP_LTGT_F32]  = "CC_OP_LTGT_F32",
+    [CC_OP_LTGT_F64]  = "CC_OP_LTGT_F64",
+    [CC_OP_NZ_F32]    = "CC_OP_NZ_F32",
+    [CC_OP_NZ_F64]    = "CC_OP_NZ_F64",
+    [CC_OP_ICM]       = "CC_OP_ICM",
+    [CC_OP_SLAG]      = "CC_OP_SLAG",
+};
+
+static inline const char *cc_name(int cc_op)
+{
+    return cc_names[cc_op];
+}
+
+/* SCLP PV interface defines */
+#define SCLP_CMDW_READ_SCP_INFO         0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
+
+#define SCP_LENGTH                      0x00
+#define SCP_FUNCTION_CODE               0x02
+#define SCP_CONTROL_MASK                0x03
+#define SCP_RESPONSE_CODE               0x06
+#define SCP_MEM_CODE                    0x08
+#define SCP_INCREMENT                   0x0a
+
+typedef struct LowCore
+{
+    /* prefix area: defined by architecture */
+    uint32_t        ccw1[2];                  /* 0x000 */
+    uint32_t        ccw2[4];                  /* 0x008 */
+    uint8_t         pad1[0x80-0x18];          /* 0x018 */
+    uint32_t        ext_params;               /* 0x080 */
+    uint16_t        cpu_addr;                 /* 0x084 */
+    uint16_t        ext_int_code;             /* 0x086 */
+    uint16_t        svc_ilc;                  /* 0x088 */
+    uint16_t        svc_code;                 /* 0x08a */
+    uint16_t        pgm_ilc;                  /* 0x08c */
+    uint16_t        pgm_code;                 /* 0x08e */
+    uint32_t        data_exc_code;            /* 0x090 */
+    uint16_t        mon_class_num;            /* 0x094 */
+    uint16_t        per_perc_atmid;           /* 0x096 */
+    uint64_t        per_address;              /* 0x098 */
+    uint8_t         exc_access_id;            /* 0x0a0 */
+    uint8_t         per_access_id;            /* 0x0a1 */
+    uint8_t         op_access_id;             /* 0x0a2 */
+    uint8_t         ar_access_id;             /* 0x0a3 */
+    uint8_t         pad2[0xA8-0xA4];          /* 0x0a4 */
+    uint64_t        trans_exc_code;           /* 0x0a8 */
+    uint64_t        monitor_code;             /* 0x0b0 */
+    uint16_t        subchannel_id;            /* 0x0b8 */
+    uint16_t        subchannel_nr;            /* 0x0ba */
+    uint32_t        io_int_parm;              /* 0x0bc */
+    uint32_t        io_int_word;              /* 0x0c0 */
+    uint8_t         pad3[0xc8-0xc4];          /* 0x0c4 */
+    uint32_t        stfl_fac_list;            /* 0x0c8 */
+    uint8_t         pad4[0xe8-0xcc];          /* 0x0cc */
+    uint32_t        mcck_interruption_code[2]; /* 0x0e8 */
+    uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
+    uint32_t        external_damage_code;     /* 0x0f4 */
+    uint64_t        failing_storage_address;  /* 0x0f8 */
+    uint8_t         pad6[0x120-0x100];        /* 0x100 */
+    PSW             restart_old_psw;          /* 0x120 */
+    PSW             external_old_psw;         /* 0x130 */
+    PSW             svc_old_psw;              /* 0x140 */
+    PSW             program_old_psw;          /* 0x150 */
+    PSW             mcck_old_psw;             /* 0x160 */
+    PSW             io_old_psw;               /* 0x170 */
+    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
+    PSW             restart_psw;              /* 0x1a0 */
+    PSW             external_new_psw;         /* 0x1b0 */
+    PSW             svc_new_psw;              /* 0x1c0 */
+    PSW             program_new_psw;          /* 0x1d0 */
+    PSW             mcck_new_psw;             /* 0x1e0 */
+    PSW             io_new_psw;               /* 0x1f0 */
+    PSW             return_psw;               /* 0x200 */
+    uint8_t         irb[64];                  /* 0x210 */
+    uint64_t        sync_enter_timer;         /* 0x250 */
+    uint64_t        async_enter_timer;        /* 0x258 */
+    uint64_t        exit_timer;               /* 0x260 */
+    uint64_t        last_update_timer;        /* 0x268 */
+    uint64_t        user_timer;               /* 0x270 */
+    uint64_t        system_timer;             /* 0x278 */
+    uint64_t        last_update_clock;        /* 0x280 */
+    uint64_t        steal_clock;              /* 0x288 */
+    PSW             return_mcck_psw;          /* 0x290 */
+    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
+    /* System info area */
+    uint64_t        save_area[16];            /* 0xc00 */
+    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
+    uint64_t        kernel_stack;             /* 0xd40 */
+    uint64_t        thread_info;              /* 0xd48 */
+    uint64_t        async_stack;              /* 0xd50 */
+    uint64_t        kernel_asce;              /* 0xd58 */
+    uint64_t        user_asce;                /* 0xd60 */
+    uint64_t        panic_stack;              /* 0xd68 */
+    uint64_t        user_exec_asce;           /* 0xd70 */
+    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
+
+    /* SMP info area: defined by DJB */
+    uint64_t        clock_comparator;         /* 0xdc0 */
+    uint64_t        ext_call_fast;            /* 0xdc8 */
+    uint64_t        percpu_offset;            /* 0xdd0 */
+    uint64_t        current_task;             /* 0xdd8 */
+    uint32_t        softirq_pending;          /* 0xde0 */
+    uint32_t        pad_0x0de4;               /* 0xde4 */
+    uint64_t        int_clock;                /* 0xde8 */
+    uint8_t         pad12[0xe00-0xdf0];       /* 0xdf0 */
+
+    /* 0xe00 is used as indicator for dump tools */
+    /* whether the kernel died with panic() or not */
+    uint32_t        panic_magic;              /* 0xe00 */
+
+    uint8_t         pad13[0x11b8-0xe04];      /* 0xe04 */
+
+    /* 64 bit extparam used for pfault, diag 250 etc  */
+    uint64_t        ext_params2;               /* 0x11B8 */
+
+    uint8_t         pad14[0x1200-0x11C0];      /* 0x11C0 */
+
+    /* System info area */
+
+    uint64_t        floating_pt_save_area[16]; /* 0x1200 */
+    uint64_t        gpregs_save_area[16];      /* 0x1280 */
+    uint32_t        st_status_fixed_logout[4]; /* 0x1300 */
+    uint8_t         pad15[0x1318-0x1310];      /* 0x1310 */
+    uint32_t        prefixreg_save_area;       /* 0x1318 */
+    uint32_t        fpt_creg_save_area;        /* 0x131c */
+    uint8_t         pad16[0x1324-0x1320];      /* 0x1320 */
+    uint32_t        tod_progreg_save_area;     /* 0x1324 */
+    uint32_t        cpu_timer_save_area[2];    /* 0x1328 */
+    uint32_t        clock_comp_save_area[2];   /* 0x1330 */
+    uint8_t         pad17[0x1340-0x1338];      /* 0x1338 */
+    uint32_t        access_regs_save_area[16]; /* 0x1340 */
+    uint64_t        cregs_save_area[16];       /* 0x1380 */
+
+    /* align to the top of the prefix area */
+
+    uint8_t         pad18[0x2000-0x1400];      /* 0x1400 */
+} __attribute__((packed)) LowCore;
+
+/* STSI */
+#define STSI_LEVEL_MASK         0x00000000f0000000ULL
+#define STSI_LEVEL_CURRENT      0x0000000000000000ULL
+#define STSI_LEVEL_1            0x0000000010000000ULL
+#define STSI_LEVEL_2            0x0000000020000000ULL
+#define STSI_LEVEL_3            0x0000000030000000ULL
+#define STSI_R0_RESERVED_MASK   0x000000000fffff00ULL
+#define STSI_R0_SEL1_MASK       0x00000000000000ffULL
+#define STSI_R1_RESERVED_MASK   0x00000000ffff0000ULL
+#define STSI_R1_SEL2_MASK       0x000000000000ffffULL
+
+/* Basic Machine Configuration */
+struct sysib_111 {
+    uint32_t res1[8];
+    uint8_t  manuf[16];
+    uint8_t  type[4];
+    uint8_t  res2[12];
+    uint8_t  model[16];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint8_t  res3[156];
+};
+
+/* Basic Machine CPU */
+struct sysib_121 {
+    uint32_t res1[80];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint8_t  res2[2];
+    uint16_t cpu_addr;
+    uint8_t  res3[152];
+};
+
+/* Basic Machine CPUs */
+struct sysib_122 {
+    uint8_t res1[32];
+    uint32_t capability;
+    uint16_t total_cpus;
+    uint16_t active_cpus;
+    uint16_t standby_cpus;
+    uint16_t reserved_cpus;
+    uint16_t adjustments[2026];
+};
+
+/* LPAR CPU */
+struct sysib_221 {
+    uint32_t res1[80];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint16_t cpu_id;
+    uint16_t cpu_addr;
+    uint8_t  res3[152];
+};
+
+/* LPAR CPUs */
+struct sysib_222 {
+    uint32_t res1[32];
+    uint16_t lpar_num;
+    uint8_t  res2;
+    uint8_t  lcpuc;
+    uint16_t total_cpus;
+    uint16_t conf_cpus;
+    uint16_t standby_cpus;
+    uint16_t reserved_cpus;
+    uint8_t  name[8];
+    uint32_t caf;
+    uint8_t  res3[16];
+    uint16_t dedicated_cpus;
+    uint16_t shared_cpus;
+    uint8_t  res4[180];
+};
+
+/* VM CPUs */
+struct sysib_322 {
+    uint8_t  res1[31];
+    uint8_t  count;
+    struct {
+        uint8_t  res2[4];
+        uint16_t total_cpus;
+        uint16_t conf_cpus;
+        uint16_t standby_cpus;
+        uint16_t reserved_cpus;
+        uint8_t  name[8];
+        uint32_t caf;
+        uint8_t  cpi[16];
+        uint8_t  res3[24];
+    } vm[8];
+    uint8_t res4[3552];
+};
+
+/* MMU defines */
+#define _ASCE_ORIGIN            ~0xfffULL /* segment table origin             */
+#define _ASCE_SUBSPACE          0x200     /* subspace group control           */
+#define _ASCE_PRIVATE_SPACE     0x100     /* private space control            */
+#define _ASCE_ALT_EVENT         0x80      /* storage alteration event control */
+#define _ASCE_SPACE_SWITCH      0x40      /* space switch event               */
+#define _ASCE_REAL_SPACE        0x20      /* real space control               */
+#define _ASCE_TYPE_MASK         0x0c      /* asce table type mask             */
+#define _ASCE_TYPE_REGION1      0x0c      /* region first table type          */
+#define _ASCE_TYPE_REGION2      0x08      /* region second table type         */
+#define _ASCE_TYPE_REGION3      0x04      /* region third table type          */
+#define _ASCE_TYPE_SEGMENT      0x00      /* segment table type               */
+#define _ASCE_TABLE_LENGTH      0x03      /* region table length              */
+
+#define _REGION_ENTRY_ORIGIN    ~0xfffULL /* region/segment table origin      */
+#define _REGION_ENTRY_INV       0x20      /* invalid region table entry       */
+#define _REGION_ENTRY_TYPE_MASK 0x0c      /* region/segment table type mask   */
+#define _REGION_ENTRY_TYPE_R1   0x0c      /* region first table type          */
+#define _REGION_ENTRY_TYPE_R2   0x08      /* region second table type         */
+#define _REGION_ENTRY_TYPE_R3   0x04      /* region third table type          */
+#define _REGION_ENTRY_LENGTH    0x03      /* region third length              */
+
+#define _SEGMENT_ENTRY_ORIGIN   ~0x7ffULL /* segment table origin             */
+#define _SEGMENT_ENTRY_RO       0x200     /* page protection bit              */
+#define _SEGMENT_ENTRY_INV      0x20      /* invalid segment table entry      */
+
+#define _PAGE_RO        0x200            /* HW read-only bit  */
+#define _PAGE_INVALID   0x400            /* HW invalid bit    */
+
+
+
+/* EBCDIC handling */
+static const uint8_t ebcdic2ascii[] = {
+    0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+    0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+    0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+    0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+    0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+    0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+    0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+    0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+    0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+    0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+    0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+    0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+    0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+    0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+    0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+    0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+    0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+    0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+    0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+    0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+    0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+    0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+    0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
+};
+
+static const uint8_t ascii2ebcdic [] = {
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+    0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+    0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+    0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+    0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+    0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+    0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+    0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+    0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        p[i] = ascii2ebcdic[(int)ascii[i]];
+    }
+}
+
+#define SIGP_SENSE             0x01
+#define SIGP_EXTERNAL_CALL     0x02
+#define SIGP_EMERGENCY         0x03
+#define SIGP_START             0x04
+#define SIGP_STOP              0x05
+#define SIGP_RESTART           0x06
+#define SIGP_STOP_STORE_STATUS 0x09
+#define SIGP_INITIAL_CPU_RESET 0x0b
+#define SIGP_CPU_RESET         0x0c
+#define SIGP_SET_PREFIX        0x0d
+#define SIGP_STORE_STATUS_ADDR 0x0e
+#define SIGP_SET_ARCH          0x12
+
+/* cpu status bits */
+#define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
+#define SIGP_STAT_INCORRECT_STATE   0x00000200UL
+#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
+#define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
+#define SIGP_STAT_STOPPED           0x00000040UL
+#define SIGP_STAT_OPERATOR_INTERV   0x00000020UL
+#define SIGP_STAT_CHECK_STOP        0x00000010UL
+#define SIGP_STAT_INOPERATIVE       0x00000004UL
+#define SIGP_STAT_INVALID_ORDER     0x00000002UL
+#define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
+
+void load_psw(CPUState *env, uint64_t mask, uint64_t addr);
+int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc,
+                  target_ulong *raddr, int *flags);
+int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code);
+uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr);
+
+#define TARGET_HAS_ICE 1
+
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
+/* Converts ns to s390's clock format */
+static inline uint64_t time2tod(uint64_t ns) {
+    return (ns << 9) / 125;
+}
+
+static inline void cpu_inject_ext(CPUState *env, uint32_t code, uint32_t param,
+                                  uint64_t param64)
+{
+    if (env->ext_index == MAX_EXT_QUEUE - 1) {
+        /* ugh - can't queue anymore. Let's drop. */
+        return;
+    }
+
+    env->ext_index++;
+    assert(env->ext_index < MAX_EXT_QUEUE);
+
+    env->ext_queue[env->ext_index].code = code;
+    env->ext_queue[env->ext_index].param = param;
+    env->ext_queue[env->ext_index].param64 = param64;
+
+    env->pending_int |= INTERRUPT_EXT;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (env->psw.mask & PSW_MASK_EXT);
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
+{
+    env->psw.addr = tb->pc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-s390x/exec.h b/qemu-0.15.x/target-s390x/exec.h
new file mode 100644
index 0000000..fb73f31
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/exec.h
@@ -0,0 +1,37 @@
+/*
+ *  S/390 execution defines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dyngen-exec.h"
+
+register struct CPUS390XState *env asm(AREG0);
+
+#include "config.h"
+#include "cpu.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline void env_to_regs(void)
+{
+}
diff --git a/qemu-0.15.x/target-s390x/helper.c b/qemu-0.15.x/target-s390x/helper.c
new file mode 100644
index 0000000..1ce7079
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/helper.c
@@ -0,0 +1,627 @@
+/*
+ *  S/390 helpers
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2011 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_S390
+//#define DEBUG_S390_PTE
+//#define DEBUG_S390_STDOUT
+
+#ifdef DEBUG_S390
+#ifdef DEBUG_S390_STDOUT
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); \
+         qemu_log(fmt, ##__VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
+#endif
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#ifdef DEBUG_S390_PTE
+#define PTE_DPRINTF DPRINTF
+#else
+#define PTE_DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#ifndef CONFIG_USER_ONLY
+static void s390x_tod_timer(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->pending_int |= INTERRUPT_TOD;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void s390x_cpu_timer(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->pending_int |= INTERRUPT_CPUTIMER;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
+#endif
+
+CPUS390XState *cpu_s390x_init(const char *cpu_model)
+{
+    CPUS390XState *env;
+#if !defined (CONFIG_USER_ONLY)
+    struct tm tm;
+#endif
+    static int inited = 0;
+    static int cpu_num = 0;
+
+    env = qemu_mallocz(sizeof(CPUS390XState));
+    cpu_exec_init(env);
+    if (!inited) {
+        inited = 1;
+        s390x_translate_init();
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    qemu_get_timedate(&tm, 0);
+    env->tod_offset = TOD_UNIX_EPOCH +
+                      (time2tod(mktimegm(&tm)) * 1000000000ULL);
+    env->tod_basetime = 0;
+    env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
+    env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
+#endif
+    env->cpu_model_str = cpu_model;
+    env->cpu_num = cpu_num++;
+    env->ext_index = -1;
+    cpu_reset(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n",
+            __FUNCTION__, address, rw, mmu_idx, is_softmmu); */
+    env->exception_index = EXCP_ADDR;
+    env->__excp_addr = address; /* FIXME: find out how this works on a real machine */
+    return 1;
+}
+
+#endif /* CONFIG_USER_ONLY */
+
+void cpu_reset(CPUS390XState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    memset(env, 0, offsetof(CPUS390XState, breakpoints));
+    /* FIXME: reset vector? */
+    tlb_flush(env, 1);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+/* Ensure to exit the TB after this call! */
+static void trigger_pgm_exception(CPUState *env, uint32_t code, uint32_t ilc)
+{
+    env->exception_index = EXCP_PGM;
+    env->int_pgm_code = code;
+    env->int_pgm_ilc = ilc;
+}
+
+static int trans_bits(CPUState *env, uint64_t mode)
+{
+    int bits = 0;
+
+    switch (mode) {
+    case PSW_ASC_PRIMARY:
+        bits = 1;
+        break;
+    case PSW_ASC_SECONDARY:
+        bits = 2;
+        break;
+    case PSW_ASC_HOME:
+        bits = 3;
+        break;
+    default:
+        cpu_abort(env, "unknown asc mode\n");
+        break;
+    }
+
+    return bits;
+}
+
+static void trigger_prot_fault(CPUState *env, target_ulong vaddr, uint64_t mode)
+{
+    int ilc = ILC_LATER_INC_2;
+    int bits = trans_bits(env, mode) | 4;
+
+    DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+
+    stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
+    trigger_pgm_exception(env, PGM_PROTECTION, ilc);
+}
+
+static void trigger_page_fault(CPUState *env, target_ulong vaddr, uint32_t type,
+                               uint64_t asc, int rw)
+{
+    int ilc = ILC_LATER;
+    int bits = trans_bits(env, asc);
+
+    if (rw == 2) {
+        /* code has is undefined ilc */
+        ilc = 2;
+    }
+
+    DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+
+    stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
+    trigger_pgm_exception(env, type, ilc);
+}
+
+static int mmu_translate_asce(CPUState *env, target_ulong vaddr, uint64_t asc,
+                              uint64_t asce, int level, target_ulong *raddr,
+                              int *flags, int rw)
+{
+    uint64_t offs = 0;
+    uint64_t origin;
+    uint64_t new_asce;
+
+    PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce);
+
+    if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) ||
+        ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) {
+        /* XXX different regions have different faults */
+        DPRINTF("%s: invalid region\n", __FUNCTION__);
+        trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw);
+        return -1;
+    }
+
+    if ((level <= _ASCE_TYPE_MASK) && ((asce & _ASCE_TYPE_MASK) != level)) {
+        trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+        return -1;
+    }
+
+    if (asce & _ASCE_REAL_SPACE) {
+        /* direct mapping */
+
+        *raddr = vaddr;
+        return 0;
+    }
+
+    origin = asce & _ASCE_ORIGIN;
+
+    switch (level) {
+    case _ASCE_TYPE_REGION1 + 4:
+        offs = (vaddr >> 50) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION1:
+        offs = (vaddr >> 39) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION2:
+        offs = (vaddr >> 28) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_REGION3:
+        offs = (vaddr >> 17) & 0x3ff8;
+        break;
+    case _ASCE_TYPE_SEGMENT:
+        offs = (vaddr >> 9) & 0x07f8;
+        origin = asce & _SEGMENT_ENTRY_ORIGIN;
+        break;
+    }
+
+    /* XXX region protection flags */
+    /* *flags &= ~PAGE_WRITE */
+
+    new_asce = ldq_phys(origin + offs);
+    PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
+                __FUNCTION__, origin, offs, new_asce);
+
+    if (level != _ASCE_TYPE_SEGMENT) {
+        /* yet another region */
+        return mmu_translate_asce(env, vaddr, asc, new_asce, level - 4, raddr,
+                                  flags, rw);
+    }
+
+    /* PTE */
+    if (new_asce & _PAGE_INVALID) {
+        DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce);
+        trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw);
+        return -1;
+    }
+
+    if (new_asce & _PAGE_RO) {
+        *flags &= ~PAGE_WRITE;
+    }
+
+    *raddr = new_asce & _ASCE_ORIGIN;
+
+    PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce);
+
+    return 0;
+}
+
+static int mmu_translate_asc(CPUState *env, target_ulong vaddr, uint64_t asc,
+                             target_ulong *raddr, int *flags, int rw)
+{
+    uint64_t asce = 0;
+    int level, new_level;
+    int r;
+
+    switch (asc) {
+    case PSW_ASC_PRIMARY:
+        PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__);
+        asce = env->cregs[1];
+        break;
+    case PSW_ASC_SECONDARY:
+        PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__);
+        asce = env->cregs[7];
+        break;
+    case PSW_ASC_HOME:
+        PTE_DPRINTF("%s: asc=home\n", __FUNCTION__);
+        asce = env->cregs[13];
+        break;
+    }
+
+    switch (asce & _ASCE_TYPE_MASK) {
+    case _ASCE_TYPE_REGION1:
+        break;
+    case _ASCE_TYPE_REGION2:
+        if (vaddr & 0xffe0000000000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xffe0000000000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    case _ASCE_TYPE_REGION3:
+        if (vaddr & 0xfffffc0000000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xfffffc0000000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    case _ASCE_TYPE_SEGMENT:
+        if (vaddr & 0xffffffff80000000ULL) {
+            DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
+                        " 0xffffffff80000000ULL\n", __FUNCTION__,
+                        vaddr);
+            trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
+            return -1;
+        }
+        break;
+    }
+
+    /* fake level above current */
+    level = asce & _ASCE_TYPE_MASK;
+    new_level = level + 4;
+    asce = (asce & ~_ASCE_TYPE_MASK) | (new_level & _ASCE_TYPE_MASK);
+
+    r = mmu_translate_asce(env, vaddr, asc, asce, new_level, raddr, flags, rw);
+
+    if ((rw == 1) && !(*flags & PAGE_WRITE)) {
+        trigger_prot_fault(env, vaddr, asc);
+        return -1;
+    }
+
+    return r;
+}
+
+int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc,
+                  target_ulong *raddr, int *flags)
+{
+    int r = -1;
+
+    *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    vaddr &= TARGET_PAGE_MASK;
+
+    if (!(env->psw.mask & PSW_MASK_DAT)) {
+        *raddr = vaddr;
+        r = 0;
+        goto out;
+    }
+
+    switch (asc) {
+    case PSW_ASC_PRIMARY:
+    case PSW_ASC_HOME:
+        r = mmu_translate_asc(env, vaddr, asc, raddr, flags, rw);
+        break;
+    case PSW_ASC_SECONDARY:
+        /*
+         * Instruction: Primary
+         * Data: Secondary
+         */
+        if (rw == 2) {
+            r = mmu_translate_asc(env, vaddr, PSW_ASC_PRIMARY, raddr, flags,
+                                  rw);
+            *flags &= ~(PAGE_READ | PAGE_WRITE);
+        } else {
+            r = mmu_translate_asc(env, vaddr, PSW_ASC_SECONDARY, raddr, flags,
+                                  rw);
+            *flags &= ~(PAGE_EXEC);
+        }
+        break;
+    case PSW_ASC_ACCREG:
+    default:
+        hw_error("guest switched to unknown asc mode\n");
+        break;
+    }
+
+out:
+    /* Convert real address -> absolute address */
+    if (*raddr < 0x2000) {
+        *raddr = *raddr + env->psa;
+    }
+
+    return r;
+}
+
+int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong _vaddr, int rw,
+                                int mmu_idx, int is_softmmu)
+{
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    target_ulong vaddr, raddr;
+    int prot;
+
+    DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d is_softmmu %d\n",
+            __FUNCTION__, _vaddr, rw, mmu_idx, is_softmmu);
+
+    _vaddr &= TARGET_PAGE_MASK;
+    vaddr = _vaddr;
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        vaddr &= 0x7fffffff;
+    }
+
+    if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot)) {
+        /* Translation ended in exception */
+        return 1;
+    }
+
+    /* check out of RAM access */
+    if (raddr > (ram_size + virtio_size)) {
+        DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__,
+                (uint64_t)aaddr, (uint64_t)ram_size);
+        trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER);
+        return 1;
+    }
+
+    DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__,
+            (uint64_t)vaddr, (uint64_t)raddr, prot);
+
+    tlb_set_page(env, _vaddr, raddr, prot,
+                 mmu_idx, TARGET_PAGE_SIZE);
+
+    return 0;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong vaddr)
+{
+    target_ulong raddr;
+    int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    int old_exc = env->exception_index;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        vaddr &= 0x7fffffff;
+    }
+
+    mmu_translate(env, vaddr, 2, asc, &raddr, &prot);
+    env->exception_index = old_exc;
+
+    return raddr;
+}
+
+void load_psw(CPUState *env, uint64_t mask, uint64_t addr)
+{
+    if (mask & PSW_MASK_WAIT) {
+        env->halted = 1;
+        env->exception_index = EXCP_HLT;
+        if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) {
+            /* XXX disabled wait state - CPU is dead */
+        }
+    }
+
+    env->psw.addr = addr;
+    env->psw.mask = mask;
+    env->cc_op = (mask >> 13) & 3;
+}
+
+static uint64_t get_psw_mask(CPUState *env)
+{
+    uint64_t r = env->psw.mask;
+
+    env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
+
+    r &= ~(3ULL << 13);
+    assert(!(env->cc_op & ~3));
+    r |= env->cc_op << 13;
+
+    return r;
+}
+
+static void do_svc_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
+    lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc);
+    lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc));
+    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
+    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    load_psw(env, mask, addr);
+}
+
+static void do_program_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+    int ilc = env->int_pgm_ilc;
+
+    switch (ilc) {
+    case ILC_LATER:
+        ilc = get_ilc(ldub_code(env->psw.addr));
+        break;
+    case ILC_LATER_INC:
+        ilc = get_ilc(ldub_code(env->psw.addr));
+        env->psw.addr += ilc * 2;
+        break;
+    case ILC_LATER_INC_2:
+        ilc = get_ilc(ldub_code(env->psw.addr)) * 2;
+        env->psw.addr += ilc;
+        break;
+    }
+
+    qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc);
+
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->pgm_ilc = cpu_to_be16(ilc);
+    lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
+    lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
+    mask = be64_to_cpu(lowcore->program_new_psw.mask);
+    addr = be64_to_cpu(lowcore->program_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+            env->int_pgm_code, ilc, env->psw.mask,
+            env->psw.addr);
+
+    load_psw(env, mask, addr);
+}
+
+#define VIRTIO_SUBCODE_64 0x0D00
+
+static void do_ext_interrupt(CPUState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    target_phys_addr_t len = TARGET_PAGE_SIZE;
+    ExtQueue *q;
+
+    if (!(env->psw.mask & PSW_MASK_EXT)) {
+        cpu_abort(env, "Ext int w/o ext mask\n");
+    }
+
+    if (env->ext_index < 0 || env->ext_index > MAX_EXT_QUEUE) {
+        cpu_abort(env, "Ext queue overrun: %d\n", env->ext_index);
+    }
+
+    q = &env->ext_queue[env->ext_index];
+    lowcore = cpu_physical_memory_map(env->psa, &len, 1);
+
+    lowcore->ext_int_code = cpu_to_be16(q->code);
+    lowcore->ext_params = cpu_to_be32(q->param);
+    lowcore->ext_params2 = cpu_to_be64(q->param64);
+    lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
+    lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64);
+    mask = be64_to_cpu(lowcore->external_new_psw.mask);
+    addr = be64_to_cpu(lowcore->external_new_psw.addr);
+
+    cpu_physical_memory_unmap(lowcore, len, 1, len);
+
+    env->ext_index--;
+    if (env->ext_index == -1) {
+        env->pending_int &= ~INTERRUPT_EXT;
+    }
+
+    DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+            env->psw.mask, env->psw.addr);
+
+    load_psw(env, mask, addr);
+}
+
+void do_interrupt (CPUState *env)
+{
+    qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index,
+             env->psw.addr);
+
+    /* handle external interrupts */
+    if ((env->psw.mask & PSW_MASK_EXT) &&
+        env->exception_index == -1) {
+        if (env->pending_int & INTERRUPT_EXT) {
+            /* code is already in env */
+            env->exception_index = EXCP_EXT;
+        } else if (env->pending_int & INTERRUPT_TOD) {
+            cpu_inject_ext(env, 0x1004, 0, 0);
+            env->exception_index = EXCP_EXT;
+            env->pending_int &= ~INTERRUPT_EXT;
+            env->pending_int &= ~INTERRUPT_TOD;
+        } else if (env->pending_int & INTERRUPT_CPUTIMER) {
+            cpu_inject_ext(env, 0x1005, 0, 0);
+            env->exception_index = EXCP_EXT;
+            env->pending_int &= ~INTERRUPT_EXT;
+            env->pending_int &= ~INTERRUPT_TOD;
+        }
+    }
+
+    switch (env->exception_index) {
+    case EXCP_PGM:
+        do_program_interrupt(env);
+        break;
+    case EXCP_SVC:
+        do_svc_interrupt(env);
+        break;
+    case EXCP_EXT:
+        do_ext_interrupt(env);
+        break;
+    }
+    env->exception_index = -1;
+
+    if (!env->pending_int) {
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+}
+
+#endif /* CONFIG_USER_ONLY */
diff --git a/qemu-0.15.x/target-s390x/helpers.h b/qemu-0.15.x/target-s390x/helpers.h
new file mode 100644
index 0000000..6ca48eb
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/helpers.h
@@ -0,0 +1,151 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_3(nc, i32, i32, i64, i64)
+DEF_HELPER_3(oc, i32, i32, i64, i64)
+DEF_HELPER_3(xc, i32, i32, i64, i64)
+DEF_HELPER_3(mvc, void, i32, i64, i64)
+DEF_HELPER_3(clc, i32, i32, i64, i64)
+DEF_HELPER_2(mvcl, i32, i32, i32)
+DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32)
+DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64)
+DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32)
+DEF_HELPER_3(clm, i32, i32, i32, i64)
+DEF_HELPER_3(stcm, void, i32, i32, i64)
+DEF_HELPER_2(mlg, void, i32, i64)
+DEF_HELPER_2(dlg, void, i32, i64)
+DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64)
+DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32)
+DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64)
+DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32)
+DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_3(srst, i32, i32, i32, i32)
+DEF_HELPER_3(clst, i32, i32, i32, i32)
+DEF_HELPER_3(mvpg, void, i64, i64, i64)
+DEF_HELPER_3(mvst, void, i32, i32, i32)
+DEF_HELPER_3(csg, i32, i32, i64, i32)
+DEF_HELPER_3(cdsg, i32, i32, i64, i32)
+DEF_HELPER_3(cs, i32, i32, i64, i32)
+DEF_HELPER_4(ex, i32, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32)
+DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32)
+DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64)
+DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64)
+DEF_HELPER_3(stcmh, void, i32, i64, i32)
+DEF_HELPER_3(icmh, i32, i32, i64, i32)
+DEF_HELPER_2(ipm, void, i32, i32)
+DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64)
+DEF_HELPER_3(stam, void, i32, i64, i32)
+DEF_HELPER_3(lam, void, i32, i64, i32)
+DEF_HELPER_3(mvcle, i32, i32, i64, i32)
+DEF_HELPER_3(clcle, i32, i32, i64, i32)
+DEF_HELPER_3(slb, i32, i32, i32, i32)
+DEF_HELPER_4(slbg, i32, i32, i32, i64, i64)
+DEF_HELPER_2(cefbr, void, i32, s32)
+DEF_HELPER_2(cdfbr, void, i32, s32)
+DEF_HELPER_2(cxfbr, void, i32, s32)
+DEF_HELPER_2(cegbr, void, i32, s64)
+DEF_HELPER_2(cdgbr, void, i32, s64)
+DEF_HELPER_2(cxgbr, void, i32, s64)
+DEF_HELPER_2(adbr, i32, i32, i32)
+DEF_HELPER_2(aebr, i32, i32, i32)
+DEF_HELPER_2(sebr, i32, i32, i32)
+DEF_HELPER_2(sdbr, i32, i32, i32)
+DEF_HELPER_2(debr, void, i32, i32)
+DEF_HELPER_2(dxbr, void, i32, i32)
+DEF_HELPER_2(mdbr, void, i32, i32)
+DEF_HELPER_2(mxbr, void, i32, i32)
+DEF_HELPER_2(ldebr, void, i32, i32)
+DEF_HELPER_2(ldxbr, void, i32, i32)
+DEF_HELPER_2(lxdbr, void, i32, i32)
+DEF_HELPER_2(ledbr, void, i32, i32)
+DEF_HELPER_2(lexbr, void, i32, i32)
+DEF_HELPER_2(lpebr, i32, i32, i32)
+DEF_HELPER_2(lpdbr, i32, i32, i32)
+DEF_HELPER_2(lpxbr, i32, i32, i32)
+DEF_HELPER_2(ltebr, i32, i32, i32)
+DEF_HELPER_2(ltdbr, i32, i32, i32)
+DEF_HELPER_2(ltxbr, i32, i32, i32)
+DEF_HELPER_2(lcebr, i32, i32, i32)
+DEF_HELPER_2(lcdbr, i32, i32, i32)
+DEF_HELPER_2(lcxbr, i32, i32, i32)
+DEF_HELPER_2(aeb, void, i32, i32)
+DEF_HELPER_2(deb, void, i32, i32)
+DEF_HELPER_2(meeb, void, i32, i32)
+DEF_HELPER_2(cdb, i32, i32, i64)
+DEF_HELPER_2(adb, i32, i32, i64)
+DEF_HELPER_2(seb, void, i32, i32)
+DEF_HELPER_2(sdb, i32, i32, i64)
+DEF_HELPER_2(mdb, void, i32, i64)
+DEF_HELPER_2(ddb, void, i32, i64)
+DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32)
+DEF_HELPER_3(cgebr, i32, i32, i32, i32)
+DEF_HELPER_3(cgdbr, i32, i32, i32, i32)
+DEF_HELPER_3(cgxbr, i32, i32, i32, i32)
+DEF_HELPER_1(lzer, void, i32)
+DEF_HELPER_1(lzdr, void, i32)
+DEF_HELPER_1(lzxr, void, i32)
+DEF_HELPER_3(cfebr, i32, i32, i32, i32)
+DEF_HELPER_3(cfdbr, i32, i32, i32, i32)
+DEF_HELPER_3(cfxbr, i32, i32, i32, i32)
+DEF_HELPER_2(axbr, i32, i32, i32)
+DEF_HELPER_2(sxbr, i32, i32, i32)
+DEF_HELPER_2(meebr, void, i32, i32)
+DEF_HELPER_2(ddbr, void, i32, i32)
+DEF_HELPER_3(madb, void, i32, i64, i32)
+DEF_HELPER_3(maebr, void, i32, i32, i32)
+DEF_HELPER_3(madbr, void, i32, i32, i32)
+DEF_HELPER_3(msdbr, void, i32, i32, i32)
+DEF_HELPER_2(lxdb, void, i32, i64)
+DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64)
+DEF_HELPER_2(flogr, i32, i32, i64)
+DEF_HELPER_2(sqdbr, void, i32, i32)
+DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32)
+DEF_HELPER_3(unpk, void, i32, i64, i64)
+DEF_HELPER_3(tr, void, i32, i64, i64)
+
+DEF_HELPER_2(servc, i32, i32, i64)
+DEF_HELPER_3(diag, i64, i32, i64, i64)
+DEF_HELPER_2(load_psw, void, i64, i64)
+DEF_HELPER_1(program_interrupt, void, i32)
+DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64)
+DEF_HELPER_1(stck, i32, i64)
+DEF_HELPER_1(stcke, i32, i64)
+DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64)
+DEF_HELPER_3(stsi, i32, i64, i32, i32)
+DEF_HELPER_3(lctl, void, i32, i64, i32)
+DEF_HELPER_3(lctlg, void, i32, i64, i32)
+DEF_HELPER_3(stctl, void, i32, i64, i32)
+DEF_HELPER_3(stctg, void, i32, i64, i32)
+DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64)
+DEF_HELPER_FLAGS_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64)
+DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64)
+DEF_HELPER_2(csp, i32, i32, i32)
+DEF_HELPER_3(mvcs, i32, i64, i64, i64)
+DEF_HELPER_3(mvcp, i32, i64, i64, i64)
+DEF_HELPER_3(sigp, i32, i64, i32, i64)
+DEF_HELPER_1(sacf, void, i64)
+DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64)
+DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void)
+DEF_HELPER_2(lra, i32, i64, i32)
+DEF_HELPER_2(stura, void, i64, i32)
+DEF_HELPER_2(cksm, void, i32, i32)
+
+DEF_HELPER_FLAGS_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
+                   i32, i32, i64, i64, i64)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-s390x/kvm.c b/qemu-0.15.x/target-s390x/kvm.c
new file mode 100644
index 0000000..4beb794
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/kvm.c
@@ -0,0 +1,490 @@
+/*
+ * QEMU S390x KVM implementation
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+#include <asm/ptrace.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "cpu.h"
+#include "device_tree.h"
+
+/* #define DEBUG_KVM */
+
+#ifdef DEBUG_KVM
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define IPA0_DIAG                       0x8300
+#define IPA0_SIGP                       0xae00
+#define IPA0_PRIV                       0xb200
+
+#define PRIV_SCLP_CALL                  0x20
+#define DIAG_KVM_HYPERCALL              0x500
+#define DIAG_KVM_BREAKPOINT             0x501
+
+#define ICPT_INSTRUCTION                0x04
+#define ICPT_WAITPSW                    0x1c
+#define ICPT_SOFT_INTERCEPT             0x24
+#define ICPT_CPU_STOP                   0x28
+#define ICPT_IO                         0x40
+
+#define SIGP_RESTART                    0x06
+#define SIGP_INITIAL_CPU_RESET          0x0b
+#define SIGP_STORE_STATUS_ADDR          0x0e
+#define SIGP_SET_ARCH                   0x12
+
+#define SCLP_CMDW_READ_SCP_INFO         0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_LAST_INFO
+};
+
+int kvm_arch_init(KVMState *s)
+{
+    return 0;
+}
+
+int kvm_arch_init_vcpu(CPUState *env)
+{
+    int ret = 0;
+
+    if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) {
+        perror("cannot init reset vcpu");
+    }
+
+    return ret;
+}
+
+void kvm_arch_reset_vcpu(CPUState *env)
+{
+    /* FIXME: add code to reset vcpu. */
+}
+
+int kvm_arch_put_registers(CPUState *env, int level)
+{
+    struct kvm_regs regs;
+    int ret;
+    int i;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (i = 0; i < 16; i++) {
+        regs.gprs[i] = env->regs[i];
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    env->kvm_run->psw_addr = env->psw.addr;
+    env->kvm_run->psw_mask = env->psw.mask;
+
+    return ret;
+}
+
+int kvm_arch_get_registers(CPUState *env)
+{
+    int ret;
+    struct kvm_regs regs;
+    int i;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = regs.gprs[i];
+    }
+
+    env->psw.addr = env->kvm_run->psw_addr;
+    env->psw.mask = env->kvm_run->psw_mask;
+
+    return 0;
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
+
+    if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
+        cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    uint8_t t[4];
+    static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
+
+    if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) {
+        return -EINVAL;
+    } else if (memcmp(t, diag_501, 4)) {
+        return -EINVAL;
+    } else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+{
+}
+
+void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+{
+}
+
+int kvm_arch_process_async_events(CPUState *env)
+{
+    return env->halted;
+}
+
+void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
+                                 uint64_t parm64, int vm)
+{
+    struct kvm_s390_interrupt kvmint;
+    int r;
+
+    if (!env->kvm_state) {
+        return;
+    }
+
+    env->halted = 0;
+    env->exception_index = -1;
+    qemu_cpu_kick(env);
+
+    kvmint.type = type;
+    kvmint.parm = parm;
+    kvmint.parm64 = parm64;
+
+    if (vm) {
+        r = kvm_vm_ioctl(env->kvm_state, KVM_S390_INTERRUPT, &kvmint);
+    } else {
+        r = kvm_vcpu_ioctl(env, KVM_S390_INTERRUPT, &kvmint);
+    }
+
+    if (r < 0) {
+        fprintf(stderr, "KVM failed to inject interrupt\n");
+        exit(1);
+    }
+}
+
+void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token)
+{
+    kvm_s390_interrupt_internal(env, KVM_S390_INT_VIRTIO, config_change,
+                                token, 1);
+}
+
+void kvm_s390_interrupt(CPUState *env, int type, uint32_t code)
+{
+    kvm_s390_interrupt_internal(env, type, code, 0, 0);
+}
+
+static void enter_pgmcheck(CPUState *env, uint16_t code)
+{
+    kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
+}
+
+static inline void setcc(CPUState *env, uint64_t cc)
+{
+    env->kvm_run->psw_mask &= ~(3ull << 44);
+    env->kvm_run->psw_mask |= (cc & 3) << 44;
+
+    env->psw.mask &= ~(3ul << 44);
+    env->psw.mask |= (cc & 3) << 44;
+}
+
+static int kvm_sclp_service_call(CPUState *env, struct kvm_run *run,
+                                 uint16_t ipbh0)
+{
+    uint32_t sccb;
+    uint64_t code;
+    int r = 0;
+
+    cpu_synchronize_state(env);
+    sccb = env->regs[ipbh0 & 0xf];
+    code = env->regs[(ipbh0 & 0xf0) >> 4];
+
+    r = sclp_service_call(env, sccb, code);
+    if (r) {
+        setcc(env, 3);
+    }
+
+    return 0;
+}
+
+static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1)
+{
+    int r = 0;
+    uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
+
+    dprintf("KVM: PRIV: %d\n", ipa1);
+    switch (ipa1) {
+        case PRIV_SCLP_CALL:
+            r = kvm_sclp_service_call(env, run, ipbh0);
+            break;
+        default:
+            dprintf("KVM: unknown PRIV: 0x%x\n", ipa1);
+            r = -1;
+            break;
+    }
+
+    return r;
+}
+
+static int handle_hypercall(CPUState *env, struct kvm_run *run)
+{
+    cpu_synchronize_state(env);
+    env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]);
+
+    return 0;
+}
+
+static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code)
+{
+    int r = 0;
+
+    switch (ipb_code) {
+        case DIAG_KVM_HYPERCALL:
+            r = handle_hypercall(env, run);
+            break;
+        case DIAG_KVM_BREAKPOINT:
+            sleep(10);
+            break;
+        default:
+            dprintf("KVM: unknown DIAG: 0x%x\n", ipb_code);
+            r = -1;
+            break;
+    }
+
+    return r;
+}
+
+static int s390_cpu_restart(CPUState *env)
+{
+    kvm_s390_interrupt(env, KVM_S390_RESTART, 0);
+    env->halted = 0;
+    env->exception_index = -1;
+    qemu_cpu_kick(env);
+    dprintf("DONE: SIGP cpu restart: %p\n", env);
+    return 0;
+}
+
+static int s390_store_status(CPUState *env, uint32_t parameter)
+{
+    /* XXX */
+    fprintf(stderr, "XXX SIGP store status\n");
+    return -1;
+}
+
+static int s390_cpu_initial_reset(CPUState *env)
+{
+    int i;
+
+    if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) {
+        perror("cannot init reset vcpu");
+    }
+
+    /* Manually zero out all registers */
+    cpu_synchronize_state(env);
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = 0;
+    }
+
+    dprintf("DONE: SIGP initial reset: %p\n", env);
+    return 0;
+}
+
+static int handle_sigp(CPUState *env, struct kvm_run *run, uint8_t ipa1)
+{
+    uint8_t order_code;
+    uint32_t parameter;
+    uint16_t cpu_addr;
+    uint8_t t;
+    int r = -1;
+    CPUState *target_env;
+
+    cpu_synchronize_state(env);
+
+    /* get order code */
+    order_code = run->s390_sieic.ipb >> 28;
+    if (order_code > 0) {
+        order_code = env->regs[order_code];
+    }
+    order_code += (run->s390_sieic.ipb & 0x0fff0000) >> 16;
+
+    /* get parameters */
+    t = (ipa1 & 0xf0) >> 4;
+    if (!(t % 2)) {
+        t++;
+    }
+
+    parameter = env->regs[t] & 0x7ffffe00;
+    cpu_addr = env->regs[ipa1 & 0x0f];
+
+    target_env = s390_cpu_addr2state(cpu_addr);
+    if (!target_env) {
+        goto out;
+    }
+
+    switch (order_code) {
+        case SIGP_RESTART:
+            r = s390_cpu_restart(target_env);
+            break;
+        case SIGP_STORE_STATUS_ADDR:
+            r = s390_store_status(target_env, parameter);
+            break;
+        case SIGP_SET_ARCH:
+            /* make the caller panic */
+            return -1;
+        case SIGP_INITIAL_CPU_RESET:
+            r = s390_cpu_initial_reset(target_env);
+            break;
+        default:
+            fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code);
+            break;
+    }
+
+out:
+    setcc(env, r ? 3 : 0);
+    return 0;
+}
+
+static int handle_instruction(CPUState *env, struct kvm_run *run)
+{
+    unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
+    uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
+    int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16;
+    int r = -1;
+
+    dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb);
+    switch (ipa0) {
+        case IPA0_PRIV:
+            r = handle_priv(env, run, ipa1);
+            break;
+        case IPA0_DIAG:
+            r = handle_diag(env, run, ipb_code);
+            break;
+        case IPA0_SIGP:
+            r = handle_sigp(env, run, ipa1);
+            break;
+    }
+
+    if (r < 0) {
+        enter_pgmcheck(env, 0x0001);
+    }
+    return 0;
+}
+
+static int handle_intercept(CPUState *env)
+{
+    struct kvm_run *run = env->kvm_run;
+    int icpt_code = run->s390_sieic.icptcode;
+    int r = 0;
+
+    dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code,
+            (long)env->kvm_run->psw_addr);
+    switch (icpt_code) {
+        case ICPT_INSTRUCTION:
+            r = handle_instruction(env, run);
+            break;
+        case ICPT_WAITPSW:
+            /* XXX What to do on system shutdown? */
+            env->halted = 1;
+            env->exception_index = EXCP_HLT;
+            break;
+        case ICPT_SOFT_INTERCEPT:
+            fprintf(stderr, "KVM unimplemented icpt SOFT\n");
+            exit(1);
+            break;
+        case ICPT_CPU_STOP:
+            qemu_system_shutdown_request();
+            break;
+        case ICPT_IO:
+            fprintf(stderr, "KVM unimplemented icpt IO\n");
+            exit(1);
+            break;
+        default:
+            fprintf(stderr, "Unknown intercept code: %d\n", icpt_code);
+            exit(1);
+            break;
+    }
+
+    return r;
+}
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
+{
+    int ret = 0;
+
+    switch (run->exit_reason) {
+        case KVM_EXIT_S390_SIEIC:
+            ret = handle_intercept(env);
+            break;
+        case KVM_EXIT_S390_RESET:
+            fprintf(stderr, "RESET not implemented\n");
+            exit(1);
+            break;
+        default:
+            fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason);
+            break;
+    }
+
+    if (ret == 0) {
+        ret = EXCP_INTERRUPT;
+    } else if (ret > 0) {
+        ret = 0;
+    }
+    return ret;
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+    return true;
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+    return 1;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
diff --git a/qemu-0.15.x/target-s390x/machine.c b/qemu-0.15.x/target-s390x/machine.c
new file mode 100644
index 0000000..3e79be6
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/machine.c
@@ -0,0 +1,30 @@
+/*
+ * QEMU S390x machine definitions
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
diff --git a/qemu-0.15.x/target-s390x/op_helper.c b/qemu-0.15.x/target-s390x/op_helper.c
new file mode 100644
index 0000000..cd33f99
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/op_helper.c
@@ -0,0 +1,2991 @@
+/*
+ *  S/390 helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "exec.h"
+#include "host-utils.h"
+#include "helpers.h"
+#include <string.h>
+#include "kvm.h"
+#include "qemu-timer.h"
+#ifdef CONFIG_KVM
+#include <linux/kvm.h>
+#endif
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    unsigned long pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (unlikely(ret != 0)) {
+        if (likely(retaddr)) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (likely(tb)) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+
+#endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* raise an exception */
+void HELPER(exception)(uint32_t excp)
+{
+    HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void mvc_fast_memset(CPUState *env, uint32_t l, uint64_t dest,
+                            uint8_t byte)
+{
+    target_phys_addr_t dest_phys;
+    target_phys_addr_t len = l;
+    void *dest_p;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    int flags;
+
+    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+        stb(dest, byte);
+        cpu_abort(env, "should never reach here");
+    }
+    dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+
+    memset(dest_p, byte, len);
+
+    cpu_physical_memory_unmap(dest_p, 1, len, len);
+}
+
+static void mvc_fast_memmove(CPUState *env, uint32_t l, uint64_t dest,
+                             uint64_t src)
+{
+    target_phys_addr_t dest_phys;
+    target_phys_addr_t src_phys;
+    target_phys_addr_t len = l;
+    void *dest_p;
+    void *src_p;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    int flags;
+
+    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+        stb(dest, 0);
+        cpu_abort(env, "should never reach here");
+    }
+    dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+    if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
+        ldub(src);
+        cpu_abort(env, "should never reach here");
+    }
+    src_phys |= src & ~TARGET_PAGE_MASK;
+
+    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+    src_p = cpu_physical_memory_map(src_phys, &len, 0);
+
+    memmove(dest_p, src_p, len);
+
+    cpu_physical_memory_unmap(dest_p, 1, len, len);
+    cpu_physical_memory_unmap(src_p, 0, len, len);
+}
+#endif
+
+/* and on array */
+uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) & ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* xor on array */
+uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+    /* xor with itself is the same as memset(0) */
+    if ((l > 32) && (src == dest) &&
+        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
+        mvc_fast_memset(env, l + 1, dest, 0);
+        return 0;
+    }
+#else
+    if (src == dest) {
+        memset(g2h(dest), 0, l + 1);
+        return 0;
+    }
+#endif
+
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) ^ ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* or on array */
+uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i;
+    unsigned char x;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+    for (i = 0; i <= l; i++) {
+        x = ldub(dest + i) | ldub(src + i);
+        if (x) {
+            cc = 1;
+        }
+        stb(dest + i, x);
+    }
+    return cc;
+}
+
+/* memmove */
+void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
+{
+    int i = 0;
+    int x = 0;
+    uint32_t l_64 = (l + 1) / 8;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __FUNCTION__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+    if ((l > 32) &&
+        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
+        (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
+        if (dest == (src + 1)) {
+            mvc_fast_memset(env, l + 1, dest, ldub(src));
+            return;
+        } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+            mvc_fast_memmove(env, l + 1, dest, src);
+            return;
+        }
+    }
+#else
+    if (dest == (src + 1)) {
+        memset(g2h(dest), ldub(src), l + 1);
+        return;
+    } else {
+        memmove(g2h(dest), g2h(src), l + 1);
+        return;
+    }
+#endif
+
+    /* handle the parts that fit into 8-byte loads/stores */
+    if (dest != (src + 1)) {
+        for (i = 0; i < l_64; i++) {
+            stq(dest + x, ldq(src + x));
+            x += 8;
+        }
+    }
+
+    /* slow version crossing pages with byte accesses */
+    for (i = x; i <= l; i++) {
+        stb(dest + i, ldub(src + i));
+    }
+}
+
+/* compare unsigned byte arrays */
+uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
+{
+    int i;
+    unsigned char x,y;
+    uint32_t cc;
+    HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
+               __FUNCTION__, l, s1, s2);
+    for (i = 0; i <= l; i++) {
+        x = ldub(s1 + i);
+        y = ldub(s2 + i);
+        HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
+        if (x < y) {
+            cc = 1;
+            goto done;
+        } else if (x > y) {
+            cc = 2;
+            goto done;
+        }
+    }
+    cc = 0;
+done:
+    HELPER_LOG("\n");
+    return cc;
+}
+
+/* compare logical under mask */
+uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
+{
+    uint8_t r,d;
+    uint32_t cc;
+    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1,
+               mask, addr);
+    cc = 0;
+    while (mask) {
+        if (mask & 8) {
+            d = ldub(addr);
+            r = (r1 & 0xff000000UL) >> 24;
+            HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
+                        addr);
+            if (r < d) {
+                cc = 1;
+                break;
+            } else if (r > d) {
+                cc = 2;
+                break;
+            }
+            addr++;
+        }
+        mask = (mask << 1) & 0xf;
+        r1 <<= 8;
+    }
+    HELPER_LOG("\n");
+    return cc;
+}
+
+/* store character under mask */
+void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
+{
+    uint8_t r;
+    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask,
+               addr);
+    while (mask) {
+        if (mask & 8) {
+            r = (r1 & 0xff000000UL) >> 24;
+            stb(addr, r);
+            HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
+            addr++;
+        }
+        mask = (mask << 1) & 0xf;
+        r1 <<= 8;
+    }
+    HELPER_LOG("\n");
+}
+
+/* 64/64 -> 128 unsigned multiplication */
+void HELPER(mlg)(uint32_t r1, uint64_t v2)
+{
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+    /* assuming 64-bit hosts have __uint128_t */
+    __uint128_t res = (__uint128_t)env->regs[r1 + 1];
+    res *= (__uint128_t)v2;
+    env->regs[r1] = (uint64_t)(res >> 64);
+    env->regs[r1 + 1] = (uint64_t)res;
+#else
+    mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
+#endif
+}
+
+/* 128 -> 64/64 unsigned division */
+void HELPER(dlg)(uint32_t r1, uint64_t v2)
+{
+    uint64_t divisor = v2;
+
+    if (!env->regs[r1]) {
+        /* 64 -> 64/64 case */
+        env->regs[r1] = env->regs[r1+1] % divisor;
+        env->regs[r1+1] = env->regs[r1+1] / divisor;
+        return;
+    } else {
+
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+        /* assuming 64-bit hosts have __uint128_t */
+        __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
+                               (env->regs[r1+1]);
+        __uint128_t quotient = dividend / divisor;
+        env->regs[r1+1] = quotient;
+        __uint128_t remainder = dividend % divisor;
+        env->regs[r1] = remainder;
+#else
+        /* 32-bit hosts would need special wrapper functionality - just abort if
+           we encounter such a case; it's very unlikely anyways. */
+        cpu_abort(env, "128 -> 64/64 division not implemented\n");
+#endif
+    }
+}
+
+static inline uint64_t get_address(int x2, int b2, int d2)
+{
+    uint64_t r = d2;
+
+    if (x2) {
+        r += env->regs[x2];
+    }
+
+    if (b2) {
+        r += env->regs[b2];
+    }
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        r &= 0x7fffffff;
+    }
+
+    return r;
+}
+
+static inline uint64_t get_address_31fix(int reg)
+{
+    uint64_t r = env->regs[reg];
+
+    /* 31-Bit mode */
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        r &= 0x7fffffff;
+    }
+
+    return r;
+}
+
+/* search string (c is byte to search, r2 is string, r1 end of string) */
+uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t i;
+    uint32_t cc = 2;
+    uint64_t str = get_address_31fix(r2);
+    uint64_t end = get_address_31fix(r1);
+
+    HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__,
+               c, env->regs[r1], env->regs[r2]);
+
+    for (i = str; i != end; i++) {
+        if (ldub(i) == c) {
+            env->regs[r1] = i;
+            cc = 1;
+            break;
+        }
+    }
+
+    return cc;
+}
+
+/* unsigned string compare (c is string terminator) */
+uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t s1 = get_address_31fix(r1);
+    uint64_t s2 = get_address_31fix(r2);
+    uint8_t v1, v2;
+    uint32_t cc;
+    c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+    if (!c) {
+        HELPER_LOG("%s: comparing '%s' and '%s'\n",
+                   __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2));
+    }
+#endif
+    for (;;) {
+        v1 = ldub(s1);
+        v2 = ldub(s2);
+        if ((v1 == c || v2 == c) || (v1 != v2)) {
+            break;
+        }
+        s1++;
+        s2++;
+    }
+
+    if (v1 == v2) {
+        cc = 0;
+    } else {
+        cc = (v1 < v2) ? 1 : 2;
+        /* FIXME: 31-bit mode! */
+        env->regs[r1] = s1;
+        env->regs[r2] = s2;
+    }
+    return cc;
+}
+
+/* move page */
+void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
+{
+    /* XXX missing r0 handling */
+#ifdef CONFIG_USER_ONLY
+    int i;
+
+    for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+        stb(r1 + i, ldub(r2 + i));
+    }
+#else
+    mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
+#endif
+}
+
+/* string copy (c is string terminator) */
+void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
+{
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t src = get_address_31fix(r2);
+    uint8_t v;
+    c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+    if (!c) {
+        HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src),
+                   dest);
+    }
+#endif
+    for (;;) {
+        v = ldub(src);
+        stb(dest, v);
+        if (v == c) {
+            break;
+        }
+        src++;
+        dest++;
+    }
+    env->regs[r1] = dest; /* FIXME: 31-bit mode! */
+}
+
+/* compare and swap 64-bit */
+uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    uint64_t v2 = ldq(a2);
+    if (env->regs[r1] == v2) {
+        cc = 0;
+        stq(a2, env->regs[r3]);
+    } else {
+        cc = 1;
+        env->regs[r1] = v2;
+    }
+    return cc;
+}
+
+/* compare double and swap 64-bit */
+uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    uint64_t v2_hi = ldq(a2);
+    uint64_t v2_lo = ldq(a2 + 8);
+    uint64_t v1_hi = env->regs[r1];
+    uint64_t v1_lo = env->regs[r1 + 1];
+
+    if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
+        cc = 0;
+        stq(a2, env->regs[r3]);
+        stq(a2 + 8, env->regs[r3 + 1]);
+    } else {
+        cc = 1;
+        env->regs[r1] = v2_hi;
+        env->regs[r1 + 1] = v2_lo;
+    }
+
+    return cc;
+}
+
+/* compare and swap 32-bit */
+uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    /* FIXME: locking? */
+    uint32_t cc;
+    HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3);
+    uint32_t v2 = ldl(a2);
+    if (((uint32_t)env->regs[r1]) == v2) {
+        cc = 0;
+        stl(a2, (uint32_t)env->regs[r3]);
+    } else {
+        cc = 1;
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
+    }
+    return cc;
+}
+
+static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 24; /* top of the lower half of r1 */
+    uint64_t rmask = 0xff000000ULL;
+    uint8_t val = 0;
+    int ccd = 0;
+    uint32_t cc = 0;
+
+    while (mask) {
+        if (mask & 8) {
+            env->regs[r1] &= ~rmask;
+            val = ldub(address);
+            if ((val & 0x80) && !ccd) {
+                cc = 1;
+            }
+            ccd = 1;
+            if (val && cc == 0) {
+                cc = 2;
+            }
+            env->regs[r1] |= (uint64_t)val << pos;
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+        rmask >>= 8;
+    }
+
+    return cc;
+}
+
+/* execute instruction
+   this instruction executes an insn modified with the contents of r1
+   it does not change the executed instruction in memory
+   it does not change the program counter
+   in other words: tricky...
+   currently implemented by interpreting the cases it is most commonly used in
+ */
+uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
+{
+    uint16_t insn = lduw_code(addr);
+    HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr,
+             insn);
+    if ((insn & 0xf0ff) == 0xd000) {
+        uint32_t l, insn2, b1, b2, d1, d2;
+        l = v1 & 0xff;
+        insn2 = ldl_code(addr + 2);
+        b1 = (insn2 >> 28) & 0xf;
+        b2 = (insn2 >> 12) & 0xf;
+        d1 = (insn2 >> 16) & 0xfff;
+        d2 = insn2 & 0xfff;
+        switch (insn & 0xf00) {
+        case 0x200:
+            helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        case 0x500:
+            cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        case 0x700:
+            cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
+            break;
+        default:
+            goto abort;
+            break;
+        }
+    } else if ((insn & 0xff00) == 0x0a00) {
+        /* supervisor call */
+        HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff);
+        env->psw.addr = ret - 4;
+        env->int_svc_code = (insn|v1) & 0xff;
+        env->int_svc_ilc = 4;
+        helper_exception(EXCP_SVC);
+    } else if ((insn & 0xff00) == 0xbf00) {
+        uint32_t insn2, r1, r3, b2, d2;
+        insn2 = ldl_code(addr + 2);
+        r1 = (insn2 >> 20) & 0xf;
+        r3 = (insn2 >> 16) & 0xf;
+        b2 = (insn2 >> 12) & 0xf;
+        d2 = insn2 & 0xfff;
+        cc = helper_icm(r1, get_address(0, b2, d2), r3);
+    } else {
+abort:
+        cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
+                  insn);
+    }
+    return cc;
+}
+
+/* absolute value 32-bit */
+uint32_t HELPER(abs_i32)(int32_t val)
+{
+    if (val < 0) {
+        return -val;
+    } else {
+        return val;
+    }
+}
+
+/* negative absolute value 32-bit */
+int32_t HELPER(nabs_i32)(int32_t val)
+{
+    if (val < 0) {
+        return val;
+    } else {
+        return -val;
+    }
+}
+
+/* absolute value 64-bit */
+uint64_t HELPER(abs_i64)(int64_t val)
+{
+    HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val);
+
+    if (val < 0) {
+        return -val;
+    } else {
+        return val;
+    }
+}
+
+/* negative absolute value 64-bit */
+int64_t HELPER(nabs_i64)(int64_t val)
+{
+    if (val < 0) {
+        return val;
+    } else {
+        return -val;
+    }
+}
+
+/* add with carry 32-bit unsigned */
+uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
+{
+    uint32_t res;
+
+    res = v1 + v2;
+    if (cc & 2) {
+        res++;
+    }
+
+    return res;
+}
+
+/* store character under mask high operates on the upper half of r1 */
+void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 56; /* top of the upper half of r1 */
+
+    while (mask) {
+        if (mask & 8) {
+            stb(address, (env->regs[r1] >> pos) & 0xff);
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+    }
+}
+
+/* insert character under mask high; same as icm, but operates on the
+   upper half of r1 */
+uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
+{
+    int pos = 56; /* top of the upper half of r1 */
+    uint64_t rmask = 0xff00000000000000ULL;
+    uint8_t val = 0;
+    int ccd = 0;
+    uint32_t cc = 0;
+
+    while (mask) {
+        if (mask & 8) {
+            env->regs[r1] &= ~rmask;
+            val = ldub(address);
+            if ((val & 0x80) && !ccd) {
+                cc = 1;
+            }
+            ccd = 1;
+            if (val && cc == 0) {
+                cc = 2;
+            }
+            env->regs[r1] |= (uint64_t)val << pos;
+            address++;
+        }
+        mask = (mask << 1) & 0xf;
+        pos -= 8;
+        rmask >>= 8;
+    }
+
+    return cc;
+}
+
+/* insert psw mask and condition code into r1 */
+void HELPER(ipm)(uint32_t cc, uint32_t r1)
+{
+    uint64_t r = env->regs[r1];
+
+    r &= 0xffffffff00ffffffULL;
+    r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf );
+    env->regs[r1] = r;
+    HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__,
+               cc, env->psw.mask, r);
+}
+
+/* load access registers r1 to r3 from memory at a2 */
+void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->aregs[i] = ldl(a2);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* store access registers r1 to r3 in memory at a2 */
+void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stl(a2, env->aregs[i]);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* move long */
+uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
+{
+    uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
+    uint64_t src = get_address_31fix(r2);
+    uint8_t pad = src >> 24;
+    uint8_t v;
+    uint32_t cc;
+
+    if (destlen == srclen) {
+        cc = 0;
+    } else if (destlen < srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+        v = ldub(src);
+        stb(dest, v);
+    }
+
+    for (; destlen; dest++, destlen--) {
+        stb(dest, pad);
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    env->regs[r2 + 1] -= src - env->regs[r2];
+    env->regs[r1] = dest;
+    env->regs[r2] = src;
+
+    return cc;
+}
+
+/* move long extended another memcopy insn with more bells and whistles */
+uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uint64_t destlen = env->regs[r1 + 1];
+    uint64_t dest = env->regs[r1];
+    uint64_t srclen = env->regs[r3 + 1];
+    uint64_t src = env->regs[r3];
+    uint8_t pad = a2 & 0xff;
+    uint8_t v;
+    uint32_t cc;
+
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        destlen = (uint32_t)destlen;
+        srclen = (uint32_t)srclen;
+        dest &= 0x7fffffff;
+        src &= 0x7fffffff;
+    }
+
+    if (destlen == srclen) {
+        cc = 0;
+    } else if (destlen < srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+        v = ldub(src);
+        stb(dest, v);
+    }
+
+    for (; destlen; dest++, destlen--) {
+        stb(dest, pad);
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    /* FIXME: 31-bit mode! */
+    env->regs[r3 + 1] -= src - env->regs[r3];
+    env->regs[r1] = dest;
+    env->regs[r3] = src;
+
+    return cc;
+}
+
+/* compare logical long extended memcompare insn with padding */
+uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uint64_t destlen = env->regs[r1 + 1];
+    uint64_t dest = get_address_31fix(r1);
+    uint64_t srclen = env->regs[r3 + 1];
+    uint64_t src = get_address_31fix(r3);
+    uint8_t pad = a2 & 0xff;
+    uint8_t v1 = 0,v2 = 0;
+    uint32_t cc = 0;
+
+    if (!(destlen || srclen)) {
+        return cc;
+    }
+
+    if (srclen > destlen) {
+        srclen = destlen;
+    }
+
+    for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
+        v1 = srclen ? ldub(src) : pad;
+        v2 = destlen ? ldub(dest) : pad;
+        if (v1 != v2) {
+            cc = (v1 < v2) ? 1 : 2;
+            break;
+        }
+    }
+
+    env->regs[r1 + 1] = destlen;
+    /* can't use srclen here, we trunc'ed it */
+    env->regs[r3 + 1] -= src - env->regs[r3];
+    env->regs[r1] = dest;
+    env->regs[r3] = src;
+
+    return cc;
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
+{
+    uint32_t v1 = env->regs[r1];
+    uint32_t res = v1 + (~v2) + (cc >> 1);
+
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
+    if (cc & 2) {
+        /* borrow */
+        return v1 ? 1 : 0;
+    } else {
+        return v1 ? 3 : 2;
+    }
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
+{
+    uint64_t res = v1 + (~v2) + (cc >> 1);
+
+    env->regs[r1] = res;
+    if (cc & 2) {
+        /* borrow */
+        return v1 ? 1 : 0;
+    } else {
+        return v1 ? 3 : 2;
+    }
+}
+
+static inline int float_comp_to_cc(int float_compare)
+{
+    switch (float_compare) {
+    case float_relation_equal:
+        return 0;
+    case float_relation_less:
+        return 1;
+    case float_relation_greater:
+        return 2;
+    case float_relation_unordered:
+        return 3;
+    default:
+        cpu_abort(env, "unknown return value for float compare\n");
+    }
+}
+
+/* condition codes for binary FP ops */
+static uint32_t set_cc_f32(float32 v1, float32 v2)
+{
+    return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status));
+}
+
+static uint32_t set_cc_f64(float64 v1, float64 v2)
+{
+    return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status));
+}
+
+/* condition codes for unary FP ops */
+static uint32_t set_cc_nz_f32(float32 v)
+{
+    if (float32_is_any_nan(v)) {
+        return 3;
+    } else if (float32_is_zero(v)) {
+        return 0;
+    } else if (float32_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t set_cc_nz_f64(float64 v)
+{
+    if (float64_is_any_nan(v)) {
+        return 3;
+    } else if (float64_is_zero(v)) {
+        return 0;
+    } else if (float64_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t set_cc_nz_f128(float128 v)
+{
+    if (float128_is_any_nan(v)) {
+        return 3;
+    } else if (float128_is_zero(v)) {
+        return 0;
+    } else if (float128_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+/* convert 32-bit int to 64-bit float */
+void HELPER(cdfbr)(uint32_t f1, int32_t v2)
+{
+    HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 32-bit int to 128-bit float */
+void HELPER(cxfbr)(uint32_t f1, int32_t v2)
+{
+    CPU_QuadU v1;
+    v1.q = int32_to_float128(v2, &env->fpu_status);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* convert 64-bit int to 32-bit float */
+void HELPER(cegbr)(uint32_t f1, int64_t v2)
+{
+    HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 64-bit float */
+void HELPER(cdgbr)(uint32_t f1, int64_t v2)
+{
+    HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
+    env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 128-bit float */
+void HELPER(cxgbr)(uint32_t f1, int64_t v2)
+{
+    CPU_QuadU x1;
+    x1.q = int64_to_float128(v2, &env->fpu_status);
+    HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2,
+               x1.ll.upper, x1.ll.lower);
+    env->fregs[f1].ll = x1.ll.upper;
+    env->fregs[f1 + 2].ll = x1.ll.lower;
+}
+
+/* convert 32-bit int to 32-bit float */
+void HELPER(cefbr)(uint32_t f1, int32_t v2)
+{
+    env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
+    HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2,
+               env->fregs[f1].l.upper, f1);
+}
+
+/* 32-bit FP addition RR */
+uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
+               env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP addition RR */
+uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__,
+               env->fregs[f2].d, env->fregs[f1].d, f1);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP subtraction RR */
+uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+    HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
+               env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP subtraction RR */
+uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+    HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
+               __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP division RR */
+void HELPER(debr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+}
+
+/* 128-bit FP division RR */
+void HELPER(dxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_div(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* 64-bit FP multiplication RR */
+void HELPER(mdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+}
+
+/* 128-bit FP multiplication RR */
+void HELPER(mxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 32-bit float to 64-bit float */
+void HELPER(ldebr)(uint32_t r1, uint32_t r2)
+{
+    env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
+                                          &env->fpu_status);
+}
+
+/* convert 128-bit float to 64-bit float */
+void HELPER(ldxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
+    HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU res;
+    res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 64-bit float to 32-bit float */
+void HELPER(ledbr)(uint32_t f1, uint32_t f2)
+{
+    float64 d2 = env->fregs[f2].d;
+    env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
+}
+
+/* convert 128-bit float to 32-bit float */
+void HELPER(lexbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
+    HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper);
+}
+
+/* absolute value of 32-bit float */
+uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2)
+{
+    float32 v1;
+    float32 v2 = env->fregs[f2].d;
+    v1 = float32_abs(v2);
+    env->fregs[f1].d = v1;
+    return set_cc_nz_f32(v1);
+}
+
+/* absolute value of 64-bit float */
+uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2)
+{
+    float64 v1;
+    float64 v2 = env->fregs[f2].d;
+    v1 = float64_abs(v2);
+    env->fregs[f1].d = v1;
+    return set_cc_nz_f64(v1);
+}
+
+/* absolute value of 128-bit float */
+uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    v1.q = float128_abs(v2.q);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+    return set_cc_nz_f128(v1.q);
+}
+
+/* load and test 64-bit float */
+uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = env->fregs[f2].d;
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load and test 32-bit float */
+uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = env->fregs[f2].l.upper;
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load and test 128-bit float */
+uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x;
+    x.ll.upper = env->fregs[f2].ll;
+    x.ll.lower = env->fregs[f2 + 2].ll;
+    env->fregs[f1].ll = x.ll.upper;
+    env->fregs[f1 + 2].ll = x.ll.lower;
+    return set_cc_nz_f128(x.q);
+}
+
+/* load complement of 32-bit float */
+uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
+
+    return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load complement of 64-bit float */
+uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_chs(env->fregs[f2].d);
+
+    return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load complement of 128-bit float */
+uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU x1, x2;
+    x2.ll.upper = env->fregs[f2].ll;
+    x2.ll.lower = env->fregs[f2 + 2].ll;
+    x1.q = float128_chs(x2.q);
+    env->fregs[f1].ll = x1.ll.upper;
+    env->fregs[f1 + 2].ll = x1.ll.lower;
+    return set_cc_nz_f128(x1.q);
+}
+
+/* 32-bit FP addition RM */
+void HELPER(aeb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP division RM */
+void HELPER(deb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP multiplication RM */
+void HELPER(meeb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2.f);
+    env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP compare RR */
+uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    float32 v2 = env->fregs[f2].l.upper;;
+    HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__,
+               v1, f1, v2);
+    return set_cc_f32(v1, v2);
+}
+
+/* 64-bit FP compare RR */
+uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
+{
+    float64 v1 = env->fregs[f1].d;
+    float64 v2 = env->fregs[f2].d;;
+    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__,
+               v1, f1, v2);
+    return set_cc_f64(v1, v2);
+}
+
+/* 128-bit FP compare RR */
+uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+
+    return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q,
+                            &env->fpu_status));
+}
+
+/* 64-bit FP compare RM */
+uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1,
+               f1, v2.d);
+    return set_cc_f64(v1, v2.d);
+}
+
+/* 64-bit FP addition RM */
+uint32_t HELPER(adb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
+    return set_cc_nz_f64(v1);
+}
+
+/* 32-bit FP subtraction RM */
+void HELPER(seb)(uint32_t f1, uint32_t val)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    CPU_FloatU v2;
+    v2.l = val;
+    env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
+}
+
+/* 64-bit FP subtraction RM */
+uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
+    return set_cc_nz_f64(v1);
+}
+
+/* 64-bit FP multiplication RM */
+void HELPER(mdb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
+}
+
+/* 64-bit FP division RM */
+void HELPER(ddb)(uint32_t f1, uint64_t a2)
+{
+    float64 v1 = env->fregs[f1].d;
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__,
+               v1, f1, v2.d);
+    env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
+}
+
+static void set_round_mode(int m3)
+{
+    switch (m3) {
+    case 0:
+        /* current mode */
+        break;
+    case 1:
+        /* biased round no nearest */
+    case 4:
+        /* round to nearest */
+        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
+        break;
+    case 5:
+        /* round to zero */
+        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
+        break;
+    case 6:
+        /* round to +inf */
+        set_float_rounding_mode(float_round_up, &env->fpu_status);
+        break;
+    case 7:
+        /* round to -inf */
+        set_float_rounding_mode(float_round_down, &env->fpu_status);
+        break;
+    }
+}
+
+/* convert 32-bit float to 64-bit int */
+uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float32 v2 = env->fregs[f2].l.upper;
+    set_round_mode(m3);
+    env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
+    return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 64-bit int */
+uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float64 v2 = env->fregs[f2].d;
+    set_round_mode(m3);
+    env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
+    return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 64-bit int */
+uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    set_round_mode(m3);
+    env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
+    if (float128_is_any_nan(v2.q)) {
+        return 3;
+    } else if (float128_is_zero(v2.q)) {
+        return 0;
+    } else if (float128_is_neg(v2.q)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+/* convert 32-bit float to 32-bit int */
+uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float32 v2 = env->fregs[f2].l.upper;
+    set_round_mode(m3);
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float32_to_int32(v2, &env->fpu_status);
+    return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 32-bit int */
+uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    float64 v2 = env->fregs[f2].d;
+    set_round_mode(m3);
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float64_to_int32(v2, &env->fpu_status);
+    return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 32-bit int */
+uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
+{
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                     float128_to_int32(v2.q, &env->fpu_status);
+    return set_cc_nz_f128(v2.q);
+}
+
+/* load 32-bit FP zero */
+void HELPER(lzer)(uint32_t f1)
+{
+    env->fregs[f1].l.upper = float32_zero;
+}
+
+/* load 64-bit FP zero */
+void HELPER(lzdr)(uint32_t f1)
+{
+    env->fregs[f1].d = float64_zero;
+}
+
+/* load 128-bit FP zero */
+void HELPER(lzxr)(uint32_t f1)
+{
+    CPU_QuadU x;
+    x.q = float64_to_float128(float64_zero, &env->fpu_status);
+    env->fregs[f1].ll = x.ll.upper;
+    env->fregs[f1 + 1].ll = x.ll.lower;
+}
+
+/* 128-bit FP subtraction RR */
+uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+    return set_cc_nz_f128(res.q);
+}
+
+/* 128-bit FP addition RR */
+uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2)
+{
+    CPU_QuadU v1;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+    CPU_QuadU v2;
+    v2.ll.upper = env->fregs[f2].ll;
+    v2.ll.lower = env->fregs[f2 + 2].ll;
+    CPU_QuadU res;
+    res.q = float128_add(v1.q, v2.q, &env->fpu_status);
+    env->fregs[f1].ll = res.ll.upper;
+    env->fregs[f1 + 2].ll = res.ll.lower;
+    return set_cc_nz_f128(res.q);
+}
+
+/* 32-bit FP multiplication RR */
+void HELPER(meebr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
+                                         env->fregs[f2].l.upper,
+                                         &env->fpu_status);
+}
+
+/* 64-bit FP division RR */
+void HELPER(ddbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
+                                   &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RM */
+void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3)
+{
+    HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3);
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    env->fregs[f1].d = float64_add(env->fregs[f1].d,
+                                   float64_mul(v2.d, env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RR */
+void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
+    env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
+                                               env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 64-bit FP multiply and subtract RR */
+void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
+    env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
+                                               env->fregs[f3].d,
+                                               &env->fpu_status),
+                                   env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 32-bit FP multiply and add RR */
+void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2)
+{
+    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+                                         float32_mul(env->fregs[f2].l.upper,
+                                                     env->fregs[f3].l.upper,
+                                                     &env->fpu_status),
+                                         &env->fpu_status);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdb)(uint32_t f1, uint64_t a2)
+{
+    CPU_DoubleU v2;
+    v2.ll = ldq(a2);
+    CPU_QuadU v1;
+    v1.q = float64_to_float128(v2.d, &env->fpu_status);
+    env->fregs[f1].ll = v1.ll.upper;
+    env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* test data class 32-bit */
+uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2)
+{
+    float32 v1 = env->fregs[f1].l.upper;
+    int neg = float32_is_neg(v1);
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg);
+    if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+        (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+        (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+        (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* test data class 64-bit */
+uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2)
+{
+    float64 v1 = env->fregs[f1].d;
+    int neg = float64_is_neg(v1);
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg);
+    if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+        (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+        (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+        (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* test data class 128-bit */
+uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2)
+{
+    CPU_QuadU v1;
+    uint32_t cc = 0;
+    v1.ll.upper = env->fregs[f1].ll;
+    v1.ll.lower = env->fregs[f1 + 2].ll;
+
+    int neg = float128_is_neg(v1.q);
+    if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
+        (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
+        (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
+        (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
+        cc = 1;
+    } else if (m2 & (1 << (9-neg))) {
+        /* assume normalized number */
+        cc = 1;
+    }
+    /* FIXME: denormalized? */
+    return cc;
+}
+
+/* find leftmost one */
+uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
+{
+    uint64_t res = 0;
+    uint64_t ov2 = v2;
+
+    while (!(v2 & 0x8000000000000000ULL) && v2) {
+        v2 <<= 1;
+        res++;
+    }
+
+    if (!v2) {
+        env->regs[r1] = 64;
+        env->regs[r1 + 1] = 0;
+        return 0;
+    } else {
+        env->regs[r1] = res;
+        env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
+        return 2;
+    }
+}
+
+/* square root 64-bit RR */
+void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
+{
+    env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
+}
+
+/* checksum */
+void HELPER(cksm)(uint32_t r1, uint32_t r2)
+{
+    uint64_t src = get_address_31fix(r2);
+    uint64_t src_len = env->regs[(r2 + 1) & 15];
+    uint64_t cksm = (uint32_t)env->regs[r1];
+
+    while (src_len >= 4) {
+        cksm += ldl(src);
+
+        /* move to next word */
+        src_len -= 4;
+        src += 4;
+    }
+
+    switch (src_len) {
+    case 0:
+        break;
+    case 1:
+        cksm += ldub(src) << 24;
+        break;
+    case 2:
+        cksm += lduw(src) << 16;
+        break;
+    case 3:
+        cksm += lduw(src) << 16;
+        cksm += ldub(src + 2) << 8;
+        break;
+    }
+
+    /* indicate we've processed everything */
+    env->regs[r2] = src + src_len;
+    env->regs[(r2 + 1) & 15] = 0;
+
+    /* store result */
+    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+                    ((uint32_t)cksm + (cksm >> 32));
+}
+
+static inline uint32_t cc_calc_ltgt_32(CPUState *env, int32_t src,
+                                       int32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltgt0_32(CPUState *env, int32_t dst)
+{
+    return cc_calc_ltgt_32(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltgt_64(CPUState *env, int64_t src,
+                                       int64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltgt0_64(CPUState *env, int64_t dst)
+{
+    return cc_calc_ltgt_64(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltugtu_32(CPUState *env, uint32_t src,
+                                         uint32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_ltugtu_64(CPUState *env, uint64_t src,
+                                         uint64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static inline uint32_t cc_calc_tm_32(CPUState *env, uint32_t val, uint32_t mask)
+{
+    HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask);
+    uint16_t r = val & mask;
+    if (r == 0 || mask == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        return 1;
+    }
+}
+
+/* set condition code for test under mask */
+static inline uint32_t cc_calc_tm_64(CPUState *env, uint64_t val, uint32_t mask)
+{
+    uint16_t r = val & mask;
+    HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r);
+    if (r == 0 || mask == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        while (!(mask & 0x8000)) {
+            mask <<= 1;
+            val <<= 1;
+        }
+        if (val & 0x8000) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_nz(CPUState *env, uint64_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_add_64(CPUState *env, int64_t a1, int64_t a2,
+                                      int64_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_addu_64(CPUState *env, uint64_t a1, uint64_t a2,
+                                       uint64_t ar)
+{
+    if (ar == 0) {
+        if (a1) {
+            return 2;
+        } else {
+            return 0;
+        }
+    } else {
+        if (ar < a1 || ar < a2) {
+          return 3;
+        } else {
+          return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_sub_64(CPUState *env, int64_t a1, int64_t a2,
+                                      int64_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_subu_64(CPUState *env, uint64_t a1, uint64_t a2,
+                                       uint64_t ar)
+{
+    if (ar == 0) {
+        return 2;
+    } else {
+        if (a2 > a1) {
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_abs_64(CPUState *env, int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static inline uint32_t cc_calc_nabs_64(CPUState *env, int64_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_64(CPUState *env, int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+
+static inline uint32_t cc_calc_add_32(CPUState *env, int32_t a1, int32_t a2,
+                                      int32_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_addu_32(CPUState *env, uint32_t a1, uint32_t a2,
+                                       uint32_t ar)
+{
+    if (ar == 0) {
+        if (a1) {
+          return 2;
+        } else {
+          return 0;
+        }
+    } else {
+        if (ar < a1 || ar < a2) {
+          return 3;
+        } else {
+          return 1;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_sub_32(CPUState *env, int32_t a1, int32_t a2,
+                                      int32_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_subu_32(CPUState *env, uint32_t a1, uint32_t a2,
+                                       uint32_t ar)
+{
+    if (ar == 0) {
+        return 2;
+    } else {
+        if (a2 > a1) {
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static inline uint32_t cc_calc_abs_32(CPUState *env, int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static inline uint32_t cc_calc_nabs_32(CPUState *env, int32_t dst)
+{
+    return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_32(CPUState *env, int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+/* calculate condition code for insert character under mask insn */
+static inline uint32_t cc_calc_icm_32(CPUState *env, uint32_t mask, uint32_t val)
+{
+    HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val);
+    uint32_t cc;
+
+    if (mask == 0xf) {
+        if (!val) {
+            return 0;
+        } else if (val & 0x80000000) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    if (!val || !mask) {
+        cc = 0;
+    } else {
+        while (mask != 1) {
+            mask >>= 1;
+            val >>= 8;
+        }
+        if (val & 0x80) {
+            cc = 1;
+        } else {
+            cc = 2;
+        }
+    }
+    return cc;
+}
+
+static inline uint32_t cc_calc_slag(CPUState *env, uint64_t src, uint64_t shift)
+{
+    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
+    uint64_t match, r;
+
+    /* check if the sign bit stays the same */
+    if (src & (1ULL << 63)) {
+        match = mask;
+    } else {
+        match = 0;
+    }
+
+    if ((src & mask) != match) {
+        /* overflow */
+        return 3;
+    }
+
+    r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
+
+    if ((int64_t)r == 0) {
+        return 0;
+    } else if ((int64_t)r < 0) {
+        return 1;
+    }
+
+    return 2;
+}
+
+
+static inline uint32_t do_calc_cc(CPUState *env, uint32_t cc_op, uint64_t src,
+                                  uint64_t dst, uint64_t vr)
+{
+    uint32_t r = 0;
+
+    switch (cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* cc_op value _is_ cc */
+        r = cc_op;
+        break;
+    case CC_OP_LTGT0_32:
+        r = cc_calc_ltgt0_32(env, dst);
+        break;
+    case CC_OP_LTGT0_64:
+        r =  cc_calc_ltgt0_64(env, dst);
+        break;
+    case CC_OP_LTGT_32:
+        r =  cc_calc_ltgt_32(env, src, dst);
+        break;
+    case CC_OP_LTGT_64:
+        r =  cc_calc_ltgt_64(env, src, dst);
+        break;
+    case CC_OP_LTUGTU_32:
+        r =  cc_calc_ltugtu_32(env, src, dst);
+        break;
+    case CC_OP_LTUGTU_64:
+        r =  cc_calc_ltugtu_64(env, src, dst);
+        break;
+    case CC_OP_TM_32:
+        r =  cc_calc_tm_32(env, src, dst);
+        break;
+    case CC_OP_TM_64:
+        r =  cc_calc_tm_64(env, src, dst);
+        break;
+    case CC_OP_NZ:
+        r =  cc_calc_nz(env, dst);
+        break;
+    case CC_OP_ADD_64:
+        r =  cc_calc_add_64(env, src, dst, vr);
+        break;
+    case CC_OP_ADDU_64:
+        r =  cc_calc_addu_64(env, src, dst, vr);
+        break;
+    case CC_OP_SUB_64:
+        r =  cc_calc_sub_64(env, src, dst, vr);
+        break;
+    case CC_OP_SUBU_64:
+        r =  cc_calc_subu_64(env, src, dst, vr);
+        break;
+    case CC_OP_ABS_64:
+        r =  cc_calc_abs_64(env, dst);
+        break;
+    case CC_OP_NABS_64:
+        r =  cc_calc_nabs_64(env, dst);
+        break;
+    case CC_OP_COMP_64:
+        r =  cc_calc_comp_64(env, dst);
+        break;
+
+    case CC_OP_ADD_32:
+        r =  cc_calc_add_32(env, src, dst, vr);
+        break;
+    case CC_OP_ADDU_32:
+        r =  cc_calc_addu_32(env, src, dst, vr);
+        break;
+    case CC_OP_SUB_32:
+        r =  cc_calc_sub_32(env, src, dst, vr);
+        break;
+    case CC_OP_SUBU_32:
+        r =  cc_calc_subu_32(env, src, dst, vr);
+        break;
+    case CC_OP_ABS_32:
+        r =  cc_calc_abs_64(env, dst);
+        break;
+    case CC_OP_NABS_32:
+        r =  cc_calc_nabs_64(env, dst);
+        break;
+    case CC_OP_COMP_32:
+        r =  cc_calc_comp_32(env, dst);
+        break;
+
+    case CC_OP_ICM:
+        r =  cc_calc_icm_32(env, src, dst);
+        break;
+    case CC_OP_SLAG:
+        r =  cc_calc_slag(env, src, dst);
+        break;
+
+    case CC_OP_LTGT_F32:
+        r = set_cc_f32(src, dst);
+        break;
+    case CC_OP_LTGT_F64:
+        r = set_cc_f64(src, dst);
+        break;
+    case CC_OP_NZ_F32:
+        r = set_cc_nz_f32(dst);
+        break;
+    case CC_OP_NZ_F64:
+        r = set_cc_nz_f64(dst);
+        break;
+
+    default:
+        cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
+    }
+
+    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__,
+               cc_name(cc_op), src, dst, vr, r);
+    return r;
+}
+
+uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
+                         uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint64_t HELPER(cvd)(int32_t bin)
+{
+    /* positive 0 */
+    uint64_t dec = 0x0c;
+    int shift = 4;
+
+    if (bin < 0) {
+        bin = -bin;
+        dec = 0x0d;
+    }
+
+    for (shift = 4; (shift < 64) && bin; shift += 4) {
+        int current_number = bin % 10;
+
+        dec |= (current_number) << shift;
+        bin /= 10;
+    }
+
+    return dec;
+}
+
+void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
+{
+    int len_dest = len >> 4;
+    int len_src = len & 0xf;
+    uint8_t b;
+    int second_nibble = 0;
+
+    dest += len_dest;
+    src += len_src;
+
+    /* last byte is special, it only flips the nibbles */
+    b = ldub(src);
+    stb(dest, (b << 4) | (b >> 4));
+    src--;
+    len_src--;
+
+    /* now pad every nibble with 0xf0 */
+
+    while (len_dest > 0) {
+        uint8_t cur_byte = 0;
+
+        if (len_src > 0) {
+            cur_byte = ldub(src);
+        }
+
+        len_dest--;
+        dest--;
+
+        /* only advance one nibble at a time */
+        if (second_nibble) {
+            cur_byte >>= 4;
+            len_src--;
+            src--;
+        }
+        second_nibble = !second_nibble;
+
+        /* digit */
+        cur_byte = (cur_byte & 0xf);
+        /* zone bits */
+        cur_byte |= 0xf0;
+
+        stb(dest, cur_byte);
+    }
+}
+
+void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
+{
+    int i;
+
+    for (i = 0; i <= len; i++) {
+        uint8_t byte = ldub(array + i);
+        uint8_t new_byte = ldub(trans + byte);
+        stb(array + i, new_byte);
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+
+void HELPER(load_psw)(uint64_t mask, uint64_t addr)
+{
+    load_psw(env, mask, addr);
+    cpu_loop_exit(env);
+}
+
+static void program_interrupt(CPUState *env, uint32_t code, int ilc)
+{
+    qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
+
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
+#endif
+    } else {
+        env->int_pgm_code = code;
+        env->int_pgm_ilc = ilc;
+        env->exception_index = EXCP_PGM;
+        cpu_loop_exit(env);
+    }
+}
+
+static void ext_interrupt(CPUState *env, int type, uint32_t param,
+                          uint64_t param64)
+{
+    cpu_inject_ext(env, type, param, param64);
+}
+
+int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code)
+{
+    int r = 0;
+    int shift = 0;
+
+#ifdef DEBUG_HELPER
+    printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
+#endif
+
+    if (sccb & ~0x7ffffff8ul) {
+        fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
+        r = -1;
+        goto out;
+    }
+
+    switch(code) {
+        case SCLP_CMDW_READ_SCP_INFO:
+        case SCLP_CMDW_READ_SCP_INFO_FORCED:
+            while ((ram_size >> (20 + shift)) > 65535) {
+                shift++;
+            }
+            stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
+            stb_phys(sccb + SCP_INCREMENT, 1 << shift);
+            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
+
+            if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
+                                            sccb & ~3, 0, 1);
+#endif
+            } else {
+                env->psw.addr += 4;
+                ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
+            }
+            break;
+        default:
+#ifdef DEBUG_HELPER
+            printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
+#endif
+            r = -1;
+            break;
+    }
+
+out:
+    return r;
+}
+
+/* SCLP service call */
+uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
+{
+    if (sclp_service_call(env, r1, r2)) {
+        return 3;
+    }
+
+    return 0;
+}
+
+/* DIAG */
+uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
+{
+    uint64_t r;
+
+    switch (num) {
+    case 0x500:
+        /* KVM hypercall */
+        r = s390_virtio_hypercall(env, mem, code);
+        break;
+    case 0x44:
+        /* yield */
+        r = 0;
+        break;
+    case 0x308:
+        /* ipl */
+        r = 0;
+        break;
+    default:
+        r = -1;
+        break;
+    }
+
+    if (r) {
+        program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
+    }
+
+    return r;
+}
+
+/* Store CPU ID */
+void HELPER(stidp)(uint64_t a1)
+{
+    stq(a1, env->cpu_num);
+}
+
+/* Set Prefix */
+void HELPER(spx)(uint64_t a1)
+{
+    uint32_t prefix;
+
+    prefix = ldl(a1);
+    env->psa = prefix & 0xfffff000;
+    qemu_log("prefix: %#x\n", prefix);
+    tlb_flush_page(env, 0);
+    tlb_flush_page(env, TARGET_PAGE_SIZE);
+}
+
+/* Set Clock */
+uint32_t HELPER(sck)(uint64_t a1)
+{
+    /* XXX not implemented - is it necessary? */
+
+    return 0;
+}
+
+static inline uint64_t clock_value(CPUState *env)
+{
+    uint64_t time;
+
+    time = env->tod_offset +
+           time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
+
+    return time;
+}
+
+/* Store Clock */
+uint32_t HELPER(stck)(uint64_t a1)
+{
+    stq(a1, clock_value(env));
+
+    return 0;
+}
+
+/* Store Clock Extended */
+uint32_t HELPER(stcke)(uint64_t a1)
+{
+    stb(a1, 0);
+    /* basically the same value as stck */
+    stq(a1 + 1, clock_value(env) | env->cpu_num);
+    /* more fine grained than stck */
+    stq(a1 + 9, 0);
+    /* XXX programmable fields */
+    stw(a1 + 17, 0);
+
+
+    return 0;
+}
+
+/* Set Clock Comparator */
+void HELPER(sckc)(uint64_t a1)
+{
+    uint64_t time = ldq(a1);
+
+    if (time == -1ULL) {
+        return;
+    }
+
+    /* difference between now and then */
+    time -= clock_value(env);
+    /* nanoseconds */
+    time = (time * 125) >> 9;
+
+    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store Clock Comparator */
+void HELPER(stckc)(uint64_t a1)
+{
+    /* XXX implement */
+    stq(a1, 0);
+}
+
+/* Set CPU Timer */
+void HELPER(spt)(uint64_t a1)
+{
+    uint64_t time = ldq(a1);
+
+    if (time == -1ULL) {
+        return;
+    }
+
+    /* nanoseconds */
+    time = (time * 125) >> 9;
+
+    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store CPU Timer */
+void HELPER(stpt)(uint64_t a1)
+{
+    /* XXX implement */
+    stq(a1, 0);
+}
+
+/* Store System Information */
+uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
+{
+    int cc = 0;
+    int sel1, sel2;
+
+    if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
+        ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
+        /* valid function code, invalid reserved bits */
+        program_interrupt(env, PGM_SPECIFICATION, 2);
+    }
+
+    sel1 = r0 & STSI_R0_SEL1_MASK;
+    sel2 = r1 & STSI_R1_SEL2_MASK;
+
+    /* XXX: spec exception if sysib is not 4k-aligned */
+
+    switch (r0 & STSI_LEVEL_MASK) {
+    case STSI_LEVEL_1:
+        if ((sel1 == 1) && (sel2 == 1)) {
+            /* Basic Machine Configuration */
+            struct sysib_111 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            ebcdic_put(sysib.manuf, "QEMU            ", 16);
+            /* same as machine type number in STORE CPU ID */
+            ebcdic_put(sysib.type, "QEMU", 4);
+            /* same as model number in STORE CPU ID */
+            ebcdic_put(sysib.model, "QEMU            ", 16);
+            ebcdic_put(sysib.sequence, "QEMU            ", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 1)) {
+            /* Basic Machine CPU */
+            struct sysib_121 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            /* XXX make different for different CPUs? */
+            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            stw_p(&sysib.cpu_addr, env->cpu_num);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* Basic Machine CPUs */
+            struct sysib_122 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            stl_p(&sysib.capability, 0x443afc29);
+            /* XXX change when SMP comes */
+            stw_p(&sysib.total_cpus, 1);
+            stw_p(&sysib.active_cpus, 1);
+            stw_p(&sysib.standby_cpus, 0);
+            stw_p(&sysib.reserved_cpus, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    case STSI_LEVEL_2:
+    {
+        if ((sel1 == 2) && (sel2 == 1)) {
+            /* LPAR CPU */
+            struct sysib_221 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            /* XXX make different for different CPUs? */
+            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.plant, "QEMU", 4);
+            stw_p(&sysib.cpu_addr, env->cpu_num);
+            stw_p(&sysib.cpu_id, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* LPAR CPUs */
+            struct sysib_222 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            stw_p(&sysib.lpar_num, 0);
+            sysib.lcpuc = 0;
+            /* XXX change when SMP comes */
+            stw_p(&sysib.total_cpus, 1);
+            stw_p(&sysib.conf_cpus, 1);
+            stw_p(&sysib.standby_cpus, 0);
+            stw_p(&sysib.reserved_cpus, 0);
+            ebcdic_put(sysib.name, "QEMU    ", 8);
+            stl_p(&sysib.caf, 1000);
+            stw_p(&sysib.dedicated_cpus, 0);
+            stw_p(&sysib.shared_cpus, 0);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    }
+    case STSI_LEVEL_3:
+    {
+        if ((sel1 == 2) && (sel2 == 2)) {
+            /* VM CPUs */
+            struct sysib_322 sysib;
+
+            memset(&sysib, 0, sizeof(sysib));
+            sysib.count = 1;
+            /* XXX change when SMP comes */
+            stw_p(&sysib.vm[0].total_cpus, 1);
+            stw_p(&sysib.vm[0].conf_cpus, 1);
+            stw_p(&sysib.vm[0].standby_cpus, 0);
+            stw_p(&sysib.vm[0].reserved_cpus, 0);
+            ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
+            stl_p(&sysib.vm[0].caf, 1000);
+            ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
+            cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
+        } else {
+            cc = 3;
+        }
+        break;
+    }
+    case STSI_LEVEL_CURRENT:
+        env->regs[0] = STSI_LEVEL_3;
+        break;
+    default:
+        cc = 3;
+        break;
+    }
+
+    return cc;
+}
+
+void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t src = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->cregs[i] = ldq(src);
+        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
+                   i, src, env->cregs[i]);
+        src += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    tlb_flush(env, 1);
+}
+
+void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t src = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
+        src += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    tlb_flush(env, 1);
+}
+
+void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t dest = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stq(dest, env->cregs[i]);
+        dest += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    int i;
+    uint64_t dest = a2;
+
+    for (i = r1;; i = (i + 1) % 16) {
+        stl(dest, env->cregs[i]);
+        dest += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
+{
+    /* XXX implement */
+
+    return 0;
+}
+
+/* insert storage key extended */
+uint64_t HELPER(iske)(uint64_t r2)
+{
+    uint64_t addr = get_address(0, 0, r2);
+
+    if (addr > ram_size) {
+        return 0;
+    }
+
+    /* XXX maybe use qemu's internal keys? */
+    return env->storage_keys[addr / TARGET_PAGE_SIZE];
+}
+
+/* set storage key extended */
+void HELPER(sske)(uint32_t r1, uint64_t r2)
+{
+    uint64_t addr = get_address(0, 0, r2);
+
+    if (addr > ram_size) {
+        return;
+    }
+
+    env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
+}
+
+/* reset reference bit extended */
+uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
+{
+    if (r2 > ram_size) {
+        return 0;
+    }
+
+    /* XXX implement */
+#if 0
+    env->storage_keys[r2 / TARGET_PAGE_SIZE] &= ~SK_REFERENCED;
+#endif
+
+    /*
+     * cc
+     *
+     * 0  Reference bit zero; change bit zero
+     * 1  Reference bit zero; change bit one
+     * 2  Reference bit one; change bit zero
+     * 3  Reference bit one; change bit one
+     */
+    return 0;
+}
+
+/* compare and swap and purge */
+uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
+{
+    uint32_t cc;
+    uint32_t o1 = env->regs[r1];
+    uint64_t a2 = get_address_31fix(r2) & ~3ULL;
+    uint32_t o2 = ldl(a2);
+
+    if (o1 == o2) {
+        stl(a2, env->regs[(r1 + 1) & 15]);
+        if (env->regs[r2] & 0x3) {
+            /* flush TLB / ALB */
+            tlb_flush(env, 1);
+        }
+        cc = 0;
+    } else {
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
+        cc = 1;
+    }
+
+    return cc;
+}
+
+static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
+                        uint64_t mode2)
+{
+    target_ulong src, dest;
+    int flags, cc = 0, i;
+
+    if (!l) {
+        return 0;
+    } else if (l > 256) {
+        /* max 256 */
+        l = 256;
+        cc = 3;
+    }
+
+    if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
+        cpu_loop_exit(env);
+    }
+    dest |= a1 & ~TARGET_PAGE_MASK;
+
+    if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
+        cpu_loop_exit(env);
+    }
+    src |= a2 & ~TARGET_PAGE_MASK;
+
+    /* XXX replace w/ memcpy */
+    for (i = 0; i < l; i++) {
+        /* XXX be more clever */
+        if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
+            (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
+            mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
+            break;
+        }
+        stb_phys(dest + i, ldub_phys(src + i));
+    }
+
+    return cc;
+}
+
+uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
+{
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __FUNCTION__, l, a1, a2);
+
+    return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
+}
+
+uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
+{
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __FUNCTION__, l, a1, a2);
+
+    return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
+}
+
+uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
+{
+    int cc = 0;
+
+    HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
+               __FUNCTION__, order_code, r1, cpu_addr);
+
+    /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register"
+       as parameter (input). Status (output) is always R1. */
+
+    switch (order_code) {
+    case SIGP_SET_ARCH:
+        /* switch arch */
+        break;
+    case SIGP_SENSE:
+        /* enumerate CPU status */
+        if (cpu_addr) {
+            /* XXX implement when SMP comes */
+            return 3;
+        }
+        env->regs[r1] &= 0xffffffff00000000ULL;
+        cc = 1;
+        break;
+    default:
+        /* unknown sigp */
+        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
+        cc = 3;
+    }
+
+    return cc;
+}
+
+void HELPER(sacf)(uint64_t a1)
+{
+    HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1);
+
+    switch (a1 & 0xf00) {
+    case 0x000:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_PRIMARY;
+        break;
+    case 0x100:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_SECONDARY;
+        break;
+    case 0x300:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_HOME;
+        break;
+    default:
+        qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
+        program_interrupt(env, PGM_SPECIFICATION, 2);
+        break;
+    }
+}
+
+/* invalidate pte */
+void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
+{
+    uint64_t page = vaddr & TARGET_PAGE_MASK;
+    uint64_t pte = 0;
+
+    /* XXX broadcast to other CPUs */
+
+    /* XXX Linux is nice enough to give us the exact pte address.
+           According to spec we'd have to find it out ourselves */
+    /* XXX Linux is fine with overwriting the pte, the spec requires
+           us to only set the invalid bit */
+    stq_phys(pte_addr, pte | _PAGE_INVALID);
+
+    /* XXX we exploit the fact that Linux passes the exact virtual
+           address here - it's not obliged to! */
+    tlb_flush_page(env, page);
+}
+
+/* flush local tlb */
+void HELPER(ptlb)(void)
+{
+    tlb_flush(env, 1);
+}
+
+/* store using real address */
+void HELPER(stura)(uint64_t addr, uint32_t v1)
+{
+    stw_phys(get_address(0, 0, addr), v1);
+}
+
+/* load real address */
+uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
+{
+    uint32_t cc = 0;
+    int old_exc = env->exception_index;
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    uint64_t ret;
+    int flags;
+
+    /* XXX incomplete - has more corner cases */
+    if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
+        program_interrupt(env, PGM_SPECIAL_OP, 2);
+    }
+
+    env->exception_index = old_exc;
+    if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
+        cc = 3;
+    }
+    if (env->exception_index == EXCP_PGM) {
+        ret = env->int_pgm_code | 0x80000000;
+    } else {
+        ret |= addr & ~TARGET_PAGE_MASK;
+    }
+    env->exception_index = old_exc;
+
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL);
+    } else {
+        env->regs[r1] = ret;
+    }
+
+    return cc;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-s390x/translate.c b/qemu-0.15.x/target-s390x/translate.c
new file mode 100644
index 0000000..77fb448
--- /dev/null
+++ b/qemu-0.15.x/target-s390x/translate.c
@@ -0,0 +1,5245 @@
+/*
+ *  S/390 translation
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2010 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+/* #define DEBUG_ILLEGAL_INSTRUCTIONS */
+/* #define DEBUG_INLINE_BRANCHES */
+#define S390X_DEBUG_DISAS
+/* #define S390X_DEBUG_DISAS_VERBOSE */
+
+#ifdef S390X_DEBUG_DISAS_VERBOSE
+#  define LOG_DISAS(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_DISAS(...) do { } while (0)
+#endif
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+/* global register indexes */
+static TCGv_ptr cpu_env;
+
+#include "gen-icount.h"
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext DisasContext;
+struct DisasContext {
+    uint64_t pc;
+    int is_jmp;
+    enum cc_op cc_op;
+    struct TranslationBlock *tb;
+};
+
+#define DISAS_EXCP 4
+
+static void gen_op_calc_cc(DisasContext *s);
+
+#ifdef DEBUG_INLINE_BRANCHES
+static uint64_t inline_branch_hit[CC_OP_MAX];
+static uint64_t inline_branch_miss[CC_OP_MAX];
+#endif
+
+static inline void debug_insn(uint64_t insn)
+{
+    LOG_DISAS("insn: 0x%" PRIx64 "\n", insn);
+}
+
+static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc)
+{
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        if (s->tb->flags & FLAG_MASK_32) {
+            return pc | 0x80000000;
+        }
+    }
+    return pc;
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+
+    cpu_fprintf(f, "\n");
+
+#ifndef CONFIG_USER_ONLY
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+#endif
+
+    cpu_fprintf(f, "\n");
+
+    if (env->cc_op > 3) {
+        cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n",
+                    env->psw.mask, env->psw.addr, cc_name(env->cc_op));
+    } else {
+        cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n",
+                    env->psw.mask, env->psw.addr, env->cc_op);
+    }
+
+#ifdef DEBUG_INLINE_BRANCHES
+    for (i = 0; i < CC_OP_MAX; i++) {
+        cpu_fprintf(f, "  %15s = %10ld\t%10ld\n", cc_name(i),
+                    inline_branch_miss[i], inline_branch_hit[i]);
+    }
+#endif
+}
+
+static TCGv_i64 psw_addr;
+static TCGv_i64 psw_mask;
+
+static TCGv_i32 cc_op;
+static TCGv_i64 cc_src;
+static TCGv_i64 cc_dst;
+static TCGv_i64 cc_vr;
+
+static char cpu_reg_names[10*3 + 6*4];
+static TCGv_i64 regs[16];
+
+static uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
+
+void s390x_translate_init(void)
+{
+    int i;
+    size_t cpu_reg_names_size = sizeof(cpu_reg_names);
+    char *p;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.addr),
+                                      "psw_addr");
+    psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.mask),
+                                      "psw_mask");
+
+    cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc_op),
+                                   "cc_op");
+    cc_src = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_src),
+                                    "cc_src");
+    cc_dst = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_dst),
+                                    "cc_dst");
+    cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, cc_vr),
+                                   "cc_vr");
+
+    p = cpu_reg_names;
+    for (i = 0; i < 16; i++) {
+        snprintf(p, cpu_reg_names_size, "r%d", i);
+        regs[i] = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, regs[i]), p);
+        p += (i < 10) ? 3 : 4;
+        cpu_reg_names_size -= (i < 10) ? 3 : 4;
+    }
+}
+
+static inline TCGv_i64 load_reg(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_mov_i64(r, regs[reg]);
+    return r;
+}
+
+static inline TCGv_i64 load_freg(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, fregs[reg].d));
+    return r;
+}
+
+static inline TCGv_i32 load_freg32(int reg)
+{
+    TCGv_i32 r = tcg_temp_new_i32();
+    tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].l.upper));
+    return r;
+}
+
+static inline TCGv_i32 load_reg32(int reg)
+{
+    TCGv_i32 r = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(r, regs[reg]);
+    return r;
+}
+
+static inline TCGv_i64 load_reg32_i64(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(r, regs[reg]);
+    return r;
+}
+
+static inline void store_reg(int reg, TCGv_i64 v)
+{
+    tcg_gen_mov_i64(regs[reg], v);
+}
+
+static inline void store_freg(int reg, TCGv_i64 v)
+{
+    tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, fregs[reg].d));
+}
+
+static inline void store_reg32(int reg, TCGv_i32 v)
+{
+#if HOST_LONG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v);
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(tmp, v);
+    /* 32 bit register writes keep the upper half */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 32);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void store_reg32_i64(int reg, TCGv_i64 v)
+{
+    /* 32 bit register writes keep the upper half */
+#if HOST_LONG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(regs[reg]), TCGV_LOW(v));
+#else
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32);
+#endif
+}
+
+static inline void store_reg16(int reg, TCGv_i32 v)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(tmp, v);
+    /* 16 bit register writes keep the upper bytes */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 16);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void store_reg8(int reg, TCGv_i64 v)
+{
+    /* 8 bit register writes keep the upper bytes */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 8);
+}
+
+static inline void store_freg32(int reg, TCGv_i32 v)
+{
+    tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, fregs[reg].l.upper));
+}
+
+static inline void update_psw_addr(DisasContext *s)
+{
+    /* psw.addr */
+    tcg_gen_movi_i64(psw_addr, s->pc);
+}
+
+static inline void potential_page_fault(DisasContext *s)
+{
+#ifndef CONFIG_USER_ONLY
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+#endif
+}
+
+static inline uint64_t ld_code2(uint64_t pc)
+{
+    return (uint64_t)lduw_code(pc);
+}
+
+static inline uint64_t ld_code4(uint64_t pc)
+{
+    return (uint64_t)ldl_code(pc);
+}
+
+static inline uint64_t ld_code6(uint64_t pc)
+{
+    uint64_t opc;
+    opc = (uint64_t)lduw_code(pc) << 32;
+    opc |= (uint64_t)(uint32_t)ldl_code(pc+2);
+    return opc;
+}
+
+static inline int get_mem_index(DisasContext *s)
+{
+    switch (s->tb->flags & FLAG_MASK_ASC) {
+    case PSW_ASC_PRIMARY >> 32:
+        return 0;
+    case PSW_ASC_SECONDARY >> 32:
+        return 1;
+    case PSW_ASC_HOME >> 32:
+        return 2;
+    default:
+        tcg_abort();
+        break;
+    }
+}
+
+static inline void gen_debug(DisasContext *s)
+{
+    TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+    s->is_jmp = DISAS_EXCP;
+}
+
+#ifdef CONFIG_USER_ONLY
+
+static void gen_illegal_opcode(DisasContext *s, int ilc)
+{
+    TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC);
+    update_psw_addr(s);
+    gen_op_calc_cc(s);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+    s->is_jmp = DISAS_EXCP;
+}
+
+#else /* CONFIG_USER_ONLY */
+
+static void debug_print_inst(DisasContext *s, int ilc)
+{
+#ifdef DEBUG_ILLEGAL_INSTRUCTIONS
+    uint64_t inst = 0;
+
+    switch (ilc & 3) {
+    case 1:
+        inst = ld_code2(s->pc);
+        break;
+    case 2:
+        inst = ld_code4(s->pc);
+        break;
+    case 3:
+        inst = ld_code6(s->pc);
+        break;
+    }
+
+    fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016"
+            PRIx64 "\n", ilc, s->pc, inst);
+#endif
+}
+
+static void gen_program_exception(DisasContext *s, int ilc, int code)
+{
+    TCGv_i32 tmp;
+
+    debug_print_inst(s, ilc);
+
+    /* remember what pgm exeption this was */
+    tmp = tcg_const_i32(code);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, int_pgm_code));
+    tcg_temp_free_i32(tmp);
+
+    tmp = tcg_const_i32(ilc);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, int_pgm_ilc));
+    tcg_temp_free_i32(tmp);
+
+    /* advance past instruction */
+    s->pc += (ilc * 2);
+    update_psw_addr(s);
+
+    /* save off cc */
+    gen_op_calc_cc(s);
+
+    /* trigger exception */
+    tmp = tcg_const_i32(EXCP_PGM);
+    gen_helper_exception(tmp);
+    tcg_temp_free_i32(tmp);
+
+    /* end TB here */
+    s->is_jmp = DISAS_EXCP;
+}
+
+
+static void gen_illegal_opcode(DisasContext *s, int ilc)
+{
+    gen_program_exception(s, ilc, PGM_SPECIFICATION);
+}
+
+static void gen_privileged_exception(DisasContext *s, int ilc)
+{
+    gen_program_exception(s, ilc, PGM_PRIVILEGED);
+}
+
+static void check_privileged(DisasContext *s, int ilc)
+{
+    if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) {
+        gen_privileged_exception(s, ilc);
+    }
+}
+
+#endif /* CONFIG_USER_ONLY */
+
+static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
+{
+    TCGv_i64 tmp;
+
+    /* 31-bitify the immediate part; register contents are dealt with below */
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        d2 &= 0x7fffffffUL;
+    }
+
+    if (x2) {
+        if (d2) {
+            tmp = tcg_const_i64(d2);
+            tcg_gen_add_i64(tmp, tmp, regs[x2]);
+        } else {
+            tmp = load_reg(x2);
+        }
+        if (b2) {
+            tcg_gen_add_i64(tmp, tmp, regs[b2]);
+        }
+    } else if (b2) {
+        if (d2) {
+            tmp = tcg_const_i64(d2);
+            tcg_gen_add_i64(tmp, tmp, regs[b2]);
+        } else {
+            tmp = load_reg(b2);
+        }
+    } else {
+        tmp = tcg_const_i64(d2);
+    }
+
+    /* 31-bit mode mask if there are values loaded from registers */
+    if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) {
+        tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL);
+    }
+
+    return tmp;
+}
+
+static void gen_op_movi_cc(DisasContext *s, uint32_t val)
+{
+    s->cc_op = CC_OP_CONST0 + val;
+}
+
+static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst)
+{
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
+                                  TCGv_i32 dst)
+{
+    tcg_gen_extu_i32_i64(cc_src, src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst, TCGv_i64 vr)
+{
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_mov_i64(cc_vr, vr);
+    s->cc_op = op;
+}
+
+static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
+                                  TCGv_i32 dst, TCGv_i32 vr)
+{
+    tcg_gen_extu_i32_i64(cc_src, src);
+    tcg_gen_extu_i32_i64(cc_dst, dst);
+    tcg_gen_extu_i32_i64(cc_vr, vr);
+    s->cc_op = op;
+}
+
+static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NZ, val);
+}
+
+static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ, val);
+}
+
+static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          enum cc_op cond)
+{
+    gen_op_update2_cc_i32(s, cond, v1, v2);
+}
+
+static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          enum cc_op cond)
+{
+    gen_op_update2_cc_i64(s, cond, v1, v2);
+}
+
+static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    cmp_32(s, v1, v2, CC_OP_LTGT_32);
+}
+
+static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    cmp_32(s, v1, v2, CC_OP_LTUGTU_32);
+}
+
+static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2)
+{
+    /* XXX optimize for the constant? put it in s? */
+    TCGv_i32 tmp = tcg_const_i32(v2);
+    cmp_32(s, v1, tmp, CC_OP_LTGT_32);
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2)
+{
+    TCGv_i32 tmp = tcg_const_i32(v2);
+    cmp_32(s, v1, tmp, CC_OP_LTUGTU_32);
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
+{
+    cmp_64(s, v1, v2, CC_OP_LTGT_64);
+}
+
+static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
+{
+    cmp_64(s, v1, v2, CC_OP_LTUGTU_64);
+}
+
+static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2)
+{
+    TCGv_i64 tmp = tcg_const_i64(v2);
+    cmp_s64(s, v1, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2)
+{
+    TCGv_i64 tmp = tcg_const_i64(v2);
+    cmp_u64(s, v1, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void set_cc_s32(DisasContext *s, TCGv_i32 val)
+{
+    gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val);
+}
+
+static inline void set_cc_s64(DisasContext *s, TCGv_i64 val)
+{
+    gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val);
+}
+
+static void set_cc_add64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADD_64, v1, v2, vr);
+}
+
+static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr);
+}
+
+static void set_cc_sub64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUB_64, v1, v2, vr);
+}
+
+static void set_cc_subu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
+                          TCGv_i64 vr)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUBU_64, v1, v2, vr);
+}
+
+static void set_cc_abs64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1);
+}
+
+static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1);
+}
+
+static void set_cc_add32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_ADD_32, v1, v2, vr);
+}
+
+static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr);
+}
+
+static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr);
+}
+
+static void set_cc_subu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
+                          TCGv_i32 vr)
+{
+    gen_op_update3_cc_i32(s, CC_OP_SUBU_32, v1, v2, vr);
+}
+
+static void set_cc_abs32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1);
+}
+
+static void set_cc_nabs32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NABS_32, v1);
+}
+
+static void set_cc_comp32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_COMP_32, v1);
+}
+
+static void set_cc_comp64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_COMP_64, v1);
+}
+
+static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
+{
+    gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2);
+}
+
+static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2)
+{
+    tcg_gen_extu_i32_i64(cc_src, v1);
+    tcg_gen_mov_i64(cc_dst, v2);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = CC_OP_LTGT_F32;
+}
+
+static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1)
+{
+    gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1);
+}
+
+static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1);
+}
+
+/* CC value is in env->cc_op */
+static inline void set_cc_static(DisasContext *s)
+{
+    tcg_gen_discard_i64(cc_src);
+    tcg_gen_discard_i64(cc_dst);
+    tcg_gen_discard_i64(cc_vr);
+    s->cc_op = CC_OP_STATIC;
+}
+
+static inline void gen_op_set_cc_op(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
+        tcg_gen_movi_i32(cc_op, s->cc_op);
+    }
+}
+
+static inline void gen_update_cc_op(DisasContext *s)
+{
+    gen_op_set_cc_op(s);
+}
+
+/* calculates cc into cc_op */
+static void gen_op_calc_cc(DisasContext *s)
+{
+    TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op);
+    TCGv_i64 dummy = tcg_const_i64(0);
+
+    switch (s->cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* s->cc_op is the cc value */
+        tcg_gen_movi_i32(cc_op, s->cc_op - CC_OP_CONST0);
+        break;
+    case CC_OP_STATIC:
+        /* env->cc_op already is the cc value */
+        break;
+    case CC_OP_NZ:
+    case CC_OP_ABS_64:
+    case CC_OP_NABS_64:
+    case CC_OP_ABS_32:
+    case CC_OP_NABS_32:
+    case CC_OP_LTGT0_32:
+    case CC_OP_LTGT0_64:
+    case CC_OP_COMP_32:
+    case CC_OP_COMP_64:
+    case CC_OP_NZ_F32:
+    case CC_OP_NZ_F64:
+        /* 1 argument */
+        gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy);
+        break;
+    case CC_OP_ICM:
+    case CC_OP_LTGT_32:
+    case CC_OP_LTGT_64:
+    case CC_OP_LTUGTU_32:
+    case CC_OP_LTUGTU_64:
+    case CC_OP_TM_32:
+    case CC_OP_TM_64:
+    case CC_OP_LTGT_F32:
+    case CC_OP_LTGT_F64:
+    case CC_OP_SLAG:
+        /* 2 arguments */
+        gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy);
+        break;
+    case CC_OP_ADD_64:
+    case CC_OP_ADDU_64:
+    case CC_OP_SUB_64:
+    case CC_OP_SUBU_64:
+    case CC_OP_ADD_32:
+    case CC_OP_ADDU_32:
+    case CC_OP_SUB_32:
+    case CC_OP_SUBU_32:
+        /* 3 arguments */
+        gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    case CC_OP_DYNAMIC:
+        /* unknown operation - assume 3 arguments and cc_op in env */
+        gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    tcg_temp_free_i32(local_cc_op);
+
+    /* We now have cc in cc_op as constant */
+    set_cc_static(s);
+}
+
+static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 4) & 0xf;
+    *r2 = insn & 0xf;
+}
+
+static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1,
+                                 int *x2, int *b2, int *d2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 20) & 0xf;
+    *x2 = (insn >> 16) & 0xf;
+    *b2 = (insn >> 12) & 0xf;
+    *d2 = insn & 0xfff;
+
+    return get_address(s, *x2, *b2, *d2);
+}
+
+static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3,
+                             int *b2, int *d2)
+{
+    debug_insn(insn);
+
+    *r1 = (insn >> 20) & 0xf;
+    /* aka m3 */
+    *r3 = (insn >> 16) & 0xf;
+    *b2 = (insn >> 12) & 0xf;
+    *d2 = insn & 0xfff;
+}
+
+static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2,
+                                 int *b1, int *d1)
+{
+    debug_insn(insn);
+
+    *i2 = (insn >> 16) & 0xff;
+    *b1 = (insn >> 12) & 0xf;
+    *d1 = insn & 0xfff;
+
+    return get_address(s, 0, *b1, *d1);
+}
+
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc)
+{
+    TranslationBlock *tb;
+
+    gen_update_cc_op(s);
+
+    tb = s->tb;
+    /* NOTE: we handle the case where the TB spans two pages here */
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
+        (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
+        /* jump to same page: we can use a direct jump */
+        tcg_gen_goto_tb(tb_num);
+        tcg_gen_movi_i64(psw_addr, pc);
+        tcg_gen_exit_tb((long)tb + tb_num);
+    } else {
+        /* jump to another page: currently not optimized */
+        tcg_gen_movi_i64(psw_addr, pc);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void account_noninline_branch(DisasContext *s, int cc_op)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_miss[cc_op]++;
+#endif
+}
+
+static inline void account_inline_branch(DisasContext *s)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_hit[s->cc_op]++;
+#endif
+}
+
+static void gen_jcc(DisasContext *s, uint32_t mask, int skip)
+{
+    TCGv_i32 tmp, tmp2, r;
+    TCGv_i64 tmp64;
+    int old_cc_op;
+
+    switch (s->cc_op) {
+    case CC_OP_LTGT0_32:
+        tmp = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* dst <= 0 */
+            tcg_gen_brcondi_i32(TCG_COND_GT, tmp, 0, skip);
+            break;
+        case 0x8 | 0x2: /* dst >= 0 */
+            tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, skip);
+            break;
+        case 0x8: /* dst == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            break;
+        case 0x7: /* dst != 0 */
+        case 0x6: /* dst != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            break;
+        case 0x4: /* dst < 0 */
+            tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, skip);
+            break;
+        case 0x2: /* dst > 0 */
+            tcg_gen_brcondi_i32(TCG_COND_LE, tmp, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        break;
+    case CC_OP_LTGT0_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* dst <= 0 */
+            tcg_gen_brcondi_i64(TCG_COND_GT, cc_dst, 0, skip);
+            break;
+        case 0x8 | 0x2: /* dst >= 0 */
+            tcg_gen_brcondi_i64(TCG_COND_LT, cc_dst, 0, skip);
+            break;
+        case 0x8: /* dst == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        case 0x7: /* dst != 0 */
+        case 0x6: /* dst != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        case 0x4: /* dst < 0 */
+            tcg_gen_brcondi_i64(TCG_COND_GE, cc_dst, 0, skip);
+            break;
+        case 0x2: /* dst > 0 */
+            tcg_gen_brcondi_i64(TCG_COND_LE, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_LTGT_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i32(TCG_COND_GT, tmp, tmp2, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i32(TCG_COND_LT, tmp, tmp2, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i32(TCG_COND_GE, tmp, tmp2, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i32(TCG_COND_LE, tmp, tmp2, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        break;
+    case CC_OP_LTGT_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i64(TCG_COND_GT, cc_src, cc_dst, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i64(TCG_COND_LT, cc_src, cc_dst, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i64(TCG_COND_GE, cc_src, cc_dst, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i64(TCG_COND_LE, cc_src, cc_dst, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_LTUGTU_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i32(TCG_COND_GTU, tmp, tmp2, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i32(TCG_COND_LTU, tmp, tmp2, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i32(TCG_COND_GEU, tmp, tmp2, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i32(TCG_COND_LEU, tmp, tmp2, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        break;
+    case CC_OP_LTUGTU_64:
+        switch (mask) {
+        case 0x8 | 0x4: /* src <= dst */
+            tcg_gen_brcond_i64(TCG_COND_GTU, cc_src, cc_dst, skip);
+            break;
+        case 0x8 | 0x2: /* src >= dst */
+            tcg_gen_brcond_i64(TCG_COND_LTU, cc_src, cc_dst, skip);
+            break;
+        case 0x8: /* src == dst */
+            tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip);
+            break;
+        case 0x7: /* src != dst */
+        case 0x6: /* src != dst */
+            tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip);
+            break;
+        case 0x4: /* src < dst */
+            tcg_gen_brcond_i64(TCG_COND_GEU, cc_src, cc_dst, skip);
+            break;
+        case 0x2: /* src > dst */
+            tcg_gen_brcond_i64(TCG_COND_LEU, cc_src, cc_dst, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_NZ:
+        switch (mask) {
+        /* dst == 0 || dst != 0 */
+        case 0x8 | 0x4:
+        case 0x8 | 0x4 | 0x2:
+        case 0x8 | 0x4 | 0x2 | 0x1:
+        case 0x8 | 0x4 | 0x1:
+            break;
+        /* dst == 0 */
+        case 0x8:
+        case 0x8 | 0x2:
+        case 0x8 | 0x2 | 0x1:
+        case 0x8 | 0x1:
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        /* dst != 0 */
+        case 0x4:
+        case 0x4 | 0x2:
+        case 0x4 | 0x2 | 0x1:
+        case 0x4 | 0x1:
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_TM_32:
+        tmp = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i32();
+
+        tcg_gen_trunc_i64_i32(tmp, cc_src);
+        tcg_gen_trunc_i64_i32(tmp2, cc_dst);
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        switch (mask) {
+        case 0x8: /* val & mask == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val & mask != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+            goto do_dynamic;
+        }
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(tmp2);
+        account_inline_branch(s);
+        break;
+    case CC_OP_TM_64:
+        tmp64 = tcg_temp_new_i64();
+
+        tcg_gen_and_i64(tmp64, cc_src, cc_dst);
+        switch (mask) {
+        case 0x8: /* val & mask == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, tmp64, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val & mask != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip);
+            break;
+        default:
+            tcg_temp_free_i64(tmp64);
+            goto do_dynamic;
+        }
+        tcg_temp_free_i64(tmp64);
+        account_inline_branch(s);
+        break;
+    case CC_OP_ICM:
+        switch (mask) {
+        case 0x8: /* val == 0 */
+            tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* val != 0 */
+        case 0x4 | 0x2: /* val != 0 */
+            tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip);
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s);
+        break;
+    case CC_OP_STATIC:
+        old_cc_op = s->cc_op;
+        goto do_dynamic_nocccalc;
+    case CC_OP_DYNAMIC:
+    default:
+do_dynamic:
+        old_cc_op = s->cc_op;
+        /* calculate cc value */
+        gen_op_calc_cc(s);
+
+do_dynamic_nocccalc:
+        /* jump based on cc */
+        account_noninline_branch(s, old_cc_op);
+
+        switch (mask) {
+        case 0x8 | 0x4 | 0x2 | 0x1:
+            /* always true */
+            break;
+        case 0x8 | 0x4 | 0x2: /* cc != 3 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 3, skip);
+            break;
+        case 0x8 | 0x4 | 0x1: /* cc != 2 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 2, skip);
+            break;
+        case 0x8 | 0x2 | 0x1: /* cc != 1 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 1, skip);
+            break;
+        case 0x8 | 0x2: /* cc == 0 || cc == 2 */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_andi_i32(tmp, cc_op, 1);
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip);
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x8 | 0x4: /* cc < 2 */
+            tcg_gen_brcondi_i32(TCG_COND_GEU, cc_op, 2, skip);
+            break;
+        case 0x8: /* cc == 0 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 0, skip);
+            break;
+        case 0x4 | 0x2 | 0x1: /* cc != 0 */
+            tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 0, skip);
+            break;
+        case 0x4 | 0x1: /* cc == 1 || cc == 3 */
+            tmp = tcg_temp_new_i32();
+            tcg_gen_andi_i32(tmp, cc_op, 1);
+            tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
+            tcg_temp_free_i32(tmp);
+            break;
+        case 0x4: /* cc == 1 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 1, skip);
+            break;
+        case 0x2 | 0x1: /* cc > 1 */
+            tcg_gen_brcondi_i32(TCG_COND_LEU, cc_op, 1, skip);
+            break;
+        case 0x2: /* cc == 2 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 2, skip);
+            break;
+        case 0x1: /* cc == 3 */
+            tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 3, skip);
+            break;
+        default: /* cc is masked by something else */
+            tmp = tcg_const_i32(3);
+            /* 3 - cc */
+            tcg_gen_sub_i32(tmp, tmp, cc_op);
+            tmp2 = tcg_const_i32(1);
+            /* 1 << (3 - cc) */
+            tcg_gen_shl_i32(tmp2, tmp2, tmp);
+            r = tcg_const_i32(mask);
+            /* mask & (1 << (3 - cc)) */
+            tcg_gen_and_i32(r, r, tmp2);
+            tcg_temp_free_i32(tmp);
+            tcg_temp_free_i32(tmp2);
+
+            tcg_gen_brcondi_i32(TCG_COND_EQ, r, 0, skip);
+            tcg_temp_free_i32(r);
+            break;
+        }
+        break;
+    }
+}
+
+static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target,
+                    uint64_t offset)
+{
+    int skip;
+
+    if (mask == 0xf) {
+        /* unconditional */
+        tcg_gen_mov_i64(psw_addr, target);
+        tcg_gen_exit_tb(0);
+    } else if (mask == 0) {
+        /* ignore cc and never match */
+        gen_goto_tb(s, 0, offset + 2);
+    } else {
+        TCGv_i64 new_addr = tcg_temp_local_new_i64();
+
+        tcg_gen_mov_i64(new_addr, target);
+        skip = gen_new_label();
+        gen_jcc(s, mask, skip);
+        tcg_gen_mov_i64(psw_addr, new_addr);
+        tcg_temp_free_i64(new_addr);
+        tcg_gen_exit_tb(0);
+        gen_set_label(skip);
+        tcg_temp_free_i64(new_addr);
+        gen_goto_tb(s, 1, offset + 2);
+    }
+}
+
+static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset)
+{
+    int skip;
+
+    if (mask == 0xf) {
+        /* unconditional */
+        gen_goto_tb(s, 0, s->pc + offset);
+    } else if (mask == 0) {
+        /* ignore cc and never match */
+        gen_goto_tb(s, 0, s->pc + 4);
+    } else {
+        skip = gen_new_label();
+        gen_jcc(s, mask, skip);
+        gen_goto_tb(s, 0, s->pc + offset);
+        gen_set_label(skip);
+        gen_goto_tb(s, 1, s->pc + 4);
+    }
+    s->is_jmp = DISAS_TB_JUMP;
+}
+
+static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
+{
+    TCGv_i64 tmp, tmp2;
+    int i;
+    int l_memset = gen_new_label();
+    int l_out = gen_new_label();
+    TCGv_i64 dest = tcg_temp_local_new_i64();
+    TCGv_i64 src = tcg_temp_local_new_i64();
+    TCGv_i32 vl;
+
+    /* Find out if we should use the inline version of mvc */
+    switch (l) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 11:
+    case 15:
+        /* use inline */
+        break;
+    default:
+        /* Fall back to helper */
+        vl = tcg_const_i32(l);
+        potential_page_fault(s);
+        gen_helper_mvc(vl, s1, s2);
+        tcg_temp_free_i32(vl);
+        return;
+    }
+
+    tcg_gen_mov_i64(dest, s1);
+    tcg_gen_mov_i64(src, s2);
+
+    if (!(s->tb->flags & FLAG_MASK_64)) {
+        /* XXX what if we overflow while moving? */
+        tcg_gen_andi_i64(dest, dest, 0x7fffffffUL);
+        tcg_gen_andi_i64(src, src, 0x7fffffffUL);
+    }
+
+    tmp = tcg_temp_new_i64();
+    tcg_gen_addi_i64(tmp, src, 1);
+    tcg_gen_brcond_i64(TCG_COND_EQ, dest, tmp, l_memset);
+    tcg_temp_free_i64(tmp);
+
+    switch (l) {
+    case 0:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 1:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld16u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st16(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 3:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st32(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    case 4:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s));
+        tcg_gen_addi_i64(src, src, 4);
+        tcg_gen_qemu_ld8u(tmp2, src, get_mem_index(s));
+        tcg_gen_qemu_st32(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 4);
+        tcg_gen_qemu_st8(tmp2, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 7:
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld64(tmp, src, get_mem_index(s));
+        tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        /* The inline version can become too big for too uneven numbers, only
+           use it on known good lengths */
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_const_i64(8);
+        for (i = 0; (i + 7) <= l; i += 8) {
+            tcg_gen_qemu_ld64(tmp, src, get_mem_index(s));
+            tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+
+            tcg_gen_add_i64(src, src, tmp2);
+            tcg_gen_add_i64(dest, dest, tmp2);
+        }
+
+        tcg_temp_free_i64(tmp2);
+        tmp2 = tcg_const_i64(1);
+
+        for (; i <= l; i++) {
+            tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+            tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+
+            tcg_gen_add_i64(src, src, tmp2);
+            tcg_gen_add_i64(dest, dest, tmp2);
+        }
+
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    }
+
+    tcg_gen_br(l_out);
+
+    gen_set_label(l_memset);
+    /* memset case (dest == (src + 1)) */
+
+    tmp = tcg_temp_new_i64();
+    tmp2 = tcg_temp_new_i64();
+    /* fill tmp with the byte */
+    tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s));
+    tcg_gen_shli_i64(tmp2, tmp, 8);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_gen_shli_i64(tmp2, tmp, 16);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_gen_shli_i64(tmp2, tmp, 32);
+    tcg_gen_or_i64(tmp, tmp, tmp2);
+    tcg_temp_free_i64(tmp2);
+
+    tmp2 = tcg_const_i64(8);
+
+    for (i = 0; (i + 7) <= l; i += 8) {
+        tcg_gen_qemu_st64(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 8);
+    }
+
+    tcg_temp_free_i64(tmp2);
+    tmp2 = tcg_const_i64(1);
+
+    for (; i <= l; i++) {
+        tcg_gen_qemu_st8(tmp, dest, get_mem_index(s));
+        tcg_gen_addi_i64(dest, dest, 1);
+    }
+
+    tcg_temp_free_i64(tmp2);
+    tcg_temp_free_i64(tmp);
+
+    gen_set_label(l_out);
+
+    tcg_temp_free(dest);
+    tcg_temp_free(src);
+}
+
+static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
+{
+    TCGv_i64 tmp;
+    TCGv_i64 tmp2;
+    TCGv_i32 vl;
+
+    /* check for simple 32bit or 64bit match */
+    switch (l) {
+    case 0:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld8u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld8u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 1:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld16u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld16u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 3:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld32u(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld32u(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    case 7:
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld64(tmp, s1, get_mem_index(s));
+        tcg_gen_qemu_ld64(tmp2, s2, get_mem_index(s));
+        cmp_u64(s, tmp, tmp2);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        return;
+    }
+
+    potential_page_fault(s);
+    vl = tcg_const_i32(l);
+    gen_helper_clc(cc_op, vl, s1, s2);
+    tcg_temp_free_i32(vl);
+    set_cc_static(s);
+}
+
+static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
+{
+    TCGv_i64 addr, tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n",
+              op, r1, x2, b2, d2);
+    addr = get_address(s, x2, b2, d2);
+    switch (op) {
+    case 0x2: /* LTG R1,D2(X2,B2) [RXY] */
+    case 0x4: /* lg r1,d2(x2,b2) */
+        tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s));
+        if (op == 0x2) {
+            set_cc_s64(s, regs[r1]);
+        }
+        break;
+    case 0x12: /* LT R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_reg32(r1, tmp32_1);
+        set_cc_s32(s, tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xc: /* MSG      R1,D2(X2,B2)     [RXY] */
+    case 0x1c: /* MSGF     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0xc) {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        }
+        tcg_gen_mul_i64(regs[r1], regs[r1], tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xd: /* DSG      R1,D2(X2,B2)     [RXY] */
+    case 0x1d: /* DSGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x1d) {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1 + 1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_div_i64(tmp3, tmp4, tmp2);
+        store_reg(r1 + 1, tmp3);
+        tcg_gen_rem_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x8: /* AG      R1,D2(X2,B2)     [RXY] */
+    case 0xa: /* ALG      R1,D2(X2,B2)     [RXY] */
+    case 0x18: /* AGF       R1,D2(X2,B2)     [RXY] */
+    case 0x1a: /* ALGF      R1,D2(X2,B2)     [RXY] */
+        if (op == 0x1a) {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        } else if (op == 0x18) {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else {
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x8:
+        case 0x18:
+            set_cc_add64(s, tmp4, tmp2, tmp3);
+            break;
+        case 0xa:
+        case 0x1a:
+            set_cc_addu64(s, tmp4, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x9: /* SG      R1,D2(X2,B2)     [RXY] */
+    case 0xb: /* SLG      R1,D2(X2,B2)     [RXY] */
+    case 0x19: /* SGF      R1,D2(X2,B2)     [RXY] */
+    case 0x1b: /* SLGF     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x19) {
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        } else if (op == 0x1b) {
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        }
+        tmp4 = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_sub_i64(tmp3, tmp4, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x9:
+        case 0x19:
+            set_cc_sub64(s, tmp4, tmp2, tmp3);
+            break;
+        case 0xb:
+        case 0x1b:
+            set_cc_subu64(s, tmp4, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0xf: /* LRVG     R1,D2(X2,B2)     [RXE] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        tcg_gen_bswap64_i64(tmp2, tmp2);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x14: /* LGF      R1,D2(X2,B2)     [RXY] */
+    case 0x16: /* LLGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        if (op == 0x14) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x15: /* LGH     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s));
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x17: /* LLGT      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x1f: /* LRVH R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_bswap16_i32(tmp32_1, tmp32_1);
+        store_reg16(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x20: /* CG      R1,D2(X2,B2)     [RXY] */
+    case 0x21: /* CLG      R1,D2(X2,B2) */
+    case 0x30: /* CGF       R1,D2(X2,B2)     [RXY] */
+    case 0x31: /* CLGF      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        switch (op) {
+        case 0x20:
+        case 0x21:
+            tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+            break;
+        case 0x30:
+            tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+            break;
+        case 0x31:
+            tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+            break;
+        default:
+            tcg_abort();
+        }
+        switch (op) {
+        case 0x20:
+        case 0x30:
+            cmp_s64(s, regs[r1], tmp2);
+            break;
+        case 0x21:
+        case 0x31:
+            cmp_u64(s, regs[r1], tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x24: /* stg r1, d2(x2,b2) */
+        tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x50: /* STY  R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x57: /* XY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_gen_xor_i32(tmp32_2, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_2);
+        set_cc_nz_u32(s, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x58: /* LY R1,D2(X2,B2) [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5a: /* AY R1,D2(X2,B2) [RXY] */
+    case 0x5b: /* SY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_temp_free_i64(tmp2);
+        switch (op) {
+        case 0x5a:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        case 0x5b:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        switch (op) {
+        case 0x5a:
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5b:
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x71: /* LAY R1,D2(X2,B2) [RXY] */
+        store_reg(r1, addr);
+        break;
+    case 0x72: /* STCY R1,D2(X2,B2) [RXY] */
+        tmp32_1 = load_reg32(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st8(tmp2, addr, get_mem_index(s));
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x73: /* ICY R1,D2(X2,B2) [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s));
+        store_reg8(r1, tmp3);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x76: /* LB R1,D2(X2,B2) [RXY] */
+    case 0x77: /* LGB R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8s(tmp2, addr, get_mem_index(s));
+        switch (op) {
+        case 0x76:
+            tcg_gen_ext8s_i64(tmp2, tmp2);
+            store_reg32_i64(r1, tmp2);
+            break;
+        case 0x77:
+            tcg_gen_ext8s_i64(tmp2, tmp2);
+            store_reg(r1, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x78: /* LHY R1,D2(X2,B2) [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x80: /* NG      R1,D2(X2,B2)     [RXY] */
+    case 0x81: /* OG      R1,D2(X2,B2)     [RXY] */
+    case 0x82: /* XG      R1,D2(X2,B2)     [RXY] */
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp3, addr, get_mem_index(s));
+        switch (op) {
+        case 0x80:
+            tcg_gen_and_i64(regs[r1], regs[r1], tmp3);
+            break;
+        case 0x81:
+            tcg_gen_or_i64(regs[r1], regs[r1], tmp3);
+            break;
+        case 0x82:
+            tcg_gen_xor_i64(regs[r1], regs[r1], tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        set_cc_nz_u64(s, regs[r1]);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x86: /* MLG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        gen_helper_mlg(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x87: /* DLG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        gen_helper_dlg(tmp32_1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x88: /* ALCG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        tcg_gen_extu_i32_i64(tmp3, cc_op);
+        tcg_gen_shri_i64(tmp3, tmp3, 1);
+        tcg_gen_andi_i64(tmp3, tmp3, 1);
+        tcg_gen_add_i64(tmp3, tmp2, tmp3);
+        tcg_gen_add_i64(tmp3, regs[r1], tmp3);
+        store_reg(r1, tmp3);
+        set_cc_addu64(s, regs[r1], tmp2, tmp3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x89: /* SLBG      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x90: /* LLGC      R1,D2(X2,B2)     [RXY] */
+        tcg_gen_qemu_ld8u(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x91: /* LLGH      R1,D2(X2,B2)     [RXY] */
+        tcg_gen_qemu_ld16u(regs[r1], addr, get_mem_index(s));
+        break;
+    case 0x94: /* LLC     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x95: /* LLH     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x96: /* ML      R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x97: /* DL     R1,D2(X2,B2)     [RXY] */
+        /* reg(r1) = reg(r1, r1+1) % ld32(addr) */
+        /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */
+        tmp = load_reg(r1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp3);
+
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        tcg_gen_div_i64(tmp, tmp, tmp2);
+        store_reg32_i64((r1 + 1) & 15, tmp);
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x98: /* ALC     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
+        set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x99: /* SLB     R1,D2(X2,B2)     [RXY] */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal e3 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+    tcg_temp_free_i64(addr);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void disas_e5(DisasContext* s, uint64_t insn)
+{
+    TCGv_i64 tmp, tmp2;
+    int op = (insn >> 32) & 0xff;
+
+    tmp = get_address(s, 0, (insn >> 28) & 0xf, (insn >> 16) & 0xfff);
+    tmp2 = get_address(s, 0, (insn >> 12) & 0xf, insn & 0xfff);
+
+    LOG_DISAS("disas_e5: insn %" PRIx64 "\n", insn);
+    switch (op) {
+    case 0x01: /* TPROT    D1(B1),D2(B2)  [SSE] */
+        /* Test Protection */
+        potential_page_fault(s);
+        gen_helper_tprot(cc_op, tmp, tmp2);
+        set_cc_static(s);
+        break;
+    default:
+        LOG_DISAS("illegal e5 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+
+    tcg_temp_free_i64(tmp);
+    tcg_temp_free_i64(tmp2);
+}
+#endif
+
+static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2)
+{
+    TCGv_i64 tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2;
+    int i, stm_len;
+    int ilc = 3;
+
+    LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n",
+              op, r1, r3, b2, d2);
+    switch (op) {
+    case 0xc: /* SRLG     R1,R3,D2(B2)     [RSY] */
+    case 0xd: /* SLLG     R1,R3,D2(B2)     [RSY] */
+    case 0xa: /* SRAG     R1,R3,D2(B2)     [RSY] */
+    case 0xb: /* SLAG     R1,R3,D2(B2)     [RSY] */
+    case 0x1c: /* RLLG     R1,R3,D2(B2)     [RSY] */
+        if (b2) {
+            tmp = get_address(s, 0, b2, d2);
+            tcg_gen_andi_i64(tmp, tmp, 0x3f);
+        } else {
+            tmp = tcg_const_i64(d2 & 0x3f);
+        }
+        switch (op) {
+        case 0xc:
+            tcg_gen_shr_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xd:
+            tcg_gen_shl_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xa:
+            tcg_gen_sar_i64(regs[r1], regs[r3], tmp);
+            break;
+        case 0xb:
+            tmp2 = tcg_temp_new_i64();
+            tmp3 = tcg_temp_new_i64();
+            gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp);
+            tcg_gen_shl_i64(tmp2, regs[r3], tmp);
+            /* override sign bit with source sign */
+            tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL);
+            tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL);
+            tcg_gen_or_i64(regs[r1], tmp2, tmp3);
+            tcg_temp_free_i64(tmp2);
+            tcg_temp_free_i64(tmp3);
+            break;
+        case 0x1c:
+            tcg_gen_rotl_i64(regs[r1], regs[r3], tmp);
+            break;
+        default:
+            tcg_abort();
+            break;
+        }
+        if (op == 0xa) {
+            set_cc_s64(s, regs[r1]);
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1d: /* RLL    R1,R3,D2(B2)        [RSY] */
+        if (b2) {
+            tmp = get_address(s, 0, b2, d2);
+            tcg_gen_andi_i64(tmp, tmp, 0x3f);
+        } else {
+            tmp = tcg_const_i64(d2 & 0x3f);
+        }
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r3);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        switch (op) {
+        case 0x1d:
+            tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1);
+            break;
+        default:
+            tcg_abort();
+            break;
+        }
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x4:  /* LMG      R1,R3,D2(B2)     [RSE] */
+    case 0x24: /* STMG     R1,R3,D2(B2)     [RSE] */
+        stm_len = 8;
+        goto do_mh;
+    case 0x26: /* STMH     R1,R3,D2(B2)     [RSE] */
+    case 0x96: /* LMH      R1,R3,D2(B2)     [RSE] */
+        stm_len = 4;
+do_mh:
+        /* Apparently, unrolling lmg/stmg of any size gains performance -
+           even for very long ones... */
+        tmp = get_address(s, 0, b2, d2);
+        tmp3 = tcg_const_i64(stm_len);
+        tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4);
+        for (i = r1;; i = (i + 1) % 16) {
+            switch (op) {
+            case 0x4:
+                tcg_gen_qemu_ld64(regs[i], tmp, get_mem_index(s));
+                break;
+            case 0x96:
+                tmp2 = tcg_temp_new_i64();
+#if HOST_LONG_BITS == 32
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2);
+#else
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_shl_i64(tmp2, tmp2, tmp4);
+                tcg_gen_ext32u_i64(regs[i], regs[i]);
+                tcg_gen_or_i64(regs[i], regs[i], tmp2);
+#endif
+                tcg_temp_free_i64(tmp2);
+                break;
+            case 0x24:
+                tcg_gen_qemu_st64(regs[i], tmp, get_mem_index(s));
+                break;
+            case 0x26:
+                tmp2 = tcg_temp_new_i64();
+                tcg_gen_shr_i64(tmp2, regs[i], tmp4);
+                tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+                tcg_temp_free_i64(tmp2);
+                break;
+            default:
+                tcg_abort();
+            }
+            if (i == r3) {
+                break;
+            }
+            tcg_gen_add_i64(tmp, tmp, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stcmh(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x2f: /* LCTLG     R1,R3,D2(B2)     [RSE] */
+        /* Load Control */
+        check_privileged(s, ilc);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lctlg(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x25: /* STCTG     R1,R3,D2(B2)     [RSE] */
+        /* Store Control */
+        check_privileged(s, ilc);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stctg(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#endif
+    case 0x30: /* CSG     R1,R3,D2(B2)     [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX rewrite in tcg */
+        gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX rewrite in tcg */
+        gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x51: /* TMY D1(B1),I2 [SIY] */
+        tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
+        tmp2 = tcg_const_i64((r1 << 4) | r3);
+        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
+        /* yes, this is a 32 bit operation with 64 bit tcg registers, because
+           that incurs less conversions */
+        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x52: /* MVIY D1(B1),I2 [SIY] */
+        tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
+        tmp2 = tcg_const_i64((r1 << 4) | r3);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x55: /* CLIY D1(B1),I2 [SIY] */
+        tmp3 = get_address(s, 0, b2, d2); /* SIY -> this is the 1st operand */
+        tmp = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld8u(tmp, tmp3, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        cmp_u32c(s, tmp32_1, (r1 << 4) | r3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x80: /* ICMH      R1,M3,D2(B2)     [RSY] */
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        /* XXX split CC calculation out */
+        gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal eb operation 0x%x\n", op);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+}
+
+static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
+                     int r1b)
+{
+    TCGv_i32 tmp_r1, tmp32;
+    TCGv_i64 addr, tmp;
+    addr = get_address(s, x2, b2, d2);
+    tmp_r1 = tcg_const_i32(r1);
+    switch (op) {
+    case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */
+        potential_page_fault(s);
+        gen_helper_lxdb(tmp_r1, addr);
+        break;
+    case 0x9: /* CEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = load_freg32(r1);
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        set_cc_cmp_f32_i64(s, tmp32, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xa: /* AEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_aeb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+
+        tmp32 = load_freg32(r1);
+        set_cc_nz_f32(s, tmp32);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xb: /* SEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_seb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+
+        tmp32 = load_freg32(r1);
+        set_cc_nz_f32(s, tmp32);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0xd: /* DEB    R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_deb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0x10: /* TCEB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tceb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x11: /* TCDB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tcdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x12: /* TCXB   R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_tcxb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x17: /* MEEB   R1,D2(X2,B2)       [RXE] */
+        tmp = tcg_temp_new_i64();
+        tmp32 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        gen_helper_meeb(tmp_r1, tmp32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32);
+        break;
+    case 0x19: /* CDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_cdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1a: /* ADB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_adb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1b: /* SDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_sdb(cc_op, tmp_r1, addr);
+        set_cc_static(s);
+        break;
+    case 0x1c: /* MDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_mdb(tmp_r1, addr);
+        break;
+    case 0x1d: /* DDB    R1,D2(X2,B2)       [RXE] */
+        potential_page_fault(s);
+        gen_helper_ddb(tmp_r1, addr);
+        break;
+    case 0x1e: /* MADB  R1,R3,D2(X2,B2) [RXF] */
+        /* for RXF insns, r1 is R3 and r1b is R1 */
+        tmp32 = tcg_const_i32(r1b);
+        potential_page_fault(s);
+        gen_helper_madb(tmp32, addr, tmp_r1);
+        tcg_temp_free_i32(tmp32);
+        break;
+    default:
+        LOG_DISAS("illegal ed operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        return;
+    }
+    tcg_temp_free_i32(tmp_r1);
+    tcg_temp_free_i64(addr);
+}
+
+static void disas_a5(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2;
+    TCGv_i32 tmp32;
+    LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2);
+    switch (op) {
+    case 0x0: /* IIHH     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1: /* IIHL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x2: /* IILH     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x3: /* IILL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* NIHH     R1,I2     [RI] */
+    case 0x8: /* OIHH     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x4:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 48)
+                               | 0x0000ffffffffffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x8:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 48);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp2, tmp, 48);
+        tcg_gen_trunc_i64_i32(tmp32, tmp2);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x5: /* NIHL     R1,I2     [RI] */
+    case 0x9: /* OIHL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x5:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 32)
+                               | 0xffff0000ffffffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x9:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 32);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp2, tmp, 32);
+        tcg_gen_trunc_i64_i32(tmp32, tmp2);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x6: /* NILH     R1,I2     [RI] */
+    case 0xa: /* OILH     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x6:
+            tmp2 = tcg_const_i64((((uint64_t)i2) << 16)
+                               | 0xffffffff0000ffffULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0xa:
+            tmp2 = tcg_const_i64(((uint64_t)i2) << 16);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp, tmp, 16);
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x7: /* NILL     R1,I2     [RI] */
+    case 0xb: /* OILL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp32 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x7:
+            tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL);
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0xb:
+            tmp2 = tcg_const_i64(i2);
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32, tmp);
+        tcg_gen_andi_i32(tmp32, tmp32, 0xffff);
+        set_cc_nz_u32(s, tmp32);        /* signedness should not matter here */
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xc: /* LLIHH     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 48 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xd: /* LLIHL     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 32 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* LLILH     R1,I2     [RI] */
+        tmp = tcg_const_i64( ((uint64_t)i2) << 16 );
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xf: /* LLILL     R1,I2     [RI] */
+        tmp = tcg_const_i64(i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal a5 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        return;
+    }
+}
+
+static void disas_a7(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    int l1;
+
+    LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2);
+    switch (op) {
+    case 0x0: /* TMLH or TMH     R1,I2     [RI] */
+    case 0x1: /* TMLL or TML     R1,I2     [RI] */
+    case 0x2: /* TMHH     R1,I2     [RI] */
+    case 0x3: /* TMHL     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64((uint16_t)i2);
+        switch (op) {
+        case 0x0:
+            tcg_gen_shri_i64(tmp, tmp, 16);
+            break;
+        case 0x1:
+            break;
+        case 0x2:
+            tcg_gen_shri_i64(tmp, tmp, 48);
+            break;
+        case 0x3:
+            tcg_gen_shri_i64(tmp, tmp, 32);
+            break;
+        }
+        tcg_gen_andi_i64(tmp, tmp, 0xffff);
+        cmp_64(s, tmp, tmp2, CC_OP_TM_64);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4: /* brc m1, i2 */
+        gen_brc(r1, s, i2 * 2LL);
+        return;
+    case 0x5: /* BRAS     R1,I2     [RI] */
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 4));
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        gen_goto_tb(s, 0, s->pc + i2 * 2LL);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x6: /* BRCT     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1);
+        gen_goto_tb(s, 0, s->pc + (i2 * 2LL));
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 4);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x7: /* BRCTG     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tcg_gen_subi_i64(tmp, tmp, 1);
+        store_reg(r1, tmp);
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1);
+        gen_goto_tb(s, 0, s->pc + (i2 * 2LL));
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 4);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x8: /* lhi r1, i2 */
+        tmp32_1 = tcg_const_i32(i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x9: /* lghi r1, i2 */
+        tmp = tcg_const_i64(i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa: /* AHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_const_i32(i2);
+
+        if (i2 < 0) {
+            tcg_gen_subi_i32(tmp32_2, tmp32_1, -i2);
+        } else {
+            tcg_gen_add_i32(tmp32_2, tmp32_1, tmp32_3);
+        }
+
+        store_reg32(r1, tmp32_2);
+        set_cc_add32(s, tmp32_1, tmp32_3, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xb: /* aghi r1, i2 */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64(i2);
+
+        if (i2 < 0) {
+            tcg_gen_subi_i64(regs[r1], tmp, -i2);
+        } else {
+            tcg_gen_add_i64(regs[r1], tmp, tmp2);
+        }
+        set_cc_add64(s, tmp, tmp2, regs[r1]);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xc: /* MHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_muli_i32(tmp32_1, tmp32_1, i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xd: /* MGHI     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        tcg_gen_muli_i64(tmp, tmp, i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* CHI     R1,I2     [RI] */
+        tmp32_1 = load_reg32(r1);
+        cmp_s32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xf: /* CGHI     R1,I2     [RI] */
+        tmp = load_reg(r1);
+        cmp_s64c(s, tmp, i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal a7 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        return;
+    }
+}
+
+static void disas_b2(DisasContext *s, int op, uint32_t insn)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    int r1, r2;
+    int ilc = 2;
+#ifndef CONFIG_USER_ONLY
+    int r3, d2, b2;
+#endif
+
+    r1 = (insn >> 4) & 0xf;
+    r2 = insn & 0xf;
+
+    LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2);
+
+    switch (op) {
+    case 0x22: /* IPM    R1               [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_ipm(cc_op, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x41: /* CKSM    R1,R2     [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_cksm(tmp32_1, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        gen_op_movi_cc(s, 0);
+        break;
+    case 0x4e: /* SAR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, aregs[r1]));
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x4f: /* EAR     R1,R2     [RRE] */
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, aregs[r2]));
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x52: /* MSR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x54: /* MVPG     R1,R2     [RRE] */
+        tmp = load_reg(0);
+        tmp2 = load_reg(r1);
+        tmp3 = load_reg(r2);
+        potential_page_fault(s);
+        gen_helper_mvpg(tmp, tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        /* XXX check CCO bit and set CC accordingly */
+        gen_op_movi_cc(s, 0);
+        break;
+    case 0x55: /* MVST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        gen_op_movi_cc(s, 1);
+        break;
+    case 0x5d: /* CLST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x5e: /* SRST     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = tcg_const_i32(r1);
+        tmp32_3 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+
+#ifndef CONFIG_USER_ONLY
+    case 0x02: /* STIDP     D2(B2)     [S] */
+        /* Store CPU ID */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stidp(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x04: /* SCK       D2(B2)     [S] */
+        /* Set Clock */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sck(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x05: /* STCK     D2(B2)     [S] */
+        /* Store Clock */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stck(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x06: /* SCKC     D2(B2)     [S] */
+        /* Set Clock Comparator */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sckc(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x07: /* STCKC    D2(B2)     [S] */
+        /* Store Clock Comparator */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stckc(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x08: /* SPT      D2(B2)     [S] */
+        /* Set CPU Timer */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_spt(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x09: /* STPT     D2(B2)     [S] */
+        /* Store CPU Timer */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stpt(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x0a: /* SPKA     D2(B2)     [S] */
+        /* Set PSW Key from Address */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_andi_i64(tmp2, psw_mask, ~PSW_MASK_KEY);
+        tcg_gen_shli_i64(tmp, tmp, PSW_SHIFT_KEY - 4);
+        tcg_gen_or_i64(psw_mask, tmp2, tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x0d: /* PTLB                [S] */
+        /* Purge TLB */
+        check_privileged(s, ilc);
+        gen_helper_ptlb();
+        break;
+    case 0x10: /* SPX      D2(B2)     [S] */
+        /* Set Prefix Register */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_spx(tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x11: /* STPX     D2(B2)     [S] */
+        /* Store Prefix */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tmp2, cpu_env, offsetof(CPUState, psa));
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x12: /* STAP     D2(B2)     [S] */
+        /* Store CPU Address */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, cpu_num));
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x21: /* IPTE     R1,R2      [RRE] */
+        /* Invalidate PTE */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        gen_helper_ipte(tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x29: /* ISKE     R1,R2      [RRE] */
+        /* Insert Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp = load_reg(r2);
+        tmp2 = tcg_temp_new_i64();
+        gen_helper_iske(tmp2, tmp);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x2a: /* RRBE     R1,R2      [RRE] */
+        /* Set Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        gen_helper_rrbe(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x2b: /* SSKE     R1,R2      [RRE] */
+        /* Set Storage Key Extended */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        gen_helper_sske(tmp32_1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x34: /* STCH ? */
+        /* Store Subchannel */
+        check_privileged(s, ilc);
+        gen_op_movi_cc(s, 3);
+        break;
+    case 0x46: /* STURA    R1,R2      [RRE] */
+        /* Store Using Real Address */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = load_reg32(r1);
+        tmp = load_reg(r2);
+        potential_page_fault(s);
+        gen_helper_stura(tmp, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x50: /* CSP      R1,R2      [RRE] */
+        /* Compare And Swap And Purge */
+        check_privileged(s, ilc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        gen_helper_csp(cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5f: /* CHSC ? */
+        /* Channel Subsystem Call */
+        check_privileged(s, ilc);
+        gen_op_movi_cc(s, 3);
+        break;
+    case 0x78: /* STCKE    D2(B2)     [S] */
+        /* Store Clock Extended */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_stcke(cc_op, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x79: /* SACF    D2(B2)     [S] */
+        /* Store Clock Extended */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        potential_page_fault(s);
+        gen_helper_sacf(tmp);
+        tcg_temp_free_i64(tmp);
+        /* addressing mode has changed, so end the block */
+        s->pc += ilc * 2;
+        update_psw_addr(s);
+        s->is_jmp = DISAS_EXCP;
+        break;
+    case 0x7d: /* STSI     D2,(B2)     [S] */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(0);
+        tmp32_2 = load_reg32(1);
+        potential_page_fault(s);
+        gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x9d: /* LFPC      D2(B2)   [S] */
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xb1: /* STFL     D2(B2)     [S] */
+        /* Store Facility List (CPU features) at 200 */
+        check_privileged(s, ilc);
+        tmp2 = tcg_const_i64(0xc0000000);
+        tmp = tcg_const_i64(200);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xb2: /* LPSWE    D2(B2)     [S] */
+        /* Load PSW Extended */
+        check_privileged(s, ilc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
+        tcg_gen_addi_i64(tmp, tmp, 8);
+        tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s));
+        gen_helper_load_psw(tmp2, tmp3);
+        /* we need to keep cc_op intact */
+        s->is_jmp = DISAS_JUMP;
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x20: /* SERVC     R1,R2     [RRE] */
+        /* SCLP Service call (PV hypercall) */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        tmp32_1 = load_reg32(r2);
+        tmp = load_reg(r1);
+        gen_helper_servc(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+#endif
+    default:
+        LOG_DISAS("illegal b2 operation 0x%x\n", op);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+}
+
+static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
+{
+    TCGv_i64 tmp;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+    LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2);
+#define FP_HELPER(i) \
+    tmp32_1 = tcg_const_i32(r1); \
+    tmp32_2 = tcg_const_i32(r2); \
+    gen_helper_ ## i (tmp32_1, tmp32_2); \
+    tcg_temp_free_i32(tmp32_1); \
+    tcg_temp_free_i32(tmp32_2);
+
+#define FP_HELPER_CC(i) \
+    tmp32_1 = tcg_const_i32(r1); \
+    tmp32_2 = tcg_const_i32(r2); \
+    gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \
+    set_cc_static(s); \
+    tcg_temp_free_i32(tmp32_1); \
+    tcg_temp_free_i32(tmp32_2);
+
+    switch (op) {
+    case 0x0: /* LPEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpebr);
+        break;
+    case 0x2: /* LTEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltebr);
+        break;
+    case 0x3: /* LCEBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcebr);
+        break;
+    case 0x4: /* LDEBR       R1,R2             [RRE] */
+        FP_HELPER(ldebr);
+        break;
+    case 0x5: /* LXDBR       R1,R2             [RRE] */
+        FP_HELPER(lxdbr);
+        break;
+    case 0x9: /* CEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cebr);
+        break;
+    case 0xa: /* AEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(aebr);
+        break;
+    case 0xb: /* SEBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sebr);
+        break;
+    case 0xd: /* DEBR        R1,R2             [RRE] */
+        FP_HELPER(debr);
+        break;
+    case 0x10: /* LPDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpdbr);
+        break;
+    case 0x12: /* LTDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltdbr);
+        break;
+    case 0x13: /* LCDBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcdbr);
+        break;
+    case 0x15: /* SQBDR       R1,R2             [RRE] */
+        FP_HELPER(sqdbr);
+        break;
+    case 0x17: /* MEEBR       R1,R2             [RRE] */
+        FP_HELPER(meebr);
+        break;
+    case 0x19: /* CDBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cdbr);
+        break;
+    case 0x1a: /* ADBR        R1,R2             [RRE] */
+        FP_HELPER_CC(adbr);
+        break;
+    case 0x1b: /* SDBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sdbr);
+        break;
+    case 0x1c: /* MDBR        R1,R2             [RRE] */
+        FP_HELPER(mdbr);
+        break;
+    case 0x1d: /* DDBR        R1,R2             [RRE] */
+        FP_HELPER(ddbr);
+        break;
+    case 0xe: /* MAEBR  R1,R3,R2 [RRF] */
+    case 0x1e: /* MADBR R1,R3,R2 [RRF] */
+    case 0x1f: /* MSDBR R1,R3,R2 [RRF] */
+        /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */
+        tmp32_1 = tcg_const_i32(m3);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(r1);
+        switch (op) {
+        case 0xe:
+            gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        case 0x1e:
+            gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        case 0x1f:
+            gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x40: /* LPXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lpxbr);
+        break;
+    case 0x42: /* LTXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(ltxbr);
+        break;
+    case 0x43: /* LCXBR       R1,R2             [RRE] */
+        FP_HELPER_CC(lcxbr);
+        break;
+    case 0x44: /* LEDBR       R1,R2             [RRE] */
+        FP_HELPER(ledbr);
+        break;
+    case 0x45: /* LDXBR       R1,R2             [RRE] */
+        FP_HELPER(ldxbr);
+        break;
+    case 0x46: /* LEXBR       R1,R2             [RRE] */
+        FP_HELPER(lexbr);
+        break;
+    case 0x49: /* CXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(cxbr);
+        break;
+    case 0x4a: /* AXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(axbr);
+        break;
+    case 0x4b: /* SXBR        R1,R2             [RRE] */
+        FP_HELPER_CC(sxbr);
+        break;
+    case 0x4c: /* MXBR        R1,R2             [RRE] */
+        FP_HELPER(mxbr);
+        break;
+    case 0x4d: /* DXBR        R1,R2             [RRE] */
+        FP_HELPER(dxbr);
+        break;
+    case 0x65: /* LXR         R1,R2             [RRE] */
+        tmp = load_freg(r2);
+        store_freg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        tmp = load_freg(r2 + 2);
+        store_freg(r1 + 2, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x74: /* LZER        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzer(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x75: /* LZDR        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzdr(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x76: /* LZXR        R1                [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_lzxr(tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x84: /* SFPC        R1                [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x8c: /* EFPC        R1                [RRE] */
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x94: /* CEFBR       R1,R2             [RRE] */
+    case 0x95: /* CDFBR       R1,R2             [RRE] */
+    case 0x96: /* CXFBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = load_reg32(r2);
+        switch (op) {
+        case 0x94:
+            gen_helper_cefbr(tmp32_1, tmp32_2);
+            break;
+        case 0x95:
+            gen_helper_cdfbr(tmp32_1, tmp32_2);
+            break;
+        case 0x96:
+            gen_helper_cxfbr(tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x98: /* CFEBR       R1,R2             [RRE] */
+    case 0x99: /* CFDBR              R1,R2             [RRE] */
+    case 0x9a: /* CFXBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        switch (op) {
+        case 0x98:
+            gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x99:
+            gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x9a:
+            gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xa4: /* CEGBR       R1,R2             [RRE] */
+    case 0xa5: /* CDGBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        switch (op) {
+        case 0xa4:
+            gen_helper_cegbr(tmp32_1, tmp);
+            break;
+        case 0xa5:
+            gen_helper_cdgbr(tmp32_1, tmp);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa6: /* CXGBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        gen_helper_cxgbr(tmp32_1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xa8: /* CGEBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xa9: /* CGDBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xaa: /* CGXBR       R1,R2             [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        tmp32_3 = tcg_const_i32(m3);
+        gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    default:
+        LOG_DISAS("illegal b3 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        break;
+    }
+
+#undef FP_HELPER_CC
+#undef FP_HELPER
+}
+
+static void disas_b9(DisasContext *s, int op, int r1, int r2)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2);
+    switch (op) {
+    case 0x0: /* LPGR     R1,R2     [RRE] */
+    case 0x1: /* LNGR     R1,R2     [RRE] */
+    case 0x2: /* LTGR R1,R2 [RRE] */
+    case 0x3: /* LCGR     R1,R2     [RRE] */
+    case 0x10: /* LPGFR R1,R2 [RRE] */
+    case 0x11: /* LNFGR     R1,R2     [RRE] */
+    case 0x12: /* LTGFR R1,R2 [RRE] */
+    case 0x13: /* LCGFR    R1,R2     [RRE] */
+        if (op & 0x10) {
+            tmp = load_reg32_i64(r2);
+        } else {
+            tmp = load_reg(r2);
+        }
+        switch (op & 0xf) {
+        case 0x0: /* LP?GR */
+            set_cc_abs64(s, tmp);
+            gen_helper_abs_i64(tmp, tmp);
+            store_reg(r1, tmp);
+            break;
+        case 0x1: /* LN?GR */
+            set_cc_nabs64(s, tmp);
+            gen_helper_nabs_i64(tmp, tmp);
+            store_reg(r1, tmp);
+            break;
+        case 0x2: /* LT?GR */
+            if (r1 != r2) {
+                store_reg(r1, tmp);
+            }
+            set_cc_s64(s, tmp);
+            break;
+        case 0x3: /* LC?GR */
+            tcg_gen_neg_i64(regs[r1], tmp);
+            set_cc_comp64(s, regs[r1]);
+            break;
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* LGR R1,R2 [RRE] */
+        store_reg(r1, regs[r2]);
+        break;
+    case 0x6: /* LGBR R1,R2 [RRE] */
+        tmp2 = load_reg(r2);
+        tcg_gen_ext8s_i64(tmp2, tmp2);
+        store_reg(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x8: /* AGR     R1,R2     [RRE] */
+    case 0xa: /* ALGR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x8:
+            set_cc_add64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xa:
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x9: /* SGR     R1,R2     [RRE] */
+    case 0xb: /* SLGR     R1,R2     [RRE] */
+    case 0x1b: /* SLGFR     R1,R2     [RRE] */
+    case 0x19: /* SGFR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        switch (op) {
+        case 0x1b:
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+            break;
+        case 0x19:
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+            break;
+        default:
+            tmp2 = load_reg(r2);
+            break;
+        }
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_sub_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        switch (op) {
+        case 0x9:
+        case 0x19:
+            set_cc_sub64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xb:
+        case 0x1b:
+            set_cc_subu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0xc: /* MSGR      R1,R2     [RRE] */
+    case 0x1c: /* MSGFR      R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        if (op == 0x1c) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        tcg_gen_mul_i64(tmp, tmp, tmp2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xd: /* DSGR      R1,R2     [RRE] */
+    case 0x1d: /* DSGFR      R1,R2     [RRE] */
+        tmp = load_reg(r1 + 1);
+        if (op == 0xd) {
+            tmp2 = load_reg(r2);
+        } else {
+            tmp32_1 = load_reg32(r2);
+            tmp2 = tcg_temp_new_i64();
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+            tcg_temp_free_i32(tmp32_1);
+        }
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        store_reg(r1 + 1, tmp3);
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x14: /* LGFR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_ext_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x16: /* LLGFR      R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x17: /* LLGTR      R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0x7fffffffUL);
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        store_reg(r1, tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x18: /* AGFR     R1,R2     [RRE] */
+    case 0x1a: /* ALGFR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp2 = tcg_temp_new_i64();
+        if (op == 0x18) {
+            tcg_gen_ext_i32_i64(tmp2, tmp32_1);
+        } else {
+            tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tmp = load_reg(r1);
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_add_i64(tmp3, tmp, tmp2);
+        store_reg(r1, tmp3);
+        if (op == 0x18) {
+            set_cc_add64(s, tmp, tmp2, tmp3);
+        } else {
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x0f: /* LRVGR    R1,R2     [RRE] */
+        tcg_gen_bswap64_i64(regs[r1], regs[r2]);
+        break;
+    case 0x1f: /* LRVR     R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x20: /* CGR      R1,R2     [RRE] */
+    case 0x30: /* CGFR     R1,R2     [RRE] */
+        tmp2 = load_reg(r2);
+        if (op == 0x30) {
+            tcg_gen_ext32s_i64(tmp2, tmp2);
+        }
+        tmp = load_reg(r1);
+        cmp_s64(s, tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x21: /* CLGR     R1,R2     [RRE] */
+    case 0x31: /* CLGFR    R1,R2     [RRE] */
+        tmp2 = load_reg(r2);
+        if (op == 0x31) {
+            tcg_gen_ext32u_i64(tmp2, tmp2);
+        }
+        tmp = load_reg(r1);
+        cmp_u64(s, tmp, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x26: /* LBR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_ext8s_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x27: /* LHR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_ext16s_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x80: /* NGR R1,R2 [RRE] */
+    case 0x81: /* OGR R1,R2 [RRE] */
+    case 0x82: /* XGR R1,R2 [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        switch (op) {
+        case 0x80:
+            tcg_gen_and_i64(tmp, tmp, tmp2);
+            break;
+        case 0x81:
+            tcg_gen_or_i64(tmp, tmp, tmp2);
+            break;
+        case 0x82:
+            tcg_gen_xor_i64(tmp, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp);
+        set_cc_nz_u64(s, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x83: /* FLOGR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tmp32_1 = tcg_const_i32(r1);
+        gen_helper_flogr(cc_op, tmp32_1, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x84: /* LLGCR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tcg_gen_andi_i64(tmp, tmp, 0xff);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x85: /* LLGHR R1,R2 [RRE] */
+        tmp = load_reg(r2);
+        tcg_gen_andi_i64(tmp, tmp, 0xffff);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x87: /* DLGR      R1,R2     [RRE] */
+        tmp32_1 = tcg_const_i32(r1);
+        tmp = load_reg(r2);
+        gen_helper_dlg(tmp32_1, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x88: /* ALCGR     R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = tcg_temp_new_i64();
+        gen_op_calc_cc(s);
+        tcg_gen_extu_i32_i64(tmp3, cc_op);
+        tcg_gen_shri_i64(tmp3, tmp3, 1);
+        tcg_gen_andi_i64(tmp3, tmp3, 1);
+        tcg_gen_add_i64(tmp3, tmp2, tmp3);
+        tcg_gen_add_i64(tmp3, tmp, tmp3);
+        store_reg(r1, tmp3);
+        set_cc_addu64(s, tmp, tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x89: /* SLBGR   R1,R2     [RRE] */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp32_1 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x94: /* LLCR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xff);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x95: /* LLHR R1,R2 [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xffff);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x96: /* MLR     R1,R2     [RRE] */
+        /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x97: /* DLR     R1,R2     [RRE] */
+        /* reg(r1) = reg(r1, r1+1) % reg(r2) */
+        /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */
+        tmp = load_reg(r1);
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32u_i64(tmp2, tmp2);
+        tcg_gen_ext32u_i64(tmp3, tmp3);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp3);
+
+        tcg_gen_rem_i64(tmp3, tmp, tmp2);
+        tcg_gen_div_i64(tmp, tmp, tmp2);
+        store_reg32_i64((r1 + 1) & 15, tmp);
+        store_reg32_i64(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x98: /* ALCR    R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        /* XXX possible optimization point */
+        gen_op_calc_cc(s);
+        gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
+        set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x99: /* SLBR    R1,R2     [RRE] */
+        tmp32_1 = load_reg32(r2);
+        tmp32_2 = tcg_const_i32(r1);
+        gen_op_calc_cc(s);
+        gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    default:
+        LOG_DISAS("illegal b9 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 2);
+        break;
+    }
+}
+
+static void disas_c0(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp;
+    TCGv_i32 tmp32_1, tmp32_2;
+    uint64_t target = s->pc + i2 * 2LL;
+    int l1;
+
+    LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2);
+
+    switch (op) {
+    case 0: /* larl r1, i2 */
+        tmp = tcg_const_i64(target);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x1: /* LGFI R1,I2 [RIL] */
+        tmp = tcg_const_i64((int64_t)i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x4: /* BRCL     M1,I2     [RIL] */
+        /* m1 & (1 << (3 - cc)) */
+        tmp32_1 = tcg_const_i32(3);
+        tmp32_2 = tcg_const_i32(1);
+        gen_op_calc_cc(s);
+        tcg_gen_sub_i32(tmp32_1, tmp32_1, cc_op);
+        tcg_gen_shl_i32(tmp32_2, tmp32_2, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tmp32_1 = tcg_const_i32(r1); /* m1 == r1 */
+        tcg_gen_and_i32(tmp32_1, tmp32_1, tmp32_2);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1);
+        gen_goto_tb(s, 0, target);
+        gen_set_label(l1);
+        gen_goto_tb(s, 1, s->pc + 6);
+        s->is_jmp = DISAS_TB_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5: /* brasl r1, i2 */
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 6));
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        gen_goto_tb(s, 0, target);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x7: /* XILF R1,I2 [RIL] */
+    case 0xb: /* NILF R1,I2 [RIL] */
+    case 0xd: /* OILF R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        switch (op) {
+        case 0x7:
+            tcg_gen_xori_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        case 0xb:
+            tcg_gen_andi_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        case 0xd:
+            tcg_gen_ori_i32(tmp32_1, tmp32_1, (uint32_t)i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x9: /* IILF R1,I2 [RIL] */
+        tmp32_1 = tcg_const_i32((uint32_t)i2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xa: /* NIHF R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32)
+                                   | 0xffffffffULL);
+        store_reg(r1, tmp);
+        tcg_gen_shri_i64(tmp, tmp, 32);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xe: /* LLIHF R1,I2 [RIL] */
+        tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xf: /* LLILF R1,I2 [RIL] */
+        tmp = tcg_const_i64((uint32_t)i2);
+        store_reg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    default:
+        LOG_DISAS("illegal c0 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+}
+
+static void disas_c2(DisasContext *s, int op, int r1, int i2)
+{
+    TCGv_i64 tmp, tmp2, tmp3;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
+
+    switch (op) {
+    case 0x4: /* SLGFI R1,I2 [RIL] */
+    case 0xa: /* ALGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2);
+        tmp3 = tcg_temp_new_i64();
+        switch (op) {
+        case 0x4:
+            tcg_gen_sub_i64(tmp3, tmp, tmp2);
+            set_cc_subu64(s, tmp, tmp2, tmp3);
+            break;
+        case 0xa:
+            tcg_gen_add_i64(tmp3, tmp, tmp2);
+            set_cc_addu64(s, tmp, tmp2, tmp3);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg(r1, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5: /* SLFI R1,I2 [RIL] */
+    case 0xb: /* ALFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(i2);
+        tmp32_3 = tcg_temp_new_i32();
+        switch (op) {
+        case 0x5:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0xb:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xc: /* CGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        cmp_s64c(s, tmp, (int64_t)i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* CLGFI R1,I2 [RIL] */
+        tmp = load_reg(r1);
+        cmp_u64c(s, tmp, (uint64_t)(uint32_t)i2);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xd: /* CFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        cmp_s32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xf: /* CLFI R1,I2 [RIL] */
+        tmp32_1 = load_reg32(r1);
+        cmp_u32c(s, tmp32_1, i2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    default:
+        LOG_DISAS("illegal c2 operation 0x%x\n", op);
+        gen_illegal_opcode(s, 3);
+        break;
+    }
+}
+
+static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2)
+{
+    switch (opc & 0xf) {
+    case 0x4:
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        break;
+    case 0x6:
+        tcg_gen_or_i32(tmp, tmp, tmp2);
+        break;
+    case 0x7:
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void disas_s390_insn(DisasContext *s)
+{
+    TCGv_i64 tmp, tmp2, tmp3, tmp4;
+    TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4;
+    unsigned char opc;
+    uint64_t insn;
+    int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b;
+    TCGv_i32 vl;
+    int ilc;
+    int l1;
+
+    opc = ldub_code(s->pc);
+    LOG_DISAS("opc 0x%x\n", opc);
+
+    ilc = get_ilc(opc);
+
+    switch (opc) {
+#ifndef CONFIG_USER_ONLY
+    case 0x01: /* SAM */
+        insn = ld_code2(s->pc);
+        /* set addressing mode, but we only do 64bit anyways */
+        break;
+#endif
+    case 0x6: /* BCTR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+
+        if (r2) {
+            gen_update_cc_op(s);
+            l1 = gen_new_label();
+            tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1);
+
+            /* not taking the branch, jump to after the instruction */
+            gen_goto_tb(s, 0, s->pc + 2);
+            gen_set_label(l1);
+
+            /* take the branch, move R2 into psw.addr */
+            tmp32_1 = load_reg32(r2);
+            tmp = tcg_temp_new_i64();
+            tcg_gen_extu_i32_i64(tmp, tmp32_1);
+            tcg_gen_mov_i64(psw_addr, tmp);
+            s->is_jmp = DISAS_JUMP;
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i64(tmp);
+        }
+        break;
+    case 0x7: /* BCR    M1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        if (r2) {
+            tmp = load_reg(r2);
+            gen_bcr(s, r1, tmp, s->pc);
+            tcg_temp_free_i64(tmp);
+            s->is_jmp = DISAS_TB_JUMP;
+        } else {
+            /* XXX: "serialization and checkpoint-synchronization function"? */
+        }
+        break;
+    case 0xa: /* SVC    I         [RR] */
+        insn = ld_code2(s->pc);
+        debug_insn(insn);
+        i = insn & 0xff;
+        update_psw_addr(s);
+        gen_op_calc_cc(s);
+        tmp32_1 = tcg_const_i32(i);
+        tmp32_2 = tcg_const_i32(ilc * 2);
+        tmp32_3 = tcg_const_i32(EXCP_SVC);
+        tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUState, int_svc_code));
+        tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUState, int_svc_ilc));
+        gen_helper_exception(tmp32_3);
+        s->is_jmp = DISAS_EXCP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0xd: /* BASR   R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2));
+        store_reg(r1, tmp);
+        if (r2) {
+            tmp2 = load_reg(r2);
+            tcg_gen_mov_i64(psw_addr, tmp2);
+            tcg_temp_free_i64(tmp2);
+            s->is_jmp = DISAS_JUMP;
+        }
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0xe: /* MVCL   R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r2);
+        potential_page_fault(s);
+        gen_helper_mvcl(cc_op, tmp32_1, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x10: /* LPR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        set_cc_abs32(s, tmp32_1);
+        gen_helper_abs_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x11: /* LNR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        set_cc_nabs32(s, tmp32_1);
+        gen_helper_nabs_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x12: /* LTR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        if (r1 != r2) {
+            store_reg32(r1, tmp32_1);
+        }
+        set_cc_s32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x13: /* LCR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        tcg_gen_neg_i32(tmp32_1, tmp32_1);
+        store_reg32(r1, tmp32_1);
+        set_cc_comp32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x14: /* NR     R1,R2     [RR] */
+    case 0x16: /* OR     R1,R2     [RR] */
+    case 0x17: /* XR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_2 = load_reg32(r2);
+        tmp32_1 = load_reg32(r1);
+        gen_and_or_xor_i32(opc, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x18: /* LR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x15: /* CLR    R1,R2     [RR] */
+    case 0x19: /* CR     R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        if (opc == 0x15) {
+            cmp_u32(s, tmp32_1, tmp32_2);
+        } else {
+            cmp_s32(s, tmp32_1, tmp32_2);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x1a: /* AR     R1,R2     [RR] */
+    case 0x1e: /* ALR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_3);
+        if (opc == 0x1a) {
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+        } else {
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x1b: /* SR     R1,R2     [RR] */
+    case 0x1f: /* SLR    R1,R2     [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r2);
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_3);
+        if (opc == 0x1b) {
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+        } else {
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+        }
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x1c: /* MR     R1,R2     [RR] */
+        /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp2 = load_reg(r2);
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32s_i64(tmp2, tmp2);
+        tcg_gen_ext32s_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x1d: /* DR     R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+        tmp32_3 = load_reg32(r2);
+
+        tmp = tcg_temp_new_i64(); /* dividend */
+        tmp2 = tcg_temp_new_i64(); /* divisor */
+        tmp3 = tcg_temp_new_i64();
+
+        /* dividend is r(r1 << 32) | r(r1 + 1) */
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_2);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp2);
+
+        /* divisor is r(r2) */
+        tcg_gen_ext_i32_i64(tmp2, tmp32_3);
+
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        tcg_gen_rem_i64(tmp, tmp, tmp2);
+
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp3);
+
+        store_reg32(r1, tmp32_1); /* remainder */
+        store_reg32(r1 + 1, tmp32_2); /* quotient */
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x28: /* LDR    R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp = load_freg(r2);
+        store_freg(r1, tmp);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x38: /* LER    R1,R2               [RR] */
+        insn = ld_code2(s->pc);
+        decode_rr(s, insn, &r1, &r2);
+        tmp32_1 = load_freg32(r2);
+        store_freg32(r1, tmp32_1);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x40: /* STH    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x41:        /* la */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x42: /* STC    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x43: /* IC     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        store_reg8(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x44: /* EX     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tmp3 = tcg_const_i64(s->pc + 4);
+        update_psw_addr(s);
+        gen_op_calc_cc(s);
+        gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x46: /* BCT    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tcg_temp_free_i64(tmp);
+
+        tmp32_1 = load_reg32(r1);
+        tcg_gen_subi_i32(tmp32_1, tmp32_1, 1);
+        store_reg32(r1, tmp32_1);
+
+        gen_update_cc_op(s);
+        l1 = gen_new_label();
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1);
+
+        /* not taking the branch, jump to after the instruction */
+        gen_goto_tb(s, 0, s->pc + 4);
+        gen_set_label(l1);
+
+        /* take the branch, move R2 into psw.addr */
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tcg_gen_mov_i64(psw_addr, tmp);
+        s->is_jmp = DISAS_JUMP;
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp);
+        break;
+    case 0x47: /* BC     M1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        gen_bcr(s, r1, tmp, s->pc + 4);
+        tcg_temp_free_i64(tmp);
+        s->is_jmp = DISAS_TB_JUMP;
+        break;
+    case 0x48: /* LH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x49: /* CH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        cmp_s32(s, tmp32_1, tmp32_2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4a: /* AH     R1,D2(X2,B2)     [RX] */
+    case 0x4b: /* SH     R1,D2(X2,B2)     [RX] */
+    case 0x4c: /* MH     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+
+        tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        switch (opc) {
+        case 0x4a:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x4b:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x4c:
+            tcg_gen_mul_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x4d: /* BAS    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4));
+        store_reg(r1, tmp2);
+        tcg_gen_mov_i64(psw_addr, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        s->is_jmp = DISAS_JUMP;
+        break;
+    case 0x4e: /* CVD    R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp32_1, regs[r1]);
+        gen_helper_cvd(tmp2, tmp32_1);
+        tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x50: /* st r1, d2(x2, b2) */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_reg(r1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x55: /* CL     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r1);
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        cmp_u32(s, tmp32_2, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x54: /* N      R1,D2(X2,B2)     [RX] */
+    case 0x56: /* O      R1,D2(X2,B2)     [RX] */
+    case 0x57: /* X      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        gen_and_or_xor_i32(opc, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        set_cc_nz_u32(s, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x58: /* l r1, d2(x2, b2) */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x59: /* C      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tmp32_2 = load_reg32(r1);
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        cmp_s32(s, tmp32_2, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x5a: /* A      R1,D2(X2,B2)     [RX] */
+    case 0x5b: /* S      R1,D2(X2,B2)     [RX] */
+    case 0x5e: /* AL     R1,D2(X2,B2)     [RX] */
+    case 0x5f: /* SL     R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tmp32_3 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp);
+        switch (opc) {
+        case 0x5a:
+        case 0x5e:
+            tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        case 0x5b:
+        case 0x5f:
+            tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_3);
+        switch (opc) {
+        case 0x5a:
+            set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5e:
+            set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5b:
+            set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        case 0x5f:
+            set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i32(tmp32_3);
+        break;
+    case 0x5c: /* M      R1,D2(X2,B2)        [RX] */
+        /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tmp3 = load_reg((r1 + 1) & 15);
+        tcg_gen_ext32s_i64(tmp2, tmp2);
+        tcg_gen_ext32s_i64(tmp3, tmp3);
+        tcg_gen_mul_i64(tmp2, tmp2, tmp3);
+        store_reg32_i64((r1 + 1) & 15, tmp2);
+        tcg_gen_shri_i64(tmp2, tmp2, 32);
+        store_reg32_i64(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x5d: /* D      R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+
+        tmp = tcg_temp_new_i64();
+        tmp2 = tcg_temp_new_i64();
+
+        /* dividend is r(r1 << 32) | r(r1 + 1) */
+        tcg_gen_extu_i32_i64(tmp, tmp32_1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_2);
+        tcg_gen_shli_i64(tmp, tmp, 32);
+        tcg_gen_or_i64(tmp, tmp, tmp2);
+
+        /* divisor is in memory */
+        tcg_gen_qemu_ld32s(tmp2, tmp3, get_mem_index(s));
+
+        /* XXX divisor == 0 -> FixP divide exception */
+
+        tcg_gen_div_i64(tmp3, tmp, tmp2);
+        tcg_gen_rem_i64(tmp, tmp, tmp2);
+
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp3);
+
+        store_reg32(r1, tmp32_1); /* remainder */
+        store_reg32(r1 + 1, tmp32_2); /* quotient */
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x60: /* STD    R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = load_freg(r1);
+        tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x68: /* LD    R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
+        store_freg(r1, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x70: /* STE R1,D2(X2,B2) [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_freg32(r1);
+        tcg_gen_extu_i32_i64(tmp2, tmp32_1);
+        tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0x71: /* MS      R1,D2(X2,B2)     [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2);
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x78: /* LE     R1,D2(X2,B2)        [RX] */
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp2);
+        store_freg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x80: /* SSM      D2(B2)       [S] */
+        /* Set System Mask */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_andi_i64(tmp3, psw_mask, ~0xff00000000000000ULL);
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_shli_i64(tmp2, tmp2, 56);
+        tcg_gen_or_i64(psw_mask, tmp3, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+    case 0x82: /* LPSW     D2(B2)       [S] */
+        /* Load PSW */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+        tcg_gen_addi_i64(tmp, tmp, 4);
+        tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s));
+        gen_helper_load_psw(tmp2, tmp3);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        /* we need to keep cc_op intact */
+        s->is_jmp = DISAS_JUMP;
+        break;
+    case 0x83: /* DIAG     R1,R3,D2     [RS] */
+        /* Diagnose call (KVM hypercall) */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp32_1 = tcg_const_i32(insn & 0xfff);
+        tmp2 = load_reg(2);
+        tmp3 = load_reg(1);
+        gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3);
+        store_reg(2, tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+#endif
+    case 0x88: /* SRL    R1,D2(B2)        [RS] */
+    case 0x89: /* SLL    R1,D2(B2)        [RS] */
+    case 0x8a: /* SRA    R1,D2(B2)        [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_temp_new_i32();
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp);
+        tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f);
+        switch (opc) {
+        case 0x88:
+            tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2);
+            break;
+        case 0x89:
+            tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2);
+            break;
+        case 0x8a:
+            tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2);
+            set_cc_s32(s, tmp32_1);
+            break;
+        default:
+            tcg_abort();
+        }
+        store_reg32(r1, tmp32_1);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x8c: /* SRDL   R1,D2(B2)        [RS] */
+    case 0x8d: /* SLDL   R1,D2(B2)        [RS] */
+    case 0x8e: /* SRDA   R1,D2(B2)        [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2); /* shift */
+        tmp2 = tcg_temp_new_i64();
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = load_reg32(r1 + 1);
+        tcg_gen_concat_i32_i64(tmp2, tmp32_2, tmp32_1); /* operand */
+        switch (opc) {
+        case 0x8c:
+            tcg_gen_shr_i64(tmp2, tmp2, tmp);
+            break;
+        case 0x8d:
+            tcg_gen_shl_i64(tmp2, tmp2, tmp);
+            break;
+        case 0x8e:
+            tcg_gen_sar_i64(tmp2, tmp2, tmp);
+            set_cc_s64(s, tmp2);
+            break;
+        }
+        tcg_gen_shri_i64(tmp, tmp2, 32);
+        tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+        store_reg32(r1, tmp32_1);
+        tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+        store_reg32(r1 + 1, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x98: /* LM     R1,R3,D2(B2)     [RS] */
+    case 0x90: /* STM    R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = tcg_temp_new_i64();
+        tmp3 = tcg_const_i64(4);
+        tmp4 = tcg_const_i64(0xffffffff00000000ULL);
+        for (i = r1;; i = (i + 1) % 16) {
+            if (opc == 0x98) {
+                tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
+                tcg_gen_and_i64(regs[i], regs[i], tmp4);
+                tcg_gen_or_i64(regs[i], regs[i], tmp2);
+            } else {
+                tcg_gen_qemu_st32(regs[i], tmp, get_mem_index(s));
+            }
+            if (i == r3) {
+                break;
+            }
+            tcg_gen_add_i64(tmp, tmp, tmp3);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        tcg_temp_free_i64(tmp4);
+        break;
+    case 0x91: /* TM     D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_const_i64(i2);
+        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
+        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x92: /* MVI    D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_const_i64(i2);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x94: /* NI     D1(B1),I2        [SI] */
+    case 0x96: /* OI     D1(B1),I2        [SI] */
+    case 0x97: /* XI     D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        switch (opc) {
+        case 0x94:
+            tcg_gen_andi_i64(tmp2, tmp2, i2);
+            break;
+        case 0x96:
+            tcg_gen_ori_i64(tmp2, tmp2, i2);
+            break;
+        case 0x97:
+            tcg_gen_xori_i64(tmp2, tmp2, i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        set_cc_nz_u64(s, tmp2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x95: /* CLI    D1(B1),I2        [SI] */
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+        cmp_u64c(s, tmp2, i2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0x9a: /* LAM      R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lam(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0x9b: /* STAM     R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stam(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xa5:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 20) & 0xf;
+        op = (insn >> 16) & 0xf;
+        i2 = insn & 0xffff;
+        disas_a5(s, op, r1, i2);
+        break;
+    case 0xa7:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 20) & 0xf;
+        op = (insn >> 16) & 0xf;
+        i2 = (short)insn;
+        disas_a7(s, op, r1, i2);
+        break;
+    case 0xa8: /* MVCLE   R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xa9: /* CLCLE   R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xac: /* STNSM   D1(B1),I2     [SI] */
+    case 0xad: /* STOSM   D1(B1),I2     [SI] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        tmp = decode_si(s, insn, &i2, &b1, &d1);
+        tmp2 = tcg_temp_new_i64();
+        tcg_gen_shri_i64(tmp2, psw_mask, 56);
+        tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s));
+        if (opc == 0xac) {
+            tcg_gen_andi_i64(psw_mask, psw_mask,
+                    ((uint64_t)i2 << 56) | 0x00ffffffffffffffULL);
+        } else {
+            tcg_gen_ori_i64(psw_mask, psw_mask, (uint64_t)i2 << 56);
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+    case 0xae: /* SIGP   R1,R3,D2(B2)     [RS] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp2 = load_reg(r3);
+        tmp32_1 = tcg_const_i32(r1);
+        potential_page_fault(s);
+        gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+    case 0xb1: /* LRA    R1,D2(X2, B2)     [RX] */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
+        tmp32_1 = tcg_const_i32(r1);
+        potential_page_fault(s);
+        gen_helper_lra(cc_op, tmp, tmp32_1);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        break;
+#endif
+    case 0xb2:
+        insn = ld_code4(s->pc);
+        op = (insn >> 16) & 0xff;
+        switch (op) {
+        case 0x9c: /* STFPC    D2(B2) [S] */
+            d2 = insn & 0xfff;
+            b2 = (insn >> 12) & 0xf;
+            tmp32_1 = tcg_temp_new_i32();
+            tmp = tcg_temp_new_i64();
+            tmp2 = get_address(s, 0, b2, d2);
+            tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUState, fpc));
+            tcg_gen_extu_i32_i64(tmp, tmp32_1);
+            tcg_gen_qemu_st32(tmp, tmp2, get_mem_index(s));
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i64(tmp2);
+            break;
+        default:
+            disas_b2(s, op, insn);
+            break;
+        }
+        break;
+    case 0xb3:
+        insn = ld_code4(s->pc);
+        op = (insn >> 16) & 0xff;
+        r3 = (insn >> 12) & 0xf; /* aka m3 */
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        disas_b3(s, op, r3, r1, r2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xb6: /* STCTL     R1,R3,D2(B2)     [RS] */
+        /* Store Control */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stctl(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xb7: /* LCTL      R1,R3,D2(B2)     [RS] */
+        /* Load Control */
+        check_privileged(s, ilc);
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_lctl(tmp32_1, tmp, tmp32_2);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+#endif
+    case 0xb9:
+        insn = ld_code4(s->pc);
+        r1 = (insn >> 4) & 0xf;
+        r2 = insn & 0xf;
+        op = (insn >> 16) & 0xff;
+        disas_b9(s, op, r1, r2);
+        break;
+    case 0xba: /* CS     R1,R3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = tcg_const_i32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbd: /* CLM    R1,M3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp);
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbe: /* STCM R1,M3,D2(B2) [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        tmp = get_address(s, 0, b2, d2);
+        tmp32_1 = load_reg32(r1);
+        tmp32_2 = tcg_const_i32(r3);
+        potential_page_fault(s);
+        gen_helper_stcm(tmp32_1, tmp32_2, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i32(tmp32_1);
+        tcg_temp_free_i32(tmp32_2);
+        break;
+    case 0xbf: /* ICM    R1,M3,D2(B2)     [RS] */
+        insn = ld_code4(s->pc);
+        decode_rs(s, insn, &r1, &r3, &b2, &d2);
+        if (r3 == 15) {
+            /* effectively a 32-bit load */
+            tmp = get_address(s, 0, b2, d2);
+            tmp32_1 = tcg_temp_new_i32();
+            tmp32_2 = tcg_const_i32(r3);
+            tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s));
+            store_reg32_i64(r1, tmp);
+            tcg_gen_trunc_i64_i32(tmp32_1, tmp);
+            set_cc_icm(s, tmp32_2, tmp32_1);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i32(tmp32_2);
+        } else if (r3) {
+            uint32_t mask = 0x00ffffffUL;
+            uint32_t shift = 24;
+            int m3 = r3;
+            tmp = get_address(s, 0, b2, d2);
+            tmp2 = tcg_temp_new_i64();
+            tmp32_1 = load_reg32(r1);
+            tmp32_2 = tcg_temp_new_i32();
+            tmp32_3 = tcg_const_i32(r3);
+            tmp32_4 = tcg_const_i32(0);
+            while (m3) {
+                if (m3 & 8) {
+                    tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s));
+                    tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
+                    if (shift) {
+                        tcg_gen_shli_i32(tmp32_2, tmp32_2, shift);
+                    }
+                    tcg_gen_andi_i32(tmp32_1, tmp32_1, mask);
+                    tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2);
+                    tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2);
+                    tcg_gen_addi_i64(tmp, tmp, 1);
+                }
+                m3 = (m3 << 1) & 0xf;
+                mask = (mask >> 8) | 0xff000000UL;
+                shift -= 8;
+            }
+            store_reg32(r1, tmp32_1);
+            set_cc_icm(s, tmp32_3, tmp32_4);
+            tcg_temp_free_i64(tmp);
+            tcg_temp_free_i64(tmp2);
+            tcg_temp_free_i32(tmp32_1);
+            tcg_temp_free_i32(tmp32_2);
+            tcg_temp_free_i32(tmp32_3);
+            tcg_temp_free_i32(tmp32_4);
+        } else {
+            /* i.e. env->cc = 0 */
+            gen_op_movi_cc(s, 0);
+        }
+        break;
+    case 0xc0:
+    case 0xc2:
+        insn = ld_code6(s->pc);
+        r1 = (insn >> 36) & 0xf;
+        op = (insn >> 32) & 0xf;
+        i2 = (int)insn;
+        switch (opc) {
+        case 0xc0:
+            disas_c0(s, op, r1, i2);
+            break;
+        case 0xc2:
+            disas_c2(s, op, r1, i2);
+            break;
+        default:
+            tcg_abort();
+        }
+        break;
+    case 0xd2: /* MVC    D1(L,B1),D2(B2)         [SS] */
+    case 0xd4: /* NC     D1(L,B1),D2(B2)         [SS] */
+    case 0xd5: /* CLC    D1(L,B1),D2(B2)         [SS] */
+    case 0xd6: /* OC     D1(L,B1),D2(B2)         [SS] */
+    case 0xd7: /* XC     D1(L,B1),D2(B2)         [SS] */
+    case 0xdc: /* TR     D1(L,B1),D2(B2)         [SS] */
+    case 0xf3: /* UNPK   D1(L1,B1),D2(L2,B2)     [SS] */
+        insn = ld_code6(s->pc);
+        vl = tcg_const_i32((insn >> 32) & 0xff);
+        b1 = (insn >> 28) & 0xf;
+        b2 = (insn >> 12) & 0xf;
+        d1 = (insn >> 16) & 0xfff;
+        d2 = insn & 0xfff;
+        tmp = get_address(s, 0, b1, d1);
+        tmp2 = get_address(s, 0, b2, d2);
+        switch (opc) {
+        case 0xd2:
+            gen_op_mvc(s, (insn >> 32) & 0xff, tmp, tmp2);
+            break;
+        case 0xd4:
+            potential_page_fault(s);
+            gen_helper_nc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xd5:
+            gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2);
+            break;
+        case 0xd6:
+            potential_page_fault(s);
+            gen_helper_oc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xd7:
+            potential_page_fault(s);
+            gen_helper_xc(cc_op, vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xdc:
+            potential_page_fault(s);
+            gen_helper_tr(vl, tmp, tmp2);
+            set_cc_static(s);
+            break;
+        case 0xf3:
+            potential_page_fault(s);
+            gen_helper_unpk(vl, tmp, tmp2);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xda: /* MVCP     D1(R1,B1),D2(B2),R3   [SS] */
+    case 0xdb: /* MVCS     D1(R1,B1),D2(B2),R3   [SS] */
+        check_privileged(s, ilc);
+        potential_page_fault(s);
+        insn = ld_code6(s->pc);
+        r1 = (insn >> 36) & 0xf;
+        r3 = (insn >> 32) & 0xf;
+        b1 = (insn >> 28) & 0xf;
+        d1 = (insn >> 16) & 0xfff;
+        b2 = (insn >> 12) & 0xf;
+        d2 = insn & 0xfff;
+        tmp = load_reg(r1);
+        /* XXX key in r3 */
+        tmp2 = get_address(s, 0, b1, d1);
+        tmp3 = get_address(s, 0, b2, d2);
+        if (opc == 0xda) {
+            gen_helper_mvcp(cc_op, tmp, tmp2, tmp3);
+        } else {
+            gen_helper_mvcs(cc_op, tmp, tmp2, tmp3);
+        }
+        set_cc_static(s);
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(tmp2);
+        tcg_temp_free_i64(tmp3);
+        break;
+#endif
+    case 0xe3:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        x2 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = ((int)((((insn >> 16) & 0xfff)
+           | ((insn << 4) & 0xff000)) << 12)) >> 12;
+        disas_e3(s, op,  r1, x2, b2, d2 );
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0xe5:
+        /* Test Protection */
+        check_privileged(s, ilc);
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        disas_e5(s, insn);
+        break;
+#endif
+    case 0xeb:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        r3 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = ((int)((((insn >> 16) & 0xfff)
+           | ((insn << 4) & 0xff000)) << 12)) >> 12;
+        disas_eb(s, op, r1, r3, b2, d2);
+        break;
+    case 0xed:
+        insn = ld_code6(s->pc);
+        debug_insn(insn);
+        op = insn & 0xff;
+        r1 = (insn >> 36) & 0xf;
+        x2 = (insn >> 32) & 0xf;
+        b2 = (insn >> 28) & 0xf;
+        d2 = (short)((insn >> 16) & 0xfff);
+        r1b = (insn >> 12) & 0xf;
+        disas_ed(s, op, r1, x2, b2, d2, r1b);
+        break;
+    default:
+        LOG_DISAS("unimplemented opcode 0x%x\n", opc);
+        gen_illegal_opcode(s, ilc);
+        break;
+    }
+
+    /* Instruction length is encoded in the opcode */
+    s->pc += (ilc * 2);
+}
+
+static inline void gen_intermediate_code_internal(CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
+{
+    DisasContext dc;
+    target_ulong pc_start;
+    uint64_t next_page_start;
+    uint16_t *gen_opc_end;
+    int j, lj = -1;
+    int num_insns, max_insns;
+    CPUBreakpoint *bp;
+
+    pc_start = tb->pc;
+
+    /* 31-bit mode */
+    if (!(tb->flags & FLAG_MASK_64)) {
+        pc_start &= 0x7fffffff;
+    }
+
+    dc.pc = pc_start;
+    dc.is_jmp = DISAS_NEXT;
+    dc.tb = tb;
+    dc.cc_op = CC_OP_DYNAMIC;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    gen_icount_start();
+
+    do {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc.pc) {
+                    gen_debug(&dc);
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc.pc;
+            gen_opc_cc_op[lj] = dc.cc_op;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+#if defined(S390X_DEBUG_DISAS_VERBOSE)
+        LOG_DISAS("pc " TARGET_FMT_lx "\n",
+                  dc.pc);
+#endif
+        disas_s390_insn(&dc);
+
+        num_insns++;
+        if (env->singlestep_enabled) {
+            gen_debug(&dc);
+        }
+    } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start
+             && num_insns < max_insns && !env->singlestep_enabled
+             && !singlestep);
+
+    if (!dc.is_jmp) {
+        update_psw_addr(&dc);
+    }
+
+    if (singlestep && dc.cc_op != CC_OP_DYNAMIC) {
+        gen_op_calc_cc(&dc);
+    } else {
+        /* next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type
+           is in env */
+        gen_op_set_cc_op(&dc);
+    }
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+    /* Generate the return instruction */
+    if (dc.is_jmp != DISAS_TB_JUMP) {
+        tcg_gen_exit_tb(0);
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j) {
+            gen_opc_instr_start[lj++] = 0;
+        }
+    } else {
+        tb->size = dc.pc - pc_start;
+        tb->icount = num_insns;
+    }
+#if defined(S390X_DEBUG_DISAS)
+    log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0);
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc.pc - pc_start, 1);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    int cc_op;
+    env->psw.addr = gen_opc_pc[pc_pos];
+    cc_op = gen_opc_cc_op[pc_pos];
+    if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
+        env->cc_op = cc_op;
+    }
+}
diff --git a/qemu-0.15.x/target-sh4/README.sh4 b/qemu-0.15.x/target-sh4/README.sh4
new file mode 100644
index 0000000..e578830
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/README.sh4
@@ -0,0 +1,150 @@
+qemu target:   sh4
+author:        Samuel Tardieu <sam at rfc1149.net>
+last modified: Tue Dec  6 07:22:44 CET 2005
+
+The sh4 target is not ready at all yet for integration in qemu. This
+file describes the current state of implementation.
+
+Most places requiring attention and/or modification can be detected by
+looking for "XXXXX" or "abort()".
+
+The sh4 core is located in target-sh4/*, while the 7750 peripheral
+features (IO ports for example) are located in hw/sh7750.[ch]. The
+main board description is in hw/shix.c, and the NAND flash in
+hw/tc58128.[ch].
+
+All the shortcomings indicated here will eventually be resolved. This
+is a work in progress. Features are added in a semi-random order: if a
+point is blocking to progress on booting the Linux kernel for the shix
+board, it is addressed first; if feedback is necessary and no progress
+can be made on blocking points until it is received, a random feature
+is worked on.
+
+Goals
+-----
+
+The primary model being worked on is the soft MMU target to be able to
+emulate the Shix 2.0 board by Alexis Polti, described at
+http://perso.enst.fr/~polti/realisations/shix20/
+
+Ultimately, qemu will be coupled with a system C or a verilog
+simulator to simulate the whole board functionalities.
+
+A sh4 user-mode has also somewhat started but will be worked on
+afterwards. The goal is to automate tests for GNAT (GNU Ada) compiler
+that I ported recently to the sh4-linux target.
+
+Registers
+---------
+
+16 general purpose registers are available at any time. The first 8
+registers are banked and the non-directly visible ones can be accessed
+by privileged instructions. In qemu, we define 24 general purpose
+registers and the code generation use either [0-7]+[8-15] or
+[16-23]+[8-15] depending on the MD and RB flags in the sr
+configuration register.
+
+Instructions
+------------
+
+Most sh4 instructions have been implemented. The missing ones at this
+time are:
+  - FPU related instructions
+  - LDTLB to load a new MMU entry
+  - SLEEP to put the processor in sleep mode
+
+Most instructions could be optimized a lot. This will be worked on
+after the current model is fully functional unless debugging
+convenience requires that it is done early.
+
+Many instructions did not have a chance to be tested yet. The plan is
+to implement unit and regression testing of those in the future.
+
+MMU
+---
+
+The MMU is implemented in the sh4 core. MMU management has not been
+tested at all yet. In the sh7750, it can be manipulated through memory
+mapped registers and this part has not yet been implemented.
+
+Exceptions
+----------
+
+Exceptions are implemented as described in the sh4 reference manual
+but have not been tested yet. They do not use qemu EXCP_ features
+yet.
+
+IRQ
+---
+
+IRQ are not implemented yet.
+
+Peripheral features
+-------------------
+
+  + Serial ports
+
+Configuration and use of the first serial port (SCI) without
+interrupts is supported. Input has not yet been tested.
+
+Configuration of the second serial port (SCIF) is supported. FIFO
+handling infrastructure has been started but is not completed yet.
+
+  + GPIO ports
+
+GPIO ports have been implemented. A registration function allows
+external modules to register interest in some port changes (see
+hw/tc58128.[ch] for an example) and will be called back. Interrupt
+generation is not yet supported but some infrastructure is in place
+for this purpose. Note that in the current model a peripheral module
+cannot directly simulate a H->L->H input port transition and have an
+interrupt generated on the low level.
+
+  + TC58128 NAND flash
+
+TC58128 NAND flash is partially implemented through GPIO ports. It
+supports reading from flash.
+
+GDB
+---
+
+GDB remote target support has been implemented and lightly tested.
+
+Files
+-----
+
+File names are hardcoded at this time. The bootloader must be stored in
+shix_bios.bin in the current directory. The initial Linux image must
+be stored in shix_linux_nand.bin in the current directory in NAND
+format. Test files can be obtained from
+http://perso.enst.fr/~polti/robot/ as well as the various datasheets I
+use.
+
+qemu disk parameter on the command line is unused. You can supply any
+existing image and it will be ignored. As the goal is to simulate an
+embedded target, it is not clear how this parameter will be handled in
+the future.
+
+To build an ELF kernel image from the NAND image, 16 bytes have to be
+stripped off the end of every 528 bytes, keeping only 512 of them. The
+following Python code snippet does it:
+
+#! /usr/bin/python
+
+def denand (infd, outfd):
+    while True:
+        d = infd.read (528)
+        if not d: return
+        outfd.write (d[:512])
+
+if __name__ == '__main__':
+    import sys
+    denand (open (sys.argv[1], 'rb'),
+            open (sys.argv[2], 'wb'))
+
+Style isssues
+-------------
+
+There is currently a mix between my style (space before opening
+parenthesis) and qemu style. This will be resolved before final
+integration is proposed.
diff --git a/qemu-0.15.x/target-sh4/cpu.h b/qemu-0.15.x/target-sh4/cpu.h
new file mode 100644
index 0000000..00e32f2
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/cpu.h
@@ -0,0 +1,377 @@
+/*
+ *  SH4 emulation
+ *
+ *  Copyright (c) 2005 Samuel Tardieu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _CPU_SH4_H
+#define _CPU_SH4_H
+
+#include "config.h"
+#include "qemu-common.h"
+
+#define TARGET_LONG_BITS 32
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_SH
+
+/* CPU Subtypes */
+#define SH_CPU_SH7750  (1 << 0)
+#define SH_CPU_SH7750S (1 << 1)
+#define SH_CPU_SH7750R (1 << 2)
+#define SH_CPU_SH7751  (1 << 3)
+#define SH_CPU_SH7751R (1 << 4)
+#define SH_CPU_SH7785  (1 << 5)
+#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R)
+#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R)
+
+#define CPUState struct CPUSH4State
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define TARGET_PAGE_BITS 12	/* 4k XXXXX */
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#define SR_MD (1 << 30)
+#define SR_RB (1 << 29)
+#define SR_BL (1 << 28)
+#define SR_FD (1 << 15)
+#define SR_M  (1 << 9)
+#define SR_Q  (1 << 8)
+#define SR_I3 (1 << 7)
+#define SR_I2 (1 << 6)
+#define SR_I1 (1 << 5)
+#define SR_I0 (1 << 4)
+#define SR_S  (1 << 1)
+#define SR_T  (1 << 0)
+
+#define FPSCR_MASK             (0x003fffff)
+#define FPSCR_FR               (1 << 21)
+#define FPSCR_SZ               (1 << 20)
+#define FPSCR_PR               (1 << 19)
+#define FPSCR_DN               (1 << 18)
+#define FPSCR_CAUSE_MASK       (0x3f << 12)
+#define FPSCR_CAUSE_SHIFT      (12)
+#define FPSCR_CAUSE_E          (1 << 17)
+#define FPSCR_CAUSE_V          (1 << 16)
+#define FPSCR_CAUSE_Z          (1 << 15)
+#define FPSCR_CAUSE_O          (1 << 14)
+#define FPSCR_CAUSE_U          (1 << 13)
+#define FPSCR_CAUSE_I          (1 << 12)
+#define FPSCR_ENABLE_MASK      (0x1f << 7)
+#define FPSCR_ENABLE_SHIFT     (7)
+#define FPSCR_ENABLE_V         (1 << 11)
+#define FPSCR_ENABLE_Z         (1 << 10)
+#define FPSCR_ENABLE_O         (1 << 9)
+#define FPSCR_ENABLE_U         (1 << 8)
+#define FPSCR_ENABLE_I         (1 << 7)
+#define FPSCR_FLAG_MASK        (0x1f << 2)
+#define FPSCR_FLAG_SHIFT       (2)
+#define FPSCR_FLAG_V           (1 << 6)
+#define FPSCR_FLAG_Z           (1 << 5)
+#define FPSCR_FLAG_O           (1 << 4)
+#define FPSCR_FLAG_U           (1 << 3)
+#define FPSCR_FLAG_I           (1 << 2)
+#define FPSCR_RM_MASK          (0x03 << 0)
+#define FPSCR_RM_NEAREST       (0 << 0)
+#define FPSCR_RM_ZERO          (1 << 0)
+
+#define DELAY_SLOT             (1 << 0)
+#define DELAY_SLOT_CONDITIONAL (1 << 1)
+#define DELAY_SLOT_TRUE        (1 << 2)
+#define DELAY_SLOT_CLEARME     (1 << 3)
+/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump
+ * after the delay slot should be taken or not. It is calculated from SR_T.
+ *
+ * It is unclear if it is permitted to modify the SR_T flag in a delay slot.
+ * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification.
+ */
+
+typedef struct tlb_t {
+    uint32_t vpn;		/* virtual page number */
+    uint32_t ppn;		/* physical page number */
+    uint32_t size;		/* mapped page size in bytes */
+    uint8_t asid;		/* address space identifier */
+    uint8_t v:1;		/* validity */
+    uint8_t sz:2;		/* page size */
+    uint8_t sh:1;		/* share status */
+    uint8_t c:1;		/* cacheability */
+    uint8_t pr:2;		/* protection key */
+    uint8_t d:1;		/* dirty */
+    uint8_t wt:1;		/* write through */
+    uint8_t sa:3;		/* space attribute (PCMCIA) */
+    uint8_t tc:1;		/* timing control */
+} tlb_t;
+
+#define UTLB_SIZE 64
+#define ITLB_SIZE 4
+
+#define NB_MMU_MODES 2
+
+enum sh_features {
+    SH_FEATURE_SH4A = 1,
+    SH_FEATURE_BCR3_AND_BCR4 = 2,
+};
+
+typedef struct memory_content {
+    uint32_t address;
+    uint32_t value;
+    struct memory_content *next;
+} memory_content;
+
+typedef struct CPUSH4State {
+    uint32_t flags;		/* general execution flags */
+    uint32_t gregs[24];		/* general registers */
+    float32 fregs[32];		/* floating point registers */
+    uint32_t sr;		/* status register */
+    uint32_t ssr;		/* saved status register */
+    uint32_t spc;		/* saved program counter */
+    uint32_t gbr;		/* global base register */
+    uint32_t vbr;		/* vector base register */
+    uint32_t sgr;		/* saved global register 15 */
+    uint32_t dbr;		/* debug base register */
+    uint32_t pc;		/* program counter */
+    uint32_t delayed_pc;	/* target of delayed jump */
+    uint32_t mach;		/* multiply and accumulate high */
+    uint32_t macl;		/* multiply and accumulate low */
+    uint32_t pr;		/* procedure register */
+    uint32_t fpscr;		/* floating point status/control register */
+    uint32_t fpul;		/* floating point communication register */
+
+    /* float point status register */
+    float_status fp_status;
+
+    /* The features that we should emulate. See sh_features above.  */
+    uint32_t features;
+
+    /* Those belong to the specific unit (SH7750) but are handled here */
+    uint32_t mmucr;		/* MMU control register */
+    uint32_t pteh;		/* page table entry high register */
+    uint32_t ptel;		/* page table entry low register */
+    uint32_t ptea;		/* page table entry assistance register */
+    uint32_t ttb;		/* tranlation table base register */
+    uint32_t tea;		/* TLB exception address register */
+    uint32_t tra;		/* TRAPA exception register */
+    uint32_t expevt;		/* exception event register */
+    uint32_t intevt;		/* interrupt event register */
+
+    tlb_t itlb[ITLB_SIZE];	/* instruction translation table */
+    tlb_t utlb[UTLB_SIZE];	/* unified translation table */
+
+    uint32_t ldst;
+
+    CPU_COMMON
+
+    int id;			/* CPU model */
+    uint32_t pvr;		/* Processor Version Register */
+    uint32_t prr;		/* Processor Revision Register */
+    uint32_t cvr;		/* Cache Version Register */
+
+    void *intc_handle;
+    int in_sleep;		/* SR_BL ignored during sleep */
+    memory_content *movcal_backup;
+    memory_content **movcal_backup_tail;
+} CPUSH4State;
+
+CPUSH4State *cpu_sh4_init(const char *cpu_model);
+int cpu_sh4_exec(CPUSH4State * s);
+int cpu_sh4_signal_handler(int host_signum, void *pinfo,
+                           void *puc);
+int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
+			     int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
+void do_interrupt(CPUSH4State * env);
+
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+#if !defined(CONFIG_USER_ONLY)
+void cpu_sh4_invalidate_tlb(CPUSH4State *s);
+uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
+                                       target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
+                                       target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
+                                       target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
+                                       target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value);
+#endif
+
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr);
+
+static inline void cpu_set_tls(CPUSH4State *env, target_ulong newtls)
+{
+  env->gbr = newtls;
+}
+
+void cpu_load_tlb(CPUSH4State * env);
+
+#include "softfloat.h"
+
+#define cpu_init cpu_sh4_init
+#define cpu_exec cpu_sh4_exec
+#define cpu_gen_code cpu_sh4_gen_code
+#define cpu_signal_handler cpu_sh4_signal_handler
+#define cpu_list sh4_cpu_list
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->sr & SR_MD) == 0 ? 1 : 0;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->gregs[15] = newsp;
+    env->gregs[0] = 0;
+}
+#endif
+
+#include "cpu-all.h"
+
+/* Memory access type */
+enum {
+    /* Privilege */
+    ACCESS_PRIV = 0x01,
+    /* Direction */
+    ACCESS_WRITE = 0x02,
+    /* Type of instruction */
+    ACCESS_CODE = 0x10,
+    ACCESS_INT = 0x20
+};
+
+/* MMU control register */
+#define MMUCR    0x1F000010
+#define MMUCR_AT (1<<0)
+#define MMUCR_TI (1<<2)
+#define MMUCR_SV (1<<8)
+#define MMUCR_URC_BITS (6)
+#define MMUCR_URC_OFFSET (10)
+#define MMUCR_URC_SIZE (1 << MMUCR_URC_BITS)
+#define MMUCR_URC_MASK (((MMUCR_URC_SIZE) - 1) << MMUCR_URC_OFFSET)
+static inline int cpu_mmucr_urc (uint32_t mmucr)
+{
+    return ((mmucr & MMUCR_URC_MASK) >> MMUCR_URC_OFFSET);
+}
+
+/* PTEH : Page Translation Entry High register */
+#define PTEH_ASID_BITS (8)
+#define PTEH_ASID_SIZE (1 << PTEH_ASID_BITS)
+#define PTEH_ASID_MASK (PTEH_ASID_SIZE - 1)
+#define cpu_pteh_asid(pteh) ((pteh) & PTEH_ASID_MASK)
+#define PTEH_VPN_BITS (22)
+#define PTEH_VPN_OFFSET (10)
+#define PTEH_VPN_SIZE (1 << PTEH_VPN_BITS)
+#define PTEH_VPN_MASK (((PTEH_VPN_SIZE) - 1) << PTEH_VPN_OFFSET)
+static inline int cpu_pteh_vpn (uint32_t pteh)
+{
+    return ((pteh & PTEH_VPN_MASK) >> PTEH_VPN_OFFSET);
+}
+
+/* PTEL : Page Translation Entry Low register */
+#define PTEL_V        (1 << 8)
+#define cpu_ptel_v(ptel) (((ptel) & PTEL_V) >> 8)
+#define PTEL_C        (1 << 3)
+#define cpu_ptel_c(ptel) (((ptel) & PTEL_C) >> 3)
+#define PTEL_D        (1 << 2)
+#define cpu_ptel_d(ptel) (((ptel) & PTEL_D) >> 2)
+#define PTEL_SH       (1 << 1)
+#define cpu_ptel_sh(ptel)(((ptel) & PTEL_SH) >> 1)
+#define PTEL_WT       (1 << 0)
+#define cpu_ptel_wt(ptel) ((ptel) & PTEL_WT)
+
+#define PTEL_SZ_HIGH_OFFSET  (7)
+#define PTEL_SZ_HIGH  (1 << PTEL_SZ_HIGH_OFFSET)
+#define PTEL_SZ_LOW_OFFSET   (4)
+#define PTEL_SZ_LOW   (1 << PTEL_SZ_LOW_OFFSET)
+static inline int cpu_ptel_sz (uint32_t ptel)
+{
+    int sz;
+    sz = (ptel & PTEL_SZ_HIGH) >> PTEL_SZ_HIGH_OFFSET;
+    sz <<= 1;
+    sz |= (ptel & PTEL_SZ_LOW) >> PTEL_SZ_LOW_OFFSET;
+    return sz;
+}
+
+#define PTEL_PPN_BITS (19)
+#define PTEL_PPN_OFFSET (10)
+#define PTEL_PPN_SIZE (1 << PTEL_PPN_BITS)
+#define PTEL_PPN_MASK (((PTEL_PPN_SIZE) - 1) << PTEL_PPN_OFFSET)
+static inline int cpu_ptel_ppn (uint32_t ptel)
+{
+    return ((ptel & PTEL_PPN_MASK) >> PTEL_PPN_OFFSET);
+}
+
+#define PTEL_PR_BITS   (2)
+#define PTEL_PR_OFFSET (5)
+#define PTEL_PR_SIZE (1 << PTEL_PR_BITS)
+#define PTEL_PR_MASK (((PTEL_PR_SIZE) - 1) << PTEL_PR_OFFSET)
+static inline int cpu_ptel_pr (uint32_t ptel)
+{
+    return ((ptel & PTEL_PR_MASK) >> PTEL_PR_OFFSET);
+}
+
+/* PTEA : Page Translation Entry Assistance register */
+#define PTEA_SA_BITS (3)
+#define PTEA_SA_SIZE (1 << PTEA_SA_BITS)
+#define PTEA_SA_MASK (PTEA_SA_SIZE - 1)
+#define cpu_ptea_sa(ptea) ((ptea) & PTEA_SA_MASK)
+#define PTEA_TC        (1 << 3)
+#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3)
+
+#define TB_FLAG_PENDING_MOVCA  (1 << 4)
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
+                    | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME))   /* Bits  0- 3 */
+            | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR))  /* Bits 19-21 */
+            | (env->sr & (SR_MD | SR_RB))                      /* Bits 29-30 */
+            | (env->sr & SR_FD)                                /* Bit 15 */
+            | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
+}
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+    env->flags = tb->flags;
+}
+
+#endif				/* _CPU_SH4_H */
diff --git a/qemu-0.15.x/target-sh4/exec.h b/qemu-0.15.x/target-sh4/exec.h
new file mode 100644
index 0000000..4a6ae58
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/exec.h
@@ -0,0 +1,33 @@
+/*
+ *  SH4 emulation
+ *
+ *  Copyright (c) 2005 Samuel Tardieu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _EXEC_SH4_H
+#define _EXEC_SH4_H
+
+#include "config.h"
+#include "dyngen-exec.h"
+
+register struct CPUSH4State *env asm(AREG0);
+
+#include "cpu.h"
+
+#ifndef CONFIG_USER_ONLY
+#include "softmmu_exec.h"
+#endif
+
+#endif				/* _EXEC_SH4_H */
diff --git a/qemu-0.15.x/target-sh4/helper.c b/qemu-0.15.x/target-sh4/helper.c
new file mode 100644
index 0000000..20e9b13
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/helper.c
@@ -0,0 +1,842 @@
+/*
+ *  SH4 emulation
+ *
+ *  Copyright (c) 2005 Samuel Tardieu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "cpu.h"
+#include "hw/sh_intc.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt (CPUState *env)
+{
+  env->exception_index = -1;
+}
+
+int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
+			     int mmu_idx, int is_softmmu)
+{
+    env->tea = address;
+    env->exception_index = -1;
+    switch (rw) {
+    case 0:
+        env->exception_index = 0x0a0;
+        break;
+    case 1:
+        env->exception_index = 0x0c0;
+        break;
+    case 2:
+        env->exception_index = 0x0a0;
+        break;
+    }
+    return 1;
+}
+
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
+{
+    /* For user mode, only U0 area is cachable. */
+    return !(addr & 0x80000000);
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+#define MMU_OK                   0
+#define MMU_ITLB_MISS            (-1)
+#define MMU_ITLB_MULTIPLE        (-2)
+#define MMU_ITLB_VIOLATION       (-3)
+#define MMU_DTLB_MISS_READ       (-4)
+#define MMU_DTLB_MISS_WRITE      (-5)
+#define MMU_DTLB_INITIAL_WRITE   (-6)
+#define MMU_DTLB_VIOLATION_READ  (-7)
+#define MMU_DTLB_VIOLATION_WRITE (-8)
+#define MMU_DTLB_MULTIPLE        (-9)
+#define MMU_DTLB_MISS            (-10)
+#define MMU_IADDR_ERROR          (-11)
+#define MMU_DADDR_ERROR_READ     (-12)
+#define MMU_DADDR_ERROR_WRITE    (-13)
+
+void do_interrupt(CPUState * env)
+{
+    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
+    int do_exp, irq_vector = env->exception_index;
+
+    /* prioritize exceptions over interrupts */
+
+    do_exp = env->exception_index != -1;
+    do_irq = do_irq && (env->exception_index == -1);
+
+    if (env->sr & SR_BL) {
+        if (do_exp && env->exception_index != 0x1e0) {
+            env->exception_index = 0x000; /* masked exception -> reset */
+        }
+        if (do_irq && !env->in_sleep) {
+            return; /* masked */
+        }
+    }
+    env->in_sleep = 0;
+
+    if (do_irq) {
+        irq_vector = sh_intc_get_pending_vector(env->intc_handle,
+						(env->sr >> 4) & 0xf);
+        if (irq_vector == -1) {
+            return; /* masked */
+	}
+    }
+
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+	const char *expname;
+	switch (env->exception_index) {
+	case 0x0e0:
+	    expname = "addr_error";
+	    break;
+	case 0x040:
+	    expname = "tlb_miss";
+	    break;
+	case 0x0a0:
+	    expname = "tlb_violation";
+	    break;
+	case 0x180:
+	    expname = "illegal_instruction";
+	    break;
+	case 0x1a0:
+	    expname = "slot_illegal_instruction";
+	    break;
+	case 0x800:
+	    expname = "fpu_disable";
+	    break;
+	case 0x820:
+	    expname = "slot_fpu";
+	    break;
+	case 0x100:
+	    expname = "data_write";
+	    break;
+	case 0x060:
+	    expname = "dtlb_miss_write";
+	    break;
+	case 0x0c0:
+	    expname = "dtlb_violation_write";
+	    break;
+	case 0x120:
+	    expname = "fpu_exception";
+	    break;
+	case 0x080:
+	    expname = "initial_page_write";
+	    break;
+	case 0x160:
+	    expname = "trapa";
+	    break;
+	default:
+            expname = do_irq ? "interrupt" : "???";
+            break;
+	}
+	qemu_log("exception 0x%03x [%s] raised\n",
+		  irq_vector, expname);
+	log_cpu_state(env, 0);
+    }
+
+    env->ssr = env->sr;
+    env->spc = env->pc;
+    env->sgr = env->gregs[15];
+    env->sr |= SR_BL | SR_MD | SR_RB;
+
+    if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
+        /* Branch instruction should be executed again before delay slot. */
+	env->spc -= 2;
+	/* Clear flags for exception/interrupt routine. */
+	env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE);
+    }
+    if (env->flags & DELAY_SLOT_CLEARME)
+        env->flags = 0;
+
+    if (do_exp) {
+        env->expevt = env->exception_index;
+        switch (env->exception_index) {
+        case 0x000:
+        case 0x020:
+        case 0x140:
+            env->sr &= ~SR_FD;
+            env->sr |= 0xf << 4; /* IMASK */
+            env->pc = 0xa0000000;
+            break;
+        case 0x040:
+        case 0x060:
+            env->pc = env->vbr + 0x400;
+            break;
+        case 0x160:
+            env->spc += 2; /* special case for TRAPA */
+            /* fall through */
+        default:
+            env->pc = env->vbr + 0x100;
+            break;
+        }
+        return;
+    }
+
+    if (do_irq) {
+        env->intevt = irq_vector;
+        env->pc = env->vbr + 0x600;
+        return;
+    }
+}
+
+static void update_itlb_use(CPUState * env, int itlbnb)
+{
+    uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
+
+    switch (itlbnb) {
+    case 0:
+	and_mask = 0x1f;
+	break;
+    case 1:
+	and_mask = 0xe7;
+	or_mask = 0x80;
+	break;
+    case 2:
+	and_mask = 0xfb;
+	or_mask = 0x50;
+	break;
+    case 3:
+	or_mask = 0x2c;
+	break;
+    }
+
+    env->mmucr &= (and_mask << 24) | 0x00ffffff;
+    env->mmucr |= (or_mask << 24);
+}
+
+static int itlb_replacement(CPUState * env)
+{
+    if ((env->mmucr & 0xe0000000) == 0xe0000000)
+	return 0;
+    if ((env->mmucr & 0x98000000) == 0x18000000)
+	return 1;
+    if ((env->mmucr & 0x54000000) == 0x04000000)
+	return 2;
+    if ((env->mmucr & 0x2c000000) == 0x00000000)
+	return 3;
+    cpu_abort(env, "Unhandled itlb_replacement");
+}
+
+/* Find the corresponding entry in the right TLB
+   Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
+*/
+static int find_tlb_entry(CPUState * env, target_ulong address,
+			  tlb_t * entries, uint8_t nbtlb, int use_asid)
+{
+    int match = MMU_DTLB_MISS;
+    uint32_t start, end;
+    uint8_t asid;
+    int i;
+
+    asid = env->pteh & 0xff;
+
+    for (i = 0; i < nbtlb; i++) {
+	if (!entries[i].v)
+	    continue;		/* Invalid entry */
+	if (!entries[i].sh && use_asid && entries[i].asid != asid)
+	    continue;		/* Bad ASID */
+	start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
+	end = start + entries[i].size - 1;
+	if (address >= start && address <= end) {	/* Match */
+	    if (match != MMU_DTLB_MISS)
+		return MMU_DTLB_MULTIPLE;	/* Multiple match */
+	    match = i;
+	}
+    }
+    return match;
+}
+
+static void increment_urc(CPUState * env)
+{
+    uint8_t urb, urc;
+
+    /* Increment URC */
+    urb = ((env->mmucr) >> 18) & 0x3f;
+    urc = ((env->mmucr) >> 10) & 0x3f;
+    urc++;
+    if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1))
+	urc = 0;
+    env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
+}
+
+/* Copy and utlb entry into itlb
+   Return entry
+*/
+static int copy_utlb_entry_itlb(CPUState *env, int utlb)
+{
+    int itlb;
+
+    tlb_t * ientry;
+    itlb = itlb_replacement(env);
+    ientry = &env->itlb[itlb];
+    if (ientry->v) {
+        tlb_flush_page(env, ientry->vpn << 10);
+    }
+    *ientry = env->utlb[utlb];
+    update_itlb_use(env, itlb);
+    return itlb;
+}
+
+/* Find itlb entry
+   Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
+*/
+static int find_itlb_entry(CPUState * env, target_ulong address,
+                           int use_asid)
+{
+    int e;
+
+    e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
+    if (e == MMU_DTLB_MULTIPLE) {
+	e = MMU_ITLB_MULTIPLE;
+    } else if (e == MMU_DTLB_MISS) {
+	e = MMU_ITLB_MISS;
+    } else if (e >= 0) {
+	update_itlb_use(env, e);
+    }
+    return e;
+}
+
+/* Find utlb entry
+   Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
+static int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
+{
+    /* per utlb access */
+    increment_urc(env);
+
+    /* Return entry */
+    return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
+}
+
+/* Match address against MMU
+   Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
+   MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
+   MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
+   MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
+   MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
+*/
+static int get_mmu_address(CPUState * env, target_ulong * physical,
+			   int *prot, target_ulong address,
+			   int rw, int access_type)
+{
+    int use_asid, n;
+    tlb_t *matching = NULL;
+
+    use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
+
+    if (rw == 2) {
+        n = find_itlb_entry(env, address, use_asid);
+	if (n >= 0) {
+	    matching = &env->itlb[n];
+	    if (!(env->sr & SR_MD) && !(matching->pr & 2))
+		n = MMU_ITLB_VIOLATION;
+	    else
+		*prot = PAGE_EXEC;
+        } else {
+            n = find_utlb_entry(env, address, use_asid);
+            if (n >= 0) {
+                n = copy_utlb_entry_itlb(env, n);
+                matching = &env->itlb[n];
+                if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
+                      n = MMU_ITLB_VIOLATION;
+                } else {
+                    *prot = PAGE_READ | PAGE_EXEC;
+                    if ((matching->pr & 1) && matching->d) {
+                        *prot |= PAGE_WRITE;
+                    }
+                }
+            } else if (n == MMU_DTLB_MULTIPLE) {
+                n = MMU_ITLB_MULTIPLE;
+            } else if (n == MMU_DTLB_MISS) {
+                n = MMU_ITLB_MISS;
+            }
+	}
+    } else {
+	n = find_utlb_entry(env, address, use_asid);
+	if (n >= 0) {
+	    matching = &env->utlb[n];
+            if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
+                n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
+                    MMU_DTLB_VIOLATION_READ;
+            } else if ((rw == 1) && !(matching->pr & 1)) {
+                n = MMU_DTLB_VIOLATION_WRITE;
+            } else if ((rw == 1) && !matching->d) {
+                n = MMU_DTLB_INITIAL_WRITE;
+            } else {
+                *prot = PAGE_READ;
+                if ((matching->pr & 1) && matching->d) {
+                    *prot |= PAGE_WRITE;
+                }
+            }
+	} else if (n == MMU_DTLB_MISS) {
+	    n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
+		MMU_DTLB_MISS_READ;
+	}
+    }
+    if (n >= 0) {
+	n = MMU_OK;
+	*physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
+	    (address & (matching->size - 1));
+    }
+    return n;
+}
+
+static int get_physical_address(CPUState * env, target_ulong * physical,
+                                int *prot, target_ulong address,
+                                int rw, int access_type)
+{
+    /* P1, P2 and P4 areas do not use translation */
+    if ((address >= 0x80000000 && address < 0xc0000000) ||
+	address >= 0xe0000000) {
+	if (!(env->sr & SR_MD)
+	    && (address < 0xe0000000 || address >= 0xe4000000)) {
+	    /* Unauthorized access in user mode (only store queues are available) */
+	    fprintf(stderr, "Unauthorized access\n");
+	    if (rw == 0)
+		return MMU_DADDR_ERROR_READ;
+	    else if (rw == 1)
+		return MMU_DADDR_ERROR_WRITE;
+	    else
+		return MMU_IADDR_ERROR;
+	}
+	if (address >= 0x80000000 && address < 0xc0000000) {
+	    /* Mask upper 3 bits for P1 and P2 areas */
+	    *physical = address & 0x1fffffff;
+	} else {
+	    *physical = address;
+	}
+	*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+	return MMU_OK;
+    }
+
+    /* If MMU is disabled, return the corresponding physical page */
+    if (!(env->mmucr & MMUCR_AT)) {
+	*physical = address & 0x1FFFFFFF;
+	*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+	return MMU_OK;
+    }
+
+    /* We need to resort to the MMU */
+    return get_mmu_address(env, physical, prot, address, rw, access_type);
+}
+
+int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
+			     int mmu_idx, int is_softmmu)
+{
+    target_ulong physical;
+    int prot, ret, access_type;
+
+    access_type = ACCESS_INT;
+    ret =
+	get_physical_address(env, &physical, &prot, address, rw,
+			     access_type);
+
+    if (ret != MMU_OK) {
+	env->tea = address;
+	if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
+	    env->pteh = (env->pteh & PTEH_ASID_MASK) |
+		    (address & PTEH_VPN_MASK);
+	}
+	switch (ret) {
+	case MMU_ITLB_MISS:
+	case MMU_DTLB_MISS_READ:
+	    env->exception_index = 0x040;
+	    break;
+	case MMU_DTLB_MULTIPLE:
+	case MMU_ITLB_MULTIPLE:
+	    env->exception_index = 0x140;
+	    break;
+	case MMU_ITLB_VIOLATION:
+	    env->exception_index = 0x0a0;
+	    break;
+	case MMU_DTLB_MISS_WRITE:
+	    env->exception_index = 0x060;
+	    break;
+	case MMU_DTLB_INITIAL_WRITE:
+	    env->exception_index = 0x080;
+	    break;
+	case MMU_DTLB_VIOLATION_READ:
+	    env->exception_index = 0x0a0;
+	    break;
+	case MMU_DTLB_VIOLATION_WRITE:
+	    env->exception_index = 0x0c0;
+	    break;
+	case MMU_IADDR_ERROR:
+	case MMU_DADDR_ERROR_READ:
+	    env->exception_index = 0x0e0;
+	    break;
+	case MMU_DADDR_ERROR_WRITE:
+	    env->exception_index = 0x100;
+	    break;
+	default:
+            cpu_abort(env, "Unhandled MMU fault");
+	}
+	return 1;
+    }
+
+    address &= TARGET_PAGE_MASK;
+    physical &= TARGET_PAGE_MASK;
+
+    tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
+    return 0;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+{
+    target_ulong physical;
+    int prot;
+
+    get_physical_address(env, &physical, &prot, addr, 0, 0);
+    return physical;
+}
+
+void cpu_load_tlb(CPUSH4State * env)
+{
+    int n = cpu_mmucr_urc(env->mmucr);
+    tlb_t * entry = &env->utlb[n];
+
+    if (entry->v) {
+        /* Overwriting valid entry in utlb. */
+        target_ulong address = entry->vpn << 10;
+	tlb_flush_page(env, address);
+    }
+
+    /* Take values into cpu status from registers. */
+    entry->asid = (uint8_t)cpu_pteh_asid(env->pteh);
+    entry->vpn  = cpu_pteh_vpn(env->pteh);
+    entry->v    = (uint8_t)cpu_ptel_v(env->ptel);
+    entry->ppn  = cpu_ptel_ppn(env->ptel);
+    entry->sz   = (uint8_t)cpu_ptel_sz(env->ptel);
+    switch (entry->sz) {
+    case 0: /* 00 */
+        entry->size = 1024; /* 1K */
+        break;
+    case 1: /* 01 */
+        entry->size = 1024 * 4; /* 4K */
+        break;
+    case 2: /* 10 */
+        entry->size = 1024 * 64; /* 64K */
+        break;
+    case 3: /* 11 */
+        entry->size = 1024 * 1024; /* 1M */
+        break;
+    default:
+        cpu_abort(env, "Unhandled load_tlb");
+        break;
+    }
+    entry->sh   = (uint8_t)cpu_ptel_sh(env->ptel);
+    entry->c    = (uint8_t)cpu_ptel_c(env->ptel);
+    entry->pr   = (uint8_t)cpu_ptel_pr(env->ptel);
+    entry->d    = (uint8_t)cpu_ptel_d(env->ptel);
+    entry->wt   = (uint8_t)cpu_ptel_wt(env->ptel);
+    entry->sa   = (uint8_t)cpu_ptea_sa(env->ptea);
+    entry->tc   = (uint8_t)cpu_ptea_tc(env->ptea);
+}
+
+ void cpu_sh4_invalidate_tlb(CPUSH4State *s)
+{
+    int i;
+
+    /* UTLB */
+    for (i = 0; i < UTLB_SIZE; i++) {
+        tlb_t * entry = &s->utlb[i];
+        entry->v = 0;
+    }
+    /* ITLB */
+    for (i = 0; i < ITLB_SIZE; i++) {
+        tlb_t * entry = &s->itlb[i];
+        entry->v = 0;
+    }
+
+    tlb_flush(s, 1);
+}
+
+uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
+                                       target_phys_addr_t addr)
+{
+    int index = (addr & 0x00000300) >> 8;
+    tlb_t * entry = &s->itlb[index];
+
+    return (entry->vpn  << 10) |
+           (entry->v    <<  8) |
+           (entry->asid);
+}
+
+void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+				    uint32_t mem_value)
+{
+    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
+    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
+    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
+
+    int index = (addr & 0x00000300) >> 8;
+    tlb_t * entry = &s->itlb[index];
+    if (entry->v) {
+        /* Overwriting valid entry in itlb. */
+        target_ulong address = entry->vpn << 10;
+        tlb_flush_page(s, address);
+    }
+    entry->asid = asid;
+    entry->vpn = vpn;
+    entry->v = v;
+}
+
+uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
+                                       target_phys_addr_t addr)
+{
+    int array = (addr & 0x00800000) >> 23;
+    int index = (addr & 0x00000300) >> 8;
+    tlb_t * entry = &s->itlb[index];
+
+    if (array == 0) {
+        /* ITLB Data Array 1 */
+        return (entry->ppn << 10) |
+               (entry->v   <<  8) |
+               (entry->pr  <<  5) |
+               ((entry->sz & 1) <<  6) |
+               ((entry->sz & 2) <<  4) |
+               (entry->c   <<  3) |
+               (entry->sh  <<  1);
+    } else {
+        /* ITLB Data Array 2 */
+        return (entry->tc << 1) |
+               (entry->sa);
+    }
+}
+
+void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value)
+{
+    int array = (addr & 0x00800000) >> 23;
+    int index = (addr & 0x00000300) >> 8;
+    tlb_t * entry = &s->itlb[index];
+
+    if (array == 0) {
+        /* ITLB Data Array 1 */
+        if (entry->v) {
+            /* Overwriting valid entry in utlb. */
+            target_ulong address = entry->vpn << 10;
+            tlb_flush_page(s, address);
+        }
+        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
+        entry->v   = (mem_value & 0x00000100) >> 8;
+        entry->sz  = (mem_value & 0x00000080) >> 6 |
+                     (mem_value & 0x00000010) >> 4;
+        entry->pr  = (mem_value & 0x00000040) >> 5;
+        entry->c   = (mem_value & 0x00000008) >> 3;
+        entry->sh  = (mem_value & 0x00000002) >> 1;
+    } else {
+        /* ITLB Data Array 2 */
+        entry->tc  = (mem_value & 0x00000008) >> 3;
+        entry->sa  = (mem_value & 0x00000007);
+    }
+}
+
+uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
+                                       target_phys_addr_t addr)
+{
+    int index = (addr & 0x00003f00) >> 8;
+    tlb_t * entry = &s->utlb[index];
+
+    increment_urc(s); /* per utlb access */
+
+    return (entry->vpn  << 10) |
+           (entry->v    <<  8) |
+           (entry->asid);
+}
+
+void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+				    uint32_t mem_value)
+{
+    int associate = addr & 0x0000080;
+    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
+    uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
+    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
+    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
+    int use_asid = (s->mmucr & MMUCR_SV) == 0 || (s->sr & SR_MD) == 0;
+
+    if (associate) {
+        int i;
+	tlb_t * utlb_match_entry = NULL;
+	int needs_tlb_flush = 0;
+
+	/* search UTLB */
+	for (i = 0; i < UTLB_SIZE; i++) {
+            tlb_t * entry = &s->utlb[i];
+            if (!entry->v)
+	        continue;
+
+            if (entry->vpn == vpn
+                && (!use_asid || entry->asid == asid || entry->sh)) {
+	        if (utlb_match_entry) {
+		    /* Multiple TLB Exception */
+		    s->exception_index = 0x140;
+		    s->tea = addr;
+		    break;
+	        }
+		if (entry->v && !v)
+		    needs_tlb_flush = 1;
+		entry->v = v;
+		entry->d = d;
+	        utlb_match_entry = entry;
+	    }
+	    increment_urc(s); /* per utlb access */
+	}
+
+	/* search ITLB */
+	for (i = 0; i < ITLB_SIZE; i++) {
+            tlb_t * entry = &s->itlb[i];
+            if (entry->vpn == vpn
+                && (!use_asid || entry->asid == asid || entry->sh)) {
+	        if (entry->v && !v)
+		    needs_tlb_flush = 1;
+	        if (utlb_match_entry)
+		    *entry = *utlb_match_entry;
+	        else
+		    entry->v = v;
+		break;
+	    }
+	}
+
+	if (needs_tlb_flush)
+	    tlb_flush_page(s, vpn << 10);
+        
+    } else {
+        int index = (addr & 0x00003f00) >> 8;
+        tlb_t * entry = &s->utlb[index];
+	if (entry->v) {
+	    /* Overwriting valid entry in utlb. */
+            target_ulong address = entry->vpn << 10;
+	    tlb_flush_page(s, address);
+	}
+	entry->asid = asid;
+	entry->vpn = vpn;
+	entry->d = d;
+	entry->v = v;
+	increment_urc(s);
+    }
+}
+
+uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
+                                       target_phys_addr_t addr)
+{
+    int array = (addr & 0x00800000) >> 23;
+    int index = (addr & 0x00003f00) >> 8;
+    tlb_t * entry = &s->utlb[index];
+
+    increment_urc(s); /* per utlb access */
+
+    if (array == 0) {
+        /* ITLB Data Array 1 */
+        return (entry->ppn << 10) |
+               (entry->v   <<  8) |
+               (entry->pr  <<  5) |
+               ((entry->sz & 1) <<  6) |
+               ((entry->sz & 2) <<  4) |
+               (entry->c   <<  3) |
+               (entry->d   <<  2) |
+               (entry->sh  <<  1) |
+               (entry->wt);
+    } else {
+        /* ITLB Data Array 2 */
+        return (entry->tc << 1) |
+               (entry->sa);
+    }
+}
+
+void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, target_phys_addr_t addr,
+                                    uint32_t mem_value)
+{
+    int array = (addr & 0x00800000) >> 23;
+    int index = (addr & 0x00003f00) >> 8;
+    tlb_t * entry = &s->utlb[index];
+
+    increment_urc(s); /* per utlb access */
+
+    if (array == 0) {
+        /* UTLB Data Array 1 */
+        if (entry->v) {
+            /* Overwriting valid entry in utlb. */
+            target_ulong address = entry->vpn << 10;
+            tlb_flush_page(s, address);
+        }
+        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
+        entry->v   = (mem_value & 0x00000100) >> 8;
+        entry->sz  = (mem_value & 0x00000080) >> 6 |
+                     (mem_value & 0x00000010) >> 4;
+        entry->pr  = (mem_value & 0x00000060) >> 5;
+        entry->c   = (mem_value & 0x00000008) >> 3;
+        entry->d   = (mem_value & 0x00000004) >> 2;
+        entry->sh  = (mem_value & 0x00000002) >> 1;
+        entry->wt  = (mem_value & 0x00000001);
+    } else {
+        /* UTLB Data Array 2 */
+        entry->tc = (mem_value & 0x00000008) >> 3;
+        entry->sa = (mem_value & 0x00000007);
+    }
+}
+
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
+{
+    int n;
+    int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
+
+    /* check area */
+    if (env->sr & SR_MD) {
+        /* For previledged mode, P2 and P4 area is not cachable. */
+        if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr)
+            return 0;
+    } else {
+        /* For user mode, only U0 area is cachable. */
+        if (0x80000000 <= addr)
+            return 0;
+    }
+
+    /*
+     * TODO : Evaluate CCR and check if the cache is on or off.
+     *        Now CCR is not in CPUSH4State, but in SH7750State.
+     *        When you move the ccr inot CPUSH4State, the code will be
+     *        as follows.
+     */
+#if 0
+    /* check if operand cache is enabled or not. */
+    if (!(env->ccr & 1))
+        return 0;
+#endif
+
+    /* if MMU is off, no check for TLB. */
+    if (env->mmucr & MMUCR_AT)
+        return 1;
+
+    /* check TLB */
+    n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid);
+    if (n >= 0)
+        return env->itlb[n].c;
+
+    n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid);
+    if (n >= 0)
+        return env->utlb[n].c;
+
+    return 0;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-sh4/helper.h b/qemu-0.15.x/target-sh4/helper.h
new file mode 100644
index 0000000..95e3c7c
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/helper.h
@@ -0,0 +1,54 @@
+#include "def-helper.h"
+
+DEF_HELPER_0(ldtlb, void)
+DEF_HELPER_0(raise_illegal_instruction, void)
+DEF_HELPER_0(raise_slot_illegal_instruction, void)
+DEF_HELPER_0(raise_fpu_disable, void)
+DEF_HELPER_0(raise_slot_fpu_disable, void)
+DEF_HELPER_0(debug, void)
+DEF_HELPER_1(sleep, void, i32)
+DEF_HELPER_1(trapa, void, i32)
+
+DEF_HELPER_2(movcal, void, i32, i32)
+DEF_HELPER_0(discard_movcal_backup, void)
+DEF_HELPER_1(ocbi, void, i32)
+
+DEF_HELPER_2(addv, i32, i32, i32)
+DEF_HELPER_2(addc, i32, i32, i32)
+DEF_HELPER_2(subv, i32, i32, i32)
+DEF_HELPER_2(subc, i32, i32, i32)
+DEF_HELPER_2(div1, i32, i32, i32)
+DEF_HELPER_2(macl, void, i32, i32)
+DEF_HELPER_2(macw, void, i32, i32)
+
+DEF_HELPER_1(ld_fpscr, void, i32)
+
+DEF_HELPER_1(fabs_FT, f32, f32)
+DEF_HELPER_1(fabs_DT, f64, f64)
+DEF_HELPER_2(fadd_FT, f32, f32, f32)
+DEF_HELPER_2(fadd_DT, f64, f64, f64)
+DEF_HELPER_1(fcnvsd_FT_DT, f64, f32)
+DEF_HELPER_1(fcnvds_DT_FT, f32, f64)
+
+DEF_HELPER_2(fcmp_eq_FT, void, f32, f32)
+DEF_HELPER_2(fcmp_eq_DT, void, f64, f64)
+DEF_HELPER_2(fcmp_gt_FT, void, f32, f32)
+DEF_HELPER_2(fcmp_gt_DT, void, f64, f64)
+DEF_HELPER_2(fdiv_FT, f32, f32, f32)
+DEF_HELPER_2(fdiv_DT, f64, f64, f64)
+DEF_HELPER_1(float_FT, f32, i32)
+DEF_HELPER_1(float_DT, f64, i32)
+DEF_HELPER_3(fmac_FT, f32, f32, f32, f32)
+DEF_HELPER_2(fmul_FT, f32, f32, f32)
+DEF_HELPER_2(fmul_DT, f64, f64, f64)
+DEF_HELPER_1(fneg_T, f32, f32)
+DEF_HELPER_2(fsub_FT, f32, f32, f32)
+DEF_HELPER_2(fsub_DT, f64, f64, f64)
+DEF_HELPER_1(fsqrt_FT, f32, f32)
+DEF_HELPER_1(fsqrt_DT, f64, f64)
+DEF_HELPER_1(ftrc_FT, i32, f32)
+DEF_HELPER_1(ftrc_DT, i32, f64)
+DEF_HELPER_2(fipr, void, i32, i32)
+DEF_HELPER_1(ftrv, void, i32)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-sh4/machine.c b/qemu-0.15.x/target-sh4/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/qemu-0.15.x/target-sh4/op_helper.c b/qemu-0.15.x/target-sh4/op_helper.c
new file mode 100644
index 0000000..a932225
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/op_helper.c
@@ -0,0 +1,752 @@
+/*
+ *  SH4 emulation
+ *
+ *  Copyright (c) 2005 Samuel Tardieu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include "exec.h"
+#include "helper.h"
+
+static void cpu_restore_state_from_retaddr(void *retaddr)
+{
+    TranslationBlock *tb;
+    unsigned long pc;
+
+    if (retaddr) {
+        pc = (unsigned long) retaddr;
+        tb = tb_find_pc(pc);
+        if (tb) {
+            /* the PC is inside the translated code. It means that we have
+               a virtual CPU fault */
+            cpu_restore_state(tb, env, pc);
+        }
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    CPUState *saved_env;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (ret) {
+        /* now we have a real cpu fault */
+        cpu_restore_state_from_retaddr(retaddr);
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+
+#endif
+
+void helper_ldtlb(void)
+{
+#ifdef CONFIG_USER_ONLY
+    /* XXXXX */
+    cpu_abort(env, "Unhandled ldtlb");
+#else
+    cpu_load_tlb(env);
+#endif
+}
+
+static inline void raise_exception(int index, void *retaddr)
+{
+    env->exception_index = index;
+    cpu_restore_state_from_retaddr(retaddr);
+    cpu_loop_exit(env);
+}
+
+void helper_raise_illegal_instruction(void)
+{
+    raise_exception(0x180, GETPC());
+}
+
+void helper_raise_slot_illegal_instruction(void)
+{
+    raise_exception(0x1a0, GETPC());
+}
+
+void helper_raise_fpu_disable(void)
+{
+    raise_exception(0x800, GETPC());
+}
+
+void helper_raise_slot_fpu_disable(void)
+{
+    raise_exception(0x820, GETPC());
+}
+
+void helper_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
+
+void helper_sleep(uint32_t next_pc)
+{
+    env->halted = 1;
+    env->in_sleep = 1;
+    env->exception_index = EXCP_HLT;
+    env->pc = next_pc;
+    cpu_loop_exit(env);
+}
+
+void helper_trapa(uint32_t tra)
+{
+    env->tra = tra << 2;
+    raise_exception(0x160, GETPC());
+}
+
+void helper_movcal(uint32_t address, uint32_t value)
+{
+    if (cpu_sh4_is_cached (env, address))
+    {
+	memory_content *r = malloc (sizeof(memory_content));
+	r->address = address;
+	r->value = value;
+	r->next = NULL;
+
+	*(env->movcal_backup_tail) = r;
+	env->movcal_backup_tail = &(r->next);
+    }
+}
+
+void helper_discard_movcal_backup(void)
+{
+    memory_content *current = env->movcal_backup;
+
+    while(current)
+    {
+	memory_content *next = current->next;
+	free (current);
+	env->movcal_backup = current = next;
+	if (current == NULL)
+	    env->movcal_backup_tail = &(env->movcal_backup);
+    } 
+}
+
+void helper_ocbi(uint32_t address)
+{
+    memory_content **current = &(env->movcal_backup);
+    while (*current)
+    {
+	uint32_t a = (*current)->address;
+	if ((a & ~0x1F) == (address & ~0x1F))
+	{
+	    memory_content *next = (*current)->next;
+	    stl(a, (*current)->value);
+	    
+	    if (next == NULL)
+	    {
+		env->movcal_backup_tail = current;
+	    }
+
+	    free (*current);
+	    *current = next;
+	    break;
+	}
+    }
+}
+
+uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
+{
+    uint32_t tmp0, tmp1;
+
+    tmp1 = arg0 + arg1;
+    tmp0 = arg1;
+    arg1 = tmp1 + (env->sr & 1);
+    if (tmp0 > tmp1)
+	env->sr |= SR_T;
+    else
+	env->sr &= ~SR_T;
+    if (tmp1 > arg1)
+	env->sr |= SR_T;
+    return arg1;
+}
+
+uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
+{
+    uint32_t dest, src, ans;
+
+    if ((int32_t) arg1 >= 0)
+	dest = 0;
+    else
+	dest = 1;
+    if ((int32_t) arg0 >= 0)
+	src = 0;
+    else
+	src = 1;
+    src += dest;
+    arg1 += arg0;
+    if ((int32_t) arg1 >= 0)
+	ans = 0;
+    else
+	ans = 1;
+    ans += dest;
+    if (src == 0 || src == 2) {
+	if (ans == 1)
+	    env->sr |= SR_T;
+	else
+	    env->sr &= ~SR_T;
+    } else
+	env->sr &= ~SR_T;
+    return arg1;
+}
+
+#define T (env->sr & SR_T)
+#define Q (env->sr & SR_Q ? 1 : 0)
+#define M (env->sr & SR_M ? 1 : 0)
+#define SETT env->sr |= SR_T
+#define CLRT env->sr &= ~SR_T
+#define SETQ env->sr |= SR_Q
+#define CLRQ env->sr &= ~SR_Q
+#define SETM env->sr |= SR_M
+#define CLRM env->sr &= ~SR_M
+
+uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
+{
+    uint32_t tmp0, tmp2;
+    uint8_t old_q, tmp1 = 0xff;
+
+    //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
+    old_q = Q;
+    if ((0x80000000 & arg1) != 0)
+	SETQ;
+    else
+	CLRQ;
+    tmp2 = arg0;
+    arg1 <<= 1;
+    arg1 |= T;
+    switch (old_q) {
+    case 0:
+	switch (M) {
+	case 0:
+	    tmp0 = arg1;
+	    arg1 -= tmp2;
+	    tmp1 = arg1 > tmp0;
+	    switch (Q) {
+	    case 0:
+		if (tmp1)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    case 1:
+		if (tmp1 == 0)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    }
+	    break;
+	case 1:
+	    tmp0 = arg1;
+	    arg1 += tmp2;
+	    tmp1 = arg1 < tmp0;
+	    switch (Q) {
+	    case 0:
+		if (tmp1 == 0)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    case 1:
+		if (tmp1)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    }
+	    break;
+	}
+	break;
+    case 1:
+	switch (M) {
+	case 0:
+	    tmp0 = arg1;
+	    arg1 += tmp2;
+	    tmp1 = arg1 < tmp0;
+	    switch (Q) {
+	    case 0:
+		if (tmp1)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    case 1:
+		if (tmp1 == 0)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    }
+	    break;
+	case 1:
+	    tmp0 = arg1;
+	    arg1 -= tmp2;
+	    tmp1 = arg1 > tmp0;
+	    switch (Q) {
+	    case 0:
+		if (tmp1 == 0)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    case 1:
+		if (tmp1)
+		    SETQ;
+		else
+		    CLRQ;
+		break;
+	    }
+	    break;
+	}
+	break;
+    }
+    if (Q == M)
+	SETT;
+    else
+	CLRT;
+    //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
+    return arg1;
+}
+
+void helper_macl(uint32_t arg0, uint32_t arg1)
+{
+    int64_t res;
+
+    res = ((uint64_t) env->mach << 32) | env->macl;
+    res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
+    env->mach = (res >> 32) & 0xffffffff;
+    env->macl = res & 0xffffffff;
+    if (env->sr & SR_S) {
+	if (res < 0)
+	    env->mach |= 0xffff0000;
+	else
+	    env->mach &= 0x00007fff;
+    }
+}
+
+void helper_macw(uint32_t arg0, uint32_t arg1)
+{
+    int64_t res;
+
+    res = ((uint64_t) env->mach << 32) | env->macl;
+    res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
+    env->mach = (res >> 32) & 0xffffffff;
+    env->macl = res & 0xffffffff;
+    if (env->sr & SR_S) {
+	if (res < -0x80000000) {
+	    env->mach = 1;
+	    env->macl = 0x80000000;
+	} else if (res > 0x000000007fffffff) {
+	    env->mach = 1;
+	    env->macl = 0x7fffffff;
+	}
+    }
+}
+
+uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
+{
+    uint32_t tmp0, tmp1;
+
+    tmp1 = arg1 - arg0;
+    tmp0 = arg1;
+    arg1 = tmp1 - (env->sr & SR_T);
+    if (tmp0 < tmp1)
+	env->sr |= SR_T;
+    else
+	env->sr &= ~SR_T;
+    if (tmp1 < arg1)
+	env->sr |= SR_T;
+    return arg1;
+}
+
+uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
+{
+    int32_t dest, src, ans;
+
+    if ((int32_t) arg1 >= 0)
+	dest = 0;
+    else
+	dest = 1;
+    if ((int32_t) arg0 >= 0)
+	src = 0;
+    else
+	src = 1;
+    src += dest;
+    arg1 -= arg0;
+    if ((int32_t) arg1 >= 0)
+	ans = 0;
+    else
+	ans = 1;
+    ans += dest;
+    if (src == 1) {
+	if (ans == 1)
+	    env->sr |= SR_T;
+	else
+	    env->sr &= ~SR_T;
+    } else
+	env->sr &= ~SR_T;
+    return arg1;
+}
+
+static inline void set_t(void)
+{
+    env->sr |= SR_T;
+}
+
+static inline void clr_t(void)
+{
+    env->sr &= ~SR_T;
+}
+
+void helper_ld_fpscr(uint32_t val)
+{
+    env->fpscr = val & FPSCR_MASK;
+    if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
+	set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+    } else {
+	set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    }
+    set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
+}
+
+static void update_fpscr(void *retaddr)
+{
+    int xcpt, cause, enable;
+
+    xcpt = get_float_exception_flags(&env->fp_status);
+
+    /* Clear the flag entries */
+    env->fpscr &= ~FPSCR_FLAG_MASK;
+
+    if (unlikely(xcpt)) {
+        if (xcpt & float_flag_invalid) {
+            env->fpscr |= FPSCR_FLAG_V;
+        }
+        if (xcpt & float_flag_divbyzero) {
+            env->fpscr |= FPSCR_FLAG_Z;
+        }
+        if (xcpt & float_flag_overflow) {
+            env->fpscr |= FPSCR_FLAG_O;
+        }
+        if (xcpt & float_flag_underflow) {
+            env->fpscr |= FPSCR_FLAG_U;
+        }
+        if (xcpt & float_flag_inexact) {
+            env->fpscr |= FPSCR_FLAG_I;
+        }
+
+        /* Accumulate in cause entries */
+        env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
+                      << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
+
+        /* Generate an exception if enabled */
+        cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
+        enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
+        if (cause & enable) {
+            cpu_restore_state_from_retaddr(retaddr);
+            env->exception_index = 0x120;
+            cpu_loop_exit(env);
+        }
+    }
+}
+
+float32 helper_fabs_FT(float32 t0)
+{
+    return float32_abs(t0);
+}
+
+float64 helper_fabs_DT(float64 t0)
+{
+    return float64_abs(t0);
+}
+
+float32 helper_fadd_FT(float32 t0, float32 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_add(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float64 helper_fadd_DT(float64 t0, float64 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float64_add(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+void helper_fcmp_eq_FT(float32 t0, float32 t1)
+{
+    int relation;
+
+    set_float_exception_flags(0, &env->fp_status);
+    relation = float32_compare(t0, t1, &env->fp_status);
+    if (unlikely(relation == float_relation_unordered)) {
+        update_fpscr(GETPC());
+    } else if (relation == float_relation_equal) {
+	set_t();
+    } else {
+	clr_t();
+    }
+}
+
+void helper_fcmp_eq_DT(float64 t0, float64 t1)
+{
+    int relation;
+
+    set_float_exception_flags(0, &env->fp_status);
+    relation = float64_compare(t0, t1, &env->fp_status);
+    if (unlikely(relation == float_relation_unordered)) {
+        update_fpscr(GETPC());
+    } else if (relation == float_relation_equal) {
+	set_t();
+    } else {
+	clr_t();
+    }
+}
+
+void helper_fcmp_gt_FT(float32 t0, float32 t1)
+{
+    int relation;
+
+    set_float_exception_flags(0, &env->fp_status);
+    relation = float32_compare(t0, t1, &env->fp_status);
+    if (unlikely(relation == float_relation_unordered)) {
+        update_fpscr(GETPC());
+    } else if (relation == float_relation_greater) {
+	set_t();
+    } else {
+	clr_t();
+    }
+}
+
+void helper_fcmp_gt_DT(float64 t0, float64 t1)
+{
+    int relation;
+
+    set_float_exception_flags(0, &env->fp_status);
+    relation = float64_compare(t0, t1, &env->fp_status);
+    if (unlikely(relation == float_relation_unordered)) {
+        update_fpscr(GETPC());
+    } else if (relation == float_relation_greater) {
+	set_t();
+    } else {
+	clr_t();
+    }
+}
+
+float64 helper_fcnvsd_FT_DT(float32 t0)
+{
+    float64 ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = float32_to_float64(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+float32 helper_fcnvds_DT_FT(float64 t0)
+{
+    float32 ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = float64_to_float32(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+float32 helper_fdiv_FT(float32 t0, float32 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_div(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float64 helper_fdiv_DT(float64 t0, float64 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float64_div(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float32 helper_float_FT(uint32_t t0)
+{
+    float32 ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = int32_to_float32(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+float64 helper_float_DT(uint32_t t0)
+{
+    float64 ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = int32_to_float64(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_mul(t0, t1, &env->fp_status);
+    t0 = float32_add(t0, t2, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float32 helper_fmul_FT(float32 t0, float32 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_mul(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float64 helper_fmul_DT(float64 t0, float64 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float64_mul(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float32 helper_fneg_T(float32 t0)
+{
+    return float32_chs(t0);
+}
+
+float32 helper_fsqrt_FT(float32 t0)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_sqrt(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float64 helper_fsqrt_DT(float64 t0)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float64_sqrt(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float32 helper_fsub_FT(float32 t0, float32 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float32_sub(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+float64 helper_fsub_DT(float64 t0, float64 t1)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    t0 = float64_sub(t0, t1, &env->fp_status);
+    update_fpscr(GETPC());
+    return t0;
+}
+
+uint32_t helper_ftrc_FT(float32 t0)
+{
+    uint32_t ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+uint32_t helper_ftrc_DT(float64 t0)
+{
+    uint32_t ret;
+    set_float_exception_flags(0, &env->fp_status);
+    ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
+    update_fpscr(GETPC());
+    return ret;
+}
+
+void helper_fipr(uint32_t m, uint32_t n)
+{
+    int bank, i;
+    float32 r, p;
+
+    bank = (env->sr & FPSCR_FR) ? 16 : 0;
+    r = float32_zero;
+    set_float_exception_flags(0, &env->fp_status);
+
+    for (i = 0 ; i < 4 ; i++) {
+        p = float32_mul(env->fregs[bank + m + i],
+                        env->fregs[bank + n + i],
+                        &env->fp_status);
+        r = float32_add(r, p, &env->fp_status);
+    }
+    update_fpscr(GETPC());
+
+    env->fregs[bank + n + 3] = r;
+}
+
+void helper_ftrv(uint32_t n)
+{
+    int bank_matrix, bank_vector;
+    int i, j;
+    float32 r[4];
+    float32 p;
+
+    bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
+    bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
+    set_float_exception_flags(0, &env->fp_status);
+    for (i = 0 ; i < 4 ; i++) {
+        r[i] = float32_zero;
+        for (j = 0 ; j < 4 ; j++) {
+            p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
+                            env->fregs[bank_vector + j],
+                            &env->fp_status);
+            r[i] = float32_add(r[i], p, &env->fp_status);
+        }
+    }
+    update_fpscr(GETPC());
+
+    for (i = 0 ; i < 4 ; i++) {
+        env->fregs[bank_vector + i] = r[i];
+    }
+}
diff --git a/qemu-0.15.x/target-sh4/translate.c b/qemu-0.15.x/target-sh4/translate.c
new file mode 100644
index 0000000..569bc73
--- /dev/null
+++ b/qemu-0.15.x/target-sh4/translate.c
@@ -0,0 +1,2075 @@
+/*
+ *  SH4 translation
+ *
+ *  Copyright (c) 2005 Samuel Tardieu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define DEBUG_DISAS
+#define SH4_DEBUG_DISAS
+//#define SH4_SINGLE_STEP
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    target_ulong pc;
+    uint32_t sr;
+    uint32_t fpscr;
+    uint16_t opcode;
+    uint32_t flags;
+    int bstate;
+    int memidx;
+    uint32_t delayed_pc;
+    int singlestep_enabled;
+    uint32_t features;
+    int has_movcal;
+} DisasContext;
+
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(ctx) 1
+#else
+#define IS_USER(ctx) (!(ctx->sr & SR_MD))
+#endif
+
+enum {
+    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
+                      * exception condition
+                      */
+    BS_STOP     = 1, /* We want to stop translation for any reason */
+    BS_BRANCH   = 2, /* We reached a branch condition     */
+    BS_EXCP     = 3, /* We reached an exception condition */
+};
+
+/* global register indexes */
+static TCGv_ptr cpu_env;
+static TCGv cpu_gregs[24];
+static TCGv cpu_pc, cpu_sr, cpu_ssr, cpu_spc, cpu_gbr;
+static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl;
+static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst;
+static TCGv cpu_fregs[32];
+
+/* internal register indexes */
+static TCGv cpu_flags, cpu_delayed_pc;
+
+static uint32_t gen_opc_hflags[OPC_BUF_SIZE];
+
+#include "gen-icount.h"
+
+static void sh4_translate_init(void)
+{
+    int i;
+    static int done_init = 0;
+    static const char * const gregnames[24] = {
+        "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
+        "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
+        "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+        "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
+        "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
+    };
+    static const char * const fregnames[32] = {
+         "FPR0_BANK0",  "FPR1_BANK0",  "FPR2_BANK0",  "FPR3_BANK0",
+         "FPR4_BANK0",  "FPR5_BANK0",  "FPR6_BANK0",  "FPR7_BANK0",
+         "FPR8_BANK0",  "FPR9_BANK0", "FPR10_BANK0", "FPR11_BANK0",
+        "FPR12_BANK0", "FPR13_BANK0", "FPR14_BANK0", "FPR15_BANK0",
+         "FPR0_BANK1",  "FPR1_BANK1",  "FPR2_BANK1",  "FPR3_BANK1",
+         "FPR4_BANK1",  "FPR5_BANK1",  "FPR6_BANK1",  "FPR7_BANK1",
+         "FPR8_BANK1",  "FPR9_BANK1", "FPR10_BANK1", "FPR11_BANK1",
+        "FPR12_BANK1", "FPR13_BANK1", "FPR14_BANK1", "FPR15_BANK1",
+    };
+
+    if (done_init)
+        return;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < 24; i++)
+        cpu_gregs[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                              offsetof(CPUState, gregs[i]),
+                                              gregnames[i]);
+
+    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
+                                    offsetof(CPUState, pc), "PC");
+    cpu_sr = tcg_global_mem_new_i32(TCG_AREG0,
+                                    offsetof(CPUState, sr), "SR");
+    cpu_ssr = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, ssr), "SSR");
+    cpu_spc = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, spc), "SPC");
+    cpu_gbr = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, gbr), "GBR");
+    cpu_vbr = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, vbr), "VBR");
+    cpu_sgr = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, sgr), "SGR");
+    cpu_dbr = tcg_global_mem_new_i32(TCG_AREG0,
+                                     offsetof(CPUState, dbr), "DBR");
+    cpu_mach = tcg_global_mem_new_i32(TCG_AREG0,
+                                      offsetof(CPUState, mach), "MACH");
+    cpu_macl = tcg_global_mem_new_i32(TCG_AREG0,
+                                      offsetof(CPUState, macl), "MACL");
+    cpu_pr = tcg_global_mem_new_i32(TCG_AREG0,
+                                    offsetof(CPUState, pr), "PR");
+    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
+                                       offsetof(CPUState, fpscr), "FPSCR");
+    cpu_fpul = tcg_global_mem_new_i32(TCG_AREG0,
+                                      offsetof(CPUState, fpul), "FPUL");
+
+    cpu_flags = tcg_global_mem_new_i32(TCG_AREG0,
+				       offsetof(CPUState, flags), "_flags_");
+    cpu_delayed_pc = tcg_global_mem_new_i32(TCG_AREG0,
+					    offsetof(CPUState, delayed_pc),
+					    "_delayed_pc_");
+    cpu_ldst = tcg_global_mem_new_i32(TCG_AREG0,
+				      offsetof(CPUState, ldst), "_ldst_");
+
+    for (i = 0; i < 32; i++)
+        cpu_fregs[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                              offsetof(CPUState, fregs[i]),
+                                              fregnames[i]);
+
+    /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+
+    done_init = 1;
+}
+
+void cpu_dump_state(CPUState * env, FILE * f,
+		    int (*cpu_fprintf) (FILE * f, const char *fmt, ...),
+		    int flags)
+{
+    int i;
+    cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n",
+		env->pc, env->sr, env->pr, env->fpscr);
+    cpu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n",
+		env->spc, env->ssr, env->gbr, env->vbr);
+    cpu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n",
+		env->sgr, env->dbr, env->delayed_pc, env->fpul);
+    for (i = 0; i < 24; i += 4) {
+	cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
+		    i, env->gregs[i], i + 1, env->gregs[i + 1],
+		    i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]);
+    }
+    if (env->flags & DELAY_SLOT) {
+	cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n",
+		    env->delayed_pc);
+    } else if (env->flags & DELAY_SLOT_CONDITIONAL) {
+	cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n",
+		    env->delayed_pc);
+    }
+}
+
+void cpu_reset(CPUSH4State * env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    memset(env, 0, offsetof(CPUSH4State, breakpoints));
+    tlb_flush(env, 1);
+
+    env->pc = 0xA0000000;
+#if defined(CONFIG_USER_ONLY)
+    env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */
+#else
+    env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0;
+    env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */
+    set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+    set_flush_to_zero(1, &env->fp_status);
+#endif
+    set_default_nan_mode(1, &env->fp_status);
+}
+
+typedef struct {
+    const char *name;
+    int id;
+    uint32_t pvr;
+    uint32_t prr;
+    uint32_t cvr;
+    uint32_t features;
+} sh4_def_t;
+
+static sh4_def_t sh4_defs[] = {
+    {
+	.name = "SH7750R",
+	.id = SH_CPU_SH7750R,
+	.pvr = 0x00050000,
+	.prr = 0x00000100,
+	.cvr = 0x00110000,
+	.features = SH_FEATURE_BCR3_AND_BCR4,
+    }, {
+	.name = "SH7751R",
+	.id = SH_CPU_SH7751R,
+	.pvr = 0x04050005,
+	.prr = 0x00000113,
+	.cvr = 0x00110000,	/* Neutered caches, should be 0x20480000 */
+	.features = SH_FEATURE_BCR3_AND_BCR4,
+    }, {
+	.name = "SH7785",
+	.id = SH_CPU_SH7785,
+	.pvr = 0x10300700,
+	.prr = 0x00000200,
+	.cvr = 0x71440211,
+	.features = SH_FEATURE_SH4A,
+     },
+};
+
+static const sh4_def_t *cpu_sh4_find_by_name(const char *name)
+{
+    int i;
+
+    if (strcasecmp(name, "any") == 0)
+	return &sh4_defs[0];
+
+    for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
+	if (strcasecmp(name, sh4_defs[i].name) == 0)
+	    return &sh4_defs[i];
+
+    return NULL;
+}
+
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
+	(*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
+}
+
+static void cpu_register(CPUSH4State *env, const sh4_def_t *def)
+{
+    env->pvr = def->pvr;
+    env->prr = def->prr;
+    env->cvr = def->cvr;
+    env->id = def->id;
+}
+
+CPUSH4State *cpu_sh4_init(const char *cpu_model)
+{
+    CPUSH4State *env;
+    const sh4_def_t *def;
+
+    def = cpu_sh4_find_by_name(cpu_model);
+    if (!def)
+	return NULL;
+    env = qemu_mallocz(sizeof(CPUSH4State));
+    env->features = def->features;
+    cpu_exec_init(env);
+    env->movcal_backup_tail = &(env->movcal_backup);
+    sh4_translate_init();
+    env->cpu_model_str = cpu_model;
+    cpu_reset(env);
+    cpu_register(env, def);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+	!ctx->singlestep_enabled) {
+	/* Use a direct jump if in same page and singlestep not enabled */
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_i32(cpu_pc, dest);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_i32(cpu_pc, dest);
+        if (ctx->singlestep_enabled)
+            gen_helper_debug();
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void gen_jump(DisasContext * ctx)
+{
+    if (ctx->delayed_pc == (uint32_t) - 1) {
+	/* Target is not statically known, it comes necessarily from a
+	   delayed jump as immediate jump are conditinal jumps */
+	tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
+	if (ctx->singlestep_enabled)
+	    gen_helper_debug();
+	tcg_gen_exit_tb(0);
+    } else {
+	gen_goto_tb(ctx, 0, ctx->delayed_pc);
+    }
+}
+
+static inline void gen_branch_slot(uint32_t delayed_pc, int t)
+{
+    TCGv sr;
+    int label = gen_new_label();
+    tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc);
+    sr = tcg_temp_new();
+    tcg_gen_andi_i32(sr, cpu_sr, SR_T);
+    tcg_gen_brcondi_i32(t ? TCG_COND_EQ:TCG_COND_NE, sr, 0, label);
+    tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE);
+    gen_set_label(label);
+}
+
+/* Immediate conditional jump (bt or bf) */
+static void gen_conditional_jump(DisasContext * ctx,
+				 target_ulong ift, target_ulong ifnott)
+{
+    int l1;
+    TCGv sr;
+
+    l1 = gen_new_label();
+    sr = tcg_temp_new();
+    tcg_gen_andi_i32(sr, cpu_sr, SR_T);
+    tcg_gen_brcondi_i32(TCG_COND_NE, sr, 0, l1);
+    gen_goto_tb(ctx, 0, ifnott);
+    gen_set_label(l1);
+    gen_goto_tb(ctx, 1, ift);
+}
+
+/* Delayed conditional jump (bt or bf) */
+static void gen_delayed_conditional_jump(DisasContext * ctx)
+{
+    int l1;
+    TCGv ds;
+
+    l1 = gen_new_label();
+    ds = tcg_temp_new();
+    tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE);
+    tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
+    gen_goto_tb(ctx, 1, ctx->pc + 2);
+    gen_set_label(l1);
+    tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE);
+    gen_jump(ctx);
+}
+
+static inline void gen_set_t(void)
+{
+    tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T);
+}
+
+static inline void gen_clr_t(void)
+{
+    tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+}
+
+static inline void gen_cmp(int cond, TCGv t0, TCGv t1)
+{
+    TCGv t;
+
+    t = tcg_temp_new();
+    tcg_gen_setcond_i32(cond, t, t1, t0);
+    tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+    tcg_gen_or_i32(cpu_sr, cpu_sr, t);
+
+    tcg_temp_free(t);
+}
+
+static inline void gen_cmp_imm(int cond, TCGv t0, int32_t imm)
+{
+    TCGv t;
+
+    t = tcg_temp_new();
+    tcg_gen_setcondi_i32(cond, t, t0, imm);
+    tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+    tcg_gen_or_i32(cpu_sr, cpu_sr, t);
+
+    tcg_temp_free(t);
+}
+
+static inline void gen_store_flags(uint32_t flags)
+{
+    tcg_gen_andi_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE);
+    tcg_gen_ori_i32(cpu_flags, cpu_flags, flags);
+}
+
+static inline void gen_copy_bit_i32(TCGv t0, int p0, TCGv t1, int p1)
+{
+    TCGv tmp = tcg_temp_new();
+
+    p0 &= 0x1f;
+    p1 &= 0x1f;
+
+    tcg_gen_andi_i32(tmp, t1, (1 << p1));
+    tcg_gen_andi_i32(t0, t0, ~(1 << p0));
+    if (p0 < p1)
+        tcg_gen_shri_i32(tmp, tmp, p1 - p0);
+    else if (p0 > p1)
+        tcg_gen_shli_i32(tmp, tmp, p0 - p1);
+    tcg_gen_or_i32(t0, t0, tmp);
+
+    tcg_temp_free(tmp);
+}
+
+static inline void gen_load_fpr64(TCGv_i64 t, int reg)
+{
+    tcg_gen_concat_i32_i64(t, cpu_fregs[reg + 1], cpu_fregs[reg]);
+}
+
+static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(tmp, t);
+    tcg_gen_mov_i32(cpu_fregs[reg + 1], tmp);
+    tcg_gen_shri_i64(t, t, 32);
+    tcg_gen_trunc_i64_i32(tmp, t);
+    tcg_gen_mov_i32(cpu_fregs[reg], tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+#define B3_0 (ctx->opcode & 0xf)
+#define B6_4 ((ctx->opcode >> 4) & 0x7)
+#define B7_4 ((ctx->opcode >> 4) & 0xf)
+#define B7_0 (ctx->opcode & 0xff)
+#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff))
+#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \
+  (ctx->opcode & 0xfff))
+#define B11_8 ((ctx->opcode >> 8) & 0xf)
+#define B15_12 ((ctx->opcode >> 12) & 0xf)
+
+#define REG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB) ? \
+		(cpu_gregs[x + 16]) : (cpu_gregs[x]))
+
+#define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \
+		? (cpu_gregs[x + 16]) : (cpu_gregs[x]))
+
+#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
+#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
+#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
+#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
+
+#define CHECK_NOT_DELAY_SLOT \
+  if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL))     \
+  {                                                           \
+      gen_helper_raise_slot_illegal_instruction();            \
+      ctx->bstate = BS_EXCP;                                  \
+      return;                                                 \
+  }
+
+#define CHECK_PRIVILEGED                                        \
+  if (IS_USER(ctx)) {                                           \
+      if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
+         gen_helper_raise_slot_illegal_instruction();           \
+      } else {                                                  \
+         gen_helper_raise_illegal_instruction();                \
+      }                                                         \
+      ctx->bstate = BS_EXCP;                                    \
+      return;                                                   \
+  }
+
+#define CHECK_FPU_ENABLED                                       \
+  if (ctx->flags & SR_FD) {                                     \
+      if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
+          gen_helper_raise_slot_fpu_disable();                  \
+      } else {                                                  \
+          gen_helper_raise_fpu_disable();                       \
+      }                                                         \
+      ctx->bstate = BS_EXCP;                                    \
+      return;                                                   \
+  }
+
+static void _decode_opc(DisasContext * ctx)
+{
+    /* This code tries to make movcal emulation sufficiently
+       accurate for Linux purposes.  This instruction writes
+       memory, and prior to that, always allocates a cache line.
+       It is used in two contexts:
+       - in memcpy, where data is copied in blocks, the first write
+       of to a block uses movca.l for performance.
+       - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used
+       to flush the cache. Here, the data written by movcal.l is never
+       written to memory, and the data written is just bogus.
+
+       To simulate this, we simulate movcal.l, we store the value to memory,
+       but we also remember the previous content. If we see ocbi, we check
+       if movcal.l for that address was done previously. If so, the write should
+       not have hit the memory, so we restore the previous content.
+       When we see an instruction that is neither movca.l
+       nor ocbi, the previous content is discarded.
+
+       To optimize, we only try to flush stores when we're at the start of
+       TB, or if we already saw movca.l in this TB and did not flush stores
+       yet.  */
+    if (ctx->has_movcal)
+	{
+	  int opcode = ctx->opcode & 0xf0ff;
+	  if (opcode != 0x0093 /* ocbi */
+	      && opcode != 0x00c3 /* movca.l */)
+	      {
+		  gen_helper_discard_movcal_backup ();
+		  ctx->has_movcal = 0;
+	      }
+	}
+
+#if 0
+    fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
+#endif
+
+    switch (ctx->opcode) {
+    case 0x0019:		/* div0u */
+	tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(SR_M | SR_Q | SR_T));
+	return;
+    case 0x000b:		/* rts */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr);
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x0028:		/* clrmac */
+	tcg_gen_movi_i32(cpu_mach, 0);
+	tcg_gen_movi_i32(cpu_macl, 0);
+	return;
+    case 0x0048:		/* clrs */
+	tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_S);
+	return;
+    case 0x0008:		/* clrt */
+	gen_clr_t();
+	return;
+    case 0x0038:		/* ldtlb */
+	CHECK_PRIVILEGED
+	gen_helper_ldtlb();
+	return;
+    case 0x002b:		/* rte */
+	CHECK_PRIVILEGED
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_mov_i32(cpu_sr, cpu_ssr);
+	tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x0058:		/* sets */
+	tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_S);
+	return;
+    case 0x0018:		/* sett */
+	gen_set_t();
+	return;
+    case 0xfbfd:		/* frchg */
+	tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR);
+	ctx->bstate = BS_STOP;
+	return;
+    case 0xf3fd:		/* fschg */
+	tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ);
+	ctx->bstate = BS_STOP;
+	return;
+    case 0x0009:		/* nop */
+	return;
+    case 0x001b:		/* sleep */
+	CHECK_PRIVILEGED
+	gen_helper_sleep(tcg_const_i32(ctx->pc + 2));
+	return;
+    }
+
+    switch (ctx->opcode & 0xf000) {
+    case 0x1000:		/* mov.l Rm,@(disp,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4);
+	    tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x5000:		/* mov.l @(disp,Rm),Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4);
+	    tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xe000:		/* mov #imm,Rn */
+	tcg_gen_movi_i32(REG(B11_8), B7_0s);
+	return;
+    case 0x9000:		/* mov.w @(disp,PC),Rn */
+	{
+	    TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2);
+	    tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xd000:		/* mov.l @(disp,PC),Rn */
+	{
+	    TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3);
+	    tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x7000:		/* add #imm,Rn */
+	tcg_gen_addi_i32(REG(B11_8), REG(B11_8), B7_0s);
+	return;
+    case 0xa000:		/* bra disp */
+	CHECK_NOT_DELAY_SLOT
+	ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
+	tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
+	ctx->flags |= DELAY_SLOT;
+	return;
+    case 0xb000:		/* bsr disp */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
+	ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
+	tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
+	ctx->flags |= DELAY_SLOT;
+	return;
+    }
+
+    switch (ctx->opcode & 0xf00f) {
+    case 0x6003:		/* mov Rm,Rn */
+	tcg_gen_mov_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x2000:		/* mov.b Rm, at Rn */
+	tcg_gen_qemu_st8(REG(B7_4), REG(B11_8), ctx->memidx);
+	return;
+    case 0x2001:		/* mov.w Rm, at Rn */
+	tcg_gen_qemu_st16(REG(B7_4), REG(B11_8), ctx->memidx);
+	return;
+    case 0x2002:		/* mov.l Rm, at Rn */
+	tcg_gen_qemu_st32(REG(B7_4), REG(B11_8), ctx->memidx);
+	return;
+    case 0x6000:		/* mov.b @Rm,Rn */
+	tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx);
+	return;
+    case 0x6001:		/* mov.w @Rm,Rn */
+	tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx);
+	return;
+    case 0x6002:		/* mov.l @Rm,Rn */
+	tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx);
+	return;
+    case 0x2004:		/* mov.b Rm, at -Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 1);
+	    tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx);	/* might cause re-execution */
+	    tcg_gen_mov_i32(REG(B11_8), addr);			/* modify register status */
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x2005:		/* mov.w Rm, at -Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 2);
+	    tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x2006:		/* mov.l Rm, at -Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	}
+	return;
+    case 0x6004:		/* mov.b @Rm+,Rn */
+	tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx);
+	if ( B11_8 != B7_4 )
+		tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1);
+	return;
+    case 0x6005:		/* mov.w @Rm+,Rn */
+	tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx);
+	if ( B11_8 != B7_4 )
+		tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
+	return;
+    case 0x6006:		/* mov.l @Rm+,Rn */
+	tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx);
+	if ( B11_8 != B7_4 )
+		tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
+	return;
+    case 0x0004:		/* mov.b Rm,@(R0,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B11_8), REG(0));
+	    tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x0005:		/* mov.w Rm,@(R0,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B11_8), REG(0));
+	    tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x0006:		/* mov.l Rm,@(R0,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B11_8), REG(0));
+	    tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x000c:		/* mov.b @(R0,Rm),Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B7_4), REG(0));
+	    tcg_gen_qemu_ld8s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x000d:		/* mov.w @(R0,Rm),Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B7_4), REG(0));
+	    tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x000e:		/* mov.l @(R0,Rm),Rn */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B7_4), REG(0));
+	    tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x6008:		/* swap.b Rm,Rn */
+	{
+	    TCGv high, low;
+	    high = tcg_temp_new();
+	    tcg_gen_andi_i32(high, REG(B7_4), 0xffff0000);
+	    low = tcg_temp_new();
+	    tcg_gen_ext16u_i32(low, REG(B7_4));
+	    tcg_gen_bswap16_i32(low, low);
+	    tcg_gen_or_i32(REG(B11_8), high, low);
+	    tcg_temp_free(low);
+	    tcg_temp_free(high);
+	}
+	return;
+    case 0x6009:		/* swap.w Rm,Rn */
+	{
+	    TCGv high, low;
+	    high = tcg_temp_new();
+	    tcg_gen_shli_i32(high, REG(B7_4), 16);
+	    low = tcg_temp_new();
+	    tcg_gen_shri_i32(low, REG(B7_4), 16);
+	    tcg_gen_ext16u_i32(low, low);
+	    tcg_gen_or_i32(REG(B11_8), high, low);
+	    tcg_temp_free(low);
+	    tcg_temp_free(high);
+	}
+	return;
+    case 0x200d:		/* xtrct Rm,Rn */
+	{
+	    TCGv high, low;
+	    high = tcg_temp_new();
+	    tcg_gen_shli_i32(high, REG(B7_4), 16);
+	    low = tcg_temp_new();
+	    tcg_gen_shri_i32(low, REG(B11_8), 16);
+	    tcg_gen_ext16u_i32(low, low);
+	    tcg_gen_or_i32(REG(B11_8), high, low);
+	    tcg_temp_free(low);
+	    tcg_temp_free(high);
+	}
+	return;
+    case 0x300c:		/* add Rm,Rn */
+	tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4));
+	return;
+    case 0x300e:		/* addc Rm,Rn */
+	gen_helper_addc(REG(B11_8), REG(B7_4), REG(B11_8));
+	return;
+    case 0x300f:		/* addv Rm,Rn */
+	gen_helper_addv(REG(B11_8), REG(B7_4), REG(B11_8));
+	return;
+    case 0x2009:		/* and Rm,Rn */
+	tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4));
+	return;
+    case 0x3000:		/* cmp/eq Rm,Rn */
+	gen_cmp(TCG_COND_EQ, REG(B7_4), REG(B11_8));
+	return;
+    case 0x3003:		/* cmp/ge Rm,Rn */
+	gen_cmp(TCG_COND_GE, REG(B7_4), REG(B11_8));
+	return;
+    case 0x3007:		/* cmp/gt Rm,Rn */
+	gen_cmp(TCG_COND_GT, REG(B7_4), REG(B11_8));
+	return;
+    case 0x3006:		/* cmp/hi Rm,Rn */
+	gen_cmp(TCG_COND_GTU, REG(B7_4), REG(B11_8));
+	return;
+    case 0x3002:		/* cmp/hs Rm,Rn */
+	gen_cmp(TCG_COND_GEU, REG(B7_4), REG(B11_8));
+	return;
+    case 0x200c:		/* cmp/str Rm,Rn */
+	{
+	    TCGv cmp1 = tcg_temp_new();
+	    TCGv cmp2 = tcg_temp_new();
+	    tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+	    tcg_gen_xor_i32(cmp1, REG(B7_4), REG(B11_8));
+	    tcg_gen_andi_i32(cmp2, cmp1, 0xff000000);
+	    tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+	    tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
+	    tcg_gen_andi_i32(cmp2, cmp1, 0x00ff0000);
+	    tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+	    tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
+	    tcg_gen_andi_i32(cmp2, cmp1, 0x0000ff00);
+	    tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+	    tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
+	    tcg_gen_andi_i32(cmp2, cmp1, 0x000000ff);
+	    tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+	    tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
+	    tcg_temp_free(cmp2);
+	    tcg_temp_free(cmp1);
+	}
+	return;
+    case 0x2007:		/* div0s Rm,Rn */
+	{
+	    gen_copy_bit_i32(cpu_sr, 8, REG(B11_8), 31);	/* SR_Q */
+	    gen_copy_bit_i32(cpu_sr, 9, REG(B7_4), 31);		/* SR_M */
+	    TCGv val = tcg_temp_new();
+	    tcg_gen_xor_i32(val, REG(B7_4), REG(B11_8));
+	    gen_copy_bit_i32(cpu_sr, 0, val, 31);		/* SR_T */
+	    tcg_temp_free(val);
+	}
+	return;
+    case 0x3004:		/* div1 Rm,Rn */
+	gen_helper_div1(REG(B11_8), REG(B7_4), REG(B11_8));
+	return;
+    case 0x300d:		/* dmuls.l Rm,Rn */
+	{
+	    TCGv_i64 tmp1 = tcg_temp_new_i64();
+	    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+	    tcg_gen_ext_i32_i64(tmp1, REG(B7_4));
+	    tcg_gen_ext_i32_i64(tmp2, REG(B11_8));
+	    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+	    tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
+	    tcg_gen_shri_i64(tmp1, tmp1, 32);
+	    tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
+
+	    tcg_temp_free_i64(tmp2);
+	    tcg_temp_free_i64(tmp1);
+	}
+	return;
+    case 0x3005:		/* dmulu.l Rm,Rn */
+	{
+	    TCGv_i64 tmp1 = tcg_temp_new_i64();
+	    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+	    tcg_gen_extu_i32_i64(tmp1, REG(B7_4));
+	    tcg_gen_extu_i32_i64(tmp2, REG(B11_8));
+	    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+	    tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
+	    tcg_gen_shri_i64(tmp1, tmp1, 32);
+	    tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
+
+	    tcg_temp_free_i64(tmp2);
+	    tcg_temp_free_i64(tmp1);
+	}
+	return;
+    case 0x600e:		/* exts.b Rm,Rn */
+	tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x600f:		/* exts.w Rm,Rn */
+	tcg_gen_ext16s_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x600c:		/* extu.b Rm,Rn */
+	tcg_gen_ext8u_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x600d:		/* extu.w Rm,Rn */
+	tcg_gen_ext16u_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x000f:		/* mac.l @Rm+, at Rn+ */
+	{
+	    TCGv arg0, arg1;
+	    arg0 = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx);
+	    arg1 = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx);
+	    gen_helper_macl(arg0, arg1);
+	    tcg_temp_free(arg1);
+	    tcg_temp_free(arg0);
+	    tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
+	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+	}
+	return;
+    case 0x400f:		/* mac.w @Rm+, at Rn+ */
+	{
+	    TCGv arg0, arg1;
+	    arg0 = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx);
+	    arg1 = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx);
+	    gen_helper_macw(arg0, arg1);
+	    tcg_temp_free(arg1);
+	    tcg_temp_free(arg0);
+	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
+	    tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
+	}
+	return;
+    case 0x0007:		/* mul.l Rm,Rn */
+	tcg_gen_mul_i32(cpu_macl, REG(B7_4), REG(B11_8));
+	return;
+    case 0x200f:		/* muls.w Rm,Rn */
+	{
+	    TCGv arg0, arg1;
+	    arg0 = tcg_temp_new();
+	    tcg_gen_ext16s_i32(arg0, REG(B7_4));
+	    arg1 = tcg_temp_new();
+	    tcg_gen_ext16s_i32(arg1, REG(B11_8));
+	    tcg_gen_mul_i32(cpu_macl, arg0, arg1);
+	    tcg_temp_free(arg1);
+	    tcg_temp_free(arg0);
+	}
+	return;
+    case 0x200e:		/* mulu.w Rm,Rn */
+	{
+	    TCGv arg0, arg1;
+	    arg0 = tcg_temp_new();
+	    tcg_gen_ext16u_i32(arg0, REG(B7_4));
+	    arg1 = tcg_temp_new();
+	    tcg_gen_ext16u_i32(arg1, REG(B11_8));
+	    tcg_gen_mul_i32(cpu_macl, arg0, arg1);
+	    tcg_temp_free(arg1);
+	    tcg_temp_free(arg0);
+	}
+	return;
+    case 0x600b:		/* neg Rm,Rn */
+	tcg_gen_neg_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x600a:		/* negc Rm,Rn */
+        {
+	    TCGv t0, t1;
+            t0 = tcg_temp_new();
+            tcg_gen_neg_i32(t0, REG(B7_4));
+            t1 = tcg_temp_new();
+            tcg_gen_andi_i32(t1, cpu_sr, SR_T);
+            tcg_gen_sub_i32(REG(B11_8), t0, t1);
+            tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+            tcg_gen_setcondi_i32(TCG_COND_GTU, t1, t0, 0);
+            tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+            tcg_gen_setcond_i32(TCG_COND_GTU, t1, REG(B11_8), t0);
+            tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+        }
+	return;
+    case 0x6007:		/* not Rm,Rn */
+	tcg_gen_not_i32(REG(B11_8), REG(B7_4));
+	return;
+    case 0x200b:		/* or Rm,Rn */
+	tcg_gen_or_i32(REG(B11_8), REG(B11_8), REG(B7_4));
+	return;
+    case 0x400c:		/* shad Rm,Rn */
+	{
+	    int label1 = gen_new_label();
+	    int label2 = gen_new_label();
+	    int label3 = gen_new_label();
+	    int label4 = gen_new_label();
+	    TCGv shift;
+	    tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1);
+	    /* Rm positive, shift to the left */
+            shift = tcg_temp_new();
+	    tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
+	    tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift);
+	    tcg_temp_free(shift);
+	    tcg_gen_br(label4);
+	    /* Rm negative, shift to the right */
+	    gen_set_label(label1);
+            shift = tcg_temp_new();
+	    tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
+	    tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2);
+	    tcg_gen_not_i32(shift, REG(B7_4));
+	    tcg_gen_andi_i32(shift, shift, 0x1f);
+	    tcg_gen_addi_i32(shift, shift, 1);
+	    tcg_gen_sar_i32(REG(B11_8), REG(B11_8), shift);
+	    tcg_temp_free(shift);
+	    tcg_gen_br(label4);
+	    /* Rm = -32 */
+	    gen_set_label(label2);
+	    tcg_gen_brcondi_i32(TCG_COND_LT, REG(B11_8), 0, label3);
+	    tcg_gen_movi_i32(REG(B11_8), 0);
+	    tcg_gen_br(label4);
+	    gen_set_label(label3);
+	    tcg_gen_movi_i32(REG(B11_8), 0xffffffff);
+	    gen_set_label(label4);
+	}
+	return;
+    case 0x400d:		/* shld Rm,Rn */
+	{
+	    int label1 = gen_new_label();
+	    int label2 = gen_new_label();
+	    int label3 = gen_new_label();
+	    TCGv shift;
+	    tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1);
+	    /* Rm positive, shift to the left */
+            shift = tcg_temp_new();
+	    tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
+	    tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift);
+	    tcg_temp_free(shift);
+	    tcg_gen_br(label3);
+	    /* Rm negative, shift to the right */
+	    gen_set_label(label1);
+            shift = tcg_temp_new();
+	    tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
+	    tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2);
+	    tcg_gen_not_i32(shift, REG(B7_4));
+	    tcg_gen_andi_i32(shift, shift, 0x1f);
+	    tcg_gen_addi_i32(shift, shift, 1);
+	    tcg_gen_shr_i32(REG(B11_8), REG(B11_8), shift);
+	    tcg_temp_free(shift);
+	    tcg_gen_br(label3);
+	    /* Rm = -32 */
+	    gen_set_label(label2);
+	    tcg_gen_movi_i32(REG(B11_8), 0);
+	    gen_set_label(label3);
+	}
+	return;
+    case 0x3008:		/* sub Rm,Rn */
+	tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4));
+	return;
+    case 0x300a:		/* subc Rm,Rn */
+	gen_helper_subc(REG(B11_8), REG(B7_4), REG(B11_8));
+	return;
+    case 0x300b:		/* subv Rm,Rn */
+	gen_helper_subv(REG(B11_8), REG(B7_4), REG(B11_8));
+	return;
+    case 0x2008:		/* tst Rm,Rn */
+	{
+	    TCGv val = tcg_temp_new();
+	    tcg_gen_and_i32(val, REG(B7_4), REG(B11_8));
+	    gen_cmp_imm(TCG_COND_EQ, val, 0);
+	    tcg_temp_free(val);
+	}
+	return;
+    case 0x200a:		/* xor Rm,Rn */
+	tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4));
+	return;
+    case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_SZ) {
+	    TCGv_i64 fp = tcg_temp_new_i64();
+	    gen_load_fpr64(fp, XREG(B7_4));
+	    gen_store_fpr64(fp, XREG(B11_8));
+	    tcg_temp_free_i64(fp);
+	} else {
+	    tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+	}
+	return;
+    case 0xf00a: /* fmov {F,D,X}Rm, at Rn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_SZ) {
+	    TCGv addr_hi = tcg_temp_new();
+	    int fr = XREG(B7_4);
+	    tcg_gen_addi_i32(addr_hi, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(cpu_fregs[fr  ], REG(B11_8), ctx->memidx);
+	    tcg_gen_qemu_st32(cpu_fregs[fr+1], addr_hi,	   ctx->memidx);
+	    tcg_temp_free(addr_hi);
+	} else {
+	    tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], REG(B11_8), ctx->memidx);
+	}
+	return;
+    case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_SZ) {
+	    TCGv addr_hi = tcg_temp_new();
+	    int fr = XREG(B11_8);
+	    tcg_gen_addi_i32(addr_hi, REG(B7_4), 4);
+	    tcg_gen_qemu_ld32u(cpu_fregs[fr  ], REG(B7_4), ctx->memidx);
+	    tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr_hi,   ctx->memidx);
+	    tcg_temp_free(addr_hi);
+	} else {
+	    tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], REG(B7_4), ctx->memidx);
+	}
+	return;
+    case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_SZ) {
+	    TCGv addr_hi = tcg_temp_new();
+	    int fr = XREG(B11_8);
+	    tcg_gen_addi_i32(addr_hi, REG(B7_4), 4);
+	    tcg_gen_qemu_ld32u(cpu_fregs[fr  ], REG(B7_4), ctx->memidx);
+	    tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr_hi,   ctx->memidx);
+	    tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8);
+	    tcg_temp_free(addr_hi);
+	} else {
+	    tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], REG(B7_4), ctx->memidx);
+	    tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
+	}
+	return;
+    case 0xf00b: /* fmov {F,D,X}Rm, at -Rn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_SZ) {
+	    TCGv addr = tcg_temp_new_i32();
+	    int fr = XREG(B7_4);
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(cpu_fregs[fr+1], addr, ctx->memidx);
+	    tcg_gen_subi_i32(addr, addr, 4);
+	    tcg_gen_qemu_st32(cpu_fregs[fr  ], addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	} else {
+	    TCGv addr;
+	    addr = tcg_temp_new_i32();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv addr = tcg_temp_new_i32();
+	    tcg_gen_add_i32(addr, REG(B7_4), REG(0));
+	    if (ctx->fpscr & FPSCR_SZ) {
+		int fr = XREG(B11_8);
+		tcg_gen_qemu_ld32u(cpu_fregs[fr	 ], addr, ctx->memidx);
+		tcg_gen_addi_i32(addr, addr, 4);
+		tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr, ctx->memidx);
+	    } else {
+		tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], addr, ctx->memidx);
+	    }
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(B11_8), REG(0));
+	    if (ctx->fpscr & FPSCR_SZ) {
+		int fr = XREG(B7_4);
+		tcg_gen_qemu_ld32u(cpu_fregs[fr	 ], addr, ctx->memidx);
+		tcg_gen_addi_i32(addr, addr, 4);
+		tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr, ctx->memidx);
+	    } else {
+		tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx);
+	    }
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+    case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+	{
+	    CHECK_FPU_ENABLED
+	    if (ctx->fpscr & FPSCR_PR) {
+                TCGv_i64 fp0, fp1;
+
+		if (ctx->opcode & 0x0110)
+		    break; /* illegal instruction */
+		fp0 = tcg_temp_new_i64();
+		fp1 = tcg_temp_new_i64();
+		gen_load_fpr64(fp0, DREG(B11_8));
+		gen_load_fpr64(fp1, DREG(B7_4));
+                switch (ctx->opcode & 0xf00f) {
+                case 0xf000:		/* fadd Rm,Rn */
+                    gen_helper_fadd_DT(fp0, fp0, fp1);
+                    break;
+                case 0xf001:		/* fsub Rm,Rn */
+                    gen_helper_fsub_DT(fp0, fp0, fp1);
+                    break;
+                case 0xf002:		/* fmul Rm,Rn */
+                    gen_helper_fmul_DT(fp0, fp0, fp1);
+                    break;
+                case 0xf003:		/* fdiv Rm,Rn */
+                    gen_helper_fdiv_DT(fp0, fp0, fp1);
+                    break;
+                case 0xf004:		/* fcmp/eq Rm,Rn */
+                    gen_helper_fcmp_eq_DT(fp0, fp1);
+                    return;
+                case 0xf005:		/* fcmp/gt Rm,Rn */
+                    gen_helper_fcmp_gt_DT(fp0, fp1);
+                    return;
+                }
+		gen_store_fpr64(fp0, DREG(B11_8));
+                tcg_temp_free_i64(fp0);
+                tcg_temp_free_i64(fp1);
+	    } else {
+                switch (ctx->opcode & 0xf00f) {
+                case 0xf000:		/* fadd Rm,Rn */
+                    gen_helper_fadd_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    break;
+                case 0xf001:		/* fsub Rm,Rn */
+                    gen_helper_fsub_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    break;
+                case 0xf002:		/* fmul Rm,Rn */
+                    gen_helper_fmul_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    break;
+                case 0xf003:		/* fdiv Rm,Rn */
+                    gen_helper_fdiv_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    break;
+                case 0xf004:		/* fcmp/eq Rm,Rn */
+                    gen_helper_fcmp_eq_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    return;
+                case 0xf005:		/* fcmp/gt Rm,Rn */
+                    gen_helper_fcmp_gt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
+                    return;
+                }
+	    }
+	}
+	return;
+    case 0xf00e: /* fmac FR0,RM,Rn */
+        {
+            CHECK_FPU_ENABLED
+            if (ctx->fpscr & FPSCR_PR) {
+                break; /* illegal instruction */
+            } else {
+                gen_helper_fmac_FT(cpu_fregs[FREG(B11_8)],
+                                   cpu_fregs[FREG(0)], cpu_fregs[FREG(B7_4)], cpu_fregs[FREG(B11_8)]);
+                return;
+            }
+        }
+    }
+
+    switch (ctx->opcode & 0xff00) {
+    case 0xc900:		/* and #imm,R0 */
+	tcg_gen_andi_i32(REG(0), REG(0), B7_0);
+	return;
+    case 0xcd00:		/* and.b #imm,@(R0,GBR) */
+	{
+	    TCGv addr, val;
+	    addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(0), cpu_gbr);
+	    val = tcg_temp_new();
+	    tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
+	    tcg_gen_andi_i32(val, val, B7_0);
+	    tcg_gen_qemu_st8(val, addr, ctx->memidx);
+	    tcg_temp_free(val);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x8b00:		/* bf label */
+	CHECK_NOT_DELAY_SLOT
+	    gen_conditional_jump(ctx, ctx->pc + 2,
+				 ctx->pc + 4 + B7_0s * 2);
+	ctx->bstate = BS_BRANCH;
+	return;
+    case 0x8f00:		/* bf/s label */
+	CHECK_NOT_DELAY_SLOT
+	gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 0);
+	ctx->flags |= DELAY_SLOT_CONDITIONAL;
+	return;
+    case 0x8900:		/* bt label */
+	CHECK_NOT_DELAY_SLOT
+	    gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2,
+				 ctx->pc + 2);
+	ctx->bstate = BS_BRANCH;
+	return;
+    case 0x8d00:		/* bt/s label */
+	CHECK_NOT_DELAY_SLOT
+	gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 1);
+	ctx->flags |= DELAY_SLOT_CONDITIONAL;
+	return;
+    case 0x8800:		/* cmp/eq #imm,R0 */
+	gen_cmp_imm(TCG_COND_EQ, REG(0), B7_0s);
+	return;
+    case 0xc400:		/* mov.b @(disp,GBR),R0 */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
+	    tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc500:		/* mov.w @(disp,GBR),R0 */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
+	    tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc600:		/* mov.l @(disp,GBR),R0 */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
+	    tcg_gen_qemu_ld32s(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc000:		/* mov.b R0,@(disp,GBR) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
+	    tcg_gen_qemu_st8(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc100:		/* mov.w R0,@(disp,GBR) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
+	    tcg_gen_qemu_st16(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc200:		/* mov.l R0,@(disp,GBR) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
+	    tcg_gen_qemu_st32(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x8000:		/* mov.b R0,@(disp,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
+	    tcg_gen_qemu_st8(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x8100:		/* mov.w R0,@(disp,Rn) */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
+	    tcg_gen_qemu_st16(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x8400:		/* mov.b @(disp,Rn),R0 */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
+	    tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0x8500:		/* mov.w @(disp,Rn),R0 */
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
+	    tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc700:		/* mova @(disp,PC),R0 */
+	tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3);
+	return;
+    case 0xcb00:		/* or #imm,R0 */
+	tcg_gen_ori_i32(REG(0), REG(0), B7_0);
+	return;
+    case 0xcf00:		/* or.b #imm,@(R0,GBR) */
+	{
+	    TCGv addr, val;
+	    addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(0), cpu_gbr);
+	    val = tcg_temp_new();
+	    tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
+	    tcg_gen_ori_i32(val, val, B7_0);
+	    tcg_gen_qemu_st8(val, addr, ctx->memidx);
+	    tcg_temp_free(val);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xc300:		/* trapa #imm */
+	{
+	    TCGv imm;
+	    CHECK_NOT_DELAY_SLOT
+	    imm = tcg_const_i32(B7_0);
+	    gen_helper_trapa(imm);
+	    tcg_temp_free(imm);
+	    ctx->bstate = BS_BRANCH;
+	}
+	return;
+    case 0xc800:		/* tst #imm,R0 */
+	{
+	    TCGv val = tcg_temp_new();
+	    tcg_gen_andi_i32(val, REG(0), B7_0);
+	    gen_cmp_imm(TCG_COND_EQ, val, 0);
+	    tcg_temp_free(val);
+	}
+	return;
+    case 0xcc00:		/* tst.b #imm,@(R0,GBR) */
+	{
+	    TCGv val = tcg_temp_new();
+	    tcg_gen_add_i32(val, REG(0), cpu_gbr);
+	    tcg_gen_qemu_ld8u(val, val, ctx->memidx);
+	    tcg_gen_andi_i32(val, val, B7_0);
+	    gen_cmp_imm(TCG_COND_EQ, val, 0);
+	    tcg_temp_free(val);
+	}
+	return;
+    case 0xca00:		/* xor #imm,R0 */
+	tcg_gen_xori_i32(REG(0), REG(0), B7_0);
+	return;
+    case 0xce00:		/* xor.b #imm,@(R0,GBR) */
+	{
+	    TCGv addr, val;
+	    addr = tcg_temp_new();
+	    tcg_gen_add_i32(addr, REG(0), cpu_gbr);
+	    val = tcg_temp_new();
+	    tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
+	    tcg_gen_xori_i32(val, val, B7_0);
+	    tcg_gen_qemu_st8(val, addr, ctx->memidx);
+	    tcg_temp_free(val);
+	    tcg_temp_free(addr);
+	}
+	return;
+    }
+
+    switch (ctx->opcode & 0xf08f) {
+    case 0x408e:		/* ldc Rm,Rn_BANK */
+	CHECK_PRIVILEGED
+	tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8));
+	return;
+    case 0x4087:		/* ldc.l @Rm+,Rn_BANK */
+	CHECK_PRIVILEGED
+	tcg_gen_qemu_ld32s(ALTREG(B6_4), REG(B11_8), ctx->memidx);
+	tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+	return;
+    case 0x0082:		/* stc Rm_BANK,Rn */
+	CHECK_PRIVILEGED
+	tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4));
+	return;
+    case 0x4083:		/* stc.l Rm_BANK, at -Rn */
+	CHECK_PRIVILEGED
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(ALTREG(B6_4), addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	}
+	return;
+    }
+
+    switch (ctx->opcode & 0xf0ff) {
+    case 0x0023:		/* braf Rn */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4);
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x0003:		/* bsrf Rn */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
+	tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr);
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x4015:		/* cmp/pl Rn */
+	gen_cmp_imm(TCG_COND_GT, REG(B11_8), 0);
+	return;
+    case 0x4011:		/* cmp/pz Rn */
+	gen_cmp_imm(TCG_COND_GE, REG(B11_8), 0);
+	return;
+    case 0x4010:		/* dt Rn */
+	tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1);
+	gen_cmp_imm(TCG_COND_EQ, REG(B11_8), 0);
+	return;
+    case 0x402b:		/* jmp @Rn */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x400b:		/* jsr @Rn */
+	CHECK_NOT_DELAY_SLOT
+	tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
+	tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
+	ctx->flags |= DELAY_SLOT;
+	ctx->delayed_pc = (uint32_t) - 1;
+	return;
+    case 0x400e:		/* ldc Rm,SR */
+	CHECK_PRIVILEGED
+	tcg_gen_andi_i32(cpu_sr, REG(B11_8), 0x700083f3);
+	ctx->bstate = BS_STOP;
+	return;
+    case 0x4007:		/* ldc.l @Rm+,SR */
+	CHECK_PRIVILEGED
+	{
+	    TCGv val = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(val, REG(B11_8), ctx->memidx);
+	    tcg_gen_andi_i32(cpu_sr, val, 0x700083f3);
+	    tcg_temp_free(val);
+	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+	    ctx->bstate = BS_STOP;
+	}
+	return;
+    case 0x0002:		/* stc SR,Rn */
+	CHECK_PRIVILEGED
+	tcg_gen_mov_i32(REG(B11_8), cpu_sr);
+	return;
+    case 0x4003:		/* stc SR, at -Rn */
+	CHECK_PRIVILEGED
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(cpu_sr, addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	}
+	return;
+#define LD(reg,ldnum,ldpnum,prechk)		\
+  case ldnum:							\
+    prechk    							\
+    tcg_gen_mov_i32 (cpu_##reg, REG(B11_8));			\
+    return;							\
+  case ldpnum:							\
+    prechk    							\
+    tcg_gen_qemu_ld32s (cpu_##reg, REG(B11_8), ctx->memidx);	\
+    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);		\
+    return;
+#define ST(reg,stnum,stpnum,prechk)		\
+  case stnum:							\
+    prechk    							\
+    tcg_gen_mov_i32 (REG(B11_8), cpu_##reg);			\
+    return;							\
+  case stpnum:							\
+    prechk    							\
+    {								\
+	TCGv addr = tcg_temp_new();				\
+	tcg_gen_subi_i32(addr, REG(B11_8), 4);			\
+	tcg_gen_qemu_st32 (cpu_##reg, addr, ctx->memidx);	\
+	tcg_gen_mov_i32(REG(B11_8), addr);			\
+	tcg_temp_free(addr);					\
+    }								\
+    return;
+#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk)		\
+	LD(reg,ldnum,ldpnum,prechk)				\
+	ST(reg,stnum,stpnum,prechk)
+	LDST(gbr,  0x401e, 0x4017, 0x0012, 0x4013, {})
+	LDST(vbr,  0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED)
+	LDST(ssr,  0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED)
+	LDST(spc,  0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED)
+	ST(sgr,  0x003a, 0x4032, CHECK_PRIVILEGED)
+	LD(sgr,  0x403a, 0x4036, CHECK_PRIVILEGED if (!(ctx->features & SH_FEATURE_SH4A)) break;)
+	LDST(dbr,  0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED)
+	LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
+	LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
+	LDST(pr,   0x402a, 0x4026, 0x002a, 0x4022, {})
+	LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED})
+    case 0x406a:		/* lds Rm,FPSCR */
+	CHECK_FPU_ENABLED
+	gen_helper_ld_fpscr(REG(B11_8));
+	ctx->bstate = BS_STOP;
+	return;
+    case 0x4066:		/* lds.l @Rm+,FPSCR */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv addr = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx);
+	    tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+	    gen_helper_ld_fpscr(addr);
+	    tcg_temp_free(addr);
+	    ctx->bstate = BS_STOP;
+	}
+	return;
+    case 0x006a:		/* sts FPSCR,Rn */
+	CHECK_FPU_ENABLED
+	tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
+	return;
+    case 0x4062:		/* sts FPSCR, at -Rn */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv addr, val;
+	    val = tcg_temp_new();
+	    tcg_gen_andi_i32(val, cpu_fpscr, 0x003fffff);
+	    addr = tcg_temp_new();
+	    tcg_gen_subi_i32(addr, REG(B11_8), 4);
+	    tcg_gen_qemu_st32(val, addr, ctx->memidx);
+	    tcg_gen_mov_i32(REG(B11_8), addr);
+	    tcg_temp_free(addr);
+	    tcg_temp_free(val);
+	}
+	return;
+    case 0x00c3:		/* movca.l R0, at Rm */
+        {
+            TCGv val = tcg_temp_new();
+            tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx);
+            gen_helper_movcal (REG(B11_8), val);            
+            tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
+        }
+        ctx->has_movcal = 1;
+	return;
+    case 0x40a9:
+	/* MOVUA.L @Rm,R0 (Rm) -> R0
+	   Load non-boundary-aligned data */
+	tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx);
+	return;
+    case 0x40e9:
+	/* MOVUA.L @Rm+,R0   (Rm) -> R0, Rm + 4 -> Rm
+	   Load non-boundary-aligned data */
+	tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx);
+	tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+	return;
+    case 0x0029:		/* movt Rn */
+	tcg_gen_andi_i32(REG(B11_8), cpu_sr, SR_T);
+	return;
+    case 0x0073:
+        /* MOVCO.L
+	       LDST -> T
+               If (T == 1) R0 -> (Rn)
+               0 -> LDST
+        */
+        if (ctx->features & SH_FEATURE_SH4A) {
+	    int label = gen_new_label();
+	    gen_clr_t();
+	    tcg_gen_or_i32(cpu_sr, cpu_sr, cpu_ldst);
+	    tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label);
+	    tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
+	    gen_set_label(label);
+	    tcg_gen_movi_i32(cpu_ldst, 0);
+	    return;
+	} else
+	    break;
+    case 0x0063:
+        /* MOVLI.L @Rm,R0
+               1 -> LDST
+               (Rm) -> R0
+               When interrupt/exception
+               occurred 0 -> LDST
+        */
+	if (ctx->features & SH_FEATURE_SH4A) {
+	    tcg_gen_movi_i32(cpu_ldst, 0);
+	    tcg_gen_qemu_ld32s(REG(0), REG(B11_8), ctx->memidx);
+	    tcg_gen_movi_i32(cpu_ldst, 1);
+	    return;
+	} else
+	    break;
+    case 0x0093:		/* ocbi @Rn */
+	{
+	    gen_helper_ocbi (REG(B11_8));
+	}
+	return;
+    case 0x00a3:		/* ocbp @Rn */
+	{
+	    TCGv dummy = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
+	    tcg_temp_free(dummy);
+	}
+	return;
+    case 0x00b3:		/* ocbwb @Rn */
+	{
+	    TCGv dummy = tcg_temp_new();
+	    tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
+	    tcg_temp_free(dummy);
+	}
+	return;
+    case 0x0083:		/* pref @Rn */
+	return;
+    case 0x00d3:		/* prefi @Rn */
+	if (ctx->features & SH_FEATURE_SH4A)
+	    return;
+	else
+	    break;
+    case 0x00e3:		/* icbi @Rn */
+	if (ctx->features & SH_FEATURE_SH4A)
+	    return;
+	else
+	    break;
+    case 0x00ab:		/* synco */
+	if (ctx->features & SH_FEATURE_SH4A)
+	    return;
+	else
+	    break;
+    case 0x4024:		/* rotcl Rn */
+	{
+	    TCGv tmp = tcg_temp_new();
+	    tcg_gen_mov_i32(tmp, cpu_sr);
+	    gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31);
+	    tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
+	    gen_copy_bit_i32(REG(B11_8), 0, tmp, 0);
+	    tcg_temp_free(tmp);
+	}
+	return;
+    case 0x4025:		/* rotcr Rn */
+	{
+	    TCGv tmp = tcg_temp_new();
+	    tcg_gen_mov_i32(tmp, cpu_sr);
+	    gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
+	    tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
+	    gen_copy_bit_i32(REG(B11_8), 31, tmp, 0);
+	    tcg_temp_free(tmp);
+	}
+	return;
+    case 0x4004:		/* rotl Rn */
+	tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1);
+	gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
+	return;
+    case 0x4005:		/* rotr Rn */
+	gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
+	tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1);
+	return;
+    case 0x4000:		/* shll Rn */
+    case 0x4020:		/* shal Rn */
+	gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31);
+	tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
+	return;
+    case 0x4021:		/* shar Rn */
+	gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
+	tcg_gen_sari_i32(REG(B11_8), REG(B11_8), 1);
+	return;
+    case 0x4001:		/* shlr Rn */
+	gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
+	tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
+	return;
+    case 0x4008:		/* shll2 Rn */
+	tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 2);
+	return;
+    case 0x4018:		/* shll8 Rn */
+	tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 8);
+	return;
+    case 0x4028:		/* shll16 Rn */
+	tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 16);
+	return;
+    case 0x4009:		/* shlr2 Rn */
+	tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 2);
+	return;
+    case 0x4019:		/* shlr8 Rn */
+	tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 8);
+	return;
+    case 0x4029:		/* shlr16 Rn */
+	tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 16);
+	return;
+    case 0x401b:		/* tas.b @Rn */
+	{
+	    TCGv addr, val;
+	    addr = tcg_temp_local_new();
+	    tcg_gen_mov_i32(addr, REG(B11_8));
+	    val = tcg_temp_local_new();
+	    tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
+	    gen_cmp_imm(TCG_COND_EQ, val, 0);
+	    tcg_gen_ori_i32(val, val, 0x80);
+	    tcg_gen_qemu_st8(val, addr, ctx->memidx);
+	    tcg_temp_free(val);
+	    tcg_temp_free(addr);
+	}
+	return;
+    case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fpul);
+	return;
+    case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	tcg_gen_mov_i32(cpu_fpul, cpu_fregs[FREG(B11_8)]);
+	return;
+    case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_PR) {
+	    TCGv_i64 fp;
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    fp = tcg_temp_new_i64();
+	    gen_helper_float_DT(fp, cpu_fpul);
+	    gen_store_fpr64(fp, DREG(B11_8));
+	    tcg_temp_free_i64(fp);
+	}
+	else {
+	    gen_helper_float_FT(cpu_fregs[FREG(B11_8)], cpu_fpul);
+	}
+	return;
+    case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_PR) {
+	    TCGv_i64 fp;
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    fp = tcg_temp_new_i64();
+	    gen_load_fpr64(fp, DREG(B11_8));
+	    gen_helper_ftrc_DT(cpu_fpul, fp);
+	    tcg_temp_free_i64(fp);
+	}
+	else {
+	    gen_helper_ftrc_FT(cpu_fpul, cpu_fregs[FREG(B11_8)]);
+	}
+	return;
+    case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */
+	CHECK_FPU_ENABLED
+	{
+	    gen_helper_fneg_T(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
+	}
+	return;
+    case 0xf05d: /* fabs FRn/DRn */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_PR) {
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    TCGv_i64 fp = tcg_temp_new_i64();
+	    gen_load_fpr64(fp, DREG(B11_8));
+	    gen_helper_fabs_DT(fp, fp);
+	    gen_store_fpr64(fp, DREG(B11_8));
+	    tcg_temp_free_i64(fp);
+	} else {
+	    gen_helper_fabs_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
+	}
+	return;
+    case 0xf06d: /* fsqrt FRn */
+	CHECK_FPU_ENABLED
+	if (ctx->fpscr & FPSCR_PR) {
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    TCGv_i64 fp = tcg_temp_new_i64();
+	    gen_load_fpr64(fp, DREG(B11_8));
+	    gen_helper_fsqrt_DT(fp, fp);
+	    gen_store_fpr64(fp, DREG(B11_8));
+	    tcg_temp_free_i64(fp);
+	} else {
+	    gen_helper_fsqrt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
+	}
+	return;
+    case 0xf07d: /* fsrra FRn */
+	CHECK_FPU_ENABLED
+	break;
+    case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
+	CHECK_FPU_ENABLED
+	if (!(ctx->fpscr & FPSCR_PR)) {
+	    tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0);
+	}
+	return;
+    case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
+	CHECK_FPU_ENABLED
+	if (!(ctx->fpscr & FPSCR_PR)) {
+	    tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0x3f800000);
+	}
+	return;
+    case 0xf0ad: /* fcnvsd FPUL,DRn */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv_i64 fp = tcg_temp_new_i64();
+	    gen_helper_fcnvsd_FT_DT(fp, cpu_fpul);
+	    gen_store_fpr64(fp, DREG(B11_8));
+	    tcg_temp_free_i64(fp);
+	}
+	return;
+    case 0xf0bd: /* fcnvds DRn,FPUL */
+	CHECK_FPU_ENABLED
+	{
+	    TCGv_i64 fp = tcg_temp_new_i64();
+	    gen_load_fpr64(fp, DREG(B11_8));
+	    gen_helper_fcnvds_DT_FT(cpu_fpul, fp);
+	    tcg_temp_free_i64(fp);
+	}
+	return;
+    case 0xf0ed: /* fipr FVm,FVn */
+        CHECK_FPU_ENABLED
+        if ((ctx->fpscr & FPSCR_PR) == 0) {
+            TCGv m, n;
+            m = tcg_const_i32((ctx->opcode >> 16) & 3);
+            n = tcg_const_i32((ctx->opcode >> 18) & 3);
+            gen_helper_fipr(m, n);
+            tcg_temp_free(m);
+            tcg_temp_free(n);
+            return;
+        }
+        break;
+    case 0xf0fd: /* ftrv XMTRX,FVn */
+        CHECK_FPU_ENABLED
+        if ((ctx->opcode & 0x0300) == 0x0100 &&
+            (ctx->fpscr & FPSCR_PR) == 0) {
+            TCGv n;
+            n = tcg_const_i32((ctx->opcode >> 18) & 3);
+            gen_helper_ftrv(n);
+            tcg_temp_free(n);
+            return;
+        }
+        break;
+    }
+#if 0
+    fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
+	    ctx->opcode, ctx->pc);
+    fflush(stderr);
+#endif
+    if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
+       gen_helper_raise_slot_illegal_instruction();
+    } else {
+       gen_helper_raise_illegal_instruction();
+    }
+    ctx->bstate = BS_EXCP;
+}
+
+static void decode_opc(DisasContext * ctx)
+{
+    uint32_t old_flags = ctx->flags;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+        tcg_gen_debug_insn_start(ctx->pc);
+    }
+
+    _decode_opc(ctx);
+
+    if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
+        if (ctx->flags & DELAY_SLOT_CLEARME) {
+            gen_store_flags(0);
+        } else {
+	    /* go out of the delay slot */
+	    uint32_t new_flags = ctx->flags;
+	    new_flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
+	    gen_store_flags(new_flags);
+        }
+        ctx->flags = 0;
+        ctx->bstate = BS_BRANCH;
+        if (old_flags & DELAY_SLOT_CONDITIONAL) {
+	    gen_delayed_conditional_jump(ctx);
+        } else if (old_flags & DELAY_SLOT) {
+            gen_jump(ctx);
+	}
+
+    }
+
+    /* go into a delay slot */
+    if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL))
+        gen_store_flags(ctx->flags);
+}
+
+static inline void
+gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
+                               int search_pc)
+{
+    DisasContext ctx;
+    target_ulong pc_start;
+    static uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
+    int i, ii;
+    int num_insns;
+    int max_insns;
+
+    pc_start = tb->pc;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    ctx.pc = pc_start;
+    ctx.flags = (uint32_t)tb->flags;
+    ctx.bstate = BS_NONE;
+    ctx.sr = env->sr;
+    ctx.fpscr = env->fpscr;
+    ctx.memidx = (env->sr & SR_MD) == 0 ? 1 : 0;
+    /* We don't know if the delayed pc came from a dynamic or static branch,
+       so assume it is a dynamic branch.  */
+    ctx.delayed_pc = -1; /* use delayed pc from env pointer */
+    ctx.tb = tb;
+    ctx.singlestep_enabled = env->singlestep_enabled;
+    ctx.features = env->features;
+    ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA);
+
+    ii = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+    gen_icount_start();
+    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (ctx.pc == bp->pc) {
+		    /* We have hit a breakpoint - make sure PC is up-to-date */
+		    tcg_gen_movi_i32(cpu_pc, ctx.pc);
+		    gen_helper_debug();
+		    ctx.bstate = BS_EXCP;
+		    break;
+		}
+	    }
+	}
+        if (search_pc) {
+            i = gen_opc_ptr - gen_opc_buf;
+            if (ii < i) {
+                ii++;
+                while (ii < i)
+                    gen_opc_instr_start[ii++] = 0;
+            }
+            gen_opc_pc[ii] = ctx.pc;
+            gen_opc_hflags[ii] = ctx.flags;
+            gen_opc_instr_start[ii] = 1;
+            gen_opc_icount[ii] = num_insns;
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+#if 0
+	fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc);
+	fflush(stderr);
+#endif
+	ctx.opcode = lduw_code(ctx.pc);
+	decode_opc(&ctx);
+        num_insns++;
+	ctx.pc += 2;
+	if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
+	    break;
+	if (env->singlestep_enabled)
+	    break;
+        if (num_insns >= max_insns)
+            break;
+        if (singlestep)
+            break;
+    }
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (env->singlestep_enabled) {
+        tcg_gen_movi_i32(cpu_pc, ctx.pc);
+        gen_helper_debug();
+    } else {
+	switch (ctx.bstate) {
+        case BS_STOP:
+            /* gen_op_interrupt_restart(); */
+            /* fall through */
+        case BS_NONE:
+            if (ctx.flags) {
+                gen_store_flags(ctx.flags | DELAY_SLOT_CLEARME);
+	    }
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_EXCP:
+            /* gen_op_interrupt_restart(); */
+            tcg_gen_exit_tb(0);
+            break;
+        case BS_BRANCH:
+        default:
+            break;
+	}
+    }
+
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        i = gen_opc_ptr - gen_opc_buf;
+        ii++;
+        while (ii <= i)
+            gen_opc_instr_start[ii++] = 0;
+    } else {
+        tb->size = ctx.pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+#ifdef DEBUG_DISAS
+#ifdef SH4_DEBUG_DISAS
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "\n");
+#endif
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+	qemu_log("IN:\n");	/* , lookup_symbol(pc_start)); */
+	log_target_disas(pc_start, ctx.pc - pc_start, 0);
+	qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code(CPUState * env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+    env->flags = gen_opc_hflags[pc_pos];
+}
diff --git a/qemu-0.15.x/target-sparc/TODO b/qemu-0.15.x/target-sparc/TODO
new file mode 100644
index 0000000..c87459f
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/TODO
@@ -0,0 +1,88 @@
+TODO-list:
+
+CPU common:
+- Unimplemented features/bugs:
+ - Delay slot handling may fail sometimes (branch end of page, delay
+ slot next page)
+ - Atomical instructions
+ - CPU features should match real CPUs (also ASI selection)
+- Optimizations/improvements:
+ - Condition code/branch handling like x86, also for FPU?
+ - Remove remaining explicit alignment checks
+ - Global register for regwptr, so that windowed registers can be
+ accessed directly
+ - Improve Sparc32plus addressing
+ - NPC/PC static optimisations (use JUMP_TB when possible)? (Is this
+ obsolete?)
+ - Synthetic instructions
+ - MMU model dependant on CPU model
+ - Select ASI helper at translation time (on V9 only if known)
+ - KQemu/KVM support for VM only
+ - Hardware breakpoint/watchpoint support
+ - Cache emulation mode
+ - Reverse-endian pages
+ - Faster FPU emulation
+ - Busy loop detection
+
+Sparc32 CPUs:
+- Unimplemented features/bugs:
+ - Sun4/Sun4c MMUs
+ - Some V8 ASIs
+
+Sparc64 CPUs:
+- Unimplemented features/bugs:
+ - Interrupt handling
+ - Secondary address space, other MMU functions
+ - Many V9/UA2005/UA2007 ASIs
+ - Rest of V9 instructions, missing VIS instructions
+ - IG/MG/AG vs. UA2007 globals
+ - Full hypervisor support
+ - SMP/CMT
+ - Sun4v CPUs
+
+Sun4:
+- To be added
+
+Sun4c:
+- A lot of unimplemented features
+- Maybe split from Sun4m
+
+Sun4m:
+- Unimplemented features/bugs:
+ - Hardware devices do not match real boards
+ - Floppy does not work
+ - CS4231: merge with cs4231a, add DMA
+ - Add cg6, bwtwo
+ - Arbitrary resolution support
+ - PCI for MicroSparc-IIe
+ - JavaStation machines
+ - SBus slot probing, FCode ROM support
+ - SMP probing support
+ - Interrupt routing does not match real HW
+ - SuSE 7.3 keyboard sometimes unresponsive
+ - Gentoo 2004.1 SMP does not work
+ - SS600MP ledma -> lebuffer
+ - Type 5 keyboard
+ - Less fixed hardware choices
+ - DBRI audio (Am7930)
+ - BPP parallel
+ - Diagnostic switch
+ - ESP PIO mode
+
+Sun4d:
+- A lot of unimplemented features:
+ - SBI
+ - IO-unit
+- Maybe split from Sun4m
+
+Sun4u:
+- Unimplemented features/bugs:
+ - Interrupt controller
+ - PCI/IOMMU support (Simba, JIO, Tomatillo, Psycho, Schizo, Safari...)
+ - SMP
+ - Happy Meal Ethernet, flash, I2C, GPIO
+ - A lot of real machine types
+
+Sun4v:
+- A lot of unimplemented features
+ - A lot of real machine types
diff --git a/qemu-0.15.x/target-sparc/cpu.h b/qemu-0.15.x/target-sparc/cpu.h
new file mode 100644
index 0000000..a51863c
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/cpu.h
@@ -0,0 +1,731 @@
+#ifndef CPU_SPARC_H
+#define CPU_SPARC_H
+
+#include "config.h"
+#include "qemu-common.h"
+
+#if !defined(TARGET_SPARC64)
+#define TARGET_LONG_BITS 32
+#define TARGET_FPREGS 32
+#define TARGET_PAGE_BITS 12 /* 4k */
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#else
+#define TARGET_LONG_BITS 64
+#define TARGET_FPREGS 64
+#define TARGET_PAGE_BITS 13 /* 8k */
+#define TARGET_PHYS_ADDR_SPACE_BITS 41
+# ifdef TARGET_ABI32
+#  define TARGET_VIRT_ADDR_SPACE_BITS 32
+# else
+#  define TARGET_VIRT_ADDR_SPACE_BITS 44
+# endif
+#endif
+
+#define CPUState struct CPUSPARCState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+#define TARGET_HAS_ICE 1
+
+#if !defined(TARGET_SPARC64)
+#define ELF_MACHINE     EM_SPARC
+#else
+#define ELF_MACHINE     EM_SPARCV9
+#endif
+
+/*#define EXCP_INTERRUPT 0x100*/
+
+/* trap definitions */
+#ifndef TARGET_SPARC64
+#define TT_TFAULT   0x01
+#define TT_ILL_INSN 0x02
+#define TT_PRIV_INSN 0x03
+#define TT_NFPU_INSN 0x04
+#define TT_WIN_OVF  0x05
+#define TT_WIN_UNF  0x06
+#define TT_UNALIGNED 0x07
+#define TT_FP_EXCP  0x08
+#define TT_DFAULT   0x09
+#define TT_TOVF     0x0a
+#define TT_EXTINT   0x10
+#define TT_CODE_ACCESS 0x21
+#define TT_UNIMP_FLUSH 0x25
+#define TT_DATA_ACCESS 0x29
+#define TT_DIV_ZERO 0x2a
+#define TT_NCP_INSN 0x24
+#define TT_TRAP     0x80
+#else
+#define TT_POWER_ON_RESET 0x01
+#define TT_TFAULT   0x08
+#define TT_CODE_ACCESS 0x0a
+#define TT_ILL_INSN 0x10
+#define TT_UNIMP_FLUSH TT_ILL_INSN
+#define TT_PRIV_INSN 0x11
+#define TT_NFPU_INSN 0x20
+#define TT_FP_EXCP  0x21
+#define TT_TOVF     0x23
+#define TT_CLRWIN   0x24
+#define TT_DIV_ZERO 0x28
+#define TT_DFAULT   0x30
+#define TT_DATA_ACCESS 0x32
+#define TT_UNALIGNED 0x34
+#define TT_PRIV_ACT 0x37
+#define TT_EXTINT   0x40
+#define TT_IVEC     0x60
+#define TT_TMISS    0x64
+#define TT_DMISS    0x68
+#define TT_DPROT    0x6c
+#define TT_SPILL    0x80
+#define TT_FILL     0xc0
+#define TT_WOTHER   (1 << 5)
+#define TT_TRAP     0x100
+#endif
+
+#define PSR_NEG_SHIFT 23
+#define PSR_NEG   (1 << PSR_NEG_SHIFT)
+#define PSR_ZERO_SHIFT 22
+#define PSR_ZERO  (1 << PSR_ZERO_SHIFT)
+#define PSR_OVF_SHIFT 21
+#define PSR_OVF   (1 << PSR_OVF_SHIFT)
+#define PSR_CARRY_SHIFT 20
+#define PSR_CARRY (1 << PSR_CARRY_SHIFT)
+#define PSR_ICC   (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
+#if !defined(TARGET_SPARC64)
+#define PSR_EF    (1<<12)
+#define PSR_PIL   0xf00
+#define PSR_S     (1<<7)
+#define PSR_PS    (1<<6)
+#define PSR_ET    (1<<5)
+#define PSR_CWP   0x1f
+#endif
+
+#define CC_SRC (env->cc_src)
+#define CC_SRC2 (env->cc_src2)
+#define CC_DST (env->cc_dst)
+#define CC_OP  (env->cc_op)
+
+enum {
+    CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
+    CC_OP_FLAGS,   /* all cc are back in status register */
+    CC_OP_DIV,     /* modify N, Z and V, C = 0*/
+    CC_OP_ADD,     /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_ADDX,    /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_TADD,    /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_TADDTV,  /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
+    CC_OP_SUB,     /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_SUBX,    /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_TSUB,    /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_TSUBTV,  /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
+    CC_OP_LOGIC,   /* modify N and Z, C = V = 0, CC_DST = res */
+    CC_OP_NB,
+};
+
+/* Trap base register */
+#define TBR_BASE_MASK 0xfffff000
+
+#if defined(TARGET_SPARC64)
+#define PS_TCT   (1<<12) /* UA2007, impl.dep. trap on control transfer */
+#define PS_IG    (1<<11) /* v9, zero on UA2007 */
+#define PS_MG    (1<<10) /* v9, zero on UA2007 */
+#define PS_CLE   (1<<9) /* UA2007 */
+#define PS_TLE   (1<<8) /* UA2007 */
+#define PS_RMO   (1<<7)
+#define PS_RED   (1<<5) /* v9, zero on UA2007 */
+#define PS_PEF   (1<<4) /* enable fpu */
+#define PS_AM    (1<<3) /* address mask */
+#define PS_PRIV  (1<<2)
+#define PS_IE    (1<<1)
+#define PS_AG    (1<<0) /* v9, zero on UA2007 */
+
+#define FPRS_FEF (1<<2)
+
+#define HS_PRIV  (1<<2)
+#endif
+
+/* Fcc */
+#define FSR_RD1        (1ULL << 31)
+#define FSR_RD0        (1ULL << 30)
+#define FSR_RD_MASK    (FSR_RD1 | FSR_RD0)
+#define FSR_RD_NEAREST 0
+#define FSR_RD_ZERO    FSR_RD0
+#define FSR_RD_POS     FSR_RD1
+#define FSR_RD_NEG     (FSR_RD1 | FSR_RD0)
+
+#define FSR_NVM   (1ULL << 27)
+#define FSR_OFM   (1ULL << 26)
+#define FSR_UFM   (1ULL << 25)
+#define FSR_DZM   (1ULL << 24)
+#define FSR_NXM   (1ULL << 23)
+#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM)
+
+#define FSR_NVA   (1ULL << 9)
+#define FSR_OFA   (1ULL << 8)
+#define FSR_UFA   (1ULL << 7)
+#define FSR_DZA   (1ULL << 6)
+#define FSR_NXA   (1ULL << 5)
+#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+
+#define FSR_NVC   (1ULL << 4)
+#define FSR_OFC   (1ULL << 3)
+#define FSR_UFC   (1ULL << 2)
+#define FSR_DZC   (1ULL << 1)
+#define FSR_NXC   (1ULL << 0)
+#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC)
+
+#define FSR_FTT2   (1ULL << 16)
+#define FSR_FTT1   (1ULL << 15)
+#define FSR_FTT0   (1ULL << 14)
+//gcc warns about constant overflow for ~FSR_FTT_MASK
+//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
+#ifdef TARGET_SPARC64
+#define FSR_FTT_NMASK      0xfffffffffffe3fffULL
+#define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL
+#define FSR_LDFSR_OLDMASK  0x0000003f000fc000ULL
+#define FSR_LDXFSR_MASK    0x0000003fcfc00fffULL
+#define FSR_LDXFSR_OLDMASK 0x00000000000fc000ULL
+#else
+#define FSR_FTT_NMASK      0xfffe3fffULL
+#define FSR_FTT_CEXC_NMASK 0xfffe3fe0ULL
+#define FSR_LDFSR_OLDMASK  0x000fc000ULL
+#endif
+#define FSR_LDFSR_MASK     0xcfc00fffULL
+#define FSR_FTT_IEEE_EXCP (1ULL << 14)
+#define FSR_FTT_UNIMPFPOP (3ULL << 14)
+#define FSR_FTT_SEQ_ERROR (4ULL << 14)
+#define FSR_FTT_INVAL_FPR (6ULL << 14)
+
+#define FSR_FCC1_SHIFT 11
+#define FSR_FCC1  (1ULL << FSR_FCC1_SHIFT)
+#define FSR_FCC0_SHIFT 10
+#define FSR_FCC0  (1ULL << FSR_FCC0_SHIFT)
+
+/* MMU */
+#define MMU_E     (1<<0)
+#define MMU_NF    (1<<1)
+
+#define PTE_ENTRYTYPE_MASK 3
+#define PTE_ACCESS_MASK    0x1c
+#define PTE_ACCESS_SHIFT   2
+#define PTE_PPN_SHIFT      7
+#define PTE_ADDR_MASK      0xffffff00
+
+#define PG_ACCESSED_BIT 5
+#define PG_MODIFIED_BIT 6
+#define PG_CACHE_BIT    7
+
+#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
+#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT)
+#define PG_CACHE_MASK    (1 << PG_CACHE_BIT)
+
+/* 3 <= NWINDOWS <= 32. */
+#define MIN_NWINDOWS 3
+#define MAX_NWINDOWS 32
+
+#if !defined(TARGET_SPARC64)
+#define NB_MMU_MODES 2
+#else
+#define NB_MMU_MODES 6
+typedef struct trap_state {
+    uint64_t tpc;
+    uint64_t tnpc;
+    uint64_t tstate;
+    uint32_t tt;
+} trap_state;
+#endif
+
+typedef struct sparc_def_t {
+    const char *name;
+    target_ulong iu_version;
+    uint32_t fpu_version;
+    uint32_t mmu_version;
+    uint32_t mmu_bm;
+    uint32_t mmu_ctpr_mask;
+    uint32_t mmu_cxr_mask;
+    uint32_t mmu_sfsr_mask;
+    uint32_t mmu_trcr_mask;
+    uint32_t mxcc_version;
+    uint32_t features;
+    uint32_t nwindows;
+    uint32_t maxtl;
+} sparc_def_t;
+
+#define CPU_FEATURE_FLOAT        (1 << 0)
+#define CPU_FEATURE_FLOAT128     (1 << 1)
+#define CPU_FEATURE_SWAP         (1 << 2)
+#define CPU_FEATURE_MUL          (1 << 3)
+#define CPU_FEATURE_DIV          (1 << 4)
+#define CPU_FEATURE_FLUSH        (1 << 5)
+#define CPU_FEATURE_FSQRT        (1 << 6)
+#define CPU_FEATURE_FMUL         (1 << 7)
+#define CPU_FEATURE_VIS1         (1 << 8)
+#define CPU_FEATURE_VIS2         (1 << 9)
+#define CPU_FEATURE_FSMULD       (1 << 10)
+#define CPU_FEATURE_HYPV         (1 << 11)
+#define CPU_FEATURE_CMT          (1 << 12)
+#define CPU_FEATURE_GL           (1 << 13)
+#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
+#define CPU_FEATURE_ASR17        (1 << 15)
+#define CPU_FEATURE_CACHE_CTRL   (1 << 16)
+
+#ifndef TARGET_SPARC64
+#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
+                              CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
+                              CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
+                              CPU_FEATURE_FMUL | CPU_FEATURE_FSMULD)
+#else
+#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
+                              CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
+                              CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
+                              CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 |   \
+                              CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD)
+enum {
+    mmu_us_12, // Ultrasparc < III (64 entry TLB)
+    mmu_us_3,  // Ultrasparc III (512 entry TLB)
+    mmu_us_4,  // Ultrasparc IV (several TLBs, 32 and 256MB pages)
+    mmu_sun4v, // T1, T2
+};
+#endif
+
+#define TTE_VALID_BIT       (1ULL << 63)
+#define TTE_NFO_BIT         (1ULL << 60)
+#define TTE_USED_BIT        (1ULL << 41)
+#define TTE_LOCKED_BIT      (1ULL <<  6)
+#define TTE_SIDEEFFECT_BIT  (1ULL <<  3)
+#define TTE_PRIV_BIT        (1ULL <<  2)
+#define TTE_W_OK_BIT        (1ULL <<  1)
+#define TTE_GLOBAL_BIT      (1ULL <<  0)
+
+#define TTE_IS_VALID(tte)   ((tte) & TTE_VALID_BIT)
+#define TTE_IS_NFO(tte)     ((tte) & TTE_NFO_BIT)
+#define TTE_IS_USED(tte)    ((tte) & TTE_USED_BIT)
+#define TTE_IS_LOCKED(tte)  ((tte) & TTE_LOCKED_BIT)
+#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
+#define TTE_IS_PRIV(tte)    ((tte) & TTE_PRIV_BIT)
+#define TTE_IS_W_OK(tte)    ((tte) & TTE_W_OK_BIT)
+#define TTE_IS_GLOBAL(tte)  ((tte) & TTE_GLOBAL_BIT)
+
+#define TTE_SET_USED(tte)   ((tte) |= TTE_USED_BIT)
+#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
+
+#define TTE_PGSIZE(tte)     (((tte) >> 61) & 3ULL)
+#define TTE_PA(tte)         ((tte) & 0x1ffffffe000ULL)
+
+#define SFSR_NF_BIT         (1ULL << 24)   /* JPS1 NoFault */
+#define SFSR_TM_BIT         (1ULL << 15)   /* JPS1 TLB Miss */
+#define SFSR_FT_VA_IMMU_BIT (1ULL << 13)   /* USIIi VA out of range (IMMU) */
+#define SFSR_FT_VA_DMMU_BIT (1ULL << 12)   /* USIIi VA out of range (DMMU) */
+#define SFSR_FT_NFO_BIT     (1ULL << 11)   /* NFO page access */
+#define SFSR_FT_ILL_BIT     (1ULL << 10)   /* illegal LDA/STA ASI */
+#define SFSR_FT_ATOMIC_BIT  (1ULL <<  9)   /* atomic op on noncacheable area */
+#define SFSR_FT_NF_E_BIT    (1ULL <<  8)   /* NF access on side effect area */
+#define SFSR_FT_PRIV_BIT    (1ULL <<  7)   /* privilege violation */
+#define SFSR_PR_BIT         (1ULL <<  3)   /* privilege mode */
+#define SFSR_WRITE_BIT      (1ULL <<  2)   /* write access mode */
+#define SFSR_OW_BIT         (1ULL <<  1)   /* status overwritten */
+#define SFSR_VALID_BIT      (1ULL <<  0)   /* status valid */
+
+#define SFSR_ASI_SHIFT      16             /* 23:16 ASI value */
+#define SFSR_ASI_MASK       (0xffULL << SFSR_ASI_SHIFT)
+#define SFSR_CT_PRIMARY     (0ULL <<  4)   /* 5:4 context type */
+#define SFSR_CT_SECONDARY   (1ULL <<  4)
+#define SFSR_CT_NUCLEUS     (2ULL <<  4)
+#define SFSR_CT_NOTRANS     (3ULL <<  4)
+#define SFSR_CT_MASK        (3ULL <<  4)
+
+typedef struct SparcTLBEntry {
+    uint64_t tag;
+    uint64_t tte;
+} SparcTLBEntry;
+
+struct CPUTimer
+{
+    const char *name;
+    uint32_t    frequency;
+    uint32_t    disabled;
+    uint64_t    disabled_mask;
+    int64_t     clock_offset;
+    struct QEMUTimer  *qtimer;
+};
+
+typedef struct CPUTimer CPUTimer;
+
+struct QEMUFile;
+void cpu_put_timer(struct QEMUFile *f, CPUTimer *s);
+void cpu_get_timer(struct QEMUFile *f, CPUTimer *s);
+
+typedef struct CPUSPARCState {
+    target_ulong gregs[8]; /* general registers */
+    target_ulong *regwptr; /* pointer to current register window */
+    target_ulong pc;       /* program counter */
+    target_ulong npc;      /* next program counter */
+    target_ulong y;        /* multiply/divide register */
+
+    /* emulator internal flags handling */
+    target_ulong cc_src, cc_src2;
+    target_ulong cc_dst;
+    uint32_t cc_op;
+
+    target_ulong t0, t1; /* temporaries live across basic blocks */
+    target_ulong cond; /* conditional branch result (XXX: save it in a
+                          temporary register when possible) */
+
+    uint32_t psr;      /* processor state register */
+    target_ulong fsr;      /* FPU state register */
+    float32 fpr[TARGET_FPREGS];  /* floating point registers */
+    uint32_t cwp;      /* index of current register window (extracted
+                          from PSR) */
+#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
+    uint32_t wim;      /* window invalid mask */
+#endif
+    target_ulong tbr;  /* trap base register */
+#if !defined(TARGET_SPARC64)
+    int      psrs;     /* supervisor mode (extracted from PSR) */
+    int      psrps;    /* previous supervisor mode */
+    int      psret;    /* enable traps */
+#endif
+    uint32_t psrpil;   /* interrupt blocking level */
+    uint32_t pil_in;   /* incoming interrupt level bitmap */
+#if !defined(TARGET_SPARC64)
+    int      psref;    /* enable fpu */
+#endif
+    target_ulong version;
+    int interrupt_index;
+    uint32_t nwindows;
+    /* NOTE: we allow 8 more registers to handle wrapping */
+    target_ulong regbase[MAX_NWINDOWS * 16 + 8];
+
+    CPU_COMMON
+
+    /* MMU regs */
+#if defined(TARGET_SPARC64)
+    uint64_t lsu;
+#define DMMU_E 0x8
+#define IMMU_E 0x4
+    //typedef struct SparcMMU
+    union {
+        uint64_t immuregs[16];
+        struct {
+            uint64_t tsb_tag_target;
+            uint64_t unused_mmu_primary_context;   // use DMMU
+            uint64_t unused_mmu_secondary_context; // use DMMU
+            uint64_t sfsr;
+            uint64_t sfar;
+            uint64_t tsb;
+            uint64_t tag_access;
+        } immu;
+    };
+    union {
+        uint64_t dmmuregs[16];
+        struct {
+            uint64_t tsb_tag_target;
+            uint64_t mmu_primary_context;
+            uint64_t mmu_secondary_context;
+            uint64_t sfsr;
+            uint64_t sfar;
+            uint64_t tsb;
+            uint64_t tag_access;
+        } dmmu;
+    };
+    SparcTLBEntry itlb[64];
+    SparcTLBEntry dtlb[64];
+    uint32_t mmu_version;
+#else
+    uint32_t mmuregs[32];
+    uint64_t mxccdata[4];
+    uint64_t mxccregs[8];
+    uint32_t mmubpctrv, mmubpctrc, mmubpctrs;
+    uint64_t mmubpaction;
+    uint64_t mmubpregs[4];
+    uint64_t prom_addr;
+#endif
+    /* temporary float registers */
+    float64 dt0, dt1;
+    float128 qt0, qt1;
+    float_status fp_status;
+#if defined(TARGET_SPARC64)
+#define MAXTL_MAX 8
+#define MAXTL_MASK (MAXTL_MAX - 1)
+    trap_state ts[MAXTL_MAX];
+    uint32_t xcc;               /* Extended integer condition codes */
+    uint32_t asi;
+    uint32_t pstate;
+    uint32_t tl;
+    uint32_t maxtl;
+    uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
+    uint64_t agregs[8]; /* alternate general registers */
+    uint64_t bgregs[8]; /* backup for normal global registers */
+    uint64_t igregs[8]; /* interrupt general registers */
+    uint64_t mgregs[8]; /* mmu general registers */
+    uint64_t fprs;
+    uint64_t tick_cmpr, stick_cmpr;
+    CPUTimer *tick, *stick;
+#define TICK_NPT_MASK        0x8000000000000000ULL
+#define TICK_INT_DIS         0x8000000000000000ULL
+    uint64_t gsr;
+    uint32_t gl; // UA2005
+    /* UA 2005 hyperprivileged registers */
+    uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
+    CPUTimer *hstick; // UA 2005
+    uint32_t softint;
+#define SOFTINT_TIMER   1
+#define SOFTINT_STIMER  (1 << 16)
+#define SOFTINT_INTRMASK (0xFFFE)
+#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
+#endif
+    sparc_def_t *def;
+
+    void *irq_manager;
+    void (*qemu_irq_ack) (void *irq_manager, int intno);
+
+    /* Leon3 cache control */
+    uint32_t cache_control;
+} CPUSPARCState;
+
+#ifndef NO_CPU_IO_DEFS
+/* helper.c */
+CPUSPARCState *cpu_sparc_init(const char *cpu_model);
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
+target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
+
+/* translate.c */
+void gen_intermediate_code_init(CPUSPARCState *env);
+
+/* cpu-exec.c */
+int cpu_sparc_exec(CPUSPARCState *s);
+
+/* op_helper.c */
+target_ulong cpu_get_psr(CPUState *env1);
+void cpu_put_psr(CPUState *env1, target_ulong val);
+#ifdef TARGET_SPARC64
+target_ulong cpu_get_ccr(CPUState *env1);
+void cpu_put_ccr(CPUState *env1, target_ulong val);
+target_ulong cpu_get_cwp64(CPUState *env1);
+void cpu_put_cwp64(CPUState *env1, int cwp);
+void cpu_change_pstate(CPUState *env1, uint32_t new_pstate);
+#endif
+int cpu_cwp_inc(CPUState *env1, int cwp);
+int cpu_cwp_dec(CPUState *env1, int cwp);
+void cpu_set_cwp(CPUState *env1, int new_cwp);
+void leon3_irq_manager(void *irq_manager, int intno);
+
+/* sun4m.c, sun4u.c */
+void cpu_check_irqs(CPUSPARCState *env);
+
+/* leon3.c */
+void leon3_irq_ack(void *irq_manager, int intno);
+
+#if defined (TARGET_SPARC64)
+
+static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
+{
+    return (x & mask) == (y & mask);
+}
+
+#define MMU_CONTEXT_BITS 13
+#define MMU_CONTEXT_MASK ((1 << MMU_CONTEXT_BITS) - 1)
+
+static inline int tlb_compare_context(const SparcTLBEntry *tlb,
+                                      uint64_t context)
+{
+    return compare_masked(context, tlb->tag, MMU_CONTEXT_MASK);
+}
+
+#endif
+#endif
+
+/* cpu-exec.c */
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size);
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx);
+
+#endif
+#endif
+int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
+
+#define cpu_init cpu_sparc_init
+#define cpu_exec cpu_sparc_exec
+#define cpu_gen_code cpu_sparc_gen_code
+#define cpu_signal_handler cpu_sparc_signal_handler
+#define cpu_list sparc_cpu_list
+
+#define CPU_SAVE_VERSION 7
+
+/* MMU modes definitions */
+#if defined (TARGET_SPARC64)
+#define MMU_USER_IDX   0
+#define MMU_MODE0_SUFFIX _user
+#define MMU_USER_SECONDARY_IDX   1
+#define MMU_MODE1_SUFFIX _user_secondary
+#define MMU_KERNEL_IDX 2
+#define MMU_MODE2_SUFFIX _kernel
+#define MMU_KERNEL_SECONDARY_IDX 3
+#define MMU_MODE3_SUFFIX _kernel_secondary
+#define MMU_NUCLEUS_IDX 4
+#define MMU_MODE4_SUFFIX _nucleus
+#define MMU_HYPV_IDX   5
+#define MMU_MODE5_SUFFIX _hypv
+#else
+#define MMU_USER_IDX   0
+#define MMU_MODE0_SUFFIX _user
+#define MMU_KERNEL_IDX 1
+#define MMU_MODE1_SUFFIX _kernel
+#endif
+
+#if defined (TARGET_SPARC64)
+static inline int cpu_has_hypervisor(CPUState *env1)
+{
+    return env1->def->features & CPU_FEATURE_HYPV;
+}
+
+static inline int cpu_hypervisor_mode(CPUState *env1)
+{
+    return cpu_has_hypervisor(env1) && (env1->hpstate & HS_PRIV);
+}
+
+static inline int cpu_supervisor_mode(CPUState *env1)
+{
+    return env1->pstate & PS_PRIV;
+}
+#endif
+
+static inline int cpu_mmu_index(CPUState *env1)
+{
+#if defined(CONFIG_USER_ONLY)
+    return MMU_USER_IDX;
+#elif !defined(TARGET_SPARC64)
+    return env1->psrs;
+#else
+    if (env1->tl > 0) {
+        return MMU_NUCLEUS_IDX;
+    } else if (cpu_hypervisor_mode(env1)) {
+        return MMU_HYPV_IDX;
+    } else if (cpu_supervisor_mode(env1)) {
+        return MMU_KERNEL_IDX;
+    } else {
+        return MMU_USER_IDX;
+    }
+#endif
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env1)
+{
+#if !defined (TARGET_SPARC64)
+    if (env1->psret != 0)
+        return 1;
+#else
+    if (env1->pstate & PS_IE)
+        return 1;
+#endif
+
+    return 0;
+}
+
+static inline int cpu_pil_allowed(CPUState *env1, int pil)
+{
+#if !defined(TARGET_SPARC64)
+    /* level 15 is non-maskable on sparc v8 */
+    return pil == 15 || pil > env1->psrpil;
+#else
+    return pil > env1->psrpil;
+#endif
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp)
+        env->regwptr[22] = newsp;
+    env->regwptr[0] = 0;
+    /* FIXME: Do we also need to clear CF?  */
+    /* XXXXX */
+    printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+#endif
+
+#include "cpu-all.h"
+
+#ifdef TARGET_SPARC64
+/* sun4u.c */
+void cpu_tick_set_count(CPUTimer *timer, uint64_t count);
+uint64_t cpu_tick_get_count(CPUTimer *timer);
+void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
+trap_state* cpu_tsptr(CPUState* env);
+#endif
+
+#define TB_FLAG_FPU_ENABLED (1 << 4)
+#define TB_FLAG_AM_ENABLED (1 << 5)
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = env->npc;
+#ifdef TARGET_SPARC64
+    // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
+    *flags = (env->pstate & PS_PRIV)               /* 2 */
+        | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
+        | ((env->tl & 0xff) << 8)
+        | (env->dmmu.mmu_primary_context << 16);   /* 16... */
+    if (env->pstate & PS_AM) {
+        *flags |= TB_FLAG_AM_ENABLED;
+    }
+    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
+        && (env->fprs & FPRS_FEF)) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
+#else
+    // FPU enable . Supervisor
+    *flags = env->psrs;
+    if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
+#endif
+}
+
+static inline bool tb_fpu_enabled(int tb_flags)
+{
+#if defined(CONFIG_USER_ONLY)
+    return true;
+#else
+    return tb_flags & TB_FLAG_FPU_ENABLED;
+#endif
+}
+
+static inline bool tb_am_enabled(int tb_flags)
+{
+#ifndef TARGET_SPARC64
+    return false;
+#else
+    return tb_flags & TB_FLAG_AM_ENABLED;
+#endif
+}
+
+/* helper.c */
+void do_interrupt(CPUState *env);
+
+static inline bool cpu_has_work(CPUState *env1)
+{
+    return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+           cpu_interrupts_enabled(env1);
+}
+
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+    env->npc = tb->cs_base;
+}
+
+#endif
diff --git a/qemu-0.15.x/target-sparc/exec.h b/qemu-0.15.x/target-sparc/exec.h
new file mode 100644
index 0000000..2395b00
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/exec.h
@@ -0,0 +1,15 @@
+#ifndef EXEC_SPARC_H
+#define EXEC_SPARC_H 1
+#include "config.h"
+#include "dyngen-exec.h"
+
+register struct CPUSPARCState *env asm(AREG0);
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#endif
diff --git a/qemu-0.15.x/target-sparc/helper.c b/qemu-0.15.x/target-sparc/helper.c
new file mode 100644
index 0000000..efab885
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/helper.c
@@ -0,0 +1,1857 @@
+/*
+ *  sparc helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+//#define DEBUG_MMU
+//#define DEBUG_FEATURES
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...) \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+/* Sparc MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    if (rw & 2)
+        env1->exception_index = TT_TFAULT;
+    else
+        env1->exception_index = TT_DFAULT;
+    return 1;
+}
+
+#else
+
+#ifndef TARGET_SPARC64
+/*
+ * Sparc V8 Reference MMU (SRMMU)
+ */
+static const int access_table[8][8] = {
+    { 0, 0, 0, 0, 8, 0, 12, 12 },
+    { 0, 0, 0, 0, 8, 0, 0, 0 },
+    { 8, 8, 0, 0, 0, 8, 12, 12 },
+    { 8, 8, 0, 0, 0, 8, 0, 0 },
+    { 8, 0, 8, 0, 8, 8, 12, 12 },
+    { 8, 0, 8, 0, 8, 0, 8, 0 },
+    { 8, 8, 8, 0, 8, 8, 12, 12 },
+    { 8, 8, 8, 0, 8, 8, 8, 0 }
+};
+
+static const int perm_table[2][8] = {
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC
+    },
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ,
+        0,
+        0,
+    }
+};
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    int access_perms = 0;
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+    int error_code = 0, is_dirty, is_user;
+    unsigned long page_offset;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+
+    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+        *page_size = TARGET_PAGE_SIZE;
+        // Boot mode: instruction fetches are taken from PROM
+        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
+            *physical = env->prom_addr | (address & 0x7ffffULL);
+            *prot = PAGE_READ | PAGE_EXEC;
+            return 0;
+        }
+        *physical = address;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
+    *physical = 0xffffffffffff0000ULL;
+
+    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    /* Ctx pde */
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+        return 1 << 2;
+    case 2: /* L0 PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 4 << 2;
+    case 1: /* L0 PDE */
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+            return (1 << 8) | (1 << 2);
+        case 3: /* Reserved */
+            return (1 << 8) | (4 << 2);
+        case 1: /* L1 PDE */
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+                return (2 << 8) | (1 << 2);
+            case 3: /* Reserved */
+                return (2 << 8) | (4 << 2);
+            case 1: /* L2 PDE */
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                    return (3 << 8) | (1 << 2);
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return (3 << 8) | (4 << 2);
+                case 2: /* L3 PTE */
+                    page_offset = (address & TARGET_PAGE_MASK) &
+                        (TARGET_PAGE_SIZE - 1);
+                }
+                *page_size = TARGET_PAGE_SIZE;
+                break;
+            case 2: /* L2 PTE */
+                page_offset = address & 0x3ffff;
+                *page_size = 0x40000;
+            }
+            break;
+        case 2: /* L1 PTE */
+            page_offset = address & 0xffffff;
+            *page_size = 0x1000000;
+        }
+    }
+
+    /* check access */
+    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+    error_code = access_table[*access_index][access_perms];
+    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
+        return error_code;
+
+    /* update page modified and dirty bits */
+    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
+    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+        pde |= PG_ACCESSED_MASK;
+        if (is_dirty)
+            pde |= PG_MODIFIED_MASK;
+        stl_phys_notdirty(pde_ptr, pde);
+    }
+
+    /* the page can be put in the TLB */
+    *prot = perm_table[is_user][access_perms];
+    if (!(pde & PG_MODIFIED_MASK)) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        *prot &= ~PAGE_WRITE;
+    }
+
+    /* Even if large ptes, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+    return error_code;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    target_phys_addr_t paddr;
+    target_ulong vaddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        vaddr = address & TARGET_PAGE_MASK;
+        paddr &= TARGET_PAGE_MASK;
+#ifdef DEBUG_MMU
+        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+               TARGET_FMT_lx "\n", address, paddr, vaddr);
+#endif
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    if (env->mmuregs[3]) /* Fault status register */
+        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
+    env->mmuregs[4] = address; /* Fault address register */
+
+    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
+        // No fault mode: if a mapping is available, just override
+        // permissions. If no mapping is available, redirect accesses to
+        // neverland. Fake/overridden mappings will be flushed when
+        // switching to normal mode.
+        vaddr = address & TARGET_PAGE_MASK;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+        return 0;
+    } else {
+        if (rw & 2)
+            env->exception_index = TT_TFAULT;
+        else
+            env->exception_index = TT_DFAULT;
+        return 1;
+    }
+}
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+        (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 0;
+    case 1: /* L1 PDE */
+        if (mmulev == 3)
+            return pde;
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+        case 3: /* Reserved */
+            return 0;
+        case 2: /* L1 PTE */
+            return pde;
+        case 1: /* L2 PDE */
+            if (mmulev == 2)
+                return pde;
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+            case 3: /* Reserved */
+                return 0;
+            case 2: /* L2 PTE */
+                return pde;
+            case 1: /* L3 PDE */
+                if (mmulev == 1)
+                    return pde;
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return 0;
+                case 2: /* L3 PTE */
+                    return pde;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    target_ulong va, va1, va2;
+    unsigned int n, m, o;
+    target_phys_addr_t pde_ptr, pa;
+    uint32_t pde;
+
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+        pde = mmu_probe(env, va, 2);
+        if (pde) {
+            pa = cpu_get_phys_page_debug(env, va);
+            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+                pde = mmu_probe(env, va1, 1);
+                if (pde) {
+                    pa = cpu_get_phys_page_debug(env, va1);
+                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+                                   va1, pa, pde);
+                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+                        pde = mmu_probe(env, va2, 0);
+                        if (pde) {
+                            pa = cpu_get_phys_page_debug(env, va2);
+                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
+                                           TARGET_FMT_plx " PTE: "
+                                           TARGET_FMT_lx "\n",
+                                           va2, pa, pde);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+#else /* !TARGET_SPARC64 */
+
+// 41 bit physical address space
+static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
+{
+    return x & 0x1ffffffffffULL;
+}
+
+/*
+ * UltraSparc IIi I/DMMUs
+ */
+
+// Returns true if TTE tag is valid and matches virtual address value in context
+// requires virtual address mask value calculated from TTE entry size
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+                                       uint64_t address, uint64_t context,
+                                       target_phys_addr_t *physical)
+{
+    uint64_t mask;
+
+    switch (TTE_PGSIZE(tlb->tte)) {
+    default:
+    case 0x0: // 8k
+        mask = 0xffffffffffffe000ULL;
+        break;
+    case 0x1: // 64k
+        mask = 0xffffffffffff0000ULL;
+        break;
+    case 0x2: // 512k
+        mask = 0xfffffffffff80000ULL;
+        break;
+    case 0x3: // 4M
+        mask = 0xffffffffffc00000ULL;
+        break;
+    }
+
+    // valid, context match, virtual address match?
+    if (TTE_IS_VALID(tlb->tte) &&
+        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
+        && compare_masked(address, tlb->tag, mask))
+    {
+        // decode physical address
+        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int get_physical_address_data(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int rw, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+    uint64_t sfsr = 0;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_READ | PAGE_WRITE;
+        return 0;
+    }
+
+    switch(mmu_idx) {
+    case MMU_USER_IDX:
+    case MMU_KERNEL_IDX:
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+        sfsr |= SFSR_CT_PRIMARY;
+        break;
+    case MMU_USER_SECONDARY_IDX:
+    case MMU_KERNEL_SECONDARY_IDX:
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
+        break;
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* FALLTHRU */
+    default:
+        context = 0;
+        break;
+    }
+
+    if (rw == 1) {
+        sfsr |= SFSR_WRITE_BIT;
+    } else if (rw == 4) {
+        sfsr |= SFSR_NF_BIT;
+    }
+
+    for (i = 0; i < 64; i++) {
+        // ctx match, vaddr match, valid?
+        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
+            int do_fault = 0;
+
+            // access ok?
+            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+                do_fault = 1;
+                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
+
+                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
+                            " mmu_idx=%d tl=%d\n",
+                            address, context, mmu_idx, env->tl);
+            }
+            if (rw == 4) {
+                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NF_E_BIT;
+                }
+            } else {
+                if (TTE_IS_NFO(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NFO_BIT;
+                }
+            }
+
+            if (do_fault) {
+                /* faults above are reported with TT_DFAULT. */
+                env->exception_index = TT_DFAULT;
+            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+                do_fault = 1;
+                env->exception_index = TT_DPROT;
+
+                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
+                            " mmu_idx=%d tl=%d\n",
+                            address, context, mmu_idx, env->tl);
+            }
+
+            if (!do_fault) {
+                *prot = PAGE_READ;
+                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
+                    *prot |= PAGE_WRITE;
+                }
+
+                TTE_SET_USED(env->dtlb[i].tte);
+
+                return 0;
+            }
+
+            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+                sfsr |= SFSR_OW_BIT; /* overflow (not read before
+                                        another fault) */
+            }
+
+            if (env->pstate & PS_PRIV) {
+                sfsr |= SFSR_PR_BIT;
+            }
+
+            /* FIXME: ASI field in SFSR must be set */
+            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
+
+            env->dmmu.sfar = address; /* Fault address register */
+
+            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+
+            return 1;
+        }
+    }
+
+    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
+                address, context);
+
+    /*
+     * On MMU misses:
+     * - UltraSPARC IIi: SFSR and SFAR unmodified
+     * - JPS1: SFAR updated and some fields of SFSR updated
+     */
+    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_DMISS;
+    return 1;
+}
+
+static int get_physical_address_code(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+        /* IMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_EXEC;
+        return 0;
+    }
+
+    if (env->tl == 0) {
+        /* PRIMARY context */
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+    } else {
+        /* NUCLEUS context */
+        context = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+        // ctx match, vaddr match, valid?
+        if (ultrasparc_tag_match(&env->itlb[i],
+                                 address, context, physical)) {
+            // access ok?
+            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+                /* Fault status register */
+                if (env->immu.sfsr & SFSR_VALID_BIT) {
+                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+                                                     another fault) */
+                } else {
+                    env->immu.sfsr = 0;
+                }
+                if (env->pstate & PS_PRIV) {
+                    env->immu.sfsr |= SFSR_PR_BIT;
+                }
+                if (env->tl > 0) {
+                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                }
+
+                /* FIXME: ASI field in SFSR must be set */
+                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+                env->exception_index = TT_TFAULT;
+
+                env->immu.tag_access = (address & ~0x1fffULL) | context;
+
+                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
+                            address, context);
+
+                return 1;
+            }
+            *prot = PAGE_EXEC;
+            TTE_SET_USED(env->itlb[i].tte);
+            return 0;
+        }
+    }
+
+    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
+                address, context);
+
+    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+    env->immu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_TMISS;
+    return 1;
+}
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    /* ??? We treat everything as a small page, then explicitly flush
+       everything when an entry is evicted.  */
+    *page_size = TARGET_PAGE_SIZE;
+
+#if defined (DEBUG_MMU)
+    /* safety net to catch wrong softmmu index use from dynamic code */
+    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
+        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
+                    " primary context=%" PRIx64
+                    " secondary context=%" PRIx64
+                " address=%" PRIx64
+                "\n",
+                (rw == 2 ? "CODE" : "DATA"),
+                env->tl, mmu_idx,
+                env->dmmu.mmu_primary_context,
+                env->dmmu.mmu_secondary_context,
+                address);
+    }
+#endif
+
+    if (rw == 2)
+        return get_physical_address_code(env, physical, prot, address,
+                                         mmu_idx);
+    else
+        return get_physical_address_data(env, physical, prot, address, rw,
+                                         mmu_idx);
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    target_ulong virt_addr, vaddr;
+    target_phys_addr_t paddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        virt_addr = address & TARGET_PAGE_MASK;
+        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
+                             (TARGET_PAGE_SIZE - 1));
+
+        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
+                    " vaddr %" PRIx64
+                    " mmu_idx=%d"
+                    " tl=%d"
+                    " primary context=%" PRIx64
+                    " secondary context=%" PRIx64
+                    "\n",
+                    address, paddr, vaddr, mmu_idx, env->tl,
+                    env->dmmu.mmu_primary_context,
+                    env->dmmu.mmu_secondary_context);
+
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+    // XXX
+    return 1;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    unsigned int i;
+    const char *mask;
+
+    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+                   PRId64 "\n",
+                   env->dmmu.mmu_primary_context,
+                   env->dmmu.mmu_secondary_context);
+    if ((env->lsu & DMMU_E) == 0) {
+        (*cpu_fprintf)(f, "DMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "DMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->dtlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->dtlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->dtlb[i].tte)?
+                               "global" : "local");
+            }
+        }
+    }
+    if ((env->lsu & IMMU_E) == 0) {
+        (*cpu_fprintf)(f, "IMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "IMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->itlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->itlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->itlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+                               TTE_IS_LOCKED(env->itlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->itlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->itlb[i].tte)?
+                               "global" : "local");
+            }
+        }
+    }
+}
+
+#endif /* TARGET_SPARC64 */
+#endif /* !CONFIG_USER_ONLY */
+
+
+#if !defined(CONFIG_USER_ONLY)
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+                                   target_ulong addr, int rw, int mmu_idx)
+{
+    target_ulong page_size;
+    int prot, access_index;
+
+    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+                                mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx)
+{
+    target_phys_addr_t phys_addr;
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_phys_addr_t phys_addr;
+    int mmu_idx = cpu_mmu_index(env);
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+            return -1;
+        }
+    }
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
+
+#ifdef TARGET_SPARC64
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_TMISS] = "Instruction Access MMU Miss",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CLRWIN] = "Clean Windows",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_DMISS] = "Data Access MMU Miss",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DPROT] = "Data Protection Error",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_PRIV_ACT] = "Privileged Action",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int intno = env->exception_index;
+    trap_state *tsptr;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x180) {
+            name = "Unknown";
+        } else if (intno >= 0x100) {
+            name = "Trap Instruction";
+        } else if (intno >= 0xc0) {
+            name = "Window Fill";
+        } else if (intno >= 0x80) {
+            name = "Window Spill";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+                " SP=%016" PRIx64 "\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->tl >= env->maxtl) {
+        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+                  " Error state", env->exception_index, env->tl, env->maxtl);
+        return;
+    }
+#endif
+    if (env->tl < env->maxtl - 1) {
+        env->tl++;
+    } else {
+        env->pstate |= PS_RED;
+        if (env->tl < env->maxtl) {
+            env->tl++;
+        }
+    }
+    tsptr = cpu_tsptr(env);
+
+    tsptr->tstate = (cpu_get_ccr(env) << 32) |
+        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+        cpu_get_cwp64(env);
+    tsptr->tpc = env->pc;
+    tsptr->tnpc = env->npc;
+    tsptr->tt = intno;
+
+    switch (intno) {
+    case TT_IVEC:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
+        break;
+    case TT_TFAULT:
+    case TT_DFAULT:
+    case TT_TMISS ... TT_TMISS + 3:
+    case TT_DMISS ... TT_DMISS + 3:
+    case TT_DPROT ... TT_DPROT + 3:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
+        break;
+    default:
+        cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
+        break;
+    }
+
+    if (intno == TT_CLRWIN) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
+    } else if ((intno & 0x1c0) == TT_SPILL) {
+        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
+    } else if ((intno & 0x1c0) == TT_FILL) {
+        cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+    }
+    env->tbr &= ~0x7fffULL;
+    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+}
+#else
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+    [TT_TFAULT] = "Instruction Access Fault",
+    [TT_ILL_INSN] = "Illegal Instruction",
+    [TT_PRIV_INSN] = "Privileged Instruction",
+    [TT_NFPU_INSN] = "FPU Disabled",
+    [TT_WIN_OVF] = "Window Overflow",
+    [TT_WIN_UNF] = "Window Underflow",
+    [TT_UNALIGNED] = "Unaligned Memory Access",
+    [TT_FP_EXCP] = "FPU Exception",
+    [TT_DFAULT] = "Data Access Fault",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_EXTINT | 0x1] = "External Interrupt 1",
+    [TT_EXTINT | 0x2] = "External Interrupt 2",
+    [TT_EXTINT | 0x3] = "External Interrupt 3",
+    [TT_EXTINT | 0x4] = "External Interrupt 4",
+    [TT_EXTINT | 0x5] = "External Interrupt 5",
+    [TT_EXTINT | 0x6] = "External Interrupt 6",
+    [TT_EXTINT | 0x7] = "External Interrupt 7",
+    [TT_EXTINT | 0x8] = "External Interrupt 8",
+    [TT_EXTINT | 0x9] = "External Interrupt 9",
+    [TT_EXTINT | 0xa] = "External Interrupt 10",
+    [TT_EXTINT | 0xb] = "External Interrupt 11",
+    [TT_EXTINT | 0xc] = "External Interrupt 12",
+    [TT_EXTINT | 0xd] = "External Interrupt 13",
+    [TT_EXTINT | 0xe] = "External Interrupt 14",
+    [TT_EXTINT | 0xf] = "External Interrupt 15",
+    [TT_TOVF] = "Tag Overflow",
+    [TT_CODE_ACCESS] = "Instruction Access Error",
+    [TT_DATA_ACCESS] = "Data Access Error",
+    [TT_DIV_ZERO] = "Division By Zero",
+    [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+    int cwp, intno = env->exception_index;
+
+#ifdef DEBUG_PCALL
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name;
+
+        if (intno < 0 || intno >= 0x100) {
+            name = "Unknown";
+        } else if (intno >= 0x80) {
+            name = "Trap Instruction";
+        } else {
+            name = excp_names[intno];
+            if (!name) {
+                name = "Unknown";
+            }
+        }
+
+        qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+                count, name, intno,
+                env->pc,
+                env->npc, env->regwptr[6]);
+        log_cpu_state(env, 0);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+
+            qemu_log("       code=");
+            ptr = (uint8_t *)env->pc;
+            for (i = 0; i < 16; i++) {
+                qemu_log(" %02x", ldub(ptr + i));
+            }
+            qemu_log("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+    if (env->psret == 0) {
+        cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
+                  env->exception_index);
+        return;
+    }
+#endif
+    env->psret = 0;
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
+    cpu_set_cwp(env, cwp);
+    env->regwptr[9] = env->pc;
+    env->regwptr[10] = env->npc;
+    env->psrps = env->psrs;
+    env->psrs = 1;
+    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
+    env->pc = env->tbr;
+    env->npc = env->pc + 4;
+    env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env->irq_manager, intno);
+    }
+#endif
+}
+#endif
+
+void cpu_reset(CPUSPARCState *env)
+{
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    tlb_flush(env, 1);
+    env->cwp = 0;
+#ifndef TARGET_SPARC64
+    env->wim = 1;
+#endif
+    env->regwptr = env->regbase + (env->cwp * 16);
+    CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+    env->cleanwin = env->nwindows - 2;
+    env->cansave = env->nwindows - 2;
+    env->pstate = PS_RMO | PS_PEF | PS_IE;
+    env->asi = 0x82; // Primary no-fault
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+    env->psret = 0;
+    env->psrs = 1;
+    env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+    env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+    env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+    env->tl = env->maxtl;
+    cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+    env->lsu = 0;
+#else
+    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+    env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+    env->pc = 0;
+    env->npc = env->pc + 4;
+#endif
+    env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+    sparc_def_t def1, *def = &def1;
+
+    if (cpu_sparc_find_by_name(def, cpu_model) < 0)
+        return -1;
+
+    env->def = qemu_mallocz(sizeof(*def));
+    memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+    if ((env->def->features & CPU_FEATURE_FLOAT))
+        env->def->features |= CPU_FEATURE_FLOAT128;
+#endif
+    env->cpu_model_str = cpu_model;
+    env->version = def->iu_version;
+    env->fsr = def->fpu_version;
+    env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+    env->mmuregs[0] |= def->mmu_version;
+    cpu_sparc_set_id(env, 0);
+    env->mxccregs[7] |= def->mxcc_version;
+#else
+    env->mmu_version = def->mmu_version;
+    env->maxtl = def->maxtl;
+    env->version |= def->maxtl << 8;
+    env->version |= def->nwindows - 1;
+#endif
+    return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+    free(env->def);
+    free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+    CPUSPARCState *env;
+
+    env = qemu_mallocz(sizeof(CPUSPARCState));
+    cpu_exec_init(env);
+
+    gen_intermediate_code_init(env);
+
+    if (cpu_sparc_register(env, cpu_model) < 0) {
+        cpu_sparc_close(env);
+        return NULL;
+    }
+    qemu_init_vcpu(env);
+
+    return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+    {
+        .name = "Fujitsu Sparc64",
+        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 4,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 III",
+        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 5,
+        .maxtl = 4,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 IV",
+        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu Sparc64 V",
+        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc I",
+        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc II",
+        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIi",
+        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI UltraSparc IIe",
+        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III",
+        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc III Cu",
+        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IIIi",
+        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV",
+        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_4,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc IV+",
+        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+    },
+    {
+        .name = "Sun UltraSparc IIIi+",
+        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_3,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Sun UltraSparc T1",
+        // defined in sparc_ifu_fdp.v and ctu.h
+        .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "Sun UltraSparc T2",
+        // defined in tlu_asi_ctl.v and n2_revid_cust.v
+        .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_sun4v,
+        .nwindows = 8,
+        .maxtl = 6,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+        | CPU_FEATURE_GL,
+    },
+    {
+        .name = "NEC UltraSparc I",
+        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+        .fpu_version = 0x00000000,
+        .mmu_version = mmu_us_12,
+        .nwindows = 8,
+        .maxtl = 5,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+#else
+    {
+        .name = "Fujitsu MB86900",
+        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Fujitsu MB86904",
+        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Fujitsu MB86907",
+        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LSI L64811",
+        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C601",
+        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Cypress CY7C611",
+        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "TI MicroSparc I",
+        .iu_version = 0x41000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x41000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x0000003f,
+        .nwindows = 7,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+        CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FMUL,
+    },
+    {
+        .name = "TI MicroSparc II",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x02000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016fff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI MicroSparc IIep",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x00ffffc0,
+        .mmu_cxr_mask = 0x000000ff,
+        .mmu_sfsr_mask = 0x00016bff,
+        .mmu_trcr_mask = 0x00ffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 40", // STP1020NPGA
+        .iu_version = 0x41000000, // SuperSPARC 2.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 50", // STP1020PGA
+        .iu_version = 0x40000000, // SuperSPARC 3.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 51",
+        .iu_version = 0x40000000, // SuperSPARC 3.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 60", // STP1020APGA
+        .iu_version = 0x40000000, // SuperSPARC 3.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc 61",
+        .iu_version = 0x44000000, // SuperSPARC 3.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "TI SuperSparc II",
+        .iu_version = 0x40000000, // SuperSPARC II 1.x
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
+        .mmu_bm = 0x00002000,
+        .mmu_ctpr_mask = 0xffffffc0,
+        .mmu_cxr_mask = 0x0000ffff,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .mxcc_version = 0x00000104,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT625",
+        .iu_version = 0x1e000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1e000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "Ross RT620",
+        .iu_version = 0x1f000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1f000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "BIT B5010",
+        .iu_version = 0x20000000,
+        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+        .mmu_version = 0x20000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Matsushita MN10501",
+        .iu_version = 0x50000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x50000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+        CPU_FEATURE_FSMULD,
+    },
+    {
+        .name = "Weitek W8601",
+        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES,
+    },
+    {
+        .name = "LEON2",
+        .iu_version = 0xf2000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf2000000,
+        .mmu_bm = 0x00004000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+    },
+    {
+        .name = "LEON3",
+        .iu_version = 0xf3000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf3000000,
+        .mmu_bm = 0x00000000,
+        .mmu_ctpr_mask = 0x007ffff0,
+        .mmu_cxr_mask = 0x0000003f,
+        .mmu_sfsr_mask = 0xffffffff,
+        .mmu_trcr_mask = 0xffffffff,
+        .nwindows = 8,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+    },
+#endif
+};
+
+static const char * const feature_name[] = {
+    "float",
+    "float128",
+    "swap",
+    "mul",
+    "div",
+    "flush",
+    "fsqrt",
+    "fmul",
+    "vis1",
+    "vis2",
+    "fsmuld",
+    "hypv",
+    "cmt",
+    "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+                           uint32_t features, const char *prefix)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
+        if (feature_name[i] && (features & (1 << i))) {
+            if (prefix)
+                (*cpu_fprintf)(f, "%s", prefix);
+            (*cpu_fprintf)(f, "%s ", feature_name[i]);
+        }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(feature_name); i++)
+        if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+            *features |= 1 << i;
+            return;
+        }
+    fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+    unsigned int i;
+    const sparc_def_t *def = NULL;
+    char *s = strdup(cpu_model);
+    char *featurestr, *name = strtok(s, ",");
+    uint32_t plus_features = 0;
+    uint32_t minus_features = 0;
+    uint64_t iu_version;
+    uint32_t fpu_version, mmu_version, nwindows;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        if (strcasecmp(name, sparc_defs[i].name) == 0) {
+            def = &sparc_defs[i];
+        }
+    }
+    if (!def)
+        goto error;
+    memcpy(cpu_def, def, sizeof(*def));
+
+    featurestr = strtok(NULL, ",");
+    while (featurestr) {
+        char *val;
+
+        if (featurestr[0] == '+') {
+            add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+        } else if (featurestr[0] == '-') {
+            add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+        } else if ((val = strchr(featurestr, '='))) {
+            *val = 0; val++;
+            if (!strcmp(featurestr, "iu_version")) {
+                char *err;
+
+                iu_version = strtoll(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+            } else if (!strcmp(featurestr, "fpu_version")) {
+                char *err;
+
+                fpu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+            } else if (!strcmp(featurestr, "mmu_version")) {
+                char *err;
+
+                mmu_version = strtol(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+            } else if (!strcmp(featurestr, "nwindows")) {
+                char *err;
+
+                nwindows = strtol(val, &err, 0);
+                if (!*val || *err || nwindows > MAX_NWINDOWS ||
+                    nwindows < MIN_NWINDOWS) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+                fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+            } else {
+                fprintf(stderr, "unrecognized feature %s\n", featurestr);
+                goto error;
+            }
+        } else {
+            fprintf(stderr, "feature string `%s' not in format "
+                    "(+feature|-feature|feature=xyz)\n", featurestr);
+            goto error;
+        }
+        featurestr = strtok(NULL, ",");
+    }
+    cpu_def->features |= plus_features;
+    cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+    print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+    free(s);
+    return 0;
+
+ error:
+    free(s);
+    return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
+                       sparc_defs[i].name,
+                       sparc_defs[i].iu_version,
+                       sparc_defs[i].fpu_version,
+                       sparc_defs[i].mmu_version,
+                       sparc_defs[i].nwindows);
+        print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+                       ~sparc_defs[i].features, "-");
+        print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+                       sparc_defs[i].features, "+");
+        (*cpu_fprintf)(f, "\n");
+    }
+    (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+    print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+    print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+    (*cpu_fprintf)(f, "\n");
+    (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+                   "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+                         uint32_t cc)
+{
+    cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
+                cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
+                cc & PSR_CARRY? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                    int flags)
+{
+    int i, x;
+
+    cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
+                env->npc);
+    cpu_fprintf(f, "General Registers:\n");
+
+    for (i = 0; i < 8; i++) {
+        if (i % REGS_PER_LINE == 0) {
+            cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+        }
+        cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+        if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+    cpu_fprintf(f, "\nCurrent Register Window:\n");
+    for (x = 0; x < 3; x++) {
+        for (i = 0; i < 8; i++) {
+            if (i % REGS_PER_LINE == 0) {
+                cpu_fprintf(f, "%%%c%d-%d: ",
+                            x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+                            i, i + REGS_PER_LINE - 1);
+            }
+            cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+            if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+                cpu_fprintf(f, "\n");
+            }
+        }
+    }
+    cpu_fprintf(f, "\nFloating Point Registers:\n");
+    for (i = 0; i < TARGET_FPREGS; i++) {
+        if ((i & 3) == 0)
+            cpu_fprintf(f, "%%f%02d:", i);
+        cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
+        if ((i & 3) == 3)
+            cpu_fprintf(f, "\n");
+    }
+#ifdef TARGET_SPARC64
+    cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+                (unsigned)cpu_get_ccr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+    cpu_fprintf(f, " xcc: ");
+    cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+    cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+                env->psrpil);
+    cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+                "cleanwin: %d cwp: %d\n",
+                env->cansave, env->canrestore, env->otherwin, env->wstate,
+                env->cleanwin, env->nwindows - 1 - env->cwp);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+                TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+    cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+    cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+    cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
+                env->psrps? 'P' : '-', env->psret? 'E' : '-',
+                env->wim);
+    cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+                env->fsr, env->y);
+#endif
+}
diff --git a/qemu-0.15.x/target-sparc/helper.h b/qemu-0.15.x/target-sparc/helper.h
new file mode 100644
index 0000000..2d36af3
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/helper.h
@@ -0,0 +1,165 @@
+#include "def-helper.h"
+
+#ifndef TARGET_SPARC64
+DEF_HELPER_0(rett, void)
+DEF_HELPER_1(wrpsr, void, tl)
+DEF_HELPER_0(rdpsr, tl)
+#else
+DEF_HELPER_1(wrpil, void, tl)
+DEF_HELPER_1(wrpstate, void, tl)
+DEF_HELPER_0(done, void)
+DEF_HELPER_0(retry, void)
+DEF_HELPER_0(flushw, void)
+DEF_HELPER_0(saved, void)
+DEF_HELPER_0(restored, void)
+DEF_HELPER_0(rdccr, tl)
+DEF_HELPER_1(wrccr, void, tl)
+DEF_HELPER_0(rdcwp, tl)
+DEF_HELPER_1(wrcwp, void, tl)
+DEF_HELPER_2(array8, tl, tl, tl)
+DEF_HELPER_2(alignaddr, tl, tl, tl)
+DEF_HELPER_1(popc, tl, tl)
+DEF_HELPER_3(ldda_asi, void, tl, int, int)
+DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
+DEF_HELPER_4(stf_asi, void, tl, int, int, int)
+DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
+DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
+DEF_HELPER_1(set_softint, void, i64)
+DEF_HELPER_1(clear_softint, void, i64)
+DEF_HELPER_1(write_softint, void, i64)
+DEF_HELPER_2(tick_set_count, void, ptr, i64)
+DEF_HELPER_1(tick_get_count, i64, ptr)
+DEF_HELPER_2(tick_set_limit, void, ptr, i64)
+#endif
+DEF_HELPER_2(check_align, void, tl, i32)
+DEF_HELPER_0(debug, void)
+DEF_HELPER_0(save, void)
+DEF_HELPER_0(restore, void)
+DEF_HELPER_2(udiv, tl, tl, tl)
+DEF_HELPER_2(udiv_cc, tl, tl, tl)
+DEF_HELPER_2(sdiv, tl, tl, tl)
+DEF_HELPER_2(sdiv_cc, tl, tl, tl)
+DEF_HELPER_2(stdf, void, tl, int)
+DEF_HELPER_2(lddf, void, tl, int)
+DEF_HELPER_2(ldqf, void, tl, int)
+DEF_HELPER_2(stqf, void, tl, int)
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
+DEF_HELPER_4(st_asi, void, tl, i64, int, int)
+#endif
+DEF_HELPER_1(ldfsr, void, i32)
+DEF_HELPER_0(check_ieee_exceptions, void)
+DEF_HELPER_0(clear_float_exceptions, void)
+DEF_HELPER_1(fabss, f32, f32)
+DEF_HELPER_1(fsqrts, f32, f32)
+DEF_HELPER_0(fsqrtd, void)
+DEF_HELPER_2(fcmps, void, f32, f32)
+DEF_HELPER_0(fcmpd, void)
+DEF_HELPER_2(fcmpes, void, f32, f32)
+DEF_HELPER_0(fcmped, void)
+DEF_HELPER_0(fsqrtq, void)
+DEF_HELPER_0(fcmpq, void)
+DEF_HELPER_0(fcmpeq, void)
+#ifdef TARGET_SPARC64
+DEF_HELPER_1(ldxfsr, void, i64)
+DEF_HELPER_0(fabsd, void)
+DEF_HELPER_2(fcmps_fcc1, void, f32, f32)
+DEF_HELPER_2(fcmps_fcc2, void, f32, f32)
+DEF_HELPER_2(fcmps_fcc3, void, f32, f32)
+DEF_HELPER_0(fcmpd_fcc1, void)
+DEF_HELPER_0(fcmpd_fcc2, void)
+DEF_HELPER_0(fcmpd_fcc3, void)
+DEF_HELPER_2(fcmpes_fcc1, void, f32, f32)
+DEF_HELPER_2(fcmpes_fcc2, void, f32, f32)
+DEF_HELPER_2(fcmpes_fcc3, void, f32, f32)
+DEF_HELPER_0(fcmped_fcc1, void)
+DEF_HELPER_0(fcmped_fcc2, void)
+DEF_HELPER_0(fcmped_fcc3, void)
+DEF_HELPER_0(fabsq, void)
+DEF_HELPER_0(fcmpq_fcc1, void)
+DEF_HELPER_0(fcmpq_fcc2, void)
+DEF_HELPER_0(fcmpq_fcc3, void)
+DEF_HELPER_0(fcmpeq_fcc1, void)
+DEF_HELPER_0(fcmpeq_fcc2, void)
+DEF_HELPER_0(fcmpeq_fcc3, void)
+#endif
+DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_0(shutdown, void)
+#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
+#define F_HELPER_DQ_0_0(name)                   \
+    F_HELPER_0_0(name ## d);                    \
+    F_HELPER_0_0(name ## q)
+
+F_HELPER_DQ_0_0(add);
+F_HELPER_DQ_0_0(sub);
+F_HELPER_DQ_0_0(mul);
+F_HELPER_DQ_0_0(div);
+
+DEF_HELPER_2(fadds, f32, f32, f32)
+DEF_HELPER_2(fsubs, f32, f32, f32)
+DEF_HELPER_2(fmuls, f32, f32, f32)
+DEF_HELPER_2(fdivs, f32, f32, f32)
+
+DEF_HELPER_2(fsmuld, void, f32, f32)
+F_HELPER_0_0(dmulq);
+
+DEF_HELPER_1(fnegs, f32, f32)
+DEF_HELPER_1(fitod, void, s32)
+DEF_HELPER_1(fitoq, void, s32)
+
+DEF_HELPER_1(fitos, f32, s32)
+
+#ifdef TARGET_SPARC64
+DEF_HELPER_0(fnegd, void)
+DEF_HELPER_0(fnegq, void)
+DEF_HELPER_0(fxtos, i32)
+F_HELPER_DQ_0_0(xto);
+#endif
+DEF_HELPER_0(fdtos, f32)
+DEF_HELPER_1(fstod, void, f32)
+DEF_HELPER_0(fqtos, f32)
+DEF_HELPER_1(fstoq, void, f32)
+F_HELPER_0_0(qtod);
+F_HELPER_0_0(dtoq);
+DEF_HELPER_1(fstoi, s32, f32)
+DEF_HELPER_0(fdtoi, s32)
+DEF_HELPER_0(fqtoi, s32)
+#ifdef TARGET_SPARC64
+DEF_HELPER_1(fstox, void, i32)
+F_HELPER_0_0(dtox);
+F_HELPER_0_0(qtox);
+F_HELPER_0_0(aligndata);
+
+F_HELPER_0_0(pmerge);
+F_HELPER_0_0(mul8x16);
+F_HELPER_0_0(mul8x16al);
+F_HELPER_0_0(mul8x16au);
+F_HELPER_0_0(mul8sux16);
+F_HELPER_0_0(mul8ulx16);
+F_HELPER_0_0(muld8sux16);
+F_HELPER_0_0(muld8ulx16);
+F_HELPER_0_0(expand);
+#define VIS_HELPER(name)                                 \
+    F_HELPER_0_0(name##16);                              \
+    DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \
+    F_HELPER_0_0(name##32);                              \
+    DEF_HELPER_2(f ## name ## 32s, i32, i32, i32)
+
+VIS_HELPER(padd);
+VIS_HELPER(psub);
+#define VIS_CMPHELPER(name)                              \
+    DEF_HELPER_0(f##name##16, i64);                      \
+    DEF_HELPER_0(f##name##32, i64)
+VIS_CMPHELPER(cmpgt);
+VIS_CMPHELPER(cmpeq);
+VIS_CMPHELPER(cmple);
+VIS_CMPHELPER(cmpne);
+#endif
+#undef F_HELPER_0_0
+#undef F_HELPER_DQ_0_0
+#undef VIS_HELPER
+#undef VIS_CMPHELPER
+DEF_HELPER_0(compute_psr, void);
+DEF_HELPER_0(compute_C_icc, i32);
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-sparc/machine.c b/qemu-0.15.x/target-sparc/machine.c
new file mode 100644
index 0000000..56ae041
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/machine.c
@@ -0,0 +1,225 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "qemu-timer.h"
+
+#include "cpu.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    CPUState *env = opaque;
+    int i;
+    uint32_t tmp;
+
+    // if env->cwp == env->nwindows - 1, this will set the ins of the last
+    // window as the outs of the first window
+    cpu_set_cwp(env, env->cwp);
+
+    for(i = 0; i < 8; i++)
+        qemu_put_betls(f, &env->gregs[i]);
+    qemu_put_be32s(f, &env->nwindows);
+    for(i = 0; i < env->nwindows * 16; i++)
+        qemu_put_betls(f, &env->regbase[i]);
+
+    /* FPU */
+    for(i = 0; i < TARGET_FPREGS; i++) {
+        union {
+            float32 f;
+            uint32_t i;
+        } u;
+        u.f = env->fpr[i];
+        qemu_put_be32(f, u.i);
+    }
+
+    qemu_put_betls(f, &env->pc);
+    qemu_put_betls(f, &env->npc);
+    qemu_put_betls(f, &env->y);
+    tmp = cpu_get_psr(env);
+    qemu_put_be32(f, tmp);
+    qemu_put_betls(f, &env->fsr);
+    qemu_put_betls(f, &env->tbr);
+    tmp = env->interrupt_index;
+    qemu_put_be32(f, tmp);
+    qemu_put_be32s(f, &env->pil_in);
+#ifndef TARGET_SPARC64
+    qemu_put_be32s(f, &env->wim);
+    /* MMU */
+    for (i = 0; i < 32; i++)
+        qemu_put_be32s(f, &env->mmuregs[i]);
+    for (i = 0; i < 4; i++) {
+        qemu_put_be64s(f, &env->mxccdata[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        qemu_put_be64s(f, &env->mxccregs[i]);
+    }
+    qemu_put_be32s(f, &env->mmubpctrv);
+    qemu_put_be32s(f, &env->mmubpctrc);
+    qemu_put_be32s(f, &env->mmubpctrs);
+    qemu_put_be64s(f, &env->mmubpaction);
+    for (i = 0; i < 4; i++) {
+        qemu_put_be64s(f, &env->mmubpregs[i]);
+    }
+#else
+    qemu_put_be64s(f, &env->lsu);
+    for (i = 0; i < 16; i++) {
+        qemu_put_be64s(f, &env->immuregs[i]);
+        qemu_put_be64s(f, &env->dmmuregs[i]);
+    }
+    for (i = 0; i < 64; i++) {
+        qemu_put_be64s(f, &env->itlb[i].tag);
+        qemu_put_be64s(f, &env->itlb[i].tte);
+        qemu_put_be64s(f, &env->dtlb[i].tag);
+        qemu_put_be64s(f, &env->dtlb[i].tte);
+    }
+    qemu_put_be32s(f, &env->mmu_version);
+    for (i = 0; i < MAXTL_MAX; i++) {
+        qemu_put_be64s(f, &env->ts[i].tpc);
+        qemu_put_be64s(f, &env->ts[i].tnpc);
+        qemu_put_be64s(f, &env->ts[i].tstate);
+        qemu_put_be32s(f, &env->ts[i].tt);
+    }
+    qemu_put_be32s(f, &env->xcc);
+    qemu_put_be32s(f, &env->asi);
+    qemu_put_be32s(f, &env->pstate);
+    qemu_put_be32s(f, &env->tl);
+    qemu_put_be32s(f, &env->cansave);
+    qemu_put_be32s(f, &env->canrestore);
+    qemu_put_be32s(f, &env->otherwin);
+    qemu_put_be32s(f, &env->wstate);
+    qemu_put_be32s(f, &env->cleanwin);
+    for (i = 0; i < 8; i++)
+        qemu_put_be64s(f, &env->agregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_put_be64s(f, &env->bgregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_put_be64s(f, &env->igregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_put_be64s(f, &env->mgregs[i]);
+    qemu_put_be64s(f, &env->fprs);
+    qemu_put_be64s(f, &env->tick_cmpr);
+    qemu_put_be64s(f, &env->stick_cmpr);
+    cpu_put_timer(f, env->tick);
+    cpu_put_timer(f, env->stick);
+    qemu_put_be64s(f, &env->gsr);
+    qemu_put_be32s(f, &env->gl);
+    qemu_put_be64s(f, &env->hpstate);
+    for (i = 0; i < MAXTL_MAX; i++)
+        qemu_put_be64s(f, &env->htstate[i]);
+    qemu_put_be64s(f, &env->hintp);
+    qemu_put_be64s(f, &env->htba);
+    qemu_put_be64s(f, &env->hver);
+    qemu_put_be64s(f, &env->hstick_cmpr);
+    qemu_put_be64s(f, &env->ssr);
+    cpu_put_timer(f, env->hstick);
+#endif
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    CPUState *env = opaque;
+    int i;
+    uint32_t tmp;
+
+    if (version_id < 6)
+        return -EINVAL;
+    for(i = 0; i < 8; i++)
+        qemu_get_betls(f, &env->gregs[i]);
+    qemu_get_be32s(f, &env->nwindows);
+    for(i = 0; i < env->nwindows * 16; i++)
+        qemu_get_betls(f, &env->regbase[i]);
+
+    /* FPU */
+    for(i = 0; i < TARGET_FPREGS; i++) {
+        union {
+            float32 f;
+            uint32_t i;
+        } u;
+        u.i = qemu_get_be32(f);
+        env->fpr[i] = u.f;
+    }
+
+    qemu_get_betls(f, &env->pc);
+    qemu_get_betls(f, &env->npc);
+    qemu_get_betls(f, &env->y);
+    tmp = qemu_get_be32(f);
+    env->cwp = 0; /* needed to ensure that the wrapping registers are
+                     correctly updated */
+    cpu_put_psr(env, tmp);
+    qemu_get_betls(f, &env->fsr);
+    qemu_get_betls(f, &env->tbr);
+    tmp = qemu_get_be32(f);
+    env->interrupt_index = tmp;
+    qemu_get_be32s(f, &env->pil_in);
+#ifndef TARGET_SPARC64
+    qemu_get_be32s(f, &env->wim);
+    /* MMU */
+    for (i = 0; i < 32; i++)
+        qemu_get_be32s(f, &env->mmuregs[i]);
+    for (i = 0; i < 4; i++) {
+        qemu_get_be64s(f, &env->mxccdata[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        qemu_get_be64s(f, &env->mxccregs[i]);
+    }
+    qemu_get_be32s(f, &env->mmubpctrv);
+    qemu_get_be32s(f, &env->mmubpctrc);
+    qemu_get_be32s(f, &env->mmubpctrs);
+    qemu_get_be64s(f, &env->mmubpaction);
+    for (i = 0; i < 4; i++) {
+        qemu_get_be64s(f, &env->mmubpregs[i]);
+    }
+#else
+    qemu_get_be64s(f, &env->lsu);
+    for (i = 0; i < 16; i++) {
+        qemu_get_be64s(f, &env->immuregs[i]);
+        qemu_get_be64s(f, &env->dmmuregs[i]);
+    }
+    for (i = 0; i < 64; i++) {
+        qemu_get_be64s(f, &env->itlb[i].tag);
+        qemu_get_be64s(f, &env->itlb[i].tte);
+        qemu_get_be64s(f, &env->dtlb[i].tag);
+        qemu_get_be64s(f, &env->dtlb[i].tte);
+    }
+    qemu_get_be32s(f, &env->mmu_version);
+    for (i = 0; i < MAXTL_MAX; i++) {
+        qemu_get_be64s(f, &env->ts[i].tpc);
+        qemu_get_be64s(f, &env->ts[i].tnpc);
+        qemu_get_be64s(f, &env->ts[i].tstate);
+        qemu_get_be32s(f, &env->ts[i].tt);
+    }
+    qemu_get_be32s(f, &env->xcc);
+    qemu_get_be32s(f, &env->asi);
+    qemu_get_be32s(f, &env->pstate);
+    qemu_get_be32s(f, &env->tl);
+    qemu_get_be32s(f, &env->cansave);
+    qemu_get_be32s(f, &env->canrestore);
+    qemu_get_be32s(f, &env->otherwin);
+    qemu_get_be32s(f, &env->wstate);
+    qemu_get_be32s(f, &env->cleanwin);
+    for (i = 0; i < 8; i++)
+        qemu_get_be64s(f, &env->agregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_get_be64s(f, &env->bgregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_get_be64s(f, &env->igregs[i]);
+    for (i = 0; i < 8; i++)
+        qemu_get_be64s(f, &env->mgregs[i]);
+    qemu_get_be64s(f, &env->fprs);
+    qemu_get_be64s(f, &env->tick_cmpr);
+    qemu_get_be64s(f, &env->stick_cmpr);
+    cpu_get_timer(f, env->tick);
+    cpu_get_timer(f, env->stick);
+    qemu_get_be64s(f, &env->gsr);
+    qemu_get_be32s(f, &env->gl);
+    qemu_get_be64s(f, &env->hpstate);
+    for (i = 0; i < MAXTL_MAX; i++)
+        qemu_get_be64s(f, &env->htstate[i]);
+    qemu_get_be64s(f, &env->hintp);
+    qemu_get_be64s(f, &env->htba);
+    qemu_get_be64s(f, &env->hver);
+    qemu_get_be64s(f, &env->hstick_cmpr);
+    qemu_get_be64s(f, &env->ssr);
+    cpu_get_timer(f, env->hstick);
+#endif
+    tlb_flush(env, 1);
+    return 0;
+}
diff --git a/qemu-0.15.x/target-sparc/op_helper.c b/qemu-0.15.x/target-sparc/op_helper.c
new file mode 100644
index 0000000..8962e38
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/op_helper.c
@@ -0,0 +1,4371 @@
+#include "exec.h"
+#include "host-utils.h"
+#include "helper.h"
+#include "sysemu.h"
+
+//#define DEBUG_MMU
+//#define DEBUG_MXCC
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
+//#define DEBUG_PCALL
+//#define DEBUG_PSTATE
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...)                                   \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, ...)                                  \
+    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, ...)                                   \
+    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_PSTATE
+#define DPRINTF_PSTATE(fmt, ...)                                   \
+    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
+#else
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size);
+#endif
+#endif
+
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+// Calculates TSB pointer value for fault page size 8k or 64k
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+                                       uint64_t tag_access_register,
+                                       int page_size)
+{
+    uint64_t tsb_base = tsb_register & ~0x1fffULL;
+    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+    int tsb_size  = tsb_register & 0xf;
+
+    // discard lower 13 bits which hold tag access context
+    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+    // now reorder bits
+    uint64_t tsb_base_mask = ~0x1fffULL;
+    uint64_t va = tag_access_va;
+
+    // move va bits to correct position
+    if (page_size == 8*1024) {
+        va >>= 9;
+    } else if (page_size == 64*1024) {
+        va >>= 12;
+    }
+
+    if (tsb_size) {
+        tsb_base_mask <<= tsb_size;
+    }
+
+    // calculate tsb_base mask and adjust va if split is in use
+    if (tsb_split) {
+        if (page_size == 8*1024) {
+            va &= ~(1ULL << (13 + tsb_size));
+        } else if (page_size == 64*1024) {
+            va |= (1ULL << (13 + tsb_size));
+        }
+        tsb_base_mask <<= 1;
+    }
+
+    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+// Calculates tag target register value by reordering bits
+// in tag access register
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+static void replace_tlb_entry(SparcTLBEntry *tlb,
+                              uint64_t tlb_tag, uint64_t tlb_tte,
+                              CPUState *env1)
+{
+    target_ulong mask, size, va, offset;
+
+    // flush page range if translation is valid
+    if (TTE_IS_VALID(tlb->tte)) {
+
+        mask = 0xffffffffffffe000ULL;
+        mask <<= 3 * ((tlb->tte >> 61) & 3);
+        size = ~mask + 1;
+
+        va = tlb->tag & mask;
+
+        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env1, va + offset);
+        }
+    }
+
+    tlb->tag = tlb_tag;
+    tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+                      const char* strmmu, CPUState *env1)
+{
+    unsigned int i;
+    target_ulong mask;
+    uint64_t context;
+
+    int is_demap_context = (demap_addr >> 6) & 1;
+
+    // demap context
+    switch ((demap_addr >> 4) & 3) {
+    case 0: // primary
+        context = env1->dmmu.mmu_primary_context;
+        break;
+    case 1: // secondary
+        context = env1->dmmu.mmu_secondary_context;
+        break;
+    case 2: // nucleus
+        context = 0;
+        break;
+    case 3: // reserved
+    default:
+        return;
+    }
+
+    for (i = 0; i < 64; i++) {
+        if (TTE_IS_VALID(tlb[i].tte)) {
+
+            if (is_demap_context) {
+                // will remove non-global entries matching context value
+                if (TTE_IS_GLOBAL(tlb[i].tte) ||
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            } else {
+                // demap page
+                // will remove any entry matching VA
+                mask = 0xffffffffffffe000ULL;
+                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+                    continue;
+                }
+
+                // entry should be global or matching context value
+                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            }
+
+            replace_tlb_entry(&tlb[i], 0, 0, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+        }
+    }
+}
+
+static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
+                                 uint64_t tlb_tag, uint64_t tlb_tte,
+                                 const char* strmmu, CPUState *env1)
+{
+    unsigned int i, replace_used;
+
+    // Try replacing invalid entry
+    for (i = 0; i < 64; i++) {
+        if (!TTE_IS_VALID(tlb[i].tte)) {
+            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+            return;
+        }
+    }
+
+    // All entries are valid, try replacing unlocked entry
+
+    for (replace_used = 0; replace_used < 2; ++replace_used) {
+
+        // Used entries are not replaced on first pass
+
+        for (i = 0; i < 64; i++) {
+            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
+
+                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
+                            strmmu, (replace_used?"used":"unused"), i);
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                return;
+            }
+        }
+
+        // Now reset used bit and search for unused entries again
+
+        for (i = 0; i < 64; i++) {
+            TTE_SET_UNUSED(tlb[i].tte);
+        }
+    }
+
+#ifdef DEBUG_MMU
+    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
+#endif
+    // error state?
+}
+
+#endif
+
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(env1))
+        addr &= 0xffffffffULL;
+#endif
+    return addr;
+}
+
+/* returns true if access using this ASI is to have address translated by MMU
+   otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+    /* Ultrasparc IIi translating asi
+       - note this list is defined by cpu implementation
+     */
+    switch (asi) {
+    case 0x04 ... 0x11:
+    case 0x16 ... 0x19:
+    case 0x1E ... 0x1F:
+    case 0x24 ... 0x2C:
+    case 0x70 ... 0x73:
+    case 0x78 ... 0x79:
+    case 0x80 ... 0xFF:
+        return 1;
+
+    default:
+        return 0;
+    }
+#else
+    /* TODO: check sparc32 bits */
+    return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+                                            int asi, target_ulong addr)
+{
+    if (is_translating_asi(asi)) {
+        return address_mask(env, addr);
+    } else {
+        return addr;
+    }
+}
+
+static void raise_exception(int tt)
+{
+    env->exception_index = tt;
+    cpu_loop_exit(env);
+}
+
+void HELPER(raise_exception)(int tt)
+{
+    raise_exception(tt);
+}
+
+void helper_shutdown(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+    qemu_system_shutdown_request();
+#endif
+}
+
+void helper_check_align(target_ulong addr, uint32_t align)
+{
+    if (addr & align) {
+#ifdef DEBUG_UNALIGNED
+    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+        raise_exception(TT_UNALIGNED);
+    }
+}
+
+#define F_HELPER(name, p) void helper_f##name##p(void)
+
+#define F_BINOP(name)                                           \
+    float32 helper_f ## name ## s (float32 src1, float32 src2)  \
+    {                                                           \
+        return float32_ ## name (src1, src2, &env->fp_status);  \
+    }                                                           \
+    F_HELPER(name, d)                                           \
+    {                                                           \
+        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+    }                                                           \
+    F_HELPER(name, q)                                           \
+    {                                                           \
+        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
+    }
+
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
+
+void helper_fsmuld(float32 src1, float32 src2)
+{
+    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
+                      float32_to_float64(src2, &env->fp_status),
+                      &env->fp_status);
+}
+
+void helper_fdmulq(void)
+{
+    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
+                       float64_to_float128(DT1, &env->fp_status),
+                       &env->fp_status);
+}
+
+float32 helper_fnegs(float32 src)
+{
+    return float32_chs(src);
+}
+
+#ifdef TARGET_SPARC64
+F_HELPER(neg, d)
+{
+    DT0 = float64_chs(DT1);
+}
+
+F_HELPER(neg, q)
+{
+    QT0 = float128_chs(QT1);
+}
+#endif
+
+/* Integer to float conversion.  */
+float32 helper_fitos(int32_t src)
+{
+    return int32_to_float32(src, &env->fp_status);
+}
+
+void helper_fitod(int32_t src)
+{
+    DT0 = int32_to_float64(src, &env->fp_status);
+}
+
+void helper_fitoq(int32_t src)
+{
+    QT0 = int32_to_float128(src, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+float32 helper_fxtos(void)
+{
+    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, d)
+{
+    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, q)
+{
+    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+}
+#endif
+#undef F_HELPER
+
+/* floating point conversion */
+float32 helper_fdtos(void)
+{
+    return float64_to_float32(DT1, &env->fp_status);
+}
+
+void helper_fstod(float32 src)
+{
+    DT0 = float32_to_float64(src, &env->fp_status);
+}
+
+float32 helper_fqtos(void)
+{
+    return float128_to_float32(QT1, &env->fp_status);
+}
+
+void helper_fstoq(float32 src)
+{
+    QT0 = float32_to_float128(src, &env->fp_status);
+}
+
+void helper_fqtod(void)
+{
+    DT0 = float128_to_float64(QT1, &env->fp_status);
+}
+
+void helper_fdtoq(void)
+{
+    QT0 = float64_to_float128(DT1, &env->fp_status);
+}
+
+/* Float to integer conversion.  */
+int32_t helper_fstoi(float32 src)
+{
+    return float32_to_int32_round_to_zero(src, &env->fp_status);
+}
+
+int32_t helper_fdtoi(void)
+{
+    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
+}
+
+int32_t helper_fqtoi(void)
+{
+    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fstox(float32 src)
+{
+    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
+}
+
+void helper_fdtox(void)
+{
+    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+}
+
+void helper_fqtox(void)
+{
+    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+}
+
+void helper_faligndata(void)
+{
+    uint64_t tmp;
+
+    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+    /* on many architectures a shift of 64 does nothing */
+    if ((env->gsr & 7) != 0) {
+        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+    }
+    *((uint64_t *)&DT0) = tmp;
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+    uint8_t b[8];
+    uint16_t w[4];
+    int16_t sw[4];
+    uint32_t l[2];
+    uint64_t ll;
+    float64 d;
+} vis64;
+
+typedef union {
+    uint8_t b[4];
+    uint16_t w[2];
+    uint32_t l;
+    float32 f;
+} vis32;
+
+void helper_fpmerge(void)
+{
+    vis64 s, d;
+
+    s.d = DT0;
+    d.d = DT1;
+
+    // Reverse calculation order to handle overlap
+    d.VIS_B64(7) = s.VIS_B64(3);
+    d.VIS_B64(6) = d.VIS_B64(3);
+    d.VIS_B64(5) = s.VIS_B64(2);
+    d.VIS_B64(4) = d.VIS_B64(2);
+    d.VIS_B64(3) = s.VIS_B64(1);
+    d.VIS_B64(2) = d.VIS_B64(1);
+    d.VIS_B64(1) = s.VIS_B64(0);
+    //d.VIS_B64(0) = d.VIS_B64(0);
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16al(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8x16au(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmul8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmuld8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fmuld8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void helper_fexpand(void)
+{
+    vis32 s;
+    vis64 d;
+
+    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+    d.d = DT1;
+    d.VIS_W64(0) = s.VIS_B32(0) << 4;
+    d.VIS_W64(1) = s.VIS_B32(1) << 4;
+    d.VIS_W64(2) = s.VIS_B32(2) << 4;
+    d.VIS_W64(3) = s.VIS_B32(3) << 4;
+
+    DT0 = d.d;
+}
+
+#define VIS_HELPER(name, F)                             \
+    void name##16(void)                                 \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
+        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
+        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
+        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
+        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
+                                                        \
+        return d.l;                                     \
+    }                                                   \
+                                                        \
+    void name##32(void)                                 \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
+        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.l = src1;                                     \
+        d.l = src2;                                     \
+                                                        \
+        d.l = F(d.l, s.l);                              \
+                                                        \
+        return d.l;                                     \
+    }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_HELPER(helper_fpadd, FADD)
+VIS_HELPER(helper_fpsub, FSUB)
+
+#define VIS_CMPHELPER(name, F)                                        \
+    uint64_t name##16(void)                                       \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
+        d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0;    \
+        d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0;    \
+        d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0;           \
+                                                                  \
+        return d.ll;                                              \
+    }                                                             \
+                                                                  \
+    uint64_t name##32(void)                                       \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
+        d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
+        d.VIS_L64(1) = 0;                                         \
+                                                                  \
+        return d.ll;                                              \
+    }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
+VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
+VIS_CMPHELPER(helper_fcmple, FCMPLE)
+VIS_CMPHELPER(helper_fcmpne, FCMPNE)
+#endif
+
+void helper_check_ieee_exceptions(void)
+{
+    target_ulong status;
+
+    status = get_float_exception_flags(&env->fp_status);
+    if (status) {
+        /* Copy IEEE 754 flags into FSR */
+        if (status & float_flag_invalid)
+            env->fsr |= FSR_NVC;
+        if (status & float_flag_overflow)
+            env->fsr |= FSR_OFC;
+        if (status & float_flag_underflow)
+            env->fsr |= FSR_UFC;
+        if (status & float_flag_divbyzero)
+            env->fsr |= FSR_DZC;
+        if (status & float_flag_inexact)
+            env->fsr |= FSR_NXC;
+
+        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+            /* Unmasked exception, generate a trap */
+            env->fsr |= FSR_FTT_IEEE_EXCP;
+            raise_exception(TT_FP_EXCP);
+        } else {
+            /* Accumulate exceptions */
+            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+        }
+    }
+}
+
+void helper_clear_float_exceptions(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
+float32 helper_fabss(float32 src)
+{
+    return float32_abs(src);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fabsd(void)
+{
+    DT0 = float64_abs(DT1);
+}
+
+void helper_fabsq(void)
+{
+    QT0 = float128_abs(QT1);
+}
+#endif
+
+float32 helper_fsqrts(float32 src)
+{
+    return float32_sqrt(src, &env->fp_status);
+}
+
+void helper_fsqrtd(void)
+{
+    DT0 = float64_sqrt(DT1, &env->fp_status);
+}
+
+void helper_fsqrtq(void)
+{
+    QT0 = float128_sqrt(QT1, &env->fp_status);
+}
+
+#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
+    void glue(helper_, name) (void)                                     \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
+                     glue(size, _is_any_nan)(reg2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
+        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                raise_exception(TT_FP_EXCP);                            \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+#define GEN_FCMPS(name, size, FS, E)                                    \
+    void glue(helper_, name)(float32 src1, float32 src2)                \
+    {                                                                   \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(src1) ||                      \
+                     glue(size, _is_any_nan)(src2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
+        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
+        case float_relation_unordered:                                  \
+            if ((env->fsr & FSR_NVM)) {                                 \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
+                raise_exception(TT_FP_EXCP);                            \
+            } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
+                env->fsr |= FSR_NVA;                                    \
+            }                                                           \
+            break;                                                      \
+        case float_relation_less:                                       \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
+            break;                                                      \
+        case float_relation_greater:                                    \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
+            break;                                                      \
+        default:                                                        \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            break;                                                      \
+        }                                                               \
+    }
+
+GEN_FCMPS(fcmps, float32, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMPS(fcmpes, float32, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+
+static uint32_t compute_all_flags(void)
+{
+    return env->psr & PSR_ICC;
+}
+
+static uint32_t compute_C_flags(void)
+{
+    return env->psr & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_icc(int32_t dst)
+{
+    uint32_t ret = 0;
+
+    if (dst == 0) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_flags_xcc(void)
+{
+    return env->xcc & PSR_ICC;
+}
+
+static uint32_t compute_C_flags_xcc(void)
+{
+    return env->xcc & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_xcc(target_long dst)
+{
+    uint32_t ret = 0;
+
+    if (!dst) {
+        ret = PSR_ZERO;
+    } else if (dst < 0) {
+        ret = PSR_NEG;
+    }
+    return ret;
+}
+#endif
+
+static inline uint32_t get_V_div_icc(target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src2 != 0) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_div(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_V_div_icc(CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_div(void)
+{
+    return 0;
+}
+
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
+{
+    uint32_t ret = 0;
+
+    if (dst < src1) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
+                                         target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_add_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_add_xcc(CC_DST, CC_SRC);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add_xcc(void)
+{
+    return get_C_add_xcc(CC_DST, CC_SRC);
+}
+#endif
+
+static uint32_t compute_all_add(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_add(void)
+{
+    return get_C_add_icc(CC_DST, CC_SRC);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_addx_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_addx(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_addx(void)
+{
+    uint32_t ret;
+
+    ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if ((src1 | src2) & 0x3) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_tadd(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_taddtv(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    return ret;
+}
+
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+                                      uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+                                     uint32_t src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (src1 < src2) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+                                      target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+        ret = PSR_CARRY;
+    }
+    return ret;
+}
+
+static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
+                                     target_ulong src2)
+{
+    uint32_t ret = 0;
+
+    if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+        ret = PSR_OVF;
+    }
+    return ret;
+}
+
+static uint32_t compute_all_sub_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub_xcc(void)
+{
+    return get_C_sub_xcc(CC_SRC, CC_SRC2);
+}
+#endif
+
+static uint32_t compute_all_sub(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_sub(void)
+{
+    return get_C_sub_icc(CC_SRC, CC_SRC2);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_subx_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_xcc(CC_DST);
+    ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx_xcc(void)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+#endif
+
+static uint32_t compute_all_subx(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_C_subx(void)
+{
+    uint32_t ret;
+
+    ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsub(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+    ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_tsubtv(void)
+{
+    uint32_t ret;
+
+    ret = get_NZ_icc(CC_DST);
+    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+    return ret;
+}
+
+static uint32_t compute_all_logic(void)
+{
+    return get_NZ_icc(CC_DST);
+}
+
+static uint32_t compute_C_logic(void)
+{
+    return 0;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_logic_xcc(void)
+{
+    return get_NZ_xcc(CC_DST);
+}
+#endif
+
+typedef struct CCTable {
+    uint32_t (*compute_all)(void); /* return all the flags */
+    uint32_t (*compute_c)(void);  /* return the C flag */
+} CCTable;
+
+static const CCTable icc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
+    [CC_OP_DIV] = { compute_all_div, compute_C_div },
+    [CC_OP_ADD] = { compute_all_add, compute_C_add },
+    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+    [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+    [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
+    [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
+    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+    [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+    [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
+    [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
+};
+
+#ifdef TARGET_SPARC64
+static const CCTable xcc_table[CC_OP_NB] = {
+    /* CC_OP_DYNAMIC should never happen */
+    [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
+    [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
+    [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
+    [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
+    [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
+    [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
+    [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
+};
+#endif
+
+void helper_compute_psr(void)
+{
+    uint32_t new_psr;
+
+    new_psr = icc_table[CC_OP].compute_all();
+    env->psr = new_psr;
+#ifdef TARGET_SPARC64
+    new_psr = xcc_table[CC_OP].compute_all();
+    env->xcc = new_psr;
+#endif
+    CC_OP = CC_OP_FLAGS;
+}
+
+uint32_t helper_compute_C_icc(void)
+{
+    uint32_t ret;
+
+    ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
+    return ret;
+}
+
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst[4] = src[4];
+    dst[5] = src[5];
+    dst[6] = src[6];
+    dst[7] = src[7];
+}
+
+static void set_cwp(int new_cwp)
+{
+    /* put the modified wrap registers at their proper location */
+    if (env->cwp == env->nwindows - 1) {
+        memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+    }
+    env->cwp = new_cwp;
+
+    /* put the wrap registers at their temporary location */
+    if (new_cwp == env->nwindows - 1) {
+        memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+    }
+    env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+void cpu_set_cwp(CPUState *env1, int new_cwp)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    set_cwp(new_cwp);
+    env = saved_env;
+}
+
+static target_ulong get_psr(void)
+{
+    helper_compute_psr();
+
+#if !defined (TARGET_SPARC64)
+    return env->version | (env->psr & PSR_ICC) |
+        (env->psref? PSR_EF : 0) |
+        (env->psrpil << 8) |
+        (env->psrs? PSR_S : 0) |
+        (env->psrps? PSR_PS : 0) |
+        (env->psret? PSR_ET : 0) | env->cwp;
+#else
+    return env->psr & PSR_ICC;
+#endif
+}
+
+target_ulong cpu_get_psr(CPUState *env1)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = get_psr();
+    env = saved_env;
+    return ret;
+}
+
+static void put_psr(target_ulong val)
+{
+    env->psr = val & PSR_ICC;
+#if !defined (TARGET_SPARC64)
+    env->psref = (val & PSR_EF)? 1 : 0;
+    env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+    cpu_check_irqs(env);
+#endif
+#if !defined (TARGET_SPARC64)
+    env->psrs = (val & PSR_S)? 1 : 0;
+    env->psrps = (val & PSR_PS)? 1 : 0;
+    env->psret = (val & PSR_ET)? 1 : 0;
+    set_cwp(val & PSR_CWP);
+#endif
+    env->cc_op = CC_OP_FLAGS;
+}
+
+void cpu_put_psr(CPUState *env1, target_ulong val)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    put_psr(val);
+    env = saved_env;
+}
+
+static int cwp_inc(int cwp)
+{
+    if (unlikely(cwp >= env->nwindows)) {
+        cwp -= env->nwindows;
+    }
+    return cwp;
+}
+
+int cpu_cwp_inc(CPUState *env1, int cwp)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = cwp_inc(cwp);
+    env = saved_env;
+    return ret;
+}
+
+static int cwp_dec(int cwp)
+{
+    if (unlikely(cwp < 0)) {
+        cwp += env->nwindows;
+    }
+    return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env1, int cwp)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = cwp_dec(cwp);
+    env = saved_env;
+    return ret;
+}
+
+#ifdef TARGET_SPARC64
+GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+
+GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+
+GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+
+GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+
+GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+
+GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
+#undef GEN_FCMPS
+
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
+    defined(DEBUG_MXCC)
+static void dump_mxcc(CPUState *env)
+{
+    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccdata[0], env->mxccdata[1],
+           env->mxccdata[2], env->mxccdata[3]);
+    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n"
+           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccregs[0], env->mxccregs[1],
+           env->mxccregs[2], env->mxccregs[3],
+           env->mxccregs[4], env->mxccregs[5],
+           env->mxccregs[6], env->mxccregs[7]);
+}
+#endif
+
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
+    && defined(DEBUG_ASI)
+static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
+                     uint64_t r1)
+{
+    switch (size)
+    {
+    case 1:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xff);
+        break;
+    case 2:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffff);
+        break;
+    case 4:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffffffff);
+        break;
+    case 8:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
+                    addr, asi, r1);
+        break;
+    }
+}
+#endif
+
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_int(void)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+
+        /* These values must always be read as zeros */
+        val &= ~CACHE_CTRL_FD;
+        val &= ~CACHE_CTRL_FI;
+        val &= ~CACHE_CTRL_IB;
+        val &= ~CACHE_CTRL_IP;
+        val &= ~CACHE_CTRL_DP;
+
+        env->cache_control = val;
+        break;
+    case 0x04:              /* Instruction cache configuration */
+    case 0x08:              /* Data cache configuration */
+        /* Read Only */
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+        break;
+    };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+        ret = env->cache_control;
+        break;
+
+        /* Configuration registers are read and only always keep those
+           predefined values */
+
+    case 0x04:              /* Instruction cache configuration */
+        ret = 0x10220000;
+        break;
+    case 0x08:              /* Data cache configuration */
+        ret = 0x18220000;
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+        break;
+    };
+    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
+
+void leon3_irq_manager(void *irq_manager, int intno)
+{
+    leon3_irq_ack(irq_manager, intno);
+    leon3_cache_control_int();
+}
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
+    uint32_t last_addr = addr;
+#endif
+
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                ret = leon3_cache_control_ld(addr, size);
+            }
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8)
+                ret = env->mxccregs[3];
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4)
+                ret = env->mxccregs[3];
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00c00: /* Module reset register */
+            if (size == 8) {
+                ret = env->mxccregs[5];
+                // should we do something here?
+            } else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8)
+                ret = env->mxccregs[7];
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
+                     "addr = %08x -> ret = %" PRIx64 ","
+                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU probe */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            if (mmulev > 4)
+                ret = 0;
+            else
+                ret = mmu_probe(env, addr, mmulev);
+            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
+                        addr, mmulev, ret);
+        }
+        break;
+    case 4: /* read MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+
+            ret = env->mmuregs[reg];
+            if (reg == 3) /* Fault status cleared on read */
+                env->mmuregs[3] = 0;
+            else if (reg == 0x13) /* Fault status read */
+                ret = env->mmuregs[3];
+            else if (reg == 0x14) /* Fault address read */
+                ret = env->mmuregs[4];
+            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
+        }
+        break;
+    case 5: // Turbosparc ITLB Diagnostic
+    case 6: // Turbosparc DTLB Diagnostic
+    case 7: // Turbosparc IOTLB Diagnostic
+        break;
+    case 9: /* Supervisor code access */
+        switch(size) {
+        case 1:
+            ret = ldub_code(addr);
+            break;
+        case 2:
+            ret = lduw_code(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_code(addr);
+            break;
+        case 8:
+            ret = ldq_code(addr);
+            break;
+        }
+        break;
+    case 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            ret = ldub_user(addr);
+            break;
+        case 2:
+            ret = lduw_user(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(addr);
+            break;
+        case 8:
+            ret = ldq_user(addr);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            ret = ldub_kernel(addr);
+            break;
+        case 2:
+            ret = lduw_kernel(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(addr);
+            break;
+        case 8:
+            ret = ldq_kernel(addr);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+        break;
+    case 0x20: /* MMU passthrough */
+        switch(size) {
+        case 1:
+            ret = ldub_phys(addr);
+            break;
+        case 2:
+            ret = lduw_phys(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_phys(addr);
+            break;
+        case 8:
+            ret = ldq_phys(addr);
+            break;
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        switch(size) {
+        case 1:
+            ret = ldub_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 2:
+            ret = lduw_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        default:
+        case 4:
+            ret = ldl_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 8:
+            ret = ldq_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        }
+        break;
+    case 0x30: // Turbosparc secondary cache diagnostic
+    case 0x31: // Turbosparc RAM snoop
+    case 0x32: // Turbosparc page table descriptor diagnostic
+    case 0x39: /* data cache diagnostic register */
+        ret = 0;
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch(reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                ret = env->mmubpregs[reg];
+                break;
+            case 1: /* Breakpoint Mask */
+                ret = env->mmubpregs[reg];
+                break;
+            case 2: /* Breakpoint Control */
+                ret = env->mmubpregs[reg];
+                break;
+            case 3: /* Breakpoint Status */
+                ret = env->mmubpregs[reg];
+                env->mmubpregs[reg] = 0ULL;
+                break;
+            }
+            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
+                        ret);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        ret = env->mmubpctrv;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        ret = env->mmubpctrc;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        ret = env->mmubpctrs;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        ret = env->mmubpaction;
+        break;
+    case 8: /* User code access, XXX */
+    default:
+        do_unassigned_access(addr, 0, 0, asi, size);
+        ret = 0;
+        break;
+    }
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+{
+    helper_check_align(addr, size - 1);
+    switch(asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                leon3_cache_control_st(addr, val, size);
+            }
+            break;
+
+        case 0x01c00000: /* MXCC stream data register 0 */
+            if (size == 8)
+                env->mxccdata[0] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00008: /* MXCC stream data register 1 */
+            if (size == 8)
+                env->mxccdata[1] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00010: /* MXCC stream data register 2 */
+            if (size == 8)
+                env->mxccdata[2] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00018: /* MXCC stream data register 3 */
+            if (size == 8)
+                env->mxccdata[3] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00100: /* MXCC stream source */
+            if (size == 8)
+                env->mxccregs[0] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        0);
+            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        8);
+            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        16);
+            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        24);
+            break;
+        case 0x01c00200: /* MXCC stream destination */
+            if (size == 8)
+                env->mxccregs[1] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
+                     env->mxccdata[0]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
+                     env->mxccdata[1]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
+                     env->mxccdata[2]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
+                     env->mxccdata[3]);
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8)
+                env->mxccregs[3] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4)
+                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
+                    | val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00e00: /* MXCC error register  */
+            // writing a 1 bit clears the error
+            if (size == 8)
+                env->mxccregs[6] &= ~val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8)
+                env->mxccregs[7] = val;
+            else
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
+                     asi, size, addr, val);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU flush */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            DPRINTF_MMU("mmu flush level %d\n", mmulev);
+            switch (mmulev) {
+            case 0: // flush page
+                tlb_flush_page(env, addr & 0xfffff000);
+                break;
+            case 1: // flush segment (256k)
+            case 2: // flush region (16M)
+            case 3: // flush context (4G)
+            case 4: // flush entire
+                tlb_flush(env, 1);
+                break;
+            default:
+                break;
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 4: /* write MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+            uint32_t oldreg;
+
+            oldreg = env->mmuregs[reg];
+            switch(reg) {
+            case 0: // Control Register
+                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+                                    (val & 0x00ffffff);
+                // Mappings generated during no-fault mode or MMU
+                // disabled mode are invalid in normal mode
+                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
+                    tlb_flush(env, 1);
+                break;
+            case 1: // Context Table Pointer Register
+                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
+                break;
+            case 2: // Context Register
+                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
+                if (oldreg != env->mmuregs[reg]) {
+                    /* we flush when the MMU context changes because
+                       QEMU has no MMU context support */
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 3: // Synchronous Fault Status Register with Clear
+            case 4: // Synchronous Fault Address Register
+                break;
+            case 0x10: // TLB Replacement Control Register
+                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
+                break;
+            case 0x13: // Synchronous Fault Status Register with Read and Clear
+                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
+                break;
+            case 0x14: // Synchronous Fault Address Register
+                env->mmuregs[4] = val;
+                break;
+            default:
+                env->mmuregs[reg] = val;
+                break;
+            }
+            if (oldreg != env->mmuregs[reg]) {
+                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
+                            reg, oldreg, env->mmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 5: // Turbosparc ITLB Diagnostic
+    case 6: // Turbosparc DTLB Diagnostic
+    case 7: // Turbosparc IOTLB Diagnostic
+        break;
+    case 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            stb_user(addr, val);
+            break;
+        case 2:
+            stw_user(addr, val);
+            break;
+        default:
+        case 4:
+            stl_user(addr, val);
+            break;
+        case 8:
+            stq_user(addr, val);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            stb_kernel(addr, val);
+            break;
+        case 2:
+            stw_kernel(addr, val);
+            break;
+        default:
+        case 4:
+            stl_kernel(addr, val);
+            break;
+        case 8:
+            stq_kernel(addr, val);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+    case 0x10: /* I/D-cache flush page */
+    case 0x11: /* I/D-cache flush segment */
+    case 0x12: /* I/D-cache flush region */
+    case 0x13: /* I/D-cache flush context */
+    case 0x14: /* I/D-cache flush user */
+        break;
+    case 0x17: /* Block copy, sta access */
+        {
+            // val = src
+            // addr = dst
+            // copy 32 bytes
+            unsigned int i;
+            uint32_t src = val & ~3, dst = addr & ~3, temp;
+
+            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+                temp = ldl_kernel(src);
+                stl_kernel(dst, temp);
+            }
+        }
+        break;
+    case 0x1f: /* Block fill, stda access */
+        {
+            // addr = dst
+            // fill 32 bytes with val
+            unsigned int i;
+            uint32_t dst = addr & 7;
+
+            for (i = 0; i < 32; i += 8, dst += 8)
+                stq_kernel(dst, val);
+        }
+        break;
+    case 0x20: /* MMU passthrough */
+        {
+            switch(size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+            default:
+                stl_phys(addr, val);
+                break;
+            case 8:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        {
+            switch(size) {
+            case 1:
+                stb_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 2:
+                stw_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 4:
+            default:
+                stl_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 8:
+                stq_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            }
+        }
+        break;
+    case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
+    case 0x31: // store buffer data, Ross RT620 I-cache flush or
+               // Turbosparc snoop RAM
+    case 0x32: // store buffer control or Turbosparc page table
+               // descriptor diagnostic
+    case 0x36: /* I-cache flash clear */
+    case 0x37: /* D-cache flash clear */
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch(reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 1: /* Breakpoint Mask */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 2: /* Breakpoint Control */
+                env->mmubpregs[reg] = (val & 0x7fULL);
+                break;
+            case 3: /* Breakpoint Status */
+                env->mmubpregs[reg] = (val & 0xfULL);
+                break;
+            }
+            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
+                        env->mmuregs[reg]);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        env->mmubpctrv = val & 0xffffffff;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        env->mmubpctrc = val & 0x3;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        env->mmubpctrs = val & 0x3;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        env->mmubpaction = val & 0x1fff;
+        break;
+    case 8: /* User code access, XXX */
+    case 9: /* Supervisor code access, XXX */
+    default:
+        do_unassigned_access(addr, 1, 0, asi, size);
+        break;
+    }
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+}
+
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0x82: // Primary no-fault
+    case 0x8a: // Primary no-fault LE
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        // Fall through
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        {
+            switch(size) {
+            case 1:
+                ret = ldub_raw(addr);
+                break;
+            case 2:
+                ret = lduw_raw(addr);
+                break;
+            case 4:
+                ret = ldl_raw(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(addr);
+                break;
+            }
+        }
+        break;
+    case 0x83: // Secondary no-fault
+    case 0x8b: // Secondary no-fault LE
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        // Fall through
+    case 0x81: // Secondary
+    case 0x89: // Secondary LE
+        // XXX
+        break;
+    default:
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0x8a: // Primary no-fault LE
+    case 0x8b: // Secondary no-fault LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch(asi) {
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        {
+            switch(size) {
+            case 1:
+                stb_raw(addr, val);
+                break;
+            case 2:
+                stw_raw(addr, val);
+                break;
+            case 4:
+                stl_raw(addr, val);
+                break;
+            case 8:
+            default:
+                stq_raw(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x81: // Secondary
+    case 0x89: // Secondary LE
+        // XXX
+        return;
+
+    case 0x82: // Primary no-fault, RO
+    case 0x83: // Secondary no-fault, RO
+    case 0x8a: // Primary no-fault LE, RO
+    case 0x8b: // Secondary no-fault LE, RO
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV)))
+        raise_exception(TT_PRIV_ACT);
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* process nonfaulting loads first */
+    if ((asi & 0xf6) == 0x82) {
+        int mmu_idx;
+
+        /* secondary space access has lowest asi bit equal to 1 */
+        if (env->pstate & PS_PRIV) {
+            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+        } else {
+            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+        }
+
+        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            /* env->exception_index is set in get_physical_address_data(). */
+            raise_exception(env->exception_index);
+        }
+
+        /* convert nonfaulting load ASIs to normal load ASIs */
+        asi &= ~0x02;
+    }
+
+    switch (asi) {
+    case 0x10: // As if user primary
+    case 0x11: // As if user secondary
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x80: // Primary
+    case 0x81: // Secondary
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0xe2: // UA2007 Primary block init
+    case 0xe3: // UA2007 Secondary block init
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch(size) {
+                case 1:
+                    ret = ldub_hypv(addr);
+                    break;
+                case 2:
+                    ret = lduw_hypv(addr);
+                    break;
+                case 4:
+                    ret = ldl_hypv(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_hypv(addr);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch(size) {
+                    case 1:
+                        ret = ldub_kernel_secondary(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel_secondary(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel_secondary(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel_secondary(addr);
+                        break;
+                    }
+                } else {
+                    switch(size) {
+                    case 1:
+                        ret = ldub_kernel(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel(addr);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch(size) {
+                case 1:
+                    ret = ldub_user_secondary(addr);
+                    break;
+                case 2:
+                    ret = lduw_user_secondary(addr);
+                    break;
+                case 4:
+                    ret = ldl_user_secondary(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user_secondary(addr);
+                    break;
+                }
+            } else {
+                switch(size) {
+                case 1:
+                    ret = ldub_user(addr);
+                    break;
+                case 2:
+                    ret = lduw_user(addr);
+                    break;
+                case 4:
+                    ret = ldl_user(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user(addr);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: // Bypass
+    case 0x15: // Bypass, non-cacheable
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+        {
+            switch(size) {
+            case 1:
+                ret = ldub_phys(addr);
+                break;
+            case 2:
+                ret = lduw_phys(addr);
+                break;
+            case 4:
+                ret = ldl_phys(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_phys(addr);
+                break;
+            }
+            break;
+        }
+    case 0x24: // Nucleus quad LDD 128 bit atomic
+    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+        //  Only ldda allowed
+        raise_exception(TT_ILL_INSN);
+        return 0;
+    case 0x04: // Nucleus
+    case 0x0c: // Nucleus Little Endian (LE)
+    {
+        switch(size) {
+        case 1:
+            ret = ldub_nucleus(addr);
+            break;
+        case 2:
+            ret = lduw_nucleus(addr);
+            break;
+        case 4:
+            ret = ldl_nucleus(addr);
+            break;
+        default:
+        case 8:
+            ret = ldq_nucleus(addr);
+            break;
+        }
+        break;
+    }
+    case 0x4a: // UPA config
+        // XXX
+        break;
+    case 0x45: // LSU
+        ret = env->lsu;
+        break;
+    case 0x50: // I-MMU regs
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                // I-TSB Tag Target register
+                ret = ultrasparc_tag_target(env->immu.tag_access);
+            } else {
+                ret = env->immuregs[reg];
+            }
+
+            break;
+        }
+    case 0x51: // I-MMU 8k TSB pointer
+        {
+            // env->immuregs[5] holds I-MMU TSB register value
+            // env->immuregs[6] holds I-MMU Tag Access register value
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x52: // I-MMU 64k TSB pointer
+        {
+            // env->immuregs[5] holds I-MMU TSB register value
+            // env->immuregs[6] holds I-MMU Tag Access register value
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x55: // I-MMU data access
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tte;
+            break;
+        }
+    case 0x56: // I-MMU tag read
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tag;
+            break;
+        }
+    case 0x58: // D-MMU regs
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                // D-TSB Tag Target register
+                ret = ultrasparc_tag_target(env->dmmu.tag_access);
+            } else {
+                ret = env->dmmuregs[reg];
+            }
+            break;
+        }
+    case 0x59: // D-MMU 8k TSB pointer
+        {
+            // env->dmmuregs[5] holds D-MMU TSB register value
+            // env->dmmuregs[6] holds D-MMU Tag Access register value
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x5a: // D-MMU 64k TSB pointer
+        {
+            // env->dmmuregs[5] holds D-MMU TSB register value
+            // env->dmmuregs[6] holds D-MMU Tag Access register value
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x5d: // D-MMU data access
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tte;
+            break;
+        }
+    case 0x5e: // D-MMU tag read
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tag;
+            break;
+        }
+    case 0x46: // D-cache data
+    case 0x47: // D-cache tag access
+    case 0x4b: // E-cache error enable
+    case 0x4c: // E-cache asynchronous fault status
+    case 0x4d: // E-cache asynchronous fault address
+    case 0x4e: // E-cache tag data
+    case 0x66: // I-cache instruction access
+    case 0x67: // I-cache tag access
+    case 0x6e: // I-cache predecode
+    case 0x6f: // I-cache LRU etc.
+    case 0x76: // E-cache tag
+    case 0x7e: // E-cache tag
+        break;
+    case 0x5b: // D-MMU data pointer
+    case 0x48: // Interrupt dispatch, RO
+    case 0x49: // Interrupt data receive
+    case 0x7f: // Incoming interrupt vector, RO
+        // XXX
+        break;
+    case 0x54: // I-MMU data in, WO
+    case 0x57: // I-MMU demap, WO
+    case 0x5c: // D-MMU data in, WO
+    case 0x5f: // D-MMU demap, WO
+    case 0x77: // Interrupt vector, WO
+    default:
+        do_unassigned_access(addr, 0, 0, 1, size);
+        ret = 0;
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV)))
+        raise_exception(TT_PRIV_ACT);
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch(asi) {
+    case 0x10: // As if user primary
+    case 0x11: // As if user secondary
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x80: // Primary
+    case 0x81: // Secondary
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0xe2: // UA2007 Primary block init
+    case 0xe3: // UA2007 Secondary block init
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch(size) {
+                case 1:
+                    stb_hypv(addr, val);
+                    break;
+                case 2:
+                    stw_hypv(addr, val);
+                    break;
+                case 4:
+                    stl_hypv(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_hypv(addr, val);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch(size) {
+                    case 1:
+                        stb_kernel_secondary(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel_secondary(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel_secondary(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel_secondary(addr, val);
+                        break;
+                    }
+                } else {
+                    switch(size) {
+                    case 1:
+                        stb_kernel(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel(addr, val);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch(size) {
+                case 1:
+                    stb_user_secondary(addr, val);
+                    break;
+                case 2:
+                    stw_user_secondary(addr, val);
+                    break;
+                case 4:
+                    stl_user_secondary(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user_secondary(addr, val);
+                    break;
+                }
+            } else {
+                switch(size) {
+                case 1:
+                    stb_user(addr, val);
+                    break;
+                case 2:
+                    stw_user(addr, val);
+                    break;
+                case 4:
+                    stl_user(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user(addr, val);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: // Bypass
+    case 0x15: // Bypass, non-cacheable
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+        {
+            switch(size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+                stl_phys(addr, val);
+                break;
+            case 8:
+            default:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        return;
+    case 0x24: // Nucleus quad LDD 128 bit atomic
+    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+        //  Only ldda allowed
+        raise_exception(TT_ILL_INSN);
+        return;
+    case 0x04: // Nucleus
+    case 0x0c: // Nucleus Little Endian (LE)
+    {
+        switch(size) {
+        case 1:
+            stb_nucleus(addr, val);
+            break;
+        case 2:
+            stw_nucleus(addr, val);
+            break;
+        case 4:
+            stl_nucleus(addr, val);
+            break;
+        default:
+        case 8:
+            stq_nucleus(addr, val);
+            break;
+        }
+        break;
+    }
+
+    case 0x4a: // UPA config
+        // XXX
+        return;
+    case 0x45: // LSU
+        {
+            uint64_t oldreg;
+
+            oldreg = env->lsu;
+            env->lsu = val & (DMMU_E | IMMU_E);
+            // Mappings generated during D/I MMU disabled mode are
+            // invalid in normal mode
+            if (oldreg != env->lsu) {
+                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+                            oldreg, env->lsu);
+#ifdef DEBUG_MMU
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                tlb_flush(env, 1);
+            }
+            return;
+        }
+    case 0x50: // I-MMU regs
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->immuregs[reg];
+            switch(reg) {
+            case 0: // RO
+                return;
+            case 1: // Not in I-MMU
+            case 2:
+                return;
+            case 3: // SFSR
+                if ((val & 1) == 0)
+                    val = 0; // Clear SFSR
+                env->immu.sfsr = val;
+                break;
+            case 4: // RO
+                return;
+            case 5: // TSB access
+                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->immu.tsb, val);
+                env->immu.tsb = val;
+                break;
+            case 6: // Tag access
+                env->immu.tag_access = val;
+                break;
+            case 7:
+            case 8:
+                return;
+            default:
+                break;
+            }
+
+            if (oldreg != env->immuregs[reg]) {
+                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x54: // I-MMU data in
+        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
+        return;
+    case 0x55: // I-MMU data access
+        {
+            // TODO: auto demap
+
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x57: // I-MMU demap
+        demap_tlb(env->itlb, addr, "immu", env);
+        return;
+    case 0x58: // D-MMU regs
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->dmmuregs[reg];
+            switch(reg) {
+            case 0: // RO
+            case 4:
+                return;
+            case 3: // SFSR
+                if ((val & 1) == 0) {
+                    val = 0; // Clear SFSR, Fault address
+                    env->dmmu.sfar = 0;
+                }
+                env->dmmu.sfsr = val;
+                break;
+            case 1: // Primary context
+                env->dmmu.mmu_primary_context = val;
+                /* can be optimized to only flush MMU_USER_IDX
+                   and MMU_KERNEL_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 2: // Secondary context
+                env->dmmu.mmu_secondary_context = val;
+                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+                   and MMU_KERNEL_SECONDARY_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 5: // TSB access
+                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->dmmu.tsb, val);
+                env->dmmu.tsb = val;
+                break;
+            case 6: // Tag access
+                env->dmmu.tag_access = val;
+                break;
+            case 7: // Virtual Watchpoint
+            case 8: // Physical Watchpoint
+            default:
+                env->dmmuregs[reg] = val;
+                break;
+            }
+
+            if (oldreg != env->dmmuregs[reg]) {
+                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5c: // D-MMU data in
+        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
+        return;
+    case 0x5d: // D-MMU data access
+        {
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5f: // D-MMU demap
+        demap_tlb(env->dtlb, addr, "dmmu", env);
+        return;
+    case 0x49: // Interrupt data receive
+        // XXX
+        return;
+    case 0x46: // D-cache data
+    case 0x47: // D-cache tag access
+    case 0x4b: // E-cache error enable
+    case 0x4c: // E-cache asynchronous fault status
+    case 0x4d: // E-cache asynchronous fault address
+    case 0x4e: // E-cache tag data
+    case 0x66: // I-cache instruction access
+    case 0x67: // I-cache tag access
+    case 0x6e: // I-cache predecode
+    case 0x6f: // I-cache LRU etc.
+    case 0x76: // E-cache tag
+    case 0x7e: // E-cache tag
+        return;
+    case 0x51: // I-MMU 8k TSB pointer, RO
+    case 0x52: // I-MMU 64k TSB pointer, RO
+    case 0x56: // I-MMU tag read, RO
+    case 0x59: // D-MMU 8k TSB pointer, RO
+    case 0x5a: // D-MMU 64k TSB pointer, RO
+    case 0x5b: // D-MMU data pointer, RO
+    case 0x5e: // D-MMU tag read, RO
+    case 0x48: // Interrupt dispatch, RO
+    case 0x7f: // Incoming interrupt vector, RO
+    case 0x82: // Primary no-fault, RO
+    case 0x83: // Secondary no-fault, RO
+    case 0x8a: // Primary no-fault LE, RO
+    case 0x8b: // Secondary no-fault LE, RO
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV)))
+        raise_exception(TT_PRIV_ACT);
+
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
+    case 0x24: // Nucleus quad LDD 128 bit atomic
+    case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+        helper_check_align(addr, 0xf);
+        if (rd == 0) {
+            env->gregs[1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c)
+                bswap64s(&env->gregs[1]);
+        } else if (rd < 8) {
+            env->gregs[rd] = ldq_nucleus(addr);
+            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[rd]);
+                bswap64s(&env->gregs[rd + 1]);
+            }
+        } else {
+            env->regwptr[rd] = ldq_nucleus(addr);
+            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->regwptr[rd]);
+                bswap64s(&env->regwptr[rd + 1]);
+            }
+        }
+        break;
+#endif
+    default:
+        helper_check_align(addr, 0x3);
+        if (rd == 0)
+            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        else if (rd < 8) {
+            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else {
+            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        }
+        break;
+    }
+}
+
+void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xf0: /* UA2007/JPS1 Block load primary */
+    case 0xf1: /* UA2007/JPS1 Block load secondary */
+    case 0xf8: /* UA2007/JPS1 Block load primary LE */
+    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block load primary, user privilege */
+    case 0x71: /* JPS1 Block load secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch(size) {
+    default:
+    case 4:
+        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
+        break;
+    case 8:
+        u.ll = helper_ld_asi(addr, asi, size, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    case 16:
+        u.ll = helper_ld_asi(addr, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    }
+}
+
+void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    target_ulong val = 0;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
+    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
+    case 0xf0: /* UA2007/JPS1 Block store primary */
+    case 0xf1: /* UA2007/JPS1 Block store secondary */
+    case 0xf8: /* UA2007/JPS1 Block store primary LE */
+    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x8f, 4);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block store primary, user privilege */
+    case 0x71: /* JPS1 Block store secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            raise_exception(TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x19, 4);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch(size) {
+    default:
+    case 4:
+        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
+        break;
+    case 8:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, size);
+        break;
+    case 16:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, 8);
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr + 8, u.ll, asi, 8);
+        break;
+    }
+}
+
+target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
+                            target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    val2 &= 0xffffffffUL;
+    ret = helper_ld_asi(addr, asi, 4, 0);
+    ret &= 0xffffffffUL;
+    if (val2 == ret)
+        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+    return ret;
+}
+
+target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
+                             target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    ret = helper_ld_asi(addr, asi, 8, 0);
+    if (val2 == ret)
+        helper_st_asi(addr, val1, asi, 8);
+    return ret;
+}
+#endif /* TARGET_SPARC64 */
+
+#ifndef TARGET_SPARC64
+void helper_rett(void)
+{
+    unsigned int cwp;
+
+    if (env->psret == 1)
+        raise_exception(TT_ILL_INSN);
+
+    env->psret = 1;
+    cwp = cwp_inc(env->cwp + 1) ;
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_UNF);
+    }
+    set_cwp(cwp);
+    env->psrs = env->psrps;
+}
+#endif
+
+static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
+{
+    int overflow = 0;
+    uint64_t x0;
+    uint32_t x1;
+
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
+    x0 = x0 / x1;
+    if (x0 > 0xffffffff) {
+        x0 = 0xffffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
+}
+
+target_ulong helper_udiv(target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(a, b, 0);
+}
+
+target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(a, b, 1);
+}
+
+static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
+{
+    int overflow = 0;
+    int64_t x0;
+    int32_t x1;
+
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
+    x0 = x0 / x1;
+    if ((int32_t) x0 != x0) {
+        x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
+}
+
+target_ulong helper_sdiv(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 0);
+}
+
+target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 1);
+}
+
+void helper_stdf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        stfq_user(addr, DT0);
+        break;
+    case MMU_KERNEL_IDX:
+        stfq_kernel(addr, DT0);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        stfq_hypv(addr, DT0);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    stfq_raw(address_mask(env, addr), DT0);
+#endif
+}
+
+void helper_lddf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        DT0 = ldfq_user(addr);
+        break;
+    case MMU_KERNEL_IDX:
+        DT0 = ldfq_kernel(addr);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        DT0 = ldfq_hypv(addr);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    DT0 = ldfq_raw(address_mask(env, addr));
+#endif
+}
+
+void helper_ldqf(target_ulong addr, int mem_idx)
+{
+    // XXX add 128 bit load
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.ll.upper = ldq_user(addr);
+        u.ll.lower = ldq_user(addr + 8);
+        QT0 = u.q;
+        break;
+    case MMU_KERNEL_IDX:
+        u.ll.upper = ldq_kernel(addr);
+        u.ll.lower = ldq_kernel(addr + 8);
+        QT0 = u.q;
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.ll.upper = ldq_hypv(addr);
+        u.ll.lower = ldq_hypv(addr + 8);
+        QT0 = u.q;
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.ll.upper = ldq_raw(address_mask(env, addr));
+    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
+    QT0 = u.q;
+#endif
+}
+
+void helper_stqf(target_ulong addr, int mem_idx)
+{
+    // XXX add 128 bit store
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.q = QT0;
+        stq_user(addr, u.ll.upper);
+        stq_user(addr + 8, u.ll.lower);
+        break;
+    case MMU_KERNEL_IDX:
+        u.q = QT0;
+        stq_kernel(addr, u.ll.upper);
+        stq_kernel(addr + 8, u.ll.lower);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.q = QT0;
+        stq_hypv(addr, u.ll.upper);
+        stq_hypv(addr + 8, u.ll.lower);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.q = QT0;
+    stq_raw(address_mask(env, addr), u.ll.upper);
+    stq_raw(address_mask(env, addr + 8), u.ll.lower);
+#endif
+}
+
+static inline void set_fsr(void)
+{
+    int rnd_mode;
+
+    switch (env->fsr & FSR_RD_MASK) {
+    case FSR_RD_NEAREST:
+        rnd_mode = float_round_nearest_even;
+        break;
+    default:
+    case FSR_RD_ZERO:
+        rnd_mode = float_round_to_zero;
+        break;
+    case FSR_RD_POS:
+        rnd_mode = float_round_up;
+        break;
+    case FSR_RD_NEG:
+        rnd_mode = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_mode, &env->fp_status);
+}
+
+void helper_ldfsr(uint32_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
+    set_fsr();
+}
+
+#ifdef TARGET_SPARC64
+void helper_ldxfsr(uint64_t new_fsr)
+{
+    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
+    set_fsr();
+}
+#endif
+
+void helper_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
+
+#ifndef TARGET_SPARC64
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(void)
+{
+    uint32_t cwp;
+
+    cwp = cwp_dec(env->cwp - 1);
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_OVF);
+    }
+    set_cwp(cwp);
+}
+
+void helper_restore(void)
+{
+    uint32_t cwp;
+
+    cwp = cwp_inc(env->cwp + 1);
+    if (env->wim & (1 << cwp)) {
+        raise_exception(TT_WIN_UNF);
+    }
+    set_cwp(cwp);
+}
+
+void helper_wrpsr(target_ulong new_psr)
+{
+    if ((new_psr & PSR_CWP) >= env->nwindows) {
+        raise_exception(TT_ILL_INSN);
+    } else {
+        cpu_put_psr(env, new_psr);
+    }
+}
+
+target_ulong helper_rdpsr(void)
+{
+    return get_psr();
+}
+
+#else
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+   handling ? */
+void helper_save(void)
+{
+    uint32_t cwp;
+
+    cwp = cwp_dec(env->cwp - 1);
+    if (env->cansave == 0) {
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
+                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                    ((env->wstate & 0x7) << 2)));
+    } else {
+        if (env->cleanwin - env->canrestore == 0) {
+            // XXX Clean windows without trap
+            raise_exception(TT_CLRWIN);
+        } else {
+            env->cansave--;
+            env->canrestore++;
+            set_cwp(cwp);
+        }
+    }
+}
+
+void helper_restore(void)
+{
+    uint32_t cwp;
+
+    cwp = cwp_inc(env->cwp + 1);
+    if (env->canrestore == 0) {
+        raise_exception(TT_FILL | (env->otherwin != 0 ?
+                                   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                   ((env->wstate & 0x7) << 2)));
+    } else {
+        env->cansave++;
+        env->canrestore--;
+        set_cwp(cwp);
+    }
+}
+
+void helper_flushw(void)
+{
+    if (env->cansave != env->nwindows - 2) {
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
+                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                    ((env->wstate & 0x7) << 2)));
+    }
+}
+
+void helper_saved(void)
+{
+    env->cansave++;
+    if (env->otherwin == 0)
+        env->canrestore--;
+    else
+        env->otherwin--;
+}
+
+void helper_restored(void)
+{
+    env->canrestore++;
+    if (env->cleanwin < env->nwindows - 1)
+        env->cleanwin++;
+    if (env->otherwin == 0)
+        env->cansave--;
+    else
+        env->otherwin--;
+}
+
+static target_ulong get_ccr(void)
+{
+    target_ulong psr;
+
+    psr = get_psr();
+
+    return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+target_ulong cpu_get_ccr(CPUState *env1)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = get_ccr();
+    env = saved_env;
+    return ret;
+}
+
+static void put_ccr(target_ulong val)
+{
+    target_ulong tmp = val;
+
+    env->xcc = (tmp >> 4) << 20;
+    env->psr = (tmp & 0xf) << 20;
+    CC_OP = CC_OP_FLAGS;
+}
+
+void cpu_put_ccr(CPUState *env1, target_ulong val)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    put_ccr(val);
+    env = saved_env;
+}
+
+static target_ulong get_cwp64(void)
+{
+    return env->nwindows - 1 - env->cwp;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env1)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = get_cwp64();
+    env = saved_env;
+    return ret;
+}
+
+static void put_cwp64(int cwp)
+{
+    if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+        cwp %= env->nwindows;
+    }
+    set_cwp(env->nwindows - 1 - cwp);
+}
+
+void cpu_put_cwp64(CPUState *env1, int cwp)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    put_cwp64(cwp);
+    env = saved_env;
+}
+
+target_ulong helper_rdccr(void)
+{
+    return get_ccr();
+}
+
+void helper_wrccr(target_ulong new_ccr)
+{
+    put_ccr(new_ccr);
+}
+
+// CWP handling is reversed in V9, but we still use the V8 register
+// order.
+target_ulong helper_rdcwp(void)
+{
+    return get_cwp64();
+}
+
+void helper_wrcwp(target_ulong new_cwp)
+{
+    put_cwp64(new_cwp);
+}
+
+// This function uses non-native bit order
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+// This function uses the order in the manuals, i.e. bit 0 is 2^0
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
+{
+    return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
+        (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
+        (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
+        (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
+        (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
+        (((pixel_addr >> 55) & 1) << 4) |
+        (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
+        GET_FIELD_SP(pixel_addr, 11, 12);
+}
+
+target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
+{
+    uint64_t tmp;
+
+    tmp = addr + offset;
+    env->gsr &= ~7ULL;
+    env->gsr |= tmp & 7ULL;
+    return tmp & ~7ULL;
+}
+
+target_ulong helper_popc(target_ulong val)
+{
+    return ctpop64(val);
+}
+
+static inline uint64_t *get_gregset(uint32_t pstate)
+{
+    switch (pstate) {
+    default:
+        DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
+                pstate,
+                (pstate & PS_IG) ? " IG" : "",
+                (pstate & PS_MG) ? " MG" : "",
+                (pstate & PS_AG) ? " AG" : "");
+        /* pass through to normal set of global registers */
+    case 0:
+        return env->bgregs;
+    case PS_AG:
+        return env->agregs;
+    case PS_MG:
+        return env->mgregs;
+    case PS_IG:
+        return env->igregs;
+    }
+}
+
+static inline void change_pstate(uint32_t new_pstate)
+{
+    uint32_t pstate_regs, new_pstate_regs;
+    uint64_t *src, *dst;
+
+    if (env->def->features & CPU_FEATURE_GL) {
+        // PS_AG is not implemented in this case
+        new_pstate &= ~PS_AG;
+    }
+
+    pstate_regs = env->pstate & 0xc01;
+    new_pstate_regs = new_pstate & 0xc01;
+
+    if (new_pstate_regs != pstate_regs) {
+        DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
+                       pstate_regs, new_pstate_regs);
+        // Switch global register bank
+        src = get_gregset(new_pstate_regs);
+        dst = get_gregset(pstate_regs);
+        memcpy32(dst, env->gregs);
+        memcpy32(env->gregs, src);
+    }
+    else {
+        DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
+                       new_pstate_regs);
+    }
+    env->pstate = new_pstate;
+}
+
+void helper_wrpstate(target_ulong new_state)
+{
+    change_pstate(new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    change_pstate(new_pstate);
+    env = saved_env;
+}
+
+void helper_wrpil(target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+    DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
+                   env->psrpil, (uint32_t)new_pil);
+
+    env->psrpil = new_pil;
+
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_done(void)
+{
+    trap_state* tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tnpc;
+    env->npc = tsptr->tnpc + 4;
+    put_ccr(tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    change_pstate((tsptr->tstate >> 8) & 0xf3f);
+    put_cwp64(tsptr->tstate & 0xff);
+    env->tl--;
+
+    DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+void helper_retry(void)
+{
+    trap_state* tsptr = cpu_tsptr(env);
+
+    env->pc = tsptr->tpc;
+    env->npc = tsptr->tnpc;
+    put_ccr(tsptr->tstate >> 32);
+    env->asi = (tsptr->tstate >> 24) & 0xff;
+    change_pstate((tsptr->tstate >> 8) & 0xf3f);
+    put_cwp64(tsptr->tstate & 0xff);
+    env->tl--;
+
+    DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+static void do_modify_softint(const char* operation, uint32_t value)
+{
+    if (env->softint != value) {
+        env->softint = value;
+        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
+#if !defined(CONFIG_USER_ONLY)
+        if (cpu_interrupts_enabled(env)) {
+            cpu_check_irqs(env);
+        }
+#endif
+    }
+}
+
+void helper_set_softint(uint64_t value)
+{
+    do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
+}
+
+void helper_clear_softint(uint64_t value)
+{
+    do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
+}
+
+void helper_write_softint(uint64_t value)
+{
+    do_modify_softint("helper_write_softint", (uint32_t)value);
+}
+#endif
+
+#ifdef TARGET_SPARC64
+trap_state* cpu_tsptr(CPUState* env)
+{
+    return &env->ts[env->tl & MAXTL_MASK];
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+                                void *retaddr);
+
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* XXX: make it generic ? */
+static void cpu_restore_state2(void *retaddr)
+{
+    TranslationBlock *tb;
+    unsigned long pc;
+
+    if (retaddr) {
+        /* now we have a real cpu fault */
+        pc = (unsigned long)retaddr;
+        tb = tb_find_pc(pc);
+        if (tb) {
+            /* the PC is inside the translated code. It means that we have
+               a virtual CPU fault */
+            cpu_restore_state(tb, env, pc);
+        }
+    }
+}
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+                                void *retaddr)
+{
+#ifdef DEBUG_UNALIGNED
+    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+    cpu_restore_state2(retaddr);
+    raise_exception(TT_UNALIGNED);
+}
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    int ret;
+    CPUState *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    if (ret) {
+        cpu_restore_state2(retaddr);
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+#ifndef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+    int fault_type;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+#ifdef DEBUG_UNASSIGNED
+    if (is_asi)
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " asi 0x%02x from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, is_asi, env->pc);
+    else
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, env->pc);
+#endif
+    /* Don't overwrite translation and access faults */
+    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+    if ((fault_type > 4) || (fault_type == 0)) {
+        env->mmuregs[3] = 0; /* Fault status register */
+        if (is_asi)
+            env->mmuregs[3] |= 1 << 16;
+        if (env->psrs)
+            env->mmuregs[3] |= 1 << 5;
+        if (is_exec)
+            env->mmuregs[3] |= 1 << 6;
+        if (is_write)
+            env->mmuregs[3] |= 1 << 7;
+        env->mmuregs[3] |= (5 << 2) | 2;
+        /* SuperSPARC will never place instruction fault addresses in the FAR */
+        if (!is_exec) {
+            env->mmuregs[4] = addr; /* Fault address register */
+        }
+    }
+    /* overflow (same type fault was not read before another fault) */
+    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+        env->mmuregs[3] |= 1;
+    }
+
+    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+        if (is_exec)
+            raise_exception(TT_CODE_ACCESS);
+        else
+            raise_exception(TT_DATA_ACCESS);
+    }
+
+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
+
+    env = saved_env;
+}
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                          int is_asi, int size)
+#else
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+#endif
+{
+    CPUState *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+
+    if (is_exec)
+        raise_exception(TT_CODE_ACCESS);
+    else
+        raise_exception(TT_DATA_ACCESS);
+
+    env = saved_env;
+}
+#endif
+
+
+#ifdef TARGET_SPARC64
+void helper_tick_set_count(void *opaque, uint64_t count)
+{
+#if !defined(CONFIG_USER_ONLY)
+    cpu_tick_set_count(opaque, count);
+#endif
+}
+
+uint64_t helper_tick_get_count(void *opaque)
+{
+#if !defined(CONFIG_USER_ONLY)
+    return cpu_tick_get_count(opaque);
+#else
+    return 0;
+#endif
+}
+
+void helper_tick_set_limit(void *opaque, uint64_t limit)
+{
+#if !defined(CONFIG_USER_ONLY)
+    cpu_tick_set_limit(opaque, limit);
+#endif
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    env = env1;
+    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+}
+#endif
diff --git a/qemu-0.15.x/target-sparc/translate.c b/qemu-0.15.x/target-sparc/translate.c
new file mode 100644
index 0000000..15967c5
--- /dev/null
+++ b/qemu-0.15.x/target-sparc/translate.c
@@ -0,0 +1,5140 @@
+/*
+   SPARC translation
+
+   Copyright (C) 2003 Thomas M. Ogrisegg <tom at fnord.at>
+   Copyright (C) 2003-2005 Fabrice Bellard
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "helper.h"
+#include "tcg-op.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define DEBUG_DISAS
+
+#define DYNAMIC_PC  1 /* dynamic pc value */
+#define JUMP_PC     2 /* dynamic pc value which takes only two values
+                         according to jump_pc[T2] */
+
+/* global register indexes */
+static TCGv_ptr cpu_env, cpu_regwptr;
+static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst;
+static TCGv_i32 cpu_cc_op;
+static TCGv_i32 cpu_psr;
+static TCGv cpu_fsr, cpu_pc, cpu_npc, cpu_gregs[8];
+static TCGv cpu_y;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_tbr;
+#endif
+static TCGv cpu_cond, cpu_dst, cpu_addr, cpu_val;
+#ifdef TARGET_SPARC64
+static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs;
+static TCGv cpu_gsr;
+static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
+static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
+static TCGv_i32 cpu_softint;
+#else
+static TCGv cpu_wim;
+#endif
+/* local register indexes (only used inside old micro ops) */
+static TCGv cpu_tmp0;
+static TCGv_i32 cpu_tmp32;
+static TCGv_i64 cpu_tmp64;
+/* Floating point registers */
+static TCGv_i32 cpu_fpr[TARGET_FPREGS];
+
+static target_ulong gen_opc_npc[OPC_BUF_SIZE];
+static target_ulong gen_opc_jump_pc[2];
+
+#include "gen-icount.h"
+
+typedef struct DisasContext {
+    target_ulong pc;    /* current Program Counter: integer or DYNAMIC_PC */
+    target_ulong npc;   /* next PC: integer or DYNAMIC_PC or JUMP_PC */
+    target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
+    int is_br;
+    int mem_idx;
+    int fpu_enabled;
+    int address_mask_32bit;
+    int singlestep;
+    uint32_t cc_op;  /* current CC operation */
+    struct TranslationBlock *tb;
+    sparc_def_t *def;
+} DisasContext;
+
+// This function uses non-native bit order
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
+
+// This function uses the order in the manuals, i.e. bit 0 is 2^0
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 31 - (TO), 31 - (FROM))
+
+#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
+#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1))
+
+#ifdef TARGET_SPARC64
+#define DFPREG(r) (((r & 1) << 5) | (r & 0x1e))
+#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c))
+#else
+#define DFPREG(r) (r & 0x1e)
+#define QFPREG(r) (r & 0x1c)
+#endif
+
+#define UA2005_HTRAP_MASK 0xff
+#define V8_TRAP_MASK 0x7f
+
+static int sign_extend(int x, int len)
+{
+    len = 32 - len;
+    return (x << len) >> len;
+}
+
+#define IS_IMM (insn & (1<<13))
+
+/* floating point registers moves */
+static void gen_op_load_fpr_DT0(unsigned int src)
+{
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
+                   offsetof(CPU_DoubleU, l.upper));
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
+                   offsetof(CPU_DoubleU, l.lower));
+}
+
+static void gen_op_load_fpr_DT1(unsigned int src)
+{
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) +
+                   offsetof(CPU_DoubleU, l.upper));
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) +
+                   offsetof(CPU_DoubleU, l.lower));
+}
+
+static void gen_op_store_DT0_fpr(unsigned int dst)
+{
+    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) +
+                   offsetof(CPU_DoubleU, l.upper));
+    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
+                   offsetof(CPU_DoubleU, l.lower));
+}
+
+static void gen_op_load_fpr_QT0(unsigned int src)
+{
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.upmost));
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.upper));
+    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.lower));
+    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.lowest));
+}
+
+static void gen_op_load_fpr_QT1(unsigned int src)
+{
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, l.upmost));
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, l.upper));
+    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, l.lower));
+    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, l.lowest));
+}
+
+static void gen_op_store_QT0_fpr(unsigned int dst)
+{
+    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.upmost));
+    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.upper));
+    tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.lower));
+    tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, l.lowest));
+}
+
+/* moves */
+#ifdef CONFIG_USER_ONLY
+#define supervisor(dc) 0
+#ifdef TARGET_SPARC64
+#define hypervisor(dc) 0
+#endif
+#else
+#define supervisor(dc) (dc->mem_idx >= MMU_KERNEL_IDX)
+#ifdef TARGET_SPARC64
+#define hypervisor(dc) (dc->mem_idx == MMU_HYPV_IDX)
+#else
+#endif
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(dc) ((dc)->address_mask_32bit)
+#else
+#define AM_CHECK(dc) (1)
+#endif
+#endif
+
+static inline void gen_address_mask(DisasContext *dc, TCGv addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(dc))
+        tcg_gen_andi_tl(addr, addr, 0xffffffffULL);
+#endif
+}
+
+static inline void gen_movl_reg_TN(int reg, TCGv tn)
+{
+    if (reg == 0)
+        tcg_gen_movi_tl(tn, 0);
+    else if (reg < 8)
+        tcg_gen_mov_tl(tn, cpu_gregs[reg]);
+    else {
+        tcg_gen_ld_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong));
+    }
+}
+
+static inline void gen_movl_TN_reg(int reg, TCGv tn)
+{
+    if (reg == 0)
+        return;
+    else if (reg < 8)
+        tcg_gen_mov_tl(cpu_gregs[reg], tn);
+    else {
+        tcg_gen_st_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong));
+    }
+}
+
+static inline void gen_goto_tb(DisasContext *s, int tb_num,
+                               target_ulong pc, target_ulong npc)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) &&
+        (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) &&
+        !s->singlestep)  {
+        /* jump to same page: we can use a direct jump */
+        tcg_gen_goto_tb(tb_num);
+        tcg_gen_movi_tl(cpu_pc, pc);
+        tcg_gen_movi_tl(cpu_npc, npc);
+        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
+    } else {
+        /* jump to another page: currently not optimized */
+        tcg_gen_movi_tl(cpu_pc, pc);
+        tcg_gen_movi_tl(cpu_npc, npc);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+// XXX suboptimal
+static inline void gen_mov_reg_N(TCGv reg, TCGv_i32 src)
+{
+    tcg_gen_extu_i32_tl(reg, src);
+    tcg_gen_shri_tl(reg, reg, PSR_NEG_SHIFT);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+static inline void gen_mov_reg_Z(TCGv reg, TCGv_i32 src)
+{
+    tcg_gen_extu_i32_tl(reg, src);
+    tcg_gen_shri_tl(reg, reg, PSR_ZERO_SHIFT);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+static inline void gen_mov_reg_V(TCGv reg, TCGv_i32 src)
+{
+    tcg_gen_extu_i32_tl(reg, src);
+    tcg_gen_shri_tl(reg, reg, PSR_OVF_SHIFT);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src)
+{
+    tcg_gen_extu_i32_tl(reg, src);
+    tcg_gen_shri_tl(reg, reg, PSR_CARRY_SHIFT);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2)
+{
+    TCGv r_temp;
+    TCGv_i32 r_const;
+    int l1;
+
+    l1 = gen_new_label();
+
+    r_temp = tcg_temp_new();
+    tcg_gen_xor_tl(r_temp, src1, src2);
+    tcg_gen_not_tl(r_temp, r_temp);
+    tcg_gen_xor_tl(cpu_tmp0, src1, dst);
+    tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
+    tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
+    r_const = tcg_const_i32(TT_TOVF);
+    gen_helper_raise_exception(r_const);
+    tcg_temp_free_i32(r_const);
+    gen_set_label(l1);
+    tcg_temp_free(r_temp);
+}
+
+static inline void gen_tag_tv(TCGv src1, TCGv src2)
+{
+    int l1;
+    TCGv_i32 r_const;
+
+    l1 = gen_new_label();
+    tcg_gen_or_tl(cpu_tmp0, src1, src2);
+    tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
+    r_const = tcg_const_i32(TT_TOVF);
+    gen_helper_raise_exception(r_const);
+    tcg_temp_free_i32(r_const);
+    gen_set_label(l1);
+}
+
+static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_movi_tl(cpu_cc_src2, src2);
+    tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_src, src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static TCGv_i32 gen_add32_carry32(void)
+{
+    TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
+
+    /* Carry is computed from a previous add: (dst < src)  */
+#if TARGET_LONG_BITS == 64
+    cc_src1_32 = tcg_temp_new_i32();
+    cc_src2_32 = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_dst);
+    tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src);
+#else
+    cc_src1_32 = cpu_cc_dst;
+    cc_src2_32 = cpu_cc_src;
+#endif
+
+    carry_32 = tcg_temp_new_i32();
+    tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
+
+#if TARGET_LONG_BITS == 64
+    tcg_temp_free_i32(cc_src1_32);
+    tcg_temp_free_i32(cc_src2_32);
+#endif
+
+    return carry_32;
+}
+
+static TCGv_i32 gen_sub32_carry32(void)
+{
+    TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
+
+    /* Carry is computed from a previous borrow: (src1 < src2)  */
+#if TARGET_LONG_BITS == 64
+    cc_src1_32 = tcg_temp_new_i32();
+    cc_src2_32 = tcg_temp_new_i32();
+    tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_src);
+    tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src2);
+#else
+    cc_src1_32 = cpu_cc_src;
+    cc_src2_32 = cpu_cc_src2;
+#endif
+
+    carry_32 = tcg_temp_new_i32();
+    tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
+
+#if TARGET_LONG_BITS == 64
+    tcg_temp_free_i32(cc_src1_32);
+    tcg_temp_free_i32(cc_src2_32);
+#endif
+
+    return carry_32;
+}
+
+static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
+                            TCGv src2, int update_cc)
+{
+    TCGv_i32 carry_32;
+    TCGv carry;
+
+    switch (dc->cc_op) {
+    case CC_OP_DIV:
+    case CC_OP_LOGIC:
+        /* Carry is known to be zero.  Fall back to plain ADD.  */
+        if (update_cc) {
+            gen_op_add_cc(dst, src1, src2);
+        } else {
+            tcg_gen_add_tl(dst, src1, src2);
+        }
+        return;
+
+    case CC_OP_ADD:
+    case CC_OP_TADD:
+    case CC_OP_TADDTV:
+#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
+        {
+            /* For 32-bit hosts, we can re-use the host's hardware carry
+               generation by using an ADD2 opcode.  We discard the low
+               part of the output.  Ideally we'd combine this operation
+               with the add that generated the carry in the first place.  */
+            TCGv dst_low = tcg_temp_new();
+            tcg_gen_op6_i32(INDEX_op_add2_i32, dst_low, dst,
+                            cpu_cc_src, src1, cpu_cc_src2, src2);
+            tcg_temp_free(dst_low);
+            goto add_done;
+        }
+#endif
+        carry_32 = gen_add32_carry32();
+        break;
+
+    case CC_OP_SUB:
+    case CC_OP_TSUB:
+    case CC_OP_TSUBTV:
+        carry_32 = gen_sub32_carry32();
+        break;
+
+    default:
+        /* We need external help to produce the carry.  */
+        carry_32 = tcg_temp_new_i32();
+        gen_helper_compute_C_icc(carry_32);
+        break;
+    }
+
+#if TARGET_LONG_BITS == 64
+    carry = tcg_temp_new();
+    tcg_gen_extu_i32_i64(carry, carry_32);
+#else
+    carry = carry_32;
+#endif
+
+    tcg_gen_add_tl(dst, src1, src2);
+    tcg_gen_add_tl(dst, dst, carry);
+
+    tcg_temp_free_i32(carry_32);
+#if TARGET_LONG_BITS == 64
+    tcg_temp_free(carry);
+#endif
+
+#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
+ add_done:
+#endif
+    if (update_cc) {
+        tcg_gen_mov_tl(cpu_cc_src, src1);
+        tcg_gen_mov_tl(cpu_cc_src2, src2);
+        tcg_gen_mov_tl(cpu_cc_dst, dst);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX);
+        dc->cc_op = CC_OP_ADDX;
+    }
+}
+
+static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_tadd_ccTV(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    gen_tag_tv(cpu_cc_src, cpu_cc_src2);
+    tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    gen_add_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
+{
+    TCGv r_temp;
+    TCGv_i32 r_const;
+    int l1;
+
+    l1 = gen_new_label();
+
+    r_temp = tcg_temp_new();
+    tcg_gen_xor_tl(r_temp, src1, src2);
+    tcg_gen_xor_tl(cpu_tmp0, src1, dst);
+    tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0);
+    tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
+    tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
+    r_const = tcg_const_i32(TT_TOVF);
+    gen_helper_raise_exception(r_const);
+    tcg_temp_free_i32(r_const);
+    gen_set_label(l1);
+    tcg_temp_free(r_temp);
+}
+
+static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_movi_tl(cpu_cc_src2, src2);
+    if (src2 == 0) {
+        tcg_gen_mov_tl(cpu_cc_dst, src1);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+        dc->cc_op = CC_OP_LOGIC;
+    } else {
+        tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_src, src2);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
+        dc->cc_op = CC_OP_SUB;
+    }
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
+                            TCGv src2, int update_cc)
+{
+    TCGv_i32 carry_32;
+    TCGv carry;
+
+    switch (dc->cc_op) {
+    case CC_OP_DIV:
+    case CC_OP_LOGIC:
+        /* Carry is known to be zero.  Fall back to plain SUB.  */
+        if (update_cc) {
+            gen_op_sub_cc(dst, src1, src2);
+        } else {
+            tcg_gen_sub_tl(dst, src1, src2);
+        }
+        return;
+
+    case CC_OP_ADD:
+    case CC_OP_TADD:
+    case CC_OP_TADDTV:
+        carry_32 = gen_add32_carry32();
+        break;
+
+    case CC_OP_SUB:
+    case CC_OP_TSUB:
+    case CC_OP_TSUBTV:
+#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
+        {
+            /* For 32-bit hosts, we can re-use the host's hardware carry
+               generation by using a SUB2 opcode.  We discard the low
+               part of the output.  Ideally we'd combine this operation
+               with the add that generated the carry in the first place.  */
+            TCGv dst_low = tcg_temp_new();
+            tcg_gen_op6_i32(INDEX_op_sub2_i32, dst_low, dst,
+                            cpu_cc_src, src1, cpu_cc_src2, src2);
+            tcg_temp_free(dst_low);
+            goto sub_done;
+        }
+#endif
+        carry_32 = gen_sub32_carry32();
+        break;
+
+    default:
+        /* We need external help to produce the carry.  */
+        carry_32 = tcg_temp_new_i32();
+        gen_helper_compute_C_icc(carry_32);
+        break;
+    }
+
+#if TARGET_LONG_BITS == 64
+    carry = tcg_temp_new();
+    tcg_gen_extu_i32_i64(carry, carry_32);
+#else
+    carry = carry_32;
+#endif
+
+    tcg_gen_sub_tl(dst, src1, src2);
+    tcg_gen_sub_tl(dst, dst, carry);
+
+    tcg_temp_free_i32(carry_32);
+#if TARGET_LONG_BITS == 64
+    tcg_temp_free(carry);
+#endif
+
+#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32
+ sub_done:
+#endif
+    if (update_cc) {
+        tcg_gen_mov_tl(cpu_cc_src, src1);
+        tcg_gen_mov_tl(cpu_cc_src2, src2);
+        tcg_gen_mov_tl(cpu_cc_dst, dst);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX);
+        dc->cc_op = CC_OP_SUBX;
+    }
+}
+
+static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_tsub_ccTV(TCGv dst, TCGv src1, TCGv src2)
+{
+    tcg_gen_mov_tl(cpu_cc_src, src1);
+    tcg_gen_mov_tl(cpu_cc_src2, src2);
+    gen_tag_tv(cpu_cc_src, cpu_cc_src2);
+    tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    gen_sub_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
+{
+    TCGv r_temp;
+    int l1;
+
+    l1 = gen_new_label();
+    r_temp = tcg_temp_new();
+
+    /* old op:
+    if (!(env->y & 1))
+        T1 = 0;
+    */
+    tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff);
+    tcg_gen_andi_tl(r_temp, cpu_y, 0x1);
+    tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff);
+    tcg_gen_brcondi_tl(TCG_COND_NE, r_temp, 0, l1);
+    tcg_gen_movi_tl(cpu_cc_src2, 0);
+    gen_set_label(l1);
+
+    // b2 = T0 & 1;
+    // env->y = (b2 << 31) | (env->y >> 1);
+    tcg_gen_andi_tl(r_temp, cpu_cc_src, 0x1);
+    tcg_gen_shli_tl(r_temp, r_temp, 31);
+    tcg_gen_shri_tl(cpu_tmp0, cpu_y, 1);
+    tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x7fffffff);
+    tcg_gen_or_tl(cpu_tmp0, cpu_tmp0, r_temp);
+    tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff);
+
+    // b1 = N ^ V;
+    gen_mov_reg_N(cpu_tmp0, cpu_psr);
+    gen_mov_reg_V(r_temp, cpu_psr);
+    tcg_gen_xor_tl(cpu_tmp0, cpu_tmp0, r_temp);
+    tcg_temp_free(r_temp);
+
+    // T0 = (b1 << 31) | (T0 >> 1);
+    // src1 = T0;
+    tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, 31);
+    tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1);
+    tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+
+    tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+
+    tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
+{
+    TCGv_i32 r_src1, r_src2;
+    TCGv_i64 r_temp, r_temp2;
+
+    r_src1 = tcg_temp_new_i32();
+    r_src2 = tcg_temp_new_i32();
+
+    tcg_gen_trunc_tl_i32(r_src1, src1);
+    tcg_gen_trunc_tl_i32(r_src2, src2);
+
+    r_temp = tcg_temp_new_i64();
+    r_temp2 = tcg_temp_new_i64();
+
+    if (sign_ext) {
+        tcg_gen_ext_i32_i64(r_temp, r_src2);
+        tcg_gen_ext_i32_i64(r_temp2, r_src1);
+    } else {
+        tcg_gen_extu_i32_i64(r_temp, r_src2);
+        tcg_gen_extu_i32_i64(r_temp2, r_src1);
+    }
+
+    tcg_gen_mul_i64(r_temp2, r_temp, r_temp2);
+
+    tcg_gen_shri_i64(r_temp, r_temp2, 32);
+    tcg_gen_trunc_i64_tl(cpu_tmp0, r_temp);
+    tcg_temp_free_i64(r_temp);
+    tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff);
+
+    tcg_gen_trunc_i64_tl(dst, r_temp2);
+
+    tcg_temp_free_i64(r_temp2);
+
+    tcg_temp_free_i32(r_src1);
+    tcg_temp_free_i32(r_src2);
+}
+
+static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2)
+{
+    /* zero-extend truncated operands before multiplication */
+    gen_op_multiply(dst, src1, src2, 0);
+}
+
+static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
+{
+    /* sign-extend truncated operands before multiplication */
+    gen_op_multiply(dst, src1, src2, 1);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_trap_ifdivzero_tl(TCGv divisor)
+{
+    TCGv_i32 r_const;
+    int l1;
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1);
+    r_const = tcg_const_i32(TT_DIV_ZERO);
+    gen_helper_raise_exception(r_const);
+    tcg_temp_free_i32(r_const);
+    gen_set_label(l1);
+}
+
+static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
+{
+    int l1, l2;
+    TCGv r_temp1, r_temp2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+    r_temp1 = tcg_temp_local_new();
+    r_temp2 = tcg_temp_local_new();
+    tcg_gen_mov_tl(r_temp1, src1);
+    tcg_gen_mov_tl(r_temp2, src2);
+    gen_trap_ifdivzero_tl(r_temp2);
+    tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1);
+    tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1);
+    tcg_gen_movi_i64(dst, INT64_MIN);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_div_i64(dst, r_temp1, r_temp2);
+    gen_set_label(l2);
+    tcg_temp_free(r_temp1);
+    tcg_temp_free(r_temp2);
+}
+#endif
+
+// 1
+static inline void gen_op_eval_ba(TCGv dst)
+{
+    tcg_gen_movi_tl(dst, 1);
+}
+
+// Z
+static inline void gen_op_eval_be(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_Z(dst, src);
+}
+
+// Z | (N ^ V)
+static inline void gen_op_eval_ble(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_N(cpu_tmp0, src);
+    gen_mov_reg_V(dst, src);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+    gen_mov_reg_Z(cpu_tmp0, src);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+}
+
+// N ^ V
+static inline void gen_op_eval_bl(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_V(cpu_tmp0, src);
+    gen_mov_reg_N(dst, src);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+}
+
+// C | Z
+static inline void gen_op_eval_bleu(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_Z(cpu_tmp0, src);
+    gen_mov_reg_C(dst, src);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+}
+
+// C
+static inline void gen_op_eval_bcs(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_C(dst, src);
+}
+
+// V
+static inline void gen_op_eval_bvs(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_V(dst, src);
+}
+
+// 0
+static inline void gen_op_eval_bn(TCGv dst)
+{
+    tcg_gen_movi_tl(dst, 0);
+}
+
+// N
+static inline void gen_op_eval_bneg(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_N(dst, src);
+}
+
+// !Z
+static inline void gen_op_eval_bne(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_Z(dst, src);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !(Z | (N ^ V))
+static inline void gen_op_eval_bg(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_N(cpu_tmp0, src);
+    gen_mov_reg_V(dst, src);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+    gen_mov_reg_Z(cpu_tmp0, src);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !(N ^ V)
+static inline void gen_op_eval_bge(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_V(cpu_tmp0, src);
+    gen_mov_reg_N(dst, src);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !(C | Z)
+static inline void gen_op_eval_bgu(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_Z(cpu_tmp0, src);
+    gen_mov_reg_C(dst, src);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !C
+static inline void gen_op_eval_bcc(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_C(dst, src);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !N
+static inline void gen_op_eval_bpos(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_N(dst, src);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !V
+static inline void gen_op_eval_bvc(TCGv dst, TCGv_i32 src)
+{
+    gen_mov_reg_V(dst, src);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+/*
+  FPSR bit field FCC1 | FCC0:
+   0 =
+   1 <
+   2 >
+   3 unordered
+*/
+static inline void gen_mov_reg_FCC0(TCGv reg, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+static inline void gen_mov_reg_FCC1(TCGv reg, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset);
+    tcg_gen_andi_tl(reg, reg, 0x1);
+}
+
+// !0: FCC0 | FCC1
+static inline void gen_op_eval_fbne(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+}
+
+// 1 or 2: FCC0 ^ FCC1
+static inline void gen_op_eval_fblg(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+}
+
+// 1 or 3: FCC0
+static inline void gen_op_eval_fbul(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+}
+
+// 1: FCC0 & !FCC1
+static inline void gen_op_eval_fbl(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+}
+
+// 2 or 3: FCC1
+static inline void gen_op_eval_fbug(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC1(dst, src, fcc_offset);
+}
+
+// 2: !FCC0 & FCC1
+static inline void gen_op_eval_fbg(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+}
+
+// 3: FCC0 & FCC1
+static inline void gen_op_eval_fbu(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+}
+
+// 0: !(FCC0 | FCC1)
+static inline void gen_op_eval_fbe(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_or_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// 0 or 3: !(FCC0 ^ FCC1)
+static inline void gen_op_eval_fbue(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_xor_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// 0 or 2: !FCC0
+static inline void gen_op_eval_fbge(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !1: !(FCC0 & !FCC1)
+static inline void gen_op_eval_fbuge(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// 0 or 1: !FCC1
+static inline void gen_op_eval_fble(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC1(dst, src, fcc_offset);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !2: !(!FCC0 & FCC1)
+static inline void gen_op_eval_fbule(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+// !3: !(FCC0 & FCC1)
+static inline void gen_op_eval_fbo(TCGv dst, TCGv src,
+                                    unsigned int fcc_offset)
+{
+    gen_mov_reg_FCC0(dst, src, fcc_offset);
+    gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset);
+    tcg_gen_and_tl(dst, dst, cpu_tmp0);
+    tcg_gen_xori_tl(dst, dst, 0x1);
+}
+
+static inline void gen_branch2(DisasContext *dc, target_ulong pc1,
+                               target_ulong pc2, TCGv r_cond)
+{
+    int l1;
+
+    l1 = gen_new_label();
+
+    tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
+
+    gen_goto_tb(dc, 0, pc1, pc1 + 4);
+
+    gen_set_label(l1);
+    gen_goto_tb(dc, 1, pc2, pc2 + 4);
+}
+
+static inline void gen_branch_a(DisasContext *dc, target_ulong pc1,
+                                target_ulong pc2, TCGv r_cond)
+{
+    int l1;
+
+    l1 = gen_new_label();
+
+    tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
+
+    gen_goto_tb(dc, 0, pc2, pc1);
+
+    gen_set_label(l1);
+    gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8);
+}
+
+static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2,
+                                      TCGv r_cond)
+{
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+
+    tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
+
+    tcg_gen_movi_tl(cpu_npc, npc1);
+    tcg_gen_br(l2);
+
+    gen_set_label(l1);
+    tcg_gen_movi_tl(cpu_npc, npc2);
+    gen_set_label(l2);
+}
+
+/* call this function before using the condition register as it may
+   have been set for a jump */
+static inline void flush_cond(DisasContext *dc, TCGv cond)
+{
+    if (dc->npc == JUMP_PC) {
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond);
+        dc->npc = DYNAMIC_PC;
+    }
+}
+
+static inline void save_npc(DisasContext *dc, TCGv cond)
+{
+    if (dc->npc == JUMP_PC) {
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond);
+        dc->npc = DYNAMIC_PC;
+    } else if (dc->npc != DYNAMIC_PC) {
+        tcg_gen_movi_tl(cpu_npc, dc->npc);
+    }
+}
+
+static inline void save_state(DisasContext *dc, TCGv cond)
+{
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    /* flush pending conditional evaluations before exposing cpu state */
+    if (dc->cc_op != CC_OP_FLAGS) {
+        dc->cc_op = CC_OP_FLAGS;
+        gen_helper_compute_psr();
+    }
+    save_npc(dc, cond);
+}
+
+static inline void gen_mov_pc_npc(DisasContext *dc, TCGv cond)
+{
+    if (dc->npc == JUMP_PC) {
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond);
+        tcg_gen_mov_tl(cpu_pc, cpu_npc);
+        dc->pc = DYNAMIC_PC;
+    } else if (dc->npc == DYNAMIC_PC) {
+        tcg_gen_mov_tl(cpu_pc, cpu_npc);
+        dc->pc = DYNAMIC_PC;
+    } else {
+        dc->pc = dc->npc;
+    }
+}
+
+static inline void gen_op_next_insn(void)
+{
+    tcg_gen_mov_tl(cpu_pc, cpu_npc);
+    tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
+}
+
+static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond,
+                            DisasContext *dc)
+{
+    TCGv_i32 r_src;
+
+#ifdef TARGET_SPARC64
+    if (cc)
+        r_src = cpu_xcc;
+    else
+        r_src = cpu_psr;
+#else
+    r_src = cpu_psr;
+#endif
+    switch (dc->cc_op) {
+    case CC_OP_FLAGS:
+        break;
+    default:
+        gen_helper_compute_psr();
+        dc->cc_op = CC_OP_FLAGS;
+        break;
+    }
+    switch (cond) {
+    case 0x0:
+        gen_op_eval_bn(r_dst);
+        break;
+    case 0x1:
+        gen_op_eval_be(r_dst, r_src);
+        break;
+    case 0x2:
+        gen_op_eval_ble(r_dst, r_src);
+        break;
+    case 0x3:
+        gen_op_eval_bl(r_dst, r_src);
+        break;
+    case 0x4:
+        gen_op_eval_bleu(r_dst, r_src);
+        break;
+    case 0x5:
+        gen_op_eval_bcs(r_dst, r_src);
+        break;
+    case 0x6:
+        gen_op_eval_bneg(r_dst, r_src);
+        break;
+    case 0x7:
+        gen_op_eval_bvs(r_dst, r_src);
+        break;
+    case 0x8:
+        gen_op_eval_ba(r_dst);
+        break;
+    case 0x9:
+        gen_op_eval_bne(r_dst, r_src);
+        break;
+    case 0xa:
+        gen_op_eval_bg(r_dst, r_src);
+        break;
+    case 0xb:
+        gen_op_eval_bge(r_dst, r_src);
+        break;
+    case 0xc:
+        gen_op_eval_bgu(r_dst, r_src);
+        break;
+    case 0xd:
+        gen_op_eval_bcc(r_dst, r_src);
+        break;
+    case 0xe:
+        gen_op_eval_bpos(r_dst, r_src);
+        break;
+    case 0xf:
+        gen_op_eval_bvc(r_dst, r_src);
+        break;
+    }
+}
+
+static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond)
+{
+    unsigned int offset;
+
+    switch (cc) {
+    default:
+    case 0x0:
+        offset = 0;
+        break;
+    case 0x1:
+        offset = 32 - 10;
+        break;
+    case 0x2:
+        offset = 34 - 10;
+        break;
+    case 0x3:
+        offset = 36 - 10;
+        break;
+    }
+
+    switch (cond) {
+    case 0x0:
+        gen_op_eval_bn(r_dst);
+        break;
+    case 0x1:
+        gen_op_eval_fbne(r_dst, cpu_fsr, offset);
+        break;
+    case 0x2:
+        gen_op_eval_fblg(r_dst, cpu_fsr, offset);
+        break;
+    case 0x3:
+        gen_op_eval_fbul(r_dst, cpu_fsr, offset);
+        break;
+    case 0x4:
+        gen_op_eval_fbl(r_dst, cpu_fsr, offset);
+        break;
+    case 0x5:
+        gen_op_eval_fbug(r_dst, cpu_fsr, offset);
+        break;
+    case 0x6:
+        gen_op_eval_fbg(r_dst, cpu_fsr, offset);
+        break;
+    case 0x7:
+        gen_op_eval_fbu(r_dst, cpu_fsr, offset);
+        break;
+    case 0x8:
+        gen_op_eval_ba(r_dst);
+        break;
+    case 0x9:
+        gen_op_eval_fbe(r_dst, cpu_fsr, offset);
+        break;
+    case 0xa:
+        gen_op_eval_fbue(r_dst, cpu_fsr, offset);
+        break;
+    case 0xb:
+        gen_op_eval_fbge(r_dst, cpu_fsr, offset);
+        break;
+    case 0xc:
+        gen_op_eval_fbuge(r_dst, cpu_fsr, offset);
+        break;
+    case 0xd:
+        gen_op_eval_fble(r_dst, cpu_fsr, offset);
+        break;
+    case 0xe:
+        gen_op_eval_fbule(r_dst, cpu_fsr, offset);
+        break;
+    case 0xf:
+        gen_op_eval_fbo(r_dst, cpu_fsr, offset);
+        break;
+    }
+}
+
+#ifdef TARGET_SPARC64
+// Inverted logic
+static const int gen_tcg_cond_reg[8] = {
+    -1,
+    TCG_COND_NE,
+    TCG_COND_GT,
+    TCG_COND_GE,
+    -1,
+    TCG_COND_EQ,
+    TCG_COND_LE,
+    TCG_COND_LT,
+};
+
+static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src)
+{
+    int l1;
+
+    l1 = gen_new_label();
+    tcg_gen_movi_tl(r_dst, 0);
+    tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], r_src, 0, l1);
+    tcg_gen_movi_tl(r_dst, 1);
+    gen_set_label(l1);
+}
+#endif
+
+/* XXX: potentially incorrect if dynamic npc */
+static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
+                      TCGv r_cond)
+{
+    unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
+    target_ulong target = dc->pc + offset;
+
+    if (cond == 0x0) {
+        /* unconditional not taken */
+        if (a) {
+            dc->pc = dc->npc + 4;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = dc->pc + 4;
+        }
+    } else if (cond == 0x8) {
+        /* unconditional taken */
+        if (a) {
+            dc->pc = target;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = target;
+            tcg_gen_mov_tl(cpu_pc, cpu_npc);
+        }
+    } else {
+        flush_cond(dc, r_cond);
+        gen_cond(r_cond, cc, cond, dc);
+        if (a) {
+            gen_branch_a(dc, target, dc->npc, r_cond);
+            dc->is_br = 1;
+        } else {
+            dc->pc = dc->npc;
+            dc->jump_pc[0] = target;
+            dc->jump_pc[1] = dc->npc + 4;
+            dc->npc = JUMP_PC;
+        }
+    }
+}
+
+/* XXX: potentially incorrect if dynamic npc */
+static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
+                      TCGv r_cond)
+{
+    unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
+    target_ulong target = dc->pc + offset;
+
+    if (cond == 0x0) {
+        /* unconditional not taken */
+        if (a) {
+            dc->pc = dc->npc + 4;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = dc->pc + 4;
+        }
+    } else if (cond == 0x8) {
+        /* unconditional taken */
+        if (a) {
+            dc->pc = target;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = target;
+            tcg_gen_mov_tl(cpu_pc, cpu_npc);
+        }
+    } else {
+        flush_cond(dc, r_cond);
+        gen_fcond(r_cond, cc, cond);
+        if (a) {
+            gen_branch_a(dc, target, dc->npc, r_cond);
+            dc->is_br = 1;
+        } else {
+            dc->pc = dc->npc;
+            dc->jump_pc[0] = target;
+            dc->jump_pc[1] = dc->npc + 4;
+            dc->npc = JUMP_PC;
+        }
+    }
+}
+
+#ifdef TARGET_SPARC64
+/* XXX: potentially incorrect if dynamic npc */
+static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
+                          TCGv r_cond, TCGv r_reg)
+{
+    unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29));
+    target_ulong target = dc->pc + offset;
+
+    flush_cond(dc, r_cond);
+    gen_cond_reg(r_cond, cond, r_reg);
+    if (a) {
+        gen_branch_a(dc, target, dc->npc, r_cond);
+        dc->is_br = 1;
+    } else {
+        dc->pc = dc->npc;
+        dc->jump_pc[0] = target;
+        dc->jump_pc[1] = dc->npc + 4;
+        dc->npc = JUMP_PC;
+    }
+}
+
+static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmps(r_rs1, r_rs2);
+        break;
+    case 1:
+        gen_helper_fcmps_fcc1(r_rs1, r_rs2);
+        break;
+    case 2:
+        gen_helper_fcmps_fcc2(r_rs1, r_rs2);
+        break;
+    case 3:
+        gen_helper_fcmps_fcc3(r_rs1, r_rs2);
+        break;
+    }
+}
+
+static inline void gen_op_fcmpd(int fccno)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmpd();
+        break;
+    case 1:
+        gen_helper_fcmpd_fcc1();
+        break;
+    case 2:
+        gen_helper_fcmpd_fcc2();
+        break;
+    case 3:
+        gen_helper_fcmpd_fcc3();
+        break;
+    }
+}
+
+static inline void gen_op_fcmpq(int fccno)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmpq();
+        break;
+    case 1:
+        gen_helper_fcmpq_fcc1();
+        break;
+    case 2:
+        gen_helper_fcmpq_fcc2();
+        break;
+    case 3:
+        gen_helper_fcmpq_fcc3();
+        break;
+    }
+}
+
+static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmpes(r_rs1, r_rs2);
+        break;
+    case 1:
+        gen_helper_fcmpes_fcc1(r_rs1, r_rs2);
+        break;
+    case 2:
+        gen_helper_fcmpes_fcc2(r_rs1, r_rs2);
+        break;
+    case 3:
+        gen_helper_fcmpes_fcc3(r_rs1, r_rs2);
+        break;
+    }
+}
+
+static inline void gen_op_fcmped(int fccno)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmped();
+        break;
+    case 1:
+        gen_helper_fcmped_fcc1();
+        break;
+    case 2:
+        gen_helper_fcmped_fcc2();
+        break;
+    case 3:
+        gen_helper_fcmped_fcc3();
+        break;
+    }
+}
+
+static inline void gen_op_fcmpeq(int fccno)
+{
+    switch (fccno) {
+    case 0:
+        gen_helper_fcmpeq();
+        break;
+    case 1:
+        gen_helper_fcmpeq_fcc1();
+        break;
+    case 2:
+        gen_helper_fcmpeq_fcc2();
+        break;
+    case 3:
+        gen_helper_fcmpeq_fcc3();
+        break;
+    }
+}
+
+#else
+
+static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
+{
+    gen_helper_fcmps(r_rs1, r_rs2);
+}
+
+static inline void gen_op_fcmpd(int fccno)
+{
+    gen_helper_fcmpd();
+}
+
+static inline void gen_op_fcmpq(int fccno)
+{
+    gen_helper_fcmpq();
+}
+
+static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
+{
+    gen_helper_fcmpes(r_rs1, r_rs2);
+}
+
+static inline void gen_op_fcmped(int fccno)
+{
+    gen_helper_fcmped();
+}
+
+static inline void gen_op_fcmpeq(int fccno)
+{
+    gen_helper_fcmpeq();
+}
+#endif
+
+static inline void gen_op_fpexception_im(int fsr_flags)
+{
+    TCGv_i32 r_const;
+
+    tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
+    tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
+    r_const = tcg_const_i32(TT_FP_EXCP);
+    gen_helper_raise_exception(r_const);
+    tcg_temp_free_i32(r_const);
+}
+
+static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
+{
+#if !defined(CONFIG_USER_ONLY)
+    if (!dc->fpu_enabled) {
+        TCGv_i32 r_const;
+
+        save_state(dc, r_cond);
+        r_const = tcg_const_i32(TT_NFPU_INSN);
+        gen_helper_raise_exception(r_const);
+        tcg_temp_free_i32(r_const);
+        dc->is_br = 1;
+        return 1;
+    }
+#endif
+    return 0;
+}
+
+static inline void gen_op_clear_ieee_excp_and_FTT(void)
+{
+    tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
+}
+
+static inline void gen_clear_float_exceptions(void)
+{
+    gen_helper_clear_float_exceptions();
+}
+
+/* asi moves */
+#ifdef TARGET_SPARC64
+static inline TCGv_i32 gen_get_asi(int insn, TCGv r_addr)
+{
+    int asi;
+    TCGv_i32 r_asi;
+
+    if (IS_IMM) {
+        r_asi = tcg_temp_new_i32();
+        tcg_gen_mov_i32(r_asi, cpu_asi);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        r_asi = tcg_const_i32(asi);
+    }
+    return r_asi;
+}
+
+static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
+                              int sign)
+{
+    TCGv_i32 r_asi, r_size, r_sign;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(size);
+    r_sign = tcg_const_i32(sign);
+    gen_helper_ld_asi(dst, addr, r_asi, r_size, r_sign);
+    tcg_temp_free_i32(r_sign);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
+{
+    TCGv_i32 r_asi, r_size;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(size);
+    gen_helper_st_asi(addr, src, r_asi, r_size);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd)
+{
+    TCGv_i32 r_asi, r_size, r_rd;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(size);
+    r_rd = tcg_const_i32(rd);
+    gen_helper_ldf_asi(addr, r_asi, r_size, r_rd);
+    tcg_temp_free_i32(r_rd);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd)
+{
+    TCGv_i32 r_asi, r_size, r_rd;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(size);
+    r_rd = tcg_const_i32(rd);
+    gen_helper_stf_asi(addr, r_asi, r_size, r_rd);
+    tcg_temp_free_i32(r_rd);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
+{
+    TCGv_i32 r_asi, r_size, r_sign;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(4);
+    r_sign = tcg_const_i32(0);
+    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    tcg_temp_free_i32(r_sign);
+    gen_helper_st_asi(addr, dst, r_asi, r_size);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+    tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
+}
+
+static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
+{
+    TCGv_i32 r_asi, r_rd;
+
+    r_asi = gen_get_asi(insn, addr);
+    r_rd = tcg_const_i32(rd);
+    gen_helper_ldda_asi(addr, r_asi, r_rd);
+    tcg_temp_free_i32(r_rd);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
+{
+    TCGv_i32 r_asi, r_size;
+
+    gen_movl_reg_TN(rd + 1, cpu_tmp0);
+    tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi);
+    r_asi = gen_get_asi(insn, addr);
+    r_size = tcg_const_i32(8);
+    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+}
+
+static inline void gen_cas_asi(TCGv dst, TCGv addr, TCGv val2, int insn,
+                               int rd)
+{
+    TCGv r_val1;
+    TCGv_i32 r_asi;
+
+    r_val1 = tcg_temp_new();
+    gen_movl_reg_TN(rd, r_val1);
+    r_asi = gen_get_asi(insn, addr);
+    gen_helper_cas_asi(dst, addr, r_val1, val2, r_asi);
+    tcg_temp_free_i32(r_asi);
+    tcg_temp_free(r_val1);
+}
+
+static inline void gen_casx_asi(TCGv dst, TCGv addr, TCGv val2, int insn,
+                                int rd)
+{
+    TCGv_i32 r_asi;
+
+    gen_movl_reg_TN(rd, cpu_tmp64);
+    r_asi = gen_get_asi(insn, addr);
+    gen_helper_casx_asi(dst, addr, cpu_tmp64, val2, r_asi);
+    tcg_temp_free_i32(r_asi);
+}
+
+#elif !defined(CONFIG_USER_ONLY)
+
+static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
+                              int sign)
+{
+    TCGv_i32 r_asi, r_size, r_sign;
+
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(size);
+    r_sign = tcg_const_i32(sign);
+    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    tcg_temp_free(r_sign);
+    tcg_temp_free(r_size);
+    tcg_temp_free(r_asi);
+    tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
+}
+
+static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
+{
+    TCGv_i32 r_asi, r_size;
+
+    tcg_gen_extu_tl_i64(cpu_tmp64, src);
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(size);
+    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    tcg_temp_free(r_size);
+    tcg_temp_free(r_asi);
+}
+
+static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
+{
+    TCGv_i32 r_asi, r_size, r_sign;
+    TCGv_i64 r_val;
+
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(4);
+    r_sign = tcg_const_i32(0);
+    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    tcg_temp_free(r_sign);
+    r_val = tcg_temp_new_i64();
+    tcg_gen_extu_tl_i64(r_val, dst);
+    gen_helper_st_asi(addr, r_val, r_asi, r_size);
+    tcg_temp_free_i64(r_val);
+    tcg_temp_free(r_size);
+    tcg_temp_free(r_asi);
+    tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
+}
+
+static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
+{
+    TCGv_i32 r_asi, r_size, r_sign;
+
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(8);
+    r_sign = tcg_const_i32(0);
+    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    tcg_temp_free(r_sign);
+    tcg_temp_free(r_size);
+    tcg_temp_free(r_asi);
+    tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64);
+    gen_movl_TN_reg(rd + 1, cpu_tmp0);
+    tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32);
+    tcg_gen_trunc_i64_tl(hi, cpu_tmp64);
+    gen_movl_TN_reg(rd, hi);
+}
+
+static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
+{
+    TCGv_i32 r_asi, r_size;
+
+    gen_movl_reg_TN(rd + 1, cpu_tmp0);
+    tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi);
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(8);
+    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    tcg_temp_free(r_size);
+    tcg_temp_free(r_asi);
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn)
+{
+    TCGv_i64 r_val;
+    TCGv_i32 r_asi, r_size;
+
+    gen_ld_asi(dst, addr, insn, 1, 0);
+
+    r_val = tcg_const_i64(0xffULL);
+    r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+    r_size = tcg_const_i32(1);
+    gen_helper_st_asi(addr, r_val, r_asi, r_size);
+    tcg_temp_free_i32(r_size);
+    tcg_temp_free_i32(r_asi);
+    tcg_temp_free_i64(r_val);
+}
+#endif
+
+static inline TCGv get_src1(unsigned int insn, TCGv def)
+{
+    TCGv r_rs1 = def;
+    unsigned int rs1;
+
+    rs1 = GET_FIELD(insn, 13, 17);
+    if (rs1 == 0) {
+        tcg_gen_movi_tl(def, 0);
+    } else if (rs1 < 8) {
+        r_rs1 = cpu_gregs[rs1];
+    } else {
+        tcg_gen_ld_tl(def, cpu_regwptr, (rs1 - 8) * sizeof(target_ulong));
+    }
+    return r_rs1;
+}
+
+static inline TCGv get_src2(unsigned int insn, TCGv def)
+{
+    TCGv r_rs2 = def;
+
+    if (IS_IMM) { /* immediate */
+        target_long simm = GET_FIELDs(insn, 19, 31);
+        tcg_gen_movi_tl(def, simm);
+    } else { /* register */
+        unsigned int rs2 = GET_FIELD(insn, 27, 31);
+        if (rs2 == 0) {
+            tcg_gen_movi_tl(def, 0);
+        } else if (rs2 < 8) {
+            r_rs2 = cpu_gregs[rs2];
+        } else {
+            tcg_gen_ld_tl(def, cpu_regwptr, (rs2 - 8) * sizeof(target_ulong));
+        }
+    }
+    return r_rs2;
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
+{
+    TCGv_i32 r_tl = tcg_temp_new_i32();
+
+    /* load env->tl into r_tl */
+    tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl));
+
+    /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */
+    tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK);
+
+    /* calculate offset to current trap state from env->ts, reuse r_tl */
+    tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state));
+    tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUState, ts));
+
+    /* tsptr = env->ts[env->tl & MAXTL_MASK] */
+    {
+        TCGv_ptr r_tl_tmp = tcg_temp_new_ptr();
+        tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl);
+        tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp);
+        tcg_temp_free_ptr(r_tl_tmp);
+    }
+
+    tcg_temp_free_i32(r_tl);
+}
+#endif
+
+#define CHECK_IU_FEATURE(dc, FEATURE)                      \
+    if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE))  \
+        goto illegal_insn;
+#define CHECK_FPU_FEATURE(dc, FEATURE)                     \
+    if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE))  \
+        goto nfpu_insn;
+
+/* before an instruction, dc->pc must be static */
+static void disas_sparc_insn(DisasContext * dc)
+{
+    unsigned int insn, opc, rs1, rs2, rd;
+    TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2;
+    target_long simm;
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+        tcg_gen_debug_insn_start(dc->pc);
+    insn = ldl_code(dc->pc);
+    opc = GET_FIELD(insn, 0, 1);
+
+    rd = GET_FIELD(insn, 2, 6);
+
+    cpu_tmp1 = cpu_src1 = tcg_temp_new();
+    cpu_tmp2 = cpu_src2 = tcg_temp_new();
+
+    switch (opc) {
+    case 0:                     /* branches/sethi */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 9);
+            int32_t target;
+            switch (xop) {
+#ifdef TARGET_SPARC64
+            case 0x1:           /* V9 BPcc */
+                {
+                    int cc;
+
+                    target = GET_FIELD_SP(insn, 0, 18);
+                    target = sign_extend(target, 19);
+                    target <<= 2;
+                    cc = GET_FIELD_SP(insn, 20, 21);
+                    if (cc == 0)
+                        do_branch(dc, target, insn, 0, cpu_cond);
+                    else if (cc == 2)
+                        do_branch(dc, target, insn, 1, cpu_cond);
+                    else
+                        goto illegal_insn;
+                    goto jmp_insn;
+                }
+            case 0x3:           /* V9 BPr */
+                {
+                    target = GET_FIELD_SP(insn, 0, 13) |
+                        (GET_FIELD_SP(insn, 20, 21) << 14);
+                    target = sign_extend(target, 16);
+                    target <<= 2;
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    do_branch_reg(dc, target, insn, cpu_cond, cpu_src1);
+                    goto jmp_insn;
+                }
+            case 0x5:           /* V9 FBPcc */
+                {
+                    int cc = GET_FIELD_SP(insn, 20, 21);
+                    if (gen_trap_ifnofpu(dc, cpu_cond))
+                        goto jmp_insn;
+                    target = GET_FIELD_SP(insn, 0, 18);
+                    target = sign_extend(target, 19);
+                    target <<= 2;
+                    do_fbranch(dc, target, insn, cc, cpu_cond);
+                    goto jmp_insn;
+                }
+#else
+            case 0x7:           /* CBN+x */
+                {
+                    goto ncp_insn;
+                }
+#endif
+            case 0x2:           /* BN+x */
+                {
+                    target = GET_FIELD(insn, 10, 31);
+                    target = sign_extend(target, 22);
+                    target <<= 2;
+                    do_branch(dc, target, insn, 0, cpu_cond);
+                    goto jmp_insn;
+                }
+            case 0x6:           /* FBN+x */
+                {
+                    if (gen_trap_ifnofpu(dc, cpu_cond))
+                        goto jmp_insn;
+                    target = GET_FIELD(insn, 10, 31);
+                    target = sign_extend(target, 22);
+                    target <<= 2;
+                    do_fbranch(dc, target, insn, 0, cpu_cond);
+                    goto jmp_insn;
+                }
+            case 0x4:           /* SETHI */
+                if (rd) { // nop
+                    uint32_t value = GET_FIELD(insn, 10, 31);
+                    TCGv r_const;
+
+                    r_const = tcg_const_tl(value << 10);
+                    gen_movl_TN_reg(rd, r_const);
+                    tcg_temp_free(r_const);
+                }
+                break;
+            case 0x0:           /* UNIMPL */
+            default:
+                goto illegal_insn;
+            }
+            break;
+        }
+        break;
+    case 1:                     /*CALL*/
+        {
+            target_long target = GET_FIELDs(insn, 2, 31) << 2;
+            TCGv r_const;
+
+            r_const = tcg_const_tl(dc->pc);
+            gen_movl_TN_reg(15, r_const);
+            tcg_temp_free(r_const);
+            target += dc->pc;
+            gen_mov_pc_npc(dc, cpu_cond);
+            dc->npc = target;
+        }
+        goto jmp_insn;
+    case 2:                     /* FPU & Logical Operations */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 12);
+            if (xop == 0x3a) {  /* generate trap */
+                int cond;
+
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {
+                    rs2 = GET_FIELD(insn, 25, 31);
+                    tcg_gen_addi_tl(cpu_dst, cpu_src1, rs2);
+                } else {
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    if (rs2 != 0) {
+                        gen_movl_reg_TN(rs2, cpu_src2);
+                        tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                    } else
+                        tcg_gen_mov_tl(cpu_dst, cpu_src1);
+                }
+
+                cond = GET_FIELD(insn, 3, 6);
+                if (cond == 0x8) { /* Trap Always */
+                    save_state(dc, cpu_cond);
+                    if ((dc->def->features & CPU_FEATURE_HYPV) &&
+                        supervisor(dc))
+                        tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK);
+                    else
+                        tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
+                    tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
+                    tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
+
+                    if (rs2 == 0 &&
+                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
+
+                        gen_helper_shutdown();
+
+                    } else {
+                        gen_helper_raise_exception(cpu_tmp32);
+                    }
+                } else if (cond != 0) {
+                    TCGv r_cond = tcg_temp_new();
+                    int l1;
+#ifdef TARGET_SPARC64
+                    /* V9 icc/xcc */
+                    int cc = GET_FIELD_SP(insn, 11, 12);
+
+                    save_state(dc, cpu_cond);
+                    if (cc == 0)
+                        gen_cond(r_cond, 0, cond, dc);
+                    else if (cc == 2)
+                        gen_cond(r_cond, 1, cond, dc);
+                    else
+                        goto illegal_insn;
+#else
+                    save_state(dc, cpu_cond);
+                    gen_cond(r_cond, 0, cond, dc);
+#endif
+                    l1 = gen_new_label();
+                    tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
+
+                    if ((dc->def->features & CPU_FEATURE_HYPV) &&
+                        supervisor(dc))
+                        tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK);
+                    else
+                        tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
+                    tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
+                    tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
+                    gen_helper_raise_exception(cpu_tmp32);
+
+                    gen_set_label(l1);
+                    tcg_temp_free(r_cond);
+                }
+                gen_op_next_insn();
+                tcg_gen_exit_tb(0);
+                dc->is_br = 1;
+                goto jmp_insn;
+            } else if (xop == 0x28) {
+                rs1 = GET_FIELD(insn, 13, 17);
+                switch(rs1) {
+                case 0: /* rdy */
+#ifndef TARGET_SPARC64
+                case 0x01 ... 0x0e: /* undefined in the SPARCv8
+                                       manual, rdy on the microSPARC
+                                       II */
+                case 0x0f:          /* stbar in the SPARCv8 manual,
+                                       rdy on the microSPARC II */
+                case 0x10 ... 0x1f: /* implementation-dependent in the
+                                       SPARCv8 manual, rdy on the
+                                       microSPARC II */
+                    /* Read Asr17 */
+                    if (rs1 == 0x11 && dc->def->features & CPU_FEATURE_ASR17) {
+                        TCGv r_const;
+
+                        /* Read Asr17 for a Leon3 monoprocessor */
+                        r_const = tcg_const_tl((1 << 8)
+                                               | (dc->def->nwindows - 1));
+                        gen_movl_TN_reg(rd, r_const);
+                        tcg_temp_free(r_const);
+                        break;
+                    }
+#endif
+                    gen_movl_TN_reg(rd, cpu_y);
+                    break;
+#ifdef TARGET_SPARC64
+                case 0x2: /* V9 rdccr */
+                    gen_helper_compute_psr();
+                    gen_helper_rdccr(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x3: /* V9 rdasi */
+                    tcg_gen_ext_i32_tl(cpu_dst, cpu_asi);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x4: /* V9 rdtick */
+                    {
+                        TCGv_ptr r_tickptr;
+
+                        r_tickptr = tcg_temp_new_ptr();
+                        tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                       offsetof(CPUState, tick));
+                        gen_helper_tick_get_count(cpu_dst, r_tickptr);
+                        tcg_temp_free_ptr(r_tickptr);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                    }
+                    break;
+                case 0x5: /* V9 rdpc */
+                    {
+                        TCGv r_const;
+
+                        r_const = tcg_const_tl(dc->pc);
+                        gen_movl_TN_reg(rd, r_const);
+                        tcg_temp_free(r_const);
+                    }
+                    break;
+                case 0x6: /* V9 rdfprs */
+                    tcg_gen_ext_i32_tl(cpu_dst, cpu_fprs);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0xf: /* V9 membar */
+                    break; /* no effect */
+                case 0x13: /* Graphics Status */
+                    if (gen_trap_ifnofpu(dc, cpu_cond))
+                        goto jmp_insn;
+                    gen_movl_TN_reg(rd, cpu_gsr);
+                    break;
+                case 0x16: /* Softint */
+                    tcg_gen_ext_i32_tl(cpu_dst, cpu_softint);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x17: /* Tick compare */
+                    gen_movl_TN_reg(rd, cpu_tick_cmpr);
+                    break;
+                case 0x18: /* System tick */
+                    {
+                        TCGv_ptr r_tickptr;
+
+                        r_tickptr = tcg_temp_new_ptr();
+                        tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                       offsetof(CPUState, stick));
+                        gen_helper_tick_get_count(cpu_dst, r_tickptr);
+                        tcg_temp_free_ptr(r_tickptr);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                    }
+                    break;
+                case 0x19: /* System tick compare */
+                    gen_movl_TN_reg(rd, cpu_stick_cmpr);
+                    break;
+                case 0x10: /* Performance Control */
+                case 0x11: /* Performance Instrumentation Counter */
+                case 0x12: /* Dispatch Control */
+                case 0x14: /* Softint set, WO */
+                case 0x15: /* Softint clear, WO */
+#endif
+                default:
+                    goto illegal_insn;
+                }
+#if !defined(CONFIG_USER_ONLY)
+            } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */
+#ifndef TARGET_SPARC64
+                if (!supervisor(dc))
+                    goto priv_insn;
+                gen_helper_compute_psr();
+                dc->cc_op = CC_OP_FLAGS;
+                gen_helper_rdpsr(cpu_dst);
+#else
+                CHECK_IU_FEATURE(dc, HYPV);
+                if (!hypervisor(dc))
+                    goto priv_insn;
+                rs1 = GET_FIELD(insn, 13, 17);
+                switch (rs1) {
+                case 0: // hpstate
+                    // gen_op_rdhpstate();
+                    break;
+                case 1: // htstate
+                    // gen_op_rdhtstate();
+                    break;
+                case 3: // hintp
+                    tcg_gen_mov_tl(cpu_dst, cpu_hintp);
+                    break;
+                case 5: // htba
+                    tcg_gen_mov_tl(cpu_dst, cpu_htba);
+                    break;
+                case 6: // hver
+                    tcg_gen_mov_tl(cpu_dst, cpu_hver);
+                    break;
+                case 31: // hstick_cmpr
+                    tcg_gen_mov_tl(cpu_dst, cpu_hstick_cmpr);
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+#endif
+                gen_movl_TN_reg(rd, cpu_dst);
+                break;
+            } else if (xop == 0x2a) { /* rdwim / V9 rdpr */
+                if (!supervisor(dc))
+                    goto priv_insn;
+#ifdef TARGET_SPARC64
+                rs1 = GET_FIELD(insn, 13, 17);
+                switch (rs1) {
+                case 0: // tpc
+                    {
+                        TCGv_ptr r_tsptr;
+
+                        r_tsptr = tcg_temp_new_ptr();
+                        gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                        tcg_gen_ld_tl(cpu_tmp0, r_tsptr,
+                                      offsetof(trap_state, tpc));
+                        tcg_temp_free_ptr(r_tsptr);
+                    }
+                    break;
+                case 1: // tnpc
+                    {
+                        TCGv_ptr r_tsptr;
+
+                        r_tsptr = tcg_temp_new_ptr();
+                        gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                        tcg_gen_ld_tl(cpu_tmp0, r_tsptr,
+                                      offsetof(trap_state, tnpc));
+                        tcg_temp_free_ptr(r_tsptr);
+                    }
+                    break;
+                case 2: // tstate
+                    {
+                        TCGv_ptr r_tsptr;
+
+                        r_tsptr = tcg_temp_new_ptr();
+                        gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                        tcg_gen_ld_tl(cpu_tmp0, r_tsptr,
+                                      offsetof(trap_state, tstate));
+                        tcg_temp_free_ptr(r_tsptr);
+                    }
+                    break;
+                case 3: // tt
+                    {
+                        TCGv_ptr r_tsptr;
+
+                        r_tsptr = tcg_temp_new_ptr();
+                        gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                        tcg_gen_ld_i32(cpu_tmp32, r_tsptr,
+                                       offsetof(trap_state, tt));
+                        tcg_temp_free_ptr(r_tsptr);
+                        tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    }
+                    break;
+                case 4: // tick
+                    {
+                        TCGv_ptr r_tickptr;
+
+                        r_tickptr = tcg_temp_new_ptr();
+                        tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                       offsetof(CPUState, tick));
+                        gen_helper_tick_get_count(cpu_tmp0, r_tickptr);
+                        gen_movl_TN_reg(rd, cpu_tmp0);
+                        tcg_temp_free_ptr(r_tickptr);
+                    }
+                    break;
+                case 5: // tba
+                    tcg_gen_mov_tl(cpu_tmp0, cpu_tbr);
+                    break;
+                case 6: // pstate
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, pstate));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 7: // tl
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, tl));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 8: // pil
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, psrpil));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 9: // cwp
+                    gen_helper_rdcwp(cpu_tmp0);
+                    break;
+                case 10: // cansave
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, cansave));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 11: // canrestore
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, canrestore));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 12: // cleanwin
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, cleanwin));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 13: // otherwin
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, otherwin));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 14: // wstate
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, wstate));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 16: // UA2005 gl
+                    CHECK_IU_FEATURE(dc, GL);
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env,
+                                   offsetof(CPUSPARCState, gl));
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
+                    break;
+                case 26: // UA2005 strand status
+                    CHECK_IU_FEATURE(dc, HYPV);
+                    if (!hypervisor(dc))
+                        goto priv_insn;
+                    tcg_gen_mov_tl(cpu_tmp0, cpu_ssr);
+                    break;
+                case 31: // ver
+                    tcg_gen_mov_tl(cpu_tmp0, cpu_ver);
+                    break;
+                case 15: // fq
+                default:
+                    goto illegal_insn;
+                }
+#else
+                tcg_gen_ext_i32_tl(cpu_tmp0, cpu_wim);
+#endif
+                gen_movl_TN_reg(rd, cpu_tmp0);
+                break;
+            } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
+#ifdef TARGET_SPARC64
+                save_state(dc, cpu_cond);
+                gen_helper_flushw();
+#else
+                if (!supervisor(dc))
+                    goto priv_insn;
+                gen_movl_TN_reg(rd, cpu_tbr);
+#endif
+                break;
+#endif
+            } else if (xop == 0x34) {   /* FPU Operations */
+                if (gen_trap_ifnofpu(dc, cpu_cond))
+                    goto jmp_insn;
+                gen_op_clear_ieee_excp_and_FTT();
+                rs1 = GET_FIELD(insn, 13, 17);
+                rs2 = GET_FIELD(insn, 27, 31);
+                xop = GET_FIELD(insn, 18, 26);
+                save_state(dc, cpu_cond);
+                switch (xop) {
+                case 0x1: /* fmovs */
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    break;
+                case 0x5: /* fnegs */
+                    gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
+                    break;
+                case 0x9: /* fabss */
+                    gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
+                    break;
+                case 0x29: /* fsqrts */
+                    CHECK_FPU_FEATURE(dc, FSQRT);
+                    gen_clear_float_exceptions();
+                    gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x2a: /* fsqrtd */
+                    CHECK_FPU_FEATURE(dc, FSQRT);
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fsqrtd();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x2b: /* fsqrtq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fsqrtq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x41: /* fadds */
+                    gen_clear_float_exceptions();
+                    gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x42: /* faddd */
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_faddd();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x43: /* faddq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT0(QFPREG(rs1));
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_faddq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x45: /* fsubs */
+                    gen_clear_float_exceptions();
+                    gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x46: /* fsubd */
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fsubd();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x47: /* fsubq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT0(QFPREG(rs1));
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fsubq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x49: /* fmuls */
+                    CHECK_FPU_FEATURE(dc, FMUL);
+                    gen_clear_float_exceptions();
+                    gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x4a: /* fmuld */
+                    CHECK_FPU_FEATURE(dc, FMUL);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fmuld();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x4b: /* fmulq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    CHECK_FPU_FEATURE(dc, FMUL);
+                    gen_op_load_fpr_QT0(QFPREG(rs1));
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fmulq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x4d: /* fdivs */
+                    gen_clear_float_exceptions();
+                    gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x4e: /* fdivd */
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdivd();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x4f: /* fdivq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT0(QFPREG(rs1));
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdivq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x69: /* fsmuld */
+                    CHECK_FPU_FEATURE(dc, FSMULD);
+                    gen_clear_float_exceptions();
+                    gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x6e: /* fdmulq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdmulq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0xc4: /* fitos */
+                    gen_clear_float_exceptions();
+                    gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0xc6: /* fdtos */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdtos(cpu_tmp32);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0xc7: /* fqtos */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fqtos(cpu_tmp32);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0xc8: /* fitod */
+                    gen_helper_fitod(cpu_fpr[rs2]);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0xc9: /* fstod */
+                    gen_helper_fstod(cpu_fpr[rs2]);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0xcb: /* fqtod */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fqtod();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0xcc: /* fitoq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_helper_fitoq(cpu_fpr[rs2]);
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0xcd: /* fstoq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_helper_fstoq(cpu_fpr[rs2]);
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0xce: /* fdtoq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fdtoq();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0xd1: /* fstoi */
+                    gen_clear_float_exceptions();
+                    gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0xd2: /* fdtoi */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdtoi(cpu_tmp32);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0xd3: /* fqtoi */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fqtoi(cpu_tmp32);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+#ifdef TARGET_SPARC64
+                case 0x2: /* V9 fmovd */
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x3: /* V9 fmovq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],
+                                    cpu_fpr[QFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],
+                                    cpu_fpr[QFPREG(rs2) + 2]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
+                                    cpu_fpr[QFPREG(rs2) + 3]);
+                    break;
+                case 0x6: /* V9 fnegd */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fnegd();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x7: /* V9 fnegq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_helper_fnegq();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0xa: /* V9 fabsd */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fabsd();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0xb: /* V9 fabsq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_helper_fabsq();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+                case 0x81: /* V9 fstox */
+                    gen_clear_float_exceptions();
+                    gen_helper_fstox(cpu_fpr[rs2]);
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x82: /* V9 fdtox */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fdtox();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x83: /* V9 fqtox */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fqtox();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x84: /* V9 fxtos */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fxtos(cpu_tmp32);
+                    gen_helper_check_ieee_exceptions();
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    break;
+                case 0x88: /* V9 fxtod */
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fxtod();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x8c: /* V9 fxtoq */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_clear_float_exceptions();
+                    gen_helper_fxtoq();
+                    gen_helper_check_ieee_exceptions();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop == 0x35) {   /* FPU Operations */
+#ifdef TARGET_SPARC64
+                int cond;
+#endif
+                if (gen_trap_ifnofpu(dc, cpu_cond))
+                    goto jmp_insn;
+                gen_op_clear_ieee_excp_and_FTT();
+                rs1 = GET_FIELD(insn, 13, 17);
+                rs2 = GET_FIELD(insn, 27, 31);
+                xop = GET_FIELD(insn, 18, 26);
+                save_state(dc, cpu_cond);
+#ifdef TARGET_SPARC64
+                if ((xop & 0x11f) == 0x005) { // V9 fmovsr
+                    int l1;
+
+                    l1 = gen_new_label();
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
+                                       0, l1);
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    gen_set_label(l1);
+                    break;
+                } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
+                    int l1;
+
+                    l1 = gen_new_label();
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
+                                       0, l1);
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], cpu_fpr[DFPREG(rs2) + 1]);
+                    gen_set_label(l1);
+                    break;
+                } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
+                    int l1;
+
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    l1 = gen_new_label();
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
+                                       0, l1);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], cpu_fpr[QFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], cpu_fpr[QFPREG(rs2) + 2]);
+                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], cpu_fpr[QFPREG(rs2) + 3]);
+                    gen_set_label(l1);
+                    break;
+                }
+#endif
+                switch (xop) {
+#ifdef TARGET_SPARC64
+#define FMOVSCC(fcc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_fcond(r_cond, fcc, cond);                   \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+#define FMOVDCC(fcc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_fcond(r_cond, fcc, cond);                   \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
+                                        cpu_fpr[DFPREG(rs2)]);          \
+                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
+                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+#define FMOVQCC(fcc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_fcond(r_cond, fcc, cond);                   \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
+                                        cpu_fpr[QFPREG(rs2)]);          \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
+                                        cpu_fpr[QFPREG(rs2) + 1]);      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
+                                        cpu_fpr[QFPREG(rs2) + 2]);      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
+                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+                    case 0x001: /* V9 fmovscc %fcc0 */
+                        FMOVSCC(0);
+                        break;
+                    case 0x002: /* V9 fmovdcc %fcc0 */
+                        FMOVDCC(0);
+                        break;
+                    case 0x003: /* V9 fmovqcc %fcc0 */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(0);
+                        break;
+                    case 0x041: /* V9 fmovscc %fcc1 */
+                        FMOVSCC(1);
+                        break;
+                    case 0x042: /* V9 fmovdcc %fcc1 */
+                        FMOVDCC(1);
+                        break;
+                    case 0x043: /* V9 fmovqcc %fcc1 */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(1);
+                        break;
+                    case 0x081: /* V9 fmovscc %fcc2 */
+                        FMOVSCC(2);
+                        break;
+                    case 0x082: /* V9 fmovdcc %fcc2 */
+                        FMOVDCC(2);
+                        break;
+                    case 0x083: /* V9 fmovqcc %fcc2 */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(2);
+                        break;
+                    case 0x0c1: /* V9 fmovscc %fcc3 */
+                        FMOVSCC(3);
+                        break;
+                    case 0x0c2: /* V9 fmovdcc %fcc3 */
+                        FMOVDCC(3);
+                        break;
+                    case 0x0c3: /* V9 fmovqcc %fcc3 */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(3);
+                        break;
+#undef FMOVSCC
+#undef FMOVDCC
+#undef FMOVQCC
+#define FMOVSCC(icc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_cond(r_cond, icc, cond, dc);                \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+#define FMOVDCC(icc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_cond(r_cond, icc, cond, dc);                \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
+                                        cpu_fpr[DFPREG(rs2)]);          \
+                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
+                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+#define FMOVQCC(icc)                                                    \
+                    {                                                   \
+                        TCGv r_cond;                                    \
+                        int l1;                                         \
+                                                                        \
+                        l1 = gen_new_label();                           \
+                        r_cond = tcg_temp_new();                        \
+                        cond = GET_FIELD_SP(insn, 14, 17);              \
+                        gen_cond(r_cond, icc, cond, dc);                \
+                        tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
+                                           0, l1);                      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
+                                        cpu_fpr[QFPREG(rs2)]);          \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
+                                        cpu_fpr[QFPREG(rs2) + 1]);      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
+                                        cpu_fpr[QFPREG(rs2) + 2]);      \
+                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
+                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        gen_set_label(l1);                              \
+                        tcg_temp_free(r_cond);                          \
+                    }
+
+                    case 0x101: /* V9 fmovscc %icc */
+                        FMOVSCC(0);
+                        break;
+                    case 0x102: /* V9 fmovdcc %icc */
+                        FMOVDCC(0);
+                        break;
+                    case 0x103: /* V9 fmovqcc %icc */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(0);
+                        break;
+                    case 0x181: /* V9 fmovscc %xcc */
+                        FMOVSCC(1);
+                        break;
+                    case 0x182: /* V9 fmovdcc %xcc */
+                        FMOVDCC(1);
+                        break;
+                    case 0x183: /* V9 fmovqcc %xcc */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        FMOVQCC(1);
+                        break;
+#undef FMOVSCC
+#undef FMOVDCC
+#undef FMOVQCC
+#endif
+                    case 0x51: /* fcmps, V9 %fcc */
+                        gen_op_fcmps(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        break;
+                    case 0x52: /* fcmpd, V9 %fcc */
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fcmpd(rd & 3);
+                        break;
+                    case 0x53: /* fcmpq, V9 %fcc */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fcmpq(rd & 3);
+                        break;
+                    case 0x55: /* fcmpes, V9 %fcc */
+                        gen_op_fcmpes(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        break;
+                    case 0x56: /* fcmped, V9 %fcc */
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fcmped(rd & 3);
+                        break;
+                    case 0x57: /* fcmpeq, V9 %fcc */
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fcmpeq(rd & 3);
+                        break;
+                    default:
+                        goto illegal_insn;
+                }
+            } else if (xop == 0x2) {
+                // clr/mov shortcut
+
+                rs1 = GET_FIELD(insn, 13, 17);
+                if (rs1 == 0) {
+                    // or %g0, x, y -> mov T0, x; mov y, T0
+                    if (IS_IMM) {       /* immediate */
+                        TCGv r_const;
+
+                        simm = GET_FIELDs(insn, 19, 31);
+                        r_const = tcg_const_tl(simm);
+                        gen_movl_TN_reg(rd, r_const);
+                        tcg_temp_free(r_const);
+                    } else {            /* register */
+                        rs2 = GET_FIELD(insn, 27, 31);
+                        gen_movl_reg_TN(rs2, cpu_dst);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                    }
+                } else {
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    if (IS_IMM) {       /* immediate */
+                        simm = GET_FIELDs(insn, 19, 31);
+                        tcg_gen_ori_tl(cpu_dst, cpu_src1, simm);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                    } else {            /* register */
+                        // or x, %g0, y -> mov T1, x; mov y, T1
+                        rs2 = GET_FIELD(insn, 27, 31);
+                        if (rs2 != 0) {
+                            gen_movl_reg_TN(rs2, cpu_src2);
+                            tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2);
+                            gen_movl_TN_reg(rd, cpu_dst);
+                        } else
+                            gen_movl_TN_reg(rd, cpu_src1);
+                    }
+                }
+#ifdef TARGET_SPARC64
+            } else if (xop == 0x25) { /* sll, V9 sllx */
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {   /* immediate */
+                    simm = GET_FIELDs(insn, 20, 31);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x3f);
+                    } else {
+                        tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x1f);
+                    }
+                } else {                /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f);
+                    } else {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f);
+                    }
+                    tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0);
+                }
+                gen_movl_TN_reg(rd, cpu_dst);
+            } else if (xop == 0x26) { /* srl, V9 srlx */
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {   /* immediate */
+                    simm = GET_FIELDs(insn, 20, 31);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_shri_i64(cpu_dst, cpu_src1, simm & 0x3f);
+                    } else {
+                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
+                        tcg_gen_shri_i64(cpu_dst, cpu_dst, simm & 0x1f);
+                    }
+                } else {                /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f);
+                        tcg_gen_shr_i64(cpu_dst, cpu_src1, cpu_tmp0);
+                    } else {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f);
+                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
+                        tcg_gen_shr_i64(cpu_dst, cpu_dst, cpu_tmp0);
+                    }
+                }
+                gen_movl_TN_reg(rd, cpu_dst);
+            } else if (xop == 0x27) { /* sra, V9 srax */
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {   /* immediate */
+                    simm = GET_FIELDs(insn, 20, 31);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_sari_i64(cpu_dst, cpu_src1, simm & 0x3f);
+                    } else {
+                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
+                        tcg_gen_ext32s_i64(cpu_dst, cpu_dst);
+                        tcg_gen_sari_i64(cpu_dst, cpu_dst, simm & 0x1f);
+                    }
+                } else {                /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    if (insn & (1 << 12)) {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f);
+                        tcg_gen_sar_i64(cpu_dst, cpu_src1, cpu_tmp0);
+                    } else {
+                        tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f);
+                        tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
+                        tcg_gen_ext32s_i64(cpu_dst, cpu_dst);
+                        tcg_gen_sar_i64(cpu_dst, cpu_dst, cpu_tmp0);
+                    }
+                }
+                gen_movl_TN_reg(rd, cpu_dst);
+#endif
+            } else if (xop < 0x36) {
+                if (xop < 0x20) {
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    cpu_src2 = get_src2(insn, cpu_src2);
+                    switch (xop & ~0x10) {
+                    case 0x0: /* add */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            if (xop & 0x10) {
+                                gen_op_addi_cc(cpu_dst, cpu_src1, simm);
+                                tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
+                                dc->cc_op = CC_OP_ADD;
+                            } else {
+                                tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
+                            }
+                        } else {
+                            if (xop & 0x10) {
+                                gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2);
+                                tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
+                                dc->cc_op = CC_OP_ADD;
+                            } else {
+                                tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                            }
+                        }
+                        break;
+                    case 0x1: /* and */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_andi_tl(cpu_dst, cpu_src1, simm);
+                        } else {
+                            tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x2: /* or */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_ori_tl(cpu_dst, cpu_src1, simm);
+                        } else {
+                            tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x3: /* xor */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_xori_tl(cpu_dst, cpu_src1, simm);
+                        } else {
+                            tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x4: /* sub */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            if (xop & 0x10) {
+                                gen_op_subi_cc(cpu_dst, cpu_src1, simm, dc);
+                            } else {
+                                tcg_gen_subi_tl(cpu_dst, cpu_src1, simm);
+                            }
+                        } else {
+                            if (xop & 0x10) {
+                                gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2);
+                                tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
+                                dc->cc_op = CC_OP_SUB;
+                            } else {
+                                tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2);
+                            }
+                        }
+                        break;
+                    case 0x5: /* andn */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_andi_tl(cpu_dst, cpu_src1, ~simm);
+                        } else {
+                            tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x6: /* orn */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_ori_tl(cpu_dst, cpu_src1, ~simm);
+                        } else {
+                            tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x7: /* xorn */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_xori_tl(cpu_dst, cpu_src1, ~simm);
+                        } else {
+                            tcg_gen_not_tl(cpu_tmp0, cpu_src2);
+                            tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_tmp0);
+                        }
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0x8: /* addx, V9 addc */
+                        gen_op_addx_int(dc, cpu_dst, cpu_src1, cpu_src2,
+                                        (xop & 0x10));
+                        break;
+#ifdef TARGET_SPARC64
+                    case 0x9: /* V9 mulx */
+                        if (IS_IMM) {
+                            simm = GET_FIELDs(insn, 19, 31);
+                            tcg_gen_muli_i64(cpu_dst, cpu_src1, simm);
+                        } else {
+                            tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        break;
+#endif
+                    case 0xa: /* umul */
+                        CHECK_IU_FEATURE(dc, MUL);
+                        gen_op_umul(cpu_dst, cpu_src1, cpu_src2);
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0xb: /* smul */
+                        CHECK_IU_FEATURE(dc, MUL);
+                        gen_op_smul(cpu_dst, cpu_src1, cpu_src2);
+                        if (xop & 0x10) {
+                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
+                            dc->cc_op = CC_OP_LOGIC;
+                        }
+                        break;
+                    case 0xc: /* subx, V9 subc */
+                        gen_op_subx_int(dc, cpu_dst, cpu_src1, cpu_src2,
+                                        (xop & 0x10));
+                        break;
+#ifdef TARGET_SPARC64
+                    case 0xd: /* V9 udivx */
+                        {
+                            TCGv r_temp1, r_temp2;
+                            r_temp1 = tcg_temp_local_new();
+                            r_temp2 = tcg_temp_local_new();
+                            tcg_gen_mov_tl(r_temp1, cpu_src1);
+                            tcg_gen_mov_tl(r_temp2, cpu_src2);
+                            gen_trap_ifdivzero_tl(r_temp2);
+                            tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2);
+                            tcg_temp_free(r_temp1);
+                            tcg_temp_free(r_temp2);
+                        }
+                        break;
+#endif
+                    case 0xe: /* udiv */
+                        CHECK_IU_FEATURE(dc, DIV);
+                        if (xop & 0x10) {
+                            gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            dc->cc_op = CC_OP_DIV;
+                        } else {
+                            gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        break;
+                    case 0xf: /* sdiv */
+                        CHECK_IU_FEATURE(dc, DIV);
+                        if (xop & 0x10) {
+                            gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            dc->cc_op = CC_OP_DIV;
+                        } else {
+                            gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
+                        }
+                        break;
+                    default:
+                        goto illegal_insn;
+                    }
+                    gen_movl_TN_reg(rd, cpu_dst);
+                } else {
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    cpu_src2 = get_src2(insn, cpu_src2);
+                    switch (xop) {
+                    case 0x20: /* taddcc */
+                        gen_op_tadd_cc(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADD);
+                        dc->cc_op = CC_OP_TADD;
+                        break;
+                    case 0x21: /* tsubcc */
+                        gen_op_tsub_cc(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUB);
+                        dc->cc_op = CC_OP_TSUB;
+                        break;
+                    case 0x22: /* taddcctv */
+                        save_state(dc, cpu_cond);
+                        gen_op_tadd_ccTV(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADDTV);
+                        dc->cc_op = CC_OP_TADDTV;
+                        break;
+                    case 0x23: /* tsubcctv */
+                        save_state(dc, cpu_cond);
+                        gen_op_tsub_ccTV(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUBTV);
+                        dc->cc_op = CC_OP_TSUBTV;
+                        break;
+                    case 0x24: /* mulscc */
+                        gen_helper_compute_psr();
+                        gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
+                        dc->cc_op = CC_OP_ADD;
+                        break;
+#ifndef TARGET_SPARC64
+                    case 0x25:  /* sll */
+                        if (IS_IMM) { /* immediate */
+                            simm = GET_FIELDs(insn, 20, 31);
+                            tcg_gen_shli_tl(cpu_dst, cpu_src1, simm & 0x1f);
+                        } else { /* register */
+                            tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
+                            tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0);
+                        }
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        break;
+                    case 0x26:  /* srl */
+                        if (IS_IMM) { /* immediate */
+                            simm = GET_FIELDs(insn, 20, 31);
+                            tcg_gen_shri_tl(cpu_dst, cpu_src1, simm & 0x1f);
+                        } else { /* register */
+                            tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
+                            tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0);
+                        }
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        break;
+                    case 0x27:  /* sra */
+                        if (IS_IMM) { /* immediate */
+                            simm = GET_FIELDs(insn, 20, 31);
+                            tcg_gen_sari_tl(cpu_dst, cpu_src1, simm & 0x1f);
+                        } else { /* register */
+                            tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
+                            tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0);
+                        }
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        break;
+#endif
+                    case 0x30:
+                        {
+                            switch(rd) {
+                            case 0: /* wry */
+                                tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
+                                tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff);
+                                break;
+#ifndef TARGET_SPARC64
+                            case 0x01 ... 0x0f: /* undefined in the
+                                                   SPARCv8 manual, nop
+                                                   on the microSPARC
+                                                   II */
+                            case 0x10 ... 0x1f: /* implementation-dependent
+                                                   in the SPARCv8
+                                                   manual, nop on the
+                                                   microSPARC II */
+                                break;
+#else
+                            case 0x2: /* V9 wrccr */
+                                tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+                                gen_helper_wrccr(cpu_dst);
+                                tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
+                                dc->cc_op = CC_OP_FLAGS;
+                                break;
+                            case 0x3: /* V9 wrasi */
+                                tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+                                tcg_gen_andi_tl(cpu_dst, cpu_dst, 0xff);
+                                tcg_gen_trunc_tl_i32(cpu_asi, cpu_dst);
+                                break;
+                            case 0x6: /* V9 wrfprs */
+                                tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+                                tcg_gen_trunc_tl_i32(cpu_fprs, cpu_dst);
+                                save_state(dc, cpu_cond);
+                                gen_op_next_insn();
+                                tcg_gen_exit_tb(0);
+                                dc->is_br = 1;
+                                break;
+                            case 0xf: /* V9 sir, nop if user */
+#if !defined(CONFIG_USER_ONLY)
+                                if (supervisor(dc)) {
+                                    ; // XXX
+                                }
+#endif
+                                break;
+                            case 0x13: /* Graphics Status */
+                                if (gen_trap_ifnofpu(dc, cpu_cond))
+                                    goto jmp_insn;
+                                tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2);
+                                break;
+                            case 0x14: /* Softint set */
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+                                tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
+                                gen_helper_set_softint(cpu_tmp64);
+                                break;
+                            case 0x15: /* Softint clear */
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+                                tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
+                                gen_helper_clear_softint(cpu_tmp64);
+                                break;
+                            case 0x16: /* Softint write */
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+                                tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
+                                gen_helper_write_softint(cpu_tmp64);
+                                break;
+                            case 0x17: /* Tick compare */
+#if !defined(CONFIG_USER_ONLY)
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+#endif
+                                {
+                                    TCGv_ptr r_tickptr;
+
+                                    tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1,
+                                                   cpu_src2);
+                                    r_tickptr = tcg_temp_new_ptr();
+                                    tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                                   offsetof(CPUState, tick));
+                                    gen_helper_tick_set_limit(r_tickptr,
+                                                              cpu_tick_cmpr);
+                                    tcg_temp_free_ptr(r_tickptr);
+                                }
+                                break;
+                            case 0x18: /* System tick */
+#if !defined(CONFIG_USER_ONLY)
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+#endif
+                                {
+                                    TCGv_ptr r_tickptr;
+
+                                    tcg_gen_xor_tl(cpu_dst, cpu_src1,
+                                                   cpu_src2);
+                                    r_tickptr = tcg_temp_new_ptr();
+                                    tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                                   offsetof(CPUState, stick));
+                                    gen_helper_tick_set_count(r_tickptr,
+                                                              cpu_dst);
+                                    tcg_temp_free_ptr(r_tickptr);
+                                }
+                                break;
+                            case 0x19: /* System tick compare */
+#if !defined(CONFIG_USER_ONLY)
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
+#endif
+                                {
+                                    TCGv_ptr r_tickptr;
+
+                                    tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1,
+                                                   cpu_src2);
+                                    r_tickptr = tcg_temp_new_ptr();
+                                    tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                                   offsetof(CPUState, stick));
+                                    gen_helper_tick_set_limit(r_tickptr,
+                                                              cpu_stick_cmpr);
+                                    tcg_temp_free_ptr(r_tickptr);
+                                }
+                                break;
+
+                            case 0x10: /* Performance Control */
+                            case 0x11: /* Performance Instrumentation
+                                          Counter */
+                            case 0x12: /* Dispatch Control */
+#endif
+                            default:
+                                goto illegal_insn;
+                            }
+                        }
+                        break;
+#if !defined(CONFIG_USER_ONLY)
+                    case 0x31: /* wrpsr, V9 saved, restored */
+                        {
+                            if (!supervisor(dc))
+                                goto priv_insn;
+#ifdef TARGET_SPARC64
+                            switch (rd) {
+                            case 0:
+                                gen_helper_saved();
+                                break;
+                            case 1:
+                                gen_helper_restored();
+                                break;
+                            case 2: /* UA2005 allclean */
+                            case 3: /* UA2005 otherw */
+                            case 4: /* UA2005 normalw */
+                            case 5: /* UA2005 invalw */
+                                // XXX
+                            default:
+                                goto illegal_insn;
+                            }
+#else
+                            tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_wrpsr(cpu_dst);
+                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
+                            dc->cc_op = CC_OP_FLAGS;
+                            save_state(dc, cpu_cond);
+                            gen_op_next_insn();
+                            tcg_gen_exit_tb(0);
+                            dc->is_br = 1;
+#endif
+                        }
+                        break;
+                    case 0x32: /* wrwim, V9 wrpr */
+                        {
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
+#ifdef TARGET_SPARC64
+                            switch (rd) {
+                            case 0: // tpc
+                                {
+                                    TCGv_ptr r_tsptr;
+
+                                    r_tsptr = tcg_temp_new_ptr();
+                                    gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                                    tcg_gen_st_tl(cpu_tmp0, r_tsptr,
+                                                  offsetof(trap_state, tpc));
+                                    tcg_temp_free_ptr(r_tsptr);
+                                }
+                                break;
+                            case 1: // tnpc
+                                {
+                                    TCGv_ptr r_tsptr;
+
+                                    r_tsptr = tcg_temp_new_ptr();
+                                    gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                                    tcg_gen_st_tl(cpu_tmp0, r_tsptr,
+                                                  offsetof(trap_state, tnpc));
+                                    tcg_temp_free_ptr(r_tsptr);
+                                }
+                                break;
+                            case 2: // tstate
+                                {
+                                    TCGv_ptr r_tsptr;
+
+                                    r_tsptr = tcg_temp_new_ptr();
+                                    gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                                    tcg_gen_st_tl(cpu_tmp0, r_tsptr,
+                                                  offsetof(trap_state,
+                                                           tstate));
+                                    tcg_temp_free_ptr(r_tsptr);
+                                }
+                                break;
+                            case 3: // tt
+                                {
+                                    TCGv_ptr r_tsptr;
+
+                                    r_tsptr = tcg_temp_new_ptr();
+                                    gen_load_trap_state_at_tl(r_tsptr, cpu_env);
+                                    tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                    tcg_gen_st_i32(cpu_tmp32, r_tsptr,
+                                                   offsetof(trap_state, tt));
+                                    tcg_temp_free_ptr(r_tsptr);
+                                }
+                                break;
+                            case 4: // tick
+                                {
+                                    TCGv_ptr r_tickptr;
+
+                                    r_tickptr = tcg_temp_new_ptr();
+                                    tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                                   offsetof(CPUState, tick));
+                                    gen_helper_tick_set_count(r_tickptr,
+                                                              cpu_tmp0);
+                                    tcg_temp_free_ptr(r_tickptr);
+                                }
+                                break;
+                            case 5: // tba
+                                tcg_gen_mov_tl(cpu_tbr, cpu_tmp0);
+                                break;
+                            case 6: // pstate
+                                {
+                                    TCGv r_tmp = tcg_temp_local_new();
+
+                                    tcg_gen_mov_tl(r_tmp, cpu_tmp0);
+                                    save_state(dc, cpu_cond);
+                                    gen_helper_wrpstate(r_tmp);
+                                    tcg_temp_free(r_tmp);
+                                    dc->npc = DYNAMIC_PC;
+                                }
+                                break;
+                            case 7: // tl
+                                {
+                                    TCGv r_tmp = tcg_temp_local_new();
+
+                                    tcg_gen_mov_tl(r_tmp, cpu_tmp0);
+                                    save_state(dc, cpu_cond);
+                                    tcg_gen_trunc_tl_i32(cpu_tmp32, r_tmp);
+                                    tcg_temp_free(r_tmp);
+                                    tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                                   offsetof(CPUSPARCState, tl));
+                                    dc->npc = DYNAMIC_PC;
+                                }
+                                break;
+                            case 8: // pil
+                                gen_helper_wrpil(cpu_tmp0);
+                                break;
+                            case 9: // cwp
+                                gen_helper_wrcwp(cpu_tmp0);
+                                break;
+                            case 10: // cansave
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState,
+                                                        cansave));
+                                break;
+                            case 11: // canrestore
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState,
+                                                        canrestore));
+                                break;
+                            case 12: // cleanwin
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState,
+                                                        cleanwin));
+                                break;
+                            case 13: // otherwin
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState,
+                                                        otherwin));
+                                break;
+                            case 14: // wstate
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState,
+                                                        wstate));
+                                break;
+                            case 16: // UA2005 gl
+                                CHECK_IU_FEATURE(dc, GL);
+                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
+                                               offsetof(CPUSPARCState, gl));
+                                break;
+                            case 26: // UA2005 strand status
+                                CHECK_IU_FEATURE(dc, HYPV);
+                                if (!hypervisor(dc))
+                                    goto priv_insn;
+                                tcg_gen_mov_tl(cpu_ssr, cpu_tmp0);
+                                break;
+                            default:
+                                goto illegal_insn;
+                            }
+#else
+                            tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                            if (dc->def->nwindows != 32)
+                                tcg_gen_andi_tl(cpu_tmp32, cpu_tmp32,
+                                                (1 << dc->def->nwindows) - 1);
+                            tcg_gen_mov_i32(cpu_wim, cpu_tmp32);
+#endif
+                        }
+                        break;
+                    case 0x33: /* wrtbr, UA2005 wrhpr */
+                        {
+#ifndef TARGET_SPARC64
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            tcg_gen_xor_tl(cpu_tbr, cpu_src1, cpu_src2);
+#else
+                            CHECK_IU_FEATURE(dc, HYPV);
+                            if (!hypervisor(dc))
+                                goto priv_insn;
+                            tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
+                            switch (rd) {
+                            case 0: // hpstate
+                                // XXX gen_op_wrhpstate();
+                                save_state(dc, cpu_cond);
+                                gen_op_next_insn();
+                                tcg_gen_exit_tb(0);
+                                dc->is_br = 1;
+                                break;
+                            case 1: // htstate
+                                // XXX gen_op_wrhtstate();
+                                break;
+                            case 3: // hintp
+                                tcg_gen_mov_tl(cpu_hintp, cpu_tmp0);
+                                break;
+                            case 5: // htba
+                                tcg_gen_mov_tl(cpu_htba, cpu_tmp0);
+                                break;
+                            case 31: // hstick_cmpr
+                                {
+                                    TCGv_ptr r_tickptr;
+
+                                    tcg_gen_mov_tl(cpu_hstick_cmpr, cpu_tmp0);
+                                    r_tickptr = tcg_temp_new_ptr();
+                                    tcg_gen_ld_ptr(r_tickptr, cpu_env,
+                                                   offsetof(CPUState, hstick));
+                                    gen_helper_tick_set_limit(r_tickptr,
+                                                              cpu_hstick_cmpr);
+                                    tcg_temp_free_ptr(r_tickptr);
+                                }
+                                break;
+                            case 6: // hver readonly
+                            default:
+                                goto illegal_insn;
+                            }
+#endif
+                        }
+                        break;
+#endif
+#ifdef TARGET_SPARC64
+                    case 0x2c: /* V9 movcc */
+                        {
+                            int cc = GET_FIELD_SP(insn, 11, 12);
+                            int cond = GET_FIELD_SP(insn, 14, 17);
+                            TCGv r_cond;
+                            int l1;
+
+                            r_cond = tcg_temp_new();
+                            if (insn & (1 << 18)) {
+                                if (cc == 0)
+                                    gen_cond(r_cond, 0, cond, dc);
+                                else if (cc == 2)
+                                    gen_cond(r_cond, 1, cond, dc);
+                                else
+                                    goto illegal_insn;
+                            } else {
+                                gen_fcond(r_cond, cc, cond);
+                            }
+
+                            l1 = gen_new_label();
+
+                            tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
+                            if (IS_IMM) {       /* immediate */
+                                TCGv r_const;
+
+                                simm = GET_FIELD_SPs(insn, 0, 10);
+                                r_const = tcg_const_tl(simm);
+                                gen_movl_TN_reg(rd, r_const);
+                                tcg_temp_free(r_const);
+                            } else {
+                                rs2 = GET_FIELD_SP(insn, 0, 4);
+                                gen_movl_reg_TN(rs2, cpu_tmp0);
+                                gen_movl_TN_reg(rd, cpu_tmp0);
+                            }
+                            gen_set_label(l1);
+                            tcg_temp_free(r_cond);
+                            break;
+                        }
+                    case 0x2d: /* V9 sdivx */
+                        gen_op_sdivx(cpu_dst, cpu_src1, cpu_src2);
+                        gen_movl_TN_reg(rd, cpu_dst);
+                        break;
+                    case 0x2e: /* V9 popc */
+                        {
+                            cpu_src2 = get_src2(insn, cpu_src2);
+                            gen_helper_popc(cpu_dst, cpu_src2);
+                            gen_movl_TN_reg(rd, cpu_dst);
+                        }
+                    case 0x2f: /* V9 movr */
+                        {
+                            int cond = GET_FIELD_SP(insn, 10, 12);
+                            int l1;
+
+                            cpu_src1 = get_src1(insn, cpu_src1);
+
+                            l1 = gen_new_label();
+
+                            tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond],
+                                              cpu_src1, 0, l1);
+                            if (IS_IMM) {       /* immediate */
+                                TCGv r_const;
+
+                                simm = GET_FIELD_SPs(insn, 0, 9);
+                                r_const = tcg_const_tl(simm);
+                                gen_movl_TN_reg(rd, r_const);
+                                tcg_temp_free(r_const);
+                            } else {
+                                rs2 = GET_FIELD_SP(insn, 0, 4);
+                                gen_movl_reg_TN(rs2, cpu_tmp0);
+                                gen_movl_TN_reg(rd, cpu_tmp0);
+                            }
+                            gen_set_label(l1);
+                            break;
+                        }
+#endif
+                    default:
+                        goto illegal_insn;
+                    }
+                }
+            } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */
+#ifdef TARGET_SPARC64
+                int opf = GET_FIELD_SP(insn, 5, 13);
+                rs1 = GET_FIELD(insn, 13, 17);
+                rs2 = GET_FIELD(insn, 27, 31);
+                if (gen_trap_ifnofpu(dc, cpu_cond))
+                    goto jmp_insn;
+
+                switch (opf) {
+                case 0x000: /* VIS I edge8cc */
+                case 0x001: /* VIS II edge8n */
+                case 0x002: /* VIS I edge8lcc */
+                case 0x003: /* VIS II edge8ln */
+                case 0x004: /* VIS I edge16cc */
+                case 0x005: /* VIS II edge16n */
+                case 0x006: /* VIS I edge16lcc */
+                case 0x007: /* VIS II edge16ln */
+                case 0x008: /* VIS I edge32cc */
+                case 0x009: /* VIS II edge32n */
+                case 0x00a: /* VIS I edge32lcc */
+                case 0x00b: /* VIS II edge32ln */
+                    // XXX
+                    goto illegal_insn;
+                case 0x010: /* VIS I array8 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x012: /* VIS I array16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    tcg_gen_shli_i64(cpu_dst, cpu_dst, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x014: /* VIS I array32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+                    tcg_gen_shli_i64(cpu_dst, cpu_dst, 2);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x018: /* VIS I alignaddr */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x019: /* VIS II bmask */
+                case 0x01a: /* VIS I alignaddrl */
+                    // XXX
+                    goto illegal_insn;
+                case 0x020: /* VIS I fcmple16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmple16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x022: /* VIS I fcmpne16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpne16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x024: /* VIS I fcmple32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmple32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x026: /* VIS I fcmpne32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpne32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x028: /* VIS I fcmpgt16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpgt16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x02a: /* VIS I fcmpeq16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpeq16(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x02c: /* VIS I fcmpgt32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpgt32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x02e: /* VIS I fcmpeq32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fcmpeq32(cpu_dst);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x031: /* VIS I fmul8x16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmul8x16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x033: /* VIS I fmul8x16au */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmul8x16au();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x035: /* VIS I fmul8x16al */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmul8x16al();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x036: /* VIS I fmul8sux16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmul8sux16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x037: /* VIS I fmul8ulx16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmul8ulx16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x038: /* VIS I fmuld8sux16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmuld8sux16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x039: /* VIS I fmuld8ulx16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fmuld8ulx16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x03a: /* VIS I fpack32 */
+                case 0x03b: /* VIS I fpack16 */
+                case 0x03d: /* VIS I fpackfix */
+                case 0x03e: /* VIS I pdist */
+                    // XXX
+                    goto illegal_insn;
+                case 0x048: /* VIS I faligndata */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_faligndata();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x04b: /* VIS I fpmerge */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fpmerge();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x04c: /* VIS II bshuffle */
+                    // XXX
+                    goto illegal_insn;
+                case 0x04d: /* VIS I fexpand */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fexpand();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x050: /* VIS I fpadd16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fpadd16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x051: /* VIS I fpadd16s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_helper_fpadd16s(cpu_fpr[rd],
+                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x052: /* VIS I fpadd32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fpadd32();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x053: /* VIS I fpadd32s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_helper_fpadd32s(cpu_fpr[rd],
+                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x054: /* VIS I fpsub16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fpsub16();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x055: /* VIS I fpsub16s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_helper_fpsub16s(cpu_fpr[rd],
+                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x056: /* VIS I fpsub32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
+                    gen_helper_fpsub32();
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x057: /* VIS I fpsub32s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_helper_fpsub32s(cpu_fpr[rd],
+                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x060: /* VIS I fzero */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], 0);
+                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], 0);
+                    break;
+                case 0x061: /* VIS I fzeros */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_movi_i32(cpu_fpr[rd], 0);
+                    break;
+                case 0x062: /* VIS I fnor */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
+                                    cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x063: /* VIS I fnors */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_nor_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x064: /* VIS I fandnot2 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
+                                     cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
+                                     cpu_fpr[DFPREG(rs1) + 1],
+                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x065: /* VIS I fandnot2s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x066: /* VIS I fnot2 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x067: /* VIS I fnot2s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    break;
+                case 0x068: /* VIS I fandnot1 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
+                                     cpu_fpr[DFPREG(rs1)]);
+                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
+                                     cpu_fpr[DFPREG(rs2) + 1],
+                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    break;
+                case 0x069: /* VIS I fandnot1s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    break;
+                case 0x06a: /* VIS I fnot1 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
+                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    break;
+                case 0x06b: /* VIS I fnot1s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    break;
+                case 0x06c: /* VIS I fxor */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
+                                    cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x06d: /* VIS I fxors */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x06e: /* VIS I fnand */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1)],
+                                     cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[DFPREG(rs1) + 1],
+                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x06f: /* VIS I fnands */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_nand_i32(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x070: /* VIS I fand */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
+                                    cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x071: /* VIS I fands */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_and_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x072: /* VIS I fxnor */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2)], -1);
+                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_tmp32,
+                                    cpu_fpr[DFPREG(rs1)]);
+                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2) + 1], -1);
+                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], cpu_tmp32,
+                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    break;
+                case 0x073: /* VIS I fxnors */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[rs2], -1);
+                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_tmp32, cpu_fpr[rs1]);
+                    break;
+                case 0x074: /* VIS I fsrc1 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
+                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    break;
+                case 0x075: /* VIS I fsrc1s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    break;
+                case 0x076: /* VIS I fornot2 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
+                                    cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x077: /* VIS I fornot2s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x078: /* VIS I fsrc2 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_op_load_fpr_DT0(DFPREG(rs2));
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                case 0x079: /* VIS I fsrc2s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    break;
+                case 0x07a: /* VIS I fornot1 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
+                                    cpu_fpr[DFPREG(rs1)]);
+                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
+                                    cpu_fpr[DFPREG(rs2) + 1],
+                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    break;
+                case 0x07b: /* VIS I fornot1s */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    break;
+                case 0x07c: /* VIS I for */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
+                                   cpu_fpr[DFPREG(rs2)]);
+                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd) + 1],
+                                   cpu_fpr[DFPREG(rs1) + 1],
+                                   cpu_fpr[DFPREG(rs2) + 1]);
+                    break;
+                case 0x07d: /* VIS I fors */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_or_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    break;
+                case 0x07e: /* VIS I fone */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], -1);
+                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], -1);
+                    break;
+                case 0x07f: /* VIS I fones */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    tcg_gen_movi_i32(cpu_fpr[rd], -1);
+                    break;
+                case 0x080: /* VIS I shutdown */
+                case 0x081: /* VIS II siam */
+                    // XXX
+                    goto illegal_insn;
+                default:
+                    goto illegal_insn;
+                }
+#else
+                goto ncp_insn;
+#endif
+            } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */
+#ifdef TARGET_SPARC64
+                goto illegal_insn;
+#else
+                goto ncp_insn;
+#endif
+#ifdef TARGET_SPARC64
+            } else if (xop == 0x39) { /* V9 return */
+                TCGv_i32 r_const;
+
+                save_state(dc, cpu_cond);
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {   /* immediate */
+                    simm = GET_FIELDs(insn, 19, 31);
+                    tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
+                } else {                /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    if (rs2) {
+                        gen_movl_reg_TN(rs2, cpu_src2);
+                        tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                    } else
+                        tcg_gen_mov_tl(cpu_dst, cpu_src1);
+                }
+                gen_helper_restore();
+                gen_mov_pc_npc(dc, cpu_cond);
+                r_const = tcg_const_i32(3);
+                gen_helper_check_align(cpu_dst, r_const);
+                tcg_temp_free_i32(r_const);
+                tcg_gen_mov_tl(cpu_npc, cpu_dst);
+                dc->npc = DYNAMIC_PC;
+                goto jmp_insn;
+#endif
+            } else {
+                cpu_src1 = get_src1(insn, cpu_src1);
+                if (IS_IMM) {   /* immediate */
+                    simm = GET_FIELDs(insn, 19, 31);
+                    tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
+                } else {                /* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    if (rs2) {
+                        gen_movl_reg_TN(rs2, cpu_src2);
+                        tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                    } else
+                        tcg_gen_mov_tl(cpu_dst, cpu_src1);
+                }
+                switch (xop) {
+                case 0x38:      /* jmpl */
+                    {
+                        TCGv r_pc;
+                        TCGv_i32 r_const;
+
+                        r_pc = tcg_const_tl(dc->pc);
+                        gen_movl_TN_reg(rd, r_pc);
+                        tcg_temp_free(r_pc);
+                        gen_mov_pc_npc(dc, cpu_cond);
+                        r_const = tcg_const_i32(3);
+                        gen_helper_check_align(cpu_dst, r_const);
+                        tcg_temp_free_i32(r_const);
+                        tcg_gen_mov_tl(cpu_npc, cpu_dst);
+                        dc->npc = DYNAMIC_PC;
+                    }
+                    goto jmp_insn;
+#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
+                case 0x39:      /* rett, V9 return */
+                    {
+                        TCGv_i32 r_const;
+
+                        if (!supervisor(dc))
+                            goto priv_insn;
+                        gen_mov_pc_npc(dc, cpu_cond);
+                        r_const = tcg_const_i32(3);
+                        gen_helper_check_align(cpu_dst, r_const);
+                        tcg_temp_free_i32(r_const);
+                        tcg_gen_mov_tl(cpu_npc, cpu_dst);
+                        dc->npc = DYNAMIC_PC;
+                        gen_helper_rett();
+                    }
+                    goto jmp_insn;
+#endif
+                case 0x3b: /* flush */
+                    if (!((dc)->def->features & CPU_FEATURE_FLUSH))
+                        goto unimp_flush;
+                    /* nop */
+                    break;
+                case 0x3c:      /* save */
+                    save_state(dc, cpu_cond);
+                    gen_helper_save();
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x3d:      /* restore */
+                    save_state(dc, cpu_cond);
+                    gen_helper_restore();
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+#if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
+                case 0x3e:      /* V9 done/retry */
+                    {
+                        switch (rd) {
+                        case 0:
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            dc->npc = DYNAMIC_PC;
+                            dc->pc = DYNAMIC_PC;
+                            gen_helper_done();
+                            goto jmp_insn;
+                        case 1:
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            dc->npc = DYNAMIC_PC;
+                            dc->pc = DYNAMIC_PC;
+                            gen_helper_retry();
+                            goto jmp_insn;
+                        default:
+                            goto illegal_insn;
+                        }
+                    }
+                    break;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+            }
+            break;
+        }
+        break;
+    case 3:                     /* load/store instructions */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 12);
+
+            /* flush pending conditional evaluations before exposing
+               cpu state */
+            if (dc->cc_op != CC_OP_FLAGS) {
+                dc->cc_op = CC_OP_FLAGS;
+                gen_helper_compute_psr();
+            }
+            cpu_src1 = get_src1(insn, cpu_src1);
+            if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa
+                rs2 = GET_FIELD(insn, 27, 31);
+                gen_movl_reg_TN(rs2, cpu_src2);
+                tcg_gen_mov_tl(cpu_addr, cpu_src1);
+            } else if (IS_IMM) {     /* immediate */
+                simm = GET_FIELDs(insn, 19, 31);
+                tcg_gen_addi_tl(cpu_addr, cpu_src1, simm);
+            } else {            /* register */
+                rs2 = GET_FIELD(insn, 27, 31);
+                if (rs2 != 0) {
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    tcg_gen_add_tl(cpu_addr, cpu_src1, cpu_src2);
+                } else
+                    tcg_gen_mov_tl(cpu_addr, cpu_src1);
+            }
+            if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) ||
+                (xop > 0x17 && xop <= 0x1d ) ||
+                (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) {
+                switch (xop) {
+                case 0x0:       /* ld, V9 lduw, load unsigned word */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld32u(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x1:       /* ldub, load unsigned byte */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x2:       /* lduh, load unsigned halfword */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld16u(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x3:       /* ldd, load double word */
+                    if (rd & 1)
+                        goto illegal_insn;
+                    else {
+                        TCGv_i32 r_const;
+
+                        save_state(dc, cpu_cond);
+                        r_const = tcg_const_i32(7);
+                        gen_helper_check_align(cpu_addr, r_const); // XXX remove
+                        tcg_temp_free_i32(r_const);
+                        gen_address_mask(dc, cpu_addr);
+                        tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
+                        tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64);
+                        tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL);
+                        gen_movl_TN_reg(rd + 1, cpu_tmp0);
+                        tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32);
+                        tcg_gen_trunc_i64_tl(cpu_val, cpu_tmp64);
+                        tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL);
+                    }
+                    break;
+                case 0x9:       /* ldsb, load signed byte */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0xa:       /* ldsh, load signed halfword */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld16s(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0xd:       /* ldstub -- XXX: should be atomically */
+                    {
+                        TCGv r_const;
+
+                        gen_address_mask(dc, cpu_addr);
+                        tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx);
+                        r_const = tcg_const_tl(0xff);
+                        tcg_gen_qemu_st8(r_const, cpu_addr, dc->mem_idx);
+                        tcg_temp_free(r_const);
+                    }
+                    break;
+                case 0x0f:      /* swap, swap register with memory. Also
+                                   atomically */
+                    CHECK_IU_FEATURE(dc, SWAP);
+                    gen_movl_reg_TN(rd, cpu_val);
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
+                    tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx);
+                    tcg_gen_mov_tl(cpu_val, cpu_tmp0);
+                    break;
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+                case 0x10:      /* lda, V9 lduwa, load word alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0);
+                    break;
+                case 0x11:      /* lduba, load unsigned byte alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0);
+                    break;
+                case 0x12:      /* lduha, load unsigned halfword alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0);
+                    break;
+                case 0x13:      /* ldda, load double word alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    if (rd & 1)
+                        goto illegal_insn;
+                    save_state(dc, cpu_cond);
+                    gen_ldda_asi(cpu_val, cpu_addr, insn, rd);
+                    goto skip_move;
+                case 0x19:      /* ldsba, load signed byte alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1);
+                    break;
+                case 0x1a:      /* ldsha, load signed halfword alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1);
+                    break;
+                case 0x1d:      /* ldstuba -- XXX: should be atomically */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_ldstub_asi(cpu_val, cpu_addr, insn);
+                    break;
+                case 0x1f:      /* swapa, swap reg with alt. memory. Also
+                                   atomically */
+                    CHECK_IU_FEATURE(dc, SWAP);
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_movl_reg_TN(rd, cpu_val);
+                    gen_swap_asi(cpu_val, cpu_addr, insn);
+                    break;
+
+#ifndef TARGET_SPARC64
+                case 0x30: /* ldc */
+                case 0x31: /* ldcsr */
+                case 0x33: /* lddc */
+                    goto ncp_insn;
+#endif
+#endif
+#ifdef TARGET_SPARC64
+                case 0x08: /* V9 ldsw */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld32s(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x0b: /* V9 ldx */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x18: /* V9 ldswa */
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1);
+                    break;
+                case 0x1b: /* V9 ldxa */
+                    save_state(dc, cpu_cond);
+                    gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0);
+                    break;
+                case 0x2d: /* V9 prefetch, no effect */
+                    goto skip_move;
+                case 0x30: /* V9 ldfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
+                    save_state(dc, cpu_cond);
+                    gen_ldf_asi(cpu_addr, insn, 4, rd);
+                    goto skip_move;
+                case 0x33: /* V9 lddfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
+                    save_state(dc, cpu_cond);
+                    gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd));
+                    goto skip_move;
+                case 0x3d: /* V9 prefetcha, no effect */
+                    goto skip_move;
+                case 0x32: /* V9 ldqfa */
+                    CHECK_FPU_FEATURE(dc, FLOAT128);
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
+                    save_state(dc, cpu_cond);
+                    gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd));
+                    goto skip_move;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+                gen_movl_TN_reg(rd, cpu_val);
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+            skip_move: ;
+#endif
+            } else if (xop >= 0x20 && xop < 0x24) {
+                if (gen_trap_ifnofpu(dc, cpu_cond))
+                    goto jmp_insn;
+                save_state(dc, cpu_cond);
+                switch (xop) {
+                case 0x20:      /* ldf, load fpreg */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
+                    tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0);
+                    break;
+                case 0x21:      /* ldfsr, V9 ldxfsr */
+#ifdef TARGET_SPARC64
+                    gen_address_mask(dc, cpu_addr);
+                    if (rd == 1) {
+                        tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
+                        gen_helper_ldxfsr(cpu_tmp64);
+                    } else {
+                        tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
+                        tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
+                        gen_helper_ldfsr(cpu_tmp32);
+                    }
+#else
+                    {
+                        tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
+                        gen_helper_ldfsr(cpu_tmp32);
+                    }
+#endif
+                    break;
+                case 0x22:      /* ldqf, load quad fpreg */
+                    {
+                        TCGv_i32 r_const;
+
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        r_const = tcg_const_i32(dc->mem_idx);
+                        gen_address_mask(dc, cpu_addr);
+                        gen_helper_ldqf(cpu_addr, r_const);
+                        tcg_temp_free_i32(r_const);
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                    }
+                    break;
+                case 0x23:      /* lddf, load double fpreg */
+                    {
+                        TCGv_i32 r_const;
+
+                        r_const = tcg_const_i32(dc->mem_idx);
+                        gen_address_mask(dc, cpu_addr);
+                        gen_helper_lddf(cpu_addr, r_const);
+                        tcg_temp_free_i32(r_const);
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                    }
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) ||
+                       xop == 0xe || xop == 0x1e) {
+                gen_movl_reg_TN(rd, cpu_val);
+                switch (xop) {
+                case 0x4: /* st, store word */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x5: /* stb, store byte */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_st8(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x6: /* sth, store halfword */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_st16(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x7: /* std, store double word */
+                    if (rd & 1)
+                        goto illegal_insn;
+                    else {
+                        TCGv_i32 r_const;
+
+                        save_state(dc, cpu_cond);
+                        gen_address_mask(dc, cpu_addr);
+                        r_const = tcg_const_i32(7);
+                        gen_helper_check_align(cpu_addr, r_const); // XXX remove
+                        tcg_temp_free_i32(r_const);
+                        gen_movl_reg_TN(rd + 1, cpu_tmp0);
+                        tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, cpu_val);
+                        tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx);
+                    }
+                    break;
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+                case 0x14: /* sta, V9 stwa, store word alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_st_asi(cpu_val, cpu_addr, insn, 4);
+                    dc->npc = DYNAMIC_PC;
+                    break;
+                case 0x15: /* stba, store byte alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_st_asi(cpu_val, cpu_addr, insn, 1);
+                    dc->npc = DYNAMIC_PC;
+                    break;
+                case 0x16: /* stha, store halfword alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    save_state(dc, cpu_cond);
+                    gen_st_asi(cpu_val, cpu_addr, insn, 2);
+                    dc->npc = DYNAMIC_PC;
+                    break;
+                case 0x17: /* stda, store double word alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    if (rd & 1)
+                        goto illegal_insn;
+                    else {
+                        save_state(dc, cpu_cond);
+                        gen_stda_asi(cpu_val, cpu_addr, insn, rd);
+                    }
+                    break;
+#endif
+#ifdef TARGET_SPARC64
+                case 0x0e: /* V9 stx */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x1e: /* V9 stxa */
+                    save_state(dc, cpu_cond);
+                    gen_st_asi(cpu_val, cpu_addr, insn, 8);
+                    dc->npc = DYNAMIC_PC;
+                    break;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop > 0x23 && xop < 0x28) {
+                if (gen_trap_ifnofpu(dc, cpu_cond))
+                    goto jmp_insn;
+                save_state(dc, cpu_cond);
+                switch (xop) {
+                case 0x24: /* stf, store fpreg */
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_fpr[rd]);
+                    tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx);
+                    break;
+                case 0x25: /* stfsr, V9 stxfsr */
+#ifdef TARGET_SPARC64
+                    gen_address_mask(dc, cpu_addr);
+                    tcg_gen_ld_i64(cpu_tmp64, cpu_env, offsetof(CPUState, fsr));
+                    if (rd == 1)
+                        tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx);
+                    else
+                        tcg_gen_qemu_st32(cpu_tmp64, cpu_addr, dc->mem_idx);
+#else
+                    tcg_gen_ld_i32(cpu_tmp32, cpu_env, offsetof(CPUState, fsr));
+                    tcg_gen_qemu_st32(cpu_tmp32, cpu_addr, dc->mem_idx);
+#endif
+                    break;
+                case 0x26:
+#ifdef TARGET_SPARC64
+                    /* V9 stqf, store quad fpreg */
+                    {
+                        TCGv_i32 r_const;
+
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        gen_op_load_fpr_QT0(QFPREG(rd));
+                        r_const = tcg_const_i32(dc->mem_idx);
+                        gen_address_mask(dc, cpu_addr);
+                        gen_helper_stqf(cpu_addr, r_const);
+                        tcg_temp_free_i32(r_const);
+                    }
+                    break;
+#else /* !TARGET_SPARC64 */
+                    /* stdfq, store floating point queue */
+#if defined(CONFIG_USER_ONLY)
+                    goto illegal_insn;
+#else
+                    if (!supervisor(dc))
+                        goto priv_insn;
+                    if (gen_trap_ifnofpu(dc, cpu_cond))
+                        goto jmp_insn;
+                    goto nfq_insn;
+#endif
+#endif
+                case 0x27: /* stdf, store double fpreg */
+                    {
+                        TCGv_i32 r_const;
+
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        r_const = tcg_const_i32(dc->mem_idx);
+                        gen_address_mask(dc, cpu_addr);
+                        gen_helper_stdf(cpu_addr, r_const);
+                        tcg_temp_free_i32(r_const);
+                    }
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop > 0x33 && xop < 0x3f) {
+                save_state(dc, cpu_cond);
+                switch (xop) {
+#ifdef TARGET_SPARC64
+                case 0x34: /* V9 stfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
+                    gen_stf_asi(cpu_addr, insn, 4, rd);
+                    break;
+                case 0x36: /* V9 stqfa */
+                    {
+                        TCGv_i32 r_const;
+
+                        CHECK_FPU_FEATURE(dc, FLOAT128);
+                        if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                            goto jmp_insn;
+                        }
+                        r_const = tcg_const_i32(7);
+                        gen_helper_check_align(cpu_addr, r_const);
+                        tcg_temp_free_i32(r_const);
+                        gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd));
+                    }
+                    break;
+                case 0x37: /* V9 stdfa */
+                    if (gen_trap_ifnofpu(dc, cpu_cond)) {
+                        goto jmp_insn;
+                    }
+                    gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd));
+                    break;
+                case 0x3c: /* V9 casa */
+                    gen_cas_asi(cpu_val, cpu_addr, cpu_src2, insn, rd);
+                    gen_movl_TN_reg(rd, cpu_val);
+                    break;
+                case 0x3e: /* V9 casxa */
+                    gen_casx_asi(cpu_val, cpu_addr, cpu_src2, insn, rd);
+                    gen_movl_TN_reg(rd, cpu_val);
+                    break;
+#else
+                case 0x34: /* stc */
+                case 0x35: /* stcsr */
+                case 0x36: /* stdcq */
+                case 0x37: /* stdc */
+                    goto ncp_insn;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+            } else
+                goto illegal_insn;
+        }
+        break;
+    }
+    /* default case for non jump instructions */
+    if (dc->npc == DYNAMIC_PC) {
+        dc->pc = DYNAMIC_PC;
+        gen_op_next_insn();
+    } else if (dc->npc == JUMP_PC) {
+        /* we can do a static jump */
+        gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
+        dc->is_br = 1;
+    } else {
+        dc->pc = dc->npc;
+        dc->npc = dc->npc + 4;
+    }
+ jmp_insn:
+    goto egress;
+ illegal_insn:
+    {
+        TCGv_i32 r_const;
+
+        save_state(dc, cpu_cond);
+        r_const = tcg_const_i32(TT_ILL_INSN);
+        gen_helper_raise_exception(r_const);
+        tcg_temp_free_i32(r_const);
+        dc->is_br = 1;
+    }
+    goto egress;
+ unimp_flush:
+    {
+        TCGv_i32 r_const;
+
+        save_state(dc, cpu_cond);
+        r_const = tcg_const_i32(TT_UNIMP_FLUSH);
+        gen_helper_raise_exception(r_const);
+        tcg_temp_free_i32(r_const);
+        dc->is_br = 1;
+    }
+    goto egress;
+#if !defined(CONFIG_USER_ONLY)
+ priv_insn:
+    {
+        TCGv_i32 r_const;
+
+        save_state(dc, cpu_cond);
+        r_const = tcg_const_i32(TT_PRIV_INSN);
+        gen_helper_raise_exception(r_const);
+        tcg_temp_free_i32(r_const);
+        dc->is_br = 1;
+    }
+    goto egress;
+#endif
+ nfpu_insn:
+    save_state(dc, cpu_cond);
+    gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
+    dc->is_br = 1;
+    goto egress;
+#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
+ nfq_insn:
+    save_state(dc, cpu_cond);
+    gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
+    dc->is_br = 1;
+    goto egress;
+#endif
+#ifndef TARGET_SPARC64
+ ncp_insn:
+    {
+        TCGv r_const;
+
+        save_state(dc, cpu_cond);
+        r_const = tcg_const_i32(TT_NCP_INSN);
+        gen_helper_raise_exception(r_const);
+        tcg_temp_free(r_const);
+        dc->is_br = 1;
+    }
+    goto egress;
+#endif
+ egress:
+    tcg_temp_free(cpu_tmp1);
+    tcg_temp_free(cpu_tmp2);
+}
+
+static inline void gen_intermediate_code_internal(TranslationBlock * tb,
+                                                  int spc, CPUSPARCState *env)
+{
+    target_ulong pc_start, last_pc;
+    uint16_t *gen_opc_end;
+    DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
+    int j, lj = -1;
+    int num_insns;
+    int max_insns;
+
+    memset(dc, 0, sizeof(DisasContext));
+    dc->tb = tb;
+    pc_start = tb->pc;
+    dc->pc = pc_start;
+    last_pc = dc->pc;
+    dc->npc = (target_ulong) tb->cs_base;
+    dc->cc_op = CC_OP_DYNAMIC;
+    dc->mem_idx = cpu_mmu_index(env);
+    dc->def = env->def;
+    dc->fpu_enabled = tb_fpu_enabled(tb->flags);
+    dc->address_mask_32bit = tb_am_enabled(tb->flags);
+    dc->singlestep = (env->singlestep_enabled || singlestep);
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    cpu_tmp0 = tcg_temp_new();
+    cpu_tmp32 = tcg_temp_new_i32();
+    cpu_tmp64 = tcg_temp_new_i64();
+
+    cpu_dst = tcg_temp_local_new();
+
+    // loads and stores
+    cpu_val = tcg_temp_local_new();
+    cpu_addr = tcg_temp_local_new();
+
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+    gen_icount_start();
+    do {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
+                    if (dc->pc != pc_start)
+                        save_state(dc, cpu_cond);
+                    gen_helper_debug();
+                    tcg_gen_exit_tb(0);
+                    dc->is_br = 1;
+                    goto exit_gen_loop;
+                }
+            }
+        }
+        if (spc) {
+            qemu_log("Search PC...\n");
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+                gen_opc_pc[lj] = dc->pc;
+                gen_opc_npc[lj] = dc->npc;
+                gen_opc_instr_start[lj] = 1;
+                gen_opc_icount[lj] = num_insns;
+            }
+        }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
+        last_pc = dc->pc;
+        disas_sparc_insn(dc);
+        num_insns++;
+
+        if (dc->is_br)
+            break;
+        /* if the next PC is different, we abort now */
+        if (dc->pc != (last_pc + 4))
+            break;
+        /* if we reach a page boundary, we stop generation so that the
+           PC of a TT_TFAULT exception is always in the right page */
+        if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0)
+            break;
+        /* if single step mode, we generate only one instruction and
+           generate an exception */
+        if (dc->singlestep) {
+            break;
+        }
+    } while ((gen_opc_ptr < gen_opc_end) &&
+             (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) &&
+             num_insns < max_insns);
+
+ exit_gen_loop:
+    tcg_temp_free(cpu_addr);
+    tcg_temp_free(cpu_val);
+    tcg_temp_free(cpu_dst);
+    tcg_temp_free_i64(cpu_tmp64);
+    tcg_temp_free_i32(cpu_tmp32);
+    tcg_temp_free(cpu_tmp0);
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (!dc->is_br) {
+        if (dc->pc != DYNAMIC_PC &&
+            (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
+            /* static PC and NPC: we can use direct chaining */
+            gen_goto_tb(dc, 0, dc->pc, dc->npc);
+        } else {
+            if (dc->pc != DYNAMIC_PC)
+                tcg_gen_movi_tl(cpu_pc, dc->pc);
+            save_npc(dc, cpu_cond);
+            tcg_gen_exit_tb(0);
+        }
+    }
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (spc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+#if 0
+        log_page_dump();
+#endif
+        gen_opc_jump_pc[0] = dc->jump_pc[0];
+        gen_opc_jump_pc[1] = dc->jump_pc[1];
+    } else {
+        tb->size = last_pc + 4 - pc_start;
+        tb->icount = num_insns;
+    }
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("--------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, last_pc + 4 - pc_start, 0);
+        qemu_log("\n");
+    }
+#endif
+}
+
+void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
+{
+    gen_intermediate_code_internal(tb, 0, env);
+}
+
+void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
+{
+    gen_intermediate_code_internal(tb, 1, env);
+}
+
+void gen_intermediate_code_init(CPUSPARCState *env)
+{
+    unsigned int i;
+    static int inited;
+    static const char * const gregnames[8] = {
+        NULL, // g0 not used
+        "g1",
+        "g2",
+        "g3",
+        "g4",
+        "g5",
+        "g6",
+        "g7",
+    };
+    static const char * const fregnames[64] = {
+        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+        "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+        "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+        "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+        "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
+        "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
+        "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
+        "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
+    };
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+
+        cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+        cpu_regwptr = tcg_global_mem_new_ptr(TCG_AREG0,
+                                             offsetof(CPUState, regwptr),
+                                             "regwptr");
+#ifdef TARGET_SPARC64
+        cpu_xcc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, xcc),
+                                         "xcc");
+        cpu_asi = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, asi),
+                                         "asi");
+        cpu_fprs = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, fprs),
+                                          "fprs");
+        cpu_gsr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, gsr),
+                                     "gsr");
+        cpu_tick_cmpr = tcg_global_mem_new(TCG_AREG0,
+                                           offsetof(CPUState, tick_cmpr),
+                                           "tick_cmpr");
+        cpu_stick_cmpr = tcg_global_mem_new(TCG_AREG0,
+                                            offsetof(CPUState, stick_cmpr),
+                                            "stick_cmpr");
+        cpu_hstick_cmpr = tcg_global_mem_new(TCG_AREG0,
+                                             offsetof(CPUState, hstick_cmpr),
+                                             "hstick_cmpr");
+        cpu_hintp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, hintp),
+                                       "hintp");
+        cpu_htba = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, htba),
+                                      "htba");
+        cpu_hver = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, hver),
+                                      "hver");
+        cpu_ssr = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, ssr), "ssr");
+        cpu_ver = tcg_global_mem_new(TCG_AREG0,
+                                     offsetof(CPUState, version), "ver");
+        cpu_softint = tcg_global_mem_new_i32(TCG_AREG0,
+                                             offsetof(CPUState, softint),
+                                             "softint");
+#else
+        cpu_wim = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, wim),
+                                     "wim");
+#endif
+        cpu_cond = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cond),
+                                      "cond");
+        cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_src),
+                                        "cc_src");
+        cpu_cc_src2 = tcg_global_mem_new(TCG_AREG0,
+                                         offsetof(CPUState, cc_src2),
+                                         "cc_src2");
+        cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_dst),
+                                        "cc_dst");
+        cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc_op),
+                                           "cc_op");
+        cpu_psr = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, psr),
+                                         "psr");
+        cpu_fsr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, fsr),
+                                     "fsr");
+        cpu_pc = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, pc),
+                                    "pc");
+        cpu_npc = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, npc),
+                                     "npc");
+        cpu_y = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, y), "y");
+#ifndef CONFIG_USER_ONLY
+        cpu_tbr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, tbr),
+                                     "tbr");
+#endif
+        for (i = 1; i < 8; i++)
+            cpu_gregs[i] = tcg_global_mem_new(TCG_AREG0,
+                                              offsetof(CPUState, gregs[i]),
+                                              gregnames[i]);
+        for (i = 0; i < TARGET_FPREGS; i++)
+            cpu_fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                                offsetof(CPUState, fpr[i]),
+                                                fregnames[i]);
+
+        /* register helpers */
+
+#define GEN_HELPER 2
+#include "helper.h"
+    }
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    target_ulong npc;
+    env->pc = gen_opc_pc[pc_pos];
+    npc = gen_opc_npc[pc_pos];
+    if (npc == 1) {
+        /* dynamic NPC: already stored */
+    } else if (npc == 2) {
+        /* jump PC: use 'cond' and the jump targets of the translation */
+        if (env->cond) {
+            env->npc = gen_opc_jump_pc[0];
+        } else {
+            env->npc = gen_opc_jump_pc[1];
+        }
+    } else {
+        env->npc = npc;
+    }
+
+    /* flush pending conditional evaluations before exposing cpu state */
+    if (CC_OP != CC_OP_FLAGS) {
+        helper_compute_psr();
+    }
+}
diff --git a/qemu-0.15.x/target-unicore32/cpu.h b/qemu-0.15.x/target-unicore32/cpu.h
new file mode 100644
index 0000000..9817607
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/cpu.h
@@ -0,0 +1,188 @@
+/*
+ * UniCore32 virtual CPU header
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __CPU_UC32_H__
+#define __CPU_UC32_H__
+
+#define TARGET_LONG_BITS                32
+#define TARGET_PAGE_BITS                12
+
+#define TARGET_PHYS_ADDR_SPACE_BITS     32
+#define TARGET_VIRT_ADDR_SPACE_BITS     32
+
+#define ELF_MACHINE             EM_UNICORE32
+
+#define CPUState                struct CPUState_UniCore32
+
+#include "cpu-defs.h"
+#include "softfloat.h"
+
+#define NB_MMU_MODES            2
+
+typedef struct CPUState_UniCore32 {
+    /* Regs for current mode.  */
+    uint32_t regs[32];
+    /* Frequently accessed ASR bits are stored separately for efficiently.
+       This contains all the other bits.  Use asr_{read,write} to access
+       the whole ASR.  */
+    uint32_t uncached_asr;
+    uint32_t bsr;
+
+    /* Banked registers.  */
+    uint32_t banked_bsr[6];
+    uint32_t banked_r29[6];
+    uint32_t banked_r30[6];
+
+    /* asr flag cache for faster execution */
+    uint32_t CF; /* 0 or 1 */
+    uint32_t VF; /* V is the bit 31. All other bits are undefined */
+    uint32_t NF; /* N is bit 31. All other bits are undefined.  */
+    uint32_t ZF; /* Z set if zero.  */
+
+    /* System control coprocessor (cp0) */
+    struct {
+        uint32_t c0_cpuid;
+        uint32_t c0_cachetype;
+        uint32_t c1_sys; /* System control register.  */
+        uint32_t c2_base; /* MMU translation table base.  */
+        uint32_t c3_faultstatus; /* Fault status registers.  */
+        uint32_t c4_faultaddr; /* Fault address registers.  */
+        uint32_t c5_cacheop; /* Cache operation registers.  */
+        uint32_t c6_tlbop; /* TLB operation registers. */
+    } cp0;
+
+    /* UniCore-F64 coprocessor state.  */
+    struct {
+        float64 regs[16];
+        uint32_t xregs[32];
+        float_status fp_status;
+    } ucf64;
+
+    CPU_COMMON
+
+    /* Internal CPU feature flags.  */
+    uint32_t features;
+
+} CPUState_UniCore32;
+
+#define ASR_M                   (0x1f)
+#define ASR_MODE_USER           (0x10)
+#define ASR_MODE_INTR           (0x12)
+#define ASR_MODE_PRIV           (0x13)
+#define ASR_MODE_TRAP           (0x17)
+#define ASR_MODE_EXTN           (0x1b)
+#define ASR_MODE_SUSR           (0x1f)
+#define ASR_I                   (1 << 7)
+#define ASR_V                   (1 << 28)
+#define ASR_C                   (1 << 29)
+#define ASR_Z                   (1 << 30)
+#define ASR_N                   (1 << 31)
+#define ASR_NZCV                (ASR_N | ASR_Z | ASR_C | ASR_V)
+#define ASR_RESERVED            (~(ASR_M | ASR_I | ASR_NZCV))
+
+#define UC32_EXCP_PRIV          (ASR_MODE_PRIV)
+#define UC32_EXCP_TRAP          (ASR_MODE_TRAP)
+
+/* Return the current ASR value.  */
+target_ulong cpu_asr_read(CPUState *env1);
+/* Set the ASR.  Note that some bits of mask must be all-set or all-clear.  */
+void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask);
+
+/* UniCore-F64 system registers.  */
+#define UC32_UCF64_FPSCR                (31)
+#define UCF64_FPSCR_MASK                (0x27ffffff)
+#define UCF64_FPSCR_RND_MASK            (0x7)
+#define UCF64_FPSCR_RND(r)              (((r) >>  0) & UCF64_FPSCR_RND_MASK)
+#define UCF64_FPSCR_TRAPEN_MASK         (0x7f)
+#define UCF64_FPSCR_TRAPEN(r)           (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK)
+#define UCF64_FPSCR_FLAG_MASK           (0x3ff)
+#define UCF64_FPSCR_FLAG(r)             (((r) >> 17) & UCF64_FPSCR_FLAG_MASK)
+#define UCF64_FPSCR_FLAG_ZERO           (1 << 17)
+#define UCF64_FPSCR_FLAG_INFINITY       (1 << 18)
+#define UCF64_FPSCR_FLAG_INVALID        (1 << 19)
+#define UCF64_FPSCR_FLAG_UNDERFLOW      (1 << 20)
+#define UCF64_FPSCR_FLAG_OVERFLOW       (1 << 21)
+#define UCF64_FPSCR_FLAG_INEXACT        (1 << 22)
+#define UCF64_FPSCR_FLAG_HUGEINT        (1 << 23)
+#define UCF64_FPSCR_FLAG_DENORMAL       (1 << 24)
+#define UCF64_FPSCR_FLAG_UNIMP          (1 << 25)
+#define UCF64_FPSCR_FLAG_DIVZERO        (1 << 26)
+
+#define UC32_HWCAP_CMOV                 4 /* 1 << 2 */
+#define UC32_HWCAP_UCF64                8 /* 1 << 3 */
+
+#define UC32_CPUID(env)                 (env->cp0.c0_cpuid)
+#define UC32_CPUID_UCV2                 0x40010863
+#define UC32_CPUID_ANY                  0xffffffff
+
+#define cpu_init                        uc32_cpu_init
+#define cpu_exec                        uc32_cpu_exec
+#define cpu_signal_handler              uc32_cpu_signal_handler
+#define cpu_handle_mmu_fault            uc32_cpu_handle_mmu_fault
+
+CPUState *uc32_cpu_init(const char *cpu_model);
+int uc32_cpu_exec(CPUState *s);
+int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
+int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
+
+#define CPU_SAVE_VERSION 2
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0;
+}
+
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->regs[29] = newsp;
+    }
+    env->regs[0] = 0;
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+    env->regs[16] = newtls;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->regs[31] = tb->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->regs[31];
+    *cs_base = 0;
+    *flags = 0;
+    if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) {
+        *flags |= (1 << 6);
+    }
+}
+
+void uc32_translate_init(void);
+void do_interrupt(CPUState *);
+void switch_mode(CPUState_UniCore32 *, int);
+
+static inline bool cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
+#endif /* __CPU_UC32_H__ */
diff --git a/qemu-0.15.x/target-unicore32/exec.h b/qemu-0.15.x/target-unicore32/exec.h
new file mode 100644
index 0000000..7912105
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/exec.h
@@ -0,0 +1,43 @@
+/*
+ *  UniCore32 execution defines
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __UC32_EXEC_H__
+#define __UC32_EXEC_H__
+
+#include "config.h"
+#include "dyngen-exec.h"
+
+register struct CPUState_UniCore32 *env asm(AREG0);
+
+#include "cpu.h"
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted) {
+        return 0;
+    }
+    /* An interrupt wakes the CPU even if the I and R ASR bits are
+       set.  We use EXITTB to silently wake CPU without causing an
+       actual interrupt.  */
+    if (cpu_has_work(env)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
+#endif /* __UC32_EXEC_H__ */
diff --git a/qemu-0.15.x/target-unicore32/helper.c b/qemu-0.15.x/target-unicore32/helper.c
new file mode 100644
index 0000000..02707d5
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/helper.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "gdbstub.h"
+#include "helper.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+static inline void set_feature(CPUState *env, int feature)
+{
+    env->features |= feature;
+}
+
+struct uc32_cpu_t {
+    uint32_t id;
+    const char *name;
+};
+
+static const struct uc32_cpu_t uc32_cpu_names[] = {
+    { UC32_CPUID_UCV2, "UniCore-II"},
+    { UC32_CPUID_ANY, "any"},
+    { 0, NULL}
+};
+
+/* return 0 if not found */
+static uint32_t uc32_cpu_find_by_name(const char *name)
+{
+    int i;
+    uint32_t id;
+
+    id = 0;
+    for (i = 0; uc32_cpu_names[i].name; i++) {
+        if (strcmp(name, uc32_cpu_names[i].name) == 0) {
+            id = uc32_cpu_names[i].id;
+            break;
+        }
+    }
+    return id;
+}
+
+CPUState *uc32_cpu_init(const char *cpu_model)
+{
+    CPUState *env;
+    uint32_t id;
+    static int inited = 1;
+
+    env = qemu_mallocz(sizeof(CPUState));
+    cpu_exec_init(env);
+
+    id = uc32_cpu_find_by_name(cpu_model);
+    switch (id) {
+    case UC32_CPUID_UCV2:
+        set_feature(env, UC32_HWCAP_CMOV);
+        set_feature(env, UC32_HWCAP_UCF64);
+        env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
+        env->cp0.c0_cachetype = 0x1dd20d2;
+        env->cp0.c1_sys = 0x00090078;
+        break;
+    case UC32_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, UC32_HWCAP_CMOV);
+        set_feature(env, UC32_HWCAP_UCF64);
+        break;
+    default:
+        cpu_abort(env, "Bad CPU ID: %x\n", id);
+    }
+
+    env->cpu_model_str = cpu_model;
+    env->cp0.c0_cpuid = id;
+    env->uncached_asr = ASR_MODE_USER;
+    env->regs[31] = 0;
+
+    if (inited) {
+        inited = 0;
+        uc32_translate_init();
+    }
+
+    tlb_flush(env, 1);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+uint32_t HELPER(clo)(uint32_t x)
+{
+    return clo32(x);
+}
+
+uint32_t HELPER(clz)(uint32_t x)
+{
+    return clz32(x);
+}
+
+void do_interrupt(CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    env->exception_index = UC32_EXCP_TRAP;
+    env->cp0.c4_faultaddr = address;
+    return 1;
+}
+
+/* These should probably raise undefined insn exceptions.  */
+void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return;
+}
+
+uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return 0;
+}
+
+void HELPER(set_cp0)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    cpu_abort(env, "cp0 insn %08x\n", insn);
+}
+
+uint32_t HELPER(get_cp0)(CPUState *env, uint32_t insn)
+{
+    cpu_abort(env, "cp0 insn %08x\n", insn);
+    return 0;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    if (mode != ASR_MODE_USER) {
+        cpu_abort(env, "Tried to switch out of user mode\n");
+    }
+}
+
+void HELPER(set_r29_banked)(CPUState *env, uint32_t mode, uint32_t val)
+{
+    cpu_abort(env, "banked r29 write\n");
+}
+
+uint32_t HELPER(get_r29_banked)(CPUState *env, uint32_t mode)
+{
+    cpu_abort(env, "banked r29 read\n");
+    return 0;
+}
+
+/* UniCore-F64 support.  We follow the convention used for F64 instrunctions:
+   Single precition routines have a "s" suffix, double precision a
+   "d" suffix.  */
+
+/* Convert host exception flags to f64 form.  */
+static inline int ucf64_exceptbits_from_host(int host_bits)
+{
+    int target_bits = 0;
+
+    if (host_bits & float_flag_invalid) {
+        target_bits |= UCF64_FPSCR_FLAG_INVALID;
+    }
+    if (host_bits & float_flag_divbyzero) {
+        target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
+    }
+    if (host_bits & float_flag_overflow) {
+        target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
+    }
+    if (host_bits & float_flag_underflow) {
+        target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
+    }
+    if (host_bits & float_flag_inexact) {
+        target_bits |= UCF64_FPSCR_FLAG_INEXACT;
+    }
+    return target_bits;
+}
+
+uint32_t HELPER(ucf64_get_fpscr)(CPUState *env)
+{
+    int i;
+    uint32_t fpscr;
+
+    fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
+    i = get_float_exception_flags(&env->ucf64.fp_status);
+    fpscr |= ucf64_exceptbits_from_host(i);
+    return fpscr;
+}
+
+/* Convert ucf64 exception flags to target form.  */
+static inline int ucf64_exceptbits_to_host(int target_bits)
+{
+    int host_bits = 0;
+
+    if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
+        host_bits |= float_flag_invalid;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
+        host_bits |= float_flag_divbyzero;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
+        host_bits |= float_flag_overflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
+        host_bits |= float_flag_underflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
+        host_bits |= float_flag_inexact;
+    }
+    return host_bits;
+}
+
+void HELPER(ucf64_set_fpscr)(CPUState *env, uint32_t val)
+{
+    int i;
+    uint32_t changed;
+
+    changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
+
+    changed ^= val;
+    if (changed & (UCF64_FPSCR_RND_MASK)) {
+        i = UCF64_FPSCR_RND(val);
+        switch (i) {
+        case 0:
+            i = float_round_nearest_even;
+            break;
+        case 1:
+            i = float_round_to_zero;
+            break;
+        case 2:
+            i = float_round_up;
+            break;
+        case 3:
+            i = float_round_down;
+            break;
+        default: /* 100 and 101 not implement */
+            cpu_abort(env, "Unsupported UniCore-F64 round mode");
+        }
+        set_float_rounding_mode(i, &env->ucf64.fp_status);
+    }
+
+    i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
+    set_float_exception_flags(i, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUState *env)
+{
+    return float32_add(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_add(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUState *env)
+{
+    return float32_sub(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_sub(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUState *env)
+{
+    return float32_mul(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUState *env)
+{
+    return float64_mul(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUState *env)
+{
+    return float32_div(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_div(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_negs)(float32 a)
+{
+    return float32_chs(a);
+}
+
+float64 HELPER(ucf64_negd)(float64 a)
+{
+    return float64_chs(a);
+}
+
+float32 HELPER(ucf64_abss)(float32 a)
+{
+    return float32_abs(a);
+}
+
+float64 HELPER(ucf64_absd)(float64 a)
+{
+    return float64_abs(a);
+}
+
+/* XXX: check quiet/signaling case */
+void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUState *env)
+{
+    int flag;
+    flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUState *env)
+{
+    int flag;
+    flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+/* Helper routines to perform bitwise copies between float and int.  */
+static inline float32 ucf64_itos(uint32_t i)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.i = i;
+    return v.s;
+}
+
+static inline uint32_t ucf64_stoi(float32 s)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.s = s;
+    return v.i;
+}
+
+static inline float64 ucf64_itod(uint64_t i)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.i = i;
+    return v.d;
+}
+
+static inline uint64_t ucf64_dtoi(float64 d)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.d = d;
+    return v.i;
+}
+
+/* Integer to float conversion.  */
+float32 HELPER(ucf64_si2sf)(float32 x, CPUState *env)
+{
+    return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_si2df)(float32 x, CPUState *env)
+{
+    return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+/* Float to integer conversion.  */
+float32 HELPER(ucf64_sf2si)(float32 x, CPUState *env)
+{
+    return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+}
+
+float32 HELPER(ucf64_df2si)(float64 x, CPUState *env)
+{
+    return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+}
+
+/* floating point conversion */
+float64 HELPER(ucf64_sf2df)(float32 x, CPUState *env)
+{
+    return float32_to_float64(x, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_df2sf)(float64 x, CPUState *env)
+{
+    return float64_to_float32(x, &env->ucf64.fp_status);
+}
diff --git a/qemu-0.15.x/target-unicore32/helper.h b/qemu-0.15.x/target-unicore32/helper.h
new file mode 100644
index 0000000..615de2a
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/helper.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include "def-helper.h"
+
+DEF_HELPER_1(clz, i32, i32)
+DEF_HELPER_1(clo, i32, i32)
+
+DEF_HELPER_1(exception, void, i32)
+
+DEF_HELPER_2(asr_write, void, i32, i32)
+DEF_HELPER_0(asr_read, i32)
+
+DEF_HELPER_3(set_cp0, void, env, i32, i32)
+DEF_HELPER_2(get_cp0, i32, env, i32)
+
+DEF_HELPER_3(set_cp, void, env, i32, i32)
+DEF_HELPER_2(get_cp, i32, env, i32)
+
+DEF_HELPER_1(get_user_reg, i32, i32)
+DEF_HELPER_2(set_user_reg, void, i32, i32)
+
+DEF_HELPER_2(add_cc, i32, i32, i32)
+DEF_HELPER_2(adc_cc, i32, i32, i32)
+DEF_HELPER_2(sub_cc, i32, i32, i32)
+DEF_HELPER_2(sbc_cc, i32, i32, i32)
+
+DEF_HELPER_2(shl, i32, i32, i32)
+DEF_HELPER_2(shr, i32, i32, i32)
+DEF_HELPER_2(sar, i32, i32, i32)
+DEF_HELPER_2(shl_cc, i32, i32, i32)
+DEF_HELPER_2(shr_cc, i32, i32, i32)
+DEF_HELPER_2(sar_cc, i32, i32, i32)
+DEF_HELPER_2(ror_cc, i32, i32, i32)
+
+DEF_HELPER_2(get_r29_banked, i32, env, i32)
+DEF_HELPER_3(set_r29_banked, void, env, i32, i32)
+
+DEF_HELPER_1(ucf64_get_fpscr, i32, env)
+DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
+
+DEF_HELPER_3(ucf64_adds, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_addd, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_subs, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_subd, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_muls, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_muld, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_divs, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_divd, f64, f64, f64, env)
+DEF_HELPER_1(ucf64_negs, f32, f32)
+DEF_HELPER_1(ucf64_negd, f64, f64)
+DEF_HELPER_1(ucf64_abss, f32, f32)
+DEF_HELPER_1(ucf64_absd, f64, f64)
+DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env)
+DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env)
+
+DEF_HELPER_2(ucf64_sf2df, f64, f32, env)
+DEF_HELPER_2(ucf64_df2sf, f32, f64, env)
+
+DEF_HELPER_2(ucf64_si2sf, f32, f32, env)
+DEF_HELPER_2(ucf64_si2df, f64, f32, env)
+
+DEF_HELPER_2(ucf64_sf2si, f32, f32, env)
+DEF_HELPER_2(ucf64_df2si, f32, f64, env)
+
+#include "def-helper.h"
diff --git a/qemu-0.15.x/target-unicore32/op_helper.c b/qemu-0.15.x/target-unicore32/op_helper.c
new file mode 100644
index 0000000..541e6f0
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/op_helper.c
@@ -0,0 +1,248 @@
+/*
+ *  UniCore32 helper routines
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include "exec.h"
+#include "helper.h"
+
+#define SIGNBIT (uint32_t)0x80000000
+#define SIGNBIT64 ((uint64_t)1 << 63)
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+static target_ulong asr_read(void)
+{
+    int ZF;
+    ZF = (env->ZF == 0);
+    return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) |
+        (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
+}
+
+target_ulong cpu_asr_read(CPUState *env1)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = asr_read();
+    env = saved_env;
+    return ret;
+}
+
+target_ulong HELPER(asr_read)(void)
+{
+    return asr_read();
+}
+
+static void asr_write(target_ulong val, target_ulong mask)
+{
+    if (mask & ASR_NZCV) {
+        env->ZF = (~val) & ASR_Z;
+        env->NF = val;
+        env->CF = (val >> 29) & 1;
+        env->VF = (val << 3) & 0x80000000;
+    }
+
+    if ((env->uncached_asr ^ val) & mask & ASR_M) {
+        switch_mode(env, val & ASR_M);
+    }
+    mask &= ~ASR_NZCV;
+    env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask);
+}
+
+void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    asr_write(val, mask);
+    env = saved_env;
+}
+
+void HELPER(asr_write)(target_ulong val, target_ulong mask)
+{
+    asr_write(val, mask);
+}
+
+/* Access to user mode registers from privileged modes.  */
+uint32_t HELPER(get_user_reg)(uint32_t regno)
+{
+    uint32_t val;
+
+    if (regno == 29) {
+        val = env->banked_r29[0];
+    } else if (regno == 30) {
+        val = env->banked_r30[0];
+    } else {
+        val = env->regs[regno];
+    }
+    return val;
+}
+
+void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
+{
+    if (regno == 29) {
+        env->banked_r29[0] = val;
+    } else if (regno == 30) {
+        env->banked_r30[0] = val;
+    } else {
+        env->regs[regno] = val;
+    }
+}
+
+/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
+   The only way to do that in TCG is a conditional branch, which clobbers
+   all our temporaries.  For now implement these as helper functions.  */
+
+uint32_t HELPER(add_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a + b;
+    env->NF = env->ZF = result;
+    env->CF = result < a;
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a + b;
+        env->CF = result < a;
+    } else {
+        result = a + b + 1;
+        env->CF = result <= a;
+    }
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a - b;
+    env->NF = env->ZF = result;
+    env->CF = a >= b;
+    env->VF = (a ^ b) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a - b - 1;
+        env->CF = a > b;
+    } else {
+        result = a - b;
+        env->CF = a >= b;
+    }
+    env->VF = (a ^ b) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+/* Similarly for variable shift instructions.  */
+
+uint32_t HELPER(shl)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        return 0;
+    }
+    return x << shift;
+}
+
+uint32_t HELPER(shr)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        return 0;
+    }
+    return (uint32_t)x >> shift;
+}
+
+uint32_t HELPER(sar)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        shift = 31;
+    }
+    return (int32_t)x >> shift;
+}
+
+uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32) {
+            env->CF = x & 1;
+        } else {
+            env->CF = 0;
+        }
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (32 - shift)) & 1;
+        return x << shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32) {
+            env->CF = (x >> 31) & 1;
+        } else {
+            env->CF = 0;
+        }
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        env->CF = (x >> 31) & 1;
+        return (int32_t)x >> 31;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return (int32_t)x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
+{
+    int shift1, shift;
+    shift1 = i & 0xff;
+    shift = shift1 & 0x1f;
+    if (shift == 0) {
+        if (shift1 != 0) {
+            env->CF = (x >> 31) & 1;
+        }
+        return x;
+    } else {
+        env->CF = (x >> (shift - 1)) & 1;
+        return ((uint32_t)x >> shift) | (x << (32 - shift));
+    }
+}
diff --git a/qemu-0.15.x/target-unicore32/translate.c b/qemu-0.15.x/target-unicore32/translate.c
new file mode 100644
index 0000000..a15e42d
--- /dev/null
+++ b/qemu-0.15.x/target-unicore32/translate.c
@@ -0,0 +1,2103 @@
+/*
+ *  UniCore32 translation
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+/* internal defines */
+typedef struct DisasContext {
+    target_ulong pc;
+    int is_jmp;
+    /* Nonzero if this instruction has been conditionally skipped.  */
+    int condjmp;
+    /* The label that will be jumped to when the instruction is skipped.  */
+    int condlabel;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+#define IS_USER(s) 1
+
+/* These instructions trap after executing, so defer them until after the
+   conditional executions state has been updated.  */
+#define DISAS_SYSCALL 5
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_R[32];
+
+/* FIXME:  These should be removed.  */
+static TCGv cpu_F0s, cpu_F1s;
+static TCGv_i64 cpu_F0d, cpu_F1d;
+
+#include "gen-icount.h"
+
+static const char *regnames[] = {
+      "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07",
+      "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15",
+      "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+      "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" };
+
+/* initialize TCG globals.  */
+void uc32_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < 32; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                offsetof(CPUState, regs[i]), regnames[i]);
+    }
+
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+static int num_temps;
+
+/* Allocate a temporary variable.  */
+static TCGv_i32 new_tmp(void)
+{
+    num_temps++;
+    return tcg_temp_new_i32();
+}
+
+/* Release a temporary variable.  */
+static void dead_tmp(TCGv tmp)
+{
+    tcg_temp_free(tmp);
+    num_temps--;
+}
+
+static inline TCGv load_cpu_offset(int offset)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_ld_i32(tmp, cpu_env, offset);
+    return tmp;
+}
+
+#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))
+
+static inline void store_cpu_offset(TCGv var, int offset)
+{
+    tcg_gen_st_i32(var, cpu_env, offset);
+    dead_tmp(var);
+}
+
+#define store_cpu_field(var, name) \
+    store_cpu_offset(var, offsetof(CPUState, name))
+
+/* Set a variable to the value of a CPU register.  */
+static void load_reg_var(DisasContext *s, TCGv var, int reg)
+{
+    if (reg == 31) {
+        uint32_t addr;
+        /* normaly, since we updated PC */
+        addr = (long)s->pc;
+        tcg_gen_movi_i32(var, addr);
+    } else {
+        tcg_gen_mov_i32(var, cpu_R[reg]);
+    }
+}
+
+/* Create a new temporary and set it to the value of a CPU register.  */
+static inline TCGv load_reg(DisasContext *s, int reg)
+{
+    TCGv tmp = new_tmp();
+    load_reg_var(s, tmp, reg);
+    return tmp;
+}
+
+/* Set a CPU register.  The source must be a temporary and will be
+   marked as dead.  */
+static void store_reg(DisasContext *s, int reg, TCGv var)
+{
+    if (reg == 31) {
+        tcg_gen_andi_i32(var, var, ~3);
+        s->is_jmp = DISAS_JUMP;
+    }
+    tcg_gen_mov_i32(cpu_R[reg], var);
+    dead_tmp(var);
+}
+
+/* Value extensions.  */
+#define gen_uxtb(var)           tcg_gen_ext8u_i32(var, var)
+#define gen_uxth(var)           tcg_gen_ext16u_i32(var, var)
+#define gen_sxtb(var)           tcg_gen_ext8s_i32(var, var)
+#define gen_sxth(var)           tcg_gen_ext16s_i32(var, var)
+
+#define UCOP_REG_M              (((insn) >>  0) & 0x1f)
+#define UCOP_REG_N              (((insn) >> 19) & 0x1f)
+#define UCOP_REG_D              (((insn) >> 14) & 0x1f)
+#define UCOP_REG_S              (((insn) >>  9) & 0x1f)
+#define UCOP_REG_LO             (((insn) >> 14) & 0x1f)
+#define UCOP_REG_HI             (((insn) >>  9) & 0x1f)
+#define UCOP_SH_OP              (((insn) >>  6) & 0x03)
+#define UCOP_SH_IM              (((insn) >>  9) & 0x1f)
+#define UCOP_OPCODES            (((insn) >> 25) & 0x0f)
+#define UCOP_IMM_9              (((insn) >>  0) & 0x1ff)
+#define UCOP_IMM10              (((insn) >>  0) & 0x3ff)
+#define UCOP_IMM14              (((insn) >>  0) & 0x3fff)
+#define UCOP_COND               (((insn) >> 25) & 0x0f)
+#define UCOP_CMOV_COND          (((insn) >> 19) & 0x0f)
+#define UCOP_CPNUM              (((insn) >> 10) & 0x0f)
+#define UCOP_UCF64_FMT          (((insn) >> 24) & 0x03)
+#define UCOP_UCF64_FUNC         (((insn) >>  6) & 0x0f)
+#define UCOP_UCF64_COND         (((insn) >>  6) & 0x0f)
+
+#define UCOP_SET(i)             ((insn) & (1 << (i)))
+#define UCOP_SET_P              UCOP_SET(28)
+#define UCOP_SET_U              UCOP_SET(27)
+#define UCOP_SET_B              UCOP_SET(26)
+#define UCOP_SET_W              UCOP_SET(25)
+#define UCOP_SET_L              UCOP_SET(24)
+#define UCOP_SET_S              UCOP_SET(24)
+
+#define ILLEGAL         cpu_abort(env,                                  \
+                        "Illegal UniCore32 instruction %x at line %d!", \
+                        insn, __LINE__)
+
+static inline void gen_set_asr(TCGv var, uint32_t mask)
+{
+    TCGv tmp_mask = tcg_const_i32(mask);
+    gen_helper_asr_write(var, tmp_mask);
+    tcg_temp_free_i32(tmp_mask);
+}
+/* Set NZCV flags from the high 4 bits of var.  */
+#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV)
+
+static void gen_exception(int excp)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_movi_i32(tmp, excp);
+    gen_helper_exception(tmp);
+    dead_tmp(tmp);
+}
+
+/* FIXME: Most targets have native widening multiplication.
+   It would be good to use that instead of a full wide multiply.  */
+/* 32x32->64 multiply.  Marks inputs as dead.  */
+static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp1, a);
+    dead_tmp(a);
+    tcg_gen_extu_i32_i64(tmp2, b);
+    dead_tmp(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(tmp1, a);
+    dead_tmp(a);
+    tcg_gen_ext_i32_i64(tmp2, b);
+    dead_tmp(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
+
+/* Set CF to the top bit of var.  */
+static void gen_set_CF_bit31(TCGv var)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_shri_i32(tmp, var, 31);
+    gen_set_CF(tmp);
+    dead_tmp(tmp);
+}
+
+/* Set N and Z flags from var.  */
+static inline void gen_logic_CC(TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
+}
+
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    dead_tmp(tmp);
+}
+
+/* dest = T0 - T1 + CF - 1.  */
+static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_sub_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    tcg_gen_subi_i32(dest, dest, 1);
+    dead_tmp(tmp);
+}
+
+static void shifter_out_im(TCGv var, int shift)
+{
+    TCGv tmp = new_tmp();
+    if (shift == 0) {
+        tcg_gen_andi_i32(tmp, var, 1);
+    } else {
+        tcg_gen_shri_i32(tmp, var, shift);
+        if (shift != 31) {
+            tcg_gen_andi_i32(tmp, tmp, 1);
+        }
+    }
+    gen_set_CF(tmp);
+    dead_tmp(tmp);
+}
+
+/* Shift by immediate.  Includes special handling for shift == 0.  */
+static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift,
+        int flags)
+{
+    switch (shiftop) {
+    case 0: /* LSL */
+        if (shift != 0) {
+            if (flags) {
+                shifter_out_im(var, 32 - shift);
+            }
+            tcg_gen_shli_i32(var, var, shift);
+        }
+        break;
+    case 1: /* LSR */
+        if (shift == 0) {
+            if (flags) {
+                tcg_gen_shri_i32(var, var, 31);
+                gen_set_CF(var);
+            }
+            tcg_gen_movi_i32(var, 0);
+        } else {
+            if (flags) {
+                shifter_out_im(var, shift - 1);
+            }
+            tcg_gen_shri_i32(var, var, shift);
+        }
+        break;
+    case 2: /* ASR */
+        if (shift == 0) {
+            shift = 32;
+        }
+        if (flags) {
+            shifter_out_im(var, shift - 1);
+        }
+        if (shift == 32) {
+            shift = 31;
+        }
+        tcg_gen_sari_i32(var, var, shift);
+        break;
+    case 3: /* ROR/RRX */
+        if (shift != 0) {
+            if (flags) {
+                shifter_out_im(var, shift - 1);
+            }
+            tcg_gen_rotri_i32(var, var, shift); break;
+        } else {
+            TCGv tmp = load_cpu_field(CF);
+            if (flags) {
+                shifter_out_im(var, 0);
+            }
+            tcg_gen_shri_i32(var, var, 1);
+            tcg_gen_shli_i32(tmp, tmp, 31);
+            tcg_gen_or_i32(var, var, tmp);
+            dead_tmp(tmp);
+        }
+    }
+};
+
+static inline void gen_uc32_shift_reg(TCGv var, int shiftop,
+                                     TCGv shift, int flags)
+{
+    if (flags) {
+        switch (shiftop) {
+        case 0:
+            gen_helper_shl_cc(var, var, shift);
+            break;
+        case 1:
+            gen_helper_shr_cc(var, var, shift);
+            break;
+        case 2:
+            gen_helper_sar_cc(var, var, shift);
+            break;
+        case 3:
+            gen_helper_ror_cc(var, var, shift);
+            break;
+        }
+    } else {
+        switch (shiftop) {
+        case 0:
+            gen_helper_shl(var, var, shift);
+            break;
+        case 1:
+            gen_helper_shr(var, var, shift);
+            break;
+        case 2:
+            gen_helper_sar(var, var, shift);
+            break;
+        case 3:
+            tcg_gen_andi_i32(shift, shift, 0x1f);
+            tcg_gen_rotr_i32(var, var, shift);
+            break;
+        }
+    }
+    dead_tmp(shift);
+}
+
+static void gen_test_cc(int cc, int label)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    int inv;
+
+    switch (cc) {
+    case 0: /* eq: Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 1: /* ne: !Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 2: /* cs: C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 3: /* cc: !C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 4: /* mi: N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 5: /* pl: !N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 6: /* vs: V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 7: /* vc: !V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 8: /* hi: C && !Z */
+        inv = gen_new_label();
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 9: /* ls: !C || Z */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 10: /* ge: N == V -> N ^ V == 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 11: /* lt: N != V -> N ^ V != 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 12: /* gt: !Z && N == V */
+        inv = gen_new_label();
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 13: /* le: Z || N != V */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    default:
+        fprintf(stderr, "Bad condition code 0x%x\n", cc);
+        abort();
+    }
+    dead_tmp(tmp);
+}
+
+static const uint8_t table_logic_cc[16] = {
+    1, /* and */    1, /* xor */    0, /* sub */    0, /* rsb */
+    0, /* add */    0, /* adc */    0, /* sbc */    0, /* rsc */
+    1, /* andl */   1, /* xorl */   0, /* cmp */    0, /* cmn */
+    1, /* orr */    1, /* mov */    1, /* bic */    1, /* mvn */
+};
+
+/* Set PC state from an immediate address.  */
+static inline void gen_bx_im(DisasContext *s, uint32_t addr)
+{
+    s->is_jmp = DISAS_UPDATE;
+    tcg_gen_movi_i32(cpu_R[31], addr & ~3);
+}
+
+/* Set PC state from var.  var is marked as dead.  */
+static inline void gen_bx(DisasContext *s, TCGv var)
+{
+    s->is_jmp = DISAS_UPDATE;
+    tcg_gen_andi_i32(cpu_R[31], var, ~3);
+    dead_tmp(var);
+}
+
+static inline void store_reg_bx(DisasContext *s, int reg, TCGv var)
+{
+    store_reg(s, reg, var);
+}
+
+static inline TCGv gen_ld8s(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld8s(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld8u(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld8u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld16s(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld16s(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld16u(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld16u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld32(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld32u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv_i64 gen_ld64(TCGv addr, int index)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(tmp, addr, index);
+    return tmp;
+}
+
+static inline void gen_st8(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st8(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st16(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st16(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st32(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st32(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st64(val, addr, index);
+    tcg_temp_free_i64(val);
+}
+
+static inline void gen_set_pc_im(uint32_t val)
+{
+    tcg_gen_movi_i32(cpu_R[31], val);
+}
+
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static inline void gen_lookup_tb(DisasContext *s)
+{
+    tcg_gen_movi_i32(cpu_R[31], s->pc & ~1);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
+        TCGv var)
+{
+    int val;
+    TCGv offset;
+
+    if (UCOP_SET(29)) {
+        /* immediate */
+        val = UCOP_IMM14;
+        if (!UCOP_SET_U) {
+            val = -val;
+        }
+        if (val != 0) {
+            tcg_gen_addi_i32(var, var, val);
+        }
+    } else {
+        /* shift/register */
+        offset = load_reg(s, UCOP_REG_M);
+        gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0);
+        if (!UCOP_SET_U) {
+            tcg_gen_sub_i32(var, var, offset);
+        } else {
+            tcg_gen_add_i32(var, var, offset);
+        }
+        dead_tmp(offset);
+    }
+}
+
+static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
+        TCGv var)
+{
+    int val;
+    TCGv offset;
+
+    if (UCOP_SET(26)) {
+        /* immediate */
+        val = (insn & 0x1f) | ((insn >> 4) & 0x3e0);
+        if (!UCOP_SET_U) {
+            val = -val;
+        }
+        if (val != 0) {
+            tcg_gen_addi_i32(var, var, val);
+        }
+    } else {
+        /* register */
+        offset = load_reg(s, UCOP_REG_M);
+        if (!UCOP_SET_U) {
+            tcg_gen_sub_i32(var, var, offset);
+        } else {
+            tcg_gen_add_i32(var, var, offset);
+        }
+        dead_tmp(offset);
+    }
+}
+
+static inline long ucf64_reg_offset(int reg)
+{
+    if (reg & 1) {
+        return offsetof(CPUState, ucf64.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.upper);
+    } else {
+        return offsetof(CPUState, ucf64.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.lower);
+    }
+}
+
+#define ucf64_gen_ld32(reg)      load_cpu_offset(ucf64_reg_offset(reg))
+#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg))
+
+/* UniCore-F64 single load/store I_offset */
+static void do_ucf64_ldst_i(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int offset;
+    TCGv tmp;
+    TCGv addr;
+
+    addr = load_reg(s, UCOP_REG_N);
+    if (!UCOP_SET_P && !UCOP_SET_W) {
+        ILLEGAL;
+    }
+
+    if (UCOP_SET_P) {
+        offset = UCOP_IMM10 << 2;
+        if (!UCOP_SET_U) {
+            offset = -offset;
+        }
+        if (offset != 0) {
+            tcg_gen_addi_i32(addr, addr, offset);
+        }
+    }
+
+    if (UCOP_SET_L) { /* load */
+        tmp = gen_ld32(addr, IS_USER(s));
+        ucf64_gen_st32(tmp, UCOP_REG_D);
+    } else { /* store */
+        tmp = ucf64_gen_ld32(UCOP_REG_D);
+        gen_st32(tmp, addr, IS_USER(s));
+    }
+
+    if (!UCOP_SET_P) {
+        offset = UCOP_IMM10 << 2;
+        if (!UCOP_SET_U) {
+            offset = -offset;
+        }
+        if (offset != 0) {
+            tcg_gen_addi_i32(addr, addr, offset);
+        }
+    }
+    if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+}
+
+/* UniCore-F64 load/store multiple words */
+static void do_ucf64_ldst_m(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int i;
+    int j, n, freg;
+    TCGv tmp;
+    TCGv addr;
+
+    if (UCOP_REG_D != 0) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_N == 31) {
+        ILLEGAL;
+    }
+    if ((insn << 24) == 0) {
+        ILLEGAL;
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+
+    n = 0;
+    for (i = 0; i < 8; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+
+    if (UCOP_SET_U) {
+        if (UCOP_SET_P) { /* pre increment */
+            tcg_gen_addi_i32(addr, addr, 4);
+        } /* unnecessary to do anything when post increment */
+    } else {
+        if (UCOP_SET_P) { /* pre decrement */
+            tcg_gen_addi_i32(addr, addr, -(n * 4));
+        } else { /* post decrement */
+            if (n != 1) {
+                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+            }
+        }
+    }
+
+    freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */
+
+    for (i = 0, j = 0; i < 8; i++, freg++) {
+        if (!UCOP_SET(i)) {
+            continue;
+        }
+
+        if (UCOP_SET_L) { /* load */
+            tmp = gen_ld32(addr, IS_USER(s));
+            ucf64_gen_st32(tmp, freg);
+        } else { /* store */
+            tmp = ucf64_gen_ld32(freg);
+            gen_st32(tmp, addr, IS_USER(s));
+        }
+
+        j++;
+        /* unnecessary to add after the last transfer */
+        if (j != n) {
+            tcg_gen_addi_i32(addr, addr, 4);
+        }
+    }
+
+    if (UCOP_SET_W) { /* write back */
+        if (UCOP_SET_U) {
+            if (!UCOP_SET_P) { /* post increment */
+                tcg_gen_addi_i32(addr, addr, 4);
+            } /* unnecessary to do anything when pre increment */
+        } else {
+            if (UCOP_SET_P) {
+                /* pre decrement */
+                if (n != 1) {
+                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                }
+            } else {
+                /* post decrement */
+                tcg_gen_addi_i32(addr, addr, -(n * 4));
+            }
+        }
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+}
+
+/* UniCore-F64 mrc/mcr */
+static void do_ucf64_trans(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+
+    if ((insn & 0xfe0003ff) == 0xe2000000) {
+        /* control register */
+        if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) {
+            ILLEGAL;
+        }
+        if (UCOP_SET(24)) {
+            /* CFF */
+            tmp = new_tmp();
+            gen_helper_ucf64_get_fpscr(tmp, cpu_env);
+            store_reg(s, UCOP_REG_D, tmp);
+        } else {
+            /* CTF */
+            tmp = load_reg(s, UCOP_REG_D);
+            gen_helper_ucf64_set_fpscr(cpu_env, tmp);
+            dead_tmp(tmp);
+            gen_lookup_tb(s);
+        }
+        return;
+    }
+    if ((insn & 0xfe0003ff) == 0xe0000000) {
+        /* general register */
+        if (UCOP_REG_D == 31) {
+            ILLEGAL;
+        }
+        if (UCOP_SET(24)) { /* MFF */
+            tmp = ucf64_gen_ld32(UCOP_REG_N);
+            store_reg(s, UCOP_REG_D, tmp);
+        } else { /* MTF */
+            tmp = load_reg(s, UCOP_REG_D);
+            ucf64_gen_st32(tmp, UCOP_REG_N);
+        }
+        return;
+    }
+    if ((insn & 0xfb000000) == 0xe9000000) {
+        /* MFFC */
+        if (UCOP_REG_D != 31) {
+            ILLEGAL;
+        }
+        if (UCOP_UCF64_COND & 0x8) {
+            ILLEGAL;
+        }
+
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, UCOP_UCF64_COND);
+        if (UCOP_SET(26)) {
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+            tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env);
+        } else {
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+            tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env);
+        }
+        dead_tmp(tmp);
+        return;
+    }
+    ILLEGAL;
+}
+
+/* UniCore-F64 convert instructions */
+static void do_ucf64_fcvt(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_UCF64_FMT == 3) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_N != 0) {
+        ILLEGAL;
+    }
+    switch (UCOP_UCF64_FUNC) {
+    case 0: /* cvt.s */
+        switch (UCOP_UCF64_FMT) {
+        case 1 /* d */:
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 2 /* w */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        default /* s */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    case 1: /* cvt.d */
+        switch (UCOP_UCF64_FMT) {
+        case 0 /* s */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env);
+            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 2 /* w */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env);
+            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        default /* d */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    case 4: /* cvt.w */
+        switch (UCOP_UCF64_FMT) {
+        case 0 /* s */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 1 /* d */:
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+    default /* w */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    default:
+        ILLEGAL;
+    }
+}
+
+/* UniCore-F64 compare instructions */
+static void do_ucf64_fcmp(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_SET(25)) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_D != 0) {
+        ILLEGAL;
+    }
+
+    ILLEGAL; /* TODO */
+    if (UCOP_SET(24)) {
+        tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+        tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+        /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */
+    } else {
+        tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+        tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+        /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */
+    }
+}
+
+#define gen_helper_ucf64_movs(x, y)      do { } while (0)
+#define gen_helper_ucf64_movd(x, y)      do { } while (0)
+
+#define UCF64_OP1(name)    do {                           \
+        if (UCOP_REG_N != 0) {                            \
+            ILLEGAL;                                      \
+        }                                                 \
+        switch (UCOP_UCF64_FMT) {                         \
+        case 0 /* s */:                                   \
+            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \
+            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 1 /* d */:                                   \
+            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \
+            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 2 /* w */:                                   \
+            ILLEGAL;                                      \
+            break;                                        \
+        }                                                 \
+    } while (0)
+
+#define UCF64_OP2(name)    do {                           \
+        switch (UCOP_UCF64_FMT) {                         \
+        case 0 /* s */:                                   \
+            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_N)); \
+            tcg_gen_ld_i32(cpu_F1s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##s(cpu_F0s,           \
+                           cpu_F0s, cpu_F1s, cpu_env);    \
+            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 1 /* d */:                                   \
+            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_N)); \
+            tcg_gen_ld_i64(cpu_F1d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##d(cpu_F0d,           \
+                           cpu_F0d, cpu_F1d, cpu_env);    \
+            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 2 /* w */:                                   \
+            ILLEGAL;                                      \
+            break;                                        \
+        }                                                 \
+    } while (0)
+
+/* UniCore-F64 data processing */
+static void do_ucf64_datap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_UCF64_FMT == 3) {
+        ILLEGAL;
+    }
+    switch (UCOP_UCF64_FUNC) {
+    case 0: /* add */
+        UCF64_OP2(add);
+        break;
+    case 1: /* sub */
+        UCF64_OP2(sub);
+        break;
+    case 2: /* mul */
+        UCF64_OP2(mul);
+        break;
+    case 4: /* div */
+        UCF64_OP2(div);
+        break;
+    case 5: /* abs */
+        UCF64_OP1(abs);
+        break;
+    case 6: /* mov */
+        UCF64_OP1(mov);
+        break;
+    case 7: /* neg */
+        UCF64_OP1(neg);
+        break;
+    default:
+        ILLEGAL;
+    }
+}
+
+/* Disassemble an F64 instruction */
+static void disas_ucf64_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (!UCOP_SET(29)) {
+        if (UCOP_SET(26)) {
+            do_ucf64_ldst_m(env, s, insn);
+        } else {
+            do_ucf64_ldst_i(env, s, insn);
+        }
+    } else {
+        if (UCOP_SET(5)) {
+            switch ((insn >> 26) & 0x3) {
+            case 0:
+                do_ucf64_datap(env, s, insn);
+                break;
+            case 1:
+                ILLEGAL;
+                break;
+            case 2:
+                do_ucf64_fcvt(env, s, insn);
+                break;
+            case 3:
+                do_ucf64_fcmp(env, s, insn);
+                break;
+            }
+        } else {
+            do_ucf64_trans(env, s, insn);
+        }
+    }
+}
+
+static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        tcg_gen_goto_tb(n);
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb((long)tb + n);
+    } else {
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void gen_jmp(DisasContext *s, uint32_t dest)
+{
+    if (unlikely(s->singlestep_enabled)) {
+        /* An indirect jump so that we still trigger the debug exception.  */
+        gen_bx_im(s, dest);
+    } else {
+        gen_goto_tb(s, 0, dest);
+        s->is_jmp = DISAS_TB_JUMP;
+    }
+}
+
+static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
+{
+    if (x) {
+        tcg_gen_sari_i32(t0, t0, 16);
+    } else {
+        gen_sxth(t0);
+    }
+    if (y) {
+        tcg_gen_sari_i32(t1, t1, 16);
+    } else {
+        gen_sxth(t1);
+    }
+    tcg_gen_mul_i32(t0, t0, t1);
+}
+
+/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
+static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0)
+{
+    TCGv tmp;
+    if (bsr) {
+        /* ??? This is also undefined in system mode.  */
+        if (IS_USER(s)) {
+            return 1;
+        }
+
+        tmp = load_cpu_field(bsr);
+        tcg_gen_andi_i32(tmp, tmp, ~mask);
+        tcg_gen_andi_i32(t0, t0, mask);
+        tcg_gen_or_i32(tmp, tmp, t0);
+        store_cpu_field(tmp, bsr);
+    } else {
+        gen_set_asr(t0, mask);
+    }
+    dead_tmp(t0);
+    gen_lookup_tb(s);
+    return 0;
+}
+
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
+{
+    TCGv tmp;
+    store_reg(s, 31, pc);
+    tmp = load_cpu_field(bsr);
+    gen_set_asr(tmp, 0xffffffff);
+    dead_tmp(tmp);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static void disas_coproc_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    switch (UCOP_CPNUM) {
+    case 2:
+        disas_ucf64_insn(env, s, insn);
+        break;
+    default:
+        /* Unknown coprocessor. */
+        cpu_abort(env, "Unknown coprocessor!");
+    }
+}
+
+
+/* Store a 64-bit value to a register pair.  Clobbers val.  */
+static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
+{
+    TCGv tmp;
+    tmp = new_tmp();
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rlow, tmp);
+    tmp = new_tmp();
+    tcg_gen_shri_i64(val, val, 32);
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rhigh, tmp);
+}
+
+/* load and add a 64-bit value from a register pair.  */
+static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
+{
+    TCGv_i64 tmp;
+    TCGv tmpl;
+    TCGv tmph;
+
+    /* Load 64-bit value rd:rn.  */
+    tmpl = load_reg(s, rlow);
+    tmph = load_reg(s, rhigh);
+    tmp = tcg_temp_new_i64();
+    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
+    dead_tmp(tmpl);
+    dead_tmp(tmph);
+    tcg_gen_add_i64(val, val, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+/* data processing instructions */
+static void do_datap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    int logic_cc;
+
+    if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) {
+        if (UCOP_SET(23)) { /* CMOV instructions */
+            if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) {
+                ILLEGAL;
+            }
+            /* if not always execute, we generate a conditional jump to
+               next instruction */
+            s->condlabel = gen_new_label();
+            gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel);
+            s->condjmp = 1;
+        }
+    }
+
+    logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24);
+
+    if (UCOP_SET(29)) {
+        unsigned int val;
+        /* immediate operand */
+        val = UCOP_IMM_9;
+        if (UCOP_SH_IM) {
+            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
+        }
+        tmp2 = new_tmp();
+        tcg_gen_movi_i32(tmp2, val);
+        if (logic_cc && UCOP_SH_IM) {
+            gen_set_CF_bit31(tmp2);
+        }
+   } else {
+        /* register */
+        tmp2 = load_reg(s, UCOP_REG_M);
+        if (UCOP_SET(5)) {
+            tmp = load_reg(s, UCOP_REG_S);
+            gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc);
+        } else {
+            gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc);
+        }
+    }
+
+    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
+        tmp = load_reg(s, UCOP_REG_N);
+    } else {
+        TCGV_UNUSED(tmp);
+    }
+
+    switch (UCOP_OPCODES) {
+    case 0x00:
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x01:
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x02:
+        if (UCOP_SET_S && UCOP_REG_D == 31) {
+            /* SUBS r31, ... is used for exception return.  */
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            gen_helper_sub_cc(tmp, tmp, tmp2);
+            gen_exception_return(s, tmp);
+        } else {
+            if (UCOP_SET_S) {
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+            } else {
+                tcg_gen_sub_i32(tmp, tmp, tmp2);
+            }
+            store_reg_bx(s, UCOP_REG_D, tmp);
+        }
+        break;
+    case 0x03:
+        if (UCOP_SET_S) {
+            gen_helper_sub_cc(tmp, tmp2, tmp);
+        } else {
+            tcg_gen_sub_i32(tmp, tmp2, tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x04:
+        if (UCOP_SET_S) {
+            gen_helper_add_cc(tmp, tmp, tmp2);
+        } else {
+            tcg_gen_add_i32(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x05:
+        if (UCOP_SET_S) {
+            gen_helper_adc_cc(tmp, tmp, tmp2);
+        } else {
+            gen_add_carry(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x06:
+        if (UCOP_SET_S) {
+            gen_helper_sbc_cc(tmp, tmp, tmp2);
+        } else {
+            gen_sub_carry(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x07:
+        if (UCOP_SET_S) {
+            gen_helper_sbc_cc(tmp, tmp2, tmp);
+        } else {
+            gen_sub_carry(tmp, tmp2, tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x08:
+        if (UCOP_SET_S) {
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            gen_logic_CC(tmp);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x09:
+        if (UCOP_SET_S) {
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
+            gen_logic_CC(tmp);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0a:
+        if (UCOP_SET_S) {
+            gen_helper_sub_cc(tmp, tmp, tmp2);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0b:
+        if (UCOP_SET_S) {
+            gen_helper_add_cc(tmp, tmp, tmp2);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0c:
+        tcg_gen_or_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x0d:
+        if (logic_cc && UCOP_REG_D == 31) {
+            /* MOVS r31, ... is used for exception return.  */
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            gen_exception_return(s, tmp2);
+        } else {
+            if (logic_cc) {
+                gen_logic_CC(tmp2);
+            }
+            store_reg_bx(s, UCOP_REG_D, tmp2);
+        }
+        break;
+    case 0x0e:
+        tcg_gen_andc_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    default:
+    case 0x0f:
+        tcg_gen_not_i32(tmp2, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp2);
+        break;
+    }
+    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
+        dead_tmp(tmp2);
+    }
+}
+
+/* multiply */
+static void do_mult(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv_i64 tmp64;
+
+    if (UCOP_SET(27)) {
+        /* 64 bit mul */
+        tmp = load_reg(s, UCOP_REG_M);
+        tmp2 = load_reg(s, UCOP_REG_N);
+        if (UCOP_SET(26)) {
+            tmp64 = gen_muls_i64_i32(tmp, tmp2);
+        } else {
+            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+        }
+        if (UCOP_SET(25)) { /* mult accumulate */
+            gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI);
+        }
+        gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64);
+        tcg_temp_free_i64(tmp64);
+    } else {
+        /* 32 bit mul */
+        tmp = load_reg(s, UCOP_REG_M);
+        tmp2 = load_reg(s, UCOP_REG_N);
+        tcg_gen_mul_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        if (UCOP_SET(25)) {
+            /* Add */
+            tmp2 = load_reg(s, UCOP_REG_S);
+            tcg_gen_add_i32(tmp, tmp, tmp2);
+            dead_tmp(tmp2);
+        }
+        if (UCOP_SET_S) {
+            gen_logic_CC(tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+    }
+}
+
+/* miscellaneous instructions */
+static void do_misc(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val;
+    TCGv tmp;
+
+    if ((insn & 0xffffffe0) == 0x10ffc120) {
+        /* Trivial implementation equivalent to bx.  */
+        tmp = load_reg(s, UCOP_REG_M);
+        gen_bx(s, tmp);
+        return;
+    }
+
+    if ((insn & 0xfbffc000) == 0x30ffc000) {
+        /* PSR = immediate */
+        val = UCOP_IMM_9;
+        if (UCOP_SH_IM) {
+            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
+        }
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, val);
+        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbffffe0) == 0x12ffc020) {
+        /* PSR.flag = reg */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbffffe0) == 0x10ffc020) {
+        /* PSR = reg */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbf83fff) == 0x10f80000) {
+        /* reg = PSR */
+        if (UCOP_SET_B) {
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            tmp = load_cpu_field(bsr);
+        } else {
+            tmp = new_tmp();
+            gen_helper_asr_read(tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+        return;
+    }
+
+    if ((insn & 0xfbf83fe0) == 0x12f80120) {
+        /* clz */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (UCOP_SET(26)) {
+            gen_helper_clo(tmp, tmp);
+        } else {
+            gen_helper_clz(tmp, tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+        return;
+    }
+
+    /* otherwise */
+    ILLEGAL;
+}
+
+/* load/store I_offset and R_offset */
+static void do_ldst_ir(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int i;
+    TCGv tmp;
+    TCGv tmp2;
+
+    tmp2 = load_reg(s, UCOP_REG_N);
+    i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
+
+    /* immediate */
+    if (UCOP_SET_P) {
+        gen_add_data_offset(s, insn, tmp2);
+    }
+
+    if (UCOP_SET_L) {
+        /* load */
+        if (UCOP_SET_B) {
+            tmp = gen_ld8u(tmp2, i);
+        } else {
+            tmp = gen_ld32(tmp2, i);
+        }
+    } else {
+        /* store */
+        tmp = load_reg(s, UCOP_REG_D);
+        if (UCOP_SET_B) {
+            gen_st8(tmp, tmp2, i);
+        } else {
+            gen_st32(tmp, tmp2, i);
+        }
+    }
+    if (!UCOP_SET_P) {
+        gen_add_data_offset(s, insn, tmp2);
+        store_reg(s, UCOP_REG_N, tmp2);
+    } else if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, tmp2);
+    } else {
+        dead_tmp(tmp2);
+    }
+    if (UCOP_SET_L) {
+        /* Complete the load.  */
+        if (UCOP_REG_D == 31) {
+            gen_bx(s, tmp);
+        } else {
+            store_reg(s, UCOP_REG_D, tmp);
+        }
+    }
+}
+
+/* SWP instruction */
+static void do_swap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv addr;
+    TCGv tmp;
+    TCGv tmp2;
+
+    if ((insn & 0xff003fe0) != 0x40000120) {
+        ILLEGAL;
+    }
+
+    /* ??? This is not really atomic.  However we know
+       we never have multiple CPUs running in parallel,
+       so it is good enough.  */
+    addr = load_reg(s, UCOP_REG_N);
+    tmp = load_reg(s, UCOP_REG_M);
+    if (UCOP_SET_B) {
+        tmp2 = gen_ld8u(addr, IS_USER(s));
+        gen_st8(tmp, addr, IS_USER(s));
+    } else {
+        tmp2 = gen_ld32(addr, IS_USER(s));
+        gen_st32(tmp, addr, IS_USER(s));
+    }
+    dead_tmp(addr);
+    store_reg(s, UCOP_REG_D, tmp2);
+}
+
+/* load/store hw/sb */
+static void do_ldst_hwsb(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv addr;
+    TCGv tmp;
+
+    if (UCOP_SH_OP == 0) {
+        do_swap(env, s, insn);
+        return;
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+    if (UCOP_SET_P) {
+        gen_add_datah_offset(s, insn, addr);
+    }
+
+    if (UCOP_SET_L) { /* load */
+        switch (UCOP_SH_OP) {
+        case 1:
+            tmp = gen_ld16u(addr, IS_USER(s));
+            break;
+        case 2:
+            tmp = gen_ld8s(addr, IS_USER(s));
+            break;
+        default: /* see do_swap */
+        case 3:
+            tmp = gen_ld16s(addr, IS_USER(s));
+            break;
+        }
+    } else { /* store */
+        if (UCOP_SH_OP != 1) {
+            ILLEGAL;
+        }
+        tmp = load_reg(s, UCOP_REG_D);
+        gen_st16(tmp, addr, IS_USER(s));
+    }
+    /* Perform base writeback before the loaded value to
+       ensure correct behavior with overlapping index registers. */
+    if (!UCOP_SET_P) {
+        gen_add_datah_offset(s, insn, addr);
+        store_reg(s, UCOP_REG_N, addr);
+    } else if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+    if (UCOP_SET_L) {
+        /* Complete the load.  */
+        store_reg(s, UCOP_REG_D, tmp);
+    }
+}
+
+/* load/store multiple words */
+static void do_ldst_m(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val, i;
+    int j, n, reg, user, loaded_base;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv addr;
+    TCGv loaded_var;
+
+    if (UCOP_SET(7)) {
+        ILLEGAL;
+    }
+    /* XXX: store correct base if write back */
+    user = 0;
+    if (UCOP_SET_B) { /* S bit in instruction table */
+        if (IS_USER(s)) {
+            ILLEGAL; /* only usable in supervisor mode */
+        }
+        if (UCOP_SET(18) == 0) { /* pc reg */
+            user = 1;
+        }
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+
+    /* compute total size */
+    loaded_base = 0;
+    TCGV_UNUSED(loaded_var);
+    n = 0;
+    for (i = 0; i < 6; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+    for (i = 9; i < 19; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+    /* XXX: test invalid n == 0 case ? */
+    if (UCOP_SET_U) {
+        if (UCOP_SET_P) {
+            /* pre increment */
+            tcg_gen_addi_i32(addr, addr, 4);
+        } else {
+            /* post increment */
+        }
+    } else {
+        if (UCOP_SET_P) {
+            /* pre decrement */
+            tcg_gen_addi_i32(addr, addr, -(n * 4));
+        } else {
+            /* post decrement */
+            if (n != 1) {
+                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+            }
+        }
+    }
+
+    j = 0;
+    reg = UCOP_SET(6) ? 16 : 0;
+    for (i = 0; i < 19; i++, reg++) {
+        if (i == 6) {
+            i = i + 3;
+        }
+        if (UCOP_SET(i)) {
+            if (UCOP_SET_L) { /* load */
+                tmp = gen_ld32(addr, IS_USER(s));
+                if (reg == 31) {
+                    gen_bx(s, tmp);
+                } else if (user) {
+                    tmp2 = tcg_const_i32(reg);
+                    gen_helper_set_user_reg(tmp2, tmp);
+                    tcg_temp_free_i32(tmp2);
+                    dead_tmp(tmp);
+                } else if (reg == UCOP_REG_N) {
+                    loaded_var = tmp;
+                    loaded_base = 1;
+                } else {
+                    store_reg(s, reg, tmp);
+                }
+            } else { /* store */
+                if (reg == 31) {
+                    /* special case: r31 = PC + 4 */
+                    val = (long)s->pc;
+                    tmp = new_tmp();
+                    tcg_gen_movi_i32(tmp, val);
+                } else if (user) {
+                    tmp = new_tmp();
+                    tmp2 = tcg_const_i32(reg);
+                    gen_helper_get_user_reg(tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                } else {
+                    tmp = load_reg(s, reg);
+                }
+                gen_st32(tmp, addr, IS_USER(s));
+            }
+            j++;
+            /* no need to add after the last transfer */
+            if (j != n) {
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+        }
+    }
+    if (UCOP_SET_W) { /* write back */
+        if (UCOP_SET_U) {
+            if (UCOP_SET_P) {
+                /* pre increment */
+            } else {
+                /* post increment */
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+        } else {
+            if (UCOP_SET_P) {
+                /* pre decrement */
+                if (n != 1) {
+                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                }
+            } else {
+                /* post decrement */
+                tcg_gen_addi_i32(addr, addr, -(n * 4));
+            }
+        }
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+    if (loaded_base) {
+        store_reg(s, UCOP_REG_N, loaded_var);
+    }
+    if (UCOP_SET_B && !user) {
+        /* Restore ASR from BSR.  */
+        tmp = load_cpu_field(bsr);
+        gen_set_asr(tmp, 0xffffffff);
+        dead_tmp(tmp);
+        s->is_jmp = DISAS_UPDATE;
+    }
+}
+
+/* branch (and link) */
+static void do_branch(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val;
+    int32_t offset;
+    TCGv tmp;
+
+    if (UCOP_COND == 0xf) {
+        ILLEGAL;
+    }
+
+    if (UCOP_COND != 0xe) {
+        /* if not always execute, we generate a conditional jump to
+           next instruction */
+        s->condlabel = gen_new_label();
+        gen_test_cc(UCOP_COND ^ 1, s->condlabel);
+        s->condjmp = 1;
+    }
+
+    val = (int32_t)s->pc;
+    if (UCOP_SET_L) {
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, val);
+        store_reg(s, 30, tmp);
+    }
+    offset = (((int32_t)insn << 8) >> 8);
+    val += (offset << 2); /* unicore is pc+4 */
+    gen_jmp(s, val);
+}
+
+static void disas_uc32_insn(CPUState *env, DisasContext *s)
+{
+    unsigned int insn;
+
+    insn = ldl_code(s->pc);
+    s->pc += 4;
+
+    /* UniCore instructions class:
+     * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx
+     * AAA  : see switch case
+     * BBBB : opcodes or cond or PUBW
+     * C    : S OR L
+     * D    : 8
+     * E    : 5
+     */
+    switch (insn >> 29) {
+    case 0b000:
+        if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
+            do_mult(env, s, insn);
+            break;
+        }
+
+        if (UCOP_SET(8)) {
+            do_misc(env, s, insn);
+            break;
+        }
+    case 0b001:
+        if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
+            do_misc(env, s, insn);
+            break;
+        }
+        do_datap(env, s, insn);
+        break;
+
+    case 0b010:
+        if (UCOP_SET(8) && UCOP_SET(5)) {
+            do_ldst_hwsb(env, s, insn);
+            break;
+        }
+        if (UCOP_SET(8) || UCOP_SET(5)) {
+            ILLEGAL;
+        }
+    case 0b011:
+        do_ldst_ir(env, s, insn);
+        break;
+
+    case 0b100:
+        if (UCOP_SET(8)) {
+            ILLEGAL; /* extended instructions */
+        }
+        do_ldst_m(env, s, insn);
+        break;
+    case 0b101:
+        do_branch(env, s, insn);
+        break;
+    case 0b110:
+        /* Coprocessor.  */
+        disas_coproc_insn(env, s, insn);
+        break;
+    case 0b111:
+        if (!UCOP_SET(28)) {
+            disas_coproc_insn(env, s, insn);
+            break;
+        }
+        if ((insn & 0xff000000) == 0xff000000) { /* syscall */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_SYSCALL;
+            break;
+        }
+        ILLEGAL;
+    }
+
+    return;
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+   basic block 'tb'. If search_pc is TRUE, also generate PC
+   information for each intermediate instruction. */
+static inline void gen_intermediate_code_internal(CPUState *env,
+        TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
+    uint16_t *gen_opc_end;
+    int j, lj;
+    target_ulong pc_start;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    num_temps = 0;
+
+    pc_start = tb->pc;
+
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->condjmp = 0;
+    cpu_F0s = tcg_temp_new_i32();
+    cpu_F1s = tcg_temp_new_i32();
+    cpu_F0d = tcg_temp_new_i64();
+    cpu_F1d = tcg_temp_new_i64();
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    gen_icount_start();
+    do {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
+                    gen_set_pc_im(dc->pc);
+                    gen_exception(EXCP_DEBUG);
+                    dc->is_jmp = DISAS_JUMP;
+                    /* Advance PC so that clearing the breakpoint will
+                       invalidate this TB.  */
+                    dc->pc += 2; /* FIXME */
+                    goto done_generating;
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        disas_uc32_insn(env, dc);
+
+        if (num_temps) {
+            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
+            num_temps = 0;
+        }
+
+        if (dc->condjmp && !dc->is_jmp) {
+            gen_set_label(dc->condlabel);
+            dc->condjmp = 0;
+        }
+        /* Translation stops when a conditional branch is encountered.
+         * Otherwise the subsequent code could get translated several times.
+         * Also stop translation when a page boundary is reached.  This
+         * ensures prefetch aborts occur at the right place.  */
+        num_insns++;
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+             !env->singlestep_enabled &&
+             !singlestep &&
+             dc->pc < next_page_start &&
+             num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        if (dc->condjmp) {
+            /* FIXME:  This can theoretically happen with self-modifying
+               code.  */
+            cpu_abort(env, "IO on conditional branch instruction");
+        }
+        gen_io_end();
+    }
+
+    /* At this stage dc->condjmp will only be set when the skipped
+       instruction was a conditional branch or trap, and the PC has
+       already been written.  */
+    if (unlikely(env->singlestep_enabled)) {
+        /* Make sure the pc is updated, and raise a debug exception.  */
+        if (dc->condjmp) {
+            if (dc->is_jmp == DISAS_SYSCALL) {
+                gen_exception(UC32_EXCP_PRIV);
+            } else {
+                gen_exception(EXCP_DEBUG);
+            }
+            gen_set_label(dc->condlabel);
+        }
+        if (dc->condjmp || !dc->is_jmp) {
+            gen_set_pc_im(dc->pc);
+            dc->condjmp = 0;
+        }
+        if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) {
+            gen_exception(UC32_EXCP_PRIV);
+        } else {
+            gen_exception(EXCP_DEBUG);
+        }
+    } else {
+        /* While branches must always occur at the end of an IT block,
+           there are a few other things that can cause us to terminate
+           the TB in the middel of an IT block:
+            - Exception generating instructions (bkpt, swi, undefined).
+            - Page boundaries.
+            - Hardware watchpoints.
+           Hardware breakpoints have already been handled and skip this code.
+         */
+        switch (dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 1, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+        case DISAS_UPDATE:
+            /* indicate that the hash table must be used to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        case DISAS_SYSCALL:
+            gen_exception(UC32_EXCP_PRIV);
+            break;
+        }
+        if (dc->condjmp) {
+            gen_set_label(dc->condlabel);
+            gen_goto_tb(dc, 1, dc->pc);
+            dc->condjmp = 0;
+        }
+    }
+
+done_generating:
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\n");
+    }
+#endif
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j) {
+            gen_opc_instr_start[lj++] = 0;
+        }
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+static const char *cpu_mode_names[16] = {
+    "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP",
+    "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
+};
+
+#define UCF64_DUMP_STATE
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+        int flags)
+{
+    int i;
+#ifdef UCF64_DUMP_STATE
+    union {
+        uint32_t i;
+        float s;
+    } s0, s1;
+    CPU_DoubleU d;
+    /* ??? This assumes float64 and double have the same layout.
+       Oh well, it's only debug dumps.  */
+    union {
+        float64 f64;
+        double d;
+    } d0;
+#endif
+    uint32_t psr;
+
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+    psr = cpu_asr_read(env);
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n",
+                psr,
+                psr & (1 << 31) ? 'N' : '-',
+                psr & (1 << 30) ? 'Z' : '-',
+                psr & (1 << 29) ? 'C' : '-',
+                psr & (1 << 28) ? 'V' : '-',
+                cpu_mode_names[psr & 0xf]);
+
+#ifdef UCF64_DUMP_STATE
+    for (i = 0; i < 16; i++) {
+        d.d = env->ucf64.regs[i];
+        s0.i = d.l.lower;
+        s1.i = d.l.upper;
+        d0.f64 = d.d;
+        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n",
+                    i * 2, (int)s0.i, s0.s,
+                    i * 2 + 1, (int)s1.i, s1.s,
+                    i, (uint64_t)d0.f64, d0.d);
+    }
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
+#endif
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->regs[31] = gen_opc_pc[pc_pos];
+}
diff --git a/qemu-0.15.x/targphys.h b/qemu-0.15.x/targphys.h
new file mode 100644
index 0000000..95648d6
--- /dev/null
+++ b/qemu-0.15.x/targphys.h
@@ -0,0 +1,21 @@
+/* Define target_phys_addr_t if it exists.  */
+
+#ifndef TARGPHYS_H
+#define TARGPHYS_H
+
+#ifdef TARGET_PHYS_ADDR_BITS
+/* target_phys_addr_t is the type of a physical address (its size can
+   be different from 'target_ulong').  */
+
+#if TARGET_PHYS_ADDR_BITS == 32
+typedef uint32_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT32_MAX
+#define TARGET_FMT_plx "%08x"
+#elif TARGET_PHYS_ADDR_BITS == 64
+typedef uint64_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT64_MAX
+#define TARGET_FMT_plx "%016" PRIx64
+#endif
+#endif
+
+#endif
diff --git a/qemu-0.15.x/tcg-runtime.c b/qemu-0.15.x/tcg-runtime.c
new file mode 100644
index 0000000..abfc364
--- /dev/null
+++ b/qemu-0.15.x/tcg-runtime.c
@@ -0,0 +1,85 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 <stdint.h>
+
+#include "tcg/tcg-runtime.h"
+
+/* 32-bit helpers */
+
+int32_t tcg_helper_div_i32(int32_t arg1, int32_t arg2)
+{
+    return arg1 / arg2;
+}
+
+int32_t tcg_helper_rem_i32(int32_t arg1, int32_t arg2)
+{
+    return arg1 % arg2;
+}
+
+uint32_t tcg_helper_divu_i32(uint32_t arg1, uint32_t arg2)
+{
+    return arg1 / arg2;
+}
+
+uint32_t tcg_helper_remu_i32(uint32_t arg1, uint32_t arg2)
+{
+    return arg1 % arg2;
+}
+
+/* 64-bit helpers */
+
+int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2)
+{
+    return arg1 << arg2;
+}
+
+int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2)
+{
+    return (uint64_t)arg1 >> arg2;
+}
+
+int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2)
+{
+    return arg1 >> arg2;
+}
+
+int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2)
+{
+    return arg1 / arg2;
+}
+
+int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2)
+{
+    return arg1 % arg2;
+}
+
+uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2)
+{
+    return arg1 / arg2;
+}
+
+uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2)
+{
+    return arg1 % arg2;
+}
diff --git a/qemu-0.15.x/tcg/LICENSE b/qemu-0.15.x/tcg/LICENSE
new file mode 100644
index 0000000..be817fa
--- /dev/null
+++ b/qemu-0.15.x/tcg/LICENSE
@@ -0,0 +1,3 @@
+All the files in this directory and subdirectories are released under
+a BSD like license (see header in each file). No other license is
+accepted.
diff --git a/qemu-0.15.x/tcg/README b/qemu-0.15.x/tcg/README
new file mode 100644
index 0000000..cfdfd96
--- /dev/null
+++ b/qemu-0.15.x/tcg/README
@@ -0,0 +1,519 @@
+Tiny Code Generator - Fabrice Bellard.
+
+1) Introduction
+
+TCG (Tiny Code Generator) began as a generic backend for a C
+compiler. It was simplified to be used in QEMU. It also has its roots
+in the QOP code generator written by Paul Brook. 
+
+2) Definitions
+
+The TCG "target" is the architecture for which we generate the
+code. It is of course not the same as the "target" of QEMU which is
+the emulated architecture. As TCG started as a generic C backend used
+for cross compiling, it is assumed that the TCG target is different
+from the host, although it is never the case for QEMU.
+
+A TCG "function" corresponds to a QEMU Translated Block (TB).
+
+A TCG "temporary" is a variable only live in a basic
+block. Temporaries are allocated explicitly in each function.
+
+A TCG "local temporary" is a variable only live in a function. Local
+temporaries are allocated explicitly in each function.
+
+A TCG "global" is a variable which is live in all the functions
+(equivalent of a C global variable). They are defined before the
+functions defined. A TCG global can be a memory location (e.g. a QEMU
+CPU register), a fixed host register (e.g. the QEMU CPU state pointer)
+or a memory location which is stored in a register outside QEMU TBs
+(not implemented yet).
+
+A TCG "basic block" corresponds to a list of instructions terminated
+by a branch instruction. 
+
+3) Intermediate representation
+
+3.1) Introduction
+
+TCG instructions operate on variables which are temporaries, local
+temporaries or globals. TCG instructions and variables are strongly
+typed. Two types are supported: 32 bit integers and 64 bit
+integers. Pointers are defined as an alias to 32 bit or 64 bit
+integers depending on the TCG target word size.
+
+Each instruction has a fixed number of output variable operands, input
+variable operands and always constant operands.
+
+The notable exception is the call instruction which has a variable
+number of outputs and inputs.
+
+In the textual form, output operands usually come first, followed by
+input operands, followed by constant operands. The output type is
+included in the instruction name. Constants are prefixed with a '$'.
+
+add_i32 t0, t1, t2  (t0 <- t1 + t2)
+
+3.2) Assumptions
+
+* Basic blocks
+
+- Basic blocks end after branches (e.g. brcond_i32 instruction),
+  goto_tb and exit_tb instructions.
+- Basic blocks start after the end of a previous basic block, or at a
+  set_label instruction.
+
+After the end of a basic block, the content of temporaries is
+destroyed, but local temporaries and globals are preserved.
+
+* Floating point types are not supported yet
+
+* Pointers: depending on the TCG target, pointer size is 32 bit or 64
+  bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or
+  TCG_TYPE_I64.
+
+* Helpers:
+
+Using the tcg_gen_helper_x_y it is possible to call any function
+taking i32, i64 or pointer types. By default, before calling a helper,
+all globals are stored at their canonical location and it is assumed
+that the function can modify them. This can be overridden by the
+TCG_CALL_CONST function modifier. By default, the helper is allowed to
+modify the CPU state or raise an exception. This can be overridden by
+the TCG_CALL_PURE function modifier, in which case the call to the
+function is removed if the return value is not used.
+
+On some TCG targets (e.g. x86), several calling conventions are
+supported.
+
+* Branches:
+
+Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an
+explicit address. Conditional branches can only jump to labels.
+
+3.3) Code Optimizations
+
+When generating instructions, you can count on at least the following
+optimizations:
+
+- Single instructions are simplified, e.g.
+
+   and_i32 t0, t0, $0xffffffff
+    
+  is suppressed.
+
+- A liveness analysis is done at the basic block level. The
+  information is used to suppress moves from a dead variable to
+  another one. It is also used to remove instructions which compute
+  dead results. The later is especially useful for condition code
+  optimization in QEMU.
+
+  In the following example:
+
+  add_i32 t0, t1, t2
+  add_i32 t0, t0, $1
+  mov_i32 t0, $1
+
+  only the last instruction is kept.
+
+3.4) Instruction Reference
+
+********* Function call
+
+* call <ret> <params> ptr
+
+call function 'ptr' (pointer type)
+
+<ret> optional 32 bit or 64 bit return value
+<params> optional 32 bit or 64 bit parameters
+
+********* Jumps/Labels
+
+* jmp t0
+
+Absolute jump to address t0 (pointer type).
+
+* set_label $label
+
+Define label 'label' at the current program point.
+
+* br $label
+
+Jump to label.
+
+* brcond_i32/i64 cond, t0, t1, label
+
+Conditional jump if t0 cond t1 is true. cond can be:
+    TCG_COND_EQ
+    TCG_COND_NE
+    TCG_COND_LT /* signed */
+    TCG_COND_GE /* signed */
+    TCG_COND_LE /* signed */
+    TCG_COND_GT /* signed */
+    TCG_COND_LTU /* unsigned */
+    TCG_COND_GEU /* unsigned */
+    TCG_COND_LEU /* unsigned */
+    TCG_COND_GTU /* unsigned */
+
+********* Arithmetic
+
+* add_i32/i64 t0, t1, t2
+
+t0=t1+t2
+
+* sub_i32/i64 t0, t1, t2
+
+t0=t1-t2
+
+* neg_i32/i64 t0, t1
+
+t0=-t1 (two's complement)
+
+* mul_i32/i64 t0, t1, t2
+
+t0=t1*t2
+
+* div_i32/i64 t0, t1, t2
+
+t0=t1/t2 (signed). Undefined behavior if division by zero or overflow.
+
+* divu_i32/i64 t0, t1, t2
+
+t0=t1/t2 (unsigned). Undefined behavior if division by zero.
+
+* rem_i32/i64 t0, t1, t2
+
+t0=t1%t2 (signed). Undefined behavior if division by zero or overflow.
+
+* remu_i32/i64 t0, t1, t2
+
+t0=t1%t2 (unsigned). Undefined behavior if division by zero.
+
+********* Logical
+
+* and_i32/i64 t0, t1, t2
+
+t0=t1&t2
+
+* or_i32/i64 t0, t1, t2
+
+t0=t1|t2
+
+* xor_i32/i64 t0, t1, t2
+
+t0=t1^t2
+
+* not_i32/i64 t0, t1
+
+t0=~t1
+
+* andc_i32/i64 t0, t1, t2
+
+t0=t1&~t2
+
+* eqv_i32/i64 t0, t1, t2
+
+t0=~(t1^t2), or equivalently, t0=t1^~t2
+
+* nand_i32/i64 t0, t1, t2
+
+t0=~(t1&t2)
+
+* nor_i32/i64 t0, t1, t2
+
+t0=~(t1|t2)
+
+* orc_i32/i64 t0, t1, t2
+
+t0=t1|~t2
+
+********* Shifts/Rotates
+
+* shl_i32/i64 t0, t1, t2
+
+t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* shr_i32/i64 t0, t1, t2
+
+t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* sar_i32/i64 t0, t1, t2
+
+t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* rotl_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* rotr_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+********* Misc
+
+* mov_i32/i64 t0, t1
+
+t0 = t1
+
+Move t1 to t0 (both operands must have the same type).
+
+* ext8s_i32/i64 t0, t1
+ext8u_i32/i64 t0, t1
+ext16s_i32/i64 t0, t1
+ext16u_i32/i64 t0, t1
+ext32s_i64 t0, t1
+ext32u_i64 t0, t1
+
+8, 16 or 32 bit sign/zero extension (both operands must have the same type)
+
+* bswap16_i32/i64 t0, t1
+
+16 bit byte swap on a 32/64 bit value. It assumes that the two/six high order
+bytes are set to zero.
+
+* bswap32_i32/i64 t0, t1
+
+32 bit byte swap on a 32/64 bit value. With a 64 bit value, it assumes that
+the four high order bytes are set to zero.
+
+* bswap64_i64 t0, t1
+
+64 bit byte swap
+
+* discard_i32/i64 t0
+
+Indicate that the value of t0 won't be used later. It is useful to
+force dead code elimination.
+
+* deposit_i32/i64 dest, t1, t2, pos, len
+
+Deposit T2 as a bitfield into T1, placing the result in DEST.
+The bitfield is described by POS/LEN, which are immediate values:
+
+  LEN - the length of the bitfield
+  POS - the position of the first bit, counting from the LSB
+
+For example, pos=8, len=4 indicates a 4-bit field at bit 8.
+This operation would be equivalent to
+
+  dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
+
+
+********* Conditional moves
+
+* setcond_i32/i64 cond, dest, t1, t2
+
+dest = (t1 cond t2)
+
+Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0.
+
+********* Type conversions
+
+* ext_i32_i64 t0, t1
+Convert t1 (32 bit) to t0 (64 bit) and does sign extension
+
+* extu_i32_i64 t0, t1
+Convert t1 (32 bit) to t0 (64 bit) and does zero extension
+
+* trunc_i64_i32 t0, t1
+Truncate t1 (64 bit) to t0 (32 bit)
+
+* concat_i32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half
+from t2 (32 bit).
+
+* concat32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half
+from t2 (64 bit).
+
+********* Load/Store
+
+* ld_i32/i64 t0, t1, offset
+ld8s_i32/i64 t0, t1, offset
+ld8u_i32/i64 t0, t1, offset
+ld16s_i32/i64 t0, t1, offset
+ld16u_i32/i64 t0, t1, offset
+ld32s_i64 t0, t1, offset
+ld32u_i64 t0, t1, offset
+
+t0 = read(t1 + offset)
+Load 8, 16, 32 or 64 bits with or without sign extension from host memory. 
+offset must be a constant.
+
+* st_i32/i64 t0, t1, offset
+st8_i32/i64 t0, t1, offset
+st16_i32/i64 t0, t1, offset
+st32_i64 t0, t1, offset
+
+write(t0, t1 + offset)
+Write 8, 16, 32 or 64 bits to host memory.
+
+********* 64-bit target on 32-bit host support
+
+The following opcodes are internal to TCG.  Thus they are to be implemented by
+32-bit host code generators, but are not to be emitted by guest translators.
+They are emitted as needed by inline functions within "tcg-op.h".
+
+* brcond2_i32 cond, t0_low, t0_high, t1_low, t1_high, label
+
+Similar to brcond, except that the 64-bit values T0 and T1
+are formed from two 32-bit arguments.
+
+* add2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+* sub2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+
+Similar to add/sub, except that the 64-bit inputs T1 and T2 are
+formed from two 32-bit arguments, and the 64-bit output T0
+is returned in two 32-bit outputs.
+
+* mulu2_i32 t0_low, t0_high, t1, t2
+
+Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding
+the full 64-bit product T0.  The later is returned in two 32-bit outputs.
+
+* setcond2_i32 cond, dest, t1_low, t1_high, t2_low, t2_high
+
+Similar to setcond, except that the 64-bit values T1 and T2 are
+formed from two 32-bit arguments.  The result is a 32-bit value.
+
+********* QEMU specific operations
+
+* exit_tb t0
+
+Exit the current TB and return the value t0 (word type).
+
+* goto_tb index
+
+Exit the current TB and jump to the TB index 'index' (constant) if the
+current TB was linked to this TB. Otherwise execute the next
+instructions.
+
+* qemu_ld8u t0, t1, flags
+qemu_ld8s t0, t1, flags
+qemu_ld16u t0, t1, flags
+qemu_ld16s t0, t1, flags
+qemu_ld32 t0, t1, flags
+qemu_ld32u t0, t1, flags
+qemu_ld32s t0, t1, flags
+qemu_ld64 t0, t1, flags
+
+Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU address
+type. 'flags' contains the QEMU memory index (selects user or kernel access)
+for example.
+
+Note that "qemu_ld32" implies a 32-bit result, while "qemu_ld32u" and
+"qemu_ld32s" imply a 64-bit result appropriately extended from 32 bits.
+
+* qemu_st8 t0, t1, flags
+qemu_st16 t0, t1, flags
+qemu_st32 t0, t1, flags
+qemu_st64 t0, t1, flags
+
+Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU
+address type. 'flags' contains the QEMU memory index (selects user or
+kernel access) for example.
+
+Note 1: Some shortcuts are defined when the last operand is known to be
+a constant (e.g. addi for add, movi for mov).
+
+Note 2: When using TCG, the opcodes must never be generated directly
+as some of them may not be available as "real" opcodes. Always use the
+function tcg_gen_xxx(args).
+
+4) Backend
+
+tcg-target.h contains the target specific definitions. tcg-target.c
+contains the target specific code.
+
+4.1) Assumptions
+
+The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or
+64 bit. It is expected that the pointer has the same size as the word.
+
+On a 32 bit target, all 64 bit operations are converted to 32 bits. A
+few specific operations must be implemented to allow it (see add2_i32,
+sub2_i32, brcond2_i32).
+
+Floating point operations are not supported in this version. A
+previous incarnation of the code generator had full support of them,
+but it is better to concentrate on integer operations first.
+
+On a 64 bit target, no assumption is made in TCG about the storage of
+the 32 bit values in 64 bit registers.
+
+4.2) Constraints
+
+GCC like constraints are used to define the constraints of every
+instruction. Memory constraints are not supported in this
+version. Aliases are specified in the input operands as for GCC.
+
+The same register may be used for both an input and an output, even when
+they are not explicitly aliased.  If an op expands to multiple target
+instructions then care must be taken to avoid clobbering input values.
+GCC style "early clobber" outputs are not currently supported.
+
+A target can define specific register or constant constraints. If an
+operation uses a constant input constraint which does not allow all
+constants, it must also accept registers in order to have a fallback.
+
+The movi_i32 and movi_i64 operations must accept any constants.
+
+The mov_i32 and mov_i64 operations must accept any registers of the
+same type.
+
+The ld/st instructions must accept signed 32 bit constant offsets. It
+can be implemented by reserving a specific register to compute the
+address if the offset is too big.
+
+The ld/st instructions must accept any destination (ld) or source (st)
+register.
+
+4.3) Function call assumptions
+
+- The only supported types for parameters and return value are: 32 and
+  64 bit integers and pointer.
+- The stack grows downwards.
+- The first N parameters are passed in registers.
+- The next parameters are passed on the stack by storing them as words.
+- Some registers are clobbered during the call. 
+- The function can return 0 or 1 value in registers. On a 32 bit
+  target, functions must be able to return 2 values in registers for
+  64 bit return type.
+
+5) Recommended coding rules for best performance
+
+- Use globals to represent the parts of the QEMU CPU state which are
+  often modified, e.g. the integer registers and the condition
+  codes. TCG will be able to use host registers to store them.
+
+- Avoid globals stored in fixed registers. They must be used only to
+  store the pointer to the CPU state and possibly to store a pointer
+  to a register window.
+
+- Use temporaries. Use local temporaries only when really needed,
+  e.g. when you need to use a value after a jump. Local temporaries
+  introduce a performance hit in the current TCG implementation: their
+  content is saved to memory at end of each basic block.
+
+- Free temporaries and local temporaries when they are no longer used
+  (tcg_temp_free). Since tcg_const_x() also creates a temporary, you
+  should free it after it is used. Freeing temporaries does not yield
+  a better generated code, but it reduces the memory usage of TCG and
+  the speed of the translation.
+
+- Don't hesitate to use helpers for complicated or seldom used target
+  instructions. There is little performance advantage in using TCG to
+  implement target instructions taking more than about twenty TCG
+  instructions. Note that this rule of thumb is more applicable to
+  helpers doing complex logic or arithmetic, where the C compiler has
+  scope to do a good job of optimisation; it is less relevant where
+  the instruction is mostly doing loads and stores, and in those cases
+  inline TCG may still be faster for longer sequences.
+
+- The hard limit on the number of TCG instructions you can generate
+  per target instruction is set by MAX_OP_PER_INSTR in exec-all.h --
+  you cannot exceed this without risking a buffer overrun.
+
+- Use the 'discard' instruction if you know that TCG won't be able to
+  prove that a given global is "dead" at a given program point. The
+  x86 target uses it to improve the condition codes optimisation.
diff --git a/qemu-0.15.x/tcg/TODO b/qemu-0.15.x/tcg/TODO
new file mode 100644
index 0000000..0747847
--- /dev/null
+++ b/qemu-0.15.x/tcg/TODO
@@ -0,0 +1,14 @@
+- Add new instructions such as: clz, ctz, popcnt.
+
+- See if it is worth exporting mul2, mulu2, div2, divu2. 
+
+- Support of globals saved in fixed registers between TBs.
+
+Ideas:
+
+- Move the slow part of the qemu_ld/st ops after the end of the TB.
+
+- Change exception syntax to get closer to QOP system (exception
+  parameters given with a specific instruction).
+
+- Add float and vector support.
diff --git a/qemu-0.15.x/tcg/arm/tcg-target.c b/qemu-0.15.x/tcg/arm/tcg-target.c
new file mode 100644
index 0000000..93eb0f1
--- /dev/null
+++ b/qemu-0.15.x/tcg/arm/tcg-target.c
@@ -0,0 +1,1865 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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(__ARM_ARCH_7__) ||  \
+    defined(__ARM_ARCH_7A__) || \
+    defined(__ARM_ARCH_7EM__) || \
+    defined(__ARM_ARCH_7M__) || \
+    defined(__ARM_ARCH_7R__)
+#define USE_ARMV7_INSTRUCTIONS
+#endif
+
+#if defined(USE_ARMV7_INSTRUCTIONS) || \
+    defined(__ARM_ARCH_6J__) || \
+    defined(__ARM_ARCH_6K__) || \
+    defined(__ARM_ARCH_6T2__) || \
+    defined(__ARM_ARCH_6Z__) || \
+    defined(__ARM_ARCH_6ZK__)
+#define USE_ARMV6_INSTRUCTIONS
+#endif
+
+#if defined(USE_ARMV6_INSTRUCTIONS) || \
+    defined(__ARM_ARCH_5T__) || \
+    defined(__ARM_ARCH_5TE__) || \
+    defined(__ARM_ARCH_5TEJ__)
+#define USE_ARMV5_INSTRUCTIONS
+#endif
+
+#ifdef USE_ARMV5_INSTRUCTIONS
+static const int use_armv5_instructions = 1;
+#else
+static const int use_armv5_instructions = 0;
+#endif
+#undef USE_ARMV5_INSTRUCTIONS
+
+#ifdef USE_ARMV6_INSTRUCTIONS
+static const int use_armv6_instructions = 1;
+#else
+static const int use_armv6_instructions = 0;
+#endif
+#undef USE_ARMV6_INSTRUCTIONS
+
+#ifdef USE_ARMV7_INSTRUCTIONS
+static const int use_armv7_instructions = 1;
+#else
+static const int use_armv7_instructions = 0;
+#endif
+#undef USE_ARMV7_INSTRUCTIONS
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "%r0",
+    "%r1",
+    "%r2",
+    "%r3",
+    "%r4",
+    "%r5",
+    "%r6",
+    "%r7",
+    "%r8",
+    "%r9",
+    "%r10",
+    "%r11",
+    "%r12",
+    "%r13",
+    "%r14",
+    "%pc",
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R13,
+    TCG_REG_R0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R12,
+    TCG_REG_R14,
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+    TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3
+};
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_R0, TCG_REG_R1
+};
+
+static inline void reloc_abs32(void *code_ptr, tcg_target_long target)
+{
+    *(uint32_t *) code_ptr = target;
+}
+
+static inline void reloc_pc24(void *code_ptr, tcg_target_long target)
+{
+    uint32_t offset = ((target - ((tcg_target_long) code_ptr + 8)) >> 2);
+
+    *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff)
+                             | (offset & 0xffffff);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                tcg_target_long value, tcg_target_long addend)
+{
+    switch (type) {
+    case R_ARM_ABS32:
+        reloc_abs32(code_ptr, value);
+        break;
+
+    case R_ARM_CALL:
+    case R_ARM_JUMP24:
+    default:
+        tcg_abort();
+
+    case R_ARM_PC24:
+        reloc_pc24(code_ptr, value);
+        break;
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'I':
+         ct->ct |= TCG_CT_CONST_ARM;
+         break;
+
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+        break;
+
+    /* qemu_ld address */
+    case 'l':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+#ifdef CONFIG_SOFTMMU
+        /* r0 and r1 will be overwritten when reading the tlb entry,
+           so don't use these. */
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#endif
+        break;
+    case 'L':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+#ifdef CONFIG_SOFTMMU
+        /* r1 is still needed to load data_reg or data_reg2,
+           so don't use it. */
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#endif
+        break;
+
+    /* qemu_st address & data_reg */
+    case 's':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+        /* r0 and r1 will be overwritten when reading the tlb entry
+           (softmmu only) and doing the byte swapping, so don't
+           use these. */
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+        break;
+    /* qemu_st64 data_reg2 */
+    case 'S':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+        /* r0 and r1 will be overwritten when reading the tlb entry
+            (softmmu only) and doing the byte swapping, so don't
+            use these. */
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#ifdef CONFIG_SOFTMMU
+        /* r2 is still needed to load data_reg, so don't use it. */
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#endif
+        break;
+
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+
+    return 0;
+}
+
+static inline uint32_t rotl(uint32_t val, int n)
+{
+  return (val << n) | (val >> (32 - n));
+}
+
+/* ARM immediates for ALU instructions are made of an unsigned 8-bit
+   right-rotated by an even amount between 0 and 30. */
+static inline int encode_imm(uint32_t imm)
+{
+    int shift;
+
+    /* simple case, only lower bits */
+    if ((imm & ~0xff) == 0)
+        return 0;
+    /* then try a simple even shift */
+    shift = ctz32(imm) & ~1;
+    if (((imm >> shift) & ~0xff) == 0)
+        return 32 - shift;
+    /* now try harder with rotations */
+    if ((rotl(imm, 2) & ~0xff) == 0)
+        return 2;
+    if ((rotl(imm, 4) & ~0xff) == 0)
+        return 4;
+    if ((rotl(imm, 6) & ~0xff) == 0)
+        return 6;
+    /* imm can't be encoded */
+    return -1;
+}
+
+static inline int check_fit_imm(uint32_t imm)
+{
+    return encode_imm(imm) >= 0;
+}
+
+/* Test if a constant matches the constraint.
+ * TODO: define constraints for:
+ *
+ * ldr/str offset:   between -0xfff and 0xfff
+ * ldrh/strh offset: between -0xff and 0xff
+ * mov operand2:     values represented with x << (2 * y), x < 0x100
+ * add, sub, eor...: ditto
+ */
+static inline int tcg_target_const_match(tcg_target_long val,
+                const TCGArgConstraint *arg_ct)
+{
+    int ct;
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val))
+        return 1;
+    else
+        return 0;
+}
+
+enum arm_data_opc_e {
+    ARITH_AND = 0x0,
+    ARITH_EOR = 0x1,
+    ARITH_SUB = 0x2,
+    ARITH_RSB = 0x3,
+    ARITH_ADD = 0x4,
+    ARITH_ADC = 0x5,
+    ARITH_SBC = 0x6,
+    ARITH_RSC = 0x7,
+    ARITH_TST = 0x8,
+    ARITH_CMP = 0xa,
+    ARITH_CMN = 0xb,
+    ARITH_ORR = 0xc,
+    ARITH_MOV = 0xd,
+    ARITH_BIC = 0xe,
+    ARITH_MVN = 0xf,
+};
+
+#define TO_CPSR(opc) \
+  ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20)
+
+#define SHIFT_IMM_LSL(im)	(((im) << 7) | 0x00)
+#define SHIFT_IMM_LSR(im)	(((im) << 7) | 0x20)
+#define SHIFT_IMM_ASR(im)	(((im) << 7) | 0x40)
+#define SHIFT_IMM_ROR(im)	(((im) << 7) | 0x60)
+#define SHIFT_REG_LSL(rs)	(((rs) << 8) | 0x10)
+#define SHIFT_REG_LSR(rs)	(((rs) << 8) | 0x30)
+#define SHIFT_REG_ASR(rs)	(((rs) << 8) | 0x50)
+#define SHIFT_REG_ROR(rs)	(((rs) << 8) | 0x70)
+
+enum arm_cond_code_e {
+    COND_EQ = 0x0,
+    COND_NE = 0x1,
+    COND_CS = 0x2,	/* Unsigned greater or equal */
+    COND_CC = 0x3,	/* Unsigned less than */
+    COND_MI = 0x4,	/* Negative */
+    COND_PL = 0x5,	/* Zero or greater */
+    COND_VS = 0x6,	/* Overflow */
+    COND_VC = 0x7,	/* No overflow */
+    COND_HI = 0x8,	/* Unsigned greater than */
+    COND_LS = 0x9,	/* Unsigned less or equal */
+    COND_GE = 0xa,
+    COND_LT = 0xb,
+    COND_GT = 0xc,
+    COND_LE = 0xd,
+    COND_AL = 0xe,
+};
+
+static const uint8_t tcg_cond_to_arm_cond[10] = {
+    [TCG_COND_EQ] = COND_EQ,
+    [TCG_COND_NE] = COND_NE,
+    [TCG_COND_LT] = COND_LT,
+    [TCG_COND_GE] = COND_GE,
+    [TCG_COND_LE] = COND_LE,
+    [TCG_COND_GT] = COND_GT,
+    /* unsigned */
+    [TCG_COND_LTU] = COND_CC,
+    [TCG_COND_GEU] = COND_CS,
+    [TCG_COND_LEU] = COND_LS,
+    [TCG_COND_GTU] = COND_HI,
+};
+
+static inline void tcg_out_bx(TCGContext *s, int cond, int rn)
+{
+    tcg_out32(s, (cond << 28) | 0x012fff10 | rn);
+}
+
+static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
+{
+    tcg_out32(s, (cond << 28) | 0x0a000000 |
+                    (((offset - 8) >> 2) & 0x00ffffff));
+}
+
+static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
+{
+    /* We pay attention here to not modify the branch target by skipping
+       the corresponding bytes. This ensure that caches and memory are
+       kept coherent during retranslation. */
+#ifdef HOST_WORDS_BIGENDIAN
+    tcg_out8(s, (cond << 4) | 0x0a);
+    s->code_ptr += 3;
+#else
+    s->code_ptr += 3;
+    tcg_out8(s, (cond << 4) | 0x0a);
+#endif
+}
+
+static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset)
+{
+    tcg_out32(s, (cond << 28) | 0x0b000000 |
+                    (((offset - 8) >> 2) & 0x00ffffff));
+}
+
+static inline void tcg_out_blx(TCGContext *s, int cond, int rn)
+{
+    tcg_out32(s, (cond << 28) | 0x012fff30 | rn);
+}
+
+static inline void tcg_out_blx_imm(TCGContext *s, int32_t offset)
+{
+    tcg_out32(s, 0xfa000000 | ((offset & 2) << 23) |
+                (((offset - 8) >> 2) & 0x00ffffff));
+}
+
+static inline void tcg_out_dat_reg(TCGContext *s,
+                int cond, int opc, int rd, int rn, int rm, int shift)
+{
+    tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) |
+                    (rn << 16) | (rd << 12) | shift | rm);
+}
+
+static inline void tcg_out_dat_reg2(TCGContext *s,
+                int cond, int opc0, int opc1, int rd0, int rd1,
+                int rn0, int rn1, int rm0, int rm1, int shift)
+{
+    if (rd0 == rn1 || rd0 == rm1) {
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+                        (rn0 << 16) | (8 << 12) | shift | rm0);
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+                        (rn1 << 16) | (rd1 << 12) | shift | rm1);
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
+    } else {
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+                        (rn0 << 16) | (rd0 << 12) | shift | rm0);
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+                        (rn1 << 16) | (rd1 << 12) | shift | rm1);
+    }
+}
+
+static inline void tcg_out_dat_imm(TCGContext *s,
+                int cond, int opc, int rd, int rn, int im)
+{
+    tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) |
+                    (rn << 16) | (rd << 12) | im);
+}
+
+static inline void tcg_out_movi32(TCGContext *s,
+                int cond, int rd, uint32_t arg)
+{
+    /* TODO: This is very suboptimal, we can easily have a constant
+     * pool somewhere after all the instructions.  */
+    if ((int)arg < 0 && (int)arg >= -0x100) {
+        tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
+    } else if (use_armv7_instructions) {
+        /* use movw/movt */
+        /* movw */
+        tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
+                  | ((arg << 4) & 0x000f0000) | (arg & 0xfff));
+        if (arg & 0xffff0000) {
+            /* movt */
+            tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
+                      | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
+        }
+    } else {
+        int opc = ARITH_MOV;
+        int rn = 0;
+
+        do {
+            int i, rot;
+
+            i = ctz32(arg) & ~1;
+            rot = ((32 - i) << 7) & 0xf00;
+            tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot);
+            arg &= ~(0xff << i);
+
+            opc = ARITH_ORR;
+            rn = rd;
+        } while (arg);
+    }
+}
+
+static inline void tcg_out_mul32(TCGContext *s,
+                int cond, int rd, int rs, int rm)
+{
+    if (rd != rm)
+        tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
+                        (rs << 8) | 0x90 | rm);
+    else if (rd != rs)
+        tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
+                        (rm << 8) | 0x90 | rs);
+    else {
+        tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) |
+                        (rs << 8) | 0x90 | rm);
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
+    }
+}
+
+static inline void tcg_out_umull32(TCGContext *s,
+                int cond, int rd0, int rd1, int rs, int rm)
+{
+    if (rd0 != rm && rd1 != rm)
+        tcg_out32(s, (cond << 28) | 0x800090 |
+                        (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
+    else if (rd0 != rs && rd1 != rs)
+        tcg_out32(s, (cond << 28) | 0x800090 |
+                        (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
+    else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
+        tcg_out32(s, (cond << 28) | 0x800098 |
+                        (rd1 << 16) | (rd0 << 12) | (rs << 8));
+    }
+}
+
+static inline void tcg_out_smull32(TCGContext *s,
+                int cond, int rd0, int rd1, int rs, int rm)
+{
+    if (rd0 != rm && rd1 != rm)
+        tcg_out32(s, (cond << 28) | 0xc00090 |
+                        (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
+    else if (rd0 != rs && rd1 != rs)
+        tcg_out32(s, (cond << 28) | 0xc00090 |
+                        (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
+    else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
+        tcg_out32(s, (cond << 28) | 0xc00098 |
+                        (rd1 << 16) | (rd0 << 12) | (rs << 8));
+    }
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int cond,
+                                 int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* sxtb */
+        tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rn, SHIFT_IMM_LSL(24));
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rd, SHIFT_IMM_ASR(24));
+    }
+}
+
+static inline void tcg_out_ext8u(TCGContext *s, int cond,
+                                 int rd, int rn)
+{
+    tcg_out_dat_imm(s, cond, ARITH_AND, rd, rn, 0xff);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int cond,
+                                  int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* sxth */
+        tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rn, SHIFT_IMM_LSL(16));
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rd, SHIFT_IMM_ASR(16));
+    }
+}
+
+static inline void tcg_out_ext16u(TCGContext *s, int cond,
+                                  int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* uxth */
+        tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rn, SHIFT_IMM_LSL(16));
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rd, SHIFT_IMM_LSR(16));
+    }
+}
+
+static inline void tcg_out_bswap16s(TCGContext *s, int cond, int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* revsh */
+        tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, rn, SHIFT_IMM_LSL(24));
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, TCG_REG_R8, SHIFT_IMM_ASR(16));
+        tcg_out_dat_reg(s, cond, ARITH_ORR,
+                        rd, TCG_REG_R8, rn, SHIFT_IMM_LSR(8));
+    }
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, int cond, int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* rev16 */
+        tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, rn, SHIFT_IMM_LSL(24));
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        TCG_REG_R8, 0, TCG_REG_R8, SHIFT_IMM_LSR(16));
+        tcg_out_dat_reg(s, cond, ARITH_ORR,
+                        rd, TCG_REG_R8, rn, SHIFT_IMM_LSR(8));
+    }
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int cond, int rd, int rn)
+{
+    if (use_armv6_instructions) {
+        /* rev */
+        tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_EOR,
+                        TCG_REG_R8, rn, rn, SHIFT_IMM_ROR(16));
+        tcg_out_dat_imm(s, cond, ARITH_BIC,
+                        TCG_REG_R8, TCG_REG_R8, 0xff | 0x800);
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd, 0, rn, SHIFT_IMM_ROR(8));
+        tcg_out_dat_reg(s, cond, ARITH_EOR,
+                        rd, rd, TCG_REG_R8, SHIFT_IMM_LSR(8));
+    }
+}
+
+static inline void tcg_out_ld32_12(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x05900000 |
+                        (rn << 16) | (rd << 12) | (im & 0xfff));
+    else
+        tcg_out32(s, (cond << 28) | 0x05100000 |
+                        (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_st32_12(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x05800000 |
+                        (rn << 16) | (rd << 12) | (im & 0xfff));
+    else
+        tcg_out32(s, (cond << 28) | 0x05000000 |
+                        (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_ld32_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07900000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st32_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07800000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+/* Register pre-increment with base writeback.  */
+static inline void tcg_out_ld32_rwb(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07b00000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st32_rwb(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07a00000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld16u_8(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x01d000b0 |
+                        (rn << 16) | (rd << 12) |
+                        ((im & 0xf0) << 4) | (im & 0xf));
+    else
+        tcg_out32(s, (cond << 28) | 0x015000b0 |
+                        (rn << 16) | (rd << 12) |
+                        (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_st16_8(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x01c000b0 |
+                        (rn << 16) | (rd << 12) |
+                        ((im & 0xf0) << 4) | (im & 0xf));
+    else
+        tcg_out32(s, (cond << 28) | 0x014000b0 |
+                        (rn << 16) | (rd << 12) |
+                        (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld16u_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x019000b0 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st16_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x018000b0 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld16s_8(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x01d000f0 |
+                        (rn << 16) | (rd << 12) |
+                        ((im & 0xf0) << 4) | (im & 0xf));
+    else
+        tcg_out32(s, (cond << 28) | 0x015000f0 |
+                        (rn << 16) | (rd << 12) |
+                        (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld16s_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x019000f0 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld8_12(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x05d00000 |
+                        (rn << 16) | (rd << 12) | (im & 0xfff));
+    else
+        tcg_out32(s, (cond << 28) | 0x05500000 |
+                        (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_st8_12(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x05c00000 |
+                        (rn << 16) | (rd << 12) | (im & 0xfff));
+    else
+        tcg_out32(s, (cond << 28) | 0x05400000 |
+                        (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_ld8_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07d00000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st8_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x07c00000 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld8s_8(TCGContext *s, int cond,
+                int rd, int rn, tcg_target_long im)
+{
+    if (im >= 0)
+        tcg_out32(s, (cond << 28) | 0x01d000d0 |
+                        (rn << 16) | (rd << 12) |
+                        ((im & 0xf0) << 4) | (im & 0xf));
+    else
+        tcg_out32(s, (cond << 28) | 0x015000d0 |
+                        (rn << 16) | (rd << 12) |
+                        (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld8s_r(TCGContext *s, int cond,
+                int rd, int rn, int rm)
+{
+    tcg_out32(s, (cond << 28) | 0x019000d0 |
+                    (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld32u(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xfff || offset < -0xfff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_ld32_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st32(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xfff || offset < -0xfff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_st32_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld16u(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xff || offset < -0xff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_ld16u_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld16s(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xff || offset < -0xff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_ld16s_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st16(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xff || offset < -0xff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_st16_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_st16_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld8u(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xfff || offset < -0xfff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_ld8_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld8s(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xff || offset < -0xff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_ld8s_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st8(TCGContext *s, int cond,
+                int rd, int rn, int32_t offset)
+{
+    if (offset > 0xfff || offset < -0xfff) {
+        tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+        tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8);
+    } else
+        tcg_out_st8_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
+{
+    int32_t val;
+
+    if (addr & 1) {
+        /* goto to a Thumb destination isn't supported */
+        tcg_abort();
+    }
+
+    val = addr - (tcg_target_long) s->code_ptr;
+    if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
+        tcg_out_b(s, cond, val);
+    else {
+#if 1
+        tcg_abort();
+#else
+        if (cond == COND_AL) {
+            tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+            tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
+        } else {
+            tcg_out_movi32(s, cond, TCG_REG_R8, val - 8);
+            tcg_out_dat_reg(s, cond, ARITH_ADD,
+                            TCG_REG_PC, TCG_REG_PC,
+                            TCG_REG_R8, SHIFT_IMM_LSL(0));
+        }
+#endif
+    }
+}
+
+static inline void tcg_out_call(TCGContext *s, uint32_t addr)
+{
+    int32_t val;
+
+    val = addr - (tcg_target_long) s->code_ptr;
+    if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) {
+        if (addr & 1) {
+            /* Use BLX if the target is in Thumb mode */
+            if (!use_armv5_instructions) {
+                tcg_abort();
+            }
+            tcg_out_blx_imm(s, val);
+        } else {
+            tcg_out_bl(s, COND_AL, val);
+        }
+    } else {
+#if 1
+        tcg_abort();
+#else
+        if (cond == COND_AL) {
+            tcg_out_dat_imm(s, cond, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4);
+            tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+            tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
+        } else {
+            tcg_out_movi32(s, cond, TCG_REG_R9, addr);
+            tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
+                            TCG_REG_PC, SHIFT_IMM_LSL(0));
+            tcg_out_bx(s, cond, TCG_REG_R9);
+        }
+#endif
+    }
+}
+
+static inline void tcg_out_callr(TCGContext *s, int cond, int arg)
+{
+    if (use_armv5_instructions) {
+        tcg_out_blx(s, cond, arg);
+    } else {
+        tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
+                        TCG_REG_PC, SHIFT_IMM_LSL(0));
+        tcg_out_bx(s, cond, arg);
+    }
+}
+
+static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value)
+        tcg_out_goto(s, cond, l->u.value);
+    else if (cond == COND_AL) {
+        tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+        tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337);
+        s->code_ptr += 4;
+    } else {
+        /* Probably this should be preferred even for COND_AL... */
+        tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337);
+        tcg_out_b_noaddr(s, cond);
+    }
+}
+
+#ifdef CONFIG_SOFTMMU
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+#define TLB_SHIFT	(CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, data_reg2, bswap;
+#ifdef CONFIG_SOFTMMU
+    int mem_index, s_bits;
+# if TARGET_LONG_BITS == 64
+    int addr_reg2;
+# endif
+    uint32_t *label_ptr;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+    data_reg = *args++;
+    if (opc == 3)
+        data_reg2 = *args++;
+    else
+        data_reg2 = 0; /* suppress warning */
+    addr_reg = *args++;
+#ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+# endif
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    /* Should generate something like the following:
+     *  shr r8, addr_reg, #TARGET_PAGE_BITS
+     *  and r0, r8, #(CPU_TLB_SIZE - 1)   @ Assumption: CPU_TLB_BITS <= 8
+     *  add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
+     */
+#  if CPU_TLB_BITS > 8
+#   error
+#  endif
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_R8,
+                    0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
+    tcg_out_dat_imm(s, COND_AL, ARITH_AND,
+                    TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
+    tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0,
+                    TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
+    /* In the
+     *  ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))]
+     * below, the offset is likely to exceed 12 bits if mem_index != 0 and
+     * not exceed otherwise, so use an
+     *  add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
+     * before.
+     */
+    if (mem_index)
+        tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
+                        (mem_index << (TLB_SHIFT & 1)) |
+                        ((16 - (TLB_SHIFT >> 1)) << 8));
+    tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addr_read));
+    tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
+                    TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
+    /* Check alignment.  */
+    if (s_bits)
+        tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
+                        0, addr_reg, (1 << s_bits) - 1);
+#  if TARGET_LONG_BITS == 64
+    /* XXX: possibly we could use a block data load or writeback in
+     * the first access.  */
+    tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addr_read) + 4);
+    tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+                    TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
+#  endif
+    tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addend));
+
+    switch (opc) {
+    case 0:
+        tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        break;
+    case 0 | 4:
+        tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        break;
+    case 1:
+        tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        if (bswap) {
+            tcg_out_bswap16(s, COND_EQ, data_reg, data_reg);
+        }
+        break;
+    case 1 | 4:
+        if (bswap) {
+            tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+            tcg_out_bswap16s(s, COND_EQ, data_reg, data_reg);
+        } else {
+            tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        }
+        break;
+    case 2:
+    default:
+        tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        if (bswap) {
+            tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
+        }
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out_ld32_rwb(s, COND_EQ, data_reg2, TCG_REG_R1, addr_reg);
+            tcg_out_ld32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);
+            tcg_out_bswap32(s, COND_EQ, data_reg2, data_reg2);
+            tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
+        } else {
+            tcg_out_ld32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
+            tcg_out_ld32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
+        }
+        break;
+    }
+
+    label_ptr = (void *) s->code_ptr;
+    tcg_out_b_noaddr(s, COND_EQ);
+
+    /* TODO: move this code to where the constants pool will be */
+    if (addr_reg != TCG_REG_R0) {
+        tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                        TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
+    }
+# if TARGET_LONG_BITS == 32
+    tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
+# else
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+    tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+# endif
+    tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
+
+    switch (opc) {
+    case 0 | 4:
+        tcg_out_ext8s(s, COND_AL, data_reg, TCG_REG_R0);
+        break;
+    case 1 | 4:
+        tcg_out_ext16s(s, COND_AL, data_reg, TCG_REG_R0);
+        break;
+    case 0:
+    case 1:
+    case 2:
+    default:
+        if (data_reg != TCG_REG_R0) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
+        }
+        break;
+    case 3:
+        if (data_reg != TCG_REG_R0) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
+        }
+        if (data_reg2 != TCG_REG_R1) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0));
+        }
+        break;
+    }
+
+    reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
+#else /* !CONFIG_SOFTMMU */
+    if (GUEST_BASE) {
+        uint32_t offset = GUEST_BASE;
+        int i;
+        int rot;
+
+        while (offset) {
+            i = ctz32(offset) & ~1;
+            rot = ((32 - i) << 7) & 0xf00;
+
+            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R8, addr_reg,
+                            ((offset >> i) & 0xff) | rot);
+            addr_reg = TCG_REG_R8;
+            offset &= ~(0xff << i);
+        }
+    }
+    switch (opc) {
+    case 0:
+        tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
+        break;
+    case 0 | 4:
+        tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0);
+        break;
+    case 1:
+        tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
+        if (bswap) {
+            tcg_out_bswap16(s, COND_AL, data_reg, data_reg);
+        }
+        break;
+    case 1 | 4:
+        if (bswap) {
+            tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
+            tcg_out_bswap16s(s, COND_AL, data_reg, data_reg);
+        } else {
+            tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0);
+        }
+        break;
+    case 2:
+    default:
+        tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
+        if (bswap) {
+            tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
+        }
+        break;
+    case 3:
+        /* TODO: use block load -
+         * check that data_reg2 > data_reg or the other way */
+        if (data_reg == addr_reg) {
+            tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
+            tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
+        } else {
+            tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
+            tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
+        }
+        if (bswap) {
+            tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
+            tcg_out_bswap32(s, COND_AL, data_reg2, data_reg2);
+        }
+        break;
+    }
+#endif
+}
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, data_reg2, bswap;
+#ifdef CONFIG_SOFTMMU
+    int mem_index, s_bits;
+# if TARGET_LONG_BITS == 64
+    int addr_reg2;
+# endif
+    uint32_t *label_ptr;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+    data_reg = *args++;
+    if (opc == 3)
+        data_reg2 = *args++;
+    else
+        data_reg2 = 0; /* suppress warning */
+    addr_reg = *args++;
+#ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+# endif
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    /* Should generate something like the following:
+     *  shr r8, addr_reg, #TARGET_PAGE_BITS
+     *  and r0, r8, #(CPU_TLB_SIZE - 1)   @ Assumption: CPU_TLB_BITS <= 8
+     *  add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
+     */
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    TCG_REG_R8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
+    tcg_out_dat_imm(s, COND_AL, ARITH_AND,
+                    TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
+    tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0,
+                    TCG_AREG0, TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
+    /* In the
+     *  ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))]
+     * below, the offset is likely to exceed 12 bits if mem_index != 0 and
+     * not exceed otherwise, so use an
+     *  add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
+     * before.
+     */
+    if (mem_index)
+        tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
+                        (mem_index << (TLB_SHIFT & 1)) |
+                        ((16 - (TLB_SHIFT >> 1)) << 8));
+    tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addr_write));
+    tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
+                    TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
+    /* Check alignment.  */
+    if (s_bits)
+        tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
+                        0, addr_reg, (1 << s_bits) - 1);
+#  if TARGET_LONG_BITS == 64
+    /* XXX: possibly we could use a block data load or writeback in
+     * the first access.  */
+    tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addr_write) + 4);
+    tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+                    TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
+#  endif
+    tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+                    offsetof(CPUState, tlb_table[0][0].addend));
+
+    switch (opc) {
+    case 0:
+        tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        break;
+    case 1:
+        if (bswap) {
+            tcg_out_bswap16(s, COND_EQ, TCG_REG_R0, data_reg);
+            tcg_out_st16_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
+        } else {
+            tcg_out_st16_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        }
+        break;
+    case 2:
+    default:
+        if (bswap) {
+            tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
+            tcg_out_st32_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
+        } else {
+            tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+        }
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2);
+            tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg);
+            tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
+            tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4);
+        } else {
+            tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
+            tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
+        }
+        break;
+    }
+
+    label_ptr = (void *) s->code_ptr;
+    tcg_out_b_noaddr(s, COND_EQ);
+
+    /* TODO: move this code to where the constants pool will be */
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
+# if TARGET_LONG_BITS == 32
+    switch (opc) {
+    case 0:
+        tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+        break;
+    case 1:
+        tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+        break;
+    case 2:
+        tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                        TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+        break;
+    case 3:
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
+        tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
+        if (data_reg != TCG_REG_R2) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+        }
+        if (data_reg2 != TCG_REG_R3) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
+        }
+        break;
+    }
+# else
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+    switch (opc) {
+    case 0:
+        tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+        break;
+    case 1:
+        tcg_out_ext16u(s, COND_AL, TCG_REG_R2, data_reg);
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+        break;
+    case 2:
+        if (data_reg != TCG_REG_R2) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+        }
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+        break;
+    case 3:
+        tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
+        tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
+        if (data_reg != TCG_REG_R2) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+        }
+        if (data_reg2 != TCG_REG_R3) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                            TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
+        }
+        break;
+    }
+# endif
+
+    tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
+    if (opc == 3)
+        tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+
+    reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
+#else /* !CONFIG_SOFTMMU */
+    if (GUEST_BASE) {
+        uint32_t offset = GUEST_BASE;
+        int i;
+        int rot;
+
+        while (offset) {
+            i = ctz32(offset) & ~1;
+            rot = ((32 - i) << 7) & 0xf00;
+
+            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R1, addr_reg,
+                            ((offset >> i) & 0xff) | rot);
+            addr_reg = TCG_REG_R1;
+            offset &= ~(0xff << i);
+        }
+    }
+    switch (opc) {
+    case 0:
+        tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
+        break;
+    case 1:
+        if (bswap) {
+            tcg_out_bswap16(s, COND_AL, TCG_REG_R0, data_reg);
+            tcg_out_st16_8(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+        } else {
+            tcg_out_st16_8(s, COND_AL, data_reg, addr_reg, 0);
+        }
+        break;
+    case 2:
+    default:
+        if (bswap) {
+            tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
+            tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+        } else {
+            tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
+        }
+        break;
+    case 3:
+        /* TODO: use block store -
+         * check that data_reg2 > data_reg or the other way */
+        if (bswap) {
+            tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg2);
+            tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+            tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
+            tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 4);
+        } else {
+            tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
+            tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4);
+        }
+        break;
+    }
+#endif
+}
+
+static uint8_t *tb_ret_addr;
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+                const TCGArg *args, const int *const_args)
+{
+    int c;
+
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        {
+            uint8_t *ld_ptr = s->code_ptr;
+            if (args[0] >> 8)
+                tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
+            else
+                tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]);
+            tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
+            if (args[0] >> 8) {
+                *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
+                tcg_out32(s, args[0]);
+            }
+        }
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* Direct jump method */
+#if defined(USE_DIRECT_JUMP)
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            tcg_out_b_noaddr(s, COND_AL);
+#else
+            tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            tcg_out32(s, 0);
+#endif
+        } else {
+            /* Indirect jump method */
+#if 1
+            c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8);
+            if (c > 0xfff || c < -0xfff) {
+                tcg_out_movi32(s, COND_AL, TCG_REG_R0,
+                                (tcg_target_long) (s->tb_next + args[0]));
+                tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
+            } else
+                tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, c);
+#else
+            tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
+            tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
+            tcg_out32(s, (tcg_target_long) (s->tb_next + args[0]));
+#endif
+        }
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_call:
+        if (const_args[0])
+            tcg_out_call(s, args[0]);
+        else
+            tcg_out_callr(s, COND_AL, args[0]);
+        break;
+    case INDEX_op_jmp:
+        if (const_args[0])
+            tcg_out_goto(s, COND_AL, args[0]);
+        else
+            tcg_out_bx(s, COND_AL, args[0]);
+        break;
+    case INDEX_op_br:
+        tcg_out_goto_label(s, COND_AL, args[0]);
+        break;
+
+    case INDEX_op_ld8u_i32:
+        tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld8s_i32:
+        tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16u_i32:
+        tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16s_i32:
+        tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld_i32:
+        tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st8_i32:
+        tcg_out_st8(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st16_i32:
+        tcg_out_st16(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i32:
+        tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_mov_i32:
+        tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                        args[0], 0, args[1], SHIFT_IMM_LSL(0));
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi32(s, COND_AL, args[0], args[1]);
+        break;
+    case INDEX_op_add_i32:
+        c = ARITH_ADD;
+        goto gen_arith;
+    case INDEX_op_sub_i32:
+        c = ARITH_SUB;
+        goto gen_arith;
+    case INDEX_op_and_i32:
+        c = ARITH_AND;
+        goto gen_arith;
+    case INDEX_op_andc_i32:
+        c = ARITH_BIC;
+        goto gen_arith;
+    case INDEX_op_or_i32:
+        c = ARITH_ORR;
+        goto gen_arith;
+    case INDEX_op_xor_i32:
+        c = ARITH_EOR;
+        /* Fall through.  */
+    gen_arith:
+        if (const_args[2]) {
+            int rot;
+            rot = encode_imm(args[2]);
+            tcg_out_dat_imm(s, COND_AL, c,
+                            args[0], args[1], rotl(args[2], rot) | (rot << 7));
+        } else
+            tcg_out_dat_reg(s, COND_AL, c,
+                            args[0], args[1], args[2], SHIFT_IMM_LSL(0));
+        break;
+    case INDEX_op_add2_i32:
+        tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC,
+                        args[0], args[1], args[2], args[3],
+                        args[4], args[5], SHIFT_IMM_LSL(0));
+        break;
+    case INDEX_op_sub2_i32:
+        tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC,
+                        args[0], args[1], args[2], args[3],
+                        args[4], args[5], SHIFT_IMM_LSL(0));
+        break;
+    case INDEX_op_neg_i32:
+        tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
+        break;
+    case INDEX_op_not_i32:
+        tcg_out_dat_reg(s, COND_AL,
+                        ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0));
+        break;
+    case INDEX_op_mul_i32:
+        tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
+        break;
+    /* XXX: Perhaps args[2] & 0x1f is wrong */
+    case INDEX_op_shl_i32:
+        c = const_args[2] ?
+                SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
+        goto gen_shift32;
+    case INDEX_op_shr_i32:
+        c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
+                SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
+        goto gen_shift32;
+    case INDEX_op_sar_i32:
+        c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
+                SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
+        goto gen_shift32;
+    case INDEX_op_rotr_i32:
+        c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) :
+                SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]);
+        /* Fall through.  */
+    gen_shift32:
+        tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
+        break;
+
+    case INDEX_op_rotl_i32:
+        if (const_args[2]) {
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
+                            ((0x20 - args[2]) & 0x1f) ?
+                            SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) :
+                            SHIFT_IMM_LSL(0));
+        } else {
+            tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_R8, args[1], 0x20);
+            tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
+                            SHIFT_REG_ROR(TCG_REG_R8));
+        }
+        break;
+
+    case INDEX_op_brcond_i32:
+        if (const_args[1]) {
+            int rot;
+            rot = encode_imm(args[1]);
+            tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
+                            args[0], rotl(args[1], rot) | (rot << 7));
+        } else {
+            tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+                            args[0], args[1], SHIFT_IMM_LSL(0));
+        }
+        tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]);
+        break;
+    case INDEX_op_brcond2_i32:
+        /* The resulting conditions are:
+         * TCG_COND_EQ    -->  a0 == a2 && a1 == a3,
+         * TCG_COND_NE    --> (a0 != a2 && a1 == a3) ||  a1 != a3,
+         * TCG_COND_LT(U) --> (a0 <  a2 && a1 == a3) ||  a1 <  a3,
+         * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
+         * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
+         * TCG_COND_GT(U) --> (a0 >  a2 && a1 == a3) ||  a1 >  a3,
+         */
+        tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+                        args[1], args[3], SHIFT_IMM_LSL(0));
+        tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+                        args[0], args[2], SHIFT_IMM_LSL(0));
+        tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]);
+        break;
+    case INDEX_op_setcond_i32:
+        if (const_args[2]) {
+            int rot;
+            rot = encode_imm(args[2]);
+            tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
+                            args[1], rotl(args[2], rot) | (rot << 7));
+        } else {
+            tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+                            args[1], args[2], SHIFT_IMM_LSL(0));
+        }
+        tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
+                        ARITH_MOV, args[0], 0, 1);
+        tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
+                        ARITH_MOV, args[0], 0, 0);
+        break;
+    case INDEX_op_setcond2_i32:
+        /* See brcond2_i32 comment */
+        tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+                        args[2], args[4], SHIFT_IMM_LSL(0));
+        tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+                        args[1], args[3], SHIFT_IMM_LSL(0));
+        tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[5]],
+                        ARITH_MOV, args[0], 0, 1);
+        tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[5])],
+                        ARITH_MOV, args[0], 0, 0);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    case INDEX_op_bswap16_i32:
+        tcg_out_bswap16(s, COND_AL, args[0], args[1]);
+        break;
+    case INDEX_op_bswap32_i32:
+        tcg_out_bswap32(s, COND_AL, args[0], args[1]);
+        break;
+
+    case INDEX_op_ext8s_i32:
+        tcg_out_ext8s(s, COND_AL, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+        tcg_out_ext16s(s, COND_AL, args[0], args[1]);
+        break;
+    case INDEX_op_ext16u_i32:
+        tcg_out_ext16u(s, COND_AL, args[0], args[1]);
+        break;
+
+    default:
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef arm_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "r", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+
+    /* TODO: "r", "r", "ri" */
+    { INDEX_op_add_i32, { "r", "r", "rI" } },
+    { INDEX_op_sub_i32, { "r", "r", "rI" } },
+    { INDEX_op_mul_i32, { "r", "r", "r" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+    { INDEX_op_and_i32, { "r", "r", "rI" } },
+    { INDEX_op_andc_i32, { "r", "r", "rI" } },
+    { INDEX_op_or_i32, { "r", "r", "rI" } },
+    { INDEX_op_xor_i32, { "r", "r", "rI" } },
+    { INDEX_op_neg_i32, { "r", "r" } },
+    { INDEX_op_not_i32, { "r", "r" } },
+
+    { INDEX_op_shl_i32, { "r", "r", "ri" } },
+    { INDEX_op_shr_i32, { "r", "r", "ri" } },
+    { INDEX_op_sar_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_brcond_i32, { "r", "rI" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rI" } },
+
+    /* TODO: "r", "r", "r", "r", "ri", "ri" */
+    { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
+    { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
+    { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "r", "r" } },
+
+#if TARGET_LONG_BITS == 32
+    { INDEX_op_qemu_ld8u, { "r", "l" } },
+    { INDEX_op_qemu_ld8s, { "r", "l" } },
+    { INDEX_op_qemu_ld16u, { "r", "l" } },
+    { INDEX_op_qemu_ld16s, { "r", "l" } },
+    { INDEX_op_qemu_ld32, { "r", "l" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "l" } },
+
+    { INDEX_op_qemu_st8, { "s", "s" } },
+    { INDEX_op_qemu_st16, { "s", "s" } },
+    { INDEX_op_qemu_st32, { "s", "s" } },
+    { INDEX_op_qemu_st64, { "S", "S", "s" } },
+#else
+    { INDEX_op_qemu_ld8u, { "r", "l", "l" } },
+    { INDEX_op_qemu_ld8s, { "r", "l", "l" } },
+    { INDEX_op_qemu_ld16u, { "r", "l", "l" } },
+    { INDEX_op_qemu_ld16s, { "r", "l", "l" } },
+    { INDEX_op_qemu_ld32, { "r", "l", "l" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "l", "l" } },
+
+    { INDEX_op_qemu_st8, { "s", "s", "s" } },
+    { INDEX_op_qemu_st16, { "s", "s", "s" } },
+    { INDEX_op_qemu_st32, { "s", "s", "s" } },
+    { INDEX_op_qemu_st64, { "S", "S", "s", "s" } },
+#endif
+
+    { INDEX_op_bswap16_i32, { "r", "r" } },
+    { INDEX_op_bswap32_i32, { "r", "r" } },
+
+    { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext16u_i32, { "r", "r" } },
+
+    { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* fail safe */
+    if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+        tcg_abort();
+#endif
+
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+    tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+                     (1 << TCG_REG_R0) |
+                     (1 << TCG_REG_R1) |
+                     (1 << TCG_REG_R2) |
+                     (1 << TCG_REG_R3) |
+                     (1 << TCG_REG_R12) |
+                     (1 << TCG_REG_R14));
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
+
+    tcg_add_target_add_op_defs(arm_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
+                int arg1, tcg_target_long arg2)
+{
+    tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+                int arg1, tcg_target_long arg2)
+{
+    tcg_out_st32(s, COND_AL, arg, arg1, arg2);
+}
+
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val > 0)
+        if (val < 0x100)
+            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
+        else
+            tcg_abort();
+    else if (val < 0) {
+        if (val > -0x100)
+            tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
+        else
+            tcg_abort();
+    }
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+                int ret, tcg_target_long arg)
+{
+    tcg_out_movi32(s, COND_AL, ret, arg);
+}
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    /* Calling convention requires us to save r4-r11 and lr;
+     * save also r12 to maintain stack 8-alignment.
+     */
+
+    /* stmdb sp!, { r4 - r12, lr } */
+    tcg_out32(s, (COND_AL << 28) | 0x092d5ff0);
+
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+
+    tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]);
+    tb_ret_addr = s->code_ptr;
+
+    /* ldmia sp!, { r4 - r12, pc } */
+    tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0);
+}
diff --git a/qemu-0.15.x/tcg/arm/tcg-target.h b/qemu-0.15.x/tcg/arm/tcg-target.h
new file mode 100644
index 0000000..d8d7d94
--- /dev/null
+++ b/qemu-0.15.x/tcg/arm/tcg-target.h
@@ -0,0 +1,93 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Fabrice Bellard
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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.
+ */
+#define TCG_TARGET_ARM 1
+
+#define TCG_TARGET_REG_BITS 32
+#undef TCG_TARGET_WORDS_BIGENDIAN
+#undef TCG_TARGET_STACK_GROWSUP
+
+enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_PC,
+};
+
+#define TCG_TARGET_NB_REGS 16
+
+#define TCG_CT_CONST_ARM 0x100
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK		TCG_REG_R13
+#define TCG_TARGET_STACK_ALIGN		8
+#define TCG_TARGET_CALL_ALIGN_ARGS	1
+#define TCG_TARGET_CALL_STACK_OFFSET	0
+
+/* optional instructions */
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#undef TCG_TARGET_HAS_ext8u_i32       /* and r0, r1, #0xff */
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+enum {
+    /* Note: must be synced with dyngen-exec.h */
+    TCG_AREG0 = TCG_REG_R7,
+};
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+#if QEMU_GNUC_PREREQ(4, 1)
+    __builtin___clear_cache((char *) start, (char *) stop);
+#else
+    register unsigned long _beg __asm ("a1") = start;
+    register unsigned long _end __asm ("a2") = stop;
+    register unsigned long _flg __asm ("a3") = 0;
+    __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
+#endif
+}
diff --git a/qemu-0.15.x/tcg/hppa/tcg-target.c b/qemu-0.15.x/tcg/hppa/tcg-target.c
new file mode 100644
index 0000000..222f33e
--- /dev/null
+++ b/qemu-0.15.x/tcg/hppa/tcg-target.c
@@ -0,0 +1,1710 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7",
+    "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+    "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
+    "%r24", "%r25", "%r26", "%dp", "%ret0", "%ret1", "%sp", "%r31",
+};
+#endif
+
+/* This is an 8 byte temp slot in the stack frame.  */
+#define STACK_TEMP_OFS -16
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R16
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+
+    TCG_REG_R17,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+
+    TCG_REG_R26,
+    TCG_REG_R25,
+    TCG_REG_R24,
+    TCG_REG_R23,
+
+    TCG_REG_RET0,
+    TCG_REG_RET1,
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+    TCG_REG_R26,
+    TCG_REG_R25,
+    TCG_REG_R24,
+    TCG_REG_R23,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_RET0,
+    TCG_REG_RET1,
+};
+
+/* True iff val fits a signed field of width BITS.  */
+static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
+{
+    return (val << ((sizeof(tcg_target_long) * 8 - bits))
+            >> (sizeof(tcg_target_long) * 8 - bits)) == val;
+}
+
+/* True iff depi can be used to compute (reg | MASK).
+   Accept a bit pattern like:
+      0....01....1
+      1....10....0
+      0..01..10..0
+   Copied from gcc sources.  */
+static inline int or_mask_p(tcg_target_ulong mask)
+{
+    if (mask == 0 || mask == -1) {
+        return 0;
+    }
+    mask += mask & -mask;
+    return (mask & (mask - 1)) == 0;
+}
+
+/* True iff depi or extru can be used to compute (reg & mask).
+   Accept a bit pattern like these:
+      0....01....1
+      1....10....0
+      1..10..01..1
+   Copied from gcc sources.  */
+static inline int and_mask_p(tcg_target_ulong mask)
+{
+    return or_mask_p(~mask);
+}
+
+static int low_sign_ext(int val, int len)
+{
+    return (((val << 1) & ~(-1u << len)) | ((val >> (len - 1)) & 1));
+}
+
+static int reassemble_12(int as12)
+{
+    return (((as12 & 0x800) >> 11) |
+            ((as12 & 0x400) >> 8) |
+            ((as12 & 0x3ff) << 3));
+}
+
+static int reassemble_17(int as17)
+{
+    return (((as17 & 0x10000) >> 16) |
+            ((as17 & 0x0f800) << 5) |
+            ((as17 & 0x00400) >> 8) |
+            ((as17 & 0x003ff) << 3));
+}
+
+static int reassemble_21(int as21)
+{
+    return (((as21 & 0x100000) >> 20) |
+            ((as21 & 0x0ffe00) >> 8) |
+            ((as21 & 0x000180) << 7) |
+            ((as21 & 0x00007c) << 14) |
+            ((as21 & 0x000003) << 12));
+}
+
+/* ??? Bizzarely, there is no PCREL12F relocation type.  I guess all
+   such relocations are simply fully handled by the assembler.  */
+#define R_PARISC_PCREL12F  R_PARISC_NONE
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    uint32_t *insn_ptr = (uint32_t *)code_ptr;
+    uint32_t insn = *insn_ptr;
+    tcg_target_long pcrel;
+
+    value += addend;
+    pcrel = (value - ((tcg_target_long)code_ptr + 8)) >> 2;
+
+    switch (type) {
+    case R_PARISC_PCREL12F:
+        assert(check_fit_tl(pcrel, 12));
+        /* ??? We assume all patches are forward.  See tcg_out_brcond
+           re setting the NUL bit on the branch and eliding the nop.  */
+        assert(pcrel >= 0);
+        insn &= ~0x1ffdu;
+        insn |= reassemble_12(pcrel);
+        break;
+    case R_PARISC_PCREL17F:
+        assert(check_fit_tl(pcrel, 17));
+        insn &= ~0x1f1ffdu;
+        insn |= reassemble_17(pcrel);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    *insn_ptr = insn;
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        break;
+    case 'L': /* qemu_ld/st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23);
+        break;
+    case 'Z':
+        ct->ct |= TCG_CT_CONST_0;
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_S11;
+        break;
+    case 'J':
+        ct->ct |= TCG_CT_CONST_S5;
+	break;
+    case 'K':
+        ct->ct |= TCG_CT_CONST_MS11;
+        break;
+    case 'M':
+        ct->ct |= TCG_CT_CONST_AND;
+        break;
+    case 'O':
+        ct->ct |= TCG_CT_CONST_OR;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct)
+{
+    int ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST) {
+        return 1;
+    } else if (ct & TCG_CT_CONST_0) {
+        return val == 0;
+    } else if (ct & TCG_CT_CONST_S5) {
+        return check_fit_tl(val, 5);
+    } else if (ct & TCG_CT_CONST_S11) {
+        return check_fit_tl(val, 11);
+    } else if (ct & TCG_CT_CONST_MS11) {
+        return check_fit_tl(-val, 11);
+    } else if (ct & TCG_CT_CONST_AND) {
+        return and_mask_p(val);
+    } else if (ct & TCG_CT_CONST_OR) {
+        return or_mask_p(val);
+    }
+    return 0;
+}
+
+#define INSN_OP(x)       ((x) << 26)
+#define INSN_EXT3BR(x)   ((x) << 13)
+#define INSN_EXT3SH(x)   ((x) << 10)
+#define INSN_EXT4(x)     ((x) << 6)
+#define INSN_EXT5(x)     (x)
+#define INSN_EXT6(x)     ((x) << 6)
+#define INSN_EXT7(x)     ((x) << 6)
+#define INSN_EXT8A(x)    ((x) << 6)
+#define INSN_EXT8B(x)    ((x) << 5)
+#define INSN_T(x)        (x)
+#define INSN_R1(x)       ((x) << 16)
+#define INSN_R2(x)       ((x) << 21)
+#define INSN_DEP_LEN(x)  (32 - (x))
+#define INSN_SHDEP_CP(x) ((31 - (x)) << 5)
+#define INSN_SHDEP_P(x)  ((x) << 5)
+#define INSN_COND(x)     ((x) << 13)
+#define INSN_IM11(x)     low_sign_ext(x, 11)
+#define INSN_IM14(x)     low_sign_ext(x, 14)
+#define INSN_IM5(x)      (low_sign_ext(x, 5) << 16)
+
+#define COND_NEVER   0
+#define COND_EQ      1
+#define COND_LT      2
+#define COND_LE      3
+#define COND_LTU     4
+#define COND_LEU     5
+#define COND_SV      6
+#define COND_OD      7
+#define COND_FALSE   8
+
+#define INSN_ADD	(INSN_OP(0x02) | INSN_EXT6(0x18))
+#define INSN_ADDC	(INSN_OP(0x02) | INSN_EXT6(0x1c))
+#define INSN_ADDI	(INSN_OP(0x2d))
+#define INSN_ADDIL	(INSN_OP(0x0a))
+#define INSN_ADDL	(INSN_OP(0x02) | INSN_EXT6(0x28))
+#define INSN_AND	(INSN_OP(0x02) | INSN_EXT6(0x08))
+#define INSN_ANDCM	(INSN_OP(0x02) | INSN_EXT6(0x00))
+#define INSN_COMCLR	(INSN_OP(0x02) | INSN_EXT6(0x22))
+#define INSN_COMICLR	(INSN_OP(0x24))
+#define INSN_DEP	(INSN_OP(0x35) | INSN_EXT3SH(3))
+#define INSN_DEPI	(INSN_OP(0x35) | INSN_EXT3SH(7))
+#define INSN_EXTRS	(INSN_OP(0x34) | INSN_EXT3SH(7))
+#define INSN_EXTRU	(INSN_OP(0x34) | INSN_EXT3SH(6))
+#define INSN_LDIL	(INSN_OP(0x08))
+#define INSN_LDO	(INSN_OP(0x0d))
+#define INSN_MTCTL	(INSN_OP(0x00) | INSN_EXT8B(0xc2))
+#define INSN_OR		(INSN_OP(0x02) | INSN_EXT6(0x09))
+#define INSN_SHD	(INSN_OP(0x34) | INSN_EXT3SH(2))
+#define INSN_SUB	(INSN_OP(0x02) | INSN_EXT6(0x10))
+#define INSN_SUBB	(INSN_OP(0x02) | INSN_EXT6(0x14))
+#define INSN_SUBI	(INSN_OP(0x25))
+#define INSN_VEXTRS	(INSN_OP(0x34) | INSN_EXT3SH(5))
+#define INSN_VEXTRU	(INSN_OP(0x34) | INSN_EXT3SH(4))
+#define INSN_VSHD	(INSN_OP(0x34) | INSN_EXT3SH(0))
+#define INSN_XOR	(INSN_OP(0x02) | INSN_EXT6(0x0a))
+#define INSN_ZDEP	(INSN_OP(0x35) | INSN_EXT3SH(2))
+#define INSN_ZVDEP	(INSN_OP(0x35) | INSN_EXT3SH(0))
+
+#define INSN_BL         (INSN_OP(0x3a) | INSN_EXT3BR(0))
+#define INSN_BL_N       (INSN_OP(0x3a) | INSN_EXT3BR(0) | 2)
+#define INSN_BLR        (INSN_OP(0x3a) | INSN_EXT3BR(2))
+#define INSN_BV         (INSN_OP(0x3a) | INSN_EXT3BR(6))
+#define INSN_BV_N       (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2)
+#define INSN_BLE_SR4    (INSN_OP(0x39) | (1 << 13))
+
+#define INSN_LDB        (INSN_OP(0x10))
+#define INSN_LDH        (INSN_OP(0x11))
+#define INSN_LDW        (INSN_OP(0x12))
+#define INSN_LDWM       (INSN_OP(0x13))
+#define INSN_FLDDS      (INSN_OP(0x0b) | INSN_EXT4(0) | (1 << 12))
+
+#define INSN_LDBX	(INSN_OP(0x03) | INSN_EXT4(0))
+#define INSN_LDHX	(INSN_OP(0x03) | INSN_EXT4(1))
+#define INSN_LDWX       (INSN_OP(0x03) | INSN_EXT4(2))
+
+#define INSN_STB        (INSN_OP(0x18))
+#define INSN_STH        (INSN_OP(0x19))
+#define INSN_STW        (INSN_OP(0x1a))
+#define INSN_STWM       (INSN_OP(0x1b))
+#define INSN_FSTDS      (INSN_OP(0x0b) | INSN_EXT4(8) | (1 << 12))
+
+#define INSN_COMBT      (INSN_OP(0x20))
+#define INSN_COMBF      (INSN_OP(0x22))
+#define INSN_COMIBT     (INSN_OP(0x21))
+#define INSN_COMIBF     (INSN_OP(0x23))
+
+/* supplied by libgcc */
+extern void *__canonicalize_funcptr_for_compare(void *);
+
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    /* PA1.1 defines COPY as OR r,0,t; PA2.0 defines COPY as LDO 0(r),t
+       but hppa-dis.c is unaware of this definition */
+    if (ret != arg) {
+        tcg_out32(s, INSN_OR | INSN_T(ret) | INSN_R1(arg)
+                  | INSN_R2(TCG_REG_R0));
+    }
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         int ret, tcg_target_long arg)
+{
+    if (check_fit_tl(arg, 14)) {
+        tcg_out32(s, INSN_LDO | INSN_R1(ret)
+                  | INSN_R2(TCG_REG_R0) | INSN_IM14(arg));
+    } else {
+        uint32_t hi, lo;
+        hi = arg >> 11;
+        lo = arg & 0x7ff;
+
+        tcg_out32(s, INSN_LDIL | INSN_R2(ret) | reassemble_21(hi));
+        if (lo) {
+            tcg_out32(s, INSN_LDO | INSN_R1(ret)
+                      | INSN_R2(ret) | INSN_IM14(lo));
+        }
+    }
+}
+
+static void tcg_out_ldst(TCGContext *s, int ret, int addr,
+                         tcg_target_long offset, int op)
+{
+    if (!check_fit_tl(offset, 14)) {
+        uint32_t hi, lo, op;
+
+        hi = offset >> 11;
+        lo = offset & 0x7ff;
+
+        if (addr == TCG_REG_R0) {
+            op = INSN_LDIL | INSN_R2(TCG_REG_R1);
+        } else {
+            op = INSN_ADDIL | INSN_R2(addr);
+        }
+        tcg_out32(s, op | reassemble_21(hi));
+
+        addr = TCG_REG_R1;
+	offset = lo;
+    }
+
+    if (ret != addr || offset != 0 || op != INSN_LDO) {
+        tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | INSN_IM14(offset));
+    }
+}
+
+/* This function is required by tcg.c.  */
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, ret, arg1, arg2, INSN_LDW);
+}
+
+/* This function is required by tcg.c.  */
+static inline void tcg_out_st(TCGContext *s, TCGType type, int ret,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, ret, arg1, arg2, INSN_STW);
+}
+
+static void tcg_out_ldst_index(TCGContext *s, int data,
+                               int base, int index, int op)
+{
+    tcg_out32(s, op | INSN_T(data) | INSN_R1(index) | INSN_R2(base));
+}
+
+static inline void tcg_out_addi2(TCGContext *s, int ret, int arg1,
+                                 tcg_target_long val)
+{
+    tcg_out_ldst(s, ret, arg1, val, INSN_LDO);
+}
+
+/* This function is required by tcg.c.  */
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    tcg_out_addi2(s, reg, reg, val);
+}
+
+static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op)
+{
+    tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2));
+}
+
+static inline void tcg_out_arithi(TCGContext *s, int t, int r1,
+                                  tcg_target_long val, int op)
+{
+    assert(check_fit_tl(val, 11));
+    tcg_out32(s, op | INSN_R1(t) | INSN_R2(r1) | INSN_IM11(val));
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+    tcg_out_arith(s, TCG_REG_R0, TCG_REG_R0, TCG_REG_R0, INSN_OR);
+}
+
+static inline void tcg_out_mtctl_sar(TCGContext *s, int arg)
+{
+    tcg_out32(s, INSN_MTCTL | INSN_R2(11) | INSN_R1(arg));
+}
+
+/* Extract LEN bits at position OFS from ARG and place in RET.
+   Note that here the bit ordering is reversed from the PA-RISC
+   standard, such that the right-most bit is 0.  */
+static inline void tcg_out_extr(TCGContext *s, int ret, int arg,
+                                unsigned ofs, unsigned len, int sign)
+{
+    assert(ofs < 32 && len <= 32 - ofs);
+    tcg_out32(s, (sign ? INSN_EXTRS : INSN_EXTRU)
+              | INSN_R1(ret) | INSN_R2(arg)
+              | INSN_SHDEP_P(31 - ofs) | INSN_DEP_LEN(len));
+}
+
+/* Likewise with OFS interpreted little-endian.  */
+static inline void tcg_out_dep(TCGContext *s, int ret, int arg,
+                               unsigned ofs, unsigned len)
+{
+    assert(ofs < 32 && len <= 32 - ofs);
+    tcg_out32(s, INSN_DEP | INSN_R2(ret) | INSN_R1(arg)
+              | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len));
+}
+
+static inline void tcg_out_depi(TCGContext *s, int ret, int arg,
+                                unsigned ofs, unsigned len)
+{
+    assert(ofs < 32 && len <= 32 - ofs);
+    tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(arg)
+              | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len));
+}
+
+static inline void tcg_out_shd(TCGContext *s, int ret, int hi, int lo,
+                               unsigned count)
+{
+    assert(count < 32);
+    tcg_out32(s, INSN_SHD | INSN_R1(hi) | INSN_R2(lo) | INSN_T(ret)
+              | INSN_SHDEP_CP(count));
+}
+
+static void tcg_out_vshd(TCGContext *s, int ret, int hi, int lo, int creg)
+{
+    tcg_out_mtctl_sar(s, creg);
+    tcg_out32(s, INSN_VSHD | INSN_T(ret) | INSN_R1(hi) | INSN_R2(lo));
+}
+
+static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m)
+{
+    int bs0, bs1;
+
+    /* Note that the argument is constrained to match or_mask_p.  */
+    for (bs0 = 0; bs0 < 32; bs0++) {
+        if ((m & (1u << bs0)) != 0) {
+            break;
+        }
+    }
+    for (bs1 = bs0; bs1 < 32; bs1++) {
+        if ((m & (1u << bs1)) == 0) {
+            break;
+        }
+    }
+    assert(bs1 == 32 || (1ul << bs1) > m);
+
+    tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
+    tcg_out_depi(s, ret, -1, bs0, bs1 - bs0);
+}
+
+static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m)
+{
+    int ls0, ls1, ms0;
+
+    /* Note that the argument is constrained to match and_mask_p.  */
+    for (ls0 = 0; ls0 < 32; ls0++) {
+        if ((m & (1u << ls0)) == 0) {
+            break;
+        }
+    }
+    for (ls1 = ls0; ls1 < 32; ls1++) {
+        if ((m & (1u << ls1)) != 0) {
+            break;
+        }
+    }
+    for (ms0 = ls1; ms0 < 32; ms0++) {
+        if ((m & (1u << ms0)) == 0) {
+            break;
+        }
+    }
+    assert (ms0 == 32);
+
+    if (ls1 == 32) {
+        tcg_out_extr(s, ret, arg, 0, ls0, 0);
+    } else {
+        tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
+        tcg_out_depi(s, ret, 0, ls0, ls1 - ls0);
+    }
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg)
+{
+    tcg_out_extr(s, ret, arg, 0, 8, 1);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg)
+{
+    tcg_out_extr(s, ret, arg, 0, 16, 1);
+}
+
+static void tcg_out_shli(TCGContext *s, int ret, int arg, int count)
+{
+    count &= 31;
+    tcg_out32(s, INSN_ZDEP | INSN_R2(ret) | INSN_R1(arg)
+              | INSN_SHDEP_CP(31 - count) | INSN_DEP_LEN(32 - count));
+}
+
+static void tcg_out_shl(TCGContext *s, int ret, int arg, int creg)
+{
+    tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI);
+    tcg_out_mtctl_sar(s, TCG_REG_R20);
+    tcg_out32(s, INSN_ZVDEP | INSN_R2(ret) | INSN_R1(arg) | INSN_DEP_LEN(32));
+}
+
+static void tcg_out_shri(TCGContext *s, int ret, int arg, int count)
+{
+    count &= 31;
+    tcg_out_extr(s, ret, arg, count, 32 - count, 0);
+}
+
+static void tcg_out_shr(TCGContext *s, int ret, int arg, int creg)
+{
+    tcg_out_vshd(s, ret, TCG_REG_R0, arg, creg);
+}
+
+static void tcg_out_sari(TCGContext *s, int ret, int arg, int count)
+{
+    count &= 31;
+    tcg_out_extr(s, ret, arg, count, 32 - count, 1);
+}
+
+static void tcg_out_sar(TCGContext *s, int ret, int arg, int creg)
+{
+    tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI);
+    tcg_out_mtctl_sar(s, TCG_REG_R20);
+    tcg_out32(s, INSN_VEXTRS | INSN_R1(ret) | INSN_R2(arg) | INSN_DEP_LEN(32));
+}
+
+static void tcg_out_rotli(TCGContext *s, int ret, int arg, int count)
+{
+    count &= 31;
+    tcg_out_shd(s, ret, arg, arg, 32 - count);
+}
+
+static void tcg_out_rotl(TCGContext *s, int ret, int arg, int creg)
+{
+    tcg_out_arithi(s, TCG_REG_R20, creg, 32, INSN_SUBI);
+    tcg_out_vshd(s, ret, arg, arg, TCG_REG_R20);
+}
+
+static void tcg_out_rotri(TCGContext *s, int ret, int arg, int count)
+{
+    count &= 31;
+    tcg_out_shd(s, ret, arg, arg, count);
+}
+
+static void tcg_out_rotr(TCGContext *s, int ret, int arg, int creg)
+{
+    tcg_out_vshd(s, ret, arg, arg, creg);
+}
+
+static void tcg_out_bswap16(TCGContext *s, int ret, int arg, int sign)
+{
+    if (ret != arg) {
+        tcg_out_mov(s, TCG_TYPE_I32, ret, arg); /* arg =  xxAB */
+    }
+    tcg_out_dep(s, ret, ret, 16, 8);          /* ret =  xBAB */
+    tcg_out_extr(s, ret, ret, 8, 16, sign);   /* ret =  ..BA */
+}
+
+static void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp)
+{
+                                          /* arg =  ABCD */
+    tcg_out_rotri(s, temp, arg, 16);      /* temp = CDAB */
+    tcg_out_dep(s, temp, temp, 16, 8);    /* temp = CBAB */
+    tcg_out_shd(s, ret, arg, temp, 8);    /* ret =  DCBA */
+}
+
+static void tcg_out_call(TCGContext *s, void *func)
+{
+    tcg_target_long val, hi, lo, disp;
+
+    val = (uint32_t)__canonicalize_funcptr_for_compare(func);
+    disp = (val - ((tcg_target_long)s->code_ptr + 8)) >> 2;
+
+    if (check_fit_tl(disp, 17)) {
+        tcg_out32(s, INSN_BL_N | INSN_R2(TCG_REG_RP) | reassemble_17(disp));
+    } else {
+        hi = val >> 11;
+        lo = val & 0x7ff;
+
+        tcg_out32(s, INSN_LDIL | INSN_R2(TCG_REG_R20) | reassemble_21(hi));
+        tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R20)
+                  | reassemble_17(lo >> 2));
+        tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_RP, TCG_REG_R31);
+    }
+}
+
+static void tcg_out_xmpyu(TCGContext *s, int retl, int reth,
+                          int arg1, int arg2)
+{
+    /* Store both words into the stack for copy to the FPU.  */
+    tcg_out_ldst(s, arg1, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_STW);
+    tcg_out_ldst(s, arg2, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4, INSN_STW);
+
+    /* Load both words into the FPU at the same time.  We get away
+       with this because we can address the left and right half of the
+       FPU registers individually once loaded.  */
+    /* fldds stack_temp(sp),fr22 */
+    tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_CALL_STACK)
+              | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
+
+    /* xmpyu fr22r,fr22,fr22 */
+    tcg_out32(s, 0x3ad64796);
+
+    /* Store the 64-bit result back into the stack.  */
+    /* fstds stack_temp(sp),fr22 */
+    tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_CALL_STACK)
+              | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
+
+    /* Load the pieces of the result that the caller requested.  */
+    if (reth) {
+        tcg_out_ldst(s, reth, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_LDW);
+    }
+    if (retl) {
+        tcg_out_ldst(s, retl, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4,
+                     INSN_LDW);
+    }
+}
+
+static void tcg_out_add2(TCGContext *s, int destl, int desth,
+                         int al, int ah, int bl, int bh, int blconst)
+{
+    int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl);
+
+    if (blconst) {
+        tcg_out_arithi(s, tmp, al, bl, INSN_ADDI);
+    } else {
+        tcg_out_arith(s, tmp, al, bl, INSN_ADD);
+    }
+    tcg_out_arith(s, desth, ah, bh, INSN_ADDC);
+
+    tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
+}
+
+static void tcg_out_sub2(TCGContext *s, int destl, int desth, int al, int ah,
+                         int bl, int bh, int alconst, int blconst)
+{
+    int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl);
+
+    if (alconst) {
+        if (blconst) {
+            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R20, bl);
+            bl = TCG_REG_R20;
+        }
+        tcg_out_arithi(s, tmp, bl, al, INSN_SUBI);
+    } else if (blconst) {
+        tcg_out_arithi(s, tmp, al, -bl, INSN_ADDI);
+    } else {
+        tcg_out_arith(s, tmp, al, bl, INSN_SUB);
+    }
+    tcg_out_arith(s, desth, ah, bh, INSN_SUBB);
+
+    tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
+}
+
+static void tcg_out_branch(TCGContext *s, int label_index, int nul)
+{
+    TCGLabel *l = &s->labels[label_index];
+    uint32_t op = nul ? INSN_BL_N : INSN_BL;
+
+    if (l->has_value) {
+        tcg_target_long val = l->u.value;
+
+        val -= (tcg_target_long)s->code_ptr + 8;
+        val >>= 2;
+        assert(check_fit_tl(val, 17));
+
+        tcg_out32(s, op | reassemble_17(val));
+    } else {
+        /* We need to keep the offset unchanged for retranslation.  */
+        uint32_t old_insn = *(uint32_t *)s->code_ptr;
+
+        tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL17F, label_index, 0);
+        tcg_out32(s, op | (old_insn & 0x1f1ffdu));
+    }
+}
+
+static const uint8_t tcg_cond_to_cmp_cond[10] =
+{
+    [TCG_COND_EQ] = COND_EQ,
+    [TCG_COND_NE] = COND_EQ | COND_FALSE,
+    [TCG_COND_LT] = COND_LT,
+    [TCG_COND_GE] = COND_LT | COND_FALSE,
+    [TCG_COND_LE] = COND_LE,
+    [TCG_COND_GT] = COND_LE | COND_FALSE,
+    [TCG_COND_LTU] = COND_LTU,
+    [TCG_COND_GEU] = COND_LTU | COND_FALSE,
+    [TCG_COND_LEU] = COND_LEU,
+    [TCG_COND_GTU] = COND_LEU | COND_FALSE,
+};
+
+static void tcg_out_brcond(TCGContext *s, int cond, TCGArg c1,
+                           TCGArg c2, int c2const, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+    int op, pacond;
+
+    /* Note that COMIB operates as if the immediate is the first
+       operand.  We model brcond with the immediate in the second
+       to better match what targets are likely to give us.  For
+       consistency, model COMB with reversed operands as well.  */
+    pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)];
+
+    if (c2const) {
+        op = (pacond & COND_FALSE ? INSN_COMIBF : INSN_COMIBT);
+        op |= INSN_IM5(c2);
+    } else {
+        op = (pacond & COND_FALSE ? INSN_COMBF : INSN_COMBT);
+        op |= INSN_R1(c2);
+    }
+    op |= INSN_R2(c1);
+    op |= INSN_COND(pacond & 7);
+
+    if (l->has_value) {
+        tcg_target_long val = l->u.value;
+
+        val -= (tcg_target_long)s->code_ptr + 8;
+        val >>= 2;
+        assert(check_fit_tl(val, 12));
+
+        /* ??? Assume that all branches to defined labels are backward.
+           Which means that if the nul bit is set, the delay slot is
+           executed if the branch is taken, and not executed in fallthru.  */
+        tcg_out32(s, op | reassemble_12(val));
+        tcg_out_nop(s);
+    } else {
+        /* We need to keep the offset unchanged for retranslation.  */
+        uint32_t old_insn = *(uint32_t *)s->code_ptr;
+
+        tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL12F, label_index, 0);
+        /* ??? Assume that all branches to undefined labels are forward.
+           Which means that if the nul bit is set, the delay slot is
+           not executed if the branch is taken, which is what we want.  */
+        tcg_out32(s, op | 2 | (old_insn & 0x1ffdu));
+    }
+}
+
+static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret,
+                           TCGArg c1, TCGArg c2, int c2const)
+{
+    int op, pacond;
+
+    /* Note that COMICLR operates as if the immediate is the first
+       operand.  We model setcond with the immediate in the second
+       to better match what targets are likely to give us.  For
+       consistency, model COMCLR with reversed operands as well.  */
+    pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)];
+
+    if (c2const) {
+        op = INSN_COMICLR | INSN_R2(c1) | INSN_R1(ret) | INSN_IM11(c2);
+    } else {
+        op = INSN_COMCLR | INSN_R2(c1) | INSN_R1(c2) | INSN_T(ret);
+    }
+    op |= INSN_COND(pacond & 7);
+    op |= pacond & COND_FALSE ? 1 << 12 : 0;
+
+    tcg_out32(s, op);
+}
+
+static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah,
+                            TCGArg bl, int blconst, TCGArg bh, int bhconst,
+                            int label_index)
+{
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        tcg_out_comclr(s, tcg_invert_cond(cond), TCG_REG_R0, al, bl, blconst);
+        tcg_out_brcond(s, cond, ah, bh, bhconst, label_index);
+        break;
+
+    default:
+        tcg_out_brcond(s, cond, ah, bh, bhconst, label_index);
+        tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst);
+        tcg_out_brcond(s, tcg_unsigned_cond(cond),
+                       al, bl, blconst, label_index);
+        break;
+    }
+}
+
+static void tcg_out_setcond(TCGContext *s, int cond, TCGArg ret,
+                            TCGArg c1, TCGArg c2, int c2const)
+{
+    tcg_out_comclr(s, tcg_invert_cond(cond), ret, c1, c2, c2const);
+    tcg_out_movi(s, TCG_TYPE_I32, ret, 1);
+}
+
+static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret,
+                             TCGArg al, TCGArg ah, TCGArg bl, int blconst,
+                             TCGArg bh, int bhconst)
+{
+    int scratch = TCG_REG_R20;
+
+    if (ret != al && ret != ah
+        && (blconst || ret != bl)
+        && (bhconst || ret != bh)) {
+        scratch = ret;
+    }
+
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        tcg_out_setcond(s, cond, scratch, al, bl, blconst);
+        tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst);
+        tcg_out_movi(s, TCG_TYPE_I32, scratch, cond == TCG_COND_NE);
+        break;
+
+    default:
+        tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst);
+        tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst);
+        tcg_out_movi(s, TCG_TYPE_I32, scratch, 0);
+        tcg_out_comclr(s, cond, TCG_REG_R0, ah, bh, bhconst);
+        tcg_out_movi(s, TCG_TYPE_I32, scratch, 1);
+        break;
+    }
+
+    tcg_out_mov(s, TCG_TYPE_I32, ret, scratch);
+}
+
+#if defined(CONFIG_SOFTMMU)
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+
+/* Load and compare a TLB entry, and branch if TLB miss.  OFFSET is set to
+   the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate
+   TLB for the memory index.  The return value is the offset from ENV
+   contained in R1 afterward (to be used when loading ADDEND); if the
+   return value is 0, R1 is not used.  */
+
+static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo,
+                            int addrhi, int s_bits, int lab_miss, int offset)
+{
+    int ret;
+
+    /* Extracting the index into the TLB.  The "normal C operation" is
+          r1 = addr_reg >> TARGET_PAGE_BITS;
+          r1 &= CPU_TLB_SIZE - 1;
+          r1 <<= CPU_TLB_ENTRY_BITS;
+       What this does is extract CPU_TLB_BITS beginning at TARGET_PAGE_BITS
+       and place them at CPU_TLB_ENTRY_BITS.  We can combine the first two
+       operations with an EXTRU.  Unfortunately, the current value of
+       CPU_TLB_ENTRY_BITS is > 3, so we can't merge that shift with the
+       add that follows.  */
+    tcg_out_extr(s, r1, addrlo, TARGET_PAGE_BITS, CPU_TLB_BITS, 0);
+    tcg_out_shli(s, r1, r1, CPU_TLB_ENTRY_BITS);
+    tcg_out_arith(s, r1, r1, TCG_AREG0, INSN_ADDL);
+
+    /* Make sure that both the addr_{read,write} and addend can be
+       read with a 14-bit offset from the same base register.  */
+    if (check_fit_tl(offset + CPU_TLB_SIZE, 14)) {
+        ret = 0;
+    } else {
+        ret = (offset + 0x400) & ~0x7ff;
+        offset = ret - offset;
+        tcg_out_addi2(s, TCG_REG_R1, r1, ret);
+        r1 = TCG_REG_R1;
+    }
+
+    /* Load the entry from the computed slot.  */
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R23, r1, offset);
+        tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset + 4);
+    } else {
+        tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset);
+    }
+
+    /* Compute the value that ought to appear in the TLB for a hit, namely, the page
+       of the address.  We include the low N bits of the address to catch unaligned
+       accesses and force them onto the slow path.  Do this computation after having
+       issued the load from the TLB slot to give the load time to complete.  */
+    tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+
+    /* If not equal, jump to lab_miss. */
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_brcond2(s, TCG_COND_NE, TCG_REG_R20, TCG_REG_R23,
+                        r0, 0, addrhi, 0, lab_miss);
+    } else {
+        tcg_out_brcond(s, TCG_COND_NE, TCG_REG_R20, r0, 0, lab_miss);
+    }
+
+    return ret;
+}
+#endif
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo_reg, int datahi_reg,
+                                   int addr_reg, int addend_reg, int opc)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 0;
+#else
+    const int bswap = 1;
+#endif
+
+    switch (opc) {
+    case 0:
+        tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX);
+        break;
+    case 0 | 4:
+        tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX);
+        tcg_out_ext8s(s, datalo_reg, datalo_reg);
+        break;
+    case 1:
+        tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX);
+        if (bswap) {
+            tcg_out_bswap16(s, datalo_reg, datalo_reg, 0);
+        }
+        break;
+    case 1 | 4:
+        tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX);
+        if (bswap) {
+            tcg_out_bswap16(s, datalo_reg, datalo_reg, 1);
+        } else {
+            tcg_out_ext16s(s, datalo_reg, datalo_reg);
+        }
+        break;
+    case 2:
+        tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDWX);
+        if (bswap) {
+            tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20);
+        }
+        break;
+    case 3:
+        if (bswap) {
+            int t = datahi_reg;
+            datahi_reg = datalo_reg;
+            datalo_reg = t;
+        }
+        /* We can't access the low-part with a reg+reg addressing mode,
+           so perform the addition now and use reg_ofs addressing mode.  */
+        if (addend_reg != TCG_REG_R0) {
+            tcg_out_arith(s, TCG_REG_R20, addr_reg, addend_reg, INSN_ADD);
+            addr_reg = TCG_REG_R20;
+	}
+        /* Make sure not to clobber the base register.  */
+        if (datahi_reg == addr_reg) {
+            tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW);
+            tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW);
+        } else {
+            tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW);
+            tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW);
+        }
+        if (bswap) {
+            tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20);
+            tcg_out_bswap32(s, datahi_reg, datahi_reg, TCG_REG_R20);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+    int datalo_reg = *args++;
+    /* Note that datahi_reg is only used for 64-bit loads.  */
+    int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0);
+    int addrlo_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+    /* Note that addrhi_reg is only used for 64-bit guests.  */
+    int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0);
+    int mem_index = *args;
+    int lab1, lab2, argreg, offset;
+
+    lab1 = gen_new_label();
+    lab2 = gen_new_label();
+
+    offset = offsetof(CPUState, tlb_table[mem_index][0].addr_read);
+    offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg,
+                              opc & 3, lab1, offset);
+
+    /* TLB Hit.  */
+    tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25),
+               offsetof(CPUState, tlb_table[mem_index][0].addend) - offset);
+    tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, TCG_REG_R20, opc);
+    tcg_out_branch(s, lab2, 1);
+
+    /* TLB Miss.  */
+    /* label1: */
+    tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
+
+    argreg = TCG_REG_R26;
+    tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
+    }
+    tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+
+    tcg_out_call(s, qemu_ld_helpers[opc & 3]);
+
+    switch (opc) {
+    case 0:
+        tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xff);
+        break;
+    case 0 | 4:
+        tcg_out_ext8s(s, datalo_reg, TCG_REG_RET0);
+        break;
+    case 1:
+        tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xffff);
+        break;
+    case 1 | 4:
+        tcg_out_ext16s(s, datalo_reg, TCG_REG_RET0);
+        break;
+    case 2:
+    case 2 | 4:
+        tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET0);
+        break;
+    case 3:
+        tcg_out_mov(s, TCG_TYPE_I32, datahi_reg, TCG_REG_RET0);
+        tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET1);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    /* label2: */
+    tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr);
+#else
+    tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg,
+                           (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_R0), opc);
+#endif
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int datalo_reg, int datahi_reg,
+                                   int addr_reg, int opc)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 0;
+#else
+    const int bswap = 1;
+#endif
+
+    switch (opc) {
+    case 0:
+        tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STB);
+        break;
+    case 1:
+        if (bswap) {
+            tcg_out_bswap16(s, TCG_REG_R20, datalo_reg, 0);
+            datalo_reg = TCG_REG_R20;
+        }
+        tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STH);
+        break;
+    case 2:
+        if (bswap) {
+            tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20);
+            datalo_reg = TCG_REG_R20;
+        }
+        tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STW);
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20);
+            tcg_out_bswap32(s, TCG_REG_R23, datahi_reg, TCG_REG_R23);
+            datahi_reg = TCG_REG_R20;
+            datalo_reg = TCG_REG_R23;
+        }
+        tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_STW);
+        tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_STW);
+        break;
+    default:
+        tcg_abort();
+    }
+
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+    int datalo_reg = *args++;
+    /* Note that datahi_reg is only used for 64-bit loads.  */
+    int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0);
+    int addrlo_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+    /* Note that addrhi_reg is only used for 64-bit guests.  */
+    int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0);
+    int mem_index = *args;
+    int lab1, lab2, argreg, offset;
+
+    lab1 = gen_new_label();
+    lab2 = gen_new_label();
+
+    offset = offsetof(CPUState, tlb_table[mem_index][0].addr_write);
+    offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg,
+                              opc, lab1, offset);
+
+    /* TLB Hit.  */
+    tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25),
+               offsetof(CPUState, tlb_table[mem_index][0].addend) - offset);
+
+    /* There are no indexed stores, so we must do this addition explitly.
+       Careful to avoid R20, which is used for the bswaps to follow.  */
+    tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_REG_R20, INSN_ADDL);
+    tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, TCG_REG_R31, opc);
+    tcg_out_branch(s, lab2, 1);
+
+    /* TLB Miss.  */
+    /* label1: */
+    tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
+
+    argreg = TCG_REG_R26;
+    tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
+    }
+
+    switch(opc) {
+    case 0:
+        tcg_out_andi(s, argreg--, datalo_reg, 0xff);
+        tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+        break;
+    case 1:
+        tcg_out_andi(s, argreg--, datalo_reg, 0xffff);
+        tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+        break;
+    case 2:
+        tcg_out_mov(s, TCG_TYPE_I32, argreg--, datalo_reg);
+        tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+        break;
+    case 3:
+        /* Because of the alignment required by the 64-bit data argument,
+           we will always use R23/R24.  Also, we will always run out of
+           argument registers for storing mem_index, so that will have
+           to go on the stack.  */
+        if (mem_index == 0) {
+            argreg = TCG_REG_R0;
+        } else {
+            argreg = TCG_REG_R20;
+            tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+        }
+        tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg);
+        tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg);
+        tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_CALL_STACK,
+                   TCG_TARGET_CALL_STACK_OFFSET - 4);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    tcg_out_call(s, qemu_st_helpers[opc]);
+
+    /* label2: */
+    tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr);
+#else
+    /* There are no indexed stores, so if GUEST_BASE is set we must do the add
+       explicitly.  Careful to avoid R20, which is used for the bswaps to follow.  */
+    if (GUEST_BASE != 0) {
+        tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_GUEST_BASE_REG, INSN_ADDL);
+        addrlo_reg = TCG_REG_R31;
+    }
+    tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, addrlo_reg, opc);
+#endif
+}
+
+static void tcg_out_exit_tb(TCGContext *s, TCGArg arg)
+{
+    if (!check_fit_tl(arg, 14)) {
+        uint32_t hi, lo;
+        hi = arg & ~0x7ff;
+        lo = arg & 0x7ff;
+        if (lo) {
+            tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, hi);
+            tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18));
+            tcg_out_addi(s, TCG_REG_RET0, lo);
+            return;
+        }
+        arg = hi;
+    }
+    tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18));
+    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, arg);
+}
+
+static void tcg_out_goto_tb(TCGContext *s, TCGArg arg)
+{
+    if (s->tb_jmp_offset) {
+        /* direct jump method */
+        fprintf(stderr, "goto_tb direct\n");
+        tcg_abort();
+    } else {
+        /* indirect jump method */
+        tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, TCG_REG_R0,
+                   (tcg_target_long)(s->tb_next + arg));
+        tcg_out32(s, INSN_BV_N | INSN_R2(TCG_REG_R20));
+    }
+    s->tb_next_offset[arg] = s->code_ptr - s->code_buf;
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                              const int *const_args)
+{
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_exit_tb(s, args[0]);
+        break;
+    case INDEX_op_goto_tb:
+        tcg_out_goto_tb(s, args[0]);
+        break;
+
+    case INDEX_op_call:
+        if (const_args[0]) {
+            tcg_out_call(s, (void *)args[0]);
+        } else {
+            /* ??? FIXME: the value in the register in args[0] is almost
+               certainly a procedure descriptor, not a code address.  We
+               probably need to use the millicode $$dyncall routine.  */
+            tcg_abort();
+        }
+        break;
+
+    case INDEX_op_jmp:
+        fprintf(stderr, "unimplemented jmp\n");
+        tcg_abort();
+        break;
+
+    case INDEX_op_br:
+        tcg_out_branch(s, args[0], 1);
+        break;
+
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
+        break;
+
+    case INDEX_op_ld8u_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB);
+        break;
+    case INDEX_op_ld8s_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB);
+        tcg_out_ext8s(s, args[0], args[0]);
+        break;
+    case INDEX_op_ld16u_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH);
+        break;
+    case INDEX_op_ld16s_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH);
+        tcg_out_ext16s(s, args[0], args[0]);
+        break;
+    case INDEX_op_ld_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDW);
+        break;
+
+    case INDEX_op_st8_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_STB);
+        break;
+    case INDEX_op_st16_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_STH);
+        break;
+    case INDEX_op_st_i32:
+        tcg_out_ldst(s, args[0], args[1], args[2], INSN_STW);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2]) {
+            tcg_out_addi2(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_arith(s, args[0], args[1], args[2], INSN_ADDL);
+        }
+        break;
+
+    case INDEX_op_sub_i32:
+        if (const_args[1]) {
+            if (const_args[2]) {
+                tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1] - args[2]);
+            } else {
+                /* Recall that SUBI is a reversed subtract.  */
+                tcg_out_arithi(s, args[0], args[2], args[1], INSN_SUBI);
+            }
+        } else if (const_args[2]) {
+            tcg_out_addi2(s, args[0], args[1], -args[2]);
+        } else {
+            tcg_out_arith(s, args[0], args[1], args[2], INSN_SUB);
+        }
+        break;
+
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            tcg_out_andi(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_arith(s, args[0], args[1], args[2], INSN_AND);
+        }
+        break;
+
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            tcg_out_ori(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_arith(s, args[0], args[1], args[2], INSN_OR);
+        }
+        break;
+
+    case INDEX_op_xor_i32:
+        tcg_out_arith(s, args[0], args[1], args[2], INSN_XOR);
+        break;
+
+    case INDEX_op_andc_i32:
+        if (const_args[2]) {
+            tcg_out_andi(s, args[0], args[1], ~args[2]);
+        } else {
+            tcg_out_arith(s, args[0], args[1], args[2], INSN_ANDCM);
+        }
+        break;
+
+    case INDEX_op_shl_i32:
+        if (const_args[2]) {
+            tcg_out_shli(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_shl(s, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_shr_i32:
+        if (const_args[2]) {
+            tcg_out_shri(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_shr(s, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_sar_i32:
+        if (const_args[2]) {
+            tcg_out_sari(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_sar(s, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_rotl_i32:
+        if (const_args[2]) {
+            tcg_out_rotli(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_rotl(s, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_rotr_i32:
+        if (const_args[2]) {
+            tcg_out_rotri(s, args[0], args[1], args[2]);
+        } else {
+            tcg_out_rotr(s, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_mul_i32:
+        tcg_out_xmpyu(s, args[0], TCG_REG_R0, args[1], args[2]);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_xmpyu(s, args[0], args[1], args[2], args[3]);
+        break;
+
+    case INDEX_op_bswap16_i32:
+        tcg_out_bswap16(s, args[0], args[1], 0);
+        break;
+    case INDEX_op_bswap32_i32:
+        tcg_out_bswap32(s, args[0], args[1], TCG_REG_R20);
+        break;
+
+    case INDEX_op_not_i32:
+        tcg_out_arithi(s, args[0], args[1], -1, INSN_SUBI);
+        break;
+    case INDEX_op_ext8s_i32:
+        tcg_out_ext8s(s, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+        tcg_out_ext16s(s, args[0], args[1]);
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]);
+        break;
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2(s, args[4], args[0], args[1],
+                        args[2], const_args[2],
+                        args[3], const_args[3], args[5]);
+        break;
+
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2(s, args[5], args[0], args[1], args[2],
+                         args[3], const_args[3], args[4], const_args[4]);
+        break;
+
+    case INDEX_op_add2_i32:
+        tcg_out_add2(s, args[0], args[1], args[2], args[3],
+                     args[4], args[5], const_args[4]);
+        break;
+
+    case INDEX_op_sub2_i32:
+        tcg_out_sub2(s, args[0], args[1], args[2], args[3],
+                     args[4], args[5], const_args[2], const_args[4]);
+        break;
+
+    case INDEX_op_deposit_i32:
+        if (const_args[2]) {
+            tcg_out_depi(s, args[0], args[2], args[3], args[4]);
+        } else {
+            tcg_out_dep(s, args[0], args[2], args[3], args[4]);
+        }
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    default:
+        fprintf(stderr, "unknown opcode 0x%x\n", opc);
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef hppa_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "r" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "rZ", "r" } },
+    { INDEX_op_st16_i32, { "rZ", "r" } },
+    { INDEX_op_st_i32, { "rZ", "r" } },
+
+    { INDEX_op_add_i32, { "r", "rZ", "ri" } },
+    { INDEX_op_sub_i32, { "r", "rI", "ri" } },
+    { INDEX_op_and_i32, { "r", "rZ", "rM" } },
+    { INDEX_op_or_i32, { "r", "rZ", "rO" } },
+    { INDEX_op_xor_i32, { "r", "rZ", "rZ" } },
+    /* Note that the second argument will be inverted, which means
+       we want a constant whose inversion matches M, and that O = ~M.
+       See the implementation of and_mask_p.  */
+    { INDEX_op_andc_i32, { "r", "rZ", "rO" } },
+
+    { INDEX_op_mul_i32, { "r", "r", "r" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+
+    { INDEX_op_shl_i32, { "r", "r", "ri" } },
+    { INDEX_op_shr_i32, { "r", "r", "ri" } },
+    { INDEX_op_sar_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_bswap16_i32, { "r", "r" } },
+    { INDEX_op_bswap32_i32, { "r", "r" } },
+    { INDEX_op_not_i32, { "r", "r" } },
+
+    { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+
+    { INDEX_op_brcond_i32, { "rZ", "rJ" } },
+    { INDEX_op_brcond2_i32,  { "rZ", "rZ", "rJ", "rJ" } },
+
+    { INDEX_op_setcond_i32, { "r", "rZ", "rI" } },
+    { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rI", "rI" } },
+
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rI", "rZ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rI", "rZ", "rK", "rZ" } },
+
+    { INDEX_op_deposit_i32, { "r", "0", "rJ" } },
+
+#if TARGET_LONG_BITS == 32
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "LZ", "L" } },
+    { INDEX_op_qemu_st16, { "LZ", "L" } },
+    { INDEX_op_qemu_st32, { "LZ", "L" } },
+    { INDEX_op_qemu_st64, { "LZ", "LZ", "L" } },
+#else
+    { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
+
+    { INDEX_op_qemu_st8, { "LZ", "L", "L" } },
+    { INDEX_op_qemu_st16, { "LZ", "L", "L" } },
+    { INDEX_op_qemu_st32, { "LZ", "L", "L" } },
+    { INDEX_op_qemu_st64, { "LZ", "LZ", "L", "L" } },
+#endif
+    { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+    /* R2, the return address register, is saved specially
+       in the caller's frame.  */
+    /* R3, the frame pointer, is not currently modified.  */
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17, /* R17 is the global env.  */
+    TCG_REG_R18
+};
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int frame_size, i;
+
+    /* Allocate space for the fixed frame marker.  */
+    frame_size = -TCG_TARGET_CALL_STACK_OFFSET;
+    frame_size += TCG_TARGET_STATIC_CALL_ARGS_SIZE;
+
+    /* Allocate space for the saved registers.  */
+    frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
+
+    /* Allocate space for the TCG temps. */
+    frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long);
+
+    /* Align the allocated space.  */
+    frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1)
+                  & -TCG_TARGET_STACK_ALIGN);
+
+    /* The return address is stored in the caller's frame.  */
+    tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, -20);
+
+    /* Allocate stack frame, saving the first register at the same time.  */
+    tcg_out_ldst(s, tcg_target_callee_save_regs[0],
+                 TCG_REG_CALL_STACK, frame_size, INSN_STWM);
+
+    /* Save all callee saved registers.  */
+    for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_st(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
+                   TCG_REG_CALL_STACK, -frame_size + i * 4);
+    }
+
+    /* Record the location of the TCG temps.  */
+    tcg_set_frame(s, TCG_REG_CALL_STACK, -frame_size + i * 4,
+                  TCG_TEMP_BUF_NLONGS * sizeof(long));
+
+#ifdef CONFIG_USE_GUEST_BASE
+    if (GUEST_BASE != 0) {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
+        tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+    }
+#endif
+
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+
+    /* Jump to TB, and adjust R18 to be the return address.  */
+    tcg_out32(s, INSN_BLE_SR4 | INSN_R2(tcg_target_call_iarg_regs[1]));
+    tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R18, TCG_REG_R31);
+
+    /* Restore callee saved registers.  */
+    tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK,
+               -frame_size - 20);
+    for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
+                   TCG_REG_CALL_STACK, -frame_size + i * 4);
+    }
+
+    /* Deallocate stack frame and return.  */
+    tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_RP));
+    tcg_out_ldst(s, tcg_target_callee_save_regs[0],
+                 TCG_REG_CALL_STACK, -frame_size, INSN_LDWM);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+
+    tcg_regset_clear(tcg_target_call_clobber_regs);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R20);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R21);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R22);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R23);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R24);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R25);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R26);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET0);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET1);
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);  /* hardwired to zero */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);  /* addil target */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP);  /* link register */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3);  /* frame pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP);  /* data pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);  /* stack pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */
+
+    tcg_add_target_add_op_defs(hppa_op_defs);
+}
diff --git a/qemu-0.15.x/tcg/hppa/tcg-target.h b/qemu-0.15.x/tcg/hppa/tcg-target.h
new file mode 100644
index 0000000..f7919ce
--- /dev/null
+++ b/qemu-0.15.x/tcg/hppa/tcg-target.h
@@ -0,0 +1,120 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+
+#define TCG_TARGET_HPPA 1
+
+#if defined(_PA_RISC1_1)
+#define TCG_TARGET_REG_BITS 32
+#else
+#error unsupported
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_RP,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_DP,
+    TCG_REG_RET0,
+    TCG_REG_RET1,
+    TCG_REG_SP,
+    TCG_REG_R31,
+};
+
+#define TCG_CT_CONST_0    0x0100
+#define TCG_CT_CONST_S5   0x0200
+#define TCG_CT_CONST_S11  0x0400
+#define TCG_CT_CONST_MS11 0x0800
+#define TCG_CT_CONST_AND  0x1000
+#define TCG_CT_CONST_OR   0x2000
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 64
+#define TCG_TARGET_CALL_STACK_OFFSET -48
+#define TCG_TARGET_STATIC_CALL_ARGS_SIZE 8*4
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_STACK_GROWSUP
+
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_deposit_i32
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32           /* sub rd, 0, rs */
+#undef TCG_TARGET_HAS_ext8u_i32         /* and rd, rs, 0xff */
+#undef TCG_TARGET_HAS_ext16u_i32        /* and rd, rs, 0xffff */
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_R17
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    start &= ~31;
+    while (start <= stop) {
+        asm volatile ("fdc 0(%0)\n\t"
+                      "sync\n\t"
+                      "fic 0(%%sr4, %0)\n\t"
+                      "sync"
+                      : : "r"(start) : "memory");
+        start += 32;
+    }
+}
diff --git a/qemu-0.15.x/tcg/i386/tcg-target.c b/qemu-0.15.x/tcg/i386/tcg-target.c
new file mode 100644
index 0000000..7529677
--- /dev/null
+++ b/qemu-0.15.x/tcg/i386/tcg-target.c
@@ -0,0 +1,1988 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+#if TCG_TARGET_REG_BITS == 64
+    "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
+    "%r8",  "%r9",  "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+#else
+    "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
+#endif
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+#if TCG_TARGET_REG_BITS == 64
+    TCG_REG_RBP,
+    TCG_REG_RBX,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R9,
+    TCG_REG_R8,
+    TCG_REG_RCX,
+    TCG_REG_RDX,
+    TCG_REG_RSI,
+    TCG_REG_RDI,
+    TCG_REG_RAX,
+#else
+    TCG_REG_EBX,
+    TCG_REG_ESI,
+    TCG_REG_EDI,
+    TCG_REG_EBP,
+    TCG_REG_ECX,
+    TCG_REG_EDX,
+    TCG_REG_EAX,
+#endif
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+#if TCG_TARGET_REG_BITS == 64
+    TCG_REG_RDI,
+    TCG_REG_RSI,
+    TCG_REG_RDX,
+    TCG_REG_RCX,
+    TCG_REG_R8,
+    TCG_REG_R9,
+#else
+    TCG_REG_EAX,
+    TCG_REG_EDX,
+    TCG_REG_ECX
+#endif
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_EAX,
+    TCG_REG_EDX
+};
+
+static uint8_t *tb_ret_addr;
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch(type) {
+    case R_386_PC32:
+        value -= (uintptr_t)code_ptr;
+        if (value != (int32_t)value) {
+            tcg_abort();
+        }
+        *(uint32_t *)code_ptr = value;
+        break;
+    case R_386_PC8:
+        value -= (uintptr_t)code_ptr;
+        if (value != (int8_t)value) {
+            tcg_abort();
+        }
+        *(uint8_t *)code_ptr = value;
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    if (TCG_TARGET_REG_BITS == 64) {
+        return 6;
+    }
+
+    flags &= TCG_CALL_TYPE_MASK;
+    switch(flags) {
+    case TCG_CALL_TYPE_STD:
+        return 0;
+    case TCG_CALL_TYPE_REGPARM_1:
+    case TCG_CALL_TYPE_REGPARM_2:
+    case TCG_CALL_TYPE_REGPARM:
+        return flags - TCG_CALL_TYPE_REGPARM_1 + 1;
+    default:
+        tcg_abort();
+    }
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch(ct_str[0]) {
+    case 'a':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX);
+        break;
+    case 'b':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX);
+        break;
+    case 'c':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX);
+        break;
+    case 'd':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX);
+        break;
+    case 'S':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI);
+        break;
+    case 'D':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI);
+        break;
+    case 'q':
+        ct->ct |= TCG_CT_REG;
+        if (TCG_TARGET_REG_BITS == 64) {
+            tcg_regset_set32(ct->u.regs, 0, 0xffff);
+        } else {
+            tcg_regset_set32(ct->u.regs, 0, 0xf);
+        }
+        break;
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        if (TCG_TARGET_REG_BITS == 64) {
+            tcg_regset_set32(ct->u.regs, 0, 0xffff);
+        } else {
+            tcg_regset_set32(ct->u.regs, 0, 0xff);
+        }
+        break;
+
+        /* qemu_ld/st address constraint */
+    case 'L':
+        ct->ct |= TCG_CT_REG;
+        if (TCG_TARGET_REG_BITS == 64) {
+            tcg_regset_set32(ct->u.regs, 0, 0xffff);
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+        } else {
+            tcg_regset_set32(ct->u.regs, 0, 0xff);
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
+        }
+        break;
+
+    case 'e':
+        ct->ct |= TCG_CT_CONST_S32;
+        break;
+    case 'Z':
+        ct->ct |= TCG_CT_CONST_U32;
+        break;
+
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+                                         const TCGArgConstraint *arg_ct)
+{
+    int ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST) {
+        return 1;
+    }
+    if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) {
+        return 1;
+    }
+    if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) {
+        return 1;
+    }
+    return 0;
+}
+
+#if TCG_TARGET_REG_BITS == 64
+# define LOWREGMASK(x)	((x) & 7)
+#else
+# define LOWREGMASK(x)	(x)
+#endif
+
+#define P_EXT		0x100		/* 0x0f opcode prefix */
+#define P_DATA16	0x200		/* 0x66 opcode prefix */
+#if TCG_TARGET_REG_BITS == 64
+# define P_ADDR32	0x400		/* 0x67 opcode prefix */
+# define P_REXW		0x800		/* Set REX.W = 1 */
+# define P_REXB_R	0x1000		/* REG field as byte register */
+# define P_REXB_RM	0x2000		/* R/M field as byte register */
+#else
+# define P_ADDR32	0
+# define P_REXW		0
+# define P_REXB_R	0
+# define P_REXB_RM	0
+#endif
+
+#define OPC_ARITH_EvIz	(0x81)
+#define OPC_ARITH_EvIb	(0x83)
+#define OPC_ARITH_GvEv	(0x03)		/* ... plus (ARITH_FOO << 3) */
+#define OPC_ADD_GvEv	(OPC_ARITH_GvEv | (ARITH_ADD << 3))
+#define OPC_BSWAP	(0xc8 | P_EXT)
+#define OPC_CALL_Jz	(0xe8)
+#define OPC_CMP_GvEv	(OPC_ARITH_GvEv | (ARITH_CMP << 3))
+#define OPC_DEC_r32	(0x48)
+#define OPC_IMUL_GvEv	(0xaf | P_EXT)
+#define OPC_IMUL_GvEvIb	(0x6b)
+#define OPC_IMUL_GvEvIz	(0x69)
+#define OPC_INC_r32	(0x40)
+#define OPC_JCC_long	(0x80 | P_EXT)	/* ... plus condition code */
+#define OPC_JCC_short	(0x70)		/* ... plus condition code */
+#define OPC_JMP_long	(0xe9)
+#define OPC_JMP_short	(0xeb)
+#define OPC_LEA         (0x8d)
+#define OPC_MOVB_EvGv	(0x88)		/* stores, more or less */
+#define OPC_MOVL_EvGv	(0x89)		/* stores, more or less */
+#define OPC_MOVL_GvEv	(0x8b)		/* loads, more or less */
+#define OPC_MOVL_EvIz	(0xc7)
+#define OPC_MOVL_Iv     (0xb8)
+#define OPC_MOVSBL	(0xbe | P_EXT)
+#define OPC_MOVSWL	(0xbf | P_EXT)
+#define OPC_MOVSLQ	(0x63 | P_REXW)
+#define OPC_MOVZBL	(0xb6 | P_EXT)
+#define OPC_MOVZWL	(0xb7 | P_EXT)
+#define OPC_POP_r32	(0x58)
+#define OPC_PUSH_r32	(0x50)
+#define OPC_PUSH_Iv	(0x68)
+#define OPC_PUSH_Ib	(0x6a)
+#define OPC_RET		(0xc3)
+#define OPC_SETCC	(0x90 | P_EXT | P_REXB_RM) /* ... plus cc */
+#define OPC_SHIFT_1	(0xd1)
+#define OPC_SHIFT_Ib	(0xc1)
+#define OPC_SHIFT_cl	(0xd3)
+#define OPC_TESTL	(0x85)
+#define OPC_XCHG_ax_r32	(0x90)
+
+#define OPC_GRP3_Ev	(0xf7)
+#define OPC_GRP5	(0xff)
+
+/* Group 1 opcode extensions for 0x80-0x83.
+   These are also used as modifiers for OPC_ARITH.  */
+#define ARITH_ADD 0
+#define ARITH_OR  1
+#define ARITH_ADC 2
+#define ARITH_SBB 3
+#define ARITH_AND 4
+#define ARITH_SUB 5
+#define ARITH_XOR 6
+#define ARITH_CMP 7
+
+/* Group 2 opcode extensions for 0xc0, 0xc1, 0xd0-0xd3.  */
+#define SHIFT_ROL 0
+#define SHIFT_ROR 1
+#define SHIFT_SHL 4
+#define SHIFT_SHR 5
+#define SHIFT_SAR 7
+
+/* Group 3 opcode extensions for 0xf6, 0xf7.  To be used with OPC_GRP3.  */
+#define EXT3_NOT   2
+#define EXT3_NEG   3
+#define EXT3_MUL   4
+#define EXT3_IMUL  5
+#define EXT3_DIV   6
+#define EXT3_IDIV  7
+
+/* Group 5 opcode extensions for 0xff.  To be used with OPC_GRP5.  */
+#define EXT5_INC_Ev	0
+#define EXT5_DEC_Ev	1
+#define EXT5_CALLN_Ev	2
+#define EXT5_JMPN_Ev	4
+
+/* Condition codes to be added to OPC_JCC_{long,short}.  */
+#define JCC_JMP (-1)
+#define JCC_JO  0x0
+#define JCC_JNO 0x1
+#define JCC_JB  0x2
+#define JCC_JAE 0x3
+#define JCC_JE  0x4
+#define JCC_JNE 0x5
+#define JCC_JBE 0x6
+#define JCC_JA  0x7
+#define JCC_JS  0x8
+#define JCC_JNS 0x9
+#define JCC_JP  0xa
+#define JCC_JNP 0xb
+#define JCC_JL  0xc
+#define JCC_JGE 0xd
+#define JCC_JLE 0xe
+#define JCC_JG  0xf
+
+static const uint8_t tcg_cond_to_jcc[10] = {
+    [TCG_COND_EQ] = JCC_JE,
+    [TCG_COND_NE] = JCC_JNE,
+    [TCG_COND_LT] = JCC_JL,
+    [TCG_COND_GE] = JCC_JGE,
+    [TCG_COND_LE] = JCC_JLE,
+    [TCG_COND_GT] = JCC_JG,
+    [TCG_COND_LTU] = JCC_JB,
+    [TCG_COND_GEU] = JCC_JAE,
+    [TCG_COND_LEU] = JCC_JBE,
+    [TCG_COND_GTU] = JCC_JA,
+};
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x)
+{
+    int rex;
+
+    if (opc & P_DATA16) {
+        /* We should never be asking for both 16 and 64-bit operation.  */
+        assert((opc & P_REXW) == 0);
+        tcg_out8(s, 0x66);
+    }
+    if (opc & P_ADDR32) {
+        tcg_out8(s, 0x67);
+    }
+
+    rex = 0;
+    rex |= (opc & P_REXW) >> 8;		/* REX.W */
+    rex |= (r & 8) >> 1;		/* REX.R */
+    rex |= (x & 8) >> 2;		/* REX.X */
+    rex |= (rm & 8) >> 3;		/* REX.B */
+
+    /* P_REXB_{R,RM} indicates that the given register is the low byte.
+       For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do,
+       as otherwise the encoding indicates %[abcd]h.  Note that the values
+       that are ORed in merely indicate that the REX byte must be present;
+       those bits get discarded in output.  */
+    rex |= opc & (r >= 4 ? P_REXB_R : 0);
+    rex |= opc & (rm >= 4 ? P_REXB_RM : 0);
+
+    if (rex) {
+        tcg_out8(s, (uint8_t)(rex | 0x40));
+    }
+
+    if (opc & P_EXT) {
+        tcg_out8(s, 0x0f);
+    }
+    tcg_out8(s, opc);
+}
+#else
+static void tcg_out_opc(TCGContext *s, int opc)
+{
+    if (opc & P_DATA16) {
+        tcg_out8(s, 0x66);
+    }
+    if (opc & P_EXT) {
+        tcg_out8(s, 0x0f);
+    }
+    tcg_out8(s, opc);
+}
+/* Discard the register arguments to tcg_out_opc early, so as not to penalize
+   the 32-bit compilation paths.  This method works with all versions of gcc,
+   whereas relying on optimization may not be able to exclude them.  */
+#define tcg_out_opc(s, opc, r, rm, x)  (tcg_out_opc)(s, opc)
+#endif
+
+static void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
+{
+    tcg_out_opc(s, opc, r, rm, 0);
+    tcg_out8(s, 0xc0 | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
+}
+
+/* Output an opcode with a full "rm + (index<<shift) + offset" address mode.
+   We handle either RM and INDEX missing with a negative value.  In 64-bit
+   mode for absolute addresses, ~RM is the size of the immediate operand
+   that will follow the instruction.  */
+
+static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
+                                     int index, int shift,
+                                     tcg_target_long offset)
+{
+    int mod, len;
+
+    if (index < 0 && rm < 0) {
+        if (TCG_TARGET_REG_BITS == 64) {
+            /* Try for a rip-relative addressing mode.  This has replaced
+               the 32-bit-mode absolute addressing encoding.  */
+            tcg_target_long pc = (tcg_target_long)s->code_ptr + 5 + ~rm;
+            tcg_target_long disp = offset - pc;
+            if (disp == (int32_t)disp) {
+                tcg_out_opc(s, opc, r, 0, 0);
+                tcg_out8(s, (LOWREGMASK(r) << 3) | 5);
+                tcg_out32(s, disp);
+                return;
+            }
+
+            /* Try for an absolute address encoding.  This requires the
+               use of the MODRM+SIB encoding and is therefore larger than
+               rip-relative addressing.  */
+            if (offset == (int32_t)offset) {
+                tcg_out_opc(s, opc, r, 0, 0);
+                tcg_out8(s, (LOWREGMASK(r) << 3) | 4);
+                tcg_out8(s, (4 << 3) | 5);
+                tcg_out32(s, offset);
+                return;
+            }
+
+            /* ??? The memory isn't directly addressable.  */
+            tcg_abort();
+        } else {
+            /* Absolute address.  */
+            tcg_out_opc(s, opc, r, 0, 0);
+            tcg_out8(s, (r << 3) | 5);
+            tcg_out32(s, offset);
+            return;
+        }
+    }
+
+    /* Find the length of the immediate addend.  Note that the encoding
+       that would be used for (%ebp) indicates absolute addressing.  */
+    if (rm < 0) {
+        mod = 0, len = 4, rm = 5;
+    } else if (offset == 0 && LOWREGMASK(rm) != TCG_REG_EBP) {
+        mod = 0, len = 0;
+    } else if (offset == (int8_t)offset) {
+        mod = 0x40, len = 1;
+    } else {
+        mod = 0x80, len = 4;
+    }
+
+    /* Use a single byte MODRM format if possible.  Note that the encoding
+       that would be used for %esp is the escape to the two byte form.  */
+    if (index < 0 && LOWREGMASK(rm) != TCG_REG_ESP) {
+        /* Single byte MODRM format.  */
+        tcg_out_opc(s, opc, r, rm, 0);
+        tcg_out8(s, mod | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
+    } else {
+        /* Two byte MODRM+SIB format.  */
+
+        /* Note that the encoding that would place %esp into the index
+           field indicates no index register.  In 64-bit mode, the REX.X
+           bit counts, so %r12 can be used as the index.  */
+        if (index < 0) {
+            index = 4;
+        } else {
+            assert(index != TCG_REG_ESP);
+        }
+
+        tcg_out_opc(s, opc, r, rm, index);
+        tcg_out8(s, mod | (LOWREGMASK(r) << 3) | 4);
+        tcg_out8(s, (shift << 6) | (LOWREGMASK(index) << 3) | LOWREGMASK(rm));
+    }
+
+    if (len == 1) {
+        tcg_out8(s, offset);
+    } else if (len == 4) {
+        tcg_out32(s, offset);
+    }
+}
+
+/* A simplification of the above with no index or shift.  */
+static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r,
+                                        int rm, tcg_target_long offset)
+{
+    tcg_out_modrm_sib_offset(s, opc, r, rm, -1, 0, offset);
+}
+
+/* Generate dest op= src.  Uses the same ARITH_* codes as tgen_arithi.  */
+static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
+{
+    /* Propagate an opcode prefix, such as P_REXW.  */
+    int ext = subop & ~0x7;
+    subop &= 0x7;
+
+    tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3) + ext, dest, src);
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    if (arg != ret) {
+        int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+        tcg_out_modrm(s, opc, ret, arg);
+    }
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         int ret, tcg_target_long arg)
+{
+    if (arg == 0) {
+        tgen_arithr(s, ARITH_XOR, ret, ret);
+        return;
+    } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
+        tcg_out_opc(s, OPC_MOVL_Iv + LOWREGMASK(ret), 0, ret, 0);
+        tcg_out32(s, arg);
+    } else if (arg == (int32_t)arg) {
+        tcg_out_modrm(s, OPC_MOVL_EvIz + P_REXW, 0, ret);
+        tcg_out32(s, arg);
+    } else {
+        tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0);
+        tcg_out32(s, arg);
+        tcg_out32(s, arg >> 31 >> 1);
+    }
+}
+
+static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
+{
+    if (val == (int8_t)val) {
+        tcg_out_opc(s, OPC_PUSH_Ib, 0, 0, 0);
+        tcg_out8(s, val);
+    } else if (val == (int32_t)val) {
+        tcg_out_opc(s, OPC_PUSH_Iv, 0, 0, 0);
+        tcg_out32(s, val);
+    } else {
+        tcg_abort();
+    }
+}
+
+static inline void tcg_out_push(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, OPC_PUSH_r32 + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_pop(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, OPC_POP_r32 + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+                              int arg1, tcg_target_long arg2)
+{
+    int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+    tcg_out_modrm_offset(s, opc, ret, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    int opc = OPC_MOVL_EvGv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+    tcg_out_modrm_offset(s, opc, arg, arg1, arg2);
+}
+
+static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
+{
+    /* Propagate an opcode prefix, such as P_DATA16.  */
+    int ext = subopc & ~0x7;
+    subopc &= 0x7;
+
+    if (count == 1) {
+        tcg_out_modrm(s, OPC_SHIFT_1 + ext, subopc, reg);
+    } else {
+        tcg_out_modrm(s, OPC_SHIFT_Ib + ext, subopc, reg);
+        tcg_out8(s, count);
+    }
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, OPC_BSWAP + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_rolw_8(TCGContext *s, int reg)
+{
+    tcg_out_shifti(s, SHIFT_ROL + P_DATA16, reg, 8);
+}
+
+static inline void tcg_out_ext8u(TCGContext *s, int dest, int src)
+{
+    /* movzbl */
+    assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+    tcg_out_modrm(s, OPC_MOVZBL + P_REXB_RM, dest, src);
+}
+
+static void tcg_out_ext8s(TCGContext *s, int dest, int src, int rexw)
+{
+    /* movsbl */
+    assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+    tcg_out_modrm(s, OPC_MOVSBL + P_REXB_RM + rexw, dest, src);
+}
+
+static inline void tcg_out_ext16u(TCGContext *s, int dest, int src)
+{
+    /* movzwl */
+    tcg_out_modrm(s, OPC_MOVZWL, dest, src);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int dest, int src, int rexw)
+{
+    /* movsw[lq] */
+    tcg_out_modrm(s, OPC_MOVSWL + rexw, dest, src);
+}
+
+static inline void tcg_out_ext32u(TCGContext *s, int dest, int src)
+{
+    /* 32-bit mov zero extends.  */
+    tcg_out_modrm(s, OPC_MOVL_GvEv, dest, src);
+}
+
+static inline void tcg_out_ext32s(TCGContext *s, int dest, int src)
+{
+    tcg_out_modrm(s, OPC_MOVSLQ, dest, src);
+}
+
+static inline void tcg_out_bswap64(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static void tgen_arithi(TCGContext *s, int c, int r0,
+                        tcg_target_long val, int cf)
+{
+    int rexw = 0;
+
+    if (TCG_TARGET_REG_BITS == 64) {
+        rexw = c & -8;
+        c &= 7;
+    }
+
+    /* ??? While INC is 2 bytes shorter than ADDL $1, they also induce
+       partial flags update stalls on Pentium4 and are not recommended
+       by current Intel optimization manuals.  */
+    if (!cf && (c == ARITH_ADD || c == ARITH_SUB) && (val == 1 || val == -1)) {
+        int is_inc = (c == ARITH_ADD) ^ (val < 0);
+        if (TCG_TARGET_REG_BITS == 64) {
+            /* The single-byte increment encodings are re-tasked as the
+               REX prefixes.  Use the MODRM encoding.  */
+            tcg_out_modrm(s, OPC_GRP5 + rexw,
+                          (is_inc ? EXT5_INC_Ev : EXT5_DEC_Ev), r0);
+        } else {
+            tcg_out8(s, (is_inc ? OPC_INC_r32 : OPC_DEC_r32) + r0);
+        }
+        return;
+    }
+
+    if (c == ARITH_AND) {
+        if (TCG_TARGET_REG_BITS == 64) {
+            if (val == 0xffffffffu) {
+                tcg_out_ext32u(s, r0, r0);
+                return;
+            }
+            if (val == (uint32_t)val) {
+                /* AND with no high bits set can use a 32-bit operation.  */
+                rexw = 0;
+            }
+        }
+        if (val == 0xffu && (r0 < 4 || TCG_TARGET_REG_BITS == 64)) {
+            tcg_out_ext8u(s, r0, r0);
+            return;
+        }
+        if (val == 0xffffu) {
+            tcg_out_ext16u(s, r0, r0);
+            return;
+        }
+    }
+
+    if (val == (int8_t)val) {
+        tcg_out_modrm(s, OPC_ARITH_EvIb + rexw, c, r0);
+        tcg_out8(s, val);
+        return;
+    }
+    if (rexw == 0 || val == (int32_t)val) {
+        tcg_out_modrm(s, OPC_ARITH_EvIz + rexw, c, r0);
+        tcg_out32(s, val);
+        return;
+    }
+
+    tcg_abort();
+}
+
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val != 0) {
+        tgen_arithi(s, ARITH_ADD + P_REXW, reg, val, 0);
+    }
+}
+
+/* Use SMALL != 0 to force a short forward branch.  */
+static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
+{
+    int32_t val, val1;
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value) {
+        val = l->u.value - (tcg_target_long)s->code_ptr;
+        val1 = val - 2;
+        if ((int8_t)val1 == val1) {
+            if (opc == -1) {
+                tcg_out8(s, OPC_JMP_short);
+            } else {
+                tcg_out8(s, OPC_JCC_short + opc);
+            }
+            tcg_out8(s, val1);
+        } else {
+            if (small) {
+                tcg_abort();
+            }
+            if (opc == -1) {
+                tcg_out8(s, OPC_JMP_long);
+                tcg_out32(s, val - 5);
+            } else {
+                tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
+                tcg_out32(s, val - 6);
+            }
+        }
+    } else if (small) {
+        if (opc == -1) {
+            tcg_out8(s, OPC_JMP_short);
+        } else {
+            tcg_out8(s, OPC_JCC_short + opc);
+        }
+        tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1);
+        s->code_ptr += 1;
+    } else {
+        if (opc == -1) {
+            tcg_out8(s, OPC_JMP_long);
+        } else {
+            tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
+        }
+        tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
+        s->code_ptr += 4;
+    }
+}
+
+static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
+                        int const_arg2, int rexw)
+{
+    if (const_arg2) {
+        if (arg2 == 0) {
+            /* test r, r */
+            tcg_out_modrm(s, OPC_TESTL + rexw, arg1, arg1);
+        } else {
+            tgen_arithi(s, ARITH_CMP + rexw, arg1, arg2, 0);
+        }
+    } else {
+        tgen_arithr(s, ARITH_CMP + rexw, arg1, arg2);
+    }
+}
+
+static void tcg_out_brcond32(TCGContext *s, TCGCond cond,
+                             TCGArg arg1, TCGArg arg2, int const_arg2,
+                             int label_index, int small)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
+    tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_brcond64(TCGContext *s, TCGCond cond,
+                             TCGArg arg1, TCGArg arg2, int const_arg2,
+                             int label_index, int small)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+    tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
+}
+#else
+/* XXX: we implement it at the target level to avoid having to
+   handle cross basic blocks temporaries */
+static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
+                            const int *const_args, int small)
+{
+    int label_next;
+    label_next = gen_new_label();
+    switch(args[4]) {
+    case TCG_COND_EQ:
+        tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+                         label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_EQ, args[1], args[3], const_args[3],
+                         args[5], small);
+        break;
+    case TCG_COND_NE:
+        tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+                         args[5], small);
+        tcg_out_brcond32(s, TCG_COND_NE, args[1], args[3], const_args[3],
+                         args[5], small);
+        break;
+    case TCG_COND_LT:
+        tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_LE:
+        tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_GT:
+        tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_GE:
+        tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_LTU:
+        tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_LEU:
+        tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_GTU:
+        tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    case TCG_COND_GEU:
+        tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+                         args[5], small);
+        tcg_out_jxx(s, JCC_JNE, label_next, 1);
+        tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+                         args[5], small);
+        break;
+    default:
+        tcg_abort();
+    }
+    tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
+}
+#endif
+
+static void tcg_out_setcond32(TCGContext *s, TCGCond cond, TCGArg dest,
+                              TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
+    tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
+    tcg_out_ext8u(s, dest, dest);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond64(TCGContext *s, TCGCond cond, TCGArg dest,
+                              TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+    tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
+    tcg_out_ext8u(s, dest, dest);
+}
+#else
+static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
+                             const int *const_args)
+{
+    TCGArg new_args[6];
+    int label_true, label_over;
+
+    memcpy(new_args, args+1, 5*sizeof(TCGArg));
+
+    if (args[0] == args[1] || args[0] == args[2]
+        || (!const_args[3] && args[0] == args[3])
+        || (!const_args[4] && args[0] == args[4])) {
+        /* When the destination overlaps with one of the argument
+           registers, don't do anything tricky.  */
+        label_true = gen_new_label();
+        label_over = gen_new_label();
+
+        new_args[5] = label_true;
+        tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+        tcg_out_jxx(s, JCC_JMP, label_over, 1);
+        tcg_out_label(s, label_true, (tcg_target_long)s->code_ptr);
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 1);
+        tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+    } else {
+        /* When the destination does not overlap one of the arguments,
+           clear the destination first, jump if cond false, and emit an
+           increment in the true case.  This results in smaller code.  */
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+
+        label_over = gen_new_label();
+        new_args[4] = tcg_invert_cond(new_args[4]);
+        new_args[5] = label_over;
+        tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+        tgen_arithi(s, ARITH_ADD, args[0], 1, 0);
+        tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+    }
+}
+#endif
+
+static void tcg_out_branch(TCGContext *s, int call, tcg_target_long dest)
+{
+    tcg_target_long disp = dest - (tcg_target_long)s->code_ptr - 5;
+
+    if (disp == (int32_t)disp) {
+        tcg_out_opc(s, call ? OPC_CALL_Jz : OPC_JMP_long, 0, 0, 0);
+        tcg_out32(s, disp);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, dest);
+        tcg_out_modrm(s, OPC_GRP5,
+                      call ? EXT5_CALLN_Ev : EXT5_JMPN_Ev, TCG_REG_R10);
+    }
+}
+
+static inline void tcg_out_calli(TCGContext *s, tcg_target_long dest)
+{
+    tcg_out_branch(s, 1, dest);
+}
+
+static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
+{
+    tcg_out_branch(s, 0, dest);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+
+/* Perform the TLB load and compare.
+
+   Inputs:
+   ADDRLO_IDX contains the index into ARGS of the low part of the
+   address; the high part of the address is at ADDR_LOW_IDX+1.
+
+   MEM_INDEX and S_BITS are the memory context and log2 size of the load.
+
+   WHICH is the offset into the CPUTLBEntry structure of the slot to read.
+   This should be offsetof addr_read or addr_write.
+
+   Outputs:
+   LABEL_PTRS is filled with 1 (32-bit addresses) or 2 (64-bit addresses)
+   positions of the displacements of forward jumps to the TLB miss case.
+
+   First argument register is loaded with the low part of the address.
+   In the TLB hit case, it has been adjusted as indicated by the TLB
+   and so is a host address.  In the TLB miss case, it continues to
+   hold a guest address.
+
+   Second argument register is clobbered.  */
+
+static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
+                                    int mem_index, int s_bits,
+                                    const TCGArg *args,
+                                    uint8_t **label_ptr, int which)
+{
+    const int addrlo = args[addrlo_idx];
+    const int r0 = tcg_target_call_iarg_regs[0];
+    const int r1 = tcg_target_call_iarg_regs[1];
+    TCGType type = TCG_TYPE_I32;
+    int rexw = 0;
+
+    if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) {
+        type = TCG_TYPE_I64;
+        rexw = P_REXW;
+    }
+
+    tcg_out_mov(s, type, r1, addrlo);
+    tcg_out_mov(s, type, r0, addrlo);
+
+    tcg_out_shifti(s, SHIFT_SHR + rexw, r1,
+                   TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+
+    tgen_arithi(s, ARITH_AND + rexw, r0,
+                TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
+    tgen_arithi(s, ARITH_AND + rexw, r1,
+                (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
+
+    tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r1, TCG_AREG0, r1, 0,
+                             offsetof(CPUState, tlb_table[mem_index][0])
+                             + which);
+
+    /* cmp 0(r1), r0 */
+    tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r0, r1, 0);
+
+    tcg_out_mov(s, type, r0, addrlo);
+
+    /* jne label1 */
+    tcg_out8(s, OPC_JCC_short + JCC_JNE);
+    label_ptr[0] = s->code_ptr;
+    s->code_ptr++;
+
+    if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+        /* cmp 4(r1), addrhi */
+        tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r1, 4);
+
+        /* jne label1 */
+        tcg_out8(s, OPC_JCC_short + JCC_JNE);
+        label_ptr[1] = s->code_ptr;
+        s->code_ptr++;
+    }
+
+    /* TLB Hit.  */
+
+    /* add addend(r1), r0 */
+    tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r0, r1,
+                         offsetof(CPUTLBEntry, addend) - which);
+}
+#endif
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
+                                   int base, tcg_target_long ofs, int sizeop)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 1;
+#else
+    const int bswap = 0;
+#endif
+    switch (sizeop) {
+    case 0:
+        tcg_out_modrm_offset(s, OPC_MOVZBL, datalo, base, ofs);
+        break;
+    case 0 | 4:
+        tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW, datalo, base, ofs);
+        break;
+    case 1:
+        tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
+        if (bswap) {
+            tcg_out_rolw_8(s, datalo);
+        }
+        break;
+    case 1 | 4:
+        if (bswap) {
+            tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
+            tcg_out_rolw_8(s, datalo);
+            tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo);
+        } else {
+            tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW, datalo, base, ofs);
+        }
+        break;
+    case 2:
+        tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+        if (bswap) {
+            tcg_out_bswap32(s, datalo);
+        }
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case 2 | 4:
+        if (bswap) {
+            tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+            tcg_out_bswap32(s, datalo);
+            tcg_out_ext32s(s, datalo, datalo);
+        } else {
+            tcg_out_modrm_offset(s, OPC_MOVSLQ, datalo, base, ofs);
+        }
+        break;
+#endif
+    case 3:
+        if (TCG_TARGET_REG_BITS == 64) {
+            tcg_out_ld(s, TCG_TYPE_I64, datalo, base, ofs);
+            if (bswap) {
+                tcg_out_bswap64(s, datalo);
+            }
+        } else {
+            if (bswap) {
+                int t = datalo;
+                datalo = datahi;
+                datahi = t;
+            }
+            if (base != datalo) {
+                tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+                tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+            } else {
+                tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+                tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+            }
+            if (bswap) {
+                tcg_out_bswap32(s, datalo);
+                tcg_out_bswap32(s, datahi);
+            }
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
+   EAX. It will be useful once fixed registers globals are less
+   common. */
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int data_reg, data_reg2 = 0;
+    int addrlo_idx;
+#if defined(CONFIG_SOFTMMU)
+    int mem_index, s_bits, arg_idx;
+    uint8_t *label_ptr[3];
+#endif
+
+    data_reg = args[0];
+    addrlo_idx = 1;
+    if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
+        data_reg2 = args[1];
+        addrlo_idx = 2;
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
+    s_bits = opc & 3;
+
+    tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+                     label_ptr, offsetof(CPUTLBEntry, addr_read));
+
+    /* TLB Hit.  */
+    tcg_out_qemu_ld_direct(s, data_reg, data_reg2,
+                           tcg_target_call_iarg_regs[0], 0, opc);
+
+    /* jmp label2 */
+    tcg_out8(s, OPC_JMP_short);
+    label_ptr[2] = s->code_ptr;
+    s->code_ptr++;
+
+    /* TLB Miss.  */
+
+    /* label1: */
+    *label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
+    if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+        *label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
+    }
+
+    /* XXX: move that code at the end of the TB */
+    /* The first argument is already loaded with addrlo.  */
+    arg_idx = 1;
+    if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
+        tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx++],
+                    args[addrlo_idx + 1]);
+    }
+    tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx],
+                 mem_index);
+    tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]);
+
+    switch(opc) {
+    case 0 | 4:
+        tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
+        break;
+    case 1 | 4:
+        tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
+        break;
+    case 0:
+        tcg_out_ext8u(s, data_reg, TCG_REG_EAX);
+        break;
+    case 1:
+        tcg_out_ext16u(s, data_reg, TCG_REG_EAX);
+        break;
+    case 2:
+        tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case 2 | 4:
+        tcg_out_ext32s(s, data_reg, TCG_REG_EAX);
+        break;
+#endif
+    case 3:
+        if (TCG_TARGET_REG_BITS == 64) {
+            tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
+        } else if (data_reg == TCG_REG_EDX) {
+            /* xchg %edx, %eax */
+            tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0);
+            tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EAX);
+        } else {
+            tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+            tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EDX);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+
+    /* label2: */
+    *label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
+#else
+    {
+        int32_t offset = GUEST_BASE;
+        int base = args[addrlo_idx];
+
+        if (TCG_TARGET_REG_BITS == 64) {
+            /* ??? We assume all operations have left us with register
+               contents that are zero extended.  So far this appears to
+               be true.  If we want to enforce this, we can either do
+               an explicit zero-extension here, or (if GUEST_BASE == 0)
+               use the ADDR32 prefix.  For now, do nothing.  */
+
+            if (offset != GUEST_BASE) {
+                tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+                tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+                base = TCG_REG_RDI, offset = 0;
+            }
+        }
+
+        tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, opc);
+    }
+#endif
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
+                                   int base, tcg_target_long ofs, int sizeop)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 1;
+#else
+    const int bswap = 0;
+#endif
+    /* ??? Ideally we wouldn't need a scratch register.  For user-only,
+       we could perform the bswap twice to restore the original value
+       instead of moving to the scratch.  But as it is, the L constraint
+       means that the second argument reg is definitely free here.  */
+    int scratch = tcg_target_call_iarg_regs[1];
+
+    switch (sizeop) {
+    case 0:
+        tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R, datalo, base, ofs);
+        break;
+    case 1:
+        if (bswap) {
+            tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+            tcg_out_rolw_8(s, scratch);
+            datalo = scratch;
+        }
+        tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16, datalo, base, ofs);
+        break;
+    case 2:
+        if (bswap) {
+            tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+            tcg_out_bswap32(s, scratch);
+            datalo = scratch;
+        }
+        tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs);
+        break;
+    case 3:
+        if (TCG_TARGET_REG_BITS == 64) {
+            if (bswap) {
+                tcg_out_mov(s, TCG_TYPE_I64, scratch, datalo);
+                tcg_out_bswap64(s, scratch);
+                datalo = scratch;
+            }
+            tcg_out_st(s, TCG_TYPE_I64, datalo, base, ofs);
+        } else if (bswap) {
+            tcg_out_mov(s, TCG_TYPE_I32, scratch, datahi);
+            tcg_out_bswap32(s, scratch);
+            tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs);
+            tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+            tcg_out_bswap32(s, scratch);
+            tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs + 4);
+        } else {
+            tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs);
+            tcg_out_st(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int data_reg, data_reg2 = 0;
+    int addrlo_idx;
+#if defined(CONFIG_SOFTMMU)
+    int mem_index, s_bits;
+    int stack_adjust;
+    uint8_t *label_ptr[3];
+#endif
+
+    data_reg = args[0];
+    addrlo_idx = 1;
+    if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
+        data_reg2 = args[1];
+        addrlo_idx = 2;
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
+    s_bits = opc;
+
+    tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+                     label_ptr, offsetof(CPUTLBEntry, addr_write));
+
+    /* TLB Hit.  */
+    tcg_out_qemu_st_direct(s, data_reg, data_reg2,
+                           tcg_target_call_iarg_regs[0], 0, opc);
+
+    /* jmp label2 */
+    tcg_out8(s, OPC_JMP_short);
+    label_ptr[2] = s->code_ptr;
+    s->code_ptr++;
+
+    /* TLB Miss.  */
+
+    /* label1: */
+    *label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
+    if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+        *label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
+    }
+
+    /* XXX: move that code at the end of the TB */
+    if (TCG_TARGET_REG_BITS == 64) {
+        tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+                    TCG_REG_RSI, data_reg);
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+        stack_adjust = 0;
+    } else if (TARGET_LONG_BITS == 32) {
+        tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, data_reg);
+        if (opc == 3) {
+            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg2);
+            tcg_out_pushi(s, mem_index);
+            stack_adjust = 4;
+        } else {
+            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
+            stack_adjust = 0;
+        }
+    } else {
+        if (opc == 3) {
+            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
+            tcg_out_pushi(s, mem_index);
+            tcg_out_push(s, data_reg2);
+            tcg_out_push(s, data_reg);
+            stack_adjust = 12;
+        } else {
+            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
+            switch(opc) {
+            case 0:
+                tcg_out_ext8u(s, TCG_REG_ECX, data_reg);
+                break;
+            case 1:
+                tcg_out_ext16u(s, TCG_REG_ECX, data_reg);
+                break;
+            case 2:
+                tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg);
+                break;
+            }
+            tcg_out_pushi(s, mem_index);
+            stack_adjust = 4;
+        }
+    }
+
+    tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
+
+    if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
+        /* Pop and discard.  This is 2 bytes smaller than the add.  */
+        tcg_out_pop(s, TCG_REG_ECX);
+    } else if (stack_adjust != 0) {
+        tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust);
+    }
+
+    /* label2: */
+    *label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
+#else
+    {
+        int32_t offset = GUEST_BASE;
+        int base = args[addrlo_idx];
+
+        if (TCG_TARGET_REG_BITS == 64) {
+            /* ??? We assume all operations have left us with register
+               contents that are zero extended.  So far this appears to
+               be true.  If we want to enforce this, we can either do
+               an explicit zero-extension here, or (if GUEST_BASE == 0)
+               use the ADDR32 prefix.  For now, do nothing.  */
+
+            if (offset != GUEST_BASE) {
+                tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+                tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+                base = TCG_REG_RDI, offset = 0;
+            }
+        }
+
+        tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, opc);
+    }
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+                              const TCGArg *args, const int *const_args)
+{
+    int c, rexw = 0;
+
+#if TCG_TARGET_REG_BITS == 64
+# define OP_32_64(x) \
+        case glue(glue(INDEX_op_, x), _i64): \
+            rexw = P_REXW; /* FALLTHRU */    \
+        case glue(glue(INDEX_op_, x), _i32)
+#else
+# define OP_32_64(x) \
+        case glue(glue(INDEX_op_, x), _i32)
+#endif
+
+    switch(opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]);
+        tcg_out_jmp(s, (tcg_target_long) tb_ret_addr);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+            tcg_out8(s, OPC_JMP_long); /* jmp im */
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            tcg_out32(s, 0);
+        } else {
+            /* indirect jump method */
+            tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
+                                 (tcg_target_long)(s->tb_next + args[0]));
+        }
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_call:
+        if (const_args[0]) {
+            tcg_out_calli(s, args[0]);
+        } else {
+            /* call *reg */
+            tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]);
+        }
+        break;
+    case INDEX_op_jmp:
+        if (const_args[0]) {
+            tcg_out_jmp(s, args[0]);
+        } else {
+            /* jmp *reg */
+            tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, args[0]);
+        }
+        break;
+    case INDEX_op_br:
+        tcg_out_jxx(s, JCC_JMP, args[0], 0);
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    OP_32_64(ld8u):
+        /* Note that we can ignore REXW for the zero-extend to 64-bit.  */
+        tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]);
+        break;
+    OP_32_64(ld8s):
+        tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, args[0], args[1], args[2]);
+        break;
+    OP_32_64(ld16u):
+        /* Note that we can ignore REXW for the zero-extend to 64-bit.  */
+        tcg_out_modrm_offset(s, OPC_MOVZWL, args[0], args[1], args[2]);
+        break;
+    OP_32_64(ld16s):
+        tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, args[0], args[1], args[2]);
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_ld32u_i64:
+#endif
+    case INDEX_op_ld_i32:
+        tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+        break;
+
+    OP_32_64(st8):
+        tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R,
+                             args[0], args[1], args[2]);
+        break;
+    OP_32_64(st16):
+        tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16,
+                             args[0], args[1], args[2]);
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_st32_i64:
+#endif
+    case INDEX_op_st_i32:
+        tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+        break;
+
+    OP_32_64(add):
+        /* For 3-operand addition, use LEA.  */
+        if (args[0] != args[1]) {
+            TCGArg a0 = args[0], a1 = args[1], a2 = args[2], c3 = 0;
+
+            if (const_args[2]) {
+                c3 = a2, a2 = -1;
+            } else if (a0 == a2) {
+                /* Watch out for dest = src + dest, since we've removed
+                   the matching constraint on the add.  */
+                tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
+                break;
+            }
+
+            tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3);
+            break;
+        }
+        c = ARITH_ADD;
+        goto gen_arith;
+    OP_32_64(sub):
+        c = ARITH_SUB;
+        goto gen_arith;
+    OP_32_64(and):
+        c = ARITH_AND;
+        goto gen_arith;
+    OP_32_64(or):
+        c = ARITH_OR;
+        goto gen_arith;
+    OP_32_64(xor):
+        c = ARITH_XOR;
+        goto gen_arith;
+    gen_arith:
+        if (const_args[2]) {
+            tgen_arithi(s, c + rexw, args[0], args[2], 0);
+        } else {
+            tgen_arithr(s, c + rexw, args[0], args[2]);
+        }
+        break;
+
+    OP_32_64(mul):
+        if (const_args[2]) {
+            int32_t val;
+            val = args[2];
+            if (val == (int8_t)val) {
+                tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, args[0], args[0]);
+                tcg_out8(s, val);
+            } else {
+                tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, args[0], args[0]);
+                tcg_out32(s, val);
+            }
+        } else {
+            tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, args[0], args[2]);
+        }
+        break;
+
+    OP_32_64(div2):
+        tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]);
+        break;
+    OP_32_64(divu2):
+        tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]);
+        break;
+
+    OP_32_64(shl):
+        c = SHIFT_SHL;
+        goto gen_shift;
+    OP_32_64(shr):
+        c = SHIFT_SHR;
+        goto gen_shift;
+    OP_32_64(sar):
+        c = SHIFT_SAR;
+        goto gen_shift;
+    OP_32_64(rotl):
+        c = SHIFT_ROL;
+        goto gen_shift;
+    OP_32_64(rotr):
+        c = SHIFT_ROR;
+        goto gen_shift;
+    gen_shift:
+        if (const_args[2]) {
+            tcg_out_shifti(s, c + rexw, args[0], args[2]);
+        } else {
+            tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, args[0]);
+        }
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond32(s, args[2], args[0], args[1], const_args[1],
+                         args[3], 0);
+        break;
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond32(s, args[3], args[0], args[1],
+                          args[2], const_args[2]);
+        break;
+
+    OP_32_64(bswap16):
+        tcg_out_rolw_8(s, args[0]);
+        break;
+    OP_32_64(bswap32):
+        tcg_out_bswap32(s, args[0]);
+        break;
+
+    OP_32_64(neg):
+        tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, args[0]);
+        break;
+    OP_32_64(not):
+        tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, args[0]);
+        break;
+
+    OP_32_64(ext8s):
+        tcg_out_ext8s(s, args[0], args[1], rexw);
+        break;
+    OP_32_64(ext16s):
+        tcg_out_ext16s(s, args[0], args[1], rexw);
+        break;
+    OP_32_64(ext8u):
+        tcg_out_ext8u(s, args[0], args[1]);
+        break;
+    OP_32_64(ext16u):
+        tcg_out_ext16u(s, args[0], args[1]);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_qemu_ld32u:
+#endif
+    case INDEX_op_qemu_ld32:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+#if TCG_TARGET_REG_BITS == 32
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2(s, args, const_args, 0);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2(s, args, const_args);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
+        break;
+    case INDEX_op_add2_i32:
+        if (const_args[4]) {
+            tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
+        } else {
+            tgen_arithr(s, ARITH_ADD, args[0], args[4]);
+        }
+        if (const_args[5]) {
+            tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
+        } else {
+            tgen_arithr(s, ARITH_ADC, args[1], args[5]);
+        }
+        break;
+    case INDEX_op_sub2_i32:
+        if (const_args[4]) {
+            tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
+        } else {
+            tgen_arithr(s, ARITH_SUB, args[0], args[4]);
+        }
+        if (const_args[5]) {
+            tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
+        } else {
+            tgen_arithr(s, ARITH_SBB, args[1], args[5]);
+        }
+        break;
+#else /* TCG_TARGET_REG_BITS == 64 */
+    case INDEX_op_movi_i64:
+        tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ld32s_i64:
+        tcg_out_modrm_offset(s, OPC_MOVSLQ, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld_i64:
+        tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i64:
+        tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_qemu_ld32s:
+        tcg_out_qemu_ld(s, args, 2 | 4);
+        break;
+
+    case INDEX_op_brcond_i64:
+        tcg_out_brcond64(s, args[2], args[0], args[1], const_args[1],
+                         args[3], 0);
+        break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond64(s, args[3], args[0], args[1],
+                          args[2], const_args[2]);
+        break;
+
+    case INDEX_op_bswap64_i64:
+        tcg_out_bswap64(s, args[0]);
+        break;
+    case INDEX_op_ext32u_i64:
+        tcg_out_ext32u(s, args[0], args[1]);
+        break;
+    case INDEX_op_ext32s_i64:
+        tcg_out_ext32s(s, args[0], args[1]);
+        break;
+#endif
+
+    default:
+        tcg_abort();
+    }
+
+#undef OP_32_64
+}
+
+static const TCGTargetOpDef x86_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "q", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+
+    { INDEX_op_add_i32, { "r", "r", "ri" } },
+    { INDEX_op_sub_i32, { "r", "0", "ri" } },
+    { INDEX_op_mul_i32, { "r", "0", "ri" } },
+    { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
+    { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
+    { INDEX_op_and_i32, { "r", "0", "ri" } },
+    { INDEX_op_or_i32, { "r", "0", "ri" } },
+    { INDEX_op_xor_i32, { "r", "0", "ri" } },
+
+    { INDEX_op_shl_i32, { "r", "0", "ci" } },
+    { INDEX_op_shr_i32, { "r", "0", "ci" } },
+    { INDEX_op_sar_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotl_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotr_i32, { "r", "0", "ci" } },
+
+    { INDEX_op_brcond_i32, { "r", "ri" } },
+
+    { INDEX_op_bswap16_i32, { "r", "0" } },
+    { INDEX_op_bswap32_i32, { "r", "0" } },
+
+    { INDEX_op_neg_i32, { "r", "0" } },
+
+    { INDEX_op_not_i32, { "r", "0" } },
+
+    { INDEX_op_ext8s_i32, { "r", "q" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext8u_i32, { "r", "q" } },
+    { INDEX_op_ext16u_i32, { "r", "r" } },
+
+    { INDEX_op_setcond_i32, { "q", "r", "ri" } },
+
+#if TCG_TARGET_REG_BITS == 32
+    { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
+    { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+    { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+    { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+#else
+    { INDEX_op_mov_i64, { "r", "r" } },
+    { INDEX_op_movi_i64, { "r" } },
+    { INDEX_op_ld8u_i64, { "r", "r" } },
+    { INDEX_op_ld8s_i64, { "r", "r" } },
+    { INDEX_op_ld16u_i64, { "r", "r" } },
+    { INDEX_op_ld16s_i64, { "r", "r" } },
+    { INDEX_op_ld32u_i64, { "r", "r" } },
+    { INDEX_op_ld32s_i64, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+    { INDEX_op_st8_i64, { "r", "r" } },
+    { INDEX_op_st16_i64, { "r", "r" } },
+    { INDEX_op_st32_i64, { "r", "r" } },
+    { INDEX_op_st_i64, { "r", "r" } },
+
+    { INDEX_op_add_i64, { "r", "0", "re" } },
+    { INDEX_op_mul_i64, { "r", "0", "re" } },
+    { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } },
+    { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } },
+    { INDEX_op_sub_i64, { "r", "0", "re" } },
+    { INDEX_op_and_i64, { "r", "0", "reZ" } },
+    { INDEX_op_or_i64, { "r", "0", "re" } },
+    { INDEX_op_xor_i64, { "r", "0", "re" } },
+
+    { INDEX_op_shl_i64, { "r", "0", "ci" } },
+    { INDEX_op_shr_i64, { "r", "0", "ci" } },
+    { INDEX_op_sar_i64, { "r", "0", "ci" } },
+    { INDEX_op_rotl_i64, { "r", "0", "ci" } },
+    { INDEX_op_rotr_i64, { "r", "0", "ci" } },
+
+    { INDEX_op_brcond_i64, { "r", "re" } },
+    { INDEX_op_setcond_i64, { "r", "r", "re" } },
+
+    { INDEX_op_bswap16_i64, { "r", "0" } },
+    { INDEX_op_bswap32_i64, { "r", "0" } },
+    { INDEX_op_bswap64_i64, { "r", "0" } },
+    { INDEX_op_neg_i64, { "r", "0" } },
+    { INDEX_op_not_i64, { "r", "0" } },
+
+    { INDEX_op_ext8s_i64, { "r", "r" } },
+    { INDEX_op_ext16s_i64, { "r", "r" } },
+    { INDEX_op_ext32s_i64, { "r", "r" } },
+    { INDEX_op_ext8u_i64, { "r", "r" } },
+    { INDEX_op_ext16u_i64, { "r", "r" } },
+    { INDEX_op_ext32u_i64, { "r", "r" } },
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld32u, { "r", "L" } },
+    { INDEX_op_qemu_ld32s, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "L", "L" } },
+    { INDEX_op_qemu_st16, { "L", "L" } },
+    { INDEX_op_qemu_st32, { "L", "L" } },
+    { INDEX_op_qemu_st64, { "L", "L" } },
+#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "cb", "L" } },
+    { INDEX_op_qemu_st16, { "L", "L" } },
+    { INDEX_op_qemu_st32, { "L", "L" } },
+    { INDEX_op_qemu_st64, { "L", "L", "L" } },
+#else
+    { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
+
+    { INDEX_op_qemu_st8, { "cb", "L", "L" } },
+    { INDEX_op_qemu_st16, { "L", "L", "L" } },
+    { INDEX_op_qemu_st32, { "L", "L", "L" } },
+    { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
+#endif
+    { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+#if TCG_TARGET_REG_BITS == 64
+    TCG_REG_RBP,
+    TCG_REG_RBX,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14, /* Currently used for the global env. */
+    TCG_REG_R15,
+#else
+    TCG_REG_EBP, /* Currently used for the global env. */
+    TCG_REG_EBX,
+    TCG_REG_ESI,
+    TCG_REG_EDI,
+#endif
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int i, frame_size, push_size, stack_addend;
+
+    /* TB prologue */
+
+    /* Reserve some stack space, also for TCG temps.  */
+    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
+    push_size *= TCG_TARGET_REG_BITS / 8;
+
+    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
+        CPU_TEMP_BUF_NLONGS * sizeof(long);
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+        ~(TCG_TARGET_STACK_ALIGN - 1);
+    stack_addend = frame_size - push_size;
+    tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
+    /* Save all callee saved registers.  */
+    for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_push(s, tcg_target_callee_save_regs[i]);
+    }
+
+    tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
+
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+
+    /* jmp *tb.  */
+    tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]);
+
+    /* TB epilogue */
+    tb_ret_addr = s->code_ptr;
+
+    tcg_out_addi(s, TCG_REG_CALL_STACK, stack_addend);
+
+    for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+        tcg_out_pop(s, tcg_target_callee_save_regs[i]);
+    }
+    tcg_out_opc(s, OPC_RET, 0, 0, 0);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* fail safe */
+    if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+        tcg_abort();
+#endif
+
+    if (TCG_TARGET_REG_BITS == 64) {
+        tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+        tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
+    } else {
+        tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
+    }
+
+    tcg_regset_clear(tcg_target_call_clobber_regs);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EAX);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
+    if (TCG_TARGET_REG_BITS == 64) {
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RDI);
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RSI);
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
+        tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
+    }
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+
+    tcg_add_target_add_op_defs(x86_op_defs);
+}
diff --git a/qemu-0.15.x/tcg/i386/tcg-target.h b/qemu-0.15.x/tcg/i386/tcg-target.h
new file mode 100644
index 0000000..bfafbfc
--- /dev/null
+++ b/qemu-0.15.x/tcg/i386/tcg-target.h
@@ -0,0 +1,126 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_I386 1
+
+#if defined(__x86_64__)
+# define TCG_TARGET_REG_BITS 64
+#else
+# define TCG_TARGET_REG_BITS 32
+#endif
+//#define TCG_TARGET_WORDS_BIGENDIAN
+
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_TARGET_NB_REGS 16
+#else
+# define TCG_TARGET_NB_REGS 8
+#endif
+
+enum {
+    TCG_REG_EAX = 0,
+    TCG_REG_ECX,
+    TCG_REG_EDX,
+    TCG_REG_EBX,
+    TCG_REG_ESP,
+    TCG_REG_EBP,
+    TCG_REG_ESI,
+    TCG_REG_EDI,
+
+    /* 64-bit registers; always define the symbols to avoid
+       too much if-deffing.  */
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_RAX = TCG_REG_EAX,
+    TCG_REG_RCX = TCG_REG_ECX,
+    TCG_REG_RDX = TCG_REG_EDX,
+    TCG_REG_RBX = TCG_REG_EBX,
+    TCG_REG_RSP = TCG_REG_ESP,
+    TCG_REG_RBP = TCG_REG_EBP,
+    TCG_REG_RSI = TCG_REG_ESI,
+    TCG_REG_RDI = TCG_REG_EDI,
+};
+
+#define TCG_CT_CONST_S32 0x100
+#define TCG_CT_CONST_U32 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_ESP 
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div2_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div2_i64
+#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* Note: must be synced with dyngen-exec.h */
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_AREG0 TCG_REG_R14
+#else
+# define TCG_AREG0 TCG_REG_EBP
+#endif
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/qemu-0.15.x/tcg/ia64/tcg-target.c b/qemu-0.15.x/tcg/ia64/tcg-target.c
new file mode 100644
index 0000000..6386a5b
--- /dev/null
+++ b/qemu-0.15.x/tcg/ia64/tcg-target.c
@@ -0,0 +1,2393 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009-2010 Aurelien Jarno <aurelien at aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 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.
+ */
+
+/*
+ * Register definitions
+ */
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+     "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+    "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+    "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+    "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
+    "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
+};
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R55
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+/* Branch registers */
+enum {
+    TCG_REG_B0 = 0,
+    TCG_REG_B1,
+    TCG_REG_B2,
+    TCG_REG_B3,
+    TCG_REG_B4,
+    TCG_REG_B5,
+    TCG_REG_B6,
+    TCG_REG_B7,
+};
+
+/* Floating point registers */
+enum {
+    TCG_REG_F0 = 0,
+    TCG_REG_F1,
+    TCG_REG_F2,
+    TCG_REG_F3,
+    TCG_REG_F4,
+    TCG_REG_F5,
+    TCG_REG_F6,
+    TCG_REG_F7,
+    TCG_REG_F8,
+    TCG_REG_F9,
+    TCG_REG_F10,
+    TCG_REG_F11,
+    TCG_REG_F12,
+    TCG_REG_F13,
+    TCG_REG_F14,
+    TCG_REG_F15,
+};
+
+/* Predicate registers */
+enum {
+    TCG_REG_P0 = 0,
+    TCG_REG_P1,
+    TCG_REG_P2,
+    TCG_REG_P3,
+    TCG_REG_P4,
+    TCG_REG_P5,
+    TCG_REG_P6,
+    TCG_REG_P7,
+    TCG_REG_P8,
+    TCG_REG_P9,
+    TCG_REG_P10,
+    TCG_REG_P11,
+    TCG_REG_P12,
+    TCG_REG_P13,
+    TCG_REG_P14,
+    TCG_REG_P15,
+};
+
+/* Application registers */
+enum {
+    TCG_REG_PFS = 64,
+};
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R34,
+    TCG_REG_R35,
+    TCG_REG_R36,
+    TCG_REG_R37,
+    TCG_REG_R38,
+    TCG_REG_R39,
+    TCG_REG_R40,
+    TCG_REG_R41,
+    TCG_REG_R42,
+    TCG_REG_R43,
+    TCG_REG_R44,
+    TCG_REG_R45,
+    TCG_REG_R46,
+    TCG_REG_R47,
+    TCG_REG_R48,
+    TCG_REG_R49,
+    TCG_REG_R50,
+    TCG_REG_R51,
+    TCG_REG_R52,
+    TCG_REG_R53,
+    TCG_REG_R54,
+    TCG_REG_R55,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31,
+    TCG_REG_R56,
+    TCG_REG_R57,
+    TCG_REG_R58,
+    TCG_REG_R59,
+    TCG_REG_R60,
+    TCG_REG_R61,
+    TCG_REG_R62,
+    TCG_REG_R63,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11
+};
+
+static const int tcg_target_call_iarg_regs[8] = {
+    TCG_REG_R56,
+    TCG_REG_R57,
+    TCG_REG_R58,
+    TCG_REG_R59,
+    TCG_REG_R60,
+    TCG_REG_R61,
+    TCG_REG_R62,
+    TCG_REG_R63,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_R8,
+    TCG_REG_R9
+};
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 8;
+}
+
+/*
+ * opcode formation
+ */
+
+/* bundle templates: stops (double bar in the IA64 manual) are marked with
+   an uppercase letter. */
+enum {
+    mii = 0x00,
+    miI = 0x01,
+    mIi = 0x02,
+    mII = 0x03,
+    mlx = 0x04,
+    mLX = 0x05,
+    mmi = 0x08,
+    mmI = 0x09,
+    Mmi = 0x0a,
+    MmI = 0x0b,
+    mfi = 0x0c,
+    mfI = 0x0d,
+    mmf = 0x0e,
+    mmF = 0x0f,
+    mib = 0x10,
+    miB = 0x11,
+    mbb = 0x12,
+    mbB = 0x13,
+    bbb = 0x16,
+    bbB = 0x17,
+    mmb = 0x18,
+    mmB = 0x19,
+    mfb = 0x1c,
+    mfB = 0x1d,
+};
+
+enum {
+    OPC_ADD_A1                = 0x10000000000ull,
+    OPC_AND_A1                = 0x10060000000ull,
+    OPC_AND_A3                = 0x10160000000ull,
+    OPC_ANDCM_A1              = 0x10068000000ull,
+    OPC_ANDCM_A3              = 0x10168000000ull,
+    OPC_ADDS_A4               = 0x10800000000ull,
+    OPC_ADDL_A5               = 0x12000000000ull,
+    OPC_ALLOC_M34             = 0x02c00000000ull,
+    OPC_BR_DPTK_FEW_B1        = 0x08400000000ull,
+    OPC_BR_SPTK_MANY_B1       = 0x08000001000ull,
+    OPC_BR_SPTK_MANY_B4       = 0x00100001000ull,
+    OPC_BR_CALL_SPTK_MANY_B5  = 0x02100001000ull,
+    OPC_BR_RET_SPTK_MANY_B4   = 0x00108001100ull,
+    OPC_BRL_SPTK_MANY_X3      = 0x18000001000ull,
+    OPC_CMP_LT_A6             = 0x18000000000ull,
+    OPC_CMP_LTU_A6            = 0x1a000000000ull,
+    OPC_CMP_EQ_A6             = 0x1c000000000ull,
+    OPC_CMP4_LT_A6            = 0x18400000000ull,
+    OPC_CMP4_LTU_A6           = 0x1a400000000ull,
+    OPC_CMP4_EQ_A6            = 0x1c400000000ull,
+    OPC_DEP_Z_I12             = 0x0a600000000ull,
+    OPC_EXTR_I11              = 0x0a400002000ull,
+    OPC_EXTR_U_I11            = 0x0a400000000ull,
+    OPC_FCVT_FX_TRUNC_S1_F10  = 0x004d0000000ull,
+    OPC_FCVT_FXU_TRUNC_S1_F10 = 0x004d8000000ull,
+    OPC_FCVT_XF_F11           = 0x000e0000000ull,
+    OPC_FMA_S1_F1             = 0x10400000000ull,
+    OPC_FNMA_S1_F1            = 0x18400000000ull,
+    OPC_FRCPA_S1_F6           = 0x00600000000ull,
+    OPC_GETF_SIG_M19          = 0x08708000000ull,
+    OPC_LD1_M1                = 0x08000000000ull,
+    OPC_LD1_M3                = 0x0a000000000ull,
+    OPC_LD2_M1                = 0x08040000000ull,
+    OPC_LD2_M3                = 0x0a040000000ull,
+    OPC_LD4_M1                = 0x08080000000ull,
+    OPC_LD4_M3                = 0x0a080000000ull,
+    OPC_LD8_M1                = 0x080c0000000ull,
+    OPC_LD8_M3                = 0x0a0c0000000ull,
+    OPC_MUX1_I3               = 0x0eca0000000ull,
+    OPC_NOP_B9                = 0x04008000000ull,
+    OPC_NOP_F16               = 0x00008000000ull,
+    OPC_NOP_I18               = 0x00008000000ull,
+    OPC_NOP_M48               = 0x00008000000ull,
+    OPC_MOV_I21               = 0x00e00100000ull,
+    OPC_MOV_RET_I21           = 0x00e00500000ull,
+    OPC_MOV_I22               = 0x00188000000ull,
+    OPC_MOV_I_I26             = 0x00150000000ull,
+    OPC_MOVL_X2               = 0x0c000000000ull,
+    OPC_OR_A1                 = 0x10070000000ull,
+    OPC_SETF_EXP_M18          = 0x0c748000000ull,
+    OPC_SETF_SIG_M18          = 0x0c708000000ull,
+    OPC_SHL_I7                = 0x0f240000000ull,
+    OPC_SHR_I5                = 0x0f220000000ull,
+    OPC_SHR_U_I5              = 0x0f200000000ull,
+    OPC_SHRP_I10              = 0x0ac00000000ull,
+    OPC_SXT1_I29              = 0x000a0000000ull,
+    OPC_SXT2_I29              = 0x000a8000000ull,
+    OPC_SXT4_I29              = 0x000b0000000ull,
+    OPC_ST1_M4                = 0x08c00000000ull,
+    OPC_ST2_M4                = 0x08c40000000ull,
+    OPC_ST4_M4                = 0x08c80000000ull,
+    OPC_ST8_M4                = 0x08cc0000000ull,
+    OPC_SUB_A1                = 0x10028000000ull,
+    OPC_SUB_A3                = 0x10128000000ull,
+    OPC_UNPACK4_L_I2          = 0x0f860000000ull,
+    OPC_XMA_L_F2              = 0x1d000000000ull,
+    OPC_XOR_A1                = 0x10078000000ull,
+    OPC_ZXT1_I29              = 0x00080000000ull,
+    OPC_ZXT2_I29              = 0x00088000000ull,
+    OPC_ZXT4_I29              = 0x00090000000ull,
+};
+
+static inline uint64_t tcg_opc_a1(int qp, uint64_t opc, int r1,
+                                  int r2, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a3(int qp, uint64_t opc, int r1,
+                                  uint64_t imm, int r3)
+{
+    return opc
+           | ((imm & 0x80) << 29) /* s */
+           | ((imm & 0x7f) << 13) /* imm7b */
+           | ((r3 & 0x7f) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a4(int qp, uint64_t opc, int r1,
+                                  uint64_t imm, int r3)
+{
+    return opc
+           | ((imm & 0x2000) << 23) /* s */
+           | ((imm & 0x1f80) << 20) /* imm6d */
+           | ((imm & 0x007f) << 13) /* imm7b */
+           | ((r3 & 0x7f) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a5(int qp, uint64_t opc, int r1,
+                                  uint64_t imm, int r3)
+{
+    return opc
+           | ((imm & 0x200000) << 15) /* s */
+           | ((imm & 0x1f0000) <<  6) /* imm5c */
+           | ((imm & 0x00ff80) << 20) /* imm9d */
+           | ((imm & 0x00007f) << 13) /* imm7b */
+           | ((r3 & 0x03) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a6(int qp, uint64_t opc, int p1,
+                                  int p2, int r2, int r3)
+{
+    return opc
+           | ((p2 & 0x3f) << 27)
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((p1 & 0x3f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b1(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* s */
+           | ((imm & 0x0fffff) << 13) /* imm20b */
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b4(int qp, uint64_t opc, int b2)
+{
+    return opc
+           | ((b2 & 0x7) << 13)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b5(int qp, uint64_t opc, int b1, int b2)
+{
+    return opc
+           | ((b2 & 0x7) << 13)
+           | ((b1 & 0x7) << 6)
+           | (qp & 0x3f);
+}
+
+
+static inline uint64_t tcg_opc_b9(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* i */
+           | ((imm & 0x0fffff) << 6)  /* imm20a */
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f1(int qp, uint64_t opc, int f1,
+                                  int f3, int f4, int f2)
+{
+    return opc
+           | ((f4 & 0x7f) << 27)
+           | ((f3 & 0x7f) << 20)
+           | ((f2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f2(int qp, uint64_t opc, int f1,
+                                  int f3, int f4, int f2)
+{
+    return opc
+           | ((f4 & 0x7f) << 27)
+           | ((f3 & 0x7f) << 20)
+           | ((f2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f6(int qp, uint64_t opc, int f1,
+                                  int p2, int f2, int f3)
+{
+    return opc
+           | ((p2 & 0x3f) << 27)
+           | ((f3 & 0x7f) << 20)
+           | ((f2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f10(int qp, uint64_t opc, int f1, int f2)
+{
+    return opc
+           | ((f2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f11(int qp, uint64_t opc, int f1, int f2)
+{
+    return opc
+           | ((f2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f16(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* i */
+           | ((imm & 0x0fffff) << 6)  /* imm20a */
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i2(int qp, uint64_t opc, int r1,
+                                  int r2, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i3(int qp, uint64_t opc, int r1,
+                                  int r2, int mbtype)
+{
+    return opc
+           | ((mbtype & 0x0f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i5(int qp, uint64_t opc, int r1,
+                                  int r3, int r2)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i7(int qp, uint64_t opc, int r1,
+                                  int r2, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i10(int qp, uint64_t opc, int r1,
+                                   int r2, int r3, uint64_t count)
+{
+    return opc
+           | ((count & 0x3f) << 27)
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i11(int qp, uint64_t opc, int r1,
+                                   int r3, uint64_t pos, uint64_t len)
+{
+    return opc
+           | ((len & 0x3f) << 27)
+           | ((r3 & 0x7f) << 20)
+           | ((pos & 0x3f) << 14)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i12(int qp, uint64_t opc, int r1,
+                                   int r2, uint64_t pos, uint64_t len)
+{
+    return opc
+           | ((len & 0x3f) << 27)
+           | ((pos & 0x3f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i18(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* i */
+           | ((imm & 0x0fffff) << 6)  /* imm20a */
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i21(int qp, uint64_t opc, int b1,
+                                   int r2, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x1ff) << 24)
+           | ((r2 & 0x7f) << 13)
+           | ((b1 & 0x7) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i22(int qp, uint64_t opc, int r1, int b2)
+{
+    return opc
+           | ((b2 & 0x7) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i26(int qp, uint64_t opc, int ar3, int r2)
+{
+    return opc
+           | ((ar3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i29(int qp, uint64_t opc, int r1, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_l2(uint64_t imm)
+{
+    return (imm & 0x7fffffffffc00000ull) >> 22;
+}
+
+static inline uint64_t tcg_opc_l3(uint64_t imm)
+{
+    return (imm & 0x07fffffffff00000ull) >> 18;
+}
+
+static inline uint64_t tcg_opc_m1(int qp, uint64_t opc, int r1, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m3(int qp, uint64_t opc, int r1,
+                                  int r3, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100) << 28) /* s */
+           | ((imm & 0x080) << 20) /* i */
+           | ((imm & 0x07f) << 13) /* imm7b */
+           | ((r3 & 0x7f) << 20)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m4(int qp, uint64_t opc, int r2, int r3)
+{
+    return opc
+           | ((r3 & 0x7f) << 20)
+           | ((r2 & 0x7f) << 13)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m18(int qp, uint64_t opc, int f1, int r2)
+{
+    return opc
+           | ((r2 & 0x7f) << 13)
+           | ((f1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m19(int qp, uint64_t opc, int r1, int f2)
+{
+    return opc
+           | ((f2 & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m34(int qp, uint64_t opc, int r1,
+                                   int sof, int sol, int sor)
+{
+    return opc
+           | ((sor & 0x0f) << 27)
+           | ((sol & 0x7f) << 20)
+           | ((sof & 0x7f) << 13)
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m48(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x100000) << 16) /* i */
+           | ((imm & 0x0fffff) << 6)  /* imm20a */
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_x2(int qp, uint64_t opc,
+                                  int r1, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x8000000000000000ull) >> 27) /* i */
+           |  (imm & 0x0000000000200000ull)        /* ic */
+           | ((imm & 0x00000000001f0000ull) << 6)  /* imm5c */
+           | ((imm & 0x000000000000ff80ull) << 20) /* imm9d */
+           | ((imm & 0x000000000000007full) << 13) /* imm7b */
+           | ((r1 & 0x7f) << 6)
+           | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_x3(int qp, uint64_t opc, uint64_t imm)
+{
+    return opc
+           | ((imm & 0x0800000000000000ull) >> 23) /* i */
+           | ((imm & 0x00000000000fffffull) << 13) /* imm20b */
+           | (qp & 0x3f);
+}
+
+
+/*
+ * Relocations
+ */
+
+static inline void reloc_pcrel21b (void *pc, tcg_target_long target)
+{
+    uint64_t imm;
+    int64_t disp;
+    int slot;
+
+    slot = (tcg_target_long) pc & 3;
+    pc = (void *)((tcg_target_long) pc & ~3);
+
+    disp = target - (tcg_target_long) pc;
+    imm = (uint64_t) disp >> 4;
+
+    switch(slot) {
+    case 0:
+        *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 8) & 0xfffffdc00003ffffull)
+                                | ((imm & 0x100000) << 21)  /* s */
+                                | ((imm & 0x0fffff) << 18); /* imm20b */
+        break;
+    case 1:
+        *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xfffffffffffb8000ull)
+                                | ((imm & 0x100000) >> 2)   /* s */
+                                | ((imm & 0x0fffe0) >> 5);  /* imm20b */
+        *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x07ffffffffffffffull)
+                                | ((imm & 0x00001f) << 59); /* imm20b */
+        break;
+    case 2:
+        *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fffffffffull)
+                                | ((imm & 0x100000) << 39)  /* s */
+                                | ((imm & 0x0fffff) << 36); /* imm20b */
+        break;
+    }
+}
+
+static inline uint64_t get_reloc_pcrel21b (void *pc)
+{
+    int64_t low, high;
+    int slot;
+
+    slot = (tcg_target_long) pc & 3;
+    pc = (void *)((tcg_target_long) pc & ~3);
+
+    low  = (*(uint64_t *)(pc + 0));
+    high = (*(uint64_t *)(pc + 8));
+
+    switch(slot) {
+    case 0:
+        return ((low >> 21) & 0x100000) + /* s */
+               ((low >> 18) & 0x0fffff);  /* imm20b */
+    case 1:
+        return ((high << 2) & 0x100000) + /* s */
+               ((high << 5) & 0x0fffe0) + /* imm20b */
+               ((low >> 59) & 0x00001f);  /* imm20b */
+    case 2:
+        return ((high >> 39) & 0x100000) + /* s */
+               ((high >> 36) & 0x0fffff);  /* imm20b */
+    default:
+        tcg_abort();
+    }
+}
+
+static inline void reloc_pcrel60b (void *pc, tcg_target_long target)
+{
+    int64_t disp;
+    uint64_t imm;
+
+    disp = target - (tcg_target_long) pc;
+    imm = (uint64_t) disp >> 4;
+
+    *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fff800000ull)
+                             |  (imm & 0x0800000000000000ull)         /* s */
+                             | ((imm & 0x07fffff000000000ull) >> 36)  /* imm39 */
+                             | ((imm & 0x00000000000fffffull) << 36); /* imm20b */
+    *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x00003fffffffffffull)
+                             | ((imm & 0x0000000ffff00000ull) << 28); /* imm39 */
+}
+
+static inline uint64_t get_reloc_pcrel60b (void *pc)
+{
+    int64_t low, high;
+
+    low  = (*(uint64_t *)(pc + 0));
+    high = (*(uint64_t *)(pc + 8));
+
+    return ((high)       & 0x0800000000000000ull) + /* s */
+           ((high >> 36) & 0x00000000000fffffull) + /* imm20b */
+           ((high << 36) & 0x07fffff000000000ull) + /* imm39 */
+           ((low >> 28)  & 0x0000000ffff00000ull);  /* imm39 */
+}
+
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch (type) {
+    case R_IA64_PCREL21B:
+        reloc_pcrel21b(code_ptr, value);
+        break;
+    case R_IA64_PCREL60B:
+        reloc_pcrel60b(code_ptr, value);
+    default:
+        tcg_abort();
+    }
+}
+
+/*
+ * Constraints
+ */
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch(ct_str[0]) {
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffffffffffffull);
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_S22;
+        break;
+    case 'S':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffffffffffffull);
+#if defined(CONFIG_SOFTMMU)
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R56);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R57);
+#endif
+        break;
+    case 'Z':
+        /* We are cheating a bit here, using the fact that the register
+           r0 is also the register number 0. Hence there is no need
+           to check for const_args in each instruction. */
+        ct->ct |= TCG_CT_CONST_ZERO;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+                                         const TCGArgConstraint *arg_ct)
+{
+    int ct;
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+        return 1;
+    else if ((ct & TCG_CT_CONST_S22) && val == ((int32_t)val << 10) >> 10)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * Code generation
+ */
+
+static uint8_t *tb_ret_addr;
+
+static inline void tcg_out_bundle(TCGContext *s, int template,
+                                  uint64_t slot0, uint64_t slot1,
+                                  uint64_t slot2)
+{
+    template &= 0x1f;          /* 5 bits */
+    slot0 &= 0x1ffffffffffull; /* 41 bits */
+    slot1 &= 0x1ffffffffffull; /* 41 bits */
+    slot2 &= 0x1ffffffffffull; /* 41 bits */
+
+    *(uint64_t *)(s->code_ptr + 0) = (slot1 << 46) | (slot0 << 5) | template;
+    *(uint64_t *)(s->code_ptr + 8) = (slot2 << 23) | (slot1 >> 18);
+    s->code_ptr += 16;
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+                               TCGArg ret, TCGArg arg)
+{
+    tcg_out_bundle(s, mmI,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, ret, 0, arg));
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+                                TCGArg reg, tcg_target_long arg)
+{
+    tcg_out_bundle(s, mLX,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_l2 (arg),
+                   tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, reg, arg));
+}
+
+static inline void tcg_out_addi(TCGContext *s, TCGArg reg, tcg_target_long val)
+{
+    if (val == ((int32_t)val << 10) >> 10) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+                                  TCG_REG_R2, val, TCG_REG_R0),
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
+                                   reg, TCG_REG_R2));
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, val);
+        tcg_out_bundle(s, mmI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
+                                   reg, TCG_REG_R2));
+    }
+}
+
+static void tcg_out_br(TCGContext *s, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    /* We pay attention here to not modify the branch target by reading
+       the existing value and using it again. This ensure that caches and
+       memory are kept coherent during retranslation. */
+    tcg_out_bundle(s, mmB,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_b1 (TCG_REG_P0, OPC_BR_SPTK_MANY_B1,
+                               get_reloc_pcrel21b(s->code_ptr + 2)));
+
+    if (l->has_value) {
+        reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value);
+    } else {
+        tcg_out_reloc(s, (s->code_ptr - 16) + 2,
+                      R_IA64_PCREL21B, label_index, 0);
+    }
+}
+
+static inline void tcg_out_call(TCGContext *s, TCGArg addr)
+{
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R2, addr),
+                   tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R3, 8, addr),
+                   tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+                               TCG_REG_B6, TCG_REG_R2, 0));
+    tcg_out_bundle(s, mmB,
+                   tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R3),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_b5 (TCG_REG_P0, OPC_BR_CALL_SPTK_MANY_B5,
+                               TCG_REG_B0, TCG_REG_B6));
+}
+
+static void tcg_out_exit_tb(TCGContext *s, tcg_target_long arg)
+{
+    int64_t disp;
+    uint64_t imm;
+
+    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R8, arg);
+
+    disp = tb_ret_addr - s->code_ptr;
+    imm = (uint64_t)disp >> 4;
+
+    tcg_out_bundle(s, mLX,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_l3 (imm),
+                   tcg_opc_x3 (TCG_REG_P0, OPC_BRL_SPTK_MANY_X3, imm));
+}
+
+static inline void tcg_out_goto_tb(TCGContext *s, TCGArg arg)
+{
+    if (s->tb_jmp_offset) {
+        /* direct jump method */
+        tcg_abort();
+    } else {
+        /* indirect jump method */
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2,
+                     (tcg_target_long)(s->tb_next + arg));
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1,
+                                   TCG_REG_R2, TCG_REG_R2),
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, TCG_REG_B6,
+                                   TCG_REG_R2, 0));
+        tcg_out_bundle(s, mmB,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4,
+                                   TCG_REG_B6));
+    }
+    s->tb_next_offset[arg] = s->code_ptr - s->code_buf;
+}
+
+static inline void tcg_out_jmp(TCGContext *s, TCGArg addr)
+{
+    tcg_out_bundle(s, mmI,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, TCG_REG_B6, addr, 0));
+    tcg_out_bundle(s, mmB,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_b4(TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
+}
+
+static inline void tcg_out_ld_rel(TCGContext *s, uint64_t opc_m4, TCGArg arg,
+                                  TCGArg arg1, tcg_target_long arg2)
+{
+    if (arg2 == ((int16_t)arg2 >> 2) << 2) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4,
+                                  TCG_REG_R2, arg2, arg1),
+                       tcg_opc_m1 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, arg2);
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1,
+                                   TCG_REG_R2, TCG_REG_R2, arg1),
+                       tcg_opc_m1 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+}
+
+static inline void tcg_out_st_rel(TCGContext *s, uint64_t opc_m4, TCGArg arg,
+                                  TCGArg arg1, tcg_target_long arg2)
+{
+    if (arg2 == ((int16_t)arg2 >> 2) << 2) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4,
+                                  TCG_REG_R2, arg2, arg1),
+                       tcg_opc_m4 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, arg2);
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1,
+                                   TCG_REG_R2, TCG_REG_R2, arg1),
+                       tcg_opc_m4 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGArg arg,
+                              TCGArg arg1, tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32) {
+        tcg_out_ld_rel(s, OPC_LD4_M1, arg, arg1, arg2);
+    } else {
+        tcg_out_ld_rel(s, OPC_LD8_M1, arg, arg1, arg2);
+    }
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGArg arg,
+                              TCGArg arg1, tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32) {
+        tcg_out_st_rel(s, OPC_ST4_M4, arg, arg1, arg2);
+    } else {
+        tcg_out_st_rel(s, OPC_ST8_M4, arg, arg1, arg2);
+    }
+}
+
+static inline void tcg_out_alu(TCGContext *s, uint64_t opc_a1, TCGArg ret,
+                               TCGArg arg1, int const_arg1,
+                               TCGArg arg2, int const_arg2)
+{
+    uint64_t opc1, opc2;
+
+    if (const_arg1 && arg1 != 0) {
+        opc1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+                          TCG_REG_R2, arg1, TCG_REG_R0);
+        arg1 = TCG_REG_R2;
+    } else {
+        opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+    }
+
+    if (const_arg2 && arg2 != 0) {
+        opc2 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+                          TCG_REG_R3, arg2, TCG_REG_R0);
+        arg2 = TCG_REG_R3;
+    } else {
+        opc2 = tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0);
+    }
+
+    tcg_out_bundle(s, mII,
+                   opc1,
+                   opc2,
+                   tcg_opc_a1(TCG_REG_P0, opc_a1, ret, arg1, arg2));
+}
+
+static inline void tcg_out_eqv(TCGContext *s, TCGArg ret,
+                               TCGArg arg1, int const_arg1,
+                               TCGArg arg2, int const_arg2)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a1 (TCG_REG_P0, OPC_XOR_A1, ret, arg1, arg2),
+                   tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_nand(TCGContext *s, TCGArg ret,
+                                TCGArg arg1, int const_arg1,
+                                TCGArg arg2, int const_arg2)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, ret, arg1, arg2),
+                   tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_nor(TCGContext *s, TCGArg ret,
+                               TCGArg arg1, int const_arg1,
+                               TCGArg arg2, int const_arg2)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret, arg1, arg2),
+                   tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_orc(TCGContext *s, TCGArg ret,
+                               TCGArg arg1, int const_arg1,
+                               TCGArg arg2, int const_arg2)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, TCG_REG_R2, -1, arg2),
+                   tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret, arg1, TCG_REG_R2));
+}
+
+static inline void tcg_out_mul(TCGContext *s, TCGArg ret,
+                               TCGArg arg1, TCGArg arg2)
+{
+    tcg_out_bundle(s, mmI,
+                   tcg_opc_m18(TCG_REG_P0, OPC_SETF_SIG_M18, TCG_REG_F6, arg1),
+                   tcg_opc_m18(TCG_REG_P0, OPC_SETF_SIG_M18, TCG_REG_F7, arg2),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    tcg_out_bundle(s, mmF,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_f2 (TCG_REG_P0, OPC_XMA_L_F2, TCG_REG_F6, TCG_REG_F6,
+                               TCG_REG_F7, TCG_REG_F0));
+    tcg_out_bundle(s, miI,
+                   tcg_opc_m19(TCG_REG_P0, OPC_GETF_SIG_M19, ret, TCG_REG_F6),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+}
+
+static inline void tcg_out_sar_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_I11,
+                                   ret, arg1, arg2, 31 - arg2));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3,
+                                   TCG_REG_R3, 0x1f, arg2),
+                       tcg_opc_i29(TCG_REG_P0, OPC_SXT4_I29, TCG_REG_R2, arg1),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_I5, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_sar_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_I11,
+                                   ret, arg1, arg2, 63 - arg2));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_I5, ret, arg1, arg2));
+    }
+}
+
+static inline void tcg_out_shl_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret,
+                                   arg1, 63 - arg2, 31 - arg2));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R2,
+                                   0x1f, arg2),
+                       tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, ret,
+                                   arg1, TCG_REG_R2));
+    }
+}
+
+static inline void tcg_out_shl_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret,
+                                   arg1, 63 - arg2, 63 - arg2));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, ret,
+                                   arg1, arg2));
+    }
+}
+
+static inline void tcg_out_shr_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+                                   arg1, arg2, 31 - arg2));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+                                   0x1f, arg2),
+                       tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R2, arg1),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_shr_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                   TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+                                   arg1, arg2, 63 - arg2));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+                                   arg1, arg2));
+    }
+}
+
+static inline void tcg_out_rotl_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                    TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+                                   TCG_REG_R2, arg1, arg1),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+                                   TCG_REG_R2, 32 - arg2, 31));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+                                   TCG_REG_R2, arg1, arg1),
+                       tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+                                   0x1f, arg2));
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R3,
+                                   0x20, TCG_REG_R3),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_rotl_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                    TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i10(TCG_REG_P0, OPC_SHRP_I10, ret, arg1,
+                                   arg1, 0x40 - arg2));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R2,
+                                   0x40, arg2),
+                       tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, TCG_REG_R3,
+                                   arg1, arg2),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, TCG_REG_R2,
+                                   arg1, TCG_REG_R2));
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_rotr_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                    TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+                                   TCG_REG_R2, arg1, arg1),
+                       tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+                                   TCG_REG_R2, arg2, 31));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+                                   0x1f, arg2),
+                       tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+                                   TCG_REG_R2, arg1, arg1),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_rotr_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+                                    TCGArg arg2, int const_arg2)
+{
+    if (const_arg2) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i10(TCG_REG_P0, OPC_SHRP_I10, ret, arg1,
+                                   arg1, arg2));
+    } else {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R2,
+                                   0x40, arg2),
+                       tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, TCG_REG_R3,
+                                   arg1, arg2),
+                       tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, TCG_REG_R2,
+                                   arg1, TCG_REG_R2));
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret,
+                                   TCG_REG_R2, TCG_REG_R3));
+    }
+}
+
+static inline void tcg_out_ext(TCGContext *s, uint64_t opc_i29,
+                               TCGArg ret, TCGArg arg)
+{
+    tcg_out_bundle(s, miI,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                   tcg_opc_i29(TCG_REG_P0, opc_i29, ret, arg));
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret, arg, 15, 15),
+                   tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, ret, 0xb));
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret, arg, 31, 31),
+                   tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, ret, 0xb));
+}
+
+static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+    tcg_out_bundle(s, miI,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                   tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb));
+}
+
+static inline uint64_t tcg_opc_cmp_a(int qp, TCGCond cond, TCGArg arg1,
+                                     TCGArg arg2, int cmp4)
+{
+    uint64_t opc_eq_a6, opc_lt_a6, opc_ltu_a6;
+
+    if (cmp4) {
+        opc_eq_a6 = OPC_CMP4_EQ_A6;
+        opc_lt_a6 = OPC_CMP4_LT_A6;
+        opc_ltu_a6 = OPC_CMP4_LTU_A6;
+    } else {
+        opc_eq_a6 = OPC_CMP_EQ_A6;
+        opc_lt_a6 = OPC_CMP_LT_A6;
+        opc_ltu_a6 = OPC_CMP_LTU_A6;
+    }
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        return tcg_opc_a6 (qp, opc_eq_a6,  TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+    case TCG_COND_NE:
+        return tcg_opc_a6 (qp, opc_eq_a6,  TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+    case TCG_COND_LT:
+        return tcg_opc_a6 (qp, opc_lt_a6,  TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+    case TCG_COND_LTU:
+        return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+    case TCG_COND_GE:
+        return tcg_opc_a6 (qp, opc_lt_a6,  TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+    case TCG_COND_GEU:
+        return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+    case TCG_COND_LE:
+        return tcg_opc_a6 (qp, opc_lt_a6,  TCG_REG_P7, TCG_REG_P6, arg2, arg1);
+    case TCG_COND_LEU:
+        return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P7, TCG_REG_P6, arg2, arg1);
+    case TCG_COND_GT:
+        return tcg_opc_a6 (qp, opc_lt_a6,  TCG_REG_P6, TCG_REG_P7, arg2, arg1);
+    case TCG_COND_GTU:
+        return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P6, TCG_REG_P7, arg2, arg1);
+    default:
+        tcg_abort();
+        break;
+    }
+}
+
+static inline void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1,
+                                  int const_arg1, TCGArg arg2, int const_arg2,
+                                  int label_index, int cmp4)
+{
+    TCGLabel *l = &s->labels[label_index];
+    uint64_t opc1, opc2;
+
+    if (const_arg1 && arg1 != 0) {
+        opc1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2,
+                          arg1, TCG_REG_R0);
+        arg1 = TCG_REG_R2;
+    } else {
+        opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+    }
+
+    if (const_arg2 && arg2 != 0) {
+        opc2 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3,
+                          arg2, TCG_REG_R0);
+        arg2 = TCG_REG_R3;
+    } else {
+        opc2 = tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0);
+    }
+
+    tcg_out_bundle(s, mII,
+                   opc1,
+                   opc2,
+                   tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4));
+    tcg_out_bundle(s, mmB,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_b1 (TCG_REG_P6, OPC_BR_DPTK_FEW_B1,
+                               get_reloc_pcrel21b(s->code_ptr + 2)));
+
+    if (l->has_value) {
+        reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value);
+    } else {
+        tcg_out_reloc(s, (s->code_ptr - 16) + 2,
+                      R_IA64_PCREL21B, label_index, 0);
+    }
+}
+
+static inline void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg ret,
+                                   TCGArg arg1, TCGArg arg2, int cmp4)
+{
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4),
+                   tcg_opc_a5(TCG_REG_P6, OPC_ADDL_A5, ret, 1, TCG_REG_R0),
+                   tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, 0, TCG_REG_R0));
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+/* Load and compare a TLB entry, and return the result in (p6, p7).
+   R2 is loaded with the address of the addend TLB entry.
+   R56 is loaded with the address, zero extented on 32-bit targets. */
+static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg,
+                                    int s_bits, uint64_t offset_rw,
+                                    uint64_t offset_addend)
+{
+    tcg_out_bundle(s, mII,
+                   tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3,
+                               TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+                               TCG_REG_R0),
+                   tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R2,
+                               addr_reg, TARGET_PAGE_BITS, CPU_TLB_BITS - 1),
+                   tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R2,
+                               TCG_REG_R2, 63 - CPU_TLB_ENTRY_BITS,
+                               63 - CPU_TLB_ENTRY_BITS));
+    tcg_out_bundle(s, mII,
+                   tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2,
+                               offset_rw, TCG_REG_R2),
+#if TARGET_LONG_BITS == 32
+                   tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R56, addr_reg),
+#else
+                   tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R56,
+                              0, addr_reg),
+#endif
+                   tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+                               TCG_REG_R2, TCG_AREG0));
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m3 (TCG_REG_P0,
+                               (TARGET_LONG_BITS == 32
+                                ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R57,
+                               TCG_REG_R2, offset_addend - offset_rw),
+                   tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3,
+                               TCG_REG_R3, TCG_REG_R56),
+                   tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6,
+                               TCG_REG_P7, TCG_REG_R3, TCG_REG_R57));
+}
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, mem_index, s_bits, bswap;
+    uint64_t opc_ld_m1[4] = { OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1 };
+    uint64_t opc_ext_i29[8] = { OPC_ZXT1_I29, OPC_ZXT2_I29, OPC_ZXT4_I29, 0,
+                                OPC_SXT1_I29, OPC_SXT2_I29, OPC_SXT4_I29, 0 };
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+    s_bits = opc & 3;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+
+    /* Read the TLB entry */
+    tcg_out_qemu_tlb(s, addr_reg, s_bits,
+                     offsetof(CPUState, tlb_table[mem_index][0].addr_read),
+                     offsetof(CPUState, tlb_table[mem_index][0].addend));
+
+    /* P6 is the fast path, and P7 the slow path */
+    tcg_out_bundle(s, mLX,
+                   tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R57,
+                               mem_index, TCG_REG_R0),
+                   tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
+                               (tcg_target_long) qemu_ld_helpers[s_bits]));
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+                               TCG_REG_R2, 8),
+                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
+                               TCG_REG_R3, TCG_REG_R56),
+                   tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
+                               TCG_REG_R3, 0));
+    if (bswap && s_bits == 1) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+                                   TCG_REG_R8, TCG_REG_R3),
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+                                   TCG_REG_R8, TCG_REG_R8, 15, 15));
+    } else if (bswap && s_bits == 2) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+                                   TCG_REG_R8, TCG_REG_R3),
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+                                   TCG_REG_R8, TCG_REG_R8, 31, 31));
+    } else {
+        tcg_out_bundle(s, mmI,
+                       tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+                                   TCG_REG_R8, TCG_REG_R3),
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+    if (!bswap || s_bits == 0) {
+        tcg_out_bundle(s, miB,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+                                   TCG_REG_B0, TCG_REG_B6));
+    } else {
+        tcg_out_bundle(s, miB,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+                                   TCG_REG_R8, TCG_REG_R8, 0xb),
+                       tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+                                   TCG_REG_B0, TCG_REG_B6));
+    }
+
+    if (opc == 3) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+                                   data_reg, 0, TCG_REG_R8));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i29(TCG_REG_P0, opc_ext_i29[opc],
+                                   data_reg, TCG_REG_R8));
+    }
+}
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, mem_index, bswap;
+    uint64_t opc_st_m4[4] = { OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4 };
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+
+    tcg_out_qemu_tlb(s, addr_reg, opc,
+                     offsetof(CPUState, tlb_table[mem_index][0].addr_write),
+                     offsetof(CPUState, tlb_table[mem_index][0].addend));
+
+    /* P6 is the fast path, and P7 the slow path */
+    tcg_out_bundle(s, mLX,
+                   tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R57,
+                              0, data_reg),
+                   tcg_opc_l2 ((tcg_target_long) qemu_st_helpers[opc]),
+                   tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
+                               (tcg_target_long) qemu_st_helpers[opc]));
+    tcg_out_bundle(s, MmI,
+                   tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+                               TCG_REG_R2, 8),
+                   tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
+                               TCG_REG_R3, TCG_REG_R56),
+                   tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
+                               TCG_REG_R3, 0));
+
+    if (!bswap || opc == 0) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+                                   TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    } else if (opc == 1) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+                                   TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+                                   TCG_REG_R2, data_reg, 15, 15),
+                       tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+                                   TCG_REG_R2, TCG_REG_R2, 0xb));
+        data_reg = TCG_REG_R2;
+    } else if (opc == 2) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+                                   TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+                                   TCG_REG_R2, data_reg, 31, 31),
+                       tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+                                   TCG_REG_R2, TCG_REG_R2, 0xb));
+        data_reg = TCG_REG_R2;
+    } else if (opc == 3) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+                                   TCG_REG_R1, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+                                   TCG_REG_R2, data_reg, 0xb));
+        data_reg = TCG_REG_R2;
+    }
+
+    tcg_out_bundle(s, miB,
+                   tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
+                               data_reg, TCG_REG_R3),
+                   tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58,
+                               mem_index, TCG_REG_R0),
+                   tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+                               TCG_REG_B0, TCG_REG_B6));
+}
+
+#else /* !CONFIG_SOFTMMU */
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+    static uint64_t const opc_ld_m1[4] = {
+        OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1
+    };
+    static uint64_t const opc_sxt_i29[4] = {
+        OPC_SXT1_I29, OPC_SXT2_I29, OPC_SXT4_I29, 0
+    };
+    int addr_reg, data_reg, s_bits, bswap;
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    s_bits = opc & 3;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+
+#if TARGET_LONG_BITS == 32
+    if (GUEST_BASE != 0) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+                                   TCG_REG_R3, addr_reg),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+                                   TCG_GUEST_BASE_REG, TCG_REG_R3));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+                                   TCG_REG_R2, addr_reg),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+
+    if (!bswap || s_bits == 0) {
+        if (s_bits == opc) {
+            tcg_out_bundle(s, miI,
+                           tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                       data_reg, TCG_REG_R2),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+        } else {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                       data_reg, TCG_REG_R2),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+                                       data_reg, data_reg));
+        }
+    } else if (s_bits == 3) {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                       data_reg, TCG_REG_R2),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       data_reg, data_reg, 0xb));
+    } else {
+        if (s_bits == 1) {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                       data_reg, TCG_REG_R2),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                      data_reg, data_reg, 15, 15));
+        } else {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                       data_reg, TCG_REG_R2),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                      data_reg, data_reg, 31, 31));
+        }
+        if (opc == s_bits) {
+            tcg_out_bundle(s, miI,
+                           tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       data_reg, data_reg, 0xb));
+        } else {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       data_reg, data_reg, 0xb),
+                           tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+                                       data_reg, data_reg));
+        }
+    }
+#else
+    if (GUEST_BASE != 0) {
+        tcg_out_bundle(s, MmI,
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+                                   TCG_GUEST_BASE_REG, addr_reg),
+                       tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                   data_reg, TCG_REG_R2),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    } else {
+        tcg_out_bundle(s, mmI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+                                   data_reg, addr_reg),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+
+    if (bswap && s_bits == 1) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                   data_reg, data_reg, 15, 15),
+                       tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                   data_reg, data_reg, 0xb));
+    } else if (bswap && s_bits == 2) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                   data_reg, data_reg, 31, 31),
+                       tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                   data_reg, data_reg, 0xb));
+    } else if (bswap && s_bits == 3) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                   data_reg, data_reg, 0xb));
+    }
+    if (s_bits != opc) {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+                                   data_reg, data_reg));
+    }
+#endif
+}
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+    static uint64_t const opc_st_m4[4] = {
+        OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
+    };
+    int addr_reg, data_reg, bswap;
+#if TARGET_LONG_BITS == 64
+    uint64_t add_guest_base;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 1;
+#else
+    bswap = 0;
+#endif
+
+#if TARGET_LONG_BITS == 32
+    if (GUEST_BASE != 0) {
+        tcg_out_bundle(s, mII,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+                                   TCG_REG_R3, addr_reg),
+                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+                                   TCG_GUEST_BASE_REG, TCG_REG_R3));
+    } else {
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+                                   TCG_REG_R2, addr_reg),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+
+    if (bswap) {
+        if (opc == 1) {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                       TCG_REG_R3, data_reg, 15, 15),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, TCG_REG_R3, 0xb));
+            data_reg = TCG_REG_R3;
+        } else if (opc == 2) {
+            tcg_out_bundle(s, mII,
+                           tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                       TCG_REG_R3, data_reg, 31, 31),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, TCG_REG_R3, 0xb));
+            data_reg = TCG_REG_R3;
+        } else if (opc == 3) {
+            tcg_out_bundle(s, miI,
+                           tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, data_reg, 0xb));
+            data_reg = TCG_REG_R3;
+        }
+    }
+    tcg_out_bundle(s, mmI,
+                   tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+                               data_reg, TCG_REG_R2),
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+#else
+    if (GUEST_BASE != 0) {
+        add_guest_base = tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+                                     TCG_GUEST_BASE_REG, addr_reg);
+        addr_reg = TCG_REG_R2;
+    } else {
+        add_guest_base = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+    }
+
+    if (!bswap || opc == 0) {
+        tcg_out_bundle(s, (GUEST_BASE ? MmI : mmI),
+                       add_guest_base,
+                       tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+                                   data_reg, addr_reg),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    } else {
+        if (opc == 1) {
+            tcg_out_bundle(s, mII,
+                           add_guest_base,
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                       TCG_REG_R3, data_reg, 15, 15),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, TCG_REG_R3, 0xb));
+            data_reg = TCG_REG_R3;
+        } else if (opc == 2) {
+            tcg_out_bundle(s, mII,
+                           add_guest_base,
+                           tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+                                       TCG_REG_R3, data_reg, 31, 31),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, TCG_REG_R3, 0xb));
+            data_reg = TCG_REG_R3;
+        } else if (opc == 3) {
+            tcg_out_bundle(s, miI,
+                           add_guest_base,
+                           tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                           tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+                                       TCG_REG_R3, data_reg, 0xb));
+            data_reg = TCG_REG_R3;
+        }
+        tcg_out_bundle(s, miI,
+                       tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+                                   data_reg, addr_reg),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+                       tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+    }
+#endif
+}
+
+#endif
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+                              const TCGArg *args, const int *const_args)
+{
+    switch(opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_exit_tb(s, args[0]);
+        break;
+    case INDEX_op_br:
+        tcg_out_br(s, args[0]);
+        break;
+    case INDEX_op_call:
+        tcg_out_call(s, args[0]);
+        break;
+    case INDEX_op_goto_tb:
+        tcg_out_goto_tb(s, args[0]);
+        break;
+    case INDEX_op_jmp:
+        tcg_out_jmp(s, args[0]);
+        break;
+
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i64:
+        tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+
+    case INDEX_op_ld8u_i32:
+    case INDEX_op_ld8u_i64:
+        tcg_out_ld_rel(s, OPC_LD1_M1, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld8s_i32:
+    case INDEX_op_ld8s_i64:
+        tcg_out_ld_rel(s, OPC_LD1_M1, args[0], args[1], args[2]);
+        tcg_out_ext(s, OPC_SXT1_I29, args[0], args[0]);
+        break;
+    case INDEX_op_ld16u_i32:
+    case INDEX_op_ld16u_i64:
+        tcg_out_ld_rel(s, OPC_LD2_M1, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16s_i32:
+    case INDEX_op_ld16s_i64:
+        tcg_out_ld_rel(s, OPC_LD2_M1, args[0], args[1], args[2]);
+        tcg_out_ext(s, OPC_SXT2_I29, args[0], args[0]);
+        break;
+    case INDEX_op_ld_i32:
+    case INDEX_op_ld32u_i64:
+        tcg_out_ld_rel(s, OPC_LD4_M1, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld32s_i64:
+        tcg_out_ld_rel(s, OPC_LD4_M1, args[0], args[1], args[2]);
+        tcg_out_ext(s, OPC_SXT4_I29, args[0], args[0]);
+        break;
+    case INDEX_op_ld_i64:
+        tcg_out_ld_rel(s, OPC_LD8_M1, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st8_i32:
+    case INDEX_op_st8_i64:
+        tcg_out_st_rel(s, OPC_ST1_M4, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st16_i32:
+    case INDEX_op_st16_i64:
+        tcg_out_st_rel(s, OPC_ST2_M4, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i32:
+    case INDEX_op_st32_i64:
+        tcg_out_st_rel(s, OPC_ST4_M4, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i64:
+        tcg_out_st_rel(s, OPC_ST8_M4, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_add_i32:
+    case INDEX_op_add_i64:
+        tcg_out_alu(s, OPC_ADD_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_sub_i32:
+    case INDEX_op_sub_i64:
+        tcg_out_alu(s, OPC_SUB_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+
+    case INDEX_op_and_i32:
+    case INDEX_op_and_i64:
+        tcg_out_alu(s, OPC_AND_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_andc_i32:
+    case INDEX_op_andc_i64:
+        tcg_out_alu(s, OPC_ANDCM_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_eqv_i32:
+    case INDEX_op_eqv_i64:
+        tcg_out_eqv(s, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_nand_i32:
+    case INDEX_op_nand_i64:
+        tcg_out_nand(s, args[0], args[1], const_args[1],
+                     args[2], const_args[2]);
+        break;
+    case INDEX_op_nor_i32:
+    case INDEX_op_nor_i64:
+        tcg_out_nor(s, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_or_i32:
+    case INDEX_op_or_i64:
+        tcg_out_alu(s, OPC_OR_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_orc_i32:
+    case INDEX_op_orc_i64:
+        tcg_out_orc(s, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+    case INDEX_op_xor_i32:
+    case INDEX_op_xor_i64:
+        tcg_out_alu(s, OPC_XOR_A1, args[0], args[1], const_args[1],
+                    args[2], const_args[2]);
+        break;
+
+    case INDEX_op_mul_i32:
+    case INDEX_op_mul_i64:
+        tcg_out_mul(s, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_sar_i32:
+        tcg_out_sar_i32(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_sar_i64:
+        tcg_out_sar_i64(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_shl_i32:
+        tcg_out_shl_i32(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_shl_i64:
+        tcg_out_shl_i64(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_shr_i32:
+        tcg_out_shr_i32(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_shr_i64:
+        tcg_out_shr_i64(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_rotl_i32:
+        tcg_out_rotl_i32(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_rotl_i64:
+        tcg_out_rotl_i64(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_rotr_i32:
+        tcg_out_rotr_i32(s, args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_rotr_i64:
+        tcg_out_rotr_i64(s, args[0], args[1], args[2], const_args[2]);
+        break;
+
+    case INDEX_op_ext8s_i32:
+    case INDEX_op_ext8s_i64:
+        tcg_out_ext(s, OPC_SXT1_I29, args[0], args[1]);
+        break;
+    case INDEX_op_ext8u_i32:
+    case INDEX_op_ext8u_i64:
+        tcg_out_ext(s, OPC_ZXT1_I29, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+    case INDEX_op_ext16s_i64:
+        tcg_out_ext(s, OPC_SXT2_I29, args[0], args[1]);
+        break;
+    case INDEX_op_ext16u_i32:
+    case INDEX_op_ext16u_i64:
+        tcg_out_ext(s, OPC_ZXT2_I29, args[0], args[1]);
+        break;
+    case INDEX_op_ext32s_i64:
+        tcg_out_ext(s, OPC_SXT4_I29, args[0], args[1]);
+        break;
+    case INDEX_op_ext32u_i64:
+        tcg_out_ext(s, OPC_ZXT4_I29, args[0], args[1]);
+        break;
+
+    case INDEX_op_bswap16_i32:
+    case INDEX_op_bswap16_i64:
+        tcg_out_bswap16(s, args[0], args[1]);
+        break;
+    case INDEX_op_bswap32_i32:
+    case INDEX_op_bswap32_i64:
+        tcg_out_bswap32(s, args[0], args[1]);
+        break;
+    case INDEX_op_bswap64_i64:
+        tcg_out_bswap64(s, args[0], args[1]);
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond(s, args[2], args[0], const_args[0],
+                       args[1], const_args[1], args[3], 1);
+        break;
+    case INDEX_op_brcond_i64:
+        tcg_out_brcond(s, args[2], args[0], const_args[0],
+                       args[1], const_args[1], args[3], 0);
+        break;
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2], 1);
+        break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2], 0);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+    case INDEX_op_qemu_ld32u:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld32s:
+        tcg_out_qemu_ld(s, args, 2 | 4);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    default:
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef ia64_op_defs[] = {
+    { INDEX_op_br, { } },
+    { INDEX_op_call, { "r" } },
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_jmp, { "r" } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "rZ", "r" } },
+    { INDEX_op_st16_i32, { "rZ", "r" } },
+    { INDEX_op_st_i32, { "rZ", "r" } },
+
+    { INDEX_op_add_i32, { "r", "rI", "rI" } },
+    { INDEX_op_sub_i32, { "r", "rI", "rI" } },
+
+    { INDEX_op_and_i32, { "r", "rI", "rI" } },
+    { INDEX_op_andc_i32, { "r", "rI", "rI" } },
+    { INDEX_op_eqv_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_nand_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_or_i32, { "r", "rI", "rI" } },
+    { INDEX_op_orc_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_xor_i32, { "r", "rI", "rI" } },
+
+    { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+
+    { INDEX_op_sar_i32, { "r", "rZ", "ri" } },
+    { INDEX_op_shl_i32, { "r", "rZ", "ri" } },
+    { INDEX_op_shr_i32, { "r", "rZ", "ri" } },
+    { INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
+    { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
+
+    { INDEX_op_ext8s_i32, { "r", "rZ"} },
+    { INDEX_op_ext8u_i32, { "r", "rZ"} },
+    { INDEX_op_ext16s_i32, { "r", "rZ"} },
+    { INDEX_op_ext16u_i32, { "r", "rZ"} },
+
+    { INDEX_op_bswap16_i32, { "r", "rZ" } },
+    { INDEX_op_bswap32_i32, { "r", "rZ" } },
+
+    { INDEX_op_brcond_i32, { "rI", "rI" } },
+    { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
+
+    { INDEX_op_mov_i64, { "r", "r" } },
+    { INDEX_op_movi_i64, { "r" } },
+
+    { INDEX_op_ld8u_i64, { "r", "r" } },
+    { INDEX_op_ld8s_i64, { "r", "r" } },
+    { INDEX_op_ld16u_i64, { "r", "r" } },
+    { INDEX_op_ld16s_i64, { "r", "r" } },
+    { INDEX_op_ld32u_i64, { "r", "r" } },
+    { INDEX_op_ld32s_i64, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+    { INDEX_op_st8_i64, { "rZ", "r" } },
+    { INDEX_op_st16_i64, { "rZ", "r" } },
+    { INDEX_op_st32_i64, { "rZ", "r" } },
+    { INDEX_op_st_i64, { "rZ", "r" } },
+
+    { INDEX_op_add_i64, { "r", "rI", "rI" } },
+    { INDEX_op_sub_i64, { "r", "rI", "rI" } },
+
+    { INDEX_op_and_i64, { "r", "rI", "rI" } },
+    { INDEX_op_andc_i64, { "r", "rI", "rI" } },
+    { INDEX_op_eqv_i64, { "r", "rZ", "rZ" } },
+    { INDEX_op_nand_i64, { "r", "rZ", "rZ" } },
+    { INDEX_op_nor_i64, { "r", "rZ", "rZ" } },
+    { INDEX_op_or_i64, { "r", "rI", "rI" } },
+    { INDEX_op_orc_i64, { "r", "rZ", "rZ" } },
+    { INDEX_op_xor_i64, { "r", "rI", "rI" } },
+
+    { INDEX_op_mul_i64, { "r", "rZ", "rZ" } },
+
+    { INDEX_op_sar_i64, { "r", "rZ", "ri" } },
+    { INDEX_op_shl_i64, { "r", "rZ", "ri" } },
+    { INDEX_op_shr_i64, { "r", "rZ", "ri" } },
+    { INDEX_op_rotl_i64, { "r", "rZ", "ri" } },
+    { INDEX_op_rotr_i64, { "r", "rZ", "ri" } },
+
+    { INDEX_op_ext8s_i64, { "r", "rZ"} },
+    { INDEX_op_ext8u_i64, { "r", "rZ"} },
+    { INDEX_op_ext16s_i64, { "r", "rZ"} },
+    { INDEX_op_ext16u_i64, { "r", "rZ"} },
+    { INDEX_op_ext32s_i64, { "r", "rZ"} },
+    { INDEX_op_ext32u_i64, { "r", "rZ"} },
+
+    { INDEX_op_bswap16_i64, { "r", "rZ" } },
+    { INDEX_op_bswap32_i64, { "r", "rZ" } },
+    { INDEX_op_bswap64_i64, { "r", "rZ" } },
+
+    { INDEX_op_brcond_i64, { "rI", "rI" } },
+    { INDEX_op_setcond_i64, { "r", "rZ", "rZ" } },
+
+    { INDEX_op_qemu_ld8u, { "r", "r" } },
+    { INDEX_op_qemu_ld8s, { "r", "r" } },
+    { INDEX_op_qemu_ld16u, { "r", "r" } },
+    { INDEX_op_qemu_ld16s, { "r", "r" } },
+    { INDEX_op_qemu_ld32, { "r", "r" } },
+    { INDEX_op_qemu_ld32u, { "r", "r" } },
+    { INDEX_op_qemu_ld32s, { "r", "r" } },
+    { INDEX_op_qemu_ld64, { "r", "r" } },
+
+    { INDEX_op_qemu_st8, { "SZ", "r" } },
+    { INDEX_op_qemu_st16, { "SZ", "r" } },
+    { INDEX_op_qemu_st32, { "SZ", "r" } },
+    { INDEX_op_qemu_st64, { "SZ", "r" } },
+
+    { -1 },
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int frame_size;
+
+    /* reserve some stack space */
+    frame_size = TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+                 ~(TCG_TARGET_STACK_ALIGN - 1);
+
+    /* First emit adhoc function descriptor */
+    *(uint64_t *)(s->code_ptr) = (uint64_t)s->code_ptr + 16; /* entry point */
+    s->code_ptr += 16; /* skip GP */
+
+    /* prologue */
+    tcg_out_bundle(s, mII,
+                   tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
+                               TCG_REG_R33, 32, 24, 0),
+                   tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+                               TCG_REG_B6, TCG_REG_R33, 0),
+                   tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+                               TCG_REG_R32, TCG_REG_B0));
+
+    /* ??? If GUEST_BASE < 0x200000, we could load the register via
+       an ADDL in the M slot of the next bundle.  */
+    if (GUEST_BASE != 0) {
+        tcg_out_bundle(s, mlx,
+                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                       tcg_opc_l2 (GUEST_BASE),
+                       tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2,
+                                   TCG_GUEST_BASE_REG, GUEST_BASE));
+        tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+    }
+
+    tcg_out_bundle(s, miB,
+                   tcg_opc_m48(TCG_REG_P0, OPC_MOV_I21,
+                               TCG_REG_AREG0, TCG_REG_R32, 0),
+                   tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+                               TCG_REG_R12, -frame_size, TCG_REG_R12),
+                   tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
+
+    /* epilogue */
+    tb_ret_addr = s->code_ptr;
+    tcg_out_bundle(s, miI,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+                               TCG_REG_B0, TCG_REG_R32, 0),
+                   tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+                               TCG_REG_R12, frame_size, TCG_REG_R12));
+    tcg_out_bundle(s, miB,
+                   tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+                   tcg_opc_i26(TCG_REG_P0, OPC_MOV_I_I26,
+                               TCG_REG_PFS, TCG_REG_R33),
+                   tcg_opc_b4 (TCG_REG_P0, OPC_BR_RET_SPTK_MANY_B4,
+                               TCG_REG_B0));
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32],
+                   0xffffffffffffffffull);
+    tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I64],
+                   0xffffffffffffffffull);
+
+    tcg_regset_clear(tcg_target_call_clobber_regs);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R15);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R16);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R17);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R18);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R19);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R20);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R21);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R22);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R23);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R24);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R25);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R26);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R27);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R28);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R29);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R30);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R31);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R56);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R57);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R58);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R59);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R60);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R61);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R62);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R63);
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);   /* zero register */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);   /* global pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12);  /* stack pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);  /* thread pointer */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R32);  /* return address */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R33);  /* PFS */
+
+    /* The following 3 are not in use, are call-saved, but *not* saved
+       by the prologue.  Therefore we cannot use them without modifying
+       the prologue.  There doesn't seem to be any good reason to use
+       these as opposed to the windowed registers.  */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R4);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R5);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6);
+
+    tcg_add_target_add_op_defs(ia64_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+}
diff --git a/qemu-0.15.x/tcg/ia64/tcg-target.h b/qemu-0.15.x/tcg/ia64/tcg-target.h
new file mode 100644
index 0000000..e56e88f
--- /dev/null
+++ b/qemu-0.15.x/tcg/ia64/tcg-target.h
@@ -0,0 +1,156 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009-2010 Aurelien Jarno <aurelien at aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_IA64 1
+
+#define TCG_TARGET_REG_BITS 64
+
+/* We only map the first 64 registers */
+#define TCG_TARGET_NB_REGS 64
+enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31,
+    TCG_REG_R32,
+    TCG_REG_R33,
+    TCG_REG_R34,
+    TCG_REG_R35,
+    TCG_REG_R36,
+    TCG_REG_R37,
+    TCG_REG_R38,
+    TCG_REG_R39,
+    TCG_REG_R40,
+    TCG_REG_R41,
+    TCG_REG_R42,
+    TCG_REG_R43,
+    TCG_REG_R44,
+    TCG_REG_R45,
+    TCG_REG_R46,
+    TCG_REG_R47,
+    TCG_REG_R48,
+    TCG_REG_R49,
+    TCG_REG_R50,
+    TCG_REG_R51,
+    TCG_REG_R52,
+    TCG_REG_R53,
+    TCG_REG_R54,
+    TCG_REG_R55,
+    TCG_REG_R56,
+    TCG_REG_R57,
+    TCG_REG_R58,
+    TCG_REG_R59,
+    TCG_REG_R60,
+    TCG_REG_R61,
+    TCG_REG_R62,
+    TCG_REG_R63,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_S22 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R12
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 16
+
+/* optional instructions */
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_eqv_i32
+#define TCG_TARGET_HAS_eqv_i64
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_nand_i32
+#define TCG_TARGET_HAS_nand_i64
+#define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_nor_i64
+#define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_orc_i64
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_rot_i64
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32   /* sub r1, r0, r3 */
+#undef TCG_TARGET_HAS_neg_i64   /* sub r1, r0, r3 */
+#undef TCG_TARGET_HAS_not_i32   /* xor r1, -1, r3 */
+#undef TCG_TARGET_HAS_not_i64   /* xor r1, -1, r3 */
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_R7
+
+/* Guest base is supported */
+#define TCG_TARGET_HAS_GUEST_BASE
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    start = start & ~(32UL - 1UL);
+    stop = (stop + (32UL - 1UL)) & ~(32UL - 1UL);
+
+    for (; start < stop; start += 32UL) {
+        asm volatile ("fc.i %0" :: "r" (start));
+    }
+    asm volatile (";;sync.i;;srlz.i;;");
+}
diff --git a/qemu-0.15.x/tcg/mips/tcg-target.c b/qemu-0.15.x/tcg/mips/tcg-target.c
new file mode 100644
index 0000000..a33d21f
--- /dev/null
+++ b/qemu-0.15.x/tcg/mips/tcg-target.c
@@ -0,0 +1,1533 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard at rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien at aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 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.
+ */
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+# define TCG_NEED_BSWAP 0
+#else
+# define TCG_NEED_BSWAP 1
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "zero",
+    "at",
+    "v0",
+    "v1",
+    "a0",
+    "a1",
+    "a2",
+    "a3",
+    "t0",
+    "t1",
+    "t2",
+    "t3",
+    "t4",
+    "t5",
+    "t6",
+    "t7",
+    "s0",
+    "s1",
+    "s2",
+    "s3",
+    "s4",
+    "s5",
+    "s6",
+    "s7",
+    "t8",
+    "t9",
+    "k0",
+    "k1",
+    "gp",
+    "sp",
+    "fp",
+    "ra",
+};
+#endif
+
+/* check if we really need so many registers :P */
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_S0,
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_T1,
+    TCG_REG_T2,
+    TCG_REG_T3,
+    TCG_REG_T4,
+    TCG_REG_T5,
+    TCG_REG_T6,
+    TCG_REG_T7,
+    TCG_REG_T8,
+    TCG_REG_T9,
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3,
+    TCG_REG_V0,
+    TCG_REG_V1
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_V0,
+    TCG_REG_V1
+};
+
+static uint8_t *tb_ret_addr;
+
+static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target)
+{
+    return target & 0xffff;
+}
+
+static inline void reloc_lo16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_lo16_val(pc, target);
+}
+
+static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target)
+{
+    return (target >> 16) & 0xffff;
+}
+
+static inline void reloc_hi16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_hi16_val(pc, target);
+}
+
+static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target)
+{
+    int32_t disp;
+
+    disp = target - (tcg_target_long) pc - 4;
+    if (disp != (disp << 14) >> 14) {
+        tcg_abort ();
+    }
+
+    return (disp >> 2) & 0xffff;
+}
+
+static inline void reloc_pc16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_pc16_val(pc, target);
+}
+
+static inline uint32_t reloc_26_val (void *pc, tcg_target_long target)
+{
+    if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) {
+        tcg_abort ();
+    }
+
+    return (target >> 2) & 0x3ffffff;
+}
+
+static inline void reloc_pc26 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff)
+                       | reloc_26_val(pc, target);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch(type) {
+    case R_MIPS_LO16:
+        reloc_lo16(code_ptr, value);
+        break;
+    case R_MIPS_HI16:
+        reloc_hi16(code_ptr, value);
+        break;
+    case R_MIPS_PC16:
+        reloc_pc16(code_ptr, value);
+        break;
+    case R_MIPS_26:
+        reloc_pc26(code_ptr, value);
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch(ct_str[0]) {
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+        break;
+    case 'C':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_clear(ct->u.regs);
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_T9);
+        break;
+    case 'L': /* qemu_ld output arg constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0);
+        break;
+    case 'l': /* qemu_ld input arg constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+#if defined(CONFIG_SOFTMMU)
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+#endif
+        break;
+    case 'S': /* qemu_st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+#if defined(CONFIG_SOFTMMU)
+# if TARGET_LONG_BITS == 64
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
+# endif
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+#endif
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_U16;
+        break;
+    case 'J':
+        ct->ct |= TCG_CT_CONST_S16;
+        break;
+    case 'Z':
+        /* We are cheating a bit here, using the fact that the register
+           ZERO is also the register number 0. Hence there is no need
+           to check for const_args in each instruction. */
+        ct->ct |= TCG_CT_CONST_ZERO;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+                                         const TCGArgConstraint *arg_ct)
+{
+    int ct;
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+        return 1;
+    else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val)
+        return 1;
+    else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val)
+        return 1;
+    else
+        return 0;
+}
+
+/* instruction opcodes */
+enum {
+    OPC_BEQ      = 0x04 << 26,
+    OPC_BNE      = 0x05 << 26,
+    OPC_ADDIU    = 0x09 << 26,
+    OPC_SLTI     = 0x0A << 26,
+    OPC_SLTIU    = 0x0B << 26,
+    OPC_ANDI     = 0x0C << 26,
+    OPC_ORI      = 0x0D << 26,
+    OPC_XORI     = 0x0E << 26,
+    OPC_LUI      = 0x0F << 26,
+    OPC_LB       = 0x20 << 26,
+    OPC_LH       = 0x21 << 26,
+    OPC_LW       = 0x23 << 26,
+    OPC_LBU      = 0x24 << 26,
+    OPC_LHU      = 0x25 << 26,
+    OPC_LWU      = 0x27 << 26,
+    OPC_SB       = 0x28 << 26,
+    OPC_SH       = 0x29 << 26,
+    OPC_SW       = 0x2B << 26,
+
+    OPC_SPECIAL  = 0x00 << 26,
+    OPC_SLL      = OPC_SPECIAL | 0x00,
+    OPC_SRL      = OPC_SPECIAL | 0x02,
+    OPC_SRA      = OPC_SPECIAL | 0x03,
+    OPC_SLLV     = OPC_SPECIAL | 0x04,
+    OPC_SRLV     = OPC_SPECIAL | 0x06,
+    OPC_SRAV     = OPC_SPECIAL | 0x07,
+    OPC_JR       = OPC_SPECIAL | 0x08,
+    OPC_JALR     = OPC_SPECIAL | 0x09,
+    OPC_MFHI     = OPC_SPECIAL | 0x10,
+    OPC_MFLO     = OPC_SPECIAL | 0x12,
+    OPC_MULT     = OPC_SPECIAL | 0x18,
+    OPC_MULTU    = OPC_SPECIAL | 0x19,
+    OPC_DIV      = OPC_SPECIAL | 0x1A,
+    OPC_DIVU     = OPC_SPECIAL | 0x1B,
+    OPC_ADDU     = OPC_SPECIAL | 0x21,
+    OPC_SUBU     = OPC_SPECIAL | 0x23,
+    OPC_AND      = OPC_SPECIAL | 0x24,
+    OPC_OR       = OPC_SPECIAL | 0x25,
+    OPC_XOR      = OPC_SPECIAL | 0x26,
+    OPC_NOR      = OPC_SPECIAL | 0x27,
+    OPC_SLT      = OPC_SPECIAL | 0x2A,
+    OPC_SLTU     = OPC_SPECIAL | 0x2B,
+
+    OPC_SPECIAL3 = 0x1f << 26,
+    OPC_SEB      = OPC_SPECIAL3 | 0x420,
+    OPC_SEH      = OPC_SPECIAL3 | 0x620,
+};
+
+/*
+ * Type reg
+ */
+static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rs & 0x1F) << 21;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (rd & 0x1F) << 11;
+    tcg_out32(s, inst);
+}
+
+/*
+ * Type immediate
+ */
+static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rs & 0x1F) << 21;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (imm & 0xffff);
+    tcg_out32(s, inst);
+}
+
+/*
+ * Type branch
+ */
+static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
+{
+    /* We pay attention here to not modify the branch target by reading
+       the existing value and using it again. This ensure that caches and
+       memory are kept coherent during retranslation. */
+    uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr);
+
+    tcg_out_opc_imm(s, opc, rt, rs, offset);
+}
+
+/*
+ * Type sa
+ */
+static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (rd & 0x1F) << 11;
+    inst |= (sa & 0x1F) <<  6;
+    tcg_out32(s, inst);
+
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+    tcg_out32(s, 0);
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+                                int reg, int32_t arg)
+{
+    if (arg == (int16_t)arg) {
+        tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg);
+    } else if (arg == (uint16_t)arg) {
+        tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg);
+    } else {
+        tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16);
+        tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
+    }
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg can't be register at */
+    if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff);
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg can't be register at */
+    if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff);
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+    tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg must be different and can't be register at */
+    if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
+    tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg)
+{
+#ifdef _MIPS_ARCH_MIPS32R2
+    tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg);
+#else
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+    tcg_out_opc_sa(s, OPC_SRA, ret, ret, 24);
+#endif
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg)
+{
+#ifdef _MIPS_ARCH_MIPS32R2
+    tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg);
+#else
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16);
+    tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
+#endif
+}
+
+static inline void tcg_out_ldst(TCGContext *s, int opc, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    if (arg2 == (int16_t) arg2) {
+        tcg_out_opc_imm(s, opc, arg, arg1, arg2);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2);
+        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1);
+        tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0);
+    }
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val == (int16_t)val) {
+        tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val);
+        tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT);
+    }
+}
+
+static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
+                           int arg2, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        tcg_out_opc_br(s, OPC_BEQ, arg1, arg2);
+        break;
+    case TCG_COND_NE:
+        tcg_out_opc_br(s, OPC_BNE, arg1, arg2);
+        break;
+    case TCG_COND_LT:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_LTU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_GE:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_GEU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_LE:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_LEU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_GT:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    case TCG_COND_GTU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+        break;
+    default:
+        tcg_abort();
+        break;
+    }
+    if (l->has_value) {
+        reloc_pc16(s->code_ptr - 4, l->u.value);
+    } else {
+        tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0);
+    }
+    tcg_out_nop(s);
+}
+
+/* XXX: we implement it at the target level to avoid having to
+   handle cross basic blocks temporaries */
+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, int arg1,
+                            int arg2, int arg3, int arg4, int label_index)
+{
+    void *label_ptr;
+
+    switch(cond) {
+    case TCG_COND_NE:
+        tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index);
+        tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index);
+        return;
+    case TCG_COND_EQ:
+        break;
+    case TCG_COND_LT:
+    case TCG_COND_LE:
+        tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GE:
+        tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index);
+        break;
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+        tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index);
+        break;
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    label_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BNE, arg2, arg4);
+    tcg_out_nop(s);
+
+    switch(cond) {
+    case TCG_COND_EQ:
+        tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index);
+        break;
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+        tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr);
+}
+
+static void tcg_out_setcond(TCGContext *s, TCGCond cond, int ret,
+                            int arg1, int arg2)
+{
+    switch (cond) {
+    case TCG_COND_EQ:
+        if (arg1 == 0) {
+            tcg_out_opc_imm(s, OPC_SLTIU, ret, arg2, 1);
+        } else if (arg2 == 0) {
+            tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1);
+        } else {
+            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+            tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1);
+        }
+        break;
+    case TCG_COND_NE:
+        if (arg1 == 0) {
+            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg2);
+        } else if (arg2 == 0) {
+            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1);
+        } else {
+            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret);
+        }
+        break;
+    case TCG_COND_LT:
+        tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+        break;
+    case TCG_COND_LTU:
+        tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+        break;
+    case TCG_COND_GE:
+        tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        break;
+    case TCG_COND_GEU:
+        tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        break;
+    case TCG_COND_LE:
+        tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        break;
+    case TCG_COND_LEU:
+        tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        break;
+    case TCG_COND_GT:
+        tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+        break;
+    case TCG_COND_GTU:
+        tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+        break;
+    default:
+        tcg_abort();
+        break;
+    }
+}
+
+/* XXX: we implement it at the target level to avoid having to
+   handle cross basic blocks temporaries */
+static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret,
+                             int arg1, int arg2, int arg3, int arg4)
+{
+    switch (cond) {
+    case TCG_COND_EQ:
+        tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_AT, arg2, arg4);
+        tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg1, arg3);
+        tcg_out_opc_reg(s, OPC_AND, ret, TCG_REG_AT, TCG_REG_T0);
+        return;
+    case TCG_COND_NE:
+        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_AT, arg2, arg4);
+        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, arg1, arg3);
+        tcg_out_opc_reg(s, OPC_OR, ret, TCG_REG_AT, TCG_REG_T0);
+        return;
+    case TCG_COND_LT:
+    case TCG_COND_LE:
+        tcg_out_setcond(s, TCG_COND_LT, TCG_REG_AT, arg2, arg4);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GE:
+        tcg_out_setcond(s, TCG_COND_GT, TCG_REG_AT, arg2, arg4);
+        break;
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+        tcg_out_setcond(s, TCG_COND_LTU, TCG_REG_AT, arg2, arg4);
+        break;
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        tcg_out_setcond(s, TCG_COND_GTU, TCG_REG_AT, arg2, arg4);
+        break;
+    default:
+        tcg_abort();
+        break;
+    }
+
+    tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg2, arg4);
+
+    switch(cond) {
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+        tcg_out_setcond(s, TCG_COND_LTU, ret, arg1, arg3);
+        break;
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        tcg_out_setcond(s, TCG_COND_LEU, ret, arg1, arg3);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        tcg_out_setcond(s, TCG_COND_GTU, ret, arg1, arg3);
+        break;
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        tcg_out_setcond(s, TCG_COND_GEU, ret, arg1, arg3);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    tcg_out_opc_reg(s, OPC_AND, ret, ret, TCG_REG_T0);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_regl, addr_reg1, addr_meml;
+    int data_regl, data_regh, data_reg1, data_reg2;
+    int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    void *label1_ptr, *label2_ptr;
+    int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+    uint8_t *label3_ptr;
+# endif
+    int addr_regh, addr_reg2, addr_memh;
+#endif
+    data_regl = *args++;
+    if (opc == 3)
+        data_regh = *args++;
+    else
+        data_regh = 0;
+    addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_regh = *args++;
+#endif
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    if (opc == 3) {
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+        data_reg1 = data_regh;
+        data_reg2 = data_regl;
+#else
+        data_reg1 = data_regl;
+        data_reg2 = data_regh;
+#endif
+    } else {
+        data_reg1 = data_regl;
+        data_reg2 = 0;
+    }
+#if TARGET_LONG_BITS == 64
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+    addr_reg1 = addr_regh;
+    addr_reg2 = addr_regl;
+    addr_memh = 0;
+    addr_meml = 4;
+# else
+    addr_reg1 = addr_regl;
+    addr_reg2 = addr_regh;
+    addr_memh = 4;
+    addr_meml = 0;
+# endif
+#else
+    addr_reg1 = addr_regl;
+    addr_meml = 0;
+#endif
+
+#if defined(CONFIG_SOFTMMU)
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+    label3_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
+    tcg_out_nop(s);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh);
+
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
+    tcg_out_nop(s);
+
+    reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
+    tcg_out_nop(s);
+# endif
+
+    /* slow path */
+    sp_args = TCG_REG_A0;
+    tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+    tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+# endif
+    tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
+    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+    tcg_out_nop(s);
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff);
+        break;
+    case 0 | 4:
+        tcg_out_ext8s(s, data_reg1, TCG_REG_V0);
+        break;
+    case 1:
+        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff);
+        break;
+    case 1 | 4:
+        tcg_out_ext16s(s, data_reg1, TCG_REG_V0);
+        break;
+    case 2:
+        tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
+        break;
+    case 3:
+        tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_V1);
+        tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    label2_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
+    tcg_out_nop(s);
+
+    /* label1: fast path */
+    reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addend));
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl);
+#else
+    if (GUEST_BASE == (int16_t)GUEST_BASE) {
+        tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_V0, addr_regl, GUEST_BASE);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, GUEST_BASE);
+        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
+    }
+#endif
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_LBU, data_reg1, TCG_REG_V0, 0);
+        break;
+    case 0 | 4:
+        tcg_out_opc_imm(s, OPC_LB, data_reg1, TCG_REG_V0, 0);
+        break;
+    case 1:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
+            tcg_out_bswap16(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LHU, data_reg1, TCG_REG_V0, 0);
+        }
+        break;
+    case 1 | 4:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
+            tcg_out_bswap16s(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LH, data_reg1, TCG_REG_V0, 0);
+        }
+        break;
+    case 2:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
+            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
+        }
+        break;
+    case 3:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 4);
+            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
+            tcg_out_bswap32(s, data_reg2, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
+            tcg_out_opc_imm(s, OPC_LW, data_reg2, TCG_REG_V0, 4);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_regl, addr_reg1, addr_meml;
+    int data_regl, data_regh, data_reg1, data_reg2;
+    int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    uint8_t *label1_ptr, *label2_ptr;
+    int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+    uint8_t *label3_ptr;
+# endif
+    int addr_regh, addr_reg2, addr_memh;
+#endif
+
+    data_regl = *args++;
+    if (opc == 3) {
+        data_regh = *args++;
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+        data_reg1 = data_regh;
+        data_reg2 = data_regl;
+#else
+        data_reg1 = data_regl;
+        data_reg2 = data_regh;
+#endif
+    } else {
+        data_reg1 = data_regl;
+        data_reg2 = 0;
+        data_regh = 0;
+    }
+    addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_regh = *args++;
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+    addr_reg1 = addr_regh;
+    addr_reg2 = addr_regl;
+    addr_memh = 0;
+    addr_meml = 4;
+# else
+    addr_reg1 = addr_regl;
+    addr_reg2 = addr_regh;
+    addr_memh = 4;
+    addr_meml = 0;
+# endif
+#else
+    addr_reg1 = addr_regl;
+    addr_meml = 0;
+#endif
+    mem_index = *args;
+    s_bits = opc;
+
+#if defined(CONFIG_SOFTMMU)
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+    label3_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
+    tcg_out_nop(s);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh);
+
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
+    tcg_out_nop(s);
+
+    reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
+    tcg_out_nop(s);
+# endif
+
+    /* slow path */
+    sp_args = TCG_REG_A0;
+    tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+    tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+# endif
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+        break;
+    case 1:
+        tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+        break;
+    case 2:
+        tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+        break;
+    case 3:
+        sp_args = (sp_args + 1) & ~1;
+        tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+        tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
+        break;
+    default:
+        tcg_abort();
+    }
+    if (sp_args > TCG_REG_A3) {
+        /* Push mem_index on the stack */
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
+        tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
+    }
+
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
+    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+    tcg_out_nop(s);
+
+    label2_ptr = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
+    tcg_out_nop(s);
+
+    /* label1: fast path */
+    reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addend));
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+#else
+    if (GUEST_BASE == (int16_t)GUEST_BASE) {
+        tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_A0, addr_regl, GUEST_BASE);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, GUEST_BASE);
+        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+    }
+
+#endif
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_SB, data_reg1, TCG_REG_A0, 0);
+        break;
+    case 1:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap16(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, TCG_REG_A0, 0);
+        } else {
+            tcg_out_opc_imm(s, OPC_SH, data_reg1, TCG_REG_A0, 0);
+        }
+        break;
+    case 2:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
+        } else {
+            tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
+        }
+        break;
+    case 3:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg2);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 4);
+        } else {
+            tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
+            tcg_out_opc_imm(s, OPC_SW, data_reg2, TCG_REG_A0, 4);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+                              const TCGArg *args, const int *const_args)
+{
+    switch(opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]);
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr);
+        tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+            tcg_abort();
+        } else {
+            /* indirect jump method */
+            tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0]));
+            tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0);
+            tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+        }
+        tcg_out_nop(s);
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_call:
+        tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_jmp:
+        tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_br:
+        tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]);
+        break;
+
+    case INDEX_op_mov_i32:
+        tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+
+    case INDEX_op_ld8u_i32:
+        tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld8s_i32:
+        tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16u_i32:
+        tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16s_i32:
+        tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld_i32:
+        tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st8_i32:
+        tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st16_i32:
+        tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i32:
+        tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_add2_i32:
+        if (const_args[4]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]);
+        } else {
+            tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]);
+        }
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]);
+        if (const_args[5]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]);
+        } else {
+             tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]);
+        }
+        tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0);
+        tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
+        break;
+    case INDEX_op_sub_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_sub2_i32:
+        if (const_args[4]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]);
+        }
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT);
+        if (const_args[5]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]);
+        } else {
+             tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]);
+        }
+        tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0);
+        tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
+        break;
+    case INDEX_op_mul_i32:
+        tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0);
+        break;
+    case INDEX_op_div_i32:
+        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_divu_i32:
+        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_rem_i32:
+        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+        break;
+    case INDEX_op_remu_i32:
+        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+        break;
+
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_nor_i32:
+        tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_not_i32:
+        tcg_out_opc_reg(s, OPC_NOR, args[0], TCG_REG_ZERO, args[1]);
+        break;
+    case INDEX_op_xor_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_sar_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]);
+        }
+        break;
+    case INDEX_op_shl_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]);
+        }
+        break;
+    case INDEX_op_shr_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]);
+        }
+        break;
+
+    case INDEX_op_ext8s_i32:
+        tcg_out_ext8s(s, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+        tcg_out_ext16s(s, args[0], args[1]);
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond(s, args[2], args[0], args[1], args[3]);
+        break;
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
+        break;
+
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2]);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2(s, args[5], args[0], args[1], args[2], args[3], args[4]);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    default:
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef mips_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "C" } },
+    { INDEX_op_jmp, { "r" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "rZ", "r" } },
+    { INDEX_op_st16_i32, { "rZ", "r" } },
+    { INDEX_op_st_i32, { "rZ", "r" } },
+
+    { INDEX_op_add_i32, { "r", "rZ", "rJZ" } },
+    { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } },
+    { INDEX_op_div_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_divu_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_rem_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_remu_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } },
+
+    { INDEX_op_and_i32, { "r", "rZ", "rIZ" } },
+    { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_not_i32, { "r", "rZ" } },
+    { INDEX_op_or_i32, { "r", "rZ", "rIZ" } },
+    { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } },
+
+    { INDEX_op_shl_i32, { "r", "rZ", "riZ" } },
+    { INDEX_op_shr_i32, { "r", "rZ", "riZ" } },
+    { INDEX_op_sar_i32, { "r", "rZ", "riZ" } },
+
+    { INDEX_op_ext8s_i32, { "r", "rZ" } },
+    { INDEX_op_ext16s_i32, { "r", "rZ" } },
+
+    { INDEX_op_brcond_i32, { "rZ", "rZ" } },
+    { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
+
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+    { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
+
+#if TARGET_LONG_BITS == 32
+    { INDEX_op_qemu_ld8u, { "L", "lZ" } },
+    { INDEX_op_qemu_ld8s, { "L", "lZ" } },
+    { INDEX_op_qemu_ld16u, { "L", "lZ" } },
+    { INDEX_op_qemu_ld16s, { "L", "lZ" } },
+    { INDEX_op_qemu_ld32, { "L", "lZ" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "lZ" } },
+
+    { INDEX_op_qemu_st8, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st16, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st32, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } },
+#else
+    { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld32, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } },
+
+    { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } },
+#endif
+    { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+    TCG_REG_S0,       /* used for the global env (TCG_AREG0) */
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_GP,
+    TCG_REG_FP,
+    TCG_REG_RA,       /* should be last for ABI compliance */
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int i, frame_size;
+
+    /* reserve some stack space */
+    frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4
+                 + TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+                 ~(TCG_TARGET_STACK_ALIGN - 1);
+
+    /* TB prologue */
+    tcg_out_addi(s, TCG_REG_SP, -frame_size);
+    for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+        tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+                   TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+    }
+
+    /* Call generated code */
+    tcg_out_opc_reg(s, OPC_JR, 0, tcg_target_call_iarg_regs[1], 0);
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    tb_ret_addr = s->code_ptr;
+
+    /* TB epilogue */
+    for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+        tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+                   TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+    }
+
+    tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0);
+    tcg_out_addi(s, TCG_REG_SP, frame_size);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
+    tcg_regset_set(tcg_target_call_clobber_regs,
+                   (1 << TCG_REG_V0) |
+                   (1 << TCG_REG_V1) |
+                   (1 << TCG_REG_A0) |
+                   (1 << TCG_REG_A1) |
+                   (1 << TCG_REG_A2) |
+                   (1 << TCG_REG_A3) |
+                   (1 << TCG_REG_T1) |
+                   (1 << TCG_REG_T2) |
+                   (1 << TCG_REG_T3) |
+                   (1 << TCG_REG_T4) |
+                   (1 << TCG_REG_T5) |
+                   (1 << TCG_REG_T6) |
+                   (1 << TCG_REG_T7) |
+                   (1 << TCG_REG_T8) |
+                   (1 << TCG_REG_T9));
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0);   /* kernel use only */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1);   /* kernel use only */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA);   /* return address */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);   /* stack pointer */
+
+    tcg_add_target_add_op_defs(mips_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+}
diff --git a/qemu-0.15.x/tcg/mips/tcg-target.h b/qemu-0.15.x/tcg/mips/tcg-target.h
new file mode 100644
index 0000000..8cb7d88
--- /dev/null
+++ b/qemu-0.15.x/tcg/mips/tcg-target.h
@@ -0,0 +1,114 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard at rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien at aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_MIPS 1
+
+#define TCG_TARGET_REG_BITS 32
+#ifdef __MIPSEB__
+# define TCG_TARGET_WORDS_BIGENDIAN
+#endif
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_ZERO = 0,
+    TCG_REG_AT,
+    TCG_REG_V0,
+    TCG_REG_V1,
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3,
+    TCG_REG_T0,
+    TCG_REG_T1,
+    TCG_REG_T2,
+    TCG_REG_T3,
+    TCG_REG_T4,
+    TCG_REG_T5,
+    TCG_REG_T6,
+    TCG_REG_T7,
+    TCG_REG_S0,
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_T8,
+    TCG_REG_T9,
+    TCG_REG_K0,
+    TCG_REG_K1,
+    TCG_REG_GP,
+    TCG_REG_SP,
+    TCG_REG_FP,
+    TCG_REG_RA,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_U16  0x200
+#define TCG_CT_CONST_S16  0x400
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 8
+#define TCG_TARGET_CALL_STACK_OFFSET 16
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_nor_i32
+#undef TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#undef TCG_TARGET_HAS_bswap32_i32
+#undef TCG_TARGET_HAS_bswap16_i32
+#undef TCG_TARGET_HAS_andc_i32
+#undef TCG_TARGET_HAS_orc_i32
+#undef TCG_TARGET_HAS_eqv_i32
+#undef TCG_TARGET_HAS_nand_i32
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32      /* sub  rd, zero, rt   */
+#undef TCG_TARGET_HAS_ext8u_i32    /* andi rt, rs, 0xff   */
+#undef TCG_TARGET_HAS_ext16u_i32   /* andi rt, rs, 0xffff */
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_S0
+
+/* guest base is supported */
+#define TCG_TARGET_HAS_GUEST_BASE
+
+#ifdef __OpenBSD__
+#include <machine/sysarch.h>
+#else
+#include <sys/cachectl.h>
+#endif
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    cacheflush ((void *)start, stop-start, ICACHE);
+}
diff --git a/qemu-0.15.x/tcg/ppc/tcg-target.c b/qemu-0.15.x/tcg/ppc/tcg-target.c
new file mode 100644
index 0000000..58c8621
--- /dev/null
+++ b/qemu-0.15.x/tcg/ppc/tcg-target.c
@@ -0,0 +1,1922 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+
+static uint8_t *tb_ret_addr;
+
+#ifdef _CALL_DARWIN
+#define LINKAGE_AREA_SIZE 24
+#define LR_OFFSET 8
+#elif defined _CALL_AIX
+#define LINKAGE_AREA_SIZE 52
+#define LR_OFFSET 8
+#else
+#define LINKAGE_AREA_SIZE 8
+#define LR_OFFSET 4
+#endif
+
+#define FAST_PATH
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG 30
+#else
+#define TCG_GUEST_BASE_REG 0
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "r14",
+    "r15",
+    "r16",
+    "r17",
+    "r18",
+    "r19",
+    "r20",
+    "r21",
+    "r22",
+    "r23",
+    "r24",
+    "r25",
+    "r26",
+    "r27",
+    "r28",
+    "r29",
+    "r30",
+    "r31"
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31,
+#ifdef _CALL_DARWIN
+    TCG_REG_R2,
+#endif
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+#ifndef _CALL_DARWIN
+    TCG_REG_R11,
+#endif
+    TCG_REG_R12,
+#ifndef _CALL_SYSV
+    TCG_REG_R13,
+#endif
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_R3,
+    TCG_REG_R4
+};
+
+static const int tcg_target_callee_save_regs[] = {
+#ifdef _CALL_DARWIN
+    TCG_REG_R11,
+    TCG_REG_R13,
+#endif
+#ifdef _CALL_AIX
+    TCG_REG_R13,
+#endif
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27, /* currently used for the global env */
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31
+};
+
+static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) pc;
+    if ((disp << 6) >> 6 != disp)
+        tcg_abort ();
+
+    return disp & 0x3fffffc;
+}
+
+static void reloc_pc24 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc)
+        | reloc_pc24_val (pc, target);
+}
+
+static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) pc;
+    if (disp != (int16_t) disp)
+        tcg_abort ();
+
+    return disp & 0xfffc;
+}
+
+static void reloc_pc14 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc)
+        | reloc_pc14_val (pc, target);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch (type) {
+    case R_PPC_REL14:
+        reloc_pc14 (code_ptr, value);
+        break;
+    case R_PPC_REL24:
+        reloc_pc24 (code_ptr, value);
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return ARRAY_SIZE (tcg_target_call_iarg_regs);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'A': case 'B': case 'C': case 'D':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A');
+        break;
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        break;
+#ifdef CONFIG_SOFTMMU
+    case 'L':                   /* qemu_ld constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+        break;
+    case 'K':                   /* qemu_st[8..32] constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
+#if TARGET_LONG_BITS == 64
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
+#endif
+        break;
+    case 'M':                   /* qemu_st64 constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7);
+        break;
+#else
+    case 'L':
+    case 'K':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        break;
+    case 'M':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+        break;
+#endif
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct)
+{
+    int ct;
+
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    return 0;
+}
+
+#define OPCD(opc) ((opc)<<26)
+#define XO31(opc) (OPCD(31)|((opc)<<1))
+#define XO19(opc) (OPCD(19)|((opc)<<1))
+
+#define B      OPCD(18)
+#define BC     OPCD(16)
+#define LBZ    OPCD(34)
+#define LHZ    OPCD(40)
+#define LHA    OPCD(42)
+#define LWZ    OPCD(32)
+#define STB    OPCD(38)
+#define STH    OPCD(44)
+#define STW    OPCD(36)
+
+#define ADDIC  OPCD(12)
+#define ADDI   OPCD(14)
+#define ADDIS  OPCD(15)
+#define ORI    OPCD(24)
+#define ORIS   OPCD(25)
+#define XORI   OPCD(26)
+#define XORIS  OPCD(27)
+#define ANDI   OPCD(28)
+#define ANDIS  OPCD(29)
+#define MULLI  OPCD( 7)
+#define CMPLI  OPCD(10)
+#define CMPI   OPCD(11)
+#define SUBFIC OPCD( 8)
+
+#define LWZU   OPCD(33)
+#define STWU   OPCD(37)
+
+#define RLWIMI OPCD(20)
+#define RLWINM OPCD(21)
+#define RLWNM  OPCD(23)
+
+#define BCLR   XO19( 16)
+#define BCCTR  XO19(528)
+#define CRAND  XO19(257)
+#define CRANDC XO19(129)
+#define CRNAND XO19(225)
+#define CROR   XO19(449)
+#define CRNOR  XO19( 33)
+
+#define EXTSB  XO31(954)
+#define EXTSH  XO31(922)
+#define ADD    XO31(266)
+#define ADDE   XO31(138)
+#define ADDC   XO31( 10)
+#define AND    XO31( 28)
+#define SUBF   XO31( 40)
+#define SUBFC  XO31(  8)
+#define SUBFE  XO31(136)
+#define OR     XO31(444)
+#define XOR    XO31(316)
+#define MULLW  XO31(235)
+#define MULHWU XO31( 11)
+#define DIVW   XO31(491)
+#define DIVWU  XO31(459)
+#define CMP    XO31(  0)
+#define CMPL   XO31( 32)
+#define LHBRX  XO31(790)
+#define LWBRX  XO31(534)
+#define STHBRX XO31(918)
+#define STWBRX XO31(662)
+#define MFSPR  XO31(339)
+#define MTSPR  XO31(467)
+#define SRAWI  XO31(824)
+#define NEG    XO31(104)
+#define MFCR   XO31( 19)
+#define CNTLZW XO31( 26)
+#define NOR    XO31(124)
+#define ANDC   XO31( 60)
+#define ORC    XO31(412)
+#define EQV    XO31(284)
+#define NAND   XO31(476)
+
+#define LBZX   XO31( 87)
+#define LHZX   XO31(279)
+#define LHAX   XO31(343)
+#define LWZX   XO31( 23)
+#define STBX   XO31(215)
+#define STHX   XO31(407)
+#define STWX   XO31(151)
+
+#define SPR(a,b) ((((a)<<5)|(b))<<11)
+#define LR     SPR(8, 0)
+#define CTR    SPR(9, 0)
+
+#define SLW    XO31( 24)
+#define SRW    XO31(536)
+#define SRAW   XO31(792)
+
+#define TW     XO31(4)
+#define TRAP   (TW | TO (31))
+
+#define RT(r) ((r)<<21)
+#define RS(r) ((r)<<21)
+#define RA(r) ((r)<<16)
+#define RB(r) ((r)<<11)
+#define TO(t) ((t)<<21)
+#define SH(s) ((s)<<11)
+#define MB(b) ((b)<<6)
+#define ME(e) ((e)<<1)
+#define BO(o) ((o)<<21)
+
+#define LK    1
+
+#define TAB(t,a,b) (RT(t) | RA(a) | RB(b))
+#define SAB(s,a,b) (RS(s) | RA(a) | RB(b))
+
+#define BF(n)    ((n)<<23)
+#define BI(n, c) (((c)+((n)*4))<<16)
+#define BT(n, c) (((c)+((n)*4))<<21)
+#define BA(n, c) (((c)+((n)*4))<<16)
+#define BB(n, c) (((c)+((n)*4))<<11)
+
+#define BO_COND_TRUE  BO (12)
+#define BO_COND_FALSE BO (4)
+#define BO_ALWAYS     BO (20)
+
+enum {
+    CR_LT,
+    CR_GT,
+    CR_EQ,
+    CR_SO
+};
+
+static const uint32_t tcg_to_bc[10] = {
+    [TCG_COND_EQ]  = BC | BI (7, CR_EQ) | BO_COND_TRUE,
+    [TCG_COND_NE]  = BC | BI (7, CR_EQ) | BO_COND_FALSE,
+    [TCG_COND_LT]  = BC | BI (7, CR_LT) | BO_COND_TRUE,
+    [TCG_COND_GE]  = BC | BI (7, CR_LT) | BO_COND_FALSE,
+    [TCG_COND_LE]  = BC | BI (7, CR_GT) | BO_COND_FALSE,
+    [TCG_COND_GT]  = BC | BI (7, CR_GT) | BO_COND_TRUE,
+    [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+    [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+    [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+    [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+};
+
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    tcg_out32 (s, OR | SAB (arg, ret, arg));
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         int ret, tcg_target_long arg)
+{
+    if (arg == (int16_t) arg)
+        tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
+    else {
+        tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff));
+        if (arg & 0xffff)
+            tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff));
+    }
+}
+
+static void tcg_out_ldst (TCGContext *s, int ret, int addr,
+                          int offset, int op1, int op2)
+{
+    if (offset == (int16_t) offset)
+        tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+    else {
+        tcg_out_movi (s, TCG_TYPE_I32, 0, offset);
+        tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+    }
+}
+
+static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) s->code_ptr;
+    if ((disp << 6) >> 6 == disp)
+        tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
+    else {
+        tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target);
+        tcg_out32 (s, MTSPR | RS (0) | CTR);
+        tcg_out32 (s, BCCTR | BO_ALWAYS | mask);
+    }
+}
+
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+{
+#ifdef _CALL_AIX
+    int reg;
+
+    if (const_arg) {
+        reg = 2;
+        tcg_out_movi (s, TCG_TYPE_I32, reg, arg);
+    }
+    else reg = arg;
+
+    tcg_out32 (s, LWZ | RT (0) | RA (reg));
+    tcg_out32 (s, MTSPR | RA (0) | CTR);
+    tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4);
+    tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+#else
+    if (const_arg) {
+        tcg_out_b (s, LK, arg);
+    }
+    else {
+        tcg_out32 (s, MTSPR | RS (arg) | LR);
+        tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+    }
+#endif
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, data_reg2, r0, r1, rbase, mem_index, s_bits, bswap;
+#ifdef CONFIG_SOFTMMU
+    int r2;
+    void *label1_ptr, *label2_ptr;
+#endif
+#if TARGET_LONG_BITS == 64
+    int addr_reg2;
+#endif
+
+    data_reg = *args++;
+    if (opc == 3)
+        data_reg2 = *args++;
+    else
+        data_reg2 = 0;
+    addr_reg = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+#endif
+    mem_index = *args;
+    s_bits = opc & 3;
+
+#ifdef CONFIG_SOFTMMU
+    r0 = 3;
+    r1 = 4;
+    r2 = 0;
+    rbase = 0;
+
+    tcg_out32 (s, (RLWINM
+                   | RA (r0)
+                   | RS (addr_reg)
+                   | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+                   | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
+                   | ME (31 - CPU_TLB_ENTRY_BITS)
+                   )
+        );
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+    tcg_out32 (s, (LWZU
+                   | RT (r1)
+                   | RA (r0)
+                   | offsetof (CPUState, tlb_table[mem_index][0].addr_read)
+                   )
+        );
+    tcg_out32 (s, (RLWINM
+                   | RA (r2)
+                   | RS (addr_reg)
+                   | SH (0)
+                   | MB ((32 - s_bits) & 31)
+                   | ME (31 - TARGET_PAGE_BITS)
+                   )
+        );
+
+    tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1));
+#if TARGET_LONG_BITS == 64
+    tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4);
+    tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1));
+    tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+#endif
+
+    label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+    tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+    /* slow path */
+#if TARGET_LONG_BITS == 32
+    tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
+    tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index);
+#else
+    tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+    tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
+    tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index);
+#endif
+
+    tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+    switch (opc) {
+    case 0|4:
+        tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
+        break;
+    case 1|4:
+        tcg_out32 (s, EXTSH | RA (data_reg) | RS (3));
+        break;
+    case 0:
+    case 1:
+    case 2:
+        if (data_reg != 3)
+            tcg_out_mov (s, TCG_TYPE_I32, data_reg, 3);
+        break;
+    case 3:
+        if (data_reg == 3) {
+            if (data_reg2 == 4) {
+                tcg_out_mov (s, TCG_TYPE_I32, 0, 4);
+                tcg_out_mov (s, TCG_TYPE_I32, 4, 3);
+                tcg_out_mov (s, TCG_TYPE_I32, 3, 0);
+            }
+            else {
+                tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+                tcg_out_mov (s, TCG_TYPE_I32, 3, 4);
+            }
+        }
+        else {
+            if (data_reg != 4) tcg_out_mov (s, TCG_TYPE_I32, data_reg, 4);
+            if (data_reg2 != 3) tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+        }
+        break;
+    }
+    label2_ptr = s->code_ptr;
+    tcg_out32 (s, B);
+
+    /* label1: fast path */
+#ifdef FAST_PATH
+    reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+    /* r0 now contains &env->tlb_table[mem_index][index].addr_read */
+    tcg_out32 (s, (LWZ
+                   | RT (r0)
+                   | RA (r0)
+                   | (offsetof (CPUTLBEntry, addend)
+                      - offsetof (CPUTLBEntry, addr_read))
+                   ));
+    /* r0 = env->tlb_table[mem_index][index].addend */
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+    /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else  /* !CONFIG_SOFTMMU */
+    r0 = addr_reg;
+    r1 = 3;
+    rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 0;
+#else
+    bswap = 1;
+#endif
+
+    switch (opc) {
+    default:
+    case 0:
+        tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+        break;
+    case 0|4:
+        tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+        tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg));
+        break;
+    case 1:
+        if (bswap)
+            tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0));
+        break;
+    case 1|4:
+        if (bswap) {
+            tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+            tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
+        }
+        else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
+        break;
+    case 2:
+        if (bswap)
+            tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0));
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+            tcg_out32 (s, LWBRX | TAB (data_reg2, rbase, r1));
+        }
+        else {
+#ifdef CONFIG_USE_GUEST_BASE
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out32 (s, LWZX | TAB (data_reg2, rbase, r0));
+            tcg_out32 (s, LWZX | TAB (data_reg, rbase, r1));
+#else
+            if (r0 == data_reg2) {
+                tcg_out32 (s, LWZ | RT (0) | RA (r0));
+                tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
+                tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 0);
+            }
+            else {
+                tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0));
+                tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
+            }
+#endif
+        }
+        break;
+    }
+
+#ifdef CONFIG_SOFTMMU
+    reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap, rbase;
+#ifdef CONFIG_SOFTMMU
+    int r2, ir;
+    void *label1_ptr, *label2_ptr;
+#endif
+#if TARGET_LONG_BITS == 64
+    int addr_reg2;
+#endif
+
+    data_reg = *args++;
+    if (opc == 3)
+        data_reg2 = *args++;
+    else
+        data_reg2 = 0;
+    addr_reg = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+#endif
+    mem_index = *args;
+
+#ifdef CONFIG_SOFTMMU
+    r0 = 3;
+    r1 = 4;
+    r2 = 0;
+    rbase = 0;
+
+    tcg_out32 (s, (RLWINM
+                   | RA (r0)
+                   | RS (addr_reg)
+                   | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+                   | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS))
+                   | ME (31 - CPU_TLB_ENTRY_BITS)
+                   )
+        );
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+    tcg_out32 (s, (LWZU
+                   | RT (r1)
+                   | RA (r0)
+                   | offsetof (CPUState, tlb_table[mem_index][0].addr_write)
+                   )
+        );
+    tcg_out32 (s, (RLWINM
+                   | RA (r2)
+                   | RS (addr_reg)
+                   | SH (0)
+                   | MB ((32 - opc) & 31)
+                   | ME (31 - TARGET_PAGE_BITS)
+                   )
+        );
+
+    tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1));
+#if TARGET_LONG_BITS == 64
+    tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4);
+    tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1));
+    tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+#endif
+
+    label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+    tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+    /* slow path */
+#if TARGET_LONG_BITS == 32
+    tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
+    ir = 4;
+#else
+    tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+    tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+    ir = 5;
+#else
+    ir = 4;
+#endif
+#endif
+
+    switch (opc) {
+    case 0:
+        tcg_out32 (s, (RLWINM
+                       | RA (ir)
+                       | RS (data_reg)
+                       | SH (0)
+                       | MB (24)
+                       | ME (31)));
+        break;
+    case 1:
+        tcg_out32 (s, (RLWINM
+                       | RA (ir)
+                       | RS (data_reg)
+                       | SH (0)
+                       | MB (16)
+                       | ME (31)));
+        break;
+    case 2:
+        tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+        break;
+    case 3:
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+        ir = 5;
+#endif
+        tcg_out_mov (s, TCG_TYPE_I32, ir++, data_reg2);
+        tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+        break;
+    }
+    ir++;
+
+    tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
+    tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
+    label2_ptr = s->code_ptr;
+    tcg_out32 (s, B);
+
+    /* label1: fast path */
+#ifdef FAST_PATH
+    reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+    tcg_out32 (s, (LWZ
+                   | RT (r0)
+                   | RA (r0)
+                   | (offsetof (CPUTLBEntry, addend)
+                      - offsetof (CPUTLBEntry, addr_write))
+                   ));
+    /* r0 = env->tlb_table[mem_index][index].addend */
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+    /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else  /* !CONFIG_SOFTMMU */
+    r0 = addr_reg;
+    r1 = 3;
+    rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 0;
+#else
+    bswap = 1;
+#endif
+    switch (opc) {
+    case 0:
+        tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
+        break;
+    case 1:
+        if (bswap)
+            tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, STHX | SAB (data_reg, rbase, r0));
+        break;
+    case 2:
+        if (bswap)
+            tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, STWX | SAB (data_reg, rbase, r0));
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out32 (s, STWBRX | SAB (data_reg,  rbase, r0));
+            tcg_out32 (s, STWBRX | SAB (data_reg2, rbase, r1));
+        }
+        else {
+#ifdef CONFIG_USE_GUEST_BASE
+            tcg_out32 (s, STWX | SAB (data_reg2, rbase, r0));
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out32 (s, STWX | SAB (data_reg,  rbase, r1));
+#else
+            tcg_out32 (s, STW | RS (data_reg2) | RA (r0));
+            tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4);
+#endif
+        }
+        break;
+    }
+
+#ifdef CONFIG_SOFTMMU
+    reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_target_qemu_prologue (TCGContext *s)
+{
+    int i, frame_size;
+
+    frame_size = 0
+        + LINKAGE_AREA_SIZE
+        + TCG_STATIC_CALL_ARGS_SIZE
+        + ARRAY_SIZE (tcg_target_callee_save_regs) * 4
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
+        ;
+    frame_size = (frame_size + 15) & ~15;
+
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
+#ifdef _CALL_AIX
+    {
+        uint32_t addr;
+
+        /* First emit adhoc function descriptor */
+        addr = (uint32_t) s->code_ptr + 12;
+        tcg_out32 (s, addr);        /* entry point */
+        s->code_ptr += 8;           /* skip TOC and environment pointer */
+    }
+#endif
+    tcg_out32 (s, MFSPR | RT (0) | LR);
+    tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff));
+    for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+        tcg_out32 (s, (STW
+                       | RS (tcg_target_callee_save_regs[i])
+                       | RA (1)
+                       | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
+                       )
+            );
+    tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET));
+
+#ifdef CONFIG_USE_GUEST_BASE
+    if (GUEST_BASE) {
+        tcg_out_movi (s, TCG_TYPE_I32, TCG_GUEST_BASE_REG, GUEST_BASE);
+        tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+    }
+#endif
+
+    tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
+    tcg_out32 (s, BCCTR | BO_ALWAYS);
+    tb_ret_addr = s->code_ptr;
+
+    for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+        tcg_out32 (s, (LWZ
+                       | RT (tcg_target_callee_save_regs[i])
+                       | RA (1)
+                       | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
+                       )
+            );
+    tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET));
+    tcg_out32 (s, MTSPR | RS (0) | LR);
+    tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size);
+    tcg_out32 (s, BCLR | BO_ALWAYS);
+}
+
+static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+                        tcg_target_long arg2)
+{
+    tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
+}
+
+static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+                        tcg_target_long arg2)
+{
+    tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
+}
+
+static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+    if (!si && rt == ra)
+        return;
+
+    if (si == (int16_t) si)
+        tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff));
+    else {
+        uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15);
+        tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h);
+        tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff));
+    }
+}
+
+static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
+                         int const_arg2, int cr)
+{
+    int imm;
+    uint32_t op;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        if (const_arg2) {
+            if ((int16_t) arg2 == arg2) {
+                op = CMPI;
+                imm = 1;
+                break;
+            }
+            else if ((uint16_t) arg2 == arg2) {
+                op = CMPLI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMPL;
+        imm = 0;
+        break;
+
+    case TCG_COND_LT:
+    case TCG_COND_GE:
+    case TCG_COND_LE:
+    case TCG_COND_GT:
+        if (const_arg2) {
+            if ((int16_t) arg2 == arg2) {
+                op = CMPI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMP;
+        imm = 0;
+        break;
+
+    case TCG_COND_LTU:
+    case TCG_COND_GEU:
+    case TCG_COND_LEU:
+    case TCG_COND_GTU:
+        if (const_arg2) {
+            if ((uint16_t) arg2 == arg2) {
+                op = CMPLI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMPL;
+        imm = 0;
+        break;
+
+    default:
+        tcg_abort ();
+    }
+    op |= BF (cr);
+
+    if (imm)
+        tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff));
+    else {
+        if (const_arg2) {
+            tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+            tcg_out32 (s, op | RA (arg1) | RB (0));
+        }
+        else
+            tcg_out32 (s, op | RA (arg1) | RB (arg2));
+    }
+
+}
+
+static void tcg_out_bc (TCGContext *s, int bc, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value)
+        tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value));
+    else {
+        uint16_t val = *(uint16_t *) &s->code_ptr[2];
+
+        /* Thanks to Andrzej Zaborowski */
+        tcg_out32 (s, bc | (val & 0xfffc));
+        tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0);
+    }
+}
+
+static void tcg_out_cr7eq_from_cond (TCGContext *s, const TCGArg *args,
+                                     const int *const_args)
+{
+    TCGCond cond = args[4];
+    int op;
+    struct { int bit1; int bit2; int cond2; } bits[] = {
+        [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT  },
+        [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT  },
+        [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT  },
+        [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT  },
+        [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU },
+        [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU },
+        [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU },
+        [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU },
+    }, *b = &bits[cond];
+
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        op = (cond == TCG_COND_EQ) ? CRAND : CRNAND;
+        tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6);
+        tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7);
+        tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+        break;
+    case TCG_COND_LT:
+    case TCG_COND_LE:
+    case TCG_COND_GT:
+    case TCG_COND_GE:
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        op = (b->bit1 != b->bit2) ? CRANDC : CRAND;
+        tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5);
+        tcg_out_cmp (s, tcg_unsigned_cond (cond), args[0], args[2],
+                     const_args[2], 7);
+        tcg_out32 (s, op | BT (7, CR_EQ) | BA (5, CR_EQ) | BB (7, b->bit2));
+        tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ));
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void tcg_out_setcond (TCGContext *s, TCGCond cond, TCGArg arg0,
+                             TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+    int crop, sh, arg;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        if (const_arg2) {
+            if (!arg2) {
+                arg = arg1;
+            }
+            else {
+                arg = 0;
+                if ((uint16_t) arg2 == arg2) {
+                    tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+                }
+                else {
+                    tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+                    tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+                }
+            }
+        }
+        else {
+            arg = 0;
+            tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+        }
+        tcg_out32 (s, CNTLZW | RS (arg) | RA (0));
+        tcg_out32 (s, (RLWINM
+                       | RA (arg0)
+                       | RS (0)
+                       | SH (27)
+                       | MB (5)
+                       | ME (31)
+                       )
+            );
+        break;
+
+    case TCG_COND_NE:
+        if (const_arg2) {
+            if (!arg2) {
+                arg = arg1;
+            }
+            else {
+                arg = 0;
+                if ((uint16_t) arg2 == arg2) {
+                    tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+                }
+                else {
+                    tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+                    tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+                }
+            }
+        }
+        else {
+            arg = 0;
+            tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+        }
+
+        if (arg == arg1 && arg1 == arg0) {
+            tcg_out32 (s, ADDIC | RT (0) | RA (arg) | 0xffff);
+            tcg_out32 (s, SUBFE | TAB (arg0, 0, arg));
+        }
+        else {
+            tcg_out32 (s, ADDIC | RT (arg0) | RA (arg) | 0xffff);
+            tcg_out32 (s, SUBFE | TAB (arg0, arg0, arg));
+        }
+        break;
+
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        sh = 30;
+        crop = 0;
+        goto crtest;
+
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+        sh = 29;
+        crop = 0;
+        goto crtest;
+
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        sh = 31;
+        crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_LT) | BB (7, CR_LT);
+        goto crtest;
+
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        sh = 31;
+        crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_GT) | BB (7, CR_GT);
+    crtest:
+        tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7);
+        if (crop) tcg_out32 (s, crop);
+        tcg_out32 (s, MFCR | RT (0));
+        tcg_out32 (s, (RLWINM
+                       | RA (arg0)
+                       | RS (0)
+                       | SH (sh)
+                       | MB (31)
+                       | ME (31)
+                       )
+            );
+        break;
+
+    default:
+        tcg_abort ();
+    }
+}
+
+static void tcg_out_setcond2 (TCGContext *s, const TCGArg *args,
+                              const int *const_args)
+{
+    tcg_out_cr7eq_from_cond (s, args + 1, const_args + 1);
+    tcg_out32 (s, MFCR | RT (0));
+    tcg_out32 (s, (RLWINM
+                   | RA (args[0])
+                   | RS (0)
+                   | SH (31)
+                   | MB (31)
+                   | ME (31)
+                   )
+        );
+}
+
+static void tcg_out_brcond (TCGContext *s, TCGCond cond,
+                            TCGArg arg1, TCGArg arg2, int const_arg2,
+                            int label_index)
+{
+    tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7);
+    tcg_out_bc (s, tcg_to_bc[cond], label_index);
+}
+
+/* XXX: we implement it at the target level to avoid having to
+   handle cross basic blocks temporaries */
+static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args,
+                             const int *const_args)
+{
+    tcg_out_cr7eq_from_cond (s, args, const_args);
+    tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), args[5]);
+}
+
+void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr)
+{
+    uint32_t *ptr;
+    long disp = addr - jmp_addr;
+    unsigned long patch_size;
+
+    ptr = (uint32_t *)jmp_addr;
+
+    if ((disp << 6) >> 6 != disp) {
+        ptr[0] = 0x3c000000 | (addr >> 16);    /* lis 0,addr at ha */
+        ptr[1] = 0x60000000 | (addr & 0xffff); /* la  0,addr at l(0) */
+        ptr[2] = 0x7c0903a6;                   /* mtctr 0 */
+        ptr[3] = 0x4e800420;                   /* brctr */
+        patch_size = 16;
+    } else {
+        /* patch the branch destination */
+        if (disp != 16) {
+            *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */
+            patch_size = 4;
+        } else {
+            ptr[0] = 0x60000000; /* nop */
+            ptr[1] = 0x60000000;
+            ptr[2] = 0x60000000;
+            ptr[3] = 0x60000000;
+            patch_size = 16;
+        }
+    }
+    /* flush icache */
+    flush_icache_range(jmp_addr, jmp_addr + patch_size);
+}
+
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                       const int *const_args)
+{
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]);
+        tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            s->code_ptr += 16;
+        }
+        else {
+            tcg_abort ();
+        }
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_br:
+        {
+            TCGLabel *l = &s->labels[args[0]];
+
+            if (l->has_value) {
+                tcg_out_b (s, 0, l->u.value);
+            }
+            else {
+                uint32_t val = *(uint32_t *) s->code_ptr;
+
+                /* Thanks to Andrzej Zaborowski */
+                tcg_out32 (s, B | (val & 0x3fffffc));
+                tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0);
+            }
+        }
+        break;
+    case INDEX_op_call:
+        tcg_out_call (s, args[0], const_args[0]);
+        break;
+    case INDEX_op_jmp:
+        if (const_args[0]) {
+            tcg_out_b (s, 0, args[0]);
+        }
+        else {
+            tcg_out32 (s, MTSPR | RS (args[0]) | CTR);
+            tcg_out32 (s, BCCTR | BO_ALWAYS);
+        }
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_ld8u_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+        break;
+    case INDEX_op_ld8s_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+        tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0]));
+        break;
+    case INDEX_op_ld16u_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX);
+        break;
+    case INDEX_op_ld16s_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX);
+        break;
+    case INDEX_op_ld_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
+        break;
+    case INDEX_op_st8_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX);
+        break;
+    case INDEX_op_st16_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX);
+        break;
+    case INDEX_op_st_i32:
+        tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2])
+            ppc_addi (s, args[0], args[1], args[2]);
+        else
+            tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_sub_i32:
+        if (const_args[2])
+            ppc_addi (s, args[0], args[1], -args[2]);
+        else
+            tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+        break;
+
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            uint32_t c;
+
+            c = args[2];
+
+            if (!c) {
+                tcg_out_movi (s, TCG_TYPE_I32, args[0], 0);
+                break;
+            }
+#ifdef __PPU__
+            uint32_t t, n;
+            int mb, me;
+
+            n = c ^ -(c & 1);
+            t = n + (n & -n);
+
+            if ((t & (t - 1)) == 0) {
+                int lzc, tzc;
+
+                if ((c & 0x80000001) == 0x80000001) {
+                    lzc = clz32 (n);
+                    tzc = ctz32 (n);
+
+                    mb = 32 - tzc;
+                    me = lzc - 1;
+                }
+                else {
+                    lzc = clz32 (c);
+                    tzc = ctz32 (c);
+
+                    mb = lzc;
+                    me = 31 - tzc;
+                }
+
+                tcg_out32 (s, (RLWINM
+                               | RA (args[0])
+                               | RS (args[1])
+                               | SH (0)
+                               | MB (mb)
+                               | ME (me)
+                               )
+                    );
+            }
+            else
+#endif /* !__PPU__ */
+            {
+                if ((c & 0xffff) == c)
+                    tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | c);
+                else if ((c & 0xffff0000) == c)
+                    tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0])
+                               | ((c >> 16) & 0xffff));
+                else {
+                    tcg_out_movi (s, TCG_TYPE_I32, 0, c);
+                    tcg_out32 (s, AND | SAB (args[1], args[0], 0));
+                }
+            }
+        }
+        else
+            tcg_out32 (s, AND | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            if (args[2] & 0xffff) {
+                tcg_out32 (s, ORI | RS (args[1])  | RA (args[0])
+                           | (args[2] & 0xffff));
+                if (args[2] >> 16)
+                    tcg_out32 (s, ORIS | RS (args[0])  | RA (args[0])
+                               | ((args[2] >> 16) & 0xffff));
+            }
+            else {
+                tcg_out32 (s, ORIS | RS (args[1])  | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
+            }
+        }
+        else
+            tcg_out32 (s, OR | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_xor_i32:
+        if (const_args[2]) {
+            if ((args[2] & 0xffff) == args[2])
+                tcg_out32 (s, XORI | RS (args[1])  | RA (args[0])
+                           | (args[2] & 0xffff));
+            else if ((args[2] & 0xffff0000) == args[2])
+                tcg_out32 (s, XORIS | RS (args[1])  | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
+            else {
+                tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+                tcg_out32 (s, XOR | SAB (args[1], args[0], 0));
+            }
+        }
+        else
+            tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_andc_i32:
+        tcg_out32 (s, ANDC | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_orc_i32:
+        tcg_out32 (s, ORC | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_eqv_i32:
+        tcg_out32 (s, EQV | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_nand_i32:
+        tcg_out32 (s, NAND | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_nor_i32:
+        tcg_out32 (s, NOR | SAB (args[1], args[0], args[2]));
+        break;
+
+    case INDEX_op_mul_i32:
+        if (const_args[2]) {
+            if (args[2] == (int16_t) args[2])
+                tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1])
+                           | (args[2] & 0xffff));
+            else {
+                tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+                tcg_out32 (s, MULLW | TAB (args[0], args[1], 0));
+            }
+        }
+        else
+            tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_div_i32:
+        tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_divu_i32:
+        tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_rem_i32:
+        tcg_out32 (s, DIVW | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+
+    case INDEX_op_remu_i32:
+        tcg_out32 (s, DIVWU | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+
+    case INDEX_op_mulu2_i32:
+        if (args[0] == args[2] || args[0] == args[3]) {
+            tcg_out32 (s, MULLW | TAB (0, args[2], args[3]));
+            tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
+            tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+        }
+        else {
+            tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3]));
+            tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
+        }
+        break;
+
+    case INDEX_op_shl_i32:
+        if (const_args[2]) {
+            tcg_out32 (s, (RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (args[2])
+                           | MB (0)
+                           | ME (31 - args[2])
+                           )
+                );
+        }
+        else
+            tcg_out32 (s, SLW | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_shr_i32:
+        if (const_args[2]) {
+            tcg_out32 (s, (RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (32 - args[2])
+                           | MB (args[2])
+                           | ME (31)
+                           )
+                );
+        }
+        else
+            tcg_out32 (s, SRW | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_sar_i32:
+        if (const_args[2])
+            tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2]));
+        else
+            tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_rotl_i32:
+        {
+            int op = 0
+                | RA (args[0])
+                | RS (args[1])
+                | MB (0)
+                | ME (31)
+                | (const_args[2] ? RLWINM | SH (args[2])
+                                 : RLWNM | RB (args[2]))
+                ;
+            tcg_out32 (s, op);
+        }
+        break;
+    case INDEX_op_rotr_i32:
+        if (const_args[2]) {
+            if (!args[2]) {
+                tcg_out_mov (s, TCG_TYPE_I32, args[0], args[1]);
+            }
+            else {
+                tcg_out32 (s, RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (32 - args[2])
+                           | MB (0)
+                           | ME (31)
+                    );
+            }
+        }
+        else {
+            tcg_out32 (s, SUBFIC | RT (0) | RA (args[2]) | 32);
+            tcg_out32 (s, RLWNM
+                       | RA (args[0])
+                       | RS (args[1])
+                       | RB (0)
+                       | MB (0)
+                       | ME (31)
+                );
+        }
+        break;
+
+    case INDEX_op_add2_i32:
+        if (args[0] == args[3] || args[0] == args[5]) {
+            tcg_out32 (s, ADDC | TAB (0, args[2], args[4]));
+            tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5]));
+            tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+        }
+        else {
+            tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4]));
+            tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5]));
+        }
+        break;
+    case INDEX_op_sub2_i32:
+        if (args[0] == args[3] || args[0] == args[5]) {
+            tcg_out32 (s, SUBFC | TAB (0, args[4], args[2]));
+            tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3]));
+            tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+        }
+        else {
+            tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2]));
+            tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3]));
+        }
+        break;
+
+    case INDEX_op_brcond_i32:
+        /*
+          args[0] = r0
+          args[1] = r1
+          args[2] = cond
+          args[3] = r1 is const
+          args[4] = label_index
+        */
+        tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]);
+        break;
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2(s, args, const_args);
+        break;
+
+    case INDEX_op_neg_i32:
+        tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
+        break;
+
+    case INDEX_op_not_i32:
+        tcg_out32 (s, NOR | SAB (args[1], args[0], args[1]));
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    case INDEX_op_ext8s_i32:
+        tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0]));
+        break;
+    case INDEX_op_ext8u_i32:
+        tcg_out32 (s, RLWINM
+                   | RA (args[0])
+                   | RS (args[1])
+                   | SH (0)
+                   | MB (24)
+                   | ME (31)
+            );
+        break;
+    case INDEX_op_ext16s_i32:
+        tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0]));
+        break;
+    case INDEX_op_ext16u_i32:
+        tcg_out32 (s, RLWINM
+                   | RA (args[0])
+                   | RS (args[1])
+                   | SH (0)
+                   | MB (16)
+                   | ME (31)
+            );
+        break;
+
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond (s, args[3], args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2 (s, args, const_args);
+        break;
+
+    case INDEX_op_bswap16_i32:
+        /* Stolen from gcc's builtin_bswap16 */
+
+        /* a1 = abcd */
+
+        /* r0 = (a1 << 8) & 0xff00 # 00d0 */
+        tcg_out32 (s, RLWINM
+                   | RA (0)
+                   | RS (args[1])
+                   | SH (8)
+                   | MB (16)
+                   | ME (23)
+            );
+
+        /* a0 = rotate_left (a1, 24) & 0xff # 000c */
+        tcg_out32 (s, RLWINM
+                   | RA (args[0])
+                   | RS (args[1])
+                   | SH (24)
+                   | MB (24)
+                   | ME (31)
+            );
+
+        /* a0 = a0 | r0 # 00dc */
+        tcg_out32 (s, OR | SAB (0, args[0], args[0]));
+        break;
+
+    case INDEX_op_bswap32_i32:
+        /* Stolen from gcc's builtin_bswap32 */
+        {
+            int a0 = args[0];
+
+            /* a1 = args[1] # abcd */
+
+            if (a0 == args[1]) {
+                a0 = 0;
+            }
+
+            /* a0 = rotate_left (a1, 8) # bcda */
+            tcg_out32 (s, RLWINM
+                       | RA (a0)
+                       | RS (args[1])
+                       | SH (8)
+                       | MB (0)
+                       | ME (31)
+                );
+
+            /* a0 = (a0 & ~0xff000000) | ((a1 << 24) & 0xff000000) # dcda */
+            tcg_out32 (s, RLWIMI
+                       | RA (a0)
+                       | RS (args[1])
+                       | SH (24)
+                       | MB (0)
+                       | ME (7)
+                );
+
+            /* a0 = (a0 & ~0x0000ff00) | ((a1 << 24) & 0x0000ff00) # dcba */
+            tcg_out32 (s, RLWIMI
+                       | RA (a0)
+                       | RS (args[1])
+                       | SH (24)
+                       | MB (16)
+                       | ME (23)
+                );
+
+            if (!a0) {
+                tcg_out_mov (s, TCG_TYPE_I32, args[0], a0);
+            }
+        }
+        break;
+
+    default:
+        tcg_dump_ops (s, stderr);
+        tcg_abort ();
+    }
+}
+
+static const TCGTargetOpDef ppc_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "r", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+
+    { INDEX_op_add_i32, { "r", "r", "ri" } },
+    { INDEX_op_mul_i32, { "r", "r", "ri" } },
+    { INDEX_op_div_i32, { "r", "r", "r" } },
+    { INDEX_op_divu_i32, { "r", "r", "r" } },
+    { INDEX_op_rem_i32, { "r", "r", "r" } },
+    { INDEX_op_remu_i32, { "r", "r", "r" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+    { INDEX_op_sub_i32, { "r", "r", "ri" } },
+    { INDEX_op_and_i32, { "r", "r", "ri" } },
+    { INDEX_op_or_i32, { "r", "r", "ri" } },
+    { INDEX_op_xor_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_shl_i32, { "r", "r", "ri" } },
+    { INDEX_op_shr_i32, { "r", "r", "ri" } },
+    { INDEX_op_sar_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+    { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_brcond_i32, { "r", "ri" } },
+
+    { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
+    { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
+    { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
+
+    { INDEX_op_neg_i32, { "r", "r" } },
+    { INDEX_op_not_i32, { "r", "r" } },
+
+    { INDEX_op_andc_i32, { "r", "r", "r" } },
+    { INDEX_op_orc_i32, { "r", "r", "r" } },
+    { INDEX_op_eqv_i32, { "r", "r", "r" } },
+    { INDEX_op_nand_i32, { "r", "r", "r" } },
+    { INDEX_op_nor_i32, { "r", "r", "r" } },
+
+    { INDEX_op_setcond_i32, { "r", "r", "ri" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+
+    { INDEX_op_bswap16_i32, { "r", "r" } },
+    { INDEX_op_bswap32_i32, { "r", "r" } },
+
+#if TARGET_LONG_BITS == 32
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "K", "K" } },
+    { INDEX_op_qemu_st16, { "K", "K" } },
+    { INDEX_op_qemu_st32, { "K", "K" } },
+    { INDEX_op_qemu_st64, { "M", "M", "M" } },
+#else
+    { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
+
+    { INDEX_op_qemu_st8, { "K", "K", "K" } },
+    { INDEX_op_qemu_st16, { "K", "K", "K" } },
+    { INDEX_op_qemu_st32, { "K", "K", "K" } },
+    { INDEX_op_qemu_st64, { "M", "M", "M", "M" } },
+#endif
+
+    { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext8u_i32, { "r", "r" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext16u_i32, { "r", "r" } },
+
+    { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+    tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+                     (1 << TCG_REG_R0) |
+#ifdef _CALL_DARWIN
+                     (1 << TCG_REG_R2) |
+#endif
+                     (1 << TCG_REG_R3) |
+                     (1 << TCG_REG_R4) |
+                     (1 << TCG_REG_R5) |
+                     (1 << TCG_REG_R6) |
+                     (1 << TCG_REG_R7) |
+                     (1 << TCG_REG_R8) |
+                     (1 << TCG_REG_R9) |
+                     (1 << TCG_REG_R10) |
+                     (1 << TCG_REG_R11) |
+                     (1 << TCG_REG_R12)
+        );
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);
+#ifndef _CALL_DARWIN
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
+#endif
+#ifdef _CALL_SYSV
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
+#endif
+
+    tcg_add_target_add_op_defs(ppc_op_defs);
+}
diff --git a/qemu-0.15.x/tcg/ppc/tcg-target.h b/qemu-0.15.x/tcg/ppc/tcg-target.h
new file mode 100644
index 0000000..a1f8599
--- /dev/null
+++ b/qemu-0.15.x/tcg/ppc/tcg-target.h
@@ -0,0 +1,98 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_PPC 1
+
+#define TCG_TARGET_REG_BITS 32
+#define TCG_TARGET_WORDS_BIGENDIAN
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31
+};
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R1
+#define TCG_TARGET_STACK_ALIGN 16
+#if defined _CALL_DARWIN || defined __APPLE__
+#define TCG_TARGET_CALL_STACK_OFFSET 24
+#elif defined _CALL_AIX
+#define TCG_TARGET_CALL_STACK_OFFSET 52
+#elif defined _CALL_SYSV
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_CALL_STACK_OFFSET 8
+#else
+#error Unsupported system
+#endif
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_eqv_i32
+#define TCG_TARGET_HAS_nand_i32
+#define TCG_TARGET_HAS_nor_i32
+
+#define TCG_AREG0 TCG_REG_R27
+
+#define TCG_TARGET_HAS_GUEST_BASE
diff --git a/qemu-0.15.x/tcg/ppc64/tcg-target.c b/qemu-0.15.x/tcg/ppc64/tcg-target.c
new file mode 100644
index 0000000..02a6cb2
--- /dev/null
+++ b/qemu-0.15.x/tcg/ppc64/tcg-target.c
@@ -0,0 +1,1699 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+
+#define TCG_CT_CONST_U32 0x100
+
+static uint8_t *tb_ret_addr;
+
+#define FAST_PATH
+
+#if TARGET_LONG_BITS == 32
+#define LD_ADDR LWZU
+#define CMP_L 0
+#else
+#define LD_ADDR LDU
+#define CMP_L (1<<21)
+#endif
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG 30
+#else
+#define TCG_GUEST_BASE_REG 0
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "r14",
+    "r15",
+    "r16",
+    "r17",
+    "r18",
+    "r19",
+    "r20",
+    "r21",
+    "r22",
+    "r23",
+    "r24",
+    "r25",
+    "r26",
+    "r27",
+    "r28",
+    "r29",
+    "r30",
+    "r31"
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31,
+#ifdef __APPLE__
+    TCG_REG_R2,
+#endif
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+#ifndef __APPLE__
+    TCG_REG_R11,
+#endif
+    TCG_REG_R12,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_R3
+};
+
+static const int tcg_target_callee_save_regs[] = {
+#ifdef __APPLE__
+    TCG_REG_R11,
+#endif
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27, /* currently used for the global env */
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31
+};
+
+static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) pc;
+    if ((disp << 38) >> 38 != disp)
+        tcg_abort ();
+
+    return disp & 0x3fffffc;
+}
+
+static void reloc_pc24 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc)
+        | reloc_pc24_val (pc, target);
+}
+
+static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) pc;
+    if (disp != (int16_t) disp)
+        tcg_abort ();
+
+    return disp & 0xfffc;
+}
+
+static void reloc_pc14 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc)
+        | reloc_pc14_val (pc, target);
+}
+
+static void patch_reloc (uint8_t *code_ptr, int type,
+                         tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch (type) {
+    case R_PPC_REL14:
+        reloc_pc14 (code_ptr, value);
+        break;
+    case R_PPC_REL24:
+        reloc_pc24 (code_ptr, value);
+        break;
+    default:
+        tcg_abort ();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static int tcg_target_get_call_iarg_regs_count (int flags)
+{
+    return ARRAY_SIZE (tcg_target_call_iarg_regs);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'A': case 'B': case 'C': case 'D':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A');
+        break;
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+        break;
+    case 'L':                   /* qemu_ld constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+#ifdef CONFIG_SOFTMMU
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
+#endif
+        break;
+    case 'S':                   /* qemu_st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+#ifdef CONFIG_SOFTMMU
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5);
+#endif
+        break;
+    case 'Z':
+        ct->ct |= TCG_CT_CONST_U32;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match (tcg_target_long val,
+                                   const TCGArgConstraint *arg_ct)
+{
+    int ct;
+
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_U32) && (val == (uint32_t) val))
+        return 1;
+    return 0;
+}
+
+#define OPCD(opc) ((opc)<<26)
+#define XO19(opc) (OPCD(19)|((opc)<<1))
+#define XO30(opc) (OPCD(30)|((opc)<<2))
+#define XO31(opc) (OPCD(31)|((opc)<<1))
+#define XO58(opc) (OPCD(58)|(opc))
+#define XO62(opc) (OPCD(62)|(opc))
+
+#define B      OPCD( 18)
+#define BC     OPCD( 16)
+#define LBZ    OPCD( 34)
+#define LHZ    OPCD( 40)
+#define LHA    OPCD( 42)
+#define LWZ    OPCD( 32)
+#define STB    OPCD( 38)
+#define STH    OPCD( 44)
+#define STW    OPCD( 36)
+
+#define STD    XO62(  0)
+#define STDU   XO62(  1)
+#define STDX   XO31(149)
+
+#define LD     XO58(  0)
+#define LDX    XO31( 21)
+#define LDU    XO58(  1)
+#define LWA    XO58(  2)
+#define LWAX   XO31(341)
+
+#define ADDIC  OPCD( 12)
+#define ADDI   OPCD( 14)
+#define ADDIS  OPCD( 15)
+#define ORI    OPCD( 24)
+#define ORIS   OPCD( 25)
+#define XORI   OPCD( 26)
+#define XORIS  OPCD( 27)
+#define ANDI   OPCD( 28)
+#define ANDIS  OPCD( 29)
+#define MULLI  OPCD(  7)
+#define CMPLI  OPCD( 10)
+#define CMPI   OPCD( 11)
+
+#define LWZU   OPCD( 33)
+#define STWU   OPCD( 37)
+
+#define RLWINM OPCD( 21)
+
+#define RLDICL XO30(  0)
+#define RLDICR XO30(  1)
+#define RLDIMI XO30(  3)
+
+#define BCLR   XO19( 16)
+#define BCCTR  XO19(528)
+#define CRAND  XO19(257)
+#define CRANDC XO19(129)
+#define CRNAND XO19(225)
+#define CROR   XO19(449)
+#define CRNOR  XO19( 33)
+
+#define EXTSB  XO31(954)
+#define EXTSH  XO31(922)
+#define EXTSW  XO31(986)
+#define ADD    XO31(266)
+#define ADDE   XO31(138)
+#define ADDC   XO31( 10)
+#define AND    XO31( 28)
+#define SUBF   XO31( 40)
+#define SUBFC  XO31(  8)
+#define SUBFE  XO31(136)
+#define OR     XO31(444)
+#define XOR    XO31(316)
+#define MULLW  XO31(235)
+#define MULHWU XO31( 11)
+#define DIVW   XO31(491)
+#define DIVWU  XO31(459)
+#define CMP    XO31(  0)
+#define CMPL   XO31( 32)
+#define LHBRX  XO31(790)
+#define LWBRX  XO31(534)
+#define STHBRX XO31(918)
+#define STWBRX XO31(662)
+#define MFSPR  XO31(339)
+#define MTSPR  XO31(467)
+#define SRAWI  XO31(824)
+#define NEG    XO31(104)
+#define MFCR   XO31( 19)
+#define CNTLZW XO31( 26)
+#define CNTLZD XO31( 58)
+
+#define MULLD  XO31(233)
+#define MULHD  XO31( 73)
+#define MULHDU XO31(  9)
+#define DIVD   XO31(489)
+#define DIVDU  XO31(457)
+
+#define LBZX   XO31( 87)
+#define LHZX   XO31(279)
+#define LHAX   XO31(343)
+#define LWZX   XO31( 23)
+#define STBX   XO31(215)
+#define STHX   XO31(407)
+#define STWX   XO31(151)
+
+#define SPR(a,b) ((((a)<<5)|(b))<<11)
+#define LR     SPR(8, 0)
+#define CTR    SPR(9, 0)
+
+#define SLW    XO31( 24)
+#define SRW    XO31(536)
+#define SRAW   XO31(792)
+
+#define SLD    XO31( 27)
+#define SRD    XO31(539)
+#define SRAD   XO31(794)
+#define SRADI  XO31(413<<1)
+
+#define TW     XO31( 4)
+#define TRAP   (TW | TO (31))
+
+#define RT(r) ((r)<<21)
+#define RS(r) ((r)<<21)
+#define RA(r) ((r)<<16)
+#define RB(r) ((r)<<11)
+#define TO(t) ((t)<<21)
+#define SH(s) ((s)<<11)
+#define MB(b) ((b)<<6)
+#define ME(e) ((e)<<1)
+#define BO(o) ((o)<<21)
+#define MB64(b) ((b)<<5)
+
+#define LK    1
+
+#define TAB(t,a,b) (RT(t) | RA(a) | RB(b))
+#define SAB(s,a,b) (RS(s) | RA(a) | RB(b))
+
+#define BF(n)    ((n)<<23)
+#define BI(n, c) (((c)+((n)*4))<<16)
+#define BT(n, c) (((c)+((n)*4))<<21)
+#define BA(n, c) (((c)+((n)*4))<<16)
+#define BB(n, c) (((c)+((n)*4))<<11)
+
+#define BO_COND_TRUE  BO (12)
+#define BO_COND_FALSE BO ( 4)
+#define BO_ALWAYS     BO (20)
+
+enum {
+    CR_LT,
+    CR_GT,
+    CR_EQ,
+    CR_SO
+};
+
+static const uint32_t tcg_to_bc[10] = {
+    [TCG_COND_EQ]  = BC | BI (7, CR_EQ) | BO_COND_TRUE,
+    [TCG_COND_NE]  = BC | BI (7, CR_EQ) | BO_COND_FALSE,
+    [TCG_COND_LT]  = BC | BI (7, CR_LT) | BO_COND_TRUE,
+    [TCG_COND_GE]  = BC | BI (7, CR_LT) | BO_COND_FALSE,
+    [TCG_COND_LE]  = BC | BI (7, CR_GT) | BO_COND_FALSE,
+    [TCG_COND_GT]  = BC | BI (7, CR_GT) | BO_COND_TRUE,
+    [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+    [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+    [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+    [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+};
+
+static void tcg_out_mov (TCGContext *s, TCGType type, int ret, int arg)
+{
+    tcg_out32 (s, OR | SAB (arg, ret, arg));
+}
+
+static void tcg_out_rld (TCGContext *s, int op, int ra, int rs, int sh, int mb)
+{
+    sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1);
+    mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f));
+    tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb);
+}
+
+static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg)
+{
+    if (arg == (int16_t) arg)
+        tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
+    else {
+        tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff));
+        if (arg & 0xffff)
+            tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff));
+    }
+}
+
+static void tcg_out_movi (TCGContext *s, TCGType type,
+                          int ret, tcg_target_long arg)
+{
+    int32_t arg32 = arg;
+    arg = type == TCG_TYPE_I32 ? arg & 0xffffffff : arg;
+
+    if (arg == arg32) {
+        tcg_out_movi32 (s, ret, arg32);
+    }
+    else {
+        if ((uint64_t) arg >> 32) {
+            uint16_t h16 = arg >> 16;
+            uint16_t l16 = arg;
+
+            tcg_out_movi32 (s, ret, arg >> 32);
+            tcg_out_rld (s, RLDICR, ret, ret, 32, 31);
+            if (h16) tcg_out32 (s, ORIS | RS (ret) | RA (ret) | h16);
+            if (l16) tcg_out32 (s, ORI | RS (ret) | RA (ret) | l16);
+        }
+        else {
+            tcg_out_movi32 (s, ret, arg32);
+            if (arg32 < 0)
+                tcg_out_rld (s, RLDICL, ret, ret, 0, 32);
+        }
+    }
+}
+
+static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
+{
+    tcg_target_long disp;
+
+    disp = target - (tcg_target_long) s->code_ptr;
+    if ((disp << 38) >> 38 == disp)
+        tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
+    else {
+        tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target);
+        tcg_out32 (s, MTSPR | RS (0) | CTR);
+        tcg_out32 (s, BCCTR | BO_ALWAYS | mask);
+    }
+}
+
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+{
+#ifdef __APPLE__
+    if (const_arg) {
+        tcg_out_b (s, LK, arg);
+    }
+    else {
+        tcg_out32 (s, MTSPR | RS (arg) | LR);
+        tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+    }
+#else
+    int reg;
+
+    if (const_arg) {
+        reg = 2;
+        tcg_out_movi (s, TCG_TYPE_I64, reg, arg);
+    }
+    else reg = arg;
+
+    tcg_out32 (s, LD | RT (0) | RA (reg));
+    tcg_out32 (s, MTSPR | RA (0) | CTR);
+    tcg_out32 (s, LD | RT (11) | RA (reg) | 16);
+    tcg_out32 (s, LD | RT (2) | RA (reg) | 8);
+    tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+#endif
+}
+
+static void tcg_out_ldst (TCGContext *s, int ret, int addr,
+                          int offset, int op1, int op2)
+{
+    if (offset == (int16_t) offset)
+        tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+    else {
+        tcg_out_movi (s, TCG_TYPE_I64, 0, offset);
+        tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+    }
+}
+
+static void tcg_out_ldsta (TCGContext *s, int ret, int addr,
+                           int offset, int op1, int op2)
+{
+    if (offset == (int16_t) (offset & ~3))
+        tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+    else {
+        tcg_out_movi (s, TCG_TYPE_I64, 0, offset);
+        tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+    }
+}
+
+#if defined (CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+
+static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2,
+                              int addr_reg, int s_bits, int offset)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+
+    tcg_out32 (s, (RLWINM
+                   | RA (r0)
+                   | RS (addr_reg)
+                   | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+                   | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
+                   | ME (31 - CPU_TLB_ENTRY_BITS)
+                   )
+        );
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+    tcg_out32 (s, (LWZU | RT (r1) | RA (r0) | offset));
+    tcg_out32 (s, (RLWINM
+                   | RA (r2)
+                   | RS (addr_reg)
+                   | SH (0)
+                   | MB ((32 - s_bits) & 31)
+                   | ME (31 - TARGET_PAGE_BITS)
+                   )
+        );
+#else
+    tcg_out_rld (s, RLDICL, r0, addr_reg,
+                 64 - TARGET_PAGE_BITS,
+                 64 - CPU_TLB_BITS);
+    tcg_out_rld (s, RLDICR, r0, r0,
+                 CPU_TLB_ENTRY_BITS,
+                 63 - CPU_TLB_ENTRY_BITS);
+
+    tcg_out32 (s, ADD | TAB (r0, r0, TCG_AREG0));
+    tcg_out32 (s, LD_ADDR | RT (r1) | RA (r0) | offset);
+
+    if (!s_bits) {
+        tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS);
+    }
+    else {
+        tcg_out_rld (s, RLDICL, r2, addr_reg,
+                     64 - TARGET_PAGE_BITS,
+                     TARGET_PAGE_BITS - s_bits);
+        tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0);
+    }
+#endif
+}
+#endif
+
+static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap;
+#ifdef CONFIG_SOFTMMU
+    int r2;
+    void *label1_ptr, *label2_ptr;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+    s_bits = opc & 3;
+
+#ifdef CONFIG_SOFTMMU
+    r0 = 3;
+    r1 = 4;
+    r2 = 0;
+    rbase = 0;
+
+    tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits,
+                      offsetof (CPUState, tlb_table[mem_index][0].addr_read));
+
+    tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
+
+    label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+    tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+    /* slow path */
+    tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
+    tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index);
+
+    tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+
+    switch (opc) {
+    case 0|4:
+        tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
+        break;
+    case 1|4:
+        tcg_out32 (s, EXTSH | RA (data_reg) | RS (3));
+        break;
+    case 2|4:
+        tcg_out32 (s, EXTSW | RA (data_reg) | RS (3));
+        break;
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+        if (data_reg != 3)
+            tcg_out_mov (s, TCG_TYPE_I64, data_reg, 3);
+        break;
+    }
+    label2_ptr = s->code_ptr;
+    tcg_out32 (s, B);
+
+    /* label1: fast path */
+#ifdef FAST_PATH
+    reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+    /* r0 now contains &env->tlb_table[mem_index][index].addr_read */
+    tcg_out32 (s, (LD
+                   | RT (r0)
+                   | RA (r0)
+                   | (offsetof (CPUTLBEntry, addend)
+                      - offsetof (CPUTLBEntry, addr_read))
+                   ));
+    /* r0 = env->tlb_table[mem_index][index].addend */
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+    /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else  /* !CONFIG_SOFTMMU */
+#if TARGET_LONG_BITS == 32
+    tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+#endif
+    r0 = addr_reg;
+    r1 = 3;
+    rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 0;
+#else
+    bswap = 1;
+#endif
+    switch (opc) {
+    default:
+    case 0:
+        tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+        break;
+    case 0|4:
+        tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+        tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg));
+        break;
+    case 1:
+        if (bswap)
+            tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0));
+        break;
+    case 1|4:
+        if (bswap) {
+            tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+            tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
+        }
+        else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
+        break;
+    case 2:
+        if (bswap)
+            tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0));
+        break;
+    case 2|4:
+        if (bswap) {
+            tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+            tcg_out32 (s, EXTSW | RA (data_reg) | RS (data_reg));
+        }
+        else tcg_out32 (s, LWAX | TAB (data_reg, rbase, r0));
+        break;
+    case 3:
+#ifdef CONFIG_USE_GUEST_BASE
+        if (bswap) {
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+            tcg_out32 (s, LWBRX | TAB (      r1, rbase, r1));
+            tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
+        }
+        else tcg_out32 (s, LDX | TAB (data_reg, rbase, r0));
+#else
+        if (bswap) {
+            tcg_out_movi32 (s, 0, 4);
+            tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
+            tcg_out32 (s, LWBRX | RT (      r1) | RA (r0));
+            tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
+        }
+        else tcg_out32 (s, LD | RT (data_reg) | RA (r0));
+#endif
+        break;
+    }
+
+#ifdef CONFIG_SOFTMMU
+    reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
+{
+    int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap;
+#ifdef CONFIG_SOFTMMU
+    int r2;
+    void *label1_ptr, *label2_ptr;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+
+#ifdef CONFIG_SOFTMMU
+    r0 = 3;
+    r1 = 4;
+    r2 = 0;
+    rbase = 0;
+
+    tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc,
+                      offsetof (CPUState, tlb_table[mem_index][0].addr_write));
+
+    tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
+
+    label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+    tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+    /* slow path */
+    tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
+    tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc)));
+    tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index);
+
+    tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
+
+    label2_ptr = s->code_ptr;
+    tcg_out32 (s, B);
+
+    /* label1: fast path */
+#ifdef FAST_PATH
+    reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+    tcg_out32 (s, (LD
+                   | RT (r0)
+                   | RA (r0)
+                   | (offsetof (CPUTLBEntry, addend)
+                      - offsetof (CPUTLBEntry, addr_write))
+                   ));
+    /* r0 = env->tlb_table[mem_index][index].addend */
+    tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+    /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else  /* !CONFIG_SOFTMMU */
+#if TARGET_LONG_BITS == 32
+    tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+#endif
+    r1 = 3;
+    r0 = addr_reg;
+    rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    bswap = 0;
+#else
+    bswap = 1;
+#endif
+    switch (opc) {
+    case 0:
+        tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
+        break;
+    case 1:
+        if (bswap)
+            tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, STHX | SAB (data_reg, rbase, r0));
+        break;
+    case 2:
+        if (bswap)
+            tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+        else
+            tcg_out32 (s, STWX | SAB (data_reg, rbase, r0));
+        break;
+    case 3:
+        if (bswap) {
+            tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+            tcg_out_rld (s, RLDICL, 0, data_reg, 32, 0);
+            tcg_out32 (s, STWBRX | SAB (0, rbase, r1));
+        }
+        else tcg_out32 (s, STDX | SAB (data_reg, rbase, r0));
+        break;
+    }
+
+#ifdef CONFIG_SOFTMMU
+    reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_target_qemu_prologue (TCGContext *s)
+{
+    int i, frame_size;
+#ifndef __APPLE__
+    uint64_t addr;
+#endif
+
+    frame_size = 0
+        + 8                     /* back chain */
+        + 8                     /* CR */
+        + 8                     /* LR */
+        + 8                     /* compiler doubleword */
+        + 8                     /* link editor doubleword */
+        + 8                     /* TOC save area */
+        + TCG_STATIC_CALL_ARGS_SIZE
+        + ARRAY_SIZE (tcg_target_callee_save_regs) * 8
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
+        ;
+    frame_size = (frame_size + 15) & ~15;
+
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
+#ifndef __APPLE__
+    /* First emit adhoc function descriptor */
+    addr = (uint64_t) s->code_ptr + 24;
+    tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */
+    s->code_ptr += 16;          /* skip TOC and environment pointer */
+#endif
+
+    /* Prologue */
+    tcg_out32 (s, MFSPR | RT (0) | LR);
+    tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff));
+    for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+        tcg_out32 (s, (STD
+                       | RS (tcg_target_callee_save_regs[i])
+                       | RA (1)
+                       | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
+                       )
+            );
+    tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16));
+
+#ifdef CONFIG_USE_GUEST_BASE
+    if (GUEST_BASE) {
+        tcg_out_movi (s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE);
+        tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+    }
+#endif
+
+    tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
+    tcg_out32 (s, BCCTR | BO_ALWAYS);
+
+    /* Epilogue */
+    tb_ret_addr = s->code_ptr;
+
+    for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+        tcg_out32 (s, (LD
+                       | RT (tcg_target_callee_save_regs[i])
+                       | RA (1)
+                       | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
+                       )
+            );
+    tcg_out32 (s, LD | RT (0) | RA (1) | (frame_size + 16));
+    tcg_out32 (s, MTSPR | RS (0) | LR);
+    tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size);
+    tcg_out32 (s, BCLR | BO_ALWAYS);
+}
+
+static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+                        tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32)
+        tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
+    else
+        tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX);
+}
+
+static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+                        tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32)
+        tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
+    else
+        tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX);
+}
+
+static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+    if (!si && rt == ra)
+        return;
+
+    if (si == (int16_t) si)
+        tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff));
+    else {
+        uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15);
+        tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h);
+        tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff));
+    }
+}
+
+static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+    /* XXX: suboptimal */
+    if (si == (int16_t) si
+        || ((((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0))
+        ppc_addi32 (s, rt, ra, si);
+    else {
+        tcg_out_movi (s, TCG_TYPE_I64, 0, si);
+        tcg_out32 (s, ADD | RT (rt) | RA (ra));
+    }
+}
+
+static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
+                         int const_arg2, int cr, int arch64)
+{
+    int imm;
+    uint32_t op;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        if (const_arg2) {
+            if ((int16_t) arg2 == arg2) {
+                op = CMPI;
+                imm = 1;
+                break;
+            }
+            else if ((uint16_t) arg2 == arg2) {
+                op = CMPLI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMPL;
+        imm = 0;
+        break;
+
+    case TCG_COND_LT:
+    case TCG_COND_GE:
+    case TCG_COND_LE:
+    case TCG_COND_GT:
+        if (const_arg2) {
+            if ((int16_t) arg2 == arg2) {
+                op = CMPI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMP;
+        imm = 0;
+        break;
+
+    case TCG_COND_LTU:
+    case TCG_COND_GEU:
+    case TCG_COND_LEU:
+    case TCG_COND_GTU:
+        if (const_arg2) {
+            if ((uint16_t) arg2 == arg2) {
+                op = CMPLI;
+                imm = 1;
+                break;
+            }
+        }
+        op = CMPL;
+        imm = 0;
+        break;
+
+    default:
+        tcg_abort ();
+    }
+    op |= BF (cr) | (arch64 << 21);
+
+    if (imm)
+        tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff));
+    else {
+        if (const_arg2) {
+            tcg_out_movi (s, TCG_TYPE_I64, 0, arg2);
+            tcg_out32 (s, op | RA (arg1) | RB (0));
+        }
+        else
+            tcg_out32 (s, op | RA (arg1) | RB (arg2));
+    }
+
+}
+
+static void tcg_out_setcond (TCGContext *s, TCGType type, TCGCond cond,
+                             TCGArg arg0, TCGArg arg1, TCGArg arg2,
+                             int const_arg2)
+{
+    int crop, sh, arg;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        if (const_arg2) {
+            if (!arg2) {
+                arg = arg1;
+            }
+            else {
+                arg = 0;
+                if ((uint16_t) arg2 == arg2) {
+                    tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+                }
+                else {
+                    tcg_out_movi (s, type, 0, arg2);
+                    tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+                }
+            }
+        }
+        else {
+            arg = 0;
+            tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+        }
+
+        if (type == TCG_TYPE_I64) {
+            tcg_out32 (s, CNTLZD | RS (arg) | RA (0));
+            tcg_out_rld (s, RLDICL, arg0, 0, 58, 6);
+        }
+        else {
+            tcg_out32 (s, CNTLZW | RS (arg) | RA (0));
+            tcg_out32 (s, (RLWINM
+                           | RA (arg0)
+                           | RS (0)
+                           | SH (27)
+                           | MB (5)
+                           | ME (31)
+                           )
+                );
+        }
+        break;
+
+    case TCG_COND_NE:
+        if (const_arg2) {
+            if (!arg2) {
+                arg = arg1;
+            }
+            else {
+                arg = 0;
+                if ((uint16_t) arg2 == arg2) {
+                    tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+                }
+                else {
+                    tcg_out_movi (s, type, 0, arg2);
+                    tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+                }
+            }
+        }
+        else {
+            arg = 0;
+            tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+        }
+
+        if (arg == arg1 && arg1 == arg0) {
+            tcg_out32 (s, ADDIC | RT (0) | RA (arg) | 0xffff);
+            tcg_out32 (s, SUBFE | TAB (arg0, 0, arg));
+        }
+        else {
+            tcg_out32 (s, ADDIC | RT (arg0) | RA (arg) | 0xffff);
+            tcg_out32 (s, SUBFE | TAB (arg0, arg0, arg));
+        }
+        break;
+
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        sh = 30;
+        crop = 0;
+        goto crtest;
+
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+        sh = 29;
+        crop = 0;
+        goto crtest;
+
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        sh = 31;
+        crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_LT) | BB (7, CR_LT);
+        goto crtest;
+
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        sh = 31;
+        crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_GT) | BB (7, CR_GT);
+    crtest:
+        tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, type == TCG_TYPE_I64);
+        if (crop) tcg_out32 (s, crop);
+        tcg_out32 (s, MFCR | RT (0));
+        tcg_out32 (s, (RLWINM
+                       | RA (arg0)
+                       | RS (0)
+                       | SH (sh)
+                       | MB (31)
+                       | ME (31)
+                       )
+            );
+        break;
+
+    default:
+        tcg_abort ();
+    }
+}
+
+static void tcg_out_bc (TCGContext *s, int bc, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value)
+        tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value));
+    else {
+        uint16_t val = *(uint16_t *) &s->code_ptr[2];
+
+        /* Thanks to Andrzej Zaborowski */
+        tcg_out32 (s, bc | (val & 0xfffc));
+        tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0);
+    }
+}
+
+static void tcg_out_brcond (TCGContext *s, TCGCond cond,
+                            TCGArg arg1, TCGArg arg2, int const_arg2,
+                            int label_index, int arch64)
+{
+    tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, arch64);
+    tcg_out_bc (s, tcg_to_bc[cond], label_index);
+}
+
+void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr)
+{
+    TCGContext s;
+    unsigned long patch_size;
+
+    s.code_ptr = (uint8_t *) jmp_addr;
+    tcg_out_b (&s, 0, addr);
+    patch_size = s.code_ptr - (uint8_t *) jmp_addr;
+    flush_icache_range (jmp_addr, jmp_addr + patch_size);
+}
+
+static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                        const int *const_args)
+{
+    int c;
+
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]);
+        tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+            s->code_ptr += 28;
+        }
+        else {
+            tcg_abort ();
+        }
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_br:
+        {
+            TCGLabel *l = &s->labels[args[0]];
+
+            if (l->has_value) {
+                tcg_out_b (s, 0, l->u.value);
+            }
+            else {
+                uint32_t val = *(uint32_t *) s->code_ptr;
+
+                /* Thanks to Andrzej Zaborowski */
+                tcg_out32 (s, B | (val & 0x3fffffc));
+                tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0);
+            }
+        }
+        break;
+    case INDEX_op_call:
+        tcg_out_call (s, args[0], const_args[0]);
+        break;
+    case INDEX_op_jmp:
+        if (const_args[0]) {
+            tcg_out_b (s, 0, args[0]);
+        }
+        else {
+            tcg_out32 (s, MTSPR | RS (args[0]) | CTR);
+            tcg_out32 (s, BCCTR | BO_ALWAYS);
+        }
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i64:
+        tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ld8u_i32:
+    case INDEX_op_ld8u_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+        break;
+    case INDEX_op_ld8s_i32:
+    case INDEX_op_ld8s_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+        tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0]));
+        break;
+    case INDEX_op_ld16u_i32:
+    case INDEX_op_ld16u_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX);
+        break;
+    case INDEX_op_ld16s_i32:
+    case INDEX_op_ld16s_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX);
+        break;
+    case INDEX_op_ld_i32:
+    case INDEX_op_ld32u_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
+        break;
+    case INDEX_op_ld32s_i64:
+        tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX);
+        break;
+    case INDEX_op_ld_i64:
+        tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX);
+        break;
+    case INDEX_op_st8_i32:
+    case INDEX_op_st8_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX);
+        break;
+    case INDEX_op_st16_i32:
+    case INDEX_op_st16_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX);
+        break;
+    case INDEX_op_st_i32:
+    case INDEX_op_st32_i64:
+        tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
+        break;
+    case INDEX_op_st_i64:
+        tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2])
+            ppc_addi32 (s, args[0], args[1], args[2]);
+        else
+            tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_sub_i32:
+        if (const_args[2])
+            ppc_addi32 (s, args[0], args[1], -args[2]);
+        else
+            tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+        break;
+
+    case INDEX_op_and_i64:
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            if ((args[2] & 0xffff) == args[2])
+                tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]);
+            else if ((args[2] & 0xffff0000) == args[2])
+                tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
+            else {
+                tcg_out_movi (s, (opc == INDEX_op_and_i32
+                                  ? TCG_TYPE_I32
+                                  : TCG_TYPE_I64),
+                              0, args[2]);
+                tcg_out32 (s, AND | SAB (args[1], args[0], 0));
+            }
+        }
+        else
+            tcg_out32 (s, AND | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_or_i64:
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            if (args[2] & 0xffff) {
+                tcg_out32 (s, ORI | RS (args[1]) | RA (args[0])
+                           | (args[2] & 0xffff));
+                if (args[2] >> 16)
+                    tcg_out32 (s, ORIS | RS (args[0])  | RA (args[0])
+                               | ((args[2] >> 16) & 0xffff));
+            }
+            else {
+                tcg_out32 (s, ORIS | RS (args[1])  | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
+            }
+        }
+        else
+            tcg_out32 (s, OR | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_xor_i64:
+    case INDEX_op_xor_i32:
+        if (const_args[2]) {
+            if ((args[2] & 0xffff) == args[2])
+                tcg_out32 (s, XORI | RS (args[1])  | RA (args[0])
+                           | (args[2] & 0xffff));
+            else if ((args[2] & 0xffff0000) == args[2])
+                tcg_out32 (s, XORIS | RS (args[1])  | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
+            else {
+                tcg_out_movi (s, (opc == INDEX_op_and_i32
+                                  ? TCG_TYPE_I32
+                                  : TCG_TYPE_I64),
+                              0, args[2]);
+                tcg_out32 (s, XOR | SAB (args[1], args[0], 0));
+            }
+        }
+        else
+            tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
+        break;
+
+    case INDEX_op_mul_i32:
+        if (const_args[2]) {
+            if (args[2] == (int16_t) args[2])
+                tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1])
+                           | (args[2] & 0xffff));
+            else {
+                tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+                tcg_out32 (s, MULLW | TAB (args[0], args[1], 0));
+            }
+        }
+        else
+            tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_div_i32:
+        tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_divu_i32:
+        tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2]));
+        break;
+
+    case INDEX_op_rem_i32:
+        tcg_out32 (s, DIVW | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+
+    case INDEX_op_remu_i32:
+        tcg_out32 (s, DIVWU | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+
+    case INDEX_op_shl_i32:
+        if (const_args[2]) {
+            tcg_out32 (s, (RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (args[2])
+                           | MB (0)
+                           | ME (31 - args[2])
+                           )
+                );
+        }
+        else
+            tcg_out32 (s, SLW | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_shr_i32:
+        if (const_args[2]) {
+            tcg_out32 (s, (RLWINM
+                           | RA (args[0])
+                           | RS (args[1])
+                           | SH (32 - args[2])
+                           | MB (args[2])
+                           | ME (31)
+                           )
+                );
+        }
+        else
+            tcg_out32 (s, SRW | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_sar_i32:
+        if (const_args[2])
+            tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2]));
+        else
+            tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 0);
+        break;
+
+    case INDEX_op_brcond_i64:
+        tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 1);
+        break;
+
+    case INDEX_op_neg_i32:
+    case INDEX_op_neg_i64:
+        tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
+        break;
+
+    case INDEX_op_add_i64:
+        if (const_args[2])
+            ppc_addi64 (s, args[0], args[1], args[2]);
+        else
+            tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_sub_i64:
+        if (const_args[2])
+            ppc_addi64 (s, args[0], args[1], -args[2]);
+        else
+            tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+        break;
+
+    case INDEX_op_shl_i64:
+        if (const_args[2])
+            tcg_out_rld (s, RLDICR, args[0], args[1], args[2], 63 - args[2]);
+        else
+            tcg_out32 (s, SLD | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_shr_i64:
+        if (const_args[2])
+            tcg_out_rld (s, RLDICL, args[0], args[1], 64 - args[2], args[2]);
+        else
+            tcg_out32 (s, SRD | SAB (args[1], args[0], args[2]));
+        break;
+    case INDEX_op_sar_i64:
+        if (const_args[2]) {
+            int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1);
+            tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh);
+        }
+        else
+            tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2]));
+        break;
+
+    case INDEX_op_mul_i64:
+        tcg_out32 (s, MULLD | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_div_i64:
+        tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_divu_i64:
+        tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2]));
+        break;
+    case INDEX_op_rem_i64:
+        tcg_out32 (s, DIVD | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLD | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+    case INDEX_op_remu_i64:
+        tcg_out32 (s, DIVDU | TAB (0, args[1], args[2]));
+        tcg_out32 (s, MULLD | TAB (0, 0, args[2]));
+        tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld (s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld (s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld (s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld (s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+    case INDEX_op_qemu_ld32u:
+        tcg_out_qemu_ld (s, args, 2);
+        break;
+    case INDEX_op_qemu_ld32s:
+        tcg_out_qemu_ld (s, args, 2 | 4);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld (s, args, 3);
+        break;
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st (s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st (s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st (s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st (s, args, 3);
+        break;
+
+    case INDEX_op_ext8s_i32:
+    case INDEX_op_ext8s_i64:
+        c = EXTSB;
+        goto gen_ext;
+    case INDEX_op_ext16s_i32:
+    case INDEX_op_ext16s_i64:
+        c = EXTSH;
+        goto gen_ext;
+    case INDEX_op_ext32s_i64:
+        c = EXTSW;
+        goto gen_ext;
+    gen_ext:
+        tcg_out32 (s, c | RS (args[1]) | RA (args[0]));
+        break;
+
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond (s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
+                         const_args[2]);
+        break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond (s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
+                         const_args[2]);
+        break;
+
+    default:
+        tcg_dump_ops (s, stderr);
+        tcg_abort ();
+    }
+}
+
+static const TCGTargetOpDef ppc_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_mov_i64, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_movi_i64, { "r" } },
+
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+    { INDEX_op_st8_i32, { "r", "r" } },
+    { INDEX_op_st8_i64, { "r", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st16_i64, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+    { INDEX_op_st_i64, { "r", "r" } },
+    { INDEX_op_st32_i64, { "r", "r" } },
+
+    { INDEX_op_ld8u_i64, { "r", "r" } },
+    { INDEX_op_ld8s_i64, { "r", "r" } },
+    { INDEX_op_ld16u_i64, { "r", "r" } },
+    { INDEX_op_ld16s_i64, { "r", "r" } },
+    { INDEX_op_ld32u_i64, { "r", "r" } },
+    { INDEX_op_ld32s_i64, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+
+    { INDEX_op_add_i32, { "r", "r", "ri" } },
+    { INDEX_op_mul_i32, { "r", "r", "ri" } },
+    { INDEX_op_div_i32, { "r", "r", "r" } },
+    { INDEX_op_divu_i32, { "r", "r", "r" } },
+    { INDEX_op_rem_i32, { "r", "r", "r" } },
+    { INDEX_op_remu_i32, { "r", "r", "r" } },
+    { INDEX_op_sub_i32, { "r", "r", "ri" } },
+    { INDEX_op_and_i32, { "r", "r", "ri" } },
+    { INDEX_op_or_i32, { "r", "r", "ri" } },
+    { INDEX_op_xor_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_shl_i32, { "r", "r", "ri" } },
+    { INDEX_op_shr_i32, { "r", "r", "ri" } },
+    { INDEX_op_sar_i32, { "r", "r", "ri" } },
+
+    { INDEX_op_brcond_i32, { "r", "ri" } },
+    { INDEX_op_brcond_i64, { "r", "ri" } },
+
+    { INDEX_op_neg_i32, { "r", "r" } },
+
+    { INDEX_op_add_i64, { "r", "r", "ri" } },
+    { INDEX_op_sub_i64, { "r", "r", "ri" } },
+    { INDEX_op_and_i64, { "r", "r", "rZ" } },
+    { INDEX_op_or_i64, { "r", "r", "rZ" } },
+    { INDEX_op_xor_i64, { "r", "r", "rZ" } },
+
+    { INDEX_op_shl_i64, { "r", "r", "ri" } },
+    { INDEX_op_shr_i64, { "r", "r", "ri" } },
+    { INDEX_op_sar_i64, { "r", "r", "ri" } },
+
+    { INDEX_op_mul_i64, { "r", "r", "r" } },
+    { INDEX_op_div_i64, { "r", "r", "r" } },
+    { INDEX_op_divu_i64, { "r", "r", "r" } },
+    { INDEX_op_rem_i64, { "r", "r", "r" } },
+    { INDEX_op_remu_i64, { "r", "r", "r" } },
+
+    { INDEX_op_neg_i64, { "r", "r" } },
+
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld32u, { "r", "L" } },
+    { INDEX_op_qemu_ld32s, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "S", "S" } },
+    { INDEX_op_qemu_st16, { "S", "S" } },
+    { INDEX_op_qemu_st32, { "S", "S" } },
+    { INDEX_op_qemu_st64, { "S", "S" } },
+
+    { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext8s_i64, { "r", "r" } },
+    { INDEX_op_ext16s_i64, { "r", "r" } },
+    { INDEX_op_ext32s_i64, { "r", "r" } },
+
+    { INDEX_op_setcond_i32, { "r", "r", "ri" } },
+    { INDEX_op_setcond_i64, { "r", "r", "ri" } },
+
+    { -1 },
+};
+
+static void tcg_target_init (TCGContext *s)
+{
+    tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+    tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+    tcg_regset_set32 (tcg_target_call_clobber_regs, 0,
+                     (1 << TCG_REG_R0) |
+#ifdef __APPLE__
+                     (1 << TCG_REG_R2) |
+#endif
+                     (1 << TCG_REG_R3) |
+                     (1 << TCG_REG_R4) |
+                     (1 << TCG_REG_R5) |
+                     (1 << TCG_REG_R6) |
+                     (1 << TCG_REG_R7) |
+                     (1 << TCG_REG_R8) |
+                     (1 << TCG_REG_R9) |
+                     (1 << TCG_REG_R10) |
+                     (1 << TCG_REG_R11) |
+                     (1 << TCG_REG_R12)
+        );
+
+    tcg_regset_clear (s->reserved_regs);
+    tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0);
+    tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1);
+#ifndef __APPLE__
+    tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2);
+#endif
+    tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13);
+
+    tcg_add_target_add_op_defs (ppc_op_defs);
+}
diff --git a/qemu-0.15.x/tcg/ppc64/tcg-target.h b/qemu-0.15.x/tcg/ppc64/tcg-target.h
new file mode 100644
index 0000000..8a6db11
--- /dev/null
+++ b/qemu-0.15.x/tcg/ppc64/tcg-target.h
@@ -0,0 +1,109 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_PPC64 1
+
+#define TCG_TARGET_REG_BITS 64
+#define TCG_TARGET_WORDS_BIGENDIAN
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15,
+    TCG_REG_R16,
+    TCG_REG_R17,
+    TCG_REG_R18,
+    TCG_REG_R19,
+    TCG_REG_R20,
+    TCG_REG_R21,
+    TCG_REG_R22,
+    TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    TCG_REG_R27,
+    TCG_REG_R28,
+    TCG_REG_R29,
+    TCG_REG_R30,
+    TCG_REG_R31
+};
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R1
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 48
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+/* #define TCG_TARGET_HAS_rot_i32 */
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+/* #define TCG_TARGET_HAS_ext8u_i32 */
+/* #define TCG_TARGET_HAS_ext16u_i32 */
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+/* #define TCG_TARGET_HAS_not_i32 */
+#define TCG_TARGET_HAS_neg_i32
+/* #define TCG_TARGET_HAS_andc_i32 */
+/* #define TCG_TARGET_HAS_orc_i32 */
+/* #define TCG_TARGET_HAS_eqv_i32 */
+/* #define TCG_TARGET_HAS_nand_i32 */
+/* #define TCG_TARGET_HAS_nor_i32 */
+
+#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i64 */
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+/* #define TCG_TARGET_HAS_ext8u_i64 */
+/* #define TCG_TARGET_HAS_ext16u_i64 */
+/* #define TCG_TARGET_HAS_ext32u_i64 */
+/* #define TCG_TARGET_HAS_bswap16_i64 */
+/* #define TCG_TARGET_HAS_bswap32_i64 */
+/* #define TCG_TARGET_HAS_bswap64_i64 */
+/* #define TCG_TARGET_HAS_not_i64 */
+#define TCG_TARGET_HAS_neg_i64
+/* #define TCG_TARGET_HAS_andc_i64 */
+/* #define TCG_TARGET_HAS_orc_i64 */
+/* #define TCG_TARGET_HAS_eqv_i64 */
+/* #define TCG_TARGET_HAS_nand_i64 */
+/* #define TCG_TARGET_HAS_nor_i64 */
+
+#define TCG_AREG0 TCG_REG_R27
+
+#define TCG_TARGET_HAS_GUEST_BASE
+#define TCG_TARGET_EXTEND_ARGS 1
diff --git a/qemu-0.15.x/tcg/s390/tcg-target.c b/qemu-0.15.x/tcg/s390/tcg-target.c
new file mode 100644
index 0000000..2fc5646
--- /dev/null
+++ b/qemu-0.15.x/tcg/s390/tcg-target.c
@@ -0,0 +1,2327 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009 Ulrich Hecht <uli at suse.de>
+ * Copyright (c) 2009 Alexander Graf <agraf at suse.de>
+ * Copyright (c) 2010 Richard Henderson <rth at twiddle.net>
+ *
+ * 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.
+ */
+
+/* ??? The translation blocks produced by TCG are generally small enough to
+   be entirely reachable with a 16-bit displacement.  Leaving the option for
+   a 32-bit displacement here Just In Case.  */
+#define USE_LONG_BRANCHES 0
+
+#define TCG_CT_CONST_32    0x0100
+#define TCG_CT_CONST_NEG   0x0200
+#define TCG_CT_CONST_ADDI  0x0400
+#define TCG_CT_CONST_MULI  0x0800
+#define TCG_CT_CONST_ANDI  0x1000
+#define TCG_CT_CONST_ORI   0x2000
+#define TCG_CT_CONST_XORI  0x4000
+#define TCG_CT_CONST_CMPI  0x8000
+
+/* Several places within the instruction set 0 means "no register"
+   rather than TCG_REG_R0.  */
+#define TCG_REG_NONE    0
+
+/* A scratch register that may be be used throughout the backend.  */
+#define TCG_TMP0        TCG_REG_R14
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R13
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+
+/* All of the following instructions are prefixed with their instruction
+   format, and are defined as 8- or 16-bit quantities, even when the two
+   halves of the 16-bit quantity may appear 32 bits apart in the insn.
+   This makes it easy to copy the values from the tables in Appendix B.  */
+typedef enum S390Opcode {
+    RIL_AFI     = 0xc209,
+    RIL_AGFI    = 0xc208,
+    RIL_ALGFI   = 0xc20a,
+    RIL_BRASL   = 0xc005,
+    RIL_BRCL    = 0xc004,
+    RIL_CFI     = 0xc20d,
+    RIL_CGFI    = 0xc20c,
+    RIL_CLFI    = 0xc20f,
+    RIL_CLGFI   = 0xc20e,
+    RIL_IIHF    = 0xc008,
+    RIL_IILF    = 0xc009,
+    RIL_LARL    = 0xc000,
+    RIL_LGFI    = 0xc001,
+    RIL_LGRL    = 0xc408,
+    RIL_LLIHF   = 0xc00e,
+    RIL_LLILF   = 0xc00f,
+    RIL_LRL     = 0xc40d,
+    RIL_MSFI    = 0xc201,
+    RIL_MSGFI   = 0xc200,
+    RIL_NIHF    = 0xc00a,
+    RIL_NILF    = 0xc00b,
+    RIL_OIHF    = 0xc00c,
+    RIL_OILF    = 0xc00d,
+    RIL_XIHF    = 0xc006,
+    RIL_XILF    = 0xc007,
+
+    RI_AGHI     = 0xa70b,
+    RI_AHI      = 0xa70a,
+    RI_BRC      = 0xa704,
+    RI_IIHH     = 0xa500,
+    RI_IIHL     = 0xa501,
+    RI_IILH     = 0xa502,
+    RI_IILL     = 0xa503,
+    RI_LGHI     = 0xa709,
+    RI_LLIHH    = 0xa50c,
+    RI_LLIHL    = 0xa50d,
+    RI_LLILH    = 0xa50e,
+    RI_LLILL    = 0xa50f,
+    RI_MGHI     = 0xa70d,
+    RI_MHI      = 0xa70c,
+    RI_NIHH     = 0xa504,
+    RI_NIHL     = 0xa505,
+    RI_NILH     = 0xa506,
+    RI_NILL     = 0xa507,
+    RI_OIHH     = 0xa508,
+    RI_OIHL     = 0xa509,
+    RI_OILH     = 0xa50a,
+    RI_OILL     = 0xa50b,
+
+    RIE_CGIJ    = 0xec7c,
+    RIE_CGRJ    = 0xec64,
+    RIE_CIJ     = 0xec7e,
+    RIE_CLGRJ   = 0xec65,
+    RIE_CLIJ    = 0xec7f,
+    RIE_CLGIJ   = 0xec7d,
+    RIE_CLRJ    = 0xec77,
+    RIE_CRJ     = 0xec76,
+
+    RRE_AGR     = 0xb908,
+    RRE_CGR     = 0xb920,
+    RRE_CLGR    = 0xb921,
+    RRE_DLGR    = 0xb987,
+    RRE_DLR     = 0xb997,
+    RRE_DSGFR   = 0xb91d,
+    RRE_DSGR    = 0xb90d,
+    RRE_LGBR    = 0xb906,
+    RRE_LCGR    = 0xb903,
+    RRE_LGFR    = 0xb914,
+    RRE_LGHR    = 0xb907,
+    RRE_LGR     = 0xb904,
+    RRE_LLGCR   = 0xb984,
+    RRE_LLGFR   = 0xb916,
+    RRE_LLGHR   = 0xb985,
+    RRE_LRVR    = 0xb91f,
+    RRE_LRVGR   = 0xb90f,
+    RRE_LTGR    = 0xb902,
+    RRE_MSGR    = 0xb90c,
+    RRE_MSR     = 0xb252,
+    RRE_NGR     = 0xb980,
+    RRE_OGR     = 0xb981,
+    RRE_SGR     = 0xb909,
+    RRE_XGR     = 0xb982,
+
+    RR_AR       = 0x1a,
+    RR_BASR     = 0x0d,
+    RR_BCR      = 0x07,
+    RR_CLR      = 0x15,
+    RR_CR       = 0x19,
+    RR_DR       = 0x1d,
+    RR_LCR      = 0x13,
+    RR_LR       = 0x18,
+    RR_LTR      = 0x12,
+    RR_NR       = 0x14,
+    RR_OR       = 0x16,
+    RR_SR       = 0x1b,
+    RR_XR       = 0x17,
+
+    RSY_RLL     = 0xeb1d,
+    RSY_RLLG    = 0xeb1c,
+    RSY_SLLG    = 0xeb0d,
+    RSY_SRAG    = 0xeb0a,
+    RSY_SRLG    = 0xeb0c,
+
+    RS_SLL      = 0x89,
+    RS_SRA      = 0x8a,
+    RS_SRL      = 0x88,
+
+    RXY_AG      = 0xe308,
+    RXY_AY      = 0xe35a,
+    RXY_CG      = 0xe320,
+    RXY_CY      = 0xe359,
+    RXY_LB      = 0xe376,
+    RXY_LG      = 0xe304,
+    RXY_LGB     = 0xe377,
+    RXY_LGF     = 0xe314,
+    RXY_LGH     = 0xe315,
+    RXY_LHY     = 0xe378,
+    RXY_LLGC    = 0xe390,
+    RXY_LLGF    = 0xe316,
+    RXY_LLGH    = 0xe391,
+    RXY_LMG     = 0xeb04,
+    RXY_LRV     = 0xe31e,
+    RXY_LRVG    = 0xe30f,
+    RXY_LRVH    = 0xe31f,
+    RXY_LY      = 0xe358,
+    RXY_STCY    = 0xe372,
+    RXY_STG     = 0xe324,
+    RXY_STHY    = 0xe370,
+    RXY_STMG    = 0xeb24,
+    RXY_STRV    = 0xe33e,
+    RXY_STRVG   = 0xe32f,
+    RXY_STRVH   = 0xe33f,
+    RXY_STY     = 0xe350,
+
+    RX_A        = 0x5a,
+    RX_C        = 0x59,
+    RX_L        = 0x58,
+    RX_LH       = 0x48,
+    RX_ST       = 0x50,
+    RX_STC      = 0x42,
+    RX_STH      = 0x40,
+} S390Opcode;
+
+#define LD_SIGNED      0x04
+#define LD_UINT8       0x00
+#define LD_INT8        (LD_UINT8 | LD_SIGNED)
+#define LD_UINT16      0x01
+#define LD_INT16       (LD_UINT16 | LD_SIGNED)
+#define LD_UINT32      0x02
+#define LD_INT32       (LD_UINT32 | LD_SIGNED)
+#define LD_UINT64      0x03
+#define LD_INT64       (LD_UINT64 | LD_SIGNED)
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
+    "%r8", "%r9", "%r10" "%r11" "%r12" "%r13" "%r14" "%r15"
+};
+#endif
+
+/* Since R6 is a potential argument register, choose it last of the
+   call-saved registers.  Likewise prefer the call-clobbered registers
+   in reverse order to maximize the chance of avoiding the arguments.  */
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_R13,
+    TCG_REG_R12,
+    TCG_REG_R11,
+    TCG_REG_R10,
+    TCG_REG_R9,
+    TCG_REG_R8,
+    TCG_REG_R7,
+    TCG_REG_R6,
+    TCG_REG_R14,
+    TCG_REG_R0,
+    TCG_REG_R1,
+    TCG_REG_R5,
+    TCG_REG_R4,
+    TCG_REG_R3,
+    TCG_REG_R2,
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+};
+
+static const int tcg_target_call_oarg_regs[] = {
+    TCG_REG_R2,
+    TCG_REG_R3,
+};
+
+#define S390_CC_EQ      8
+#define S390_CC_LT      4
+#define S390_CC_GT      2
+#define S390_CC_OV      1
+#define S390_CC_NE      (S390_CC_LT | S390_CC_GT)
+#define S390_CC_LE      (S390_CC_LT | S390_CC_EQ)
+#define S390_CC_GE      (S390_CC_GT | S390_CC_EQ)
+#define S390_CC_NEVER   0
+#define S390_CC_ALWAYS  15
+
+/* Condition codes that result from a COMPARE and COMPARE LOGICAL.  */
+static const uint8_t tcg_cond_to_s390_cond[10] = {
+    [TCG_COND_EQ]  = S390_CC_EQ,
+    [TCG_COND_NE]  = S390_CC_NE,
+    [TCG_COND_LT]  = S390_CC_LT,
+    [TCG_COND_LE]  = S390_CC_LE,
+    [TCG_COND_GT]  = S390_CC_GT,
+    [TCG_COND_GE]  = S390_CC_GE,
+    [TCG_COND_LTU] = S390_CC_LT,
+    [TCG_COND_LEU] = S390_CC_LE,
+    [TCG_COND_GTU] = S390_CC_GT,
+    [TCG_COND_GEU] = S390_CC_GE,
+};
+
+/* Condition codes that result from a LOAD AND TEST.  Here, we have no
+   unsigned instruction variation, however since the test is vs zero we
+   can re-map the outcomes appropriately.  */
+static const uint8_t tcg_cond_to_ltr_cond[10] = {
+    [TCG_COND_EQ]  = S390_CC_EQ,
+    [TCG_COND_NE]  = S390_CC_NE,
+    [TCG_COND_LT]  = S390_CC_LT,
+    [TCG_COND_LE]  = S390_CC_LE,
+    [TCG_COND_GT]  = S390_CC_GT,
+    [TCG_COND_GE]  = S390_CC_GE,
+    [TCG_COND_LTU] = S390_CC_NEVER,
+    [TCG_COND_LEU] = S390_CC_EQ,
+    [TCG_COND_GTU] = S390_CC_NE,
+    [TCG_COND_GEU] = S390_CC_ALWAYS,
+};
+
+#ifdef CONFIG_SOFTMMU
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+static uint8_t *tb_ret_addr;
+
+/* A list of relevant facilities used by this translator.  Some of these
+   are required for proper operation, and these are checked at startup.  */
+
+#define FACILITY_ZARCH_ACTIVE	(1ULL << (63 - 2))
+#define FACILITY_LONG_DISP	(1ULL << (63 - 18))
+#define FACILITY_EXT_IMM	(1ULL << (63 - 21))
+#define FACILITY_GEN_INST_EXT	(1ULL << (63 - 34))
+
+static uint64_t facilities;
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    tcg_target_long code_ptr_tl = (tcg_target_long)code_ptr;
+    tcg_target_long pcrel2;
+
+    /* ??? Not the usual definition of "addend".  */
+    pcrel2 = (value - (code_ptr_tl + addend)) >> 1;
+
+    switch (type) {
+    case R_390_PC16DBL:
+        assert(pcrel2 == (int16_t)pcrel2);
+        *(int16_t *)code_ptr = pcrel2;
+        break;
+    case R_390_PC32DBL:
+        assert(pcrel2 == (int32_t)pcrel2);
+        *(int32_t *)code_ptr = pcrel2;
+        break;
+    default:
+        tcg_abort();
+        break;
+    }
+}
+
+static int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return sizeof(tcg_target_call_iarg_regs) / sizeof(int);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str = *pct_str;
+
+    switch (ct_str[0]) {
+    case 'r':                  /* all registers */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffff);
+        break;
+    case 'R':                  /* not R0 */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+        break;
+    case 'L':                  /* qemu_ld/st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffff);
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2);
+        tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+        break;
+    case 'a':                  /* force R2 for division */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_clear(ct->u.regs);
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_R2);
+        break;
+    case 'b':                  /* force R3 for division */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_clear(ct->u.regs);
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_R3);
+        break;
+    case 'N':                  /* force immediate negate */
+        ct->ct |= TCG_CT_CONST_NEG;
+        break;
+    case 'W':                  /* force 32-bit ("word") immediate */
+        ct->ct |= TCG_CT_CONST_32;
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_ADDI;
+        break;
+    case 'K':
+        ct->ct |= TCG_CT_CONST_MULI;
+        break;
+    case 'A':
+        ct->ct |= TCG_CT_CONST_ANDI;
+        break;
+    case 'O':
+        ct->ct |= TCG_CT_CONST_ORI;
+        break;
+    case 'X':
+        ct->ct |= TCG_CT_CONST_XORI;
+        break;
+    case 'C':
+        ct->ct |= TCG_CT_CONST_CMPI;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+
+    return 0;
+}
+
+/* Immediates to be used with logical AND.  This is an optimization only,
+   since a full 64-bit immediate AND can always be performed with 4 sequential
+   NI[LH][LH] instructions.  What we're looking for is immediates that we
+   can load efficiently, and the immediate load plus the reg-reg AND is
+   smaller than the sequential NI's.  */
+
+static int tcg_match_andi(int ct, tcg_target_ulong val)
+{
+    int i;
+
+    if (facilities & FACILITY_EXT_IMM) {
+        if (ct & TCG_CT_CONST_32) {
+            /* All 32-bit ANDs can be performed with 1 48-bit insn.  */
+            return 1;
+        }
+
+        /* Zero-extensions.  */
+        if (val == 0xff || val == 0xffff || val == 0xffffffff) {
+            return 1;
+        }
+    } else {
+        if (ct & TCG_CT_CONST_32) {
+            val = (uint32_t)val;
+        } else if (val == 0xffffffff) {
+            return 1;
+        }
+    }
+
+    /* Try all 32-bit insns that can perform it in one go.  */
+    for (i = 0; i < 4; i++) {
+        tcg_target_ulong mask = ~(0xffffull << i*16);
+        if ((val & mask) == mask) {
+            return 1;
+        }
+    }
+
+    /* Look for 16-bit values performing the mask.  These are better
+       to load with LLI[LH][LH].  */
+    for (i = 0; i < 4; i++) {
+        tcg_target_ulong mask = 0xffffull << i*16;
+        if ((val & mask) == val) {
+            return 0;
+        }
+    }
+
+    /* Look for 32-bit values performing the 64-bit mask.  These
+       are better to load with LLI[LH]F, or if extended immediates
+       not available, with a pair of LLI insns.  */
+    if ((ct & TCG_CT_CONST_32) == 0) {
+        if (val <= 0xffffffff || (val & 0xffffffff) == 0) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+/* Immediates to be used with logical OR.  This is an optimization only,
+   since a full 64-bit immediate OR can always be performed with 4 sequential
+   OI[LH][LH] instructions.  What we're looking for is immediates that we
+   can load efficiently, and the immediate load plus the reg-reg OR is
+   smaller than the sequential OI's.  */
+
+static int tcg_match_ori(int ct, tcg_target_long val)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        if (ct & TCG_CT_CONST_32) {
+            /* All 32-bit ORs can be performed with 1 48-bit insn.  */
+            return 1;
+        }
+    }
+
+    /* Look for negative values.  These are best to load with LGHI.  */
+    if (val < 0) {
+        if (val == (int16_t)val) {
+            return 0;
+        }
+        if (facilities & FACILITY_EXT_IMM) {
+            if (val == (int32_t)val) {
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+/* Immediates to be used with logical XOR.  This is almost, but not quite,
+   only an optimization.  XOR with immediate is only supported with the
+   extended-immediate facility.  That said, there are a few patterns for
+   which it is better to load the value into a register first.  */
+
+static int tcg_match_xori(int ct, tcg_target_long val)
+{
+    if ((facilities & FACILITY_EXT_IMM) == 0) {
+        return 0;
+    }
+
+    if (ct & TCG_CT_CONST_32) {
+        /* All 32-bit XORs can be performed with 1 48-bit insn.  */
+        return 1;
+    }
+
+    /* Look for negative values.  These are best to load with LGHI.  */
+    if (val < 0 && val == (int32_t)val) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Imediates to be used with comparisons.  */
+
+static int tcg_match_cmpi(int ct, tcg_target_long val)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        /* The COMPARE IMMEDIATE instruction is available.  */
+        if (ct & TCG_CT_CONST_32) {
+            /* We have a 32-bit immediate and can compare against anything.  */
+            return 1;
+        } else {
+            /* ??? We have no insight here into whether the comparison is
+               signed or unsigned.  The COMPARE IMMEDIATE insn uses a 32-bit
+               signed immediate, and the COMPARE LOGICAL IMMEDIATE insn uses
+               a 32-bit unsigned immediate.  If we were to use the (semi)
+               obvious "val == (int32_t)val" we would be enabling unsigned
+               comparisons vs very large numbers.  The only solution is to
+               take the intersection of the ranges.  */
+            /* ??? Another possible solution is to simply lie and allow all
+               constants here and force the out-of-range values into a temp
+               register in tgen_cmp when we have knowledge of the actual
+               comparison code in use.  */
+            return val >= 0 && val <= 0x7fffffff;
+        }
+    } else {
+        /* Only the LOAD AND TEST instruction is available.  */
+        return val == 0;
+    }
+}
+
+/* Test if a constant matches the constraint. */
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct)
+{
+    int ct = arg_ct->ct;
+
+    if (ct & TCG_CT_CONST) {
+        return 1;
+    }
+
+    /* Handle the modifiers.  */
+    if (ct & TCG_CT_CONST_NEG) {
+        val = -val;
+    }
+    if (ct & TCG_CT_CONST_32) {
+        val = (int32_t)val;
+    }
+
+    /* The following are mutually exclusive.  */
+    if (ct & TCG_CT_CONST_ADDI) {
+        /* Immediates that may be used with add.  If we have the
+           extended-immediates facility then we have ADD IMMEDIATE
+           with signed and unsigned 32-bit, otherwise we have only
+           ADD HALFWORD IMMEDIATE with a signed 16-bit.  */
+        if (facilities & FACILITY_EXT_IMM) {
+            return val == (int32_t)val || val == (uint32_t)val;
+        } else {
+            return val == (int16_t)val;
+        }
+    } else if (ct & TCG_CT_CONST_MULI) {
+        /* Immediates that may be used with multiply.  If we have the
+           general-instruction-extensions, then we have MULTIPLY SINGLE
+           IMMEDIATE with a signed 32-bit, otherwise we have only
+           MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit.  */
+        if (facilities & FACILITY_GEN_INST_EXT) {
+            return val == (int32_t)val;
+        } else {
+            return val == (int16_t)val;
+        }
+    } else if (ct & TCG_CT_CONST_ANDI) {
+        return tcg_match_andi(ct, val);
+    } else if (ct & TCG_CT_CONST_ORI) {
+        return tcg_match_ori(ct, val);
+    } else if (ct & TCG_CT_CONST_XORI) {
+        return tcg_match_xori(ct, val);
+    } else if (ct & TCG_CT_CONST_CMPI) {
+        return tcg_match_cmpi(ct, val);
+    }
+
+    return 0;
+}
+
+/* Emit instructions according to the given instruction format.  */
+
+static void tcg_out_insn_RR(TCGContext *s, S390Opcode op, TCGReg r1, TCGReg r2)
+{
+    tcg_out16(s, (op << 8) | (r1 << 4) | r2);
+}
+
+static void tcg_out_insn_RRE(TCGContext *s, S390Opcode op,
+                             TCGReg r1, TCGReg r2)
+{
+    tcg_out32(s, (op << 16) | (r1 << 4) | r2);
+}
+
+static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
+{
+    tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff));
+}
+
+static void tcg_out_insn_RIL(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
+{
+    tcg_out16(s, op | (r1 << 4));
+    tcg_out32(s, i2);
+}
+
+static void tcg_out_insn_RS(TCGContext *s, S390Opcode op, TCGReg r1,
+                            TCGReg b2, TCGReg r3, int disp)
+{
+    tcg_out32(s, (op << 24) | (r1 << 20) | (r3 << 16) | (b2 << 12)
+              | (disp & 0xfff));
+}
+
+static void tcg_out_insn_RSY(TCGContext *s, S390Opcode op, TCGReg r1,
+                             TCGReg b2, TCGReg r3, int disp)
+{
+    tcg_out16(s, (op & 0xff00) | (r1 << 4) | r3);
+    tcg_out32(s, (op & 0xff) | (b2 << 28)
+              | ((disp & 0xfff) << 16) | ((disp & 0xff000) >> 4));
+}
+
+#define tcg_out_insn_RX   tcg_out_insn_RS
+#define tcg_out_insn_RXY  tcg_out_insn_RSY
+
+/* Emit an opcode with "type-checking" of the format.  */
+#define tcg_out_insn(S, FMT, OP, ...) \
+    glue(tcg_out_insn_,FMT)(S, glue(glue(FMT,_),OP), ## __VA_ARGS__)
+
+
+/* emit 64-bit shifts */
+static void tcg_out_sh64(TCGContext* s, S390Opcode op, TCGReg dest,
+                         TCGReg src, TCGReg sh_reg, int sh_imm)
+{
+    tcg_out_insn_RSY(s, op, dest, sh_reg, src, sh_imm);
+}
+
+/* emit 32-bit shifts */
+static void tcg_out_sh32(TCGContext* s, S390Opcode op, TCGReg dest,
+                         TCGReg sh_reg, int sh_imm)
+{
+    tcg_out_insn_RS(s, op, dest, sh_reg, 0, sh_imm);
+}
+
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
+{
+    if (src != dst) {
+        if (type == TCG_TYPE_I32) {
+            tcg_out_insn(s, RR, LR, dst, src);
+        } else {
+            tcg_out_insn(s, RRE, LGR, dst, src);
+        }
+    }
+}
+
+/* load a register with an immediate value */
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         TCGReg ret, tcg_target_long sval)
+{
+    static const S390Opcode lli_insns[4] = {
+        RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH
+    };
+
+    tcg_target_ulong uval = sval;
+    int i;
+
+    if (type == TCG_TYPE_I32) {
+        uval = (uint32_t)sval;
+        sval = (int32_t)sval;
+    }
+
+    /* Try all 32-bit insns that can load it in one go.  */
+    if (sval >= -0x8000 && sval < 0x8000) {
+        tcg_out_insn(s, RI, LGHI, ret, sval);
+        return;
+    }
+
+    for (i = 0; i < 4; i++) {
+        tcg_target_long mask = 0xffffull << i*16;
+        if ((uval & mask) == uval) {
+            tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16);
+            return;
+        }
+    }
+
+    /* Try all 48-bit insns that can load it in one go.  */
+    if (facilities & FACILITY_EXT_IMM) {
+        if (sval == (int32_t)sval) {
+            tcg_out_insn(s, RIL, LGFI, ret, sval);
+            return;
+        }
+        if (uval <= 0xffffffff) {
+            tcg_out_insn(s, RIL, LLILF, ret, uval);
+            return;
+        }
+        if ((uval & 0xffffffff) == 0) {
+            tcg_out_insn(s, RIL, LLIHF, ret, uval >> 31 >> 1);
+            return;
+        }
+    }
+
+    /* Try for PC-relative address load.  */
+    if ((sval & 1) == 0) {
+        intptr_t off = (sval - (intptr_t)s->code_ptr) >> 1;
+        if (off == (int32_t)off) {
+            tcg_out_insn(s, RIL, LARL, ret, off);
+            return;
+        }
+    }
+
+    /* If extended immediates are not present, then we may have to issue
+       several instructions to load the low 32 bits.  */
+    if (!(facilities & FACILITY_EXT_IMM)) {
+        /* A 32-bit unsigned value can be loaded in 2 insns.  And given
+           that the lli_insns loop above did not succeed, we know that
+           both insns are required.  */
+        if (uval <= 0xffffffff) {
+            tcg_out_insn(s, RI, LLILL, ret, uval);
+            tcg_out_insn(s, RI, IILH, ret, uval >> 16);
+            return;
+        }
+
+        /* If all high bits are set, the value can be loaded in 2 or 3 insns.
+           We first want to make sure that all the high bits get set.  With
+           luck the low 16-bits can be considered negative to perform that for
+           free, otherwise we load an explicit -1.  */
+        if (sval >> 31 >> 1 == -1) {
+            if (uval & 0x8000) {
+                tcg_out_insn(s, RI, LGHI, ret, uval);
+            } else {
+                tcg_out_insn(s, RI, LGHI, ret, -1);
+                tcg_out_insn(s, RI, IILL, ret, uval);
+            }
+            tcg_out_insn(s, RI, IILH, ret, uval >> 16);
+            return;
+        }
+    }
+
+    /* If we get here, both the high and low parts have non-zero bits.  */
+
+    /* Recurse to load the lower 32-bits.  */
+    tcg_out_movi(s, TCG_TYPE_I32, ret, sval);
+
+    /* Insert data into the high 32-bits.  */
+    uval = uval >> 31 >> 1;
+    if (facilities & FACILITY_EXT_IMM) {
+        if (uval < 0x10000) {
+            tcg_out_insn(s, RI, IIHL, ret, uval);
+        } else if ((uval & 0xffff) == 0) {
+            tcg_out_insn(s, RI, IIHH, ret, uval >> 16);
+        } else {
+            tcg_out_insn(s, RIL, IIHF, ret, uval);
+        }
+    } else {
+        if (uval & 0xffff) {
+            tcg_out_insn(s, RI, IIHL, ret, uval);
+        }
+        if (uval & 0xffff0000) {
+            tcg_out_insn(s, RI, IIHH, ret, uval >> 16);
+        }
+    }
+}
+
+
+/* Emit a load/store type instruction.  Inputs are:
+   DATA:     The register to be loaded or stored.
+   BASE+OFS: The effective address.
+   OPC_RX:   If the operation has an RX format opcode (e.g. STC), otherwise 0.
+   OPC_RXY:  The RXY format opcode for the operation (e.g. STCY).  */
+
+static void tcg_out_mem(TCGContext *s, S390Opcode opc_rx, S390Opcode opc_rxy,
+                        TCGReg data, TCGReg base, TCGReg index,
+                        tcg_target_long ofs)
+{
+    if (ofs < -0x80000 || ofs >= 0x80000) {
+        /* Combine the low 16 bits of the offset with the actual load insn;
+           the high 48 bits must come from an immediate load.  */
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, ofs & ~0xffff);
+        ofs &= 0xffff;
+
+        /* If we were already given an index register, add it in.  */
+        if (index != TCG_REG_NONE) {
+            tcg_out_insn(s, RRE, AGR, TCG_TMP0, index);
+        }
+        index = TCG_TMP0;
+    }
+
+    if (opc_rx && ofs >= 0 && ofs < 0x1000) {
+        tcg_out_insn_RX(s, opc_rx, data, base, index, ofs);
+    } else {
+        tcg_out_insn_RXY(s, opc_rxy, data, base, index, ofs);
+    }
+}
+
+
+/* load data without address translation or endianness conversion */
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg data,
+                              TCGReg base, tcg_target_long ofs)
+{
+    if (type == TCG_TYPE_I32) {
+        tcg_out_mem(s, RX_L, RXY_LY, data, base, TCG_REG_NONE, ofs);
+    } else {
+        tcg_out_mem(s, 0, RXY_LG, data, base, TCG_REG_NONE, ofs);
+    }
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg data,
+                              TCGReg base, tcg_target_long ofs)
+{
+    if (type == TCG_TYPE_I32) {
+        tcg_out_mem(s, RX_ST, RXY_STY, data, base, TCG_REG_NONE, ofs);
+    } else {
+        tcg_out_mem(s, 0, RXY_STG, data, base, TCG_REG_NONE, ofs);
+    }
+}
+
+/* load data from an absolute host address */
+static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
+{
+    tcg_target_long addr = (tcg_target_long)abs;
+
+    if (facilities & FACILITY_GEN_INST_EXT) {
+        tcg_target_long disp = (addr - (tcg_target_long)s->code_ptr) >> 1;
+        if (disp == (int32_t)disp) {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RIL, LRL, dest, disp);
+            } else {
+                tcg_out_insn(s, RIL, LGRL, dest, disp);
+            }
+            return;
+        }
+    }
+
+    tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff);
+    tcg_out_ld(s, type, dest, dest, addr & 0xffff);
+}
+
+static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LGBR, dest, src);
+        return;
+    }
+
+    if (type == TCG_TYPE_I32) {
+        if (dest == src) {
+            tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 24);
+        } else {
+            tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 24);
+        }
+        tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 24);
+    } else {
+        tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 56);
+        tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 56);
+    }
+}
+
+static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LLGCR, dest, src);
+        return;
+    }
+
+    if (dest == src) {
+        tcg_out_movi(s, type, TCG_TMP0, 0xff);
+        src = TCG_TMP0;
+    } else {
+        tcg_out_movi(s, type, dest, 0xff);
+    }
+    if (type == TCG_TYPE_I32) {
+        tcg_out_insn(s, RR, NR, dest, src);
+    } else {
+        tcg_out_insn(s, RRE, NGR, dest, src);
+    }
+}
+
+static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LGHR, dest, src);
+        return;
+    }
+
+    if (type == TCG_TYPE_I32) {
+        if (dest == src) {
+            tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 16);
+        } else {
+            tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 16);
+        }
+        tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 16);
+    } else {
+        tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 48);
+        tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 48);
+    }
+}
+
+static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LLGHR, dest, src);
+        return;
+    }
+
+    if (dest == src) {
+        tcg_out_movi(s, type, TCG_TMP0, 0xffff);
+        src = TCG_TMP0;
+    } else {
+        tcg_out_movi(s, type, dest, 0xffff);
+    }
+    if (type == TCG_TYPE_I32) {
+        tcg_out_insn(s, RR, NR, dest, src);
+    } else {
+        tcg_out_insn(s, RRE, NGR, dest, src);
+    }
+}
+
+static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src)
+{
+    tcg_out_insn(s, RRE, LGFR, dest, src);
+}
+
+static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src)
+{
+    tcg_out_insn(s, RRE, LLGFR, dest, src);
+}
+
+static inline void tgen32_addi(TCGContext *s, TCGReg dest, int32_t val)
+{
+    if (val == (int16_t)val) {
+        tcg_out_insn(s, RI, AHI, dest, val);
+    } else {
+        tcg_out_insn(s, RIL, AFI, dest, val);
+    }
+}
+
+static inline void tgen64_addi(TCGContext *s, TCGReg dest, int64_t val)
+{
+    if (val == (int16_t)val) {
+        tcg_out_insn(s, RI, AGHI, dest, val);
+    } else if (val == (int32_t)val) {
+        tcg_out_insn(s, RIL, AGFI, dest, val);
+    } else if (val == (uint32_t)val) {
+        tcg_out_insn(s, RIL, ALGFI, dest, val);
+    } else {
+        tcg_abort();
+    }
+
+}
+
+static void tgen64_andi(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+    static const S390Opcode ni_insns[4] = {
+        RI_NILL, RI_NILH, RI_NIHL, RI_NIHH
+    };
+    static const S390Opcode nif_insns[2] = {
+        RIL_NILF, RIL_NIHF
+    };
+
+    int i;
+
+    /* Look for no-op.  */
+    if (val == -1) {
+        return;
+    }
+
+    /* Look for the zero-extensions.  */
+    if (val == 0xffffffff) {
+        tgen_ext32u(s, dest, dest);
+        return;
+    }
+
+    if (facilities & FACILITY_EXT_IMM) {
+        if (val == 0xff) {
+            tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
+            return;
+        }
+        if (val == 0xffff) {
+            tgen_ext16u(s, TCG_TYPE_I64, dest, dest);
+            return;
+        }
+
+        /* Try all 32-bit insns that can perform it in one go.  */
+        for (i = 0; i < 4; i++) {
+            tcg_target_ulong mask = ~(0xffffull << i*16);
+            if ((val & mask) == mask) {
+                tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16);
+                return;
+            }
+        }
+
+        /* Try all 48-bit insns that can perform it in one go.  */
+        if (facilities & FACILITY_EXT_IMM) {
+            for (i = 0; i < 2; i++) {
+                tcg_target_ulong mask = ~(0xffffffffull << i*32);
+                if ((val & mask) == mask) {
+                    tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
+                    return;
+                }
+            }
+        }
+
+        /* Perform the AND via sequential modifications to the high and low
+           parts.  Do this via recursion to handle 16-bit vs 32-bit masks in
+           each half.  */
+        tgen64_andi(s, dest, val | 0xffffffff00000000ull);
+        tgen64_andi(s, dest, val | 0x00000000ffffffffull);
+    } else {
+        /* With no extended-immediate facility, just emit the sequence.  */
+        for (i = 0; i < 4; i++) {
+            tcg_target_ulong mask = 0xffffull << i*16;
+            if ((val & mask) != mask) {
+                tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16);
+            }
+        }
+    }
+}
+
+static void tgen64_ori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+    static const S390Opcode oi_insns[4] = {
+        RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
+    };
+    static const S390Opcode nif_insns[2] = {
+        RIL_OILF, RIL_OIHF
+    };
+
+    int i;
+
+    /* Look for no-op.  */
+    if (val == 0) {
+        return;
+    }
+
+    if (facilities & FACILITY_EXT_IMM) {
+        /* Try all 32-bit insns that can perform it in one go.  */
+        for (i = 0; i < 4; i++) {
+            tcg_target_ulong mask = (0xffffull << i*16);
+            if ((val & mask) != 0 && (val & ~mask) == 0) {
+                tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
+                return;
+            }
+        }
+
+        /* Try all 48-bit insns that can perform it in one go.  */
+        for (i = 0; i < 2; i++) {
+            tcg_target_ulong mask = (0xffffffffull << i*32);
+            if ((val & mask) != 0 && (val & ~mask) == 0) {
+                tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
+                return;
+            }
+        }
+
+        /* Perform the OR via sequential modifications to the high and
+           low parts.  Do this via recursion to handle 16-bit vs 32-bit
+           masks in each half.  */
+        tgen64_ori(s, dest, val & 0x00000000ffffffffull);
+        tgen64_ori(s, dest, val & 0xffffffff00000000ull);
+    } else {
+        /* With no extended-immediate facility, we don't need to be so
+           clever.  Just iterate over the insns and mask in the constant.  */
+        for (i = 0; i < 4; i++) {
+            tcg_target_ulong mask = (0xffffull << i*16);
+            if ((val & mask) != 0) {
+                tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
+            }
+        }
+    }
+}
+
+static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+    /* Perform the xor by parts.  */
+    if (val & 0xffffffff) {
+        tcg_out_insn(s, RIL, XILF, dest, val);
+    }
+    if (val > 0xffffffff) {
+        tcg_out_insn(s, RIL, XIHF, dest, val >> 31 >> 1);
+    }
+}
+
+static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+                    TCGArg c2, int c2const)
+{
+    bool is_unsigned = (c > TCG_COND_GT);
+    if (c2const) {
+        if (c2 == 0) {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, LTR, r1, r1);
+            } else {
+                tcg_out_insn(s, RRE, LTGR, r1, r1);
+            }
+            return tcg_cond_to_ltr_cond[c];
+        } else {
+            if (is_unsigned) {
+                if (type == TCG_TYPE_I32) {
+                    tcg_out_insn(s, RIL, CLFI, r1, c2);
+                } else {
+                    tcg_out_insn(s, RIL, CLGFI, r1, c2);
+                }
+            } else {
+                if (type == TCG_TYPE_I32) {
+                    tcg_out_insn(s, RIL, CFI, r1, c2);
+                } else {
+                    tcg_out_insn(s, RIL, CGFI, r1, c2);
+                }
+            }
+        }
+    } else {
+        if (is_unsigned) {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, CLR, r1, c2);
+            } else {
+                tcg_out_insn(s, RRE, CLGR, r1, c2);
+            }
+        } else {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, CR, r1, c2);
+            } else {
+                tcg_out_insn(s, RRE, CGR, r1, c2);
+            }
+        }
+    }
+    return tcg_cond_to_s390_cond[c];
+}
+
+static void tgen_setcond(TCGContext *s, TCGType type, TCGCond c,
+                         TCGReg dest, TCGReg r1, TCGArg c2, int c2const)
+{
+    int cc = tgen_cmp(s, type, c, r1, c2, c2const);
+
+    /* Emit: r1 = 1; if (cc) goto over; r1 = 0; over:  */
+    tcg_out_movi(s, type, dest, 1);
+    tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
+    tcg_out_movi(s, type, dest, 0);
+}
+
+static void tgen_gotoi(TCGContext *s, int cc, tcg_target_long dest)
+{
+    tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
+    if (off > -0x8000 && off < 0x7fff) {
+        tcg_out_insn(s, RI, BRC, cc, off);
+    } else if (off == (int32_t)off) {
+        tcg_out_insn(s, RIL, BRCL, cc, off);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest);
+        tcg_out_insn(s, RR, BCR, cc, TCG_TMP0);
+    }
+}
+
+static void tgen_branch(TCGContext *s, int cc, int labelno)
+{
+    TCGLabel* l = &s->labels[labelno];
+    if (l->has_value) {
+        tgen_gotoi(s, cc, l->u.value);
+    } else if (USE_LONG_BRANCHES) {
+        tcg_out16(s, RIL_BRCL | (cc << 4));
+        tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, labelno, -2);
+        s->code_ptr += 4;
+    } else {
+        tcg_out16(s, RI_BRC | (cc << 4));
+        tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, labelno, -2);
+        s->code_ptr += 2;
+    }
+}
+
+static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
+                                TCGReg r1, TCGReg r2, int labelno)
+{
+    TCGLabel* l = &s->labels[labelno];
+    tcg_target_long off;
+
+    if (l->has_value) {
+        off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1;
+    } else {
+        /* We need to keep the offset unchanged for retranslation.  */
+        off = ((int16_t *)s->code_ptr)[1];
+        tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2);
+    }
+
+    tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2);
+    tcg_out16(s, off);
+    tcg_out16(s, cc << 12 | (opc & 0xff));
+}
+
+static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
+                                    TCGReg r1, int i2, int labelno)
+{
+    TCGLabel* l = &s->labels[labelno];
+    tcg_target_long off;
+
+    if (l->has_value) {
+        off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1;
+    } else {
+        /* We need to keep the offset unchanged for retranslation.  */
+        off = ((int16_t *)s->code_ptr)[1];
+        tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2);
+    }
+
+    tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc);
+    tcg_out16(s, off);
+    tcg_out16(s, (i2 << 8) | (opc & 0xff));
+}
+
+static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
+                        TCGReg r1, TCGArg c2, int c2const, int labelno)
+{
+    int cc;
+
+    if (facilities & FACILITY_GEN_INST_EXT) {
+        bool is_unsigned = (c > TCG_COND_GT);
+        bool in_range;
+        S390Opcode opc;
+
+        cc = tcg_cond_to_s390_cond[c];
+
+        if (!c2const) {
+            opc = (type == TCG_TYPE_I32
+                   ? (is_unsigned ? RIE_CLRJ : RIE_CRJ)
+                   : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ));
+            tgen_compare_branch(s, opc, cc, r1, c2, labelno);
+            return;
+        }
+
+        /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field.
+           If the immediate we've been given does not fit that range, we'll
+           fall back to separate compare and branch instructions using the
+           larger comparison range afforded by COMPARE IMMEDIATE.  */
+        if (type == TCG_TYPE_I32) {
+            if (is_unsigned) {
+                opc = RIE_CLIJ;
+                in_range = (uint32_t)c2 == (uint8_t)c2;
+            } else {
+                opc = RIE_CIJ;
+                in_range = (int32_t)c2 == (int8_t)c2;
+            }
+        } else {
+            if (is_unsigned) {
+                opc = RIE_CLGIJ;
+                in_range = (uint64_t)c2 == (uint8_t)c2;
+            } else {
+                opc = RIE_CGIJ;
+                in_range = (int64_t)c2 == (int8_t)c2;
+            }
+        }
+        if (in_range) {
+            tgen_compare_imm_branch(s, opc, cc, r1, c2, labelno);
+            return;
+        }
+    }
+
+    cc = tgen_cmp(s, type, c, r1, c2, c2const);
+    tgen_branch(s, cc, labelno);
+}
+
+static void tgen_calli(TCGContext *s, tcg_target_long dest)
+{
+    tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
+    if (off == (int32_t)off) {
+        tcg_out_insn(s, RIL, BRASL, TCG_REG_R14, off);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest);
+        tcg_out_insn(s, RR, BASR, TCG_REG_R14, TCG_TMP0);
+    }
+}
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data,
+                                   TCGReg base, TCGReg index, int disp)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 0;
+#else
+    const int bswap = 1;
+#endif
+    switch (opc) {
+    case LD_UINT8:
+        tcg_out_insn(s, RXY, LLGC, data, base, index, disp);
+        break;
+    case LD_INT8:
+        tcg_out_insn(s, RXY, LGB, data, base, index, disp);
+        break;
+    case LD_UINT16:
+        if (bswap) {
+            /* swapped unsigned halfword load with upper bits zeroed */
+            tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
+            tgen_ext16u(s, TCG_TYPE_I64, data, data);
+        } else {
+            tcg_out_insn(s, RXY, LLGH, data, base, index, disp);
+        }
+        break;
+    case LD_INT16:
+        if (bswap) {
+            /* swapped sign-extended halfword load */
+            tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
+            tgen_ext16s(s, TCG_TYPE_I64, data, data);
+        } else {
+            tcg_out_insn(s, RXY, LGH, data, base, index, disp);
+        }
+        break;
+    case LD_UINT32:
+        if (bswap) {
+            /* swapped unsigned int load with upper bits zeroed */
+            tcg_out_insn(s, RXY, LRV, data, base, index, disp);
+            tgen_ext32u(s, data, data);
+        } else {
+            tcg_out_insn(s, RXY, LLGF, data, base, index, disp);
+        }
+        break;
+    case LD_INT32:
+        if (bswap) {
+            /* swapped sign-extended int load */
+            tcg_out_insn(s, RXY, LRV, data, base, index, disp);
+            tgen_ext32s(s, data, data);
+        } else {
+            tcg_out_insn(s, RXY, LGF, data, base, index, disp);
+        }
+        break;
+    case LD_UINT64:
+        if (bswap) {
+            tcg_out_insn(s, RXY, LRVG, data, base, index, disp);
+        } else {
+            tcg_out_insn(s, RXY, LG, data, base, index, disp);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data,
+                                   TCGReg base, TCGReg index, int disp)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    const int bswap = 0;
+#else
+    const int bswap = 1;
+#endif
+    switch (opc) {
+    case LD_UINT8:
+        if (disp >= 0 && disp < 0x1000) {
+            tcg_out_insn(s, RX, STC, data, base, index, disp);
+        } else {
+            tcg_out_insn(s, RXY, STCY, data, base, index, disp);
+        }
+        break;
+    case LD_UINT16:
+        if (bswap) {
+            tcg_out_insn(s, RXY, STRVH, data, base, index, disp);
+        } else if (disp >= 0 && disp < 0x1000) {
+            tcg_out_insn(s, RX, STH, data, base, index, disp);
+        } else {
+            tcg_out_insn(s, RXY, STHY, data, base, index, disp);
+        }
+        break;
+    case LD_UINT32:
+        if (bswap) {
+            tcg_out_insn(s, RXY, STRV, data, base, index, disp);
+        } else if (disp >= 0 && disp < 0x1000) {
+            tcg_out_insn(s, RX, ST, data, base, index, disp);
+        } else {
+            tcg_out_insn(s, RXY, STY, data, base, index, disp);
+        }
+        break;
+    case LD_UINT64:
+        if (bswap) {
+            tcg_out_insn(s, RXY, STRVG, data, base, index, disp);
+        } else {
+            tcg_out_insn(s, RXY, STG, data, base, index, disp);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+#if defined(CONFIG_SOFTMMU)
+static void tgen64_andi_tmp(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+    if (tcg_match_andi(0, val)) {
+        tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, val);
+        tcg_out_insn(s, RRE, NGR, dest, TCG_TMP0);
+    } else {
+        tgen64_andi(s, dest, val);
+    }
+}
+
+static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
+                                  TCGReg addr_reg, int mem_index, int opc,
+                                  uint16_t **label2_ptr_p, int is_store)
+{
+    const TCGReg arg0 = TCG_REG_R2;
+    const TCGReg arg1 = TCG_REG_R3;
+    int s_bits = opc & 3;
+    uint16_t *label1_ptr;
+    tcg_target_long ofs;
+
+    if (TARGET_LONG_BITS == 32) {
+        tgen_ext32u(s, arg0, addr_reg);
+    } else {
+        tcg_out_mov(s, TCG_TYPE_I64, arg0, addr_reg);
+    }
+
+    tcg_out_sh64(s, RSY_SRLG, arg1, addr_reg, TCG_REG_NONE,
+                 TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+
+    tgen64_andi_tmp(s, arg0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tgen64_andi_tmp(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+    if (is_store) {
+        ofs = offsetof(CPUState, tlb_table[mem_index][0].addr_write);
+    } else {
+        ofs = offsetof(CPUState, tlb_table[mem_index][0].addr_read);
+    }
+    assert(ofs < 0x80000);
+
+    if (TARGET_LONG_BITS == 32) {
+        tcg_out_mem(s, RX_C, RXY_CY, arg0, arg1, TCG_AREG0, ofs);
+    } else {
+        tcg_out_mem(s, 0, RXY_CG, arg0, arg1, TCG_AREG0, ofs);
+    }
+
+    if (TARGET_LONG_BITS == 32) {
+        tgen_ext32u(s, arg0, addr_reg);
+    } else {
+        tcg_out_mov(s, TCG_TYPE_I64, arg0, addr_reg);
+    }
+
+    label1_ptr = (uint16_t*)s->code_ptr;
+
+    /* je label1 (offset will be patched in later) */
+    tcg_out_insn(s, RI, BRC, S390_CC_EQ, 0);
+
+    /* call load/store helper */
+    if (is_store) {
+        /* Make sure to zero-extend the value to the full register
+           for the calling convention.  */
+        switch (opc) {
+        case LD_UINT8:
+            tgen_ext8u(s, TCG_TYPE_I64, arg1, data_reg);
+            break;
+        case LD_UINT16:
+            tgen_ext16u(s, TCG_TYPE_I64, arg1, data_reg);
+            break;
+        case LD_UINT32:
+            tgen_ext32u(s, arg1, data_reg);
+            break;
+        case LD_UINT64:
+            tcg_out_mov(s, TCG_TYPE_I64, arg1, data_reg);
+            break;
+        default:
+            tcg_abort();
+        }
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index);
+        tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+        tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]);
+
+        /* sign extension */
+        switch (opc) {
+        case LD_INT8:
+            tgen_ext8s(s, TCG_TYPE_I64, data_reg, arg0);
+            break;
+        case LD_INT16:
+            tgen_ext16s(s, TCG_TYPE_I64, data_reg, arg0);
+            break;
+        case LD_INT32:
+            tgen_ext32s(s, data_reg, arg0);
+            break;
+        default:
+            /* unsigned -> just copy */
+            tcg_out_mov(s, TCG_TYPE_I64, data_reg, arg0);
+            break;
+        }
+    }
+
+    /* jump to label2 (end) */
+    *label2_ptr_p = (uint16_t*)s->code_ptr;
+
+    tcg_out_insn(s, RI, BRC, S390_CC_ALWAYS, 0);
+
+    /* this is label1, patch branch */
+    *(label1_ptr + 1) = ((unsigned long)s->code_ptr -
+                         (unsigned long)label1_ptr) >> 1;
+
+    ofs = offsetof(CPUState, tlb_table[mem_index][0].addend);
+    assert(ofs < 0x80000);
+
+    tcg_out_mem(s, 0, RXY_AG, arg0, arg1, TCG_AREG0, ofs);
+}
+
+static void tcg_finish_qemu_ldst(TCGContext* s, uint16_t *label2_ptr)
+{
+    /* patch branch */
+    *(label2_ptr + 1) = ((unsigned long)s->code_ptr -
+                         (unsigned long)label2_ptr) >> 1;
+}
+#else
+static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg,
+                                  TCGReg *index_reg, tcg_target_long *disp)
+{
+    if (TARGET_LONG_BITS == 32) {
+        tgen_ext32u(s, TCG_TMP0, *addr_reg);
+        *addr_reg = TCG_TMP0;
+    }
+    if (GUEST_BASE < 0x80000) {
+        *index_reg = TCG_REG_NONE;
+        *disp = GUEST_BASE;
+    } else {
+        *index_reg = TCG_GUEST_BASE_REG;
+        *disp = 0;
+    }
+}
+#endif /* CONFIG_SOFTMMU */
+
+/* load data with address translation (if applicable)
+   and endianness conversion */
+static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc)
+{
+    TCGReg addr_reg, data_reg;
+#if defined(CONFIG_SOFTMMU)
+    int mem_index;
+    uint16_t *label2_ptr;
+#else
+    TCGReg index_reg;
+    tcg_target_long disp;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+    mem_index = *args;
+
+    tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index,
+                          opc, &label2_ptr, 0);
+
+    tcg_out_qemu_ld_direct(s, opc, data_reg, TCG_REG_R2, TCG_REG_NONE, 0);
+
+    tcg_finish_qemu_ldst(s, label2_ptr);
+#else
+    tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
+    tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, index_reg, disp);
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc)
+{
+    TCGReg addr_reg, data_reg;
+#if defined(CONFIG_SOFTMMU)
+    int mem_index;
+    uint16_t *label2_ptr;
+#else
+    TCGReg index_reg;
+    tcg_target_long disp;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+    mem_index = *args;
+
+    tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index,
+                          opc, &label2_ptr, 1);
+
+    tcg_out_qemu_st_direct(s, opc, data_reg, TCG_REG_R2, TCG_REG_NONE, 0);
+
+    tcg_finish_qemu_ldst(s, label2_ptr);
+#else
+    tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
+    tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, index_reg, disp);
+#endif
+}
+
+#if TCG_TARGET_REG_BITS == 64
+# define OP_32_64(x) \
+        case glue(glue(INDEX_op_,x),_i32): \
+        case glue(glue(INDEX_op_,x),_i64)
+#else
+# define OP_32_64(x) \
+        case glue(glue(INDEX_op_,x),_i32)
+#endif
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+                const TCGArg *args, const int *const_args)
+{
+    S390Opcode op;
+
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        /* return value */
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]);
+        tgen_gotoi(s, S390_CC_ALWAYS, (unsigned long)tb_ret_addr);
+        break;
+
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            tcg_abort();
+        } else {
+            /* load address stored at s->tb_next + args[0] */
+            tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_TMP0, s->tb_next + args[0]);
+            /* and go there */
+            tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_TMP0);
+        }
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+
+    case INDEX_op_call:
+        if (const_args[0]) {
+            tgen_calli(s, args[0]);
+        } else {
+            tcg_out_insn(s, RR, BASR, TCG_REG_R14, args[0]);
+        }
+        break;
+
+    case INDEX_op_mov_i32:
+        tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+
+    OP_32_64(ld8u):
+        /* ??? LLC (RXY format) is only present with the extended-immediate
+           facility, whereas LLGC is always present.  */
+        tcg_out_mem(s, 0, RXY_LLGC, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+
+    OP_32_64(ld8s):
+        /* ??? LB is no smaller than LGB, so no point to using it.  */
+        tcg_out_mem(s, 0, RXY_LGB, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+
+    OP_32_64(ld16u):
+        /* ??? LLH (RXY format) is only present with the extended-immediate
+           facility, whereas LLGH is always present.  */
+        tcg_out_mem(s, 0, RXY_LLGH, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+
+    case INDEX_op_ld16s_i32:
+        tcg_out_mem(s, RX_LH, RXY_LHY, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+
+    case INDEX_op_ld_i32:
+        tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+        break;
+
+    OP_32_64(st8):
+        tcg_out_mem(s, RX_STC, RXY_STCY, args[0], args[1],
+                    TCG_REG_NONE, args[2]);
+        break;
+
+    OP_32_64(st16):
+        tcg_out_mem(s, RX_STH, RXY_STHY, args[0], args[1],
+                    TCG_REG_NONE, args[2]);
+        break;
+
+    case INDEX_op_st_i32:
+        tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2]) {
+            tgen32_addi(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RR, AR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_sub_i32:
+        if (const_args[2]) {
+            tgen32_addi(s, args[0], -args[2]);
+        } else {
+            tcg_out_insn(s, RR, SR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            tgen64_andi(s, args[0], args[2] | 0xffffffff00000000ull);
+        } else {
+            tcg_out_insn(s, RR, NR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            tgen64_ori(s, args[0], args[2] & 0xffffffff);
+        } else {
+            tcg_out_insn(s, RR, OR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_xor_i32:
+        if (const_args[2]) {
+            tgen64_xori(s, args[0], args[2] & 0xffffffff);
+        } else {
+            tcg_out_insn(s, RR, XR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_neg_i32:
+        tcg_out_insn(s, RR, LCR, args[0], args[1]);
+        break;
+
+    case INDEX_op_mul_i32:
+        if (const_args[2]) {
+            if ((int32_t)args[2] == (int16_t)args[2]) {
+                tcg_out_insn(s, RI, MHI, args[0], args[2]);
+            } else {
+                tcg_out_insn(s, RIL, MSFI, args[0], args[2]);
+            }
+        } else {
+            tcg_out_insn(s, RRE, MSR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_div2_i32:
+        tcg_out_insn(s, RR, DR, TCG_REG_R2, args[4]);
+        break;
+    case INDEX_op_divu2_i32:
+        tcg_out_insn(s, RRE, DLR, TCG_REG_R2, args[4]);
+        break;
+
+    case INDEX_op_shl_i32:
+        op = RS_SLL;
+    do_shift32:
+        if (const_args[2]) {
+            tcg_out_sh32(s, op, args[0], TCG_REG_NONE, args[2]);
+        } else {
+            tcg_out_sh32(s, op, args[0], args[2], 0);
+        }
+        break;
+    case INDEX_op_shr_i32:
+        op = RS_SRL;
+        goto do_shift32;
+    case INDEX_op_sar_i32:
+        op = RS_SRA;
+        goto do_shift32;
+
+    case INDEX_op_rotl_i32:
+        /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol.  */
+        if (const_args[2]) {
+            tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_REG_NONE, args[2]);
+        } else {
+            tcg_out_sh64(s, RSY_RLL, args[0], args[1], args[2], 0);
+        }
+        break;
+    case INDEX_op_rotr_i32:
+        if (const_args[2]) {
+            tcg_out_sh64(s, RSY_RLL, args[0], args[1],
+                         TCG_REG_NONE, (32 - args[2]) & 31);
+        } else {
+            tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
+            tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_TMP0, 0);
+        }
+        break;
+
+    case INDEX_op_ext8s_i32:
+        tgen_ext8s(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+        tgen_ext16s(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_ext8u_i32:
+        tgen_ext8u(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+    case INDEX_op_ext16u_i32:
+        tgen_ext16u(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+
+    OP_32_64(bswap16):
+        /* The TCG bswap definition requires bits 0-47 already be zero.
+           Thus we don't need the G-type insns to implement bswap16_i64.  */
+        tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
+        tcg_out_sh32(s, RS_SRL, args[0], TCG_REG_NONE, 16);
+        break;
+    OP_32_64(bswap32):
+        tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
+        break;
+
+    case INDEX_op_br:
+        tgen_branch(s, S390_CC_ALWAYS, args[0]);
+        break;
+
+    case INDEX_op_brcond_i32:
+        tgen_brcond(s, TCG_TYPE_I32, args[2], args[0],
+                    args[1], const_args[1], args[3]);
+        break;
+    case INDEX_op_setcond_i32:
+        tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1],
+                     args[2], const_args[2]);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, LD_UINT8);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, LD_INT8);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, LD_UINT16);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, LD_INT16);
+        break;
+    case INDEX_op_qemu_ld32:
+        /* ??? Technically we can use a non-extending instruction.  */
+        tcg_out_qemu_ld(s, args, LD_UINT32);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, LD_UINT64);
+        break;
+
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, LD_UINT8);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, LD_UINT16);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, LD_UINT32);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, LD_UINT64);
+        break;
+
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_mov_i64:
+        tcg_out_mov(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i64:
+        tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+
+    case INDEX_op_ld16s_i64:
+        tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+    case INDEX_op_ld32u_i64:
+        tcg_out_mem(s, 0, RXY_LLGF, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+    case INDEX_op_ld32s_i64:
+        tcg_out_mem(s, 0, RXY_LGF, args[0], args[1], TCG_REG_NONE, args[2]);
+        break;
+    case INDEX_op_ld_i64:
+        tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_st32_i64:
+        tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i64:
+        tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_add_i64:
+        if (const_args[2]) {
+            tgen64_addi(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RRE, AGR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_sub_i64:
+        if (const_args[2]) {
+            tgen64_addi(s, args[0], -args[2]);
+        } else {
+            tcg_out_insn(s, RRE, SGR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_and_i64:
+        if (const_args[2]) {
+            tgen64_andi(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RRE, NGR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_or_i64:
+        if (const_args[2]) {
+            tgen64_ori(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RRE, OGR, args[0], args[2]);
+        }
+        break;
+    case INDEX_op_xor_i64:
+        if (const_args[2]) {
+            tgen64_xori(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RRE, XGR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_neg_i64:
+        tcg_out_insn(s, RRE, LCGR, args[0], args[1]);
+        break;
+    case INDEX_op_bswap64_i64:
+        tcg_out_insn(s, RRE, LRVGR, args[0], args[1]);
+        break;
+
+    case INDEX_op_mul_i64:
+        if (const_args[2]) {
+            if (args[2] == (int16_t)args[2]) {
+                tcg_out_insn(s, RI, MGHI, args[0], args[2]);
+            } else {
+                tcg_out_insn(s, RIL, MSGFI, args[0], args[2]);
+            }
+        } else {
+            tcg_out_insn(s, RRE, MSGR, args[0], args[2]);
+        }
+        break;
+
+    case INDEX_op_div2_i64:
+        /* ??? We get an unnecessary sign-extension of the dividend
+           into R3 with this definition, but as we do in fact always
+           produce both quotient and remainder using INDEX_op_div_i64
+           instead requires jumping through even more hoops.  */
+        tcg_out_insn(s, RRE, DSGR, TCG_REG_R2, args[4]);
+        break;
+    case INDEX_op_divu2_i64:
+        tcg_out_insn(s, RRE, DLGR, TCG_REG_R2, args[4]);
+        break;
+
+    case INDEX_op_shl_i64:
+        op = RSY_SLLG;
+    do_shift64:
+        if (const_args[2]) {
+            tcg_out_sh64(s, op, args[0], args[1], TCG_REG_NONE, args[2]);
+        } else {
+            tcg_out_sh64(s, op, args[0], args[1], args[2], 0);
+        }
+        break;
+    case INDEX_op_shr_i64:
+        op = RSY_SRLG;
+        goto do_shift64;
+    case INDEX_op_sar_i64:
+        op = RSY_SRAG;
+        goto do_shift64;
+
+    case INDEX_op_rotl_i64:
+        if (const_args[2]) {
+            tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
+                         TCG_REG_NONE, args[2]);
+        } else {
+            tcg_out_sh64(s, RSY_RLLG, args[0], args[1], args[2], 0);
+        }
+        break;
+    case INDEX_op_rotr_i64:
+        if (const_args[2]) {
+            tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
+                         TCG_REG_NONE, (64 - args[2]) & 63);
+        } else {
+            /* We can use the smaller 32-bit negate because only the
+               low 6 bits are examined for the rotate.  */
+            tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
+            tcg_out_sh64(s, RSY_RLLG, args[0], args[1], TCG_TMP0, 0);
+        }
+        break;
+
+    case INDEX_op_ext8s_i64:
+        tgen_ext8s(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i64:
+        tgen_ext16s(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ext32s_i64:
+        tgen_ext32s(s, args[0], args[1]);
+        break;
+    case INDEX_op_ext8u_i64:
+        tgen_ext8u(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ext16u_i64:
+        tgen_ext16u(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ext32u_i64:
+        tgen_ext32u(s, args[0], args[1]);
+        break;
+
+    case INDEX_op_brcond_i64:
+        tgen_brcond(s, TCG_TYPE_I64, args[2], args[0],
+                    args[1], const_args[1], args[3]);
+        break;
+    case INDEX_op_setcond_i64:
+        tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1],
+                     args[2], const_args[2]);
+        break;
+
+    case INDEX_op_qemu_ld32u:
+        tcg_out_qemu_ld(s, args, LD_UINT32);
+        break;
+    case INDEX_op_qemu_ld32s:
+        tcg_out_qemu_ld(s, args, LD_INT32);
+        break;
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+    case INDEX_op_jmp:
+        /* This one is obsolete and never emitted.  */
+        tcg_abort();
+        break;
+
+    default:
+        fprintf(stderr,"unimplemented opc 0x%x\n",opc);
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef s390_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "r", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+
+    { INDEX_op_add_i32, { "r", "0", "rWI" } },
+    { INDEX_op_sub_i32, { "r", "0", "rWNI" } },
+    { INDEX_op_mul_i32, { "r", "0", "rK" } },
+
+    { INDEX_op_div2_i32, { "b", "a", "0", "1", "r" } },
+    { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } },
+
+    { INDEX_op_and_i32, { "r", "0", "rWA" } },
+    { INDEX_op_or_i32, { "r", "0", "rWO" } },
+    { INDEX_op_xor_i32, { "r", "0", "rWX" } },
+
+    { INDEX_op_neg_i32, { "r", "r" } },
+
+    { INDEX_op_shl_i32, { "r", "0", "Ri" } },
+    { INDEX_op_shr_i32, { "r", "0", "Ri" } },
+    { INDEX_op_sar_i32, { "r", "0", "Ri" } },
+
+    { INDEX_op_rotl_i32, { "r", "r", "Ri" } },
+    { INDEX_op_rotr_i32, { "r", "r", "Ri" } },
+
+    { INDEX_op_ext8s_i32, { "r", "r" } },
+    { INDEX_op_ext8u_i32, { "r", "r" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+    { INDEX_op_ext16u_i32, { "r", "r" } },
+
+    { INDEX_op_bswap16_i32, { "r", "r" } },
+    { INDEX_op_bswap32_i32, { "r", "r" } },
+
+    { INDEX_op_brcond_i32, { "r", "rWC" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rWC" } },
+
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+    { INDEX_op_qemu_ld64, { "r", "L" } },
+
+    { INDEX_op_qemu_st8, { "L", "L" } },
+    { INDEX_op_qemu_st16, { "L", "L" } },
+    { INDEX_op_qemu_st32, { "L", "L" } },
+    { INDEX_op_qemu_st64, { "L", "L" } },
+
+#if defined(__s390x__)
+    { INDEX_op_mov_i64, { "r", "r" } },
+    { INDEX_op_movi_i64, { "r" } },
+
+    { INDEX_op_ld8u_i64, { "r", "r" } },
+    { INDEX_op_ld8s_i64, { "r", "r" } },
+    { INDEX_op_ld16u_i64, { "r", "r" } },
+    { INDEX_op_ld16s_i64, { "r", "r" } },
+    { INDEX_op_ld32u_i64, { "r", "r" } },
+    { INDEX_op_ld32s_i64, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+
+    { INDEX_op_st8_i64, { "r", "r" } },
+    { INDEX_op_st16_i64, { "r", "r" } },
+    { INDEX_op_st32_i64, { "r", "r" } },
+    { INDEX_op_st_i64, { "r", "r" } },
+
+    { INDEX_op_add_i64, { "r", "0", "rI" } },
+    { INDEX_op_sub_i64, { "r", "0", "rNI" } },
+    { INDEX_op_mul_i64, { "r", "0", "rK" } },
+
+    { INDEX_op_div2_i64, { "b", "a", "0", "1", "r" } },
+    { INDEX_op_divu2_i64, { "b", "a", "0", "1", "r" } },
+
+    { INDEX_op_and_i64, { "r", "0", "rA" } },
+    { INDEX_op_or_i64, { "r", "0", "rO" } },
+    { INDEX_op_xor_i64, { "r", "0", "rX" } },
+
+    { INDEX_op_neg_i64, { "r", "r" } },
+
+    { INDEX_op_shl_i64, { "r", "r", "Ri" } },
+    { INDEX_op_shr_i64, { "r", "r", "Ri" } },
+    { INDEX_op_sar_i64, { "r", "r", "Ri" } },
+
+    { INDEX_op_rotl_i64, { "r", "r", "Ri" } },
+    { INDEX_op_rotr_i64, { "r", "r", "Ri" } },
+
+    { INDEX_op_ext8s_i64, { "r", "r" } },
+    { INDEX_op_ext8u_i64, { "r", "r" } },
+    { INDEX_op_ext16s_i64, { "r", "r" } },
+    { INDEX_op_ext16u_i64, { "r", "r" } },
+    { INDEX_op_ext32s_i64, { "r", "r" } },
+    { INDEX_op_ext32u_i64, { "r", "r" } },
+
+    { INDEX_op_bswap16_i64, { "r", "r" } },
+    { INDEX_op_bswap32_i64, { "r", "r" } },
+    { INDEX_op_bswap64_i64, { "r", "r" } },
+
+    { INDEX_op_brcond_i64, { "r", "rC" } },
+    { INDEX_op_setcond_i64, { "r", "r", "rC" } },
+
+    { INDEX_op_qemu_ld32u, { "r", "L" } },
+    { INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
+
+    { -1 },
+};
+
+/* ??? Linux kernels provide an AUXV entry AT_HWCAP that provides most of
+   this information.  However, getting at that entry is not easy this far
+   away from main.  Our options are: start searching from environ, but
+   that fails as soon as someone does a setenv in between.  Read the data
+   from /proc/self/auxv.  Or do the probing ourselves.  The only thing
+   extra that AT_HWCAP gives us is HWCAP_S390_HIGH_GPRS, which indicates
+   that the kernel saves all 64-bits of the registers around traps while
+   in 31-bit mode.  But this is true of all "recent" kernels (ought to dig
+   back and see from when this might not be true).  */
+
+#include <signal.h>
+
+static volatile sig_atomic_t got_sigill;
+
+static void sigill_handler(int sig)
+{
+    got_sigill = 1;
+}
+
+static void query_facilities(void)
+{
+    struct sigaction sa_old, sa_new;
+    register int r0 __asm__("0");
+    register void *r1 __asm__("1");
+    int fail;
+
+    memset(&sa_new, 0, sizeof(sa_new));
+    sa_new.sa_handler = sigill_handler;
+    sigaction(SIGILL, &sa_new, &sa_old);
+
+    /* First, try STORE FACILITY LIST EXTENDED.  If this is present, then
+       we need not do any more probing.  Unfortunately, this itself is an
+       extension and the original STORE FACILITY LIST instruction is
+       kernel-only, storing its results at absolute address 200.  */
+    /* stfle 0(%r1) */
+    r1 = &facilities;
+    asm volatile(".word 0xb2b0,0x1000"
+                 : "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
+
+    if (got_sigill) {
+        /* STORE FACILITY EXTENDED is not available.  Probe for one of each
+           kind of instruction that we're interested in.  */
+        /* ??? Possibly some of these are in practice never present unless
+           the store-facility-extended facility is also present.  But since
+           that isn't documented it's just better to probe for each.  */
+
+        /* Test for z/Architecture.  Required even in 31-bit mode.  */
+        got_sigill = 0;
+        /* agr %r0,%r0 */
+        asm volatile(".word 0xb908,0x0000" : "=r"(r0) : : "cc");
+        if (!got_sigill) {
+            facilities |= FACILITY_ZARCH_ACTIVE;
+        }
+
+        /* Test for long displacement.  */
+        got_sigill = 0;
+        /* ly %r0,0(%r1) */
+        r1 = &facilities;
+        asm volatile(".word 0xe300,0x1000,0x0058"
+                     : "=r"(r0) : "r"(r1) : "cc");
+        if (!got_sigill) {
+            facilities |= FACILITY_LONG_DISP;
+        }
+
+        /* Test for extended immediates.  */
+        got_sigill = 0;
+        /* afi %r0,0 */
+        asm volatile(".word 0xc209,0x0000,0x0000" : : : "cc");
+        if (!got_sigill) {
+            facilities |= FACILITY_EXT_IMM;
+        }
+
+        /* Test for general-instructions-extension.  */
+        got_sigill = 0;
+        /* msfi %r0,1 */
+        asm volatile(".word 0xc201,0x0000,0x0001");
+        if (!got_sigill) {
+            facilities |= FACILITY_GEN_INST_EXT;
+        }
+    }
+
+    sigaction(SIGILL, &sa_old, NULL);
+
+    /* The translator currently uses these extensions unconditionally.
+       Pruning this back to the base ESA/390 architecture doesn't seem
+       worthwhile, since even the KVM target requires z/Arch.  */
+    fail = 0;
+    if ((facilities & FACILITY_ZARCH_ACTIVE) == 0) {
+        fprintf(stderr, "TCG: z/Arch facility is required.\n");
+        fprintf(stderr, "TCG: Boot with a 64-bit enabled kernel.\n");
+        fail = 1;
+    }
+    if ((facilities & FACILITY_LONG_DISP) == 0) {
+        fprintf(stderr, "TCG: long-displacement facility is required.\n");
+        fail = 1;
+    }
+
+    /* So far there's just enough support for 31-bit mode to let the
+       compile succeed.  This is good enough to run QEMU with KVM.  */
+    if (sizeof(void *) != 8) {
+        fprintf(stderr, "TCG: 31-bit mode is not supported.\n");
+        fail = 1;
+    }
+
+    if (fail) {
+        exit(-1);
+    }
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* fail safe */
+    if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) {
+        tcg_abort();
+    }
+#endif
+
+    query_facilities();
+
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
+
+    tcg_regset_clear(tcg_target_call_clobber_regs);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R1);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R4);
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R5);
+    /* The return register can be considered call-clobbered.  */
+    tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_TMP0);
+    /* XXX many insns can't be used with R0, so we better avoid it for now */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+
+    tcg_add_target_add_op_defs(s390_op_defs);
+    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+}
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    /* stmg %r6,%r15,48(%r15) (save registers) */
+    tcg_out_insn(s, RXY, STMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 48);
+
+    /* aghi %r15,-160 (stack frame) */
+    tcg_out_insn(s, RI, AGHI, TCG_REG_R15, -160);
+
+    if (GUEST_BASE >= 0x80000) {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
+        tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+    }
+
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+    /* br %r3 (go to TB) */
+    tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]);
+
+    tb_ret_addr = s->code_ptr;
+
+    /* lmg %r6,%r15,208(%r15) (restore registers) */
+    tcg_out_insn(s, RXY, LMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 208);
+
+    /* br %r14 (return) */
+    tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    tcg_abort();
+}
diff --git a/qemu-0.15.x/tcg/s390/tcg-target.h b/qemu-0.15.x/tcg/s390/tcg-target.h
new file mode 100644
index 0000000..4e45cf3
--- /dev/null
+++ b/qemu-0.15.x/tcg/s390/tcg-target.h
@@ -0,0 +1,109 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009 Ulrich Hecht <uli at suse.de>
+ *
+ * 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.
+ */
+#define TCG_TARGET_S390 1
+
+#ifdef __s390x__
+#define TCG_TARGET_REG_BITS 64
+#else
+#define TCG_TARGET_REG_BITS 32
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+typedef enum TCGReg {
+    TCG_REG_R0 = 0,
+    TCG_REG_R1,
+    TCG_REG_R2,
+    TCG_REG_R3,
+    TCG_REG_R4,
+    TCG_REG_R5,
+    TCG_REG_R6,
+    TCG_REG_R7,
+    TCG_REG_R8,
+    TCG_REG_R9,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    TCG_REG_R14,
+    TCG_REG_R15
+} TCGReg;
+
+#define TCG_TARGET_NB_REGS 16
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div2_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div2_i64
+#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+// #define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_neg_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK		TCG_REG_R15
+#define TCG_TARGET_STACK_ALIGN		8
+#define TCG_TARGET_CALL_STACK_OFFSET	0
+
+#define TCG_TARGET_EXTEND_ARGS 1
+
+enum {
+    /* Note: must be synced with dyngen-exec.h */
+    TCG_AREG0 = TCG_REG_R10,
+};
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/qemu-0.15.x/tcg/sparc/tcg-target.c b/qemu-0.15.x/tcg/sparc/tcg-target.c
new file mode 100644
index 0000000..ac76e11
--- /dev/null
+++ b/qemu-0.15.x/tcg/sparc/tcg-target.c
@@ -0,0 +1,1572 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "%g0",
+    "%g1",
+    "%g2",
+    "%g3",
+    "%g4",
+    "%g5",
+    "%g6",
+    "%g7",
+    "%o0",
+    "%o1",
+    "%o2",
+    "%o3",
+    "%o4",
+    "%o5",
+    "%o6",
+    "%o7",
+    "%l0",
+    "%l1",
+    "%l2",
+    "%l3",
+    "%l4",
+    "%l5",
+    "%l6",
+    "%l7",
+    "%i0",
+    "%i1",
+    "%i2",
+    "%i3",
+    "%i4",
+    "%i5",
+    "%i6",
+    "%i7",
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_L0,
+    TCG_REG_L1,
+    TCG_REG_L2,
+    TCG_REG_L3,
+    TCG_REG_L4,
+    TCG_REG_L5,
+    TCG_REG_L6,
+    TCG_REG_L7,
+    TCG_REG_I0,
+    TCG_REG_I1,
+    TCG_REG_I2,
+    TCG_REG_I3,
+    TCG_REG_I4,
+};
+
+static const int tcg_target_call_iarg_regs[6] = {
+    TCG_REG_O0,
+    TCG_REG_O1,
+    TCG_REG_O2,
+    TCG_REG_O3,
+    TCG_REG_O4,
+    TCG_REG_O5,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_O0,
+    TCG_REG_O1,
+};
+
+static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
+{
+    return (val << ((sizeof(tcg_target_long) * 8 - bits))
+            >> (sizeof(tcg_target_long) * 8 - bits)) == val;
+}
+
+static inline int check_fit_i32(uint32_t val, unsigned int bits)
+{
+    return ((val << (32 - bits)) >> (32 - bits)) == val;
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch (type) {
+    case R_SPARC_32:
+        if (value != (uint32_t)value)
+            tcg_abort();
+        *(uint32_t *)code_ptr = value;
+        break;
+    case R_SPARC_WDISP22:
+        value -= (long)code_ptr;
+        value >>= 2;
+        if (!check_fit_tl(value, 22))
+            tcg_abort();
+        *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value;
+        break;
+    case R_SPARC_WDISP19:
+        value -= (long)code_ptr;
+        value >>= 2;
+        if (!check_fit_tl(value, 19))
+            tcg_abort();
+        *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value;
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 6;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch (ct_str[0]) {
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        break;
+    case 'L': /* qemu_ld/st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+        // Helper args
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2);
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_S11;
+        break;
+    case 'J':
+        ct->ct |= TCG_CT_CONST_S13;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+                                         const TCGArgConstraint *arg_ct)
+{
+    int ct;
+
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11))
+        return 1;
+    else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13))
+        return 1;
+    else
+        return 0;
+}
+
+#define INSN_OP(x)  ((x) << 30)
+#define INSN_OP2(x) ((x) << 22)
+#define INSN_OP3(x) ((x) << 19)
+#define INSN_OPF(x) ((x) << 5)
+#define INSN_RD(x)  ((x) << 25)
+#define INSN_RS1(x) ((x) << 14)
+#define INSN_RS2(x) (x)
+#define INSN_ASI(x) ((x) << 5)
+
+#define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff))
+#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
+#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
+#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
+
+#define INSN_COND(x, a) (((x) << 25) | ((a) << 29))
+#define COND_N     0x0
+#define COND_E     0x1
+#define COND_LE    0x2
+#define COND_L     0x3
+#define COND_LEU   0x4
+#define COND_CS    0x5
+#define COND_NEG   0x6
+#define COND_VS    0x7
+#define COND_A     0x8
+#define COND_NE    0x9
+#define COND_G     0xa
+#define COND_GE    0xb
+#define COND_GU    0xc
+#define COND_CC    0xd
+#define COND_POS   0xe
+#define COND_VC    0xf
+#define BA         (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2))
+
+#define MOVCC_ICC  (1 << 18)
+#define MOVCC_XCC  (1 << 18 | 1 << 12)
+
+#define ARITH_ADD  (INSN_OP(2) | INSN_OP3(0x00))
+#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
+#define ARITH_AND  (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
+#define ARITH_OR   (INSN_OP(2) | INSN_OP3(0x02))
+#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
+#define ARITH_ORN  (INSN_OP(2) | INSN_OP3(0x06))
+#define ARITH_XOR  (INSN_OP(2) | INSN_OP3(0x03))
+#define ARITH_SUB  (INSN_OP(2) | INSN_OP3(0x04))
+#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14))
+#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10))
+#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c))
+#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a))
+#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e))
+#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f))
+#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
+#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d))
+#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d))
+#define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c))
+
+#define SHIFT_SLL  (INSN_OP(2) | INSN_OP3(0x25))
+#define SHIFT_SRL  (INSN_OP(2) | INSN_OP3(0x26))
+#define SHIFT_SRA  (INSN_OP(2) | INSN_OP3(0x27))
+
+#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12))
+#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12))
+#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12))
+
+#define RDY        (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0))
+#define WRY        (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0))
+#define JMPL       (INSN_OP(2) | INSN_OP3(0x38))
+#define SAVE       (INSN_OP(2) | INSN_OP3(0x3c))
+#define RESTORE    (INSN_OP(2) | INSN_OP3(0x3d))
+#define SETHI      (INSN_OP(0) | INSN_OP2(0x4))
+#define CALL       INSN_OP(1)
+#define LDUB       (INSN_OP(3) | INSN_OP3(0x01))
+#define LDSB       (INSN_OP(3) | INSN_OP3(0x09))
+#define LDUH       (INSN_OP(3) | INSN_OP3(0x02))
+#define LDSH       (INSN_OP(3) | INSN_OP3(0x0a))
+#define LDUW       (INSN_OP(3) | INSN_OP3(0x00))
+#define LDSW       (INSN_OP(3) | INSN_OP3(0x08))
+#define LDX        (INSN_OP(3) | INSN_OP3(0x0b))
+#define STB        (INSN_OP(3) | INSN_OP3(0x05))
+#define STH        (INSN_OP(3) | INSN_OP3(0x06))
+#define STW        (INSN_OP(3) | INSN_OP3(0x04))
+#define STX        (INSN_OP(3) | INSN_OP3(0x0e))
+#define LDUBA      (INSN_OP(3) | INSN_OP3(0x11))
+#define LDSBA      (INSN_OP(3) | INSN_OP3(0x19))
+#define LDUHA      (INSN_OP(3) | INSN_OP3(0x12))
+#define LDSHA      (INSN_OP(3) | INSN_OP3(0x1a))
+#define LDUWA      (INSN_OP(3) | INSN_OP3(0x10))
+#define LDSWA      (INSN_OP(3) | INSN_OP3(0x18))
+#define LDXA       (INSN_OP(3) | INSN_OP3(0x1b))
+#define STBA       (INSN_OP(3) | INSN_OP3(0x15))
+#define STHA       (INSN_OP(3) | INSN_OP3(0x16))
+#define STWA       (INSN_OP(3) | INSN_OP3(0x14))
+#define STXA       (INSN_OP(3) | INSN_OP3(0x1e))
+
+#ifndef ASI_PRIMARY_LITTLE
+#define ASI_PRIMARY_LITTLE 0x88
+#endif
+
+static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2,
+                                 int op)
+{
+    tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
+              INSN_RS2(rs2));
+}
+
+static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1,
+                                  uint32_t offset, int op)
+{
+    tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
+              INSN_IMM13(offset));
+}
+
+static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
+			   int val2, int val2const, int op)
+{
+    tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1)
+              | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+    tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR);
+}
+
+static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg)
+{
+    tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10));
+}
+
+static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg)
+{
+    tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR);
+}
+
+static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg)
+{
+    if (check_fit_tl(arg, 13))
+        tcg_out_movi_imm13(s, ret, arg);
+    else {
+        tcg_out_sethi(s, ret, arg);
+        if (arg & 0x3ff)
+            tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
+    }
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+                                int ret, tcg_target_long arg)
+{
+    /* All 32-bit constants, as well as 64-bit constants with
+       no high bits set go through movi_imm32.  */
+    if (TCG_TARGET_REG_BITS == 32
+        || type == TCG_TYPE_I32
+        || (arg & ~(tcg_target_long)0xffffffff) == 0) {
+        tcg_out_movi_imm32(s, ret, arg);
+    } else if (check_fit_tl(arg, 13)) {
+        /* A 13-bit constant sign-extended to 64-bits.  */
+        tcg_out_movi_imm13(s, ret, arg);
+    } else if (check_fit_tl(arg, 32)) {
+        /* A 32-bit constant sign-extended to 64-bits.  */
+        tcg_out_sethi(s, ret, ~arg);
+        tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR);
+    } else {
+        tcg_out_movi_imm32(s, TCG_REG_I4, arg >> (TCG_TARGET_REG_BITS / 2));
+        tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX);
+        tcg_out_movi_imm32(s, ret, arg);
+        tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR);
+    }
+}
+
+static inline void tcg_out_ld_raw(TCGContext *s, int ret,
+                                  tcg_target_long arg)
+{
+    tcg_out_sethi(s, ret, arg);
+    tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
+              INSN_IMM13(arg & 0x3ff));
+}
+
+static inline void tcg_out_ld_ptr(TCGContext *s, int ret,
+                                  tcg_target_long arg)
+{
+    if (!check_fit_tl(arg, 10))
+        tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL);
+    if (TCG_TARGET_REG_BITS == 64) {
+        tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) |
+                  INSN_IMM13(arg & 0x3ff));
+    } else {
+        tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
+                  INSN_IMM13(arg & 0x3ff));
+    }
+}
+
+static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op)
+{
+    if (check_fit_tl(offset, 13))
+        tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
+                  INSN_IMM13(offset));
+    else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
+        tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
+                  INSN_RS2(addr));
+    }
+}
+
+static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr,
+                                    int offset, int op, int asi)
+{
+    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
+    tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
+              INSN_ASI(asi) | INSN_RS2(addr));
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+                              int arg1, tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32)
+        tcg_out_ldst(s, ret, arg1, arg2, LDUW);
+    else
+        tcg_out_ldst(s, ret, arg1, arg2, LDX);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    if (type == TCG_TYPE_I32)
+        tcg_out_ldst(s, arg, arg1, arg2, STW);
+    else
+        tcg_out_ldst(s, arg, arg1, arg2, STX);
+}
+
+static inline void tcg_out_sety(TCGContext *s, int rs)
+{
+    tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
+}
+
+static inline void tcg_out_rdy(TCGContext *s, int rd)
+{
+    tcg_out32(s, RDY | INSN_RD(rd));
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val != 0) {
+        if (check_fit_tl(val, 13))
+            tcg_out_arithi(s, reg, reg, val, ARITH_ADD);
+        else {
+            tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val);
+            tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD);
+        }
+    }
+}
+
+static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val != 0) {
+        if (check_fit_tl(val, 13))
+            tcg_out_arithi(s, reg, reg, val, ARITH_AND);
+        else {
+            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val);
+            tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND);
+        }
+    }
+}
+
+static void tcg_out_div32(TCGContext *s, int rd, int rs1,
+                          int val2, int val2const, int uns)
+{
+    /* Load Y with the sign/zero extension of RS1 to 64-bits.  */
+    if (uns) {
+        tcg_out_sety(s, TCG_REG_G0);
+    } else {
+        tcg_out_arithi(s, TCG_REG_I5, rs1, 31, SHIFT_SRA);
+        tcg_out_sety(s, TCG_REG_I5);
+    }
+
+    tcg_out_arithc(s, rd, rs1, val2, val2const,
+                   uns ? ARITH_UDIV : ARITH_SDIV);
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+    tcg_out_sethi(s, TCG_REG_G0, 0);
+}
+
+static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
+{
+    int32_t val;
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value) {
+        val = l->u.value - (tcg_target_long)s->code_ptr;
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2)
+                      | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr)));
+    } else {
+        tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0);
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0));
+    }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index)
+{
+    int32_t val;
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value) {
+        val = l->u.value - (tcg_target_long)s->code_ptr;
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+                      (0x5 << 19) |
+                      INSN_OFF19(l->u.value - (unsigned long)s->code_ptr)));
+    } else {
+        tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0);
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+                      (0x5 << 19) | 0));
+    }
+}
+#endif
+
+static const uint8_t tcg_cond_to_bcond[10] = {
+    [TCG_COND_EQ] = COND_E,
+    [TCG_COND_NE] = COND_NE,
+    [TCG_COND_LT] = COND_L,
+    [TCG_COND_GE] = COND_GE,
+    [TCG_COND_LE] = COND_LE,
+    [TCG_COND_GT] = COND_G,
+    [TCG_COND_LTU] = COND_CS,
+    [TCG_COND_GEU] = COND_CC,
+    [TCG_COND_LEU] = COND_LEU,
+    [TCG_COND_GTU] = COND_GU,
+};
+
+static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const)
+{
+    tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC);
+}
+
+static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond,
+                               TCGArg arg1, TCGArg arg2, int const_arg2,
+                               int label_index)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2);
+    tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index);
+    tcg_out_nop(s);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond,
+                               TCGArg arg1, TCGArg arg2, int const_arg2,
+                               int label_index)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2);
+    tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index);
+    tcg_out_nop(s);
+}
+#else
+static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond,
+                                TCGArg al, TCGArg ah,
+                                TCGArg bl, int blconst,
+                                TCGArg bh, int bhconst, int label_dest)
+{
+    int cc, label_next = gen_new_label();
+
+    tcg_out_cmp(s, ah, bh, bhconst);
+
+    /* Note that we fill one of the delay slots with the second compare.  */
+    switch (cond) {
+    case TCG_COND_EQ:
+        cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+        tcg_out_branch_i32(s, cc, label_next);
+        tcg_out_cmp(s, al, bl, blconst);
+        cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_EQ], 0);
+        tcg_out_branch_i32(s, cc, label_dest);
+        break;
+
+    case TCG_COND_NE:
+        cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+        tcg_out_branch_i32(s, cc, label_dest);
+        tcg_out_cmp(s, al, bl, blconst);
+        tcg_out_branch_i32(s, cc, label_dest);
+        break;
+
+    default:
+        /* ??? One could fairly easily special-case 64-bit unsigned
+           compares against 32-bit zero-extended constants.  For instance,
+           we know that (unsigned)AH < 0 is false and need not emit it.
+           Similarly, (unsigned)AH > 0 being true implies AH != 0, so the
+           second branch will never be taken.  */
+        cc = INSN_COND(tcg_cond_to_bcond[cond], 0);
+        tcg_out_branch_i32(s, cc, label_dest);
+        tcg_out_nop(s);
+        cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+        tcg_out_branch_i32(s, cc, label_next);
+        tcg_out_cmp(s, al, bl, blconst);
+        cc = INSN_COND(tcg_cond_to_bcond[tcg_unsigned_cond(cond)], 0);
+        tcg_out_branch_i32(s, cc, label_dest);
+        break;
+    }
+    tcg_out_nop(s);
+
+    tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
+}
+#endif
+
+static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
+                                TCGArg c1, TCGArg c2, int c2const)
+{
+    TCGArg t;
+
+    /* For 32-bit comparisons, we can play games with ADDX/SUBX.  */
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        if (c2 != 0) {
+            tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR);
+        }
+        c1 = TCG_REG_G0, c2 = ret, c2const = 0;
+        cond = (cond == TCG_COND_EQ ? TCG_COND_LEU : TCG_COND_LTU);
+	break;
+
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        if (c2const && c2 != 0) {
+            tcg_out_movi_imm13(s, TCG_REG_I5, c2);
+            c2 = TCG_REG_I5;
+        }
+        t = c1, c1 = c2, c2 = t, c2const = 0;
+        cond = tcg_swap_cond(cond);
+        break;
+
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+        break;
+
+    default:
+        tcg_out_cmp(s, c1, c2, c2const);
+#if defined(__sparc_v9__) || defined(__sparc_v8plus__)
+        tcg_out_movi_imm13(s, ret, 0);
+        tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+                   | INSN_RS1(tcg_cond_to_bcond[cond])
+                   | MOVCC_ICC | INSN_IMM11(1));
+#else
+        t = gen_new_label();
+        tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t);
+        tcg_out_movi_imm13(s, ret, 1);
+        tcg_out_movi_imm13(s, ret, 0);
+        tcg_out_label(s, t, (tcg_target_long)s->code_ptr);
+#endif
+        return;
+    }
+
+    tcg_out_cmp(s, c1, c2, c2const);
+    if (cond == TCG_COND_LTU) {
+        tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDX);
+    } else {
+        tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBX);
+    }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
+                                TCGArg c1, TCGArg c2, int c2const)
+{
+    tcg_out_cmp(s, c1, c2, c2const);
+    tcg_out_movi_imm13(s, ret, 0);
+    tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+               | INSN_RS1(tcg_cond_to_bcond[cond])
+               | MOVCC_XCC | INSN_IMM11(1));
+}
+#else
+static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
+                                 TCGArg al, TCGArg ah,
+                                 TCGArg bl, int blconst,
+                                 TCGArg bh, int bhconst)
+{
+    int lab;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_I5, al, bl, blconst);
+        tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst);
+        tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_AND);
+        break;
+
+    case TCG_COND_NE:
+        tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_I5, al, al, blconst);
+        tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst);
+        tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR);
+        break;
+
+    default:
+        lab = gen_new_label();
+
+        tcg_out_cmp(s, ah, bh, bhconst);
+        tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), lab);
+        tcg_out_movi_imm13(s, ret, 1);
+        tcg_out_branch_i32(s, INSN_COND(COND_NE, 1), lab);
+        tcg_out_movi_imm13(s, ret, 0);
+
+        tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), ret, al, bl, blconst);
+
+        tcg_out_label(s, lab, (tcg_target_long)s->code_ptr);
+        break;
+    }
+}
+#endif
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+    tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_CALL_STACK_OFFSET,
+                  CPU_TEMP_BUF_NLONGS * (int)sizeof(long));
+    tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
+              INSN_IMM13(-(TCG_TARGET_STACK_MINFRAME +
+                           CPU_TEMP_BUF_NLONGS * (int)sizeof(long))));
+    tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I1) |
+              INSN_RS2(TCG_REG_G0));
+    tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_I0);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static const void * const qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static const void * const qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+#if TARGET_LONG_BITS == 32
+#define TARGET_LD_OP LDUW
+#else
+#define TARGET_LD_OP LDX
+#endif
+
+#if defined(CONFIG_SOFTMMU)
+#if HOST_LONG_BITS == 32
+#define TARGET_ADDEND_LD_OP LDUW
+#else
+#define TARGET_ADDEND_LD_OP LDX
+#endif
+#endif
+
+#ifdef __arch64__
+#define HOST_LD_OP LDX
+#define HOST_ST_OP STX
+#define HOST_SLL_OP SHIFT_SLLX
+#define HOST_SRA_OP SHIFT_SRAX
+#else
+#define HOST_LD_OP LDUW
+#define HOST_ST_OP STW
+#define HOST_SLL_OP SHIFT_SLL
+#define HOST_SRA_OP SHIFT_SRA
+#endif
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    uint32_t *label1_ptr, *label2_ptr;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    arg0 = TCG_REG_O0;
+    arg1 = TCG_REG_O1;
+    arg2 = TCG_REG_O2;
+
+#if defined(CONFIG_SOFTMMU)
+    /* srl addr_reg, x, arg1 */
+    tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS,
+                   SHIFT_SRL);
+    /* and addr_reg, x, arg0 */
+    tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+                   ARITH_AND);
+
+    /* and arg1, x, arg1 */
+    tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+    /* add arg1, x, arg1 */
+    tcg_out_addi(s, arg1, offsetof(CPUState,
+                                   tlb_table[mem_index][0].addr_read));
+
+    /* add env, arg1, arg1 */
+    tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD);
+
+    /* ld [arg1], arg2 */
+    tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) |
+              INSN_RS2(TCG_REG_G0));
+
+    /* subcc arg0, arg2, %g0 */
+    tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
+
+    /* will become:
+       be label1
+        or
+       be,pt %xcc label1 */
+    label1_ptr = (uint32_t *)s->code_ptr;
+    tcg_out32(s, 0);
+
+    /* mov (delay slot) */
+    tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
+
+    /* mov */
+    tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+
+    /* XXX: move that code at the end of the TB */
+    /* qemu_ld_helper[s_bits](arg0, arg1) */
+    tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits]
+                           - (tcg_target_ulong)s->code_ptr) >> 2)
+                         & 0x3fffffff));
+    /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+       global registers */
+    // delay slot
+    tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_ST_OP);
+    tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_LD_OP);
+
+    /* data_reg = sign_extend(arg0) */
+    switch(opc) {
+    case 0 | 4:
+        /* sll arg0, 24/56, data_reg */
+        tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8,
+                       HOST_SLL_OP);
+        /* sra data_reg, 24/56, data_reg */
+        tcg_out_arithi(s, data_reg, data_reg,
+                       (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP);
+        break;
+    case 1 | 4:
+        /* sll arg0, 16/48, data_reg */
+        tcg_out_arithi(s, data_reg, arg0,
+                       (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP);
+        /* sra data_reg, 16/48, data_reg */
+        tcg_out_arithi(s, data_reg, data_reg,
+                       (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP);
+        break;
+    case 2 | 4:
+        /* sll arg0, 32, data_reg */
+        tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP);
+        /* sra data_reg, 32, data_reg */
+        tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP);
+        break;
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    default:
+        /* mov */
+        tcg_out_mov(s, TCG_TYPE_REG, data_reg, arg0);
+        break;
+    }
+
+    /* will become:
+       ba label2 */
+    label2_ptr = (uint32_t *)s->code_ptr;
+    tcg_out32(s, 0);
+
+    /* nop (delay slot */
+    tcg_out_nop(s);
+
+    /* label1: */
+#if TARGET_LONG_BITS == 32
+    /* be label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
+                   INSN_OFF22((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#else
+    /* be,pt %xcc label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+                   (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#endif
+
+    /* ld [arg1 + x], arg1 */
+    tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
+                 offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP);
+
+#if TARGET_LONG_BITS == 32
+    /* and addr_reg, x, arg0 */
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff);
+    tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND);
+    /* add arg0, arg1, arg0 */
+    tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD);
+#else
+    /* add addr_reg, arg1, arg0 */
+    tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD);
+#endif
+
+#else
+    arg0 = addr_reg;
+#endif
+
+    switch(opc) {
+    case 0:
+        /* ldub [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDUB);
+        break;
+    case 0 | 4:
+        /* ldsb [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDSB);
+        break;
+    case 1:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* lduh [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDUH);
+#else
+        /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 1 | 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* ldsh [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDSH);
+#else
+        /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 2:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* lduw [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDUW);
+#else
+        /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 2 | 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* ldsw [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDSW);
+#else
+        /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 3:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* ldx [arg0], data_reg */
+        tcg_out_ldst(s, data_reg, arg0, 0, LDX);
+#else
+        /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    /* label2: */
+    *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) |
+                   INSN_OFF22((unsigned long)s->code_ptr -
+                              (unsigned long)label2_ptr));
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    uint32_t *label1_ptr, *label2_ptr;
+#endif
+
+    data_reg = *args++;
+    addr_reg = *args++;
+    mem_index = *args;
+
+    s_bits = opc;
+
+    arg0 = TCG_REG_O0;
+    arg1 = TCG_REG_O1;
+    arg2 = TCG_REG_O2;
+
+#if defined(CONFIG_SOFTMMU)
+    /* srl addr_reg, x, arg1 */
+    tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS,
+                   SHIFT_SRL);
+
+    /* and addr_reg, x, arg0 */
+    tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+                   ARITH_AND);
+
+    /* and arg1, x, arg1 */
+    tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+    /* add arg1, x, arg1 */
+    tcg_out_addi(s, arg1, offsetof(CPUState,
+                                   tlb_table[mem_index][0].addr_write));
+
+    /* add env, arg1, arg1 */
+    tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD);
+
+    /* ld [arg1], arg2 */
+    tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) |
+              INSN_RS2(TCG_REG_G0));
+
+    /* subcc arg0, arg2, %g0 */
+    tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
+
+    /* will become:
+       be label1
+        or
+       be,pt %xcc label1 */
+    label1_ptr = (uint32_t *)s->code_ptr;
+    tcg_out32(s, 0);
+
+    /* mov (delay slot) */
+    tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
+
+    /* mov */
+    tcg_out_mov(s, TCG_TYPE_REG, arg1, data_reg);
+
+    /* mov */
+    tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index);
+
+    /* XXX: move that code at the end of the TB */
+    /* qemu_st_helper[s_bits](arg0, arg1, arg2) */
+    tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits]
+                           - (tcg_target_ulong)s->code_ptr) >> 2)
+                         & 0x3fffffff));
+    /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+       global registers */
+    // delay slot
+    tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_ST_OP);
+    tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_LD_OP);
+
+    /* will become:
+       ba label2 */
+    label2_ptr = (uint32_t *)s->code_ptr;
+    tcg_out32(s, 0);
+
+    /* nop (delay slot) */
+    tcg_out_nop(s);
+
+#if TARGET_LONG_BITS == 32
+    /* be label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
+                   INSN_OFF22((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#else
+    /* be,pt %xcc label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+                   (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#endif
+
+    /* ld [arg1 + x], arg1 */
+    tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
+                 offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP);
+
+#if TARGET_LONG_BITS == 32
+    /* and addr_reg, x, arg0 */
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff);
+    tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND);
+    /* add arg0, arg1, arg0 */
+    tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD);
+#else
+    /* add addr_reg, arg1, arg0 */
+    tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD);
+#endif
+
+#else
+    arg0 = addr_reg;
+#endif
+
+    switch(opc) {
+    case 0:
+        /* stb data_reg, [arg0] */
+        tcg_out_ldst(s, data_reg, arg0, 0, STB);
+        break;
+    case 1:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* sth data_reg, [arg0] */
+        tcg_out_ldst(s, data_reg, arg0, 0, STH);
+#else
+        /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 2:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* stw data_reg, [arg0] */
+        tcg_out_ldst(s, data_reg, arg0, 0, STW);
+#else
+        /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    case 3:
+#ifdef TARGET_WORDS_BIGENDIAN
+        /* stx data_reg, [arg0] */
+        tcg_out_ldst(s, data_reg, arg0, 0, STX);
+#else
+        /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */
+        tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE);
+#endif
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    /* label2: */
+    *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) |
+                   INSN_OFF22((unsigned long)s->code_ptr -
+                              (unsigned long)label2_ptr));
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                              const int *const_args)
+{
+    int c;
+
+    switch (opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]);
+        tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) |
+                  INSN_IMM13(8));
+        tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) |
+                      INSN_RS2(TCG_REG_G0));
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+            tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000);
+            tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
+                      INSN_IMM13((args[0] & 0x1fff)));
+            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+        } else {
+            /* indirect jump method */
+            tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0]));
+            tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
+                      INSN_RS2(TCG_REG_G0));
+        }
+        tcg_out_nop(s);
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_call:
+        if (const_args[0])
+            tcg_out32(s, CALL | ((((tcg_target_ulong)args[0]
+                                   - (tcg_target_ulong)s->code_ptr) >> 2)
+                                 & 0x3fffffff));
+        else {
+            tcg_out_ld_ptr(s, TCG_REG_I5,
+                           (tcg_target_long)(s->tb_next + args[0]));
+            tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) |
+                      INSN_RS2(TCG_REG_G0));
+        }
+        /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+           global registers */
+        // delay slot
+        tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                     TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                     sizeof(long), HOST_ST_OP);
+        tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+                     TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                     sizeof(long), HOST_LD_OP);
+        break;
+    case INDEX_op_jmp:
+    case INDEX_op_br:
+        tcg_out_branch_i32(s, COND_A, args[0]);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
+        break;
+
+#if TCG_TARGET_REG_BITS == 64
+#define OP_32_64(x)                             \
+        glue(glue(case INDEX_op_, x), _i32):    \
+        glue(glue(case INDEX_op_, x), _i64)
+#else
+#define OP_32_64(x)                             \
+        glue(glue(case INDEX_op_, x), _i32)
+#endif
+    OP_32_64(ld8u):
+        tcg_out_ldst(s, args[0], args[1], args[2], LDUB);
+        break;
+    OP_32_64(ld8s):
+        tcg_out_ldst(s, args[0], args[1], args[2], LDSB);
+        break;
+    OP_32_64(ld16u):
+        tcg_out_ldst(s, args[0], args[1], args[2], LDUH);
+        break;
+    OP_32_64(ld16s):
+        tcg_out_ldst(s, args[0], args[1], args[2], LDSH);
+        break;
+    case INDEX_op_ld_i32:
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_ld32u_i64:
+#endif
+        tcg_out_ldst(s, args[0], args[1], args[2], LDUW);
+        break;
+    OP_32_64(st8):
+        tcg_out_ldst(s, args[0], args[1], args[2], STB);
+        break;
+    OP_32_64(st16):
+        tcg_out_ldst(s, args[0], args[1], args[2], STH);
+        break;
+    case INDEX_op_st_i32:
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_st32_i64:
+#endif
+        tcg_out_ldst(s, args[0], args[1], args[2], STW);
+        break;
+    OP_32_64(add):
+        c = ARITH_ADD;
+        goto gen_arith;
+    OP_32_64(sub):
+        c = ARITH_SUB;
+        goto gen_arith;
+    OP_32_64(and):
+        c = ARITH_AND;
+        goto gen_arith;
+    OP_32_64(andc):
+        c = ARITH_ANDN;
+        goto gen_arith;
+    OP_32_64(or):
+        c = ARITH_OR;
+        goto gen_arith;
+    OP_32_64(orc):
+        c = ARITH_ORN;
+        goto gen_arith;
+    OP_32_64(xor):
+        c = ARITH_XOR;
+        goto gen_arith;
+    case INDEX_op_shl_i32:
+        c = SHIFT_SLL;
+        goto gen_arith;
+    case INDEX_op_shr_i32:
+        c = SHIFT_SRL;
+        goto gen_arith;
+    case INDEX_op_sar_i32:
+        c = SHIFT_SRA;
+        goto gen_arith;
+    case INDEX_op_mul_i32:
+        c = ARITH_UMUL;
+        goto gen_arith;
+
+    OP_32_64(neg):
+	c = ARITH_SUB;
+	goto gen_arith1;
+    OP_32_64(not):
+	c = ARITH_ORN;
+	goto gen_arith1;
+
+    case INDEX_op_div_i32:
+        tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
+        break;
+    case INDEX_op_divu_i32:
+        tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1);
+        break;
+
+    case INDEX_op_rem_i32:
+    case INDEX_op_remu_i32:
+        tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2],
+                      opc == INDEX_op_remu_i32);
+        tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2],
+                       ARITH_UMUL);
+        tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB);
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
+                           args[3]);
+        break;
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond_i32(s, args[3], args[0], args[1],
+                            args[2], const_args[2]);
+        break;
+
+#if TCG_TARGET_REG_BITS == 32
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2_i32(s, args[4], args[0], args[1],
+                            args[2], const_args[2],
+                            args[3], const_args[3], args[5]);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
+                             args[3], const_args[3],
+                             args[4], const_args[4]);
+        break;
+    case INDEX_op_add2_i32:
+        tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
+                       ARITH_ADDCC);
+        tcg_out_arithc(s, args[1], args[3], args[5], const_args[5],
+                       ARITH_ADDX);
+        break;
+    case INDEX_op_sub2_i32:
+        tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
+                       ARITH_SUBCC);
+        tcg_out_arithc(s, args[1], args[3], args[5], const_args[5],
+                       ARITH_SUBX);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_arithc(s, args[0], args[2], args[3], const_args[3],
+                       ARITH_UMUL);
+        tcg_out_rdy(s, args[1]);
+        break;
+#endif
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32:
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_qemu_ld32u:
+#endif
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_qemu_ld32s:
+        tcg_out_qemu_ld(s, args, 2 | 4);
+        break;
+#endif
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+
+#if TCG_TARGET_REG_BITS == 64
+    case INDEX_op_movi_i64:
+        tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+        break;
+    case INDEX_op_ld32s_i64:
+        tcg_out_ldst(s, args[0], args[1], args[2], LDSW);
+        break;
+    case INDEX_op_ld_i64:
+        tcg_out_ldst(s, args[0], args[1], args[2], LDX);
+        break;
+    case INDEX_op_st_i64:
+        tcg_out_ldst(s, args[0], args[1], args[2], STX);
+        break;
+    case INDEX_op_shl_i64:
+        c = SHIFT_SLLX;
+        goto gen_arith;
+    case INDEX_op_shr_i64:
+        c = SHIFT_SRLX;
+        goto gen_arith;
+    case INDEX_op_sar_i64:
+        c = SHIFT_SRAX;
+        goto gen_arith;
+    case INDEX_op_mul_i64:
+        c = ARITH_MULX;
+        goto gen_arith;
+    case INDEX_op_div_i64:
+        c = ARITH_SDIVX;
+        goto gen_arith;
+    case INDEX_op_divu_i64:
+        c = ARITH_UDIVX;
+        goto gen_arith;
+    case INDEX_op_rem_i64:
+    case INDEX_op_remu_i64:
+        tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2],
+                       opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX);
+        tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2],
+                       ARITH_MULX);
+        tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB);
+        break;
+    case INDEX_op_ext32s_i64:
+        if (const_args[1]) {
+            tcg_out_movi(s, TCG_TYPE_I64, args[0], (int32_t)args[1]);
+        } else {
+            tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA);
+        }
+        break;
+    case INDEX_op_ext32u_i64:
+        if (const_args[1]) {
+            tcg_out_movi_imm32(s, args[0], args[1]);
+        } else {
+            tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL);
+        }
+        break;
+
+    case INDEX_op_brcond_i64:
+        tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
+                           args[3]);
+        break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond_i64(s, args[3], args[0], args[1],
+                            args[2], const_args[2]);
+        break;
+
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+#endif
+    gen_arith:
+        tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
+        break;
+
+    gen_arith1:
+	tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
+	break;
+
+    default:
+        fprintf(stderr, "unknown opcode 0x%x\n", opc);
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef sparc_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "r", "r" } },
+    { INDEX_op_st16_i32, { "r", "r" } },
+    { INDEX_op_st_i32, { "r", "r" } },
+
+    { INDEX_op_add_i32, { "r", "r", "rJ" } },
+    { INDEX_op_mul_i32, { "r", "r", "rJ" } },
+    { INDEX_op_div_i32, { "r", "r", "rJ" } },
+    { INDEX_op_divu_i32, { "r", "r", "rJ" } },
+    { INDEX_op_rem_i32, { "r", "r", "rJ" } },
+    { INDEX_op_remu_i32, { "r", "r", "rJ" } },
+    { INDEX_op_sub_i32, { "r", "r", "rJ" } },
+    { INDEX_op_and_i32, { "r", "r", "rJ" } },
+    { INDEX_op_andc_i32, { "r", "r", "rJ" } },
+    { INDEX_op_or_i32, { "r", "r", "rJ" } },
+    { INDEX_op_orc_i32, { "r", "r", "rJ" } },
+    { INDEX_op_xor_i32, { "r", "r", "rJ" } },
+
+    { INDEX_op_shl_i32, { "r", "r", "rJ" } },
+    { INDEX_op_shr_i32, { "r", "r", "rJ" } },
+    { INDEX_op_sar_i32, { "r", "r", "rJ" } },
+
+    { INDEX_op_neg_i32, { "r", "rJ" } },
+    { INDEX_op_not_i32, { "r", "rJ" } },
+
+    { INDEX_op_brcond_i32, { "r", "rJ" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
+
+#if TCG_TARGET_REG_BITS == 32
+    { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
+    { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } },
+#endif
+
+    { INDEX_op_qemu_ld8u, { "r", "L" } },
+    { INDEX_op_qemu_ld8s, { "r", "L" } },
+    { INDEX_op_qemu_ld16u, { "r", "L" } },
+    { INDEX_op_qemu_ld16s, { "r", "L" } },
+    { INDEX_op_qemu_ld32, { "r", "L" } },
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_qemu_ld32u, { "r", "L" } },
+    { INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
+
+    { INDEX_op_qemu_st8, { "L", "L" } },
+    { INDEX_op_qemu_st16, { "L", "L" } },
+    { INDEX_op_qemu_st32, { "L", "L" } },
+
+#if TCG_TARGET_REG_BITS == 64
+    { INDEX_op_mov_i64, { "r", "r" } },
+    { INDEX_op_movi_i64, { "r" } },
+    { INDEX_op_ld8u_i64, { "r", "r" } },
+    { INDEX_op_ld8s_i64, { "r", "r" } },
+    { INDEX_op_ld16u_i64, { "r", "r" } },
+    { INDEX_op_ld16s_i64, { "r", "r" } },
+    { INDEX_op_ld32u_i64, { "r", "r" } },
+    { INDEX_op_ld32s_i64, { "r", "r" } },
+    { INDEX_op_ld_i64, { "r", "r" } },
+    { INDEX_op_st8_i64, { "r", "r" } },
+    { INDEX_op_st16_i64, { "r", "r" } },
+    { INDEX_op_st32_i64, { "r", "r" } },
+    { INDEX_op_st_i64, { "r", "r" } },
+    { INDEX_op_qemu_ld64, { "L", "L" } },
+    { INDEX_op_qemu_st64, { "L", "L" } },
+
+    { INDEX_op_add_i64, { "r", "r", "rJ" } },
+    { INDEX_op_mul_i64, { "r", "r", "rJ" } },
+    { INDEX_op_div_i64, { "r", "r", "rJ" } },
+    { INDEX_op_divu_i64, { "r", "r", "rJ" } },
+    { INDEX_op_rem_i64, { "r", "r", "rJ" } },
+    { INDEX_op_remu_i64, { "r", "r", "rJ" } },
+    { INDEX_op_sub_i64, { "r", "r", "rJ" } },
+    { INDEX_op_and_i64, { "r", "r", "rJ" } },
+    { INDEX_op_andc_i64, { "r", "r", "rJ" } },
+    { INDEX_op_or_i64, { "r", "r", "rJ" } },
+    { INDEX_op_orc_i64, { "r", "r", "rJ" } },
+    { INDEX_op_xor_i64, { "r", "r", "rJ" } },
+
+    { INDEX_op_shl_i64, { "r", "r", "rJ" } },
+    { INDEX_op_shr_i64, { "r", "r", "rJ" } },
+    { INDEX_op_sar_i64, { "r", "r", "rJ" } },
+
+    { INDEX_op_neg_i64, { "r", "rJ" } },
+    { INDEX_op_not_i64, { "r", "rJ" } },
+
+    { INDEX_op_ext32s_i64, { "r", "ri" } },
+    { INDEX_op_ext32u_i64, { "r", "ri" } },
+
+    { INDEX_op_brcond_i64, { "r", "rJ" } },
+    { INDEX_op_setcond_i64, { "r", "r", "rJ" } },
+#endif
+    { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+#if TCG_TARGET_REG_BITS == 64
+    tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+#endif
+    tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+                     (1 << TCG_REG_G1) |
+                     (1 << TCG_REG_G2) |
+                     (1 << TCG_REG_G3) |
+                     (1 << TCG_REG_G4) |
+                     (1 << TCG_REG_G5) |
+                     (1 << TCG_REG_G6) |
+                     (1 << TCG_REG_G7) |
+                     (1 << TCG_REG_O0) |
+                     (1 << TCG_REG_O1) |
+                     (1 << TCG_REG_O2) |
+                     (1 << TCG_REG_O3) |
+                     (1 << TCG_REG_O4) |
+                     (1 << TCG_REG_O5) |
+                     (1 << TCG_REG_O7));
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0);
+#if TCG_TARGET_REG_BITS == 64
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use
+#endif
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7);
+    tcg_add_target_add_op_defs(sparc_op_defs);
+}
diff --git a/qemu-0.15.x/tcg/sparc/tcg-target.h b/qemu-0.15.x/tcg/sparc/tcg-target.h
new file mode 100644
index 0000000..df0785e
--- /dev/null
+++ b/qemu-0.15.x/tcg/sparc/tcg-target.h
@@ -0,0 +1,150 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+#define TCG_TARGET_SPARC 1
+
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+#define TCG_TARGET_REG_BITS 64
+#else
+#define TCG_TARGET_REG_BITS 32
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_G0 = 0,
+    TCG_REG_G1,
+    TCG_REG_G2,
+    TCG_REG_G3,
+    TCG_REG_G4,
+    TCG_REG_G5,
+    TCG_REG_G6,
+    TCG_REG_G7,
+    TCG_REG_O0,
+    TCG_REG_O1,
+    TCG_REG_O2,
+    TCG_REG_O3,
+    TCG_REG_O4,
+    TCG_REG_O5,
+    TCG_REG_O6,
+    TCG_REG_O7,
+    TCG_REG_L0,
+    TCG_REG_L1,
+    TCG_REG_L2,
+    TCG_REG_L3,
+    TCG_REG_L4,
+    TCG_REG_L5,
+    TCG_REG_L6,
+    TCG_REG_L7,
+    TCG_REG_I0,
+    TCG_REG_I1,
+    TCG_REG_I2,
+    TCG_REG_I3,
+    TCG_REG_I4,
+    TCG_REG_I5,
+    TCG_REG_I6,
+    TCG_REG_I7,
+};
+
+#define TCG_CT_CONST_S11 0x100
+#define TCG_CT_CONST_S13 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_I6
+#ifdef __arch64__
+// Reserve space for AREG0
+#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \
+                                   TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16)
+#define TCG_TARGET_STACK_ALIGN 16
+#else
+// AREG0 + one word for alignment
+#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \
+                                   TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME
+#define TCG_TARGET_STACK_ALIGN 8
+#endif
+
+#ifdef __arch64__
+#define TCG_TARGET_EXTEND_ARGS 1
+#endif
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+/* Note: must be synced with dyngen-exec.h */
+#ifdef CONFIG_SOLARIS
+#define TCG_AREG0 TCG_REG_G2
+#elif defined(__sparc_v9__)
+#define TCG_AREG0 TCG_REG_G5
+#else
+#define TCG_AREG0 TCG_REG_G6
+#endif
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    unsigned long p;
+
+    p = start & ~(8UL - 1UL);
+    stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
+
+    for (; p < stop; p += 8)
+        __asm__ __volatile__("flush\t%0" : : "r" (p));
+}
diff --git a/qemu-0.15.x/tcg/tcg-op.h b/qemu-0.15.x/tcg/tcg-op.h
new file mode 100644
index 0000000..ebf5e13
--- /dev/null
+++ b/qemu-0.15.x/tcg/tcg-op.h
@@ -0,0 +1,2539 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 "tcg.h"
+
+int gen_new_label(void);
+
+static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+}
+
+static inline void tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 arg1)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+}
+
+static inline void tcg_gen_op1i(TCGOpcode opc, TCGArg arg1)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = arg1;
+}
+
+static inline void tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+}
+
+static inline void tcg_gen_op2_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+}
+
+static inline void tcg_gen_op2i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGArg arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op2i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGArg arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op2ii(TCGOpcode opc, TCGArg arg1, TCGArg arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = arg1;
+    *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op3_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+}
+
+static inline void tcg_gen_op3_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+}
+
+static inline void tcg_gen_op3i_i32(TCGOpcode opc, TCGv_i32 arg1,
+                                    TCGv_i32 arg2, TCGArg arg3)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = arg3;
+}
+
+static inline void tcg_gen_op3i_i64(TCGOpcode opc, TCGv_i64 arg1,
+                                    TCGv_i64 arg2, TCGArg arg3)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = arg3;
+}
+
+static inline void tcg_gen_ldst_op_i32(TCGOpcode opc, TCGv_i32 val,
+                                       TCGv_ptr base, TCGArg offset)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(val);
+    *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+    *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_ldst_op_i64(TCGOpcode opc, TCGv_i64 val,
+                                       TCGv_ptr base, TCGArg offset)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+    *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i32(TCGOpcode opc, TCGv_i64 val,
+                                                TCGv_i32 addr, TCGArg mem_index)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_I32(addr);
+    *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i64(TCGOpcode opc, TCGv_i64 val,
+                                                TCGv_i64 addr, TCGArg mem_index)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_I64(addr);
+    *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_op4_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+}
+
+static inline void tcg_gen_op4_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+}
+
+static inline void tcg_gen_op4i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGv_i32 arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGv_i64 arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                     TCGArg arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = arg3;
+    *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                     TCGArg arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = arg3;
+    *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op5_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+}
+
+static inline void tcg_gen_op5_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+}
+
+static inline void tcg_gen_op5i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5ii_i32(TCGOpcode opc, TCGv_i32 arg1,
+                                     TCGv_i32 arg2, TCGv_i32 arg3,
+                                     TCGArg arg4, TCGArg arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = arg4;
+    *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 arg1,
+                                     TCGv_i64 arg2, TCGv_i64 arg3,
+                                     TCGArg arg4, TCGArg arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = arg4;
+    *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5,
+                                   TCGv_i32 arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg6);
+}
+
+static inline void tcg_gen_op6_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5,
+                                   TCGv_i64 arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg6);
+}
+
+static inline void tcg_gen_op6i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGv_i32 arg3, TCGv_i32 arg4,
+                                    TCGv_i32 arg5, TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+    *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGv_i64 arg3, TCGv_i64 arg4,
+                                    TCGv_i64 arg5, TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+    *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 arg1,
+                                     TCGv_i32 arg2, TCGv_i32 arg3,
+                                     TCGv_i32 arg4, TCGArg arg5, TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = arg5;
+    *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6ii_i64(TCGOpcode opc, TCGv_i64 arg1,
+                                     TCGv_i64 arg2, TCGv_i64 arg3,
+                                     TCGv_i64 arg4, TCGArg arg5, TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = arg5;
+    *gen_opparam_ptr++ = arg6;
+}
+
+static inline void gen_set_label(int n)
+{
+    tcg_gen_op1i(INDEX_op_set_label, n);
+}
+
+static inline void tcg_gen_br(int label)
+{
+    tcg_gen_op1i(INDEX_op_br, label);
+}
+
+static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+    if (!TCGV_EQUAL_I32(ret, arg))
+        tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg);
+}
+
+static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg)
+{
+    tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg);
+}
+
+/* A version of dh_sizemask from def-helper.h that doesn't rely on
+   preprocessor magic.  */
+static inline int tcg_gen_sizemask(int n, int is_64bit, int is_signed)
+{
+    return (is_64bit << n*2) | (is_signed << (n*2 + 1));
+}
+
+/* helper calls */
+static inline void tcg_gen_helperN(void *func, int flags, int sizemask,
+                                   TCGArg ret, int nargs, TCGArg *args)
+{
+    TCGv_ptr fn;
+    fn = tcg_const_ptr((tcg_target_long)func);
+    tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret,
+                  nargs, args);
+    tcg_temp_free_ptr(fn);
+}
+
+/* Note: Both tcg_gen_helper32() and tcg_gen_helper64() are currently
+   reserved for helpers in tcg-runtime.c. These helpers are all const
+   and pure, hence the call to tcg_gen_callN() with TCG_CALL_CONST |
+   TCG_CALL_PURE. This may need to be adjusted if these functions
+   start to be used with other helpers. */
+static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret,
+                                    TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_ptr fn;
+    TCGArg args[2];
+    fn = tcg_const_ptr((tcg_target_long)func);
+    args[0] = GET_TCGV_I32(a);
+    args[1] = GET_TCGV_I32(b);
+    tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask,
+                  GET_TCGV_I32(ret), 2, args);
+    tcg_temp_free_ptr(fn);
+}
+
+static inline void tcg_gen_helper64(void *func, int sizemask, TCGv_i64 ret,
+                                    TCGv_i64 a, TCGv_i64 b)
+{
+    TCGv_ptr fn;
+    TCGArg args[2];
+    fn = tcg_const_ptr((tcg_target_long)func);
+    args[0] = GET_TCGV_I64(a);
+    args[1] = GET_TCGV_I64(b);
+    tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask,
+                  GET_TCGV_I64(ret), 2, args);
+    tcg_temp_free_ptr(fn);
+}
+
+/* 32 bit ops */
+
+static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_add_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0 = tcg_const_i32(arg1);
+    tcg_gen_sub_i32(ret, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_sub_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_movi_i32(ret, 0);
+    } else if (arg2 == 0xffffffff) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_and_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0xffffffff) {
+        tcg_gen_movi_i32(ret, 0xffffffff);
+    } else if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_or_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_movi_i32(ret, 0);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_xor_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_shl_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_shr_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_sar_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+    }
+}
+
+static inline void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1,
+                                      TCGv_i32 arg2, int label_index)
+{
+    tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index);
+}
+
+static inline void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1,
+                                       int32_t arg2, int label_index)
+{
+    TCGv_i32 t0 = tcg_const_i32(arg2);
+    tcg_gen_brcond_i32(cond, arg1, t0, label_index);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret,
+                                       TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond);
+}
+
+static inline void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret,
+                                        TCGv_i32 arg1, int32_t arg2)
+{
+    TCGv_i32 t0 = tcg_const_i32(arg2);
+    tcg_gen_setcond_i32(cond, ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    TCGv_i32 t0 = tcg_const_i32(arg2);
+    tcg_gen_mul_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+
+#ifdef TCG_TARGET_HAS_div_i32
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
+}
+#elif defined(TCG_TARGET_HAS_div2_i32)
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_sari_i32(t0, arg1, 31);
+    tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_sari_i32(t0, arg1, 31);
+    tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_movi_i32(t0, 0);
+    tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_movi_i32(t0, 0);
+    tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+#else
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 32-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 0, 1);
+    sizemask |= tcg_gen_sizemask(1, 0, 1);
+    sizemask |= tcg_gen_sizemask(2, 0, 1);
+
+    tcg_gen_helper32(tcg_helper_div_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 32-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 0, 1);
+    sizemask |= tcg_gen_sizemask(1, 0, 1);
+    sizemask |= tcg_gen_sizemask(2, 0, 1);
+
+    tcg_gen_helper32(tcg_helper_rem_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 32-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 0, 0);
+    sizemask |= tcg_gen_sizemask(1, 0, 0);
+    sizemask |= tcg_gen_sizemask(2, 0, 0);
+
+    tcg_gen_helper32(tcg_helper_divu_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 32-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 0, 0);
+    sizemask |= tcg_gen_sizemask(1, 0, 0);
+    sizemask |= tcg_gen_sizemask(2, 0, 0);
+
+    tcg_gen_helper32(tcg_helper_remu_i32, sizemask, ret, arg1, arg2);
+}
+#endif
+
+#if TCG_TARGET_REG_BITS == 32
+
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    if (!TCGV_EQUAL_I64(ret, arg)) {
+        tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+        tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+    }
+}
+
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
+{
+    tcg_gen_movi_i32(TCGV_LOW(ret), arg);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32);
+}
+
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), 31);
+}
+
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                  tcg_target_long offset)
+{
+    /* since arg2 and ret have different types, they cannot be the
+       same temporary */
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+    tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
+#else
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4);
+#endif
+}
+
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                   tcg_target_long offset)
+{
+    tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                  tcg_target_long offset)
+{
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+    tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
+#else
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
+    tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4);
+#endif
+}
+
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+                    TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                    TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+                    TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                    TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+    tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+    tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+    tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+/* XXX: use generic code when basic block handling is OK or CPU
+   specific code (x86) */
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_shl_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0);
+}
+
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_shr_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0);
+}
+
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_sar_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1);
+}
+
+static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1,
+                                      TCGv_i64 arg2, int label_index)
+{
+    tcg_gen_op6ii_i32(INDEX_op_brcond2_i32,
+                      TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                      TCGV_HIGH(arg2), cond, label_index);
+}
+
+static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
+                                       TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret),
+                     TCGV_LOW(arg1), TCGV_HIGH(arg1),
+                     TCGV_LOW(arg2), TCGV_HIGH(arg2), cond);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    TCGv_i32 t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i32();
+
+    tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0),
+                    TCGV_LOW(arg1), TCGV_LOW(arg2));
+
+    tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2));
+    tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
+    tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2));
+    tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
+
+    tcg_gen_mov_i64(ret, t0);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i32(t1);
+}
+
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 0);
+    sizemask |= tcg_gen_sizemask(1, 1, 0);
+    sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+    tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 0);
+    sizemask |= tcg_gen_sizemask(1, 1, 0);
+    sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+    tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+}
+
+#else
+
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    if (!TCGV_EQUAL_I64(ret, arg))
+        tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg);
+}
+
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
+{
+    tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg);
+}
+
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                   tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+    tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_and_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_or_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_movi_i64(ret, 0);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2);
+    }
+}
+
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_xor_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_shl_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_shr_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_sar_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1,
+                                      TCGv_i64 arg2, int label_index)
+{
+    tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index);
+}
+
+static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
+                                       TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond);
+}
+
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2);
+}
+
+#ifdef TCG_TARGET_HAS_div_i64
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
+}
+#elif defined(TCG_TARGET_HAS_div2_i64)
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_sari_i64(t0, arg1, 63);
+    tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_sari_i64(t0, arg1, 63);
+    tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_movi_i64(t0, 0);
+    tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_movi_i64(t0, 0);
+    tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+#else
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and signed.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 1);
+    sizemask |= tcg_gen_sizemask(1, 1, 1);
+    sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+    tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 0);
+    sizemask |= tcg_gen_sizemask(1, 1, 0);
+    sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+    tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    int sizemask = 0;
+    /* Return value and both arguments are 64-bit and unsigned.  */
+    sizemask |= tcg_gen_sizemask(0, 1, 0);
+    sizemask |= tcg_gen_sizemask(1, 1, 0);
+    sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+    tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+}
+#endif
+
+#endif
+
+static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_add_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg1);
+    tcg_gen_sub_i64(ret, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_sub_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+static inline void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1,
+                                       int64_t arg2, int label_index)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_brcond_i64(cond, arg1, t0, label_index);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret,
+                                        TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_setcond_i64(cond, ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_mul_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+
+/***************************************/
+/* optional operations */
+
+static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8s_i32
+    tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
+#else
+    tcg_gen_shli_i32(ret, arg, 24);
+    tcg_gen_sari_i32(ret, ret, 24);
+#endif
+}
+
+static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16s_i32
+    tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
+#else
+    tcg_gen_shli_i32(ret, arg, 16);
+    tcg_gen_sari_i32(ret, ret, 16);
+#endif
+}
+
+static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8u_i32
+    tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
+#else
+    tcg_gen_andi_i32(ret, arg, 0xffu);
+#endif
+}
+
+static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16u_i32
+    tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
+#else
+    tcg_gen_andi_i32(ret, arg, 0xffffu);
+#endif
+}
+
+/* Note: we assume the two high bytes are set to zero */
+static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap16_i32
+    tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
+#else
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    
+    tcg_gen_ext8u_i32(t0, arg);
+    tcg_gen_shli_i32(t0, t0, 8);
+    tcg_gen_shri_i32(ret, arg, 8);
+    tcg_gen_or_i32(ret, ret, t0);
+    tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap32_i32
+    tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
+#else
+    TCGv_i32 t0, t1;
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+    
+    tcg_gen_shli_i32(t0, arg, 24);
+    
+    tcg_gen_andi_i32(t1, arg, 0x0000ff00);
+    tcg_gen_shli_i32(t1, t1, 8);
+    tcg_gen_or_i32(t0, t0, t1);
+    
+    tcg_gen_shri_i32(t1, arg, 8);
+    tcg_gen_andi_i32(t1, t1, 0x0000ff00);
+    tcg_gen_or_i32(t0, t0, t1);
+    
+    tcg_gen_shri_i32(t1, arg, 24);
+    tcg_gen_or_i32(ret, t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+#endif
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(ret, TCGV_LOW(arg));
+}
+
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+    tcg_gen_mov_i32(TCGV_LOW(ret), arg);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+    tcg_gen_mov_i32(TCGV_LOW(ret), arg);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+    tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
+
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+    tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    TCGv_i32 t0, t1;
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+
+    tcg_gen_bswap32_i32(t0, TCGV_LOW(arg));
+    tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg));
+    tcg_gen_mov_i32(TCGV_LOW(ret), t1);
+    tcg_gen_mov_i32(TCGV_HIGH(ret), t0);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+}
+#else
+
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8s_i64
+    tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
+#else
+    tcg_gen_shli_i64(ret, arg, 56);
+    tcg_gen_sari_i64(ret, ret, 56);
+#endif
+}
+
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16s_i64
+    tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
+#else
+    tcg_gen_shli_i64(ret, arg, 48);
+    tcg_gen_sari_i64(ret, ret, 48);
+#endif
+}
+
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext32s_i64
+    tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
+#else
+    tcg_gen_shli_i64(ret, arg, 32);
+    tcg_gen_sari_i64(ret, ret, 32);
+#endif
+}
+
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8u_i64
+    tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
+#else
+    tcg_gen_andi_i64(ret, arg, 0xffu);
+#endif
+}
+
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16u_i64
+    tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
+#else
+    tcg_gen_andi_i64(ret, arg, 0xffffu);
+#endif
+}
+
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext32u_i64
+    tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
+#else
+    tcg_gen_andi_i64(ret, arg, 0xffffffffu);
+#endif
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+   registers.  This will probably break MIPS64 targets.  */
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+   registers */
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+    tcg_gen_ext32u_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)));
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+   registers */
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+    tcg_gen_ext32s_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)));
+}
+
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap16_i64
+    tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+
+    tcg_gen_ext8u_i64(t0, arg);
+    tcg_gen_shli_i64(t0, t0, 8);
+    tcg_gen_shri_i64(ret, arg, 8);
+    tcg_gen_or_i64(ret, ret, t0);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap32_i64
+    tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
+#else
+    TCGv_i64 t0, t1;
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    tcg_gen_shli_i64(t0, arg, 24);
+    tcg_gen_ext32u_i64(t0, t0);
+
+    tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+    tcg_gen_shli_i64(t1, t1, 8);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 8);
+    tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 24);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap64_i64
+    tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    
+    tcg_gen_shli_i64(t0, arg, 56);
+    
+    tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+    tcg_gen_shli_i64(t1, t1, 40);
+    tcg_gen_or_i64(t0, t0, t1);
+    
+    tcg_gen_andi_i64(t1, arg, 0x00ff0000);
+    tcg_gen_shli_i64(t1, t1, 24);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_andi_i64(t1, arg, 0xff000000);
+    tcg_gen_shli_i64(t1, t1, 8);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 8);
+    tcg_gen_andi_i64(t1, t1, 0xff000000);
+    tcg_gen_or_i64(t0, t0, t1);
+    
+    tcg_gen_shri_i64(t1, arg, 24);
+    tcg_gen_andi_i64(t1, t1, 0x00ff0000);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 40);
+    tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 56);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+#endif
+
+static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_neg_i32
+    tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg);
+#else
+    TCGv_i32 t0 = tcg_const_i32(0);
+    tcg_gen_sub_i32(ret, t0, arg);
+    tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_neg_i64
+    tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg);
+#else
+    TCGv_i64 t0 = tcg_const_i64(0);
+    tcg_gen_sub_i64(ret, t0, arg);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_not_i32
+    tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg);
+#else
+    tcg_gen_xori_i32(ret, arg, -1);
+#endif
+}
+
+static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_not_i64
+    tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
+#elif defined(TCG_TARGET_HAS_not_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+#else
+    tcg_gen_xori_i64(ret, arg, -1);
+#endif
+}
+
+static inline void tcg_gen_discard_i32(TCGv_i32 arg)
+{
+    tcg_gen_op1_i32(INDEX_op_discard, arg);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
+{
+    tcg_gen_discard_i32(TCGV_LOW(arg));
+    tcg_gen_discard_i32(TCGV_HIGH(arg));
+}
+#else
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
+{
+    tcg_gen_op1_i64(INDEX_op_discard, arg);
+}
+#endif
+
+static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(dest), low);
+    tcg_gen_mov_i32(TCGV_HIGH(dest), high);
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    /* This extension is only needed for type correctness.
+       We may be able to do better given target specific information.  */
+    tcg_gen_extu_i32_i64(tmp, high);
+    tcg_gen_shli_i64(tmp, tmp, 32);
+    tcg_gen_extu_i32_i64(dest, low);
+    tcg_gen_or_i64(dest, dest, tmp);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_concat_i32_i64(dest, TCGV_LOW(low), TCGV_LOW(high));
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(dest, low);
+    tcg_gen_shli_i64(tmp, high, 32);
+    tcg_gen_or_i64(dest, dest, tmp);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_andc_i32
+    tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_not_i32(t0, arg2);
+    tcg_gen_and_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_andc_i64
+    tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_andc_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_not_i64(t0, arg2);
+    tcg_gen_and_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_eqv_i32
+    tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2);
+#else
+    tcg_gen_xor_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_eqv_i64
+    tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_eqv_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+    tcg_gen_xor_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_nand_i32
+    tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2);
+#else
+    tcg_gen_and_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_nand_i64
+    tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_nand_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+    tcg_gen_and_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_nor_i32
+    tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2);
+#else
+    tcg_gen_or_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_nor_i64
+    tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_nor_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+    tcg_gen_or_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_orc_i32
+    tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_not_i32(t0, arg2);
+    tcg_gen_or_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_orc_i64
+    tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_orc_i32) && TCG_TARGET_REG_BITS == 32
+    tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+    tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_not_i64(t0, arg2);
+    tcg_gen_or_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+    tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0, t1;
+
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+    tcg_gen_shl_i32(t0, arg1, arg2);
+    tcg_gen_subfi_i32(t1, 32, arg2);
+    tcg_gen_shr_i32(t1, arg1, t1);
+    tcg_gen_or_i32(ret, t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+    tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
+#else
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    tcg_gen_shl_i64(t0, arg1, arg2);
+    tcg_gen_subfi_i64(t1, 64, arg2);
+    tcg_gen_shr_i64(t1, arg1, t1);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+#ifdef TCG_TARGET_HAS_rot_i32
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_rotl_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+#else
+        TCGv_i32 t0, t1;
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+        tcg_gen_shli_i32(t0, arg1, arg2);
+        tcg_gen_shri_i32(t1, arg1, 32 - arg2);
+        tcg_gen_or_i32(ret, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+#endif
+    }
+}
+
+static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+#ifdef TCG_TARGET_HAS_rot_i64
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_rotl_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+#else
+        TCGv_i64 t0, t1;
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
+        tcg_gen_shli_i64(t0, arg1, arg2);
+        tcg_gen_shri_i64(t1, arg1, 64 - arg2);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+#endif
+    }
+}
+
+static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+    tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0, t1;
+
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+    tcg_gen_shr_i32(t0, arg1, arg2);
+    tcg_gen_subfi_i32(t1, 32, arg2);
+    tcg_gen_shl_i32(t1, arg1, t1);
+    tcg_gen_or_i32(ret, t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+    tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
+#else
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    tcg_gen_shr_i64(t0, arg1, arg2);
+    tcg_gen_subfi_i64(t1, 64, arg2);
+    tcg_gen_shl_i64(t1, arg1, t1);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_rotli_i32(ret, arg1, 32 - arg2);
+    }
+}
+
+static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_rotli_i64(ret, arg1, 64 - arg2);
+    }
+}
+
+static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
+				       TCGv_i32 arg2, unsigned int ofs,
+				       unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i32
+  tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
+#else
+  uint32_t mask = (1u << len) - 1;
+  TCGv_i32 t1 = tcg_temp_new_i32 ();
+
+  tcg_gen_andi_i32(t1, arg2, mask);
+  tcg_gen_shli_i32(t1, t1, ofs);
+  tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
+  tcg_gen_or_i32(ret, ret, t1);
+
+  tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
+				       TCGv_i64 arg2, unsigned int ofs,
+				       unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i64
+  tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
+#else
+  uint64_t mask = (1ull << len) - 1;
+  TCGv_i64 t1 = tcg_temp_new_i64 ();
+
+  tcg_gen_andi_i64(t1, arg2, mask);
+  tcg_gen_shli_i64(t1, t1, ofs);
+  tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
+  tcg_gen_or_i64(ret, ret, t1);
+
+  tcg_temp_free_i64(t1);
+#endif
+}
+
+/***************************************/
+/* QEMU specific operations. Their type depend on the QEMU CPU
+   type. */
+#ifndef TARGET_LONG_BITS
+#error must include QEMU headers
+#endif
+
+#if TARGET_LONG_BITS == 32
+#define TCGv TCGv_i32
+#define tcg_temp_new() tcg_temp_new_i32()
+#define tcg_global_reg_new tcg_global_reg_new_i32
+#define tcg_global_mem_new tcg_global_mem_new_i32
+#define tcg_temp_local_new() tcg_temp_local_new_i32()
+#define tcg_temp_free tcg_temp_free_i32
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32
+#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b)
+#else
+#define TCGv TCGv_i64
+#define tcg_temp_new() tcg_temp_new_i64()
+#define tcg_global_reg_new tcg_global_reg_new_i64
+#define tcg_global_mem_new tcg_global_mem_new_i64
+#define tcg_temp_local_new() tcg_temp_local_new_i64()
+#define tcg_temp_free tcg_temp_free_i64
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64
+#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b)
+#endif
+
+/* debug info: write the PC of the corresponding QEMU CPU instruction */
+static inline void tcg_gen_debug_insn_start(uint64_t pc)
+{
+    /* XXX: must really use a 32 bit size for TCGArg in all cases */
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+    tcg_gen_op2ii(INDEX_op_debug_insn_start, 
+                  (uint32_t)(pc), (uint32_t)(pc >> 32));
+#else
+    tcg_gen_op1i(INDEX_op_debug_insn_start, pc);
+#endif
+}
+
+static inline void tcg_gen_exit_tb(tcg_target_long val)
+{
+    tcg_gen_op1i(INDEX_op_exit_tb, val);
+}
+
+static inline void tcg_gen_goto_tb(int idx)
+{
+    tcg_gen_op1i(INDEX_op_goto_tb, idx);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld8u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld8s, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld16u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld16s, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld32, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld32, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), addr, mem_index);
+#else
+    tcg_gen_op5i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret),
+                     TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_st8, arg, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_st8, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_st16, arg, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_st16, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op3i_i32(INDEX_op_qemu_st32, arg, addr, mem_index);
+#else
+    tcg_gen_op4i_i32(INDEX_op_qemu_st32, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_op4i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), addr,
+                     mem_index);
+#else
+    tcg_gen_op5i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg),
+                     TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i32(TCGV_PTR_TO_NAT(A))
+
+#else /* TCG_TARGET_REG_BITS == 32 */
+
+static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32u, ret, addr, mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32s, ret, addr, mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_ld64, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st8, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st16, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st32, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
+{
+    tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index);
+}
+
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i64(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i64(TCGV_PTR_TO_NAT(A))
+
+#endif /* TCG_TARGET_REG_BITS != 32 */
+
+#if TARGET_LONG_BITS == 64
+#define tcg_gen_movi_tl tcg_gen_movi_i64
+#define tcg_gen_mov_tl tcg_gen_mov_i64
+#define tcg_gen_ld8u_tl tcg_gen_ld8u_i64
+#define tcg_gen_ld8s_tl tcg_gen_ld8s_i64
+#define tcg_gen_ld16u_tl tcg_gen_ld16u_i64
+#define tcg_gen_ld16s_tl tcg_gen_ld16s_i64
+#define tcg_gen_ld32u_tl tcg_gen_ld32u_i64
+#define tcg_gen_ld32s_tl tcg_gen_ld32s_i64
+#define tcg_gen_ld_tl tcg_gen_ld_i64
+#define tcg_gen_st8_tl tcg_gen_st8_i64
+#define tcg_gen_st16_tl tcg_gen_st16_i64
+#define tcg_gen_st32_tl tcg_gen_st32_i64
+#define tcg_gen_st_tl tcg_gen_st_i64
+#define tcg_gen_add_tl tcg_gen_add_i64
+#define tcg_gen_addi_tl tcg_gen_addi_i64
+#define tcg_gen_sub_tl tcg_gen_sub_i64
+#define tcg_gen_neg_tl tcg_gen_neg_i64
+#define tcg_gen_subfi_tl tcg_gen_subfi_i64
+#define tcg_gen_subi_tl tcg_gen_subi_i64
+#define tcg_gen_and_tl tcg_gen_and_i64
+#define tcg_gen_andi_tl tcg_gen_andi_i64
+#define tcg_gen_or_tl tcg_gen_or_i64
+#define tcg_gen_ori_tl tcg_gen_ori_i64
+#define tcg_gen_xor_tl tcg_gen_xor_i64
+#define tcg_gen_xori_tl tcg_gen_xori_i64
+#define tcg_gen_not_tl tcg_gen_not_i64
+#define tcg_gen_shl_tl tcg_gen_shl_i64
+#define tcg_gen_shli_tl tcg_gen_shli_i64
+#define tcg_gen_shr_tl tcg_gen_shr_i64
+#define tcg_gen_shri_tl tcg_gen_shri_i64
+#define tcg_gen_sar_tl tcg_gen_sar_i64
+#define tcg_gen_sari_tl tcg_gen_sari_i64
+#define tcg_gen_brcond_tl tcg_gen_brcond_i64
+#define tcg_gen_brcondi_tl tcg_gen_brcondi_i64
+#define tcg_gen_setcond_tl tcg_gen_setcond_i64
+#define tcg_gen_setcondi_tl tcg_gen_setcondi_i64
+#define tcg_gen_mul_tl tcg_gen_mul_i64
+#define tcg_gen_muli_tl tcg_gen_muli_i64
+#define tcg_gen_div_tl tcg_gen_div_i64
+#define tcg_gen_rem_tl tcg_gen_rem_i64
+#define tcg_gen_divu_tl tcg_gen_divu_i64
+#define tcg_gen_remu_tl tcg_gen_remu_i64
+#define tcg_gen_discard_tl tcg_gen_discard_i64
+#define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32
+#define tcg_gen_trunc_i64_tl tcg_gen_mov_i64
+#define tcg_gen_extu_i32_tl tcg_gen_extu_i32_i64
+#define tcg_gen_ext_i32_tl tcg_gen_ext_i32_i64
+#define tcg_gen_extu_tl_i64 tcg_gen_mov_i64
+#define tcg_gen_ext_tl_i64 tcg_gen_mov_i64
+#define tcg_gen_ext8u_tl tcg_gen_ext8u_i64
+#define tcg_gen_ext8s_tl tcg_gen_ext8s_i64
+#define tcg_gen_ext16u_tl tcg_gen_ext16u_i64
+#define tcg_gen_ext16s_tl tcg_gen_ext16s_i64
+#define tcg_gen_ext32u_tl tcg_gen_ext32u_i64
+#define tcg_gen_ext32s_tl tcg_gen_ext32s_i64
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i64
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64
+#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64
+#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i64
+#define tcg_gen_eqv_tl tcg_gen_eqv_i64
+#define tcg_gen_nand_tl tcg_gen_nand_i64
+#define tcg_gen_nor_tl tcg_gen_nor_i64
+#define tcg_gen_orc_tl tcg_gen_orc_i64
+#define tcg_gen_rotl_tl tcg_gen_rotl_i64
+#define tcg_gen_rotli_tl tcg_gen_rotli_i64
+#define tcg_gen_rotr_tl tcg_gen_rotr_i64
+#define tcg_gen_rotri_tl tcg_gen_rotri_i64
+#define tcg_gen_deposit_tl tcg_gen_deposit_i64
+#define tcg_const_tl tcg_const_i64
+#define tcg_const_local_tl tcg_const_local_i64
+#else
+#define tcg_gen_movi_tl tcg_gen_movi_i32
+#define tcg_gen_mov_tl tcg_gen_mov_i32
+#define tcg_gen_ld8u_tl tcg_gen_ld8u_i32
+#define tcg_gen_ld8s_tl tcg_gen_ld8s_i32
+#define tcg_gen_ld16u_tl tcg_gen_ld16u_i32
+#define tcg_gen_ld16s_tl tcg_gen_ld16s_i32
+#define tcg_gen_ld32u_tl tcg_gen_ld_i32
+#define tcg_gen_ld32s_tl tcg_gen_ld_i32
+#define tcg_gen_ld_tl tcg_gen_ld_i32
+#define tcg_gen_st8_tl tcg_gen_st8_i32
+#define tcg_gen_st16_tl tcg_gen_st16_i32
+#define tcg_gen_st32_tl tcg_gen_st_i32
+#define tcg_gen_st_tl tcg_gen_st_i32
+#define tcg_gen_add_tl tcg_gen_add_i32
+#define tcg_gen_addi_tl tcg_gen_addi_i32
+#define tcg_gen_sub_tl tcg_gen_sub_i32
+#define tcg_gen_neg_tl tcg_gen_neg_i32
+#define tcg_gen_subfi_tl tcg_gen_subfi_i32
+#define tcg_gen_subi_tl tcg_gen_subi_i32
+#define tcg_gen_and_tl tcg_gen_and_i32
+#define tcg_gen_andi_tl tcg_gen_andi_i32
+#define tcg_gen_or_tl tcg_gen_or_i32
+#define tcg_gen_ori_tl tcg_gen_ori_i32
+#define tcg_gen_xor_tl tcg_gen_xor_i32
+#define tcg_gen_xori_tl tcg_gen_xori_i32
+#define tcg_gen_not_tl tcg_gen_not_i32
+#define tcg_gen_shl_tl tcg_gen_shl_i32
+#define tcg_gen_shli_tl tcg_gen_shli_i32
+#define tcg_gen_shr_tl tcg_gen_shr_i32
+#define tcg_gen_shri_tl tcg_gen_shri_i32
+#define tcg_gen_sar_tl tcg_gen_sar_i32
+#define tcg_gen_sari_tl tcg_gen_sari_i32
+#define tcg_gen_brcond_tl tcg_gen_brcond_i32
+#define tcg_gen_brcondi_tl tcg_gen_brcondi_i32
+#define tcg_gen_setcond_tl tcg_gen_setcond_i32
+#define tcg_gen_setcondi_tl tcg_gen_setcondi_i32
+#define tcg_gen_mul_tl tcg_gen_mul_i32
+#define tcg_gen_muli_tl tcg_gen_muli_i32
+#define tcg_gen_div_tl tcg_gen_div_i32
+#define tcg_gen_rem_tl tcg_gen_rem_i32
+#define tcg_gen_divu_tl tcg_gen_divu_i32
+#define tcg_gen_remu_tl tcg_gen_remu_i32
+#define tcg_gen_discard_tl tcg_gen_discard_i32
+#define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32
+#define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32
+#define tcg_gen_extu_i32_tl tcg_gen_mov_i32
+#define tcg_gen_ext_i32_tl tcg_gen_mov_i32
+#define tcg_gen_extu_tl_i64 tcg_gen_extu_i32_i64
+#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64
+#define tcg_gen_ext8u_tl tcg_gen_ext8u_i32
+#define tcg_gen_ext8s_tl tcg_gen_ext8s_i32
+#define tcg_gen_ext16u_tl tcg_gen_ext16u_i32
+#define tcg_gen_ext16s_tl tcg_gen_ext16s_i32
+#define tcg_gen_ext32u_tl tcg_gen_mov_i32
+#define tcg_gen_ext32s_tl tcg_gen_mov_i32
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32
+#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i32
+#define tcg_gen_eqv_tl tcg_gen_eqv_i32
+#define tcg_gen_nand_tl tcg_gen_nand_i32
+#define tcg_gen_nor_tl tcg_gen_nor_i32
+#define tcg_gen_orc_tl tcg_gen_orc_i32
+#define tcg_gen_rotl_tl tcg_gen_rotl_i32
+#define tcg_gen_rotli_tl tcg_gen_rotli_i32
+#define tcg_gen_rotr_tl tcg_gen_rotr_i32
+#define tcg_gen_rotri_tl tcg_gen_rotri_i32
+#define tcg_gen_deposit_tl tcg_gen_deposit_i32
+#define tcg_const_tl tcg_const_i32
+#define tcg_const_local_tl tcg_const_local_i32
+#endif
+
+#if TCG_TARGET_REG_BITS == 32
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i32(TCGV_PTR_TO_NAT(R), \
+                                               TCGV_PTR_TO_NAT(A), \
+                                               TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i32(TCGV_PTR_TO_NAT(R), \
+                                                 TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_mov_i32(TCGV_PTR_TO_NAT(R), (A))
+#else /* TCG_TARGET_REG_BITS == 32 */
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i64(TCGV_PTR_TO_NAT(R), \
+                                               TCGV_PTR_TO_NAT(A), \
+                                               TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R),   \
+                                                 TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
+#endif /* TCG_TARGET_REG_BITS != 32 */
diff --git a/qemu-0.15.x/tcg/tcg-opc.h b/qemu-0.15.x/tcg/tcg-opc.h
new file mode 100644
index 0000000..2c7ca1a
--- /dev/null
+++ b/qemu-0.15.x/tcg/tcg-opc.h
@@ -0,0 +1,310 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+
+/*
+ * DEF(name, oargs, iargs, cargs, flags)
+ */
+
+/* predefined ops */
+DEF(end, 0, 0, 0, 0) /* must be kept first */
+DEF(nop, 0, 0, 0, 0)
+DEF(nop1, 0, 0, 1, 0)
+DEF(nop2, 0, 0, 2, 0)
+DEF(nop3, 0, 0, 3, 0)
+DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */
+
+DEF(discard, 1, 0, 0, 0)
+
+DEF(set_label, 0, 0, 1, 0)
+DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
+DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+
+DEF(mov_i32, 1, 1, 0, 0)
+DEF(movi_i32, 1, 0, 1, 0)
+DEF(setcond_i32, 1, 2, 1, 0)
+/* load/store */
+DEF(ld8u_i32, 1, 1, 1, 0)
+DEF(ld8s_i32, 1, 1, 1, 0)
+DEF(ld16u_i32, 1, 1, 1, 0)
+DEF(ld16s_i32, 1, 1, 1, 0)
+DEF(ld_i32, 1, 1, 1, 0)
+DEF(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+/* arith */
+DEF(add_i32, 1, 2, 0, 0)
+DEF(sub_i32, 1, 2, 0, 0)
+DEF(mul_i32, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_div_i32
+DEF(div_i32, 1, 2, 0, 0)
+DEF(divu_i32, 1, 2, 0, 0)
+DEF(rem_i32, 1, 2, 0, 0)
+DEF(remu_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_div2_i32
+DEF(div2_i32, 2, 3, 0, 0)
+DEF(divu2_i32, 2, 3, 0, 0)
+#endif
+DEF(and_i32, 1, 2, 0, 0)
+DEF(or_i32, 1, 2, 0, 0)
+DEF(xor_i32, 1, 2, 0, 0)
+/* shifts/rotates */
+DEF(shl_i32, 1, 2, 0, 0)
+DEF(shr_i32, 1, 2, 0, 0)
+DEF(sar_i32, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i32
+DEF(rotl_i32, 1, 2, 0, 0)
+DEF(rotr_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_deposit_i32
+DEF(deposit_i32, 1, 2, 2, 0)
+#endif
+
+DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+#if TCG_TARGET_REG_BITS == 32
+DEF(add2_i32, 2, 4, 0, 0)
+DEF(sub2_i32, 2, 4, 0, 0)
+DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(mulu2_i32, 2, 2, 0, 0)
+DEF(setcond2_i32, 1, 4, 1, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8s_i32
+DEF(ext8s_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16s_i32
+DEF(ext16s_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8u_i32
+DEF(ext8u_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16u_i32
+DEF(ext16u_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap16_i32
+DEF(bswap16_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap32_i32
+DEF(bswap32_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i32
+DEF(not_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_neg_i32
+DEF(neg_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_andc_i32
+DEF(andc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i32
+DEF(orc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_eqv_i32
+DEF(eqv_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nand_i32
+DEF(nand_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nor_i32
+DEF(nor_i32, 1, 2, 0, 0)
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+DEF(mov_i64, 1, 1, 0, 0)
+DEF(movi_i64, 1, 0, 1, 0)
+DEF(setcond_i64, 1, 2, 1, 0)
+/* load/store */
+DEF(ld8u_i64, 1, 1, 1, 0)
+DEF(ld8s_i64, 1, 1, 1, 0)
+DEF(ld16u_i64, 1, 1, 1, 0)
+DEF(ld16s_i64, 1, 1, 1, 0)
+DEF(ld32u_i64, 1, 1, 1, 0)
+DEF(ld32s_i64, 1, 1, 1, 0)
+DEF(ld_i64, 1, 1, 1, 0)
+DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+/* arith */
+DEF(add_i64, 1, 2, 0, 0)
+DEF(sub_i64, 1, 2, 0, 0)
+DEF(mul_i64, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_div_i64
+DEF(div_i64, 1, 2, 0, 0)
+DEF(divu_i64, 1, 2, 0, 0)
+DEF(rem_i64, 1, 2, 0, 0)
+DEF(remu_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_div2_i64
+DEF(div2_i64, 2, 3, 0, 0)
+DEF(divu2_i64, 2, 3, 0, 0)
+#endif
+DEF(and_i64, 1, 2, 0, 0)
+DEF(or_i64, 1, 2, 0, 0)
+DEF(xor_i64, 1, 2, 0, 0)
+/* shifts/rotates */
+DEF(shl_i64, 1, 2, 0, 0)
+DEF(shr_i64, 1, 2, 0, 0)
+DEF(sar_i64, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i64
+DEF(rotl_i64, 1, 2, 0, 0)
+DEF(rotr_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_deposit_i64
+DEF(deposit_i64, 1, 2, 2, 0)
+#endif
+
+DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+#ifdef TCG_TARGET_HAS_ext8s_i64
+DEF(ext8s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16s_i64
+DEF(ext16s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext32s_i64
+DEF(ext32s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8u_i64
+DEF(ext8u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16u_i64
+DEF(ext16u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext32u_i64
+DEF(ext32u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap16_i64
+DEF(bswap16_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap32_i64
+DEF(bswap32_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap64_i64
+DEF(bswap64_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i64
+DEF(not_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_neg_i64
+DEF(neg_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_andc_i64
+DEF(andc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i64
+DEF(orc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_eqv_i64
+DEF(eqv_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nand_i64
+DEF(nand_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nor_i64
+DEF(nor_i64, 1, 2, 0, 0)
+#endif
+#endif
+
+/* QEMU specific */
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+DEF(debug_insn_start, 0, 0, 2, 0)
+#else
+DEF(debug_insn_start, 0, 0, 1, 0)
+#endif
+DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op
+   constants must be defined */
+#if TCG_TARGET_REG_BITS == 32
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld32, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+
+#else /* TCG_TARGET_REG_BITS == 32 */
+
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+
+#endif /* TCG_TARGET_REG_BITS != 32 */
+
+#undef DEF
diff --git a/qemu-0.15.x/tcg/tcg-runtime.h b/qemu-0.15.x/tcg/tcg-runtime.h
new file mode 100644
index 0000000..5615b13
--- /dev/null
+++ b/qemu-0.15.x/tcg/tcg-runtime.h
@@ -0,0 +1,18 @@
+#ifndef TCG_RUNTIME_H
+#define TCG_RUNTIME_H
+
+/* tcg-runtime.c */
+int32_t tcg_helper_div_i32(int32_t arg1, int32_t arg2);
+int32_t tcg_helper_rem_i32(int32_t arg1, int32_t arg2);
+uint32_t tcg_helper_divu_i32(uint32_t arg1, uint32_t arg2);
+uint32_t tcg_helper_remu_i32(uint32_t arg1, uint32_t arg2);
+
+int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2);
+int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
+int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2);
+int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
+int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
+uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
+uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
+
+#endif
diff --git a/qemu-0.15.x/tcg/tcg.c b/qemu-0.15.x/tcg/tcg.c
new file mode 100644
index 0000000..c05413b
--- /dev/null
+++ b/qemu-0.15.x/tcg/tcg.c
@@ -0,0 +1,2224 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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.
+ */
+
+/* define it to use liveness analysis (better code) */
+#define USE_LIVENESS_ANALYSIS
+
+#include "config.h"
+
+#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
+/* define it to suppress various consistency checks (faster) */
+#define NDEBUG
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#ifdef _WIN32
+#include <malloc.h>
+#endif
+#ifdef _AIX
+#include <alloca.h>
+#endif
+
+#include "qemu-common.h"
+#include "cache-utils.h"
+#include "host-utils.h"
+#include "qemu-timer.h"
+
+/* Note: the long term plan is to reduce the dependancies on the QEMU
+   CPU definitions. Currently they are used for qemu_ld/st
+   instructions */
+#define NO_CPU_IO_DEFS
+#include "cpu.h"
+
+#include "tcg-op.h"
+#include "elf.h"
+
+#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
+#error GUEST_BASE not supported on this host.
+#endif
+
+static void tcg_target_init(TCGContext *s);
+static void tcg_target_qemu_prologue(TCGContext *s);
+static void patch_reloc(uint8_t *code_ptr, int type, 
+                        tcg_target_long value, tcg_target_long addend);
+
+static TCGOpDef tcg_op_defs[] = {
+#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
+#include "tcg-opc.h"
+#undef DEF
+};
+
+static TCGRegSet tcg_target_available_regs[2];
+static TCGRegSet tcg_target_call_clobber_regs;
+
+/* XXX: move that inside the context */
+uint16_t *gen_opc_ptr;
+TCGArg *gen_opparam_ptr;
+
+static inline void tcg_out8(TCGContext *s, uint8_t v)
+{
+    *s->code_ptr++ = v;
+}
+
+static inline void tcg_out16(TCGContext *s, uint16_t v)
+{
+    *(uint16_t *)s->code_ptr = v;
+    s->code_ptr += 2;
+}
+
+static inline void tcg_out32(TCGContext *s, uint32_t v)
+{
+    *(uint32_t *)s->code_ptr = v;
+    s->code_ptr += 4;
+}
+
+/* label relocation processing */
+
+static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
+                          int label_index, long addend)
+{
+    TCGLabel *l;
+    TCGRelocation *r;
+
+    l = &s->labels[label_index];
+    if (l->has_value) {
+        /* FIXME: This may break relocations on RISC targets that
+           modify instruction fields in place.  The caller may not have 
+           written the initial value.  */
+        patch_reloc(code_ptr, type, l->u.value, addend);
+    } else {
+        /* add a new relocation entry */
+        r = tcg_malloc(sizeof(TCGRelocation));
+        r->type = type;
+        r->ptr = code_ptr;
+        r->addend = addend;
+        r->next = l->u.first_reloc;
+        l->u.first_reloc = r;
+    }
+}
+
+static void tcg_out_label(TCGContext *s, int label_index, 
+                          tcg_target_long value)
+{
+    TCGLabel *l;
+    TCGRelocation *r;
+
+    l = &s->labels[label_index];
+    if (l->has_value)
+        tcg_abort();
+    r = l->u.first_reloc;
+    while (r != NULL) {
+        patch_reloc(r->ptr, r->type, value, r->addend);
+        r = r->next;
+    }
+    l->has_value = 1;
+    l->u.value = value;
+}
+
+int gen_new_label(void)
+{
+    TCGContext *s = &tcg_ctx;
+    int idx;
+    TCGLabel *l;
+
+    if (s->nb_labels >= TCG_MAX_LABELS)
+        tcg_abort();
+    idx = s->nb_labels++;
+    l = &s->labels[idx];
+    l->has_value = 0;
+    l->u.first_reloc = NULL;
+    return idx;
+}
+
+#include "tcg-target.c"
+
+/* pool based memory allocation */
+void *tcg_malloc_internal(TCGContext *s, int size)
+{
+    TCGPool *p;
+    int pool_size;
+    
+    if (size > TCG_POOL_CHUNK_SIZE) {
+        /* big malloc: insert a new pool (XXX: could optimize) */
+        p = qemu_malloc(sizeof(TCGPool) + size);
+        p->size = size;
+        if (s->pool_current)
+            s->pool_current->next = p;
+        else
+            s->pool_first = p;
+        p->next = s->pool_current;
+    } else {
+        p = s->pool_current;
+        if (!p) {
+            p = s->pool_first;
+            if (!p)
+                goto new_pool;
+        } else {
+            if (!p->next) {
+            new_pool:
+                pool_size = TCG_POOL_CHUNK_SIZE;
+                p = qemu_malloc(sizeof(TCGPool) + pool_size);
+                p->size = pool_size;
+                p->next = NULL;
+                if (s->pool_current) 
+                    s->pool_current->next = p;
+                else
+                    s->pool_first = p;
+            } else {
+                p = p->next;
+            }
+        }
+    }
+    s->pool_current = p;
+    s->pool_cur = p->data + size;
+    s->pool_end = p->data + p->size;
+    return p->data;
+}
+
+void tcg_pool_reset(TCGContext *s)
+{
+    s->pool_cur = s->pool_end = NULL;
+    s->pool_current = NULL;
+}
+
+void tcg_context_init(TCGContext *s)
+{
+    int op, total_args, n;
+    TCGOpDef *def;
+    TCGArgConstraint *args_ct;
+    int *sorted_args;
+
+    memset(s, 0, sizeof(*s));
+    s->temps = s->static_temps;
+    s->nb_globals = 0;
+    
+    /* Count total number of arguments and allocate the corresponding
+       space */
+    total_args = 0;
+    for(op = 0; op < NB_OPS; op++) {
+        def = &tcg_op_defs[op];
+        n = def->nb_iargs + def->nb_oargs;
+        total_args += n;
+    }
+
+    args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
+    sorted_args = qemu_malloc(sizeof(int) * total_args);
+
+    for(op = 0; op < NB_OPS; op++) {
+        def = &tcg_op_defs[op];
+        def->args_ct = args_ct;
+        def->sorted_args = sorted_args;
+        n = def->nb_iargs + def->nb_oargs;
+        sorted_args += n;
+        args_ct += n;
+    }
+    
+    tcg_target_init(s);
+}
+
+void tcg_prologue_init(TCGContext *s)
+{
+    /* init global prologue and epilogue */
+    s->code_buf = code_gen_prologue;
+    s->code_ptr = s->code_buf;
+    tcg_target_qemu_prologue(s);
+    flush_icache_range((unsigned long)s->code_buf, 
+                       (unsigned long)s->code_ptr);
+}
+
+void tcg_set_frame(TCGContext *s, int reg,
+                   tcg_target_long start, tcg_target_long size)
+{
+    s->frame_start = start;
+    s->frame_end = start + size;
+    s->frame_reg = reg;
+}
+
+void tcg_func_start(TCGContext *s)
+{
+    int i;
+    tcg_pool_reset(s);
+    s->nb_temps = s->nb_globals;
+    for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
+        s->first_free_temp[i] = -1;
+    s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
+    s->nb_labels = 0;
+    s->current_frame_offset = s->frame_start;
+
+    gen_opc_ptr = gen_opc_buf;
+    gen_opparam_ptr = gen_opparam_buf;
+}
+
+static inline void tcg_temp_alloc(TCGContext *s, int n)
+{
+    if (n > TCG_MAX_TEMPS)
+        tcg_abort();
+}
+
+static inline int tcg_global_reg_new_internal(TCGType type, int reg,
+                                              const char *name)
+{
+    TCGContext *s = &tcg_ctx;
+    TCGTemp *ts;
+    int idx;
+
+#if TCG_TARGET_REG_BITS == 32
+    if (type != TCG_TYPE_I32)
+        tcg_abort();
+#endif
+    if (tcg_regset_test_reg(s->reserved_regs, reg))
+        tcg_abort();
+    idx = s->nb_globals;
+    tcg_temp_alloc(s, s->nb_globals + 1);
+    ts = &s->temps[s->nb_globals];
+    ts->base_type = type;
+    ts->type = type;
+    ts->fixed_reg = 1;
+    ts->reg = reg;
+    ts->name = name;
+    s->nb_globals++;
+    tcg_regset_set_reg(s->reserved_regs, reg);
+    return idx;
+}
+
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
+{
+    int idx;
+
+    idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
+    return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
+{
+    int idx;
+
+    idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_global_mem_new_internal(TCGType type, int reg,
+                                              tcg_target_long offset,
+                                              const char *name)
+{
+    TCGContext *s = &tcg_ctx;
+    TCGTemp *ts;
+    int idx;
+
+    idx = s->nb_globals;
+#if TCG_TARGET_REG_BITS == 32
+    if (type == TCG_TYPE_I64) {
+        char buf[64];
+        tcg_temp_alloc(s, s->nb_globals + 2);
+        ts = &s->temps[s->nb_globals];
+        ts->base_type = type;
+        ts->type = TCG_TYPE_I32;
+        ts->fixed_reg = 0;
+        ts->mem_allocated = 1;
+        ts->mem_reg = reg;
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+        ts->mem_offset = offset + 4;
+#else
+        ts->mem_offset = offset;
+#endif
+        pstrcpy(buf, sizeof(buf), name);
+        pstrcat(buf, sizeof(buf), "_0");
+        ts->name = strdup(buf);
+        ts++;
+
+        ts->base_type = type;
+        ts->type = TCG_TYPE_I32;
+        ts->fixed_reg = 0;
+        ts->mem_allocated = 1;
+        ts->mem_reg = reg;
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+        ts->mem_offset = offset;
+#else
+        ts->mem_offset = offset + 4;
+#endif
+        pstrcpy(buf, sizeof(buf), name);
+        pstrcat(buf, sizeof(buf), "_1");
+        ts->name = strdup(buf);
+
+        s->nb_globals += 2;
+    } else
+#endif
+    {
+        tcg_temp_alloc(s, s->nb_globals + 1);
+        ts = &s->temps[s->nb_globals];
+        ts->base_type = type;
+        ts->type = type;
+        ts->fixed_reg = 0;
+        ts->mem_allocated = 1;
+        ts->mem_reg = reg;
+        ts->mem_offset = offset;
+        ts->name = name;
+        s->nb_globals++;
+    }
+    return idx;
+}
+
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+                                const char *name)
+{
+    int idx;
+
+    idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
+    return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+                                const char *name)
+{
+    int idx;
+
+    idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_temp_new_internal(TCGType type, int temp_local)
+{
+    TCGContext *s = &tcg_ctx;
+    TCGTemp *ts;
+    int idx, k;
+
+    k = type;
+    if (temp_local)
+        k += TCG_TYPE_COUNT;
+    idx = s->first_free_temp[k];
+    if (idx != -1) {
+        /* There is already an available temp with the
+           right type */
+        ts = &s->temps[idx];
+        s->first_free_temp[k] = ts->next_free_temp;
+        ts->temp_allocated = 1;
+        assert(ts->temp_local == temp_local);
+    } else {
+        idx = s->nb_temps;
+#if TCG_TARGET_REG_BITS == 32
+        if (type == TCG_TYPE_I64) {
+            tcg_temp_alloc(s, s->nb_temps + 2);
+            ts = &s->temps[s->nb_temps];
+            ts->base_type = type;
+            ts->type = TCG_TYPE_I32;
+            ts->temp_allocated = 1;
+            ts->temp_local = temp_local;
+            ts->name = NULL;
+            ts++;
+            ts->base_type = TCG_TYPE_I32;
+            ts->type = TCG_TYPE_I32;
+            ts->temp_allocated = 1;
+            ts->temp_local = temp_local;
+            ts->name = NULL;
+            s->nb_temps += 2;
+        } else
+#endif
+        {
+            tcg_temp_alloc(s, s->nb_temps + 1);
+            ts = &s->temps[s->nb_temps];
+            ts->base_type = type;
+            ts->type = type;
+            ts->temp_allocated = 1;
+            ts->temp_local = temp_local;
+            ts->name = NULL;
+            s->nb_temps++;
+        }
+    }
+
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use++;
+#endif
+    return idx;
+}
+
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
+{
+    int idx;
+
+    idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
+    return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
+{
+    int idx;
+
+    idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline void tcg_temp_free_internal(int idx)
+{
+    TCGContext *s = &tcg_ctx;
+    TCGTemp *ts;
+    int k;
+
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use--;
+    if (s->temps_in_use < 0) {
+        fprintf(stderr, "More temporaries freed than allocated!\n");
+    }
+#endif
+
+    assert(idx >= s->nb_globals && idx < s->nb_temps);
+    ts = &s->temps[idx];
+    assert(ts->temp_allocated != 0);
+    ts->temp_allocated = 0;
+    k = ts->base_type;
+    if (ts->temp_local)
+        k += TCG_TYPE_COUNT;
+    ts->next_free_temp = s->first_free_temp[k];
+    s->first_free_temp[k] = idx;
+}
+
+void tcg_temp_free_i32(TCGv_i32 arg)
+{
+    tcg_temp_free_internal(GET_TCGV_I32(arg));
+}
+
+void tcg_temp_free_i64(TCGv_i64 arg)
+{
+    tcg_temp_free_internal(GET_TCGV_I64(arg));
+}
+
+TCGv_i32 tcg_const_i32(int32_t val)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_movi_i32(t0, val);
+    return t0;
+}
+
+TCGv_i64 tcg_const_i64(int64_t val)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_movi_i64(t0, val);
+    return t0;
+}
+
+TCGv_i32 tcg_const_local_i32(int32_t val)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_local_new_i32();
+    tcg_gen_movi_i32(t0, val);
+    return t0;
+}
+
+TCGv_i64 tcg_const_local_i64(int64_t val)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_local_new_i64();
+    tcg_gen_movi_i64(t0, val);
+    return t0;
+}
+
+#if defined(CONFIG_DEBUG_TCG)
+void tcg_clear_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    s->temps_in_use = 0;
+}
+
+int tcg_check_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    if (s->temps_in_use) {
+        /* Clear the count so that we don't give another
+         * warning immediately next time around.
+         */
+        s->temps_in_use = 0;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+void tcg_register_helper(void *func, const char *name)
+{
+    TCGContext *s = &tcg_ctx;
+    int n;
+    if ((s->nb_helpers + 1) > s->allocated_helpers) {
+        n = s->allocated_helpers;
+        if (n == 0) {
+            n = 4;
+        } else {
+            n *= 2;
+        }
+        s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
+        s->allocated_helpers = n;
+    }
+    s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
+    s->helpers[s->nb_helpers].name = name;
+    s->nb_helpers++;
+}
+
+/* Note: we convert the 64 bit args to 32 bit and do some alignment
+   and endian swap. Maybe it would be better to do the alignment
+   and endian swap in tcg_reg_alloc_call(). */
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+                   int sizemask, TCGArg ret, int nargs, TCGArg *args)
+{
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
+    int call_type;
+#endif
+    int i;
+    int real_args;
+    int nb_rets;
+    TCGArg *nparam;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+    for (i = 0; i < nargs; ++i) {
+        int is_64bit = sizemask & (1 << (i+1)*2);
+        int is_signed = sizemask & (2 << (i+1)*2);
+        if (!is_64bit) {
+            TCGv_i64 temp = tcg_temp_new_i64();
+            TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
+            if (is_signed) {
+                tcg_gen_ext32s_i64(temp, orig);
+            } else {
+                tcg_gen_ext32u_i64(temp, orig);
+            }
+            args[i] = GET_TCGV_I64(temp);
+        }
+    }
+#endif /* TCG_TARGET_EXTEND_ARGS */
+
+    *gen_opc_ptr++ = INDEX_op_call;
+    nparam = gen_opparam_ptr++;
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
+    call_type = (flags & TCG_CALL_TYPE_MASK);
+#endif
+    if (ret != TCG_CALL_DUMMY_ARG) {
+#if TCG_TARGET_REG_BITS < 64
+        if (sizemask & 1) {
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+            *gen_opparam_ptr++ = ret + 1;
+            *gen_opparam_ptr++ = ret;
+#else
+            *gen_opparam_ptr++ = ret;
+            *gen_opparam_ptr++ = ret + 1;
+#endif
+            nb_rets = 2;
+        } else
+#endif
+        {
+            *gen_opparam_ptr++ = ret;
+            nb_rets = 1;
+        }
+    } else {
+        nb_rets = 0;
+    }
+    real_args = 0;
+    for (i = 0; i < nargs; i++) {
+#if TCG_TARGET_REG_BITS < 64
+        int is_64bit = sizemask & (1 << (i+1)*2);
+        if (is_64bit) {
+#ifdef TCG_TARGET_I386
+            /* REGPARM case: if the third parameter is 64 bit, it is
+               allocated on the stack */
+            if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
+                call_type = TCG_CALL_TYPE_REGPARM_2;
+                flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
+            }
+#endif
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+            /* some targets want aligned 64 bit args */
+            if (real_args & 1) {
+                *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
+                real_args++;
+            }
+#endif
+	    /* If stack grows up, then we will be placing successive
+	       arguments at lower addresses, which means we need to
+	       reverse the order compared to how we would normally
+	       treat either big or little-endian.  For those arguments
+	       that will wind up in registers, this still works for
+	       HPPA (the only current STACK_GROWSUP target) since the
+	       argument registers are *also* allocated in decreasing
+	       order.  If another such target is added, this logic may
+	       have to get more complicated to differentiate between
+	       stack arguments and register arguments.  */
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
+            *gen_opparam_ptr++ = args[i] + 1;
+            *gen_opparam_ptr++ = args[i];
+#else
+            *gen_opparam_ptr++ = args[i];
+            *gen_opparam_ptr++ = args[i] + 1;
+#endif
+            real_args += 2;
+            continue;
+        }
+#endif /* TCG_TARGET_REG_BITS < 64 */
+
+        *gen_opparam_ptr++ = args[i];
+        real_args++;
+    }
+    *gen_opparam_ptr++ = GET_TCGV_PTR(func);
+
+    *gen_opparam_ptr++ = flags;
+
+    *nparam = (nb_rets << 16) | (real_args + 1);
+
+    /* total parameters, needed to go backward in the instruction stream */
+    *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+    for (i = 0; i < nargs; ++i) {
+        int is_64bit = sizemask & (1 << (i+1)*2);
+        if (!is_64bit) {
+            TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
+            tcg_temp_free_i64(temp);
+        }
+    }
+#endif /* TCG_TARGET_EXTEND_ARGS */
+}
+
+#if TCG_TARGET_REG_BITS == 32
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
+                        int c, int right, int arith)
+{
+    if (c == 0) {
+        tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
+        tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
+    } else if (c >= 32) {
+        c -= 32;
+        if (right) {
+            if (arith) {
+                tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
+                tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
+            } else {
+                tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
+                tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+            }
+        } else {
+            tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
+            tcg_gen_movi_i32(TCGV_LOW(ret), 0);
+        }
+    } else {
+        TCGv_i32 t0, t1;
+
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+        if (right) {
+            tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
+            if (arith)
+                tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
+            else
+                tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
+            tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
+            tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
+            tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
+        } else {
+            tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
+            /* Note: ret can be the same as arg1, so we use t1 */
+            tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
+            tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
+            tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
+            tcg_gen_mov_i32(TCGV_LOW(ret), t1);
+        }
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+    }
+}
+#endif
+
+
+static void tcg_reg_alloc_start(TCGContext *s)
+{
+    int i;
+    TCGTemp *ts;
+    for(i = 0; i < s->nb_globals; i++) {
+        ts = &s->temps[i];
+        if (ts->fixed_reg) {
+            ts->val_type = TEMP_VAL_REG;
+        } else {
+            ts->val_type = TEMP_VAL_MEM;
+        }
+    }
+    for(i = s->nb_globals; i < s->nb_temps; i++) {
+        ts = &s->temps[i];
+        ts->val_type = TEMP_VAL_DEAD;
+        ts->mem_allocated = 0;
+        ts->fixed_reg = 0;
+    }
+    for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+        s->reg_to_temp[i] = -1;
+    }
+}
+
+static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
+                                 int idx)
+{
+    TCGTemp *ts;
+
+    ts = &s->temps[idx];
+    if (idx < s->nb_globals) {
+        pstrcpy(buf, buf_size, ts->name);
+    } else {
+        if (ts->temp_local) 
+            snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
+        else
+            snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
+    }
+    return buf;
+}
+
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
+{
+    return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
+}
+
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
+{
+    return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
+}
+
+static int helper_cmp(const void *p1, const void *p2)
+{
+    const TCGHelperInfo *th1 = p1;
+    const TCGHelperInfo *th2 = p2;
+    if (th1->func < th2->func)
+        return -1;
+    else if (th1->func == th2->func)
+        return 0;
+    else
+        return 1;
+}
+
+/* find helper definition (Note: A hash table would be better) */
+static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
+{
+    int m, m_min, m_max;
+    TCGHelperInfo *th;
+    tcg_target_ulong v;
+
+    if (unlikely(!s->helpers_sorted)) {
+        qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 
+              helper_cmp);
+        s->helpers_sorted = 1;
+    }
+
+    /* binary search */
+    m_min = 0;
+    m_max = s->nb_helpers - 1;
+    while (m_min <= m_max) {
+        m = (m_min + m_max) >> 1;
+        th = &s->helpers[m];
+        v = th->func;
+        if (v == val)
+            return th;
+        else if (val < v) {
+            m_max = m - 1;
+        } else {
+            m_min = m + 1;
+        }
+    }
+    return NULL;
+}
+
+static const char * const cond_name[] =
+{
+    [TCG_COND_EQ] = "eq",
+    [TCG_COND_NE] = "ne",
+    [TCG_COND_LT] = "lt",
+    [TCG_COND_GE] = "ge",
+    [TCG_COND_LE] = "le",
+    [TCG_COND_GT] = "gt",
+    [TCG_COND_LTU] = "ltu",
+    [TCG_COND_GEU] = "geu",
+    [TCG_COND_LEU] = "leu",
+    [TCG_COND_GTU] = "gtu"
+};
+
+void tcg_dump_ops(TCGContext *s, FILE *outfile)
+{
+    const uint16_t *opc_ptr;
+    const TCGArg *args;
+    TCGArg arg;
+    TCGOpcode c;
+    int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
+    const TCGOpDef *def;
+    char buf[128];
+
+    first_insn = 1;
+    opc_ptr = gen_opc_buf;
+    args = gen_opparam_buf;
+    while (opc_ptr < gen_opc_ptr) {
+        c = *opc_ptr++;
+        def = &tcg_op_defs[c];
+        if (c == INDEX_op_debug_insn_start) {
+            uint64_t pc;
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+            pc = ((uint64_t)args[1] << 32) | args[0];
+#else
+            pc = args[0];
+#endif
+            if (!first_insn) 
+                fprintf(outfile, "\n");
+            fprintf(outfile, " ---- 0x%" PRIx64, pc);
+            first_insn = 0;
+            nb_oargs = def->nb_oargs;
+            nb_iargs = def->nb_iargs;
+            nb_cargs = def->nb_cargs;
+        } else if (c == INDEX_op_call) {
+            TCGArg arg;
+
+            /* variable number of arguments */
+            arg = *args++;
+            nb_oargs = arg >> 16;
+            nb_iargs = arg & 0xffff;
+            nb_cargs = def->nb_cargs;
+
+            fprintf(outfile, " %s ", def->name);
+
+            /* function name */
+            fprintf(outfile, "%s",
+                    tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
+            /* flags */
+            fprintf(outfile, ",$0x%" TCG_PRIlx,
+                    args[nb_oargs + nb_iargs]);
+            /* nb out args */
+            fprintf(outfile, ",$%d", nb_oargs);
+            for(i = 0; i < nb_oargs; i++) {
+                fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
+            }
+            for(i = 0; i < (nb_iargs - 1); i++) {
+                fprintf(outfile, ",");
+                if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
+                    fprintf(outfile, "<dummy>");
+                } else {
+                    fprintf(outfile, "%s",
+                            tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
+                }
+            }
+        } else if (c == INDEX_op_movi_i32 
+#if TCG_TARGET_REG_BITS == 64
+                   || c == INDEX_op_movi_i64
+#endif
+                   ) {
+            tcg_target_ulong val;
+            TCGHelperInfo *th;
+
+            nb_oargs = def->nb_oargs;
+            nb_iargs = def->nb_iargs;
+            nb_cargs = def->nb_cargs;
+            fprintf(outfile, " %s %s,$", def->name, 
+                    tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
+            val = args[1];
+            th = tcg_find_helper(s, val);
+            if (th) {
+                fprintf(outfile, "%s", th->name);
+            } else {
+                if (c == INDEX_op_movi_i32)
+                    fprintf(outfile, "0x%x", (uint32_t)val);
+                else
+                    fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
+            }
+        } else {
+            fprintf(outfile, " %s ", def->name);
+            if (c == INDEX_op_nopn) {
+                /* variable number of arguments */
+                nb_cargs = *args;
+                nb_oargs = 0;
+                nb_iargs = 0;
+            } else {
+                nb_oargs = def->nb_oargs;
+                nb_iargs = def->nb_iargs;
+                nb_cargs = def->nb_cargs;
+            }
+            
+            k = 0;
+            for(i = 0; i < nb_oargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+            }
+            for(i = 0; i < nb_iargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+            }
+            switch (c) {
+            case INDEX_op_brcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+            case INDEX_op_brcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+            case INDEX_op_brcond_i64:
+#endif
+            case INDEX_op_setcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+            case INDEX_op_setcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+            case INDEX_op_setcond_i64:
+#endif
+                if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
+                    fprintf(outfile, ",%s", cond_name[args[k++]]);
+                else
+                    fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
+                i = 1;
+                break;
+            default:
+                i = 0;
+                break;
+            }
+            for(; i < nb_cargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                arg = args[k++];
+                fprintf(outfile, "$0x%" TCG_PRIlx, arg);
+            }
+        }
+        fprintf(outfile, "\n");
+        args += nb_iargs + nb_oargs + nb_cargs;
+    }
+}
+
+/* we give more priority to constraints with less registers */
+static int get_constraint_priority(const TCGOpDef *def, int k)
+{
+    const TCGArgConstraint *arg_ct;
+
+    int i, n;
+    arg_ct = &def->args_ct[k];
+    if (arg_ct->ct & TCG_CT_ALIAS) {
+        /* an alias is equivalent to a single register */
+        n = 1;
+    } else {
+        if (!(arg_ct->ct & TCG_CT_REG))
+            return 0;
+        n = 0;
+        for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+            if (tcg_regset_test_reg(arg_ct->u.regs, i))
+                n++;
+        }
+    }
+    return TCG_TARGET_NB_REGS - n + 1;
+}
+
+/* sort from highest priority to lowest */
+static void sort_constraints(TCGOpDef *def, int start, int n)
+{
+    int i, j, p1, p2, tmp;
+
+    for(i = 0; i < n; i++)
+        def->sorted_args[start + i] = start + i;
+    if (n <= 1)
+        return;
+    for(i = 0; i < n - 1; i++) {
+        for(j = i + 1; j < n; j++) {
+            p1 = get_constraint_priority(def, def->sorted_args[start + i]);
+            p2 = get_constraint_priority(def, def->sorted_args[start + j]);
+            if (p1 < p2) {
+                tmp = def->sorted_args[start + i];
+                def->sorted_args[start + i] = def->sorted_args[start + j];
+                def->sorted_args[start + j] = tmp;
+            }
+        }
+    }
+}
+
+void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
+{
+    TCGOpcode op;
+    TCGOpDef *def;
+    const char *ct_str;
+    int i, nb_args;
+
+    for(;;) {
+        if (tdefs->op == (TCGOpcode)-1)
+            break;
+        op = tdefs->op;
+        assert((unsigned)op < NB_OPS);
+        def = &tcg_op_defs[op];
+#if defined(CONFIG_DEBUG_TCG)
+        /* Duplicate entry in op definitions? */
+        assert(!def->used);
+        def->used = 1;
+#endif
+        nb_args = def->nb_iargs + def->nb_oargs;
+        for(i = 0; i < nb_args; i++) {
+            ct_str = tdefs->args_ct_str[i];
+            /* Incomplete TCGTargetOpDef entry? */
+            assert(ct_str != NULL);
+            tcg_regset_clear(def->args_ct[i].u.regs);
+            def->args_ct[i].ct = 0;
+            if (ct_str[0] >= '0' && ct_str[0] <= '9') {
+                int oarg;
+                oarg = ct_str[0] - '0';
+                assert(oarg < def->nb_oargs);
+                assert(def->args_ct[oarg].ct & TCG_CT_REG);
+                /* TCG_CT_ALIAS is for the output arguments. The input
+                   argument is tagged with TCG_CT_IALIAS. */
+                def->args_ct[i] = def->args_ct[oarg];
+                def->args_ct[oarg].ct = TCG_CT_ALIAS;
+                def->args_ct[oarg].alias_index = i;
+                def->args_ct[i].ct |= TCG_CT_IALIAS;
+                def->args_ct[i].alias_index = oarg;
+            } else {
+                for(;;) {
+                    if (*ct_str == '\0')
+                        break;
+                    switch(*ct_str) {
+                    case 'i':
+                        def->args_ct[i].ct |= TCG_CT_CONST;
+                        ct_str++;
+                        break;
+                    default:
+                        if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
+                            fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
+                                    ct_str, i, def->name);
+                            exit(1);
+                        }
+                    }
+                }
+            }
+        }
+
+        /* TCGTargetOpDef entry with too much information? */
+        assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+
+        /* sort the constraints (XXX: this is just an heuristic) */
+        sort_constraints(def, 0, def->nb_oargs);
+        sort_constraints(def, def->nb_oargs, def->nb_iargs);
+
+#if 0
+        {
+            int i;
+
+            printf("%s: sorted=", def->name);
+            for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
+                printf(" %d", def->sorted_args[i]);
+            printf("\n");
+        }
+#endif
+        tdefs++;
+    }
+
+#if defined(CONFIG_DEBUG_TCG)
+    i = 0;
+    for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
+        if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+            /* Wrong entry in op definitions? */
+            if (tcg_op_defs[op].used) {
+                fprintf(stderr, "Invalid op definition for %s\n",
+                        tcg_op_defs[op].name);
+                i = 1;
+            }
+        } else {
+            /* Missing entry in op definitions? */
+            if (!tcg_op_defs[op].used) {
+                fprintf(stderr, "Missing op definition for %s\n",
+                        tcg_op_defs[op].name);
+                i = 1;
+            }
+        }
+    }
+    if (i == 1) {
+        tcg_abort();
+    }
+#endif
+}
+
+#ifdef USE_LIVENESS_ANALYSIS
+
+/* set a nop for an operation using 'nb_args' */
+static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 
+                               TCGArg *args, int nb_args)
+{
+    if (nb_args == 0) {
+        *opc_ptr = INDEX_op_nop;
+    } else {
+        *opc_ptr = INDEX_op_nopn;
+        args[0] = nb_args;
+        args[nb_args - 1] = nb_args;
+    }
+}
+
+/* liveness analysis: end of function: globals are live, temps are
+   dead. */
+/* XXX: at this stage, not used as there would be little gains because
+   most TBs end with a conditional jump. */
+static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
+{
+    memset(dead_temps, 0, s->nb_globals);
+    memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
+}
+
+/* liveness analysis: end of basic block: globals are live, temps are
+   dead, local temps are live. */
+static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
+{
+    int i;
+    TCGTemp *ts;
+
+    memset(dead_temps, 0, s->nb_globals);
+    ts = &s->temps[s->nb_globals];
+    for(i = s->nb_globals; i < s->nb_temps; i++) {
+        if (ts->temp_local)
+            dead_temps[i] = 0;
+        else
+            dead_temps[i] = 1;
+        ts++;
+    }
+}
+
+/* Liveness analysis : update the opc_dead_args array to tell if a
+   given input arguments is dead. Instructions updating dead
+   temporaries are removed. */
+static void tcg_liveness_analysis(TCGContext *s)
+{
+    int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
+    TCGOpcode op;
+    TCGArg *args;
+    const TCGOpDef *def;
+    uint8_t *dead_temps;
+    unsigned int dead_args;
+    
+    gen_opc_ptr++; /* skip end */
+
+    nb_ops = gen_opc_ptr - gen_opc_buf;
+
+    s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
+    
+    dead_temps = tcg_malloc(s->nb_temps);
+    memset(dead_temps, 1, s->nb_temps);
+
+    args = gen_opparam_ptr;
+    op_index = nb_ops - 1;
+    while (op_index >= 0) {
+        op = gen_opc_buf[op_index];
+        def = &tcg_op_defs[op];
+        switch(op) {
+        case INDEX_op_call:
+            {
+                int call_flags;
+
+                nb_args = args[-1];
+                args -= nb_args;
+                nb_iargs = args[0] & 0xffff;
+                nb_oargs = args[0] >> 16;
+                args++;
+                call_flags = args[nb_oargs + nb_iargs];
+
+                /* pure functions can be removed if their result is not
+                   used */
+                if (call_flags & TCG_CALL_PURE) {
+                    for(i = 0; i < nb_oargs; i++) {
+                        arg = args[i];
+                        if (!dead_temps[arg])
+                            goto do_not_remove_call;
+                    }
+                    tcg_set_nop(s, gen_opc_buf + op_index, 
+                                args - 1, nb_args);
+                } else {
+                do_not_remove_call:
+
+                    /* output args are dead */
+                    dead_args = 0;
+                    for(i = 0; i < nb_oargs; i++) {
+                        arg = args[i];
+                        if (dead_temps[arg]) {
+                            dead_args |= (1 << i);
+                        }
+                        dead_temps[arg] = 1;
+                    }
+                    
+                    if (!(call_flags & TCG_CALL_CONST)) {
+                        /* globals are live (they may be used by the call) */
+                        memset(dead_temps, 0, s->nb_globals);
+                    }
+
+                    /* input args are live */
+                    for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+                        arg = args[i];
+                        if (arg != TCG_CALL_DUMMY_ARG) {
+                            if (dead_temps[arg]) {
+                                dead_args |= (1 << i);
+                            }
+                            dead_temps[arg] = 0;
+                        }
+                    }
+                    s->op_dead_args[op_index] = dead_args;
+                }
+                args--;
+            }
+            break;
+        case INDEX_op_set_label:
+            args--;
+            /* mark end of basic block */
+            tcg_la_bb_end(s, dead_temps);
+            break;
+        case INDEX_op_debug_insn_start:
+            args -= def->nb_args;
+            break;
+        case INDEX_op_nopn:
+            nb_args = args[-1];
+            args -= nb_args;
+            break;
+        case INDEX_op_discard:
+            args--;
+            /* mark the temporary as dead */
+            dead_temps[args[0]] = 1;
+            break;
+        case INDEX_op_end:
+            break;
+            /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
+        default:
+            args -= def->nb_args;
+            nb_iargs = def->nb_iargs;
+            nb_oargs = def->nb_oargs;
+
+            /* Test if the operation can be removed because all
+               its outputs are dead. We assume that nb_oargs == 0
+               implies side effects */
+            if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
+                for(i = 0; i < nb_oargs; i++) {
+                    arg = args[i];
+                    if (!dead_temps[arg])
+                        goto do_not_remove;
+                }
+                tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
+#ifdef CONFIG_PROFILER
+                s->del_op_count++;
+#endif
+            } else {
+            do_not_remove:
+
+                /* output args are dead */
+                dead_args = 0;
+                for(i = 0; i < nb_oargs; i++) {
+                    arg = args[i];
+                    if (dead_temps[arg]) {
+                        dead_args |= (1 << i);
+                    }
+                    dead_temps[arg] = 1;
+                }
+
+                /* if end of basic block, update */
+                if (def->flags & TCG_OPF_BB_END) {
+                    tcg_la_bb_end(s, dead_temps);
+                } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
+                    /* globals are live */
+                    memset(dead_temps, 0, s->nb_globals);
+                }
+
+                /* input args are live */
+                for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+                    arg = args[i];
+                    if (dead_temps[arg]) {
+                        dead_args |= (1 << i);
+                    }
+                    dead_temps[arg] = 0;
+                }
+                s->op_dead_args[op_index] = dead_args;
+            }
+            break;
+        }
+        op_index--;
+    }
+
+    if (args != gen_opparam_buf)
+        tcg_abort();
+}
+#else
+/* dummy liveness analysis */
+static void tcg_liveness_analysis(TCGContext *s)
+{
+    int nb_ops;
+    nb_ops = gen_opc_ptr - gen_opc_buf;
+
+    s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
+    memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t));
+}
+#endif
+
+#ifndef NDEBUG
+static void dump_regs(TCGContext *s)
+{
+    TCGTemp *ts;
+    int i;
+    char buf[64];
+
+    for(i = 0; i < s->nb_temps; i++) {
+        ts = &s->temps[i];
+        printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
+        switch(ts->val_type) {
+        case TEMP_VAL_REG:
+            printf("%s", tcg_target_reg_names[ts->reg]);
+            break;
+        case TEMP_VAL_MEM:
+            printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
+            break;
+        case TEMP_VAL_CONST:
+            printf("$0x%" TCG_PRIlx, ts->val);
+            break;
+        case TEMP_VAL_DEAD:
+            printf("D");
+            break;
+        default:
+            printf("???");
+            break;
+        }
+        printf("\n");
+    }
+
+    for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+        if (s->reg_to_temp[i] >= 0) {
+            printf("%s: %s\n", 
+                   tcg_target_reg_names[i], 
+                   tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
+        }
+    }
+}
+
+static void check_regs(TCGContext *s)
+{
+    int reg, k;
+    TCGTemp *ts;
+    char buf[64];
+
+    for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+        k = s->reg_to_temp[reg];
+        if (k >= 0) {
+            ts = &s->temps[k];
+            if (ts->val_type != TEMP_VAL_REG ||
+                ts->reg != reg) {
+                printf("Inconsistency for register %s:\n", 
+                       tcg_target_reg_names[reg]);
+                goto fail;
+            }
+        }
+    }
+    for(k = 0; k < s->nb_temps; k++) {
+        ts = &s->temps[k];
+        if (ts->val_type == TEMP_VAL_REG &&
+            !ts->fixed_reg &&
+            s->reg_to_temp[ts->reg] != k) {
+                printf("Inconsistency for temp %s:\n", 
+                       tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
+        fail:
+                printf("reg state:\n");
+                dump_regs(s);
+                tcg_abort();
+        }
+    }
+}
+#endif
+
+static void temp_allocate_frame(TCGContext *s, int temp)
+{
+    TCGTemp *ts;
+    ts = &s->temps[temp];
+#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */
+    s->current_frame_offset = (s->current_frame_offset +
+                               (tcg_target_long)sizeof(tcg_target_long) - 1) &
+        ~(sizeof(tcg_target_long) - 1);
+#endif
+    if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
+        s->frame_end) {
+        tcg_abort();
+    }
+    ts->mem_offset = s->current_frame_offset;
+    ts->mem_reg = s->frame_reg;
+    ts->mem_allocated = 1;
+    s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long);
+}
+
+/* free register 'reg' by spilling the corresponding temporary if necessary */
+static void tcg_reg_free(TCGContext *s, int reg)
+{
+    TCGTemp *ts;
+    int temp;
+
+    temp = s->reg_to_temp[reg];
+    if (temp != -1) {
+        ts = &s->temps[temp];
+        assert(ts->val_type == TEMP_VAL_REG);
+        if (!ts->mem_coherent) {
+            if (!ts->mem_allocated) 
+                temp_allocate_frame(s, temp);
+            tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+        }
+        ts->val_type = TEMP_VAL_MEM;
+        s->reg_to_temp[reg] = -1;
+    }
+}
+
+/* Allocate a register belonging to reg1 & ~reg2 */
+static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
+{
+    int i, reg;
+    TCGRegSet reg_ct;
+
+    tcg_regset_andnot(reg_ct, reg1, reg2);
+
+    /* first try free registers */
+    for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
+        reg = tcg_target_reg_alloc_order[i];
+        if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
+            return reg;
+    }
+
+    /* XXX: do better spill choice */
+    for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
+        reg = tcg_target_reg_alloc_order[i];
+        if (tcg_regset_test_reg(reg_ct, reg)) {
+            tcg_reg_free(s, reg);
+            return reg;
+        }
+    }
+
+    tcg_abort();
+}
+
+/* save a temporary to memory. 'allocated_regs' is used in case a
+   temporary registers needs to be allocated to store a constant. */
+static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
+{
+    TCGTemp *ts;
+    int reg;
+
+    ts = &s->temps[temp];
+    if (!ts->fixed_reg) {
+        switch(ts->val_type) {
+        case TEMP_VAL_REG:
+            tcg_reg_free(s, ts->reg);
+            break;
+        case TEMP_VAL_DEAD:
+            ts->val_type = TEMP_VAL_MEM;
+            break;
+        case TEMP_VAL_CONST:
+            reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+                                allocated_regs);
+            if (!ts->mem_allocated) 
+                temp_allocate_frame(s, temp);
+            tcg_out_movi(s, ts->type, reg, ts->val);
+            tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+            ts->val_type = TEMP_VAL_MEM;
+            break;
+        case TEMP_VAL_MEM:
+            break;
+        default:
+            tcg_abort();
+        }
+    }
+}
+
+/* save globals to their cannonical location and assume they can be
+   modified be the following code. 'allocated_regs' is used in case a
+   temporary registers needs to be allocated to store a constant. */
+static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
+{
+    int i;
+
+    for(i = 0; i < s->nb_globals; i++) {
+        temp_save(s, i, allocated_regs);
+    }
+}
+
+/* at the end of a basic block, we assume all temporaries are dead and
+   all globals are stored at their canonical location. */
+static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
+{
+    TCGTemp *ts;
+    int i;
+
+    for(i = s->nb_globals; i < s->nb_temps; i++) {
+        ts = &s->temps[i];
+        if (ts->temp_local) {
+            temp_save(s, i, allocated_regs);
+        } else {
+            if (ts->val_type == TEMP_VAL_REG) {
+                s->reg_to_temp[ts->reg] = -1;
+            }
+            ts->val_type = TEMP_VAL_DEAD;
+        }
+    }
+
+    save_globals(s, allocated_regs);
+}
+
+#define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
+
+static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
+{
+    TCGTemp *ots;
+    tcg_target_ulong val;
+
+    ots = &s->temps[args[0]];
+    val = args[1];
+
+    if (ots->fixed_reg) {
+        /* for fixed registers, we do not do any constant
+           propagation */
+        tcg_out_movi(s, ots->type, ots->reg, val);
+    } else {
+        /* The movi is not explicitly generated here */
+        if (ots->val_type == TEMP_VAL_REG)
+            s->reg_to_temp[ots->reg] = -1;
+        ots->val_type = TEMP_VAL_CONST;
+        ots->val = val;
+    }
+}
+
+static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
+                              const TCGArg *args,
+                              unsigned int dead_args)
+{
+    TCGTemp *ts, *ots;
+    int reg;
+    const TCGArgConstraint *arg_ct;
+
+    ots = &s->temps[args[0]];
+    ts = &s->temps[args[1]];
+    arg_ct = &def->args_ct[0];
+
+    /* XXX: always mark arg dead if IS_DEAD_ARG(1) */
+    if (ts->val_type == TEMP_VAL_REG) {
+        if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
+            /* the mov can be suppressed */
+            if (ots->val_type == TEMP_VAL_REG)
+                s->reg_to_temp[ots->reg] = -1;
+            reg = ts->reg;
+            s->reg_to_temp[reg] = -1;
+            ts->val_type = TEMP_VAL_DEAD;
+        } else {
+            if (ots->val_type == TEMP_VAL_REG) {
+                reg = ots->reg;
+            } else {
+                reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
+            }
+            if (ts->reg != reg) {
+                tcg_out_mov(s, ots->type, reg, ts->reg);
+            }
+        }
+    } else if (ts->val_type == TEMP_VAL_MEM) {
+        if (ots->val_type == TEMP_VAL_REG) {
+            reg = ots->reg;
+        } else {
+            reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
+        }
+        tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+    } else if (ts->val_type == TEMP_VAL_CONST) {
+        if (ots->fixed_reg) {
+            reg = ots->reg;
+            tcg_out_movi(s, ots->type, reg, ts->val);
+        } else {
+            /* propagate constant */
+            if (ots->val_type == TEMP_VAL_REG)
+                s->reg_to_temp[ots->reg] = -1;
+            ots->val_type = TEMP_VAL_CONST;
+            ots->val = ts->val;
+            return;
+        }
+    } else {
+        tcg_abort();
+    }
+    s->reg_to_temp[reg] = args[0];
+    ots->reg = reg;
+    ots->val_type = TEMP_VAL_REG;
+    ots->mem_coherent = 0;
+}
+
+static void tcg_reg_alloc_op(TCGContext *s, 
+                             const TCGOpDef *def, TCGOpcode opc,
+                             const TCGArg *args,
+                             unsigned int dead_args)
+{
+    TCGRegSet allocated_regs;
+    int i, k, nb_iargs, nb_oargs, reg;
+    TCGArg arg;
+    const TCGArgConstraint *arg_ct;
+    TCGTemp *ts;
+    TCGArg new_args[TCG_MAX_OP_ARGS];
+    int const_args[TCG_MAX_OP_ARGS];
+
+    nb_oargs = def->nb_oargs;
+    nb_iargs = def->nb_iargs;
+
+    /* copy constants */
+    memcpy(new_args + nb_oargs + nb_iargs, 
+           args + nb_oargs + nb_iargs, 
+           sizeof(TCGArg) * def->nb_cargs);
+
+    /* satisfy input constraints */ 
+    tcg_regset_set(allocated_regs, s->reserved_regs);
+    for(k = 0; k < nb_iargs; k++) {
+        i = def->sorted_args[nb_oargs + k];
+        arg = args[i];
+        arg_ct = &def->args_ct[i];
+        ts = &s->temps[arg];
+        if (ts->val_type == TEMP_VAL_MEM) {
+            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+            tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+            ts->val_type = TEMP_VAL_REG;
+            ts->reg = reg;
+            ts->mem_coherent = 1;
+            s->reg_to_temp[reg] = arg;
+        } else if (ts->val_type == TEMP_VAL_CONST) {
+            if (tcg_target_const_match(ts->val, arg_ct)) {
+                /* constant is OK for instruction */
+                const_args[i] = 1;
+                new_args[i] = ts->val;
+                goto iarg_end;
+            } else {
+                /* need to move to a register */
+                reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+                tcg_out_movi(s, ts->type, reg, ts->val);
+                ts->val_type = TEMP_VAL_REG;
+                ts->reg = reg;
+                ts->mem_coherent = 0;
+                s->reg_to_temp[reg] = arg;
+            }
+        }
+        assert(ts->val_type == TEMP_VAL_REG);
+        if (arg_ct->ct & TCG_CT_IALIAS) {
+            if (ts->fixed_reg) {
+                /* if fixed register, we must allocate a new register
+                   if the alias is not the same register */
+                if (arg != args[arg_ct->alias_index])
+                    goto allocate_in_reg;
+            } else {
+                /* if the input is aliased to an output and if it is
+                   not dead after the instruction, we must allocate
+                   a new register and move it */
+                if (!IS_DEAD_ARG(i)) {
+                    goto allocate_in_reg;
+                }
+            }
+        }
+        reg = ts->reg;
+        if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+            /* nothing to do : the constraint is satisfied */
+        } else {
+        allocate_in_reg:
+            /* allocate a new register matching the constraint 
+               and move the temporary register into it */
+            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+            tcg_out_mov(s, ts->type, reg, ts->reg);
+        }
+        new_args[i] = reg;
+        const_args[i] = 0;
+        tcg_regset_set_reg(allocated_regs, reg);
+    iarg_end: ;
+    }
+    
+    if (def->flags & TCG_OPF_BB_END) {
+        tcg_reg_alloc_bb_end(s, allocated_regs);
+    } else {
+        /* mark dead temporaries and free the associated registers */
+        for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+            arg = args[i];
+            if (IS_DEAD_ARG(i)) {
+                ts = &s->temps[arg];
+                if (!ts->fixed_reg) {
+                    if (ts->val_type == TEMP_VAL_REG)
+                        s->reg_to_temp[ts->reg] = -1;
+                    ts->val_type = TEMP_VAL_DEAD;
+                }
+            }
+        }
+        
+        if (def->flags & TCG_OPF_CALL_CLOBBER) {
+            /* XXX: permit generic clobber register list ? */ 
+            for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+                if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
+                    tcg_reg_free(s, reg);
+                }
+            }
+            /* XXX: for load/store we could do that only for the slow path
+               (i.e. when a memory callback is called) */
+            
+            /* store globals and free associated registers (we assume the insn
+               can modify any global. */
+            save_globals(s, allocated_regs);
+        }
+        
+        /* satisfy the output constraints */
+        tcg_regset_set(allocated_regs, s->reserved_regs);
+        for(k = 0; k < nb_oargs; k++) {
+            i = def->sorted_args[k];
+            arg = args[i];
+            arg_ct = &def->args_ct[i];
+            ts = &s->temps[arg];
+            if (arg_ct->ct & TCG_CT_ALIAS) {
+                reg = new_args[arg_ct->alias_index];
+            } else {
+                /* if fixed register, we try to use it */
+                reg = ts->reg;
+                if (ts->fixed_reg &&
+                    tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+                    goto oarg_end;
+                }
+                reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+            }
+            tcg_regset_set_reg(allocated_regs, reg);
+            /* if a fixed register is used, then a move will be done afterwards */
+            if (!ts->fixed_reg) {
+                if (ts->val_type == TEMP_VAL_REG)
+                    s->reg_to_temp[ts->reg] = -1;
+                if (IS_DEAD_ARG(i)) {
+                    ts->val_type = TEMP_VAL_DEAD;
+                } else {
+                    ts->val_type = TEMP_VAL_REG;
+                    ts->reg = reg;
+                    /* temp value is modified, so the value kept in memory is
+                       potentially not the same */
+                    ts->mem_coherent = 0;
+                    s->reg_to_temp[reg] = arg;
+               }
+            }
+        oarg_end:
+            new_args[i] = reg;
+        }
+    }
+
+    /* emit instruction */
+    tcg_out_op(s, opc, new_args, const_args);
+    
+    /* move the outputs in the correct register if needed */
+    for(i = 0; i < nb_oargs; i++) {
+        ts = &s->temps[args[i]];
+        reg = new_args[i];
+        if (ts->fixed_reg && ts->reg != reg) {
+            tcg_out_mov(s, ts->type, ts->reg, reg);
+        }
+    }
+}
+
+#ifdef TCG_TARGET_STACK_GROWSUP
+#define STACK_DIR(x) (-(x))
+#else
+#define STACK_DIR(x) (x)
+#endif
+
+static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
+                              TCGOpcode opc, const TCGArg *args,
+                              unsigned int dead_args)
+{
+    int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
+    TCGArg arg, func_arg;
+    TCGTemp *ts;
+    tcg_target_long stack_offset, call_stack_size, func_addr;
+    int const_func_arg, allocate_args;
+    TCGRegSet allocated_regs;
+    const TCGArgConstraint *arg_ct;
+
+    arg = *args++;
+
+    nb_oargs = arg >> 16;
+    nb_iargs = arg & 0xffff;
+    nb_params = nb_iargs - 1;
+
+    flags = args[nb_oargs + nb_iargs];
+
+    nb_regs = tcg_target_get_call_iarg_regs_count(flags);
+    if (nb_regs > nb_params)
+        nb_regs = nb_params;
+
+    /* assign stack slots first */
+    call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
+    call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 
+        ~(TCG_TARGET_STACK_ALIGN - 1);
+    allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
+    if (allocate_args) {
+        /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
+           preallocate call stack */
+        tcg_abort();
+    }
+
+    stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
+    for(i = nb_regs; i < nb_params; i++) {
+        arg = args[nb_oargs + i];
+#ifdef TCG_TARGET_STACK_GROWSUP
+        stack_offset -= sizeof(tcg_target_long);
+#endif
+        if (arg != TCG_CALL_DUMMY_ARG) {
+            ts = &s->temps[arg];
+            if (ts->val_type == TEMP_VAL_REG) {
+                tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
+            } else if (ts->val_type == TEMP_VAL_MEM) {
+                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+                                    s->reserved_regs);
+                /* XXX: not correct if reading values from the stack */
+                tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+                tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
+            } else if (ts->val_type == TEMP_VAL_CONST) {
+                reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
+                                    s->reserved_regs);
+                /* XXX: sign extend may be needed on some targets */
+                tcg_out_movi(s, ts->type, reg, ts->val);
+                tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
+            } else {
+                tcg_abort();
+            }
+        }
+#ifndef TCG_TARGET_STACK_GROWSUP
+        stack_offset += sizeof(tcg_target_long);
+#endif
+    }
+    
+    /* assign input registers */
+    tcg_regset_set(allocated_regs, s->reserved_regs);
+    for(i = 0; i < nb_regs; i++) {
+        arg = args[nb_oargs + i];
+        if (arg != TCG_CALL_DUMMY_ARG) {
+            ts = &s->temps[arg];
+            reg = tcg_target_call_iarg_regs[i];
+            tcg_reg_free(s, reg);
+            if (ts->val_type == TEMP_VAL_REG) {
+                if (ts->reg != reg) {
+                    tcg_out_mov(s, ts->type, reg, ts->reg);
+                }
+            } else if (ts->val_type == TEMP_VAL_MEM) {
+                tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+            } else if (ts->val_type == TEMP_VAL_CONST) {
+                /* XXX: sign extend ? */
+                tcg_out_movi(s, ts->type, reg, ts->val);
+            } else {
+                tcg_abort();
+            }
+            tcg_regset_set_reg(allocated_regs, reg);
+        }
+    }
+    
+    /* assign function address */
+    func_arg = args[nb_oargs + nb_iargs - 1];
+    arg_ct = &def->args_ct[0];
+    ts = &s->temps[func_arg];
+    func_addr = ts->val;
+    const_func_arg = 0;
+    if (ts->val_type == TEMP_VAL_MEM) {
+        reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+        tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+        func_arg = reg;
+        tcg_regset_set_reg(allocated_regs, reg);
+    } else if (ts->val_type == TEMP_VAL_REG) {
+        reg = ts->reg;
+        if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+            tcg_out_mov(s, ts->type, reg, ts->reg);
+        }
+        func_arg = reg;
+        tcg_regset_set_reg(allocated_regs, reg);
+    } else if (ts->val_type == TEMP_VAL_CONST) {
+        if (tcg_target_const_match(func_addr, arg_ct)) {
+            const_func_arg = 1;
+            func_arg = func_addr;
+        } else {
+            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+            tcg_out_movi(s, ts->type, reg, func_addr);
+            func_arg = reg;
+            tcg_regset_set_reg(allocated_regs, reg);
+        }
+    } else {
+        tcg_abort();
+    }
+        
+    
+    /* mark dead temporaries and free the associated registers */
+    for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+        arg = args[i];
+        if (IS_DEAD_ARG(i)) {
+            ts = &s->temps[arg];
+            if (!ts->fixed_reg) {
+                if (ts->val_type == TEMP_VAL_REG)
+                    s->reg_to_temp[ts->reg] = -1;
+                ts->val_type = TEMP_VAL_DEAD;
+            }
+        }
+    }
+    
+    /* clobber call registers */
+    for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+        if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
+            tcg_reg_free(s, reg);
+        }
+    }
+    
+    /* store globals and free associated registers (we assume the call
+       can modify any global. */
+    if (!(flags & TCG_CALL_CONST)) {
+        save_globals(s, allocated_regs);
+    }
+
+    tcg_out_op(s, opc, &func_arg, &const_func_arg);
+
+    /* assign output registers and emit moves if needed */
+    for(i = 0; i < nb_oargs; i++) {
+        arg = args[i];
+        ts = &s->temps[arg];
+        reg = tcg_target_call_oarg_regs[i];
+        assert(s->reg_to_temp[reg] == -1);
+        if (ts->fixed_reg) {
+            if (ts->reg != reg) {
+                tcg_out_mov(s, ts->type, ts->reg, reg);
+            }
+        } else {
+            if (ts->val_type == TEMP_VAL_REG)
+                s->reg_to_temp[ts->reg] = -1;
+            if (IS_DEAD_ARG(i)) {
+                ts->val_type = TEMP_VAL_DEAD;
+            } else {
+                ts->val_type = TEMP_VAL_REG;
+                ts->reg = reg;
+                ts->mem_coherent = 0;
+                s->reg_to_temp[reg] = arg;
+            }
+        }
+    }
+    
+    return nb_iargs + nb_oargs + def->nb_cargs + 1;
+}
+
+#ifdef CONFIG_PROFILER
+
+static int64_t tcg_table_op_count[NB_OPS];
+
+static void dump_op_count(void)
+{
+    int i;
+    FILE *f;
+    f = fopen("/tmp/op.log", "w");
+    for(i = INDEX_op_end; i < NB_OPS; i++) {
+        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
+    }
+    fclose(f);
+}
+#endif
+
+
+static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
+                                      long search_pc)
+{
+    TCGOpcode opc;
+    int op_index;
+    const TCGOpDef *def;
+    unsigned int dead_args;
+    const TCGArg *args;
+
+#ifdef DEBUG_DISAS
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+        qemu_log("OP:\n");
+        tcg_dump_ops(s, logfile);
+        qemu_log("\n");
+    }
+#endif
+
+#ifdef CONFIG_PROFILER
+    s->la_time -= profile_getclock();
+#endif
+    tcg_liveness_analysis(s);
+#ifdef CONFIG_PROFILER
+    s->la_time += profile_getclock();
+#endif
+
+#ifdef DEBUG_DISAS
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
+        qemu_log("OP after liveness analysis:\n");
+        tcg_dump_ops(s, logfile);
+        qemu_log("\n");
+    }
+#endif
+
+    tcg_reg_alloc_start(s);
+
+    s->code_buf = gen_code_buf;
+    s->code_ptr = gen_code_buf;
+
+    args = gen_opparam_buf;
+    op_index = 0;
+
+    for(;;) {
+        opc = gen_opc_buf[op_index];
+#ifdef CONFIG_PROFILER
+        tcg_table_op_count[opc]++;
+#endif
+        def = &tcg_op_defs[opc];
+#if 0
+        printf("%s: %d %d %d\n", def->name,
+               def->nb_oargs, def->nb_iargs, def->nb_cargs);
+        //        dump_regs(s);
+#endif
+        switch(opc) {
+        case INDEX_op_mov_i32:
+#if TCG_TARGET_REG_BITS == 64
+        case INDEX_op_mov_i64:
+#endif
+            dead_args = s->op_dead_args[op_index];
+            tcg_reg_alloc_mov(s, def, args, dead_args);
+            break;
+        case INDEX_op_movi_i32:
+#if TCG_TARGET_REG_BITS == 64
+        case INDEX_op_movi_i64:
+#endif
+            tcg_reg_alloc_movi(s, args);
+            break;
+        case INDEX_op_debug_insn_start:
+            /* debug instruction */
+            break;
+        case INDEX_op_nop:
+        case INDEX_op_nop1:
+        case INDEX_op_nop2:
+        case INDEX_op_nop3:
+            break;
+        case INDEX_op_nopn:
+            args += args[0];
+            goto next;
+        case INDEX_op_discard:
+            {
+                TCGTemp *ts;
+                ts = &s->temps[args[0]];
+                /* mark the temporary as dead */
+                if (!ts->fixed_reg) {
+                    if (ts->val_type == TEMP_VAL_REG)
+                        s->reg_to_temp[ts->reg] = -1;
+                    ts->val_type = TEMP_VAL_DEAD;
+                }
+            }
+            break;
+        case INDEX_op_set_label:
+            tcg_reg_alloc_bb_end(s, s->reserved_regs);
+            tcg_out_label(s, args[0], (long)s->code_ptr);
+            break;
+        case INDEX_op_call:
+            dead_args = s->op_dead_args[op_index];
+            args += tcg_reg_alloc_call(s, def, opc, args, dead_args);
+            goto next;
+        case INDEX_op_end:
+            goto the_end;
+        default:
+            /* Note: in order to speed up the code, it would be much
+               faster to have specialized register allocator functions for
+               some common argument patterns */
+            dead_args = s->op_dead_args[op_index];
+            tcg_reg_alloc_op(s, def, opc, args, dead_args);
+            break;
+        }
+        args += def->nb_args;
+    next:
+        if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
+            return op_index;
+        }
+        op_index++;
+#ifndef NDEBUG
+        check_regs(s);
+#endif
+    }
+ the_end:
+    return -1;
+}
+
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
+{
+#ifdef CONFIG_PROFILER
+    {
+        int n;
+        n = (gen_opc_ptr - gen_opc_buf);
+        s->op_count += n;
+        if (n > s->op_count_max)
+            s->op_count_max = n;
+
+        s->temp_count += s->nb_temps;
+        if (s->nb_temps > s->temp_count_max)
+            s->temp_count_max = s->nb_temps;
+    }
+#endif
+
+    tcg_gen_code_common(s, gen_code_buf, -1);
+
+    /* flush instruction cache */
+    flush_icache_range((unsigned long)gen_code_buf, 
+                       (unsigned long)s->code_ptr);
+    return s->code_ptr -  gen_code_buf;
+}
+
+/* Return the index of the micro operation such as the pc after is <
+   offset bytes from the start of the TB.  The contents of gen_code_buf must
+   not be changed, though writing the same values is ok.
+   Return -1 if not found. */
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
+{
+    return tcg_gen_code_common(s, gen_code_buf, offset);
+}
+
+#ifdef CONFIG_PROFILER
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
+{
+    TCGContext *s = &tcg_ctx;
+    int64_t tot;
+
+    tot = s->interm_time + s->code_time;
+    cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
+                tot, tot / 2.4e9);
+    cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 
+                s->tb_count, 
+                s->tb_count1 - s->tb_count,
+                s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
+    cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n", 
+                s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
+    cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
+                s->tb_count ? 
+                (double)s->del_op_count / s->tb_count : 0);
+    cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
+                s->tb_count ? 
+                (double)s->temp_count / s->tb_count : 0,
+                s->temp_count_max);
+    
+    cpu_fprintf(f, "cycles/op           %0.1f\n", 
+                s->op_count ? (double)tot / s->op_count : 0);
+    cpu_fprintf(f, "cycles/in byte      %0.1f\n", 
+                s->code_in_len ? (double)tot / s->code_in_len : 0);
+    cpu_fprintf(f, "cycles/out byte     %0.1f\n", 
+                s->code_out_len ? (double)tot / s->code_out_len : 0);
+    if (tot == 0)
+        tot = 1;
+    cpu_fprintf(f, "  gen_interm time   %0.1f%%\n", 
+                (double)s->interm_time / tot * 100.0);
+    cpu_fprintf(f, "  gen_code time     %0.1f%%\n", 
+                (double)s->code_time / tot * 100.0);
+    cpu_fprintf(f, "liveness/code time  %0.1f%%\n", 
+                (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
+    cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
+                s->restore_count);
+    cpu_fprintf(f, "  avg cycles        %0.1f\n",
+                s->restore_count ? (double)s->restore_time / s->restore_count : 0);
+
+    dump_op_count();
+}
+#else
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
+{
+    cpu_fprintf(f, "[TCG profiler not compiled]\n");
+}
+#endif
diff --git a/qemu-0.15.x/tcg/tcg.h b/qemu-0.15.x/tcg/tcg.h
new file mode 100644
index 0000000..a2dd8b8
--- /dev/null
+++ b/qemu-0.15.x/tcg/tcg.h
@@ -0,0 +1,523 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 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 "qemu-common.h"
+#include "tcg-target.h"
+#include "tcg-runtime.h"
+
+#if TCG_TARGET_REG_BITS == 32
+typedef int32_t tcg_target_long;
+typedef uint32_t tcg_target_ulong;
+#define TCG_PRIlx PRIx32
+#define TCG_PRIld PRId32
+#elif TCG_TARGET_REG_BITS == 64
+typedef int64_t tcg_target_long;
+typedef uint64_t tcg_target_ulong;
+#define TCG_PRIlx PRIx64
+#define TCG_PRIld PRId64
+#else
+#error unsupported
+#endif
+
+#if TCG_TARGET_NB_REGS <= 32
+typedef uint32_t TCGRegSet;
+#elif TCG_TARGET_NB_REGS <= 64
+typedef uint64_t TCGRegSet;
+#else
+#error unsupported
+#endif
+
+typedef enum TCGOpcode {
+#define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
+#include "tcg-opc.h"
+#undef DEF
+    NB_OPS,
+} TCGOpcode;
+
+#define tcg_regset_clear(d) (d) = 0
+#define tcg_regset_set(d, s) (d) = (s)
+#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg)
+#define tcg_regset_set_reg(d, r) (d) |= 1L << (r)
+#define tcg_regset_reset_reg(d, r) (d) &= ~(1L << (r))
+#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1)
+#define tcg_regset_or(d, a, b) (d) = (a) | (b)
+#define tcg_regset_and(d, a, b) (d) = (a) & (b)
+#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b)
+#define tcg_regset_not(d, a) (d) = ~(a)
+
+typedef struct TCGRelocation {
+    struct TCGRelocation *next;
+    int type;
+    uint8_t *ptr;
+    tcg_target_long addend;
+} TCGRelocation; 
+
+typedef struct TCGLabel {
+    int has_value;
+    union {
+        tcg_target_ulong value;
+        TCGRelocation *first_reloc;
+    } u;
+} TCGLabel;
+
+typedef struct TCGPool {
+    struct TCGPool *next;
+    int size;
+    uint8_t data[0] __attribute__ ((aligned));
+} TCGPool;
+
+#define TCG_POOL_CHUNK_SIZE 32768
+
+#define TCG_MAX_LABELS 512
+
+#define TCG_MAX_TEMPS 512
+
+/* when the size of the arguments of a called function is smaller than
+   this value, they are statically allocated in the TB stack frame */
+#define TCG_STATIC_CALL_ARGS_SIZE 128
+
+typedef enum TCGType {
+    TCG_TYPE_I32,
+    TCG_TYPE_I64,
+    TCG_TYPE_COUNT, /* number of different types */
+
+    /* An alias for the size of the host register.  */
+#if TCG_TARGET_REG_BITS == 32
+    TCG_TYPE_REG = TCG_TYPE_I32,
+#else
+    TCG_TYPE_REG = TCG_TYPE_I64,
+#endif
+
+    /* An alias for the size of the native pointer.  We don't currently
+       support any hosts with 64-bit registers and 32-bit pointers.  */
+    TCG_TYPE_PTR = TCG_TYPE_REG,
+
+    /* An alias for the size of the target "long", aka register.  */
+#if TARGET_LONG_BITS == 64
+    TCG_TYPE_TL = TCG_TYPE_I64,
+#else
+    TCG_TYPE_TL = TCG_TYPE_I32,
+#endif
+} TCGType;
+
+typedef tcg_target_ulong TCGArg;
+
+/* Define a type and accessor macros for varables.  Using a struct is
+   nice because it gives some level of type safely.  Ideally the compiler
+   be able to see through all this.  However in practice this is not true,
+   expecially on targets with braindamaged ABIs (e.g. i386).
+   We use plain int by default to avoid this runtime overhead.
+   Users of tcg_gen_* don't need to know about any of this, and should
+   treat TCGv as an opaque type.
+   In addition we do typechecking for different types of variables.  TCGv_i32
+   and TCGv_i64 are 32/64-bit variables respectively.  TCGv and TCGv_ptr
+   are aliases for target_ulong and host pointer sized values respectively.
+ */
+
+#ifdef CONFIG_DEBUG_TCG
+#define DEBUG_TCGV 1
+#endif
+
+#ifdef DEBUG_TCGV
+
+typedef struct
+{
+    int i32;
+} TCGv_i32;
+
+typedef struct
+{
+    int i64;
+} TCGv_i64;
+
+typedef struct {
+    int iptr;
+} TCGv_ptr;
+
+#define MAKE_TCGV_I32(i) __extension__                  \
+    ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_I64(i) __extension__                  \
+    ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_PTR(i) __extension__                  \
+    ({ TCGv_ptr make_tcgv_tmp = {i}; make_tcgv_tmp; })
+#define GET_TCGV_I32(t) ((t).i32)
+#define GET_TCGV_I64(t) ((t).i64)
+#define GET_TCGV_PTR(t) ((t).iptr)
+#if TCG_TARGET_REG_BITS == 32
+#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
+#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
+#endif
+
+#else /* !DEBUG_TCGV */
+
+typedef int TCGv_i32;
+typedef int TCGv_i64;
+#if TCG_TARGET_REG_BITS == 32
+#define TCGv_ptr TCGv_i32
+#else
+#define TCGv_ptr TCGv_i64
+#endif
+#define MAKE_TCGV_I32(x) (x)
+#define MAKE_TCGV_I64(x) (x)
+#define MAKE_TCGV_PTR(x) (x)
+#define GET_TCGV_I32(t) (t)
+#define GET_TCGV_I64(t) (t)
+#define GET_TCGV_PTR(t) (t)
+
+#if TCG_TARGET_REG_BITS == 32
+#define TCGV_LOW(t) (t)
+#define TCGV_HIGH(t) ((t) + 1)
+#endif
+
+#endif /* DEBUG_TCGV */
+
+#define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b))
+#define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b))
+
+/* Dummy definition to avoid compiler warnings.  */
+#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1)
+#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
+
+/* call flags */
+#define TCG_CALL_TYPE_MASK      0x000f
+#define TCG_CALL_TYPE_STD       0x0000 /* standard C call */
+#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
+#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
+#define TCG_CALL_TYPE_REGPARM   0x0003 /* i386 style regparm call (3 regs) */
+/* A pure function only reads its arguments and TCG global variables
+   and cannot raise exceptions. Hence a call to a pure function can be
+   safely suppressed if the return value is not used. */
+#define TCG_CALL_PURE           0x0010 
+/* A const function only reads its arguments and does not use TCG
+   global variables. Hence a call to such a function does not
+   save TCG global variables back to their canonical location. */
+#define TCG_CALL_CONST          0x0020
+
+/* used to align parameters */
+#define TCG_CALL_DUMMY_TCGV     MAKE_TCGV_I32(-1)
+#define TCG_CALL_DUMMY_ARG      ((TCGArg)(-1))
+
+typedef enum {
+    TCG_COND_EQ,
+    TCG_COND_NE,
+    TCG_COND_LT,
+    TCG_COND_GE,
+    TCG_COND_LE,
+    TCG_COND_GT,
+    /* unsigned */
+    TCG_COND_LTU,
+    TCG_COND_GEU,
+    TCG_COND_LEU,
+    TCG_COND_GTU,
+} TCGCond;
+
+/* Invert the sense of the comparison.  */
+static inline TCGCond tcg_invert_cond(TCGCond c)
+{
+    return (TCGCond)(c ^ 1);
+}
+
+/* Swap the operands in a comparison.  */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+    int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
+    return (TCGCond)(c ^ mask);
+}
+
+static inline TCGCond tcg_unsigned_cond(TCGCond c)
+{
+    return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
+}
+
+#define TEMP_VAL_DEAD  0
+#define TEMP_VAL_REG   1
+#define TEMP_VAL_MEM   2
+#define TEMP_VAL_CONST 3
+
+/* XXX: optimize memory layout */
+typedef struct TCGTemp {
+    TCGType base_type;
+    TCGType type;
+    int val_type;
+    int reg;
+    tcg_target_long val;
+    int mem_reg;
+    tcg_target_long mem_offset;
+    unsigned int fixed_reg:1;
+    unsigned int mem_coherent:1;
+    unsigned int mem_allocated:1;
+    unsigned int temp_local:1; /* If true, the temp is saved across
+                                  basic blocks. Otherwise, it is not
+                                  preserved across basic blocks. */
+    unsigned int temp_allocated:1; /* never used for code gen */
+    /* index of next free temp of same base type, -1 if end */
+    int next_free_temp;
+    const char *name;
+} TCGTemp;
+
+typedef struct TCGHelperInfo {
+    tcg_target_ulong func;
+    const char *name;
+} TCGHelperInfo;
+
+typedef struct TCGContext TCGContext;
+
+struct TCGContext {
+    uint8_t *pool_cur, *pool_end;
+    TCGPool *pool_first, *pool_current;
+    TCGLabel *labels;
+    int nb_labels;
+    TCGTemp *temps; /* globals first, temps after */
+    int nb_globals;
+    int nb_temps;
+    /* index of free temps, -1 if none */
+    int first_free_temp[TCG_TYPE_COUNT * 2]; 
+
+    /* goto_tb support */
+    uint8_t *code_buf;
+    unsigned long *tb_next;
+    uint16_t *tb_next_offset;
+    uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
+
+    /* liveness analysis */
+    uint16_t *op_dead_args; /* for each operation, each bit tells if the
+                               corresponding argument is dead */
+    
+    /* tells in which temporary a given register is. It does not take
+       into account fixed registers */
+    int reg_to_temp[TCG_TARGET_NB_REGS];
+    TCGRegSet reserved_regs;
+    tcg_target_long current_frame_offset;
+    tcg_target_long frame_start;
+    tcg_target_long frame_end;
+    int frame_reg;
+
+    uint8_t *code_ptr;
+    TCGTemp static_temps[TCG_MAX_TEMPS];
+
+    TCGHelperInfo *helpers;
+    int nb_helpers;
+    int allocated_helpers;
+    int helpers_sorted;
+
+#ifdef CONFIG_PROFILER
+    /* profiling info */
+    int64_t tb_count1;
+    int64_t tb_count;
+    int64_t op_count; /* total insn count */
+    int op_count_max; /* max insn per TB */
+    int64_t temp_count;
+    int temp_count_max;
+    int64_t del_op_count;
+    int64_t code_in_len;
+    int64_t code_out_len;
+    int64_t interm_time;
+    int64_t code_time;
+    int64_t la_time;
+    int64_t restore_count;
+    int64_t restore_time;
+#endif
+
+#ifdef CONFIG_DEBUG_TCG
+    int temps_in_use;
+#endif
+};
+
+extern TCGContext tcg_ctx;
+extern uint16_t *gen_opc_ptr;
+extern TCGArg *gen_opparam_ptr;
+extern uint16_t gen_opc_buf[];
+extern TCGArg gen_opparam_buf[];
+
+/* pool based memory allocation */
+
+void *tcg_malloc_internal(TCGContext *s, int size);
+void tcg_pool_reset(TCGContext *s);
+void tcg_pool_delete(TCGContext *s);
+
+static inline void *tcg_malloc(int size)
+{
+    TCGContext *s = &tcg_ctx;
+    uint8_t *ptr, *ptr_end;
+    size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1);
+    ptr = s->pool_cur;
+    ptr_end = ptr + size;
+    if (unlikely(ptr_end > s->pool_end)) {
+        return tcg_malloc_internal(&tcg_ctx, size);
+    } else {
+        s->pool_cur = ptr_end;
+        return ptr;
+    }
+}
+
+void tcg_context_init(TCGContext *s);
+void tcg_prologue_init(TCGContext *s);
+void tcg_func_start(TCGContext *s);
+
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
+
+void tcg_set_frame(TCGContext *s, int reg,
+                   tcg_target_long start, tcg_target_long size);
+
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+                                const char *name);
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
+static inline TCGv_i32 tcg_temp_new_i32(void)
+{
+    return tcg_temp_new_internal_i32(0);
+}
+static inline TCGv_i32 tcg_temp_local_new_i32(void)
+{
+    return tcg_temp_new_internal_i32(1);
+}
+void tcg_temp_free_i32(TCGv_i32 arg);
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
+
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+                                const char *name);
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
+static inline TCGv_i64 tcg_temp_new_i64(void)
+{
+    return tcg_temp_new_internal_i64(0);
+}
+static inline TCGv_i64 tcg_temp_local_new_i64(void)
+{
+    return tcg_temp_new_internal_i64(1);
+}
+void tcg_temp_free_i64(TCGv_i64 arg);
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
+
+#if defined(CONFIG_DEBUG_TCG)
+/* If you call tcg_clear_temp_count() at the start of a section of
+ * code which is not supposed to leak any TCG temporaries, then
+ * calling tcg_check_temp_count() at the end of the section will
+ * return 1 if the section did in fact leak a temporary.
+ */
+void tcg_clear_temp_count(void);
+int tcg_check_temp_count(void);
+#else
+#define tcg_clear_temp_count() do { } while (0)
+#define tcg_check_temp_count() 0
+#endif
+
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
+
+#define TCG_CT_ALIAS  0x80
+#define TCG_CT_IALIAS 0x40
+#define TCG_CT_REG    0x01
+#define TCG_CT_CONST  0x02 /* any constant of register size */
+
+typedef struct TCGArgConstraint {
+    uint16_t ct;
+    uint8_t alias_index;
+    union {
+        TCGRegSet regs;
+    } u;
+} TCGArgConstraint;
+
+#define TCG_MAX_OP_ARGS 16
+
+#define TCG_OPF_BB_END     0x01 /* instruction defines the end of a basic
+                                   block */
+#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers 
+                                   and potentially update globals. */
+#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
+                                     cannot be removed if its output
+                                     are not used */
+
+typedef struct TCGOpDef {
+    const char *name;
+    uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
+    uint8_t flags;
+    TCGArgConstraint *args_ct;
+    int *sorted_args;
+#if defined(CONFIG_DEBUG_TCG)
+    int used;
+#endif
+} TCGOpDef;
+        
+typedef struct TCGTargetOpDef {
+    TCGOpcode op;
+    const char *args_ct_str[TCG_MAX_OP_ARGS];
+} TCGTargetOpDef;
+
+#define tcg_abort() \
+do {\
+    fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\
+    abort();\
+} while (0)
+
+void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
+
+#if TCG_TARGET_REG_BITS == 32
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32(V))
+#define tcg_global_reg_new_ptr(R, N) \
+    TCGV_NAT_TO_PTR(tcg_global_reg_new_i32((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+    TCGV_NAT_TO_PTR(tcg_global_mem_new_i32((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i32())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i32(TCGV_PTR_TO_NAT(T))
+#else
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I64(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I64(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64(V))
+#define tcg_global_reg_new_ptr(R, N) \
+    TCGV_NAT_TO_PTR(tcg_global_reg_new_i64((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+    TCGV_NAT_TO_PTR(tcg_global_mem_new_i64((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i64())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
+#endif
+
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+                   int sizemask, TCGArg ret, int nargs, TCGArg *args);
+
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
+                        int c, int right, int arith);
+
+/* only used for debugging purposes */
+void tcg_register_helper(void *func, const char *name);
+const char *tcg_helper_get_name(TCGContext *s, void *func);
+void tcg_dump_ops(TCGContext *s, FILE *outfile);
+
+void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
+TCGv_i32 tcg_const_i32(int32_t val);
+TCGv_i64 tcg_const_i64(int64_t val);
+TCGv_i32 tcg_const_local_i32(int32_t val);
+TCGv_i64 tcg_const_local_i64(int64_t val);
+
+extern uint8_t code_gen_prologue[];
+#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
+#define tcg_qemu_tb_exec(env, tb_ptr)                                    \
+    ((long REGPARM __attribute__ ((longcall)) (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
+#else
+#define tcg_qemu_tb_exec(env, tb_ptr)                                    \
+    ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
+#endif
diff --git a/qemu-0.15.x/test-qmp-commands.c b/qemu-0.15.x/test-qmp-commands.c
new file mode 100644
index 0000000..7752904
--- /dev/null
+++ b/qemu-0.15.x/test-qmp-commands.c
@@ -0,0 +1,113 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "test-qmp-commands.h"
+#include "qapi/qmp-core.h"
+#include "module.h"
+
+void qmp_user_def_cmd(Error **errp)
+{
+}
+
+void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
+{
+}
+
+UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
+{
+    UserDefTwo *ret;
+    UserDefOne *ud1c = qemu_mallocz(sizeof(UserDefOne));
+    UserDefOne *ud1d = qemu_mallocz(sizeof(UserDefOne));
+
+    ud1c->string = strdup(ud1a->string);
+    ud1c->integer = ud1a->integer;
+    ud1d->string = strdup(ud1b->string);
+    ud1d->integer = ud1b->integer;
+
+    ret = qemu_mallocz(sizeof(UserDefTwo));
+    ret->string = strdup("blah1");
+    ret->dict.string = strdup("blah2");
+    ret->dict.dict.userdef = ud1c;
+    ret->dict.dict.string = strdup("blah3");
+    ret->dict.has_dict2 = true;
+    ret->dict.dict2.userdef = ud1d;
+    ret->dict.dict2.string = strdup("blah4");
+
+    return ret;
+}
+
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_error(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that involve both input parameters and return values */
+static void test_dispatch_cmd_io(void)
+{
+    QDict *req = qdict_new();
+    QDict *args = qdict_new();
+    QDict *ud1a = qdict_new();
+    QDict *ud1b = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
+    qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
+    qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
+    qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
+    qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
+    qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
+    qdict_put_obj(req, "arguments", QOBJECT(args));
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    /* TODO: put in full payload and check for errors */
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
+    g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
+    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+
+    module_call_init(MODULE_INIT_QAPI);
+    g_test_run();
+
+    return 0;
+}
diff --git a/qemu-0.15.x/test-visitor.c b/qemu-0.15.x/test-visitor.c
new file mode 100644
index 0000000..5133ad6
--- /dev/null
+++ b/qemu-0.15.x/test-visitor.c
@@ -0,0 +1,306 @@
+#include <glib.h>
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestStruct
+{
+    int64_t x;
+    int64_t y;
+} TestStruct;
+
+typedef struct TestStructList
+{
+    TestStruct *value;
+    struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), errp);
+    visit_type_int(v, &(*obj)->x, "x", errp);
+    visit_type_int(v, &(*obj)->y, "y", errp);
+    visit_end_struct(v, errp);
+}
+
+static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
+{
+    GenericList *i;
+
+    visit_start_list(m, name, errp);
+
+    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+        TestStructList *native_i = (TestStructList *)i;
+        visit_type_TestStruct(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+
+/* test core visitor methods */
+static void test_visitor_core(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    TestStruct ts = { 42, 82 };
+    TestStruct *pts = &ts;
+    TestStructList *lts = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+    int64_t value = 0;
+
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+
+    obj = qmp_output_get_qobject(mo);
+
+    str = qobject_to_json(obj);
+
+    printf("%s\n", qstring_get_str(str));
+
+    QDECREF(str);
+
+    obj = QOBJECT(qint_from_int(0x42));
+
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_int(v, &value, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(value == 0x42);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("{'x': 42, 'y': 84}");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    pts = NULL;
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(pts != NULL);
+    g_assert(pts->x == 42);
+    g_assert(pts->y == 84);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(lts != NULL);
+    g_assert(lts->value->x == 42);
+    g_assert(lts->value->y == 84);
+
+    lts = lts->next;
+    g_assert(lts != NULL);
+    g_assert(lts->value->x == 12);
+    g_assert(lts->value->y == 24);
+
+    g_assert(lts->next == NULL);
+
+    qobject_decref(obj);
+}
+
+/* test deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    UserDefOne ud1;
+    UserDefOne *ud1_p = &ud1, *ud1c_p = NULL;
+    UserDefTwo ud2;
+    UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    ud1.integer = 42;
+    ud1.string = strdup("fourty two");
+
+    /* sanity check */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefOne(v, &ud1_p, "o_O", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    qobject_decref(obj);
+
+    ud2.string = strdup("fourty three");
+    ud2.dict.string = strdup("fourty four");
+    ud2.dict.dict.userdef = ud1_p;
+    ud2.dict.dict.string = strdup("fourty five");
+    ud2.dict.has_dict2 = true;
+    ud2.dict.dict2.userdef = ud1_p;
+    ud2.dict.dict2.string = strdup("fourty six");
+
+    /* c type -> qobject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefTwo(v, &ud2_p, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* qobject -> c type, should match original struct */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_UserDefTwo(v, &ud2c_p, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(!g_strcmp0(ud2c_p->string, ud2.string));
+    g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict2.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string));
+    qemu_free(ud1.string);
+    qemu_free(ud2.string);
+    qemu_free(ud2.dict.string);
+    qemu_free(ud2.dict.dict.string);
+    qemu_free(ud2.dict.dict2.string);
+
+    qapi_free_UserDefTwo(ud2c_p);
+
+    qobject_decref(obj);
+}
+
+/* test enum values */
+static void test_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    EnumOne enum1 = ENUM_ONE_VALUE2, enum1_cpy = ENUM_ONE_VALUE1;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_EnumOne(v, &enum1, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+    g_assert(g_strcmp0(qstring_get_str(qobject_to_qstring(obj)), "value2") == 0);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_EnumOne(v, &enum1_cpy, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_debug("enum1_cpy, enum1: %d, %d", enum1_cpy, enum1);
+    g_assert(enum1_cpy == enum1);
+
+    qobject_decref(obj);
+}
+
+/* test enum values nested in schema-defined structs */
+static void test_nested_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    nested_enums = qemu_mallocz(sizeof(NestedEnumsOne));
+    nested_enums->enum1 = ENUM_ONE_VALUE1;
+    nested_enums->enum2 = ENUM_ONE_VALUE2;
+    nested_enums->enum3 = ENUM_ONE_VALUE3;
+    nested_enums->enum4 = ENUM_ONE_VALUE3;
+    nested_enums->has_enum2 = false;
+    nested_enums->has_enum4 = true;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_assert(nested_enums_cpy);
+    g_assert(nested_enums_cpy->enum1 == nested_enums->enum1);
+    g_assert(nested_enums_cpy->enum3 == nested_enums->enum3);
+    g_assert(nested_enums_cpy->enum4 == nested_enums->enum4);
+    g_assert(nested_enums_cpy->has_enum2 == false);
+    g_assert(nested_enums_cpy->has_enum4 == true);
+
+    qobject_decref(obj);
+    qapi_free_NestedEnumsOne(nested_enums);
+    qapi_free_NestedEnumsOne(nested_enums_cpy);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/0.15/visitor_core", test_visitor_core);
+    g_test_add_func("/0.15/nested_structs", test_nested_structs);
+    g_test_add_func("/0.15/enums", test_enums);
+    g_test_add_func("/0.15/nested_enums", test_nested_enums);
+
+    g_test_run();
+
+    return 0;
+}
diff --git a/qemu-0.15.x/tests/Makefile b/qemu-0.15.x/tests/Makefile
new file mode 100644
index 0000000..430e0c1
--- /dev/null
+++ b/qemu-0.15.x/tests/Makefile
@@ -0,0 +1,151 @@
+-include ../config-host.mak
+-include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/tests)
+
+QEMU=../i386-linux-user/qemu-i386
+QEMU_X86_64=../x86_64-linux-user/qemu-x86_64
+CC_X86_64=$(CC_I386) -m64
+
+QEMU_INCLUDES += -I..
+CFLAGS=-Wall -O2 -g -fno-strict-aliasing
+#CFLAGS+=-msse2
+LDFLAGS=
+
+# TODO: automatically detect ARM and MIPS compilers, and run those too
+
+# runcom maps page 0, so it requires root privileges
+# also, pi_10.com runs indefinitely
+
+I386_TESTS=hello-i386 \
+	   linux-test \
+	   testthread \
+	   sha1-i386 \
+	   test-i386 \
+	   test-mmap \
+	   # runcom
+
+# native i386 compilers sometimes are not biarch.  assume cross-compilers are
+ifneq ($(ARCH),i386)
+I386_TESTS+=run-test-x86_64
+endif
+
+TESTS = test_path
+ifneq ($(call find-in-path, $(CC_I386)),)
+TESTS += $(I386_TESTS)
+endif
+
+all: $(patsubst %,run-%,$(TESTS))
+
+# rules to run tests
+
+.PHONY: $(patsubst %,run-%,$(TESTS))
+
+run-%: %
+	-$(QEMU) ./$*
+
+run-hello-i386: hello-i386
+run-linux-test: linux-test
+run-testthread: testthread
+run-sha1-i386: sha1-i386
+
+run-test-i386: test-i386
+	./test-i386 > test-i386.ref
+	-$(QEMU) test-i386 > test-i386.out
+	@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
+
+run-test-x86_64: test-x86_64
+	./test-x86_64 > test-x86_64.ref
+	-$(QEMU_X86_64) test-x86_64 > test-x86_64.out
+	@if diff -u test-x86_64.ref test-x86_64.out ; then echo "Auto Test OK"; fi
+
+run-test-mmap: test-mmap
+	-$(QEMU) ./test-mmap
+	-$(QEMU) -p 8192 ./test-mmap 8192
+	-$(QEMU) -p 16384 ./test-mmap 16384
+	-$(QEMU) -p 32768 ./test-mmap 32768
+
+run-runcom: runcom
+	-$(QEMU) ./runcom $(SRC_PATH)/tests/pi_10.com
+
+run-test_path: test_path
+	./test_path
+
+# rules to compile tests
+
+test_path: test_path.o
+test_path.o: test_path.c
+
+hello-i386: hello-i386.c
+	$(CC_I386) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
+	strip $@
+
+testthread: testthread.c
+	$(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
+
+# i386/x86_64 emulation test (test various opcodes) */
+test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
+           test-i386.h test-i386-shift.h test-i386-muldiv.h
+	$(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ \
+              $(<D)/test-i386.c $(<D)/test-i386-code16.S $(<D)/test-i386-vm86.S -lm
+
+test-x86_64: test-i386.c \
+           test-i386.h test-i386-shift.h test-i386-muldiv.h
+	$(CC_X86_64) $(CFLAGS) $(LDFLAGS) -o $@ $(<D)/test-i386.c -lm
+
+# generic Linux and CPU test
+linux-test: linux-test.c
+	$(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
+
+# vm86 test
+runcom: runcom.c
+	$(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+test-mmap: test-mmap.c
+	$(CC_I386) -m32 $(CFLAGS) -Wall -O2 $(LDFLAGS) -o $@ $<
+
+# speed test
+sha1-i386: sha1.c
+	$(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+sha1: sha1.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+speed: sha1 sha1-i386
+	time ./sha1
+	time $(QEMU) ./sha1-i386
+
+# broken test
+# NOTE: -fomit-frame-pointer is currently needed : this is a bug in libqemu
+qruncom: qruncom.c ../ioport-user.c ../i386-user/libqemu.a
+	$(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user -I../fpu \
+              -o $@ $(filter %.c, $^) -L../i386-user -lqemu -lm
+
+# arm test
+hello-arm: hello-arm.o
+	arm-linux-ld -o $@ $<
+
+hello-arm.o: hello-arm.c
+	arm-linux-gcc -Wall -g -O2 -c -o $@ $<
+
+test-arm-iwmmxt: test-arm-iwmmxt.s
+	cpp < $< | arm-linux-gnu-gcc -Wall -static -march=iwmmxt -mabi=aapcs -x assembler - -o $@
+
+# MIPS test
+hello-mips: hello-mips.c
+	mips-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $<
+
+hello-mipsel: hello-mips.c
+	mipsel-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $<
+
+# testsuite for the CRIS port.
+test-cris:
+	$(MAKE) -C cris check
+
+# testsuite for the LM32 port.
+test-lm32:
+	$(MAKE) -C lm32 check
+
+clean:
+	rm -f *~ *.o test-i386.out test-i386.ref \
+           test-x86_64.log test-x86_64.ref qruncom $(TESTS)
diff --git a/qemu-0.15.x/tests/alpha/Makefile b/qemu-0.15.x/tests/alpha/Makefile
new file mode 100644
index 0000000..2b1f03d
--- /dev/null
+++ b/qemu-0.15.x/tests/alpha/Makefile
@@ -0,0 +1,35 @@
+CROSS=alpha-linux-gnu-
+CC=$(CROSS)gcc
+AS=$(CROSS)as
+
+SIM=../../alpha-linux-user/qemu-alpha
+
+CFLAGS=-O
+LINK=$(CC) -o $@ crt.o $< -nostdlib
+
+TESTS=test-cond test-cmov
+
+all: hello-alpha $(TESTS)
+
+hello-alpha: hello-alpha.o crt.o
+	$(LINK)
+
+test-cond: test-cond.o crt.o
+	$(LINK)
+
+test-cmov.o: test-cond.c
+	$(CC) -c $(CFLAGS) -DTEST_CMOV -o $@ $<
+
+test-cmov: test-cmov.o crt.o
+	$(LINK)
+
+test-ovf: test-ovf.o crt.o
+	$(LINK)
+
+check: $(TESTS)
+	for f in $(TESTS); do $(SIM) $$f || exit 1; done
+
+clean:
+	$(RM) *.o *~ hello-alpha $(TESTS)
+
+.PHONY: clean all check
diff --git a/qemu-0.15.x/tests/alpha/crt.s b/qemu-0.15.x/tests/alpha/crt.s
new file mode 100644
index 0000000..31af882
--- /dev/null
+++ b/qemu-0.15.x/tests/alpha/crt.s
@@ -0,0 +1,26 @@
+	.text
+
+	.globl _start
+	.ent _start,0
+_start:
+	.frame $15,0,$15
+	br $29,1f
+1:	ldgp $29, 0($29)
+	.prologue 0
+	ldq $27,main($29) !literal!1
+	jsr $26,($27)
+	or $0,$0,$16
+	.end _start
+
+	.globl _exit
+_exit:
+	lda $0,1
+	callsys
+
+	call_pal 0
+
+	.globl write
+write:
+	lda $0,4
+	callsys
+	ret
diff --git a/qemu-0.15.x/tests/alpha/hello-alpha.c b/qemu-0.15.x/tests/alpha/hello-alpha.c
new file mode 100644
index 0000000..79892e6
--- /dev/null
+++ b/qemu-0.15.x/tests/alpha/hello-alpha.c
@@ -0,0 +1,5 @@
+int main (void)
+{
+  write (1, "hello\n", 6);
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/alpha/test-cond.c b/qemu-0.15.x/tests/alpha/test-cond.c
new file mode 100644
index 0000000..74adffa
--- /dev/null
+++ b/qemu-0.15.x/tests/alpha/test-cond.c
@@ -0,0 +1,87 @@
+
+#ifdef TEST_CMOV
+
+#define TEST_COND(N) 				\
+int test_##N (long a)				\
+{						\
+  int res = 1;					\
+						\
+  asm ("cmov"#N" %1,$31,%0"			\
+       : "+r" (res) : "r" (a));			\
+  return !res;					\
+}
+
+#else
+
+#define TEST_COND(N) 				\
+int test_##N (long a)				\
+{						\
+  int res = 1;					\
+						\
+  asm ("b"#N" %1,1f\n\t"			\
+       "addq $31,$31,%0\n\t"			\
+       "1: unop\n"				\
+       : "+r" (res) : "r" (a));			\
+  return res;					\
+}
+
+#endif
+
+TEST_COND(eq)
+TEST_COND(ne)
+TEST_COND(ge)
+TEST_COND(gt)
+TEST_COND(lbc)
+TEST_COND(lbs)
+TEST_COND(le)
+TEST_COND(lt)
+
+static struct {
+  int (*func)(long);
+  long v;
+  int r;
+} vectors[] =
+  {
+    {test_eq, 0, 1},
+    {test_eq, 1, 0},
+
+    {test_ne, 0, 0},
+    {test_ne, 1, 1},
+
+    {test_ge, 0, 1},
+    {test_ge, 1, 1},
+    {test_ge, -1, 0},
+
+    {test_gt, 0, 0},
+    {test_gt, 1, 1},
+    {test_gt, -1, 0},
+
+    {test_lbc, 0, 1},
+    {test_lbc, 1, 0},
+    {test_lbc, -1, 0},
+
+    {test_lbs, 0, 0},
+    {test_lbs, 1, 1},
+    {test_lbs, -1, 1},
+
+    {test_le, 0, 1},
+    {test_le, 1, 0},
+    {test_le, -1, 1},
+
+    {test_lt, 0, 0},
+    {test_lt, 1, 0},
+    {test_lt, -1, 1},
+  };
+
+int main (void)
+{
+  int i;
+
+  for (i = 0; i < sizeof (vectors)/sizeof(vectors[0]); i++)
+    if ((*vectors[i].func)(vectors[i].v) != vectors[i].r) {
+      write(1, "Failed\n", 7);
+      return 1;
+    }
+  write(1, "OK\n", 3);
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/alpha/test-ovf.c b/qemu-0.15.x/tests/alpha/test-ovf.c
new file mode 100644
index 0000000..01c80e7
--- /dev/null
+++ b/qemu-0.15.x/tests/alpha/test-ovf.c
@@ -0,0 +1,29 @@
+static long test_subqv (long a, long b)
+{
+  long res;
+
+  asm ("subq/v %1,%2,%0"
+       : "=r" (res) : "r" (a), "r" (b));
+  return res;
+}
+static struct {
+  long (*func)(long, long);
+  long a;
+  long b;
+  long r;
+} vectors[] =
+  {
+    {test_subqv, 0, 0x7d54000, 0xfffffffff82ac000L}
+  };
+
+int main (void)
+{
+  int i;
+
+  for (i = 0; i < sizeof (vectors)/sizeof(vectors[0]); i++)
+    if ((*vectors[i].func)(vectors[i].a, vectors[i].b) != vectors[i].r) {
+      write(1, "Failed\n", 7);
+    }
+  write(1, "OK\n", 3);
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/Makefile b/qemu-0.15.x/tests/cris/Makefile
new file mode 100644
index 0000000..b86bcad
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/Makefile
@@ -0,0 +1,155 @@
+-include ../../config-host.mak
+
+CROSS=crisv32-axis-linux-gnu-
+SIM=../../cris-linux-user/qemu-cris -L ./
+SIMG=cris-axis-linux-gnu-run --sysroot=./
+
+CC      = $(CROSS)gcc
+#AS      = $(CROSS)as
+AS	= $(CC) -x assembler-with-cpp
+SIZE    = $(CROSS)size
+LD      = $(CC)
+OBJCOPY = $(CROSS)objcopy
+
+# we rely on GCC inline:ing the stuff we tell it to in many places here.
+CFLAGS  = -Winline -Wall -g -O2 -static
+NOSTDFLAGS = -nostartfiles -nostdlib
+ASFLAGS += -g -Wa,-I,$(SRC_PATH)/tests/cris/
+LDLIBS  =
+NOSTDLIBS = -lgcc
+
+CRT        = crt.o
+SYS        = sys.o
+TESTCASES += check_abs.tst
+TESTCASES += check_addc.tst
+TESTCASES += check_addcm.tst
+TESTCASES += check_addo.tst
+TESTCASES += check_addoq.tst
+TESTCASES += check_addi.tst
+TESTCASES += check_addiv32.tst
+TESTCASES += check_addm.tst
+TESTCASES += check_addr.tst
+TESTCASES += check_addq.tst
+TESTCASES += check_addxc.tst
+TESTCASES += check_addxm.tst
+TESTCASES += check_addxr.tst
+TESTCASES += check_andc.tst
+TESTCASES += check_andm.tst
+TESTCASES += check_andr.tst
+TESTCASES += check_andq.tst
+TESTCASES += check_asr.tst
+TESTCASES += check_ba.tst
+TESTCASES += check_bas.tst
+TESTCASES += check_bcc.tst
+TESTCASES += check_bound.tst
+TESTCASES += check_boundc.tst
+TESTCASES += check_boundr.tst
+TESTCASES += check_btst.tst
+TESTCASES += check_clearfv32.tst
+TESTCASES += check_cmpc.tst
+TESTCASES += check_cmpr.tst
+TESTCASES += check_cmpq.tst
+TESTCASES += check_cmpm.tst
+TESTCASES += check_cmpxc.tst
+TESTCASES += check_cmpxm.tst
+TESTCASES += check_cmp-2.tst
+TESTCASES += check_clrjmp1.tst
+TESTCASES += check_dstep.tst
+TESTCASES += check_ftag.tst
+TESTCASES += check_int64.tst
+# check_jsr is broken.
+#TESTCASES += check_jsr.tst
+TESTCASES += check_mcp.tst
+TESTCASES += check_movei.tst
+TESTCASES += check_mover.tst
+TESTCASES += check_moverm.tst
+TESTCASES += check_moveq.tst
+TESTCASES += check_movemr.tst
+TESTCASES += check_movemrv32.tst
+TESTCASES += check_movecr.tst
+TESTCASES += check_movmp.tst
+TESTCASES += check_movpr.tst
+TESTCASES += check_movprv32.tst
+TESTCASES += check_movdelsr1.tst
+TESTCASES += check_movpmv32.tst
+TESTCASES += check_movsr.tst
+TESTCASES += check_movsm.tst
+TESTCASES += check_movscr.tst
+TESTCASES += check_movur.tst
+TESTCASES += check_movum.tst
+TESTCASES += check_movucr.tst
+TESTCASES += check_mulx.tst
+TESTCASES += check_mulv32.tst
+TESTCASES += check_neg.tst
+TESTCASES += check_not.tst
+TESTCASES += check_lz.tst
+TESTCASES += check_lapc.tst
+TESTCASES += check_lsl.tst
+TESTCASES += check_lsr.tst
+TESTCASES += check_orc.tst
+TESTCASES += check_orm.tst
+TESTCASES += check_orr.tst
+TESTCASES += check_orq.tst
+TESTCASES += check_ret.tst
+TESTCASES += check_swap.tst
+TESTCASES += check_scc.tst
+TESTCASES += check_subc.tst
+TESTCASES += check_subq.tst
+TESTCASES += check_subr.tst
+TESTCASES += check_subm.tst
+TESTCASES += check_glibc_kernelversion.tst
+TESTCASES += check_xarith.tst
+
+TESTCASES += check_hello.ctst
+TESTCASES += check_stat1.ctst
+TESTCASES += check_stat2.ctst
+TESTCASES += check_stat3.ctst
+TESTCASES += check_stat4.ctst
+TESTCASES += check_openpf1.ctst
+TESTCASES += check_openpf2.ctst
+TESTCASES += check_openpf3.ctst
+TESTCASES += check_openpf4.ctst
+TESTCASES += check_openpf5.ctst
+TESTCASES += check_mapbrk.ctst
+TESTCASES += check_mmap1.ctst
+TESTCASES += check_mmap2.ctst
+TESTCASES += check_mmap3.ctst
+TESTCASES += check_sigalrm.ctst
+TESTCASES += check_time1.ctst
+TESTCASES += check_time2.ctst
+TESTCASES += check_settls1.ctst
+
+TESTCASES += check_gcctorture_pr28634-1.ctst
+#TESTCASES += check_gcctorture_pr28634.ctst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/cris/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/cris/%.s
+	$(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o
+	$(CC) $(CFLAGS) $(NOSTDFLAGS) $(LDLIBS) $(NOSTDLIBS) $(CRT) $< $(SYS) -o $@
+
+%.ctst: %.o
+	$(CC) $(CFLAGS) $(LDLIBS) $< -o $@
+
+build: $(CRT) $(SYS) $(TESTCASES)
+
+check: $(CRT) $(SYS) $(TESTCASES)
+	@echo -e "\nQEMU simulator."
+	for case in $(TESTCASES); do \
+		echo -n "$$case "; \
+		$(SIM) ./$$case; \
+	done
+check-g: $(CRT) $(SYS) $(TESTCASES)
+	@echo -e "\nGDB simulator."
+	@for case in $(TESTCASES); do \
+		echo -n "$$case "; \
+		$(SIMG) $$case; \
+	done
+
+clean:
+	$(RM) -fr $(TESTCASES) $(CRT) $(SYS)
diff --git a/qemu-0.15.x/tests/cris/README b/qemu-0.15.x/tests/cris/README
new file mode 100644
index 0000000..2e65a76
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/README
@@ -0,0 +1 @@
+Test-suite for the cris port. Heavily based on the test-suite for the CRIS port of sim by Hans-Peter Nilsson.
diff --git a/qemu-0.15.x/tests/cris/check_abs.c b/qemu-0.15.x/tests/cris/check_abs.c
new file mode 100644
index 0000000..9770a8d
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_abs.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+static inline int cris_abs(int n)
+{
+	int r;
+	asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n));
+	return r;
+}
+
+static inline void
+verify_abs(int val, int res,
+	   const int n, const int z, const int v, const int c)
+{
+	int r;
+
+	cris_tst_cc_init();
+	r = cris_abs(val);
+	cris_tst_cc(n, z, v, c);
+	if (r != res)
+		err();
+}
+
+int main(void)
+{
+	verify_abs(-1, 1, 0, 0, 0, 0);
+	verify_abs(0x80000000, 0x80000000, 1, 0, 0, 0);
+	verify_abs(0x7fffffff, 0x7fffffff, 0, 0, 0, 0);
+	verify_abs(42, 42, 0, 0, 0, 0);
+	verify_abs(1, 1, 0, 0, 0, 0);
+	verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
+	verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
+	verify_abs(-31, 0x1f, 0, 0, 0, 0);
+	verify_abs(0, 0, 0, 1, 0, 0);
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_addc.c b/qemu-0.15.x/tests/cris/check_addc.c
new file mode 100644
index 0000000..facd1be
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addc.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+static inline int cris_addc(int a, const int b)
+{
+	asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b));
+	return a;
+}
+
+#define verify_addc(a, b, res, n, z, v, c)  \
+{                                           \
+	int r;                              \
+	r = cris_addc((a), (b));            \
+	cris_tst_cc((n), (z), (v), (c));    \
+	if (r != (res))                     \
+		err();                      \
+}
+
+int main(void)
+{
+	cris_tst_cc_init();
+	asm volatile ("clearf cz");
+	verify_addc(0, 0, 0, 0, 0, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("setf z");
+	verify_addc(0, 0, 0, 0, 1, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("setf cz");
+	verify_addc(0, 0, 1, 0, 0, 0, 0);
+	cris_tst_cc_init();
+	asm volatile ("clearf c");
+	verify_addc(-1, 2, 1, 0, 0, 0, 1);
+
+	cris_tst_cc_init();
+	asm volatile ("clearf nzv");
+	asm volatile ("setf c");
+	verify_addc(-1, 2, 2, 0, 0, 0, 1);
+
+	cris_tst_cc_init();
+	asm volatile ("setf c");
+	verify_addc(0xffff, 0xffff, 0x1ffff, 0, 0, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("clearf nzvc");
+	verify_addc(-1, -1, 0xfffffffe, 1, 0, 0, 1);
+
+	cris_tst_cc_init();
+	asm volatile ("setf c");
+	verify_addc(0x78134452, 0x5432f789, 0xcc463bdc, 1, 0, 1, 0);
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_addcm.c b/qemu-0.15.x/tests/cris/check_addcm.c
new file mode 100644
index 0000000..7928bc9
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addcm.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+/* need to avoid acr as source here.  */
+static inline int cris_addc_m(int a, const int *b)
+{
+	asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b));
+	return a;
+}
+
+/* 'b' is a crisv32 constrain to avoid postinc with $acr.  */
+static inline int cris_addc_pi_m(int a, int **b)
+{
+	asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b));
+	return a;
+}
+
+#define verify_addc_m(a, b, res, n, z, v, c)  \
+{                                           \
+	int r;                              \
+	r = cris_addc_m((a), (b));            \
+	cris_tst_cc((n), (z), (v), (c));    \
+	if (r != (res))                     \
+		err();                      \
+}
+
+#define verify_addc_pi_m(a, b, res, n, z, v, c)  \
+{                                           \
+	int r;                              \
+	r = cris_addc_pi_m((a), (b));            \
+	cris_tst_cc((n), (z), (v), (c));    \
+	if (r != (res))                     \
+		err();                      \
+}
+
+int x[] = { 0, 0, 2, -1, 0xffff, -1, 0x5432f789};
+
+int main(void)
+{
+	int *p = (void *)&x[0];
+#if 1
+	cris_tst_cc_init();
+	asm volatile ("clearf cz");
+	verify_addc_m(0, p, 0, 0, 0, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("setf z");
+	verify_addc_m(0, p, 0, 0, 1, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("setf c");
+	verify_addc_m(0, p, 1, 0, 0, 0, 0);
+
+	cris_tst_cc_init();
+	asm volatile ("clearf c");
+	verify_addc_pi_m(0, &p, 0, 0, 1, 0, 0);
+
+	p = &x[1];
+	cris_tst_cc_init();
+	asm volatile ("setf c");
+	verify_addc_pi_m(0, &p, 1, 0, 0, 0, 0);
+
+	if (p != &x[2])
+		err();
+
+	cris_tst_cc_init();
+	asm volatile ("clearf c");
+	verify_addc_pi_m(-1, &p, 1, 0, 0, 0, 1);
+
+	if (p != &x[3])
+		err();
+#endif
+	p = &x[3];
+	/* TODO: investigate why this one fails.  */
+	cris_tst_cc_init();
+	asm volatile ("setf c");
+	verify_addc_m(2, p, 2, 0, 0, 0, 1);
+	p += 4;
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_addi.s b/qemu-0.15.x/tests/cris/check_addi.s
new file mode 100644
index 0000000..a00dec0
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addi.s
@@ -0,0 +1,57 @@
+# mach:  crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 0\n1\n2\n4\nbe02460f\n69d035a6\nc16c14d4\n
+
+ .include "testutils.inc"
+ start
+ moveq 0,r3
+ moveq 0,r4
+ clearf zcvn
+ addi r4.b,r3
+ test_cc 0 0 0 0
+ checkr3 0
+
+ moveq 0,r3
+ moveq 1,r4
+ setf zcvn
+ addi r4.b,r3
+ test_cc 1 1 1 1
+ checkr3 1
+
+ moveq 0,r3
+ moveq 1,r4
+ setf cv
+ clearf zn
+ addi r4.w,r3
+ test_cc 0 0 1 1
+ checkr3 2
+
+ moveq 0,r3
+ moveq 1,r4
+ clearf cv
+ setf zn
+ addi r4.d,r3
+ test_cc 1 1 0 0
+ checkr3 4
+
+ move.d 0x12345678,r3
+ move.d 0xabcdef97,r4
+ clearf cn
+ setf zv
+ addi r4.b,r3
+ test_cc 0 1 1 0
+ checkr3 be02460f
+
+ move.d 0x12345678,r3
+ move.d 0xabcdef97,r4
+ setf cn
+ clearf zv
+ addi r4.w,r3
+ test_cc 1 0 0 1
+ checkr3 69d035a6
+
+ move.d 0x12345678,r3
+ move.d 0xabcdef97,r4
+ addi r4.d,r3
+ checkr3 c16c14d4
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addiv32.s b/qemu-0.15.x/tests/cris/check_addiv32.s
new file mode 100644
index 0000000..20ba25d
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addiv32.s
@@ -0,0 +1,62 @@
+# mach: crisv32
+# output: 4455aa77\n4455aa77\nee19ccff\nff22\n4455aa77\nff224455\n55aa77ff\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword 0x55aa77ff
+ .dword 0xccff2244
+ .dword 0x88ccee19
+
+ start
+ setf cv
+ moveq -1,r0
+ move.d x-32768,r5
+ move.d 32769,r6
+ addi r6.b,r5,acr
+ test_cc 0 0 1 1
+ move.d [acr],r3
+ checkr3 4455aa77
+
+ addu.w 32771,r5
+ setf znvc
+ moveq -1,r8
+ addi r8.w,r5,acr
+ test_cc 1 1 1 1
+ move.d [acr],r3
+ checkr3 4455aa77
+
+ moveq 5,r10
+ clearf znvc
+ addi r10.b,acr,acr
+ test_cc 0 0 0 0
+ move.d [acr],r3
+ checkr3 ee19ccff
+
+ subq 1,r5
+ move.d r5,r8
+ subq 1,r8
+ moveq 1,r9
+ addi r9.d,r8,acr
+ test_cc 0 0 0 0
+ movu.w [acr],r3
+ checkr3 ff22
+
+ moveq -2,r11
+ addi r11.w,acr,acr
+ move.d [acr],r3
+ checkr3 4455aa77
+
+ moveq 5,r9
+ addi r9.d,acr,acr
+ subq 18,acr
+ move.d [acr],r3
+ checkr3 ff224455
+
+ move.d -76789888/4,r12
+ addi r12.d,r5,acr
+ add.d 76789886,acr
+ move.d [acr],r3
+ checkr3 55aa77ff
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addm.s b/qemu-0.15.x/tests/cris/check_addm.s
new file mode 100644
index 0000000..efece9f
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addm.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n781344d0\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword 2,-1,0xffff,-1,0x5432f789
+ .word 2,-1,0xffff,0xf789
+ .byte 2,0xff,0x89
+ .byte 0x7e
+
+ start
+ moveq -1,r3
+ move.d x,r5
+ add.d [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ add.d [r5],r3
+ test_cc 0 0 0 1
+ addq 4,r5
+ checkr3 1
+
+ move.d 0xffff,r3
+ add.d [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+
+ moveq -1,r3
+ add.d [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ move.d 0x78134452,r3
+ add.d [r5+],r3
+ test_cc 1 0 1 0
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ add.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 ffff0001
+
+ moveq 2,r3
+ add.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xffff,r3
+ add.w [r5],r3
+ test_cc 1 0 0 1
+ checkr3 fffe
+
+ move.d 0xfedaffff,r3
+ add.w [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 fedafffe
+
+ move.d 0x78134452,r3
+ add.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 78133bdb
+
+ moveq -1,r3
+ add.b [r5],r3
+ test_cc 0 0 0 1
+ addq 1,r5
+ checkr3 ffffff01
+
+ moveq 2,r3
+ add.b [r5],r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xff,r3
+ add.b [r5],r3
+ test_cc 1 0 0 1
+ checkr3 fe
+
+ move.d 0xfeda49ff,r3
+ add.b [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 feda49fe
+
+ move.d 0x78134452,r3
+ add.b [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 781344db
+
+ move.d 0x78134452,r3
+ add.b [r5],r3
+ test_cc 1 0 1 0
+ checkr3 781344d0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addo.c b/qemu-0.15.x/tests/cris/check_addo.c
new file mode 100644
index 0000000..3d8e789
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addo.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+/* this would be better to do in asm, it's an orgy in GCC inline asm now.  */
+
+#define cris_addo_b(o, v) \
+	asm volatile ("addo.b\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
+#define cris_addo_w(o, v) \
+	asm volatile ("addo.w\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
+#define cris_addo_d(o, v) \
+	asm volatile ("addo.d\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
+#define cris_addo_pi_b(o, v) \
+	asm volatile ("addo.b\t[%0+], %1, $acr\n" \
+                         : "+b" (o): "r" (v) : "acr");
+#define cris_addo_pi_w(o, v) \
+	asm volatile ("addo.w\t[%0+], %1, $acr\n" \
+                         : "+b" (o): "r" (v) : "acr");
+#define cris_addo_pi_d(o, v) \
+	asm volatile ("addo.d\t[%0+], %1, $acr\n" \
+                         : "+b" (o): "r" (v) : "acr");
+
+struct {
+	uint32_t v1;
+	uint16_t v2;
+	uint32_t v3;
+	uint8_t v4;
+	uint8_t v5;
+	uint16_t v6;
+	uint32_t v7;
+} y = {
+	32769,
+	-1,
+	5,
+	3, -4,
+	2,
+	-76789887
+};
+
+static int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
+
+int main(void)
+{
+	int *r;
+	unsigned char *t, *p;
+
+	/* Note, this test-case will trig an unaligned access, partly
+	   to x[0] and to [x1].  */
+	t = (unsigned char *)x;
+	t -= 32768;
+	p = (unsigned char *) &y.v1;
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_pi_d(p, t);
+	cris_tst_cc(1, 1, 1, 1);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*r != 0x4455aa77)
+		err();
+
+
+	t += 32770;
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_pi_w(p, t);
+	cris_tst_cc(1, 1, 1, 1);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*r != 0x4455aa77)
+		err();
+
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_d(p, r);
+	cris_tst_cc(1, 1, 1, 1);
+	p += 4;
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*r != 0xee19ccff)
+		err();
+
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_pi_b(p, t);
+	cris_tst_cc(0, 0, 0, 0);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*(uint16_t*)r != 0xff22)
+		err();
+
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_b(p, r);
+	cris_tst_cc(1, 1, 1, 1);
+	p += 1;
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*r != 0x4455aa77)
+		err();
+
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_w(p, r);
+	cris_tst_cc(1, 1, 1, 1);
+	p += 2;
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	if (*r != 0xff224455)
+		err();
+
+	mb(); /* dont reorder anything beyond here.  */
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addo_pi_d(p, t);
+	cris_tst_cc(0, 0, 0, 0);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
+	r = (void*)(((char *)r) + 76789885);
+	if (*r != 0x55aa77ff)
+		err();
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_addoq.c b/qemu-0.15.x/tests/cris/check_addoq.c
new file mode 100644
index 0000000..ed509e2
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addoq.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+/* this would be better to do in asm, it's an orgy in GCC inline asm now.  */
+
+/* ACR will be clobbered.  */
+#define cris_addoq(o, v) \
+	asm volatile ("addoq\t%1, %0, $acr\n" : : "r" (v), "i" (o) : "acr");
+
+
+int main(void)
+{
+	int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
+	int *p, *t = x + 1;
+
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addoq(0, t);
+	cris_tst_cc(1, 1, 1, 1);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
+	if (*p != 0xccff2244)
+		err();
+
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_addoq(4, t);
+	cris_tst_cc(0, 0, 0, 0);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
+	if (*p != 0x88ccee19)
+		err();
+
+	cris_tst_cc_init();
+	asm volatile ("clearf\tzvnc\n");
+	cris_addoq(-8, t + 1);
+	cris_tst_cc(0, 0, 0, 0);
+	asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
+	if (*p != 0x55aa77ff)
+		err();
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_addq.s b/qemu-0.15.x/tests/cris/check_addq.s
new file mode 100644
index 0000000..e6f874f
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addq.s
@@ -0,0 +1,47 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n0\n1\n100\n10000\n47\n67\na6\n80000001\n
+
+ .include "testutils.inc"
+ start
+ moveq -2,r3
+ addq 1,r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ addq 1,r3
+ test_cc 0 1 0 1
+ checkr3 0
+
+ addq 1,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xff,r3
+ addq 1,r3
+ test_cc 0 0 0 0
+ checkr3 100
+
+ move.d 0xffff,r3
+ addq 1,r3
+ test_cc 0 0 0 0
+ checkr3 10000
+
+ move.d 0x42,r3
+ addq 5,r3
+ test_cc 0 0 0 0
+ checkr3 47
+
+ addq 32,r3
+ test_cc 0 0 0 0
+ checkr3 67
+
+ addq 63,r3
+ test_cc 0 0 0 0
+ checkr3 a6
+
+ move.d 0x7ffffffe,r3
+ addq 3,r3
+ test_cc 1 0 1 0
+ checkr3 80000001
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addr.s b/qemu-0.15.x/tests/cris/check_addr.s
new file mode 100644
index 0000000..7f55cdc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addr.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ add.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ moveq -1,r4
+ add.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ add.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+
+ moveq -1,r4
+ move.d r4,r3
+ add.d r4,r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.d r4,r3
+ test_cc 1 0 1 0
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ moveq 2,r4
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 ffff0001
+
+ moveq 2,r3
+ moveq -1,r4
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ add.w r4,r3
+ test_cc 1 0 0 1
+ checkr3 fffe
+
+ move.d 0xfedaffff,r4
+ move.d r4,r3
+ add.w r4,r3
+ test_cc 1 0 0 1
+ checkr3 fedafffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 78133bdb
+
+ moveq -1,r3
+ moveq 2,r4
+ add.b r4,r3
+ test_cc 0 0 0 1
+ checkr3 ffffff01
+
+ moveq 2,r3
+ moveq -1,r4
+ add.b r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xff,r4
+ move.d r4,r3
+ add.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 fe
+
+ move.d 0xfeda49ff,r4
+ move.d r4,r3
+ add.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 feda49fe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 781344db
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addxc.s b/qemu-0.15.x/tests/cris/check_addxc.s
new file mode 100644
index 0000000..09c8355
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addxc.s
@@ -0,0 +1,91 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
+
+ .include "testutils.inc"
+ start
+ moveq 2,r3
+ adds.b 0xff,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ adds.w 0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ addu.b 0xff,r3
+ checkr3 101
+
+ moveq 2,r3
+ move.d 0xffffffff,r4
+ addu.w -1,r3
+ test_cc 0 0 0 0
+ checkr3 10001
+
+ move.d 0xffff,r3
+ addu.b -1,r3
+ test_cc 0 0 0 0
+ checkr3 100fe
+
+ move.d 0xffff,r3
+ addu.w -1,r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+
+ move.d 0xffff,r3
+ adds.b 0xff,r3
+ test_cc 0 0 0 1
+ checkr3 fffe
+
+ move.d 0xffff,r3
+ adds.w 0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 fffe
+
+ moveq -1,r3
+ adds.b 0xff,r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ moveq -1,r3
+ adds.w 0xff,r3
+ test_cc 0 0 0 1
+ checkr3 fe
+
+ moveq -1,r3
+ adds.w 0xffff,r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ move.d 0x78134452,r3
+ addu.b 0x89,r3
+ test_cc 0 0 0 0
+ checkr3 781344db
+
+ move.d 0x78134452,r3
+ adds.b 0x89,r3
+ test_cc 0 0 0 1
+ checkr3 781343db
+
+ move.d 0x78134452,r3
+ addu.w 0xf789,r3
+ test_cc 0 0 0 0
+ checkr3 78143bdb
+
+ move.d 0x78134452,r3
+ adds.w 0xf789,r3
+ test_cc 0 0 0 1
+ checkr3 78133bdb
+
+ move.d 0x7fffffee,r3
+ addu.b 0xff,r3
+ test_cc 1 0 1 0
+ checkr3 800000ed
+
+ move.d 0x1,r3
+ adds.w 0xffff,r3
+ test_cc 0 1 0 1
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addxm.s b/qemu-0.15.x/tests/cris/check_addxm.s
new file mode 100644
index 0000000..7563494
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addxm.s
@@ -0,0 +1,106 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .byte 0xff
+ .word 0xffff
+ .word 0xff
+ .word 0xffff
+ .byte 0x89
+ .word 0xf789
+ .byte 0xff
+ .word 0xffff
+
+ start
+ moveq 2,r3
+ move.d x,r5
+ adds.b [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ adds.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ subq 3,r5
+ addu.b [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 101
+
+ moveq 2,r3
+ addu.w [r5+],r3
+ subq 3,r5
+ test_cc 0 0 0 0
+ checkr3 10001
+
+ move.d 0xffff,r3
+ addu.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 100fe
+
+ move.d 0xffff,r3
+ addu.w [r5],r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+
+ move.d 0xffff,r3
+ adds.b [r5],r3
+ test_cc 0 0 0 1
+ checkr3 fffe
+
+ move.d 0xffff,r3
+ adds.w [r5],r3
+ test_cc 0 0 0 1
+ checkr3 fffe
+
+ moveq -1,r3
+ adds.b [r5],r3
+ test_cc 1 0 0 1
+ addq 3,r5
+ checkr3 fffffffe
+
+ moveq -1,r3
+ adds.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 fe
+
+ moveq -1,r3
+ adds.w [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ move.d 0x78134452,r3
+ addu.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 781344db
+
+ move.d 0x78134452,r3
+ adds.b [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 781343db
+
+ move.d 0x78134452,r3
+ addu.w [r5],r3
+ test_cc 0 0 0 0
+ checkr3 78143bdb
+
+ move.d 0x78134452,r3
+ adds.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 78133bdb
+
+ move.d 0x7fffffee,r3
+ addu.b [r5+],r3
+ test_cc 1 0 1 0
+ checkr3 800000ed
+
+ move.d 0x1,r3
+ adds.w [r5+],r3
+ test_cc 0 1 0 1
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_addxr.s b/qemu-0.15.x/tests/cris/check_addxr.s
new file mode 100644
index 0000000..7f55cdc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_addxr.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ add.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ moveq 2,r3
+ moveq -1,r4
+ add.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ add.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+
+ moveq -1,r4
+ move.d r4,r3
+ add.d r4,r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.d r4,r3
+ test_cc 1 0 1 0
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ moveq 2,r4
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 ffff0001
+
+ moveq 2,r3
+ moveq -1,r4
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ add.w r4,r3
+ test_cc 1 0 0 1
+ checkr3 fffe
+
+ move.d 0xfedaffff,r4
+ move.d r4,r3
+ add.w r4,r3
+ test_cc 1 0 0 1
+ checkr3 fedafffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.w r4,r3
+ test_cc 0 0 0 1
+ checkr3 78133bdb
+
+ moveq -1,r3
+ moveq 2,r4
+ add.b r4,r3
+ test_cc 0 0 0 1
+ checkr3 ffffff01
+
+ moveq 2,r3
+ moveq -1,r4
+ add.b r4,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ move.d 0xff,r4
+ move.d r4,r3
+ add.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 fe
+
+ move.d 0xfeda49ff,r4
+ move.d r4,r3
+ add.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 feda49fe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ add.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 781344db
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_andc.s b/qemu-0.15.x/tests/cris/check_andc.s
new file mode 100644
index 0000000..a947b77
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_andc.s
@@ -0,0 +1,80 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ and.d 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ and.d -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ and.d 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r3
+ and.d -1,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ and.d 0x5432f789,r3
+ test_move_cc 0 0 0 0
+ checkr3 50124400
+
+ moveq -1,r3
+ and.w 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0002
+
+ moveq 2,r3
+ and.w -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xfffff,r3
+ and.w 0xffff,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffff
+
+ move.d 0xfedaffaf,r3
+ and.w 0xff5f,r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaff0f
+
+ move.d 0x78134452,r3
+ and.w 0xf789,r3
+ test_move_cc 0 0 0 0
+ checkr3 78134400
+
+ moveq -1,r3
+ and.b 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff02
+
+ moveq 2,r3
+ and.b -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xfa7,r3
+ and.b 0x5a,r3
+ test_move_cc 0 0 0 0
+ checkr3 f02
+
+ move.d 0x78134453,r3
+ and.b 0x89,r3
+ test_move_cc 0 0 0 0
+ checkr3 78134401
+
+ and.b 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 78134400
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_andm.s b/qemu-0.15.x/tests/cris/check_andm.s
new file mode 100644
index 0000000..9385886
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_andm.s
@@ -0,0 +1,90 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword 2,-1,0xffff,-1,0x5432f789
+ .word 2,-1,0xffff,0xff5f,0xf789
+ .byte 2,-1,0x5a,0x89,0
+
+ start
+ moveq -1,r3
+ move.d x,r5
+ and.d [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ and.d [r5],r3
+ test_move_cc 0 0 0 0
+ addq 4,r5
+ checkr3 2
+
+ move.d 0xffff,r3
+ and.d [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r3
+ and.d [r5+],r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ and.d [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 50124400
+
+ moveq -1,r3
+ and.w [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0002
+
+ moveq 2,r3
+ and.w [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xfffff,r3
+ and.w [r5],r3
+ test_move_cc 1 0 0 0
+ addq 2,r5
+ checkr3 fffff
+
+ move.d 0xfedaffaf,r3
+ and.w [r5+],r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaff0f
+
+ move.d 0x78134452,r3
+ and.w [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 78134400
+
+ moveq -1,r3
+ and.b [r5],r3
+ test_move_cc 0 0 0 0
+ addq 1,r5
+ checkr3 ffffff02
+
+ moveq 2,r3
+ and.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xfa7,r3
+ and.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 f02
+
+ move.d 0x78134453,r3
+ and.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 78134401
+
+ and.b [r5],r3
+ test_move_cc 0 1 0 0
+ checkr3 78134400
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_andq.s b/qemu-0.15.x/tests/cris/check_andq.s
new file mode 100644
index 0000000..55aa7b0
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_andq.s
@@ -0,0 +1,46 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n1f\nffffffe0\n78134452\n0\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ andq 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ andq -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ andq -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r3
+ andq -1,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ andq 31,r3
+ test_move_cc 0 0 0 0
+ checkr3 1f
+
+ moveq -1,r3
+ andq -32,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffe0
+
+ move.d 0x78134457,r3
+ andq -14,r3
+ test_move_cc 0 0 0 0
+ checkr3 78134452
+
+ moveq 0,r3
+ andq -14,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_andr.s b/qemu-0.15.x/tests/cris/check_andr.s
new file mode 100644
index 0000000..61aa1dc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_andr.s
@@ -0,0 +1,95 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ and.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ moveq -1,r4
+ and.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ and.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r4
+ move.d r4,r3
+ and.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ and.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 50124400
+
+ moveq -1,r3
+ moveq 2,r4
+ and.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0002
+
+ moveq 2,r3
+ moveq -1,r4
+ and.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xfffff,r3
+ move.d 0xffff,r4
+ and.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffff
+
+ move.d 0xfedaffaf,r3
+ move.d 0xff5f,r4
+ and.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaff0f
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ and.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 78134400
+
+ moveq -1,r3
+ moveq 2,r4
+ and.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff02
+
+ moveq 2,r3
+ moveq -1,r4
+ and.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0x5a,r4
+ move.d 0xfa7,r3
+ and.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 f02
+
+ move.d 0x5432f789,r4
+ move.d 0x78134453,r3
+ and.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 78134401
+
+ moveq 0,r7
+ and.b r7,r3
+ test_move_cc 0 1 0 0
+ checkr3 78134400
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_asr.s b/qemu-0.15.x/tests/cris/check_asr.s
new file mode 100644
index 0000000..0a02ae6
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_asr.s
@@ -0,0 +1,230 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n1\nffffffff\nffffffff\n5a67f\nffffffff\nffffffff\nffffffff\nf699fc67\nffffffff\n1\nffffffff\nffffffff\n5a67f\nda67ffff\nda67ffff\nda67ffff\nda67fc67\nffffffff\nffffffff\n1\nffffffff\nffffffff\n5a670007\nda67f1ff\nda67f1ff\nda67f1ff\nda67f1e7\nffffffff\nffffffff\n1\nffffffff\nffffffff\nffffffff\n5a67f1ff\n5a67f1f9\n0\n5a670000\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ asrq 0,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ asrq 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ asrq 31,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ asrq 15,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5a67f19f,r3
+ asrq 12,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67f
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 f699fc67
+
+ moveq -1,r3
+ moveq 0,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ asr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 31,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 15,r4
+ asr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ asr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67f
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67ffff
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67ffff
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67ffff
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67fc67
+
+ moveq -1,r3
+ moveq 0,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 1,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ asr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 31,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 15,r4
+ asr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5a67719f,r3
+ moveq 12,r4
+ asr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a670007
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67f1ff
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67f1ff
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67f1ff
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67f1e7
+
+ moveq -1,r3
+ moveq 0,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 1,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ asr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 31,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 15,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 7,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+; FIXME: was wrong.
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 5a67f1ff
+
+; FIXME: was wrong.
+ move.d 0x5a67f19f,r3
+ moveq 4,r4
+ asr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 5a67f1f9
+
+ move.d 0x5a67f19f,r3
+ asrq 31,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0x5a67419f,r3
+ moveq 16,r4
+ asr.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 5a670000
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_ba.s b/qemu-0.15.x/tests/cris/check_ba.s
new file mode 100644
index 0000000..873a408
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_ba.s
@@ -0,0 +1,93 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: a\n
+
+
+ .set smalloffset,0
+ .set largeoffset,0
+
+
+	.macro fail
+	jump _fail
+	.endm
+
+	.global	main
+main:
+ moveq 0,$r3
+
+; Short forward branch.
+ ba 0f
+ addq 1,$r3
+ fail
+
+; Max short forward branch.
+1:
+ ba 2f
+ addq 1,$r3
+ fail
+
+; Short backward branch.
+0:
+ ba 1b
+ addq 1,$r3
+ fail
+
+ .space 254-2+smalloffset+1b-.,0
+ moveq 0,$r3
+
+2:
+; Transit branch (long).
+ ba 3f
+ addq 1,$r3
+ fail
+
+ moveq 0,$r3
+4:
+; Long forward branch.
+ ba 5f
+ addq 1,$r3
+ fail
+
+ .space 256-2-smalloffset+4b-.,0
+
+ moveq 0,$r3
+
+; Max short backward branch.
+3:
+ ba 4b
+ addq 1,$r3
+ fail
+
+5:
+; Max long forward branch.
+ ba 6f
+ addq 1,$r3
+ fail
+
+ .space 32766+largeoffset-2+5b-.,0
+
+ moveq 0,$r3
+6:
+; Transit branch.
+ ba 7f
+ addq 1,$r3
+ fail
+
+ moveq 0,$r3
+9:
+ jsr pass
+ nop
+
+; Transit branch.
+ moveq 0,$r3
+7:
+ ba 8f
+ addq 1,$r3
+ fail
+
+ .space 32768-largeoffset+9b-.,0
+
+8:
+; Max long backward branch.
+ ba 9b
+ addq 1,$r3
+ fail
diff --git a/qemu-0.15.x/tests/cris/check_bas.s b/qemu-0.15.x/tests/cris/check_bas.s
new file mode 100644
index 0000000..11929d4
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_bas.s
@@ -0,0 +1,102 @@
+# mach: crisv32
+# output: 0\n0\n0\nfb349abc\n0\n12124243\n0\n0\neab5baad\n0\nefb37832\n
+
+ .include "testutils.inc"
+ start
+x:
+ setf zncv
+ bsr 0f
+ nop
+0:
+ test_cc 1 1 1 1
+ move srp,r3
+ sub.d 0b,r3
+ checkr3 0
+
+ bas 1f,mof
+ moveq 0,r0
+6:
+ nop
+ quit
+
+2:
+ move srp,r3
+ sub.d 3f,r3
+ checkr3 0
+ move srp,r4
+ subq 4,r4
+ move.d [r4],r3
+ checkr3 fb349abc
+
+ basc 4f,mof
+ nop
+ .dword 0x12124243
+7:
+ nop
+ quit
+
+8:
+ move mof,r3
+ sub.d 7f,r3
+ checkr3 0
+
+ move mof,r4
+ subq 4,r4
+ move.d [r4],r3
+ checkr3 eab5baad
+
+ jasc 9f,mof
+ nop
+ .dword 0xefb37832
+0:
+ quit
+
+ quit
+9:
+ move mof,r3
+ sub.d 0b,r3
+ checkr3 0
+
+ move mof,r4
+ subq 4,r4
+ move.d [r4],r3
+ checkr3 efb37832
+
+ quit
+
+4:
+ move mof,r3
+ sub.d 7b,r3
+ checkr3 0
+ move mof,r4
+ subq 4,r4
+ move.d [r4],r3
+ checkr3 12124243
+ basc 5f,bz
+ moveq 0,r3
+ .dword 0x7634aeba
+ quit
+
+ .space 32770,0
+1:
+ move mof,r3
+ sub.d 6b,r3
+ checkr3 0
+
+ bsrc 2b
+ nop
+ .dword 0xfb349abc
+3:
+
+ quit
+
+5:
+ move mof,r3
+ sub.d 7b,r3
+ checkr3 0
+ move.d 8b,r6
+ jasc r6,mof
+ nop
+ .dword 0xeab5baad
+7:
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_bcc.s b/qemu-0.15.x/tests/cris/check_bcc.s
new file mode 100644
index 0000000..c57ffa6
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_bcc.s
@@ -0,0 +1,197 @@
+	.global	main
+	.type	main, @function
+main:
+	clearf nzvc
+	setf   nzv
+	bcc    0f
+	addq   1, $r3
+	jump   dofail
+
+0:
+	clearf nzvc
+	setf   nzv
+	bcs    dofail
+	addq   1,$r3
+
+	clearf nzvc
+	setf   ncv
+	bne    1f
+	addq   1, $r3
+
+fail:
+dofail:
+	jump	_fail
+
+1:
+	clearf nzvc
+	setf ncv
+	beq dofail
+	addq 1,$r3
+
+	clearf nzvc
+	setf ncz
+	bvc 2f
+	addq 1,$r3
+	jump dofail
+
+2:
+	clearf nzvc
+	setf ncz
+	bvs dofail
+	addq 1,$r3
+
+	clearf	nzvc
+	setf	vcz
+	bpl	3f
+	addq	1,$r3
+	jump	fail
+3:
+	clearf	nzvc
+	setf	vcz
+	bmi	dofail
+	addq	1,$r3
+
+	clearf	nzvc
+	setf	nv
+	bls	dofail
+	addq	1,$r3
+
+	clearf	nzvc
+	setf	nv
+	bhi	4f
+	addq	1,$r3
+	jump	dofail
+
+4:
+	clearf	nzvc
+	setf	zc
+	bge	5f
+	addq	1,$r3
+	jump	dofail
+
+5:
+	clearf	nzvc
+	setf zc
+	blt dofail
+	addq 1,$r3
+
+	clearf nzvc
+	setf c
+	bgt 6f
+	addq 1,$r3
+	jump  fail
+
+6:
+ clearf nzvc
+ setf c
+ ble dofail
+ addq 1,$r3
+
+;;;;;;;;;;
+
+ setf nzvc
+ clearf nzv
+ bcc dofail
+ addq 1,$r3
+
+ setf nzvc
+ clearf nzv
+ bcs 0f
+ addq 1,$r3
+ jump fail
+
+0:
+ setf nzvc
+ clearf ncv
+ bne dofail
+ addq 1,$r3
+
+ setf nzvc
+ clearf ncv
+ beq 1f
+ addq 1,$r3
+ jump fail
+
+1:
+ setf nzvc
+ clearf ncz
+ bvc dofail
+ addq 1,$r3
+
+ setf nzvc
+ clearf ncz
+ bvs 2f
+ addq 1,$r3
+ jump fail
+
+2:
+ setf nzvc
+ clearf vcz
+ bpl dofail
+ addq 1,$r3
+
+ setf nzvc
+ clearf vcz
+ bmi 3f
+ addq 1,$r3
+ jump fail
+
+3:
+ setf nzvc
+ clearf nv
+ bls 4f
+ addq 1,$r3
+ jump fail
+
+4:
+ setf nzvc
+ clearf nv
+ bhi dofail
+ addq 1,$r3
+
+ setf zvc
+ clearf nzc
+ bge dofail
+ addq 1,$r3
+
+ setf nzc
+ clearf vzc
+ blt 5f
+ addq 1,$r3
+ jump fail
+
+5:
+ setf nzvc
+ clearf c
+ bgt dofail
+ addq 1,$r3
+
+ setf nzvc
+ clearf c
+ ble 6f
+ addq 1,$r3
+ jump fail
+
+6:
+	; do a forward branch.
+	ba   2f
+	nop
+	.fill	100
+1:
+	ba	3f
+	nop
+	.fill	800
+2:
+	ba	1b
+	nop
+	.fill	1024
+3:
+
+	moveq	31, $r0
+1:	bne	1b
+	subq	1, $r0
+
+	jsr	pass
+	moveq	0, $r10
+	ret
+	nop
diff --git a/qemu-0.15.x/tests/cris/check_bound.c b/qemu-0.15.x/tests/cris/check_bound.c
new file mode 100644
index 0000000..e883175
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_bound.c
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+static inline int cris_bound_b(int v, int b)
+{
+	int r = v;
+	asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b));
+	return r;
+}
+
+static inline int cris_bound_w(int v, int b)
+{
+	int r = v;
+	asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b));
+	return r;
+}
+
+static inline int cris_bound_d(int v, int b)
+{
+	int r = v;
+	asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b));
+	return r;
+}
+
+int main(void)
+{
+	int r;
+
+	cris_tst_cc_init();
+	r = cris_bound_d(-1, 2);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_d(2, 0xffffffff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_d(0xffff, 0xffff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xffff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_d(-1, 0xffffffff);
+	cris_tst_cc(1, 0, 0, 0);
+	if (r != 0xffffffff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_d(0x78134452, 0x5432f789);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0x5432f789)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(-1, 2);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(-1, 0xffff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xffff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(2, 0xffff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(0xfedaffff, 0xffff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xffff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(0x78134452, 0xf789);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xf789)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(-1, 2);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(2, 0xff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 2)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(-1, 0xff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(0xff, 0xff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(0xfeda49ff, 0xff);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xff)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(0x78134452, 0x89);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0x89)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_w(0x78134452, 0);
+	cris_tst_cc(0, 1, 0, 0);
+	if (r != 0)
+		err();
+
+	cris_tst_cc_init();
+	r = cris_bound_b(0xffff, -1);
+	cris_tst_cc(0, 0, 0, 0);
+	if (r != 0xff)
+		err();
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_boundc.s b/qemu-0.15.x/tests/cris/check_boundc.s
new file mode 100644
index 0000000..fb9e5bc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_boundc.s
@@ -0,0 +1,101 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n5432f789\n2\nffff\n2\nffff\nffff\nf789\n2\n2\nff\nff\nff\n89\n0\nff\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ bound.d 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ bound.d 0xffffffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ bound.d 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r3
+ bound.d 0xffffffff,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ bound.d 0x5432f789,r3
+ test_move_cc 0 0 0 0
+ checkr3 5432f789
+
+ moveq -1,r3
+ bound.w 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq -1,r3
+ bound.w 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq 2,r3
+ bound.w 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ bound.w 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0xfedaffff,r3
+ bound.w 0xffff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0x78134452,r3
+ bound.w 0xf789,r3
+ test_move_cc 0 0 0 0
+ checkr3 f789
+
+ moveq -1,r3
+ bound.b 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ bound.b 0xff,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq -1,r3
+ bound.b 0xff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0xff,r3
+ bound.b 0xff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0xfeda49ff,r3
+ bound.b 0xff,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0x78134452,r3
+ bound.b 0x89,r3
+ test_move_cc 0 0 0 0
+ checkr3 89
+
+ bound.w 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xffff,r3
+ bound.b -1,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_boundr.s b/qemu-0.15.x/tests/cris/check_boundr.s
new file mode 100644
index 0000000..5c50cc5
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_boundr.s
@@ -0,0 +1,125 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\nffff\nffffffff\n5432f789\n2\n2\nffff\nffff\nffff\nf789\n2\n2\nff\nff\n89\nfeda4953\nfeda4962\n0\n0\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ bound.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ moveq -1,r4
+ bound.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ bound.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r4
+ move.d r4,r3
+ bound.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ bound.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5432f789
+
+ moveq -1,r3
+ moveq 2,r4
+ bound.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ moveq -1,r4
+ bound.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq -1,r3
+ bound.w r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ bound.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0xfedaffff,r4
+ move.d r4,r3
+ bound.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ bound.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 f789
+
+ moveq -1,r3
+ moveq 2,r4
+ bound.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ moveq 2,r3
+ moveq -1,r4
+ bound.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xff,r4
+ move.d r4,r3
+ bound.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0xfeda49ff,r4
+ move.d r4,r3
+ bound.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ bound.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 89
+
+ move.d 0xfeda4956,r3
+ move.d 0xfeda4953,r4
+ bound.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 feda4953
+
+ move.d 0xfeda4962,r3
+ move.d 0xfeda4963,r4
+ bound.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 feda4962
+
+ move.d 0xfeda4956,r3
+ move.d 0,r4
+ bound.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xfeda4956,r4
+ move.d 0,r3
+ bound.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_btst.s b/qemu-0.15.x/tests/cris/check_btst.s
new file mode 100644
index 0000000..e39fc8f
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_btst.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1111\n
+
+ .include "testutils.inc"
+ start
+ clearf nzvc
+ moveq -1,r3
+ .if 1 ;..asm.arch.cris.v32
+ .else
+ setf vc
+ .endif
+ btstq 0,r3
+ test_cc 1 0 0 0
+
+ moveq 2,r3
+ btstq 1,r3
+ test_cc 1 0 0 0
+
+ moveq 4,r3
+ btstq 1,r3
+ test_cc 0 1 0 0
+
+ moveq -1,r3
+ btstq 31,r3
+ test_cc 1 0 0 0
+
+ move.d 0x5a67f19f,r3
+ btstq 12,r3
+ test_cc 1 0 0 0
+
+ move.d 0xda67f19f,r3
+ move.d 29,r4
+ btst r4,r3
+ test_cc 0 0 0 0
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ move.d 0xda67f191,r3
+ move.d 33,r4
+ btst r4,r3
+ test_cc 0 0 0 0
+
+ moveq -1,r3
+ moveq 0,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ moveq 2,r3
+ moveq 1,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ moveq -1,r3
+ moveq 31,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ moveq 4,r3
+ btstq 1,r3
+ test_cc 0 1 0 0
+
+ moveq -1,r3
+ moveq 15,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ btst r4,r3
+ test_cc 1 0 0 0
+
+ move.d 0x5a678000,r3
+ moveq 11,r4
+ btst r4,r3
+ test_cc 0 1 0 0
+
+ move.d 0x5a67f19f,r3
+ btst r3,r3
+ test_cc 0 0 0 0
+
+ move.d 0x1111,r3
+ checkr3 1111
+
+ ; check that X gets cleared and that only the NZ flags are touched.
+ move.d	0xff, $r0
+ move $r0, $ccs
+ btst r3,r3
+ move $ccs, $r0
+ and.d 0xff, $r0
+ cmp.d	0xe3, $r0
+ test_cc 0 1 0 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_clearfv32.s b/qemu-0.15.x/tests/cris/check_clearfv32.s
new file mode 100644
index 0000000..4e91360
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_clearfv32.s
@@ -0,0 +1,19 @@
+# mach: crisv32
+# output: ef\nef\n
+
+; Check that "clearf x" doesn't trivially fail.
+
+ .include "testutils.inc"
+ start
+ setf puixnzvc
+ clearf x	; Actually, x would be cleared by almost-all other insns.
+ move ccs,r3
+ and.d 0xff, $r3
+ checkr3 ef
+
+ setf puixnzvc
+ moveq 0, $r3	; moveq should only clear the xflag.
+ move ccs,r3
+ and.d 0xff, $r3
+ checkr3 ef
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_clrjmp1.s b/qemu-0.15.x/tests/cris/check_clrjmp1.s
new file mode 100644
index 0000000..45a7005
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_clrjmp1.s
@@ -0,0 +1,36 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffff00\n
+
+; A bug resulting in a non-effectual clear.b discovered running the GCC
+; testsuite; jump actually wrote to p0.
+
+ .include "testutils.inc"
+
+ start
+ jump 1f
+ nop
+ .p2align 8
+1:
+ move.d y,r4
+
+ .if 0 ;0 == ..asm.arch.cris.v32
+; There was a bug causing this insn to set special register p0
+; (byte-clear) to 8 (low 8 bits of location after insn).
+ jump [r4+]
+ .endif
+
+1:
+ move.d 0f,r4
+
+; The corresponding bug would cause this insn too, to set p0.
+ jump r4
+ nop
+ quit
+0:
+ moveq -1,r3
+ clear.b r3
+ checkr3 ffffff00
+ quit
+
+y:
+ .dword 1b
diff --git a/qemu-0.15.x/tests/cris/check_cmp-2.s b/qemu-0.15.x/tests/cris/check_cmp-2.s
new file mode 100644
index 0000000..414d370
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmp-2.s
@@ -0,0 +1,15 @@
+
+
+.include "testutils.inc"
+
+	start
+
+	move.d	4294967283, $r0
+	move.d	$r0, $r10
+	cmp.d	$r0, $r10
+	beq	1f
+	move.d $r10, $r3
+	fail
+1:
+	pass
+	quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpc.s b/qemu-0.15.x/tests/cris/check_cmpc.s
new file mode 100644
index 0000000..267c9ba
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpc.s
@@ -0,0 +1,86 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649282\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ cmp.d -2,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.d 1,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmp.d -0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ moveq -1,r3
+ cmp.d 1,r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ cmp.d -0x5432f789,r3
+ test_cc 1 0 1 1
+ checkr3 78134452
+
+ moveq -1,r3
+ cmp.w -2,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.w 1,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmp.w 1,r3
+ test_cc 1 0 0 0
+ checkr3 ffff
+
+ move.d 0xfedaffff,r3
+ cmp.w 1,r3
+ test_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d 0x78134452,r3
+ cmp.w 0x877,r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ moveq -1,r3
+ cmp.b -2,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.b 1,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xff,r3
+ cmp.b 1,r3
+ test_cc 1 0 0 0
+ checkr3 ff
+
+ move.d 0xfeda49ff,r3
+ cmp.b 1,r3
+ test_cc 1 0 0 0
+ checkr3 feda49ff
+
+ move.d 0x78134452,r3
+ cmp.b 0x77,r3
+ test_cc 1 0 0 1
+ checkr3 78134452
+
+ move.d 0x85649282,r3
+ cmp.b 0x82,r3
+ test_cc 0 1 0 0
+ checkr3 85649282
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpm.s b/qemu-0.15.x/tests/cris/check_cmpm.s
new file mode 100644
index 0000000..e4dde15
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpm.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword -2,1,-0xffff,1,-0x5432f789
+ .word -2,1,1,0x877
+ .byte -2,1,0x77
+ .byte 0x22
+
+ start
+ moveq -1,r3
+ move.d x,r5
+ cmp.d [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.d [r5],r3
+ test_cc 0 0 0 0
+ addq 4,r5
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmp.d [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ moveq -1,r3
+ cmp.d [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ cmp.d [r5+],r3
+ test_cc 1 0 1 1
+ checkr3 78134452
+
+ moveq -1,r3
+ cmp.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmp.w [r5],r3
+ test_cc 1 0 0 0
+ checkr3 ffff
+
+ move.d 0xfedaffff,r3
+ cmp.w [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d 0x78134452,r3
+ cmp.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ moveq -1,r3
+ cmp.b [r5],r3
+ test_cc 0 0 0 0
+ addq 1,r5
+ checkr3 ffffffff
+
+ moveq 2,r3
+ cmp.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xff,r3
+ cmp.b [r5],r3
+ test_cc 1 0 0 0
+ checkr3 ff
+
+ move.d 0xfeda49ff,r3
+ cmp.b [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 feda49ff
+
+ move.d 0x78134452,r3
+ cmp.b [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 78134452
+
+ move.d 0x85649222,r3
+ cmp.b [r5],r3
+ test_cc 0 1 0 0
+ checkr3 85649222
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpq.s b/qemu-0.15.x/tests/cris/check_cmpq.s
new file mode 100644
index 0000000..5469141
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpq.s
@@ -0,0 +1,75 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1\n1f\n1f\nffffffe1\nffffffe1\nffffffe0\n0\n0\nffffffff\nffffffff\n10000\n100\n5678900\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ cmpq 1,r3
+ test_cc 0 1 0 0
+ checkr3 1
+
+ cmpq -1,r3
+ test_cc 0 0 0 1
+ checkr3 1
+
+ cmpq 31,r3
+ test_cc 1 0 0 1
+ checkr3 1
+
+ moveq 31,r3
+ cmpq 31,r3
+ test_cc 0 1 0 0
+ checkr3 1f
+
+ cmpq -31,r3
+ test_cc 0 0 0 1
+ checkr3 1f
+
+ movs.b -31,r3
+ cmpq -31,r3
+ test_cc 0 1 0 0
+ checkr3 ffffffe1
+
+ cmpq -32,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffe1
+
+ movs.b -32,r3
+ cmpq -32,r3
+ test_cc 0 1 0 0
+ checkr3 ffffffe0
+
+ moveq 0,r3
+ cmpq 1,r3
+ test_cc 1 0 0 1
+ checkr3 0
+
+ cmpq -32,r3
+ test_cc 0 0 0 1
+ checkr3 0
+
+ moveq -1,r3
+ cmpq 1,r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ cmpq -1,r3
+ test_cc 0 1 0 0
+ checkr3 ffffffff
+
+ move.d 0x10000,r3
+ cmpq 1,r3
+ test_cc 0 0 0 0
+ checkr3 10000
+
+ move.d 0x100,r3
+ cmpq 1,r3
+ test_cc 0 0 0 0
+ checkr3 100
+
+ move.d 0x5678900,r3
+ cmpq 7,r3
+ test_cc 0 0 0 0
+ checkr3 5678900
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpr.s b/qemu-0.15.x/tests/cris/check_cmpr.s
new file mode 100644
index 0000000..b30af7a
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpr.s
@@ -0,0 +1,102 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq -2,r4
+ cmp.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ cmp.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ move.d -0xffff,r4
+ cmp.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ moveq 1,r4
+ moveq -1,r3
+ cmp.d r4,r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ cmp.d r4,r3
+ test_cc 1 0 1 1
+ checkr3 78134452
+
+ moveq -1,r3
+ moveq -2,r4
+ cmp.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ cmp.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d 0xffff,r3
+ move.d -0xffff,r4
+ cmp.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 ffff
+
+ move.d 0xfedaffff,r3
+ move.d -0xfedaffff,r4
+ cmp.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ cmp.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ moveq -1,r3
+ moveq -2,r4
+ cmp.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ cmp.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 2
+
+ move.d -0xff,r4
+ move.d 0xff,r3
+ cmp.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 ff
+
+ move.d -0xfeda49ff,r4
+ move.d 0xfeda49ff,r3
+ cmp.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 feda49ff
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ cmp.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 78134452
+
+ move.d 0x85649222,r3
+ move.d 0x77445622,r4
+ cmp.b r4,r3
+ test_cc 0 1 0 0
+ checkr3 85649222
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpxc.s b/qemu-0.15.x/tests/cris/check_cmpxc.s
new file mode 100644
index 0000000..b237a93
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpxc.s
@@ -0,0 +1,92 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
+
+ .include "testutils.inc"
+ start
+ moveq 2,r3
+ cmps.b 0xff,r3
+ test_cc 0 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ cmps.w 0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ cmpu.b 0xff,r3
+ test_cc 1 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ move.d 0xffffffff,r4
+ cmpu.w -1,r3
+ test_cc 1 0 0 1
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmpu.b -1,r3
+ test_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmpu.w -1,r3
+ test_cc 0 1 0 0
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmps.b 0xff,r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmps.w 0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ moveq -1,r3
+ cmps.b 0xff,r3
+ test_cc 0 1 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ cmps.w 0xff,r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ cmps.w 0xffff,r3
+ test_cc 0 1 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ cmpu.b 0x89,r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmps.b 0x89,r3
+ test_cc 0 0 0 1
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmpu.w 0xf789,r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmps.w 0xf789,r3
+ test_cc 0 0 0 1
+ checkr3 78134452
+
+ move.d 0x4452,r3
+ cmps.w 0x8002,r3
+ test_cc 0 0 0 1
+ checkr3 4452
+
+ move.d 0x80000032,r3
+ cmpu.w 0x764,r3
+ test_cc 0 0 1 0
+ checkr3 80000032
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_cmpxm.s b/qemu-0.15.x/tests/cris/check_cmpxm.s
new file mode 100644
index 0000000..87ea5bf
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_cmpxm.s
@@ -0,0 +1,106 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .byte 0xff
+ .word 0xffff
+ .word 0xff
+ .word 0xffff
+ .byte 0x89
+ .word 0xf789
+ .word 0x8002
+ .word 0x764
+
+ start
+ moveq 2,r3
+ move.d x,r5
+ cmps.b [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ cmps.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ subq 3,r5
+ cmpu.b [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 2
+
+ moveq 2,r3
+ cmpu.w [r5+],r3
+ test_cc 1 0 0 1
+ subq 3,r5
+ checkr3 2
+
+ move.d 0xffff,r3
+ cmpu.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmpu.w [r5],r3
+ test_cc 0 1 0 0
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmps.b [r5],r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ move.d 0xffff,r3
+ cmps.w [r5],r3
+ test_cc 0 0 0 1
+ checkr3 ffff
+
+ moveq -1,r3
+ cmps.b [r5],r3
+ test_cc 0 1 0 0
+ addq 3,r5
+ checkr3 ffffffff
+
+ moveq -1,r3
+ cmps.w [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ cmps.w [r5+],r3
+ test_cc 0 1 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ cmpu.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmps.b [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmpu.w [r5],r3
+ test_cc 0 0 0 0
+ checkr3 78134452
+
+ move.d 0x78134452,r3
+ cmps.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 78134452
+
+ move.d 0x4452,r3
+ cmps.w [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 4452
+
+ move.d 0x80000032,r3
+ cmpu.w [r5+],r3
+ test_cc 0 0 1 0
+ checkr3 80000032
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_dstep.s b/qemu-0.15.x/tests/cris/check_dstep.s
new file mode 100644
index 0000000..bd43b83
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_dstep.s
@@ -0,0 +1,42 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: fffffffc\n4\nffff\nfffffffe\n9bf3911b\n0\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ dstep r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffffc
+
+ moveq 2,r3
+ moveq -1,r4
+ dstep r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 4
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ dstep r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r4
+ move.d r4,r3
+ dstep r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ dstep r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 9bf3911b
+
+ move.d 0xffff,r3
+ move.d 0x1fffe,r4
+ dstep r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_ftag.c b/qemu-0.15.x/tests/cris/check_ftag.c
new file mode 100644
index 0000000..908773a
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_ftag.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+static inline void cris_ftag_i(unsigned int x)
+{
+	register unsigned int v asm("$r10") = x;
+	asm ("ftagi\t[%0]\n" : : "r" (v) );
+}
+static inline void cris_ftag_d(unsigned int x)
+{
+	register unsigned int v asm("$r10") = x;
+	asm ("ftagd\t[%0]\n" : : "r" (v) );
+}
+static inline void cris_fidx_i(unsigned int x)
+{
+	register unsigned int v asm("$r10") = x;
+	asm ("fidxi\t[%0]\n" : : "r" (v) );
+}
+static inline void cris_fidx_d(unsigned int x)
+{
+	register unsigned int v asm("$r10") = x;
+	asm ("fidxd\t[%0]\n" : : "r" (v) );
+}
+
+
+int main(void)
+{
+	cris_ftag_i(0);
+	cris_ftag_d(0);
+	cris_fidx_i(0);
+	cris_fidx_d(0);
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_gcctorture_pr28634-1.c b/qemu-0.15.x/tests/cris/check_gcctorture_pr28634-1.c
new file mode 100644
index 0000000..45ecd15
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_gcctorture_pr28634-1.c
@@ -0,0 +1,15 @@
+/* PR rtl-optimization/28634.  On targets with delayed branches,
+   dbr_schedule could do the next iteration's addition in the
+   branch delay slot, then subtract the value again if the branch
+   wasn't taken.  This can lead to rounding errors.  */
+int x = -1;
+int y = 1;
+int
+main (void)
+{
+  while (y > 0)
+    y += x;
+  if (y != x + 1)
+    abort ();
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_gcctorture_pr28634.c b/qemu-0.15.x/tests/cris/check_gcctorture_pr28634.c
new file mode 100644
index 0000000..a0c5254
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_gcctorture_pr28634.c
@@ -0,0 +1,15 @@
+/* PR rtl-optimization/28634.  On targets with delayed branches,
+   dbr_schedule could do the next iteration's addition in the
+   branch delay slot, then subtract the value again if the branch
+   wasn't taken.  This can lead to rounding errors.  */
+double x = -0x1.0p53;
+double y = 1;
+int
+main (void)
+{
+  while (y > 0)
+    y += x;
+  if (y != x + 1)
+    abort ();
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_glibc_kernelversion.c b/qemu-0.15.x/tests/cris/check_glibc_kernelversion.c
new file mode 100644
index 0000000..fcbc7b0
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_glibc_kernelversion.c
@@ -0,0 +1,116 @@
+/*
+ * Check the lz insn.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+
+#define __LINUX_KERNEL_VERSION 131584
+
+#define DL_SYSDEP_OSCHECK(FATAL) \
+  do {                                                                        \
+    /* Test whether the kernel is new enough.  This test is only              \
+       performed if the library is not compiled to run on all                 \
+       kernels.  */                                                           \
+    if (__LINUX_KERNEL_VERSION > 0)                                           \
+      {                                                                       \
+        char bufmem[64];                                                      \
+        char *buf = bufmem;                                                   \
+        unsigned int version;                                                 \
+        int parts;                                                            \
+        char *cp;                                                             \
+        struct utsname uts;                                                   \
+                                                                              \
+        /* Try the uname syscall */                                           \
+        if (__uname (&uts))                                                   \
+          {                                                                   \
+            /* This was not successful.  Now try reading the /proc            \
+               filesystem.  */                                                \
+            ssize_t reslen;                                                   \
+            int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);         \
+            if (fd == -1                                                      \
+                || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0)      \
+              /* This also didn't work.  We give up since we cannot           \
+                 make sure the library can actually work.  */                 \
+              FATAL ("FATAL: cannot determine library version\n");            \
+            __close (fd);                                                     \
+            buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0';          \
+          }                                                                   \
+        else                                                                  \
+          buf = uts.release;                                                  \
+                                                                              \
+        /* Now convert it into a number.  The string consists of at most      \
+           three parts.  */                                                   \
+        version = 0;                                                          \
+        parts = 0;                                                            \
+        cp = buf;                                                             \
+        while ((*cp >= '0') && (*cp <= '9'))                                  \
+          {                                                                   \
+            unsigned int here = *cp++ - '0';                                  \
+                                                                              \
+            while ((*cp >= '0') && (*cp <= '9'))                              \
+              {                                                               \
+                here *= 10;                                                   \
+                here += *cp++ - '0';                                          \
+              }                                                               \
+                                                                              \
+            ++parts;                                                          \
+            version <<= 8;                                                    \
+            version |= here;                                                  \
+                                                                              \
+            if (*cp++ != '.')                                                 \
+              /* Another part following?  */                                  \
+              break;                                                          \
+          }                                                                   \
+                                                                              \
+        if (parts < 3)                                                        \
+          version <<= 8 * (3 - parts);                                        \
+                                                                              \
+        /* Now we can test with the required version.  */                     \
+        if (version < __LINUX_KERNEL_VERSION)                                 \
+          /* Not sufficent.  */                                               \
+          FATAL ("FATAL: kernel too old\n");                                  \
+                                                                              \
+        _dl_osversion = version;                                              \
+      }                                                                       \
+  } while (0)
+
+int main(void)
+{
+        char bufmem[64] = "2.6.22";
+        char *buf = bufmem;
+        unsigned int version;
+        int parts;
+        char *cp;
+
+        version = 0;
+        parts = 0;
+        cp = buf;
+        while ((*cp >= '0') && (*cp <= '9'))
+          {
+            unsigned int here = *cp++ - '0';
+
+            while ((*cp >= '0') && (*cp <= '9'))
+              {
+                here *= 10;
+                here += *cp++ - '0';
+              }
+
+            ++parts;
+            version <<= 8;
+            version |= here;
+
+            if (*cp++ != '.')
+              /* Another part following?  */
+              break;
+          }
+
+        if (parts < 3)
+          version <<= 8 * (3 - parts);
+	if (version < __LINUX_KERNEL_VERSION)
+		err();
+	pass();
+	exit(0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_hello.c b/qemu-0.15.x/tests/cris/check_hello.c
new file mode 100644
index 0000000..fb403ba
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdlib.h>
+int main ()
+{
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_int64.c b/qemu-0.15.x/tests/cris/check_int64.c
new file mode 100644
index 0000000..fc60017
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_int64.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+
+static inline int64_t add64(const int64_t a, const int64_t b)
+{
+	return a + b;
+}
+
+static inline int64_t sub64(const int64_t a, const int64_t b)
+{
+	return a - b;
+}
+
+int main(void)
+{
+	int64_t a = 1;
+	int64_t b = 2;
+
+	/* FIXME: add some tests.  */
+	a = add64(a, b);
+	if (a != 3)
+		err();
+
+	a = sub64(a, b);
+	if (a != 1)
+		err();
+
+	a = add64(a, -4);
+	if (a != -3)
+		err();
+
+	a = add64(a, 3);
+	if (a != 0)
+		err();
+
+	a = 0;
+	a = sub64(a, 1);
+	if (a != -1)
+		err();
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_jsr.s b/qemu-0.15.x/tests/cris/check_jsr.s
new file mode 100644
index 0000000..1060237
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_jsr.s
@@ -0,0 +1,85 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 0\n0\n0\n0\n0\n0\n
+
+# Test that jsr Rn and jsr [PC+] work.
+
+ .include "testutils.inc"
+ start
+x:
+ move.d 0f,r6
+ setf nzvc
+ jsr r6
+ .if 1; ..asm.arch.cris.v32
+ nop
+ .endif
+0:
+ test_move_cc 1 1 1 1
+ move srp,r3
+ sub.d 0b,r3
+ checkr3 0
+
+ move.d 1f,r0
+ setf nzvc
+ jsr r0
+ .if 1 ; ..asm.arch.cris.v32
+ moveq 0,r0
+ .endif
+6:
+ nop
+ quit
+
+2:
+ test_move_cc 0 0 0 0
+ move srp,r3
+ sub.d 3f,r3
+ checkr3 0
+ jsr 4f
+ .if 1 ; ..asm.arch.cris.v32
+ nop
+ .endif
+7:
+ nop
+ quit
+
+8:
+ move srp,r3
+ sub.d 7b,r3
+ checkr3 0
+ quit
+
+4:
+ move srp,r3
+ sub.d 7b,r3
+ checkr3 0
+ move.d 5f,r3
+ jump r3
+ .if 1; ..asm.arch.cris.v32
+ moveq 0,r3
+ .endif
+ quit
+
+ .space 32770,0
+1:
+ test_move_cc 1 1 1 1
+ move srp,r3
+ sub.d 6b,r3
+ checkr3 0
+
+ clearf cznv
+ jsr 2b
+ .if 1; ..asm.arch.cris.v32
+ nop
+ .endif
+3:
+
+ quit
+
+5:
+ move srp,r3
+ sub.d 7b,r3
+ checkr3 0
+ jump 8b
+ .if 1 ; ..asm.arch.cris.v32
+ nop
+ .endif
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_lapc.s b/qemu-0.15.x/tests/cris/check_lapc.s
new file mode 100644
index 0000000..9a6150b
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_lapc.s
@@ -0,0 +1,78 @@
+# mach: crisv32
+# output: 0\n0\nfffffffa\nfffffffe\nffffffda\n1e\n1e\n0\n
+
+.include "testutils.inc"
+
+; To accommodate dumpr3 with more than one instruction, keep it
+; out of lapc operand ranges and difference calculations.
+
+ start
+ lapc.d 0f,r3
+0:
+ sub.d .,r3
+ checkr3 0
+
+ lapcq 0f,r3
+0:
+ sub.d .,r3
+ checkr3 0
+
+ lapc.d .,r3
+ sub.d .,r3
+ checkr3 fffffffa
+
+ lapcq .,r3
+ sub.d .,r3
+ checkr3 fffffffe
+
+0:
+ .rept 16
+ nop
+ .endr
+ lapc.d 0b,r3
+ sub.d .,r3
+ checkr3 ffffffda
+
+ setf zcvn
+ lapc.d 0f,r3
+ test_cc 1 1 1 1
+ sub.d .,r3
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+0:
+ checkr3 1e
+0:
+ lapcq 0f,r3
+ sub.d 0b,r3
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+0:
+ checkr3 1e
+ clearf cn
+ setf zv
+1:
+ lapcq .,r3
+ test_cc 0 1 1 0
+ sub.d 1b,r3
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_lsl.s b/qemu-0.15.x/tests/cris/check_lsl.s
new file mode 100644
index 0000000..9e2ddd7
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_lsl.s
@@ -0,0 +1,217 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n4\n80000000\nffff8000\n7f19f000\n80000000\n0\n0\n699fc67c\nffffffff\n4\n80000000\nffff8000\n7f19f000\nda670000\nda670000\nda670000\nda67c67c\nffffffff\nfffafffe\n4\nffff0000\nffff8000\n5a67f000\nda67f100\nda67f100\nda67f100\nda67f17c\nfff3faff\nfff3fafe\n4\nffffff00\nffffff00\nffffff80\n5a67f100\n5a67f1f0\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ lslq 0,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ lslq 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 4
+
+ moveq -1,r3
+ lslq 31,r3
+ test_move_cc 1 0 0 0
+ checkr3 80000000
+
+ moveq -1,r3
+ lslq 15,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff8000
+
+ move.d 0x5a67f19f,r3
+ lslq 12,r3
+ test_move_cc 0 0 0 0
+ checkr3 7f19f000
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsl.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 80000000
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsl.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsl.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsl.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 699fc67c
+
+ moveq -1,r3
+ moveq 0,r4
+ lsl.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ lsl.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 4
+
+ moveq -1,r3
+ moveq 31,r4
+ lsl.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 80000000
+
+ moveq -1,r3
+ moveq 15,r4
+ lsl.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff8000
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsl.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 7f19f000
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsl.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsl.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsl.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsl.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 da67c67c
+
+ moveq -1,r3
+ moveq 0,r4
+ lsl.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0xfffaffff,r3
+ moveq 1,r4
+ lsl.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffafffe
+
+ moveq 2,r3
+ moveq 1,r4
+ lsl.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 4
+
+ moveq -1,r3
+ moveq 31,r4
+ lsl.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffff0000
+
+ moveq -1,r3
+ moveq 15,r4
+ lsl.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff8000
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsl.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 5a67f000
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsl.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 da67f17c
+
+ move.d 0xfff3faff,r3
+ moveq 0,r4
+ lsl.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fff3faff
+
+ move.d 0xfff3faff,r3
+ moveq 1,r4
+ lsl.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fff3fafe
+
+ moveq 2,r3
+ moveq 1,r4
+ lsl.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 4
+
+ moveq -1,r3
+ moveq 31,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffffff00
+
+ moveq -1,r3
+ moveq 15,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffffff00
+
+ moveq -1,r3
+ moveq 7,r4
+ lsl.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffff80
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsl.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 5a67f100
+
+ move.d 0x5a67f19f,r3
+ moveq 4,r4
+ lsl.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 5a67f1f0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_lsr.s b/qemu-0.15.x/tests/cris/check_lsr.s
new file mode 100644
index 0000000..18fdbef
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_lsr.s
@@ -0,0 +1,218 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\n1\n1\n1ffff\n5a67f\n1\n0\n0\n3699fc67\nffffffff\n1\n1\n1ffff\n5a67f\nda670000\nda670000\nda670000\nda673c67\nffffffff\nffff7fff\n1\nffff0000\nffff0001\n5a67000f\nda67f100\nda67f100\nda67f100\nda67f127\nffffffff\nffffff7f\n1\nffffff00\nffffff00\nffffff01\n5a67f100\n5a67f109\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ lsrq 0,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ lsrq 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ lsrq 31,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ lsrq 15,r3
+ test_move_cc 0 0 0 0
+ checkr3 1ffff
+
+ move.d 0x5a67f19f,r3
+ lsrq 12,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67f
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsr.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsr.d r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3699fc67
+
+ moveq -1,r3
+ moveq 0,r4
+ lsr.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq 1,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 31,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 15,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1ffff
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsr.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67f
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsr.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsr.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsr.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da670000
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 da673c67
+
+ moveq -1,r3
+ moveq 0,r4
+ lsr.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 1,r4
+ lsr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff7fff
+
+ moveq 2,r3
+ moveq 1,r4
+ lsr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+;; FIXME: this was wrong. Z should be set.
+ moveq -1,r3
+ moveq 31,r4
+ lsr.w r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffff0000
+
+ moveq -1,r3
+ moveq 15,r4
+ lsr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0001
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsr.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67000f
+
+ move.d 0xda67f19f,r3
+ move.d 31,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 32,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 33,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 da67f100
+
+ move.d 0xda67f19f,r3
+ move.d 66,r4
+ lsr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 da67f127
+
+ moveq -1,r3
+ moveq 0,r4
+ lsr.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 1,r4
+ lsr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff7f
+
+ moveq 2,r3
+ moveq 1,r4
+ lsr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ moveq -1,r3
+ moveq 31,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffffff00
+
+ moveq -1,r3
+ moveq 15,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffffff00
+
+ moveq -1,r3
+ moveq 7,r4
+ lsr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff01
+
+ move.d 0x5a67f19f,r3
+ moveq 12,r4
+ lsr.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 5a67f100
+
+ move.d 0x5a67f19f,r3
+ moveq 4,r4
+ lsr.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5a67f109
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_lz.c b/qemu-0.15.x/tests/cris/check_lz.c
new file mode 100644
index 0000000..69c2e6d
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_lz.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+
+static inline int cris_lz(int x)
+{
+	int r;
+	asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x));
+	return r;
+}
+
+void check_lz(void)
+{
+	int i;
+
+	if (cris_lz(0) != 32)
+		err();
+	if (cris_lz(1) != 31)
+		err();
+	if (cris_lz(2) != 30)
+		err();
+	if (cris_lz(4) != 29)
+		err();
+	if (cris_lz(8) != 28)
+		err();
+
+	/* try all positions with a single bit.  */
+	for (i = 1; i < 32; i++) {
+		if (cris_lz(1 << (i-1)) != (32 - i))
+			err();
+	}
+
+	/* try all positions with all bits.  */
+	for (i = 1; i < 32; i++) {
+		/* split up this computation to clarify it.  */
+		uint32_t val;
+		val = (unsigned int)-1 >> (32 - i);
+		if (cris_lz(val) != (32 - i))
+			err();
+	}
+}
+
+int main(void)
+{
+	check_lz();
+	pass();
+	exit(0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_mapbrk.c b/qemu-0.15.x/tests/cris/check_mapbrk.c
new file mode 100644
index 0000000..1aff762
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mapbrk.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Basic sanity check that syscalls to implement malloc (brk, mmap2,
+   munmap) are trivially functional.  */
+
+int main ()
+{
+  void *p1, *p2, *p3, *p4, *p5, *p6;
+
+  if ((p1 = malloc (8100)) == NULL
+      || (p2 = malloc (16300)) == NULL
+      || (p3 = malloc (4000)) == NULL
+      || (p4 = malloc (500)) == NULL
+      || (p5 = malloc (1023*1024)) == NULL
+      || (p6 = malloc (8191*1024)) == NULL)
+  {
+    printf ("fail\n");
+    exit (1);
+  }
+
+  free (p1);
+  free (p2);
+  free (p3);
+  free (p4);
+  free (p5);
+  free (p6);
+
+  p1 = malloc (64000);
+  if (p1 == NULL)
+  {
+    printf ("fail\n");
+    exit (1);
+  }
+  free (p1);
+
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_mcp.s b/qemu-0.15.x/tests/cris/check_mcp.s
new file mode 100644
index 0000000..e65ccdd
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mcp.s
@@ -0,0 +1,49 @@
+# mach: crisv32
+# output: fffffffe\n1\n1ffff\nfffffffe\ncc463bdc\n4c463bdc\n0\n
+
+ .include "testutils.inc"
+ start
+
+; Set R, clear C.
+ move 0x100,ccs
+ moveq -5,r3
+ move 2,mof
+ mcp mof,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ moveq 2,r3
+ move -1,srp
+ mcp srp,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move 0xffff,srp
+ move srp,r3
+ mcp srp,r3
+ test_cc 0 0 0 0
+ checkr3 1ffff
+
+ move -1,mof
+ move mof,r3
+ mcp mof,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move 0x5432f789,mof
+ move.d 0x78134452,r3
+ mcp mof,r3
+ test_cc 1 0 1 0
+ checkr3 cc463bdc
+
+ move 0x80000000,srp
+ mcp srp,r3
+ test_cc 0 0 1 0
+ checkr3 4c463bdc
+
+ move 0xb3b9c423,srp
+ mcp srp,r3
+ test_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_mmap1.c b/qemu-0.15.x/tests/cris/check_mmap1.c
new file mode 100644
index 0000000..b803f0c
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mmap1.c
@@ -0,0 +1,48 @@
+/*
+#notarget: cris*-*-elf
+*/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+int main (int argc, char *argv[])
+{
+  int fd = open (argv[0], O_RDONLY);
+  struct stat sb;
+  int size;
+  void *a;
+  const char *str = "a string you'll only find in the program";
+
+  if (fd == -1)
+    {
+      perror ("open");
+      abort ();
+    }
+
+  if (fstat (fd, &sb) < 0)
+    {
+      perror ("fstat");
+      abort ();
+    }
+
+  size = sb.st_size;
+
+  /* We want to test mmapping a size that isn't exactly a page.  */
+  if ((size & 8191) == 0)
+    size--;
+
+  a = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+  if (memmem (a, size, str, strlen (str) + 1) == NULL)
+    abort ();
+
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_mmap2.c b/qemu-0.15.x/tests/cris/check_mmap2.c
new file mode 100644
index 0000000..35139a0
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mmap2.c
@@ -0,0 +1,48 @@
+/*
+#notarget: cris*-*-elf
+*/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+int main (int argc, char *argv[])
+{
+  int fd = open (argv[0], O_RDONLY);
+  struct stat sb;
+  int size;
+  void *a;
+  const char *str = "a string you'll only find in the program";
+
+  if (fd == -1)
+    {
+      perror ("open");
+      abort ();
+    }
+
+  if (fstat (fd, &sb) < 0)
+    {
+      perror ("fstat");
+      abort ();
+    }
+
+  size = sb.st_size;
+
+  /* We want to test mmapping a size that isn't exactly a page.  */
+  if ((size & 8191) == 0)
+    size--;
+
+  a = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+
+  if (memmem (a, size, str, strlen (str) + 1) == NULL)
+    abort ();
+
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_mmap3.c b/qemu-0.15.x/tests/cris/check_mmap3.c
new file mode 100644
index 0000000..34401fa
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mmap3.c
@@ -0,0 +1,33 @@
+/*
+#notarget: cris*-*-elf
+*/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+int main (int argc, char *argv[])
+{
+  volatile unsigned char *a;
+
+  /* Check that we can map a non-multiple of a page and still get a full page.  */
+  a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC,
+	    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (a == NULL || a == (unsigned char *) -1)
+    abort ();
+
+  a[0] = 0xbe;
+  a[8191] = 0xef;
+  memset ((char *) a + 1, 0, 8190);
+
+  if (a[0] != 0xbe || a[8191] != 0xef)
+    abort ();
+
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_movdelsr1.s b/qemu-0.15.x/tests/cris/check_movdelsr1.s
new file mode 100644
index 0000000..300cc87
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movdelsr1.s
@@ -0,0 +1,33 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: aa117acd\n
+# output: eeaabb42\n
+
+; Bug with move to special register in delay slot, due to
+; special flush-insn-cache simulator use.  Ordinary move worked;
+; special register caused branch to fail.
+
+ .include "testutils.inc"
+ start
+ move -1,srp
+
+ move.d 0xaa117acd,r1
+ moveq 3,r9
+ cmpq 1,r9
+ bhi 0f
+ move.d r1,r3
+
+ fail
+0:
+ checkr3 aa117acd
+
+ move.d 0xeeaabb42,r1
+ moveq 3,r9
+ cmpq 1,r9
+ bhi 0f
+ move r1,srp
+
+ fail
+0:
+ move srp,r3
+ checkr3 eeaabb42
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movecr.s b/qemu-0.15.x/tests/cris/check_movecr.s
new file mode 100644
index 0000000..da8ec26
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movecr.s
@@ -0,0 +1,37 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffff42\n94\nffff4321\n9234\n76543210\n76540000\n
+
+; Move constant byte, word, dword to register.  Check that no extension is
+; performed, that only part of the register is set.
+
+ .include "testutils.inc"
+ startnostack
+ moveq -1,r3
+ move.b 0x42,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff42
+
+ moveq 0,r3
+ move.b 0x94,r3
+ test_move_cc 1 0 0 0
+ checkr3 94
+
+ moveq -1,r3
+ move.w 0x4321,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff4321
+
+ moveq 0,r3
+ move.w 0x9234,r3
+ test_move_cc 1 0 0 0
+ checkr3 9234
+
+ move.d 0x76543210,r3
+ test_move_cc 0 0 0 0
+ checkr3 76543210
+
+ move.w 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 76540000
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movei.s b/qemu-0.15.x/tests/cris/check_movei.s
new file mode 100644
index 0000000..bbfa633
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movei.s
@@ -0,0 +1,50 @@
+# mach: crisv32
+# output: fffffffe\n
+# output: fffffffe\n
+
+; Check basic integral-write semantics regarding flags.
+
+ .include "testutils.inc"
+ start
+
+ move.d 0, $r3	
+; A write that works.  Check that flags are set correspondingly.
+ move.d d,r4
+ ;; store to bring it into the tlb with the right prot bits
+ move.d r3,[r4]
+ moveq -2,r5
+ setf c
+ clearf p
+ move.d [r4],r3
+ ax
+ move.d r5,[r4]
+ move.d [r4],r3
+
+ bcc 0f
+ nop
+ fail
+
+0:
+ checkr3 fffffffe
+
+; A write that fails; check flags too.
+ move.d d,r4
+ moveq 23,r5
+ setf p
+ clearf c
+ move.d [r4],r3
+ ax
+ move.d r5,[r4]
+ move.d [r4],r3
+
+ bcs 0f
+ nop
+ fail
+
+0:
+ checkr3 fffffffe
+ quit
+
+ .data
+d:
+ .dword 42424242
diff --git a/qemu-0.15.x/tests/cris/check_movemr.s b/qemu-0.15.x/tests/cris/check_movemr.s
new file mode 100644
index 0000000..88489de
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movemr.s
@@ -0,0 +1,78 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 12345678\n10234567\n12345678\n12344567\n12344523\n76543210\nffffffaa\naa\n9911\nffff9911\n78\n56\n3456\n6712\n
+
+ .include "testutils.inc"
+ start
+
+ .data
+mem1:
+ .dword 0x12345678
+mem2:
+ .word 0x4567
+mem3:
+ .byte 0x23
+ .dword 0x76543210
+ .byte 0xaa,0x11,0x99
+
+ .text
+ move.d mem1,r2
+ move.d [r2],r3
+ test_move_cc 0 0 0 0
+ checkr3 12345678
+
+ move.d mem2,r3
+ move.d [r3],r3
+ test_move_cc 0 0 0 0
+ checkr3 10234567
+
+ move.d mem1,r2
+ move.d [r2+],r3
+ test_move_cc 0 0 0 0
+ checkr3 12345678
+
+ move.w [r2+],r3
+ test_move_cc 0 0 0 0
+ checkr3 12344567
+
+ move.b [r2+],r3
+ test_move_cc 0 0 0 0
+ checkr3 12344523
+
+ move.d [r2+],r3
+ test_move_cc 0 0 0 0
+ checkr3 76543210
+
+ movs.b [r2],r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffaa
+
+ movu.b [r2+],r3
+ test_move_cc 0 0 0 0
+ checkr3 aa
+
+ movu.w [r2],r3
+ test_move_cc 0 0 0 0
+ checkr3 9911
+
+ movs.w [r2+],r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff9911
+
+ move.d mem1,r13
+ movs.b [r13+],r3
+ test_move_cc 0 0 0 0
+ checkr3 78
+
+ movu.b [r13],r3
+ test_move_cc 0 0 0 0
+ checkr3 56
+
+ movs.w [r13+],r3
+ test_move_cc 0 0 0 0
+ checkr3 3456
+
+ movu.w [r13+],r3
+ test_move_cc 0 0 0 0
+ checkr3 6712
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movemrv32.s b/qemu-0.15.x/tests/cris/check_movemrv32.s
new file mode 100644
index 0000000..53950ab
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movemrv32.s
@@ -0,0 +1,96 @@
+# mach: crisv32
+# output: 15\n7\n2\nffff1234\nb\n16\nf\n2\nffffffef\nf\nffff1234\nf\nfffffff4\nd\nfffffff2\n10\nfffffff2\nd\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword 8,9,10,11
+y:
+ .dword -12,13,-14,15,16
+
+ start
+ moveq 7,r0
+ moveq 2,r1
+ move.d 0xffff1234,r2
+ moveq 21,r3
+ move.d x,r4
+ setf zcvn
+ movem r2,[r4+]
+ test_cc 1 1 1 1
+ subq 12,r4
+
+ checkr3 15
+
+ move.d [r4+],r3
+ checkr3 7
+
+ move.d [r4+],r3
+ checkr3 2
+
+ move.d [r4+],r3
+ checkr3 ffff1234
+
+ move.d [r4+],r3
+ checkr3 b
+
+ subq 16,r4
+ moveq 22,r0
+ moveq 15,r1
+ clearf zcvn
+ movem r0,[r4]
+ test_cc 0 0 0 0
+ move.d [r4+],r3
+ checkr3 16
+
+ move.d r1,r3
+ checkr3 f
+
+ move.d [r4+],r3
+ checkr3 2
+
+ subq 8,r4
+ moveq 10,r2
+ moveq -17,r0
+ clearf zc
+ setf vn
+ movem r1,[r4]
+ test_cc 1 0 1 0
+ move.d [r4+],r3
+ checkr3 ffffffef
+
+ move.d [r4+],r3
+ checkr3 f
+
+ move.d [r4+],r3
+ checkr3 ffff1234
+
+ move.d y,r4
+ setf zc
+ clearf vn
+ movem [r4+],r3
+ test_cc 0 1 0 1
+ checkr3 f
+
+ move.d r0,r3
+ checkr3 fffffff4
+
+ move.d r1,r3
+ checkr3 d
+
+ move.d r2,r3
+ checkr3 fffffff2
+
+ move.d [r4],r3
+ checkr3 10
+
+ subq 8,r4
+ setf zcvn
+ movem [r4+],r0
+ test_cc 1 1 1 1
+ move.d r0,r3
+ checkr3 fffffff2
+
+ move.d r1,r3
+ checkr3 d
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_moveq.c b/qemu-0.15.x/tests/cris/check_moveq.c
new file mode 100644
index 0000000..9f71194
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_moveq.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+#define cris_moveq(dst, src) \
+               asm volatile ("moveq %1, %0\n" : "=r" (dst) : "i" (src));
+
+
+
+int main(void)
+{
+	int t;
+
+	cris_tst_cc_init();
+	asm volatile ("setf\tzvnc\n");
+	cris_moveq(t, 10);
+	cris_tst_cc(1, 1, 1, 1);
+	if (t != 10)
+		err();
+
+	/* make sure moveq doesnt clobber the zflag.  */
+	cris_tst_cc_init();
+	asm volatile ("setf vnc\n");
+	asm volatile ("clearf z\n");
+	cris_moveq(t, 0);
+	cris_tst_cc(1, 0, 1, 1);
+	if (t != 0)
+		err();
+
+	/* make sure moveq doesnt clobber the nflag.
+	   Also check large immediates  */
+	cris_tst_cc_init();
+	asm volatile ("setf zvc\n");
+	asm volatile ("clearf n\n");
+	cris_moveq(t, -31);
+	cris_tst_cc(0, 1, 1, 1);
+	if (t != -31)
+		err();
+
+	cris_tst_cc_init();
+	asm volatile ("setf nzvc\n");
+	cris_moveq(t, 31);
+	cris_tst_cc(1, 1, 1, 1);
+	if (t != 31)
+		err();
+
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_mover.s b/qemu-0.15.x/tests/cris/check_mover.s
new file mode 100644
index 0000000..b4db595
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mover.s
@@ -0,0 +1,28 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffff05\nffff0005\n5\nffffff00\n
+
+; Move between registers.  Check that just the subreg is copied.
+
+ .include "testutils.inc"
+ startnostack
+ moveq -30,r3
+ moveq 5,r4
+ move.b r4,r3
+ test_move_cc 0 0 0 0  		; FIXME
+ checkr3 ffffff05
+
+ move.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0005
+
+ move.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq -1,r3
+ moveq 0,r4
+ move.b r4,r3
+ test_move_cc 0 1 0 0
+ checkr3 ffffff00
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_moverm.s b/qemu-0.15.x/tests/cris/check_moverm.s
new file mode 100644
index 0000000..eabc958
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_moverm.s
@@ -0,0 +1,45 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 7823fec2\n10231879\n102318fe\n
+
+ .include "testutils.inc"
+ start
+
+ .data
+mem1:
+ .dword 0x12345678
+mem2:
+ .word 0x4567
+mem3:
+ .byte 0x23
+ .dword 0x76543210
+ .byte 0xaa,0x11,0x99
+
+ .text
+ move.d mem1,r2
+ move.d 0x7823fec2,r4
+ setf nzvc
+ move.d r4,[r2+]
+ test_cc 1 1 1 1
+ subq 4,r2
+ move.d [r2],r3
+ checkr3 7823fec2
+
+ move.d mem2,r3
+ move.d 0x45231879,r4
+ clearf nzvc
+ move.w r4,[r3]
+ test_cc 0 0 0 0
+ move.d [r3],r3
+ checkr3 10231879
+
+ move.d mem2,r2
+ moveq -2,r4
+ clearf nc
+ setf zv
+ move.b r4,[r2+]
+ test_cc 0 1 1 0
+ subq 1,r2
+ move.d [r2],r3
+ checkr3 102318fe
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movmp.s b/qemu-0.15.x/tests/cris/check_movmp.s
new file mode 100644
index 0000000..7fc11f0
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movmp.s
@@ -0,0 +1,131 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
+
+# Test generic "move Ps,[]" and "move [],Pd" insns; the ones with
+# functionality common to all models.
+
+ .include "testutils.inc"
+ start
+
+ .data
+filler:
+ .byte 0xaa
+ .word 0x4433
+ .dword 0x55778866
+ .byte 0xcc
+
+ .text
+; Test that writing to zero-registers is a nop
+ .if 0
+ ; We used to just ignore the writes, but now an error is emitted.  We
+ ; keep the test-code but disabled, in case we need to change this again.
+ move 0xaa,p0
+ move 0x4433,p4
+ move 0x55774433,p8
+ .endif
+
+ moveq -1,r3
+ setf zcvn
+ clear.b r3
+ test_cc 1 1 1 1
+ checkr3 ffffff00
+
+ moveq -1,r3
+ clearf zcvn
+ clear.w r3
+ test_cc 0 0 0 0
+ checkr3 ffff0000
+
+ moveq -1,r3
+ clear.d r3
+ checkr3 0
+
+; "Write" using ordinary memory references too.
+ .if 0 ; See ".if 0" above.
+ move.d filler,r6
+ move [r6],p0
+ move [r6],p4
+ move [r6],p8
+ .endif
+
+# ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
+
+ moveq -1,r3
+ clear.b r3
+ checkr3 ffffff00
+
+ moveq -1,r3
+ clear.w r3
+ checkr3 ffff0000
+
+ moveq -1,r3
+ clear.d r3
+ checkr3 0
+
+; And postincremented.
+ .if 0 ; See ".if 0" above.
+ move [r6+],p0
+ move [r6+],p4
+ move [r6+],p8
+ .endif
+
+# ffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
+
+ moveq -1,r3
+ clear.b r3
+ checkr3 ffffff00
+
+ moveq -1,r3
+ clear.w r3
+ checkr3 ffff0000
+
+ moveq -1,r3
+ clear.d r3
+ checkr3 0
+
+; Now see that we can write to the registers too.
+# bb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
+; [PC+]
+ move.d filler,r9
+ move 0xbb113344,srp
+ move srp,r3
+ checkr3 bb113344
+
+; [R+]
+ move [r9+],srp
+ move srp,r3
+ checkr3 664433aa
+
+; [R]
+ move [r9],srp
+ move srp,r3
+ checkr3 cc557788
+
+; And check writing to memory, clear and srp.
+
+ move.d filler,r9
+ move 0xabcde012,srp
+ setf zcvn
+ move srp,[r9+]
+ test_cc 1 1 1 1
+ subq 4,r9
+ move.d [r9],r3
+ checkr3 abcde012
+
+ clearf zcvn
+ clear.b [r9]
+ test_cc 0 0 0 0
+ move.d [r9],r3
+ checkr3 abcde000
+
+ addq 2,r9
+ clear.w [r9+]
+ subq 2,r9
+ move.d [r9],r3
+ checkr3 77880000
+
+ clear.d [r9]
+ move.d [r9],r3
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movpmv32.s b/qemu-0.15.x/tests/cris/check_movpmv32.s
new file mode 100644
index 0000000..daf0970
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movpmv32.s
@@ -0,0 +1,35 @@
+# mach: crisv32
+# output: 11223320\nbb113344\naa557711\n
+
+# Test v32-specific special registers.  FIXME: more registers.
+
+ .include "testutils.inc"
+ start
+ .data
+store:
+ .dword 0x11223344
+ .dword 0x77665544
+
+ .text
+ moveq -1,r3
+ move.d store,r4
+ move vr,[r4]
+ move [r4+],mof
+ move mof,r3
+ checkr3 11223320
+
+ moveq -1,r3
+ clearf zcvn
+ move 0xbb113344,mof
+ test_cc 0 0 0 0
+ move mof,r3
+ checkr3 bb113344
+
+ setf zcvn
+ move 0xaa557711,mof
+ test_cc 1 1 1 1
+ move mof,[r4]
+ move.d [r4],r3
+ checkr3 aa557711
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movpr.s b/qemu-0.15.x/tests/cris/check_movpr.s
new file mode 100644
index 0000000..eef9bdb
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movpr.s
@@ -0,0 +1,28 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: ffffff00\nffff0000\n0\nbb113344\n
+
+# Test generic "move Ps,Rd" and "move Rs,Pd" insns; the ones with
+# functionality common to all models.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ clear.b r3
+ checkr3 ffffff00
+
+ moveq -1,r3
+ clear.w r3
+ checkr3 ffff0000
+
+ moveq -1,r3
+ clear.d r3
+ checkr3 0
+
+ moveq -1,r3
+ move.d 0xbb113344,r4
+ setf zcvn
+ move r4,srp
+ move srp,r3
+ test_cc 1 1 1 1
+ checkr3 bb113344
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movprv32.s b/qemu-0.15.x/tests/cris/check_movprv32.s
new file mode 100644
index 0000000..d0d90e1
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movprv32.s
@@ -0,0 +1,21 @@
+# mach: crisv32
+# output: ffffff20\nbb113344\n
+
+# Test v32-specific special registers.  FIXME: more registers.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ setf zcvn
+ move vr,r3
+ test_cc 1 1 1 1
+ checkr3 ffffff20
+
+ moveq -1,r3
+ move.d 0xbb113344,r4
+ clearf cvnz
+ move r4,mof
+ test_cc 0 0 0 0
+ move mof,r3
+ checkr3 bb113344
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movscr.s b/qemu-0.15.x/tests/cris/check_movscr.s
new file mode 100644
index 0000000..53c8ce6
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movscr.s
@@ -0,0 +1,29 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 42\nffffff85\n7685\nffff8765\n0\n
+
+; Move constant byte, word, dword to register.  Check that sign-extension
+; is performed.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ movs.b 0x42,r3
+ checkr3 42
+
+ movs.b 0x85,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffff85
+
+ movs.w 0x7685,r3
+ test_move_cc 0 0 0 0
+ checkr3 7685
+
+ movs.w 0x8765,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff8765
+
+ movs.w 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movsm.s b/qemu-0.15.x/tests/cris/check_movsm.s
new file mode 100644
index 0000000..7074336
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movsm.s
@@ -0,0 +1,44 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 5\nfffffff5\n5\nfffffff5\n0\n
+
+; Movs between registers.  Check that sign-extension is performed and the
+; full register is set.
+
+ .include "testutils.inc"
+
+ .data
+x:
+ .byte 5,-11
+ .word 5,-11
+ .word 0
+
+ start
+ move.d x,r5
+
+ moveq -1,r3
+ movs.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r3
+ movs.b [r5],r3
+ test_move_cc 1 0 0 0
+ addq 1,r5
+ checkr3 fffffff5
+
+ moveq -1,r3
+ movs.w [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r3
+ movs.w [r5],r3
+ test_move_cc 1 0 0 0
+ addq 2,r5
+ checkr3 fffffff5
+
+ movs.w [r5],r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movsr.s b/qemu-0.15.x/tests/cris/check_movsr.s
new file mode 100644
index 0000000..d1889a7
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movsr.s
@@ -0,0 +1,46 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 5\nfffffff5\n5\nfffffff5\n0\n
+
+; Movs between registers.  Check that sign-extension is performed and the
+; full register is set.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r5
+ moveq 5,r4
+ move.b r4,r5
+ moveq -1,r3
+ movs.b r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r5
+ moveq -11,r4
+ move.b r4,r5
+ moveq 0,r3
+ movs.b r5,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffff5
+
+ moveq -1,r5
+ moveq 5,r4
+ move.w r4,r5
+ moveq -1,r3
+ movs.w r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r5
+ moveq -11,r4
+ move.w r4,r5
+ moveq 0,r3
+ movs.w r5,r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffff5
+
+ moveq 0,r5
+ movs.b r5,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movucr.s b/qemu-0.15.x/tests/cris/check_movucr.s
new file mode 100644
index 0000000..7c8487d
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movucr.s
@@ -0,0 +1,33 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 42\n85\n7685\n8765\n0\n
+
+; Move constant byte, word, dword to register.  Check that zero-extension
+; is performed.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ movu.b 0x42,r3
+ test_move_cc 0 0 0 0
+ checkr3 42
+
+ moveq -1,r3
+ movu.b 0x85,r3
+ test_move_cc 0 0 0 0
+ checkr3 85
+
+ moveq -1,r3
+ movu.w 0x7685,r3
+ test_move_cc 0 0 0 0
+ checkr3 7685
+
+ moveq -1,r3
+ movu.w 0x8765,r3
+ test_move_cc 0 0 0 0
+ checkr3 8765
+
+ movu.b 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movum.s b/qemu-0.15.x/tests/cris/check_movum.s
new file mode 100644
index 0000000..038e539
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movum.s
@@ -0,0 +1,40 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 5\nf5\n5\nfff5\n0\n
+
+; Movu between registers.  Check that zero-extension is performed and the
+; full register is set.
+
+ .include "testutils.inc"
+
+ .data
+x:
+ .byte 5,-11
+ .word 5,-11
+ .word 0
+
+ start
+ move.d x,r5
+
+ movu.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ movu.b [r5],r3
+ test_move_cc 0 0 0 0
+ addq 1,r5
+ checkr3 f5
+
+ movu.w [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ movu.w [r5],r3
+ test_move_cc 0 0 0 0
+ addq 2,r5
+ checkr3 fff5
+
+ movu.w [r5],r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_movur.s b/qemu-0.15.x/tests/cris/check_movur.s
new file mode 100644
index 0000000..3ecf475
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_movur.s
@@ -0,0 +1,45 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 5\nf5\n5\nfff5\n0\n
+
+; Movu between registers.  Check that zero-extension is performed and the
+; full register is set.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r5
+ moveq 5,r4
+ move.b r4,r5
+ moveq -1,r3
+ movu.b r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r5
+ moveq -11,r4
+ move.b r4,r5
+ moveq -1,r3
+ movu.b r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 f5
+
+ moveq -1,r5
+ moveq 5,r4
+ move.w r4,r5
+ moveq -1,r3
+ movu.w r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 5
+
+ moveq 0,r5
+ moveq -11,r4
+ move.w r4,r5
+ moveq -1,r3
+ movu.w r5,r3
+ test_move_cc 0 0 0 0
+ checkr3 fff5
+
+ movu.w 0,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_mulv32.s b/qemu-0.15.x/tests/cris/check_mulv32.s
new file mode 100644
index 0000000..f379358
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mulv32.s
@@ -0,0 +1,51 @@
+# mach: crisv32
+# output: fffffffe\n
+# output: ffffffff\n
+# output: fffffffe\n
+# output: 1\n
+# output: fffffffe\n
+# output: ffffffff\n
+# output: fffffffe\n
+# output: 1\n
+
+; Check that carry is not modified on v32.
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ setf c
+ muls.d r4,r3
+ test_cc 1 0 0 1
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 2,r4
+ setf c
+ mulu.d r4,r3
+ test_cc 0 0 1 1
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 1
+
+ moveq -1,r3
+ moveq 2,r4
+ clearf c
+ muls.d r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 2,r4
+ clearf c
+ mulu.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 1
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_mulx.s b/qemu-0.15.x/tests/cris/check_mulx.s
new file mode 100644
index 0000000..d43241a
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_mulx.s
@@ -0,0 +1,246 @@
+# mach: crisv10 crisv32
+# output: fffffffe\nffffffff\nfffffffe\n1\nfffffffe\nffffffff\nfffffffe\n1\nfffe0001\n0\nfffe0001\n0\n1\n0\n1\nfffffffe\n193eade2\n277e3a49\n193eade2\n277e3a49\nfffffffe\nffffffff\n1fffe\n0\nfffffffe\nffffffff\n1fffe\n0\n1\n0\nfffe0001\n0\nfdbdade2\nffffffff\n420fade2\n0\nfffffffe\nffffffff\n1fe\n0\nfffffffe\nffffffff\n1fe\n0\n1\n0\nfe01\n0\n1\n0\nfe01\n0\nffffd9e2\nffffffff\n2be2\n0\n0\n0\n0\n0\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq 2,r4
+ muls.d r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 2,r4
+ mulu.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 1
+
+ moveq 2,r3
+ moveq -1,r4
+ muls.d r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq -1,r4
+ mulu.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 1
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ muls.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 fffe0001
+ move mof,r3
+ checkr3 0
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ mulu.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 fffe0001
+ move mof,r3
+ checkr3 0
+
+ moveq -1,r4
+ move.d r4,r3
+ muls.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+ move mof,r3
+ checkr3 0
+
+ moveq -1,r4
+ move.d r4,r3
+ mulu.d r4,r3
+ test_cc 1 0 1 0
+ checkr3 1
+ move mof,r3
+ checkr3 fffffffe
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ muls.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 193eade2
+ move mof,r3
+ checkr3 277e3a49
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ mulu.d r4,r3
+ test_cc 0 0 1 0
+ checkr3 193eade2
+ move mof,r3
+ checkr3 277e3a49
+
+ move.d 0xffff,r3
+ moveq 2,r4
+ muls.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 2,r4
+ mulu.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+ move mof,r3
+ checkr3 0
+
+ moveq 2,r3
+ move.d 0xffff,r4
+ muls.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq -1,r4
+ mulu.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fffe
+ move mof,r3
+ checkr3 0
+
+ move.d 0xffff,r4
+ move.d r4,r3
+ muls.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+ move mof,r3
+ checkr3 0
+
+ moveq -1,r4
+ move.d r4,r3
+ mulu.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 fffe0001
+ move mof,r3
+ checkr3 0
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ muls.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fdbdade2
+ move mof,r3
+ checkr3 ffffffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ mulu.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 420fade2
+ move mof,r3
+ checkr3 0
+
+ move.d 0xff,r3
+ moveq 2,r4
+ muls.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq -1,r3
+ moveq 2,r4
+ mulu.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fe
+ move mof,r3
+ checkr3 0
+
+ moveq 2,r3
+ moveq -1,r4
+ muls.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+ move mof,r3
+ checkr3 ffffffff
+
+ moveq 2,r3
+ moveq -1,r4
+ mulu.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 1fe
+ move mof,r3
+ checkr3 0
+
+ move.d 0xff,r4
+ move.d r4,r3
+ muls.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+ move mof,r3
+ checkr3 0
+
+ moveq -1,r4
+ move.d r4,r3
+ mulu.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 fe01
+ move mof,r3
+ checkr3 0
+
+ move.d 0xfeda49ff,r4
+ move.d r4,r3
+ muls.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+ move mof,r3
+ checkr3 0
+
+ move.d 0xfeda49ff,r4
+ move.d r4,r3
+ mulu.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 fe01
+ move mof,r3
+ checkr3 0
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ muls.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 ffffd9e2
+ move mof,r3
+ checkr3 ffffffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ mulu.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 2be2
+ move mof,r3
+ checkr3 0
+
+ moveq 0,r3
+ move.d 0xf87f4aeb,r4
+ muls.d r4,r3
+ test_cc 0 1 0 0
+ checkr3 0
+ move mof,r3
+ checkr3 0
+
+ move.d 0xf87f4aeb,r3
+ moveq 0,r4
+ mulu.d r4,r3
+ test_cc 0 1 0 0
+ checkr3 0
+ move mof,r3
+ checkr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_neg.s b/qemu-0.15.x/tests/cris/check_neg.s
new file mode 100644
index 0000000..963c4b6
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_neg.s
@@ -0,0 +1,104 @@
+# mach:  crisv0 crisv3 crisv8 crisv10 crisv32
+# output: ffffffff\nffffffff\n0\n80000000\n1\nba987655\nffff\nffff\n0\n89ab8000\nffff0001\n45677655\nff\nff\n0\n89abae80\nffffff01\n45678955\n
+
+ .include "testutils.inc"
+ start
+ moveq 0,r3
+ moveq 1,r4
+ neg.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 1,r3
+ moveq 0,r4
+ neg.d r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+;; FIXME: this was wrong.
+ moveq 0,r3
+ neg.d r3,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0x80000000,r3
+ neg.d r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 80000000
+
+ moveq -1,r3
+ neg.d r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0x456789ab,r3
+ neg.d r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 ba987655
+
+ moveq 0,r3
+ moveq 1,r4
+ neg.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff
+
+ moveq 1,r3
+ moveq 0,r4
+ neg.w r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff
+
+ moveq 0,r3
+ neg.w r3,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0x89ab8000,r3
+ neg.w r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 89ab8000
+
+ moveq -1,r3
+ neg.w r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0001
+
+ move.d 0x456789ab,r3
+ neg.w r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 45677655
+
+ moveq 0,r3
+ moveq 1,r4
+ neg.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ff
+
+ moveq 1,r3
+ moveq 0,r4
+ neg.b r3,r3
+ test_move_cc 1 0 0 0
+ checkr3 ff
+
+ moveq 0,r3
+ neg.b r3,r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+;; FIXME: was wrong.
+ move.d 0x89abae80,r3
+ neg.b r3,r3
+ test_move_cc 1 0 0 1
+ checkr3 89abae80
+
+ moveq -1,r3
+ neg.b r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffffff01
+
+ move.d 0x456789ab,r3
+ neg.b r3,r3
+ test_move_cc 0 0 0 0
+ checkr3 45678955
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_not.s b/qemu-0.15.x/tests/cris/check_not.s
new file mode 100644
index 0000000..33bcf15
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_not.s
@@ -0,0 +1,31 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: fffffffe\nfffffffd\nffff0f00\n0\n87ecbbad\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ not r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffffe
+
+ moveq 2,r3
+ not r3
+ test_move_cc 1 0 0 0
+ checkr3 fffffffd
+
+ move.d 0xf0ff,r3
+ not r3
+ test_move_cc 1 0 0 0
+ checkr3 ffff0f00
+
+ moveq -1,r3
+ not r3
+ test_move_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0x78134452,r3
+ not r3
+ test_move_cc 1 0 0 0
+ checkr3 87ecbbad
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_openpf1.c b/qemu-0.15.x/tests/cris/check_openpf1.c
new file mode 100644
index 0000000..fdcf4c5
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_openpf1.c
@@ -0,0 +1,38 @@
+/* Check that --sysroot is applied to open(2).
+#sim: --sysroot=@exedir@
+
+   We assume, with EXE being the name of the executable:
+   - The simulator executes with cwd the same directory where the executable
+     is located (so argv[0] contains a plain filename without directory
+     components).
+   - There's no /EXE on the host file system.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+int main (int argc, char *argv[])
+{
+  char *fnam = argv[0];
+  FILE *f;
+  if (argv[0][0] != '/')
+    {
+      fnam = malloc (strlen (argv[0]) + 2);
+      if (fnam == NULL)
+	abort ();
+      strcpy (fnam, "/");
+      strcat (fnam, argv[0]);
+    }
+
+  f = fopen (fnam, "rb");
+  if (f == NULL)
+    abort ();
+  fclose(f);
+
+  /* Cover another execution path.  */
+  if (fopen ("/nonexistent", "rb") != NULL
+      || errno != ENOENT)
+    abort ();
+  printf ("pass\n");
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_openpf2.c b/qemu-0.15.x/tests/cris/check_openpf2.c
new file mode 100644
index 0000000..5d56189
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_openpf2.c
@@ -0,0 +1,16 @@
+/* Check that the simulator has chdir:ed to the --sysroot argument
+#sim: --sysroot=@srcdir@
+   (or that  --sysroot is applied to relative file paths).  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+int main (int argc, char *argv[])
+{
+  FILE *f = fopen ("check_openpf2.c", "rb");
+  if (f == NULL)
+    abort ();
+  fclose(f);
+  printf ("pass\n");
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_openpf3.c b/qemu-0.15.x/tests/cris/check_openpf3.c
new file mode 100644
index 0000000..557adee
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_openpf3.c
@@ -0,0 +1,49 @@
+/* Basic file operations (rename, unlink); once without sysroot.  We
+   also test that the simulator has chdir:ed to PREFIX, when defined.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef PREFIX
+#define PREFIX
+#endif
+
+void err (const char *s)
+{
+  perror (s);
+  abort ();
+}
+
+int main (int argc, char *argv[])
+{
+  FILE *f;
+  struct stat buf;
+
+  unlink (PREFIX "testfoo2.tmp");
+
+  f = fopen ("testfoo1.tmp", "w");
+  if (f == NULL)
+    err ("open");
+  fclose (f);
+
+  if (rename (PREFIX "testfoo1.tmp", PREFIX "testfoo2.tmp") != 0)
+    err ("rename");
+
+  if (stat (PREFIX "testfoo2.tmp", &buf) != 0
+      || !S_ISREG (buf.st_mode))
+    err ("stat 1");
+
+  if (stat ("testfoo2.tmp", &buf) != 0
+      || !S_ISREG (buf.st_mode))
+    err ("stat 2");
+
+  if (unlink (PREFIX "testfoo2.tmp") != 0)
+    err ("unlink");
+
+  printf ("pass\n");
+  return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_openpf4.c b/qemu-0.15.x/tests/cris/check_openpf4.c
new file mode 100644
index 0000000..8bbee41
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_openpf4.c
@@ -0,0 +1,5 @@
+/* Basic file operations, now *with* sysroot.
+#sim: --sysroot=@exedir@
+*/
+#define PREFIX "/"
+#include "check_openpf3.c"
diff --git a/qemu-0.15.x/tests/cris/check_openpf5.c b/qemu-0.15.x/tests/cris/check_openpf5.c
new file mode 100644
index 0000000..1f86ea2
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_openpf5.c
@@ -0,0 +1,56 @@
+/* Check that TRT happens when error on too many opened files.
+#notarget: cris*-*-elf
+#sim: --sysroot=@exedir@
+*/
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+int main (int argc, char *argv[])
+{
+  int i;
+  int filemax;
+
+#ifdef OPEN_MAX
+  filemax = OPEN_MAX;
+#else
+  filemax = sysconf (_SC_OPEN_MAX);
+#endif
+
+  char *fn = malloc (strlen (argv[0]) + 2);
+  if (fn == NULL)
+    abort ();
+  strcpy (fn, "/");
+  strcat (fn, argv[0]);
+
+  for (i = 0; i < filemax + 1; i++)
+    {
+      if (open (fn, O_RDONLY) < 0)
+	{
+	  /* Shouldn't happen too early.  */
+	  if (i < filemax - 3 - 1)
+	    {
+	      fprintf (stderr, "i: %d\n", i);
+	      abort ();
+	    }
+	  if (errno != EMFILE)
+	    {
+	      perror ("open");
+	      abort ();
+	    }
+	  goto ok;
+	}
+    }
+  abort ();
+
+ok:
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_orc.s b/qemu-0.15.x/tests/cris/check_orc.s
new file mode 100644
index 0000000..c733f03
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_orc.s
@@ -0,0 +1,71 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ or.d 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ or.d 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xf0ff,r3
+ or.d 0xff0f,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r3
+ or.d -1,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ or.d 0x5432f789,r3
+ test_move_cc 0 0 0 0
+ checkr3 7c33f7db
+
+ move.d 0xffff0001,r3
+ or.w 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0003
+
+ moveq 2,r3
+ or.w 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xfedaffaf,r3
+ or.w 0xff5f,r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d 0x78134452,r3
+ or.w 0xf789,r3
+ test_move_cc 1 0 0 0
+ checkr3 7813f7db
+
+ moveq 1,r3
+ or.b 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ or.b 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xfa3,r3
+ or.b 0x4a,r3
+ test_move_cc 1 0 0 0
+ checkr3 feb
+
+ move.d 0x78134453,r3
+ or.b 0x89,r3
+ test_move_cc 1 0 0 0
+ checkr3 781344db
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_orm.s b/qemu-0.15.x/tests/cris/check_orm.s
new file mode 100644
index 0000000..ee723a6
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_orm.s
@@ -0,0 +1,75 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword 2,1,0xff0f,-1,0x5432f789
+ .word 2,1,0xff5f,0xf789
+ .byte 2,1,0x4a,0x89
+
+ start
+ moveq 1,r3
+ move.d x,r5
+ or.d [r5+],r3
+ checkr3 3
+
+ moveq 2,r3
+ or.d [r5],r3
+ addq 4,r5
+ checkr3 3
+
+ move.d 0xf0ff,r3
+ or.d [r5+],r3
+ checkr3 ffff
+
+ moveq -1,r3
+ or.d [r5+],r3
+ checkr3 ffffffff
+
+ move.d 0x78134452,r3
+ or.d [r5+],r3
+ checkr3 7c33f7db
+
+ move.d 0xffff0001,r3
+ or.w [r5+],r3
+ checkr3 ffff0003
+
+ moveq 2,r3
+ or.w [r5],r3
+ addq 2,r5
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xfedaffaf,r3
+ or.w [r5+],r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d 0x78134452,r3
+ or.w [r5+],r3
+ test_move_cc 1 0 0 0
+ checkr3 7813f7db
+
+ moveq 1,r3
+ or.b [r5+],r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ or.b [r5],r3
+ addq 1,r5
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xfa3,r3
+ or.b [r5+],r3
+ test_move_cc 1 0 0 0
+ checkr3 feb
+
+ move.d 0x78134453,r3
+ or.b [r5],r3
+ test_move_cc 1 0 0 0
+ checkr3 781344db
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_orq.s b/qemu-0.15.x/tests/cris/check_orq.s
new file mode 100644
index 0000000..5060edc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_orq.s
@@ -0,0 +1,41 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 3\n3\nffffffff\nffffffff\n1f\nffffffe0\n7813445e\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ orq 2,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ orq 1,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xf0ff,r3
+ orq -1,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 0,r3
+ orq -1,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ moveq 0,r3
+ orq 31,r3
+ test_move_cc 0 0 0 0
+ checkr3 1f
+
+ moveq 0,r3
+ orq -32,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffe0
+
+ move.d 0x78134452,r3
+ orq 12,r3
+ test_move_cc 0 0 0 0
+ checkr3 7813445e
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_orr.s b/qemu-0.15.x/tests/cris/check_orr.s
new file mode 100644
index 0000000..a514c11
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_orr.s
@@ -0,0 +1,84 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ moveq 2,r4
+ or.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ moveq 1,r4
+ or.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xff0f,r4
+ move.d 0xf0ff,r3
+ or.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff
+
+ moveq -1,r4
+ move.d r4,r3
+ or.d r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 ffffffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ or.d r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 7c33f7db
+
+ move.d 0xffff0001,r3
+ moveq 2,r4
+ or.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 ffff0003
+
+ moveq 2,r3
+ move.d 0xffff0001,r4
+ or.w r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0xfedaffaf,r3
+ move.d 0xffffff5f,r4
+ or.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 fedaffff
+
+ move.d 0x5432f789,r4
+ move.d 0x78134452,r3
+ or.w r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 7813f7db
+
+ moveq 1,r3
+ move.d 0xffffff02,r4
+ or.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ moveq 2,r3
+ moveq 1,r4
+ or.b r4,r3
+ test_move_cc 0 0 0 0
+ checkr3 3
+
+ move.d 0x4a,r4
+ move.d 0xfa3,r3
+ or.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 feb
+
+ move.d 0x5432f789,r4
+ move.d 0x78134453,r3
+ or.b r4,r3
+ test_move_cc 1 0 0 0
+ checkr3 781344db
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_ret.s b/qemu-0.15.x/tests/cris/check_ret.s
new file mode 100644
index 0000000..b44fb25
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_ret.s
@@ -0,0 +1,25 @@
+# mach: crisv3 crisv8 crisv10
+# output: 3\n
+
+# Test that ret works.
+
+ .include "testutils.inc"
+ start
+x:
+ moveq 0,r3
+ jsr z
+w:
+ quit
+y:
+ addq 1,r3
+ checkr3 3
+ quit
+
+z:
+ addq 1,r3
+ move srp,r2
+ add.d y-w,r2
+ move r2,srp
+ ret
+ addq 1,r3
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_scc.s b/qemu-0.15.x/tests/cris/check_scc.s
new file mode 100644
index 0000000..4a8674c
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_scc.s
@@ -0,0 +1,95 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n0\n1\n1\n0\n1\n0\n0\n1\n1\n0\n1\n1\n0\n
+
+ .include "testutils.inc"
+
+ .macro lcheckr3 v
+	move	 $ccs, $r9
+	checkr3 \v
+	move	$r9, $ccs
+ .endm
+
+ start
+ clearf nzvc
+ scc r3
+ lcheckr3 1
+ scs r3
+ lcheckr3 0
+ sne r3
+ lcheckr3 1
+ seq r3
+ lcheckr3 0
+ svc r3
+ lcheckr3 1
+ svs r3
+ lcheckr3 0
+ spl r3
+ lcheckr3 1
+ smi r3
+ lcheckr3 0
+ sls r3
+ lcheckr3 0
+ shi r3
+ lcheckr3 1
+ sge r3
+ lcheckr3 1
+ slt r3
+ lcheckr3 0
+ sgt r3
+ lcheckr3 1
+ sle r3
+ lcheckr3 0
+ sa r3
+ lcheckr3 1
+ setf nzvc
+ scc r3
+ lcheckr3 0
+ scs r3
+ lcheckr3 1
+ sne r3
+ lcheckr3 0
+ svc r3
+ lcheckr3 0
+ svs r3
+ lcheckr3 1
+ spl r3
+ lcheckr3 0
+ smi r3
+ lcheckr3 1
+ sls r3
+ lcheckr3 1
+ shi r3
+ lcheckr3 0
+ sge r3
+ lcheckr3 1
+ slt r3
+ lcheckr3 0
+ sgt r3
+ lcheckr3 0
+ sle r3
+ lcheckr3 1
+ sa r3
+ lcheckr3 1
+ clearf n
+ sge r3
+ lcheckr3 0
+ slt r3
+ lcheckr3 1
+
+ .if 1 ;..asm.arch.cris.v32
+ setf p
+ ssb r3
+ .else
+ moveq 1,r3
+ .endif
+ lcheckr3 1
+
+ .if 1 ;..asm.arch.cris.v32
+ clearf p
+ ssb r3
+ .else
+ moveq 0,r3
+ .endif
+ lcheckr3 0
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_settls1.c b/qemu-0.15.x/tests/cris/check_settls1.c
new file mode 100644
index 0000000..69d2026
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_settls1.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+
+#ifndef SYS_set_thread_area
+#define SYS_set_thread_area 243
+#endif
+
+int main (void)
+{
+    unsigned long tp, old_tp;
+    int ret;
+
+    asm volatile ("move $pid,%0" : "=r" (old_tp));
+    old_tp &= ~0xff;
+
+    ret = syscall (SYS_set_thread_area, 0xf0);
+    if (ret != -1 || errno != EINVAL) {
+        syscall (SYS_set_thread_area, old_tp);
+        perror ("Invalid thread area accepted:");
+        abort();
+    }
+
+    ret = syscall (SYS_set_thread_area, 0xeddeed00);
+    if (ret != 0) {
+        perror ("Valid thread area not accepted: ");
+        abort ();
+    }
+
+    asm volatile ("move $pid,%0" : "=r" (tp));
+    tp &= ~0xff;
+    syscall (SYS_set_thread_area, old_tp);
+
+    if (tp != 0xeddeed00) {
+	* (volatile int *) 0 = 0;
+        perror ("tls2");
+        abort ();
+    }
+
+    printf ("pass\n");
+    return EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/tests/cris/check_sigalrm.c b/qemu-0.15.x/tests/cris/check_sigalrm.c
new file mode 100644
index 0000000..39fa8d9
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_sigalrm.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define MAGIC (0xdeadbeef)
+
+int s = 0;
+void sighandler(int sig)
+{
+	s = MAGIC;
+}
+
+int main(int argc, char **argv)
+{
+	int p;
+
+	p = getpid();
+	signal(SIGALRM, sighandler);
+	kill(p, SIGALRM);
+	if (s != MAGIC)
+		return EXIT_FAILURE;
+
+	printf ("passed\n");
+	return EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/tests/cris/check_stat1.c b/qemu-0.15.x/tests/cris/check_stat1.c
new file mode 100644
index 0000000..2e2cae5
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_stat1.c
@@ -0,0 +1,16 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (void)
+{
+  struct stat buf;
+
+  if (stat (".", &buf) != 0
+      || !S_ISDIR (buf.st_mode))
+    abort ();
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_stat2.c b/qemu-0.15.x/tests/cris/check_stat2.c
new file mode 100644
index 0000000..e36172e
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_stat2.c
@@ -0,0 +1,20 @@
+/*
+#notarget: cris*-*-elf
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (void)
+{
+  struct stat buf;
+
+  if (lstat (".", &buf) != 0
+      || !S_ISDIR (buf.st_mode))
+    abort ();
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_stat3.c b/qemu-0.15.x/tests/cris/check_stat3.c
new file mode 100644
index 0000000..36a9d5d
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_stat3.c
@@ -0,0 +1,25 @@
+/* Simulator options:
+#sim: --sysroot=@exedir@
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int main (int argc, char *argv[])
+{
+  char path[1024] = "/";
+  struct stat buf;
+
+  strncat(path, argv[0], sizeof(path) - 2);
+  if (stat (".", &buf) != 0
+      || !S_ISDIR (buf.st_mode))
+    abort ();
+  if (stat (path, &buf) != 0
+      || !S_ISREG (buf.st_mode))
+    abort ();
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_stat4.c b/qemu-0.15.x/tests/cris/check_stat4.c
new file mode 100644
index 0000000..04f21fe
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_stat4.c
@@ -0,0 +1,27 @@
+/* Simulator options:
+#notarget: cris*-*-elf
+#sim: --sysroot=@exedir@
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int main (int argc, char *argv[])
+{
+  char path[1024] = "/";
+  struct stat buf;
+
+  strncat(path, argv[0], sizeof(path) - 2);
+  if (lstat (".", &buf) != 0
+      || !S_ISDIR (buf.st_mode))
+    abort ();
+  if (lstat (path, &buf) != 0
+      || !S_ISREG (buf.st_mode))
+    abort ();
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_subc.s b/qemu-0.15.x/tests/cris/check_subc.s
new file mode 100644
index 0000000..e34b544
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_subc.s
@@ -0,0 +1,87 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
+
+ .include "testutils.inc"
+ start
+
+ moveq -1,r3
+ sub.d -2,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ moveq 2,r3
+ sub.d 1,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xffff,r3
+ sub.d -0xffff,r3
+ test_cc 0 0 0 1
+ checkr3 1fffe
+
+ moveq -1,r3
+ sub.d 1,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move.d 0x78134452,r3
+ sub.d -0x5432f789,r3
+ test_cc 1 0 1 1
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ sub.w -2,r3
+ test_cc 0 0 0 0
+ checkr3 ffff0001
+
+ moveq 2,r3
+ sub.w 1,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xffff,r3
+ sub.w 1,r3
+ test_cc 1 0 0 0
+ checkr3 fffe
+
+ move.d 0xfedaffff,r3
+ sub.w 1,r3
+ test_cc 1 0 0 0
+ checkr3 fedafffe
+
+ move.d 0x78134452,r3
+ sub.w 0x877,r3
+ test_cc 0 0 0 0
+ checkr3 78133bdb
+
+ moveq -1,r3
+ sub.b -2,r3
+ test_cc 0 0 0 0
+ checkr3 ffffff01
+
+ moveq 2,r3
+ sub.b 1,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xff,r3
+ sub.b 1,r3
+ test_cc 1 0 0 0
+ checkr3 fe
+
+ move.d 0xfeda49ff,r3
+ sub.b 1,r3
+ test_cc 1 0 0 0
+ checkr3 feda49fe
+
+ move.d 0x78134452,r3
+ sub.b 0x77,r3
+ test_cc 1 0 0 1
+ checkr3 781344db
+
+ move.d 0x85649282,r3
+ sub.b 0x82,r3
+ test_cc 0 1 0 0
+ checkr3 85649200
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_subm.s b/qemu-0.15.x/tests/cris/check_subm.s
new file mode 100644
index 0000000..e07ea02
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_subm.s
@@ -0,0 +1,96 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
+
+ .include "testutils.inc"
+ .data
+x:
+ .dword -2,1,-0xffff,1,-0x5432f789
+ .word -2,1,1,0x877
+ .byte -2,1,0x77
+ .byte 0x22
+
+ start
+ moveq -1,r3
+ move.d x,r5
+ sub.d [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ moveq 2,r3
+ sub.d [r5],r3
+ test_cc 0 0 0 0
+ addq 4,r5
+ checkr3 1
+
+ move.d 0xffff,r3
+ sub.d [r5+],r3
+ test_cc 0 0 0 1
+ checkr3 1fffe
+
+ moveq -1,r3
+ sub.d [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move.d 0x78134452,r3
+ sub.d [r5+],r3
+ test_cc 1 0 1 1
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ sub.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 ffff0001
+
+ moveq 2,r3
+ sub.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xffff,r3
+ sub.w [r5],r3
+ test_cc 1 0 0 0
+ checkr3 fffe
+
+ move.d 0xfedaffff,r3
+ sub.w [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 fedafffe
+
+ move.d 0x78134452,r3
+ sub.w [r5+],r3
+ test_cc 0 0 0 0
+ checkr3 78133bdb
+
+ moveq -1,r3
+ sub.b [r5],r3
+ test_cc 0 0 0 0
+ addq 1,r5
+ checkr3 ffffff01
+
+ moveq 2,r3
+ sub.b [r5],r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xff,r3
+ sub.b [r5],r3
+ test_cc 1 0 0 0
+ checkr3 fe
+
+ move.d 0xfeda49ff,r3
+ sub.b [r5+],r3
+ test_cc 1 0 0 0
+ checkr3 feda49fe
+
+ move.d 0x78134452,r3
+ sub.b [r5+],r3
+ test_cc 1 0 0 1
+ checkr3 781344db
+
+ move.d 0x85649222,r3
+ sub.b [r5],r3
+ test_cc 0 1 0 0
+ checkr3 85649200
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_subq.s b/qemu-0.15.x/tests/cris/check_subq.s
new file mode 100644
index 0000000..9e34fa3
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_subq.s
@@ -0,0 +1,52 @@
+# mach: crisv3 crisv8 crisv10 crisv32
+# output: 0\nffffffff\nfffffffe\nffff\nff\n56788f9\n56788d9\n567889a\n0\n7ffffffc\n
+
+ .include "testutils.inc"
+ start
+ moveq 1,r3
+ subq 1,r3
+ test_cc 0 1 0 0
+ checkr3 0
+
+ subq 1,r3
+ test_cc 1 0 0 1
+ checkr3 ffffffff
+
+ subq 1,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move.d 0x10000,r3
+ subq 1,r3
+ test_cc 0 0 0 0
+ checkr3 ffff
+
+ move.d 0x100,r3
+ subq 1,r3
+ test_cc 0 0 0 0
+ checkr3 ff
+
+ move.d 0x5678900,r3
+ subq 7,r3
+ test_cc 0 0 0 0
+ checkr3 56788f9
+
+ subq 32,r3
+ test_cc 0 0 0 0
+ checkr3 56788d9
+
+ subq 63,r3
+ test_cc 0 0 0 0
+ checkr3 567889a
+
+ move.d 34,r3
+ subq 34,r3
+ test_cc 0 1 0 0
+ checkr3 0
+
+ move.d 0x80000024,r3
+ subq 40,r3
+ test_cc 0 0 1 0
+ checkr3 7ffffffc
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_subr.s b/qemu-0.15.x/tests/cris/check_subr.s
new file mode 100644
index 0000000..742fbc8
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_subr.s
@@ -0,0 +1,102 @@
+# mach: crisv0 crisv3 crisv8 crisv10 crisv32
+# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
+
+ .include "testutils.inc"
+ start
+ moveq -1,r3
+ moveq -2,r4
+ sub.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ moveq 2,r3
+ moveq 1,r4
+ sub.d r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xffff,r3
+ move.d -0xffff,r4
+ sub.d r4,r3
+ test_cc 0 0 0 1
+ checkr3 1fffe
+
+ moveq 1,r4
+ moveq -1,r3
+ sub.d r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffffffe
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ sub.d r4,r3
+ test_cc 1 0 1 1
+ checkr3 cc463bdb
+
+ moveq -1,r3
+ moveq -2,r4
+ sub.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 ffff0001
+
+ moveq 2,r3
+ moveq 1,r4
+ sub.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d 0xffff,r3
+ move.d -0xffff,r4
+ sub.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fffe
+
+ move.d 0xfedaffff,r3
+ move.d -0xfedaffff,r4
+ sub.w r4,r3
+ test_cc 1 0 0 0
+ checkr3 fedafffe
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ sub.w r4,r3
+ test_cc 0 0 0 0
+ checkr3 78133bdb
+
+ moveq -1,r3
+ moveq -2,r4
+ sub.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 ffffff01
+
+ moveq 2,r3
+ moveq 1,r4
+ sub.b r4,r3
+ test_cc 0 0 0 0
+ checkr3 1
+
+ move.d -0xff,r4
+ move.d 0xff,r3
+ sub.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 fe
+
+ move.d -0xfeda49ff,r4
+ move.d 0xfeda49ff,r3
+ sub.b r4,r3
+ test_cc 1 0 0 0
+ checkr3 feda49fe
+
+ move.d -0x5432f789,r4
+ move.d 0x78134452,r3
+ sub.b r4,r3
+ test_cc 1 0 0 1
+ checkr3 781344db
+
+ move.d 0x85649222,r3
+ move.d 0x77445622,r4
+ sub.b r4,r3
+ test_cc 0 1 0 0
+ checkr3 85649200
+
+ quit
diff --git a/qemu-0.15.x/tests/cris/check_swap.c b/qemu-0.15.x/tests/cris/check_swap.c
new file mode 100644
index 0000000..f851cbc
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_swap.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sys.h"
+#include "crisutils.h"
+
+#define N 8
+#define W 4
+#define B 2
+#define R 1
+
+static inline int cris_swap(const int mode, int x)
+{
+	switch (mode)
+	{
+		case N: asm ("swapn\t%0\n" : "+r" (x) : "0" (x)); break;
+		case W: asm ("swapw\t%0\n" : "+r" (x) : "0" (x)); break;
+		case B: asm ("swapb\t%0\n" : "+r" (x) : "0" (x)); break;
+		case R: asm ("swapr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case B|R: asm ("swapbr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case W|R: asm ("swapwr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case W|B: asm ("swapwb\t%0\n" : "+r" (x) : "0" (x)); break;
+		case W|B|R: asm ("swapwbr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case N|R: asm ("swapnr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case N|B: asm ("swapnb\t%0\n" : "+r" (x) : "0" (x)); break;
+		case N|B|R: asm ("swapnbr\t%0\n" : "+r" (x) : "0" (x)); break;
+		case N|W: asm ("swapnw\t%0\n" : "+r" (x) : "0" (x)); break;
+		default:
+			err();
+			break;
+	}
+	return x;
+}
+
+/* Made this a macro to be able to pick up the location of the errors.  */
+#define verify_swap(mode, val, expected, n, z)          \
+do {                                                    \
+        int r;                                          \
+        cris_tst_cc_init();                             \
+	r = cris_swap(mode, val);                       \
+        cris_tst_mov_cc(n, z);                          \
+	if (r != expected)                              \
+		err();                                  \
+} while(0)
+
+void check_swap(void)
+{
+	/* Some of these numbers are borrowed from GDB's cris sim
+	   testsuite.  */
+	if (cris_swap(N, 0) != 0xffffffff)
+		err();
+	if (cris_swap(W, 0x12345678) != 0x56781234)
+		err();
+	if (cris_swap(B, 0x12345678) != 0x34127856)
+		err();
+
+	verify_swap(R, 0x78134452, 0x1ec8224a, 0, 0);
+	verify_swap(B, 0x78134452, 0x13785244, 0, 0);
+	verify_swap(B|R, 0x78134452, 0xc81e4a22, 1, 0);
+	verify_swap(W, 0x78134452, 0x44527813, 0, 0);
+	verify_swap(W|R, 0x78134452, 0x224a1ec8, 0, 0);
+	verify_swap(W|B|R, 0x78134452, 0x4a22c81e, 0, 0);
+	verify_swap(N, 0x78134452, 0x87ecbbad, 1, 0);
+	verify_swap(N|R, 0x78134452, 0xe137ddb5, 1, 0);
+	verify_swap(N|B, 0x78134452, 0xec87adbb, 1, 0);
+	verify_swap(N|B|R, 0x78134452, 0x37e1b5dd, 0, 0);
+	verify_swap(N|W, 0x78134452, 0xbbad87ec, 1, 0);
+	verify_swap(N|B|R, 0xffffffff, 0, 0, 1);
+}
+
+int main(void)
+{
+	check_swap();
+	pass();
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/cris/check_time1.c b/qemu-0.15.x/tests/cris/check_time1.c
new file mode 100644
index 0000000..3fcf0e1
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_time1.c
@@ -0,0 +1,46 @@
+/* Basic time functionality test: check that milliseconds are
+   incremented for each syscall (does not work on host).  */
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+
+void err (const char *s)
+{
+  perror (s);
+  abort ();
+}
+
+int
+main (void)
+{
+  struct timeval t_m = {0, 0};
+  struct timezone t_z = {0, 0};
+  struct timeval t_m1 = {0, 0};
+  int i;
+
+  if (gettimeofday (&t_m, &t_z) != 0)
+    err ("gettimeofday");
+
+  for (i = 1; i < 10000; i++)
+    if (gettimeofday (&t_m1, NULL) != 0)
+      err ("gettimeofday 1");
+    else
+      if (t_m1.tv_sec * 1000000 + t_m1.tv_usec
+	  != (t_m.tv_sec * 1000000 + t_m.tv_usec + i * 1000))
+	{
+	  fprintf (stderr, "t0 (%ld, %ld), i %d, t1 (%ld, %ld)\n",
+		   t_m.tv_sec, t_m.tv_usec, i, t_m1.tv_sec, t_m1.tv_usec);
+	  abort ();
+	}
+
+  if (time (NULL) != t_m1.tv_sec)
+    {
+      fprintf (stderr, "time != gettod\n");
+      abort ();
+    }
+
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_time2.c b/qemu-0.15.x/tests/cris/check_time2.c
new file mode 100644
index 0000000..20b69b4
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_time2.c
@@ -0,0 +1,18 @@
+/* CB_SYS_time doesn't implement the Linux time syscall; the return
+   value isn't written to the argument.  */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  time_t x = (time_t) -1;
+  time_t t = time (&x);
+
+  if (t == (time_t) -1 || t != x)
+    abort ();
+  printf ("pass\n");
+  exit (0);
+}
diff --git a/qemu-0.15.x/tests/cris/check_xarith.s b/qemu-0.15.x/tests/cris/check_xarith.s
new file mode 100644
index 0000000..80038b2
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/check_xarith.s
@@ -0,0 +1,72 @@
+
+.include "testutils.inc"
+
+	start
+
+	moveq	-1, $r0
+	moveq	0, $r1
+	addq	1, $r0
+	ax
+	addq	0, $r1
+
+	move.d	$r0, $r3
+	checkr3 0
+	move.d	$r1, $r3
+	checkr3 1
+
+	move.d  0, $r0
+	moveq	-1, $r1
+	subq	1, $r0
+	ax
+	subq	0, $r1
+
+	move.d	$r0, $r3
+	checkr3 ffffffff
+	move.d	$r1, $r3
+	checkr3 fffffffe
+
+
+	moveq	-1, $r0
+	moveq	-1, $r1
+	cmpq	-1, $r0
+	ax
+	cmpq	-1, $r1
+	beq	1f
+	nop
+	fail
+1:
+	cmpq	0, $r0
+	ax
+	cmpq	-1, $r1
+	bne	1f
+	nop
+	fail
+1:
+
+	;; test for broken X sequence, run it several times.
+	moveq	8, $r0
+1:
+	moveq	0, $r3
+	move.d	$r0, $r1
+	andq	1, $r1
+	lslq	4, $r1
+	moveq	1, $r2
+	or.d	$r1, $r2
+	ba	2f
+	move	$r2, $ccs
+2:
+	addq	0, $r3
+	move.d	$r0, $r4
+	move.d	$r1, $r5
+	move.d	$r2, $r6
+	move.d	$r3, $r7
+	lsrq	4, $r1
+	move.d	$r1, $r8
+	xor	$r1, $r3
+	checkr3	0
+	subq	1, $r0
+	bne	1b
+	nop
+
+	pass
+	quit
diff --git a/qemu-0.15.x/tests/cris/crisutils.h b/qemu-0.15.x/tests/cris/crisutils.h
new file mode 100644
index 0000000..29b71cd
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/crisutils.h
@@ -0,0 +1,71 @@
+static char *tst_cc_loc = NULL;
+
+#define cris_tst_cc_init() \
+do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0)
+
+/* We need a real symbol to signal error.  */
+void _err(void) {
+	if (!tst_cc_loc)
+		tst_cc_loc = "tst_cc_failed\n";
+	_fail(tst_cc_loc);
+}
+
+static inline void cris_tst_cc_n1(void)
+{
+	asm volatile ("bpl _err\n"
+		      "nop\n");
+}
+static inline void cris_tst_cc_n0(void)
+{
+	asm volatile ("bmi _err\n"
+		      "nop\n");
+}
+
+static inline void cris_tst_cc_z1(void)
+{
+	asm volatile ("bne _err\n"
+		      "nop\n");
+}
+static inline void cris_tst_cc_z0(void)
+{
+	asm volatile ("beq _err\n"
+		      "nop\n");
+}
+static inline void cris_tst_cc_v1(void)
+{
+	asm volatile ("bvc _err\n"
+		      "nop\n");
+}
+static inline void cris_tst_cc_v0(void)
+{
+	asm volatile ("bvs _err\n"
+		      "nop\n");
+}
+
+static inline void cris_tst_cc_c1(void)
+{
+	asm volatile ("bcc _err\n"
+		      "nop\n");
+}
+static inline void cris_tst_cc_c0(void)
+{
+	asm volatile ("bcs _err\n"
+		      "nop\n");
+}
+
+static inline void cris_tst_mov_cc(int n, int z)
+{
+	if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
+	if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
+	asm volatile ("" : : "g" (_err));
+}
+
+static inline void cris_tst_cc(const int n, const int z,
+			       const int v, const int c)
+{
+	if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
+	if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
+	if (v) cris_tst_cc_v1(); else cris_tst_cc_v0();
+	if (c) cris_tst_cc_c1(); else cris_tst_cc_c0();
+	asm volatile ("" : : "g" (_err));
+}
diff --git a/qemu-0.15.x/tests/cris/crt.s b/qemu-0.15.x/tests/cris/crt.s
new file mode 100644
index 0000000..af027d7
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/crt.s
@@ -0,0 +1,13 @@
+	.data
+_stack_start:
+	.space	8192, 0
+_stack_end:
+	.text
+	.global	_start
+_start:
+	move.d	_stack_end, $sp
+	jsr	main
+	nop
+	moveq	0, $r10
+	jump	exit
+	nop
diff --git a/qemu-0.15.x/tests/cris/sys.c b/qemu-0.15.x/tests/cris/sys.c
new file mode 100644
index 0000000..551c5dd
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/sys.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static inline int mystrlen(char *s) {
+	int i = 0;
+	while (s[i])
+		i++;
+	return i;
+}
+
+void pass(void) {
+	char s[] = "passed.\n";
+	write (1, s, sizeof (s) - 1);
+	exit (0);
+}
+
+void _fail(char *reason) {
+	char s[] = "\nfailed: ";
+	int len = mystrlen(reason);
+	write (1, s, sizeof (s) - 1);
+	write (1, reason, len);
+	write (1, "\n", 1);
+//	exit (1);
+}
+
+void *memset (void *s, int c, size_t n) {
+	char *p = s;
+	int i;
+	for (i = 0; i < n; i++)
+		p[i] = c;
+	return p;
+}
+
+void exit (int status) {
+	asm volatile ("moveq 1, $r9\n" /* NR_exit.  */
+		      "break 13\n");
+	while(1)
+		;
+}
+
+ssize_t write (int fd, const void *buf, size_t count) {
+	int r;
+	asm ("move.d %0, $r10\n"
+	     "move.d %1, $r11\n"
+	     "move.d %2, $r12\n"
+	     "moveq 4, $r9\n" /* NR_write.  */
+	     "break 13\n" : : "r" (fd), "r" (buf), "r" (count) : "memory");
+	asm ("move.d $r10, %0\n" : "=r" (r));
+	return r;
+}
diff --git a/qemu-0.15.x/tests/cris/sys.h b/qemu-0.15.x/tests/cris/sys.h
new file mode 100644
index 0000000..c5f88e1
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/sys.h
@@ -0,0 +1,16 @@
+#include <unistd.h>
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+#define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__)
+
+#define err()                         \
+{                                     \
+  _fail("at " CURRENT_LOCATION " ");  \
+}
+
+#define mb() asm volatile ("" : : : "memory")
+
+void pass(void);
+void _fail(char *reason);
diff --git a/qemu-0.15.x/tests/cris/testutils.inc b/qemu-0.15.x/tests/cris/testutils.inc
new file mode 100644
index 0000000..aa1641b
--- /dev/null
+++ b/qemu-0.15.x/tests/cris/testutils.inc
@@ -0,0 +1,117 @@
+	.syntax	no_register_prefix
+
+	.macro	start
+	.text
+	.global	main
+main:
+	.endm
+
+	.macro	quit
+	jump	pass
+	nop
+	.endm
+
+	.macro	pass
+	jump	pass
+	nop
+	.endm
+
+	.macro	startnostack
+	start
+	.endm
+
+	.macro	fail
+	.data
+99:
+	.asciz " checkr3 failed\n"
+	.text
+	move.d	99b, $r10
+	jsr	_fail
+	nop
+	.endm
+
+	.macro	checkr3 val
+	cmp.d	0x\val, $r3
+	beq	100f
+	nop
+	.data
+99:
+	.asciz "checkr3 failed\n"
+	.text
+	move.d	99b, $r10
+	jsr	_fail
+	nop
+100:
+	.endm
+
+; Test the condition codes
+        .macro test_cc N Z V C
+        .if \N
+        bpl 9f
+        nop
+        .else
+        bmi 9f
+        nop
+        .endif
+        .if \Z
+        bne 9f
+        nop
+        .else
+        beq 9f
+        nop
+        .endif
+        .if \V
+        bvc 9f
+        nop
+        .else
+        bvs 9f
+        nop
+        .endif
+        .if \C
+        bcc 9f
+        nop
+        .else
+        bcs 9f
+        nop
+        .endif
+        ba 8f
+        nop
+9:
+	.data
+99:
+	.asciz "test_move_cc failed\n"
+	.text
+	move.d	99b, $r10
+	jsr	_fail
+	nop
+8:
+        .endm
+
+
+        .macro test_move_cc N Z V C
+        .if \N
+        bpl 9f
+        nop
+        .else
+        bmi 9f
+        nop
+        .endif
+        .if \Z
+        bne 9f
+        nop
+        .else
+        beq 9f
+        nop
+        .endif
+        ba 8f
+        nop
+9:
+	.data
+99:
+	.asciz "test_move_cc failed\n"
+	.text
+	move.d	99b, $r10
+	jsr	_fail
+	nop
+8:
+        .endm
diff --git a/qemu-0.15.x/tests/hello-arm.c b/qemu-0.15.x/tests/hello-arm.c
new file mode 100644
index 0000000..e0daa7a
--- /dev/null
+++ b/qemu-0.15.x/tests/hello-arm.c
@@ -0,0 +1,113 @@
+#define __NR_SYSCALL_BASE	0x900000
+#define __NR_exit1			(__NR_SYSCALL_BASE+  1)
+#define __NR_write			(__NR_SYSCALL_BASE+  4)
+
+#define __sys2(x) #x
+#define __sys1(x) __sys2(x)
+
+#ifndef __syscall
+#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
+#endif
+
+#define __syscall_return(type, res)					\
+do {									\
+	return (type) (res);						\
+} while (0)
+
+#define _syscall0(type,name)						\
+type name(void) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+  "mov %0,r0"								\
+  :"=r" (__res) : : "r0","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  __syscall(name)							\
+  "mov %0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1))						\
+	: "r0","lr");							\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1,type2 arg2) {					\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2))				\
+	: "r0","r1","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1,type2 arg2,type3 arg3) {				\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3))	\
+        : "r0","r1","r2","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)		\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {				\
+  long __res;										\
+  __asm__ __volatile__ (								\
+  "mov\tr0,%1\n\t"									\
+  "mov\tr1,%2\n\t"									\
+  "mov\tr2,%3\n\t"									\
+  "mov\tr3,%4\n\t"									\
+  __syscall(name)									\
+  "mov\t%0,r0"										\
+  	: "=r" (__res)									\
+  	: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4))	\
+  	: "r0","r1","r2","r3","lr");							\
+  __syscall_return(type,__res);								\
+}
+
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)	\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {			\
+  long __res;										\
+  __asm__ __volatile__ (								\
+  "mov\tr0,%1\n\t"									\
+  "mov\tr1,%2\n\t"									\
+  "mov\tr2,%3\n\t"									\
+  "mov\tr3,%4\n\t"									\
+  "mov\tr4,%5\n\t"									\
+  __syscall(name)									\
+  "mov\t%0,r0"										\
+  	: "=r" (__res)									\
+  	: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)),	\
+	  "r" ((long)(arg5))								\
+	: "r0","r1","r2","r3","r4","lr");						\
+  __syscall_return(type,__res);								\
+}
+
+_syscall1(int,exit1,int,status);
+_syscall3(int,write,int,fd,const char *,buf, int, len);
+
+void _start(void)
+{
+    write(1, "Hello World\n", 12);
+    exit1(0);
+}
diff --git a/qemu-0.15.x/tests/hello-i386.c b/qemu-0.15.x/tests/hello-i386.c
new file mode 100644
index 0000000..86afc34
--- /dev/null
+++ b/qemu-0.15.x/tests/hello-i386.c
@@ -0,0 +1,26 @@
+#include <asm/unistd.h>
+
+static inline volatile void exit(int status)
+{
+  int __res;
+  __asm__ volatile ("movl %%ecx,%%ebx\n"\
+		    "int $0x80" \
+		    :  "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
+}
+
+static inline int write(int fd, const char * buf, int len)
+{
+  int status;
+  __asm__ volatile ("pushl %%ebx\n"\
+		    "movl %%esi,%%ebx\n"\
+		    "int $0x80\n" \
+		    "popl %%ebx\n"\
+		    : "=a" (status) \
+		    : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
+}
+
+void _start(void)
+{
+    write(1, "Hello World\n", 12);
+    exit(0);
+}
diff --git a/qemu-0.15.x/tests/hello-mips.c b/qemu-0.15.x/tests/hello-mips.c
new file mode 100644
index 0000000..f825673
--- /dev/null
+++ b/qemu-0.15.x/tests/hello-mips.c
@@ -0,0 +1,64 @@
+/*
+* MIPS o32 Linux syscall example
+*
+* http://www.linux-mips.org/wiki/RISC/os
+* http://www.linux-mips.org/wiki/MIPSABIHistory
+* http://www.linux.com/howtos/Assembly-HOWTO/mips.shtml
+*
+* mipsel-linux-gcc -nostdlib -mno-abicalls -fno-PIC -mabi=32 \
+*                  -O2 -static -o hello-mips hello-mips.c
+*
+*/
+#define __NR_SYSCALL_BASE	4000
+#define __NR_exit			(__NR_SYSCALL_BASE+  1)
+#define __NR_write			(__NR_SYSCALL_BASE+  4)
+
+static inline void exit1(int status)
+{
+    register unsigned long __a0 asm("$4") = (unsigned long) status;
+
+    __asm__ __volatile__ (
+        "	.set push	\n"
+        "	.set noreorder	\n"
+        "	li	$2, %0	\n"
+        "	syscall		\n"
+        "	.set pop	"
+        :
+	: "i" (__NR_exit), "r" (__a0)
+	: "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
+	  "memory");
+}
+
+static inline int write(int fd, const char *buf, int len)
+{
+    register unsigned long __a0 asm("$4") = (unsigned long) fd;
+    register unsigned long __a1 asm("$5") = (unsigned long) buf;
+    register unsigned long __a2 asm("$6") = (unsigned long) len;
+    register unsigned long __a3 asm("$7");
+    unsigned long __v0;
+
+    __asm__ __volatile__ (
+        "	.set push	\n"
+        "	.set noreorder	\n"
+        "	li	$2, %2	\n"
+        "	syscall		\n"
+        "	move	%0, $2	\n"
+        "	.set pop	"
+        : "=r" (__v0), "=r" (__a3)
+        : "i" (__NR_write), "r" (__a0), "r" (__a1), "r" (__a2)
+	: "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
+	  "memory");
+
+/*    if (__a3 == 0) */
+        return (int) __v0;
+/*
+    errno = __v0;
+    return -1;
+ */
+}
+
+void __start(void)
+{
+    write (1, "Hello, World!\n", 14);
+    exit1 (42);
+}
diff --git a/qemu-0.15.x/tests/linux-test.c b/qemu-0.15.x/tests/linux-test.c
new file mode 100644
index 0000000..2e4a746
--- /dev/null
+++ b/qemu-0.15.x/tests/linux-test.c
@@ -0,0 +1,537 @@
+/*
+ *  linux and CPU test
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <utime.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sched.h>
+#include <dirent.h>
+#include <setjmp.h>
+#include <sys/shm.h>
+
+#define TESTPATH "/tmp/linux-test.tmp"
+#define TESTPORT 7654
+#define STACK_SIZE 16384
+
+void error1(const char *filename, int line, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "%s:%d: ", filename, line);
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(1);
+}
+
+int __chk_error(const char *filename, int line, int ret)
+{
+    if (ret < 0) {
+        error1(filename, line, "%m (ret=%d, errno=%d)",
+               ret, errno);
+    }
+    return ret;
+}
+
+#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__)
+
+#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret))
+
+/*******************************************************/
+
+#define FILE_BUF_SIZE 300
+
+void test_file(void)
+{
+    int fd, i, len, ret;
+    uint8_t buf[FILE_BUF_SIZE];
+    uint8_t buf2[FILE_BUF_SIZE];
+    uint8_t buf3[FILE_BUF_SIZE];
+    char cur_dir[1024];
+    struct stat st;
+    struct utimbuf tbuf;
+    struct iovec vecs[2];
+    DIR *dir;
+    struct dirent *de;
+
+    /* clean up, just in case */
+    unlink(TESTPATH "/file1");
+    unlink(TESTPATH "/file2");
+    unlink(TESTPATH "/file3");
+    rmdir(TESTPATH);
+
+    if (getcwd(cur_dir, sizeof(cur_dir)) == NULL)
+        error("getcwd");
+
+    chk_error(mkdir(TESTPATH, 0755));
+
+    chk_error(chdir(TESTPATH));
+
+    /* open/read/write/close/readv/writev/lseek */
+
+    fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644));
+    for(i=0;i < FILE_BUF_SIZE; i++)
+        buf[i] = i;
+    len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2));
+    if (len != (FILE_BUF_SIZE / 2))
+        error("write");
+    vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2);
+    vecs[0].iov_len = 16;
+    vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16;
+    vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16;
+    len = chk_error(writev(fd, vecs, 2));
+    if (len != (FILE_BUF_SIZE / 2))
+     error("writev");
+    chk_error(close(fd));
+
+    chk_error(rename("file1", "file2"));
+
+    fd = chk_error(open("file2", O_RDONLY));
+
+    len = chk_error(read(fd, buf2, FILE_BUF_SIZE));
+    if (len != FILE_BUF_SIZE)
+        error("read");
+    if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0)
+        error("memcmp");
+
+#define FOFFSET 16
+    ret = chk_error(lseek(fd, FOFFSET, SEEK_SET));
+    if (ret != 16)
+        error("lseek");
+    vecs[0].iov_base = buf3;
+    vecs[0].iov_len = 32;
+    vecs[1].iov_base = buf3 + 32;
+    vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32;
+    len = chk_error(readv(fd, vecs, 2));
+    if (len != FILE_BUF_SIZE - FOFFSET)
+        error("readv");
+    if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0)
+        error("memcmp");
+
+    chk_error(close(fd));
+
+    /* access */
+    chk_error(access("file2", R_OK));
+
+    /* stat/chmod/utime/truncate */
+
+    chk_error(chmod("file2", 0600));
+    tbuf.actime = 1001;
+    tbuf.modtime = 1000;
+    chk_error(truncate("file2", 100));
+    chk_error(utime("file2", &tbuf));
+    chk_error(stat("file2", &st));
+    if (st.st_size != 100)
+        error("stat size");
+    if (!S_ISREG(st.st_mode))
+        error("stat mode");
+    if ((st.st_mode & 0777) != 0600)
+        error("stat mode2");
+    if (st.st_atime != 1001 ||
+        st.st_mtime != 1000)
+        error("stat time");
+
+    chk_error(stat(TESTPATH, &st));
+    if (!S_ISDIR(st.st_mode))
+        error("stat mode");
+
+    /* fstat */
+    fd = chk_error(open("file2", O_RDWR));
+    chk_error(ftruncate(fd, 50));
+    chk_error(fstat(fd, &st));
+    chk_error(close(fd));
+
+    if (st.st_size != 50)
+        error("stat size");
+    if (!S_ISREG(st.st_mode))
+        error("stat mode");
+
+    /* symlink/lstat */
+    chk_error(symlink("file2", "file3"));
+    chk_error(lstat("file3", &st));
+    if (!S_ISLNK(st.st_mode))
+        error("stat mode");
+
+    /* getdents */
+    dir = opendir(TESTPATH);
+    if (!dir)
+        error("opendir");
+    len = 0;
+    for(;;) {
+        de = readdir(dir);
+        if (!de)
+            break;
+        if (strcmp(de->d_name, ".") != 0 &&
+            strcmp(de->d_name, "..") != 0 &&
+            strcmp(de->d_name, "file2") != 0 &&
+            strcmp(de->d_name, "file3") != 0)
+            error("readdir");
+        len++;
+    }
+    closedir(dir);
+    if (len != 4)
+        error("readdir");
+
+    chk_error(unlink("file3"));
+    chk_error(unlink("file2"));
+    chk_error(chdir(cur_dir));
+    chk_error(rmdir(TESTPATH));
+}
+
+void test_fork(void)
+{
+    int pid, status;
+
+    pid = chk_error(fork());
+    if (pid == 0) {
+        /* child */
+        exit(2);
+    }
+    chk_error(waitpid(pid, &status, 0));
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 2)
+        error("waitpid status=0x%x", status);
+}
+
+void test_time(void)
+{
+    struct timeval tv, tv2;
+    struct timespec ts, rem;
+    struct rusage rusg1, rusg2;
+    int ti, i;
+
+    chk_error(gettimeofday(&tv, NULL));
+    rem.tv_sec = 1;
+    ts.tv_sec = 0;
+    ts.tv_nsec = 20 * 1000000;
+    chk_error(nanosleep(&ts, &rem));
+    if (rem.tv_sec != 1)
+        error("nanosleep");
+    chk_error(gettimeofday(&tv2, NULL));
+    ti = tv2.tv_sec - tv.tv_sec;
+    if (ti >= 2)
+        error("gettimeofday");
+
+    chk_error(getrusage(RUSAGE_SELF, &rusg1));
+    for(i = 0;i < 10000; i++);
+    chk_error(getrusage(RUSAGE_SELF, &rusg2));
+    if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 ||
+        (rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0)
+        error("getrusage");
+}
+
+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';
+}
+
+/* strcat and truncate. */
+char *pstrcat(char *buf, int buf_size, const char *s)
+{
+    int len;
+    len = strlen(buf);
+    if (len < buf_size)
+        pstrcpy(buf + len, buf_size - len, s);
+    return buf;
+}
+
+int server_socket(void)
+{
+    int val, fd;
+    struct sockaddr_in sockaddr;
+
+    /* server socket */
+    fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
+
+    val = 1;
+    chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)));
+
+    sockaddr.sin_family = AF_INET;
+    sockaddr.sin_port = htons(TESTPORT);
+    sockaddr.sin_addr.s_addr = 0;
+    chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
+    chk_error(listen(fd, 0));
+    return fd;
+
+}
+
+int client_socket(void)
+{
+    int fd;
+    struct sockaddr_in sockaddr;
+
+    /* server socket */
+    fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
+    sockaddr.sin_family = AF_INET;
+    sockaddr.sin_port = htons(TESTPORT);
+    inet_aton("127.0.0.1", &sockaddr.sin_addr);
+    chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
+    return fd;
+}
+
+const char socket_msg[] = "hello socket\n";
+
+void test_socket(void)
+{
+    int server_fd, client_fd, fd, pid, ret, val;
+    struct sockaddr_in sockaddr;
+    socklen_t len;
+    char buf[512];
+
+    server_fd = server_socket();
+
+    /* test a few socket options */
+    len = sizeof(val);
+    chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len));
+    if (val != SOCK_STREAM)
+        error("getsockopt");
+
+    pid = chk_error(fork());
+    if (pid == 0) {
+        client_fd = client_socket();
+        send(client_fd, socket_msg, sizeof(socket_msg), 0);
+        close(client_fd);
+        exit(0);
+    }
+    len = sizeof(sockaddr);
+    fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len));
+
+    ret = chk_error(recv(fd, buf, sizeof(buf), 0));
+    if (ret != sizeof(socket_msg))
+        error("recv");
+    if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0)
+        error("socket_msg");
+    chk_error(close(fd));
+    chk_error(close(server_fd));
+}
+
+#define WCOUNT_MAX 512
+
+void test_pipe(void)
+{
+    fd_set rfds, wfds;
+    int fds[2], fd_max, ret;
+    uint8_t ch;
+    int wcount, rcount;
+
+    chk_error(pipe(fds));
+    chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK));
+    chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK));
+    wcount = 0;
+    rcount = 0;
+    for(;;) {
+        FD_ZERO(&rfds);
+        fd_max = fds[0];
+        FD_SET(fds[0], &rfds);
+
+        FD_ZERO(&wfds);
+        FD_SET(fds[1], &wfds);
+        if (fds[1] > fd_max)
+            fd_max = fds[1];
+
+        ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL));
+        if (ret > 0) {
+            if (FD_ISSET(fds[0], &rfds)) {
+                chk_error(read(fds[0], &ch, 1));
+                rcount++;
+                if (rcount >= WCOUNT_MAX)
+                    break;
+            }
+            if (FD_ISSET(fds[1], &wfds)) {
+                ch = 'a';
+                chk_error(write(fds[0], &ch, 1));
+                wcount++;
+            }
+        }
+    }
+    chk_error(close(fds[0]));
+    chk_error(close(fds[1]));
+}
+
+int thread1_res;
+int thread2_res;
+
+int thread1_func(void *arg)
+{
+    int i;
+    for(i=0;i<5;i++) {
+        thread1_res++;
+        usleep(10 * 1000);
+    }
+    return 0;
+}
+
+int thread2_func(void *arg)
+{
+    int i;
+    for(i=0;i<6;i++) {
+        thread2_res++;
+        usleep(10 * 1000);
+    }
+    return 0;
+}
+
+void test_clone(void)
+{
+    uint8_t *stack1, *stack2;
+    int pid1, pid2, status1, status2;
+
+    stack1 = malloc(STACK_SIZE);
+    pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE,
+                           CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"));
+
+    stack2 = malloc(STACK_SIZE);
+    pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE,
+                           CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
+
+    while (waitpid(pid1, &status1, 0) != pid1);
+    free(stack1);
+    while (waitpid(pid2, &status2, 0) != pid2);
+    free(stack2);
+    if (thread1_res != 5 ||
+        thread2_res != 6)
+        error("clone");
+}
+
+/***********************************/
+
+volatile int alarm_count;
+jmp_buf jmp_env;
+
+void sig_alarm(int sig)
+{
+    if (sig != SIGALRM)
+        error("signal");
+    alarm_count++;
+}
+
+void sig_segv(int sig, siginfo_t *info, void *puc)
+{
+    if (sig != SIGSEGV)
+        error("signal");
+    longjmp(jmp_env, 1);
+}
+
+void test_signal(void)
+{
+    struct sigaction act;
+    struct itimerval it, oit;
+
+    /* timer test */
+
+    alarm_count = 0;
+
+    act.sa_handler = sig_alarm;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+    chk_error(sigaction(SIGALRM, &act, NULL));
+
+    it.it_interval.tv_sec = 0;
+    it.it_interval.tv_usec = 10 * 1000;
+    it.it_value.tv_sec = 0;
+    it.it_value.tv_usec = 10 * 1000;
+    chk_error(setitimer(ITIMER_REAL, &it, NULL));
+    chk_error(getitimer(ITIMER_REAL, &oit));
+    if (oit.it_value.tv_sec != it.it_value.tv_sec ||
+        oit.it_value.tv_usec != it.it_value.tv_usec)
+        error("itimer");
+
+    while (alarm_count < 5) {
+        usleep(10 * 1000);
+    }
+
+    it.it_interval.tv_sec = 0;
+    it.it_interval.tv_usec = 0;
+    it.it_value.tv_sec = 0;
+    it.it_value.tv_usec = 0;
+    memset(&oit, 0xff, sizeof(oit));
+    chk_error(setitimer(ITIMER_REAL, &it, &oit));
+    if (oit.it_value.tv_sec != 0 ||
+        oit.it_value.tv_usec != 10 * 1000)
+        error("setitimer");
+
+    /* SIGSEGV test */
+    act.sa_sigaction = sig_segv;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO;
+    chk_error(sigaction(SIGSEGV, &act, NULL));
+    if (setjmp(jmp_env) == 0) {
+        *(uint8_t *)0 = 0;
+    }
+
+    act.sa_handler = SIG_DFL;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+    chk_error(sigaction(SIGSEGV, &act, NULL));
+}
+
+#define SHM_SIZE 32768
+
+void test_shm(void)
+{
+    void *ptr;
+    int shmid;
+
+    shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777));
+    ptr = shmat(shmid, NULL, 0);
+    if (!ptr)
+        error("shmat");
+
+    memset(ptr, 0, SHM_SIZE);
+
+    chk_error(shmctl(shmid, IPC_RMID, 0));
+    chk_error(shmdt(ptr));
+}
+
+int main(int argc, char **argv)
+{
+    test_file();
+    test_fork();
+    test_time();
+    test_socket();
+    //    test_clone();
+    test_signal();
+    test_shm();
+    return 0;
+}
diff --git a/qemu-0.15.x/tests/lm32/Makefile b/qemu-0.15.x/tests/lm32/Makefile
new file mode 100644
index 0000000..03a1abb
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/Makefile
@@ -0,0 +1,102 @@
+-include ../../config-host.mak
+
+CROSS=lm32-elf-
+
+SIM = qemu-system-lm32
+SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)as
+AS      = $(CC) -x assembler
+SIZE    = $(CROSS)size
+LD      = $(CC)
+OBJCOPY = $(CROSS)objcopy
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o
+TESTCASES += test_add.tst
+TESTCASES += test_addi.tst
+TESTCASES += test_and.tst
+TESTCASES += test_andhi.tst
+TESTCASES += test_andi.tst
+TESTCASES += test_b.tst
+TESTCASES += test_be.tst
+TESTCASES += test_bg.tst
+TESTCASES += test_bge.tst
+TESTCASES += test_bgeu.tst
+TESTCASES += test_bgu.tst
+TESTCASES += test_bi.tst
+TESTCASES += test_bne.tst
+TESTCASES += test_break.tst
+TESTCASES += test_bret.tst
+TESTCASES += test_call.tst
+TESTCASES += test_calli.tst
+TESTCASES += test_cmpe.tst
+TESTCASES += test_cmpei.tst
+TESTCASES += test_cmpg.tst
+TESTCASES += test_cmpgi.tst
+TESTCASES += test_cmpge.tst
+TESTCASES += test_cmpgei.tst
+TESTCASES += test_cmpgeu.tst
+TESTCASES += test_cmpgeui.tst
+TESTCASES += test_cmpgu.tst
+TESTCASES += test_cmpgui.tst
+TESTCASES += test_cmpne.tst
+TESTCASES += test_cmpnei.tst
+TESTCASES += test_divu.tst
+TESTCASES += test_eret.tst
+TESTCASES += test_lb.tst
+TESTCASES += test_lbu.tst
+TESTCASES += test_lh.tst
+TESTCASES += test_lhu.tst
+TESTCASES += test_lw.tst
+TESTCASES += test_modu.tst
+TESTCASES += test_mul.tst
+TESTCASES += test_muli.tst
+TESTCASES += test_nor.tst
+TESTCASES += test_nori.tst
+TESTCASES += test_or.tst
+TESTCASES += test_ori.tst
+TESTCASES += test_orhi.tst
+#TESTCASES += test_rcsr.tst
+TESTCASES += test_ret.tst
+TESTCASES += test_sb.tst
+TESTCASES += test_scall.tst
+TESTCASES += test_sextb.tst
+TESTCASES += test_sexth.tst
+TESTCASES += test_sh.tst
+TESTCASES += test_sl.tst
+TESTCASES += test_sli.tst
+TESTCASES += test_sr.tst
+TESTCASES += test_sri.tst
+TESTCASES += test_sru.tst
+TESTCASES += test_srui.tst
+TESTCASES += test_sub.tst
+TESTCASES += test_sw.tst
+#TESTCASES += test_wcsr.tst
+TESTCASES += test_xnor.tst
+TESTCASES += test_xnori.tst
+TESTCASES += test_xor.tst
+TESTCASES += test_xori.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/lm32/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/lm32/%.S
+	$(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT)
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(CRT) $(TESTCASES)
+
+check: $(CRT) $(SYS) $(TESTCASES)
+	@for case in $(TESTCASES); do \
+		$(SIM) $(SIMFLAGS) ./$$case; \
+	done
+
+clean:
+	$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/qemu-0.15.x/tests/lm32/crt.S b/qemu-0.15.x/tests/lm32/crt.S
new file mode 100644
index 0000000..5f9cfd9
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/crt.S
@@ -0,0 +1,84 @@
+.text
+.global _start
+
+_start:
+_reset_handler:
+	xor r0, r0, r0
+	mvhi r1, hi(_start)
+	ori r1, r1, lo(_start)
+	wcsr eba, r1
+	wcsr deba, r1
+	bi _main
+	nop
+	nop
+
+_breakpoint_handler:
+	ori r25, r25, 1
+	addi ra, ba, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_instruction_bus_error_handler:
+	ori r25, r25, 2
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_watchpoint_handler:
+	ori r25, r25, 4
+	addi ra, ba, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_data_bus_error_handler:
+	ori r25, r25, 8
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_divide_by_zero_handler:
+	ori r25, r25, 16
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_interrupt_handler:
+	ori r25, r25, 32
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_system_call_handler:
+	ori r25, r25, 64
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
diff --git a/qemu-0.15.x/tests/lm32/linker.ld b/qemu-0.15.x/tests/lm32/linker.ld
new file mode 100644
index 0000000..52d43a4
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/linker.ld
@@ -0,0 +1,55 @@
+OUTPUT_FORMAT("elf32-lm32")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+	ram : ORIGIN = 0x08000000, LENGTH = 0x04000000  /* 64M */
+}
+
+SECTIONS
+{
+	.text :
+	{
+		_ftext = .;
+		*(.text .stub .text.* .gnu.linkonce.t.*)
+		_etext = .;
+	} > ram
+
+	.rodata :
+	{
+		. = ALIGN(4);
+		_frodata = .;
+		*(.rodata .rodata.* .gnu.linkonce.r.*)
+		*(.rodata1)
+		_erodata = .;
+	} > ram
+
+	.data :
+	{
+		. = ALIGN(4);
+		_fdata = .;
+		*(.data .data.* .gnu.linkonce.d.*)
+		*(.data1)
+		_gp = ALIGN(16);
+		*(.sdata .sdata.* .gnu.linkonce.s.*)
+		_edata = .;
+	} > ram
+
+	.bss :
+	{
+		. = ALIGN(4);
+		_fbss = .;
+		*(.dynsbss)
+		*(.sbss .sbss.* .gnu.linkonce.sb.*)
+		*(.scommon)
+		*(.dynbss)
+		*(.bss .bss.* .gnu.linkonce.b.*)
+		*(COMMON)
+		_ebss = .;
+		_end = .;
+	} > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
+
diff --git a/qemu-0.15.x/tests/lm32/macros.inc b/qemu-0.15.x/tests/lm32/macros.inc
new file mode 100644
index 0000000..367c7c5
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/macros.inc
@@ -0,0 +1,79 @@
+
+.macro test_name name
+	.data
+tn_\name:
+	.asciz "\name"
+	.text
+	mvhi r13, hi(tn_\name)
+	ori r13, r13, lo(tn_\name)
+	sw (r12+8), r13
+.endm
+
+.macro load reg val
+	mvhi \reg, hi(\val)
+	ori \reg, \reg, lo(\val)
+.endm
+
+.macro tc_pass
+	mvi r13, 0
+	sw (r12+4), r13
+.endm
+
+.macro tc_fail
+	mvi r13, 1
+	sw (r12+4), r13
+.endm
+
+.macro check_r3 val
+	mvhi r13, hi(\val)
+	ori r13, r13, lo(\val)
+	be r3, r13, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro check_mem adr val
+	mvhi r13, hi(\adr)
+	ori r13, r13, lo(\adr)
+	mvhi r14, hi(\val)
+	ori r14, r14, lo(\val)
+	lw r13, (r13+0)
+	be r13, r14, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro check_excp excp
+	andi r13, r25, \excp
+	bne r13, r0, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro start
+	.global _main
+	.text
+_main:
+	mvhi r12, hi(0xffff0000)      # base address of test block
+	ori r12, r12, lo(0xffff0000)
+.endm
+
+.macro end
+	sw (r12+0), r0
+1:
+	bi 1b
+.endm
+
+# base +
+#  0  ctrl
+#  4  pass/fail
+#  8  ptr to test name
diff --git a/qemu-0.15.x/tests/lm32/test_add.S b/qemu-0.15.x/tests/lm32/test_add.S
new file mode 100644
index 0000000..030ad19
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_add.S
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name ADD_1
+mvi r1, 0
+mvi r2, 0
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_2
+mvi r1, 0
+mvi r2, 1
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_3
+mvi r1, 1
+mvi r2, 0
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_4
+mvi r1, 1
+mvi r2, -1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_5
+mvi r1, -1
+mvi r2, 1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_6
+mvi r1, -1
+mvi r2, 0
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_7
+mvi r1, 0
+mvi r2, -1
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_8
+mvi r3, 2
+add r3, r3, r3
+check_r3 4
+
+test_name ADD_9
+mvi r1, 4
+mvi r3, 2
+add r3, r1, r3
+check_r3 6
+
+test_name ADD_10
+mvi r1, 4
+mvi r3, 2
+add r3, r3, r1
+check_r3 6
+
+test_name ADD_11
+mvi r1, 4
+add r3, r1, r1
+check_r3 8
+
+test_name ADD_12
+load r1 0x12345678
+load r2 0xabcdef97
+add r3, r1, r2
+check_r3 0xbe02460f
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_addi.S b/qemu-0.15.x/tests/lm32/test_addi.S
new file mode 100644
index 0000000..68e766d
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_addi.S
@@ -0,0 +1,56 @@
+.include "macros.inc"
+
+start
+
+test_name ADDI_1
+mvi r1, 0
+addi r3, r1, 0
+check_r3 0
+
+test_name ADDI_2
+mvi r1, 0
+addi r3, r1, 1
+check_r3 1
+
+test_name ADDI_3
+mvi r1, 1
+addi r3, r1, 0
+check_r3 1
+
+test_name ADDI_4
+mvi r1, 1
+addi r3, r1, -1
+check_r3 0
+
+test_name ADDI_5
+mvi r1, -1
+addi r3, r1, 1
+check_r3 0
+
+test_name ADDI_6
+mvi r1, -1
+addi r3, r1, 0
+check_r3 -1
+
+test_name ADDI_7
+mvi r1, 0
+addi r3, r1, -1
+check_r3 -1
+
+test_name ADDI_8
+mvi r3, 4
+addi r3, r3, 4
+check_r3 8
+
+test_name ADDI_9
+mvi r3, 4
+addi r3, r3, -4
+check_r3 0
+
+test_name ADDI_10
+mvi r3, 4
+addi r3, r3, -5
+check_r3 -1
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_and.S b/qemu-0.15.x/tests/lm32/test_and.S
new file mode 100644
index 0000000..80962ce
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_and.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name AND_1
+mvi r1, 0
+mvi r2, 0
+and r3, r1, r2
+check_r3 0
+
+test_name AND_2
+mvi r1, 0
+mvi r2, 1
+and r3, r1, r2
+check_r3 0
+
+test_name AND_3
+mvi r1, 1
+mvi r2, 1
+and r3, r1, r2
+check_r3 1
+
+test_name AND_4
+mvi r3, 7
+and r3, r3, r3
+check_r3 7
+
+test_name AND_5
+mvi r1, 7
+and r3, r1, r1
+check_r3 7
+
+test_name AND_6
+mvi r1, 7
+mvi r3, 0
+and r3, r1, r3
+check_r3 0
+
+test_name AND_7
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+and r3, r1, r2
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_andhi.S b/qemu-0.15.x/tests/lm32/test_andhi.S
new file mode 100644
index 0000000..4f73af5
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_andhi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDHI_1
+mvi r1, 0
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_2
+mvi r1, 1
+andhi r3, r1, 1
+check_r3 0
+
+test_name ANDHI_3
+load r1 0x000f0000
+andhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ANDHI_4
+load r1 0xffffffff
+andhi r3, r1, 0xffff
+check_r3 0xffff0000
+
+test_name ANDHI_5
+load r1 0xffffffff
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_6
+load r3 0x55aaffff
+andhi r3, r3, 0xaaaa
+check_r3 0x00aa0000
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_andi.S b/qemu-0.15.x/tests/lm32/test_andi.S
new file mode 100644
index 0000000..da1b0a3
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_andi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDI_1
+mvi r1, 0
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_2
+mvi r1, 1
+andi r3, r1, 1
+check_r3 1
+
+test_name ANDI_3
+load r1 0x000f0000
+andi r3, r1, 1
+check_r3 0
+
+test_name ANDI_4
+load r1 0xffffffff
+andi r3, r1, 0xffff
+check_r3 0xffff
+
+test_name ANDI_5
+load r1 0xffffffff
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_6
+load r3 0xffff55aa
+andi r3, r3, 0xaaaa
+check_r3 0x000000aa
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_b.S b/qemu-0.15.x/tests/lm32/test_b.S
new file mode 100644
index 0000000..98172d8
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_b.S
@@ -0,0 +1,13 @@
+.include "macros.inc"
+
+start
+
+test_name B_1
+load r1 jump
+b r1
+tc_fail
+end
+
+jump:
+tc_pass
+end
diff --git a/qemu-0.15.x/tests/lm32/test_be.S b/qemu-0.15.x/tests/lm32/test_be.S
new file mode 100644
index 0000000..635caba
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_be.S
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BE_1
+mvi r1, 0
+mvi r2, 0
+be r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BE_2
+mvi r1, 1
+mvi r2, 0
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BE_3
+mvi r1, 0
+mvi r2, 1
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BE_4
+mvi r1, 1
+mvi r2, 1
+be r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_bg.S b/qemu-0.15.x/tests/lm32/test_bg.S
new file mode 100644
index 0000000..81823c2
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bg.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BG_1
+mvi r1, 0
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_2
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_3
+mvi r1, 0
+mvi r2, 1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_4
+mvi r1, 0
+mvi r2, -1
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_5
+mvi r1, -1
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_6
+mvi r1, -1
+mvi r2, -1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BG_7
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_bge.S b/qemu-0.15.x/tests/lm32/test_bge.S
new file mode 100644
index 0000000..6684d15
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bge.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGE_1
+mvi r1, 0
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_2
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_3
+mvi r1, 0
+mvi r2, 1
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_4
+mvi r1, 0
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_5
+mvi r1, -1
+mvi r2, 0
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_6
+mvi r1, -1
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGE_7
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_bgeu.S b/qemu-0.15.x/tests/lm32/test_bgeu.S
new file mode 100644
index 0000000..be44030
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bgeu.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGEU_1
+mvi r1, 0
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_2
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_3
+mvi r1, 0
+mvi r2, 1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_4
+mvi r1, 0
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_5
+mvi r1, -1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_6
+mvi r1, -1
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGEU_7
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_bgu.S b/qemu-0.15.x/tests/lm32/test_bgu.S
new file mode 100644
index 0000000..8cc695b
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bgu.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGU_1
+mvi r1, 0
+mvi r2, 0
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_2
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_3
+mvi r1, 0
+mvi r2, 1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_4
+mvi r1, 0
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_5
+mvi r1, -1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_6
+mvi r1, -1
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGU_7
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_bi.S b/qemu-0.15.x/tests/lm32/test_bi.S
new file mode 100644
index 0000000..a1fbd6f
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bi.S
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+start
+
+test_name BI_1
+bi jump
+tc_fail
+end
+
+jump_back:
+tc_pass
+end
+
+jump:
+tc_pass
+
+test_name BI_2
+bi jump_back
+tc_fail
+
+end
+
+
diff --git a/qemu-0.15.x/tests/lm32/test_bne.S b/qemu-0.15.x/tests/lm32/test_bne.S
new file mode 100644
index 0000000..871a006
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bne.S
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BNE_1
+mvi r1, 0
+mvi r2, 0
+bne r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BNE_2
+mvi r1, 1
+mvi r2, 0
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BNE_3
+mvi r1, 0
+mvi r2, 1
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_fail
+bi 3f
+2:
+test_name BNE_4
+mvi r1, 1
+mvi r2, 1
+bne r1, r2, 1b
+tc_pass
+3:
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_break.S b/qemu-0.15.x/tests/lm32/test_break.S
new file mode 100644
index 0000000..0384fc6
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_break.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name BREAK_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+break
+check_excp 1
+
+test_name BREAK_2
+mv r3, ba
+check_r3 insn
+
+test_name BREAK_3
+rcsr r3, IE
+check_r3 4
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_bret.S b/qemu-0.15.x/tests/lm32/test_bret.S
new file mode 100644
index 0000000..645210e
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_bret.S
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name BRET_1
+mvi r1, 4
+wcsr IE, r1
+load ba mark
+bret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name BRET_2
+rcsr r3, IE
+check_r3 5
+
+test_name BRET_3
+mvi r1, 0
+wcsr IE, r1
+load ba mark2
+bret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name BRET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_call.S b/qemu-0.15.x/tests/lm32/test_call.S
new file mode 100644
index 0000000..1b91a5f
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_call.S
@@ -0,0 +1,16 @@
+.include "macros.inc"
+
+start
+
+test_name CALL_1
+load r1 mark
+call r1
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/qemu-0.15.x/tests/lm32/test_calli.S b/qemu-0.15.x/tests/lm32/test_calli.S
new file mode 100644
index 0000000..1d87ae6
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_calli.S
@@ -0,0 +1,15 @@
+.include "macros.inc"
+
+start
+
+test_name CALLI_1
+calli mark
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpe.S b/qemu-0.15.x/tests/lm32/test_cmpe.S
new file mode 100644
index 0000000..60a8855
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpe.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPE_1
+mvi r1, 0
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 1
+
+test_name CMPE_2
+mvi r1, 0
+mvi r2, 1
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_3
+mvi r1, 1
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_4
+mvi r3, 0
+mvi r2, 1
+cmpe r3, r3, r2
+check_r3 0
+
+test_name CMPE_5
+mvi r3, 0
+mvi r2, 0
+cmpe r3, r3, r2
+check_r3 1
+
+test_name CMPE_6
+mvi r3, 0
+cmpe r3, r3, r3
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpei.S b/qemu-0.15.x/tests/lm32/test_cmpei.S
new file mode 100644
index 0000000..c3d3566
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpei.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPEI_1
+mvi r1, 0
+cmpei r3, r1, 0
+check_r3 1
+
+test_name CMPEI_2
+mvi r1, 0
+cmpei r3, r1, 1
+check_r3 0
+
+test_name CMPEI_3
+mvi r1, 1
+cmpei r3, r1, 0
+check_r3 0
+
+test_name CMPEI_4
+load r1 0xffffffff
+cmpei r3, r1, -1
+check_r3 1
+
+test_name CMPEI_5
+mvi r3, 0
+cmpei r3, r3, 0
+check_r3 1
+
+test_name CMPEI_6
+mvi r3, 0
+cmpei r3, r3, 1
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpg.S b/qemu-0.15.x/tests/lm32/test_cmpg.S
new file mode 100644
index 0000000..0124078
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpg.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPG_1
+mvi r1, 0
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_2
+mvi r1, 0
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_3
+mvi r1, 1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_4
+mvi r1, 1
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_5
+mvi r1, 0
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_6
+mvi r1, -1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_7
+mvi r1, -1
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_8
+mvi r3, 0
+mvi r2, 1
+cmpg r3, r3, r2
+check_r3 0
+
+test_name CMPG_9
+mvi r3, 1
+mvi r2, 0
+cmpg r3, r3, r2
+check_r3 1
+
+test_name CMPG_10
+mvi r3, 0
+cmpg r3, r3, r3
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpge.S b/qemu-0.15.x/tests/lm32/test_cmpge.S
new file mode 100644
index 0000000..84620a0
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpge.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGE_1
+mvi r1, 0
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_2
+mvi r1, 0
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_3
+mvi r1, 1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_4
+mvi r1, 1
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_5
+mvi r1, 0
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_6
+mvi r1, -1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_7
+mvi r1, -1
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_8
+mvi r3, 0
+mvi r2, 1
+cmpge r3, r3, r2
+check_r3 0
+
+test_name CMPGE_9
+mvi r3, 1
+mvi r2, 0
+cmpge r3, r3, r2
+check_r3 1
+
+test_name CMPGE_10
+mvi r3, 0
+cmpge r3, r3, r3
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgei.S b/qemu-0.15.x/tests/lm32/test_cmpgei.S
new file mode 100644
index 0000000..6a8870f
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgei.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEI_1
+mvi r1, 0
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_2
+mvi r1, 0
+cmpgei r3, r1, 1
+check_r3 0
+
+test_name CMPGEI_3
+mvi r1, 1
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_4
+mvi r1, 1
+cmpgei r3, r1, 1
+check_r3 1
+
+test_name CMPGEI_5
+mvi r1, 0
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_6
+mvi r1, -1
+cmpgei r3, r1, 0
+check_r3 0
+
+test_name CMPGEI_7
+mvi r1, -1
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_8
+mvi r3, 0
+cmpgei r3, r3, 1
+check_r3 0
+
+test_name CMPGEI_9
+mvi r3, 1
+cmpgei r3, r3, 0
+check_r3 1
+
+test_name CMPGEI_10
+mvi r3, 0
+cmpgei r3, r3, 0
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgeu.S b/qemu-0.15.x/tests/lm32/test_cmpgeu.S
new file mode 100644
index 0000000..2110ccb
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgeu.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEU_1
+mvi r1, 0
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_2
+mvi r1, 0
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_3
+mvi r1, 1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_4
+mvi r1, 1
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_5
+mvi r1, 0
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_6
+mvi r1, -1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_7
+mvi r1, -1
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_8
+mvi r3, 0
+mvi r2, 1
+cmpgeu r3, r3, r2
+check_r3 0
+
+test_name CMPGEU_9
+mvi r3, 1
+mvi r2, 0
+cmpgeu r3, r3, r2
+check_r3 1
+
+test_name CMPGEU_10
+mvi r3, 0
+cmpgeu r3, r3, r3
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgeui.S b/qemu-0.15.x/tests/lm32/test_cmpgeui.S
new file mode 100644
index 0000000..b9d1755
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgeui.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEUI_1
+mvi r1, 0
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_2
+mvi r1, 0
+cmpgeui r3, r1, 1
+check_r3 0
+
+test_name CMPGEUI_3
+mvi r1, 1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_4
+mvi r1, 1
+cmpgeui r3, r1, 1
+check_r3 1
+
+test_name CMPGEUI_5
+mvi r1, 0
+cmpgeui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGEUI_6
+mvi r1, -1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_7
+mvi r1, -1
+cmpgeui r3, r1, 0xffff
+check_r3 1
+
+test_name CMPGEUI_8
+mvi r3, 0
+cmpgeui r3, r3, 1
+check_r3 0
+
+test_name CMPGEUI_9
+mvi r3, 1
+cmpgeui r3, r3, 0
+check_r3 1
+
+test_name CMPGEUI_10
+mvi r3, 0
+cmpgeui r3, r3, 0
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgi.S b/qemu-0.15.x/tests/lm32/test_cmpgi.S
new file mode 100644
index 0000000..1f622d2
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgi.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGI_1
+mvi r1, 0
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_2
+mvi r1, 0
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_3
+mvi r1, 1
+cmpgi r3, r1, 0
+check_r3 1
+
+test_name CMPGI_4
+mvi r1, 1
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_5
+mvi r1, 0
+cmpgi r3, r1, -1
+check_r3 1
+
+test_name CMPGI_6
+mvi r1, -1
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_7
+mvi r1, -1
+cmpgi r3, r1, -1
+check_r3 0
+
+test_name CMPGI_8
+mvi r3, 0
+cmpgi r3, r3, 1
+check_r3 0
+
+test_name CMPGI_9
+mvi r3, 1
+cmpgi r3, r3, 0
+check_r3 1
+
+test_name CMPGI_10
+mvi r3, 0
+cmpgi r3, r3, 0
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgu.S b/qemu-0.15.x/tests/lm32/test_cmpgu.S
new file mode 100644
index 0000000..dd46547
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgu.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGU_1
+mvi r1, 0
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_2
+mvi r1, 0
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_3
+mvi r1, 1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_4
+mvi r1, 1
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_5
+mvi r1, 0
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_6
+mvi r1, -1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_7
+mvi r1, -1
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_8
+mvi r3, 0
+mvi r2, 1
+cmpgu r3, r3, r2
+check_r3 0
+
+test_name CMPGU_9
+mvi r3, 1
+mvi r2, 0
+cmpgu r3, r3, r2
+check_r3 1
+
+test_name CMPGU_10
+mvi r3, 0
+cmpgu r3, r3, r3
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpgui.S b/qemu-0.15.x/tests/lm32/test_cmpgui.S
new file mode 100644
index 0000000..759bb64
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpgui.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGUI_1
+mvi r1, 0
+cmpgui r3, r1, 0
+check_r3 0
+
+test_name CMPGUI_2
+mvi r1, 0
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_3
+mvi r1, 1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_4
+mvi r1, 1
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_5
+mvi r1, 0
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_6
+mvi r1, -1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_7
+mvi r1, -1
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_8
+mvi r3, 0
+cmpgui r3, r3, 1
+check_r3 0
+
+test_name CMPGUI_9
+mvi r3, 1
+cmpgui r3, r3, 0
+check_r3 1
+
+test_name CMPGUI_10
+mvi r3, 0
+cmpgui r3, r3, 0
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpne.S b/qemu-0.15.x/tests/lm32/test_cmpne.S
new file mode 100644
index 0000000..0f10781
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpne.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNE_1
+mvi r1, 0
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 0
+
+test_name CMPNE_2
+mvi r1, 0
+mvi r2, 1
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_3
+mvi r1, 1
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_4
+mvi r3, 0
+mvi r2, 1
+cmpne r3, r3, r2
+check_r3 1
+
+test_name CMPNE_5
+mvi r3, 0
+mvi r2, 0
+cmpne r3, r3, r2
+check_r3 0
+
+test_name CMPNE_6
+mvi r3, 0
+cmpne r3, r3, r3
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_cmpnei.S b/qemu-0.15.x/tests/lm32/test_cmpnei.S
new file mode 100644
index 0000000..060dd9d
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_cmpnei.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNEI_1
+mvi r1, 0
+cmpnei r3, r1, 0
+check_r3 0
+
+test_name CMPNEI_2
+mvi r1, 0
+cmpnei r3, r1, 1
+check_r3 1
+
+test_name CMPNEI_3
+mvi r1, 1
+cmpnei r3, r1, 0
+check_r3 1
+
+test_name CMPNEI_4
+load r1 0xffffffff
+cmpnei r3, r1, -1
+check_r3 0
+
+test_name CMPNEI_5
+mvi r3, 0
+cmpnei r3, r3, 0
+check_r3 0
+
+test_name CMPNEI_6
+mvi r3, 0
+cmpnei r3, r3, 1
+check_r3 1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_divu.S b/qemu-0.15.x/tests/lm32/test_divu.S
new file mode 100644
index 0000000..f381d09
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_divu.S
@@ -0,0 +1,29 @@
+.include "macros.inc"
+
+start
+
+test_name DIVU_1
+mvi r1, 0
+mvi r2, 1
+divu r3, r1, r2
+check_r3 0
+
+test_name DIVU_2
+mvi r1, 1
+mvi r2, 1
+divu r3, r1, r2
+check_r3 1
+
+test_name DIVU_3
+mvi r1, 0
+mvi r2, 0
+divu r3, r1, r2
+check_excp 16
+
+test_name DIVU_4
+load r1 0xabcdef12
+load r2 0x12345
+divu r3, r1, r2
+check_r3 0x9700
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_eret.S b/qemu-0.15.x/tests/lm32/test_eret.S
new file mode 100644
index 0000000..6830bd1
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_eret.S
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name ERET_1
+mvi r1, 2
+wcsr IE, r1
+load ea mark
+eret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name ERET_2
+rcsr r3, IE
+check_r3 3
+
+test_name ERET_3
+mvi r1, 0
+wcsr IE, r1
+load ea mark2
+eret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name ERET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/qemu-0.15.x/tests/lm32/test_lb.S b/qemu-0.15.x/tests/lm32/test_lb.S
new file mode 100644
index 0000000..f84d21e
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_lb.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LB_1
+load r1 data
+lb r3, (r1+0)
+check_r3 0x7e
+
+test_name LB_2
+lb r3, (r1+1)
+check_r3 0x7f
+
+test_name LB_3
+lb r3, (r1+-1)
+check_r3 0x7d
+
+test_name LB_4
+load r1 data_msb
+lb r3, (r1+0)
+check_r3 0xfffffffe
+
+test_name LB_5
+lb r3, (r1+1)
+check_r3 0xffffffff
+
+test_name LB_6
+lb r3, (r1+-1)
+check_r3 0xfffffffd
+
+test_name LB_7
+load r3 data
+lb r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/qemu-0.15.x/tests/lm32/test_lbu.S b/qemu-0.15.x/tests/lm32/test_lbu.S
new file mode 100644
index 0000000..4c1786a
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_lbu.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LBU_1
+load r1 data
+lbu r3, (r1+0)
+check_r3 0x7e
+
+test_name LBU_2
+lbu r3, (r1+1)
+check_r3 0x7f
+
+test_name LBU_3
+lbu r3, (r1+-1)
+check_r3 0x7d
+
+test_name LBU_4
+load r1 data_msb
+lbu r3, (r1+0)
+check_r3 0xfe
+
+test_name LBU_5
+lbu r3, (r1+1)
+check_r3 0xff
+
+test_name LBU_6
+lbu r3, (r1+-1)
+check_r3 0xfd
+
+test_name LBU_7
+load r3 data
+lbu r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/qemu-0.15.x/tests/lm32/test_lh.S b/qemu-0.15.x/tests/lm32/test_lh.S
new file mode 100644
index 0000000..e57d9e3
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_lh.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LH_1
+load r1 data
+lh r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LH_2
+lh r3, (r1+2)
+check_r3 0x7071
+
+test_name LH_3
+lh r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LH_4
+load r1 data_msb
+lh r3, (r1+0)
+check_r3 0xfffffeff
+
+test_name LH_5
+lh r3, (r1+2)
+check_r3 0xfffff0f1
+
+test_name LH_6
+lh r3, (r1+-2)
+check_r3 0xfffffcfd
+
+test_name LH_7
+load r3 data
+lh r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/qemu-0.15.x/tests/lm32/test_lhu.S b/qemu-0.15.x/tests/lm32/test_lhu.S
new file mode 100644
index 0000000..e648775
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_lhu.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LHU_1
+load r1 data
+lhu r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LHU_2
+lhu r3, (r1+2)
+check_r3 0x7071
+
+test_name LHU_3
+lhu r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LHU_4
+load r1 data_msb
+lhu r3, (r1+0)
+check_r3 0xfeff
+
+test_name LHU_5
+lhu r3, (r1+2)
+check_r3 0xf0f1
+
+test_name LHU_6
+lhu r3, (r1+-2)
+check_r3 0xfcfd
+
+test_name LHU_7
+load r3 data
+lhu r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/qemu-0.15.x/tests/lm32/test_lw.S b/qemu-0.15.x/tests/lm32/test_lw.S
new file mode 100644
index 0000000..f8c919d
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_lw.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name LW_1
+load r1 data
+lw r3, (r1+0)
+check_r3 0x7e7f7071
+
+test_name LW_2
+lw r3, (r1+4)
+check_r3 0x72737475
+
+test_name LW_3
+lw r3, (r1+-4)
+check_r3 0x7a7b7c7d
+
+test_name LW_4
+load r3 data
+lw r3, (r3+0)
+check_r3 0x7e7f7071
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0x72, 0x73, 0x74, 0x75
diff --git a/qemu-0.15.x/tests/lm32/test_modu.S b/qemu-0.15.x/tests/lm32/test_modu.S
new file mode 100644
index 0000000..4248690
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_modu.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name MODU_1
+mvi r1, 0
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_2
+mvi r1, 1
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_3
+mvi r1, 3
+mvi r2, 2
+modu r3, r1, r2
+check_r3 1
+
+test_name MODU_4
+mvi r1, 0
+mvi r2, 0
+modu r3, r1, r2
+check_excp 16
+
+test_name MODU_5
+load r1 0xabcdef12
+load r2 0x12345
+modu r3, r1, r2
+check_r3 0x3c12
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_mul.S b/qemu-0.15.x/tests/lm32/test_mul.S
new file mode 100644
index 0000000..e9b937e
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_mul.S
@@ -0,0 +1,70 @@
+.include "macros.inc"
+
+start
+
+test_name MUL_1
+mvi r1, 0
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_2
+mvi r1, 1
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_3
+mvi r1, 0
+mvi r2, 1
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_4
+mvi r1, 1
+mvi r2, 1
+mul r3, r1, r2
+check_r3 1
+
+test_name MUL_5
+mvi r1, 2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 -2
+
+test_name MUL_6
+mvi r1, -2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 2
+
+test_name MUL_7
+mvi r1, 0x1234
+mvi r2, 0x789
+mul r3, r1, r2
+check_r3 0x8929d4
+
+test_name MUL_8
+mvi r3, 4
+mul r3, r3, r3
+check_r3 16
+
+test_name MUL_9
+mvi r2, 2
+mvi r3, 4
+mul r3, r3, r2
+check_r3 8
+
+test_name MUL_10
+load r1 0x12345678
+load r2 0x7bcdef12
+mul r3, r1, r2
+check_r3 0xa801c70
+
+test_name MUL_11
+load r1 0x12345678
+load r2 0xabcdef12
+mul r3, r1, r2
+check_r3 0x8a801c70
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_muli.S b/qemu-0.15.x/tests/lm32/test_muli.S
new file mode 100644
index 0000000..d6dd4a0
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_muli.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name MULI_1
+mvi r1, 0
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_2
+mvi r1, 1
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_3
+mvi r1, 0
+muli r3, r1, 1
+check_r3 0
+
+test_name MULI_4
+mvi r1, 1
+muli r3, r1, 1
+check_r3 1
+
+test_name MULI_5
+mvi r1, 2
+muli r3, r1, -1
+check_r3 -2
+
+test_name MULI_6
+mvi r1, -2
+muli r3, r1, -1
+check_r3 2
+
+test_name MULI_7
+mvi r1, 0x1234
+muli r3, r1, 0x789
+check_r3 0x8929d4
+
+test_name MULI_8
+mvi r3, 4
+muli r3, r3, 4
+check_r3 16
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_nor.S b/qemu-0.15.x/tests/lm32/test_nor.S
new file mode 100644
index 0000000..74d7592
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_nor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name NOR_1
+mvi r1, 0
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xffffffff
+
+test_name NOR_2
+mvi r1, 0
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_3
+mvi r1, 1
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_4
+mvi r1, 1
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+nor r3, r1, r2
+check_r3 0
+
+test_name NOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+nor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name NOR_7
+load r1 0xaa55aa55
+nor r3, r1, r1
+check_r3 0x55aa55aa
+
+test_name NOR_8
+load r3 0xaa55aa55
+nor r3, r3, r3
+check_r3 0x55aa55aa
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_nori.S b/qemu-0.15.x/tests/lm32/test_nori.S
new file mode 100644
index 0000000..d00309c
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_nori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name NORI_1
+mvi r1, 0
+nori r3, r1, 0
+check_r3 0xffffffff
+
+test_name NORI_2
+mvi r1, 0
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_3
+mvi r1, 1
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_4
+mvi r1, 1
+nori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name NORI_5
+load r1 0xaa55aa55
+nori r3, r1, 0x55aa
+check_r3 0x55aa0000
+
+test_name NORI_6
+load r3 0xaa55aa55
+nori r3, r3, 0x55aa
+check_r3 0x55aa0000
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_or.S b/qemu-0.15.x/tests/lm32/test_or.S
new file mode 100644
index 0000000..4ed2923
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_or.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name OR_1
+mvi r1, 0
+mvi r2, 0
+or r3, r1, r2
+check_r3 0
+
+test_name OR_2
+mvi r1, 0
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_3
+mvi r1, 1
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_4
+mvi r1, 1
+mvi r2, 0
+or r3, r1, r2
+check_r3 1
+
+test_name OR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+or r3, r1, r2
+check_r3 0xffffffff
+
+test_name OR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+or r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name OR_7
+load r1 0xaa55aa55
+or r3, r1, r1
+check_r3 0xaa55aa55
+
+test_name OR_8
+load r3 0xaa55aa55
+or r3, r3, r3
+check_r3 0xaa55aa55
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_orhi.S b/qemu-0.15.x/tests/lm32/test_orhi.S
new file mode 100644
index 0000000..78b7600
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_orhi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORHI_1
+mvi r1, 0
+orhi r3, r1, 0
+check_r3 0
+
+test_name ORHI_2
+mvi r1, 0
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_3
+load r1 0x00010000
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_4
+mvi r1, 1
+orhi r3, r1, 0
+check_r3 1
+
+test_name ORHI_5
+load r1 0xaa55aa55
+orhi r3, r1, 0x55aa
+check_r3 0xffffaa55
+
+test_name ORHI_6
+load r3 0xaa55aa55
+orhi r3, r3, 0x55aa
+check_r3 0xffffaa55
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_ori.S b/qemu-0.15.x/tests/lm32/test_ori.S
new file mode 100644
index 0000000..3d576cd
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_ori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORI_1
+mvi r1, 0
+ori r3, r1, 0
+check_r3 0
+
+test_name ORI_2
+mvi r1, 0
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_3
+mvi r1, 1
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_4
+mvi r1, 1
+ori r3, r1, 0
+check_r3 1
+
+test_name ORI_5
+load r1 0xaa55aa55
+ori r3, r1, 0x55aa
+check_r3 0xaa55ffff
+
+test_name ORI_6
+load r3 0xaa55aa55
+ori r3, r3, 0x55aa
+check_r3 0xaa55ffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_ret.S b/qemu-0.15.x/tests/lm32/test_ret.S
new file mode 100644
index 0000000..320264f
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_ret.S
@@ -0,0 +1,14 @@
+.include "macros.inc"
+
+start
+
+test_name RET_1
+load ra mark
+ret
+
+tc_fail
+end
+
+mark:
+tc_pass
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sb.S b/qemu-0.15.x/tests/lm32/test_sb.S
new file mode 100644
index 0000000..89e39d6
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sb.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SB_1
+load r1 data
+load r2 0xf0f1f2aa
+sb (r1+0), r2
+check_mem data 0xaa000000
+
+test_name SB_2
+load r2 0xf0f1f2bb
+sb (r1+1), r2
+check_mem data 0xaabb0000
+
+test_name SB_3
+load r2 0xf0f1f2cc
+sb (r1+-1), r2
+check_mem data0 0x000000cc
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/qemu-0.15.x/tests/lm32/test_scall.S b/qemu-0.15.x/tests/lm32/test_scall.S
new file mode 100644
index 0000000..b442e32
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_scall.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SCALL_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+scall
+check_excp 64
+
+test_name SCALL_2
+mv r3, ea
+check_r3 insn
+
+test_name SCALL_3
+rcsr r3, IE
+check_r3 2
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sextb.S b/qemu-0.15.x/tests/lm32/test_sextb.S
new file mode 100644
index 0000000..58db8ee
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sextb.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTB_1
+mvi r1, 0
+sextb r3, r1
+check_r3 0
+
+test_name SEXTB_2
+mvi r1, 0x7f
+sextb r3, r1
+check_r3 0x0000007f
+
+test_name SEXTB_3
+mvi r1, 0x80
+sextb r3, r1
+check_r3 0xffffff80
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sexth.S b/qemu-0.15.x/tests/lm32/test_sexth.S
new file mode 100644
index 0000000..a059ec3
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sexth.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTH_1
+mvi r1, 0
+sexth r3, r1
+check_r3 0
+
+test_name SEXTH_2
+load r1 0x7fff
+sexth r3, r1
+check_r3 0x00007fff
+
+test_name SEXTH_3
+load r1 0x8000
+sexth r3, r1
+check_r3 0xffff8000
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sh.S b/qemu-0.15.x/tests/lm32/test_sh.S
new file mode 100644
index 0000000..ea8b3f2
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sh.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SH_1
+load r1 data
+load r2 0xf0f1aaaa
+sh (r1+0), r2
+check_mem data 0xaaaa0000
+
+test_name SH_2
+load r2 0xf0f1bbbb
+sh (r1+2), r2
+check_mem data 0xaaaabbbb
+
+test_name SH_3
+load r2 0xf0f1cccc
+sh (r1+-2), r2
+check_mem data0 0x0000cccc
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/qemu-0.15.x/tests/lm32/test_sl.S b/qemu-0.15.x/tests/lm32/test_sl.S
new file mode 100644
index 0000000..0aee17f
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sl.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name SL_1
+mvi r1, 1
+mvi r2, 0
+sl r3, r1, r2
+check_r3 1
+
+test_name SL_2
+mvi r1, 0
+mvi r2, 1
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_3
+mvi r1, 1
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0x80000000
+
+test_name SL_4
+mvi r1, 16
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_5
+mvi r1, 1
+mvi r2, 34
+sl r3, r1, r2
+check_r3 4
+
+test_name SL_6
+mvi r1, 2
+sl r3, r1, r1
+check_r3 8
+
+test_name SL_7
+mvi r3, 2
+sl r3, r3, r3
+check_r3 8
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sli.S b/qemu-0.15.x/tests/lm32/test_sli.S
new file mode 100644
index 0000000..a421de9
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sli.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SLI_1
+mvi r1, 1
+sli r3, r1, 0
+check_r3 1
+
+test_name SLI_2
+mvi r1, 0
+sli r3, r1, 1
+check_r3 0
+
+test_name SLI_3
+mvi r1, 1
+sli r3, r1, 31
+check_r3 0x80000000
+
+test_name SLI_4
+mvi r1, 16
+sli r3, r1, 31
+check_r3 0
+
+test_name SLI_7
+mvi r3, 2
+sli r3, r3, 2
+check_r3 8
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sr.S b/qemu-0.15.x/tests/lm32/test_sr.S
new file mode 100644
index 0000000..62431a9
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sr.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SR_1
+mvi r1, 1
+mvi r2, 0
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_2
+mvi r1, 0
+mvi r2, 1
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_3
+load r1 0x40000000
+mvi r2, 30
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_4
+load r1 0x40000000
+mvi r2, 31
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_5
+mvi r1, 16
+mvi r2, 34
+sr r3, r1, r2
+check_r3 4
+
+test_name SR_6
+mvi r1, 2
+sr r3, r1, r1
+check_r3 0
+
+test_name SR_7
+mvi r3, 2
+sr r3, r3, r3
+check_r3 0
+
+test_name SR_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sr r3, r1, r2
+check_r3 0xfffffffc
+
+test_name SR_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sr r3, r1, r2
+check_r3 0xffffffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sri.S b/qemu-0.15.x/tests/lm32/test_sri.S
new file mode 100644
index 0000000..c1be907
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sri.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRI_1
+mvi r1, 1
+sri r3, r1, 0
+check_r3 1
+
+test_name SRI_2
+mvi r1, 0
+sri r3, r1, 1
+check_r3 0
+
+test_name SRI_3
+load r1 0x40000000
+sri r3, r1, 30
+check_r3 1
+
+test_name SRI_4
+load r1 0x40000000
+sri r3, r1, 31
+check_r3 0
+
+test_name SRI_5
+mvi r3, 2
+sri r3, r3, 2
+check_r3 0
+
+test_name SRI_6
+mvi r1, 0xfffffff0
+sri r3, r1, 2
+check_r3 0xfffffffc
+
+test_name SRI_7
+mvi r1, 0xfffffff0
+sri r3, r1, 4
+check_r3 0xffffffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sru.S b/qemu-0.15.x/tests/lm32/test_sru.S
new file mode 100644
index 0000000..2ab0b54
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sru.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SRU_1
+mvi r1, 1
+mvi r2, 0
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_2
+mvi r1, 0
+mvi r2, 1
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_3
+load r1 0x40000000
+mvi r2, 30
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_4
+load r1 0x40000000
+mvi r2, 31
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_5
+mvi r1, 16
+mvi r2, 34
+sru r3, r1, r2
+check_r3 4
+
+test_name SRU_6
+mvi r1, 2
+sru r3, r1, r1
+check_r3 0
+
+test_name SRU_7
+mvi r3, 2
+sru r3, r3, r3
+check_r3 0
+
+test_name SRU_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sru r3, r1, r2
+check_r3 0x3ffffffc
+
+test_name SRU_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sru r3, r1, r2
+check_r3 0x0fffffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_srui.S b/qemu-0.15.x/tests/lm32/test_srui.S
new file mode 100644
index 0000000..872c374
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_srui.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRUI_1
+mvi r1, 1
+srui r3, r1, 0
+check_r3 1
+
+test_name SRUI_2
+mvi r1, 0
+srui r3, r1, 1
+check_r3 0
+
+test_name SRUI_3
+load r1 0x40000000
+srui r3, r1, 30
+check_r3 1
+
+test_name SRUI_4
+load r1 0x40000000
+srui r3, r1, 31
+check_r3 0
+
+test_name SRUI_5
+mvi r3, 2
+srui r3, r3, 2
+check_r3 0
+
+test_name SRUI_6
+mvi r1, 0xfffffff0
+srui r3, r1, 2
+check_r3 0x3ffffffc
+
+test_name SRUI_7
+mvi r1, 0xfffffff0
+srui r3, r1, 4
+check_r3 0x0fffffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sub.S b/qemu-0.15.x/tests/lm32/test_sub.S
new file mode 100644
index 0000000..44b74a9
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sub.S
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name SUB_1
+mvi r1, 0
+mvi r2, 0
+sub r3, r1, r2
+check_r3 0
+
+test_name SUB_2
+mvi r1, 0
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_3
+mvi r1, 1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_4
+mvi r1, 1
+mvi r2, -1
+sub r3, r1, r2
+check_r3 2
+
+test_name SUB_5
+mvi r1, -1
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -2
+
+test_name SUB_6
+mvi r1, -1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_7
+mvi r1, 0
+mvi r2, -1
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_8
+mvi r3, 2
+sub r3, r3, r3
+check_r3 0
+
+test_name SUB_9
+mvi r1, 4
+mvi r3, 2
+sub r3, r1, r3
+check_r3 2
+
+test_name SUB_10
+mvi r1, 4
+mvi r3, 2
+sub r3, r3, r1
+check_r3 -2
+
+test_name SUB_11
+mvi r1, 4
+sub r3, r1, r1
+check_r3 0
+
+test_name SUB_12
+load r1 0x12345678
+load r2 0xabcdef97
+sub r3, r1, r2
+check_r3 0x666666e1
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_sw.S b/qemu-0.15.x/tests/lm32/test_sw.S
new file mode 100644
index 0000000..d1fdadc
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_sw.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name SW_1
+load r1 data
+load r2 0xaabbccdd
+sw (r1+0), r2
+check_mem data 0xaabbccdd
+
+test_name SW_2
+load r2 0x00112233
+sw (r1+4), r2
+check_mem data1 0x00112233
+
+test_name SW_3
+load r2 0x44556677
+sw (r1+-4), r2
+check_mem data0 0x44556677
+
+test_name SW_4
+sw (r1+0), r1
+lw r3, (r1+0)
+check_r3 data
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/qemu-0.15.x/tests/lm32/test_xnor.S b/qemu-0.15.x/tests/lm32/test_xnor.S
new file mode 100644
index 0000000..14a6207
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_xnor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XNOR_1
+mvi r1, 0
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_2
+mvi r1, 0
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_3
+mvi r1, 1
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_4
+mvi r1, 1
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xnor r3, r1, r2
+check_r3 0
+
+test_name XNOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xnor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name XNOR_7
+load r1 0xaa55aa55
+xnor r3, r1, r1
+check_r3 0xffffffff
+
+test_name XNOR_8
+load r3 0xaa55aa55
+xnor r3, r3, r3
+check_r3 0xffffffff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_xnori.S b/qemu-0.15.x/tests/lm32/test_xnori.S
new file mode 100644
index 0000000..9d9c3c6
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_xnori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XNORI_1
+mvi r1, 0
+xnori r3, r1, 0
+check_r3 0xffffffff
+
+test_name XNORI_2
+mvi r1, 0
+xnori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name XNORI_3
+mvi r1, 1
+xnori r3, r1, 1
+check_r3 0xffffffff
+
+test_name XNORI_4
+mvi r1, 1
+xnori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name XNORI_5
+load r1 0xaa55aa55
+xnori r3, r1, 0x5555
+check_r3 0x55aa00ff
+
+test_name XNORI_6
+load r3 0xaa55aa55
+xnori r3, r3, 0x5555
+check_r3 0x55aa00ff
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_xor.S b/qemu-0.15.x/tests/lm32/test_xor.S
new file mode 100644
index 0000000..6c6e712
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_xor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XOR_1
+mvi r1, 0
+mvi r2, 0
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_2
+mvi r1, 0
+mvi r2, 1
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_3
+mvi r1, 1
+mvi r2, 1
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_4
+mvi r1, 1
+mvi r2, 0
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xor r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name XOR_7
+load r1 0xaa55aa55
+xor r3, r1, r1
+check_r3 0
+
+test_name XOR_8
+load r3 0xaa55aa55
+xor r3, r3, r3
+check_r3 0
+
+end
diff --git a/qemu-0.15.x/tests/lm32/test_xori.S b/qemu-0.15.x/tests/lm32/test_xori.S
new file mode 100644
index 0000000..2051699
--- /dev/null
+++ b/qemu-0.15.x/tests/lm32/test_xori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XORI_1
+mvi r1, 0
+xori r3, r1, 0
+check_r3 0
+
+test_name XORI_2
+mvi r1, 0
+xori r3, r1, 1
+check_r3 1
+
+test_name XORI_3
+mvi r1, 1
+xori r3, r1, 1
+check_r3 0
+
+test_name XORI_4
+mvi r1, 1
+xori r3, r1, 0
+check_r3 1
+
+test_name XORI_5
+load r1 0xaa55aa55
+xori r3, r1, 0x5555
+check_r3 0xaa55ff00
+
+test_name XORI_6
+load r3 0xaa55aa55
+xori r3, r3, 0x5555
+check_r3 0xaa55ff00
+
+end
diff --git a/qemu-0.15.x/tests/pi_10.com b/qemu-0.15.x/tests/pi_10.com
new file mode 100644
index 0000000..8993ba1
Binary files /dev/null and b/qemu-0.15.x/tests/pi_10.com differ
diff --git a/qemu-0.15.x/tests/qruncom.c b/qemu-0.15.x/tests/qruncom.c
new file mode 100644
index 0000000..079f7a2
--- /dev/null
+++ b/qemu-0.15.x/tests/qruncom.c
@@ -0,0 +1,284 @@
+/*
+ * Example of use of user mode libqemu: launch a basic .com DOS
+ * executable
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <malloc.h>
+
+#include "cpu.h"
+
+//#define SIGTEST
+
+int cpu_get_pic_interrupt(CPUState *env)
+{
+    return -1;
+}
+
+uint64_t cpu_get_tsc(CPUState *env)
+{
+    return 0;
+}
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+                     unsigned long addr, unsigned int sel)
+{
+    unsigned int e1, e2;
+    e1 = (addr & 0xffff) | (sel << 16);
+    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+    stl((uint8_t *)ptr, e1);
+    stl((uint8_t *)ptr + 4, e2);
+}
+
+uint64_t idt_table[256];
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+    set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+void qemu_free(void *ptr)
+{
+    free(ptr);
+}
+
+void *qemu_malloc(size_t size)
+{
+    return malloc(size);
+}
+
+void *qemu_mallocz(size_t size)
+{
+    void *ptr;
+    ptr = qemu_malloc(size);
+    if (!ptr)
+        return NULL;
+    memset(ptr, 0, size);
+    return ptr;
+}
+
+void *qemu_vmalloc(size_t size)
+{
+    return memalign(4096, size);
+}
+
+void qemu_vfree(void *ptr)
+{
+    free(ptr);
+}
+
+void qemu_printf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+}
+
+/* XXX: this is a bug in helper2.c */
+int errno;
+
+/**********************************************/
+
+#define COM_BASE_ADDR    0x10100
+
+static void usage(void)
+{
+    printf("qruncom version 0.1 (c) 2003 Fabrice Bellard\n"
+           "usage: qruncom file.com\n"
+           "user mode libqemu demo: run simple .com DOS executables\n");
+    exit(1);
+}
+
+static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
+{
+    return (uint8_t *)((seg << 4) + (reg & 0xffff));
+}
+
+static inline void pushw(CPUState *env, int val)
+{
+    env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | ((env->regs[R_ESP] - 2) & 0xffff);
+    *(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val;
+}
+
+static void host_segv_handler(int host_signum, siginfo_t *info,
+                              void *puc)
+{
+    if (cpu_signal_handler(host_signum, info, puc)) {
+        return;
+    }
+    abort();
+}
+
+int main(int argc, char **argv)
+{
+    uint8_t *vm86_mem;
+    const char *filename;
+    int fd, ret, seg;
+    CPUState *env;
+
+    if (argc != 2)
+        usage();
+    filename = argv[1];
+
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
+                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (vm86_mem == MAP_FAILED) {
+        perror("mmap");
+        exit(1);
+    }
+
+    /* load the MSDOS .com executable */
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        perror(filename);
+        exit(1);
+    }
+    ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
+    if (ret < 0) {
+        perror("read");
+        exit(1);
+    }
+    close(fd);
+
+    /* install exception handler for CPU emulator */
+    {
+        struct sigaction act;
+
+        sigfillset(&act.sa_mask);
+        act.sa_flags = SA_SIGINFO;
+        //        act.sa_flags |= SA_ONSTACK;
+
+        act.sa_sigaction = host_segv_handler;
+        sigaction(SIGSEGV, &act, NULL);
+        sigaction(SIGBUS, &act, NULL);
+    }
+
+    //    cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC);
+
+    env = cpu_init("qemu32");
+
+    cpu_x86_set_cpl(env, 3);
+
+    env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+    /* NOTE: hflags duplicates some of the virtual CPU state */
+    env->hflags |= HF_PE_MASK | VM_MASK;
+
+    /* flags setup : we activate the IRQs by default as in user
+       mode. We also activate the VM86 flag to run DOS code */
+    env->eflags |= IF_MASK | VM_MASK;
+
+    /* init basic registers */
+    env->eip = 0x100;
+    env->regs[R_ESP] = 0xfffe;
+    seg = (COM_BASE_ADDR - 0x100) >> 4;
+
+    cpu_x86_load_seg_cache(env, R_CS, seg,
+                           (seg << 4), 0xffff, 0);
+    cpu_x86_load_seg_cache(env, R_SS, seg,
+                           (seg << 4), 0xffff, 0);
+    cpu_x86_load_seg_cache(env, R_DS, seg,
+                           (seg << 4), 0xffff, 0);
+    cpu_x86_load_seg_cache(env, R_ES, seg,
+                           (seg << 4), 0xffff, 0);
+    cpu_x86_load_seg_cache(env, R_FS, seg,
+                           (seg << 4), 0xffff, 0);
+    cpu_x86_load_seg_cache(env, R_GS, seg,
+                           (seg << 4), 0xffff, 0);
+
+    /* exception support */
+    env->idt.base = (unsigned long)idt_table;
+    env->idt.limit = sizeof(idt_table) - 1;
+    set_idt(0, 0);
+    set_idt(1, 0);
+    set_idt(2, 0);
+    set_idt(3, 3);
+    set_idt(4, 3);
+    set_idt(5, 3);
+    set_idt(6, 0);
+    set_idt(7, 0);
+    set_idt(8, 0);
+    set_idt(9, 0);
+    set_idt(10, 0);
+    set_idt(11, 0);
+    set_idt(12, 0);
+    set_idt(13, 0);
+    set_idt(14, 0);
+    set_idt(15, 0);
+    set_idt(16, 0);
+    set_idt(17, 0);
+    set_idt(18, 0);
+    set_idt(19, 0);
+
+    /* put return code */
+    *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */
+    *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00;
+    *seg_to_linear(env->segs[R_CS].selector, 2) = 0xcd; /* int $0x21 */
+    *seg_to_linear(env->segs[R_CS].selector, 3) = 0x21;
+    pushw(env, 0x0000);
+
+    /* the value of these registers seem to be assumed by pi_10.com */
+    env->regs[R_ESI] = 0x100;
+    env->regs[R_ECX] = 0xff;
+    env->regs[R_EBP] = 0x0900;
+    env->regs[R_EDI] = 0xfffe;
+
+    /* inform the emulator of the mmaped memory */
+    page_set_flags(0x00000000, 0x110000,
+                   PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);
+
+    for(;;) {
+        ret = cpu_x86_exec(env);
+        switch(ret) {
+        case EXCP0D_GPF:
+            {
+                int int_num, ah;
+                int_num = *(uint8_t *)(env->segs[R_CS].base + env->eip + 1);
+                if (int_num != 0x21)
+                    goto unknown_int;
+                ah = (env->regs[R_EAX] >> 8) & 0xff;
+                switch(ah) {
+                case 0x00: /* exit */
+                    exit(0);
+                case 0x02: /* write char */
+                    {
+                        uint8_t c = env->regs[R_EDX];
+                        write(1, &c, 1);
+                    }
+                    break;
+                case 0x09: /* write string */
+                    {
+                        uint8_t c;
+                        for(;;) {
+                            c = *seg_to_linear(env->segs[R_DS].selector, env->regs[R_EAX]);
+                            if (c == '$')
+                                break;
+                            write(1, &c, 1);
+                        }
+                        env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | '$';
+                    }
+                    break;
+                default:
+                unknown_int:
+                    fprintf(stderr, "unsupported int 0x%02x\n", int_num);
+                    cpu_dump_state(env, stderr, fprintf, 0);
+                    //                    exit(1);
+                }
+                env->eip += 2;
+            }
+            break;
+        default:
+            fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit(1);
+        }
+    }
+}
diff --git a/qemu-0.15.x/tests/runcom.c b/qemu-0.15.x/tests/runcom.c
new file mode 100644
index 0000000..d60342b
--- /dev/null
+++ b/qemu-0.15.x/tests/runcom.c
@@ -0,0 +1,192 @@
+/*
+ * Simple example of use of vm86: launch a basic .com DOS executable
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <signal.h>
+
+#include <linux/unistd.h>
+#include <asm/vm86.h>
+
+extern int vm86 (unsigned long int subfunction,
+		 struct vm86plus_struct *info);
+
+#define VIF_MASK                0x00080000
+
+//#define SIGTEST
+
+#define COM_BASE_ADDR    0x10100
+
+static void usage(void)
+{
+    printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n"
+           "usage: runcom file.com\n"
+           "VM86 Run simple .com DOS executables (linux vm86 test mode)\n");
+    exit(1);
+}
+
+static inline void set_bit(uint8_t *a, unsigned int bit)
+{
+    a[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
+{
+    return (uint8_t *)((seg << 4) + (reg & 0xffff));
+}
+
+static inline void pushw(struct vm86_regs *r, int val)
+{
+    r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
+    *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
+}
+
+void dump_regs(struct vm86_regs *r)
+{
+    fprintf(stderr,
+            "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
+            "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
+            "EIP=%08lx EFL=%08lx\n"
+            "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n",
+            r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
+            r->eip, r->eflags,
+            r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
+}
+
+#ifdef SIGTEST
+void alarm_handler(int sig)
+{
+    fprintf(stderr, "alarm signal=%d\n", sig);
+    alarm(1);
+}
+#endif
+
+int main(int argc, char **argv)
+{
+    uint8_t *vm86_mem;
+    const char *filename;
+    int fd, ret, seg;
+    struct vm86plus_struct ctx;
+    struct vm86_regs *r;
+
+    if (argc != 2)
+        usage();
+    filename = argv[1];
+
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
+                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (vm86_mem == MAP_FAILED) {
+        perror("mmap");
+        exit(1);
+    }
+#ifdef SIGTEST
+    {
+        struct sigaction act;
+
+        act.sa_handler = alarm_handler;
+        sigemptyset(&act.sa_mask);
+        act.sa_flags = 0;
+        sigaction(SIGALRM, &act, NULL);
+        alarm(1);
+    }
+#endif
+
+    /* load the MSDOS .com executable */
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        perror(filename);
+        exit(1);
+    }
+    ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
+    if (ret < 0) {
+        perror("read");
+        exit(1);
+    }
+    close(fd);
+
+    memset(&ctx, 0, sizeof(ctx));
+    /* init basic registers */
+    r = &ctx.regs;
+    r->eip = 0x100;
+    r->esp = 0xfffe;
+    seg = (COM_BASE_ADDR - 0x100) >> 4;
+    r->cs = seg;
+    r->ss = seg;
+    r->ds = seg;
+    r->es = seg;
+    r->fs = seg;
+    r->gs = seg;
+    r->eflags = VIF_MASK;
+
+    /* put return code */
+    set_bit((uint8_t *)&ctx.int_revectored, 0x21);
+    *seg_to_linear(r->cs, 0) = 0xb4; /* mov ah, $0 */
+    *seg_to_linear(r->cs, 1) = 0x00;
+    *seg_to_linear(r->cs, 2) = 0xcd; /* int $0x21 */
+    *seg_to_linear(r->cs, 3) = 0x21;
+    pushw(&ctx.regs, 0x0000);
+
+    /* the value of these registers seem to be assumed by pi_10.com */
+    r->esi = 0x100;
+    r->ecx = 0xff;
+    r->ebp = 0x0900;
+    r->edi = 0xfffe;
+
+    for(;;) {
+        ret = vm86(VM86_ENTER, &ctx);
+        switch(VM86_TYPE(ret)) {
+        case VM86_INTx:
+            {
+                int int_num, ah;
+
+                int_num = VM86_ARG(ret);
+                if (int_num != 0x21)
+                    goto unknown_int;
+                ah = (r->eax >> 8) & 0xff;
+                switch(ah) {
+                case 0x00: /* exit */
+                    exit(0);
+                case 0x02: /* write char */
+                    {
+                        uint8_t c = r->edx;
+                        write(1, &c, 1);
+                    }
+                    break;
+                case 0x09: /* write string */
+                    {
+                        uint8_t c;
+                        for(;;) {
+                            c = *seg_to_linear(r->ds, r->edx);
+                            if (c == '$')
+                                break;
+                            write(1, &c, 1);
+                        }
+                        r->eax = (r->eax & ~0xff) | '$';
+                    }
+                    break;
+                default:
+                unknown_int:
+                    fprintf(stderr, "unsupported int 0x%02x\n", int_num);
+                    dump_regs(&ctx.regs);
+                    //                    exit(1);
+                }
+            }
+            break;
+        case VM86_SIGNAL:
+            /* a signal came, we just ignore that */
+            break;
+        case VM86_STI:
+            break;
+        default:
+            fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
+            dump_regs(&ctx.regs);
+            exit(1);
+        }
+    }
+}
diff --git a/qemu-0.15.x/tests/sha1.c b/qemu-0.15.x/tests/sha1.c
new file mode 100644
index 0000000..93b7c8e
--- /dev/null
+++ b/qemu-0.15.x/tests/sha1.c
@@ -0,0 +1,240 @@
+
+/* from valgrind tests */
+
+/* ================ sha1.c ================ */
+/*
+SHA-1 in C
+By Steve Reid <steve at edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+/* ================ sha1.h ================ */
+/*
+SHA-1 in C
+By Steve Reid <steve at edmweb.com>
+100% Public Domain
+*/
+
+typedef struct {
+    uint32_t state[5];
+    uint32_t count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+/* ================ end of sha1.h ================ */
+#include <endian.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+uint32_t a, b, c, d, e;
+typedef union {
+    unsigned char c[64];
+    uint32_t l[16];
+} CHAR64LONG16;
+#ifdef SHA1HANDSOFF
+CHAR64LONG16 block[1];  /* use array to appear as a pointer */
+    memcpy(block, buffer, 64);
+#else
+    /* The following had better never be used because it causes the
+     * pointer-to-const buffer to be cast into a pointer to non-const.
+     * And the result is written through.  I threw a "const" in, hoping
+     * this will cause a diagnostic.
+     */
+CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+    memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
+{
+uint32_t i;
+uint32_t j;
+
+    j = context->count[0];
+    if ((context->count[0] += len << 3) < j)
+	context->count[1]++;
+    context->count[1] += (len>>29);
+    j = (j >> 3) & 63;
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned i;
+unsigned char finalcount[8];
+unsigned char c;
+
+#if 0	/* untested "improvement" by DHR */
+    /* Convert context->count to a sequence of bytes
+     * in finalcount.  Second element first, but
+     * big-endian order within element.
+     * But we do it all backwards.
+     */
+    unsigned char *fcp = &finalcount[8];
+
+    for (i = 0; i < 2; i++)
+    {
+	uint32_t t = context->count[i];
+	int j;
+
+	for (j = 0; j < 4; t >>= 8, j++)
+	    *--fcp = (unsigned char) t;
+    }
+#else
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+#endif
+    c = 0200;
+    SHA1Update(context, &c, 1);
+    while ((context->count[0] & 504) != 448) {
+	c = 0000;
+        SHA1Update(context, &c, 1);
+    }
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+    for (i = 0; i < 20; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    memset(context, '\0', sizeof(*context));
+    memset(&finalcount, '\0', sizeof(finalcount));
+}
+/* ================ end of sha1.c ================ */
+
+#define BUFSIZE 4096
+
+int
+main(int argc, char **argv)
+{
+    SHA1_CTX ctx;
+    unsigned char hash[20], buf[BUFSIZE];
+    int i;
+
+    for(i=0;i<BUFSIZE;i++)
+        buf[i] = i;
+
+    SHA1Init(&ctx);
+    for(i=0;i<1000;i++)
+        SHA1Update(&ctx, buf, BUFSIZE);
+    SHA1Final(hash, &ctx);
+
+    printf("SHA1=");
+    for(i=0;i<20;i++)
+        printf("%02x", hash[i]);
+    printf("\n");
+    return 0;
+}
diff --git a/qemu-0.15.x/tests/test-arm-iwmmxt.s b/qemu-0.15.x/tests/test-arm-iwmmxt.s
new file mode 100644
index 0000000..d647f94
--- /dev/null
+++ b/qemu-0.15.x/tests/test-arm-iwmmxt.s
@@ -0,0 +1,49 @@
+@ Checks whether iwMMXt is functional.
+.code	32
+.globl	main
+
+main:
+ldr	r0, =data0
+ldr	r1, =data1
+ldr	r2, =data2
+#ifndef FPA
+wldrd	wr0, [r0, #0]
+wldrd	wr1, [r0, #8]
+wldrd	wr2, [r1, #0]
+wldrd	wr3, [r1, #8]
+wsubb	wr2, wr2, wr0
+wsubb	wr3, wr3, wr1
+wldrd	wr0, [r2, #0]
+wldrd	wr1, [r2, #8]
+waddb	wr0, wr0, wr2
+waddb	wr1, wr1, wr3
+wstrd	wr0, [r2, #0]
+wstrd	wr1, [r2, #8]
+#else
+ldfe	f0, [r0, #0]
+ldfe	f1, [r0, #8]
+ldfe	f2, [r1, #0]
+ldfe	f3, [r1, #8]
+adfdp	f2, f2, f0
+adfdp	f3, f3, f1
+ldfe	f0, [r2, #0]
+ldfe	f1, [r2, #8]
+adfd	f0, f0, f2
+adfd	f1, f1, f3
+stfe	f0, [r2, #0]
+stfe	f1, [r2, #8]
+#endif
+mov	r0, #1
+mov	r1, r2
+mov	r2, #0x11
+swi	#0x900004
+mov	r0, #0
+swi	#0x900001
+
+.data
+data0:
+.string	"aaaabbbbccccdddd"
+data1:
+.string	"bbbbccccddddeeee"
+data2:
+.string	"hvLLWs\x1fsdrs9\x1fNJ-\n"
diff --git a/qemu-0.15.x/tests/test-i386-code16.S b/qemu-0.15.x/tests/test-i386-code16.S
new file mode 100644
index 0000000..816c24b
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386-code16.S
@@ -0,0 +1,79 @@
+        .code16
+        .globl code16_start
+        .globl code16_end
+
+CS_SEG = 0xf
+
+code16_start:
+
+        .globl code16_func1
+
+        /* basic test */
+code16_func1 = . - code16_start
+        mov $1, %eax
+        data32 lret
+
+/* test push/pop in 16 bit mode */
+        .globl code16_func2
+code16_func2 = . - code16_start
+        xor %eax, %eax
+        mov $0x12345678, %ebx
+        movl %esp, %ecx
+        push %bx
+        subl %esp, %ecx
+        pop %ax
+        data32 lret
+
+/* test various jmp opcodes */
+        .globl code16_func3
+code16_func3 = . - code16_start
+        jmp 1f
+        nop
+1:
+        mov $4, %eax
+        mov $0x12345678, %ebx
+        xor %bx, %bx
+        jz 2f
+        add $2, %ax
+2:
+
+        call myfunc
+
+        lcall $CS_SEG, $(myfunc2 - code16_start)
+
+        ljmp $CS_SEG, $(myjmp1 - code16_start)
+myjmp1_next:
+
+        cs lcall *myfunc2_addr - code16_start
+
+        cs ljmp *myjmp2_addr - code16_start
+myjmp2_next:
+
+        data32 lret
+
+myfunc2_addr:
+        .short myfunc2 - code16_start
+        .short CS_SEG
+
+myjmp2_addr:
+        .short myjmp2 - code16_start
+        .short CS_SEG
+
+myjmp1:
+        add $8, %ax
+        jmp myjmp1_next
+
+myjmp2:
+        add $16, %ax
+        jmp myjmp2_next
+
+myfunc:
+        add $1, %ax
+        ret
+
+myfunc2:
+        add $4, %ax
+        lret
+
+
+code16_end:
diff --git a/qemu-0.15.x/tests/test-i386-muldiv.h b/qemu-0.15.x/tests/test-i386-muldiv.h
new file mode 100644
index 0000000..015f59e
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386-muldiv.h
@@ -0,0 +1,76 @@
+
+void glue(glue(test_, OP), b)(long op0, long op1)
+{
+    long res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm ("push %4\n\t"
+         "popf\n\t"
+         stringify(OP)"b %b2\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=a" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
+           stringify(OP) "b", s0, s1, res, flags & CC_MASK);
+}
+
+void glue(glue(test_, OP), w)(long op0h, long op0, long op1)
+{
+    long res, s1, flags, resh;
+    s1 = op1;
+    resh = op0h;
+    res = op0;
+    flags = 0;
+    asm ("push %5\n\t"
+         "popf\n\t"
+         stringify(OP) "w %w3\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=a" (res), "=g" (flags), "=d" (resh)
+         : "q" (s1), "0" (res), "1" (flags), "2" (resh));
+    printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n",
+           stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK);
+}
+
+void glue(glue(test_, OP), l)(long op0h, long op0, long op1)
+{
+    long res, s1, flags, resh;
+    s1 = op1;
+    resh = op0h;
+    res = op0;
+    flags = 0;
+    asm ("push %5\n\t"
+         "popf\n\t"
+         stringify(OP) "l %k3\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=a" (res), "=g" (flags), "=d" (resh)
+         : "q" (s1), "0" (res), "1" (flags), "2" (resh));
+    printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n",
+           stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK);
+}
+
+#if defined(__x86_64__)
+void glue(glue(test_, OP), q)(long op0h, long op0, long op1)
+{
+    long res, s1, flags, resh;
+    s1 = op1;
+    resh = op0h;
+    res = op0;
+    flags = 0;
+    asm ("push %5\n\t"
+         "popf\n\t"
+         stringify(OP) "q %3\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=a" (res), "=g" (flags), "=d" (resh)
+         : "q" (s1), "0" (res), "1" (flags), "2" (resh));
+    printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n",
+           stringify(OP) "q", op0h, op0, s1, resh, res, flags & CC_MASK);
+}
+#endif
+
+#undef OP
diff --git a/qemu-0.15.x/tests/test-i386-shift.h b/qemu-0.15.x/tests/test-i386-shift.h
new file mode 100644
index 0000000..3d8f84b
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386-shift.h
@@ -0,0 +1,185 @@
+
+#define exec_op glue(exec_, OP)
+#define exec_opq glue(glue(exec_, OP), q)
+#define exec_opl glue(glue(exec_, OP), l)
+#define exec_opw glue(glue(exec_, OP), w)
+#define exec_opb glue(glue(exec_, OP), b)
+
+#ifndef OP_SHIFTD
+
+#ifdef OP_NOBYTE
+#define EXECSHIFT(size, rsize, res, s1, s2, flags) \
+    asm ("push %4\n\t"\
+         "popf\n\t"\
+         stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=g" (res), "=g" (flags)\
+         : "r" (s1), "0" (res), "1" (flags));
+#else
+#define EXECSHIFT(size, rsize, res, s1, s2, flags) \
+    asm ("push %4\n\t"\
+         "popf\n\t"\
+         stringify(OP) size " %%cl, %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=q" (res), "=g" (flags)\
+         : "c" (s1), "0" (res), "1" (flags));
+#endif
+
+#if defined(__x86_64__)
+void exec_opq(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("q", "", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "q", s0, s1, res, iflags, flags & CC_MASK);
+}
+#endif
+
+void exec_opl(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("l", "k", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK);
+}
+
+void exec_opw(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("w", "w", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK);
+}
+
+#else
+#define EXECSHIFT(size, rsize, res, s1, s2, flags) \
+    asm ("push %4\n\t"\
+         "popf\n\t"\
+         stringify(OP) size " %%cl, %" rsize "5, %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=g" (res), "=g" (flags)\
+         : "c" (s1), "0" (res), "1" (flags), "r" (s2));
+
+#if defined(__x86_64__)
+void exec_opq(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("q", "", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "q", s0, s2, s1, res, iflags, flags & CC_MASK);
+}
+#endif
+
+void exec_opl(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("l", "k", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK);
+}
+
+void exec_opw(long s2, long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("w", "w", res, s1, s2, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK);
+}
+
+#endif
+
+#ifndef OP_NOBYTE
+void exec_opb(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECSHIFT("b", "b", res, s1, 0, flags);
+    /* overflow is undefined if count != 1 */
+    if (s1 != 1)
+      flags &= ~CC_O;
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n",
+           stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK);
+}
+#endif
+
+void exec_op(long s2, long s0, long s1)
+{
+    s2 = i2l(s2);
+    s0 = i2l(s0);
+#if defined(__x86_64__)
+    exec_opq(s2, s0, s1, 0);
+#endif
+    exec_opl(s2, s0, s1, 0);
+#ifdef OP_SHIFTD
+    exec_opw(s2, s0, s1, 0);
+#else
+    exec_opw(s2, s0, s1, 0);
+#endif
+#ifndef OP_NOBYTE
+    exec_opb(s0, s1, 0);
+#endif
+#ifdef OP_CC
+#if defined(__x86_64__)
+    exec_opq(s2, s0, s1, CC_C);
+#endif
+    exec_opl(s2, s0, s1, CC_C);
+    exec_opw(s2, s0, s1, CC_C);
+    exec_opb(s0, s1, CC_C);
+#endif
+}
+
+void glue(test_, OP)(void)
+{
+    int i, n;
+#if defined(__x86_64__)
+    n = 64;
+#else
+    n = 32;
+#endif
+    for(i = 0; i < n; i++)
+        exec_op(0x21ad3d34, 0x12345678, i);
+    for(i = 0; i < n; i++)
+        exec_op(0x813f3421, 0x82345679, i);
+}
+
+void *glue(_test_, OP) __init_call = glue(test_, OP);
+
+#undef OP
+#undef OP_CC
+#undef OP_SHIFTD
+#undef OP_NOBYTE
+#undef EXECSHIFT
diff --git a/qemu-0.15.x/tests/test-i386-ssse3.c b/qemu-0.15.x/tests/test-i386-ssse3.c
new file mode 100644
index 0000000..0a42bd0
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386-ssse3.c
@@ -0,0 +1,57 @@
+/* See if various MMX/SSE SSSE3 instructions give expected results */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+int main(int argc, char *argv[]) {
+	char hello[16];
+	const char ehlo[8] = "EHLO    ";
+	uint64_t mask = 0x8080800302020001;
+
+	uint64_t a = 0x0000000000090007;
+	uint64_t b = 0x0000000000000000;
+	uint32_t c;
+	uint16_t d;
+
+	const char e[16] = "LLOaaaaaaaaaaaaa";
+	const char f[16] = "aaaaaaaaaaaaaaHE";
+
+	/* pshufb mm1/xmm1, mm2/xmm2 */
+	asm volatile ("movq    (%0), %%mm0" : : "r" (ehlo) : "mm0", "mm1");
+	asm volatile ("movq    %0, %%mm1" : : "m" (mask));
+	asm volatile ("pshufb  %mm1, %mm0");
+	asm volatile ("movq    %%mm0, %0" : "=m" (hello));
+	printf("%s\n", hello);
+
+	/* pshufb mm1/xmm1, m64/m128 */
+	asm volatile ("movq    (%0), %%mm0" : : "r" (ehlo) : "mm0");
+	asm volatile ("pshufb  %0, %%mm0" : : "m" (mask));
+	asm volatile ("movq    %%mm0, %0" : "=m" (hello));
+	printf("%s\n", hello);
+
+	/* psubsw mm1/xmm1, m64/m128 */
+	asm volatile ("movq    %0, %%mm0" : : "r" (a) : "mm0");
+	asm volatile ("phsubsw %0, %%mm0" : : "m" (b));
+	asm volatile ("movq    %%mm0, %0" : "=m" (a));
+	printf("%i - %i = %i\n", 9, 7, -(int16_t) a);
+
+	/* palignr mm1/xmm1, m64/m128, imm8 */
+	asm volatile ("movdqa  (%0), %%xmm0" : : "r" (e) : "xmm0");
+	asm volatile ("palignr $14, (%0), %%xmm0" : : "r" (f));
+	asm volatile ("movdqa  %%xmm0, (%0)" : : "r" (hello));
+	printf("%5.5s\n", hello);
+
+#if 1 /* SSE4 */
+	/* popcnt r64, r/m64 */
+	asm volatile ("movq    $0x8421000010009c63, %%rax" : : : "rax");
+	asm volatile ("popcnt  %%ax, %%dx" : : : "dx");
+	asm volatile ("popcnt  %%eax, %%ecx" : : : "ecx");
+	asm volatile ("popcnt  %rax, %rax");
+	asm volatile ("movq    %%rax, %0" : "=m" (a));
+	asm volatile ("movl    %%ecx, %0" : "=m" (c));
+	asm volatile ("movw    %%dx, %0" : "=m" (d));
+	printf("%i = %i\n%i = %i = %i\n", 13, (int) a, 9, c, d + 1);
+#endif
+
+	return 0;
+}
diff --git a/qemu-0.15.x/tests/test-i386-vm86.S b/qemu-0.15.x/tests/test-i386-vm86.S
new file mode 100644
index 0000000..3bb96c9
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386-vm86.S
@@ -0,0 +1,103 @@
+        .code16
+        .globl vm86_code_start
+        .globl vm86_code_end
+
+#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100)
+
+vm86_code_start:
+        movw $GET_OFFSET(hello_world), %dx
+        movb $0x09, %ah
+        int $0x21
+
+        /* prepare int 0x90 vector */
+        xorw %ax, %ax
+        movw %ax, %es
+        es movw $GET_OFFSET(int90_test), 0x90 * 4
+        es movw %cs, 0x90 * 4 + 2
+
+        /* launch int 0x90 */
+
+        int $0x90
+
+        /* test IF support */
+        movw $GET_OFFSET(IF_msg), %dx
+        movb $0x09, %ah
+        int $0x21
+
+        pushf
+        popw %dx
+        movb $0xff, %ah
+        int $0x21
+
+        cli
+        pushf
+        popw %dx
+        movb $0xff, %ah
+        int $0x21
+
+        sti
+        pushfl
+        popl %edx
+        movb $0xff, %ah
+        int $0x21
+
+#if 0
+        movw $GET_OFFSET(IF_msg1), %dx
+        movb $0x09, %ah
+        int $0x21
+
+        pushf
+        movw %sp, %bx
+        andw $~0x200, (%bx)
+        popf
+#else
+        cli
+#endif
+
+        pushf
+        popw %dx
+        movb $0xff, %ah
+        int $0x21
+
+        pushfl
+        movw %sp, %bx
+        orw $0x200, (%bx)
+        popfl
+
+        pushfl
+        popl %edx
+        movb $0xff, %ah
+        int $0x21
+
+        movb $0x00, %ah
+        int $0x21
+
+int90_test:
+        pushf
+        pop %dx
+        movb $0xff, %ah
+        int $0x21
+
+        movw %sp, %bx
+        movw 4(%bx), %dx
+        movb $0xff, %ah
+        int $0x21
+
+        movw $GET_OFFSET(int90_msg), %dx
+        movb $0x09, %ah
+        int $0x21
+        iret
+
+int90_msg:
+        .string "INT90 started\n$"
+
+hello_world:
+        .string "Hello VM86 world\n$"
+
+IF_msg:
+        .string "VM86 IF test\n$"
+
+IF_msg1:
+        .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
+
+vm86_code_end:
diff --git a/qemu-0.15.x/tests/test-i386.c b/qemu-0.15.x/tests/test-i386.c
new file mode 100644
index 0000000..56ff110
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386.c
@@ -0,0 +1,2764 @@
+/*
+ *  x86 CPU test
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+#include <sys/mman.h>
+
+#if !defined(__x86_64__)
+//#define TEST_VM86
+#define TEST_SEGS
+#endif
+//#define LINUX_VM86_IOPL_FIX
+//#define TEST_P4_FLAGS
+#ifdef __SSE__
+#define TEST_SSE
+#define TEST_CMOV  1
+#define TEST_FCOMI 1
+#else
+#undef TEST_SSE
+#define TEST_CMOV  1
+#define TEST_FCOMI 1
+#endif
+
+#if defined(__x86_64__)
+#define FMT64X "%016lx"
+#define FMTLX "%016lx"
+#define X86_64_ONLY(x) x
+#else
+#define FMT64X "%016" PRIx64
+#define FMTLX "%08lx"
+#define X86_64_ONLY(x)
+#endif
+
+#ifdef TEST_VM86
+#include <asm/vm86.h>
+#endif
+
+#define xglue(x, y) x ## y
+#define glue(x, y) xglue(x, y)
+#define stringify(s)	tostring(s)
+#define tostring(s)	#s
+
+#define CC_C   	0x0001
+#define CC_P 	0x0004
+#define CC_A	0x0010
+#define CC_Z	0x0040
+#define CC_S    0x0080
+#define CC_O    0x0800
+
+#define __init_call	__attribute__ ((unused,__section__ ("initcall")))
+
+#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
+
+#if defined(__x86_64__)
+static inline long i2l(long v)
+{
+    return v | ((v ^ 0xabcd) << 32);
+}
+#else
+static inline long i2l(long v)
+{
+    return v;
+}
+#endif
+
+#define OP add
+#include "test-i386.h"
+
+#define OP sub
+#include "test-i386.h"
+
+#define OP xor
+#include "test-i386.h"
+
+#define OP and
+#include "test-i386.h"
+
+#define OP or
+#include "test-i386.h"
+
+#define OP cmp
+#include "test-i386.h"
+
+#define OP adc
+#define OP_CC
+#include "test-i386.h"
+
+#define OP sbb
+#define OP_CC
+#include "test-i386.h"
+
+#define OP inc
+#define OP_CC
+#define OP1
+#include "test-i386.h"
+
+#define OP dec
+#define OP_CC
+#define OP1
+#include "test-i386.h"
+
+#define OP neg
+#define OP_CC
+#define OP1
+#include "test-i386.h"
+
+#define OP not
+#define OP_CC
+#define OP1
+#include "test-i386.h"
+
+#undef CC_MASK
+#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
+
+#define OP shl
+#include "test-i386-shift.h"
+
+#define OP shr
+#include "test-i386-shift.h"
+
+#define OP sar
+#include "test-i386-shift.h"
+
+#define OP rol
+#include "test-i386-shift.h"
+
+#define OP ror
+#include "test-i386-shift.h"
+
+#define OP rcr
+#define OP_CC
+#include "test-i386-shift.h"
+
+#define OP rcl
+#define OP_CC
+#include "test-i386-shift.h"
+
+#define OP shld
+#define OP_SHIFTD
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+#define OP shrd
+#define OP_SHIFTD
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+/* XXX: should be more precise ? */
+#undef CC_MASK
+#define CC_MASK (CC_C)
+
+#define OP bt
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+#define OP bts
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+#define OP btr
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+#define OP btc
+#define OP_NOBYTE
+#include "test-i386-shift.h"
+
+/* lea test (modrm support) */
+#define TEST_LEAQ(STR)\
+{\
+    asm("lea " STR ", %0"\
+        : "=r" (res)\
+        : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
+    printf("lea %s = " FMTLX "\n", STR, res);\
+}
+
+#define TEST_LEA(STR)\
+{\
+    asm("lea " STR ", %0"\
+        : "=r" (res)\
+        : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
+    printf("lea %s = " FMTLX "\n", STR, res);\
+}
+
+#define TEST_LEA16(STR)\
+{\
+    asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
+        : "=wq" (res)\
+        : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
+    printf("lea %s = %08lx\n", STR, res);\
+}
+
+
+void test_lea(void)
+{
+    long eax, ebx, ecx, edx, esi, edi, res;
+    eax = i2l(0x0001);
+    ebx = i2l(0x0002);
+    ecx = i2l(0x0004);
+    edx = i2l(0x0008);
+    esi = i2l(0x0010);
+    edi = i2l(0x0020);
+
+    TEST_LEA("0x4000");
+
+    TEST_LEA("(%%eax)");
+    TEST_LEA("(%%ebx)");
+    TEST_LEA("(%%ecx)");
+    TEST_LEA("(%%edx)");
+    TEST_LEA("(%%esi)");
+    TEST_LEA("(%%edi)");
+
+    TEST_LEA("0x40(%%eax)");
+    TEST_LEA("0x40(%%ebx)");
+    TEST_LEA("0x40(%%ecx)");
+    TEST_LEA("0x40(%%edx)");
+    TEST_LEA("0x40(%%esi)");
+    TEST_LEA("0x40(%%edi)");
+
+    TEST_LEA("0x4000(%%eax)");
+    TEST_LEA("0x4000(%%ebx)");
+    TEST_LEA("0x4000(%%ecx)");
+    TEST_LEA("0x4000(%%edx)");
+    TEST_LEA("0x4000(%%esi)");
+    TEST_LEA("0x4000(%%edi)");
+
+    TEST_LEA("(%%eax, %%ecx)");
+    TEST_LEA("(%%ebx, %%edx)");
+    TEST_LEA("(%%ecx, %%ecx)");
+    TEST_LEA("(%%edx, %%ecx)");
+    TEST_LEA("(%%esi, %%ecx)");
+    TEST_LEA("(%%edi, %%ecx)");
+
+    TEST_LEA("0x40(%%eax, %%ecx)");
+    TEST_LEA("0x4000(%%ebx, %%edx)");
+
+    TEST_LEA("(%%ecx, %%ecx, 2)");
+    TEST_LEA("(%%edx, %%ecx, 4)");
+    TEST_LEA("(%%esi, %%ecx, 8)");
+
+    TEST_LEA("(,%%eax, 2)");
+    TEST_LEA("(,%%ebx, 4)");
+    TEST_LEA("(,%%ecx, 8)");
+
+    TEST_LEA("0x40(,%%eax, 2)");
+    TEST_LEA("0x40(,%%ebx, 4)");
+    TEST_LEA("0x40(,%%ecx, 8)");
+
+
+    TEST_LEA("-10(%%ecx, %%ecx, 2)");
+    TEST_LEA("-10(%%edx, %%ecx, 4)");
+    TEST_LEA("-10(%%esi, %%ecx, 8)");
+
+    TEST_LEA("0x4000(%%ecx, %%ecx, 2)");
+    TEST_LEA("0x4000(%%edx, %%ecx, 4)");
+    TEST_LEA("0x4000(%%esi, %%ecx, 8)");
+
+#if defined(__x86_64__)
+    TEST_LEAQ("0x4000");
+    TEST_LEAQ("0x4000(%%rip)");
+
+    TEST_LEAQ("(%%rax)");
+    TEST_LEAQ("(%%rbx)");
+    TEST_LEAQ("(%%rcx)");
+    TEST_LEAQ("(%%rdx)");
+    TEST_LEAQ("(%%rsi)");
+    TEST_LEAQ("(%%rdi)");
+
+    TEST_LEAQ("0x40(%%rax)");
+    TEST_LEAQ("0x40(%%rbx)");
+    TEST_LEAQ("0x40(%%rcx)");
+    TEST_LEAQ("0x40(%%rdx)");
+    TEST_LEAQ("0x40(%%rsi)");
+    TEST_LEAQ("0x40(%%rdi)");
+
+    TEST_LEAQ("0x4000(%%rax)");
+    TEST_LEAQ("0x4000(%%rbx)");
+    TEST_LEAQ("0x4000(%%rcx)");
+    TEST_LEAQ("0x4000(%%rdx)");
+    TEST_LEAQ("0x4000(%%rsi)");
+    TEST_LEAQ("0x4000(%%rdi)");
+
+    TEST_LEAQ("(%%rax, %%rcx)");
+    TEST_LEAQ("(%%rbx, %%rdx)");
+    TEST_LEAQ("(%%rcx, %%rcx)");
+    TEST_LEAQ("(%%rdx, %%rcx)");
+    TEST_LEAQ("(%%rsi, %%rcx)");
+    TEST_LEAQ("(%%rdi, %%rcx)");
+
+    TEST_LEAQ("0x40(%%rax, %%rcx)");
+    TEST_LEAQ("0x4000(%%rbx, %%rdx)");
+
+    TEST_LEAQ("(%%rcx, %%rcx, 2)");
+    TEST_LEAQ("(%%rdx, %%rcx, 4)");
+    TEST_LEAQ("(%%rsi, %%rcx, 8)");
+
+    TEST_LEAQ("(,%%rax, 2)");
+    TEST_LEAQ("(,%%rbx, 4)");
+    TEST_LEAQ("(,%%rcx, 8)");
+
+    TEST_LEAQ("0x40(,%%rax, 2)");
+    TEST_LEAQ("0x40(,%%rbx, 4)");
+    TEST_LEAQ("0x40(,%%rcx, 8)");
+
+
+    TEST_LEAQ("-10(%%rcx, %%rcx, 2)");
+    TEST_LEAQ("-10(%%rdx, %%rcx, 4)");
+    TEST_LEAQ("-10(%%rsi, %%rcx, 8)");
+
+    TEST_LEAQ("0x4000(%%rcx, %%rcx, 2)");
+    TEST_LEAQ("0x4000(%%rdx, %%rcx, 4)");
+    TEST_LEAQ("0x4000(%%rsi, %%rcx, 8)");
+#else
+    /* limited 16 bit addressing test */
+    TEST_LEA16("0x4000");
+    TEST_LEA16("(%%bx)");
+    TEST_LEA16("(%%si)");
+    TEST_LEA16("(%%di)");
+    TEST_LEA16("0x40(%%bx)");
+    TEST_LEA16("0x40(%%si)");
+    TEST_LEA16("0x40(%%di)");
+    TEST_LEA16("0x4000(%%bx)");
+    TEST_LEA16("0x4000(%%si)");
+    TEST_LEA16("(%%bx,%%si)");
+    TEST_LEA16("(%%bx,%%di)");
+    TEST_LEA16("0x40(%%bx,%%si)");
+    TEST_LEA16("0x40(%%bx,%%di)");
+    TEST_LEA16("0x4000(%%bx,%%si)");
+    TEST_LEA16("0x4000(%%bx,%%di)");
+#endif
+}
+
+#define TEST_JCC(JCC, v1, v2)\
+{\
+    int res;\
+    asm("movl $1, %0\n\t"\
+        "cmpl %2, %1\n\t"\
+        "j" JCC " 1f\n\t"\
+        "movl $0, %0\n\t"\
+        "1:\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2));\
+    printf("%-10s %d\n", "j" JCC, res);\
+\
+    asm("movl $0, %0\n\t"\
+        "cmpl %2, %1\n\t"\
+        "set" JCC " %b0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2));\
+    printf("%-10s %d\n", "set" JCC, res);\
+ if (TEST_CMOV) {\
+    long val = i2l(1);\
+    long res = i2l(0x12345678);\
+X86_64_ONLY(\
+    asm("cmpl %2, %1\n\t"\
+        "cmov" JCC "q %3, %0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2), "m" (val), "0" (res));\
+        printf("%-10s R=" FMTLX "\n", "cmov" JCC "q", res);)\
+    asm("cmpl %2, %1\n\t"\
+        "cmov" JCC "l %k3, %k0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2), "m" (val), "0" (res));\
+        printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);\
+    asm("cmpl %2, %1\n\t"\
+        "cmov" JCC "w %w3, %w0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2), "r" (1), "0" (res));\
+        printf("%-10s R=" FMTLX "\n", "cmov" JCC "w", res);\
+ } \
+}
+
+/* various jump tests */
+void test_jcc(void)
+{
+    TEST_JCC("ne", 1, 1);
+    TEST_JCC("ne", 1, 0);
+
+    TEST_JCC("e", 1, 1);
+    TEST_JCC("e", 1, 0);
+
+    TEST_JCC("l", 1, 1);
+    TEST_JCC("l", 1, 0);
+    TEST_JCC("l", 1, -1);
+
+    TEST_JCC("le", 1, 1);
+    TEST_JCC("le", 1, 0);
+    TEST_JCC("le", 1, -1);
+
+    TEST_JCC("ge", 1, 1);
+    TEST_JCC("ge", 1, 0);
+    TEST_JCC("ge", -1, 1);
+
+    TEST_JCC("g", 1, 1);
+    TEST_JCC("g", 1, 0);
+    TEST_JCC("g", 1, -1);
+
+    TEST_JCC("b", 1, 1);
+    TEST_JCC("b", 1, 0);
+    TEST_JCC("b", 1, -1);
+
+    TEST_JCC("be", 1, 1);
+    TEST_JCC("be", 1, 0);
+    TEST_JCC("be", 1, -1);
+
+    TEST_JCC("ae", 1, 1);
+    TEST_JCC("ae", 1, 0);
+    TEST_JCC("ae", 1, -1);
+
+    TEST_JCC("a", 1, 1);
+    TEST_JCC("a", 1, 0);
+    TEST_JCC("a", 1, -1);
+
+
+    TEST_JCC("p", 1, 1);
+    TEST_JCC("p", 1, 0);
+
+    TEST_JCC("np", 1, 1);
+    TEST_JCC("np", 1, 0);
+
+    TEST_JCC("o", 0x7fffffff, 0);
+    TEST_JCC("o", 0x7fffffff, -1);
+
+    TEST_JCC("no", 0x7fffffff, 0);
+    TEST_JCC("no", 0x7fffffff, -1);
+
+    TEST_JCC("s", 0, 1);
+    TEST_JCC("s", 0, -1);
+    TEST_JCC("s", 0, 0);
+
+    TEST_JCC("ns", 0, 1);
+    TEST_JCC("ns", 0, -1);
+    TEST_JCC("ns", 0, 0);
+}
+
+#define TEST_LOOP(insn) \
+{\
+    for(i = 0; i < sizeof(ecx_vals) / sizeof(long); i++) {\
+        ecx = ecx_vals[i];\
+        for(zf = 0; zf < 2; zf++) {\
+    asm("test %2, %2\n\t"\
+        "movl $1, %0\n\t"\
+          insn " 1f\n\t" \
+        "movl $0, %0\n\t"\
+        "1:\n\t"\
+        : "=a" (res)\
+        : "c" (ecx), "b" (!zf)); \
+    printf("%-10s ECX=" FMTLX " ZF=%ld r=%d\n", insn, ecx, zf, res);      \
+        }\
+   }\
+}
+
+void test_loop(void)
+{
+    long ecx, zf;
+    const long ecx_vals[] = {
+        0,
+        1,
+        0x10000,
+        0x10001,
+#if defined(__x86_64__)
+        0x100000000L,
+        0x100000001L,
+#endif
+    };
+    int i, res;
+
+#if !defined(__x86_64__)
+    TEST_LOOP("jcxz");
+    TEST_LOOP("loopw");
+    TEST_LOOP("loopzw");
+    TEST_LOOP("loopnzw");
+#endif
+
+    TEST_LOOP("jecxz");
+    TEST_LOOP("loopl");
+    TEST_LOOP("loopzl");
+    TEST_LOOP("loopnzl");
+}
+
+#undef CC_MASK
+#ifdef TEST_P4_FLAGS
+#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
+#else
+#define CC_MASK (CC_O | CC_C)
+#endif
+
+#define OP mul
+#include "test-i386-muldiv.h"
+
+#define OP imul
+#include "test-i386-muldiv.h"
+
+void test_imulw2(long op0, long op1)
+{
+    long res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm volatile ("push %4\n\t"
+         "popf\n\t"
+         "imulw %w2, %w0\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=q" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
+           "imulw", s0, s1, res, flags & CC_MASK);
+}
+
+void test_imull2(long op0, long op1)
+{
+    long res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm volatile ("push %4\n\t"
+         "popf\n\t"
+         "imull %k2, %k0\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=q" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
+           "imull", s0, s1, res, flags & CC_MASK);
+}
+
+#if defined(__x86_64__)
+void test_imulq2(long op0, long op1)
+{
+    long res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm volatile ("push %4\n\t"
+         "popf\n\t"
+         "imulq %2, %0\n\t"
+         "pushf\n\t"
+         "pop %1\n\t"
+         : "=q" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
+           "imulq", s0, s1, res, flags & CC_MASK);
+}
+#endif
+
+#define TEST_IMUL_IM(size, rsize, op0, op1)\
+{\
+    long res, flags, s1;\
+    flags = 0;\
+    res = 0;\
+    s1 = op1;\
+    asm volatile ("push %3\n\t"\
+         "popf\n\t"\
+         "imul" size " $" #op0 ", %" rsize "2, %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=r" (res), "=g" (flags)\
+         : "r" (s1), "1" (flags), "0" (res));\
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",\
+           "imul" size " im", (long)op0, (long)op1, res, flags & CC_MASK);\
+}
+
+
+#undef CC_MASK
+#define CC_MASK (0)
+
+#define OP div
+#include "test-i386-muldiv.h"
+
+#define OP idiv
+#include "test-i386-muldiv.h"
+
+void test_mul(void)
+{
+    test_imulb(0x1234561d, 4);
+    test_imulb(3, -4);
+    test_imulb(0x80, 0x80);
+    test_imulb(0x10, 0x10);
+
+    test_imulw(0, 0x1234001d, 45);
+    test_imulw(0, 23, -45);
+    test_imulw(0, 0x8000, 0x8000);
+    test_imulw(0, 0x100, 0x100);
+
+    test_imull(0, 0x1234001d, 45);
+    test_imull(0, 23, -45);
+    test_imull(0, 0x80000000, 0x80000000);
+    test_imull(0, 0x10000, 0x10000);
+
+    test_mulb(0x1234561d, 4);
+    test_mulb(3, -4);
+    test_mulb(0x80, 0x80);
+    test_mulb(0x10, 0x10);
+
+    test_mulw(0, 0x1234001d, 45);
+    test_mulw(0, 23, -45);
+    test_mulw(0, 0x8000, 0x8000);
+    test_mulw(0, 0x100, 0x100);
+
+    test_mull(0, 0x1234001d, 45);
+    test_mull(0, 23, -45);
+    test_mull(0, 0x80000000, 0x80000000);
+    test_mull(0, 0x10000, 0x10000);
+
+    test_imulw2(0x1234001d, 45);
+    test_imulw2(23, -45);
+    test_imulw2(0x8000, 0x8000);
+    test_imulw2(0x100, 0x100);
+
+    test_imull2(0x1234001d, 45);
+    test_imull2(23, -45);
+    test_imull2(0x80000000, 0x80000000);
+    test_imull2(0x10000, 0x10000);
+
+    TEST_IMUL_IM("w", "w", 45, 0x1234);
+    TEST_IMUL_IM("w", "w", -45, 23);
+    TEST_IMUL_IM("w", "w", 0x8000, 0x80000000);
+    TEST_IMUL_IM("w", "w", 0x7fff, 0x1000);
+
+    TEST_IMUL_IM("l", "k", 45, 0x1234);
+    TEST_IMUL_IM("l", "k", -45, 23);
+    TEST_IMUL_IM("l", "k", 0x8000, 0x80000000);
+    TEST_IMUL_IM("l", "k", 0x7fff, 0x1000);
+
+    test_idivb(0x12341678, 0x127e);
+    test_idivb(0x43210123, -5);
+    test_idivb(0x12340004, -1);
+
+    test_idivw(0, 0x12345678, 12347);
+    test_idivw(0, -23223, -45);
+    test_idivw(0, 0x12348000, -1);
+    test_idivw(0x12343, 0x12345678, 0x81238567);
+
+    test_idivl(0, 0x12345678, 12347);
+    test_idivl(0, -233223, -45);
+    test_idivl(0, 0x80000000, -1);
+    test_idivl(0x12343, 0x12345678, 0x81234567);
+
+    test_divb(0x12341678, 0x127e);
+    test_divb(0x43210123, -5);
+    test_divb(0x12340004, -1);
+
+    test_divw(0, 0x12345678, 12347);
+    test_divw(0, -23223, -45);
+    test_divw(0, 0x12348000, -1);
+    test_divw(0x12343, 0x12345678, 0x81238567);
+
+    test_divl(0, 0x12345678, 12347);
+    test_divl(0, -233223, -45);
+    test_divl(0, 0x80000000, -1);
+    test_divl(0x12343, 0x12345678, 0x81234567);
+
+#if defined(__x86_64__)
+    test_imulq(0, 0x1234001d1234001d, 45);
+    test_imulq(0, 23, -45);
+    test_imulq(0, 0x8000000000000000, 0x8000000000000000);
+    test_imulq(0, 0x100000000, 0x100000000);
+
+    test_mulq(0, 0x1234001d1234001d, 45);
+    test_mulq(0, 23, -45);
+    test_mulq(0, 0x8000000000000000, 0x8000000000000000);
+    test_mulq(0, 0x100000000, 0x100000000);
+
+    test_imulq2(0x1234001d1234001d, 45);
+    test_imulq2(23, -45);
+    test_imulq2(0x8000000000000000, 0x8000000000000000);
+    test_imulq2(0x100000000, 0x100000000);
+
+    TEST_IMUL_IM("q", "", 45, 0x12341234);
+    TEST_IMUL_IM("q", "", -45, 23);
+    TEST_IMUL_IM("q", "", 0x8000, 0x8000000000000000);
+    TEST_IMUL_IM("q", "", 0x7fff, 0x10000000);
+
+    test_idivq(0, 0x12345678abcdef, 12347);
+    test_idivq(0, -233223, -45);
+    test_idivq(0, 0x8000000000000000, -1);
+    test_idivq(0x12343, 0x12345678, 0x81234567);
+
+    test_divq(0, 0x12345678abcdef, 12347);
+    test_divq(0, -233223, -45);
+    test_divq(0, 0x8000000000000000, -1);
+    test_divq(0x12343, 0x12345678, 0x81234567);
+#endif
+}
+
+#define TEST_BSX(op, size, op0)\
+{\
+    long res, val, resz;\
+    val = op0;\
+    asm("xor %1, %1\n"\
+        "mov $0x12345678, %0\n"\
+        #op " %" size "2, %" size "0 ; setz %b1" \
+        : "=&r" (res), "=&q" (resz)\
+        : "r" (val));\
+    printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\
+}
+
+void test_bsx(void)
+{
+    TEST_BSX(bsrw, "w", 0);
+    TEST_BSX(bsrw, "w", 0x12340128);
+    TEST_BSX(bsfw, "w", 0);
+    TEST_BSX(bsfw, "w", 0x12340128);
+    TEST_BSX(bsrl, "k", 0);
+    TEST_BSX(bsrl, "k", 0x00340128);
+    TEST_BSX(bsfl, "k", 0);
+    TEST_BSX(bsfl, "k", 0x00340128);
+#if defined(__x86_64__)
+    TEST_BSX(bsrq, "", 0);
+    TEST_BSX(bsrq, "", 0x003401281234);
+    TEST_BSX(bsfq, "", 0);
+    TEST_BSX(bsfq, "", 0x003401281234);
+#endif
+}
+
+/**********************************************/
+
+union float64u {
+    double d;
+    uint64_t l;
+};
+
+union float64u q_nan = { .l = 0xFFF8000000000000LL };
+union float64u s_nan = { .l = 0xFFF0000000000000LL };
+
+void test_fops(double a, double b)
+{
+    printf("a=%f b=%f a+b=%f\n", a, b, a + b);
+    printf("a=%f b=%f a-b=%f\n", a, b, a - b);
+    printf("a=%f b=%f a*b=%f\n", a, b, a * b);
+    printf("a=%f b=%f a/b=%f\n", a, b, a / b);
+    printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
+    printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
+    printf("a=%f sin(a)=%f\n", a, sin(a));
+    printf("a=%f cos(a)=%f\n", a, cos(a));
+    printf("a=%f tan(a)=%f\n", a, tan(a));
+    printf("a=%f log(a)=%f\n", a, log(a));
+    printf("a=%f exp(a)=%f\n", a, exp(a));
+    printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
+    /* just to test some op combining */
+    printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
+    printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
+    printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
+
+}
+
+void fpu_clear_exceptions(void)
+{
+    struct __attribute__((packed)) {
+        uint16_t fpuc;
+        uint16_t dummy1;
+        uint16_t fpus;
+        uint16_t dummy2;
+        uint16_t fptag;
+        uint16_t dummy3;
+        uint32_t ignored[4];
+        long double fpregs[8];
+    } float_env32;
+
+    asm volatile ("fnstenv %0\n" : : "m" (float_env32));
+    float_env32.fpus &= ~0x7f;
+    asm volatile ("fldenv %0\n" : : "m" (float_env32));
+}
+
+/* XXX: display exception bits when supported */
+#define FPUS_EMASK 0x0000
+//#define FPUS_EMASK 0x007f
+
+void test_fcmp(double a, double b)
+{
+    long eflags, fpus;
+
+    fpu_clear_exceptions();
+    asm("fcom %2\n"
+        "fstsw %%ax\n"
+        : "=a" (fpus)
+        : "t" (a), "u" (b));
+    printf("fcom(%f %f)=%04lx \n",
+           a, b, fpus & (0x4500 | FPUS_EMASK));
+    fpu_clear_exceptions();
+    asm("fucom %2\n"
+        "fstsw %%ax\n"
+        : "=a" (fpus)
+        : "t" (a), "u" (b));
+    printf("fucom(%f %f)=%04lx\n",
+           a, b, fpus & (0x4500 | FPUS_EMASK));
+    if (TEST_FCOMI) {
+        /* test f(u)comi instruction */
+        fpu_clear_exceptions();
+        asm("fcomi %3, %2\n"
+            "fstsw %%ax\n"
+            "pushf\n"
+            "pop %0\n"
+            : "=r" (eflags), "=a" (fpus)
+            : "t" (a), "u" (b));
+        printf("fcomi(%f %f)=%04lx %02lx\n",
+               a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
+        fpu_clear_exceptions();
+        asm("fucomi %3, %2\n"
+            "fstsw %%ax\n"
+            "pushf\n"
+            "pop %0\n"
+            : "=r" (eflags), "=a" (fpus)
+            : "t" (a), "u" (b));
+        printf("fucomi(%f %f)=%04lx %02lx\n",
+               a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
+    }
+    fpu_clear_exceptions();
+    asm volatile("fxam\n"
+                 "fstsw %%ax\n"
+                 : "=a" (fpus)
+                 : "t" (a));
+    printf("fxam(%f)=%04lx\n", a, fpus & 0x4700);
+    fpu_clear_exceptions();
+}
+
+void test_fcvt(double a)
+{
+    float fa;
+    long double la;
+    int16_t fpuc;
+    int i;
+    int64_t lla;
+    int ia;
+    int16_t wa;
+    double ra;
+
+    fa = a;
+    la = a;
+    printf("(float)%f = %f\n", a, fa);
+    printf("(long double)%f = %Lf\n", a, la);
+    printf("a=" FMT64X "\n", *(uint64_t *)&a);
+    printf("la=" FMT64X " %04x\n", *(uint64_t *)&la,
+           *(unsigned short *)((char *)(&la) + 8));
+
+    /* test all roundings */
+    asm volatile ("fstcw %0" : "=m" (fpuc));
+    for(i=0;i<4;i++) {
+        uint16_t val16;
+        val16 = (fpuc & ~0x0c00) | (i << 10);
+        asm volatile ("fldcw %0" : : "m" (val16));
+        asm volatile ("fist %0" : "=m" (wa) : "t" (a));
+        asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
+        asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
+        asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
+        asm volatile ("fldcw %0" : : "m" (fpuc));
+        printf("(short)a = %d\n", wa);
+        printf("(int)a = %d\n", ia);
+        printf("(int64_t)a = " FMT64X "\n", lla);
+        printf("rint(a) = %f\n", ra);
+    }
+}
+
+#define TEST(N) \
+    asm("fld" #N : "=t" (a)); \
+    printf("fld" #N "= %f\n", a);
+
+void test_fconst(void)
+{
+    double a;
+    TEST(1);
+    TEST(l2t);
+    TEST(l2e);
+    TEST(pi);
+    TEST(lg2);
+    TEST(ln2);
+    TEST(z);
+}
+
+void test_fbcd(double a)
+{
+    unsigned short bcd[5];
+    double b;
+
+    asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
+    asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
+    printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
+           a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
+}
+
+#define TEST_ENV(env, save, restore)\
+{\
+    memset((env), 0xaa, sizeof(*(env)));\
+    for(i=0;i<5;i++)\
+        asm volatile ("fldl %0" : : "m" (dtab[i]));\
+    asm volatile (save " %0\n" : : "m" (*(env)));\
+    asm volatile (restore " %0\n": : "m" (*(env)));\
+    for(i=0;i<5;i++)\
+        asm volatile ("fstpl %0" : "=m" (rtab[i]));\
+    for(i=0;i<5;i++)\
+        printf("res[%d]=%f\n", i, rtab[i]);\
+    printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
+           (env)->fpuc,\
+           (env)->fpus & 0xff00,\
+           (env)->fptag);\
+}
+
+void test_fenv(void)
+{
+    struct __attribute__((packed)) {
+        uint16_t fpuc;
+        uint16_t dummy1;
+        uint16_t fpus;
+        uint16_t dummy2;
+        uint16_t fptag;
+        uint16_t dummy3;
+        uint32_t ignored[4];
+        long double fpregs[8];
+    } float_env32;
+    struct __attribute__((packed)) {
+        uint16_t fpuc;
+        uint16_t fpus;
+        uint16_t fptag;
+        uint16_t ignored[4];
+        long double fpregs[8];
+    } float_env16;
+    double dtab[8];
+    double rtab[8];
+    int i;
+
+    for(i=0;i<8;i++)
+        dtab[i] = i + 1;
+
+    TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv");
+    TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor");
+    TEST_ENV(&float_env32, "fnstenv", "fldenv");
+    TEST_ENV(&float_env32, "fnsave", "frstor");
+
+    /* test for ffree */
+    for(i=0;i<5;i++)
+        asm volatile ("fldl %0" : : "m" (dtab[i]));
+    asm volatile("ffree %st(2)");
+    asm volatile ("fnstenv %0\n" : : "m" (float_env32));
+    asm volatile ("fninit");
+    printf("fptag=%04x\n", float_env32.fptag);
+}
+
+
+#define TEST_FCMOV(a, b, eflags, CC)\
+{\
+    double res;\
+    asm("push %3\n"\
+        "popf\n"\
+        "fcmov" CC " %2, %0\n"\
+        : "=t" (res)\
+        : "0" (a), "u" (b), "g" (eflags));\
+    printf("fcmov%s eflags=0x%04lx-> %f\n", \
+           CC, (long)eflags, res);\
+}
+
+void test_fcmov(void)
+{
+    double a, b;
+    long eflags, i;
+
+    a = 1.0;
+    b = 2.0;
+    for(i = 0; i < 4; i++) {
+        eflags = 0;
+        if (i & 1)
+            eflags |= CC_C;
+        if (i & 2)
+            eflags |= CC_Z;
+        TEST_FCMOV(a, b, eflags, "b");
+        TEST_FCMOV(a, b, eflags, "e");
+        TEST_FCMOV(a, b, eflags, "be");
+        TEST_FCMOV(a, b, eflags, "nb");
+        TEST_FCMOV(a, b, eflags, "ne");
+        TEST_FCMOV(a, b, eflags, "nbe");
+    }
+    TEST_FCMOV(a, b, 0, "u");
+    TEST_FCMOV(a, b, CC_P, "u");
+    TEST_FCMOV(a, b, 0, "nu");
+    TEST_FCMOV(a, b, CC_P, "nu");
+}
+
+void test_floats(void)
+{
+    test_fops(2, 3);
+    test_fops(1.4, -5);
+    test_fcmp(2, -1);
+    test_fcmp(2, 2);
+    test_fcmp(2, 3);
+    test_fcmp(2, q_nan.d);
+    test_fcmp(q_nan.d, -1);
+    test_fcmp(-1.0/0.0, -1);
+    test_fcmp(1.0/0.0, -1);
+    test_fcvt(0.5);
+    test_fcvt(-0.5);
+    test_fcvt(1.0/7.0);
+    test_fcvt(-1.0/9.0);
+    test_fcvt(32768);
+    test_fcvt(-1e20);
+    test_fcvt(-1.0/0.0);
+    test_fcvt(1.0/0.0);
+    test_fcvt(q_nan.d);
+    test_fconst();
+    test_fbcd(1234567890123456.0);
+    test_fbcd(-123451234567890.0);
+    test_fenv();
+    if (TEST_CMOV) {
+        test_fcmov();
+    }
+}
+
+/**********************************************/
+#if !defined(__x86_64__)
+
+#define TEST_BCD(op, op0, cc_in, cc_mask)\
+{\
+    int res, flags;\
+    res = op0;\
+    flags = cc_in;\
+    asm ("push %3\n\t"\
+         "popf\n\t"\
+         #op "\n\t"\
+         "pushf\n\t"\
+         "pop %1\n\t"\
+        : "=a" (res), "=g" (flags)\
+        : "0" (res), "1" (flags));\
+    printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\
+           #op, op0, res, cc_in, flags & cc_mask);\
+}
+
+void test_bcd(void)
+{
+    TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+
+    TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+    TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
+
+    TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A));
+    TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A));
+
+    TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A));
+    TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A));
+    TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A));
+    TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A));
+    TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A));
+    TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A));
+    TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A));
+    TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A));
+
+    TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
+    TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
+}
+#endif
+
+#define TEST_XCHG(op, size, opconst)\
+{\
+    long op0, op1;\
+    op0 = i2l(0x12345678);\
+    op1 = i2l(0xfbca7654);\
+    asm(#op " %" size "0, %" size "1" \
+        : "=q" (op0), opconst (op1) \
+        : "0" (op0));\
+    printf("%-10s A=" FMTLX " B=" FMTLX "\n",\
+           #op, op0, op1);\
+}
+
+#define TEST_CMPXCHG(op, size, opconst, eax)\
+{\
+    long op0, op1, op2;\
+    op0 = i2l(0x12345678);\
+    op1 = i2l(0xfbca7654);\
+    op2 = i2l(eax);\
+    asm(#op " %" size "0, %" size "1" \
+        : "=q" (op0), opconst (op1) \
+        : "0" (op0), "a" (op2));\
+    printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\
+           #op, op2, op0, op1);\
+}
+
+void test_xchg(void)
+{
+#if defined(__x86_64__)
+    TEST_XCHG(xchgq, "", "+q");
+#endif
+    TEST_XCHG(xchgl, "k", "+q");
+    TEST_XCHG(xchgw, "w", "+q");
+    TEST_XCHG(xchgb, "b", "+q");
+
+#if defined(__x86_64__)
+    TEST_XCHG(xchgq, "", "=m");
+#endif
+    TEST_XCHG(xchgl, "k", "+m");
+    TEST_XCHG(xchgw, "w", "+m");
+    TEST_XCHG(xchgb, "b", "+m");
+
+#if defined(__x86_64__)
+    TEST_XCHG(xaddq, "", "+q");
+#endif
+    TEST_XCHG(xaddl, "k", "+q");
+    TEST_XCHG(xaddw, "w", "+q");
+    TEST_XCHG(xaddb, "b", "+q");
+
+    {
+        int res;
+        res = 0x12345678;
+        asm("xaddl %1, %0" : "=r" (res) : "0" (res));
+        printf("xaddl same res=%08x\n", res);
+    }
+
+#if defined(__x86_64__)
+    TEST_XCHG(xaddq, "", "+m");
+#endif
+    TEST_XCHG(xaddl, "k", "+m");
+    TEST_XCHG(xaddw, "w", "+m");
+    TEST_XCHG(xaddb, "b", "+m");
+
+#if defined(__x86_64__)
+    TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfbca7654);
+#endif
+    TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfbca7654);
+    TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfbca7654);
+    TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfbca7654);
+
+#if defined(__x86_64__)
+    TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfffefdfc);
+#endif
+    TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfffefdfc);
+    TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfffefdfc);
+    TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfffefdfc);
+
+#if defined(__x86_64__)
+    TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfbca7654);
+#endif
+    TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfbca7654);
+    TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfbca7654);
+    TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfbca7654);
+
+#if defined(__x86_64__)
+    TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfffefdfc);
+#endif
+    TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfffefdfc);
+    TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfffefdfc);
+    TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfffefdfc);
+
+    {
+        uint64_t op0, op1, op2;
+        long eax, edx;
+        long i, eflags;
+
+        for(i = 0; i < 2; i++) {
+            op0 = 0x123456789abcdLL;
+            eax = i2l(op0 & 0xffffffff);
+            edx = i2l(op0 >> 32);
+            if (i == 0)
+                op1 = 0xfbca765423456LL;
+            else
+                op1 = op0;
+            op2 = 0x6532432432434LL;
+            asm("cmpxchg8b %2\n"
+                "pushf\n"
+                "pop %3\n"
+                : "=a" (eax), "=d" (edx), "=m" (op1), "=g" (eflags)
+                : "0" (eax), "1" (edx), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32)));
+            printf("cmpxchg8b: eax=" FMTLX " edx=" FMTLX " op1=" FMT64X " CC=%02lx\n",
+                   eax, edx, op1, eflags & CC_Z);
+        }
+    }
+}
+
+#ifdef TEST_SEGS
+/**********************************************/
+/* segmentation tests */
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <asm/ldt.h>
+#include <linux/version.h>
+
+static inline int modify_ldt(int func, void * ptr, unsigned long bytecount)
+{
+    return syscall(__NR_modify_ldt, func, ptr, bytecount);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
+#define modify_ldt_ldt_s user_desc
+#endif
+
+#define MK_SEL(n) (((n) << 3) | 7)
+
+uint8_t seg_data1[4096];
+uint8_t seg_data2[4096];
+
+#define TEST_LR(op, size, seg, mask)\
+{\
+    int res, res2;\
+    uint16_t mseg = seg;\
+    res = 0x12345678;\
+    asm (op " %" size "2, %" size "0\n" \
+         "movl $0, %1\n"\
+         "jnz 1f\n"\
+         "movl $1, %1\n"\
+         "1:\n"\
+         : "=r" (res), "=r" (res2) : "m" (mseg), "0" (res));\
+    printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
+}
+
+#define TEST_ARPL(op, size, op1, op2)\
+{\
+    long a, b, c;                               \
+    a = (op1);                                  \
+    b = (op2);                                  \
+    asm volatile(op " %" size "3, %" size "0\n"\
+                 "movl $0,%1\n"\
+                 "jnz 1f\n"\
+                 "movl $1,%1\n"\
+                 "1:\n"\
+                 : "=r" (a), "=r" (c) : "0" (a), "r" (b));    \
+    printf(op size " A=" FMTLX " B=" FMTLX " R=" FMTLX " z=%ld\n",\
+           (long)(op1), (long)(op2), a, c);\
+}
+
+/* NOTE: we use Linux modify_ldt syscall */
+void test_segs(void)
+{
+    struct modify_ldt_ldt_s ldt;
+    long long ldt_table[3];
+    int res, res2;
+    char tmp;
+    struct {
+        uint32_t offset;
+        uint16_t seg;
+    } __attribute__((packed)) segoff;
+
+    ldt.entry_number = 1;
+    ldt.base_addr = (unsigned long)&seg_data1;
+    ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
+    ldt.seg_32bit = 1;
+    ldt.contents = MODIFY_LDT_CONTENTS_DATA;
+    ldt.read_exec_only = 0;
+    ldt.limit_in_pages = 1;
+    ldt.seg_not_present = 0;
+    ldt.useable = 1;
+    modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
+
+    ldt.entry_number = 2;
+    ldt.base_addr = (unsigned long)&seg_data2;
+    ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12;
+    ldt.seg_32bit = 1;
+    ldt.contents = MODIFY_LDT_CONTENTS_DATA;
+    ldt.read_exec_only = 0;
+    ldt.limit_in_pages = 1;
+    ldt.seg_not_present = 0;
+    ldt.useable = 1;
+    modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
+
+    modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
+#if 0
+    {
+        int i;
+        for(i=0;i<3;i++)
+            printf("%d: %016Lx\n", i, ldt_table[i]);
+    }
+#endif
+    /* do some tests with fs or gs */
+    asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
+
+    seg_data1[1] = 0xaa;
+    seg_data2[1] = 0x55;
+
+    asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
+    printf("FS[1] = %02x\n", res);
+
+    asm volatile ("pushl %%gs\n"
+                  "movl %1, %%gs\n"
+                  "gs movzbl 0x1, %0\n"
+                  "popl %%gs\n"
+                  : "=r" (res)
+                  : "r" (MK_SEL(2)));
+    printf("GS[1] = %02x\n", res);
+
+    /* tests with ds/ss (implicit segment case) */
+    tmp = 0xa5;
+    asm volatile ("pushl %%ebp\n\t"
+                  "pushl %%ds\n\t"
+                  "movl %2, %%ds\n\t"
+                  "movl %3, %%ebp\n\t"
+                  "movzbl 0x1, %0\n\t"
+                  "movzbl (%%ebp), %1\n\t"
+                  "popl %%ds\n\t"
+                  "popl %%ebp\n\t"
+                  : "=r" (res), "=r" (res2)
+                  : "r" (MK_SEL(1)), "r" (&tmp));
+    printf("DS[1] = %02x\n", res);
+    printf("SS[tmp] = %02x\n", res2);
+
+    segoff.seg = MK_SEL(2);
+    segoff.offset = 0xabcdef12;
+    asm volatile("lfs %2, %0\n\t"
+                 "movl %%fs, %1\n\t"
+                 : "=r" (res), "=g" (res2)
+                 : "m" (segoff));
+    printf("FS:reg = %04x:%08x\n", res2, res);
+
+    TEST_LR("larw", "w", MK_SEL(2), 0x0100);
+    TEST_LR("larl", "", MK_SEL(2), 0x0100);
+    TEST_LR("lslw", "w", MK_SEL(2), 0);
+    TEST_LR("lsll", "", MK_SEL(2), 0);
+
+    TEST_LR("larw", "w", 0xfff8, 0);
+    TEST_LR("larl", "", 0xfff8, 0);
+    TEST_LR("lslw", "w", 0xfff8, 0);
+    TEST_LR("lsll", "", 0xfff8, 0);
+
+    TEST_ARPL("arpl", "w", 0x12345678 | 3, 0x762123c | 1);
+    TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 3);
+    TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 1);
+}
+
+/* 16 bit code test */
+extern char code16_start, code16_end;
+extern char code16_func1;
+extern char code16_func2;
+extern char code16_func3;
+
+void test_code16(void)
+{
+    struct modify_ldt_ldt_s ldt;
+    int res, res2;
+
+    /* build a code segment */
+    ldt.entry_number = 1;
+    ldt.base_addr = (unsigned long)&code16_start;
+    ldt.limit = &code16_end - &code16_start;
+    ldt.seg_32bit = 0;
+    ldt.contents = MODIFY_LDT_CONTENTS_CODE;
+    ldt.read_exec_only = 0;
+    ldt.limit_in_pages = 0;
+    ldt.seg_not_present = 0;
+    ldt.useable = 1;
+    modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
+
+    /* call the first function */
+    asm volatile ("lcall %1, %2"
+                  : "=a" (res)
+                  : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc");
+    printf("func1() = 0x%08x\n", res);
+    asm volatile ("lcall %2, %3"
+                  : "=a" (res), "=c" (res2)
+                  : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc");
+    printf("func2() = 0x%08x spdec=%d\n", res, res2);
+    asm volatile ("lcall %1, %2"
+                  : "=a" (res)
+                  : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc");
+    printf("func3() = 0x%08x\n", res);
+}
+#endif
+
+#if defined(__x86_64__)
+asm(".globl func_lret\n"
+    "func_lret:\n"
+    "movl $0x87654641, %eax\n"
+    "lretq\n");
+#else
+asm(".globl func_lret\n"
+    "func_lret:\n"
+    "movl $0x87654321, %eax\n"
+    "lret\n"
+
+    ".globl func_iret\n"
+    "func_iret:\n"
+    "movl $0xabcd4321, %eax\n"
+    "iret\n");
+#endif
+
+extern char func_lret;
+extern char func_iret;
+
+void test_misc(void)
+{
+    char table[256];
+    long res, i;
+
+    for(i=0;i<256;i++) table[i] = 256 - i;
+    res = 0x12345678;
+    asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
+    printf("xlat: EAX=" FMTLX "\n", res);
+
+#if defined(__x86_64__)
+#if 0
+    {
+        /* XXX: see if Intel Core2 and AMD64 behavior really
+           differ. Here we implemented the Intel way which is not
+           compatible yet with QEMU. */
+        static struct __attribute__((packed)) {
+            uint64_t offset;
+            uint16_t seg;
+        } desc;
+        long cs_sel;
+
+        asm volatile ("mov %%cs, %0" : "=r" (cs_sel));
+
+        asm volatile ("push %1\n"
+                      "call func_lret\n"
+                      : "=a" (res)
+                      : "r" (cs_sel) : "memory", "cc");
+        printf("func_lret=" FMTLX "\n", res);
+
+        desc.offset = (long)&func_lret;
+        desc.seg = cs_sel;
+
+        asm volatile ("xor %%rax, %%rax\n"
+                      "rex64 lcall *(%%rcx)\n"
+                      : "=a" (res)
+                      : "c" (&desc)
+                      : "memory", "cc");
+        printf("func_lret2=" FMTLX "\n", res);
+
+        asm volatile ("push %2\n"
+                      "mov $ 1f, %%rax\n"
+                      "push %%rax\n"
+                      "rex64 ljmp *(%%rcx)\n"
+                      "1:\n"
+                      : "=a" (res)
+                      : "c" (&desc), "b" (cs_sel)
+                      : "memory", "cc");
+        printf("func_lret3=" FMTLX "\n", res);
+    }
+#endif
+#else
+    asm volatile ("push %%cs ; call %1"
+                  : "=a" (res)
+                  : "m" (func_lret): "memory", "cc");
+    printf("func_lret=" FMTLX "\n", res);
+
+    asm volatile ("pushf ; push %%cs ; call %1"
+                  : "=a" (res)
+                  : "m" (func_iret): "memory", "cc");
+    printf("func_iret=" FMTLX "\n", res);
+#endif
+
+#if defined(__x86_64__)
+    /* specific popl test */
+    asm volatile ("push $12345432 ; push $0x9abcdef ; pop (%%rsp) ; pop %0"
+                  : "=g" (res));
+    printf("popl esp=" FMTLX "\n", res);
+#else
+    /* specific popl test */
+    asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
+                  : "=g" (res));
+    printf("popl esp=" FMTLX "\n", res);
+
+    /* specific popw test */
+    asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0"
+                  : "=g" (res));
+    printf("popw esp=" FMTLX "\n", res);
+#endif
+}
+
+uint8_t str_buffer[4096];
+
+#define TEST_STRING1(OP, size, DF, REP)\
+{\
+    long esi, edi, eax, ecx, eflags;\
+\
+    esi = (long)(str_buffer + sizeof(str_buffer) / 2);\
+    edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\
+    eax = i2l(0x12345678);\
+    ecx = 17;\
+\
+    asm volatile ("push $0\n\t"\
+                  "popf\n\t"\
+                  DF "\n\t"\
+                  REP #OP size "\n\t"\
+                  "cld\n\t"\
+                  "pushf\n\t"\
+                  "pop %4\n\t"\
+                  : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\
+                  : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\
+    printf("%-10s ESI=" FMTLX " EDI=" FMTLX " EAX=" FMTLX " ECX=" FMTLX " EFL=%04x\n",\
+           REP #OP size, esi, edi, eax, ecx,\
+           (int)(eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)));\
+}
+
+#define TEST_STRING(OP, REP)\
+    TEST_STRING1(OP, "b", "", REP);\
+    TEST_STRING1(OP, "w", "", REP);\
+    TEST_STRING1(OP, "l", "", REP);\
+    X86_64_ONLY(TEST_STRING1(OP, "q", "", REP));\
+    TEST_STRING1(OP, "b", "std", REP);\
+    TEST_STRING1(OP, "w", "std", REP);\
+    TEST_STRING1(OP, "l", "std", REP);\
+    X86_64_ONLY(TEST_STRING1(OP, "q", "std", REP))
+
+void test_string(void)
+{
+    int i;
+    for(i = 0;i < sizeof(str_buffer); i++)
+        str_buffer[i] = i + 0x56;
+   TEST_STRING(stos, "");
+   TEST_STRING(stos, "rep ");
+   TEST_STRING(lods, ""); /* to verify stos */
+   TEST_STRING(lods, "rep ");
+   TEST_STRING(movs, "");
+   TEST_STRING(movs, "rep ");
+   TEST_STRING(lods, ""); /* to verify stos */
+
+   /* XXX: better tests */
+   TEST_STRING(scas, "");
+   TEST_STRING(scas, "repz ");
+   TEST_STRING(scas, "repnz ");
+   TEST_STRING(cmps, "");
+   TEST_STRING(cmps, "repz ");
+   TEST_STRING(cmps, "repnz ");
+}
+
+#ifdef TEST_VM86
+/* VM86 test */
+
+static inline void set_bit(uint8_t *a, unsigned int bit)
+{
+    a[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
+{
+    return (uint8_t *)((seg << 4) + (reg & 0xffff));
+}
+
+static inline void pushw(struct vm86_regs *r, int val)
+{
+    r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
+    *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
+}
+
+static inline int vm86(int func, struct vm86plus_struct *v86)
+{
+    return syscall(__NR_vm86, func, v86);
+}
+
+extern char vm86_code_start;
+extern char vm86_code_end;
+
+#define VM86_CODE_CS 0x100
+#define VM86_CODE_IP 0x100
+
+void test_vm86(void)
+{
+    struct vm86plus_struct ctx;
+    struct vm86_regs *r;
+    uint8_t *vm86_mem;
+    int seg, ret;
+
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
+                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (vm86_mem == MAP_FAILED) {
+        printf("ERROR: could not map vm86 memory");
+        return;
+    }
+    memset(&ctx, 0, sizeof(ctx));
+
+    /* init basic registers */
+    r = &ctx.regs;
+    r->eip = VM86_CODE_IP;
+    r->esp = 0xfffe;
+    seg = VM86_CODE_CS;
+    r->cs = seg;
+    r->ss = seg;
+    r->ds = seg;
+    r->es = seg;
+    r->fs = seg;
+    r->gs = seg;
+    r->eflags = VIF_MASK;
+
+    /* move code to proper address. We use the same layout as a .com
+       dos program. */
+    memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
+           &vm86_code_start, &vm86_code_end - &vm86_code_start);
+
+    /* mark int 0x21 as being emulated */
+    set_bit((uint8_t *)&ctx.int_revectored, 0x21);
+
+    for(;;) {
+        ret = vm86(VM86_ENTER, &ctx);
+        switch(VM86_TYPE(ret)) {
+        case VM86_INTx:
+            {
+                int int_num, ah, v;
+
+                int_num = VM86_ARG(ret);
+                if (int_num != 0x21)
+                    goto unknown_int;
+                ah = (r->eax >> 8) & 0xff;
+                switch(ah) {
+                case 0x00: /* exit */
+                    goto the_end;
+                case 0x02: /* write char */
+                    {
+                        uint8_t c = r->edx;
+                        putchar(c);
+                    }
+                    break;
+                case 0x09: /* write string */
+                    {
+                        uint8_t c, *ptr;
+                        ptr = seg_to_linear(r->ds, r->edx);
+                        for(;;) {
+                            c = *ptr++;
+                            if (c == '$')
+                                break;
+                            putchar(c);
+                        }
+                        r->eax = (r->eax & ~0xff) | '$';
+                    }
+                    break;
+                case 0xff: /* extension: write eflags number in edx */
+                    v = (int)r->edx;
+#ifndef LINUX_VM86_IOPL_FIX
+                    v &= ~0x3000;
+#endif
+                    printf("%08x\n", v);
+                    break;
+                default:
+                unknown_int:
+                    printf("unsupported int 0x%02x\n", int_num);
+                    goto the_end;
+                }
+            }
+            break;
+        case VM86_SIGNAL:
+            /* a signal came, we just ignore that */
+            break;
+        case VM86_STI:
+            break;
+        default:
+            printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
+            goto the_end;
+        }
+    }
+ the_end:
+    printf("VM86 end\n");
+    munmap(vm86_mem, 0x110000);
+}
+#endif
+
+/* exception tests */
+#if defined(__i386__) && !defined(REG_EAX)
+#define REG_EAX EAX
+#define REG_EBX EBX
+#define REG_ECX ECX
+#define REG_EDX EDX
+#define REG_ESI ESI
+#define REG_EDI EDI
+#define REG_EBP EBP
+#define REG_ESP ESP
+#define REG_EIP EIP
+#define REG_EFL EFL
+#define REG_TRAPNO TRAPNO
+#define REG_ERR ERR
+#endif
+
+#if defined(__x86_64__)
+#define REG_EIP REG_RIP
+#endif
+
+jmp_buf jmp_env;
+int v1;
+int tab[2];
+
+void sig_handler(int sig, siginfo_t *info, void *puc)
+{
+    struct ucontext *uc = puc;
+
+    printf("si_signo=%d si_errno=%d si_code=%d",
+           info->si_signo, info->si_errno, info->si_code);
+    printf(" si_addr=0x%08lx",
+           (unsigned long)info->si_addr);
+    printf("\n");
+
+    printf("trapno=" FMTLX " err=" FMTLX,
+           (long)uc->uc_mcontext.gregs[REG_TRAPNO],
+           (long)uc->uc_mcontext.gregs[REG_ERR]);
+    printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]);
+    printf("\n");
+    longjmp(jmp_env, 1);
+}
+
+void test_exceptions(void)
+{
+    struct sigaction act;
+    volatile int val;
+
+    act.sa_sigaction = sig_handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO | SA_NODEFER;
+    sigaction(SIGFPE, &act, NULL);
+    sigaction(SIGILL, &act, NULL);
+    sigaction(SIGSEGV, &act, NULL);
+    sigaction(SIGBUS, &act, NULL);
+    sigaction(SIGTRAP, &act, NULL);
+
+    /* test division by zero reporting */
+    printf("DIVZ exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* now divide by zero */
+        v1 = 0;
+        v1 = 2 / v1;
+    }
+
+#if !defined(__x86_64__)
+    printf("BOUND exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* bound exception */
+        tab[0] = 1;
+        tab[1] = 10;
+        asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0]));
+    }
+#endif
+
+#ifdef TEST_SEGS
+    printf("segment exceptions:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* load an invalid segment */
+        asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
+    }
+    if (setjmp(jmp_env) == 0) {
+        /* null data segment is valid */
+        asm volatile ("movl %0, %%fs" : : "r" (3));
+        /* null stack segment */
+        asm volatile ("movl %0, %%ss" : : "r" (3));
+    }
+
+    {
+        struct modify_ldt_ldt_s ldt;
+        ldt.entry_number = 1;
+        ldt.base_addr = (unsigned long)&seg_data1;
+        ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
+        ldt.seg_32bit = 1;
+        ldt.contents = MODIFY_LDT_CONTENTS_DATA;
+        ldt.read_exec_only = 0;
+        ldt.limit_in_pages = 1;
+        ldt.seg_not_present = 1;
+        ldt.useable = 1;
+        modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
+
+        if (setjmp(jmp_env) == 0) {
+            /* segment not present */
+            asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
+        }
+    }
+#endif
+
+    /* test SEGV reporting */
+    printf("PF exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        val = 1;
+        /* we add a nop to test a weird PC retrieval case */
+        asm volatile ("nop");
+        /* now store in an invalid address */
+        *(char *)0x1234 = 1;
+    }
+
+    /* test SEGV reporting */
+    printf("PF exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        val = 1;
+        /* read from an invalid address */
+        v1 = *(char *)0x1234;
+    }
+
+    /* test illegal instruction reporting */
+    printf("UD2 exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* now execute an invalid instruction */
+        asm volatile("ud2");
+    }
+    printf("lock nop exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* now execute an invalid instruction */
+        asm volatile("lock nop");
+    }
+
+    printf("INT exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("int $0xfd");
+    }
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("int $0x01");
+    }
+    if (setjmp(jmp_env) == 0) {
+        asm volatile (".byte 0xcd, 0x03");
+    }
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("int $0x04");
+    }
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("int $0x05");
+    }
+
+    printf("INT3 exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("int3");
+    }
+
+    printf("CLI exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("cli");
+    }
+
+    printf("STI exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("cli");
+    }
+
+#if !defined(__x86_64__)
+    printf("INTO exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        /* overflow exception */
+        asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
+    }
+#endif
+
+    printf("OUTB exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
+    }
+
+    printf("INB exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
+    }
+
+    printf("REP OUTSB exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
+    }
+
+    printf("REP INSB exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
+    }
+
+    printf("HLT exception:\n");
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("hlt");
+    }
+
+    printf("single step exception:\n");
+    val = 0;
+    if (setjmp(jmp_env) == 0) {
+        asm volatile ("pushf\n"
+                      "orl $0x00100, (%%esp)\n"
+                      "popf\n"
+                      "movl $0xabcd, %0\n"
+                      "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
+    }
+    printf("val=0x%x\n", val);
+}
+
+#if !defined(__x86_64__)
+/* specific precise single step test */
+void sig_trap_handler(int sig, siginfo_t *info, void *puc)
+{
+    struct ucontext *uc = puc;
+    printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]);
+}
+
+const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
+uint8_t sstep_buf2[4];
+
+void test_single_step(void)
+{
+    struct sigaction act;
+    volatile int val;
+    int i;
+
+    val = 0;
+    act.sa_sigaction = sig_trap_handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_SIGINFO;
+    sigaction(SIGTRAP, &act, NULL);
+    asm volatile ("pushf\n"
+                  "orl $0x00100, (%%esp)\n"
+                  "popf\n"
+                  "movl $0xabcd, %0\n"
+
+                  /* jmp test */
+                  "movl $3, %%ecx\n"
+                  "1:\n"
+                  "addl $1, %0\n"
+                  "decl %%ecx\n"
+                  "jnz 1b\n"
+
+                  /* movsb: the single step should stop at each movsb iteration */
+                  "movl $sstep_buf1, %%esi\n"
+                  "movl $sstep_buf2, %%edi\n"
+                  "movl $0, %%ecx\n"
+                  "rep movsb\n"
+                  "movl $3, %%ecx\n"
+                  "rep movsb\n"
+                  "movl $1, %%ecx\n"
+                  "rep movsb\n"
+
+                  /* cmpsb: the single step should stop at each cmpsb iteration */
+                  "movl $sstep_buf1, %%esi\n"
+                  "movl $sstep_buf2, %%edi\n"
+                  "movl $0, %%ecx\n"
+                  "rep cmpsb\n"
+                  "movl $4, %%ecx\n"
+                  "rep cmpsb\n"
+
+                  /* getpid() syscall: single step should skip one
+                     instruction */
+                  "movl $20, %%eax\n"
+                  "int $0x80\n"
+                  "movl $0, %%eax\n"
+
+                  /* when modifying SS, trace is not done on the next
+                     instruction */
+                  "movl %%ss, %%ecx\n"
+                  "movl %%ecx, %%ss\n"
+                  "addl $1, %0\n"
+                  "movl $1, %%eax\n"
+                  "movl %%ecx, %%ss\n"
+                  "jmp 1f\n"
+                  "addl $1, %0\n"
+                  "1:\n"
+                  "movl $1, %%eax\n"
+                  "pushl %%ecx\n"
+                  "popl %%ss\n"
+                  "addl $1, %0\n"
+                  "movl $1, %%eax\n"
+
+                  "pushf\n"
+                  "andl $~0x00100, (%%esp)\n"
+                  "popf\n"
+                  : "=m" (val)
+                  :
+                  : "cc", "memory", "eax", "ecx", "esi", "edi");
+    printf("val=%d\n", val);
+    for(i = 0; i < 4; i++)
+        printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);
+}
+
+/* self modifying code test */
+uint8_t code[] = {
+    0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
+    0xc3, /* ret */
+};
+
+asm(".section \".data\"\n"
+    "smc_code2:\n"
+    "movl 4(%esp), %eax\n"
+    "movl %eax, smc_patch_addr2 + 1\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "nop\n"
+    "smc_patch_addr2:\n"
+    "movl $1, %eax\n"
+    "ret\n"
+    ".previous\n"
+    );
+
+typedef int FuncType(void);
+extern int smc_code2(int);
+void test_self_modifying_code(void)
+{
+    int i;
+    printf("self modifying code:\n");
+    printf("func1 = 0x%x\n", ((FuncType *)code)());
+    for(i = 2; i <= 4; i++) {
+        code[1] = i;
+        printf("func%d = 0x%x\n", i, ((FuncType *)code)());
+    }
+
+    /* more difficult test : the modified code is just after the
+       modifying instruction. It is forbidden in Intel specs, but it
+       is used by old DOS programs */
+    for(i = 2; i <= 4; i++) {
+        printf("smc_code2(%d) = %d\n", i, smc_code2(i));
+    }
+}
+#endif
+
+long enter_stack[4096];
+
+#if defined(__x86_64__)
+#define RSP "%%rsp"
+#define RBP "%%rbp"
+#else
+#define RSP "%%esp"
+#define RBP "%%ebp"
+#endif
+
+#if !defined(__x86_64__)
+/* causes an infinite loop, disable it for now.  */
+#define TEST_ENTER(size, stack_type, level)
+#else
+#define TEST_ENTER(size, stack_type, level)\
+{\
+    long esp_save, esp_val, ebp_val, ebp_save, i;\
+    stack_type *ptr, *stack_end, *stack_ptr;\
+    memset(enter_stack, 0, sizeof(enter_stack));\
+    stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\
+    ebp_val = (long)stack_ptr;\
+    for(i=1;i<=32;i++)\
+       *--stack_ptr = i;\
+    esp_val = (long)stack_ptr;\
+    asm("mov " RSP ", %[esp_save]\n"\
+        "mov " RBP ", %[ebp_save]\n"\
+        "mov %[esp_val], " RSP "\n"\
+        "mov %[ebp_val], " RBP "\n"\
+        "enter" size " $8, $" #level "\n"\
+        "mov " RSP ", %[esp_val]\n"\
+        "mov " RBP ", %[ebp_val]\n"\
+        "mov %[esp_save], " RSP "\n"\
+        "mov %[ebp_save], " RBP "\n"\
+        : [esp_save] "=r" (esp_save),\
+        [ebp_save] "=r" (ebp_save),\
+        [esp_val] "=r" (esp_val),\
+        [ebp_val] "=r" (ebp_val)\
+        :  "[esp_val]" (esp_val),\
+        "[ebp_val]" (ebp_val));\
+    printf("level=%d:\n", level);\
+    printf("esp_val=" FMTLX "\n", esp_val - (long)stack_end);\
+    printf("ebp_val=" FMTLX "\n", ebp_val - (long)stack_end);\
+    for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\
+        printf(FMTLX "\n", (long)ptr[0]);\
+}
+#endif
+
+static void test_enter(void)
+{
+#if defined(__x86_64__)
+    TEST_ENTER("q", uint64_t, 0);
+    TEST_ENTER("q", uint64_t, 1);
+    TEST_ENTER("q", uint64_t, 2);
+    TEST_ENTER("q", uint64_t, 31);
+#else
+    TEST_ENTER("l", uint32_t, 0);
+    TEST_ENTER("l", uint32_t, 1);
+    TEST_ENTER("l", uint32_t, 2);
+    TEST_ENTER("l", uint32_t, 31);
+#endif
+
+    TEST_ENTER("w", uint16_t, 0);
+    TEST_ENTER("w", uint16_t, 1);
+    TEST_ENTER("w", uint16_t, 2);
+    TEST_ENTER("w", uint16_t, 31);
+}
+
+#ifdef TEST_SSE
+
+typedef int __m64 __attribute__ ((__mode__ (__V2SI__)));
+typedef float __m128 __attribute__ ((__mode__(__V4SF__)));
+
+typedef union {
+    double d[2];
+    float s[4];
+    uint32_t l[4];
+    uint64_t q[2];
+    __m128 dq;
+} XMMReg;
+
+static uint64_t __attribute__((aligned(16))) test_values[4][2] = {
+    { 0x456723c698694873, 0xdc515cff944a58ec },
+    { 0x1f297ccd58bad7ab, 0x41f21efba9e3e146 },
+    { 0x007c62c2085427f8, 0x231be9e8cde7438d },
+    { 0x0f76255a085427f8, 0xc233e9e8c4c9439a },
+};
+
+#define SSE_OP(op)\
+{\
+    asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           b.q[1], b.q[0],\
+           r.q[1], r.q[0]);\
+}
+
+#define SSE_OP2(op)\
+{\
+    int i;\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    a.q[1] = test_values[2*i][1];\
+    b.q[0] = test_values[2*i+1][0];\
+    b.q[1] = test_values[2*i+1][1];\
+    SSE_OP(op);\
+    }\
+}
+
+#define MMX_OP2(op)\
+{\
+    int i;\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    b.q[0] = test_values[2*i+1][0];\
+    asm volatile (#op " %2, %0" : "=y" (r.q[0]) : "0" (a.q[0]), "y" (b.q[0]));\
+    printf("%-9s: a=" FMT64X " b=" FMT64X " r=" FMT64X "\n",\
+           #op,\
+           a.q[0],\
+           b.q[0],\
+           r.q[0]);\
+    }\
+    SSE_OP2(op);\
+}
+
+#define SHUF_OP(op, ib)\
+{\
+    a.q[0] = test_values[0][0];\
+    a.q[1] = test_values[0][1];\
+    b.q[0] = test_values[1][0];\
+    b.q[1] = test_values[1][1];\
+    asm volatile (#op " $" #ib ", %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           b.q[1], b.q[0],\
+           ib,\
+           r.q[1], r.q[0]);\
+}
+
+#define PSHUF_OP(op, ib)\
+{\
+    int i;\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    a.q[1] = test_values[2*i][1];\
+    asm volatile (#op " $" #ib ", %1, %0" : "=x" (r.dq) : "x" (a.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           ib,\
+           r.q[1], r.q[0]);\
+    }\
+}
+
+#define SHIFT_IM(op, ib)\
+{\
+    int i;\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    a.q[1] = test_values[2*i][1];\
+    asm volatile (#op " $" #ib ", %0" : "=x" (r.dq) : "0" (a.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           ib,\
+           r.q[1], r.q[0]);\
+    }\
+}
+
+#define SHIFT_OP(op, ib)\
+{\
+    int i;\
+    SHIFT_IM(op, ib);\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    a.q[1] = test_values[2*i][1];\
+    b.q[0] = ib;\
+    b.q[1] = 0;\
+    asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           b.q[1], b.q[0],\
+           r.q[1], r.q[0]);\
+    }\
+}
+
+#define MOVMSK(op)\
+{\
+    int i, reg;\
+    for(i=0;i<2;i++) {\
+    a.q[0] = test_values[2*i][0];\
+    a.q[1] = test_values[2*i][1];\
+    asm volatile (#op " %1, %0" : "=r" (reg) : "x" (a.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           reg);\
+    }\
+}
+
+#define SSE_OPS(a) \
+SSE_OP(a ## ps);\
+SSE_OP(a ## ss);
+
+#define SSE_OPD(a) \
+SSE_OP(a ## pd);\
+SSE_OP(a ## sd);
+
+#define SSE_COMI(op, field)\
+{\
+    unsigned int eflags;\
+    XMMReg a, b;\
+    a.field[0] = a1;\
+    b.field[0] = b1;\
+    asm volatile (#op " %2, %1\n"\
+        "pushf\n"\
+        "pop %0\n"\
+        : "=m" (eflags)\
+        : "x" (a.dq), "x" (b.dq));\
+    printf("%-9s: a=%f b=%f cc=%04x\n",\
+           #op, a1, b1,\
+           eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\
+}
+
+void test_sse_comi(double a1, double b1)
+{
+    SSE_COMI(ucomiss, s);
+    SSE_COMI(ucomisd, d);
+    SSE_COMI(comiss, s);
+    SSE_COMI(comisd, d);
+}
+
+#define CVT_OP_XMM(op)\
+{\
+    asm volatile (#op " %1, %0" : "=x" (r.dq) : "x" (a.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           r.q[1], r.q[0]);\
+}
+
+/* Force %xmm0 usage to avoid the case where both register index are 0
+   to test instruction decoding more extensively */
+#define CVT_OP_XMM2MMX(op)\
+{\
+    asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \
+                  : "%xmm0"); \
+    asm volatile("emms\n"); \
+    printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           r.q[0]);\
+}
+
+#define CVT_OP_MMX2XMM(op)\
+{\
+    asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\
+    asm volatile("emms\n"); \
+    printf("%-9s: a=" FMT64X " r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.q[0],\
+           r.q[1], r.q[0]);\
+}
+
+#define CVT_OP_REG2XMM(op)\
+{\
+    asm volatile (#op " %1, %0" : "=x" (r.dq) : "r" (a.l[0]));\
+    printf("%-9s: a=%08x r=" FMT64X "" FMT64X "\n",\
+           #op,\
+           a.l[0],\
+           r.q[1], r.q[0]);\
+}
+
+#define CVT_OP_XMM2REG(op)\
+{\
+    asm volatile (#op " %1, %0" : "=r" (r.l[0]) : "x" (a.dq));\
+    printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\
+           #op,\
+           a.q[1], a.q[0],\
+           r.l[0]);\
+}
+
+struct fpxstate {
+    uint16_t fpuc;
+    uint16_t fpus;
+    uint16_t fptag;
+    uint16_t fop;
+    uint32_t fpuip;
+    uint16_t cs_sel;
+    uint16_t dummy0;
+    uint32_t fpudp;
+    uint16_t ds_sel;
+    uint16_t dummy1;
+    uint32_t mxcsr;
+    uint32_t mxcsr_mask;
+    uint8_t fpregs1[8 * 16];
+    uint8_t xmm_regs[8 * 16];
+    uint8_t dummy2[224];
+};
+
+static struct fpxstate fpx_state __attribute__((aligned(16)));
+static struct fpxstate fpx_state2 __attribute__((aligned(16)));
+
+void test_fxsave(void)
+{
+    struct fpxstate *fp = &fpx_state;
+    struct fpxstate *fp2 = &fpx_state2;
+    int i, nb_xmm;
+    XMMReg a, b;
+    a.q[0] = test_values[0][0];
+    a.q[1] = test_values[0][1];
+    b.q[0] = test_values[1][0];
+    b.q[1] = test_values[1][1];
+
+    asm("movdqa %2, %%xmm0\n"
+        "movdqa %3, %%xmm7\n"
+#if defined(__x86_64__)
+        "movdqa %2, %%xmm15\n"
+#endif
+        " fld1\n"
+        " fldpi\n"
+        " fldln2\n"
+        " fxsave %0\n"
+        " fxrstor %0\n"
+        " fxsave %1\n"
+        " fninit\n"
+        : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp)
+        : "m" (a), "m" (b));
+    printf("fpuc=%04x\n", fp->fpuc);
+    printf("fpus=%04x\n", fp->fpus);
+    printf("fptag=%04x\n", fp->fptag);
+    for(i = 0; i < 3; i++) {
+        printf("ST%d: " FMT64X " %04x\n",
+               i,
+               *(uint64_t *)&fp->fpregs1[i * 16],
+               *(uint16_t *)&fp->fpregs1[i * 16 + 8]);
+    }
+    printf("mxcsr=%08x\n", fp->mxcsr & 0x1f80);
+#if defined(__x86_64__)
+    nb_xmm = 16;
+#else
+    nb_xmm = 8;
+#endif
+    for(i = 0; i < nb_xmm; i++) {
+        printf("xmm%d: " FMT64X "" FMT64X "\n",
+               i,
+               *(uint64_t *)&fp->xmm_regs[i * 16],
+               *(uint64_t *)&fp->xmm_regs[i * 16 + 8]);
+    }
+}
+
+void test_sse(void)
+{
+    XMMReg r, a, b;
+    int i;
+
+    MMX_OP2(punpcklbw);
+    MMX_OP2(punpcklwd);
+    MMX_OP2(punpckldq);
+    MMX_OP2(packsswb);
+    MMX_OP2(pcmpgtb);
+    MMX_OP2(pcmpgtw);
+    MMX_OP2(pcmpgtd);
+    MMX_OP2(packuswb);
+    MMX_OP2(punpckhbw);
+    MMX_OP2(punpckhwd);
+    MMX_OP2(punpckhdq);
+    MMX_OP2(packssdw);
+    MMX_OP2(pcmpeqb);
+    MMX_OP2(pcmpeqw);
+    MMX_OP2(pcmpeqd);
+
+    MMX_OP2(paddq);
+    MMX_OP2(pmullw);
+    MMX_OP2(psubusb);
+    MMX_OP2(psubusw);
+    MMX_OP2(pminub);
+    MMX_OP2(pand);
+    MMX_OP2(paddusb);
+    MMX_OP2(paddusw);
+    MMX_OP2(pmaxub);
+    MMX_OP2(pandn);
+
+    MMX_OP2(pmulhuw);
+    MMX_OP2(pmulhw);
+
+    MMX_OP2(psubsb);
+    MMX_OP2(psubsw);
+    MMX_OP2(pminsw);
+    MMX_OP2(por);
+    MMX_OP2(paddsb);
+    MMX_OP2(paddsw);
+    MMX_OP2(pmaxsw);
+    MMX_OP2(pxor);
+    MMX_OP2(pmuludq);
+    MMX_OP2(pmaddwd);
+    MMX_OP2(psadbw);
+    MMX_OP2(psubb);
+    MMX_OP2(psubw);
+    MMX_OP2(psubd);
+    MMX_OP2(psubq);
+    MMX_OP2(paddb);
+    MMX_OP2(paddw);
+    MMX_OP2(paddd);
+
+    MMX_OP2(pavgb);
+    MMX_OP2(pavgw);
+
+    asm volatile ("pinsrw $1, %1, %0" : "=y" (r.q[0]) : "r" (0x12345678));
+    printf("%-9s: r=" FMT64X "\n", "pinsrw", r.q[0]);
+
+    asm volatile ("pinsrw $5, %1, %0" : "=x" (r.dq) : "r" (0x12345678));
+    printf("%-9s: r=" FMT64X "" FMT64X "\n", "pinsrw", r.q[1], r.q[0]);
+
+    a.q[0] = test_values[0][0];
+    a.q[1] = test_values[0][1];
+    asm volatile ("pextrw $1, %1, %0" : "=r" (r.l[0]) : "y" (a.q[0]));
+    printf("%-9s: r=%08x\n", "pextrw", r.l[0]);
+
+    asm volatile ("pextrw $5, %1, %0" : "=r" (r.l[0]) : "x" (a.dq));
+    printf("%-9s: r=%08x\n", "pextrw", r.l[0]);
+
+    asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0]));
+    printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]);
+
+    asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq));
+    printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]);
+
+    {
+        r.q[0] = -1;
+        r.q[1] = -1;
+
+        a.q[0] = test_values[0][0];
+        a.q[1] = test_values[0][1];
+        b.q[0] = test_values[1][0];
+        b.q[1] = test_values[1][1];
+        asm volatile("maskmovq %1, %0" :
+                     : "y" (a.q[0]), "y" (b.q[0]), "D" (&r)
+                     : "memory");
+        printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n",
+               "maskmov",
+               r.q[0],
+               a.q[0],
+               b.q[0]);
+        asm volatile("maskmovdqu %1, %0" :
+                     : "x" (a.dq), "x" (b.dq), "D" (&r)
+                     : "memory");
+        printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n",
+               "maskmov",
+               r.q[1], r.q[0],
+               a.q[1], a.q[0],
+               b.q[1], b.q[0]);
+    }
+
+    asm volatile ("emms");
+
+    SSE_OP2(punpcklqdq);
+    SSE_OP2(punpckhqdq);
+    SSE_OP2(andps);
+    SSE_OP2(andpd);
+    SSE_OP2(andnps);
+    SSE_OP2(andnpd);
+    SSE_OP2(orps);
+    SSE_OP2(orpd);
+    SSE_OP2(xorps);
+    SSE_OP2(xorpd);
+
+    SSE_OP2(unpcklps);
+    SSE_OP2(unpcklpd);
+    SSE_OP2(unpckhps);
+    SSE_OP2(unpckhpd);
+
+    SHUF_OP(shufps, 0x78);
+    SHUF_OP(shufpd, 0x02);
+
+    PSHUF_OP(pshufd, 0x78);
+    PSHUF_OP(pshuflw, 0x78);
+    PSHUF_OP(pshufhw, 0x78);
+
+    SHIFT_OP(psrlw, 7);
+    SHIFT_OP(psrlw, 16);
+    SHIFT_OP(psraw, 7);
+    SHIFT_OP(psraw, 16);
+    SHIFT_OP(psllw, 7);
+    SHIFT_OP(psllw, 16);
+
+    SHIFT_OP(psrld, 7);
+    SHIFT_OP(psrld, 32);
+    SHIFT_OP(psrad, 7);
+    SHIFT_OP(psrad, 32);
+    SHIFT_OP(pslld, 7);
+    SHIFT_OP(pslld, 32);
+
+    SHIFT_OP(psrlq, 7);
+    SHIFT_OP(psrlq, 32);
+    SHIFT_OP(psllq, 7);
+    SHIFT_OP(psllq, 32);
+
+    SHIFT_IM(psrldq, 16);
+    SHIFT_IM(psrldq, 7);
+    SHIFT_IM(pslldq, 16);
+    SHIFT_IM(pslldq, 7);
+
+    MOVMSK(movmskps);
+    MOVMSK(movmskpd);
+
+    /* FPU specific ops */
+
+    {
+        uint32_t mxcsr;
+        asm volatile("stmxcsr %0" : "=m" (mxcsr));
+        printf("mxcsr=%08x\n", mxcsr & 0x1f80);
+        asm volatile("ldmxcsr %0" : : "m" (mxcsr));
+    }
+
+    test_sse_comi(2, -1);
+    test_sse_comi(2, 2);
+    test_sse_comi(2, 3);
+    test_sse_comi(2, q_nan.d);
+    test_sse_comi(q_nan.d, -1);
+
+    for(i = 0; i < 2; i++) {
+        a.s[0] = 2.7;
+        a.s[1] = 3.4;
+        a.s[2] = 4;
+        a.s[3] = -6.3;
+        b.s[0] = 45.7;
+        b.s[1] = 353.4;
+        b.s[2] = 4;
+        b.s[3] = 56.3;
+        if (i == 1) {
+            a.s[0] = q_nan.d;
+            b.s[3] = q_nan.d;
+        }
+
+        SSE_OPS(add);
+        SSE_OPS(mul);
+        SSE_OPS(sub);
+        SSE_OPS(min);
+        SSE_OPS(div);
+        SSE_OPS(max);
+        SSE_OPS(sqrt);
+        SSE_OPS(cmpeq);
+        SSE_OPS(cmplt);
+        SSE_OPS(cmple);
+        SSE_OPS(cmpunord);
+        SSE_OPS(cmpneq);
+        SSE_OPS(cmpnlt);
+        SSE_OPS(cmpnle);
+        SSE_OPS(cmpord);
+
+
+        a.d[0] = 2.7;
+        a.d[1] = -3.4;
+        b.d[0] = 45.7;
+        b.d[1] = -53.4;
+        if (i == 1) {
+            a.d[0] = q_nan.d;
+            b.d[1] = q_nan.d;
+        }
+        SSE_OPD(add);
+        SSE_OPD(mul);
+        SSE_OPD(sub);
+        SSE_OPD(min);
+        SSE_OPD(div);
+        SSE_OPD(max);
+        SSE_OPD(sqrt);
+        SSE_OPD(cmpeq);
+        SSE_OPD(cmplt);
+        SSE_OPD(cmple);
+        SSE_OPD(cmpunord);
+        SSE_OPD(cmpneq);
+        SSE_OPD(cmpnlt);
+        SSE_OPD(cmpnle);
+        SSE_OPD(cmpord);
+    }
+
+    /* float to float/int */
+    a.s[0] = 2.7;
+    a.s[1] = 3.4;
+    a.s[2] = 4;
+    a.s[3] = -6.3;
+    CVT_OP_XMM(cvtps2pd);
+    CVT_OP_XMM(cvtss2sd);
+    CVT_OP_XMM2MMX(cvtps2pi);
+    CVT_OP_XMM2MMX(cvttps2pi);
+    CVT_OP_XMM2REG(cvtss2si);
+    CVT_OP_XMM2REG(cvttss2si);
+    CVT_OP_XMM(cvtps2dq);
+    CVT_OP_XMM(cvttps2dq);
+
+    a.d[0] = 2.6;
+    a.d[1] = -3.4;
+    CVT_OP_XMM(cvtpd2ps);
+    CVT_OP_XMM(cvtsd2ss);
+    CVT_OP_XMM2MMX(cvtpd2pi);
+    CVT_OP_XMM2MMX(cvttpd2pi);
+    CVT_OP_XMM2REG(cvtsd2si);
+    CVT_OP_XMM2REG(cvttsd2si);
+    CVT_OP_XMM(cvtpd2dq);
+    CVT_OP_XMM(cvttpd2dq);
+
+    /* sse/mmx moves */
+    CVT_OP_XMM2MMX(movdq2q);
+    CVT_OP_MMX2XMM(movq2dq);
+
+    /* int to float */
+    a.l[0] = -6;
+    a.l[1] = 2;
+    a.l[2] = 100;
+    a.l[3] = -60000;
+    CVT_OP_MMX2XMM(cvtpi2ps);
+    CVT_OP_MMX2XMM(cvtpi2pd);
+    CVT_OP_REG2XMM(cvtsi2ss);
+    CVT_OP_REG2XMM(cvtsi2sd);
+    CVT_OP_XMM(cvtdq2ps);
+    CVT_OP_XMM(cvtdq2pd);
+
+    /* XXX: test PNI insns */
+#if 0
+    SSE_OP2(movshdup);
+#endif
+    asm volatile ("emms");
+}
+
+#endif
+
+#define TEST_CONV_RAX(op)\
+{\
+    unsigned long a, r;\
+    a = i2l(0x8234a6f8);\
+    r = a;\
+    asm volatile(#op : "=a" (r) : "0" (r));\
+    printf("%-10s A=" FMTLX " R=" FMTLX "\n", #op, a, r);\
+}
+
+#define TEST_CONV_RAX_RDX(op)\
+{\
+    unsigned long a, d, r, rh;                   \
+    a = i2l(0x8234a6f8);\
+    d = i2l(0x8345a1f2);\
+    r = a;\
+    rh = d;\
+    asm volatile(#op : "=a" (r), "=d" (rh) : "0" (r), "1" (rh));   \
+    printf("%-10s A=" FMTLX " R=" FMTLX ":" FMTLX "\n", #op, a, r, rh);  \
+}
+
+void test_conv(void)
+{
+    TEST_CONV_RAX(cbw);
+    TEST_CONV_RAX(cwde);
+#if defined(__x86_64__)
+    TEST_CONV_RAX(cdqe);
+#endif
+
+    TEST_CONV_RAX_RDX(cwd);
+    TEST_CONV_RAX_RDX(cdq);
+#if defined(__x86_64__)
+    TEST_CONV_RAX_RDX(cqo);
+#endif
+
+    {
+        unsigned long a, r;
+        a = i2l(0x12345678);
+        asm volatile("bswapl %k0" : "=r" (r) : "0" (a));
+        printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapl", a, r);
+    }
+#if defined(__x86_64__)
+    {
+        unsigned long a, r;
+        a = i2l(0x12345678);
+        asm volatile("bswapq %0" : "=r" (r) : "0" (a));
+        printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapq", a, r);
+    }
+#endif
+}
+
+extern void *__start_initcall;
+extern void *__stop_initcall;
+
+
+int main(int argc, char **argv)
+{
+    void **ptr;
+    void (*func)(void);
+
+    ptr = &__start_initcall;
+    while (ptr != &__stop_initcall) {
+        func = *ptr++;
+        func();
+    }
+    test_bsx();
+    test_mul();
+    test_jcc();
+    test_loop();
+    test_floats();
+#if !defined(__x86_64__)
+    test_bcd();
+#endif
+    test_xchg();
+    test_string();
+    test_misc();
+    test_lea();
+#ifdef TEST_SEGS
+    test_segs();
+    test_code16();
+#endif
+#ifdef TEST_VM86
+    test_vm86();
+#endif
+#if !defined(__x86_64__)
+    test_exceptions();
+    test_self_modifying_code();
+    test_single_step();
+#endif
+    test_enter();
+    test_conv();
+#ifdef TEST_SSE
+    test_sse();
+    test_fxsave();
+#endif
+    return 0;
+}
diff --git a/qemu-0.15.x/tests/test-i386.h b/qemu-0.15.x/tests/test-i386.h
new file mode 100644
index 0000000..75106b8
--- /dev/null
+++ b/qemu-0.15.x/tests/test-i386.h
@@ -0,0 +1,152 @@
+
+#define exec_op glue(exec_, OP)
+#define exec_opq glue(glue(exec_, OP), q)
+#define exec_opl glue(glue(exec_, OP), l)
+#define exec_opw glue(glue(exec_, OP), w)
+#define exec_opb glue(glue(exec_, OP), b)
+
+#define EXECOP2(size, rsize, res, s1, flags) \
+    asm ("push %4\n\t"\
+         "popf\n\t"\
+         stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=q" (res), "=g" (flags)\
+         : "q" (s1), "0" (res), "1" (flags)); \
+    printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \
+           stringify(OP) size, s0, s1, res, iflags, flags & CC_MASK);
+
+#define EXECOP1(size, rsize, res, flags) \
+    asm ("push %3\n\t"\
+         "popf\n\t"\
+         stringify(OP) size " %" rsize "0\n\t" \
+         "pushf\n\t"\
+         "pop %1\n\t"\
+         : "=q" (res), "=g" (flags)\
+         : "0" (res), "1" (flags)); \
+    printf("%-10s A=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \
+           stringify(OP) size, s0, res, iflags, flags & CC_MASK);
+
+#ifdef OP1
+#if defined(__x86_64__)
+void exec_opq(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP1("q", "", res, flags);
+}
+#endif
+
+void exec_opl(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP1("l", "k", res, flags);
+}
+
+void exec_opw(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP1("w", "w", res, flags);
+}
+
+void exec_opb(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP1("b", "b", res, flags);
+}
+#else
+#if defined(__x86_64__)
+void exec_opq(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP2("q", "", res, s1, flags);
+}
+#endif
+
+void exec_opl(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP2("l", "k", res, s1, flags);
+}
+
+void exec_opw(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP2("w", "w", res, s1, flags);
+}
+
+void exec_opb(long s0, long s1, long iflags)
+{
+    long res, flags;
+    res = s0;
+    flags = iflags;
+    EXECOP2("b", "b", res, s1, flags);
+}
+#endif
+
+void exec_op(long s0, long s1)
+{
+    s0 = i2l(s0);
+    s1 = i2l(s1);
+#if defined(__x86_64__)
+    exec_opq(s0, s1, 0);
+#endif
+    exec_opl(s0, s1, 0);
+    exec_opw(s0, s1, 0);
+    exec_opb(s0, s1, 0);
+#ifdef OP_CC
+#if defined(__x86_64__)
+    exec_opq(s0, s1, CC_C);
+#endif
+    exec_opl(s0, s1, CC_C);
+    exec_opw(s0, s1, CC_C);
+    exec_opb(s0, s1, CC_C);
+#endif
+}
+
+void glue(test_, OP)(void)
+{
+    exec_op(0x12345678, 0x812FADA);
+    exec_op(0x12341, 0x12341);
+    exec_op(0x12341, -0x12341);
+    exec_op(0xffffffff, 0);
+    exec_op(0xffffffff, -1);
+    exec_op(0xffffffff, 1);
+    exec_op(0xffffffff, 2);
+    exec_op(0x7fffffff, 0);
+    exec_op(0x7fffffff, 1);
+    exec_op(0x7fffffff, -1);
+    exec_op(0x80000000, -1);
+    exec_op(0x80000000, 1);
+    exec_op(0x80000000, -2);
+    exec_op(0x12347fff, 0);
+    exec_op(0x12347fff, 1);
+    exec_op(0x12347fff, -1);
+    exec_op(0x12348000, -1);
+    exec_op(0x12348000, 1);
+    exec_op(0x12348000, -2);
+    exec_op(0x12347f7f, 0);
+    exec_op(0x12347f7f, 1);
+    exec_op(0x12347f7f, -1);
+    exec_op(0x12348080, -1);
+    exec_op(0x12348080, 1);
+    exec_op(0x12348080, -2);
+}
+
+void *glue(_test_, OP) __init_call = glue(test_, OP);
+
+#undef OP
+#undef OP_CC
diff --git a/qemu-0.15.x/tests/test-mmap.c b/qemu-0.15.x/tests/test-mmap.c
new file mode 100644
index 0000000..c67174a
--- /dev/null
+++ b/qemu-0.15.x/tests/test-mmap.c
@@ -0,0 +1,476 @@
+/*
+ * Small test program to verify simulated mmap behaviour.
+ *
+ * When running qemu-linux-user with the -p flag, you may need to tell
+ * this test program about the pagesize because getpagesize() will not reflect
+ * the -p choice. Simply pass one argument beeing the pagesize.
+ *
+ * Copyright (c) 2007 AXIS Communications AB
+ * Written by Edgar E. Iglesias.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#define D(x)
+
+#define fail_unless(x)                                         \
+do                                                             \
+{                                                              \
+  if (!(x)) {                                                  \
+    fprintf (stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \
+    exit (EXIT_FAILURE);                                       \
+  }                                                            \
+} while (0);
+
+unsigned char *dummybuf;
+static unsigned int pagesize;
+static unsigned int pagemask;
+int test_fd;
+size_t test_fsize;
+
+void check_aligned_anonymous_unfixed_mmaps(void)
+{
+	void *p1;
+	void *p2;
+	void *p3;
+	void *p4;
+	void *p5;
+	uintptr_t p;
+	int i;
+
+	fprintf (stderr, "%s", __func__);
+	for (i = 0; i < 0x1fff; i++)
+	{
+		size_t len;
+
+		len = pagesize + (pagesize * i & 7);
+		p1 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		p2 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		p3 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		p4 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		p5 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+		/* Make sure we get pages aligned with the pagesize. The
+		   target expects this.  */
+		fail_unless (p1 != MAP_FAILED);
+		fail_unless (p2 != MAP_FAILED);
+		fail_unless (p3 != MAP_FAILED);
+		fail_unless (p4 != MAP_FAILED);
+		fail_unless (p5 != MAP_FAILED);
+		p = (uintptr_t) p1;
+		D(printf ("p=%x\n", p));
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p2;
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p3;
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p4;
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p5;
+		fail_unless ((p & pagemask) == 0);
+
+		/* Make sure we can read from the entire area.  */
+		memcpy (dummybuf, p1, pagesize);
+		memcpy (dummybuf, p2, pagesize);
+		memcpy (dummybuf, p3, pagesize);
+		memcpy (dummybuf, p4, pagesize);
+		memcpy (dummybuf, p5, pagesize);
+
+		munmap (p1, len);
+		munmap (p2, len);
+		munmap (p3, len);
+		munmap (p4, len);
+		munmap (p5, len);
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_large_anonymous_unfixed_mmap(void)
+{
+	void *p1;
+	uintptr_t p;
+	size_t len;
+
+	fprintf (stderr, "%s", __func__);
+
+	len = 0x02000000;
+	p1 = mmap(NULL, len, PROT_READ, 
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+	/* Make sure we get pages aligned with the pagesize. The
+	   target expects this.  */
+	fail_unless (p1 != MAP_FAILED);
+	p = (uintptr_t) p1;
+	fail_unless ((p & pagemask) == 0);
+	
+	/* Make sure we can read from the entire area.  */
+	memcpy (dummybuf, p1, pagesize);
+	munmap (p1, len);
+	fprintf (stderr, " passed\n");
+}
+
+void check_aligned_anonymous_unfixed_colliding_mmaps(void)
+{
+	char *p1;
+	char *p2;
+	char *p3;
+	uintptr_t p;
+	int i;
+
+	fprintf (stderr, "%s", __func__);
+	for (i = 0; i < 0x2fff; i++)
+	{
+		int nlen;
+		p1 = mmap(NULL, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		fail_unless (p1 != MAP_FAILED);
+		p = (uintptr_t) p1;
+		fail_unless ((p & pagemask) == 0);
+		memcpy (dummybuf, p1, pagesize);
+
+		p2 = mmap(NULL, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		fail_unless (p2 != MAP_FAILED);
+		p = (uintptr_t) p2;
+		fail_unless ((p & pagemask) == 0);
+		memcpy (dummybuf, p2, pagesize);
+
+
+		munmap (p1, pagesize);
+		nlen = pagesize * 8;
+		p3 = mmap(NULL, nlen, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		fail_unless (p3 != MAP_FAILED);
+
+		/* Check if the mmaped areas collide.  */
+		if (p3 < p2 
+		    && (p3 + nlen) > p2)
+			fail_unless (0);
+
+		memcpy (dummybuf, p3, pagesize);
+
+		/* Make sure we get pages aligned with the pagesize. The
+		   target expects this.  */
+		p = (uintptr_t) p3;
+		fail_unless ((p & pagemask) == 0);
+		munmap (p2, pagesize);
+		munmap (p3, nlen);
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_aligned_anonymous_fixed_mmaps(void)
+{
+	char *addr;
+	void *p1;
+	uintptr_t p;
+	int i;
+
+	/* Find a suitable address to start with.  */
+	addr = mmap(NULL, pagesize * 40, PROT_READ | PROT_WRITE, 
+		    MAP_PRIVATE | MAP_ANONYMOUS,
+		    -1, 0);
+	fprintf (stderr, "%s addr=%p", __func__, addr);
+	fail_unless (addr != MAP_FAILED);
+
+	for (i = 0; i < 40; i++)
+	{
+		/* Create submaps within our unfixed map.  */
+		p1 = mmap(addr, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+			  -1, 0);
+		/* Make sure we get pages aligned with the pagesize. 
+		   The target expects this.  */
+		p = (uintptr_t) p1;
+		fail_unless (p1 == addr);
+		fail_unless ((p & pagemask) == 0);		
+		memcpy (dummybuf, p1, pagesize);
+		munmap (p1, pagesize);
+		addr += pagesize;
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_aligned_anonymous_fixed_mmaps_collide_with_host(void)
+{
+	char *addr;
+	void *p1;
+	uintptr_t p;
+	int i;
+
+	/* Find a suitable address to start with.  Right were the x86 hosts
+	 stack is.  */
+	addr = ((void *)0x80000000);
+	fprintf (stderr, "%s addr=%p", __func__, addr);
+	fprintf (stderr, "FIXME: QEMU fails to track pages used by the host.");
+
+	for (i = 0; i < 20; i++)
+	{
+		/* Create submaps within our unfixed map.  */
+		p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE, 
+			  MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+			  -1, 0);
+		/* Make sure we get pages aligned with the pagesize. 
+		   The target expects this.  */
+		p = (uintptr_t) p1;
+		fail_unless (p1 == addr);
+		fail_unless ((p & pagemask) == 0);		
+		memcpy (p1, dummybuf, pagesize);
+		munmap (p1, pagesize);
+		addr += pagesize;
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_file_unfixed_mmaps(void)
+{
+	unsigned int *p1, *p2, *p3;
+	uintptr_t p;
+	int i;
+
+	fprintf (stderr, "%s", __func__);
+	for (i = 0; i < 0x10; i++)
+	{
+		size_t len;
+
+		len = pagesize;
+		p1 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE, 
+			  test_fd, 0);
+		p2 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE, 
+			  test_fd, pagesize);
+		p3 = mmap(NULL, len, PROT_READ, 
+			  MAP_PRIVATE, 
+			  test_fd, pagesize * 2);
+
+		fail_unless (p1 != MAP_FAILED);
+		fail_unless (p2 != MAP_FAILED);
+		fail_unless (p3 != MAP_FAILED);
+
+		/* Make sure we get pages aligned with the pagesize. The
+		   target expects this.  */
+		p = (uintptr_t) p1;
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p2;
+		fail_unless ((p & pagemask) == 0);
+		p = (uintptr_t) p3;
+		fail_unless ((p & pagemask) == 0);
+
+		/* Verify that the file maps was made correctly.  */
+		D(printf ("p1=%d p2=%d p3=%d\n", *p1, *p2, *p3));
+		fail_unless (*p1 == 0);
+		fail_unless (*p2 == (pagesize / sizeof *p2));
+		fail_unless (*p3 == ((pagesize * 2) / sizeof *p3));
+
+		memcpy (dummybuf, p1, pagesize);
+		memcpy (dummybuf, p2, pagesize);
+		memcpy (dummybuf, p3, pagesize);
+		munmap (p1, len);
+		munmap (p2, len);
+		munmap (p3, len);
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_file_unfixed_eof_mmaps(void)
+{
+	char *cp;
+	unsigned int *p1;
+	uintptr_t p;
+	int i;
+
+	fprintf (stderr, "%s", __func__);
+	for (i = 0; i < 0x10; i++)
+	{
+		p1 = mmap(NULL, pagesize, PROT_READ, 
+			  MAP_PRIVATE, 
+			  test_fd, 
+			  (test_fsize - sizeof *p1) & ~pagemask);
+
+		fail_unless (p1 != MAP_FAILED);
+
+		/* Make sure we get pages aligned with the pagesize. The
+		   target expects this.  */
+		p = (uintptr_t) p1;
+		fail_unless ((p & pagemask) == 0);
+		/* Verify that the file maps was made correctly.  */
+		fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
+			     == ((test_fsize - sizeof *p1) / sizeof *p1));
+
+		/* Verify that the end of page is accessible and zeroed.  */
+		cp = (void *) p1;
+		fail_unless (cp[pagesize - 4] == 0);
+		munmap (p1, pagesize);
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_file_fixed_eof_mmaps(void)
+{
+	char *addr;
+	char *cp;
+	unsigned int *p1;
+	uintptr_t p;
+	int i;
+
+	/* Find a suitable address to start with.  */
+	addr = mmap(NULL, pagesize * 44, PROT_READ, 
+		    MAP_PRIVATE | MAP_ANONYMOUS,
+		    -1, 0);
+
+	fprintf (stderr, "%s addr=%p", __func__, (void *)addr);
+	fail_unless (addr != MAP_FAILED);
+
+	for (i = 0; i < 0x10; i++)
+	{
+		/* Create submaps within our unfixed map.  */
+		p1 = mmap(addr, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_FIXED, 
+			  test_fd, 
+			  (test_fsize - sizeof *p1) & ~pagemask);
+
+		fail_unless (p1 != MAP_FAILED);
+
+		/* Make sure we get pages aligned with the pagesize. The
+		   target expects this.  */
+		p = (uintptr_t) p1;
+		fail_unless ((p & pagemask) == 0);
+
+		/* Verify that the file maps was made correctly.  */
+		fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
+			     == ((test_fsize - sizeof *p1) / sizeof *p1));
+
+		/* Verify that the end of page is accessible and zeroed.  */
+		cp = (void *)p1;
+		fail_unless (cp[pagesize - 4] == 0);
+		munmap (p1, pagesize);
+		addr += pagesize;
+	}
+	fprintf (stderr, " passed\n");
+}
+
+void check_file_fixed_mmaps(void)
+{
+	unsigned char *addr;
+	unsigned int *p1, *p2, *p3, *p4;
+	int i;
+
+	/* Find a suitable address to start with.  */
+	addr = mmap(NULL, pagesize * 40 * 4, PROT_READ, 
+		    MAP_PRIVATE | MAP_ANONYMOUS,
+		    -1, 0);
+	fprintf (stderr, "%s addr=%p", __func__, (void *)addr);
+	fail_unless (addr != MAP_FAILED);
+
+	for (i = 0; i < 40; i++)
+	{
+		p1 = mmap(addr, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_FIXED,
+			  test_fd, 0);
+		p2 = mmap(addr + pagesize, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_FIXED,
+			  test_fd, pagesize);
+		p3 = mmap(addr + pagesize * 2, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_FIXED,
+			  test_fd, pagesize * 2);
+		p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ, 
+			  MAP_PRIVATE | MAP_FIXED,
+			  test_fd, pagesize * 3);
+
+		/* Make sure we get pages aligned with the pagesize. 
+		   The target expects this.  */
+		fail_unless (p1 == (void *)addr);
+		fail_unless (p2 == (void *)addr + pagesize);
+		fail_unless (p3 == (void *)addr + pagesize * 2);
+		fail_unless (p4 == (void *)addr + pagesize * 3);
+
+		/* Verify that the file maps was made correctly.  */
+		fail_unless (*p1 == 0);
+		fail_unless (*p2 == (pagesize / sizeof *p2));
+		fail_unless (*p3 == ((pagesize * 2) / sizeof *p3));
+		fail_unless (*p4 == ((pagesize * 3) / sizeof *p4));
+
+		memcpy (dummybuf, p1, pagesize);
+		memcpy (dummybuf, p2, pagesize);
+		memcpy (dummybuf, p3, pagesize);
+		memcpy (dummybuf, p4, pagesize);
+
+		munmap (p1, pagesize);
+		munmap (p2, pagesize);
+		munmap (p3, pagesize);
+		munmap (p4, pagesize);
+		addr += pagesize * 4;
+	}
+	fprintf (stderr, " passed\n");
+}
+
+int main(int argc, char **argv)
+{
+	char tempname[] = "/tmp/.cmmapXXXXXX";
+	unsigned int i;
+
+	/* Trust the first argument, otherwise probe the system for our
+	   pagesize.  */
+	if (argc > 1)
+		pagesize = strtoul(argv[1], NULL, 0);
+	else
+		pagesize = sysconf(_SC_PAGESIZE);
+
+	/* Assume pagesize is a power of two.  */
+	pagemask = pagesize - 1;
+	dummybuf = malloc (pagesize);
+	printf ("pagesize=%u pagemask=%x\n", pagesize, pagemask);
+
+	test_fd = mkstemp(tempname);
+	unlink(tempname);
+
+	/* Fill the file with int's counting from zero and up.  */
+	for (i = 0; i < (pagesize * 4) / sizeof i; i++)
+		write (test_fd, &i, sizeof i);
+	/* Append a few extra writes to make the file end at non 
+	   page boundary.  */
+	write (test_fd, &i, sizeof i); i++;
+	write (test_fd, &i, sizeof i); i++;
+	write (test_fd, &i, sizeof i); i++;
+
+	test_fsize = lseek(test_fd, 0, SEEK_CUR);
+
+	/* Run the tests.  */
+	check_aligned_anonymous_unfixed_mmaps();
+	check_aligned_anonymous_unfixed_colliding_mmaps();
+	check_aligned_anonymous_fixed_mmaps();
+	check_file_unfixed_mmaps();
+	check_file_fixed_mmaps();
+	check_file_fixed_eof_mmaps();
+	check_file_unfixed_eof_mmaps();
+
+	/* Fails at the moment.  */
+	/* check_aligned_anonymous_fixed_mmaps_collide_with_host(); */
+
+	return EXIT_SUCCESS;
+}
diff --git a/qemu-0.15.x/tests/test_path.c b/qemu-0.15.x/tests/test_path.c
new file mode 100644
index 0000000..234ed97
--- /dev/null
+++ b/qemu-0.15.x/tests/test_path.c
@@ -0,0 +1,160 @@
+/* Test path override code */
+#include "../config-host.h"
+#include "../qemu-malloc.c"
+#include "../cutils.c"
+#include "../path.c"
+#include "../trace.c"
+#ifdef CONFIG_SIMPLE_TRACE
+#include "../simpletrace.c"
+#endif
+
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void qemu_log(const char *fmt, ...);
+
+/* Any log message kills the test. */
+void qemu_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "FATAL: ");
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    exit(1);
+}
+
+#define NO_CHANGE(_path)						\
+	do {								\
+	    if (strcmp(path(_path), _path) != 0) return __LINE__;	\
+	} while(0)
+
+#define CHANGE_TO(_path, _newpath)					\
+	do {								\
+	    if (strcmp(path(_path), _newpath) != 0) return __LINE__;	\
+	} while(0)
+
+static void cleanup(void)
+{
+    unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2");
+    unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3");
+    unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4");
+    unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5");
+    rmdir("/tmp/qemu-test_path/DIR1/DIR2");
+    rmdir("/tmp/qemu-test_path/DIR1/DIR3");
+    rmdir("/tmp/qemu-test_path/DIR1");
+    rmdir("/tmp/qemu-test_path");
+}
+
+static unsigned int do_test(void)
+{
+    if (mkdir("/tmp/qemu-test_path", 0700) != 0)
+	return __LINE__;
+
+    if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0)
+	return __LINE__;
+
+    if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0)
+	return __LINE__;
+
+    if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0)
+	return __LINE__;
+
+    if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0)
+	return __LINE__;
+
+    if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0)
+	return __LINE__;
+
+    if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0)
+	return __LINE__;
+
+    if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0)
+	return __LINE__;
+
+    if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0)
+	return __LINE__;
+
+    init_paths("/tmp/qemu-test_path");
+
+    NO_CHANGE("/tmp");
+    NO_CHANGE("/tmp/");
+    NO_CHANGE("/tmp/qemu-test_path");
+    NO_CHANGE("/tmp/qemu-test_path/");
+    NO_CHANGE("/tmp/qemu-test_path/D");
+    NO_CHANGE("/tmp/qemu-test_path/DI");
+    NO_CHANGE("/tmp/qemu-test_path/DIR");
+    NO_CHANGE("/tmp/qemu-test_path/DIR1");
+    NO_CHANGE("/tmp/qemu-test_path/DIR1/");
+
+    NO_CHANGE("/D");
+    NO_CHANGE("/DI");
+    NO_CHANGE("/DIR");
+    NO_CHANGE("/DIR2");
+    NO_CHANGE("/DIR1.");
+
+    CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1");
+    CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1");
+
+    NO_CHANGE("/DIR1/D");
+    NO_CHANGE("/DIR1/DI");
+    NO_CHANGE("/DIR1/DIR");
+    NO_CHANGE("/DIR1/DIR1");
+
+    CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
+    CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2");
+
+    CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3");
+    CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3");
+
+    NO_CHANGE("/DIR1/DIR2/F");
+    NO_CHANGE("/DIR1/DIR2/FI");
+    NO_CHANGE("/DIR1/DIR2/FIL");
+    NO_CHANGE("/DIR1/DIR2/FIL.");
+
+    CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2");
+    CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3");
+    CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4");
+    CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5");
+
+    NO_CHANGE("/DIR1/DIR2/FILE6");
+    NO_CHANGE("/DIR1/DIR2/FILE/X");
+
+    CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1");
+    CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1");
+    CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1");
+    CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1");
+    CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
+    CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+
+    NO_CHANGE("/DIR1/DIR2/../DIR1");
+    NO_CHANGE("/DIR1/DIR2/../FILE");
+
+    CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+    CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
+
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+
+    ret = do_test();
+    cleanup();
+    if (ret) {
+	fprintf(stderr, "test_path: failed on line %i\n", ret);
+	return 1;
+    }
+    return 0;
+}
diff --git a/qemu-0.15.x/tests/testthread.c b/qemu-0.15.x/tests/testthread.c
new file mode 100644
index 0000000..27e4825
--- /dev/null
+++ b/qemu-0.15.x/tests/testthread.c
@@ -0,0 +1,51 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/wait.h>
+#include <sched.h>
+
+void *thread1_func(void *arg)
+{
+    int i;
+    char buf[512];
+
+    for(i=0;i<10;i++) {
+        snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
+        write(1, buf, strlen(buf));
+        usleep(100 * 1000);
+    }
+    return NULL;
+}
+
+void *thread2_func(void *arg)
+{
+    int i;
+    char buf[512];
+    for(i=0;i<20;i++) {
+        snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
+        write(1, buf, strlen(buf));
+        usleep(150 * 1000);
+    }
+    return NULL;
+}
+
+void test_pthread(void)
+{
+    pthread_t tid1, tid2;
+
+    pthread_create(&tid1, NULL, thread1_func, "hello1");
+    pthread_create(&tid2, NULL, thread2_func, "hello2");
+    pthread_join(tid1, NULL);
+    pthread_join(tid2, NULL);
+    printf("End of pthread test.\n");
+}
+
+int main(int argc, char **argv)
+{
+    test_pthread();
+    return 0;
+}
diff --git a/qemu-0.15.x/thunk.c b/qemu-0.15.x/thunk.c
new file mode 100644
index 0000000..0657188
--- /dev/null
+++ b/qemu-0.15.x/thunk.c
@@ -0,0 +1,288 @@
+/*
+ *  Generic thunking code to convert data between host and target CPU
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "qemu.h"
+#include "thunk.h"
+
+//#define DEBUG
+
+#define MAX_STRUCTS 128
+
+/* XXX: make it dynamic */
+StructEntry struct_entries[MAX_STRUCTS];
+
+static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
+
+static inline const argtype *thunk_type_next(const argtype *type_ptr)
+{
+    int type;
+
+    type = *type_ptr++;
+    switch(type) {
+    case TYPE_CHAR:
+    case TYPE_SHORT:
+    case TYPE_INT:
+    case TYPE_LONGLONG:
+    case TYPE_ULONGLONG:
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+        return type_ptr;
+    case TYPE_PTR:
+        return thunk_type_next_ptr(type_ptr);
+    case TYPE_ARRAY:
+        return thunk_type_next_ptr(type_ptr + 1);
+    case TYPE_STRUCT:
+        return type_ptr + 1;
+    default:
+        return NULL;
+    }
+}
+
+static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
+{
+    return thunk_type_next(type_ptr);
+}
+
+void thunk_register_struct(int id, const char *name, const argtype *types)
+{
+    const argtype *type_ptr;
+    StructEntry *se;
+    int nb_fields, offset, max_align, align, size, i, j;
+
+    se = struct_entries + id;
+
+    /* first we count the number of fields */
+    type_ptr = types;
+    nb_fields = 0;
+    while (*type_ptr != TYPE_NULL) {
+        type_ptr = thunk_type_next(type_ptr);
+        nb_fields++;
+    }
+    se->field_types = types;
+    se->nb_fields = nb_fields;
+    se->name = name;
+#ifdef DEBUG
+    printf("struct %s: id=%d nb_fields=%d\n",
+           se->name, id, se->nb_fields);
+#endif
+    /* now we can alloc the data */
+
+    for(i = 0;i < 2; i++) {
+        offset = 0;
+        max_align = 1;
+        se->field_offsets[i] = malloc(nb_fields * sizeof(int));
+        type_ptr = se->field_types;
+        for(j = 0;j < nb_fields; j++) {
+            size = thunk_type_size(type_ptr, i);
+            align = thunk_type_align(type_ptr, i);
+            offset = (offset + align - 1) & ~(align - 1);
+            se->field_offsets[i][j] = offset;
+            offset += size;
+            if (align > max_align)
+                max_align = align;
+            type_ptr = thunk_type_next(type_ptr);
+        }
+        offset = (offset + max_align - 1) & ~(max_align - 1);
+        se->size[i] = offset;
+        se->align[i] = max_align;
+#ifdef DEBUG
+        printf("%s: size=%d align=%d\n",
+               i == THUNK_HOST ? "host" : "target", offset, max_align);
+#endif
+    }
+}
+
+void thunk_register_struct_direct(int id, const char *name,
+                                  const StructEntry *se1)
+{
+    StructEntry *se;
+    se = struct_entries + id;
+    *se = *se1;
+    se->name = name;
+}
+
+
+/* now we can define the main conversion functions */
+const argtype *thunk_convert(void *dst, const void *src,
+                             const argtype *type_ptr, int to_host)
+{
+    int type;
+
+    type = *type_ptr++;
+    switch(type) {
+    case TYPE_CHAR:
+        *(uint8_t *)dst = *(uint8_t *)src;
+        break;
+    case TYPE_SHORT:
+        *(uint16_t *)dst = tswap16(*(uint16_t *)src);
+        break;
+    case TYPE_INT:
+        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
+        break;
+    case TYPE_LONGLONG:
+    case TYPE_ULONGLONG:
+        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
+        break;
+#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
+        break;
+#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+        if (to_host) {
+            if (type == TYPE_LONG) {
+                /* sign extension */
+                *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
+            } else {
+                *(uint64_t *)dst = tswap32(*(uint32_t *)src);
+            }
+        } else {
+            *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
+        }
+        break;
+#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
+        break;
+#elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+        if (to_host) {
+            *(uint32_t *)dst = tswap64(*(uint64_t *)src);
+        } else {
+            if (type == TYPE_LONG) {
+                /* sign extension */
+                *(uint64_t *)dst = tswap64(*(int32_t *)src);
+            } else {
+                *(uint64_t *)dst = tswap64(*(uint32_t *)src);
+            }
+        }
+        break;
+#else
+#warning unsupported conversion
+#endif
+    case TYPE_ARRAY:
+        {
+            int array_length, i, dst_size, src_size;
+            const uint8_t *s;
+            uint8_t  *d;
+
+            array_length = *type_ptr++;
+            dst_size = thunk_type_size(type_ptr, to_host);
+            src_size = thunk_type_size(type_ptr, 1 - to_host);
+            d = dst;
+            s = src;
+            for(i = 0;i < array_length; i++) {
+                thunk_convert(d, s, type_ptr, to_host);
+                d += dst_size;
+                s += src_size;
+            }
+            type_ptr = thunk_type_next(type_ptr);
+        }
+        break;
+    case TYPE_STRUCT:
+        {
+            int i;
+            const StructEntry *se;
+            const uint8_t *s;
+            uint8_t  *d;
+            const argtype *field_types;
+            const int *dst_offsets, *src_offsets;
+
+            se = struct_entries + *type_ptr++;
+            if (se->convert[0] != NULL) {
+                /* specific conversion is needed */
+                (*se->convert[to_host])(dst, src);
+            } else {
+                /* standard struct conversion */
+                field_types = se->field_types;
+                dst_offsets = se->field_offsets[to_host];
+                src_offsets = se->field_offsets[1 - to_host];
+                d = dst;
+                s = src;
+                for(i = 0;i < se->nb_fields; i++) {
+                    field_types = thunk_convert(d + dst_offsets[i],
+                                                s + src_offsets[i],
+                                                field_types, to_host);
+                }
+            }
+        }
+        break;
+    default:
+        fprintf(stderr, "Invalid type 0x%x\n", type);
+        break;
+    }
+    return type_ptr;
+}
+
+/* from em86 */
+
+/* Utility function: Table-driven functions to translate bitmasks
+ * between X86 and Alpha formats...
+ */
+unsigned int target_to_host_bitmask(unsigned int x86_mask,
+                                    const bitmask_transtbl * trans_tbl)
+{
+    const bitmask_transtbl *btp;
+    unsigned int	alpha_mask = 0;
+
+    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
+	if((x86_mask & btp->x86_mask) == btp->x86_bits) {
+	    alpha_mask |= btp->alpha_bits;
+	}
+    }
+    return(alpha_mask);
+}
+
+unsigned int host_to_target_bitmask(unsigned int alpha_mask,
+                                    const bitmask_transtbl * trans_tbl)
+{
+    const bitmask_transtbl *btp;
+    unsigned int	x86_mask = 0;
+
+    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
+	if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
+	    x86_mask |= btp->x86_bits;
+	}
+    }
+    return(x86_mask);
+}
+
+#ifndef NO_THUNK_TYPE_SIZE
+int thunk_type_size_array(const argtype *type_ptr, int is_host)
+{
+    return thunk_type_size(type_ptr, is_host);
+}
+
+int thunk_type_align_array(const argtype *type_ptr, int is_host)
+{
+    return thunk_type_align(type_ptr, is_host);
+}
+#endif /* ndef NO_THUNK_TYPE_SIZE */
diff --git a/qemu-0.15.x/thunk.h b/qemu-0.15.x/thunk.h
new file mode 100644
index 0000000..109c541
--- /dev/null
+++ b/qemu-0.15.x/thunk.h
@@ -0,0 +1,161 @@
+/*
+ *  Generic thunking code to convert data between host and target CPU
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef THUNK_H
+#define THUNK_H
+
+#include <inttypes.h>
+#include "cpu.h"
+
+/* types enums definitions */
+
+typedef enum argtype {
+    TYPE_NULL,
+    TYPE_CHAR,
+    TYPE_SHORT,
+    TYPE_INT,
+    TYPE_LONG,
+    TYPE_ULONG,
+    TYPE_PTRVOID, /* pointer on unknown data */
+    TYPE_LONGLONG,
+    TYPE_ULONGLONG,
+    TYPE_PTR,
+    TYPE_ARRAY,
+    TYPE_STRUCT,
+} argtype;
+
+#define MK_PTR(type) TYPE_PTR, type
+#define MK_ARRAY(type, size) TYPE_ARRAY, size, type
+#define MK_STRUCT(id) TYPE_STRUCT, id
+
+#define THUNK_TARGET 0
+#define THUNK_HOST   1
+
+typedef struct {
+    /* standard struct handling */
+    const argtype *field_types;
+    int nb_fields;
+    int *field_offsets[2];
+    /* special handling */
+    void (*convert[2])(void *dst, const void *src);
+    int size[2];
+    int align[2];
+    const char *name;
+} StructEntry;
+
+/* Translation table for bitmasks... */
+typedef struct bitmask_transtbl {
+	unsigned int	x86_mask;
+	unsigned int	x86_bits;
+	unsigned int	alpha_mask;
+	unsigned int	alpha_bits;
+} bitmask_transtbl;
+
+void thunk_register_struct(int id, const char *name, const argtype *types);
+void thunk_register_struct_direct(int id, const char *name,
+                                  const StructEntry *se1);
+const argtype *thunk_convert(void *dst, const void *src,
+                             const argtype *type_ptr, int to_host);
+#ifndef NO_THUNK_TYPE_SIZE
+
+extern StructEntry struct_entries[];
+
+int thunk_type_size_array(const argtype *type_ptr, int is_host);
+int thunk_type_align_array(const argtype *type_ptr, int is_host);
+
+static inline int thunk_type_size(const argtype *type_ptr, int is_host)
+{
+    int type, size;
+    const StructEntry *se;
+
+    type = *type_ptr;
+    switch(type) {
+    case TYPE_CHAR:
+        return 1;
+    case TYPE_SHORT:
+        return 2;
+    case TYPE_INT:
+        return 4;
+    case TYPE_LONGLONG:
+    case TYPE_ULONGLONG:
+        return 8;
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+    case TYPE_PTR:
+        if (is_host) {
+            return HOST_LONG_SIZE;
+        } else {
+            return TARGET_ABI_BITS / 8;
+        }
+        break;
+    case TYPE_ARRAY:
+        size = type_ptr[1];
+        return size * thunk_type_size_array(type_ptr + 2, is_host);
+    case TYPE_STRUCT:
+        se = struct_entries + type_ptr[1];
+        return se->size[is_host];
+    default:
+        return -1;
+    }
+}
+
+static inline int thunk_type_align(const argtype *type_ptr, int is_host)
+{
+    int type;
+    const StructEntry *se;
+
+    type = *type_ptr;
+    switch(type) {
+    case TYPE_CHAR:
+        return 1;
+    case TYPE_SHORT:
+        return 2;
+    case TYPE_INT:
+        return 4;
+    case TYPE_LONGLONG:
+    case TYPE_ULONGLONG:
+        return 8;
+    case TYPE_LONG:
+    case TYPE_ULONG:
+    case TYPE_PTRVOID:
+    case TYPE_PTR:
+        if (is_host) {
+            return HOST_LONG_SIZE;
+        } else {
+            return TARGET_ABI_BITS / 8;
+        }
+        break;
+    case TYPE_ARRAY:
+        return thunk_type_align_array(type_ptr + 2, is_host);
+    case TYPE_STRUCT:
+        se = struct_entries + type_ptr[1];
+        return se->align[is_host];
+    default:
+        return -1;
+    }
+}
+
+#endif /* NO_THUNK_TYPE_SIZE */
+
+unsigned int target_to_host_bitmask(unsigned int x86_mask,
+                                    const bitmask_transtbl * trans_tbl);
+unsigned int host_to_target_bitmask(unsigned int alpha_mask,
+                                    const bitmask_transtbl * trans_tbl);
+
+#endif
diff --git a/qemu-0.15.x/trace-events b/qemu-0.15.x/trace-events
new file mode 100644
index 0000000..713f042
--- /dev/null
+++ b/qemu-0.15.x/trace-events
@@ -0,0 +1,427 @@
+# Trace events for debugging and performance instrumentation
+#
+# This file is processed by the tracetool script during the build.
+#
+# To add a new trace event:
+#
+# 1. Choose a name for the trace event.  Declare its arguments and format
+#    string.
+#
+# 2. Call the trace event from code using trace_##name, e.g. multiwrite_cb() ->
+#    trace_multiwrite_cb().  The source file must #include "trace.h".
+#
+# Format of a trace event:
+#
+# [disable] <name>(<type1> <arg1>[, <type2> <arg2>] ...) "<format-string>"
+#
+# Example: qemu_malloc(size_t size) "size %zu"
+#
+# The "disable" keyword will build without the trace event.
+# In case of 'simple' trace backend, it will allow the trace event to be
+# compiled, but this would be turned off by default. It can be toggled on via
+# the monitor.
+#
+# The <name> must be a valid as a C function name.
+#
+# Types should be standard C types.  Use void * for pointers because the trace
+# system may not have the necessary headers included.
+#
+# The <format-string> should be a sprintf()-compatible format string.
+
+# qemu-malloc.c
+disable qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
+disable qemu_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
+disable qemu_free(void *ptr) "ptr %p"
+
+# osdep.c
+disable qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p"
+disable qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
+disable qemu_vfree(void *ptr) "ptr %p"
+
+# hw/virtio.c
+disable virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
+disable virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
+disable virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
+disable virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p"
+disable virtio_irq(void *vq) "vq %p"
+disable virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
+
+# hw/virtio-serial-bus.c
+disable virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
+disable virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d"
+disable virtio_serial_handle_control_message(uint16_t event, uint16_t value) "event %u, value %u"
+disable virtio_serial_handle_control_message_port(unsigned int port) "port %u"
+
+# hw/virtio-console.c
+disable virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, in_len %zu, out_len %zd"
+disable virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
+disable virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
+
+# block.c
+disable multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
+disable bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
+disable bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
+disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
+disable bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
+disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
+
+# hw/virtio-blk.c
+disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
+disable virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
+disable virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+
+# posix-aio-compat.c
+disable paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
+disable paio_complete(void *acb, void *opaque, int ret) "acb %p opaque %p ret %d"
+disable paio_cancel(void *acb, void *opaque) "acb %p opaque %p"
+
+# ioport.c
+disable cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u"
+disable cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
+
+# balloon.c
+# Since requests are raised via monitor, not many tracepoints are needed.
+disable balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
+
+# hw/apic.c
+disable apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
+disable apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d polarity %d trigger_mode %d"
+disable cpu_set_apic_base(uint64_t val) "%016"PRIx64""
+disable cpu_get_apic_base(uint64_t val) "%016"PRIx64""
+disable apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
+disable apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+# coalescing
+disable apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
+disable apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
+disable apic_set_irq(int apic_irq_delivered) "coalescing %d"
+
+# hw/cs4231.c
+disable cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
+disable cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
+disable cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
+disable cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
+
+# hw/ds1225y.c
+disable nvram_read(uint32_t addr, uint32_t ret) "read addr %d: 0x%02x"
+disable nvram_write(uint32_t addr, uint32_t old, uint32_t val) "write addr %d: 0x%02x -> 0x%02x"
+
+# hw/eccmemctl.c
+disable ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x"
+disable ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x"
+disable ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x"
+disable ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x"
+disable ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x"
+disable ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x"
+disable ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x"
+disable ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x"
+disable ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x"
+disable ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x"
+disable ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x"
+disable ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x"
+disable ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x"
+disable ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x"
+disable ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x"
+disable ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
+disable ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
+disable ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
+
+# hw/lance.c
+disable lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
+disable lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
+
+# hw/slavio_intctl.c
+disable slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
+disable slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
+disable slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x"
+disable slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x"
+disable slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x"
+disable slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x"
+disable slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x"
+disable slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x"
+disable slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d"
+disable slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x"
+disable slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d"
+disable slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d"
+
+# hw/slavio_misc.c
+disable slavio_misc_update_irq_raise(void) "Raise IRQ"
+disable slavio_misc_update_irq_lower(void) "Lower IRQ"
+disable slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d"
+disable slavio_cfg_mem_writeb(uint32_t val) "Write config %02x"
+disable slavio_cfg_mem_readb(uint32_t ret) "Read config %02x"
+disable slavio_diag_mem_writeb(uint32_t val) "Write diag %02x"
+disable slavio_diag_mem_readb(uint32_t ret) "Read diag %02x"
+disable slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x"
+disable slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x"
+disable slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x"
+disable slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x"
+disable slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x"
+disable slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x"
+disable apc_mem_writeb(uint32_t val) "Write power management %02x"
+disable apc_mem_readb(uint32_t ret) "Read power management %02x"
+disable slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x"
+disable slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x"
+disable slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x"
+disable slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
+
+# hw/slavio_timer.c
+disable slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
+disable slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
+disable slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64""
+disable slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x"
+disable slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x"
+disable slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64""
+disable slavio_timer_mem_writel_counter_invalid(void) "not user timer"
+disable slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started"
+disable slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped"
+disable slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer"
+disable slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter"
+disable slavio_timer_mem_writel_mode_invalid(void) "not system timer"
+disable slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64""
+
+# hw/sparc32_dma.c
+disable ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64""
+disable ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64""
+disable sparc32_dma_set_irq_raise(void) "Raise IRQ"
+disable sparc32_dma_set_irq_lower(void) "Lower IRQ"
+disable espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x"
+disable espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x"
+disable sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x"
+disable sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x"
+disable sparc32_dma_enable_raise(void) "Raise DMA enable"
+disable sparc32_dma_enable_lower(void) "Lower DMA enable"
+
+# hw/sun4m.c
+disable sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d"
+disable sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
+disable sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
+disable sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
+
+# hw/sun4m_iommu.c
+disable sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
+disable sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
+disable sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64""
+disable sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x"
+disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
+disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
+disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
+disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+
+# hw/usb-ehci.c
+disable usb_ehci_reset(void) "=== RESET ==="
+disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
+disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
+disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
+disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
+disable usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
+disable usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
+disable usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x"
+disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
+disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
+disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
+disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
+disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
+disable usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
+disable usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
+
+# hw/usb-desc.c
+disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
+disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
+disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+disable usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
+disable usb_set_addr(int addr) "dev %d"
+disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+disable usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+disable usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+
+# hw/scsi-bus.c
+disable scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
+disable scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
+disable scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
+disable scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
+disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
+disable scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64""
+disable scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
+
+# vl.c
+disable vm_state_notify(int running, int reason) "running %d reason %d"
+
+# block/qed-l2-cache.c
+disable qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
+disable qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
+disable qed_find_l2_cache_entry(void *l2_cache, void *entry, uint64_t offset, int ref) "l2_cache %p entry %p offset %"PRIu64" ref %d"
+
+# block/qed-table.c
+disable qed_read_table(void *s, uint64_t offset, void *table) "s %p offset %"PRIu64" table %p"
+disable qed_read_table_cb(void *s, void *table, int ret) "s %p table %p ret %d"
+disable qed_write_table(void *s, uint64_t offset, void *table, unsigned int index, unsigned int n) "s %p offset %"PRIu64" table %p index %u n %u"
+disable qed_write_table_cb(void *s, void *table, int flush, int ret) "s %p table %p flush %d ret %d"
+
+# block/qed.c
+disable qed_need_check_timer_cb(void *s) "s %p"
+disable qed_start_need_check_timer(void *s) "s %p"
+disable qed_cancel_need_check_timer(void *s) "s %p"
+disable qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
+disable qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
+disable qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64""
+disable qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+disable qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+disable qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
+disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
+disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+
+# hw/grlib_gptimer.c
+disable grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
+disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
+disable grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x"
+disable grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x"
+disable grlib_gptimer_hit(int id) "timer:%d HIT"
+disable grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
+disable grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
+
+# hw/grlib_irqmp.c
+disable grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n"
+disable grlib_irqmp_ack(int intno) "interrupt:%d"
+disable grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
+disable grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
+disable grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
+
+# hw/grlib_apbuart.c
+disable grlib_apbuart_event(int event) "event:%d"
+disable grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
+
+# hw/leon3.c
+disable leon3_set_irq(int intno) "Set CPU IRQ %d"
+disable leon3_reset_irq(int intno) "Reset CPU IRQ %d"
+
+# spice-qemu-char.c
+disable spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d"
+disable spice_vmc_read(int bytes, int len) "spice read %d of requested %d"
+disable spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
+disable spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
+
+# hw/lm32_pic.c
+disable lm32_pic_raise_irq(void) "Raise CPU interrupt"
+disable lm32_pic_lower_irq(void) "Lower CPU interrupt"
+disable lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
+disable lm32_pic_set_im(uint32_t im) "im 0x%08x"
+disable lm32_pic_set_ip(uint32_t ip) "ip 0x%08x"
+disable lm32_pic_get_im(uint32_t im) "im 0x%08x"
+disable lm32_pic_get_ip(uint32_t ip) "ip 0x%08x"
+
+# hw/lm32_juart.c
+disable lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x"
+disable lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x"
+disable lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x"
+disable lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x"
+
+# hw/lm32_timer.c
+disable lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+disable lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+disable lm32_timer_hit(void) "timer hit"
+disable lm32_timer_irq_state(int level) "irq state %d"
+
+# hw/lm32_uart.c
+disable lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+disable lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+disable lm32_uart_irq_state(int level) "irq state %d"
+
+# hw/lm32_sys.c
+disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/milkymist-ac97.c
+disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
+disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
+disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
+disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
+disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
+disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
+disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
+disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
+
+# hw/milkymist-hpdmc.c
+disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+
+# hw/milkymist-memcard.c
+disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# hw/milkymist-minimac2.c
+disable milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac2_tx_frame(uint32_t length) "length %u"
+disable milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
+disable milkymist_minimac2_drop_rx_frame(const void *buf) "buf %p"
+disable milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
+disable milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
+disable milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
+disable milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-pfpu.c
+disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
+disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-softusb.c
+disable milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_mevt(uint8_t m) "m %d"
+disable milkymist_softusb_kevt(uint8_t m) "m %d"
+disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
+disable milkymist_softusb_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-sysctl.c
+disable milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_icap_write(uint32_t value) "value %08x"
+disable milkymist_sysctl_start_timer0(void) "Start timer0"
+disable milkymist_sysctl_stop_timer0(void) "Stop timer0"
+disable milkymist_sysctl_start_timer1(void) "Start timer1"
+disable milkymist_sysctl_stop_timer1(void) "Stop timer1"
+disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
+disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
+
+# hw/milkymist-tmu2.c
+disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_start(void) "Start TMU"
+disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-uart.c
+disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
+disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-vgafb.c
+disable milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# xen-all.c
+disable xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx"
+disable xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i"
+
+# xen-mapcache.c
+disable xen_map_cache(uint64_t phys_addr) "want %#"PRIx64""
+disable xen_remap_bucket(uint64_t index) "index %#"PRIx64""
+disable xen_map_cache_return(void* ptr) "%p"
+disable xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64""
+disable xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx"
+
+# exec.c
+disable qemu_put_ram_ptr(void* addr) "%p"
+
+# hw/xen_platform.c
+disable xen_platform_log(char *s) "xen platform: %s"
diff --git a/qemu-0.15.x/translate-all.c b/qemu-0.15.x/translate-all.c
new file mode 100644
index 0000000..041c108
--- /dev/null
+++ b/qemu-0.15.x/translate-all.c
@@ -0,0 +1,163 @@
+/*
+ *  Host code generation
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+
+#define NO_CPU_IO_DEFS
+#include "cpu.h"
+#include "disas.h"
+#include "tcg.h"
+#include "qemu-timer.h"
+
+/* code generation context */
+TCGContext tcg_ctx;
+
+uint16_t gen_opc_buf[OPC_BUF_SIZE];
+TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
+
+target_ulong gen_opc_pc[OPC_BUF_SIZE];
+uint16_t gen_opc_icount[OPC_BUF_SIZE];
+uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
+
+void cpu_gen_init(void)
+{
+    tcg_context_init(&tcg_ctx); 
+}
+
+/* return non zero if the very first instruction is invalid so that
+   the virtual CPU can trigger an exception.
+
+   '*gen_code_size_ptr' contains the size of the generated code (host
+   code).
+*/
+int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
+{
+    TCGContext *s = &tcg_ctx;
+    uint8_t *gen_code_buf;
+    int gen_code_size;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+    s->tb_count1++; /* includes aborted translations because of
+                       exceptions */
+    ti = profile_getclock();
+#endif
+    tcg_func_start(s);
+
+    gen_intermediate_code(env, tb);
+
+    /* generate machine code */
+    gen_code_buf = tb->tc_ptr;
+    tb->tb_next_offset[0] = 0xffff;
+    tb->tb_next_offset[1] = 0xffff;
+    s->tb_next_offset = tb->tb_next_offset;
+#ifdef USE_DIRECT_JUMP
+    s->tb_jmp_offset = tb->tb_jmp_offset;
+    s->tb_next = NULL;
+#else
+    s->tb_jmp_offset = NULL;
+    s->tb_next = tb->tb_next;
+#endif
+
+#ifdef CONFIG_PROFILER
+    s->tb_count++;
+    s->interm_time += profile_getclock() - ti;
+    s->code_time -= profile_getclock();
+#endif
+    gen_code_size = tcg_gen_code(s, gen_code_buf);
+    *gen_code_size_ptr = gen_code_size;
+#ifdef CONFIG_PROFILER
+    s->code_time += profile_getclock();
+    s->code_in_len += tb->size;
+    s->code_out_len += gen_code_size;
+#endif
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
+        qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
+        log_disas(tb->tc_ptr, *gen_code_size_ptr);
+        qemu_log("\n");
+        qemu_log_flush();
+    }
+#endif
+    return 0;
+}
+
+/* The cpu state corresponding to 'searched_pc' is restored.
+ */
+int cpu_restore_state(TranslationBlock *tb,
+                      CPUState *env, unsigned long searched_pc)
+{
+    TCGContext *s = &tcg_ctx;
+    int j;
+    unsigned long tc_ptr;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+    ti = profile_getclock();
+#endif
+    tcg_func_start(s);
+
+    gen_intermediate_code_pc(env, tb);
+
+    if (use_icount) {
+        /* Reset the cycle counter to the start of the block.  */
+        env->icount_decr.u16.low += tb->icount;
+        /* Clear the IO flag.  */
+        env->can_do_io = 0;
+    }
+
+    /* find opc index corresponding to search_pc */
+    tc_ptr = (unsigned long)tb->tc_ptr;
+    if (searched_pc < tc_ptr)
+        return -1;
+
+    s->tb_next_offset = tb->tb_next_offset;
+#ifdef USE_DIRECT_JUMP
+    s->tb_jmp_offset = tb->tb_jmp_offset;
+    s->tb_next = NULL;
+#else
+    s->tb_jmp_offset = NULL;
+    s->tb_next = tb->tb_next;
+#endif
+    j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
+    if (j < 0)
+        return -1;
+    /* now find start of instruction before */
+    while (gen_opc_instr_start[j] == 0)
+        j--;
+    env->icount_decr.u16.low -= gen_opc_icount[j];
+
+    restore_state_to_opc(env, tb, j);
+
+#ifdef CONFIG_PROFILER
+    s->restore_time += profile_getclock() - ti;
+    s->restore_count++;
+#endif
+    return 0;
+}
diff --git a/qemu-0.15.x/uboot_image.h b/qemu-0.15.x/uboot_image.h
new file mode 100644
index 0000000..9fc2760
--- /dev/null
+++ b/qemu-0.15.x/uboot_image.h
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef __UBOOT_IMAGE_H__
+#define __UBOOT_IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define IH_OS_INVALID		0	/* Invalid OS	*/
+#define IH_OS_OPENBSD		1	/* OpenBSD	*/
+#define IH_OS_NETBSD		2	/* NetBSD	*/
+#define IH_OS_FREEBSD		3	/* FreeBSD	*/
+#define IH_OS_4_4BSD		4	/* 4.4BSD	*/
+#define IH_OS_LINUX		5	/* Linux	*/
+#define IH_OS_SVR4		6	/* SVR4		*/
+#define IH_OS_ESIX		7	/* Esix		*/
+#define IH_OS_SOLARIS		8	/* Solaris	*/
+#define IH_OS_IRIX		9	/* Irix		*/
+#define IH_OS_SCO		10	/* SCO		*/
+#define IH_OS_DELL		11	/* Dell		*/
+#define IH_OS_NCR		12	/* NCR		*/
+#define IH_OS_LYNXOS		13	/* LynxOS	*/
+#define IH_OS_VXWORKS		14	/* VxWorks	*/
+#define IH_OS_PSOS		15	/* pSOS		*/
+#define IH_OS_QNX		16	/* QNX		*/
+#define IH_OS_U_BOOT		17	/* Firmware	*/
+#define IH_OS_RTEMS		18	/* RTEMS	*/
+#define IH_OS_ARTOS		19	/* ARTOS	*/
+#define IH_OS_UNITY		20	/* Unity OS	*/
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define IH_CPU_INVALID		0	/* Invalid CPU	*/
+#define IH_CPU_ALPHA		1	/* Alpha	*/
+#define IH_CPU_ARM		2	/* ARM		*/
+#define IH_CPU_I386		3	/* Intel x86	*/
+#define IH_CPU_IA64		4	/* IA64		*/
+#define IH_CPU_MIPS		5	/* MIPS		*/
+#define IH_CPU_MIPS64		6	/* MIPS	 64 Bit */
+#define IH_CPU_PPC		7	/* PowerPC	*/
+#define IH_CPU_S390		8	/* IBM S390	*/
+#define IH_CPU_SH		9	/* SuperH	*/
+#define IH_CPU_SPARC		10	/* Sparc	*/
+#define IH_CPU_SPARC64		11	/* Sparc 64 Bit */
+#define IH_CPU_M68K		12	/* M68K		*/
+#define IH_CPU_NIOS		13	/* Nios-32	*/
+#define IH_CPU_MICROBLAZE	14	/* MicroBlaze   */
+#define IH_CPU_NIOS2		15	/* Nios-II	*/
+#define IH_CPU_BLACKFIN		16	/* Blackfin	*/
+#define IH_CPU_AVR32		17	/* AVR32	*/
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *	provided by U-Boot; it is expected that (if they behave
+ *	well) you can continue to work in U-Boot after return from
+ *	the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *	will take over control completely. Usually these programs
+ *	will install their own set of exception handlers, device
+ *	drivers, set up the MMU, etc. - this means, that you cannot
+ *	expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *	parameters (address, size) are passed to an OS kernel that is
+ *	being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *	(Linux) kernel image and one or more data images like
+ *	RAMDisks. This construct is useful for instance when you want
+ *	to boot over the network using BOOTP etc., where the boot
+ *	server provides just a single image file, but you want to get
+ *	for instance an OS kernel and a RAMDisk image.
+ *
+ *	"Multi-File Images" start with a list of image sizes, each
+ *	image size (in bytes) specified by an "uint32_t" in network
+ *	byte order. This list is terminated by an "(uint32_t)0".
+ *	Immediately after the terminating 0 follow the images, one by
+ *	one, all aligned on "uint32_t" boundaries (size rounded up to
+ *	a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ *	U-Boot or FPGA images) which usually will be programmed to
+ *	flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ *	U-Boot's command interpreter; this feature is especially
+ *	useful when you configure U-Boot to use a real shell (hush)
+ *	as command interpreter (=> Shell Scripts).
+ */
+
+#define IH_TYPE_INVALID		0	/* Invalid Image		*/
+#define IH_TYPE_STANDALONE	1	/* Standalone Program		*/
+#define IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
+#define IH_TYPE_RAMDISK		3	/* RAMDisk Image		*/
+#define IH_TYPE_MULTI		4	/* Multi-File Image		*/
+#define IH_TYPE_FIRMWARE	5	/* Firmware Image		*/
+#define IH_TYPE_SCRIPT		6	/* Script file			*/
+#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
+#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE		0	/*  No	 Compression Used	*/
+#define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
+#define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct uboot_image_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+} uboot_image_header_t;
+
+
+#endif	/* __IMAGE_H__ */
diff --git a/qemu-0.15.x/ui/cocoa.m b/qemu-0.15.x/ui/cocoa.m
new file mode 100644
index 0000000..515e684
--- /dev/null
+++ b/qemu-0.15.x/ui/cocoa.m
@@ -0,0 +1,1025 @@
+/*
+ * QEMU Cocoa CG display driver
+ *
+ * Copyright (c) 2008 Mike Kronenberg
+ *
+ * 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include <crt_externs.h>
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+#ifndef MAC_OS_X_VERSION_10_4
+#define MAC_OS_X_VERSION_10_4 1040
+#endif
+#ifndef MAC_OS_X_VERSION_10_5
+#define MAC_OS_X_VERSION_10_5 1050
+#endif
+
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define COCOA_DEBUG(...)  { (void) fprintf (stdout, __VA_ARGS__); }
+#else
+#define COCOA_DEBUG(...)  ((void) 0)
+#endif
+
+#define cgrect(nsrect) (*(CGRect *)&(nsrect))
+#define COCOA_MOUSE_EVENT \
+        if (isTabletEnabled) { \
+            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
+        } else if (isMouseGrabed) { \
+            kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
+        } else { \
+            [NSApp sendEvent:event]; \
+        }
+
+typedef struct {
+    int width;
+    int height;
+    int bitsPerComponent;
+    int bitsPerPixel;
+} QEMUScreen;
+
+NSWindow *normalWindow;
+static DisplayChangeListener *dcl;
+
+int gArgc;
+char **gArgv;
+
+// keymap conversion
+int keymap[] =
+{
+//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
+    30, //  0       0x00    0x1e            A       QZ_a
+    31, //  1       0x01    0x1f            S       QZ_s
+    32, //  2       0x02    0x20            D       QZ_d
+    33, //  3       0x03    0x21            F       QZ_f
+    35, //  4       0x04    0x23            H       QZ_h
+    34, //  5       0x05    0x22            G       QZ_g
+    44, //  6       0x06    0x2c            Z       QZ_z
+    45, //  7       0x07    0x2d            X       QZ_x
+    46, //  8       0x08    0x2e            C       QZ_c
+    47, //  9       0x09    0x2f            V       QZ_v
+    0,  //  10      0x0A    Undefined
+    48, //  11      0x0B    0x30            B       QZ_b
+    16, //  12      0x0C    0x10            Q       QZ_q
+    17, //  13      0x0D    0x11            W       QZ_w
+    18, //  14      0x0E    0x12            E       QZ_e
+    19, //  15      0x0F    0x13            R       QZ_r
+    21, //  16      0x10    0x15            Y       QZ_y
+    20, //  17      0x11    0x14            T       QZ_t
+    2,  //  18      0x12    0x02            1       QZ_1
+    3,  //  19      0x13    0x03            2       QZ_2
+    4,  //  20      0x14    0x04            3       QZ_3
+    5,  //  21      0x15    0x05            4       QZ_4
+    7,  //  22      0x16    0x07            6       QZ_6
+    6,  //  23      0x17    0x06            5       QZ_5
+    13, //  24      0x18    0x0d            =       QZ_EQUALS
+    10, //  25      0x19    0x0a            9       QZ_9
+    8,  //  26      0x1A    0x08            7       QZ_7
+    12, //  27      0x1B    0x0c            -       QZ_MINUS
+    9,  //  28      0x1C    0x09            8       QZ_8
+    11, //  29      0x1D    0x0b            0       QZ_0
+    27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
+    24, //  31      0x1F    0x18            O       QZ_o
+    22, //  32      0x20    0x16            U       QZ_u
+    26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
+    23, //  34      0x22    0x17            I       QZ_i
+    25, //  35      0x23    0x19            P       QZ_p
+    28, //  36      0x24    0x1c            ENTER   QZ_RETURN
+    38, //  37      0x25    0x26            L       QZ_l
+    36, //  38      0x26    0x24            J       QZ_j
+    40, //  39      0x27    0x28            '       QZ_QUOTE
+    37, //  40      0x28    0x25            K       QZ_k
+    39, //  41      0x29    0x27            ;       QZ_SEMICOLON
+    43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
+    51, //  43      0x2B    0x33            ,       QZ_COMMA
+    53, //  44      0x2C    0x35            /       QZ_SLASH
+    49, //  45      0x2D    0x31            N       QZ_n
+    50, //  46      0x2E    0x32            M       QZ_m
+    52, //  47      0x2F    0x34            .       QZ_PERIOD
+    15, //  48      0x30    0x0f            TAB     QZ_TAB
+    57, //  49      0x31    0x39            SPACE   QZ_SPACE
+    41, //  50      0x32    0x29            `       QZ_BACKQUOTE
+    14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
+    0,  //  52      0x34    Undefined
+    1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
+    0,  //  54      0x36                            QZ_RMETA
+    0,  //  55      0x37                            QZ_LMETA
+    42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
+    58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
+    56, //  58      0x3A    0x38            L ALT   QZ_LALT
+    29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
+    54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
+    184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
+    157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
+    0,  //  63      0x3F    Undefined
+    0,  //  64      0x40    Undefined
+    0,  //  65      0x41    Undefined
+    0,  //  66      0x42    Undefined
+    55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
+    0,  //  68      0x44    Undefined
+    78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
+    0,  //  70      0x46    Undefined
+    69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
+    0,  //  72      0x48    Undefined
+    0,  //  73      0x49    Undefined
+    0,  //  74      0x4A    Undefined
+    181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
+    152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
+    0,  //  77      0x4D    undefined
+    74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
+    0,  //  79      0x4F    Undefined
+    0,  //  80      0x50    Undefined
+    0,  //  81      0x51                            QZ_KP_EQUALS
+    82, //  82      0x52    0x52            KP 0    QZ_KP0
+    79, //  83      0x53    0x4f            KP 1    QZ_KP1
+    80, //  84      0x54    0x50            KP 2    QZ_KP2
+    81, //  85      0x55    0x51            KP 3    QZ_KP3
+    75, //  86      0x56    0x4b            KP 4    QZ_KP4
+    76, //  87      0x57    0x4c            KP 5    QZ_KP5
+    77, //  88      0x58    0x4d            KP 6    QZ_KP6
+    71, //  89      0x59    0x47            KP 7    QZ_KP7
+    0,  //  90      0x5A    Undefined
+    72, //  91      0x5B    0x48            KP 8    QZ_KP8
+    73, //  92      0x5C    0x49            KP 9    QZ_KP9
+    0,  //  93      0x5D    Undefined
+    0,  //  94      0x5E    Undefined
+    0,  //  95      0x5F    Undefined
+    63, //  96      0x60    0x3f            F5      QZ_F5
+    64, //  97      0x61    0x40            F6      QZ_F6
+    65, //  98      0x62    0x41            F7      QZ_F7
+    61, //  99      0x63    0x3d            F3      QZ_F3
+    66, //  100     0x64    0x42            F8      QZ_F8
+    67, //  101     0x65    0x43            F9      QZ_F9
+    0,  //  102     0x66    Undefined
+    87, //  103     0x67    0x57            F11     QZ_F11
+    0,  //  104     0x68    Undefined
+    183,//  105     0x69    0xb7                    QZ_PRINT
+    0,  //  106     0x6A    Undefined
+    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
+    0,  //  108     0x6C    Undefined
+    68, //  109     0x6D    0x44            F10     QZ_F10
+    0,  //  110     0x6E    Undefined
+    88, //  111     0x6F    0x58            F12     QZ_F12
+    0,  //  112     0x70    Undefined
+    110,//  113     0x71    0x0                     QZ_PAUSE
+    210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
+    199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
+    201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
+    211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
+    62, //  118     0x76    0x3e            F4      QZ_F4
+    207,//  119     0x77    0xcf    E0,4f   END     QZ_END
+    60, //  120     0x78    0x3c            F2      QZ_F2
+    209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
+    59, //  122     0x7A    0x3b            F1      QZ_F1
+    203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
+    205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
+    208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
+    200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
+/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
+
+/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
+/*
+    219 //          0xdb            e0,5b   L GUI
+    220 //          0xdc            e0,5c   R GUI
+    221 //          0xdd            e0,5d   APPS
+        //              E0,2A,E0,37         PRNT SCRN
+        //              E1,1D,45,E1,9D,C5   PAUSE
+    83  //          0x53    0x53            KP .
+// ACPI Scan Codes
+    222 //          0xde            E0, 5E  Power
+    223 //          0xdf            E0, 5F  Sleep
+    227 //          0xe3            E0, 63  Wake
+// Windows Multimedia Scan Codes
+    153 //          0x99            E0, 19  Next Track
+    144 //          0x90            E0, 10  Previous Track
+    164 //          0xa4            E0, 24  Stop
+    162 //          0xa2            E0, 22  Play/Pause
+    160 //          0xa0            E0, 20  Mute
+    176 //          0xb0            E0, 30  Volume Up
+    174 //          0xae            E0, 2E  Volume Down
+    237 //          0xed            E0, 6D  Media Select
+    236 //          0xec            E0, 6C  E-Mail
+    161 //          0xa1            E0, 21  Calculator
+    235 //          0xeb            E0, 6B  My Computer
+    229 //          0xe5            E0, 65  WWW Search
+    178 //          0xb2            E0, 32  WWW Home
+    234 //          0xea            E0, 6A  WWW Back
+    233 //          0xe9            E0, 69  WWW Forward
+    232 //          0xe8            E0, 68  WWW Stop
+    231 //          0xe7            E0, 67  WWW Refresh
+    230 //          0xe6            E0, 66  WWW Favorites
+*/
+};
+
+static int cocoa_keycode_to_qemu(int keycode)
+{
+    if((sizeof(keymap)/sizeof(int)) <= keycode)
+    {
+        printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
+        return 0;
+    }
+    return keymap[keycode];
+}
+
+
+
+/*
+ ------------------------------------------------------
+    QemuCocoaView
+ ------------------------------------------------------
+*/
+ at interface QemuCocoaView : NSView
+{
+    QEMUScreen screen;
+    NSWindow *fullScreenWindow;
+    float cx,cy,cw,ch,cdx,cdy;
+    CGDataProviderRef dataProviderRef;
+    int modifiers_state[256];
+    BOOL isMouseGrabed;
+    BOOL isFullscreen;
+    BOOL isAbsoluteEnabled;
+    BOOL isTabletEnabled;
+}
+- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
+- (void) grabMouse;
+- (void) ungrabMouse;
+- (void) toggleFullScreen:(id)sender;
+- (void) handleEvent:(NSEvent *)event;
+- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
+- (BOOL) isMouseGrabed;
+- (BOOL) isAbsoluteEnabled;
+- (float) cdx;
+- (float) cdy;
+- (QEMUScreen) gscreen;
+ at end
+
+QemuCocoaView *cocoaView;
+
+ at implementation QemuCocoaView
+- (id)initWithFrame:(NSRect)frameRect
+{
+    COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
+
+    self = [super initWithFrame:frameRect];
+    if (self) {
+
+        screen.bitsPerComponent = 8;
+        screen.bitsPerPixel = 32;
+        screen.width = frameRect.size.width;
+        screen.height = frameRect.size.height;
+
+    }
+    return self;
+}
+
+- (void) dealloc
+{
+    COCOA_DEBUG("QemuCocoaView: dealloc\n");
+
+    if (dataProviderRef)
+        CGDataProviderRelease(dataProviderRef);
+
+    [super dealloc];
+}
+
+- (BOOL) isOpaque
+{
+    return YES;
+}
+
+- (void) drawRect:(NSRect) rect
+{
+    COCOA_DEBUG("QemuCocoaView: drawRect\n");
+
+    // get CoreGraphic context
+    CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
+    CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
+    CGContextSetShouldAntialias (viewContextRef, NO);
+
+    // draw screen bitmap directly to Core Graphics context
+    if (dataProviderRef) {
+        CGImageRef imageRef = CGImageCreate(
+            screen.width, //width
+            screen.height, //height
+            screen.bitsPerComponent, //bitsPerComponent
+            screen.bitsPerPixel, //bitsPerPixel
+            (screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
+#ifdef __LITTLE_ENDIAN__
+            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
+            kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
+#else
+            CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
+            kCGImageAlphaNoneSkipFirst, //bitmapInfo
+#endif
+            dataProviderRef, //provider
+            NULL, //decode
+            0, //interpolate
+            kCGRenderingIntentDefault //intent
+        );
+// test if host supports "CGImageCreateWithImageInRect" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+        if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
+#endif
+            // compatibility drawing code (draws everything) (OS X < 10.4)
+            CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+        } else {
+            // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
+            const NSRect *rectList;
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+            NSInteger rectCount;
+#else
+            int rectCount;
+#endif
+            int i;
+            CGImageRef clipImageRef;
+            CGRect clipRect;
+
+            [self getRectsBeingDrawn:&rectList count:&rectCount];
+            for (i = 0; i < rectCount; i++) {
+                clipRect.origin.x = rectList[i].origin.x / cdx;
+                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
+                clipRect.size.width = rectList[i].size.width / cdx;
+                clipRect.size.height = rectList[i].size.height / cdy;
+                clipImageRef = CGImageCreateWithImageInRect(
+                    imageRef,
+                    clipRect
+                );
+                CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
+                CGImageRelease (clipImageRef);
+            }
+        }
+#endif
+        CGImageRelease (imageRef);
+    }
+}
+
+- (void) setContentDimensions
+{
+    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
+
+    if (isFullscreen) {
+        cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
+        cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
+        cw = screen.width * cdx;
+        ch = screen.height * cdy;
+        cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
+        cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
+    } else {
+        cx = 0;
+        cy = 0;
+        cw = screen.width;
+        ch = screen.height;
+        cdx = 1.0;
+        cdy = 1.0;
+    }
+}
+
+- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
+{
+    COCOA_DEBUG("QemuCocoaView: resizeContent\n");
+
+    // update screenBuffer
+    if (dataProviderRef)
+        CGDataProviderRelease(dataProviderRef);
+
+    //sync host window color space with guests
+	screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
+	screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
+
+    dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
+
+    // update windows
+    if (isFullscreen) {
+        [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
+        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
+    } else {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
+        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
+    }
+    screen.width = w;
+    screen.height = h;
+	[normalWindow center];
+    [self setContentDimensions];
+    [self setFrame:NSMakeRect(cx, cy, cw, ch)];
+}
+
+- (void) toggleFullScreen:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
+
+    if (isFullscreen) { // switch from fullscreen to desktop
+        isFullscreen = FALSE;
+        [self ungrabMouse];
+        [self setContentDimensions];
+// test if host supports "exitFullScreenModeWithOptions" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
+            [self exitFullScreenModeWithOptions:nil];
+        } else {
+#endif
+            [fullScreenWindow close];
+            [normalWindow setContentView: self];
+            [normalWindow makeKeyAndOrderFront: self];
+            [NSMenu setMenuBarVisible:YES];
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        }
+#endif
+    } else { // switch from desktop to fullscreen
+        isFullscreen = TRUE;
+        [self grabMouse];
+        [self setContentDimensions];
+// test if host supports "enterFullScreenMode:withOptions" at compile time
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
+            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
+                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
+                 nil]];
+        } else {
+#endif
+            [NSMenu setMenuBarVisible:NO];
+            fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
+                styleMask:NSBorderlessWindowMask
+                backing:NSBackingStoreBuffered
+                defer:NO];
+            [fullScreenWindow setHasShadow:NO];
+            [fullScreenWindow setContentView:self];
+            [fullScreenWindow makeKeyAndOrderFront:self];
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+        }
+#endif
+    }
+}
+
+- (void) handleEvent:(NSEvent *)event
+{
+    COCOA_DEBUG("QemuCocoaView: handleEvent\n");
+
+    int buttons = 0;
+    int keycode;
+    NSPoint p = [event locationInWindow];
+
+    switch ([event type]) {
+        case NSFlagsChanged:
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            if (keycode) {
+                if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
+                    kbd_put_keycode(keycode);
+                    kbd_put_keycode(keycode | 0x80);
+                } else if (is_graphic_console()) {
+                    if (keycode & 0x80)
+                        kbd_put_keycode(0xe0);
+                    if (modifiers_state[keycode] == 0) { // keydown
+                        kbd_put_keycode(keycode & 0x7f);
+                        modifiers_state[keycode] = 1;
+                    } else { // keyup
+                        kbd_put_keycode(keycode | 0x80);
+                        modifiers_state[keycode] = 0;
+                    }
+                }
+            }
+
+            // release Mouse grab when pressing ctrl+alt
+            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+                [self ungrabMouse];
+            }
+            break;
+        case NSKeyDown:
+
+            // forward command Key Combos
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                [NSApp sendEvent:event];
+                return;
+            }
+
+            // default
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+
+            // handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
+            if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+                switch (keycode) {
+
+                    // enable graphic console
+                    case 0x02 ... 0x0a: // '1' to '9' keys
+                        console_select(keycode - 0x02);
+                        break;
+                }
+
+            // handle keys for graphic console
+            } else if (is_graphic_console()) {
+                if (keycode & 0x80) //check bit for e0 in front
+                    kbd_put_keycode(0xe0);
+                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
+
+            // handlekeys for Monitor
+            } else {
+                int keysym = 0;
+                switch([event keyCode]) {
+                case 115:
+                    keysym = QEMU_KEY_HOME;
+                    break;
+                case 117:
+                    keysym = QEMU_KEY_DELETE;
+                    break;
+                case 119:
+                    keysym = QEMU_KEY_END;
+                    break;
+                case 123:
+                    keysym = QEMU_KEY_LEFT;
+                    break;
+                case 124:
+                    keysym = QEMU_KEY_RIGHT;
+                    break;
+                case 125:
+                    keysym = QEMU_KEY_DOWN;
+                    break;
+                case 126:
+                    keysym = QEMU_KEY_UP;
+                    break;
+                default:
+                    {
+                        NSString *ks = [event characters];
+                        if ([ks length] > 0)
+                            keysym = [ks characterAtIndex:0];
+                    }
+                }
+                if (keysym)
+                    kbd_put_keysym(keysym);
+            }
+            break;
+        case NSKeyUp:
+            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            if (is_graphic_console()) {
+                if (keycode & 0x80)
+                    kbd_put_keycode(0xe0);
+                kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
+            }
+            break;
+        case NSMouseMoved:
+            if (isAbsoluteEnabled) {
+                if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
+                    if (isTabletEnabled) { // if we leave the window, deactivate the tablet
+                        [NSCursor unhide];
+                        isTabletEnabled = FALSE;
+                    }
+                } else {
+                    if (!isTabletEnabled) { // if we enter the window, activate the tablet
+                        [NSCursor hide];
+                        isTabletEnabled = TRUE;
+                    }
+                }
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseDown:
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                buttons |= MOUSE_EVENT_RBUTTON;
+            } else {
+                buttons |= MOUSE_EVENT_LBUTTON;
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSRightMouseDown:
+            buttons |= MOUSE_EVENT_RBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseDown:
+            buttons |= MOUSE_EVENT_MBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseDragged:
+            if ([event modifierFlags] & NSCommandKeyMask) {
+                buttons |= MOUSE_EVENT_RBUTTON;
+            } else {
+                buttons |= MOUSE_EVENT_LBUTTON;
+            }
+            COCOA_MOUSE_EVENT
+            break;
+        case NSRightMouseDragged:
+            buttons |= MOUSE_EVENT_RBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseDragged:
+            buttons |= MOUSE_EVENT_MBUTTON;
+            COCOA_MOUSE_EVENT
+            break;
+        case NSLeftMouseUp:
+            if (isTabletEnabled) {
+                    COCOA_MOUSE_EVENT
+            } else if (!isMouseGrabed) {
+                if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
+                    [self grabMouse];
+                } else {
+                    [NSApp sendEvent:event];
+                }
+            } else {
+                COCOA_MOUSE_EVENT
+            }
+            break;
+        case NSRightMouseUp:
+            COCOA_MOUSE_EVENT
+            break;
+        case NSOtherMouseUp:
+            COCOA_MOUSE_EVENT
+            break;
+        case NSScrollWheel:
+            if (isTabletEnabled || isMouseGrabed) {
+                kbd_mouse_event(0, 0, -[event deltaY], 0);
+            } else {
+                [NSApp sendEvent:event];
+            }
+            break;
+        default:
+            [NSApp sendEvent:event];
+    }
+}
+
+- (void) grabMouse
+{
+    COCOA_DEBUG("QemuCocoaView: grabMouse\n");
+
+    if (!isFullscreen) {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
+        else
+            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
+    }
+    [NSCursor hide];
+    CGAssociateMouseAndMouseCursorPosition(FALSE);
+    isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
+}
+
+- (void) ungrabMouse
+{
+    COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
+
+    if (!isFullscreen) {
+        if (qemu_name)
+            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
+        else
+            [normalWindow setTitle:@"QEMU"];
+    }
+    [NSCursor unhide];
+    CGAssociateMouseAndMouseCursorPosition(TRUE);
+    isMouseGrabed = FALSE;
+}
+
+- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
+- (BOOL) isMouseGrabed {return isMouseGrabed;}
+- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
+- (float) cdx {return cdx;}
+- (float) cdy {return cdy;}
+- (QEMUScreen) gscreen {return screen;}
+ at end
+
+
+
+/*
+ ------------------------------------------------------
+    QemuCocoaAppController
+ ------------------------------------------------------
+*/
+ at interface QemuCocoaAppController : NSObject
+{
+}
+- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
+- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+- (void)toggleFullScreen:(id)sender;
+- (void)showQEMUDoc:(id)sender;
+- (void)showQEMUTec:(id)sender;
+ at end
+
+ at implementation QemuCocoaAppController
+- (id) init
+{
+    COCOA_DEBUG("QemuCocoaAppController: init\n");
+
+    self = [super init];
+    if (self) {
+
+        // create a view and add it to the window
+        cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
+        if(!cocoaView) {
+            fprintf(stderr, "(cocoa) can't create a view\n");
+            exit(1);
+        }
+
+        // create a window
+        normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
+            styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
+            backing:NSBackingStoreBuffered defer:NO];
+        if(!normalWindow) {
+            fprintf(stderr, "(cocoa) can't create window\n");
+            exit(1);
+        }
+        [normalWindow setAcceptsMouseMovedEvents:YES];
+        [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
+        [normalWindow setContentView:cocoaView];
+        [normalWindow useOptimizedDrawing:YES];
+        [normalWindow makeKeyAndOrderFront:self];
+		[normalWindow center];
+
+    }
+    return self;
+}
+
+- (void) dealloc
+{
+    COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
+
+    if (cocoaView)
+        [cocoaView release];
+    [super dealloc];
+}
+
+- (void)applicationDidFinishLaunching: (NSNotification *) note
+{
+    COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
+
+    // Display an open dialog box if no argument were passed or
+    // if qemu was launched from the finder ( the Finder passes "-psn" )
+    if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
+        NSOpenPanel *op = [[NSOpenPanel alloc] init];
+        [op setPrompt:@"Boot image"];
+        [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
+        [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
+              modalForWindow:normalWindow modalDelegate:self
+              didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
+    } else {
+        // or Launch Qemu, with the global args
+        [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
+    }
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification
+{
+    COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
+
+    qemu_system_shutdown_request();
+    exit(0);
+}
+
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
+{
+    return YES;
+}
+
+- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
+{
+    COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
+
+    int status;
+    status = qemu_main(argc, argv, *_NSGetEnviron());
+    exit(status);
+}
+
+- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+    COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
+
+    if(returnCode == NSCancelButton) {
+        exit(0);
+    } else if(returnCode == NSOKButton) {
+        const char *bin = "qemu";
+        char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
+
+        char **argv = (char**)malloc( sizeof(char*)*3 );
+
+        asprintf(&argv[0], "%s", bin);
+        asprintf(&argv[1], "-hda");
+        asprintf(&argv[2], "%s", img);
+
+        printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
+
+        [self startEmulationWithArgc:3 argv:(char**)argv];
+    }
+}
+- (void)toggleFullScreen:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
+
+    [cocoaView toggleFullScreen:sender];
+}
+
+- (void)showQEMUDoc:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
+
+    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
+        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+}
+
+- (void)showQEMUTec:(id)sender
+{
+    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
+
+    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
+        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+}
+ at end
+
+
+
+// Dock Connection
+typedef struct CPSProcessSerNum
+{
+        UInt32                lo;
+        UInt32                hi;
+} CPSProcessSerNum;
+
+OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
+OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+int main (int argc, const char * argv[]) {
+
+    gArgc = argc;
+    gArgv = (char **)argv;
+    CPSProcessSerNum PSN;
+    int i;
+
+    /* In case we don't need to display a window, let's not do that */
+    for (i = 1; i < argc; i++) {
+        const char *opt = argv[i];
+
+        if (opt[0] == '-') {
+            /* Treat --foo the same as -foo.  */
+            if (opt[1] == '-') {
+                opt++;
+            }
+            if (!strcmp(opt, "-h") || !strcmp(opt, "-help") ||
+                !strcmp(opt, "-vnc") ||
+                !strcmp(opt, "-nographic") ||
+                !strcmp(opt, "-version") ||
+                !strcmp(opt, "-curses")) {
+                return qemu_main(gArgc, gArgv, *_NSGetEnviron());
+            }
+        }
+    }
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    [NSApplication sharedApplication];
+
+    if (!CPSGetCurrentProcess(&PSN))
+        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+            if (!CPSSetFrontProcess(&PSN))
+                [NSApplication sharedApplication];
+
+    // Add menus
+    NSMenu      *menu;
+    NSMenuItem  *menuItem;
+
+    [NSApp setMainMenu:[[NSMenu alloc] init]];
+
+    // Application menu
+    menu = [[NSMenu alloc] initWithTitle:@""];
+    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
+    [menu addItem:[NSMenuItem separatorItem]]; //Separator
+    [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
+    menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
+    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+    [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
+    [menu addItem:[NSMenuItem separatorItem]]; //Separator
+    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+    [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
+
+    // View menu
+    menu = [[NSMenu alloc] initWithTitle:@"View"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+
+    // Window menu
+    menu = [[NSMenu alloc] initWithTitle:@"Window"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+    [NSApp setWindowsMenu:menu];
+
+    // Help menu
+    menu = [[NSMenu alloc] initWithTitle:@"Help"];
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+
+    // Create an Application controller
+    QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
+    [NSApp setDelegate:appController];
+
+    // Start the main event loop
+    [NSApp run];
+
+    [appController release];
+    [pool release];
+
+    return 0;
+}
+
+
+
+#pragma mark qemu
+static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
+
+    NSRect rect;
+    if ([cocoaView cdx] == 1.0) {
+        rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
+    } else {
+        rect = NSMakeRect(
+            x * [cocoaView cdx],
+            ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
+            w * [cocoaView cdx],
+            h * [cocoaView cdy]);
+    }
+    [cocoaView setNeedsDisplayInRect:rect];
+}
+
+static void cocoa_resize(DisplayState *ds)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
+
+    [cocoaView resizeContentToWidth:(int)(ds_get_width(ds)) height:(int)(ds_get_height(ds)) displayState:ds];
+}
+
+static void cocoa_refresh(DisplayState *ds)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
+
+    if (kbd_mouse_is_absolute()) {
+        if (![cocoaView isAbsoluteEnabled]) {
+            if ([cocoaView isMouseGrabed]) {
+                [cocoaView ungrabMouse];
+            }
+        }
+        [cocoaView setAbsoluteEnabled:YES];
+    }
+
+    NSDate *distantPast;
+    NSEvent *event;
+    distantPast = [NSDate distantPast];
+    do {
+        event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
+                        inMode: NSDefaultRunLoopMode dequeue:YES];
+        if (event != nil) {
+            [cocoaView handleEvent:event];
+        }
+    } while(event != nil);
+    vga_hw_update();
+}
+
+static void cocoa_cleanup(void)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
+	qemu_free(dcl);
+}
+
+void cocoa_display_init(DisplayState *ds, int full_screen)
+{
+    COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
+
+	dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+	
+    // register vga output callbacks
+    dcl->dpy_update = cocoa_update;
+    dcl->dpy_resize = cocoa_resize;
+    dcl->dpy_refresh = cocoa_refresh;
+
+	register_displaychangelistener(ds, dcl);
+
+    // register cleanup function
+    atexit(cocoa_cleanup);
+}
diff --git a/qemu-0.15.x/ui/curses.c b/qemu-0.15.x/ui/curses.c
new file mode 100644
index 0000000..d29b6cf
--- /dev/null
+++ b/qemu-0.15.x/ui/curses.c
@@ -0,0 +1,367 @@
+/*
+ * QEMU curses/ncurses display driver
+ * 
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog at zabor.org>
+ * 
+ * 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 <curses.h>
+
+#ifndef _WIN32
+#include <sys/ioctl.h>
+#include <termios.h>
+#endif
+
+#ifdef __OpenBSD__
+#define resize_term resizeterm
+#endif
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+static console_ch_t screen[160 * 100];
+static WINDOW *screenpad = NULL;
+static int width, height, gwidth, gheight, invalidate;
+static int px, py, sminx, sminy, smaxx, smaxy;
+
+static void curses_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    chtype *line;
+
+    line = ((chtype *) screen) + y * width;
+    for (h += y; y < h; y ++, line += width)
+        mvwaddchnstr(screenpad, y, 0, line, width);
+
+    pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
+    refresh();
+}
+
+static void curses_calc_pad(void)
+{
+    if (is_fixedsize_console()) {
+        width = gwidth;
+        height = gheight;
+    } else {
+        width = COLS;
+        height = LINES;
+    }
+
+    if (screenpad)
+        delwin(screenpad);
+
+    clear();
+    refresh();
+
+    screenpad = newpad(height, width);
+
+    if (width > COLS) {
+        px = (width - COLS) / 2;
+        sminx = 0;
+        smaxx = COLS;
+    } else {
+        px = 0;
+        sminx = (COLS - width) / 2;
+        smaxx = sminx + width;
+    }
+
+    if (height > LINES) {
+        py = (height - LINES) / 2;
+        sminy = 0;
+        smaxy = LINES;
+    } else {
+        py = 0;
+        sminy = (LINES - height) / 2;
+        smaxy = sminy + height;
+    }
+}
+
+static void curses_resize(DisplayState *ds)
+{
+    if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
+        return;
+
+    gwidth = ds_get_width(ds);
+    gheight = ds_get_height(ds);
+
+    curses_calc_pad();
+    ds->surface->width = width * FONT_WIDTH;
+    ds->surface->height = height * FONT_HEIGHT;
+}
+
+#ifndef _WIN32
+#if defined(SIGWINCH) && defined(KEY_RESIZE)
+static void curses_winch_handler(int signum)
+{
+    struct winsize {
+        unsigned short ws_row;
+        unsigned short ws_col;
+        unsigned short ws_xpixel;   /* unused */
+        unsigned short ws_ypixel;   /* unused */
+    } ws;
+
+    /* terminal size changed */
+    if (ioctl(1, TIOCGWINSZ, &ws) == -1)
+        return;
+
+    resize_term(ws.ws_row, ws.ws_col);
+    curses_calc_pad();
+    invalidate = 1;
+
+    /* some systems require this */
+    signal(SIGWINCH, curses_winch_handler);
+}
+#endif
+#endif
+
+static void curses_cursor_position(DisplayState *ds, int x, int y)
+{
+    if (x >= 0) {
+        x = sminx + x - px;
+        y = sminy + y - py;
+
+        if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
+            move(y, x);
+            curs_set(1);
+            /* it seems that curs_set(1) must always be called before
+             * curs_set(2) for the latter to have effect */
+            if (!is_graphic_console())
+                curs_set(2);
+            return;
+        }
+    }
+
+    curs_set(0);
+}
+
+/* generic keyboard conversion */
+
+#include "curses_keys.h"
+
+static kbd_layout_t *kbd_layout = NULL;
+
+static void curses_refresh(DisplayState *ds)
+{
+    int chr, nextchr, keysym, keycode, keycode_alt;
+
+    if (invalidate) {
+        clear();
+        refresh();
+        curses_calc_pad();
+        ds->surface->width = FONT_WIDTH * width;
+        ds->surface->height = FONT_HEIGHT * height;
+        vga_hw_invalidate();
+        invalidate = 0;
+    }
+
+    vga_hw_text_update(screen);
+
+    nextchr = ERR;
+    while (1) {
+        /* while there are any pending key strokes to process */
+        if (nextchr == ERR)
+            chr = getch();
+        else {
+            chr = nextchr;
+            nextchr = ERR;
+        }
+
+        if (chr == ERR)
+            break;
+
+#ifdef KEY_RESIZE
+        /* this shouldn't occur when we use a custom SIGWINCH handler */
+        if (chr == KEY_RESIZE) {
+            clear();
+            refresh();
+            curses_calc_pad();
+            curses_update(ds, 0, 0, width, height);
+            ds->surface->width = FONT_WIDTH * width;
+            ds->surface->height = FONT_HEIGHT * height;
+            continue;
+        }
+#endif
+
+        keycode = curses2keycode[chr];
+        keycode_alt = 0;
+
+        /* alt key */
+        if (keycode == 1) {
+            nextchr = getch();
+
+            if (nextchr != ERR) {
+                chr = nextchr;
+                keycode_alt = ALT;
+                keycode = curses2keycode[nextchr];
+                nextchr = ERR;
+
+                if (keycode != -1) {
+                    keycode |= ALT;
+
+                    /* process keys reserved for qemu */
+                    if (keycode >= QEMU_KEY_CONSOLE0 &&
+                            keycode < QEMU_KEY_CONSOLE0 + 9) {
+                        erase();
+                        wnoutrefresh(stdscr);
+                        console_select(keycode - QEMU_KEY_CONSOLE0);
+
+                        invalidate = 1;
+                        continue;
+                    }
+                }
+            }
+        }
+
+        if (kbd_layout) {
+            keysym = -1;
+            if (chr < CURSES_KEYS)
+                keysym = curses2keysym[chr];
+
+            if (keysym == -1) {
+                if (chr < ' ') {
+                    keysym = chr + '@';
+                    if (keysym >= 'A' && keysym <= 'Z')
+                        keysym += 'a' - 'A';
+                    keysym |= KEYSYM_CNTRL;
+                } else
+                    keysym = chr;
+            }
+
+            keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
+            if (keycode == 0)
+                continue;
+
+            keycode |= (keysym & ~KEYSYM_MASK) >> 16;
+            keycode |= keycode_alt;
+        }
+
+        if (keycode == -1)
+            continue;
+
+        if (is_graphic_console()) {
+            /* since terminals don't know about key press and release
+             * events, we need to emit both for each key received */
+            if (keycode & SHIFT)
+                kbd_put_keycode(SHIFT_CODE);
+            if (keycode & CNTRL)
+                kbd_put_keycode(CNTRL_CODE);
+            if (keycode & ALT)
+                kbd_put_keycode(ALT_CODE);
+            if (keycode & ALTGR) {
+                kbd_put_keycode(SCANCODE_EMUL0);
+                kbd_put_keycode(ALT_CODE);
+            }
+            if (keycode & GREY)
+                kbd_put_keycode(GREY_CODE);
+            kbd_put_keycode(keycode & KEY_MASK);
+            if (keycode & GREY)
+                kbd_put_keycode(GREY_CODE);
+            kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
+            if (keycode & ALTGR) {
+                kbd_put_keycode(SCANCODE_EMUL0);
+                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
+            }
+            if (keycode & ALT)
+                kbd_put_keycode(ALT_CODE | KEY_RELEASE);
+            if (keycode & CNTRL)
+                kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
+            if (keycode & SHIFT)
+                kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
+        } else {
+            keysym = curses2qemu[chr];
+            if (keysym == -1)
+                keysym = chr;
+
+            kbd_put_keysym(keysym);
+        }
+    }
+}
+
+static void curses_atexit(void)
+{
+    endwin();
+}
+
+static void curses_setup(void)
+{
+    int i, colour_default[8] = {
+        COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
+        COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
+    };
+
+    /* input as raw as possible, let everything be interpreted
+     * by the guest system */
+    initscr(); noecho(); intrflush(stdscr, FALSE);
+    nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
+    start_color(); raw(); scrollok(stdscr, FALSE);
+
+    for (i = 0; i < 64; i ++)
+        init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
+}
+
+static void curses_keyboard_setup(void)
+{
+#if defined(__APPLE__)
+    /* always use generic keymaps */
+    if (!keyboard_layout)
+        keyboard_layout = "en-us";
+#endif
+    if(keyboard_layout) {
+        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+        if (!kbd_layout)
+            exit(1);
+    }
+}
+
+void curses_display_init(DisplayState *ds, int full_screen)
+{
+    DisplayChangeListener *dcl;
+#ifndef _WIN32
+    if (!isatty(1)) {
+        fprintf(stderr, "We need a terminal output\n");
+        exit(1);
+    }
+#endif
+
+    curses_setup();
+    curses_keyboard_setup();
+    atexit(curses_atexit);
+
+#ifndef _WIN32
+#if defined(SIGWINCH) && defined(KEY_RESIZE)
+    /* some curses implementations provide a handler, but we
+     * want to be sure this is handled regardless of the library */
+    signal(SIGWINCH, curses_winch_handler);
+#endif
+#endif
+
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = curses_update;
+    dcl->dpy_resize = curses_resize;
+    dcl->dpy_refresh = curses_refresh;
+    dcl->dpy_text_cursor = curses_cursor_position;
+    register_displaychangelistener(ds, dcl);
+    qemu_free_displaysurface(ds);
+    ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
+
+    invalidate = 1;
+}
diff --git a/qemu-0.15.x/ui/curses_keys.h b/qemu-0.15.x/ui/curses_keys.h
new file mode 100644
index 0000000..c0d5eb4
--- /dev/null
+++ b/qemu-0.15.x/ui/curses_keys.h
@@ -0,0 +1,509 @@
+/*
+ * Keycode and keysyms conversion tables for curses
+ * 
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog at zabor.org>
+ * 
+ * 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 <curses.h>
+#include "keymaps.h"
+
+
+#define KEY_RELEASE         0x80
+#define KEY_MASK            0x7f
+#define GREY_CODE           0xe0
+#define GREY                SCANCODE_GREY
+#define SHIFT_CODE          0x2a
+#define SHIFT               SCANCODE_SHIFT
+#define CNTRL_CODE          0x1d
+#define CNTRL               SCANCODE_CTRL
+#define ALT_CODE            0x38
+#define ALT                 SCANCODE_ALT
+#define ALTGR               SCANCODE_ALTGR
+
+#define KEYSYM_MASK         0x0ffffff
+#define KEYSYM_SHIFT        (SCANCODE_SHIFT << 16)
+#define KEYSYM_CNTRL        (SCANCODE_CTRL  << 16)
+#define KEYSYM_ALT          (SCANCODE_ALT   << 16)
+#define KEYSYM_ALTGR        (SCANCODE_ALTGR << 16)
+
+/* curses won't detect a Control + Alt + 1, so use Alt + 1 */
+#define QEMU_KEY_CONSOLE0   (2 | ALT)   /* (curses2keycode['1'] | ALT) */
+
+#define CURSES_KEYS         KEY_MAX     /* KEY_MAX defined in <curses.h> */
+
+static const int curses2keysym[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    [0x7f] = KEY_BACKSPACE,
+    ['\r'] = KEY_ENTER,
+    ['\n'] = KEY_ENTER,
+    [27] = 27,
+    [KEY_BTAB] = '\t' | KEYSYM_SHIFT,
+};
+
+static const int curses2keycode[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    [0x01b] = 1, /* Escape */
+    ['1'] = 2,
+    ['2'] = 3,
+    ['3'] = 4,
+    ['4'] = 5,
+    ['5'] = 6,
+    ['6'] = 7,
+    ['7'] = 8,
+    ['8'] = 9,
+    ['9'] = 10,
+    ['0'] = 11,
+    ['-'] = 12,
+    ['='] = 13,
+    [0x07f] = 14, /* Backspace */
+    [KEY_BACKSPACE] = 14, /* Backspace */
+
+    ['\t'] = 15, /* Tab */
+    ['q'] = 16,
+    ['w'] = 17,
+    ['e'] = 18,
+    ['r'] = 19,
+    ['t'] = 20,
+    ['y'] = 21,
+    ['u'] = 22,
+    ['i'] = 23,
+    ['o'] = 24,
+    ['p'] = 25,
+    ['['] = 26,
+    [']'] = 27,
+    ['\n'] = 28, /* Return */
+    ['\r'] = 28, /* Return */
+    [KEY_ENTER] = 28, /* Return */
+
+    ['a'] = 30,
+    ['s'] = 31,
+    ['d'] = 32,
+    ['f'] = 33,
+    ['g'] = 34,
+    ['h'] = 35,
+    ['j'] = 36,
+    ['k'] = 37,
+    ['l'] = 38,
+    [';'] = 39,
+    ['\''] = 40, /* Single quote */
+    ['`'] = 41,
+    ['\\'] = 43, /* Backslash */
+
+    ['z'] = 44,
+    ['x'] = 45,
+    ['c'] = 46,
+    ['v'] = 47,
+    ['b'] = 48,
+    ['n'] = 49,
+    ['m'] = 50,
+    [','] = 51,
+    ['.'] = 52,
+    ['/'] = 53,
+
+    [' '] = 57,
+
+    [KEY_F(1)] = 59, /* Function Key 1 */
+    [KEY_F(2)] = 60, /* Function Key 2 */
+    [KEY_F(3)] = 61, /* Function Key 3 */
+    [KEY_F(4)] = 62, /* Function Key 4 */
+    [KEY_F(5)] = 63, /* Function Key 5 */
+    [KEY_F(6)] = 64, /* Function Key 6 */
+    [KEY_F(7)] = 65, /* Function Key 7 */
+    [KEY_F(8)] = 66, /* Function Key 8 */
+    [KEY_F(9)] = 67, /* Function Key 9 */
+    [KEY_F(10)] = 68, /* Function Key 10 */
+    [KEY_F(11)] = 87, /* Function Key 11 */
+    [KEY_F(12)] = 88, /* Function Key 12 */
+
+    [KEY_HOME] = 71 | GREY, /* Home */
+    [KEY_UP] = 72 | GREY, /* Up Arrow */
+    [KEY_PPAGE] = 73 | GREY, /* Page Up */
+    [KEY_LEFT] = 75 | GREY, /* Left Arrow */
+    [KEY_RIGHT] = 77 | GREY, /* Right Arrow */
+    [KEY_END] = 79 | GREY, /* End */
+    [KEY_DOWN] = 80 | GREY, /* Down Arrow */
+    [KEY_NPAGE] = 81 | GREY, /* Page Down */
+    [KEY_IC] = 82 | GREY, /* Insert */
+    [KEY_DC] = 83 | GREY, /* Delete */
+
+    ['!'] = 2 | SHIFT,
+    ['@'] = 3 | SHIFT,
+    ['#'] = 4 | SHIFT,
+    ['$'] = 5 | SHIFT,
+    ['%'] = 6 | SHIFT,
+    ['^'] = 7 | SHIFT,
+    ['&'] = 8 | SHIFT,
+    ['*'] = 9 | SHIFT,
+    ['('] = 10 | SHIFT,
+    [')'] = 11 | SHIFT,
+    ['_'] = 12 | SHIFT,
+    ['+'] = 13 | SHIFT,
+
+    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
+    ['Q'] = 16 | SHIFT,
+    ['W'] = 17 | SHIFT,
+    ['E'] = 18 | SHIFT,
+    ['R'] = 19 | SHIFT,
+    ['T'] = 20 | SHIFT,
+    ['Y'] = 21 | SHIFT,
+    ['U'] = 22 | SHIFT,
+    ['I'] = 23 | SHIFT,
+    ['O'] = 24 | SHIFT,
+    ['P'] = 25 | SHIFT,
+    ['{'] = 26 | SHIFT,
+    ['}'] = 27 | SHIFT,
+
+    ['A'] = 30 | SHIFT,
+    ['S'] = 31 | SHIFT,
+    ['D'] = 32 | SHIFT,
+    ['F'] = 33 | SHIFT,
+    ['G'] = 34 | SHIFT,
+    ['H'] = 35 | SHIFT,
+    ['J'] = 36 | SHIFT,
+    ['K'] = 37 | SHIFT,
+    ['L'] = 38 | SHIFT,
+    [':'] = 39 | SHIFT,
+    ['"'] = 40 | SHIFT,
+    ['~'] = 41 | SHIFT,
+    ['|'] = 43 | SHIFT,
+
+    ['Z'] = 44 | SHIFT,
+    ['X'] = 45 | SHIFT,
+    ['C'] = 46 | SHIFT,
+    ['V'] = 47 | SHIFT,
+    ['B'] = 48 | SHIFT,
+    ['N'] = 49 | SHIFT,
+    ['M'] = 50 | SHIFT,
+    ['<'] = 51 | SHIFT,
+    ['>'] = 52 | SHIFT,
+    ['?'] = 53 | SHIFT,
+
+    [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
+    [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
+    [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
+    [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
+    [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
+    [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
+    [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
+    [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
+    [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
+    [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
+    [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
+    [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
+
+    ['Q' - '@'] = 16 | CNTRL, /* Control + q */
+    ['W' - '@'] = 17 | CNTRL, /* Control + w */
+    ['E' - '@'] = 18 | CNTRL, /* Control + e */
+    ['R' - '@'] = 19 | CNTRL, /* Control + r */
+    ['T' - '@'] = 20 | CNTRL, /* Control + t */
+    ['Y' - '@'] = 21 | CNTRL, /* Control + y */
+    ['U' - '@'] = 22 | CNTRL, /* Control + u */
+    /* Control + i collides with Tab */
+    ['O' - '@'] = 24 | CNTRL, /* Control + o */
+    ['P' - '@'] = 25 | CNTRL, /* Control + p */
+
+    ['A' - '@'] = 30 | CNTRL, /* Control + a */
+    ['S' - '@'] = 31 | CNTRL, /* Control + s */
+    ['D' - '@'] = 32 | CNTRL, /* Control + d */
+    ['F' - '@'] = 33 | CNTRL, /* Control + f */
+    ['G' - '@'] = 34 | CNTRL, /* Control + g */
+    ['H' - '@'] = 35 | CNTRL, /* Control + h */
+    /* Control + j collides with Return */
+    ['K' - '@'] = 37 | CNTRL, /* Control + k */
+    ['L' - '@'] = 38 | CNTRL, /* Control + l */
+
+    ['Z' - '@'] = 44 | CNTRL, /* Control + z */
+    ['X' - '@'] = 45 | CNTRL, /* Control + x */
+    ['C' - '@'] = 46 | CNTRL, /* Control + c */
+    ['V' - '@'] = 47 | CNTRL, /* Control + v */
+    ['B' - '@'] = 48 | CNTRL, /* Control + b */
+    ['N' - '@'] = 49 | CNTRL, /* Control + n */
+    /* Control + m collides with the keycode for Enter */
+
+};
+
+static const int curses2qemu[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
+    ['\n'] = '\n',
+    ['\r'] = '\n',
+
+    [0x07f] = QEMU_KEY_BACKSPACE,
+
+    [KEY_DOWN] = QEMU_KEY_DOWN,
+    [KEY_UP] = QEMU_KEY_UP,
+    [KEY_LEFT] = QEMU_KEY_LEFT,
+    [KEY_RIGHT] = QEMU_KEY_RIGHT,
+    [KEY_HOME] = QEMU_KEY_HOME,
+    [KEY_BACKSPACE] = QEMU_KEY_BACKSPACE,
+
+    [KEY_DC] = QEMU_KEY_DELETE,
+    [KEY_NPAGE] = QEMU_KEY_PAGEDOWN,
+    [KEY_PPAGE] = QEMU_KEY_PAGEUP,
+    [KEY_ENTER] = '\n',
+    [KEY_END] = QEMU_KEY_END,
+
+};
+
+static const name2keysym_t name2keysym[] = {
+    /* Plain ASCII */
+    { "space", 0x020 },
+    { "exclam", 0x021 },
+    { "quotedbl", 0x022 },
+    { "numbersign", 0x023 },
+    { "dollar", 0x024 },
+    { "percent", 0x025 },
+    { "ampersand", 0x026 },
+    { "apostrophe", 0x027 },
+    { "parenleft", 0x028 },
+    { "parenright", 0x029 },
+    { "asterisk", 0x02a },
+    { "plus", 0x02b },
+    { "comma", 0x02c },
+    { "minus", 0x02d },
+    { "period", 0x02e },
+    { "slash", 0x02f },
+    { "0", 0x030 },
+    { "1", 0x031 },
+    { "2", 0x032 },
+    { "3", 0x033 },
+    { "4", 0x034 },
+    { "5", 0x035 },
+    { "6", 0x036 },
+    { "7", 0x037 },
+    { "8", 0x038 },
+    { "9", 0x039 },
+    { "colon", 0x03a },
+    { "semicolon", 0x03b },
+    { "less", 0x03c },
+    { "equal", 0x03d },
+    { "greater", 0x03e },
+    { "question", 0x03f },
+    { "at", 0x040 },
+    { "A", 0x041 },
+    { "B", 0x042 },
+    { "C", 0x043 },
+    { "D", 0x044 },
+    { "E", 0x045 },
+    { "F", 0x046 },
+    { "G", 0x047 },
+    { "H", 0x048 },
+    { "I", 0x049 },
+    { "J", 0x04a },
+    { "K", 0x04b },
+    { "L", 0x04c },
+    { "M", 0x04d },
+    { "N", 0x04e },
+    { "O", 0x04f },
+    { "P", 0x050 },
+    { "Q", 0x051 },
+    { "R", 0x052 },
+    { "S", 0x053 },
+    { "T", 0x054 },
+    { "U", 0x055 },
+    { "V", 0x056 },
+    { "W", 0x057 },
+    { "X", 0x058 },
+    { "Y", 0x059 },
+    { "Z", 0x05a },
+    { "bracketleft", 0x05b },
+    { "backslash", 0x05c },
+    { "bracketright", 0x05d },
+    { "asciicircum", 0x05e },
+    { "underscore", 0x05f },
+    { "grave", 0x060 },
+    { "a", 0x061 },
+    { "b", 0x062 },
+    { "c", 0x063 },
+    { "d", 0x064 },
+    { "e", 0x065 },
+    { "f", 0x066 },
+    { "g", 0x067 },
+    { "h", 0x068 },
+    { "i", 0x069 },
+    { "j", 0x06a },
+    { "k", 0x06b },
+    { "l", 0x06c },
+    { "m", 0x06d },
+    { "n", 0x06e },
+    { "o", 0x06f },
+    { "p", 0x070 },
+    { "q", 0x071 },
+    { "r", 0x072 },
+    { "s", 0x073 },
+    { "t", 0x074 },
+    { "u", 0x075 },
+    { "v", 0x076 },
+    { "w", 0x077 },
+    { "x", 0x078 },
+    { "y", 0x079 },
+    { "z", 0x07a },
+    { "braceleft", 0x07b },
+    { "bar", 0x07c },
+    { "braceright", 0x07d },
+    { "asciitilde", 0x07e },
+
+    /* Latin-1 extensions */
+    { "nobreakspace", 0x0a0 },
+    { "exclamdown", 0x0a1 },
+    { "cent", 0x0a2 },
+    { "sterling", 0x0a3 },
+    { "currency", 0x0a4 },
+    { "yen", 0x0a5 },
+    { "brokenbar", 0x0a6 },
+    { "section", 0x0a7 },
+    { "diaeresis", 0x0a8 },
+    { "copyright", 0x0a9 },
+    { "ordfeminine", 0x0aa },
+    { "guillemotleft", 0x0ab },
+    { "notsign", 0x0ac },
+    { "hyphen", 0x0ad },
+    { "registered", 0x0ae },
+    { "macron", 0x0af },
+    { "degree", 0x0b0 },
+    { "plusminus", 0x0b1 },
+    { "twosuperior", 0x0b2 },
+    { "threesuperior", 0x0b3 },
+    { "acute", 0x0b4 },
+    { "mu", 0x0b5 },
+    { "paragraph", 0x0b6 },
+    { "periodcentered", 0x0b7 },
+    { "cedilla", 0x0b8 },
+    { "onesuperior", 0x0b9 },
+    { "masculine", 0x0ba },
+    { "guillemotright", 0x0bb },
+    { "onequarter", 0x0bc },
+    { "onehalf", 0x0bd },
+    { "threequarters", 0x0be },
+    { "questiondown", 0x0bf },
+    { "Agrave", 0x0c0 },
+    { "Aacute", 0x0c1 },
+    { "Acircumflex", 0x0c2 },
+    { "Atilde", 0x0c3 },
+    { "Adiaeresis", 0x0c4 },
+    { "Aring", 0x0c5 },
+    { "AE", 0x0c6 },
+    { "Ccedilla", 0x0c7 },
+    { "Egrave", 0x0c8 },
+    { "Eacute", 0x0c9 },
+    { "Ecircumflex", 0x0ca },
+    { "Ediaeresis", 0x0cb },
+    { "Igrave", 0x0cc },
+    { "Iacute", 0x0cd },
+    { "Icircumflex", 0x0ce },
+    { "Idiaeresis", 0x0cf },
+    { "ETH", 0x0d0 },
+    { "Eth", 0x0d0 },
+    { "Ntilde", 0x0d1 },
+    { "Ograve", 0x0d2 },
+    { "Oacute", 0x0d3 },
+    { "Ocircumflex", 0x0d4 },
+    { "Otilde", 0x0d5 },
+    { "Odiaeresis", 0x0d6 },
+    { "multiply", 0x0d7 },
+    { "Ooblique", 0x0d8 },
+    { "Oslash", 0x0d8 },
+    { "Ugrave", 0x0d9 },
+    { "Uacute", 0x0da },
+    { "Ucircumflex", 0x0db },
+    { "Udiaeresis", 0x0dc },
+    { "Yacute", 0x0dd },
+    { "THORN", 0x0de },
+    { "Thorn", 0x0de },
+    { "ssharp", 0x0df },
+    { "agrave", 0x0e0 },
+    { "aacute", 0x0e1 },
+    { "acircumflex", 0x0e2 },
+    { "atilde", 0x0e3 },
+    { "adiaeresis", 0x0e4 },
+    { "aring", 0x0e5 },
+    { "ae", 0x0e6 },
+    { "ccedilla", 0x0e7 },
+    { "egrave", 0x0e8 },
+    { "eacute", 0x0e9 },
+    { "ecircumflex", 0x0ea },
+    { "ediaeresis", 0x0eb },
+    { "igrave", 0x0ec },
+    { "iacute", 0x0ed },
+    { "icircumflex", 0x0ee },
+    { "idiaeresis", 0x0ef },
+    { "eth", 0x0f0 },
+    { "ntilde", 0x0f1 },
+    { "ograve", 0x0f2 },
+    { "oacute", 0x0f3 },
+    { "ocircumflex", 0x0f4 },
+    { "otilde", 0x0f5 },
+    { "odiaeresis", 0x0f6 },
+    { "division", 0x0f7 },
+    { "oslash", 0x0f8 },
+    { "ooblique", 0x0f8 },
+    { "ugrave", 0x0f9 },
+    { "uacute", 0x0fa },
+    { "ucircumflex", 0x0fb },
+    { "udiaeresis", 0x0fc },
+    { "yacute", 0x0fd },
+    { "thorn", 0x0fe },
+    { "ydiaeresis", 0x0ff },
+
+    /* Special keys */
+    { "BackSpace", KEY_BACKSPACE },
+    { "Tab", '\t' },
+    { "Return", KEY_ENTER },
+    { "Right", KEY_RIGHT },
+    { "Left", KEY_LEFT },
+    { "Up", KEY_UP },
+    { "Down", KEY_DOWN },
+    { "Page_Down", KEY_NPAGE },
+    { "Page_Up", KEY_PPAGE },
+    { "Insert", KEY_IC },
+    { "Delete", KEY_DC },
+    { "Home", KEY_HOME },
+    { "End", KEY_END },
+    { "F1", KEY_F(1) },
+    { "F2", KEY_F(2) },
+    { "F3", KEY_F(3) },
+    { "F4", KEY_F(4) },
+    { "F5", KEY_F(5) },
+    { "F6", KEY_F(6) },
+    { "F7", KEY_F(7) },
+    { "F8", KEY_F(8) },
+    { "F9", KEY_F(9) },
+    { "F10", KEY_F(10) },
+    { "F11", KEY_F(11) },
+    { "F12", KEY_F(12) },
+    { "F13", KEY_F(13) },
+    { "F14", KEY_F(14) },
+    { "F15", KEY_F(15) },
+    { "F16", KEY_F(16) },
+    { "F17", KEY_F(17) },
+    { "F18", KEY_F(18) },
+    { "F19", KEY_F(19) },
+    { "F20", KEY_F(20) },
+    { "F21", KEY_F(21) },
+    { "F22", KEY_F(22) },
+    { "F23", KEY_F(23) },
+    { "F24", KEY_F(24) },
+    { "Escape", 27 },
+
+    { NULL, 0 },
+};
diff --git a/qemu-0.15.x/ui/d3des.c b/qemu-0.15.x/ui/d3des.c
new file mode 100644
index 0000000..60c840e
--- /dev/null
+++ b/qemu-0.15.x/ui/d3des.c
@@ -0,0 +1,424 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static const unsigned short bytebit[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static const unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static const unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static const unsigned char totrot[16] = {
+	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static const unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+/* Thanks to James Gillogly & Phil Karn! */
+void deskey(unsigned char *key, int edf)
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+		}
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+			}
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+		    }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+			}
+		}
+	cookey(kn);
+	return;
+	}
+
+static void cookey(register unsigned long *raw1)
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+		}
+	usekey(dough);
+	return;
+	}
+
+void cpkey(register unsigned long *into)
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+	}
+
+void usekey(register unsigned long *from)
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+	}
+
+void des(unsigned char *inblock, unsigned char *outblock)
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+	}
+
+static void scrunch(register unsigned char *outof, register unsigned long *into)
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+	}
+
+static void unscrun(register unsigned long *outof, register unsigned char *into)
+{
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into++ = (unsigned char)(*outof++	 & 0xffL);
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into	=  (unsigned char)(*outof	 & 0xffL);
+	return;
+	}
+
+static const unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static const unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static const unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static const unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static const unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static const unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static const unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static const unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(register unsigned long *block, register unsigned long *keys)
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+		}
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+	}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/qemu-0.15.x/ui/d3des.h b/qemu-0.15.x/ui/d3des.h
new file mode 100644
index 0000000..78d546f
--- /dev/null
+++ b/qemu-0.15.x/ui/d3des.h
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* d3des.h -
+ *
+ *	Headers and defines for d3des.c
+ *	Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *	(GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0	0	/* MODE == encrypt */
+#define DE1	1	/* MODE == decrypt */
+
+void deskey(unsigned char *, int);
+/*		      hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+void usekey(unsigned long *);
+/*		    cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+void cpkey(unsigned long *);
+/*		   cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+void des(unsigned char *, unsigned char *);
+/*		    from[8]	      to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/qemu-0.15.x/ui/keymaps.c b/qemu-0.15.x/ui/keymaps.c
new file mode 100644
index 0000000..78c7ea3
--- /dev/null
+++ b/qemu-0.15.x/ui/keymaps.c
@@ -0,0 +1,210 @@
+/*
+ * QEMU keysym to keycode conversion using rdesktop keymaps
+ *
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * 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 "keymaps.h"
+#include "sysemu.h"
+
+static int get_keysym(const name2keysym_t *table,
+		      const char *name)
+{
+    const name2keysym_t *p;
+    for(p = table; p->name != NULL; p++) {
+        if (!strcmp(p->name, name))
+            return p->keysym;
+    }
+    return 0;
+}
+
+
+static void add_to_key_range(struct key_range **krp, int code) {
+    struct key_range *kr;
+    for (kr = *krp; kr; kr = kr->next) {
+	if (code >= kr->start && code <= kr->end)
+	    break;
+	if (code == kr->start - 1) {
+	    kr->start--;
+	    break;
+	}
+	if (code == kr->end + 1) {
+	    kr->end++;
+	    break;
+	}
+    }
+    if (kr == NULL) {
+	kr = qemu_mallocz(sizeof(*kr));
+        kr->start = kr->end = code;
+        kr->next = *krp;
+        *krp = kr;
+    }
+}
+
+static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) {
+    if (keysym < MAX_NORMAL_KEYCODE) {
+	//fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
+	k->keysym2keycode[keysym] = keycode;
+    } else {
+	if (k->extra_count >= MAX_EXTRA_COUNT) {
+	    fprintf(stderr,
+		    "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n",
+		    line, keysym);
+	} else {
+#if 0
+	    fprintf(stderr, "Setting %d: %d,%d\n",
+		    k->extra_count, keysym, keycode);
+#endif
+	    k->keysym2keycode_extra[k->extra_count].
+		keysym = keysym;
+	    k->keysym2keycode_extra[k->extra_count].
+		keycode = keycode;
+	    k->extra_count++;
+	}
+    }
+}
+
+static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
+					   const char *language,
+					   kbd_layout_t * k)
+{
+    FILE *f;
+    char * filename;
+    char line[1024];
+    int len;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
+
+    if (!k)
+	k = qemu_mallocz(sizeof(kbd_layout_t));
+    if (!(filename && (f = fopen(filename, "r")))) {
+	fprintf(stderr,
+		"Could not read keymap file: '%s'\n", language);
+	return NULL;
+    }
+    qemu_free(filename);
+    for(;;) {
+	if (fgets(line, 1024, f) == NULL)
+            break;
+        len = strlen(line);
+        if (len > 0 && line[len - 1] == '\n')
+            line[len - 1] = '\0';
+        if (line[0] == '#')
+	    continue;
+	if (!strncmp(line, "map ", 4))
+	    continue;
+	if (!strncmp(line, "include ", 8)) {
+	    parse_keyboard_layout(table, line + 8, k);
+        } else {
+	    char *end_of_keysym = line;
+	    while (*end_of_keysym != 0 && *end_of_keysym != ' ')
+		end_of_keysym++;
+	    if (*end_of_keysym) {
+		int keysym;
+		*end_of_keysym = 0;
+		keysym = get_keysym(table, line);
+		if (keysym == 0) {
+                    //		    fprintf(stderr, "Warning: unknown keysym %s\n", line);
+		} else {
+		    const char *rest = end_of_keysym + 1;
+		    char *rest2;
+		    int keycode = strtol(rest, &rest2, 0);
+
+		    if (rest && strstr(rest, "numlock")) {
+			add_to_key_range(&k->keypad_range, keycode);
+			add_to_key_range(&k->numlock_range, keysym);
+			//fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode);
+		    }
+
+		    if (rest && strstr(rest, "shift"))
+			keycode |= SCANCODE_SHIFT;
+		    if (rest && strstr(rest, "altgr"))
+			keycode |= SCANCODE_ALTGR;
+		    if (rest && strstr(rest, "ctrl"))
+			keycode |= SCANCODE_CTRL;
+
+		    add_keysym(line, keysym, keycode, k);
+
+		    if (rest && strstr(rest, "addupper")) {
+			char *c;
+			for (c = line; *c; c++)
+			    *c = toupper(*c);
+			keysym = get_keysym(table, line);
+			if (keysym)
+			    add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k);
+		    }
+		}
+	    }
+	}
+    }
+    fclose(f);
+    return k;
+}
+
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language)
+{
+    return parse_keyboard_layout(table, language, NULL);
+}
+
+
+int keysym2scancode(void *kbd_layout, int keysym)
+{
+    kbd_layout_t *k = kbd_layout;
+    if (keysym < MAX_NORMAL_KEYCODE) {
+	if (k->keysym2keycode[keysym] == 0)
+	    fprintf(stderr, "Warning: no scancode found for keysym %d\n",
+		    keysym);
+	return k->keysym2keycode[keysym];
+    } else {
+	int i;
+#ifdef XK_ISO_Left_Tab
+	if (keysym == XK_ISO_Left_Tab)
+	    keysym = XK_Tab;
+#endif
+	for (i = 0; i < k->extra_count; i++)
+	    if (k->keysym2keycode_extra[i].keysym == keysym)
+		return k->keysym2keycode_extra[i].keycode;
+    }
+    return 0;
+}
+
+int keycode_is_keypad(void *kbd_layout, int keycode)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->keypad_range; kr; kr = kr->next)
+        if (keycode >= kr->start && keycode <= kr->end)
+            return 1;
+    return 0;
+}
+
+int keysym_is_numlock(void *kbd_layout, int keysym)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->numlock_range; kr; kr = kr->next)
+        if (keysym >= kr->start && keysym <= kr->end)
+            return 1;
+    return 0;
+}
diff --git a/qemu-0.15.x/ui/keymaps.h b/qemu-0.15.x/ui/keymaps.h
new file mode 100644
index 0000000..a7600d5
--- /dev/null
+++ b/qemu-0.15.x/ui/keymaps.h
@@ -0,0 +1,77 @@
+/*
+ * QEMU keysym to keycode conversion using rdesktop keymaps
+ *
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * 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 __QEMU_KEYMAPS_H__
+#define __QEMU_KEYMAPS_H__
+
+#include "qemu-common.h"
+
+typedef struct {
+	const char* name;
+	int keysym;
+} name2keysym_t;
+
+struct key_range {
+    int start;
+    int end;
+    struct key_range *next;
+};
+
+#define MAX_NORMAL_KEYCODE 512
+#define MAX_EXTRA_COUNT 256
+typedef struct {
+    uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+    struct {
+	int keysym;
+	uint16_t keycode;
+    } keysym2keycode_extra[MAX_EXTRA_COUNT];
+    int extra_count;
+    struct key_range *keypad_range;
+    struct key_range *numlock_range;
+} kbd_layout_t;
+
+/* scancode without modifiers */
+#define SCANCODE_KEYMASK 0xff
+/* scancode without grey or up bit */
+#define SCANCODE_KEYCODEMASK 0x7f
+
+/* "grey" keys will usually need a 0xe0 prefix */
+#define SCANCODE_GREY   0x80
+#define SCANCODE_EMUL0  0xE0
+/* "up" flag */
+#define SCANCODE_UP     0x80
+
+/* Additional modifiers to use if not catched another way. */
+#define SCANCODE_SHIFT  0x100
+#define SCANCODE_CTRL   0x200
+#define SCANCODE_ALT    0x400
+#define SCANCODE_ALTGR  0x800
+
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language);
+int keysym2scancode(void *kbd_layout, int keysym);
+int keycode_is_keypad(void *kbd_layout, int keycode);
+int keysym_is_numlock(void *kbd_layout, int keysym);
+
+#endif /* __QEMU_KEYMAPS_H__ */
diff --git a/qemu-0.15.x/ui/qemu-spice.h b/qemu-0.15.x/ui/qemu-spice.h
new file mode 100644
index 0000000..f34be69
--- /dev/null
+++ b/qemu-0.15.x/ui/qemu-spice.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SPICE_H
+#define QEMU_SPICE_H
+
+#ifdef CONFIG_SPICE
+
+#include <spice.h>
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "qemu-char.h"
+
+extern int using_spice;
+
+void qemu_spice_init(void);
+void qemu_spice_input_init(void);
+void qemu_spice_audio_init(void);
+void qemu_spice_display_init(DisplayState *ds);
+int qemu_spice_add_interface(SpiceBaseInstance *sin);
+int qemu_spice_set_passwd(const char *passwd,
+                          bool fail_if_connected, bool disconnect_if_connected);
+int qemu_spice_set_pw_expire(time_t expires);
+int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
+                            const char *subject);
+
+void do_info_spice_print(Monitor *mon, const QObject *data);
+void do_info_spice(Monitor *mon, QObject **ret_data);
+
+int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr);
+
+#else  /* CONFIG_SPICE */
+
+#define using_spice 0
+static inline int qemu_spice_set_passwd(const char *passwd,
+                                        bool fail_if_connected,
+                                        bool disconnect_if_connected)
+{
+    return -1;
+}
+static inline int qemu_spice_set_pw_expire(time_t expires)
+{
+    return -1;
+}
+static inline int qemu_spice_migrate_info(const char *h, int p, int t, const char *s)
+{ return -1; }
+
+#endif /* CONFIG_SPICE */
+
+#endif /* QEMU_SPICE_H */
diff --git a/qemu-0.15.x/ui/sdl.c b/qemu-0.15.x/ui/sdl.c
new file mode 100644
index 0000000..9efcda5
--- /dev/null
+++ b/qemu-0.15.x/ui/sdl.c
@@ -0,0 +1,904 @@
+/*
+ * QEMU SDL display 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.
+ */
+
+/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
+#undef WIN32_LEAN_AND_MEAN
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+#include "x_keymap.h"
+#include "sdl_zoom.h"
+
+static DisplayChangeListener *dcl;
+static SDL_Surface *real_screen;
+static SDL_Surface *guest_screen = NULL;
+static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
+static int last_vm_running;
+static int gui_saved_grab;
+static int gui_fullscreen;
+static int gui_noframe;
+static int gui_key_modifier_pressed;
+static int gui_keysym;
+static int gui_fullscreen_initial_grab;
+static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
+static uint8_t modifiers_state[256];
+static int width, height;
+static SDL_Cursor *sdl_cursor_normal;
+static SDL_Cursor *sdl_cursor_hidden;
+static int absolute_enabled = 0;
+static int guest_cursor = 0;
+static int guest_x, guest_y;
+static SDL_Cursor *guest_sprite = NULL;
+static uint8_t allocator;
+static SDL_PixelFormat host_format;
+static int scaling_active = 0;
+static Notifier mouse_mode_notifier;
+
+static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
+    SDL_Rect rec;
+    rec.x = x;
+    rec.y = y;
+    rec.w = w;
+    rec.h = h;
+
+    if (guest_screen) {
+        if (!scaling_active) {
+            SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
+        } else {
+            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
+                fprintf(stderr, "Zoom blit failed\n");
+                exit(1);
+            }
+        }
+    } 
+    SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
+}
+
+static void sdl_setdata(DisplayState *ds)
+{
+    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
+
+    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
+                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
+                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
+                                            ds->surface->pf.bmask, ds->surface->pf.amask);
+}
+
+static void do_sdl_resize(int new_width, int new_height, int bpp)
+{
+    int flags;
+
+    //    printf("resizing to %d %d\n", w, h);
+
+    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
+    if (gui_fullscreen)
+        flags |= SDL_FULLSCREEN;
+    if (gui_noframe)
+        flags |= SDL_NOFRAME;
+
+    width = new_width;
+    height = new_height;
+    real_screen = SDL_SetVideoMode(width, height, bpp, flags);
+    if (!real_screen) {
+	fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
+		height, bpp, SDL_GetError());
+        exit(1);
+    }
+}
+
+static void sdl_resize(DisplayState *ds)
+{
+    if  (!allocator) {
+        if (!scaling_active)
+            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
+            do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
+        sdl_setdata(ds);
+    } else {
+        if (guest_screen != NULL) {
+            SDL_FreeSurface(guest_screen);
+            guest_screen = NULL;
+        }
+    }
+}
+
+static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
+{
+    PixelFormat qemu_pf;
+
+    memset(&qemu_pf, 0x00, sizeof(PixelFormat));
+
+    qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
+    qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
+    qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
+
+    qemu_pf.rmask = sdl_pf->Rmask;
+    qemu_pf.gmask = sdl_pf->Gmask;
+    qemu_pf.bmask = sdl_pf->Bmask;
+    qemu_pf.amask = sdl_pf->Amask;
+
+    qemu_pf.rshift = sdl_pf->Rshift;
+    qemu_pf.gshift = sdl_pf->Gshift;
+    qemu_pf.bshift = sdl_pf->Bshift;
+    qemu_pf.ashift = sdl_pf->Ashift;
+
+    qemu_pf.rbits = 8 - sdl_pf->Rloss;
+    qemu_pf.gbits = 8 - sdl_pf->Gloss;
+    qemu_pf.bbits = 8 - sdl_pf->Bloss;
+    qemu_pf.abits = 8 - sdl_pf->Aloss;
+
+    qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
+    qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
+    qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
+    qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
+
+    return qemu_pf;
+}
+
+static DisplaySurface* sdl_create_displaysurface(int width, int height)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    if (surface == NULL) {
+        fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
+        exit(1);
+    }
+
+    surface->width = width;
+    surface->height = height;
+
+    if (scaling_active) {
+        int linesize;
+        PixelFormat pf;
+        if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
+            linesize = width * 4;
+            pf = qemu_default_pixelformat(32);
+        } else {
+            linesize = width * host_format.BytesPerPixel;
+            pf = sdl_to_qemu_pixelformat(&host_format);
+        }
+        qemu_alloc_display(surface, width, height, linesize, pf, 0);
+        return surface;
+    }
+
+    if (host_format.BitsPerPixel == 16)
+        do_sdl_resize(width, height, 16);
+    else
+        do_sdl_resize(width, height, 32);
+
+    surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
+    surface->linesize = real_screen->pitch;
+    surface->data = real_screen->pixels;
+
+#ifdef HOST_WORDS_BIGENDIAN
+    surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_REALPIXELS_FLAG;
+#endif
+    allocator = 1;
+
+    return surface;
+}
+
+static void sdl_free_displaysurface(DisplaySurface *surface)
+{
+    allocator = 0;
+    if (surface == NULL)
+        return;
+
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
+}
+
+static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
+{
+    sdl_free_displaysurface(surface);
+    return sdl_create_displaysurface(width, height);
+}
+
+/* generic keyboard conversion */
+
+#include "sdl_keysym.h"
+
+static kbd_layout_t *kbd_layout = NULL;
+
+static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
+{
+    int keysym;
+    /* workaround for X11+SDL bug with AltGR */
+    keysym = ev->keysym.sym;
+    if (keysym == 0 && ev->keysym.scancode == 113)
+        keysym = SDLK_MODE;
+    /* For Japanese key '\' and '|' */
+    if (keysym == 92 && ev->keysym.scancode == 133) {
+        keysym = 0xa5;
+    }
+    return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
+}
+
+/* specific keyboard conversions from scan codes */
+
+#if defined(_WIN32)
+
+static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
+{
+    return ev->keysym.scancode;
+}
+
+#else
+
+#if defined(SDL_VIDEO_DRIVER_X11)
+#include <X11/XKBlib.h>
+
+static int check_for_evdev(void)
+{
+    SDL_SysWMinfo info;
+    XkbDescPtr desc = NULL;
+    int has_evdev = 0;
+    char *keycodes = NULL;
+
+    SDL_VERSION(&info.version);
+    if (!SDL_GetWMInfo(&info)) {
+        return 0;
+    }
+    desc = XkbGetKeyboard(info.info.x11.display,
+                          XkbGBN_AllComponentsMask,
+                          XkbUseCoreKbd);
+    if (desc && desc->names) {
+        keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
+        if (keycodes == NULL) {
+            fprintf(stderr, "could not lookup keycode name\n");
+        } else if (strstart(keycodes, "evdev", NULL)) {
+            has_evdev = 1;
+        } else if (!strstart(keycodes, "xfree86", NULL)) {
+            fprintf(stderr, "unknown keycodes `%s', please report to "
+                    "qemu-devel at nongnu.org\n", keycodes);
+        }
+    }
+
+    if (desc) {
+        XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
+    }
+    if (keycodes) {
+        XFree(keycodes);
+    }
+    return has_evdev;
+}
+#else
+static int check_for_evdev(void)
+{
+	return 0;
+}
+#endif
+
+static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
+{
+    int keycode;
+    static int has_evdev = -1;
+
+    if (has_evdev == -1)
+        has_evdev = check_for_evdev();
+
+    keycode = ev->keysym.scancode;
+
+    if (keycode < 9) {
+        keycode = 0;
+    } else if (keycode < 97) {
+        keycode -= 8; /* just an offset */
+    } else if (keycode < 158) {
+        /* use conversion table */
+        if (has_evdev)
+            keycode = translate_evdev_keycode(keycode - 97);
+        else
+            keycode = translate_xfree86_keycode(keycode - 97);
+    } else if (keycode == 208) { /* Hiragana_Katakana */
+        keycode = 0x70;
+    } else if (keycode == 211) { /* backslash */
+        keycode = 0x73;
+    } else {
+        keycode = 0;
+    }
+    return keycode;
+}
+
+#endif
+
+static void reset_keys(void)
+{
+    int i;
+    for(i = 0; i < 256; i++) {
+        if (modifiers_state[i]) {
+            if (i & SCANCODE_GREY)
+                kbd_put_keycode(SCANCODE_EMUL0);
+            kbd_put_keycode(i | SCANCODE_UP);
+            modifiers_state[i] = 0;
+        }
+    }
+}
+
+static void sdl_process_key(SDL_KeyboardEvent *ev)
+{
+    int keycode, v;
+
+    if (ev->keysym.sym == SDLK_PAUSE) {
+        /* specific case */
+        v = 0;
+        if (ev->type == SDL_KEYUP)
+            v |= SCANCODE_UP;
+        kbd_put_keycode(0xe1);
+        kbd_put_keycode(0x1d | v);
+        kbd_put_keycode(0x45 | v);
+        return;
+    }
+
+    if (kbd_layout) {
+        keycode = sdl_keyevent_to_keycode_generic(ev);
+    } else {
+        keycode = sdl_keyevent_to_keycode(ev);
+    }
+
+    switch(keycode) {
+    case 0x00:
+        /* sent when leaving window: reset the modifiers state */
+        reset_keys();
+        return;
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                         /* Right ALT */
+        if (ev->type == SDL_KEYUP)
+            modifiers_state[keycode] = 0;
+        else
+            modifiers_state[keycode] = 1;
+        break;
+#define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION)
+#if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14
+        /* SDL versions before 1.2.14 don't support key up for caps/num lock. */
+    case 0x45: /* num lock */
+    case 0x3a: /* caps lock */
+        /* SDL does not send the key up event, so we generate it */
+        kbd_put_keycode(keycode);
+        kbd_put_keycode(keycode | SCANCODE_UP);
+        return;
+#endif
+    }
+
+    /* now send the key code */
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    if (ev->type == SDL_KEYUP)
+        kbd_put_keycode(keycode | SCANCODE_UP);
+    else
+        kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+}
+
+static void sdl_update_caption(void)
+{
+    char win_title[1024];
+    char icon_title[1024];
+    const char *status = "";
+
+    if (!vm_running)
+        status = " [Stopped]";
+    else if (gui_grab) {
+        if (alt_grab)
+            status = " - Press Ctrl-Alt-Shift to exit mouse grab";
+        else if (ctrl_grab)
+            status = " - Press Right-Ctrl to exit mouse grab";
+        else
+            status = " - Press Ctrl-Alt to exit mouse grab";
+    }
+
+    if (qemu_name) {
+        snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
+        snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
+    } else {
+        snprintf(win_title, sizeof(win_title), "QEMU%s", status);
+        snprintf(icon_title, sizeof(icon_title), "QEMU");
+    }
+
+    SDL_WM_SetCaption(win_title, icon_title);
+}
+
+static void sdl_hide_cursor(void)
+{
+    if (!cursor_hide)
+        return;
+
+    if (kbd_mouse_is_absolute()) {
+        SDL_ShowCursor(1);
+        SDL_SetCursor(sdl_cursor_hidden);
+    } else {
+        SDL_ShowCursor(0);
+    }
+}
+
+static void sdl_show_cursor(void)
+{
+    if (!cursor_hide)
+        return;
+
+    if (!kbd_mouse_is_absolute()) {
+        SDL_ShowCursor(1);
+        if (guest_cursor &&
+                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+            SDL_SetCursor(guest_sprite);
+        else
+            SDL_SetCursor(sdl_cursor_normal);
+    }
+}
+
+static void sdl_grab_start(void)
+{
+    if (guest_cursor) {
+        SDL_SetCursor(guest_sprite);
+        if (!kbd_mouse_is_absolute() && !absolute_enabled)
+            SDL_WarpMouse(guest_x, guest_y);
+    } else
+        sdl_hide_cursor();
+
+    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
+        gui_grab = 1;
+        sdl_update_caption();
+    } else
+        sdl_show_cursor();
+}
+
+static void sdl_grab_end(void)
+{
+    SDL_WM_GrabInput(SDL_GRAB_OFF);
+    gui_grab = 0;
+    sdl_show_cursor();
+    sdl_update_caption();
+}
+
+static void sdl_mouse_mode_change(Notifier *notify, void *data)
+{
+    if (kbd_mouse_is_absolute()) {
+        if (!absolute_enabled) {
+            sdl_hide_cursor();
+            if (gui_grab) {
+                sdl_grab_end();
+            }
+            absolute_enabled = 1;
+        }
+    } else if (absolute_enabled) {
+	sdl_show_cursor();
+	absolute_enabled = 0;
+    }
+}
+
+static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
+{
+    int buttons;
+    buttons = 0;
+    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
+        buttons |= MOUSE_EVENT_LBUTTON;
+    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
+        buttons |= MOUSE_EVENT_RBUTTON;
+    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
+        buttons |= MOUSE_EVENT_MBUTTON;
+
+    if (kbd_mouse_is_absolute()) {
+       dx = x * 0x7FFF / (width - 1);
+       dy = y * 0x7FFF / (height - 1);
+    } else if (guest_cursor) {
+        x -= guest_x;
+        y -= guest_y;
+        guest_x += x;
+        guest_y += y;
+        dx = x;
+        dy = y;
+    }
+
+    kbd_mouse_event(dx, dy, dz, buttons);
+}
+
+static void toggle_full_screen(DisplayState *ds)
+{
+    gui_fullscreen = !gui_fullscreen;
+    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
+    if (gui_fullscreen) {
+        scaling_active = 0;
+        gui_saved_grab = gui_grab;
+        sdl_grab_start();
+    } else {
+        if (!gui_saved_grab)
+            sdl_grab_end();
+    }
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void sdl_refresh(DisplayState *ds)
+{
+    SDL_Event ev1, *ev = &ev1;
+    int mod_state;
+    int buttonstate = SDL_GetMouseState(NULL, NULL);
+
+    if (last_vm_running != vm_running) {
+        last_vm_running = vm_running;
+        sdl_update_caption();
+    }
+
+    vga_hw_update();
+    SDL_EnableUNICODE(!is_graphic_console());
+
+    while (SDL_PollEvent(ev)) {
+        switch (ev->type) {
+        case SDL_VIDEOEXPOSE:
+            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
+            break;
+        case SDL_KEYDOWN:
+        case SDL_KEYUP:
+            if (ev->type == SDL_KEYDOWN) {
+                if (alt_grab) {
+                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+                                (gui_grab_code | KMOD_LSHIFT);
+                } else if (ctrl_grab) {
+                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
+                } else {
+                    mod_state = (SDL_GetModState() & gui_grab_code) ==
+                                gui_grab_code;
+                }
+                gui_key_modifier_pressed = mod_state;
+                if (gui_key_modifier_pressed) {
+                    int keycode;
+                    keycode = sdl_keyevent_to_keycode(&ev->key);
+                    switch(keycode) {
+                    case 0x21: /* 'f' key on US keyboard */
+                        toggle_full_screen(ds);
+                        gui_keysym = 1;
+                        break;
+                    case 0x16: /* 'u' key on US keyboard */
+                        scaling_active = 0;
+                        sdl_resize(ds);
+                        vga_hw_invalidate();
+                        vga_hw_update();
+                        break;
+                    case 0x02 ... 0x0a: /* '1' to '9' keys */
+                        /* Reset the modifiers sent to the current console */
+                        reset_keys();
+                        console_select(keycode - 0x02);
+                        if (!is_graphic_console()) {
+                            /* display grab if going to a text console */
+                            if (gui_grab)
+                                sdl_grab_end();
+                        }
+                        gui_keysym = 1;
+                        break;
+                    default:
+                        break;
+                    }
+                } else if (!is_graphic_console()) {
+                    int keysym;
+                    keysym = 0;
+                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+                        switch(ev->key.keysym.sym) {
+                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
+                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
+                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
+                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
+                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
+                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
+                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
+                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
+                        default: break;
+                        }
+                    } else {
+                        switch(ev->key.keysym.sym) {
+                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
+                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
+                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
+                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
+                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
+                        case SDLK_END: keysym = QEMU_KEY_END; break;
+                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
+                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
+                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
+                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
+                        default: break;
+                        }
+                    }
+                    if (keysym) {
+                        kbd_put_keysym(keysym);
+                    } else if (ev->key.keysym.unicode != 0) {
+                        kbd_put_keysym(ev->key.keysym.unicode);
+                    }
+                }
+            } else if (ev->type == SDL_KEYUP) {
+                if (!alt_grab) {
+                    mod_state = (ev->key.keysym.mod & gui_grab_code);
+                } else {
+                    mod_state = (ev->key.keysym.mod &
+                                 (gui_grab_code | KMOD_LSHIFT));
+                }
+                if (!mod_state) {
+                    if (gui_key_modifier_pressed) {
+                        gui_key_modifier_pressed = 0;
+                        if (gui_keysym == 0) {
+                            /* exit/enter grab if pressing Ctrl-Alt */
+                            if (!gui_grab) {
+                                /* if the application is not active,
+                                   do not try to enter grab state. It
+                                   prevents
+                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
+                                   from blocking all the application
+                                   (SDL bug). */
+                                if (SDL_GetAppState() & SDL_APPACTIVE)
+                                    sdl_grab_start();
+                            } else {
+                                sdl_grab_end();
+                            }
+                            /* SDL does not send back all the
+                               modifiers key, so we must correct it */
+                            reset_keys();
+                            break;
+                        }
+                        gui_keysym = 0;
+                    }
+                }
+            }
+            if (is_graphic_console() && !gui_keysym)
+                sdl_process_key(&ev->key);
+            break;
+        case SDL_QUIT:
+            if (!no_quit) {
+                no_shutdown = 0;
+                qemu_system_shutdown_request();
+            }
+            break;
+        case SDL_MOUSEMOTION:
+            if (gui_grab || kbd_mouse_is_absolute() ||
+                absolute_enabled) {
+                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
+                       ev->motion.x, ev->motion.y, ev->motion.state);
+            }
+            break;
+        case SDL_MOUSEBUTTONDOWN:
+        case SDL_MOUSEBUTTONUP:
+            {
+                SDL_MouseButtonEvent *bev = &ev->button;
+                if (!gui_grab && !kbd_mouse_is_absolute()) {
+                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
+                        (bev->button == SDL_BUTTON_LEFT)) {
+                        /* start grabbing all events */
+                        sdl_grab_start();
+                    }
+                } else {
+                    int dz;
+                    dz = 0;
+                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
+                        buttonstate |= SDL_BUTTON(bev->button);
+                    } else {
+                        buttonstate &= ~SDL_BUTTON(bev->button);
+                    }
+#ifdef SDL_BUTTON_WHEELUP
+                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
+                        dz = -1;
+                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
+                        dz = 1;
+                    }
+#endif
+                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
+                }
+            }
+            break;
+        case SDL_ACTIVEEVENT:
+            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
+                !ev->active.gain && !gui_fullscreen_initial_grab) {
+                sdl_grab_end();
+            }
+            if (ev->active.state & SDL_APPACTIVE) {
+                if (ev->active.gain) {
+                    /* Back to default interval */
+                    dcl->gui_timer_interval = 0;
+                    dcl->idle = 0;
+                } else {
+                    /* Sleeping interval */
+                    dcl->gui_timer_interval = 500;
+                    dcl->idle = 1;
+                }
+            }
+            break;
+	case SDL_VIDEORESIZE:
+        {
+	    SDL_ResizeEvent *rev = &ev->resize;
+            int bpp = real_screen->format->BitsPerPixel;
+            if (bpp != 16 && bpp != 32)
+                bpp = 32;
+            do_sdl_resize(rev->w, rev->h, bpp);
+            scaling_active = 1;
+            if (!is_buffer_shared(ds->surface)) {
+                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
+                dpy_resize(ds);
+            }
+            vga_hw_invalidate();
+            vga_hw_update();
+            break;
+        }
+        default:
+            break;
+        }
+    }
+}
+
+static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
+{
+    SDL_Rect dst = { x, y, w, h };
+    SDL_FillRect(real_screen, &dst, c);
+}
+
+static void sdl_mouse_warp(int x, int y, int on)
+{
+    if (on) {
+        if (!guest_cursor)
+            sdl_show_cursor();
+        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+            SDL_SetCursor(guest_sprite);
+            if (!kbd_mouse_is_absolute() && !absolute_enabled)
+                SDL_WarpMouse(x, y);
+        }
+    } else if (gui_grab)
+        sdl_hide_cursor();
+    guest_cursor = on;
+    guest_x = x, guest_y = y;
+}
+
+static void sdl_mouse_define(QEMUCursor *c)
+{
+    uint8_t *image, *mask;
+    int bpl;
+
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
+
+    bpl = cursor_get_mono_bpl(c);
+    image = qemu_mallocz(bpl * c->height);
+    mask  = qemu_mallocz(bpl * c->height);
+    cursor_get_mono_image(c, 0x000000, image);
+    cursor_get_mono_mask(c, 0, mask);
+    guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
+                                    c->hot_x, c->hot_y);
+    qemu_free(image);
+    qemu_free(mask);
+
+    if (guest_cursor &&
+            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+        SDL_SetCursor(guest_sprite);
+}
+
+static void sdl_cleanup(void)
+{
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
+    SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
+{
+    int flags;
+    uint8_t data = 0;
+    DisplayAllocator *da;
+    const SDL_VideoInfo *vi;
+    char *filename;
+
+#if defined(__APPLE__)
+    /* always use generic keymaps */
+    if (!keyboard_layout)
+        keyboard_layout = "en-us";
+#endif
+    if(keyboard_layout) {
+        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+        if (!kbd_layout)
+            exit(1);
+    }
+
+    if (no_frame)
+        gui_noframe = 1;
+
+    if (!full_screen) {
+        setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
+    }
+#ifdef __linux__
+    /* on Linux, SDL may use fbcon|directfb|svgalib when run without
+     * accessible $DISPLAY to open X11 window.  This is often the case
+     * when qemu is run using sudo.  But in this case, and when actually
+     * run in X11 environment, SDL fights with X11 for the video card,
+     * making current display unavailable, often until reboot.
+     * So make x11 the default SDL video driver if this variable is unset.
+     * This is a bit hackish but saves us from bigger problem.
+     * Maybe it's a good idea to fix this in SDL instead.
+     */
+    setenv("SDL_VIDEODRIVER", "x11", 0);
+#endif
+
+    /* Enable normal up/down events for Caps-Lock and Num-Lock keys.
+     * This requires SDL >= 1.2.14. */
+    setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
+
+    flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
+    if (SDL_Init (flags)) {
+        fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
+                SDL_GetError());
+        exit(1);
+    }
+    vi = SDL_GetVideoInfo();
+    host_format = *(vi->vfmt);
+
+    /* Load a 32x32x4 image. White pixels are transparent. */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
+    if (filename) {
+        SDL_Surface *image = SDL_LoadBMP(filename);
+        if (image) {
+            uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
+            SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
+            SDL_WM_SetIcon(image, NULL);
+        }
+        qemu_free(filename);
+    }
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = sdl_update;
+    dcl->dpy_resize = sdl_resize;
+    dcl->dpy_refresh = sdl_refresh;
+    dcl->dpy_setdata = sdl_setdata;
+    dcl->dpy_fill = sdl_fill;
+    ds->mouse_set = sdl_mouse_warp;
+    ds->cursor_define = sdl_mouse_define;
+    register_displaychangelistener(ds, dcl);
+
+    da = qemu_mallocz(sizeof(DisplayAllocator));
+    da->create_displaysurface = sdl_create_displaysurface;
+    da->resize_displaysurface = sdl_resize_displaysurface;
+    da->free_displaysurface = sdl_free_displaysurface;
+    if (register_displayallocator(ds, da) == da) {
+        dpy_resize(ds);
+    }
+
+    mouse_mode_notifier.notify = sdl_mouse_mode_change;
+    qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
+
+    sdl_update_caption();
+    SDL_EnableKeyRepeat(250, 50);
+    gui_grab = 0;
+
+    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
+    sdl_cursor_normal = SDL_GetCursor();
+
+    atexit(sdl_cleanup);
+    if (full_screen) {
+        gui_fullscreen = 1;
+        gui_fullscreen_initial_grab = 1;
+        sdl_grab_start();
+    }
+}
diff --git a/qemu-0.15.x/ui/sdl_keysym.h b/qemu-0.15.x/ui/sdl_keysym.h
new file mode 100644
index 0000000..ee90480
--- /dev/null
+++ b/qemu-0.15.x/ui/sdl_keysym.h
@@ -0,0 +1,277 @@
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                0x020},
+    { "exclam",               0x021},
+    { "quotedbl",             0x022},
+    { "numbersign",           0x023},
+    { "dollar",               0x024},
+    { "percent",              0x025},
+    { "ampersand",            0x026},
+    { "apostrophe",           0x027},
+    { "parenleft",            0x028},
+    { "parenright",           0x029},
+    { "asterisk",             0x02a},
+    { "plus",                 0x02b},
+    { "comma",                0x02c},
+    { "minus",                0x02d},
+    { "period",               0x02e},
+    { "slash",                0x02f},
+    { "0",                    0x030},
+    { "1",                    0x031},
+    { "2",                    0x032},
+    { "3",                    0x033},
+    { "4",                    0x034},
+    { "5",                    0x035},
+    { "6",                    0x036},
+    { "7",                    0x037},
+    { "8",                    0x038},
+    { "9",                    0x039},
+    { "colon",                0x03a},
+    { "semicolon",            0x03b},
+    { "less",                 0x03c},
+    { "equal",                0x03d},
+    { "greater",              0x03e},
+    { "question",             0x03f},
+    { "at",                   0x040},
+    { "A",                    0x041},
+    { "B",                    0x042},
+    { "C",                    0x043},
+    { "D",                    0x044},
+    { "E",                    0x045},
+    { "F",                    0x046},
+    { "G",                    0x047},
+    { "H",                    0x048},
+    { "I",                    0x049},
+    { "J",                    0x04a},
+    { "K",                    0x04b},
+    { "L",                    0x04c},
+    { "M",                    0x04d},
+    { "N",                    0x04e},
+    { "O",                    0x04f},
+    { "P",                    0x050},
+    { "Q",                    0x051},
+    { "R",                    0x052},
+    { "S",                    0x053},
+    { "T",                    0x054},
+    { "U",                    0x055},
+    { "V",                    0x056},
+    { "W",                    0x057},
+    { "X",                    0x058},
+    { "Y",                    0x059},
+    { "Z",                    0x05a},
+    { "bracketleft",          0x05b},
+    { "backslash",            0x05c},
+    { "bracketright",         0x05d},
+    { "asciicircum",          0x05e},
+    { "underscore",           0x05f},
+    { "grave",                0x060},
+    { "a",                    0x061},
+    { "b",                    0x062},
+    { "c",                    0x063},
+    { "d",                    0x064},
+    { "e",                    0x065},
+    { "f",                    0x066},
+    { "g",                    0x067},
+    { "h",                    0x068},
+    { "i",                    0x069},
+    { "j",                    0x06a},
+    { "k",                    0x06b},
+    { "l",                    0x06c},
+    { "m",                    0x06d},
+    { "n",                    0x06e},
+    { "o",                    0x06f},
+    { "p",                    0x070},
+    { "q",                    0x071},
+    { "r",                    0x072},
+    { "s",                    0x073},
+    { "t",                    0x074},
+    { "u",                    0x075},
+    { "v",                    0x076},
+    { "w",                    0x077},
+    { "x",                    0x078},
+    { "y",                    0x079},
+    { "z",                    0x07a},
+    { "braceleft",            0x07b},
+    { "bar",                  0x07c},
+    { "braceright",           0x07d},
+    { "asciitilde",           0x07e},
+
+/* latin 1 extensions */
+{ "nobreakspace",         0x0a0},
+{ "exclamdown",           0x0a1},
+{ "cent",         	  0x0a2},
+{ "sterling",             0x0a3},
+{ "currency",             0x0a4},
+{ "yen",                  0x0a5},
+{ "brokenbar",            0x0a6},
+{ "section",              0x0a7},
+{ "diaeresis",            0x0a8},
+{ "copyright",            0x0a9},
+{ "ordfeminine",          0x0aa},
+{ "guillemotleft",        0x0ab},
+{ "notsign",              0x0ac},
+{ "hyphen",               0x0ad},
+{ "registered",           0x0ae},
+{ "macron",               0x0af},
+{ "degree",               0x0b0},
+{ "plusminus",            0x0b1},
+{ "twosuperior",          0x0b2},
+{ "threesuperior",        0x0b3},
+{ "acute",                0x0b4},
+{ "mu",                   0x0b5},
+{ "paragraph",            0x0b6},
+{ "periodcentered",       0x0b7},
+{ "cedilla",              0x0b8},
+{ "onesuperior",          0x0b9},
+{ "masculine",            0x0ba},
+{ "guillemotright",       0x0bb},
+{ "onequarter",           0x0bc},
+{ "onehalf",              0x0bd},
+{ "threequarters",        0x0be},
+{ "questiondown",         0x0bf},
+{ "Agrave",               0x0c0},
+{ "Aacute",               0x0c1},
+{ "Acircumflex",          0x0c2},
+{ "Atilde",               0x0c3},
+{ "Adiaeresis",           0x0c4},
+{ "Aring",                0x0c5},
+{ "AE",                   0x0c6},
+{ "Ccedilla",             0x0c7},
+{ "Egrave",               0x0c8},
+{ "Eacute",               0x0c9},
+{ "Ecircumflex",          0x0ca},
+{ "Ediaeresis",           0x0cb},
+{ "Igrave",               0x0cc},
+{ "Iacute",               0x0cd},
+{ "Icircumflex",          0x0ce},
+{ "Idiaeresis",           0x0cf},
+{ "ETH",                  0x0d0},
+{ "Eth",                  0x0d0},
+{ "Ntilde",               0x0d1},
+{ "Ograve",               0x0d2},
+{ "Oacute",               0x0d3},
+{ "Ocircumflex",          0x0d4},
+{ "Otilde",               0x0d5},
+{ "Odiaeresis",           0x0d6},
+{ "multiply",             0x0d7},
+{ "Ooblique",             0x0d8},
+{ "Oslash",               0x0d8},
+{ "Ugrave",               0x0d9},
+{ "Uacute",               0x0da},
+{ "Ucircumflex",          0x0db},
+{ "Udiaeresis",           0x0dc},
+{ "Yacute",               0x0dd},
+{ "THORN",                0x0de},
+{ "Thorn",                0x0de},
+{ "ssharp",               0x0df},
+{ "agrave",               0x0e0},
+{ "aacute",               0x0e1},
+{ "acircumflex",          0x0e2},
+{ "atilde",               0x0e3},
+{ "adiaeresis",           0x0e4},
+{ "aring",                0x0e5},
+{ "ae",                   0x0e6},
+{ "ccedilla",             0x0e7},
+{ "egrave",               0x0e8},
+{ "eacute",               0x0e9},
+{ "ecircumflex",          0x0ea},
+{ "ediaeresis",           0x0eb},
+{ "igrave",               0x0ec},
+{ "iacute",               0x0ed},
+{ "icircumflex",          0x0ee},
+{ "idiaeresis",           0x0ef},
+{ "eth",                  0x0f0},
+{ "ntilde",               0x0f1},
+{ "ograve",               0x0f2},
+{ "oacute",               0x0f3},
+{ "ocircumflex",          0x0f4},
+{ "otilde",               0x0f5},
+{ "odiaeresis",           0x0f6},
+{ "division",             0x0f7},
+{ "oslash",               0x0f8},
+{ "ooblique",             0x0f8},
+{ "ugrave",               0x0f9},
+{ "uacute",               0x0fa},
+{ "ucircumflex",          0x0fb},
+{ "udiaeresis",           0x0fc},
+{ "yacute",               0x0fd},
+{ "thorn",                0x0fe},
+{ "ydiaeresis",           0x0ff},
+{"EuroSign", SDLK_EURO},
+
+    /* modifiers */
+{"Control_L", SDLK_LCTRL},
+{"Control_R", SDLK_RCTRL},
+{"Alt_L", SDLK_LALT},
+{"Alt_R", SDLK_RALT},
+{"Caps_Lock", SDLK_CAPSLOCK},
+{"Meta_L", SDLK_LMETA},
+{"Meta_R", SDLK_RMETA},
+{"Shift_L", SDLK_LSHIFT},
+{"Shift_R", SDLK_RSHIFT},
+{"Super_L", SDLK_LSUPER},
+{"Super_R", SDLK_RSUPER},
+
+    /* special keys */
+{"BackSpace", SDLK_BACKSPACE},
+{"Tab", SDLK_TAB},
+{"Return", SDLK_RETURN},
+{"Right", SDLK_RIGHT},
+{"Left", SDLK_LEFT},
+{"Up", SDLK_UP},
+{"Down", SDLK_DOWN},
+{"Page_Down", SDLK_PAGEDOWN},
+{"Page_Up", SDLK_PAGEUP},
+{"Insert", SDLK_INSERT},
+{"Delete", SDLK_DELETE},
+{"Home", SDLK_HOME},
+{"End", SDLK_END},
+{"Scroll_Lock", SDLK_SCROLLOCK},
+{"F1", SDLK_F1},
+{"F2", SDLK_F2},
+{"F3", SDLK_F3},
+{"F4", SDLK_F4},
+{"F5", SDLK_F5},
+{"F6", SDLK_F6},
+{"F7", SDLK_F7},
+{"F8", SDLK_F8},
+{"F9", SDLK_F9},
+{"F10", SDLK_F10},
+{"F11", SDLK_F11},
+{"F12", SDLK_F12},
+{"F13", SDLK_F13},
+{"F14", SDLK_F14},
+{"F15", SDLK_F15},
+{"Sys_Req", SDLK_SYSREQ},
+{"KP_0", SDLK_KP0},
+{"KP_1", SDLK_KP1},
+{"KP_2", SDLK_KP2},
+{"KP_3", SDLK_KP3},
+{"KP_4", SDLK_KP4},
+{"KP_5", SDLK_KP5},
+{"KP_6", SDLK_KP6},
+{"KP_7", SDLK_KP7},
+{"KP_8", SDLK_KP8},
+{"KP_9", SDLK_KP9},
+{"KP_Add", SDLK_KP_PLUS},
+{"KP_Decimal", SDLK_KP_PERIOD},
+{"KP_Divide", SDLK_KP_DIVIDE},
+{"KP_Enter", SDLK_KP_ENTER},
+{"KP_Equal", SDLK_KP_EQUALS},
+{"KP_Multiply", SDLK_KP_MULTIPLY},
+{"KP_Subtract", SDLK_KP_MINUS},
+{"help", SDLK_HELP},
+{"Menu", SDLK_MENU},
+{"Power", SDLK_POWER},
+{"Print", SDLK_PRINT},
+{"Mode_switch", SDLK_MODE},
+{"Multi_Key", SDLK_COMPOSE},
+{"Num_Lock", SDLK_NUMLOCK},
+{"Pause", SDLK_PAUSE},
+{"Escape", SDLK_ESCAPE},
+
+{NULL, 0},
+};
diff --git a/qemu-0.15.x/ui/sdl_zoom.c b/qemu-0.15.x/ui/sdl_zoom.c
new file mode 100644
index 0000000..a986c7c
--- /dev/null
+++ b/qemu-0.15.x/ui/sdl_zoom.c
@@ -0,0 +1,95 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sdl_zoom.h"
+#include "osdep.h"
+#include <stdint.h>
+#include <stdio.h>
+
+static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                          SDL_Rect *dst_rect);
+
+#define BPP 32
+#include  "sdl_zoom_template.h"
+#undef BPP
+#define BPP 16
+#include  "sdl_zoom_template.h"
+#undef BPP
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth,
+                  SDL_Rect *in_rect)
+{
+    SDL_Rect zoom, src_rect;
+    int extra;
+
+    /* Grow the size of the modified rectangle to avoid edge artefacts */
+    src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0;
+    src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0;
+
+    src_rect.w = in_rect->w + 1;
+    if (src_rect.x + src_rect.w > src_sfc->w)
+        src_rect.w = src_sfc->w - src_rect.x;
+
+    src_rect.h = in_rect->h + 1;
+    if (src_rect.y + src_rect.h > src_sfc->h)
+        src_rect.h = src_sfc->h - src_rect.y;
+
+    /* (x,y) : round down */
+    zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w));
+    zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h));
+
+    /* (w,h) : round up */
+    zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) /
+                     (double)(src_sfc->w));
+
+    zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) /
+                     (double)(src_sfc->h));
+
+    /* Account for any (x,y) rounding by adding one-source-pixel's worth
+     * of destination pixels and then edge checking.
+     */
+
+    extra = ((dst_sfc->w-1) / src_sfc->w) + 1;
+
+    if ((zoom.x + zoom.w) < (dst_sfc->w - extra))
+        zoom.w += extra;
+    else
+        zoom.w = dst_sfc->w - zoom.x;
+
+    extra = ((dst_sfc->h-1) / src_sfc->h) + 1;
+
+    if ((zoom.y + zoom.h) < (dst_sfc->h - extra))
+        zoom.h += extra;
+    else
+        zoom.h = dst_sfc->h - zoom.y;
+
+    /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the
+     * destination surface that needs to be updated.
+     */
+    if (src_sfc->format->BitsPerPixel == 32)
+        sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom);
+    else if (src_sfc->format->BitsPerPixel == 16)
+        sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom);
+    else {
+        fprintf(stderr, "pixel format not supported\n");
+        return -1;
+    }
+
+    /* Return the rectangle of the update to the caller */
+    *in_rect = zoom;
+
+    return 0;
+}
+
diff --git a/qemu-0.15.x/ui/sdl_zoom.h b/qemu-0.15.x/ui/sdl_zoom.h
new file mode 100644
index 0000000..74955bc
--- /dev/null
+++ b/qemu-0.15.x/ui/sdl_zoom.h
@@ -0,0 +1,25 @@
+/*
+ * SDL_zoom - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef SDL_zoom_h
+#define SDL_zoom_h
+
+#include <SDL.h>
+
+#define SMOOTHING_OFF		0
+#define SMOOTHING_ON		1
+
+int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc,
+                  int smooth, SDL_Rect *src_rect);
+
+#endif /* SDL_zoom_h */
diff --git a/qemu-0.15.x/ui/sdl_zoom_template.h b/qemu-0.15.x/ui/sdl_zoom_template.h
new file mode 100644
index 0000000..64bbca8
--- /dev/null
+++ b/qemu-0.15.x/ui/sdl_zoom_template.h
@@ -0,0 +1,225 @@
+/*
+ * SDL_zoom_template - surface scaling
+ * 
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+ * Derived from: SDL_rotozoom,  LGPL (c) A. Schiffler from the SDL_gfx library.
+ * Modifications by Stefano Stabellini.
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#if BPP == 16
+#define SDL_TYPE Uint16
+#elif BPP == 32
+#define SDL_TYPE Uint32
+#else
+#error unsupport depth
+#endif
+
+/*  
+ *  Simple helper functions to make the code looks nicer
+ *
+ *  Assume spf = source SDL_PixelFormat
+ *         dpf = dest SDL_PixelFormat
+ *
+ */
+#define getRed(color)   (((color) & spf->Rmask) >> spf->Rshift)
+#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift)
+#define getBlue(color)  (((color) & spf->Bmask) >> spf->Bshift)
+#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift)
+
+#define setRed(r, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \
+              (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \
+} while (0);
+
+#define setGreen(g, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \
+              (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \
+} while (0);
+
+#define setBlue(b, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \
+              (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \
+} while (0);
+
+#define setAlpha(a, pcolor) do { \
+    *pcolor = ((*pcolor) & (~(dpf->Amask))) + \
+              (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \
+} while (0);
+
+static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth,
+                                   SDL_Rect *dst_rect)
+{
+    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump;
+    SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp;
+    int d_gap;
+    SDL_PixelFormat *spf = src->format;
+    SDL_PixelFormat *dpf = dst->format;
+
+    if (smooth) { 
+        /* For interpolation: assume source dimension is one pixel.
+         * Smaller here to avoid overflow on right and bottom edge.
+         */
+        sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+        sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+    } else {
+        sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+        sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+    }
+
+    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+        return (-1);
+    }
+    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+        free(sax);
+        return (-1);
+    }
+
+    sp = csp = (SDL_TYPE *) src->pixels;
+    dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch +
+                       dst_rect->x * dst->format->BytesPerPixel);
+
+    csx = 0;
+    csax = sax;
+    for (x = 0; x <= dst->w; x++) {
+        *csax = csx;
+        csax++;
+        csx &= 0xffff;
+        csx += sx;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y <= dst->h; y++) {
+        *csay = csy;
+        csay++;
+        csy &= 0xffff;
+        csy += sy;
+    }
+
+    d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel;
+
+    if (smooth) {
+        csay = say;
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0; y < dst_rect->h ; y++) {
+            /* Setup colour source pointers */
+            c00 = csp + sstep_jump;
+            c01 = c00 + 1;
+            c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump;
+            c11 = c10 + 1;
+            csax = sax + dst_rect->x; 
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Interpolate colours */
+                ex = (*csax & 0xffff);
+                ey = (*csay & 0xffff);
+                t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) +
+                     getRed(*c00)) & (dpf->Rmask >> dpf->Rshift);
+                t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) +
+                     getRed(*c10)) & (dpf->Rmask >> dpf->Rshift);
+                setRed((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) +
+                     getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift);
+                t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) +
+                     getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift);
+                setGreen((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) +
+                     getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift);
+                t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) +
+                     getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift);
+                setBlue((((t2 - t1) * ey) >> 16) + t1, dp);
+                t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) +
+                     getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift);
+                t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) +
+                     getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift);
+                setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); 
+
+                /* Advance source pointers */
+                csax++; 
+                sstep = (*csax >> 16);
+                c00 += sstep;
+                c01 += sstep;
+                c10 += sstep;
+                c11 += sstep;
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointer */
+            csay++;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+            /* Advance destination pointers */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+
+
+    } else {
+        csay = say;
+
+        for (y = 0; y < dst_rect->y; y++) {
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+        }
+
+        /* Calculate sstep_jump */
+        csax = sax; 
+        sstep_jump = 0;
+        for (x = 0; x < dst_rect->x; x++) {
+            csax++; 
+            sstep = (*csax >> 16);
+            sstep_jump += sstep;
+        }
+
+        for (y = 0 ; y < dst_rect->h ; y++) {
+            sp = csp + sstep_jump;
+            csax = sax + dst_rect->x;
+
+            for (x = 0; x < dst_rect->w; x++) {
+
+                /* Draw */
+                *dp = *sp;
+
+                /* Advance source pointers */
+                csax++;
+                sstep = (*csax >> 16);
+                sp += sstep;
+
+                /* Advance destination pointer */
+                dp++;
+            }
+            /* Advance source pointers */
+            csay++;
+            sstep = (*csay >> 16) * src->pitch;
+            csp = (SDL_TYPE *) ((Uint8 *) csp + sstep);
+
+            /* Advance destination pointer */
+            dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap);
+        }
+    }
+
+    free(sax);
+    free(say);
+    return (0);
+}
+
+#undef SDL_TYPE
+
diff --git a/qemu-0.15.x/ui/spice-core.c b/qemu-0.15.x/ui/spice-core.c
new file mode 100644
index 0000000..3d77c01
--- /dev/null
+++ b/qemu-0.15.x/ui/spice-core.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include <netdb.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "qemu-x509.h"
+#include "qemu_socket.h"
+#include "qint.h"
+#include "qbool.h"
+#include "qstring.h"
+#include "qjson.h"
+#include "notify.h"
+#include "migration.h"
+#include "monitor.h"
+#include "hw/hw.h"
+
+/* core bits */
+
+static SpiceServer *spice_server;
+static Notifier migration_state;
+static const char *auth = "spice";
+static char *auth_passwd;
+static time_t auth_expires = TIME_MAX;
+int using_spice = 0;
+
+struct SpiceTimer {
+    QEMUTimer *timer;
+    QTAILQ_ENTRY(SpiceTimer) next;
+};
+static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
+
+static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
+{
+    SpiceTimer *timer;
+
+    timer = qemu_mallocz(sizeof(*timer));
+    timer->timer = qemu_new_timer_ms(rt_clock, func, opaque);
+    QTAILQ_INSERT_TAIL(&timers, timer, next);
+    return timer;
+}
+
+static void timer_start(SpiceTimer *timer, uint32_t ms)
+{
+    qemu_mod_timer(timer->timer, qemu_get_clock_ms(rt_clock) + ms);
+}
+
+static void timer_cancel(SpiceTimer *timer)
+{
+    qemu_del_timer(timer->timer);
+}
+
+static void timer_remove(SpiceTimer *timer)
+{
+    qemu_del_timer(timer->timer);
+    qemu_free_timer(timer->timer);
+    QTAILQ_REMOVE(&timers, timer, next);
+    qemu_free(timer);
+}
+
+struct SpiceWatch {
+    int fd;
+    int event_mask;
+    SpiceWatchFunc func;
+    void *opaque;
+    QTAILQ_ENTRY(SpiceWatch) next;
+};
+static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
+
+static void watch_read(void *opaque)
+{
+    SpiceWatch *watch = opaque;
+    watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
+}
+
+static void watch_write(void *opaque)
+{
+    SpiceWatch *watch = opaque;
+    watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
+}
+
+static void watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+    IOHandler *on_read = NULL;
+    IOHandler *on_write = NULL;
+
+    watch->event_mask = event_mask;
+    if (watch->event_mask & SPICE_WATCH_EVENT_READ) {
+        on_read = watch_read;
+    }
+    if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
+        on_write = watch_write;
+    }
+    qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+}
+
+static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+    SpiceWatch *watch;
+
+    watch = qemu_mallocz(sizeof(*watch));
+    watch->fd     = fd;
+    watch->func   = func;
+    watch->opaque = opaque;
+    QTAILQ_INSERT_TAIL(&watches, watch, next);
+
+    watch_update_mask(watch, event_mask);
+    return watch;
+}
+
+static void watch_remove(SpiceWatch *watch)
+{
+    watch_update_mask(watch, 0);
+    QTAILQ_REMOVE(&watches, watch, next);
+    qemu_free(watch);
+}
+
+#if SPICE_INTERFACE_CORE_MINOR >= 3
+
+typedef struct ChannelList ChannelList;
+struct ChannelList {
+    SpiceChannelEventInfo *info;
+    QTAILQ_ENTRY(ChannelList) link;
+};
+static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list);
+
+static void channel_list_add(SpiceChannelEventInfo *info)
+{
+    ChannelList *item;
+
+    item = qemu_mallocz(sizeof(*item));
+    item->info = info;
+    QTAILQ_INSERT_TAIL(&channel_list, item, link);
+}
+
+static void channel_list_del(SpiceChannelEventInfo *info)
+{
+    ChannelList *item;
+
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        if (item->info != info) {
+            continue;
+        }
+        QTAILQ_REMOVE(&channel_list, item, link);
+        qemu_free(item);
+        return;
+    }
+}
+
+static void add_addr_info(QDict *dict, struct sockaddr *addr, int len)
+{
+    char host[NI_MAXHOST], port[NI_MAXSERV];
+    const char *family;
+
+    getnameinfo(addr, len, host, sizeof(host), port, sizeof(port),
+                NI_NUMERICHOST | NI_NUMERICSERV);
+    family = inet_strfamily(addr->sa_family);
+
+    qdict_put(dict, "host", qstring_from_str(host));
+    qdict_put(dict, "port", qstring_from_str(port));
+    qdict_put(dict, "family", qstring_from_str(family));
+}
+
+static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
+{
+    int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+
+    qdict_put(dict, "connection-id", qint_from_int(info->connection_id));
+    qdict_put(dict, "channel-type", qint_from_int(info->type));
+    qdict_put(dict, "channel-id", qint_from_int(info->id));
+    qdict_put(dict, "tls", qbool_from_int(tls));
+}
+
+static QList *channel_list_get(void)
+{
+    ChannelList *item;
+    QList *list;
+    QDict *dict;
+
+    list = qlist_new();
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        dict = qdict_new();
+        add_addr_info(dict, &item->info->paddr, item->info->plen);
+        add_channel_info(dict, item->info);
+        qlist_append(list, dict);
+    }
+    return list;
+}
+
+static void channel_event(int event, SpiceChannelEventInfo *info)
+{
+    static const int qevent[] = {
+        [ SPICE_CHANNEL_EVENT_CONNECTED    ] = QEVENT_SPICE_CONNECTED,
+        [ SPICE_CHANNEL_EVENT_INITIALIZED  ] = QEVENT_SPICE_INITIALIZED,
+        [ SPICE_CHANNEL_EVENT_DISCONNECTED ] = QEVENT_SPICE_DISCONNECTED,
+    };
+    QDict *server, *client;
+    QObject *data;
+
+    client = qdict_new();
+    add_addr_info(client, &info->paddr, info->plen);
+
+    server = qdict_new();
+    add_addr_info(server, &info->laddr, info->llen);
+
+    if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
+        qdict_put(server, "auth", qstring_from_str(auth));
+        add_channel_info(client, info);
+        channel_list_add(info);
+    }
+    if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) {
+        channel_list_del(info);
+    }
+
+    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
+                              QOBJECT(client), QOBJECT(server));
+    monitor_protocol_event(qevent[event], data);
+    qobject_decref(data);
+}
+
+#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */
+
+static QList *channel_list_get(void)
+{
+    return NULL;
+}
+
+#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */
+
+static SpiceCoreInterface core_interface = {
+    .base.type          = SPICE_INTERFACE_CORE,
+    .base.description   = "qemu core services",
+    .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
+
+    .timer_add          = timer_add,
+    .timer_start        = timer_start,
+    .timer_cancel       = timer_cancel,
+    .timer_remove       = timer_remove,
+
+    .watch_add          = watch_add,
+    .watch_update_mask  = watch_update_mask,
+    .watch_remove       = watch_remove,
+
+#if SPICE_INTERFACE_CORE_MINOR >= 3
+    .channel_event      = channel_event,
+#endif
+};
+
+/* config string parsing */
+
+static int name2enum(const char *string, const char *table[], int entries)
+{
+    int i;
+
+    if (string) {
+        for (i = 0; i < entries; i++) {
+            if (!table[i]) {
+                continue;
+            }
+            if (strcmp(string, table[i]) != 0) {
+                continue;
+            }
+            return i;
+        }
+    }
+    return -1;
+}
+
+static int parse_name(const char *string, const char *optname,
+                      const char *table[], int entries)
+{
+    int value = name2enum(string, table, entries);
+
+    if (value != -1) {
+        return value;
+    }
+    fprintf(stderr, "spice: invalid %s: %s\n", optname, string);
+    exit(1);
+}
+
+static const char *stream_video_names[] = {
+    [ SPICE_STREAM_VIDEO_OFF ]    = "off",
+    [ SPICE_STREAM_VIDEO_ALL ]    = "all",
+    [ SPICE_STREAM_VIDEO_FILTER ] = "filter",
+};
+#define parse_stream_video(_name) \
+    name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
+
+static const char *compression_names[] = {
+    [ SPICE_IMAGE_COMPRESS_OFF ]      = "off",
+    [ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
+    [ SPICE_IMAGE_COMPRESS_AUTO_LZ ]  = "auto_lz",
+    [ SPICE_IMAGE_COMPRESS_QUIC ]     = "quic",
+    [ SPICE_IMAGE_COMPRESS_GLZ ]      = "glz",
+    [ SPICE_IMAGE_COMPRESS_LZ ]       = "lz",
+};
+#define parse_compression(_name)                                        \
+    parse_name(_name, "image compression",                              \
+               compression_names, ARRAY_SIZE(compression_names))
+
+static const char *wan_compression_names[] = {
+    [ SPICE_WAN_COMPRESSION_AUTO   ] = "auto",
+    [ SPICE_WAN_COMPRESSION_NEVER  ] = "never",
+    [ SPICE_WAN_COMPRESSION_ALWAYS ] = "always",
+};
+#define parse_wan_compression(_name)                                    \
+    parse_name(_name, "wan compression",                                \
+               wan_compression_names, ARRAY_SIZE(wan_compression_names))
+
+/* functions for the rest of qemu */
+
+static void info_spice_iter(QObject *obj, void *opaque)
+{
+    QDict *client;
+    Monitor *mon = opaque;
+
+    client = qobject_to_qdict(obj);
+    monitor_printf(mon, "Channel:\n");
+    monitor_printf(mon, "     address: %s:%s%s\n",
+                   qdict_get_str(client, "host"),
+                   qdict_get_str(client, "port"),
+                   qdict_get_bool(client, "tls") ? " [tls]" : "");
+    monitor_printf(mon, "     session: %" PRId64 "\n",
+                   qdict_get_int(client, "connection-id"));
+    monitor_printf(mon, "     channel: %d:%d\n",
+                   (int)qdict_get_int(client, "channel-type"),
+                   (int)qdict_get_int(client, "channel-id"));
+}
+
+void do_info_spice_print(Monitor *mon, const QObject *data)
+{
+    QDict *server;
+    QList *channels;
+    const char *host;
+    int port;
+
+    server = qobject_to_qdict(data);
+    if (qdict_get_bool(server, "enabled") == 0) {
+        monitor_printf(mon, "Server: disabled\n");
+        return;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    host = qdict_get_str(server, "host");
+    port = qdict_get_try_int(server, "port", -1);
+    if (port != -1) {
+        monitor_printf(mon, "     address: %s:%d\n", host, port);
+    }
+    port = qdict_get_try_int(server, "tls-port", -1);
+    if (port != -1) {
+        monitor_printf(mon, "     address: %s:%d [tls]\n", host, port);
+    }
+    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
+
+    channels = qdict_get_qlist(server, "channels");
+    if (qlist_empty(channels)) {
+        monitor_printf(mon, "Channels: none\n");
+    } else {
+        qlist_iter(channels, info_spice_iter, mon);
+    }
+}
+
+void do_info_spice(Monitor *mon, QObject **ret_data)
+{
+    QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+    QDict *server;
+    QList *clist;
+    const char *addr;
+    int port, tls_port;
+
+    if (!spice_server) {
+        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+        return;
+    }
+
+    addr = qemu_opt_get(opts, "addr");
+    port = qemu_opt_get_number(opts, "port", 0);
+    tls_port = qemu_opt_get_number(opts, "tls-port", 0);
+    clist = channel_list_get();
+
+    server = qdict_new();
+    qdict_put(server, "enabled", qbool_from_int(true));
+    qdict_put(server, "auth", qstring_from_str(auth));
+    qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
+    if (port) {
+        qdict_put(server, "port", qint_from_int(port));
+    }
+    if (tls_port) {
+        qdict_put(server, "tls-port", qint_from_int(tls_port));
+    }
+    if (clist) {
+        qdict_put(server, "channels", clist);
+    }
+
+    *ret_data = QOBJECT(server);
+}
+
+static void migration_state_notifier(Notifier *notifier, void *data)
+{
+    int state = get_migration_state();
+
+    if (state == MIG_STATE_COMPLETED) {
+#if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */
+        spice_server_migrate_switch(spice_server);
+#endif
+    }
+}
+
+int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
+                            const char *subject)
+{
+    return spice_server_migrate_info(spice_server, hostname,
+                                     port, tls_port, subject);
+}
+
+static int add_channel(const char *name, const char *value, void *opaque)
+{
+    int security = 0;
+    int rc;
+
+    if (strcmp(name, "tls-channel") == 0) {
+        security = SPICE_CHANNEL_SECURITY_SSL;
+    }
+    if (strcmp(name, "plaintext-channel") == 0) {
+        security = SPICE_CHANNEL_SECURITY_NONE;
+    }
+    if (security == 0) {
+        return 0;
+    }
+    if (strcmp(value, "default") == 0) {
+        rc = spice_server_set_channel_security(spice_server, NULL, security);
+    } else {
+        rc = spice_server_set_channel_security(spice_server, value, security);
+    }
+    if (rc != 0) {
+        fprintf(stderr, "spice: failed to set channel security for %s\n", value);
+        exit(1);
+    }
+    return 0;
+}
+
+void qemu_spice_init(void)
+{
+    QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+    const char *password, *str, *x509_dir, *addr,
+        *x509_key_password = NULL,
+        *x509_dh_file = NULL,
+        *tls_ciphers = NULL;
+    char *x509_key_file = NULL,
+        *x509_cert_file = NULL,
+        *x509_cacert_file = NULL;
+    int port, tls_port, len, addr_flags;
+    spice_image_compression_t compression;
+    spice_wan_compression_t wan_compr;
+
+    if (!opts) {
+        return;
+    }
+    port = qemu_opt_get_number(opts, "port", 0);
+    tls_port = qemu_opt_get_number(opts, "tls-port", 0);
+    if (!port && !tls_port) {
+        fprintf(stderr, "neither port nor tls-port specified for spice.");
+        exit(1);
+    }
+    if (port < 0 || port > 65535) {
+        fprintf(stderr, "spice port is out of range");
+        exit(1);
+    }
+    if (tls_port < 0 || tls_port > 65535) {
+        fprintf(stderr, "spice tls-port is out of range");
+        exit(1);
+    }
+    password = qemu_opt_get(opts, "password");
+
+    if (tls_port) {
+        x509_dir = qemu_opt_get(opts, "x509-dir");
+        if (NULL == x509_dir) {
+            x509_dir = ".";
+        }
+        len = strlen(x509_dir) + 32;
+
+        str = qemu_opt_get(opts, "x509-key-file");
+        if (str) {
+            x509_key_file = qemu_strdup(str);
+        } else {
+            x509_key_file = qemu_malloc(len);
+            snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
+        }
+
+        str = qemu_opt_get(opts, "x509-cert-file");
+        if (str) {
+            x509_cert_file = qemu_strdup(str);
+        } else {
+            x509_cert_file = qemu_malloc(len);
+            snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
+        }
+
+        str = qemu_opt_get(opts, "x509-cacert-file");
+        if (str) {
+            x509_cacert_file = qemu_strdup(str);
+        } else {
+            x509_cacert_file = qemu_malloc(len);
+            snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
+        }
+
+        x509_key_password = qemu_opt_get(opts, "x509-key-password");
+        x509_dh_file = qemu_opt_get(opts, "x509-dh-file");
+        tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
+    }
+
+    addr = qemu_opt_get(opts, "addr");
+    addr_flags = 0;
+    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+        addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY;
+    } else if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+        addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY;
+    }
+
+    spice_server = spice_server_new();
+    spice_server_set_addr(spice_server, addr ? addr : "", addr_flags);
+    if (port) {
+        spice_server_set_port(spice_server, port);
+    }
+    if (tls_port) {
+        spice_server_set_tls(spice_server, tls_port,
+                             x509_cacert_file,
+                             x509_cert_file,
+                             x509_key_file,
+                             x509_key_password,
+                             x509_dh_file,
+                             tls_ciphers);
+    }
+    if (password) {
+        spice_server_set_ticket(spice_server, password, 0, 0, 0);
+    }
+    if (qemu_opt_get_bool(opts, "sasl", 0)) {
+#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */
+        if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
+            spice_server_set_sasl(spice_server, 1) == -1) {
+            fprintf(stderr, "spice: failed to enable sasl\n");
+            exit(1);
+        }
+#else
+        fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n");
+        exit(1);
+#endif
+    }
+    if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
+        auth = "none";
+        spice_server_set_noauth(spice_server);
+    }
+
+#if SPICE_SERVER_VERSION >= 0x000801
+    if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) {
+        spice_server_set_agent_copypaste(spice_server, false);
+    }
+#endif
+
+    compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
+    str = qemu_opt_get(opts, "image-compression");
+    if (str) {
+        compression = parse_compression(str);
+    }
+    spice_server_set_image_compression(spice_server, compression);
+
+    wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+    str = qemu_opt_get(opts, "jpeg-wan-compression");
+    if (str) {
+        wan_compr = parse_wan_compression(str);
+    }
+    spice_server_set_jpeg_compression(spice_server, wan_compr);
+
+    wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+    str = qemu_opt_get(opts, "zlib-glz-wan-compression");
+    if (str) {
+        wan_compr = parse_wan_compression(str);
+    }
+    spice_server_set_zlib_glz_compression(spice_server, wan_compr);
+
+    str = qemu_opt_get(opts, "streaming-video");
+    if (str) {
+        int streaming_video = parse_stream_video(str);
+        spice_server_set_streaming_video(spice_server, streaming_video);
+    }
+
+    spice_server_set_agent_mouse
+        (spice_server, qemu_opt_get_bool(opts, "agent-mouse", 1));
+    spice_server_set_playback_compression
+        (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1));
+
+    qemu_opt_foreach(opts, add_channel, NULL, 0);
+
+    if (0 != spice_server_init(spice_server, &core_interface)) {
+        fprintf(stderr, "failed to initialize spice server");
+        exit(1);
+    };
+    using_spice = 1;
+
+    migration_state.notify = migration_state_notifier;
+    add_migration_state_change_notifier(&migration_state);
+
+    qemu_spice_input_init();
+    qemu_spice_audio_init();
+
+    qemu_free(x509_key_file);
+    qemu_free(x509_cert_file);
+    qemu_free(x509_cacert_file);
+}
+
+int qemu_spice_add_interface(SpiceBaseInstance *sin)
+{
+    if (!spice_server) {
+        if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) {
+            fprintf(stderr, "Oops: spice configured but not active\n");
+            exit(1);
+        }
+        /*
+         * Create a spice server instance.
+         * It does *not* listen on the network.
+         * It handles QXL local rendering only.
+         *
+         * With a command line like '-vnc :0 -vga qxl' you'll end up here.
+         */
+        spice_server = spice_server_new();
+        spice_server_init(spice_server, &core_interface);
+    }
+    return spice_server_add_interface(spice_server, sin);
+}
+
+static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn)
+{
+    time_t lifetime, now = time(NULL);
+    char *passwd;
+
+    if (now < auth_expires) {
+        passwd = auth_passwd;
+        lifetime = (auth_expires - now);
+        if (lifetime > INT_MAX) {
+            lifetime = INT_MAX;
+        }
+    } else {
+        passwd = NULL;
+        lifetime = 1;
+    }
+    return spice_server_set_ticket(spice_server, passwd, lifetime,
+                                   fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_passwd(const char *passwd,
+                          bool fail_if_conn, bool disconnect_if_conn)
+{
+    free(auth_passwd);
+    auth_passwd = strdup(passwd);
+    return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_pw_expire(time_t expires)
+{
+    auth_expires = expires;
+    return qemu_spice_set_ticket(false, false);
+}
+
+static void spice_register_config(void)
+{
+    qemu_add_opts(&qemu_spice_opts);
+}
+machine_init(spice_register_config);
+
+static void spice_initialize(void)
+{
+    qemu_spice_init();
+}
+device_init(spice_initialize);
diff --git a/qemu-0.15.x/ui/spice-display.c b/qemu-0.15.x/ui/spice-display.c
new file mode 100644
index 0000000..feeee73
--- /dev/null
+++ b/qemu-0.15.x/ui/spice-display.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+
+#include "spice-display.h"
+
+static int debug = 0;
+
+static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...)
+{
+    va_list args;
+
+    if (level <= debug) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+}
+
+int qemu_spice_rect_is_empty(const QXLRect* r)
+{
+    return r->top == r->bottom || r->left == r->right;
+}
+
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+{
+    if (qemu_spice_rect_is_empty(r)) {
+        return;
+    }
+
+    if (qemu_spice_rect_is_empty(dest)) {
+        *dest = *r;
+        return;
+    }
+
+    dest->top = MIN(dest->top, r->top);
+    dest->left = MIN(dest->left, r->left);
+    dest->bottom = MAX(dest->bottom, r->bottom);
+    dest->right = MAX(dest->right, r->right);
+}
+
+static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+{
+    SimpleSpiceUpdate *update;
+    QXLDrawable *drawable;
+    QXLImage *image;
+    QXLCommand *cmd;
+    uint8_t *src, *dst;
+    int by, bw, bh;
+    struct timespec time_space;
+
+    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+        return NULL;
+    };
+
+    dprint(2, "%s: lr %d -> %d,  tb -> %d -> %d\n", __FUNCTION__,
+           ssd->dirty.left, ssd->dirty.right,
+           ssd->dirty.top, ssd->dirty.bottom);
+
+    update   = qemu_mallocz(sizeof(*update));
+    drawable = &update->drawable;
+    image    = &update->image;
+    cmd      = &update->ext.cmd;
+
+    bw       = ssd->dirty.right - ssd->dirty.left;
+    bh       = ssd->dirty.bottom - ssd->dirty.top;
+    update->bitmap = qemu_malloc(bw * bh * 4);
+
+    drawable->bbox            = ssd->dirty;
+    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
+    drawable->effect          = QXL_EFFECT_OPAQUE;
+    drawable->release_info.id = (intptr_t)update;
+    drawable->type            = QXL_DRAW_COPY;
+    drawable->surfaces_dest[0] = -1;
+    drawable->surfaces_dest[1] = -1;
+    drawable->surfaces_dest[2] = -1;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    /* time in milliseconds from epoch. */
+    drawable->mm_time = time_space.tv_sec * 1000
+                      + time_space.tv_nsec / 1000 / 1000;
+
+    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
+    drawable->u.copy.src_bitmap      = (intptr_t)image;
+    drawable->u.copy.src_area.right  = bw;
+    drawable->u.copy.src_area.bottom = bh;
+
+    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
+    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
+    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
+    image->bitmap.stride     = bw * 4;
+    image->descriptor.width  = image->bitmap.x = bw;
+    image->descriptor.height = image->bitmap.y = bh;
+    image->bitmap.data = (intptr_t)(update->bitmap);
+    image->bitmap.palette = 0;
+    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+
+    if (ssd->conv == NULL) {
+        PixelFormat dst = qemu_default_pixelformat(32);
+        ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
+        assert(ssd->conv);
+    }
+
+    src = ds_get_data(ssd->ds) +
+        ssd->dirty.top * ds_get_linesize(ssd->ds) +
+        ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
+    dst = update->bitmap;
+    for (by = 0; by < bh; by++) {
+        qemu_pf_conv_run(ssd->conv, dst, src, bw);
+        src += ds_get_linesize(ssd->ds);
+        dst += image->bitmap.stride;
+    }
+
+    cmd->type = QXL_CMD_DRAW;
+    cmd->data = (intptr_t)drawable;
+
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    return update;
+}
+
+/*
+ * Called from spice server thread context (via interface_release_ressource)
+ * We do *not* hold the global qemu mutex here, so extra care is needed
+ * when calling qemu functions.  Qemu interfaces used:
+ *    - qemu_free (underlying glibc free is re-entrant).
+ */
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
+{
+    qemu_free(update->bitmap);
+    qemu_free(update);
+}
+
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+{
+    QXLDevMemSlot memslot;
+
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    memset(&memslot, 0, sizeof(memslot));
+    memslot.slot_group_id = MEMSLOT_GROUP_HOST;
+    memslot.virt_end = ~0;
+    ssd->worker->add_memslot(ssd->worker, &memslot);
+}
+
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+{
+    QXLDevSurfaceCreate surface;
+
+    dprint(1, "%s: %dx%d\n", __FUNCTION__,
+           ds_get_width(ssd->ds), ds_get_height(ssd->ds));
+
+    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
+    surface.width      = ds_get_width(ssd->ds);
+    surface.height     = ds_get_height(ssd->ds);
+    surface.stride     = -surface.width * 4;
+    surface.mouse_mode = true;
+    surface.flags      = 0;
+    surface.type       = 0;
+    surface.mem        = (intptr_t)ssd->buf;
+    surface.group_id   = MEMSLOT_GROUP_HOST;
+
+    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+}
+
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    ssd->worker->destroy_primary_surface(ssd->worker, 0);
+}
+
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    SimpleSpiceDisplay *ssd = opaque;
+
+    if (running) {
+        ssd->worker->start(ssd->worker);
+    } else {
+        ssd->worker->stop(ssd->worker);
+    }
+    ssd->running = running;
+}
+
+/* display listener callbacks */
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                               int x, int y, int w, int h)
+{
+    QXLRect update_area;
+
+    dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
+    update_area.left = x,
+    update_area.right = x + w;
+    update_area.top = y;
+    update_area.bottom = y + h;
+
+    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+        ssd->notify++;
+    }
+    qemu_spice_rect_union(&ssd->dirty, &update_area);
+}
+
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    qemu_pf_conv_put(ssd->conv);
+    ssd->conv = NULL;
+
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update != NULL) {
+        qemu_spice_destroy_update(ssd, ssd->update);
+        ssd->update = NULL;
+    }
+    qemu_mutex_unlock(&ssd->lock);
+    qemu_spice_destroy_host_primary(ssd);
+    qemu_spice_create_host_primary(ssd);
+
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    ssd->notify++;
+}
+
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    vga_hw_update();
+
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update == NULL) {
+        ssd->update = qemu_spice_create_update(ssd);
+        ssd->notify++;
+    }
+    if (ssd->cursor) {
+        ssd->ds->cursor_define(ssd->cursor);
+        cursor_put(ssd->cursor);
+        ssd->cursor = NULL;
+    }
+    if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
+        ssd->ds->mouse_set(ssd->mouse_x, ssd->mouse_y, 1);
+        ssd->mouse_x = -1;
+        ssd->mouse_y = -1;
+    }
+    qemu_mutex_unlock(&ssd->lock);
+
+    if (ssd->notify) {
+        ssd->notify = 0;
+        ssd->worker->wakeup(ssd->worker);
+        dprint(2, "%s: notify\n", __FUNCTION__);
+    }
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+    dprint(1, "%s:\n", __FUNCTION__);
+    ssd->worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    /* nothing to do */
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    /* nothing to do */
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits  = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = ssd->bufsize;
+    info->n_surfaces = NUM_SURFACES;
+}
+
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+    SimpleSpiceUpdate *update;
+    int ret = false;
+
+    dprint(3, "%s:\n", __FUNCTION__);
+
+    qemu_mutex_lock(&ssd->lock);
+    if (ssd->update != NULL) {
+        update = ssd->update;
+        ssd->update = NULL;
+        *ext = update->ext;
+        ret = true;
+    }
+    qemu_mutex_unlock(&ssd->lock);
+
+    return ret;
+}
+
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    return 1;
+}
+
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+    uintptr_t id;
+
+    dprint(2, "%s:\n", __FUNCTION__);
+    id = ext.info->id;
+    qemu_spice_destroy_update(ssd, (void*)id);
+}
+
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    return false;
+}
+
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    return 1;
+}
+
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+}
+
+static int interface_flush_resources(QXLInstance *sin)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+    return 0;
+}
+
+static const QXLInterface dpy_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qemu simple display",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+};
+
+static SimpleSpiceDisplay sdpy;
+
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+    qemu_spice_display_update(&sdpy, x, y, w, h);
+}
+
+static void display_resize(struct DisplayState *ds)
+{
+    qemu_spice_display_resize(&sdpy);
+}
+
+static void display_refresh(struct DisplayState *ds)
+{
+    qemu_spice_display_refresh(&sdpy);
+}
+
+static DisplayChangeListener display_listener = {
+    .dpy_update  = display_update,
+    .dpy_resize  = display_resize,
+    .dpy_refresh = display_refresh,
+};
+
+void qemu_spice_display_init(DisplayState *ds)
+{
+    assert(sdpy.ds == NULL);
+    sdpy.ds = ds;
+    qemu_mutex_init(&sdpy.lock);
+    sdpy.mouse_x = -1;
+    sdpy.mouse_y = -1;
+    sdpy.bufsize = (16 * 1024 * 1024);
+    sdpy.buf = qemu_malloc(sdpy.bufsize);
+    register_displaychangelistener(ds, &display_listener);
+
+    sdpy.qxl.base.sif = &dpy_interface.base;
+    qemu_spice_add_interface(&sdpy.qxl.base);
+    assert(sdpy.worker);
+
+    qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
+    qemu_spice_create_host_memslot(&sdpy);
+    qemu_spice_create_host_primary(&sdpy);
+}
diff --git a/qemu-0.15.x/ui/spice-display.h b/qemu-0.15.x/ui/spice-display.h
new file mode 100644
index 0000000..2f95f68
--- /dev/null
+++ b/qemu-0.15.x/ui/spice-display.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <spice/ipc_ring.h>
+#include <spice/enums.h>
+#include <spice/qxl_dev.h>
+
+#include "qemu-thread.h"
+#include "console.h"
+#include "pflib.h"
+
+#define NUM_MEMSLOTS 8
+#define MEMSLOT_GENERATION_BITS 8
+#define MEMSLOT_SLOT_BITS 8
+
+#define MEMSLOT_GROUP_HOST  0
+#define MEMSLOT_GROUP_GUEST 1
+#define NUM_MEMSLOTS_GROUPS 2
+
+#define NUM_SURFACES 1024
+
+typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
+typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
+
+struct SimpleSpiceDisplay {
+    DisplayState *ds;
+    void *buf;
+    int bufsize;
+    QXLWorker *worker;
+    QXLInstance qxl;
+    uint32_t unique;
+    QemuPfConv *conv;
+
+    QXLRect dirty;
+    int notify;
+    int running;
+
+    /*
+     * All struct members below this comment can be accessed from
+     * both spice server and qemu (iothread) context and any access
+     * to them must be protected by the lock.
+     */
+    QemuMutex lock;
+    SimpleSpiceUpdate *update;
+    QEMUCursor *cursor;
+    int mouse_x, mouse_y;
+};
+
+struct SimpleSpiceUpdate {
+    QXLDrawable drawable;
+    QXLImage image;
+    QXLCommandExt ext;
+    uint8_t *bitmap;
+};
+
+int qemu_spice_rect_is_empty(const QXLRect* r);
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
+
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                               int x, int y, int w, int h);
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
diff --git a/qemu-0.15.x/ui/spice-input.c b/qemu-0.15.x/ui/spice-input.c
new file mode 100644
index 0000000..75abf5f
--- /dev/null
+++ b/qemu-0.15.x/ui/spice-input.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <spice.h>
+#include <spice/enums.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "console.h"
+
+/* keyboard bits */
+
+typedef struct QemuSpiceKbd {
+    SpiceKbdInstance sin;
+    int ledstate;
+} QemuSpiceKbd;
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
+static void kbd_leds(void *opaque, int l);
+
+static const SpiceKbdInterface kbd_interface = {
+    .base.type          = SPICE_INTERFACE_KEYBOARD,
+    .base.description   = "qemu keyboard",
+    .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
+    .push_scan_freg     = kbd_push_key,
+    .get_leds           = kbd_get_leds,
+};
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
+{
+    kbd_put_keycode(frag);
+}
+
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
+{
+    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
+    return kbd->ledstate;
+}
+
+static void kbd_leds(void *opaque, int ledstate)
+{
+    QemuSpiceKbd *kbd = opaque;
+
+    kbd->ledstate = 0;
+    if (ledstate & QEMU_SCROLL_LOCK_LED) {
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
+    }
+    if (ledstate & QEMU_NUM_LOCK_LED) {
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
+    }
+    if (ledstate & QEMU_CAPS_LOCK_LED) {
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
+    }
+    spice_server_kbd_leds(&kbd->sin, ledstate);
+}
+
+/* mouse bits */
+
+typedef struct QemuSpicePointer {
+    SpiceMouseInstance  mouse;
+    SpiceTabletInstance tablet;
+    int width, height, x, y;
+    Notifier mouse_mode;
+    bool absolute;
+} QemuSpicePointer;
+
+static int map_buttons(int spice_buttons)
+{
+    int qemu_buttons = 0;
+
+    /*
+     * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this
+     * isn't what we get passed in via interface callbacks for the
+     * middle and right button ...
+     */
+    if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) {
+        qemu_buttons |= MOUSE_EVENT_LBUTTON;
+    }
+    if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) {
+        qemu_buttons |= MOUSE_EVENT_MBUTTON;
+    }
+    if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) {
+        qemu_buttons |= MOUSE_EVENT_RBUTTON;
+    }
+    return qemu_buttons;
+}
+
+static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
+                         uint32_t buttons_state)
+{
+    kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state));
+}
+
+static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
+{
+    kbd_mouse_event(0, 0, 0, map_buttons(buttons_state));
+}
+
+static const SpiceMouseInterface mouse_interface = {
+    .base.type          = SPICE_INTERFACE_MOUSE,
+    .base.description   = "mouse",
+    .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
+    .motion             = mouse_motion,
+    .buttons            = mouse_buttons,
+};
+
+static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    if (height < 16) {
+        height = 16;
+    }
+    if (width < 16) {
+        width = 16;
+    }
+    pointer->width  = width;
+    pointer->height = height;
+}
+
+static void tablet_position(SpiceTabletInstance* sin, int x, int y,
+                            uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    pointer->x = x * 0x7FFF / (pointer->width - 1);
+    pointer->y = y * 0x7FFF / (pointer->height - 1);
+    kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+}
+
+
+static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
+                         uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state));
+}
+
+static void tablet_buttons(SpiceTabletInstance *sin,
+                           uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+}
+
+static const SpiceTabletInterface tablet_interface = {
+    .base.type          = SPICE_INTERFACE_TABLET,
+    .base.description   = "tablet",
+    .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
+    .set_logical_size   = tablet_set_logical_size,
+    .position           = tablet_position,
+    .wheel              = tablet_wheel,
+    .buttons            = tablet_buttons,
+};
+
+static void mouse_mode_notifier(Notifier *notifier, void *data)
+{
+    QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
+    bool is_absolute  = kbd_mouse_is_absolute();
+
+    if (pointer->absolute == is_absolute) {
+        return;
+    }
+
+    if (is_absolute) {
+        qemu_spice_add_interface(&pointer->tablet.base);
+    } else {
+        spice_server_remove_interface(&pointer->tablet.base);
+    }
+    pointer->absolute = is_absolute;
+}
+
+void qemu_spice_input_init(void)
+{
+    QemuSpiceKbd *kbd;
+    QemuSpicePointer *pointer;
+
+    kbd = qemu_mallocz(sizeof(*kbd));
+    kbd->sin.base.sif = &kbd_interface.base;
+    qemu_spice_add_interface(&kbd->sin.base);
+    qemu_add_led_event_handler(kbd_leds, kbd);
+
+    pointer = qemu_mallocz(sizeof(*pointer));
+    pointer->mouse.base.sif  = &mouse_interface.base;
+    pointer->tablet.base.sif = &tablet_interface.base;
+    qemu_spice_add_interface(&pointer->mouse.base);
+
+    pointer->absolute = false;
+    pointer->mouse_mode.notify = mouse_mode_notifier;
+    qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
+    mouse_mode_notifier(&pointer->mouse_mode, NULL);
+}
diff --git a/qemu-0.15.x/ui/vnc-auth-sasl.c b/qemu-0.15.x/ui/vnc-auth-sasl.c
new file mode 100644
index 0000000..15af49b
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-auth-sasl.c
@@ -0,0 +1,632 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "vnc.h"
+
+/* Max amount of data we send/recv for SASL steps to prevent DOS */
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+
+void vnc_sasl_client_cleanup(VncState *vs)
+{
+    if (vs->sasl.conn) {
+        vs->sasl.runSSF = vs->sasl.waitWriteSSF = vs->sasl.wantSSF = 0;
+        vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
+        vs->sasl.encoded = NULL;
+        free(vs->sasl.username);
+        free(vs->sasl.mechlist);
+        vs->sasl.username = vs->sasl.mechlist = NULL;
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+    }
+}
+
+
+long vnc_client_write_sasl(VncState *vs)
+{
+    long ret;
+
+    VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
+              "Encoded: %p size %d offset %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
+
+    if (!vs->sasl.encoded) {
+        int err;
+        err = sasl_encode(vs->sasl.conn,
+                          (char *)vs->output.buffer,
+                          vs->output.offset,
+                          (const char **)&vs->sasl.encoded,
+                          &vs->sasl.encodedLength);
+        if (err != SASL_OK)
+            return vnc_client_io_error(vs, -1, EIO);
+
+        vs->sasl.encodedOffset = 0;
+    }
+
+    ret = vnc_client_write_buf(vs,
+                               vs->sasl.encoded + vs->sasl.encodedOffset,
+                               vs->sasl.encodedLength - vs->sasl.encodedOffset);
+    if (!ret)
+        return 0;
+
+    vs->sasl.encodedOffset += ret;
+    if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
+        vs->output.offset = 0;
+        vs->sasl.encoded = NULL;
+        vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
+    }
+
+    /* Can't merge this block with one above, because
+     * someone might have written more unencrypted
+     * data in vs->output while we were processing
+     * SASL encoded output
+     */
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+long vnc_client_read_sasl(VncState *vs)
+{
+    long ret;
+    uint8_t encoded[4096];
+    const char *decoded;
+    unsigned int decodedLen;
+    int err;
+
+    ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
+    if (!ret)
+        return 0;
+
+    err = sasl_decode(vs->sasl.conn,
+                      (char *)encoded, ret,
+                      &decoded, &decodedLen);
+
+    if (err != SASL_OK)
+        return vnc_client_io_error(vs, -1, -EIO);
+    VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
+              encoded, ret, decoded, decodedLen);
+    buffer_reserve(&vs->input, decodedLen);
+    buffer_append(&vs->input, decoded, decodedLen);
+    return decodedLen;
+}
+
+
+static int vnc_auth_sasl_check_access(VncState *vs)
+{
+    const void *val;
+    int err;
+    int allow;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        return -1;
+    }
+    if (val == NULL) {
+        VNC_DEBUG("no client username was found, denying access\n");
+        return -1;
+    }
+    VNC_DEBUG("SASL client username %s\n", (const char *)val);
+
+    vs->sasl.username = qemu_strdup((const char*)val);
+
+    if (vs->vd->sasl.acl == NULL) {
+        VNC_DEBUG("no ACL activated, allowing access\n");
+        return 0;
+    }
+
+    allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
+
+    VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
+              allow ? "allowed" : "denied");
+    return allow ? 0 : -1;
+}
+
+static int vnc_auth_sasl_check_ssf(VncState *vs)
+{
+    const void *val;
+    int err, ssf;
+
+    if (!vs->sasl.wantSSF)
+        return 1;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
+    if (err != SASL_OK)
+        return 0;
+
+    ssf = *(const int *)val;
+    VNC_DEBUG("negotiated an SSF of %d\n", ssf);
+    if (ssf < 56)
+        return 0; /* 56 is good for Kerberos */
+
+    /* Only setup for read initially, because we're about to send an RPC
+     * reply which must be in plain text. When the next incoming RPC
+     * arrives, we'll switch on writes too
+     *
+     * cf qemudClientReadSASL  in qemud.c
+     */
+    vs->sasl.runSSF = 1;
+
+    /* We have a SSF that's good enough */
+    return 1;
+}
+
+/*
+ * Step Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
+
+static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
+              clientdata, datalen);
+    err = sasl_server_step(vs->sasl.conn,
+                           clientdata,
+                           datalen,
+                           &serverout,
+                           &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl step failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl step reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        /*
+         * Delay writing in SSF encoded mode until pending output
+         * buffer is written
+         */
+        if (vs->sasl.runSSF)
+            vs->sasl.waitWriteSSF = vs->output.offset;
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t steplen = read_u32(data, 0);
+    VNC_DEBUG("Got client step len %d\n", steplen);
+    if (steplen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", steplen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (steplen == 0)
+        return protocol_client_auth_sasl_step(vs, NULL, 0);
+    else
+        vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
+    return 0;
+}
+
+/*
+ * Start Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
+              vs->sasl.mechlist, clientdata, datalen);
+    err = sasl_server_start(vs->sasl.conn,
+                            vs->sasl.mechlist,
+                            clientdata,
+                            datalen,
+                            &serverout,
+                            &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl start failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl start reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t startlen = read_u32(data, 0);
+    VNC_DEBUG("Got client start len %d\n", startlen);
+    if (startlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", startlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (startlen == 0)
+        return protocol_client_auth_sasl_start(vs, NULL, 0);
+
+    vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
+    return 0;
+}
+
+static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
+{
+    char *mechname = malloc(len + 1);
+    if (!mechname) {
+        VNC_DEBUG("Out of memory reading mechname\n");
+        vnc_client_error(vs);
+    }
+    strncpy(mechname, (char*)data, len);
+    mechname[len] = '\0';
+    VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
+              mechname, vs->sasl.mechlist);
+
+    if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
+        if (vs->sasl.mechlist[len] != '\0' &&
+            vs->sasl.mechlist[len] != ',') {
+            VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
+            goto fail;
+        }
+    } else {
+        char *offset = strstr(vs->sasl.mechlist, mechname);
+        VNC_DEBUG("Two %p\n", offset);
+        if (!offset) {
+            goto fail;
+        }
+        VNC_DEBUG("Two '%s'\n", offset);
+        if (offset[-1] != ',' ||
+            (offset[len] != '\0'&&
+             offset[len] != ',')) {
+            goto fail;
+        }
+    }
+
+    free(vs->sasl.mechlist);
+    vs->sasl.mechlist = mechname;
+
+    VNC_DEBUG("Validated mechname '%s'\n", mechname);
+    vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
+    return 0;
+
+ fail:
+    vnc_client_error(vs);
+    free(mechname);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t mechlen = read_u32(data, 0);
+    VNC_DEBUG("Got client mechname len %d\n", mechlen);
+    if (mechlen > 100) {
+        VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    if (mechlen < 1) {
+        VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
+    return 0;
+}
+
+void start_auth_sasl(VncState *vs)
+{
+    const char *mechlist = NULL;
+    sasl_security_properties_t secprops;
+    int err;
+    char *localAddr, *remoteAddr;
+    int mechlistlen;
+
+    VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
+
+    /* Get local & remote client addresses in form  IPADDR;PORT */
+    if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
+        goto authabort;
+
+    if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
+        free(localAddr);
+        goto authabort;
+    }
+
+    err = sasl_server_new("vnc",
+                          NULL, /* FQDN - just delegates to gethostname */
+                          NULL, /* User realm */
+                          localAddr,
+                          remoteAddr,
+                          NULL, /* Callbacks, not needed */
+                          SASL_SUCCESS_DATA,
+                          &vs->sasl.conn);
+    free(localAddr);
+    free(remoteAddr);
+    localAddr = remoteAddr = NULL;
+
+    if (err != SASL_OK) {
+        VNC_DEBUG("sasl context setup failed %d (%s)",
+                  err, sasl_errstring(err, NULL, NULL));
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+#ifdef CONFIG_VNC_TLS
+    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
+    if (vs->auth == VNC_AUTH_VENCRYPT &&
+        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
+        gnutls_cipher_algorithm_t cipher;
+        sasl_ssf_t ssf;
+
+        cipher = gnutls_cipher_get(vs->tls.session);
+        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
+            VNC_DEBUG("%s", "cannot TLS get cipher size\n");
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+        ssf *= 8; /* tls key size is bytes, sasl wants bits */
+
+        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
+        if (err != SASL_OK) {
+            VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
+                      err, sasl_errstring(err, NULL, NULL));
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        vs->sasl.wantSSF = 1;
+
+    memset (&secprops, 0, sizeof secprops);
+    /* Inform SASL that we've got an external SSF layer from TLS */
+    if (strncmp(vs->vd->display, "unix:", 5) == 0
+#ifdef CONFIG_VNC_TLS
+        /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
+           is not sufficiently strong */
+        || (vs->auth == VNC_AUTH_VENCRYPT &&
+            vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+#endif /* CONFIG_VNC_TLS */
+        ) {
+        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
+        secprops.min_ssf = 0;
+        secprops.max_ssf = 0;
+        secprops.maxbufsize = 8192;
+        secprops.security_flags = 0;
+    } else {
+        /* Plain TCP, better get an SSF layer */
+        secprops.min_ssf = 56; /* Good enough to require kerberos */
+        secprops.max_ssf = 100000; /* Arbitrary big number */
+        secprops.maxbufsize = 8192;
+        /* Forbid any anonymous or trivially crackable auth */
+        secprops.security_flags =
+            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
+    }
+
+    err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot set SASL security props %d (%s)\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    err = sasl_listmech(vs->sasl.conn,
+                        NULL, /* Don't need to set user */
+                        "", /* Prefix */
+                        ",", /* Separator */
+                        "", /* Suffix */
+                        &mechlist,
+                        NULL,
+                        NULL);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
+
+    if (!(vs->sasl.mechlist = strdup(mechlist))) {
+        VNC_DEBUG("Out of memory");
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    mechlistlen = strlen(mechlist);
+    vnc_write_u32(vs, mechlistlen);
+    vnc_write(vs, mechlist, mechlistlen);
+    vnc_flush(vs);
+
+    VNC_DEBUG("Wait for client mechname length\n");
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
+
+    return;
+
+ authabort:
+    vnc_client_error(vs);
+    return;
+}
+
+
diff --git a/qemu-0.15.x/ui/vnc-auth-sasl.h b/qemu-0.15.x/ui/vnc-auth-sasl.h
new file mode 100644
index 0000000..fd9b18a
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-auth-sasl.h
@@ -0,0 +1,74 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 __QEMU_VNC_AUTH_SASL_H__
+#define __QEMU_VNC_AUTH_SASL_H__
+
+
+#include <sasl/sasl.h>
+
+typedef struct VncStateSASL VncStateSASL;
+typedef struct VncDisplaySASL VncDisplaySASL;
+
+#include "acl.h"
+
+struct VncStateSASL {
+    sasl_conn_t *conn;
+    /* If we want to negotiate an SSF layer with client */
+    int wantSSF :1;
+    /* If we are now running the SSF layer */
+    int runSSF :1;
+    /*
+     * If this is non-zero, then wait for that many bytes
+     * to be written plain, before switching to SSF encoding
+     * This allows the VNC auth result to finish being
+     * written in plain.
+     */
+    unsigned int waitWriteSSF;
+
+    /*
+     * Buffering encoded data to allow more clear data
+     * to be stuffed onto the output buffer
+     */
+    const uint8_t *encoded;
+    unsigned int encodedLength;
+    unsigned int encodedOffset;
+    char *username;
+    char *mechlist;
+};
+
+struct VncDisplaySASL {
+    qemu_acl *acl;
+};
+
+void vnc_sasl_client_cleanup(VncState *vs);
+
+long vnc_client_read_sasl(VncState *vs);
+long vnc_client_write_sasl(VncState *vs);
+
+void start_auth_sasl(VncState *vs);
+
+#endif /* __QEMU_VNC_AUTH_SASL_H__ */
+
diff --git a/qemu-0.15.x/ui/vnc-auth-vencrypt.c b/qemu-0.15.x/ui/vnc-auth-vencrypt.c
new file mode 100644
index 0000000..674ba97
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-auth-vencrypt.c
@@ -0,0 +1,175 @@
+/*
+ * QEMU VNC display driver: VeNCrypt authentication setup
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "vnc.h"
+
+
+static void start_auth_vencrypt_subauth(VncState *vs)
+{
+    switch (vs->subauth) {
+    case VNC_AUTH_VENCRYPT_TLSNONE:
+    case VNC_AUTH_VENCRYPT_X509NONE:
+       VNC_DEBUG("Accept TLS auth none\n");
+       vnc_write_u32(vs, 0); /* Accept auth completion */
+       start_client_init(vs);
+       break;
+
+    case VNC_AUTH_VENCRYPT_TLSVNC:
+    case VNC_AUTH_VENCRYPT_X509VNC:
+       VNC_DEBUG("Start TLS auth VNC\n");
+       start_auth_vnc(vs);
+       break;
+
+#ifdef CONFIG_VNC_SASL
+    case VNC_AUTH_VENCRYPT_TLSSASL:
+    case VNC_AUTH_VENCRYPT_X509SASL:
+      VNC_DEBUG("Start TLS auth SASL\n");
+      return start_auth_sasl(vs);
+#endif /* CONFIG_VNC_SASL */
+
+    default: /* Should not be possible, but just in case */
+       VNC_DEBUG("Reject subauth %d server bug\n", vs->auth);
+       vnc_write_u8(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Unsupported authentication type";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    }
+}
+
+static void vnc_tls_handshake_io(void *opaque);
+
+static int vnc_start_vencrypt_handshake(struct VncState *vs) {
+    int ret;
+
+    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
+       if (!gnutls_error_is_fatal(ret)) {
+           VNC_DEBUG("Handshake interrupted (blocking)\n");
+           if (!gnutls_record_get_direction(vs->tls.session))
+               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
+           else
+               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
+           return 0;
+       }
+       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
+       vnc_client_error(vs);
+       return -1;
+    }
+
+    if (vs->vd->tls.x509verify) {
+        if (vnc_tls_validate_certificate(vs) < 0) {
+            VNC_DEBUG("Client verification failed\n");
+            vnc_client_error(vs);
+            return -1;
+        } else {
+            VNC_DEBUG("Client verification passed\n");
+        }
+    }
+
+    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
+    vs->tls.wiremode = VNC_WIREMODE_TLS;
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+
+    start_auth_vencrypt_subauth(vs);
+
+    return 0;
+}
+
+static void vnc_tls_handshake_io(void *opaque) {
+    struct VncState *vs = (struct VncState *)opaque;
+
+    VNC_DEBUG("Handshake IO continue\n");
+    vnc_start_vencrypt_handshake(vs);
+}
+
+
+
+#define NEED_X509_AUTH(vs)                              \
+    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN ||  \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+
+
+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
+{
+    int auth = read_u32(data, 0);
+
+    if (auth != vs->subauth) {
+        VNC_DEBUG("Rejecting auth %d\n", auth);
+        vnc_write_u8(vs, 0); /* Reject auth */
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
+        vnc_write_u8(vs, 1); /* Accept auth */
+        vnc_flush(vs);
+
+        if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
+            VNC_DEBUG("Failed to setup TLS\n");
+            return 0;
+        }
+
+        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
+        if (vnc_start_vencrypt_handshake(vs) < 0) {
+            VNC_DEBUG("Failed to start TLS handshake\n");
+            return 0;
+        }
+    }
+    return 0;
+}
+
+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
+{
+    if (data[0] != 0 ||
+        data[1] != 2) {
+        VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
+        vnc_write_u8(vs, 1); /* Reject version */
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
+        vnc_write_u8(vs, 0); /* Accept version */
+        vnc_write_u8(vs, 1); /* Number of sub-auths */
+        vnc_write_u32(vs, vs->subauth); /* The supported auth */
+        vnc_flush(vs);
+        vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
+    }
+    return 0;
+}
+
+
+void start_auth_vencrypt(VncState *vs)
+{
+    /* Send VeNCrypt version 0.2 */
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 2);
+
+    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
+}
+
diff --git a/qemu-0.15.x/ui/vnc-auth-vencrypt.h b/qemu-0.15.x/ui/vnc-auth-vencrypt.h
new file mode 100644
index 0000000..9f674c5
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-auth-vencrypt.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 __QEMU_VNC_AUTH_VENCRYPT_H__
+#define __QEMU_VNC_AUTH_VENCRYPT_H__
+
+void start_auth_vencrypt(VncState *vs);
+
+#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
diff --git a/qemu-0.15.x/ui/vnc-enc-hextile-template.h b/qemu-0.15.x/ui/vnc-enc-hextile-template.h
new file mode 100644
index 0000000..b9f9f5e
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-hextile-template.h
@@ -0,0 +1,211 @@
+#define CONCAT_I(a, b) a ## b
+#define CONCAT(a, b) CONCAT_I(a, b)
+#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
+#ifdef GENERIC
+#define NAME CONCAT(generic_, BPP)
+#else
+#define NAME BPP
+#endif
+
+static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
+                                             int x, int y, int w, int h,
+                                             void *last_bg_,
+                                             void *last_fg_,
+                                             int *has_bg, int *has_fg)
+{
+    VncDisplay *vd = vs->vd;
+    uint8_t *row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    pixel_t *irow = (pixel_t *)row;
+    int j, i;
+    pixel_t *last_bg = (pixel_t *)last_bg_;
+    pixel_t *last_fg = (pixel_t *)last_fg_;
+    pixel_t bg = 0;
+    pixel_t fg = 0;
+    int n_colors = 0;
+    int bg_count = 0;
+    int fg_count = 0;
+    int flags = 0;
+    uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
+    int n_data = 0;
+    int n_subtiles = 0;
+
+    for (j = 0; j < h; j++) {
+	for (i = 0; i < w; i++) {
+	    switch (n_colors) {
+	    case 0:
+		bg = irow[i];
+		n_colors = 1;
+		break;
+	    case 1:
+		if (irow[i] != bg) {
+		    fg = irow[i];
+		    n_colors = 2;
+		}
+		break;
+	    case 2:
+		if (irow[i] != bg && irow[i] != fg) {
+		    n_colors = 3;
+		} else {
+		    if (irow[i] == bg)
+			bg_count++;
+		    else if (irow[i] == fg)
+			fg_count++;
+		}
+		break;
+	    default:
+		break;
+	    }
+	}
+	if (n_colors > 2)
+	    break;
+	irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+    }
+
+    if (n_colors > 1 && fg_count > bg_count) {
+	pixel_t tmp = fg;
+	fg = bg;
+	bg = tmp;
+    }
+
+    if (!*has_bg || *last_bg != bg) {
+	flags |= 0x02;
+	*has_bg = 1;
+	*last_bg = bg;
+    }
+
+    if (n_colors < 3 && (!*has_fg || *last_fg != fg)) {
+	flags |= 0x04;
+	*has_fg = 1;
+	*last_fg = fg;
+    }
+
+    switch (n_colors) {
+    case 1:
+	n_data = 0;
+	break;
+    case 2:
+	flags |= 0x08;
+
+	irow = (pixel_t *)row;
+
+	for (j = 0; j < h; j++) {
+	    int min_x = -1;
+	    for (i = 0; i < w; i++) {
+		if (irow[i] == fg) {
+		    if (min_x == -1)
+			min_x = i;
+		} else if (min_x != -1) {
+		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+		    n_data += 2;
+		    n_subtiles++;
+		    min_x = -1;
+		}
+	    }
+	    if (min_x != -1) {
+		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+		n_data += 2;
+		n_subtiles++;
+	    }
+	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+	}
+	break;
+    case 3:
+	flags |= 0x18;
+
+	irow = (pixel_t *)row;
+
+	if (!*has_bg || *last_bg != bg)
+	    flags |= 0x02;
+
+	for (j = 0; j < h; j++) {
+	    int has_color = 0;
+	    int min_x = -1;
+	    pixel_t color = 0; /* shut up gcc */
+
+	    for (i = 0; i < w; i++) {
+		if (!has_color) {
+		    if (irow[i] == bg)
+			continue;
+		    color = irow[i];
+		    min_x = i;
+		    has_color = 1;
+		} else if (irow[i] != color) {
+		    has_color = 0;
+#ifdef GENERIC
+                    vnc_convert_pixel(vs, data + n_data, color);
+                    n_data += vs->clientds.pf.bytes_per_pixel;
+#else
+		    memcpy(data + n_data, &color, sizeof(color));
+                    n_data += sizeof(pixel_t);
+#endif
+		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+		    n_data += 2;
+		    n_subtiles++;
+
+		    min_x = -1;
+		    if (irow[i] != bg) {
+			color = irow[i];
+			min_x = i;
+			has_color = 1;
+		    }
+		}
+	    }
+	    if (has_color) {
+#ifdef GENERIC
+                vnc_convert_pixel(vs, data + n_data, color);
+                n_data += vs->clientds.pf.bytes_per_pixel;
+#else
+                memcpy(data + n_data, &color, sizeof(color));
+                n_data += sizeof(pixel_t);
+#endif
+		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+		n_data += 2;
+		n_subtiles++;
+	    }
+	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+	}
+
+	/* A SubrectsColoured subtile invalidates the foreground color */
+	*has_fg = 0;
+	if (n_data > (w * h * sizeof(pixel_t))) {
+	    n_colors = 4;
+	    flags = 0x01;
+	    *has_bg = 0;
+
+	    /* we really don't have to invalidate either the bg or fg
+	       but we've lost the old values.  oh well. */
+	}
+    default:
+	break;
+    }
+
+    if (n_colors > 3) {
+	flags = 0x01;
+	*has_fg = 0;
+	*has_bg = 0;
+	n_colors = 4;
+    }
+
+    vnc_write_u8(vs, flags);
+    if (n_colors < 4) {
+	if (flags & 0x02)
+	    vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
+	if (flags & 0x04)
+	    vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
+	if (n_subtiles) {
+	    vnc_write_u8(vs, n_subtiles);
+	    vnc_write(vs, data, n_data);
+	}
+    } else {
+	for (j = 0; j < h; j++) {
+	    vs->write_pixels(vs, &vd->server->pf, row,
+                             w * ds_get_bytes_per_pixel(vs->ds));
+	    row += ds_get_linesize(vs->ds);
+	}
+    }
+}
+
+#undef NAME
+#undef pixel_t
+#undef CONCAT_I
+#undef CONCAT
diff --git a/qemu-0.15.x/ui/vnc-enc-hextile.c b/qemu-0.15.x/ui/vnc-enc-hextile.c
new file mode 100644
index 0000000..364a491
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-hextile.c
@@ -0,0 +1,116 @@
+/*
+ * QEMU VNC display driver: hextile encoding
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "vnc.h"
+
+static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
+{
+    ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
+    ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
+}
+
+#define BPP 8
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+
+#define BPP 16
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+
+#define BPP 32
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+
+#define GENERIC
+#define BPP 8
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 16
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 32
+#include "vnc-enc-hextile-template.h"
+#undef BPP
+#undef GENERIC
+
+int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
+                                        int y, int w, int h)
+{
+    int i, j;
+    int has_fg, has_bg;
+    uint8_t *last_fg, *last_bg;
+    VncDisplay *vd = vs->vd;
+
+    last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
+    has_fg = has_bg = 0;
+    for (j = y; j < (y + h); j += 16) {
+        for (i = x; i < (x + w); i += 16) {
+            vs->hextile.send_tile(vs, i, j,
+                                  MIN(16, x + w - i), MIN(16, y + h - j),
+                                  last_bg, last_fg, &has_bg, &has_fg);
+        }
+    }
+    free(last_fg);
+    free(last_bg);
+
+    return 1;
+}
+
+void vnc_hextile_set_pixel_conversion(VncState *vs, int generic)
+{
+    if (!generic) {
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->hextile.send_tile = send_hextile_tile_8;
+                break;
+            case 16:
+                vs->hextile.send_tile = send_hextile_tile_16;
+                break;
+            case 32:
+                vs->hextile.send_tile = send_hextile_tile_32;
+                break;
+        }
+    } else {
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->hextile.send_tile = send_hextile_tile_generic_8;
+                break;
+            case 16:
+                vs->hextile.send_tile = send_hextile_tile_generic_16;
+                break;
+            case 32:
+                vs->hextile.send_tile = send_hextile_tile_generic_32;
+                break;
+        }
+    }
+}
diff --git a/qemu-0.15.x/ui/vnc-enc-tight.c b/qemu-0.15.x/ui/vnc-enc-tight.c
new file mode 100644
index 0000000..5c02803
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-tight.c
@@ -0,0 +1,1777 @@
+/*
+ * QEMU VNC display driver: tight encoding
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 "config-host.h"
+
+/* This needs to be before jpeglib.h line because of conflict with
+   INT32 definitions between jmorecfg.h (included by jpeglib.h) and
+   Win32 basetsd.h (included by windows.h). */
+#include "qemu-common.h"
+
+#ifdef CONFIG_VNC_PNG
+/* The following define is needed by pngconf.h. Otherwise it won't compile,
+   because setjmp.h was already included by qemu-common.h. */
+#define PNG_SKIP_SETJMP_CHECK
+#include <png.h>
+#endif
+#ifdef CONFIG_VNC_JPEG
+#include <stdio.h>
+#include <jpeglib.h>
+#endif
+
+#include "bswap.h"
+#include "qint.h"
+#include "vnc.h"
+#include "vnc-enc-tight.h"
+#include "vnc-palette.h"
+
+/* Compression level stuff. The following array contains various
+   encoder parameters for each of 10 compression levels (0..9).
+   Last three parameters correspond to JPEG quality levels (0..9). */
+
+static const struct {
+    int max_rect_size, max_rect_width;
+    int mono_min_rect_size, gradient_min_rect_size;
+    int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level;
+    int gradient_threshold, gradient_threshold24;
+    int idx_max_colors_divisor;
+    int jpeg_quality, jpeg_threshold, jpeg_threshold24;
+} tight_conf[] = {
+    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
+    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
+    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
+    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
+    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
+    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
+    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
+    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
+    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
+    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
+};
+
+
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                         int w, int h);
+
+#ifdef CONFIG_VNC_JPEG
+static const struct {
+    double jpeg_freq_min;       /* Don't send JPEG if the freq is bellow */
+    double jpeg_freq_threshold; /* Always send JPEG if the freq is above */
+    int jpeg_idx;               /* Allow indexed JPEG */
+    int jpeg_full;              /* Allow full color JPEG */
+} tight_jpeg_conf[] = {
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   8,  1, 1 },
+    { 0,   10, 1, 1 },
+    { 0.1, 10, 1, 1 },
+    { 0.2, 10, 1, 1 },
+    { 0.3, 12, 0, 0 },
+    { 0.4, 14, 0, 0 },
+    { 0.5, 16, 0, 0 },
+};
+#endif
+
+#ifdef CONFIG_VNC_PNG
+static const struct {
+    int png_zlib_level, png_filters;
+} tight_png_conf[] = {
+    { 0, PNG_NO_FILTERS },
+    { 1, PNG_NO_FILTERS },
+    { 2, PNG_NO_FILTERS },
+    { 3, PNG_NO_FILTERS },
+    { 4, PNG_NO_FILTERS },
+    { 5, PNG_ALL_FILTERS },
+    { 6, PNG_ALL_FILTERS },
+    { 7, PNG_ALL_FILTERS },
+    { 8, PNG_ALL_FILTERS },
+    { 9, PNG_ALL_FILTERS },
+};
+
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+                         VncPalette *palette);
+
+static bool tight_can_send_png_rect(VncState *vs, int w, int h)
+{
+    if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
+        return false;
+    }
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+        vs->clientds.pf.bytes_per_pixel == 1) {
+        return false;
+    }
+
+    return true;
+}
+#endif
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+static unsigned int
+tight_detect_smooth_image24(VncState *vs, int w, int h)
+{
+    int off;
+    int x, y, d, dx;
+    unsigned int c;
+    unsigned int stats[256];
+    int pixels = 0;
+    int pix, left[3];
+    unsigned int errors;
+    unsigned char *buf = vs->tight.tight.buffer;
+
+    /*
+     * If client is big-endian, color samples begin from the second
+     * byte (offset 1) of a 32-bit pixel value.
+     */
+    off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+
+    memset(stats, 0, sizeof (stats));
+
+    for (y = 0, x = 0; y < h && x < w;) {
+        for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH;
+             d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    stats[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixels++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    /* 95% smooth or more ... */
+    if (stats[0] * 33 / pixels >= 95) {
+        return 0;
+    }
+
+    errors = 0;
+    for (c = 1; c < 8; c++) {
+        errors += stats[c] * (c * c);
+        if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
+            return 0;
+        }
+    }
+    for (; c < 256; c++) {
+        errors += stats[c] * (c * c);
+    }
+    errors /= (pixels * 3 - stats[0]);
+
+    return errors;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                     \
+                                                                        \
+    static unsigned int                                                 \
+    tight_detect_smooth_image##bpp(VncState *vs, int w, int h) {        \
+        bool endian;                                                    \
+        uint##bpp##_t pix;                                              \
+        int max[3], shift[3];                                           \
+        int x, y, d, dx;                                                \
+        unsigned int c;                                                 \
+        unsigned int stats[256];                                        \
+        int pixels = 0;                                                 \
+        int sample, sum, left[3];                                       \
+        unsigned int errors;                                            \
+        unsigned char *buf = vs->tight.tight.buffer;                    \
+                                                                        \
+        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
+                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
+                                                                        \
+                                                                        \
+        max[0] = vs->clientds.pf.rmax;                                  \
+        max[1] = vs->clientds.pf.gmax;                                  \
+        max[2] = vs->clientds.pf.bmax;                                  \
+        shift[0] = vs->clientds.pf.rshift;                              \
+        shift[1] = vs->clientds.pf.gshift;                              \
+        shift[2] = vs->clientds.pf.bshift;                              \
+                                                                        \
+        memset(stats, 0, sizeof(stats));                                \
+                                                                        \
+        y = 0, x = 0;                                                   \
+        while (y < h && x < w) {                                        \
+            for (d = 0; d < h - y &&                                    \
+                     d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) {  \
+                pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d];              \
+                if (endian) {                                           \
+                    pix = bswap##bpp(pix);                              \
+                }                                                       \
+                for (c = 0; c < 3; c++) {                               \
+                    left[c] = (int)(pix >> shift[c] & max[c]);          \
+                }                                                       \
+                for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH;       \
+                     dx++) {                                            \
+                    pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx];       \
+                    if (endian) {                                       \
+                        pix = bswap##bpp(pix);                          \
+                    }                                                   \
+                    sum = 0;                                            \
+                    for (c = 0; c < 3; c++) {                           \
+                        sample = (int)(pix >> shift[c] & max[c]);       \
+                        sum += abs(sample - left[c]);                   \
+                        left[c] = sample;                               \
+                    }                                                   \
+                    if (sum > 255) {                                    \
+                        sum = 255;                                      \
+                    }                                                   \
+                    stats[sum]++;                                       \
+                    pixels++;                                           \
+                }                                                       \
+            }                                                           \
+            if (w > h) {                                                \
+                x += h;                                                 \
+                y = 0;                                                  \
+            } else {                                                    \
+                x = 0;                                                  \
+                y += w;                                                 \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        errors = 0;                                                     \
+        for (c = 1; c < 8; c++) {                                       \
+            errors += stats[c] * (c * c);                               \
+            if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {           \
+                return 0;                                               \
+            }                                                           \
+        }                                                               \
+        for (; c < 256; c++) {                                          \
+            errors += stats[c] * (c * c);                               \
+        }                                                               \
+        errors /= (pixels - stats[0]);                                  \
+                                                                        \
+        return errors;                                                  \
+    }
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+static int
+tight_detect_smooth_image(VncState *vs, int w, int h)
+{
+    unsigned int errors;
+    int compression = vs->tight.compression;
+    int quality = vs->tight.quality;
+
+    if (!vs->vd->lossy) {
+        return 0;
+    }
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+        vs->clientds.pf.bytes_per_pixel == 1 ||
+        w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
+        return 0;
+    }
+
+    if (vs->tight.quality != (uint8_t)-1) {
+        if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if (w * h < tight_conf[compression].gradient_min_rect_size) {
+            return 0;
+        }
+    }
+
+    if (vs->clientds.pf.bytes_per_pixel == 4) {
+        if (vs->tight.pixel24) {
+            errors = tight_detect_smooth_image24(vs, w, h);
+            if (vs->tight.quality != (uint8_t)-1) {
+                return (errors < tight_conf[quality].jpeg_threshold24);
+            }
+            return (errors < tight_conf[compression].gradient_threshold24);
+        } else {
+            errors = tight_detect_smooth_image32(vs, w, h);
+        }
+    } else {
+        errors = tight_detect_smooth_image16(vs, w, h);
+    }
+    if (quality != -1) {
+        return (errors < tight_conf[quality].jpeg_threshold);
+    }
+    return (errors < tight_conf[compression].gradient_threshold);
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
+                                                                        \
+    static int                                                          \
+    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
+                            int max, size_t count,                      \
+                            uint32_t *bg, uint32_t *fg,                 \
+                            VncPalette **palette) {                     \
+        uint##bpp##_t *data;                                            \
+        uint##bpp##_t c0, c1, ci;                                       \
+        int i, n0, n1;                                                  \
+                                                                        \
+        data = (uint##bpp##_t *)vs->tight.tight.buffer;                 \
+                                                                        \
+        c0 = data[0];                                                   \
+        i = 1;                                                          \
+        while (i < count && data[i] == c0)                              \
+            i++;                                                        \
+        if (i >= count) {                                               \
+            *bg = *fg = c0;                                             \
+            return 1;                                                   \
+        }                                                               \
+                                                                        \
+        if (max < 2) {                                                  \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        n0 = i;                                                         \
+        c1 = data[i];                                                   \
+        n1 = 0;                                                         \
+        for (i++; i < count; i++) {                                     \
+            ci = data[i];                                               \
+            if (ci == c0) {                                             \
+                n0++;                                                   \
+            } else if (ci == c1) {                                      \
+                n1++;                                                   \
+            } else                                                      \
+                break;                                                  \
+        }                                                               \
+        if (i >= count) {                                               \
+            if (n0 > n1) {                                              \
+                *bg = (uint32_t)c0;                                     \
+                *fg = (uint32_t)c1;                                     \
+            } else {                                                    \
+                *bg = (uint32_t)c1;                                     \
+                *fg = (uint32_t)c0;                                     \
+            }                                                           \
+            return 2;                                                   \
+        }                                                               \
+                                                                        \
+        if (max == 2) {                                                 \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        *palette = palette_new(max, bpp);                               \
+        palette_put(*palette, c0);                                      \
+        palette_put(*palette, c1);                                      \
+        palette_put(*palette, ci);                                      \
+                                                                        \
+        for (i++; i < count; i++) {                                     \
+            if (data[i] == ci) {                                        \
+                continue;                                               \
+            } else {                                                    \
+                ci = data[i];                                           \
+                if (!palette_put(*palette, (uint32_t)ci)) {             \
+                    return 0;                                           \
+                }                                                       \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        return palette_size(*palette);                                  \
+    }
+
+DEFINE_FILL_PALETTE_FUNCTION(8)
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+static int tight_fill_palette(VncState *vs, int x, int y,
+                              size_t count, uint32_t *bg, uint32_t *fg,
+                              VncPalette **palette)
+{
+    int max;
+
+    max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
+    if (max < 2 &&
+        count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
+        max = 2;
+    }
+    if (max >= 256) {
+        max = 256;
+    }
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+        return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
+    case 2:
+        return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
+    default:
+        max = 2;
+        return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
+    }
+    return 0;
+}
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
+                                                                        \
+    static void                                                         \
+    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
+                                   VncPalette *palette) {               \
+        uint##bpp##_t *src;                                             \
+        uint##bpp##_t rgb;                                              \
+        int i, rep;                                                     \
+        uint8_t idx;                                                    \
+                                                                        \
+        src = (uint##bpp##_t *) buf;                                    \
+                                                                        \
+        for (i = 0; i < count; i++) {                                   \
+                                                                        \
+            rgb = *src++;                                               \
+            rep = 0;                                                    \
+            while (i < count && *src == rgb) {                          \
+                rep++, src++, i++;                                      \
+            }                                                           \
+            idx = palette_idx(palette, rgb);                            \
+            /*                                                          \
+             * Should never happen, but don't break everything          \
+             * if it does, use the first color instead                  \
+             */                                                         \
+            if (idx == (uint8_t)-1) {                                   \
+                idx = 0;                                                \
+            }                                                           \
+            while (rep >= 0) {                                          \
+                *buf++ = idx;                                           \
+                rep--;                                                  \
+            }                                                           \
+        }                                                               \
+    }
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
+                                                                        \
+    static void                                                         \
+    tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h,             \
+                                uint##bpp##_t bg, uint##bpp##_t fg) {   \
+        uint##bpp##_t *ptr;                                             \
+        unsigned int value, mask;                                       \
+        int aligned_width;                                              \
+        int x, y, bg_bits;                                              \
+                                                                        \
+        ptr = (uint##bpp##_t *) buf;                                    \
+        aligned_width = w - w % 8;                                      \
+                                                                        \
+        for (y = 0; y < h; y++) {                                       \
+            for (x = 0; x < aligned_width; x += 8) {                    \
+                for (bg_bits = 0; bg_bits < 8; bg_bits++) {             \
+                    if (*ptr++ != bg) {                                 \
+                        break;                                          \
+                    }                                                   \
+                }                                                       \
+                if (bg_bits == 8) {                                     \
+                    *buf++ = 0;                                         \
+                    continue;                                           \
+                }                                                       \
+                mask = 0x80 >> bg_bits;                                 \
+                value = mask;                                           \
+                for (bg_bits++; bg_bits < 8; bg_bits++) {               \
+                    mask >>= 1;                                         \
+                    if (*ptr++ != bg) {                                 \
+                        value |= mask;                                  \
+                    }                                                   \
+                }                                                       \
+                *buf++ = (uint8_t)value;                                \
+            }                                                           \
+                                                                        \
+            mask = 0x80;                                                \
+            value = 0;                                                  \
+            if (x >= w) {                                               \
+                continue;                                               \
+            }                                                           \
+                                                                        \
+            for (; x < w; x++) {                                        \
+                if (*ptr++ != bg) {                                     \
+                    value |= mask;                                      \
+                }                                                       \
+                mask >>= 1;                                             \
+            }                                                           \
+            *buf++ = (uint8_t)value;                                    \
+        }                                                               \
+    }
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+{
+    uint32_t *buf32;
+    uint32_t pix32;
+    int shift[3];
+    int *prev;
+    int here[3], upper[3], left[3], upperleft[3];
+    int prediction;
+    int x, y, c;
+
+    buf32 = (uint32_t *)buf;
+    memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
+
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
+        shift[0] = vs->clientds.pf.rshift;
+        shift[1] = vs->clientds.pf.gshift;
+        shift[2] = vs->clientds.pf.bshift;
+    } else {
+        shift[0] = 24 - vs->clientds.pf.rshift;
+        shift[1] = 24 - vs->clientds.pf.gshift;
+        shift[2] = 24 - vs->clientds.pf.bshift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            upper[c] = 0;
+            here[c] = 0;
+        }
+        prev = (int *)vs->tight.gradient.buffer;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                upperleft[c] = upper[c];
+                left[c] = here[c];
+                upper[c] = *prev;
+                here[c] = (int)(pix32 >> shift[c] & 0xFF);
+                *prev++ = here[c];
+
+                prediction = left[c] + upper[c] - upperleft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(here[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                            \
+                                                                        \
+    static void                                                         \
+    tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf,        \
+                               int w, int h) {                          \
+        uint##bpp##_t pix, diff;                                        \
+        bool endian;                                                    \
+        int *prev;                                                      \
+        int max[3], shift[3];                                           \
+        int here[3], upper[3], left[3], upperleft[3];                   \
+        int prediction;                                                 \
+        int x, y, c;                                                    \
+                                                                        \
+        memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));     \
+                                                                        \
+        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
+                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
+                                                                        \
+        max[0] = vs->clientds.pf.rmax;                                  \
+        max[1] = vs->clientds.pf.gmax;                                  \
+        max[2] = vs->clientds.pf.bmax;                                  \
+        shift[0] = vs->clientds.pf.rshift;                              \
+        shift[1] = vs->clientds.pf.gshift;                              \
+        shift[2] = vs->clientds.pf.bshift;                              \
+                                                                        \
+        for (y = 0; y < h; y++) {                                       \
+            for (c = 0; c < 3; c++) {                                   \
+                upper[c] = 0;                                           \
+                here[c] = 0;                                            \
+            }                                                           \
+            prev = (int *)vs->tight.gradient.buffer;                    \
+            for (x = 0; x < w; x++) {                                   \
+                pix = *buf;                                             \
+                if (endian) {                                           \
+                    pix = bswap##bpp(pix);                              \
+                }                                                       \
+                diff = 0;                                               \
+                for (c = 0; c < 3; c++) {                               \
+                    upperleft[c] = upper[c];                            \
+                    left[c] = here[c];                                  \
+                    upper[c] = *prev;                                   \
+                    here[c] = (int)(pix >> shift[c] & max[c]);          \
+                    *prev++ = here[c];                                  \
+                                                                        \
+                    prediction = left[c] + upper[c] - upperleft[c];     \
+                    if (prediction < 0) {                               \
+                        prediction = 0;                                 \
+                    } else if (prediction > max[c]) {                   \
+                        prediction = max[c];                            \
+                    }                                                   \
+                    diff |= ((here[c] - prediction) & max[c])           \
+                        << shift[c];                                    \
+                }                                                       \
+                if (endian) {                                           \
+                    diff = bswap##bpp(diff);                            \
+                }                                                       \
+                *buf++ = diff;                                          \
+            }                                                           \
+        }                                                               \
+    }
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successful, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                \
+                                                                        \
+    static bool                                                         \
+    check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h,     \
+                          uint32_t* color, bool samecolor)              \
+    {                                                                   \
+        VncDisplay *vd = vs->vd;                                        \
+        uint##bpp##_t *fbptr;                                           \
+        uint##bpp##_t c;                                                \
+        int dx, dy;                                                     \
+                                                                        \
+        fbptr = (uint##bpp##_t *)                                       \
+            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
+             x * ds_get_bytes_per_pixel(vs->ds));                       \
+                                                                        \
+        c = *fbptr;                                                     \
+        if (samecolor && (uint32_t)c != *color) {                       \
+            return false;                                               \
+        }                                                               \
+                                                                        \
+        for (dy = 0; dy < h; dy++) {                                    \
+            for (dx = 0; dx < w; dx++) {                                \
+                if (c != fbptr[dx]) {                                   \
+                    return false;                                       \
+                }                                                       \
+            }                                                           \
+            fbptr = (uint##bpp##_t *)                                   \
+                ((uint8_t *)fbptr + ds_get_linesize(vs->ds));           \
+        }                                                               \
+                                                                        \
+        *color = (uint32_t)c;                                           \
+        return true;                                                    \
+    }
+
+DEFINE_CHECK_SOLID_FUNCTION(32)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(8)
+
+static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
+                             uint32_t* color, bool samecolor)
+{
+    VncDisplay *vd = vs->vd;
+
+    switch(vd->server->pf.bytes_per_pixel) {
+    case 4:
+        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
+    case 2:
+        return check_solid_tile16(vs, x, y, w, h, color, samecolor);
+    default:
+        return check_solid_tile8(vs, x, y, w, h, color, samecolor);
+    }
+}
+
+static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
+                                 uint32_t color, int *w_ptr, int *h_ptr)
+{
+    int dx, dy, dw, dh;
+    int w_prev;
+    int w_best = 0, h_best = 0;
+
+    w_prev = w;
+
+    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+
+        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
+        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
+
+        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
+            break;
+        }
+
+        for (dx = x + dw; dx < x + w_prev;) {
+            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
+
+            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
+                break;
+            }
+            dx += dw;
+        }
+
+        w_prev = dx - x;
+        if (w_prev * (dy + dh - y) > w_best * h_best) {
+            w_best = w_prev;
+            h_best = dy + dh - y;
+        }
+    }
+
+    *w_ptr = w_best;
+    *h_ptr = h_best;
+}
+
+static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
+                              uint32_t color, int *x_ptr, int *y_ptr,
+                              int *w_ptr, int *h_ptr)
+{
+    int cx, cy;
+
+    /* Try to extend the area upwards. */
+    for ( cy = *y_ptr - 1;
+          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
+          cy-- );
+    *h_ptr += *y_ptr - (cy + 1);
+    *y_ptr = cy + 1;
+
+    /* ... downwards. */
+    for ( cy = *y_ptr + *h_ptr;
+          cy < y + h &&
+              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
+          cy++ );
+    *h_ptr += cy - (*y_ptr + *h_ptr);
+
+    /* ... to the left. */
+    for ( cx = *x_ptr - 1;
+          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
+          cx-- );
+    *w_ptr += *x_ptr - (cx + 1);
+    *x_ptr = cx + 1;
+
+    /* ... to the right. */
+    for ( cx = *x_ptr + *w_ptr;
+          cx < x + w &&
+              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
+          cx++ );
+    *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+static int tight_init_stream(VncState *vs, int stream_id,
+                             int level, int strategy)
+{
+    z_streamp zstream = &vs->tight.stream[stream_id];
+
+    if (zstream->opaque == NULL) {
+        int err;
+
+        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
+        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, strategy);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        vs->tight.levels[stream_id] = level;
+        zstream->opaque = vs;
+    }
+
+    if (vs->tight.levels[stream_id] != level) {
+        if (deflateParams(zstream, level, strategy) != Z_OK) {
+            return -1;
+        }
+        vs->tight.levels[stream_id] = level;
+    }
+    return 0;
+}
+
+static void tight_send_compact_size(VncState *vs, size_t len)
+{
+    int lpc = 0;
+    int bytes = 0;
+    char buf[3] = {0, 0, 0};
+
+    buf[bytes++] = len & 0x7F;
+    if (len > 0x7F) {
+        buf[bytes-1] |= 0x80;
+        buf[bytes++] = (len >> 7) & 0x7F;
+        if (len > 0x3FFF) {
+            buf[bytes-1] |= 0x80;
+            buf[bytes++] = (len >> 14) & 0xFF;
+        }
+    }
+    for (lpc = 0; lpc < bytes; lpc++) {
+        vnc_write_u8(vs, buf[lpc]);
+    }
+}
+
+static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
+                               int level, int strategy)
+{
+    z_streamp zstream = &vs->tight.stream[stream_id];
+    int previous_out;
+
+    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
+        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
+        return bytes;
+    }
+
+    if (tight_init_stream(vs, stream_id, level, strategy)) {
+        return -1;
+    }
+
+    /* reserve memory in output buffer */
+    buffer_reserve(&vs->tight.zlib, bytes + 64);
+
+    /* set pointers */
+    zstream->next_in = vs->tight.tight.buffer;
+    zstream->avail_in = vs->tight.tight.offset;
+    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
+    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
+    previous_out = zstream->avail_out;
+    zstream->data_type = Z_BINARY;
+
+    /* start encoding */
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during tight compression\n");
+        return -1;
+    }
+
+    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
+    /* ...how much data has actually been produced by deflate() */
+    bytes = previous_out - zstream->avail_out;
+
+    tight_send_compact_size(vs, bytes);
+    vnc_write(vs, vs->tight.zlib.buffer, bytes);
+
+    buffer_reset(&vs->tight.zlib);
+
+    return bytes;
+}
+
+/*
+ * Subencoding implementations.
+ */
+static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
+{
+    uint32_t *buf32;
+    uint32_t pix;
+    int rshift, gshift, bshift;
+
+    buf32 = (uint32_t *)buf;
+
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
+        rshift = vs->clientds.pf.rshift;
+        gshift = vs->clientds.pf.gshift;
+        bshift = vs->clientds.pf.bshift;
+    } else {
+        rshift = 24 - vs->clientds.pf.rshift;
+        gshift = 24 - vs->clientds.pf.gshift;
+        bshift = 24 - vs->clientds.pf.bshift;
+    }
+
+    if (ret) {
+        *ret = count * 3;
+    }
+
+    while (count--) {
+        pix = *buf32++;
+        *buf++ = (char)(pix >> rshift);
+        *buf++ = (char)(pix >> gshift);
+        *buf++ = (char)(pix >> bshift);
+    }
+}
+
+static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
+{
+    int stream = 0;
+    ssize_t bytes;
+
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        return send_png_rect(vs, x, y, w, h, NULL);
+    }
+#endif
+
+    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
+
+    if (vs->tight.pixel24) {
+        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
+        bytes = 3;
+    } else {
+        bytes = vs->clientds.pf.bytes_per_pixel;
+    }
+
+    bytes = tight_compress_data(vs, stream, w * h * bytes,
+                                tight_conf[vs->tight.compression].raw_zlib_level,
+                                Z_DEFAULT_STRATEGY);
+
+    return (bytes >= 0);
+}
+
+static int send_solid_rect(VncState *vs)
+{
+    size_t bytes;
+
+    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
+
+    if (vs->tight.pixel24) {
+        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
+        bytes = 3;
+    } else {
+        bytes = vs->clientds.pf.bytes_per_pixel;
+    }
+
+    vnc_write(vs, vs->tight.tight.buffer, bytes);
+    return 1;
+}
+
+static int send_mono_rect(VncState *vs, int x, int y,
+                          int w, int h, uint32_t bg, uint32_t fg)
+{
+    ssize_t bytes;
+    int stream = 1;
+    int level = tight_conf[vs->tight.compression].mono_zlib_level;
+
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        int ret;
+        int bpp = vs->clientds.pf.bytes_per_pixel * 8;
+        VncPalette *palette = palette_new(2, bpp);
+
+        palette_put(palette, bg);
+        palette_put(palette, fg);
+        ret = send_png_rect(vs, x, y, w, h, palette);
+        palette_destroy(palette);
+        return ret;
+    }
+#endif
+
+    bytes = ((w + 7) / 8) * h;
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
+    vnc_write_u8(vs, 1);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+    {
+        uint32_t buf[2] = {bg, fg};
+        size_t ret = sizeof (buf);
+
+        if (vs->tight.pixel24) {
+            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
+        }
+        vnc_write(vs, buf, ret);
+
+        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
+        break;
+    }
+    case 2:
+        vnc_write(vs, &bg, 2);
+        vnc_write(vs, &fg, 2);
+        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
+        break;
+    default:
+        vnc_write_u8(vs, bg);
+        vnc_write_u8(vs, fg);
+        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
+        break;
+    }
+    vs->tight.tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
+    return (bytes >= 0);
+}
+
+struct palette_cb_priv {
+    VncState *vs;
+    uint8_t *header;
+#ifdef CONFIG_VNC_PNG
+    png_colorp png_palette;
+#endif
+};
+
+static void write_palette(int idx, uint32_t color, void *opaque)
+{
+    struct palette_cb_priv *priv = opaque;
+    VncState *vs = priv->vs;
+    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
+
+    if (bytes == 4) {
+        ((uint32_t*)priv->header)[idx] = color;
+    } else {
+        ((uint16_t*)priv->header)[idx] = color;
+    }
+}
+
+static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
+{
+    int stream = 3;
+    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
+    ssize_t bytes;
+
+    if (vs->clientds.pf.bytes_per_pixel == 1)
+        return send_full_color_rect(vs, x, y, w, h);
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
+
+    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
+
+    if (vs->tight.pixel24) {
+        tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
+        bytes = 3;
+    } else if (vs->clientds.pf.bytes_per_pixel == 4) {
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
+        bytes = 4;
+    } else {
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
+        bytes = 2;
+    }
+
+    buffer_reset(&vs->tight.gradient);
+
+    bytes = w * h * bytes;
+    vs->tight.tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes,
+                                level, Z_FILTERED);
+    return (bytes >= 0);
+}
+
+static int send_palette_rect(VncState *vs, int x, int y,
+                             int w, int h, VncPalette *palette)
+{
+    int stream = 2;
+    int level = tight_conf[vs->tight.compression].idx_zlib_level;
+    int colors;
+    ssize_t bytes;
+
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        return send_png_rect(vs, x, y, w, h, palette);
+    }
+#endif
+
+    colors = palette_size(palette);
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
+    vnc_write_u8(vs, colors - 1);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 4:
+    {
+        size_t old_offset, offset;
+        uint32_t header[palette_size(palette)];
+        struct palette_cb_priv priv = { vs, (uint8_t *)header };
+
+        old_offset = vs->output.offset;
+        palette_iter(palette, write_palette, &priv);
+        vnc_write(vs, header, sizeof(header));
+
+        if (vs->tight.pixel24) {
+            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
+            vs->output.offset = old_offset + offset;
+        }
+
+        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
+        break;
+    }
+    case 2:
+    {
+        uint16_t header[palette_size(palette)];
+        struct palette_cb_priv priv = { vs, (uint8_t *)header };
+
+        palette_iter(palette, write_palette, &priv);
+        vnc_write(vs, header, sizeof(header));
+        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
+        break;
+    }
+    default:
+        return -1; /* No palette for 8bits colors */
+        break;
+    }
+    bytes = w * h;
+    vs->tight.tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes,
+                                level, Z_DEFAULT_STRATEGY);
+    return (bytes >= 0);
+}
+
+#if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG)
+static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
+                              int count)
+{
+    VncDisplay *vd = vs->vd;
+    uint32_t *fbptr;
+    uint32_t pix;
+
+    fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) +
+                         x * ds_get_bytes_per_pixel(vs->ds));
+
+    while (count--) {
+        pix = *fbptr++;
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift);
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift);
+        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift);
+    }
+}
+
+#define DEFINE_RGB_GET_ROW_FUNCTION(bpp)                                \
+                                                                        \
+    static void                                                         \
+    rgb_prepare_row##bpp(VncState *vs, uint8_t *dst,                    \
+                         int x, int y, int count)                       \
+    {                                                                   \
+        VncDisplay *vd = vs->vd;                                        \
+        uint##bpp##_t *fbptr;                                           \
+        uint##bpp##_t pix;                                              \
+        int r, g, b;                                                    \
+                                                                        \
+        fbptr = (uint##bpp##_t *)                                       \
+            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
+             x * ds_get_bytes_per_pixel(vs->ds));                       \
+                                                                        \
+        while (count--) {                                               \
+            pix = *fbptr++;                                             \
+                                                                        \
+            r = (int)((pix >> vs->ds->surface->pf.rshift)               \
+                      & vs->ds->surface->pf.rmax);                      \
+            g = (int)((pix >> vs->ds->surface->pf.gshift)               \
+                      & vs->ds->surface->pf.gmax);                      \
+            b = (int)((pix >> vs->ds->surface->pf.bshift)               \
+                      & vs->ds->surface->pf.bmax);                      \
+                                                                        \
+            *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \
+                               / vs->ds->surface->pf.rmax);             \
+            *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \
+                               / vs->ds->surface->pf.gmax);             \
+            *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \
+                               / vs->ds->surface->pf.bmax);             \
+        }                                                               \
+    }
+
+DEFINE_RGB_GET_ROW_FUNCTION(16)
+DEFINE_RGB_GET_ROW_FUNCTION(32)
+
+static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
+                            int count)
+{
+    if (ds_get_bytes_per_pixel(vs->ds) == 4) {
+        if (vs->ds->surface->pf.rmax == 0xFF &&
+            vs->ds->surface->pf.gmax == 0xFF &&
+            vs->ds->surface->pf.bmax == 0xFF) {
+            rgb_prepare_row24(vs, dst, x, y, count);
+        } else {
+            rgb_prepare_row32(vs, dst, x, y, count);
+        }
+    } else {
+        rgb_prepare_row16(vs, dst, x, y, count);
+    }
+}
+#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */
+
+/*
+ * JPEG compression stuff.
+ */
+#ifdef CONFIG_VNC_JPEG
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+/* This is called once per encoding */
+static void jpeg_init_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight.jpeg;
+
+    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
+    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
+}
+
+/* This is called when we ran out of buffer (shouldn't happen!) */
+static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight.jpeg;
+
+    buffer->offset = buffer->capacity;
+    buffer_reserve(buffer, 2048);
+    jpeg_init_destination(cinfo);
+    return TRUE;
+}
+
+/* This is called when we are done processing data */
+static void jpeg_term_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight.jpeg;
+
+    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
+}
+
+static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
+{
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    struct jpeg_destination_mgr manager;
+    JSAMPROW row[1];
+    uint8_t *buf;
+    int dy;
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1)
+        return send_full_color_rect(vs, x, y, w, h);
+
+    buffer_reserve(&vs->tight.jpeg, 2048);
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.client_data = vs;
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, true);
+
+    manager.init_destination = jpeg_init_destination;
+    manager.empty_output_buffer = jpeg_empty_output_buffer;
+    manager.term_destination = jpeg_term_destination;
+    cinfo.dest = &manager;
+
+    jpeg_start_compress(&cinfo, true);
+
+    buf = qemu_malloc(w * 3);
+    row[0] = buf;
+    for (dy = 0; dy < h; dy++) {
+        rgb_prepare_row(vs, buf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, row, 1);
+    }
+    qemu_free(buf);
+
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
+
+    tight_send_compact_size(vs, vs->tight.jpeg.offset);
+    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
+    buffer_reset(&vs->tight.jpeg);
+
+    return 1;
+}
+#endif /* CONFIG_VNC_JPEG */
+
+/*
+ * PNG compression stuff.
+ */
+#ifdef CONFIG_VNC_PNG
+static void write_png_palette(int idx, uint32_t pix, void *opaque)
+{
+    struct palette_cb_priv *priv = opaque;
+    VncState *vs = priv->vs;
+    png_colorp color = &priv->png_palette[idx];
+
+    if (vs->tight.pixel24)
+    {
+        color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
+        color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
+        color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
+    }
+    else
+    {
+        int red, green, blue;
+
+        red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
+        green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
+        blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
+        color->red = ((red * 255 + vs->clientds.pf.rmax / 2) /
+                      vs->clientds.pf.rmax);
+        color->green = ((green * 255 + vs->clientds.pf.gmax / 2) /
+                        vs->clientds.pf.gmax);
+        color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) /
+                       vs->clientds.pf.bmax);
+    }
+}
+
+static void png_write_data(png_structp png_ptr, png_bytep data,
+                           png_size_t length)
+{
+    VncState *vs = png_get_io_ptr(png_ptr);
+
+    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
+    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
+
+    vs->tight.png.offset += length;
+}
+
+static void png_flush_data(png_structp png_ptr)
+{
+}
+
+static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
+{
+    return qemu_malloc(size);
+}
+
+static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
+{
+    qemu_free(ptr);
+}
+
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+                         VncPalette *palette)
+{
+    png_byte color_type;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_colorp png_palette = NULL;
+    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
+    int filters = tight_png_conf[vs->tight.compression].png_filters;
+    uint8_t *buf;
+    int dy;
+
+    png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
+                                        NULL, vnc_png_malloc, vnc_png_free);
+
+    if (png_ptr == NULL)
+        return -1;
+
+    info_ptr = png_create_info_struct(png_ptr);
+
+    if (info_ptr == NULL) {
+        png_destroy_write_struct(&png_ptr, NULL);
+        return -1;
+    }
+
+    png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
+    png_set_compression_level(png_ptr, level);
+    png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
+
+    if (palette) {
+        color_type = PNG_COLOR_TYPE_PALETTE;
+    } else {
+        color_type = PNG_COLOR_TYPE_RGB;
+    }
+
+    png_set_IHDR(png_ptr, info_ptr, w, h,
+                 8, color_type, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        struct palette_cb_priv priv;
+
+        png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
+                                 palette_size(palette));
+
+        priv.vs = vs;
+        priv.png_palette = png_palette;
+        palette_iter(palette, write_png_palette, &priv);
+
+        png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
+
+        if (vs->clientds.pf.bytes_per_pixel == 4) {
+            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
+        } else {
+            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
+        }
+    }
+
+    png_write_info(png_ptr, info_ptr);
+
+    buffer_reserve(&vs->tight.png, 2048);
+    buf = qemu_malloc(w * 3);
+    for (dy = 0; dy < h; dy++)
+    {
+        if (color_type == PNG_COLOR_TYPE_PALETTE) {
+            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
+        } else {
+            rgb_prepare_row(vs, buf, x, y + dy, w);
+        }
+        png_write_row(png_ptr, buf);
+    }
+    qemu_free(buf);
+
+    png_write_end(png_ptr, NULL);
+
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        png_free(png_ptr, png_palette);
+    }
+
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
+
+    tight_send_compact_size(vs, vs->tight.png.offset);
+    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
+    buffer_reset(&vs->tight.png);
+    return 1;
+}
+#endif /* CONFIG_VNC_PNG */
+
+static void vnc_tight_start(VncState *vs)
+{
+    buffer_reset(&vs->tight.tight);
+
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->tight.tmp = vs->output;
+    vs->output = vs->tight.tight;
+}
+
+static void vnc_tight_stop(VncState *vs)
+{
+    // switch back to normal output/zlib buffers
+    vs->tight.tight = vs->output;
+    vs->output = vs->tight.tmp;
+}
+
+static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
+                                int bg, int fg, int colors, VncPalette *palette)
+{
+    int ret;
+
+    if (colors == 0) {
+        if (tight_detect_smooth_image(vs, w, h)) {
+            ret = send_gradient_rect(vs, x, y, w, h);
+        } else {
+            ret = send_full_color_rect(vs, x, y, w, h);
+        }
+    } else if (colors == 1) {
+        ret = send_solid_rect(vs);
+    } else if (colors == 2) {
+        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+    } else if (colors <= 256) {
+        ret = send_palette_rect(vs, x, y, w, h, palette);
+    } else {
+        ret = 0;
+    }
+    return ret;
+}
+
+#ifdef CONFIG_VNC_JPEG
+static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
+                              int bg, int fg, int colors,
+                              VncPalette *palette, bool force)
+{
+    int ret;
+
+    if (colors == 0) {
+        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
+                      tight_detect_smooth_image(vs, w, h))) {
+            int quality = tight_conf[vs->tight.quality].jpeg_quality;
+
+            ret = send_jpeg_rect(vs, x, y, w, h, quality);
+        } else {
+            ret = send_full_color_rect(vs, x, y, w, h);
+        }
+    } else if (colors == 1) {
+        ret = send_solid_rect(vs);
+    } else if (colors == 2) {
+        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+    } else if (colors <= 256) {
+        if (force || (colors > 96 &&
+                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
+                      tight_detect_smooth_image(vs, w, h))) {
+            int quality = tight_conf[vs->tight.quality].jpeg_quality;
+
+            ret = send_jpeg_rect(vs, x, y, w, h, quality);
+        } else {
+            ret = send_palette_rect(vs, x, y, w, h, palette);
+        }
+    } else {
+        ret = 0;
+    }
+    return ret;
+}
+#endif
+
+static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+{
+    VncPalette *palette = NULL;
+    uint32_t bg = 0, fg = 0;
+    int colors;
+    int ret = 0;
+#ifdef CONFIG_VNC_JPEG
+    bool force_jpeg = false;
+    bool allow_jpeg = true;
+#endif
+
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+
+    vnc_tight_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    vnc_tight_stop(vs);
+
+#ifdef CONFIG_VNC_JPEG
+    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
+        double freq = vnc_update_freq(vs, x, y, w, h);
+
+        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
+            allow_jpeg = false;
+        }
+        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+            force_jpeg = true;
+            vnc_sent_lossy_rect(vs, x, y, w, h);
+        }
+    }
+#endif
+
+    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
+
+#ifdef CONFIG_VNC_JPEG
+    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
+        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette,
+                                 force_jpeg);
+    } else {
+        ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
+    }
+#else
+    ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
+#endif
+
+    palette_destroy(palette);
+    return ret;
+}
+
+static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
+{
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+
+    vnc_tight_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    vnc_tight_stop(vs);
+
+    return send_solid_rect(vs);
+}
+
+static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
+                            bool split)
+{
+    int max_size, max_width;
+    int max_sub_width, max_sub_height;
+    int dx, dy;
+    int rw, rh;
+    int n = 0;
+
+    max_size = tight_conf[vs->tight.compression].max_rect_size;
+    max_width = tight_conf[vs->tight.compression].max_rect_width;
+
+    if (split && (w > max_width || w * h > max_size)) {
+        max_sub_width = (w > max_width) ? max_width : w;
+        max_sub_height = max_size / max_sub_width;
+
+        for (dy = 0; dy < h; dy += max_sub_height) {
+            for (dx = 0; dx < w; dx += max_width) {
+                rw = MIN(max_sub_width, w - dx);
+                rh = MIN(max_sub_height, h - dy);
+                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
+            }
+        }
+    } else {
+        n += send_sub_rect(vs, x, y, w, h);
+    }
+
+    return n;
+}
+
+static int find_large_solid_color_rect(VncState *vs, int x, int y,
+                                       int w, int h, int max_rows)
+{
+    int dx, dy, dw, dh;
+    int n = 0;
+
+    /* Try to find large solid-color areas and send them separately. */
+
+    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+
+        /* If a rectangle becomes too large, send its upper part now. */
+
+        if (dy - y >= max_rows) {
+            n += send_rect_simple(vs, x, y, w, max_rows, true);
+            y += max_rows;
+            h -= max_rows;
+        }
+
+        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
+
+        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
+            uint32_t color_value;
+            int x_best, y_best, w_best, h_best;
+
+            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
+
+            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
+                continue ;
+            }
+
+            /* Get dimensions of solid-color area. */
+
+            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
+                                 color_value, &w_best, &h_best);
+
+            /* Make sure a solid rectangle is large enough
+               (or the whole rectangle is of the same color). */
+
+            if (w_best * h_best != w * h &&
+                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
+                continue;
+            }
+
+            /* Try to extend solid rectangle to maximum size. */
+
+            x_best = dx; y_best = dy;
+            extend_solid_area(vs, x, y, w, h, color_value,
+                              &x_best, &y_best, &w_best, &h_best);
+
+            /* Send rectangles at top and left to solid-color area. */
+
+            if (y_best != y) {
+                n += send_rect_simple(vs, x, y, w, y_best-y, true);
+            }
+            if (x_best != x) {
+                n += tight_send_framebuffer_update(vs, x, y_best,
+                                                   x_best-x, h_best);
+            }
+
+            /* Send solid-color rectangle. */
+            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
+
+            /* Send remaining rectangles (at right and bottom). */
+
+            if (x_best + w_best != x + w) {
+                n += tight_send_framebuffer_update(vs, x_best+w_best,
+                                                   y_best,
+                                                   w-(x_best-x)-w_best,
+                                                   h_best);
+            }
+            if (y_best + h_best != y + h) {
+                n += tight_send_framebuffer_update(vs, x, y_best+h_best,
+                                                   w, h-(y_best-y)-h_best);
+            }
+
+            /* Return after all recursive calls are done. */
+            return n;
+        }
+    }
+    return n + send_rect_simple(vs, x, y, w, h, true);
+}
+
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                         int w, int h)
+{
+    int max_rows;
+
+    if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
+        vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
+        vs->tight.pixel24 = true;
+    } else {
+        vs->tight.pixel24 = false;
+    }
+
+#ifdef CONFIG_VNC_JPEG
+    if (vs->tight.quality != (uint8_t)-1) {
+        double freq = vnc_update_freq(vs, x, y, w, h);
+
+        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+            return send_rect_simple(vs, x, y, w, h, false);
+        }
+    }
+#endif
+
+    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) {
+        return send_rect_simple(vs, x, y, w, h, true);
+    }
+
+    /* Calculate maximum number of rows in one non-solid rectangle. */
+
+    max_rows = tight_conf[vs->tight.compression].max_rect_size;
+    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
+
+    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
+}
+
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                      int w, int h)
+{
+    vs->tight.type = VNC_ENCODING_TIGHT;
+    return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+                                          int w, int h)
+{
+    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
+    return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
+void vnc_tight_clear(VncState *vs)
+{
+    int i;
+    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
+        if (vs->tight.stream[i].opaque) {
+            deflateEnd(&vs->tight.stream[i]);
+        }
+    }
+
+    buffer_free(&vs->tight.tight);
+    buffer_free(&vs->tight.zlib);
+    buffer_free(&vs->tight.gradient);
+#ifdef CONFIG_VNC_JPEG
+    buffer_free(&vs->tight.jpeg);
+#endif
+#ifdef CONFIG_VNC_PNG
+    buffer_free(&vs->tight.png);
+#endif
+}
diff --git a/qemu-0.15.x/ui/vnc-enc-tight.h b/qemu-0.15.x/ui/vnc-enc-tight.h
new file mode 100644
index 0000000..a3add78
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-tight.h
@@ -0,0 +1,183 @@
+/*
+ * QEMU VNC display driver: tight encoding
+ *
+ * From libvncserver/rfb/rfbproto.h
+ * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
+ * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *
+ * 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 VNC_ENCODING_TIGHT_H
+#define VNC_ENCODING_TIGHT_H
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.
+ *
+ *-- The first byte of each Tight-encoded rectangle is a "compression control
+ *   byte". Its format is as follows (bit 0 is the least significant one):
+ *
+ *   bit 0:    if 1, then compression stream 0 should be reset;
+ *   bit 1:    if 1, then compression stream 1 should be reset;
+ *   bit 2:    if 1, then compression stream 2 should be reset;
+ *   bit 3:    if 1, then compression stream 3 should be reset;
+ *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
+ *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 1010 (0x0A), then the compression type is "png",
+ *             if 0xxx, then the compression type is "basic",
+ *             values greater than 1010 are not valid.
+ *
+ * If the compression type is "basic", then bits 6..4 of the
+ * compression control byte (those xxx in 0xxx) specify the following:
+ *
+ *   bits 5-4:  decimal representation is the index of a particular zlib
+ *              stream which should be used for decompressing the data;
+ *   bit 6:     if 1, then a "filter id" byte is following this byte.
+ *
+ *-- The data that follows after the compression control byte described
+ * above depends on the compression type ("fill", "jpeg", "png" or "basic").
+ *
+ *-- If the compression type is "fill", then the only pixel value follows, in
+ * client pixel format (see NOTE 1). This value applies to all pixels of the
+ * rectangle.
+ *
+ *-- If the compression type is "jpeg" or "png", the following data stream
+ * looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     JPEG or PNG image.
+ *
+ * Data size is compactly represented in one, two or three bytes, according
+ * to the following scheme:
+ *
+ *  0xxxxxxx                    (for values 0..127)
+ *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
+ *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
+ *
+ * Here each character denotes one bit, xxxxxxx are the least significant 7
+ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
+ * most significant 8 bits (bits 14-21). For example, decimal value 10000
+ * should be represented as two bytes: binary 10010000 01001110, or
+ * hexadecimal 90 4E.
+ *
+ *-- If the compression type is "basic" and bit 6 of the compression control
+ * byte was set to 1, then the next (second) byte specifies "filter id" which
+ * tells the decoder what filter type was used by the encoder to pre-process
+ * pixel data before the compression. The "filter id" byte can be one of the
+ * following:
+ *
+ *   0:  no filter ("copy" filter);
+ *   1:  "palette" filter;
+ *   2:  "gradient" filter.
+ *
+ *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
+ * byte), or if the filter id is 0, then raw pixel values in the client
+ * format (see NOTE 1) will be compressed. See below details on the
+ * compression.
+ *
+ *-- The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better.
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ *   if (P[i,j] < 0) then P[i,j] := 0;
+ *   if (P[i,j] > MAX) then P[i,j] := MAX;
+ *   D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.
+ *
+ *-- The "palette" filter converts true-color pixel data to indexed colors
+ * and a palette which can consist of 2..256 colors. If the number of colors
+ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
+ * encode one pixel. 1-bit encoding is performed such way that the most
+ * significant bits correspond to the leftmost pixels, and each raw of pixels
+ * is aligned to the byte boundary. When "palette" filter is used, the
+ * palette is sent before the pixel data. The palette begins with an unsigned
+ * byte which value is the number of colors in the palette minus 1 (i.e. 1
+ * means 2 colors, 255 means 256 colors in the palette). Then follows the
+ * palette itself which consist of pixel values in client pixel format (see
+ * NOTE 1).
+ *
+ *-- The pixel data is compressed using the zlib library. But if the data
+ * size after applying the filter but before the compression is less then 12,
+ * then the data is sent as is, uncompressed. Four separate zlib streams
+ * (0..3) can be used and the decoder should read the actual stream id from
+ * the compression control byte (see NOTE 2).
+ *
+ * If the compression is not used, then the pixel data is sent as is,
+ * otherwise the data stream looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     zlib-compressed data.
+ *
+ * Data size is compactly represented in one, two or three bytes, just like
+ * in the "jpeg" compression method (see above).
+ *
+ *-- NOTE 1. If the color depth is 24, and all three color components are
+ * 8-bit wide, then one pixel in Tight encoding is always represented by
+ * three bytes, where the first byte is red component, the second byte is
+ * green component, and the third byte is blue component of the pixel color
+ * value. This applies to colors in palettes as well.
+ *
+ *-- NOTE 2. The decoder must reset compression streams' states before
+ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
+ * byte are set to 1. Note that the decoder must reset zlib streams even if
+ * the compression type is "fill", "jpeg" or "png".
+ *
+ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
+ * when bits-per-pixel value is either 16 or 32, not 8.
+ *
+ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
+ * pixels. If a rectangle is wider, it must be split into several rectangles
+ * and each one should be encoded separately.
+ *
+ */
+
+#define VNC_TIGHT_EXPLICIT_FILTER       0x04
+#define VNC_TIGHT_FILL                  0x08
+#define VNC_TIGHT_JPEG                  0x09
+#define VNC_TIGHT_PNG                   0x0A
+#define VNC_TIGHT_MAX_SUBENCODING       0x0A
+
+/* Filters to improve compression efficiency */
+#define VNC_TIGHT_FILTER_COPY             0x00
+#define VNC_TIGHT_FILTER_PALETTE          0x01
+#define VNC_TIGHT_FILTER_GRADIENT         0x02
+
+/* Note: The following constant should not be changed. */
+#define VNC_TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define VNC_TIGHT_MIN_SPLIT_RECT_SIZE     4096
+#define VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE  2048
+#define VNC_TIGHT_MAX_SPLIT_TILE_SIZE       16
+
+#define VNC_TIGHT_JPEG_MIN_RECT_SIZE      4096
+#define VNC_TIGHT_DETECT_SUBROW_WIDTH        7
+#define VNC_TIGHT_DETECT_MIN_WIDTH           8
+#define VNC_TIGHT_DETECT_MIN_HEIGHT          8
+
+#endif /* VNC_ENCODING_TIGHT_H */
diff --git a/qemu-0.15.x/ui/vnc-enc-zlib.c b/qemu-0.15.x/ui/vnc-enc-zlib.c
new file mode 100644
index 0000000..e32e4cd
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zlib.c
@@ -0,0 +1,152 @@
+/*
+ * QEMU VNC display driver: zlib encoding
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "vnc.h"
+
+#define ZALLOC_ALIGNMENT 16
+
+void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = qemu_mallocz(size);
+
+    return (p);
+}
+
+void vnc_zlib_zfree(void *x, void *addr)
+{
+    qemu_free(addr);
+}
+
+static void vnc_zlib_start(VncState *vs)
+{
+    buffer_reset(&vs->zlib.zlib);
+
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->zlib.tmp = vs->output;
+    vs->output = vs->zlib.zlib;
+}
+
+static int vnc_zlib_stop(VncState *vs)
+{
+    z_streamp zstream = &vs->zlib.stream;
+    int previous_out;
+
+    // switch back to normal output/zlib buffers
+    vs->zlib.zlib = vs->output;
+    vs->output = vs->zlib.tmp;
+
+    // compress the zlib buffer
+
+    // initialize the stream
+    // XXX need one stream per session
+    if (zstream->opaque != vs) {
+        int err;
+
+        VNC_DEBUG("VNC: initializing zlib stream\n");
+        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        vs->zlib.level = vs->tight.compression;
+        zstream->opaque = vs;
+    }
+
+    if (vs->tight.compression != vs->zlib.level) {
+        if (deflateParams(zstream, vs->tight.compression,
+                          Z_DEFAULT_STRATEGY) != Z_OK) {
+            return -1;
+        }
+        vs->zlib.level = vs->tight.compression;
+    }
+
+    // reserve memory in output buffer
+    buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64);
+
+    // set pointers
+    zstream->next_in = vs->zlib.zlib.buffer;
+    zstream->avail_in = vs->zlib.zlib.offset;
+    zstream->next_out = vs->output.buffer + vs->output.offset;
+    zstream->avail_out = vs->output.capacity - vs->output.offset;
+    previous_out = zstream->avail_out;
+    zstream->data_type = Z_BINARY;
+
+    // start encoding
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zlib compression\n");
+        return -1;
+    }
+
+    vs->output.offset = vs->output.capacity - zstream->avail_out;
+    return previous_out - zstream->avail_out;
+}
+
+int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int old_offset, new_offset, bytes_written;
+
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
+
+    // remember where we put in the follow-up size
+    old_offset = vs->output.offset;
+    vnc_write_s32(vs, 0);
+
+    // compress the stream
+    vnc_zlib_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    bytes_written = vnc_zlib_stop(vs);
+
+    if (bytes_written == -1)
+        return 0;
+
+    // hack in the size
+    new_offset = vs->output.offset;
+    vs->output.offset = old_offset;
+    vnc_write_u32(vs, bytes_written);
+    vs->output.offset = new_offset;
+
+    return 1;
+}
+
+void vnc_zlib_clear(VncState *vs)
+{
+    if (vs->zlib.stream.opaque) {
+        deflateEnd(&vs->zlib.stream);
+    }
+    buffer_free(&vs->zlib.zlib);
+}
diff --git a/qemu-0.15.x/ui/vnc-enc-zrle-template.c b/qemu-0.15.x/ui/vnc-enc-zrle-template.c
new file mode 100644
index 0000000..70ae624
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zrle-template.c
@@ -0,0 +1,263 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrleencodetemplate.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel.
+ *
+ * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+ * bigger than the largest tile of pixel data, since the ZRLE encoding
+ * algorithm writes to the position one past the end of the pixel data.
+ */
+
+
+#include <assert.h>
+
+#undef ZRLE_ENDIAN_SUFFIX
+
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+#define ZRLE_ENDIAN_SUFFIX le
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+#define ZRLE_ENDIAN_SUFFIX be
+#else
+#define ZRLE_ENDIAN_SUFFIX ne
+#endif
+
+#ifndef ZRLE_CONCAT
+#define ZRLE_CONCAT_I(a, b)    a##b
+#define ZRLE_CONCAT2(a, b)     ZRLE_CONCAT_I(a, b)
+#define ZRLE_CONCAT3(a, b, c)  ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c))
+#endif
+
+#ifdef ZRLE_COMPACT_PIXEL
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    ZRLE_COMPACT_PIXEL
+#define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
+#define ZRLE_BPP_OUT         24
+#elif ZRLE_BPP == 15
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    16
+#define ZRLE_PIXEL           uint16_t
+#define ZRLE_BPP_OUT         16
+#else
+#define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+#define ZRLE_WRITE_SUFFIX    ZRLE_BPP
+#define ZRLE_BPP_OUT         ZRLE_BPP
+#define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
+#endif
+
+#define ZRLE_WRITE_PIXEL     ZRLE_CONCAT2(zrle_write_u,       ZRLE_WRITE_SUFFIX)
+#define ZRLE_ENCODE          ZRLE_CONCAT2(zrle_encode_,      ZRLE_ENCODE_SUFFIX)
+#define ZRLE_ENCODE_TILE     ZRLE_CONCAT2(zrle_encode_tile,  ZRLE_ENCODE_SUFFIX)
+#define ZRLE_WRITE_PALETTE   ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
+
+static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
+                             int zywrle_level);
+
+#if ZRLE_BPP != 8
+#include "vnc-enc-zywrle-template.c"
+#endif
+
+
+static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
+                        int zywrle_level)
+{
+    int ty;
+
+    for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) {
+
+        int tx, th;
+
+        th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty);
+
+        for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) {
+            int tw;
+            ZRLE_PIXEL *buf;
+
+            tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx);
+
+            buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP);
+            ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level);
+        }
+    }
+}
+
+static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
+                             int zywrle_level)
+{
+    VncPalette *palette = &vs->zrle.palette;
+
+    int runs = 0;
+    int single_pixels = 0;
+
+    bool use_rle;
+    bool use_palette;
+
+    int i;
+
+    ZRLE_PIXEL *ptr = data;
+    ZRLE_PIXEL *end = ptr + h * w;
+    *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+    /* Real limit is 127 but we wan't a way to know if there is more than 127 */
+    palette_init(palette, 256, ZRLE_BPP);
+
+    while (ptr < end) {
+        ZRLE_PIXEL pix = *ptr;
+        if (*++ptr != pix) { /* FIXME */
+            single_pixels++;
+        } else {
+            while (*++ptr == pix) ;
+            runs++;
+        }
+        palette_put(palette, pix);
+    }
+
+    /* Solid tile is a special case */
+
+    if (palette_size(palette) == 1) {
+        bool found;
+
+        vnc_write_u8(vs, 1);
+        ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found));
+        return;
+    }
+
+    zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT,
+                            runs, single_pixels, zywrle_level,
+                            &use_rle, &use_palette);
+
+    if (!use_palette) {
+        vnc_write_u8(vs, (use_rle ? 128 : 0));
+    } else {
+        uint32_t colors[VNC_PALETTE_MAX_SIZE];
+        size_t size = palette_size(palette);
+
+        vnc_write_u8(vs, (use_rle ? 128 : 0) | size);
+        palette_fill(palette, colors);
+
+        for (i = 0; i < size; i++) {
+            ZRLE_WRITE_PIXEL(vs, colors[i]);
+        }
+    }
+
+    if (use_rle) {
+        ZRLE_PIXEL *ptr = data;
+        ZRLE_PIXEL *end = ptr + w * h;
+        ZRLE_PIXEL *run_start;
+        ZRLE_PIXEL pix;
+
+        while (ptr < end) {
+            int len;
+            int index = 0;
+
+            run_start = ptr;
+            pix = *ptr++;
+
+            while (*ptr == pix && ptr < end) {
+                ptr++;
+            }
+
+            len = ptr - run_start;
+
+            if (use_palette)
+                index = palette_idx(palette, pix);
+
+            if (len <= 2 && use_palette) {
+                if (len == 2) {
+                    vnc_write_u8(vs, index);
+                }
+                vnc_write_u8(vs, index);
+                continue;
+            }
+            if (use_palette) {
+                vnc_write_u8(vs, index | 128);
+            } else {
+                ZRLE_WRITE_PIXEL(vs, pix);
+            }
+
+            len -= 1;
+
+            while (len >= 255) {
+                vnc_write_u8(vs, 255);
+                len -= 255;
+            }
+
+            vnc_write_u8(vs, len);
+        }
+    } else if (use_palette) { /* no RLE */
+        int bppp;
+        ZRLE_PIXEL *ptr = data;
+
+        /* packed pixels */
+
+        assert (palette_size(palette) < 17);
+
+        bppp = bits_per_packed_pixel[palette_size(palette)-1];
+
+        for (i = 0; i < h; i++) {
+            uint8_t nbits = 0;
+            uint8_t byte = 0;
+
+            ZRLE_PIXEL *eol = ptr + w;
+
+            while (ptr < eol) {
+                ZRLE_PIXEL pix = *ptr++;
+                uint8_t index = palette_idx(palette, pix);
+
+                byte = (byte << bppp) | index;
+                nbits += bppp;
+                if (nbits >= 8) {
+                    vnc_write_u8(vs, byte);
+                    nbits = 0;
+                }
+            }
+            if (nbits > 0) {
+                byte <<= 8 - nbits;
+                vnc_write_u8(vs, byte);
+            }
+        }
+    } else {
+
+        /* raw */
+
+#if ZRLE_BPP != 8
+        if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
+            ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf);
+            ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
+        }
+        else
+#endif
+        {
+#ifdef ZRLE_COMPACT_PIXEL
+            ZRLE_PIXEL *ptr;
+
+            for (ptr = data; ptr < data + w * h; ptr++) {
+                ZRLE_WRITE_PIXEL(vs, *ptr);
+            }
+#else
+            vnc_write(vs, data, w * h * (ZRLE_BPP / 8));
+#endif
+        }
+    }
+}
+
+#undef ZRLE_PIXEL
+#undef ZRLE_WRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef ZYWRLE_ENCODE_TILE
+#undef ZRLE_BPP_OUT
+#undef ZRLE_WRITE_SUFFIX
+#undef ZRLE_ENCODE_SUFFIX
diff --git a/qemu-0.15.x/ui/vnc-enc-zrle.c b/qemu-0.15.x/ui/vnc-enc-zrle.c
new file mode 100644
index 0000000..917d384
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zrle.c
@@ -0,0 +1,366 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrle.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 "vnc.h"
+#include "vnc-enc-zrle.h"
+
+static const int bits_per_packed_pixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+
+static void vnc_zrle_start(VncState *vs)
+{
+    buffer_reset(&vs->zrle.zrle);
+
+    /* make the output buffer be the zlib buffer, so we can compress it later */
+    vs->zrle.tmp = vs->output;
+    vs->output = vs->zrle.zrle;
+}
+
+static void vnc_zrle_stop(VncState *vs)
+{
+    /* switch back to normal output/zlib buffers */
+    vs->zrle.zrle = vs->output;
+    vs->output = vs->zrle.tmp;
+}
+
+static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
+                             int bpp)
+{
+    Buffer tmp;
+
+    buffer_reset(&vs->zrle.fb);
+    buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
+
+    tmp = vs->output;
+    vs->output = vs->zrle.fb;
+
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+
+    vs->zrle.fb = vs->output;
+    vs->output = tmp;
+    return vs->zrle.fb.buffer;
+}
+
+static int zrle_compress_data(VncState *vs, int level)
+{
+    z_streamp zstream = &vs->zrle.stream;
+
+    buffer_reset(&vs->zrle.zlib);
+
+    if (zstream->opaque != vs) {
+        int err;
+
+        zstream->zalloc = vnc_zlib_zalloc;
+        zstream->zfree = vnc_zlib_zfree;
+
+        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        zstream->opaque = vs;
+    }
+
+    /* reserve memory in output buffer */
+    buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
+
+    /* set pointers */
+    zstream->next_in = vs->zrle.zrle.buffer;
+    zstream->avail_in = vs->zrle.zrle.offset;
+    zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
+    zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
+    zstream->data_type = Z_BINARY;
+
+    /* start encoding */
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zrle compression\n");
+        return -1;
+    }
+
+    vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
+    return vs->zrle.zlib.offset;
+}
+
+/* Try to work out whether to use RLE and/or a palette.  We do this by
+ * estimating the number of bytes which will be generated and picking the
+ * method which results in the fewest bytes.  Of course this may not result
+ * in the fewest bytes after compression... */
+static void zrle_choose_palette_rle(VncState *vs, int w, int h,
+                                    VncPalette *palette, int bpp_out,
+                                    int runs, int single_pixels,
+                                    int zywrle_level,
+                                    bool *use_rle, bool *use_palette)
+{
+    size_t estimated_bytes;
+    size_t plain_rle_bytes;
+
+    *use_palette = *use_rle = false;
+
+    estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */
+
+    if (bpp_out != 8) {
+        if (zywrle_level > 0 && !(zywrle_level & 0x80))
+            estimated_bytes >>= zywrle_level;
+    }
+
+    plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels);
+
+    if (plain_rle_bytes < estimated_bytes) {
+        *use_rle = true;
+        estimated_bytes = plain_rle_bytes;
+    }
+
+    if (palette_size(palette) < 128) {
+        int palette_rle_bytes;
+
+        palette_rle_bytes = (bpp_out / 8) * palette_size(palette);
+        palette_rle_bytes += 2 * runs + single_pixels;
+
+        if (palette_rle_bytes < estimated_bytes) {
+            *use_rle = true;
+            *use_palette = true;
+            estimated_bytes = palette_rle_bytes;
+        }
+
+        if (palette_size(palette) < 17) {
+            int packed_bytes;
+
+            packed_bytes = (bpp_out / 8) * palette_size(palette);
+            packed_bytes += w * h *
+                bits_per_packed_pixel[palette_size(palette)-1] / 8;
+
+            if (packed_bytes < estimated_bytes) {
+                *use_rle = false;
+                *use_palette = true;
+                estimated_bytes = packed_bytes;
+            }
+        }
+    }
+}
+
+static void zrle_write_u32(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 4);
+}
+
+static void zrle_write_u24a(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 3);
+}
+
+static void zrle_write_u24b(VncState *vs, uint32_t value)
+{
+    vnc_write(vs, ((uint8_t *)&value) + 1, 3);
+}
+
+static void zrle_write_u16(VncState *vs, uint16_t value)
+{
+    vnc_write(vs, (uint8_t *)&value, 2);
+}
+
+static void zrle_write_u8(VncState *vs, uint8_t value)
+{
+    vnc_write_u8(vs, value);
+}
+
+#define ENDIAN_LITTLE 0
+#define ENDIAN_BIG    1
+#define ENDIAN_NO     2
+
+#define ZRLE_BPP 8
+#define ZYWRLE_ENDIAN ENDIAN_NO
+#include "vnc-enc-zrle-template.c"
+#undef ZRLE_BPP
+
+#define ZRLE_BPP 15
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_BPP
+#define ZRLE_BPP 16
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_BPP
+#define ZRLE_BPP 32
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#define ZRLE_COMPACT_PIXEL 24a
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+
+#undef ZRLE_COMPACT_PIXEL
+#define ZRLE_COMPACT_PIXEL 24b
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#include "vnc-enc-zrle-template.c"
+
+#undef ZYWRLE_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#include "vnc-enc-zrle-template.c"
+#undef ZRLE_COMPACT_PIXEL
+#undef ZRLE_BPP
+
+static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
+                                        int w, int h)
+{
+    bool be = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+    size_t bytes;
+    int zywrle_level;
+
+    if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
+        if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
+            || vs->tight.quality == 9) {
+            zywrle_level = 0;
+            vs->zrle.type = VNC_ENCODING_ZRLE;
+        } else if (vs->tight.quality < 3) {
+            zywrle_level = 3;
+        } else if (vs->tight.quality < 6) {
+            zywrle_level = 2;
+        } else {
+            zywrle_level = 1;
+        }
+    } else {
+        zywrle_level = 0;
+    }
+
+    vnc_zrle_start(vs);
+
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 1:
+        zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
+        break;
+
+    case 2:
+        if (vs->clientds.pf.gmax > 0x1F) {
+            if (be) {
+                zrle_encode_16be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_16le(vs, x, y, w, h, zywrle_level);
+            }
+        } else {
+            if (be) {
+                zrle_encode_15be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_15le(vs, x, y, w, h, zywrle_level);
+            }
+        }
+        break;
+
+    case 4:
+    {
+        bool fits_in_ls3bytes;
+        bool fits_in_ms3bytes;
+
+        fits_in_ls3bytes =
+            ((vs->clientds.pf.rmax << vs->clientds.pf.rshift) < (1 << 24) &&
+             (vs->clientds.pf.gmax << vs->clientds.pf.gshift) < (1 << 24) &&
+             (vs->clientds.pf.bmax << vs->clientds.pf.bshift) < (1 << 24));
+
+        fits_in_ms3bytes = (vs->clientds.pf.rshift > 7 &&
+                            vs->clientds.pf.gshift > 7 &&
+                            vs->clientds.pf.bshift > 7);
+
+        if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
+            if (be) {
+                zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
+          }
+        } else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
+            if (be) {
+                zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
+            }
+        } else {
+            if (be) {
+                zrle_encode_32be(vs, x, y, w, h, zywrle_level);
+            } else {
+                zrle_encode_32le(vs, x, y, w, h, zywrle_level);
+            }
+        }
+    }
+    break;
+    }
+
+    vnc_zrle_stop(vs);
+    bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
+    vnc_write_u32(vs, bytes);
+    vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
+    return 1;
+}
+
+int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    vs->zrle.type = VNC_ENCODING_ZRLE;
+    return zrle_send_framebuffer_update(vs, x, y, w, h);
+}
+
+int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    vs->zrle.type = VNC_ENCODING_ZYWRLE;
+    return zrle_send_framebuffer_update(vs, x, y, w, h);
+}
+
+void vnc_zrle_clear(VncState *vs)
+{
+    if (vs->zrle.stream.opaque) {
+        deflateEnd(&vs->zrle.stream);
+    }
+    buffer_free(&vs->zrle.zrle);
+    buffer_free(&vs->zrle.fb);
+    buffer_free(&vs->zrle.zlib);
+}
diff --git a/qemu-0.15.x/ui/vnc-enc-zrle.h b/qemu-0.15.x/ui/vnc-enc-zrle.h
new file mode 100644
index 0000000..6b18213
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zrle.h
@@ -0,0 +1,40 @@
+/*
+ * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
+ *
+ * From libvncserver/libvncserver/zrle.c
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 VNC_ENCODING_ZRLE_H
+#define VNC_ENCODING_ZRLE_H
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZRLE - encoding combining Zlib compression, tiling, palettisation and
+ * run-length encoding.
+ */
+
+#define VNC_ZRLE_TILE_WIDTH  64
+#define VNC_ZRLE_TILE_HEIGHT 64
+
+#endif
diff --git a/qemu-0.15.x/ui/vnc-enc-zywrle-template.c b/qemu-0.15.x/ui/vnc-enc-zywrle-template.c
new file mode 100644
index 0000000..4cde6e4
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zywrle-template.c
@@ -0,0 +1,170 @@
+
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *
+ *                                                                  *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- 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.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. 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 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 THE FOUNDATION
+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.
+ ********************************************************************/
+
+/* Change Log:
+     V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
+	                     (Thanks Johannes Schindelin, author of LibVNC
+						  Server/Client)
+     V0.01 : 2007/02/06 : Initial release
+*/
+
+/*
+[References]
+ PLHarr:
+   Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy,
+   "An Improved N-Bit to N-Bit Reversible Haar-Like Transform,"
+   Pacific Graphics 2004, October 2004, pp. 371-380.
+ EZW:
+   Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients,
+   IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
+*/
+
+
+/* Template Macro stuffs. */
+#undef ZYWRLE_ANALYZE
+#undef ZYWRLE_SYNTHESIZE
+
+#define ZYWRLE_SUFFIX     ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
+
+#define ZYWRLE_ANALYZE    ZRLE_CONCAT2(zywrle_analyze_,   ZYWRLE_SUFFIX)
+#define ZYWRLE_SYNTHESIZE ZRLE_CONCAT2(zywrle_synthesize_,ZYWRLE_SUFFIX)
+
+#define ZYWRLE_RGBYUV     ZRLE_CONCAT2(zywrle_rgbyuv_,    ZYWRLE_SUFFIX)
+#define ZYWRLE_YUVRGB     ZRLE_CONCAT2(zywrle_yuvrgb_,    ZYWRLE_SUFFIX)
+#define ZYWRLE_YMASK      ZRLE_CONCAT2(ZYWRLE_YMASK,      ZRLE_BPP)
+#define ZYWRLE_UVMASK     ZRLE_CONCAT2(ZYWRLE_UVMASK,     ZRLE_BPP)
+#define ZYWRLE_LOAD_PIXEL ZRLE_CONCAT2(ZYWRLE_LOAD_PIXEL, ZRLE_BPP)
+#define ZYWRLE_SAVE_PIXEL ZRLE_CONCAT2(ZYWRLE_SAVE_PIXEL, ZRLE_BPP)
+
+/* Packing/Unpacking pixel stuffs.
+   Endian conversion stuffs. */
+#undef S_0
+#undef S_1
+#undef L_0
+#undef L_1
+#undef L_2
+
+#if ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define S_0	1
+#  define S_1	0
+#  define L_0	3
+#  define L_1	2
+#  define L_2	1
+#else
+#  define S_0	0
+#  define S_1	1
+#  define L_0	0
+#  define L_1	1
+#  define L_2	2
+#endif
+
+#define ZYWRLE_QUANTIZE
+#include "vnc-enc-zywrle.h"
+
+#ifndef ZRLE_COMPACT_PIXEL
+static inline void ZYWRLE_RGBYUV(int *buf, ZRLE_PIXEL *data,
+                                 int width, int height, int scanline)
+{
+    int r, g, b;
+    int y, u, v;
+    int *line;
+    int *end;
+
+    end = buf + height * width;
+    while (buf < end) {
+        line = buf + width;
+        while (buf < line) {
+            ZYWRLE_LOAD_PIXEL(data, r, g, b);
+            ZYWRLE_RGBYUV_(r, g, b, y, u, v, ZYWRLE_YMASK, ZYWRLE_UVMASK);
+            ZYWRLE_SAVE_COEFF(buf, v, y, u);
+            buf++;
+            data++;
+        }
+        data += scanline - width;
+    }
+}
+
+static ZRLE_PIXEL *ZYWRLE_ANALYZE(ZRLE_PIXEL *dst, ZRLE_PIXEL *src,
+                                  int w, int h, int scanline, int level,
+                                  int *buf) {
+    int l;
+    int uw = w;
+    int uh = h;
+    int *top;
+    int *end;
+    int *line;
+    ZRLE_PIXEL *p;
+    int r, g, b;
+    int s;
+    int *ph;
+
+    zywrle_calc_size(&w, &h, level);
+
+    if (w == 0 || h == 0) {
+        return NULL;
+    }
+    uw -= w;
+    uh -= h;
+
+    p = dst;
+    ZYWRLE_LOAD_UNALIGN(src,*(ZRLE_PIXEL*)top = *p;);
+    ZYWRLE_RGBYUV(buf, src, w, h, scanline);
+    wavelet(buf, w, h, level);
+    for (l = 0; l < level; l++) {
+        ZYWRLE_PACK_COEFF(buf, dst, 3, w, h, scanline, l);
+        ZYWRLE_PACK_COEFF(buf, dst, 2, w, h, scanline, l);
+        ZYWRLE_PACK_COEFF(buf, dst, 1, w, h, scanline, l);
+        if (l == level - 1) {
+            ZYWRLE_PACK_COEFF(buf, dst, 0, w, h, scanline, l);
+        }
+    }
+    ZYWRLE_SAVE_UNALIGN(dst,*dst = *(ZRLE_PIXEL*)top;);
+    return dst;
+}
+#endif  /* ZRLE_COMPACT_PIXEL */
+
+#undef ZYWRLE_RGBYUV
+#undef ZYWRLE_YUVRGB
+#undef ZYWRLE_LOAD_PIXEL
+#undef ZYWRLE_SAVE_PIXEL
diff --git a/qemu-0.15.x/ui/vnc-enc-zywrle.h b/qemu-0.15.x/ui/vnc-enc-zywrle.h
new file mode 100644
index 0000000..ac5d27a
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-enc-zywrle.h
@@ -0,0 +1,659 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *
+ *                                                                  *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- 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.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. 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 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 THE FOUNDATION
+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 VNC_ENCODING_ZYWRLE_H
+#define VNC_ENCODING_ZYWRLE_H
+
+/* Tables for Coefficients filtering. */
+#ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static const unsigned int zywrle_param[3][3]={
+	{0x0000F000, 0x00000000, 0x00000000},
+	{0x0000C000, 0x00F0F0F0, 0x00000000},
+	{0x0000C000, 0x00C0C0C0, 0x00F0F0F0},
+/*	{0x0000FF00, 0x00000000, 0x00000000},
+	{0x0000FF00, 0x00FFFFFF, 0x00000000},
+	{0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */
+};
+#else
+/* Type B:Non liner quantization filter. */
+static const int8_t zywrle_conv[4][256]={
+{	/* bi=5, bo=5 r=0.0:PSNR=24.849 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=5 r=2.0:PSNR=74.031 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 32,
+	32, 32, 32, 32, 32, 32, 32, 32,
+	32, 32, 32, 32, 32, 32, 32, 32,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 56, 56, 56, 56, 56,
+	56, 56, 56, 56, 64, 64, 64, 64,
+	64, 64, 64, 64, 72, 72, 72, 72,
+	72, 72, 72, 72, 80, 80, 80, 80,
+	80, 80, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 96, 96,
+	96, 96, 96, 104, 104, 104, 104, 104,
+	104, 104, 104, 104, 104, 112, 112, 112,
+	112, 112, 112, 112, 112, 112, 120, 120,
+	120, 120, 120, 120, 120, 120, 120, 120,
+	0, -120, -120, -120, -120, -120, -120, -120,
+	-120, -120, -120, -112, -112, -112, -112, -112,
+	-112, -112, -112, -112, -104, -104, -104, -104,
+	-104, -104, -104, -104, -104, -104, -96, -96,
+	-96, -96, -96, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -80,
+	-80, -80, -80, -80, -80, -72, -72, -72,
+	-72, -72, -72, -72, -72, -64, -64, -64,
+	-64, -64, -64, -64, -64, -56, -56, -56,
+	-56, -56, -56, -56, -56, -56, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, -32, -32, -32, -32, -32, -32, -32,
+	-32, -32, -32, -32, -32, -32, -32, -32,
+	-32, -32, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=4 r=2.0:PSNR=64.441 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	64, 64, 64, 64, 64, 64, 64, 64,
+	64, 64, 64, 64, 64, 64, 64, 64,
+	80, 80, 80, 80, 80, 80, 80, 80,
+	80, 80, 80, 80, 80, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	104, 104, 104, 104, 104, 104, 104, 104,
+	104, 104, 104, 112, 112, 112, 112, 112,
+	112, 112, 112, 112, 120, 120, 120, 120,
+	120, 120, 120, 120, 120, 120, 120, 120,
+	0, -120, -120, -120, -120, -120, -120, -120,
+	-120, -120, -120, -120, -120, -112, -112, -112,
+	-112, -112, -112, -112, -112, -112, -104, -104,
+	-104, -104, -104, -104, -104, -104, -104, -104,
+	-104, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -80, -80, -80, -80,
+	-80, -80, -80, -80, -80, -80, -80, -80,
+	-80, -64, -64, -64, -64, -64, -64, -64,
+	-64, -64, -64, -64, -64, -64, -64, -64,
+	-64, -48, -48, -48, -48, -48, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=2 r=2.0:PSNR=43.175 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	0, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+}
+};
+
+static const int8_t *zywrle_param[3][3][3]={
+	{{zywrle_conv[0], zywrle_conv[2], zywrle_conv[0]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
+	{{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
+         {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]},
+         {zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
+	{{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
+         {zywrle_conv[2], zywrle_conv[2], zywrle_conv[2]},
+         {zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}},
+};
+#endif
+
+/*   Load/Save pixel stuffs. */
+#define ZYWRLE_YMASK15  0xFFFFFFF8
+#define ZYWRLE_UVMASK15 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL15(src, r, g, b)                               \
+    do {                                                                \
+	r = (((uint8_t*)src)[S_1]<< 1)& 0xF8;                           \
+	g = (((uint8_t*)src)[S_1]<< 6) | (((uint8_t*)src)[S_0]>> 2);    \
+        g &= 0xF8;                                                      \
+	b =  (((uint8_t*)src)[S_0]<< 3)& 0xF8;                          \
+    } while (0)
+
+#define ZYWRLE_SAVE_PIXEL15(dst, r, g, b)                               \
+    do {                                                                \
+	r &= 0xF8;                                                      \
+	g &= 0xF8;                                                      \
+	b &= 0xF8;                                                      \
+	((uint8_t*)dst)[S_1] = (uint8_t)((r >> 1)|(g >> 6));            \
+	((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 2))& 0xFF);    \
+    } while (0)
+
+#define ZYWRLE_YMASK16  0xFFFFFFFC
+#define ZYWRLE_UVMASK16 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL16(src, r, g, b)                               \
+    do {                                                                \
+	r = ((uint8_t*)src)[S_1] & 0xF8;                                \
+	g = (((uint8_t*)src)[S_1]<< 5) | (((uint8_t*)src)[S_0] >> 3);   \
+        g &= 0xFC;                                                      \
+	b = (((uint8_t*)src)[S_0]<< 3) & 0xF8;                          \
+    } while (0)
+
+#define ZYWRLE_SAVE_PIXEL16(dst, r, g,b)                                \
+    do {                                                                \
+	r &= 0xF8;                                                      \
+	g &= 0xFC;                                                      \
+	b &= 0xF8;                                                      \
+	((uint8_t*)dst)[S_1] = (uint8_t)(r | (g >> 5));                 \
+	((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 3)) & 0xFF);   \
+    } while (0)
+
+#define ZYWRLE_YMASK32  0xFFFFFFFF
+#define ZYWRLE_UVMASK32 0xFFFFFFFF
+#define ZYWRLE_LOAD_PIXEL32(src, r, g, b)     \
+    do {                                      \
+	r = ((uint8_t*)src)[L_2];             \
+	g = ((uint8_t*)src)[L_1];             \
+	b = ((uint8_t*)src)[L_0];             \
+    } while (0)
+#define ZYWRLE_SAVE_PIXEL32(dst, r, g, b)             \
+    do {                                              \
+	((uint8_t*)dst)[L_2] = (uint8_t)r;            \
+	((uint8_t*)dst)[L_1] = (uint8_t)g;            \
+	((uint8_t*)dst)[L_0] = (uint8_t)b;            \
+    } while (0)
+
+static inline void harr(int8_t *px0, int8_t *px1)
+{
+    /* Piecewise-Linear Harr(PLHarr) */
+    int x0 = (int)*px0, x1 = (int)*px1;
+    int orgx0 = x0, orgx1 = x1;
+
+    if ((x0 ^ x1) & 0x80) {
+        /* differ sign */
+        x1 += x0;
+        if (((x1 ^ orgx1) & 0x80) == 0) {
+            /* |x1| > |x0| */
+            x0 -= x1;	/* H = -B */
+        }
+    } else {
+        /* same sign */
+        x0 -= x1;
+        if (((x0 ^ orgx0) & 0x80) == 0) {
+            /* |x0| > |x1| */
+            x1 += x0;	/* L = A */
+        }
+    }
+    *px0 = (int8_t)x1;
+    *px1 = (int8_t)x0;
+}
+
+/*
+ 1D-Wavelet transform.
+
+ In coefficients array, the famous 'pyramid' decomposition is well used.
+
+ 1D Model:
+   |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
+   |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
+
+ But this method needs line buffer because H/L is different position from X0/X1.
+ So, I used 'interleave' decomposition instead of it.
+
+ 1D Model:
+   |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
+   |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
+
+ In this method, H/L and X0/X1 is always same position.
+ This lead us to more speed and less memory.
+ Of cause, the result of both method is quite same
+ because it's only difference that coefficient position.
+*/
+static inline void wavelet_level(int *data, int size, int l, int skip_pixel)
+{
+    int s, ofs;
+    int8_t *px0;
+    int8_t *end;
+
+    px0 = (int8_t*)data;
+    s = (8 << l) * skip_pixel;
+    end = px0 + (size >> (l + 1)) * s;
+    s -= 2;
+    ofs = (4 << l) * skip_pixel;
+
+    while (px0 < end) {
+        harr(px0, px0 + ofs);
+        px0++;
+        harr(px0, px0 + ofs);
+        px0++;
+        harr(px0, px0 + ofs);
+        px0 += s;
+    }
+}
+
+#ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static inline void filter_wavelet_square(int *buf, int width, int height,
+                                         int level, int l)
+{
+    int r, s;
+    int x, y;
+    int *h;
+    const unsigned int *m;
+
+    m = &(zywrle_param[level - 1][l]);
+    s = 2 << l;
+
+    for (r = 1; r < 4; r++) {
+        h = buf;
+        if (r & 0x01) {
+            h += s >> 1;
+        }
+        if (r & 0x02) {
+            h += (s >> 1) * width;
+        }
+        for (y = 0; y < height / s; y++) {
+            for (x = 0; x < width / s; x++) {
+                /*
+                  these are same following code.
+                  h[x] = h[x] / (~m[x]+1) * (~m[x]+1);
+                  ( round h[x] with m[x] bit )
+                  '&' operator isn't 'round' but is 'floor'.
+                  So, we must offset when h[x] is negative.
+                */
+                if (((int8_t*)h)[0] & 0x80) {
+                    ((int8_t*)h)[0] += ~((int8_t*)m)[0];
+                }
+                if (((int8_t*)h)[1] & 0x80) {
+                    ((int8_t*)h)[1] += ~((int8_t*)m)[1];
+                }
+                if (((int8_t*)h)[2] & 0x80) {
+                    ((int8_t*)h)[2] += ~((int8_t*)m)[2];
+                }
+                *h &= *m;
+                h += s;
+            }
+            h += (s-1)*width;
+        }
+    }
+}
+#else
+/*
+ Type B:Non liner quantization filter.
+
+ Coefficients have Gaussian curve and smaller value which is
+ large part of coefficients isn't more important than larger value.
+ So, I use filter of Non liner quantize/dequantize table.
+ In general, Non liner quantize formula is explained as following.
+
+    y=f(x)   = sign(x)*round( ((abs(x)/(2^7))^ r   )* 2^(bo-1) )*2^(8-bo)
+    x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
+ ( r:power coefficient  bi:effective MSB in input  bo:effective MSB in output )
+
+   r < 1.0 : Smaller value is more important than larger value.
+   r > 1.0 : Larger value is more important than smaller value.
+   r = 1.0 : Liner quantization which is same with EZW style.
+
+ r = 0.75 is famous non liner quantization used in MP3 audio codec.
+ In contrast to audio data, larger value is important in wavelet coefficients.
+ So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
+
+ As compared with EZW style liner quantization, this filter tended to be
+ more sharp edge and be more compression rate but be more blocking noise and be
+ less quality. Especially, the surface of graphic objects has distinguishable
+ noise in middle quality mode.
+
+ We need only quantized-dequantized(filtered) value rather than quantized value
+ itself because all values are packed or palette-lized in later ZRLE section.
+ This lead us not to need to modify client decoder when we change
+ the filtering procedure in future.
+ Client only decodes coefficients given by encoder.
+*/
+static inline void filter_wavelet_square(int *buf, int width, int height,
+                                         int level, int l)
+{
+    int r, s;
+    int x, y;
+    int *h;
+    const int8_t **m;
+
+    m = zywrle_param[level - 1][l];
+    s = 2 << l;
+
+    for (r = 1; r < 4; r++) {
+        h = buf;
+        if (r & 0x01) {
+            h += s >> 1;
+        }
+        if (r & 0x02) {
+            h += (s >> 1) * width;
+        }
+        for (y = 0; y < height / s; y++) {
+            for (x = 0; x < width / s; x++) {
+                ((int8_t*)h)[0] = m[0][((uint8_t*)h)[0]];
+                ((int8_t*)h)[1] = m[1][((uint8_t*)h)[1]];
+                ((int8_t*)h)[2] = m[2][((uint8_t*)h)[2]];
+                h += s;
+            }
+            h += (s - 1) * width;
+        }
+    }
+}
+#endif
+
+static inline void wavelet(int *buf, int width, int height, int level)
+{
+	int l, s;
+	int *top;
+	int *end;
+
+	for (l = 0; l < level; l++) {
+		top = buf;
+		end = buf + height * width;
+		s = width << l;
+		while (top < end) {
+			wavelet_level(top, width, l, 1);
+			top += s;
+		}
+		top = buf;
+		end = buf + width;
+		s = 1<<l;
+		while (top < end) {
+			wavelet_level(top, height, l, width);
+			top += s;
+		}
+		filter_wavelet_square(buf, width, height, level, l);
+	}
+}
+
+
+/* Load/Save coefficients stuffs.
+ Coefficients manages as 24 bits little-endian pixel. */
+#define ZYWRLE_LOAD_COEFF(src, r, g, b)         \
+    do {                                        \
+	r = ((int8_t*)src)[2];                  \
+	g = ((int8_t*)src)[1];                  \
+	b = ((int8_t*)src)[0];                  \
+    } while (0)
+
+#define ZYWRLE_SAVE_COEFF(dst, r, g, b)       \
+    do {                                      \
+	((int8_t*)dst)[2] = (int8_t)r;        \
+	((int8_t*)dst)[1] = (int8_t)g;        \
+	((int8_t*)dst)[0] = (int8_t)b;        \
+    } while (0)
+
+/*
+  RGB <=> YUV conversion stuffs.
+  YUV coversion is explained as following formula in strict meaning:
+  Y =  0.299R + 0.587G + 0.114B (   0<=Y<=255)
+  U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
+  V =  0.500R - 0.419G - 0.081B (-128<=V<=127)
+
+  I use simple conversion RCT(reversible color transform) which is described
+  in JPEG-2000 specification.
+  Y = (R + 2G + B)/4 (   0<=Y<=255)
+  U = B-G (-256<=U<=255)
+  V = R-G (-256<=V<=255)
+*/
+
+/* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
+   For make Same N-bit, UV is lossy.
+   More exact PLHarr, we reduce to odd range(-127<=x<=127). */
+#define ZYWRLE_RGBYUV_(r, g, b, y, u, v, ymask, uvmask)          \
+    do {                                                         \
+	y = (r + (g << 1) + b) >> 2;                             \
+	u =  b - g;                                              \
+	v =  r - g;                                              \
+	y -= 128;                                                \
+	u >>= 1;                                                 \
+	v >>= 1;                                                 \
+	y &= ymask;                                              \
+	u &= uvmask;                                             \
+	v &= uvmask;                                             \
+	if (y == -128) {                                         \
+            y += (0xFFFFFFFF - ymask + 1);                       \
+        }                                                        \
+	if (u == -128) {                                         \
+            u += (0xFFFFFFFF - uvmask + 1);                      \
+        }                                                        \
+	if (v == -128) {                                         \
+            v += (0xFFFFFFFF - uvmask + 1);                      \
+        }                                                        \
+    } while (0)
+
+
+/*
+ coefficient packing/unpacking stuffs.
+ Wavelet transform makes 4 sub coefficient image from 1 original image.
+
+ model with pyramid decomposition:
+   +------+------+
+   |      |      |
+   |  L   |  Hx  |
+   |      |      |
+   +------+------+
+   |      |      |
+   |  H   |  Hxy |
+   |      |      |
+   +------+------+
+
+ So, we must transfer each sub images individually in strict meaning.
+ But at least ZRLE meaning, following one decompositon image is same as
+ avobe individual sub image. I use this format.
+ (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
+  for simplified procedure for any wavelet level.)
+
+   +------+------+
+   |      L      |
+   +------+------+
+   |      Hx     |
+   +------+------+
+   |      Hy     |
+   +------+------+
+   |      Hxy    |
+   +------+------+
+*/
+#define ZYWRLE_INC_PTR(data)                         \
+    do {                                             \
+        data++;                                      \
+        if( data - p >= (w + uw) ) {                 \
+            data += scanline-(w + uw);               \
+            p = data;                                \
+        }                                            \
+    } while (0)
+
+#define ZYWRLE_TRANSFER_COEFF(buf, data, t, w, h, scanline, level, TRANS) \
+    do {                                                                \
+        ph = buf;                                                       \
+        s = 2 << level;                                                 \
+        if (t & 0x01) {                                                 \
+            ph += s >> 1;                                               \
+        }                                                               \
+        if (t & 0x02) {                                                 \
+            ph += (s >> 1) * w;                                         \
+        }                                                               \
+        end = ph + h * w;                                               \
+        while (ph < end) {                                              \
+            line = ph + w;                                              \
+            while (ph < line) {                                         \
+                TRANS                                                   \
+                    ZYWRLE_INC_PTR(data);                               \
+                ph += s;                                                \
+            }                                                           \
+            ph += (s - 1) * w;                                          \
+        }                                                               \
+    } while (0)
+
+#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level)	\
+    ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
+                          ZYWRLE_LOAD_COEFF(ph, r, g, b);               \
+                          ZYWRLE_SAVE_PIXEL(data, r, g, b);)
+
+#define ZYWRLE_UNPACK_COEFF(buf, data, t, width, height, scanline, level) \
+    ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
+                          ZYWRLE_LOAD_PIXEL(data, r, g, b);             \
+                          ZYWRLE_SAVE_COEFF(ph, r, g, b);)
+
+#define ZYWRLE_SAVE_UNALIGN(data, TRANS)                     \
+    do {                                                     \
+        top = buf + w * h;                                   \
+        end = buf + (w + uw) * (h + uh);                     \
+        while (top < end) {                                  \
+            TRANS                                            \
+                ZYWRLE_INC_PTR(data);                        \
+                top++;                                       \
+        }                                                    \
+    } while (0)
+
+#define ZYWRLE_LOAD_UNALIGN(data,TRANS)                                 \
+    do {                                                                \
+        top = buf + w * h;                                              \
+        if (uw) {                                                       \
+            p = data + w;                                               \
+            end = (int*)(p + h * scanline);                             \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + uw);                                  \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline - uw;                                     \
+            }                                                           \
+        }                                                               \
+        if (uh) {                                                       \
+            p = data + h * scanline;                                    \
+            end = (int*)(p + uh * scanline);                            \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + w);                                   \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline - w;                                      \
+            }                                                           \
+        }                                                               \
+        if (uw && uh) {                                                 \
+            p= data + w + h * scanline;                                 \
+            end = (int*)(p + uh * scanline);                            \
+            while (p < (ZRLE_PIXEL*)end) {                              \
+                line = (int*)(p + uw);                                  \
+                while (p < (ZRLE_PIXEL*)line) {                         \
+                    TRANS                                               \
+                        p++;                                            \
+                    top++;                                              \
+                }                                                       \
+                p += scanline-uw;                                       \
+            }                                                           \
+        }                                                               \
+    } while (0)
+
+static inline void zywrle_calc_size(int *w, int *h, int level)
+{
+    *w &= ~((1 << level) - 1);
+    *h &= ~((1 << level) - 1);
+}
+
+#endif
diff --git a/qemu-0.15.x/ui/vnc-jobs-async.c b/qemu-0.15.x/ui/vnc-jobs-async.c
new file mode 100644
index 0000000..1dfa6c3
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-jobs-async.c
@@ -0,0 +1,341 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 "vnc.h"
+#include "vnc-jobs.h"
+
+/*
+ * Locking:
+ *
+ * There is three levels of locking:
+ * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?)
+ * - VncDisplay global lock: mainly used for framebuffer updates to avoid
+ *                      screen corruption if the framebuffer is updated
+ *			while the worker is doing something.
+ * - VncState::output lock: used to make sure the output buffer is not corrupted
+ * 		   	 if two threads try to write on it at the same time
+ *
+ * While the VNC worker thread is working, the VncDisplay global lock is hold
+ * to avoid screen corruptions (this does not block vnc_refresh() because it
+ * uses trylock()) but the output lock is not hold because the thread work on
+ * its own output buffer.
+ * When the encoding job is done, the worker thread will hold the output lock
+ * and copy its output buffer in vs->output.
+*/
+
+struct VncJobQueue {
+    QemuCond cond;
+    QemuMutex mutex;
+    QemuThread thread;
+    Buffer buffer;
+    bool exit;
+    QTAILQ_HEAD(, VncJob) jobs;
+};
+
+typedef struct VncJobQueue VncJobQueue;
+
+/*
+ * We use a single global queue, but most of the functions are
+ * already reetrant, so we can easilly add more than one encoding thread
+ */
+static VncJobQueue *queue;
+
+static void vnc_lock_queue(VncJobQueue *queue)
+{
+    qemu_mutex_lock(&queue->mutex);
+}
+
+static void vnc_unlock_queue(VncJobQueue *queue)
+{
+    qemu_mutex_unlock(&queue->mutex);
+}
+
+VncJob *vnc_job_new(VncState *vs)
+{
+    VncJob *job = qemu_mallocz(sizeof(VncJob));
+
+    job->vs = vs;
+    vnc_lock_queue(queue);
+    QLIST_INIT(&job->rectangles);
+    vnc_unlock_queue(queue);
+    return job;
+}
+
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
+{
+    VncRectEntry *entry = qemu_mallocz(sizeof(VncRectEntry));
+
+    entry->rect.x = x;
+    entry->rect.y = y;
+    entry->rect.w = w;
+    entry->rect.h = h;
+
+    vnc_lock_queue(queue);
+    QLIST_INSERT_HEAD(&job->rectangles, entry, next);
+    vnc_unlock_queue(queue);
+    return 1;
+}
+
+void vnc_job_push(VncJob *job)
+{
+    vnc_lock_queue(queue);
+    if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
+        qemu_free(job);
+    } else {
+        QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
+        qemu_cond_broadcast(&queue->cond);
+    }
+    vnc_unlock_queue(queue);
+}
+
+static bool vnc_has_job_locked(VncState *vs)
+{
+    VncJob *job;
+
+    QTAILQ_FOREACH(job, &queue->jobs, next) {
+        if (job->vs == vs || !vs) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool vnc_has_job(VncState *vs)
+{
+    bool ret;
+
+    vnc_lock_queue(queue);
+    ret = vnc_has_job_locked(vs);
+    vnc_unlock_queue(queue);
+    return ret;
+}
+
+void vnc_jobs_clear(VncState *vs)
+{
+    VncJob *job, *tmp;
+
+    vnc_lock_queue(queue);
+    QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) {
+        if (job->vs == vs || !vs) {
+            QTAILQ_REMOVE(&queue->jobs, job, next);
+        }
+    }
+    vnc_unlock_queue(queue);
+}
+
+void vnc_jobs_join(VncState *vs)
+{
+    vnc_lock_queue(queue);
+    while (vnc_has_job_locked(vs)) {
+        qemu_cond_wait(&queue->cond, &queue->mutex);
+    }
+    vnc_unlock_queue(queue);
+}
+
+/*
+ * Copy data for local use
+ */
+static void vnc_async_encoding_start(VncState *orig, VncState *local)
+{
+    local->vnc_encoding = orig->vnc_encoding;
+    local->features = orig->features;
+    local->ds = orig->ds;
+    local->vd = orig->vd;
+    local->lossy_rect = orig->lossy_rect;
+    local->write_pixels = orig->write_pixels;
+    local->clientds = orig->clientds;
+    local->tight = orig->tight;
+    local->zlib = orig->zlib;
+    local->hextile = orig->hextile;
+    local->zrle = orig->zrle;
+    local->output =  queue->buffer;
+    local->csock = -1; /* Don't do any network work on this thread */
+
+    buffer_reset(&local->output);
+}
+
+static void vnc_async_encoding_end(VncState *orig, VncState *local)
+{
+    orig->tight = local->tight;
+    orig->zlib = local->zlib;
+    orig->hextile = local->hextile;
+    orig->zrle = local->zrle;
+    orig->lossy_rect = local->lossy_rect;
+
+    queue->buffer = local->output;
+}
+
+static int vnc_worker_thread_loop(VncJobQueue *queue)
+{
+    VncJob *job;
+    VncRectEntry *entry, *tmp;
+    VncState vs;
+    int n_rectangles;
+    int saved_offset;
+    bool flush;
+
+    vnc_lock_queue(queue);
+    while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
+        qemu_cond_wait(&queue->cond, &queue->mutex);
+    }
+    /* Here job can only be NULL if queue->exit is true */
+    job = QTAILQ_FIRST(&queue->jobs);
+    vnc_unlock_queue(queue);
+
+    if (queue->exit) {
+        return -1;
+    }
+
+    vnc_lock_output(job->vs);
+    if (job->vs->csock == -1 || job->vs->abort == true) {
+        goto disconnected;
+    }
+    vnc_unlock_output(job->vs);
+
+    /* Make a local copy of vs and switch output buffers */
+    vnc_async_encoding_start(job->vs, &vs);
+
+    /* Start sending rectangles */
+    n_rectangles = 0;
+    vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(&vs, 0);
+    saved_offset = vs.output.offset;
+    vnc_write_u16(&vs, 0);
+
+    vnc_lock_display(job->vs->vd);
+    QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
+        int n;
+
+        if (job->vs->csock == -1) {
+            vnc_unlock_display(job->vs->vd);
+            /* output mutex must be locked before going to
+             * disconnected:
+             */
+            vnc_lock_output(job->vs);
+            goto disconnected;
+        }
+
+        n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
+                                        entry->rect.w, entry->rect.h);
+
+        if (n >= 0) {
+            n_rectangles += n;
+        }
+        qemu_free(entry);
+    }
+    vnc_unlock_display(job->vs->vd);
+
+    /* Put n_rectangles at the beginning of the message */
+    vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+    vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+
+    /* Switch back buffers */
+    vnc_lock_output(job->vs);
+    if (job->vs->csock == -1) {
+        goto disconnected;
+    }
+
+    vnc_write(job->vs, vs.output.buffer, vs.output.offset);
+
+disconnected:
+    /* Copy persistent encoding data */
+    vnc_async_encoding_end(job->vs, &vs);
+    flush = (job->vs->csock != -1 && job->vs->abort != true);
+    vnc_unlock_output(job->vs);
+
+    if (flush) {
+        vnc_flush(job->vs);
+    }
+
+    vnc_lock_queue(queue);
+    QTAILQ_REMOVE(&queue->jobs, job, next);
+    vnc_unlock_queue(queue);
+    qemu_cond_broadcast(&queue->cond);
+    qemu_free(job);
+    return 0;
+}
+
+static VncJobQueue *vnc_queue_init(void)
+{
+    VncJobQueue *queue = qemu_mallocz(sizeof(VncJobQueue));
+
+    qemu_cond_init(&queue->cond);
+    qemu_mutex_init(&queue->mutex);
+    QTAILQ_INIT(&queue->jobs);
+    return queue;
+}
+
+static void vnc_queue_clear(VncJobQueue *q)
+{
+    qemu_cond_destroy(&queue->cond);
+    qemu_mutex_destroy(&queue->mutex);
+    buffer_free(&queue->buffer);
+    qemu_free(q);
+    queue = NULL; /* Unset global queue */
+}
+
+static void *vnc_worker_thread(void *arg)
+{
+    VncJobQueue *queue = arg;
+
+    qemu_thread_get_self(&queue->thread);
+
+    while (!vnc_worker_thread_loop(queue)) ;
+    vnc_queue_clear(queue);
+    return NULL;
+}
+
+void vnc_start_worker_thread(void)
+{
+    VncJobQueue *q;
+
+    if (vnc_worker_thread_running())
+        return ;
+
+    q = vnc_queue_init();
+    qemu_thread_create(&q->thread, vnc_worker_thread, q);
+    queue = q; /* Set global queue */
+}
+
+bool vnc_worker_thread_running(void)
+{
+    return queue; /* Check global queue */
+}
+
+void vnc_stop_worker_thread(void)
+{
+    if (!vnc_worker_thread_running())
+        return ;
+
+    /* Remove all jobs and wake up the thread */
+    vnc_lock_queue(queue);
+    queue->exit = true;
+    vnc_unlock_queue(queue);
+    vnc_jobs_clear(NULL);
+    qemu_cond_broadcast(&queue->cond);
+}
diff --git a/qemu-0.15.x/ui/vnc-jobs-sync.c b/qemu-0.15.x/ui/vnc-jobs-sync.c
new file mode 100644
index 0000000..49b77af
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-jobs-sync.c
@@ -0,0 +1,73 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 "vnc.h"
+#include "vnc-jobs.h"
+
+void vnc_jobs_clear(VncState *vs)
+{
+}
+
+void vnc_jobs_join(VncState *vs)
+{
+}
+
+VncJob *vnc_job_new(VncState *vs)
+{
+    vs->job.vs = vs;
+    vs->job.rectangles = 0;
+
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vs->job.saved_offset = vs->output.offset;
+    vnc_write_u16(vs, 0);
+    return &vs->job;
+}
+
+void vnc_job_push(VncJob *job)
+{
+    VncState *vs = job->vs;
+
+    vs->output.buffer[job->saved_offset] = (job->rectangles >> 8) & 0xFF;
+    vs->output.buffer[job->saved_offset + 1] = job->rectangles & 0xFF;
+    vnc_flush(job->vs);
+}
+
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
+{
+    int n;
+
+    n = vnc_send_framebuffer_update(job->vs, x, y, w, h);
+    if (n >= 0)
+        job->rectangles += n;
+    return n;
+}
+
+bool vnc_has_job(VncState *vs)
+{
+    return false;
+}
diff --git a/qemu-0.15.x/ui/vnc-jobs.h b/qemu-0.15.x/ui/vnc-jobs.h
new file mode 100644
index 0000000..b8dab81
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-jobs.h
@@ -0,0 +1,87 @@
+/*
+ * QEMU VNC display driver
+ *
+ * From libvncserver/rfb/rfbproto.h
+ * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
+ * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *
+ * 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 VNC_JOBS_H
+#define VNC_JOBS_H
+
+/* Jobs */
+VncJob *vnc_job_new(VncState *vs);
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h);
+void vnc_job_push(VncJob *job);
+bool vnc_has_job(VncState *vs);
+void vnc_jobs_clear(VncState *vs);
+void vnc_jobs_join(VncState *vs);
+
+#ifdef CONFIG_VNC_THREAD
+
+void vnc_start_worker_thread(void);
+bool vnc_worker_thread_running(void);
+void vnc_stop_worker_thread(void);
+
+#endif /* CONFIG_VNC_THREAD */
+
+/* Locks */
+static inline int vnc_trylock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    return qemu_mutex_trylock(&vd->mutex);
+#else
+    return 0;
+#endif
+}
+
+static inline void vnc_lock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_lock(&vd->mutex);
+#endif
+}
+
+static inline void vnc_unlock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_unlock(&vd->mutex);
+#endif
+}
+
+static inline void vnc_lock_output(VncState *vs)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_lock(&vs->output_mutex);
+#endif
+}
+
+static inline void vnc_unlock_output(VncState *vs)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_unlock(&vs->output_mutex);
+#endif
+}
+
+#endif /* VNC_JOBS_H */
diff --git a/qemu-0.15.x/ui/vnc-palette.c b/qemu-0.15.x/ui/vnc-palette.c
new file mode 100644
index 0000000..13ece42
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-palette.c
@@ -0,0 +1,158 @@
+/*
+ * QEMU VNC display driver: palette hash table
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 "vnc-palette.h"
+
+static VncPaletteEntry *palette_find(const VncPalette *palette,
+                                     uint32_t color, unsigned int hash)
+{
+    VncPaletteEntry *entry;
+
+    QLIST_FOREACH(entry, &palette->table[hash], next) {
+        if (entry->color == color) {
+            return entry;
+        }
+    }
+
+    return NULL;
+}
+
+static unsigned int palette_hash(uint32_t rgb, int bpp)
+{
+    if (bpp == 16) {
+        return ((unsigned int)(((rgb >> 8) + rgb) & 0xFF));
+    } else {
+        return ((unsigned int)(((rgb >> 16) + (rgb >> 8)) & 0xFF));
+    }
+}
+
+VncPalette *palette_new(size_t max, int bpp)
+{
+    VncPalette *palette;
+
+    palette = qemu_mallocz(sizeof(*palette));
+    palette_init(palette, max, bpp);
+    return palette;
+}
+
+void palette_init(VncPalette *palette, size_t max, int bpp)
+{
+    memset(palette, 0, sizeof (*palette));
+    palette->max = max;
+    palette->bpp = bpp;
+}
+
+void palette_destroy(VncPalette *palette)
+{
+    qemu_free(palette);
+}
+
+int palette_put(VncPalette *palette, uint32_t color)
+{
+    unsigned int hash;
+    unsigned int idx = palette->size;
+    VncPaletteEntry *entry;
+
+    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
+    entry = palette_find(palette, color, hash);
+
+    if (!entry && palette->size >= palette->max) {
+        return 0;
+    }
+    if (!entry) {
+        VncPaletteEntry *entry;
+
+        entry = &palette->pool[palette->size];
+        entry->color = color;
+        entry->idx = idx;
+        QLIST_INSERT_HEAD(&palette->table[hash], entry, next);
+        palette->size++;
+    }
+    return palette->size;
+}
+
+int palette_idx(const VncPalette *palette, uint32_t color)
+{
+    VncPaletteEntry *entry;
+    unsigned int hash;
+
+    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
+    entry = palette_find(palette, color, hash);
+    return (entry == NULL ? -1 : entry->idx);
+}
+
+size_t palette_size(const VncPalette *palette)
+{
+    return palette->size;
+}
+
+void palette_iter(const VncPalette *palette,
+                  void (*iter)(int idx, uint32_t color, void *opaque),
+                  void *opaque)
+{
+    int i;
+    VncPaletteEntry *entry;
+
+    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
+        QLIST_FOREACH(entry, &palette->table[i], next) {
+            iter(entry->idx, entry->color, opaque);
+        }
+    }
+}
+
+uint32_t palette_color(const VncPalette *palette, int idx, bool *found)
+{
+    int i;
+    VncPaletteEntry *entry;
+
+    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
+        QLIST_FOREACH(entry, &palette->table[i], next) {
+            if (entry->idx == idx) {
+                *found = true;
+                return entry->color;
+            }
+        }
+    }
+
+    *found = false;
+    return -1;
+}
+
+static void palette_fill_cb(int idx, uint32_t color, void *opaque)
+{
+    uint32_t *colors = opaque;
+
+    colors[idx] = color;
+}
+
+size_t palette_fill(const VncPalette *palette,
+                    uint32_t colors[VNC_PALETTE_MAX_SIZE])
+{
+    palette_iter(palette, palette_fill_cb, colors);
+    return palette_size(palette);
+}
diff --git a/qemu-0.15.x/ui/vnc-palette.h b/qemu-0.15.x/ui/vnc-palette.h
new file mode 100644
index 0000000..3260885
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-palette.h
@@ -0,0 +1,68 @@
+/*
+ * QEMU VNC display driver: palette hash table
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary at gmail.com>
+ *
+ * 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 VNC_PALETTE_H
+#define VNC_PALETTE_H
+
+#include "qlist.h"
+#include "qemu-queue.h"
+#include <stdint.h>
+
+#define VNC_PALETTE_HASH_SIZE 256
+#define VNC_PALETTE_MAX_SIZE  256
+
+typedef struct VncPaletteEntry {
+    int idx;
+    uint32_t color;
+    QLIST_ENTRY(VncPaletteEntry) next;
+} VncPaletteEntry;
+
+typedef struct VncPalette {
+    VncPaletteEntry pool[VNC_PALETTE_MAX_SIZE];
+    size_t size;
+    size_t max;
+    int bpp;
+    QLIST_HEAD(,VncPaletteEntry) table[VNC_PALETTE_HASH_SIZE];
+} VncPalette;
+
+VncPalette *palette_new(size_t max, int bpp);
+void palette_init(VncPalette *palette, size_t max, int bpp);
+void palette_destroy(VncPalette *palette);
+
+int palette_put(VncPalette *palette, uint32_t color);
+int palette_idx(const VncPalette *palette, uint32_t color);
+size_t palette_size(const VncPalette *palette);
+
+void palette_iter(const VncPalette *palette,
+                  void (*iter)(int idx, uint32_t color, void *opaque),
+                  void *opaque);
+uint32_t palette_color(const VncPalette *palette, int idx, bool *found);
+size_t palette_fill(const VncPalette *palette,
+                    uint32_t colors[VNC_PALETTE_MAX_SIZE]);
+
+#endif /* VNC_PALETTE_H */
diff --git a/qemu-0.15.x/ui/vnc-tls.c b/qemu-0.15.x/ui/vnc-tls.c
new file mode 100644
index 0000000..31f1467
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-tls.c
@@ -0,0 +1,445 @@
+/*
+ * QEMU VNC display driver: TLS helpers
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "qemu-x509.h"
+#include "vnc.h"
+#include "qemu_socket.h"
+
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
+static void vnc_debug_gnutls_log(int level, const char* str) {
+    VNC_DEBUG("%d %s", level, str);
+}
+#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
+
+
+#define DH_BITS 1024
+static gnutls_dh_params_t dh_params;
+
+static int vnc_tls_initialize(void)
+{
+    static int tlsinitialized = 0;
+
+    if (tlsinitialized)
+        return 1;
+
+    if (gnutls_global_init () < 0)
+        return 0;
+
+    /* XXX ought to re-generate diffie-hellmen params periodically */
+    if (gnutls_dh_params_init (&dh_params) < 0)
+        return 0;
+    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
+        return 0;
+
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
+    gnutls_global_set_log_level(10);
+    gnutls_global_set_log_function(vnc_debug_gnutls_log);
+#endif
+
+    tlsinitialized = 1;
+
+    return 1;
+}
+
+static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
+                            const void *data,
+                            size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = send(vs->csock, data, len, 0);
+    if (ret < 0) {
+        if (errno == EINTR)
+            goto retry;
+        return -1;
+    }
+    return ret;
+}
+
+
+static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
+                            void *data,
+                            size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = qemu_recv(vs->csock, data, len, 0);
+    if (ret < 0) {
+        if (errno == EINTR)
+            goto retry;
+        return -1;
+    }
+    return ret;
+}
+
+
+static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
+{
+    gnutls_anon_server_credentials anon_cred;
+    int ret;
+
+    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
+        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+        return NULL;
+    }
+
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
+
+    return anon_cred;
+}
+
+
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
+{
+    gnutls_certificate_credentials_t x509_cred;
+    int ret;
+
+    if (!vd->tls.x509cacert) {
+        VNC_DEBUG("No CA x509 certificate specified\n");
+        return NULL;
+    }
+    if (!vd->tls.x509cert) {
+        VNC_DEBUG("No server x509 certificate specified\n");
+        return NULL;
+    }
+    if (!vd->tls.x509key) {
+        VNC_DEBUG("No server private key specified\n");
+        return NULL;
+    }
+
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
+        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+        return NULL;
+    }
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
+                                                      vd->tls.x509cacert,
+                                                      GNUTLS_X509_FMT_PEM)) < 0) {
+        VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+        gnutls_certificate_free_credentials(x509_cred);
+        return NULL;
+    }
+
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
+                                                     vd->tls.x509cert,
+                                                     vd->tls.x509key,
+                                                     GNUTLS_X509_FMT_PEM)) < 0) {
+        VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
+        gnutls_certificate_free_credentials(x509_cred);
+        return NULL;
+    }
+
+    if (vd->tls.x509cacrl) {
+        if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
+                                                        vd->tls.x509cacrl,
+                                                        GNUTLS_X509_FMT_PEM)) < 0) {
+            VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
+            gnutls_certificate_free_credentials(x509_cred);
+            return NULL;
+        }
+    }
+
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+    return x509_cred;
+}
+
+
+int vnc_tls_validate_certificate(struct VncState *vs)
+{
+    int ret;
+    unsigned int status;
+    const gnutls_datum_t *certs;
+    unsigned int nCerts, i;
+    time_t now;
+
+    VNC_DEBUG("Validating client certificate\n");
+    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
+        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
+        return -1;
+    }
+
+    if ((now = time(NULL)) == ((time_t)-1)) {
+        return -1;
+    }
+
+    if (status != 0) {
+        if (status & GNUTLS_CERT_INVALID)
+            VNC_DEBUG("The certificate is not trusted.\n");
+
+        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+            VNC_DEBUG("The certificate hasn't got a known issuer.\n");
+
+        if (status & GNUTLS_CERT_REVOKED)
+            VNC_DEBUG("The certificate has been revoked.\n");
+
+        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+            VNC_DEBUG("The certificate uses an insecure algorithm\n");
+
+        return -1;
+    } else {
+        VNC_DEBUG("Certificate is valid!\n");
+    }
+
+    /* Only support x509 for now */
+    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
+        return -1;
+
+    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
+        return -1;
+
+    for (i = 0 ; i < nCerts ; i++) {
+        gnutls_x509_crt_t cert;
+        VNC_DEBUG ("Checking certificate chain %d\n", i);
+        if (gnutls_x509_crt_init (&cert) < 0)
+            return -1;
+
+        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
+            VNC_DEBUG("The certificate has expired\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_activation_time (cert) > now) {
+            VNC_DEBUG("The certificate is not yet activated\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_activation_time (cert) > now) {
+            VNC_DEBUG("The certificate is not yet activated\n");
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (i == 0) {
+            size_t dnameSize = 1024;
+            vs->tls.dname = qemu_malloc(dnameSize);
+        requery:
+            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
+                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+                    vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
+                    goto requery;
+                }
+                gnutls_x509_crt_deinit (cert);
+                VNC_DEBUG("Cannot get client distinguished name: %s",
+                          gnutls_strerror (ret));
+                return -1;
+            }
+
+            if (vs->vd->tls.x509verify) {
+                int allow;
+                if (!vs->vd->tls.acl) {
+                    VNC_DEBUG("no ACL activated, allowing access");
+                    gnutls_x509_crt_deinit (cert);
+                    continue;
+                }
+
+                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
+                                                  vs->tls.dname);
+
+                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
+                          vs->tls.dname, allow ? "allowed" : "denied");
+                if (!allow) {
+                    gnutls_x509_crt_deinit (cert);
+                    return -1;
+                }
+            }
+        }
+
+        gnutls_x509_crt_deinit (cert);
+    }
+
+    return 0;
+}
+
+
+int vnc_tls_client_setup(struct VncState *vs,
+                         int needX509Creds) {
+    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
+
+    VNC_DEBUG("Do TLS setup\n");
+    if (vnc_tls_initialize() < 0) {
+        VNC_DEBUG("Failed to init TLS\n");
+        vnc_client_error(vs);
+        return -1;
+    }
+    if (vs->tls.session == NULL) {
+        if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_set_default_priority(vs->tls.session) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
+            gnutls_deinit(vs->tls.session);
+            vs->tls.session = NULL;
+            vnc_client_error(vs);
+            return -1;
+        }
+
+        if (needX509Creds) {
+            gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
+            if (!x509_cred) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                gnutls_certificate_free_credentials(x509_cred);
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (vs->vd->tls.x509verify) {
+                VNC_DEBUG("Requesting a client certificate\n");
+                gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
+            }
+
+        } else {
+            gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
+            if (!anon_cred) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                vnc_client_error(vs);
+                return -1;
+            }
+            if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
+                gnutls_deinit(vs->tls.session);
+                vs->tls.session = NULL;
+                gnutls_anon_free_server_credentials(anon_cred);
+                vnc_client_error(vs);
+                return -1;
+            }
+        }
+
+        gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
+        gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
+        gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
+    }
+    return 0;
+}
+
+
+void vnc_tls_client_cleanup(struct VncState *vs)
+{
+    if (vs->tls.session) {
+        gnutls_deinit(vs->tls.session);
+        vs->tls.session = NULL;
+    }
+    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
+    free(vs->tls.dname);
+}
+
+
+
+static int vnc_set_x509_credential(VncDisplay *vd,
+                                   const char *certdir,
+                                   const char *filename,
+                                   char **cred,
+                                   int ignoreMissing)
+{
+    struct stat sb;
+
+    if (*cred) {
+        qemu_free(*cred);
+        *cred = NULL;
+    }
+
+    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
+
+    strcpy(*cred, certdir);
+    strcat(*cred, "/");
+    strcat(*cred, filename);
+
+    VNC_DEBUG("Check %s\n", *cred);
+    if (stat(*cred, &sb) < 0) {
+        qemu_free(*cred);
+        *cred = NULL;
+        if (ignoreMissing && errno == ENOENT)
+            return 0;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
+                               const char *certdir)
+{
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
+        goto cleanup;
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
+        goto cleanup;
+
+    return 0;
+
+ cleanup:
+    qemu_free(vd->tls.x509cacert);
+    qemu_free(vd->tls.x509cacrl);
+    qemu_free(vd->tls.x509cert);
+    qemu_free(vd->tls.x509key);
+    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
+    return -1;
+}
+
diff --git a/qemu-0.15.x/ui/vnc-tls.h b/qemu-0.15.x/ui/vnc-tls.h
new file mode 100644
index 0000000..2b93633
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc-tls.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU VNC display driver. TLS helpers
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 __QEMU_VNC_TLS_H__
+#define __QEMU_VNC_TLS_H__
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "acl.h"
+
+enum {
+    VNC_WIREMODE_CLEAR,
+    VNC_WIREMODE_TLS,
+};
+
+typedef struct VncDisplayTLS VncDisplayTLS;
+typedef struct VncStateTLS VncStateTLS;
+
+/* Server state */
+struct VncDisplayTLS {
+    int x509verify; /* Non-zero if server requests & validates client cert */
+    qemu_acl *acl;
+
+    /* Paths to x509 certs/keys */
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+};
+
+/* Per client state */
+struct VncStateTLS {
+    /* Whether data is being TLS encrypted yet */
+    int wiremode;
+    gnutls_session_t session;
+
+    /* Client's Distinguished Name from the x509 cert */
+    char *dname;
+};
+
+int vnc_tls_client_setup(VncState *vs, int x509Creds);
+void vnc_tls_client_cleanup(VncState *vs);
+
+int vnc_tls_validate_certificate(VncState *vs);
+
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
+			       const char *path);
+
+
+#endif /* __QEMU_VNC_TLS_H__ */
+
diff --git a/qemu-0.15.x/ui/vnc.c b/qemu-0.15.x/ui/vnc.c
new file mode 100644
index 0000000..f1e27d9
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc.c
@@ -0,0 +1,2933 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 "vnc.h"
+#include "vnc-jobs.h"
+#include "sysemu.h"
+#include "qemu_socket.h"
+#include "qemu-timer.h"
+#include "acl.h"
+#include "qemu-objects.h"
+
+#define VNC_REFRESH_INTERVAL_BASE 30
+#define VNC_REFRESH_INTERVAL_INC  50
+#define VNC_REFRESH_INTERVAL_MAX  2000
+static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
+static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
+
+#include "vnc_keysym.h"
+#include "d3des.h"
+
+static VncDisplay *vnc_display; /* needed for info vnc */
+static DisplayChangeListener *dcl;
+
+static int vnc_cursor_define(VncState *vs);
+
+static char *addr_to_string(const char *format,
+                            struct sockaddr_storage *sa,
+                            socklen_t salen) {
+    char *addr;
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+    size_t addrlen;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return NULL;
+    }
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = qemu_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+
+char *vnc_socket_local_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+char *vnc_socket_remote_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
+                          socklen_t salen)
+{
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return -1;
+    }
+
+    qdict_put(qdict, "host", qstring_from_str(host));
+    qdict_put(qdict, "service", qstring_from_str(serv));
+    qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
+
+    return 0;
+}
+
+static int vnc_server_addr_put(QDict *qdict, int fd)
+{
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
+        return -1;
+    }
+
+    return put_addr_qdict(qdict, &sa, salen);
+}
+
+static int vnc_qdict_remote_addr(QDict *qdict, int fd)
+{
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
+        return -1;
+    }
+
+    return put_addr_qdict(qdict, &sa, salen);
+}
+
+static const char *vnc_auth_name(VncDisplay *vd) {
+    switch (vd->auth) {
+    case VNC_AUTH_INVALID:
+        return "invalid";
+    case VNC_AUTH_NONE:
+        return "none";
+    case VNC_AUTH_VNC:
+        return "vnc";
+    case VNC_AUTH_RA2:
+        return "ra2";
+    case VNC_AUTH_RA2NE:
+        return "ra2ne";
+    case VNC_AUTH_TIGHT:
+        return "tight";
+    case VNC_AUTH_ULTRA:
+        return "ultra";
+    case VNC_AUTH_TLS:
+        return "tls";
+    case VNC_AUTH_VENCRYPT:
+#ifdef CONFIG_VNC_TLS
+        switch (vd->subauth) {
+        case VNC_AUTH_VENCRYPT_PLAIN:
+            return "vencrypt+plain";
+        case VNC_AUTH_VENCRYPT_TLSNONE:
+            return "vencrypt+tls+none";
+        case VNC_AUTH_VENCRYPT_TLSVNC:
+            return "vencrypt+tls+vnc";
+        case VNC_AUTH_VENCRYPT_TLSPLAIN:
+            return "vencrypt+tls+plain";
+        case VNC_AUTH_VENCRYPT_X509NONE:
+            return "vencrypt+x509+none";
+        case VNC_AUTH_VENCRYPT_X509VNC:
+            return "vencrypt+x509+vnc";
+        case VNC_AUTH_VENCRYPT_X509PLAIN:
+            return "vencrypt+x509+plain";
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            return "vencrypt+tls+sasl";
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            return "vencrypt+x509+sasl";
+        default:
+            return "vencrypt";
+        }
+#else
+        return "vencrypt";
+#endif
+    case VNC_AUTH_SASL:
+        return "sasl";
+    }
+    return "unknown";
+}
+
+static int vnc_server_info_put(QDict *qdict)
+{
+    if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
+        return -1;
+    }
+
+    qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
+    return 0;
+}
+
+static void vnc_client_cache_auth(VncState *client)
+{
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
+    QDict *qdict;
+#endif
+
+    if (!client->info) {
+        return;
+    }
+
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
+    qdict = qobject_to_qdict(client->info);
+#endif
+
+#ifdef CONFIG_VNC_TLS
+    if (client->tls.session &&
+        client->tls.dname) {
+        qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (client->sasl.conn &&
+        client->sasl.username) {
+        qdict_put(qdict, "sasl_username",
+                  qstring_from_str(client->sasl.username));
+    }
+#endif
+}
+
+static void vnc_client_cache_addr(VncState *client)
+{
+    QDict *qdict;
+
+    qdict = qdict_new();
+    if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
+        QDECREF(qdict);
+        /* XXX: how to report the error? */
+        return;
+    }
+
+    client->info = QOBJECT(qdict);
+}
+
+static void vnc_qmp_event(VncState *vs, MonitorEvent event)
+{
+    QDict *server;
+    QObject *data;
+
+    if (!vs->info) {
+        return;
+    }
+
+    server = qdict_new();
+    if (vnc_server_info_put(server) < 0) {
+        QDECREF(server);
+        return;
+    }
+
+    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
+                              vs->info, QOBJECT(server));
+
+    monitor_protocol_event(event, data);
+
+    qobject_incref(vs->info);
+    qobject_decref(data);
+}
+
+static void info_vnc_iter(QObject *obj, void *opaque)
+{
+    QDict *client;
+    Monitor *mon = opaque;
+
+    client = qobject_to_qdict(obj);
+    monitor_printf(mon, "Client:\n");
+    monitor_printf(mon, "     address: %s:%s\n",
+                   qdict_get_str(client, "host"),
+                   qdict_get_str(client, "service"));
+
+#ifdef CONFIG_VNC_TLS
+    monitor_printf(mon, "  x509_dname: %s\n",
+        qdict_haskey(client, "x509_dname") ?
+        qdict_get_str(client, "x509_dname") : "none");
+#endif
+#ifdef CONFIG_VNC_SASL
+    monitor_printf(mon, "    username: %s\n",
+        qdict_haskey(client, "sasl_username") ?
+        qdict_get_str(client, "sasl_username") : "none");
+#endif
+}
+
+void do_info_vnc_print(Monitor *mon, const QObject *data)
+{
+    QDict *server;
+    QList *clients;
+
+    server = qobject_to_qdict(data);
+    if (qdict_get_bool(server, "enabled") == 0) {
+        monitor_printf(mon, "Server: disabled\n");
+        return;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    monitor_printf(mon, "     address: %s:%s\n",
+                   qdict_get_str(server, "host"),
+                   qdict_get_str(server, "service"));
+    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
+
+    clients = qdict_get_qlist(server, "clients");
+    if (qlist_empty(clients)) {
+        monitor_printf(mon, "Client: none\n");
+    } else {
+        qlist_iter(clients, info_vnc_iter, mon);
+    }
+}
+
+void do_info_vnc(Monitor *mon, QObject **ret_data)
+{
+    if (vnc_display == NULL || vnc_display->display == NULL) {
+        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+    } else {
+        QList *clist;
+        VncState *client;
+
+        clist = qlist_new();
+        QTAILQ_FOREACH(client, &vnc_display->clients, next) {
+            if (client->info) {
+                /* incref so that it's not freed by upper layers */
+                qobject_incref(client->info);
+                qlist_append_obj(clist, client->info);
+            }
+        }
+
+        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
+                                       QOBJECT(clist));
+        assert(*ret_data != NULL);
+
+        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
+            qobject_decref(*ret_data);
+            *ret_data = NULL;
+        }
+    }
+}
+
+/* TODO
+   1) Get the queue working for IO.
+   2) there is some weirdness when using the -S option (the screen is grey
+      and not totally invalidated
+   3) resolutions > 1024
+*/
+
+static int vnc_update_client(VncState *vs, int has_dirty);
+static int vnc_update_client_sync(VncState *vs, int has_dirty);
+static void vnc_disconnect_start(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
+static void vnc_init_timer(VncDisplay *vd);
+static void vnc_remove_timer(VncDisplay *vd);
+
+static void vnc_colordepth(VncState *vs);
+static void framebuffer_update_request(VncState *vs, int incremental,
+                                       int x_position, int y_position,
+                                       int w, int h);
+static void vnc_refresh(void *opaque);
+static int vnc_refresh_server_surface(VncDisplay *vd);
+
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    int i;
+    VncDisplay *vd = ds->opaque;
+    struct VncSurface *s = &vd->guest;
+
+    h += y;
+
+    /* round x down to ensure the loop only spans one 16-pixel block per,
+       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
+       two 16-pixel blocks but we only mark the first as dirty
+    */
+    w += (x % 16);
+    x -= (x % 16);
+
+    x = MIN(x, s->ds->width);
+    y = MIN(y, s->ds->height);
+    w = MIN(x + w, s->ds->width) - x;
+    h = MIN(h, s->ds->height);
+
+    for (; y < h; y++)
+        for (i = 0; i < w; i += 16)
+            set_bit((x + i) / 16, s->dirty[y]);
+}
+
+void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+                            int32_t encoding)
+{
+    vnc_write_u16(vs, x);
+    vnc_write_u16(vs, y);
+    vnc_write_u16(vs, w);
+    vnc_write_u16(vs, h);
+
+    vnc_write_s32(vs, encoding);
+}
+
+void buffer_reserve(Buffer *buffer, size_t len)
+{
+    if ((buffer->capacity - buffer->offset) < len) {
+        buffer->capacity += (len + 1024);
+        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        if (buffer->buffer == NULL) {
+            fprintf(stderr, "vnc: out of memory\n");
+            exit(1);
+        }
+    }
+}
+
+int buffer_empty(Buffer *buffer)
+{
+    return buffer->offset == 0;
+}
+
+uint8_t *buffer_end(Buffer *buffer)
+{
+    return buffer->buffer + buffer->offset;
+}
+
+void buffer_reset(Buffer *buffer)
+{
+        buffer->offset = 0;
+}
+
+void buffer_free(Buffer *buffer)
+{
+    qemu_free(buffer->buffer);
+    buffer->offset = 0;
+    buffer->capacity = 0;
+    buffer->buffer = NULL;
+}
+
+void buffer_append(Buffer *buffer, const void *data, size_t len)
+{
+    memcpy(buffer->buffer + buffer->offset, data, len);
+    buffer->offset += len;
+}
+
+static void vnc_desktop_resize(VncState *vs)
+{
+    DisplayState *ds = vs->ds;
+
+    if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+        return;
+    }
+    if (vs->client_width == ds_get_width(ds) &&
+        vs->client_height == ds_get_height(ds)) {
+        return;
+    }
+    vs->client_width = ds_get_width(ds);
+    vs->client_height = ds_get_height(ds);
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1); /* number of rects */
+    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
+                           VNC_ENCODING_DESKTOPRESIZE);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
+#ifdef CONFIG_VNC_THREAD
+static void vnc_abort_display_jobs(VncDisplay *vd)
+{
+    VncState *vs;
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_lock_output(vs);
+        vs->abort = true;
+        vnc_unlock_output(vs);
+    }
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_jobs_join(vs);
+    }
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_lock_output(vs);
+        vs->abort = false;
+        vnc_unlock_output(vs);
+    }
+}
+#else
+static void vnc_abort_display_jobs(VncDisplay *vd)
+{
+}
+#endif
+
+static void vnc_dpy_resize(DisplayState *ds)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs;
+
+    vnc_abort_display_jobs(vd);
+
+    /* server surface */
+    if (!vd->server)
+        vd->server = qemu_mallocz(sizeof(*vd->server));
+    if (vd->server->data)
+        qemu_free(vd->server->data);
+    *(vd->server) = *(ds->surface);
+    vd->server->data = qemu_mallocz(vd->server->linesize *
+                                    vd->server->height);
+
+    /* guest surface */
+    if (!vd->guest.ds)
+        vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
+    if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
+        console_color_init(ds);
+    *(vd->guest.ds) = *(ds->surface);
+    memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_colordepth(vs);
+        vnc_desktop_resize(vs);
+        if (vs->vd->cursor) {
+            vnc_cursor_define(vs);
+        }
+        memset(vs->dirty, 0xFF, sizeof(vs->dirty));
+    }
+}
+
+/* fastest code */
+static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
+                                  void *pixels, int size)
+{
+    vnc_write(vs, pixels, size);
+}
+
+/* slowest but generic code. */
+void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
+{
+    uint8_t r, g, b;
+    VncDisplay *vd = vs->vd;
+
+    r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
+        vd->server->pf.rbits);
+    g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
+        vd->server->pf.gbits);
+    b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
+        vd->server->pf.bbits);
+    v = (r << vs->clientds.pf.rshift) |
+        (g << vs->clientds.pf.gshift) |
+        (b << vs->clientds.pf.bshift);
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 1:
+        buf[0] = v;
+        break;
+    case 2:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 8;
+            buf[1] = v;
+        } else {
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    default:
+    case 4:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 24;
+            buf[1] = v >> 16;
+            buf[2] = v >> 8;
+            buf[3] = v;
+        } else {
+            buf[3] = v >> 24;
+            buf[2] = v >> 16;
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    }
+}
+
+static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
+                                     void *pixels1, int size)
+{
+    uint8_t buf[4];
+
+    if (pf->bytes_per_pixel == 4) {
+        uint32_t *pixels = pixels1;
+        int n, i;
+        n = size >> 2;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (pf->bytes_per_pixel == 2) {
+        uint16_t *pixels = pixels1;
+        int n, i;
+        n = size >> 1;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (pf->bytes_per_pixel == 1) {
+        uint8_t *pixels = pixels1;
+        int n, i;
+        n = size;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else {
+        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
+    }
+}
+
+int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int i;
+    uint8_t *row;
+    VncDisplay *vd = vs->vd;
+
+    row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    for (i = 0; i < h; i++) {
+        vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
+        row += ds_get_linesize(vs->ds);
+    }
+    return 1;
+}
+
+int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    int n = 0;
+
+    switch(vs->vnc_encoding) {
+        case VNC_ENCODING_ZLIB:
+            n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
+            n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_TIGHT:
+            n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_TIGHT_PNG:
+            n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_ZRLE:
+            n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_ZYWRLE:
+            n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
+            break;
+        default:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+            n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+            break;
+    }
+    return n;
+}
+
+static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    /* send bitblit op to the vnc client */
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1); /* number of rects */
+    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
+    vnc_write_u16(vs, src_x);
+    vnc_write_u16(vs, src_y);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
+static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs, *vn;
+    uint8_t *src_row;
+    uint8_t *dst_row;
+    int i,x,y,pitch,depth,inc,w_lim,s;
+    int cmp_bytes;
+
+    vnc_refresh_server_surface(vd);
+    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vs->force_update = 1;
+            vnc_update_client_sync(vs, 1);
+            /* vs might be free()ed here */
+        }
+    }
+
+    /* do bitblit op on the local surface too */
+    pitch = ds_get_linesize(vd->ds);
+    depth = ds_get_bytes_per_pixel(vd->ds);
+    src_row = vd->server->data + pitch * src_y + depth * src_x;
+    dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
+    y = dst_y;
+    inc = 1;
+    if (dst_y > src_y) {
+        /* copy backwards */
+        src_row += pitch * (h-1);
+        dst_row += pitch * (h-1);
+        pitch = -pitch;
+        y = dst_y + h - 1;
+        inc = -1;
+    }
+    w_lim = w - (16 - (dst_x % 16));
+    if (w_lim < 0)
+        w_lim = w;
+    else
+        w_lim = w - (w_lim % 16);
+    for (i = 0; i < h; i++) {
+        for (x = 0; x <= w_lim;
+                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
+            if (x == w_lim) {
+                if ((s = w - w_lim) == 0)
+                    break;
+            } else if (!x) {
+                s = (16 - (dst_x % 16));
+                s = MIN(s, w_lim);
+            } else {
+                s = 16;
+            }
+            cmp_bytes = s * depth;
+            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
+                continue;
+            memmove(dst_row, src_row, cmp_bytes);
+            QTAILQ_FOREACH(vs, &vd->clients, next) {
+                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+                    set_bit(((x + dst_x) / 16), vs->dirty[y]);
+                }
+            }
+        }
+        src_row += pitch - w * depth;
+        dst_row += pitch - w * depth;
+        y += inc;
+    }
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
+        }
+    }
+}
+
+static void vnc_mouse_set(int x, int y, int visible)
+{
+    /* can we ask the client(s) to move the pointer ??? */
+}
+
+static int vnc_cursor_define(VncState *vs)
+{
+    QEMUCursor *c = vs->vd->cursor;
+    PixelFormat pf = qemu_default_pixelformat(32);
+    int isize;
+
+    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
+        vnc_lock_output(vs);
+        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs,  0);  /*  padding     */
+        vnc_write_u16(vs, 1);  /*  # of rects  */
+        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
+                               VNC_ENCODING_RICH_CURSOR);
+        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
+        vnc_write_pixels_generic(vs, &pf, c->data, isize);
+        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
+        vnc_unlock_output(vs);
+        return 0;
+    }
+    return -1;
+}
+
+static void vnc_dpy_cursor_define(QEMUCursor *c)
+{
+    VncDisplay *vd = vnc_display;
+    VncState *vs;
+
+    cursor_put(vd->cursor);
+    qemu_free(vd->cursor_mask);
+
+    vd->cursor = c;
+    cursor_get(vd->cursor);
+    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
+    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
+    cursor_get_mono_mask(c, 0, vd->cursor_mask);
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_cursor_define(vs);
+    }
+}
+
+static int find_and_clear_dirty_height(struct VncState *vs,
+                                       int y, int last_x, int x, int height)
+{
+    int h;
+
+    for (h = 1; h < (height - y); h++) {
+        int tmp_x;
+        if (!test_bit(last_x, vs->dirty[y + h])) {
+            break;
+        }
+        for (tmp_x = last_x; tmp_x < x; tmp_x++) {
+            clear_bit(tmp_x, vs->dirty[y + h]);
+        }
+    }
+
+    return h;
+}
+
+#ifdef CONFIG_VNC_THREAD
+static int vnc_update_client_sync(VncState *vs, int has_dirty)
+{
+    int ret = vnc_update_client(vs, has_dirty);
+    vnc_jobs_join(vs);
+    return ret;
+}
+#else
+static int vnc_update_client_sync(VncState *vs, int has_dirty)
+{
+    return vnc_update_client(vs, has_dirty);
+}
+#endif
+
+static int vnc_update_client(VncState *vs, int has_dirty)
+{
+    if (vs->need_update && vs->csock != -1) {
+        VncDisplay *vd = vs->vd;
+        VncJob *job;
+        int y;
+        int width, height;
+        int n = 0;
+
+
+        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
+            /* kernel send buffers are full -> drop frames to throttle */
+            return 0;
+
+        if (!has_dirty && !vs->audio_cap && !vs->force_update)
+            return 0;
+
+        /*
+         * Send screen updates to the vnc client using the server
+         * surface and server dirty map.  guest surface updates
+         * happening in parallel don't disturb us, the next pass will
+         * send them to the client.
+         */
+        job = vnc_job_new(vs);
+
+        width = MIN(vd->server->width, vs->client_width);
+        height = MIN(vd->server->height, vs->client_height);
+
+        for (y = 0; y < height; y++) {
+            int x;
+            int last_x = -1;
+            for (x = 0; x < width / 16; x++) {
+                if (test_and_clear_bit(x, vs->dirty[y])) {
+                    if (last_x == -1) {
+                        last_x = x;
+                    }
+                } else {
+                    if (last_x != -1) {
+                        int h = find_and_clear_dirty_height(vs, y, last_x, x,
+                                                            height);
+
+                        n += vnc_job_add_rect(job, last_x * 16, y,
+                                              (x - last_x) * 16, h);
+                    }
+                    last_x = -1;
+                }
+            }
+            if (last_x != -1) {
+                int h = find_and_clear_dirty_height(vs, y, last_x, x, height);
+                n += vnc_job_add_rect(job, last_x * 16, y,
+                                      (x - last_x) * 16, h);
+            }
+        }
+
+        vnc_job_push(job);
+        vs->force_update = 0;
+        return n;
+    }
+
+    if (vs->csock == -1)
+        vnc_disconnect_finish(vs);
+
+    return 0;
+}
+
+/* audio */
+static void audio_capture_notify(void *opaque, audcnotification_e cmd)
+{
+    VncState *vs = opaque;
+
+    switch (cmd) {
+    case AUD_CNOTIFY_DISABLE:
+        vnc_lock_output(vs);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
+        vnc_unlock_output(vs);
+        vnc_flush(vs);
+        break;
+
+    case AUD_CNOTIFY_ENABLE:
+        vnc_lock_output(vs);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
+        vnc_unlock_output(vs);
+        vnc_flush(vs);
+        break;
+    }
+}
+
+static void audio_capture_destroy(void *opaque)
+{
+}
+
+static void audio_capture(void *opaque, void *buf, int size)
+{
+    VncState *vs = opaque;
+
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+    vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
+static void audio_add(VncState *vs)
+{
+    struct audio_capture_ops ops;
+
+    if (vs->audio_cap) {
+        monitor_printf(default_mon, "audio already running\n");
+        return;
+    }
+
+    ops.notify = audio_capture_notify;
+    ops.destroy = audio_capture_destroy;
+    ops.capture = audio_capture;
+
+    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
+    if (!vs->audio_cap) {
+        monitor_printf(default_mon, "Failed to add audio capture\n");
+    }
+}
+
+static void audio_del(VncState *vs)
+{
+    if (vs->audio_cap) {
+        AUD_del_capture(vs->audio_cap, vs);
+        vs->audio_cap = NULL;
+    }
+}
+
+static void vnc_disconnect_start(VncState *vs)
+{
+    if (vs->csock == -1)
+        return;
+    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    closesocket(vs->csock);
+    vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+    int i;
+
+    vnc_jobs_join(vs); /* Wait encoding jobs */
+
+    vnc_lock_output(vs);
+    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
+
+    buffer_free(&vs->input);
+    buffer_free(&vs->output);
+
+    qobject_decref(vs->info);
+
+    vnc_zlib_clear(vs);
+    vnc_tight_clear(vs);
+    vnc_zrle_clear(vs);
+
+#ifdef CONFIG_VNC_TLS
+    vnc_tls_client_cleanup(vs);
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
+    audio_del(vs);
+
+    QTAILQ_REMOVE(&vs->vd->clients, vs, next);
+
+    if (QTAILQ_EMPTY(&vs->vd->clients)) {
+        dcl->idle = 1;
+    }
+
+    qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
+    vnc_remove_timer(vs->vd);
+    if (vs->vd->lock_key_sync)
+        qemu_remove_led_event_handler(vs->led);
+    vnc_unlock_output(vs);
+
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_destroy(&vs->output_mutex);
+#endif
+    for (i = 0; i < VNC_STAT_ROWS; ++i) {
+        qemu_free(vs->lossy_rect[i]);
+    }
+    qemu_free(vs->lossy_rect);
+    qemu_free(vs);
+}
+
+int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+{
+    if (ret == 0 || ret == -1) {
+        if (ret == -1) {
+            switch (last_errno) {
+                case EINTR:
+                case EAGAIN:
+#ifdef _WIN32
+                case WSAEWOULDBLOCK:
+#endif
+                    return 0;
+                default:
+                    break;
+            }
+        }
+
+        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
+                  ret, ret < 0 ? last_errno : 0);
+        vnc_disconnect_start(vs);
+
+        return 0;
+    }
+    return ret;
+}
+
+
+void vnc_client_error(VncState *vs)
+{
+    VNC_DEBUG("Closing down client sock: protocol error\n");
+    vnc_disconnect_start(vs);
+}
+
+
+/*
+ * Called to write a chunk of data to the client socket. The data may
+ * be the raw data, or may have already been encoded by SASL.
+ * The data will be written either straight onto the socket, or
+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes written, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_write(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = send(vs->csock, (const void *)data, datalen, 0);
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to write buffered data to the client socket, when not
+ * using any SASL SSF encryption layers. Will write as much data
+ * as possible without blocking. If all buffered data is written,
+ * will switch the FD poll() handler back to read monitoring.
+ *
+ * Returns the number of bytes written, which may be less than
+ * the buffered output data if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+static long vnc_client_write_plain(VncState *vs)
+{
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.waitWriteSSF);
+
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        vs->sasl.waitWriteSSF) {
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
+        if (ret)
+            vs->sasl.waitWriteSSF -= ret;
+    } else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
+    if (!ret)
+        return 0;
+
+    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
+    vs->output.offset -= ret;
+
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is data to be written to
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring encryption calls)
+ */
+static void vnc_client_write_locked(void *opaque)
+{
+    VncState *vs = opaque;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        !vs->sasl.waitWriteSSF) {
+        vnc_client_write_sasl(vs);
+    } else
+#endif /* CONFIG_VNC_SASL */
+        vnc_client_write_plain(vs);
+}
+
+void vnc_client_write(void *opaque)
+{
+    VncState *vs = opaque;
+
+    vnc_lock_output(vs);
+    if (vs->output.offset) {
+        vnc_client_write_locked(opaque);
+    } else if (vs->csock != -1) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+    vnc_unlock_output(vs);
+}
+
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+{
+    vs->read_handler = func;
+    vs->read_handler_expect = expecting;
+}
+
+
+/*
+ * Called to read a chunk of data from the client socket. The data may
+ * be the raw data, or may need to be further decoded by SASL.
+ * The data will be read either straight from to the socket, or
+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes read, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_read(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = qemu_recv(vs->csock, data, datalen, 0);
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to read data from the client socket to the input buffer,
+ * when not using any SASL SSF encryption layers. Will read as much
+ * data as possible without blocking.
+ *
+ * Returns the number of bytes read. Returns -1 on error, and
+ * disconnects the client socket.
+ */
+static long vnc_client_read_plain(VncState *vs)
+{
+    int ret;
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
+              vs->input.buffer, vs->input.capacity, vs->input.offset);
+    buffer_reserve(&vs->input, 4096);
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
+    if (!ret)
+        return 0;
+    vs->input.offset += ret;
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is more data to be read from
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring decryption calls)
+ */
+void vnc_client_read(void *opaque)
+{
+    VncState *vs = opaque;
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn && vs->sasl.runSSF)
+        ret = vnc_client_read_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_read_plain(vs);
+    if (!ret) {
+        if (vs->csock == -1)
+            vnc_disconnect_finish(vs);
+        return;
+    }
+
+    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
+        size_t len = vs->read_handler_expect;
+        int ret;
+
+        ret = vs->read_handler(vs, vs->input.buffer, len);
+        if (vs->csock == -1) {
+            vnc_disconnect_finish(vs);
+            return;
+        }
+
+        if (!ret) {
+            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+            vs->input.offset -= len;
+        } else {
+            vs->read_handler_expect = ret;
+        }
+    }
+}
+
+void vnc_write(VncState *vs, const void *data, size_t len)
+{
+    buffer_reserve(&vs->output, len);
+
+    if (vs->csock != -1 && buffer_empty(&vs->output)) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+    }
+
+    buffer_append(&vs->output, data, len);
+}
+
+void vnc_write_s32(VncState *vs, int32_t value)
+{
+    vnc_write_u32(vs, *(uint32_t *)&value);
+}
+
+void vnc_write_u32(VncState *vs, uint32_t value)
+{
+    uint8_t buf[4];
+
+    buf[0] = (value >> 24) & 0xFF;
+    buf[1] = (value >> 16) & 0xFF;
+    buf[2] = (value >>  8) & 0xFF;
+    buf[3] = value & 0xFF;
+
+    vnc_write(vs, buf, 4);
+}
+
+void vnc_write_u16(VncState *vs, uint16_t value)
+{
+    uint8_t buf[2];
+
+    buf[0] = (value >> 8) & 0xFF;
+    buf[1] = value & 0xFF;
+
+    vnc_write(vs, buf, 2);
+}
+
+void vnc_write_u8(VncState *vs, uint8_t value)
+{
+    vnc_write(vs, (char *)&value, 1);
+}
+
+void vnc_flush(VncState *vs)
+{
+    vnc_lock_output(vs);
+    if (vs->csock != -1 && vs->output.offset) {
+        vnc_client_write_locked(vs);
+    }
+    vnc_unlock_output(vs);
+}
+
+uint8_t read_u8(uint8_t *data, size_t offset)
+{
+    return data[offset];
+}
+
+uint16_t read_u16(uint8_t *data, size_t offset)
+{
+    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
+}
+
+int32_t read_s32(uint8_t *data, size_t offset)
+{
+    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
+                     (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+uint32_t read_u32(uint8_t *data, size_t offset)
+{
+    return ((data[offset] << 24) | (data[offset + 1] << 16) |
+            (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
+{
+}
+
+static void check_pointer_type_change(Notifier *notifier, void *data)
+{
+    VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
+    int absolute = kbd_mouse_is_absolute();
+
+    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
+        vnc_lock_output(vs);
+        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1);
+        vnc_framebuffer_update(vs, absolute, 0,
+                               ds_get_width(vs->ds), ds_get_height(vs->ds),
+                               VNC_ENCODING_POINTER_TYPE_CHANGE);
+        vnc_unlock_output(vs);
+        vnc_flush(vs);
+    }
+    vs->absolute = absolute;
+}
+
+static void pointer_event(VncState *vs, int button_mask, int x, int y)
+{
+    int buttons = 0;
+    int dz = 0;
+
+    if (button_mask & 0x01)
+        buttons |= MOUSE_EVENT_LBUTTON;
+    if (button_mask & 0x02)
+        buttons |= MOUSE_EVENT_MBUTTON;
+    if (button_mask & 0x04)
+        buttons |= MOUSE_EVENT_RBUTTON;
+    if (button_mask & 0x08)
+        dz = -1;
+    if (button_mask & 0x10)
+        dz = 1;
+
+    if (vs->absolute) {
+        kbd_mouse_event(ds_get_width(vs->ds) > 1 ?
+                          x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000,
+                        ds_get_height(vs->ds) > 1 ?
+                          y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000,
+                        dz, buttons);
+    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
+        x -= 0x7FFF;
+        y -= 0x7FFF;
+
+        kbd_mouse_event(x, y, dz, buttons);
+    } else {
+        if (vs->last_x != -1)
+            kbd_mouse_event(x - vs->last_x,
+                            y - vs->last_y,
+                            dz, buttons);
+        vs->last_x = x;
+        vs->last_y = y;
+    }
+}
+
+static void reset_keys(VncState *vs)
+{
+    int i;
+    for(i = 0; i < 256; i++) {
+        if (vs->modifiers_state[i]) {
+            if (i & SCANCODE_GREY)
+                kbd_put_keycode(SCANCODE_EMUL0);
+            kbd_put_keycode(i | SCANCODE_UP);
+            vs->modifiers_state[i] = 0;
+        }
+    }
+}
+
+static void press_key(VncState *vs, int keysym)
+{
+    int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+    if (keycode & SCANCODE_GREY)
+        kbd_put_keycode(SCANCODE_EMUL0);
+    kbd_put_keycode(keycode | SCANCODE_UP);
+}
+
+static void kbd_leds(void *opaque, int ledstate)
+{
+    VncState *vs = opaque;
+    int caps, num;
+
+    caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
+    num  = ledstate & QEMU_NUM_LOCK_LED  ? 1 : 0;
+
+    if (vs->modifiers_state[0x3a] != caps) {
+        vs->modifiers_state[0x3a] = caps;
+    }
+    if (vs->modifiers_state[0x45] != num) {
+        vs->modifiers_state[0x45] = num;
+    }
+}
+
+static void do_key_event(VncState *vs, int down, int keycode, int sym)
+{
+    /* QEMU console switch */
+    switch(keycode) {
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                          /* Right ALT */
+        if (down)
+            vs->modifiers_state[keycode] = 1;
+        else
+            vs->modifiers_state[keycode] = 0;
+        break;
+    case 0x02 ... 0x0a: /* '1' to '9' keys */
+        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+            /* Reset the modifiers sent to the current console */
+            reset_keys(vs);
+            console_select(keycode - 0x02);
+            return;
+        }
+        break;
+    case 0x3a:                        /* CapsLock */
+    case 0x45:                        /* NumLock */
+        if (down)
+            vs->modifiers_state[keycode] ^= 1;
+        break;
+    }
+
+    if (down && vs->vd->lock_key_sync &&
+        keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
+        /* If the numlock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles numlock away from the VNC window.
+        */
+        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
+            if (!vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 1;
+                press_key(vs, 0xff7f);
+            }
+        } else {
+            if (vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 0;
+                press_key(vs, 0xff7f);
+            }
+        }
+    }
+
+    if (down && vs->vd->lock_key_sync &&
+        ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
+        /* If the capslock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles capslock away from the VNC window.
+        */
+        int uppercase = !!(sym >= 'A' && sym <= 'Z');
+        int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
+        int capslock = !!(vs->modifiers_state[0x3a]);
+        if (capslock) {
+            if (uppercase == shift) {
+                vs->modifiers_state[0x3a] = 0;
+                press_key(vs, 0xffe5);
+            }
+        } else {
+            if (uppercase != shift) {
+                vs->modifiers_state[0x3a] = 1;
+                press_key(vs, 0xffe5);
+            }
+        }
+    }
+
+    if (is_graphic_console()) {
+        if (keycode & SCANCODE_GREY)
+            kbd_put_keycode(SCANCODE_EMUL0);
+        if (down)
+            kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+        else
+            kbd_put_keycode(keycode | SCANCODE_UP);
+    } else {
+        /* QEMU console emulation */
+        if (down) {
+            int numlock = vs->modifiers_state[0x45];
+            switch (keycode) {
+            case 0x2a:                          /* Left Shift */
+            case 0x36:                          /* Right Shift */
+            case 0x1d:                          /* Left CTRL */
+            case 0x9d:                          /* Right CTRL */
+            case 0x38:                          /* Left ALT */
+            case 0xb8:                          /* Right ALT */
+                break;
+            case 0xc8:
+                kbd_put_keysym(QEMU_KEY_UP);
+                break;
+            case 0xd0:
+                kbd_put_keysym(QEMU_KEY_DOWN);
+                break;
+            case 0xcb:
+                kbd_put_keysym(QEMU_KEY_LEFT);
+                break;
+            case 0xcd:
+                kbd_put_keysym(QEMU_KEY_RIGHT);
+                break;
+            case 0xd3:
+                kbd_put_keysym(QEMU_KEY_DELETE);
+                break;
+            case 0xc7:
+                kbd_put_keysym(QEMU_KEY_HOME);
+                break;
+            case 0xcf:
+                kbd_put_keysym(QEMU_KEY_END);
+                break;
+            case 0xc9:
+                kbd_put_keysym(QEMU_KEY_PAGEUP);
+                break;
+            case 0xd1:
+                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
+                break;
+
+            case 0x47:
+                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                break;
+            case 0x48:
+                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                break;
+            case 0x49:
+                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                break;
+            case 0x4b:
+                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                break;
+            case 0x4c:
+                kbd_put_keysym('5');
+                break;
+            case 0x4d:
+                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                break;
+            case 0x4f:
+                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                break;
+            case 0x50:
+                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                break;
+            case 0x51:
+                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                break;
+            case 0x52:
+                kbd_put_keysym('0');
+                break;
+            case 0x53:
+                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                break;
+
+            case 0xb5:
+                kbd_put_keysym('/');
+                break;
+            case 0x37:
+                kbd_put_keysym('*');
+                break;
+            case 0x4a:
+                kbd_put_keysym('-');
+                break;
+            case 0x4e:
+                kbd_put_keysym('+');
+                break;
+            case 0x9c:
+                kbd_put_keysym('\n');
+                break;
+
+            default:
+                kbd_put_keysym(sym);
+                break;
+            }
+        }
+    }
+}
+
+static void key_event(VncState *vs, int down, uint32_t sym)
+{
+    int keycode;
+    int lsym = sym;
+
+    if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
+        lsym = lsym - 'A' + 'a';
+    }
+
+    keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
+    do_key_event(vs, down, keycode, sym);
+}
+
+static void ext_key_event(VncState *vs, int down,
+                          uint32_t sym, uint16_t keycode)
+{
+    /* if the user specifies a keyboard layout, always use it */
+    if (keyboard_layout)
+        key_event(vs, down, sym);
+    else
+        do_key_event(vs, down, keycode, sym);
+}
+
+static void framebuffer_update_request(VncState *vs, int incremental,
+                                       int x_position, int y_position,
+                                       int w, int h)
+{
+    int i;
+    const size_t width = ds_get_width(vs->ds) / 16;
+
+    if (y_position > ds_get_height(vs->ds))
+        y_position = ds_get_height(vs->ds);
+    if (y_position + h >= ds_get_height(vs->ds))
+        h = ds_get_height(vs->ds) - y_position;
+
+    vs->need_update = 1;
+    if (!incremental) {
+        vs->force_update = 1;
+        for (i = 0; i < h; i++) {
+            bitmap_set(vs->dirty[y_position + i], 0, width);
+            bitmap_clear(vs->dirty[y_position + i], width,
+                         VNC_DIRTY_BITS - width);
+        }
+    }
+}
+
+static void send_ext_key_event_ack(VncState *vs)
+{
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_EXT_KEY_EVENT);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
+static void send_ext_audio_ack(VncState *vs)
+{
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_AUDIO);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
+static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+{
+    int i;
+    unsigned int enc = 0;
+
+    vs->features = 0;
+    vs->vnc_encoding = 0;
+    vs->tight.compression = 9;
+    vs->tight.quality = -1; /* Lossless by default */
+    vs->absolute = -1;
+
+    /*
+     * Start from the end because the encodings are sent in order of preference.
+     * This way the prefered encoding (first encoding defined in the array)
+     * will be set at the end of the loop.
+     */
+    for (i = n_encodings - 1; i >= 0; i--) {
+        enc = encodings[i];
+        switch (enc) {
+        case VNC_ENCODING_RAW:
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_COPYRECT:
+            vs->features |= VNC_FEATURE_COPYRECT_MASK;
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vs->features |= VNC_FEATURE_HEXTILE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_TIGHT:
+            vs->features |= VNC_FEATURE_TIGHT_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_TIGHT_PNG:
+            vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZLIB:
+            vs->features |= VNC_FEATURE_ZLIB_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZRLE:
+            vs->features |= VNC_FEATURE_ZRLE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZYWRLE:
+            vs->features |= VNC_FEATURE_ZYWRLE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_DESKTOPRESIZE:
+            vs->features |= VNC_FEATURE_RESIZE_MASK;
+            break;
+        case VNC_ENCODING_POINTER_TYPE_CHANGE:
+            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
+            break;
+        case VNC_ENCODING_RICH_CURSOR:
+            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
+            break;
+        case VNC_ENCODING_EXT_KEY_EVENT:
+            send_ext_key_event_ack(vs);
+            break;
+        case VNC_ENCODING_AUDIO:
+            send_ext_audio_ack(vs);
+            break;
+        case VNC_ENCODING_WMVi:
+            vs->features |= VNC_FEATURE_WMVI_MASK;
+            break;
+        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
+            vs->tight.compression = (enc & 0x0F);
+            break;
+        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
+            if (vs->vd->lossy) {
+                vs->tight.quality = (enc & 0x0F);
+            }
+            break;
+        default:
+            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
+            break;
+        }
+    }
+    vnc_desktop_resize(vs);
+    check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
+}
+
+static void set_pixel_conversion(VncState *vs)
+{
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
+        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
+        vs->write_pixels = vnc_write_pixels_copy;
+        vnc_hextile_set_pixel_conversion(vs, 0);
+    } else {
+        vs->write_pixels = vnc_write_pixels_generic;
+        vnc_hextile_set_pixel_conversion(vs, 1);
+    }
+}
+
+static void set_pixel_format(VncState *vs,
+                             int bits_per_pixel, int depth,
+                             int big_endian_flag, int true_color_flag,
+                             int red_max, int green_max, int blue_max,
+                             int red_shift, int green_shift, int blue_shift)
+{
+    if (!true_color_flag) {
+        vnc_client_error(vs);
+        return;
+    }
+
+    vs->clientds = *(vs->vd->guest.ds);
+    vs->clientds.pf.rmax = red_max;
+    vs->clientds.pf.rbits = hweight_long(red_max);
+    vs->clientds.pf.rshift = red_shift;
+    vs->clientds.pf.rmask = red_max << red_shift;
+    vs->clientds.pf.gmax = green_max;
+    vs->clientds.pf.gbits = hweight_long(green_max);
+    vs->clientds.pf.gshift = green_shift;
+    vs->clientds.pf.gmask = green_max << green_shift;
+    vs->clientds.pf.bmax = blue_max;
+    vs->clientds.pf.bbits = hweight_long(blue_max);
+    vs->clientds.pf.bshift = blue_shift;
+    vs->clientds.pf.bmask = blue_max << blue_shift;
+    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
+    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
+    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
+    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
+
+    set_pixel_conversion(vs);
+
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void pixel_format_message (VncState *vs) {
+    char pad[3] = { 0, 0, 0 };
+
+    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
+    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
+
+#ifdef HOST_WORDS_BIGENDIAN
+    vnc_write_u8(vs, 1);             /* big-endian-flag */
+#else
+    vnc_write_u8(vs, 0);             /* big-endian-flag */
+#endif
+    vnc_write_u8(vs, 1);             /* true-color-flag */
+    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
+    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
+
+    vnc_hextile_set_pixel_conversion(vs, 0);
+
+    vs->clientds = *(vs->ds->surface);
+    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
+    vs->write_pixels = vnc_write_pixels_copy;
+
+    vnc_write(vs, pad, 3);           /* padding */
+}
+
+static void vnc_dpy_setdata(DisplayState *ds)
+{
+    /* We don't have to do anything */
+}
+
+static void vnc_colordepth(VncState *vs)
+{
+    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
+        /* Sending a WMVi message to notify the client*/
+        vnc_lock_output(vs);
+        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1); /* number of rects */
+        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
+                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
+        pixel_format_message(vs);
+        vnc_unlock_output(vs);
+        vnc_flush(vs);
+    } else {
+        set_pixel_conversion(vs);
+    }
+}
+
+static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
+{
+    int i;
+    uint16_t limit;
+    VncDisplay *vd = vs->vd;
+
+    if (data[0] > 3) {
+        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+        if (!qemu_timer_expired(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval))
+            qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
+    }
+
+    switch (data[0]) {
+    case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
+        if (len == 1)
+            return 20;
+
+        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+                         read_u8(data, 6), read_u8(data, 7),
+                         read_u16(data, 8), read_u16(data, 10),
+                         read_u16(data, 12), read_u8(data, 14),
+                         read_u8(data, 15), read_u8(data, 16));
+        break;
+    case VNC_MSG_CLIENT_SET_ENCODINGS:
+        if (len == 1)
+            return 4;
+
+        if (len == 4) {
+            limit = read_u16(data, 2);
+            if (limit > 0)
+                return 4 + (limit * 4);
+        } else
+            limit = read_u16(data, 2);
+
+        for (i = 0; i < limit; i++) {
+            int32_t val = read_s32(data, 4 + (i * 4));
+            memcpy(data + 4 + (i * 4), &val, sizeof(val));
+        }
+
+        set_encodings(vs, (int32_t *)(data + 4), limit);
+        break;
+    case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
+        if (len == 1)
+            return 10;
+
+        framebuffer_update_request(vs,
+                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+                                   read_u16(data, 6), read_u16(data, 8));
+        break;
+    case VNC_MSG_CLIENT_KEY_EVENT:
+        if (len == 1)
+            return 8;
+
+        key_event(vs, read_u8(data, 1), read_u32(data, 4));
+        break;
+    case VNC_MSG_CLIENT_POINTER_EVENT:
+        if (len == 1)
+            return 6;
+
+        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+        break;
+    case VNC_MSG_CLIENT_CUT_TEXT:
+        if (len == 1)
+            return 8;
+
+        if (len == 8) {
+            uint32_t dlen = read_u32(data, 4);
+            if (dlen > 0)
+                return 8 + dlen;
+        }
+
+        client_cut_text(vs, read_u32(data, 4), data + 8);
+        break;
+    case VNC_MSG_CLIENT_QEMU:
+        if (len == 1)
+            return 2;
+
+        switch (read_u8(data, 1)) {
+        case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
+            if (len == 2)
+                return 12;
+
+            ext_key_event(vs, read_u16(data, 2),
+                          read_u32(data, 4), read_u32(data, 8));
+            break;
+        case VNC_MSG_CLIENT_QEMU_AUDIO:
+            if (len == 2)
+                return 4;
+
+            switch (read_u16 (data, 2)) {
+            case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
+                audio_add(vs);
+                break;
+            case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
+                audio_del(vs);
+                break;
+            case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
+                if (len == 4)
+                    return 10;
+                switch (read_u8(data, 4)) {
+                case 0: vs->as.fmt = AUD_FMT_U8; break;
+                case 1: vs->as.fmt = AUD_FMT_S8; break;
+                case 2: vs->as.fmt = AUD_FMT_U16; break;
+                case 3: vs->as.fmt = AUD_FMT_S16; break;
+                case 4: vs->as.fmt = AUD_FMT_U32; break;
+                case 5: vs->as.fmt = AUD_FMT_S32; break;
+                default:
+                    printf("Invalid audio format %d\n", read_u8(data, 4));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.nchannels = read_u8(data, 5);
+                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
+                    printf("Invalid audio channel coount %d\n",
+                           read_u8(data, 5));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.freq = read_u32(data, 6);
+                break;
+            default:
+                printf ("Invalid audio message %d\n", read_u8(data, 4));
+                vnc_client_error(vs);
+                break;
+            }
+            break;
+
+        default:
+            printf("Msg: %d\n", read_u16(data, 0));
+            vnc_client_error(vs);
+            break;
+        }
+        break;
+    default:
+        printf("Msg: %d\n", data[0]);
+        vnc_client_error(vs);
+        break;
+    }
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+    return 0;
+}
+
+static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
+{
+    char buf[1024];
+    int size;
+
+    vs->client_width = ds_get_width(vs->ds);
+    vs->client_height = ds_get_height(vs->ds);
+    vnc_write_u16(vs, vs->client_width);
+    vnc_write_u16(vs, vs->client_height);
+
+    pixel_format_message(vs);
+
+    if (qemu_name)
+        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
+    else
+        size = snprintf(buf, sizeof(buf), "QEMU");
+
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
+
+    vnc_client_cache_auth(vs);
+    vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+
+    return 0;
+}
+
+void start_client_init(VncState *vs)
+{
+    vnc_read_when(vs, protocol_client_init, 1);
+}
+
+static void make_challenge(VncState *vs)
+{
+    int i;
+
+    srand(time(NULL)+getpid()+getpid()*987654+rand());
+
+    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
+        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
+}
+
+static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
+{
+    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
+    int i, j, pwlen;
+    unsigned char key[8];
+    time_t now = time(NULL);
+
+    if (!vs->vd->password) {
+        VNC_DEBUG("No password configured on server");
+        goto reject;
+    }
+    if (vs->vd->expires < now) {
+        VNC_DEBUG("Password is expired");
+        goto reject;
+    }
+
+    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
+
+    /* Calculate the expected challenge response */
+    pwlen = strlen(vs->vd->password);
+    for (i=0; i<sizeof(key); i++)
+        key[i] = i<pwlen ? vs->vd->password[i] : 0;
+    deskey(key, EN0);
+    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
+        des(response+j, response+j);
+
+    /* Compare expected vs actual challenge response */
+    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
+        VNC_DEBUG("Client challenge reponse did not match\n");
+        goto reject;
+    } else {
+        VNC_DEBUG("Accepting VNC challenge response\n");
+        vnc_write_u32(vs, 0); /* Accept auth */
+        vnc_flush(vs);
+
+        start_client_init(vs);
+    }
+    return 0;
+
+reject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    if (vs->minor >= 8) {
+        static const char err[] = "Authentication failed";
+        vnc_write_u32(vs, sizeof(err));
+        vnc_write(vs, err, sizeof(err));
+    }
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return 0;
+}
+
+void start_auth_vnc(VncState *vs)
+{
+    make_challenge(vs);
+    /* Send client a 'random' challenge */
+    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
+    vnc_flush(vs);
+
+    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
+}
+
+
+static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
+{
+    /* We only advertise 1 auth scheme at a time, so client
+     * must pick the one we sent. Verify this */
+    if (data[0] != vs->auth) { /* Reject auth */
+       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
+       vnc_write_u32(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Authentication failed";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    } else { /* Accept requested auth */
+       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
+       switch (vs->auth) {
+       case VNC_AUTH_NONE:
+           VNC_DEBUG("Accept auth none\n");
+           if (vs->minor >= 8) {
+               vnc_write_u32(vs, 0); /* Accept auth completion */
+               vnc_flush(vs);
+           }
+           start_client_init(vs);
+           break;
+
+       case VNC_AUTH_VNC:
+           VNC_DEBUG("Start VNC auth\n");
+           start_auth_vnc(vs);
+           break;
+
+#ifdef CONFIG_VNC_TLS
+       case VNC_AUTH_VENCRYPT:
+           VNC_DEBUG("Accept VeNCrypt auth\n");;
+           start_auth_vencrypt(vs);
+           break;
+#endif /* CONFIG_VNC_TLS */
+
+#ifdef CONFIG_VNC_SASL
+       case VNC_AUTH_SASL:
+           VNC_DEBUG("Accept SASL auth\n");
+           start_auth_sasl(vs);
+           break;
+#endif /* CONFIG_VNC_SASL */
+
+       default: /* Should not be possible, but just in case */
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
+           vnc_write_u8(vs, 1);
+           if (vs->minor >= 8) {
+               static const char err[] = "Authentication failed";
+               vnc_write_u32(vs, sizeof(err));
+               vnc_write(vs, err, sizeof(err));
+           }
+           vnc_client_error(vs);
+       }
+    }
+    return 0;
+}
+
+static int protocol_version(VncState *vs, uint8_t *version, size_t len)
+{
+    char local[13];
+
+    memcpy(local, version, 12);
+    local[12] = 0;
+
+    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
+        VNC_DEBUG("Malformed protocol version %s\n", local);
+        vnc_client_error(vs);
+        return 0;
+    }
+    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
+    if (vs->major != 3 ||
+        (vs->minor != 3 &&
+         vs->minor != 4 &&
+         vs->minor != 5 &&
+         vs->minor != 7 &&
+         vs->minor != 8)) {
+        VNC_DEBUG("Unsupported client version\n");
+        vnc_write_u32(vs, VNC_AUTH_INVALID);
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
+    }
+    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
+     * as equivalent to v3.3 by servers
+     */
+    if (vs->minor == 4 || vs->minor == 5)
+        vs->minor = 3;
+
+    if (vs->minor == 3) {
+        if (vs->auth == VNC_AUTH_NONE) {
+            VNC_DEBUG("Tell client auth none\n");
+            vnc_write_u32(vs, vs->auth);
+            vnc_flush(vs);
+            start_client_init(vs);
+       } else if (vs->auth == VNC_AUTH_VNC) {
+            VNC_DEBUG("Tell client VNC auth\n");
+            vnc_write_u32(vs, vs->auth);
+            vnc_flush(vs);
+            start_auth_vnc(vs);
+       } else {
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
+            vnc_write_u32(vs, VNC_AUTH_INVALID);
+            vnc_flush(vs);
+            vnc_client_error(vs);
+       }
+    } else {
+        VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
+        vnc_write_u8(vs, 1); /* num auth */
+        vnc_write_u8(vs, vs->auth);
+        vnc_read_when(vs, protocol_client_auth, 1);
+        vnc_flush(vs);
+    }
+
+    return 0;
+}
+
+static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
+{
+    struct VncSurface *vs = &vd->guest;
+
+    return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
+}
+
+void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
+{
+    int i, j;
+
+    w = (x + w) / VNC_STAT_RECT;
+    h = (y + h) / VNC_STAT_RECT;
+    x /= VNC_STAT_RECT;
+    y /= VNC_STAT_RECT;
+
+    for (j = y; j <= h; j++) {
+        for (i = x; i <= w; i++) {
+            vs->lossy_rect[j][i] = 1;
+        }
+    }
+}
+
+static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
+{
+    VncState *vs;
+    int sty = y / VNC_STAT_RECT;
+    int stx = x / VNC_STAT_RECT;
+    int has_dirty = 0;
+
+    y = y / VNC_STAT_RECT * VNC_STAT_RECT;
+    x = x / VNC_STAT_RECT * VNC_STAT_RECT;
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        int j;
+
+        /* kernel send buffers are full -> refresh later */
+        if (vs->output.offset) {
+            continue;
+        }
+
+        if (!vs->lossy_rect[sty][stx]) {
+            continue;
+        }
+
+        vs->lossy_rect[sty][stx] = 0;
+        for (j = 0; j < VNC_STAT_RECT; ++j) {
+            bitmap_set(vs->dirty[y + j], x / 16, VNC_STAT_RECT / 16);
+        }
+        has_dirty++;
+    }
+
+    return has_dirty;
+}
+
+static int vnc_update_stats(VncDisplay *vd,  struct timeval * tv)
+{
+    int x, y;
+    struct timeval res;
+    int has_dirty = 0;
+
+    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
+        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+            VncRectStat *rect = vnc_stat_rect(vd, x, y);
+
+            rect->updated = false;
+        }
+    }
+
+    qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
+
+    if (timercmp(&vd->guest.last_freq_check, &res, >)) {
+        return has_dirty;
+    }
+    vd->guest.last_freq_check = *tv;
+
+    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
+        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+            VncRectStat *rect= vnc_stat_rect(vd, x, y);
+            int count = ARRAY_SIZE(rect->times);
+            struct timeval min, max;
+
+            if (!timerisset(&rect->times[count - 1])) {
+                continue ;
+            }
+
+            max = rect->times[(rect->idx + count - 1) % count];
+            qemu_timersub(tv, &max, &res);
+
+            if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
+                rect->freq = 0;
+                has_dirty += vnc_refresh_lossy_rect(vd, x, y);
+                memset(rect->times, 0, sizeof (rect->times));
+                continue ;
+            }
+
+            min = rect->times[rect->idx];
+            max = rect->times[(rect->idx + count - 1) % count];
+            qemu_timersub(&max, &min, &res);
+
+            rect->freq = res.tv_sec + res.tv_usec / 1000000.;
+            rect->freq /= count;
+            rect->freq = 1. / rect->freq;
+        }
+    }
+    return has_dirty;
+}
+
+double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
+{
+    int i, j;
+    double total = 0;
+    int num = 0;
+
+    x =  (x / VNC_STAT_RECT) * VNC_STAT_RECT;
+    y =  (y / VNC_STAT_RECT) * VNC_STAT_RECT;
+
+    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
+        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
+            total += vnc_stat_rect(vs->vd, i, j)->freq;
+            num++;
+        }
+    }
+
+    if (num) {
+        return total / num;
+    } else {
+        return 0;
+    }
+}
+
+static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
+{
+    VncRectStat *rect;
+
+    rect = vnc_stat_rect(vd, x, y);
+    if (rect->updated) {
+        return ;
+    }
+    rect->times[rect->idx] = *tv;
+    rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
+    rect->updated = true;
+}
+
+static int vnc_refresh_server_surface(VncDisplay *vd)
+{
+    int y;
+    uint8_t *guest_row;
+    uint8_t *server_row;
+    int cmp_bytes;
+    VncState *vs;
+    int has_dirty = 0;
+
+    struct timeval tv = { 0, 0 };
+
+    if (!vd->non_adaptive) {
+        gettimeofday(&tv, NULL);
+        has_dirty = vnc_update_stats(vd, &tv);
+    }
+
+    /*
+     * Walk through the guest dirty map.
+     * Check and copy modified bits from guest to server surface.
+     * Update server dirty map.
+     */
+    cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
+    guest_row  = vd->guest.ds->data;
+    server_row = vd->server->data;
+    for (y = 0; y < vd->guest.ds->height; y++) {
+        if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) {
+            int x;
+            uint8_t *guest_ptr;
+            uint8_t *server_ptr;
+
+            guest_ptr  = guest_row;
+            server_ptr = server_row;
+
+            for (x = 0; x < vd->guest.ds->width;
+                    x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+                if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
+                    continue;
+                if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
+                    continue;
+                memcpy(server_ptr, guest_ptr, cmp_bytes);
+                if (!vd->non_adaptive)
+                    vnc_rect_updated(vd, x, y, &tv);
+                QTAILQ_FOREACH(vs, &vd->clients, next) {
+                    set_bit((x / 16), vs->dirty[y]);
+                }
+                has_dirty++;
+            }
+        }
+        guest_row  += ds_get_linesize(vd->ds);
+        server_row += ds_get_linesize(vd->ds);
+    }
+    return has_dirty;
+}
+
+static void vnc_refresh(void *opaque)
+{
+    VncDisplay *vd = opaque;
+    VncState *vs, *vn;
+    int has_dirty, rects = 0;
+
+    vga_hw_update();
+
+    if (vnc_trylock_display(vd)) {
+        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+        qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) +
+                       vd->timer_interval);
+        return;
+    }
+
+    has_dirty = vnc_refresh_server_surface(vd);
+    vnc_unlock_display(vd);
+
+    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
+        rects += vnc_update_client(vs, has_dirty);
+        /* vs might be free()ed here */
+    }
+
+    /* vd->timer could be NULL now if the last client disconnected,
+     * in this case don't update the timer */
+    if (vd->timer == NULL)
+        return;
+
+    if (has_dirty && rects) {
+        vd->timer_interval /= 2;
+        if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+    } else {
+        vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
+        if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
+    }
+    qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
+}
+
+static void vnc_init_timer(VncDisplay *vd)
+{
+    vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+    if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) {
+        vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd);
+        vnc_dpy_resize(vd->ds);
+        vnc_refresh(vd);
+    }
+}
+
+static void vnc_remove_timer(VncDisplay *vd)
+{
+    if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) {
+        qemu_del_timer(vd->timer);
+        qemu_free_timer(vd->timer);
+        vd->timer = NULL;
+    }
+}
+
+static void vnc_connect(VncDisplay *vd, int csock, int skipauth)
+{
+    VncState *vs = qemu_mallocz(sizeof(VncState));
+    int i;
+
+    vs->csock = csock;
+
+    if (skipauth) {
+	vs->auth = VNC_AUTH_NONE;
+#ifdef CONFIG_VNC_TLS
+	vs->subauth = VNC_AUTH_INVALID;
+#endif
+    } else {
+	vs->auth = vd->auth;
+#ifdef CONFIG_VNC_TLS
+	vs->subauth = vd->subauth;
+#endif
+    }
+
+    vs->lossy_rect = qemu_mallocz(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
+    for (i = 0; i < VNC_STAT_ROWS; ++i) {
+        vs->lossy_rect[i] = qemu_mallocz(VNC_STAT_COLS * sizeof (uint8_t));
+    }
+
+    VNC_DEBUG("New client on socket %d\n", csock);
+    dcl->idle = 0;
+    socket_set_nonblock(vs->csock);
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+
+    vnc_client_cache_addr(vs);
+    vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
+
+    vs->vd = vd;
+    vs->ds = vd->ds;
+    vs->last_x = -1;
+    vs->last_y = -1;
+
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
+
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_init(&vs->output_mutex);
+#endif
+
+    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
+
+    vga_hw_update();
+
+    vnc_write(vs, "RFB 003.008\n", 12);
+    vnc_flush(vs);
+    vnc_read_when(vs, protocol_version, 12);
+    reset_keys(vs);
+    if (vs->vd->lock_key_sync)
+        vs->led = qemu_add_led_event_handler(kbd_leds, vs);
+
+    vs->mouse_mode_notifier.notify = check_pointer_type_change;
+    qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
+
+    vnc_init_timer(vd);
+
+    /* vs might be free()ed here */
+}
+
+static void vnc_listen_read(void *opaque)
+{
+    VncDisplay *vs = opaque;
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
+
+    /* Catch-up */
+    vga_hw_update();
+
+    int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+    if (csock != -1) {
+        vnc_connect(vs, csock, 0);
+    }
+}
+
+void vnc_display_init(DisplayState *ds)
+{
+    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+
+    ds->opaque = vs;
+    dcl->idle = 1;
+    vnc_display = vs;
+
+    vs->lsock = -1;
+
+    vs->ds = ds;
+    QTAILQ_INIT(&vs->clients);
+    vs->expires = TIME_MAX;
+
+    if (keyboard_layout)
+        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+    else
+        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+
+    if (!vs->kbd_layout)
+        exit(1);
+
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_init(&vs->mutex);
+    vnc_start_worker_thread();
+#endif
+
+    dcl->dpy_copy = vnc_dpy_copy;
+    dcl->dpy_update = vnc_dpy_update;
+    dcl->dpy_resize = vnc_dpy_resize;
+    dcl->dpy_setdata = vnc_dpy_setdata;
+    register_displaychangelistener(ds, dcl);
+    ds->mouse_set = vnc_mouse_set;
+    ds->cursor_define = vnc_dpy_cursor_define;
+}
+
+
+void vnc_display_close(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (!vs)
+        return;
+    if (vs->display) {
+        qemu_free(vs->display);
+        vs->display = NULL;
+    }
+    if (vs->lsock != -1) {
+        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        close(vs->lsock);
+        vs->lsock = -1;
+    }
+    vs->auth = VNC_AUTH_INVALID;
+#ifdef CONFIG_VNC_TLS
+    vs->subauth = VNC_AUTH_INVALID;
+    vs->tls.x509verify = 0;
+#endif
+}
+
+int vnc_display_disable_login(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (!vs) {
+        return -1;
+    }
+
+    if (vs->password) {
+        qemu_free(vs->password);
+    }
+
+    vs->password = NULL;
+    vs->auth = VNC_AUTH_VNC;
+
+    return 0;
+}
+
+int vnc_display_password(DisplayState *ds, const char *password)
+{
+    int ret = 0;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (!vs) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    if (!password) {
+        /* This is not the intention of this interface but err on the side
+           of being safe */
+        ret = vnc_display_disable_login(ds);
+        goto out;
+    }
+
+    if (vs->password) {
+        qemu_free(vs->password);
+        vs->password = NULL;
+    }
+    vs->password = qemu_strdup(password);
+    vs->auth = VNC_AUTH_VNC;
+out:
+    if (ret != 0) {
+        qerror_report(QERR_SET_PASSWD_FAILED);
+    }
+    return ret;
+}
+
+int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    vs->expires = expires;
+    return 0;
+}
+
+char *vnc_display_local_addr(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    
+    return vnc_socket_local_addr("%s:%s", vs->lsock);
+}
+
+int vnc_display_open(DisplayState *ds, const char *display)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    const char *options;
+    int password = 0;
+    int reverse = 0;
+#ifdef CONFIG_VNC_TLS
+    int tls = 0, x509 = 0;
+#endif
+#ifdef CONFIG_VNC_SASL
+    int sasl = 0;
+    int saslErr;
+#endif
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
+    int acl = 0;
+#endif
+    int lock_key_sync = 1;
+
+    if (!vnc_display)
+        return -1;
+    vnc_display_close(ds);
+    if (strcmp(display, "none") == 0)
+        return 0;
+
+    if (!(vs->display = strdup(display)))
+        return -1;
+
+    options = display;
+    while ((options = strchr(options, ','))) {
+        options++;
+        if (strncmp(options, "password", 8) == 0) {
+            password = 1; /* Require password auth */
+        } else if (strncmp(options, "reverse", 7) == 0) {
+            reverse = 1;
+        } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
+            lock_key_sync = 0;
+#ifdef CONFIG_VNC_SASL
+        } else if (strncmp(options, "sasl", 4) == 0) {
+            sasl = 1; /* Require SASL auth */
+#endif
+#ifdef CONFIG_VNC_TLS
+        } else if (strncmp(options, "tls", 3) == 0) {
+            tls = 1; /* Require TLS */
+        } else if (strncmp(options, "x509", 4) == 0) {
+            char *start, *end;
+            x509 = 1; /* Require x509 certificates */
+            if (strncmp(options, "x509verify", 10) == 0)
+                vs->tls.x509verify = 1; /* ...and verify client certs */
+
+            /* Now check for 'x509=/some/path' postfix
+             * and use that to setup x509 certificate/key paths */
+            start = strchr(options, '=');
+            end = strchr(options, ',');
+            if (start && (!end || (start < end))) {
+                int len = end ? end-(start+1) : strlen(start+1);
+                char *path = qemu_strndup(start + 1, len);
+
+                VNC_DEBUG("Trying certificate path '%s'\n", path);
+                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+                    qemu_free(path);
+                    qemu_free(vs->display);
+                    vs->display = NULL;
+                    return -1;
+                }
+                qemu_free(path);
+            } else {
+                fprintf(stderr, "No certificate path provided\n");
+                qemu_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
+#endif
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
+        } else if (strncmp(options, "acl", 3) == 0) {
+            acl = 1;
+#endif
+        } else if (strncmp(options, "lossy", 5) == 0) {
+            vs->lossy = true;
+        } else if (strncmp(options, "non-adapative", 13) == 0) {
+            vs->non_adaptive = true;
+        }
+    }
+
+#ifdef CONFIG_VNC_TLS
+    if (acl && x509 && vs->tls.x509verify) {
+        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+            fprintf(stderr, "Failed to create x509 dname ACL\n");
+            exit(1);
+        }
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (acl && sasl) {
+        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+            fprintf(stderr, "Failed to create username ACL\n");
+            exit(1);
+        }
+    }
+#endif
+
+    /*
+     * Combinations we support here:
+     *
+     *  - no-auth                (clear text, no auth)
+     *  - password               (clear text, weak auth)
+     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
+     *  - tls                    (encrypt, weak anonymous creds, no auth)
+     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
+     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
+     *  - tls + x509             (encrypt, good x509 creds, no auth)
+     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
+     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
+     *
+     * NB1. TLS is a stackable auth scheme.
+     * NB2. the x509 schemes have option to validate a client cert dname
+     */
+    if (password) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with password auth\n");
+            vs->auth = VNC_AUTH_VNC;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    } else if (sasl) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            vs->auth = VNC_AUTH_SASL;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#endif /* CONFIG_VNC_SASL */
+    } else {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+            }
+        } else {
+#endif
+            VNC_DEBUG("Initializing VNC server with no auth\n");
+            vs->auth = VNC_AUTH_NONE;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif
+    }
+
+#ifdef CONFIG_VNC_SASL
+    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
+        fprintf(stderr, "Failed to initialize SASL auth %s",
+                sasl_errstring(saslErr, NULL, NULL));
+        free(vs->display);
+        vs->display = NULL;
+        return -1;
+    }
+#endif
+    vs->lock_key_sync = lock_key_sync;
+
+    if (reverse) {
+        /* connect to viewer */
+        if (strncmp(display, "unix:", 5) == 0)
+            vs->lsock = unix_connect(display+5);
+        else
+            vs->lsock = inet_connect(display, SOCK_STREAM);
+        if (-1 == vs->lsock) {
+            free(vs->display);
+            vs->display = NULL;
+            return -1;
+        } else {
+            int csock = vs->lsock;
+            vs->lsock = -1;
+            vnc_connect(vs, csock, 0);
+        }
+        return 0;
+
+    } else {
+        /* listen for connects */
+        char *dpy;
+        dpy = qemu_malloc(256);
+        if (strncmp(display, "unix:", 5) == 0) {
+            pstrcpy(dpy, 256, "unix:");
+            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+        } else {
+            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
+        }
+        if (-1 == vs->lsock) {
+            free(dpy);
+            return -1;
+        } else {
+            free(vs->display);
+            vs->display = dpy;
+        }
+    }
+    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
+}
+
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    return vnc_connect(vs, csock, skipauth);
+}
diff --git a/qemu-0.15.x/ui/vnc.h b/qemu-0.15.x/ui/vnc.h
new file mode 100644
index 0000000..66689f1
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc.h
@@ -0,0 +1,556 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * 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 __QEMU_VNC_H
+#define __QEMU_VNC_H
+
+#include "qemu-common.h"
+#include "qemu-queue.h"
+#ifdef CONFIG_VNC_THREAD
+#include "qemu-thread.h"
+#endif
+#include "console.h"
+#include "monitor.h"
+#include "audio/audio.h"
+#include "bitmap.h"
+#include <zlib.h>
+#include <stdbool.h>
+
+#include "keymaps.h"
+#include "vnc-palette.h"
+#include "vnc-enc-zrle.h"
+
+// #define _VNC_DEBUG 1
+
+#ifdef _VNC_DEBUG
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define VNC_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+/*****************************************************************************
+ *
+ * Core data structures
+ *
+ *****************************************************************************/
+
+typedef struct Buffer
+{
+    size_t capacity;
+    size_t offset;
+    uint8_t *buffer;
+} Buffer;
+
+typedef struct VncState VncState;
+typedef struct VncJob VncJob;
+typedef struct VncRect VncRect;
+typedef struct VncRectEntry VncRectEntry;
+
+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
+
+typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
+
+typedef void VncSendHextileTile(VncState *vs,
+                                int x, int y, int w, int h,
+                                void *last_bg,
+                                void *last_fg,
+                                int *has_bg, int *has_fg);
+
+/* VNC_MAX_WIDTH must be a multiple of 16. */
+#define VNC_MAX_WIDTH 2560
+#define VNC_MAX_HEIGHT 2048
+
+/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
+#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / 16)
+
+#define VNC_STAT_RECT  64
+#define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT)
+#define VNC_STAT_ROWS (VNC_MAX_HEIGHT / VNC_STAT_RECT)
+
+#define VNC_AUTH_CHALLENGE_SIZE 16
+
+typedef struct VncDisplay VncDisplay;
+
+#ifdef CONFIG_VNC_TLS
+#include "vnc-tls.h"
+#include "vnc-auth-vencrypt.h"
+#endif
+#ifdef CONFIG_VNC_SASL
+#include "vnc-auth-sasl.h"
+#endif
+
+struct VncRectStat
+{
+    /* time of last 10 updates, to find update frequency */
+    struct timeval times[10];
+    int idx;
+
+    double freq;        /* Update frequency (in Hz) */
+    bool updated;       /* Already updated during this refresh */
+};
+
+typedef struct VncRectStat VncRectStat;
+
+struct VncSurface
+{
+    struct timeval last_freq_check;
+    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
+    VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
+    DisplaySurface *ds;
+};
+
+struct VncDisplay
+{
+    QTAILQ_HEAD(, VncState) clients;
+    QEMUTimer *timer;
+    int timer_interval;
+    int lsock;
+    DisplayState *ds;
+    kbd_layout_t *kbd_layout;
+    int lock_key_sync;
+#ifdef CONFIG_VNC_THREAD
+    QemuMutex mutex;
+#endif
+
+    QEMUCursor *cursor;
+    int cursor_msize;
+    uint8_t *cursor_mask;
+
+    struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
+    DisplaySurface *server;  /* vnc server surface */
+
+    char *display;
+    char *password;
+    time_t expires;
+    int auth;
+    bool lossy;
+    bool non_adaptive;
+#ifdef CONFIG_VNC_TLS
+    int subauth; /* Used by VeNCrypt */
+    VncDisplayTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncDisplaySASL sasl;
+#endif
+};
+
+typedef struct VncTight {
+    int type;
+    uint8_t quality;
+    uint8_t compression;
+    uint8_t pixel24;
+    Buffer tight;
+    Buffer tmp;
+    Buffer zlib;
+    Buffer gradient;
+#ifdef CONFIG_VNC_JPEG
+    Buffer jpeg;
+#endif
+#ifdef CONFIG_VNC_PNG
+    Buffer png;
+#endif
+    int levels[4];
+    z_stream stream[4];
+} VncTight;
+
+typedef struct VncHextile {
+    VncSendHextileTile *send_tile;
+} VncHextile;
+
+typedef struct VncZlib {
+    Buffer zlib;
+    Buffer tmp;
+    z_stream stream;
+    int level;
+} VncZlib;
+
+typedef struct VncZrle {
+    int type;
+    Buffer fb;
+    Buffer zrle;
+    Buffer tmp;
+    Buffer zlib;
+    z_stream stream;
+    VncPalette palette;
+} VncZrle;
+
+typedef struct VncZywrle {
+    int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT];
+} VncZywrle;
+
+#ifdef CONFIG_VNC_THREAD
+struct VncRect
+{
+    int x;
+    int y;
+    int w;
+    int h;
+};
+
+struct VncRectEntry
+{
+    struct VncRect rect;
+    QLIST_ENTRY(VncRectEntry) next;
+};
+
+struct VncJob
+{
+    VncState *vs;
+
+    QLIST_HEAD(, VncRectEntry) rectangles;
+    QTAILQ_ENTRY(VncJob) next;
+};
+#else
+struct VncJob
+{
+    VncState *vs;
+    int rectangles;
+    size_t saved_offset;
+};
+#endif
+
+struct VncState
+{
+    int csock;
+
+    DisplayState *ds;
+    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS);
+    uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in
+                           * vnc-jobs-async.c */
+
+    VncDisplay *vd;
+    int need_update;
+    int force_update;
+    uint32_t features;
+    int absolute;
+    int last_x;
+    int last_y;
+    int client_width;
+    int client_height;
+
+    uint32_t vnc_encoding;
+
+    int major;
+    int minor;
+
+    int auth;
+    char challenge[VNC_AUTH_CHALLENGE_SIZE];
+#ifdef CONFIG_VNC_TLS
+    int subauth; /* Used by VeNCrypt */
+    VncStateTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncStateSASL sasl;
+#endif
+
+    QObject *info;
+
+    Buffer output;
+    Buffer input;
+    /* current output mode information */
+    VncWritePixels *write_pixels;
+    DisplaySurface clientds;
+
+    CaptureVoiceOut *audio_cap;
+    struct audsettings as;
+
+    VncReadEvent *read_handler;
+    size_t read_handler_expect;
+    /* input */
+    uint8_t modifiers_state[256];
+    QEMUPutLEDEntry *led;
+
+    bool abort;
+#ifndef CONFIG_VNC_THREAD
+    VncJob job;
+#else
+    QemuMutex output_mutex;
+#endif
+
+    /* Encoding specific, if you add something here, don't forget to
+     *  update vnc_async_encoding_start()
+     */
+    VncTight tight;
+    VncZlib zlib;
+    VncHextile hextile;
+    VncZrle zrle;
+    VncZywrle zywrle;
+
+    Notifier mouse_mode_notifier;
+
+    QTAILQ_ENTRY(VncState) next;
+};
+
+
+/*****************************************************************************
+ *
+ * Authentication modes
+ *
+ *****************************************************************************/
+
+enum {
+    VNC_AUTH_INVALID = 0,
+    VNC_AUTH_NONE = 1,
+    VNC_AUTH_VNC = 2,
+    VNC_AUTH_RA2 = 5,
+    VNC_AUTH_RA2NE = 6,
+    VNC_AUTH_TIGHT = 16,
+    VNC_AUTH_ULTRA = 17,
+    VNC_AUTH_TLS = 18,      /* Supported in GTK-VNC & VINO */
+    VNC_AUTH_VENCRYPT = 19, /* Supported in GTK-VNC & VeNCrypt */
+    VNC_AUTH_SASL = 20,     /* Supported in GTK-VNC & VINO */
+};
+
+enum {
+    VNC_AUTH_VENCRYPT_PLAIN = 256,
+    VNC_AUTH_VENCRYPT_TLSNONE = 257,
+    VNC_AUTH_VENCRYPT_TLSVNC = 258,
+    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+    VNC_AUTH_VENCRYPT_X509NONE = 260,
+    VNC_AUTH_VENCRYPT_X509VNC = 261,
+    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
+    VNC_AUTH_VENCRYPT_X509SASL = 263,
+    VNC_AUTH_VENCRYPT_TLSSASL = 264,
+};
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define VNC_ENCODING_RAW                  0x00000000
+#define VNC_ENCODING_COPYRECT             0x00000001
+#define VNC_ENCODING_RRE                  0x00000002
+#define VNC_ENCODING_CORRE                0x00000004
+#define VNC_ENCODING_HEXTILE              0x00000005
+#define VNC_ENCODING_ZLIB                 0x00000006
+#define VNC_ENCODING_TIGHT                0x00000007
+#define VNC_ENCODING_ZLIBHEX              0x00000008
+#define VNC_ENCODING_TRLE                 0x0000000f
+#define VNC_ENCODING_ZRLE                 0x00000010
+#define VNC_ENCODING_ZYWRLE               0x00000011
+#define VNC_ENCODING_COMPRESSLEVEL0       0xFFFFFF00 /* -256 */
+#define VNC_ENCODING_QUALITYLEVEL0        0xFFFFFFE0 /* -32  */
+#define VNC_ENCODING_XCURSOR              0xFFFFFF10 /* -240 */
+#define VNC_ENCODING_RICH_CURSOR          0xFFFFFF11 /* -239 */
+#define VNC_ENCODING_POINTER_POS          0xFFFFFF18 /* -232 */
+#define VNC_ENCODING_LASTRECT             0xFFFFFF20 /* -224 */
+#define VNC_ENCODING_DESKTOPRESIZE        0xFFFFFF21 /* -223 */
+#define VNC_ENCODING_POINTER_TYPE_CHANGE  0XFFFFFEFF /* -257 */
+#define VNC_ENCODING_EXT_KEY_EVENT        0XFFFFFEFE /* -258 */
+#define VNC_ENCODING_AUDIO                0XFFFFFEFD /* -259 */
+#define VNC_ENCODING_TIGHT_PNG            0xFFFFFEFC /* -260 */
+#define VNC_ENCODING_WMVi                 0x574D5669
+
+/*****************************************************************************
+ *
+ * Other tight constants
+ *
+ *****************************************************************************/
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define VNC_TIGHT_CCB_RESET_MASK   (0x0f)
+#define VNC_TIGHT_CCB_TYPE_MASK    (0x0f << 4)
+#define VNC_TIGHT_CCB_TYPE_FILL    (0x08 << 4)
+#define VNC_TIGHT_CCB_TYPE_JPEG    (0x09 << 4)
+#define VNC_TIGHT_CCB_TYPE_PNG     (0x0A << 4)
+#define VNC_TIGHT_CCB_BASIC_MAX    (0x07 << 4)
+#define VNC_TIGHT_CCB_BASIC_ZLIB   (0x03 << 4)
+#define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
+
+/*****************************************************************************
+ *
+ * Features
+ *
+ *****************************************************************************/
+
+#define VNC_FEATURE_RESIZE                   0
+#define VNC_FEATURE_HEXTILE                  1
+#define VNC_FEATURE_POINTER_TYPE_CHANGE      2
+#define VNC_FEATURE_WMVI                     3
+#define VNC_FEATURE_TIGHT                    4
+#define VNC_FEATURE_ZLIB                     5
+#define VNC_FEATURE_COPYRECT                 6
+#define VNC_FEATURE_RICH_CURSOR              7
+#define VNC_FEATURE_TIGHT_PNG                8
+#define VNC_FEATURE_ZRLE                     9
+#define VNC_FEATURE_ZYWRLE                  10
+
+#define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
+#define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
+#define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
+#define VNC_FEATURE_WMVI_MASK                (1 << VNC_FEATURE_WMVI)
+#define VNC_FEATURE_TIGHT_MASK               (1 << VNC_FEATURE_TIGHT)
+#define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
+#define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
+#define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
+#define VNC_FEATURE_TIGHT_PNG_MASK           (1 << VNC_FEATURE_TIGHT_PNG)
+#define VNC_FEATURE_ZRLE_MASK                (1 << VNC_FEATURE_ZRLE)
+#define VNC_FEATURE_ZYWRLE_MASK              (1 << VNC_FEATURE_ZYWRLE)
+
+
+/* Client -> Server message IDs */
+#define VNC_MSG_CLIENT_SET_PIXEL_FORMAT           0
+#define VNC_MSG_CLIENT_SET_ENCODINGS              2
+#define VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST 3
+#define VNC_MSG_CLIENT_KEY_EVENT                  4
+#define VNC_MSG_CLIENT_POINTER_EVENT              5
+#define VNC_MSG_CLIENT_CUT_TEXT                   6
+#define VNC_MSG_CLIENT_VMWARE_0                   127
+#define VNC_MSG_CLIENT_CALL_CONTROL               249
+#define VNC_MSG_CLIENT_XVP                        250
+#define VNC_MSG_CLIENT_SET_DESKTOP_SIZE           251
+#define VNC_MSG_CLIENT_TIGHT                      252
+#define VNC_MSG_CLIENT_GII                        253
+#define VNC_MSG_CLIENT_VMWARE_1                   254
+#define VNC_MSG_CLIENT_QEMU                       255
+
+/* Server -> Client message IDs */
+#define VNC_MSG_SERVER_FRAMEBUFFER_UPDATE         0
+#define VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES     1
+#define VNC_MSG_SERVER_BELL                       2
+#define VNC_MSG_SERVER_CUT_TEXT                   3
+#define VNC_MSG_SERVER_VMWARE_0                   127
+#define VNC_MSG_SERVER_CALL_CONTROL               249
+#define VNC_MSG_SERVER_XVP                        250
+#define VNC_MSG_SERVER_TIGHT                      252
+#define VNC_MSG_SERVER_GII                        253
+#define VNC_MSG_SERVER_VMWARE_1                   254
+#define VNC_MSG_SERVER_QEMU                       255
+
+
+
+/* QEMU client -> server message IDs */
+#define VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT         0
+#define VNC_MSG_CLIENT_QEMU_AUDIO                 1
+
+/* QEMU server -> client message IDs */
+#define VNC_MSG_SERVER_QEMU_AUDIO                 1
+
+
+
+/* QEMU client -> server audio message IDs */
+#define VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE          0
+#define VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE         1
+#define VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT      2
+
+/* QEMU server -> client audio message IDs */
+#define VNC_MSG_SERVER_QEMU_AUDIO_END             0
+#define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN           1
+#define VNC_MSG_SERVER_QEMU_AUDIO_DATA            2
+
+
+/*****************************************************************************
+ *
+ * Internal APIs
+ *
+ *****************************************************************************/
+
+/* Event loop functions */
+void vnc_client_read(void *opaque);
+void vnc_client_write(void *opaque);
+
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
+
+/* Protocol I/O functions */
+void vnc_write(VncState *vs, const void *data, size_t len);
+void vnc_write_u32(VncState *vs, uint32_t value);
+void vnc_write_s32(VncState *vs, int32_t value);
+void vnc_write_u16(VncState *vs, uint16_t value);
+void vnc_write_u8(VncState *vs, uint8_t value);
+void vnc_flush(VncState *vs);
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
+
+
+/* Buffer I/O functions */
+uint8_t read_u8(uint8_t *data, size_t offset);
+uint16_t read_u16(uint8_t *data, size_t offset);
+int32_t read_s32(uint8_t *data, size_t offset);
+uint32_t read_u32(uint8_t *data, size_t offset);
+
+/* Protocol stage functions */
+void vnc_client_error(VncState *vs);
+int vnc_client_io_error(VncState *vs, int ret, int last_errno);
+
+void start_client_init(VncState *vs);
+void start_auth_vnc(VncState *vs);
+
+/* Buffer management */
+void buffer_reserve(Buffer *buffer, size_t len);
+int buffer_empty(Buffer *buffer);
+uint8_t *buffer_end(Buffer *buffer);
+void buffer_reset(Buffer *buffer);
+void buffer_free(Buffer *buffer);
+void buffer_append(Buffer *buffer, const void *data, size_t len);
+
+
+/* Misc helpers */
+
+char *vnc_socket_local_addr(const char *format, int fd);
+char *vnc_socket_remote_addr(const char *format, int fd);
+
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+    return (vs->features & (1 << feature));
+}
+
+/* Framebuffer */
+void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+                            int32_t encoding);
+
+void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
+double vnc_update_freq(VncState *vs, int x, int y, int w, int h);
+void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h);
+
+/* Encodings */
+int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+
+int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+
+int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
+                                         int y, int w, int h);
+void vnc_hextile_set_pixel_conversion(VncState *vs, int generic);
+
+void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size);
+void vnc_zlib_zfree(void *x, void *addr);
+int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+void vnc_zlib_clear(VncState *vs);
+
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+                                          int w, int h);
+void vnc_tight_clear(VncState *vs);
+
+int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+void vnc_zrle_clear(VncState *vs);
+
+#endif /* __QEMU_VNC_H */
diff --git a/qemu-0.15.x/ui/vnc_keysym.h b/qemu-0.15.x/ui/vnc_keysym.h
new file mode 100644
index 0000000..df33cfe
--- /dev/null
+++ b/qemu-0.15.x/ui/vnc_keysym.h
@@ -0,0 +1,342 @@
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                0x020},
+    { "exclam",               0x021},
+    { "quotedbl",             0x022},
+    { "numbersign",           0x023},
+    { "dollar",               0x024},
+    { "percent",              0x025},
+    { "ampersand",            0x026},
+    { "apostrophe",           0x027},
+    { "parenleft",            0x028},
+    { "parenright",           0x029},
+    { "asterisk",             0x02a},
+    { "plus",                 0x02b},
+    { "comma",                0x02c},
+    { "minus",                0x02d},
+    { "period",               0x02e},
+    { "slash",                0x02f},
+    { "0",                    0x030},
+    { "1",                    0x031},
+    { "2",                    0x032},
+    { "3",                    0x033},
+    { "4",                    0x034},
+    { "5",                    0x035},
+    { "6",                    0x036},
+    { "7",                    0x037},
+    { "8",                    0x038},
+    { "9",                    0x039},
+    { "colon",                0x03a},
+    { "semicolon",            0x03b},
+    { "less",                 0x03c},
+    { "equal",                0x03d},
+    { "greater",              0x03e},
+    { "question",             0x03f},
+    { "at",                   0x040},
+    { "A",                    0x041},
+    { "B",                    0x042},
+    { "C",                    0x043},
+    { "D",                    0x044},
+    { "E",                    0x045},
+    { "F",                    0x046},
+    { "G",                    0x047},
+    { "H",                    0x048},
+    { "I",                    0x049},
+    { "J",                    0x04a},
+    { "K",                    0x04b},
+    { "L",                    0x04c},
+    { "M",                    0x04d},
+    { "N",                    0x04e},
+    { "O",                    0x04f},
+    { "P",                    0x050},
+    { "Q",                    0x051},
+    { "R",                    0x052},
+    { "S",                    0x053},
+    { "T",                    0x054},
+    { "U",                    0x055},
+    { "V",                    0x056},
+    { "W",                    0x057},
+    { "X",                    0x058},
+    { "Y",                    0x059},
+    { "Z",                    0x05a},
+    { "bracketleft",          0x05b},
+    { "backslash",            0x05c},
+    { "bracketright",         0x05d},
+    { "asciicircum",          0x05e},
+    { "underscore",           0x05f},
+    { "grave",                0x060},
+    { "a",                    0x061},
+    { "b",                    0x062},
+    { "c",                    0x063},
+    { "d",                    0x064},
+    { "e",                    0x065},
+    { "f",                    0x066},
+    { "g",                    0x067},
+    { "h",                    0x068},
+    { "i",                    0x069},
+    { "j",                    0x06a},
+    { "k",                    0x06b},
+    { "l",                    0x06c},
+    { "m",                    0x06d},
+    { "n",                    0x06e},
+    { "o",                    0x06f},
+    { "p",                    0x070},
+    { "q",                    0x071},
+    { "r",                    0x072},
+    { "s",                    0x073},
+    { "t",                    0x074},
+    { "u",                    0x075},
+    { "v",                    0x076},
+    { "w",                    0x077},
+    { "x",                    0x078},
+    { "y",                    0x079},
+    { "z",                    0x07a},
+    { "braceleft",            0x07b},
+    { "bar",                  0x07c},
+    { "braceright",           0x07d},
+    { "asciitilde",           0x07e},
+
+/* latin 1 extensions */
+{ "nobreakspace",         0x0a0},
+{ "exclamdown",           0x0a1},
+{ "cent",         	  0x0a2},
+{ "sterling",             0x0a3},
+{ "currency",             0x0a4},
+{ "yen",                  0x0a5},
+{ "brokenbar",            0x0a6},
+{ "section",              0x0a7},
+{ "diaeresis",            0x0a8},
+{ "copyright",            0x0a9},
+{ "ordfeminine",          0x0aa},
+{ "guillemotleft",        0x0ab},
+{ "notsign",              0x0ac},
+{ "hyphen",               0x0ad},
+{ "registered",           0x0ae},
+{ "macron",               0x0af},
+{ "degree",               0x0b0},
+{ "plusminus",            0x0b1},
+{ "twosuperior",          0x0b2},
+{ "threesuperior",        0x0b3},
+{ "acute",                0x0b4},
+{ "mu",                   0x0b5},
+{ "paragraph",            0x0b6},
+{ "periodcentered",       0x0b7},
+{ "cedilla",              0x0b8},
+{ "onesuperior",          0x0b9},
+{ "masculine",            0x0ba},
+{ "guillemotright",       0x0bb},
+{ "onequarter",           0x0bc},
+{ "onehalf",              0x0bd},
+{ "threequarters",        0x0be},
+{ "questiondown",         0x0bf},
+{ "Agrave",               0x0c0},
+{ "Aacute",               0x0c1},
+{ "Acircumflex",          0x0c2},
+{ "Atilde",               0x0c3},
+{ "Adiaeresis",           0x0c4},
+{ "Aring",                0x0c5},
+{ "AE",                   0x0c6},
+{ "Ccedilla",             0x0c7},
+{ "Egrave",               0x0c8},
+{ "Eacute",               0x0c9},
+{ "Ecircumflex",          0x0ca},
+{ "Ediaeresis",           0x0cb},
+{ "Igrave",               0x0cc},
+{ "Iacute",               0x0cd},
+{ "Icircumflex",          0x0ce},
+{ "Idiaeresis",           0x0cf},
+{ "ETH",                  0x0d0},
+{ "Eth",                  0x0d0},
+{ "Ntilde",               0x0d1},
+{ "Ograve",               0x0d2},
+{ "Oacute",               0x0d3},
+{ "Ocircumflex",          0x0d4},
+{ "Otilde",               0x0d5},
+{ "Odiaeresis",           0x0d6},
+{ "multiply",             0x0d7},
+{ "Ooblique",             0x0d8},
+{ "Oslash",               0x0d8},
+{ "Ugrave",               0x0d9},
+{ "Uacute",               0x0da},
+{ "Ucircumflex",          0x0db},
+{ "Udiaeresis",           0x0dc},
+{ "Yacute",               0x0dd},
+{ "THORN",                0x0de},
+{ "Thorn",                0x0de},
+{ "ssharp",               0x0df},
+{ "agrave",               0x0e0},
+{ "aacute",               0x0e1},
+{ "acircumflex",          0x0e2},
+{ "atilde",               0x0e3},
+{ "adiaeresis",           0x0e4},
+{ "aring",                0x0e5},
+{ "ae",                   0x0e6},
+{ "ccedilla",             0x0e7},
+{ "egrave",               0x0e8},
+{ "eacute",               0x0e9},
+{ "ecircumflex",          0x0ea},
+{ "ediaeresis",           0x0eb},
+{ "igrave",               0x0ec},
+{ "iacute",               0x0ed},
+{ "icircumflex",          0x0ee},
+{ "idiaeresis",           0x0ef},
+{ "eth",                  0x0f0},
+{ "ntilde",               0x0f1},
+{ "ograve",               0x0f2},
+{ "oacute",               0x0f3},
+{ "ocircumflex",          0x0f4},
+{ "otilde",               0x0f5},
+{ "odiaeresis",           0x0f6},
+{ "division",             0x0f7},
+{ "oslash",               0x0f8},
+{ "ooblique",             0x0f8},
+{ "ugrave",               0x0f9},
+{ "uacute",               0x0fa},
+{ "ucircumflex",          0x0fb},
+{ "udiaeresis",           0x0fc},
+{ "yacute",               0x0fd},
+{ "thorn",                0x0fe},
+{ "ydiaeresis",           0x0ff},
+{"EuroSign", 0x20ac},  /* XK_EuroSign */
+
+/* latin 2 - Polish national characters */
+{ "eogonek",              0x1ea},
+{ "Eogonek",              0x1ca},
+{ "aogonek",              0x1b1},
+{ "Aogonek",              0x1a1},
+{ "sacute",               0x1b6},
+{ "Sacute",               0x1a6},
+{ "lstroke",              0x1b3},
+{ "Lstroke",              0x1a3},
+{ "zabovedot",            0x1bf},
+{ "Zabovedot",            0x1af},
+{ "zacute",               0x1bc},
+{ "Zacute",               0x1ac},
+{ "cacute",               0x1e6},
+{ "Cacute",               0x1c6},
+{ "nacute",               0x1f1},
+{ "Nacute",               0x1d1},
+
+    /* modifiers */
+{"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */
+{"Control_L", 0xffe3}, /* XK_Control_L */
+{"Control_R", 0xffe4}, /* XK_Control_R */
+{"Alt_L", 0xffe9},     /* XK_Alt_L */
+{"Alt_R", 0xffea},     /* XK_Alt_R */
+{"Caps_Lock", 0xffe5}, /* XK_Caps_Lock */
+{"Meta_L", 0xffe7},    /* XK_Meta_L */
+{"Meta_R", 0xffe8},    /* XK_Meta_R */
+{"Shift_L", 0xffe1},   /* XK_Shift_L */
+{"Shift_R", 0xffe2},   /* XK_Shift_R */
+{"Super_L", 0xffeb},   /* XK_Super_L */
+{"Super_R", 0xffec},   /* XK_Super_R */
+
+    /* special keys */
+{"BackSpace", 0xff08}, /* XK_BackSpace */
+{"Tab", 0xff09},       /* XK_Tab */
+{"Return", 0xff0d},    /* XK_Return */
+{"Right", 0xff53},     /* XK_Right */
+{"Left", 0xff51},      /* XK_Left */
+{"Up", 0xff52},        /* XK_Up */
+{"Down", 0xff54},      /* XK_Down */
+{"Page_Down", 0xff56}, /* XK_Page_Down */
+{"Page_Up", 0xff55},   /* XK_Page_Up */
+{"Insert", 0xff63},    /* XK_Insert */
+{"Delete", 0xffff},    /* XK_Delete */
+{"Home", 0xff50},      /* XK_Home */
+{"End", 0xff57},       /* XK_End */
+{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"KP_Home", 0xff95},
+{"KP_Left", 0xff96},
+{"KP_Up", 0xff97},
+{"KP_Right", 0xff98},
+{"KP_Down", 0xff99},
+{"KP_Prior", 0xff9a},
+{"KP_Page_Up", 0xff9a},
+{"KP_Next", 0xff9b},
+{"KP_Page_Down", 0xff9b},
+{"KP_End", 0xff9c},
+{"KP_Begin", 0xff9d},
+{"KP_Insert", 0xff9e},
+{"KP_Delete", 0xff9f},
+{"F1", 0xffbe},        /* XK_F1 */
+{"F2", 0xffbf},        /* XK_F2 */
+{"F3", 0xffc0},        /* XK_F3 */
+{"F4", 0xffc1},        /* XK_F4 */
+{"F5", 0xffc2},        /* XK_F5 */
+{"F6", 0xffc3},        /* XK_F6 */
+{"F7", 0xffc4},        /* XK_F7 */
+{"F8", 0xffc5},        /* XK_F8 */
+{"F9", 0xffc6},        /* XK_F9 */
+{"F10", 0xffc7},       /* XK_F10 */
+{"F11", 0xffc8},       /* XK_F11 */
+{"F12", 0xffc9},       /* XK_F12 */
+{"F13", 0xffca},       /* XK_F13 */
+{"F14", 0xffcb},       /* XK_F14 */
+{"F15", 0xffcc},       /* XK_F15 */
+{"Sys_Req", 0xff15},   /* XK_Sys_Req */
+{"KP_0", 0xffb0},      /* XK_KP_0 */
+{"KP_1", 0xffb1},      /* XK_KP_1 */
+{"KP_2", 0xffb2},      /* XK_KP_2 */
+{"KP_3", 0xffb3},      /* XK_KP_3 */
+{"KP_4", 0xffb4},      /* XK_KP_4 */
+{"KP_5", 0xffb5},      /* XK_KP_5 */
+{"KP_6", 0xffb6},      /* XK_KP_6 */
+{"KP_7", 0xffb7},      /* XK_KP_7 */
+{"KP_8", 0xffb8},      /* XK_KP_8 */
+{"KP_9", 0xffb9},      /* XK_KP_9 */
+{"KP_Add", 0xffab},    /* XK_KP_Add */
+{"KP_Separator", 0xffac},/* XK_KP_Separator */
+{"KP_Decimal", 0xffae},  /* XK_KP_Decimal */
+{"KP_Divide", 0xffaf},   /* XK_KP_Divide */
+{"KP_Enter", 0xff8d},    /* XK_KP_Enter */
+{"KP_Equal", 0xffbd},    /* XK_KP_Equal */
+{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */
+{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */
+{"help", 0xff6a},        /* XK_Help */
+{"Menu", 0xff67},        /* XK_Menu */
+{"Print", 0xff61},       /* XK_Print */
+{"Mode_switch", 0xff7e}, /* XK_Mode_switch */
+{"Num_Lock", 0xff7f},    /* XK_Num_Lock */
+{"Pause", 0xff13},       /* XK_Pause */
+{"Escape", 0xff1b},      /* XK_Escape */
+
+/* dead keys */
+{"dead_grave", 0xfe50}, /* XK_dead_grave */
+{"dead_acute", 0xfe51}, /* XK_dead_acute */
+{"dead_circumflex", 0xfe52}, /* XK_dead_circumflex */
+{"dead_tilde", 0xfe53}, /* XK_dead_tilde */
+{"dead_macron", 0xfe54}, /* XK_dead_macron */
+{"dead_breve", 0xfe55}, /* XK_dead_breve */
+{"dead_abovedot", 0xfe56}, /* XK_dead_abovedot */
+{"dead_diaeresis", 0xfe57}, /* XK_dead_diaeresis */
+{"dead_abovering", 0xfe58}, /* XK_dead_abovering */
+{"dead_doubleacute", 0xfe59}, /* XK_dead_doubleacute */
+{"dead_caron", 0xfe5a}, /* XK_dead_caron */
+{"dead_cedilla", 0xfe5b}, /* XK_dead_cedilla */
+{"dead_ogonek", 0xfe5c}, /* XK_dead_ogonek */
+{"dead_iota", 0xfe5d}, /* XK_dead_iota */
+{"dead_voiced_sound", 0xfe5e}, /* XK_dead_voiced_sound */
+{"dead_semivoiced_sound", 0xfe5f}, /* XK_dead_semivoiced_sound */
+{"dead_belowdot", 0xfe60}, /* XK_dead_belowdot */
+{"dead_hook", 0xfe61}, /* XK_dead_hook */
+{"dead_horn", 0xfe62}, /* XK_dead_horn */
+
+
+    /* localized keys */
+{"BackApostrophe", 0xff21},
+{"Muhenkan", 0xff22},
+{"Katakana", 0xff27},
+{"Hankaku", 0xff29},
+{"Zenkaku_Hankaku", 0xff2a},
+{"Henkan_Mode_Real", 0xff23},
+{"Henkan_Mode_Ultra", 0xff3e},
+{"backslash_ja", 0xffa5},
+{"Katakana_Real", 0xff25},
+{"Eisu_toggle", 0xff30},
+
+{NULL,0},
+};
diff --git a/qemu-0.15.x/ui/x_keymap.c b/qemu-0.15.x/ui/x_keymap.c
new file mode 100644
index 0000000..b9b0944
--- /dev/null
+++ b/qemu-0.15.x/ui/x_keymap.c
@@ -0,0 +1,168 @@
+/*
+ * QEMU SDL display 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 "qemu-common.h"
+#include "x_keymap.h"
+
+static const uint8_t x_keycode_to_pc_keycode[115] = {
+   0xc7,      /*  97  Home   */
+   0xc8,      /*  98  Up     */
+   0xc9,      /*  99  PgUp   */
+   0xcb,      /* 100  Left   */
+   0x4c,        /* 101  KP-5   */
+   0xcd,      /* 102  Right  */
+   0xcf,      /* 103  End    */
+   0xd0,      /* 104  Down   */
+   0xd1,      /* 105  PgDn   */
+   0xd2,      /* 106  Ins    */
+   0xd3,      /* 107  Del    */
+   0x9c,      /* 108  Enter  */
+   0x9d,      /* 109  Ctrl-R */
+   0x0,       /* 110  Pause  */
+   0xb7,      /* 111  Print  */
+   0xb5,      /* 112  Divide */
+   0xb8,      /* 113  Alt-R  */
+   0xc6,      /* 114  Break  */
+   0x0,         /* 115 */
+   0x0,         /* 116 */
+   0x0,         /* 117 */
+   0x0,         /* 118 */
+   0x0,         /* 119 */
+   0x0,         /* 120 */
+   0x0,         /* 121 */
+   0x0,         /* 122 */
+   0x0,         /* 123 */
+   0x0,         /* 124 */
+   0x0,         /* 125 */
+   0x0,         /* 126 */
+   0x0,         /* 127 */
+   0x0,         /* 128 */
+   0x79,         /* 129 Henkan */
+   0x0,         /* 130 */
+   0x7b,         /* 131 Muhenkan */
+   0x0,         /* 132 */
+   0x7d,         /* 133 Yen */
+   0x0,         /* 134 */
+   0x0,         /* 135 */
+   0x47,         /* 136 KP_7 */
+   0x48,         /* 137 KP_8 */
+   0x49,         /* 138 KP_9 */
+   0x4b,         /* 139 KP_4 */
+   0x4c,         /* 140 KP_5 */
+   0x4d,         /* 141 KP_6 */
+   0x4f,         /* 142 KP_1 */
+   0x50,         /* 143 KP_2 */
+   0x51,         /* 144 KP_3 */
+   0x52,         /* 145 KP_0 */
+   0x53,         /* 146 KP_. */
+   0x47,         /* 147 KP_HOME */
+   0x48,         /* 148 KP_UP */
+   0x49,         /* 149 KP_PgUp */
+   0x4b,         /* 150 KP_Left */
+   0x4c,         /* 151 KP_ */
+   0x4d,         /* 152 KP_Right */
+   0x4f,         /* 153 KP_End */
+   0x50,         /* 154 KP_Down */
+   0x51,         /* 155 KP_PgDn */
+   0x52,         /* 156 KP_Ins */
+   0x53,         /* 157 KP_Del */
+};
+
+/* This table is generated based off the xfree86 -> scancode mapping above
+ * and the keycode mappings in /usr/share/X11/xkb/keycodes/evdev
+ * and  /usr/share/X11/xkb/keycodes/xfree86
+ */
+
+static const uint8_t evdev_keycode_to_pc_keycode[61] = {
+    0,         /*  97 EVDEV - RO   ("Internet" Keyboards) */
+    0,         /*  98 EVDEV - KATA (Katakana) */
+    0,         /*  99 EVDEV - HIRA (Hiragana) */
+    0x79,      /* 100 EVDEV - HENK (Henkan) */
+    0x70,      /* 101 EVDEV - HKTG (Hiragana/Katakana toggle) */
+    0x7b,      /* 102 EVDEV - MUHE (Muhenkan) */
+    0,         /* 103 EVDEV - JPCM (KPJPComma) */
+    0x9c,      /* 104 KPEN */
+    0x9d,      /* 105 RCTL */
+    0xb5,      /* 106 KPDV */
+    0xb7,      /* 107 PRSC */
+    0xb8,      /* 108 RALT */
+    0,         /* 109 EVDEV - LNFD ("Internet" Keyboards) */
+    0xc7,      /* 110 HOME */
+    0xc8,      /* 111 UP */
+    0xc9,      /* 112 PGUP */
+    0xcb,      /* 113 LEFT */
+    0xcd,      /* 114 RGHT */
+    0xcf,      /* 115 END */
+    0xd0,      /* 116 DOWN */
+    0xd1,      /* 117 PGDN */
+    0xd2,      /* 118 INS */
+    0xd3,      /* 119 DELE */
+    0,         /* 120 EVDEV - I120 ("Internet" Keyboards) */
+    0,         /* 121 EVDEV - MUTE */
+    0,         /* 122 EVDEV - VOL- */
+    0,         /* 123 EVDEV - VOL+ */
+    0,         /* 124 EVDEV - POWR */
+    0,         /* 125 EVDEV - KPEQ */
+    0,         /* 126 EVDEV - I126 ("Internet" Keyboards) */
+    0,         /* 127 EVDEV - PAUS */
+    0,         /* 128 EVDEV - ???? */
+    0,         /* 129 EVDEV - I129 ("Internet" Keyboards) */
+    0xf1,      /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
+    0xf2,      /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
+    0x7d,      /* 132 AE13 (Yen)*/
+    0xdb,      /* 133 EVDEV - LWIN */
+    0xdc,      /* 134 EVDEV - RWIN */
+    0xdd,      /* 135 EVDEV - MENU */
+    0,         /* 136 EVDEV - STOP */
+    0,         /* 137 EVDEV - AGAI */
+    0,         /* 138 EVDEV - PROP */
+    0,         /* 139 EVDEV - UNDO */
+    0,         /* 140 EVDEV - FRNT */
+    0,         /* 141 EVDEV - COPY */
+    0,         /* 142 EVDEV - OPEN */
+    0,         /* 143 EVDEV - PAST */
+    0,         /* 144 EVDEV - FIND */
+    0,         /* 145 EVDEV - CUT  */
+    0,         /* 146 EVDEV - HELP */
+    0,         /* 147 EVDEV - I147 */
+    0,         /* 148 EVDEV - I148 */
+    0,         /* 149 EVDEV - I149 */
+    0,         /* 150 EVDEV - I150 */
+    0,         /* 151 EVDEV - I151 */
+    0,         /* 152 EVDEV - I152 */
+    0,         /* 153 EVDEV - I153 */
+    0,         /* 154 EVDEV - I154 */
+    0,         /* 155 EVDEV - I156 */
+    0,         /* 156 EVDEV - I157 */
+    0,         /* 157 EVDEV - I158 */
+};
+
+uint8_t translate_xfree86_keycode(const int key)
+{
+    return x_keycode_to_pc_keycode[key];
+}
+
+uint8_t translate_evdev_keycode(const int key)
+{
+    return evdev_keycode_to_pc_keycode[key];
+}
diff --git a/qemu-0.15.x/ui/x_keymap.h b/qemu-0.15.x/ui/x_keymap.h
new file mode 100644
index 0000000..afde2e9
--- /dev/null
+++ b/qemu-0.15.x/ui/x_keymap.h
@@ -0,0 +1,32 @@
+/*
+ * QEMU SDL display 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 QEMU_X_KEYMAP_H
+#define QEMU_X_KEYMAP_H
+
+uint8_t translate_xfree86_keycode(const int key);
+
+uint8_t translate_evdev_keycode(const int key);
+
+#endif
diff --git a/qemu-0.15.x/usb-bsd.c b/qemu-0.15.x/usb-bsd.c
new file mode 100644
index 0000000..3b97eb4
--- /dev/null
+++ b/qemu-0.15.x/usb-bsd.c
@@ -0,0 +1,645 @@
+/*
+ * BSD host USB redirector
+ *
+ * Copyright (c) 2006 Lonnie Mendez
+ * Portions of code and concepts borrowed from
+ * usb-linux.c and libusb's bsd.c and are copyright their respective owners.
+ *
+ * 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 "qemu-common.h"
+#include "monitor.h"
+#include "hw/usb.h"
+
+/* usb.h declares these */
+#undef USB_SPEED_HIGH
+#undef USB_SPEED_FULL
+#undef USB_SPEED_LOW
+
+#include <sys/ioctl.h>
+#ifndef __DragonFly__
+#include <dev/usb/usb.h>
+#else
+#include <bus/usb/usb.h>
+#endif
+
+/* This value has maximum potential at 16.
+ * You should also set hw.usb.debug to gain
+ * more detailed view.
+ */
+//#define DEBUG
+#define UGEN_DEBUG_LEVEL 0
+
+
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
+                        int vendor_id, int product_id,
+                        const char *product_name, int speed);
+static int usb_host_find_device(int *pbus_num, int *paddr,
+                                const char *devname);
+
+typedef struct USBHostDevice {
+    USBDevice dev;
+    int ep_fd[USB_MAX_ENDPOINTS];
+    int devfd;
+    char devpath[32];
+} USBHostDevice;
+
+
+#if 0
+static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
+{
+    char buf[32];
+    int fd;
+
+    /* Get the address for this endpoint */
+    ep = UE_GET_ADDR(ep);
+
+    if (dev->ep_fd[ep] < 0) {
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+        snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep);
+#else
+        snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep);
+#endif
+        /* Try to open it O_RDWR first for those devices which have in and out
+         * endpoints with the same address (eg 0x02 and 0x82)
+         */
+        fd = open(buf, O_RDWR);
+        if (fd < 0 && errno == ENXIO)
+            fd = open(buf, mode);
+        if (fd < 0) {
+#ifdef DEBUG
+            printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
+                   buf, strerror(errno));
+#endif
+        }
+        dev->ep_fd[ep] = fd;
+    }
+
+    return dev->ep_fd[ep];
+}
+
+static void ensure_eps_closed(USBHostDevice *dev)
+{
+    int epnum = 1;
+
+    if (!dev)
+        return;
+
+    while (epnum < USB_MAX_ENDPOINTS) {
+        if (dev->ep_fd[epnum] >= 0) {
+            close(dev->ep_fd[epnum]);
+            dev->ep_fd[epnum] = -1;
+        }
+        epnum++;
+    }
+}
+#endif
+
+static void usb_host_handle_reset(USBDevice *dev)
+{
+#if 0
+    USBHostDevice *s = (USBHostDevice *)dev;
+#endif
+}
+
+#if 0
+/* XXX:
+ * -check device states against transfer requests
+ *  and return appropriate response
+ */
+static int usb_host_handle_control(USBDevice *dev,
+                                   USBPacket *p,
+                                   int request,
+                                   int value,
+                                   int index,
+                                   int length,
+                                   uint8_t *data)
+{
+    USBHostDevice *s = (USBHostDevice *)dev;
+    struct usb_ctl_request req;
+    struct usb_alt_interface aiface;
+    int ret, timeout = 50;
+
+    if ((request >> 8) == UT_WRITE_DEVICE &&
+        (request & 0xff) == UR_SET_ADDRESS) {
+
+        /* specific SET_ADDRESS support */
+        dev->addr = value;
+        return 0;
+    } else if ((request >> 8) == UT_WRITE_DEVICE &&
+               (request & 0xff) == UR_SET_CONFIG) {
+
+        ensure_eps_closed(s); /* can't do this without all eps closed */
+
+        ret = ioctl(s->devfd, USB_SET_CONFIG, &value);
+        if (ret < 0) {
+#ifdef DEBUG
+            printf("handle_control: failed to set configuration - %s\n",
+                   strerror(errno));
+#endif
+            return USB_RET_STALL;
+        }
+
+        return 0;
+    } else if ((request >> 8) == UT_WRITE_INTERFACE &&
+               (request & 0xff) == UR_SET_INTERFACE) {
+
+        aiface.uai_interface_index = index;
+        aiface.uai_alt_no = value;
+
+        ensure_eps_closed(s); /* can't do this without all eps closed */
+        ret = ioctl(s->devfd, USB_SET_ALTINTERFACE, &aiface);
+        if (ret < 0) {
+#ifdef DEBUG
+            printf("handle_control: failed to set alternate interface - %s\n",
+                   strerror(errno));
+#endif
+            return USB_RET_STALL;
+        }
+
+        return 0;
+    } else {
+        req.ucr_request.bmRequestType = request >> 8;
+        req.ucr_request.bRequest = request & 0xff;
+        USETW(req.ucr_request.wValue, value);
+        USETW(req.ucr_request.wIndex, index);
+        USETW(req.ucr_request.wLength, length);
+        req.ucr_data = data;
+        req.ucr_flags = USBD_SHORT_XFER_OK;
+
+        ret = ioctl(s->devfd, USB_SET_TIMEOUT, &timeout);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+        if (ret < 0 && errno != EINVAL) {
+#else
+        if (ret < 0) {
+#endif
+#ifdef DEBUG
+            printf("handle_control: setting timeout failed - %s\n",
+                   strerror(errno));
+#endif
+        }
+
+        ret = ioctl(s->devfd, USB_DO_REQUEST, &req);
+        /* ugen returns EIO for usbd_do_request_ no matter what
+         * happens with the transfer */
+        if (ret < 0) {
+#ifdef DEBUG
+            printf("handle_control: error after request - %s\n",
+                   strerror(errno));
+#endif
+            return USB_RET_NAK; // STALL
+        } else {
+            return req.ucr_actlen;
+        }
+    }
+}
+
+static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBHostDevice *s = (USBHostDevice *)dev;
+    int ret, fd, mode;
+    int one = 1, shortpacket = 0, timeout = 50;
+    sigset_t new_mask, old_mask;
+    uint8_t devep = p->devep;
+
+    /* protect data transfers from SIGALRM signal */
+    sigemptyset(&new_mask);
+    sigaddset(&new_mask, SIGALRM);
+    sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
+
+    if (p->pid == USB_TOKEN_IN) {
+        devep |= 0x80;
+        mode = O_RDONLY;
+        shortpacket = 1;
+    } else {
+        mode = O_WRONLY;
+    }
+
+    fd = ensure_ep_open(s, devep, mode);
+    if (fd < 0) {
+        sigprocmask(SIG_SETMASK, &old_mask, NULL);
+        return USB_RET_NODEV;
+    }
+
+    if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) {
+#ifdef DEBUG
+        printf("handle_data: failed to set timeout - %s\n",
+               strerror(errno));
+#endif
+    }
+
+    if (shortpacket) {
+        if (ioctl(fd, USB_SET_SHORT_XFER, &one) < 0) {
+#ifdef DEBUG
+            printf("handle_data: failed to set short xfer mode - %s\n",
+                   strerror(errno));
+#endif
+            sigprocmask(SIG_SETMASK, &old_mask, NULL);
+        }
+    }
+
+    if (p->pid == USB_TOKEN_IN)
+        ret = read(fd, p->data, p->len);
+    else
+        ret = write(fd, p->data, p->len);
+
+    sigprocmask(SIG_SETMASK, &old_mask, NULL);
+
+    if (ret < 0) {
+#ifdef DEBUG
+        printf("handle_data: error after %s data - %s\n",
+               pid == USB_TOKEN_IN ? "reading" : "writing", strerror(errno));
+#endif
+        switch(errno) {
+        case ETIMEDOUT:
+        case EINTR:
+            return USB_RET_NAK;
+        default:
+            return USB_RET_STALL;
+        }
+    } else {
+        return ret;
+    }
+}
+#endif
+
+static void usb_host_handle_destroy(USBDevice *opaque)
+{
+    USBHostDevice *s = (USBHostDevice *)opaque;
+    int i;
+
+    for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+        if (s->ep_fd[i] >= 0)
+            close(s->ep_fd[i]);
+
+    if (s->devfd < 0)
+        return;
+
+    close(s->devfd);
+
+    qemu_free(s);
+}
+
+static int usb_host_initfn(USBDevice *dev)
+{
+    return 0;
+}
+
+USBDevice *usb_host_device_open(const char *devname)
+{
+    struct usb_device_info bus_info, dev_info;
+    USBDevice *d = NULL;
+    USBHostDevice *dev, *ret = NULL;
+    char ctlpath[PATH_MAX + 1];
+    char buspath[PATH_MAX + 1];
+    int bfd, dfd, bus, address, i;
+    int ugendebug = UGEN_DEBUG_LEVEL;
+
+    if (usb_host_find_device(&bus, &address, devname) < 0) {
+        goto fail;
+    }
+
+    snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
+
+    bfd = open(buspath, O_RDWR);
+    if (bfd < 0) {
+#ifdef DEBUG
+        printf("usb_host_device_open: failed to open usb bus - %s\n",
+               strerror(errno));
+#endif
+        goto fail;
+    }
+
+    bus_info.udi_addr = address;
+    if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) {
+#ifdef DEBUG
+        printf("usb_host_device_open: failed to grab bus information - %s\n",
+               strerror(errno));
+#endif
+        goto fail_bfd;
+    }
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+    snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]);
+#else
+    snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]);
+#endif
+
+    dfd  = open(ctlpath, O_RDWR);
+    if (dfd < 0) {
+        dfd = open(ctlpath, O_RDONLY);
+        if (dfd < 0) {
+#ifdef DEBUG
+            printf("usb_host_device_open: failed to open usb device %s - %s\n",
+                   ctlpath, strerror(errno));
+#endif
+        }
+        goto fail_dfd;
+    }
+
+    if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
+#ifdef DEBUG
+        printf("usb_host_device_open: failed to grab device info - %s\n",
+               strerror(errno));
+#endif
+        goto fail_dfd;
+    }
+
+    d = usb_create(NULL /* FIXME */, "usb-host");
+    dev = DO_UPCAST(USBHostDevice, dev, d);
+
+    if (dev_info.udi_speed == 1) {
+        dev->dev.speed = USB_SPEED_LOW - 1;
+        dev->dev.speedmask = USB_SPEED_MASK_LOW;
+    } else {
+        dev->dev.speed = USB_SPEED_FULL - 1;
+        dev->dev.speedmask = USB_SPEED_MASK_FULL;
+    }
+
+    if (strncmp(dev_info.udi_product, "product", 7) != 0) {
+        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                dev_info.udi_product);
+    } else {
+        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                 "host:%s", devname);
+    }
+
+    pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
+    pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
+
+    /* Mark the endpoints as not yet open */
+    for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+        dev->ep_fd[i] = -1;
+    }
+
+    ioctl(dfd, USB_SETDEBUG, &ugendebug);
+
+    ret = (USBDevice *)dev;
+
+fail_dfd:
+    close(dfd);
+fail_bfd:
+    close(bfd);
+fail:
+    return ret;
+}
+
+static struct USBDeviceInfo usb_host_dev_info = {
+    .product_desc   = "USB Host Device",
+    .qdev.name      = "usb-host",
+    .qdev.size      = sizeof(USBHostDevice),
+    .init           = usb_host_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_host_handle_reset,
+#if 0
+    .handle_control = usb_host_handle_control,
+    .handle_data    = usb_host_handle_data,
+#endif
+    .handle_destroy = usb_host_handle_destroy,
+};
+
+static void usb_host_register_devices(void)
+{
+    usb_qdev_register(&usb_host_dev_info);
+}
+device_init(usb_host_register_devices)
+
+static int usb_host_scan(void *opaque, USBScanFunc *func)
+{
+    struct usb_device_info bus_info;
+    struct usb_device_info dev_info;
+    uint16_t vendor_id, product_id, class_id, speed;
+    int bfd, dfd, bus, address;
+    char busbuf[20], devbuf[20], product_name[256];
+    int ret = 0;
+
+    for (bus = 0; bus < 10; bus++) {
+
+        snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus);
+        bfd = open(busbuf, O_RDWR);
+        if (bfd < 0)
+	    continue;
+
+        for (address = 1; address < 127; address++) {
+
+            bus_info.udi_addr = address;
+            if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0)
+                continue;
+
+            /* only list devices that can be used by generic layer */
+            if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
+                continue;
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+            snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
+#else
+            snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
+#endif
+
+            dfd = open(devbuf, O_RDONLY);
+            if (dfd < 0) {
+#ifdef DEBUG
+                printf("usb_host_scan: couldn't open device %s - %s\n", devbuf,
+                       strerror(errno));
+#endif
+                continue;
+            }
+
+            if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0)
+                printf("usb_host_scan: couldn't get device information for %s - %s\n",
+                       devbuf, strerror(errno));
+
+            /* XXX: might need to fixup endianness of word values before copying over */
+
+            vendor_id = dev_info.udi_vendorNo;
+            product_id = dev_info.udi_productNo;
+            class_id = dev_info.udi_class;
+            speed = dev_info.udi_speed;
+
+            if (strncmp(dev_info.udi_product, "product", 7) != 0)
+                pstrcpy(product_name, sizeof(product_name),
+                        dev_info.udi_product);
+            else
+                product_name[0] = '\0';
+
+            ret = func(opaque, bus, address, class_id, vendor_id,
+                       product_id, product_name, speed);
+
+            close(dfd);
+
+            if (ret)
+                goto the_end;
+        }
+
+        close(bfd);
+    }
+
+the_end:
+    return ret;
+}
+
+typedef struct FindDeviceState {
+    int vendor_id;
+    int product_id;
+    int bus_num;
+    int addr;
+} FindDeviceState;
+
+static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
+                                     int class_id,
+                                     int vendor_id, int product_id,
+                                     const char *product_name, int speed)
+{
+    FindDeviceState *s = opaque;
+    if (vendor_id == s->vendor_id &&
+        product_id == s->product_id) {
+        s->bus_num = bus_num;
+        s->addr = addr;
+        return 1;
+     } else {
+        return 0;
+     }
+}
+
+
+/* the syntax is :
+   'bus.addr' (decimal numbers) or
+   'vendor_id:product_id' (hexa numbers) */
+static int usb_host_find_device(int *pbus_num, int *paddr,
+                                const char *devname)
+{
+    const char *p;
+    int ret;
+    FindDeviceState fs;
+
+    p = strchr(devname, '.');
+    if (p) {
+        *pbus_num = strtoul(devname, NULL, 0);
+        *paddr = strtoul(p + 1, NULL, 0);
+        return 0;
+    }
+    p = strchr(devname, ':');
+    if (p) {
+        fs.vendor_id = strtoul(devname, NULL, 16);
+        fs.product_id = strtoul(p + 1, NULL, 16);
+        ret = usb_host_scan(&fs, usb_host_find_device_scan);
+        if (ret) {
+            *pbus_num = fs.bus_num;
+            *paddr = fs.addr;
+            return 0;
+        }
+     }
+     return -1;
+}
+
+/**********************/
+/* USB host device info */
+
+struct usb_class_info {
+    int class;
+    const char *class_name;
+};
+
+static const struct usb_class_info usb_class_info[] = {
+    { USB_CLASS_AUDIO, "Audio"},
+    { USB_CLASS_COMM, "Communication"},
+    { USB_CLASS_HID, "HID"},
+    { USB_CLASS_HUB, "Hub" },
+    { USB_CLASS_PHYSICAL, "Physical" },
+    { USB_CLASS_PRINTER, "Printer" },
+    { USB_CLASS_MASS_STORAGE, "Storage" },
+    { USB_CLASS_CDC_DATA, "Data" },
+    { USB_CLASS_APP_SPEC, "Application Specific" },
+    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
+    { USB_CLASS_STILL_IMAGE, "Still Image" },
+    { USB_CLASS_CSCID, "Smart Card" },
+    { USB_CLASS_CONTENT_SEC, "Content Security" },
+    { -1, NULL }
+};
+
+static const char *usb_class_str(uint8_t class)
+{
+    const struct usb_class_info *p;
+    for (p = usb_class_info; p->class != -1; p++) {
+        if (p->class == class)
+            break;
+    }
+    return p->class_name;
+}
+
+static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
+                            int vendor_id, int product_id,
+                            const char *product_name,
+                            int speed)
+{
+    const char *class_str, *speed_str;
+
+    switch(speed) {
+    case USB_SPEED_LOW:
+        speed_str = "1.5";
+        break;
+    case USB_SPEED_FULL:
+        speed_str = "12";
+        break;
+    case USB_SPEED_HIGH:
+        speed_str = "480";
+        break;
+    default:
+        speed_str = "?";
+        break;
+    }
+
+    monitor_printf(mon, "  Device %d.%d, speed %s Mb/s\n",
+                   bus_num, addr, speed_str);
+    class_str = usb_class_str(class_id);
+    if (class_str)
+        monitor_printf(mon, "    %s:", class_str);
+    else
+        monitor_printf(mon, "    Class %02x:", class_id);
+    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
+    if (product_name[0] != '\0')
+        monitor_printf(mon, ", %s", product_name);
+    monitor_printf(mon, "\n");
+}
+
+static int usb_host_info_device(void *opaque,
+                                int bus_num, int addr,
+                                int class_id,
+                                int vendor_id, int product_id,
+                                const char *product_name,
+                                int speed)
+{
+    Monitor *mon = opaque;
+
+    usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
+                    product_name, speed);
+    return 0;
+}
+
+void usb_host_info(Monitor *mon)
+{
+    usb_host_scan(mon, usb_host_info_device);
+}
+
+/* XXX add this */
+int usb_host_device_close(const char *devname)
+{
+    return 0;
+}
diff --git a/qemu-0.15.x/usb-linux.c b/qemu-0.15.x/usb-linux.c
new file mode 100644
index 0000000..53cc5fc
--- /dev/null
+++ b/qemu-0.15.x/usb-linux.c
@@ -0,0 +1,1961 @@
+/*
+ * Linux host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ *      Support for host device auto connect & disconnect
+ *      Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux at tjworld.net>
+ *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ *      to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "sysemu.h"
+
+#include <dirent.h>
+#include <sys/ioctl.h>
+
+#include <linux/usbdevice_fs.h>
+#include <linux/version.h>
+#include "hw/usb.h"
+
+/* We redefine it to avoid version problems */
+struct usb_ctrltransfer {
+    uint8_t  bRequestType;
+    uint8_t  bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    uint32_t timeout;
+    void *data;
+};
+
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
+                        int class_id, int vendor_id, int product_id,
+                        const char *product_name, int speed);
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
+
+#define USBPROCBUS_PATH "/proc/bus/usb"
+#define PRODUCT_NAME_SZ 32
+#define MAX_ENDPOINTS 15
+#define MAX_PORTLEN 16
+#define USBDEVBUS_PATH "/dev/bus/usb"
+#define USBSYSBUS_PATH "/sys/bus/usb"
+
+static char *usb_host_device_path;
+
+#define USB_FS_NONE 0
+#define USB_FS_PROC 1
+#define USB_FS_DEV 2
+#define USB_FS_SYS 3
+
+static int usb_fs_type;
+
+/* endpoint association data */
+#define ISO_FRAME_DESC_PER_URB 32
+#define INVALID_EP_TYPE 255
+
+/* devio.c limits single requests to 16k */
+#define MAX_USBFS_BUFFER_SIZE 16384
+
+typedef struct AsyncURB AsyncURB;
+
+struct endp_data {
+    uint8_t type;
+    uint8_t halted;
+    uint8_t iso_started;
+    AsyncURB *iso_urb;
+    int iso_urb_idx;
+    int iso_buffer_used;
+    int max_packet_size;
+    int inflight;
+};
+
+struct USBAutoFilter {
+    uint32_t bus_num;
+    uint32_t addr;
+    char     *port;
+    uint32_t vendor_id;
+    uint32_t product_id;
+};
+
+typedef struct USBHostDevice {
+    USBDevice dev;
+    int       fd;
+
+    uint8_t   descr[8192];
+    int       descr_len;
+    int       configuration;
+    int       ninterfaces;
+    int       closing;
+    uint32_t  iso_urb_count;
+    Notifier  exit;
+
+    struct endp_data endp_table[MAX_ENDPOINTS];
+    QLIST_HEAD(, AsyncURB) aurbs;
+
+    /* Host side address */
+    int bus_num;
+    int addr;
+    char port[MAX_PORTLEN];
+    struct USBAutoFilter match;
+
+    QTAILQ_ENTRY(USBHostDevice) next;
+} USBHostDevice;
+
+static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
+
+static int usb_host_close(USBHostDevice *dev);
+static int parse_filter(const char *spec, struct USBAutoFilter *f);
+static void usb_host_auto_check(void *unused);
+static int usb_host_read_file(char *line, size_t line_size,
+                            const char *device_file, const char *device_name);
+
+static struct endp_data *get_endp(USBHostDevice *s, int ep)
+{
+    return s->endp_table + ep - 1;
+}
+
+static int is_isoc(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;
+}
+
+static int is_valid(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->type != INVALID_EP_TYPE;
+}
+
+static int is_halted(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->halted;
+}
+
+static void clear_halt(USBHostDevice *s, int ep)
+{
+    get_endp(s, ep)->halted = 0;
+}
+
+static void set_halt(USBHostDevice *s, int ep)
+{
+    get_endp(s, ep)->halted = 1;
+}
+
+static int is_iso_started(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->iso_started;
+}
+
+static void clear_iso_started(USBHostDevice *s, int ep)
+{
+    get_endp(s, ep)->iso_started = 0;
+}
+
+static void set_iso_started(USBHostDevice *s, int ep)
+{
+    struct endp_data *e = get_endp(s, ep);
+    if (!e->iso_started) {
+        e->iso_started = 1;
+        e->inflight = 0;
+    }
+}
+
+static int change_iso_inflight(USBHostDevice *s, int ep, int value)
+{
+    struct endp_data *e = get_endp(s, ep);
+
+    e->inflight += value;
+    return e->inflight;
+}
+
+static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
+{
+    get_endp(s, ep)->iso_urb = iso_urb;
+}
+
+static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->iso_urb;
+}
+
+static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
+{
+    get_endp(s, ep)->iso_urb_idx = i;
+}
+
+static int get_iso_urb_idx(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->iso_urb_idx;
+}
+
+static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
+{
+    get_endp(s, ep)->iso_buffer_used = i;
+}
+
+static int get_iso_buffer_used(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->iso_buffer_used;
+}
+
+static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
+{
+    int raw = descriptor[4] + (descriptor[5] << 8);
+    int size, microframes;
+
+    size = raw & 0x7ff;
+    switch ((raw >> 11) & 3) {
+    case 1:  microframes = 2; break;
+    case 2:  microframes = 3; break;
+    default: microframes = 1; break;
+    }
+    get_endp(s, ep)->max_packet_size = size * microframes;
+}
+
+static int get_max_packet_size(USBHostDevice *s, int ep)
+{
+    return get_endp(s, ep)->max_packet_size;
+}
+
+/*
+ * Async URB state.
+ * We always allocate iso packet descriptors even for bulk transfers
+ * to simplify allocation and casts.
+ */
+struct AsyncURB
+{
+    struct usbdevfs_urb urb;
+    struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
+    USBHostDevice *hdev;
+    QLIST_ENTRY(AsyncURB) next;
+
+    /* For regular async urbs */
+    USBPacket     *packet;
+    int more; /* large transfer, more urbs follow */
+
+    /* For buffered iso handling */
+    int iso_frame_idx; /* -1 means in flight */
+};
+
+static AsyncURB *async_alloc(USBHostDevice *s)
+{
+    AsyncURB *aurb = qemu_mallocz(sizeof(AsyncURB));
+    aurb->hdev = s;
+    QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
+    return aurb;
+}
+
+static void async_free(AsyncURB *aurb)
+{
+    QLIST_REMOVE(aurb, next);
+    qemu_free(aurb);
+}
+
+static void do_disconnect(USBHostDevice *s)
+{
+    printf("husb: device %d.%d disconnected\n",
+           s->bus_num, s->addr);
+    usb_host_close(s);
+    usb_host_auto_check(NULL);
+}
+
+static void async_complete(void *opaque)
+{
+    USBHostDevice *s = opaque;
+    AsyncURB *aurb;
+    int urbs = 0;
+
+    while (1) {
+        USBPacket *p;
+
+        int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
+        if (r < 0) {
+            if (errno == EAGAIN) {
+                if (urbs > 2) {
+                    fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
+                }
+                return;
+            }
+            if (errno == ENODEV && !s->closing) {
+                do_disconnect(s);
+                return;
+            }
+
+            DPRINTF("husb: async. reap urb failed errno %d\n", errno);
+            return;
+        }
+
+        DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
+                aurb, aurb->urb.status, aurb->urb.actual_length);
+
+        /* If this is a buffered iso urb mark it as complete and don't do
+           anything else (it is handled further in usb_host_handle_iso_data) */
+        if (aurb->iso_frame_idx == -1) {
+            int inflight;
+            if (aurb->urb.status == -EPIPE) {
+                set_halt(s, aurb->urb.endpoint & 0xf);
+            }
+            aurb->iso_frame_idx = 0;
+            urbs++;
+            inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);
+            if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {
+                fprintf(stderr, "husb: out of buffers for iso stream\n");
+            }
+            continue;
+        }
+
+        p = aurb->packet;
+
+        if (p) {
+            switch (aurb->urb.status) {
+            case 0:
+                p->len += aurb->urb.actual_length;
+                break;
+
+            case -EPIPE:
+                set_halt(s, p->devep);
+                p->len = USB_RET_STALL;
+                break;
+
+            default:
+                p->len = USB_RET_NAK;
+                break;
+            }
+
+            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
+                usb_generic_async_ctrl_complete(&s->dev, p);
+            } else if (!aurb->more) {
+                usb_packet_complete(&s->dev, p);
+            }
+        }
+
+        async_free(aurb);
+    }
+}
+
+static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+    AsyncURB *aurb;
+
+    QLIST_FOREACH(aurb, &s->aurbs, next) {
+        if (p != aurb->packet) {
+            continue;
+        }
+
+        DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
+
+        /* Mark it as dead (see async_complete above) */
+        aurb->packet = NULL;
+
+        int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
+        if (r < 0) {
+            DPRINTF("husb: async. discard urb failed errno %d\n", errno);
+        }
+    }
+}
+
+static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
+{
+    const char *op = NULL;
+    int dev_descr_len, config_descr_len;
+    int interface, nb_interfaces;
+    int ret, i;
+
+    if (configuration == 0) /* address state - ignore */
+        return 1;
+
+    DPRINTF("husb: claiming interfaces. config %d\n", configuration);
+
+    i = 0;
+    dev_descr_len = dev->descr[0];
+    if (dev_descr_len > dev->descr_len) {
+        fprintf(stderr, "husb: update iface failed. descr too short\n");
+        return 0;
+    }
+
+    i += dev_descr_len;
+    while (i < dev->descr_len) {
+        DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
+                i, dev->descr_len,
+               dev->descr[i], dev->descr[i+1]);
+
+        if (dev->descr[i+1] != USB_DT_CONFIG) {
+            i += dev->descr[i];
+            continue;
+        }
+        config_descr_len = dev->descr[i];
+
+        printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
+
+        if (configuration < 0 || configuration == dev->descr[i + 5]) {
+            configuration = dev->descr[i + 5];
+            break;
+        }
+
+        i += config_descr_len;
+    }
+
+    if (i >= dev->descr_len) {
+        fprintf(stderr,
+                "husb: update iface failed. no matching configuration\n");
+        return 0;
+    }
+    nb_interfaces = dev->descr[i + 4];
+
+#ifdef USBDEVFS_DISCONNECT
+    /* earlier Linux 2.4 do not support that */
+    {
+        struct usbdevfs_ioctl ctrl;
+        for (interface = 0; interface < nb_interfaces; interface++) {
+            ctrl.ioctl_code = USBDEVFS_DISCONNECT;
+            ctrl.ifno = interface;
+            ctrl.data = 0;
+            op = "USBDEVFS_DISCONNECT";
+            ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
+            if (ret < 0 && errno != ENODATA) {
+                goto fail;
+            }
+        }
+    }
+#endif
+
+    /* XXX: only grab if all interfaces are free */
+    for (interface = 0; interface < nb_interfaces; interface++) {
+        op = "USBDEVFS_CLAIMINTERFACE";
+        ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
+        if (ret < 0) {
+            if (errno == EBUSY) {
+                printf("husb: update iface. device already grabbed\n");
+            } else {
+                perror("husb: failed to claim interface");
+            }
+            goto fail;
+        }
+    }
+
+    printf("husb: %d interfaces claimed for configuration %d\n",
+           nb_interfaces, configuration);
+
+    dev->ninterfaces   = nb_interfaces;
+    dev->configuration = configuration;
+    return 1;
+
+fail:
+    if (errno == ENODEV) {
+        do_disconnect(dev);
+    }
+    perror(op);
+    return 0;
+}
+
+static int usb_host_release_interfaces(USBHostDevice *s)
+{
+    int ret, i;
+
+    DPRINTF("husb: releasing interfaces\n");
+
+    for (i = 0; i < s->ninterfaces; i++) {
+        ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
+        if (ret < 0) {
+            perror("husb: failed to release interface");
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static void usb_host_handle_reset(USBDevice *dev)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+
+    DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
+
+    ioctl(s->fd, USBDEVFS_RESET);
+
+    usb_host_claim_interfaces(s, s->configuration);
+}
+
+static void usb_host_handle_destroy(USBDevice *dev)
+{
+    USBHostDevice *s = (USBHostDevice *)dev;
+
+    usb_host_close(s);
+    QTAILQ_REMOVE(&hostdevs, s, next);
+    qemu_remove_exit_notifier(&s->exit);
+}
+
+static int usb_linux_update_endp_table(USBHostDevice *s);
+
+/* iso data is special, we need to keep enough urbs in flight to make sure
+   that the controller never runs out of them, otherwise the device will
+   likely suffer a buffer underrun / overrun. */
+static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
+{
+    AsyncURB *aurb;
+    int i, j, len = get_max_packet_size(s, ep);
+
+    aurb = qemu_mallocz(s->iso_urb_count * sizeof(*aurb));
+    for (i = 0; i < s->iso_urb_count; i++) {
+        aurb[i].urb.endpoint      = ep;
+        aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
+        aurb[i].urb.buffer        = qemu_malloc(aurb[i].urb.buffer_length);
+        aurb[i].urb.type          = USBDEVFS_URB_TYPE_ISO;
+        aurb[i].urb.flags         = USBDEVFS_URB_ISO_ASAP;
+        aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
+        for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
+            aurb[i].urb.iso_frame_desc[j].length = len;
+        if (in) {
+            aurb[i].urb.endpoint |= 0x80;
+            /* Mark as fully consumed (idle) */
+            aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
+        }
+    }
+    set_iso_urb(s, ep, aurb);
+
+    return aurb;
+}
+
+static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
+{
+    AsyncURB *aurb;
+    int i, ret, killed = 0, free = 1;
+
+    aurb = get_iso_urb(s, ep);
+    if (!aurb) {
+        return;
+    }
+
+    for (i = 0; i < s->iso_urb_count; i++) {
+        /* in flight? */
+        if (aurb[i].iso_frame_idx == -1) {
+            ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
+            if (ret < 0) {
+                printf("husb: discard isoc in urb failed errno %d\n", errno);
+                free = 0;
+                continue;
+            }
+            killed++;
+        }
+    }
+
+    /* Make sure any urbs we've killed are reaped before we free them */
+    if (killed) {
+        async_complete(s);
+    }
+
+    for (i = 0; i < s->iso_urb_count; i++) {
+        qemu_free(aurb[i].urb.buffer);
+    }
+
+    if (free)
+        qemu_free(aurb);
+    else
+        printf("husb: leaking iso urbs because of discard failure\n");
+    set_iso_urb(s, ep, NULL);
+    set_iso_urb_idx(s, ep, 0);
+    clear_iso_started(s, ep);
+}
+
+static int urb_status_to_usb_ret(int status)
+{
+    switch (status) {
+    case -EPIPE:
+        return USB_RET_STALL;
+    default:
+        return USB_RET_NAK;
+    }
+}
+
+static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+{
+    AsyncURB *aurb;
+    int i, j, ret, max_packet_size, offset, len = 0;
+
+    max_packet_size = get_max_packet_size(s, p->devep);
+    if (max_packet_size == 0)
+        return USB_RET_NAK;
+
+    aurb = get_iso_urb(s, p->devep);
+    if (!aurb) {
+        aurb = usb_host_alloc_iso(s, p->devep, in);
+    }
+
+    i = get_iso_urb_idx(s, p->devep);
+    j = aurb[i].iso_frame_idx;
+    if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
+        if (in) {
+            /* Check urb status  */
+            if (aurb[i].urb.status) {
+                len = urb_status_to_usb_ret(aurb[i].urb.status);
+                /* Move to the next urb */
+                aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
+            /* Check frame status */
+            } else if (aurb[i].urb.iso_frame_desc[j].status) {
+                len = urb_status_to_usb_ret(
+                                        aurb[i].urb.iso_frame_desc[j].status);
+            /* Check the frame fits */
+            } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
+                printf("husb: received iso data is larger then packet\n");
+                len = USB_RET_NAK;
+            /* All good copy data over */
+            } else {
+                len = aurb[i].urb.iso_frame_desc[j].actual_length;
+                memcpy(p->data,
+                       aurb[i].urb.buffer +
+                           j * aurb[i].urb.iso_frame_desc[0].length,
+                       len);
+            }
+        } else {
+            len = p->len;
+            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
+
+            /* Check the frame fits */
+            if (len > max_packet_size) {
+                printf("husb: send iso data is larger then max packet size\n");
+                return USB_RET_NAK;
+            }
+
+            /* All good copy data over */
+            memcpy(aurb[i].urb.buffer + offset, p->data, len);
+            aurb[i].urb.iso_frame_desc[j].length = len;
+            offset += len;
+            set_iso_buffer_used(s, p->devep, offset);
+
+            /* Start the stream once we have buffered enough data */
+            if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
+                set_iso_started(s, p->devep);
+            }
+        }
+        aurb[i].iso_frame_idx++;
+        if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+            i = (i + 1) % s->iso_urb_count;
+            set_iso_urb_idx(s, p->devep, i);
+        }
+    } else {
+        if (in) {
+            set_iso_started(s, p->devep);
+        } else {
+            DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
+        }
+    }
+
+    if (is_iso_started(s, p->devep)) {
+        /* (Re)-submit all fully consumed / filled urbs */
+        for (i = 0; i < s->iso_urb_count; i++) {
+            if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+                ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
+                if (ret < 0) {
+                    printf("husb error submitting iso urb %d: %d\n", i, errno);
+                    if (!in || len == 0) {
+                        switch(errno) {
+                        case ETIMEDOUT:
+                            len = USB_RET_NAK;
+                            break;
+                        case EPIPE:
+                        default:
+                            len = USB_RET_STALL;
+                        }
+                    }
+                    break;
+                }
+                aurb[i].iso_frame_idx = -1;
+                change_iso_inflight(s, p->devep, +1);
+            }
+        }
+    }
+
+    return len;
+}
+
+static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+    struct usbdevfs_urb *urb;
+    AsyncURB *aurb;
+    int ret, rem;
+    uint8_t *pbuf;
+    uint8_t ep;
+
+    if (!is_valid(s, p->devep)) {
+        return USB_RET_NAK;
+    }
+
+    if (p->pid == USB_TOKEN_IN) {
+        ep = p->devep | 0x80;
+    } else {
+        ep = p->devep;
+    }
+
+    if (is_halted(s, p->devep)) {
+        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
+        if (ret < 0) {
+            DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
+                   ep, errno);
+            return USB_RET_NAK;
+        }
+        clear_halt(s, p->devep);
+    }
+
+    if (is_isoc(s, p->devep)) {
+        return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
+    }
+
+    rem = p->len;
+    pbuf = p->data;
+    p->len = 0;
+    while (rem) {
+        aurb = async_alloc(s);
+        aurb->packet = p;
+
+        urb = &aurb->urb;
+        urb->endpoint      = ep;
+        urb->type          = USBDEVFS_URB_TYPE_BULK;
+        urb->usercontext   = s;
+        urb->buffer        = pbuf;
+
+        if (rem > MAX_USBFS_BUFFER_SIZE) {
+            urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
+            aurb->more         = 1;
+        } else {
+            urb->buffer_length = rem;
+            aurb->more         = 0;
+        }
+        pbuf += urb->buffer_length;
+        rem  -= urb->buffer_length;
+
+        ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
+
+        DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
+                urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
+
+        if (ret < 0) {
+            DPRINTF("husb: submit failed. errno %d\n", errno);
+            async_free(aurb);
+
+            switch(errno) {
+            case ETIMEDOUT:
+                return USB_RET_NAK;
+            case EPIPE:
+            default:
+                return USB_RET_STALL;
+            }
+        }
+    }
+
+    return USB_RET_ASYNC;
+}
+
+static int ctrl_error(void)
+{
+    if (errno == ETIMEDOUT) {
+        return USB_RET_NAK;
+    } else {
+        return USB_RET_STALL;
+    }
+}
+
+static int usb_host_set_address(USBHostDevice *s, int addr)
+{
+    DPRINTF("husb: ctrl set addr %u\n", addr);
+    s->dev.addr = addr;
+    return 0;
+}
+
+static int usb_host_set_config(USBHostDevice *s, int config)
+{
+    usb_host_release_interfaces(s);
+
+    int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
+
+    DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
+
+    if (ret < 0) {
+        return ctrl_error();
+    }
+    usb_host_claim_interfaces(s, config);
+    return 0;
+}
+
+static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
+{
+    struct usbdevfs_setinterface si;
+    int i, ret;
+
+    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+        if (is_isoc(s, i)) {
+            usb_host_stop_n_free_iso(s, i);
+        }
+    }
+
+    si.interface  = iface;
+    si.altsetting = alt;
+    ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
+
+    DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
+            iface, alt, ret, errno);
+
+    if (ret < 0) {
+        return ctrl_error();
+    }
+    usb_linux_update_endp_table(s);
+    return 0;
+}
+
+static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
+               int request, int value, int index, int length, uint8_t *data)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+    struct usbdevfs_urb *urb;
+    AsyncURB *aurb;
+    int ret;
+
+    /*
+     * Process certain standard device requests.
+     * These are infrequent and are processed synchronously.
+     */
+
+    /* Note request is (bRequestType << 8) | bRequest */
+    DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
+            request >> 8, request & 0xff, value, index, length);
+
+    switch (request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        return usb_host_set_address(s, value);
+
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        return usb_host_set_config(s, value & 0xff);
+
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        return usb_host_set_interface(s, index, value);
+    }
+
+    /* The rest are asynchronous */
+
+    if (length > sizeof(dev->data_buf)) {
+        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
+                length, sizeof(dev->data_buf));
+        return USB_RET_STALL;
+    }
+
+    aurb = async_alloc(s);
+    aurb->packet = p;
+
+    /*
+     * Setup ctrl transfer.
+     *
+     * s->ctrl is laid out such that data buffer immediately follows
+     * 'req' struct which is exactly what usbdevfs expects.
+     */
+    urb = &aurb->urb;
+
+    urb->type     = USBDEVFS_URB_TYPE_CONTROL;
+    urb->endpoint = p->devep;
+
+    urb->buffer        = &dev->setup_buf;
+    urb->buffer_length = length + 8;
+
+    urb->usercontext = s;
+
+    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
+
+    DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
+
+    if (ret < 0) {
+        DPRINTF("husb: submit failed. errno %d\n", errno);
+        async_free(aurb);
+
+        switch(errno) {
+        case ETIMEDOUT:
+            return USB_RET_NAK;
+        case EPIPE:
+        default:
+            return USB_RET_STALL;
+        }
+    }
+
+    return USB_RET_ASYNC;
+}
+
+static int usb_linux_get_configuration(USBHostDevice *s)
+{
+    uint8_t configuration;
+    struct usb_ctrltransfer ct;
+    int ret;
+
+    if (usb_fs_type == USB_FS_SYS) {
+        char device_name[32], line[1024];
+        int configuration;
+
+        sprintf(device_name, "%d-%s", s->bus_num, s->port);
+
+        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
+                                device_name)) {
+            goto usbdevfs;
+        }
+        if (sscanf(line, "%d", &configuration) != 1) {
+            goto usbdevfs;
+        }
+        return configuration;
+    }
+
+usbdevfs:
+    ct.bRequestType = USB_DIR_IN;
+    ct.bRequest = USB_REQ_GET_CONFIGURATION;
+    ct.wValue = 0;
+    ct.wIndex = 0;
+    ct.wLength = 1;
+    ct.data = &configuration;
+    ct.timeout = 50;
+
+    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
+    if (ret < 0) {
+        perror("usb_linux_get_configuration");
+        return -1;
+    }
+
+    /* in address state */
+    if (configuration == 0) {
+        return -1;
+    }
+
+    return configuration;
+}
+
+static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
+    uint8_t configuration, uint8_t interface)
+{
+    uint8_t alt_setting;
+    struct usb_ctrltransfer ct;
+    int ret;
+
+    if (usb_fs_type == USB_FS_SYS) {
+        char device_name[64], line[1024];
+        int alt_setting;
+
+        sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
+                (int)configuration, (int)interface);
+
+        if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
+                                device_name)) {
+            goto usbdevfs;
+        }
+        if (sscanf(line, "%d", &alt_setting) != 1) {
+            goto usbdevfs;
+        }
+        return alt_setting;
+    }
+
+usbdevfs:
+    ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
+    ct.bRequest = USB_REQ_GET_INTERFACE;
+    ct.wValue = 0;
+    ct.wIndex = interface;
+    ct.wLength = 1;
+    ct.data = &alt_setting;
+    ct.timeout = 50;
+    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
+    if (ret < 0) {
+        /* Assume alt 0 on error */
+        return 0;
+    }
+
+    return alt_setting;
+}
+
+/* returns 1 on problem encountered or 0 for success */
+static int usb_linux_update_endp_table(USBHostDevice *s)
+{
+    uint8_t *descriptors;
+    uint8_t devep, type, configuration, alt_interface;
+    int interface, length, i;
+
+    for (i = 0; i < MAX_ENDPOINTS; i++)
+        s->endp_table[i].type = INVALID_EP_TYPE;
+
+    i = usb_linux_get_configuration(s);
+    if (i < 0)
+        return 1;
+    configuration = i;
+
+    /* get the desired configuration, interface, and endpoint descriptors
+     * from device description */
+    descriptors = &s->descr[18];
+    length = s->descr_len - 18;
+    i = 0;
+
+    if (descriptors[i + 1] != USB_DT_CONFIG ||
+        descriptors[i + 5] != configuration) {
+        DPRINTF("invalid descriptor data - configuration\n");
+        return 1;
+    }
+    i += descriptors[i];
+
+    while (i < length) {
+        if (descriptors[i + 1] != USB_DT_INTERFACE ||
+            (descriptors[i + 1] == USB_DT_INTERFACE &&
+             descriptors[i + 4] == 0)) {
+            i += descriptors[i];
+            continue;
+        }
+
+        interface = descriptors[i + 2];
+        alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
+
+        /* the current interface descriptor is the active interface
+         * and has endpoints */
+        if (descriptors[i + 3] != alt_interface) {
+            i += descriptors[i];
+            continue;
+        }
+
+        /* advance to the endpoints */
+        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
+            i += descriptors[i];
+        }
+
+        if (i >= length)
+            break;
+
+        while (i < length) {
+            if (descriptors[i + 1] != USB_DT_ENDPOINT) {
+                break;
+            }
+
+            devep = descriptors[i + 2];
+            if ((devep & 0x0f) == 0) {
+                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
+                return 1;
+            }
+
+            switch (descriptors[i + 3] & 0x3) {
+            case 0x00:
+                type = USBDEVFS_URB_TYPE_CONTROL;
+                break;
+            case 0x01:
+                type = USBDEVFS_URB_TYPE_ISO;
+                set_max_packet_size(s, (devep & 0xf), descriptors + i);
+                break;
+            case 0x02:
+                type = USBDEVFS_URB_TYPE_BULK;
+                break;
+            case 0x03:
+                type = USBDEVFS_URB_TYPE_INTERRUPT;
+                break;
+            default:
+                DPRINTF("usb_host: malformed endpoint type\n");
+                type = USBDEVFS_URB_TYPE_BULK;
+            }
+            s->endp_table[(devep & 0xf) - 1].type = type;
+            s->endp_table[(devep & 0xf) - 1].halted = 0;
+
+            i += descriptors[i];
+        }
+    }
+    return 0;
+}
+
+/*
+ * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
+ * this function assumes this is safe, if:
+ * 1) There are no isoc endpoints
+ * 2) There are no interrupt endpoints with a max_packet_size > 64
+ * Note bulk endpoints with a max_packet_size > 64 in theory also are not
+ * usb1 compatible, but in practice this seems to work fine.
+ */
+static int usb_linux_full_speed_compat(USBHostDevice *dev)
+{
+    int i, packet_size;
+
+    /*
+     * usb_linux_update_endp_table only registers info about ep in the current
+     * interface altsettings, so we need to parse the descriptors again.
+     */
+    for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
+        if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
+            switch (dev->descr[i + 3] & 0x3) {
+            case 0x00: /* CONTROL */
+                break;
+            case 0x01: /* ISO */
+                return 0;
+            case 0x02: /* BULK */
+                break;
+            case 0x03: /* INTERRUPT */
+                packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
+                if (packet_size > 64)
+                    return 0;
+                break;
+            }
+        }
+    }
+    return 1;
+}
+
+static int usb_host_open(USBHostDevice *dev, int bus_num,
+                        int addr, char *port, const char *prod_name, int speed)
+{
+    int fd = -1, ret;
+    char buf[1024];
+
+    if (dev->fd != -1) {
+        goto fail;
+    }
+    printf("husb: open device %d.%d\n", bus_num, addr);
+
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto fail;
+    }
+    snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
+             bus_num, addr);
+    fd = open(buf, O_RDWR | O_NONBLOCK);
+    if (fd < 0) {
+        perror(buf);
+        goto fail;
+    }
+    DPRINTF("husb: opened %s\n", buf);
+
+    dev->bus_num = bus_num;
+    dev->addr = addr;
+    strcpy(dev->port, port);
+    dev->fd = fd;
+
+    /* read the device description */
+    dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
+    if (dev->descr_len <= 0) {
+        perror("husb: reading device data failed");
+        goto fail;
+    }
+
+#ifdef DEBUG
+    {
+        int x;
+        printf("=== begin dumping device descriptor data ===\n");
+        for (x = 0; x < dev->descr_len; x++) {
+            printf("%02x ", dev->descr[x]);
+        }
+        printf("\n=== end dumping device descriptor data ===\n");
+    }
+#endif
+
+
+    /*
+     * Initial configuration is -1 which makes us claim first
+     * available config. We used to start with 1, which does not
+     * always work. I've seen devices where first config starts
+     * with 2.
+     */
+    if (!usb_host_claim_interfaces(dev, -1)) {
+        goto fail;
+    }
+
+    ret = usb_linux_update_endp_table(dev);
+    if (ret) {
+        goto fail;
+    }
+
+    if (speed == -1) {
+        struct usbdevfs_connectinfo ci;
+
+        ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
+        if (ret < 0) {
+            perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
+            goto fail;
+        }
+
+        if (ci.slow) {
+            speed = USB_SPEED_LOW;
+        } else {
+            speed = USB_SPEED_HIGH;
+        }
+    }
+    dev->dev.speed = speed;
+    dev->dev.speedmask = (1 << speed);
+    if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
+        dev->dev.speedmask |= USB_SPEED_MASK_FULL;
+    }
+
+    printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
+
+    if (!prod_name || prod_name[0] == '\0') {
+        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                 "host:%d.%d", bus_num, addr);
+    } else {
+        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                prod_name);
+    }
+
+    ret = usb_device_attach(&dev->dev);
+    if (ret) {
+        goto fail;
+    }
+
+    /* USB devio uses 'write' flag to check for async completions */
+    qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
+
+    return 0;
+
+fail:
+    if (dev->fd != -1) {
+        close(dev->fd);
+        dev->fd = -1;
+    }
+    return -1;
+}
+
+static int usb_host_close(USBHostDevice *dev)
+{
+    int i;
+
+    if (dev->fd == -1 || !dev->dev.attached) {
+        return -1;
+    }
+
+    qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
+    dev->closing = 1;
+    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+        if (is_isoc(dev, i)) {
+            usb_host_stop_n_free_iso(dev, i);
+        }
+    }
+    async_complete(dev);
+    dev->closing = 0;
+    usb_device_detach(&dev->dev);
+    ioctl(dev->fd, USBDEVFS_RESET);
+    close(dev->fd);
+    dev->fd = -1;
+    return 0;
+}
+
+static void usb_host_exit_notifier(struct Notifier *n, void *data)
+{
+    USBHostDevice *s = container_of(n, USBHostDevice, exit);
+
+    if (s->fd != -1) {
+        ioctl(s->fd, USBDEVFS_RESET);
+    }
+}
+
+static int usb_host_initfn(USBDevice *dev)
+{
+    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
+
+    dev->auto_attach = 0;
+    s->fd = -1;
+    QTAILQ_INSERT_TAIL(&hostdevs, s, next);
+    s->exit.notify = usb_host_exit_notifier;
+    qemu_add_exit_notifier(&s->exit);
+    usb_host_auto_check(NULL);
+    return 0;
+}
+
+static struct USBDeviceInfo usb_host_dev_info = {
+    .product_desc   = "USB Host Device",
+    .qdev.name      = "usb-host",
+    .qdev.size      = sizeof(USBHostDevice),
+    .init           = usb_host_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usb_host_async_cancel,
+    .handle_data    = usb_host_handle_data,
+    .handle_control = usb_host_handle_control,
+    .handle_reset   = usb_host_handle_reset,
+    .handle_destroy = usb_host_handle_destroy,
+    .usbdevice_name = "host",
+    .usbdevice_init = usb_host_device_open,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
+        DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
+        DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
+        DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
+        DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
+        DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void usb_host_register_devices(void)
+{
+    usb_qdev_register(&usb_host_dev_info);
+}
+device_init(usb_host_register_devices)
+
+USBDevice *usb_host_device_open(const char *devname)
+{
+    struct USBAutoFilter filter;
+    USBDevice *dev;
+    char *p;
+
+    dev = usb_create(NULL /* FIXME */, "usb-host");
+
+    if (strstr(devname, "auto:")) {
+        if (parse_filter(devname, &filter) < 0) {
+            goto fail;
+        }
+    } else {
+        if ((p = strchr(devname, '.'))) {
+            filter.bus_num    = strtoul(devname, NULL, 0);
+            filter.addr       = strtoul(p + 1, NULL, 0);
+            filter.vendor_id  = 0;
+            filter.product_id = 0;
+        } else if ((p = strchr(devname, ':'))) {
+            filter.bus_num    = 0;
+            filter.addr       = 0;
+            filter.vendor_id  = strtoul(devname, NULL, 16);
+            filter.product_id = strtoul(p + 1, NULL, 16);
+        } else {
+            goto fail;
+        }
+    }
+
+    qdev_prop_set_uint32(&dev->qdev, "hostbus",   filter.bus_num);
+    qdev_prop_set_uint32(&dev->qdev, "hostaddr",  filter.addr);
+    qdev_prop_set_uint32(&dev->qdev, "vendorid",  filter.vendor_id);
+    qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+
+fail:
+    qdev_free(&dev->qdev);
+    return NULL;
+}
+
+int usb_host_device_close(const char *devname)
+{
+#if 0
+    char product_name[PRODUCT_NAME_SZ];
+    int bus_num, addr;
+    USBHostDevice *s;
+
+    if (strstr(devname, "auto:")) {
+        return usb_host_auto_del(devname);
+    }
+    if (usb_host_find_device(&bus_num, &addr, product_name,
+                                    sizeof(product_name), devname) < 0) {
+        return -1;
+    }
+    s = hostdev_find(bus_num, addr);
+    if (s) {
+        usb_device_delete_addr(s->bus_num, s->dev.addr);
+        return 0;
+    }
+#endif
+
+    return -1;
+}
+
+static int get_tag_value(char *buf, int buf_size,
+                         const char *str, const char *tag,
+                         const char *stopchars)
+{
+    const char *p;
+    char *q;
+    p = strstr(str, tag);
+    if (!p) {
+        return -1;
+    }
+    p += strlen(tag);
+    while (qemu_isspace(*p)) {
+        p++;
+    }
+    q = buf;
+    while (*p != '\0' && !strchr(stopchars, *p)) {
+        if ((q - buf) < (buf_size - 1)) {
+            *q++ = *p;
+        }
+        p++;
+    }
+    *q = '\0';
+    return q - buf;
+}
+
+/*
+ * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
+ * host's USB devices. This is legacy support since many distributions
+ * are moving to /sys/bus/usb
+ */
+static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
+{
+    FILE *f = NULL;
+    char line[1024];
+    char buf[1024];
+    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
+    char product_name[512];
+    int ret = 0;
+
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto the_end;
+    }
+    snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
+    f = fopen(line, "r");
+    if (!f) {
+        perror("husb: cannot open devices file");
+        goto the_end;
+    }
+
+    device_count = 0;
+    bus_num = addr = class_id = product_id = vendor_id = 0;
+    speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
+    for(;;) {
+        if (fgets(line, sizeof(line), f) == NULL) {
+            break;
+        }
+        if (strlen(line) > 0) {
+            line[strlen(line) - 1] = '\0';
+        }
+        if (line[0] == 'T' && line[1] == ':') {
+            if (device_count && (vendor_id || product_id)) {
+                /* New device.  Add the previously discovered device.  */
+                ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
+                           product_id, product_name, speed);
+                if (ret) {
+                    goto the_end;
+                }
+            }
+            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
+                goto fail;
+            }
+            bus_num = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
+                goto fail;
+            }
+            addr = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
+                goto fail;
+            }
+            if (!strcmp(buf, "5000")) {
+                speed = USB_SPEED_SUPER;
+            } else if (!strcmp(buf, "480")) {
+                speed = USB_SPEED_HIGH;
+            } else if (!strcmp(buf, "1.5")) {
+                speed = USB_SPEED_LOW;
+            } else {
+                speed = USB_SPEED_FULL;
+            }
+            product_name[0] = '\0';
+            class_id = 0xff;
+            device_count++;
+            product_id = 0;
+            vendor_id = 0;
+        } else if (line[0] == 'P' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
+                goto fail;
+            }
+            vendor_id = strtoul(buf, NULL, 16);
+            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
+                goto fail;
+            }
+            product_id = strtoul(buf, NULL, 16);
+        } else if (line[0] == 'S' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
+                goto fail;
+            }
+            pstrcpy(product_name, sizeof(product_name), buf);
+        } else if (line[0] == 'D' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
+                goto fail;
+            }
+            class_id = strtoul(buf, NULL, 16);
+        }
+    fail: ;
+    }
+    if (device_count && (vendor_id || product_id)) {
+        /* Add the last device.  */
+        ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
+                   product_id, product_name, speed);
+    }
+ the_end:
+    if (f) {
+        fclose(f);
+    }
+    return ret;
+}
+
+/*
+ * Read sys file-system device file
+ *
+ * @line address of buffer to put file contents in
+ * @line_size size of line
+ * @device_file path to device file (printf format string)
+ * @device_name device being opened (inserted into device_file)
+ *
+ * @return 0 failed, 1 succeeded ('line' contains data)
+ */
+static int usb_host_read_file(char *line, size_t line_size,
+                              const char *device_file, const char *device_name)
+{
+    FILE *f;
+    int ret = 0;
+    char filename[PATH_MAX];
+
+    snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
+             device_file);
+    f = fopen(filename, "r");
+    if (f) {
+        ret = fgets(line, line_size, f) != NULL;
+        fclose(f);
+    }
+
+    return ret;
+}
+
+/*
+ * Use /sys/bus/usb/devices/ directory to determine host's USB
+ * devices.
+ *
+ * This code is based on Robert Schiele's original patches posted to
+ * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
+ */
+static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
+{
+    DIR *dir = NULL;
+    char line[1024];
+    int bus_num, addr, speed, class_id, product_id, vendor_id;
+    int ret = 0;
+    char port[MAX_PORTLEN];
+    char product_name[512];
+    struct dirent *de;
+
+    dir = opendir(USBSYSBUS_PATH "/devices");
+    if (!dir) {
+        perror("husb: cannot open devices directory");
+        goto the_end;
+    }
+
+    while ((de = readdir(dir))) {
+        if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
+            if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
+                continue;
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
+                goto the_end;
+            }
+            if (sscanf(line, "%d", &addr) != 1) {
+                goto the_end;
+            }
+            if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
+                                    de->d_name)) {
+                goto the_end;
+            }
+            if (sscanf(line, "%x", &class_id) != 1) {
+                goto the_end;
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), "idVendor",
+                                    de->d_name)) {
+                goto the_end;
+            }
+            if (sscanf(line, "%x", &vendor_id) != 1) {
+                goto the_end;
+            }
+            if (!usb_host_read_file(line, sizeof(line), "idProduct",
+                                    de->d_name)) {
+                goto the_end;
+            }
+            if (sscanf(line, "%x", &product_id) != 1) {
+                goto the_end;
+            }
+            if (!usb_host_read_file(line, sizeof(line), "product",
+                                    de->d_name)) {
+                *product_name = 0;
+            } else {
+                if (strlen(line) > 0) {
+                    line[strlen(line) - 1] = '\0';
+                }
+                pstrcpy(product_name, sizeof(product_name), line);
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
+                goto the_end;
+            }
+            if (!strcmp(line, "5000\n")) {
+                speed = USB_SPEED_SUPER;
+            } else if (!strcmp(line, "480\n")) {
+                speed = USB_SPEED_HIGH;
+            } else if (!strcmp(line, "1.5\n")) {
+                speed = USB_SPEED_LOW;
+            } else {
+                speed = USB_SPEED_FULL;
+            }
+
+            ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
+                       product_id, product_name, speed);
+            if (ret) {
+                goto the_end;
+            }
+        }
+    }
+ the_end:
+    if (dir) {
+        closedir(dir);
+    }
+    return ret;
+}
+
+/*
+ * Determine how to access the host's USB devices and call the
+ * specific support function.
+ */
+static int usb_host_scan(void *opaque, USBScanFunc *func)
+{
+    Monitor *mon = cur_mon;
+    FILE *f = NULL;
+    DIR *dir = NULL;
+    int ret = 0;
+    const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
+    char devpath[PATH_MAX];
+
+    /* only check the host once */
+    if (!usb_fs_type) {
+        dir = opendir(USBSYSBUS_PATH "/devices");
+        if (dir) {
+            /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_SYS;
+            closedir(dir);
+            DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
+            goto found_devices;
+        }
+        f = fopen(USBPROCBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /proc/bus/usb/ */
+            strcpy(devpath, USBPROCBUS_PATH);
+            usb_fs_type = USB_FS_PROC;
+            fclose(f);
+            DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
+            goto found_devices;
+        }
+        /* try additional methods if an access method hasn't been found yet */
+        f = fopen(USBDEVBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /dev/bus/usb/ */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_DEV;
+            fclose(f);
+            DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
+            goto found_devices;
+        }
+    found_devices:
+        if (!usb_fs_type) {
+            if (mon) {
+                monitor_printf(mon, "husb: unable to access USB devices\n");
+            }
+            return -ENOENT;
+        }
+
+        /* the module setting (used later for opening devices) */
+        usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
+        strcpy(usb_host_device_path, devpath);
+        if (mon) {
+            monitor_printf(mon, "husb: using %s file-system with %s\n",
+                           fs_type[usb_fs_type], usb_host_device_path);
+        }
+    }
+
+    switch (usb_fs_type) {
+    case USB_FS_PROC:
+    case USB_FS_DEV:
+        ret = usb_host_scan_dev(opaque, func);
+        break;
+    case USB_FS_SYS:
+        ret = usb_host_scan_sys(opaque, func);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
+    return ret;
+}
+
+static QEMUTimer *usb_auto_timer;
+
+static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
+                              int class_id, int vendor_id, int product_id,
+                              const char *product_name, int speed)
+{
+    struct USBAutoFilter *f;
+    struct USBHostDevice *s;
+
+    /* Ignore hubs */
+    if (class_id == 9)
+        return 0;
+
+    QTAILQ_FOREACH(s, &hostdevs, next) {
+        f = &s->match;
+
+        if (f->bus_num > 0 && f->bus_num != bus_num) {
+            continue;
+        }
+        if (f->addr > 0 && f->addr != addr) {
+            continue;
+        }
+        if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
+            continue;
+        }
+
+        if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
+            continue;
+        }
+
+        if (f->product_id > 0 && f->product_id != product_id) {
+            continue;
+        }
+        /* We got a match */
+
+        /* Already attached ? */
+        if (s->fd != -1) {
+            return 0;
+        }
+        DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
+
+        usb_host_open(s, bus_num, addr, port, product_name, speed);
+        break;
+    }
+
+    return 0;
+}
+
+static void usb_host_auto_check(void *unused)
+{
+    struct USBHostDevice *s;
+    int unconnected = 0;
+
+    usb_host_scan(NULL, usb_host_auto_scan);
+
+    QTAILQ_FOREACH(s, &hostdevs, next) {
+        if (s->fd == -1) {
+            unconnected++;
+        }
+    }
+
+    if (unconnected == 0) {
+        /* nothing to watch */
+        if (usb_auto_timer) {
+            qemu_del_timer(usb_auto_timer);
+        }
+        return;
+    }
+
+    if (!usb_auto_timer) {
+        usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
+        if (!usb_auto_timer) {
+            return;
+        }
+    }
+    qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
+}
+
+/*
+ * Autoconnect filter
+ * Format:
+ *    auto:bus:dev[:vid:pid]
+ *    auto:bus.dev[:vid:pid]
+ *
+ *    bus  - bus number    (dec, * means any)
+ *    dev  - device number (dec, * means any)
+ *    vid  - vendor id     (hex, * means any)
+ *    pid  - product id    (hex, * means any)
+ *
+ *    See 'lsusb' output.
+ */
+static int parse_filter(const char *spec, struct USBAutoFilter *f)
+{
+    enum { BUS, DEV, VID, PID, DONE };
+    const char *p = spec;
+    int i;
+
+    f->bus_num    = 0;
+    f->addr       = 0;
+    f->vendor_id  = 0;
+    f->product_id = 0;
+
+    for (i = BUS; i < DONE; i++) {
+        p = strpbrk(p, ":.");
+        if (!p) {
+            break;
+        }
+        p++;
+
+        if (*p == '*') {
+            continue;
+        }
+        switch(i) {
+        case BUS: f->bus_num = strtol(p, NULL, 10);    break;
+        case DEV: f->addr    = strtol(p, NULL, 10);    break;
+        case VID: f->vendor_id  = strtol(p, NULL, 16); break;
+        case PID: f->product_id = strtol(p, NULL, 16); break;
+        }
+    }
+
+    if (i < DEV) {
+        fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**********************/
+/* USB host device info */
+
+struct usb_class_info {
+    int class;
+    const char *class_name;
+};
+
+static const struct usb_class_info usb_class_info[] = {
+    { USB_CLASS_AUDIO, "Audio"},
+    { USB_CLASS_COMM, "Communication"},
+    { USB_CLASS_HID, "HID"},
+    { USB_CLASS_HUB, "Hub" },
+    { USB_CLASS_PHYSICAL, "Physical" },
+    { USB_CLASS_PRINTER, "Printer" },
+    { USB_CLASS_MASS_STORAGE, "Storage" },
+    { USB_CLASS_CDC_DATA, "Data" },
+    { USB_CLASS_APP_SPEC, "Application Specific" },
+    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
+    { USB_CLASS_STILL_IMAGE, "Still Image" },
+    { USB_CLASS_CSCID, "Smart Card" },
+    { USB_CLASS_CONTENT_SEC, "Content Security" },
+    { -1, NULL }
+};
+
+static const char *usb_class_str(uint8_t class)
+{
+    const struct usb_class_info *p;
+    for(p = usb_class_info; p->class != -1; p++) {
+        if (p->class == class) {
+            break;
+        }
+    }
+    return p->class_name;
+}
+
+static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
+                            int class_id, int vendor_id, int product_id,
+                            const char *product_name,
+                            int speed)
+{
+    const char *class_str, *speed_str;
+
+    switch(speed) {
+    case USB_SPEED_LOW:
+        speed_str = "1.5";
+        break;
+    case USB_SPEED_FULL:
+        speed_str = "12";
+        break;
+    case USB_SPEED_HIGH:
+        speed_str = "480";
+        break;
+    case USB_SPEED_SUPER:
+        speed_str = "5000";
+        break;
+    default:
+        speed_str = "?";
+        break;
+    }
+
+    monitor_printf(mon, "  Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
+                   bus_num, addr, port, speed_str);
+    class_str = usb_class_str(class_id);
+    if (class_str) {
+        monitor_printf(mon, "    %s:", class_str);
+    } else {
+        monitor_printf(mon, "    Class %02x:", class_id);
+    }
+    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
+    if (product_name[0] != '\0') {
+        monitor_printf(mon, ", %s", product_name);
+    }
+    monitor_printf(mon, "\n");
+}
+
+static int usb_host_info_device(void *opaque, int bus_num, int addr,
+                                char *path, int class_id,
+                                int vendor_id, int product_id,
+                                const char *product_name,
+                                int speed)
+{
+    Monitor *mon = opaque;
+
+    usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
+                    product_name, speed);
+    return 0;
+}
+
+static void dec2str(int val, char *str, size_t size)
+{
+    if (val == 0) {
+        snprintf(str, size, "*");
+    } else {
+        snprintf(str, size, "%d", val);
+    }
+}
+
+static void hex2str(int val, char *str, size_t size)
+{
+    if (val == 0) {
+        snprintf(str, size, "*");
+    } else {
+        snprintf(str, size, "%04x", val);
+    }
+}
+
+void usb_host_info(Monitor *mon)
+{
+    struct USBAutoFilter *f;
+    struct USBHostDevice *s;
+
+    usb_host_scan(mon, usb_host_info_device);
+
+    if (QTAILQ_EMPTY(&hostdevs)) {
+        return;
+    }
+
+    monitor_printf(mon, "  Auto filters:\n");
+    QTAILQ_FOREACH(s, &hostdevs, next) {
+        char bus[10], addr[10], vid[10], pid[10];
+        f = &s->match;
+        dec2str(f->bus_num, bus, sizeof(bus));
+        dec2str(f->addr, addr, sizeof(addr));
+        hex2str(f->vendor_id, vid, sizeof(vid));
+        hex2str(f->product_id, pid, sizeof(pid));
+        monitor_printf(mon, "    Bus %s, Addr %s, Port %s, ID %s:%s\n",
+                       bus, addr, f->port ? f->port : "*", vid, pid);
+    }
+}
diff --git a/qemu-0.15.x/usb-redir.c b/qemu-0.15.x/usb-redir.c
new file mode 100644
index 0000000..e212993
--- /dev/null
+++ b/qemu-0.15.x/usb-redir.c
@@ -0,0 +1,1218 @@
+/*
+ * USB redirector usb-guest
+ *
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Red Hat Authors:
+ * Hans de Goede <hdegoede at redhat.com>
+ *
+ * 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 "qemu-common.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "sysemu.h"
+
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <usbredirparser.h>
+
+#include "hw/usb.h"
+
+#define MAX_ENDPOINTS 32
+#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
+#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
+
+typedef struct AsyncURB AsyncURB;
+typedef struct USBRedirDevice USBRedirDevice;
+
+/* Struct to hold buffered packets (iso or int input packets) */
+struct buf_packet {
+    uint8_t *data;
+    int len;
+    int status;
+    QTAILQ_ENTRY(buf_packet)next;
+};
+
+struct endp_data {
+    uint8_t type;
+    uint8_t interval;
+    uint8_t interface; /* bInterfaceNumber this ep belongs to */
+    uint8_t iso_started;
+    uint8_t iso_error; /* For reporting iso errors to the HC */
+    uint8_t interrupt_started;
+    uint8_t interrupt_error;
+    QTAILQ_HEAD(, buf_packet) bufpq;
+};
+
+struct USBRedirDevice {
+    USBDevice dev;
+    /* Properties */
+    CharDriverState *cs;
+    uint8_t debug;
+    /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
+    const uint8_t *read_buf;
+    int read_buf_size;
+    /* For async handling of open/close */
+    QEMUBH *open_close_bh;
+    /* To delay the usb attach in case of quick chardev close + open */
+    QEMUTimer *attach_timer;
+    int64_t next_attach_time;
+    struct usbredirparser *parser;
+    struct endp_data endpoint[MAX_ENDPOINTS];
+    uint32_t packet_id;
+    QTAILQ_HEAD(, AsyncURB) asyncq;
+};
+
+struct AsyncURB {
+    USBRedirDevice *dev;
+    USBPacket *packet;
+    uint32_t packet_id;
+    int get;
+    union {
+        struct usb_redir_control_packet_header control_packet;
+        struct usb_redir_bulk_packet_header bulk_packet;
+        struct usb_redir_interrupt_packet_header interrupt_packet;
+    };
+    QTAILQ_ENTRY(AsyncURB)next;
+};
+
+static void usbredir_device_connect(void *priv,
+    struct usb_redir_device_connect_header *device_connect);
+static void usbredir_device_disconnect(void *priv);
+static void usbredir_interface_info(void *priv,
+    struct usb_redir_interface_info_header *interface_info);
+static void usbredir_ep_info(void *priv,
+    struct usb_redir_ep_info_header *ep_info);
+static void usbredir_configuration_status(void *priv, uint32_t id,
+    struct usb_redir_configuration_status_header *configuration_status);
+static void usbredir_alt_setting_status(void *priv, uint32_t id,
+    struct usb_redir_alt_setting_status_header *alt_setting_status);
+static void usbredir_iso_stream_status(void *priv, uint32_t id,
+    struct usb_redir_iso_stream_status_header *iso_stream_status);
+static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+    struct usb_redir_interrupt_receiving_status_header
+    *interrupt_receiving_status);
+static void usbredir_bulk_streams_status(void *priv, uint32_t id,
+    struct usb_redir_bulk_streams_status_header *bulk_streams_status);
+static void usbredir_control_packet(void *priv, uint32_t id,
+    struct usb_redir_control_packet_header *control_packet,
+    uint8_t *data, int data_len);
+static void usbredir_bulk_packet(void *priv, uint32_t id,
+    struct usb_redir_bulk_packet_header *bulk_packet,
+    uint8_t *data, int data_len);
+static void usbredir_iso_packet(void *priv, uint32_t id,
+    struct usb_redir_iso_packet_header *iso_packet,
+    uint8_t *data, int data_len);
+static void usbredir_interrupt_packet(void *priv, uint32_t id,
+    struct usb_redir_interrupt_packet_header *interrupt_header,
+    uint8_t *data, int data_len);
+
+static int usbredir_handle_status(USBRedirDevice *dev,
+                                       int status, int actual_len);
+
+#define VERSION "qemu usb-redir guest " QEMU_VERSION
+
+/*
+ * Logging stuff
+ */
+
+#define ERROR(...) \
+    do { \
+        if (dev->debug >= usbredirparser_error) { \
+            error_report("usb-redir error: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define WARNING(...) \
+    do { \
+        if (dev->debug >= usbredirparser_warning) { \
+            error_report("usb-redir warning: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define INFO(...) \
+    do { \
+        if (dev->debug >= usbredirparser_info) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define DPRINTF(...) \
+    do { \
+        if (dev->debug >= usbredirparser_debug) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+#define DPRINTF2(...) \
+    do { \
+        if (dev->debug >= usbredirparser_debug_data) { \
+            error_report("usb-redir: " __VA_ARGS__); \
+        } \
+    } while (0)
+
+static void usbredir_log(void *priv, int level, const char *msg)
+{
+    USBRedirDevice *dev = priv;
+
+    if (dev->debug < level) {
+        return;
+    }
+
+    error_report("%s\n", msg);
+}
+
+static void usbredir_log_data(USBRedirDevice *dev, const char *desc,
+    const uint8_t *data, int len)
+{
+    int i, j, n;
+
+    if (dev->debug < usbredirparser_debug_data) {
+        return;
+    }
+
+    for (i = 0; i < len; i += j) {
+        char buf[128];
+
+        n = sprintf(buf, "%s", desc);
+        for (j = 0; j < 8 && i + j < len; j++) {
+            n += sprintf(buf + n, " %02X", data[i + j]);
+        }
+        error_report("%s\n", buf);
+    }
+}
+
+/*
+ * usbredirparser io functions
+ */
+
+static int usbredir_read(void *priv, uint8_t *data, int count)
+{
+    USBRedirDevice *dev = priv;
+
+    if (dev->read_buf_size < count) {
+        count = dev->read_buf_size;
+    }
+
+    memcpy(data, dev->read_buf, count);
+
+    dev->read_buf_size -= count;
+    if (dev->read_buf_size) {
+        dev->read_buf += count;
+    } else {
+        dev->read_buf = NULL;
+    }
+
+    return count;
+}
+
+static int usbredir_write(void *priv, uint8_t *data, int count)
+{
+    USBRedirDevice *dev = priv;
+
+    return qemu_chr_write(dev->cs, data, count);
+}
+
+/*
+ * Async and buffered packets helpers
+ */
+
+static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p)
+{
+    AsyncURB *aurb = (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
+    aurb->dev = dev;
+    aurb->packet = p;
+    aurb->packet_id = dev->packet_id;
+    QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next);
+    dev->packet_id++;
+
+    return aurb;
+}
+
+static void async_free(USBRedirDevice *dev, AsyncURB *aurb)
+{
+    QTAILQ_REMOVE(&dev->asyncq, aurb, next);
+    qemu_free(aurb);
+}
+
+static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id)
+{
+    AsyncURB *aurb;
+
+    QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
+        if (aurb->packet_id == packet_id) {
+            return aurb;
+        }
+    }
+    ERROR("could not find async urb for packet_id %u\n", packet_id);
+    return NULL;
+}
+
+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    AsyncURB *aurb;
+
+    QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
+        if (p != aurb->packet) {
+            continue;
+        }
+
+        DPRINTF("async cancel id %u\n", aurb->packet_id);
+        usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id);
+        usbredirparser_do_write(dev->parser);
+
+        /* Mark it as dead */
+        aurb->packet = NULL;
+        break;
+    }
+}
+
+static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+    uint8_t *data, int len, int status, uint8_t ep)
+{
+    struct buf_packet *bufp = qemu_malloc(sizeof(struct buf_packet));
+    bufp->data   = data;
+    bufp->len    = len;
+    bufp->status = status;
+    QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    return bufp;
+}
+
+static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
+    uint8_t ep)
+{
+    QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    free(bufp->data);
+    qemu_free(bufp);
+}
+
+static void usbredir_free_bufpq(USBRedirDevice *dev, uint8_t ep)
+{
+    struct buf_packet *buf, *buf_next;
+
+    QTAILQ_FOREACH_SAFE(buf, &dev->endpoint[EP2I(ep)].bufpq, next, buf_next) {
+        bufp_free(dev, buf, ep);
+    }
+}
+
+/*
+ * USBDevice callbacks
+ */
+
+static void usbredir_handle_reset(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+
+    DPRINTF("reset device\n");
+    usbredirparser_send_reset(dev->parser);
+    usbredirparser_do_write(dev->parser);
+}
+
+static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+                                     uint8_t ep)
+{
+    int status, len;
+
+    if (!dev->endpoint[EP2I(ep)].iso_started &&
+            !dev->endpoint[EP2I(ep)].iso_error) {
+        struct usb_redir_start_iso_stream_header start_iso = {
+            .endpoint = ep,
+            /* TODO maybe do something with these depending on ep interval? */
+            .pkts_per_urb = 32,
+            .no_urbs = 3,
+        };
+        /* No id, we look at the ep when receiving a status back */
+        usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
+        usbredirparser_do_write(dev->parser);
+        DPRINTF("iso stream started ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 1;
+    }
+
+    if (ep & USB_DIR_IN) {
+        struct buf_packet *isop;
+
+        isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+        if (isop == NULL) {
+            DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+            /* Check iso_error for stream errors, otherwise its an underrun */
+            status = dev->endpoint[EP2I(ep)].iso_error;
+            dev->endpoint[EP2I(ep)].iso_error = 0;
+            return usbredir_handle_status(dev, status, 0);
+        }
+        DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
+                 isop->len);
+
+        status = isop->status;
+        if (status != usb_redir_success) {
+            bufp_free(dev, isop, ep);
+            return usbredir_handle_status(dev, status, 0);
+        }
+
+        len = isop->len;
+        if (len > p->len) {
+            ERROR("received iso data is larger then packet ep %02X\n", ep);
+            bufp_free(dev, isop, ep);
+            return USB_RET_NAK;
+        }
+        memcpy(p->data, isop->data, len);
+        bufp_free(dev, isop, ep);
+        return len;
+    } else {
+        /* If the stream was not started because of a pending error don't
+           send the packet to the usb-host */
+        if (dev->endpoint[EP2I(ep)].iso_started) {
+            struct usb_redir_iso_packet_header iso_packet = {
+                .endpoint = ep,
+                .length = p->len
+            };
+            /* No id, we look at the ep when receiving a status back */
+            usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
+                                           p->data, p->len);
+            usbredirparser_do_write(dev->parser);
+        }
+        status = dev->endpoint[EP2I(ep)].iso_error;
+        dev->endpoint[EP2I(ep)].iso_error = 0;
+        DPRINTF2("iso-token-out ep %02X status %d len %d\n", ep, status,
+                 p->len);
+        return usbredir_handle_status(dev, status, p->len);
+    }
+}
+
+static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
+{
+    struct usb_redir_stop_iso_stream_header stop_iso_stream = {
+        .endpoint = ep
+    };
+    if (dev->endpoint[EP2I(ep)].iso_started) {
+        usbredirparser_send_stop_iso_stream(dev->parser, 0, &stop_iso_stream);
+        DPRINTF("iso stream stopped ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 0;
+    }
+    usbredir_free_bufpq(dev, ep);
+}
+
+static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
+                                      uint8_t ep)
+{
+    AsyncURB *aurb = async_alloc(dev, p);
+    struct usb_redir_bulk_packet_header bulk_packet;
+
+    DPRINTF("bulk-out ep %02X len %d id %u\n", ep, p->len, aurb->packet_id);
+
+    bulk_packet.endpoint  = ep;
+    bulk_packet.length    = p->len;
+    bulk_packet.stream_id = 0;
+    aurb->bulk_packet = bulk_packet;
+
+    if (ep & USB_DIR_IN) {
+        usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
+                                        &bulk_packet, NULL, 0);
+    } else {
+        usbredir_log_data(dev, "bulk data out:", p->data, p->len);
+        usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
+                                        &bulk_packet, p->data, p->len);
+    }
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
+                                           USBPacket *p, uint8_t ep)
+{
+    if (ep & USB_DIR_IN) {
+        /* Input interrupt endpoint, buffered packet input */
+        struct buf_packet *intp;
+        int status, len;
+
+        if (!dev->endpoint[EP2I(ep)].interrupt_started &&
+                !dev->endpoint[EP2I(ep)].interrupt_error) {
+            struct usb_redir_start_interrupt_receiving_header start_int = {
+                .endpoint = ep,
+            };
+            /* No id, we look at the ep when receiving a status back */
+            usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
+                                                          &start_int);
+            usbredirparser_do_write(dev->parser);
+            DPRINTF("interrupt recv started ep %02X\n", ep);
+            dev->endpoint[EP2I(ep)].interrupt_started = 1;
+        }
+
+        intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+        if (intp == NULL) {
+            DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
+            /* Check interrupt_error for stream errors */
+            status = dev->endpoint[EP2I(ep)].interrupt_error;
+            dev->endpoint[EP2I(ep)].interrupt_error = 0;
+            return usbredir_handle_status(dev, status, 0);
+        }
+        DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
+                intp->status, intp->len);
+
+        status = intp->status;
+        if (status != usb_redir_success) {
+            bufp_free(dev, intp, ep);
+            return usbredir_handle_status(dev, status, 0);
+        }
+
+        len = intp->len;
+        if (len > p->len) {
+            ERROR("received int data is larger then packet ep %02X\n", ep);
+            bufp_free(dev, intp, ep);
+            return USB_RET_NAK;
+        }
+        memcpy(p->data, intp->data, len);
+        bufp_free(dev, intp, ep);
+        return len;
+    } else {
+        /* Output interrupt endpoint, normal async operation */
+        AsyncURB *aurb = async_alloc(dev, p);
+        struct usb_redir_interrupt_packet_header interrupt_packet;
+
+        DPRINTF("interrupt-out ep %02X len %d id %u\n", ep, p->len,
+                aurb->packet_id);
+
+        interrupt_packet.endpoint  = ep;
+        interrupt_packet.length    = p->len;
+        aurb->interrupt_packet     = interrupt_packet;
+
+        usbredir_log_data(dev, "interrupt data out:", p->data, p->len);
+        usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
+                                        &interrupt_packet, p->data, p->len);
+        usbredirparser_do_write(dev->parser);
+        return USB_RET_ASYNC;
+    }
+}
+
+static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
+    uint8_t ep)
+{
+    struct usb_redir_stop_interrupt_receiving_header stop_interrupt_recv = {
+        .endpoint = ep
+    };
+    if (dev->endpoint[EP2I(ep)].interrupt_started) {
+        usbredirparser_send_stop_interrupt_receiving(dev->parser, 0,
+                                                     &stop_interrupt_recv);
+        DPRINTF("interrupt recv stopped ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].interrupt_started = 0;
+    }
+    usbredir_free_bufpq(dev, ep);
+}
+
+static int usbredir_handle_data(USBDevice *udev, USBPacket *p)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    uint8_t ep;
+
+    ep = p->devep;
+    if (p->pid == USB_TOKEN_IN) {
+        ep |= USB_DIR_IN;
+    }
+
+    switch (dev->endpoint[EP2I(ep)].type) {
+    case USB_ENDPOINT_XFER_CONTROL:
+        ERROR("handle_data called for control transfer on ep %02X\n", ep);
+        return USB_RET_NAK;
+    case USB_ENDPOINT_XFER_ISOC:
+        return usbredir_handle_iso_data(dev, p, ep);
+    case USB_ENDPOINT_XFER_BULK:
+        return usbredir_handle_bulk_data(dev, p, ep);;
+    case USB_ENDPOINT_XFER_INT:
+        return usbredir_handle_interrupt_data(dev, p, ep);;
+    default:
+        ERROR("handle_data ep %02X has unknown type %d\n", ep,
+              dev->endpoint[EP2I(ep)].type);
+        return USB_RET_NAK;
+    }
+}
+
+static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
+                                int config)
+{
+    struct usb_redir_set_configuration_header set_config;
+    AsyncURB *aurb = async_alloc(dev, p);
+    int i;
+
+    DPRINTF("set config %d id %u\n", config, aurb->packet_id);
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        switch (dev->endpoint[i].type) {
+        case USB_ENDPOINT_XFER_ISOC:
+            usbredir_stop_iso_stream(dev, I2EP(i));
+            break;
+        case USB_ENDPOINT_XFER_INT:
+            if (i & 0x10) {
+                usbredir_stop_interrupt_receiving(dev, I2EP(i));
+            }
+            break;
+        }
+        usbredir_free_bufpq(dev, I2EP(i));
+    }
+
+    set_config.configuration = config;
+    usbredirparser_send_set_configuration(dev->parser, aurb->packet_id,
+                                          &set_config);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
+{
+    AsyncURB *aurb = async_alloc(dev, p);
+
+    DPRINTF("get config id %u\n", aurb->packet_id);
+
+    aurb->get = 1;
+    usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
+                                   int interface, int alt)
+{
+    struct usb_redir_set_alt_setting_header set_alt;
+    AsyncURB *aurb = async_alloc(dev, p);
+    int i;
+
+    DPRINTF("set interface %d alt %d id %u\n", interface, alt,
+            aurb->packet_id);
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        if (dev->endpoint[i].interface == interface) {
+            switch (dev->endpoint[i].type) {
+            case USB_ENDPOINT_XFER_ISOC:
+                usbredir_stop_iso_stream(dev, I2EP(i));
+                break;
+            case USB_ENDPOINT_XFER_INT:
+                if (i & 0x10) {
+                    usbredir_stop_interrupt_receiving(dev, I2EP(i));
+                }
+                break;
+            }
+            usbredir_free_bufpq(dev, I2EP(i));
+        }
+    }
+
+    set_alt.interface = interface;
+    set_alt.alt = alt;
+    usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id,
+                                        &set_alt);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
+                                   int interface)
+{
+    struct usb_redir_get_alt_setting_header get_alt;
+    AsyncURB *aurb = async_alloc(dev, p);
+
+    DPRINTF("get interface %d id %u\n", interface, aurb->packet_id);
+
+    get_alt.interface = interface;
+    aurb->get = 1;
+    usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
+                                        &get_alt);
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
+        int request, int value, int index, int length, uint8_t *data)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    struct usb_redir_control_packet_header control_packet;
+    AsyncURB *aurb;
+
+    /* Special cases for certain standard device requests */
+    switch (request) {
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        DPRINTF("set address %d\n", value);
+        dev->dev.addr = value;
+        return 0;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        return usbredir_set_config(dev, p, value & 0xff);
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        return usbredir_get_config(dev, p);
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        return usbredir_set_interface(dev, p, index, value);
+    case InterfaceRequest | USB_REQ_GET_INTERFACE:
+        return usbredir_get_interface(dev, p, index);
+    }
+
+    /* "Normal" ctrl requests */
+    aurb = async_alloc(dev, p);
+
+    /* Note request is (bRequestType << 8) | bRequest */
+    DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n",
+            request >> 8, request & 0xff, value, index, length,
+            aurb->packet_id);
+
+    control_packet.request     = request & 0xFF;
+    control_packet.requesttype = request >> 8;
+    control_packet.endpoint    = control_packet.requesttype & USB_DIR_IN;
+    control_packet.value       = value;
+    control_packet.index       = index;
+    control_packet.length      = length;
+    aurb->control_packet       = control_packet;
+
+    if (control_packet.requesttype & USB_DIR_IN) {
+        usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
+                                           &control_packet, NULL, 0);
+    } else {
+        usbredir_log_data(dev, "ctrl data out:", data, length);
+        usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
+                                           &control_packet, data, length);
+    }
+    usbredirparser_do_write(dev->parser);
+    return USB_RET_ASYNC;
+}
+
+/*
+ * Close events can be triggered by usbredirparser_do_write which gets called
+ * from within the USBDevice data / control packet callbacks and doing a
+ * usb_detach from within these callbacks is not a good idea.
+ *
+ * So we use a bh handler to take care of close events. We also handle
+ * open events from this callback to make sure that a close directly followed
+ * by an open gets handled in the right order.
+ */
+static void usbredir_open_close_bh(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    usbredir_device_disconnect(dev);
+
+    if (dev->parser) {
+        usbredirparser_destroy(dev->parser);
+        dev->parser = NULL;
+    }
+
+    if (dev->cs->opened) {
+        dev->parser = qemu_oom_check(usbredirparser_create());
+        dev->parser->priv = dev;
+        dev->parser->log_func = usbredir_log;
+        dev->parser->read_func = usbredir_read;
+        dev->parser->write_func = usbredir_write;
+        dev->parser->device_connect_func = usbredir_device_connect;
+        dev->parser->device_disconnect_func = usbredir_device_disconnect;
+        dev->parser->interface_info_func = usbredir_interface_info;
+        dev->parser->ep_info_func = usbredir_ep_info;
+        dev->parser->configuration_status_func = usbredir_configuration_status;
+        dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
+        dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
+        dev->parser->interrupt_receiving_status_func =
+            usbredir_interrupt_receiving_status;
+        dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
+        dev->parser->control_packet_func = usbredir_control_packet;
+        dev->parser->bulk_packet_func = usbredir_bulk_packet;
+        dev->parser->iso_packet_func = usbredir_iso_packet;
+        dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
+        dev->read_buf = NULL;
+        dev->read_buf_size = 0;
+        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
+        usbredirparser_do_write(dev->parser);
+    }
+}
+
+static void usbredir_do_attach(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    usb_device_attach(&dev->dev);
+}
+
+/*
+ * chardev callbacks
+ */
+
+static int usbredir_chardev_can_read(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    if (dev->parser) {
+        /* usbredir_parser_do_read will consume *all* data we give it */
+        return 1024 * 1024;
+    } else {
+        /* usbredir_open_close_bh hasn't handled the open event yet */
+        return 0;
+    }
+}
+
+static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
+{
+    USBRedirDevice *dev = opaque;
+
+    /* No recursion allowed! */
+    assert(dev->read_buf == NULL);
+
+    dev->read_buf = buf;
+    dev->read_buf_size = size;
+
+    usbredirparser_do_read(dev->parser);
+    /* Send any acks, etc. which may be queued now */
+    usbredirparser_do_write(dev->parser);
+}
+
+static void usbredir_chardev_event(void *opaque, int event)
+{
+    USBRedirDevice *dev = opaque;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+    case CHR_EVENT_CLOSED:
+        qemu_bh_schedule(dev->open_close_bh);
+        break;
+    }
+}
+
+/*
+ * init + destroy
+ */
+
+static int usbredir_initfn(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    int i;
+
+    if (dev->cs == NULL) {
+        qerror_report(QERR_MISSING_PARAMETER, "chardev");
+        return -1;
+    }
+
+    dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
+    dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
+
+    QTAILQ_INIT(&dev->asyncq);
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        QTAILQ_INIT(&dev->endpoint[i].bufpq);
+    }
+
+    /* We'll do the attach once we receive the speed from the usb-host */
+    udev->auto_attach = 0;
+
+    qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
+                          usbredir_chardev_read, usbredir_chardev_event, dev);
+
+    return 0;
+}
+
+static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
+{
+    AsyncURB *aurb, *next_aurb;
+    int i;
+
+    QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) {
+        async_free(dev, aurb);
+    }
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        usbredir_free_bufpq(dev, I2EP(i));
+    }
+}
+
+static void usbredir_handle_destroy(USBDevice *udev)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+
+    qemu_chr_close(dev->cs);
+    /* Note must be done after qemu_chr_close, as that causes a close event */
+    qemu_bh_delete(dev->open_close_bh);
+
+    qemu_del_timer(dev->attach_timer);
+    qemu_free_timer(dev->attach_timer);
+
+    usbredir_cleanup_device_queues(dev);
+
+    if (dev->parser) {
+        usbredirparser_destroy(dev->parser);
+    }
+}
+
+/*
+ * usbredirparser packet complete callbacks
+ */
+
+static int usbredir_handle_status(USBRedirDevice *dev,
+                                       int status, int actual_len)
+{
+    switch (status) {
+    case usb_redir_success:
+        return actual_len;
+    case usb_redir_stall:
+        return USB_RET_STALL;
+    case usb_redir_cancelled:
+        WARNING("returning cancelled packet to HC?\n");
+    case usb_redir_inval:
+    case usb_redir_ioerror:
+    case usb_redir_timeout:
+    default:
+        return USB_RET_NAK;
+    }
+}
+
+static void usbredir_device_connect(void *priv,
+    struct usb_redir_device_connect_header *device_connect)
+{
+    USBRedirDevice *dev = priv;
+
+    switch (device_connect->speed) {
+    case usb_redir_speed_low:
+        DPRINTF("attaching low speed device\n");
+        dev->dev.speed = USB_SPEED_LOW;
+        break;
+    case usb_redir_speed_full:
+        DPRINTF("attaching full speed device\n");
+        dev->dev.speed = USB_SPEED_FULL;
+        break;
+    case usb_redir_speed_high:
+        DPRINTF("attaching high speed device\n");
+        dev->dev.speed = USB_SPEED_HIGH;
+        break;
+    case usb_redir_speed_super:
+        DPRINTF("attaching super speed device\n");
+        dev->dev.speed = USB_SPEED_SUPER;
+        break;
+    default:
+        DPRINTF("attaching unknown speed device, assuming full speed\n");
+        dev->dev.speed = USB_SPEED_FULL;
+    }
+    dev->dev.speedmask = (1 << dev->dev.speed);
+    qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
+}
+
+static void usbredir_device_disconnect(void *priv)
+{
+    USBRedirDevice *dev = priv;
+
+    /* Stop any pending attaches */
+    qemu_del_timer(dev->attach_timer);
+
+    if (dev->dev.attached) {
+        usb_device_detach(&dev->dev);
+        usbredir_cleanup_device_queues(dev);
+        /*
+         * Delay next usb device attach to give the guest a chance to see
+         * see the detach / attach in case of quick close / open succession
+         */
+        dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200;
+    }
+}
+
+static void usbredir_interface_info(void *priv,
+    struct usb_redir_interface_info_header *interface_info)
+{
+    /* The intention is to allow specifying acceptable interface classes
+       for redirection on the cmdline and in the future verify this here,
+       and disconnect (or never connect) the device if a not accepted
+       interface class is detected */
+}
+
+static void usbredir_ep_info(void *priv,
+    struct usb_redir_ep_info_header *ep_info)
+{
+    USBRedirDevice *dev = priv;
+    int i;
+
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        dev->endpoint[i].type = ep_info->type[i];
+        dev->endpoint[i].interval = ep_info->interval[i];
+        dev->endpoint[i].interface = ep_info->interface[i];
+        if (dev->endpoint[i].type != usb_redir_type_invalid) {
+            DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
+                    dev->endpoint[i].type, dev->endpoint[i].interface);
+        }
+    }
+}
+
+static void usbredir_configuration_status(void *priv, uint32_t id,
+    struct usb_redir_configuration_status_header *config_status)
+{
+    USBRedirDevice *dev = priv;
+    AsyncURB *aurb;
+    int len = 0;
+
+    DPRINTF("set config status %d config %d id %u\n", config_status->status,
+            config_status->configuration, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        return;
+    }
+    if (aurb->packet) {
+        if (aurb->get) {
+            dev->dev.data_buf[0] = config_status->configuration;
+            len = 1;
+        }
+        aurb->packet->len =
+            usbredir_handle_status(dev, config_status->status, len);
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+}
+
+static void usbredir_alt_setting_status(void *priv, uint32_t id,
+    struct usb_redir_alt_setting_status_header *alt_setting_status)
+{
+    USBRedirDevice *dev = priv;
+    AsyncURB *aurb;
+    int len = 0;
+
+    DPRINTF("alt status %d intf %d alt %d id: %u\n",
+            alt_setting_status->status,
+            alt_setting_status->interface,
+            alt_setting_status->alt, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        return;
+    }
+    if (aurb->packet) {
+        if (aurb->get) {
+            dev->dev.data_buf[0] = alt_setting_status->alt;
+            len = 1;
+        }
+        aurb->packet->len =
+            usbredir_handle_status(dev, alt_setting_status->status, len);
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+}
+
+static void usbredir_iso_stream_status(void *priv, uint32_t id,
+    struct usb_redir_iso_stream_status_header *iso_stream_status)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = iso_stream_status->endpoint;
+
+    DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
+            ep, id);
+
+    dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status;
+    if (iso_stream_status->status == usb_redir_stall) {
+        DPRINTF("iso stream stopped by peer ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].iso_started = 0;
+    }
+}
+
+static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+    struct usb_redir_interrupt_receiving_status_header
+    *interrupt_receiving_status)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = interrupt_receiving_status->endpoint;
+
+    DPRINTF("interrupt recv status %d ep %02X id %u\n",
+            interrupt_receiving_status->status, ep, id);
+
+    dev->endpoint[EP2I(ep)].interrupt_error =
+        interrupt_receiving_status->status;
+    if (interrupt_receiving_status->status == usb_redir_stall) {
+        DPRINTF("interrupt receiving stopped by peer ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].interrupt_started = 0;
+    }
+}
+
+static void usbredir_bulk_streams_status(void *priv, uint32_t id,
+    struct usb_redir_bulk_streams_status_header *bulk_streams_status)
+{
+}
+
+static void usbredir_control_packet(void *priv, uint32_t id,
+    struct usb_redir_control_packet_header *control_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    int len = control_packet->length;
+    AsyncURB *aurb;
+
+    DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
+            len, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        free(data);
+        return;
+    }
+
+    aurb->control_packet.status = control_packet->status;
+    aurb->control_packet.length = control_packet->length;
+    if (memcmp(&aurb->control_packet, control_packet,
+               sizeof(*control_packet))) {
+        ERROR("return control packet mismatch, please report this!\n");
+        len = USB_RET_NAK;
+    }
+
+    if (aurb->packet) {
+        len = usbredir_handle_status(dev, control_packet->status, len);
+        if (len > 0) {
+            usbredir_log_data(dev, "ctrl data in:", data, data_len);
+            if (data_len <= sizeof(dev->dev.data_buf)) {
+                memcpy(dev->dev.data_buf, data, data_len);
+            } else {
+                ERROR("ctrl buffer too small (%d > %zu)\n",
+                      data_len, sizeof(dev->dev.data_buf));
+                len = USB_RET_STALL;
+            }
+        }
+        aurb->packet->len = len;
+        usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+    free(data);
+}
+
+static void usbredir_bulk_packet(void *priv, uint32_t id,
+    struct usb_redir_bulk_packet_header *bulk_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = bulk_packet->endpoint;
+    int len = bulk_packet->length;
+    AsyncURB *aurb;
+
+    DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
+            ep, len, id);
+
+    aurb = async_find(dev, id);
+    if (!aurb) {
+        free(data);
+        return;
+    }
+
+    if (aurb->bulk_packet.endpoint != bulk_packet->endpoint ||
+            aurb->bulk_packet.stream_id != bulk_packet->stream_id) {
+        ERROR("return bulk packet mismatch, please report this!\n");
+        len = USB_RET_NAK;
+    }
+
+    if (aurb->packet) {
+        len = usbredir_handle_status(dev, bulk_packet->status, len);
+        if (len > 0) {
+            usbredir_log_data(dev, "bulk data in:", data, data_len);
+            if (data_len <= aurb->packet->len) {
+                memcpy(aurb->packet->data, data, data_len);
+            } else {
+                ERROR("bulk buffer too small (%d > %d)\n", data_len,
+                      aurb->packet->len);
+                len = USB_RET_STALL;
+            }
+        }
+        aurb->packet->len = len;
+        usb_packet_complete(&dev->dev, aurb->packet);
+    }
+    async_free(dev, aurb);
+    free(data);
+}
+
+static void usbredir_iso_packet(void *priv, uint32_t id,
+    struct usb_redir_iso_packet_header *iso_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = iso_packet->endpoint;
+
+    DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep,
+             data_len, id);
+
+    if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
+        ERROR("received iso packet for non iso endpoint %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    if (dev->endpoint[EP2I(ep)].iso_started == 0) {
+        DPRINTF("received iso packet for non started stream ep %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    /* bufp_alloc also adds the packet to the ep queue */
+    bufp_alloc(dev, data, data_len, iso_packet->status, ep);
+}
+
+static void usbredir_interrupt_packet(void *priv, uint32_t id,
+    struct usb_redir_interrupt_packet_header *interrupt_packet,
+    uint8_t *data, int data_len)
+{
+    USBRedirDevice *dev = priv;
+    uint8_t ep = interrupt_packet->endpoint;
+
+    DPRINTF("interrupt-in status %d ep %02X len %d id %u\n",
+            interrupt_packet->status, ep, data_len, id);
+
+    if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
+        ERROR("received int packet for non interrupt endpoint %02X\n", ep);
+        free(data);
+        return;
+    }
+
+    if (ep & USB_DIR_IN) {
+        if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
+            DPRINTF("received int packet while not started ep %02X\n", ep);
+            free(data);
+            return;
+        }
+
+        /* bufp_alloc also adds the packet to the ep queue */
+        bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
+    } else {
+        int len = interrupt_packet->length;
+
+        AsyncURB *aurb = async_find(dev, id);
+        if (!aurb) {
+            return;
+        }
+
+        if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) {
+            ERROR("return int packet mismatch, please report this!\n");
+            len = USB_RET_NAK;
+        }
+
+        if (aurb->packet) {
+            aurb->packet->len = usbredir_handle_status(dev,
+                                               interrupt_packet->status, len);
+            usb_packet_complete(&dev->dev, aurb->packet);
+        }
+        async_free(dev, aurb);
+    }
+}
+
+static struct USBDeviceInfo usbredir_dev_info = {
+    .product_desc   = "USB Redirection Device",
+    .qdev.name      = "usb-redir",
+    .qdev.size      = sizeof(USBRedirDevice),
+    .init           = usbredir_initfn,
+    .handle_destroy = usbredir_handle_destroy,
+    .handle_packet  = usb_generic_handle_packet,
+    .cancel_packet  = usbredir_cancel_packet,
+    .handle_reset   = usbredir_handle_reset,
+    .handle_data    = usbredir_handle_data,
+    .handle_control = usbredir_handle_control,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+        DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void usbredir_register_devices(void)
+{
+    usb_qdev_register(&usbredir_dev_info);
+}
+device_init(usbredir_register_devices);
diff --git a/qemu-0.15.x/usb-stub.c b/qemu-0.15.x/usb-stub.c
new file mode 100644
index 0000000..9c3fcea
--- /dev/null
+++ b/qemu-0.15.x/usb-stub.c
@@ -0,0 +1,52 @@
+/*
+ * Stub host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ *      Support for host device auto connect & disconnect
+ *      Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux at tjworld.net>
+ *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ *      to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * 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 "qemu-common.h"
+#include "console.h"
+#include "hw/usb.h"
+#include "monitor.h"
+
+void usb_host_info(Monitor *mon)
+{
+    monitor_printf(mon, "USB host devices not supported\n");
+}
+
+/* XXX: modify configure to compile the right host driver */
+USBDevice *usb_host_device_open(const char *devname)
+{
+    return NULL;
+}
+
+int usb_host_device_close(const char *devname)
+{
+    return 0;
+}
diff --git a/qemu-0.15.x/user-exec.c b/qemu-0.15.x/user-exec.c
new file mode 100644
index 0000000..02c2f8b
--- /dev/null
+++ b/qemu-0.15.x/user-exec.c
@@ -0,0 +1,674 @@
+/*
+ *  User emulator execution
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "exec.h"
+#include "disas.h"
+#include "tcg.h"
+
+#undef EAX
+#undef ECX
+#undef EDX
+#undef EBX
+#undef ESP
+#undef EBP
+#undef ESI
+#undef EDI
+#undef EIP
+#include <signal.h>
+#ifdef __linux__
+#include <sys/ucontext.h>
+#endif
+
+//#define DEBUG_SIGNAL
+
+static void exception_action(CPUState *env1)
+{
+#if defined(TARGET_I386)
+    raise_exception_err(env1->exception_index, env1->error_code);
+#else
+    cpu_loop_exit(env1);
+#endif
+}
+
+/* exit the current TB from a signal handler. The host registers are
+   restored in a state compatible with the CPU emulator
+ */
+void cpu_resume_from_signal(CPUState *env1, void *puc)
+{
+#ifdef __linux__
+    struct ucontext *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#endif
+
+    env = env1;
+
+    /* XXX: restore cpu registers saved in host registers */
+
+    if (puc) {
+        /* XXX: use siglongjmp ? */
+#ifdef __linux__
+#ifdef __ia64
+        sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
+#else
+        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+#endif
+#elif defined(__OpenBSD__)
+        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
+#endif
+    }
+    env->exception_index = -1;
+    longjmp(env->jmp_env, 1);
+}
+
+/* 'pc' is the host PC at which the exception was raised. 'address' is
+   the effective address of the memory exception. 'is_write' is 1 if a
+   write caused the exception and otherwise 0'. 'old_set' is the
+   signal set which should be restored */
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set,
+                                    void *puc)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    if (cpu_single_env) {
+        env = cpu_single_env; /* XXX: find a correct solution for multithread */
+    }
+#if defined(DEBUG_SIGNAL)
+    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+                pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(h2g(address), pc, puc)) {
+        return 1;
+    }
+
+    /* see if it is an MMU fault */
+    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
+    if (ret < 0) {
+        return 0; /* not an MMU fault */
+    }
+    if (ret == 0) {
+        return 1; /* the MMU fault was handled without causing real CPU fault */
+    }
+    /* now we have a real cpu fault */
+    tb = tb_find_pc(pc);
+    if (tb) {
+        /* the PC is inside the translated code. It means that we have
+           a virtual CPU fault */
+        cpu_restore_state(tb, env, pc);
+    }
+
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    exception_action(env);
+
+    /* never comes here */
+    return 1;
+}
+
+#if defined(__i386__)
+
+#if defined(__APPLE__)
+#include <sys/ucontext.h>
+
+#define EIP_sig(context)  (*((unsigned long *)&(context)->uc_mcontext->ss.eip))
+#define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
+#define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__NetBSD__)
+#include <ucontext.h>
+
+#define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
+#define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#include <ucontext.h>
+
+#define EIP_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_eip))
+#define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
+#define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define EIP_sig(context)     ((context)->sc_eip)
+#define TRAP_sig(context)    ((context)->sc_trapno)
+#define ERROR_sig(context)   ((context)->sc_err)
+#define MASK_sig(context)    ((context)->sc_mask)
+#else
+#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
+#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context)    ((context)->uc_sigmask)
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+    unsigned long pc;
+    int trapno;
+
+#ifndef REG_EIP
+/* for glibc 2.1 */
+#define REG_EIP    EIP
+#define REG_ERR    ERR
+#define REG_TRAPNO TRAPNO
+#endif
+    pc = EIP_sig(uc);
+    trapno = TRAP_sig(uc);
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             trapno == 0xe ?
+                             (ERROR_sig(uc) >> 1) & 1 : 0,
+                             &MASK_sig(uc), puc);
+}
+
+#elif defined(__x86_64__)
+
+#ifdef __NetBSD__
+#define PC_sig(context)       _UC_MACHINE_PC(context)
+#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define PC_sig(context)       ((context)->sc_rip)
+#define TRAP_sig(context)     ((context)->sc_trapno)
+#define ERROR_sig(context)    ((context)->sc_err)
+#define MASK_sig(context)     ((context)->sc_mask)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#include <ucontext.h>
+
+#define PC_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_rip))
+#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
+#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#else
+#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
+#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    unsigned long pc;
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+
+    pc = PC_sig(uc);
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             TRAP_sig(uc) == 0xe ?
+                             (ERROR_sig(uc) >> 1) & 1 : 0,
+                             &MASK_sig(uc), puc);
+}
+
+#elif defined(_ARCH_PPC)
+
+/***********************************************************************
+ * signal context platform-specific definitions
+ * From Wine
+ */
+#ifdef linux
+/* All Registers access - only for local access */
+#define REG_sig(reg_name, context)              \
+    ((context)->uc_mcontext.regs->reg_name)
+/* Gpr Registers access  */
+#define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
+/* Program counter */
+#define IAR_sig(context)                       REG_sig(nip, context)
+/* Machine State Register (Supervisor) */
+#define MSR_sig(context)                       REG_sig(msr, context)
+/* Count register */
+#define CTR_sig(context)                       REG_sig(ctr, context)
+/* User's integer exception register */
+#define XER_sig(context)                       REG_sig(xer, context)
+/* Link register */
+#define LR_sig(context)                        REG_sig(link, context)
+/* Condition register */
+#define CR_sig(context)                        REG_sig(ccr, context)
+
+/* Float Registers access  */
+#define FLOAT_sig(reg_num, context)                                     \
+    (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num])
+#define FPSCR_sig(context) \
+    (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
+/* Exception Registers access */
+#define DAR_sig(context)                       REG_sig(dar, context)
+#define DSISR_sig(context)                     REG_sig(dsisr, context)
+#define TRAP_sig(context)                      REG_sig(trap, context)
+#endif /* linux */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <ucontext.h>
+#define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
+#define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
+#define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
+#define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
+#define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
+#define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
+/* Exception Registers access */
+#define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
+#define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
+#define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
+#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
+
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+typedef struct ucontext SIGCONTEXT;
+/* All Registers access - only for local access */
+#define REG_sig(reg_name, context)              \
+    ((context)->uc_mcontext->ss.reg_name)
+#define FLOATREG_sig(reg_name, context)         \
+    ((context)->uc_mcontext->fs.reg_name)
+#define EXCEPREG_sig(reg_name, context)         \
+    ((context)->uc_mcontext->es.reg_name)
+#define VECREG_sig(reg_name, context)           \
+    ((context)->uc_mcontext->vs.reg_name)
+/* Gpr Registers access */
+#define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
+/* Program counter */
+#define IAR_sig(context)                       REG_sig(srr0, context)
+/* Machine State Register (Supervisor) */
+#define MSR_sig(context)                       REG_sig(srr1, context)
+#define CTR_sig(context)                       REG_sig(ctr, context)
+/* Link register */
+#define XER_sig(context)                       REG_sig(xer, context)
+/* User's integer exception register */
+#define LR_sig(context)                        REG_sig(lr, context)
+/* Condition register */
+#define CR_sig(context)                        REG_sig(cr, context)
+/* Float Registers access */
+#define FLOAT_sig(reg_num, context)             \
+    FLOATREG_sig(fpregs[reg_num], context)
+#define FPSCR_sig(context)                      \
+    ((double)FLOATREG_sig(fpscr, context))
+/* Exception Registers access */
+/* Fault registers for coredump */
+#define DAR_sig(context)                       EXCEPREG_sig(dar, context)
+#define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
+/* number of powerpc exception taken */
+#define TRAP_sig(context)                      EXCEPREG_sig(exception, context)
+#endif /* __APPLE__ */
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+    ucontext_t *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
+    unsigned long pc;
+    int is_write;
+
+    pc = IAR_sig(uc);
+    is_write = 0;
+#if 0
+    /* ppc 4xx case */
+    if (DSISR_sig(uc) & 0x00800000) {
+        is_write = 1;
+    }
+#else
+    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
+        is_write = 1;
+    }
+#endif
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__alpha__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                           void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    uint32_t *pc = uc->uc_mcontext.sc_pc;
+    uint32_t insn = *pc;
+    int is_write = 0;
+
+    /* XXX: need kernel patch to get write flag faster */
+    switch (insn >> 26) {
+    case 0x0d: /* stw */
+    case 0x0e: /* stb */
+    case 0x0f: /* stq_u */
+    case 0x24: /* stf */
+    case 0x25: /* stg */
+    case 0x26: /* sts */
+    case 0x27: /* stt */
+    case 0x2c: /* stl */
+    case 0x2d: /* stq */
+    case 0x2e: /* stl_c */
+    case 0x2f: /* stq_c */
+        is_write = 1;
+    }
+
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+#elif defined(__sparc__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    int is_write;
+    uint32_t insn;
+#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
+    uint32_t *regs = (uint32_t *)(info + 1);
+    void *sigmask = (regs + 20);
+    /* XXX: is there a standard glibc define ? */
+    unsigned long pc = regs[1];
+#else
+#ifdef __linux__
+    struct sigcontext *sc = puc;
+    unsigned long pc = sc->sigc_regs.tpc;
+    void *sigmask = (void *)sc->sigc_mask;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+    unsigned long pc = uc->sc_pc;
+    void *sigmask = (void *)(long)uc->sc_mask;
+#endif
+#endif
+
+    /* XXX: need kernel patch to get write flag faster */
+    is_write = 0;
+    insn = *(uint32_t *)pc;
+    if ((insn >> 30) == 3) {
+        switch ((insn >> 19) & 0x3f) {
+        case 0x05: /* stb */
+        case 0x15: /* stba */
+        case 0x06: /* sth */
+        case 0x16: /* stha */
+        case 0x04: /* st */
+        case 0x14: /* sta */
+        case 0x07: /* std */
+        case 0x17: /* stda */
+        case 0x0e: /* stx */
+        case 0x1e: /* stxa */
+        case 0x24: /* stf */
+        case 0x34: /* stfa */
+        case 0x27: /* stdf */
+        case 0x37: /* stdfa */
+        case 0x26: /* stqf */
+        case 0x36: /* stqfa */
+        case 0x25: /* stfsr */
+        case 0x3c: /* casa */
+        case 0x3e: /* casxa */
+            is_write = 1;
+            break;
+        }
+    }
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, sigmask, NULL);
+}
+
+#elif defined(__arm__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    int is_write;
+
+#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+    pc = uc->uc_mcontext.gregs[R15];
+#else
+    pc = uc->uc_mcontext.arm_pc;
+#endif
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write,
+                             &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mc68000)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    int is_write;
+
+    pc = uc->uc_mcontext.gregs[16];
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write,
+                             &uc->uc_sigmask, puc);
+}
+
+#elif defined(__ia64)
+
+#ifndef __ISR_VALID
+  /* This ought to be in <bits/siginfo.h>... */
+# define __ISR_VALID    1
+#endif
+
+int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long ip;
+    int is_write = 0;
+
+    ip = uc->uc_mcontext.sc_ip;
+    switch (host_signum) {
+    case SIGILL:
+    case SIGFPE:
+    case SIGSEGV:
+    case SIGBUS:
+    case SIGTRAP:
+        if (info->si_code && (info->si_segvflags & __ISR_VALID)) {
+            /* ISR.W (write-access) is bit 33:  */
+            is_write = (info->si_isr >> 33) & 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
+                             is_write,
+                             (sigset_t *)&uc->uc_sigmask, puc);
+}
+
+#elif defined(__s390__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    uint16_t *pinsn;
+    int is_write = 0;
+
+    pc = uc->uc_mcontext.psw.addr;
+
+    /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
+       of the normal 2 arguments.  The 3rd argument contains the "int_code"
+       from the hardware which does in fact contain the is_write value.
+       The rt signal handler, as far as I can tell, does not give this value
+       at all.  Not that we could get to it from here even if it were.  */
+    /* ??? This is not even close to complete, since it ignores all
+       of the read-modify-write instructions.  */
+    pinsn = (uint16_t *)pc;
+    switch (pinsn[0] >> 8) {
+    case 0x50: /* ST */
+    case 0x42: /* STC */
+    case 0x40: /* STH */
+        is_write = 1;
+        break;
+    case 0xc4: /* RIL format insns */
+        switch (pinsn[0] & 0xf) {
+        case 0xf: /* STRL */
+        case 0xb: /* STGRL */
+        case 0x7: /* STHRL */
+            is_write = 1;
+        }
+        break;
+    case 0xe3: /* RXY format insns */
+        switch (pinsn[2] & 0xff) {
+        case 0x50: /* STY */
+        case 0x24: /* STG */
+        case 0x72: /* STCY */
+        case 0x70: /* STHY */
+        case 0x8e: /* STPQ */
+        case 0x3f: /* STRVH */
+        case 0x3e: /* STRV */
+        case 0x2f: /* STRVG */
+            is_write = 1;
+        }
+        break;
+    }
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mips__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    greg_t pc = uc->uc_mcontext.pc;
+    int is_write;
+
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__hppa__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    struct siginfo *info = pinfo;
+    struct ucontext *uc = puc;
+    unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
+    uint32_t insn = *(uint32_t *)pc;
+    int is_write = 0;
+
+    /* XXX: need kernel patch to get write flag faster.  */
+    switch (insn >> 26) {
+    case 0x1a: /* STW */
+    case 0x19: /* STH */
+    case 0x18: /* STB */
+    case 0x1b: /* STWM */
+        is_write = 1;
+        break;
+
+    case 0x09: /* CSTWX, FSTWX, FSTWS */
+    case 0x0b: /* CSTDX, FSTDX, FSTDS */
+        /* Distinguish from coprocessor load ... */
+        is_write = (insn >> 9) & 1;
+        break;
+
+    case 0x03:
+        switch ((insn >> 6) & 15) {
+        case 0xa: /* STWS */
+        case 0x9: /* STHS */
+        case 0x8: /* STBS */
+        case 0xe: /* STWAS */
+        case 0xc: /* STBYS */
+            is_write = 1;
+        }
+        break;
+    }
+
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#else
+
+#error host CPU specific signal handler needed
+
+#endif
+
+#if defined(TARGET_I386)
+
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+        selector &= 0xffff;
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
+                               (selector << 4), 0xffff, 0);
+    } else {
+        helper_load_seg(seg_reg, selector);
+    }
+    env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+
+    helper_fsave(ptr, data32);
+
+    env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+
+    helper_frstor(ptr, data32);
+
+    env = saved_env;
+}
+
+#endif /* TARGET_I386 */
diff --git a/qemu-0.15.x/version.rc b/qemu-0.15.x/version.rc
new file mode 100644
index 0000000..82e10ec
--- /dev/null
+++ b/qemu-0.15.x/version.rc
@@ -0,0 +1,28 @@
+#include <winver.h>
+#include "config-host.h"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION CONFIG_FILEVERSION
+PRODUCTVERSION CONFIG_PRODUCTVERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_APP
+FILESUBTYPE VFT2_UNKNOWN
+{
+  BLOCK "StringFileInfo"
+  {
+    BLOCK "040904E4"
+    {
+      VALUE "CompanyName", "http://www.qemu.org"
+      VALUE "FileDescription", "QEMU machine emulators and tools"
+      VALUE "FileVersion", QEMU_VERSION
+      VALUE "LegalCopyright", "Copyright various authors. Released under the GNU General Public License."
+      VALUE "LegalTrademarks", "QEMU is a trademark of Fabrice Bellard."
+      VALUE "ProductName", "QEMU"
+    }
+  }
+  BLOCK "VarFileInfo"
+  {
+    VALUE "Translation", 0x0409, 1252
+  }
+}
diff --git a/qemu-0.15.x/vgafont.h b/qemu-0.15.x/vgafont.h
new file mode 100644
index 0000000..3606dd7
--- /dev/null
+++ b/qemu-0.15.x/vgafont.h
@@ -0,0 +1,4611 @@
+static const uint8_t vgafont16[256 * 16] = {
+
+	/* 0 0x00 '^@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 1 0x01 '^A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x81, /* 10000001 */
+	0xa5, /* 10100101 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 2 0x02 '^B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xdb, /* 11011011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 3 0x03 '^C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 4 0x04 '^D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 5 0x05 '^E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 6 0x06 '^F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 8 0x08 '^H' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xe7, /* 11100111 */
+	0xc3, /* 11000011 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x42, /* 01000010 */
+	0x42, /* 01000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 10 0x0a '^J' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0x99, /* 10011001 */
+	0xbd, /* 10111101 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0xc3, /* 11000011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 11 0x0b '^K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x1a, /* 00011010 */
+	0x32, /* 00110010 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 12 0x0c '^L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 13 0x0d '^M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x33, /* 00110011 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x70, /* 01110000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 14 0x0e '^N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x67, /* 01100111 */
+	0xe7, /* 11100111 */
+	0xe6, /* 11100110 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 15 0x0f '^O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xdb, /* 11011011 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0x3c, /* 00111100 */
+	0xdb, /* 11011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 16 0x10 '^P' */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0xf0, /* 11110000 */
+	0xf8, /* 11111000 */
+	0xfe, /* 11111110 */
+	0xf8, /* 11111000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 17 0x11 '^Q' */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0e, /* 00001110 */
+	0x1e, /* 00011110 */
+	0x3e, /* 00111110 */
+	0xfe, /* 11111110 */
+	0x3e, /* 00111110 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 18 0x12 '^R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 19 0x13 '^S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 20 0x14 '^T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7b, /* 01111011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 21 0x15 '^U' */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 23 0x17 '^W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 24 0x18 '^X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 25 0x19 '^Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xfe, /* 11111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x28, /* 00101000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x28, /* 00101000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 31 0x1f '^_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 32 0x20 ' ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 33 0x21 '!' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 34 0x22 '"' */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 35 0x23 '#' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 36 0x24 '$' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x86, /* 10000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 37 0x25 '%' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 38 0x26 '&' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 39 0x27 ''' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 40 0x28 '(' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 41 0x29 ')' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 42 0x2a '*' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0xff, /* 11111111 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 43 0x2b '+' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 44 0x2c ',' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 45 0x2d '-' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 46 0x2e '.' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 47 0x2f '/' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 48 0x30 '0' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 49 0x31 '1' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x38, /* 00111000 */
+	0x78, /* 01111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 50 0x32 '2' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 51 0x33 '3' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x3c, /* 00111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 52 0x34 '4' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x1c, /* 00011100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 53 0x35 '5' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 54 0x36 '6' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 55 0x37 '7' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 56 0x38 '8' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 57 0x39 '9' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 58 0x3a ':' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 59 0x3b ';' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 60 0x3c '<' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 61 0x3d '=' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 62 0x3e '>' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 63 0x3f '?' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 64 0x40 '@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xdc, /* 11011100 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 65 0x41 'A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 66 0x42 'B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 67 0x43 'C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 68 0x44 'D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 69 0x45 'E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 70 0x46 'F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 71 0x47 'G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xde, /* 11011110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x66, /* 01100110 */
+	0x3a, /* 00111010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 72 0x48 'H' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 73 0x49 'I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 74 0x4a 'J' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 75 0x4b 'K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe6, /* 11100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 76 0x4c 'L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 77 0x4d 'M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xee, /* 11101110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 78 0x4e 'N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 79 0x4f 'O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 80 0x50 'P' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 81 0x51 'Q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xde, /* 11011110 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 82 0x52 'R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 83 0x53 'S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 84 0x54 'T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x5a, /* 01011010 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 85 0x55 'U' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 86 0x56 'V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 87 0x57 'W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0xee, /* 11101110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 88 0x58 'X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 89 0x59 'Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 90 0x5a 'Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 91 0x5b '[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 92 0x5c '\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0x70, /* 01110000 */
+	0x38, /* 00111000 */
+	0x1c, /* 00011100 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 93 0x5d ']' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 94 0x5e '^' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 95 0x5f '_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 96 0x60 '`' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 97 0x61 'a' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 98 0x62 'b' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 99 0x63 'c' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 100 0x64 'd' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 101 0x65 'e' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 102 0x66 'f' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x36, /* 00110110 */
+	0x32, /* 00110010 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 103 0x67 'g' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 104 0x68 'h' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x6c, /* 01101100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 105 0x69 'i' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 106 0x6a 'j' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 107 0x6b 'k' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 108 0x6c 'l' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 112 0x70 'p' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 113 0x71 'q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+
+	/* 114 0x72 'r' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 115 0x73 's' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 116 0x74 't' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0xfc, /* 11111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x36, /* 00110110 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 117 0x75 'u' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 118 0x76 'v' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 119 0x77 'w' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 120 0x78 'x' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 121 0x79 'y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+
+	/* 122 0x7a 'z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 123 0x7b '{' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 124 0x7c '|' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 125 0x7d '}' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 126 0x7e '~' */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 127 0x7f '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 128 0x80 '€' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 129 0x81 '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 130 0x82 '‚' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 131 0x83 'ƒ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 132 0x84 '„' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 133 0x85 'Â…' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 134 0x86 '†' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 135 0x87 '‡' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 136 0x88 'ˆ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 137 0x89 '‰' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 138 0x8a 'Š' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 139 0x8b '‹' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 140 0x8c 'Œ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 141 0x8d '' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 142 0x8e 'ÂŽ' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 143 0x8f '' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 144 0x90 '' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 145 0x91 '‘' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x6e, /* 01101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 146 0x92 'Â’' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3e, /* 00111110 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xce, /* 11001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 147 0x93 '“' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 148 0x94 '”' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 149 0x95 '•' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 150 0x96 '–' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 151 0x97 '—' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 152 0x98 '˜' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 153 0x99 '™' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 154 0x9a 'š' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 155 0x9b '›' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 156 0x9c 'œ' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x64, /* 01100100 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xe6, /* 11100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 157 0x9d '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 158 0x9e 'ž' */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xf8, /* 11111000 */
+	0xc4, /* 11000100 */
+	0xcc, /* 11001100 */
+	0xde, /* 11011110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 159 0x9f 'Ÿ' */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 160 0xa0 ' ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 161 0xa1 '¡' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 162 0xa2 '¢' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 163 0xa3 '£' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 164 0xa4 '¤' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 165 0xa5 'Â¥' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 166 0xa6 '¦' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 167 0xa7 '§' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 168 0xa8 '¨' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 169 0xa9 '©' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 170 0xaa 'ª' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 171 0xab '«' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xdc, /* 11011100 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 172 0xac '¬' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x66, /* 01100110 */
+	0xce, /* 11001110 */
+	0x9a, /* 10011010 */
+	0x3f, /* 00111111 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 173 0xad '­' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 174 0xae '®' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 175 0xaf '¯' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 176 0xb0 '°' */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+
+	/* 177 0xb1 '±' */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+
+	/* 178 0xb2 '²' */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+
+	/* 179 0xb3 '³' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 180 0xb4 '´' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 181 0xb5 'µ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 182 0xb6 '¶' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 183 0xb7 '·' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 184 0xb8 '¸' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 185 0xb9 '¹' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 186 0xba 'º' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 187 0xbb '»' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 188 0xbc '¼' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 189 0xbd '½' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 190 0xbe '¾' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 191 0xbf '¿' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 192 0xc0 'À' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 193 0xc1 'Á' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 194 0xc2 'Â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 195 0xc3 'Ã' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 196 0xc4 'Ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 197 0xc5 'Ã…' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 198 0xc6 'Æ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 199 0xc7 'Ç' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 200 0xc8 'È' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 201 0xc9 'É' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 202 0xca 'Ê' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 203 0xcb 'Ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 204 0xcc 'Ì' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 205 0xcd 'Í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 206 0xce 'ÃŽ' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 207 0xcf 'Ï' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 208 0xd0 'Ð' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 209 0xd1 'Ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 210 0xd2 'Ã’' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 211 0xd3 'Ó' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 212 0xd4 'Ô' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 213 0xd5 'Õ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 214 0xd6 'Ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 215 0xd7 '×' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 216 0xd8 'Ø' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 217 0xd9 'Ù' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 218 0xda 'Ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 219 0xdb 'Û' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 220 0xdc 'Ü' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 221 0xdd 'Ý' */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+
+	/* 222 0xde 'Þ' */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+
+	/* 223 0xdf 'ß' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 224 0xe0 'à' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 225 0xe1 'á' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xd8, /* 11011000 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 226 0xe2 'â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 227 0xe3 'ã' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 228 0xe4 'ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 229 0xe5 'Ã¥' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 230 0xe6 'æ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+
+	/* 231 0xe7 'ç' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 232 0xe8 'è' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 233 0xe9 'é' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 234 0xea 'ê' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xee, /* 11101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 235 0xeb 'ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x3e, /* 00111110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 236 0xec 'ì' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 237 0xed 'í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x03, /* 00000011 */
+	0x06, /* 00000110 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xf3, /* 11110011 */
+	0x7e, /* 01111110 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 238 0xee 'î' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 239 0xef 'ï' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 240 0xf0 'ð' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 241 0xf1 'ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 242 0xf2 'ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 243 0xf3 'ó' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 244 0xf4 'ô' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 245 0xf5 'õ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 246 0xf6 'ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 247 0xf7 '÷' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 248 0xf8 'ø' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 249 0xf9 'ù' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 250 0xfa 'ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 251 0xfb 'û' */
+	0x00, /* 00000000 */
+	0x0f, /* 00001111 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xec, /* 11101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3c, /* 00111100 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 252 0xfc 'ü' */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 253 0xfd 'ý' */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x32, /* 00110010 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 254 0xfe 'þ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 255 0xff 'ÿ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+};
diff --git a/qemu-0.15.x/vl.c b/qemu-0.15.x/vl.c
new file mode 100644
index 0000000..63260e4
--- /dev/null
+++ b/qemu-0.15.x/vl.c
@@ -0,0 +1,3341 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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 <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <libgen.h>
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+
+#ifdef CONFIG_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <libutil.h>
+#include <sys/sysctl.h>
+#else
+#include <util.h>
+#endif
+#else
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#if defined(__OpenBSD__)
+#include <util.h>
+#endif
+
+#if defined(CONFIG_VDE)
+#include <libvdeplug.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef CONFIG_SDL
+#if defined(__APPLE__) || defined(main)
+#include <SDL.h>
+int qemu_main(int argc, char **argv, char **envp);
+int main(int argc, char **argv)
+{
+    return qemu_main(argc, argv, NULL);
+}
+#undef main
+#define main qemu_main
+#endif
+#endif /* CONFIG_SDL */
+
+#ifdef CONFIG_COCOA
+#undef main
+#define main qemu_main
+#endif /* CONFIG_COCOA */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/isa.h"
+#include "hw/baum.h"
+#include "hw/bt.h"
+#include "hw/watchdog.h"
+#include "hw/smbios.h"
+#include "hw/xen.h"
+#include "hw/qdev.h"
+#include "hw/loader.h"
+#include "bt-host.h"
+#include "net.h"
+#include "net/slirp.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "cache-utils.h"
+#include "block.h"
+#include "blockdev.h"
+#include "block-migration.h"
+#include "dma.h"
+#include "audio/audio.h"
+#include "migration.h"
+#include "kvm.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "qemu-objects.h"
+#include "qemu-options.h"
+#ifdef CONFIG_VIRTFS
+#include "fsdev/qemu-fsdev.h"
+#endif
+
+#include "disas.h"
+
+#include "qemu_socket.h"
+
+#include "slirp/libslirp.h"
+
+#include "trace.h"
+#include "simpletrace.h"
+#include "qemu-queue.h"
+#include "cpus.h"
+#include "arch_init.h"
+
+#include "ui/qemu-spice.h"
+
+//#define DEBUG_NET
+//#define DEBUG_SLIRP
+
+#define DEFAULT_RAM_SIZE 128
+
+#define MAX_VIRTIO_CONSOLES 1
+
+static const char *data_dir;
+const char *bios_name = NULL;
+enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
+DisplayType display_type = DT_DEFAULT;
+int display_remote = 0;
+const char* keyboard_layout = NULL;
+ram_addr_t ram_size;
+const char *mem_path = NULL;
+#ifdef MAP_POPULATE
+int mem_prealloc = 0; /* force preallocation of physical target memory */
+#endif
+int nb_nics;
+NICInfo nd_table[MAX_NICS];
+int vm_running;
+int autostart;
+int incoming_expected; /* Started with -incoming and waiting for incoming */
+static int rtc_utc = 1;
+static int rtc_date_offset = -1; /* -1 means no change */
+QEMUClock *rtc_clock;
+int vga_interface_type = VGA_NONE;
+static int full_screen = 0;
+#ifdef CONFIG_SDL
+static int no_frame = 0;
+#endif
+int no_quit = 0;
+CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+int win2k_install_hack = 0;
+int rtc_td_hack = 0;
+int usb_enabled = 0;
+int singlestep = 0;
+int smp_cpus = 1;
+int max_cpus = 0;
+int smp_cores = 1;
+int smp_threads = 1;
+#ifdef CONFIG_VNC
+const char *vnc_display;
+#endif
+int acpi_enabled = 1;
+int no_hpet = 0;
+int fd_bootchk = 1;
+int no_reboot = 0;
+int no_shutdown = 0;
+int cursor_hide = 1;
+int graphic_rotate = 0;
+uint8_t irq0override = 1;
+const char *watchdog;
+QEMUOptionRom option_rom[MAX_OPTION_ROMS];
+int nb_option_roms;
+int semihosting_enabled = 0;
+int old_param = 0;
+const char *qemu_name;
+int alt_grab = 0;
+int ctrl_grab = 0;
+unsigned int nb_prom_envs = 0;
+const char *prom_envs[MAX_PROM_ENVS];
+int boot_menu;
+
+typedef struct FWBootEntry FWBootEntry;
+
+struct FWBootEntry {
+    QTAILQ_ENTRY(FWBootEntry) link;
+    int32_t bootindex;
+    DeviceState *dev;
+    char *suffix;
+};
+
+QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order);
+
+int nb_numa_nodes;
+uint64_t node_mem[MAX_NODES];
+uint64_t node_cpumask[MAX_NODES];
+
+static QEMUTimer *nographic_timer;
+
+uint8_t qemu_uuid[16];
+
+static QEMUBootSetHandler *boot_set_handler;
+static void *boot_set_opaque;
+
+static NotifierList exit_notifiers =
+    NOTIFIER_LIST_INITIALIZER(exit_notifiers);
+
+static NotifierList machine_init_done_notifiers =
+    NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
+
+static int tcg_allowed = 1;
+int kvm_allowed = 0;
+int xen_allowed = 0;
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static int default_serial = 1;
+static int default_parallel = 1;
+static int default_virtcon = 1;
+static int default_monitor = 1;
+static int default_vga = 1;
+static int default_floppy = 1;
+static int default_cdrom = 1;
+static int default_sdcard = 1;
+
+static struct {
+    const char *driver;
+    int *flag;
+} default_list[] = {
+    { .driver = "isa-serial",           .flag = &default_serial    },
+    { .driver = "isa-parallel",         .flag = &default_parallel  },
+    { .driver = "isa-fdc",              .flag = &default_floppy    },
+    { .driver = "ide-cd",               .flag = &default_cdrom     },
+    { .driver = "ide-hd",               .flag = &default_cdrom     },
+    { .driver = "ide-drive",            .flag = &default_cdrom     },
+    { .driver = "scsi-cd",              .flag = &default_cdrom     },
+    { .driver = "virtio-serial-pci",    .flag = &default_virtcon   },
+    { .driver = "virtio-serial-s390",   .flag = &default_virtcon   },
+    { .driver = "virtio-serial",        .flag = &default_virtcon   },
+    { .driver = "VGA",                  .flag = &default_vga       },
+    { .driver = "cirrus-vga",           .flag = &default_vga       },
+    { .driver = "vmware-svga",          .flag = &default_vga       },
+    { .driver = "isa-vga",              .flag = &default_vga       },
+    { .driver = "qxl-vga",              .flag = &default_vga       },
+};
+
+static int default_driver_check(QemuOpts *opts, void *opaque)
+{
+    const char *driver = qemu_opt_get(opts, "driver");
+    int i;
+
+    if (!driver)
+        return 0;
+    for (i = 0; i < ARRAY_SIZE(default_list); i++) {
+        if (strcmp(default_list[i].driver, driver) != 0)
+            continue;
+        *(default_list[i].flag) = 0;
+    }
+    return 0;
+}
+
+/***********************************************************/
+/* real time host monotonic timer */
+
+/***********************************************************/
+/* host time/date access */
+void qemu_get_timedate(struct tm *tm, int offset)
+{
+    time_t ti;
+    struct tm *ret;
+
+    time(&ti);
+    ti += offset;
+    if (rtc_date_offset == -1) {
+        if (rtc_utc)
+            ret = gmtime(&ti);
+        else
+            ret = localtime(&ti);
+    } else {
+        ti -= rtc_date_offset;
+        ret = gmtime(&ti);
+    }
+
+    memcpy(tm, ret, sizeof(struct tm));
+}
+
+int qemu_timedate_diff(struct tm *tm)
+{
+    time_t seconds;
+
+    if (rtc_date_offset == -1)
+        if (rtc_utc)
+            seconds = mktimegm(tm);
+        else
+            seconds = mktime(tm);
+    else
+        seconds = mktimegm(tm) + rtc_date_offset;
+
+    return seconds - time(NULL);
+}
+
+void rtc_change_mon_event(struct tm *tm)
+{
+    QObject *data;
+
+    data = qobject_from_jsonf("{ 'offset': %d }", qemu_timedate_diff(tm));
+    monitor_protocol_event(QEVENT_RTC_CHANGE, data);
+    qobject_decref(data);
+}
+
+static void configure_rtc_date_offset(const char *startdate, int legacy)
+{
+    time_t rtc_start_date;
+    struct tm tm;
+
+    if (!strcmp(startdate, "now") && legacy) {
+        rtc_date_offset = -1;
+    } else {
+        if (sscanf(startdate, "%d-%d-%dT%d:%d:%d",
+                   &tm.tm_year,
+                   &tm.tm_mon,
+                   &tm.tm_mday,
+                   &tm.tm_hour,
+                   &tm.tm_min,
+                   &tm.tm_sec) == 6) {
+            /* OK */
+        } else if (sscanf(startdate, "%d-%d-%d",
+                          &tm.tm_year,
+                          &tm.tm_mon,
+                          &tm.tm_mday) == 3) {
+            tm.tm_hour = 0;
+            tm.tm_min = 0;
+            tm.tm_sec = 0;
+        } else {
+            goto date_fail;
+        }
+        tm.tm_year -= 1900;
+        tm.tm_mon--;
+        rtc_start_date = mktimegm(&tm);
+        if (rtc_start_date == -1) {
+        date_fail:
+            fprintf(stderr, "Invalid date format. Valid formats are:\n"
+                            "'2006-06-17T16:01:21' or '2006-06-17'\n");
+            exit(1);
+        }
+        rtc_date_offset = time(NULL) - rtc_start_date;
+    }
+}
+
+static void configure_rtc(QemuOpts *opts)
+{
+    const char *value;
+
+    value = qemu_opt_get(opts, "base");
+    if (value) {
+        if (!strcmp(value, "utc")) {
+            rtc_utc = 1;
+        } else if (!strcmp(value, "localtime")) {
+            rtc_utc = 0;
+        } else {
+            configure_rtc_date_offset(value, 0);
+        }
+    }
+    value = qemu_opt_get(opts, "clock");
+    if (value) {
+        if (!strcmp(value, "host")) {
+            rtc_clock = host_clock;
+        } else if (!strcmp(value, "vm")) {
+            rtc_clock = vm_clock;
+        } else {
+            fprintf(stderr, "qemu: invalid option value '%s'\n", value);
+            exit(1);
+        }
+    }
+    value = qemu_opt_get(opts, "driftfix");
+    if (value) {
+        if (!strcmp(value, "slew")) {
+            rtc_td_hack = 1;
+        } else if (!strcmp(value, "none")) {
+            rtc_td_hack = 0;
+        } else {
+            fprintf(stderr, "qemu: invalid option value '%s'\n", value);
+            exit(1);
+        }
+    }
+}
+
+/***********************************************************/
+/* Bluetooth support */
+static int nb_hcis;
+static int cur_hci;
+static struct HCIInfo *hci_table[MAX_NICS];
+
+static struct bt_vlan_s {
+    struct bt_scatternet_s net;
+    int id;
+    struct bt_vlan_s *next;
+} *first_bt_vlan;
+
+/* find or alloc a new bluetooth "VLAN" */
+static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
+{
+    struct bt_vlan_s **pvlan, *vlan;
+    for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return &vlan->net;
+    }
+    vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
+    vlan->id = id;
+    pvlan = &first_bt_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return &vlan->net;
+}
+
+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+}
+
+static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
+{
+    return -ENOTSUP;
+}
+
+static struct HCIInfo null_hci = {
+    .cmd_send = null_hci_send,
+    .sco_send = null_hci_send,
+    .acl_send = null_hci_send,
+    .bdaddr_set = null_hci_addr_set,
+};
+
+struct HCIInfo *qemu_next_hci(void)
+{
+    if (cur_hci == nb_hcis)
+        return &null_hci;
+
+    return hci_table[cur_hci++];
+}
+
+static struct HCIInfo *hci_init(const char *str)
+{
+    char *endp;
+    struct bt_scatternet_s *vlan = 0;
+
+    if (!strcmp(str, "null"))
+        /* null */
+        return &null_hci;
+    else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
+        /* host[:hciN] */
+        return bt_host_hci(str[4] ? str + 5 : "hci0");
+    else if (!strncmp(str, "hci", 3)) {
+        /* hci[,vlan=n] */
+        if (str[3]) {
+            if (!strncmp(str + 3, ",vlan=", 6)) {
+                vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
+                if (*endp)
+                    vlan = 0;
+            }
+        } else
+            vlan = qemu_find_bt_vlan(0);
+        if (vlan)
+           return bt_new_hci(vlan);
+    }
+
+    fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
+
+    return 0;
+}
+
+static int bt_hci_parse(const char *str)
+{
+    struct HCIInfo *hci;
+    bdaddr_t bdaddr;
+
+    if (nb_hcis >= MAX_NICS) {
+        fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS);
+        return -1;
+    }
+
+    hci = hci_init(str);
+    if (!hci)
+        return -1;
+
+    bdaddr.b[0] = 0x52;
+    bdaddr.b[1] = 0x54;
+    bdaddr.b[2] = 0x00;
+    bdaddr.b[3] = 0x12;
+    bdaddr.b[4] = 0x34;
+    bdaddr.b[5] = 0x56 + nb_hcis;
+    hci->bdaddr_set(hci, bdaddr.b);
+
+    hci_table[nb_hcis++] = hci;
+
+    return 0;
+}
+
+static void bt_vhci_add(int vlan_id)
+{
+    struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a VHCI to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    bt_vhci_init(bt_new_hci(vlan));
+}
+
+static struct bt_device_s *bt_device_add(const char *opt)
+{
+    struct bt_scatternet_s *vlan;
+    int vlan_id = 0;
+    char *endp = strstr(opt, ",vlan=");
+    int len = (endp ? endp - opt : strlen(opt)) + 1;
+    char devname[10];
+
+    pstrcpy(devname, MIN(sizeof(devname), len), opt);
+
+    if (endp) {
+        vlan_id = strtol(endp + 6, &endp, 0);
+        if (*endp) {
+            fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n");
+            return 0;
+        }
+    }
+
+    vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a slave device to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    if (!strcmp(devname, "keyboard"))
+        return bt_keyboard_init(vlan);
+
+    fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname);
+    return 0;
+}
+
+static int bt_parse(const char *opt)
+{
+    const char *endp, *p;
+    int vlan;
+
+    if (strstart(opt, "hci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp)
+                if (!strstart(endp, ",vlan=", 0))
+                    opt = endp + 1;
+
+            return bt_hci_parse(opt);
+       }
+    } else if (strstart(opt, "vhci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp) {
+                if (strstart(endp, ",vlan=", &p)) {
+                    vlan = strtol(p, (char **) &endp, 0);
+                    if (*endp) {
+                        fprintf(stderr, "qemu: bad scatternet '%s'\n", p);
+                        return 1;
+                    }
+                } else {
+                    fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1);
+                    return 1;
+                }
+            } else
+                vlan = 0;
+
+            bt_vhci_add(vlan);
+            return 0;
+        }
+    } else if (strstart(opt, "device:", &endp))
+        return !bt_device_add(endp);
+
+    fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt);
+    return 1;
+}
+
+/***********************************************************/
+/* QEMU Block devices */
+
+#define HD_OPTS "media=disk"
+#define CDROM_OPTS "media=cdrom"
+#define FD_OPTS ""
+#define PFLASH_OPTS ""
+#define MTD_OPTS ""
+#define SD_OPTS ""
+
+static int drive_init_func(QemuOpts *opts, void *opaque)
+{
+    int *use_scsi = opaque;
+
+    return drive_init(opts, *use_scsi) == NULL;
+}
+
+static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
+{
+    if (NULL == qemu_opt_get(opts, "snapshot")) {
+        qemu_opt_set(opts, "snapshot", "on");
+    }
+    return 0;
+}
+
+static void default_drive(int enable, int snapshot, int use_scsi,
+                          BlockInterfaceType type, int index,
+                          const char *optstr)
+{
+    QemuOpts *opts;
+
+    if (type == IF_DEFAULT) {
+        type = use_scsi ? IF_SCSI : IF_IDE;
+    }
+
+    if (!enable || drive_get_by_index(type, index)) {
+        return;
+    }
+
+    opts = drive_add(type, index, NULL, optstr);
+    if (snapshot) {
+        drive_enable_snapshot(opts, NULL);
+    }
+    if (!drive_init(opts, use_scsi)) {
+        exit(1);
+    }
+}
+
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
+{
+    boot_set_handler = func;
+    boot_set_opaque = opaque;
+}
+
+int qemu_boot_set(const char *boot_devices)
+{
+    if (!boot_set_handler) {
+        return -EINVAL;
+    }
+    return boot_set_handler(boot_set_opaque, boot_devices);
+}
+
+static void validate_bootdevices(char *devices)
+{
+    /* We just do some generic consistency checks */
+    const char *p;
+    int bitmap = 0;
+
+    for (p = devices; *p != '\0'; p++) {
+        /* Allowed boot devices are:
+         * a-b: floppy disk drives
+         * c-f: IDE disk drives
+         * g-m: machine implementation dependant drives
+         * n-p: network devices
+         * It's up to each machine implementation to check if the given boot
+         * devices match the actual hardware implementation and firmware
+         * features.
+         */
+        if (*p < 'a' || *p > 'p') {
+            fprintf(stderr, "Invalid boot device '%c'\n", *p);
+            exit(1);
+        }
+        if (bitmap & (1 << (*p - 'a'))) {
+            fprintf(stderr, "Boot device '%c' was given twice\n", *p);
+            exit(1);
+        }
+        bitmap |= 1 << (*p - 'a');
+    }
+}
+
+static void restore_boot_devices(void *opaque)
+{
+    char *standard_boot_devices = opaque;
+    static int first = 1;
+
+    /* Restore boot order and remove ourselves after the first boot */
+    if (first) {
+        first = 0;
+        return;
+    }
+
+    qemu_boot_set(standard_boot_devices);
+
+    qemu_unregister_reset(restore_boot_devices, standard_boot_devices);
+    qemu_free(standard_boot_devices);
+}
+
+void add_boot_device_path(int32_t bootindex, DeviceState *dev,
+                          const char *suffix)
+{
+    FWBootEntry *node, *i;
+
+    if (bootindex < 0) {
+        return;
+    }
+
+    assert(dev != NULL || suffix != NULL);
+
+    node = qemu_mallocz(sizeof(FWBootEntry));
+    node->bootindex = bootindex;
+    node->suffix = suffix ? qemu_strdup(suffix) : NULL;
+    node->dev = dev;
+
+    QTAILQ_FOREACH(i, &fw_boot_order, link) {
+        if (i->bootindex == bootindex) {
+            fprintf(stderr, "Two devices with same boot index %d\n", bootindex);
+            exit(1);
+        } else if (i->bootindex < bootindex) {
+            continue;
+        }
+        QTAILQ_INSERT_BEFORE(i, node, link);
+        return;
+    }
+    QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
+}
+
+/*
+ * This function returns null terminated string that consist of new line
+ * separated device paths.
+ *
+ * memory pointed by "size" is assigned total length of the array in bytes
+ *
+ */
+char *get_boot_devices_list(uint32_t *size)
+{
+    FWBootEntry *i;
+    uint32_t total = 0;
+    char *list = NULL;
+
+    QTAILQ_FOREACH(i, &fw_boot_order, link) {
+        char *devpath = NULL, *bootpath;
+        int len;
+
+        if (i->dev) {
+            devpath = qdev_get_fw_dev_path(i->dev);
+            assert(devpath);
+        }
+
+        if (i->suffix && devpath) {
+            size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
+
+            bootpath = qemu_malloc(bootpathlen);
+            snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
+            qemu_free(devpath);
+        } else if (devpath) {
+            bootpath = devpath;
+        } else {
+            bootpath = qemu_strdup(i->suffix);
+            assert(bootpath);
+        }
+
+        if (total) {
+            list[total-1] = '\n';
+        }
+        len = strlen(bootpath) + 1;
+        list = qemu_realloc(list, total + len);
+        memcpy(&list[total], bootpath, len);
+        total += len;
+        qemu_free(bootpath);
+    }
+
+    *size = total;
+
+    return list;
+}
+
+static void numa_add(const char *optarg)
+{
+    char option[128];
+    char *endptr;
+    unsigned long long value, endvalue;
+    int nodenr;
+
+    optarg = get_opt_name(option, 128, optarg, ',') + 1;
+    if (!strcmp(option, "node")) {
+        if (get_param_value(option, 128, "nodeid", optarg) == 0) {
+            nodenr = nb_numa_nodes;
+        } else {
+            nodenr = strtoull(option, NULL, 10);
+        }
+
+        if (get_param_value(option, 128, "mem", optarg) == 0) {
+            node_mem[nodenr] = 0;
+        } else {
+            int64_t sval;
+            sval = strtosz(option, NULL);
+            if (sval < 0) {
+                fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
+                exit(1);
+            }
+            node_mem[nodenr] = sval;
+        }
+        if (get_param_value(option, 128, "cpus", optarg) == 0) {
+            node_cpumask[nodenr] = 0;
+        } else {
+            value = strtoull(option, &endptr, 10);
+            if (value >= 64) {
+                value = 63;
+                fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n");
+            } else {
+                if (*endptr == '-') {
+                    endvalue = strtoull(endptr+1, &endptr, 10);
+                    if (endvalue >= 63) {
+                        endvalue = 62;
+                        fprintf(stderr,
+                            "only 63 CPUs in NUMA mode supported.\n");
+                    }
+                    value = (2ULL << endvalue) - (1ULL << value);
+                } else {
+                    value = 1ULL << value;
+                }
+            }
+            node_cpumask[nodenr] = value;
+        }
+        nb_numa_nodes++;
+    }
+    return;
+}
+
+static void smp_parse(const char *optarg)
+{
+    int smp, sockets = 0, threads = 0, cores = 0;
+    char *endptr;
+    char option[128];
+
+    smp = strtoul(optarg, &endptr, 10);
+    if (endptr != optarg) {
+        if (*endptr == ',') {
+            endptr++;
+        }
+    }
+    if (get_param_value(option, 128, "sockets", endptr) != 0)
+        sockets = strtoull(option, NULL, 10);
+    if (get_param_value(option, 128, "cores", endptr) != 0)
+        cores = strtoull(option, NULL, 10);
+    if (get_param_value(option, 128, "threads", endptr) != 0)
+        threads = strtoull(option, NULL, 10);
+    if (get_param_value(option, 128, "maxcpus", endptr) != 0)
+        max_cpus = strtoull(option, NULL, 10);
+
+    /* compute missing values, prefer sockets over cores over threads */
+    if (smp == 0 || sockets == 0) {
+        sockets = sockets > 0 ? sockets : 1;
+        cores = cores > 0 ? cores : 1;
+        threads = threads > 0 ? threads : 1;
+        if (smp == 0) {
+            smp = cores * threads * sockets;
+        }
+    } else {
+        if (cores == 0) {
+            threads = threads > 0 ? threads : 1;
+            cores = smp / (sockets * threads);
+        } else {
+            threads = smp / (cores * sockets);
+        }
+    }
+    smp_cpus = smp;
+    smp_cores = cores > 0 ? cores : 1;
+    smp_threads = threads > 0 ? threads : 1;
+    if (max_cpus == 0)
+        max_cpus = smp_cpus;
+}
+
+/***********************************************************/
+/* USB devices */
+
+static int usb_device_add(const char *devname)
+{
+    const char *p;
+    USBDevice *dev = NULL;
+
+    if (!usb_enabled)
+        return -1;
+
+    /* drivers with .usbdevice_name entry in USBDeviceInfo */
+    dev = usbdevice_create(devname);
+    if (dev)
+        goto done;
+
+    /* the other ones */
+#ifndef CONFIG_LINUX
+    /* only the linux version is qdev-ified, usb-bsd still needs this */
+    if (strstart(devname, "host:", &p)) {
+        dev = usb_host_device_open(p);
+    } else
+#endif
+    if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+        dev = usb_bt_init(devname[2] ? hci_init(p) :
+                        bt_new_hci(qemu_find_bt_vlan(0)));
+    } else {
+        return -1;
+    }
+    if (!dev)
+        return -1;
+
+done:
+    return 0;
+}
+
+static int usb_device_del(const char *devname)
+{
+    int bus_num, addr;
+    const char *p;
+
+    if (strstart(devname, "host:", &p))
+        return usb_host_device_close(p);
+
+    if (!usb_enabled)
+        return -1;
+
+    p = strchr(devname, '.');
+    if (!p)
+        return -1;
+    bus_num = strtoul(devname, NULL, 0);
+    addr = strtoul(p + 1, NULL, 0);
+
+    return usb_device_delete_addr(bus_num, addr);
+}
+
+static int usb_parse(const char *cmdline)
+{
+    int r;
+    r = usb_device_add(cmdline);
+    if (r < 0) {
+        fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline);
+    }
+    return r;
+}
+
+void do_usb_add(Monitor *mon, const QDict *qdict)
+{
+    const char *devname = qdict_get_str(qdict, "devname");
+    if (usb_device_add(devname) < 0) {
+        error_report("could not add USB device '%s'", devname);
+    }
+}
+
+void do_usb_del(Monitor *mon, const QDict *qdict)
+{
+    const char *devname = qdict_get_str(qdict, "devname");
+    if (usb_device_del(devname) < 0) {
+        error_report("could not delete USB device '%s'", devname);
+    }
+}
+
+/***********************************************************/
+/* PCMCIA/Cardbus */
+
+static struct pcmcia_socket_entry_s {
+    PCMCIASocket *socket;
+    struct pcmcia_socket_entry_s *next;
+} *pcmcia_sockets = 0;
+
+void pcmcia_socket_register(PCMCIASocket *socket)
+{
+    struct pcmcia_socket_entry_s *entry;
+
+    entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
+    entry->socket = socket;
+    entry->next = pcmcia_sockets;
+    pcmcia_sockets = entry;
+}
+
+void pcmcia_socket_unregister(PCMCIASocket *socket)
+{
+    struct pcmcia_socket_entry_s *entry, **ptr;
+
+    ptr = &pcmcia_sockets;
+    for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
+        if (entry->socket == socket) {
+            *ptr = entry->next;
+            qemu_free(entry);
+        }
+}
+
+void pcmcia_info(Monitor *mon)
+{
+    struct pcmcia_socket_entry_s *iter;
+
+    if (!pcmcia_sockets)
+        monitor_printf(mon, "No PCMCIA sockets\n");
+
+    for (iter = pcmcia_sockets; iter; iter = iter->next)
+        monitor_printf(mon, "%s: %s\n", iter->socket->slot_string,
+                       iter->socket->attached ? iter->socket->card_string :
+                       "Empty");
+}
+
+/***********************************************************/
+/* machine registration */
+
+static QEMUMachine *first_machine = NULL;
+QEMUMachine *current_machine = NULL;
+
+int qemu_register_machine(QEMUMachine *m)
+{
+    QEMUMachine **pm;
+    pm = &first_machine;
+    while (*pm != NULL)
+        pm = &(*pm)->next;
+    m->next = NULL;
+    *pm = m;
+    return 0;
+}
+
+static QEMUMachine *find_machine(const char *name)
+{
+    QEMUMachine *m;
+
+    for(m = first_machine; m != NULL; m = m->next) {
+        if (!strcmp(m->name, name))
+            return m;
+        if (m->alias && !strcmp(m->alias, name))
+            return m;
+    }
+    return NULL;
+}
+
+static QEMUMachine *find_default_machine(void)
+{
+    QEMUMachine *m;
+
+    for(m = first_machine; m != NULL; m = m->next) {
+        if (m->is_default) {
+            return m;
+        }
+    }
+    return NULL;
+}
+
+/***********************************************************/
+/* main execution loop */
+
+static void gui_update(void *opaque)
+{
+    uint64_t interval = GUI_REFRESH_INTERVAL;
+    DisplayState *ds = opaque;
+    DisplayChangeListener *dcl = ds->listeners;
+
+    qemu_flush_coalesced_mmio_buffer();
+    dpy_refresh(ds);
+
+    while (dcl != NULL) {
+        if (dcl->gui_timer_interval &&
+            dcl->gui_timer_interval < interval)
+            interval = dcl->gui_timer_interval;
+        dcl = dcl->next;
+    }
+    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
+}
+
+static void nographic_update(void *opaque)
+{
+    uint64_t interval = GUI_REFRESH_INTERVAL;
+
+    qemu_flush_coalesced_mmio_buffer();
+    qemu_mod_timer(nographic_timer, interval + qemu_get_clock_ms(rt_clock));
+}
+
+struct vm_change_state_entry {
+    VMChangeStateHandler *cb;
+    void *opaque;
+    QLIST_ENTRY (vm_change_state_entry) entries;
+};
+
+static QLIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head;
+
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque)
+{
+    VMChangeStateEntry *e;
+
+    e = qemu_mallocz(sizeof (*e));
+
+    e->cb = cb;
+    e->opaque = opaque;
+    QLIST_INSERT_HEAD(&vm_change_state_head, e, entries);
+    return e;
+}
+
+void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
+{
+    QLIST_REMOVE (e, entries);
+    qemu_free (e);
+}
+
+void vm_state_notify(int running, int reason)
+{
+    VMChangeStateEntry *e;
+
+    trace_vm_state_notify(running, reason);
+
+    for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
+        e->cb(e->opaque, running, reason);
+    }
+}
+
+void vm_start(void)
+{
+    if (!vm_running) {
+        cpu_enable_ticks();
+        vm_running = 1;
+        vm_state_notify(1, 0);
+        resume_all_vcpus();
+        monitor_protocol_event(QEVENT_RESUME, NULL);
+    }
+}
+
+/* reset/shutdown handler */
+
+typedef struct QEMUResetEntry {
+    QTAILQ_ENTRY(QEMUResetEntry) entry;
+    QEMUResetHandler *func;
+    void *opaque;
+} QEMUResetEntry;
+
+static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
+    QTAILQ_HEAD_INITIALIZER(reset_handlers);
+static int reset_requested;
+static int shutdown_requested, shutdown_signal = -1;
+static pid_t shutdown_pid;
+static int powerdown_requested;
+static int debug_requested;
+static int vmstop_requested;
+
+int qemu_shutdown_requested_get(void)
+{
+    return shutdown_requested;
+}
+
+int qemu_reset_requested_get(void)
+{
+    return reset_requested;
+}
+
+int qemu_shutdown_requested(void)
+{
+    int r = shutdown_requested;
+    shutdown_requested = 0;
+    return r;
+}
+
+void qemu_kill_report(void)
+{
+    if (shutdown_signal != -1) {
+        fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal);
+        if (shutdown_pid == 0) {
+            /* This happens for eg ^C at the terminal, so it's worth
+             * avoiding printing an odd message in that case.
+             */
+            fputc('\n', stderr);
+        } else {
+            fprintf(stderr, " from pid " FMT_pid "\n", shutdown_pid);
+        }
+        shutdown_signal = -1;
+    }
+}
+
+int qemu_reset_requested(void)
+{
+    int r = reset_requested;
+    reset_requested = 0;
+    return r;
+}
+
+int qemu_powerdown_requested(void)
+{
+    int r = powerdown_requested;
+    powerdown_requested = 0;
+    return r;
+}
+
+static int qemu_debug_requested(void)
+{
+    int r = debug_requested;
+    debug_requested = 0;
+    return r;
+}
+
+static int qemu_vmstop_requested(void)
+{
+    int r = vmstop_requested;
+    vmstop_requested = 0;
+    return r;
+}
+
+void qemu_register_reset(QEMUResetHandler *func, void *opaque)
+{
+    QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry));
+
+    re->func = func;
+    re->opaque = opaque;
+    QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
+}
+
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
+{
+    QEMUResetEntry *re;
+
+    QTAILQ_FOREACH(re, &reset_handlers, entry) {
+        if (re->func == func && re->opaque == opaque) {
+            QTAILQ_REMOVE(&reset_handlers, re, entry);
+            qemu_free(re);
+            return;
+        }
+    }
+}
+
+void qemu_system_reset(bool report)
+{
+    QEMUResetEntry *re, *nre;
+
+    /* reset all devices */
+    QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
+        re->func(re->opaque);
+    }
+    if (report) {
+        monitor_protocol_event(QEVENT_RESET, NULL);
+    }
+    cpu_synchronize_all_post_reset();
+}
+
+void qemu_system_reset_request(void)
+{
+    if (no_reboot) {
+        shutdown_requested = 1;
+    } else {
+        reset_requested = 1;
+    }
+    cpu_stop_current();
+    qemu_notify_event();
+}
+
+void qemu_system_killed(int signal, pid_t pid)
+{
+    shutdown_signal = signal;
+    shutdown_pid = pid;
+    no_shutdown = 0;
+    qemu_system_shutdown_request();
+}
+
+void qemu_system_shutdown_request(void)
+{
+    shutdown_requested = 1;
+    qemu_notify_event();
+}
+
+void qemu_system_powerdown_request(void)
+{
+    powerdown_requested = 1;
+    qemu_notify_event();
+}
+
+void qemu_system_debug_request(void)
+{
+    debug_requested = 1;
+    qemu_notify_event();
+}
+
+void qemu_system_vmstop_request(int reason)
+{
+    vmstop_requested = reason;
+    qemu_notify_event();
+}
+
+void main_loop_wait(int nonblocking)
+{
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+    int timeout;
+
+    if (nonblocking)
+        timeout = 0;
+    else {
+        timeout = qemu_calculate_timeout();
+        qemu_bh_update_timeout(&timeout);
+    }
+
+    os_host_main_loop_wait(&timeout);
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    /* poll any events */
+    /* XXX: separate device handlers from system ones */
+    nfds = -1;
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+
+    qemu_mutex_unlock_iothread();
+    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+    qemu_mutex_lock_iothread();
+
+    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+
+    qemu_run_all_timers();
+
+    /* Check bottom-halves last in case any of the earlier events triggered
+       them.  */
+    qemu_bh_poll();
+
+}
+
+#ifndef CONFIG_IOTHREAD
+static int vm_request_pending(void)
+{
+    return powerdown_requested ||
+           reset_requested ||
+           shutdown_requested ||
+           debug_requested ||
+           vmstop_requested;
+}
+#endif
+
+qemu_irq qemu_system_powerdown;
+
+static void main_loop(void)
+{
+    bool nonblocking = false;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+    int r;
+
+    qemu_main_loop_start();
+
+    for (;;) {
+#ifndef CONFIG_IOTHREAD
+        nonblocking = cpu_exec_all();
+        if (vm_request_pending()) {
+            nonblocking = true;
+        }
+#endif
+#ifdef CONFIG_PROFILER
+        ti = profile_getclock();
+#endif
+        main_loop_wait(nonblocking);
+#ifdef CONFIG_PROFILER
+        dev_time += profile_getclock() - ti;
+#endif
+
+        if (qemu_debug_requested()) {
+            vm_stop(VMSTOP_DEBUG);
+        }
+        if (qemu_shutdown_requested()) {
+            qemu_kill_report();
+            monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
+            if (no_shutdown) {
+                vm_stop(VMSTOP_SHUTDOWN);
+            } else
+                break;
+        }
+        if (qemu_reset_requested()) {
+            pause_all_vcpus();
+            cpu_synchronize_all_states();
+            qemu_system_reset(VMRESET_REPORT);
+            resume_all_vcpus();
+        }
+        if (qemu_powerdown_requested()) {
+            monitor_protocol_event(QEVENT_POWERDOWN, NULL);
+            qemu_irq_raise(qemu_system_powerdown);
+        }
+        if ((r = qemu_vmstop_requested())) {
+            vm_stop(r);
+        }
+    }
+    bdrv_close_all();
+    pause_all_vcpus();
+}
+
+static void version(void)
+{
+    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+static void help(int exitcode)
+{
+    const char *options_help =
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask)     \
+        opt_help
+#define DEFHEADING(text) stringify(text) "\n"
+#include "qemu-options.def"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+        ;
+    version();
+    printf("usage: %s [options] [disk_image]\n"
+           "\n"
+           "'disk_image' is a raw hard disk image for IDE hard disk 0\n"
+           "\n"
+           "%s\n"
+           "During emulation, the following keys are useful:\n"
+           "ctrl-alt-f      toggle full screen\n"
+           "ctrl-alt-n      switch to virtual console 'n'\n"
+           "ctrl-alt        toggle mouse and keyboard grab\n"
+           "\n"
+           "When using -nographic, press 'ctrl-a h' to get some help.\n",
+           "qemu",
+           options_help);
+    exit(exitcode);
+}
+
+#define HAS_ARG 0x0001
+
+typedef struct QEMUOption {
+    const char *name;
+    int flags;
+    int index;
+    uint32_t arch_mask;
+} QEMUOption;
+
+static const QEMUOption qemu_options[] = {
+    { "h", 0, QEMU_OPTION_h, QEMU_ARCH_ALL },
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask)     \
+    { option, opt_arg, opt_enum, arch_mask },
+#define DEFHEADING(text)
+#include "qemu-options.def"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+    { NULL },
+};
+static void select_vgahw (const char *p)
+{
+    const char *opts;
+
+    default_vga = 0;
+    vga_interface_type = VGA_NONE;
+    if (strstart(p, "std", &opts)) {
+        vga_interface_type = VGA_STD;
+    } else if (strstart(p, "cirrus", &opts)) {
+        vga_interface_type = VGA_CIRRUS;
+    } else if (strstart(p, "vmware", &opts)) {
+        vga_interface_type = VGA_VMWARE;
+    } else if (strstart(p, "xenfb", &opts)) {
+        vga_interface_type = VGA_XENFB;
+    } else if (strstart(p, "qxl", &opts)) {
+        vga_interface_type = VGA_QXL;
+    } else if (!strstart(p, "none", &opts)) {
+    invalid_vga:
+        fprintf(stderr, "Unknown vga type: %s\n", p);
+        exit(1);
+    }
+    while (*opts) {
+        const char *nextopt;
+
+        if (strstart(opts, ",retrace=", &nextopt)) {
+            opts = nextopt;
+            if (strstart(opts, "dumb", &nextopt))
+                vga_retrace_method = VGA_RETRACE_DUMB;
+            else if (strstart(opts, "precise", &nextopt))
+                vga_retrace_method = VGA_RETRACE_PRECISE;
+            else goto invalid_vga;
+        } else goto invalid_vga;
+        opts = nextopt;
+    }
+}
+
+static DisplayType select_display(const char *p)
+{
+    const char *opts;
+    DisplayType display = DT_DEFAULT;
+
+    if (strstart(p, "sdl", &opts)) {
+#ifdef CONFIG_SDL
+        display = DT_SDL;
+        while (*opts) {
+            const char *nextopt;
+
+            if (strstart(opts, ",frame=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    no_frame = 0;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    no_frame = 1;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",alt_grab=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    alt_grab = 1;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    alt_grab = 0;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",ctrl_grab=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    ctrl_grab = 1;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    ctrl_grab = 0;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else if (strstart(opts, ",window_close=", &nextopt)) {
+                opts = nextopt;
+                if (strstart(opts, "on", &nextopt)) {
+                    no_quit = 0;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    no_quit = 1;
+                } else {
+                    goto invalid_sdl_args;
+                }
+            } else {
+            invalid_sdl_args:
+                fprintf(stderr, "Invalid SDL option string: %s\n", p);
+                exit(1);
+            }
+            opts = nextopt;
+        }
+#else
+        fprintf(stderr, "SDL support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "vnc", &opts)) {
+#ifdef CONFIG_VNC
+        display_remote++;
+
+        if (*opts) {
+            const char *nextopt;
+
+            if (strstart(opts, "=", &nextopt)) {
+                vnc_display = nextopt;
+            }
+        }
+        if (!vnc_display) {
+            fprintf(stderr, "VNC requires a display argument vnc=<display>\n");
+            exit(1);
+        }
+#else
+        fprintf(stderr, "VNC support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "curses", &opts)) {
+#ifdef CONFIG_CURSES
+        display = DT_CURSES;
+#else
+        fprintf(stderr, "Curses support is disabled\n");
+        exit(1);
+#endif
+    } else if (strstart(p, "none", &opts)) {
+        display = DT_NONE;
+    } else {
+        fprintf(stderr, "Unknown display type: %s\n", p);
+        exit(1);
+    }
+
+    return display;
+}
+
+static int balloon_parse(const char *arg)
+{
+    QemuOpts *opts;
+
+    if (strcmp(arg, "none") == 0) {
+        return 0;
+    }
+
+    if (!strncmp(arg, "virtio", 6)) {
+        if (arg[6] == ',') {
+            /* have params -> parse them */
+            opts = qemu_opts_parse(qemu_find_opts("device"), arg+7, 0);
+            if (!opts)
+                return  -1;
+        } else {
+            /* create empty opts */
+            opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+        }
+        qemu_opt_set(opts, "driver", "virtio-balloon");
+        return 0;
+    }
+
+    return -1;
+}
+
+char *qemu_find_file(int type, const char *name)
+{
+    int len;
+    const char *subdir;
+    char *buf;
+
+    /* If name contains path separators then try it as a straight path.  */
+    if ((strchr(name, '/') || strchr(name, '\\'))
+        && access(name, R_OK) == 0) {
+        return qemu_strdup(name);
+    }
+    switch (type) {
+    case QEMU_FILE_TYPE_BIOS:
+        subdir = "";
+        break;
+    case QEMU_FILE_TYPE_KEYMAP:
+        subdir = "keymaps/";
+        break;
+    default:
+        abort();
+    }
+    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
+    buf = qemu_mallocz(len);
+    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
+    if (access(buf, R_OK)) {
+        qemu_free(buf);
+        return NULL;
+    }
+    return buf;
+}
+
+static int device_help_func(QemuOpts *opts, void *opaque)
+{
+    return qdev_device_help(opts);
+}
+
+static int device_init_func(QemuOpts *opts, void *opaque)
+{
+    DeviceState *dev;
+
+    dev = qdev_device_add(opts);
+    if (!dev)
+        return -1;
+    return 0;
+}
+
+static int chardev_init_func(QemuOpts *opts, void *opaque)
+{
+    CharDriverState *chr;
+
+    chr = qemu_chr_open_opts(opts, NULL);
+    if (!chr)
+        return -1;
+    return 0;
+}
+
+#ifdef CONFIG_VIRTFS
+static int fsdev_init_func(QemuOpts *opts, void *opaque)
+{
+    int ret;
+    ret = qemu_fsdev_add(opts);
+
+    return ret;
+}
+#endif
+
+static int mon_init_func(QemuOpts *opts, void *opaque)
+{
+    CharDriverState *chr;
+    const char *chardev;
+    const char *mode;
+    int flags;
+
+    mode = qemu_opt_get(opts, "mode");
+    if (mode == NULL) {
+        mode = "readline";
+    }
+    if (strcmp(mode, "readline") == 0) {
+        flags = MONITOR_USE_READLINE;
+    } else if (strcmp(mode, "control") == 0) {
+        flags = MONITOR_USE_CONTROL;
+    } else {
+        fprintf(stderr, "unknown monitor mode \"%s\"\n", mode);
+        exit(1);
+    }
+
+    if (qemu_opt_get_bool(opts, "pretty", 0))
+        flags |= MONITOR_USE_PRETTY;
+
+    if (qemu_opt_get_bool(opts, "default", 0))
+        flags |= MONITOR_IS_DEFAULT;
+
+    chardev = qemu_opt_get(opts, "chardev");
+    chr = qemu_chr_find(chardev);
+    if (chr == NULL) {
+        fprintf(stderr, "chardev \"%s\" not found\n", chardev);
+        exit(1);
+    }
+
+    monitor_init(chr, flags);
+    return 0;
+}
+
+static void monitor_parse(const char *optarg, const char *mode)
+{
+    static int monitor_device_index = 0;
+    QemuOpts *opts;
+    const char *p;
+    char label[32];
+    int def = 0;
+
+    if (strstart(optarg, "chardev:", &p)) {
+        snprintf(label, sizeof(label), "%s", p);
+    } else {
+        snprintf(label, sizeof(label), "compat_monitor%d",
+                 monitor_device_index);
+        if (monitor_device_index == 0) {
+            def = 1;
+        }
+        opts = qemu_chr_parse_compat(label, optarg);
+        if (!opts) {
+            fprintf(stderr, "parse error: %s\n", optarg);
+            exit(1);
+        }
+    }
+
+    opts = qemu_opts_create(qemu_find_opts("mon"), label, 1);
+    if (!opts) {
+        fprintf(stderr, "duplicate chardev: %s\n", label);
+        exit(1);
+    }
+    qemu_opt_set(opts, "mode", mode);
+    qemu_opt_set(opts, "chardev", label);
+    if (def)
+        qemu_opt_set(opts, "default", "on");
+    monitor_device_index++;
+}
+
+struct device_config {
+    enum {
+        DEV_USB,       /* -usbdevice     */
+        DEV_BT,        /* -bt            */
+        DEV_SERIAL,    /* -serial        */
+        DEV_PARALLEL,  /* -parallel      */
+        DEV_VIRTCON,   /* -virtioconsole */
+        DEV_DEBUGCON,  /* -debugcon */
+    } type;
+    const char *cmdline;
+    QTAILQ_ENTRY(device_config) next;
+};
+QTAILQ_HEAD(, device_config) device_configs = QTAILQ_HEAD_INITIALIZER(device_configs);
+
+static void add_device_config(int type, const char *cmdline)
+{
+    struct device_config *conf;
+
+    conf = qemu_mallocz(sizeof(*conf));
+    conf->type = type;
+    conf->cmdline = cmdline;
+    QTAILQ_INSERT_TAIL(&device_configs, conf, next);
+}
+
+static int foreach_device_config(int type, int (*func)(const char *cmdline))
+{
+    struct device_config *conf;
+    int rc;
+
+    QTAILQ_FOREACH(conf, &device_configs, next) {
+        if (conf->type != type)
+            continue;
+        rc = func(conf->cmdline);
+        if (0 != rc)
+            return rc;
+    }
+    return 0;
+}
+
+static int serial_parse(const char *devname)
+{
+    static int index = 0;
+    char label[32];
+
+    if (strcmp(devname, "none") == 0)
+        return 0;
+    if (index == MAX_SERIAL_PORTS) {
+        fprintf(stderr, "qemu: too many serial ports\n");
+        exit(1);
+    }
+    snprintf(label, sizeof(label), "serial%d", index);
+    serial_hds[index] = qemu_chr_open(label, devname, NULL);
+    if (!serial_hds[index]) {
+        fprintf(stderr, "qemu: could not open serial device '%s': %s\n",
+                devname, strerror(errno));
+        return -1;
+    }
+    index++;
+    return 0;
+}
+
+static int parallel_parse(const char *devname)
+{
+    static int index = 0;
+    char label[32];
+
+    if (strcmp(devname, "none") == 0)
+        return 0;
+    if (index == MAX_PARALLEL_PORTS) {
+        fprintf(stderr, "qemu: too many parallel ports\n");
+        exit(1);
+    }
+    snprintf(label, sizeof(label), "parallel%d", index);
+    parallel_hds[index] = qemu_chr_open(label, devname, NULL);
+    if (!parallel_hds[index]) {
+        fprintf(stderr, "qemu: could not open parallel device '%s': %s\n",
+                devname, strerror(errno));
+        return -1;
+    }
+    index++;
+    return 0;
+}
+
+static int virtcon_parse(const char *devname)
+{
+    QemuOptsList *device = qemu_find_opts("device");
+    static int index = 0;
+    char label[32];
+    QemuOpts *bus_opts, *dev_opts;
+
+    if (strcmp(devname, "none") == 0)
+        return 0;
+    if (index == MAX_VIRTIO_CONSOLES) {
+        fprintf(stderr, "qemu: too many virtio consoles\n");
+        exit(1);
+    }
+
+    bus_opts = qemu_opts_create(device, NULL, 0);
+    qemu_opt_set(bus_opts, "driver", "virtio-serial");
+
+    dev_opts = qemu_opts_create(device, NULL, 0);
+    qemu_opt_set(dev_opts, "driver", "virtconsole");
+
+    snprintf(label, sizeof(label), "virtcon%d", index);
+    virtcon_hds[index] = qemu_chr_open(label, devname, NULL);
+    if (!virtcon_hds[index]) {
+        fprintf(stderr, "qemu: could not open virtio console '%s': %s\n",
+                devname, strerror(errno));
+        return -1;
+    }
+    qemu_opt_set(dev_opts, "chardev", label);
+
+    index++;
+    return 0;
+}
+
+static int debugcon_parse(const char *devname)
+{   
+    QemuOpts *opts;
+
+    if (!qemu_chr_open("debugcon", devname, NULL)) {
+        exit(1);
+    }
+    opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1);
+    if (!opts) {
+        fprintf(stderr, "qemu: already have a debugcon device\n");
+        exit(1);
+    }
+    qemu_opt_set(opts, "driver", "isa-debugcon");
+    qemu_opt_set(opts, "chardev", "debugcon");
+    return 0;
+}
+
+static QEMUMachine *machine_parse(const char *name)
+{
+    QEMUMachine *m, *machine = NULL;
+
+    if (name) {
+        machine = find_machine(name);
+    }
+    if (machine) {
+        return machine;
+    }
+    printf("Supported machines are:\n");
+    for (m = first_machine; m != NULL; m = m->next) {
+        if (m->alias) {
+            printf("%-10s %s (alias of %s)\n", m->alias, m->desc, m->name);
+        }
+        printf("%-10s %s%s\n", m->name, m->desc,
+               m->is_default ? " (default)" : "");
+    }
+    exit(!name || *name != '?');
+}
+
+static int tcg_init(void)
+{
+    return 0;
+}
+
+static struct {
+    const char *opt_name;
+    const char *name;
+    int (*available)(void);
+    int (*init)(void);
+    int *allowed;
+} accel_list[] = {
+    { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
+    { "xen", "Xen", xen_available, xen_init, &xen_allowed },
+    { "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
+};
+
+static int configure_accelerator(void)
+{
+    const char *p = NULL;
+    char buf[10];
+    int i, ret;
+    bool accel_initalised = 0;
+    bool init_failed = 0;
+
+    QemuOptsList *list = qemu_find_opts("machine");
+    if (!QTAILQ_EMPTY(&list->head)) {
+        p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
+    }
+
+    if (p == NULL) {
+        /* Use the default "accelerator", tcg */
+        p = "tcg";
+    }
+
+    while (!accel_initalised && *p != '\0') {
+        if (*p == ':') {
+            p++;
+        }
+        p = get_opt_name(buf, sizeof (buf), p, ':');
+        for (i = 0; i < ARRAY_SIZE(accel_list); i++) {
+            if (strcmp(accel_list[i].opt_name, buf) == 0) {
+                *(accel_list[i].allowed) = 1;
+                ret = accel_list[i].init();
+                if (ret < 0) {
+                    init_failed = 1;
+                    if (!accel_list[i].available()) {
+                        printf("%s not supported for this target\n",
+                               accel_list[i].name);
+                    } else {
+                        fprintf(stderr, "failed to initialize %s: %s\n",
+                                accel_list[i].name,
+                                strerror(-ret));
+                    }
+                    *(accel_list[i].allowed) = 0;
+                } else {
+                    accel_initalised = 1;
+                }
+                break;
+            }
+        }
+        if (i == ARRAY_SIZE(accel_list)) {
+            fprintf(stderr, "\"%s\" accelerator does not exist.\n", buf);
+        }
+    }
+
+    if (!accel_initalised) {
+        fprintf(stderr, "No accelerator found!\n");
+        exit(1);
+    }
+
+    if (init_failed) {
+        fprintf(stderr, "Back to %s accelerator.\n", accel_list[i].name);
+    }
+
+    return !accel_initalised;
+}
+
+void qemu_add_exit_notifier(Notifier *notify)
+{
+    notifier_list_add(&exit_notifiers, notify);
+}
+
+void qemu_remove_exit_notifier(Notifier *notify)
+{
+    notifier_list_remove(&exit_notifiers, notify);
+}
+
+static void qemu_run_exit_notifiers(void)
+{
+    notifier_list_notify(&exit_notifiers, NULL);
+}
+
+void qemu_add_machine_init_done_notifier(Notifier *notify)
+{
+    notifier_list_add(&machine_init_done_notifiers, notify);
+}
+
+static void qemu_run_machine_init_done_notifiers(void)
+{
+    notifier_list_notify(&machine_init_done_notifiers, NULL);
+}
+
+static const QEMUOption *lookup_opt(int argc, char **argv,
+                                    const char **poptarg, int *poptind)
+{
+    const QEMUOption *popt;
+    int optind = *poptind;
+    char *r = argv[optind];
+    const char *optarg;
+
+    loc_set_cmdline(argv, optind, 1);
+    optind++;
+    /* Treat --foo the same as -foo.  */
+    if (r[1] == '-')
+        r++;
+    popt = qemu_options;
+    for(;;) {
+        if (!popt->name) {
+            error_report("invalid option");
+            exit(1);
+        }
+        if (!strcmp(popt->name, r + 1))
+            break;
+        popt++;
+    }
+    if (popt->flags & HAS_ARG) {
+        if (optind >= argc) {
+            error_report("requires an argument");
+            exit(1);
+        }
+        optarg = argv[optind++];
+        loc_set_cmdline(argv, optind - 2, 2);
+    } else {
+        optarg = NULL;
+    }
+
+    *poptarg = optarg;
+    *poptind = optind;
+
+    return popt;
+}
+
+int main(int argc, char **argv, char **envp)
+{
+    const char *gdbstub_dev = NULL;
+    int i;
+    int snapshot, linux_boot;
+    const char *icount_option = NULL;
+    const char *initrd_filename;
+    const char *kernel_filename, *kernel_cmdline;
+    char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
+    DisplayState *ds;
+    DisplayChangeListener *dcl;
+    int cyls, heads, secs, translation;
+    QemuOpts *hda_opts = NULL, *opts;
+    QemuOptsList *olist;
+    int optind;
+    const char *optarg;
+    const char *loadvm = NULL;
+    QEMUMachine *machine;
+    const char *cpu_model;
+    int tb_size;
+    const char *pid_file = NULL;
+    const char *incoming = NULL;
+#ifdef CONFIG_VNC
+    int show_vnc_port = 0;
+#endif
+    int defconfig = 1;
+    const char *trace_file = NULL;
+    const char *log_mask = NULL;
+    const char *log_file = NULL;
+
+    atexit(qemu_run_exit_notifiers);
+    error_set_progname(argv[0]);
+
+    init_clocks();
+
+    qemu_cache_utils_init(envp);
+
+    QLIST_INIT (&vm_change_state_head);
+    os_setup_early_signal_handling();
+
+    module_call_init(MODULE_INIT_MACHINE);
+    machine = find_default_machine();
+    cpu_model = NULL;
+    initrd_filename = NULL;
+    ram_size = 0;
+    snapshot = 0;
+    kernel_filename = NULL;
+    kernel_cmdline = "";
+    cyls = heads = secs = 0;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+
+    for (i = 0; i < MAX_NODES; i++) {
+        node_mem[i] = 0;
+        node_cpumask[i] = 0;
+    }
+
+    nb_numa_nodes = 0;
+    nb_nics = 0;
+
+    tb_size = 0;
+    autostart= 1;
+
+    /* first pass of option parsing */
+    optind = 1;
+    while (optind < argc) {
+        if (argv[optind][0] != '-') {
+            /* disk image */
+            optind++;
+            continue;
+        } else {
+            const QEMUOption *popt;
+
+            popt = lookup_opt(argc, argv, &optarg, &optind);
+            switch (popt->index) {
+            case QEMU_OPTION_nodefconfig:
+                defconfig=0;
+                break;
+            }
+        }
+    }
+
+    if (defconfig) {
+        int ret;
+
+        ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf");
+        if (ret < 0 && ret != -ENOENT) {
+            exit(1);
+        }
+
+        ret = qemu_read_config_file(arch_config_name);
+        if (ret < 0 && ret != -ENOENT) {
+            exit(1);
+        }
+    }
+    cpudef_init();
+
+    /* second pass of option parsing */
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+        if (argv[optind][0] != '-') {
+	    hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
+        } else {
+            const QEMUOption *popt;
+
+            popt = lookup_opt(argc, argv, &optarg, &optind);
+            if (!(popt->arch_mask & arch_type)) {
+                printf("Option %s not supported for this target\n", popt->name);
+                exit(1);
+            }
+            switch(popt->index) {
+            case QEMU_OPTION_M:
+                machine = machine_parse(optarg);
+                break;
+            case QEMU_OPTION_cpu:
+                /* hw initialization will check this */
+                if (*optarg == '?') {
+                    list_cpus(stdout, &fprintf, optarg);
+                    exit(0);
+                } else {
+                    cpu_model = optarg;
+                }
+                break;
+            case QEMU_OPTION_initrd:
+                initrd_filename = optarg;
+                break;
+            case QEMU_OPTION_hda:
+                {
+                    char buf[256];
+                    if (cyls == 0)
+                        snprintf(buf, sizeof(buf), "%s", HD_OPTS);
+                    else
+                        snprintf(buf, sizeof(buf),
+                                 "%s,cyls=%d,heads=%d,secs=%d%s",
+                                 HD_OPTS , cyls, heads, secs,
+                                 translation == BIOS_ATA_TRANSLATION_LBA ?
+                                 ",trans=lba" :
+                                 translation == BIOS_ATA_TRANSLATION_NONE ?
+                                 ",trans=none" : "");
+                    drive_add(IF_DEFAULT, 0, optarg, buf);
+                    break;
+                }
+            case QEMU_OPTION_hdb:
+            case QEMU_OPTION_hdc:
+            case QEMU_OPTION_hdd:
+                drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
+                          HD_OPTS);
+                break;
+            case QEMU_OPTION_drive:
+                if (drive_def(optarg) == NULL) {
+                    exit(1);
+                }
+	        break;
+            case QEMU_OPTION_set:
+                if (qemu_set_option(optarg) != 0)
+                    exit(1);
+	        break;
+            case QEMU_OPTION_global:
+                if (qemu_global_option(optarg) != 0)
+                    exit(1);
+	        break;
+            case QEMU_OPTION_mtdblock:
+                drive_add(IF_MTD, -1, optarg, MTD_OPTS);
+                break;
+            case QEMU_OPTION_sd:
+                drive_add(IF_SD, 0, optarg, SD_OPTS);
+                break;
+            case QEMU_OPTION_pflash:
+                drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
+                break;
+            case QEMU_OPTION_snapshot:
+                snapshot = 1;
+                break;
+            case QEMU_OPTION_hdachs:
+                {
+                    const char *p;
+                    p = optarg;
+                    cyls = strtol(p, (char **)&p, 0);
+                    if (cyls < 1 || cyls > 16383)
+                        goto chs_fail;
+                    if (*p != ',')
+                        goto chs_fail;
+                    p++;
+                    heads = strtol(p, (char **)&p, 0);
+                    if (heads < 1 || heads > 16)
+                        goto chs_fail;
+                    if (*p != ',')
+                        goto chs_fail;
+                    p++;
+                    secs = strtol(p, (char **)&p, 0);
+                    if (secs < 1 || secs > 63)
+                        goto chs_fail;
+                    if (*p == ',') {
+                        p++;
+                        if (!strcmp(p, "none"))
+                            translation = BIOS_ATA_TRANSLATION_NONE;
+                        else if (!strcmp(p, "lba"))
+                            translation = BIOS_ATA_TRANSLATION_LBA;
+                        else if (!strcmp(p, "auto"))
+                            translation = BIOS_ATA_TRANSLATION_AUTO;
+                        else
+                            goto chs_fail;
+                    } else if (*p != '\0') {
+                    chs_fail:
+                        fprintf(stderr, "qemu: invalid physical CHS format\n");
+                        exit(1);
+                    }
+		    if (hda_opts != NULL) {
+                        char num[16];
+                        snprintf(num, sizeof(num), "%d", cyls);
+                        qemu_opt_set(hda_opts, "cyls", num);
+                        snprintf(num, sizeof(num), "%d", heads);
+                        qemu_opt_set(hda_opts, "heads", num);
+                        snprintf(num, sizeof(num), "%d", secs);
+                        qemu_opt_set(hda_opts, "secs", num);
+                        if (translation == BIOS_ATA_TRANSLATION_LBA)
+                            qemu_opt_set(hda_opts, "trans", "lba");
+                        if (translation == BIOS_ATA_TRANSLATION_NONE)
+                            qemu_opt_set(hda_opts, "trans", "none");
+                    }
+                }
+                break;
+            case QEMU_OPTION_numa:
+                if (nb_numa_nodes >= MAX_NODES) {
+                    fprintf(stderr, "qemu: too many NUMA nodes\n");
+                    exit(1);
+                }
+                numa_add(optarg);
+                break;
+            case QEMU_OPTION_display:
+                display_type = select_display(optarg);
+                break;
+            case QEMU_OPTION_nographic:
+                display_type = DT_NOGRAPHIC;
+                break;
+            case QEMU_OPTION_curses:
+#ifdef CONFIG_CURSES
+                display_type = DT_CURSES;
+#else
+                fprintf(stderr, "Curses support is disabled\n");
+                exit(1);
+#endif
+                break;
+            case QEMU_OPTION_portrait:
+                graphic_rotate = 90;
+                break;
+            case QEMU_OPTION_rotate:
+                graphic_rotate = strtol(optarg, (char **) &optarg, 10);
+                if (graphic_rotate != 0 && graphic_rotate != 90 &&
+                    graphic_rotate != 180 && graphic_rotate != 270) {
+                    fprintf(stderr,
+                        "qemu: only 90, 180, 270 deg rotation is available\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_kernel:
+                kernel_filename = optarg;
+                break;
+            case QEMU_OPTION_append:
+                kernel_cmdline = optarg;
+                break;
+            case QEMU_OPTION_cdrom:
+                drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
+                break;
+            case QEMU_OPTION_boot:
+                {
+                    static const char * const params[] = {
+                        "order", "once", "menu", NULL
+                    };
+                    char buf[sizeof(boot_devices)];
+                    char *standard_boot_devices;
+                    int legacy = 0;
+
+                    if (!strchr(optarg, '=')) {
+                        legacy = 1;
+                        pstrcpy(buf, sizeof(buf), optarg);
+                    } else if (check_params(buf, sizeof(buf), params, optarg) < 0) {
+                        fprintf(stderr,
+                                "qemu: unknown boot parameter '%s' in '%s'\n",
+                                buf, optarg);
+                        exit(1);
+                    }
+
+                    if (legacy ||
+                        get_param_value(buf, sizeof(buf), "order", optarg)) {
+                        validate_bootdevices(buf);
+                        pstrcpy(boot_devices, sizeof(boot_devices), buf);
+                    }
+                    if (!legacy) {
+                        if (get_param_value(buf, sizeof(buf),
+                                            "once", optarg)) {
+                            validate_bootdevices(buf);
+                            standard_boot_devices = qemu_strdup(boot_devices);
+                            pstrcpy(boot_devices, sizeof(boot_devices), buf);
+                            qemu_register_reset(restore_boot_devices,
+                                                standard_boot_devices);
+                        }
+                        if (get_param_value(buf, sizeof(buf),
+                                            "menu", optarg)) {
+                            if (!strcmp(buf, "on")) {
+                                boot_menu = 1;
+                            } else if (!strcmp(buf, "off")) {
+                                boot_menu = 0;
+                            } else {
+                                fprintf(stderr,
+                                        "qemu: invalid option value '%s'\n",
+                                        buf);
+                                exit(1);
+                            }
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_fda:
+            case QEMU_OPTION_fdb:
+                drive_add(IF_FLOPPY, popt->index - QEMU_OPTION_fda,
+                          optarg, FD_OPTS);
+                break;
+            case QEMU_OPTION_no_fd_bootchk:
+                fd_bootchk = 0;
+                break;
+            case QEMU_OPTION_netdev:
+                if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_net:
+                if (net_client_parse(qemu_find_opts("net"), optarg) == -1) {
+                    exit(1);
+                }
+                break;
+#ifdef CONFIG_SLIRP
+            case QEMU_OPTION_tftp:
+                legacy_tftp_prefix = optarg;
+                break;
+            case QEMU_OPTION_bootp:
+                legacy_bootp_filename = optarg;
+                break;
+            case QEMU_OPTION_redir:
+                if (net_slirp_redir(optarg) < 0)
+                    exit(1);
+                break;
+#endif
+            case QEMU_OPTION_bt:
+                add_device_config(DEV_BT, optarg);
+                break;
+            case QEMU_OPTION_audio_help:
+                if (!(audio_available())) {
+                    printf("Option %s not supported for this target\n", popt->name);
+                    exit(1);
+                }
+                AUD_help ();
+                exit (0);
+                break;
+            case QEMU_OPTION_soundhw:
+                if (!(audio_available())) {
+                    printf("Option %s not supported for this target\n", popt->name);
+                    exit(1);
+                }
+                select_soundhw (optarg);
+                break;
+            case QEMU_OPTION_h:
+                help(0);
+                break;
+            case QEMU_OPTION_version:
+                version();
+                exit(0);
+                break;
+            case QEMU_OPTION_m: {
+                int64_t value;
+
+                value = strtosz(optarg, NULL);
+                if (value < 0) {
+                    fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
+                    exit(1);
+                }
+
+                /* On 32-bit hosts, QEMU is limited by virtual address space */
+                if (value > (2047 << 20) && HOST_LONG_BITS == 32) {
+                    fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
+                    exit(1);
+                }
+                if (value != (uint64_t)(ram_addr_t)value) {
+                    fprintf(stderr, "qemu: ram size too large\n");
+                    exit(1);
+                }
+                ram_size = value;
+                break;
+            }
+            case QEMU_OPTION_mempath:
+                mem_path = optarg;
+                break;
+#ifdef MAP_POPULATE
+            case QEMU_OPTION_mem_prealloc:
+                mem_prealloc = 1;
+                break;
+#endif
+            case QEMU_OPTION_d:
+                log_mask = optarg;
+                break;
+            case QEMU_OPTION_D:
+                log_file = optarg;
+                break;
+            case QEMU_OPTION_s:
+                gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
+                break;
+            case QEMU_OPTION_gdb:
+                gdbstub_dev = optarg;
+                break;
+            case QEMU_OPTION_L:
+                data_dir = optarg;
+                break;
+            case QEMU_OPTION_bios:
+                bios_name = optarg;
+                break;
+            case QEMU_OPTION_singlestep:
+                singlestep = 1;
+                break;
+            case QEMU_OPTION_S:
+                autostart = 0;
+                break;
+	    case QEMU_OPTION_k:
+		keyboard_layout = optarg;
+		break;
+            case QEMU_OPTION_localtime:
+                rtc_utc = 0;
+                break;
+            case QEMU_OPTION_vga:
+                select_vgahw (optarg);
+                break;
+            case QEMU_OPTION_g:
+                {
+                    const char *p;
+                    int w, h, depth;
+                    p = optarg;
+                    w = strtol(p, (char **)&p, 10);
+                    if (w <= 0) {
+                    graphic_error:
+                        fprintf(stderr, "qemu: invalid resolution or depth\n");
+                        exit(1);
+                    }
+                    if (*p != 'x')
+                        goto graphic_error;
+                    p++;
+                    h = strtol(p, (char **)&p, 10);
+                    if (h <= 0)
+                        goto graphic_error;
+                    if (*p == 'x') {
+                        p++;
+                        depth = strtol(p, (char **)&p, 10);
+                        if (depth != 8 && depth != 15 && depth != 16 &&
+                            depth != 24 && depth != 32)
+                            goto graphic_error;
+                    } else if (*p == '\0') {
+                        depth = graphic_depth;
+                    } else {
+                        goto graphic_error;
+                    }
+
+                    graphic_width = w;
+                    graphic_height = h;
+                    graphic_depth = depth;
+                }
+                break;
+            case QEMU_OPTION_echr:
+                {
+                    char *r;
+                    term_escape_char = strtol(optarg, &r, 0);
+                    if (r == optarg)
+                        printf("Bad argument to echr\n");
+                    break;
+                }
+            case QEMU_OPTION_monitor:
+                monitor_parse(optarg, "readline");
+                default_monitor = 0;
+                break;
+            case QEMU_OPTION_qmp:
+                monitor_parse(optarg, "control");
+                default_monitor = 0;
+                break;
+            case QEMU_OPTION_mon:
+                opts = qemu_opts_parse(qemu_find_opts("mon"), optarg, 1);
+                if (!opts) {
+                    exit(1);
+                }
+                default_monitor = 0;
+                break;
+            case QEMU_OPTION_chardev:
+                opts = qemu_opts_parse(qemu_find_opts("chardev"), optarg, 1);
+                if (!opts) {
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_fsdev:
+                olist = qemu_find_opts("fsdev");
+                if (!olist) {
+                    fprintf(stderr, "fsdev is not supported by this qemu build.\n");
+                    exit(1);
+                }
+                opts = qemu_opts_parse(olist, optarg, 1);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_virtfs: {
+                QemuOpts *fsdev;
+                QemuOpts *device;
+
+                olist = qemu_find_opts("virtfs");
+                if (!olist) {
+                    fprintf(stderr, "virtfs is not supported by this qemu build.\n");
+                    exit(1);
+                }
+                opts = qemu_opts_parse(olist, optarg, 1);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+
+                if (qemu_opt_get(opts, "fstype") == NULL ||
+                        qemu_opt_get(opts, "mount_tag") == NULL ||
+                        qemu_opt_get(opts, "path") == NULL ||
+                        qemu_opt_get(opts, "security_model") == NULL) {
+                    fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
+                            "security_model=[mapped|passthrough|none],"
+                            "mount_tag=tag.\n");
+                    exit(1);
+                }
+
+                fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
+                                         qemu_opt_get(opts, "mount_tag"), 1);
+                if (!fsdev) {
+                    fprintf(stderr, "duplicate fsdev id: %s\n",
+                            qemu_opt_get(opts, "mount_tag"));
+                    exit(1);
+                }
+                qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype"));
+                qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
+                qemu_opt_set(fsdev, "security_model",
+                             qemu_opt_get(opts, "security_model"));
+
+                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+                qemu_opt_set(device, "driver", "virtio-9p-pci");
+                qemu_opt_set(device, "fsdev",
+                             qemu_opt_get(opts, "mount_tag"));
+                qemu_opt_set(device, "mount_tag",
+                             qemu_opt_get(opts, "mount_tag"));
+                break;
+            }
+            case QEMU_OPTION_serial:
+                add_device_config(DEV_SERIAL, optarg);
+                default_serial = 0;
+                if (strncmp(optarg, "mon:", 4) == 0) {
+                    default_monitor = 0;
+                }
+                break;
+            case QEMU_OPTION_watchdog:
+                if (watchdog) {
+                    fprintf(stderr,
+                            "qemu: only one watchdog option may be given\n");
+                    return 1;
+                }
+                watchdog = optarg;
+                break;
+            case QEMU_OPTION_watchdog_action:
+                if (select_watchdog_action(optarg) == -1) {
+                    fprintf(stderr, "Unknown -watchdog-action parameter\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_virtiocon:
+                add_device_config(DEV_VIRTCON, optarg);
+                default_virtcon = 0;
+                if (strncmp(optarg, "mon:", 4) == 0) {
+                    default_monitor = 0;
+                }
+                break;
+            case QEMU_OPTION_parallel:
+                add_device_config(DEV_PARALLEL, optarg);
+                default_parallel = 0;
+                if (strncmp(optarg, "mon:", 4) == 0) {
+                    default_monitor = 0;
+                }
+                break;
+            case QEMU_OPTION_debugcon:
+                add_device_config(DEV_DEBUGCON, optarg);
+                break;
+	    case QEMU_OPTION_loadvm:
+		loadvm = optarg;
+		break;
+            case QEMU_OPTION_full_screen:
+                full_screen = 1;
+                break;
+#ifdef CONFIG_SDL
+            case QEMU_OPTION_no_frame:
+                no_frame = 1;
+                break;
+            case QEMU_OPTION_alt_grab:
+                alt_grab = 1;
+                break;
+            case QEMU_OPTION_ctrl_grab:
+                ctrl_grab = 1;
+                break;
+            case QEMU_OPTION_no_quit:
+                no_quit = 1;
+                break;
+            case QEMU_OPTION_sdl:
+                display_type = DT_SDL;
+                break;
+#else
+            case QEMU_OPTION_no_frame:
+            case QEMU_OPTION_alt_grab:
+            case QEMU_OPTION_ctrl_grab:
+            case QEMU_OPTION_no_quit:
+            case QEMU_OPTION_sdl:
+                fprintf(stderr, "SDL support is disabled\n");
+                exit(1);
+#endif
+            case QEMU_OPTION_pidfile:
+                pid_file = optarg;
+                break;
+            case QEMU_OPTION_win2k_hack:
+                win2k_install_hack = 1;
+                break;
+            case QEMU_OPTION_rtc_td_hack:
+                rtc_td_hack = 1;
+                break;
+            case QEMU_OPTION_acpitable:
+                do_acpitable_option(optarg);
+                break;
+            case QEMU_OPTION_smbios:
+                do_smbios_option(optarg);
+                break;
+            case QEMU_OPTION_enable_kvm:
+                olist = qemu_find_opts("machine");
+                qemu_opts_reset(olist);
+                qemu_opts_parse(olist, "accel=kvm", 0);
+                break;
+            case QEMU_OPTION_machine:
+                olist = qemu_find_opts("machine");
+                qemu_opts_reset(olist);
+                opts = qemu_opts_parse(olist, optarg, 1);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+                machine = machine_parse(qemu_opt_get(opts, "type"));
+                break;
+            case QEMU_OPTION_usb:
+                usb_enabled = 1;
+                break;
+            case QEMU_OPTION_usbdevice:
+                usb_enabled = 1;
+                add_device_config(DEV_USB, optarg);
+                break;
+            case QEMU_OPTION_device:
+                if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_smp:
+                smp_parse(optarg);
+                if (smp_cpus < 1) {
+                    fprintf(stderr, "Invalid number of CPUs\n");
+                    exit(1);
+                }
+                if (max_cpus < smp_cpus) {
+                    fprintf(stderr, "maxcpus must be equal to or greater than "
+                            "smp\n");
+                    exit(1);
+                }
+                if (max_cpus > 255) {
+                    fprintf(stderr, "Unsupported number of maxcpus\n");
+                    exit(1);
+                }
+                break;
+	    case QEMU_OPTION_vnc:
+#ifdef CONFIG_VNC
+                display_remote++;
+                vnc_display = optarg;
+#else
+                fprintf(stderr, "VNC support is disabled\n");
+                exit(1);
+#endif
+                break;
+            case QEMU_OPTION_no_acpi:
+                acpi_enabled = 0;
+                break;
+            case QEMU_OPTION_no_hpet:
+                no_hpet = 1;
+                break;
+            case QEMU_OPTION_balloon:
+                if (balloon_parse(optarg) < 0) {
+                    fprintf(stderr, "Unknown -balloon argument %s\n", optarg);
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_no_reboot:
+                no_reboot = 1;
+                break;
+            case QEMU_OPTION_no_shutdown:
+                no_shutdown = 1;
+                break;
+            case QEMU_OPTION_show_cursor:
+                cursor_hide = 0;
+                break;
+            case QEMU_OPTION_uuid:
+                if(qemu_uuid_parse(optarg, qemu_uuid) < 0) {
+                    fprintf(stderr, "Fail to parse UUID string."
+                            " Wrong format.\n");
+                    exit(1);
+                }
+                break;
+	    case QEMU_OPTION_option_rom:
+		if (nb_option_roms >= MAX_OPTION_ROMS) {
+		    fprintf(stderr, "Too many option ROMs\n");
+		    exit(1);
+		}
+                opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1);
+                option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile");
+                option_rom[nb_option_roms].bootindex =
+                    qemu_opt_get_number(opts, "bootindex", -1);
+                if (!option_rom[nb_option_roms].name) {
+                    fprintf(stderr, "Option ROM file is not specified\n");
+                    exit(1);
+                }
+		nb_option_roms++;
+		break;
+            case QEMU_OPTION_semihosting:
+                semihosting_enabled = 1;
+                break;
+            case QEMU_OPTION_name:
+                qemu_name = qemu_strdup(optarg);
+		 {
+		     char *p = strchr(qemu_name, ',');
+		     if (p != NULL) {
+		        *p++ = 0;
+			if (strncmp(p, "process=", 8)) {
+			    fprintf(stderr, "Unknown subargument %s to -name\n", p);
+			    exit(1);
+			}
+			p += 8;
+			os_set_proc_name(p);
+		     }	
+		 }	
+                break;
+            case QEMU_OPTION_prom_env:
+                if (nb_prom_envs >= MAX_PROM_ENVS) {
+                    fprintf(stderr, "Too many prom variables\n");
+                    exit(1);
+                }
+                prom_envs[nb_prom_envs] = optarg;
+                nb_prom_envs++;
+                break;
+            case QEMU_OPTION_old_param:
+                old_param = 1;
+                break;
+            case QEMU_OPTION_clock:
+                configure_alarms(optarg);
+                break;
+            case QEMU_OPTION_startdate:
+                configure_rtc_date_offset(optarg, 1);
+                break;
+            case QEMU_OPTION_rtc:
+                opts = qemu_opts_parse(qemu_find_opts("rtc"), optarg, 0);
+                if (!opts) {
+                    exit(1);
+                }
+                configure_rtc(opts);
+                break;
+            case QEMU_OPTION_tb_size:
+                tb_size = strtol(optarg, NULL, 0);
+                if (tb_size < 0)
+                    tb_size = 0;
+                break;
+            case QEMU_OPTION_icount:
+                icount_option = optarg;
+                break;
+            case QEMU_OPTION_incoming:
+                incoming = optarg;
+                incoming_expected = true;
+                break;
+            case QEMU_OPTION_nodefaults:
+                default_serial = 0;
+                default_parallel = 0;
+                default_virtcon = 0;
+                default_monitor = 0;
+                default_vga = 0;
+                default_net = 0;
+                default_floppy = 0;
+                default_cdrom = 0;
+                default_sdcard = 0;
+                break;
+            case QEMU_OPTION_xen_domid:
+                if (!(xen_available())) {
+                    printf("Option %s not supported for this target\n", popt->name);
+                    exit(1);
+                }
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                if (!(xen_available())) {
+                    printf("Option %s not supported for this target\n", popt->name);
+                    exit(1);
+                }
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                if (!(xen_available())) {
+                    printf("Option %s not supported for this target\n", popt->name);
+                    exit(1);
+                }
+                xen_mode = XEN_ATTACH;
+                break;
+#ifdef CONFIG_SIMPLE_TRACE
+            case QEMU_OPTION_trace:
+                opts = qemu_opts_parse(qemu_find_opts("trace"), optarg, 0);
+                if (opts) {
+                    trace_file = qemu_opt_get(opts, "file");
+                }
+                break;
+#endif
+            case QEMU_OPTION_readconfig:
+                {
+                    int ret = qemu_read_config_file(optarg);
+                    if (ret < 0) {
+                        fprintf(stderr, "read config %s: %s\n", optarg,
+                            strerror(-ret));
+                        exit(1);
+                    }
+                    break;
+                }
+            case QEMU_OPTION_spice:
+                olist = qemu_find_opts("spice");
+                if (!olist) {
+                    fprintf(stderr, "spice is not supported by this qemu build.\n");
+                    exit(1);
+                }
+                opts = qemu_opts_parse(olist, optarg, 0);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_writeconfig:
+                {
+                    FILE *fp;
+                    if (strcmp(optarg, "-") == 0) {
+                        fp = stdout;
+                    } else {
+                        fp = fopen(optarg, "w");
+                        if (fp == NULL) {
+                            fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
+                            exit(1);
+                        }
+                    }
+                    qemu_config_write(fp);
+                    fclose(fp);
+                    break;
+                }
+            default:
+                os_parse_cmd_args(popt->index, optarg);
+            }
+        }
+    }
+    loc_set_none();
+
+    /* Open the logfile at this point, if necessary. We can't open the logfile
+     * when encountering either of the logging options (-d or -D) because the
+     * other one may be encountered later on the command line, changing the
+     * location or level of logging.
+     */
+    if (log_mask) {
+        if (log_file) {
+            set_cpu_log_filename(log_file);
+        }
+        set_cpu_log(log_mask);
+    }
+
+    if (!st_init(trace_file)) {
+        fprintf(stderr, "warning: unable to initialize simple trace backend\n");
+    }
+
+    /* If no data_dir is specified then try to find it relative to the
+       executable path.  */
+    if (!data_dir) {
+        data_dir = os_find_datadir(argv[0]);
+    }
+    /* If all else fails use the install patch specified when building.  */
+    if (!data_dir) {
+        data_dir = CONFIG_QEMU_DATADIR;
+    }
+
+    /*
+     * Default to max_cpus = smp_cpus, in case the user doesn't
+     * specify a max_cpus value.
+     */
+    if (!max_cpus)
+        max_cpus = smp_cpus;
+
+    machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
+    if (smp_cpus > machine->max_cpus) {
+        fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
+                "supported by machine `%s' (%d)\n", smp_cpus,  machine->name,
+                machine->max_cpus);
+        exit(1);
+    }
+
+    /*
+     * Get the default machine options from the machine if it is not already
+     * specified either by the configuration file or by the command line.
+     */
+    if (machine->default_machine_opts) {
+        QemuOptsList *list = qemu_find_opts("machine");
+        const char *p = NULL;
+
+        if (!QTAILQ_EMPTY(&list->head)) {
+            p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
+        }
+        if (p == NULL) {
+            qemu_opts_reset(list);
+            opts = qemu_opts_parse(list, machine->default_machine_opts, 0);
+            if (!opts) {
+                fprintf(stderr, "parse error for machine %s: %s\n",
+                        machine->name, machine->default_machine_opts);
+                exit(1);
+            }
+        }
+    }
+
+    qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
+    qemu_opts_foreach(qemu_find_opts("global"), default_driver_check, NULL, 0);
+
+    if (machine->no_serial) {
+        default_serial = 0;
+    }
+    if (machine->no_parallel) {
+        default_parallel = 0;
+    }
+    if (!machine->use_virtcon) {
+        default_virtcon = 0;
+    }
+    if (machine->no_vga) {
+        default_vga = 0;
+    }
+    if (machine->no_floppy) {
+        default_floppy = 0;
+    }
+    if (machine->no_cdrom) {
+        default_cdrom = 0;
+    }
+    if (machine->no_sdcard) {
+        default_sdcard = 0;
+    }
+
+    if (display_type == DT_NOGRAPHIC) {
+        if (default_parallel)
+            add_device_config(DEV_PARALLEL, "null");
+        if (default_serial && default_monitor) {
+            add_device_config(DEV_SERIAL, "mon:stdio");
+        } else if (default_virtcon && default_monitor) {
+            add_device_config(DEV_VIRTCON, "mon:stdio");
+        } else {
+            if (default_serial)
+                add_device_config(DEV_SERIAL, "stdio");
+            if (default_virtcon)
+                add_device_config(DEV_VIRTCON, "stdio");
+            if (default_monitor)
+                monitor_parse("stdio", "readline");
+        }
+    } else {
+        if (default_serial)
+            add_device_config(DEV_SERIAL, "vc:80Cx24C");
+        if (default_parallel)
+            add_device_config(DEV_PARALLEL, "vc:80Cx24C");
+        if (default_monitor)
+            monitor_parse("vc:80Cx24C", "readline");
+        if (default_virtcon)
+            add_device_config(DEV_VIRTCON, "vc:80Cx24C");
+    }
+    if (default_vga)
+        vga_interface_type = VGA_CIRRUS;
+
+    socket_init();
+
+    if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
+        exit(1);
+#ifdef CONFIG_VIRTFS
+    if (qemu_opts_foreach(qemu_find_opts("fsdev"), fsdev_init_func, NULL, 1) != 0) {
+        exit(1);
+    }
+#endif
+
+    os_daemonize();
+
+    if (pid_file && qemu_create_pidfile(pid_file) != 0) {
+        os_pidfile_error();
+        exit(1);
+    }
+
+    configure_accelerator();
+
+    if (qemu_init_main_loop()) {
+        fprintf(stderr, "qemu_init_main_loop failed\n");
+        exit(1);
+    }
+    linux_boot = (kernel_filename != NULL);
+
+    if (!linux_boot && *kernel_cmdline != '\0') {
+        fprintf(stderr, "-append only allowed with -kernel option\n");
+        exit(1);
+    }
+
+    if (!linux_boot && initrd_filename != NULL) {
+        fprintf(stderr, "-initrd only allowed with -kernel option\n");
+        exit(1);
+    }
+
+    os_set_line_buffering();
+
+    if (init_timer_alarm() < 0) {
+        fprintf(stderr, "could not initialize alarm timer\n");
+        exit(1);
+    }
+    configure_icount(icount_option);
+
+    if (net_init_clients() < 0) {
+        exit(1);
+    }
+
+    /* init the bluetooth world */
+    if (foreach_device_config(DEV_BT, bt_parse))
+        exit(1);
+
+    /* init the memory */
+    if (ram_size == 0)
+        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+
+    /* init the dynamic translator */
+    cpu_exec_init_all(tb_size * 1024 * 1024);
+
+    bdrv_init_with_whitelist();
+
+    blk_mig_init();
+
+    /* open the virtual block devices */
+    if (snapshot)
+        qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
+    if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0)
+        exit(1);
+
+    default_drive(default_cdrom, snapshot, machine->use_scsi,
+                  IF_DEFAULT, 2, CDROM_OPTS);
+    default_drive(default_floppy, snapshot, machine->use_scsi,
+                  IF_FLOPPY, 0, FD_OPTS);
+    default_drive(default_sdcard, snapshot, machine->use_scsi,
+                  IF_SD, 0, SD_OPTS);
+
+    register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
+                         ram_load, NULL);
+
+    if (nb_numa_nodes > 0) {
+        int i;
+
+        if (nb_numa_nodes > MAX_NODES) {
+            nb_numa_nodes = MAX_NODES;
+        }
+
+        /* If no memory size if given for any node, assume the default case
+         * and distribute the available memory equally across all nodes
+         */
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_mem[i] != 0)
+                break;
+        }
+        if (i == nb_numa_nodes) {
+            uint64_t usedmem = 0;
+
+            /* On Linux, the each node's border has to be 8MB aligned,
+             * the final node gets the rest.
+             */
+            for (i = 0; i < nb_numa_nodes - 1; i++) {
+                node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1);
+                usedmem += node_mem[i];
+            }
+            node_mem[i] = ram_size - usedmem;
+        }
+
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] != 0)
+                break;
+        }
+        /* assigning the VCPUs round-robin is easier to implement, guest OSes
+         * must cope with this anyway, because there are BIOSes out there in
+         * real machines which also use this scheme.
+         */
+        if (i == nb_numa_nodes) {
+            for (i = 0; i < smp_cpus; i++) {
+                node_cpumask[i % nb_numa_nodes] |= 1 << i;
+            }
+        }
+    }
+
+    if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) {
+        exit(1);
+    }
+
+    if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
+        exit(1);
+    if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
+        exit(1);
+    if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0)
+        exit(1);
+    if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
+        exit(1);
+
+    module_call_init(MODULE_INIT_DEVICE);
+
+    if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
+        exit(0);
+
+    if (watchdog) {
+        i = select_watchdog(watchdog);
+        if (i > 0)
+            exit (i == 1 ? 1 : 0);
+    }
+
+    if (machine->compat_props) {
+        qdev_prop_register_global_list(machine->compat_props);
+    }
+    qemu_add_globals();
+
+    machine->init(ram_size, boot_devices,
+                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
+
+    cpu_synchronize_all_post_init();
+
+    set_numa_modes();
+
+    current_machine = machine;
+
+    /* init USB devices */
+    if (usb_enabled) {
+        if (foreach_device_config(DEV_USB, usb_parse) < 0)
+            exit(1);
+    }
+
+    /* init generic devices */
+    if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
+        exit(1);
+
+    net_check_clients();
+
+    /* just use the first displaystate for the moment */
+    ds = get_displaystate();
+
+    if (using_spice)
+        display_remote++;
+    if (display_type == DT_DEFAULT && !display_remote) {
+#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+        display_type = DT_SDL;
+#elif defined(CONFIG_VNC)
+        vnc_display = "localhost:0,to=99";
+        show_vnc_port = 1;
+#else
+        display_type = DT_NONE;
+#endif
+    }
+
+
+    /* init local displays */
+    switch (display_type) {
+    case DT_NOGRAPHIC:
+        break;
+#if defined(CONFIG_CURSES)
+    case DT_CURSES:
+        curses_display_init(ds, full_screen);
+        break;
+#endif
+#if defined(CONFIG_SDL)
+    case DT_SDL:
+        sdl_display_init(ds, full_screen, no_frame);
+        break;
+#elif defined(CONFIG_COCOA)
+    case DT_SDL:
+        cocoa_display_init(ds, full_screen);
+        break;
+#endif
+    default:
+        break;
+    }
+
+    /* must be after terminal init, SDL library changes signal handlers */
+    os_setup_signal_handling();
+
+#ifdef CONFIG_VNC
+    /* init remote displays */
+    if (vnc_display) {
+        vnc_display_init(ds);
+        if (vnc_display_open(ds, vnc_display) < 0)
+            exit(1);
+
+        if (show_vnc_port) {
+            printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
+        }
+    }
+#endif
+#ifdef CONFIG_SPICE
+    if (using_spice && !qxl_enabled) {
+        qemu_spice_display_init(ds);
+    }
+#endif
+
+    /* display setup */
+    dpy_resize(ds);
+    dcl = ds->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh != NULL) {
+            ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds);
+            qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock));
+            break;
+        }
+        dcl = dcl->next;
+    }
+    if (ds->gui_timer == NULL) {
+        nographic_timer = qemu_new_timer_ms(rt_clock, nographic_update, NULL);
+        qemu_mod_timer(nographic_timer, qemu_get_clock_ms(rt_clock));
+    }
+    text_consoles_set_display(ds);
+
+    if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
+        fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
+                gdbstub_dev);
+        exit(1);
+    }
+
+    qdev_machine_creation_done();
+
+    if (rom_load_all() != 0) {
+        fprintf(stderr, "rom loading failed\n");
+        exit(1);
+    }
+
+    /* TODO: once all bus devices are qdevified, this should be done
+     * when bus is created by qdev.c */
+    qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
+    qemu_run_machine_init_done_notifiers();
+
+    qemu_system_reset(VMRESET_SILENT);
+    if (loadvm) {
+        if (load_vmstate(loadvm) < 0) {
+            autostart = 0;
+        }
+    }
+
+    if (incoming) {
+        int ret = qemu_start_incoming_migration(incoming);
+        if (ret < 0) {
+            fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
+                    incoming, ret);
+            exit(ret);
+        }
+    } else if (autostart) {
+        vm_start();
+    }
+
+    os_setup_post();
+
+    main_loop();
+    quit_timers();
+    net_cleanup();
+
+    return 0;
+}
diff --git a/qemu-0.15.x/x86_64.ld b/qemu-0.15.x/x86_64.ld
new file mode 100644
index 0000000..b7a9f4e
--- /dev/null
+++ b/qemu-0.15.x/x86_64.ld
@@ -0,0 +1,180 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x60000000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt      :
+  {
+    *(.rel.plt)
+    PROVIDE (__rel_iplt_start = .);
+    *(.rel.iplt)
+    PROVIDE (__rel_iplt_end = .);
+  }
+  .rela.plt       :
+  {
+    *(.rela.plt)
+    PROVIDE (__rela_iplt_start = .);
+    *(.rela.iplt)
+    PROVIDE (__rela_iplt_end = .);
+  }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x90909090
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(64 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(64 / 8);
+  }
+  . = ALIGN(64 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/qemu-0.15.x/xen-all.c b/qemu-0.15.x/xen-all.c
new file mode 100644
index 0000000..167bed6
--- /dev/null
+++ b/qemu-0.15.x/xen-all.c
@@ -0,0 +1,955 @@
+/*
+ * Copyright (C) 2010       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/mman.h>
+
+#include "hw/pci.h"
+#include "hw/pc.h"
+#include "hw/xen_common.h"
+#include "hw/xen_backend.h"
+
+#include "range.h"
+#include "xen-mapcache.h"
+#include "trace.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
+//#define DEBUG_XEN
+
+#ifdef DEBUG_XEN
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* Compatibility with older version */
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
+static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
+{
+    return shared_page->vcpu_iodata[i].vp_eport;
+}
+static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
+{
+    return &shared_page->vcpu_iodata[vcpu].vp_ioreq;
+}
+#  define FMT_ioreq_size PRIx64
+#else
+static inline uint32_t xen_vcpu_eport(shared_iopage_t *shared_page, int i)
+{
+    return shared_page->vcpu_ioreq[i].vp_eport;
+}
+static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
+{
+    return &shared_page->vcpu_ioreq[vcpu];
+}
+#  define FMT_ioreq_size "u"
+#endif
+
+#define BUFFER_IO_MAX_DELAY  100
+
+typedef struct XenPhysmap {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    target_phys_addr_t phys_offset;
+
+    QLIST_ENTRY(XenPhysmap) list;
+} XenPhysmap;
+
+typedef struct XenIOState {
+    shared_iopage_t *shared_page;
+    buffered_iopage_t *buffered_io_page;
+    QEMUTimer *buffered_io_timer;
+    /* the evtchn port for polling the notification, */
+    evtchn_port_t *ioreq_local_port;
+    /* the evtchn fd for polling */
+    XenEvtchn xce_handle;
+    /* which vcpu we are serving */
+    int send_vcpu;
+
+    struct xs_handle *xenstore;
+    CPUPhysMemoryClient client;
+    QLIST_HEAD(, XenPhysmap) physmap;
+    const XenPhysmap *log_for_dirtybit;
+
+    Notifier exit;
+} XenIOState;
+
+/* Xen specific function for piix pci */
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num + ((pci_dev->devfn >> 3) << 2);
+}
+
+void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+                              irq_num & 3, level);
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+    int i;
+
+    /* Scan for updates to PCI link routes (0x60-0x63). */
+    for (i = 0; i < len; i++) {
+        uint8_t v = (val >> (8 * i)) & 0xff;
+        if (v & 0x80) {
+            v = 0;
+        }
+        v &= 0xf;
+        if (((address + i) >= 0x60) && ((address + i) <= 0x63)) {
+            xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
+        }
+    }
+}
+
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+    pc_cmos_set_s3_resume(opaque, irq, level);
+    if (level) {
+        xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
+    }
+}
+
+/* Xen Interrupt Controller */
+
+static void xen_set_irq(void *opaque, int irq, int level)
+{
+    xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
+}
+
+qemu_irq *xen_interrupt_controller_init(void)
+{
+    return qemu_allocate_irqs(xen_set_irq, NULL, 16);
+}
+
+/* Memory Ops */
+
+static void xen_ram_init(ram_addr_t ram_size)
+{
+    RAMBlock *new_block;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+
+    new_block = qemu_mallocz(sizeof (*new_block));
+    pstrcpy(new_block->idstr, sizeof (new_block->idstr), "xen.ram");
+    new_block->host = NULL;
+    new_block->offset = 0;
+    new_block->length = ram_size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+                                       new_block->length >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, new_block->length >> TARGET_PAGE_BITS);
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        below_4g_mem_size = ram_size;
+    }
+
+    cpu_register_physical_memory(0, below_4g_mem_size, new_block->offset);
+#if TARGET_PHYS_ADDR_BITS > 32
+    if (above_4g_mem_size > 0) {
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     new_block->offset + below_4g_mem_size);
+    }
+#endif
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size)
+{
+    unsigned long nr_pfn;
+    xen_pfn_t *pfn_list;
+    int i;
+
+    trace_xen_ram_alloc(ram_addr, size);
+
+    nr_pfn = size >> TARGET_PAGE_BITS;
+    pfn_list = qemu_malloc(sizeof (*pfn_list) * nr_pfn);
+
+    for (i = 0; i < nr_pfn; i++) {
+        pfn_list[i] = (ram_addr >> TARGET_PAGE_BITS) + i;
+    }
+
+    if (xc_domain_populate_physmap_exact(xen_xc, xen_domid, nr_pfn, 0, 0, pfn_list)) {
+        hw_error("xen: failed to populate ram at %lx", ram_addr);
+    }
+
+    qemu_free(pfn_list);
+}
+
+static XenPhysmap *get_physmapping(XenIOState *state,
+                                   target_phys_addr_t start_addr, ram_addr_t size)
+{
+    XenPhysmap *physmap = NULL;
+
+    start_addr &= TARGET_PAGE_MASK;
+
+    QLIST_FOREACH(physmap, &state->physmap, list) {
+        if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) {
+            return physmap;
+        }
+    }
+    return NULL;
+}
+
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 340
+static int xen_add_to_physmap(XenIOState *state,
+                              target_phys_addr_t start_addr,
+                              ram_addr_t size,
+                              target_phys_addr_t phys_offset)
+{
+    unsigned long i = 0;
+    int rc = 0;
+    XenPhysmap *physmap = NULL;
+    target_phys_addr_t pfn, start_gpfn;
+    RAMBlock *block;
+
+    if (get_physmapping(state, start_addr, size)) {
+        return 0;
+    }
+    if (size <= 0) {
+        return -1;
+    }
+
+    /* Xen can only handle a single dirty log region for now and we want
+     * the linear framebuffer to be that region.
+     * Avoid tracking any regions that is not videoram and avoid tracking
+     * the legacy vga region. */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!strcmp(block->idstr, "vga.vram") && block->offset == phys_offset
+                && start_addr > 0xbffff) {
+            goto go_physmap;
+        }
+    }
+    return -1;
+
+go_physmap:
+    DPRINTF("mapping vram to %llx - %llx, from %llx\n",
+            start_addr, start_addr + size, phys_offset);
+
+    pfn = phys_offset >> TARGET_PAGE_BITS;
+    start_gpfn = start_addr >> TARGET_PAGE_BITS;
+    for (i = 0; i < size >> TARGET_PAGE_BITS; i++) {
+        unsigned long idx = pfn + i;
+        xen_pfn_t gpfn = start_gpfn + i;
+
+        rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
+        if (rc) {
+            DPRINTF("add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
+                    PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
+            return -rc;
+        }
+    }
+
+    physmap = qemu_malloc(sizeof (XenPhysmap));
+
+    physmap->start_addr = start_addr;
+    physmap->size = size;
+    physmap->phys_offset = phys_offset;
+
+    QLIST_INSERT_HEAD(&state->physmap, physmap, list);
+
+    xc_domain_pin_memory_cacheattr(xen_xc, xen_domid,
+                                   start_addr >> TARGET_PAGE_BITS,
+                                   (start_addr + size) >> TARGET_PAGE_BITS,
+                                   XEN_DOMCTL_MEM_CACHEATTR_WB);
+    return 0;
+}
+
+static int xen_remove_from_physmap(XenIOState *state,
+                                   target_phys_addr_t start_addr,
+                                   ram_addr_t size)
+{
+    unsigned long i = 0;
+    int rc = 0;
+    XenPhysmap *physmap = NULL;
+    target_phys_addr_t phys_offset = 0;
+
+    physmap = get_physmapping(state, start_addr, size);
+    if (physmap == NULL) {
+        return -1;
+    }
+
+    phys_offset = physmap->phys_offset;
+    size = physmap->size;
+
+    DPRINTF("unmapping vram to %llx - %llx, from %llx\n",
+            phys_offset, phys_offset + size, start_addr);
+
+    size >>= TARGET_PAGE_BITS;
+    start_addr >>= TARGET_PAGE_BITS;
+    phys_offset >>= TARGET_PAGE_BITS;
+    for (i = 0; i < size; i++) {
+        unsigned long idx = start_addr + i;
+        xen_pfn_t gpfn = phys_offset + i;
+
+        rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
+        if (rc) {
+            fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
+                    PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
+            return -rc;
+        }
+    }
+
+    QLIST_REMOVE(physmap, list);
+    if (state->log_for_dirtybit == physmap) {
+        state->log_for_dirtybit = NULL;
+    }
+    free(physmap);
+
+    return 0;
+}
+
+#else
+static int xen_add_to_physmap(XenIOState *state,
+                              target_phys_addr_t start_addr,
+                              ram_addr_t size,
+                              target_phys_addr_t phys_offset)
+{
+    return -ENOSYS;
+}
+
+static int xen_remove_from_physmap(XenIOState *state,
+                                   target_phys_addr_t start_addr,
+                                   ram_addr_t size)
+{
+    return -ENOSYS;
+}
+#endif
+
+static void xen_client_set_memory(struct CPUPhysMemoryClient *client,
+                                  target_phys_addr_t start_addr,
+                                  ram_addr_t size,
+                                  ram_addr_t phys_offset,
+                                  bool log_dirty)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    hvmmem_type_t mem_type;
+
+    if (!(start_addr != phys_offset
+          && ( (log_dirty && flags < IO_MEM_UNASSIGNED)
+               || (!log_dirty && flags == IO_MEM_UNASSIGNED)))) {
+        return;
+    }
+
+    trace_xen_client_set_memory(start_addr, size, phys_offset, log_dirty);
+
+    start_addr &= TARGET_PAGE_MASK;
+    size = TARGET_PAGE_ALIGN(size);
+    phys_offset &= TARGET_PAGE_MASK;
+
+    switch (flags) {
+    case IO_MEM_RAM:
+        xen_add_to_physmap(state, start_addr, size, phys_offset);
+        break;
+    case IO_MEM_ROM:
+        mem_type = HVMMEM_ram_ro;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type,
+                                start_addr >> TARGET_PAGE_BITS,
+                                size >> TARGET_PAGE_BITS)) {
+            DPRINTF("xc_hvm_set_mem_type error, addr: "TARGET_FMT_plx"\n",
+                    start_addr);
+        }
+        break;
+    case IO_MEM_UNASSIGNED:
+        if (xen_remove_from_physmap(state, start_addr, size) < 0) {
+            DPRINTF("physmapping does not exist at "TARGET_FMT_plx"\n", start_addr);
+        }
+        break;
+    }
+}
+
+static int xen_sync_dirty_bitmap(XenIOState *state,
+                                 target_phys_addr_t start_addr,
+                                 ram_addr_t size)
+{
+    target_phys_addr_t npages = size >> TARGET_PAGE_BITS;
+    target_phys_addr_t vram_offset = 0;
+    const int width = sizeof(unsigned long) * 8;
+    unsigned long bitmap[(npages + width - 1) / width];
+    int rc, i, j;
+    const XenPhysmap *physmap = NULL;
+
+    physmap = get_physmapping(state, start_addr, size);
+    if (physmap == NULL) {
+        /* not handled */
+        return -1;
+    }
+
+    if (state->log_for_dirtybit == NULL) {
+        state->log_for_dirtybit = physmap;
+    } else if (state->log_for_dirtybit != physmap) {
+        return -1;
+    }
+    vram_offset = physmap->phys_offset;
+
+    rc = xc_hvm_track_dirty_vram(xen_xc, xen_domid,
+                                 start_addr >> TARGET_PAGE_BITS, npages,
+                                 bitmap);
+    if (rc) {
+        return rc;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bitmap); i++) {
+        unsigned long map = bitmap[i];
+        while (map != 0) {
+            j = ffsl(map) - 1;
+            map &= ~(1ul << j);
+            cpu_physical_memory_set_dirty(vram_offset + (i * width + j) * TARGET_PAGE_SIZE);
+        };
+    }
+
+    return 0;
+}
+
+static int xen_log_start(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    return xen_sync_dirty_bitmap(state, phys_addr, size);
+}
+
+static int xen_log_stop(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    state->log_for_dirtybit = NULL;
+    /* Disable dirty bit tracking */
+    return xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL);
+}
+
+static int xen_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+                                        target_phys_addr_t start_addr,
+                                        target_phys_addr_t end_addr)
+{
+    XenIOState *state = container_of(client, XenIOState, client);
+
+    return xen_sync_dirty_bitmap(state, start_addr, end_addr - start_addr);
+}
+
+static int xen_client_migration_log(struct CPUPhysMemoryClient *client,
+                                    int enable)
+{
+    return 0;
+}
+
+static CPUPhysMemoryClient xen_cpu_phys_memory_client = {
+    .set_memory = xen_client_set_memory,
+    .sync_dirty_bitmap = xen_client_sync_dirty_bitmap,
+    .migration_log = xen_client_migration_log,
+    .log_start = xen_log_start,
+    .log_stop = xen_log_stop,
+};
+
+/* VCPU Operations, MMIO, IO ring ... */
+
+static void xen_reset_vcpu(void *opaque)
+{
+    CPUState *env = opaque;
+
+    env->halted = 1;
+}
+
+void xen_vcpu_init(void)
+{
+    CPUState *first_cpu;
+
+    if ((first_cpu = qemu_get_cpu(0))) {
+        qemu_register_reset(xen_reset_vcpu, first_cpu);
+        xen_reset_vcpu(first_cpu);
+    }
+}
+
+/* get the ioreq packets from share mem */
+static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu)
+{
+    ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu);
+
+    if (req->state != STATE_IOREQ_READY) {
+        DPRINTF("I/O request not ready: "
+                "%x, ptr: %x, port: %"PRIx64", "
+                "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
+                req->state, req->data_is_ptr, req->addr,
+                req->data, req->count, req->size);
+        return NULL;
+    }
+
+    xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+    req->state = STATE_IOREQ_INPROCESS;
+    return req;
+}
+
+/* use poll to get the port notification */
+/* ioreq_vec--out,the */
+/* retval--the number of ioreq packet */
+static ioreq_t *cpu_get_ioreq(XenIOState *state)
+{
+    int i;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(state->xce_handle);
+    if (port != -1) {
+        for (i = 0; i < smp_cpus; i++) {
+            if (state->ioreq_local_port[i] == port) {
+                break;
+            }
+        }
+
+        if (i == smp_cpus) {
+            hw_error("Fatal error while trying to get io event!\n");
+        }
+
+        /* unmask the wanted port again */
+        xc_evtchn_unmask(state->xce_handle, port);
+
+        /* get the io packet from shared memory */
+        state->send_vcpu = i;
+        return cpu_get_ioreq_from_shared_memory(state, i);
+    }
+
+    /* read error or read nothing */
+    return NULL;
+}
+
+static uint32_t do_inp(pio_addr_t addr, unsigned long size)
+{
+    switch (size) {
+        case 1:
+            return cpu_inb(addr);
+        case 2:
+            return cpu_inw(addr);
+        case 4:
+            return cpu_inl(addr);
+        default:
+            hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void do_outp(pio_addr_t addr,
+        unsigned long size, uint32_t val)
+{
+    switch (size) {
+        case 1:
+            return cpu_outb(addr, val);
+        case 2:
+            return cpu_outw(addr, val);
+        case 4:
+            return cpu_outl(addr, val);
+        default:
+            hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void cpu_ioreq_pio(ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (req->dir == IOREQ_READ) {
+        if (!req->data_is_ptr) {
+            req->data = do_inp(req->addr, req->size);
+        } else {
+            uint32_t tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(req->addr, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t *) &tmp, req->size);
+            }
+        }
+    } else if (req->dir == IOREQ_WRITE) {
+        if (!req->data_is_ptr) {
+            do_outp(req->addr, req->size, req->data);
+        } else {
+            for (i = 0; i < req->count; i++) {
+                uint32_t tmp = 0;
+
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                do_outp(req->addr, req->size, tmp);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_move(ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (!req->data_is_ptr) {
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t *) &req->data, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t *) &req->data, req->size);
+            }
+        }
+    } else {
+        target_ulong tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    }
+}
+
+static void handle_ioreq(ioreq_t *req)
+{
+    if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
+            (req->size < sizeof (target_ulong))) {
+        req->data &= ((target_ulong) 1 << (8 * req->size)) - 1;
+    }
+
+    switch (req->type) {
+        case IOREQ_TYPE_PIO:
+            cpu_ioreq_pio(req);
+            break;
+        case IOREQ_TYPE_COPY:
+            cpu_ioreq_move(req);
+            break;
+        case IOREQ_TYPE_TIMEOFFSET:
+            break;
+        case IOREQ_TYPE_INVALIDATE:
+            xen_invalidate_map_cache();
+            break;
+        default:
+            hw_error("Invalid ioreq type 0x%x\n", req->type);
+    }
+}
+
+static void handle_buffered_iopage(XenIOState *state)
+{
+    buf_ioreq_t *buf_req = NULL;
+    ioreq_t req;
+    int qw;
+
+    if (!state->buffered_io_page) {
+        return;
+    }
+
+    while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
+        buf_req = &state->buffered_io_page->buf_ioreq[
+            state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
+        req.size = 1UL << buf_req->size;
+        req.count = 1;
+        req.addr = buf_req->addr;
+        req.data = buf_req->data;
+        req.state = STATE_IOREQ_READY;
+        req.dir = buf_req->dir;
+        req.df = 1;
+        req.type = buf_req->type;
+        req.data_is_ptr = 0;
+        qw = (req.size == 8);
+        if (qw) {
+            buf_req = &state->buffered_io_page->buf_ioreq[
+                (state->buffered_io_page->read_pointer + 1) % IOREQ_BUFFER_SLOT_NUM];
+            req.data |= ((uint64_t)buf_req->data) << 32;
+        }
+
+        handle_ioreq(&req);
+
+        xen_mb();
+        state->buffered_io_page->read_pointer += qw ? 2 : 1;
+    }
+}
+
+static void handle_buffered_io(void *opaque)
+{
+    XenIOState *state = opaque;
+
+    handle_buffered_iopage(state);
+    qemu_mod_timer(state->buffered_io_timer,
+                   BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+}
+
+static void cpu_handle_ioreq(void *opaque)
+{
+    XenIOState *state = opaque;
+    ioreq_t *req = cpu_get_ioreq(state);
+
+    handle_buffered_iopage(state);
+    if (req) {
+        handle_ioreq(req);
+
+        if (req->state != STATE_IOREQ_INPROCESS) {
+            fprintf(stderr, "Badness in I/O request ... not in service?!: "
+                    "%x, ptr: %x, port: %"PRIx64", "
+                    "data: %"PRIx64", count: %" FMT_ioreq_size ", size: %" FMT_ioreq_size "\n",
+                    req->state, req->data_is_ptr, req->addr,
+                    req->data, req->count, req->size);
+            destroy_hvm_domain();
+            return;
+        }
+
+        xen_wmb(); /* Update ioreq contents /then/ update state. */
+
+        /*
+         * We do this before we send the response so that the tools
+         * have the opportunity to pick up on the reset before the
+         * guest resumes and does a hlt with interrupts disabled which
+         * causes Xen to powerdown the domain.
+         */
+        if (vm_running) {
+            if (qemu_shutdown_requested_get()) {
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                qemu_system_reset(VMRESET_REPORT);
+            }
+        }
+
+        req->state = STATE_IORESP_READY;
+        xc_evtchn_notify(state->xce_handle, state->ioreq_local_port[state->send_vcpu]);
+    }
+}
+
+static int store_dev_info(int domid, CharDriverState *cs, const char *string)
+{
+    struct xs_handle *xs = NULL;
+    char *path = NULL;
+    char *newpath = NULL;
+    char *pts = NULL;
+    int ret = -1;
+
+    /* Only continue if we're talking to a pty. */
+    if (strncmp(cs->filename, "pty:", 4)) {
+        return 0;
+    }
+    pts = cs->filename + 4;
+
+    /* We now have everything we need to set the xenstore entry. */
+    xs = xs_open(0);
+    if (xs == NULL) {
+        fprintf(stderr, "Could not contact XenStore\n");
+        goto out;
+    }
+
+    path = xs_get_domain_path(xs, domid);
+    if (path == NULL) {
+        fprintf(stderr, "xs_get_domain_path() error\n");
+        goto out;
+    }
+    newpath = realloc(path, (strlen(path) + strlen(string) +
+                strlen("/tty") + 1));
+    if (newpath == NULL) {
+        fprintf(stderr, "realloc error\n");
+        goto out;
+    }
+    path = newpath;
+
+    strcat(path, string);
+    strcat(path, "/tty");
+    if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
+        fprintf(stderr, "xs_write for '%s' fail", string);
+        goto out;
+    }
+    ret = 0;
+
+out:
+    free(path);
+    xs_close(xs);
+
+    return ret;
+}
+
+void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+{
+    if (i == 0) {
+        store_dev_info(xen_domid, chr, "/console");
+    } else {
+        char buf[32];
+        snprintf(buf, sizeof(buf), "/device/console/%d", i);
+        store_dev_info(xen_domid, chr, buf);
+    }
+}
+
+static void xenstore_record_dm_state(XenIOState *s, const char *state)
+{
+    char path[50];
+
+    snprintf(path, sizeof (path), "/local/domain/0/device-model/%u/state", xen_domid);
+    if (!xs_write(s->xenstore, XBT_NULL, path, state, strlen(state))) {
+        fprintf(stderr, "error recording dm state\n");
+        exit(1);
+    }
+}
+
+static void xen_main_loop_prepare(XenIOState *state)
+{
+    int evtchn_fd = -1;
+
+    if (state->xce_handle != XC_HANDLER_INITIAL_VALUE) {
+        evtchn_fd = xc_evtchn_fd(state->xce_handle);
+    }
+
+    state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
+                                                 state);
+    qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock));
+
+    if (evtchn_fd != -1) {
+        qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
+    }
+
+    /* record state running */
+    xenstore_record_dm_state(state, "running");
+}
+
+
+/* Initialise Xen */
+
+static void xen_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    XenIOState *state = opaque;
+    if (running) {
+        xen_main_loop_prepare(state);
+    }
+}
+
+static void xen_exit_notifier(Notifier *n, void *data)
+{
+    XenIOState *state = container_of(n, XenIOState, exit);
+
+    xc_evtchn_close(state->xce_handle);
+    xs_daemon_close(state->xenstore);
+}
+
+int xen_init(void)
+{
+    xen_xc = xen_xc_interface_open(0, 0, 0);
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int xen_hvm_init(void)
+{
+    int i, rc;
+    unsigned long ioreq_pfn;
+    XenIOState *state;
+
+    state = qemu_mallocz(sizeof (XenIOState));
+
+    state->xce_handle = xen_xc_evtchn_open(NULL, 0);
+    if (state->xce_handle == XC_HANDLER_INITIAL_VALUE) {
+        perror("xen: event channel open");
+        return -errno;
+    }
+
+    state->xenstore = xs_daemon_open();
+    if (state->xenstore == NULL) {
+        perror("xen: xenstore open");
+        return -errno;
+    }
+
+    state->exit.notify = xen_exit_notifier;
+    qemu_add_exit_notifier(&state->exit);
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
+    DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
+    state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                              PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (state->shared_page == NULL) {
+        hw_error("map shared IO page returned error %d handle=" XC_INTERFACE_FMT,
+                 errno, xen_xc);
+    }
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
+    DPRINTF("buffered io page at pfn %lx\n", ioreq_pfn);
+    state->buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                                   PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (state->buffered_io_page == NULL) {
+        hw_error("map buffered IO page returned error %d", errno);
+    }
+
+    state->ioreq_local_port = qemu_mallocz(smp_cpus * sizeof (evtchn_port_t));
+
+    /* FIXME: how about if we overflow the page here? */
+    for (i = 0; i < smp_cpus; i++) {
+        rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+                                        xen_vcpu_eport(state->shared_page, i));
+        if (rc == -1) {
+            fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+            return -1;
+        }
+        state->ioreq_local_port[i] = rc;
+    }
+
+    /* Init RAM management */
+    xen_map_cache_init();
+    xen_ram_init(ram_size);
+
+    qemu_add_vm_change_state_handler(xen_vm_change_state_handler, state);
+
+    state->client = xen_cpu_phys_memory_client;
+    QLIST_INIT(&state->physmap);
+    cpu_register_phys_memory_client(&state->client);
+    state->log_for_dirtybit = NULL;
+
+    /* Initialize backend core & drivers */
+    if (xen_be_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+    xen_be_register("console", &xen_console_ops);
+    xen_be_register("vkbd", &xen_kbdmouse_ops);
+    xen_be_register("qdisk", &xen_blkdev_ops);
+
+    return 0;
+}
+
+void destroy_hvm_domain(void)
+{
+    XenXC xc_handle;
+    int sts;
+
+    xc_handle = xen_xc_interface_open(0, 0, 0);
+    if (xc_handle == XC_HANDLER_INITIAL_VALUE) {
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    } else {
+        sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
+        if (sts != 0) {
+            fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
+                    "sts %d, %s\n", sts, strerror(errno));
+        } else {
+            fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
+        }
+        xc_interface_close(xc_handle);
+    }
+}
diff --git a/qemu-0.15.x/xen-mapcache.c b/qemu-0.15.x/xen-mapcache.c
new file mode 100644
index 0000000..007136a
--- /dev/null
+++ b/qemu-0.15.x/xen-mapcache.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2011       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/resource.h>
+
+#include "hw/xen_backend.h"
+#include "blockdev.h"
+#include "bitmap.h"
+
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#include "xen-mapcache.h"
+#include "trace.h"
+
+
+//#define MAPCACHE_DEBUG
+
+#ifdef MAPCACHE_DEBUG
+#  define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#  define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#if defined(__i386__)
+#  define MCACHE_BUCKET_SHIFT 16
+#  define MCACHE_MAX_SIZE     (1UL<<31) /* 2GB Cap */
+#elif defined(__x86_64__)
+#  define MCACHE_BUCKET_SHIFT 20
+#  define MCACHE_MAX_SIZE     (1UL<<35) /* 32GB Cap */
+#endif
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+
+#define mapcache_lock()   ((void)0)
+#define mapcache_unlock() ((void)0)
+
+typedef struct MapCacheEntry {
+    target_phys_addr_t paddr_index;
+    uint8_t *vaddr_base;
+    unsigned long *valid_mapping;
+    uint8_t lock;
+    target_phys_addr_t size;
+    struct MapCacheEntry *next;
+} MapCacheEntry;
+
+typedef struct MapCacheRev {
+    uint8_t *vaddr_req;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    QTAILQ_ENTRY(MapCacheRev) next;
+} MapCacheRev;
+
+typedef struct MapCache {
+    MapCacheEntry *entry;
+    unsigned long nr_buckets;
+    QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+
+    /* For most cases (>99.9%), the page address is the same. */
+    target_phys_addr_t last_address_index;
+    uint8_t *last_address_vaddr;
+    unsigned long max_mcache_size;
+    unsigned int mcache_bucket_shift;
+} MapCache;
+
+static MapCache *mapcache;
+
+static inline int test_bits(int nr, int size, const unsigned long *addr)
+{
+    unsigned long res = find_next_zero_bit(addr, size + nr, nr);
+    if (res >= nr + size)
+        return 1;
+    else
+        return 0;
+}
+
+void xen_map_cache_init(void)
+{
+    unsigned long size;
+    struct rlimit rlimit_as;
+
+    mapcache = qemu_mallocz(sizeof (MapCache));
+
+    QTAILQ_INIT(&mapcache->locked_entries);
+    mapcache->last_address_index = -1;
+
+    getrlimit(RLIMIT_AS, &rlimit_as);
+    if (rlimit_as.rlim_max < MCACHE_MAX_SIZE) {
+        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+    } else {
+        rlimit_as.rlim_cur = MCACHE_MAX_SIZE;
+    }
+
+    setrlimit(RLIMIT_AS, &rlimit_as);
+    mapcache->max_mcache_size = rlimit_as.rlim_cur;
+
+    mapcache->nr_buckets =
+        (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
+          (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
+         (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
+
+    size = mapcache->nr_buckets * sizeof (MapCacheEntry);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__,
+            mapcache->nr_buckets, size);
+    mapcache->entry = qemu_mallocz(size);
+}
+
+static void xen_remap_bucket(MapCacheEntry *entry,
+                             target_phys_addr_t size,
+                             target_phys_addr_t address_index)
+{
+    uint8_t *vaddr_base;
+    xen_pfn_t *pfns;
+    int *err;
+    unsigned int i;
+    target_phys_addr_t nb_pfn = size >> XC_PAGE_SHIFT;
+
+    trace_xen_remap_bucket(address_index);
+
+    pfns = qemu_mallocz(nb_pfn * sizeof (xen_pfn_t));
+    err = qemu_mallocz(nb_pfn * sizeof (int));
+
+    if (entry->vaddr_base != NULL) {
+        if (munmap(entry->vaddr_base, entry->size) != 0) {
+            perror("unmap fails");
+            exit(-1);
+        }
+    }
+    if (entry->valid_mapping != NULL) {
+        qemu_free(entry->valid_mapping);
+        entry->valid_mapping = NULL;
+    }
+
+    for (i = 0; i < nb_pfn; i++) {
+        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
+    }
+
+    vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE,
+                                     pfns, err, nb_pfn);
+    if (vaddr_base == NULL) {
+        perror("xc_map_foreign_bulk");
+        exit(-1);
+    }
+
+    entry->vaddr_base = vaddr_base;
+    entry->paddr_index = address_index;
+    entry->size = size;
+    entry->valid_mapping = (unsigned long *) qemu_mallocz(sizeof(unsigned long) *
+            BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
+
+    bitmap_zero(entry->valid_mapping, nb_pfn);
+    for (i = 0; i < nb_pfn; i++) {
+        if (!err[i]) {
+            bitmap_set(entry->valid_mapping, i, 1);
+        }
+    }
+
+    qemu_free(pfns);
+    qemu_free(err);
+}
+
+uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
+                       uint8_t lock)
+{
+    MapCacheEntry *entry, *pentry = NULL;
+    target_phys_addr_t address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
+    target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
+    target_phys_addr_t __size = size;
+
+    trace_xen_map_cache(phys_addr);
+
+    if (address_index == mapcache->last_address_index && !lock && !__size) {
+        trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
+        return mapcache->last_address_vaddr + address_offset;
+    }
+
+    /* size is always a multiple of MCACHE_BUCKET_SIZE */
+    if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE)
+        __size += MCACHE_BUCKET_SIZE;
+    if (__size % MCACHE_BUCKET_SIZE)
+        __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
+    if (!__size)
+        __size = MCACHE_BUCKET_SIZE;
+
+    entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+
+    while (entry && entry->lock && entry->vaddr_base &&
+            (entry->paddr_index != address_index || entry->size != __size ||
+             !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                 entry->valid_mapping))) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        entry = qemu_mallocz(sizeof (MapCacheEntry));
+        pentry->next = entry;
+        xen_remap_bucket(entry, __size, address_index);
+    } else if (!entry->lock) {
+        if (!entry->vaddr_base || entry->paddr_index != address_index ||
+                entry->size != __size ||
+                !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                    entry->valid_mapping)) {
+            xen_remap_bucket(entry, __size, address_index);
+        }
+    }
+
+    if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+                entry->valid_mapping)) {
+        mapcache->last_address_index = -1;
+        trace_xen_map_cache_return(NULL);
+        return NULL;
+    }
+
+    mapcache->last_address_index = address_index;
+    mapcache->last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        MapCacheRev *reventry = qemu_mallocz(sizeof(MapCacheRev));
+        entry->lock++;
+        reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
+        reventry->paddr_index = mapcache->last_address_index;
+        reventry->size = entry->size;
+        QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
+    }
+
+    trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
+    return mapcache->last_address_vaddr + address_offset;
+}
+
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+    MapCacheEntry *entry = NULL, *pentry = NULL;
+    MapCacheRev *reventry;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    int found = 0;
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == ptr) {
+            paddr_index = reventry->paddr_index;
+            size = reventry->size;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "%s, could not find %p\n", __func__, ptr);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index,
+                    reventry->vaddr_req);
+        }
+        abort();
+        return 0;
+    }
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr);
+        return 0;
+    }
+    return (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
+        ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
+}
+
+void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+    MapCacheEntry *entry = NULL, *pentry = NULL;
+    MapCacheRev *reventry;
+    target_phys_addr_t paddr_index;
+    target_phys_addr_t size;
+    int found = 0;
+
+    if (mapcache->last_address_vaddr == buffer) {
+        mapcache->last_address_index = -1;
+    }
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            size = reventry->size;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        DPRINTF("%s, could not find %p\n", __func__, buffer);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
+    qemu_free(reventry);
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+        return;
+    }
+    entry->lock--;
+    if (entry->lock > 0 || pentry == NULL) {
+        return;
+    }
+
+    pentry->next = entry->next;
+    if (munmap(entry->vaddr_base, entry->size) != 0) {
+        perror("unmap fails");
+        exit(-1);
+    }
+    qemu_free(entry->valid_mapping);
+    qemu_free(entry);
+}
+
+void xen_invalidate_map_cache(void)
+{
+    unsigned long i;
+    MapCacheRev *reventry;
+
+    /* Flush pending AIO before destroying the mapcache */
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        DPRINTF("There should be no locked mappings at this time, "
+                "but "TARGET_FMT_plx" -> %p is present\n",
+                reventry->paddr_index, reventry->vaddr_req);
+    }
+
+    mapcache_lock();
+
+    for (i = 0; i < mapcache->nr_buckets; i++) {
+        MapCacheEntry *entry = &mapcache->entry[i];
+
+        if (entry->vaddr_base == NULL) {
+            continue;
+        }
+
+        if (munmap(entry->vaddr_base, entry->size) != 0) {
+            perror("unmap fails");
+            exit(-1);
+        }
+
+        entry->paddr_index = 0;
+        entry->vaddr_base = NULL;
+        entry->size = 0;
+        qemu_free(entry->valid_mapping);
+        entry->valid_mapping = NULL;
+    }
+
+    mapcache->last_address_index = -1;
+    mapcache->last_address_vaddr = NULL;
+
+    mapcache_unlock();
+}
diff --git a/qemu-0.15.x/xen-mapcache.h b/qemu-0.15.x/xen-mapcache.h
new file mode 100644
index 0000000..da874ca
--- /dev/null
+++ b/qemu-0.15.x/xen-mapcache.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef XEN_MAPCACHE_H
+#define XEN_MAPCACHE_H
+
+#include <stdlib.h>
+
+#ifdef CONFIG_XEN
+
+void xen_map_cache_init(void);
+uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size,
+                       uint8_t lock);
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
+void xen_invalidate_map_cache_entry(uint8_t *buffer);
+void xen_invalidate_map_cache(void);
+
+#else
+
+static inline void xen_map_cache_init(void)
+{
+}
+
+static inline uint8_t *xen_map_cache(target_phys_addr_t phys_addr,
+                                     target_phys_addr_t size,
+                                     uint8_t lock)
+{
+    abort();
+}
+
+static inline ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+    abort();
+}
+
+static inline void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+}
+
+static inline void xen_invalidate_map_cache(void)
+{
+}
+
+#endif
+
+#endif /* !XEN_MAPCACHE_H */
diff --git a/qemu-0.15.x/xen-stub.c b/qemu-0.15.x/xen-stub.c
new file mode 100644
index 0000000..efe2ab5
--- /dev/null
+++ b/qemu-0.15.x/xen-stub.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/xen.h"
+
+void xenstore_store_pv_console_info(int i, CharDriverState *chr)
+{
+}
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    return -1;
+}
+
+void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+}
+
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
+{
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size)
+{
+}
+
+qemu_irq *xen_interrupt_controller_init(void)
+{
+    return NULL;
+}
+
+int xen_init(void)
+{
+    return -ENOSYS;
+}



More information about the SerialICE mailing list